[Pkg-golang-commits] [golang] 01/01: Imported Upstream version 1.8~beta1
Michael Hudson-Doyle
mwhudson-guest at moszumanska.debian.org
Wed Dec 7 21:34:19 UTC 2016
This is an automated email from the git hooks/post-receive script.
mwhudson-guest pushed a commit to branch upstream-1.8
in repository golang.
commit 7c1f35a3d06c29f961bbb7859cdb154b2ab7c730
Author: Michael Hudson-Doyle <michael.hudson at canonical.com>
Date: Thu Dec 8 10:15:14 2016 +1300
Imported Upstream version 1.8~beta1
---
AUTHORS | 76 +
CONTRIBUTORS | 103 +-
VERSION | 2 +-
api/except.txt | 186 +-
api/go1.8.txt | 259 +
doc/articles/go_command.html | 95 +-
doc/code.html | 39 +-
doc/conduct.html | 4 +-
doc/devel/release.html | 25 +-
doc/devel/weekly.html | 12 +-
doc/docs.html | 8 +-
doc/effective_go.html | 10 +-
doc/gccgo_contribute.html | 2 +-
doc/go1.7.html | 13 +-
doc/go1.8.html | 1615 ++
doc/go1.8.txt | 56 +
doc/go_faq.html | 85 +-
doc/go_spec.html | 93 +-
doc/install-source.html | 14 +-
doc/install.html | 70 +-
doc/progs/json1.go | 6 +-
doc/progs/json3.go | 2 +-
doc/progs/json4.go | 2 +-
lib/time/update.bash | 4 +-
lib/time/zoneinfo.zip | Bin 364741 -> 364943 bytes
misc/cgo/errors/issue16591.go | 17 +
misc/cgo/errors/malloc.go | 34 +
misc/cgo/errors/ptr.go | 21 +
misc/cgo/errors/test.bash | 11 +
misc/cgo/test/api.go | 6 +
misc/cgo/test/basic.go | 3 +
misc/cgo/test/callback.go | 1 +
misc/cgo/test/cgo_test.go | 6 +
misc/cgo/test/cgo_thread_lock.go | 53 +
misc/cgo/test/checkconst.go | 33 +
misc/cgo/test/complex.go | 24 +
misc/cgo/test/issue17065.go | 29 +
misc/cgo/test/issue17537.go | 42 +
misc/cgo/test/issue18126.go | 26 +
misc/cgo/test/issue7978.go | 11 +
misc/cgo/test/issue8756.go | 17 +
misc/cgo/test/issue8756/issue8756.go | 11 +
misc/cgo/testcarchive/carchive_test.go | 190 +-
misc/cgo/testcarchive/main2.c | 56 +-
misc/cgo/testcarchive/main3.c | 25 +-
misc/cgo/testcarchive/main4.c | 19 +-
misc/cgo/testcarchive/main5.c | 18 +
misc/cgo/testcarchive/src/libgo2/libgo2.go | 30 +
misc/cgo/testcarchive/src/libgo3/libgo3.go | 12 +
misc/cgo/testcshared/main4.c | 9 +-
misc/cgo/testcshared/main5.c | 18 +-
misc/cgo/testcshared/test.bash | 2 +-
misc/cgo/testgodefs/test.bash | 2 +-
misc/cgo/testplugin/altpath/src/common/common.go | 11 +
.../testplugin/altpath/src/plugin-mismatch/main.go | 17 +
misc/cgo/testplugin/src/common/common.go | 11 +
misc/cgo/testplugin/src/host/host.go | 148 +
misc/cgo/testplugin/src/plugin1/plugin1.go | 35 +
misc/cgo/testplugin/src/plugin2/plugin2.go | 18 +
misc/cgo/testplugin/src/sub/plugin1/plugin1.go | 23 +
misc/cgo/testplugin/test.bash | 34 +
misc/cgo/testplugin/unnamed1.go | 12 +
misc/cgo/testplugin/unnamed2.go | 12 +
misc/cgo/testsanitizers/msan5.go | 57 +
misc/cgo/testsanitizers/test.bash | 14 +
misc/cgo/testsanitizers/tsan7.go | 40 +
misc/cgo/testsanitizers/tsan8.go | 60 +
misc/cgo/testshared/shared_test.go | 30 +-
misc/cgo/testshared/src/depBase/dep.go | 9 +
misc/cgo/testshared/src/exe/exe.go | 6 +
misc/cgo/testsigfwd/main.go | 1 +
misc/nacl/testzip.proto | 8 +
src/androidtest.bash | 20 +-
src/archive/tar/common.go | 27 +-
src/archive/tar/reader.go | 531 +-
src/archive/tar/reader_test.go | 773 +-
src/archive/tar/strconv.go | 252 +
src/archive/tar/strconv_test.go | 319 +
src/archive/tar/tar_test.go | 236 +-
src/archive/tar/testdata/gnu-incremental.tar | Bin 0 -> 2560 bytes
src/archive/tar/testdata/pax-bad-hdr-file.tar | Bin 0 -> 2560 bytes
src/archive/tar/testdata/pax-bad-mtime-file.tar | Bin 0 -> 2560 bytes
src/archive/tar/testdata/pax-pos-size-file.tar | Bin 0 -> 2560 bytes
src/archive/tar/testdata/ustar.issue12594.tar | Bin 0 -> 3072 bytes
src/archive/tar/testdata/writer-big-long.tar | Bin 4096 -> 4096 bytes
src/archive/tar/writer.go | 106 +-
src/archive/tar/writer_test.go | 483 +-
src/archive/zip/reader.go | 49 +-
src/archive/zip/reader_test.go | 31 +-
src/archive/zip/struct.go | 3 +
src/archive/zip/testdata/extra-timestamp.zip | Bin 0 -> 152 bytes
src/archive/zip/writer.go | 28 +-
src/archive/zip/writer_test.go | 27 +
src/archive/zip/zip_test.go | 363 +-
src/bufio/bufio.go | 29 +-
src/bufio/bufio_test.go | 21 +
src/bufio/scan.go | 1 -
src/builtin/builtin.go | 4 +-
src/bytes/buffer.go | 43 +-
src/bytes/buffer_test.go | 13 +
src/bytes/bytes.go | 146 +-
src/bytes/bytes_amd64.go | 115 +
src/bytes/bytes_generic.go | 41 +
src/bytes/bytes_s390x.go | 118 +
src/bytes/bytes_test.go | 194 +-
src/bytes/example_test.go | 203 +
src/cmd/addr2line/addr2line_test.go | 4 +-
src/cmd/api/run.go | 2 +-
src/cmd/asm/internal/arch/amd64.go | 4 +-
src/cmd/asm/internal/arch/arch.go | 74 +-
src/cmd/asm/internal/arch/mips.go | 67 +
src/cmd/asm/internal/arch/mips64.go | 67 -
src/cmd/asm/internal/arch/ppc64.go | 12 +
src/cmd/asm/internal/arch/s390x.go | 12 +-
src/cmd/asm/internal/asm/asm.go | 93 +-
src/cmd/asm/internal/asm/endtoend_test.go | 3 +-
src/cmd/asm/internal/asm/operand_test.go | 187 +-
src/cmd/asm/internal/asm/parse.go | 8 -
src/cmd/asm/internal/asm/testdata/amd64enc.s | 192 +-
src/cmd/asm/internal/asm/testdata/mips.s | 430 +
src/cmd/asm/internal/asm/testdata/ppc64.s | 349 +
src/cmd/asm/internal/asm/testdata/s390x.s | 151 +-
src/cmd/asm/internal/flags/flags.go | 9 +-
src/cmd/asm/main.go | 35 +-
src/cmd/cgo/ast.go | 3 +-
src/cmd/cgo/doc.go | 12 +
src/cmd/cgo/gcc.go | 418 +-
src/cmd/cgo/main.go | 15 +-
src/cmd/cgo/out.go | 86 +-
src/cmd/compile/fmt_test.go | 716 +
src/cmd/compile/internal/amd64/cgen.go | 161 -
src/cmd/compile/internal/amd64/galign.go | 73 +-
src/cmd/compile/internal/amd64/ggen.go | 681 +-
src/cmd/compile/internal/amd64/gsubr.go | 1423 --
src/cmd/compile/internal/amd64/peep.go | 1025 -
src/cmd/compile/internal/amd64/prog.go | 120 +-
src/cmd/compile/internal/amd64/reg.go | 152 -
src/cmd/compile/internal/amd64/ssa.go | 562 +-
src/cmd/compile/internal/arm/cgen.go | 224 -
src/cmd/compile/internal/arm/cgen64.go | 859 -
src/cmd/compile/internal/arm/galign.go | 49 +-
src/cmd/compile/internal/arm/ggen.go | 479 +-
src/cmd/compile/internal/arm/gsubr.go | 1225 -
src/cmd/compile/internal/arm/peep.go | 1734 --
src/cmd/compile/internal/arm/prog.go | 19 +-
src/cmd/compile/internal/arm/reg.go | 136 -
src/cmd/compile/internal/arm/ssa.go | 915 +-
src/cmd/compile/internal/arm64/cgen.go | 151 -
src/cmd/compile/internal/arm64/galign.go | 52 +-
src/cmd/compile/internal/arm64/ggen.go | 501 +-
src/cmd/compile/internal/arm64/gsubr.go | 983 -
src/cmd/compile/internal/arm64/peep.go | 797 -
src/cmd/compile/internal/arm64/prog.go | 158 +-
src/cmd/compile/internal/arm64/reg.go | 169 -
src/cmd/compile/internal/arm64/ssa.go | 844 +
src/cmd/compile/internal/big/accuracy_string.go | 17 -
src/cmd/compile/internal/big/arith.go | 305 -
src/cmd/compile/internal/big/arith_decl.go | 53 -
src/cmd/compile/internal/big/arith_test.go | 442 -
src/cmd/compile/internal/big/bits_test.go | 224 -
src/cmd/compile/internal/big/calibrate_test.go | 88 -
src/cmd/compile/internal/big/decimal.go | 266 -
src/cmd/compile/internal/big/decimal_test.go | 116 -
src/cmd/compile/internal/big/example_rat_test.go | 65 -
src/cmd/compile/internal/big/example_test.go | 128 -
src/cmd/compile/internal/big/float.go | 1683 --
src/cmd/compile/internal/big/float_test.go | 1764 --
src/cmd/compile/internal/big/floatconv.go | 275 -
src/cmd/compile/internal/big/floatconv_test.go | 662 -
src/cmd/compile/internal/big/floatexample_test.go | 141 -
src/cmd/compile/internal/big/floatmarsh.go | 33 -
src/cmd/compile/internal/big/floatmarsh_test.go | 54 -
src/cmd/compile/internal/big/ftoa.go | 456 -
src/cmd/compile/internal/big/gcd_test.go | 47 -
src/cmd/compile/internal/big/hilbert_test.go | 160 -
src/cmd/compile/internal/big/int.go | 934 -
src/cmd/compile/internal/big/int_test.go | 1482 --
src/cmd/compile/internal/big/intconv.go | 248 -
src/cmd/compile/internal/big/intconv_test.go | 391 -
src/cmd/compile/internal/big/intmarsh.go | 74 -
src/cmd/compile/internal/big/intmarsh_test.go | 121 -
src/cmd/compile/internal/big/nat.go | 1282 -
src/cmd/compile/internal/big/nat_test.go | 654 -
src/cmd/compile/internal/big/natconv.go | 492 -
src/cmd/compile/internal/big/natconv_test.go | 422 -
src/cmd/compile/internal/big/rat.go | 510 -
src/cmd/compile/internal/big/rat_test.go | 622 -
src/cmd/compile/internal/big/ratconv.go | 264 -
src/cmd/compile/internal/big/ratconv_test.go | 453 -
src/cmd/compile/internal/big/ratmarsh.go | 73 -
src/cmd/compile/internal/big/ratmarsh_test.go | 125 -
.../compile/internal/big/roundingmode_string.go | 16 -
src/cmd/compile/internal/big/vendor.bash | 31 -
src/cmd/compile/internal/gc/alg.go | 108 +-
src/cmd/compile/internal/gc/align.go | 50 +-
src/cmd/compile/internal/gc/asm_test.go | 119 +-
src/cmd/compile/internal/gc/bexport.go | 325 +-
src/cmd/compile/internal/gc/bimport.go | 450 +-
src/cmd/compile/internal/gc/builtin.go | 339 +-
src/cmd/compile/internal/gc/builtin/runtime.go | 38 +-
src/cmd/compile/internal/gc/builtin/unsafe.go | 18 -
src/cmd/compile/internal/gc/builtin_test.go | 2 +-
src/cmd/compile/internal/gc/bv.go | 65 +-
src/cmd/compile/internal/gc/cgen.go | 3600 ---
src/cmd/compile/internal/gc/closure.go | 135 +-
src/cmd/compile/internal/gc/const.go | 329 +-
src/cmd/compile/internal/gc/constFold_test.go | 4596 ++--
src/cmd/compile/internal/gc/cplx.go | 474 -
src/cmd/compile/internal/gc/dcl.go | 412 +-
src/cmd/compile/internal/gc/esc.go | 807 +-
src/cmd/compile/internal/gc/export.go | 325 +-
src/cmd/compile/internal/gc/fixedbugs_test.go | 2 +-
src/cmd/compile/internal/gc/float_test.go | 33 +
src/cmd/compile/internal/gc/fmt.go | 1149 +-
src/cmd/compile/internal/gc/gen.go | 1139 +-
src/cmd/compile/internal/gc/global_test.go | 6 +-
src/cmd/compile/internal/gc/go.go | 186 +-
src/cmd/compile/internal/gc/gsubr.go | 720 +-
src/cmd/compile/internal/gc/iface_test.go | 128 +
src/cmd/compile/internal/gc/init.go | 54 +-
src/cmd/compile/internal/gc/inl.go | 215 +-
src/cmd/compile/internal/gc/lex.go | 1176 +-
src/cmd/compile/internal/gc/magic.go | 4 +-
src/cmd/compile/internal/gc/main.go | 242 +-
src/cmd/compile/internal/gc/mkbuiltin.go | 219 +-
src/cmd/compile/internal/gc/mpfloat.go | 10 +-
src/cmd/compile/internal/gc/mpint.go | 46 +-
src/cmd/compile/internal/gc/noder.go | 1083 +
src/cmd/compile/internal/gc/obj.go | 183 +-
src/cmd/compile/internal/gc/opnames.go | 6 +-
src/cmd/compile/internal/gc/order.go | 182 +-
src/cmd/compile/internal/gc/parser.go | 3353 ---
src/cmd/compile/internal/gc/pgen.go | 274 +-
src/cmd/compile/internal/gc/phi.go | 521 +
src/cmd/compile/internal/gc/plive.go | 316 +-
src/cmd/compile/internal/gc/popt.go | 1094 -
src/cmd/compile/internal/gc/racewalk.go | 104 +-
src/cmd/compile/internal/gc/range.go | 171 +-
src/cmd/compile/internal/gc/reflect.go | 203 +-
src/cmd/compile/internal/gc/reg.go | 1532 --
src/cmd/compile/internal/gc/select.go | 82 +-
src/cmd/compile/internal/gc/sinit.go | 823 +-
src/cmd/compile/internal/gc/sizeof_test.go | 6 +-
.../internal/gc/sparselocatephifunctions.go | 202 -
src/cmd/compile/internal/gc/ssa.go | 2043 +-
src/cmd/compile/internal/gc/ssa_test.go | 58 +-
src/cmd/compile/internal/gc/subr.go | 591 +-
src/cmd/compile/internal/gc/swt.go | 677 +-
src/cmd/compile/internal/gc/swt_test.go | 152 +-
src/cmd/compile/internal/gc/syntax.go | 146 +-
.../gc/testdata/{addressed_ssa.go => addressed.go} | 0
.../gc/testdata/{append_ssa.go => append.go} | 0
src/cmd/compile/internal/gc/testdata/arith.go | 1020 +
.../{arithBoundary_ssa.go => arithBoundary.go} | 0
.../testdata/{arithConst_ssa.go => arithConst.go} | 0
src/cmd/compile/internal/gc/testdata/arith_ssa.go | 580 -
.../gc/testdata/{array_ssa.go => array.go} | 0
.../gc/testdata/{assert_ssa.go => assert.go} | 0
.../gc/testdata/{break_ssa.go => break.go} | 0
.../internal/gc/testdata/{chan_ssa.go => chan.go} | 0
.../gc/testdata/{closure_ssa.go => closure.go} | 0
.../internal/gc/testdata/{cmp_ssa.go => cmp.go} | 0
.../gc/testdata/{compound_ssa.go => compound.go} | 0
.../internal/gc/testdata/{copy_ssa.go => copy.go} | 0
.../internal/gc/testdata/{ctl_ssa.go => ctl.go} | 0
.../{deferNoReturn_ssa.go => deferNoReturn.go} | 0
.../gc/testdata/{divbyzero_ssa.go => divbyzero.go} | 0
.../internal/gc/testdata/{fp_ssa.go => fp.go} | 0
.../internal/gc/testdata/gen/arithBoundaryGen.go | 4 +-
.../internal/gc/testdata/gen/arithConstGen.go | 4 +-
.../internal/gc/testdata/gen/constFoldGen.go | 8 +-
.../compile/internal/gc/testdata/gen/copyGen.go | 4 +-
.../compile/internal/gc/testdata/gen/zeroGen.go | 4 +-
.../gc/testdata/{loadstore_ssa.go => loadstore.go} | 0
.../internal/gc/testdata/{map_ssa.go => map.go} | 0
.../internal/gc/testdata/{phi_ssa.go => phi.go} | 0
.../gc/testdata/{regalloc_ssa.go => regalloc.go} | 0
.../gc/testdata/{short_ssa.go => short.go} | 0
src/cmd/compile/internal/gc/testdata/sqrt_const.go | 59 +
src/cmd/compile/internal/gc/testdata/string.go | 224 +
src/cmd/compile/internal/gc/testdata/string_ssa.go | 160 -
.../gc/testdata/{unsafe_ssa.go => unsafe.go} | 0
.../internal/gc/testdata/{zero_ssa.go => zero.go} | 0
src/cmd/compile/internal/gc/timings.go | 235 +
src/cmd/compile/internal/gc/trace.go | 27 +
src/cmd/compile/internal/gc/type.go | 122 +-
src/cmd/compile/internal/gc/typecheck.go | 890 +-
src/cmd/compile/internal/gc/universe.go | 145 +-
src/cmd/compile/internal/gc/unsafe.go | 127 +-
src/cmd/compile/internal/gc/util.go | 11 +-
src/cmd/compile/internal/gc/walk.go | 1403 +-
src/cmd/compile/internal/mips/galign.go | 26 +
src/cmd/compile/internal/mips/ggen.go | 101 +
src/cmd/compile/internal/mips/prog.go | 157 +
src/cmd/compile/internal/mips/ssa.go | 907 +
src/cmd/compile/internal/mips64/cgen.go | 157 -
src/cmd/compile/internal/mips64/galign.go | 51 +-
src/cmd/compile/internal/mips64/ggen.go | 419 +-
src/cmd/compile/internal/mips64/gsubr.go | 1071 -
src/cmd/compile/internal/mips64/peep.go | 772 -
src/cmd/compile/internal/mips64/prog.go | 28 +-
src/cmd/compile/internal/mips64/reg.go | 162 -
src/cmd/compile/internal/mips64/ssa.go | 672 +
src/cmd/compile/internal/ppc64/cgen.go | 143 -
src/cmd/compile/internal/ppc64/galign.go | 56 +-
src/cmd/compile/internal/ppc64/ggen.go | 488 +-
src/cmd/compile/internal/ppc64/gsubr.go | 1076 -
src/cmd/compile/internal/ppc64/peep.go | 1032 -
src/cmd/compile/internal/ppc64/prog.go | 62 +-
src/cmd/compile/internal/ppc64/reg.go | 168 -
src/cmd/compile/internal/ppc64/ssa.go | 938 +
src/cmd/compile/internal/s390x/cgen.go | 178 -
src/cmd/compile/internal/s390x/galign.go | 51 +-
src/cmd/compile/internal/s390x/ggen.go | 453 +-
src/cmd/compile/internal/s390x/gsubr.go | 1110 -
src/cmd/compile/internal/s390x/peep.go | 1664 --
src/cmd/compile/internal/s390x/prog.go | 89 +-
src/cmd/compile/internal/s390x/reg.go | 130 -
src/cmd/compile/internal/s390x/ssa.go | 862 +
src/cmd/compile/internal/ssa/block.go | 15 +-
src/cmd/compile/internal/ssa/check.go | 27 +-
src/cmd/compile/internal/ssa/compile.go | 118 +-
src/cmd/compile/internal/ssa/config.go | 173 +-
src/cmd/compile/internal/ssa/cse.go | 174 +-
src/cmd/compile/internal/ssa/cse_test.go | 1 -
src/cmd/compile/internal/ssa/deadcode.go | 12 +
src/cmd/compile/internal/ssa/deadstore.go | 13 +-
src/cmd/compile/internal/ssa/decompose.go | 97 +-
src/cmd/compile/internal/ssa/dom.go | 8 +-
src/cmd/compile/internal/ssa/export_test.go | 22 +-
src/cmd/compile/internal/ssa/flagalloc.go | 47 +-
src/cmd/compile/internal/ssa/func.go | 70 +-
src/cmd/compile/internal/ssa/fuse.go | 4 +-
src/cmd/compile/internal/ssa/gen/386.rules | 1252 +
src/cmd/compile/internal/ssa/gen/386Ops.go | 506 +
src/cmd/compile/internal/ssa/gen/AMD64.rules | 586 +-
src/cmd/compile/internal/ssa/gen/AMD64Ops.go | 434 +-
src/cmd/compile/internal/ssa/gen/ARM.rules | 1231 +-
src/cmd/compile/internal/ssa/gen/ARM64.rules | 1302 +
src/cmd/compile/internal/ssa/gen/ARM64Ops.go | 535 +
src/cmd/compile/internal/ssa/gen/ARMOps.go | 527 +-
src/cmd/compile/internal/ssa/gen/MIPS.rules | 739 +
src/cmd/compile/internal/ssa/gen/MIPS64.rules | 708 +
src/cmd/compile/internal/ssa/gen/MIPS64Ops.go | 381 +
src/cmd/compile/internal/ssa/gen/MIPSOps.go | 413 +
src/cmd/compile/internal/ssa/gen/PPC64.rules | 832 +
src/cmd/compile/internal/ssa/gen/PPC64Ops.go | 398 +
src/cmd/compile/internal/ssa/gen/S390X.rules | 1649 ++
src/cmd/compile/internal/ssa/gen/S390XOps.go | 623 +
src/cmd/compile/internal/ssa/gen/dec64.rules | 447 +
src/cmd/compile/internal/ssa/gen/dec64Ops.go | 20 +
src/cmd/compile/internal/ssa/gen/generic.rules | 199 +-
src/cmd/compile/internal/ssa/gen/genericOps.go | 250 +-
src/cmd/compile/internal/ssa/gen/main.go | 114 +-
src/cmd/compile/internal/ssa/gen/rulegen.go | 412 +-
src/cmd/compile/internal/ssa/html.go | 15 +-
src/cmd/compile/internal/ssa/lca.go | 123 +
src/cmd/compile/internal/ssa/lca_test.go | 103 +
src/cmd/compile/internal/ssa/likelyadjust.go | 29 +-
src/cmd/compile/internal/ssa/location.go | 22 +-
src/cmd/compile/internal/ssa/loopbce.go | 10 +-
src/cmd/compile/internal/ssa/lower.go | 11 +-
src/cmd/compile/internal/ssa/nilcheck.go | 209 +-
src/cmd/compile/internal/ssa/nilcheck_test.go | 10 -
src/cmd/compile/internal/ssa/op.go | 72 +-
src/cmd/compile/internal/ssa/opGen.go | 19742 +++++++++++++--
src/cmd/compile/internal/ssa/opt.go | 3 +
src/cmd/compile/internal/ssa/passbm_test.go | 2 -
src/cmd/compile/internal/ssa/phiopt.go | 66 +-
src/cmd/compile/internal/ssa/prove.go | 101 +-
src/cmd/compile/internal/ssa/regalloc.go | 537 +-
src/cmd/compile/internal/ssa/rewrite.go | 184 +-
src/cmd/compile/internal/ssa/rewrite386.go | 14787 ++++++++++++
src/cmd/compile/internal/ssa/rewriteAMD64.go | 23855 +++++++++++--------
src/cmd/compile/internal/ssa/rewriteARM.go | 18629 ++++++++++++++-
src/cmd/compile/internal/ssa/rewriteARM64.go | 16703 +++++++++++++
src/cmd/compile/internal/ssa/rewriteMIPS.go | 9831 ++++++++
src/cmd/compile/internal/ssa/rewriteMIPS64.go | 10432 ++++++++
src/cmd/compile/internal/ssa/rewritePPC64.go | 10848 +++++++++
src/cmd/compile/internal/ssa/rewriteS390X.go | 18694 +++++++++++++++
src/cmd/compile/internal/ssa/rewrite_test.go | 3 +
src/cmd/compile/internal/ssa/rewritedec.go | 2 +-
src/cmd/compile/internal/ssa/rewritedec64.go | 2720 +++
src/cmd/compile/internal/ssa/rewritegeneric.go | 2379 +-
src/cmd/compile/internal/ssa/schedule.go | 55 +-
src/cmd/compile/internal/ssa/sparsemap.go | 8 +-
src/cmd/compile/internal/ssa/sparsetreemap.go | 2 +-
src/cmd/compile/internal/ssa/stackalloc.go | 2 +-
src/cmd/compile/internal/ssa/stackframe.go | 10 +
src/cmd/compile/internal/ssa/tighten.go | 152 +-
src/cmd/compile/internal/ssa/trim.go | 127 +-
src/cmd/compile/internal/ssa/type.go | 69 +-
src/cmd/compile/internal/ssa/type_test.go | 1 +
src/cmd/compile/internal/ssa/value.go | 55 +-
src/cmd/compile/internal/ssa/writebarrier.go | 278 +
src/cmd/compile/internal/syntax/dumper.go | 212 +
src/cmd/compile/internal/syntax/dumper_test.go | 22 +
src/cmd/compile/internal/syntax/nodes.go | 452 +
src/cmd/compile/internal/syntax/parser.go | 2143 ++
src/cmd/compile/internal/syntax/parser_test.go | 184 +
src/cmd/compile/internal/syntax/printer.go | 942 +
src/cmd/compile/internal/syntax/printer_test.go | 24 +
src/cmd/compile/internal/syntax/scanner.go | 664 +
src/cmd/compile/internal/syntax/scanner_test.go | 355 +
src/cmd/compile/internal/syntax/source.go | 181 +
src/cmd/compile/internal/syntax/syntax.go | 100 +
src/cmd/compile/internal/syntax/tokens.go | 263 +
src/cmd/compile/internal/x86/387.go | 357 +
src/cmd/compile/internal/x86/cgen.go | 159 -
src/cmd/compile/internal/x86/cgen64.go | 598 -
src/cmd/compile/internal/x86/galign.go | 58 +-
src/cmd/compile/internal/x86/ggen.go | 856 +-
src/cmd/compile/internal/x86/gsubr.go | 1844 --
src/cmd/compile/internal/x86/peep.go | 807 -
src/cmd/compile/internal/x86/prog.go | 89 +-
src/cmd/compile/internal/x86/reg.go | 114 -
src/cmd/compile/internal/x86/ssa.go | 918 +
src/cmd/compile/main.go | 25 +-
src/cmd/cover/cover.go | 82 +-
src/cmd/cover/cover_test.go | 23 +-
src/cmd/cover/html.go | 29 +-
src/cmd/cover/profile.go | 23 +
src/cmd/cover/testdata/main.go | 6 +-
src/cmd/cover/testdata/test.go | 43 +
src/cmd/dist/build.go | 59 +-
src/cmd/dist/buildgo.go | 10 +-
src/cmd/dist/buildtool.go | 119 +-
src/cmd/dist/deps.go | 12 +-
src/cmd/dist/test.go | 150 +-
src/cmd/dist/util.go | 5 +
src/cmd/doc/dirs.go | 8 +-
src/cmd/doc/doc_test.go | 68 +-
src/cmd/doc/pkg.go | 327 +-
src/cmd/doc/testdata/pkg.go | 46 +
src/cmd/fix/context.go | 25 +
src/cmd/fix/context_test.go | 42 +
src/cmd/fix/fix.go | 9 +-
src/cmd/fix/gotypes.go | 8 +-
src/cmd/fix/main.go | 9 +-
src/cmd/fix/netipv6zone.go | 8 +-
src/cmd/fix/printerconfig.go | 8 +-
src/cmd/go/alldocs.go | 191 +-
src/cmd/go/bootstrap.go | 3 +
src/cmd/go/bug.go | 209 +
src/cmd/go/build.go | 442 +-
src/cmd/go/build_test.go | 44 +
src/cmd/go/env.go | 43 +-
src/cmd/go/generate.go | 10 +-
src/cmd/go/get.go | 46 +-
src/cmd/go/go_test.go | 850 +-
src/cmd/go/go_windows_test.go | 3 +-
src/cmd/go/help.go | 52 +-
src/cmd/go/http.go | 4 +
src/cmd/go/list.go | 19 +-
src/cmd/go/main.go | 9 +-
src/cmd/go/pkg.go | 262 +-
src/cmd/go/test.go | 158 +-
src/cmd/go/testdata/src/canonical/a/a.go | 3 +
src/cmd/go/testdata/src/canonical/a/vendor/c/c.go | 1 +
src/cmd/go/testdata/src/canonical/b/b.go | 3 +
src/cmd/go/testdata/src/canonical/d/d.go | 3 +
src/cmd/go/testdata/{ => src}/cgocover/p.go | 0
src/cmd/go/testdata/{ => src}/cgocover/p_test.go | 0
.../go/testdata/{cgocover => src/cgocover2}/p.go | 0
src/cmd/go/testdata/src/cgocover2/x_test.go | 10 +
.../go/testdata/{cgocover => src/cgocover3}/p.go | 0
src/cmd/go/testdata/src/cgocover3/p_test.go | 1 +
src/cmd/go/testdata/src/cgocover3/x_test.go | 10 +
src/cmd/go/testdata/src/cgocover4/notcgo.go | 1 +
.../go/testdata/{cgocover => src/cgocover4}/p.go | 0
src/cmd/go/testdata/src/cgocover4/x_test.go | 10 +
src/cmd/go/testdata/src/dupload/dupload.go | 8 +
src/cmd/go/testdata/src/dupload/p/p.go | 1 +
src/cmd/go/testdata/src/dupload/p2/p2.go | 2 +
src/cmd/go/testdata/src/dupload/vendor/p/p.go | 1 +
src/cmd/go/testdata/src/gencycle/gencycle.go | 5 +
src/cmd/go/testdata/src/importmain/ismain/main.go | 5 +
src/cmd/go/testdata/src/importmain/test/test.go | 1 +
.../go/testdata/src/importmain/test/test_test.go | 6 +
src/cmd/go/testdata/src/my.pkg/main/main.go | 5 +
src/cmd/go/testdata/src/my.pkg/pkg.go | 3 +
src/cmd/go/testdata/src/testrace/race_test.go | 29 +
src/cmd/go/testdata/standalone_benchmark_test.go | 6 +
src/cmd/go/testdata/standalone_fail_sub_test.go | 8 +
.../go/testdata/standalone_parallel_sub_test.go | 14 +
src/cmd/go/testdata/standalone_sub_test.go | 7 +
src/cmd/go/testflag.go | 4 +-
src/cmd/go/tool.go | 2 +-
src/cmd/go/vcs.go | 70 +-
src/cmd/go/vcs_test.go | 69 +-
src/cmd/gofmt/doc.go | 5 +-
src/cmd/gofmt/gofmt.go | 52 +-
src/cmd/gofmt/gofmt_test.go | 13 +
src/cmd/gofmt/simplify.go | 60 +-
src/cmd/gofmt/testdata/composites.golden | 14 +
src/cmd/gofmt/testdata/composites.input | 14 +
src/cmd/internal/browser/browser.go | 46 +
src/cmd/internal/dwarf/dwarf.go | 604 +
src/cmd/internal/dwarf/dwarf_defs.go | 483 +
src/cmd/internal/gcprog/gcprog.go | 1 -
src/cmd/internal/goobj/read.go | 108 +-
src/cmd/internal/obj/addrtype_string.go | 27 +
src/cmd/internal/obj/arm/a.out.go | 4 +-
src/cmd/internal/obj/arm/anames.go | 2 +
src/cmd/internal/obj/arm/asm5.go | 79 +-
src/cmd/internal/obj/arm/list5.go | 2 +-
src/cmd/internal/obj/arm/obj5.go | 45 +-
src/cmd/internal/obj/arm64/a.out.go | 20 +-
src/cmd/internal/obj/arm64/anames7.go | 1 +
src/cmd/internal/obj/arm64/asm7.go | 438 +-
src/cmd/internal/obj/arm64/asm_test.go | 62 +
src/cmd/internal/obj/arm64/obj7.go | 150 +-
src/cmd/internal/obj/data.go | 20 +-
src/cmd/internal/obj/ld.go | 4 +-
src/cmd/internal/obj/link.go | 345 +-
src/cmd/internal/obj/mips/a.out.go | 50 +-
src/cmd/internal/obj/mips/anames.go | 13 +
src/cmd/internal/obj/mips/asm0.go | 754 +-
src/cmd/internal/obj/mips/list0.go | 6 +-
src/cmd/internal/obj/mips/obj0.go | 230 +-
src/cmd/internal/obj/obj.go | 1 -
src/cmd/internal/obj/objfile.go | 119 +-
src/cmd/internal/obj/pass.go | 2 +-
src/cmd/internal/obj/pcln.go | 40 +-
src/cmd/internal/obj/plist.go | 82 +-
src/cmd/internal/obj/ppc64/a.out.go | 454 +-
src/cmd/internal/obj/ppc64/anames.go | 244 +
src/cmd/internal/obj/ppc64/anames9.go | 2 +
src/cmd/internal/obj/ppc64/asm9.go | 1260 +-
src/cmd/internal/obj/ppc64/list9.go | 6 +
src/cmd/internal/obj/ppc64/obj9.go | 134 +-
src/cmd/internal/obj/reloctype_string.go | 17 +
src/cmd/internal/obj/s390x/a.out.go | 46 +-
src/cmd/internal/obj/s390x/anames.go | 40 +-
src/cmd/internal/obj/s390x/asmz.go | 644 +-
src/cmd/internal/obj/s390x/objz.go | 96 +-
src/cmd/internal/obj/sizeof_test.go | 6 +-
src/cmd/internal/obj/stack.go | 2 +-
src/cmd/internal/obj/sym.go | 58 +-
src/cmd/internal/obj/symkind_string.go | 16 +
src/cmd/internal/obj/util.go | 92 +-
src/cmd/internal/obj/x86/a.out.go | 10 +-
src/cmd/internal/obj/x86/anames.go | 8 +
src/cmd/internal/obj/x86/asm6.go | 204 +-
src/cmd/internal/obj/x86/list6.go | 2 +-
src/cmd/internal/obj/x86/obj6.go | 158 +-
src/cmd/internal/obj/x86/obj6_test.go | 8 +-
src/cmd/internal/objfile/disasm.go | 56 +-
src/cmd/internal/objfile/elf.go | 4 +
src/cmd/internal/objfile/goobj.go | 71 +-
src/cmd/internal/objfile/objfile.go | 31 +-
src/cmd/internal/pprof/commands/commands.go | 244 -
src/cmd/internal/pprof/driver/driver.go | 1041 -
src/cmd/internal/pprof/driver/interactive.go | 492 -
src/cmd/internal/pprof/fetch/fetch.go | 82 -
src/cmd/internal/pprof/plugin/plugin.go | 213 -
src/cmd/internal/pprof/profile/legacy_profile.go | 1236 -
src/cmd/internal/pprof/profile/profile_test.go | 24 -
src/cmd/internal/pprof/report/report.go | 1684 --
src/cmd/internal/pprof/report/source.go | 454 -
src/cmd/internal/pprof/symbolizer/symbolizer.go | 195 -
src/cmd/internal/pprof/symbolz/symbolz.go | 111 -
src/cmd/internal/sys/arch.go | 36 +
src/cmd/link/doc.go | 2 +
src/cmd/link/internal/amd64/asm.go | 476 +-
src/cmd/link/internal/amd64/l.go | 12 +-
src/cmd/link/internal/amd64/obj.go | 136 +-
src/cmd/link/internal/arm/asm.go | 453 +-
src/cmd/link/internal/arm/l.go | 14 +-
src/cmd/link/internal/arm/obj.go | 115 +-
src/cmd/link/internal/arm64/asm.go | 159 +-
src/cmd/link/internal/arm64/l.go | 12 +-
src/cmd/link/internal/arm64/obj.go | 113 +-
src/cmd/link/internal/ld/ar.go | 17 +-
src/cmd/link/internal/ld/config.go | 250 +
src/cmd/link/internal/ld/data.go | 1330 +-
src/cmd/link/internal/ld/deadcode.go | 87 +-
src/cmd/link/internal/ld/decodesym.go | 186 +-
src/cmd/link/internal/ld/dwarf.go | 1904 +-
src/cmd/link/internal/ld/dwarf_defs.go | 516 -
src/cmd/link/internal/ld/elf.go | 541 +-
src/cmd/link/internal/ld/go.go | 82 +-
src/cmd/link/internal/ld/ld.go | 36 +-
src/cmd/link/internal/ld/ldelf.go | 141 +-
src/cmd/link/internal/ld/ldmacho.go | 114 +-
src/cmd/link/internal/ld/ldpe.go | 397 +-
src/cmd/link/internal/ld/lib.go | 1126 +-
src/cmd/link/internal/ld/link.go | 152 +-
src/cmd/link/internal/ld/macho.go | 234 +-
src/cmd/link/internal/ld/main.go | 264 +
src/cmd/link/internal/ld/objfile.go | 130 +-
src/cmd/link/internal/ld/pcln.go | 188 +-
src/cmd/link/internal/ld/pe.go | 241 +-
src/cmd/link/internal/ld/pobj.go | 227 -
src/cmd/link/internal/ld/sym.go | 120 +-
src/cmd/link/internal/ld/symbols.go | 84 +
src/cmd/link/internal/ld/symtab.go | 482 +-
src/cmd/link/internal/ld/typelink.go | 49 +
src/cmd/link/internal/ld/util.go | 64 +-
src/cmd/link/internal/mips/asm.go | 191 +
src/cmd/link/internal/mips/l.go | 74 +
src/cmd/link/internal/mips/obj.go | 110 +
src/cmd/link/internal/mips64/asm.go | 99 +-
src/cmd/link/internal/mips64/l.go | 12 +-
src/cmd/link/internal/mips64/obj.go | 93 +-
src/cmd/link/internal/ppc64/asm.go | 370 +-
src/cmd/link/internal/ppc64/l.go | 12 +-
src/cmd/link/internal/ppc64/obj.go | 110 +-
src/cmd/link/internal/s390x/asm.go | 295 +-
src/cmd/link/internal/s390x/l.go | 12 +-
src/cmd/link/internal/s390x/obj.go | 55 +-
src/cmd/link/internal/x86/asm.go | 376 +-
src/cmd/link/internal/x86/l.go | 12 +-
src/cmd/link/internal/x86/obj.go | 131 +-
src/cmd/link/linkbig_test.go | 109 +
src/cmd/link/main.go | 37 +-
src/cmd/nm/nm.go | 24 +-
src/cmd/nm/nm_test.go | 2 +-
src/cmd/objdump/objdump_test.go | 73 +-
src/cmd/pack/pack_test.go | 16 +-
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 +
.../pprof => pprof/internal}/report/source_html.go | 0
.../{internal/pprof => pprof/internal}/svg/svg.go | 0
.../pprof => pprof/internal}/svg/svgpan.go | 0
src/cmd/pprof/internal/symbolizer/symbolizer.go | 195 +
src/cmd/pprof/internal/symbolz/symbolz.go | 111 +
.../pprof => pprof/internal}/tempfile/tempfile.go | 0
src/cmd/pprof/pprof.go | 19 +-
src/cmd/trace/main.go | 72 +-
src/cmd/trace/pprof.go | 117 +-
src/cmd/trace/trace.go | 209 +-
src/cmd/trace/trace_test.go | 101 +
.../golang.org/x/arch/ppc64/ppc64asm/decode.go | 179 +
.../x/arch/ppc64/ppc64asm/decode_test.go | 64 +
.../vendor/golang.org/x/arch/ppc64/ppc64asm/doc.go | 6 +
.../golang.org/x/arch/ppc64/ppc64asm/ext_test.go | 535 +
.../golang.org/x/arch/ppc64/ppc64asm/field.go | 84 +
.../golang.org/x/arch/ppc64/ppc64asm/field_test.go | 60 +
.../vendor/golang.org/x/arch/ppc64/ppc64asm/gnu.go | 125 +
.../golang.org/x/arch/ppc64/ppc64asm/inst.go | 344 +
.../x/arch/ppc64/ppc64asm/objdump_test.go | 133 +
.../x/arch/ppc64/ppc64asm/objdumpext_test.go | 255 +
.../golang.org/x/arch/ppc64/ppc64asm/plan9.go | 172 +
.../golang.org/x/arch/ppc64/ppc64asm/tables.go | 5421 +++++
.../x/arch/ppc64/ppc64asm/testdata/decode.txt | 25 +
src/cmd/vendor/vendor.json | 6 +
src/cmd/vet/all/main.go | 332 +
src/cmd/vet/all/whitelist/386.txt | 29 +
src/cmd/vet/all/whitelist/64bit.txt | 13 +
src/cmd/vet/all/whitelist/all.txt | 92 +
src/cmd/vet/all/whitelist/amd64.txt | 35 +
src/cmd/vet/all/whitelist/android_386.txt | 8 +
src/cmd/vet/all/whitelist/android_amd64.txt | 3 +
src/cmd/vet/all/whitelist/android_arm.txt | 5 +
src/cmd/vet/all/whitelist/arm.txt | 26 +
src/cmd/vet/all/whitelist/arm64.txt | 17 +
src/cmd/vet/all/whitelist/darwin_386.txt | 8 +
src/cmd/vet/all/whitelist/darwin_amd64.txt | 4 +
src/cmd/vet/all/whitelist/darwin_arm.txt | 12 +
src/cmd/vet/all/whitelist/darwin_arm64.txt | 14 +
src/cmd/vet/all/whitelist/dragonfly_amd64.txt | 7 +
src/cmd/vet/all/whitelist/freebsd_386.txt | 19 +
src/cmd/vet/all/whitelist/freebsd_amd64.txt | 6 +
src/cmd/vet/all/whitelist/freebsd_arm.txt | 4 +
src/cmd/vet/all/whitelist/linux_386.txt | 13 +
src/cmd/vet/all/whitelist/linux_amd64.txt | 8 +
src/cmd/vet/all/whitelist/linux_arm.txt | 12 +
src/cmd/vet/all/whitelist/linux_arm64.txt | 5 +
src/cmd/vet/all/whitelist/linux_ppc64x.txt | 5 +
src/cmd/vet/all/whitelist/mips64x.txt | 8 +
src/cmd/vet/all/whitelist/nacl_386.txt | 13 +
src/cmd/vet/all/whitelist/nacl_amd64p32.txt | 31 +
src/cmd/vet/all/whitelist/nacl_arm.txt | 8 +
src/cmd/vet/all/whitelist/netbsd.txt | 3 +
src/cmd/vet/all/whitelist/netbsd_386.txt | 23 +
src/cmd/vet/all/whitelist/netbsd_amd64.txt | 3 +
src/cmd/vet/all/whitelist/netbsd_arm.txt | 5 +
src/cmd/vet/all/whitelist/openbsd_386.txt | 17 +
src/cmd/vet/all/whitelist/openbsd_amd64.txt | 3 +
src/cmd/vet/all/whitelist/openbsd_arm.txt | 4 +
src/cmd/vet/all/whitelist/plan9_386.txt | 3 +
src/cmd/vet/all/whitelist/plan9_amd64.txt | 4 +
src/cmd/vet/all/whitelist/plan9_arm.txt | 4 +
src/cmd/vet/all/whitelist/ppc64x.txt | 12 +
src/cmd/vet/all/whitelist/readme.txt | 4 +
src/cmd/vet/all/whitelist/s390x.txt | 19 +
src/cmd/vet/all/whitelist/solaris_amd64.txt | 6 +
src/cmd/vet/all/whitelist/windows.txt | 5 +
src/cmd/vet/all/whitelist/windows_386.txt | 9 +
src/cmd/vet/all/whitelist/windows_amd64.txt | 8 +
src/cmd/vet/asmdecl.go | 465 +-
src/cmd/vet/cgo.go | 5 +
src/cmd/vet/copylock.go | 8 +
src/cmd/vet/doc.go | 21 +-
src/cmd/vet/httpresponse.go | 153 +
src/cmd/vet/main.go | 27 +-
src/cmd/vet/print.go | 83 +-
src/cmd/vet/shift.go | 6 +
src/cmd/vet/structtag.go | 54 +-
src/cmd/vet/testdata/asm.go | 35 -
src/cmd/vet/testdata/asm/asm.go | 45 +
src/cmd/vet/testdata/asm/asm1.s | 315 +
src/cmd/vet/testdata/{ => asm}/asm2.s | 0
src/cmd/vet/testdata/{ => asm}/asm3.s | 0
src/cmd/vet/testdata/{ => asm}/asm4.s | 0
src/cmd/vet/testdata/{ => asm}/asm5.s | 0
src/cmd/vet/testdata/asm/asm6.s | 193 +
src/cmd/vet/testdata/asm/asm7.s | 193 +
src/cmd/vet/testdata/asm1.s | 265 -
src/cmd/vet/testdata/asm8.s | 165 +
src/cmd/vet/testdata/{ => buildtag}/buildtag.go | 0
.../vet/testdata/{ => buildtag}/buildtag_bad.go | 0
src/cmd/vet/testdata/cgo.go | 54 -
src/cmd/vet/testdata/cgo/cgo.go | 56 +
src/cmd/vet/testdata/{ => cgo}/cgo2.go | 0
src/cmd/vet/testdata/copylock.go | 18 +
src/cmd/vet/testdata/httpresponse.go | 85 +
src/cmd/vet/testdata/print.go | 34 +-
src/cmd/vet/testdata/shift.go | 2 +
src/cmd/vet/testdata/structtag.go | 30 +
src/cmd/vet/testdata/testingpkg/tests.go | 1 +
.../vet/testdata/{ => testingpkg}/tests_test.go | 0
src/cmd/vet/testdata/unsafeptr.go | 4 +-
src/cmd/vet/types.go | 14 +-
src/cmd/vet/unsafeptr.go | 2 +-
src/cmd/vet/vet_test.go | 128 +-
src/cmd/yacc/doc.go | 69 -
src/cmd/yacc/testdata/expr/README | 20 -
src/cmd/yacc/testdata/expr/expr.y | 202 -
src/cmd/yacc/testdata/expr/main.go | 15 -
src/cmd/yacc/yacc.go | 3641 ---
src/cmp.bash | 2 +-
src/compress/flate/deflate.go | 20 +-
src/compress/flate/deflate_test.go | 183 +
src/compress/flate/deflatefast.go | 186 +-
src/compress/flate/example_test.go | 243 +
src/compress/flate/flate_test.go | 1 +
src/compress/flate/huffman_bit_writer.go | 2 +-
src/compress/flate/inflate.go | 3 +
src/compress/flate/inflate_test.go | 29 +
src/compress/flate/writer_test.go | 9 +-
src/compress/gzip/example_test.go | 128 +
src/compress/gzip/gunzip.go | 7 +-
src/compress/gzip/gunzip_test.go | 20 +
src/compress/gzip/gzip.go | 23 +-
src/compress/gzip/gzip_test.go | 4 +
src/compress/gzip/issue14937_test.go | 9 +-
src/compress/zlib/reader_test.go | 18 +
src/compress/zlib/writer.go | 11 +-
src/compress/zlib/writer_test.go | 5 +
src/container/heap/heap.go | 9 +-
src/container/list/list_test.go | 6 +-
src/context/benchmark_test.go | 44 +
src/context/context.go | 26 +-
src/context/context_test.go | 84 +-
src/context/example_test.go | 116 +
src/context/net_test.go | 21 +
src/context/withtimeout_test.go | 33 -
src/context/x_test.go | 29 +
src/crypto/aes/aes_gcm.go | 7 +
src/crypto/aes/asm_amd64.s | 11 -
src/crypto/aes/asm_s390x.s | 115 +-
src/crypto/aes/cipher_amd64.go | 4 +-
src/crypto/aes/cipher_s390x.go | 8 +-
src/crypto/aes/gcm_s390x.go | 270 +
src/crypto/cipher/example_test.go | 4 +-
src/crypto/cipher/gcm.go | 8 +
src/crypto/cipher/gcm_test.go | 158 +
src/crypto/ecdsa/ecdsa.go | 2 +-
src/crypto/ecdsa/ecdsa_test.go | 12 +
src/crypto/elliptic/elliptic_test.go | 2 +-
src/crypto/elliptic/p256.go | 28 +-
src/crypto/elliptic/p256_asm_s390x.s | 2201 ++
src/crypto/elliptic/p256_generic.go | 16 +
src/crypto/elliptic/p256_s390x.go | 513 +
src/crypto/hmac/hmac.go | 2 +-
src/crypto/internal/cipherhw/asm_amd64.s | 17 +
src/crypto/internal/cipherhw/asm_s390x.s | 44 +
src/crypto/internal/cipherhw/cipherhw_amd64.go | 16 +
src/crypto/internal/cipherhw/cipherhw_s390x.go | 18 +
src/crypto/internal/cipherhw/doc.go | 7 +
src/crypto/internal/cipherhw/generic.go | 11 +
src/crypto/md5/example_test.go | 17 +
src/crypto/md5/md5block_amd64p32.s | 2 +-
src/crypto/rand/util_test.go | 9 +
src/crypto/rc4/rc4_arm.s | 4 +-
src/crypto/rsa/rsa.go | 23 +-
src/crypto/rsa/rsa_test.go | 11 +
src/crypto/sha1/example_test.go | 17 +
src/crypto/sha1/sha1.go | 70 +-
src/crypto/sha1/sha1_test.go | 17 +-
src/crypto/sha1/sha1block_amd64.go | 2 +-
src/crypto/sha1/sha1block_amd64p32.s | 2 +-
src/crypto/sha256/example_test.go | 41 +
src/crypto/sha256/sha256block_386.s | 2 +-
src/crypto/sha256/sha256block_amd64.s | 4 +-
src/crypto/sha256/sha256block_decl.go | 2 +-
src/crypto/sha256/sha256block_generic.go | 2 +-
src/crypto/sha256/sha256block_ppc64le.s | 269 +
src/crypto/sha512/sha512block_decl.go | 2 +-
src/crypto/sha512/sha512block_generic.go | 2 +-
src/crypto/sha512/sha512block_ppc64le.s | 293 +
src/crypto/tls/alert.go | 2 +
src/crypto/tls/cipher_suites.go | 155 +-
src/crypto/tls/common.go | 230 +-
src/crypto/tls/conn.go | 144 +-
src/crypto/tls/conn_test.go | 22 +-
src/crypto/tls/example_test.go | 58 +
src/crypto/tls/handshake_client.go | 198 +-
src/crypto/tls/handshake_client_test.go | 538 +-
src/crypto/tls/handshake_messages.go | 7 +-
src/crypto/tls/handshake_messages_test.go | 63 +
src/crypto/tls/handshake_server.go | 130 +-
src/crypto/tls/handshake_server_test.go | 307 +-
src/crypto/tls/handshake_test.go | 71 +-
src/crypto/tls/key_agreement.go | 156 +-
.../testdata/Client-TLSv10-ClientCert-ECDSA-ECDSA | 112 +-
.../testdata/Client-TLSv10-ClientCert-ECDSA-RSA | 175 +-
.../testdata/Client-TLSv10-ClientCert-RSA-ECDSA | 176 +-
.../tls/testdata/Client-TLSv10-ClientCert-RSA-RSA | 239 +-
.../tls/testdata/Client-TLSv10-ECDHE-ECDSA-AES | 93 +-
.../tls/testdata/Client-TLSv10-ECDHE-RSA-AES | 168 +-
src/crypto/tls/testdata/Client-TLSv10-RSA-RC4 | 145 +-
.../tls/testdata/Client-TLSv11-ECDHE-ECDSA-AES | 95 +-
.../tls/testdata/Client-TLSv11-ECDHE-RSA-AES | 170 +-
src/crypto/tls/testdata/Client-TLSv11-RSA-RC4 | 145 +-
.../tls/testdata/Client-TLSv12-AES128-GCM-SHA256 | 149 +-
.../tls/testdata/Client-TLSv12-AES128-SHA256 | 89 +
.../tls/testdata/Client-TLSv12-AES256-GCM-SHA384 | 149 +-
src/crypto/tls/testdata/Client-TLSv12-ALPN | 165 +-
src/crypto/tls/testdata/Client-TLSv12-ALPN-NoMatch | 158 +-
.../testdata/Client-TLSv12-ClientCert-ECDSA-ECDSA | 119 +-
.../testdata/Client-TLSv12-ClientCert-ECDSA-RSA | 177 +-
.../Client-TLSv12-ClientCert-RSA-AES256-GCM-SHA384 | 250 +-
.../testdata/Client-TLSv12-ClientCert-RSA-ECDSA | 183 +-
.../tls/testdata/Client-TLSv12-ClientCert-RSA-RSA | 240 +-
.../tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES | 95 +-
.../tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES-GCM | 87 +-
.../Client-TLSv12-ECDHE-ECDSA-AES128-SHA256 | 91 +
.../Client-TLSv12-ECDHE-ECDSA-AES256-GCM-SHA384 | 87 +-
.../Client-TLSv12-ECDHE-ECDSA-CHACHA20-POLY1305 | 77 +
.../tls/testdata/Client-TLSv12-ECDHE-RSA-AES | 170 +-
.../testdata/Client-TLSv12-ECDHE-RSA-AES128-SHA256 | 95 +
.../Client-TLSv12-ECDHE-RSA-CHACHA20-POLY1305 | 81 +
src/crypto/tls/testdata/Client-TLSv12-RSA-RC4 | 145 +-
.../tls/testdata/Client-TLSv12-RenegotiateOnce | 456 +-
.../tls/testdata/Client-TLSv12-RenegotiateTwice | 751 +-
.../Client-TLSv12-RenegotiateTwiceRejected | 463 +-
.../testdata/Client-TLSv12-RenegotiationRejected | 168 +-
src/crypto/tls/testdata/Client-TLSv12-SCT | 162 +-
.../Client-TLSv12-X25519-ECDHE-RSA-AES-GCM | 85 +
src/crypto/tls/testdata/Server-SSLv3-RSA-3DES | 140 +-
src/crypto/tls/testdata/Server-SSLv3-RSA-AES | 142 +-
src/crypto/tls/testdata/Server-SSLv3-RSA-RC4 | 132 +-
.../tls/testdata/Server-TLSv10-ECDHE-ECDSA-AES | 81 +-
src/crypto/tls/testdata/Server-TLSv10-RSA-3DES | 132 +-
src/crypto/tls/testdata/Server-TLSv10-RSA-AES | 138 +-
src/crypto/tls/testdata/Server-TLSv10-RSA-RC4 | 126 +-
src/crypto/tls/testdata/Server-TLSv11-FallbackSCSV | 21 +-
src/crypto/tls/testdata/Server-TLSv11-RSA-RC4 | 126 +-
src/crypto/tls/testdata/Server-TLSv12-ALPN | 181 +-
src/crypto/tls/testdata/Server-TLSv12-ALPN-NoMatch | 182 +-
.../Server-TLSv12-CipherSuiteCertPreferenceECDSA | 97 +-
.../Server-TLSv12-CipherSuiteCertPreferenceRSA | 173 +-
.../Server-TLSv12-ClientAuthRequestedAndECDSAGiven | 163 +-
.../Server-TLSv12-ClientAuthRequestedAndGiven | 227 +-
.../Server-TLSv12-ClientAuthRequestedNotGiven | 145 +-
.../tls/testdata/Server-TLSv12-ECDHE-ECDSA-AES | 83 +-
src/crypto/tls/testdata/Server-TLSv12-IssueTicket | 154 +-
.../testdata/Server-TLSv12-IssueTicketPreDisable | 154 +-
src/crypto/tls/testdata/Server-TLSv12-RSA-3DES | 137 +-
src/crypto/tls/testdata/Server-TLSv12-RSA-AES | 141 +-
src/crypto/tls/testdata/Server-TLSv12-RSA-AES-GCM | 149 +-
.../testdata/Server-TLSv12-RSA-AES256-GCM-SHA384 | 149 +-
src/crypto/tls/testdata/Server-TLSv12-RSA-RC4 | 131 +-
src/crypto/tls/testdata/Server-TLSv12-Resume | 64 +-
.../tls/testdata/Server-TLSv12-ResumeDisabled | 160 +-
src/crypto/tls/testdata/Server-TLSv12-SNI | 131 +-
.../tls/testdata/Server-TLSv12-SNI-GetCertificate | 131 +-
.../Server-TLSv12-SNI-GetCertificateNotFound | 131 +-
.../Server-TLSv12-X25519-ECDHE-RSA-AES-GCM | 79 +
src/crypto/tls/tls.go | 6 +-
src/crypto/tls/tls_test.go | 150 +-
src/crypto/x509/cert_pool.go | 15 +-
src/crypto/x509/pkix/pkix.go | 56 +-
src/crypto/x509/root_cgo_darwin.go | 83 +-
src/crypto/x509/root_darwin.go | 114 +-
src/crypto/x509/root_darwin_test.go | 1 -
src/crypto/x509/root_linux.go | 9 +-
src/crypto/x509/root_windows.go | 35 +-
src/crypto/x509/verify.go | 76 +-
src/crypto/x509/verify_test.go | 309 +-
src/crypto/x509/x509.go | 218 +-
src/crypto/x509/x509_test.go | 224 +-
src/database/sql/convert.go | 72 +-
src/database/sql/convert_test.go | 83 +
src/database/sql/ctxutil.go | 156 +
src/database/sql/driver/driver.go | 197 +-
src/database/sql/driver/types.go | 42 +-
src/database/sql/driver/types_test.go | 16 +
src/database/sql/example_test.go | 62 +
src/database/sql/fakedb_test.go | 375 +-
src/database/sql/internal/types.go | 11 +
src/database/sql/sql.go | 909 +-
src/database/sql/sql_test.go | 476 +-
src/debug/elf/file.go | 89 +-
src/debug/elf/file_test.go | 57 +
.../testdata/go-relocation-test-gcc492-mipsle.obj | Bin 0 -> 2864 bytes
.../testdata/go-relocation-test-gcc540-mips.obj | Bin 0 -> 3064 bytes
.../testdata/go-relocation-test-gcc620-sparc64.obj | Bin 0 -> 5952 bytes
src/debug/gosym/pclntab.go | 10 +-
src/debug/gosym/pclntab_test.go | 4 +-
src/debug/macho/macho.go | 2 +-
src/debug/pe/file.go | 21 +-
src/debug/pe/file_test.go | 2 +-
src/debug/pe/section.go | 14 +-
src/debug/pe/string.go | 14 +-
src/debug/pe/symbol.go | 13 +-
src/encoding/asn1/asn1.go | 9 +-
src/encoding/asn1/asn1_test.go | 41 +-
src/encoding/asn1/marshal.go | 621 +-
src/encoding/asn1/marshal_test.go | 34 +
src/encoding/base64/base64.go | 24 +-
src/encoding/base64/base64_test.go | 21 +
src/encoding/binary/binary.go | 59 +-
src/encoding/binary/binary_test.go | 39 +-
src/encoding/csv/reader.go | 68 +-
src/encoding/csv/reader_test.go | 72 +-
src/encoding/gob/encoder.go | 3 +
src/encoding/gob/encoder_test.go | 14 +
src/encoding/hex/example_test.go | 98 +
src/encoding/hex/hex.go | 15 +-
src/encoding/hex/hex_test.go | 16 +
src/encoding/json/decode.go | 129 +-
src/encoding/json/decode_test.go | 297 +-
src/encoding/json/encode.go | 132 +-
src/encoding/json/encode_test.go | 273 +-
src/encoding/json/example_marshaling_test.go | 73 +
src/encoding/json/example_test.go | 26 +-
src/encoding/json/scanner_test.go | 1 +
src/encoding/json/stream.go | 9 +-
src/encoding/json/tables.go | 218 +
src/encoding/json/tagkey_test.go | 5 +
src/encoding/pem/example_test.go | 44 +
src/encoding/pem/pem.go | 19 +-
src/encoding/pem/pem_test.go | 42 +
src/encoding/xml/marshal.go | 180 +-
src/encoding/xml/marshal_test.go | 91 +-
src/encoding/xml/read.go | 92 +-
src/encoding/xml/read_test.go | 21 +-
src/encoding/xml/typeinfo.go | 8 +-
src/expvar/expvar.go | 27 +
src/expvar/expvar_test.go | 28 +-
src/flag/export_test.go | 1 +
src/flag/flag.go | 37 +-
src/fmt/doc.go | 70 +-
src/fmt/export_test.go | 1 +
src/fmt/fmt_test.go | 28 +-
src/fmt/format.go | 2 +-
src/fmt/print.go | 8 +
src/fmt/scan.go | 96 +-
src/fmt/scan_test.go | 143 +-
src/go/ast/ast.go | 4 +-
src/go/build/build.go | 67 +-
src/go/build/build_test.go | 12 +
src/go/build/deps_test.go | 140 +-
src/go/build/doc.go | 1 +
src/go/build/syslist.go | 2 +-
src/go/build/testdata/ignored/ignored.go | 3 +
src/go/constant/value.go | 40 +-
src/go/doc/comment.go | 2 +-
src/go/doc/comment_test.go | 1 +
src/go/doc/reader.go | 24 +-
src/go/doc/testdata/issue17788.0.golden | 8 +
src/go/doc/testdata/issue17788.1.golden | 8 +
src/go/doc/testdata/issue17788.2.golden | 8 +
src/go/doc/testdata/issue17788.go | 8 +
src/go/doc/testdata/predeclared.0.golden | 8 +
src/go/doc/testdata/predeclared.1.golden | 22 +
src/go/doc/testdata/predeclared.2.golden | 8 +
src/go/doc/testdata/predeclared.go | 22 +
src/go/format/format_test.go | 27 +
src/go/internal/gccgoimporter/importer.go | 5 +-
src/go/internal/gccgoimporter/importer_test.go | 1 +
src/go/internal/gccgoimporter/parser.go | 40 +-
.../internal/gccgoimporter/testdata/conversions.go | 5 +
.../gccgoimporter/testdata/conversions.gox | 6 +
src/go/internal/gcimporter/bimport.go | 288 +-
src/go/internal/gcimporter/exportdata.go | 10 +-
src/go/internal/gcimporter/gcimporter.go | 881 +-
src/go/internal/gcimporter/gcimporter_test.go | 85 +-
src/go/internal/gcimporter/testdata/exports.go | 7 +-
.../internal/gcimporter/testdata/versions/test.go | 25 +
.../gcimporter/testdata/versions/test_go1.7_0.a | Bin 0 -> 1862 bytes
.../gcimporter/testdata/versions/test_go1.7_1.a | Bin 0 -> 2316 bytes
src/go/printer/printer.go | 38 +-
src/go/printer/printer_test.go | 55 +-
src/go/printer/testdata/comments.golden | 26 +
src/go/printer/testdata/comments.input | 18 +
src/go/scanner/scanner.go | 6 +-
src/go/scanner/scanner_test.go | 1 +
src/go/token/position.go | 2 +
src/go/token/position_test.go | 31 +-
src/go/types/api.go | 13 +-
src/go/types/api_test.go | 392 +-
src/go/types/assignments.go | 4 +-
src/go/types/builtins.go | 6 +-
src/go/types/call.go | 27 +-
src/go/types/check.go | 1 -
src/go/types/check_test.go | 2 +
src/go/types/conversions.go | 11 +-
src/go/types/decl.go | 104 +
src/go/types/expr.go | 41 +-
src/go/types/initorder.go | 230 +-
src/go/types/object.go | 53 +-
src/go/types/ordering.go | 20 +-
src/go/types/predicates.go | 35 +-
src/go/types/resolver.go | 22 +-
src/go/types/sizes.go | 51 +-
src/go/types/sizes_test.go | 112 +
src/go/types/stdlib_test.go | 1 +
src/go/types/stmt.go | 26 +-
src/go/types/testdata/conversions2.src | 313 +
src/go/types/testdata/expr3.src | 24 +
src/go/types/testdata/stmt0.src | 12 +-
src/go/types/type.go | 11 +-
src/go/types/typexpr.go | 25 +-
src/hash/crc32/crc32.go | 160 +-
src/hash/crc32/crc32_amd64.go | 214 +-
src/hash/crc32/crc32_amd64.s | 116 +-
src/hash/crc32/crc32_amd64p32.go | 37 +-
src/hash/crc32/crc32_generic.go | 92 +-
src/hash/crc32/crc32_otherarch.go | 15 +
src/hash/crc32/crc32_s390x.go | 81 +-
src/hash/crc32/crc32_test.go | 215 +-
src/html/template/clone_test.go | 68 +
src/html/template/content_test.go | 41 +
src/html/template/context.go | 14 +-
src/html/template/doc.go | 2 +-
src/html/template/error.go | 2 +-
src/html/template/escape.go | 14 +-
src/html/template/escape_test.go | 14 +-
src/html/template/js.go | 42 +-
src/html/template/js_test.go | 18 +
src/html/template/template.go | 81 +-
src/html/template/template_test.go | 130 +-
src/html/template/transition.go | 30 +-
src/html/template/url.go | 2 +-
src/image/color/color.go | 23 +-
src/image/color/ycbcr.go | 94 +-
src/image/color/ycbcr_test.go | 63 +-
src/image/draw/bench_test.go | 2 +-
src/image/draw/draw.go | 16 +-
src/image/draw/example_test.go | 48 +
src/image/gif/reader.go | 83 +-
src/image/gif/reader_test.go | 17 +
src/image/png/example_test.go | 77 +
src/image/png/reader.go | 266 +-
src/image/png/reader_test.go | 175 +-
src/image/png/testdata/pngsuite/README | 21 +-
src/image/png/testdata/pngsuite/ftbbn0g01.png | Bin 0 -> 176 bytes
src/image/png/testdata/pngsuite/ftbbn0g01.sng | 44 +
src/image/png/testdata/pngsuite/ftbbn0g02.png | Bin 0 -> 197 bytes
src/image/png/testdata/pngsuite/ftbbn0g02.sng | 45 +
src/image/png/testdata/pngsuite/ftbbn0g04.png | Bin 0 -> 429 bytes
src/image/png/testdata/pngsuite/ftbbn0g04.sng | 45 +
src/image/png/testdata/pngsuite/ftbbn2c16.png | Bin 0 -> 2041 bytes
src/image/png/testdata/pngsuite/ftbbn2c16.sng | 45 +
src/image/png/testdata/pngsuite/ftbbn3p08.png | Bin 0 -> 1499 bytes
src/image/png/testdata/pngsuite/ftbbn3p08.sng | 292 +
src/image/png/testdata/pngsuite/ftbgn2c16.png | Bin 0 -> 2041 bytes
src/image/png/testdata/pngsuite/ftbgn2c16.sng | 45 +
src/image/png/testdata/pngsuite/ftbgn3p08.png | Bin 0 -> 1499 bytes
src/image/png/testdata/pngsuite/ftbgn3p08.sng | 292 +
src/image/png/testdata/pngsuite/ftbrn2c08.png | Bin 0 -> 1633 bytes
src/image/png/testdata/pngsuite/ftbrn2c08.sng | 45 +
src/image/png/testdata/pngsuite/ftbwn0g16.png | Bin 0 -> 1313 bytes
src/image/png/testdata/pngsuite/ftbwn0g16.sng | 45 +
src/image/png/testdata/pngsuite/ftbwn3p08.png | Bin 0 -> 1496 bytes
src/image/png/testdata/pngsuite/ftbwn3p08.sng | 291 +
src/image/png/testdata/pngsuite/ftbyn3p08.png | Bin 0 -> 1499 bytes
src/image/png/testdata/pngsuite/ftbyn3p08.sng | 292 +
src/image/png/testdata/pngsuite/ftp0n0g08.png | Bin 0 -> 719 bytes
src/image/png/testdata/pngsuite/ftp0n0g08.sng | 41 +
src/image/png/testdata/pngsuite/ftp0n2c08.png | Bin 0 -> 1594 bytes
src/image/png/testdata/pngsuite/ftp0n2c08.sng | 41 +
src/image/png/testdata/pngsuite/ftp0n3p08.png | Bin 0 -> 1476 bytes
src/image/png/testdata/pngsuite/ftp0n3p08.sng | 288 +
src/image/png/testdata/pngsuite/ftp1n3p08.png | Bin 0 -> 1483 bytes
src/image/png/testdata/pngsuite/ftp1n3p08.sng | 290 +
src/image/png/writer.go | 5 +-
src/index/suffixarray/example_test.go | 22 +
src/{cmd => }/internal/pprof/profile/encode.go | 0
src/{cmd => }/internal/pprof/profile/filter.go | 0
src/internal/pprof/profile/legacy_profile.go | 1266 +
src/{cmd => }/internal/pprof/profile/profile.go | 0
src/internal/pprof/profile/profile_test.go | 79 +
src/{cmd => }/internal/pprof/profile/proto.go | 0
src/{cmd => }/internal/pprof/profile/proto_test.go | 0
src/{cmd => }/internal/pprof/profile/prune.go | 0
src/internal/race/norace.go | 2 +
src/internal/race/race.go | 4 +
src/internal/syscall/unix/getrandom_linux_mipsx.go | 11 +
src/internal/syscall/windows/mksyscall.go | 7 +
src/internal/syscall/windows/registry/mksyscall.go | 7 +
src/internal/syscall/windows/registry/syscall.go | 2 -
.../syscall/windows/registry/zsyscall_windows.go | 27 +-
src/internal/syscall/windows/reparse_windows.go | 64 +
src/internal/syscall/windows/security_windows.go | 57 +
src/internal/syscall/windows/syscall_windows.go | 26 +-
src/internal/syscall/windows/zsyscall_windows.go | 174 +-
src/internal/testenv/testenv.go | 52 +-
src/internal/testenv/testenv_notwin.go | 20 +
src/internal/testenv/testenv_windows.go | 49 +
src/internal/trace/goroutines.go | 6 +-
src/internal/trace/mkcanned.bash | 19 +
src/internal/trace/order.go | 5 +-
src/internal/trace/parser.go | 33 +-
src/internal/trace/parser_test.go | 47 +-
src/internal/trace/testdata/http_1_7_good | Bin 0 -> 1971 bytes
src/internal/trace/testdata/stress_1_7_good | Bin 0 -> 396526 bytes
.../trace/testdata/stress_start_stop_1_7_good | Bin 0 -> 2055 bytes
src/internal/trace/writer.go | 45 +
src/io/io.go | 7 +-
src/io/ioutil/ioutil.go | 9 +-
src/io/ioutil/tempfile.go | 5 +
src/io/ioutil/tempfile_test.go | 16 +
src/io/multi.go | 1 +
src/io/multi_test.go | 32 +-
src/io/pipe.go | 18 +-
src/log/log.go | 2 +
src/log/syslog/doc.go | 2 +-
src/log/syslog/example_test.go | 23 +
src/log/syslog/syslog.go | 2 +
src/log/syslog/syslog_test.go | 5 +-
src/make.bash | 2 +
src/make.rc | 2 +-
src/math/all_test.go | 145 +-
src/math/arith_s390x.go | 29 +
src/math/arith_s390x_test.go | 144 +
src/math/big/arith_amd64.s | 35 +
src/math/big/arith_decl_s390x.go | 23 +
src/math/big/arith_mipsx.s | 46 +
src/math/big/arith_ppc64.s | 14 +
src/math/big/arith_ppc64le.s | 50 +
src/math/big/arith_ppc64x.s | 178 +-
src/math/big/arith_s390x.s | 1230 +-
src/math/big/arith_s390x_test.go | 44 +
src/math/big/arith_test.go | 13 +
src/math/big/decimal.go | 7 +-
src/math/big/decimal_test.go | 22 +-
src/math/big/doc.go | 2 +-
src/math/big/example_test.go | 13 +
src/math/big/float.go | 44 +-
src/math/big/float_test.go | 47 +-
src/math/big/floatconv.go | 24 +-
src/math/big/floatconv_test.go | 52 +
src/math/big/floatexample_test.go | 6 +-
src/math/big/floatmarsh.go | 2 +-
src/math/big/ftoa.go | 2 +
src/math/big/gcd_test.go | 3 +
src/math/big/int.go | 39 +-
src/math/big/int_test.go | 173 +-
src/math/big/intconv.go | 4 +
src/math/big/intmarsh.go | 6 +-
src/math/big/nat.go | 176 +-
src/math/big/natconv_test.go | 6 +
src/math/big/prime.go | 320 +
src/math/big/prime_test.go | 214 +
src/math/big/rat_test.go | 12 +-
src/math/big/ratconv.go | 16 +-
src/math/big/ratconv_test.go | 11 +-
src/math/cmplx/cmath_test.go | 8 +
src/math/cmplx/example_test.go | 28 +
src/math/cmplx/tan.go | 12 +-
src/math/cosh_s390x.s | 227 +
src/math/dim_arm64.s | 78 +
src/math/exp_386.s | 36 +-
src/math/expm1.go | 2 +-
src/math/export_s390x_test.go | 14 +
src/math/floor_arm64.s | 26 +
src/math/floor_ppc64x.s | 25 +
src/math/floor_s390x.s | 26 +
src/math/gamma.go | 43 +-
src/math/j0.go | 38 +-
src/math/j1.go | 38 +-
src/math/jn.go | 2 +-
src/math/log10_s390x.s | 170 +
src/math/log1p.go | 7 +-
src/math/modf_386.s | 12 +-
src/math/modf_arm64.s | 18 +
src/math/rand/gen_cooked.go | 89 +
src/math/rand/race_test.go | 1 +
src/math/rand/rand.go | 42 +-
src/math/rand/rand_test.go | 15 +-
src/math/rand/regress_test.go | 20 +
src/math/rand/rng.go | 295 +-
src/math/sin.go | 8 +-
src/math/sin_s390x.s | 356 +
src/math/sincos.go | 4 +-
src/math/sinh.go | 8 +-
src/math/sinh_s390x.s | 261 +
src/math/sinh_stub.s | 17 +
src/math/sqrt_amd64.s | 5 +-
src/math/sqrt_mipsx.s | 14 +
src/math/stubs_arm64.s | 30 +-
src/math/stubs_mips64x.s | 9 +
src/math/stubs_mipsx.s | 98 +
src/math/stubs_ppc64x.s | 18 +-
src/math/stubs_s390x.s | 167 +-
src/math/tan.go | 4 +-
src/math/tanh.go | 4 +-
src/math/tanh_s390x.s | 173 +
src/mime/mediatype.go | 37 +-
src/mime/mediatype_test.go | 14 +-
src/mime/multipart/multipart.go | 219 +-
src/mime/multipart/multipart_test.go | 69 +
src/mime/quotedprintable/example_test.go | 37 +
src/mime/quotedprintable/reader.go | 13 +-
src/mime/quotedprintable/reader_test.go | 16 +-
src/net/cgo_unix.go | 5 +
src/net/conf.go | 26 +-
src/net/conf_test.go | 114 +-
src/net/dial.go | 31 +-
src/net/dial_test.go | 17 +
src/net/dnsclient.go | 16 +-
src/net/dnsclient_unix.go | 43 +-
src/net/dnsclient_unix_test.go | 84 +-
src/net/dnsconfig_unix.go | 25 +-
src/net/dnsconfig_unix_test.go | 83 +
src/net/dnsmsg.go | 2 +-
src/net/dnsmsg_test.go | 6 +-
src/net/dnsname_test.go | 27 +-
src/net/error_test.go | 21 +-
src/net/example_test.go | 13 +
src/net/fd_io_plan9.go | 93 +
src/net/fd_plan9.go | 149 +-
src/net/fd_poll_nacl.go | 2 +
src/net/fd_poll_runtime.go | 4 +-
src/net/fd_unix.go | 15 +-
src/net/fd_windows.go | 66 +-
src/net/file.go | 3 +
src/net/file_plan9.go | 2 +-
src/net/http/client.go | 349 +-
src/net/http/client_test.go | 623 +-
src/net/http/clientserver_test.go | 169 +-
src/net/http/cookie.go | 66 +-
src/net/http/cookie_test.go | 98 +
src/net/http/cookiejar/dummy_publicsuffix_test.go | 21 +
src/net/http/cookiejar/example_test.go | 65 +
src/net/http/cookiejar/jar.go | 33 +-
src/net/http/doc.go | 30 +-
src/net/http/export_test.go | 39 +
src/net/http/fcgi/fcgi.go | 6 +-
src/net/http/fs.go | 339 +-
src/net/http/fs_test.go | 162 +-
src/net/http/h2_bundle.go | 2040 +-
src/net/http/header.go | 6 +-
src/net/http/http.go | 98 +
src/net/http/http_test.go | 20 +-
src/net/http/httptest/example_test.go | 16 +-
src/net/http/httptest/httptest.go | 3 +
src/net/http/httptest/recorder.go | 58 +-
src/net/http/httptest/recorder_test.go | 22 +-
src/net/http/httptest/server.go | 15 +-
src/net/http/httptrace/example_test.go | 29 +
src/net/http/httptrace/trace.go | 28 +-
src/net/http/httptrace/trace_test.go | 29 +-
src/net/http/httputil/persist.go | 9 +-
src/net/http/httputil/reverseproxy.go | 149 +-
src/net/http/httputil/reverseproxy_test.go | 179 +-
src/net/http/internal/chunked.go | 30 +-
src/net/http/internal/chunked_test.go | 27 +
src/net/http/main_test.go | 21 +
src/net/http/npn_test.go | 1 +
src/net/http/range_test.go | 2 +-
src/net/http/readrequest_test.go | 26 +-
src/net/http/request.go | 165 +-
src/net/http/request_test.go | 198 +-
src/net/http/requestwrite_test.go | 82 +-
src/net/http/response.go | 4 +-
src/net/http/response_test.go | 35 +-
src/net/http/responsewrite_test.go | 21 +-
src/net/http/serve_test.go | 521 +-
src/net/http/server.go | 715 +-
src/net/http/sniff_test.go | 2 +
src/net/http/transfer.go | 73 +-
src/net/http/transport.go | 266 +-
src/net/http/transport_internal_test.go | 67 +
src/net/http/transport_test.go | 381 +-
src/net/interface.go | 24 +-
src/net/interface_plan9.go | 198 +
src/net/interface_solaris.go | 107 +
src/net/interface_stub.go | 2 +-
src/net/interface_test.go | 11 +-
src/net/ip.go | 92 +-
src/net/ip_test.go | 16 +-
src/net/iprawsock.go | 11 +-
src/net/iprawsock_posix.go | 4 +
src/net/ipsock.go | 54 +-
src/net/ipsock_plan9.go | 60 +-
src/net/ipsock_posix.go | 3 +
src/net/ipsock_test.go | 14 +-
src/net/lookup.go | 275 +-
src/net/lookup_nacl.go | 52 +
src/net/lookup_plan9.go | 37 +-
src/net/lookup_stub.go | 52 -
src/net/lookup_test.go | 78 +-
src/net/lookup_unix.go | 37 +-
src/net/lookup_windows.go | 59 +-
src/net/lookup_windows_test.go | 4 +-
src/net/mail/message.go | 15 +-
src/net/mail/message_test.go | 23 +-
src/net/main_test.go | 2 +
src/net/net.go | 122 +-
src/net/net_test.go | 104 +-
src/net/parse.go | 58 +-
src/net/parse_test.go | 7 +-
src/net/port_unix.go | 27 +-
src/net/rpc/client.go | 2 +
src/net/rpc/client_test.go | 4 -
src/net/rpc/server.go | 6 +-
src/net/rpc/server_test.go | 3 +-
src/net/smtp/smtp.go | 5 +-
src/net/smtp/smtp_test.go | 71 +-
src/net/sock_linux.go | 2 +-
src/net/sock_posix.go | 3 +
src/net/tcpsock.go | 10 +-
src/net/tcpsock_posix.go | 4 +
src/net/tcpsock_test.go | 120 +-
src/net/tcpsock_unix_test.go | 4 +-
src/net/testdata/invalid-ndots-resolv.conf | 1 +
src/net/testdata/large-ndots-resolv.conf | 1 +
src/net/testdata/negative-ndots-resolv.conf | 1 +
src/net/textproto/header.go | 4 +-
src/net/timeout_test.go | 47 +-
src/net/udpsock.go | 14 +-
src/net/udpsock_plan9.go | 38 +-
src/net/udpsock_plan9_test.go | 69 +
src/net/udpsock_posix.go | 4 +
src/net/unixsock.go | 14 +-
src/net/unixsock_posix.go | 25 +-
src/net/unixsock_test.go | 124 +-
src/net/url/example_test.go | 19 +
src/net/url/url.go | 185 +-
src/net/url/url_test.go | 327 +-
src/net/writev_test.go | 225 +
src/net/writev_unix.go | 95 +
src/os/dir.go | 46 +
src/os/dir_unix.go | 27 +
src/os/dir_windows.go | 64 +
src/os/doc.go | 139 -
src/os/env.go | 3 +-
src/os/env_test.go | 28 +
src/os/env_unix_test.go | 26 +
src/os/error.go | 14 +
src/os/error_plan9.go | 48 +-
src/os/error_test.go | 2 +
src/os/error_unix.go | 33 +-
src/os/error_windows.go | 34 +-
src/os/error_windows_test.go | 4 +
src/os/example_test.go | 106 +
src/os/exec.go | 87 +
src/os/exec/example_test.go | 62 +
src/os/exec/exec.go | 63 +-
src/os/exec/exec_test.go | 50 +-
src/os/exec_windows.go | 4 +-
src/os/executable.go | 23 +
src/os/executable_darwin.go | 24 +
src/os/executable_freebsd.go | 33 +
src/os/executable_plan9.go | 19 +
src/os/executable_procfs.go | 36 +
src/os/executable_solaris.go | 27 +
src/os/executable_test.go | 87 +
src/os/executable_windows.go | 32 +
src/os/export_windows_test.go | 13 +
src/os/file.go | 45 +-
src/os/file_plan9.go | 14 +-
src/os/file_posix.go | 22 +-
src/os/file_unix.go | 97 +-
src/os/file_windows.go | 247 +-
src/os/os_test.go | 145 +-
src/os/os_unix_test.go | 39 +
src/os/os_windows_test.go | 555 +-
src/os/path_test.go | 10 +-
src/os/path_unix.go | 18 +
src/os/path_windows.go | 190 +
src/os/path_windows_test.go | 46 +
src/os/signal/doc.go | 9 +-
src/os/signal/signal_windows_test.go | 3 +-
src/os/stat_plan9.go | 10 +-
src/os/stat_unix.go | 52 +
src/os/stat_windows.go | 98 +-
src/os/sys.go | 10 +
src/os/types.go | 5 +
src/os/types_plan9.go | 13 +-
src/os/types_unix.go | 6 +
src/os/wait_wait6.go | 1 +
src/os/wait_waitid.go | 2 +-
src/path/filepath/match.go | 18 +-
src/path/filepath/match_test.go | 11 +-
src/path/filepath/path.go | 11 +-
src/path/filepath/path_test.go | 103 +-
src/path/filepath/path_unix.go | 2 +
src/path/filepath/path_windows.go | 8 +-
src/path/filepath/path_windows_test.go | 72 +-
src/path/filepath/symlink.go | 5 +-
src/path/path.go | 2 +
src/plugin/plugin.go | 73 +
src/plugin/plugin_dlopen.go | 138 +
src/plugin/plugin_stubs.go | 17 +
src/reflect/all_test.go | 246 +-
src/reflect/asm_mipsx.s | 34 +
src/reflect/deepequal.go | 11 +-
src/reflect/export_test.go | 4 +
src/reflect/makefunc.go | 2 +
src/reflect/swapper.go | 74 +
src/reflect/type.go | 147 +-
src/reflect/value.go | 18 +-
src/regexp/all_test.go | 124 +-
src/regexp/exec.go | 31 +-
src/regexp/exec_test.go | 6 +
src/regexp/onepass.go | 5 -
src/regexp/regexp.go | 56 +-
src/runtime/HACKING.md | 135 +
src/runtime/alg.go | 10 +-
src/runtime/append_test.go | 16 +
src/runtime/asm.s | 3 -
src/runtime/asm_386.s | 103 +-
src/runtime/asm_amd64.s | 174 +-
src/runtime/asm_amd64p32.s | 94 +-
src/runtime/asm_arm.s | 95 +-
src/runtime/asm_arm64.s | 104 +-
src/runtime/asm_mips64x.s | 105 +-
src/runtime/asm_mipsx.s | 794 +
src/runtime/asm_ppc64x.s | 366 +-
src/runtime/asm_s390x.s | 462 +-
src/runtime/atomic_mipsx.s | 11 +
src/runtime/atomic_pointer.go | 23 +-
src/runtime/cgo/asm_arm64.s | 1 -
src/runtime/cgo/asm_mips64x.s | 12 +-
src/runtime/cgo/asm_s390x.s | 46 +-
src/runtime/cgo/cgo.go | 3 -
src/runtime/cgo/gcc_context.c | 2 +-
src/runtime/cgo/gcc_dragonfly_amd64.c | 12 -
src/runtime/cgo/gcc_libinit_windows.c | 4 +-
src/runtime/cgo/gcc_linux_mips64x.c | 2 +-
src/runtime/cgo/gcc_mips64x.S | 5 +-
src/runtime/cgo/gcc_s390x.S | 60 +-
src/runtime/cgo/gcc_setenv.c | 4 +
src/runtime/cgo/gcc_sigaction.c | 76 +
src/runtime/cgo/sigaction.go | 22 +
src/runtime/cgo_mips64x.go | 12 -
src/runtime/cgo_mmap.go | 1 -
src/runtime/cgo_sigaction.go | 89 +
src/runtime/cgocall.go | 71 +-
src/runtime/cgocheck.go | 4 +-
src/runtime/chan.go | 49 +-
src/runtime/chan_test.go | 11 +-
src/runtime/cpuflags_amd64.go | 75 +
src/runtime/cpuidlow_amd64.s | 22 +
src/runtime/cpuprof.go | 3 +-
src/runtime/cputicks.go | 2 +
src/runtime/crash_cgo_test.go | 115 +-
src/runtime/crash_test.go | 55 +-
src/runtime/crash_unix_test.go | 4 +-
src/runtime/debug/garbage.go | 8 +-
src/runtime/debug/garbage_test.go | 19 +-
src/runtime/defs1_linux.go | 2 +-
src/runtime/defs1_netbsd_386.go | 6 -
src/runtime/defs1_netbsd_amd64.go | 7 -
src/runtime/defs1_netbsd_arm.go | 17 +-
src/runtime/defs1_solaris_amd64.go | 10 +-
src/runtime/defs2_linux.go | 2 +-
src/runtime/defs3_linux.go | 2 +-
src/runtime/defs_arm_linux.go | 2 +-
src/runtime/defs_dragonfly.go | 1 -
src/runtime/defs_dragonfly_amd64.go | 7 -
src/runtime/defs_freebsd.go | 1 -
src/runtime/defs_freebsd_386.go | 6 -
src/runtime/defs_freebsd_amd64.go | 7 -
src/runtime/defs_freebsd_arm.go | 6 -
src/runtime/defs_linux_386.go | 4 +-
src/runtime/defs_linux_amd64.go | 4 +-
src/runtime/defs_linux_arm.go | 4 +-
src/runtime/defs_linux_arm64.go | 4 +-
src/runtime/defs_linux_mips64x.go | 4 +-
src/runtime/defs_linux_mipsx.go | 188 +
src/runtime/defs_linux_ppc64.go | 4 +-
src/runtime/defs_linux_ppc64le.go | 4 +-
src/runtime/defs_linux_s390x.go | 4 +-
src/runtime/defs_netbsd.go | 1 -
src/runtime/defs_openbsd.go | 1 -
src/runtime/defs_openbsd_386.go | 6 -
src/runtime/defs_openbsd_amd64.go | 7 -
src/runtime/defs_openbsd_arm.go | 6 -
src/runtime/defs_plan9_386.go | 3 +
src/runtime/defs_plan9_amd64.go | 3 +
src/runtime/defs_plan9_arm.go | 3 +
src/runtime/defs_solaris.go | 1 -
src/runtime/duff_arm64.s | 387 +-
src/runtime/export_mmap_test.go | 6 +
src/runtime/export_test.go | 17 +-
src/runtime/extern.go | 5 +
src/runtime/gc_test.go | 42 -
src/runtime/gcinfo_test.go | 2 +-
src/runtime/hash32.go | 2 +-
src/runtime/hash_test.go | 3 +
src/runtime/hashmap.go | 305 +-
src/runtime/hashmap_fast.go | 36 +-
src/runtime/heapdump.go | 18 +-
src/runtime/iface.go | 237 +-
src/runtime/internal/atomic/asm.s | 8 -
src/runtime/internal/atomic/asm_386.s | 5 +-
src/runtime/internal/atomic/asm_amd64.s | 5 +-
src/runtime/internal/atomic/asm_amd64p32.s | 2 +-
src/runtime/internal/atomic/asm_arm.s | 2 +-
src/runtime/internal/atomic/asm_arm64.s | 2 +-
src/runtime/internal/atomic/asm_mipsx.s | 149 +
src/runtime/internal/atomic/asm_s390x.s | 8 +-
src/runtime/internal/atomic/atomic_arm.go | 18 +
src/runtime/internal/atomic/atomic_arm64.go | 36 +-
src/runtime/internal/atomic/atomic_arm64.s | 19 +
src/runtime/internal/atomic/atomic_mipsx.go | 132 +
src/runtime/internal/atomic/atomic_mipsx.s | 28 +
src/runtime/internal/atomic/atomic_ppc64x.s | 12 +-
src/runtime/internal/atomic/atomic_test.go | 44 +-
src/runtime/internal/atomic/bench_test.go | 28 +
src/runtime/internal/atomic/sys_nacl_arm.s | 3 -
src/runtime/internal/sys/arch.go | 1 +
src/runtime/internal/sys/arch_386.go | 16 +-
src/runtime/internal/sys/arch_amd64.go | 16 +-
src/runtime/internal/sys/arch_amd64p32.go | 16 +-
src/runtime/internal/sys/arch_arm.go | 16 +-
src/runtime/internal/sys/arch_arm64.go | 16 +-
src/runtime/internal/sys/arch_mips.go | 18 +
src/runtime/internal/sys/arch_mips64.go | 16 +-
src/runtime/internal/sys/arch_mips64le.go | 16 +-
src/runtime/internal/sys/arch_mipsle.go | 18 +
src/runtime/internal/sys/arch_ppc64.go | 16 +-
src/runtime/internal/sys/arch_ppc64le.go | 16 +-
src/runtime/internal/sys/arch_s390x.go | 16 +-
src/runtime/internal/sys/intrinsics.go | 33 -
src/runtime/internal/sys/intrinsics_386.s | 16 -
src/runtime/internal/sys/intrinsics_stubs.go | 2 -
src/runtime/internal/sys/intrinsics_test.go | 16 -
src/runtime/internal/sys/zgoarch_mips.go | 26 +
src/runtime/internal/sys/zgoarch_mipsle.go | 26 +
src/runtime/lfstack_32bit.go | 2 +-
src/runtime/malloc.go | 173 +-
src/runtime/map_test.go | 1 +
src/runtime/mbarrier.go | 215 +-
src/runtime/mbitmap.go | 298 +-
src/runtime/mcache.go | 3 +-
src/runtime/mcentral.go | 2 +
src/runtime/mem_linux.go | 9 +-
src/runtime/mem_plan9.go | 10 +-
src/runtime/memclr_386.s | 4 +-
src/runtime/memclr_amd64.s | 4 +-
src/runtime/memclr_arm.s | 4 +-
src/runtime/memclr_arm64.s | 4 +-
src/runtime/memclr_mips64x.s | 4 +-
src/runtime/memclr_mipsx.s | 71 +
src/runtime/memclr_plan9_386.s | 4 +-
src/runtime/memclr_plan9_amd64.s | 4 +-
src/runtime/memclr_ppc64x.s | 75 +-
src/runtime/memclr_s390x.s | 74 +-
src/runtime/memmove_386.s | 2 +-
src/runtime/memmove_amd64.s | 245 +-
src/runtime/memmove_arm.s | 2 +-
src/runtime/memmove_linux_amd64_test.go | 3 +-
src/runtime/memmove_mipsx.s | 258 +
src/runtime/memmove_plan9_386.s | 2 +-
src/runtime/memmove_plan9_amd64.s | 2 +-
src/runtime/memmove_test.go | 108 +
src/runtime/mfinal.go | 46 +-
src/runtime/mfixalloc.go | 15 +-
src/runtime/mgc.go | 356 +-
src/runtime/mgcmark.go | 517 +-
src/runtime/mgcsweep.go | 50 +-
src/runtime/mgcsweepbuf.go | 178 +
src/runtime/mgcwork.go | 27 +-
src/runtime/mheap.go | 279 +-
src/runtime/mkduff.go | 16 +-
src/runtime/mksizeclasses.go | 309 +
src/runtime/mprof.go | 105 +-
src/runtime/msan_amd64.s | 6 +-
src/runtime/msize.go | 239 +-
src/runtime/mstats.go | 395 +-
src/runtime/mstkbar.go | 4 +
src/runtime/net_plan9.go | 29 +
src/runtime/netpoll.go | 4 +
src/runtime/noasm.go | 1 +
src/runtime/os3_plan9.go | 3 +
src/runtime/os3_solaris.go | 118 +-
src/runtime/os_darwin.go | 147 +-
src/runtime/os_darwin_arm.go | 4 +-
src/runtime/os_darwin_arm64.go | 4 +-
src/runtime/os_dragonfly.go | 110 +-
src/runtime/os_freebsd.go | 113 +-
src/runtime/os_freebsd_arm.go | 4 +-
src/runtime/os_linux.go | 170 +-
src/runtime/os_linux_arm.go | 5 +-
src/runtime/os_linux_arm64.go | 4 +-
src/runtime/os_linux_be64.go | 48 +
src/runtime/os_linux_generic.go | 9 +-
src/runtime/os_linux_mips64x.go | 12 +-
src/runtime/os_linux_mipsx.go | 62 +
src/runtime/os_linux_noauxv.go | 2 +-
src/runtime/os_linux_ppc64x.go | 60 +
src/runtime/os_linux_s390x.go | 50 +-
src/runtime/os_nacl.go | 9 +-
src/runtime/os_nacl_arm.go | 4 +-
src/runtime/os_netbsd.go | 102 +-
src/runtime/os_netbsd_arm.go | 4 +-
src/runtime/os_openbsd.go | 135 +-
src/runtime/os_openbsd_arm.go | 4 +-
src/runtime/os_plan9.go | 55 +-
src/runtime/os_plan9_arm.go | 4 +-
src/runtime/os_windows.go | 112 +-
src/runtime/panic.go | 160 +-
src/runtime/plugin.go | 96 +
.../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/mprof_test.go | 29 +-
src/runtime/pprof/pprof.go | 211 +-
src/runtime/pprof/pprof_test.go | 171 +-
src/runtime/print.go | 40 +-
src/runtime/proc.go | 299 +-
src/runtime/race.go | 40 +-
src/runtime/race/README | 2 +-
src/runtime/race/output_test.go | 78 +-
src/runtime/race/race_darwin_amd64.syso | Bin 326172 -> 328168 bytes
src/runtime/race/race_freebsd_amd64.syso | Bin 404216 -> 405576 bytes
src/runtime/race/race_linux_amd64.syso | Bin 376048 -> 378032 bytes
src/runtime/race/race_test.go | 17 +-
src/runtime/race/race_windows_amd64.syso | Bin 367717 -> 369467 bytes
src/runtime/race/testdata/cgo_test.go | 3 +-
src/runtime/race/testdata/pool_test.go | 47 +
src/runtime/race/testdata/reflect_test.go | 46 +
src/runtime/rt0_android_amd64.s | 15 +-
src/runtime/rt0_android_arm.s | 15 +-
src/runtime/rt0_android_arm64.s | 7 +-
src/runtime/rt0_linux_mipsx.s | 27 +
src/runtime/rune.go | 219 -
src/runtime/runtime-gdb_test.go | 126 +-
src/runtime/runtime-lldb_test.go | 4 +-
src/runtime/runtime.go | 3 +
src/runtime/runtime1.go | 34 +-
src/runtime/runtime2.go | 33 +-
src/runtime/runtime_mmap_test.go | 28 +-
src/runtime/select.go | 6 +-
src/runtime/sema.go | 40 +-
src/runtime/sigaction_linux.go | 11 +
src/runtime/signal1_unix.go | 350 -
src/runtime/signal2_unix.go | 69 -
src/runtime/signal_386.go | 179 +-
src/runtime/signal_amd64x.go | 198 +-
src/runtime/signal_arm.go | 164 +-
src/runtime/signal_arm64.go | 164 +-
src/runtime/signal_darwin.go | 49 -
src/runtime/signal_darwin_386.go | 27 +-
src/runtime/signal_darwin_amd64.go | 63 +-
src/runtime/signal_darwin_arm.go | 41 +-
src/runtime/signal_darwin_arm64.go | 73 +-
src/runtime/signal_dragonfly_amd64.go | 41 +-
src/runtime/signal_freebsd.go | 41 -
src/runtime/signal_freebsd_386.go | 25 +-
src/runtime/signal_freebsd_amd64.go | 41 +-
src/runtime/signal_freebsd_arm.go | 39 +-
src/runtime/signal_linux_386.go | 37 +-
src/runtime/signal_linux_amd64.go | 41 +-
src/runtime/signal_linux_arm.go | 49 +-
src/runtime/signal_linux_arm64.go | 77 +-
src/runtime/signal_linux_mips64x.go | 81 +-
src/runtime/signal_linux_mipsx.go | 65 +
src/runtime/signal_linux_ppc64x.go | 85 +-
src/runtime/signal_linux_s390x.go | 211 +-
src/runtime/signal_mips64x.go | 164 +-
src/runtime/signal_mipsx.go | 91 +
src/runtime/signal_nacl_386.go | 37 +-
src/runtime/signal_nacl_amd64p32.go | 41 +-
src/runtime/signal_nacl_arm.go | 38 +-
src/runtime/signal_netbsd_386.go | 35 +-
src/runtime/signal_netbsd_amd64.go | 41 +-
src/runtime/signal_netbsd_arm.go | 49 +-
src/runtime/signal_openbsd.go | 41 -
src/runtime/signal_openbsd_386.go | 24 +-
src/runtime/signal_openbsd_amd64.go | 40 +-
src/runtime/signal_openbsd_arm.go | 38 +-
src/runtime/signal_ppc64x.go | 167 +-
src/runtime/signal_sighandler.go | 133 +
src/runtime/signal_sigtramp.go | 58 -
src/runtime/signal_solaris.go | 2 +-
src/runtime/signal_solaris_amd64.go | 41 +-
src/runtime/signal_unix.go | 640 +-
src/runtime/signal_windows.go | 2 +-
src/runtime/sigpanic_unix.go | 53 -
src/runtime/sigtab_linux_generic.go | 2 +
src/runtime/sigtab_linux_mips64x.go | 81 -
src/runtime/sigtab_linux_mipsx.go | 145 +
src/runtime/sizeclasses.go | 27 +
src/runtime/slice.go | 32 +-
src/runtime/softfloat_arm.go | 35 +
src/runtime/stack.go | 44 +-
src/runtime/string.go | 186 +-
src/runtime/string_test.go | 163 +-
src/runtime/stubs.go | 94 +-
src/runtime/stubs32.go | 2 +-
src/runtime/stubs_asm.go | 11 +
src/runtime/symtab.go | 111 +-
src/runtime/sys_arm.go | 17 -
src/runtime/sys_arm64.go | 18 -
src/runtime/sys_darwin_386.s | 37 +-
src/runtime/sys_darwin_amd64.s | 45 +-
src/runtime/sys_darwin_arm.s | 4 +-
src/runtime/sys_darwin_arm64.s | 2 +-
src/runtime/sys_dragonfly_amd64.s | 39 +-
src/runtime/sys_freebsd_386.s | 20 +-
src/runtime/sys_freebsd_amd64.s | 27 +-
src/runtime/sys_linux_386.s | 32 +-
src/runtime/sys_linux_amd64.s | 42 +-
src/runtime/sys_linux_arm.s | 25 +-
src/runtime/sys_linux_arm64.s | 16 +-
src/runtime/sys_linux_mips64x.s | 22 +-
src/runtime/sys_linux_mipsx.s | 467 +
src/runtime/sys_linux_ppc64x.s | 16 +-
src/runtime/sys_linux_s390x.s | 34 +-
src/runtime/sys_mips64x.go | 23 -
src/runtime/sys_mipsx.go | 20 +
src/runtime/sys_nacl_386.s | 4 +-
src/runtime/sys_nacl_amd64p32.s | 4 +-
src/runtime/sys_nacl_arm.s | 4 +-
src/runtime/sys_netbsd_386.s | 22 +-
src/runtime/sys_netbsd_amd64.s | 27 +-
src/runtime/sys_netbsd_arm.s | 2 +-
src/runtime/sys_openbsd_386.s | 24 +-
src/runtime/sys_openbsd_amd64.s | 29 +-
src/runtime/sys_openbsd_arm.s | 80 +-
src/runtime/sys_plan9_386.s | 4 +-
src/runtime/sys_plan9_amd64.s | 6 +-
src/runtime/sys_plan9_arm.s | 6 +-
src/runtime/sys_ppc64x.go | 17 -
src/runtime/sys_s390x.go | 27 -
src/runtime/sys_solaris_amd64.s | 13 +
src/runtime/sys_windows_386.s | 8 +-
src/runtime/sys_windows_amd64.s | 12 +-
src/runtime/sys_x86.go | 30 -
src/runtime/syscall_windows_test.go | 94 +
src/runtime/testdata/testprog/deadlock.go | 11 +
src/runtime/testdata/testprog/gc.go | 18 +-
src/runtime/testdata/testprog/map.go | 77 +
src/runtime/testdata/testprogcgo/pprof.go | 2 +-
src/runtime/testdata/testprogcgo/raceprof.go | 78 +
src/runtime/testdata/testprogcgo/racesig.go | 102 +
src/runtime/testdata/testprogcgo/threadpprof.go | 35 +-
src/runtime/testdata/testprogcgo/threadprof.go | 9 +-
src/runtime/time.go | 8 +-
src/runtime/tls_mipsx.s | 21 +
src/runtime/trace.go | 134 +-
src/runtime/trace/trace_stack_test.go | 27 +-
src/runtime/trace/trace_test.go | 29 +-
src/runtime/traceback.go | 63 +-
src/runtime/type.go | 83 +-
src/runtime/unaligned2.go | 2 +-
src/runtime/utf8.go | 123 +
src/runtime/vdso_none.go | 1 +
src/runtime/vlop_386.s | 20 +-
src/runtime/vlop_arm.s | 34 +-
src/runtime/vlrt.go | 23 +-
src/runtime/write_err_android.go | 4 +-
src/sort/example_search_test.go | 42 +
src/sort/genzfunc.go | 122 +
src/sort/sort.go | 68 +-
src/sort/sort_test.go | 92 +-
src/sort/zfuncversion.go | 265 +
src/strconv/atoi.go | 4 +
src/strconv/decimal.go | 6 +-
src/strconv/ftoa_test.go | 3 +
src/strconv/quote.go | 10 +
src/strconv/quote_test.go | 3 +-
src/strconv/strconv_test.go | 31 +
src/strings/strings.go | 163 +-
src/strings/strings_amd64.go | 52 +-
src/strings/strings_generic.go | 2 +-
src/strings/strings_s390x.go | 98 +
src/strings/strings_test.go | 178 +-
src/sync/atomic/asm_amd64.s | 3 +
src/sync/atomic/asm_amd64p32.s | 15 +-
src/sync/atomic/asm_arm.s | 42 +-
src/sync/atomic/asm_mips64x.s | 4 +-
src/sync/atomic/asm_mipsx.s | 85 +
src/sync/atomic/asm_ppc64x.s | 4 +-
src/sync/atomic/asm_s390x.s | 22 +-
src/sync/atomic/atomic_test.go | 29 +-
src/sync/cond_test.go | 4 +-
src/sync/example_pool_test.go | 45 +
src/sync/mutex.go | 8 +-
src/sync/mutex_test.go | 108 +-
src/sync/pool.go | 81 +-
src/sync/pool_test.go | 3 +-
src/sync/runtime.go | 3 +
src/sync/rwmutex.go | 4 +-
src/sync/rwmutex_test.go | 42 -
src/syscall/asm9_unix1_amd64.s | 45 +
src/syscall/asm9_unix2_amd64.s | 46 +
src/syscall/asm_darwin_arm.s | 121 +-
src/syscall/asm_darwin_arm64.s | 30 +-
src/syscall/asm_dragonfly_amd64.s | 134 -
src/syscall/asm_freebsd_386.s | 143 -
src/syscall/asm_freebsd_amd64.s | 137 -
src/syscall/asm_linux_mipsx.s | 142 +
src/syscall/asm_netbsd_386.s | 143 -
src/syscall/asm_netbsd_amd64.s | 136 -
src/syscall/asm_openbsd_386.s | 143 -
src/syscall/asm_openbsd_amd64.s | 136 -
src/syscall/asm_openbsd_arm.s | 10 +-
src/syscall/asm_plan9_386.s | 61 +-
src/syscall/asm_plan9_amd64.s | 59 +-
src/syscall/asm_unix_386.s | 142 +
src/syscall/asm_unix_amd64.s | 102 +
src/syscall/const_plan9.go | 11 +
src/syscall/dir_plan9.go | 2 +-
src/syscall/dirent.go | 102 +
src/syscall/dll_windows.go | 1 -
src/syscall/endian_big.go | 9 +
src/syscall/endian_little.go | 9 +
src/syscall/env_windows.go | 2 +-
src/syscall/exec_linux.go | 6 +-
src/syscall/exec_linux_test.go | 10 +-
src/syscall/exec_plan9.go | 5 -
src/syscall/exec_unix.go | 2 +-
src/syscall/exec_windows.go | 2 -
src/syscall/flock_linux_32bit.go | 2 +-
src/syscall/mkall.sh | 2 +-
src/syscall/mksyscall_windows.go | 31 +-
src/syscall/mksysnum_linux.pl | 14 +-
src/syscall/net_nacl.go | 44 +-
src/syscall/netlink_linux.go | 5 +-
src/syscall/setuidgid_32_linux.go | 13 +
src/syscall/setuidgid_linux.go | 13 +
src/syscall/sockcmsg_linux.go | 3 +
src/syscall/sockcmsg_unix.go | 7 +-
src/syscall/syscall.go | 6 +
src/syscall/syscall_darwin.go | 36 +-
src/syscall/syscall_darwin_386.go | 19 +-
src/syscall/syscall_darwin_amd64.go | 19 +-
src/syscall/syscall_darwin_arm.go | 19 +-
src/syscall/syscall_darwin_arm64.go | 19 +-
src/syscall/syscall_darwin_test.go | 23 -
src/syscall/syscall_dragonfly.go | 35 +-
src/syscall/syscall_dragonfly_amd64.go | 19 +-
src/syscall/syscall_freebsd.go | 36 +-
src/syscall/syscall_freebsd_386.go | 19 +-
src/syscall/syscall_freebsd_amd64.go | 19 +-
src/syscall/syscall_freebsd_arm.go | 19 +-
src/syscall/syscall_linux.go | 42 +-
src/syscall/syscall_linux_386.go | 24 +-
src/syscall/syscall_linux_amd64.go | 24 +-
src/syscall/syscall_linux_arm.go | 22 +-
src/syscall/syscall_linux_arm64.go | 24 +-
src/syscall/syscall_linux_mips64x.go | 22 +-
src/syscall/syscall_linux_mipsx.go | 222 +
src/syscall/syscall_linux_ppc64x.go | 24 +-
src/syscall/syscall_linux_s390x.go | 24 +-
src/syscall/syscall_linux_test.go | 28 +
src/syscall/syscall_nacl.go | 40 +-
src/syscall/syscall_nacl_386.go | 17 +-
src/syscall/syscall_nacl_amd64p32.go | 17 +-
src/syscall/syscall_nacl_arm.go | 17 +-
src/syscall/syscall_netbsd.go | 38 +-
src/syscall/syscall_netbsd_386.go | 19 +-
src/syscall/syscall_netbsd_amd64.go | 19 +-
src/syscall/syscall_netbsd_arm.go | 19 +-
src/syscall/syscall_openbsd.go | 38 +-
src/syscall/syscall_openbsd_386.go | 19 +-
src/syscall/syscall_openbsd_amd64.go | 19 +-
src/syscall/syscall_openbsd_arm.go | 19 +-
src/syscall/syscall_plan9.go | 2 -
src/syscall/syscall_solaris.go | 84 +-
src/syscall/syscall_solaris_amd64.go | 19 +-
src/syscall/syscall_test.go | 14 +
src/syscall/syscall_unix.go | 1 +
src/syscall/syscall_unix_test.go | 9 -
src/syscall/syscall_windows.go | 28 +-
src/syscall/timestruct.go | 40 +
src/syscall/types_linux.go | 2 +-
src/syscall/zerrors_linux_mips.go | 1834 ++
src/syscall/zerrors_linux_mipsle.go | 1834 ++
src/syscall/zsyscall_linux_386.go | 4 +-
src/syscall/zsyscall_linux_amd64.go | 4 +-
src/syscall/zsyscall_linux_arm.go | 4 +-
src/syscall/zsyscall_linux_arm64.go | 4 +-
src/syscall/zsyscall_linux_mips.go | 1759 ++
src/syscall/zsyscall_linux_mips64.go | 4 +-
src/syscall/zsyscall_linux_mips64le.go | 4 +-
src/syscall/zsyscall_linux_mipsle.go | 1759 ++
src/syscall/zsyscall_linux_ppc64.go | 4 +-
src/syscall/zsyscall_linux_ppc64le.go | 4 +-
src/syscall/zsyscall_linux_s390x.go | 4 +-
src/syscall/zsyscall_solaris_amd64.go | 86 +-
src/syscall/zsyscall_windows.go | 259 +-
src/syscall/zsysnum_linux_mips.go | 357 +
src/syscall/zsysnum_linux_mipsle.go | 357 +
src/syscall/ztypes_linux_386.go | 7 +-
src/syscall/ztypes_linux_amd64.go | 7 +-
src/syscall/ztypes_linux_arm.go | 7 +-
src/syscall/ztypes_linux_arm64.go | 7 +-
src/syscall/ztypes_linux_mips.go | 592 +
src/syscall/ztypes_linux_mips64.go | 7 +-
src/syscall/ztypes_linux_mips64le.go | 7 +-
src/syscall/ztypes_linux_mipsle.go | 592 +
src/syscall/ztypes_linux_ppc64.go | 7 +-
src/syscall/ztypes_linux_ppc64le.go | 7 +-
src/syscall/ztypes_windows.go | 2 +
src/testing/benchmark.go | 26 +-
src/testing/example.go | 10 +-
src/testing/internal/testdeps/deps.go | 51 +
src/testing/quick/quick.go | 2 +
src/testing/sub_test.go | 51 +-
src/testing/testing.go | 249 +-
src/testing/testing_test.go | 38 +-
src/text/tabwriter/tabwriter.go | 1 +
src/text/template/exec.go | 47 +-
src/text/template/exec_test.go | 106 +-
src/text/template/funcs.go | 80 +-
src/text/template/multi_test.go | 36 +
src/text/template/parse/lex.go | 77 +-
src/text/template/parse/lex_test.go | 259 +-
src/text/template/parse/parse.go | 25 +-
src/text/template/parse/parse_test.go | 34 +
src/text/template/template.go | 15 +-
src/time/example_test.go | 18 +-
src/time/export_android_test.go | 12 +
src/time/format.go | 57 +-
src/time/format_test.go | 3 +
src/time/sleep.go | 28 +-
src/time/time.go | 77 +-
src/time/time_test.go | 146 +-
src/time/zoneinfo.go | 2 +
src/time/zoneinfo_abbrs_windows.go | 183 +-
src/time/zoneinfo_android.go | 119 +
src/time/zoneinfo_android_test.go | 18 +
src/time/zoneinfo_unix.go | 2 +-
src/time/zoneinfo_windows.go | 2 -
src/unicode/letter.go | 7 +
src/unicode/letter_test.go | 4 +
src/unicode/utf8/utf8.go | 15 +-
src/unicode/utf8/utf8_test.go | 91 +
src/unsafe/unsafe.go | 10 +-
.../x/crypto/chacha20poly1305/chacha20poly1305.go | 83 +
.../chacha20poly1305/chacha20poly1305_amd64.go | 80 +
.../chacha20poly1305/chacha20poly1305_amd64.s | 2707 +++
.../chacha20poly1305/chacha20poly1305_generic.go | 70 +
.../chacha20poly1305/chacha20poly1305_noasm.go | 15 +
.../chacha20poly1305/chacha20poly1305_test.go | 182 +
.../chacha20poly1305_test_vectors.go | 332 +
.../internal/chacha20/chacha_generic.go | 199 +
.../internal/chacha20/chacha_test.go | 29 +
.../golang_org/x/crypto/curve25519/const_amd64.s | 20 +
.../golang_org/x/crypto/curve25519/cswap_amd64.s | 88 +
.../golang_org/x/crypto/curve25519/curve25519.go | 841 +
.../x/crypto/curve25519/curve25519_test.go | 29 +
src/vendor/golang_org/x/crypto/curve25519/doc.go | 23 +
.../golang_org/x/crypto/curve25519/freeze_amd64.s | 71 +
.../x/crypto/curve25519/ladderstep_amd64.s | 1375 ++
.../x/crypto/curve25519/mont25519_amd64.go | 240 +
.../golang_org/x/crypto/curve25519/mul_amd64.s | 167 +
.../golang_org/x/crypto/curve25519/square_amd64.s | 130 +
.../golang_org/x/crypto/poly1305/poly1305.go | 32 +
.../golang_org/x/crypto/poly1305/poly1305_test.go | 92 +
.../golang_org/x/crypto/poly1305/sum_amd64.go | 22 +
.../golang_org/x/crypto/poly1305/sum_amd64.s | 125 +
src/vendor/golang_org/x/crypto/poly1305/sum_arm.go | 22 +
src/vendor/golang_org/x/crypto/poly1305/sum_arm.s | 427 +
src/vendor/golang_org/x/crypto/poly1305/sum_ref.go | 1531 ++
src/vendor/golang_org/x/net/idna/idna.go | 68 +
src/vendor/golang_org/x/net/idna/idna_test.go | 43 +
src/vendor/golang_org/x/net/idna/punycode.go | 200 +
src/vendor/golang_org/x/net/idna/punycode_test.go | 198 +
src/vendor/golang_org/x/net/lex/httplex/httplex.go | 39 +
.../golang_org/x/net/lex/httplex/httplex_test.go | 18 +
src/vendor/golang_org/x/net/lif/address.go | 105 +
src/vendor/golang_org/x/net/lif/address_test.go | 121 +
src/vendor/golang_org/x/net/lif/binary.go | 68 +
src/vendor/golang_org/x/net/lif/defs_solaris.go | 90 +
src/vendor/golang_org/x/net/lif/lif.go | 43 +
src/vendor/golang_org/x/net/lif/link.go | 122 +
src/vendor/golang_org/x/net/lif/link_test.go | 61 +
.../golang_org/x/net/lif/sys_solaris_amd64.s | 11 +
src/vendor/golang_org/x/net/lif/syscall.go | 33 +
.../golang_org/x/net/lif/zsys_solaris_amd64.go | 103 +
src/vendor/golang_org/x/net/route/address.go | 18 +-
.../golang_org/x/net/route/interface_freebsd.go | 12 +-
.../golang_org/x/net/route/interface_openbsd.go | 9 +-
src/vendor/golang_org/x/net/route/message.go | 6 +
src/vendor/golang_org/x/net/route/message_test.go | 23 +
src/vendor/golang_org/x/net/route/route_openbsd.go | 6 +-
src/vendor/golang_org/x/net/route/route_test.go | 35 +-
.../golang_org/x/text/transform/transform.go | 705 +
.../golang_org/x/text/unicode/norm/composition.go | 514 +
.../golang_org/x/text/unicode/norm/forminfo.go | 256 +
src/vendor/golang_org/x/text/unicode/norm/input.go | 105 +
src/vendor/golang_org/x/text/unicode/norm/iter.go | 450 +
.../golang_org/x/text/unicode/norm/normalize.go | 608 +
.../golang_org/x/text/unicode/norm/readwriter.go | 125 +
.../golang_org/x/text/unicode/norm/tables.go | 7627 ++++++
.../golang_org/x/text/unicode/norm/transform.go | 88 +
src/vendor/golang_org/x/text/unicode/norm/trie.go | 54 +
.../golang_org/x/text/unicode/norm/triegen.go | 117 +
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/bugs/bug395.go | 24 -
test/bugs/placeholder | 2 -
test/checkbce.go | 4 +-
test/const.go | 35 +
test/convert2.go | 315 +
test/ddd1.go | 5 +-
test/escape_because.go | 48 +-
test/escape_iface.go | 18 +-
test/fixedbugs/bug255.go | 2 +-
test/fixedbugs/bug332.go | 4 +-
test/fixedbugs/bug376.go | 3 +-
test/fixedbugs/bug498.go | 23 +
test/fixedbugs/bug499.go | 15 +
test/fixedbugs/issue10607.go | 2 +-
test/fixedbugs/issue11370.go | 13 +
test/fixedbugs/issue11610.go | 2 +-
test/fixedbugs/issue13162.go | 82 +
test/fixedbugs/issue13171.go | 2 +-
test/fixedbugs/issue13262.go | 21 +
test/fixedbugs/issue13485.go | 18 +
test/fixedbugs/issue14136.go | 2 +-
test/fixedbugs/issue15141.go | 33 +
test/fixedbugs/issue15277.go | 2 +
test/fixedbugs/issue15303.go | 24 +
test/fixedbugs/issue15514.dir/a.go | 7 +
test/fixedbugs/issue15514.dir/b.go | 7 +
test/fixedbugs/issue15514.dir/c.go | 10 +
test/fixedbugs/issue15514.go | 7 +
test/fixedbugs/issue15528.go | 131 +
test/fixedbugs/issue15609.dir/call.go | 7 +
test/fixedbugs/issue15609.dir/call_386.s | 8 +
test/fixedbugs/issue15609.dir/call_amd64.s | 8 +
test/fixedbugs/issue15609.dir/call_decl.go | 5 +
test/fixedbugs/issue15609.dir/main.go | 14 +
test/fixedbugs/issue15722.go | 21 +
test/fixedbugs/issue15747.go | 11 +-
test/fixedbugs/issue15895.go | 27 +
test/fixedbugs/issue16306.go | 15 +
test/fixedbugs/issue16317.dir/a.go | 11 +
test/fixedbugs/issue16317.dir/b.go | 11 +
test/fixedbugs/issue16317.go | 10 +
test/fixedbugs/issue16331.go | 48 +
test/fixedbugs/issue16369.go | 13 +
test/fixedbugs/issue16428.go | 12 +
test/fixedbugs/issue16439.go | 18 +
test/fixedbugs/issue16616.dir/a.go | 7 +
test/fixedbugs/issue16616.dir/b.go | 14 +
test/fixedbugs/issue16616.dir/issue16616.go | 26 +
test/fixedbugs/issue16616.go | 9 +
test/fixedbugs/issue16733.go | 16 +
test/fixedbugs/issue16741.go | 17 +
test/fixedbugs/issue16760.go | 42 +
test/fixedbugs/issue16804.go | 16 +
test/fixedbugs/issue16870.go | 140 +
test/fixedbugs/issue16948.go | 34 +
test/fixedbugs/issue16949.go | 30 +
test/fixedbugs/issue16985.go | 37 +
test/fixedbugs/issue17005.go | 46 +
test/fixedbugs/issue17038.go | 9 +
test/fixedbugs/issue17039.go | 17 +
test/fixedbugs/issue17111.go | 16 +
test/fixedbugs/issue17194.go | 17 +
test/fixedbugs/issue17270.go | 11 +
test/fixedbugs/issue17381.go | 54 +
test/fixedbugs/issue17449.go | 34 +
test/fixedbugs/issue17551.go | 21 +
test/fixedbugs/issue17588.go | 20 +
test/fixedbugs/issue17596.go | 19 +
test/fixedbugs/issue17631.go | 22 +
test/fixedbugs/issue17640.go | 28 +
test/fixedbugs/issue17645.go | 17 +
test/fixedbugs/issue17710.go | 13 +
test/fixedbugs/issue17752.go | 20 +
test/fixedbugs/issue17918.go | 41 +
test/fixedbugs/issue18092.go | 15 +
test/fixedbugs/issue4085b.go | 24 +-
test/fixedbugs/issue4215.go | 53 +
test/fixedbugs/issue6750.go | 22 +
test/fixedbugs/issue8613.go | 1 -
test/fixedbugs/issue9608.dir/issue9608.go | 9 +
test/float_lit2.go | 4 +-
test/inline_variadic.go | 19 +
test/interface/assertinline.go | 41 +-
test/intrinsic.dir/main.go | 15 -
test/intrinsic.go | 2 +-
test/intrinsic_atomic.go | 20 +
test/live.go | 234 +-
test/live2.go | 11 +-
test/live_ssa.go | 648 -
test/live_syscall.go | 4 +-
test/method2.go | 4 +-
test/nilptr3.go | 104 +-
test/nilptr3_ssa.go | 230 -
test/nosplit.go | 4 +-
test/notinheap.go | 55 +
test/notinheap2.go | 43 +
test/nowritebarrier.go | 78 +
test/nul1.go | 7 +-
test/phiopt.go | 2 +-
test/prove.go | 4 +-
test/range.go | 25 +
test/run.go | 68 +-
test/sliceopt.go | 77 +-
test/switch2.go | 4 +-
test/switch5.go | 22 +-
test/switch6.go | 8 +-
test/syntax/chan1.go | 4 +-
test/syntax/semi4.go | 9 +-
test/uintptrescapes2.go | 10 +-
test/writebarrier.go | 17 +-
2133 files changed, 312937 insertions(+), 121883 deletions(-)
diff --git a/AUTHORS b/AUTHORS
index 9494ba0..cb487d5 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -27,6 +27,7 @@ Ainar Garipov <gugl.zadolbal at gmail.com>
Akihiro Suda <suda.kyoto at gmail.com>
Akshat Kumar <seed at mail.nanosouffle.net>
Alan Shreve <alan at inconshreveable.com>
+Albert Nigmatzianov <albertnigma at gmail.com>
Albert Strasheim <fullung at gmail.com>
Alberto Bertogli <albertito at blitiri.com.ar>
Alberto Donizetti <alb.donizetti at gmail.com>
@@ -35,11 +36,14 @@ Aleksandar Dezelin <dezelin at gmail.com>
Alessandro Arzilli <alessandro.arzilli at gmail.com>
Alex A Skinner <alex at lx.lc>
Alex Brainman <alex.brainman at gmail.com>
+Alex Browne <stephenalexbrowne at gmail.com>
+Alex Carol <alex.carol.c at gmail.com>
Alex Jin <toalexjin at gmail.com>
Alex Plugaru <alex at plugaru.org> <alexandru.plugaru at gmail.com>
Alex Schroeder <alex at gnu.org>
Alex Sergeyev <abc at alexsergeyev.com>
Alexander Demakin <alexander.demakin at gmail.com>
+Alexander Döring <email at alexd.ch>
Alexander Larsson <alexander.larsson at gmail.com>
Alexander Morozov <lk4d4math at gmail.com>
Alexander Neumann <alexander at bumpern.de>
@@ -55,10 +59,14 @@ Alexey Borzenkov <snaury at gmail.com>
Alexey Palazhchenko <alexey.palazhchenko at gmail.com>
Aliaksandr Valialkin <valyala at gmail.com>
Alif Rachmawadi <subosito at gmail.com>
+Allan Simon <allan.simon at supinfo.com>
+Alok Menghrajani <alok.menghrajani at gmail.com>
Amazon.com, Inc
Amir Mohammad Saied <amir at gluegadget.com>
Amrut Joshi <amrut.joshi at gmail.com>
Andre Nathan <andrenth at gmail.com>
+Andreas Auernhammer <aead at mail.de>
+Andreas Litt <andreas.litt at gmail.com>
Andrei Korzhevskii <a.korzhevskiy at gmail.com>
Andrei Vieru <euvieru at gmail.com>
Andrew Balholm <andybalholm at gmail.com>
@@ -68,6 +76,7 @@ Andrew Ekstedt <andrew.ekstedt at gmail.com>
Andrew Etter <andrew.etter at gmail.com>
Andrew Harding <andrew at spacemonkey.com>
Andrew Lutomirski <andy at luto.us>
+Andrew Pogrebnoy <absourd.noise at gmail.com>
Andrew Pritchard <awpritchard at gmail.com>
Andrew Radev <andrey.radev at gmail.com>
Andrew Skiba <skibaa at gmail.com>
@@ -100,6 +109,7 @@ Arnout Engelen <arnout at bzzt.net>
Aron Nopanen <aron.nopanen at gmail.com>
Artyom Pervukhin <artyom.pervukhin at gmail.com>
Arvindh Rajesh Tamilmani <art at a-30.net>
+Atin Malaviya <amalaviy at akamai.com>
Ato Araki <ato.araki at gmail.com>
Audrey Lim <audreylh at gmail.com>
Augusto Roman <aroman at gmail.com>
@@ -118,7 +128,9 @@ Bjorn Tillenius <bjorn at tillenius.me>
Bjorn Tipling <bjorn.tipling at gmail.com>
Blake Gentry <blakesgentry at gmail.com>
Blake Mizerany <blake.mizerany at gmail.com>
+Blixt <me at blixt.nyc>
Bobby Powers <bobbypowers at gmail.com>
+Bolt
Brady Catherman <brady at gmail.com>
Brady Sullivan <brady at bsull.com>
Brendan Daniel Tracey <tracey.brendan at gmail.com>
@@ -126,12 +138,15 @@ Brett Cannon <bcannon at gmail.com>
Brian Dellisanti <briandellisanti at gmail.com>
Brian G. Merrell <bgmerrell at gmail.com>
Brian Gitonga Marete <marete at toshnix.com> <bgmarete at gmail.com>
+Brian Kennedy <btkennedy at gmail.com>
Brian Ketelsen <bketelsen at gmail.com>
Brian Smith <ohohvi at gmail.com>
+Bryan Alexander <Kozical at msn.com>
Bryan Ford <brynosaurus at gmail.com>
Caine Tighe <arctanofyourface at gmail.com>
Caleb Spare <cespare at gmail.com>
Carl Chatfield <carlchatfield at gmail.com>
+Carl Johnson <me at carlmjohnson.net>
Carlos Castillo <cookieo9 at gmail.com>
Carlos Cirello <uldericofilho at gmail.com>
Case Nelson <case.nelson at gmail.com>
@@ -170,6 +185,7 @@ CoreOS, Inc.
Corey Thomasson <cthom.lists at gmail.com>
Cristian Staretu <unclejacksons at gmail.com>
Currant
+Cyrill Schumacher <cyrill at schumacher.fm>
Damian Gryski <dgryski at gmail.com>
Dan Caddigan <goldcaddy77 at gmail.com>
Dan Callahan <dan.callahan at gmail.com>
@@ -180,6 +196,7 @@ Daniel Johansson <dajo2002 at gmail.com>
Daniel Kerwin <d.kerwin at gini.net>
Daniel Krech <eikeon at eikeon.com>
Daniel Lidén <daniel.liden.87 at gmail.com>
+Daniel Martí <mvdan at mvdan.cc>
Daniel Morsing <daniel.morsing at gmail.com>
Daniel Ortiz Pereira da Silva <daniel.particular at gmail.com>
Daniel Skinner <daniel at dasa.cc>
@@ -199,10 +216,12 @@ David Jakob Fritz <david.jakob.fritz at gmail.com>
David Leon Gil <coruus at gmail.com>
David R. Jenni <david.r.jenni at gmail.com>
David Sansome <me at davidsansome.com>
+David Stainton <dstainton415 at gmail.com>
David Thomas <davidthomas426 at gmail.com>
David Titarenco <david.titarenco at gmail.com>
Davies Liu <davies.liu at gmail.com>
Dean Prichard <dean.prichard at gmail.com>
+Deepak Jois <deepak.jois at gmail.com>
Denis Bernard <db047h at gmail.com>
Denis Brandolini <denis.brandolini at gmail.com>
Denys Honsiorovskyi <honsiorovskyi at gmail.com>
@@ -211,11 +230,13 @@ Derek Parker <parkerderek86 at gmail.com>
Derek Shockey <derek.shockey at gmail.com>
Develer SRL
Devon H. O'Dell <devon.odell at gmail.com>
+Dhaivat Pandit <dhaivatpandit at gmail.com>
Dhiru Kholia <dhiru.kholia at gmail.com>
Didier Spezia <didier.06 at gmail.com>
Dimitri Tcaciuc <dtcaciuc at gmail.com>
Dirk Gadsden <dirk at esherido.com>
Diwaker Gupta <diwakergupta at gmail.com>
+Dmitri Popov <operator at cv.dp-net.com>
Dmitri Shuralyov <shurcooL at gmail.com>
Dmitriy Dudkin <dudkin.dmitriy at gmail.com>
Dmitriy Shelenin <deemok at googlemail.com> <deemok at gmail.com>
@@ -257,10 +278,12 @@ Evan Shaw <chickencha at gmail.com>
Ewan Chou <coocood 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>
Fastly, Inc.
Fatih Arslan <fatih at arslan.io>
Fazlul Shahriar <fshahriar at gmail.com>
+Fedor Indutny <fedor at indutny.com>
Felix Geisendörfer <haimuiba at gmail.com>
Filippo Valsorda <hi at filippo.io>
Firmansyah Adiputra <frm.adiputra at gmail.com>
@@ -275,16 +298,20 @@ Fredrik Enestad <fredrik.enestad at soundtrackyourbrand.com>
Frithjof Schulze <schulze at math.uni-hannover.de> <sfrithjof at gmail.com>
Frits van Bommel <fvbommel at gmail.com>
Gabriel Aszalos <gabriel.aszalos at gmail.com>
+Gabriel Russell <gabriel.russell at gmail.com>
+Gareth Paul Jones <gpj at foursquare.com>
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>
+Geoffroy Lorieux <lorieux.g at gmail.com>
Georg Reinke <guelfey at gmail.com>
George Shammas <george at shamm.as> <georgyo at gmail.com>
Gerasimos Dimitriadis <gedimitr at gmail.com>
Gideon Jan-Wessel Redelinghuys <gjredelinghuys at gmail.com>
Giles Lean <giles.lean at pobox.com>
Giulio Iotti <dullgiulio at gmail.com>
+Gleb Stepanov <glebstepanov1992 at gmail.com>
Google Inc.
Gordon Klaus <gordon.klaus at gmail.com>
Graham King <graham4king at gmail.com>
@@ -307,6 +334,7 @@ Hector Chu <hectorchu at gmail.com>
Hector Martin Cantero <hector at marcansoft.com>
Henning Schmiedehausen <henning at schmiedehausen.org>
Henrik Edwards <henrik.edwards at gmail.com>
+Henrik Hodne <henrik at hodne.io>
Herbert Georg Fischer <herbert.fischer at gmail.com>
Hironao OTSUBO <motemen at gmail.com>
Hiroshi Ioka <hirochachacha at gmail.com>
@@ -327,12 +355,14 @@ Ingo Oeser <nightlyone at googlemail.com>
Intel Corporation
Irieda Noboru <irieda at gmail.com>
Isaac Wagner <ibw at isaacwagner.me>
+Ivan Babrou <ivan at cloudflare.com>
Ivan Ukhov <ivan.ukhov at gmail.com>
Jacob Hoffman-Andrews <github at hoffman-andrews.com>
Jae Kwon <jae at tendermint.com>
Jakob Borg <jakob at nym.se>
Jakub Ryszard Czarnowicz <j.czarnowicz at gmail.com>
James Bardin <j.bardin at gmail.com>
+James Clarke <jrtc27 at jrtc27.com>
James David Chalfant <james.chalfant at gmail.com>
James Fysh <james.fysh at gmail.com>
James Gray <james at james4k.com>
@@ -342,6 +372,7 @@ James Schofield <james at shoeboxapp.com>
James Sweet <james.sweet88 at googlemail.com>
James Toy <nil at opensesame.st>
James Whitehead <jnwhiteh at gmail.com>
+Jamie Beverly <jamie.r.beverly at gmail.com>
Jamil Djadala <djadala at gmail.com>
Jan H. Hosang <jan.hosang at gmail.com>
Jan Mercl <0xjnml at gmail.com>
@@ -352,14 +383,17 @@ Jani Monoses <jani.monoses at ubuntu.com>
Jaroslavas Počepko <jp at webmaster.ms>
Jason Barnett <jason.w.barnett at gmail.com>
Jason Del Ponte <delpontej at gmail.com>
+Jason Smale <jsmale at zendesk.com>
Jason Travis <infomaniac7 at gmail.com>
Jay Weisskopf <jay at jayschwa.net>
+Jean-Nicolas Moal <jn.moal at gmail.com>
Jeff Hodges <jeff at somethingsimilar.com>
Jeff R. Allen <jra at nella.org>
Jeff Sickel <jas at corpus-callosum.com>
Jeff Wendling <jeff at spacemonkey.com>
Jens Frederich <jfrederich at gmail.com>
Jeremy Jackins <jeremyjackins at gmail.com>
+Jeroen Bobbeldijk <jerbob92 at gmail.com>
Jess Frazelle <me at jessfraz.com>
Jihyun Yu <yjh0502 at gmail.com>
Jim McGrath <jimmc2 at gmail.com>
@@ -367,6 +401,7 @@ Jimmy Zelinskie <jimmyzelinskie at gmail.com>
Jingcheng Zhang <diogin at gmail.com>
Jingguo Yao <yaojingguo at gmail.com>
Jiong Du <londevil at gmail.com>
+Jirka Daněk <dnk at mail.muni.cz>
Joakim Sernbrant <serbaut at gmail.com>
Joe Farrell <joe2farrell at gmail.com>
Joe Harrison <joehazzers at gmail.com>
@@ -393,9 +428,11 @@ Jonathan Mark <jhmark at xenops.com>
Jonathan Rudenberg <jonathan at titanous.com>
Jonathan Wills <runningwild at gmail.com>
Jongmin Kim <atomaths at gmail.com>
+Joonas Kuorilehto <joneskoo at derbian.fi>
Jose Luis Vázquez González <josvazg at gmail.com>
Joseph Holsten <joseph at josephholsten.com>
Josh Bleecher Snyder <josharian at gmail.com>
+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>
@@ -406,7 +443,9 @@ Julian Kornberger <jk+github at digineo.de>
Julian Phillips <julian at quantumfyre.co.uk>
Julien Schmidt <google at julienschmidt.com>
Justin Nuß <nuss.justin at gmail.com>
+Justyn Temme <justyntemme at gmail.com>
Kai Backman <kaib at golang.org>
+Kale Blankenship <kale at lemnisys.com>
Kamil Kisiel <kamil at kamilkisiel.net> <kamil.kisiel at gmail.com>
Kang Hu <hukangustc at gmail.com>
Kato Kazuyoshi <kato.kazuyoshi at gmail.com>
@@ -437,6 +476,7 @@ Kyle Lemons <kyle at kylelemons.net>
L Campbell <unpantsu at gmail.com>
Lai Jiangshan <eag0628 at gmail.com>
Larz Conwell <larzconwell at gmail.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>
@@ -448,10 +488,12 @@ Luan Santos <cfcluan at gmail.com>
Luca Greco <luca.greco at alcacoop.it>
Lucien Stuker <lucien.stuker at gmail.com>
Lucio De Re <lucio.dere at gmail.com>
+Luigi Riefolo <luigi.riefolo at gmail.com>
Luit van Drongelen <luitvd at gmail.com>
Luka Zakrajšek <tr00.g33k at gmail.com>
Luke Curley <qpingu at gmail.com>
Mal Curtis <mal at mal.co.nz>
+Manfred Touron <m at 42.am>
Manu S Ajith <neo at codingarena.in>
Manuel Mendez <mmendez534 at gmail.com>
Marc Weistroff <marc at weistroff.net>
@@ -465,7 +507,9 @@ Markover Inc. DBA Poptip
Markus Duft <markus.duft at salomon.at>
Markus Sonderegger <marraison at gmail.com>
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 Möhrmann <martisch at uos.de>
Martin Neubauer <m.ne at gmx.net>
Martin Olsson <martin at minimum.se>
@@ -487,10 +531,13 @@ Matt T. Proud <matt.proud at gmail.com>
Matt Williams <gh at mattyw.net>
Matthew Brennan <matty.brennan at gmail.com>
Matthew Cottingham <mattcottingham at gmail.com>
+Matthew Denton <mdenton at skyportsystems.com>
Matthew Holt <Matthew.Holt+git at gmail.com>
Matthew Horsnell <matthew.horsnell at gmail.com>
+Matthieu Hauglustaine <matt.hauglustaine at gmail.com>
Maxim Khitrov <max at mxcrypt.com>
Maxwell Krohn <themax at gmail.com>
+MediaMath, Inc
Meir Fischer <meirfischer at gmail.com>
Meng Zhuo <mengzhuo1203 at gmail.com>
Meteor Development Group
@@ -517,6 +564,8 @@ Miguel Mendez <stxmendez at gmail.com>
Mihai Borobocea <MihaiBorobocea at gmail.com>
Mikael Tillenius <mikti42 at gmail.com>
Mike Andrews <mra at xoba.com>
+Mike Appleby <mike at app.leby.org>
+Mike Houston <mike at kothar.net>
Mike Rosset <mike.rosset at gmail.com>
Mikhail Gusarov <dottedmag at dottedmag.net>
Mikhail Panchenko <m at mihasya.com>
@@ -524,7 +573,9 @@ Miki Tebeka <miki.tebeka at gmail.com>
Mikio Hara <mikioh.mikioh at gmail.com>
Mikkel Krautz <mikkel at krautz.dk>
Miquel Sabaté Solà <mikisabate at gmail.com>
+Miroslav Genov <mgenov at gmail.com>
Mohit Agarwal <mohit at sdf.org>
+Momchil Velikov <momchil.velikov at gmail.com>
Monty Taylor <mordred at inaugust.com>
Moov Corporation
Moriyoshi Koizumi <mozo at mozo.jp>
@@ -559,6 +610,7 @@ Niko Dziemba <niko at dziemba.com>
Nikolay Turpitko <nikolay at turpitko.com>
Noah Campbell <noahcampbell at gmail.com>
Norberto Lopes <nlopes.ml at gmail.com>
+Oleg Vakheta <helginet at gmail.com>
Oleku Konko <oleku.konko at gmail.com>
Oling Cat <olingcat at gmail.com>
Oliver Hookins <ohookins at gmail.com>
@@ -573,6 +625,7 @@ Padraig Kitterick <padraigkitterick at gmail.com>
Palm Stone Games
Paolo Giarrusso <p.giarrusso at gmail.com>
Paolo Martini <mrtnpaolo at gmail.com>
+Parker Moore <parkrmoore at gmail.com>
Pascal S. de Kloe <pascal at quies.net>
Patrick Crosby <patrick at stathat.com>
Patrick Gavlin <pgavlin at gmail.com>
@@ -619,6 +672,7 @@ Quan Yong Zhai <qyzhai at gmail.com>
Quentin Perez <qperez at ocs.online.net>
Quoc-Viet Nguyen <afelion at gmail.com>
RackTop Systems Inc.
+Radu Berinde <radu at cockroachlabs.com>
Raif S. Naffah <go at naffah-raif.name>
Rajat Goel <rajat.goel2010 at gmail.com>
Ralph Corderoy <ralph at inputplus.co.uk>
@@ -629,6 +683,7 @@ Ricardo Padilha <ricardospadilha at gmail.com>
Richard Barnes <rlb at ipv.sx>
Richard Crowley <r at rcrowley.org>
Richard Eric Gavaletz <gavaletz at gmail.com>
+Richard Gibson <richard.gibson at gmail.com>
Richard Miller <miller.research at gmail.com>
Richard Musiol <mail at richard-musiol.de>
Rick Arnold <rickarnoldjr at gmail.com>
@@ -659,12 +714,14 @@ S.Çağlar Onur <caglar at 10ur.org>
Salmān Aljammāz <s at 0x65.net>
Sam Hug <samuel.b.hug at gmail.com>
Sam Whited <sam at samwhited.com>
+Samuele Pedroni <pedronis at lucediurna.net>
Sanjay Menakuru <balasanjay at gmail.com>
Sasha Sobol <sasha at scaledinference.com>
Scott Barron <scott.barron at github.com>
Scott Bell <scott at sctsm.com>
Scott Ferguson <scottwferg at gmail.com>
Scott Lawrence <bytbox at gmail.com>
+Sean Rees <sean at erifax.org>
Sebastien Binet <seb.binet at gmail.com>
Sébastien Paolacci <sebastien.paolacci at gmail.com>
Sergei Skorobogatov <skorobo at rambler.ru>
@@ -681,9 +738,12 @@ Shinji Tanaka <shinji.tanaka at gmail.com>
Shivakumar GN <shivakumar.gn at gmail.com>
Silvan Jegen <s.jegen at gmail.com>
Simon Jefford <simon.jefford at gmail.com>
+Simon Rawet <simon at rawet.se>
Simon Thulbourn <simon+github at thulbourn.com>
Simon Whitehead <chemnova at gmail.com>
+Sina Siadat <siadat at gmail.com>
Sokolov Yura <funny.falcon at gmail.com>
+Song Gao <song at gao.io>
Spencer Nelson <s at spenczar.com>
Spring Mc <heresy.mc at gmail.com>
Square, Inc.
@@ -700,7 +760,9 @@ Steve Streeting <steve at stevestreeting.com>
Steven Elliot Harris <seharris at gmail.com>
Steven Hartland <steven.hartland at multiplay.co.uk>
Stripe, Inc.
+Suyash <dextrous93 at gmail.com>
Sven Almgren <sven at tras.se>
+Syohei YOSHIDA <syohex at gmail.com>
Szabolcs Nagy <nsz at port70.net>
Tad Glines <tad.glines at gmail.com>
Taj Khattra <taj.khattra at gmail.com>
@@ -710,15 +772,18 @@ Tamir Duberstein <tamird at gmail.com>
Tarmigan Casebolt <tarmigan at gmail.com>
Taru Karttunen <taruti at taruti.net>
Tatsuhiro Tsujikawa <tatsuhiro.t at gmail.com>
+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 de Zeeuw <thomasdezeeuw at gmail.com>
Thomas Desrosiers <thomasdesr at gmail.com>
Thomas Kappler <tkappler at gmail.com>
Thorben Krueger <thorben.krueger at gmail.com>
Tilman Dilo <tilman.dilo at gmail.com>
Tim Cooijmans <timcooijmans at gmail.com>
Tim Ebringer <tim.ebringer at gmail.com>
+Tim Henderson <tim.tadh at gmail.com>
Timo Savola <timo.savola at gmail.com>
Timo Truyts <alkaloid.btx at gmail.com>
Timothy Studd <tim at timstudd.com>
@@ -731,8 +796,11 @@ Tor Andersson <tor.andersson at gmail.com>
Tormod Erevik Lea <tormodlea at gmail.com>
Totoro W <tw19881113 at gmail.com>
Travis Cline <travis.cline at gmail.com>
+Trey Lawrence <lawrence.trey at gmail.com>
Trey Tacon <ttacon at gmail.com>
+Tristan Ooohry <ooohry at gmail.com>
Tudor Golubenco <tudor.g at gmail.com>
+Tuo Shan <sturbo89 at gmail.com>
Tyler Bunnell <tylerbunnell at gmail.com>
Tyler Treat <ttreat31 at gmail.com>
Ugorji Nwoke <ugorji at gmail.com>
@@ -742,13 +810,18 @@ Upthere, Inc.
Uriel Mangado <uriel at berlinblue.org>
Vadim Grek <vadimprog at gmail.com>
Vadim Vygonets <unixdj at gmail.com>
+Vendasta
Vincent Ambo <tazjin at googlemail.com>
Vincent Batts <vbatts at hashbangbash.com> <vbatts at gmail.com>
Vincent Vanackere <vincent.vanackere at gmail.com>
Vinu Rajashekhar <vinutheraj at gmail.com>
Vishvananda Ishaya <vishvananda at gmail.com>
+Vitor De Mario <vitordemario at gmail.com>
+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>
+Weaveworks
Wei Guangjing <vcc.163 at gmail.com>
Willem van der Schyff <willemvds at gmail.com>
William Josephson <wjosephson at gmail.com>
@@ -757,6 +830,7 @@ Wisdom Omuya <deafgoat at gmail.com>
Xia Bin <snyh at snyh.org>
Xing Xing <mikespook at gmail.com>
Xudong Zhang <felixmelon at gmail.com>
+Xuyang Kang <xuyangkang at gmail.com>
Yahoo Inc.
Yann Kerhervé <yann.kerherve at gmail.com>
Yao Zhang <lunaria21 at gmail.com>
@@ -766,11 +840,13 @@ Yesudeep Mangalapilly <yesudeep at google.com>
Yissakhar Z. Beck <yissakhar.beck at gmail.com>
Yo-An Lin <yoanlin93 at gmail.com>
Yongjian Xu <i3dmaster at gmail.com>
+Yorman Arias <cixtords at gmail.com>
Yoshiyuki Kanno <nekotaroh at gmail.com> <yoshiyuki.kanno at stoic.co.jp>
Yusuke Kagiwada <block.rxckin.beats at gmail.com>
Yuusei Kuwana <kuwana at kumama.org>
Yuval Pavel Zholkover <paulzhol at gmail.com>
Zemanta d.o.o.
+Zev Goldstein <zev.goldstein at gmail.com>
Ziad Hatahet <hatahet at gmail.com>
Zorion Arrizabalaga <zorionk at gmail.com>
申习之 <bronze1man at gmail.com>
diff --git a/CONTRIBUTORS b/CONTRIBUTORS
index 6763f52..43d1d9a 100644
--- a/CONTRIBUTORS
+++ b/CONTRIBUTORS
@@ -53,6 +53,7 @@ Akihiro Suda <suda.kyoto at gmail.com>
Akshat Kumar <seed at mail.nanosouffle.net>
Alan Donovan <adonovan at google.com>
Alan Shreve <alan at inconshreveable.com>
+Albert Nigmatzianov <albertnigma at gmail.com>
Albert Strasheim <fullung at gmail.com>
Alberto Bertogli <albertito at blitiri.com.ar>
Alberto Donizetti <alb.donizetti at gmail.com>
@@ -62,12 +63,15 @@ Alessandro Arzilli <alessandro.arzilli at gmail.com>
Alex A Skinner <alex at lx.lc>
Alex Brainman <alex.brainman at gmail.com>
Alex Bramley <abramley at google.com>
+Alex Browne <stephenalexbrowne at gmail.com>
+Alex Carol <alex.carol.c at gmail.com>
Alex Jin <toalexjin at gmail.com>
Alex Plugaru <alex at plugaru.org> <alexandru.plugaru at gmail.com>
Alex Schroeder <alex at gnu.org>
Alex Sergeyev <abc at alexsergeyev.com>
Alex Vaghin <crhyme at google.com>
Alexander Demakin <alexander.demakin at gmail.com>
+Alexander Döring <email at alexd.ch>
Alexander Larsson <alexander.larsson at gmail.com>
Alexander Morozov <lk4d4math at gmail.com>
Alexander Neumann <alexander at bumpern.de>
@@ -85,11 +89,15 @@ Alexey Palazhchenko <alexey.palazhchenko at gmail.com>
Alexis Imperial-Legrand <ail at google.com>
Aliaksandr Valialkin <valyala at gmail.com>
Alif Rachmawadi <subosito at gmail.com>
+Allan Simon <allan.simon at supinfo.com>
+Alok Menghrajani <alok.menghrajani at gmail.com>
Amir Mohammad Saied <amir at gluegadget.com>
Amrut Joshi <amrut.joshi at gmail.com>
Andre Nathan <andrenth at gmail.com>
Andrea Spadaccini <spadaccio at google.com>
+Andreas Auernhammer <aead at mail.de>
Andreas Jellinghaus <andreas at ionisiert.de> <anj at google.com>
+Andreas Litt <andreas.litt at gmail.com>
Andrei Korzhevskii <a.korzhevskiy at gmail.com>
Andrei Vieru <euvieru at gmail.com>
Andres Erbsen <andreser at google.com>
@@ -102,6 +110,7 @@ Andrew Gerrand <adg at golang.org>
Andrew Harding <andrew at spacemonkey.com>
Andrew Lutomirski <andy at luto.us>
Andrew Pilloud <andrewpilloud at igneoussystems.com>
+Andrew Pogrebnoy <absourd.noise at gmail.com>
Andrew Pritchard <awpritchard at gmail.com>
Andrew Radev <andrey.radev at gmail.com>
Andrew Skiba <skibaa at gmail.com>
@@ -124,6 +133,7 @@ Anthony Canino <anthony.canino1 at gmail.com>
Anthony Eufemio <anthony.eufemio at gmail.com>
Anthony Martin <ality at pbrane.org>
Anthony Starks <ajstarks at gmail.com>
+Antonio Murdaca <runcom at redhat.com>
Apisak Darakananda <pongad at gmail.com>
Aram Hăvărneanu <aram at mgk.ro>
Areski Belaid <areski at gmail.com>
@@ -136,6 +146,7 @@ Aron Nopanen <aron.nopanen at gmail.com>
Artyom Pervukhin <artyom.pervukhin at gmail.com>
Arvindh Rajesh Tamilmani <art at a-30.net>
Asim Shankar <asimshankar at gmail.com>
+Atin Malaviya <amalaviy at akamai.com>
Ato Araki <ato.araki at gmail.com>
Audrey Lim <audreylh at gmail.com>
Augusto Roman <aroman at gmail.com>
@@ -160,13 +171,17 @@ Bill Neubauer <wcn at golang.org> <wcn at google.com> <bill.neubauer at gmail.com>
Bill O'Farrell <billo at ca.ibm.com>
Bill Thiede <couchmoney at gmail.com>
Billie Harold Cleek <bhcleek at gmail.com>
+Billy Lynch <wlynch at google.com>
Bjorn Tillenius <bjorn at tillenius.me>
Bjorn Tipling <bjorn.tipling at gmail.com>
Blake Gentry <blakesgentry at gmail.com>
Blake Mizerany <blake.mizerany at gmail.com>
+Blixt <me at blixt.nyc>
Bobby Powers <bobbypowers at gmail.com>
+Boris Nagaev <nagaev at google.com>
Brad Fitzpatrick <bradfitz at golang.org> <bradfitz at gmail.com>
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 Gilmore <varz at google.com>
@@ -176,9 +191,11 @@ Brett Cannon <bcannon at gmail.com>
Brian Dellisanti <briandellisanti at gmail.com>
Brian G. Merrell <bgmerrell at gmail.com>
Brian Gitonga Marete <marete at toshnix.com> <bgmarete at gmail.com> <bgm at google.com>
+Brian Kennedy <btkennedy at gmail.com>
Brian Ketelsen <bketelsen at gmail.com>
Brian Slesinsky <skybrian at google.com>
Brian Smith <ohohvi 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>
@@ -187,10 +204,12 @@ Caio Marcelo de Oliveira Filho <caio.oliveira at intel.com>
Caleb Spare <cespare at gmail.com>
Carl Chatfield <carlchatfield at gmail.com>
Carl Jackson <carl at stripe.com>
+Carl Johnson <me at carlmjohnson.net>
Carl Mastrangelo <notcarl at google.com>
Carl Shapiro <cshapiro at google.com> <cshapiro at golang.org>
Carlos Castillo <cookieo9 at gmail.com>
Carlos Cirello <uldericofilho at gmail.com>
+Carlos Eduardo Seo <cseo at linux.vnet.ibm.com>
Cary Hull <chull at google.com>
Case Nelson <case.nelson at gmail.com>
Casey Marshall <casey.marshall at gmail.com>
@@ -240,10 +259,12 @@ Corey Thomasson <cthom.lists at gmail.com>
Cosmos Nicolaou <cnicolaou at google.com>
Cristian Staretu <unclejacksons at gmail.com>
Cuihtlauac ALVARADO <cuihtlauac.alvarado at orange.com>
+Cyrill Schumacher <cyrill at schumacher.fm>
Damian Gryski <dgryski at gmail.com>
Damien Neil <dneil at google.com>
Dan Caddigan <goldcaddy77 at gmail.com>
Dan Callahan <dan.callahan at gmail.com>
+Dan Harrington <harringtond at google.com>
Dan Jacques <dnj at google.com>
Dan Peterson <dpiddy at gmail.com>
Dan Pupius <dan at medium.com>
@@ -253,12 +274,14 @@ Daniel Johansson <dajo2002 at gmail.com>
Daniel Kerwin <d.kerwin at gini.net>
Daniel Krech <eikeon at eikeon.com>
Daniel Lidén <daniel.liden.87 at gmail.com>
+Daniel Martí <mvdan at mvdan.cc>
Daniel Morsing <daniel.morsing at gmail.com>
Daniel Nadasi <dnadasi at google.com>
Daniel Ortiz Pereira da Silva <daniel.particular at gmail.com>
Daniel Skinner <daniel at dasa.cc>
Daniel Speichert <daniel at speichert.pl>
Daniel Theophanes <kardianos at gmail.com>
+Daria Kolistratova <daria.kolistratova at intel.com>
Darren Elwood <darren at textnode.com>
Datong Sun <dndx at idndx.com>
Dave Borowitz <dborowitz at google.com>
@@ -280,30 +303,37 @@ David Forsythe <dforsythe at gmail.com>
David G. Andersen <dave.andersen at gmail.com>
David Glasser <glasser at meteor.com>
David Howden <dhowden at gmail.com>
+David Hubbard <dsp at google.com>
David Jakob Fritz <david.jakob.fritz at gmail.com>
David Leon Gil <coruus at gmail.com>
David McLeish <davemc at google.com>
David Presotto <presotto at gmail.com>
David R. Jenni <david.r.jenni at gmail.com>
David Sansome <me at davidsansome.com>
+David Stainton <dstainton415 at gmail.com>
David Symonds <dsymonds at golang.org>
David Thomas <davidthomas426 at gmail.com>
David Titarenco <david.titarenco at gmail.com>
Davies Liu <davies.liu at gmail.com>
Dean Prichard <dean.prichard at gmail.com>
+Deepak Jois <deepak.jois at gmail.com>
Denis Bernard <db047h at gmail.com>
Denis Brandolini <denis.brandolini at gmail.com>
+Denis Nagorny <denis.nagorny at intel.com>
Denys Honsiorovskyi <honsiorovskyi at gmail.com>
Derek Buitenhuis <derek.buitenhuis at gmail.com>
Derek Che <drc at yahoo-inc.com>
Derek Parker <parkerderek86 at gmail.com>
Derek Shockey <derek.shockey at gmail.com>
Devon H. O'Dell <devon.odell at gmail.com>
+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>
Dimitri Tcaciuc <dtcaciuc at gmail.com>
Dirk Gadsden <dirk at esherido.com>
Diwaker Gupta <diwakergupta at gmail.com>
+Dmitri Popov <operator at cv.dp-net.com>
Dmitri Shuralyov <shurcooL at gmail.com>
Dmitriy Dudkin <dudkin.dmitriy at gmail.com>
Dmitriy Shelenin <deemok at googlemail.com> <deemok at gmail.com>
@@ -343,10 +373,12 @@ Eric Roshan-Eisner <eric.d.eisner at gmail.com>
Erik Aigner <aigner.erik at gmail.com>
Erik Dubbelboer <erik at dubbelboer.com>
Erik St. Martin <alakriti at gmail.com>
+Erik Staab <estaab at google.com>
Erik Westrup <erik.westrup at gmail.com>
Ernest Chiang <ernest_chiang at htc.com>
Esko Luontola <esko.luontola at gmail.com>
Ethan Burns <eaburns at google.com>
+Ethan Miller <eamiller at us.ibm.com>
Evan Broder <evan at stripe.com>
Evan Brown <evanbrown at google.com>
Evan Kroske <evankroske at google.com>
@@ -356,10 +388,12 @@ Evan Shaw <chickencha at gmail.com>
Ewan Chou <coocood 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>
Fatih Arslan <fatih at arslan.io>
Fazlul Shahriar <fshahriar at gmail.com>
Federico Simoncelli <fsimonce at redhat.com>
+Fedor Indutny <fedor at indutny.com>
Felix Geisendörfer <haimuiba at gmail.com>
Filippo Valsorda <hi at filippo.io>
Firmansyah Adiputra <frm.adiputra at gmail.com>
@@ -378,12 +412,15 @@ Frits van Bommel <fvbommel at gmail.com>
Fumitoshi Ukai <ukai at google.com>
Gaal Yahas <gaal at google.com>
Gabriel Aszalos <gabriel.aszalos at gmail.com>
+Gabriel Russell <gabriel.russell at gmail.com>
+Gareth Paul Jones <gpj at foursquare.com>
Garrick Evans <garrick at google.com>
Gary Burd <gary at beagledreams.com> <gary.burd at gmail.com>
Gary Elliott <garyelliott at google.com>
Gaurish Sharma <contact at gaurishsharma.com>
Gautham Thambidorai <gautham.dorai at gmail.com>
Geert-Johan Riemer <gjr19912 at gmail.com>
+Geoffroy Lorieux <lorieux.g at gmail.com>
Georg Reinke <guelfey at gmail.com>
George Shammas <george at shamm.as> <georgyo at gmail.com>
Gerasimos Dimitriadis <gedimitr at gmail.com>
@@ -391,6 +428,7 @@ Gideon Jan-Wessel Redelinghuys <gjredelinghuys at gmail.com>
Giles Lean <giles.lean at pobox.com>
Giovanni Bajo <rasky at develer.com>
Giulio Iotti <dullgiulio at gmail.com>
+Gleb Stepanov <glebstepanov1992 at gmail.com>
Glenn Brown <glennb at google.com>
Glenn Lewis <gmlewis at google.com>
Gordon Klaus <gordon.klaus at gmail.com>
@@ -417,6 +455,7 @@ Hector Chu <hectorchu at gmail.com>
Hector Martin Cantero <hector at marcansoft.com>
Henning Schmiedehausen <henning at schmiedehausen.org>
Henrik Edwards <henrik.edwards at gmail.com>
+Henrik Hodne <henrik at hodne.io>
Herbert Georg Fischer <herbert.fischer at gmail.com>
Hironao OTSUBO <motemen at gmail.com>
Hiroshi Ioka <hirochachacha at gmail.com>
@@ -438,9 +477,11 @@ Ingo Krabbe <ikrabbe.ask at gmail.com>
Ingo Oeser <nightlyone at googlemail.com> <nightlyone at gmail.com>
Irieda Noboru <irieda at gmail.com>
Isaac Wagner <ibw at isaacwagner.me>
+Ivan Babrou <ivan at cloudflare.com>
Ivan Krasin <krasin at golang.org>
Ivan Ukhov <ivan.ukhov at gmail.com>
Jaana Burcu Dogan <jbd at google.com> <jbd at golang.org> <burcujdogan at gmail.com>
+Jack Lindamood <jlindamo at justin.tv>
Jacob Baskin <jbaskin at google.com>
Jacob H. Haven <jacob at cloudflare.com>
Jacob Hoffman-Andrews <github at hoffman-andrews.com>
@@ -451,6 +492,7 @@ Jakub Ryszard Czarnowicz <j.czarnowicz at gmail.com>
James Aguilar <jaguilar at google.com>
James Bardin <j.bardin at gmail.com>
James Chacon <jchacon at google.com>
+James Clarke <jrtc27 at jrtc27.com>
James David Chalfant <james.chalfant at gmail.com>
James Fysh <james.fysh at gmail.com>
James Gray <james at james4k.com>
@@ -462,6 +504,7 @@ 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 Turner <jamwt at dropbox.com>
Jamie Wilkinson <jaq at spacepants.org>
@@ -477,9 +520,11 @@ Jaroslavas Počepko <jp at webmaster.ms>
Jason Barnett <jason.w.barnett at gmail.com>
Jason Del Ponte <delpontej at gmail.com>
Jason Hall <jasonhall at google.com>
+Jason Smale <jsmale at zendesk.com>
Jason Travis <infomaniac7 at gmail.com>
Jay Weisskopf <jay at jayschwa.net>
Jean-Marc Eurin <jmeurin at google.com>
+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>
@@ -490,14 +535,17 @@ Jens Frederich <jfrederich at gmail.com>
Jeremiah Harmsen <jeremiah at google.com>
Jeremy Jackins <jeremyjackins at gmail.com>
Jeremy Schlatter <jeremy.schlatter at gmail.com>
+Jeroen Bobbeldijk <jerbob92 at gmail.com>
Jess Frazelle <me at jessfraz.com>
Jihyun Yu <yjh0502 at gmail.com>
Jim Cote <jfcote87 at gmail.com>
+Jim Kingdon <jim at bolt.me>
Jim McGrath <jimmc2 at gmail.com>
Jimmy Zelinskie <jimmyzelinskie at gmail.com>
Jingcheng Zhang <diogin at gmail.com>
Jingguo Yao <yaojingguo at gmail.com>
Jiong Du <londevil at gmail.com>
+Jirka Daněk <dnk at mail.muni.cz>
Joakim Sernbrant <serbaut at gmail.com>
Joe Farrell <joe2farrell at gmail.com>
Joe Harrison <joehazzers at gmail.com>
@@ -524,6 +572,7 @@ John Potocny <johnp at vividcortex.com>
John Schnake <schnake.john at gmail.com>
John Shahid <jvshahid at gmail.com>
John Tuley <john at tuley.org>
+Jon Chen <jchen at justin.tv>
Jonathan Allie <jonallie at google.com>
Jonathan Amsterdam <jba at google.com>
Jonathan Boulle <jonathanboulle at gmail.com>
@@ -536,14 +585,17 @@ Jonathan Pittman <jmpittman at google.com> <jonathan.mark.pittman at gmail.com>
Jonathan Rudenberg <jonathan at titanous.com>
Jonathan Wills <runningwild at gmail.com>
Jongmin Kim <atomaths at gmail.com>
+Joonas Kuorilehto <joneskoo at derbian.fi>
Jos Visser <josv at google.com>
Jose Luis Vázquez González <josvazg at gmail.com>
Joseph Bonneau <jcb at google.com>
Joseph Holsten <joseph at josephholsten.com>
Josh Bleecher Snyder <josharian at gmail.com>
+Josh Chorlton <jchorlton at gmail.com>
Josh Goebel <dreamer3 at gmail.com>
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>
Jostein Stuhaug <js at solidsystem.no>
JP Sugarbroad <jpsugar at google.com>
@@ -556,7 +608,9 @@ Julien Schmidt <google at julienschmidt.com>
Jungho Ahn <jhahn at google.com>
Jure Ham <jure.ham at zemanta.com>
Justin Nuß <nuss.justin at gmail.com>
+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 Kisiel <kamil at kamilkisiel.net> <kamil.kisiel at gmail.com>
Kang Hu <hukangustc at gmail.com>
@@ -598,6 +652,7 @@ L Campbell <unpantsu at gmail.com>
Lai Jiangshan <eag0628 at gmail.com>
Larry Hosken <lahosken at golang.org>
Larz Conwell <larzconwell at gmail.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>
@@ -608,6 +663,7 @@ Luan Santos <cfcluan at gmail.com>
Luca Greco <luca.greco at alcacoop.it>
Lucien Stuker <lucien.stuker at gmail.com>
Lucio De Re <lucio.dere at gmail.com>
+Luigi Riefolo <luigi.riefolo at gmail.com>
Luit van Drongelen <luitvd at gmail.com>
Luka Zakrajšek <tr00.g33k at gmail.com>
Luke Curley <qpingu at gmail.com>
@@ -615,6 +671,7 @@ Luna Duclos <luna.duclos at palmstonegames.com>
Luuk van Dijk <lvd at golang.org> <lvd at google.com>
Lynn Boger <laboger at linux.vnet.ibm.com>
Mal Curtis <mal at mal.co.nz>
+Manfred Touron <m at 42.am>
Manoj Dayaram <platform-dev at moovweb.com> <manoj.dayaram at moovweb.com>
Manu Garg <manugarg at google.com>
Manu S Ajith <neo at codingarena.in>
@@ -635,8 +692,10 @@ Marko Tiikkaja <marko at joh.to>
Markus Duft <markus.duft at salomon.at>
Markus Sonderegger <marraison at gmail.com>
Markus Zimmermann <zimmski at gmail.com>
+Martin Bertschler <mbertschler at gmail.com>
Martin Garton <garton at gmail.com>
-Martin Möhrmann <martisch at uos.de>
+Martin Hamrle <martin.hamrle 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>
@@ -660,8 +719,10 @@ Matt Williams <gh at mattyw.net> <mattyjwilliams at gmail.com>
Matthew Brennan <matty.brennan at gmail.com>
Matthew Cottingham <mattcottingham at gmail.com>
Matthew Dempsky <mdempsky at google.com>
+Matthew Denton <mdenton at skyportsystems.com>
Matthew Holt <Matthew.Holt+git at gmail.com>
Matthew Horsnell <matthew.horsnell at gmail.com>
+Matthieu Hauglustaine <matt.hauglustaine at gmail.com>
Maxim Khitrov <max at mxcrypt.com>
Maxim Pimenov <mpimenov at google.com>
Maxim Ushakov <ushakov at google.com>
@@ -671,6 +732,7 @@ Meng Zhuo <mengzhuo1203 at gmail.com>
Mhd Sulhan <m.shulhan at gmail.com>
Micah Stetson <micah.stetson at gmail.com>
Michael Chaten <mchaten at gmail.com>
+Michael Darakananda <pongad at google.com>
Michael Elkins <michael.elkins at gmail.com>
Michael Fraenkel <michael.fraenkel at gmail.com>
Michael Gehring <mg at ebfe.org> <gnirheg.leahcim at gmail.com>
@@ -704,17 +766,22 @@ Miguel Mendez <stxmendez at gmail.com>
Mihai Borobocea <MihaiBorobocea at gmail.com>
Mikael Tillenius <mikti42 at gmail.com>
Mike Andrews <mra at xoba.com>
+Mike Appleby <mike at app.leby.org>
Mike Danese <mikedanese at google.com>
+Mike Houston <mike at kothar.net>
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>
Mikhail Gusarov <dottedmag at dottedmag.net>
Mikhail Panchenko <m at mihasya.com>
Miki Tebeka <miki.tebeka at gmail.com>
Mikio Hara <mikioh.mikioh at gmail.com>
Mikkel Krautz <mikkel at krautz.dk> <krautz at gmail.com>
Miquel Sabaté Solà <mikisabate at gmail.com>
+Miroslav Genov <mgenov at gmail.com>
Mohit Agarwal <mohit at sdf.org>
+Momchil Velikov <momchil.velikov at gmail.com>
Monty Taylor <mordred at inaugust.com>
Moriyoshi Koizumi <mozo at mozo.jp>
Morten Siebuhr <sbhr at sbhr.dk>
@@ -738,6 +805,7 @@ 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 Patavalis <nick.patavalis at gmail.com>
Nick Petroni <npetroni at cs.umd.edu>
Nicolas Kaiser <nikai at nikai.net>
@@ -751,6 +819,7 @@ Nikolay Turpitko <nikolay at turpitko.com>
Noah Campbell <noahcampbell at gmail.com>
Nodir Turakulov <nodir at google.com>
Norberto Lopes <nlopes.ml at gmail.com>
+Oleg Vakheta <helginet at gmail.com>
Oleku Konko <oleku.konko at gmail.com>
Oling Cat <olingcat at gmail.com>
Oliver Hookins <ohookins at gmail.com>
@@ -763,6 +832,7 @@ Omar Jarjur <ojarjur at google.com>
Padraig Kitterick <padraigkitterick at gmail.com>
Paolo Giarrusso <p.giarrusso at gmail.com>
Paolo Martini <mrtnpaolo at gmail.com>
+Parker Moore <parkrmoore at gmail.com>
Pascal S. de Kloe <pascal at quies.net>
Patrick Crosby <patrick at stathat.com>
Patrick Gavlin <pgavlin at gmail.com>
@@ -817,6 +887,7 @@ Pierre Durand <pierredurand at gmail.com>
Pierre Roullon <pierre.roullon at gmail.com>
Pieter Droogendijk <pieter at binky.org.uk>
Pietro Gagliardi <pietro10 at mac.com>
+Prasanna Swaminathan <prasanna at mediamath.com>
Prashant Varanasi <prashant at prashantv.com>
Preetam Jinka <pj at preet.am>
Quan Tran <qeed.quan at gmail.com>
@@ -824,10 +895,12 @@ Quan Yong Zhai <qyzhai at gmail.com>
Quentin Perez <qperez at ocs.online.net>
Quentin Smith <quentin at golang.org>
Quoc-Viet Nguyen <afelion at gmail.com>
+Radu Berinde <radu at cockroachlabs.com>
Rahul Chaudhry <rahulchaudhry at chromium.org>
Raif S. Naffah <go at naffah-raif.name>
Rajat Goel <rajat.goel2010 at gmail.com>
Ralph Corderoy <ralph at inputplus.co.uk>
+Ramesh Dharan <dharan at google.com>
Raph Levien <raph at google.com>
Raul Silvera <rsilvera at google.com>
Reinaldo de Souza Jr <juniorz at gmail.com>
@@ -837,6 +910,7 @@ Ricardo Padilha <ricardospadilha at gmail.com>
Richard Barnes <rlb at ipv.sx>
Richard Crowley <r at rcrowley.org>
Richard Eric Gavaletz <gavaletz at gmail.com>
+Richard Gibson <richard.gibson at gmail.com>
Richard Miller <miller.research at gmail.com>
Richard Musiol <mail at richard-musiol.de> <neelance at gmail.com>
Rick Arnold <rickarnoldjr at gmail.com>
@@ -884,7 +958,10 @@ Sam Thorogood <thorogood at google.com> <sam.thorogood at gmail.com>
Sam Whited <sam at samwhited.com>
Sameer Ajmani <sameer at golang.org> <ajmani at gmail.com>
Sami Commerot <samic at google.com>
+Samuel Tan <samueltan at google.com>
+Samuele Pedroni <pedronis at lucediurna.net>
Sanjay Menakuru <balasanjay at gmail.com>
+Sarah Adams <shadams at google.com>
Sasha Lionheart <lionhearts at google.com>
Sasha Sobol <sasha at scaledinference.com>
Scott Barron <scott.barron at github.com>
@@ -897,6 +974,7 @@ Scott Van Woudenberg <scottvw at google.com>
Sean Burford <sburford at google.com>
Sean Dolphin <Sean.Dolphin at kpcompass.com>
Sean Harger <sharger at google.com>
+Sean Rees <sean at erifax.org>
Sebastien Binet <seb.binet at gmail.com>
Sébastien Paolacci <sebastien.paolacci at gmail.com>
Sergei Skorobogatov <skorobo at rambler.ru>
@@ -917,9 +995,12 @@ Shivakumar GN <shivakumar.gn at gmail.com>
Shun Fan <sfan at google.com>
Silvan Jegen <s.jegen at gmail.com>
Simon Jefford <simon.jefford at gmail.com>
+Simon Rawet <simon at rawet.se>
Simon Thulbourn <simon+github at thulbourn.com>
Simon Whitehead <chemnova at gmail.com>
+Sina Siadat <siadat at gmail.com>
Sokolov Yura <funny.falcon at gmail.com>
+Song Gao <song at gao.io>
Spencer Nelson <s at spenczar.com>
Spring Mc <heresy.mc at gmail.com>
Srdjan Petrovic <spetrovic at google.com>
@@ -939,7 +1020,10 @@ Steven Elliot Harris <seharris at gmail.com>
Steven Hartland <steven.hartland at multiplay.co.uk>
Sugu Sougoumarane <ssougou at gmail.com>
Suharsh Sivakumar <suharshs at google.com>
+Suyash <dextrous93 at gmail.com>
Sven Almgren <sven at tras.se>
+Sven Blumenstein <svbl at google.com>
+Syohei YOSHIDA <syohex at gmail.com>
Szabolcs Nagy <nsz at port70.net>
Tad Glines <tad.glines at gmail.com>
Taj Khattra <taj.khattra at gmail.com>
@@ -950,9 +1034,12 @@ Tamir Duberstein <tamird at gmail.com>
Tarmigan Casebolt <tarmigan at gmail.com>
Taru Karttunen <taruti at taruti.net>
Tatsuhiro Tsujikawa <tatsuhiro.t at gmail.com>
+Terrel Shumway <gopher at shumway.us>
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 de Zeeuw <thomasdezeeuw at gmail.com>
Thomas Desrosiers <thomasdesr at gmail.com>
Thomas Habets <habets at google.com>
Thomas Kappler <tkappler at gmail.com>
@@ -960,6 +1047,7 @@ Thorben Krueger <thorben.krueger at gmail.com>
Tilman Dilo <tilman.dilo at gmail.com>
Tim Cooijmans <timcooijmans at gmail.com>
Tim Ebringer <tim.ebringer at gmail.com>
+Tim Henderson <tim.tadh at gmail.com>
Tim Hockin <thockin at google.com>
Tim Swast <swast at google.com>
Timo Savola <timo.savola at gmail.com>
@@ -974,15 +1062,19 @@ Tom Bergan <tombergan at google.com>
Tom Heng <zhm20070928 at gmail.com>
Tom Linford <tomlinford at gmail.com>
Tom Szymanski <tgs at google.com>
+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>
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 Tacon <ttacon at gmail.com>
Tristan Amini <tamini01 at ca.ibm.com>
+Tristan Ooohry <ooohry at gmail.com>
Tudor Golubenco <tudor.g at gmail.com>
+Tuo Shan <sturbo89 at gmail.com> <shantuo at google.com>
Tyler Bunnell <tylerbunnell at gmail.com>
Tyler Treat <ttreat31 at gmail.com>
Tzu-Jung Lee <roylee17 at currant.com>
@@ -994,15 +1086,21 @@ Uttam C Pawar <uttam.c.pawar at intel.com>
Vadim Grek <vadimprog at gmail.com>
Vadim Vygonets <unixdj at gmail.com>
Vega Garcia Luis Alfonso <vegacom at gmail.com>
+Victor Chudnovsky <vchudnov at google.com>
Vincent Ambo <tazjin at googlemail.com>
Vincent Batts <vbatts at hashbangbash.com> <vbatts at gmail.com>
Vincent Vanackere <vincent.vanackere at gmail.com>
Vinu Rajashekhar <vinutheraj at gmail.com>
Vish Subramanian <vish at google.com>
Vishvananda Ishaya <vishvananda at gmail.com>
+Vitor De Mario <vitordemario at gmail.com>
Vlad Krasnov <vlad at cloudflare.com>
+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>
+Volodymyr Paprotski <vpaprots at ca.ibm.com>
+Walter Poupore <wpoupore at google.com>
Wedson Almeida Filho <wedsonaf at google.com>
Wei Guangjing <vcc.163 at gmail.com>
Will Chan <willchan at google.com>
@@ -1015,6 +1113,7 @@ Wisdom Omuya <deafgoat at gmail.com>
Xia Bin <snyh at snyh.org>
Xing Xing <mikespook at gmail.com>
Xudong Zhang <felixmelon at gmail.com>
+Xuyang Kang <xuyangkang at gmail.com>
Yan Zou <yzou at google.com>
Yann Kerhervé <yann.kerherve at gmail.com>
Yao Zhang <lunaria21 at gmail.com>
@@ -1024,6 +1123,7 @@ Yesudeep Mangalapilly <yesudeep at google.com>
Yissakhar Z. Beck <yissakhar.beck at gmail.com>
Yo-An Lin <yoanlin93 at gmail.com>
Yongjian Xu <i3dmaster at gmail.com>
+Yorman Arias <cixtords at gmail.com>
Yoshiyuki Kanno <nekotaroh at gmail.com> <yoshiyuki.kanno at stoic.co.jp>
Yu Heng Zhang <annita.zhang at cn.ibm.com>
Yu Xuan Zhang <zyxsh at cn.ibm.com>
@@ -1032,6 +1132,7 @@ Yusuke Kagiwada <block.rxckin.beats at gmail.com>
Yuusei Kuwana <kuwana at kumama.org>
Yuval Pavel Zholkover <paulzhol at gmail.com>
Yves Junqueira <yvesj at google.com> <yves.junqueira at gmail.com>
+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>
diff --git a/VERSION b/VERSION
index 83caa74..6ec9dfa 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-go1.7.4
\ No newline at end of file
+go1.8beta1
\ No newline at end of file
diff --git a/api/except.txt b/api/except.txt
index 4040d14..2062cbf 100644
--- a/api/except.txt
+++ b/api/except.txt
@@ -1,23 +1,107 @@
+pkg encoding/json, method (*RawMessage) MarshalJSON() ([]uint8, error)
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
+pkg syscall (darwin-386), const ImplementsGetwd = false
pkg syscall (darwin-386), func Fchflags(string, int) error
+pkg syscall (darwin-386-cgo), const ImplementsGetwd = false
pkg syscall (darwin-386-cgo), func Fchflags(string, int) error
+pkg syscall (darwin-amd64), const ImplementsGetwd = false
pkg syscall (darwin-amd64), func Fchflags(string, int) error
+pkg syscall (darwin-amd64-cgo), const ImplementsGetwd = false
pkg syscall (darwin-amd64-cgo), func Fchflags(string, int) error
+pkg syscall (freebsd-386), const AF_MAX = 38
+pkg syscall (freebsd-386), const DLT_MATCHING_MAX = 242
+pkg syscall (freebsd-386), const ELAST = 94
+pkg syscall (freebsd-386), const O_CLOEXEC = 0
pkg syscall (freebsd-386), func Fchflags(string, int) error
+pkg syscall (freebsd-386-cgo), const AF_MAX = 38
+pkg syscall (freebsd-386-cgo), const DLT_MATCHING_MAX = 242
+pkg syscall (freebsd-386-cgo), const ELAST = 94
+pkg syscall (freebsd-386-cgo), const O_CLOEXEC = 0
+pkg syscall (freebsd-amd64), const AF_MAX = 38
+pkg syscall (freebsd-amd64), const DLT_MATCHING_MAX = 242
+pkg syscall (freebsd-amd64), const ELAST = 94
+pkg syscall (freebsd-amd64), const O_CLOEXEC = 0
pkg syscall (freebsd-amd64), func Fchflags(string, int) error
+pkg syscall (freebsd-amd64-cgo), const AF_MAX = 38
+pkg syscall (freebsd-amd64-cgo), const DLT_MATCHING_MAX = 242
+pkg syscall (freebsd-amd64-cgo), const ELAST = 94
+pkg syscall (freebsd-amd64-cgo), const O_CLOEXEC = 0
+pkg syscall (freebsd-arm), const AF_MAX = 38
+pkg syscall (freebsd-arm), const BIOCGRTIMEOUT = 1074545262
+pkg syscall (freebsd-arm), const BIOCSRTIMEOUT = 2148287085
+pkg syscall (freebsd-arm), const ELAST = 94
+pkg syscall (freebsd-arm), const O_CLOEXEC = 0
+pkg syscall (freebsd-arm), const SIOCAIFADDR = 2151967019
+pkg syscall (freebsd-arm), const SIOCGIFSTATUS = 3274991931
+pkg syscall (freebsd-arm), const SIOCSIFPHYADDR = 2151967046
+pkg syscall (freebsd-arm), const SYS_CAP_FCNTLS_GET = 537
+pkg syscall (freebsd-arm), const SYS_CAP_FCNTLS_GET ideal-int
+pkg syscall (freebsd-arm), const SYS_CAP_FCNTLS_LIMIT = 536
+pkg syscall (freebsd-arm), const SYS_CAP_FCNTLS_LIMIT ideal-int
+pkg syscall (freebsd-arm), const SYS_CAP_IOCTLS_GET = 535
+pkg syscall (freebsd-arm), const SYS_CAP_IOCTLS_GET ideal-int
+pkg syscall (freebsd-arm), const SYS_CAP_IOCTLS_LIMIT = 534
+pkg syscall (freebsd-arm), const SYS_CAP_IOCTLS_LIMIT ideal-int
+pkg syscall (freebsd-arm), const SYS_CAP_RIGHTS_GET = 515
+pkg syscall (freebsd-arm), const SYS_CAP_RIGHTS_GET ideal-int
+pkg syscall (freebsd-arm), const SYS_CAP_RIGHTS_LIMIT = 533
+pkg syscall (freebsd-arm), const SYS_CAP_RIGHTS_LIMIT ideal-int
+pkg syscall (freebsd-arm), const SizeofBpfHdr = 24
+pkg syscall (freebsd-arm), const SizeofIfData = 88
+pkg syscall (freebsd-arm), const SizeofIfMsghdr = 104
+pkg syscall (freebsd-arm), const SizeofSockaddrDatalink = 56
+pkg syscall (freebsd-arm), const SizeofSockaddrUnix = 108
+pkg syscall (freebsd-arm), const TIOCTIMESTAMP = 1074558041
pkg syscall (freebsd-arm), func Fchflags(string, int) error
+pkg syscall (freebsd-arm), type BpfHdr struct, Pad_cgo_0 [2]uint8
+pkg syscall (freebsd-arm), type RawSockaddrDatalink struct, Pad_cgo_0 [2]uint8
+pkg syscall (freebsd-arm), type RawSockaddrUnix struct, Pad_cgo_0 [2]uint8
+pkg syscall (freebsd-arm), type Stat_t struct, Pad_cgo_0 [4]uint8
+pkg syscall (freebsd-arm-cgo), const AF_MAX = 38
+pkg syscall (freebsd-arm-cgo), const BIOCGRTIMEOUT = 1074545262
+pkg syscall (freebsd-arm-cgo), const BIOCSRTIMEOUT = 2148287085
+pkg syscall (freebsd-arm-cgo), const ELAST = 94
+pkg syscall (freebsd-arm-cgo), const O_CLOEXEC = 0
+pkg syscall (freebsd-arm-cgo), const SIOCAIFADDR = 2151967019
+pkg syscall (freebsd-arm-cgo), const SIOCGIFSTATUS = 3274991931
+pkg syscall (freebsd-arm-cgo), const SIOCSIFPHYADDR = 2151967046
+pkg syscall (freebsd-arm-cgo), const SYS_CAP_FCNTLS_GET = 537
+pkg syscall (freebsd-arm-cgo), const SYS_CAP_FCNTLS_GET ideal-int
+pkg syscall (freebsd-arm-cgo), const SYS_CAP_FCNTLS_LIMIT = 536
+pkg syscall (freebsd-arm-cgo), const SYS_CAP_FCNTLS_LIMIT ideal-int
+pkg syscall (freebsd-arm-cgo), const SYS_CAP_IOCTLS_GET = 535
+pkg syscall (freebsd-arm-cgo), const SYS_CAP_IOCTLS_GET ideal-int
+pkg syscall (freebsd-arm-cgo), const SYS_CAP_IOCTLS_LIMIT = 534
+pkg syscall (freebsd-arm-cgo), const SYS_CAP_IOCTLS_LIMIT ideal-int
+pkg syscall (freebsd-arm-cgo), const SYS_CAP_RIGHTS_GET = 515
+pkg syscall (freebsd-arm-cgo), const SYS_CAP_RIGHTS_GET ideal-int
+pkg syscall (freebsd-arm-cgo), const SYS_CAP_RIGHTS_LIMIT = 533
+pkg syscall (freebsd-arm-cgo), const SYS_CAP_RIGHTS_LIMIT ideal-int
+pkg syscall (freebsd-arm-cgo), const SizeofBpfHdr = 24
+pkg syscall (freebsd-arm-cgo), const SizeofIfData = 88
+pkg syscall (freebsd-arm-cgo), const SizeofIfMsghdr = 104
+pkg syscall (freebsd-arm-cgo), const SizeofSockaddrDatalink = 56
+pkg syscall (freebsd-arm-cgo), const SizeofSockaddrUnix = 108
+pkg syscall (freebsd-arm-cgo), const TIOCTIMESTAMP = 1074558041
pkg syscall (freebsd-arm-cgo), func Fchflags(string, int) error
+pkg syscall (freebsd-arm-cgo), type BpfHdr struct, Pad_cgo_0 [2]uint8
+pkg syscall (freebsd-arm-cgo), type RawSockaddrDatalink struct, Pad_cgo_0 [2]uint8
+pkg syscall (freebsd-arm-cgo), type RawSockaddrUnix struct, Pad_cgo_0 [2]uint8
+pkg syscall (freebsd-arm-cgo), type Stat_t struct, Pad_cgo_0 [4]uint8
+pkg syscall (linux-386), type Cmsghdr struct, X__cmsg_data [0]uint8
+pkg syscall (linux-386-cgo), type Cmsghdr struct, X__cmsg_data [0]uint8
+pkg syscall (linux-amd64), type Cmsghdr struct, X__cmsg_data [0]uint8
+pkg syscall (linux-amd64-cgo), type Cmsghdr struct, X__cmsg_data [0]uint8
+pkg syscall (linux-arm), type Cmsghdr struct, X__cmsg_data [0]uint8
+pkg syscall (linux-arm-cgo), type Cmsghdr struct, X__cmsg_data [0]uint8
+pkg syscall (netbsd-arm), const SizeofIfData = 132
pkg syscall (netbsd-arm), func Fchflags(string, int) error
+pkg syscall (netbsd-arm), type IfMsghdr struct, Pad_cgo_1 [4]uint8
+pkg syscall (netbsd-arm-cgo), const SizeofIfData = 132
pkg syscall (netbsd-arm-cgo), func Fchflags(string, int) error
-pkg testing, func RegisterCover(Cover)
-pkg text/template/parse, type DotNode bool
-pkg text/template/parse, type Node interface { Copy, String, Type }
-pkg os (linux-arm), const O_SYNC = 4096
-pkg os (linux-arm-cgo), const O_SYNC = 4096
-pkg syscall (darwin-386), const ImplementsGetwd = false
-pkg syscall (darwin-386-cgo), const ImplementsGetwd = false
-pkg syscall (darwin-amd64), const ImplementsGetwd = false
-pkg syscall (darwin-amd64-cgo), const ImplementsGetwd = false
+pkg syscall (netbsd-arm-cgo), type IfMsghdr struct, Pad_cgo_1 [4]uint8
pkg syscall (openbsd-386), const BIOCGRTIMEOUT = 1074283118
pkg syscall (openbsd-386), const BIOCSRTIMEOUT = 2148024941
pkg syscall (openbsd-386), const RTF_FMASK = 63496
@@ -246,87 +330,11 @@ pkg syscall (openbsd-amd64-cgo), type Statfs_t struct, F_spare [3]uint32
pkg syscall (openbsd-amd64-cgo), type Statfs_t struct, Pad_cgo_1 [4]uint8
pkg syscall (openbsd-amd64-cgo), type Timespec struct, Pad_cgo_0 [4]uint8
pkg syscall (openbsd-amd64-cgo), type Timespec struct, Sec int32
+pkg testing, func RegisterCover(Cover)
+pkg testing, func MainStart(func(string, string) (bool, error), []InternalTest, []InternalBenchmark, []InternalExample) *M
+pkg text/template/parse, type DotNode bool
+pkg text/template/parse, type Node interface { Copy, String, Type }
pkg unicode, const Version = "6.2.0"
-pkg syscall (freebsd-386), const AF_MAX = 38
-pkg syscall (freebsd-386), const DLT_MATCHING_MAX = 242
-pkg syscall (freebsd-386), const ELAST = 94
-pkg syscall (freebsd-386), const O_CLOEXEC = 0
-pkg syscall (freebsd-386-cgo), const AF_MAX = 38
-pkg syscall (freebsd-386-cgo), const DLT_MATCHING_MAX = 242
-pkg syscall (freebsd-386-cgo), const ELAST = 94
-pkg syscall (freebsd-386-cgo), const O_CLOEXEC = 0
-pkg syscall (freebsd-amd64), const AF_MAX = 38
-pkg syscall (freebsd-amd64), const DLT_MATCHING_MAX = 242
-pkg syscall (freebsd-amd64), const ELAST = 94
-pkg syscall (freebsd-amd64), const O_CLOEXEC = 0
-pkg syscall (freebsd-amd64-cgo), const AF_MAX = 38
-pkg syscall (freebsd-amd64-cgo), const DLT_MATCHING_MAX = 242
-pkg syscall (freebsd-amd64-cgo), const ELAST = 94
-pkg syscall (freebsd-amd64-cgo), const O_CLOEXEC = 0
-pkg syscall (freebsd-arm), const AF_MAX = 38
-pkg syscall (freebsd-arm), const BIOCGRTIMEOUT = 1074545262
-pkg syscall (freebsd-arm), const BIOCSRTIMEOUT = 2148287085
-pkg syscall (freebsd-arm), const ELAST = 94
-pkg syscall (freebsd-arm), const O_CLOEXEC = 0
-pkg syscall (freebsd-arm), const SIOCAIFADDR = 2151967019
-pkg syscall (freebsd-arm), const SIOCGIFSTATUS = 3274991931
-pkg syscall (freebsd-arm), const SIOCSIFPHYADDR = 2151967046
-pkg syscall (freebsd-arm), const SYS_CAP_FCNTLS_GET = 537
-pkg syscall (freebsd-arm), const SYS_CAP_FCNTLS_GET ideal-int
-pkg syscall (freebsd-arm), const SYS_CAP_FCNTLS_LIMIT = 536
-pkg syscall (freebsd-arm), const SYS_CAP_FCNTLS_LIMIT ideal-int
-pkg syscall (freebsd-arm), const SYS_CAP_IOCTLS_GET = 535
-pkg syscall (freebsd-arm), const SYS_CAP_IOCTLS_GET ideal-int
-pkg syscall (freebsd-arm), const SYS_CAP_IOCTLS_LIMIT = 534
-pkg syscall (freebsd-arm), const SYS_CAP_IOCTLS_LIMIT ideal-int
-pkg syscall (freebsd-arm), const SYS_CAP_RIGHTS_GET = 515
-pkg syscall (freebsd-arm), const SYS_CAP_RIGHTS_GET ideal-int
-pkg syscall (freebsd-arm), const SYS_CAP_RIGHTS_LIMIT = 533
-pkg syscall (freebsd-arm), const SYS_CAP_RIGHTS_LIMIT ideal-int
-pkg syscall (freebsd-arm), const SizeofBpfHdr = 24
-pkg syscall (freebsd-arm), const SizeofIfData = 88
-pkg syscall (freebsd-arm), const SizeofIfMsghdr = 104
-pkg syscall (freebsd-arm), const SizeofSockaddrDatalink = 56
-pkg syscall (freebsd-arm), const SizeofSockaddrUnix = 108
-pkg syscall (freebsd-arm), const TIOCTIMESTAMP = 1074558041
-pkg syscall (freebsd-arm), type BpfHdr struct, Pad_cgo_0 [2]uint8
-pkg syscall (freebsd-arm), type RawSockaddrDatalink struct, Pad_cgo_0 [2]uint8
-pkg syscall (freebsd-arm), type RawSockaddrUnix struct, Pad_cgo_0 [2]uint8
-pkg syscall (freebsd-arm), type Stat_t struct, Pad_cgo_0 [4]uint8
-pkg syscall (freebsd-arm-cgo), const AF_MAX = 38
-pkg syscall (freebsd-arm-cgo), const BIOCGRTIMEOUT = 1074545262
-pkg syscall (freebsd-arm-cgo), const BIOCSRTIMEOUT = 2148287085
-pkg syscall (freebsd-arm-cgo), const ELAST = 94
-pkg syscall (freebsd-arm-cgo), const O_CLOEXEC = 0
-pkg syscall (freebsd-arm-cgo), const SIOCAIFADDR = 2151967019
-pkg syscall (freebsd-arm-cgo), const SIOCGIFSTATUS = 3274991931
-pkg syscall (freebsd-arm-cgo), const SIOCSIFPHYADDR = 2151967046
-pkg syscall (freebsd-arm-cgo), const SYS_CAP_FCNTLS_GET = 537
-pkg syscall (freebsd-arm-cgo), const SYS_CAP_FCNTLS_GET ideal-int
-pkg syscall (freebsd-arm-cgo), const SYS_CAP_FCNTLS_LIMIT = 536
-pkg syscall (freebsd-arm-cgo), const SYS_CAP_FCNTLS_LIMIT ideal-int
-pkg syscall (freebsd-arm-cgo), const SYS_CAP_IOCTLS_GET = 535
-pkg syscall (freebsd-arm-cgo), const SYS_CAP_IOCTLS_GET ideal-int
-pkg syscall (freebsd-arm-cgo), const SYS_CAP_IOCTLS_LIMIT = 534
-pkg syscall (freebsd-arm-cgo), const SYS_CAP_IOCTLS_LIMIT ideal-int
-pkg syscall (freebsd-arm-cgo), const SYS_CAP_RIGHTS_GET = 515
-pkg syscall (freebsd-arm-cgo), const SYS_CAP_RIGHTS_GET ideal-int
-pkg syscall (freebsd-arm-cgo), const SYS_CAP_RIGHTS_LIMIT = 533
-pkg syscall (freebsd-arm-cgo), const SYS_CAP_RIGHTS_LIMIT ideal-int
-pkg syscall (freebsd-arm-cgo), const SizeofBpfHdr = 24
-pkg syscall (freebsd-arm-cgo), const SizeofIfData = 88
-pkg syscall (freebsd-arm-cgo), const SizeofIfMsghdr = 104
-pkg syscall (freebsd-arm-cgo), const SizeofSockaddrDatalink = 56
-pkg syscall (freebsd-arm-cgo), const SizeofSockaddrUnix = 108
-pkg syscall (freebsd-arm-cgo), const TIOCTIMESTAMP = 1074558041
-pkg syscall (freebsd-arm-cgo), type BpfHdr struct, Pad_cgo_0 [2]uint8
-pkg syscall (freebsd-arm-cgo), type RawSockaddrDatalink struct, Pad_cgo_0 [2]uint8
-pkg syscall (freebsd-arm-cgo), type RawSockaddrUnix struct, Pad_cgo_0 [2]uint8
-pkg syscall (freebsd-arm-cgo), type Stat_t struct, Pad_cgo_0 [4]uint8
-pkg syscall (netbsd-arm), const SizeofIfData = 132
-pkg syscall (netbsd-arm), type IfMsghdr struct, Pad_cgo_1 [4]uint8
-pkg syscall (netbsd-arm-cgo), const SizeofIfData = 132
-pkg syscall (netbsd-arm-cgo), type IfMsghdr struct, Pad_cgo_1 [4]uint8
pkg unicode, const Version = "6.3.0"
pkg unicode, const Version = "7.0.0"
pkg unicode, const Version = "8.0.0"
diff --git a/api/go1.8.txt b/api/go1.8.txt
new file mode 100644
index 0000000..e9ddc28
--- /dev/null
+++ b/api/go1.8.txt
@@ -0,0 +1,259 @@
+pkg compress/gzip, const HuffmanOnly = -2
+pkg compress/gzip, const HuffmanOnly ideal-int
+pkg compress/zlib, const HuffmanOnly = -2
+pkg compress/zlib, const HuffmanOnly ideal-int
+pkg crypto/tls, const ECDSAWithP256AndSHA256 = 1027
+pkg crypto/tls, const ECDSAWithP256AndSHA256 SignatureScheme
+pkg crypto/tls, const ECDSAWithP384AndSHA384 = 1283
+pkg crypto/tls, const ECDSAWithP384AndSHA384 SignatureScheme
+pkg crypto/tls, const ECDSAWithP521AndSHA512 = 1539
+pkg crypto/tls, const ECDSAWithP521AndSHA512 SignatureScheme
+pkg crypto/tls, const PKCS1WithSHA1 = 513
+pkg crypto/tls, const PKCS1WithSHA1 SignatureScheme
+pkg crypto/tls, const PKCS1WithSHA256 = 1025
+pkg crypto/tls, const PKCS1WithSHA256 SignatureScheme
+pkg crypto/tls, const PKCS1WithSHA384 = 1281
+pkg crypto/tls, const PKCS1WithSHA384 SignatureScheme
+pkg crypto/tls, const PKCS1WithSHA512 = 1537
+pkg crypto/tls, const PKCS1WithSHA512 SignatureScheme
+pkg crypto/tls, const PSSWithSHA256 = 2052
+pkg crypto/tls, const PSSWithSHA256 SignatureScheme
+pkg crypto/tls, const PSSWithSHA384 = 2053
+pkg crypto/tls, const PSSWithSHA384 SignatureScheme
+pkg crypto/tls, const PSSWithSHA512 = 2054
+pkg crypto/tls, const PSSWithSHA512 SignatureScheme
+pkg crypto/tls, const TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 = 49187
+pkg crypto/tls, const TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 uint16
+pkg crypto/tls, const TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305 = 52393
+pkg crypto/tls, const TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305 uint16
+pkg crypto/tls, const TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 = 49191
+pkg crypto/tls, const TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 uint16
+pkg crypto/tls, const TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305 = 52392
+pkg crypto/tls, const TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305 uint16
+pkg crypto/tls, const TLS_RSA_WITH_AES_128_CBC_SHA256 = 60
+pkg crypto/tls, const TLS_RSA_WITH_AES_128_CBC_SHA256 uint16
+pkg crypto/tls, const X25519 = 29
+pkg crypto/tls, const X25519 CurveID
+pkg crypto/tls, method (*Config) Clone() *Config
+pkg crypto/tls, method (*Conn) CloseWrite() error
+pkg crypto/tls, type CertificateRequestInfo struct
+pkg crypto/tls, type CertificateRequestInfo struct, AcceptableCAs [][]uint8
+pkg crypto/tls, type CertificateRequestInfo struct, SignatureSchemes []SignatureScheme
+pkg crypto/tls, type ClientHelloInfo struct, Conn net.Conn
+pkg crypto/tls, type ClientHelloInfo struct, SignatureSchemes []SignatureScheme
+pkg crypto/tls, type ClientHelloInfo struct, SupportedProtos []string
+pkg crypto/tls, type ClientHelloInfo struct, SupportedVersions []uint16
+pkg crypto/tls, type Config struct, GetClientCertificate func(*CertificateRequestInfo) (*Certificate, error)
+pkg crypto/tls, type Config struct, GetConfigForClient func(*ClientHelloInfo) (*Config, error)
+pkg crypto/tls, type Config struct, KeyLogWriter io.Writer
+pkg crypto/tls, type Config struct, VerifyPeerCertificate func([][]uint8, [][]*x509.Certificate) error
+pkg crypto/tls, type SignatureScheme uint16
+pkg crypto/x509, const NameMismatch = 5
+pkg crypto/x509, const NameMismatch InvalidReason
+pkg crypto/x509, const SHA256WithRSAPSS = 13
+pkg crypto/x509, const SHA256WithRSAPSS SignatureAlgorithm
+pkg crypto/x509, const SHA384WithRSAPSS = 14
+pkg crypto/x509, const SHA384WithRSAPSS SignatureAlgorithm
+pkg crypto/x509, const SHA512WithRSAPSS = 15
+pkg crypto/x509, const SHA512WithRSAPSS SignatureAlgorithm
+pkg crypto/x509, type UnknownAuthorityError struct, Cert *Certificate
+pkg database/sql, const LevelDefault = 0
+pkg database/sql, const LevelDefault IsolationLevel
+pkg database/sql, const LevelLinearizable = 7
+pkg database/sql, const LevelLinearizable IsolationLevel
+pkg database/sql, const LevelReadCommitted = 2
+pkg database/sql, const LevelReadCommitted IsolationLevel
+pkg database/sql, const LevelReadUncommitted = 1
+pkg database/sql, const LevelReadUncommitted IsolationLevel
+pkg database/sql, const LevelRepeatableRead = 4
+pkg database/sql, const LevelRepeatableRead IsolationLevel
+pkg database/sql, const LevelSerializable = 6
+pkg database/sql, const LevelSerializable IsolationLevel
+pkg database/sql, const LevelSnapshot = 5
+pkg database/sql, const LevelSnapshot IsolationLevel
+pkg database/sql, const LevelWriteCommitted = 3
+pkg database/sql, const LevelWriteCommitted IsolationLevel
+pkg database/sql/driver, func IsolationFromContext(context.Context) (IsolationLevel, bool)
+pkg database/sql/driver, func ReadOnlyFromContext(context.Context) bool
+pkg database/sql/driver, type ConnBeginContext interface { BeginContext }
+pkg database/sql/driver, type ConnBeginContext interface, BeginContext(context.Context) (Tx, error)
+pkg database/sql/driver, type ConnPrepareContext interface { PrepareContext }
+pkg database/sql/driver, type ConnPrepareContext interface, PrepareContext(context.Context, string) (Stmt, error)
+pkg database/sql/driver, type ExecerContext interface { ExecContext }
+pkg database/sql/driver, type ExecerContext interface, ExecContext(context.Context, string, []NamedValue) (Result, error)
+pkg database/sql/driver, type IsolationLevel int
+pkg database/sql/driver, type NamedValue struct
+pkg database/sql/driver, type NamedValue struct, Name string
+pkg database/sql/driver, type NamedValue struct, Ordinal int
+pkg database/sql/driver, type NamedValue struct, Value Value
+pkg database/sql/driver, type Pinger interface { Ping }
+pkg database/sql/driver, type Pinger interface, Ping(context.Context) error
+pkg database/sql/driver, type QueryerContext interface { QueryContext }
+pkg database/sql/driver, type QueryerContext interface, QueryContext(context.Context, string, []NamedValue) (Rows, error)
+pkg database/sql/driver, type RowsColumnTypeDatabaseTypeName interface { Close, ColumnTypeDatabaseTypeName, Columns, Next }
+pkg database/sql/driver, type RowsColumnTypeDatabaseTypeName interface, Close() error
+pkg database/sql/driver, type RowsColumnTypeDatabaseTypeName interface, Columns() []string
+pkg database/sql/driver, type RowsColumnTypeDatabaseTypeName interface, ColumnTypeDatabaseTypeName(int) string
+pkg database/sql/driver, type RowsColumnTypeDatabaseTypeName interface, Next([]Value) error
+pkg database/sql/driver, type RowsColumnTypeLength interface { Close, ColumnTypeLength, Columns, Next }
+pkg database/sql/driver, type RowsColumnTypeLength interface, Close() error
+pkg database/sql/driver, type RowsColumnTypeLength interface, Columns() []string
+pkg database/sql/driver, type RowsColumnTypeLength interface, ColumnTypeLength(int) (int64, bool)
+pkg database/sql/driver, type RowsColumnTypeLength interface, Next([]Value) error
+pkg database/sql/driver, type RowsColumnTypeNullable interface { Close, ColumnTypeNullable, Columns, Next }
+pkg database/sql/driver, type RowsColumnTypeNullable interface, Close() error
+pkg database/sql/driver, type RowsColumnTypeNullable interface, Columns() []string
+pkg database/sql/driver, type RowsColumnTypeNullable interface, ColumnTypeNullable(int) (bool, bool)
+pkg database/sql/driver, type RowsColumnTypeNullable interface, Next([]Value) error
+pkg database/sql/driver, type RowsColumnTypePrecisionScale interface { Close, ColumnTypePrecisionScale, Columns, Next }
+pkg database/sql/driver, type RowsColumnTypePrecisionScale interface, Close() error
+pkg database/sql/driver, type RowsColumnTypePrecisionScale interface, Columns() []string
+pkg database/sql/driver, type RowsColumnTypePrecisionScale interface, ColumnTypePrecisionScale(int) (int64, int64, bool)
+pkg database/sql/driver, type RowsColumnTypePrecisionScale interface, Next([]Value) error
+pkg database/sql/driver, type RowsColumnTypeScanType interface { Close, ColumnTypeScanType, Columns, Next }
+pkg database/sql/driver, type RowsColumnTypeScanType interface, Close() error
+pkg database/sql/driver, type RowsColumnTypeScanType interface, Columns() []string
+pkg database/sql/driver, type RowsColumnTypeScanType interface, ColumnTypeScanType(int) reflect.Type
+pkg database/sql/driver, type RowsColumnTypeScanType interface, Next([]Value) error
+pkg database/sql/driver, type RowsNextResultSet interface { Close, Columns, HasNextResultSet, Next, NextResultSet }
+pkg database/sql/driver, type RowsNextResultSet interface, Close() error
+pkg database/sql/driver, type RowsNextResultSet interface, Columns() []string
+pkg database/sql/driver, type RowsNextResultSet interface, HasNextResultSet() bool
+pkg database/sql/driver, type RowsNextResultSet interface, NextResultSet() error
+pkg database/sql/driver, type RowsNextResultSet interface, Next([]Value) error
+pkg database/sql/driver, type StmtExecContext interface { ExecContext }
+pkg database/sql/driver, type StmtExecContext interface, ExecContext(context.Context, []NamedValue) (Result, error)
+pkg database/sql/driver, type StmtQueryContext interface { QueryContext }
+pkg database/sql/driver, type StmtQueryContext interface, QueryContext(context.Context, []NamedValue) (Rows, error)
+pkg database/sql, func IsolationContext(context.Context, IsolationLevel) context.Context
+pkg database/sql, func Named(string, interface{}) NamedArg
+pkg database/sql, func ReadOnlyContext(context.Context) context.Context
+pkg database/sql, method (*ColumnType) DatabaseTypeName() string
+pkg database/sql, method (*ColumnType) DecimalSize() (int64, int64, bool)
+pkg database/sql, method (*ColumnType) Length() (int64, bool)
+pkg database/sql, method (*ColumnType) Name() string
+pkg database/sql, method (*ColumnType) Nullable() (bool, bool)
+pkg database/sql, method (*ColumnType) ScanType() reflect.Type
+pkg database/sql, method (*DB) BeginContext(context.Context) (*Tx, error)
+pkg database/sql, method (*DB) ExecContext(context.Context, string, ...interface{}) (Result, error)
+pkg database/sql, method (*DB) PingContext(context.Context) error
+pkg database/sql, method (*DB) PrepareContext(context.Context, string) (*Stmt, error)
+pkg database/sql, method (*DB) QueryContext(context.Context, string, ...interface{}) (*Rows, error)
+pkg database/sql, method (*DB) QueryRowContext(context.Context, string, ...interface{}) *Row
+pkg database/sql, method (*Rows) ColumnTypes() ([]*ColumnType, error)
+pkg database/sql, method (*Rows) NextResultSet() bool
+pkg database/sql, method (*Stmt) ExecContext(context.Context, ...interface{}) (Result, error)
+pkg database/sql, method (*Stmt) QueryContext(context.Context, ...interface{}) (*Rows, error)
+pkg database/sql, method (*Stmt) QueryRowContext(context.Context, ...interface{}) *Row
+pkg database/sql, method (*Tx) ExecContext(context.Context, string, ...interface{}) (Result, error)
+pkg database/sql, method (*Tx) PrepareContext(context.Context, string) (*Stmt, error)
+pkg database/sql, method (*Tx) QueryContext(context.Context, string, ...interface{}) (*Rows, error)
+pkg database/sql, method (*Tx) QueryRowContext(context.Context, string, ...interface{}) *Row
+pkg database/sql, method (*Tx) StmtContext(context.Context, *Stmt) *Stmt
+pkg database/sql, type ColumnType struct
+pkg database/sql, type IsolationLevel int
+pkg database/sql, type NamedArg struct
+pkg database/sql, type NamedArg struct, Name string
+pkg database/sql, type NamedArg struct, Value interface{}
+pkg debug/gosym, func PCValue([]uint8, uint64, int) int
+pkg debug/pe, method (*COFFSymbol) FullName(StringTable) (string, error)
+pkg debug/pe, method (StringTable) String(uint32) (string, error)
+pkg debug/pe, type File struct, COFFSymbols []COFFSymbol
+pkg debug/pe, type File struct, StringTable StringTable
+pkg debug/pe, type Reloc struct
+pkg debug/pe, type Reloc struct, SymbolTableIndex uint32
+pkg debug/pe, type Reloc struct, Type uint16
+pkg debug/pe, type Reloc struct, VirtualAddress uint32
+pkg debug/pe, type Section struct, Relocs []Reloc
+pkg debug/pe, type StringTable []uint8
+pkg encoding/base64, method (Encoding) Strict() *Encoding
+pkg encoding/json, method (RawMessage) MarshalJSON() ([]uint8, error)
+pkg encoding/json, type UnmarshalTypeError struct, Field string
+pkg encoding/json, type UnmarshalTypeError struct, Struct string
+pkg expvar, func Handler() http.Handler
+pkg expvar, method (*Float) Value() float64
+pkg expvar, method (Func) Value() interface{}
+pkg expvar, method (*Int) Value() int64
+pkg expvar, method (*String) Value() string
+pkg go/build, type NoGoError struct, Ignored bool
+pkg go/doc, func IsPredeclared(string) bool
+pkg go/types, func Default(Type) Type
+pkg go/types, func IdenticalIgnoreTags(Type, Type) bool
+pkg math/big, method (*Float) Scan(fmt.ScanState, int32) error
+pkg math/big, method (*Int) Sqrt(*Int) *Int
+pkg math/rand, func Uint64() uint64
+pkg math/rand, method (*Rand) Uint64() uint64
+pkg math/rand, type Source64 interface, Int63() int64
+pkg math/rand, type Source64 interface { Int63, Seed, Uint64 }
+pkg math/rand, type Source64 interface, Seed(int64)
+pkg math/rand, type Source64 interface, Uint64() uint64
+pkg net/http, const TrailerPrefix ideal-string
+pkg net/http, const TrailerPrefix = "Trailer:"
+pkg net/http/httptrace, type ClientTrace struct, TLSHandshakeDone func(tls.ConnectionState, error)
+pkg net/http/httptrace, type ClientTrace struct, TLSHandshakeStart func()
+pkg net/http/httputil, type ReverseProxy struct, ModifyResponse func(*http.Response) error
+pkg net/http, method (*Server) Close() error
+pkg net/http, method (*Server) Shutdown(context.Context) error
+pkg net/http, type Pusher interface { Push }
+pkg net/http, type Pusher interface, Push(string, *PushOptions) error
+pkg net/http, type PushOptions struct
+pkg net/http, type PushOptions struct, Header Header
+pkg net/http, type PushOptions struct, Method string
+pkg net/http, type Request struct, GetBody func() (io.ReadCloser, error)
+pkg net/http, type Server struct, IdleTimeout time.Duration
+pkg net/http, type Server struct, ReadHeaderTimeout time.Duration
+pkg net/http, type Transport struct, ProxyConnectHeader Header
+pkg net/http, var ErrAbortHandler error
+pkg net/http, var ErrServerClosed error
+pkg net/http, var NoBody noBody
+pkg net/mail, func ParseDate(string) (time.Time, error)
+pkg net, method (*Buffers) Read([]uint8) (int, error)
+pkg net, method (*Buffers) WriteTo(io.Writer) (int64, error)
+pkg net, method (*Resolver) LookupAddr(context.Context, string) ([]string, error)
+pkg net, method (*Resolver) LookupCNAME(context.Context, string) (string, error)
+pkg net, method (*Resolver) LookupHost(context.Context, string) ([]string, error)
+pkg net, method (*Resolver) LookupIPAddr(context.Context, string) ([]IPAddr, error)
+pkg net, method (*Resolver) LookupMX(context.Context, string) ([]*MX, error)
+pkg net, method (*Resolver) LookupNS(context.Context, string) ([]*NS, error)
+pkg net, method (*Resolver) LookupPort(context.Context, string, string) (int, error)
+pkg net, method (*Resolver) LookupSRV(context.Context, string, string, string) (string, []*SRV, error)
+pkg net, method (*Resolver) LookupTXT(context.Context, string) ([]string, error)
+pkg net, method (*UnixListener) SetUnlinkOnClose(bool)
+pkg net, type Buffers [][]uint8
+pkg net, type Dialer struct, Resolver *Resolver
+pkg net, type Resolver struct
+pkg net, type Resolver struct, PreferGo bool
+pkg net/url, func PathEscape(string) string
+pkg net/url, func PathUnescape(string) (string, error)
+pkg net/url, method (*URL) Hostname() string
+pkg net/url, method (*URL) MarshalBinary() ([]uint8, error)
+pkg net/url, method (*URL) Port() string
+pkg net/url, method (*URL) UnmarshalBinary([]uint8) error
+pkg net, var DefaultResolver *Resolver
+pkg os, func Executable() (string, error)
+pkg os, var ErrClosed error
+pkg plugin, func Open(string) (*Plugin, error)
+pkg plugin, method (*Plugin) Lookup(string) (Symbol, error)
+pkg plugin, type Plugin struct
+pkg plugin, type Symbol interface {}
+pkg reflect, func Swapper(interface{}) func(int, int)
+pkg runtime, func MutexProfile([]BlockProfileRecord) (int, bool)
+pkg runtime, func SetMutexProfileFraction(int) int
+pkg sort, func Slice(interface{}, func(int, int) bool)
+pkg sort, func SliceIsSorted(interface{}, func(int, int) bool) bool
+pkg sort, func SliceStable(interface{}, func(int, int) bool)
+pkg syscall (linux-arm-cgo), func TimevalToNsec(Timeval) int64
+pkg syscall (linux-arm), func TimevalToNsec(Timeval) int64
+pkg syscall (windows-386), const ERROR_DIR_NOT_EMPTY = 145
+pkg syscall (windows-386), const ERROR_DIR_NOT_EMPTY Errno
+pkg syscall (windows-amd64), const ERROR_DIR_NOT_EMPTY = 145
+pkg syscall (windows-amd64), const ERROR_DIR_NOT_EMPTY Errno
+pkg testing, func CoverMode() string
+pkg testing, func MainStart(testDeps, []InternalTest, []InternalBenchmark, []InternalExample) *M
+pkg testing, method (*B) Context() context.Context
+pkg testing, method (*B) Name() string
+pkg testing, method (*T) Context() context.Context
+pkg testing, method (*T) Name() string
+pkg testing, type TB interface, Context() context.Context
+pkg testing, type TB interface, Name() string
+pkg time, func Until(Time) Duration
diff --git a/doc/articles/go_command.html b/doc/articles/go_command.html
index cc1d86a..0fd83cb 100644
--- a/doc/articles/go_command.html
+++ b/doc/articles/go_command.html
@@ -97,13 +97,14 @@ a tool like the go command to look at an unfamiliar import path and
deduce where to obtain the source code.</p>
<p>Second, the place to store sources in the local file system is derived
-in a known way from the import path. Specifically, the first choice
-is <code>$GOPATH/src/<import-path></code>. If <code>$GOPATH</code> is
-unset, the go command will fall back to storing source code alongside the
-standard Go packages, in <code>$GOROOT/src/<import-path></code>.
+in a known way from the import path, specifically
+<code>$GOPATH/src/<import-path></code>.
+If unset, <code>$GOPATH</code> defaults to a subdirectory
+named <code>go</code> in the user's home directory.
If <code>$GOPATH</code> is set to a list of paths, the go command tries
<code><dir>/src/<import-path></code> for each of the directories in
-that list.</p>
+that list.
+</p>
<p>Each of those trees contains, by convention, a top-level directory named
"<code>bin</code>", for holding compiled executables, and a top-level directory
@@ -137,41 +138,26 @@ to the use of a specific tool chain.</p>
<h2>Getting started with the go command</h2>
-<p>Finally, a quick tour of how to use the go command, to supplement
-the information in <a href="/doc/code.html">How to Write Go Code</a>,
-which you might want to read first. Assuming you want
-to keep your source code separate from the Go distribution source
-tree, the first step is to set <code>$GOPATH</code>, the one piece of global
-configuration that the go command needs. The <code>$GOPATH</code> can be a
-list of directories, but by far the most common usage should be to set it to a
-single directory. In particular, you do not need a separate entry in
-<code>$GOPATH</code> for each of your projects. One <code>$GOPATH</code> can
-support many projects.</p>
-
-<p>Here’s an example. Let’s say we decide to keep our Go code in the directory
-<code>$HOME/mygo</code>. We need to create that directory and set
-<code>$GOPATH</code> accordingly.</p>
+<p>Finally, a quick tour of how to use the go command.
+As mentioned above, the default <code>$GOPATH</code> on Unix is <code>$HOME/go</code>.
+We'll store our programs there.
+To use a different location, you can set <code>$GOPATH</code>;
+see <a href="/doc/code.html">How to Write Go Code</a> for details.
-<pre>
-$ mkdir $HOME/mygo
-$ export GOPATH=$HOME/mygo
-$
-</pre>
-
-<p>Into this directory, we now add some source code. Suppose we want to use
+<p>We first add some source code. Suppose we want to use
the indexing library from the codesearch project along with a left-leaning
red-black tree. We can install both with the "<code>go get</code>"
subcommand:</p>
<pre>
-$ go get code.google.com/p/codesearch/index
+$ go get github.com/google/codesearch/index
$ go get github.com/petar/GoLLRB/llrb
$
</pre>
-<p>Both of these projects are now downloaded and installed into our
-<code>$GOPATH</code> directory. The one tree now contains the two directories
-<code>src/code.google.com/p/codesearch/index/</code> and
+<p>Both of these projects are now downloaded and installed into <code>$HOME/go</code>,
+which contains the two directories
+<code>src/github.com/google/codesearch/index/</code> and
<code>src/github.com/petar/GoLLRB/llrb/</code>, along with the compiled
packages (in <code>pkg/</code>) for those libraries and their dependencies.</p>
@@ -184,13 +170,14 @@ the pattern "<code>./...</code>" means start in the current directory
("<code>...</code>"):</p>
<pre>
+$ cd $HOME/go/src
$ go list ./...
-code.google.com/p/codesearch/cmd/cgrep
-code.google.com/p/codesearch/cmd/cindex
-code.google.com/p/codesearch/cmd/csearch
-code.google.com/p/codesearch/index
-code.google.com/p/codesearch/regexp
-code.google.com/p/codesearch/sparse
+github.com/google/codesearch/cmd/cgrep
+github.com/google/codesearch/cmd/cindex
+github.com/google/codesearch/cmd/csearch
+github.com/google/codesearch/index
+github.com/google/codesearch/regexp
+github.com/google/codesearch/sparse
github.com/petar/GoLLRB/example
github.com/petar/GoLLRB/llrb
$
@@ -200,12 +187,12 @@ $
<pre>
$ go test ./...
-? code.google.com/p/codesearch/cmd/cgrep [no test files]
-? code.google.com/p/codesearch/cmd/cindex [no test files]
-? code.google.com/p/codesearch/cmd/csearch [no test files]
-ok code.google.com/p/codesearch/index 0.239s
-ok code.google.com/p/codesearch/regexp 0.021s
-? code.google.com/p/codesearch/sparse [no test files]
+? github.com/google/codesearch/cmd/cgrep [no test files]
+? github.com/google/codesearch/cmd/cindex [no test files]
+? github.com/google/codesearch/cmd/csearch [no test files]
+ok github.com/google/codesearch/index 0.203s
+ok github.com/google/codesearch/regexp 0.017s
+? github.com/google/codesearch/sparse [no test files]
? github.com/petar/GoLLRB/example [no test files]
ok github.com/petar/GoLLRB/llrb 0.231s
$
@@ -215,18 +202,18 @@ $
current directory:</p>
<pre>
-$ cd $GOPATH/src/code.google.com/p/codesearch/regexp
+$ cd github.com/google/codesearch/regexp
$ go list
-code.google.com/p/codesearch/regexp
+github.com/google/codesearch/regexp
$ go test -v
-=== RUN TestNstateEnc
---- PASS: TestNstateEnc (0.00 seconds)
-=== RUN TestMatch
---- PASS: TestMatch (0.01 seconds)
-=== RUN TestGrep
---- PASS: TestGrep (0.00 seconds)
+=== RUN TestNstateEnc
+--- PASS: TestNstateEnc (0.00s)
+=== RUN TestMatch
+--- PASS: TestMatch (0.00s)
+=== RUN TestGrep
+--- PASS: TestGrep (0.00s)
PASS
-ok code.google.com/p/codesearch/regexp 0.021s
+ok github.com/google/codesearch/regexp 0.018s
$ go install
$
</pre>
@@ -244,9 +231,6 @@ pick such a long name, but that ability would require additional configuration
and complexity in the tool. Typing an extra directory name or two is a small
price to pay for the increased simplicity and power.</p>
-<p>As the example shows, it’s fine to work with packages from many different
-projects at once within a single <code>$GOPATH</code> root directory.</p>
-
<h2>Limitations</h2>
<p>As mentioned above, the go command is not a general-purpose build
@@ -255,8 +239,7 @@ In particular, it does not have any facility for generating Go
source files <em>during</em> a build, although it does provide
<a href="/cmd/go/#hdr-Generate_Go_files_by_processing_source"><code>go</code>
<code>generate</code></a>,
-which can automate the creation of Go files <em>before</em>
-the build, such as by running <code>yacc</code>.
+which can automate the creation of Go files <em>before</em> the build.
For more advanced build setups, you may need to write a
makefile (or a configuration file for the build tool of your choice)
to run whatever tool creates the Go files and then check those generated source files
diff --git a/doc/code.html b/doc/code.html
index fdca404..9978b52 100644
--- a/doc/code.html
+++ b/doc/code.html
@@ -120,36 +120,49 @@ We will discuss the distinction <a href="#PackageNames">later</a>.
<p>
The <code>GOPATH</code> environment variable specifies the location of your
-workspace. It is likely the only environment variable you'll need to set
-when developing Go code.
+workspace. It defaults to a directory named <code>go</code> inside your home directory,
+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.
+(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.
</p>
<p>
-To get started, create a workspace directory and set <code>GOPATH</code>
-accordingly. Your workspace can be located wherever you like, but we'll use
-<code>$HOME/work</code> in this document. Note that this must <b>not</b> be the
-same path as your Go installation.
-(Another common setup is to set <code>GOPATH=$HOME</code>.)
+The command <code>go</code> <code>env</code> <code>GOPATH</code>
+prints the effective current <code>GOPATH</code>;
+it prints the default location if the environment variable is unset.
+</p>
+
+<p>
+For convenience, add the workspace's <code>bin</code> subdirectory
+to your <code>PATH</code>:
</p>
<pre>
-$ <b>mkdir $HOME/work</b>
-$ <b>export GOPATH=$HOME/work</b>
+$ <b>export PATH=$PATH:$(go env GOPATH)/bin</b>
</pre>
<p>
-For convenience, add the workspace's <code>bin</code> subdirectory
-to your <code>PATH</code>:
+The scripts in the rest of this document use <code>$GOPATH</code>
+instead of <code>$(go env GOPATH)</code> for brevity.
+To make the scripts run as written
+if you have not set GOPATH,
+you can substitute $HOME/go in those commands
+or else run:
</p>
<pre>
-$ <b>export PATH=$PATH:$GOPATH/bin</b>
+$ <b>export GOPATH=$(go env GOPATH)</b>
</pre>
<p>
To learn more about setting up the <code>GOPATH</code> environment variable,
please see
-<a href="/cmd/go/#hdr-GOPATH_environment_variable"><code>go help gopath</code></a>
+<a href="/cmd/go/#hdr-GOPATH_environment_variable"><code>'go help gopath'</code></a>
</p>
<h3 id="ImportPaths">Import paths</h3>
diff --git a/doc/conduct.html b/doc/conduct.html
index ce824a1..c749266 100644
--- a/doc/conduct.html
+++ b/doc/conduct.html
@@ -20,8 +20,8 @@ ul ul {
<p>
Online communities include people from many different backgrounds.
The Go contributors are committed to providing a friendly, safe and welcoming
-environment for all, regardless of age, disability, gender, nationality, race,
-religion, sexuality, or similar personal characteristic.
+environment for all, regardless of age, disability, gender, nationality,
+ethnicity, religion, sexuality, or similar personal characteristic.
</p>
<p>
diff --git a/doc/devel/release.html b/doc/devel/release.html
index 51957df..773f889 100644
--- a/doc/devel/release.html
+++ b/doc/devel/release.html
@@ -50,23 +50,11 @@ See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.7.1">Go
</p>
<p>
-go1.7.2 should not be used. It was tagged but not fully released.
-The release was deferred due to a last minute bug report.
-Use go1.7.3 instead, and refer to the summary of changes below.
-</p>
-
-<p>
-go1.7.3 (released 2016/10/19) includes fixes to the compiler, runtime,
+go1.7.2 (released 2016/10/17) includes fixes to the compiler, runtime,
and the <code>crypto/cipher</code>, <code>crypto/tls</code>,
<code>net/http</code>, and <code>strings</code> packages.
-See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.7.3">Go
-1.7.3 milestone</a> on our issue tracker for details.
-</p>
-
-<p>
-go1.7.4 (released 2016/12/01) includes two security fixes.
-See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.7.4">Go
-1.7.4 milestone</a> on our issue tracker for details.
+See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.7.2">Go
+1.7.2 milestone</a> on our issue tracker for details.
</p>
<h2 id="go1.6">go1.6 (released 2016/02/17)</h2>
@@ -100,13 +88,6 @@ See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.6.3">Go
1.6.3 milestone</a> on our issue tracker for details.
</p>
-<p>
-go1.6.4 (released 2016/12/01) includes two security fixes.
-It contains the same fixes as Go 1.7.4 and was released at the same time.
-See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.7.4">Go
-1.7.4 milestone</a> on our issue tracker for details.
-</p>
-
<h2 id="go1.5">go1.5 (released 2015/08/19)</h2>
<p>
diff --git a/doc/devel/weekly.html b/doc/devel/weekly.html
index 143727f..7166a76 100644
--- a/doc/devel/weekly.html
+++ b/doc/devel/weekly.html
@@ -2450,7 +2450,7 @@ The http package's URL parsing and query escaping code (such as ParseURL and
URLEscape) has been moved to the new url package, with several simplifications
to the names. Client code can be updated automatically with gofix.
-* asn1: support unmarshalling structs with int32 members (thanks Dave Cheney).
+* asn1: support unmarshaling structs with int32 members (thanks Dave Cheney).
* build: allow builds without cgo or hg,
support versioning without hg (thanks Gustavo Niemeyer).
* builtin: add documentation for builtins.
@@ -3030,7 +3030,7 @@ Other changes:
* 5g: alignment fixes.
* 6l, 8l: fix Mach-O binaries with many dynamic libraries.
* 8l: emit resources (.rsrc) in Windows PE. (thanks Wei Guangjing).
-* asn1: fix marshalling of empty optional RawValues (thanks Mikkel Krautz).
+* asn1: fix marshaling of empty optional RawValues (thanks Mikkel Krautz).
* big: make Int and Rat implement fmt.Scanner (thanks Evan Shaw),
~8x faster number scanning,
remove some unnecessary conversions.
@@ -4238,7 +4238,7 @@ example: http://golang.org/pkg/xml/
<pre>
The json, gob, and template packages have changed, and code that uses them
may need to be updated after this release. They will no longer read or write
-unexported struct fields. When marshalling a struct with json or gob the
+unexported struct fields. When marshaling a struct with json or gob the
unexported fields will be silently ignored. Attempting to unmarshal json or
gob data into an unexported field will generate an error. Accessing an
unexported field from a template will cause the Execute function to return
@@ -5682,7 +5682,7 @@ Other changes:
pidigits ~10% performance win by using adds instead of shifts.
* time: remove incorrect time.ISO8601 and add time.RFC3339 (thanks Micah Stetson).
* utf16: add DecodeRune, EncodeRune.
-* xml: add support for XML marshalling embedded structs (thanks Raif S. Naffah),
+* xml: add support for XML marshaling embedded structs (thanks Raif S. Naffah),
new "innerxml" tag to collect inner XML.
</pre>
@@ -5925,10 +5925,10 @@ Other changes and fixes:
* 8a/8l: Added CMOVcc instructions (thanks Evan Shaw)
* 8l: pe executable building code changed to include import table for kernel32.dll functions (thanks Alex Brainman)
* 5g/6g/8g: bug fixes
-* asn1: bug fixes and additions (incl marshalling)
+* asn1: bug fixes and additions (incl marshaling)
* build: fix build for Native Client, Linux/ARM
* dashboard: show benchmarks, add garbage collector benchmarks
-* encoding/pem: add marshalling support
+* encoding/pem: add marshaling support
* exp/draw: fast paths for a nil mask
* godoc: support for directories outside $GOROOT
* http: sort header keys when writing Response or Request to wire (thanks Petar Maymounkov)
diff --git a/doc/docs.html b/doc/docs.html
index 7eb3a3a..1ccd1f3 100644
--- a/doc/docs.html
+++ b/doc/docs.html
@@ -40,7 +40,13 @@ The first section covers basic syntax and data structures; the second discusses
methods and interfaces; and the third introduces Go's concurrency primitives.
Each section concludes with a few exercises so you can practice what you've
learned. You can <a href="//tour.golang.org/">take the tour online</a> or
-<a href="//code.google.com/p/go-tour/">install it locally</a>.
+install it locally with:
+</p>
+<p>
+<pre>
+$ go get golang.org/x/tour/gotour
+</pre>
+This will place the <code>gotour</code> binary in your workspace's <code>bin</code> directory.
</p>
<h3 id="code"><a href="code.html">How to write Go code</a></h3>
diff --git a/doc/effective_go.html b/doc/effective_go.html
index f6fe48c..e3f3124 100644
--- a/doc/effective_go.html
+++ b/doc/effective_go.html
@@ -245,15 +245,15 @@ func Compile(str string) (*Regexp, error) {
</pre>
<p>
-If the name always begins the comment, the output of <code>godoc</code>
-can usefully be run through <code>grep</code>.
+If every doc comment begins with the name of the item it describes,
+the output of <code>godoc</code> can usefully be run through <code>grep</code>.
Imagine you couldn't remember the name "Compile" but were looking for
the parsing function for regular expressions, so you ran
the command,
</p>
<pre>
-$ godoc regexp | grep parse
+$ godoc regexp | grep -i parse
</pre>
<p>
@@ -2409,7 +2409,7 @@ The <code>http</code> package contains this code:
// Handler object that calls f.
type HandlerFunc func(ResponseWriter, *Request)
-// ServeHTTP calls f(c, req).
+// ServeHTTP calls f(w, req).
func (f HandlerFunc) ServeHTTP(w ResponseWriter, req *Request) {
f(w, req)
}
@@ -2447,7 +2447,7 @@ the handler installed at that page has value <code>ArgServer</code>
and type <code>HandlerFunc</code>.
The HTTP server will invoke the method <code>ServeHTTP</code>
of that type, with <code>ArgServer</code> as the receiver, which will in turn call
-<code>ArgServer</code> (via the invocation <code>f(c, req)</code>
+<code>ArgServer</code> (via the invocation <code>f(w, req)</code>
inside <code>HandlerFunc.ServeHTTP</code>).
The arguments will then be displayed.
</p>
diff --git a/doc/gccgo_contribute.html b/doc/gccgo_contribute.html
index dd1327a..1286fcc 100644
--- a/doc/gccgo_contribute.html
+++ b/doc/gccgo_contribute.html
@@ -12,7 +12,7 @@ information on building gccgo for yourself,
see <a href="/doc/gccgo_install.html">Setting up and using gccgo</a>.
For more of the gritty details on the process of doing development
with the gccgo frontend,
-see <a href="https://code.google.com/p/gofrontend/source/browse/HACKING">the
+see <a href="https://go.googlesource.com/gofrontend/+/master/HACKING">the
file HACKING</a> in the gofrontend repository.
</p>
diff --git a/doc/go1.7.html b/doc/go1.7.html
index 6839c5e..2b0f01d 100644
--- a/doc/go1.7.html
+++ b/doc/go1.7.html
@@ -43,7 +43,7 @@ includes the <a href="#context">context package</a>, promoted from the
and now used in the standard library;
and <a href="#testing">adds support in the testing package</a> for
creating hierarchies of tests and benchmarks.
-The release also <a href="#cmd/go">finalizes the vendoring support</a>
+The release also <a href="#cmd_go">finalizes the vendoring support</a>
started in Go 1.5, making it a standard feature.
</p>
@@ -357,7 +357,7 @@ the code generation changes alone typically reduce program CPU time by 5-35%.
</p>
<p>
-<!-- git log --grep '-[0-9][0-9]\.[0-9][0-9]%' go1.6.. -->
+<!-- git log -''-grep '-[0-9][0-9]\.[0-9][0-9]%' go1.6.. -->
There have been significant optimizations bringing more than 10% improvements
to implementations in the
<a href="/pkg/crypto/sha1/"><code>crypto/sha1</code></a>,
@@ -394,9 +394,9 @@ This allows the use of contexts for cancelation, timeouts, and passing
request-scoped data in other standard library packages,
including
<a href="#net">net</a>,
-<a href="#net/http">net/http</a>,
+<a href="#net_http">net/http</a>,
and
-<a href="#os/exec">os/exec</a>,
+<a href="#os_exec">os/exec</a>,
as noted below.
</p>
@@ -552,10 +552,9 @@ The
<dd>
<p>
-As noted above,
-there are significant performance optimizations throughout the package.
+There are many performance optimizations throughout the package.
Decompression speed is improved by about 10%,
-while compression speed for <code>DefaultCompression</code> is roughly doubled.
+while compression for <code>DefaultCompression</code> is twice as fast.
</p>
<p>
diff --git a/doc/go1.8.html b/doc/go1.8.html
new file mode 100644
index 0000000..22176a2
--- /dev/null
+++ b/doc/go1.8.html
@@ -0,0 +1,1615 @@
+<!--{
+ "Title": "Go 1.8 Release Notes",
+ "Path": "/doc/go1.8",
+ "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.8</h2>
+
+<p><strong>
+Go 1.8 is not yet released. These are work-in-progress
+release notes. Go 1.8 is expected to be released in February 2017.
+</strong></p>
+
+<p>
+The latest Go release, version 1.8, arrives six months after <a href="go1.7">Go 1.7</a>.
+Most of its changes are in the implementation of the toolchain, runtime, and libraries.
+There is one minor change to the language specification.
+As always, the release maintains the Go 1 <a href="/doc/go1compat.html">promise of compatibility</a>.
+We expect almost all Go programs to continue to compile and run as before.
+</p>
+
+<p>
+The release <a href="#ports">adds support for 32-bit MIPS</a>,
+<a href="#compiler">updates the compiler back end</a> to generate more efficient code,
+<a href="#gc">reduces GC pauses</a> by eliminating stop-the-world stack rescanning,
+<a href="#h2push">adds HTTP/2 Push support</a>,
+<a href="#http_shutdown">adds HTTP graceful shutdown</a>,
+<a href="#more_context">adds more context support</a>,
+<a href="#mutex_prof">enables profiling mutexes</a>,
+and <a href="#sort_slice">simplifies sorting slices</a>.
+</p>
+
+<h2 id="language">Changes to the language</h2>
+
+<p>
+ When explicitly converting a value from one struct type to another, as of Go 1. 8 the tags are ignored.
+ Thus two structs that differ only in their tags may be converted from one to the other:
+</p>
+
+<pre>
+func example() {
+ type T1 struct {
+ X int `json:"foo"`
+ }
+ type T2 struct {
+ X int `json:"bar"`
+ }
+ var v1 T1
+ var v2 T2
+ v1 = T1(v2) // now legal
+}
+</pre>
+
+
+<p> <!-- CL 17711 -->
+ The language specification now only requires that implementations
+ support up to 16-bit exponents in floating-point constants. This does not affect
+ either the “<a href="/cmd/compile/"><code>gc</code></a>” or
+ <code>gccgo</code> compilers, both of
+ which still support 32-bit exponents.
+</p>
+
+<h2 id="ports">Ports</h2>
+
+<p>
+Go now supports 32-bit MIPS on Linux for both big-endian
+(<code>linux/mips</code>) and little-endian machines
+(<code>linux/mipsle</code>).
+</p>
+
+<p>
+On DragonFly BSD, Go now requires DragonFly 4.4.4 or later. <!-- CL 29491, CL 29971 -->
+</p>
+
+<p>
+The Plan 9 port's networking support is now much more complete
+and matches the behavior of Unix and Windows with respect to deadlines
+and cancelation.
+</p>
+
+<p>
+ Go 1.8 now only supports OS X 10.8 or later. This is likely the last
+ Go release to support 10.8. Compiling Go or running
+ binaries on older OS X versions is untested.
+</p>
+
+
+<h3 id="known_issues">Known Issues</h3>
+
+<p>
+There are some instabilities on FreeBSD and NetBSD 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>,
+<a href="https://golang.org/issue/16396">issue 16396</a>, and
+<a href="https://golang.org/issue/16511">issue 16511</a>.
+Any help in solving these issues would be appreciated.
+</p>
+
+<h2 id="tools">Tools</h2>
+
+<h3 id="cmd_asm">Assembler</h3>
+
+<p>
+For 64-bit x86 systems, the following instructions have been added:
+<code>VBROADCASTSD</code>,
+<code>BROADCASTSS</code>,
+<code>MOVDDUP</code>,
+<code>MOVSHDUP</code>,
+<code>MOVSLDUP</code>,
+<code>VMOVDDUP</code>,
+<code>VMOVSHDUP</code>,
+and <code>VMOVSLDUP</code>.</p>
+
+<p>
+For 64-bit PPC systems, the common vector scalar instructions have been
+added:
+<code>LXS</code>,
+<code>LXSDX</code>,
+<code>LXSI</code>,
+<code>LXSIWAX</code>,
+<code>LXSIWZX</code>,
+<code>LXV</code>,
+<code>LXVD2X</code>,
+<code>LXVDSX</code>,
+<code>LXVW4X</code>,
+<code>MFVSR</code>,
+<code>MFVSRD</code>,
+<code>MFVSRWZ</code>,
+<code>MTVSR</code>,
+<code>MTVSRD</code>,
+<code>MTVSRWA</code>,
+<code>MTVSRWZ</code>,
+<code>STXS</code>,
+<code>STXSDX</code>,
+<code>STXSI</code>,
+<code>STXSIWX</code>,
+<code>STXV</code>,
+<code>STXVD2X</code>,
+<code>STXVW4X</code>,
+<code>XSCV</code>,
+<code>XSCVDPSP</code>,
+<code>XSCVDPSPN</code>,
+<code>XSCVDPSXDS</code>,
+<code>XSCVDPSXWS</code>,
+<code>XSCVDPUXDS</code>,
+<code>XSCVDPUXWS</code>,
+<code>XSCVSPDP</code>,
+<code>XSCVSPDPN</code>,
+<code>XSCVSXDDP</code>,
+<code>XSCVSXDSP</code>,
+<code>XSCVUXDDP</code>,
+<code>XSCVUXDSP</code>,
+<code>XSCVX</code>,
+<code>XSCVXP</code>,
+<code>XVCV</code>,
+<code>XVCVDPSP</code>,
+<code>XVCVDPSXDS</code>,
+<code>XVCVDPSXWS</code>,
+<code>XVCVDPUXDS</code>,
+<code>XVCVDPUXWS</code>,
+<code>XVCVSPDP</code>,
+<code>XVCVSPSXDS</code>,
+<code>XVCVSPSXWS</code>,
+<code>XVCVSPUXDS</code>,
+<code>XVCVSPUXWS</code>,
+<code>XVCVSXDDP</code>,
+<code>XVCVSXDSP</code>,
+<code>XVCVSXWDP</code>,
+<code>XVCVSXWSP</code>,
+<code>XVCVUXDDP</code>,
+<code>XVCVUXDSP</code>,
+<code>XVCVUXWDP</code>,
+<code>XVCVUXWSP</code>,
+<code>XVCVX</code>,
+<code>XVCVXP</code>,
+<code>XXLAND</code>,
+<code>XXLANDC</code>,
+<code>XXLANDQ</code>,
+<code>XXLEQV</code>,
+<code>XXLNAND</code>,
+<code>XXLNOR</code>,
+<code>XXLOR</code>,
+<code>XXLORC</code>,
+<code>XXLORQ</code>,
+<code>XXLXOR</code>,
+<code>XXMRG</code>,
+<code>XXMRGHW</code>,
+<code>XXMRGLW</code>,
+<code>XXPERM</code>,
+<code>XXPERMDI</code>,
+<code>XXSEL</code>,
+<code>XXSI</code>,
+<code>XXSLDWI</code>,
+<code>XXSPLT</code>, and
+<code>XXSPLTW</code>.
+</p>
+
+<h3 id="tool_yacc">Yacc</h3>
+
+<p> <!-- CL 27324, CL 27325 -->
+The <code>yacc</code> tool (previously available by running
+“<code>go</code> <code>tool</code> <code>yacc</code>”)
+has been removed. As of Go 1.7 it was no longer used by the Go compiler.
+It has moved to the “tools” repository and is now available at
+<code><a href="https://godoc.org/golang.org/x/tools/cmd/goyacc">golang.org/x/tools/cmd/goyacc</a></code>.
+</p>
+
+<h3 id="tool_fix">Fix</h3>
+
+<p> <!-- CL 28872 -->
+ The <code>fix</code> tool has a new “<code>context</code>”
+ fix to change imports from “<code>golang.org/x/net/context</code>”
+ to “<a href="/pkg/context/"><code>context</code></a>”.
+</p>
+
+<h3 id="tool_pprof">Pprof</h3>
+
+<p> <!-- CL 33157 -->
+ The <code>pprof</code> tool can now profile TLS servers
+ and skip certificate validation by using the "<code>https+insecure</code>"
+ URL scheme.
+</p>
+
+<p> <!-- CL 23781 -->
+ The callgrind output now has instruction-level granularity.
+</p>
+
+<p>
+ TODO: more. proto? standalone profiles with symbols?
+<pre>
+runtime/pprof: output CPU profiles in pprof protobuf format (CL 33071)
+runtime/pprof: write profiles in protobuf format. (CL 32257)
+</pre>
+</p>
+
+<h3 id="tool_trace">Trace</h3>
+
+<p>TODO:</p>
+<pre>
+cmd/trace: add option to output pprof files (CL 23324)
+cmd/trace: fix a runnable goroutine count bug (CL 25552)
+cmd/trace: move process-wide GC events to their own row (CL 30017)
+internal/trace: fix analysis of EvGoWaiting/EvGoInSyscall events (CL 25572)
+cmd/trace: annotate different mark worker types (CL 30702)
+</pre>
+
+<h3 id="tool_vet">Vet</h3>
+
+<p>Vet is stricter in some ways and looser where it
+ previously caused false positives.</p>
+
+<p>Vet now checks copying of array of locks,
+ duplicate JSON and XML struct field tags,
+ non-space-separated struct tags,
+ deferred calls to HTTP <code>Response.Body.Close</code>
+ before checking errors,
+ indexed arguments in <code>Printf</code>,
+ and improves existing checks.</p>
+</p>
+
+<h3 id="compiler">Compiler Toolchain</h3>
+
+<p>
+Go 1.7 introduced a new compiler back end for 64-bit x86 systems.
+In Go 1.8, that back end has been developed further and is now used for
+all architectures.
+</p>
+
+<p>
+The new back end, based on
+<a href="https://en.wikipedia.org/wiki/Static_single_assignment_form">static single assignment form</a> (SSA),
+generates more compact, more efficient code
+and provides a better platform for optimizations
+such as bounds check elimination.
+The new back end reduces the CPU time required by
+<a href="https://golang.org/test/bench/go1/">our benchmark programs</a> by 20-30%
+on 32-bit ARM systems. For 64-bit x86 systems, which already used the SSA backend in
+Go 1.7, the gains are a more modest 0-10%. Other architectures will likely
+see improvements closer to the 32-bit ARM numbers.
+</p>
+
+<p>
+ The temporary <code>-ssa=0</code> compiler flag introduced in Go 1.7
+ to disable the new backend has been removed in Go 1.8.
+</p>
+
+<p>
+ In addition to enabling the new compiler back end for all systems,
+ Go 1.8 also introduces a new compiler front end. The new compiler
+ front end should not be noticeable to users but is the foundation for
+ future performance work.
+</p>
+
+<p>
+ The compiler and linker have been optimized and run faster in this
+ release than in Go 1.7, although they are still slower than we would
+ like and will continue to be optimized in future releases.
+ Compared to the previous release, Go 1.8 is
+ <a href="https://dave.cheney.net/2016/11/19/go-1-8-toolchain-improvements">about 15% faster</a>.
+</p>
+
+<h3 id="cmd_cgo">Cgo</h3>
+
+<p> <!-- CL 29991 -->
+The environment variable <code>PKG_CONFIG</code> may now be used to
+set the program to run to handle <code>#cgo pkg-config</code>
+directives. The default is <code>pkg-config</code>, the program
+always used by earlier releases. This is intended to make it easier
+to cross-compile
+<a href="/cmd/cgo/">cgo</a> code.
+</p>
+
+<p> <!-- CL 32354 -->
+The <a href="/cmd/cgo/">cgo</a> tool now supports a <code>-srcdir</code>
+option, which is used by the <a href="/cmd/go/">go</a> command.
+</p>
+
+<p> <!-- CL 31768, 31811 -->
+If <a href="/cmd/cgo/">cgo</a> code calls <code>C.malloc</code>, and
+<code>malloc</code> returns <code>NULL</code>, the program will now
+crash with an out of memory error.
+<code>C.malloc</code> will never return <code>nil</code>.
+Unlike most C functions, <code>C.malloc</code> may not be used in a
+two-result form returning an errno value.
+</p>
+
+<p> <!-- CL 33237 -->
+If <a href="/cmd/cgo/">cgo</a> is used to call a C function passing a
+pointer to a C union, and if the C union can contain any pointer
+values, and if <a href="/cmd/cgo/#hdr-Passing_pointers">cgo pointer
+checking</a> is enabled (as it is by default), the union value is now
+checked for Go pointers.
+</p>
+
+<h3 id="gccgo">Gccgo</h3>
+
+<p>
+Due to the alignment of Go's semiannual release schedule with GCC's
+annual release schedule,
+GCC release 6 contains the Go 1.6.1 version of gccgo.
+We expect that the next release, GCC 7, will contain the Go 1.8
+version of gccgo.
+</p>
+
+<h3 id="gopath">Default GOPATH</h3>
+
+<p>
+ The
+ <a href="/cmd/go/#hdr-GOPATH_environment_variable"><code>GOPATH</code>
+ environment variable</a> now has a default value if it
+ is unset. It defaults to
+ <code>$HOME/go</code> on Unix and
+ <code>%USERPROFILE%/go</code> on Windows.
+</p>
+
+<h3 id="go_bug">Go bug</h3>
+
+<p>
+ The new
+ “<a href="/cmd/go/#hdr-Print_information_for_bug_reports"><code>go</code>
+ <code>bug</code></a>” command starts a bug report on GitHub, prefilled
+ with information about the current system.
+</p>
+
+<h3 id="cmd_doc">Go doc</h3>
+
+<p> <!-- CL 25419 -->
+ The
+ “<a href="/cmd/go/#hdr-Show_documentation_for_package_or_symbol"><code>go</code>
+ <code>doc</code></a>” command
+ now groups constants and variables with their type,
+ following the behavior of
+ <a href="/cmd/godoc/"><code>godoc</code></a>.
+</p>
+
+<p> <!-- CL 25420 -->
+ In order to improve the readability of <code>doc</code>'s
+ output, each summary of the first-level items is guaranteed to
+ occupy a single line.
+</p>
+
+<p> <!-- CL 31852 -->
+ Documentation for a specific method in an interface definition can
+ now be requested, as in
+ “<code>go</code> <code>doc</code> <code>net.Conn.SetDeadline</code>”.
+</p>
+
+<h3 id="plugin">Plugins</h3>
+
+<p>
+ Go now supports a “<code>plugin</code>” build mode for generating
+ plugins written in Go, and a
+ new <a href="/pkg/plugin/"><code>plugin</code></a> package for
+ loading such plugins at run time. Plugin support is only currently
+ available on Linux and macOS.
+</p>
+
+<h2 id="runtime">Runtime</h2>
+
+<h3 id="liveness">Argument Liveness</h3>
+
+<p>
+ <!-- Issue 15843 --> The garbage collector no longer considers
+ arguments live throughout the entirety of a function. For more
+ information, and for how to force a variable to remain live, see
+ the <a href="/pkg/runtime/#KeepAlive"><code>runtime.KeepAlive</code></a>
+ function added in Go 1.7.
+</p>
+
+<p>
+ <i>Updating:</i>
+ Code that sets a finalizer on an allocated object may need to add
+ calls to <code>runtime.KeepAlive</code> in functions or methods
+ using that object.
+ Read the
+ <a href="/pkg/runtime/#KeepAlive"><code>KeepAlive</code>
+ documentation</a> and its example for more details.
+</p>
+
+<h3 id="memstats">MemStats Documentation</h3>
+
+<p> <!-- CL 28972 -->
+ The runtime's <a href="/pkg/runtime/#MemStats"><code>MemStats</code></a>
+ type has been more thoroughly documented.
+</p>
+
+<h2 id="performance">Performance</h2>
+
+<p>
+As always, the changes are so general and varied that precise statements
+about performance are difficult to make.
+Most programs should run a bit faster,
+due to speedups in the garbage collector and
+optimizations in the standard library.
+</p>
+
+<p>
+There have been optimizations to implementations in the
+<a href="/pkg/bytes/"><code>bytes</code></a>,
+<a href="/pkg/crypto/aes/"><code>crypto/aes</code></a>,
+<a href="/pkg/crypto/cipher/"><code>crypto/cipher</code></a>,
+<a href="/pkg/crypto/elliptic/"><code>crypto/elliptic</code></a>,
+<a href="/pkg/crypto/sha256/"><code>crypto/sha256</code></a>,
+<a href="/pkg/crypto/sha512/"><code>crypto/sha512</code></a>,
+<a href="/pkg/encoding/asn1/"><code>encoding/asn1</code></a>,
+<a href="/pkg/encoding/csv/"><code>encoding/csv</code></a>,
+<a href="/pkg/encoding/hex/"><code>encoding/hex</code></a>,
+<a href="/pkg/encoding/json/"><code>encoding/json</code></a>,
+<a href="/pkg/hash/crc32/"><code>hash/crc32</code></a>,
+<a href="/pkg/image/color/"><code>image/color</code></a>,
+<a href="/pkg/image/draw/"><code>image/draw</code></a>,
+<a href="/pkg/math/"><code>math</code></a>,
+<a href="/pkg/math/big/"><code>math/big</code></a>,
+<a href="/pkg/reflect/"><code>reflect</code></a>,
+<a href="/pkg/regexp/"><code>regexp</code></a>,
+<a href="/pkg/runtime/"><code>runtime</code></a>,
+<a href="/pkg/strconv/"><code>strconv</code></a>,
+<a href="/pkg/strings/"><code>strings</code></a>,
+<a href="/pkg/syscall/"><code>syscall</code></a>,
+<a href="/pkg/text/template/"><code>text/template</code></a>, and
+<a href="/pkg/unicode/utf8/"><code>unicode/utf8</code></a>,
+packages.
+</p>
+
+<h3 id="gc">Garbage Collector</h3>
+
+<p>
+ Garbage collection pauses should be significantly shorter than they
+ were in Go 1.7, usually under 100 microseconds and often as low as
+ 10 microseconds.
+ See the
+ <a href="https://github.com/golang/proposal/blob/master/design/17503-eliminate-rescan.md"
+ >document on eliminating stop-the-world stack re-scanning</a>
+ for details. More work remains for Go 1.9.
+</p>
+
+<h3 id="defer">Defer</h3>
+
+<!-- CL 29656, CL 29656 -->
+<p>
+ The overhead of <a href="/ref/spec/#Defer_statements">deferred
+ function calls</a> has been reduced by about half.
+</p>
+
+<h3 id="cgoperf">Cgo</h3>
+
+<p>The overhead of calls from Go into C has been reduced by about half.</p>
+
+<h2 id="library">Standard library</h2>
+
+<h3 id="examples">Examples</h3>
+
+<p>
+Examples have been added to the documentation across many packages.
+</p>
+
+<h3 id="sort_slice">Sort</h3>
+
+<p>
+The <a href="/pkg/sort/">sort</a> package
+now includes a convenience function
+<a href="/pkg/sort/#Slice"><code>Slice</code></a> to sort a
+slice given a <em>less</em> function.
+
+In many cases this means that writing a new sorter type is not
+necessary.
+</p>
+
+<p>
+Also new are
+<a href="/pkg/sort/#SliceStable"><code>SliceStable</code></a> and
+<a href="/pkg/sort/#SliceIsSorted"><code>SliceIsSorted</code></a>.
+</p>
+
+<h3 id="h2push">HTTP/2 Push</h3>
+
+<p>
+The <a href="/pkg/net/http/">net/http</a> package now includes a
+mechanism to
+send HTTP/2 server pushes from a
+<a href="/pkg/net/http/#Handler"><code>Handler</code></a>.
+Similar to the existing <code>Flusher</code> and <code>Hijacker</code>
+interfaces, an HTTP/2
+<a href="/pkg/net/http/#ResponseWriter"><code>ResponseWriter</code></a>
+now implements the new
+<a href="/pkg/net/http/#Pusher"><code>Pusher</code></a> interface.
+</p>
+
+<h3 id="http_shutdown">HTTP Server Graceful Shutdown</h3>
+
+<p> <!-- CL 32329 -->
+ The HTTP Server now has support for graceful shutdown using the new
+ <a href="/pkg/net/http/#Server.Shutdown"><code>Server.Shutdown</code></a>
+ method and abrupt shutdown using the new
+ <a href="/pkg/net/http/#Server.Close"><code>Server.Close</code></a>
+ method.
+</p>
+
+<h3 id="more_context">More Context Support</h3>
+
+<p>
+ Continuing <a href="/doc/go1.7#context">Go 1.7's adoption</a>
+ of <a href="/pkg/context/#Context"><code>context.Context</code></a>
+ into the standard library, Go 1.8 adds more context support
+ to existing packages:
+</p>
+
+<ul>
+ <li>The new <a href="/pkg/net/http/#Server.Shutdown"><code>Server.Shutdown</code></a>
+ takes a context argument.</li>
+ <li>There have been <a href="#database_sql">significant additions</a> to the
+ <a href="/pkg/database/sql/">database/sql</a> package with context support.</li>
+ <li>The new <a href="/pkg/testing/#T.Context"><code>T.Context</code></a>
+ method in the <a href="/pkg/testing/">testing</a> package now returns a context for
+ the active test or benchmark.</li>
+ <li>All nine of the new <code>Lookup</code> methods on the new
+ <a href="/pkg/net/#Resolver"><code>net.Resolver</code></a> now
+ take a context.</li>
+ </ul>
+
+<h3 id="mutex_prof">Mutex Contention Profiling</h3>
+
+<p>
+ The runtime and tools now support profiling contended mutexes.
+</p>
+
+<p>
+ Most users will want to use the new <code>-mutexprofile</code>
+ flag with <a href="/cmd/go/#hdr-Description_of_testing_flags"><code>go</code> <code>test</code></a>,
+ and then use <a href="/cmd/pprof/">pprof</a> on the resultant file.
+</p>
+
+<p>
+ Lower-level support is also available via the new
+ <a href="/pkg/runtime/#MutexProfile"><code>MutexProfile</code></a>
+ and
+ <a href="/pkg/runtime/#SetMutexProfileFraction"><code>SetMutexProfileFraction</code></a>.
+</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. The follow sections list the user visible changes and additions.
+Optimizations and bug fixes are not listed.
+</p>
+
+<dl id="archive_tar"><dt><a href="/pkg/archive/tar/">archive/tar</a></dt>
+ <dd>
+
+ <p> <!-- CL 28471, CL 31440, CL 31441, CL 31444, CL 28418, CL 31439 -->
+ The tar implementation corrects many bugs in corner cases of the file format.
+ The <a href="/pkg/archive/tar/#Reader"><code>Reader</code></a>
+ is now able to process tar files in the PAX format with entries larger than 8GB.
+ The <a href="/pkg/archive/tar/#Writer"><code>Writer</code></a>
+ no longer produces invalid tar files in some situations involving long pathnames.
+ </p>
+
+ </dd>
+</dl>
+
+<dl id="archive_zip"><dt><a href="/pkg/archive/zip/">archive/zip</a></dt>
+ <dd>
+
+ <p> <!-- CL 18274 -->
+ The zip <code>Reader</code> now supports modification times in
+ the NTFS, UNIX, and Extended Time Stamp metadata fields.
+ <!-- CL 30811 -->
+ When writing zip files, the Extended Time Stamp field is written
+ for files with non-zero modification times.
+ </p>
+
+ </dd>
+</dl>
+
+<dl id="compress_flate"><dt><a href="/pkg/compress/flate/">compress/flate</a></dt>
+ <dd>
+
+ <p> <!-- CL 31640, CL 31174, CL 32149 -->
+ There have been some minor fixes to the encoder to improve the
+ compression ratio in certain situations. As a result, the exact
+ encoded output of <code>DEFLATE</code> may be different from Go 1.7. Since
+ DEFLATE is the underlying compression of gzip, png, zlib, and zip,
+ those formats may have changed outputs.
+ </p>
+
+ <p>
+ The encoder, when operating in
+ <a href="/pkg/compress/flate/#NoCompression"><code>NoCompression</code></a>
+ mode, now produces a consistent output that is not dependent on
+ the size of the slices passed to the
+ <a href="/pkg/compress/flate/#Writer.Write"><code>Write</code></a>
+ method.
+ </p>
+
+ <p> <!-- CL 28216 -->
+ The decoder, upon encountering an error, now returns any
+ buffered data it had uncompressed along with the error.
+ </p>
+
+ </dd>
+</dl>
+
+
+<dl id="compress_gzip"><dt><a href="/pkg/compress/gzip/">compress/gzip</a></dt>
+ <dd>
+
+ <p>
+ The <a href="/pkg/compress/gzip/#Writer"><code>Writer</code></a>
+ now encodes a zero <code>MTIME</code> field when
+ the <a href="/pkg/compress/gzip/#Header"><code>Header.ModTime</code></a>
+ field is the zero value.
+
+ In previous releases of Go, the <code>Writer</code> would encode
+ a nonsensical value.
+
+ Similarly,
+ the <a href="/pkg/compress/gzip/#Reader"><code>Reader</code></a>
+ now reports a zero encoded <code>MTIME</code> field as a zero
+ <code>Header.ModTime</code>.
+ </p>
+
+ </dd>
+</dl>
+
+<dl id="context"><dt><a href="/pkg/context/">context</a></dt>
+ <dd>
+ <p> <!-- CL 30370 -->
+ The <a href="/pkg/context#DeadlineExceeded"><code>DeadlineExceeded</code></a>
+ error now implements
+ <a href="/pkg/net/#Error"><code>net.Error</code></a>
+ and reports true for both the <code>Timeout</code> and
+ <code>Temporary</code> methods.
+ </p>
+ </dd>
+</dl>
+
+<dl id="crypto_tls"><dt><a href="/pkg/crypto/tls/">crypto/tls</a></dt>
+ <dd>
+ <p> <!-- CL 25159, CL 31318 -->
+ The new method
+ <a href="/pkg/crypto/tls/#Conn.CloseWrite"><code>Conn.CloseWrite</code></a>
+ allows TLS connections to be half closed.
+ </p>
+
+ <p> <!-- CL 28075 -->
+ The new method
+ <a href="/pkg/crypto/tls/#Config.Clone"><code>Config.Clone</code></a>
+ clones a TLS configuration.
+ </p>
+
+ <p>
+ <!-- CL 30790 -->
+ The new <a href="/pkg/crypto/tls/#Config.GetConfigForClient"><code>Config.GetConfigForClient</code></a>
+ callback allows selecting a configuration for a client dynamically, based
+ on the client's
+ <a href="/pkg/crypto/tls/#ClientHelloInfo"><code>ClientHelloInfo</code></a>.
+
+ <!-- CL 31391, CL 32119 -->
+ The <a href="/pkg/crypto/tls/#ClientHelloInfo"><code>ClientHelloInfo</code></a>
+ struct now has new
+ fields <code>Conn</code>, <code>SignatureSchemes</code> (using
+ the new
+ type <a href="/kg/crypto/tls/#SignatureScheme"><code>SignatureScheme</code></a>),
+ <code>SupportedProtos</code>, and <code>SupportedVersions</code>.
+ </p>
+
+ <p> <!-- CL 32115 -->
+ The new <a href="/pkg/crypto/tls/#Config.GetClientCertificate"><code>Config.GetClientCertificate</code></a>
+ callback allows selecting a client certificate based on the server's
+ TLS <code>CertificateRequest</code> message, represented by the new
+ <a href="/pkg/crypto/tls/#CertificateRequestInfo"><code>CertificateRequestInfo</code></a>.
+ </p>
+
+ <p> <!-- CL 27434 -->
+ The new
+ <a href="/pkg/crypto/tls/#Config.KeyLogWriter"><code>Config.KeyLogWriter</code></a>
+ allows debugging TLS connections
+ in <a href="https://www.wireshark.org/">WireShark</a> and
+ similar tools.
+ </p>
+
+ <p> <!-- CL 32115 -->
+ The new
+ <a href="/pkg/crypto/tls/#Config.VerifyPeerCertificate"><code>Config.VerifyPeerCertificate</code></a>
+ callback allows additional validation of a peer's presented certificate.
+ </p>
+
+ <p> <!-- CL 18130 -->
+ The <code>crypto/tls</code> package now implements basic
+ countermeasures against CBC padding oracles. There should be
+ no explicit secret-dependent timings, but it does not attempt to
+ normalize memory accesses to prevent cache timing leaks.
+ </p>
+
+ <p>
+ The <code>crypto/tls</code> package now supports
+ X25519 and <!-- CL 30824, CL 30825 -->
+ ChaCha20-Poly1305. <!-- CL 30957, CL 30958 -->
+ ChaCha20-Poly1305 is now prioritized unless <!-- CL 32871 -->
+ AES-GCM when hardware support is present.
+ </p>
+
+ <p> <!-- CL 27315 -->
+ AES-128-CBC cipher suites with SHA-256 are also
+ now supported.
+ </p>
+
+ </dd>
+</dl>
+
+<dl id="crypto_x509"><dt><a href="/pkg/crypto/x509/">crypto/x509</a></dt>
+ <dd>
+ <p> <!-- CL 30578 -->
+ <a href="/pkg/crypto/x509/#SystemCertPool"><code>SystemCertPool</code></a>
+ is now implemented on Windows.
+ </p>
+
+ <p> <!-- CL 24743 -->
+ PSS signatures are now supported.
+ </p>
+
+ <p> <!-- CL 32644 -->
+ <a href="/pkg/crypto/x509/#UnknownAuthorityError"><code>UnknownAuthorityError</code></a>
+ now has a <code>Cert</code> field, reporting the untrusted
+ certificate.
+ </p>
+
+ <p>
+ Certificate validation is more permissive in a few cases and
+ stricter in a few other cases.
+ <!--
+crypto/x509: allow a leaf certificate to be specified directly as root (CL 27393)
+crypto/x509: check that the issuer name matches the issuer's subject name (CL 23571)
+crypto/x509: don't accept a root that already appears in a chain. (CL 32121)
+crypto/x509: fix name constraints handling (CL 30155)
+crypto/x509: parse all names in an RDN (CL 30810)
+crypto/x509: recognise ISO OID for RSA+SHA1 (CL 27394)
+crypto/x509: require a NULL parameters for RSA public keys (CL 16166, CL 27312)
+crypto/x509: return error for missing SerialNumber (CL 27238)
+-->
+ </p>
+
+ <p><!-- CL 30375 -->
+ Root certificates will now also be looked for
+ at <code>/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem</code>
+ on Linux, to support RHEL and CentOS.
+ </p>
+
+ </dd>
+</dl>
+
+<dl id="database_sql"><dt><a href="/pkg/database/sql/">database/sql</a></dt>
+ <dd>
+ <p>
+ The package now supports <code>context.Context</code>. There are new methods
+ ending in <code>Context</code> such as
+ <a href="/pkg/database/sql/#DB.QueryContext"><code>DB.QueryContext</code></a> and
+ <a href="/pkg/database/sql/#DB.PrepareContext"><code>DB.PrepareContext</code></a>
+ that take context arguments. Using the new <code>Context</code> methods ensures that
+ connections are closed and returned to the connection pool when the
+ request is done; enables canceling in-progress queries
+ should the driver support that; and allows the database
+ pool to cancel waiting for the next available connection.
+ </p>
+ <p>
+ The <a href="/pkg/database/sql#IsolationLevel"><code>IsolationLevel</code></a>
+ can now be set when starting a transaction by setting the isolation level
+ on the <code>Context</code> then passing that <code>Context</code> to
+ <a href="/pkg/database/sql#DB.BeginContext"><code>DB.BeginContext</code></a>.
+ An error will be returned if an isolation level is selected that the driver
+ does not support. A read-only attribute may also be set on the transaction
+ with <a href="/pkg/database/sql/#ReadOnlyContext"><code>ReadOnlyContext</code></a>.
+ </p>
+ <p>
+ Queries now expose the SQL column type information for drivers that support it.
+ Rows can return <a href="/pkg/database/sql#Rows.ColumnTypes"><code>ColumnTypes</code></a>
+ which can include SQL type information, column type lengths, and the Go type.
+ </p>
+ <p>
+ A <a href="/pkg/database/sql/#Rows"><code>Rows</code></a>
+ can now represent multiple result sets. After
+ <a href="/pkg/database/sql/#Rows.Next"><code>Rows.Next</code></a> returns false,
+ <a href="/pkg/database/sql/#Rows.NextResultSet"><code>Rows.NextResultSet</code></a>
+ may be called to advance to the next result set. The existing <code>Rows</code>
+ should continue to be used after it advances to the next result set.
+ </p>
+ <p>
+ <a href="/pkg/database/sql/#NamedParam"><code>NamedParam</code></a> may be used
+ as query arguments. The new function <a href="/pkg/database/sql/#Param"><code>Param</code></a>
+ helps create a <a href="/pkg/database/sql/#NamedParam"><code>NamedParam</code></a>
+ more succinctly.
+ <p>
+ If a driver supports the new
+ <a href="/pkg/database/sql/driver/#Pinger"><code>Pinger</code></a>
+ interface, the <code>DB</code>'s
+ <a href="/pkg/database/sql/#DB.Ping"><code>DB.Ping</code></a>
+ and
+ <a href="/pkg/database/sql/#DB.PingContext"><code>DB.PingContext</code></a>
+ methods will use that interface to check whether a
+ database connection is still valid.
+ </p>
+ <p>
+ The new <code>Context</code> query methods work for all drivers, but
+ <code>Context</code> cancelation is not responsive unless the driver has been
+ updated to use them. The other features require driver support in
+ <a href="/pkg/database/sql/driver"><code>database/sql/driver</code></a>.
+ Driver authors should review the new interfaces. Users of existing
+ driver should review the driver documentation to see what
+ it supports and any system specific documentation on each feature.
+ </p>
+ </dd>
+</dl>
+
+<dl id="debug_pe"><dt><a href="/pkg/debug/pe/">debug/pe</a></dt>
+ <dd>
+ <p> <!-- CL 22720, CL 27212, CL 22181, CL 22332, CL 22336, Issue 15345 -->
+ The package has been fleshed out and is now used by <a href="/cmd/link/">the Go linker</a>.
+ New are
+ <a href="/pkg/debug/pe/#Reloc"><code>Reloc</code></a>,
+ <a href="/pkg/debug/pe/#Section"><code>Section</code></a>,
+ <a href="/pkg/debug/pe/#StringTable"><code>StringTable</code></a>,
+ the method
+ <a href="/pkg/debug/pe/#COFFSymbol.FullName"><code>COFFSymbol.FullName</code></a>,
+ and
+ <a href="/pkg/debug/pe/#File"><code>File</code></a>
+ fields
+ <a href="/pkg/debug/pe/#File.COFFSymbols"><code>COFFSymbols</code></a> and
+ <a href="/pkg/debug/pe/#File.StringTable"><code>StringTable</code></a>.
+ </p>
+ </dd>
+</dl>
+
+<dl id="encoding_base64"><dt><a href="/pkg/encoding/base64/">encoding/base64</a></dt>
+ <dd>
+ <p> <!-- CL 24964 -->
+ The new
+ <a href="/pkg/encoding/base64/#Encoding.Strict"><code>Encoding.Strict</code></a>
+ method returns an <code>Encoding</code> that causes the decoder
+ to return an error when the trailing padding bits are not zero.
+ </p>
+ </dd>
+</dl>
+
+<dl id="encoding_binary"><dt><a href="/pkg/encoding/binary/">encoding/binary</a></dt>
+ <dd>
+ <p> <!-- CL 28514 -->
+ <a href="/pkg/encoding/binary/#Read"><code>Read</code></a>
+ and
+ <a href="/pkg/encoding/binary/#Write"><code>Write</code></a>
+ now support booleans.
+ </p>
+ </dd>
+</dl>
+
+<dl id="encoding_json"><dt><a href="/pkg/encoding/json/">encoding/json</a></dt>
+ <dd>
+
+ <p> <!-- CL 18692 -->
+ <a href="/pkg/encoding/json/#UnmarshalTypeError"><code>UnmarshalTypeError</code></a>
+ now includes the struct and field name.
+ </p>
+
+ <p> <!-- CL 31932 -->
+ A nil <a href="/pkg/encoding/json/#Marshaler"><code>Marshaler</code></a>
+ now marshals as a JSON <code>null</code> value.
+ </p>
+
+ <p> <!-- CL 21811 -->
+ A <a href="/pkg/encoding/json/#RawMessage"><code>RawMessage</code></a> value now
+ marshals the same as its pointer type.
+ </p>
+
+ <p> <!-- CL 30371 -->
+ <a href="/pkg/encoding/json/#Marshal"><code>Marshal</code></a>
+ encodes floating-point numbers using the same format as in ES6,
+ preferring decimal (not exponential) notation for a wider range of values.
+ In particular, all floating-point integers up to 2<sup>64</sup> format the
+ same as the equivalent <code>int64</code> representation.
+ </p>
+
+ <p> <!-- CL 30944 -->
+
+ In previous versions of Go, unmarshaling a JSON <code>null</code> into an
+ of <a href="/pkg/encoding/json/#Unmarshaler"><code>Unmarshaler</code></a>
+ was considered a no-op; now the <code>Unmarshaler</code>'s
+ <code>UnmarshalJSON</code> method is called with the JSON literal
+ <code>null</code> and can define the semantics of that case.
+ </p>
+
+ </dd>
+</dl>
+
+<dl id="encoding_pem"><dt><a href="/pkg/encoding/pem/">encoding/pem</a></dt>
+ <dd>
+ <p> <!-- CL 27391 -->
+ <a href="/pkg/encoding/pem/#Decode"><code>Decode</code></a>
+ is now strict about the format of the ending line.
+ </p>
+ </dd>
+</dl>
+
+<dl id="encoding_xml"><dt><a href="/pkg/encoding/xml/">encoding/xml</a></dt>
+ <dd>
+ <p> <!-- CL 30946 -->
+ <a href="/pkg/encoding/xml/#Unmarshal"><code>Unmarshal</code></a>
+ now has wildcard support for collecting all attributes using
+ the new <code>",any,attr"</code> struct tag.
+ </p>
+ </dd>
+</dl>
+
+<dl id="expvar"><dt><a href="/pkg/expvar/">expvar</a></dt>
+ <dd>
+ <p> <!-- CL 30917 -->
+ The new methods
+ <a href="/pkg/expvar/#Int.Value"><code>Int.Value</code></a>,
+ <a href="/pkg/expvar/#String.Value"><code>String.Value</code></a>,
+ <a href="/pkg/expvar/#Float.Value"><code>Float.Value</code></a>, and
+ <a href="/pkg/expvar/#Func.Value"><code>Func.Value</code></a>
+ report the current value of an exported variable.
+ </p>
+
+ <p> <!-- CL 24722 -->
+ The new
+ function <a href="/pkg/expvar/#Handler"><code>Handler</code></a>
+ returns the package's HTTP handler, to enable installing it in
+ non-standard locations.
+ </p>
+ </dd>
+</dl>
+
+<dl id="fmt"><dt><a href="/pkg/fmt/">fmt</a></dt>
+ <dd>
+ <p><!-- CL 30611 -->
+ <a href="/pkg/fmt/#Scanf"><code>Scanf</code></a>,
+ <a href="/pkg/fmt/#Fscanf"><code>Fscanf</code></a>, and
+ <a href="/pkg/fmt/#Sscanf"><code>Sscanf</code></a> now
+ handle spaces differently and more consistently than
+ previous releases. See the
+ <a href="/pkg/fmt/#hdr-Scanning">scanning documentation</a>
+ for details.
+ </p>
+ </dd>
+</dl>
+
+<dl id="go_doc"><dt><a href="/pkg/go/doc/">go/doc</a></dt>
+ <dd>
+ <p><!-- CL 29870 -->
+ The new <a href="/pkg/go/doc/#IsPredeclared"><code>IsPredeclared</code></a>
+ function reports whether a string is a predeclared identifier.
+ </p>
+ </dd>
+</dl>
+
+<dl id="go_types"><dt><a href="/pkg/go/types/">go/types</a></dt>
+ <dd>
+ <p><!-- CL 30715 -->
+ The new function
+ <a href="/pkg/go/types/#Default"><code>Default</code></a>
+ returns the default "typed" type for an "untyped" type.
+ </p>
+
+ <p><!-- CL 31939 -->
+ The alignment of <code>complex64</code> now matches
+ the <a href="/cmd/compile/">Go compiler</a>.
+ </p>
+ </dd>
+</dl>
+
+<dl id="html_template"><dt><a href="/pkg/html/template/">html/template</a></dt>
+ <dd>
+ <p><!-- CL 14336 -->
+ The package now validates
+ the <code>"type"</code> attribute on
+ a <code><script></code> tag.
+ </p>
+ </dd>
+</dl>
+
+<dl id="image_png"><dt><a href="/pkg/image/png/">image/png</a></dt>
+ <dd>
+ <p> <!-- CL 32143, CL 32140 -->
+ <a href="/pkg/image/png/#Decode"><code>Decode</code></a>
+ (and <code>DecodeConfig</code>)
+ now supports True Color and grayscale transparency.
+ </p>
+ <p> <!-- CL 29872 -->
+ <a href="/pkg/image/png/#Encoder"><code>Encoder</code></a>
+ is now faster and creates smaller output
+ when encoding paletted images.
+ </p>
+ </dd>
+</dl>
+
+<dl id="math_big"><dt><a href="/pkg/math/big/">math/big</a></dt>
+ <dd>
+ <p><!-- CL 30706 -->
+ The new method
+ <a href="/pkg/math/big/#Int.Sqrt"><code>Int.Sqrt</code></a>
+ calculates ⌊√x⌋.
+ </p>
+
+ <p>
+ The new method
+ <a href="/pkg/math/big/#Float.Scan"><code>Float.Scan</code></a>
+ is a support routine for
+ <a href="/pkg/fmt/#Scanner"><code>fmt.Scanner</code></a>.
+ </p>
+
+ <p>
+ <a href="/pkg/math/big/#Int.ModInverse"><code>Int.ModInverse</code></a>
+ now supports negative numbers.
+ </p>
+
+ </dd>
+</dl>
+
+<dl id="math_rand"><dt><a href="/pkg/math/rand/">math/rand</a></dt>
+ <dd>
+
+ <p><!-- CL 27253, CL 33456 -->
+ The new <a href="/pkg/math/rand/#Rand.Uint64"><code>Rand.Uint64</code></a>
+ method returns <code>uint64</code> values. The
+ new <a href="/pkg/math/rand/#Source64"><code>Source64</code></a>
+ interface describes sources capable of generating such values
+ directly; otherwise the <code>Rand.Uint64</code> method
+ constructs a <code>uint64</code> from two calls
+ to <a href="/pkg/math/rand/#Source"><code>Source</code></a>'s
+ <code>Int63</code> method.
+ </p>
+
+ </dd>
+</dl>
+
+<dl id="mime"><dt><a href="/pkg/mime/">mime</a></dt>
+ <dd>
+ <p> <!-- CL 32175 -->
+ <a href="/pkg/mime/#ParseMediaType"><code>ParseMediaType</code></a>
+ now preserves unnecessary backslash escapes as literals,
+ in order to support MSIE.
+ When MSIE sends a full file path (in "intranet mode"), it does not
+ escape backslashes: <code>"C:\dev\go\foo.txt"</code>, not
+ <code>"C:\\dev\\go\\foo.txt"</code>.
+ If we see an unnecessary backslash escape, we now assume it is from MSIE
+ and intended as a literal backslash.
+ No known MIME generators emit unnecessary backslash escapes
+ for simple token characters like numbers and letters.
+ </p>
+ </dd>
+</dl>
+
+<dl id="mime_quotedprintable"><dt><a href="/pkg/mime/quotedprintable/">mime/quotedprintable</a></dt>
+ <dd>
+
+ <p>
+ The
+ <a href="/pkg/mime/quotedprintable/#Reader"><code>Reader</code></a>'s
+ parsing has been relaxed in two ways to accept
+ more input seen in the wild.
+
+ <!-- CL 32174 -->
+ First, it accepts an equals sign (<code>=</code>) not followed
+ by two hex digits as a literal equal sign.
+
+ <!-- CL 27530 -->
+ Second, it silently ignores a trailing equals sign at the end of
+ an encoded input.
+ </p>
+
+ </dd>
+</dl>
+
+<dl id="net"><dt><a href="/pkg/net/">net</a></dt>
+ <dd>
+
+ <p><!-- CL 30164, CL 33473 -->
+ The <a href="/pkg/net/#Conn"><code>Conn</code></a> documentation
+ has been updated to clarify expectations of an interface
+ implementation. Updates in the <code>net/http</code> packages
+ depend on implementations obeying the documentation.
+ </p>
+ <p><i>Updating:</i> implementations of the <code>Conn</code> interface should verify
+ they implement the documented semantics. The
+ <a href="https://godoc.org/golang.org/x/net/nettest">golang.org/x/net/nettest</a>
+ package will exercise a <code>Conn</code> and validate it behaves properly.
+ </p>
+
+ <p><!-- CL 32099 -->
+ The new method
+ <a href="/pkg/net/#UnixListener.SetUnlinkOnClose"><code>UnixListener.SetUnlinkOnClose</code></a>
+ sets whether the underlying socket file should be removed from the file system when
+ the listener is closed.
+ </p>
+
+ <p><!-- CL 29951 -->
+ The new <a href="/pkg/net/#Buffers"><code>Buffers</code></a> types permits
+ more efficiently writing to the network from multiple discontiguous buffers
+ in memory. On certain machines, for certain types of connections,
+ this is optimized into an OS-specific batch write operation (such as <code>writev</code>).
+ </p>
+
+ <p><!-- CL 29440 -->
+ The new <a href="/pkg/net/#Resolver"><code>Resolver</code></a> looks up names and numbers
+ and supports <a href="/pkg/context/#Context"><code>context.Context</code></a>.
+ The <a href="/pkg/net/#Dialer"><code>Dialer</code></a> now has an optional
+ <a href="/pkg/net/#Dialer.Resolver"><code>Resolver</code> field</a>.
+ </p>
+
+ <p><!-- CL 29892 -->
+ <a href="/pkg/net/#Interfaces"><code>Interfaces</code></a> is now supported on Solaris.
+ </p>
+
+ <p><!-- CL 29233, CL 24901 -->
+ The Go DNS resolver now supports <code>resolv.conf</code>'s "<code>rotate</code>"
+ and "<code>option ndots:0</code>" options. The "<code>ndots</code>" option is
+ now respected in the same way as <code>libresolve</code>.
+ </p>
+
+ </dd>
+</dl>
+
+<dl id="net_http"><dt><a href="/pkg/net/http/">net/http</a></dt>
+ <dd>
+
+ <p>Server changes:</p>
+ <ul>
+ <li>The server now supports graceful shutdown support, <a href="#http_shutdown">mentioned above</a>.</li>
+
+ <li> <!-- CL 32024 -->
+ The <a href="/pkg/net/http/#Server"><code>Server</code></a>
+ adds configuration options
+ <code>ReadHeaderTimeout</code> and <code>IdleTimeout</code>
+ and documents <code>WriteTimeout</code>.
+ </li>
+
+ <li> <!-- CL 32014 -->
+ <a href="/pkg/net/http/#FileServer"><code>FileServer</code></a>
+ and
+ <a href="/pkg/net/http/#ServeContent"><code>ServeContent</code></a>
+ now support HTTP <code>If-Match</code> conditional requests,
+ in addition to the previous <code>If-None-Match</code>
+ support.
+ </li>
+ </ul>
+
+ <p>
+ There are several additions to what a server's <code>Handler</code> can do:
+ </p>
+
+ <ul>
+ <li><!-- CL 31173 -->
+ The <a href="/pkg/context/#Context"><code>Context</code></a>
+ returned
+ by <a href="/pkg/net/http/#Request.Context"><code>Request.Context</code></a>
+ is canceled if the underlying <code>net.Conn</code>
+ closes. For instance, if the user closes their browser in the
+ middle of a slow request, the <code>Handler</code> can now
+ detect that the user is gone. This complements the
+ existing <a href="/pkg/net/http/#CloseNotifier"><code>CloseNotifier</code></a>
+ support. This functionality requires that the underlying
+ <a href="/pkg/net/#Conn"><code>net.Conn</code></a> implements
+ <a href="#net">recently-clarified interface documentation</a>.
+ </li>
+
+ <li><!-- CL 32479 -->
+ To serve trailers known after the header has been written,
+ see the new
+ <a href="/pkg/net/http/#TrailerPrefix"><code>TrailerPrefix</code></a>
+ mechanism.
+ </li>
+
+ <li><!-- CL 33099 -->
+ A <code>Handler</code> can now abort a response by panicking
+ with the error
+ <a href="/pkg/net/http/#ErrAbortHandler"><code>ErrAbortHandler</code></a>.
+ </li>
+
+ <li><!-- CL 30812 -->
+ A <code>Write</code> of zero bytes to a
+ <a href="/pkg/net/http/#ResponseWriter"><code>ResponseWriter</code></a>
+ is now defined as a
+ way to test whether a <code>ResponseWriter</code> has been hijacked:
+ if so, the <code>Write</code> returns
+ <a href="/pkg/net/http/#ErrHijacked"><code>ErrHijacked</code></a>
+ without printing an error
+ to the server's error log.
+ </li>
+
+ </ul>
+
+ <p>Client & Transport changes:</p>
+ <ul>
+ <li><!-- CL 28930 -->
+ The <a href="/pkg/net/http/#Client"><code>Client</code></a>
+ now copies most request headers on redirect. See
+ <a href="/pkg/net/http/#Client">the documentation</a>
+ on the <code>Client</code> type for details.
+ </li>
+
+ <li><!-- CL 29072 -->
+ The <a href="/pkg/net/http/#Transport"><code>Transport</code></a>
+ now supports international domain names. Consequently, so do
+ <a href="/pkg/net/http/#Get">Get</a> and other helpers.
+ </li>
+
+ <li><!-- CL 31733, CL 29852 -->
+ The <code>Client</code> now supports 307 and 308 redirects.
+ If the redirect requires resending the request body,
+ the request must have the new
+ <a href="/pkg/net/http/#Request"><code>Request.GetBody</code></a>
+ field defined.
+ <a href="pkg/net/http/#NewRequest"><code>NewRequest</code></a>
+ sets <code>Request.GetBody</code> automatically for common
+ body types.
+ </li>
+
+ <li><!-- CL 32482 -->
+ The <code>Transport</code> now rejects requests for URLs with
+ ports containing non-digit characters.
+ </li>
+
+ <li><!-- CL 27117 -->
+ The <code>Transport</code> will now retry non-idempotent
+ requests if no bytes were written before a network failure.
+ </li>
+
+ <li><!-- CL 32481 -->
+ The
+ new <a href="/pkg/net/http/#Transport"><code>Transport.ProxyConnectHeader</code></a>
+ allows configuration of header values to send to a proxy
+ during a <code>CONNECT</code> request.
+ </li>
+
+ <li> <!-- CL 28077 -->
+ The <a href="/pkg/net/http/#DefaultTransport"><code>DefaultTransport.Dialer</code></a>
+ now enables <code>DualStack</code> ("<a href="https://tools.ietf.org/html/rfc6555">Happy Eyeballs</a>") support,
+ to use IPv4 as a backup if it looks like IPv6 might be
+ failing.
+ </li>
+ </ul>
+
+ </dd>
+</dl>
+
+<dl id="net_http_httptrace"><dt><a href="/pkg/net/http/httptrace/">net/http/httptrace</a></dt>
+ <dd>
+ <p> <!-- CL 30359 -->
+ There is now support for tracing a client request's TLS handshakes with
+ the new
+ <a href="/pkg/net/http/httptrace/#ClientTrace.TLSHandshakeStart"><code>ClientTrace.TLSHandshakeStart</code></a>
+ and
+ <a href="/pkg/net/http/httptrace/#ClientTrace.TLSHandshakeDone"><code>ClientTrace.TLSHandshakeDone</code></a>.
+ </p>
+ </dd>
+</dl>
+
+<dl id="net_http_httputil"><dt><a href="/pkg/net/http/httputil/">net/http/httputil</a></dt>
+ <dd>
+ <p> <!-- CL 32356 -->
+ The <a href="/pkg/net/http/httputil/#ReverseProxy"><code>ReverseProxy</code></a>
+ has a new optional hook,
+ <a href="/pkg/net/http/httputil/#ReverseProxy.ModifyResponse"><code>ModifyResponse</code></a>,
+ for modifying the response from the backend before proxying it to the client.
+ </p>
+
+ </dd>
+</dl>
+
+<dl id="net_mail"><dt><a href="/pkg/net/mail/">net/mail</a></dt>
+ <dd>
+
+ <p> <!-- CL 32176 -->
+ Empty quoted strings are once again allowed in the name part of
+ an address. That is, Go 1.4 and earlier accepted
+ <code>"" <gopher at example.com></code>,
+ but Go 1.5 introduced a bug that rejected this address.
+ The address is recognized again.
+ </p>
+
+ <p> <!-- CL 31581 -->
+ The
+ <a href="/pkg/net/mail/#Header.Date"><code>Header.Date</code></a>
+ method has always provided a way to parse
+ the <code>Date:</code> header.
+ A new function
+ <a href="/pkg/net/mail/#ParseDate"><code>ParseDate</code></a>
+ allows parsing dates found in other
+ header lines, such as the <code>Resent-Date:</code> header.
+ </p>
+
+ </dd>
+</dl>
+
+<dl id="net_smtp"><dt><a href="/pkg/net/smtp/">net/smtp</a></dt>
+ <dd>
+
+ <p> <!-- CL 33143 -->
+ If an implementation of
+ the <a href="/pkg/net/smtp/#Auth"><code>Auth</code></a>
+ interface's <code>Start</code> method returns an
+ empty <code>toServer</code> value, the package no longer sends
+ trailing whitespace in the SMTP <code>AUTH</code> command,
+ which some servers rejected.
+ </p>
+
+ </dd>
+</dl>
+
+<dl id="net_url"><dt><a href="/pkg/net/url/">net/url</a></dt>
+ <dd>
+
+ <p> <!-- CL 31322 --> The new functions
+ <a href="/pkg/net/url/#PathEscape"><code>PathEscape</code></a>
+ and
+ <a href="/pkg/net/url/#PathUnescape"><code>PathUnescape</code></a>
+ are similar to the query escaping and unescaping functions but
+ for path elements.</p>
+
+ <p> <!-- CL 28933 --> The new methods
+ <a href="/pkg/net/url/#URL.Hostname"><code>URL.Hostname</code></a>
+ and
+ <a href="/pkg/net/url/#URL.Port"><code>URL.Port</code></a>
+ return the hostname and port fields of a URL,
+ correctly handling the case where the port may not be present.
+ </p>
+
+ <p> <!-- CL 28343 --> The existing method
+ <a href="/pkg/net/url/#URL.ResolveReference"><code>URL.ResolveReference</code></a>
+ now properly handles paths with escaped bytes without losing
+ the escaping.
+ </p>
+
+ <p> <!-- CL 31467 -->
+ The <code>URL</code> type now implements
+ <a href="/pkg/encoding/#BinaryMarshaler"><code>encoding.BinaryMarshaler</code></a> and
+ <a href="/pkg/encoding/#BinaryUnmarshaler"><code>encoding.BinaryUnmarshaler</code></a>,
+ making it possible to process URLs in <a href="/pkg/encoding/gob/">gob data</a>.
+ </p>
+
+ <p> <!-- CL 29610, CL 31582 -->
+ Following RFC 3986,
+ <a href="/pkg/net/url/#Parse"><code>Parse</code></a>
+ now rejects URLs like <code>this_that:other/thing</code> instead of
+ interpreting them as relative paths (<code>this_that</code> is not a valid scheme).
+ To force interpretation as a relative path,
+ such URLs should be prefixed with <code>"./"</code>.
+ The <code>URL.String</code> method now inserts this prefix as needed.
+ </p>
+
+ </dd>
+</dl>
+
+<dl id="os"><dt><a href="/pkg/os/">os</a></dt>
+ <dd>
+ <p>
+ The new function
+ <a href="/pkg/os/#Executable"><code>Executable</code></a> returns
+ the path name of the running executable.
+ </p>
+
+ <p> <!-- CL 30614 -->
+ An attempt to call a method on
+ an <a href="/pkg/os/#File"><code>os.File</code></a> that has
+ already been closed will now return the new error
+ value <a href="/pkg/os/#ErrClosed"><code>os.ErrClosed</code></a>.
+ Previously it returned a system-specific error such
+ as <code>syscall.EBADF</code>.
+ </p>
+
+ <p> <!-- CL 31358 -->
+ On Unix systems, <a href="/pkg/os/#Rename"><code>os.Rename</code></a>
+ will now return an error when used to rename a directory to an
+ existing empty directory.
+ Previously it would fail when renaming to a non-empty directory
+ but succeed when renaming to an empty directory.
+ This makes the behavior on Unix correspond to that on other systems.
+ </p>
+
+ <p> <!-- CL 32451 -->
+ On Windows, long absolute paths are now transparently converted to
+ extended-length paths (paths that start with <code>\\?\</code>).
+ This permits the package to work with files whose path names are
+ longer than 260 characters.
+ </p>
+
+ <p> <!-- CL 29753 -->
+ On Windows, <a href="/pkg/os/#IsExist"><code>os.IsExist</code></a>
+ will now return <code>true</code> for the system
+ error <code>ERROR_DIR_NOT_EMPTY</code>.
+ This roughly corresponds to the existing handling of the Unix
+ error <code>ENOTEMPTY</code>.
+ </p>
+
+ <p> <!-- CL 32152 -->
+ On Plan 9, files that are not served by <code>#M</code> will now
+ have <a href="/pkg/os/#ModeDevice"><code>ModeDevice</code></a> set in
+ the value returned
+ by <a href="/pkg/os/#FileInfo"><code>FileInfo.Mode</code></a>.
+ </p>
+ </dd>
+</dl>
+
+<dl id="os_signal"><dt><a href="/pkg/os/signal/">os/signal</a></dt>
+ <dd>
+ <p> <!-- CL 32796 -->
+ In a Go library built with <code>-buildmode=c-archive</code>
+ or <code>c-shared</code>, when C code calls a Go function,
+ the <code>SIGPIPE</code> signal will be treated as usual for Go code.
+ In particular, when <code>SIGPIPE</code> is triggered by a write
+ to a closed Go network connection, it will not cause the program
+ to exit.
+ </p>
+ </dd>
+</dl>
+
+<dl id="path_filepath"><dt><a href="/pkg/path/filepath/">path/filepath</a></dt>
+ <dd>
+ <p>
+ <p>A number of bugs and corner cases on Windows were fixed:
+ <a href="/pkg/path/filepath/#Abs"><code>Abs</code></a> now calls <code>Clean</code> paths as documented,
+ <a href="/pkg/path/filepath/#Glob"><code>Glob</code></a> now matches
+ "<code>\\?\c:\*</code>",
+ <a href="/pkg/path/filepath/#EvalSymlinks"><code>EvalSymlinks</code></a> now
+ correctly handles "<code>C:.</code>", and
+ <a href="/pkg/path/filepath/#Clean"><code>Clean</code></a> now properly
+ handles a leading "<code>..</code>" in the path.
+ <p>
+
+ </dd>
+</dl>
+
+<dl id="reflect"><dt><a href="/pkg/reflect/">reflect</a></dt>
+ <dd>
+ <p> <!-- CL 30088 -->
+ The new function
+ <a href="/pkg/reflect/#Swapper"><code>Swapper</code></a> was
+ added to support <a href="#sortslice"><code>sort.Slice</code></a>.
+ </p>
+ </dd>
+</dl>
+
+<dl id="strconv"><dt><a href="/pkg/strconv/">strconv</a></dt>
+ <dd>
+ <p> <!-- CL 31210 -->
+ The <a href="/pkg/strconv/#Unquote"><code>Unquote</code></a>
+ function now strips carriage returns (<code>\r</code>) in
+ backquoted raw strings, following the
+ <a href="/ref/spec#String_literals">Go language semantics</a>.
+ </p>
+ </dd>
+</dl>
+
+<dl id="syscall"><dt><a href="/pkg/syscall/">syscall</a></dt>
+ <dd>
+ <p> <!-- CL 25050, CL 25022 -->
+ The <a href="/pkg/syscall/#Getpagesize"><code>Getpagesize</code></a>
+ now returns the system's size, rather than a constant value.
+ Previously it always returned 4KB.
+ </p>
+
+ <p> <!-- CL 31446 -->
+ The signature
+ of <a href="/pkg/syscall/#Utimes"><code>Utimes</code></a> has
+ changed on Solaris to match all the other Unix systems'
+ signature. Portable code should continue to use
+ <a href="/pkg/os/#Chtimes"><code>os.Chtimes</code></a> instead.
+ </p>
+
+ <p> <!-- CL 32319 -->
+ The <code>X__cmsg_data</code> field has been removed from
+ <a href="/pkg/syscall/#Cmsghdr"><code>Cmsghdr</code></a>.
+ </p>
+ </dd>
+</dl>
+
+<dl id="text_template"><dt><a href="/pkg/text/template/">text/template</a></dt>
+ <dd>
+ <p> <!-- CL 31462 -->
+ <a href="/pkg/text/template/#Template.Execute"><code>Template.Execute</code></a>
+ can now take a
+ <a href="/pkg/reflect/#Value"><code>reflect.Value</code></a> as its data
+ argument, and
+ <a href="/pkg/text/template/#FuncMap"><code>FuncMap</code></a>
+ functions can also accept and return <code>reflect.Value</code>.
+ </p>
+
+ </dd>
+</dl>
+
+<dl id="time"><dt><a href="/pkg/time/">time</a></dt>
+ <dd>
+
+ <p> <!-- CL 20118 --> The new function
+ <a href="/pkg/time/#Until"><code>Until</code></a> complements
+ the analogous <code>Since</code> function.
+ </p>
+
+ <p> <!-- CL 29338 -->
+ <a href="/pkg/time/#ParseDuration"><code>ParseDuration</code></a>
+ now accepts long fractional parts.
+ </p>
+
+ <p> <!-- CL 33429 -->
+ <a href="/pkg/time/#Parse"><code>Parse</code></a>
+ now rejects dates before the start of a month, such as June 0;
+ it already rejected dates beyond the end of the month, such as
+ June 31 and July 32.
+ </p>
+
+ <p> <!-- CL 33029 -->
+ The <code>tzdata</code> database has been updated to version
+ 2016i for systems that don't already have a local time zone
+ database.
+ </p>
+
+ <p>
+ </dd>
+</dl>
+
+<dl id="testing"><dt><a href="/pkg/testing/">testing</a></dt>
+ <dd>
+ <p><!-- CL 29970 -->
+ The new method
+ <a href="/pkg/testing/#T.Name"><code>T.Name</code></a>
+ (and <code>B.Name</code>) returns the name of the current
+ test or benchmark.
+ </p>
+
+ <p><!-- CL 31724 -->
+ The new method
+ <a href="/pkg/testing/#T.Context"><code>T.Context</code></a>
+ (and <code>B.Context</code>) returns
+ a <a href="/pkg/context/#Context"><code>Context</code></a> for
+ the current running test or benchmark.
+ </p>
+
+ <p><!-- CL 32483 -->
+ The new function
+ <a href="/pkg/testing/#CoverMode"><code>CoverMode</code></a>
+ reports the test coverage mode.
+ </p>
+
+ <p><!-- CL 32615 -->
+ Tests and benchmarks are now marked as failed if the race
+ detector is enabled and a data race occurs during execution.
+ Previously, individual test cases would appear to pass,
+ and only the overall execution of the test binary would fail.
+ </p>
+
+ </dd>
+</dl>
+
+<dl id="unicode"><dt><a href="/pkg/unicode/">unicode</a></dt>
+ <dd>
+ <p><!-- CL 30935 -->
+ <code>SimpleFold</code> now returns its argument unchanged
+ if the provided input was an invalid rune.
+ Previously, the implementation failed with an index bounds check panic.
+ </p>
+ </dd>
+</dl>
diff --git a/doc/go1.8.txt b/doc/go1.8.txt
new file mode 100644
index 0000000..e66ad38
--- /dev/null
+++ b/doc/go1.8.txt
@@ -0,0 +1,56 @@
+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: plugin support on darwin/amd64 (CL 29394)
+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/go_faq.html b/doc/go_faq.html
index 5954d17..3006b3d 100644
--- a/doc/go_faq.html
+++ b/doc/go_faq.html
@@ -271,6 +271,27 @@ you will need to abide by the guidelines at
<h2 id="Design">Design</h2>
+<h3 id="runtime">
+Does Go have a runtime?</h3>
+
+<p>
+Go does have an extensive library, called the <em>runtime</em>,
+that is part of every Go program.
+The runtime library implements garbage collection, concurrency,
+stack management, and other critical features of the Go language.
+Although it is more central to the language, Go's runtime is analogous
+to <code>libc</code>, the C library.
+</p>
+
+<p>
+It is important to understand, however, that Go's runtime does not
+include a virtual machine, such as is provided by the Java runtime.
+Go programs are compiled ahead of time to native machine code.
+Thus, although the term is often used to describe the virtual
+environment in which a program runs, in Go the word “runtime”
+is just the name given to the library providing critical language services.
+</p>
+
<h3 id="unicode_identifiers">
What's up with Unicode identifiers?</h3>
@@ -748,6 +769,29 @@ for i, v := range t {
}
</pre>
+<h3 id="convert_slice_with_same_underlying_type">
+Can I convert []T1 to []T2 if T1 and T2 have the same underlying type?</h3>
+
+This last line of this code sample does not compile.
+
+<pre>
+type T1 int
+type T2 int
+var t1 T1
+var x = T2(t1) // OK
+var st1 []T1
+var sx = ([]T2)(st1) // NOT OK
+</pre>
+
+<p>
+In Go, types are closely tied to methods, in that every named type has
+a (possibly empty) method set.
+The general rule is that you can change the name of the type being
+converted (and thus possibly change its method set) but you can't
+change the name (and method set) of elements of a composite type.
+Go requires you to be explicit about type conversions.
+</p>
+
<h3 id="nil_error">
Why is my nil error value not equal to nil?
</h3>
@@ -868,6 +912,7 @@ Why does Go not have covariant result types?</h3>
<p>
Covariant result types would mean that an interface like
+</p>
<pre>
type Copyable interface {
@@ -875,13 +920,15 @@ type Copyable interface {
}
</pre>
+<p>
would be satisfied by the method
+</p>
<pre>
func (v Value) Copy() Value
</pre>
-because <code>Value</code> implements the empty interface.
+<p>because <code>Value</code> implements the empty interface.
In Go method types must match exactly, so <code>Value</code> does not
implement <code>Copyable</code>.
Go separates the notion of what a
@@ -1047,7 +1094,7 @@ it's easy to work around this. For GitHub, try one of these solutions:
<ul>
<li>Manually clone the repository in the expected package directory:
<pre>
-$ cd $GOPATH/src/github.com/username
+$ cd src/github.com/username
$ git clone git at github.com:username/package.git
</pre>
</li>
@@ -1127,6 +1174,12 @@ struct. If the interface value holds a pointer, copying the interface value
makes a copy of the pointer, but again not the data it points to.
</p>
+<p>
+Note that this discussion is about the semantics of the operations.
+Actual implementations may apply optimizations to avoid copying
+as long as the optimizations do not change the semantics.
+</p>
+
<h3 id="pointer_to_interface">
When should I use a pointer to an interface?</h3>
@@ -1262,11 +1315,26 @@ size of value should use an explicitly sized type, like <code>int64</code>.
Prior to Go 1.1, the 64-bit Go compilers (both gc and gccgo) used
a 32-bit representation for <code>int</code>. As of Go 1.1 they use
a 64-bit representation.
+</p>
+
+<p>
On the other hand, floating-point scalars and complex
-numbers are always sized: <code>float32</code>, <code>complex64</code>,
-etc., because programmers should be aware of precision when using
-floating-point numbers.
-The default size of a floating-point constant is <code>float64</code>.
+types are always sized (there are no <code>float</code> or <code>complex</code> basic types),
+because programmers should be aware of precision when using floating-point numbers.
+The default type used for an (untyped) floating-point constant is <code>float64</code>.
+Thus <code>foo</code> <code>:=</code> <code>3.0</code> declares a variable <code>foo</code>
+of type <code>float64</code>.
+For a <code>float32</code> variable initialized by an (untyped) constant, the variable type
+must be specified explicitly in the variable declaration:
+</p>
+
+<pre>
+var foo float32 = 3.0
+</pre>
+
+<p>
+Alternatively, the constant must be given a type with a conversion as in
+<code>foo := float32(3.0)</code>.
</p>
<h3 id="stack_or_heap">
@@ -1670,8 +1738,7 @@ What compiler technology is used to build the compilers?</h3>
<p>
<code>Gccgo</code> has a front end written in C++, with a recursive descent parser coupled to the
-standard GCC back end. <code>Gc</code> is written in Go using
-<code>yacc</code>/<code>bison</code> for the parser
+standard GCC back end. <code>Gc</code> is written in Go with a recursive descent parser
and uses a custom loader, also written in Go but
based on the Plan 9 loader, to generate ELF/Mach-O/PE binaries.
</p>
@@ -1732,7 +1799,7 @@ A simple C "hello, world" program compiled and linked statically using gcc
on Linux is around 750 kB,
including an implementation of <code>printf</code>.
An equivalent Go program using <code>fmt.Printf</code>
-is around 2.3 MB, but
+is around 1.5 MB, but
that includes more powerful run-time support and type information.
</p>
diff --git a/doc/go_spec.html b/doc/go_spec.html
index 731186e..5872eef 100644
--- a/doc/go_spec.html
+++ b/doc/go_spec.html
@@ -1,6 +1,6 @@
<!--{
"Title": "The Go Programming Language Specification",
- "Subtitle": "Version of May 31, 2016",
+ "Subtitle": "Version of November 18, 2016",
"Path": "/ref/spec"
}-->
@@ -605,7 +605,7 @@ implementation must:
<li>Represent floating-point constants, including the parts of
a complex constant, with a mantissa of at least 256 bits
- and a signed exponent of at least 32 bits.</li>
+ and a signed binary exponent of at least 16 bits.</li>
<li>Give an error if unable to represent an integer constant
precisely.</li>
@@ -2006,7 +2006,7 @@ _, y, _ := coord(p) // coord() returns three values; only interested in y coord
<p>
Unlike regular variable declarations, a short variable declaration may <i>redeclare</i>
variables provided they were originally declared earlier in the same block
-(or the parameter lists if the block is the function body) with the same type,
+(or the parameter lists if the block is the function body) with the same type,
and at least one of the non-<a href="#Blank_identifier">blank</a> variables is new.
As a consequence, redeclaration can only appear in a multi-variable short declaration.
Redeclaration does not introduce a new variable; it just assigns a new value to the original.
@@ -2286,8 +2286,10 @@ For array and slice literals the following rules apply:
<li>Each element has an associated integer index marking
its position in the array.
</li>
- <li>An element with a key uses the key as its index; the
- key must be a constant integer expression.
+ <li>An element with a key uses the key as its index. The
+ key must be a non-negative constant representable by
+ a value of type <code>int</code>; and if it is typed
+ it must be of integer type.
</li>
<li>An element without a key uses the previous element's index plus one.
If the first element has no key, its index is zero.
@@ -2320,7 +2322,7 @@ days := [...]string{"Sat", "Sun"} // len(days) == 2
<p>
A slice literal describes the entire underlying array literal.
-Thus, the length and capacity of a slice literal are the maximum
+Thus the length and capacity of a slice literal are the maximum
element index plus one. A slice literal has the form
</p>
@@ -2350,10 +2352,11 @@ the <code>&T</code> when the element or key type is <code>*T</code>.
[][]int{{1, 2, 3}, {4, 5}} // same as [][]int{[]int{1, 2, 3}, []int{4, 5}}
[][]Point{{{0, 1}, {1, 2}}} // same as [][]Point{[]Point{Point{0, 1}, Point{1, 2}}}
map[string]Point{"orig": {0, 0}} // same as map[string]Point{"orig": Point{0, 0}}
-
-[...]*Point{{1.5, -3.5}, {0, 0}} // same as [...]*Point{&Point{1.5, -3.5}, &Point{0, 0}}
-
map[Point]string{{0, 0}: "orig"} // same as map[Point]string{Point{0, 0}: "orig"}
+
+type PPoint *Point
+[2]*Point{{1.5, -3.5}, {}} // same as [2]*Point{&Point{1.5, -3.5}, &Point{}}
+[2]PPoint{{1.5, -3.5}, {}} // same as [2]PPoint{PPoint(&Point{1.5, -3.5}), PPoint(&Point{})}
</pre>
<p>
@@ -2933,6 +2936,7 @@ used in an <a href="#Assignments">assignment</a> or initialization of the specia
v, ok = a[x]
v, ok := a[x]
var v, ok = a[x]
+var v, ok T = a[x]
</pre>
<p>
@@ -3113,13 +3117,16 @@ known to be <code>T</code> in a correct program.
</p>
<pre>
-var x interface{} = 7 // x has dynamic type int and value 7
-i := x.(int) // i has type int and value 7
+var x interface{} = 7 // x has dynamic type int and value 7
+i := x.(int) // i has type int and value 7
type I interface { m() }
-var y I
-s := y.(string) // illegal: string does not implement I (missing method m)
-r := y.(io.Reader) // r has type io.Reader and y must implement both I and io.Reader
+
+func f(y I) {
+ s := y.(string) // illegal: string does not implement I (missing method m)
+ r := y.(io.Reader) // r has type io.Reader and the dynamic type of y must implement both I and io.Reader
+ …
+}
</pre>
<p>
@@ -3130,6 +3137,7 @@ A type assertion used in an <a href="#Assignments">assignment</a> or initializat
v, ok = x.(T)
v, ok := x.(T)
var v, ok = x.(T)
+var v, ok T1 = x.(T)
</pre>
<p>
@@ -3737,6 +3745,7 @@ A receive expression used in an <a href="#Assignments">assignment</a> or initial
x, ok = <-ch
x, ok := <-ch
var x, ok = <-ch
+var x, ok T = <-ch
</pre>
<p>
@@ -3834,10 +3843,12 @@ in any of these cases:
to <code>T</code>.
</li>
<li>
- <code>x</code>'s type and <code>T</code> have identical
+ ignoring struct tags (see below),
+ <code>x</code>'s type and <code>T</code> have <a href="#Type_identity">identical</a>
<a href="#Types">underlying types</a>.
</li>
<li>
+ ignoring struct tags (see below),
<code>x</code>'s type and <code>T</code> are unnamed pointer types
and their pointer base types have identical underlying types.
</li>
@@ -3858,6 +3869,31 @@ in any of these cases:
</ul>
<p>
+<a href="#Struct_types">Struct tags</a> are ignored when comparing struct types
+for identity for the purpose of conversion:
+</p>
+
+<pre>
+type Person struct {
+ Name string
+ Address *struct {
+ Street string
+ City string
+ }
+}
+
+var data *struct {
+ Name string `json:"name"`
+ Address *struct {
+ Street string `json:"street"`
+ City string `json:"city"`
+ } `json:"address"`
+}
+
+var person = (*Person)(data) // ignoring tags, the underlying types are identical
+</pre>
+
+<p>
Specific rules apply to (non-constant) conversions between numeric types or
to and from a string type.
These conversions may change the representation of <code>x</code>
@@ -4687,8 +4723,8 @@ TypeList = Type { "," Type } .
<p>
The TypeSwitchGuard may include a
<a href="#Short_variable_declarations">short variable declaration</a>.
-When that form is used, the variable is declared at the beginning of
-the <a href="#Blocks">implicit block</a> in each clause.
+When that form is used, the variable is declared at the end of the
+TypeSwitchCase in the <a href="#Blocks">implicit block</a> of each clause.
In clauses with a case listing exactly one type, the variable
has that type; otherwise, the variable has the type of the expression
in the TypeSwitchGuard.
@@ -4763,8 +4799,8 @@ The "fallthrough" statement is not permitted in a type switch.
<h3 id="For_statements">For statements</h3>
<p>
-A "for" statement specifies repeated execution of a block. The iteration is
-controlled by a condition, a "for" clause, or a "range" clause.
+A "for" statement specifies repeated execution of a block. There are three forms:
+The iteration may be controlled by a single condition, a "for" clause, or a "range" clause.
</p>
<pre class="ebnf">
@@ -4772,6 +4808,8 @@ ForStmt = "for" [ Condition | ForClause | RangeClause ] Block .
Condition = Expression .
</pre>
+<h4 id="For_condition">For statements with single condition</h4>
+
<p>
In its simplest form, a "for" statement specifies the repeated execution of
a block as long as a boolean condition evaluates to true.
@@ -4786,6 +4824,8 @@ for a < b {
}
</pre>
+<h4 id="For_clause">For statements with <code>for</code> clause</h4>
+
<p>
A "for" statement with a ForClause is also controlled by its condition, but
additionally it may specify an <i>init</i>
@@ -4824,6 +4864,8 @@ for cond { S() } is the same as for ; cond ; { S() }
for { S() } is the same as for true { S() }
</pre>
+<h4 id="For_range">For statements with <code>range</code> clause</h4>
+
<p>
A "for" statement with a "range" clause
iterates through all entries of an array, slice, string or map,
@@ -5723,12 +5765,12 @@ var a = complex(2, -2) // complex128
const b = complex(1.0, -1.4) // untyped complex constant 1 - 1.4i
x := float32(math.Cos(math.Pi/2)) // float32
var c64 = complex(5, -x) // complex64
-const s uint = complex(1, 0) // untyped complex constant 1 + 0i can be converted to uint
-_ = complex(1, 2<<s) // illegal: 2 has floating-point type, cannot shift
+var s uint = complex(1, 0) // untyped complex constant 1 + 0i can be converted to uint
+_ = complex(1, 2<<s) // illegal: 2 assumes floating-point type, cannot shift
var rl = real(c64) // float32
var im = imag(a) // float64
const c = imag(b) // untyped constant -1.4
-_ = imag(3 << s) // illegal: 3 has complex type, cannot shift
+_ = imag(3 << s) // illegal: 3 assumes complex type, cannot shift
</pre>
<h3 id="Handling_panics">Handling panics</h3>
@@ -6159,9 +6201,10 @@ func init() { … }
</pre>
<p>
-Multiple such functions may be defined, even within a single
-source file. The <code>init</code> identifier is not
-<a href="#Declarations_and_scope">declared</a> and thus
+Multiple such functions may be defined per package, even within a single
+source file. In the package block, the <code>init</code> identifier can
+be used only to declare <code>init</code> functions, yet the identifier
+itself is not <a href="#Declarations_and_scope">declared</a>. Thus
<code>init</code> functions cannot be referred to from anywhere
in a program.
</p>
diff --git a/doc/install-source.html b/doc/install-source.html
index 77616c1..4a25e37 100644
--- a/doc/install-source.html
+++ b/doc/install-source.html
@@ -43,17 +43,13 @@ architectures.
<code>amd64</code> (also known as <code>x86-64</code>)
</dt>
<dd>
- A mature implementation. New in 1.7 is its SSA-based back end
- that generates compact, efficient code.
+ A mature implementation.
</dd>
<dt>
<code>386</code> (<code>x86</code> or <code>x86-32</code>)
</dt>
<dd>
- Comparable to the <code>amd64</code> port, but does
- not yet use the SSA-based back end. It has an effective
- optimizer (registerizer) and generates good code (although
- <code>gccgo</code> can do noticeably better sometimes).
+ Comparable to the <code>amd64</code> port.
</dd>
<dt>
<code>arm</code> (<code>ARM</code>)
@@ -434,7 +430,7 @@ to override the defaults.
<ul>
<li><code>$GOROOT</code>
<p>
-The root of the Go tree, often <code>$HOME/go</code>.
+The root of the Go tree, often <code>$HOME/go1.X</code>.
Its value is built into the tree when it is compiled, and
defaults to the parent of the directory where <code>all.bash</code> was run.
There is no need to set this unless you want to switch between multiple
@@ -459,7 +455,7 @@ These default to the values of <code>$GOHOSTOS</code> and
<p>
Choices for <code>$GOOS</code> are
-<code>darwin</code> (Mac OS X 10.7 and above and iOS), <code>dragonfly</code>, <code>freebsd</code>,
+<code>darwin</code> (Mac OS X 10.8 and above and iOS), <code>dragonfly</code>, <code>freebsd</code>,
<code>linux</code>, <code>netbsd</code>, <code>openbsd</code>,
<code>plan9</code>, <code>solaris</code> and <code>windows</code>.
Choices for <code>$GOARCH</code> are
@@ -636,7 +632,7 @@ something like this:
</p>
<pre>
-export GOROOT=$HOME/go
+export GOROOT=$HOME/go1.X
export GOARCH=amd64
export GOOS=linux
</pre>
diff --git a/doc/install.html b/doc/install.html
index cfe3e67..ebe66c0 100644
--- a/doc/install.html
+++ b/doc/install.html
@@ -49,12 +49,12 @@ If your OS or architecture is not on the list, you may be able to
<tr><td colspan="3"><hr></td></tr>
<tr><td>FreeBSD 8-STABLE or later</td> <td>amd64</td> <td>Debian GNU/kFreeBSD not supported</td></tr>
<tr><td>Linux 2.6.23 or later with glibc</td> <td>amd64, 386, arm</td> <td>CentOS/RHEL 5.x not supported</td></tr>
-<tr><td>Mac OS X 10.7 or later</td> <td>amd64</td> <td>use the clang or gcc<sup>†</sup> that comes with Xcode<sup>‡</sup> for <code>cgo</code> support</td></tr>
+<tr><td>Mac OS X 10.8 or later</td> <td>amd64</td> <td>use the clang or gcc<sup>†</sup> that comes with Xcode<sup>‡</sup> for <code>cgo</code> support</td></tr>
<tr><td>Windows XP or later</td> <td>amd64, 386</td> <td>use MinGW gcc<sup>†</sup>. No need for cygwin or msys.</td></tr>
</table>
<p>
-<sup>†</sup><code>gcc</code> is required only if you plan to use
+<sup>†</sup>A C compiler is required only if you plan to use
<a href="/cmd/cgo">cgo</a>.<br/>
<sup>‡</sup>You only need to install the command line tools for
<a href="http://developer.apple.com/Xcode/">Xcode</a>. If you have already
@@ -117,12 +117,12 @@ to point to the directory in which it was installed.
</p>
<p>
-For example, if you installed Go to your home directory you should add the
-following commands to <code>$HOME/.profile</code>:
+For example, if you installed Go to your home directory you should add
+commands like the following to <code>$HOME/.profile</code>:
</p>
<pre>
-export GOROOT=$HOME/go
+export GOROOT=$HOME/go1.X
export PATH=$PATH:$GOROOT/bin
</pre>
@@ -219,37 +219,16 @@ and building a simple program, as follows.
</p>
<p>
-Create a directory to contain your <a href="code.html#Workspaces">workspace</a>,
-<code class="testUnix">$HOME/work</code>
-<code class="testWindows" style="display: none">C:\work</code>
-for example, and set the <code>GOPATH</code> environment
-variable to point to that location.
+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.)
</p>
-<pre class="testUnix">
-$ <b>export GOPATH=$HOME/work</b>
-</pre>
-
-<pre class="testWindows" style="display: none">
-C:\> <b>set GOPATH=C:\work</b>
-</pre>
-
<p>
-<span class="testUnix">
-You should put the above command in your shell startup script
-(<code>$HOME/.profile</code> for example).
-</span>
-<span class="testWindows">
-On Windows, follow the <a href="#windows_env">instructions above</a> to set the
-<code>GOPATH</code> environment variable on your system.
-</span>
-</p>
-
-<p>
-Next, make the directories <code>src/github.com/user/hello</code> inside your
-workspace (if you use GitHub, substitute your user name for <code>user</code>),
-and inside the <code>hello</code> directory create a file named <code>hello.go</code>
-with the following contents:
+Next, make the directory <code>src/hello</code> inside your workspace,
+and in that directory create a file named <code>hello.go</code> that looks like:
</p>
<pre>
@@ -263,30 +242,33 @@ func main() {
</pre>
<p>
-Then compile it with the <code>go</code> tool:
+Then build it with the <code>go</code> tool:
</p>
<pre class="testUnix">
-$ <b>go install github.com/user/hello</b>
+$ <b>cd $HOME/go/src/hello
+$ <b>go build</b>
</pre>
<pre class="testWindows" style="display: none">
-C:\> <b>go install github.com/user/hello</b>
+C:\> <b>cd %USERPROFILE%\go\src\hello<b>
+C:\Users\Gopher\go\src\hello> <b>go build</b>
</pre>
<p>
-The command above will put an executable command named <code>hello</code>
-(or <code>hello.exe</code>) inside the <code>bin</code> directory of your workspace.
-Execute the command to see the greeting:
+The command above will build an executable named
+<code class="testUnix">hello</code><code class="testWindows">hello.exe</code>
+in the directory alongside your source code.
+Execute it to see the greeting:
</p>
<pre class="testUnix">
-$ <b>$GOPATH/bin/hello</b>
+$ <b>./hello</b>
hello, world
</pre>
<pre class="testWindows" style="display: none">
-C:\> <b>%GOPATH%\bin\hello</b>
+C:\Users\Gopher\go\src\hello> <b>hello</b>
hello, world
</pre>
@@ -295,6 +277,12 @@ If you see the "hello, world" message then your Go installation is working.
</p>
<p>
+You can run <code>go</code> <code>install</code> to install the binary into
+your workspace's <code>bin</code> directory
+or <code>go</code> <code>clean</code> to remove it.
+</p>
+
+<p>
Before rushing off to write Go code please read the
<a href="/doc/code.html">How to Write Go Code</a> document,
which describes some essential concepts about using the Go tools.
diff --git a/doc/progs/json1.go b/doc/progs/json1.go
index 9e10f47..9804efb 100644
--- a/doc/progs/json1.go
+++ b/doc/progs/json1.go
@@ -28,7 +28,7 @@ func Encode() {
expected := []byte(`{"Name":"Alice","Body":"Hello","Time":1294706395881547000}`)
if !reflect.DeepEqual(b, expected) {
- log.Panicf("Error marshalling %q, expected %q, got %q.", m, expected, b)
+ log.Panicf("Error marshaling %q, expected %q, got %q.", m, expected, b)
}
}
@@ -49,7 +49,7 @@ func Decode() {
}
if !reflect.DeepEqual(m, expected) {
- log.Panicf("Error unmarshalling %q, expected %q, got %q.", b, expected, m)
+ log.Panicf("Error unmarshaling %q, expected %q, got %q.", b, expected, m)
}
m = Message{
@@ -77,7 +77,7 @@ func PartialDecode() {
}
if !reflect.DeepEqual(expected, m) {
- log.Panicf("Error unmarshalling %q, expected %q, got %q.", b, expected, m)
+ log.Panicf("Error unmarshaling %q, expected %q, got %q.", b, expected, m)
}
}
diff --git a/doc/progs/json3.go b/doc/progs/json3.go
index a04fdfa..442c155 100644
--- a/doc/progs/json3.go
+++ b/doc/progs/json3.go
@@ -33,7 +33,7 @@ func Decode() {
}
if !reflect.DeepEqual(f, expected) {
- log.Panicf("Error unmarshalling %q, expected %q, got %q", b, expected, f)
+ log.Panicf("Error unmarshaling %q, expected %q, got %q", b, expected, f)
}
f = map[string]interface{}{
diff --git a/doc/progs/json4.go b/doc/progs/json4.go
index 4926302..1c7e5b4 100644
--- a/doc/progs/json4.go
+++ b/doc/progs/json4.go
@@ -36,7 +36,7 @@ func Decode() {
}
if !reflect.DeepEqual(expected, m) {
- log.Panicf("Error unmarshalling %q, expected %q, got %q", b, expected, m)
+ log.Panicf("Error unmarshaling %q, expected %q, got %q", b, expected, m)
}
}
diff --git a/lib/time/update.bash b/lib/time/update.bash
index e4987bb..b70788e 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=2016f
-DATA=2016f
+CODE=2016i
+DATA=2016i
set -e
rm -rf work
diff --git a/lib/time/zoneinfo.zip b/lib/time/zoneinfo.zip
index bbb8e86..e12d6dc 100644
Binary files a/lib/time/zoneinfo.zip and b/lib/time/zoneinfo.zip differ
diff --git a/misc/cgo/errors/issue16591.go b/misc/cgo/errors/issue16591.go
new file mode 100644
index 0000000..10eb840
--- /dev/null
+++ b/misc/cgo/errors/issue16591.go
@@ -0,0 +1,17 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Issue 16591: Test that we detect an invalid call that was being
+// hidden by a type conversion inserted by cgo checking.
+
+package p
+
+// void f(int** p) { }
+import "C"
+
+type x *C.int
+
+func F(p *x) {
+ C.f(p) // ERROR HERE
+}
diff --git a/misc/cgo/errors/malloc.go b/misc/cgo/errors/malloc.go
new file mode 100644
index 0000000..65da020
--- /dev/null
+++ b/misc/cgo/errors/malloc.go
@@ -0,0 +1,34 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Test that C.malloc does not return nil.
+
+package main
+
+// #include <stdlib.h>
+import "C"
+
+import (
+ "fmt"
+ "runtime"
+)
+
+func main() {
+ var size C.size_t
+ size--
+
+ // The Dragonfly libc succeeds when asked to allocate
+ // 0xffffffffffffffff bytes, so pass a different value that
+ // causes it to fail.
+ if runtime.GOOS == "dragonfly" {
+ size = C.size_t(0x7fffffff << (32 * (^uintptr(0) >> 63)))
+ }
+
+ p := C.malloc(size)
+ if p == nil {
+ fmt.Println("malloc: C.malloc returned nil")
+ // Just exit normally--the test script expects this
+ // program to crash, so exiting normally indicates failure.
+ }
+}
diff --git a/misc/cgo/errors/ptr.go b/misc/cgo/errors/ptr.go
index e39f041..4dafbdf 100644
--- a/misc/cgo/errors/ptr.go
+++ b/misc/cgo/errors/ptr.go
@@ -322,6 +322,27 @@ var ptrTests = []ptrTest{
body: `p := &C.s{}; defer C.f(p); p.p = new(C.int)`,
fail: true,
},
+ {
+ // Check a pointer to a union if the union has any
+ // pointer fields.
+ name: "union1",
+ c: `typedef union { char **p; unsigned long i; } u; void f(u *pu) {}`,
+ imports: []string{"unsafe"},
+ body: `var b C.char; p := &b; C.f((*C.u)(unsafe.Pointer(&p)))`,
+ fail: true,
+ },
+ {
+ // Don't check a pointer to a union if the union does
+ // not have any pointer fields.
+ // Like ptrdata1 above, the uintptr represents an
+ // integer that happens to have the same
+ // representation as a pointer.
+ name: "union2",
+ c: `typedef union { unsigned long i; } u; void f(u *pu) {}`,
+ imports: []string{"unsafe"},
+ body: `var b C.char; p := &b; C.f((*C.u)(unsafe.Pointer(&p)))`,
+ fail: false,
+ },
}
func main() {
diff --git a/misc/cgo/errors/test.bash b/misc/cgo/errors/test.bash
index 84d44d8..05261e9 100755
--- a/misc/cgo/errors/test.bash
+++ b/misc/cgo/errors/test.bash
@@ -46,6 +46,7 @@ check issue13423.go
expect issue13635.go C.uchar C.schar C.ushort C.uint C.ulong C.longlong C.ulonglong C.complexfloat C.complexdouble
check issue13830.go
check issue16116.go
+check issue16591.go
if ! go build issue14669.go; then
exit 1
@@ -58,5 +59,15 @@ if ! go run ptr.go; then
exit 1
fi
+# The malloc.go test should crash.
+rm -f malloc.out
+if go run malloc.go >malloc.out 2>&1; then
+ echo '`go run malloc.go` succeeded unexpectedly'
+ cat malloc.out
+ rm -f malloc.out
+ exit 1
+fi
+rm -f malloc.out
+
rm -rf errs _obj
exit 0
diff --git a/misc/cgo/test/api.go b/misc/cgo/test/api.go
index b4ae3dd..d2b09cb 100644
--- a/misc/cgo/test/api.go
+++ b/misc/cgo/test/api.go
@@ -7,6 +7,11 @@
package cgotest
// #include <stdlib.h>
+//
+// // Test for issue 17723.
+// typedef char *cstring_pointer;
+// static void cstring_pointer_fun(cstring_pointer dummy) { }
+//
// const char *api_hello = "hello!";
import "C"
import "unsafe"
@@ -21,4 +26,5 @@ func testAPI() {
var b []byte
b = C.GoBytes(unsafe.Pointer(C.api_hello), C.int(6))
_, _ = s, b
+ C.cstring_pointer_fun(nil)
}
diff --git a/misc/cgo/test/basic.go b/misc/cgo/test/basic.go
index 2189af6..3ceb4ce 100644
--- a/misc/cgo/test/basic.go
+++ b/misc/cgo/test/basic.go
@@ -162,3 +162,6 @@ func testUnsignedInt(t *testing.T) {
func sliceOperands(array [2000]int) {
_ = array[C.KILO:C.KILO:C.KILO] // no type error
}
+
+// set in cgo_thread_lock.go init
+var testThreadLockFunc = func(*testing.T) {}
diff --git a/misc/cgo/test/callback.go b/misc/cgo/test/callback.go
index 21d1df5..b88bf13 100644
--- a/misc/cgo/test/callback.go
+++ b/misc/cgo/test/callback.go
@@ -186,6 +186,7 @@ func testCallbackCallers(t *testing.T) {
"runtime.asmcgocall",
"runtime.cgocall",
"test._Cfunc_callback",
+ "test.nestedCall.func1",
"test.nestedCall",
"test.testCallbackCallers",
"test.TestCallbackCallers",
diff --git a/misc/cgo/test/cgo_test.go b/misc/cgo/test/cgo_test.go
index 8a95b02..a6de999 100644
--- a/misc/cgo/test/cgo_test.go
+++ b/misc/cgo/test/cgo_test.go
@@ -70,5 +70,11 @@ func Test12030(t *testing.T) { test12030(t) }
func TestGCC68255(t *testing.T) { testGCC68255(t) }
func TestCallGoWithString(t *testing.T) { testCallGoWithString(t) }
func Test14838(t *testing.T) { test14838(t) }
+func Test8756(t *testing.T) { test8756(t) }
+func Test17065(t *testing.T) { test17065(t) }
+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 BenchmarkCgoCall(b *testing.B) { benchCgoCall(b) }
diff --git a/misc/cgo/test/cgo_thread_lock.go b/misc/cgo/test/cgo_thread_lock.go
new file mode 100644
index 0000000..b105068
--- /dev/null
+++ b/misc/cgo/test/cgo_thread_lock.go
@@ -0,0 +1,53 @@
+// Copyright 2016 The Go Authors. 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,freebsd,openbsd
+
+package cgotest
+
+/*
+#include <unistd.h>
+#include <sys/syscall.h>
+void Gosched(void);
+static int Ctid(void) { Gosched(); return syscall(SYS_gettid); }
+*/
+import "C"
+
+import (
+ "runtime"
+ "syscall"
+ "testing"
+ "time"
+)
+
+//export Gosched
+func Gosched() {
+ runtime.Gosched()
+}
+
+func init() {
+ testThreadLockFunc = testThreadLock
+}
+
+func testThreadLock(t *testing.T) {
+ stop := make(chan int)
+ go func() {
+ // We need the G continue running,
+ // so the M has a chance to run this G.
+ for {
+ select {
+ case <-stop:
+ return
+ case <-time.After(time.Millisecond * 100):
+ }
+ }
+ }()
+ defer close(stop)
+
+ for i := 0; i < 1000; i++ {
+ if C.int(syscall.Gettid()) != C.Ctid() {
+ t.Fatalf("cgo has not locked OS thread")
+ }
+ }
+}
diff --git a/misc/cgo/test/checkconst.go b/misc/cgo/test/checkconst.go
new file mode 100644
index 0000000..0160c1e
--- /dev/null
+++ b/misc/cgo/test/checkconst.go
@@ -0,0 +1,33 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Test a constant in conjunction with pointer checking.
+
+package cgotest
+
+/*
+#include <stdlib.h>
+
+#define CheckConstVal 0
+
+typedef struct {
+ int *p;
+} CheckConstStruct;
+
+static void CheckConstFunc(CheckConstStruct *p, int e) {
+}
+*/
+import "C"
+
+import (
+ "testing"
+ "unsafe"
+)
+
+func testCheckConst(t *testing.T) {
+ // The test is that this compiles successfully.
+ p := C.malloc(C.size_t(unsafe.Sizeof(C.int(0))))
+ defer C.free(p)
+ C.CheckConstFunc(&C.CheckConstStruct{(*C.int)(p)}, C.CheckConstVal)
+}
diff --git a/misc/cgo/test/complex.go b/misc/cgo/test/complex.go
new file mode 100644
index 0000000..ca0a97d
--- /dev/null
+++ b/misc/cgo/test/complex.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 cgotest
+
+/*
+struct {
+ float x;
+ _Complex float y;
+} cplxAlign = { 3.14, 2.17 };
+*/
+import "C"
+
+import "testing"
+
+func TestComplexAlign(t *testing.T) {
+ if C.cplxAlign.x != 3.14 {
+ t.Errorf("got %v, expected 3.14", C.cplxAlign.x)
+ }
+ if C.cplxAlign.y != 2.17 {
+ t.Errorf("got %v, expected 2.17", C.cplxAlign.y)
+ }
+}
diff --git a/misc/cgo/test/issue17065.go b/misc/cgo/test/issue17065.go
new file mode 100644
index 0000000..ede30bc
--- /dev/null
+++ b/misc/cgo/test/issue17065.go
@@ -0,0 +1,29 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cgotest
+
+/*
+// Test that C symbols larger than a page play nicely with the race detector.
+// See issue 17065.
+
+int ii[65537];
+*/
+import "C"
+
+import (
+ "runtime"
+ "testing"
+)
+
+var sink C.int
+
+func test17065(t *testing.T) {
+ if runtime.GOOS == "darwin" {
+ t.Skip("broken on darwin; issue 17065")
+ }
+ for i := range C.ii {
+ sink = C.ii[i]
+ }
+}
diff --git a/misc/cgo/test/issue17537.go b/misc/cgo/test/issue17537.go
new file mode 100644
index 0000000..debdbfe
--- /dev/null
+++ b/misc/cgo/test/issue17537.go
@@ -0,0 +1,42 @@
+// Copyright 2016 The Go 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 17537. The void* cast introduced by cgo to avoid problems
+// with const/volatile qualifiers breaks C preprocessor macros that
+// emulate functions.
+
+package cgotest
+
+/*
+#include <stdlib.h>
+
+typedef struct {
+ int i;
+} S17537;
+
+int I17537(S17537 *p);
+
+#define I17537(p) ((p)->i)
+
+// Calling this function used to fail without the cast.
+const int F17537(const char **p) {
+ return **p;
+}
+*/
+import "C"
+
+import "testing"
+
+func test17537(t *testing.T) {
+ v := C.S17537{i: 17537}
+ if got, want := C.I17537(&v), C.int(17537); got != want {
+ t.Errorf("got %d, want %d", got, want)
+ }
+
+ p := (*C.char)(C.malloc(1))
+ *p = 17
+ if got, want := C.F17537(&p), C.int(17); got != want {
+ t.Errorf("got %d, want %d", got, want)
+ }
+}
diff --git a/misc/cgo/test/issue18126.go b/misc/cgo/test/issue18126.go
new file mode 100644
index 0000000..ac94a66
--- /dev/null
+++ b/misc/cgo/test/issue18126.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.
+
+// Issue 18126: cgo check of void function returning errno.
+
+package cgotest
+
+/*
+#include <stdlib.h>
+
+void Issue18126C(void **p) {
+}
+*/
+import "C"
+
+import (
+ "testing"
+)
+
+func test18126(t *testing.T) {
+ p := C.malloc(1)
+ _, err := C.Issue18126C(&p)
+ C.free(p)
+ _ = err
+}
diff --git a/misc/cgo/test/issue7978.go b/misc/cgo/test/issue7978.go
index e4cbf1d..7fb62e8 100644
--- a/misc/cgo/test/issue7978.go
+++ b/misc/cgo/test/issue7978.go
@@ -88,9 +88,20 @@ func issue7978wait(store uint32, wait uint32) {
//export issue7978cb
func issue7978cb() {
+ // Force a stack growth from the callback to put extra
+ // pressure on the runtime. See issue #17785.
+ growStack(64)
issue7978wait(3, 4)
}
+func growStack(n int) int {
+ var buf [128]int
+ if n == 0 {
+ return 0
+ }
+ return buf[growStack(n-1)]
+}
+
func issue7978go() {
C.issue7978c((*C.uint32_t)(&issue7978sync))
issue7978wait(7, 8)
diff --git a/misc/cgo/test/issue8756.go b/misc/cgo/test/issue8756.go
new file mode 100644
index 0000000..d8ee3b8
--- /dev/null
+++ b/misc/cgo/test/issue8756.go
@@ -0,0 +1,17 @@
+package cgotest
+
+/*
+#cgo LDFLAGS: -lm
+#include <math.h>
+*/
+import "C"
+import (
+ "testing"
+
+ "./issue8756"
+)
+
+func test8756(t *testing.T) {
+ issue8756.Pow()
+ C.pow(1, 2)
+}
diff --git a/misc/cgo/test/issue8756/issue8756.go b/misc/cgo/test/issue8756/issue8756.go
new file mode 100644
index 0000000..5f6b777
--- /dev/null
+++ b/misc/cgo/test/issue8756/issue8756.go
@@ -0,0 +1,11 @@
+package issue8756
+
+/*
+#cgo LDFLAGS: -lm
+#include <math.h>
+*/
+import "C"
+
+func Pow() {
+ C.pow(1, 2)
+}
diff --git a/misc/cgo/testcarchive/carchive_test.go b/misc/cgo/testcarchive/carchive_test.go
index ab14c00..3c768a0 100644
--- a/misc/cgo/testcarchive/carchive_test.go
+++ b/misc/cgo/testcarchive/carchive_test.go
@@ -6,6 +6,7 @@ package carchive_test
import (
"bufio"
+ "debug/elf"
"fmt"
"io/ioutil"
"os"
@@ -34,13 +35,9 @@ var GOOS, GOARCH string
var libgodir string
func init() {
- bin = []string{"./testp"}
GOOS = goEnv("GOOS")
GOARCH = goEnv("GOARCH")
- execScript := "go_" + GOOS + "_" + GOARCH + "_exec"
- if executor, err := exec.LookPath(execScript); err == nil {
- bin = []string{executor, "./testp"}
- }
+ bin = cmdToRun("./testp")
ccOut := goEnv("CC")
cc = []string{string(ccOut)}
@@ -84,8 +81,13 @@ func init() {
cc = append(cc, []string{"-framework", "CoreFoundation", "-framework", "Foundation"}...)
}
libgodir = GOOS + "_" + GOARCH
- if GOOS == "darwin" && (GOARCH == "arm" || GOARCH == "arm64") {
- libgodir = GOOS + "_" + GOARCH + "_shared"
+ switch GOOS {
+ case "darwin":
+ if GOARCH == "arm" || GOARCH == "arm64" {
+ libgodir += "_shared"
+ }
+ case "dragonfly", "freebsd", "linux", "netbsd", "openbsd", "solaris":
+ libgodir += "_shared"
}
cc = append(cc, "-I", filepath.Join("pkg", libgodir))
@@ -120,81 +122,62 @@ func goEnv(key string) string {
return strings.TrimSpace(string(out))
}
-func compilemain(t *testing.T, libgo string) {
- ccArgs := append(cc, "-o", "testp"+exeSuffix, "main.c")
- if GOOS == "windows" {
- ccArgs = append(ccArgs, "main_windows.c", libgo, "-lntdll", "-lws2_32", "-lwinmm")
- } else {
- ccArgs = append(ccArgs, "main_unix.c", libgo)
- }
- t.Log(ccArgs)
-
- if out, err := exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput(); err != nil {
- t.Logf("%s", out)
- t.Fatal(err)
+func cmdToRun(name string) []string {
+ execScript := "go_" + goEnv("GOOS") + "_" + goEnv("GOARCH") + "_exec"
+ executor, err := exec.LookPath(execScript)
+ if err != nil {
+ return []string{name}
}
+ return []string{executor, name}
}
-func TestInstall(t *testing.T) {
- defer func() {
- os.Remove("libgo.a")
- os.Remove("libgo.h")
- os.Remove("testp")
- os.RemoveAll("pkg")
- }()
-
- cmd := exec.Command("go", "install", "-buildmode=c-archive", "libgo")
+func testInstall(t *testing.T, exe, libgoa, libgoh string, buildcmd ...string) {
+ cmd := exec.Command(buildcmd[0], buildcmd[1:]...)
cmd.Env = gopathEnv
if out, err := cmd.CombinedOutput(); err != nil {
t.Logf("%s", out)
t.Fatal(err)
}
+ defer func() {
+ os.Remove(libgoa)
+ os.Remove(libgoh)
+ }()
- compilemain(t, filepath.Join("pkg", libgodir, "libgo.a"))
-
- binArgs := append(bin, "arg1", "arg2")
- if out, err := exec.Command(binArgs[0], binArgs[1:]...).CombinedOutput(); err != nil {
- t.Logf("%s", out)
- t.Fatal(err)
+ ccArgs := append(cc, "-o", exe, "main.c")
+ if GOOS == "windows" {
+ ccArgs = append(ccArgs, "main_windows.c", libgoa, "-lntdll", "-lws2_32", "-lwinmm")
+ } else {
+ ccArgs = append(ccArgs, "main_unix.c", libgoa)
}
-
- os.Remove("libgo.a")
- os.Remove("libgo.h")
- os.Remove("testp")
-
- // Test building libgo other than installing it.
- // Header files are now present.
- cmd = exec.Command("go", "build", "-buildmode=c-archive", filepath.Join("src", "libgo", "libgo.go"))
- cmd.Env = gopathEnv
- if out, err := cmd.CombinedOutput(); err != nil {
+ t.Log(ccArgs)
+ if out, err := exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput(); err != nil {
t.Logf("%s", out)
t.Fatal(err)
}
+ defer os.Remove(exe)
- compilemain(t, "libgo.a")
-
+ binArgs := append(cmdToRun(exe), "arg1", "arg2")
if out, err := exec.Command(binArgs[0], binArgs[1:]...).CombinedOutput(); err != nil {
t.Logf("%s", out)
t.Fatal(err)
}
+}
- os.Remove("libgo.a")
- os.Remove("libgo.h")
- os.Remove("testp")
+func TestInstall(t *testing.T) {
+ defer os.RemoveAll("pkg")
- cmd = exec.Command("go", "build", "-buildmode=c-archive", "-o", "libgo.a", "libgo")
- cmd.Env = gopathEnv
- if out, err := cmd.CombinedOutput(); err != nil {
- t.Logf("%s", out)
- t.Fatal(err)
- }
+ testInstall(t, "./testp1"+exeSuffix,
+ filepath.Join("pkg", libgodir, "libgo.a"),
+ filepath.Join("pkg", libgodir, "libgo.h"),
+ "go", "install", "-buildmode=c-archive", "libgo")
- compilemain(t, "libgo.a")
+ // Test building libgo other than installing it.
+ // Header files are now present.
+ testInstall(t, "./testp2"+exeSuffix, "libgo.a", "libgo.h",
+ "go", "build", "-buildmode=c-archive", filepath.Join("src", "libgo", "libgo.go"))
- if out, err := exec.Command(binArgs[0], binArgs[1:]...).CombinedOutput(); err != nil {
- t.Logf("%s", out)
- t.Fatal(err)
- }
+ testInstall(t, "./testp3"+exeSuffix, "libgo.a", "libgo.h",
+ "go", "build", "-buildmode=c-archive", "-o", "libgo.a", "libgo")
}
func TestEarlySignalHandler(t *testing.T) {
@@ -282,6 +265,25 @@ func TestSignalForwarding(t *testing.T) {
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()
+
+ 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.SIGPIPE {
+ t.Logf("%s", out)
+ t.Errorf("got %v; expected SIGPIPE", ee)
+ }
}
func TestSignalForwardingExternal(t *testing.T) {
@@ -487,3 +489,71 @@ func TestExtar(t *testing.T) {
}
}
}
+
+func TestPIE(t *testing.T) {
+ switch GOOS {
+ case "windows", "darwin", "plan9":
+ t.Skipf("skipping PIE test on %s", GOOS)
+ }
+
+ defer func() {
+ os.Remove("testp" + exeSuffix)
+ os.RemoveAll("pkg")
+ }()
+
+ cmd := exec.Command("go", "install", "-buildmode=c-archive", "libgo")
+ cmd.Env = gopathEnv
+ if out, err := cmd.CombinedOutput(); err != nil {
+ t.Logf("%s", out)
+ t.Fatal(err)
+ }
+
+ ccArgs := append(cc, "-fPIE", "-pie", "-o", "testp"+exeSuffix, "main.c", "main_unix.c", filepath.Join("pkg", libgodir, "libgo.a"))
+ if out, err := exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput(); err != nil {
+ t.Logf("%s", out)
+ t.Fatal(err)
+ }
+
+ binArgs := append(bin, "arg1", "arg2")
+ if out, err := exec.Command(binArgs[0], binArgs[1:]...).CombinedOutput(); err != nil {
+ t.Logf("%s", out)
+ t.Fatal(err)
+ }
+
+ f, err := elf.Open("testp" + exeSuffix)
+ if err != nil {
+ t.Fatal("elf.Open failed: ", err)
+ }
+ defer f.Close()
+ if hasDynTag(t, f, elf.DT_TEXTREL) {
+ t.Errorf("%s has DT_TEXTREL flag", "testp"+exeSuffix)
+ }
+}
+
+func hasDynTag(t *testing.T, f *elf.File, tag elf.DynTag) bool {
+ ds := f.SectionByType(elf.SHT_DYNAMIC)
+ if ds == nil {
+ t.Error("no SHT_DYNAMIC section")
+ return false
+ }
+ d, err := ds.Data()
+ if err != nil {
+ t.Errorf("can't read SHT_DYNAMIC contents: %v", err)
+ return false
+ }
+ for len(d) > 0 {
+ var t elf.DynTag
+ switch f.Class {
+ case elf.ELFCLASS32:
+ t = elf.DynTag(f.ByteOrder.Uint32(d[:4]))
+ d = d[8:]
+ case elf.ELFCLASS64:
+ t = elf.DynTag(f.ByteOrder.Uint64(d[:8]))
+ d = d[16:]
+ }
+ if t == tag {
+ return true
+ }
+ }
+ return false
+}
diff --git a/misc/cgo/testcarchive/main2.c b/misc/cgo/testcarchive/main2.c
index 3726977..55625c5 100644
--- a/misc/cgo/testcarchive/main2.c
+++ b/misc/cgo/testcarchive/main2.c
@@ -7,14 +7,17 @@
#include <setjmp.h>
#include <signal.h>
+#include <stdarg.h>
#include <stddef.h>
#include <stdio.h>
+#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <sched.h>
#include <time.h>
+#include <errno.h>
#include "libgo2.h"
@@ -24,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) {
@@ -36,6 +40,11 @@ static void recur(int i, char *p) {
}
// Signal handler that uses up more stack space than a goroutine will have.
+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];
@@ -46,11 +55,22 @@ static void ioHandler(int signo, siginfo_t* info, void* ctxt) {
static jmp_buf jmp;
static char* nullPointer;
+// An arbitrary function which requires proper stack alignment; see
+// http://golang.org/issue/17641.
+static void callWithVarargs(void* dummy, ...) {
+ va_list args;
+ va_start(args, dummy);
+ va_end(args);
+}
+
// Signal handler for SIGSEGV on a C thread.
static void segvHandler(int signo, siginfo_t* info, void* ctxt) {
sigset_t mask;
int i;
+ // Call an arbitrary function that requires the stack to be properly aligned.
+ callWithVarargs("dummy arg", 3.1415);
+
if (sigemptyset(&mask) < 0) {
die("sigemptyset");
}
@@ -93,12 +113,17 @@ static void init() {
die("sigaction");
}
+ sa.sa_sigaction = pipeHandler;
+ if (sigaction(SIGPIPE, &sa, NULL) < 0) {
+ die("sigaction");
+ }
}
int main(int argc, char** argv) {
int verbose;
sigset_t mask;
int i;
+ struct timespec ts;
verbose = argc > 1;
setvbuf(stdout, NULL, _IONBF, 0);
@@ -148,12 +173,35 @@ int main(int argc, char** argv) {
// Wait until the signal has been delivered.
i = 0;
while (!sigioSeen) {
- if (sched_yield() < 0) {
- perror("sched_yield");
+ ts.tv_sec = 0;
+ ts.tv_nsec = 1000000;
+ nanosleep(&ts, NULL);
+ i++;
+ if (i > 5000) {
+ 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 > 100000) {
- fprintf(stderr, "looping too long waiting for signal\n");
+ if (i > 1000) {
+ 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 11046d0..07d5d1e 100644
--- a/misc/cgo/testcarchive/main3.c
+++ b/misc/cgo/testcarchive/main3.c
@@ -9,6 +9,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <time.h>
#include <sched.h>
#include "libgo3.h"
@@ -28,11 +29,19 @@ int main(int argc, char** argv) {
int verbose;
struct sigaction sa;
int i;
+ struct timespec ts;
verbose = argc > 2;
setvbuf(stdout, NULL, _IONBF, 0);
if (verbose) {
+ printf("raising SIGPIPE\n");
+ }
+
+ // Test that the Go runtime handles SIGPIPE.
+ ProvokeSIGPIPE();
+
+ if (verbose) {
printf("calling sigaction\n");
}
@@ -64,11 +73,11 @@ int main(int argc, char** argv) {
// Wait until the signal has been delivered.
i = 0;
while (!sigioSeen) {
- if (sched_yield() < 0) {
- perror("sched_yield");
- }
+ ts.tv_sec = 0;
+ ts.tv_nsec = 1000000;
+ nanosleep(&ts, NULL);
i++;
- if (i > 100000) {
+ if (i > 5000) {
fprintf(stderr, "looping too long waiting for signal\n");
exit(EXIT_FAILURE);
}
@@ -138,11 +147,11 @@ int main(int argc, char** argv) {
// Wait until the signal has been delivered.
i = 0;
while (!sigioSeen) {
- if (sched_yield() < 0) {
- perror("sched_yield");
- }
+ ts.tv_sec = 0;
+ ts.tv_nsec = 1000000;
+ nanosleep(&ts, NULL);
i++;
- if (i > 100000) {
+ if (i > 5000) {
fprintf(stderr, "looping too long waiting for signal\n");
exit(EXIT_FAILURE);
}
diff --git a/misc/cgo/testcarchive/main4.c b/misc/cgo/testcarchive/main4.c
index 353f980..4fd55e7 100644
--- a/misc/cgo/testcarchive/main4.c
+++ b/misc/cgo/testcarchive/main4.c
@@ -8,6 +8,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <time.h>
#include <sched.h>
#include <pthread.h>
@@ -48,6 +49,7 @@ static void* thread1(void* arg __attribute__ ((unused))) {
stack_t ss;
int i;
stack_t nss;
+ struct timespec ts;
// Set up an alternate signal stack for this thread.
memset(&ss, 0, sizeof ss);
@@ -73,11 +75,11 @@ static void* thread1(void* arg __attribute__ ((unused))) {
// Wait until the signal has been delivered.
i = 0;
while (SIGIOCount() == 0) {
- if (sched_yield() < 0) {
- perror("sched_yield");
- }
+ ts.tv_sec = 0;
+ ts.tv_nsec = 1000000;
+ nanosleep(&ts, NULL);
i++;
- if (i > 100000) {
+ if (i > 5000) {
fprintf(stderr, "looping too long waiting for signal\n");
exit(EXIT_FAILURE);
}
@@ -105,6 +107,7 @@ static void* thread2(void* arg __attribute__ ((unused))) {
int i;
int oldcount;
pthread_t tid;
+ struct timespec ts;
stack_t nss;
// Set up an alternate signal stack for this thread.
@@ -129,11 +132,11 @@ static void* thread2(void* arg __attribute__ ((unused))) {
// Wait until the signal has been delivered.
i = 0;
while (SIGIOCount() == oldcount) {
- if (sched_yield() < 0) {
- perror("sched_yield");
- }
+ ts.tv_sec = 0;
+ ts.tv_nsec = 1000000;
+ nanosleep(&ts, NULL);
i++;
- if (i > 100000) {
+ if (i > 5000) {
fprintf(stderr, "looping too long waiting for signal\n");
exit(EXIT_FAILURE);
}
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/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..19fcc7f 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/testcshared/main4.c b/misc/cgo/testcshared/main4.c
index fd7b5b3..355cdef 100644
--- a/misc/cgo/testcshared/main4.c
+++ b/misc/cgo/testcshared/main4.c
@@ -77,6 +77,7 @@ int main(int argc, char** argv) {
void (*fn)(void);
sigset_t mask;
int i;
+ struct timespec ts;
verbose = argc > 2;
setvbuf(stdout, NULL, _IONBF, 0);
@@ -166,11 +167,11 @@ int main(int argc, char** argv) {
// Wait until the signal has been delivered.
i = 0;
while (!sigioSeen) {
- if (sched_yield() < 0) {
- perror("sched_yield");
- }
+ ts.tv_sec = 0;
+ ts.tv_nsec = 1000000;
+ nanosleep(&ts, NULL);
i++;
- if (i > 100000) {
+ if (i > 5000) {
fprintf(stderr, "looping too long waiting for signal\n");
exit(EXIT_FAILURE);
}
diff --git a/misc/cgo/testcshared/main5.c b/misc/cgo/testcshared/main5.c
index 97a258f..1bc9910 100644
--- a/misc/cgo/testcshared/main5.c
+++ b/misc/cgo/testcshared/main5.c
@@ -10,6 +10,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <time.h>
#include <sched.h>
#include <dlfcn.h>
@@ -31,6 +32,7 @@ int main(int argc, char** argv) {
void (*fn1)(void);
int (*sawSIGIO)(void);
int i;
+ struct timespec ts;
verbose = argc > 2;
setvbuf(stdout, NULL, _IONBF, 0);
@@ -77,11 +79,11 @@ int main(int argc, char** argv) {
// Wait until the signal has been delivered.
i = 0;
while (!sigioSeen) {
- if (sched_yield() < 0) {
- perror("sched_yield");
- }
+ ts.tv_sec = 0;
+ ts.tv_nsec = 1000000;
+ nanosleep(&ts, NULL);
i++;
- if (i > 100000) {
+ if (i > 5000) {
fprintf(stderr, "looping too long waiting for signal\n");
exit(EXIT_FAILURE);
}
@@ -182,11 +184,11 @@ int main(int argc, char** argv) {
// Wait until the signal has been delivered.
i = 0;
while (!sigioSeen) {
- if (sched_yield() < 0) {
- perror("sched_yield");
- }
+ ts.tv_sec = 0;
+ ts.tv_nsec = 1000000;
+ nanosleep(&ts, NULL);
i++;
- if (i > 100000) {
+ if (i > 5000) {
fprintf(stderr, "looping too long waiting for signal\n");
exit(EXIT_FAILURE);
}
diff --git a/misc/cgo/testcshared/test.bash b/misc/cgo/testcshared/test.bash
index e4bb7d3..052ee0e 100755
--- a/misc/cgo/testcshared/test.bash
+++ b/misc/cgo/testcshared/test.bash
@@ -105,7 +105,7 @@ status=0
# test0: exported symbols in shared lib are accessible.
# TODO(iant): using _shared here shouldn't really be necessary.
-$(go env CC) ${GOGCCFLAGS} -I ${installdir} -o testp main0.c libgo.$libext
+$(go env CC) ${GOGCCFLAGS} -I ${installdir} -o testp main0.c ./libgo.$libext
binpush testp
output=$(run LD_LIBRARY_PATH=. ./testp)
diff --git a/misc/cgo/testgodefs/test.bash b/misc/cgo/testgodefs/test.bash
index 14235c0..a82ff93 100755
--- a/misc/cgo/testgodefs/test.bash
+++ b/misc/cgo/testgodefs/test.bash
@@ -12,7 +12,7 @@ FILE_PREFIXES="anonunion issue8478"
RM=
for FP in $FILE_PREFIXES
do
- go tool cgo -godefs ${FP}.go > ${FP}_defs.go
+ go tool cgo -godefs -srcdir . ${FP}.go > ${FP}_defs.go
RM="${RM} ${FP}_defs.go"
done
diff --git a/misc/cgo/testplugin/altpath/src/common/common.go b/misc/cgo/testplugin/altpath/src/common/common.go
new file mode 100644
index 0000000..505ba02
--- /dev/null
+++ b/misc/cgo/testplugin/altpath/src/common/common.go
@@ -0,0 +1,11 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package common
+
+var X int
+
+func init() {
+ X = 4
+}
diff --git a/misc/cgo/testplugin/altpath/src/plugin-mismatch/main.go b/misc/cgo/testplugin/altpath/src/plugin-mismatch/main.go
new file mode 100644
index 0000000..8aacafc
--- /dev/null
+++ b/misc/cgo/testplugin/altpath/src/plugin-mismatch/main.go
@@ -0,0 +1,17 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+// // No C code required.
+import "C"
+
+// The common package imported here does not match the common package
+// imported by plugin1. A program that attempts to load plugin1 and
+// plugin-mismatch should produce an error.
+import "common"
+
+func ReadCommonX() int {
+ return common.X
+}
diff --git a/misc/cgo/testplugin/src/common/common.go b/misc/cgo/testplugin/src/common/common.go
new file mode 100644
index 0000000..b064e6b
--- /dev/null
+++ b/misc/cgo/testplugin/src/common/common.go
@@ -0,0 +1,11 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package common
+
+var X int
+
+func init() {
+ X = 3
+}
diff --git a/misc/cgo/testplugin/src/host/host.go b/misc/cgo/testplugin/src/host/host.go
new file mode 100644
index 0000000..898f44e
--- /dev/null
+++ b/misc/cgo/testplugin/src/host/host.go
@@ -0,0 +1,148 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "fmt"
+ "log"
+ "path/filepath"
+ "plugin"
+ "strings"
+
+ "common"
+)
+
+func init() {
+ common.X *= 5
+}
+
+// testUnnamed tests that two plugins built with .go files passed on
+// the command line do not have overlapping symbols. That is,
+// unnamed1.so/FuncInt and unnamed2.so/FuncInt should be distinct functions.
+func testUnnamed() {
+ p, err := plugin.Open("unnamed1.so")
+ if err != nil {
+ log.Fatalf(`plugin.Open("unnamed1.so"): %v`, err)
+ }
+ fn, err := p.Lookup("FuncInt")
+ if err != nil {
+ log.Fatalf(`unnamed1.so: Lookup("FuncInt") failed: %v`, err)
+ }
+ if got, want := fn.(func() int)(), 1; got != want {
+ log.Fatalf("unnamed1.so: FuncInt()=%d, want %d", got, want)
+ }
+
+ p, err = plugin.Open("unnamed2.so")
+ if err != nil {
+ log.Fatalf(`plugin.Open("unnamed2.so"): %v`, err)
+ }
+ fn, err = p.Lookup("FuncInt")
+ if err != nil {
+ log.Fatalf(`unnamed2.so: Lookup("FuncInt") failed: %v`, err)
+ }
+ if got, want := fn.(func() int)(), 2; got != want {
+ log.Fatalf("unnamed2.so: FuncInt()=%d, want %d", got, want)
+ }
+}
+
+func main() {
+ if got, want := common.X, 3*5; got != want {
+ log.Fatalf("before plugin load common.X=%d, want %d", got, want)
+ }
+
+ p, err := plugin.Open("plugin1.so")
+ if err != nil {
+ log.Fatalf("plugin.Open failed: %v", err)
+ }
+
+ const wantX = 3 * 5 * 7
+ if got := common.X; got != wantX {
+ log.Fatalf("after plugin load common.X=%d, want %d", got, wantX)
+ }
+
+ seven, err := p.Lookup("Seven")
+ if err != nil {
+ log.Fatalf(`Lookup("Seven") failed: %v`, err)
+ }
+ if got, want := *seven.(*int), 7; got != want {
+ log.Fatalf("plugin1.Seven=%d, want %d", got, want)
+ }
+
+ readFunc, err := p.Lookup("ReadCommonX")
+ if err != nil {
+ log.Fatalf(`plugin1.Lookup("ReadCommonX") failed: %v`, err)
+ }
+ if got := readFunc.(func() int)(); got != wantX {
+ log.Fatalf("plugin1.ReadCommonX()=%d, want %d", got, wantX)
+ }
+
+ // sub/plugin1.so is a different plugin with the same name as
+ // the already loaded plugin. It also depends on common. Test
+ // that we can load the different plugin, it is actually
+ // different, and that it sees the same common package.
+ subpPath, err := filepath.Abs("sub/plugin1.so")
+ if err != nil {
+ log.Fatalf("filepath.Abs(%q) failed: %v", subpPath, err)
+ }
+ subp, err := plugin.Open(subpPath)
+ if err != nil {
+ log.Fatalf("plugin.Open(%q) failed: %v", subpPath, err)
+ }
+
+ funcVar, err := subp.Lookup("FuncVar")
+ if err != nil {
+ log.Fatalf(`sub/plugin1.Lookup("FuncVar") failed: %v`, err)
+ }
+ called := false
+ *funcVar.(*func()) = func() {
+ called = true
+ }
+
+ readFunc, err = subp.Lookup("ReadCommonX")
+ if err != nil {
+ log.Fatalf(`sub/plugin1.Lookup("ReadCommonX") failed: %v`, err)
+ }
+ if got := readFunc.(func() int)(); got != wantX {
+ log.Fatalf("sub/plugin1.ReadCommonX()=%d, want %d", got, wantX)
+ }
+ if !called {
+ log.Fatal("calling ReadCommonX did not call FuncVar")
+ }
+
+ subf, err := subp.Lookup("F")
+ if err != nil {
+ log.Fatalf(`sub/plugin1.Lookup("F") failed: %v`, err)
+ }
+ if gotf := subf.(func() int)(); gotf != 17 {
+ log.Fatalf(`sub/plugin1.F()=%d, want 17`, gotf)
+ }
+ f, err := p.Lookup("F")
+ if err != nil {
+ log.Fatalf(`plugin1.Lookup("F") failed: %v`, err)
+ }
+ if gotf := f.(func() int)(); gotf != 3 {
+ log.Fatalf(`plugin1.F()=%d, want 17`, gotf)
+ }
+
+ // plugin2 has no exported symbols, only an init function.
+ if _, err := plugin.Open("plugin2.so"); err != nil {
+ log.Fatalf("plugin.Open failed: %v", err)
+ }
+ if got, want := common.X, 2; got != want {
+ log.Fatalf("after loading plugin2, common.X=%d, want %d", got, want)
+ }
+
+ _, err = plugin.Open("plugin-mismatch.so")
+ if err == nil {
+ log.Fatal(`plugin.Open("plugin-mismatch.so"): should have failed`)
+ }
+ if s := err.Error(); !strings.Contains(s, "different version") {
+ log.Fatalf(`plugin.Open("plugin-mismatch.so"): error does not mention "different version": %v`, s)
+ }
+
+ testUnnamed()
+
+ fmt.Println("PASS")
+}
diff --git a/misc/cgo/testplugin/src/plugin1/plugin1.go b/misc/cgo/testplugin/src/plugin1/plugin1.go
new file mode 100644
index 0000000..7a62242
--- /dev/null
+++ b/misc/cgo/testplugin/src/plugin1/plugin1.go
@@ -0,0 +1,35 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+// // No C code required.
+import "C"
+
+import "common"
+
+func F() int { return 3 }
+
+func ReadCommonX() int {
+ return common.X
+}
+
+var Seven int
+
+func call(fn func()) {
+ fn()
+}
+
+func g() {
+ common.X *= Seven
+}
+
+func init() {
+ Seven = 7
+ call(g)
+}
+
+func main() {
+ panic("plugin1.main called")
+}
diff --git a/misc/cgo/testplugin/src/plugin2/plugin2.go b/misc/cgo/testplugin/src/plugin2/plugin2.go
new file mode 100644
index 0000000..6c23a5e
--- /dev/null
+++ b/misc/cgo/testplugin/src/plugin2/plugin2.go
@@ -0,0 +1,18 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+// // No C code required.
+import "C"
+
+import "common"
+
+func init() {
+ common.X = 2
+}
+
+func main() {
+ panic("plugin1.main called")
+}
diff --git a/misc/cgo/testplugin/src/sub/plugin1/plugin1.go b/misc/cgo/testplugin/src/sub/plugin1/plugin1.go
new file mode 100644
index 0000000..cf9000c
--- /dev/null
+++ b/misc/cgo/testplugin/src/sub/plugin1/plugin1.go
@@ -0,0 +1,23 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+// // No C code required.
+import "C"
+
+import "common"
+
+func F() int { return 17 }
+
+var FuncVar = func() {}
+
+func ReadCommonX() int {
+ FuncVar()
+ return common.X
+}
+
+func main() {
+ panic("plugin1.main called")
+}
diff --git a/misc/cgo/testplugin/test.bash b/misc/cgo/testplugin/test.bash
new file mode 100755
index 0000000..fee99a7
--- /dev/null
+++ b/misc/cgo/testplugin/test.bash
@@ -0,0 +1,34 @@
+#!/usr/bin/env bash
+# Copyright 2016 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+set -e
+
+if [ ! -f src/host/host.go ]; then
+ cwd=$(pwd)
+ echo "misc/cgo/testplugin/test.bash is running in $cwd" 1>&2
+ exit 1
+fi
+
+goos=$(go env GOOS)
+goarch=$(go env GOARCH)
+
+function cleanup() {
+ rm -f plugin*.so unnamed*.so
+ rm -rf host pkg sub
+}
+trap cleanup EXIT
+
+rm -rf pkg sub
+mkdir sub
+
+GOPATH=$(pwd) go build -buildmode=plugin plugin1
+GOPATH=$(pwd) go build -buildmode=plugin plugin2
+GOPATH=$(pwd)/altpath go build -buildmode=plugin plugin-mismatch
+GOPATH=$(pwd) go build -buildmode=plugin -o=sub/plugin1.so sub/plugin1
+GOPATH=$(pwd) go build -buildmode=plugin unnamed1.go
+GOPATH=$(pwd) go build -buildmode=plugin unnamed2.go
+GOPATH=$(pwd) go build host
+
+LD_LIBRARY_PATH=$(pwd) ./host
diff --git a/misc/cgo/testplugin/unnamed1.go b/misc/cgo/testplugin/unnamed1.go
new file mode 100644
index 0000000..102edaf
--- /dev/null
+++ b/misc/cgo/testplugin/unnamed1.go
@@ -0,0 +1,12 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+// // No C code required.
+import "C"
+
+func FuncInt() int { return 1 }
+
+func main() {}
diff --git a/misc/cgo/testplugin/unnamed2.go b/misc/cgo/testplugin/unnamed2.go
new file mode 100644
index 0000000..55070d5
--- /dev/null
+++ b/misc/cgo/testplugin/unnamed2.go
@@ -0,0 +1,12 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+// // No C code required.
+import "C"
+
+func FuncInt() int { return 2 }
+
+func main() {}
diff --git a/misc/cgo/testsanitizers/msan5.go b/misc/cgo/testsanitizers/msan5.go
new file mode 100644
index 0000000..f1479eb
--- /dev/null
+++ b/misc/cgo/testsanitizers/msan5.go
@@ -0,0 +1,57 @@
+// Copyright 2016 The Go Authors. 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
+
+// Using reflect to set a value was not seen by msan.
+
+/*
+#include <stdlib.h>
+
+extern void Go1(int*);
+extern void Go2(char*);
+
+// Use weak as a hack to permit defining a function even though we use export.
+void C1() __attribute__ ((weak));
+void C2() __attribute__ ((weak));
+
+void C1() {
+ int i;
+ Go1(&i);
+ if (i != 42) {
+ abort();
+ }
+}
+
+void C2() {
+ char a[2];
+ a[1] = 42;
+ Go2(a);
+ if (a[0] != 42) {
+ abort();
+ }
+}
+*/
+import "C"
+
+import (
+ "reflect"
+ "unsafe"
+)
+
+//export Go1
+func Go1(p *C.int) {
+ reflect.ValueOf(p).Elem().Set(reflect.ValueOf(C.int(42)))
+}
+
+//export Go2
+func Go2(p *C.char) {
+ a := (*[2]byte)(unsafe.Pointer(p))
+ reflect.Copy(reflect.ValueOf(a[:1]), reflect.ValueOf(a[1:]))
+}
+
+func main() {
+ C.C1()
+ C.C2()
+}
diff --git a/misc/cgo/testsanitizers/test.bash b/misc/cgo/testsanitizers/test.bash
index 78747d1..01cce95 100755
--- a/misc/cgo/testsanitizers/test.bash
+++ b/misc/cgo/testsanitizers/test.bash
@@ -15,6 +15,11 @@ if test -x "$(type -p clang)"; then
fi
export CC
+if [ "$(sysctl -n vm.overcommit_memory)" = 2 ]; then
+ echo "skipping msan/tsan tests: vm.overcommit_memory=2" >&2
+ exit 0
+fi
+
msan=yes
TMPDIR=${TMPDIR:-/tmp}
@@ -88,6 +93,11 @@ if test "$msan" = "yes"; then
status=1
fi
+ if ! go run -msan msan5.go; then
+ echo "FAIL: msan5"
+ status=1
+ fi
+
if go run -msan msan_fail.go 2>/dev/null; then
echo "FAIL: msan_fail"
status=1
@@ -134,6 +144,7 @@ if test "$tsan" = "yes"; then
testtsan tsan2.go
testtsan tsan3.go
testtsan tsan4.go
+ testtsan tsan8.go
# These tests are only reliable using clang or GCC version 7 or later.
# Otherwise runtime/cgo/libcgo.h can't tell whether TSAN is in use.
@@ -156,6 +167,9 @@ if test "$tsan" = "yes"; then
# 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"
fi
fi
diff --git a/misc/cgo/testsanitizers/tsan7.go b/misc/cgo/testsanitizers/tsan7.go
new file mode 100644
index 0000000..2fb9e45
--- /dev/null
+++ b/misc/cgo/testsanitizers/tsan7.go
@@ -0,0 +1,40 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+// Setting an environment variable in a cgo program changes the C
+// environment. Test that this does not confuse the race detector.
+
+/*
+#cgo CFLAGS: -fsanitize=thread
+#cgo LDFLAGS: -fsanitize=thread
+*/
+import "C"
+
+import (
+ "fmt"
+ "os"
+ "sync"
+ "time"
+)
+
+func main() {
+ var wg sync.WaitGroup
+ var mu sync.Mutex
+ f := func() {
+ defer wg.Done()
+ for i := 0; i < 100; i++ {
+ time.Sleep(time.Microsecond)
+ mu.Lock()
+ s := fmt.Sprint(i)
+ os.Setenv("TSAN_TEST"+s, s)
+ mu.Unlock()
+ }
+ }
+ wg.Add(2)
+ go f()
+ go f()
+ wg.Wait()
+}
diff --git a/misc/cgo/testsanitizers/tsan8.go b/misc/cgo/testsanitizers/tsan8.go
new file mode 100644
index 0000000..88d82a6
--- /dev/null
+++ b/misc/cgo/testsanitizers/tsan8.go
@@ -0,0 +1,60 @@
+// Copyright 2016 The Go Authors. 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 when run under the C/C++ ThreadSanitizer. The TSAN
+// sigaction function interceptor returned SIG_DFL instead of the Go runtime's
+// handler in registerSegvForwarder.
+
+/*
+#cgo CFLAGS: -fsanitize=thread
+#cgo LDFLAGS: -fsanitize=thread
+
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+struct sigaction prev_sa;
+
+void forwardSignal(int signo, siginfo_t *info, void *context) {
+ // One of sa_sigaction and/or sa_handler
+ if ((prev_sa.sa_flags&SA_SIGINFO) != 0) {
+ prev_sa.sa_sigaction(signo, info, context);
+ return;
+ }
+ if (prev_sa.sa_handler != SIG_IGN && prev_sa.sa_handler != SIG_DFL) {
+ prev_sa.sa_handler(signo);
+ return;
+ }
+
+ fprintf(stderr, "No Go handler to forward to!\n");
+ abort();
+}
+
+void registerSegvFowarder() {
+ struct sigaction sa;
+ memset(&sa, 0, sizeof(sa));
+ sigemptyset(&sa.sa_mask);
+ sa.sa_flags = SA_SIGINFO | SA_ONSTACK;
+ sa.sa_sigaction = forwardSignal;
+
+ if (sigaction(SIGSEGV, &sa, &prev_sa) != 0) {
+ perror("failed to register SEGV forwarder");
+ exit(EXIT_FAILURE);
+ }
+}
+*/
+import "C"
+
+func main() {
+ C.registerSegvFowarder()
+
+ defer func() {
+ recover()
+ }()
+ var nilp *int
+ *nilp = 42
+}
diff --git a/misc/cgo/testshared/shared_test.go b/misc/cgo/testshared/shared_test.go
index 34d97de..af4f915 100644
--- a/misc/cgo/testshared/shared_test.go
+++ b/misc/cgo/testshared/shared_test.go
@@ -43,7 +43,7 @@ func run(t *testing.T, msg string, args ...string) {
}
// goCmd invokes the go tool with the installsuffix set up by TestMain. It calls
-// t.Errorf if the command fails.
+// t.Fatalf if the command fails.
func goCmd(t *testing.T, args ...string) {
newargs := []string{args[0], "-installsuffix=" + suffix}
if testing.Verbose() {
@@ -63,7 +63,7 @@ func goCmd(t *testing.T, args ...string) {
}
if err != nil {
if t != nil {
- t.Errorf("executing %s failed %v:\n%s", strings.Join(c.Args, " "), err, output)
+ t.Fatalf("executing %s failed %v:\n%s", strings.Join(c.Args, " "), err, output)
} else {
log.Fatalf("executing %s failed %v:\n%s", strings.Join(c.Args, " "), err, output)
}
@@ -97,6 +97,9 @@ func testMain(m *testing.M) (int, error) {
if gorootInstallDir == "" {
return 0, errors.New("could not create temporary directory after 10000 tries")
}
+ if testing.Verbose() {
+ fmt.Printf("+ mkdir -p %s\n", gorootInstallDir)
+ }
defer os.RemoveAll(gorootInstallDir)
// Some tests need to edit the source in GOPATH, so copy this directory to a
@@ -105,6 +108,9 @@ func testMain(m *testing.M) (int, error) {
if err != nil {
return 0, fmt.Errorf("TempDir failed: %v", err)
}
+ if testing.Verbose() {
+ fmt.Printf("+ mkdir -p %s\n", scratchDir)
+ }
defer os.RemoveAll(scratchDir)
err = filepath.Walk(".", func(path string, info os.FileInfo, err error) error {
scratchPath := filepath.Join(scratchDir, path)
@@ -112,12 +118,18 @@ func testMain(m *testing.M) (int, error) {
if path == "." {
return nil
}
+ if testing.Verbose() {
+ fmt.Printf("+ mkdir -p %s\n", scratchPath)
+ }
return os.Mkdir(scratchPath, info.Mode())
} else {
fromBytes, err := ioutil.ReadFile(path)
if err != nil {
return err
}
+ if testing.Verbose() {
+ fmt.Printf("+ cp %s %s\n", path, scratchPath)
+ }
return ioutil.WriteFile(scratchPath, fromBytes, info.Mode())
}
})
@@ -125,7 +137,13 @@ func testMain(m *testing.M) (int, error) {
return 0, fmt.Errorf("walk failed: %v", err)
}
os.Setenv("GOPATH", scratchDir)
+ if testing.Verbose() {
+ fmt.Printf("+ export GOPATH=%s\n", scratchDir)
+ }
myContext.GOPATH = scratchDir
+ if testing.Verbose() {
+ fmt.Printf("+ cd %s\n", scratchDir)
+ }
os.Chdir(scratchDir)
// All tests depend on runtime being built into a shared library. Because
@@ -376,6 +394,14 @@ func TestTrivialExecutable(t *testing.T) {
AssertHasRPath(t, "./bin/trivial", gorootInstallDir)
}
+// Build a trivial program in PIE mode that links against the shared runtime and check it runs.
+func TestTrivialExecutablePIE(t *testing.T) {
+ goCmd(t, "build", "-buildmode=pie", "-o", "trivial.pie", "-linkshared", "trivial")
+ run(t, "trivial executable", "./trivial.pie")
+ AssertIsLinkedTo(t, "./trivial.pie", soname)
+ AssertHasRPath(t, "./trivial.pie", gorootInstallDir)
+}
+
// Build an executable that uses cgo linked against the shared runtime and check it
// runs.
func TestCgoExecutable(t *testing.T) {
diff --git a/misc/cgo/testshared/src/depBase/dep.go b/misc/cgo/testshared/src/depBase/dep.go
index c3ae96f..a518b4e 100644
--- a/misc/cgo/testshared/src/depBase/dep.go
+++ b/misc/cgo/testshared/src/depBase/dep.go
@@ -1,5 +1,10 @@
package depBase
+import (
+ "os"
+ "reflect"
+)
+
var V int = 1
var HasMask []string = []string{"hi"}
@@ -13,6 +18,10 @@ type Dep struct {
}
func (d *Dep) Method() int {
+ // This code below causes various go.itab.* symbols to be generated in
+ // the shared library. Similar code in ../exe/exe.go results in
+ // exercising https://github.com/golang/go/issues/17594
+ reflect.TypeOf(os.Stdout).Elem()
return 10
}
diff --git a/misc/cgo/testshared/src/exe/exe.go b/misc/cgo/testshared/src/exe/exe.go
index 136803f..31fbedd 100644
--- a/misc/cgo/testshared/src/exe/exe.go
+++ b/misc/cgo/testshared/src/exe/exe.go
@@ -2,11 +2,17 @@ package main
import (
"depBase"
+ "os"
+ "reflect"
"runtime"
)
func main() {
defer depBase.ImplementedInAsm()
+ // This code below causes various go.itab.* symbols to be generated in
+ // the executable. Similar code in ../depBase/dep.go results in
+ // exercising https://github.com/golang/go/issues/17594
+ reflect.TypeOf(os.Stdout).Elem()
runtime.GC()
depBase.V = depBase.F() + 1
}
diff --git a/misc/cgo/testsigfwd/main.go b/misc/cgo/testsigfwd/main.go
index d5fbf50..61bd0da 100644
--- a/misc/cgo/testsigfwd/main.go
+++ b/misc/cgo/testsigfwd/main.go
@@ -50,6 +50,7 @@ static void iohandler(int signum) {
static void* sigioThread(void* arg __attribute__ ((unused))) {
raise(SIGIO);
+ return NULL;
}
static void sigioOnThread() {
diff --git a/misc/nacl/testzip.proto b/misc/nacl/testzip.proto
index 8a8784c..561df80 100644
--- a/misc/nacl/testzip.proto
+++ b/misc/nacl/testzip.proto
@@ -18,6 +18,10 @@ go src=..
asm
testdata
+
+ compile
+ internal
+ syntax
+ parser.go
doc
main.go
pkg.go
@@ -44,6 +48,10 @@ go src=..
x86asm
testdata
+
+ ppc64
+ ppc64asm
+ testdata
+ +
archive
tar
testdata
diff --git a/src/androidtest.bash b/src/androidtest.bash
index 823b83b..3ac56d1 100755
--- a/src/androidtest.bash
+++ b/src/androidtest.bash
@@ -30,6 +30,10 @@ if [ "$GOARM" != "7" ]; then
echo "android only supports GOARM=7, got GOARM=$GOARM" 1>&2
exit 1
fi
+if [ "$GOARCH" = "" ]; then
+ echo "GOARCH must be set" 1>&2
+ exit 1
+fi
export CGO_ENABLED=1
unset GOBIN
@@ -43,6 +47,12 @@ GOOS=$GOHOSTOS GOARCH=$GOHOSTARCH go build \
-o ../bin/go_android_${GOARCH}_exec \
../misc/android/go_android_exec.go
+export pkgdir=$(dirname $(go list -f '{{.Target}}' runtime))
+if [ "$pkgdir" = "" ]; then
+ echo "could not find android pkg dir" 1>&2
+ exit 1
+fi
+
export ANDROID_TEST_DIR=/tmp/androidtest-$$
function cleanup() {
@@ -64,15 +74,7 @@ mkdir -p $FAKE_GOROOT/pkg
cp -a "${GOROOT}/src" "${FAKE_GOROOT}/"
cp -a "${GOROOT}/test" "${FAKE_GOROOT}/"
cp -a "${GOROOT}/lib" "${FAKE_GOROOT}/"
-
-# For android, the go tool will install the compiled package in
-# pkg/android_${GOARCH}_shared directory by default, not in
-# the usual pkg/${GOOS}_${GOARCH}. Some tests in src/go/* assume
-# the compiled packages were installed in the usual places.
-# Instead of reflecting this exception into the go/* packages,
-# we copy the compiled packages into the usual places.
-cp -a "${GOROOT}/pkg/android_${GOARCH}_shared" "${FAKE_GOROOT}/pkg/"
-mv "${FAKE_GOROOT}/pkg/android_${GOARCH}_shared" "${FAKE_GOROOT}/pkg/android_${GOARCH}"
+cp -a "${pkgdir}" "${FAKE_GOROOT}/pkg/"
echo '# Syncing test files to android device'
adb shell mkdir -p /data/local/tmp/goroot
diff --git a/src/archive/tar/common.go b/src/archive/tar/common.go
index 2a1e432..d2ae66d 100644
--- a/src/archive/tar/common.go
+++ b/src/archive/tar/common.go
@@ -13,7 +13,6 @@
package tar
import (
- "bytes"
"errors"
"fmt"
"os"
@@ -21,6 +20,10 @@ import (
"time"
)
+// BUG: Use of the Uid and Gid fields in Header could overflow on 32-bit
+// architectures. If a large value is encountered when decoding, the result
+// stored in Header will be the truncated version.
+
// Header type flags.
const (
TypeReg = '0' // regular file
@@ -271,28 +274,6 @@ func FileInfoHeader(fi os.FileInfo, link string) (*Header, error) {
return h, nil
}
-func isASCII(s string) bool {
- for _, c := range s {
- if c >= 0x80 {
- return false
- }
- }
- return true
-}
-
-func toASCII(s string) string {
- if isASCII(s) {
- return s
- }
- var buf bytes.Buffer
- for _, c := range s {
- if c < 0x80 {
- buf.WriteByte(byte(c))
- }
- }
- return buf.String()
-}
-
// isHeaderOnlyType checks if the given type flag is of the type that has no
// data section even if a size is specified.
func isHeaderOnlyType(flag byte) bool {
diff --git a/src/archive/tar/reader.go b/src/archive/tar/reader.go
index 096ef08..9abe888 100644
--- a/src/archive/tar/reader.go
+++ b/src/archive/tar/reader.go
@@ -22,22 +22,20 @@ var (
ErrHeader = errors.New("archive/tar: invalid tar header")
)
-const maxNanoSecondIntSize = 9
-
// A Reader provides sequential access to the contents of a tar archive.
// A tar archive consists of a sequence of files.
// The Next method advances to the next file in the archive (including the first),
// and then it can be treated as an io.Reader to access the file's data.
type Reader struct {
r io.Reader
- err error
pad int64 // amount of padding (ignored) after current file entry
curr numBytesReader // reader for current file entry
blk block // buffer to use as temporary local storage
-}
-type parser struct {
- err error // Last error seen
+ // err is a persistent error.
+ // It is only the responsibility of every exported method of Reader to
+ // ensure that this error is sticky.
+ err error
}
// A numBytesReader is an io.Reader with a numBytes method, returning the number
@@ -108,8 +106,12 @@ func (tr *Reader) Next() (*Header, error) {
if tr.err != nil {
return nil, tr.err
}
+ hdr, err := tr.next()
+ tr.err = err
+ return hdr, err
+}
- var hdr *Header
+func (tr *Reader) next() (*Header, error) {
var extHdrs map[string]string
// Externally, Next iterates through the tar archive as if it is a series of
@@ -119,29 +121,29 @@ func (tr *Reader) Next() (*Header, error) {
// one or more "header files" until it finds a "normal file".
loop:
for {
- tr.err = tr.skipUnread()
- if tr.err != nil {
- return nil, tr.err
+ if err := tr.skipUnread(); err != nil {
+ return nil, err
}
-
- hdr = tr.readHeader()
- if tr.err != nil {
- return nil, tr.err
+ hdr, rawHdr, err := tr.readHeader()
+ if err != nil {
+ return nil, err
+ }
+ if err := tr.handleRegularFile(hdr); err != nil {
+ return nil, err
}
// Check for PAX/GNU special headers and files.
switch hdr.Typeflag {
case TypeXHeader:
- extHdrs, tr.err = parsePAX(tr)
- if tr.err != nil {
- return nil, tr.err
+ extHdrs, err = parsePAX(tr)
+ if err != nil {
+ return nil, err
}
continue loop // This is a meta header affecting the next header
case TypeGNULongName, TypeGNULongLink:
- var realname []byte
- realname, tr.err = ioutil.ReadAll(tr)
- if tr.err != nil {
- return nil, tr.err
+ realname, err := ioutil.ReadAll(tr)
+ if err != nil {
+ return nil, err
}
// Convert GNU extensions to use PAX headers.
@@ -156,31 +158,73 @@ loop:
extHdrs[paxLinkpath] = p.parseString(realname)
}
if p.err != nil {
- tr.err = p.err
- return nil, tr.err
+ return nil, p.err
}
continue loop // This is a meta header affecting the next header
default:
- mergePAX(hdr, extHdrs)
+ // The old GNU sparse format is handled here since it is technically
+ // just a regular file with additional attributes.
- // Check for a PAX format sparse file
- sp, err := tr.checkForGNUSparsePAXHeaders(hdr, extHdrs)
- if err != nil {
- tr.err = err
+ if err := mergePAX(hdr, extHdrs); err != nil {
return nil, err
}
- if sp != nil {
- // Current file is a PAX format GNU sparse file.
- // Set the current file reader to a sparse file reader.
- tr.curr, tr.err = newSparseFileReader(tr.curr, sp, hdr.Size)
- if tr.err != nil {
- return nil, tr.err
- }
+
+ // The extended headers may have updated the size.
+ // Thus, setup the regFileReader again after merging PAX headers.
+ if err := tr.handleRegularFile(hdr); err != nil {
+ return nil, err
+ }
+
+ // Sparse formats rely on being able to read from the logical data
+ // section; there must be a preceding call to handleRegularFile.
+ if err := tr.handleSparseFile(hdr, rawHdr, extHdrs); err != nil {
+ return nil, err
}
- break loop // This is a file, so stop
+ return hdr, nil // This is a file, so stop
+ }
+ }
+}
+
+// handleRegularFile sets up the current file reader and padding such that it
+// can only read the following logical data section. It will properly handle
+// special headers that contain no data section.
+func (tr *Reader) handleRegularFile(hdr *Header) error {
+ nb := hdr.Size
+ if isHeaderOnlyType(hdr.Typeflag) {
+ nb = 0
+ }
+ if nb < 0 {
+ return ErrHeader
+ }
+
+ tr.pad = -nb & (blockSize - 1) // blockSize is a power of two
+ tr.curr = ®FileReader{r: tr.r, nb: nb}
+ return nil
+}
+
+// handleSparseFile checks if the current file is a sparse format of any type
+// and sets the curr reader appropriately.
+func (tr *Reader) handleSparseFile(hdr *Header, rawHdr *block, extHdrs map[string]string) error {
+ var sp []sparseEntry
+ var err error
+ if hdr.Typeflag == TypeGNUSparse {
+ sp, err = tr.readOldGNUSparseMap(hdr, rawHdr)
+ if err != nil {
+ return err
+ }
+ } else {
+ sp, err = tr.checkForGNUSparsePAXHeaders(hdr, extHdrs)
+ if err != nil {
+ return err
}
}
- return hdr, nil
+
+ // If sp is non-nil, then this is a sparse file.
+ // Note that it is possible for len(sp) to be zero.
+ if sp != nil {
+ tr.curr, err = newSparseFileReader(tr.curr, sp, hdr.Size)
+ }
+ return err
}
// checkForGNUSparsePAXHeaders checks the PAX headers for GNU sparse headers. If they are found, then
@@ -219,13 +263,13 @@ func (tr *Reader) checkForGNUSparsePAXHeaders(hdr *Header, headers map[string]st
hdr.Name = sparseName
}
if sparseSizeOk {
- realSize, err := strconv.ParseInt(sparseSize, 10, 0)
+ realSize, err := strconv.ParseInt(sparseSize, 10, 64)
if err != nil {
return nil, ErrHeader
}
hdr.Size = realSize
} else if sparseRealSizeOk {
- realSize, err := strconv.ParseInt(sparseRealSize, 10, 0)
+ realSize, err := strconv.ParseInt(sparseRealSize, 10, 64)
if err != nil {
return nil, ErrHeader
}
@@ -249,53 +293,32 @@ func (tr *Reader) checkForGNUSparsePAXHeaders(hdr *Header, headers map[string]st
// in the header struct overwrite those found in the header
// struct with higher precision or longer values. Esp. useful
// for name and linkname fields.
-func mergePAX(hdr *Header, headers map[string]string) error {
+func mergePAX(hdr *Header, headers map[string]string) (err error) {
+ var id64 int64
for k, v := range headers {
switch k {
case paxPath:
hdr.Name = v
case paxLinkpath:
hdr.Linkname = v
- case paxGname:
- hdr.Gname = v
case paxUname:
hdr.Uname = v
+ case paxGname:
+ hdr.Gname = v
case paxUid:
- uid, err := strconv.ParseInt(v, 10, 0)
- if err != nil {
- return err
- }
- hdr.Uid = int(uid)
+ id64, err = strconv.ParseInt(v, 10, 64)
+ hdr.Uid = int(id64) // Integer overflow possible
case paxGid:
- gid, err := strconv.ParseInt(v, 10, 0)
- if err != nil {
- return err
- }
- hdr.Gid = int(gid)
+ id64, err = strconv.ParseInt(v, 10, 64)
+ hdr.Gid = int(id64) // Integer overflow possible
case paxAtime:
- t, err := parsePAXTime(v)
- if err != nil {
- return err
- }
- hdr.AccessTime = t
+ hdr.AccessTime, err = parsePAXTime(v)
case paxMtime:
- t, err := parsePAXTime(v)
- if err != nil {
- return err
- }
- hdr.ModTime = t
+ hdr.ModTime, err = parsePAXTime(v)
case paxCtime:
- t, err := parsePAXTime(v)
- if err != nil {
- return err
- }
- hdr.ChangeTime = t
+ hdr.ChangeTime, err = parsePAXTime(v)
case paxSize:
- size, err := strconv.ParseInt(v, 10, 0)
- if err != nil {
- return err
- }
- hdr.Size = size
+ hdr.Size, err = strconv.ParseInt(v, 10, 64)
default:
if strings.HasPrefix(k, paxXattr) {
if hdr.Xattrs == nil {
@@ -304,44 +327,11 @@ func mergePAX(hdr *Header, headers map[string]string) error {
hdr.Xattrs[k[len(paxXattr):]] = v
}
}
- }
- return nil
-}
-
-// parsePAXTime takes a string of the form %d.%d as described in
-// the PAX specification.
-func parsePAXTime(t string) (time.Time, error) {
- buf := []byte(t)
- pos := bytes.IndexByte(buf, '.')
- var seconds, nanoseconds int64
- var err error
- if pos == -1 {
- seconds, err = strconv.ParseInt(t, 10, 0)
- if err != nil {
- return time.Time{}, err
- }
- } else {
- seconds, err = strconv.ParseInt(string(buf[:pos]), 10, 0)
- if err != nil {
- return time.Time{}, err
- }
- nanoBuf := string(buf[pos+1:])
- // Pad as needed before converting to a decimal.
- // For example .030 -> .030000000 -> 30000000 nanoseconds
- if len(nanoBuf) < maxNanoSecondIntSize {
- // Right pad
- nanoBuf += strings.Repeat("0", maxNanoSecondIntSize-len(nanoBuf))
- } else if len(nanoBuf) > maxNanoSecondIntSize {
- // Right truncate
- nanoBuf = nanoBuf[:maxNanoSecondIntSize]
- }
- nanoseconds, err = strconv.ParseInt(nanoBuf, 10, 0)
if err != nil {
- return time.Time{}, err
+ return ErrHeader
}
}
- ts := time.Unix(seconds, nanoseconds)
- return ts, nil
+ return nil
}
// parsePAX parses PAX headers.
@@ -354,12 +344,11 @@ func parsePAX(r io.Reader) (map[string]string, error) {
sbuf := string(buf)
// For GNU PAX sparse format 0.0 support.
- // This function transforms the sparse format 0.0 headers into sparse format 0.1 headers.
- var sparseMap bytes.Buffer
+ // This function transforms the sparse format 0.0 headers into format 0.1
+ // headers since 0.0 headers were not PAX compliant.
+ var sparseMap []string
- headers := make(map[string]string)
- // Each record is constructed as
- // "%d %s=%s\n", length, keyword, value
+ extHdrs := make(map[string]string)
for len(sbuf) > 0 {
key, value, residual, err := parsePAXRecord(sbuf)
if err != nil {
@@ -367,127 +356,29 @@ func parsePAX(r io.Reader) (map[string]string, error) {
}
sbuf = residual
- keyStr := key
- if keyStr == paxGNUSparseOffset || keyStr == paxGNUSparseNumBytes {
- // GNU sparse format 0.0 special key. Write to sparseMap instead of using the headers map.
- sparseMap.WriteString(value)
- sparseMap.Write([]byte{','})
- } else {
- // Normal key. Set the value in the headers map.
- headers[keyStr] = value
- }
- }
- if sparseMap.Len() != 0 {
- // Add sparse info to headers, chopping off the extra comma
- sparseMap.Truncate(sparseMap.Len() - 1)
- headers[paxGNUSparseMap] = sparseMap.String()
- }
- return headers, nil
-}
-
-// parsePAXRecord parses the input PAX record string into a key-value pair.
-// If parsing is successful, it will slice off the currently read record and
-// return the remainder as r.
-//
-// A PAX record is of the following form:
-// "%d %s=%s\n" % (size, key, value)
-func parsePAXRecord(s string) (k, v, r string, err error) {
- // The size field ends at the first space.
- sp := strings.IndexByte(s, ' ')
- if sp == -1 {
- return "", "", s, ErrHeader
- }
-
- // Parse the first token as a decimal integer.
- n, perr := strconv.ParseInt(s[:sp], 10, 0) // Intentionally parse as native int
- if perr != nil || n < 5 || int64(len(s)) < n {
- return "", "", s, ErrHeader
- }
-
- // Extract everything between the space and the final newline.
- rec, nl, rem := s[sp+1:n-1], s[n-1:n], s[n:]
- if nl != "\n" {
- return "", "", s, ErrHeader
- }
-
- // The first equals separates the key from the value.
- eq := strings.IndexByte(rec, '=')
- if eq == -1 {
- return "", "", s, ErrHeader
- }
- return rec[:eq], rec[eq+1:], rem, nil
-}
-
-// parseString parses bytes as a NUL-terminated C-style string.
-// If a NUL byte is not found then the whole slice is returned as a string.
-func (*parser) parseString(b []byte) string {
- n := 0
- for n < len(b) && b[n] != 0 {
- n++
- }
- return string(b[0:n])
-}
-
-// parseNumeric parses the input as being encoded in either base-256 or octal.
-// This function may return negative numbers.
-// If parsing fails or an integer overflow occurs, err will be set.
-func (p *parser) parseNumeric(b []byte) int64 {
- // Check for base-256 (binary) format first.
- // If the first bit is set, then all following bits constitute a two's
- // complement encoded number in big-endian byte order.
- if len(b) > 0 && b[0]&0x80 != 0 {
- // Handling negative numbers relies on the following identity:
- // -a-1 == ^a
- //
- // If the number is negative, we use an inversion mask to invert the
- // data bytes and treat the value as an unsigned number.
- var inv byte // 0x00 if positive or zero, 0xff if negative
- if b[0]&0x40 != 0 {
- inv = 0xff
- }
-
- var x uint64
- for i, c := range b {
- c ^= inv // Inverts c only if inv is 0xff, otherwise does nothing
- if i == 0 {
- c &= 0x7f // Ignore signal bit in first byte
+ switch key {
+ case paxGNUSparseOffset, paxGNUSparseNumBytes:
+ // Validate sparse header order and value.
+ if (len(sparseMap)%2 == 0 && key != paxGNUSparseOffset) ||
+ (len(sparseMap)%2 == 1 && key != paxGNUSparseNumBytes) ||
+ strings.Contains(value, ",") {
+ return nil, ErrHeader
}
- if (x >> 56) > 0 {
- p.err = ErrHeader // Integer overflow
- return 0
+ sparseMap = append(sparseMap, value)
+ default:
+ // According to PAX specification, a value is stored only if it is
+ // non-empty. Otherwise, the key is deleted.
+ if len(value) > 0 {
+ extHdrs[key] = value
+ } else {
+ delete(extHdrs, key)
}
- x = x<<8 | uint64(c)
- }
- if (x >> 63) > 0 {
- p.err = ErrHeader // Integer overflow
- return 0
}
- if inv == 0xff {
- return ^int64(x)
- }
- return int64(x)
- }
-
- // Normal case is base-8 (octal) format.
- return p.parseOctal(b)
-}
-
-func (p *parser) parseOctal(b []byte) int64 {
- // Because unused fields are filled with NULs, we need
- // to skip leading NULs. Fields may also be padded with
- // spaces or NULs.
- // So we remove leading and trailing NULs and spaces to
- // be sure.
- b = bytes.Trim(b, " \x00")
-
- if len(b) == 0 {
- return 0
}
- x, perr := strconv.ParseUint(p.parseString(b), 8, 64)
- if perr != nil {
- p.err = ErrHeader
+ if len(sparseMap) > 0 {
+ extHdrs[paxGNUSparseMap] = strings.Join(sparseMap, ",")
}
- return int64(x)
+ return extHdrs, nil
}
// skipUnread skips any unread bytes in the existing file entry, as well as any
@@ -516,51 +407,46 @@ func (tr *Reader) skipUnread() error {
// Seek seems supported, so perform the real Seek.
pos2, err := sr.Seek(dataSkip-1, io.SeekCurrent)
if err != nil {
- tr.err = err
- return tr.err
+ return err
}
seekSkipped = pos2 - pos1
}
}
- var copySkipped int64 // Number of bytes skipped via CopyN
- copySkipped, tr.err = io.CopyN(ioutil.Discard, tr.r, totalSkip-seekSkipped)
- if tr.err == io.EOF && seekSkipped+copySkipped < dataSkip {
- tr.err = io.ErrUnexpectedEOF
+ copySkipped, err := io.CopyN(ioutil.Discard, tr.r, totalSkip-seekSkipped)
+ if err == io.EOF && seekSkipped+copySkipped < dataSkip {
+ err = io.ErrUnexpectedEOF
}
- return tr.err
+ return err
}
// readHeader reads the next block header and assumes that the underlying reader
-// is already aligned to a block boundary.
+// is already aligned to a block boundary. It returns the raw block of the
+// header in case further processing is required.
//
// The err will be set to io.EOF only when one of the following occurs:
// * Exactly 0 bytes are read and EOF is hit.
// * Exactly 1 block of zeros is read and EOF is hit.
// * At least 2 blocks of zeros are read.
-func (tr *Reader) readHeader() *Header {
- if _, tr.err = io.ReadFull(tr.r, tr.blk[:]); tr.err != nil {
- return nil // io.EOF is okay here
- }
-
+func (tr *Reader) readHeader() (*Header, *block, error) {
// Two blocks of zero bytes marks the end of the archive.
+ if _, err := io.ReadFull(tr.r, tr.blk[:]); err != nil {
+ return nil, nil, err // EOF is okay here; exactly 0 bytes read
+ }
if bytes.Equal(tr.blk[:], zeroBlock[:]) {
- if _, tr.err = io.ReadFull(tr.r, tr.blk[:]); tr.err != nil {
- return nil // io.EOF is okay here
+ if _, err := io.ReadFull(tr.r, tr.blk[:]); err != nil {
+ return nil, nil, err // EOF is okay here; exactly 1 block of zeros read
}
if bytes.Equal(tr.blk[:], zeroBlock[:]) {
- tr.err = io.EOF
- } else {
- tr.err = ErrHeader // zero block and then non-zero block
+ return nil, nil, io.EOF // normal EOF; exactly 2 block of zeros read
}
- return nil
+ return nil, nil, ErrHeader // Zero block and then non-zero block
}
// Verify the header matches a known format.
format := tr.blk.GetFormat()
if format == formatUnknown {
- tr.err = ErrHeader
- return nil
+ return nil, nil, ErrHeader
}
var p parser
@@ -577,6 +463,26 @@ func (tr *Reader) readHeader() *Header {
hdr.Typeflag = v7.TypeFlag()[0]
hdr.Linkname = p.parseString(v7.LinkName())
+ // The atime and ctime fields are often left unused. Some versions of Go
+ // had a bug in the tar.Writer where it would output an invalid tar file
+ // in certain rare situations because the logic incorrectly believed that
+ // the old GNU format had a prefix field. This is wrong and leads to
+ // an outputted file that actually mangles the atime and ctime fields.
+ //
+ // In order to continue reading tar files created by a buggy writer, we
+ // try to parse the atime and ctime fields, but just return the zero value
+ // of time.Time when we cannot parse them.
+ //
+ // See https://golang.org/issues/12594
+ tryParseTime := func(b []byte) time.Time {
+ var p parser
+ n := p.parseNumeric(b)
+ if b[0] != 0x00 && p.err == nil {
+ return time.Unix(n, 0)
+ }
+ return time.Time{}
+ }
+
// Unpack format specific fields.
if format > formatV7 {
ustar := tr.blk.USTAR()
@@ -589,9 +495,7 @@ func (tr *Reader) readHeader() *Header {
var prefix string
switch format {
- case formatUSTAR, formatGNU:
- // TODO(dsnet): Do not use the prefix field for the GNU format!
- // See golang.org/issues/12594
+ case formatUSTAR:
ustar := tr.blk.USTAR()
prefix = p.parseString(ustar.Prefix())
case formatSTAR:
@@ -599,97 +503,68 @@ func (tr *Reader) readHeader() *Header {
prefix = p.parseString(star.Prefix())
hdr.AccessTime = time.Unix(p.parseNumeric(star.AccessTime()), 0)
hdr.ChangeTime = time.Unix(p.parseNumeric(star.ChangeTime()), 0)
+ case formatGNU:
+ gnu := tr.blk.GNU()
+ hdr.AccessTime = tryParseTime(gnu.AccessTime())
+ hdr.ChangeTime = tryParseTime(gnu.ChangeTime())
}
if len(prefix) > 0 {
hdr.Name = prefix + "/" + hdr.Name
}
}
+ return hdr, &tr.blk, p.err
+}
- nb := hdr.Size
- if isHeaderOnlyType(hdr.Typeflag) {
- nb = 0
- }
- if nb < 0 {
- tr.err = ErrHeader
- return nil
- }
-
- // Set the current file reader.
- tr.pad = -nb & (blockSize - 1) // blockSize is a power of two
- tr.curr = ®FileReader{r: tr.r, nb: nb}
-
- // Check for old GNU sparse format entry.
- if hdr.Typeflag == TypeGNUSparse {
- // Get the real size of the file.
- hdr.Size = p.parseNumeric(tr.blk.GNU().RealSize())
- if p.err != nil {
- tr.err = p.err
- return nil
- }
-
- // Read the sparse map.
- sp := tr.readOldGNUSparseMap(&tr.blk)
- if tr.err != nil {
- return nil
- }
-
- // Current file is a GNU sparse file. Update the current file reader.
- tr.curr, tr.err = newSparseFileReader(tr.curr, sp, hdr.Size)
- if tr.err != nil {
- return nil
- }
+// readOldGNUSparseMap reads the sparse map from the old GNU sparse format.
+// The sparse map is stored in the tar header if it's small enough.
+// If it's larger than four entries, then one or more extension headers are used
+// to store the rest of the sparse map.
+//
+// The Header.Size does not reflect the size of any extended headers used.
+// Thus, this function will read from the raw io.Reader to fetch extra headers.
+// This method mutates blk in the process.
+func (tr *Reader) readOldGNUSparseMap(hdr *Header, blk *block) ([]sparseEntry, error) {
+ // Make sure that the input format is GNU.
+ // Unfortunately, the STAR format also has a sparse header format that uses
+ // the same type flag but has a completely different layout.
+ if blk.GetFormat() != formatGNU {
+ return nil, ErrHeader
}
+ var p parser
+ hdr.Size = p.parseNumeric(blk.GNU().RealSize())
if p.err != nil {
- tr.err = p.err
- return nil
+ return nil, p.err
}
-
- return hdr
-}
-
-// readOldGNUSparseMap reads the sparse map as stored in the old GNU sparse format.
-// The sparse map is stored in the tar header if it's small enough. If it's larger than four entries,
-// then one or more extension headers are used to store the rest of the sparse map.
-func (tr *Reader) readOldGNUSparseMap(blk *block) []sparseEntry {
- var p parser
var s sparseArray = blk.GNU().Sparse()
var sp = make([]sparseEntry, 0, s.MaxEntries())
- for i := 0; i < s.MaxEntries(); i++ {
- offset := p.parseOctal(s.Entry(i).Offset())
- numBytes := p.parseOctal(s.Entry(i).NumBytes())
- if p.err != nil {
- tr.err = p.err
- return nil
- }
- if offset == 0 && numBytes == 0 {
- break
- }
- sp = append(sp, sparseEntry{offset: offset, numBytes: numBytes})
- }
-
- for s.IsExtended()[0] > 0 {
- // There are more entries. Read an extension header and parse its entries.
- var blk block
- if _, tr.err = io.ReadFull(tr.r, blk[:]); tr.err != nil {
- return nil
- }
- s = blk.Sparse()
-
+ for {
for i := 0; i < s.MaxEntries(); i++ {
- offset := p.parseOctal(s.Entry(i).Offset())
- numBytes := p.parseOctal(s.Entry(i).NumBytes())
- if p.err != nil {
- tr.err = p.err
- return nil
+ // This termination condition is identical to GNU and BSD tar.
+ if s.Entry(i).Offset()[0] == 0x00 {
+ break // Don't return, need to process extended headers (even if empty)
}
- if offset == 0 && numBytes == 0 {
- break
+ offset := p.parseNumeric(s.Entry(i).Offset())
+ numBytes := p.parseNumeric(s.Entry(i).NumBytes())
+ if p.err != nil {
+ return nil, p.err
}
sp = append(sp, sparseEntry{offset: offset, numBytes: numBytes})
}
+
+ if s.IsExtended()[0] > 0 {
+ // There are more entries. Read an extension header and parse its entries.
+ if _, err := io.ReadFull(tr.r, blk[:]); err != nil {
+ if err == io.EOF {
+ err = io.ErrUnexpectedEOF
+ }
+ return nil, err
+ }
+ s = blk.Sparse()
+ continue
+ }
+ return sp, nil // Done
}
- return sp
}
// readGNUSparseMap1x0 reads the sparse map as stored in GNU's PAX sparse format
@@ -817,7 +692,7 @@ func (tr *Reader) numBytes() int64 {
// Calling Read on special types like TypeLink, TypeSymLink, TypeChar,
// TypeBlock, TypeDir, and TypeFifo returns 0, io.EOF regardless of what
// the Header.Size claims.
-func (tr *Reader) Read(b []byte) (n int, err error) {
+func (tr *Reader) Read(b []byte) (int, error) {
if tr.err != nil {
return 0, tr.err
}
@@ -825,11 +700,11 @@ func (tr *Reader) Read(b []byte) (n int, err error) {
return 0, io.EOF
}
- n, err = tr.curr.Read(b)
+ n, err := tr.curr.Read(b)
if err != nil && err != io.EOF {
tr.err = err
}
- return
+ return n, err
}
func (rfr *regFileReader) Read(b []byte) (n int, err error) {
diff --git a/src/archive/tar/reader_test.go b/src/archive/tar/reader_test.go
index 7b148b5..3386868 100644
--- a/src/archive/tar/reader_test.go
+++ b/src/archive/tar/reader_test.go
@@ -18,17 +18,15 @@ import (
"time"
)
-type untarTest struct {
- file string // Test input file
- headers []*Header // Expected output headers
- chksums []string // MD5 checksum of files, leave as nil if not checked
- err error // Expected error to occur
-}
-
-var gnuTarTest = &untarTest{
- file: "testdata/gnu.tar",
- headers: []*Header{
- {
+func TestReader(t *testing.T) {
+ vectors := []struct {
+ file string // Test input file
+ headers []*Header // Expected output headers
+ chksums []string // MD5 checksum of files, leave as nil if not checked
+ err error // Expected error to occur
+ }{{
+ file: "testdata/gnu.tar",
+ headers: []*Header{{
Name: "small.txt",
Mode: 0640,
Uid: 73025,
@@ -38,8 +36,7 @@ var gnuTarTest = &untarTest{
Typeflag: '0',
Uname: "dsymonds",
Gname: "eng",
- },
- {
+ }, {
Name: "small2.txt",
Mode: 0640,
Uid: 73025,
@@ -49,18 +46,14 @@ var gnuTarTest = &untarTest{
Typeflag: '0',
Uname: "dsymonds",
Gname: "eng",
+ }},
+ chksums: []string{
+ "e38b27eaccb4391bdec553a7f3ae6b2f",
+ "c65bd2e50a56a2138bf1716f2fd56fe9",
},
- },
- chksums: []string{
- "e38b27eaccb4391bdec553a7f3ae6b2f",
- "c65bd2e50a56a2138bf1716f2fd56fe9",
- },
-}
-
-var sparseTarTest = &untarTest{
- file: "testdata/sparse-formats.tar",
- headers: []*Header{
- {
+ }, {
+ file: "testdata/sparse-formats.tar",
+ headers: []*Header{{
Name: "sparse-gnu",
Mode: 420,
Uid: 1000,
@@ -73,8 +66,7 @@ var sparseTarTest = &untarTest{
Gname: "david",
Devmajor: 0,
Devminor: 0,
- },
- {
+ }, {
Name: "sparse-posix-0.0",
Mode: 420,
Uid: 1000,
@@ -87,8 +79,7 @@ var sparseTarTest = &untarTest{
Gname: "david",
Devmajor: 0,
Devminor: 0,
- },
- {
+ }, {
Name: "sparse-posix-0.1",
Mode: 420,
Uid: 1000,
@@ -101,8 +92,7 @@ var sparseTarTest = &untarTest{
Gname: "david",
Devmajor: 0,
Devminor: 0,
- },
- {
+ }, {
Name: "sparse-posix-1.0",
Mode: 420,
Uid: 1000,
@@ -115,8 +105,7 @@ var sparseTarTest = &untarTest{
Gname: "david",
Devmajor: 0,
Devminor: 0,
- },
- {
+ }, {
Name: "end",
Mode: 420,
Uid: 1000,
@@ -129,209 +118,237 @@ var sparseTarTest = &untarTest{
Gname: "david",
Devmajor: 0,
Devminor: 0,
+ }},
+ chksums: []string{
+ "6f53234398c2449fe67c1812d993012f",
+ "6f53234398c2449fe67c1812d993012f",
+ "6f53234398c2449fe67c1812d993012f",
+ "6f53234398c2449fe67c1812d993012f",
+ "b0061974914468de549a2af8ced10316",
},
- },
- chksums: []string{
- "6f53234398c2449fe67c1812d993012f",
- "6f53234398c2449fe67c1812d993012f",
- "6f53234398c2449fe67c1812d993012f",
- "6f53234398c2449fe67c1812d993012f",
- "b0061974914468de549a2af8ced10316",
- },
-}
-
-var untarTests = []*untarTest{
- gnuTarTest,
- sparseTarTest,
- {
+ }, {
file: "testdata/star.tar",
- headers: []*Header{
- {
- Name: "small.txt",
- Mode: 0640,
- Uid: 73025,
- Gid: 5000,
- Size: 5,
- ModTime: time.Unix(1244592783, 0),
- Typeflag: '0',
- Uname: "dsymonds",
- Gname: "eng",
- AccessTime: time.Unix(1244592783, 0),
- ChangeTime: time.Unix(1244592783, 0),
- },
- {
- Name: "small2.txt",
- Mode: 0640,
- Uid: 73025,
- Gid: 5000,
- Size: 11,
- ModTime: time.Unix(1244592783, 0),
- Typeflag: '0',
- Uname: "dsymonds",
- Gname: "eng",
- AccessTime: time.Unix(1244592783, 0),
- ChangeTime: time.Unix(1244592783, 0),
- },
- },
- },
- {
+ headers: []*Header{{
+ Name: "small.txt",
+ Mode: 0640,
+ Uid: 73025,
+ Gid: 5000,
+ Size: 5,
+ ModTime: time.Unix(1244592783, 0),
+ Typeflag: '0',
+ Uname: "dsymonds",
+ Gname: "eng",
+ AccessTime: time.Unix(1244592783, 0),
+ ChangeTime: time.Unix(1244592783, 0),
+ }, {
+ Name: "small2.txt",
+ Mode: 0640,
+ Uid: 73025,
+ Gid: 5000,
+ Size: 11,
+ ModTime: time.Unix(1244592783, 0),
+ Typeflag: '0',
+ Uname: "dsymonds",
+ Gname: "eng",
+ AccessTime: time.Unix(1244592783, 0),
+ ChangeTime: time.Unix(1244592783, 0),
+ }},
+ }, {
file: "testdata/v7.tar",
- headers: []*Header{
- {
- Name: "small.txt",
- Mode: 0444,
- Uid: 73025,
- Gid: 5000,
- Size: 5,
- ModTime: time.Unix(1244593104, 0),
- Typeflag: '\x00',
- },
- {
- Name: "small2.txt",
- Mode: 0444,
- Uid: 73025,
- Gid: 5000,
- Size: 11,
- ModTime: time.Unix(1244593104, 0),
- Typeflag: '\x00',
- },
- },
- },
- {
+ headers: []*Header{{
+ Name: "small.txt",
+ Mode: 0444,
+ Uid: 73025,
+ Gid: 5000,
+ Size: 5,
+ ModTime: time.Unix(1244593104, 0),
+ Typeflag: '\x00',
+ }, {
+ Name: "small2.txt",
+ Mode: 0444,
+ Uid: 73025,
+ Gid: 5000,
+ Size: 11,
+ ModTime: time.Unix(1244593104, 0),
+ Typeflag: '\x00',
+ }},
+ }, {
file: "testdata/pax.tar",
- headers: []*Header{
- {
- Name: "a/123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100",
- Mode: 0664,
- Uid: 1000,
- Gid: 1000,
- Uname: "shane",
- Gname: "shane",
- Size: 7,
- ModTime: time.Unix(1350244992, 23960108),
- ChangeTime: time.Unix(1350244992, 23960108),
- AccessTime: time.Unix(1350244992, 23960108),
- Typeflag: TypeReg,
- },
- {
- Name: "a/b",
- Mode: 0777,
- Uid: 1000,
- Gid: 1000,
- Uname: "shane",
- Gname: "shane",
- Size: 0,
- ModTime: time.Unix(1350266320, 910238425),
- ChangeTime: time.Unix(1350266320, 910238425),
- AccessTime: time.Unix(1350266320, 910238425),
- Typeflag: TypeSymlink,
- Linkname: "123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100",
- },
+ headers: []*Header{{
+ Name: "a/123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100",
+ Mode: 0664,
+ Uid: 1000,
+ Gid: 1000,
+ Uname: "shane",
+ Gname: "shane",
+ Size: 7,
+ ModTime: time.Unix(1350244992, 23960108),
+ ChangeTime: time.Unix(1350244992, 23960108),
+ AccessTime: time.Unix(1350244992, 23960108),
+ Typeflag: TypeReg,
+ }, {
+ Name: "a/b",
+ Mode: 0777,
+ Uid: 1000,
+ Gid: 1000,
+ Uname: "shane",
+ Gname: "shane",
+ Size: 0,
+ ModTime: time.Unix(1350266320, 910238425),
+ ChangeTime: time.Unix(1350266320, 910238425),
+ AccessTime: time.Unix(1350266320, 910238425),
+ Typeflag: TypeSymlink,
+ Linkname: "123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100",
+ }},
+ }, {
+ file: "testdata/pax-bad-hdr-file.tar",
+ err: ErrHeader,
+ }, {
+ file: "testdata/pax-bad-mtime-file.tar",
+ err: ErrHeader,
+ }, {
+ file: "testdata/pax-pos-size-file.tar",
+ headers: []*Header{{
+ Name: "foo",
+ Mode: 0640,
+ Uid: 319973,
+ Gid: 5000,
+ Size: 999,
+ ModTime: time.Unix(1442282516, 0),
+ Typeflag: '0',
+ Uname: "joetsai",
+ Gname: "eng",
+ }},
+ chksums: []string{
+ "0afb597b283fe61b5d4879669a350556",
},
- },
- {
+ }, {
file: "testdata/nil-uid.tar", // golang.org/issue/5290
- headers: []*Header{
- {
- Name: "P1050238.JPG.log",
- Mode: 0664,
- Uid: 0,
- Gid: 0,
- Size: 14,
- ModTime: time.Unix(1365454838, 0),
- Typeflag: TypeReg,
- Linkname: "",
- Uname: "eyefi",
- Gname: "eyefi",
- Devmajor: 0,
- Devminor: 0,
- },
- },
- },
- {
+ headers: []*Header{{
+ Name: "P1050238.JPG.log",
+ Mode: 0664,
+ Uid: 0,
+ Gid: 0,
+ Size: 14,
+ ModTime: time.Unix(1365454838, 0),
+ Typeflag: TypeReg,
+ Linkname: "",
+ Uname: "eyefi",
+ Gname: "eyefi",
+ Devmajor: 0,
+ Devminor: 0,
+ }},
+ }, {
file: "testdata/xattrs.tar",
- headers: []*Header{
- {
- Name: "small.txt",
- Mode: 0644,
- Uid: 1000,
- Gid: 10,
- Size: 5,
- ModTime: time.Unix(1386065770, 448252320),
- Typeflag: '0',
- Uname: "alex",
- Gname: "wheel",
- AccessTime: time.Unix(1389782991, 419875220),
- ChangeTime: time.Unix(1389782956, 794414986),
- Xattrs: map[string]string{
- "user.key": "value",
- "user.key2": "value2",
- // Interestingly, selinux encodes the terminating null inside the xattr
- "security.selinux": "unconfined_u:object_r:default_t:s0\x00",
- },
+ headers: []*Header{{
+ Name: "small.txt",
+ Mode: 0644,
+ Uid: 1000,
+ Gid: 10,
+ Size: 5,
+ ModTime: time.Unix(1386065770, 448252320),
+ Typeflag: '0',
+ Uname: "alex",
+ Gname: "wheel",
+ AccessTime: time.Unix(1389782991, 419875220),
+ ChangeTime: time.Unix(1389782956, 794414986),
+ Xattrs: map[string]string{
+ "user.key": "value",
+ "user.key2": "value2",
+ // Interestingly, selinux encodes the terminating null inside the xattr
+ "security.selinux": "unconfined_u:object_r:default_t:s0\x00",
},
- {
- Name: "small2.txt",
- Mode: 0644,
- Uid: 1000,
- Gid: 10,
- Size: 11,
- ModTime: time.Unix(1386065770, 449252304),
- Typeflag: '0',
- Uname: "alex",
- Gname: "wheel",
- AccessTime: time.Unix(1389782991, 419875220),
- ChangeTime: time.Unix(1386065770, 449252304),
- Xattrs: map[string]string{
- "security.selinux": "unconfined_u:object_r:default_t:s0\x00",
- },
+ }, {
+ Name: "small2.txt",
+ Mode: 0644,
+ Uid: 1000,
+ Gid: 10,
+ Size: 11,
+ ModTime: time.Unix(1386065770, 449252304),
+ Typeflag: '0',
+ Uname: "alex",
+ Gname: "wheel",
+ AccessTime: time.Unix(1389782991, 419875220),
+ ChangeTime: time.Unix(1386065770, 449252304),
+ Xattrs: map[string]string{
+ "security.selinux": "unconfined_u:object_r:default_t:s0\x00",
},
- },
- },
- {
+ }},
+ }, {
// Matches the behavior of GNU, BSD, and STAR tar utilities.
file: "testdata/gnu-multi-hdrs.tar",
- headers: []*Header{
- {
- Name: "GNU2/GNU2/long-path-name",
- Linkname: "GNU4/GNU4/long-linkpath-name",
- ModTime: time.Unix(0, 0),
- Typeflag: '2',
- },
- },
- },
- {
+ headers: []*Header{{
+ Name: "GNU2/GNU2/long-path-name",
+ Linkname: "GNU4/GNU4/long-linkpath-name",
+ ModTime: time.Unix(0, 0),
+ Typeflag: '2',
+ }},
+ }, {
+ // GNU tar file with atime and ctime fields set.
+ // Created with the GNU tar v1.27.1.
+ // tar --incremental -S -cvf gnu-incremental.tar test2
+ file: "testdata/gnu-incremental.tar",
+ headers: []*Header{{
+ Name: "test2/",
+ Mode: 16877,
+ Uid: 1000,
+ Gid: 1000,
+ Size: 14,
+ ModTime: time.Unix(1441973427, 0),
+ Typeflag: 'D',
+ Uname: "rawr",
+ Gname: "dsnet",
+ AccessTime: time.Unix(1441974501, 0),
+ ChangeTime: time.Unix(1441973436, 0),
+ }, {
+ Name: "test2/foo",
+ Mode: 33188,
+ Uid: 1000,
+ Gid: 1000,
+ Size: 64,
+ ModTime: time.Unix(1441973363, 0),
+ Typeflag: '0',
+ Uname: "rawr",
+ Gname: "dsnet",
+ AccessTime: time.Unix(1441974501, 0),
+ ChangeTime: time.Unix(1441973436, 0),
+ }, {
+ Name: "test2/sparse",
+ Mode: 33188,
+ Uid: 1000,
+ Gid: 1000,
+ Size: 536870912,
+ ModTime: time.Unix(1441973427, 0),
+ Typeflag: 'S',
+ Uname: "rawr",
+ Gname: "dsnet",
+ AccessTime: time.Unix(1441991948, 0),
+ ChangeTime: time.Unix(1441973436, 0),
+ }},
+ }, {
// Matches the behavior of GNU and BSD tar utilities.
file: "testdata/pax-multi-hdrs.tar",
- headers: []*Header{
- {
- Name: "bar",
- Linkname: "PAX4/PAX4/long-linkpath-name",
- ModTime: time.Unix(0, 0),
- Typeflag: '2',
- },
- },
- },
- {
+ headers: []*Header{{
+ Name: "bar",
+ Linkname: "PAX4/PAX4/long-linkpath-name",
+ ModTime: time.Unix(0, 0),
+ Typeflag: '2',
+ }},
+ }, {
file: "testdata/neg-size.tar",
err: ErrHeader,
- },
- {
+ }, {
file: "testdata/issue10968.tar",
err: ErrHeader,
- },
- {
+ }, {
file: "testdata/issue11169.tar",
err: ErrHeader,
- },
- {
+ }, {
file: "testdata/issue12435.tar",
err: ErrHeader,
- },
-}
+ }}
-func TestReader(t *testing.T) {
- for i, v := range untarTests {
+ for i, v := range vectors {
f, err := os.Open(v.file)
if err != nil {
t.Errorf("file %s, test %d: unexpected error: %v", v.file, i, err)
@@ -440,83 +457,8 @@ func TestPartialRead(t *testing.T) {
}
}
-func TestParsePAXHeader(t *testing.T) {
- paxTests := [][3]string{
- {"a", "a=name", "10 a=name\n"}, // Test case involving multiple acceptable lengths
- {"a", "a=name", "9 a=name\n"}, // Test case involving multiple acceptable length
- {"mtime", "mtime=1350244992.023960108", "30 mtime=1350244992.023960108\n"}}
- for _, test := range paxTests {
- key, expected, raw := test[0], test[1], test[2]
- reader := bytes.NewReader([]byte(raw))
- headers, err := parsePAX(reader)
- if err != nil {
- t.Errorf("Couldn't parse correctly formatted headers: %v", err)
- continue
- }
- if strings.EqualFold(headers[key], expected) {
- t.Errorf("mtime header incorrectly parsed: got %s, wanted %s", headers[key], expected)
- continue
- }
- trailer := make([]byte, 100)
- n, err := reader.Read(trailer)
- if err != io.EOF || n != 0 {
- t.Error("Buffer wasn't consumed")
- }
- }
- badHeaderTests := [][]byte{
- []byte("3 somelongkey=\n"),
- []byte("50 tooshort=\n"),
- }
- for _, test := range badHeaderTests {
- if _, err := parsePAX(bytes.NewReader(test)); err != ErrHeader {
- t.Fatal("Unexpected success when parsing bad header")
- }
- }
-}
-
-func TestParsePAXTime(t *testing.T) {
- // Some valid PAX time values
- timestamps := map[string]time.Time{
- "1350244992.023960108": time.Unix(1350244992, 23960108), // The common case
- "1350244992.02396010": time.Unix(1350244992, 23960100), // Lower precision value
- "1350244992.0239601089": time.Unix(1350244992, 23960108), // Higher precision value
- "1350244992": time.Unix(1350244992, 0), // Low precision value
- }
- for input, expected := range timestamps {
- ts, err := parsePAXTime(input)
- if err != nil {
- t.Fatal(err)
- }
- if !ts.Equal(expected) {
- t.Fatalf("Time parsing failure %s %s", ts, expected)
- }
- }
-}
-
-func TestMergePAX(t *testing.T) {
- hdr := new(Header)
- // Test a string, integer, and time based value.
- headers := map[string]string{
- "path": "a/b/c",
- "uid": "1000",
- "mtime": "1350244992.023960108",
- }
- err := mergePAX(hdr, headers)
- if err != nil {
- t.Fatal(err)
- }
- want := &Header{
- Name: "a/b/c",
- Uid: 1000,
- ModTime: time.Unix(1350244992, 23960108),
- }
- if !reflect.DeepEqual(hdr, want) {
- t.Errorf("incorrect merge: got %+v, want %+v", hdr, want)
- }
-}
-
func TestSparseFileReader(t *testing.T) {
- var vectors = []struct {
+ vectors := []struct {
realSize int64 // Real size of the output file
sparseMap []sparseEntry // Input sparse map
sparseData string // Input compact data
@@ -639,9 +581,11 @@ func TestSparseFileReader(t *testing.T) {
r := bytes.NewReader([]byte(v.sparseData))
rfr := ®FileReader{r: r, nb: int64(len(v.sparseData))}
- var sfr *sparseFileReader
- var err error
- var buf []byte
+ var (
+ sfr *sparseFileReader
+ err error
+ buf []byte
+ )
sfr, err = newSparseFileReader(rfr, v.sparseMap, v.realSize)
if err != nil {
@@ -668,6 +612,64 @@ func TestSparseFileReader(t *testing.T) {
}
}
+func TestReadOldGNUSparseMap(t *testing.T) {
+ const (
+ t00 = "00000000000\x0000000000000\x00"
+ t11 = "00000000001\x0000000000001\x00"
+ t12 = "00000000001\x0000000000002\x00"
+ t21 = "00000000002\x0000000000001\x00"
+ )
+
+ mkBlk := func(size, sp0, sp1, sp2, sp3, ext string, format int) *block {
+ var blk block
+ copy(blk.GNU().RealSize(), size)
+ copy(blk.GNU().Sparse().Entry(0), sp0)
+ copy(blk.GNU().Sparse().Entry(1), sp1)
+ copy(blk.GNU().Sparse().Entry(2), sp2)
+ copy(blk.GNU().Sparse().Entry(3), sp3)
+ copy(blk.GNU().Sparse().IsExtended(), ext)
+ if format != formatUnknown {
+ blk.SetFormat(format)
+ }
+ return &blk
+ }
+
+ vectors := []struct {
+ data string // Input data
+ rawHdr *block // Input raw header
+ want []sparseEntry // Expected sparse entries to be outputted
+ err error // Expected error to be returned
+ }{
+ {"", mkBlk("", "", "", "", "", "", formatUnknown), nil, ErrHeader},
+ {"", mkBlk("1234", "fewa", "", "", "", "", formatGNU), nil, ErrHeader},
+ {"", mkBlk("0031", "", "", "", "", "", formatGNU), nil, nil},
+ {"", mkBlk("1234", t00, t11, "", "", "", formatGNU),
+ []sparseEntry{{0, 0}, {1, 1}}, nil},
+ {"", mkBlk("1234", t11, t12, t21, t11, "", formatGNU),
+ []sparseEntry{{1, 1}, {1, 2}, {2, 1}, {1, 1}}, nil},
+ {"", mkBlk("1234", t11, t12, t21, t11, "\x80", formatGNU),
+ []sparseEntry{}, io.ErrUnexpectedEOF},
+ {t11 + t11,
+ mkBlk("1234", t11, t12, t21, t11, "\x80", formatGNU),
+ []sparseEntry{}, io.ErrUnexpectedEOF},
+ {t11 + t21 + strings.Repeat("\x00", 512),
+ mkBlk("1234", t11, t12, t21, t11, "\x80", formatGNU),
+ []sparseEntry{{1, 1}, {1, 2}, {2, 1}, {1, 1}, {1, 1}, {2, 1}}, nil},
+ }
+
+ for i, v := range vectors {
+ tr := Reader{r: strings.NewReader(v.data)}
+ hdr := new(Header)
+ got, err := tr.readOldGNUSparseMap(hdr, v.rawHdr)
+ if !reflect.DeepEqual(got, v.want) && !(len(got) == 0 && len(v.want) == 0) {
+ t.Errorf("test %d, readOldGNUSparseMap(...): got %v, want %v", i, got, v.want)
+ }
+ if err != v.err {
+ t.Errorf("test %d, unexpected error: got %v, want %v", i, err, v.err)
+ }
+ }
+}
+
func TestReadGNUSparseMap0x1(t *testing.T) {
const (
maxUint = ^uint(0)
@@ -679,7 +681,7 @@ func TestReadGNUSparseMap0x1(t *testing.T) {
big3 = fmt.Sprintf("%d", (int64(maxInt) / 3))
)
- var vectors = []struct {
+ vectors := []struct {
extHdrs map[string]string // Input data
sparseMap []sparseEntry // Expected sparse entries to be outputted
err error // Expected errors that may be raised
@@ -745,12 +747,12 @@ func TestReadGNUSparseMap0x1(t *testing.T) {
}
func TestReadGNUSparseMap1x0(t *testing.T) {
- var sp = []sparseEntry{{1, 2}, {3, 4}}
+ sp := []sparseEntry{{1, 2}, {3, 4}}
for i := 0; i < 98; i++ {
sp = append(sp, sparseEntry{54321, 12345})
}
- var vectors = []struct {
+ vectors := []struct {
input string // Input data
sparseMap []sparseEntry // Expected sparse entries to be outputted
cnt int // Expected number of bytes read
@@ -825,8 +827,7 @@ func TestReadGNUSparseMap1x0(t *testing.T) {
}
func TestUninitializedRead(t *testing.T) {
- test := gnuTarTest
- f, err := os.Open(test.file)
+ f, err := os.Open("testdata/gnu.tar")
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}
@@ -868,7 +869,7 @@ func TestReadTruncation(t *testing.T) {
data2 += strings.Repeat("\x00", 10*512)
trash := strings.Repeat("garbage ", 64) // Exactly 512 bytes
- var vectors = []struct {
+ vectors := []struct {
input string // Input stream
cnt int // Expected number of headers read
err error // Expected error outcome
@@ -904,8 +905,7 @@ func TestReadTruncation(t *testing.T) {
{pax + trash[:1], 0, io.ErrUnexpectedEOF},
{pax + trash[:511], 0, io.ErrUnexpectedEOF},
{sparse[:511], 0, io.ErrUnexpectedEOF},
- // TODO(dsnet): This should pass, but currently fails.
- // {sparse[:512], 0, io.ErrUnexpectedEOF},
+ {sparse[:512], 0, io.ErrUnexpectedEOF},
{sparse[:3584], 1, io.EOF},
{sparse[:9200], 1, io.EOF}, // Terminate in padding of sparse header
{sparse[:9216], 1, io.EOF},
@@ -1002,7 +1002,7 @@ func TestReadHeaderOnly(t *testing.T) {
t.Fatalf("len(hdrs): got %d, want %d", len(hdrs), 16)
}
for i := 0; i < 8; i++ {
- var hdr1, hdr2 = hdrs[i+0], hdrs[i+8]
+ hdr1, hdr2 := hdrs[i+0], hdrs[i+8]
hdr1.Size, hdr2.Size = 0, 0
if !reflect.DeepEqual(*hdr1, *hdr2) {
t.Errorf("incorrect header:\ngot %+v\nwant %+v", *hdr1, *hdr2)
@@ -1010,116 +1010,87 @@ func TestReadHeaderOnly(t *testing.T) {
}
}
-func TestParsePAXRecord(t *testing.T) {
- var medName = strings.Repeat("CD", 50)
- var longName = strings.Repeat("AB", 100)
-
- var vectors = []struct {
- input string
- residual string
- outputKey string
- outputVal string
- ok bool
- }{
- {"6 k=v\n\n", "\n", "k", "v", true},
- {"19 path=/etc/hosts\n", "", "path", "/etc/hosts", true},
- {"210 path=" + longName + "\nabc", "abc", "path", longName, true},
- {"110 path=" + medName + "\n", "", "path", medName, true},
- {"9 foo=ba\n", "", "foo", "ba", true},
- {"11 foo=bar\n\x00", "\x00", "foo", "bar", true},
- {"18 foo=b=\nar=\n==\x00\n", "", "foo", "b=\nar=\n==\x00", true},
- {"27 foo=hello9 foo=ba\nworld\n", "", "foo", "hello9 foo=ba\nworld", true},
- {"27 ☺☻☹=日a本b語ç\nmeow mix", "meow mix", "☺☻☹", "日a本b語ç", true},
- {"17 \x00hello=\x00world\n", "", "\x00hello", "\x00world", true},
- {"1 k=1\n", "1 k=1\n", "", "", false},
- {"6 k~1\n", "6 k~1\n", "", "", false},
- {"6_k=1\n", "6_k=1\n", "", "", false},
- {"6 k=1 ", "6 k=1 ", "", "", false},
- {"632 k=1\n", "632 k=1\n", "", "", false},
- {"16 longkeyname=hahaha\n", "16 longkeyname=hahaha\n", "", "", false},
- {"3 somelongkey=\n", "3 somelongkey=\n", "", "", false},
- {"50 tooshort=\n", "50 tooshort=\n", "", "", false},
- }
+func TestMergePAX(t *testing.T) {
+ vectors := []struct {
+ in map[string]string
+ want *Header
+ ok bool
+ }{{
+ in: map[string]string{
+ "path": "a/b/c",
+ "uid": "1000",
+ "mtime": "1350244992.023960108",
+ },
+ want: &Header{
+ Name: "a/b/c",
+ Uid: 1000,
+ ModTime: time.Unix(1350244992, 23960108),
+ },
+ ok: true,
+ }, {
+ in: map[string]string{
+ "gid": "gtgergergersagersgers",
+ },
+ }, {
+ in: map[string]string{
+ "missing": "missing",
+ "SCHILY.xattr.key": "value",
+ },
+ want: &Header{
+ Xattrs: map[string]string{"key": "value"},
+ },
+ ok: true,
+ }}
- for _, v := range vectors {
- key, val, res, err := parsePAXRecord(v.input)
- ok := (err == nil)
- if v.ok != ok {
- if v.ok {
- t.Errorf("parsePAXRecord(%q): got parsing failure, want success", v.input)
- } else {
- t.Errorf("parsePAXRecord(%q): got parsing success, want failure", v.input)
- }
- }
- if ok && (key != v.outputKey || val != v.outputVal) {
- t.Errorf("parsePAXRecord(%q): got (%q: %q), want (%q: %q)",
- v.input, key, val, v.outputKey, v.outputVal)
+ for i, v := range vectors {
+ got := new(Header)
+ err := mergePAX(got, v.in)
+ if v.ok && !reflect.DeepEqual(*got, *v.want) {
+ t.Errorf("test %d, mergePAX(...):\ngot %+v\nwant %+v", i, *got, *v.want)
}
- if res != v.residual {
- t.Errorf("parsePAXRecord(%q): got residual %q, want residual %q",
- v.input, res, v.residual)
+ if ok := err == nil; ok != v.ok {
+ t.Errorf("test %d, mergePAX(...): got %v, want %v", i, ok, v.ok)
}
}
}
-func TestParseNumeric(t *testing.T) {
- var vectors = []struct {
- input string
- output int64
- ok bool
+func TestParsePAX(t *testing.T) {
+ vectors := []struct {
+ in string
+ want map[string]string
+ ok bool
}{
- // Test base-256 (binary) encoded values.
- {"", 0, true},
- {"\x80", 0, true},
- {"\x80\x00", 0, true},
- {"\x80\x00\x00", 0, true},
- {"\xbf", (1 << 6) - 1, true},
- {"\xbf\xff", (1 << 14) - 1, true},
- {"\xbf\xff\xff", (1 << 22) - 1, true},
- {"\xff", -1, true},
- {"\xff\xff", -1, true},
- {"\xff\xff\xff", -1, true},
- {"\xc0", -1 * (1 << 6), true},
- {"\xc0\x00", -1 * (1 << 14), true},
- {"\xc0\x00\x00", -1 * (1 << 22), true},
- {"\x87\x76\xa2\x22\xeb\x8a\x72\x61", 537795476381659745, true},
- {"\x80\x00\x00\x00\x07\x76\xa2\x22\xeb\x8a\x72\x61", 537795476381659745, true},
- {"\xf7\x76\xa2\x22\xeb\x8a\x72\x61", -615126028225187231, true},
- {"\xff\xff\xff\xff\xf7\x76\xa2\x22\xeb\x8a\x72\x61", -615126028225187231, true},
- {"\x80\x7f\xff\xff\xff\xff\xff\xff\xff", math.MaxInt64, true},
- {"\x80\x80\x00\x00\x00\x00\x00\x00\x00", 0, false},
- {"\xff\x80\x00\x00\x00\x00\x00\x00\x00", math.MinInt64, true},
- {"\xff\x7f\xff\xff\xff\xff\xff\xff\xff", 0, false},
- {"\xf5\xec\xd1\xc7\x7e\x5f\x26\x48\x81\x9f\x8f\x9b", 0, false},
-
- // Test base-8 (octal) encoded values.
- {"0000000\x00", 0, true},
- {" \x0000000\x00", 0, true},
- {" \x0000003\x00", 3, true},
- {"00000000227\x00", 0227, true},
- {"032033\x00 ", 032033, true},
- {"320330\x00 ", 0320330, true},
- {"0000660\x00 ", 0660, true},
- {"\x00 0000660\x00 ", 0660, true},
- {"0123456789abcdef", 0, false},
- {"0123456789\x00abcdef", 0, false},
- {"01234567\x0089abcdef", 342391, true},
- {"0123\x7e\x5f\x264123", 0, false},
+ {"", nil, true},
+ {"6 k=1\n", map[string]string{"k": "1"}, true},
+ {"10 a=name\n", map[string]string{"a": "name"}, true},
+ {"9 a=name\n", map[string]string{"a": "name"}, true},
+ {"30 mtime=1350244992.023960108\n", map[string]string{"mtime": "1350244992.023960108"}, true},
+ {"3 somelongkey=\n", nil, false},
+ {"50 tooshort=\n", nil, false},
+ {"13 key1=haha\n13 key2=nana\n13 key3=kaka\n",
+ map[string]string{"key1": "haha", "key2": "nana", "key3": "kaka"}, true},
+ {"13 key1=val1\n13 key2=val2\n8 key1=\n",
+ map[string]string{"key2": "val2"}, true},
+ {"22 GNU.sparse.size=10\n26 GNU.sparse.numblocks=2\n" +
+ "23 GNU.sparse.offset=1\n25 GNU.sparse.numbytes=2\n" +
+ "23 GNU.sparse.offset=3\n25 GNU.sparse.numbytes=4\n",
+ map[string]string{paxGNUSparseSize: "10", paxGNUSparseNumBlocks: "2", paxGNUSparseMap: "1,2,3,4"}, true},
+ {"22 GNU.sparse.size=10\n26 GNU.sparse.numblocks=1\n" +
+ "25 GNU.sparse.numbytes=2\n23 GNU.sparse.offset=1\n",
+ nil, false},
+ {"22 GNU.sparse.size=10\n26 GNU.sparse.numblocks=1\n" +
+ "25 GNU.sparse.offset=1,2\n25 GNU.sparse.numbytes=2\n",
+ nil, false},
}
- for _, v := range vectors {
- var p parser
- num := p.parseNumeric([]byte(v.input))
- ok := (p.err == nil)
- if v.ok != ok {
- if v.ok {
- t.Errorf("parseNumeric(%q): got parsing failure, want success", v.input)
- } else {
- t.Errorf("parseNumeric(%q): got parsing success, want failure", v.input)
- }
+ for i, v := range vectors {
+ r := strings.NewReader(v.in)
+ got, err := parsePAX(r)
+ if !reflect.DeepEqual(got, v.want) && !(len(got) == 0 && len(v.want) == 0) {
+ t.Errorf("test %d, parsePAX(...):\ngot %v\nwant %v", i, got, v.want)
}
- if ok && num != v.output {
- t.Errorf("parseNumeric(%q): got %d, want %d", v.input, num, v.output)
+ if ok := err == nil; ok != v.ok {
+ t.Errorf("test %d, parsePAX(...): got %v, want %v", i, ok, v.ok)
}
}
}
diff --git a/src/archive/tar/strconv.go b/src/archive/tar/strconv.go
new file mode 100644
index 0000000..bb5b51c
--- /dev/null
+++ b/src/archive/tar/strconv.go
@@ -0,0 +1,252 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tar
+
+import (
+ "bytes"
+ "fmt"
+ "strconv"
+ "strings"
+ "time"
+)
+
+func isASCII(s string) bool {
+ for _, c := range s {
+ if c >= 0x80 {
+ return false
+ }
+ }
+ return true
+}
+
+func toASCII(s string) string {
+ if isASCII(s) {
+ return s
+ }
+ var buf bytes.Buffer
+ for _, c := range s {
+ if c < 0x80 {
+ buf.WriteByte(byte(c))
+ }
+ }
+ return buf.String()
+}
+
+type parser struct {
+ err error // Last error seen
+}
+
+type formatter struct {
+ err error // Last error seen
+}
+
+// parseString parses bytes as a NUL-terminated C-style string.
+// If a NUL byte is not found then the whole slice is returned as a string.
+func (*parser) parseString(b []byte) string {
+ n := 0
+ for n < len(b) && b[n] != 0 {
+ n++
+ }
+ return string(b[0:n])
+}
+
+// Write s into b, terminating it with a NUL if there is room.
+func (f *formatter) formatString(b []byte, s string) {
+ if len(s) > len(b) {
+ f.err = ErrFieldTooLong
+ return
+ }
+ ascii := toASCII(s)
+ copy(b, ascii)
+ if len(ascii) < len(b) {
+ b[len(ascii)] = 0
+ }
+}
+
+// fitsInBase256 reports whether x can be encoded into n bytes using base-256
+// encoding. Unlike octal encoding, base-256 encoding does not require that the
+// string ends with a NUL character. Thus, all n bytes are available for output.
+//
+// If operating in binary mode, this assumes strict GNU binary mode; which means
+// that the first byte can only be either 0x80 or 0xff. Thus, the first byte is
+// equivalent to the sign bit in two's complement form.
+func fitsInBase256(n int, x int64) bool {
+ var binBits = uint(n-1) * 8
+ return n >= 9 || (x >= -1<<binBits && x < 1<<binBits)
+}
+
+// parseNumeric parses the input as being encoded in either base-256 or octal.
+// This function may return negative numbers.
+// If parsing fails or an integer overflow occurs, err will be set.
+func (p *parser) parseNumeric(b []byte) int64 {
+ // Check for base-256 (binary) format first.
+ // If the first bit is set, then all following bits constitute a two's
+ // complement encoded number in big-endian byte order.
+ if len(b) > 0 && b[0]&0x80 != 0 {
+ // Handling negative numbers relies on the following identity:
+ // -a-1 == ^a
+ //
+ // If the number is negative, we use an inversion mask to invert the
+ // data bytes and treat the value as an unsigned number.
+ var inv byte // 0x00 if positive or zero, 0xff if negative
+ if b[0]&0x40 != 0 {
+ inv = 0xff
+ }
+
+ var x uint64
+ for i, c := range b {
+ c ^= inv // Inverts c only if inv is 0xff, otherwise does nothing
+ if i == 0 {
+ c &= 0x7f // Ignore signal bit in first byte
+ }
+ if (x >> 56) > 0 {
+ p.err = ErrHeader // Integer overflow
+ return 0
+ }
+ x = x<<8 | uint64(c)
+ }
+ if (x >> 63) > 0 {
+ p.err = ErrHeader // Integer overflow
+ return 0
+ }
+ if inv == 0xff {
+ return ^int64(x)
+ }
+ return int64(x)
+ }
+
+ // Normal case is base-8 (octal) format.
+ return p.parseOctal(b)
+}
+
+// Write x into b, as binary (GNUtar/star extension).
+func (f *formatter) formatNumeric(b []byte, x int64) {
+ if fitsInBase256(len(b), x) {
+ for i := len(b) - 1; i >= 0; i-- {
+ b[i] = byte(x)
+ x >>= 8
+ }
+ b[0] |= 0x80 // Highest bit indicates binary format
+ return
+ }
+
+ f.formatOctal(b, 0) // Last resort, just write zero
+ f.err = ErrFieldTooLong
+}
+
+func (p *parser) parseOctal(b []byte) int64 {
+ // Because unused fields are filled with NULs, we need
+ // to skip leading NULs. Fields may also be padded with
+ // spaces or NULs.
+ // So we remove leading and trailing NULs and spaces to
+ // be sure.
+ b = bytes.Trim(b, " \x00")
+
+ if len(b) == 0 {
+ return 0
+ }
+ x, perr := strconv.ParseUint(p.parseString(b), 8, 64)
+ if perr != nil {
+ p.err = ErrHeader
+ }
+ return int64(x)
+}
+
+func (f *formatter) formatOctal(b []byte, x int64) {
+ s := strconv.FormatInt(x, 8)
+ // Add leading zeros, but leave room for a NUL.
+ if n := len(b) - len(s) - 1; n > 0 {
+ s = strings.Repeat("0", n) + s
+ }
+ f.formatString(b, s)
+}
+
+// parsePAXTime takes a string of the form %d.%d as described in the PAX
+// specification. Note that this implementation allows for negative timestamps,
+// which is allowed for by the PAX specification, but not always portable.
+func parsePAXTime(s string) (time.Time, error) {
+ const maxNanoSecondDigits = 9
+
+ // Split string into seconds and sub-seconds parts.
+ ss, sn := s, ""
+ if pos := strings.IndexByte(s, '.'); pos >= 0 {
+ ss, sn = s[:pos], s[pos+1:]
+ }
+
+ // Parse the seconds.
+ secs, err := strconv.ParseInt(ss, 10, 64)
+ if err != nil {
+ return time.Time{}, ErrHeader
+ }
+ if len(sn) == 0 {
+ return time.Unix(secs, 0), nil // No sub-second values
+ }
+
+ // Parse the nanoseconds.
+ if strings.Trim(sn, "0123456789") != "" {
+ return time.Time{}, ErrHeader
+ }
+ if len(sn) < maxNanoSecondDigits {
+ sn += strings.Repeat("0", maxNanoSecondDigits-len(sn)) // Right pad
+ } else {
+ sn = sn[:maxNanoSecondDigits] // Right truncate
+ }
+ nsecs, _ := strconv.ParseInt(sn, 10, 64) // Must succeed
+ if len(ss) > 0 && ss[0] == '-' {
+ return time.Unix(secs, -1*int64(nsecs)), nil // Negative correction
+ }
+ return time.Unix(secs, int64(nsecs)), nil
+}
+
+// TODO(dsnet): Implement formatPAXTime.
+
+// parsePAXRecord parses the input PAX record string into a key-value pair.
+// If parsing is successful, it will slice off the currently read record and
+// return the remainder as r.
+//
+// A PAX record is of the following form:
+// "%d %s=%s\n" % (size, key, value)
+func parsePAXRecord(s string) (k, v, r string, err error) {
+ // The size field ends at the first space.
+ sp := strings.IndexByte(s, ' ')
+ if sp == -1 {
+ return "", "", s, ErrHeader
+ }
+
+ // Parse the first token as a decimal integer.
+ n, perr := strconv.ParseInt(s[:sp], 10, 0) // Intentionally parse as native int
+ if perr != nil || n < 5 || int64(len(s)) < n {
+ return "", "", s, ErrHeader
+ }
+
+ // Extract everything between the space and the final newline.
+ rec, nl, rem := s[sp+1:n-1], s[n-1:n], s[n:]
+ if nl != "\n" {
+ return "", "", s, ErrHeader
+ }
+
+ // The first equals separates the key from the value.
+ eq := strings.IndexByte(rec, '=')
+ if eq == -1 {
+ return "", "", s, ErrHeader
+ }
+ return rec[:eq], rec[eq+1:], rem, nil
+}
+
+// formatPAXRecord formats a single PAX record, prefixing it with the
+// appropriate length.
+func formatPAXRecord(k, v string) string {
+ const padding = 3 // Extra padding for ' ', '=', and '\n'
+ size := len(k) + len(v) + padding
+ size += len(strconv.Itoa(size))
+ record := fmt.Sprintf("%d %s=%s\n", size, k, v)
+
+ // Final adjustment if adding size field increased the record size.
+ if len(record) != size {
+ size = len(record)
+ record = fmt.Sprintf("%d %s=%s\n", size, k, v)
+ }
+ return record
+}
diff --git a/src/archive/tar/strconv_test.go b/src/archive/tar/strconv_test.go
new file mode 100644
index 0000000..beb7093
--- /dev/null
+++ b/src/archive/tar/strconv_test.go
@@ -0,0 +1,319 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tar
+
+import (
+ "math"
+ "strings"
+ "testing"
+ "time"
+)
+
+func TestFitsInBase256(t *testing.T) {
+ vectors := []struct {
+ in int64
+ width int
+ ok bool
+ }{
+ {+1, 8, true},
+ {0, 8, true},
+ {-1, 8, true},
+ {1 << 56, 8, false},
+ {(1 << 56) - 1, 8, true},
+ {-1 << 56, 8, true},
+ {(-1 << 56) - 1, 8, false},
+ {121654, 8, true},
+ {-9849849, 8, true},
+ {math.MaxInt64, 9, true},
+ {0, 9, true},
+ {math.MinInt64, 9, true},
+ {math.MaxInt64, 12, true},
+ {0, 12, true},
+ {math.MinInt64, 12, true},
+ }
+
+ for _, v := range vectors {
+ ok := fitsInBase256(v.width, v.in)
+ if ok != v.ok {
+ t.Errorf("fitsInBase256(%d, %d): got %v, want %v", v.in, v.width, ok, v.ok)
+ }
+ }
+}
+
+func TestParseNumeric(t *testing.T) {
+ vectors := []struct {
+ in string
+ want int64
+ ok bool
+ }{
+ // Test base-256 (binary) encoded values.
+ {"", 0, true},
+ {"\x80", 0, true},
+ {"\x80\x00", 0, true},
+ {"\x80\x00\x00", 0, true},
+ {"\xbf", (1 << 6) - 1, true},
+ {"\xbf\xff", (1 << 14) - 1, true},
+ {"\xbf\xff\xff", (1 << 22) - 1, true},
+ {"\xff", -1, true},
+ {"\xff\xff", -1, true},
+ {"\xff\xff\xff", -1, true},
+ {"\xc0", -1 * (1 << 6), true},
+ {"\xc0\x00", -1 * (1 << 14), true},
+ {"\xc0\x00\x00", -1 * (1 << 22), true},
+ {"\x87\x76\xa2\x22\xeb\x8a\x72\x61", 537795476381659745, true},
+ {"\x80\x00\x00\x00\x07\x76\xa2\x22\xeb\x8a\x72\x61", 537795476381659745, true},
+ {"\xf7\x76\xa2\x22\xeb\x8a\x72\x61", -615126028225187231, true},
+ {"\xff\xff\xff\xff\xf7\x76\xa2\x22\xeb\x8a\x72\x61", -615126028225187231, true},
+ {"\x80\x7f\xff\xff\xff\xff\xff\xff\xff", math.MaxInt64, true},
+ {"\x80\x80\x00\x00\x00\x00\x00\x00\x00", 0, false},
+ {"\xff\x80\x00\x00\x00\x00\x00\x00\x00", math.MinInt64, true},
+ {"\xff\x7f\xff\xff\xff\xff\xff\xff\xff", 0, false},
+ {"\xf5\xec\xd1\xc7\x7e\x5f\x26\x48\x81\x9f\x8f\x9b", 0, false},
+
+ // Test base-8 (octal) encoded values.
+ {"0000000\x00", 0, true},
+ {" \x0000000\x00", 0, true},
+ {" \x0000003\x00", 3, true},
+ {"00000000227\x00", 0227, true},
+ {"032033\x00 ", 032033, true},
+ {"320330\x00 ", 0320330, true},
+ {"0000660\x00 ", 0660, true},
+ {"\x00 0000660\x00 ", 0660, true},
+ {"0123456789abcdef", 0, false},
+ {"0123456789\x00abcdef", 0, false},
+ {"01234567\x0089abcdef", 342391, true},
+ {"0123\x7e\x5f\x264123", 0, false},
+ }
+
+ for _, v := range vectors {
+ var p parser
+ got := p.parseNumeric([]byte(v.in))
+ ok := (p.err == nil)
+ if ok != v.ok {
+ if v.ok {
+ t.Errorf("parseNumeric(%q): got parsing failure, want success", v.in)
+ } else {
+ t.Errorf("parseNumeric(%q): got parsing success, want failure", v.in)
+ }
+ }
+ if ok && got != v.want {
+ t.Errorf("parseNumeric(%q): got %d, want %d", v.in, got, v.want)
+ }
+ }
+}
+
+func TestFormatNumeric(t *testing.T) {
+ vectors := []struct {
+ in int64
+ want string
+ ok bool
+ }{
+ // Test base-256 (binary) encoded values.
+ {-1, "\xff", true},
+ {-1, "\xff\xff", true},
+ {-1, "\xff\xff\xff", true},
+ {(1 << 0), "0", false},
+ {(1 << 8) - 1, "\x80\xff", true},
+ {(1 << 8), "0\x00", false},
+ {(1 << 16) - 1, "\x80\xff\xff", true},
+ {(1 << 16), "00\x00", false},
+ {-1 * (1 << 0), "\xff", true},
+ {-1*(1<<0) - 1, "0", false},
+ {-1 * (1 << 8), "\xff\x00", true},
+ {-1*(1<<8) - 1, "0\x00", false},
+ {-1 * (1 << 16), "\xff\x00\x00", true},
+ {-1*(1<<16) - 1, "00\x00", false},
+ {537795476381659745, "0000000\x00", false},
+ {537795476381659745, "\x80\x00\x00\x00\x07\x76\xa2\x22\xeb\x8a\x72\x61", true},
+ {-615126028225187231, "0000000\x00", false},
+ {-615126028225187231, "\xff\xff\xff\xff\xf7\x76\xa2\x22\xeb\x8a\x72\x61", true},
+ {math.MaxInt64, "0000000\x00", false},
+ {math.MaxInt64, "\x80\x00\x00\x00\x7f\xff\xff\xff\xff\xff\xff\xff", true},
+ {math.MinInt64, "0000000\x00", false},
+ {math.MinInt64, "\xff\xff\xff\xff\x80\x00\x00\x00\x00\x00\x00\x00", true},
+ {math.MaxInt64, "\x80\x7f\xff\xff\xff\xff\xff\xff\xff", true},
+ {math.MinInt64, "\xff\x80\x00\x00\x00\x00\x00\x00\x00", true},
+ }
+
+ for _, v := range vectors {
+ var f formatter
+ got := make([]byte, len(v.want))
+ f.formatNumeric(got, v.in)
+ ok := (f.err == nil)
+ if ok != v.ok {
+ if v.ok {
+ t.Errorf("formatNumeric(%d): got formatting failure, want success", v.in)
+ } else {
+ t.Errorf("formatNumeric(%d): got formatting success, want failure", v.in)
+ }
+ }
+ if string(got) != v.want {
+ t.Errorf("formatNumeric(%d): got %q, want %q", v.in, got, v.want)
+ }
+ }
+}
+
+func TestParsePAXTime(t *testing.T) {
+ vectors := []struct {
+ in string
+ want time.Time
+ ok bool
+ }{
+ {"1350244992.023960108", time.Unix(1350244992, 23960108), true},
+ {"1350244992.02396010", time.Unix(1350244992, 23960100), true},
+ {"1350244992.0239601089", time.Unix(1350244992, 23960108), true},
+ {"1350244992.3", time.Unix(1350244992, 300000000), true},
+ {"1350244992", time.Unix(1350244992, 0), true},
+ {"-1.000000001", time.Unix(-1, -1e0+0e0), true},
+ {"-1.000001", time.Unix(-1, -1e3+0e0), true},
+ {"-1.001000", time.Unix(-1, -1e6+0e0), true},
+ {"-1", time.Unix(-1, -0e0+0e0), true},
+ {"-1.999000", time.Unix(-1, -1e9+1e6), true},
+ {"-1.999999", time.Unix(-1, -1e9+1e3), true},
+ {"-1.999999999", time.Unix(-1, -1e9+1e0), true},
+ {"0.000000001", time.Unix(0, 1e0+0e0), true},
+ {"0.000001", time.Unix(0, 1e3+0e0), true},
+ {"0.001000", time.Unix(0, 1e6+0e0), true},
+ {"0", time.Unix(0, 0e0), true},
+ {"0.999000", time.Unix(0, 1e9-1e6), true},
+ {"0.999999", time.Unix(0, 1e9-1e3), true},
+ {"0.999999999", time.Unix(0, 1e9-1e0), true},
+ {"1.000000001", time.Unix(+1, +1e0-0e0), true},
+ {"1.000001", time.Unix(+1, +1e3-0e0), true},
+ {"1.001000", time.Unix(+1, +1e6-0e0), true},
+ {"1", time.Unix(+1, +0e0-0e0), true},
+ {"1.999000", time.Unix(+1, +1e9-1e6), true},
+ {"1.999999", time.Unix(+1, +1e9-1e3), true},
+ {"1.999999999", time.Unix(+1, +1e9-1e0), true},
+ {"-1350244992.023960108", time.Unix(-1350244992, -23960108), true},
+ {"-1350244992.02396010", time.Unix(-1350244992, -23960100), true},
+ {"-1350244992.0239601089", time.Unix(-1350244992, -23960108), true},
+ {"-1350244992.3", time.Unix(-1350244992, -300000000), true},
+ {"-1350244992", time.Unix(-1350244992, 0), true},
+ {"", time.Time{}, false},
+ {"0", time.Unix(0, 0), true},
+ {"1.", time.Unix(1, 0), true},
+ {"0.0", time.Unix(0, 0), true},
+ {".5", time.Time{}, false},
+ {"-1.3", time.Unix(-1, -3e8), true},
+ {"-1.0", time.Unix(-1, -0e0), true},
+ {"-0.0", time.Unix(-0, -0e0), true},
+ {"-0.1", time.Unix(-0, -1e8), true},
+ {"-0.01", time.Unix(-0, -1e7), true},
+ {"-0.99", time.Unix(-0, -99e7), true},
+ {"-0.98", time.Unix(-0, -98e7), true},
+ {"-1.1", time.Unix(-1, -1e8), true},
+ {"-1.01", time.Unix(-1, -1e7), true},
+ {"-2.99", time.Unix(-2, -99e7), true},
+ {"-5.98", time.Unix(-5, -98e7), true},
+ {"-", time.Time{}, false},
+ {"+", time.Time{}, false},
+ {"-1.-1", time.Time{}, false},
+ {"99999999999999999999999999999999999999999999999", time.Time{}, false},
+ {"0.123456789abcdef", time.Time{}, false},
+ {"foo", time.Time{}, false},
+ {"\x00", time.Time{}, false},
+ {"𝟵𝟴𝟳𝟲𝟱.𝟰𝟯𝟮𝟭𝟬", time.Time{}, false}, // Unicode numbers (U+1D7EC to U+1D7F5)
+ {"98765﹒43210", time.Time{}, false}, // Unicode period (U+FE52)
+ }
+
+ for _, v := range vectors {
+ ts, err := parsePAXTime(v.in)
+ ok := (err == nil)
+ if v.ok != ok {
+ if v.ok {
+ t.Errorf("parsePAXTime(%q): got parsing failure, want success", v.in)
+ } else {
+ t.Errorf("parsePAXTime(%q): got parsing success, want failure", v.in)
+ }
+ }
+ if ok && !ts.Equal(v.want) {
+ t.Errorf("parsePAXTime(%q): got (%ds %dns), want (%ds %dns)",
+ v.in, ts.Unix(), ts.Nanosecond(), v.want.Unix(), v.want.Nanosecond())
+ }
+ }
+}
+
+func TestParsePAXRecord(t *testing.T) {
+ medName := strings.Repeat("CD", 50)
+ longName := strings.Repeat("AB", 100)
+
+ vectors := []struct {
+ in string
+ wantRes string
+ wantKey string
+ wantVal string
+ ok bool
+ }{
+ {"6 k=v\n\n", "\n", "k", "v", true},
+ {"19 path=/etc/hosts\n", "", "path", "/etc/hosts", true},
+ {"210 path=" + longName + "\nabc", "abc", "path", longName, true},
+ {"110 path=" + medName + "\n", "", "path", medName, true},
+ {"9 foo=ba\n", "", "foo", "ba", true},
+ {"11 foo=bar\n\x00", "\x00", "foo", "bar", true},
+ {"18 foo=b=\nar=\n==\x00\n", "", "foo", "b=\nar=\n==\x00", true},
+ {"27 foo=hello9 foo=ba\nworld\n", "", "foo", "hello9 foo=ba\nworld", true},
+ {"27 ☺☻☹=日a本b語ç\nmeow mix", "meow mix", "☺☻☹", "日a本b語ç", true},
+ {"17 \x00hello=\x00world\n", "", "\x00hello", "\x00world", true},
+ {"1 k=1\n", "1 k=1\n", "", "", false},
+ {"6 k~1\n", "6 k~1\n", "", "", false},
+ {"6_k=1\n", "6_k=1\n", "", "", false},
+ {"6 k=1 ", "6 k=1 ", "", "", false},
+ {"632 k=1\n", "632 k=1\n", "", "", false},
+ {"16 longkeyname=hahaha\n", "16 longkeyname=hahaha\n", "", "", false},
+ {"3 somelongkey=\n", "3 somelongkey=\n", "", "", false},
+ {"50 tooshort=\n", "50 tooshort=\n", "", "", false},
+ }
+
+ for _, v := range vectors {
+ key, val, res, err := parsePAXRecord(v.in)
+ ok := (err == nil)
+ if ok != v.ok {
+ if v.ok {
+ t.Errorf("parsePAXRecord(%q): got parsing failure, want success", v.in)
+ } else {
+ t.Errorf("parsePAXRecord(%q): got parsing success, want failure", v.in)
+ }
+ }
+ if v.ok && (key != v.wantKey || val != v.wantVal) {
+ t.Errorf("parsePAXRecord(%q): got (%q: %q), want (%q: %q)",
+ v.in, key, val, v.wantKey, v.wantVal)
+ }
+ if res != v.wantRes {
+ t.Errorf("parsePAXRecord(%q): got residual %q, want residual %q",
+ v.in, res, v.wantRes)
+ }
+ }
+}
+
+func TestFormatPAXRecord(t *testing.T) {
+ medName := strings.Repeat("CD", 50)
+ longName := strings.Repeat("AB", 100)
+
+ vectors := []struct {
+ inKey string
+ inVal string
+ want string
+ }{
+ {"k", "v", "6 k=v\n"},
+ {"path", "/etc/hosts", "19 path=/etc/hosts\n"},
+ {"path", longName, "210 path=" + longName + "\n"},
+ {"path", medName, "110 path=" + medName + "\n"},
+ {"foo", "ba", "9 foo=ba\n"},
+ {"foo", "bar", "11 foo=bar\n"},
+ {"foo", "b=\nar=\n==\x00", "18 foo=b=\nar=\n==\x00\n"},
+ {"foo", "hello9 foo=ba\nworld", "27 foo=hello9 foo=ba\nworld\n"},
+ {"☺☻☹", "日a本b語ç", "27 ☺☻☹=日a本b語ç\n"},
+ {"\x00hello", "\x00world", "17 \x00hello=\x00world\n"},
+ }
+
+ for _, v := range vectors {
+ got := formatPAXRecord(v.inKey, v.inVal)
+ if got != v.want {
+ t.Errorf("formatPAXRecord(%q, %q): got %q, want %q",
+ v.inKey, v.inVal, got, v.want)
+ }
+ }
+}
diff --git a/src/archive/tar/tar_test.go b/src/archive/tar/tar_test.go
index d63c072..cf8337c 100644
--- a/src/archive/tar/tar_test.go
+++ b/src/archive/tar/tar_test.go
@@ -135,190 +135,178 @@ type headerRoundTripTest struct {
}
func TestHeaderRoundTrip(t *testing.T) {
- golden := []headerRoundTripTest{
+ vectors := []headerRoundTripTest{{
// regular file.
- {
- h: &Header{
- Name: "test.txt",
- Mode: 0644 | c_ISREG,
- Size: 12,
- ModTime: time.Unix(1360600916, 0),
- Typeflag: TypeReg,
- },
- fm: 0644,
+ h: &Header{
+ Name: "test.txt",
+ Mode: 0644 | c_ISREG,
+ Size: 12,
+ ModTime: time.Unix(1360600916, 0),
+ Typeflag: TypeReg,
},
+ fm: 0644,
+ }, {
// symbolic link.
- {
- h: &Header{
- Name: "link.txt",
- Mode: 0777 | c_ISLNK,
- Size: 0,
- ModTime: time.Unix(1360600852, 0),
- Typeflag: TypeSymlink,
- },
- fm: 0777 | os.ModeSymlink,
+ h: &Header{
+ Name: "link.txt",
+ Mode: 0777 | c_ISLNK,
+ Size: 0,
+ ModTime: time.Unix(1360600852, 0),
+ Typeflag: TypeSymlink,
},
+ fm: 0777 | os.ModeSymlink,
+ }, {
// character device node.
- {
- h: &Header{
- Name: "dev/null",
- Mode: 0666 | c_ISCHR,
- Size: 0,
- ModTime: time.Unix(1360578951, 0),
- Typeflag: TypeChar,
- },
- fm: 0666 | os.ModeDevice | os.ModeCharDevice,
+ h: &Header{
+ Name: "dev/null",
+ Mode: 0666 | c_ISCHR,
+ Size: 0,
+ ModTime: time.Unix(1360578951, 0),
+ Typeflag: TypeChar,
},
+ fm: 0666 | os.ModeDevice | os.ModeCharDevice,
+ }, {
// block device node.
- {
- h: &Header{
- Name: "dev/sda",
- Mode: 0660 | c_ISBLK,
- Size: 0,
- ModTime: time.Unix(1360578954, 0),
- Typeflag: TypeBlock,
- },
- fm: 0660 | os.ModeDevice,
+ h: &Header{
+ Name: "dev/sda",
+ Mode: 0660 | c_ISBLK,
+ Size: 0,
+ ModTime: time.Unix(1360578954, 0),
+ Typeflag: TypeBlock,
},
+ fm: 0660 | os.ModeDevice,
+ }, {
// directory.
- {
- h: &Header{
- Name: "dir/",
- Mode: 0755 | c_ISDIR,
- Size: 0,
- ModTime: time.Unix(1360601116, 0),
- Typeflag: TypeDir,
- },
- fm: 0755 | os.ModeDir,
+ h: &Header{
+ Name: "dir/",
+ Mode: 0755 | c_ISDIR,
+ Size: 0,
+ ModTime: time.Unix(1360601116, 0),
+ Typeflag: TypeDir,
},
+ fm: 0755 | os.ModeDir,
+ }, {
// fifo node.
- {
- h: &Header{
- Name: "dev/initctl",
- Mode: 0600 | c_ISFIFO,
- Size: 0,
- ModTime: time.Unix(1360578949, 0),
- Typeflag: TypeFifo,
- },
- fm: 0600 | os.ModeNamedPipe,
+ h: &Header{
+ Name: "dev/initctl",
+ Mode: 0600 | c_ISFIFO,
+ Size: 0,
+ ModTime: time.Unix(1360578949, 0),
+ Typeflag: TypeFifo,
},
+ fm: 0600 | os.ModeNamedPipe,
+ }, {
// setuid.
- {
- h: &Header{
- Name: "bin/su",
- Mode: 0755 | c_ISREG | c_ISUID,
- Size: 23232,
- ModTime: time.Unix(1355405093, 0),
- Typeflag: TypeReg,
- },
- fm: 0755 | os.ModeSetuid,
+ h: &Header{
+ Name: "bin/su",
+ Mode: 0755 | c_ISREG | c_ISUID,
+ Size: 23232,
+ ModTime: time.Unix(1355405093, 0),
+ Typeflag: TypeReg,
},
+ fm: 0755 | os.ModeSetuid,
+ }, {
// setguid.
- {
- h: &Header{
- Name: "group.txt",
- Mode: 0750 | c_ISREG | c_ISGID,
- Size: 0,
- ModTime: time.Unix(1360602346, 0),
- Typeflag: TypeReg,
- },
- fm: 0750 | os.ModeSetgid,
+ h: &Header{
+ Name: "group.txt",
+ Mode: 0750 | c_ISREG | c_ISGID,
+ Size: 0,
+ ModTime: time.Unix(1360602346, 0),
+ Typeflag: TypeReg,
},
+ fm: 0750 | os.ModeSetgid,
+ }, {
// sticky.
- {
- h: &Header{
- Name: "sticky.txt",
- Mode: 0600 | c_ISREG | c_ISVTX,
- Size: 7,
- ModTime: time.Unix(1360602540, 0),
- Typeflag: TypeReg,
- },
- fm: 0600 | os.ModeSticky,
+ h: &Header{
+ Name: "sticky.txt",
+ Mode: 0600 | c_ISREG | c_ISVTX,
+ Size: 7,
+ ModTime: time.Unix(1360602540, 0),
+ Typeflag: TypeReg,
},
+ fm: 0600 | os.ModeSticky,
+ }, {
// hard link.
- {
- h: &Header{
- Name: "hard.txt",
- Mode: 0644 | c_ISREG,
- Size: 0,
- Linkname: "file.txt",
- ModTime: time.Unix(1360600916, 0),
- Typeflag: TypeLink,
- },
- fm: 0644,
+ h: &Header{
+ Name: "hard.txt",
+ Mode: 0644 | c_ISREG,
+ Size: 0,
+ Linkname: "file.txt",
+ ModTime: time.Unix(1360600916, 0),
+ Typeflag: TypeLink,
},
+ fm: 0644,
+ }, {
// More information.
- {
- h: &Header{
- Name: "info.txt",
- Mode: 0600 | c_ISREG,
- Size: 0,
- Uid: 1000,
- Gid: 1000,
- ModTime: time.Unix(1360602540, 0),
- Uname: "slartibartfast",
- Gname: "users",
- Typeflag: TypeReg,
- },
- fm: 0600,
+ h: &Header{
+ Name: "info.txt",
+ Mode: 0600 | c_ISREG,
+ Size: 0,
+ Uid: 1000,
+ Gid: 1000,
+ ModTime: time.Unix(1360602540, 0),
+ Uname: "slartibartfast",
+ Gname: "users",
+ Typeflag: TypeReg,
},
- }
+ fm: 0600,
+ }}
- for i, g := range golden {
- fi := g.h.FileInfo()
+ for i, v := range vectors {
+ fi := v.h.FileInfo()
h2, err := FileInfoHeader(fi, "")
if err != nil {
t.Error(err)
continue
}
if strings.Contains(fi.Name(), "/") {
- t.Errorf("FileInfo of %q contains slash: %q", g.h.Name, fi.Name())
+ t.Errorf("FileInfo of %q contains slash: %q", v.h.Name, fi.Name())
}
- name := path.Base(g.h.Name)
+ name := path.Base(v.h.Name)
if fi.IsDir() {
name += "/"
}
if got, want := h2.Name, name; got != want {
t.Errorf("i=%d: Name: got %v, want %v", i, got, want)
}
- if got, want := h2.Size, g.h.Size; got != want {
+ if got, want := h2.Size, v.h.Size; got != want {
t.Errorf("i=%d: Size: got %v, want %v", i, got, want)
}
- if got, want := h2.Uid, g.h.Uid; got != want {
+ if got, want := h2.Uid, v.h.Uid; got != want {
t.Errorf("i=%d: Uid: got %d, want %d", i, got, want)
}
- if got, want := h2.Gid, g.h.Gid; got != want {
+ if got, want := h2.Gid, v.h.Gid; got != want {
t.Errorf("i=%d: Gid: got %d, want %d", i, got, want)
}
- if got, want := h2.Uname, g.h.Uname; got != want {
+ if got, want := h2.Uname, v.h.Uname; got != want {
t.Errorf("i=%d: Uname: got %q, want %q", i, got, want)
}
- if got, want := h2.Gname, g.h.Gname; got != want {
+ if got, want := h2.Gname, v.h.Gname; got != want {
t.Errorf("i=%d: Gname: got %q, want %q", i, got, want)
}
- if got, want := h2.Linkname, g.h.Linkname; got != want {
+ if got, want := h2.Linkname, v.h.Linkname; got != want {
t.Errorf("i=%d: Linkname: got %v, want %v", i, got, want)
}
- if got, want := h2.Typeflag, g.h.Typeflag; got != want {
- t.Logf("%#v %#v", g.h, fi.Sys())
+ if got, want := h2.Typeflag, v.h.Typeflag; got != want {
+ t.Logf("%#v %#v", v.h, fi.Sys())
t.Errorf("i=%d: Typeflag: got %q, want %q", i, got, want)
}
- if got, want := h2.Mode, g.h.Mode; got != want {
+ if got, want := h2.Mode, v.h.Mode; got != want {
t.Errorf("i=%d: Mode: got %o, want %o", i, got, want)
}
- if got, want := fi.Mode(), g.fm; got != want {
+ if got, want := fi.Mode(), v.fm; got != want {
t.Errorf("i=%d: fi.Mode: got %o, want %o", i, got, want)
}
- if got, want := h2.AccessTime, g.h.AccessTime; got != want {
+ if got, want := h2.AccessTime, v.h.AccessTime; got != want {
t.Errorf("i=%d: AccessTime: got %v, want %v", i, got, want)
}
- if got, want := h2.ChangeTime, g.h.ChangeTime; got != want {
+ if got, want := h2.ChangeTime, v.h.ChangeTime; got != want {
t.Errorf("i=%d: ChangeTime: got %v, want %v", i, got, want)
}
- if got, want := h2.ModTime, g.h.ModTime; got != want {
+ if got, want := h2.ModTime, v.h.ModTime; got != want {
t.Errorf("i=%d: ModTime: got %v, want %v", i, got, want)
}
- if sysh, ok := fi.Sys().(*Header); !ok || sysh != g.h {
+ if sysh, ok := fi.Sys().(*Header); !ok || sysh != v.h {
t.Errorf("i=%d: Sys didn't return original *Header", i)
}
}
diff --git a/src/archive/tar/testdata/gnu-incremental.tar b/src/archive/tar/testdata/gnu-incremental.tar
new file mode 100644
index 0000000..4c442e5
Binary files /dev/null and b/src/archive/tar/testdata/gnu-incremental.tar differ
diff --git a/src/archive/tar/testdata/pax-bad-hdr-file.tar b/src/archive/tar/testdata/pax-bad-hdr-file.tar
new file mode 100644
index 0000000..b97cc98
Binary files /dev/null and b/src/archive/tar/testdata/pax-bad-hdr-file.tar differ
diff --git a/src/archive/tar/testdata/pax-bad-mtime-file.tar b/src/archive/tar/testdata/pax-bad-mtime-file.tar
new file mode 100644
index 0000000..9b22f7e
Binary files /dev/null and b/src/archive/tar/testdata/pax-bad-mtime-file.tar differ
diff --git a/src/archive/tar/testdata/pax-pos-size-file.tar b/src/archive/tar/testdata/pax-pos-size-file.tar
new file mode 100644
index 0000000..aed9a8a
Binary files /dev/null and b/src/archive/tar/testdata/pax-pos-size-file.tar differ
diff --git a/src/archive/tar/testdata/ustar.issue12594.tar b/src/archive/tar/testdata/ustar.issue12594.tar
new file mode 100644
index 0000000..c7910ae
Binary files /dev/null and b/src/archive/tar/testdata/ustar.issue12594.tar differ
diff --git a/src/archive/tar/testdata/writer-big-long.tar b/src/archive/tar/testdata/writer-big-long.tar
index 5960ee8..52bd748 100644
Binary files a/src/archive/tar/testdata/writer-big-long.tar and b/src/archive/tar/testdata/writer-big-long.tar differ
diff --git a/src/archive/tar/writer.go b/src/archive/tar/writer.go
index 426e443..596fb8b 100644
--- a/src/archive/tar/writer.go
+++ b/src/archive/tar/writer.go
@@ -42,10 +42,6 @@ type Writer struct {
paxHdrBuff block // buffer to use in writeHeader when writing a PAX header
}
-type formatter struct {
- err error // Last error seen
-}
-
// NewWriter creates a new Writer writing to w.
func NewWriter(w io.Writer) *Writer { return &Writer{w: w} }
@@ -71,56 +67,6 @@ func (tw *Writer) Flush() error {
return tw.err
}
-// Write s into b, terminating it with a NUL if there is room.
-func (f *formatter) formatString(b []byte, s string) {
- if len(s) > len(b) {
- f.err = ErrFieldTooLong
- return
- }
- ascii := toASCII(s)
- copy(b, ascii)
- if len(ascii) < len(b) {
- b[len(ascii)] = 0
- }
-}
-
-// Encode x as an octal ASCII string and write it into b with leading zeros.
-func (f *formatter) formatOctal(b []byte, x int64) {
- s := strconv.FormatInt(x, 8)
- // leading zeros, but leave room for a NUL.
- for len(s)+1 < len(b) {
- s = "0" + s
- }
- f.formatString(b, s)
-}
-
-// fitsInBase256 reports whether x can be encoded into n bytes using base-256
-// encoding. Unlike octal encoding, base-256 encoding does not require that the
-// string ends with a NUL character. Thus, all n bytes are available for output.
-//
-// If operating in binary mode, this assumes strict GNU binary mode; which means
-// that the first byte can only be either 0x80 or 0xff. Thus, the first byte is
-// equivalent to the sign bit in two's complement form.
-func fitsInBase256(n int, x int64) bool {
- var binBits = uint(n-1) * 8
- return n >= 9 || (x >= -1<<binBits && x < 1<<binBits)
-}
-
-// Write x into b, as binary (GNUtar/star extension).
-func (f *formatter) formatNumeric(b []byte, x int64) {
- if fitsInBase256(len(b), x) {
- for i := len(b) - 1; i >= 0; i-- {
- b[i] = byte(x)
- x >>= 8
- }
- b[0] |= 0x80 // Highest bit indicates binary format
- return
- }
-
- f.formatOctal(b, 0) // Last resort, just write zero
- f.err = ErrFieldTooLong
-}
-
var (
minTime = time.Unix(0, 0)
// There is room for 11 octal digits (33 bits) of mtime.
@@ -224,9 +170,41 @@ func (tw *Writer) writeHeader(hdr *Header, allowPax bool) error {
formatNumeric(ustar.DevMajor(), hdr.Devmajor, paxNone)
formatNumeric(ustar.DevMinor(), hdr.Devminor, paxNone)
+ // TODO(dsnet): The logic surrounding the prefix field is broken when trying
+ // to encode the header as GNU format. The challenge with the current logic
+ // is that we are unsure what format we are using at any given moment until
+ // we have processed *all* of the fields. The problem is that by the time
+ // all fields have been processed, some work has already been done to handle
+ // each field under the assumption that it is for one given format or
+ // another. In some situations, this causes the Writer to be confused and
+ // encode a prefix field when the format being used is GNU. Thus, producing
+ // an invalid tar file.
+ //
+ // As a short-term fix, we disable the logic to use the prefix field, which
+ // will force the badly generated GNU files to become encoded as being
+ // the PAX format.
+ //
+ // As an alternative fix, we could hard-code preferPax to be true. However,
+ // this is problematic for the following reasons:
+ // * The preferPax functionality is not tested at all.
+ // * This can result in headers that try to use both the GNU and PAX
+ // features at the same time, which is also wrong.
+ //
+ // The proper fix for this is to use a two-pass method:
+ // * The first pass simply determines what set of formats can possibly
+ // encode the given header.
+ // * The second pass actually encodes the header as that given format
+ // without worrying about violating the format.
+ //
+ // See the following:
+ // https://golang.org/issue/12594
+ // https://golang.org/issue/17630
+ // https://golang.org/issue/9683
+ const usePrefix = false
+
// try to use a ustar header when only the name is too long
_, paxPathUsed := paxHeaders[paxPath]
- if !tw.preferPax && len(paxHeaders) == 1 && paxPathUsed {
+ if usePrefix && !tw.preferPax && len(paxHeaders) == 1 && paxPathUsed {
prefix, suffix, ok := splitUSTARPath(hdr.Name)
if ok {
// Since we can encode in USTAR format, disable PAX header.
@@ -317,7 +295,7 @@ func (tw *Writer) writePAXHeader(hdr *Header, paxHeaders map[string]string) erro
var buf bytes.Buffer
// Keys are sorted before writing to body to allow deterministic output.
- var keys []string
+ keys := make([]string, 0, len(paxHeaders))
for k := range paxHeaders {
keys = append(keys, k)
}
@@ -340,22 +318,6 @@ func (tw *Writer) writePAXHeader(hdr *Header, paxHeaders map[string]string) erro
return nil
}
-// formatPAXRecord formats a single PAX record, prefixing it with the
-// appropriate length.
-func formatPAXRecord(k, v string) string {
- const padding = 3 // Extra padding for ' ', '=', and '\n'
- size := len(k) + len(v) + padding
- size += len(strconv.Itoa(size))
- record := fmt.Sprintf("%d %s=%s\n", size, k, v)
-
- // Final adjustment if adding size field increased the record size.
- if len(record) != size {
- size = len(record)
- record = fmt.Sprintf("%d %s=%s\n", size, k, v)
- }
- return record
-}
-
// Write writes to the current entry in the tar archive.
// Write returns the error ErrWriteTooLong if more than
// hdr.Size bytes are written after WriteHeader.
diff --git a/src/archive/tar/writer_test.go b/src/archive/tar/writer_test.go
index 27aa8e5..d88b8f4 100644
--- a/src/archive/tar/writer_test.go
+++ b/src/archive/tar/writer_test.go
@@ -9,7 +9,6 @@ import (
"fmt"
"io"
"io/ioutil"
- "math"
"os"
"reflect"
"sort"
@@ -19,176 +18,6 @@ import (
"time"
)
-type writerTestEntry struct {
- header *Header
- contents string
-}
-
-type writerTest struct {
- file string // filename of expected output
- entries []*writerTestEntry
-}
-
-var writerTests = []*writerTest{
- // The writer test file was produced with this command:
- // tar (GNU tar) 1.26
- // ln -s small.txt link.txt
- // tar -b 1 --format=ustar -c -f writer.tar small.txt small2.txt link.txt
- {
- file: "testdata/writer.tar",
- entries: []*writerTestEntry{
- {
- header: &Header{
- Name: "small.txt",
- Mode: 0640,
- Uid: 73025,
- Gid: 5000,
- Size: 5,
- ModTime: time.Unix(1246508266, 0),
- Typeflag: '0',
- Uname: "dsymonds",
- Gname: "eng",
- },
- contents: "Kilts",
- },
- {
- header: &Header{
- Name: "small2.txt",
- Mode: 0640,
- Uid: 73025,
- Gid: 5000,
- Size: 11,
- ModTime: time.Unix(1245217492, 0),
- Typeflag: '0',
- Uname: "dsymonds",
- Gname: "eng",
- },
- contents: "Google.com\n",
- },
- {
- header: &Header{
- Name: "link.txt",
- Mode: 0777,
- Uid: 1000,
- Gid: 1000,
- Size: 0,
- ModTime: time.Unix(1314603082, 0),
- Typeflag: '2',
- Linkname: "small.txt",
- Uname: "strings",
- Gname: "strings",
- },
- // no contents
- },
- },
- },
- // The truncated test file was produced using these commands:
- // dd if=/dev/zero bs=1048576 count=16384 > /tmp/16gig.txt
- // tar -b 1 -c -f- /tmp/16gig.txt | dd bs=512 count=8 > writer-big.tar
- {
- file: "testdata/writer-big.tar",
- entries: []*writerTestEntry{
- {
- header: &Header{
- Name: "tmp/16gig.txt",
- Mode: 0640,
- Uid: 73025,
- Gid: 5000,
- Size: 16 << 30,
- ModTime: time.Unix(1254699560, 0),
- Typeflag: '0',
- Uname: "dsymonds",
- Gname: "eng",
- },
- // fake contents
- contents: strings.Repeat("\x00", 4<<10),
- },
- },
- },
- // The truncated test file was produced using these commands:
- // dd if=/dev/zero bs=1048576 count=16384 > (longname/)*15 /16gig.txt
- // tar -b 1 -c -f- (longname/)*15 /16gig.txt | dd bs=512 count=8 > writer-big-long.tar
- {
- file: "testdata/writer-big-long.tar",
- entries: []*writerTestEntry{
- {
- header: &Header{
- Name: strings.Repeat("longname/", 15) + "16gig.txt",
- Mode: 0644,
- Uid: 1000,
- Gid: 1000,
- Size: 16 << 30,
- ModTime: time.Unix(1399583047, 0),
- Typeflag: '0',
- Uname: "guillaume",
- Gname: "guillaume",
- },
- // fake contents
- contents: strings.Repeat("\x00", 4<<10),
- },
- },
- },
- // This file was produced using gnu tar 1.17
- // gnutar -b 4 --format=ustar (longname/)*15 + file.txt
- {
- file: "testdata/ustar.tar",
- entries: []*writerTestEntry{
- {
- header: &Header{
- Name: strings.Repeat("longname/", 15) + "file.txt",
- Mode: 0644,
- Uid: 0765,
- Gid: 024,
- Size: 06,
- ModTime: time.Unix(1360135598, 0),
- Typeflag: '0',
- Uname: "shane",
- Gname: "staff",
- },
- contents: "hello\n",
- },
- },
- },
- // This file was produced using gnu tar 1.26
- // echo "Slartibartfast" > file.txt
- // ln file.txt hard.txt
- // tar -b 1 --format=ustar -c -f hardlink.tar file.txt hard.txt
- {
- file: "testdata/hardlink.tar",
- entries: []*writerTestEntry{
- {
- header: &Header{
- Name: "file.txt",
- Mode: 0644,
- Uid: 1000,
- Gid: 100,
- Size: 15,
- ModTime: time.Unix(1425484303, 0),
- Typeflag: '0',
- Uname: "vbatts",
- Gname: "users",
- },
- contents: "Slartibartfast\n",
- },
- {
- header: &Header{
- Name: "hard.txt",
- Mode: 0644,
- Uid: 1000,
- Gid: 100,
- Size: 0,
- ModTime: time.Unix(1425484303, 0),
- Typeflag: '1',
- Linkname: "file.txt",
- Uname: "vbatts",
- Gname: "users",
- },
- // no contents
- },
- },
- },
-}
-
// Render byte array in a two-character hexadecimal string, spaced for easy visual inspection.
func bytestr(offset int, b []byte) string {
const rowLen = 32
@@ -228,9 +57,168 @@ func bytediff(a []byte, b []byte) string {
}
func TestWriter(t *testing.T) {
+ type entry struct {
+ header *Header
+ contents string
+ }
+
+ vectors := []struct {
+ file string // filename of expected output
+ entries []*entry
+ }{{
+ // The writer test file was produced with this command:
+ // tar (GNU tar) 1.26
+ // ln -s small.txt link.txt
+ // tar -b 1 --format=ustar -c -f writer.tar small.txt small2.txt link.txt
+ file: "testdata/writer.tar",
+ entries: []*entry{{
+ header: &Header{
+ Name: "small.txt",
+ Mode: 0640,
+ Uid: 73025,
+ Gid: 5000,
+ Size: 5,
+ ModTime: time.Unix(1246508266, 0),
+ Typeflag: '0',
+ Uname: "dsymonds",
+ Gname: "eng",
+ },
+ contents: "Kilts",
+ }, {
+ header: &Header{
+ Name: "small2.txt",
+ Mode: 0640,
+ Uid: 73025,
+ Gid: 5000,
+ Size: 11,
+ ModTime: time.Unix(1245217492, 0),
+ Typeflag: '0',
+ Uname: "dsymonds",
+ Gname: "eng",
+ },
+ contents: "Google.com\n",
+ }, {
+ header: &Header{
+ Name: "link.txt",
+ Mode: 0777,
+ Uid: 1000,
+ Gid: 1000,
+ Size: 0,
+ ModTime: time.Unix(1314603082, 0),
+ Typeflag: '2',
+ Linkname: "small.txt",
+ Uname: "strings",
+ Gname: "strings",
+ },
+ // no contents
+ }},
+ }, {
+ // The truncated test file was produced using these commands:
+ // dd if=/dev/zero bs=1048576 count=16384 > /tmp/16gig.txt
+ // tar -b 1 -c -f- /tmp/16gig.txt | dd bs=512 count=8 > writer-big.tar
+ file: "testdata/writer-big.tar",
+ entries: []*entry{{
+ header: &Header{
+ Name: "tmp/16gig.txt",
+ Mode: 0640,
+ Uid: 73025,
+ Gid: 5000,
+ Size: 16 << 30,
+ ModTime: time.Unix(1254699560, 0),
+ Typeflag: '0',
+ Uname: "dsymonds",
+ Gname: "eng",
+ },
+ // fake contents
+ contents: strings.Repeat("\x00", 4<<10),
+ }},
+ }, {
+ // This truncated file was produced using this library.
+ // It was verified to work with GNU tar 1.27.1 and BSD tar 3.1.2.
+ // dd if=/dev/zero bs=1G count=16 >> writer-big-long.tar
+ // gnutar -xvf writer-big-long.tar
+ // bsdtar -xvf writer-big-long.tar
+ //
+ // This file is in PAX format.
+ file: "testdata/writer-big-long.tar",
+ entries: []*entry{{
+ header: &Header{
+ Name: strings.Repeat("longname/", 15) + "16gig.txt",
+ Mode: 0644,
+ Uid: 1000,
+ Gid: 1000,
+ Size: 16 << 30,
+ ModTime: time.Unix(1399583047, 0),
+ Typeflag: '0',
+ Uname: "guillaume",
+ Gname: "guillaume",
+ },
+ // fake contents
+ contents: strings.Repeat("\x00", 4<<10),
+ }},
+ }, {
+ // TODO(dsnet): The Writer output should match the following file.
+ // To fix an issue (see https://golang.org/issue/12594), we disabled
+ // prefix support, which alters the generated output.
+ /*
+ // This file was produced using gnu tar 1.17
+ // gnutar -b 4 --format=ustar (longname/)*15 + file.txt
+ file: "testdata/ustar.tar"
+ */
+ file: "testdata/ustar.issue12594.tar", // This is a valid tar file, but not expected
+ entries: []*entry{{
+ header: &Header{
+ Name: strings.Repeat("longname/", 15) + "file.txt",
+ Mode: 0644,
+ Uid: 0765,
+ Gid: 024,
+ Size: 06,
+ ModTime: time.Unix(1360135598, 0),
+ Typeflag: '0',
+ Uname: "shane",
+ Gname: "staff",
+ },
+ contents: "hello\n",
+ }},
+ }, {
+ // This file was produced using gnu tar 1.26
+ // echo "Slartibartfast" > file.txt
+ // ln file.txt hard.txt
+ // tar -b 1 --format=ustar -c -f hardlink.tar file.txt hard.txt
+ file: "testdata/hardlink.tar",
+ entries: []*entry{{
+ header: &Header{
+ Name: "file.txt",
+ Mode: 0644,
+ Uid: 1000,
+ Gid: 100,
+ Size: 15,
+ ModTime: time.Unix(1425484303, 0),
+ Typeflag: '0',
+ Uname: "vbatts",
+ Gname: "users",
+ },
+ contents: "Slartibartfast\n",
+ }, {
+ header: &Header{
+ Name: "hard.txt",
+ Mode: 0644,
+ Uid: 1000,
+ Gid: 100,
+ Size: 0,
+ ModTime: time.Unix(1425484303, 0),
+ Typeflag: '1',
+ Linkname: "file.txt",
+ Uname: "vbatts",
+ Gname: "users",
+ },
+ // no contents
+ }},
+ }}
+
testLoop:
- for i, test := range writerTests {
- expected, err := ioutil.ReadFile(test.file)
+ for i, v := range vectors {
+ expected, err := ioutil.ReadFile(v.file)
if err != nil {
t.Errorf("test %d: Unexpected error: %v", i, err)
continue
@@ -239,7 +227,7 @@ testLoop:
buf := new(bytes.Buffer)
tw := NewWriter(iotest.TruncateWriter(buf, 4<<10)) // only catch the first 4 KB
big := false
- for j, entry := range test.entries {
+ for j, entry := range v.entries {
big = big || entry.header.Size > 1<<10
if err := tw.WriteHeader(entry.header); err != nil {
t.Errorf("test %d, entry %d: Failed writing header: %v", i, j, err)
@@ -576,9 +564,9 @@ func TestWriteAfterClose(t *testing.T) {
}
func TestSplitUSTARPath(t *testing.T) {
- var sr = strings.Repeat
+ sr := strings.Repeat
- var vectors = []struct {
+ vectors := []struct {
input string // Input path
prefix string // Expected output prefix
suffix string // Expected output suffix
@@ -609,114 +597,51 @@ func TestSplitUSTARPath(t *testing.T) {
}
}
-func TestFormatPAXRecord(t *testing.T) {
- var medName = strings.Repeat("CD", 50)
- var longName = strings.Repeat("AB", 100)
-
- var vectors = []struct {
- inputKey string
- inputVal string
- output string
- }{
- {"k", "v", "6 k=v\n"},
- {"path", "/etc/hosts", "19 path=/etc/hosts\n"},
- {"path", longName, "210 path=" + longName + "\n"},
- {"path", medName, "110 path=" + medName + "\n"},
- {"foo", "ba", "9 foo=ba\n"},
- {"foo", "bar", "11 foo=bar\n"},
- {"foo", "b=\nar=\n==\x00", "18 foo=b=\nar=\n==\x00\n"},
- {"foo", "hello9 foo=ba\nworld", "27 foo=hello9 foo=ba\nworld\n"},
- {"☺☻☹", "日a本b語ç", "27 ☺☻☹=日a本b語ç\n"},
- {"\x00hello", "\x00world", "17 \x00hello=\x00world\n"},
- }
-
- for _, v := range vectors {
- output := formatPAXRecord(v.inputKey, v.inputVal)
- if output != v.output {
- t.Errorf("formatPAXRecord(%q, %q): got %q, want %q",
- v.inputKey, v.inputVal, output, v.output)
+// TestIssue12594 tests that the Writer does not attempt to populate the prefix
+// field when encoding a header in the GNU format. The prefix field is valid
+// in USTAR and PAX, but not GNU.
+func TestIssue12594(t *testing.T) {
+ names := []string{
+ "0/1/2/3/4/5/6/7/8/9/10/11/12/13/14/15/16/17/18/19/20/21/22/23/24/25/26/27/28/29/30/file.txt",
+ "0/1/2/3/4/5/6/7/8/9/10/11/12/13/14/15/16/17/18/19/20/21/22/23/24/25/26/27/28/29/30/31/32/33/file.txt",
+ "0/1/2/3/4/5/6/7/8/9/10/11/12/13/14/15/16/17/18/19/20/21/22/23/24/25/26/27/28/29/30/31/32/333/file.txt",
+ "0/1/2/3/4/5/6/7/8/9/10/11/12/13/14/15/16/17/18/19/20/21/22/23/24/25/26/27/28/29/30/31/32/33/34/35/36/37/38/39/40/file.txt",
+ "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000/file.txt",
+ "/home/support/.openoffice.org/3/user/uno_packages/cache/registry/com.sun.star.comp.deployment.executable.PackageRegistryBackend",
+ }
+
+ for i, name := range names {
+ var b bytes.Buffer
+
+ tw := NewWriter(&b)
+ if err := tw.WriteHeader(&Header{
+ Name: name,
+ Uid: 1 << 25, // Prevent USTAR format
+ }); err != nil {
+ t.Errorf("test %d, unexpected WriteHeader error: %v", i, err)
}
- }
-}
-
-func TestFitsInBase256(t *testing.T) {
- var vectors = []struct {
- input int64
- width int
- ok bool
- }{
- {+1, 8, true},
- {0, 8, true},
- {-1, 8, true},
- {1 << 56, 8, false},
- {(1 << 56) - 1, 8, true},
- {-1 << 56, 8, true},
- {(-1 << 56) - 1, 8, false},
- {121654, 8, true},
- {-9849849, 8, true},
- {math.MaxInt64, 9, true},
- {0, 9, true},
- {math.MinInt64, 9, true},
- {math.MaxInt64, 12, true},
- {0, 12, true},
- {math.MinInt64, 12, true},
- }
-
- for _, v := range vectors {
- ok := fitsInBase256(v.width, v.input)
- if ok != v.ok {
- t.Errorf("checkNumeric(%d, %d): got %v, want %v", v.input, v.width, ok, v.ok)
+ if err := tw.Close(); err != nil {
+ t.Errorf("test %d, unexpected Close error: %v", i, err)
}
- }
-}
-func TestFormatNumeric(t *testing.T) {
- var vectors = []struct {
- input int64
- output string
- ok bool
- }{
- // Test base-256 (binary) encoded values.
- {-1, "\xff", true},
- {-1, "\xff\xff", true},
- {-1, "\xff\xff\xff", true},
- {(1 << 0), "0", false},
- {(1 << 8) - 1, "\x80\xff", true},
- {(1 << 8), "0\x00", false},
- {(1 << 16) - 1, "\x80\xff\xff", true},
- {(1 << 16), "00\x00", false},
- {-1 * (1 << 0), "\xff", true},
- {-1*(1<<0) - 1, "0", false},
- {-1 * (1 << 8), "\xff\x00", true},
- {-1*(1<<8) - 1, "0\x00", false},
- {-1 * (1 << 16), "\xff\x00\x00", true},
- {-1*(1<<16) - 1, "00\x00", false},
- {537795476381659745, "0000000\x00", false},
- {537795476381659745, "\x80\x00\x00\x00\x07\x76\xa2\x22\xeb\x8a\x72\x61", true},
- {-615126028225187231, "0000000\x00", false},
- {-615126028225187231, "\xff\xff\xff\xff\xf7\x76\xa2\x22\xeb\x8a\x72\x61", true},
- {math.MaxInt64, "0000000\x00", false},
- {math.MaxInt64, "\x80\x00\x00\x00\x7f\xff\xff\xff\xff\xff\xff\xff", true},
- {math.MinInt64, "0000000\x00", false},
- {math.MinInt64, "\xff\xff\xff\xff\x80\x00\x00\x00\x00\x00\x00\x00", true},
- {math.MaxInt64, "\x80\x7f\xff\xff\xff\xff\xff\xff\xff", true},
- {math.MinInt64, "\xff\x80\x00\x00\x00\x00\x00\x00\x00", true},
- }
+ // The prefix field should never appear in the GNU format.
+ var blk block
+ copy(blk[:], b.Bytes())
+ prefix := string(blk.USTAR().Prefix())
+ if i := strings.IndexByte(prefix, 0); i >= 0 {
+ prefix = prefix[:i] // Truncate at the NUL terminator
+ }
+ if blk.GetFormat() == formatGNU && len(prefix) > 0 && strings.HasPrefix(name, prefix) {
+ t.Errorf("test %d, found prefix in GNU format: %s", i, prefix)
+ }
- for _, v := range vectors {
- var f formatter
- output := make([]byte, len(v.output))
- f.formatNumeric(output, v.input)
- ok := (f.err == nil)
- if ok != v.ok {
- if v.ok {
- t.Errorf("formatNumeric(%d): got formatting failure, want success", v.input)
- } else {
- t.Errorf("formatNumeric(%d): got formatting success, want failure", v.input)
- }
+ tr := NewReader(&b)
+ hdr, err := tr.Next()
+ if err != nil {
+ t.Errorf("test %d, unexpected Next error: %v", i, err)
}
- if string(output) != v.output {
- t.Errorf("formatNumeric(%d): got %q, want %q", v.input, output, v.output)
+ if hdr.Name != name {
+ t.Errorf("test %d, hdr.Name = %s, want %s", i, hdr.Name, name)
}
}
}
diff --git a/src/archive/zip/reader.go b/src/archive/zip/reader.go
index f6c3ead..9bbc9a9 100644
--- a/src/archive/zip/reader.go
+++ b/src/archive/zip/reader.go
@@ -13,6 +13,7 @@ import (
"hash/crc32"
"io"
"os"
+ "time"
)
var (
@@ -289,13 +290,16 @@ func readDirectoryHeader(f *File, r io.Reader) error {
// Other zip authors might not even follow the basic format,
// and we'll just ignore the Extra content in that case.
b := readBuf(f.Extra)
+
+ Extras:
for len(b) >= 4 { // need at least tag and size
tag := b.uint16()
size := b.uint16()
if int(size) > len(b) {
break
}
- if tag == zip64ExtraId {
+ switch tag {
+ case zip64ExtraId:
// update directory values from the zip64 extra block.
// They should only be consulted if the sizes read earlier
// are maxed out.
@@ -323,7 +327,42 @@ func readDirectoryHeader(f *File, r io.Reader) error {
}
f.headerOffset = int64(eb.uint64())
}
- break
+ break Extras
+
+ case ntfsExtraId:
+ if size == 32 {
+ eb := readBuf(b[:size])
+ eb.uint32() // reserved
+ eb.uint16() // tag1
+ size1 := eb.uint16()
+ if size1 == 24 {
+ sub := readBuf(eb[:size1])
+ lo := sub.uint32()
+ hi := sub.uint32()
+ tick := (uint64(uint64(lo)|uint64(hi)<<32) - 116444736000000000) / 10000000
+ f.SetModTime(time.Unix(int64(tick), 0))
+ }
+ }
+ break Extras
+
+ case unixExtraId:
+ if size >= 12 {
+ eb := readBuf(b[:size])
+ eb.uint32() // AcTime
+ epoch := eb.uint32() // ModTime
+ f.SetModTime(time.Unix(int64(epoch), 0))
+ break Extras
+ }
+ case exttsExtraId:
+ if size >= 3 {
+ eb := readBuf(b[:size])
+ flags := eb.uint8() // Flags
+ epoch := eb.uint32() // AcTime/ModTime/CrTime
+ if flags&1 != 0 {
+ f.SetModTime(time.Unix(int64(epoch), 0))
+ }
+ break Extras
+ }
}
b = b[size:]
}
@@ -508,6 +547,12 @@ func findSignatureInBlock(b []byte) int {
type readBuf []byte
+func (b *readBuf) uint8() uint8 {
+ v := uint8((*b)[0])
+ *b = (*b)[1:]
+ return v
+}
+
func (b *readBuf) uint16() uint16 {
v := binary.LittleEndian.Uint16(*b)
*b = (*b)[2:]
diff --git a/src/archive/zip/reader_test.go b/src/archive/zip/reader_test.go
index dfaae78..576a169 100644
--- a/src/archive/zip/reader_test.go
+++ b/src/archive/zip/reader_test.go
@@ -65,13 +65,13 @@ var tests = []ZipTest{
{
Name: "test.txt",
Content: []byte("This is a test text file.\n"),
- Mtime: "09-05-10 12:12:02",
+ Mtime: "09-05-10 02:12:00",
Mode: 0644,
},
{
Name: "gophercolor16x16.png",
File: "gophercolor16x16.png",
- Mtime: "09-05-10 15:52:58",
+ Mtime: "09-05-10 05:52:58",
Mode: 0644,
},
},
@@ -83,13 +83,13 @@ var tests = []ZipTest{
{
Name: "test.txt",
Content: []byte("This is a test text file.\n"),
- Mtime: "09-05-10 12:12:02",
+ Mtime: "09-05-10 02:12:00",
Mode: 0644,
},
{
Name: "gophercolor16x16.png",
File: "gophercolor16x16.png",
- Mtime: "09-05-10 15:52:58",
+ Mtime: "09-05-10 05:52:58",
Mode: 0644,
},
},
@@ -145,6 +145,17 @@ var tests = []ZipTest{
File: crossPlatform,
},
{
+ Name: "extra-timestamp.zip",
+ File: []ZipTestFile{
+ {
+ Name: "hello.txt",
+ Content: []byte(""),
+ Mtime: "01-06-16 12:25:56",
+ Mode: 0666,
+ },
+ },
+ },
+ {
// created by Go, before we wrote the "optional" data
// descriptor signatures (which are required by OS X)
Name: "go-no-datadesc-sig.zip",
@@ -152,13 +163,13 @@ var tests = []ZipTest{
{
Name: "foo.txt",
Content: []byte("foo\n"),
- Mtime: "03-08-12 16:59:10",
+ Mtime: "03-09-12 00:59:10",
Mode: 0644,
},
{
Name: "bar.txt",
Content: []byte("bar\n"),
- Mtime: "03-08-12 16:59:12",
+ Mtime: "03-09-12 00:59:12",
Mode: 0644,
},
},
@@ -205,13 +216,13 @@ var tests = []ZipTest{
{
Name: "foo.txt",
Content: []byte("foo\n"),
- Mtime: "03-08-12 16:59:10",
+ Mtime: "03-09-12 00:59:10",
Mode: 0644,
},
{
Name: "bar.txt",
Content: []byte("bar\n"),
- Mtime: "03-08-12 16:59:12",
+ Mtime: "03-09-12 00:59:12",
Mode: 0644,
},
},
@@ -225,14 +236,14 @@ var tests = []ZipTest{
{
Name: "foo.txt",
Content: []byte("foo\n"),
- Mtime: "03-08-12 16:59:10",
+ Mtime: "03-09-12 00:59:10",
Mode: 0644,
ContentErr: ErrChecksum,
},
{
Name: "bar.txt",
Content: []byte("bar\n"),
- Mtime: "03-08-12 16:59:12",
+ Mtime: "03-09-12 00:59:12",
Mode: 0644,
},
},
diff --git a/src/archive/zip/struct.go b/src/archive/zip/struct.go
index e92d02f..287571e 100644
--- a/src/archive/zip/struct.go
+++ b/src/archive/zip/struct.go
@@ -63,6 +63,9 @@ const (
// extra header id's
zip64ExtraId = 0x0001 // zip64 Extended Information Extra Field
+ ntfsExtraId = 0x000a // NTFS Extra Field
+ unixExtraId = 0x000d // UNIX Extra Field
+ exttsExtraId = 0x5455 // Extended Timestamp Extra Field
)
// FileHeader describes a file within a zip file.
diff --git a/src/archive/zip/testdata/extra-timestamp.zip b/src/archive/zip/testdata/extra-timestamp.zip
new file mode 100644
index 0000000..819e22c
Binary files /dev/null and b/src/archive/zip/testdata/extra-timestamp.zip differ
diff --git a/src/archive/zip/writer.go b/src/archive/zip/writer.go
index 3a9292e..ea4559e 100644
--- a/src/archive/zip/writer.go
+++ b/src/archive/zip/writer.go
@@ -22,6 +22,10 @@ type Writer struct {
last *fileWriter
closed bool
compressors map[uint16]Compressor
+
+ // testHookCloseSizeOffset if non-nil is called with the size
+ // of offset of the central directory at Close.
+ testHookCloseSizeOffset func(size, offset uint64)
}
type header struct {
@@ -98,6 +102,19 @@ func (w *Writer) Close() error {
b.uint32(h.CompressedSize)
b.uint32(h.UncompressedSize)
}
+
+ // use Extended Timestamp Extra Field.
+ if h.ModifiedTime != 0 || h.ModifiedDate != 0 {
+ mt := uint32(h.ModTime().Unix())
+ var mbuf [9]byte // 2x uint16 + uint8 + uint32
+ eb := writeBuf(mbuf[:])
+ eb.uint16(exttsExtraId)
+ eb.uint16(5) // size = uint8 + uint32
+ eb.uint8(1) // flags = modtime
+ eb.uint32(mt) // ModTime
+ h.Extra = append(h.Extra, mbuf[:]...)
+ }
+
b.uint16(uint16(len(h.Name)))
b.uint16(uint16(len(h.Extra)))
b.uint16(uint16(len(h.Comment)))
@@ -127,7 +144,11 @@ func (w *Writer) Close() error {
size := uint64(end - start)
offset := uint64(start)
- if records > uint16max || size > uint32max || offset > uint32max {
+ if f := w.testHookCloseSizeOffset; f != nil {
+ f(size, offset)
+ }
+
+ if records >= uint16max || size >= uint32max || offset >= uint32max {
var buf [directory64EndLen + directory64LocLen]byte
b := writeBuf(buf[:])
@@ -376,6 +397,11 @@ func (w nopCloser) Close() error {
type writeBuf []byte
+func (b *writeBuf) uint8(v uint8) {
+ (*b)[0] = v
+ *b = (*b)[1:]
+}
+
func (b *writeBuf) uint16(v uint16) {
binary.LittleEndian.PutUint16(*b, v)
*b = (*b)[2:]
diff --git a/src/archive/zip/writer_test.go b/src/archive/zip/writer_test.go
index 86841c7..f20daa0 100644
--- a/src/archive/zip/writer_test.go
+++ b/src/archive/zip/writer_test.go
@@ -11,6 +11,7 @@ import (
"math/rand"
"os"
"testing"
+ "time"
)
// TODO(adg): a more sophisticated test suite
@@ -20,6 +21,7 @@ type WriteTest struct {
Data []byte
Method uint16
Mode os.FileMode
+ Mtime string
}
var writeTests = []WriteTest{
@@ -28,30 +30,35 @@ var writeTests = []WriteTest{
Data: []byte("Rabbits, guinea pigs, gophers, marsupial rats, and quolls."),
Method: Store,
Mode: 0666,
+ Mtime: "02-01-08 00:01:02",
},
{
Name: "bar",
Data: nil, // large data set in the test
Method: Deflate,
Mode: 0644,
+ Mtime: "03-02-08 01:02:03",
},
{
Name: "setuid",
Data: []byte("setuid file"),
Method: Deflate,
Mode: 0755 | os.ModeSetuid,
+ Mtime: "04-03-08 02:03:04",
},
{
Name: "setgid",
Data: []byte("setgid file"),
Method: Deflate,
Mode: 0755 | os.ModeSetgid,
+ Mtime: "05-04-08 03:04:04",
},
{
Name: "symlink",
Data: []byte("../link/target"),
Method: Deflate,
Mode: 0755 | os.ModeSymlink,
+ Mtime: "03-02-08 11:22:33",
},
}
@@ -148,6 +155,11 @@ func testCreate(t *testing.T, w *Writer, wt *WriteTest) {
if wt.Mode != 0 {
header.SetMode(wt.Mode)
}
+ mtime, err := time.Parse("01-02-06 15:04:05", wt.Mtime)
+ if err != nil {
+ t.Fatal("time.Parse:", err)
+ }
+ header.SetModTime(mtime)
f, err := w.CreateHeader(header)
if err != nil {
t.Fatal(err)
@@ -178,6 +190,21 @@ func testReadFile(t *testing.T, f *File, wt *WriteTest) {
if !bytes.Equal(b, wt.Data) {
t.Errorf("File contents %q, want %q", b, wt.Data)
}
+
+ mtime, err := time.Parse("01-02-06 15:04:05", wt.Mtime)
+ if err != nil {
+ t.Fatal("time.Parse:", err)
+ }
+
+ diff := mtime.Sub(f.ModTime())
+ if diff < 0 {
+ diff = -diff
+ }
+
+ // allow several time span
+ if diff > 5*time.Second {
+ t.Errorf("File modtime %v, want %v", mtime, f.ModTime())
+ }
}
func BenchmarkCompressedZipGarbage(b *testing.B) {
diff --git a/src/archive/zip/zip_test.go b/src/archive/zip/zip_test.go
index 3a3c915..8801e90 100644
--- a/src/archive/zip/zip_test.go
+++ b/src/archive/zip/zip_test.go
@@ -8,11 +8,14 @@ package zip
import (
"bytes"
+ "errors"
"fmt"
"hash"
+ "internal/race"
"internal/testenv"
"io"
"io/ioutil"
+ "reflect"
"sort"
"strings"
"testing"
@@ -111,6 +114,44 @@ func TestFileHeaderRoundTrip64(t *testing.T) {
testHeaderRoundTrip(fh, uint32max, fh.UncompressedSize64, t)
}
+func TestZeroFileRoundTrip(t *testing.T) {
+ var b bytes.Buffer
+ w := NewWriter(&b)
+ if _, err := w.Create(""); err != nil {
+ t.Fatal(err)
+ }
+ if err := w.Close(); err != nil {
+ t.Fatal(err)
+ }
+ r, err := NewReader(bytes.NewReader(b.Bytes()), int64(b.Len()))
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // Verify that fields that should reasonably be the zero value stays
+ // as the zero value.
+ var want FileHeader
+ if len(r.File) != 1 {
+ t.Fatalf("len(r.File) = %d, want 1", len(r.File))
+ }
+ fh := r.File[0].FileHeader
+ got := FileHeader{
+ Name: fh.Name,
+ ModifiedTime: fh.ModifiedTime,
+ ModifiedDate: fh.ModifiedDate,
+ UncompressedSize: fh.UncompressedSize,
+ UncompressedSize64: fh.UncompressedSize64,
+ ExternalAttrs: fh.ExternalAttrs,
+ Comment: fh.Comment,
+ }
+ if len(fh.Extra) > 0 {
+ got.Extra = fh.Extra
+ }
+ if !reflect.DeepEqual(got, want) {
+ t.Errorf("FileHeader mismatch:\ngot %#v\nwant %#v", got, want)
+ }
+}
+
type repeatedByte struct {
off int64
b byte
@@ -232,6 +273,7 @@ func TestZip64(t *testing.T) {
if testing.Short() {
t.Skip("slow test; skipping")
}
+ t.Parallel()
const size = 1 << 32 // before the "END\n" part
buf := testZip64(t, size)
testZip64DirectoryRecordLength(buf, t)
@@ -241,6 +283,7 @@ func TestZip64EdgeCase(t *testing.T) {
if testing.Short() {
t.Skip("slow test; skipping")
}
+ t.Parallel()
// Test a zip file with uncompressed size 0xFFFFFFFF.
// That's the magic marker for a 64-bit file, so even though
// it fits in a 32-bit field we must use the 64-bit field.
@@ -251,6 +294,256 @@ func TestZip64EdgeCase(t *testing.T) {
testZip64DirectoryRecordLength(buf, t)
}
+// Tests that we generate a zip64 file if the the directory at offset
+// 0xFFFFFFFF, but not before.
+func TestZip64DirectoryOffset(t *testing.T) {
+ if testing.Short() && race.Enabled {
+ t.Skip("skipping in short mode")
+ }
+ t.Parallel()
+ const filename = "huge.txt"
+ gen := func(wantOff uint64) func(*Writer) {
+ return func(w *Writer) {
+ w.testHookCloseSizeOffset = func(size, off uint64) {
+ if off != wantOff {
+ t.Errorf("central directory offset = %d (%x); want %d", off, off, wantOff)
+ }
+ }
+ f, err := w.CreateHeader(&FileHeader{
+ Name: filename,
+ Method: Store,
+ })
+ if err != nil {
+ t.Fatal(err)
+ }
+ f.(*fileWriter).crc32 = fakeHash32{}
+ size := wantOff - fileHeaderLen - uint64(len(filename)) - dataDescriptorLen
+ if _, err := io.CopyN(f, zeros{}, int64(size)); err != nil {
+ t.Fatal(err)
+ }
+ if err := w.Close(); err != nil {
+ t.Fatal(err)
+ }
+ }
+ }
+ t.Run("uint32max-2_NoZip64", func(t *testing.T) {
+ t.Parallel()
+ if generatesZip64(t, gen(0xfffffffe)) {
+ t.Error("unexpected zip64")
+ }
+ })
+ t.Run("uint32max-1_Zip64", func(t *testing.T) {
+ t.Parallel()
+ if !generatesZip64(t, gen(0xffffffff)) {
+ t.Error("expected zip64")
+ }
+ })
+}
+
+// At 16k records, we need to generate a zip64 file.
+func TestZip64ManyRecords(t *testing.T) {
+ if testing.Short() && race.Enabled {
+ t.Skip("skipping in short mode")
+ }
+ t.Parallel()
+ gen := func(numRec int) func(*Writer) {
+ return func(w *Writer) {
+ for i := 0; i < numRec; i++ {
+ _, err := w.CreateHeader(&FileHeader{
+ Name: "a.txt",
+ Method: Store,
+ })
+ if err != nil {
+ t.Fatal(err)
+ }
+ }
+ if err := w.Close(); err != nil {
+ t.Fatal(err)
+ }
+ }
+ }
+ // 16k-1 records shouldn't make a zip64:
+ t.Run("uint16max-1_NoZip64", func(t *testing.T) {
+ t.Parallel()
+ if generatesZip64(t, gen(0xfffe)) {
+ t.Error("unexpected zip64")
+ }
+ })
+ // 16k records should make a zip64:
+ t.Run("uint16max_Zip64", func(t *testing.T) {
+ t.Parallel()
+ if !generatesZip64(t, gen(0xffff)) {
+ t.Error("expected zip64")
+ }
+ })
+}
+
+// suffixSaver is an io.Writer & io.ReaderAt that remembers the last 0
+// to 'keep' bytes of data written to it. Call Suffix to get the
+// suffix bytes.
+type suffixSaver struct {
+ keep int
+ buf []byte
+ start int
+ size int64
+}
+
+func (ss *suffixSaver) Size() int64 { return ss.size }
+
+var errDiscardedBytes = errors.New("ReadAt of discarded bytes")
+
+func (ss *suffixSaver) ReadAt(p []byte, off int64) (n int, err error) {
+ back := ss.size - off
+ if back > int64(ss.keep) {
+ return 0, errDiscardedBytes
+ }
+ suf := ss.Suffix()
+ n = copy(p, suf[len(suf)-int(back):])
+ if n != len(p) {
+ err = io.EOF
+ }
+ return
+}
+
+func (ss *suffixSaver) Suffix() []byte {
+ if len(ss.buf) < ss.keep {
+ return ss.buf
+ }
+ buf := make([]byte, ss.keep)
+ n := copy(buf, ss.buf[ss.start:])
+ copy(buf[n:], ss.buf[:])
+ return buf
+}
+
+func (ss *suffixSaver) Write(p []byte) (n int, err error) {
+ n = len(p)
+ ss.size += int64(len(p))
+ if len(ss.buf) < ss.keep {
+ space := ss.keep - len(ss.buf)
+ add := len(p)
+ if add > space {
+ add = space
+ }
+ ss.buf = append(ss.buf, p[:add]...)
+ p = p[add:]
+ }
+ for len(p) > 0 {
+ n := copy(ss.buf[ss.start:], p)
+ p = p[n:]
+ ss.start += n
+ if ss.start == ss.keep {
+ ss.start = 0
+ }
+ }
+ return
+}
+
+// generatesZip64 reports whether f wrote a zip64 file.
+// f is also responsible for closing w.
+func generatesZip64(t *testing.T, f func(w *Writer)) bool {
+ ss := &suffixSaver{keep: 10 << 20}
+ w := NewWriter(ss)
+ f(w)
+ return suffixIsZip64(t, ss)
+}
+
+type sizedReaderAt interface {
+ io.ReaderAt
+ Size() int64
+}
+
+func suffixIsZip64(t *testing.T, zip sizedReaderAt) bool {
+ d := make([]byte, 1024)
+ if _, err := zip.ReadAt(d, zip.Size()-int64(len(d))); err != nil {
+ t.Fatalf("ReadAt: %v", err)
+ }
+
+ sigOff := findSignatureInBlock(d)
+ if sigOff == -1 {
+ t.Errorf("failed to find signature in block")
+ return false
+ }
+
+ dirOff, err := findDirectory64End(zip, zip.Size()-int64(len(d))+int64(sigOff))
+ if err != nil {
+ t.Fatalf("findDirectory64End: %v", err)
+ }
+ if dirOff == -1 {
+ return false
+ }
+
+ d = make([]byte, directory64EndLen)
+ if _, err := zip.ReadAt(d, dirOff); err != nil {
+ t.Fatalf("ReadAt(off=%d): %v", dirOff, err)
+ }
+
+ b := readBuf(d)
+ if sig := b.uint32(); sig != directory64EndSignature {
+ return false
+ }
+
+ size := b.uint64()
+ if size != directory64EndLen-12 {
+ t.Errorf("expected length of %d, got %d", directory64EndLen-12, size)
+ }
+ return true
+}
+
+// Zip64 is required if the total size of the records is uint32max.
+func TestZip64LargeDirectory(t *testing.T) {
+ if testing.Short() {
+ t.Skip("skipping in short mode")
+ }
+ t.Parallel()
+ // gen returns a func that writes a zip with a wantLen bytes
+ // of central directory.
+ gen := func(wantLen int64) func(*Writer) {
+ return func(w *Writer) {
+ w.testHookCloseSizeOffset = func(size, off uint64) {
+ if size != uint64(wantLen) {
+ t.Errorf("Close central directory size = %d; want %d", size, wantLen)
+ }
+ }
+
+ uint16string := strings.Repeat(".", uint16max)
+ remain := wantLen
+ for remain > 0 {
+ commentLen := int(uint16max) - directoryHeaderLen - 1
+ thisRecLen := directoryHeaderLen + int(uint16max) + commentLen
+ if int64(thisRecLen) > remain {
+ remove := thisRecLen - int(remain)
+ commentLen -= remove
+ thisRecLen -= remove
+ }
+ remain -= int64(thisRecLen)
+ f, err := w.CreateHeader(&FileHeader{
+ Name: uint16string,
+ Comment: uint16string[:commentLen],
+ })
+ if err != nil {
+ t.Fatalf("CreateHeader: %v", err)
+ }
+ f.(*fileWriter).crc32 = fakeHash32{}
+ }
+ if err := w.Close(); err != nil {
+ t.Fatalf("Close: %v", err)
+ }
+ }
+ }
+ t.Run("uint32max-1_NoZip64", func(t *testing.T) {
+ t.Parallel()
+ if generatesZip64(t, gen(uint32max-1)) {
+ t.Error("unexpected zip64")
+ }
+ })
+ t.Run("uint32max_HasZip64", func(t *testing.T) {
+ t.Parallel()
+ if !generatesZip64(t, gen(uint32max)) {
+ t.Error("expected zip64")
+ }
+ })
+}
+
func testZip64(t testing.TB, size int64) *rleBuffer {
const chunkSize = 1024
chunks := int(size / chunkSize)
@@ -339,30 +632,8 @@ func testZip64(t testing.TB, size int64) *rleBuffer {
// Issue 9857
func testZip64DirectoryRecordLength(buf *rleBuffer, t *testing.T) {
- d := make([]byte, 1024)
- if _, err := buf.ReadAt(d, buf.Size()-int64(len(d))); err != nil {
- t.Fatal("read:", err)
- }
-
- sigOff := findSignatureInBlock(d)
- dirOff, err := findDirectory64End(buf, buf.Size()-int64(len(d))+int64(sigOff))
- if err != nil {
- t.Fatal("findDirectory64End:", err)
- }
-
- d = make([]byte, directory64EndLen)
- if _, err := buf.ReadAt(d, dirOff); err != nil {
- t.Fatal("read:", err)
- }
-
- b := readBuf(d)
- if sig := b.uint32(); sig != directory64EndSignature {
- t.Fatalf("Expected directory64EndSignature (%d), got %d", directory64EndSignature, sig)
- }
-
- size := b.uint64()
- if size != directory64EndLen-12 {
- t.Fatalf("Expected length of %d, got %d", directory64EndLen-12, size)
+ if !suffixIsZip64(t, buf) {
+ t.Fatal("not a zip64")
}
}
@@ -448,3 +719,47 @@ func BenchmarkZip64Test(b *testing.B) {
testZip64(b, 1<<26)
}
}
+
+func TestSuffixSaver(t *testing.T) {
+ const keep = 10
+ ss := &suffixSaver{keep: keep}
+ ss.Write([]byte("abc"))
+ if got := string(ss.Suffix()); got != "abc" {
+ t.Errorf("got = %q; want abc", got)
+ }
+ ss.Write([]byte("defghijklmno"))
+ if got := string(ss.Suffix()); got != "fghijklmno" {
+ t.Errorf("got = %q; want fghijklmno", got)
+ }
+ if got, want := ss.Size(), int64(len("abc")+len("defghijklmno")); got != want {
+ t.Errorf("Size = %d; want %d", got, want)
+ }
+ buf := make([]byte, ss.Size())
+ for off := int64(0); off < ss.Size(); off++ {
+ for size := 1; size <= int(ss.Size()-off); size++ {
+ readBuf := buf[:size]
+ n, err := ss.ReadAt(readBuf, off)
+ if off < ss.Size()-keep {
+ if err != errDiscardedBytes {
+ t.Errorf("off %d, size %d = %v, %v (%q); want errDiscardedBytes", off, size, n, err, readBuf[:n])
+ }
+ continue
+ }
+ want := "abcdefghijklmno"[off : off+int64(size)]
+ got := string(readBuf[:n])
+ if err != nil || got != want {
+ t.Errorf("off %d, size %d = %v, %v (%q); want %q", off, size, n, err, got, want)
+ }
+ }
+ }
+
+}
+
+type zeros struct{}
+
+func (zeros) Read(p []byte) (int, error) {
+ for i := range p {
+ p[i] = 0
+ }
+ return len(p), nil
+}
diff --git a/src/bufio/bufio.go b/src/bufio/bufio.go
index 3b30b8b..e1e8fb2 100644
--- a/src/bufio/bufio.go
+++ b/src/bufio/bufio.go
@@ -206,10 +206,18 @@ func (b *Reader) Read(p []byte) (n int, err error) {
}
return n, b.readErr()
}
- b.fill() // buffer is empty
- if b.r == b.w {
+ // One read.
+ // Do not use b.fill, which will loop.
+ b.r = 0
+ b.w = 0
+ n, b.err = b.rd.Read(b.buf)
+ if n < 0 {
+ panic(errNegativeRead)
+ }
+ if n == 0 {
return 0, b.readErr()
}
+ b.w += n
}
// copy as much as we can
@@ -549,11 +557,6 @@ func (b *Writer) Reset(w io.Writer) {
// Flush writes any buffered data to the underlying io.Writer.
func (b *Writer) Flush() error {
- err := b.flush()
- return err
-}
-
-func (b *Writer) flush() error {
if b.err != nil {
return b.err
}
@@ -596,7 +599,7 @@ func (b *Writer) Write(p []byte) (nn int, err error) {
} else {
n = copy(b.buf[b.n:], p)
b.n += n
- b.flush()
+ b.Flush()
}
nn += n
p = p[n:]
@@ -615,7 +618,7 @@ func (b *Writer) WriteByte(c byte) error {
if b.err != nil {
return b.err
}
- if b.Available() <= 0 && b.flush() != nil {
+ if b.Available() <= 0 && b.Flush() != nil {
return b.err
}
b.buf[b.n] = c
@@ -638,7 +641,7 @@ func (b *Writer) WriteRune(r rune) (size int, err error) {
}
n := b.Available()
if n < utf8.UTFMax {
- if b.flush(); b.err != nil {
+ if b.Flush(); b.err != nil {
return 0, b.err
}
n = b.Available()
@@ -663,7 +666,7 @@ func (b *Writer) WriteString(s string) (int, error) {
b.n += n
nn += n
s = s[n:]
- b.flush()
+ b.Flush()
}
if b.err != nil {
return nn, b.err
@@ -684,7 +687,7 @@ func (b *Writer) ReadFrom(r io.Reader) (n int64, err error) {
var m int
for {
if b.Available() == 0 {
- if err1 := b.flush(); err1 != nil {
+ if err1 := b.Flush(); err1 != nil {
return n, err1
}
}
@@ -708,7 +711,7 @@ func (b *Writer) ReadFrom(r io.Reader) (n int64, err error) {
if err == io.EOF {
// If we filled the buffer exactly, flush preemptively.
if b.Available() == 0 {
- err = b.flush()
+ err = b.Flush()
} else {
err = nil
}
diff --git a/src/bufio/bufio_test.go b/src/bufio/bufio_test.go
index 8580486..ef0f6c8 100644
--- a/src/bufio/bufio_test.go
+++ b/src/bufio/bufio_test.go
@@ -1236,6 +1236,27 @@ func TestWriterReadFromErrNoProgress(t *testing.T) {
}
}
+func TestReadZero(t *testing.T) {
+ for _, size := range []int{100, 2} {
+ t.Run(fmt.Sprintf("bufsize=%d", size), func(t *testing.T) {
+ r := io.MultiReader(strings.NewReader("abc"), &emptyThenNonEmptyReader{r: strings.NewReader("def"), n: 1})
+ br := NewReaderSize(r, size)
+ want := func(s string, wantErr error) {
+ p := make([]byte, 50)
+ n, err := br.Read(p)
+ if err != wantErr || n != len(s) || string(p[:n]) != s {
+ t.Fatalf("read(%d) = %q, %v, want %q, %v", len(p), string(p[:n]), err, s, wantErr)
+ }
+ t.Logf("read(%d) = %q, %v", len(p), string(p[:n]), err)
+ }
+ want("abc", nil)
+ want("", nil)
+ want("def", nil)
+ want("", io.EOF)
+ })
+ }
+}
+
func TestReaderReset(t *testing.T) {
r := NewReader(strings.NewReader("foo foo"))
buf := make([]byte, 3)
diff --git a/src/bufio/scan.go b/src/bufio/scan.go
index 27a0f00..9f741c9 100644
--- a/src/bufio/scan.go
+++ b/src/bufio/scan.go
@@ -199,7 +199,6 @@ func (s *Scanner) Scan() bool {
s.buf = newBuf
s.end -= s.start
s.start = 0
- continue
}
// Finally we can read some input. Make sure we don't get stuck with
// a misbehaving Reader. Officially we don't need to do this, but let's
diff --git a/src/builtin/builtin.go b/src/builtin/builtin.go
index d63ad22..281de0b 100644
--- a/src/builtin/builtin.go
+++ b/src/builtin/builtin.go
@@ -173,8 +173,8 @@ func cap(v Type) int
// specify a different capacity; it must be no smaller than the
// length, so make([]int, 0, 10) allocates a slice of length 0 and
// capacity 10.
-// Map: An initial allocation is made according to the size but the
-// resulting map has length 0. The size may be omitted, in which case
+// Map: An empty map is allocated with enough space to hold the
+// specified number of elements. The size may be omitted, in which case
// a small starting size is allocated.
// Channel: The channel's buffer is initialized with the specified
// buffer capacity. If zero, or the size is omitted, the channel is
diff --git a/src/bytes/buffer.go b/src/bytes/buffer.go
index 9154a1b..2ee3d73 100644
--- a/src/bytes/buffer.go
+++ b/src/bytes/buffer.go
@@ -15,22 +15,25 @@ 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)]
- runeBytes [utf8.UTFMax]byte // avoid allocation of slice on each call to WriteRune
- bootstrap [64]byte // memory to hold first slice; helps small buffers avoid allocation.
- lastRead readOp // last read operation, so that Unread* can work correctly.
+ 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.
}
// The readOp constants describe the last action performed on
-// the buffer, so that UnreadRune and UnreadByte can
-// check for invalid usage.
+// the buffer, so that UnreadRune and UnreadByte can check for
+// invalid usage. opReadRuneX constants are choosen such that
+// converted to int they correspond to the rune size that was read.
type readOp int
const (
- opInvalid readOp = iota // Non-read operation.
- opReadRune // Read rune.
- opRead // Any other read operation.
+ opRead readOp = -1 // Any other read operation.
+ opInvalid = 0 // Non-read operation.
+ opReadRune1 = 1 // Read rune of size 1.
+ opReadRune2 = 2 // Read rune of size 2.
+ opReadRune3 = 3 // Read rune of size 3.
+ opReadRune4 = 4 // Read rune of size 4.
)
// ErrTooLarge is passed to panic if memory cannot be allocated to store data in a buffer.
@@ -246,8 +249,10 @@ func (b *Buffer) WriteRune(r rune) (n int, err error) {
b.WriteByte(byte(r))
return 1, nil
}
- n = utf8.EncodeRune(b.runeBytes[0:], r)
- b.Write(b.runeBytes[0:n])
+ b.lastRead = opInvalid
+ m := b.grow(utf8.UTFMax)
+ n = utf8.EncodeRune(b.buf[m:m+utf8.UTFMax], r)
+ b.buf = b.buf[:m+n]
return n, nil
}
@@ -318,14 +323,15 @@ func (b *Buffer) ReadRune() (r rune, size int, err error) {
b.Truncate(0)
return 0, 0, io.EOF
}
- b.lastRead = opReadRune
c := b.buf[b.off]
if c < utf8.RuneSelf {
b.off++
+ b.lastRead = opReadRune1
return rune(c), 1, nil
}
r, n := utf8.DecodeRune(b.buf[b.off:])
b.off += n
+ b.lastRead = readOp(n)
return r, n, nil
}
@@ -335,14 +341,13 @@ func (b *Buffer) ReadRune() (r rune, size int, err error) {
// it is stricter than UnreadByte, which will unread the last byte
// from any read operation.)
func (b *Buffer) UnreadRune() error {
- if b.lastRead != opReadRune {
+ if b.lastRead <= opInvalid {
return errors.New("bytes.Buffer: UnreadRune: previous operation was not ReadRune")
}
- b.lastRead = opInvalid
- if b.off > 0 {
- _, n := utf8.DecodeLastRune(b.buf[0:b.off])
- b.off -= n
+ if b.off >= int(b.lastRead) {
+ b.off -= int(b.lastRead)
}
+ b.lastRead = opInvalid
return nil
}
@@ -350,7 +355,7 @@ func (b *Buffer) UnreadRune() error {
// read operation. If write has happened since the last read, UnreadByte
// returns an error.
func (b *Buffer) UnreadByte() error {
- if b.lastRead != opReadRune && b.lastRead != opRead {
+ if b.lastRead == opInvalid {
return errors.New("bytes.Buffer: UnreadByte: previous operation was not a read")
}
b.lastRead = opInvalid
diff --git a/src/bytes/buffer_test.go b/src/bytes/buffer_test.go
index 7de17ae..b1b85f9 100644
--- a/src/bytes/buffer_test.go
+++ b/src/bytes/buffer_test.go
@@ -514,6 +514,19 @@ func TestBufferGrowth(t *testing.T) {
}
}
+func BenchmarkWriteRune(b *testing.B) {
+ const n = 4 << 10
+ const r = '☺'
+ b.SetBytes(int64(n * utf8.RuneLen(r)))
+ buf := NewBuffer(make([]byte, n*utf8.UTFMax))
+ for i := 0; i < b.N; i++ {
+ buf.Reset()
+ for i := 0; i < n; i++ {
+ buf.WriteRune(r)
+ }
+ }
+}
+
// From Issue 5154.
func BenchmarkBufferNotEmptyWriteRead(b *testing.B) {
buf := make([]byte, 1024)
diff --git a/src/bytes/bytes.go b/src/bytes/bytes.go
index 305c85d..406a382 100644
--- a/src/bytes/bytes.go
+++ b/src/bytes/bytes.go
@@ -93,37 +93,6 @@ func ContainsRune(b []byte, r rune) bool {
return IndexRune(b, r) >= 0
}
-// Index returns the index of the first instance of sep in s, or -1 if sep is not present in s.
-func Index(s, sep []byte) int {
- n := len(sep)
- if n == 0 {
- return 0
- }
- if n > len(s) {
- return -1
- }
- c := sep[0]
- if n == 1 {
- return IndexByte(s, c)
- }
- 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 Equal(s[i:i+n], sep) {
- return i
- }
- i++
- }
- return -1
-}
-
func indexBytePortable(s []byte, c byte) int {
for i, b := range s {
if b == c {
@@ -161,15 +130,28 @@ func LastIndexByte(s []byte, c byte) int {
// IndexRune interprets s as a sequence of UTF-8-encoded Unicode code points.
// It returns the byte index of the first occurrence in s of the given rune.
// It returns -1 if rune is not present in s.
+// If r is utf8.RuneError, it returns the first instance of any
+// invalid UTF-8 byte sequence.
func IndexRune(s []byte, r rune) int {
- for i := 0; i < len(s); {
- r1, size := utf8.DecodeRune(s[i:])
- if r == r1 {
- return i
+ switch {
+ case 0 <= r && r < utf8.RuneSelf:
+ return IndexByte(s, byte(r))
+ case r == utf8.RuneError:
+ for i := 0; i < len(s); {
+ r1, n := utf8.DecodeRune(s[i:])
+ if r1 == utf8.RuneError {
+ return i
+ }
+ i += n
}
- i += size
+ return -1
+ case !utf8.ValidRune(r):
+ return -1
+ default:
+ var b [utf8.UTFMax]byte
+ n := utf8.EncodeRune(b[:], r)
+ return Index(s, b[:n])
}
- return -1
}
// IndexAny interprets s as a sequence of UTF-8-encoded Unicode code points.
@@ -178,10 +160,19 @@ func IndexRune(s []byte, r rune) int {
// point in common.
func IndexAny(s []byte, chars string) int {
if len(chars) > 0 {
- var r rune
+ if len(s) > 8 {
+ if as, isASCII := makeASCIISet(chars); isASCII {
+ for i, c := range s {
+ if as.contains(c) {
+ return i
+ }
+ }
+ return -1
+ }
+ }
var width int
for i := 0; i < len(s); i += width {
- r = rune(s[i])
+ r := rune(s[i])
if r < utf8.RuneSelf {
width = 1
} else {
@@ -203,11 +194,21 @@ func IndexAny(s []byte, chars string) int {
// there is no code point in common.
func LastIndexAny(s []byte, chars string) int {
if len(chars) > 0 {
+ if len(s) > 8 {
+ if as, isASCII := makeASCIISet(chars); isASCII {
+ for i := len(s) - 1; i >= 0; i-- {
+ if as.contains(s[i]) {
+ return i
+ }
+ }
+ return -1
+ }
+ }
for i := len(s); i > 0; {
- r, size := utf8.DecodeLastRune(s[0:i])
+ r, size := utf8.DecodeLastRune(s[:i])
i -= size
- for _, ch := range chars {
- if r == ch {
+ for _, c := range chars {
+ if r == c {
return i
}
}
@@ -398,7 +399,20 @@ func Map(mapping func(r rune) rune, s []byte) []byte {
}
// Repeat returns a new byte slice consisting of count copies of b.
+//
+// It panics if count is negative or if
+// the result of (len(b) * count) overflows.
func Repeat(b []byte, count int) []byte {
+ // Since we cannot return an error on overflow,
+ // we should panic if the repeat will generate
+ // an overflow.
+ // See Issue golang.org/issue/16237.
+ if count < 0 {
+ panic("bytes: negative Repeat count")
+ } else if count > 0 && len(b)*count/count != len(b) {
+ panic("bytes: Repeat count causes overflow")
+ }
+
nb := make([]byte, len(b)*count)
bp := copy(nb, b)
for bp < len(nb) {
@@ -419,20 +433,20 @@ func ToTitle(s []byte) []byte { return Map(unicode.ToTitle, s) }
// ToUpperSpecial returns a copy of the byte slice s with all Unicode letters mapped to their
// upper case, giving priority to the special casing rules.
-func ToUpperSpecial(_case unicode.SpecialCase, s []byte) []byte {
- return Map(func(r rune) rune { return _case.ToUpper(r) }, s)
+func ToUpperSpecial(c unicode.SpecialCase, s []byte) []byte {
+ return Map(func(r rune) rune { return c.ToUpper(r) }, s)
}
// ToLowerSpecial returns a copy of the byte slice s with all Unicode letters mapped to their
// lower case, giving priority to the special casing rules.
-func ToLowerSpecial(_case unicode.SpecialCase, s []byte) []byte {
- return Map(func(r rune) rune { return _case.ToLower(r) }, s)
+func ToLowerSpecial(c unicode.SpecialCase, s []byte) []byte {
+ return Map(func(r rune) rune { return c.ToLower(r) }, s)
}
// ToTitleSpecial returns a copy of the byte slice s with all Unicode letters mapped to their
// title case, giving priority to the special casing rules.
-func ToTitleSpecial(_case unicode.SpecialCase, s []byte) []byte {
- return Map(func(r rune) rune { return _case.ToTitle(r) }, s)
+func ToTitleSpecial(c unicode.SpecialCase, s []byte) []byte {
+ return Map(func(r rune) rune { return c.ToTitle(r) }, s)
}
// isSeparator reports whether the rune could mark a word boundary.
@@ -578,7 +592,43 @@ func lastIndexFunc(s []byte, f func(r rune) bool, truth bool) int {
return -1
}
+// asciiSet is a 32-byte value, where each bit represents the presence of a
+// given ASCII character in the set. The 128-bits of the lower 16 bytes,
+// starting with the least-significant bit of the lowest word to the
+// most-significant bit of the highest word, map to the full range of all
+// 128 ASCII characters. The 128-bits of the upper 16 bytes will be zeroed,
+// ensuring that any non-ASCII character will be reported as not in the set.
+type asciiSet [8]uint32
+
+// makeASCIISet creates a set of ASCII characters and reports whether all
+// characters in chars are ASCII.
+func makeASCIISet(chars string) (as asciiSet, ok bool) {
+ for i := 0; i < len(chars); i++ {
+ c := chars[i]
+ if c >= utf8.RuneSelf {
+ return as, false
+ }
+ as[c>>5] |= 1 << uint(c&31)
+ }
+ return as, true
+}
+
+// contains reports whether c is inside the set.
+func (as *asciiSet) contains(c byte) bool {
+ return (as[c>>5] & (1 << uint(c&31))) != 0
+}
+
func makeCutsetFunc(cutset string) func(r rune) bool {
+ if len(cutset) == 1 && cutset[0] < utf8.RuneSelf {
+ return func(r rune) bool {
+ return r == rune(cutset[0])
+ }
+ }
+ if as, isASCII := makeASCIISet(cutset); isASCII {
+ return func(r rune) bool {
+ return r < utf8.RuneSelf && as.contains(byte(r))
+ }
+ }
return func(r rune) bool {
for _, c := range cutset {
if c == r {
diff --git a/src/bytes/bytes_amd64.go b/src/bytes/bytes_amd64.go
new file mode 100644
index 0000000..6affff6
--- /dev/null
+++ b/src/bytes/bytes_amd64.go
@@ -0,0 +1,115 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package bytes
+
+//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
+
+var shortStringLen int
+
+func init() {
+ if supportAVX2() {
+ 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 []byte) int {
+ n := len(sep)
+ switch {
+ case n == 0:
+ return 0
+ case n == 1:
+ return IndexByte(s, sep[0])
+ case n == len(s):
+ if Equal(sep, s) {
+ return 0
+ }
+ return -1
+ case n > len(s):
+ return -1
+ case n <= shortStringLen:
+ // Use brute force when s and sep both are small
+ if len(s) <= 64 {
+ return indexShortStr(s, sep)
+ }
+ c := sep[0]
+ i := 0
+ t := s[:len(s)-n+1]
+ fails := 0
+ for i < len(t) {
+ if t[i] != c {
+ // IndexByte skips 16/32 bytes per iteration,
+ // so it's faster than indexShortStr.
+ o := IndexByte(t[i:], c)
+ if o < 0 {
+ return -1
+ }
+ i += o
+ }
+ if Equal(s[i:i+n], sep) {
+ return i
+ }
+ fails++
+ i++
+ // Switch to indexShortStr when IndexByte produces too many false positives.
+ // 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)
+ if r >= 0 {
+ return r + i
+ }
+ return -1
+ }
+ }
+ return -1
+ }
+ // Rabin-Karp search
+ hashsep, pow := hashStr(sep)
+ var h uint32
+ for i := 0; i < n; i++ {
+ h = h*primeRK + uint32(s[i])
+ }
+ if h == hashsep && Equal(s[:n], sep) {
+ return 0
+ }
+ for i := n; i < len(s); {
+ h *= primeRK
+ h += uint32(s[i])
+ h -= pow * uint32(s[i-n])
+ i++
+ if h == hashsep && Equal(s[i-n:i], sep) {
+ return i - n
+ }
+ }
+ return -1
+}
+
+// primeRK is the prime base used in Rabin-Karp algorithm.
+const primeRK = 16777619
+
+// hashStr returns the hash and the appropriate multiplicative
+// factor for use in Rabin-Karp algorithm.
+func hashStr(sep []byte) (uint32, uint32) {
+ hash := uint32(0)
+ for i := 0; i < len(sep); i++ {
+ hash = hash*primeRK + uint32(sep[i])
+ }
+ var pow, sq uint32 = 1, primeRK
+ for i := len(sep); i > 0; i >>= 1 {
+ if i&1 != 0 {
+ pow *= sq
+ }
+ sq *= sq
+ }
+ return hash, pow
+}
diff --git a/src/bytes/bytes_generic.go b/src/bytes/bytes_generic.go
new file mode 100644
index 0000000..06c9e1f
--- /dev/null
+++ b/src/bytes/bytes_generic.go
@@ -0,0 +1,41 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !amd64,!s390x
+
+package bytes
+
+// TODO: implements short string optimization on non amd64 platforms
+// and get rid of bytes_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 []byte) int {
+ n := len(sep)
+ if n == 0 {
+ return 0
+ }
+ if n > len(s) {
+ return -1
+ }
+ c := sep[0]
+ if n == 1 {
+ return IndexByte(s, c)
+ }
+ 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 Equal(s[i:i+n], sep) {
+ return i
+ }
+ i++
+ }
+ return -1
+}
diff --git a/src/bytes/bytes_s390x.go b/src/bytes/bytes_s390x.go
new file mode 100644
index 0000000..988c603
--- /dev/null
+++ b/src/bytes/bytes_s390x.go
@@ -0,0 +1,118 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package bytes
+
+//go:noescape
+
+// indexShortStr returns the index of the first instance of sep in s,
+// or -1 if sep is not present in s.
+// indexShortStr requires 2 <= len(sep) <= shortStringLen
+func indexShortStr(s, c []byte) int // ../runtime/asm_s390x.s
+
+// supportsVX reports whether the vector facility is available.
+// indexShortStr must not be called if the vector facility is not
+// available.
+func supportsVX() bool // ../runtime/asm_s390x.s
+
+var shortStringLen = -1
+
+func init() {
+ if supportsVX() {
+ shortStringLen = 64
+ }
+}
+
+// Index returns the index of the first instance of sep in s, or -1 if sep is not present in s.
+func Index(s, sep []byte) int {
+ n := len(sep)
+ switch {
+ case n == 0:
+ return 0
+ case n == 1:
+ return IndexByte(s, sep[0])
+ case n == len(s):
+ if Equal(sep, s) {
+ return 0
+ }
+ return -1
+ case n > len(s):
+ return -1
+ case n <= shortStringLen:
+ // Use brute force when s and sep both are small
+ if len(s) <= 64 {
+ return indexShortStr(s, sep)
+ }
+ c := sep[0]
+ i := 0
+ t := s[:len(s)-n+1]
+ fails := 0
+ for i < len(t) {
+ if t[i] != c {
+ // IndexByte skips 16/32 bytes per iteration,
+ // so it's faster than indexShortStr.
+ o := IndexByte(t[i:], c)
+ if o < 0 {
+ return -1
+ }
+ i += o
+ }
+ if Equal(s[i:i+n], sep) {
+ return i
+ }
+ fails++
+ i++
+ // Switch to indexShortStr when IndexByte produces too many false positives.
+ // 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)
+ if r >= 0 {
+ return r + i
+ }
+ return -1
+ }
+ }
+ return -1
+ }
+ // Rabin-Karp search
+ hashsep, pow := hashStr(sep)
+ var h uint32
+ for i := 0; i < n; i++ {
+ h = h*primeRK + uint32(s[i])
+ }
+ if h == hashsep && Equal(s[:n], sep) {
+ return 0
+ }
+ for i := n; i < len(s); {
+ h *= primeRK
+ h += uint32(s[i])
+ h -= pow * uint32(s[i-n])
+ i++
+ if h == hashsep && Equal(s[i-n:i], sep) {
+ return i - n
+ }
+ }
+ return -1
+}
+
+// primeRK is the prime base used in Rabin-Karp algorithm.
+const primeRK = 16777619
+
+// hashStr returns the hash and the appropriate multiplicative
+// factor for use in Rabin-Karp algorithm.
+func hashStr(sep []byte) (uint32, uint32) {
+ hash := uint32(0)
+ for i := 0; i < len(sep); i++ {
+ hash = hash*primeRK + uint32(sep[i])
+ }
+ var pow, sq uint32 = 1, primeRK
+ for i := len(sep); i > 0; i >>= 1 {
+ if i&1 != 0 {
+ pow *= sq
+ }
+ sq *= sq
+ }
+ return hash, pow
+}
diff --git a/src/bytes/bytes_test.go b/src/bytes/bytes_test.go
index c48f662..26eac5e 100644
--- a/src/bytes/bytes_test.go
+++ b/src/bytes/bytes_test.go
@@ -7,8 +7,10 @@ package bytes_test
import (
. "bytes"
"fmt"
+ "internal/testenv"
"math/rand"
"reflect"
+ "strings"
"testing"
"unicode"
"unicode/utf8"
@@ -165,8 +167,12 @@ var indexAnyTests = []BinOpTest{
{"abc", "xyz", -1},
{"abc", "xcz", 2},
{"ab☺c", "x☺yz", 2},
+ {"a☺b☻c☹d", "cx", len("a☺b☻")},
+ {"a☺b☻c☹d", "uvw☻xyz", len("a☺b")},
{"aRegExp*", ".(|)*+?^$[]", 7},
{dots + dots + dots, " ", -1},
+ {"012abcba210", "\xffb", 4},
+ {"012\x80bcb\x80210", "\xffb", 3},
}
var lastIndexAnyTests = []BinOpTest{
@@ -178,18 +184,13 @@ var lastIndexAnyTests = []BinOpTest{
{"aaa", "a", 2},
{"abc", "xyz", -1},
{"abc", "ab", 1},
- {"a☺b☻c☹d", "uvw☻xyz", 2 + len("☺")},
+ {"ab☺c", "x☺yz", 2},
+ {"a☺b☻c☹d", "cx", len("a☺b☻")},
+ {"a☺b☻c☹d", "uvw☻xyz", len("a☺b")},
{"a.RegExp*", ".(|)*+?^$[]", 8},
{dots + dots + dots, " ", -1},
-}
-
-var indexRuneTests = []BinOpTest{
- {"", "a", -1},
- {"", "☺", -1},
- {"foo", "☹", -1},
- {"foo", "o", 1},
- {"foo☺bar", "☺", 3},
- {"foo☺☻☹bar", "☹", 9},
+ {"012abcba210", "\xffb", 6},
+ {"012\x80bcb\x80210", "\xffb", 7},
}
// Execute f on each test case. funcName should be the name of f; it's used
@@ -346,13 +347,52 @@ func TestIndexByteSmall(t *testing.T) {
}
func TestIndexRune(t *testing.T) {
- for _, tt := range indexRuneTests {
- a := []byte(tt.a)
- r, _ := utf8.DecodeRuneInString(tt.b)
- pos := IndexRune(a, r)
- if pos != tt.i {
- t.Errorf(`IndexRune(%q, '%c') = %v`, tt.a, r, pos)
+ tests := []struct {
+ in string
+ rune rune
+ want int
+ }{
+ {"", 'a', -1},
+ {"", '☺', -1},
+ {"foo", '☹', -1},
+ {"foo", 'o', 1},
+ {"foo☺bar", '☺', 3},
+ {"foo☺☻☹bar", '☹', 9},
+ {"a A x", 'A', 2},
+ {"some_text=some_value", '=', 9},
+ {"☺a", 'a', 3},
+ {"a☻☺b", '☺', 4},
+
+ // RuneError should match any invalid UTF-8 byte sequence.
+ {"�", '�', 0},
+ {"\xff", '�', 0},
+ {"☻x�", '�', len("☻x")},
+ {"☻x\xe2\x98", '�', len("☻x")},
+ {"☻x\xe2\x98�", '�', len("☻x")},
+ {"☻x\xe2\x98x", '�', len("☻x")},
+
+ // Invalid rune values should never match.
+ {"a☺b☻c☹d\xe2\x98�\xff�\xed\xa0\x80", -1, -1},
+ {"a☺b☻c☹d\xe2\x98�\xff�\xed\xa0\x80", 0xD800, -1}, // Surrogate pair
+ {"a☺b☻c☹d\xe2\x98�\xff�\xed\xa0\x80", utf8.MaxRune + 1, -1},
+ }
+ for _, tt := range tests {
+ if got := IndexRune([]byte(tt.in), tt.rune); got != tt.want {
+ t.Errorf("IndexRune(%q, %d) = %v; want %v", tt.in, tt.rune, got, tt.want)
+ }
+ }
+
+ haystack := []byte("test世界")
+ allocs := testing.AllocsPerRun(1000, func() {
+ if i := IndexRune(haystack, 's'); i != 2 {
+ t.Fatalf("'s' at %d; want 2", i)
+ }
+ if i := IndexRune(haystack, '世'); i != 4 {
+ t.Fatalf("'世' at %d; want 4", i)
}
+ })
+ if allocs != 0 {
+ t.Errorf("expected no allocations, got %f", allocs)
}
}
@@ -370,6 +410,9 @@ func valName(x int) string {
func benchBytes(b *testing.B, sizes []int, f func(b *testing.B, n int)) {
for _, n := range sizes {
+ if isRaceBuilder && n > 4<<10 {
+ continue
+ }
b.Run(valName(n), func(b *testing.B) {
if len(bmbuf) < n {
bmbuf = make([]byte, n)
@@ -382,6 +425,8 @@ func benchBytes(b *testing.B, sizes []int, f func(b *testing.B, n int)) {
var indexSizes = []int{10, 32, 4 << 10, 4 << 20, 64 << 20}
+var isRaceBuilder = strings.HasSuffix(testenv.Builder(), "-race")
+
func BenchmarkIndexByte(b *testing.B) {
benchBytes(b, indexSizes, bmIndexByte(IndexByte))
}
@@ -404,6 +449,44 @@ func bmIndexByte(index func([]byte, byte) int) func(b *testing.B, n int) {
}
}
+func BenchmarkIndexRune(b *testing.B) {
+ benchBytes(b, indexSizes, bmIndexRune(IndexRune))
+}
+
+func BenchmarkIndexRuneASCII(b *testing.B) {
+ benchBytes(b, indexSizes, bmIndexRuneASCII(IndexRune))
+}
+
+func bmIndexRuneASCII(index func([]byte, rune) int) func(b *testing.B, n int) {
+ return func(b *testing.B, n int) {
+ buf := bmbuf[0:n]
+ buf[n-1] = 'x'
+ for i := 0; i < b.N; i++ {
+ j := index(buf, 'x')
+ if j != n-1 {
+ b.Fatal("bad index", j)
+ }
+ }
+ buf[n-1] = '\x00'
+ }
+}
+
+func bmIndexRune(index func([]byte, rune) int) func(b *testing.B, n int) {
+ return func(b *testing.B, n int) {
+ buf := bmbuf[0:n]
+ utf8.EncodeRune(buf[n-3:], '世')
+ for i := 0; i < b.N; i++ {
+ j := index(buf, '世')
+ if j != n-3 {
+ b.Fatal("bad index", j)
+ }
+ }
+ buf[n-3] = '\x00'
+ buf[n-2] = '\x00'
+ buf[n-1] = '\x00'
+ }
+}
+
func BenchmarkEqual(b *testing.B) {
b.Run("0", func(b *testing.B) {
var buf [4]byte
@@ -844,6 +927,54 @@ func TestRepeat(t *testing.T) {
}
}
+func repeat(b []byte, count int) (err error) {
+ defer func() {
+ if r := recover(); r != nil {
+ switch v := r.(type) {
+ case error:
+ err = v
+ default:
+ err = fmt.Errorf("%s", v)
+ }
+ }
+ }()
+
+ Repeat(b, count)
+
+ return
+}
+
+// See Issue golang.org/issue/16237
+func TestRepeatCatchesOverflow(t *testing.T) {
+ tests := [...]struct {
+ s string
+ count int
+ errStr string
+ }{
+ 0: {"--", -2147483647, "negative"},
+ 1: {"", int(^uint(0) >> 1), ""},
+ 2: {"-", 10, ""},
+ 3: {"gopher", 0, ""},
+ 4: {"-", -1, "negative"},
+ 5: {"--", -102, "negative"},
+ 6: {string(make([]byte, 255)), int((^uint(0))/255 + 1), "overflow"},
+ }
+
+ for i, tt := range tests {
+ err := repeat([]byte(tt.s), tt.count)
+ if tt.errStr == "" {
+ if err != nil {
+ t.Errorf("#%d panicked %v", i, err)
+ }
+ continue
+ }
+
+ if err == nil || !strings.Contains(err.Error(), tt.errStr) {
+ t.Errorf("#%d expected %q got %q", i, tt.errStr, err)
+ }
+ }
+}
+
func runesEqual(a, b []rune) bool {
if len(a) != len(b) {
return false
@@ -906,6 +1037,9 @@ var trimTests = []TrimTest{
{"Trim", "* listitem", " *", "listitem"},
{"Trim", `"quote"`, `"`, "quote"},
{"Trim", "\u2C6F\u2C6F\u0250\u0250\u2C6F\u2C6F", "\u2C6F", "\u0250\u0250"},
+ {"Trim", "\x80test\xff", "\xff", "test"},
+ {"Trim", " Ġ ", " ", "Ġ"},
+ {"Trim", " Ġİ0", "0 ", "Ġİ"},
//empty string tests
{"Trim", "abba", "", "abba"},
{"Trim", "", "123", ""},
@@ -1325,3 +1459,31 @@ func BenchmarkBytesCompare(b *testing.B) {
})
}
}
+
+func BenchmarkIndexAnyASCII(b *testing.B) {
+ x := Repeat([]byte{'#'}, 4096) // Never matches set
+ cs := "0123456789abcdef"
+ for k := 1; k <= 4096; k <<= 4 {
+ for j := 1; j <= 16; j <<= 1 {
+ b.Run(fmt.Sprintf("%d:%d", k, j), func(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ IndexAny(x[:k], cs[:j])
+ }
+ })
+ }
+ }
+}
+
+func BenchmarkTrimASCII(b *testing.B) {
+ cs := "0123456789abcdef"
+ for k := 1; k <= 4096; k <<= 4 {
+ for j := 1; j <= 16; j <<= 1 {
+ b.Run(fmt.Sprintf("%d:%d", k, j), func(b *testing.B) {
+ x := Repeat([]byte(cs[:j]), k) // Always matches set
+ for i := 0; i < b.N; i++ {
+ Trim(x[:k], cs[:j])
+ }
+ })
+ }
+ }
+}
diff --git a/src/bytes/example_test.go b/src/bytes/example_test.go
index ad2dbc6..0d35a0d 100644
--- a/src/bytes/example_test.go
+++ b/src/bytes/example_test.go
@@ -11,6 +11,7 @@ import (
"io"
"os"
"sort"
+ "unicode"
)
func ExampleBuffer() {
@@ -83,3 +84,205 @@ func ExampleTrimPrefix() {
fmt.Printf("Hello%s", b)
// Output: Hello, world!
}
+
+func ExampleFields() {
+ fmt.Printf("Fields are: %q", bytes.Fields([]byte(" foo bar baz ")))
+ // Output: Fields are: ["foo" "bar" "baz"]
+}
+
+func ExampleFieldsFunc() {
+ f := func(c rune) bool {
+ return !unicode.IsLetter(c) && !unicode.IsNumber(c)
+ }
+ fmt.Printf("Fields are: %q", bytes.FieldsFunc([]byte(" foo1;bar2,baz3..."), f))
+ // Output: Fields are: ["foo1" "bar2" "baz3"]
+}
+
+func ExampleContains() {
+ fmt.Println(bytes.Contains([]byte("seafood"), []byte("foo")))
+ fmt.Println(bytes.Contains([]byte("seafood"), []byte("bar")))
+ fmt.Println(bytes.Contains([]byte("seafood"), []byte("")))
+ fmt.Println(bytes.Contains([]byte(""), []byte("")))
+ // Output:
+ // true
+ // false
+ // true
+ // true
+}
+
+func ExampleCount() {
+ fmt.Println(bytes.Count([]byte("cheese"), []byte("e")))
+ fmt.Println(bytes.Count([]byte("five"), []byte(""))) // before & after each rune
+ // Output:
+ // 3
+ // 5
+}
+
+func ExampleEqualFold() {
+ fmt.Println(bytes.EqualFold([]byte("Go"), []byte("go")))
+ // Output: true
+}
+
+func ExampleHasPrefix() {
+ fmt.Println(bytes.HasPrefix([]byte("Gopher"), []byte("Go")))
+ fmt.Println(bytes.HasPrefix([]byte("Gopher"), []byte("C")))
+ fmt.Println(bytes.HasPrefix([]byte("Gopher"), []byte("")))
+ // Output:
+ // true
+ // false
+ // true
+}
+
+func ExampleHasSuffix() {
+ fmt.Println(bytes.HasSuffix([]byte("Amigo"), []byte("go")))
+ fmt.Println(bytes.HasSuffix([]byte("Amigo"), []byte("O")))
+ fmt.Println(bytes.HasSuffix([]byte("Amigo"), []byte("Ami")))
+ fmt.Println(bytes.HasSuffix([]byte("Amigo"), []byte("")))
+ // Output:
+ // true
+ // false
+ // false
+ // true
+}
+
+func ExampleIndex() {
+ fmt.Println(bytes.Index([]byte("chicken"), []byte("ken")))
+ fmt.Println(bytes.Index([]byte("chicken"), []byte("dmr")))
+ // Output:
+ // 4
+ // -1
+}
+
+func ExampleIndexFunc() {
+ f := func(c rune) bool {
+ return unicode.Is(unicode.Han, c)
+ }
+ fmt.Println(bytes.IndexFunc([]byte("Hello, 世界"), f))
+ fmt.Println(bytes.IndexFunc([]byte("Hello, world"), f))
+ // Output:
+ // 7
+ // -1
+}
+
+func ExampleIndexAny() {
+ fmt.Println(bytes.IndexAny([]byte("chicken"), "aeiouy"))
+ fmt.Println(bytes.IndexAny([]byte("crwth"), "aeiouy"))
+ // Output:
+ // 2
+ // -1
+}
+
+func ExampleIndexRune() {
+ fmt.Println(bytes.IndexRune([]byte("chicken"), 'k'))
+ fmt.Println(bytes.IndexRune([]byte("chicken"), 'd'))
+ // Output:
+ // 4
+ // -1
+}
+
+func ExampleLastIndex() {
+ fmt.Println(bytes.Index([]byte("go gopher"), []byte("go")))
+ fmt.Println(bytes.LastIndex([]byte("go gopher"), []byte("go")))
+ fmt.Println(bytes.LastIndex([]byte("go gopher"), []byte("rodent")))
+ // Output:
+ // 0
+ // 3
+ // -1
+}
+
+func ExampleJoin() {
+ s := [][]byte{[]byte("foo"), []byte("bar"), []byte("baz")}
+ fmt.Printf("%s", bytes.Join(s, []byte(", ")))
+ // Output: foo, bar, baz
+}
+
+func ExampleRepeat() {
+ fmt.Printf("ba%s", bytes.Repeat([]byte("na"), 2))
+ // Output: banana
+}
+
+func ExampleReplace() {
+ fmt.Printf("%s\n", bytes.Replace([]byte("oink oink oink"), []byte("k"), []byte("ky"), 2))
+ fmt.Printf("%s\n", bytes.Replace([]byte("oink oink oink"), []byte("oink"), []byte("moo"), -1))
+ // Output:
+ // oinky oinky oink
+ // moo moo moo
+}
+
+func ExampleSplit() {
+ fmt.Printf("%q\n", bytes.Split([]byte("a,b,c"), []byte(",")))
+ fmt.Printf("%q\n", bytes.Split([]byte("a man a plan a canal panama"), []byte("a ")))
+ fmt.Printf("%q\n", bytes.Split([]byte(" xyz "), []byte("")))
+ fmt.Printf("%q\n", bytes.Split([]byte(""), []byte("Bernardo O'Higgins")))
+ // Output:
+ // ["a" "b" "c"]
+ // ["" "man " "plan " "canal panama"]
+ // [" " "x" "y" "z" " "]
+ // [""]
+}
+
+func ExampleSplitN() {
+ fmt.Printf("%q\n", bytes.SplitN([]byte("a,b,c"), []byte(","), 2))
+ z := bytes.SplitN([]byte("a,b,c"), []byte(","), 0)
+ fmt.Printf("%q (nil = %v)\n", z, z == nil)
+ // Output:
+ // ["a" "b,c"]
+ // [] (nil = true)
+}
+
+func ExampleSplitAfter() {
+ fmt.Printf("%q\n", bytes.SplitAfter([]byte("a,b,c"), []byte(",")))
+ // Output: ["a," "b," "c"]
+}
+
+func ExampleSplitAfterN() {
+ fmt.Printf("%q\n", bytes.SplitAfterN([]byte("a,b,c"), []byte(","), 2))
+ // Output: ["a," "b,c"]
+}
+
+func ExampleTitle() {
+ fmt.Printf("%s", bytes.Title([]byte("her royal highness")))
+ // Output: Her Royal Highness
+}
+
+func ExampleToTitle() {
+ fmt.Printf("%s\n", bytes.ToTitle([]byte("loud noises")))
+ fmt.Printf("%s\n", bytes.ToTitle([]byte("хлеб")))
+ // Output:
+ // LOUD NOISES
+ // ХЛЕБ
+}
+
+func ExampleTrim() {
+ fmt.Printf("[%q]", bytes.Trim([]byte(" !!! Achtung! Achtung! !!! "), "! "))
+ // Output: ["Achtung! Achtung"]
+}
+
+func ExampleMap() {
+ rot13 := func(r rune) rune {
+ switch {
+ case r >= 'A' && r <= 'Z':
+ return 'A' + (r-'A'+13)%26
+ case r >= 'a' && r <= 'z':
+ return 'a' + (r-'a'+13)%26
+ }
+ return r
+ }
+ fmt.Printf("%s", bytes.Map(rot13, []byte("'Twas brillig and the slithy gopher...")))
+ // Output: 'Gjnf oevyyvt naq gur fyvgul tbcure...
+}
+
+func ExampleTrimSpace() {
+ fmt.Printf("%s", bytes.TrimSpace([]byte(" \t\n a lone gopher \n\t\r\n")))
+ // Output: a lone gopher
+}
+
+func ExampleToUpper() {
+ fmt.Printf("%s", bytes.ToUpper([]byte("Gopher")))
+ // Output: GOPHER
+}
+
+func ExampleToLower() {
+ fmt.Printf("%s", bytes.ToLower([]byte("Gopher")))
+ // Output: gopher
+}
diff --git a/src/cmd/addr2line/addr2line_test.go b/src/cmd/addr2line/addr2line_test.go
index 620b416..2bd2e35 100644
--- a/src/cmd/addr2line/addr2line_test.go
+++ b/src/cmd/addr2line/addr2line_test.go
@@ -18,7 +18,7 @@ import (
)
func loadSyms(t *testing.T) map[string]string {
- cmd := exec.Command("go", "tool", "nm", os.Args[0])
+ cmd := exec.Command(testenv.GoToolPath(t), "tool", "nm", os.Args[0])
out, err := cmd.CombinedOutput()
if err != nil {
t.Fatalf("go tool nm %v: %v\n%s", os.Args[0], err, string(out))
@@ -98,7 +98,7 @@ func TestAddr2Line(t *testing.T) {
defer os.RemoveAll(tmpDir)
exepath := filepath.Join(tmpDir, "testaddr2line.exe")
- out, err := exec.Command("go", "build", "-o", exepath, "cmd/addr2line").CombinedOutput()
+ 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 c8433c5..1753644 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"),
+ "-c", file("go1", "go1.1", "go1.2", "go1.3", "go1.4", "go1.5", "go1.6", "go1.7", "go1.8"),
"-next", file("next"),
"-except", file("except")).CombinedOutput()
if err != nil {
diff --git a/src/cmd/asm/internal/arch/amd64.go b/src/cmd/asm/internal/arch/amd64.go
index 625e136..ff20d32 100644
--- a/src/cmd/asm/internal/arch/amd64.go
+++ b/src/cmd/asm/internal/arch/amd64.go
@@ -13,8 +13,8 @@ import (
"cmd/internal/obj/x86"
)
-// IsAMD4OP reports whether the op (as defined by an ppc64.A* constant) is
-// The FMADD-like instructions behave similarly.
+// IsAMD4OP reports whether the op (as defined by an amd64.A* constant) is
+// a 4-operand instruction.
func IsAMD4OP(op obj.As) bool {
switch op {
case x86.AVPERM2F128,
diff --git a/src/cmd/asm/internal/arch/arch.go b/src/cmd/asm/internal/arch/arch.go
index 4b5b46a..9110ca7 100644
--- a/src/cmd/asm/internal/arch/arch.go
+++ b/src/cmd/asm/internal/arch/arch.go
@@ -59,6 +59,14 @@ func Set(GOARCH string) *Arch {
return archArm()
case "arm64":
return archArm64()
+ case "mips":
+ a := archMips()
+ a.LinkArch = &mips.Linkmips
+ return a
+ case "mipsle":
+ a := archMips()
+ a.LinkArch = &mips.Linkmipsle
+ return a
case "mips64":
a := archMips64()
a.LinkArch = &mips.Linkmips64
@@ -319,6 +327,12 @@ func archPPC64() *Arch {
for i := ppc64.REG_F0; i <= ppc64.REG_F31; i++ {
register[obj.Rconv(i)] = int16(i)
}
+ for i := ppc64.REG_V0; i <= ppc64.REG_V31; i++ {
+ register[obj.Rconv(i)] = int16(i)
+ }
+ for i := ppc64.REG_VS0; i <= ppc64.REG_VS63; i++ {
+ register[obj.Rconv(i)] = int16(i)
+ }
for i := ppc64.REG_CR0; i <= ppc64.REG_CR7; i++ {
register[obj.Rconv(i)] = int16(i)
}
@@ -368,6 +382,62 @@ func archPPC64() *Arch {
}
}
+func archMips() *Arch {
+ register := make(map[string]int16)
+ // Create maps for easy lookup of instruction names etc.
+ // Note that there is no list of names as there is for x86.
+ for i := mips.REG_R0; i <= mips.REG_R31; i++ {
+ register[obj.Rconv(i)] = int16(i)
+ }
+
+ for i := mips.REG_F0; i <= mips.REG_F31; i++ {
+ register[obj.Rconv(i)] = int16(i)
+ }
+ for i := mips.REG_M0; i <= mips.REG_M31; i++ {
+ register[obj.Rconv(i)] = int16(i)
+ }
+ for i := mips.REG_FCR0; i <= mips.REG_FCR31; i++ {
+ register[obj.Rconv(i)] = int16(i)
+ }
+ register["HI"] = mips.REG_HI
+ register["LO"] = mips.REG_LO
+ // Pseudo-registers.
+ register["SB"] = RSB
+ register["FP"] = RFP
+ register["PC"] = RPC
+ // Avoid unintentionally clobbering g using R30.
+ delete(register, "R30")
+ register["g"] = mips.REG_R30
+
+ registerPrefix := map[string]bool{
+ "F": true,
+ "FCR": true,
+ "M": true,
+ "R": true,
+ }
+
+ instructions := make(map[string]obj.As)
+ for i, s := range obj.Anames {
+ instructions[s] = obj.As(i)
+ }
+ for i, s := range mips.Anames {
+ if obj.As(i) >= obj.A_ARCHSPECIFIC {
+ instructions[s] = obj.As(i) + obj.ABaseMIPS
+ }
+ }
+ // Annoying alias.
+ instructions["JAL"] = mips.AJAL
+
+ return &Arch{
+ LinkArch: &mips.Linkmipsle,
+ Instructions: instructions,
+ Register: register,
+ RegisterPrefix: registerPrefix,
+ RegisterNumber: mipsRegisterNumber,
+ IsJump: jumpMIPS,
+ }
+}
+
func archMips64() *Arch {
register := make(map[string]int16)
// Create maps for easy lookup of instruction names etc.
@@ -409,7 +479,7 @@ func archMips64() *Arch {
}
for i, s := range mips.Anames {
if obj.As(i) >= obj.A_ARCHSPECIFIC {
- instructions[s] = obj.As(i) + obj.ABaseMIPS64
+ instructions[s] = obj.As(i) + obj.ABaseMIPS
}
}
// Annoying alias.
@@ -421,7 +491,7 @@ func archMips64() *Arch {
Register: register,
RegisterPrefix: registerPrefix,
RegisterNumber: mipsRegisterNumber,
- IsJump: jumpMIPS64,
+ IsJump: jumpMIPS,
}
}
diff --git a/src/cmd/asm/internal/arch/mips.go b/src/cmd/asm/internal/arch/mips.go
new file mode 100644
index 0000000..14b2933
--- /dev/null
+++ b/src/cmd/asm/internal/arch/mips.go
@@ -0,0 +1,67 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file encapsulates some of the odd characteristics of the
+// MIPS (MIPS64) instruction set, to minimize its interaction
+// with the core of the assembler.
+
+package arch
+
+import (
+ "cmd/internal/obj"
+ "cmd/internal/obj/mips"
+)
+
+func jumpMIPS(word string) bool {
+ switch word {
+ case "BEQ", "BFPF", "BFPT", "BGEZ", "BGEZAL", "BGTZ", "BLEZ", "BLTZ", "BLTZAL", "BNE", "JMP", "JAL", "CALL":
+ return true
+ }
+ return false
+}
+
+// IsMIPSCMP reports whether the op (as defined by an mips.A* constant) is
+// one of the CMP instructions that require special handling.
+func IsMIPSCMP(op obj.As) bool {
+ switch op {
+ case mips.ACMPEQF, mips.ACMPEQD, mips.ACMPGEF, mips.ACMPGED,
+ mips.ACMPGTF, mips.ACMPGTD:
+ return true
+ }
+ return false
+}
+
+// IsMIPSMUL reports whether the op (as defined by an mips.A* constant) is
+// one of the MUL/DIV/REM instructions that require special handling.
+func IsMIPSMUL(op obj.As) bool {
+ switch op {
+ case mips.AMUL, mips.AMULU, mips.AMULV, mips.AMULVU,
+ mips.ADIV, mips.ADIVU, mips.ADIVV, mips.ADIVVU,
+ mips.AREM, mips.AREMU, mips.AREMV, mips.AREMVU:
+ return true
+ }
+ return false
+}
+
+func mipsRegisterNumber(name string, n int16) (int16, bool) {
+ switch name {
+ case "F":
+ if 0 <= n && n <= 31 {
+ return mips.REG_F0 + n, true
+ }
+ case "FCR":
+ if 0 <= n && n <= 31 {
+ return mips.REG_FCR0 + n, true
+ }
+ case "M":
+ if 0 <= n && n <= 31 {
+ return mips.REG_M0 + n, true
+ }
+ case "R":
+ if 0 <= n && n <= 31 {
+ return mips.REG_R0 + n, true
+ }
+ }
+ return 0, false
+}
diff --git a/src/cmd/asm/internal/arch/mips64.go b/src/cmd/asm/internal/arch/mips64.go
deleted file mode 100644
index dd93cfb..0000000
--- a/src/cmd/asm/internal/arch/mips64.go
+++ /dev/null
@@ -1,67 +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 encapsulates some of the odd characteristics of the
-// 64-bit MIPS (MIPS64) instruction set, to minimize its interaction
-// with the core of the assembler.
-
-package arch
-
-import (
- "cmd/internal/obj"
- "cmd/internal/obj/mips"
-)
-
-func jumpMIPS64(word string) bool {
- switch word {
- case "BEQ", "BFPF", "BFPT", "BGEZ", "BGEZAL", "BGTZ", "BLEZ", "BLTZ", "BLTZAL", "BNE", "JMP", "JAL", "CALL":
- return true
- }
- return false
-}
-
-// IsMIPS64CMP reports whether the op (as defined by an mips.A* constant) is
-// one of the CMP instructions that require special handling.
-func IsMIPS64CMP(op obj.As) bool {
- switch op {
- case mips.ACMPEQF, mips.ACMPEQD, mips.ACMPGEF, mips.ACMPGED,
- mips.ACMPGTF, mips.ACMPGTD:
- return true
- }
- return false
-}
-
-// IsMIPS64MUL reports whether the op (as defined by an mips.A* constant) is
-// one of the MUL/DIV/REM instructions that require special handling.
-func IsMIPS64MUL(op obj.As) bool {
- switch op {
- case mips.AMUL, mips.AMULU, mips.AMULV, mips.AMULVU,
- mips.ADIV, mips.ADIVU, mips.ADIVV, mips.ADIVVU,
- mips.AREM, mips.AREMU, mips.AREMV, mips.AREMVU:
- return true
- }
- return false
-}
-
-func mipsRegisterNumber(name string, n int16) (int16, bool) {
- switch name {
- case "F":
- if 0 <= n && n <= 31 {
- return mips.REG_F0 + n, true
- }
- case "FCR":
- if 0 <= n && n <= 31 {
- return mips.REG_FCR0 + n, true
- }
- case "M":
- if 0 <= n && n <= 31 {
- return mips.REG_M0 + n, true
- }
- case "R":
- if 0 <= n && n <= 31 {
- return mips.REG_R0 + n, true
- }
- }
- return 0, false
-}
diff --git a/src/cmd/asm/internal/arch/ppc64.go b/src/cmd/asm/internal/arch/ppc64.go
index fef2565..7e3d55b 100644
--- a/src/cmd/asm/internal/arch/ppc64.go
+++ b/src/cmd/asm/internal/arch/ppc64.go
@@ -39,6 +39,10 @@ func IsPPC64RLD(op obj.As) bool {
return false
}
+func IsPPC64ISEL(op obj.As) bool {
+ return op == ppc64.AISEL
+}
+
// IsPPC64CMP reports whether the op (as defined by an ppc64.A* constant) is
// one of the CMP instructions that require special handling.
func IsPPC64CMP(op obj.As) bool {
@@ -73,6 +77,14 @@ func ppc64RegisterNumber(name string, n int16) (int16, bool) {
if 0 <= n && n <= 7 {
return ppc64.REG_CR0 + n, true
}
+ case "VS":
+ if 0 <= n && n <= 63 {
+ return ppc64.REG_VS0 + n, true
+ }
+ case "V":
+ if 0 <= n && n <= 31 {
+ return ppc64.REG_V0 + n, true
+ }
case "F":
if 0 <= n && n <= 31 {
return ppc64.REG_F0 + n, true
diff --git a/src/cmd/asm/internal/arch/s390x.go b/src/cmd/asm/internal/arch/s390x.go
index 6fa0292..1836f87 100644
--- a/src/cmd/asm/internal/arch/s390x.go
+++ b/src/cmd/asm/internal/arch/s390x.go
@@ -22,7 +22,9 @@ func jumpS390x(word string) bool {
"BGT",
"BL",
"BLE",
+ "BLEU",
"BLT",
+ "BLTU",
"BNE",
"BR",
"BVC",
@@ -78,11 +80,7 @@ func IsS390xCMP(op obj.As) bool {
// one of the NEG-like instructions that require special handling.
func IsS390xNEG(op obj.As) bool {
switch op {
- case s390x.AADDME,
- s390x.AADDZE,
- s390x.ANEG,
- s390x.ASUBME,
- s390x.ASUBZE:
+ case s390x.ANEG, s390x.ANEGW:
return true
}
return false
@@ -110,6 +108,10 @@ func IsS390xWithIndex(op obj.As) bool {
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
}
diff --git a/src/cmd/asm/internal/asm/asm.go b/src/cmd/asm/internal/asm/asm.go
index c9c6420..d7c5687 100644
--- a/src/cmd/asm/internal/asm/asm.go
+++ b/src/cmd/asm/internal/asm/asm.go
@@ -269,17 +269,7 @@ func (p *Parser) asmGlobl(word string, operands [][]lex.Token) {
}
// log.Printf("GLOBL %s %d, $%d", name, flag, size)
- prog := &obj.Prog{
- Ctxt: p.ctxt,
- As: obj.AGLOBL,
- Lineno: p.histLineNum,
- From: nameAddr,
- From3: &obj.Addr{
- Offset: flag,
- },
- To: addr,
- }
- p.append(prog, "", false)
+ p.ctxt.Globl(nameAddr.Sym, addr.Offset, int(flag))
}
// asmPCData assembles a PCDATA pseudo-op.
@@ -379,7 +369,7 @@ func (p *Parser) asmJump(op obj.As, cond string, a []obj.Addr) {
prog.Reg = reg
break
}
- if p.arch.Family == sys.MIPS64 {
+ if p.arch.Family == sys.MIPS || p.arch.Family == sys.MIPS64 {
// 3-operand jumps.
// First two must be registers
target = &a[2]
@@ -403,7 +393,7 @@ func (p *Parser) asmJump(op obj.As, cond string, a []obj.Addr) {
fallthrough
default:
- p.errorf("wrong number of arguments to %s instruction", obj.Aconv(op))
+ p.errorf("wrong number of arguments to %s instruction", op)
return
}
switch {
@@ -476,7 +466,7 @@ func (p *Parser) branch(jmp, target *obj.Prog) {
// asmInstruction assembles an instruction.
// MOVW R9, (R10)
func (p *Parser) asmInstruction(op obj.As, cond string, a []obj.Addr) {
- // fmt.Printf("%s %+v\n", obj.Aconv(op), a)
+ // fmt.Printf("%s %+v\n", op, a)
prog := &obj.Prog{
Ctxt: p.ctxt,
Lineno: p.histLineNum,
@@ -525,7 +515,7 @@ func (p *Parser) asmInstruction(op obj.As, cond string, a []obj.Addr) {
prog.To = a[1]
break
}
- p.errorf("unrecognized addressing for %s", obj.Aconv(op))
+ p.errorf("unrecognized addressing for %s", op)
return
}
if arch.IsARMFloatCmp(op) {
@@ -537,8 +527,8 @@ func (p *Parser) asmInstruction(op obj.As, cond string, a []obj.Addr) {
prog.From = a[0]
prog.Reg = p.getRegister(prog, op, &a[1])
break
- } else if p.arch.Family == sys.MIPS64 {
- if arch.IsMIPS64CMP(op) || arch.IsMIPS64MUL(op) {
+ } else if p.arch.Family == sys.MIPS || p.arch.Family == sys.MIPS64 {
+ if arch.IsMIPSCMP(op) || arch.IsMIPSMUL(op) {
prog.From = a[0]
prog.Reg = p.getRegister(prog, op, &a[1])
break
@@ -548,7 +538,7 @@ func (p *Parser) asmInstruction(op obj.As, cond string, a []obj.Addr) {
prog.To = a[1]
case 3:
switch p.arch.Family {
- case sys.MIPS64:
+ case sys.MIPS, sys.MIPS64:
prog.From = a[0]
prog.Reg = p.getRegister(prog, op, &a[1])
prog.To = a[2]
@@ -572,7 +562,7 @@ func (p *Parser) asmInstruction(op obj.As, cond string, a []obj.Addr) {
// Catch missing operand here, because we store immediate as part of From3, and can't distinguish
// missing operand from legal value 0 in obj/x86/asm6.
if arch.IsAMD4OP(op) {
- p.errorf("4 operands required, but only 3 are provided for %s instruction", obj.Aconv(op))
+ p.errorf("4 operands required, but only 3 are provided for %s instruction", op)
}
prog.From = a[0]
prog.From3 = newAddr(a[1])
@@ -583,7 +573,7 @@ func (p *Parser) asmInstruction(op obj.As, cond string, a []obj.Addr) {
prog.From = a[0]
prog.To = a[1]
if a[2].Type != obj.TYPE_REG {
- p.errorf("invalid addressing modes for third operand to %s instruction, must be register", obj.Aconv(op))
+ p.errorf("invalid addressing modes for third operand to %s instruction, must be register", op)
return
}
prog.RegTo2 = a[2].Reg
@@ -619,7 +609,7 @@ func (p *Parser) asmInstruction(op obj.As, cond string, a []obj.Addr) {
prog.From3 = newAddr(a[1])
prog.To = a[2]
default:
- p.errorf("invalid addressing modes for %s instruction", obj.Aconv(op))
+ p.errorf("invalid addressing modes for %s instruction", op)
return
}
case sys.S390X:
@@ -656,10 +646,10 @@ func (p *Parser) asmInstruction(op obj.As, cond string, a []obj.Addr) {
prog.From = a[1]
prog.From3 = newAddr(a[2])
if a[0].Type != obj.TYPE_CONST {
- p.errorf("first operand must be an immediate in %s instruction", obj.Aconv(op))
+ p.errorf("first operand must be an immediate in %s instruction", op)
}
if prog.From3.Type != obj.TYPE_REG {
- p.errorf("third operand must be a register in %s instruction", obj.Aconv(op))
+ p.errorf("third operand must be a register in %s instruction", op)
}
prog.From3.Offset = int64(p.getImmediate(prog, op, &a[0]))
prog.To = a[3]
@@ -673,15 +663,42 @@ func (p *Parser) asmInstruction(op obj.As, cond string, a []obj.Addr) {
prog.To = a[3]
break
}
- if p.arch.Family == sys.PPC64 && arch.IsPPC64RLD(op) {
- // 2nd operand must always be a register.
- // TODO: Do we need to guard this with the instruction type?
- // That is, are there 4-operand instructions without this property?
- prog.From = a[0]
- prog.Reg = p.getRegister(prog, op, &a[1])
- prog.From3 = newAddr(a[2])
- prog.To = a[3]
- break
+ if p.arch.Family == sys.PPC64 {
+ if arch.IsPPC64RLD(op) {
+ prog.From = a[0]
+ prog.Reg = p.getRegister(prog, op, &a[1])
+ prog.From3 = newAddr(a[2])
+ prog.To = a[3]
+ break
+ } else if arch.IsPPC64ISEL(op) {
+ // ISEL BC,RB,RA,RT becomes isel rt,ra,rb,bc
+ prog.From3 = newAddr(a[2]) // ra
+ prog.From = a[0] // bc
+ prog.Reg = p.getRegister(prog, op, &a[1]) // rb
+ prog.To = a[3] // rt
+ break
+ }
+ // Else, it is a VA-form instruction
+ // reg reg reg reg
+ // imm reg reg reg
+ // Or a VX-form instruction
+ // imm imm reg reg
+ if a[1].Type == obj.TYPE_REG {
+ prog.From = a[0]
+ prog.Reg = p.getRegister(prog, op, &a[1])
+ prog.From3 = newAddr(a[2])
+ prog.To = a[3]
+ break
+ } else if a[1].Type == obj.TYPE_CONST {
+ prog.From = a[0]
+ prog.Reg = p.getRegister(prog, op, &a[2])
+ prog.From3 = newAddr(a[1])
+ prog.To = a[3]
+ break
+ } else {
+ p.errorf("invalid addressing modes for %s instruction", op)
+ return
+ }
}
if p.arch.Family == sys.S390X {
prog.From = a[1]
@@ -690,7 +707,7 @@ func (p *Parser) asmInstruction(op obj.As, cond string, a []obj.Addr) {
prog.To = a[3]
break
}
- p.errorf("can't handle %s instruction with 4 operands", obj.Aconv(op))
+ p.errorf("can't handle %s instruction with 4 operands", op)
return
case 5:
if p.arch.Family == sys.PPC64 && arch.IsPPC64RLD(op) {
@@ -712,7 +729,7 @@ func (p *Parser) asmInstruction(op obj.As, cond string, a []obj.Addr) {
prog.To = a[4]
break
}
- p.errorf("can't handle %s instruction with 5 operands", obj.Aconv(op))
+ p.errorf("can't handle %s instruction with 5 operands", op)
return
case 6:
if p.arch.Family == sys.ARM && arch.IsARMMRC(op) {
@@ -736,7 +753,7 @@ func (p *Parser) asmInstruction(op obj.As, cond string, a []obj.Addr) {
}
fallthrough
default:
- p.errorf("can't handle %s instruction with %d operands", obj.Aconv(op), len(a))
+ p.errorf("can't handle %s instruction with %d operands", op, len(a))
return
}
@@ -771,7 +788,7 @@ func (p *Parser) getConstantPseudo(pseudo string, addr *obj.Addr) int64 {
// getConstant checks that addr represents a plain constant and returns its value.
func (p *Parser) getConstant(prog *obj.Prog, op obj.As, addr *obj.Addr) int64 {
if addr.Type != obj.TYPE_MEM || addr.Name != 0 || addr.Reg != 0 || addr.Index != 0 {
- p.errorf("%s: expected integer constant; found %s", obj.Aconv(op), obj.Dconv(prog, addr))
+ p.errorf("%s: expected integer constant; found %s", op, obj.Dconv(prog, addr))
}
return addr.Offset
}
@@ -779,7 +796,7 @@ func (p *Parser) getConstant(prog *obj.Prog, op obj.As, addr *obj.Addr) int64 {
// getImmediate checks that addr represents an immediate constant and returns its value.
func (p *Parser) getImmediate(prog *obj.Prog, op obj.As, addr *obj.Addr) int64 {
if addr.Type != obj.TYPE_CONST || addr.Name != 0 || addr.Reg != 0 || addr.Index != 0 {
- p.errorf("%s: expected immediate constant; found %s", obj.Aconv(op), obj.Dconv(prog, addr))
+ p.errorf("%s: expected immediate constant; found %s", op, obj.Dconv(prog, addr))
}
return addr.Offset
}
@@ -787,7 +804,7 @@ func (p *Parser) getImmediate(prog *obj.Prog, op obj.As, addr *obj.Addr) int64 {
// getRegister checks that addr represents a register and returns its value.
func (p *Parser) getRegister(prog *obj.Prog, op obj.As, addr *obj.Addr) int16 {
if addr.Type != obj.TYPE_REG || addr.Offset != 0 || addr.Name != 0 || addr.Index != 0 {
- p.errorf("%s: expected register; found %s", obj.Aconv(op), obj.Dconv(prog, addr))
+ p.errorf("%s: expected register; found %s", op, obj.Dconv(prog, addr))
}
return addr.Reg
}
diff --git a/src/cmd/asm/internal/asm/endtoend_test.go b/src/cmd/asm/internal/asm/endtoend_test.go
index bc992a7..a2f31f8 100644
--- a/src/cmd/asm/internal/asm/endtoend_test.go
+++ b/src/cmd/asm/internal/asm/endtoend_test.go
@@ -383,7 +383,8 @@ func TestAMD64Errors(t *testing.T) {
testErrors(t, "amd64", "amd64error")
}
-func TestMIPS64EndToEnd(t *testing.T) {
+func TestMIPSEndToEnd(t *testing.T) {
+ testEndToEnd(t, "mips", "mips")
testEndToEnd(t, "mips64", "mips64")
}
diff --git a/src/cmd/asm/internal/asm/operand_test.go b/src/cmd/asm/internal/asm/operand_test.go
index eafc8a3..f1531a8 100644
--- a/src/cmd/asm/internal/asm/operand_test.go
+++ b/src/cmd/asm/internal/asm/operand_test.go
@@ -5,7 +5,6 @@
package asm
import (
- "os"
"testing"
"cmd/asm/internal/arch"
@@ -16,7 +15,8 @@ import (
// A simple in-out test: Do we print what we parse?
func setArch(goarch string) (*arch.Arch, *obj.Link) {
- os.Setenv("GOOS", "linux") // obj can handle this OS for all architectures.
+ obj.GOOS = "linux" // obj can handle this OS for all architectures.
+ obj.GOARCH = goarch
architecture := arch.Set(goarch)
if architecture == nil {
panic("asm: unrecognized architecture " + goarch)
@@ -65,6 +65,11 @@ func TestPPC64OperandParser(t *testing.T) {
testOperandParser(t, parser, ppc64OperandTests)
}
+func TestMIPSOperandParser(t *testing.T) {
+ parser := newParser("mips")
+ testOperandParser(t, parser, mipsOperandTests)
+}
+
func TestMIPS64OperandParser(t *testing.T) {
parser := newParser("mips64")
testOperandParser(t, parser, mips64OperandTests)
@@ -340,6 +345,102 @@ var ppc64OperandTests = []operandTest{
{"6(PC)", "6(PC)"},
{"CR7", "CR7"},
{"CTR", "CTR"},
+ {"VS0", "VS0"},
+ {"VS1", "VS1"},
+ {"VS2", "VS2"},
+ {"VS3", "VS3"},
+ {"VS4", "VS4"},
+ {"VS5", "VS5"},
+ {"VS6", "VS6"},
+ {"VS7", "VS7"},
+ {"VS8", "VS8"},
+ {"VS9", "VS9"},
+ {"VS10", "VS10"},
+ {"VS11", "VS11"},
+ {"VS12", "VS12"},
+ {"VS13", "VS13"},
+ {"VS14", "VS14"},
+ {"VS15", "VS15"},
+ {"VS16", "VS16"},
+ {"VS17", "VS17"},
+ {"VS18", "VS18"},
+ {"VS19", "VS19"},
+ {"VS20", "VS20"},
+ {"VS21", "VS21"},
+ {"VS22", "VS22"},
+ {"VS23", "VS23"},
+ {"VS24", "VS24"},
+ {"VS25", "VS25"},
+ {"VS26", "VS26"},
+ {"VS27", "VS27"},
+ {"VS28", "VS28"},
+ {"VS29", "VS29"},
+ {"VS30", "VS30"},
+ {"VS31", "VS31"},
+ {"VS32", "VS32"},
+ {"VS33", "VS33"},
+ {"VS34", "VS34"},
+ {"VS35", "VS35"},
+ {"VS36", "VS36"},
+ {"VS37", "VS37"},
+ {"VS38", "VS38"},
+ {"VS39", "VS39"},
+ {"VS40", "VS40"},
+ {"VS41", "VS41"},
+ {"VS42", "VS42"},
+ {"VS43", "VS43"},
+ {"VS44", "VS44"},
+ {"VS45", "VS45"},
+ {"VS46", "VS46"},
+ {"VS47", "VS47"},
+ {"VS48", "VS48"},
+ {"VS49", "VS49"},
+ {"VS50", "VS50"},
+ {"VS51", "VS51"},
+ {"VS52", "VS52"},
+ {"VS53", "VS53"},
+ {"VS54", "VS54"},
+ {"VS55", "VS55"},
+ {"VS56", "VS56"},
+ {"VS57", "VS57"},
+ {"VS58", "VS58"},
+ {"VS59", "VS59"},
+ {"VS60", "VS60"},
+ {"VS61", "VS61"},
+ {"VS62", "VS62"},
+ {"VS63", "VS63"},
+ {"V0", "V0"},
+ {"V1", "V1"},
+ {"V2", "V2"},
+ {"V3", "V3"},
+ {"V4", "V4"},
+ {"V5", "V5"},
+ {"V6", "V6"},
+ {"V7", "V7"},
+ {"V8", "V8"},
+ {"V9", "V9"},
+ {"V10", "V10"},
+ {"V11", "V11"},
+ {"V12", "V12"},
+ {"V13", "V13"},
+ {"V14", "V14"},
+ {"V15", "V15"},
+ {"V16", "V16"},
+ {"V17", "V17"},
+ {"V18", "V18"},
+ {"V19", "V19"},
+ {"V20", "V20"},
+ {"V21", "V21"},
+ {"V22", "V22"},
+ {"V23", "V23"},
+ {"V24", "V24"},
+ {"V25", "V25"},
+ {"V26", "V26"},
+ {"V27", "V27"},
+ {"V28", "V28"},
+ {"V29", "V29"},
+ {"V30", "V30"},
+ {"V31", "V31"},
{"F14", "F14"},
{"F15", "F15"},
{"F16", "F16"},
@@ -532,6 +633,88 @@ var mips64OperandTests = []operandTest{
{"[):[o-FP", ""}, // Issue 12469 - asm hung parsing the o-FP range on non ARM platforms.
}
+var mipsOperandTests = []operandTest{
+ {"$((1<<63)-1)", "$9223372036854775807"},
+ {"$(-64*1024)", "$-65536"},
+ {"$(1024 * 8)", "$8192"},
+ {"$-1", "$-1"},
+ {"$-24(R4)", "$-24(R4)"},
+ {"$0", "$0"},
+ {"$0(R1)", "$(R1)"},
+ {"$0.5", "$(0.5)"},
+ {"$0x7000", "$28672"},
+ {"$0x88888eef", "$2290650863"},
+ {"$1", "$1"},
+ {"$_main<>(SB)", "$_main<>(SB)"},
+ {"$argframe(FP)", "$argframe(FP)"},
+ {"$~3", "$-4"},
+ {"(-288-3*8)(R1)", "-312(R1)"},
+ {"(16)(R7)", "16(R7)"},
+ {"(8)(g)", "8(g)"},
+ {"(R0)", "(R0)"},
+ {"(R3)", "(R3)"},
+ {"(R4)", "(R4)"},
+ {"(R5)", "(R5)"},
+ {"-1(R4)", "-1(R4)"},
+ {"-1(R5)", "-1(R5)"},
+ {"6(PC)", "6(PC)"},
+ {"F14", "F14"},
+ {"F15", "F15"},
+ {"F16", "F16"},
+ {"F17", "F17"},
+ {"F18", "F18"},
+ {"F19", "F19"},
+ {"F20", "F20"},
+ {"F21", "F21"},
+ {"F22", "F22"},
+ {"F23", "F23"},
+ {"F24", "F24"},
+ {"F25", "F25"},
+ {"F26", "F26"},
+ {"F27", "F27"},
+ {"F28", "F28"},
+ {"F29", "F29"},
+ {"F30", "F30"},
+ {"F31", "F31"},
+ {"R0", "R0"},
+ {"R1", "R1"},
+ {"R11", "R11"},
+ {"R12", "R12"},
+ {"R13", "R13"},
+ {"R14", "R14"},
+ {"R15", "R15"},
+ {"R16", "R16"},
+ {"R17", "R17"},
+ {"R18", "R18"},
+ {"R19", "R19"},
+ {"R2", "R2"},
+ {"R20", "R20"},
+ {"R21", "R21"},
+ {"R22", "R22"},
+ {"R23", "R23"},
+ {"R24", "R24"},
+ {"R25", "R25"},
+ {"R26", "R26"},
+ {"R27", "R27"},
+ {"R29", "R29"},
+ {"R3", "R3"},
+ {"R31", "R31"},
+ {"R4", "R4"},
+ {"R5", "R5"},
+ {"R6", "R6"},
+ {"R7", "R7"},
+ {"R8", "R8"},
+ {"R9", "R9"},
+ {"LO", "LO"},
+ {"a(FP)", "a(FP)"},
+ {"g", "g"},
+ {"ret+8(FP)", "ret+8(FP)"},
+ {"runtime·abort(SB)", "runtime.abort(SB)"},
+ {"·AddUint32(SB)", "\"\".AddUint32(SB)"},
+ {"·trunc(SB)", "\"\".trunc(SB)"},
+ {"[):[o-FP", ""}, // Issue 12469 - asm hung parsing the o-FP range on non ARM platforms.
+}
+
var s390xOperandTests = []operandTest{
{"$((1<<63)-1)", "$9223372036854775807"},
{"$(-64*1024)", "$-65536"},
diff --git a/src/cmd/asm/internal/asm/parse.go b/src/cmd/asm/internal/asm/parse.go
index 40206e6..406c65e 100644
--- a/src/cmd/asm/internal/asm/parse.go
+++ b/src/cmd/asm/internal/asm/parse.go
@@ -941,14 +941,6 @@ func (p *Parser) atof(str string) float64 {
return value
}
-func (p *Parser) atos(str string) string {
- value, err := strconv.Unquote(str)
- if err != nil {
- p.errorf("%s", err)
- }
- return value
-}
-
// EOF represents the end of input.
var EOF = lex.Make(scanner.EOF, "EOF")
diff --git a/src/cmd/asm/internal/asm/testdata/amd64enc.s b/src/cmd/asm/internal/asm/testdata/amd64enc.s
index 22dfe12..b27faa5 100644
--- a/src/cmd/asm/internal/asm/testdata/amd64enc.s
+++ b/src/cmd/asm/internal/asm/testdata/amd64enc.s
@@ -2551,14 +2551,14 @@ TEXT asmtest(SB),7,$0
MOVQ (R11), X11 // 66450f6e1b or 664d0f6e1b or f3450f7e1b
MOVQ DX, X11 // 66440f6eda or 664c0f6eda
MOVQ R11, X11 // 66450f6edb or 664d0f6edb
- //TODO: MOVDDUP (BX), X2 // f20f1213
- //TODO: MOVDDUP (R11), X2 // f2410f1213
- //TODO: MOVDDUP X2, X2 // f20f12d2
- //TODO: MOVDDUP X11, X2 // f2410f12d3
- //TODO: MOVDDUP (BX), X11 // f2440f121b
- //TODO: MOVDDUP (R11), X11 // f2450f121b
- //TODO: MOVDDUP X2, X11 // f2440f12da
- //TODO: MOVDDUP X11, X11 // f2450f12db
+ MOVDDUP (BX), X2 // f20f1213
+ MOVDDUP (R11), X2 // f2410f1213
+ MOVDDUP X2, X2 // f20f12d2
+ MOVDDUP X11, X2 // f2410f12d3
+ MOVDDUP (BX), X11 // f2440f121b
+ MOVDDUP (R11), X11 // f2450f121b
+ MOVDDUP X2, X11 // f2440f12da
+ MOVDDUP X11, X11 // f2450f12db
MOVQ X2, M2 // f20fd6d2
MOVQ X11, M2 // f2410fd6d3
MOVQ X2, M3 // f20fd6da
@@ -2697,22 +2697,22 @@ TEXT asmtest(SB),7,$0
//TODO: MOVSD X11, (BX) // f2440f111b
//TODO: MOVSD X2, (R11) // f2410f1113
//TODO: MOVSD X11, (R11) // f2450f111b
- //TODO: MOVSHDUP (BX), X2 // f30f1613
- //TODO: MOVSHDUP (R11), X2 // f3410f1613
- //TODO: MOVSHDUP X2, X2 // f30f16d2
- //TODO: MOVSHDUP X11, X2 // f3410f16d3
- //TODO: MOVSHDUP (BX), X11 // f3440f161b
- //TODO: MOVSHDUP (R11), X11 // f3450f161b
- //TODO: MOVSHDUP X2, X11 // f3440f16da
- //TODO: MOVSHDUP X11, X11 // f3450f16db
- //TODO: MOVSLDUP (BX), X2 // f30f1213
- //TODO: MOVSLDUP (R11), X2 // f3410f1213
- //TODO: MOVSLDUP X2, X2 // f30f12d2
- //TODO: MOVSLDUP X11, X2 // f3410f12d3
- //TODO: MOVSLDUP (BX), X11 // f3440f121b
- //TODO: MOVSLDUP (R11), X11 // f3450f121b
- //TODO: MOVSLDUP X2, X11 // f3440f12da
- //TODO: MOVSLDUP X11, X11 // f3450f12db
+ MOVSHDUP (BX), X2 // f30f1613
+ MOVSHDUP (R11), X2 // f3410f1613
+ MOVSHDUP X2, X2 // f30f16d2
+ MOVSHDUP X11, X2 // f3410f16d3
+ MOVSHDUP (BX), X11 // f3440f161b
+ MOVSHDUP (R11), X11 // f3450f161b
+ MOVSHDUP X2, X11 // f3440f16da
+ MOVSHDUP X11, X11 // f3450f16db
+ MOVSLDUP (BX), X2 // f30f1213
+ MOVSLDUP (R11), X2 // f3410f1213
+ MOVSLDUP X2, X2 // f30f12d2
+ MOVSLDUP X11, X2 // f3410f12d3
+ MOVSLDUP (BX), X11 // f3440f121b
+ MOVSLDUP (R11), X11 // f3450f121b
+ MOVSLDUP X2, X11 // f3440f12da
+ MOVSLDUP X11, X11 // f3450f12db
MOVSQ // 48a5
MOVSS (BX), X2 // f30f1013
MOVSS (R11), X2 // f3410f1013
@@ -6116,30 +6116,30 @@ TEXT asmtest(SB),7,$0
//TODO: VBROADCASTI128 (R11), Y2 // c4c27d5a13
//TODO: VBROADCASTI128 (BX), Y11 // c4627d5a1b
//TODO: VBROADCASTI128 (R11), Y11 // c4427d5a1b
- //TODO: VBROADCASTSD (BX), Y2 // c4e27d1913
- //TODO: VBROADCASTSD (R11), Y2 // c4c27d1913
- //TODO: VBROADCASTSD (BX), Y11 // c4627d191b
- //TODO: VBROADCASTSD (R11), Y11 // c4427d191b
- //TODO: VBROADCASTSD X2, Y2 // c4e27d19d2
- //TODO: VBROADCASTSD X11, Y2 // c4c27d19d3
- //TODO: VBROADCASTSD X2, Y11 // c4627d19da
- //TODO: VBROADCASTSD X11, Y11 // c4427d19db
- //TODO: VBROADCASTSS (BX), X2 // c4e2791813
- //TODO: VBROADCASTSS (R11), X2 // c4c2791813
- //TODO: VBROADCASTSS (BX), X11 // c46279181b
- //TODO: VBROADCASTSS (R11), X11 // c44279181b
- //TODO: VBROADCASTSS X2, X2 // c4e27918d2
- //TODO: VBROADCASTSS X11, X2 // c4c27918d3
- //TODO: VBROADCASTSS X2, X11 // c4627918da
- //TODO: VBROADCASTSS X11, X11 // c4427918db
- //TODO: VBROADCASTSS (BX), Y2 // c4e27d1813
- //TODO: VBROADCASTSS (R11), Y2 // c4c27d1813
- //TODO: VBROADCASTSS (BX), Y11 // c4627d181b
- //TODO: VBROADCASTSS (R11), Y11 // c4427d181b
- //TODO: VBROADCASTSS X2, Y2 // c4e27d18d2
- //TODO: VBROADCASTSS X11, Y2 // c4c27d18d3
- //TODO: VBROADCASTSS X2, Y11 // c4627d18da
- //TODO: VBROADCASTSS X11, Y11 // c4427d18db
+ VBROADCASTSD (BX), Y2 // c4e27d1913
+ VBROADCASTSD (R11), Y2 // c4c27d1913
+ VBROADCASTSD (BX), Y11 // c4627d191b
+ VBROADCASTSD (R11), Y11 // c4427d191b
+ VBROADCASTSD X2, Y2 // c4e27d19d2
+ VBROADCASTSD X11, Y2 // c4c27d19d3
+ VBROADCASTSD X2, Y11 // c4627d19da
+ VBROADCASTSD X11, Y11 // c4427d19db
+ VBROADCASTSS (BX), X2 // c4e2791813
+ VBROADCASTSS (R11), X2 // c4c2791813
+ VBROADCASTSS (BX), X11 // c46279181b
+ VBROADCASTSS (R11), X11 // c44279181b
+ VBROADCASTSS X2, X2 // c4e27918d2
+ VBROADCASTSS X11, X2 // c4c27918d3
+ VBROADCASTSS X2, X11 // c4627918da
+ VBROADCASTSS X11, X11 // c4427918db
+ VBROADCASTSS (BX), Y2 // c4e27d1813
+ VBROADCASTSS (R11), Y2 // c4c27d1813
+ VBROADCASTSS (BX), Y11 // c4627d181b
+ VBROADCASTSS (R11), Y11 // c4427d181b
+ VBROADCASTSS X2, Y2 // c4e27d18d2
+ VBROADCASTSS X11, Y2 // c4c27d18d3
+ VBROADCASTSS X2, Y11 // c4627d18da
+ VBROADCASTSS X11, Y11 // c4427d18db
//TODO: VCMPPD $7, (BX), X9, X2 // c4e131c21307 or c5b1c21307
//TODO: VCMPPD $7, (R11), X9, X2 // c4c131c21307
//TODO: VCMPPD $7, X2, X9, X2 // c4e131c2d207 or c5b1c2d207
@@ -7642,22 +7642,22 @@ TEXT asmtest(SB),7,$0
//TODO: VMOVD (R11), X11 // c441796e1b
//TODO: VMOVD DX, X11 // c461796eda or c5796eda
//TODO: VMOVD R11, X11 // c441796edb
- //TODO: VMOVDDUP (BX), X2 // c4e17b1213 or c5fb1213
- //TODO: VMOVDDUP (R11), X2 // c4c17b1213
- //TODO: VMOVDDUP X2, X2 // c4e17b12d2 or c5fb12d2
- //TODO: VMOVDDUP X11, X2 // c4c17b12d3
- //TODO: VMOVDDUP (BX), X11 // c4617b121b or c57b121b
- //TODO: VMOVDDUP (R11), X11 // c4417b121b
- //TODO: VMOVDDUP X2, X11 // c4617b12da or c57b12da
- //TODO: VMOVDDUP X11, X11 // c4417b12db
- //TODO: VMOVDDUP (BX), Y2 // c4e17f1213 or c5ff1213
- //TODO: VMOVDDUP (R11), Y2 // c4c17f1213
- //TODO: VMOVDDUP Y2, Y2 // c4e17f12d2 or c5ff12d2
- //TODO: VMOVDDUP Y11, Y2 // c4c17f12d3
- //TODO: VMOVDDUP (BX), Y11 // c4617f121b or c57f121b
- //TODO: VMOVDDUP (R11), Y11 // c4417f121b
- //TODO: VMOVDDUP Y2, Y11 // c4617f12da or c57f12da
- //TODO: VMOVDDUP Y11, Y11 // c4417f12db
+ VMOVDDUP (BX), X2 // c4e17b1213 or c5fb1213
+ VMOVDDUP (R11), X2 // c4c17b1213
+ VMOVDDUP X2, X2 // c4e17b12d2 or c5fb12d2
+ VMOVDDUP X11, X2 // c4c17b12d3
+ VMOVDDUP (BX), X11 // c4617b121b or c57b121b
+ VMOVDDUP (R11), X11 // c4417b121b
+ VMOVDDUP X2, X11 // c4617b12da or c57b12da
+ VMOVDDUP X11, X11 // c4417b12db
+ VMOVDDUP (BX), Y2 // c4e17f1213 or c5ff1213
+ VMOVDDUP (R11), Y2 // c4c17f1213
+ VMOVDDUP Y2, Y2 // c4e17f12d2 or c5ff12d2
+ VMOVDDUP Y11, Y2 // c4c17f12d3
+ VMOVDDUP (BX), Y11 // c4617f121b or c57f121b
+ VMOVDDUP (R11), Y11 // c4417f121b
+ VMOVDDUP Y2, Y11 // c4617f12da or c57f12da
+ VMOVDDUP Y11, Y11 // c4417f12db
VMOVDQA (BX), X2 // c4e1796f13 or c5f96f13
VMOVDQA (R11), X2 // c4c1796f13
VMOVDQA X2, X2 // c4e1796fd2 or c5f96fd2 or c4e1797fd2 or c5f97fd2
@@ -7826,38 +7826,38 @@ TEXT asmtest(SB),7,$0
//TODO: VMOVSD X11, X9, X2 // c4c13310d3 or c4613311da or c53311da
//TODO: VMOVSD X2, X9, X11 // c4613310da or c53310da or c4c13311d3
//TODO: VMOVSD X11, X9, X11 // c4413310db or c4413311db
- //TODO: VMOVSHDUP (BX), X2 // c4e17a1613 or c5fa1613
- //TODO: VMOVSHDUP (R11), X2 // c4c17a1613
- //TODO: VMOVSHDUP X2, X2 // c4e17a16d2 or c5fa16d2
- //TODO: VMOVSHDUP X11, X2 // c4c17a16d3
- //TODO: VMOVSHDUP (BX), X11 // c4617a161b or c57a161b
- //TODO: VMOVSHDUP (R11), X11 // c4417a161b
- //TODO: VMOVSHDUP X2, X11 // c4617a16da or c57a16da
- //TODO: VMOVSHDUP X11, X11 // c4417a16db
- //TODO: VMOVSHDUP (BX), Y2 // c4e17e1613 or c5fe1613
- //TODO: VMOVSHDUP (R11), Y2 // c4c17e1613
- //TODO: VMOVSHDUP Y2, Y2 // c4e17e16d2 or c5fe16d2
- //TODO: VMOVSHDUP Y11, Y2 // c4c17e16d3
- //TODO: VMOVSHDUP (BX), Y11 // c4617e161b or c57e161b
- //TODO: VMOVSHDUP (R11), Y11 // c4417e161b
- //TODO: VMOVSHDUP Y2, Y11 // c4617e16da or c57e16da
- //TODO: VMOVSHDUP Y11, Y11 // c4417e16db
- //TODO: VMOVSLDUP (BX), X2 // c4e17a1213 or c5fa1213
- //TODO: VMOVSLDUP (R11), X2 // c4c17a1213
- //TODO: VMOVSLDUP X2, X2 // c4e17a12d2 or c5fa12d2
- //TODO: VMOVSLDUP X11, X2 // c4c17a12d3
- //TODO: VMOVSLDUP (BX), X11 // c4617a121b or c57a121b
- //TODO: VMOVSLDUP (R11), X11 // c4417a121b
- //TODO: VMOVSLDUP X2, X11 // c4617a12da or c57a12da
- //TODO: VMOVSLDUP X11, X11 // c4417a12db
- //TODO: VMOVSLDUP (BX), Y2 // c4e17e1213 or c5fe1213
- //TODO: VMOVSLDUP (R11), Y2 // c4c17e1213
- //TODO: VMOVSLDUP Y2, Y2 // c4e17e12d2 or c5fe12d2
- //TODO: VMOVSLDUP Y11, Y2 // c4c17e12d3
- //TODO: VMOVSLDUP (BX), Y11 // c4617e121b or c57e121b
- //TODO: VMOVSLDUP (R11), Y11 // c4417e121b
- //TODO: VMOVSLDUP Y2, Y11 // c4617e12da or c57e12da
- //TODO: VMOVSLDUP Y11, Y11 // c4417e12db
+ VMOVSHDUP (BX), X2 // c4e17a1613 or c5fa1613
+ VMOVSHDUP (R11), X2 // c4c17a1613
+ VMOVSHDUP X2, X2 // c4e17a16d2 or c5fa16d2
+ VMOVSHDUP X11, X2 // c4c17a16d3
+ VMOVSHDUP (BX), X11 // c4617a161b or c57a161b
+ VMOVSHDUP (R11), X11 // c4417a161b
+ VMOVSHDUP X2, X11 // c4617a16da or c57a16da
+ VMOVSHDUP X11, X11 // c4417a16db
+ VMOVSHDUP (BX), Y2 // c4e17e1613 or c5fe1613
+ VMOVSHDUP (R11), Y2 // c4c17e1613
+ VMOVSHDUP Y2, Y2 // c4e17e16d2 or c5fe16d2
+ VMOVSHDUP Y11, Y2 // c4c17e16d3
+ VMOVSHDUP (BX), Y11 // c4617e161b or c57e161b
+ VMOVSHDUP (R11), Y11 // c4417e161b
+ VMOVSHDUP Y2, Y11 // c4617e16da or c57e16da
+ VMOVSHDUP Y11, Y11 // c4417e16db
+ VMOVSLDUP (BX), X2 // c4e17a1213 or c5fa1213
+ VMOVSLDUP (R11), X2 // c4c17a1213
+ VMOVSLDUP X2, X2 // c4e17a12d2 or c5fa12d2
+ VMOVSLDUP X11, X2 // c4c17a12d3
+ VMOVSLDUP (BX), X11 // c4617a121b or c57a121b
+ VMOVSLDUP (R11), X11 // c4417a121b
+ VMOVSLDUP X2, X11 // c4617a12da or c57a12da
+ VMOVSLDUP X11, X11 // c4417a12db
+ VMOVSLDUP (BX), Y2 // c4e17e1213 or c5fe1213
+ VMOVSLDUP (R11), Y2 // c4c17e1213
+ VMOVSLDUP Y2, Y2 // c4e17e12d2 or c5fe12d2
+ VMOVSLDUP Y11, Y2 // c4c17e12d3
+ VMOVSLDUP (BX), Y11 // c4617e121b or c57e121b
+ VMOVSLDUP (R11), Y11 // c4417e121b
+ VMOVSLDUP Y2, Y11 // c4617e12da or c57e12da
+ VMOVSLDUP Y11, Y11 // c4417e12db
//TODO: VMOVSS X2, (BX) // c4e17a1113 or c5fa1113
//TODO: VMOVSS X11, (BX) // c4617a111b or c57a111b
//TODO: VMOVSS X2, (R11) // c4c17a1113
diff --git a/src/cmd/asm/internal/asm/testdata/mips.s b/src/cmd/asm/internal/asm/testdata/mips.s
new file mode 100644
index 0000000..f48d918
--- /dev/null
+++ b/src/cmd/asm/internal/asm/testdata/mips.s
@@ -0,0 +1,430 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This input was created by taking the mips64 testcase and modified
+// by hand.
+
+TEXT foo(SB),7,$0
+
+ //inst:
+ //
+ // load ints and bytes
+ //
+ // LMOVW rreg ',' rreg
+ // {
+ // outcode(int($1), &$2, 0, &$4);
+ // }
+ MOVW R1, R2
+ MOVW LO, R1
+ MOVW HI, R1
+ MOVW R1, LO
+ MOVW R1, HI
+ MOVW R1, R2
+ MOVW LO, R1
+ MOVW HI, R1
+ MOVW R1, LO
+ MOVW R1, HI
+
+ // LMOVW addr ',' rreg
+ // {
+ // outcode(int($1), &$2, 0, &$4);
+ // }
+ MOVW foo<>+3(SB), R2
+ MOVW 16(R1), R2
+ MOVW (R1), R2
+ MOVW foo<>+3(SB), R2
+ MOVW 16(R1), R2
+ MOVW (R1), R2
+ LL (R1), R2
+
+ // LMOVB rreg ',' rreg
+ // {
+ // outcode(int($1), &$2, 0, &$4);
+ // }
+ MOVB R1, R2
+
+ // LMOVB addr ',' rreg
+ // {
+ // outcode(int($1), &$2, 0, &$4);
+ // }
+ MOVB foo<>+3(SB), R2
+ MOVB 16(R1), R2
+ MOVB (R1), R2
+
+ //
+ // load floats
+ //
+ // LFMOV addr ',' freg
+ // {
+ // outcode(int($1), &$2, 0, &$4);
+ // }
+ MOVF foo<>+3(SB), F2
+ MOVF 16(R1), F2
+ MOVF (R1), F2
+
+ // LFMOV fimm ',' freg
+ // {
+ // outcode(int($1), &$2, 0, &$4);
+ // }
+ MOVF $0.1, F2 // MOVF $(0.10000000000000001), F2
+
+ // LFMOV freg ',' freg
+ // {
+ // outcode(int($1), &$2, 0, &$4);
+ // }
+ MOVF F1, F2
+
+ // LFMOV freg ',' addr
+ // {
+ // outcode(int($1), &$2, 0, &$4);
+ // }
+ MOVF F2, foo<>+3(SB)
+ MOVF F2, 16(R1)
+ MOVF F2, (R1)
+
+ //
+ // store ints and bytes
+ //
+ // LMOVW rreg ',' addr
+ // {
+ // outcode(int($1), &$2, 0, &$4);
+ // }
+ MOVW R1, foo<>+3(SB)
+ MOVW R1, 16(R2)
+ MOVW R1, (R2)
+ MOVW R1, foo<>+3(SB)
+ MOVW R1, 16(R2)
+ MOVW R1, (R2)
+ SC R1, (R2)
+
+ // LMOVB rreg ',' addr
+ // {
+ // outcode(int($1), &$2, 0, &$4);
+ // }
+ MOVB R1, foo<>+3(SB)
+ MOVB R1, 16(R2)
+ MOVB R1, (R2)
+
+ //
+ // store floats
+ //
+ // LMOVW freg ',' addr
+ // {
+ // outcode(int($1), &$2, 0, &$4);
+ // }
+ MOVD F1, foo<>+3(SB)
+ MOVD F1, 16(R2)
+ MOVD F1, (R2)
+
+ //
+ // floating point status
+ //
+ // LMOVW fpscr ',' freg
+ // {
+ // outcode(int($1), &$2, 0, &$4);
+ // }
+ MOVW FCR0, R1
+
+ // LMOVW freg ',' fpscr
+ // {
+ // outcode(int($1), &$2, 0, &$4);
+ // }
+ MOVW R1, FCR0
+
+ // LMOVW rreg ',' mreg
+ // {
+ // outcode(int($1), &$2, 0, &$4);
+ // }
+ MOVW R1, M1
+ MOVW R1, M1
+
+ // LMOVW mreg ',' rreg
+ // {
+ // outcode(int($1), &$2, 0, &$4);
+ // }
+ MOVW M1, R1
+ MOVW M1, R1
+
+
+ //
+ // integer operations
+ // logical instructions
+ // shift instructions
+ // unary instructions
+ //
+ // LADDW rreg ',' sreg ',' rreg
+ // {
+ // outcode(int($1), &$2, int($4), &$6);
+ // }
+ ADD R1, R2, R3
+
+ // LADDW imm ',' sreg ',' rreg
+ // {
+ // outcode(int($1), &$2, int($4), &$6);
+ // }
+ ADD $1, R2, R3
+
+ // LADDW rreg ',' rreg
+ // {
+ // outcode(int($1), &$2, 0, &$4);
+ // }
+ ADD R1, R2
+
+ // LADDW imm ',' rreg
+ // {
+ // outcode(int($1), &$2, 0, &$4);
+ // }
+ ADD $4, R1
+
+ // LMUL rreg ',' rreg
+ // {
+ // outcode(int($1), &$2, 0, &$4);
+ // }
+ MUL R1, R2
+
+ // LSHW rreg ',' sreg ',' rreg
+ // {
+ // outcode(int($1), &$2, int($4), &$6);
+ // }
+ SLL R1, R2, R3
+
+ // LSHW rreg ',' rreg
+ // {
+ // outcode(int($1), &$2, 0, &$4);
+ // }
+ SLL R1, R2
+
+ // LSHW imm ',' sreg ',' rreg
+ // {
+ // outcode(int($1), &$2, int($4), &$6);
+ // }
+ SLL $4, R1, R2
+
+ // LSHW imm ',' rreg
+ // {
+ // outcode(int($1), &$2, 0, &$4);
+ // }
+ SLL $4, R1
+
+ //
+ // move immediate: macro for lui+or, addi, addis, and other combinations
+ //
+ // LMOVW imm ',' rreg
+ // {
+ // outcode(int($1), &$2, 0, &$4);
+ // }
+ MOVW $1, R1
+ MOVW $1, R1
+
+ // LMOVW ximm ',' rreg
+ // {
+ // outcode(int($1), &$2, 0, &$4);
+ // }
+ MOVW $1, R1
+ MOVW $foo(SB), R1
+ MOVW $1, R1
+ MOVW $foo(SB), R1
+
+
+ //
+ // branch
+ //
+ // LBRA rel
+ // {
+ // outcode(int($1), &nullgen, 0, &$2);
+ // }
+ BEQ R1, 2(PC)
+label0:
+ JMP 1(PC)
+ BEQ R1, 2(PC)
+ JMP label0+0 // JMP 66
+ BEQ R1, 2(PC)
+ JAL 1(PC) // CALL 1(PC)
+ BEQ R1, 2(PC)
+ JAL label0+0 // CALL 66
+
+ // LBRA addr
+ // {
+ // outcode(int($1), &nullgen, 0, &$2);
+ // }
+ BEQ R1, 2(PC)
+ JMP 0(R1) // JMP (R1)
+ BEQ R1, 2(PC)
+ JMP foo+0(SB) // JMP foo(SB)
+ BEQ R1, 2(PC)
+ JAL 0(R1) // CALL (R1)
+ BEQ R1, 2(PC)
+ JAL foo+0(SB) // CALL foo(SB)
+
+//
+// BEQ/BNE
+//
+// LBRA rreg ',' rel
+// {
+// outcode(int($1), &$2, 0, &$4);
+// }
+label1:
+ BEQ R1, 1(PC)
+ BEQ R1, label1 // BEQ R1, 81
+
+// LBRA rreg ',' sreg ',' rel
+// {
+// outcode(int($1), &$2, 0, &$4);
+// }
+label2:
+ BEQ R1, R2, 1(PC)
+ BEQ R1, R2, label2 // BEQ R1, R2, 83
+
+//
+// other integer conditional branch
+//
+// LBRA rreg ',' rel
+// {
+// outcode(int($1), &$2, 0, &$4);
+// }
+label3:
+ BLTZ R1, 1(PC)
+ BLTZ R1, label3 // BLTZ R1, 85
+
+//
+// floating point conditional branch
+//
+// LBRA rel
+label4:
+ BFPT 1(PC)
+ BFPT label4 // BFPT 87
+
+
+ //
+ // floating point operate
+ //
+ // LFCONV freg ',' freg
+ // {
+ // outcode(int($1), &$2, 0, &$4);
+ // }
+ ABSD F1, F2
+
+ // LFADD freg ',' freg
+ // {
+ // outcode(int($1), &$2, 0, &$4);
+ // }
+ ADDD F1, F2
+
+ // LFADD freg ',' freg ',' freg
+ // {
+ // outcode(int($1), &$2, int($4.Reg), &$6);
+ // }
+ ADDD F1, F2, F3
+
+ // LFCMP freg ',' freg
+ // {
+ // outcode(int($1), &$2, 0, &$4);
+ // }
+ CMPEQD F1, F2
+
+
+ //
+ // WORD
+ //
+ WORD $1
+
+ //
+ // NOP
+ //
+ // LNOP comma // asm doesn't support the trailing comma.
+ // {
+ // outcode(int($1), &nullgen, 0, &nullgen);
+ // }
+ NOP
+
+ // LNOP rreg comma // asm doesn't support the trailing comma.
+ // {
+ // outcode(int($1), &$2, 0, &nullgen);
+ // }
+ NOP R2
+
+ // LNOP freg comma // asm doesn't support the trailing comma.
+ // {
+ // outcode(int($1), &$2, 0, &nullgen);
+ // }
+ NOP F2
+
+ // LNOP ',' rreg // asm doesn't support the leading comma.
+ // {
+ // outcode(int($1), &nullgen, 0, &$3);
+ // }
+ NOP R2
+
+ // LNOP ',' freg // asm doesn't support the leading comma.
+ // {
+ // outcode(int($1), &nullgen, 0, &$3);
+ // }
+ NOP F2
+
+ // LNOP imm
+ // {
+ // outcode(int($1), &$2, 0, &nullgen);
+ // }
+ NOP $4
+
+ //
+ // special
+ //
+ SYSCALL
+ BREAK
+ SYNC
+
+ //
+ // conditional move on zero/nonzero gp value
+ //
+ CMOVN R1, R2, R3
+ CMOVZ R1, R2, R3
+
+ //
+ // conditional move on fp false/true
+ //
+ CMOVF R1, R2
+ CMOVT R1, R2
+
+ //
+ // conditional traps
+ //
+ TEQ $1, R1, R2
+ TEQ $1, R1
+
+
+ //
+ // other
+ //
+ CLO R1, R2
+ SQRTD F0, F1
+ MUL R1, R2, R3
+
+
+ //
+ // RET
+ //
+ // LRETRN comma // asm doesn't support the trailing comma.
+ // {
+ // outcode(int($1), &nullgen, 0, &nullgen);
+ // }
+ SYSCALL
+ BEQ R1, 2(PC)
+ RET
+
+
+ // More JMP/JAL cases, and canonical names JMP, CALL.
+
+ JAL foo(SB) // CALL foo(SB)
+ BEQ R1, 2(PC)
+ JMP foo(SB)
+ CALL foo(SB)
+
+ // END
+ //
+ // LEND comma // asm doesn't support the trailing comma.
+ // {
+ // outcode(int($1), &nullgen, 0, &nullgen);
+ // }
+ END
diff --git a/src/cmd/asm/internal/asm/testdata/ppc64.s b/src/cmd/asm/internal/asm/testdata/ppc64.s
index 2e3bf3b..d1ebaa2 100644
--- a/src/cmd/asm/internal/asm/testdata/ppc64.s
+++ b/src/cmd/asm/internal/asm/testdata/ppc64.s
@@ -594,6 +594,15 @@ label1:
// }
RLWMI R1, R2, 4, 5, R3 // RLWMI R1, R2, $201326592, R3
+
+// opcodes added with constant shift counts, not masks
+
+ RLDICR $3, R2, $24, R4
+
+ RLDICL $1, R2, $61, R6
+
+ RLDIMI $7, R2, $52, R7
+
//
// load/store multiple
//
@@ -664,6 +673,346 @@ label1:
DCBF (R1)
DCBF (R1+R2) // DCBF (R1)(R2*1)
+// VMX instructions
+
+// Described as:
+// <instruction type>, <instruction format>
+// <go asm operand order> produces
+// <Power ISA operand order>
+
+// Vector load, VX-form
+// <MNEMONIC> (RB)(RA*1),VRT produces
+// <mnemonic> VRT,RA,RB
+ LVEBX (R1)(R2*1), V0
+ LVEHX (R3)(R4*1), V1
+ LVEWX (R5)(R6*1), V2
+ LVX (R7)(R8*1), V3
+ LVXL (R9)(R10*1), V4
+ LVSL (R11)(R12*1), V5
+ LVSR (R14)(R15*1), V6
+
+// Vector store, VX-form
+// <MNEMONIC> VRT,(RB)(RA*1) produces
+// <mnemonic> VRT,RA,RB
+ STVEBX V31, (R1)(R2*1)
+ STVEHX V30, (R2)(R3*1)
+ STVEWX V29, (R4)(R5*1)
+ STVX V28, (R6)(R7*1)
+ STVXL V27, (R9)(R9*1)
+
+// Vector AND, VX-form
+// <MNEMONIC> VRA,VRB,VRT produces
+// <mnemonic> VRT,VRA,VRB
+ VANDL 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
+ VORC V23, V22, V21
+ VNOR V20, V19, V18
+ VXOR V17, V16, V15
+ VEQV V14, V13, V12
+
+// Vector ADD, VX-form
+// <MNEMONIC> VRA,VRB,VRT produces
+// <mnemonic> VRT,VRA,VRB
+ VADDUBM V3, V2, V1
+ VADDUHM V3, V2, V1
+ VADDUWM V3, V2, V1
+ VADDUDM V3, V2, V1
+ VADDUQM V3, V2, V1
+ VADDCUQ V3, V2, V1
+ VADDCUW V3, V2, V1
+ VADDUBS V3, V2, V1
+ VADDUHS V3, V2, V1
+ VADDUWS V3, V2, V1
+ VADDSBS V3, V2, V1
+ VADDSHS V3, V2, V1
+ VADDSWS V3, V2, V1
+
+// Vector ADD extended, VA-form
+// <MNEMONIC> VRA,VRB,VRC,VRT produces
+// <mnemonic> VRT,VRA,VRB,VRC
+ VADDEUQM V4, V3, V2, V1
+ VADDECUQ V4, V3, V2, V1
+
+// Vector SUB, VX-form
+// <MNEMONIC> VRA,VRB,VRT produces
+// <mnemonic> VRT,VRA,VRB
+ VSUBUBM V3, V2, V1
+ VSUBUHM V3, V2, V1
+ VSUBUWM V3, V2, V1
+ VSUBUDM V3, V2, V1
+ VSUBUQM V3, V2, V1
+ VSUBCUQ V3, V2, V1
+ VSUBCUW V3, V2, V1
+ VSUBUBS V3, V2, V1
+ VSUBUHS V3, V2, V1
+ VSUBUWS V3, V2, V1
+ VSUBSBS V3, V2, V1
+ VSUBSHS V3, V2, V1
+ VSUBSWS V3, V2, V1
+
+// Vector SUB extended, VA-form
+// <MNEMONIC> VRA,VRB,VRC,VRT produces
+// <mnemonic> VRT,VRA,VRB,VRC
+ VSUBEUQM V4, V3, V2, V1
+ VSUBECUQ V4, V3, V2, V1
+
+// Vector rotate, VX-form
+// <MNEMONIC> VRA,VRB,VRT produces
+// <mnemonic> VRT,VRA,VRB
+ VRLB V2, V1, V0
+ VRLH V2, V1, V0
+ VRLW V2, V1, V0
+ VRLD V2, V1, V0
+
+// Vector shift, VX-form
+// <MNEMONIC> VRA,VRB,VRT
+// <mnemonic> VRT,VRA,VRB
+ VSLB V2, V1, V0
+ VSLH V2, V1, V0
+ VSLW V2, V1, V0
+ VSL V2, V1, V0
+ VSLO V2, V1, V0
+ VSRB V2, V1, V0
+ VSRH V2, V1, V0
+ VSRW V2, V1, V0
+ VSR V2, V1, V0
+ VSRO V2, V1, V0
+ VSLD V2, V1, V0
+ VSRD V2, V1, V0
+ VSRAB V2, V1, V0
+ VSRAH V2, V1, V0
+ VSRAW V2, V1, V0
+ VSRAD V2, V1, V0
+
+// Vector shift by octect immediate, VA-form with SHB 4-bit field
+// <MNEMONIC> SHB,VRA,VRB,VRT produces
+// <mnemonic> VRT,VRA,VRB,SHB
+ VSLDOI $4, V2, V1, V0
+
+// Vector count, VX-form
+// <MNEMONIC> VRB,VRT produces
+// <mnemonic> VRT,VRB
+ VCLZB V4, V5
+ VCLZH V4, V5
+ VCLZW V4, V5
+ VCLZD V4, V5
+ VPOPCNTB V4, V5
+ VPOPCNTH V4, V5
+ VPOPCNTW V4, V5
+ VPOPCNTD V4, V5
+
+// Vector compare, VC-form
+// <MNEMONIC> VRA,VRB,VRT produces
+// <mnemonic> VRT,VRA,VRB
+// * Note: 'CC' suffix denotes Rc=1
+// i.e. vcmpequb. v3,v1,v2 equals VCMPEQUBCC V1,V2,V3
+ VCMPEQUB V3, V2, V1
+ VCMPEQUBCC V3, V2, V1
+ VCMPEQUH V3, V2, V1
+ VCMPEQUHCC V3, V2, V1
+ VCMPEQUW V3, V2, V1
+ VCMPEQUWCC V3, V2, V1
+ VCMPEQUD V3, V2, V1
+ VCMPEQUDCC V3, V2, V1
+ VCMPGTUB V3, V2, V1
+ VCMPGTUBCC V3, V2, V1
+ VCMPGTUH V3, V2, V1
+ VCMPGTUHCC V3, V2, V1
+ VCMPGTUW V3, V2, V1
+ VCMPGTUWCC V3, V2, V1
+ VCMPGTUD V3, V2, V1
+ VCMPGTUDCC V3, V2, V1
+ VCMPGTSB V3, V2, V1
+ VCMPGTSBCC V3, V2, V1
+ VCMPGTSH V3, V2, V1
+ VCMPGTSHCC V3, V2, V1
+ VCMPGTSW V3, V2, V1
+ VCMPGTSWCC V3, V2, V1
+ VCMPGTSD V3, V2, V1
+ VCMPGTSDCC V3, V2, V1
+
+// Vector permute, VA-form
+// <MNEMONIC> VRA,VRB,VRC,VRT produces
+// <mnemonic> VRT,VRA,VRB,VRC
+ VPERM V3, V2, V1, V0
+
+// Vector select, VA-form
+// <MNEMONIC> VRA,VRB,VRC,VRT produces
+// <mnemonic> VRT,VRA,VRB,VRC
+ VSEL V3, V2, V1, V0
+
+// Vector splat, VX-form with 4-bit UIM field
+// <MNEMONIC> UIM,VRB,VRT produces
+// <mnemonic> VRT,VRB,UIM
+ VSPLTB $15, V1, V0
+ VSPLTH $7, V1, V0
+ VSPLTW $3, V1, V0
+
+// Vector splat immediate signed, VX-form with 5-bit SIM field
+// <MNEMONIC> SIM,VRT produces
+// <mnemonic> VRT,SIM
+ VSPLTISB $31, V4
+ VSPLTISH $31, V4
+ VSPLTISW $31, V4
+
+// Vector AES cipher, VX-form
+// <MNEMONIC> VRA,VRB,VRT produces
+// <mnemonic> VRT,VRA,VRB
+ VCIPHER V3, V2, V1
+ VCIPHERLAST V3, V2, V1
+ VNCIPHER V3, V2, V1
+ VNCIPHERLAST V3, V2, V1
+
+// Vector AES subbytes, VX-form
+// <MNEMONIC> VRA,VRT produces
+// <mnemonic> VRT,VRA
+ VSBOX V2, V1
+
+// Vector SHA, VX-form with ST bit field and 4-bit SIX field
+// <MNEMONIC> SIX,VRA,ST,VRT produces
+// <mnemonic> VRT,VRA,ST,SIX
+ VSHASIGMAW $15, V1, $1, V0
+ VSHASIGMAD $15, V1, $1, V0
+
+// VSX instructions
+// Described as:
+// <instruction type>, <instruction format>
+// <go asm operand order> produces
+// <Power ISA operand order>
+
+// VSX load, XX1-form
+// <MNEMONIC> (RB)(RA*1),XT produces
+// <mnemonic> XT,RA,RB
+ LXVD2X (R1)(R2*1), VS0
+ LXVDSX (R1)(R2*1), VS0
+ LXVW4X (R1)(R2*1), VS0
+ LXSDX (R1)(R2*1), VS0
+ LXSIWAX (R1)(R2*1), VS0
+ LXSIWZX (R1)(R2*1), VS0
+
+// VSX store, XX1-form
+// <MNEMONIC> XS,(RB)(RA*1) produces
+// <mnemonic> XS,RA,RB
+ STXVD2X VS63, (R1)(R2*1)
+ STXVW4X VS63, (R1)(R2*1)
+ STXSDX VS63, (R1)(R2*1)
+ STXSIWX VS63, (R1)(R2*1)
+
+// VSX move from VSR, XX1-form
+// <MNEMONIC> XS,RA produces
+// <mnemonic> RA,XS
+ MFVSRD VS0, R1
+ MFVSRWZ VS33, R1
+
+// VSX move to VSR, XX1-form
+// <MNEMONIC> RA,XT produces
+// <mnemonic> XT,RA
+ MTVSRD R1, VS0
+ MTVSRWA R1, VS31
+ MTVSRWZ R1, VS63
+
+// VSX AND, XX3-form
+// <MNEMONIC> XA,XB,XT produces
+// <mnemonic> XT,XA,XB
+ XXLANDQ VS0,VS1,VS32
+ XXLANDC VS0,VS1,VS32
+ XXLEQV VS0,VS1,VS32
+ XXLNAND VS0,VS1,VS32
+
+// VSX OR, XX3-form
+// <MNEMONIC> XA,XB,XT produces
+// <mnemonic> XT,XA,XB
+ XXLORC VS0,VS1,VS32
+ XXLNOR VS0,VS1,VS32
+ XXLORQ VS0,VS1,VS32
+ XXLXOR VS0,VS1,VS32
+
+// VSX select, XX4-form
+// <MNEMONIC> XA,XB,XC,XT produces
+// <mnemonic> XT,XA,XB,XC
+ XXSEL VS0,VS1,VS3,VS32
+
+// VSX merge, XX3-form
+// <MNEMONIC> XA,XB,XT produces
+// <mnemonic> XT,XA,XB
+ XXMRGHW VS0,VS1,VS32
+ XXMRGLW VS0,VS1,VS32
+
+// VSX splat, XX2-form
+// <MNEMONIC> XB,UIM,XT produces
+// <mnemonic> XT,XB,UIM
+ XXSPLTW VS0,$3,VS32
+
+// VSX permute, XX3-form
+// <MNEMONIC> XA,XB,DM,XT produces
+// <mnemonic> XT,XA,XB,DM
+ XXPERMDI VS0,VS1,$3,VS32
+
+// VSX shift, XX3-form
+// <MNEMONIC> XA,XB,SHW,XT produces
+// <mnemonic> XT,XA,XB,SHW
+ XXSLDWI VS0,VS1,$3,VS32
+
+// VSX scalar FP-FP conversion, XX2-form
+// <MNEMONIC> XB,XT produces
+// <mnemonic> XT,XB
+ XSCVDPSP VS0,VS32
+ XSCVSPDP VS0,VS32
+ XSCVDPSPN VS0,VS32
+ XSCVSPDPN VS0,VS32
+
+// VSX vector FP-FP conversion, XX2-form
+// <MNEMONIC> XB,XT produces
+// <mnemonic> XT,XB
+ XVCVDPSP VS0,VS32
+ XVCVSPDP VS0,VS32
+
+// VSX scalar FP-integer conversion, XX2-form
+// <MNEMONIC> XB,XT produces
+// <mnemonic> XT,XB
+ XSCVDPSXDS VS0,VS32
+ XSCVDPSXWS VS0,VS32
+ XSCVDPUXDS VS0,VS32
+ XSCVDPUXWS VS0,VS32
+
+// VSX scalar integer-FP conversion, XX2-form
+// <MNEMONIC> XB,XT produces
+// <mnemonic> XT,XB
+ XSCVSXDDP VS0,VS32
+ XSCVUXDDP VS0,VS32
+ XSCVSXDSP VS0,VS32
+ XSCVUXDSP VS0,VS32
+
+// VSX vector FP-integer conversion, XX2-form
+// <MNEMONIC> XB,XT produces
+// <mnemonic> XT,XB
+ XVCVDPSXDS VS0,VS32
+ XVCVDPSXWS VS0,VS32
+ XVCVDPUXDS VS0,VS32
+ XVCVDPUXWS VS0,VS32
+ XVCVSPSXDS VS0,VS32
+ XVCVSPSXWS VS0,VS32
+ XVCVSPUXDS VS0,VS32
+ XVCVSPUXWS VS0,VS32
+
+// VSX scalar integer-FP conversion, XX2-form
+// <MNEMONIC> XB,XT produces
+// <mnemonic> XT,XB
+ XVCVSXDDP VS0,VS32
+ XVCVSXWDP VS0,VS32
+ XVCVUXDDP VS0,VS32
+ XVCVUXWDP VS0,VS32
+ XVCVSXDSP VS0,VS32
+ XVCVSXWSP VS0,VS32
+ XVCVUXDSP VS0,VS32
+ XVCVUXWSP VS0,VS32
+
//
// NOP
//
diff --git a/src/cmd/asm/internal/asm/testdata/s390x.s b/src/cmd/asm/internal/asm/testdata/s390x.s
index 7729384..badedc1 100644
--- a/src/cmd/asm/internal/asm/testdata/s390x.s
+++ b/src/cmd/asm/internal/asm/testdata/s390x.s
@@ -13,6 +13,13 @@ TEXT main·foo(SB),7,$16-0 // TEXT main.foo(SB), 7, $16-0
MOVDBR R1, R2 // b90f0021
MOVWBR R3, R4 // b91f0043
+ MOVDEQ R0, R1 // b9e28010
+ MOVDGE R2, R3 // b9e2a032
+ MOVDGT R4, R5 // b9e22054
+ MOVDLE R6, R7 // b9e2c076
+ MOVDLT R8, R9 // b9e24098
+ MOVDNE R10, R11 // b9e270ba
+
MOVD (R15), R1 // e310f0000004
MOVW (R15), R2 // e320f0000014
MOVH (R15), R3 // e330f0000015
@@ -45,24 +52,34 @@ TEXT main·foo(SB),7,$16-0 // TEXT main.foo(SB), 7, $16-0
ADD R1, R2 // b9e81022
ADD R1, R2, R3 // b9e81032
- ADD $8192, R1 // c21800002000
+ ADD $8192, R1 // a71b2000
ADD $8192, R1, R2 // ec21200000d9
+ ADD $32768, R1 // c21800008000
+ ADD $32768, R1, R2 // b9040021c22800008000
ADDC R1, R2 // b9ea1022
- ADDC $1, R1, R2 // b9040021c22a00000001
+ ADDC $1, R1, R2 // ec21000100db
ADDC R1, R2, R3 // b9ea1032
+ ADDW R1, R2 // 1a21
+ ADDW R1, R2, R3 // b9f81032
+ ADDW $8192, R1 // a71a2000
+ ADDW $8192, R1, R2 // ec21200000d8
SUB R3, R4 // b9090043
SUB R3, R4, R5 // b9e93054
- SUB $8192, R3 // c238ffffe000
+ SUB $8192, R3 // a73be000
SUB $8192, R3, R4 // ec43e00000d9
SUBC R1, R2 // b90b0021
- SUBC $1, R1, R2 // b9040021c22affffffff
+ SUBC $1, R1, R2 // ec21ffff00db
SUBC R2, R3, R4 // b9eb2043
+ SUBW R3, R4 // 1b43
+ SUBW R3, R4, R5 // b9f93054
+ SUBW $8192, R1 // c21500002000
+ SUBW $8192, R1, R2 // 1821c22500002000
MULLW R6, R7 // b91c0076
MULLW R6, R7, R8 // b9040087b91c0086
- MULLW $8192, R6 // a76d2000
- MULLW $8192, R6, R7 // b9040076a77d2000
- MULLW $-65537, R8 // c280fffeffff
- MULLW $-65537, R8, R9 // b9040098c290fffeffff
+ MULLW $8192, R6 // a76c2000
+ MULLW $8192, R6, R7 // 1876a77c2000
+ MULLW $-32769, R8 // c281ffff7fff
+ MULLW $-32769, R8, R9 // 1898c291ffff7fff
MULLD $-2147483648, R1 // c21080000000
MULLD $-2147483648, R1, R2 // b9040021c22080000000
MULHD R9, R8 // b90400b8b98600a9ebb9003f000ab98000b8b90900abebb8003f000ab98000b9b9e9b08a
@@ -73,10 +90,99 @@ TEXT main·foo(SB),7,$16-0 // TEXT main.foo(SB), 7, $16-0
DIVD R1, R2, R3 // b90400b2b90d00a1b904003b
DIVW R4, R5 // b90400b5b91d00a4b904005b
DIVW R4, R5, R6 // b90400b5b91d00a4b904006b
- DIVDU R7, R8 // b90400a0b90400b8b98700a7b904008b
- DIVDU R7, R8, R9 // b90400a0b90400b8b98700a7b904009b
- DIVWU R1, R2 // b90400a0b90400b2b99700a1b904002b
- DIVWU R1, R2, R3 // b90400a0b90400b2b99700a1b904003b
+ DIVDU R7, R8 // a7a90000b90400b8b98700a7b904008b
+ DIVDU R7, R8, R9 // a7a90000b90400b8b98700a7b904009b
+ DIVWU R1, R2 // a7a90000b90400b2b99700a1b904002b
+ DIVWU R1, R2, R3 // a7a90000b90400b2b99700a1b904003b
+ MODD R1, R2 // b90400b2b90d00a1b904002a
+ MODD R1, R2, R3 // b90400b2b90d00a1b904003a
+ MODW R4, R5 // b90400b5b91d00a4b904005a
+ MODW R4, R5, R6 // b90400b5b91d00a4b904006a
+ MODDU R7, R8 // a7a90000b90400b8b98700a7b904008a
+ MODDU R7, R8, R9 // a7a90000b90400b8b98700a7b904009a
+ MODWU R1, R2 // a7a90000b90400b2b99700a1b904002a
+ MODWU R1, R2, R3 // a7a90000b90400b2b99700a1b904003a
+ NEG R1 // b9030011
+ NEG R1, R2 // b9030021
+ NEGW R1 // b9130011
+ NEGW R1, R2 // b9130021
+ FLOGR R2, R2 // b9830022
+
+ AND R1, R2 // b9800021
+ AND R1, R2, R3 // b9e42031
+ AND $-2, R1 // a517fffe
+ AND $-65536, R1 // c01bffff0000
+ AND $1, R1 // c0a100000001b980001a
+ ANDW R1, R2 // 1421
+ ANDW R1, R2, R3 // b9f42031
+ ANDW $1, R1 // c01b00000001
+ ANDW $131071, R1 // a5160001
+ ANDW $65536, R1 // c01b00010000
+ ANDW $-2, R1 // a517fffe
+ OR R1, R2 // b9810021
+ OR R1, R2, R3 // b9e62031
+ OR $1, R1 // a51b0001
+ OR $131071, R1 // c01d0001ffff
+ OR $65536, R1 // c01d00010000
+ OR $-2, R1 // c0a1fffffffeb981001a
+ ORW R1, R2 // 1621
+ ORW R1, R2, R3 // b9f62031
+ ORW $1, R1 // a51b0001
+ ORW $131071, R1 // c01d0001ffff
+ ORW $65536, R1 // a51a0001
+ ORW $-2, R1 // c01dfffffffe
+ XOR R1, R2 // b9820021
+ XOR R1, R2, R3 // b9e72031
+ XOR $1, R1 // c01700000001
+ XOR $131071, R1 // c0170001ffff
+ XOR $65536, R1 // c01700010000
+ XOR $-2, R1 // c0a1fffffffeb982001a
+ XORW R1, R2 // 1721
+ XORW R1, R2, R3 // b9f72031
+ XORW $1, R1 // c01700000001
+ XORW $131071, R1 // c0170001ffff
+ XORW $65536, R1 // c01700010000
+ XORW $-2, R1 // c017fffffffe
+
+ ADD -524288(R1), R2 // e32010008008
+ ADD 524287(R3), R4 // e3403fff7f08
+ ADD -524289(R1), R2 // c0a1fff7ffffe32a10000008
+ ADD 524288(R3), R4 // c0a100080000e34a30000008
+ ADD -524289(R1)(R2*1), R3 // c0a1fff7ffff41aa2000e33a10000008
+ ADD 524288(R3)(R4*1), R5 // c0a10008000041aa4000e35a30000008
+ ADDC (R1), R2 // e3201000000a
+ ADDW (R5), R6 // 5a605000
+ ADDW 4095(R7), R8 // 5a807fff
+ ADDW -1(R1), R2 // e3201fffff5a
+ ADDW 4096(R3), R4 // e3403000015a
+ MULLD (R1)(R2*1), R3 // e3321000000c
+ MULLW (R3)(R4*1), R5 // 71543000
+ MULLW 4096(R3), R4 // e34030000151
+ SUB (R1), R2 // e32010000009
+ SUBC (R1), R2 // e3201000000b
+ SUBE (R1), R2 // e32010000089
+ SUBW (R1), R2 // 5b201000
+ SUBW -1(R1), R2 // e3201fffff5b
+ AND (R1), R2 // e32010000080
+ ANDW (R1), R2 // 54201000
+ ANDW -1(R1), R2 // e3201fffff54
+ OR (R1), R2 // e32010000081
+ ORW (R1), R2 // 56201000
+ ORW -1(R1), R2 // e3201fffff56
+ XOR (R1), R2 // e32010000082
+ XORW (R1), R2 // 57201000
+ XORW -1(R1), R2 // e3201fffff57
+
+ LAA R1, R2, 524287(R3) // eb213fff7ff8
+ LAAG R4, R5, -524288(R6) // eb54600080e8
+ LAAL R7, R8, 8192(R9) // eb87900002fa
+ LAALG R10, R11, -8192(R12) // ebbac000feea
+ LAN R1, R2, (R3) // eb21300000f4
+ LANG R4, R5, (R6) // eb54600000e4
+ LAX R7, R8, (R9) // eb87900000f7
+ LAXG R10, R11, (R12) // ebbac00000e7
+ 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
@@ -87,10 +193,14 @@ TEXT main·foo(SB),7,$16-0 // TEXT main.foo(SB), 7, $16-0
MVC $256, 8192(R1), 8192(R2) // MVC 8192(R1), $256, 8192(R2) // b90400a2c2a800002000b90400b1c2b800002000d2ffa000b000
CMP R1, R2 // b9200012
+ CMP R3, $32767 // a73f7fff
+ CMP R3, $32768 // c23c00008000
CMP R3, $-2147483648 // c23c80000000
CMPU R4, R5 // b9210045
CMPU R6, $4294967295 // c26effffffff
CMPW R7, R8 // 1978
+ CMPW R9, $-32768 // a79e8000
+ CMPW R9, $-32769 // c29dffff7fff
CMPW R9, $-2147483648 // c29d80000000
CMPWU R1, R2 // 1512
CMPWU R3, $4294967295 // c23fffffffff
@@ -101,6 +211,8 @@ TEXT main·foo(SB),7,$16-0 // TEXT main.foo(SB), 7, $16-0
BLE 0(PC) // a7c40000
BGT 0(PC) // a7240000
BGE 0(PC) // a7a40000
+ BLTU 0(PC) // a7540000
+ BLEU 0(PC) // a7d40000
CMPBNE R1, R2, 0(PC) // ec1200007064
CMPBEQ R3, R4, 0(PC) // ec3400008064
@@ -167,6 +279,8 @@ TEXT main·foo(SB),7,$16-0 // TEXT main.foo(SB), 7, $16-0
FABS F1, F2 // b3100021
FSQRTS F3, F4 // b3140043
FSQRT F5, F15 // b31500f5
+ FIEBR $0, F0, F1 // b3570010
+ FIDBR $7, F2, F3 // b35f7032
VL (R15), V1 // e710f0000006
VST V1, (R15) // e710f000000e
@@ -209,9 +323,20 @@ TEXT main·foo(SB),7,$16-0 // TEXT main.foo(SB), 7, $16-0
VERIMB $2, V31, V1, V2 // VERIMB V31, V1, $2, V2 // e72f10020472
VSEL V1, V2, V3, V4 // VSEL V2, V3, V1, V4 // e7412000308d
VGFMAH V21, V31, V24, V0 // VGFMAH V31, V24, V21, V0 // e705f10087bc
- WFMSDB V2, V25, V24, V31 // WFMSDB V25, V24, V2, V31 // e7f298038b8e
+ 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
RET
diff --git a/src/cmd/asm/internal/flags/flags.go b/src/cmd/asm/internal/flags/flags.go
index 4557c2a..bd90b82 100644
--- a/src/cmd/asm/internal/flags/flags.go
+++ b/src/cmd/asm/internal/flags/flags.go
@@ -15,7 +15,7 @@ import (
var (
Debug = flag.Bool("debug", false, "dump instructions as they are parsed")
- OutputFile = flag.String("o", "", "output file; default foo.6 for /a/b/c/foo.s on amd64")
+ OutputFile = flag.String("o", "", "output file; default foo.o for /a/b/c/foo.s as first argument")
PrintOut = flag.Bool("S", false, "print assembly and machine code")
TrimPath = flag.String("trimpath", "", "remove prefix from recorded source file paths")
Shared = flag.Bool("shared", false, "generate code that can be linked into a shared library")
@@ -49,7 +49,7 @@ func (m *MultiFlag) Set(val string) error {
}
func Usage() {
- fmt.Fprintf(os.Stderr, "usage: asm [options] file.s\n")
+ fmt.Fprintf(os.Stderr, "usage: asm [options] file.s ...\n")
fmt.Fprintf(os.Stderr, "Flags:\n")
flag.PrintDefaults()
os.Exit(2)
@@ -58,12 +58,15 @@ func Usage() {
func Parse() {
flag.Usage = Usage
flag.Parse()
- if flag.NArg() != 1 {
+ if flag.NArg() == 0 {
flag.Usage()
}
// Flag refinement.
if *OutputFile == "" {
+ if flag.NArg() != 1 {
+ flag.Usage()
+ }
input := filepath.Base(flag.Arg(0))
if strings.HasSuffix(input, ".s") {
input = input[:len(input)-2]
diff --git a/src/cmd/asm/main.go b/src/cmd/asm/main.go
index c612583..13e5302 100644
--- a/src/cmd/asm/main.go
+++ b/src/cmd/asm/main.go
@@ -24,7 +24,7 @@ func main() {
log.SetFlags(0)
log.SetPrefix("asm: ")
- GOARCH := obj.Getgoarch()
+ GOARCH := obj.GOARCH
architecture := arch.Set(GOARCH)
if architecture == nil {
@@ -51,25 +51,36 @@ func main() {
defer bio.MustClose(out)
buf := bufio.NewWriter(bio.MustWriter(out))
- fmt.Fprintf(buf, "go object %s %s %s\n", obj.Getgoos(), obj.Getgoarch(), obj.Getgoversion())
+ fmt.Fprintf(buf, "go object %s %s %s\n", obj.GOOS, obj.GOARCH, obj.Version)
fmt.Fprintf(buf, "!\n")
- lexer := lex.NewLexer(flag.Arg(0), ctxt)
- parser := asm.NewParser(ctxt, architecture, lexer)
- diag := false
- ctxt.DiagFunc = func(format string, args ...interface{}) {
- diag = true
- log.Printf(format, args...)
+ var ok, diag bool
+ var failedFile string
+ for _, f := range flag.Args() {
+ lexer := lex.NewLexer(f, ctxt)
+ parser := asm.NewParser(ctxt, architecture, lexer)
+ ctxt.DiagFunc = func(format string, args ...interface{}) {
+ diag = true
+ log.Printf(format, args...)
+ }
+ pList := obj.Linknewplist(ctxt)
+ pList.Firstpc, ok = parser.Parse()
+ if !ok {
+ failedFile = f
+ break
+ }
}
- pList := obj.Linknewplist(ctxt)
- var ok bool
- pList.Firstpc, ok = parser.Parse()
if ok {
// reports errors to parser.Errorf
obj.Writeobjdirect(ctxt, buf)
}
if !ok || diag {
- log.Printf("assembly of %s failed", flag.Arg(0))
+ if failedFile != "" {
+ log.Printf("assembly of %s failed", failedFile)
+ } else {
+ log.Print("assembly failed")
+ }
+ out.Close()
os.Remove(*flags.OutputFile)
os.Exit(1)
}
diff --git a/src/cmd/cgo/ast.go b/src/cmd/cgo/ast.go
index 000ecd4..8ce8241 100644
--- a/src/cmd/cgo/ast.go
+++ b/src/cmd/cgo/ast.go
@@ -87,6 +87,7 @@ func (f *File) ReadGo(name string) {
if cg != nil {
f.Preamble += fmt.Sprintf("#line %d %q\n", sourceLine(cg), name)
f.Preamble += commentText(cg) + "\n"
+ f.Preamble += "#line 1 \"cgo-generated-wrapper\"\n"
}
}
}
@@ -296,7 +297,7 @@ func (f *File) walk(x interface{}, context string, visit func(*File, interface{}
// everything else just recurs
default:
- error_(token.NoPos, "unexpected type %T in walk", x, visit)
+ error_(token.NoPos, "unexpected type %T in walk", x)
panic("unexpected type")
case nil:
diff --git a/src/cmd/cgo/doc.go b/src/cmd/cgo/doc.go
index d3a7b6d..85441e6 100644
--- a/src/cmd/cgo/doc.go
+++ b/src/cmd/cgo/doc.go
@@ -53,6 +53,8 @@ For example:
// #include <png.h>
import "C"
+The default pkg-config tool may be changed by setting the PKG_CONFIG environment variable.
+
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
@@ -214,6 +216,13 @@ by making copies of the data. In pseudo-Go definitions:
// C data with explicit length to Go []byte
func C.GoBytes(unsafe.Pointer, C.int) []byte
+As a special case, C.malloc does not call the C library malloc directly
+but instead calls a Go helper function that wraps the C library malloc
+but guarantees never to return nil. If C's malloc indicates out of memory,
+the helper function crashes the program, like when Go itself runs out
+of memory. Because C.malloc cannot fail, it has no two-result form
+that returns errno.
+
C references to Go
Go functions can be exported for use by C code in the following way:
@@ -317,6 +326,9 @@ The following options are available when running cgo directly:
Write out input file in Go syntax replacing C package
names with real values. Used to generate files in the
syscall package when bootstrapping a new target.
+ -srcdir directory
+ Find the Go input files, listed on the command line,
+ in directory.
-objdir directory
Put all generated files in directory.
-importpath string
diff --git a/src/cmd/cgo/gcc.go b/src/cmd/cgo/gcc.go
index fc1d011..670a73f 100644
--- a/src/cmd/cgo/gcc.go
+++ b/src/cmd/cgo/gcc.go
@@ -167,7 +167,23 @@ func (p *Package) Translate(f *File) {
if len(needType) > 0 {
p.loadDWARF(f, needType)
}
- p.rewriteCalls(f)
+ if p.rewriteCalls(f) {
+ // Add `import _cgo_unsafe "unsafe"` as the first decl
+ // after the package statement.
+ imp := &ast.GenDecl{
+ Tok: token.IMPORT,
+ Specs: []ast.Spec{
+ &ast.ImportSpec{
+ Name: ast.NewIdent("_cgo_unsafe"),
+ Path: &ast.BasicLit{
+ Kind: token.STRING,
+ Value: `"unsafe"`,
+ },
+ },
+ },
+ }
+ f.AST.Decls = append([]ast.Decl{imp}, f.AST.Decls...)
+ }
p.rewriteRef(f)
}
@@ -413,6 +429,7 @@ func (p *Package) loadDWARF(f *File, names []*Name) {
var b bytes.Buffer
b.WriteString(f.Preamble)
b.WriteString(builtinProlog)
+ 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" {
@@ -578,7 +595,9 @@ func (p *Package) mangleName(n *Name) {
// rewriteCalls rewrites all calls that pass pointers to check that
// they follow the rules for passing pointers between Go and C.
-func (p *Package) rewriteCalls(f *File) {
+// This returns whether the package needs to import unsafe as _cgo_unsafe.
+func (p *Package) rewriteCalls(f *File) bool {
+ needsUnsafe := false
for _, call := range f.Calls {
// This is a call to C.xxx; set goname to "xxx".
goname := call.Call.Fun.(*ast.SelectorExpr).Sel.Name
@@ -590,18 +609,24 @@ func (p *Package) rewriteCalls(f *File) {
// Probably a type conversion.
continue
}
- p.rewriteCall(f, call, name)
+ if p.rewriteCall(f, call, name) {
+ needsUnsafe = true
+ }
}
+ return needsUnsafe
}
-// rewriteCall rewrites one call to add pointer checks. We replace
-// each pointer argument x with _cgoCheckPointer(x).(T).
-func (p *Package) rewriteCall(f *File, call *Call, name *Name) {
+// rewriteCall rewrites one call to add pointer checks.
+// If any pointer checks are required, we rewrite the call into a
+// function literal that calls _cgoCheckPointer for each pointer
+// argument and then calls the original function.
+// This returns whether the package needs to import unsafe as _cgo_unsafe.
+func (p *Package) rewriteCall(f *File, call *Call, name *Name) bool {
// Avoid a crash if the number of arguments is
// less than the number of parameters.
// This will be caught when the generated file is compiled.
if len(call.Call.Args) < len(name.FuncType.Params) {
- return
+ return false
}
any := false
@@ -612,38 +637,60 @@ func (p *Package) rewriteCall(f *File, call *Call, name *Name) {
}
}
if !any {
- return
+ return false
}
// We need to rewrite this call.
//
- // We are going to rewrite C.f(p) to C.f(_cgoCheckPointer(p)).
- // If the call to C.f is deferred, that will check p at the
- // point of the defer statement, not when the function is called, so
- // rewrite to func(_cgo0 ptype) { C.f(_cgoCheckPointer(_cgo0)) }(p)
-
- var dargs []ast.Expr
- if call.Deferred {
- dargs = make([]ast.Expr, len(name.FuncType.Params))
- }
+ // We are going to rewrite C.f(p) to
+ // func (_cgo0 ptype) {
+ // _cgoCheckPointer(_cgo0)
+ // C.f(_cgo0)
+ // }(p)
+ // Using a function literal like this lets us do correct
+ // argument type checking, and works correctly if the call is
+ // deferred.
+ needsUnsafe := false
+ params := make([]*ast.Field, len(name.FuncType.Params))
+ nargs := make([]ast.Expr, len(name.FuncType.Params))
+ var stmts []ast.Stmt
for i, param := range name.FuncType.Params {
+ // params is going to become the parameters of the
+ // function literal.
+ // nargs is going to become the list of arguments made
+ // by the call within the function literal.
+ // nparam is the parameter of the function literal that
+ // corresponds to param.
+
origArg := call.Call.Args[i]
- darg := origArg
+ nparam := ast.NewIdent(fmt.Sprintf("_cgo%d", i))
+ nargs[i] = nparam
- if call.Deferred {
- dargs[i] = darg
- darg = ast.NewIdent(fmt.Sprintf("_cgo%d", i))
- call.Call.Args[i] = darg
+ // The Go version of the C type might use unsafe.Pointer,
+ // but the file might not import unsafe.
+ // Rewrite the Go type if necessary to use _cgo_unsafe.
+ ptype := p.rewriteUnsafe(param.Go)
+ if ptype != param.Go {
+ needsUnsafe = true
+ }
+
+ params[i] = &ast.Field{
+ Names: []*ast.Ident{nparam},
+ Type: ptype,
}
if !p.needsPointerCheck(f, param.Go, origArg) {
continue
}
+ // Run the cgo pointer checks on nparam.
+
+ // Change the function literal to call the real function
+ // with the parameter passed through _cgoCheckPointer.
c := &ast.CallExpr{
Fun: ast.NewIdent("_cgoCheckPointer"),
Args: []ast.Expr{
- darg,
+ nparam,
},
}
@@ -651,95 +698,83 @@ func (p *Package) rewriteCall(f *File, call *Call, name *Name) {
// expression.
c.Args = p.checkAddrArgs(f, c.Args, origArg)
- // _cgoCheckPointer returns interface{}.
- // We need to type assert that to the type we want.
- // If the Go version of this C type uses
- // unsafe.Pointer, we can't use a type assertion,
- // because the Go file might not import unsafe.
- // Instead we use a local variant of _cgoCheckPointer.
-
- var arg ast.Expr
- if n := p.unsafeCheckPointerName(param.Go, call.Deferred); n != "" {
- c.Fun = ast.NewIdent(n)
- arg = c
- } else {
- // In order for the type assertion to succeed,
- // we need it to match the actual type of the
- // argument. The only type we have is the
- // type of the function parameter. We know
- // that the argument type must be assignable
- // to the function parameter type, or the code
- // would not compile, but there is nothing
- // requiring that the types be exactly the
- // same. Add a type conversion to the
- // argument so that the type assertion will
- // succeed.
- c.Args[0] = &ast.CallExpr{
- Fun: param.Go,
- Args: []ast.Expr{
- c.Args[0],
- },
- }
-
- arg = &ast.TypeAssertExpr{
- X: c,
- Type: param.Go,
- }
+ stmt := &ast.ExprStmt{
+ X: c,
}
-
- call.Call.Args[i] = arg
+ stmts = append(stmts, stmt)
}
- if call.Deferred {
- params := make([]*ast.Field, len(name.FuncType.Params))
- for i, param := range name.FuncType.Params {
- ptype := param.Go
- if p.hasUnsafePointer(ptype) {
- // Avoid generating unsafe.Pointer by using
- // interface{}. This works because we are
- // going to call a _cgoCheckPointer function
- // anyhow.
- ptype = &ast.InterfaceType{
- Methods: &ast.FieldList{},
- }
- }
- params[i] = &ast.Field{
- Names: []*ast.Ident{
- ast.NewIdent(fmt.Sprintf("_cgo%d", i)),
- },
- Type: ptype,
- }
- }
-
- dbody := &ast.CallExpr{
- Fun: call.Call.Fun,
- Args: call.Call.Args,
+ fcall := &ast.CallExpr{
+ Fun: call.Call.Fun,
+ Args: nargs,
+ }
+ ftype := &ast.FuncType{
+ Params: &ast.FieldList{
+ List: params,
+ },
+ }
+ if name.FuncType.Result != nil {
+ rtype := p.rewriteUnsafe(name.FuncType.Result.Go)
+ if rtype != name.FuncType.Result.Go {
+ needsUnsafe = true
}
- call.Call.Fun = &ast.FuncLit{
- Type: &ast.FuncType{
- Params: &ast.FieldList{
- List: params,
- },
- },
- Body: &ast.BlockStmt{
- List: []ast.Stmt{
- &ast.ExprStmt{
- X: dbody,
- },
+ ftype.Results = &ast.FieldList{
+ List: []*ast.Field{
+ &ast.Field{
+ Type: rtype,
},
},
}
- call.Call.Args = dargs
- call.Call.Lparen = token.NoPos
- call.Call.Rparen = token.NoPos
+ }
- // There is a Ref pointing to the old call.Call.Fun.
- for _, ref := range f.Ref {
- if ref.Expr == &call.Call.Fun {
- ref.Expr = &dbody.Fun
+ // There is a Ref pointing to the old call.Call.Fun.
+ for _, ref := range f.Ref {
+ if ref.Expr == &call.Call.Fun {
+ ref.Expr = &fcall.Fun
+
+ // If this call expects two results, we have to
+ // adjust the results of the function we generated.
+ if ref.Context == "call2" {
+ if ftype.Results == nil {
+ // An explicit void argument
+ // looks odd but it seems to
+ // be how cgo has worked historically.
+ ftype.Results = &ast.FieldList{
+ List: []*ast.Field{
+ &ast.Field{
+ Type: ast.NewIdent("_Ctype_void"),
+ },
+ },
+ }
+ }
+ ftype.Results.List = append(ftype.Results.List,
+ &ast.Field{
+ Type: ast.NewIdent("error"),
+ })
}
}
}
+
+ var fbody ast.Stmt
+ if ftype.Results == nil {
+ fbody = &ast.ExprStmt{
+ X: fcall,
+ }
+ } else {
+ fbody = &ast.ReturnStmt{
+ Results: []ast.Expr{fcall},
+ }
+ }
+ call.Call.Fun = &ast.FuncLit{
+ Type: ftype,
+ Body: &ast.BlockStmt{
+ List: append(stmts, fbody),
+ },
+ }
+ call.Call.Lparen = token.NoPos
+ call.Call.Rparen = token.NoPos
+
+ return needsUnsafe
}
// needsPointerCheck returns whether the type t needs a pointer check.
@@ -782,6 +817,11 @@ func (p *Package) hasPointer(f *File, t ast.Expr, top bool) bool {
if !top {
return true
}
+ // Check whether this is a pointer to a C union (or class)
+ // type that contains a pointer.
+ if unionWithPointer[t.X] {
+ return true
+ }
return p.hasPointer(f, t.X, false)
case *ast.FuncType, *ast.InterfaceType, *ast.MapType, *ast.ChanType:
return true
@@ -935,69 +975,52 @@ func (p *Package) isType(t ast.Expr) bool {
return false
}
-// unsafeCheckPointerName is given the Go version of a C type. If the
-// type uses unsafe.Pointer, we arrange to build a version of
-// _cgoCheckPointer that returns that type. This avoids using a type
-// assertion to unsafe.Pointer in our copy of user code. We return
-// the name of the _cgoCheckPointer function we are going to build, or
-// the empty string if the type does not use unsafe.Pointer.
-//
-// The deferred parameter is true if this check is for the argument of
-// a deferred function. In that case we need to use an empty interface
-// as the argument type, because the deferred function we introduce in
-// rewriteCall will use an empty interface type, and we can't add a
-// type assertion. This is handled by keeping a separate list, and
-// writing out the lists separately in writeDefs.
-func (p *Package) unsafeCheckPointerName(t ast.Expr, deferred bool) string {
- if !p.hasUnsafePointer(t) {
- return ""
- }
- var buf bytes.Buffer
- conf.Fprint(&buf, fset, t)
- s := buf.String()
- checks := &p.CgoChecks
- if deferred {
- checks = &p.DeferredCgoChecks
- }
- for i, t := range *checks {
- if s == t {
- return p.unsafeCheckPointerNameIndex(i, deferred)
- }
- }
- *checks = append(*checks, s)
- return p.unsafeCheckPointerNameIndex(len(*checks)-1, deferred)
-}
-
-// hasUnsafePointer returns whether the Go type t uses unsafe.Pointer.
-// t is the Go version of a C type, so we don't need to handle every case.
-// We only care about direct references, not references via typedefs.
-func (p *Package) hasUnsafePointer(t ast.Expr) bool {
+// rewriteUnsafe returns a version of t with references to unsafe.Pointer
+// rewritten to use _cgo_unsafe.Pointer instead.
+func (p *Package) rewriteUnsafe(t ast.Expr) ast.Expr {
switch t := t.(type) {
case *ast.Ident:
// We don't see a SelectorExpr for unsafe.Pointer;
// this is created by code in this file.
- return t.Name == "unsafe.Pointer"
+ if t.Name == "unsafe.Pointer" {
+ return ast.NewIdent("_cgo_unsafe.Pointer")
+ }
case *ast.ArrayType:
- return p.hasUnsafePointer(t.Elt)
+ t1 := p.rewriteUnsafe(t.Elt)
+ if t1 != t.Elt {
+ r := *t
+ r.Elt = t1
+ return &r
+ }
case *ast.StructType:
+ changed := false
+ fields := *t.Fields
+ fields.List = nil
for _, f := range t.Fields.List {
- if p.hasUnsafePointer(f.Type) {
- return true
+ ft := p.rewriteUnsafe(f.Type)
+ if ft == f.Type {
+ fields.List = append(fields.List, f)
+ } else {
+ fn := *f
+ fn.Type = ft
+ fields.List = append(fields.List, &fn)
+ changed = true
}
}
+ if changed {
+ r := *t
+ r.Fields = &fields
+ return &r
+ }
case *ast.StarExpr: // Pointer type.
- return p.hasUnsafePointer(t.X)
- }
- return false
-}
-
-// unsafeCheckPointerNameIndex returns the name to use for a
-// _cgoCheckPointer variant based on the index in the CgoChecks slice.
-func (p *Package) unsafeCheckPointerNameIndex(i int, deferred bool) string {
- if deferred {
- return fmt.Sprintf("_cgoCheckPointerInDefer%d", i)
+ x1 := p.rewriteUnsafe(t.X)
+ if x1 != t.X {
+ r := *t
+ r.X = x1
+ return &r
+ }
}
- return fmt.Sprintf("_cgoCheckPointer%d", i)
+ return t
}
// rewriteRef rewrites all the C.xxx references in f.AST to refer to the
@@ -1415,6 +1438,10 @@ var tagGen int
var typedef = make(map[string]*Type)
var goIdent = make(map[string]*ast.Ident)
+// unionWithPointer is true for a Go type that represents a C union (or class)
+// that may contain a pointer. This is used for cgo pointer checking.
+var unionWithPointer = make(map[ast.Expr]bool)
+
func (c *typeConv) Init(ptrSize, intSize int64) {
c.ptrSize = ptrSize
c.intSize = intSize
@@ -1464,6 +1491,19 @@ func base(dt dwarf.Type) dwarf.Type {
return dt
}
+// unqual strips away qualifiers from a DWARF type.
+// In general we don't care about top-level qualifiers.
+func unqual(dt dwarf.Type) dwarf.Type {
+ for {
+ if d, ok := dt.(*dwarf.QualType); ok {
+ dt = d.Type
+ } else {
+ break
+ }
+ }
+ return dt
+}
+
// Map from dwarf text names to aliases we use in package "C".
var dwarfToName = map[string]string{
"long int": "long",
@@ -1641,7 +1681,7 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type {
case 16:
t.Go = c.complex128
}
- if t.Align = t.Size; t.Align >= c.ptrSize {
+ if t.Align = t.Size / 2; t.Align >= c.ptrSize {
t.Align = c.ptrSize
}
@@ -1699,9 +1739,16 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type {
c.ptrs[dt.Type] = append(c.ptrs[dt.Type], t)
case *dwarf.QualType:
- // Ignore qualifier.
- t = c.Type(dt.Type, pos)
- c.m[dtype] = t
+ t1 := c.Type(dt.Type, pos)
+ t.Size = t1.Size
+ t.Align = t1.Align
+ t.Go = t1.Go
+ if unionWithPointer[t1.Go] {
+ unionWithPointer[t.Go] = true
+ }
+ t.EnumValues = nil
+ t.Typedef = ""
+ t.C.Set("%s "+dt.Qual, t1.C)
return t
case *dwarf.StructType:
@@ -1733,6 +1780,9 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type {
switch dt.Kind {
case "class", "union":
t.Go = c.Opaque(t.Size)
+ if c.dwarfHasPointer(dt, pos) {
+ unionWithPointer[t.Go] = true
+ }
if t.C.Empty() {
t.C.Set("__typeof__(unsigned char[%d])", t.Size)
}
@@ -1775,6 +1825,9 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type {
goIdent[name.Name] = name
sub := c.Type(dt.Type, pos)
t.Go = name
+ if unionWithPointer[sub.Go] {
+ unionWithPointer[t.Go] = true
+ }
t.Size = sub.Size
t.Align = sub.Align
oldType := typedef[name.Name]
@@ -1905,7 +1958,7 @@ func isStructUnionClass(x ast.Expr) bool {
// FuncArg returns a Go type with the same memory layout as
// dtype when used as the type of a C function argument.
func (c *typeConv) FuncArg(dtype dwarf.Type, pos token.Pos) *Type {
- t := c.Type(dtype, pos)
+ t := c.Type(unqual(dtype), pos)
switch dt := dtype.(type) {
case *dwarf.ArrayType:
// Arrays are passed implicitly as pointers in C.
@@ -1935,9 +1988,12 @@ func (c *typeConv) FuncArg(dtype dwarf.Type, pos token.Pos) *Type {
return nil
}
- // Remember the C spelling, in case the struct
- // has __attribute__((unavailable)) on it. See issue 2888.
- t.Typedef = dt.Name
+ // For a struct/union/class, remember the C spelling,
+ // in case it has __attribute__((unavailable)).
+ // See issue 2888.
+ if isStructUnionClass(t.Go) {
+ t.Typedef = dt.Name
+ }
}
}
return t
@@ -1966,7 +2022,7 @@ func (c *typeConv) FuncType(dtype *dwarf.FuncType, pos token.Pos) *FuncType {
if _, ok := dtype.ReturnType.(*dwarf.VoidType); ok {
gr = []*ast.Field{{Type: c.goVoid}}
} else if dtype.ReturnType != nil {
- r = c.Type(dtype.ReturnType, pos)
+ r = c.Type(unqual(dtype.ReturnType), pos)
gr = []*ast.Field{{Type: r.Go}}
}
return &FuncType{
@@ -2153,6 +2209,44 @@ func (c *typeConv) Struct(dt *dwarf.StructType, pos token.Pos) (expr *ast.Struct
return
}
+// dwarfHasPointer returns whether the DWARF type dt contains a pointer.
+func (c *typeConv) dwarfHasPointer(dt dwarf.Type, pos token.Pos) bool {
+ switch dt := dt.(type) {
+ default:
+ fatalf("%s: unexpected type: %s", lineno(pos), dt)
+ return false
+
+ case *dwarf.AddrType, *dwarf.BoolType, *dwarf.CharType, *dwarf.EnumType,
+ *dwarf.FloatType, *dwarf.ComplexType, *dwarf.FuncType,
+ *dwarf.IntType, *dwarf.UcharType, *dwarf.UintType, *dwarf.VoidType:
+
+ return false
+
+ case *dwarf.ArrayType:
+ return c.dwarfHasPointer(dt.Type, pos)
+
+ case *dwarf.PtrType:
+ return true
+
+ case *dwarf.QualType:
+ return c.dwarfHasPointer(dt.Type, pos)
+
+ case *dwarf.StructType:
+ for _, f := range dt.Field {
+ if c.dwarfHasPointer(f.Type, pos) {
+ return true
+ }
+ }
+ return false
+
+ case *dwarf.TypedefType:
+ if dt.Name == "_GoString_" || dt.Name == "_GoBytes_" {
+ return true
+ }
+ return c.dwarfHasPointer(dt.Type, pos)
+ }
+}
+
func upper(s string) string {
if s == "" {
return ""
diff --git a/src/cmd/cgo/main.go b/src/cmd/cgo/main.go
index 72ac19a..df27983 100644
--- a/src/cmd/cgo/main.go
+++ b/src/cmd/cgo/main.go
@@ -42,10 +42,6 @@ type Package struct {
GoFiles []string // list of Go files
GccFiles []string // list of gcc output files
Preamble string // collected preamble for _cgo_export.h
-
- // See unsafeCheckPointerName.
- CgoChecks []string
- DeferredCgoChecks []string
}
// A File collects information about a single Go input file.
@@ -147,6 +143,8 @@ var ptrSizeMap = map[string]int64{
"amd64": 8,
"arm": 4,
"arm64": 8,
+ "mips": 4,
+ "mipsle": 4,
"mips64": 8,
"mips64le": 8,
"ppc64": 8,
@@ -160,6 +158,8 @@ var intSizeMap = map[string]int64{
"amd64": 8,
"arm": 4,
"arm64": 8,
+ "mips": 4,
+ "mipsle": 4,
"mips64": 8,
"mips64le": 8,
"ppc64": 8,
@@ -182,6 +182,7 @@ var dynlinker = flag.Bool("dynlinker", false, "record dynamic linker information
// constant values used in the host's C libraries and system calls.
var godefs = flag.Bool("godefs", false, "for bootstrap: write Go definitions for C file to standard output")
+var srcDir = flag.String("srcdir", "", "source directory")
var objDir = flag.String("objdir", "", "object directory")
var importPath = flag.String("importpath", "", "import path of package being built (for comments in generated files)")
var exportHeader = flag.String("exportheader", "", "where to write export header if any exported functions")
@@ -260,6 +261,9 @@ func main() {
// Use the beginning of the md5 of the input to disambiguate.
h := md5.New()
for _, input := range goFiles {
+ if *srcDir != "" {
+ input = filepath.Join(*srcDir, input)
+ }
f, err := os.Open(input)
if err != nil {
fatalf("%s", err)
@@ -271,6 +275,9 @@ func main() {
fs := make([]*File, len(goFiles))
for i, input := range goFiles {
+ if *srcDir != "" {
+ input = filepath.Join(*srcDir, input)
+ }
f := new(File)
f.ReadGo(input)
f.DiscardCgoDirectives()
diff --git a/src/cmd/cgo/out.go b/src/cmd/cgo/out.go
index 842b1c5..e82ec37 100644
--- a/src/cmd/cgo/out.go
+++ b/src/cmd/cgo/out.go
@@ -19,7 +19,10 @@ import (
"strings"
)
-var conf = printer.Config{Mode: printer.SourcePos, Tabwidth: 8}
+var (
+ conf = printer.Config{Mode: printer.SourcePos, Tabwidth: 8}
+ noSourceConf = printer.Config{Tabwidth: 8}
+)
// writeDefs creates output files to be compiled by gc and gcc.
func (p *Package) writeDefs() {
@@ -95,7 +98,19 @@ func (p *Package) writeDefs() {
for _, name := range typedefNames {
def := typedef[name]
fmt.Fprintf(fgo2, "type %s ", name)
- conf.Fprint(fgo2, fset, def.Go)
+ // We don't have source info for these types, so write them out without source info.
+ // Otherwise types would look like:
+ //
+ // type _Ctype_struct_cb struct {
+ // //line :1
+ // on_test *[0]byte
+ // //line :1
+ // }
+ //
+ // Which is not useful. Moreover we never override source info,
+ // so subsequent source code uses the same source info.
+ // Moreover, empty file name makes compile emit no source debug info at all.
+ noSourceConf.Fprint(fgo2, fset, def.Go)
fmt.Fprintf(fgo2, "\n\n")
}
if *gccgo {
@@ -111,17 +126,11 @@ func (p *Package) writeDefs() {
fmt.Fprint(fgo2, goProlog)
}
- for i, t := range p.CgoChecks {
- n := p.unsafeCheckPointerNameIndex(i, false)
- fmt.Fprintf(fgo2, "\nfunc %s(p %s, args ...interface{}) %s {\n", n, t, t)
- fmt.Fprintf(fgo2, "\treturn _cgoCheckPointer(p, args...).(%s)\n", t)
- fmt.Fprintf(fgo2, "}\n")
+ if fc != nil {
+ fmt.Fprintf(fc, "#line 1 \"cgo-generated-wrappers\"\n")
}
- for i, t := range p.DeferredCgoChecks {
- n := p.unsafeCheckPointerNameIndex(i, true)
- fmt.Fprintf(fgo2, "\nfunc %s(p interface{}, args ...interface{}) %s {\n", n, t)
- fmt.Fprintf(fgo2, "\treturn _cgoCheckPointer(p, args...).(%s)\n", t)
- fmt.Fprintf(fgo2, "}\n")
+ if fm != nil {
+ fmt.Fprintf(fm, "#line 1 \"cgo-generated-wrappers\"\n")
}
gccgoSymbolPrefix := p.gccgoSymbolPrefix()
@@ -346,11 +355,7 @@ func (p *Package) structType(n *Name) (string, int64) {
fmt.Fprintf(&buf, "\t\tchar __pad%d[%d];\n", off, pad)
off += pad
}
- qual := ""
- if c := t.C.String(); c[len(c)-1] == '*' {
- qual = "const "
- }
- fmt.Fprintf(&buf, "\t\t%s%s r;\n", qual, t.C)
+ fmt.Fprintf(&buf, "\t\t%s r;\n", t.C)
off += t.Size
}
if off%p.PtrSize != 0 {
@@ -611,20 +616,10 @@ func (p *Package) writeOutputFunc(fgcc *os.File, n *Name) {
}
}
fmt.Fprintf(fgcc, "%s(", n.C)
- for i, t := range n.FuncType.Params {
+ for i := range n.FuncType.Params {
if i > 0 {
fmt.Fprintf(fgcc, ", ")
}
- // We know the type params are correct, because
- // the Go equivalents had good type params.
- // However, our version of the type omits the magic
- // words const and volatile, which can provoke
- // C compiler warnings. Silence them by casting
- // all pointers to void*. (Eventually that will produce
- // other warnings.)
- if c := t.C.String(); c[len(c)-1] == '*' {
- fmt.Fprintf(fgcc, "(void*)")
- }
fmt.Fprintf(fgcc, "a->p%d", i)
}
fmt.Fprintf(fgcc, ");\n")
@@ -684,14 +679,10 @@ func (p *Package) writeGccgoOutputFunc(fgcc *os.File, n *Name) {
}
}
fmt.Fprintf(fgcc, "%s(", n.C)
- for i, t := range n.FuncType.Params {
+ for i := range n.FuncType.Params {
if i > 0 {
fmt.Fprintf(fgcc, ", ")
}
- // Cast to void* to avoid warnings due to omitted qualifiers.
- if c := t.C.String(); c[len(c)-1] == '*' {
- fmt.Fprintf(fgcc, "(void*)")
- }
fmt.Fprintf(fgcc, "p%d", i)
}
fmt.Fprintf(fgcc, ");\n")
@@ -1217,8 +1208,8 @@ var goTypes = map[string]*Type{
"uint64": {Size: 8, Align: 8, C: c("GoUint64")},
"float32": {Size: 4, Align: 4, C: c("GoFloat32")},
"float64": {Size: 8, Align: 8, C: c("GoFloat64")},
- "complex64": {Size: 8, Align: 8, C: c("GoComplex64")},
- "complex128": {Size: 16, Align: 16, C: c("GoComplex128")},
+ "complex64": {Size: 8, Align: 4, C: c("GoComplex64")},
+ "complex128": {Size: 16, Align: 8, C: c("GoComplex128")},
}
// Map an ast type to a Type.
@@ -1299,6 +1290,7 @@ func (p *Package) cgoType(e ast.Expr) *Type {
}
const gccProlog = `
+#line 1 "cgo-gcc-prolog"
/*
If x and y are not equal, the type will be invalid
(have a negative array count) and an inscrutable error will come
@@ -1332,6 +1324,7 @@ const noTsanProlog = `
// This must match the TSAN code in runtime/cgo/libcgo.h.
const yesTsanProlog = `
+#line 1 "cgo-tsan-prolog"
#define CGO_NO_SANITIZE_THREAD __attribute__ ((no_sanitize_thread))
long long _cgo_sync __attribute__ ((common));
@@ -1354,6 +1347,7 @@ static void _cgo_tsan_release() {
var tsanProlog = noTsanProlog
const builtinProlog = `
+#line 1 "cgo-builtin-prolog"
#include <stddef.h> /* for ptrdiff_t and size_t below */
/* Define intgo when compiling with GCC. */
@@ -1377,14 +1371,14 @@ func _cgo_runtime_cgocall(unsafe.Pointer, uintptr) int32
func _cgo_runtime_cgocallback(unsafe.Pointer, unsafe.Pointer, uintptr, uintptr)
//go:linkname _cgoCheckPointer runtime.cgoCheckPointer
-func _cgoCheckPointer(interface{}, ...interface{}) interface{}
+func _cgoCheckPointer(interface{}, ...interface{})
//go:linkname _cgoCheckResult runtime.cgoCheckResult
func _cgoCheckResult(interface{})
`
const gccgoGoProlog = `
-func _cgoCheckPointer(interface{}, ...interface{}) interface{}
+func _cgoCheckPointer(interface{}, ...interface{})
func _cgoCheckResult(interface{})
`
@@ -1461,9 +1455,15 @@ const cMallocDefGo = `
var __cgofn__cgoPREFIX_Cfunc__Cmalloc byte
var _cgoPREFIX_Cfunc__Cmalloc = unsafe.Pointer(&__cgofn__cgoPREFIX_Cfunc__Cmalloc)
+//go:linkname runtime_throw runtime.throw
+func runtime_throw(string)
+
//go:cgo_unsafe_args
func _cgo_cmalloc(p0 uint64) (r1 unsafe.Pointer) {
_cgo_runtime_cgocall(_cgoPREFIX_Cfunc__Cmalloc, uintptr(unsafe.Pointer(&p0)))
+ if r1 == nil {
+ runtime_throw("runtime: C malloc failed")
+ }
return
}
`
@@ -1500,6 +1500,7 @@ func (p *Package) cPrologGccgo() string {
}
const cPrologGccgo = `
+#line 1 "cgo-c-prolog-gccgo"
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
@@ -1564,18 +1565,17 @@ typedef struct __go_empty_interface {
void *__object;
} Eface;
-extern Eface runtimeCgoCheckPointer(Eface, Slice)
+extern void runtimeCgoCheckPointer(Eface, Slice)
__asm__("runtime.cgoCheckPointer")
__attribute__((weak));
-extern Eface localCgoCheckPointer(Eface, Slice)
+extern void localCgoCheckPointer(Eface, Slice)
__asm__("GCCGOSYMBOLPREF._cgoCheckPointer");
-Eface localCgoCheckPointer(Eface ptr, Slice args) {
+void localCgoCheckPointer(Eface ptr, Slice args) {
if(runtimeCgoCheckPointer) {
- return runtimeCgoCheckPointer(ptr, args);
+ runtimeCgoCheckPointer(ptr, args);
}
- return ptr;
}
extern void runtimeCgoCheckResult(Eface)
@@ -1598,6 +1598,7 @@ func (p *Package) gccExportHeaderProlog() string {
const gccExportHeaderProlog = `
/* Start of boilerplate cgo prologue. */
+#line 1 "cgo-gcc-export-header-prolog"
#ifndef GO_CGO_PROLOGUE_H
#define GO_CGO_PROLOGUE_H
@@ -1651,6 +1652,7 @@ const gccExportHeaderEpilog = `
// We use weak declarations, and test the addresses, so that this code
// works with older versions of gccgo.
const gccgoExportFileProlog = `
+#line 1 "cgo-gccgo-export-file-prolog"
extern _Bool runtime_iscgo __attribute__ ((weak));
static void GoInit(void) __attribute__ ((constructor));
diff --git a/src/cmd/compile/fmt_test.go b/src/cmd/compile/fmt_test.go
new file mode 100644
index 0000000..1a64808
--- /dev/null
+++ b/src/cmd/compile/fmt_test.go
@@ -0,0 +1,716 @@
+// Copyright 2016 The Go 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 TestFormats; a test that verifies
+// format strings in the compiler (this directory and all
+// subdirectories, recursively).
+//
+// TestFormats finds potential (Printf, etc.) format strings.
+// If they are used in a call, the format verbs are verified
+// based on the matching argument type against a precomputed
+// table of valid formats. The knownFormats table can be used
+// to automatically rewrite format strings with the -u flag.
+//
+// A new knownFormats table based on the found formats is printed
+// when the test is run in verbose mode (-v flag). The table
+// needs to be updated whenever a new (type, format) combination
+// is found and the format verb is not 'v' or 'T' (as in "%v" or
+// "%T").
+//
+// Run as: go test -run Formats [-u][-v]
+//
+// Known bugs:
+// - indexed format strings ("%[2]s", etc.) are not supported
+// (the test will fail)
+// - format strings that are not simple string literals cannot
+// be updated automatically
+// (the test will fail with respective warnings)
+// - format strings in _test packages outside the current
+// package are not processed
+// (the test will report those files)
+//
+package main_test
+
+import (
+ "bytes"
+ "flag"
+ "fmt"
+ "go/ast"
+ "go/build"
+ "go/constant"
+ "go/format"
+ "go/importer"
+ "go/parser"
+ "go/token"
+ "go/types"
+ "internal/testenv"
+ "io/ioutil"
+ "log"
+ "os"
+ "path/filepath"
+ "sort"
+ "strconv"
+ "strings"
+ "testing"
+ "unicode/utf8"
+)
+
+var update = flag.Bool("u", false, "update format strings")
+
+// The following variables collect information across all processed files.
+var (
+ fset = token.NewFileSet()
+ formatStrings = make(map[*ast.BasicLit]bool) // set of all potential format strings found
+ foundFormats = make(map[string]bool) // set of all formats found
+ callSites = make(map[*ast.CallExpr]*callSite) // map of all calls
+)
+
+// A File is a corresponding (filename, ast) pair.
+type File struct {
+ name string
+ ast *ast.File
+}
+
+func TestFormats(t *testing.T) {
+ testenv.MustHaveGoBuild(t) // more restrictive than necessary, but that's ok
+
+ // process all directories
+ filepath.Walk(".", func(path string, info os.FileInfo, err error) error {
+ if info.IsDir() {
+ if info.Name() == "testdata" {
+ return filepath.SkipDir
+ }
+
+ importPath := filepath.Join("cmd/compile", path)
+ if blacklistedPackages[filepath.ToSlash(importPath)] {
+ return filepath.SkipDir
+ }
+
+ pkg, err := build.Import(importPath, path, 0)
+ if err != nil {
+ if _, ok := err.(*build.NoGoError); ok {
+ return nil // nothing to do here
+ }
+ t.Fatal(err)
+ }
+ collectPkgFormats(t, pkg)
+ }
+ return nil
+ })
+
+ // test and rewrite formats
+ updatedFiles := make(map[string]File) // files that were rewritten
+ for _, p := range callSites {
+ // test current format literal and determine updated one
+ out := formatReplace(p.str, func(index int, in string) string {
+ if in == "*" {
+ return in // cannot rewrite '*' (as in "%*d")
+ }
+ // in != '*'
+ typ := p.types[index]
+ format := typ + " " + in // e.g., "*Node %n"
+
+ // check if format is known
+ out, known := knownFormats[format]
+
+ // record format if not yet found
+ _, found := foundFormats[format]
+ if !found {
+ foundFormats[format] = true
+ }
+
+ // report an error if the format is unknown and this is the first
+ // time we see it; ignore "%v" and "%T" which are always valid
+ if !known && !found && in != "%v" && in != "%T" {
+ t.Errorf("%s: unknown format %q for %s argument", posString(p.arg), in, typ)
+ }
+
+ if out == "" {
+ out = in
+ }
+ return out
+ })
+
+ // replace existing format literal if it changed
+ if out != p.str {
+ // we cannot replace the argument if it's not a string literal for now
+ // (e.g., it may be "foo" + "bar")
+ lit, ok := p.arg.(*ast.BasicLit)
+ if !ok {
+ delete(callSites, p.call) // treat as if we hadn't found this site
+ continue
+ }
+
+ if testing.Verbose() {
+ fmt.Printf("%s:\n\t- %q\n\t+ %q\n", posString(p.arg), p.str, out)
+ }
+
+ // find argument index of format argument
+ index := -1
+ for i, arg := range p.call.Args {
+ if p.arg == arg {
+ index = i
+ break
+ }
+ }
+ if index < 0 {
+ // we may have processed the same call site twice,
+ // but that shouldn't happen
+ panic("internal error: matching argument not found")
+ }
+
+ // replace literal
+ new := *lit // make a copy
+ new.Value = strconv.Quote(out) // this may introduce "-quotes where there were `-quotes
+ p.call.Args[index] = &new
+ updatedFiles[p.file.name] = p.file
+ }
+ }
+
+ // write dirty files back
+ var filesUpdated bool
+ if len(updatedFiles) > 0 && *update {
+ for _, file := range updatedFiles {
+ var buf bytes.Buffer
+ if err := format.Node(&buf, fset, file.ast); err != nil {
+ t.Errorf("WARNING: formatting %s failed: %v", file.name, err)
+ continue
+ }
+ if err := ioutil.WriteFile(file.name, buf.Bytes(), 0x666); err != nil {
+ t.Errorf("WARNING: writing %s failed: %v", file.name, err)
+ continue
+ }
+ fmt.Printf("updated %s\n", file.name)
+ filesUpdated = true
+ }
+ }
+
+ // report all function names containing a format string
+ if len(callSites) > 0 && testing.Verbose() {
+ set := make(map[string]bool)
+ for _, p := range callSites {
+ set[nodeString(p.call.Fun)] = true
+ }
+ var list []string
+ for s := range set {
+ list = append(list, s)
+ }
+ fmt.Println("\nFunctions")
+ printList(list)
+ }
+
+ // report all formats found
+ if len(foundFormats) > 0 && testing.Verbose() {
+ var list []string
+ for s := range foundFormats {
+ list = append(list, fmt.Sprintf("%q: \"\",", s))
+ }
+ fmt.Println("\nvar knownFormats = map[string]string{")
+ printList(list)
+ fmt.Println("}")
+ }
+
+ // check that knownFormats is up to date
+ if !testing.Verbose() && !*update {
+ var mismatch bool
+ for s := range foundFormats {
+ if _, ok := knownFormats[s]; !ok {
+ mismatch = true
+ break
+ }
+ }
+ if !mismatch {
+ for s := range knownFormats {
+ if _, ok := foundFormats[s]; !ok {
+ mismatch = true
+ break
+ }
+ }
+ }
+ if mismatch {
+ t.Errorf("knownFormats is out of date; please run with -v to regenerate")
+ }
+ }
+
+ // all format strings of calls must be in the formatStrings set (self-verification)
+ for _, p := range callSites {
+ if lit, ok := p.arg.(*ast.BasicLit); ok && lit.Kind == token.STRING {
+ if formatStrings[lit] {
+ // ok
+ delete(formatStrings, lit)
+ } else {
+ // this should never happen
+ panic(fmt.Sprintf("internal error: format string not found (%s)", posString(lit)))
+ }
+ }
+ }
+
+ // if we have any strings left, we may need to update them manually
+ if len(formatStrings) > 0 && filesUpdated {
+ var list []string
+ for lit := range formatStrings {
+ list = append(list, fmt.Sprintf("%s: %s", posString(lit), nodeString(lit)))
+ }
+ fmt.Println("\nWARNING: Potentially missed format strings")
+ printList(list)
+ t.Fail()
+ }
+
+ fmt.Println()
+}
+
+// A callSite describes a function call that appears to contain
+// a format string.
+type callSite struct {
+ file File
+ call *ast.CallExpr // call containing the format string
+ arg ast.Expr // format argument (string literal or constant)
+ str string // unquoted format string
+ types []string // argument types
+}
+
+func collectPkgFormats(t *testing.T, pkg *build.Package) {
+ // collect all files
+ var filenames []string
+ filenames = append(filenames, pkg.GoFiles...)
+ filenames = append(filenames, pkg.CgoFiles...)
+ filenames = append(filenames, pkg.TestGoFiles...)
+
+ // TODO(gri) verify _test files outside package
+ for _, name := range pkg.XTestGoFiles {
+ // don't process this test itself
+ if name != "fmt_test.go" && testing.Verbose() {
+ fmt.Printf("WARNING: %s not processed\n", filepath.Join(pkg.Dir, name))
+ }
+ }
+
+ // make filenames relative to .
+ for i, name := range filenames {
+ filenames[i] = filepath.Join(pkg.Dir, name)
+ }
+
+ // parse all files
+ files := make([]*ast.File, len(filenames))
+ for i, filename := range filenames {
+ f, err := parser.ParseFile(fset, filename, nil, parser.ParseComments)
+ if err != nil {
+ t.Fatal(err)
+ }
+ files[i] = f
+ }
+
+ // typecheck package
+ conf := types.Config{Importer: importer.Default()}
+ etypes := make(map[ast.Expr]types.TypeAndValue)
+ if _, err := conf.Check(pkg.ImportPath, fset, files, &types.Info{Types: etypes}); err != nil {
+ t.Fatal(err)
+ }
+
+ // collect all potential format strings (for extra verification later)
+ for _, file := range files {
+ ast.Inspect(file, func(n ast.Node) bool {
+ if s, ok := stringLit(n); ok && isFormat(s) {
+ formatStrings[n.(*ast.BasicLit)] = true
+ }
+ return true
+ })
+ }
+
+ // collect all formats/arguments of calls with format strings
+ for index, file := range files {
+ ast.Inspect(file, func(n ast.Node) bool {
+ if call, ok := n.(*ast.CallExpr); ok {
+ // ignore blacklisted functions
+ if blacklistedFunctions[nodeString(call.Fun)] {
+ return true
+ }
+ // look for an arguments that might be a format string
+ for i, arg := range call.Args {
+ if s, ok := stringVal(etypes[arg]); ok && isFormat(s) {
+ // make sure we have enough arguments
+ n := numFormatArgs(s)
+ if i+1+n > len(call.Args) {
+ t.Errorf("%s: not enough format args (blacklist %s?)", posString(call), nodeString(call.Fun))
+ break // ignore this call
+ }
+ // assume last n arguments are to be formatted;
+ // determine their types
+ argTypes := make([]string, n)
+ for i, arg := range call.Args[len(call.Args)-n:] {
+ if tv, ok := etypes[arg]; ok {
+ argTypes[i] = typeString(tv.Type)
+ }
+ }
+ // collect call site
+ if callSites[call] != nil {
+ panic("internal error: file processed twice?")
+ }
+ callSites[call] = &callSite{
+ file: File{filenames[index], file},
+ call: call,
+ arg: arg,
+ str: s,
+ types: argTypes,
+ }
+ break // at most one format per argument list
+ }
+ }
+ }
+ return true
+ })
+ }
+}
+
+// printList prints list in sorted order.
+func printList(list []string) {
+ sort.Strings(list)
+ for _, s := range list {
+ fmt.Println("\t", s)
+ }
+}
+
+// posString returns a string representation of n's position
+// in the form filename:line:col: .
+func posString(n ast.Node) string {
+ if n == nil {
+ return ""
+ }
+ return fset.Position(n.Pos()).String()
+}
+
+// nodeString returns a string representation of n.
+func nodeString(n ast.Node) string {
+ var buf bytes.Buffer
+ if err := format.Node(&buf, fset, n); err != nil {
+ log.Fatal(err) // should always succeed
+ }
+ return buf.String()
+}
+
+// typeString returns a string representation of n.
+func typeString(typ types.Type) string {
+ return filepath.ToSlash(typ.String())
+}
+
+// stringLit returns the unquoted string value and true if
+// n represents a string literal; otherwise it returns ""
+// and false.
+func stringLit(n ast.Node) (string, bool) {
+ if lit, ok := n.(*ast.BasicLit); ok && lit.Kind == token.STRING {
+ s, err := strconv.Unquote(lit.Value)
+ if err != nil {
+ log.Fatal(err) // should not happen with correct ASTs
+ }
+ return s, true
+ }
+ return "", false
+}
+
+// stringVal returns the (unquoted) string value and true if
+// tv is a string constant; otherwise it returns "" and false.
+func stringVal(tv types.TypeAndValue) (string, bool) {
+ if tv.IsValue() && tv.Value != nil && tv.Value.Kind() == constant.String {
+ return constant.StringVal(tv.Value), true
+ }
+ return "", false
+}
+
+// formatIter iterates through the string s in increasing
+// index order and calls f for each format specifier '%..v'.
+// The arguments for f describe the specifier's index range.
+// If a format specifier contains a "*", f is called with
+// the index range for "*" alone, before being called for
+// the entire specifier. The result of f is the index of
+// the rune at which iteration continues.
+func formatIter(s string, f func(i, j int) int) {
+ i := 0 // index after current rune
+ var r rune // current rune
+
+ next := func() {
+ r1, w := utf8.DecodeRuneInString(s[i:])
+ if w == 0 {
+ r1 = -1 // signal end-of-string
+ }
+ r = r1
+ i += w
+ }
+
+ flags := func() {
+ for r == ' ' || r == '#' || r == '+' || r == '-' || r == '0' {
+ next()
+ }
+ }
+
+ index := func() {
+ if r == '[' {
+ log.Fatalf("cannot handle indexed arguments: %s", s)
+ }
+ }
+
+ digits := func() {
+ index()
+ if r == '*' {
+ i = f(i-1, i)
+ next()
+ return
+ }
+ for '0' <= r && r <= '9' {
+ next()
+ }
+ }
+
+ for next(); r >= 0; next() {
+ if r == '%' {
+ i0 := i
+ next()
+ flags()
+ digits()
+ if r == '.' {
+ next()
+ digits()
+ }
+ index()
+ // accept any letter (a-z, A-Z) as format verb;
+ // ignore anything else
+ if 'a' <= r && r <= 'z' || 'A' <= r && r <= 'Z' {
+ i = f(i0-1, i)
+ }
+ }
+ }
+}
+
+// isFormat reports whether s contains format specifiers.
+func isFormat(s string) (yes bool) {
+ formatIter(s, func(i, j int) int {
+ yes = true
+ return len(s) // stop iteration
+ })
+ return
+}
+
+// oneFormat reports whether s is exactly one format specifier.
+func oneFormat(s string) (yes bool) {
+ formatIter(s, func(i, j int) int {
+ yes = i == 0 && j == len(s)
+ return j
+ })
+ return
+}
+
+// numFormatArgs returns the number of format specifiers in s.
+func numFormatArgs(s string) int {
+ count := 0
+ formatIter(s, func(i, j int) int {
+ count++
+ return j
+ })
+ return count
+}
+
+// formatReplace replaces the i'th format specifier s in the incoming
+// string in with the result of f(i, s) and returns the new string.
+func formatReplace(in string, f func(i int, s string) string) string {
+ var buf []byte
+ i0 := 0
+ index := 0
+ formatIter(in, func(i, j int) int {
+ if sub := in[i:j]; sub != "*" { // ignore calls for "*" width/length specifiers
+ buf = append(buf, in[i0:i]...)
+ buf = append(buf, f(index, sub)...)
+ i0 = j
+ }
+ index++
+ return j
+ })
+ return string(append(buf, in[i0:]...))
+}
+
+// blacklistedPackages is the set of packages which can
+// be ignored.
+var blacklistedPackages = map[string]bool{}
+
+// blacklistedFunctions is the set of functions which may have
+// format-like arguments but which don't do any formatting and
+// thus may be ignored.
+var blacklistedFunctions = map[string]bool{}
+
+func init() {
+ // verify that knownFormats entries are correctly formatted
+ for key, val := range knownFormats {
+ // key must be "typename format", and format starts with a '%'
+ // (formats containing '*' alone are not collected in this table)
+ i := strings.Index(key, "%")
+ if i < 0 || !oneFormat(key[i:]) {
+ log.Fatalf("incorrect knownFormats key: %q", key)
+ }
+ // val must be "format" or ""
+ if val != "" && !oneFormat(val) {
+ log.Fatalf("incorrect knownFormats value: %q (key = %q)", val, key)
+ }
+ }
+}
+
+// knownFormats entries are of the form "typename format" -> "newformat".
+// An absent entry means that the format is not recognized as valid.
+// An empty new format means that the format should remain unchanged.
+// 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": "",
+ "*cmd/compile/internal/gc.Node %+S": "",
+ "*cmd/compile/internal/gc.Node %+v": "",
+ "*cmd/compile/internal/gc.Node %0j": "",
+ "*cmd/compile/internal/gc.Node %L": "",
+ "*cmd/compile/internal/gc.Node %S": "",
+ "*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": "",
+ "*cmd/compile/internal/ssa.SparseTreeNode %v": "",
+ "*cmd/compile/internal/ssa.Value %s": "",
+ "*cmd/compile/internal/ssa.Value %v": "",
+ "*cmd/compile/internal/ssa.sparseTreeMapEntry %v": "",
+ "*cmd/internal/obj.Addr %v": "",
+ "*cmd/internal/obj.Prog %p": "",
+ "*cmd/internal/obj.Prog %s": "",
+ "*cmd/internal/obj.Prog %v": "",
+ "*math/big.Int %#x": "",
+ "[16]byte %x": "",
+ "[]*cmd/compile/internal/gc.Node %v": "",
+ "[]*cmd/compile/internal/gc.Sig %#v": "",
+ "[]*cmd/compile/internal/ssa.Value %v": "",
+ "[]byte %s": "",
+ "[]byte %x": "",
+ "[]cmd/compile/internal/ssa.Edge %v": "",
+ "[]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": "",
+ "cmd/compile/internal/gc.Nodes %v": "",
+ "cmd/compile/internal/gc.Op %#v": "",
+ "cmd/compile/internal/gc.Op %v": "",
+ "cmd/compile/internal/gc.Val %#v": "",
+ "cmd/compile/internal/gc.Val %T": "",
+ "cmd/compile/internal/gc.Val %v": "",
+ "cmd/compile/internal/gc.initKind %d": "",
+ "cmd/compile/internal/ssa.BranchPrediction %d": "",
+ "cmd/compile/internal/ssa.Edge %v": "",
+ "cmd/compile/internal/ssa.GCNode %v": "",
+ "cmd/compile/internal/ssa.ID %d": "",
+ "cmd/compile/internal/ssa.LocalSlot %v": "",
+ "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": "",
+ "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": "",
+ "int %v": "",
+ "int %x": "",
+ "int16 %d": "",
+ "int16 %x": "",
+ "int32 %d": "",
+ "int32 %v": "",
+ "int32 %x": "",
+ "int64 %+d": "",
+ "int64 %-10d": "",
+ "int64 %X": "",
+ "int64 %d": "",
+ "int64 %v": "",
+ "int64 %x": "",
+ "int8 %d": "",
+ "int8 %x": "",
+ "interface{} %#v": "",
+ "interface{} %T": "",
+ "interface{} %q": "",
+ "interface{} %s": "",
+ "interface{} %v": "",
+ "map[*cmd/compile/internal/gc.Node]*cmd/compile/internal/ssa.Value %v": "",
+ "reflect.Type %s": "",
+ "rune %#U": "",
+ "rune %c": "",
+ "string %-16s": "",
+ "string %.*s": "",
+ "string %q": "",
+ "string %s": "",
+ "string %v": "",
+ "time.Duration %d": "",
+ "time.Duration %v": "",
+ "uint %04x": "",
+ "uint %d": "",
+ "uint16 %d": "",
+ "uint16 %v": "",
+ "uint16 %x": "",
+ "uint32 %08x": "",
+ "uint32 %d": "",
+ "uint32 %x": "",
+ "uint64 %016x": "",
+ "uint64 %08x": "",
+ "uint64 %d": "",
+ "uint64 %x": "",
+ "uint8 %d": "",
+ "uint8 %x": "",
+ "uintptr %d": "",
+}
diff --git a/src/cmd/compile/internal/amd64/cgen.go b/src/cmd/compile/internal/amd64/cgen.go
deleted file mode 100644
index 4b00003..0000000
--- a/src/cmd/compile/internal/amd64/cgen.go
+++ /dev/null
@@ -1,161 +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 amd64
-
-import (
- "cmd/compile/internal/gc"
- "cmd/internal/obj"
- "cmd/internal/obj/x86"
-)
-
-func blockcopy(n, ns *gc.Node, osrc, odst, w int64) {
- var noddi gc.Node
- gc.Nodreg(&noddi, gc.Types[gc.Tptr], x86.REG_DI)
- var nodsi gc.Node
- gc.Nodreg(&nodsi, gc.Types[gc.Tptr], x86.REG_SI)
-
- var nodl gc.Node
- var nodr gc.Node
- if n.Ullman >= ns.Ullman {
- gc.Agenr(n, &nodr, &nodsi)
- if ns.Op == gc.ONAME {
- gc.Gvardef(ns)
- }
- gc.Agenr(ns, &nodl, &noddi)
- } else {
- if ns.Op == gc.ONAME {
- gc.Gvardef(ns)
- }
- gc.Agenr(ns, &nodl, &noddi)
- gc.Agenr(n, &nodr, &nodsi)
- }
-
- if nodl.Reg != x86.REG_DI {
- gmove(&nodl, &noddi)
- }
- if nodr.Reg != x86.REG_SI {
- gmove(&nodr, &nodsi)
- }
- gc.Regfree(&nodl)
- gc.Regfree(&nodr)
-
- c := w % 8 // bytes
- q := w / 8 // quads
-
- var oldcx gc.Node
- var cx gc.Node
- savex(x86.REG_CX, &cx, &oldcx, nil, gc.Types[gc.TINT64])
-
- // if we are copying forward on the stack and
- // the src and dst overlap, then reverse direction
- if osrc < odst && odst < osrc+w {
- // reverse direction
- gins(x86.ASTD, nil, nil) // set direction flag
- if c > 0 {
- gconreg(addptr, w-1, x86.REG_SI)
- gconreg(addptr, w-1, x86.REG_DI)
-
- gconreg(movptr, c, x86.REG_CX)
- gins(x86.AREP, nil, nil) // repeat
- gins(x86.AMOVSB, nil, nil) // MOVB *(SI)-,*(DI)-
- }
-
- if q > 0 {
- if c > 0 {
- gconreg(addptr, -7, x86.REG_SI)
- gconreg(addptr, -7, x86.REG_DI)
- } else {
- gconreg(addptr, w-8, x86.REG_SI)
- gconreg(addptr, w-8, x86.REG_DI)
- }
-
- gconreg(movptr, q, x86.REG_CX)
- gins(x86.AREP, nil, nil) // repeat
- gins(x86.AMOVSQ, nil, nil) // MOVQ *(SI)-,*(DI)-
- }
-
- // we leave with the flag clear
- gins(x86.ACLD, nil, nil)
- } else {
- // normal direction
- if q > 128 || (gc.Nacl && q >= 4) || (obj.Getgoos() == "plan9" && q >= 4) {
- gconreg(movptr, q, x86.REG_CX)
- gins(x86.AREP, nil, nil) // repeat
- gins(x86.AMOVSQ, nil, nil) // MOVQ *(SI)+,*(DI)+
- } else if q >= 4 {
- var oldx0 gc.Node
- var x0 gc.Node
- savex(x86.REG_X0, &x0, &oldx0, nil, gc.Types[gc.TFLOAT64])
-
- p := gins(obj.ADUFFCOPY, nil, nil)
- p.To.Type = obj.TYPE_ADDR
- p.To.Sym = gc.Linksym(gc.Pkglookup("duffcopy", gc.Runtimepkg))
-
- // 64 blocks taking 14 bytes each
- // see ../../../../runtime/mkduff.go
- p.To.Offset = 14 * (64 - q/2)
- restx(&x0, &oldx0)
-
- if q%2 != 0 {
- gins(x86.AMOVSQ, nil, nil) // MOVQ *(SI)+,*(DI)+
- }
- } else if !gc.Nacl && c == 0 {
- // We don't need the MOVSQ side-effect of updating SI and DI,
- // and issuing a sequence of MOVQs directly is faster.
- nodsi.Op = gc.OINDREG
-
- noddi.Op = gc.OINDREG
- for q > 0 {
- gmove(&nodsi, &cx) // MOVQ x+(SI),CX
- gmove(&cx, &noddi) // MOVQ CX,x+(DI)
- nodsi.Xoffset += 8
- noddi.Xoffset += 8
- q--
- }
- } else {
- for q > 0 {
- gins(x86.AMOVSQ, nil, nil) // MOVQ *(SI)+,*(DI)+
- q--
- }
- }
-
- // copy the remaining c bytes
- if w < 4 || c <= 1 || (odst < osrc && osrc < odst+w) {
- for c > 0 {
- gins(x86.AMOVSB, nil, nil) // MOVB *(SI)+,*(DI)+
- c--
- }
- } else if w < 8 || c <= 4 {
- nodsi.Op = gc.OINDREG
- noddi.Op = gc.OINDREG
- cx.Type = gc.Types[gc.TINT32]
- nodsi.Type = gc.Types[gc.TINT32]
- noddi.Type = gc.Types[gc.TINT32]
- if c > 4 {
- nodsi.Xoffset = 0
- noddi.Xoffset = 0
- gmove(&nodsi, &cx)
- gmove(&cx, &noddi)
- }
-
- nodsi.Xoffset = c - 4
- noddi.Xoffset = c - 4
- gmove(&nodsi, &cx)
- gmove(&cx, &noddi)
- } else {
- nodsi.Op = gc.OINDREG
- noddi.Op = gc.OINDREG
- cx.Type = gc.Types[gc.TINT64]
- nodsi.Type = gc.Types[gc.TINT64]
- noddi.Type = gc.Types[gc.TINT64]
- nodsi.Xoffset = c - 8
- noddi.Xoffset = c - 8
- gmove(&nodsi, &cx)
- gmove(&cx, &noddi)
- }
- }
-
- restx(&cx, &oldcx)
-}
diff --git a/src/cmd/compile/internal/amd64/galign.go b/src/cmd/compile/internal/amd64/galign.go
index 4291534..bb3830b 100644
--- a/src/cmd/compile/internal/amd64/galign.go
+++ b/src/cmd/compile/internal/amd64/galign.go
@@ -10,86 +10,21 @@ import (
"cmd/internal/obj/x86"
)
-var (
- addptr = x86.AADDQ
- movptr = x86.AMOVQ
- leaptr = x86.ALEAQ
- cmpptr = x86.ACMPQ
-)
-
-func betypeinit() {
- if obj.Getgoarch() == "amd64p32" {
- addptr = x86.AADDL
- movptr = x86.AMOVL
- leaptr = x86.ALEAL
- cmpptr = x86.ACMPL
- }
-
- if gc.Ctxt.Flag_dynlink || obj.Getgoos() == "nacl" {
- resvd = append(resvd, x86.REG_R15)
- }
- if gc.Ctxt.Framepointer_enabled || obj.Getgoos() == "nacl" {
- resvd = append(resvd, x86.REG_BP)
- }
- gc.Thearch.ReservedRegs = resvd
-}
+var leaptr = x86.ALEAQ
-func Main() {
+func Init() {
gc.Thearch.LinkArch = &x86.Linkamd64
- if obj.Getgoarch() == "amd64p32" {
+ if obj.GOARCH == "amd64p32" {
gc.Thearch.LinkArch = &x86.Linkamd64p32
+ leaptr = x86.ALEAL
}
gc.Thearch.REGSP = x86.REGSP
- gc.Thearch.REGCTXT = x86.REGCTXT
- gc.Thearch.REGCALLX = x86.REG_BX
- gc.Thearch.REGCALLX2 = x86.REG_AX
- gc.Thearch.REGRETURN = x86.REG_AX
- gc.Thearch.REGMIN = x86.REG_AX
- gc.Thearch.REGMAX = x86.REG_R15
- gc.Thearch.FREGMIN = x86.REG_X0
- gc.Thearch.FREGMAX = x86.REG_X15
gc.Thearch.MAXWIDTH = 1 << 50
- gc.Thearch.AddIndex = addindex
- gc.Thearch.Betypeinit = betypeinit
- gc.Thearch.Cgen_bmul = cgen_bmul
- gc.Thearch.Cgen_hmul = cgen_hmul
- gc.Thearch.Cgen_shift = cgen_shift
- gc.Thearch.Clearfat = clearfat
gc.Thearch.Defframe = defframe
- gc.Thearch.Dodiv = dodiv
- gc.Thearch.Excise = excise
- gc.Thearch.Expandchecks = expandchecks
- gc.Thearch.Getg = getg
- gc.Thearch.Gins = gins
- gc.Thearch.Ginsboolval = ginsboolval
- gc.Thearch.Ginscmp = ginscmp
- gc.Thearch.Ginscon = ginscon
- gc.Thearch.Ginsnop = ginsnop
- gc.Thearch.Gmove = gmove
- gc.Thearch.Peep = peep
gc.Thearch.Proginfo = proginfo
- gc.Thearch.Regtyp = regtyp
- gc.Thearch.Sameaddr = sameaddr
- gc.Thearch.Smallindir = smallindir
- gc.Thearch.Stackaddr = stackaddr
- gc.Thearch.Blockcopy = blockcopy
- gc.Thearch.Sudoaddable = sudoaddable
- gc.Thearch.Sudoclean = sudoclean
- gc.Thearch.Excludedregs = excludedregs
- gc.Thearch.RtoB = RtoB
- gc.Thearch.FtoB = FtoB
- gc.Thearch.BtoR = BtoR
- gc.Thearch.BtoF = BtoF
- gc.Thearch.Optoas = optoas
- gc.Thearch.Doregbits = doregbits
- gc.Thearch.Regnames = regnames
- gc.Thearch.SSARegToReg = ssaRegToReg
gc.Thearch.SSAMarkMoves = ssaMarkMoves
gc.Thearch.SSAGenValue = ssaGenValue
gc.Thearch.SSAGenBlock = ssaGenBlock
-
- gc.Main()
- gc.Exit(0)
}
diff --git a/src/cmd/compile/internal/amd64/ggen.go b/src/cmd/compile/internal/amd64/ggen.go
index 909f7b0..c137b52 100644
--- a/src/cmd/compile/internal/amd64/ggen.go
+++ b/src/cmd/compile/internal/amd64/ggen.go
@@ -11,7 +11,7 @@ import (
)
// no floating point in note handlers on Plan 9
-var isPlan9 = obj.Getgoos() == "plan9"
+var isPlan9 = obj.GOOS == "plan9"
func defframe(ptxt *obj.Prog) {
// fill in argument size, stack size
@@ -40,7 +40,7 @@ func defframe(ptxt *obj.Prog) {
gc.Fatalf("needzero class %d", n.Class)
}
if n.Type.Width%int64(gc.Widthptr) != 0 || n.Xoffset%int64(gc.Widthptr) != 0 || n.Type.Width == 0 {
- gc.Fatalf("var %v has size %d offset %d", gc.Nconv(n, gc.FmtLong), int(n.Type.Width), int(n.Xoffset))
+ 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) {
@@ -112,696 +112,67 @@ func zerorange(p *obj.Prog, frame int64, lo int64, hi int64, ax *uint32, x0 *uin
gc.Fatalf("zerorange count not a multiple of widthptr %d", cnt)
}
if *ax == 0 {
- p = appendpp(p, x86.AMOVQ, obj.TYPE_CONST, 0, 0, obj.TYPE_REG, x86.REG_AX, 0)
+ p = gc.Appendpp(p, x86.AMOVQ, obj.TYPE_CONST, 0, 0, obj.TYPE_REG, x86.REG_AX, 0)
*ax = 1
}
- p = appendpp(p, x86.AMOVL, obj.TYPE_REG, x86.REG_AX, 0, obj.TYPE_MEM, x86.REG_SP, frame+lo)
+ 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)
cnt -= int64(gc.Widthptr)
}
if cnt == 8 {
if *ax == 0 {
- p = appendpp(p, x86.AMOVQ, obj.TYPE_CONST, 0, 0, obj.TYPE_REG, x86.REG_AX, 0)
+ p = gc.Appendpp(p, x86.AMOVQ, obj.TYPE_CONST, 0, 0, obj.TYPE_REG, x86.REG_AX, 0)
*ax = 1
}
- p = appendpp(p, x86.AMOVQ, obj.TYPE_REG, x86.REG_AX, 0, obj.TYPE_MEM, x86.REG_SP, frame+lo)
+ p = gc.Appendpp(p, x86.AMOVQ, obj.TYPE_REG, x86.REG_AX, 0, obj.TYPE_MEM, x86.REG_SP, frame+lo)
} else if !isPlan9 && cnt <= int64(8*gc.Widthreg) {
if *x0 == 0 {
- p = appendpp(p, x86.AXORPS, obj.TYPE_REG, x86.REG_X0, 0, obj.TYPE_REG, x86.REG_X0, 0)
+ p = gc.Appendpp(p, x86.AXORPS, obj.TYPE_REG, x86.REG_X0, 0, obj.TYPE_REG, x86.REG_X0, 0)
*x0 = 1
}
for i := int64(0); i < cnt/16; i++ {
- p = appendpp(p, x86.AMOVUPS, obj.TYPE_REG, x86.REG_X0, 0, obj.TYPE_MEM, x86.REG_SP, frame+lo+i*16)
+ p = gc.Appendpp(p, x86.AMOVUPS, obj.TYPE_REG, x86.REG_X0, 0, obj.TYPE_MEM, x86.REG_SP, frame+lo+i*16)
}
if cnt%16 != 0 {
- p = appendpp(p, x86.AMOVUPS, obj.TYPE_REG, x86.REG_X0, 0, obj.TYPE_MEM, x86.REG_SP, frame+lo+cnt-int64(16))
+ p = gc.Appendpp(p, x86.AMOVUPS, obj.TYPE_REG, x86.REG_X0, 0, obj.TYPE_MEM, x86.REG_SP, frame+lo+cnt-int64(16))
}
} else if !gc.Nacl && !isPlan9 && (cnt <= int64(128*gc.Widthreg)) {
if *x0 == 0 {
- p = appendpp(p, x86.AXORPS, obj.TYPE_REG, x86.REG_X0, 0, obj.TYPE_REG, x86.REG_X0, 0)
+ p = gc.Appendpp(p, x86.AXORPS, obj.TYPE_REG, x86.REG_X0, 0, obj.TYPE_REG, x86.REG_X0, 0)
*x0 = 1
}
- p = appendpp(p, leaptr, obj.TYPE_MEM, x86.REG_SP, frame+lo+dzDI(cnt), obj.TYPE_REG, x86.REG_DI, 0)
- p = appendpp(p, obj.ADUFFZERO, obj.TYPE_NONE, 0, 0, obj.TYPE_ADDR, 0, dzOff(cnt))
+ p = 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))
if cnt%16 != 0 {
- p = appendpp(p, x86.AMOVUPS, obj.TYPE_REG, x86.REG_X0, 0, obj.TYPE_MEM, x86.REG_DI, -int64(8))
+ p = gc.Appendpp(p, x86.AMOVUPS, obj.TYPE_REG, x86.REG_X0, 0, obj.TYPE_MEM, x86.REG_DI, -int64(8))
}
} else {
if *ax == 0 {
- p = appendpp(p, x86.AMOVQ, obj.TYPE_CONST, 0, 0, obj.TYPE_REG, x86.REG_AX, 0)
+ p = gc.Appendpp(p, x86.AMOVQ, obj.TYPE_CONST, 0, 0, obj.TYPE_REG, x86.REG_AX, 0)
*ax = 1
}
- p = appendpp(p, x86.AMOVQ, obj.TYPE_CONST, 0, cnt/int64(gc.Widthreg), obj.TYPE_REG, x86.REG_CX, 0)
- p = appendpp(p, leaptr, obj.TYPE_MEM, x86.REG_SP, frame+lo, obj.TYPE_REG, x86.REG_DI, 0)
- p = appendpp(p, x86.AREP, obj.TYPE_NONE, 0, 0, obj.TYPE_NONE, 0, 0)
- p = appendpp(p, x86.ASTOSQ, obj.TYPE_NONE, 0, 0, obj.TYPE_NONE, 0, 0)
+ 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)
}
return p
}
-func appendpp(p *obj.Prog, as obj.As, ftype obj.AddrType, freg int, foffset int64, ttype obj.AddrType, treg int, toffset int64) *obj.Prog {
- q := gc.Ctxt.NewProg()
- gc.Clearp(q)
- q.As = as
- q.Lineno = p.Lineno
- q.From.Type = ftype
- q.From.Reg = int16(freg)
- q.From.Offset = foffset
- q.To.Type = ttype
- q.To.Reg = int16(treg)
- q.To.Offset = toffset
- q.Link = p.Link
- p.Link = q
- return q
-}
-
-var panicdiv *gc.Node
-
-/*
- * generate division.
- * generates one of:
- * res = nl / nr
- * res = nl % nr
- * according to op.
- */
-func dodiv(op gc.Op, nl *gc.Node, nr *gc.Node, res *gc.Node) {
- // Have to be careful about handling
- // most negative int divided by -1 correctly.
- // The hardware will trap.
- // Also the byte divide instruction needs AH,
- // which we otherwise don't have to deal with.
- // Easiest way to avoid for int8, int16: use int32.
- // For int32 and int64, use explicit test.
- // Could use int64 hw for int32.
- t := nl.Type
-
- t0 := t
- check := false
- if t.IsSigned() {
- check = true
- if gc.Isconst(nl, gc.CTINT) && nl.Int64() != -(1<<uint64(t.Width*8-1)) {
- check = false
- } else if gc.Isconst(nr, gc.CTINT) && nr.Int64() != -1 {
- check = false
- }
- }
-
- if t.Width < 4 {
- if t.IsSigned() {
- t = gc.Types[gc.TINT32]
- } else {
- t = gc.Types[gc.TUINT32]
- }
- check = false
- }
-
- a := optoas(op, t)
-
- var n3 gc.Node
- gc.Regalloc(&n3, t0, nil)
- var ax gc.Node
- var oldax gc.Node
- if nl.Ullman >= nr.Ullman {
- savex(x86.REG_AX, &ax, &oldax, res, t0)
- gc.Cgen(nl, &ax)
- gc.Regalloc(&ax, t0, &ax) // mark ax live during cgen
- gc.Cgen(nr, &n3)
- gc.Regfree(&ax)
- } else {
- gc.Cgen(nr, &n3)
- savex(x86.REG_AX, &ax, &oldax, res, t0)
- gc.Cgen(nl, &ax)
- }
-
- if t != t0 {
- // Convert
- ax1 := ax
-
- n31 := n3
- ax.Type = t
- n3.Type = t
- gmove(&ax1, &ax)
- gmove(&n31, &n3)
- }
-
- var n4 gc.Node
- if gc.Nacl {
- // Native Client does not relay the divide-by-zero trap
- // to the executing program, so we must insert a check
- // for ourselves.
- gc.Nodconst(&n4, t, 0)
-
- gins(optoas(gc.OCMP, t), &n3, &n4)
- p1 := gc.Gbranch(optoas(gc.ONE, t), nil, +1)
- if panicdiv == nil {
- panicdiv = gc.Sysfunc("panicdivide")
- }
- gc.Ginscall(panicdiv, -1)
- gc.Patch(p1, gc.Pc)
- }
-
- var p2 *obj.Prog
- if check {
- gc.Nodconst(&n4, t, -1)
- gins(optoas(gc.OCMP, t), &n3, &n4)
- p1 := gc.Gbranch(optoas(gc.ONE, t), nil, +1)
- if op == gc.ODIV {
- // a / (-1) is -a.
- gins(optoas(gc.OMINUS, t), nil, &ax)
-
- gmove(&ax, res)
- } else {
- // a % (-1) is 0.
- gc.Nodconst(&n4, t, 0)
-
- gmove(&n4, res)
- }
-
- p2 = gc.Gbranch(obj.AJMP, nil, 0)
- gc.Patch(p1, gc.Pc)
- }
-
- var olddx gc.Node
- var dx gc.Node
- savex(x86.REG_DX, &dx, &olddx, res, t)
- if !t.IsSigned() {
- gc.Nodconst(&n4, t, 0)
- gmove(&n4, &dx)
- } else {
- gins(optoas(gc.OEXTEND, t), nil, nil)
- }
- gins(a, &n3, nil)
- gc.Regfree(&n3)
- if op == gc.ODIV {
- gmove(&ax, res)
- } else {
- gmove(&dx, res)
- }
- restx(&dx, &olddx)
- if check {
- gc.Patch(p2, gc.Pc)
- }
- restx(&ax, &oldax)
-}
-
-/*
- * register dr is one of the special ones (AX, CX, DI, SI, etc.).
- * we need to use it. if it is already allocated as a temporary
- * (r > 1; can only happen if a routine like sgen passed a
- * special as cgen's res and then cgen used regalloc to reuse
- * it as its own temporary), then move it for now to another
- * register. caller must call restx to move it back.
- * the move is not necessary if dr == res, because res is
- * known to be dead.
- */
-func savex(dr int, x *gc.Node, oldx *gc.Node, res *gc.Node, t *gc.Type) {
- r := uint8(gc.GetReg(dr))
-
- // save current ax and dx if they are live
- // and not the destination
- *oldx = gc.Node{}
-
- gc.Nodreg(x, t, dr)
- if r > 1 && !gc.Samereg(x, res) {
- gc.Regalloc(oldx, gc.Types[gc.TINT64], nil)
- x.Type = gc.Types[gc.TINT64]
- gmove(x, oldx)
- x.Type = t
- // TODO(marvin): Fix Node.EType type union.
- oldx.Etype = gc.EType(r) // squirrel away old r value
- gc.SetReg(dr, 1)
- }
-}
-
-func restx(x *gc.Node, oldx *gc.Node) {
- if oldx.Op != 0 {
- x.Type = gc.Types[gc.TINT64]
- gc.SetReg(int(x.Reg), int(oldx.Etype))
- gmove(oldx, x)
- gc.Regfree(oldx)
- }
-}
-
-/*
- * generate high multiply:
- * res = (nl*nr) >> width
- */
-func cgen_hmul(nl *gc.Node, nr *gc.Node, res *gc.Node) {
- t := nl.Type
- a := optoas(gc.OHMUL, t)
- if nl.Ullman < nr.Ullman {
- nl, nr = nr, nl
- }
-
- var n1 gc.Node
- gc.Cgenr(nl, &n1, res)
- var n2 gc.Node
- gc.Cgenr(nr, &n2, nil)
- var ax, oldax, dx, olddx gc.Node
- savex(x86.REG_AX, &ax, &oldax, res, gc.Types[gc.TUINT64])
- savex(x86.REG_DX, &dx, &olddx, res, gc.Types[gc.TUINT64])
- gmove(&n1, &ax)
- gins(a, &n2, nil)
- gc.Regfree(&n2)
- gc.Regfree(&n1)
-
- if t.Width == 1 {
- // byte multiply behaves differently.
- var byteAH, byteDX gc.Node
- gc.Nodreg(&byteAH, t, x86.REG_AH)
- gc.Nodreg(&byteDX, t, x86.REG_DX)
- gmove(&byteAH, &byteDX)
- }
- gmove(&dx, res)
-
- restx(&ax, &oldax)
- restx(&dx, &olddx)
-}
-
-/*
- * generate shift according to op, one of:
- * res = nl << nr
- * res = nl >> nr
- */
-func cgen_shift(op gc.Op, bounded bool, nl *gc.Node, nr *gc.Node, res *gc.Node) {
- a := optoas(op, nl.Type)
-
- if nr.Op == gc.OLITERAL {
- var n1 gc.Node
- gc.Regalloc(&n1, nl.Type, res)
- gc.Cgen(nl, &n1)
- sc := uint64(nr.Int64())
- if sc >= uint64(nl.Type.Width*8) {
- // large shift gets 2 shifts by width-1
- var n3 gc.Node
- gc.Nodconst(&n3, gc.Types[gc.TUINT32], nl.Type.Width*8-1)
-
- gins(a, &n3, &n1)
- gins(a, &n3, &n1)
- } else {
- gins(a, nr, &n1)
- }
- gmove(&n1, res)
- gc.Regfree(&n1)
- return
- }
-
- if nl.Ullman >= gc.UINF {
- var n4 gc.Node
- gc.Tempname(&n4, nl.Type)
- gc.Cgen(nl, &n4)
- nl = &n4
- }
-
- if nr.Ullman >= gc.UINF {
- var n5 gc.Node
- gc.Tempname(&n5, nr.Type)
- gc.Cgen(nr, &n5)
- nr = &n5
- }
-
- rcx := gc.GetReg(x86.REG_CX)
- var n1 gc.Node
- gc.Nodreg(&n1, gc.Types[gc.TUINT32], x86.REG_CX)
-
- // Allow either uint32 or uint64 as shift type,
- // to avoid unnecessary conversion from uint32 to uint64
- // just to do the comparison.
- tcount := gc.Types[gc.Simtype[nr.Type.Etype]]
-
- if tcount.Etype < gc.TUINT32 {
- tcount = gc.Types[gc.TUINT32]
- }
-
- gc.Regalloc(&n1, nr.Type, &n1) // to hold the shift type in CX
- var n3 gc.Node
- gc.Regalloc(&n3, tcount, &n1) // to clear high bits of CX
-
- var cx gc.Node
- gc.Nodreg(&cx, gc.Types[gc.TUINT64], x86.REG_CX)
-
- var oldcx gc.Node
- if rcx > 0 && !gc.Samereg(&cx, res) {
- gc.Regalloc(&oldcx, gc.Types[gc.TUINT64], nil)
- gmove(&cx, &oldcx)
- }
-
- cx.Type = tcount
-
- var n2 gc.Node
- if gc.Samereg(&cx, res) {
- gc.Regalloc(&n2, nl.Type, nil)
- } else {
- gc.Regalloc(&n2, nl.Type, res)
- }
- if nl.Ullman >= nr.Ullman {
- gc.Cgen(nl, &n2)
- gc.Cgen(nr, &n1)
- gmove(&n1, &n3)
- } else {
- gc.Cgen(nr, &n1)
- gmove(&n1, &n3)
- gc.Cgen(nl, &n2)
- }
-
- gc.Regfree(&n3)
-
- // test and fix up large shifts
- if !bounded {
- gc.Nodconst(&n3, tcount, nl.Type.Width*8)
- gins(optoas(gc.OCMP, tcount), &n1, &n3)
- p1 := gc.Gbranch(optoas(gc.OLT, tcount), nil, +1)
- if op == gc.ORSH && nl.Type.IsSigned() {
- gc.Nodconst(&n3, gc.Types[gc.TUINT32], nl.Type.Width*8-1)
- gins(a, &n3, &n2)
- } else {
- gc.Nodconst(&n3, nl.Type, 0)
- gmove(&n3, &n2)
- }
-
- gc.Patch(p1, gc.Pc)
- }
-
- gins(a, &n1, &n2)
-
- if oldcx.Op != 0 {
- cx.Type = gc.Types[gc.TUINT64]
- gmove(&oldcx, &cx)
- gc.Regfree(&oldcx)
- }
-
- gmove(&n2, res)
-
- gc.Regfree(&n1)
- gc.Regfree(&n2)
-}
-
-/*
- * generate byte multiply:
- * res = nl * nr
- * there is no 2-operand byte multiply instruction so
- * we do a full-width multiplication and truncate afterwards.
- */
-func cgen_bmul(op gc.Op, nl *gc.Node, nr *gc.Node, res *gc.Node) bool {
- if optoas(op, nl.Type) != x86.AIMULB {
- return false
- }
-
- // largest ullman on left.
- if nl.Ullman < nr.Ullman {
- nl, nr = nr, nl
- }
-
- // generate operands in "8-bit" registers.
- var n1b gc.Node
- gc.Regalloc(&n1b, nl.Type, res)
-
- gc.Cgen(nl, &n1b)
- var n2b gc.Node
- gc.Regalloc(&n2b, nr.Type, nil)
- gc.Cgen(nr, &n2b)
-
- // perform full-width multiplication.
- t := gc.Types[gc.TUINT64]
-
- if nl.Type.IsSigned() {
- t = gc.Types[gc.TINT64]
- }
- var n1 gc.Node
- gc.Nodreg(&n1, t, int(n1b.Reg))
- var n2 gc.Node
- gc.Nodreg(&n2, t, int(n2b.Reg))
- a := optoas(op, t)
- gins(a, &n2, &n1)
-
- // truncate.
- gmove(&n1, res)
-
- gc.Regfree(&n1b)
- gc.Regfree(&n2b)
- return true
-}
-
-func clearfat(nl *gc.Node) {
- /* clear a fat object */
- if gc.Debug['g'] != 0 {
- gc.Dump("\nclearfat", nl)
- }
-
- // Avoid taking the address for simple enough types.
- if gc.Componentgen(nil, nl) {
- return
- }
-
- w := nl.Type.Width
-
- if w > 1024 || (w >= 64 && (gc.Nacl || isPlan9)) {
- var oldn1 gc.Node
- var n1 gc.Node
- savex(x86.REG_DI, &n1, &oldn1, nil, gc.Types[gc.Tptr])
- gc.Agen(nl, &n1)
-
- var ax gc.Node
- var oldax gc.Node
- savex(x86.REG_AX, &ax, &oldax, nil, gc.Types[gc.Tptr])
- gconreg(x86.AMOVL, 0, x86.REG_AX)
- gconreg(movptr, w/8, x86.REG_CX)
-
- gins(x86.AREP, nil, nil) // repeat
- gins(x86.ASTOSQ, nil, nil) // STOQ AL,*(DI)+
-
- if w%8 != 0 {
- n1.Op = gc.OINDREG
- clearfat_tail(&n1, w%8)
- }
-
- restx(&n1, &oldn1)
- restx(&ax, &oldax)
- return
- }
-
- if w >= 64 {
- var oldn1 gc.Node
- var n1 gc.Node
- savex(x86.REG_DI, &n1, &oldn1, nil, gc.Types[gc.Tptr])
- gc.Agen(nl, &n1)
-
- var vec_zero gc.Node
- var old_x0 gc.Node
- savex(x86.REG_X0, &vec_zero, &old_x0, nil, gc.Types[gc.TFLOAT64])
- gins(x86.AXORPS, &vec_zero, &vec_zero)
-
- if di := dzDI(w); di != 0 {
- gconreg(addptr, di, x86.REG_DI)
- }
- p := gins(obj.ADUFFZERO, nil, nil)
- p.To.Type = obj.TYPE_ADDR
- p.To.Sym = gc.Linksym(gc.Pkglookup("duffzero", gc.Runtimepkg))
- p.To.Offset = dzOff(w)
-
- if w%16 != 0 {
- n1.Op = gc.OINDREG
- n1.Xoffset -= 16 - w%16
- gins(x86.AMOVUPS, &vec_zero, &n1)
- }
-
- restx(&vec_zero, &old_x0)
- restx(&n1, &oldn1)
- return
- }
-
- // NOTE: Must use agen, not igen, so that optimizer sees address
- // being taken. We are not writing on field boundaries.
- var n1 gc.Node
- gc.Agenr(nl, &n1, nil)
- n1.Op = gc.OINDREG
-
- clearfat_tail(&n1, w)
-
- gc.Regfree(&n1)
-}
-
-func clearfat_tail(n1 *gc.Node, b int64) {
- if b >= 16 && isPlan9 {
- var z gc.Node
- gc.Nodconst(&z, gc.Types[gc.TUINT64], 0)
- q := b / 8
- for ; q > 0; q-- {
- n1.Type = z.Type
- gins(x86.AMOVQ, &z, n1)
- n1.Xoffset += 8
- b -= 8
- }
- if b != 0 {
- n1.Xoffset -= 8 - b
- gins(x86.AMOVQ, &z, n1)
- }
- return
- }
- if b >= 16 {
- var vec_zero gc.Node
- gc.Regalloc(&vec_zero, gc.Types[gc.TFLOAT64], nil)
- gins(x86.AXORPS, &vec_zero, &vec_zero)
-
- for b >= 16 {
- gins(x86.AMOVUPS, &vec_zero, n1)
- n1.Xoffset += 16
- b -= 16
- }
-
- // MOVUPS X0, off(base) is a few bytes shorter than MOV 0, off(base)
- if b != 0 {
- n1.Xoffset -= 16 - b
- gins(x86.AMOVUPS, &vec_zero, n1)
- }
-
- gc.Regfree(&vec_zero)
- return
- }
-
- // Write sequence of MOV 0, off(base) instead of using STOSQ.
- // The hope is that although the code will be slightly longer,
- // the MOVs will have no dependencies and pipeline better
- // than the unrolled STOSQ loop.
- var z gc.Node
- gc.Nodconst(&z, gc.Types[gc.TUINT64], 0)
- if b >= 8 {
- n1.Type = z.Type
- gins(x86.AMOVQ, &z, n1)
- n1.Xoffset += 8
- b -= 8
-
- if b != 0 {
- n1.Xoffset -= 8 - b
- gins(x86.AMOVQ, &z, n1)
- }
- return
- }
-
- if b >= 4 {
- gc.Nodconst(&z, gc.Types[gc.TUINT32], 0)
- n1.Type = z.Type
- gins(x86.AMOVL, &z, n1)
- n1.Xoffset += 4
- b -= 4
-
- if b != 0 {
- n1.Xoffset -= 4 - b
- gins(x86.AMOVL, &z, n1)
- }
- return
- }
-
- if b >= 2 {
- gc.Nodconst(&z, gc.Types[gc.TUINT16], 0)
- n1.Type = z.Type
- gins(x86.AMOVW, &z, n1)
- n1.Xoffset += 2
- b -= 2
- }
-
- gc.Nodconst(&z, gc.Types[gc.TUINT8], 0)
- for b > 0 {
- n1.Type = z.Type
- gins(x86.AMOVB, &z, n1)
- n1.Xoffset++
- b--
- }
-
-}
-
-// Called after regopt and peep have run.
-// Expand CHECKNIL pseudo-op into actual nil pointer check.
-func expandchecks(firstp *obj.Prog) {
- var p1 *obj.Prog
- var p2 *obj.Prog
-
- for p := firstp; p != nil; p = p.Link {
- if p.As != obj.ACHECKNIL {
- continue
- }
- if gc.Debug_checknil != 0 && p.Lineno > 1 { // p->lineno==1 in generated wrappers
- gc.Warnl(p.Lineno, "generated nil check")
- }
-
- // check is
- // CMP arg, $0
- // JNE 2(PC) (likely)
- // MOV AX, 0
- p1 = gc.Ctxt.NewProg()
-
- p2 = gc.Ctxt.NewProg()
- gc.Clearp(p1)
- gc.Clearp(p2)
- p1.Link = p2
- p2.Link = p.Link
- p.Link = p1
- p1.Lineno = p.Lineno
- p2.Lineno = p.Lineno
- p1.Pc = 9999
- p2.Pc = 9999
- p.As = cmpptr
- p.To.Type = obj.TYPE_CONST
- p.To.Offset = 0
- p1.As = x86.AJNE
- p1.From.Type = obj.TYPE_CONST
- p1.From.Offset = 1 // likely
- p1.To.Type = obj.TYPE_BRANCH
- p1.To.Val = p2.Link
-
- // crash by write to memory address 0.
- // if possible, since we know arg is 0, use 0(arg),
- // which will be shorter to encode than plain 0.
- p2.As = x86.AMOVL
-
- p2.From.Type = obj.TYPE_REG
- p2.From.Reg = x86.REG_AX
- if regtyp(&p.From) {
- p2.To.Type = obj.TYPE_MEM
- p2.To.Reg = p.From.Reg
- } else {
- p2.To.Type = obj.TYPE_MEM
- p2.To.Reg = x86.REG_NONE
- }
-
- p2.To.Offset = 0
- }
-}
-
-// addr += index*width if possible.
-func addindex(index *gc.Node, width int64, addr *gc.Node) bool {
- switch width {
- case 1, 2, 4, 8:
- p1 := gins(x86.ALEAQ, index, addr)
- p1.From.Type = obj.TYPE_MEM
- p1.From.Scale = int16(width)
- p1.From.Index = p1.From.Reg
- p1.From.Reg = p1.To.Reg
- return true
- }
- return false
-}
-
-// res = runtime.getg()
-func getg(res *gc.Node) {
- var n1 gc.Node
- gc.Regalloc(&n1, res.Type, res)
- mov := optoas(gc.OAS, gc.Types[gc.Tptr])
- p := gins(mov, nil, &n1)
+func ginsnop() {
+ // This is actually not the x86 NOP anymore,
+ // but at the point where it gets used, AX is dead
+ // so it's okay if we lose the high bits.
+ p := gc.Prog(x86.AXCHGL)
p.From.Type = obj.TYPE_REG
- p.From.Reg = x86.REG_TLS
- p = gins(mov, nil, &n1)
- p.From = p.To
- p.From.Type = obj.TYPE_MEM
- p.From.Index = x86.REG_TLS
- p.From.Scale = 1
- gmove(&n1, res)
- gc.Regfree(&n1)
+ p.From.Reg = x86.REG_AX
+ p.To.Type = obj.TYPE_REG
+ p.To.Reg = x86.REG_AX
}
diff --git a/src/cmd/compile/internal/amd64/gsubr.go b/src/cmd/compile/internal/amd64/gsubr.go
deleted file mode 100644
index 5d9070c..0000000
--- a/src/cmd/compile/internal/amd64/gsubr.go
+++ /dev/null
@@ -1,1423 +0,0 @@
-// Derived from Inferno utils/6c/txt.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6c/txt.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth at terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth at terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// Portions Copyright © 2009 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-package amd64
-
-import (
- "cmd/compile/internal/big"
- "cmd/compile/internal/gc"
- "cmd/internal/obj"
- "cmd/internal/obj/x86"
- "fmt"
-)
-
-var resvd = []int{
- x86.REG_DI, // for movstring
- x86.REG_SI, // for movstring
-
- x86.REG_AX, // for divide
- x86.REG_CX, // for shift
- x86.REG_DX, // for divide
- x86.REG_SP, // for stack
-}
-
-/*
- * generate
- * as $c, reg
- */
-func gconreg(as obj.As, c int64, reg int) {
- var nr gc.Node
-
- switch as {
- case x86.AADDL,
- x86.AMOVL,
- x86.ALEAL:
- gc.Nodreg(&nr, gc.Types[gc.TINT32], reg)
-
- default:
- gc.Nodreg(&nr, gc.Types[gc.TINT64], reg)
- }
-
- ginscon(as, c, &nr)
-}
-
-/*
- * generate
- * as $c, n
- */
-func ginscon(as obj.As, c int64, n2 *gc.Node) {
- var n1 gc.Node
-
- switch as {
- case x86.AADDL,
- x86.AMOVL,
- x86.ALEAL:
- gc.Nodconst(&n1, gc.Types[gc.TINT32], c)
-
- default:
- gc.Nodconst(&n1, gc.Types[gc.TINT64], c)
- }
-
- if as != x86.AMOVQ && (c < -(1<<31) || c >= 1<<31) {
- // cannot have 64-bit immediate in ADD, etc.
- // instead, MOV into register first.
- var ntmp gc.Node
- gc.Regalloc(&ntmp, gc.Types[gc.TINT64], nil)
-
- gins(x86.AMOVQ, &n1, &ntmp)
- gins(as, &ntmp, n2)
- gc.Regfree(&ntmp)
- return
- }
-
- gins(as, &n1, n2)
-}
-
-func ginscmp(op gc.Op, t *gc.Type, n1, n2 *gc.Node, likely int) *obj.Prog {
- if t.IsInteger() && n1.Op == gc.OLITERAL && gc.Smallintconst(n1) && n2.Op != gc.OLITERAL {
- // Reverse comparison to place constant last.
- op = gc.Brrev(op)
- n1, n2 = n2, n1
- }
- // General case.
- var r1, r2, g1, g2 gc.Node
-
- // A special case to make write barriers more efficient.
- // Comparing the first field of a named struct can be done directly.
- base := n1
- if n1.Op == gc.ODOT && n1.Left.Type.IsStruct() && n1.Left.Type.Field(0).Sym == n1.Sym {
- base = n1.Left
- }
-
- if base.Op == gc.ONAME && base.Class != gc.PAUTOHEAP || n1.Op == gc.OINDREG {
- r1 = *n1
- } else {
- gc.Regalloc(&r1, t, n1)
- gc.Regalloc(&g1, n1.Type, &r1)
- gc.Cgen(n1, &g1)
- gmove(&g1, &r1)
- }
- if n2.Op == gc.OLITERAL && t.IsInteger() && gc.Smallintconst(n2) {
- r2 = *n2
- } else {
- gc.Regalloc(&r2, t, n2)
- gc.Regalloc(&g2, n1.Type, &r2)
- gc.Cgen(n2, &g2)
- gmove(&g2, &r2)
- }
- gins(optoas(gc.OCMP, t), &r1, &r2)
- if r1.Op == gc.OREGISTER {
- gc.Regfree(&g1)
- gc.Regfree(&r1)
- }
- if r2.Op == gc.OREGISTER {
- gc.Regfree(&g2)
- gc.Regfree(&r2)
- }
- return gc.Gbranch(optoas(op, t), nil, likely)
-}
-
-func ginsboolval(a obj.As, n *gc.Node) {
- gins(jmptoset(a), nil, n)
-}
-
-// set up nodes representing 2^63
-var (
- bigi gc.Node
- bigf gc.Node
- bignodes_did bool
-)
-
-func bignodes() {
- if bignodes_did {
- return
- }
- bignodes_did = true
-
- var i big.Int
- i.SetInt64(1)
- i.Lsh(&i, 63)
-
- gc.Nodconst(&bigi, gc.Types[gc.TUINT64], 0)
- bigi.SetBigInt(&i)
-
- bigi.Convconst(&bigf, gc.Types[gc.TFLOAT64])
-}
-
-/*
- * generate move:
- * t = f
- * hard part is conversions.
- */
-func gmove(f *gc.Node, t *gc.Node) {
- if gc.Debug['M'] != 0 {
- fmt.Printf("gmove %v -> %v\n", gc.Nconv(f, gc.FmtLong), gc.Nconv(t, gc.FmtLong))
- }
-
- ft := gc.Simsimtype(f.Type)
- tt := gc.Simsimtype(t.Type)
- cvt := t.Type
-
- if gc.Iscomplex[ft] || gc.Iscomplex[tt] {
- gc.Complexmove(f, t)
- return
- }
-
- // cannot have two memory operands
- var a obj.As
- if gc.Ismem(f) && gc.Ismem(t) {
- goto hard
- }
-
- // convert constant to desired type
- if f.Op == gc.OLITERAL {
- var con gc.Node
- f.Convconst(&con, t.Type)
- f = &con
- ft = tt // so big switch will choose a simple mov
-
- // some constants can't move directly to memory.
- if gc.Ismem(t) {
- // float constants come from memory.
- if gc.Isfloat[tt] {
- goto hard
- }
-
- // 64-bit immediates are really 32-bit sign-extended
- // unless moving into a register.
- if gc.Isint[tt] {
- if i := con.Int64(); int64(int32(i)) != i {
- goto hard
- }
- }
- }
- }
-
- // value -> value copy, only one memory operand.
- // figure out the instruction to use.
- // break out of switch for one-instruction gins.
- // goto rdst for "destination must be register".
- // goto hard for "convert to cvt type first".
- // otherwise handle and return.
-
- switch uint32(ft)<<16 | uint32(tt) {
- default:
- gc.Dump("f", f)
- gc.Dump("t", t)
- gc.Fatalf("gmove %v -> %v", gc.Tconv(f.Type, gc.FmtLong), gc.Tconv(t.Type, gc.FmtLong))
-
- /*
- * integer copy and truncate
- */
- case gc.TINT8<<16 | gc.TINT8, // same size
- gc.TINT8<<16 | gc.TUINT8,
- gc.TUINT8<<16 | gc.TINT8,
- gc.TUINT8<<16 | gc.TUINT8,
- gc.TINT16<<16 | gc.TINT8,
- // truncate
- gc.TUINT16<<16 | gc.TINT8,
- gc.TINT32<<16 | gc.TINT8,
- gc.TUINT32<<16 | gc.TINT8,
- gc.TINT64<<16 | gc.TINT8,
- gc.TUINT64<<16 | gc.TINT8,
- gc.TINT16<<16 | gc.TUINT8,
- gc.TUINT16<<16 | gc.TUINT8,
- gc.TINT32<<16 | gc.TUINT8,
- gc.TUINT32<<16 | gc.TUINT8,
- gc.TINT64<<16 | gc.TUINT8,
- gc.TUINT64<<16 | gc.TUINT8:
- a = x86.AMOVB
-
- case gc.TINT16<<16 | gc.TINT16, // same size
- gc.TINT16<<16 | gc.TUINT16,
- gc.TUINT16<<16 | gc.TINT16,
- gc.TUINT16<<16 | gc.TUINT16,
- gc.TINT32<<16 | gc.TINT16,
- // truncate
- gc.TUINT32<<16 | gc.TINT16,
- gc.TINT64<<16 | gc.TINT16,
- gc.TUINT64<<16 | gc.TINT16,
- gc.TINT32<<16 | gc.TUINT16,
- gc.TUINT32<<16 | gc.TUINT16,
- gc.TINT64<<16 | gc.TUINT16,
- gc.TUINT64<<16 | gc.TUINT16:
- a = x86.AMOVW
-
- case gc.TINT32<<16 | gc.TINT32, // same size
- gc.TINT32<<16 | gc.TUINT32,
- gc.TUINT32<<16 | gc.TINT32,
- gc.TUINT32<<16 | gc.TUINT32:
- a = x86.AMOVL
-
- case gc.TINT64<<16 | gc.TINT32, // truncate
- gc.TUINT64<<16 | gc.TINT32,
- gc.TINT64<<16 | gc.TUINT32,
- gc.TUINT64<<16 | gc.TUINT32:
- a = x86.AMOVQL
-
- case gc.TINT64<<16 | gc.TINT64, // same size
- gc.TINT64<<16 | gc.TUINT64,
- gc.TUINT64<<16 | gc.TINT64,
- gc.TUINT64<<16 | gc.TUINT64:
- a = x86.AMOVQ
-
- /*
- * integer up-conversions
- */
- case gc.TINT8<<16 | gc.TINT16, // sign extend int8
- gc.TINT8<<16 | gc.TUINT16:
- a = x86.AMOVBWSX
-
- goto rdst
-
- case gc.TINT8<<16 | gc.TINT32,
- gc.TINT8<<16 | gc.TUINT32:
- a = x86.AMOVBLSX
- goto rdst
-
- case gc.TINT8<<16 | gc.TINT64,
- gc.TINT8<<16 | gc.TUINT64:
- a = x86.AMOVBQSX
- goto rdst
-
- case gc.TUINT8<<16 | gc.TINT16, // zero extend uint8
- gc.TUINT8<<16 | gc.TUINT16:
- a = x86.AMOVBWZX
-
- goto rdst
-
- case gc.TUINT8<<16 | gc.TINT32,
- gc.TUINT8<<16 | gc.TUINT32:
- a = x86.AMOVBLZX
- goto rdst
-
- case gc.TUINT8<<16 | gc.TINT64,
- gc.TUINT8<<16 | gc.TUINT64:
- a = x86.AMOVBQZX
- goto rdst
-
- case gc.TINT16<<16 | gc.TINT32, // sign extend int16
- gc.TINT16<<16 | gc.TUINT32:
- a = x86.AMOVWLSX
-
- goto rdst
-
- case gc.TINT16<<16 | gc.TINT64,
- gc.TINT16<<16 | gc.TUINT64:
- a = x86.AMOVWQSX
- goto rdst
-
- case gc.TUINT16<<16 | gc.TINT32, // zero extend uint16
- gc.TUINT16<<16 | gc.TUINT32:
- a = x86.AMOVWLZX
-
- goto rdst
-
- case gc.TUINT16<<16 | gc.TINT64,
- gc.TUINT16<<16 | gc.TUINT64:
- a = x86.AMOVWQZX
- goto rdst
-
- case gc.TINT32<<16 | gc.TINT64, // sign extend int32
- gc.TINT32<<16 | gc.TUINT64:
- a = x86.AMOVLQSX
-
- goto rdst
-
- // AMOVL into a register zeros the top of the register,
- // so this is not always necessary, but if we rely on AMOVL
- // the optimizer is almost certain to screw with us.
- case gc.TUINT32<<16 | gc.TINT64, // zero extend uint32
- gc.TUINT32<<16 | gc.TUINT64:
- a = x86.AMOVLQZX
-
- goto rdst
-
- /*
- * float to integer
- */
- case gc.TFLOAT32<<16 | gc.TINT32:
- a = x86.ACVTTSS2SL
-
- goto rdst
-
- case gc.TFLOAT64<<16 | gc.TINT32:
- a = x86.ACVTTSD2SL
- goto rdst
-
- case gc.TFLOAT32<<16 | gc.TINT64:
- a = x86.ACVTTSS2SQ
- goto rdst
-
- case gc.TFLOAT64<<16 | gc.TINT64:
- a = x86.ACVTTSD2SQ
- goto rdst
-
- // convert via int32.
- case gc.TFLOAT32<<16 | gc.TINT16,
- gc.TFLOAT32<<16 | gc.TINT8,
- gc.TFLOAT32<<16 | gc.TUINT16,
- gc.TFLOAT32<<16 | gc.TUINT8,
- gc.TFLOAT64<<16 | gc.TINT16,
- gc.TFLOAT64<<16 | gc.TINT8,
- gc.TFLOAT64<<16 | gc.TUINT16,
- gc.TFLOAT64<<16 | gc.TUINT8:
- cvt = gc.Types[gc.TINT32]
-
- goto hard
-
- // convert via int64.
- case gc.TFLOAT32<<16 | gc.TUINT32,
- gc.TFLOAT64<<16 | gc.TUINT32:
- cvt = gc.Types[gc.TINT64]
-
- goto hard
-
- // algorithm is:
- // if small enough, use native float64 -> int64 conversion.
- // otherwise, subtract 2^63, convert, and add it back.
- case gc.TFLOAT32<<16 | gc.TUINT64,
- gc.TFLOAT64<<16 | gc.TUINT64:
- a := x86.ACVTTSS2SQ
-
- if ft == gc.TFLOAT64 {
- a = x86.ACVTTSD2SQ
- }
- bignodes()
- var r1 gc.Node
- gc.Regalloc(&r1, gc.Types[ft], nil)
- var r2 gc.Node
- gc.Regalloc(&r2, gc.Types[tt], t)
- var r3 gc.Node
- gc.Regalloc(&r3, gc.Types[ft], nil)
- var r4 gc.Node
- gc.Regalloc(&r4, gc.Types[tt], nil)
- gins(optoas(gc.OAS, f.Type), f, &r1)
- gins(optoas(gc.OCMP, f.Type), &bigf, &r1)
- p1 := gc.Gbranch(optoas(gc.OLE, f.Type), nil, +1)
- gins(a, &r1, &r2)
- p2 := gc.Gbranch(obj.AJMP, nil, 0)
- gc.Patch(p1, gc.Pc)
- gins(optoas(gc.OAS, f.Type), &bigf, &r3)
- gins(optoas(gc.OSUB, f.Type), &r3, &r1)
- gins(a, &r1, &r2)
- gins(x86.AMOVQ, &bigi, &r4)
- gins(x86.AXORQ, &r4, &r2)
- gc.Patch(p2, gc.Pc)
- gmove(&r2, t)
- gc.Regfree(&r4)
- gc.Regfree(&r3)
- gc.Regfree(&r2)
- gc.Regfree(&r1)
- return
-
- /*
- * integer to float
- */
- case gc.TINT32<<16 | gc.TFLOAT32:
- a = x86.ACVTSL2SS
-
- goto rdst
-
- case gc.TINT32<<16 | gc.TFLOAT64:
- a = x86.ACVTSL2SD
- goto rdst
-
- case gc.TINT64<<16 | gc.TFLOAT32:
- a = x86.ACVTSQ2SS
- goto rdst
-
- case gc.TINT64<<16 | gc.TFLOAT64:
- a = x86.ACVTSQ2SD
- goto rdst
-
- // convert via int32
- case gc.TINT16<<16 | gc.TFLOAT32,
- gc.TINT16<<16 | gc.TFLOAT64,
- gc.TINT8<<16 | gc.TFLOAT32,
- gc.TINT8<<16 | gc.TFLOAT64,
- gc.TUINT16<<16 | gc.TFLOAT32,
- gc.TUINT16<<16 | gc.TFLOAT64,
- gc.TUINT8<<16 | gc.TFLOAT32,
- gc.TUINT8<<16 | gc.TFLOAT64:
- cvt = gc.Types[gc.TINT32]
-
- goto hard
-
- // convert via int64.
- case gc.TUINT32<<16 | gc.TFLOAT32,
- gc.TUINT32<<16 | gc.TFLOAT64:
- cvt = gc.Types[gc.TINT64]
-
- goto hard
-
- // algorithm is:
- // if small enough, use native int64 -> uint64 conversion.
- // otherwise, halve (rounding to odd?), convert, and double.
- case gc.TUINT64<<16 | gc.TFLOAT32,
- gc.TUINT64<<16 | gc.TFLOAT64:
- a := x86.ACVTSQ2SS
-
- if tt == gc.TFLOAT64 {
- a = x86.ACVTSQ2SD
- }
- var zero gc.Node
- gc.Nodconst(&zero, gc.Types[gc.TUINT64], 0)
- var one gc.Node
- gc.Nodconst(&one, gc.Types[gc.TUINT64], 1)
- var r1 gc.Node
- gc.Regalloc(&r1, f.Type, f)
- var r2 gc.Node
- gc.Regalloc(&r2, t.Type, t)
- var r3 gc.Node
- gc.Regalloc(&r3, f.Type, nil)
- var r4 gc.Node
- gc.Regalloc(&r4, f.Type, nil)
- gmove(f, &r1)
- gins(x86.ACMPQ, &r1, &zero)
- p1 := gc.Gbranch(x86.AJLT, nil, +1)
- gins(a, &r1, &r2)
- p2 := gc.Gbranch(obj.AJMP, nil, 0)
- gc.Patch(p1, gc.Pc)
- gmove(&r1, &r3)
- gins(x86.ASHRQ, &one, &r3)
- gmove(&r1, &r4)
- gins(x86.AANDL, &one, &r4)
- gins(x86.AORQ, &r4, &r3)
- gins(a, &r3, &r2)
- gins(optoas(gc.OADD, t.Type), &r2, &r2)
- gc.Patch(p2, gc.Pc)
- gmove(&r2, t)
- gc.Regfree(&r4)
- gc.Regfree(&r3)
- gc.Regfree(&r2)
- gc.Regfree(&r1)
- return
-
- /*
- * float to float
- */
- case gc.TFLOAT32<<16 | gc.TFLOAT32:
- a = x86.AMOVSS
-
- case gc.TFLOAT64<<16 | gc.TFLOAT64:
- a = x86.AMOVSD
-
- case gc.TFLOAT32<<16 | gc.TFLOAT64:
- a = x86.ACVTSS2SD
- goto rdst
-
- case gc.TFLOAT64<<16 | gc.TFLOAT32:
- a = x86.ACVTSD2SS
- goto rdst
- }
-
- gins(a, f, t)
- return
-
- // requires register destination
-rdst:
- {
- var r1 gc.Node
- gc.Regalloc(&r1, t.Type, t)
-
- gins(a, f, &r1)
- gmove(&r1, t)
- gc.Regfree(&r1)
- return
- }
-
- // requires register intermediate
-hard:
- var r1 gc.Node
- gc.Regalloc(&r1, cvt, t)
-
- gmove(f, &r1)
- gmove(&r1, t)
- gc.Regfree(&r1)
- return
-}
-
-func samaddr(f *gc.Node, t *gc.Node) bool {
- if f.Op != t.Op {
- return false
- }
-
- switch f.Op {
- case gc.OREGISTER:
- if f.Reg != t.Reg {
- break
- }
- return true
- }
-
- return false
-}
-
-/*
- * generate one instruction:
- * as f, t
- */
-func gins(as obj.As, f *gc.Node, t *gc.Node) *obj.Prog {
- // Node nod;
-
- // if(f != N && f->op == OINDEX) {
- // gc.Regalloc(&nod, ®node, Z);
- // v = constnode.vconst;
- // gc.Cgen(f->right, &nod);
- // constnode.vconst = v;
- // idx.reg = nod.reg;
- // gc.Regfree(&nod);
- // }
- // if(t != N && t->op == OINDEX) {
- // gc.Regalloc(&nod, ®node, Z);
- // v = constnode.vconst;
- // gc.Cgen(t->right, &nod);
- // constnode.vconst = v;
- // idx.reg = nod.reg;
- // gc.Regfree(&nod);
- // }
-
- if f != nil && f.Op == gc.OADDR && (as == x86.AMOVL || as == x86.AMOVQ) {
- // Turn MOVL $xxx into LEAL xxx.
- // These should be equivalent but most of the backend
- // only expects to see LEAL, because that's what we had
- // historically generated. Various hidden assumptions are baked in by now.
- if as == x86.AMOVL {
- as = x86.ALEAL
- } else {
- as = x86.ALEAQ
- }
- f = f.Left
- }
-
- switch as {
- case x86.AMOVB,
- x86.AMOVW,
- x86.AMOVL,
- x86.AMOVQ,
- x86.AMOVSS,
- x86.AMOVSD:
- if f != nil && t != nil && samaddr(f, t) {
- return nil
- }
-
- case x86.ALEAQ:
- if f != nil && gc.Isconst(f, gc.CTNIL) {
- gc.Fatalf("gins LEAQ nil %v", f.Type)
- }
- }
-
- p := gc.Prog(as)
- gc.Naddr(&p.From, f)
- gc.Naddr(&p.To, t)
-
- if gc.Debug['g'] != 0 {
- fmt.Printf("%v\n", p)
- }
-
- w := int32(0)
- switch as {
- case x86.AMOVB:
- w = 1
-
- case x86.AMOVW:
- w = 2
-
- case x86.AMOVL:
- w = 4
-
- case x86.AMOVQ:
- w = 8
- }
-
- if w != 0 && ((f != nil && p.From.Width < int64(w)) || (t != nil && p.To.Width > int64(w))) {
- gc.Dump("f", f)
- gc.Dump("t", t)
- gc.Fatalf("bad width: %v (%d, %d)\n", p, p.From.Width, p.To.Width)
- }
-
- if p.To.Type == obj.TYPE_ADDR && w > 0 {
- gc.Fatalf("bad use of addr: %v", p)
- }
-
- return p
-}
-
-func ginsnop() {
- // This is actually not the x86 NOP anymore,
- // but at the point where it gets used, AX is dead
- // so it's okay if we lose the high bits.
- var reg gc.Node
- gc.Nodreg(®, gc.Types[gc.TINT], x86.REG_AX)
- gins(x86.AXCHGL, ®, ®)
-}
-
-/*
- * return Axxx for Oxxx on type t.
- */
-func optoas(op gc.Op, t *gc.Type) obj.As {
- if t == nil {
- gc.Fatalf("optoas: t is nil")
- }
-
- // avoid constant conversions in switches below
- const (
- OMINUS_ = uint32(gc.OMINUS) << 16
- OLSH_ = uint32(gc.OLSH) << 16
- ORSH_ = uint32(gc.ORSH) << 16
- OADD_ = uint32(gc.OADD) << 16
- OSUB_ = uint32(gc.OSUB) << 16
- OMUL_ = uint32(gc.OMUL) << 16
- ODIV_ = uint32(gc.ODIV) << 16
- OMOD_ = uint32(gc.OMOD) << 16
- OOR_ = uint32(gc.OOR) << 16
- OAND_ = uint32(gc.OAND) << 16
- OXOR_ = uint32(gc.OXOR) << 16
- OEQ_ = uint32(gc.OEQ) << 16
- ONE_ = uint32(gc.ONE) << 16
- OLT_ = uint32(gc.OLT) << 16
- OLE_ = uint32(gc.OLE) << 16
- OGE_ = uint32(gc.OGE) << 16
- OGT_ = uint32(gc.OGT) << 16
- OCMP_ = uint32(gc.OCMP) << 16
- OPS_ = uint32(gc.OPS) << 16
- OPC_ = uint32(gc.OPC) << 16
- OAS_ = uint32(gc.OAS) << 16
- OHMUL_ = uint32(gc.OHMUL) << 16
- OSQRT_ = uint32(gc.OSQRT) << 16
- OADDR_ = uint32(gc.OADDR) << 16
- OINC_ = uint32(gc.OINC) << 16
- ODEC_ = uint32(gc.ODEC) << 16
- OLROT_ = uint32(gc.OLROT) << 16
- ORROTC_ = uint32(gc.ORROTC) << 16
- OEXTEND_ = uint32(gc.OEXTEND) << 16
- )
-
- a := obj.AXXX
- switch uint32(op)<<16 | uint32(gc.Simtype[t.Etype]) {
- default:
- gc.Fatalf("optoas: no entry %v-%v", op, t)
-
- case OADDR_ | gc.TPTR32:
- a = x86.ALEAL
-
- case OADDR_ | gc.TPTR64:
- a = x86.ALEAQ
-
- case OEQ_ | gc.TBOOL,
- OEQ_ | gc.TINT8,
- OEQ_ | gc.TUINT8,
- OEQ_ | gc.TINT16,
- OEQ_ | gc.TUINT16,
- OEQ_ | gc.TINT32,
- OEQ_ | gc.TUINT32,
- OEQ_ | gc.TINT64,
- OEQ_ | gc.TUINT64,
- OEQ_ | gc.TPTR32,
- OEQ_ | gc.TPTR64,
- OEQ_ | gc.TFLOAT32,
- OEQ_ | gc.TFLOAT64:
- a = x86.AJEQ
-
- case ONE_ | gc.TBOOL,
- ONE_ | gc.TINT8,
- ONE_ | gc.TUINT8,
- ONE_ | gc.TINT16,
- ONE_ | gc.TUINT16,
- ONE_ | gc.TINT32,
- ONE_ | gc.TUINT32,
- ONE_ | gc.TINT64,
- ONE_ | gc.TUINT64,
- ONE_ | gc.TPTR32,
- ONE_ | gc.TPTR64,
- ONE_ | gc.TFLOAT32,
- ONE_ | gc.TFLOAT64:
- a = x86.AJNE
-
- case OPS_ | gc.TBOOL,
- OPS_ | gc.TINT8,
- OPS_ | gc.TUINT8,
- OPS_ | gc.TINT16,
- OPS_ | gc.TUINT16,
- OPS_ | gc.TINT32,
- OPS_ | gc.TUINT32,
- OPS_ | gc.TINT64,
- OPS_ | gc.TUINT64,
- OPS_ | gc.TPTR32,
- OPS_ | gc.TPTR64,
- OPS_ | gc.TFLOAT32,
- OPS_ | gc.TFLOAT64:
- a = x86.AJPS
-
- case OPC_ | gc.TBOOL,
- OPC_ | gc.TINT8,
- OPC_ | gc.TUINT8,
- OPC_ | gc.TINT16,
- OPC_ | gc.TUINT16,
- OPC_ | gc.TINT32,
- OPC_ | gc.TUINT32,
- OPC_ | gc.TINT64,
- OPC_ | gc.TUINT64,
- OPC_ | gc.TPTR32,
- OPC_ | gc.TPTR64,
- OPC_ | gc.TFLOAT32,
- OPC_ | gc.TFLOAT64:
- a = x86.AJPC
-
- case OLT_ | gc.TINT8,
- OLT_ | gc.TINT16,
- OLT_ | gc.TINT32,
- OLT_ | gc.TINT64:
- a = x86.AJLT
-
- case OLT_ | gc.TUINT8,
- OLT_ | gc.TUINT16,
- OLT_ | gc.TUINT32,
- OLT_ | gc.TUINT64:
- a = x86.AJCS
-
- case OLE_ | gc.TINT8,
- OLE_ | gc.TINT16,
- OLE_ | gc.TINT32,
- OLE_ | gc.TINT64:
- a = x86.AJLE
-
- case OLE_ | gc.TUINT8,
- OLE_ | gc.TUINT16,
- OLE_ | gc.TUINT32,
- OLE_ | gc.TUINT64:
- a = x86.AJLS
-
- case OGT_ | gc.TINT8,
- OGT_ | gc.TINT16,
- OGT_ | gc.TINT32,
- OGT_ | gc.TINT64:
- a = x86.AJGT
-
- case OGT_ | gc.TUINT8,
- OGT_ | gc.TUINT16,
- OGT_ | gc.TUINT32,
- OGT_ | gc.TUINT64,
- OLT_ | gc.TFLOAT32,
- OLT_ | gc.TFLOAT64:
- a = x86.AJHI
-
- case OGE_ | gc.TINT8,
- OGE_ | gc.TINT16,
- OGE_ | gc.TINT32,
- OGE_ | gc.TINT64:
- a = x86.AJGE
-
- case OGE_ | gc.TUINT8,
- OGE_ | gc.TUINT16,
- OGE_ | gc.TUINT32,
- OGE_ | gc.TUINT64,
- OLE_ | gc.TFLOAT32,
- OLE_ | gc.TFLOAT64:
- a = x86.AJCC
-
- case OCMP_ | gc.TBOOL,
- OCMP_ | gc.TINT8,
- OCMP_ | gc.TUINT8:
- a = x86.ACMPB
-
- case OCMP_ | gc.TINT16,
- OCMP_ | gc.TUINT16:
- a = x86.ACMPW
-
- case OCMP_ | gc.TINT32,
- OCMP_ | gc.TUINT32,
- OCMP_ | gc.TPTR32:
- a = x86.ACMPL
-
- case OCMP_ | gc.TINT64,
- OCMP_ | gc.TUINT64,
- OCMP_ | gc.TPTR64:
- a = x86.ACMPQ
-
- case OCMP_ | gc.TFLOAT32:
- a = x86.AUCOMISS
-
- case OCMP_ | gc.TFLOAT64:
- a = x86.AUCOMISD
-
- case OAS_ | gc.TBOOL,
- OAS_ | gc.TINT8,
- OAS_ | gc.TUINT8:
- a = x86.AMOVB
-
- case OAS_ | gc.TINT16,
- OAS_ | gc.TUINT16:
- a = x86.AMOVW
-
- case OAS_ | gc.TINT32,
- OAS_ | gc.TUINT32,
- OAS_ | gc.TPTR32:
- a = x86.AMOVL
-
- case OAS_ | gc.TINT64,
- OAS_ | gc.TUINT64,
- OAS_ | gc.TPTR64:
- a = x86.AMOVQ
-
- case OAS_ | gc.TFLOAT32:
- a = x86.AMOVSS
-
- case OAS_ | gc.TFLOAT64:
- a = x86.AMOVSD
-
- case OADD_ | gc.TINT8,
- OADD_ | gc.TUINT8:
- a = x86.AADDB
-
- case OADD_ | gc.TINT16,
- OADD_ | gc.TUINT16:
- a = x86.AADDW
-
- case OADD_ | gc.TINT32,
- OADD_ | gc.TUINT32,
- OADD_ | gc.TPTR32:
- a = x86.AADDL
-
- case OADD_ | gc.TINT64,
- OADD_ | gc.TUINT64,
- OADD_ | gc.TPTR64:
- a = x86.AADDQ
-
- case OADD_ | gc.TFLOAT32:
- a = x86.AADDSS
-
- case OADD_ | gc.TFLOAT64:
- a = x86.AADDSD
-
- case OSUB_ | gc.TINT8,
- OSUB_ | gc.TUINT8:
- a = x86.ASUBB
-
- case OSUB_ | gc.TINT16,
- OSUB_ | gc.TUINT16:
- a = x86.ASUBW
-
- case OSUB_ | gc.TINT32,
- OSUB_ | gc.TUINT32,
- OSUB_ | gc.TPTR32:
- a = x86.ASUBL
-
- case OSUB_ | gc.TINT64,
- OSUB_ | gc.TUINT64,
- OSUB_ | gc.TPTR64:
- a = x86.ASUBQ
-
- case OSUB_ | gc.TFLOAT32:
- a = x86.ASUBSS
-
- case OSUB_ | gc.TFLOAT64:
- a = x86.ASUBSD
-
- case OINC_ | gc.TINT8,
- OINC_ | gc.TUINT8:
- a = x86.AINCB
-
- case OINC_ | gc.TINT16,
- OINC_ | gc.TUINT16:
- a = x86.AINCW
-
- case OINC_ | gc.TINT32,
- OINC_ | gc.TUINT32,
- OINC_ | gc.TPTR32:
- a = x86.AINCL
-
- case OINC_ | gc.TINT64,
- OINC_ | gc.TUINT64,
- OINC_ | gc.TPTR64:
- a = x86.AINCQ
-
- case ODEC_ | gc.TINT8,
- ODEC_ | gc.TUINT8:
- a = x86.ADECB
-
- case ODEC_ | gc.TINT16,
- ODEC_ | gc.TUINT16:
- a = x86.ADECW
-
- case ODEC_ | gc.TINT32,
- ODEC_ | gc.TUINT32,
- ODEC_ | gc.TPTR32:
- a = x86.ADECL
-
- case ODEC_ | gc.TINT64,
- ODEC_ | gc.TUINT64,
- ODEC_ | gc.TPTR64:
- a = x86.ADECQ
-
- case OMINUS_ | gc.TINT8,
- OMINUS_ | gc.TUINT8:
- a = x86.ANEGB
-
- case OMINUS_ | gc.TINT16,
- OMINUS_ | gc.TUINT16:
- a = x86.ANEGW
-
- case OMINUS_ | gc.TINT32,
- OMINUS_ | gc.TUINT32,
- OMINUS_ | gc.TPTR32:
- a = x86.ANEGL
-
- case OMINUS_ | gc.TINT64,
- OMINUS_ | gc.TUINT64,
- OMINUS_ | gc.TPTR64:
- a = x86.ANEGQ
-
- case OAND_ | gc.TBOOL,
- OAND_ | gc.TINT8,
- OAND_ | gc.TUINT8:
- a = x86.AANDB
-
- case OAND_ | gc.TINT16,
- OAND_ | gc.TUINT16:
- a = x86.AANDW
-
- case OAND_ | gc.TINT32,
- OAND_ | gc.TUINT32,
- OAND_ | gc.TPTR32:
- a = x86.AANDL
-
- case OAND_ | gc.TINT64,
- OAND_ | gc.TUINT64,
- OAND_ | gc.TPTR64:
- a = x86.AANDQ
-
- case OOR_ | gc.TBOOL,
- OOR_ | gc.TINT8,
- OOR_ | gc.TUINT8:
- a = x86.AORB
-
- case OOR_ | gc.TINT16,
- OOR_ | gc.TUINT16:
- a = x86.AORW
-
- case OOR_ | gc.TINT32,
- OOR_ | gc.TUINT32,
- OOR_ | gc.TPTR32:
- a = x86.AORL
-
- case OOR_ | gc.TINT64,
- OOR_ | gc.TUINT64,
- OOR_ | gc.TPTR64:
- a = x86.AORQ
-
- case OXOR_ | gc.TINT8,
- OXOR_ | gc.TUINT8:
- a = x86.AXORB
-
- case OXOR_ | gc.TINT16,
- OXOR_ | gc.TUINT16:
- a = x86.AXORW
-
- case OXOR_ | gc.TINT32,
- OXOR_ | gc.TUINT32,
- OXOR_ | gc.TPTR32:
- a = x86.AXORL
-
- case OXOR_ | gc.TINT64,
- OXOR_ | gc.TUINT64,
- OXOR_ | gc.TPTR64:
- a = x86.AXORQ
-
- case OLROT_ | gc.TINT8,
- OLROT_ | gc.TUINT8:
- a = x86.AROLB
-
- case OLROT_ | gc.TINT16,
- OLROT_ | gc.TUINT16:
- a = x86.AROLW
-
- case OLROT_ | gc.TINT32,
- OLROT_ | gc.TUINT32,
- OLROT_ | gc.TPTR32:
- a = x86.AROLL
-
- case OLROT_ | gc.TINT64,
- OLROT_ | gc.TUINT64,
- OLROT_ | gc.TPTR64:
- a = x86.AROLQ
-
- case OLSH_ | gc.TINT8,
- OLSH_ | gc.TUINT8:
- a = x86.ASHLB
-
- case OLSH_ | gc.TINT16,
- OLSH_ | gc.TUINT16:
- a = x86.ASHLW
-
- case OLSH_ | gc.TINT32,
- OLSH_ | gc.TUINT32,
- OLSH_ | gc.TPTR32:
- a = x86.ASHLL
-
- case OLSH_ | gc.TINT64,
- OLSH_ | gc.TUINT64,
- OLSH_ | gc.TPTR64:
- a = x86.ASHLQ
-
- case ORSH_ | gc.TUINT8:
- a = x86.ASHRB
-
- case ORSH_ | gc.TUINT16:
- a = x86.ASHRW
-
- case ORSH_ | gc.TUINT32,
- ORSH_ | gc.TPTR32:
- a = x86.ASHRL
-
- case ORSH_ | gc.TUINT64,
- ORSH_ | gc.TPTR64:
- a = x86.ASHRQ
-
- case ORSH_ | gc.TINT8:
- a = x86.ASARB
-
- case ORSH_ | gc.TINT16:
- a = x86.ASARW
-
- case ORSH_ | gc.TINT32:
- a = x86.ASARL
-
- case ORSH_ | gc.TINT64:
- a = x86.ASARQ
-
- case ORROTC_ | gc.TINT8,
- ORROTC_ | gc.TUINT8:
- a = x86.ARCRB
-
- case ORROTC_ | gc.TINT16,
- ORROTC_ | gc.TUINT16:
- a = x86.ARCRW
-
- case ORROTC_ | gc.TINT32,
- ORROTC_ | gc.TUINT32:
- a = x86.ARCRL
-
- case ORROTC_ | gc.TINT64,
- ORROTC_ | gc.TUINT64:
- a = x86.ARCRQ
-
- case OHMUL_ | gc.TINT8,
- OMUL_ | gc.TINT8,
- OMUL_ | gc.TUINT8:
- a = x86.AIMULB
-
- case OHMUL_ | gc.TINT16,
- OMUL_ | gc.TINT16,
- OMUL_ | gc.TUINT16:
- a = x86.AIMULW
-
- case OHMUL_ | gc.TINT32,
- OMUL_ | gc.TINT32,
- OMUL_ | gc.TUINT32,
- OMUL_ | gc.TPTR32:
- a = x86.AIMULL
-
- case OHMUL_ | gc.TINT64,
- OMUL_ | gc.TINT64,
- OMUL_ | gc.TUINT64,
- OMUL_ | gc.TPTR64:
- a = x86.AIMULQ
-
- case OHMUL_ | gc.TUINT8:
- a = x86.AMULB
-
- case OHMUL_ | gc.TUINT16:
- a = x86.AMULW
-
- case OHMUL_ | gc.TUINT32,
- OHMUL_ | gc.TPTR32:
- a = x86.AMULL
-
- case OHMUL_ | gc.TUINT64,
- OHMUL_ | gc.TPTR64:
- a = x86.AMULQ
-
- case OMUL_ | gc.TFLOAT32:
- a = x86.AMULSS
-
- case OMUL_ | gc.TFLOAT64:
- a = x86.AMULSD
-
- case ODIV_ | gc.TINT8,
- OMOD_ | gc.TINT8:
- a = x86.AIDIVB
-
- case ODIV_ | gc.TUINT8,
- OMOD_ | gc.TUINT8:
- a = x86.ADIVB
-
- case ODIV_ | gc.TINT16,
- OMOD_ | gc.TINT16:
- a = x86.AIDIVW
-
- case ODIV_ | gc.TUINT16,
- OMOD_ | gc.TUINT16:
- a = x86.ADIVW
-
- case ODIV_ | gc.TINT32,
- OMOD_ | gc.TINT32:
- a = x86.AIDIVL
-
- case ODIV_ | gc.TUINT32,
- ODIV_ | gc.TPTR32,
- OMOD_ | gc.TUINT32,
- OMOD_ | gc.TPTR32:
- a = x86.ADIVL
-
- case ODIV_ | gc.TINT64,
- OMOD_ | gc.TINT64:
- a = x86.AIDIVQ
-
- case ODIV_ | gc.TUINT64,
- ODIV_ | gc.TPTR64,
- OMOD_ | gc.TUINT64,
- OMOD_ | gc.TPTR64:
- a = x86.ADIVQ
-
- case OEXTEND_ | gc.TINT16:
- a = x86.ACWD
-
- case OEXTEND_ | gc.TINT32:
- a = x86.ACDQ
-
- case OEXTEND_ | gc.TINT64:
- a = x86.ACQO
-
- case ODIV_ | gc.TFLOAT32:
- a = x86.ADIVSS
-
- case ODIV_ | gc.TFLOAT64:
- a = x86.ADIVSD
-
- case OSQRT_ | gc.TFLOAT64:
- a = x86.ASQRTSD
- }
-
- return a
-}
-
-// jmptoset returns ASETxx for AJxx.
-func jmptoset(jmp obj.As) obj.As {
- switch jmp {
- case x86.AJEQ:
- return x86.ASETEQ
- case x86.AJNE:
- return x86.ASETNE
- case x86.AJLT:
- return x86.ASETLT
- case x86.AJCS:
- return x86.ASETCS
- case x86.AJLE:
- return x86.ASETLE
- case x86.AJLS:
- return x86.ASETLS
- case x86.AJGT:
- return x86.ASETGT
- case x86.AJHI:
- return x86.ASETHI
- case x86.AJGE:
- return x86.ASETGE
- case x86.AJCC:
- return x86.ASETCC
- case x86.AJMI:
- return x86.ASETMI
- case x86.AJOC:
- return x86.ASETOC
- case x86.AJOS:
- return x86.ASETOS
- case x86.AJPC:
- return x86.ASETPC
- case x86.AJPL:
- return x86.ASETPL
- case x86.AJPS:
- return x86.ASETPS
- }
- gc.Fatalf("jmptoset: no entry for %v", jmp)
- panic("unreachable")
-}
-
-const (
- ODynam = 1 << 0
- OAddable = 1 << 1
-)
-
-var clean [20]gc.Node
-
-var cleani int = 0
-
-func sudoclean() {
- if clean[cleani-1].Op != gc.OEMPTY {
- gc.Regfree(&clean[cleani-1])
- }
- if clean[cleani-2].Op != gc.OEMPTY {
- gc.Regfree(&clean[cleani-2])
- }
- cleani -= 2
-}
-
-/*
- * generate code to compute address of n,
- * a reference to a (perhaps nested) field inside
- * an array or struct.
- * return 0 on failure, 1 on success.
- * on success, leaves usable address in a.
- *
- * caller is responsible for calling sudoclean
- * after successful sudoaddable,
- * to release the register used for a.
- */
-func sudoaddable(as obj.As, n *gc.Node, a *obj.Addr) bool {
- if n.Type == nil {
- return false
- }
-
- *a = obj.Addr{}
-
- switch n.Op {
- case gc.OLITERAL:
- if !gc.Isconst(n, gc.CTINT) {
- break
- }
- v := n.Int64()
- if v >= 32000 || v <= -32000 {
- break
- }
- switch as {
- default:
- return false
-
- case x86.AADDB,
- x86.AADDW,
- x86.AADDL,
- x86.AADDQ,
- x86.ASUBB,
- x86.ASUBW,
- x86.ASUBL,
- x86.ASUBQ,
- x86.AANDB,
- x86.AANDW,
- x86.AANDL,
- x86.AANDQ,
- x86.AORB,
- x86.AORW,
- x86.AORL,
- x86.AORQ,
- x86.AXORB,
- x86.AXORW,
- x86.AXORL,
- x86.AXORQ,
- x86.AINCB,
- x86.AINCW,
- x86.AINCL,
- x86.AINCQ,
- x86.ADECB,
- x86.ADECW,
- x86.ADECL,
- x86.ADECQ,
- x86.AMOVB,
- x86.AMOVW,
- x86.AMOVL,
- x86.AMOVQ:
- break
- }
-
- cleani += 2
- reg := &clean[cleani-1]
- reg1 := &clean[cleani-2]
- reg.Op = gc.OEMPTY
- reg1.Op = gc.OEMPTY
- gc.Naddr(a, n)
- return true
-
- case gc.ODOT,
- gc.ODOTPTR:
- cleani += 2
- reg := &clean[cleani-1]
- reg1 := &clean[cleani-2]
- reg.Op = gc.OEMPTY
- reg1.Op = gc.OEMPTY
- var nn *gc.Node
- var oary [10]int64
- o := gc.Dotoffset(n, oary[:], &nn)
- if nn == nil {
- sudoclean()
- return false
- }
-
- if nn.Addable && o == 1 && oary[0] >= 0 {
- // directly addressable set of DOTs
- n1 := *nn
-
- n1.Type = n.Type
- n1.Xoffset += oary[0]
- gc.Naddr(a, &n1)
- return true
- }
-
- gc.Regalloc(reg, gc.Types[gc.Tptr], nil)
- n1 := *reg
- n1.Op = gc.OINDREG
- if oary[0] >= 0 {
- gc.Agen(nn, reg)
- n1.Xoffset = oary[0]
- } else {
- gc.Cgen(nn, reg)
- gc.Cgen_checknil(reg)
- n1.Xoffset = -(oary[0] + 1)
- }
-
- for i := 1; i < o; i++ {
- if oary[i] >= 0 {
- gc.Fatalf("can't happen")
- }
- gins(movptr, &n1, reg)
- gc.Cgen_checknil(reg)
- n1.Xoffset = -(oary[i] + 1)
- }
-
- a.Type = obj.TYPE_NONE
- a.Index = x86.REG_NONE
- gc.Fixlargeoffset(&n1)
- gc.Naddr(a, &n1)
- return true
-
- case gc.OINDEX:
- return false
- }
-
- return false
-}
diff --git a/src/cmd/compile/internal/amd64/peep.go b/src/cmd/compile/internal/amd64/peep.go
deleted file mode 100644
index 4ae5fce..0000000
--- a/src/cmd/compile/internal/amd64/peep.go
+++ /dev/null
@@ -1,1025 +0,0 @@
-// Derived from Inferno utils/6c/peep.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6c/peep.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth at terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth at terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// Portions Copyright © 2009 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-package amd64
-
-import (
- "cmd/compile/internal/gc"
- "cmd/internal/obj"
- "cmd/internal/obj/x86"
- "fmt"
-)
-
-var gactive uint32
-
-const (
- exregoffset = x86.REG_R15
-)
-
-// do we need the carry bit
-func needc(p *obj.Prog) bool {
- for p != nil {
- flags := progcarryflags(p)
- if flags&gc.UseCarry != 0 {
- return true
- }
- if flags&(gc.SetCarry|gc.KillCarry) != 0 {
- return false
- }
- p = p.Link
- }
-
- return false
-}
-
-func rnops(r *gc.Flow) *gc.Flow {
- if r != nil {
- var p *obj.Prog
- var r1 *gc.Flow
- for {
- p = r.Prog
- if p.As != obj.ANOP || p.From.Type != obj.TYPE_NONE || p.To.Type != obj.TYPE_NONE {
- break
- }
- r1 = gc.Uniqs(r)
- if r1 == nil {
- break
- }
- r = r1
- }
- }
-
- return r
-}
-
-func peep(firstp *obj.Prog) {
- g := gc.Flowstart(firstp, nil)
- if g == nil {
- return
- }
- gactive = 0
-
- // byte, word arithmetic elimination.
- elimshortmov(g)
-
- // constant propagation
- // find MOV $con,R followed by
- // another MOV $con,R without
- // setting R in the interim
- var p *obj.Prog
- for r := g.Start; r != nil; r = r.Link {
- p = r.Prog
- switch p.As {
- case x86.ALEAL,
- x86.ALEAQ:
- if regtyp(&p.To) {
- if p.From.Sym != nil {
- if p.From.Index == x86.REG_NONE {
- conprop(r)
- }
- }
- }
-
- case x86.AMOVB,
- x86.AMOVW,
- x86.AMOVL,
- x86.AMOVQ,
- x86.AMOVSS,
- x86.AMOVSD:
- if regtyp(&p.To) {
- if p.From.Type == obj.TYPE_CONST || p.From.Type == obj.TYPE_FCONST {
- conprop(r)
- }
- }
- }
- }
-
- var r *gc.Flow
- var r1 *gc.Flow
- var p1 *obj.Prog
- var t int
-loop1:
- if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
- gc.Dumpit("loop1", g.Start, 0)
- }
-
- t = 0
- for r = g.Start; r != nil; r = r.Link {
- p = r.Prog
- switch p.As {
- case x86.AMOVL,
- x86.AMOVQ,
- x86.AMOVSS,
- x86.AMOVSD:
- if regtyp(&p.To) {
- if regtyp(&p.From) {
- if copyprop(g, r) {
- excise(r)
- t++
- } else if subprop(r) && copyprop(g, r) {
- excise(r)
- t++
- }
- }
- }
-
- case x86.AMOVBLZX,
- x86.AMOVWLZX,
- x86.AMOVBLSX,
- x86.AMOVWLSX:
- if regtyp(&p.To) {
- r1 = rnops(gc.Uniqs(r))
- if r1 != nil {
- p1 = r1.Prog
- if p.As == p1.As && p.To.Type == p1.From.Type && p.To.Reg == p1.From.Reg {
- p1.As = x86.AMOVL
- t++
- }
- }
- }
-
- case x86.AMOVBQSX,
- x86.AMOVBQZX,
- x86.AMOVWQSX,
- x86.AMOVWQZX,
- x86.AMOVLQSX,
- x86.AMOVLQZX,
- x86.AMOVQL:
- if regtyp(&p.To) {
- r1 = rnops(gc.Uniqs(r))
- if r1 != nil {
- p1 = r1.Prog
- if p.As == p1.As && p.To.Type == p1.From.Type && p.To.Reg == p1.From.Reg {
- p1.As = x86.AMOVQ
- t++
- }
- }
- }
-
- case x86.AADDL,
- x86.AADDQ,
- x86.AADDW:
- if p.From.Type != obj.TYPE_CONST || needc(p.Link) {
- break
- }
- if p.From.Offset == -1 {
- if p.As == x86.AADDQ {
- p.As = x86.ADECQ
- } else if p.As == x86.AADDL {
- p.As = x86.ADECL
- } else {
- p.As = x86.ADECW
- }
- p.From = obj.Addr{}
- break
- }
-
- if p.From.Offset == 1 {
- if p.As == x86.AADDQ {
- p.As = x86.AINCQ
- } else if p.As == x86.AADDL {
- p.As = x86.AINCL
- } else {
- p.As = x86.AINCW
- }
- p.From = obj.Addr{}
- break
- }
-
- case x86.ASUBL,
- x86.ASUBQ,
- x86.ASUBW:
- if p.From.Type != obj.TYPE_CONST || needc(p.Link) {
- break
- }
- if p.From.Offset == -1 {
- if p.As == x86.ASUBQ {
- p.As = x86.AINCQ
- } else if p.As == x86.ASUBL {
- p.As = x86.AINCL
- } else {
- p.As = x86.AINCW
- }
- p.From = obj.Addr{}
- break
- }
-
- if p.From.Offset == 1 {
- if p.As == x86.ASUBQ {
- p.As = x86.ADECQ
- } else if p.As == x86.ASUBL {
- p.As = x86.ADECL
- } else {
- p.As = x86.ADECW
- }
- p.From = obj.Addr{}
- break
- }
- }
- }
-
- if t != 0 {
- goto loop1
- }
-
- // MOVLQZX removal.
- // The MOVLQZX exists to avoid being confused for a
- // MOVL that is just copying 32-bit data around during
- // copyprop. Now that copyprop is done, remov MOVLQZX R1, R2
- // if it is dominated by an earlier ADDL/MOVL/etc into R1 that
- // will have already cleared the high bits.
- //
- // MOVSD removal.
- // We never use packed registers, so a MOVSD between registers
- // can be replaced by MOVAPD, which moves the pair of float64s
- // instead of just the lower one. We only use the lower one, but
- // the processor can do better if we do moves using both.
- for r := g.Start; r != nil; r = r.Link {
- p = r.Prog
- if p.As == x86.AMOVLQZX {
- if regtyp(&p.From) {
- if p.From.Type == p.To.Type && p.From.Reg == p.To.Reg {
- if prevl(r, p.From.Reg) {
- excise(r)
- }
- }
- }
- }
-
- if p.As == x86.AMOVSD {
- if regtyp(&p.From) {
- if regtyp(&p.To) {
- p.As = x86.AMOVAPD
- }
- }
- }
- }
-
- // load pipelining
- // push any load from memory as early as possible
- // to give it time to complete before use.
- for r := g.Start; r != nil; r = r.Link {
- p = r.Prog
- switch p.As {
- case x86.AMOVB,
- x86.AMOVW,
- x86.AMOVL,
- x86.AMOVQ,
- x86.AMOVLQZX:
- if regtyp(&p.To) && !regconsttyp(&p.From) {
- pushback(r)
- }
- }
- }
-
- gc.Flowend(g)
-}
-
-func pushback(r0 *gc.Flow) {
- var r *gc.Flow
- var p *obj.Prog
-
- var b *gc.Flow
- p0 := r0.Prog
- for r = gc.Uniqp(r0); r != nil && gc.Uniqs(r) != nil; r = gc.Uniqp(r) {
- p = r.Prog
- if p.As != obj.ANOP {
- if !regconsttyp(&p.From) || !regtyp(&p.To) {
- break
- }
- if copyu(p, &p0.To, nil) != 0 || copyu(p0, &p.To, nil) != 0 {
- break
- }
- }
-
- if p.As == obj.ACALL {
- break
- }
- b = r
- }
-
- if b == nil {
- if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
- fmt.Printf("no pushback: %v\n", r0.Prog)
- if r != nil {
- fmt.Printf("\t%v [%v]\n", r.Prog, gc.Uniqs(r) != nil)
- }
- }
-
- return
- }
-
- if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
- fmt.Printf("pushback\n")
- for r := b; ; r = r.Link {
- fmt.Printf("\t%v\n", r.Prog)
- if r == r0 {
- break
- }
- }
- }
-
- t := *r0.Prog
- for r = gc.Uniqp(r0); ; r = gc.Uniqp(r) {
- p0 = r.Link.Prog
- p = r.Prog
- p0.As = p.As
- p0.Lineno = p.Lineno
- p0.From = p.From
- p0.To = p.To
-
- if r == b {
- break
- }
- }
-
- p0 = r.Prog
- p0.As = t.As
- p0.Lineno = t.Lineno
- p0.From = t.From
- p0.To = t.To
-
- if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
- fmt.Printf("\tafter\n")
- for r := b; ; r = r.Link {
- fmt.Printf("\t%v\n", r.Prog)
- if r == r0 {
- break
- }
- }
- }
-}
-
-func excise(r *gc.Flow) {
- p := r.Prog
- if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
- fmt.Printf("%v ===delete===\n", p)
- }
-
- obj.Nopout(p)
-
- gc.Ostats.Ndelmov++
-}
-
-func regtyp(a *obj.Addr) bool {
- return a.Type == obj.TYPE_REG && (x86.REG_AX <= a.Reg && a.Reg <= x86.REG_R15 || x86.REG_X0 <= a.Reg && a.Reg <= x86.REG_X15)
-}
-
-// movb elimination.
-// movb is simulated by the linker
-// when a register other than ax, bx, cx, dx
-// is used, so rewrite to other instructions
-// when possible. a movb into a register
-// can smash the entire 32-bit register without
-// causing any trouble.
-//
-// TODO: Using the Q forms here instead of the L forms
-// seems unnecessary, and it makes the instructions longer.
-func elimshortmov(g *gc.Graph) {
- var p *obj.Prog
-
- for r := g.Start; r != nil; r = r.Link {
- p = r.Prog
- if regtyp(&p.To) {
- switch p.As {
- case x86.AINCB,
- x86.AINCW:
- p.As = x86.AINCQ
-
- case x86.ADECB,
- x86.ADECW:
- p.As = x86.ADECQ
-
- case x86.ANEGB,
- x86.ANEGW:
- p.As = x86.ANEGQ
-
- case x86.ANOTB,
- x86.ANOTW:
- p.As = x86.ANOTQ
- }
-
- if regtyp(&p.From) || p.From.Type == obj.TYPE_CONST {
- // move or arithmetic into partial register.
- // from another register or constant can be movl.
- // we don't switch to 64-bit arithmetic if it can
- // change how the carry bit is set (and the carry bit is needed).
- switch p.As {
- case x86.AMOVB,
- x86.AMOVW:
- p.As = x86.AMOVQ
-
- case x86.AADDB,
- x86.AADDW:
- if !needc(p.Link) {
- p.As = x86.AADDQ
- }
-
- case x86.ASUBB,
- x86.ASUBW:
- if !needc(p.Link) {
- p.As = x86.ASUBQ
- }
-
- case x86.AMULB,
- x86.AMULW:
- p.As = x86.AMULQ
-
- case x86.AIMULB,
- x86.AIMULW:
- p.As = x86.AIMULQ
-
- case x86.AANDB,
- x86.AANDW:
- p.As = x86.AANDQ
-
- case x86.AORB,
- x86.AORW:
- p.As = x86.AORQ
-
- case x86.AXORB,
- x86.AXORW:
- p.As = x86.AXORQ
-
- case x86.ASHLB,
- x86.ASHLW:
- p.As = x86.ASHLQ
- }
- } else if p.From.Type != obj.TYPE_REG {
- // explicit zero extension, but don't
- // do that if source is a byte register
- // (only AH can occur and it's forbidden).
- switch p.As {
- case x86.AMOVB:
- p.As = x86.AMOVBQZX
-
- case x86.AMOVW:
- p.As = x86.AMOVWQZX
- }
- }
- }
- }
-}
-
-// is 'a' a register or constant?
-func regconsttyp(a *obj.Addr) bool {
- if regtyp(a) {
- return true
- }
- switch a.Type {
- case obj.TYPE_CONST,
- obj.TYPE_FCONST,
- obj.TYPE_SCONST,
- obj.TYPE_ADDR: // TODO(rsc): Not all TYPE_ADDRs are constants.
- return true
- }
-
- return false
-}
-
-// is reg guaranteed to be truncated by a previous L instruction?
-func prevl(r0 *gc.Flow, reg int16) bool {
- for r := gc.Uniqp(r0); r != nil; r = gc.Uniqp(r) {
- p := r.Prog
- if p.To.Type == obj.TYPE_REG && p.To.Reg == reg {
- flags := progflags(p)
- if flags&gc.RightWrite != 0 {
- if flags&gc.SizeL != 0 {
- return true
- }
- return false
- }
- }
- }
- return false
-}
-
-/*
- * the idea is to substitute
- * one register for another
- * from one MOV to another
- * MOV a, R0
- * ADD b, R0 / no use of R1
- * MOV R0, R1
- * would be converted to
- * MOV a, R1
- * ADD b, R1
- * MOV R1, R0
- * hopefully, then the former or latter MOV
- * will be eliminated by copy propagation.
- */
-func subprop(r0 *gc.Flow) bool {
- if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
- fmt.Printf("subprop %v\n", r0.Prog)
- }
- p := r0.Prog
- v1 := &p.From
- if !regtyp(v1) {
- if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
- fmt.Printf("\tnot regtype %v; return 0\n", gc.Ctxt.Dconv(v1))
- }
- return false
- }
-
- v2 := &p.To
- if !regtyp(v2) {
- if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
- fmt.Printf("\tnot regtype %v; return 0\n", gc.Ctxt.Dconv(v2))
- }
- return false
- }
-
- for r := gc.Uniqp(r0); r != nil; r = gc.Uniqp(r) {
- if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
- fmt.Printf("\t? %v\n", r.Prog)
- }
- if gc.Uniqs(r) == nil {
- if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
- fmt.Printf("\tno unique successor\n")
- }
- break
- }
-
- p = r.Prog
- if p.As == obj.AVARDEF || p.As == obj.AVARKILL {
- continue
- }
- if p.Info.Flags&gc.Call != 0 {
- if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
- fmt.Printf("\tfound %v; return 0\n", p)
- }
- return false
- }
-
- if p.Info.Reguse|p.Info.Regset != 0 {
- if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
- fmt.Printf("\tfound %v; return 0\n", p)
- }
- return false
- }
-
- if (p.Info.Flags&gc.Move != 0) && (p.Info.Flags&(gc.SizeL|gc.SizeQ|gc.SizeF|gc.SizeD) != 0) && p.To.Type == v1.Type && p.To.Reg == v1.Reg {
- copysub(&p.To, v1, v2, true)
- if gc.Debug['P'] != 0 {
- fmt.Printf("gotit: %v->%v\n%v", gc.Ctxt.Dconv(v1), gc.Ctxt.Dconv(v2), r.Prog)
- if p.From.Type == v2.Type && p.From.Reg == v2.Reg {
- fmt.Printf(" excise")
- }
- fmt.Printf("\n")
- }
-
- for r = gc.Uniqs(r); r != r0; r = gc.Uniqs(r) {
- p = r.Prog
- copysub(&p.From, v1, v2, true)
- copysub(&p.To, v1, v2, true)
- if gc.Debug['P'] != 0 {
- fmt.Printf("%v\n", r.Prog)
- }
- }
-
- v1.Reg, v2.Reg = v2.Reg, v1.Reg
- if gc.Debug['P'] != 0 {
- fmt.Printf("%v last\n", r.Prog)
- }
- return true
- }
-
- if copyau(&p.From, v2) || copyau(&p.To, v2) {
- if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
- fmt.Printf("\tcopyau %v failed\n", gc.Ctxt.Dconv(v2))
- }
- break
- }
-
- if copysub(&p.From, v1, v2, false) || copysub(&p.To, v1, v2, false) {
- if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
- fmt.Printf("\tcopysub failed\n")
- }
- break
- }
- }
-
- if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
- fmt.Printf("\tran off end; return 0\n")
- }
- return false
-}
-
-/*
- * The idea is to remove redundant copies.
- * v1->v2 F=0
- * (use v2 s/v2/v1/)*
- * set v1 F=1
- * use v2 return fail
- * -----------------
- * v1->v2 F=0
- * (use v2 s/v2/v1/)*
- * set v1 F=1
- * set v2 return success
- */
-func copyprop(g *gc.Graph, r0 *gc.Flow) bool {
- if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
- fmt.Printf("copyprop %v\n", r0.Prog)
- }
- p := r0.Prog
- v1 := &p.From
- v2 := &p.To
- if copyas(v1, v2) {
- return true
- }
- gactive++
- return copy1(v1, v2, r0.S1, false)
-}
-
-func copy1(v1 *obj.Addr, v2 *obj.Addr, r *gc.Flow, f bool) bool {
- if uint32(r.Active) == gactive {
- if gc.Debug['P'] != 0 {
- fmt.Printf("act set; return 1\n")
- }
- return true
- }
-
- r.Active = int32(gactive)
- if gc.Debug['P'] != 0 {
- fmt.Printf("copy %v->%v f=%v\n", gc.Ctxt.Dconv(v1), gc.Ctxt.Dconv(v2), f)
- }
- for ; r != nil; r = r.S1 {
- p := r.Prog
- if gc.Debug['P'] != 0 {
- fmt.Printf("%v", p)
- }
- if !f && gc.Uniqp(r) == nil {
- f = true
- if gc.Debug['P'] != 0 {
- fmt.Printf("; merge; f=%v", f)
- }
- }
-
- switch t := copyu(p, v2, nil); t {
- case 2: /* rar, can't split */
- if gc.Debug['P'] != 0 {
- fmt.Printf("; %v rar; return 0\n", gc.Ctxt.Dconv(v2))
- }
- return false
-
- case 3: /* set */
- if gc.Debug['P'] != 0 {
- fmt.Printf("; %v set; return 1\n", gc.Ctxt.Dconv(v2))
- }
- return true
-
- case 1, /* used, substitute */
- 4: /* use and set */
- if f {
- if gc.Debug['P'] == 0 {
- return false
- }
- if t == 4 {
- fmt.Printf("; %v used+set and f=%v; return 0\n", gc.Ctxt.Dconv(v2), f)
- } else {
- fmt.Printf("; %v used and f=%v; return 0\n", gc.Ctxt.Dconv(v2), f)
- }
- return false
- }
-
- if copyu(p, v2, v1) != 0 {
- if gc.Debug['P'] != 0 {
- fmt.Printf("; sub fail; return 0\n")
- }
- return false
- }
-
- if gc.Debug['P'] != 0 {
- fmt.Printf("; sub %v/%v", gc.Ctxt.Dconv(v2), gc.Ctxt.Dconv(v1))
- }
- if t == 4 {
- if gc.Debug['P'] != 0 {
- fmt.Printf("; %v used+set; return 1\n", gc.Ctxt.Dconv(v2))
- }
- return true
- }
- }
-
- if !f {
- t := copyu(p, v1, nil)
- if t == 2 || t == 3 || t == 4 {
- f = true
- if gc.Debug['P'] != 0 {
- fmt.Printf("; %v set and !f; f=%v", gc.Ctxt.Dconv(v1), f)
- }
- }
- }
-
- if gc.Debug['P'] != 0 {
- fmt.Printf("\n")
- }
- if r.S2 != nil {
- if !copy1(v1, v2, r.S2, f) {
- return false
- }
- }
- }
- return true
-}
-
-/*
- * return
- * 1 if v only used (and substitute),
- * 2 if read-alter-rewrite
- * 3 if set
- * 4 if set and used
- * 0 otherwise (not touched)
- */
-func copyu(p *obj.Prog, v *obj.Addr, s *obj.Addr) int {
- switch p.As {
- case obj.AJMP:
- if s != nil {
- if copysub(&p.To, v, s, true) {
- return 1
- }
- return 0
- }
-
- if copyau(&p.To, v) {
- return 1
- }
- return 0
-
- case obj.ARET:
- if s != nil {
- return 1
- }
- return 3
-
- case obj.ACALL:
- if x86.REGEXT != 0 /*TypeKind(100016)*/ && v.Type == obj.TYPE_REG && v.Reg <= x86.REGEXT && v.Reg > exregoffset {
- return 2
- }
- if x86.REGARG >= 0 && v.Type == obj.TYPE_REG && v.Reg == x86.REGARG {
- return 2
- }
- if v.Type == p.From.Type && v.Reg == p.From.Reg {
- return 2
- }
-
- if s != nil {
- if copysub(&p.To, v, s, true) {
- return 1
- }
- return 0
- }
-
- if copyau(&p.To, v) {
- return 4
- }
- return 3
-
- case obj.ATEXT:
- if x86.REGARG >= 0 && v.Type == obj.TYPE_REG && v.Reg == x86.REGARG {
- return 3
- }
- return 0
- }
-
- if p.As == obj.AVARDEF || p.As == obj.AVARKILL {
- return 0
- }
-
- if (p.Info.Reguse|p.Info.Regset)&RtoB(int(v.Reg)) != 0 {
- return 2
- }
-
- if (p.Info.Reguse|p.Info.Regset)&FtoB(int(v.Reg)) != 0 {
- return 2
- }
-
- if p.Info.Flags&gc.LeftAddr != 0 {
- if copyas(&p.From, v) {
- return 2
- }
- }
-
- if p.Info.Flags&(gc.RightRead|gc.RightWrite) == gc.RightRead|gc.RightWrite {
- if copyas(&p.To, v) {
- return 2
- }
- }
-
- if p.Info.Flags&gc.RightWrite != 0 {
- if copyas(&p.To, v) {
- if s != nil {
- if copysub(&p.From, v, s, true) {
- return 1
- }
- return 0
- }
- if copyau(&p.From, v) {
- return 4
- }
- return 3
- }
- }
-
- if p.Info.Flags&(gc.LeftAddr|gc.LeftRead|gc.LeftWrite|gc.RightAddr|gc.RightRead|gc.RightWrite) != 0 {
- if s != nil {
- if copysub(&p.From, v, s, true) {
- return 1
- }
- if copysub(&p.To, v, s, true) {
- return 1
- }
- return 0
- }
-
- if copyau(&p.From, v) {
- return 1
- }
- if copyau(&p.To, v) {
- return 1
- }
- }
- return 0
-}
-
-/*
- * direct reference,
- * could be set/use depending on
- * semantics
- */
-func copyas(a *obj.Addr, v *obj.Addr) bool {
- if x86.REG_AL <= a.Reg && a.Reg <= x86.REG_R15B {
- gc.Fatalf("use of byte register")
- }
- if x86.REG_AL <= v.Reg && v.Reg <= x86.REG_R15B {
- gc.Fatalf("use of byte register")
- }
-
- if a.Type != v.Type || a.Name != v.Name || a.Reg != v.Reg {
- return false
- }
- if regtyp(v) {
- return true
- }
- if v.Type == obj.TYPE_MEM && (v.Name == obj.NAME_AUTO || v.Name == obj.NAME_PARAM) {
- if v.Offset == a.Offset {
- return true
- }
- }
- return false
-}
-
-func sameaddr(a *obj.Addr, v *obj.Addr) bool {
- if a.Type != v.Type || a.Name != v.Name || a.Reg != v.Reg {
- return false
- }
- if regtyp(v) {
- return true
- }
- if v.Type == obj.TYPE_MEM && (v.Name == obj.NAME_AUTO || v.Name == obj.NAME_PARAM) {
- if v.Offset == a.Offset {
- return true
- }
- }
- return false
-}
-
-/*
- * either direct or indirect
- */
-func copyau(a *obj.Addr, v *obj.Addr) bool {
- if copyas(a, v) {
- if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
- fmt.Printf("\tcopyau: copyas returned 1\n")
- }
- return true
- }
-
- if regtyp(v) {
- if a.Type == obj.TYPE_MEM && a.Reg == v.Reg {
- if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
- fmt.Printf("\tcopyau: found indir use - return 1\n")
- }
- return true
- }
-
- if a.Index == v.Reg {
- if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
- fmt.Printf("\tcopyau: found index use - return 1\n")
- }
- return true
- }
- }
- return false
-}
-
-// copysub substitute s for v in a.
-// copysub returns true on failure to substitute. TODO(dfc) reverse this logic, copysub should return false on failure
-func copysub(a *obj.Addr, v *obj.Addr, s *obj.Addr, f bool) bool {
- if copyas(a, v) {
- if s.Reg >= x86.REG_AX && s.Reg <= x86.REG_R15 || s.Reg >= x86.REG_X0 && s.Reg <= x86.REG_X0+15 {
- if f {
- a.Reg = s.Reg
- }
- }
- return false
- }
-
- if regtyp(v) {
- if a.Type == obj.TYPE_MEM && a.Reg == v.Reg {
- if (s.Reg == x86.REG_BP || s.Reg == x86.REG_R13) && a.Index != x86.REG_NONE {
- return true /* can't use BP-base with index */
- }
- if f {
- a.Reg = s.Reg
- }
- }
- if a.Index == v.Reg {
- if f {
- a.Index = s.Reg
- }
- }
- }
- return false
-}
-
-func conprop(r0 *gc.Flow) {
- p0 := r0.Prog
- v0 := &p0.To
- r := r0
-
-loop:
- r = gc.Uniqs(r)
- if r == nil || r == r0 {
- return
- }
- if gc.Uniqp(r) == nil {
- return
- }
-
- p := r.Prog
- t := copyu(p, v0, nil)
- switch t {
- case 0, // miss
- 1: // use
- goto loop
-
- case 2, // rar
- 4: // use and set
- break
-
- case 3: // set
- if p.As == p0.As {
- if p.From.Type == p0.From.Type {
- if p.From.Reg == p0.From.Reg {
- if p.From.Node == p0.From.Node {
- if p.From.Offset == p0.From.Offset {
- if p.From.Scale == p0.From.Scale {
- if p.From.Type == obj.TYPE_FCONST && p.From.Val.(float64) == p0.From.Val.(float64) {
- if p.From.Index == p0.From.Index {
- excise(r)
- goto loop
- }
- }
- }
- }
- }
- }
- }
- }
- }
-}
-
-func smallindir(a *obj.Addr, reg *obj.Addr) bool {
- return regtyp(reg) && a.Type == obj.TYPE_MEM && a.Reg == reg.Reg && a.Index == x86.REG_NONE && 0 <= a.Offset && a.Offset < 4096
-}
-
-func stackaddr(a *obj.Addr) bool {
- return a.Type == obj.TYPE_REG && a.Reg == x86.REG_SP
-}
diff --git a/src/cmd/compile/internal/amd64/prog.go b/src/cmd/compile/internal/amd64/prog.go
index 91b479b..bd95f46 100644
--- a/src/cmd/compile/internal/amd64/prog.go
+++ b/src/cmd/compile/internal/amd64/prog.go
@@ -22,14 +22,13 @@ const (
// Instructions not generated need not be listed.
// As an exception to that rule, we typically write down all the
// size variants of an operation even if we just use a subset.
-var progtable = [x86.ALAST & obj.AMask]obj.ProgInfo{
+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.ACHECKNIL: {Flags: gc.LeftRead},
obj.AVARDEF: {Flags: gc.Pseudo | gc.RightWrite},
obj.AVARKILL: {Flags: gc.Pseudo | gc.RightWrite},
obj.AVARLIVE: {Flags: gc.Pseudo | gc.LeftRead},
@@ -61,9 +60,9 @@ var progtable = [x86.ALAST & obj.AMask]obj.ProgInfo{
x86.ABSWAPQ & obj.AMask: {Flags: gc.SizeQ | RightRdwr},
obj.ACALL & obj.AMask: {Flags: gc.RightAddr | gc.Call | gc.KillCarry},
- x86.ACDQ & obj.AMask: {Flags: gc.OK, Reguse: AX, Regset: AX | DX},
- x86.ACQO & obj.AMask: {Flags: gc.OK, Reguse: AX, Regset: AX | DX},
- x86.ACWD & obj.AMask: {Flags: gc.OK, Reguse: AX, Regset: AX | DX},
+ x86.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},
@@ -78,6 +77,8 @@ var progtable = [x86.ALAST & obj.AMask]obj.ProgInfo{
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},
@@ -98,17 +99,17 @@ var progtable = [x86.ALAST & obj.AMask]obj.ProgInfo{
x86.ADECL & obj.AMask: {Flags: gc.SizeL | RightRdwr},
x86.ADECQ & obj.AMask: {Flags: gc.SizeQ | RightRdwr},
x86.ADECW & obj.AMask: {Flags: gc.SizeW | RightRdwr},
- x86.ADIVB & obj.AMask: {Flags: gc.SizeB | gc.LeftRead | gc.SetCarry, Reguse: AX, Regset: AX},
- x86.ADIVL & obj.AMask: {Flags: gc.SizeL | gc.LeftRead | gc.SetCarry, Reguse: AX | DX, Regset: AX | DX},
- x86.ADIVQ & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.SetCarry, Reguse: AX | DX, Regset: AX | DX},
- x86.ADIVW & obj.AMask: {Flags: gc.SizeW | gc.LeftRead | gc.SetCarry, Reguse: AX | DX, Regset: AX | DX},
+ x86.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, Reguse: AX, Regset: AX},
- x86.AIDIVL & obj.AMask: {Flags: gc.SizeL | gc.LeftRead | gc.SetCarry, Reguse: AX | DX, Regset: AX | DX},
- x86.AIDIVQ & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.SetCarry, Reguse: AX | DX, Regset: AX | DX},
- x86.AIDIVW & obj.AMask: {Flags: gc.SizeW | gc.LeftRead | gc.SetCarry, Reguse: AX | DX, Regset: AX | DX},
- x86.AIMULB & obj.AMask: {Flags: gc.SizeB | gc.LeftRead | gc.SetCarry, Reguse: AX, Regset: AX},
+ x86.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},
@@ -136,6 +137,7 @@ var progtable = [x86.ALAST & obj.AMask]obj.ProgInfo{
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},
@@ -154,20 +156,20 @@ var progtable = [x86.ALAST & obj.AMask]obj.ProgInfo{
x86.AMOVQ & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Move},
x86.AMOVW & obj.AMask: {Flags: gc.SizeW | gc.LeftRead | gc.RightWrite | gc.Move},
x86.AMOVUPS & obj.AMask: {Flags: gc.LeftRead | gc.RightWrite | gc.Move},
- x86.AMOVSB & obj.AMask: {Flags: gc.OK, Reguse: DI | SI, Regset: DI | SI},
- x86.AMOVSL & obj.AMask: {Flags: gc.OK, Reguse: DI | SI, Regset: DI | SI},
- x86.AMOVSQ & obj.AMask: {Flags: gc.OK, Reguse: DI | SI, Regset: DI | SI},
- x86.AMOVSW & obj.AMask: {Flags: gc.OK, Reguse: DI | SI, Regset: DI | SI},
- obj.ADUFFCOPY & obj.AMask: {Flags: gc.OK, Reguse: DI | SI, Regset: DI | SI | X0},
+ x86.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, Reguse: AX, Regset: AX},
- x86.AMULL & obj.AMask: {Flags: gc.SizeL | gc.LeftRead | gc.SetCarry, Reguse: AX, Regset: AX | DX},
- x86.AMULQ & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.SetCarry, Reguse: AX, Regset: AX | DX},
- x86.AMULW & obj.AMask: {Flags: gc.SizeW | gc.LeftRead | gc.SetCarry, Reguse: AX, Regset: AX | DX},
+ x86.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},
@@ -193,8 +195,8 @@ var progtable = [x86.ALAST & obj.AMask]obj.ProgInfo{
x86.ARCRL & obj.AMask: {Flags: gc.SizeL | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry | gc.UseCarry},
x86.ARCRQ & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry | gc.UseCarry},
x86.ARCRW & obj.AMask: {Flags: gc.SizeW | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry | gc.UseCarry},
- x86.AREP & obj.AMask: {Flags: gc.OK, Reguse: CX, Regset: CX},
- x86.AREPN & obj.AMask: {Flags: gc.OK, Reguse: CX, Regset: CX},
+ 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},
@@ -241,11 +243,11 @@ var progtable = [x86.ALAST & obj.AMask]obj.ProgInfo{
x86.ASHRQ & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry},
x86.ASHRW & obj.AMask: {Flags: gc.SizeW | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry},
x86.ASQRTSD & obj.AMask: {Flags: gc.SizeD | gc.LeftRead | RightRdwr},
- x86.ASTOSB & obj.AMask: {Flags: gc.OK, Reguse: AX | DI, Regset: DI},
- x86.ASTOSL & obj.AMask: {Flags: gc.OK, Reguse: AX | DI, Regset: DI},
- x86.ASTOSQ & obj.AMask: {Flags: gc.OK, Reguse: AX | DI, Regset: DI},
- x86.ASTOSW & obj.AMask: {Flags: gc.OK, Reguse: AX | DI, Regset: DI},
- obj.ADUFFZERO & obj.AMask: {Flags: gc.OK, Reguse: X0 | DI, Regset: DI},
+ x86.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},
@@ -258,6 +260,8 @@ var progtable = [x86.ALAST & obj.AMask]obj.ProgInfo{
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},
@@ -269,61 +273,15 @@ var progtable = [x86.ALAST & obj.AMask]obj.ProgInfo{
x86.AXORPS & obj.AMask: {Flags: gc.LeftRead | RightRdwr},
}
-func progflags(p *obj.Prog) uint32 {
- flags := progtable[p.As&obj.AMask].Flags
- if flags&gc.ImulAXDX != 0 && p.To.Type != obj.TYPE_NONE {
- flags |= RightRdwr
- }
- return flags
-}
-
-func progcarryflags(p *obj.Prog) uint32 {
- return progtable[p.As&obj.AMask].Flags
-}
-
-func proginfo(p *obj.Prog) {
- info := &p.Info
- *info = progtable[p.As&obj.AMask]
+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.ShiftCX != 0) && p.From.Type != obj.TYPE_CONST {
- info.Reguse |= CX
- }
-
- if info.Flags&gc.ImulAXDX != 0 {
- if p.To.Type == obj.TYPE_NONE {
- info.Reguse |= AX
- info.Regset |= AX | DX
- } else {
- info.Flags |= RightRdwr
- }
+ if info.Flags&gc.ImulAXDX != 0 && p.To.Type != obj.TYPE_NONE {
+ info.Flags |= RightRdwr
}
- // Addressing makes some registers used.
- if p.From.Type == obj.TYPE_MEM && p.From.Name == obj.NAME_NONE {
- info.Regindex |= RtoB(int(p.From.Reg))
- }
- if p.From.Index != x86.REG_NONE {
- info.Regindex |= RtoB(int(p.From.Index))
- }
- if p.To.Type == obj.TYPE_MEM && p.To.Name == obj.NAME_NONE {
- info.Regindex |= RtoB(int(p.To.Reg))
- }
- if p.To.Index != x86.REG_NONE {
- info.Regindex |= RtoB(int(p.To.Index))
- }
- if gc.Ctxt.Flag_dynlink {
- // When -dynlink is passed, many operations on external names (and
- // also calling duffzero/duffcopy) use R15 as a scratch register.
- if p.As == x86.ALEAQ || info.Flags == gc.Pseudo || p.As == obj.ACALL || p.As == obj.ARET || p.As == obj.AJMP {
- return
- }
- if p.As == obj.ADUFFZERO || p.As == obj.ADUFFCOPY || (p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local) || (p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local) {
- info.Reguse |= R15
- info.Regset |= R15
- return
- }
- }
+ return info
}
diff --git a/src/cmd/compile/internal/amd64/reg.go b/src/cmd/compile/internal/amd64/reg.go
deleted file mode 100644
index 77720c8..0000000
--- a/src/cmd/compile/internal/amd64/reg.go
+++ /dev/null
@@ -1,152 +0,0 @@
-// Derived from Inferno utils/6c/reg.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6c/reg.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth at terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth at terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// Portions Copyright © 2009 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-package amd64
-
-import (
- "cmd/compile/internal/gc"
- "cmd/internal/obj/x86"
-)
-
-const (
- NREGVAR = 32
-)
-
-var regname = []string{
- ".AX",
- ".CX",
- ".DX",
- ".BX",
- ".SP",
- ".BP",
- ".SI",
- ".DI",
- ".R8",
- ".R9",
- ".R10",
- ".R11",
- ".R12",
- ".R13",
- ".R14",
- ".R15",
- ".X0",
- ".X1",
- ".X2",
- ".X3",
- ".X4",
- ".X5",
- ".X6",
- ".X7",
- ".X8",
- ".X9",
- ".X10",
- ".X11",
- ".X12",
- ".X13",
- ".X14",
- ".X15",
-}
-
-func regnames(n *int) []string {
- *n = NREGVAR
- return regname
-}
-
-func excludedregs() uint64 {
- return RtoB(x86.REG_SP)
-}
-
-func doregbits(r int) uint64 {
- b := uint64(0)
- if r >= x86.REG_AX && r <= x86.REG_R15 {
- b |= RtoB(r)
- } else if r >= x86.REG_AL && r <= x86.REG_R15B {
- b |= RtoB(r - x86.REG_AL + x86.REG_AX)
- } else if r >= x86.REG_AH && r <= x86.REG_BH {
- b |= RtoB(r - x86.REG_AH + x86.REG_AX)
- } else if r >= x86.REG_X0 && r <= x86.REG_X0+15 {
- b |= FtoB(r)
- }
- return b
-}
-
-// For ProgInfo.
-const (
- AX = 1 << (x86.REG_AX - x86.REG_AX)
- BX = 1 << (x86.REG_BX - x86.REG_AX)
- CX = 1 << (x86.REG_CX - x86.REG_AX)
- DX = 1 << (x86.REG_DX - x86.REG_AX)
- DI = 1 << (x86.REG_DI - x86.REG_AX)
- SI = 1 << (x86.REG_SI - x86.REG_AX)
- R15 = 1 << (x86.REG_R15 - x86.REG_AX)
- X0 = 1 << 16
-)
-
-func RtoB(r int) uint64 {
- if r < x86.REG_AX || r > x86.REG_R15 {
- return 0
- }
- return 1 << uint(r-x86.REG_AX)
-}
-
-func BtoR(b uint64) int {
- b &= 0xffff
- if gc.Nacl {
- b &^= (1<<(x86.REG_BP-x86.REG_AX) | 1<<(x86.REG_R15-x86.REG_AX))
- } else if gc.Ctxt.Framepointer_enabled {
- // BP is part of the calling convention if framepointer_enabled.
- b &^= (1 << (x86.REG_BP - x86.REG_AX))
- }
- if b == 0 {
- return 0
- }
- return gc.Bitno(b) + x86.REG_AX
-}
-
-/*
- * bit reg
- * 16 X0
- * ...
- * 31 X15
- */
-func FtoB(f int) uint64 {
- if f < x86.REG_X0 || f > x86.REG_X15 {
- return 0
- }
- return 1 << uint(f-x86.REG_X0+16)
-}
-
-func BtoF(b uint64) int {
- b &= 0xFFFF0000
- if b == 0 {
- return 0
- }
- return gc.Bitno(b) - 16 + x86.REG_X0
-}
diff --git a/src/cmd/compile/internal/amd64/ssa.go b/src/cmd/compile/internal/amd64/ssa.go
index 0350c29..3c997f2 100644
--- a/src/cmd/compile/internal/amd64/ssa.go
+++ b/src/cmd/compile/internal/amd64/ssa.go
@@ -14,46 +14,6 @@ import (
"cmd/internal/obj/x86"
)
-// Smallest possible faulting page at address zero.
-const minZeroPage = 4096
-
-// ssaRegToReg maps ssa register numbers to obj register numbers.
-var ssaRegToReg = []int16{
- x86.REG_AX,
- x86.REG_CX,
- x86.REG_DX,
- x86.REG_BX,
- x86.REG_SP,
- x86.REG_BP,
- x86.REG_SI,
- x86.REG_DI,
- x86.REG_R8,
- x86.REG_R9,
- x86.REG_R10,
- x86.REG_R11,
- x86.REG_R12,
- x86.REG_R13,
- x86.REG_R14,
- x86.REG_R15,
- x86.REG_X0,
- x86.REG_X1,
- x86.REG_X2,
- x86.REG_X3,
- x86.REG_X4,
- x86.REG_X5,
- x86.REG_X6,
- x86.REG_X7,
- x86.REG_X8,
- x86.REG_X9,
- x86.REG_X10,
- x86.REG_X11,
- x86.REG_X12,
- x86.REG_X13,
- x86.REG_X14,
- x86.REG_X15,
- 0, // SB isn't a real register. We fill an Addr.Reg field with 0 in this case.
-}
-
// markMoves marks any MOVXconst ops that need to avoid clobbering flags.
func ssaMarkMoves(s *gc.SSAGenState, b *ssa.Block) {
flive := b.FlagsLiveAtEnd
@@ -190,9 +150,9 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
s.SetLineno(v.Line)
switch v.Op {
case ssa.OpAMD64ADDQ, ssa.OpAMD64ADDL:
- r := gc.SSARegNum(v)
- r1 := gc.SSARegNum(v.Args[0])
- r2 := gc.SSARegNum(v.Args[1])
+ r := v.Reg()
+ r1 := v.Args[0].Reg()
+ r2 := v.Args[1].Reg()
switch {
case r == r1:
p := gc.Prog(v.Op.Asm())
@@ -233,95 +193,93 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
ssa.OpAMD64ADDSS, ssa.OpAMD64ADDSD, ssa.OpAMD64SUBSS, ssa.OpAMD64SUBSD,
ssa.OpAMD64MULSS, ssa.OpAMD64MULSD, ssa.OpAMD64DIVSS, ssa.OpAMD64DIVSD,
ssa.OpAMD64PXOR:
- r := gc.SSARegNum(v)
- if r != gc.SSARegNum(v.Args[0]) {
+ r := v.Reg()
+ if r != v.Args[0].Reg() {
v.Fatalf("input[0] and output not in same register %s", v.LongString())
}
- opregreg(v.Op.Asm(), r, gc.SSARegNum(v.Args[1]))
-
- case ssa.OpAMD64DIVQ, ssa.OpAMD64DIVL, ssa.OpAMD64DIVW,
- ssa.OpAMD64DIVQU, ssa.OpAMD64DIVLU, ssa.OpAMD64DIVWU,
- ssa.OpAMD64MODQ, ssa.OpAMD64MODL, ssa.OpAMD64MODW,
- ssa.OpAMD64MODQU, ssa.OpAMD64MODLU, ssa.OpAMD64MODWU:
-
- // Arg[0] is already in AX as it's the only register we allow
- // and AX is the only output
- x := gc.SSARegNum(v.Args[1])
+ opregreg(v.Op.Asm(), r, v.Args[1].Reg())
- // CPU faults upon signed overflow, which occurs when most
- // negative int is divided by -1.
- var j *obj.Prog
- if v.Op == ssa.OpAMD64DIVQ || v.Op == ssa.OpAMD64DIVL ||
- v.Op == ssa.OpAMD64DIVW || v.Op == ssa.OpAMD64MODQ ||
- v.Op == ssa.OpAMD64MODL || v.Op == ssa.OpAMD64MODW {
+ case ssa.OpAMD64DIVQU, ssa.OpAMD64DIVLU, ssa.OpAMD64DIVWU:
+ // Arg[0] (the dividend) is in AX.
+ // Arg[1] (the divisor) can be in any other register.
+ // Result[0] (the quotient) is in AX.
+ // Result[1] (the remainder) is in DX.
+ r := v.Args[1].Reg()
- var c *obj.Prog
- switch v.Op {
- case ssa.OpAMD64DIVQ, ssa.OpAMD64MODQ:
- c = gc.Prog(x86.ACMPQ)
- j = gc.Prog(x86.AJEQ)
- // go ahead and sign extend to save doing it later
- gc.Prog(x86.ACQO)
+ // Zero extend dividend.
+ c := gc.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
- case ssa.OpAMD64DIVL, ssa.OpAMD64MODL:
- c = gc.Prog(x86.ACMPL)
- j = gc.Prog(x86.AJEQ)
- gc.Prog(x86.ACDQ)
-
- case ssa.OpAMD64DIVW, ssa.OpAMD64MODW:
- c = gc.Prog(x86.ACMPW)
- j = gc.Prog(x86.AJEQ)
- gc.Prog(x86.ACWD)
- }
- c.From.Type = obj.TYPE_REG
- c.From.Reg = x
- c.To.Type = obj.TYPE_CONST
- c.To.Offset = -1
+ // Issue divide.
+ p := gc.Prog(v.Op.Asm())
+ p.From.Type = obj.TYPE_REG
+ p.From.Reg = r
- j.To.Type = obj.TYPE_BRANCH
+ case ssa.OpAMD64DIVQ, ssa.OpAMD64DIVL, ssa.OpAMD64DIVW:
+ // Arg[0] (the dividend) is in AX.
+ // Arg[1] (the divisor) can be in any other register.
+ // Result[0] (the quotient) is in AX.
+ // Result[1] (the remainder) is in DX.
+ r := v.Args[1].Reg()
+ // CPU faults upon signed overflow, which occurs when the most
+ // negative int is divided by -1. Handle divide by -1 as a special case.
+ var c *obj.Prog
+ switch v.Op {
+ case ssa.OpAMD64DIVQ:
+ c = gc.Prog(x86.ACMPQ)
+ case ssa.OpAMD64DIVL:
+ c = gc.Prog(x86.ACMPL)
+ case ssa.OpAMD64DIVW:
+ c = gc.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.To.Type = obj.TYPE_BRANCH
- // for unsigned ints, we sign extend by setting DX = 0
- // signed ints were sign extended above
- if v.Op == ssa.OpAMD64DIVQU || v.Op == ssa.OpAMD64MODQU ||
- v.Op == ssa.OpAMD64DIVLU || v.Op == ssa.OpAMD64MODLU ||
- v.Op == ssa.OpAMD64DIVWU || v.Op == ssa.OpAMD64MODWU {
- c := gc.Prog(x86.AXORQ)
- c.From.Type = obj.TYPE_REG
- c.From.Reg = x86.REG_DX
- c.To.Type = obj.TYPE_REG
- c.To.Reg = x86.REG_DX
+ // Sign extend dividend.
+ switch v.Op {
+ case ssa.OpAMD64DIVQ:
+ gc.Prog(x86.ACQO)
+ case ssa.OpAMD64DIVL:
+ gc.Prog(x86.ACDQ)
+ case ssa.OpAMD64DIVW:
+ gc.Prog(x86.ACWD)
}
+ // Issue divide.
p := gc.Prog(v.Op.Asm())
p.From.Type = obj.TYPE_REG
- p.From.Reg = x
+ p.From.Reg = r
- // signed division, rest of the check for -1 case
- if j != nil {
- j2 := gc.Prog(obj.AJMP)
- j2.To.Type = obj.TYPE_BRANCH
+ // Skip over -1 fixup code.
+ j2 := gc.Prog(obj.AJMP)
+ j2.To.Type = obj.TYPE_BRANCH
- var n *obj.Prog
- if v.Op == ssa.OpAMD64DIVQ || v.Op == ssa.OpAMD64DIVL ||
- v.Op == ssa.OpAMD64DIVW {
- // n * -1 = -n
- n = gc.Prog(x86.ANEGQ)
- n.To.Type = obj.TYPE_REG
- n.To.Reg = x86.REG_AX
- } else {
- // n % -1 == 0
- n = gc.Prog(x86.AXORQ)
- n.From.Type = obj.TYPE_REG
- n.From.Reg = x86.REG_DX
- n.To.Type = obj.TYPE_REG
- n.To.Reg = x86.REG_DX
- }
+ // Issue -1 fixup code.
+ // n / -1 = -n
+ n1 := gc.Prog(x86.ANEGQ)
+ n1.To.Type = obj.TYPE_REG
+ n1.To.Reg = x86.REG_AX
- j.To.Val = n
- j2.To.Val = s.Pc()
- }
+ // n % -1 == 0
+ n2 := gc.Prog(x86.AXORL)
+ n2.From.Type = obj.TYPE_REG
+ n2.From.Reg = x86.REG_DX
+ n2.To.Type = obj.TYPE_REG
+ n2.To.Reg = x86.REG_DX
+
+ // TODO(khr): issue only the -1 fixup code we need.
+ // For instance, if only the quotient is used, no point in zeroing the remainder.
+
+ 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:
@@ -333,7 +291,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
// and DX is the only output we care about (the high bits)
p := gc.Prog(v.Op.Asm())
p.From.Type = obj.TYPE_REG
- p.From.Reg = gc.SSARegNum(v.Args[1])
+ p.From.Reg = v.Args[1].Reg()
// IMULB puts the high portion in AH instead of DL,
// so move it to DL for consistency
@@ -345,19 +303,33 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
m.To.Reg = x86.REG_DX
}
+ 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.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.From.Type = obj.TYPE_REG
+ p.From.Reg = v.Args[2].Reg()
+
case ssa.OpAMD64AVGQU:
// compute (x+y)/2 unsigned.
// Do a 64-bit add, the overflow goes into the carry.
// Shift right once and pull the carry back into the 63rd bit.
- r := gc.SSARegNum(v)
- if r != gc.SSARegNum(v.Args[0]) {
+ r := v.Reg()
+ 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.From.Type = obj.TYPE_REG
p.To.Type = obj.TYPE_REG
p.To.Reg = r
- p.From.Reg = gc.SSARegNum(v.Args[1])
+ p.From.Reg = v.Args[1].Reg()
p = gc.Prog(x86.ARCRQ)
p.From.Type = obj.TYPE_CONST
p.From.Offset = 1
@@ -365,8 +337,8 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
p.To.Reg = r
case ssa.OpAMD64ADDQconst, ssa.OpAMD64ADDLconst:
- r := gc.SSARegNum(v)
- a := gc.SSARegNum(v.Args[0])
+ r := v.Reg()
+ a := v.Args[0].Reg()
if r == a {
if v.AuxInt == 1 {
var asm obj.As
@@ -417,29 +389,20 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
p.To.Type = obj.TYPE_REG
p.To.Reg = r
- case ssa.OpAMD64CMOVQEQconst, ssa.OpAMD64CMOVLEQconst, ssa.OpAMD64CMOVWEQconst,
- ssa.OpAMD64CMOVQNEconst, ssa.OpAMD64CMOVLNEconst, ssa.OpAMD64CMOVWNEconst:
- r := gc.SSARegNum(v)
- if r != gc.SSARegNum(v.Args[0]) {
+ case ssa.OpAMD64CMOVQEQ, ssa.OpAMD64CMOVLEQ:
+ r := v.Reg()
+ if r != v.Args[0].Reg() {
v.Fatalf("input[0] and output not in same register %s", v.LongString())
}
-
- // Constant into AX
- p := gc.Prog(moveByType(v.Type))
- p.From.Type = obj.TYPE_CONST
- p.From.Offset = v.AuxInt
- p.To.Type = obj.TYPE_REG
- p.To.Reg = x86.REG_AX
-
- p = gc.Prog(v.Op.Asm())
+ p := gc.Prog(v.Op.Asm())
p.From.Type = obj.TYPE_REG
- p.From.Reg = x86.REG_AX
+ p.From.Reg = v.Args[1].Reg()
p.To.Type = obj.TYPE_REG
p.To.Reg = r
case ssa.OpAMD64MULQconst, ssa.OpAMD64MULLconst:
- r := gc.SSARegNum(v)
- if r != gc.SSARegNum(v.Args[0]) {
+ r := v.Reg()
+ 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())
@@ -451,7 +414,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
// then we don't need to use resultInArg0 for these ops.
//p.From3 = new(obj.Addr)
//p.From3.Type = obj.TYPE_REG
- //p.From3.Reg = gc.SSARegNum(v.Args[0])
+ //p.From3.Reg = v.Args[0].Reg()
case ssa.OpAMD64SUBQconst, ssa.OpAMD64SUBLconst,
ssa.OpAMD64ANDQconst, ssa.OpAMD64ANDLconst,
@@ -461,8 +424,8 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
ssa.OpAMD64SHRQconst, ssa.OpAMD64SHRLconst, ssa.OpAMD64SHRWconst, ssa.OpAMD64SHRBconst,
ssa.OpAMD64SARQconst, ssa.OpAMD64SARLconst, ssa.OpAMD64SARWconst, ssa.OpAMD64SARBconst,
ssa.OpAMD64ROLQconst, ssa.OpAMD64ROLLconst, ssa.OpAMD64ROLWconst, ssa.OpAMD64ROLBconst:
- r := gc.SSARegNum(v)
- if r != gc.SSARegNum(v.Args[0]) {
+ r := v.Reg()
+ 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())
@@ -471,15 +434,15 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
p.To.Type = obj.TYPE_REG
p.To.Reg = r
case ssa.OpAMD64SBBQcarrymask, ssa.OpAMD64SBBLcarrymask:
- r := gc.SSARegNum(v)
+ r := v.Reg()
p := gc.Prog(v.Op.Asm())
p.From.Type = obj.TYPE_REG
p.From.Reg = r
p.To.Type = obj.TYPE_REG
p.To.Reg = r
case ssa.OpAMD64LEAQ1, ssa.OpAMD64LEAQ2, ssa.OpAMD64LEAQ4, ssa.OpAMD64LEAQ8:
- r := gc.SSARegNum(v.Args[0])
- i := gc.SSARegNum(v.Args[1])
+ r := v.Args[0].Reg()
+ i := v.Args[1].Reg()
p := gc.Prog(x86.ALEAQ)
switch v.Op {
case ssa.OpAMD64LEAQ1:
@@ -499,25 +462,25 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
p.From.Index = i
gc.AddAux(&p.From, v)
p.To.Type = obj.TYPE_REG
- p.To.Reg = gc.SSARegNum(v)
- case ssa.OpAMD64LEAQ:
- p := gc.Prog(x86.ALEAQ)
+ p.To.Reg = v.Reg()
+ case ssa.OpAMD64LEAQ, ssa.OpAMD64LEAL:
+ p := gc.Prog(v.Op.Asm())
p.From.Type = obj.TYPE_MEM
- p.From.Reg = gc.SSARegNum(v.Args[0])
+ p.From.Reg = v.Args[0].Reg()
gc.AddAux(&p.From, v)
p.To.Type = obj.TYPE_REG
- p.To.Reg = gc.SSARegNum(v)
+ 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(), gc.SSARegNum(v.Args[1]), gc.SSARegNum(v.Args[0]))
+ opregreg(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(), gc.SSARegNum(v.Args[0]), gc.SSARegNum(v.Args[1]))
+ opregreg(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.From.Type = obj.TYPE_REG
- p.From.Reg = gc.SSARegNum(v.Args[0])
+ 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:
@@ -525,9 +488,9 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
p.From.Type = obj.TYPE_CONST
p.From.Offset = v.AuxInt
p.To.Type = obj.TYPE_REG
- p.To.Reg = gc.SSARegNum(v.Args[0])
+ p.To.Reg = v.Args[0].Reg()
case ssa.OpAMD64MOVLconst, ssa.OpAMD64MOVQconst:
- x := gc.SSARegNum(v)
+ x := v.Reg()
p := gc.Prog(v.Op.Asm())
p.From.Type = obj.TYPE_CONST
p.From.Offset = v.AuxInt
@@ -539,7 +502,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
p.Mark |= x86.PRESERVEFLAGS
}
case ssa.OpAMD64MOVSSconst, ssa.OpAMD64MOVSDconst:
- x := gc.SSARegNum(v)
+ x := v.Reg()
p := gc.Prog(v.Op.Asm())
p.From.Type = obj.TYPE_FCONST
p.From.Val = math.Float64frombits(uint64(v.AuxInt))
@@ -548,40 +511,40 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
case ssa.OpAMD64MOVQload, ssa.OpAMD64MOVSSload, ssa.OpAMD64MOVSDload, ssa.OpAMD64MOVLload, ssa.OpAMD64MOVWload, ssa.OpAMD64MOVBload, ssa.OpAMD64MOVBQSXload, ssa.OpAMD64MOVWQSXload, ssa.OpAMD64MOVLQSXload, ssa.OpAMD64MOVOload:
p := gc.Prog(v.Op.Asm())
p.From.Type = obj.TYPE_MEM
- p.From.Reg = gc.SSARegNum(v.Args[0])
+ p.From.Reg = v.Args[0].Reg()
gc.AddAux(&p.From, v)
p.To.Type = obj.TYPE_REG
- p.To.Reg = gc.SSARegNum(v)
+ p.To.Reg = v.Reg()
case ssa.OpAMD64MOVQloadidx8, ssa.OpAMD64MOVSDloadidx8:
p := gc.Prog(v.Op.Asm())
p.From.Type = obj.TYPE_MEM
- p.From.Reg = gc.SSARegNum(v.Args[0])
+ p.From.Reg = v.Args[0].Reg()
gc.AddAux(&p.From, v)
p.From.Scale = 8
- p.From.Index = gc.SSARegNum(v.Args[1])
+ p.From.Index = v.Args[1].Reg()
p.To.Type = obj.TYPE_REG
- p.To.Reg = gc.SSARegNum(v)
+ p.To.Reg = v.Reg()
case ssa.OpAMD64MOVLloadidx4, ssa.OpAMD64MOVSSloadidx4:
p := gc.Prog(v.Op.Asm())
p.From.Type = obj.TYPE_MEM
- p.From.Reg = gc.SSARegNum(v.Args[0])
+ p.From.Reg = v.Args[0].Reg()
gc.AddAux(&p.From, v)
p.From.Scale = 4
- p.From.Index = gc.SSARegNum(v.Args[1])
+ p.From.Index = v.Args[1].Reg()
p.To.Type = obj.TYPE_REG
- p.To.Reg = gc.SSARegNum(v)
+ p.To.Reg = v.Reg()
case ssa.OpAMD64MOVWloadidx2:
p := gc.Prog(v.Op.Asm())
p.From.Type = obj.TYPE_MEM
- p.From.Reg = gc.SSARegNum(v.Args[0])
+ p.From.Reg = v.Args[0].Reg()
gc.AddAux(&p.From, v)
p.From.Scale = 2
- p.From.Index = gc.SSARegNum(v.Args[1])
+ p.From.Index = v.Args[1].Reg()
p.To.Type = obj.TYPE_REG
- p.To.Reg = gc.SSARegNum(v)
+ p.To.Reg = v.Reg()
case ssa.OpAMD64MOVBloadidx1, ssa.OpAMD64MOVWloadidx1, ssa.OpAMD64MOVLloadidx1, ssa.OpAMD64MOVQloadidx1, ssa.OpAMD64MOVSSloadidx1, ssa.OpAMD64MOVSDloadidx1:
- r := gc.SSARegNum(v.Args[0])
- i := gc.SSARegNum(v.Args[1])
+ r := v.Args[0].Reg()
+ i := v.Args[1].Reg()
if i == x86.REG_SP {
r, i = i, r
}
@@ -592,50 +555,50 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
p.From.Index = i
gc.AddAux(&p.From, v)
p.To.Type = obj.TYPE_REG
- p.To.Reg = gc.SSARegNum(v)
+ 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.From.Type = obj.TYPE_REG
- p.From.Reg = gc.SSARegNum(v.Args[1])
+ p.From.Reg = v.Args[1].Reg()
p.To.Type = obj.TYPE_MEM
- p.To.Reg = gc.SSARegNum(v.Args[0])
+ p.To.Reg = v.Args[0].Reg()
gc.AddAux(&p.To, v)
case ssa.OpAMD64MOVQstoreidx8, ssa.OpAMD64MOVSDstoreidx8:
p := gc.Prog(v.Op.Asm())
p.From.Type = obj.TYPE_REG
- p.From.Reg = gc.SSARegNum(v.Args[2])
+ p.From.Reg = v.Args[2].Reg()
p.To.Type = obj.TYPE_MEM
- p.To.Reg = gc.SSARegNum(v.Args[0])
+ p.To.Reg = v.Args[0].Reg()
p.To.Scale = 8
- p.To.Index = gc.SSARegNum(v.Args[1])
+ p.To.Index = v.Args[1].Reg()
gc.AddAux(&p.To, v)
case ssa.OpAMD64MOVSSstoreidx4, ssa.OpAMD64MOVLstoreidx4:
p := gc.Prog(v.Op.Asm())
p.From.Type = obj.TYPE_REG
- p.From.Reg = gc.SSARegNum(v.Args[2])
+ p.From.Reg = v.Args[2].Reg()
p.To.Type = obj.TYPE_MEM
- p.To.Reg = gc.SSARegNum(v.Args[0])
+ p.To.Reg = v.Args[0].Reg()
p.To.Scale = 4
- p.To.Index = gc.SSARegNum(v.Args[1])
+ p.To.Index = v.Args[1].Reg()
gc.AddAux(&p.To, v)
case ssa.OpAMD64MOVWstoreidx2:
p := gc.Prog(v.Op.Asm())
p.From.Type = obj.TYPE_REG
- p.From.Reg = gc.SSARegNum(v.Args[2])
+ p.From.Reg = v.Args[2].Reg()
p.To.Type = obj.TYPE_MEM
- p.To.Reg = gc.SSARegNum(v.Args[0])
+ p.To.Reg = v.Args[0].Reg()
p.To.Scale = 2
- p.To.Index = gc.SSARegNum(v.Args[1])
+ p.To.Index = v.Args[1].Reg()
gc.AddAux(&p.To, v)
case ssa.OpAMD64MOVBstoreidx1, ssa.OpAMD64MOVWstoreidx1, ssa.OpAMD64MOVLstoreidx1, ssa.OpAMD64MOVQstoreidx1, ssa.OpAMD64MOVSSstoreidx1, ssa.OpAMD64MOVSDstoreidx1:
- r := gc.SSARegNum(v.Args[0])
- i := gc.SSARegNum(v.Args[1])
+ r := v.Args[0].Reg()
+ i := v.Args[1].Reg()
if i == x86.REG_SP {
r, i = i, r
}
p := gc.Prog(v.Op.Asm())
p.From.Type = obj.TYPE_REG
- p.From.Reg = gc.SSARegNum(v.Args[2])
+ p.From.Reg = v.Args[2].Reg()
p.To.Type = obj.TYPE_MEM
p.To.Reg = r
p.To.Scale = 1
@@ -647,15 +610,15 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
sc := v.AuxValAndOff()
p.From.Offset = sc.Val()
p.To.Type = obj.TYPE_MEM
- p.To.Reg = gc.SSARegNum(v.Args[0])
+ 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.From.Type = obj.TYPE_CONST
sc := v.AuxValAndOff()
p.From.Offset = sc.Val()
- r := gc.SSARegNum(v.Args[0])
- i := gc.SSARegNum(v.Args[1])
+ r := v.Args[0].Reg()
+ i := v.Args[1].Reg()
switch v.Op {
case ssa.OpAMD64MOVBstoreconstidx1, ssa.OpAMD64MOVWstoreconstidx1, ssa.OpAMD64MOVLstoreconstidx1, ssa.OpAMD64MOVQstoreconstidx1:
p.To.Scale = 1
@@ -674,10 +637,14 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
p.To.Index = i
gc.AddAux2(&p.To, v, sc.Off())
case ssa.OpAMD64MOVLQSX, ssa.OpAMD64MOVWQSX, ssa.OpAMD64MOVBQSX, ssa.OpAMD64MOVLQZX, ssa.OpAMD64MOVWQZX, ssa.OpAMD64MOVBQZX,
- ssa.OpAMD64CVTSL2SS, ssa.OpAMD64CVTSL2SD, ssa.OpAMD64CVTSQ2SS, ssa.OpAMD64CVTSQ2SD,
ssa.OpAMD64CVTTSS2SL, ssa.OpAMD64CVTTSD2SL, ssa.OpAMD64CVTTSS2SQ, ssa.OpAMD64CVTTSD2SQ,
ssa.OpAMD64CVTSS2SD, ssa.OpAMD64CVTSD2SS:
- opregreg(v.Op.Asm(), gc.SSARegNum(v), gc.SSARegNum(v.Args[0]))
+ opregreg(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())
case ssa.OpAMD64DUFFZERO:
off := duffStart(v.AuxInt)
adj := duffAdj(v.AuxInt)
@@ -695,9 +662,9 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
p.To.Offset = off
case ssa.OpAMD64MOVOconst:
if v.AuxInt != 0 {
- v.Unimplementedf("MOVOconst can only do constant=0")
+ v.Fatalf("MOVOconst can only do constant=0")
}
- r := gc.SSARegNum(v)
+ r := v.Reg()
opregreg(x86.AXORPS, r, r)
case ssa.OpAMD64DUFFCOPY:
p := gc.Prog(obj.ADUFFCOPY)
@@ -705,78 +672,45 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
p.To.Sym = gc.Linksym(gc.Pkglookup("duffcopy", gc.Runtimepkg))
p.To.Offset = v.AuxInt
- case ssa.OpCopy, ssa.OpAMD64MOVQconvert: // TODO: use MOVQreg for reg->reg copies instead of OpCopy?
+ case ssa.OpCopy, ssa.OpAMD64MOVQconvert, ssa.OpAMD64MOVLconvert: // TODO: use MOVQreg for reg->reg copies instead of OpCopy?
if v.Type.IsMemory() {
return
}
- x := gc.SSARegNum(v.Args[0])
- y := gc.SSARegNum(v)
+ x := v.Args[0].Reg()
+ y := v.Reg()
if x != y {
opregreg(moveByType(v.Type), y, x)
}
case ssa.OpLoadReg:
if v.Type.IsFlags() {
- v.Unimplementedf("load flags not implemented: %v", v.LongString())
+ v.Fatalf("load flags not implemented: %v", v.LongString())
return
}
p := gc.Prog(loadByType(v.Type))
- n, off := gc.AutoVar(v.Args[0])
- p.From.Type = obj.TYPE_MEM
- p.From.Node = n
- p.From.Sym = gc.Linksym(n.Sym)
- p.From.Offset = off
- if n.Class == gc.PPARAM || n.Class == gc.PPARAMOUT {
- p.From.Name = obj.NAME_PARAM
- p.From.Offset += n.Xoffset
- } else {
- p.From.Name = obj.NAME_AUTO
- }
+ gc.AddrAuto(&p.From, v.Args[0])
p.To.Type = obj.TYPE_REG
- p.To.Reg = gc.SSARegNum(v)
+ p.To.Reg = v.Reg()
case ssa.OpStoreReg:
if v.Type.IsFlags() {
- v.Unimplementedf("store flags not implemented: %v", v.LongString())
+ v.Fatalf("store flags not implemented: %v", v.LongString())
return
}
p := gc.Prog(storeByType(v.Type))
p.From.Type = obj.TYPE_REG
- p.From.Reg = gc.SSARegNum(v.Args[0])
- n, off := gc.AutoVar(v)
- p.To.Type = obj.TYPE_MEM
- p.To.Node = n
- p.To.Sym = gc.Linksym(n.Sym)
- p.To.Offset = off
- if n.Class == gc.PPARAM || n.Class == gc.PPARAMOUT {
- p.To.Name = obj.NAME_PARAM
- p.To.Offset += n.Xoffset
- } else {
- p.To.Name = obj.NAME_AUTO
- }
+ p.From.Reg = v.Args[0].Reg()
+ gc.AddrAuto(&p.To, v)
case ssa.OpPhi:
- // just check to make sure regalloc and stackalloc did it right
- if v.Type.IsMemory() {
- return
- }
- f := v.Block.Func
- loc := f.RegAlloc[v.ID]
- for _, a := range v.Args {
- if aloc := f.RegAlloc[a.ID]; aloc != loc { // TODO: .Equal() instead?
- v.Fatalf("phi arg at different location than phi: %v @ %v, but arg %v @ %v\n%s\n", v, loc, a, aloc, v.Block.Func)
- }
- }
+ gc.CheckLoweredPhi(v)
case ssa.OpInitMem:
// memory arg needs no code
case ssa.OpArg:
// input args need no code
case ssa.OpAMD64LoweredGetClosurePtr:
- // Output is hardwired to DX only,
- // and DX contains the closure pointer on
- // closure entry, and this "instruction"
- // is scheduled to the very beginning
- // of the entry block.
+ // Closure pointer is DX.
+ gc.CheckLoweredGetClosurePtr(v)
case ssa.OpAMD64LoweredGetG:
- r := gc.SSARegNum(v)
+ r := v.Reg()
// See the comments in cmd/internal/obj/x86/obj6.go
// near CanUse1InsnTLS for a detailed explanation of these instructions.
if x86.CanUse1InsnTLS(gc.Ctxt) {
@@ -824,7 +758,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
case ssa.OpAMD64CALLclosure:
p := gc.Prog(obj.ACALL)
p.To.Type = obj.TYPE_REG
- p.To.Reg = gc.SSARegNum(v.Args[0])
+ p.To.Reg = v.Args[0].Reg()
if gc.Maxarg < v.AuxInt {
gc.Maxarg = v.AuxInt
}
@@ -847,30 +781,36 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
case ssa.OpAMD64CALLinter:
p := gc.Prog(obj.ACALL)
p.To.Type = obj.TYPE_REG
- p.To.Reg = gc.SSARegNum(v.Args[0])
+ p.To.Reg = v.Args[0].Reg()
if gc.Maxarg < v.AuxInt {
gc.Maxarg = v.AuxInt
}
case ssa.OpAMD64NEGQ, ssa.OpAMD64NEGL,
ssa.OpAMD64BSWAPQ, ssa.OpAMD64BSWAPL,
ssa.OpAMD64NOTQ, ssa.OpAMD64NOTL:
- r := gc.SSARegNum(v)
- if r != gc.SSARegNum(v.Args[0]) {
+ r := v.Reg()
+ 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.To.Type = obj.TYPE_REG
p.To.Reg = r
- case ssa.OpAMD64BSFQ, ssa.OpAMD64BSFL, ssa.OpAMD64BSFW,
- ssa.OpAMD64BSRQ, ssa.OpAMD64BSRL, ssa.OpAMD64BSRW,
- ssa.OpAMD64SQRTSD:
+ case ssa.OpAMD64BSFQ, ssa.OpAMD64BSFL:
+ p := gc.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.From.Type = obj.TYPE_REG
- p.From.Reg = gc.SSARegNum(v.Args[0])
+ p.From.Reg = v.Args[0].Reg()
p.To.Type = obj.TYPE_REG
- p.To.Reg = gc.SSARegNum(v)
+ 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,
@@ -880,32 +820,34 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
ssa.OpAMD64SETA, ssa.OpAMD64SETAE:
p := gc.Prog(v.Op.Asm())
p.To.Type = obj.TYPE_REG
- p.To.Reg = gc.SSARegNum(v)
+ p.To.Reg = v.Reg()
case ssa.OpAMD64SETNEF:
p := gc.Prog(v.Op.Asm())
p.To.Type = obj.TYPE_REG
- p.To.Reg = gc.SSARegNum(v)
+ p.To.Reg = v.Reg()
q := gc.Prog(x86.ASETPS)
q.To.Type = obj.TYPE_REG
q.To.Reg = x86.REG_AX
// ORL avoids partial register write and is smaller than ORQ, used by old compiler
- opregreg(x86.AORL, gc.SSARegNum(v), x86.REG_AX)
+ opregreg(x86.AORL, v.Reg(), x86.REG_AX)
case ssa.OpAMD64SETEQF:
p := gc.Prog(v.Op.Asm())
p.To.Type = obj.TYPE_REG
- p.To.Reg = gc.SSARegNum(v)
+ p.To.Reg = v.Reg()
q := gc.Prog(x86.ASETPC)
q.To.Type = obj.TYPE_REG
q.To.Reg = x86.REG_AX
// ANDL avoids partial register write and is smaller than ANDQ, used by old compiler
- opregreg(x86.AANDL, gc.SSARegNum(v), x86.REG_AX)
+ opregreg(x86.AANDL, v.Reg(), x86.REG_AX)
case ssa.OpAMD64InvertFlags:
v.Fatalf("InvertFlags should never make it to codegen %v", v.LongString())
case ssa.OpAMD64FlagEQ, ssa.OpAMD64FlagLT_ULT, ssa.OpAMD64FlagLT_UGT, ssa.OpAMD64FlagGT_ULT, ssa.OpAMD64FlagGT_UGT:
v.Fatalf("Flag* ops should never make it to codegen %v", v.LongString())
+ case ssa.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)
@@ -919,66 +861,8 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
case ssa.OpVarLive:
gc.Gvarlive(v.Aux.(*gc.Node))
case ssa.OpKeepAlive:
- if !v.Args[0].Type.IsPtrShaped() {
- v.Fatalf("keeping non-pointer alive %v", v.Args[0])
- }
- n, off := gc.AutoVar(v.Args[0])
- if n == nil {
- v.Fatalf("KeepLive with non-spilled value %s %s", v, v.Args[0])
- }
- if off != 0 {
- v.Fatalf("KeepLive with non-zero offset spill location %s:%d", n, off)
- }
- gc.Gvarlive(n)
+ gc.KeepAlive(v)
case ssa.OpAMD64LoweredNilCheck:
- // Optimization - if the subsequent block has a load or store
- // at the same address, we don't need to issue this instruction.
- mem := v.Args[1]
- for _, w := range v.Block.Succs[0].Block().Values {
- if w.Op == ssa.OpPhi {
- if w.Type.IsMemory() {
- mem = w
- }
- continue
- }
- if len(w.Args) == 0 || !w.Args[len(w.Args)-1].Type.IsMemory() {
- // w doesn't use a store - can't be a memory op.
- continue
- }
- if w.Args[len(w.Args)-1] != mem {
- v.Fatalf("wrong store after nilcheck v=%s w=%s", v, w)
- }
- switch w.Op {
- case ssa.OpAMD64MOVQload, ssa.OpAMD64MOVLload, ssa.OpAMD64MOVWload, ssa.OpAMD64MOVBload,
- ssa.OpAMD64MOVQstore, ssa.OpAMD64MOVLstore, ssa.OpAMD64MOVWstore, ssa.OpAMD64MOVBstore,
- ssa.OpAMD64MOVBQSXload, ssa.OpAMD64MOVWQSXload, ssa.OpAMD64MOVLQSXload,
- ssa.OpAMD64MOVSSload, ssa.OpAMD64MOVSDload, ssa.OpAMD64MOVOload,
- ssa.OpAMD64MOVSSstore, ssa.OpAMD64MOVSDstore, ssa.OpAMD64MOVOstore:
- if w.Args[0] == v.Args[0] && w.Aux == nil && w.AuxInt >= 0 && w.AuxInt < minZeroPage {
- if gc.Debug_checknil != 0 && int(v.Line) > 1 {
- gc.Warnl(v.Line, "removed nil check")
- }
- return
- }
- case ssa.OpAMD64MOVQstoreconst, ssa.OpAMD64MOVLstoreconst, ssa.OpAMD64MOVWstoreconst, ssa.OpAMD64MOVBstoreconst:
- off := ssa.ValAndOff(v.AuxInt).Off()
- if w.Args[0] == v.Args[0] && w.Aux == nil && off >= 0 && off < minZeroPage {
- if gc.Debug_checknil != 0 && int(v.Line) > 1 {
- gc.Warnl(v.Line, "removed nil check")
- }
- return
- }
- }
- if w.Type.IsMemory() {
- if w.Op == ssa.OpVarDef || w.Op == ssa.OpVarKill || w.Op == ssa.OpVarLive {
- // these ops are OK
- mem = w
- continue
- }
- // We can't delay the nil check past the next store.
- break
- }
- }
// Issue a load which will fault if the input is nil.
// TODO: We currently use the 2-byte instruction TESTB AX, (reg).
// Should we use the 3-byte TESTB $0, (reg) instead? It is larger
@@ -989,13 +873,65 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
p.From.Type = obj.TYPE_REG
p.From.Reg = x86.REG_AX
p.To.Type = obj.TYPE_MEM
- p.To.Reg = gc.SSARegNum(v.Args[0])
+ 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")
}
+ case ssa.OpAMD64MOVLatomicload, ssa.OpAMD64MOVQatomicload:
+ p := gc.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.OpAMD64XCHGL, ssa.OpAMD64XCHGQ:
+ r := v.Reg0()
+ 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.From.Type = obj.TYPE_REG
+ p.From.Reg = r
+ p.To.Type = obj.TYPE_MEM
+ p.To.Reg = v.Args[1].Reg()
+ gc.AddAux(&p.To, v)
+ case ssa.OpAMD64XADDLlock, ssa.OpAMD64XADDQlock:
+ r := v.Reg0()
+ 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())
+ p.From.Type = obj.TYPE_REG
+ p.From.Reg = r
+ p.To.Type = obj.TYPE_MEM
+ p.To.Reg = v.Args[1].Reg()
+ gc.AddAux(&p.To, v)
+ case ssa.OpAMD64CMPXCHGLlock, ssa.OpAMD64CMPXCHGQlock:
+ 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())
+ 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.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())
+ 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)
default:
- v.Unimplementedf("genValue not implemented: %s", v.LongString())
+ v.Fatalf("genValue not implemented: %s", v.LongString())
}
}
@@ -1029,7 +965,7 @@ func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) {
s.SetLineno(b.Line)
switch b.Kind {
- case ssa.BlockPlain, ssa.BlockCall, ssa.BlockCheck:
+ case ssa.BlockPlain:
if b.Succs[0].Block() != next {
p := gc.Prog(obj.AJMP)
p.To.Type = obj.TYPE_BRANCH
@@ -1109,6 +1045,6 @@ func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) {
}
default:
- b.Unimplementedf("branch not implemented: %s. Control: %s", b.LongString(), b.Control.LongString())
+ b.Fatalf("branch not implemented: %s. Control: %s", b.LongString(), b.Control.LongString())
}
}
diff --git a/src/cmd/compile/internal/arm/cgen.go b/src/cmd/compile/internal/arm/cgen.go
deleted file mode 100644
index c60df08..0000000
--- a/src/cmd/compile/internal/arm/cgen.go
+++ /dev/null
@@ -1,224 +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 arm
-
-import (
- "cmd/compile/internal/gc"
- "cmd/internal/obj"
- "cmd/internal/obj/arm"
-)
-
-/*
- * generate array index into res.
- * n might be any size; res is 32-bit.
- * returns Prog* to patch to panic call.
- */
-func cgenindex(n *gc.Node, res *gc.Node, bounded bool) *obj.Prog {
- if !gc.Is64(n.Type) {
- gc.Cgen(n, res)
- return nil
- }
-
- var tmp gc.Node
- gc.Tempname(&tmp, gc.Types[gc.TINT64])
- gc.Cgen(n, &tmp)
- var lo gc.Node
- var hi gc.Node
- split64(&tmp, &lo, &hi)
- gmove(&lo, res)
- if bounded {
- splitclean()
- return nil
- }
-
- var n1 gc.Node
- gc.Regalloc(&n1, gc.Types[gc.TINT32], nil)
- var n2 gc.Node
- gc.Regalloc(&n2, gc.Types[gc.TINT32], nil)
- var zero gc.Node
- gc.Nodconst(&zero, gc.Types[gc.TINT32], 0)
- gmove(&hi, &n1)
- gmove(&zero, &n2)
- gins(arm.ACMP, &n1, &n2)
- gc.Regfree(&n2)
- gc.Regfree(&n1)
- splitclean()
- return gc.Gbranch(arm.ABNE, nil, -1)
-}
-
-func igenindex(n *gc.Node, res *gc.Node, bounded bool) *obj.Prog {
- gc.Tempname(res, n.Type)
- return cgenindex(n, res, bounded)
-}
-
-func blockcopy(n, res *gc.Node, osrc, odst, w int64) {
- // determine alignment.
- // want to avoid unaligned access, so have to use
- // smaller operations for less aligned types.
- // for example moving [4]byte must use 4 MOVB not 1 MOVW.
- align := int(n.Type.Align)
-
- var op obj.As
- switch align {
- default:
- gc.Fatalf("sgen: invalid alignment %d for %v", align, n.Type)
-
- case 1:
- op = arm.AMOVB
-
- case 2:
- op = arm.AMOVH
-
- case 4:
- op = arm.AMOVW
- }
-
- if w%int64(align) != 0 {
- gc.Fatalf("sgen: unaligned size %d (align=%d) for %v", w, align, n.Type)
- }
- c := int32(w / int64(align))
-
- if osrc%int64(align) != 0 || odst%int64(align) != 0 {
- gc.Fatalf("sgen: unaligned offset src %d or dst %d (align %d)", osrc, odst, align)
- }
-
- // if we are copying forward on the stack and
- // the src and dst overlap, then reverse direction
- dir := align
- if osrc < odst && odst < osrc+w {
- dir = -dir
- }
-
- if op == arm.AMOVW && !gc.Nacl && dir > 0 && c >= 4 && c <= 128 {
- var r0 gc.Node
- r0.Op = gc.OREGISTER
- r0.Reg = arm.REG_R0
- var r1 gc.Node
- r1.Op = gc.OREGISTER
- r1.Reg = arm.REG_R0 + 1
- var r2 gc.Node
- r2.Op = gc.OREGISTER
- r2.Reg = arm.REG_R0 + 2
-
- var src gc.Node
- gc.Regalloc(&src, gc.Types[gc.Tptr], &r1)
- var dst gc.Node
- gc.Regalloc(&dst, gc.Types[gc.Tptr], &r2)
- if n.Ullman >= res.Ullman {
- // eval n first
- gc.Agen(n, &src)
-
- if res.Op == gc.ONAME {
- gc.Gvardef(res)
- }
- gc.Agen(res, &dst)
- } else {
- // eval res first
- if res.Op == gc.ONAME {
- gc.Gvardef(res)
- }
- gc.Agen(res, &dst)
- gc.Agen(n, &src)
- }
-
- var tmp gc.Node
- gc.Regalloc(&tmp, gc.Types[gc.Tptr], &r0)
- f := gc.Sysfunc("duffcopy")
- p := gins(obj.ADUFFCOPY, nil, f)
- gc.Afunclit(&p.To, f)
-
- // 8 and 128 = magic constants: see ../../runtime/asm_arm.s
- p.To.Offset = 8 * (128 - int64(c))
-
- gc.Regfree(&tmp)
- gc.Regfree(&src)
- gc.Regfree(&dst)
- return
- }
-
- var dst gc.Node
- var src gc.Node
- if n.Ullman >= res.Ullman {
- gc.Agenr(n, &dst, res) // temporarily use dst
- gc.Regalloc(&src, gc.Types[gc.Tptr], nil)
- gins(arm.AMOVW, &dst, &src)
- if res.Op == gc.ONAME {
- gc.Gvardef(res)
- }
- gc.Agen(res, &dst)
- } else {
- if res.Op == gc.ONAME {
- gc.Gvardef(res)
- }
- gc.Agenr(res, &dst, res)
- gc.Agenr(n, &src, nil)
- }
-
- var tmp gc.Node
- gc.Regalloc(&tmp, gc.Types[gc.TUINT32], nil)
-
- // set up end marker
- var nend gc.Node
-
- if c >= 4 {
- gc.Regalloc(&nend, gc.Types[gc.TUINT32], nil)
-
- p := gins(arm.AMOVW, &src, &nend)
- p.From.Type = obj.TYPE_ADDR
- if dir < 0 {
- p.From.Offset = int64(dir)
- } else {
- p.From.Offset = w
- }
- }
-
- // move src and dest to the end of block if necessary
- if dir < 0 {
- p := gins(arm.AMOVW, &src, &src)
- p.From.Type = obj.TYPE_ADDR
- p.From.Offset = w + int64(dir)
-
- p = gins(arm.AMOVW, &dst, &dst)
- p.From.Type = obj.TYPE_ADDR
- p.From.Offset = w + int64(dir)
- }
-
- // move
- if c >= 4 {
- p := gins(op, &src, &tmp)
- p.From.Type = obj.TYPE_MEM
- p.From.Offset = int64(dir)
- p.Scond |= arm.C_PBIT
- ploop := p
-
- p = gins(op, &tmp, &dst)
- p.To.Type = obj.TYPE_MEM
- p.To.Offset = int64(dir)
- p.Scond |= arm.C_PBIT
-
- p = gins(arm.ACMP, &src, nil)
- raddr(&nend, p)
-
- gc.Patch(gc.Gbranch(arm.ABNE, nil, 0), ploop)
- gc.Regfree(&nend)
- } else {
- var p *obj.Prog
- for ; c > 0; c-- {
- p = gins(op, &src, &tmp)
- p.From.Type = obj.TYPE_MEM
- p.From.Offset = int64(dir)
- p.Scond |= arm.C_PBIT
-
- p = gins(op, &tmp, &dst)
- p.To.Type = obj.TYPE_MEM
- p.To.Offset = int64(dir)
- p.Scond |= arm.C_PBIT
- }
- }
-
- gc.Regfree(&dst)
- gc.Regfree(&src)
- gc.Regfree(&tmp)
-}
diff --git a/src/cmd/compile/internal/arm/cgen64.go b/src/cmd/compile/internal/arm/cgen64.go
deleted file mode 100644
index 33e8406..0000000
--- a/src/cmd/compile/internal/arm/cgen64.go
+++ /dev/null
@@ -1,859 +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 arm
-
-import (
- "cmd/compile/internal/gc"
- "cmd/internal/obj"
- "cmd/internal/obj/arm"
-)
-
-/*
- * attempt to generate 64-bit
- * res = n
- * return 1 on success, 0 if op not handled.
- */
-func cgen64(n *gc.Node, res *gc.Node) {
- if res.Op != gc.OINDREG && res.Op != gc.ONAME {
- gc.Dump("n", n)
- gc.Dump("res", res)
- gc.Fatalf("cgen64 %v of %v", n.Op, res.Op)
- }
-
- l := n.Left
- var t1 gc.Node
- if !l.Addable {
- gc.Tempname(&t1, l.Type)
- gc.Cgen(l, &t1)
- l = &t1
- }
-
- var hi1 gc.Node
- var lo1 gc.Node
- split64(l, &lo1, &hi1)
- switch n.Op {
- default:
- gc.Fatalf("cgen64 %v", n.Op)
-
- case gc.OMINUS:
- var lo2 gc.Node
- var hi2 gc.Node
- split64(res, &lo2, &hi2)
-
- gc.Regalloc(&t1, lo1.Type, nil)
- var al gc.Node
- gc.Regalloc(&al, lo1.Type, nil)
- var ah gc.Node
- gc.Regalloc(&ah, hi1.Type, nil)
-
- gins(arm.AMOVW, &lo1, &al)
- gins(arm.AMOVW, &hi1, &ah)
-
- gmove(ncon(0), &t1)
- p1 := gins(arm.ASUB, &al, &t1)
- p1.Scond |= arm.C_SBIT
- gins(arm.AMOVW, &t1, &lo2)
-
- gmove(ncon(0), &t1)
- gins(arm.ASBC, &ah, &t1)
- gins(arm.AMOVW, &t1, &hi2)
-
- gc.Regfree(&t1)
- gc.Regfree(&al)
- gc.Regfree(&ah)
- splitclean()
- splitclean()
- return
-
- case gc.OCOM:
- gc.Regalloc(&t1, lo1.Type, nil)
- gmove(ncon(^uint32(0)), &t1)
-
- var lo2 gc.Node
- var hi2 gc.Node
- split64(res, &lo2, &hi2)
- var n1 gc.Node
- gc.Regalloc(&n1, lo1.Type, nil)
-
- gins(arm.AMOVW, &lo1, &n1)
- gins(arm.AEOR, &t1, &n1)
- gins(arm.AMOVW, &n1, &lo2)
-
- gins(arm.AMOVW, &hi1, &n1)
- gins(arm.AEOR, &t1, &n1)
- gins(arm.AMOVW, &n1, &hi2)
-
- gc.Regfree(&t1)
- gc.Regfree(&n1)
- splitclean()
- splitclean()
- return
-
- // binary operators.
- // common setup below.
- case gc.OADD,
- gc.OSUB,
- gc.OMUL,
- gc.OLSH,
- gc.ORSH,
- gc.OAND,
- gc.OOR,
- gc.OXOR,
- gc.OLROT:
- break
- }
-
- // setup for binary operators
- r := n.Right
-
- if r != nil && !r.Addable {
- var t2 gc.Node
- gc.Tempname(&t2, r.Type)
- gc.Cgen(r, &t2)
- r = &t2
- }
-
- var hi2 gc.Node
- var lo2 gc.Node
- if gc.Is64(r.Type) {
- split64(r, &lo2, &hi2)
- }
-
- var al gc.Node
- gc.Regalloc(&al, lo1.Type, nil)
- var ah gc.Node
- gc.Regalloc(&ah, hi1.Type, nil)
-
- // Do op. Leave result in ah:al.
- switch n.Op {
- default:
- gc.Fatalf("cgen64: not implemented: %v\n", n)
-
- // TODO: Constants
- case gc.OADD:
- var bl gc.Node
- gc.Regalloc(&bl, gc.Types[gc.TPTR32], nil)
-
- var bh gc.Node
- gc.Regalloc(&bh, gc.Types[gc.TPTR32], nil)
- gins(arm.AMOVW, &hi1, &ah)
- gins(arm.AMOVW, &lo1, &al)
- gins(arm.AMOVW, &hi2, &bh)
- gins(arm.AMOVW, &lo2, &bl)
- p1 := gins(arm.AADD, &bl, &al)
- p1.Scond |= arm.C_SBIT
- gins(arm.AADC, &bh, &ah)
- gc.Regfree(&bl)
- gc.Regfree(&bh)
-
- // TODO: Constants.
- case gc.OSUB:
- var bl gc.Node
- gc.Regalloc(&bl, gc.Types[gc.TPTR32], nil)
-
- var bh gc.Node
- gc.Regalloc(&bh, gc.Types[gc.TPTR32], nil)
- gins(arm.AMOVW, &lo1, &al)
- gins(arm.AMOVW, &hi1, &ah)
- gins(arm.AMOVW, &lo2, &bl)
- gins(arm.AMOVW, &hi2, &bh)
- p1 := gins(arm.ASUB, &bl, &al)
- p1.Scond |= arm.C_SBIT
- gins(arm.ASBC, &bh, &ah)
- gc.Regfree(&bl)
- gc.Regfree(&bh)
-
- // TODO(kaib): this can be done with 4 regs and does not need 6
- case gc.OMUL:
- var bl gc.Node
- gc.Regalloc(&bl, gc.Types[gc.TPTR32], nil)
-
- var bh gc.Node
- gc.Regalloc(&bh, gc.Types[gc.TPTR32], nil)
- var cl gc.Node
- gc.Regalloc(&cl, gc.Types[gc.TPTR32], nil)
- var ch gc.Node
- gc.Regalloc(&ch, gc.Types[gc.TPTR32], nil)
-
- // load args into bh:bl and bh:bl.
- gins(arm.AMOVW, &hi1, &bh)
-
- gins(arm.AMOVW, &lo1, &bl)
- gins(arm.AMOVW, &hi2, &ch)
- gins(arm.AMOVW, &lo2, &cl)
-
- // bl * cl -> ah al
- p1 := gins(arm.AMULLU, nil, nil)
-
- p1.From.Type = obj.TYPE_REG
- p1.From.Reg = bl.Reg
- p1.Reg = cl.Reg
- p1.To.Type = obj.TYPE_REGREG
- p1.To.Reg = ah.Reg
- p1.To.Offset = int64(al.Reg)
-
- //print("%v\n", p1);
-
- // bl * ch + ah -> ah
- p1 = gins(arm.AMULA, nil, nil)
-
- p1.From.Type = obj.TYPE_REG
- p1.From.Reg = bl.Reg
- p1.Reg = ch.Reg
- p1.To.Type = obj.TYPE_REGREG2
- p1.To.Reg = ah.Reg
- p1.To.Offset = int64(ah.Reg)
-
- //print("%v\n", p1);
-
- // bh * cl + ah -> ah
- p1 = gins(arm.AMULA, nil, nil)
-
- p1.From.Type = obj.TYPE_REG
- p1.From.Reg = bh.Reg
- p1.Reg = cl.Reg
- p1.To.Type = obj.TYPE_REGREG2
- p1.To.Reg = ah.Reg
- p1.To.Offset = int64(ah.Reg)
-
- //print("%v\n", p1);
-
- gc.Regfree(&bh)
-
- gc.Regfree(&bl)
- gc.Regfree(&ch)
- gc.Regfree(&cl)
-
- // We only rotate by a constant c in [0,64).
- // if c >= 32:
- // lo, hi = hi, lo
- // c -= 32
- // if c == 0:
- // no-op
- // else:
- // t = hi
- // shld hi:lo, c
- // shld lo:t, c
- case gc.OLROT:
- v := uint64(r.Int64())
-
- var bl gc.Node
- gc.Regalloc(&bl, lo1.Type, nil)
- var bh gc.Node
- gc.Regalloc(&bh, hi1.Type, nil)
- if v >= 32 {
- // reverse during load to do the first 32 bits of rotate
- v -= 32
-
- gins(arm.AMOVW, &hi1, &bl)
- gins(arm.AMOVW, &lo1, &bh)
- } else {
- gins(arm.AMOVW, &hi1, &bh)
- gins(arm.AMOVW, &lo1, &bl)
- }
-
- if v == 0 {
- gins(arm.AMOVW, &bh, &ah)
- gins(arm.AMOVW, &bl, &al)
- } else {
- // rotate by 1 <= v <= 31
- // MOVW bl<<v, al
- // MOVW bh<<v, ah
- // OR bl>>(32-v), ah
- // OR bh>>(32-v), al
- gshift(arm.AMOVW, &bl, arm.SHIFT_LL, int32(v), &al)
-
- gshift(arm.AMOVW, &bh, arm.SHIFT_LL, int32(v), &ah)
- gshift(arm.AORR, &bl, arm.SHIFT_LR, int32(32-v), &ah)
- gshift(arm.AORR, &bh, arm.SHIFT_LR, int32(32-v), &al)
- }
-
- gc.Regfree(&bl)
- gc.Regfree(&bh)
-
- case gc.OLSH:
- var bl gc.Node
- gc.Regalloc(&bl, lo1.Type, nil)
- var bh gc.Node
- gc.Regalloc(&bh, hi1.Type, nil)
- gins(arm.AMOVW, &hi1, &bh)
- gins(arm.AMOVW, &lo1, &bl)
-
- var p6 *obj.Prog
- var s gc.Node
- var n1 gc.Node
- var creg gc.Node
- var p1 *obj.Prog
- var p2 *obj.Prog
- var p3 *obj.Prog
- var p4 *obj.Prog
- var p5 *obj.Prog
- if r.Op == gc.OLITERAL {
- v := uint64(r.Int64())
- if v >= 64 {
- // TODO(kaib): replace with gins(AMOVW, nodintconst(0), &al)
- // here and below (verify it optimizes to EOR)
- gins(arm.AEOR, &al, &al)
-
- gins(arm.AEOR, &ah, &ah)
- } else if v > 32 {
- gins(arm.AEOR, &al, &al)
-
- // MOVW bl<<(v-32), ah
- gshift(arm.AMOVW, &bl, arm.SHIFT_LL, int32(v-32), &ah)
- } else if v == 32 {
- gins(arm.AEOR, &al, &al)
- gins(arm.AMOVW, &bl, &ah)
- } else if v > 0 {
- // MOVW bl<<v, al
- gshift(arm.AMOVW, &bl, arm.SHIFT_LL, int32(v), &al)
-
- // MOVW bh<<v, ah
- gshift(arm.AMOVW, &bh, arm.SHIFT_LL, int32(v), &ah)
-
- // OR bl>>(32-v), ah
- gshift(arm.AORR, &bl, arm.SHIFT_LR, int32(32-v), &ah)
- } else {
- gins(arm.AMOVW, &bl, &al)
- gins(arm.AMOVW, &bh, &ah)
- }
-
- goto olsh_break
- }
-
- gc.Regalloc(&s, gc.Types[gc.TUINT32], nil)
- gc.Regalloc(&creg, gc.Types[gc.TUINT32], nil)
- if gc.Is64(r.Type) {
- // shift is >= 1<<32
- var cl gc.Node
- var ch gc.Node
- split64(r, &cl, &ch)
-
- gmove(&ch, &s)
- gins(arm.ATST, &s, nil)
- p6 = gc.Gbranch(arm.ABNE, nil, 0)
- gmove(&cl, &s)
- splitclean()
- } else {
- gmove(r, &s)
- p6 = nil
- }
-
- gins(arm.ATST, &s, nil)
-
- // shift == 0
- p1 = gins(arm.AMOVW, &bl, &al)
-
- p1.Scond = arm.C_SCOND_EQ
- p1 = gins(arm.AMOVW, &bh, &ah)
- p1.Scond = arm.C_SCOND_EQ
- p2 = gc.Gbranch(arm.ABEQ, nil, 0)
-
- // shift is < 32
- gc.Nodconst(&n1, gc.Types[gc.TUINT32], 32)
-
- gmove(&n1, &creg)
- gins(arm.ACMP, &s, &creg)
-
- // MOVW.LO bl<<s, al
- p1 = gregshift(arm.AMOVW, &bl, arm.SHIFT_LL, &s, &al)
-
- p1.Scond = arm.C_SCOND_LO
-
- // MOVW.LO bh<<s, ah
- p1 = gregshift(arm.AMOVW, &bh, arm.SHIFT_LL, &s, &ah)
-
- p1.Scond = arm.C_SCOND_LO
-
- // SUB.LO s, creg
- p1 = gins(arm.ASUB, &s, &creg)
-
- p1.Scond = arm.C_SCOND_LO
-
- // OR.LO bl>>creg, ah
- p1 = gregshift(arm.AORR, &bl, arm.SHIFT_LR, &creg, &ah)
-
- p1.Scond = arm.C_SCOND_LO
-
- // BLO end
- p3 = gc.Gbranch(arm.ABLO, nil, 0)
-
- // shift == 32
- p1 = gins(arm.AEOR, &al, &al)
-
- p1.Scond = arm.C_SCOND_EQ
- p1 = gins(arm.AMOVW, &bl, &ah)
- p1.Scond = arm.C_SCOND_EQ
- p4 = gc.Gbranch(arm.ABEQ, nil, 0)
-
- // shift is < 64
- gc.Nodconst(&n1, gc.Types[gc.TUINT32], 64)
-
- gmove(&n1, &creg)
- gins(arm.ACMP, &s, &creg)
-
- // EOR.LO al, al
- p1 = gins(arm.AEOR, &al, &al)
-
- p1.Scond = arm.C_SCOND_LO
-
- // MOVW.LO creg>>1, creg
- p1 = gshift(arm.AMOVW, &creg, arm.SHIFT_LR, 1, &creg)
-
- p1.Scond = arm.C_SCOND_LO
-
- // SUB.LO creg, s
- p1 = gins(arm.ASUB, &creg, &s)
-
- p1.Scond = arm.C_SCOND_LO
-
- // MOVW bl<<s, ah
- p1 = gregshift(arm.AMOVW, &bl, arm.SHIFT_LL, &s, &ah)
-
- p1.Scond = arm.C_SCOND_LO
-
- p5 = gc.Gbranch(arm.ABLO, nil, 0)
-
- // shift >= 64
- if p6 != nil {
- gc.Patch(p6, gc.Pc)
- }
- gins(arm.AEOR, &al, &al)
- gins(arm.AEOR, &ah, &ah)
-
- gc.Patch(p2, gc.Pc)
- gc.Patch(p3, gc.Pc)
- gc.Patch(p4, gc.Pc)
- gc.Patch(p5, gc.Pc)
- gc.Regfree(&s)
- gc.Regfree(&creg)
-
- olsh_break:
- gc.Regfree(&bl)
- gc.Regfree(&bh)
-
- case gc.ORSH:
- var bl gc.Node
- gc.Regalloc(&bl, lo1.Type, nil)
- var bh gc.Node
- gc.Regalloc(&bh, hi1.Type, nil)
- gins(arm.AMOVW, &hi1, &bh)
- gins(arm.AMOVW, &lo1, &bl)
-
- var p4 *obj.Prog
- var p5 *obj.Prog
- var n1 gc.Node
- var p6 *obj.Prog
- var s gc.Node
- var p1 *obj.Prog
- var p2 *obj.Prog
- var creg gc.Node
- var p3 *obj.Prog
- if r.Op == gc.OLITERAL {
- v := uint64(r.Int64())
- if v >= 64 {
- if bh.Type.Etype == gc.TINT32 {
- // MOVW bh->31, al
- gshift(arm.AMOVW, &bh, arm.SHIFT_AR, 31, &al)
-
- // MOVW bh->31, ah
- gshift(arm.AMOVW, &bh, arm.SHIFT_AR, 31, &ah)
- } else {
- gins(arm.AEOR, &al, &al)
- gins(arm.AEOR, &ah, &ah)
- }
- } else if v > 32 {
- if bh.Type.Etype == gc.TINT32 {
- // MOVW bh->(v-32), al
- gshift(arm.AMOVW, &bh, arm.SHIFT_AR, int32(v-32), &al)
-
- // MOVW bh->31, ah
- gshift(arm.AMOVW, &bh, arm.SHIFT_AR, 31, &ah)
- } else {
- // MOVW bh>>(v-32), al
- gshift(arm.AMOVW, &bh, arm.SHIFT_LR, int32(v-32), &al)
-
- gins(arm.AEOR, &ah, &ah)
- }
- } else if v == 32 {
- gins(arm.AMOVW, &bh, &al)
- if bh.Type.Etype == gc.TINT32 {
- // MOVW bh->31, ah
- gshift(arm.AMOVW, &bh, arm.SHIFT_AR, 31, &ah)
- } else {
- gins(arm.AEOR, &ah, &ah)
- }
- } else if v > 0 {
- // MOVW bl>>v, al
- gshift(arm.AMOVW, &bl, arm.SHIFT_LR, int32(v), &al)
-
- // OR bh<<(32-v), al
- gshift(arm.AORR, &bh, arm.SHIFT_LL, int32(32-v), &al)
-
- if bh.Type.Etype == gc.TINT32 {
- // MOVW bh->v, ah
- gshift(arm.AMOVW, &bh, arm.SHIFT_AR, int32(v), &ah)
- } else {
- // MOVW bh>>v, ah
- gshift(arm.AMOVW, &bh, arm.SHIFT_LR, int32(v), &ah)
- }
- } else {
- gins(arm.AMOVW, &bl, &al)
- gins(arm.AMOVW, &bh, &ah)
- }
-
- goto orsh_break
- }
-
- gc.Regalloc(&s, gc.Types[gc.TUINT32], nil)
- gc.Regalloc(&creg, gc.Types[gc.TUINT32], nil)
- if gc.Is64(r.Type) {
- // shift is >= 1<<32
- var ch gc.Node
- var cl gc.Node
- split64(r, &cl, &ch)
-
- gmove(&ch, &s)
- gins(arm.ATST, &s, nil)
- var p1 *obj.Prog
- if bh.Type.Etype == gc.TINT32 {
- p1 = gshift(arm.AMOVW, &bh, arm.SHIFT_AR, 31, &ah)
- } else {
- p1 = gins(arm.AEOR, &ah, &ah)
- }
- p1.Scond = arm.C_SCOND_NE
- p6 = gc.Gbranch(arm.ABNE, nil, 0)
- gmove(&cl, &s)
- splitclean()
- } else {
- gmove(r, &s)
- p6 = nil
- }
-
- gins(arm.ATST, &s, nil)
-
- // shift == 0
- p1 = gins(arm.AMOVW, &bl, &al)
-
- p1.Scond = arm.C_SCOND_EQ
- p1 = gins(arm.AMOVW, &bh, &ah)
- p1.Scond = arm.C_SCOND_EQ
- p2 = gc.Gbranch(arm.ABEQ, nil, 0)
-
- // check if shift is < 32
- gc.Nodconst(&n1, gc.Types[gc.TUINT32], 32)
-
- gmove(&n1, &creg)
- gins(arm.ACMP, &s, &creg)
-
- // MOVW.LO bl>>s, al
- p1 = gregshift(arm.AMOVW, &bl, arm.SHIFT_LR, &s, &al)
-
- p1.Scond = arm.C_SCOND_LO
-
- // SUB.LO s,creg
- p1 = gins(arm.ASUB, &s, &creg)
-
- p1.Scond = arm.C_SCOND_LO
-
- // OR.LO bh<<(32-s), al
- p1 = gregshift(arm.AORR, &bh, arm.SHIFT_LL, &creg, &al)
-
- p1.Scond = arm.C_SCOND_LO
-
- if bh.Type.Etype == gc.TINT32 {
- // MOVW bh->s, ah
- p1 = gregshift(arm.AMOVW, &bh, arm.SHIFT_AR, &s, &ah)
- } else {
- // MOVW bh>>s, ah
- p1 = gregshift(arm.AMOVW, &bh, arm.SHIFT_LR, &s, &ah)
- }
-
- p1.Scond = arm.C_SCOND_LO
-
- // BLO end
- p3 = gc.Gbranch(arm.ABLO, nil, 0)
-
- // shift == 32
- p1 = gins(arm.AMOVW, &bh, &al)
-
- p1.Scond = arm.C_SCOND_EQ
- if bh.Type.Etype == gc.TINT32 {
- gshift(arm.AMOVW, &bh, arm.SHIFT_AR, 31, &ah)
- } else {
- gins(arm.AEOR, &ah, &ah)
- }
- p4 = gc.Gbranch(arm.ABEQ, nil, 0)
-
- // check if shift is < 64
- gc.Nodconst(&n1, gc.Types[gc.TUINT32], 64)
-
- gmove(&n1, &creg)
- gins(arm.ACMP, &s, &creg)
-
- // MOVW.LO creg>>1, creg
- p1 = gshift(arm.AMOVW, &creg, arm.SHIFT_LR, 1, &creg)
-
- p1.Scond = arm.C_SCOND_LO
-
- // SUB.LO creg, s
- p1 = gins(arm.ASUB, &creg, &s)
-
- p1.Scond = arm.C_SCOND_LO
-
- if bh.Type.Etype == gc.TINT32 {
- // MOVW bh->(s-32), al
- p1 := gregshift(arm.AMOVW, &bh, arm.SHIFT_AR, &s, &al)
-
- p1.Scond = arm.C_SCOND_LO
- } else {
- // MOVW bh>>(v-32), al
- p1 := gregshift(arm.AMOVW, &bh, arm.SHIFT_LR, &s, &al)
-
- p1.Scond = arm.C_SCOND_LO
- }
-
- // BLO end
- p5 = gc.Gbranch(arm.ABLO, nil, 0)
-
- // s >= 64
- if p6 != nil {
- gc.Patch(p6, gc.Pc)
- }
- if bh.Type.Etype == gc.TINT32 {
- // MOVW bh->31, al
- gshift(arm.AMOVW, &bh, arm.SHIFT_AR, 31, &al)
- } else {
- gins(arm.AEOR, &al, &al)
- }
-
- gc.Patch(p2, gc.Pc)
- gc.Patch(p3, gc.Pc)
- gc.Patch(p4, gc.Pc)
- gc.Patch(p5, gc.Pc)
- gc.Regfree(&s)
- gc.Regfree(&creg)
-
- orsh_break:
- gc.Regfree(&bl)
- gc.Regfree(&bh)
-
- // TODO(kaib): literal optimizations
- // make constant the right side (it usually is anyway).
- // if(lo1.op == OLITERAL) {
- // nswap(&lo1, &lo2);
- // nswap(&hi1, &hi2);
- // }
- // if(lo2.op == OLITERAL) {
- // // special cases for constants.
- // lv = mpgetfix(lo2.val.u.xval);
- // hv = mpgetfix(hi2.val.u.xval);
- // splitclean(); // right side
- // split64(res, &lo2, &hi2);
- // switch(n->op) {
- // case OXOR:
- // gmove(&lo1, &lo2);
- // gmove(&hi1, &hi2);
- // switch(lv) {
- // case 0:
- // break;
- // case 0xffffffffu:
- // gins(ANOTL, N, &lo2);
- // break;
- // default:
- // gins(AXORL, ncon(lv), &lo2);
- // break;
- // }
- // switch(hv) {
- // case 0:
- // break;
- // case 0xffffffffu:
- // gins(ANOTL, N, &hi2);
- // break;
- // default:
- // gins(AXORL, ncon(hv), &hi2);
- // break;
- // }
- // break;
-
- // case OAND:
- // switch(lv) {
- // case 0:
- // gins(AMOVL, ncon(0), &lo2);
- // break;
- // default:
- // gmove(&lo1, &lo2);
- // if(lv != 0xffffffffu)
- // gins(AANDL, ncon(lv), &lo2);
- // break;
- // }
- // switch(hv) {
- // case 0:
- // gins(AMOVL, ncon(0), &hi2);
- // break;
- // default:
- // gmove(&hi1, &hi2);
- // if(hv != 0xffffffffu)
- // gins(AANDL, ncon(hv), &hi2);
- // break;
- // }
- // break;
-
- // case OOR:
- // switch(lv) {
- // case 0:
- // gmove(&lo1, &lo2);
- // break;
- // case 0xffffffffu:
- // gins(AMOVL, ncon(0xffffffffu), &lo2);
- // break;
- // default:
- // gmove(&lo1, &lo2);
- // gins(AORL, ncon(lv), &lo2);
- // break;
- // }
- // switch(hv) {
- // case 0:
- // gmove(&hi1, &hi2);
- // break;
- // case 0xffffffffu:
- // gins(AMOVL, ncon(0xffffffffu), &hi2);
- // break;
- // default:
- // gmove(&hi1, &hi2);
- // gins(AORL, ncon(hv), &hi2);
- // break;
- // }
- // break;
- // }
- // splitclean();
- // splitclean();
- // goto out;
- // }
- case gc.OXOR,
- gc.OAND,
- gc.OOR:
- var n1 gc.Node
- gc.Regalloc(&n1, lo1.Type, nil)
-
- gins(arm.AMOVW, &lo1, &al)
- gins(arm.AMOVW, &hi1, &ah)
- gins(arm.AMOVW, &lo2, &n1)
- gins(optoas(n.Op, lo1.Type), &n1, &al)
- gins(arm.AMOVW, &hi2, &n1)
- gins(optoas(n.Op, lo1.Type), &n1, &ah)
- gc.Regfree(&n1)
- }
-
- if gc.Is64(r.Type) {
- splitclean()
- }
- splitclean()
-
- split64(res, &lo1, &hi1)
- gins(arm.AMOVW, &al, &lo1)
- gins(arm.AMOVW, &ah, &hi1)
- splitclean()
-
- //out:
- gc.Regfree(&al)
-
- gc.Regfree(&ah)
-}
-
-/*
- * generate comparison of nl, nr, both 64-bit.
- * nl is memory; nr is constant or memory.
- */
-func cmp64(nl *gc.Node, nr *gc.Node, op gc.Op, likely int, to *obj.Prog) {
- var lo1 gc.Node
- var hi1 gc.Node
- var lo2 gc.Node
- var hi2 gc.Node
- var r1 gc.Node
- var r2 gc.Node
-
- split64(nl, &lo1, &hi1)
- split64(nr, &lo2, &hi2)
-
- // compare most significant word;
- // if they differ, we're done.
- t := hi1.Type
-
- gc.Regalloc(&r1, gc.Types[gc.TINT32], nil)
- gc.Regalloc(&r2, gc.Types[gc.TINT32], nil)
- gins(arm.AMOVW, &hi1, &r1)
- gins(arm.AMOVW, &hi2, &r2)
- gins(arm.ACMP, &r1, &r2)
- gc.Regfree(&r1)
- gc.Regfree(&r2)
-
- var br *obj.Prog
- switch op {
- default:
- gc.Fatalf("cmp64 %v %v", op, t)
-
- // cmp hi
- // bne L
- // cmp lo
- // beq to
- // L:
- case gc.OEQ:
- br = gc.Gbranch(arm.ABNE, nil, -likely)
-
- // cmp hi
- // bne to
- // cmp lo
- // bne to
- case gc.ONE:
- gc.Patch(gc.Gbranch(arm.ABNE, nil, likely), to)
-
- // cmp hi
- // bgt to
- // blt L
- // cmp lo
- // bge to (or bgt to)
- // L:
- case gc.OGE,
- gc.OGT:
- gc.Patch(gc.Gbranch(optoas(gc.OGT, t), nil, likely), to)
-
- br = gc.Gbranch(optoas(gc.OLT, t), nil, -likely)
-
- // cmp hi
- // blt to
- // bgt L
- // cmp lo
- // ble to (or jlt to)
- // L:
- case gc.OLE,
- gc.OLT:
- gc.Patch(gc.Gbranch(optoas(gc.OLT, t), nil, likely), to)
-
- br = gc.Gbranch(optoas(gc.OGT, t), nil, -likely)
- }
-
- // compare least significant word
- t = lo1.Type
-
- gc.Regalloc(&r1, gc.Types[gc.TINT32], nil)
- gc.Regalloc(&r2, gc.Types[gc.TINT32], nil)
- gins(arm.AMOVW, &lo1, &r1)
- gins(arm.AMOVW, &lo2, &r2)
- gins(arm.ACMP, &r1, &r2)
- gc.Regfree(&r1)
- gc.Regfree(&r2)
-
- // jump again
- gc.Patch(gc.Gbranch(optoas(op, t), nil, likely), to)
-
- // point first branch down here if appropriate
- if br != nil {
- gc.Patch(br, gc.Pc)
- }
-
- splitclean()
- splitclean()
-}
diff --git a/src/cmd/compile/internal/arm/galign.go b/src/cmd/compile/internal/arm/galign.go
index afd86e4..308b016 100644
--- a/src/cmd/compile/internal/arm/galign.go
+++ b/src/cmd/compile/internal/arm/galign.go
@@ -10,62 +10,15 @@ import (
"cmd/internal/obj/arm"
)
-func betypeinit() {
-}
-
-func Main() {
+func Init() {
gc.Thearch.LinkArch = &arm.Linkarm
gc.Thearch.REGSP = arm.REGSP
- gc.Thearch.REGCTXT = arm.REGCTXT
- gc.Thearch.REGCALLX = arm.REG_R1
- gc.Thearch.REGCALLX2 = arm.REG_R2
- gc.Thearch.REGRETURN = arm.REG_R0
- gc.Thearch.REGMIN = arm.REG_R0
- gc.Thearch.REGMAX = arm.REGEXT
- gc.Thearch.FREGMIN = arm.REG_F0
- gc.Thearch.FREGMAX = arm.FREGEXT
gc.Thearch.MAXWIDTH = (1 << 32) - 1
- gc.Thearch.ReservedRegs = resvd
- gc.Thearch.Betypeinit = betypeinit
- gc.Thearch.Cgen64 = cgen64
- gc.Thearch.Cgen_hmul = cgen_hmul
- gc.Thearch.Cgen_shift = cgen_shift
- gc.Thearch.Clearfat = clearfat
- gc.Thearch.Cmp64 = cmp64
gc.Thearch.Defframe = defframe
- gc.Thearch.Excise = excise
- gc.Thearch.Expandchecks = expandchecks
- gc.Thearch.Getg = getg
- gc.Thearch.Gins = gins
- gc.Thearch.Ginscmp = ginscmp
- gc.Thearch.Ginscon = ginscon
- gc.Thearch.Ginsnop = ginsnop
- gc.Thearch.Gmove = gmove
- gc.Thearch.Cgenindex = cgenindex
- gc.Thearch.Peep = peep
gc.Thearch.Proginfo = proginfo
- gc.Thearch.Regtyp = regtyp
- gc.Thearch.Sameaddr = sameaddr
- gc.Thearch.Smallindir = smallindir
- gc.Thearch.Stackaddr = stackaddr
- gc.Thearch.Blockcopy = blockcopy
- gc.Thearch.Sudoaddable = sudoaddable
- gc.Thearch.Sudoclean = sudoclean
- gc.Thearch.Excludedregs = excludedregs
- gc.Thearch.RtoB = RtoB
- gc.Thearch.FtoB = RtoB
- gc.Thearch.BtoR = BtoR
- gc.Thearch.BtoF = BtoF
- gc.Thearch.Optoas = optoas
- gc.Thearch.Doregbits = doregbits
- gc.Thearch.Regnames = regnames
- gc.Thearch.SSARegToReg = ssaRegToReg
gc.Thearch.SSAMarkMoves = func(s *gc.SSAGenState, b *ssa.Block) {}
gc.Thearch.SSAGenValue = ssaGenValue
gc.Thearch.SSAGenBlock = ssaGenBlock
-
- gc.Main()
- gc.Exit(0)
}
diff --git a/src/cmd/compile/internal/arm/ggen.go b/src/cmd/compile/internal/arm/ggen.go
index 4a45e58..6dce0a4 100644
--- a/src/cmd/compile/internal/arm/ggen.go
+++ b/src/cmd/compile/internal/arm/ggen.go
@@ -34,7 +34,7 @@ func defframe(ptxt *obj.Prog) {
gc.Fatalf("needzero class %d", n.Class)
}
if n.Type.Width%int64(gc.Widthptr) != 0 || n.Xoffset%int64(gc.Widthptr) != 0 || n.Type.Width == 0 {
- gc.Fatalf("var %v has size %d offset %d", gc.Nconv(n, gc.FmtLong), int(n.Type.Width), int(n.Xoffset))
+ 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
@@ -62,489 +62,42 @@ func zerorange(p *obj.Prog, frame int64, lo int64, hi int64, r0 *uint32) *obj.Pr
return p
}
if *r0 == 0 {
- p = appendpp(p, arm.AMOVW, obj.TYPE_CONST, 0, 0, obj.TYPE_REG, arm.REG_R0, 0)
+ p = gc.Appendpp(p, arm.AMOVW, obj.TYPE_CONST, 0, 0, obj.TYPE_REG, arm.REG_R0, 0)
*r0 = 1
}
if cnt < int64(4*gc.Widthptr) {
for i := int64(0); i < cnt; i += int64(gc.Widthptr) {
- p = appendpp(p, arm.AMOVW, obj.TYPE_REG, arm.REG_R0, 0, obj.TYPE_MEM, arm.REGSP, int32(4+frame+lo+i))
+ p = gc.Appendpp(p, arm.AMOVW, obj.TYPE_REG, arm.REG_R0, 0, obj.TYPE_MEM, arm.REGSP, 4+frame+lo+i)
}
} else if !gc.Nacl && (cnt <= int64(128*gc.Widthptr)) {
- p = appendpp(p, arm.AADD, obj.TYPE_CONST, 0, int32(4+frame+lo), obj.TYPE_REG, arm.REG_R1, 0)
+ p = gc.Appendpp(p, arm.AADD, obj.TYPE_CONST, 0, 4+frame+lo, obj.TYPE_REG, arm.REG_R1, 0)
p.Reg = arm.REGSP
- p = appendpp(p, obj.ADUFFZERO, obj.TYPE_NONE, 0, 0, obj.TYPE_MEM, 0, 0)
- f := gc.Sysfunc("duffzero")
- gc.Naddr(&p.To, f)
- gc.Afunclit(&p.To, f)
+ p = gc.Appendpp(p, obj.ADUFFZERO, obj.TYPE_NONE, 0, 0, obj.TYPE_MEM, 0, 0)
+ gc.Naddr(&p.To, gc.Sysfunc("duffzero"))
p.To.Offset = 4 * (128 - cnt/int64(gc.Widthptr))
} else {
- p = appendpp(p, arm.AADD, obj.TYPE_CONST, 0, int32(4+frame+lo), obj.TYPE_REG, arm.REG_R1, 0)
+ p = gc.Appendpp(p, arm.AADD, obj.TYPE_CONST, 0, 4+frame+lo, obj.TYPE_REG, arm.REG_R1, 0)
p.Reg = arm.REGSP
- p = appendpp(p, arm.AADD, obj.TYPE_CONST, 0, int32(cnt), obj.TYPE_REG, arm.REG_R2, 0)
+ p = gc.Appendpp(p, arm.AADD, obj.TYPE_CONST, 0, cnt, obj.TYPE_REG, arm.REG_R2, 0)
p.Reg = arm.REG_R1
- p = appendpp(p, arm.AMOVW, obj.TYPE_REG, arm.REG_R0, 0, obj.TYPE_MEM, arm.REG_R1, 4)
+ p = gc.Appendpp(p, arm.AMOVW, obj.TYPE_REG, arm.REG_R0, 0, obj.TYPE_MEM, arm.REG_R1, 4)
p1 := p
p.Scond |= arm.C_PBIT
- p = appendpp(p, arm.ACMP, obj.TYPE_REG, arm.REG_R1, 0, obj.TYPE_NONE, 0, 0)
+ p = gc.Appendpp(p, arm.ACMP, obj.TYPE_REG, arm.REG_R1, 0, obj.TYPE_NONE, 0, 0)
p.Reg = arm.REG_R2
- p = appendpp(p, arm.ABNE, obj.TYPE_NONE, 0, 0, obj.TYPE_BRANCH, 0, 0)
+ p = gc.Appendpp(p, arm.ABNE, obj.TYPE_NONE, 0, 0, obj.TYPE_BRANCH, 0, 0)
gc.Patch(p, p1)
}
return p
}
-func appendpp(p *obj.Prog, as obj.As, ftype obj.AddrType, freg int, foffset int32, ttype obj.AddrType, treg int, toffset int32) *obj.Prog {
- q := gc.Ctxt.NewProg()
- gc.Clearp(q)
- q.As = as
- q.Lineno = p.Lineno
- q.From.Type = ftype
- q.From.Reg = int16(freg)
- q.From.Offset = int64(foffset)
- q.To.Type = ttype
- q.To.Reg = int16(treg)
- q.To.Offset = int64(toffset)
- q.Link = p.Link
- p.Link = q
- return q
-}
-
-/*
- * generate high multiply
- * res = (nl * nr) >> wordsize
- */
-func cgen_hmul(nl *gc.Node, nr *gc.Node, res *gc.Node) {
- if nl.Ullman < nr.Ullman {
- nl, nr = nr, nl
- }
-
- t := nl.Type
- w := t.Width * 8
- var n1 gc.Node
- gc.Regalloc(&n1, t, res)
- gc.Cgen(nl, &n1)
- var n2 gc.Node
- gc.Regalloc(&n2, t, nil)
- gc.Cgen(nr, &n2)
- switch gc.Simtype[t.Etype] {
- case gc.TINT8,
- gc.TINT16:
- gins(optoas(gc.OMUL, t), &n2, &n1)
- gshift(arm.AMOVW, &n1, arm.SHIFT_AR, int32(w), &n1)
-
- case gc.TUINT8,
- gc.TUINT16:
- gins(optoas(gc.OMUL, t), &n2, &n1)
- gshift(arm.AMOVW, &n1, arm.SHIFT_LR, int32(w), &n1)
-
- // perform a long multiplication.
- case gc.TINT32,
- gc.TUINT32:
- var p *obj.Prog
- if t.IsSigned() {
- p = gins(arm.AMULL, &n2, nil)
- } else {
- p = gins(arm.AMULLU, &n2, nil)
- }
-
- // n2 * n1 -> (n1 n2)
- p.Reg = n1.Reg
-
- p.To.Type = obj.TYPE_REGREG
- p.To.Reg = n1.Reg
- p.To.Offset = int64(n2.Reg)
-
- default:
- gc.Fatalf("cgen_hmul %v", t)
- }
-
- gc.Cgen(&n1, res)
- gc.Regfree(&n1)
- gc.Regfree(&n2)
-}
-
-/*
- * generate shift according to op, one of:
- * res = nl << nr
- * res = nl >> nr
- */
-func cgen_shift(op gc.Op, bounded bool, nl *gc.Node, nr *gc.Node, res *gc.Node) {
- if nl.Type.Width > 4 {
- gc.Fatalf("cgen_shift %v", nl.Type)
- }
-
- w := int(nl.Type.Width * 8)
-
- if op == gc.OLROT {
- v := nr.Int64()
- var n1 gc.Node
- gc.Regalloc(&n1, nl.Type, res)
- if w == 32 {
- gc.Cgen(nl, &n1)
- gshift(arm.AMOVW, &n1, arm.SHIFT_RR, int32(w)-int32(v), &n1)
- } else {
- var n2 gc.Node
- gc.Regalloc(&n2, nl.Type, nil)
- gc.Cgen(nl, &n2)
- gshift(arm.AMOVW, &n2, arm.SHIFT_LL, int32(v), &n1)
- gshift(arm.AORR, &n2, arm.SHIFT_LR, int32(w)-int32(v), &n1)
- gc.Regfree(&n2)
-
- // Ensure sign/zero-extended result.
- gins(optoas(gc.OAS, nl.Type), &n1, &n1)
- }
-
- gmove(&n1, res)
- gc.Regfree(&n1)
- return
- }
-
- if nr.Op == gc.OLITERAL {
- var n1 gc.Node
- gc.Regalloc(&n1, nl.Type, res)
- gc.Cgen(nl, &n1)
- sc := uint64(nr.Int64())
- if sc == 0 {
- } else // nothing to do
- if sc >= uint64(nl.Type.Width*8) {
- if op == gc.ORSH && nl.Type.IsSigned() {
- gshift(arm.AMOVW, &n1, arm.SHIFT_AR, int32(w), &n1)
- } else {
- gins(arm.AEOR, &n1, &n1)
- }
- } else {
- if op == gc.ORSH && nl.Type.IsSigned() {
- gshift(arm.AMOVW, &n1, arm.SHIFT_AR, int32(sc), &n1)
- } else if op == gc.ORSH {
- gshift(arm.AMOVW, &n1, arm.SHIFT_LR, int32(sc), &n1) // OLSH
- } else {
- gshift(arm.AMOVW, &n1, arm.SHIFT_LL, int32(sc), &n1)
- }
- }
-
- if w < 32 && op == gc.OLSH {
- gins(optoas(gc.OAS, nl.Type), &n1, &n1)
- }
- gmove(&n1, res)
- gc.Regfree(&n1)
- return
- }
-
- tr := nr.Type
- var t gc.Node
- var n1 gc.Node
- var n2 gc.Node
- var n3 gc.Node
- if tr.Width > 4 {
- var nt gc.Node
- gc.Tempname(&nt, nr.Type)
- if nl.Ullman >= nr.Ullman {
- gc.Regalloc(&n2, nl.Type, res)
- gc.Cgen(nl, &n2)
- gc.Cgen(nr, &nt)
- n1 = nt
- } else {
- gc.Cgen(nr, &nt)
- gc.Regalloc(&n2, nl.Type, res)
- gc.Cgen(nl, &n2)
- }
-
- var hi gc.Node
- var lo gc.Node
- split64(&nt, &lo, &hi)
- gc.Regalloc(&n1, gc.Types[gc.TUINT32], nil)
- gc.Regalloc(&n3, gc.Types[gc.TUINT32], nil)
- gmove(&lo, &n1)
- gmove(&hi, &n3)
- splitclean()
- gins(arm.ATST, &n3, nil)
- gc.Nodconst(&t, gc.Types[gc.TUINT32], int64(w))
- p1 := gins(arm.AMOVW, &t, &n1)
- p1.Scond = arm.C_SCOND_NE
- tr = gc.Types[gc.TUINT32]
- gc.Regfree(&n3)
- } else {
- if nl.Ullman >= nr.Ullman {
- gc.Regalloc(&n2, nl.Type, res)
- gc.Cgen(nl, &n2)
- gc.Regalloc(&n1, nr.Type, nil)
- gc.Cgen(nr, &n1)
- } else {
- gc.Regalloc(&n1, nr.Type, nil)
- gc.Cgen(nr, &n1)
- gc.Regalloc(&n2, nl.Type, res)
- gc.Cgen(nl, &n2)
- }
- }
-
- // test for shift being 0
- gins(arm.ATST, &n1, nil)
-
- p3 := gc.Gbranch(arm.ABEQ, nil, -1)
-
- // test and fix up large shifts
- // TODO: if(!bounded), don't emit some of this.
- gc.Regalloc(&n3, tr, nil)
-
- gc.Nodconst(&t, gc.Types[gc.TUINT32], int64(w))
- gmove(&t, &n3)
- gins(arm.ACMP, &n1, &n3)
- if op == gc.ORSH {
- var p1 *obj.Prog
- var p2 *obj.Prog
- if nl.Type.IsSigned() {
- p1 = gshift(arm.AMOVW, &n2, arm.SHIFT_AR, int32(w)-1, &n2)
- p2 = gregshift(arm.AMOVW, &n2, arm.SHIFT_AR, &n1, &n2)
- } else {
- p1 = gins(arm.AEOR, &n2, &n2)
- p2 = gregshift(arm.AMOVW, &n2, arm.SHIFT_LR, &n1, &n2)
- }
-
- p1.Scond = arm.C_SCOND_HS
- p2.Scond = arm.C_SCOND_LO
- } else {
- p1 := gins(arm.AEOR, &n2, &n2)
- p2 := gregshift(arm.AMOVW, &n2, arm.SHIFT_LL, &n1, &n2)
- p1.Scond = arm.C_SCOND_HS
- p2.Scond = arm.C_SCOND_LO
- }
-
- gc.Regfree(&n3)
-
- gc.Patch(p3, gc.Pc)
-
- // Left-shift of smaller word must be sign/zero-extended.
- if w < 32 && op == gc.OLSH {
- gins(optoas(gc.OAS, nl.Type), &n2, &n2)
- }
- gmove(&n2, res)
-
- gc.Regfree(&n1)
- gc.Regfree(&n2)
-}
-
-func clearfat(nl *gc.Node) {
- /* clear a fat object */
- if gc.Debug['g'] != 0 {
- gc.Dump("\nclearfat", nl)
- }
-
- w := uint32(nl.Type.Width)
-
- // Avoid taking the address for simple enough types.
- if gc.Componentgen(nil, nl) {
- return
- }
-
- c := w % 4 // bytes
- q := w / 4 // quads
-
- if nl.Type.Align < 4 {
- q = 0
- c = w
- }
-
- var r0 gc.Node
- r0.Op = gc.OREGISTER
-
- r0.Reg = arm.REG_R0
- var r1 gc.Node
- r1.Op = gc.OREGISTER
- r1.Reg = arm.REG_R1
- var dst gc.Node
- gc.Regalloc(&dst, gc.Types[gc.Tptr], &r1)
- gc.Agen(nl, &dst)
- var nc gc.Node
- gc.Nodconst(&nc, gc.Types[gc.TUINT32], 0)
- var nz gc.Node
- gc.Regalloc(&nz, gc.Types[gc.TUINT32], &r0)
- gc.Cgen(&nc, &nz)
-
- if q > 128 {
- var end gc.Node
- gc.Regalloc(&end, gc.Types[gc.Tptr], nil)
- p := gins(arm.AMOVW, &dst, &end)
- p.From.Type = obj.TYPE_ADDR
- p.From.Offset = int64(q) * 4
-
- p = gins(arm.AMOVW, &nz, &dst)
- p.To.Type = obj.TYPE_MEM
- p.To.Offset = 4
- p.Scond |= arm.C_PBIT
- pl := p
-
- p = gins(arm.ACMP, &dst, nil)
- raddr(&end, p)
- gc.Patch(gc.Gbranch(arm.ABNE, nil, 0), pl)
-
- gc.Regfree(&end)
- } else if q >= 4 && !gc.Nacl {
- f := gc.Sysfunc("duffzero")
- p := gins(obj.ADUFFZERO, nil, f)
- gc.Afunclit(&p.To, f)
-
- // 4 and 128 = magic constants: see ../../runtime/asm_arm.s
- p.To.Offset = 4 * (128 - int64(q))
- } else {
- var p *obj.Prog
- for q > 0 {
- p = gins(arm.AMOVW, &nz, &dst)
- p.To.Type = obj.TYPE_MEM
- p.To.Offset = 4
- p.Scond |= arm.C_PBIT
-
- //print("1. %v\n", p);
- q--
- }
- }
-
- if c > 4 {
- // Loop to zero unaligned memory.
- var end gc.Node
- gc.Regalloc(&end, gc.Types[gc.Tptr], nil)
- p := gins(arm.AMOVW, &dst, &end)
- p.From.Type = obj.TYPE_ADDR
- p.From.Offset = int64(c)
-
- p = gins(arm.AMOVB, &nz, &dst)
- p.To.Type = obj.TYPE_MEM
- p.To.Offset = 1
- p.Scond |= arm.C_PBIT
- pl := p
-
- p = gins(arm.ACMP, &dst, nil)
- raddr(&end, p)
- gc.Patch(gc.Gbranch(arm.ABNE, nil, 0), pl)
-
- gc.Regfree(&end)
- c = 0
- }
- var p *obj.Prog
- for c > 0 {
- p = gins(arm.AMOVB, &nz, &dst)
- p.To.Type = obj.TYPE_MEM
- p.To.Offset = 1
- p.Scond |= arm.C_PBIT
-
- //print("2. %v\n", p);
- c--
- }
-
- gc.Regfree(&dst)
- gc.Regfree(&nz)
-}
-
-// Called after regopt and peep have run.
-// Expand CHECKNIL pseudo-op into actual nil pointer check.
-func expandchecks(firstp *obj.Prog) {
- var reg int
- var p1 *obj.Prog
-
- for p := firstp; p != nil; p = p.Link {
- if p.As != obj.ACHECKNIL {
- continue
- }
- if gc.Debug_checknil != 0 && p.Lineno > 1 { // p->lineno==1 in generated wrappers
- gc.Warnl(p.Lineno, "generated nil check")
- }
- if p.From.Type != obj.TYPE_REG {
- gc.Fatalf("invalid nil check %v", p)
- }
- reg = int(p.From.Reg)
-
- // check is
- // CMP arg, $0
- // MOV.EQ arg, 0(arg)
- p1 = gc.Ctxt.NewProg()
-
- gc.Clearp(p1)
- p1.Link = p.Link
- p.Link = p1
- p1.Lineno = p.Lineno
- p1.Pc = 9999
- p1.As = arm.AMOVW
- p1.From.Type = obj.TYPE_REG
- p1.From.Reg = int16(reg)
- p1.To.Type = obj.TYPE_MEM
- p1.To.Reg = int16(reg)
- p1.To.Offset = 0
- p1.Scond = arm.C_SCOND_EQ
- p.As = arm.ACMP
- p.From.Type = obj.TYPE_CONST
- p.From.Reg = 0
- p.From.Offset = 0
- p.Reg = int16(reg)
- }
-}
-
func ginsnop() {
- var r gc.Node
- gc.Nodreg(&r, gc.Types[gc.TINT], arm.REG_R0)
- p := gins(arm.AAND, &r, &r)
+ p := gc.Prog(arm.AAND)
+ p.From.Type = obj.TYPE_REG
+ p.From.Reg = arm.REG_R0
+ p.To.Type = obj.TYPE_REG
+ p.To.Reg = arm.REG_R0
p.Scond = arm.C_SCOND_EQ
}
-
-/*
- * generate
- * as $c, n
- */
-func ginscon(as obj.As, c int64, n *gc.Node) {
- var n1 gc.Node
- gc.Nodconst(&n1, gc.Types[gc.TINT32], c)
- var n2 gc.Node
- gc.Regalloc(&n2, gc.Types[gc.TINT32], nil)
- gmove(&n1, &n2)
- gins(as, &n2, n)
- gc.Regfree(&n2)
-}
-
-func ginscmp(op gc.Op, t *gc.Type, n1, n2 *gc.Node, likely int) *obj.Prog {
- if t.IsInteger() && n1.Op == gc.OLITERAL && n1.Int64() == 0 && n2.Op != gc.OLITERAL {
- op = gc.Brrev(op)
- n1, n2 = n2, n1
- }
- var r1, r2, g1, g2 gc.Node
- gc.Regalloc(&r1, t, n1)
- gc.Regalloc(&g1, n1.Type, &r1)
- gc.Cgen(n1, &g1)
- gmove(&g1, &r1)
- if t.IsInteger() && n2.Op == gc.OLITERAL && n2.Int64() == 0 {
- gins(arm.ACMP, &r1, n2)
- } else {
- gc.Regalloc(&r2, t, n2)
- gc.Regalloc(&g2, n1.Type, &r2)
- gc.Cgen(n2, &g2)
- gmove(&g2, &r2)
- gins(optoas(gc.OCMP, t), &r1, &r2)
- gc.Regfree(&g2)
- gc.Regfree(&r2)
- }
- gc.Regfree(&g1)
- gc.Regfree(&r1)
- return gc.Gbranch(optoas(op, t), nil, likely)
-}
-
-// addr += index*width if possible.
-func addindex(index *gc.Node, width int64, addr *gc.Node) bool {
- switch width {
- case 2:
- gshift(arm.AADD, index, arm.SHIFT_LL, 1, addr)
- return true
- case 4:
- gshift(arm.AADD, index, arm.SHIFT_LL, 2, addr)
- return true
- case 8:
- gshift(arm.AADD, index, arm.SHIFT_LL, 3, addr)
- return true
- }
- return false
-}
-
-// res = runtime.getg()
-func getg(res *gc.Node) {
- var n1 gc.Node
- gc.Nodreg(&n1, res.Type, arm.REGG)
- gmove(&n1, res)
-}
diff --git a/src/cmd/compile/internal/arm/gsubr.go b/src/cmd/compile/internal/arm/gsubr.go
deleted file mode 100644
index b5d7bc0..0000000
--- a/src/cmd/compile/internal/arm/gsubr.go
+++ /dev/null
@@ -1,1225 +0,0 @@
-// Derived from Inferno utils/5c/txt.c
-// http://code.google.com/p/inferno-os/source/browse/utils/5c/txt.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth at terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth at terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// Portions Copyright © 2009 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-package arm
-
-import (
- "cmd/compile/internal/gc"
- "cmd/internal/obj"
- "cmd/internal/obj/arm"
- "fmt"
-)
-
-var resvd = []int{
- arm.REG_R9, // formerly reserved for m; might be okay to reuse now; not sure about NaCl
- arm.REG_R10, // reserved for g
-}
-
-/*
- * return constant i node.
- * overwritten by next call, but useful in calls to gins.
- */
-
-var ncon_n gc.Node
-
-func ncon(i uint32) *gc.Node {
- if ncon_n.Type == nil {
- gc.Nodconst(&ncon_n, gc.Types[gc.TUINT32], 0)
- }
- ncon_n.SetInt(int64(i))
- return &ncon_n
-}
-
-var sclean [10]gc.Node
-
-var nsclean int
-
-/*
- * n is a 64-bit value. fill in lo and hi to refer to its 32-bit halves.
- */
-func split64(n *gc.Node, lo *gc.Node, hi *gc.Node) {
- if !gc.Is64(n.Type) {
- gc.Fatalf("split64 %v", n.Type)
- }
-
- if nsclean >= len(sclean) {
- gc.Fatalf("split64 clean")
- }
- sclean[nsclean].Op = gc.OEMPTY
- nsclean++
- switch n.Op {
- default:
- switch n.Op {
- default:
- var n1 gc.Node
- if !dotaddable(n, &n1) {
- gc.Igen(n, &n1, nil)
- sclean[nsclean-1] = n1
- }
-
- n = &n1
-
- case gc.ONAME, gc.OINDREG:
- // nothing
- }
-
- *lo = *n
- *hi = *n
- lo.Type = gc.Types[gc.TUINT32]
- if n.Type.Etype == gc.TINT64 {
- hi.Type = gc.Types[gc.TINT32]
- } else {
- hi.Type = gc.Types[gc.TUINT32]
- }
- hi.Xoffset += 4
-
- case gc.OLITERAL:
- var n1 gc.Node
- n.Convconst(&n1, n.Type)
- i := n1.Int64()
- gc.Nodconst(lo, gc.Types[gc.TUINT32], int64(uint32(i)))
- i >>= 32
- if n.Type.Etype == gc.TINT64 {
- gc.Nodconst(hi, gc.Types[gc.TINT32], int64(int32(i)))
- } else {
- gc.Nodconst(hi, gc.Types[gc.TUINT32], int64(uint32(i)))
- }
- }
-}
-
-func splitclean() {
- if nsclean <= 0 {
- gc.Fatalf("splitclean")
- }
- nsclean--
- if sclean[nsclean].Op != gc.OEMPTY {
- gc.Regfree(&sclean[nsclean])
- }
-}
-
-func gmove(f *gc.Node, t *gc.Node) {
- if gc.Debug['M'] != 0 {
- fmt.Printf("gmove %v -> %v\n", f, t)
- }
-
- ft := gc.Simsimtype(f.Type)
- tt := gc.Simsimtype(t.Type)
- cvt := t.Type
-
- if gc.Iscomplex[ft] || gc.Iscomplex[tt] {
- gc.Complexmove(f, t)
- return
- }
-
- // cannot have two memory operands;
- // except 64-bit, which always copies via registers anyway.
- var a obj.As
- var r1 gc.Node
- if !gc.Is64(f.Type) && !gc.Is64(t.Type) && gc.Ismem(f) && gc.Ismem(t) {
- goto hard
- }
-
- // convert constant to desired type
- if f.Op == gc.OLITERAL {
- var con gc.Node
- switch tt {
- default:
- f.Convconst(&con, t.Type)
-
- case gc.TINT16,
- gc.TINT8:
- var con gc.Node
- f.Convconst(&con, gc.Types[gc.TINT32])
- var r1 gc.Node
- gc.Regalloc(&r1, con.Type, t)
- gins(arm.AMOVW, &con, &r1)
- gmove(&r1, t)
- gc.Regfree(&r1)
- return
-
- case gc.TUINT16,
- gc.TUINT8:
- var con gc.Node
- f.Convconst(&con, gc.Types[gc.TUINT32])
- var r1 gc.Node
- gc.Regalloc(&r1, con.Type, t)
- gins(arm.AMOVW, &con, &r1)
- gmove(&r1, t)
- gc.Regfree(&r1)
- return
- }
-
- f = &con
- ft = gc.Simsimtype(con.Type)
-
- // constants can't move directly to memory
- if gc.Ismem(t) && !gc.Is64(t.Type) {
- goto hard
- }
- }
-
- // value -> value copy, only one memory operand.
- // figure out the instruction to use.
- // break out of switch for one-instruction gins.
- // goto rdst for "destination must be register".
- // goto hard for "convert to cvt type first".
- // otherwise handle and return.
-
- switch uint32(ft)<<16 | uint32(tt) {
- default:
- // should not happen
- gc.Fatalf("gmove %v -> %v", f, t)
- return
-
- /*
- * integer copy and truncate
- */
- case gc.TINT8<<16 | gc.TINT8: // same size
- if !gc.Ismem(f) {
- a = arm.AMOVB
- break
- }
- fallthrough
-
- case gc.TUINT8<<16 | gc.TINT8,
- gc.TINT16<<16 | gc.TINT8, // truncate
- gc.TUINT16<<16 | gc.TINT8,
- gc.TINT32<<16 | gc.TINT8,
- gc.TUINT32<<16 | gc.TINT8:
- a = arm.AMOVBS
-
- case gc.TUINT8<<16 | gc.TUINT8:
- if !gc.Ismem(f) {
- a = arm.AMOVB
- break
- }
- fallthrough
-
- case gc.TINT8<<16 | gc.TUINT8,
- gc.TINT16<<16 | gc.TUINT8,
- gc.TUINT16<<16 | gc.TUINT8,
- gc.TINT32<<16 | gc.TUINT8,
- gc.TUINT32<<16 | gc.TUINT8:
- a = arm.AMOVBU
-
- case gc.TINT64<<16 | gc.TINT8, // truncate low word
- gc.TUINT64<<16 | gc.TINT8:
- a = arm.AMOVBS
-
- goto trunc64
-
- case gc.TINT64<<16 | gc.TUINT8,
- gc.TUINT64<<16 | gc.TUINT8:
- a = arm.AMOVBU
- goto trunc64
-
- case gc.TINT16<<16 | gc.TINT16: // same size
- if !gc.Ismem(f) {
- a = arm.AMOVH
- break
- }
- fallthrough
-
- case gc.TUINT16<<16 | gc.TINT16,
- gc.TINT32<<16 | gc.TINT16, // truncate
- gc.TUINT32<<16 | gc.TINT16:
- a = arm.AMOVHS
-
- case gc.TUINT16<<16 | gc.TUINT16:
- if !gc.Ismem(f) {
- a = arm.AMOVH
- break
- }
- fallthrough
-
- case gc.TINT16<<16 | gc.TUINT16,
- gc.TINT32<<16 | gc.TUINT16,
- gc.TUINT32<<16 | gc.TUINT16:
- a = arm.AMOVHU
-
- case gc.TINT64<<16 | gc.TINT16, // truncate low word
- gc.TUINT64<<16 | gc.TINT16:
- a = arm.AMOVHS
-
- goto trunc64
-
- case gc.TINT64<<16 | gc.TUINT16,
- gc.TUINT64<<16 | gc.TUINT16:
- a = arm.AMOVHU
- goto trunc64
-
- case gc.TINT32<<16 | gc.TINT32, // same size
- gc.TINT32<<16 | gc.TUINT32,
- gc.TUINT32<<16 | gc.TINT32,
- gc.TUINT32<<16 | gc.TUINT32:
- a = arm.AMOVW
-
- case gc.TINT64<<16 | gc.TINT32, // truncate
- gc.TUINT64<<16 | gc.TINT32,
- gc.TINT64<<16 | gc.TUINT32,
- gc.TUINT64<<16 | gc.TUINT32:
- var flo gc.Node
- var fhi gc.Node
- split64(f, &flo, &fhi)
-
- var r1 gc.Node
- gc.Regalloc(&r1, t.Type, nil)
- gins(arm.AMOVW, &flo, &r1)
- gins(arm.AMOVW, &r1, t)
- gc.Regfree(&r1)
- splitclean()
- return
-
- case gc.TINT64<<16 | gc.TINT64, // same size
- gc.TINT64<<16 | gc.TUINT64,
- gc.TUINT64<<16 | gc.TINT64,
- gc.TUINT64<<16 | gc.TUINT64:
- var fhi gc.Node
- var flo gc.Node
- split64(f, &flo, &fhi)
-
- var tlo gc.Node
- var thi gc.Node
- split64(t, &tlo, &thi)
- var r1 gc.Node
- gc.Regalloc(&r1, flo.Type, nil)
- var r2 gc.Node
- gc.Regalloc(&r2, fhi.Type, nil)
- gins(arm.AMOVW, &flo, &r1)
- gins(arm.AMOVW, &fhi, &r2)
- gins(arm.AMOVW, &r1, &tlo)
- gins(arm.AMOVW, &r2, &thi)
- gc.Regfree(&r1)
- gc.Regfree(&r2)
- splitclean()
- splitclean()
- return
-
- /*
- * integer up-conversions
- */
- case gc.TINT8<<16 | gc.TINT16, // sign extend int8
- gc.TINT8<<16 | gc.TUINT16,
- gc.TINT8<<16 | gc.TINT32,
- gc.TINT8<<16 | gc.TUINT32:
- a = arm.AMOVBS
-
- goto rdst
-
- case gc.TINT8<<16 | gc.TINT64, // convert via int32
- gc.TINT8<<16 | gc.TUINT64:
- cvt = gc.Types[gc.TINT32]
-
- goto hard
-
- case gc.TUINT8<<16 | gc.TINT16, // zero extend uint8
- gc.TUINT8<<16 | gc.TUINT16,
- gc.TUINT8<<16 | gc.TINT32,
- gc.TUINT8<<16 | gc.TUINT32:
- a = arm.AMOVBU
-
- goto rdst
-
- case gc.TUINT8<<16 | gc.TINT64, // convert via uint32
- gc.TUINT8<<16 | gc.TUINT64:
- cvt = gc.Types[gc.TUINT32]
-
- goto hard
-
- case gc.TINT16<<16 | gc.TINT32, // sign extend int16
- gc.TINT16<<16 | gc.TUINT32:
- a = arm.AMOVHS
-
- goto rdst
-
- case gc.TINT16<<16 | gc.TINT64, // convert via int32
- gc.TINT16<<16 | gc.TUINT64:
- cvt = gc.Types[gc.TINT32]
-
- goto hard
-
- case gc.TUINT16<<16 | gc.TINT32, // zero extend uint16
- gc.TUINT16<<16 | gc.TUINT32:
- a = arm.AMOVHU
-
- goto rdst
-
- case gc.TUINT16<<16 | gc.TINT64, // convert via uint32
- gc.TUINT16<<16 | gc.TUINT64:
- cvt = gc.Types[gc.TUINT32]
-
- goto hard
-
- case gc.TINT32<<16 | gc.TINT64, // sign extend int32
- gc.TINT32<<16 | gc.TUINT64:
- var tlo gc.Node
- var thi gc.Node
- split64(t, &tlo, &thi)
-
- var r1 gc.Node
- gc.Regalloc(&r1, tlo.Type, nil)
- var r2 gc.Node
- gc.Regalloc(&r2, thi.Type, nil)
- gmove(f, &r1)
- p1 := gins(arm.AMOVW, &r1, &r2)
- p1.From.Type = obj.TYPE_SHIFT
- p1.From.Offset = 2<<5 | 31<<7 | int64(r1.Reg)&15 // r1->31
- p1.From.Reg = 0
-
- //print("gmove: %v\n", p1);
- gins(arm.AMOVW, &r1, &tlo)
-
- gins(arm.AMOVW, &r2, &thi)
- gc.Regfree(&r1)
- gc.Regfree(&r2)
- splitclean()
- return
-
- case gc.TUINT32<<16 | gc.TINT64, // zero extend uint32
- gc.TUINT32<<16 | gc.TUINT64:
- var thi gc.Node
- var tlo gc.Node
- split64(t, &tlo, &thi)
-
- gmove(f, &tlo)
- var r1 gc.Node
- gc.Regalloc(&r1, thi.Type, nil)
- gins(arm.AMOVW, ncon(0), &r1)
- gins(arm.AMOVW, &r1, &thi)
- gc.Regfree(&r1)
- splitclean()
- return
-
- // case CASE(TFLOAT64, TUINT64):
- /*
- * float to integer
- */
- case gc.TFLOAT32<<16 | gc.TINT8,
- gc.TFLOAT32<<16 | gc.TUINT8,
- gc.TFLOAT32<<16 | gc.TINT16,
- gc.TFLOAT32<<16 | gc.TUINT16,
- gc.TFLOAT32<<16 | gc.TINT32,
- gc.TFLOAT32<<16 | gc.TUINT32,
-
- // case CASE(TFLOAT32, TUINT64):
-
- gc.TFLOAT64<<16 | gc.TINT8,
- gc.TFLOAT64<<16 | gc.TUINT8,
- gc.TFLOAT64<<16 | gc.TINT16,
- gc.TFLOAT64<<16 | gc.TUINT16,
- gc.TFLOAT64<<16 | gc.TINT32,
- gc.TFLOAT64<<16 | gc.TUINT32:
- fa := arm.AMOVF
-
- a := arm.AMOVFW
- if ft == gc.TFLOAT64 {
- fa = arm.AMOVD
- a = arm.AMOVDW
- }
-
- ta := arm.AMOVW
- switch tt {
- case gc.TINT8:
- ta = arm.AMOVBS
-
- case gc.TUINT8:
- ta = arm.AMOVBU
-
- case gc.TINT16:
- ta = arm.AMOVHS
-
- case gc.TUINT16:
- ta = arm.AMOVHU
- }
-
- var r1 gc.Node
- gc.Regalloc(&r1, gc.Types[ft], f)
- var r2 gc.Node
- gc.Regalloc(&r2, gc.Types[tt], t)
- gins(fa, f, &r1) // load to fpu
- p1 := gins(a, &r1, &r1) // convert to w
- switch tt {
- case gc.TUINT8,
- gc.TUINT16,
- gc.TUINT32:
- p1.Scond |= arm.C_UBIT
- }
-
- gins(arm.AMOVW, &r1, &r2) // copy to cpu
- gins(ta, &r2, t) // store
- gc.Regfree(&r1)
- gc.Regfree(&r2)
- return
-
- /*
- * integer to float
- */
- case gc.TINT8<<16 | gc.TFLOAT32,
- gc.TUINT8<<16 | gc.TFLOAT32,
- gc.TINT16<<16 | gc.TFLOAT32,
- gc.TUINT16<<16 | gc.TFLOAT32,
- gc.TINT32<<16 | gc.TFLOAT32,
- gc.TUINT32<<16 | gc.TFLOAT32,
- gc.TINT8<<16 | gc.TFLOAT64,
- gc.TUINT8<<16 | gc.TFLOAT64,
- gc.TINT16<<16 | gc.TFLOAT64,
- gc.TUINT16<<16 | gc.TFLOAT64,
- gc.TINT32<<16 | gc.TFLOAT64,
- gc.TUINT32<<16 | gc.TFLOAT64:
- fa := arm.AMOVW
-
- switch ft {
- case gc.TINT8:
- fa = arm.AMOVBS
-
- case gc.TUINT8:
- fa = arm.AMOVBU
-
- case gc.TINT16:
- fa = arm.AMOVHS
-
- case gc.TUINT16:
- fa = arm.AMOVHU
- }
-
- a := arm.AMOVWF
- ta := arm.AMOVF
- if tt == gc.TFLOAT64 {
- a = arm.AMOVWD
- ta = arm.AMOVD
- }
-
- var r1 gc.Node
- gc.Regalloc(&r1, gc.Types[ft], f)
- var r2 gc.Node
- gc.Regalloc(&r2, gc.Types[tt], t)
- gins(fa, f, &r1) // load to cpu
- gins(arm.AMOVW, &r1, &r2) // copy to fpu
- p1 := gins(a, &r2, &r2) // convert
- switch ft {
- case gc.TUINT8,
- gc.TUINT16,
- gc.TUINT32:
- p1.Scond |= arm.C_UBIT
- }
-
- gins(ta, &r2, t) // store
- gc.Regfree(&r1)
- gc.Regfree(&r2)
- return
-
- case gc.TUINT64<<16 | gc.TFLOAT32,
- gc.TUINT64<<16 | gc.TFLOAT64:
- gc.Fatalf("gmove UINT64, TFLOAT not implemented")
- return
-
- /*
- * float to float
- */
- case gc.TFLOAT32<<16 | gc.TFLOAT32:
- a = arm.AMOVF
-
- case gc.TFLOAT64<<16 | gc.TFLOAT64:
- a = arm.AMOVD
-
- case gc.TFLOAT32<<16 | gc.TFLOAT64:
- var r1 gc.Node
- gc.Regalloc(&r1, gc.Types[gc.TFLOAT64], t)
- gins(arm.AMOVF, f, &r1)
- gins(arm.AMOVFD, &r1, &r1)
- gins(arm.AMOVD, &r1, t)
- gc.Regfree(&r1)
- return
-
- case gc.TFLOAT64<<16 | gc.TFLOAT32:
- var r1 gc.Node
- gc.Regalloc(&r1, gc.Types[gc.TFLOAT64], t)
- gins(arm.AMOVD, f, &r1)
- gins(arm.AMOVDF, &r1, &r1)
- gins(arm.AMOVF, &r1, t)
- gc.Regfree(&r1)
- return
- }
-
- gins(a, f, t)
- return
-
- // TODO(kaib): we almost always require a register dest anyway, this can probably be
- // removed.
- // requires register destination
-rdst:
- {
- gc.Regalloc(&r1, t.Type, t)
-
- gins(a, f, &r1)
- gmove(&r1, t)
- gc.Regfree(&r1)
- return
- }
-
- // requires register intermediate
-hard:
- gc.Regalloc(&r1, cvt, t)
-
- gmove(f, &r1)
- gmove(&r1, t)
- gc.Regfree(&r1)
- return
-
- // truncate 64 bit integer
-trunc64:
- var fhi gc.Node
- var flo gc.Node
- split64(f, &flo, &fhi)
-
- gc.Regalloc(&r1, t.Type, nil)
- gins(a, &flo, &r1)
- gins(a, &r1, t)
- gc.Regfree(&r1)
- splitclean()
- return
-}
-
-func samaddr(f *gc.Node, t *gc.Node) bool {
- if f.Op != t.Op {
- return false
- }
-
- switch f.Op {
- case gc.OREGISTER:
- if f.Reg != t.Reg {
- break
- }
- return true
- }
-
- return false
-}
-
-/*
- * generate one instruction:
- * as f, t
- */
-func gins(as obj.As, f *gc.Node, t *gc.Node) *obj.Prog {
- // Node nod;
- // int32 v;
-
- if f != nil && f.Op == gc.OINDEX {
- gc.Fatalf("gins OINDEX not implemented")
- }
-
- // gc.Regalloc(&nod, ®node, Z);
- // v = constnode.vconst;
- // gc.Cgen(f->right, &nod);
- // constnode.vconst = v;
- // idx.reg = nod.reg;
- // gc.Regfree(&nod);
- if t != nil && t.Op == gc.OINDEX {
- gc.Fatalf("gins OINDEX not implemented")
- }
-
- // gc.Regalloc(&nod, ®node, Z);
- // v = constnode.vconst;
- // gc.Cgen(t->right, &nod);
- // constnode.vconst = v;
- // idx.reg = nod.reg;
- // gc.Regfree(&nod);
-
- p := gc.Prog(as)
- gc.Naddr(&p.From, f)
- gc.Naddr(&p.To, t)
-
- switch as {
- case arm.ABL:
- if p.To.Type == obj.TYPE_REG {
- p.To.Type = obj.TYPE_MEM
- }
-
- case arm.ACMP, arm.ACMPF, arm.ACMPD:
- if t != nil {
- if f.Op != gc.OREGISTER {
- /* generate a comparison
- TODO(kaib): one of the args can actually be a small constant. relax the constraint and fix call sites.
- */
- gc.Fatalf("bad operands to gcmp")
- }
- p.From = p.To
- p.To = obj.Addr{}
- raddr(f, p)
- }
-
- case arm.AMULU:
- if f != nil && f.Op != gc.OREGISTER {
- gc.Fatalf("bad operands to mul")
- }
-
- case arm.AMOVW:
- if (p.From.Type == obj.TYPE_MEM || p.From.Type == obj.TYPE_ADDR || p.From.Type == obj.TYPE_CONST) && (p.To.Type == obj.TYPE_MEM || p.To.Type == obj.TYPE_ADDR) {
- gc.Fatalf("gins double memory")
- }
-
- case arm.AADD:
- if p.To.Type == obj.TYPE_MEM {
- gc.Fatalf("gins arith to mem")
- }
-
- case arm.ARSB:
- if p.From.Type == obj.TYPE_NONE {
- gc.Fatalf("rsb with no from")
- }
- }
-
- if gc.Debug['g'] != 0 {
- fmt.Printf("%v\n", p)
- }
- return p
-}
-
-/*
- * insert n into reg slot of p
- */
-func raddr(n *gc.Node, p *obj.Prog) {
- var a obj.Addr
- gc.Naddr(&a, n)
- if a.Type != obj.TYPE_REG {
- if n != nil {
- gc.Fatalf("bad in raddr: %v", n.Op)
- } else {
- gc.Fatalf("bad in raddr: <null>")
- }
- p.Reg = 0
- } else {
- p.Reg = a.Reg
- }
-}
-
-/* generate a constant shift
- * arm encodes a shift by 32 as 0, thus asking for 0 shift is illegal.
- */
-func gshift(as obj.As, lhs *gc.Node, stype int32, sval int32, rhs *gc.Node) *obj.Prog {
- if sval <= 0 || sval > 32 {
- gc.Fatalf("bad shift value: %d", sval)
- }
-
- sval = sval & 0x1f
-
- p := gins(as, nil, rhs)
- p.From.Type = obj.TYPE_SHIFT
- p.From.Offset = int64(stype) | int64(sval)<<7 | int64(lhs.Reg)&15
- return p
-}
-
-/* generate a register shift
- */
-func gregshift(as obj.As, lhs *gc.Node, stype int32, reg *gc.Node, rhs *gc.Node) *obj.Prog {
- p := gins(as, nil, rhs)
- p.From.Type = obj.TYPE_SHIFT
- p.From.Offset = int64(stype) | (int64(reg.Reg)&15)<<8 | 1<<4 | int64(lhs.Reg)&15
- return p
-}
-
-/*
- * return Axxx for Oxxx on type t.
- */
-func optoas(op gc.Op, t *gc.Type) obj.As {
- if t == nil {
- gc.Fatalf("optoas: t is nil")
- }
-
- // avoid constant conversions in switches below
- const (
- OMINUS_ = uint32(gc.OMINUS) << 16
- OLSH_ = uint32(gc.OLSH) << 16
- ORSH_ = uint32(gc.ORSH) << 16
- OADD_ = uint32(gc.OADD) << 16
- OSUB_ = uint32(gc.OSUB) << 16
- OMUL_ = uint32(gc.OMUL) << 16
- ODIV_ = uint32(gc.ODIV) << 16
- OMOD_ = uint32(gc.OMOD) << 16
- OOR_ = uint32(gc.OOR) << 16
- OAND_ = uint32(gc.OAND) << 16
- OXOR_ = uint32(gc.OXOR) << 16
- OEQ_ = uint32(gc.OEQ) << 16
- ONE_ = uint32(gc.ONE) << 16
- OLT_ = uint32(gc.OLT) << 16
- OLE_ = uint32(gc.OLE) << 16
- OGE_ = uint32(gc.OGE) << 16
- OGT_ = uint32(gc.OGT) << 16
- OCMP_ = uint32(gc.OCMP) << 16
- OPS_ = uint32(gc.OPS) << 16
- OAS_ = uint32(gc.OAS) << 16
- OSQRT_ = uint32(gc.OSQRT) << 16
- )
-
- a := obj.AXXX
- switch uint32(op)<<16 | uint32(gc.Simtype[t.Etype]) {
- default:
- gc.Fatalf("optoas: no entry %v-%v etype %v simtype %v", op, t, gc.Types[t.Etype], gc.Types[gc.Simtype[t.Etype]])
-
- /* case CASE(OADDR, TPTR32):
- a = ALEAL;
- break;
-
- case CASE(OADDR, TPTR64):
- a = ALEAQ;
- break;
- */
- // TODO(kaib): make sure the conditional branches work on all edge cases
- case OEQ_ | gc.TBOOL,
- OEQ_ | gc.TINT8,
- OEQ_ | gc.TUINT8,
- OEQ_ | gc.TINT16,
- OEQ_ | gc.TUINT16,
- OEQ_ | gc.TINT32,
- OEQ_ | gc.TUINT32,
- OEQ_ | gc.TINT64,
- OEQ_ | gc.TUINT64,
- OEQ_ | gc.TPTR32,
- OEQ_ | gc.TPTR64,
- OEQ_ | gc.TFLOAT32,
- OEQ_ | gc.TFLOAT64:
- a = arm.ABEQ
-
- case ONE_ | gc.TBOOL,
- ONE_ | gc.TINT8,
- ONE_ | gc.TUINT8,
- ONE_ | gc.TINT16,
- ONE_ | gc.TUINT16,
- ONE_ | gc.TINT32,
- ONE_ | gc.TUINT32,
- ONE_ | gc.TINT64,
- ONE_ | gc.TUINT64,
- ONE_ | gc.TPTR32,
- ONE_ | gc.TPTR64,
- ONE_ | gc.TFLOAT32,
- ONE_ | gc.TFLOAT64:
- a = arm.ABNE
-
- case OLT_ | gc.TINT8,
- OLT_ | gc.TINT16,
- OLT_ | gc.TINT32,
- OLT_ | gc.TINT64,
- OLT_ | gc.TFLOAT32,
- OLT_ | gc.TFLOAT64:
- a = arm.ABLT
-
- case OLT_ | gc.TUINT8,
- OLT_ | gc.TUINT16,
- OLT_ | gc.TUINT32,
- OLT_ | gc.TUINT64:
- a = arm.ABLO
-
- case OLE_ | gc.TINT8,
- OLE_ | gc.TINT16,
- OLE_ | gc.TINT32,
- OLE_ | gc.TINT64,
- OLE_ | gc.TFLOAT32,
- OLE_ | gc.TFLOAT64:
- a = arm.ABLE
-
- case OLE_ | gc.TUINT8,
- OLE_ | gc.TUINT16,
- OLE_ | gc.TUINT32,
- OLE_ | gc.TUINT64:
- a = arm.ABLS
-
- case OGT_ | gc.TINT8,
- OGT_ | gc.TINT16,
- OGT_ | gc.TINT32,
- OGT_ | gc.TINT64,
- OGT_ | gc.TFLOAT32,
- OGT_ | gc.TFLOAT64:
- a = arm.ABGT
-
- case OGT_ | gc.TUINT8,
- OGT_ | gc.TUINT16,
- OGT_ | gc.TUINT32,
- OGT_ | gc.TUINT64:
- a = arm.ABHI
-
- case OGE_ | gc.TINT8,
- OGE_ | gc.TINT16,
- OGE_ | gc.TINT32,
- OGE_ | gc.TINT64,
- OGE_ | gc.TFLOAT32,
- OGE_ | gc.TFLOAT64:
- a = arm.ABGE
-
- case OGE_ | gc.TUINT8,
- OGE_ | gc.TUINT16,
- OGE_ | gc.TUINT32,
- OGE_ | gc.TUINT64:
- a = arm.ABHS
-
- case OCMP_ | gc.TBOOL,
- OCMP_ | gc.TINT8,
- OCMP_ | gc.TUINT8,
- OCMP_ | gc.TINT16,
- OCMP_ | gc.TUINT16,
- OCMP_ | gc.TINT32,
- OCMP_ | gc.TUINT32,
- OCMP_ | gc.TPTR32:
- a = arm.ACMP
-
- case OCMP_ | gc.TFLOAT32:
- a = arm.ACMPF
-
- case OCMP_ | gc.TFLOAT64:
- a = arm.ACMPD
-
- case OPS_ | gc.TFLOAT32,
- OPS_ | gc.TFLOAT64:
- a = arm.ABVS
-
- case OAS_ | gc.TBOOL:
- a = arm.AMOVB
-
- case OAS_ | gc.TINT8:
- a = arm.AMOVBS
-
- case OAS_ | gc.TUINT8:
- a = arm.AMOVBU
-
- case OAS_ | gc.TINT16:
- a = arm.AMOVHS
-
- case OAS_ | gc.TUINT16:
- a = arm.AMOVHU
-
- case OAS_ | gc.TINT32,
- OAS_ | gc.TUINT32,
- OAS_ | gc.TPTR32:
- a = arm.AMOVW
-
- case OAS_ | gc.TFLOAT32:
- a = arm.AMOVF
-
- case OAS_ | gc.TFLOAT64:
- a = arm.AMOVD
-
- case OADD_ | gc.TINT8,
- OADD_ | gc.TUINT8,
- OADD_ | gc.TINT16,
- OADD_ | gc.TUINT16,
- OADD_ | gc.TINT32,
- OADD_ | gc.TUINT32,
- OADD_ | gc.TPTR32:
- a = arm.AADD
-
- case OADD_ | gc.TFLOAT32:
- a = arm.AADDF
-
- case OADD_ | gc.TFLOAT64:
- a = arm.AADDD
-
- case OSUB_ | gc.TINT8,
- OSUB_ | gc.TUINT8,
- OSUB_ | gc.TINT16,
- OSUB_ | gc.TUINT16,
- OSUB_ | gc.TINT32,
- OSUB_ | gc.TUINT32,
- OSUB_ | gc.TPTR32:
- a = arm.ASUB
-
- case OSUB_ | gc.TFLOAT32:
- a = arm.ASUBF
-
- case OSUB_ | gc.TFLOAT64:
- a = arm.ASUBD
-
- case OMINUS_ | gc.TINT8,
- OMINUS_ | gc.TUINT8,
- OMINUS_ | gc.TINT16,
- OMINUS_ | gc.TUINT16,
- OMINUS_ | gc.TINT32,
- OMINUS_ | gc.TUINT32,
- OMINUS_ | gc.TPTR32:
- a = arm.ARSB
-
- case OAND_ | gc.TINT8,
- OAND_ | gc.TUINT8,
- OAND_ | gc.TINT16,
- OAND_ | gc.TUINT16,
- OAND_ | gc.TINT32,
- OAND_ | gc.TUINT32,
- OAND_ | gc.TPTR32:
- a = arm.AAND
-
- case OOR_ | gc.TINT8,
- OOR_ | gc.TUINT8,
- OOR_ | gc.TINT16,
- OOR_ | gc.TUINT16,
- OOR_ | gc.TINT32,
- OOR_ | gc.TUINT32,
- OOR_ | gc.TPTR32:
- a = arm.AORR
-
- case OXOR_ | gc.TINT8,
- OXOR_ | gc.TUINT8,
- OXOR_ | gc.TINT16,
- OXOR_ | gc.TUINT16,
- OXOR_ | gc.TINT32,
- OXOR_ | gc.TUINT32,
- OXOR_ | gc.TPTR32:
- a = arm.AEOR
-
- case OLSH_ | gc.TINT8,
- OLSH_ | gc.TUINT8,
- OLSH_ | gc.TINT16,
- OLSH_ | gc.TUINT16,
- OLSH_ | gc.TINT32,
- OLSH_ | gc.TUINT32,
- OLSH_ | gc.TPTR32:
- a = arm.ASLL
-
- case ORSH_ | gc.TUINT8,
- ORSH_ | gc.TUINT16,
- ORSH_ | gc.TUINT32,
- ORSH_ | gc.TPTR32:
- a = arm.ASRL
-
- case ORSH_ | gc.TINT8,
- ORSH_ | gc.TINT16,
- ORSH_ | gc.TINT32:
- a = arm.ASRA
-
- case OMUL_ | gc.TUINT8,
- OMUL_ | gc.TUINT16,
- OMUL_ | gc.TUINT32,
- OMUL_ | gc.TPTR32:
- a = arm.AMULU
-
- case OMUL_ | gc.TINT8,
- OMUL_ | gc.TINT16,
- OMUL_ | gc.TINT32:
- a = arm.AMUL
-
- case OMUL_ | gc.TFLOAT32:
- a = arm.AMULF
-
- case OMUL_ | gc.TFLOAT64:
- a = arm.AMULD
-
- case ODIV_ | gc.TUINT8,
- ODIV_ | gc.TUINT16,
- ODIV_ | gc.TUINT32,
- ODIV_ | gc.TPTR32:
- a = arm.ADIVU
-
- case ODIV_ | gc.TINT8,
- ODIV_ | gc.TINT16,
- ODIV_ | gc.TINT32:
- a = arm.ADIV
-
- case OMOD_ | gc.TUINT8,
- OMOD_ | gc.TUINT16,
- OMOD_ | gc.TUINT32,
- OMOD_ | gc.TPTR32:
- a = arm.AMODU
-
- case OMOD_ | gc.TINT8,
- OMOD_ | gc.TINT16,
- OMOD_ | gc.TINT32:
- a = arm.AMOD
-
- // case CASE(OEXTEND, TINT16):
- // a = ACWD;
- // break;
-
- // case CASE(OEXTEND, TINT32):
- // a = ACDQ;
- // break;
-
- // case CASE(OEXTEND, TINT64):
- // a = ACQO;
- // break;
-
- case ODIV_ | gc.TFLOAT32:
- a = arm.ADIVF
-
- case ODIV_ | gc.TFLOAT64:
- a = arm.ADIVD
-
- case OSQRT_ | gc.TFLOAT64:
- a = arm.ASQRTD
- }
-
- return a
-}
-
-const (
- ODynam = 1 << 0
- OPtrto = 1 << 1
-)
-
-var clean [20]gc.Node
-
-var cleani int = 0
-
-func sudoclean() {
- if clean[cleani-1].Op != gc.OEMPTY {
- gc.Regfree(&clean[cleani-1])
- }
- if clean[cleani-2].Op != gc.OEMPTY {
- gc.Regfree(&clean[cleani-2])
- }
- cleani -= 2
-}
-
-func dotaddable(n *gc.Node, n1 *gc.Node) bool {
- if n.Op != gc.ODOT {
- return false
- }
-
- var oary [10]int64
- var nn *gc.Node
- o := gc.Dotoffset(n, oary[:], &nn)
- if nn != nil && nn.Addable && o == 1 && oary[0] >= 0 {
- *n1 = *nn
- n1.Type = n.Type
- n1.Xoffset += oary[0]
- return true
- }
-
- return false
-}
-
-/*
- * generate code to compute address of n,
- * a reference to a (perhaps nested) field inside
- * an array or struct.
- * return 0 on failure, 1 on success.
- * on success, leaves usable address in a.
- *
- * caller is responsible for calling sudoclean
- * after successful sudoaddable,
- * to release the register used for a.
- */
-func sudoaddable(as obj.As, n *gc.Node, a *obj.Addr) bool {
- if n.Type == nil {
- return false
- }
-
- *a = obj.Addr{}
-
- switch n.Op {
- case gc.OLITERAL:
- if !gc.Isconst(n, gc.CTINT) {
- break
- }
- v := n.Int64()
- if v >= 32000 || v <= -32000 {
- break
- }
- switch as {
- default:
- return false
-
- case arm.AADD,
- arm.ASUB,
- arm.AAND,
- arm.AORR,
- arm.AEOR,
- arm.AMOVB,
- arm.AMOVBS,
- arm.AMOVBU,
- arm.AMOVH,
- arm.AMOVHS,
- arm.AMOVHU,
- arm.AMOVW:
- break
- }
-
- cleani += 2
- reg := &clean[cleani-1]
- reg1 := &clean[cleani-2]
- reg.Op = gc.OEMPTY
- reg1.Op = gc.OEMPTY
- gc.Naddr(a, n)
- return true
-
- case gc.ODOT,
- gc.ODOTPTR:
- cleani += 2
- reg := &clean[cleani-1]
- reg1 := &clean[cleani-2]
- reg.Op = gc.OEMPTY
- reg1.Op = gc.OEMPTY
- var nn *gc.Node
- var oary [10]int64
- o := gc.Dotoffset(n, oary[:], &nn)
- if nn == nil {
- sudoclean()
- return false
- }
-
- if nn.Addable && o == 1 && oary[0] >= 0 {
- // directly addressable set of DOTs
- n1 := *nn
-
- n1.Type = n.Type
- n1.Xoffset += oary[0]
- gc.Naddr(a, &n1)
- return true
- }
-
- gc.Regalloc(reg, gc.Types[gc.Tptr], nil)
- n1 := *reg
- n1.Op = gc.OINDREG
- if oary[0] >= 0 {
- gc.Agen(nn, reg)
- n1.Xoffset = oary[0]
- } else {
- gc.Cgen(nn, reg)
- gc.Cgen_checknil(reg)
- n1.Xoffset = -(oary[0] + 1)
- }
-
- for i := 1; i < o; i++ {
- if oary[i] >= 0 {
- gc.Fatalf("can't happen")
- }
- gins(arm.AMOVW, &n1, reg)
- gc.Cgen_checknil(reg)
- n1.Xoffset = -(oary[i] + 1)
- }
-
- a.Type = obj.TYPE_NONE
- a.Name = obj.NAME_NONE
- n1.Type = n.Type
- gc.Naddr(a, &n1)
- return true
-
- case gc.OINDEX:
- return false
- }
-
- return false
-}
diff --git a/src/cmd/compile/internal/arm/peep.go b/src/cmd/compile/internal/arm/peep.go
deleted file mode 100644
index e1c8e4d..0000000
--- a/src/cmd/compile/internal/arm/peep.go
+++ /dev/null
@@ -1,1734 +0,0 @@
-// Inferno utils/5c/peep.c
-// http://code.google.com/p/inferno-os/source/browse/utils/5c/peep.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth at terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth at terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// Portions Copyright © 2009 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-package arm
-
-import (
- "cmd/compile/internal/gc"
- "cmd/internal/obj"
- "cmd/internal/obj/arm"
- "fmt"
-)
-
-var gactive uint32
-
-// UNUSED
-func peep(firstp *obj.Prog) {
- g := gc.Flowstart(firstp, nil)
- if g == nil {
- return
- }
- gactive = 0
-
- var p *obj.Prog
- var t int
-loop1:
- if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
- gc.Dumpit("loop1", g.Start, 0)
- }
-
- t = 0
- for r := g.Start; r != nil; r = r.Link {
- p = r.Prog
- switch p.As {
- /*
- * elide shift into TYPE_SHIFT operand of subsequent instruction
- */
- // if(shiftprop(r)) {
- // excise(r);
- // t++;
- // break;
- // }
- case arm.ASLL,
- arm.ASRL,
- arm.ASRA:
- break
-
- case arm.AMOVB,
- arm.AMOVH,
- arm.AMOVW,
- arm.AMOVF,
- arm.AMOVD:
- if regtyp(&p.From) {
- if p.From.Type == p.To.Type && isfloatreg(&p.From) == isfloatreg(&p.To) {
- if p.Scond == arm.C_SCOND_NONE {
- if copyprop(g, r) {
- excise(r)
- t++
- break
- }
-
- if subprop(r) && copyprop(g, r) {
- excise(r)
- t++
- break
- }
- }
- }
- }
-
- case arm.AMOVHS,
- arm.AMOVHU,
- arm.AMOVBS,
- arm.AMOVBU:
- if p.From.Type == obj.TYPE_REG {
- if shortprop(r) {
- t++
- }
- }
- }
- }
-
- /*
- if(p->scond == C_SCOND_NONE)
- if(regtyp(&p->to))
- if(isdconst(&p->from)) {
- constprop(&p->from, &p->to, r->s1);
- }
- break;
- */
- if t != 0 {
- goto loop1
- }
-
- for r := g.Start; r != nil; r = r.Link {
- p = r.Prog
- switch p.As {
- /*
- * EOR -1,x,y => MVN x,y
- */
- case arm.AEOR:
- if isdconst(&p.From) && p.From.Offset == -1 {
- p.As = arm.AMVN
- p.From.Type = obj.TYPE_REG
- if p.Reg != 0 {
- p.From.Reg = p.Reg
- } else {
- p.From.Reg = p.To.Reg
- }
- p.Reg = 0
- }
- }
- }
-
- for r := g.Start; r != nil; r = r.Link {
- p = r.Prog
- switch p.As {
- case arm.AMOVW,
- arm.AMOVB,
- arm.AMOVBS,
- arm.AMOVBU:
- if p.From.Type == obj.TYPE_MEM && p.From.Offset == 0 {
- xtramodes(g, r, &p.From)
- } else if p.To.Type == obj.TYPE_MEM && p.To.Offset == 0 {
- xtramodes(g, r, &p.To)
- } else {
- continue
- }
- }
- }
-
- // case ACMP:
- // /*
- // * elide CMP $0,x if calculation of x can set condition codes
- // */
- // if(isdconst(&p->from) || p->from.offset != 0)
- // continue;
- // r2 = r->s1;
- // if(r2 == nil)
- // continue;
- // t = r2->prog->as;
- // switch(t) {
- // default:
- // continue;
- // case ABEQ:
- // case ABNE:
- // case ABMI:
- // case ABPL:
- // break;
- // case ABGE:
- // t = ABPL;
- // break;
- // case ABLT:
- // t = ABMI;
- // break;
- // case ABHI:
- // t = ABNE;
- // break;
- // case ABLS:
- // t = ABEQ;
- // break;
- // }
- // r1 = r;
- // do
- // r1 = uniqp(r1);
- // while (r1 != nil && r1->prog->as == ANOP);
- // if(r1 == nil)
- // continue;
- // p1 = r1->prog;
- // if(p1->to.type != TYPE_REG)
- // continue;
- // if(p1->to.reg != p->reg)
- // if(!(p1->as == AMOVW && p1->from.type == TYPE_REG && p1->from.reg == p->reg))
- // continue;
- //
- // switch(p1->as) {
- // default:
- // continue;
- // case AMOVW:
- // if(p1->from.type != TYPE_REG)
- // continue;
- // case AAND:
- // case AEOR:
- // case AORR:
- // case ABIC:
- // case AMVN:
- // case ASUB:
- // case ARSB:
- // case AADD:
- // case AADC:
- // case ASBC:
- // case ARSC:
- // break;
- // }
- // p1->scond |= C_SBIT;
- // r2->prog->as = t;
- // excise(r);
- // continue;
-
- // predicate(g);
-
- gc.Flowend(g)
-}
-
-func regtyp(a *obj.Addr) bool {
- return a.Type == obj.TYPE_REG && (arm.REG_R0 <= a.Reg && a.Reg <= arm.REG_R15 || arm.REG_F0 <= a.Reg && a.Reg <= arm.REG_F15)
-}
-
-/*
- * the idea is to substitute
- * one register for another
- * from one MOV to another
- * MOV a, R0
- * ADD b, R0 / no use of R1
- * MOV R0, R1
- * would be converted to
- * MOV a, R1
- * ADD b, R1
- * MOV R1, R0
- * hopefully, then the former or latter MOV
- * will be eliminated by copy propagation.
- */
-func subprop(r0 *gc.Flow) bool {
- p := r0.Prog
- v1 := &p.From
- if !regtyp(v1) {
- return false
- }
- v2 := &p.To
- if !regtyp(v2) {
- return false
- }
- for r := gc.Uniqp(r0); r != nil; r = gc.Uniqp(r) {
- if gc.Uniqs(r) == nil {
- break
- }
- p = r.Prog
- if p.As == obj.AVARDEF || p.As == obj.AVARKILL {
- continue
- }
- if p.Info.Flags&gc.Call != 0 {
- return false
- }
-
- // TODO(rsc): Whatever invalidated the info should have done this call.
- proginfo(p)
-
- if (p.Info.Flags&gc.CanRegRead != 0) && p.To.Type == obj.TYPE_REG {
- p.Info.Flags |= gc.RegRead
- p.Info.Flags &^= (gc.CanRegRead | gc.RightRead)
- p.Reg = p.To.Reg
- }
-
- switch p.As {
- case arm.AMULLU,
- arm.AMULA,
- arm.AMVN:
- return false
- }
-
- if p.Info.Flags&(gc.RightRead|gc.RightWrite) == gc.RightWrite {
- if p.To.Type == v1.Type {
- if p.To.Reg == v1.Reg {
- if p.Scond == arm.C_SCOND_NONE {
- copysub(&p.To, v1, v2, true)
- if gc.Debug['P'] != 0 {
- fmt.Printf("gotit: %v->%v\n%v", gc.Ctxt.Dconv(v1), gc.Ctxt.Dconv(v2), r.Prog)
- if p.From.Type == v2.Type {
- fmt.Printf(" excise")
- }
- fmt.Printf("\n")
- }
-
- for r = gc.Uniqs(r); r != r0; r = gc.Uniqs(r) {
- p = r.Prog
- copysub(&p.From, v1, v2, true)
- copysub1(p, v1, v2, true)
- copysub(&p.To, v1, v2, true)
- if gc.Debug['P'] != 0 {
- fmt.Printf("%v\n", r.Prog)
- }
- }
-
- v1.Reg, v2.Reg = v2.Reg, v1.Reg
- if gc.Debug['P'] != 0 {
- fmt.Printf("%v last\n", r.Prog)
- }
- return true
- }
- }
- }
- }
-
- if copyau(&p.From, v2) || copyau1(p, v2) || copyau(&p.To, v2) {
- break
- }
- if copysub(&p.From, v1, v2, false) || copysub1(p, v1, v2, false) || copysub(&p.To, v1, v2, false) {
- break
- }
- }
-
- return false
-}
-
-/*
- * The idea is to remove redundant copies.
- * v1->v2 F=0
- * (use v2 s/v2/v1/)*
- * set v1 F=1
- * use v2 return fail
- * -----------------
- * v1->v2 F=0
- * (use v2 s/v2/v1/)*
- * set v1 F=1
- * set v2 return success
- */
-func copyprop(g *gc.Graph, r0 *gc.Flow) bool {
- p := r0.Prog
- v1 := &p.From
- v2 := &p.To
- if copyas(v1, v2) {
- return true
- }
- gactive++
- return copy1(v1, v2, r0.S1, false)
-}
-
-func copy1(v1 *obj.Addr, v2 *obj.Addr, r *gc.Flow, f bool) bool {
- if uint32(r.Active) == gactive {
- if gc.Debug['P'] != 0 {
- fmt.Printf("act set; return 1\n")
- }
- return true
- }
-
- r.Active = int32(gactive)
- if gc.Debug['P'] != 0 {
- fmt.Printf("copy %v->%v f=%v\n", gc.Ctxt.Dconv(v1), gc.Ctxt.Dconv(v2), f)
- }
- for ; r != nil; r = r.S1 {
- p := r.Prog
- if gc.Debug['P'] != 0 {
- fmt.Printf("%v", p)
- }
- if !f && gc.Uniqp(r) == nil {
- f = true
- if gc.Debug['P'] != 0 {
- fmt.Printf("; merge; f=%v", f)
- }
- }
-
- switch t := copyu(p, v2, nil); t {
- case 2: /* rar, can't split */
- if gc.Debug['P'] != 0 {
- fmt.Printf("; %vrar; return 0\n", gc.Ctxt.Dconv(v2))
- }
- return false
-
- case 3: /* set */
- if gc.Debug['P'] != 0 {
- fmt.Printf("; %vset; return 1\n", gc.Ctxt.Dconv(v2))
- }
- return true
-
- case 1, /* used, substitute */
- 4: /* use and set */
- if f {
- if gc.Debug['P'] == 0 {
- return false
- }
- if t == 4 {
- fmt.Printf("; %vused+set and f=%v; return 0\n", gc.Ctxt.Dconv(v2), f)
- } else {
- fmt.Printf("; %vused and f=%v; return 0\n", gc.Ctxt.Dconv(v2), f)
- }
- return false
- }
-
- if copyu(p, v2, v1) != 0 {
- if gc.Debug['P'] != 0 {
- fmt.Printf("; sub fail; return 0\n")
- }
- return false
- }
-
- if gc.Debug['P'] != 0 {
- fmt.Printf("; sub%v/%v", gc.Ctxt.Dconv(v2), gc.Ctxt.Dconv(v1))
- }
- if t == 4 {
- if gc.Debug['P'] != 0 {
- fmt.Printf("; %vused+set; return 1\n", gc.Ctxt.Dconv(v2))
- }
- return true
- }
- }
-
- if !f {
- t := copyu(p, v1, nil)
- if t == 2 || t == 3 || t == 4 {
- f = true
- if gc.Debug['P'] != 0 {
- fmt.Printf("; %vset and !f; f=%v", gc.Ctxt.Dconv(v1), f)
- }
- }
- }
-
- if gc.Debug['P'] != 0 {
- fmt.Printf("\n")
- }
- if r.S2 != nil {
- if !copy1(v1, v2, r.S2, f) {
- return false
- }
- }
- }
- return true
-}
-
-// UNUSED
-/*
- * The idea is to remove redundant constants.
- * $c1->v1
- * ($c1->v2 s/$c1/v1)*
- * set v1 return
- * The v1->v2 should be eliminated by copy propagation.
- */
-func constprop(c1 *obj.Addr, v1 *obj.Addr, r *gc.Flow) {
- if gc.Debug['P'] != 0 {
- fmt.Printf("constprop %v->%v\n", gc.Ctxt.Dconv(c1), gc.Ctxt.Dconv(v1))
- }
- var p *obj.Prog
- for ; r != nil; r = r.S1 {
- p = r.Prog
- if gc.Debug['P'] != 0 {
- fmt.Printf("%v", p)
- }
- if gc.Uniqp(r) == nil {
- if gc.Debug['P'] != 0 {
- fmt.Printf("; merge; return\n")
- }
- return
- }
-
- if p.As == arm.AMOVW && copyas(&p.From, c1) {
- if gc.Debug['P'] != 0 {
- fmt.Printf("; sub%v/%v", gc.Ctxt.Dconv(&p.From), gc.Ctxt.Dconv(v1))
- }
- p.From = *v1
- } else if copyu(p, v1, nil) > 1 {
- if gc.Debug['P'] != 0 {
- fmt.Printf("; %vset; return\n", gc.Ctxt.Dconv(v1))
- }
- return
- }
-
- if gc.Debug['P'] != 0 {
- fmt.Printf("\n")
- }
- if r.S2 != nil {
- constprop(c1, v1, r.S2)
- }
- }
-}
-
-/*
- * shortprop eliminates redundant zero/sign extensions.
- *
- * MOVBS x, R
- * <no use R>
- * MOVBS R, R'
- *
- * changed to
- *
- * MOVBS x, R
- * ...
- * MOVB R, R' (compiled to mov)
- *
- * MOVBS above can be a MOVBS, MOVBU, MOVHS or MOVHU.
- */
-func shortprop(r *gc.Flow) bool {
- p := r.Prog
- r1 := findpre(r, &p.From)
- if r1 == nil {
- return false
- }
-
- p1 := r1.Prog
- if p1.As == p.As {
- // Two consecutive extensions.
- goto gotit
- }
-
- if p1.As == arm.AMOVW && isdconst(&p1.From) && p1.From.Offset >= 0 && p1.From.Offset < 128 {
- // Loaded an immediate.
- goto gotit
- }
-
- return false
-
-gotit:
- if gc.Debug['P'] != 0 {
- fmt.Printf("shortprop\n%v\n%v", p1, p)
- }
- switch p.As {
- case arm.AMOVBS,
- arm.AMOVBU:
- p.As = arm.AMOVB
-
- case arm.AMOVHS,
- arm.AMOVHU:
- p.As = arm.AMOVH
- }
-
- if gc.Debug['P'] != 0 {
- fmt.Printf(" => %v\n", obj.Aconv(p.As))
- }
- return true
-}
-
-// UNUSED
-/*
- * ASLL x,y,w
- * .. (not use w, not set x y w)
- * AXXX w,a,b (a != w)
- * .. (not use w)
- * (set w)
- * ----------- changed to
- * ..
- * AXXX (x<<y),a,b
- * ..
- */
-func shiftprop(r *gc.Flow) bool {
- p := r.Prog
- if p.To.Type != obj.TYPE_REG {
- if gc.Debug['P'] != 0 {
- fmt.Printf("\tBOTCH: result not reg; FAILURE\n")
- }
- return false
- }
-
- n := p.To.Reg
- var a obj.Addr
- if p.Reg != 0 && p.Reg != p.To.Reg {
- a.Type = obj.TYPE_REG
- a.Reg = p.Reg
- }
-
- if gc.Debug['P'] != 0 {
- fmt.Printf("shiftprop\n%v", p)
- }
- r1 := r
- var p1 *obj.Prog
- for {
- /* find first use of shift result; abort if shift operands or result are changed */
- r1 = gc.Uniqs(r1)
-
- if r1 == nil {
- if gc.Debug['P'] != 0 {
- fmt.Printf("\tbranch; FAILURE\n")
- }
- return false
- }
-
- if gc.Uniqp(r1) == nil {
- if gc.Debug['P'] != 0 {
- fmt.Printf("\tmerge; FAILURE\n")
- }
- return false
- }
-
- p1 = r1.Prog
- if gc.Debug['P'] != 0 {
- fmt.Printf("\n%v", p1)
- }
- switch copyu(p1, &p.To, nil) {
- case 0: /* not used or set */
- if (p.From.Type == obj.TYPE_REG && copyu(p1, &p.From, nil) > 1) || (a.Type == obj.TYPE_REG && copyu(p1, &a, nil) > 1) {
- if gc.Debug['P'] != 0 {
- fmt.Printf("\targs modified; FAILURE\n")
- }
- return false
- }
-
- continue
- case 3: /* set, not used */
- {
- if gc.Debug['P'] != 0 {
- fmt.Printf("\tBOTCH: noref; FAILURE\n")
- }
- return false
- }
- }
-
- break
- }
-
- /* check whether substitution can be done */
- switch p1.As {
- default:
- if gc.Debug['P'] != 0 {
- fmt.Printf("\tnon-dpi; FAILURE\n")
- }
- return false
-
- case arm.AAND,
- arm.AEOR,
- arm.AADD,
- arm.AADC,
- arm.AORR,
- arm.ASUB,
- arm.ASBC,
- arm.ARSB,
- arm.ARSC:
- if p1.Reg == n || (p1.Reg == 0 && p1.To.Type == obj.TYPE_REG && p1.To.Reg == n) {
- if p1.From.Type != obj.TYPE_REG {
- if gc.Debug['P'] != 0 {
- fmt.Printf("\tcan't swap; FAILURE\n")
- }
- return false
- }
-
- p1.Reg = p1.From.Reg
- p1.From.Reg = n
- switch p1.As {
- case arm.ASUB:
- p1.As = arm.ARSB
-
- case arm.ARSB:
- p1.As = arm.ASUB
-
- case arm.ASBC:
- p1.As = arm.ARSC
-
- case arm.ARSC:
- p1.As = arm.ASBC
- }
-
- if gc.Debug['P'] != 0 {
- fmt.Printf("\t=>%v", p1)
- }
- }
- fallthrough
-
- case arm.ABIC,
- arm.ATST,
- arm.ACMP,
- arm.ACMN:
- if p1.Reg == n {
- if gc.Debug['P'] != 0 {
- fmt.Printf("\tcan't swap; FAILURE\n")
- }
- return false
- }
-
- if p1.Reg == 0 && p1.To.Reg == n {
- if gc.Debug['P'] != 0 {
- fmt.Printf("\tshift result used twice; FAILURE\n")
- }
- return false
- }
-
- // case AMVN:
- if p1.From.Type == obj.TYPE_SHIFT {
- if gc.Debug['P'] != 0 {
- fmt.Printf("\tshift result used in shift; FAILURE\n")
- }
- return false
- }
-
- if p1.From.Type != obj.TYPE_REG || p1.From.Reg != n {
- if gc.Debug['P'] != 0 {
- fmt.Printf("\tBOTCH: where is it used?; FAILURE\n")
- }
- return false
- }
- }
-
- /* check whether shift result is used subsequently */
- p2 := p1
-
- if p1.To.Reg != n {
- var p1 *obj.Prog
- for {
- r1 = gc.Uniqs(r1)
- if r1 == nil {
- if gc.Debug['P'] != 0 {
- fmt.Printf("\tinconclusive; FAILURE\n")
- }
- return false
- }
-
- p1 = r1.Prog
- if gc.Debug['P'] != 0 {
- fmt.Printf("\n%v", p1)
- }
- switch copyu(p1, &p.To, nil) {
- case 0: /* not used or set */
- continue
-
- case 3: /* set, not used */
- break
-
- default: /* used */
- if gc.Debug['P'] != 0 {
- fmt.Printf("\treused; FAILURE\n")
- }
- return false
- }
-
- break
- }
- }
-
- /* make the substitution */
- p2.From.Reg = 0
- o := p.Reg
- if o == 0 {
- o = p.To.Reg
- }
- o &= 15
-
- switch p.From.Type {
- case obj.TYPE_CONST:
- o |= int16(p.From.Offset&0x1f) << 7
-
- case obj.TYPE_REG:
- o |= 1<<4 | (p.From.Reg&15)<<8
- }
-
- switch p.As {
- case arm.ASLL:
- o |= 0 << 5
-
- case arm.ASRL:
- o |= 1 << 5
-
- case arm.ASRA:
- o |= 2 << 5
- }
-
- p2.From = obj.Addr{}
- p2.From.Type = obj.TYPE_SHIFT
- p2.From.Offset = int64(o)
- if gc.Debug['P'] != 0 {
- fmt.Printf("\t=>%v\tSUCCEED\n", p2)
- }
- return true
-}
-
-/*
- * findpre returns the last instruction mentioning v
- * before r. It must be a set, and there must be
- * a unique path from that instruction to r.
- */
-func findpre(r *gc.Flow, v *obj.Addr) *gc.Flow {
- var r1 *gc.Flow
-
- for r1 = gc.Uniqp(r); r1 != nil; r, r1 = r1, gc.Uniqp(r1) {
- if gc.Uniqs(r1) != r {
- return nil
- }
- switch copyu(r1.Prog, v, nil) {
- case 1, /* used */
- 2: /* read-alter-rewrite */
- return nil
-
- case 3, /* set */
- 4: /* set and used */
- return r1
- }
- }
-
- return nil
-}
-
-/*
- * findinc finds ADD instructions with a constant
- * argument which falls within the immed_12 range.
- */
-func findinc(r *gc.Flow, r2 *gc.Flow, v *obj.Addr) *gc.Flow {
- var r1 *gc.Flow
- var p *obj.Prog
-
- for r1 = gc.Uniqs(r); r1 != nil && r1 != r2; r, r1 = r1, gc.Uniqs(r1) {
- if gc.Uniqp(r1) != r {
- return nil
- }
- switch copyu(r1.Prog, v, nil) {
- case 0: /* not touched */
- continue
-
- case 4: /* set and used */
- p = r1.Prog
-
- if p.As == arm.AADD {
- if isdconst(&p.From) {
- if p.From.Offset > -4096 && p.From.Offset < 4096 {
- return r1
- }
- }
- }
- fallthrough
-
- default:
- return nil
- }
- }
-
- return nil
-}
-
-func nochange(r *gc.Flow, r2 *gc.Flow, p *obj.Prog) bool {
- if r == r2 {
- return true
- }
- n := int(0)
- var a [3]obj.Addr
- if p.Reg != 0 && p.Reg != p.To.Reg {
- a[n].Type = obj.TYPE_REG
- a[n].Reg = p.Reg
- n++
- }
-
- switch p.From.Type {
- case obj.TYPE_SHIFT:
- a[n].Type = obj.TYPE_REG
- a[n].Reg = int16(arm.REG_R0 + (p.From.Offset & 0xf))
- n++
- fallthrough
-
- case obj.TYPE_REG:
- a[n].Type = obj.TYPE_REG
- a[n].Reg = p.From.Reg
- n++
- }
-
- if n == 0 {
- return true
- }
- var i int
- for ; r != nil && r != r2; r = gc.Uniqs(r) {
- p = r.Prog
- for i = 0; i < n; i++ {
- if copyu(p, &a[i], nil) > 1 {
- return false
- }
- }
- }
-
- return true
-}
-
-func findu1(r *gc.Flow, v *obj.Addr) bool {
- for ; r != nil; r = r.S1 {
- if r.Active != 0 {
- return false
- }
- r.Active = 1
- switch copyu(r.Prog, v, nil) {
- case 1, /* used */
- 2, /* read-alter-rewrite */
- 4: /* set and used */
- return true
-
- case 3: /* set */
- return false
- }
-
- if r.S2 != nil {
- if findu1(r.S2, v) {
- return true
- }
- }
- }
-
- return false
-}
-
-func finduse(g *gc.Graph, r *gc.Flow, v *obj.Addr) bool {
- for r1 := g.Start; r1 != nil; r1 = r1.Link {
- r1.Active = 0
- }
- return findu1(r, v)
-}
-
-/*
- * xtramodes enables the ARM post increment and
- * shift offset addressing modes to transform
- * MOVW 0(R3),R1
- * ADD $4,R3,R3
- * into
- * MOVW.P 4(R3),R1
- * and
- * ADD R0,R1
- * MOVBU 0(R1),R0
- * into
- * MOVBU R0<<0(R1),R0
- */
-func xtramodes(g *gc.Graph, r *gc.Flow, a *obj.Addr) bool {
- p := r.Prog
- v := *a
- v.Type = obj.TYPE_REG
- r1 := findpre(r, &v)
- if r1 != nil {
- p1 := r1.Prog
- if p1.To.Type == obj.TYPE_REG && p1.To.Reg == v.Reg {
- switch p1.As {
- case arm.AADD:
- if p1.Scond&arm.C_SBIT != 0 {
- // avoid altering ADD.S/ADC sequences.
- break
- }
-
- if p1.From.Type == obj.TYPE_REG || (p1.From.Type == obj.TYPE_SHIFT && p1.From.Offset&(1<<4) == 0 && ((p.As != arm.AMOVB && p.As != arm.AMOVBS) || (a == &p.From && p1.From.Offset&^0xf == 0))) || ((p1.From.Type == obj.TYPE_ADDR || p1.From.Type == obj.TYPE_CONST) && p1.From.Offset > -4096 && p1.From.Offset < 4096) {
- if nochange(gc.Uniqs(r1), r, p1) {
- if a != &p.From || v.Reg != p.To.Reg {
- if finduse(g, r.S1, &v) {
- if p1.Reg == 0 || p1.Reg == v.Reg {
- /* pre-indexing */
- p.Scond |= arm.C_WBIT
- } else {
- return false
- }
- }
- }
-
- switch p1.From.Type {
- /* register offset */
- case obj.TYPE_REG:
- if gc.Nacl {
- return false
- }
- *a = obj.Addr{}
- a.Type = obj.TYPE_SHIFT
- a.Offset = int64(p1.From.Reg) & 15
-
- /* scaled register offset */
- case obj.TYPE_SHIFT:
- if gc.Nacl {
- return false
- }
- *a = obj.Addr{}
- a.Type = obj.TYPE_SHIFT
- fallthrough
-
- /* immediate offset */
- case obj.TYPE_CONST,
- obj.TYPE_ADDR:
- a.Offset = p1.From.Offset
- }
-
- if p1.Reg != 0 {
- a.Reg = p1.Reg
- }
- excise(r1)
- return true
- }
- }
-
- case arm.AMOVW:
- if p1.From.Type == obj.TYPE_REG {
- r2 := findinc(r1, r, &p1.From)
- if r2 != nil {
- var r3 *gc.Flow
- for r3 = gc.Uniqs(r2); r3.Prog.As == obj.ANOP; r3 = gc.Uniqs(r3) {
- }
- if r3 == r {
- /* post-indexing */
- p1 := r2.Prog
-
- a.Reg = p1.To.Reg
- a.Offset = p1.From.Offset
- p.Scond |= arm.C_PBIT
- if !finduse(g, r, &r1.Prog.To) {
- excise(r1)
- }
- excise(r2)
- return true
- }
- }
- }
- }
- }
- }
-
- if a != &p.From || a.Reg != p.To.Reg {
- r1 := findinc(r, nil, &v)
- if r1 != nil {
- /* post-indexing */
- p1 := r1.Prog
-
- a.Offset = p1.From.Offset
- p.Scond |= arm.C_PBIT
- excise(r1)
- return true
- }
- }
-
- return false
-}
-
-/*
- * return
- * 1 if v only used (and substitute),
- * 2 if read-alter-rewrite
- * 3 if set
- * 4 if set and used
- * 0 otherwise (not touched)
- */
-func copyu(p *obj.Prog, v *obj.Addr, s *obj.Addr) int {
- switch p.As {
- default:
- fmt.Printf("copyu: can't find %v\n", obj.Aconv(p.As))
- return 2
-
- case arm.AMOVM:
- if v.Type != obj.TYPE_REG {
- return 0
- }
- if p.From.Type == obj.TYPE_CONST { /* read reglist, read/rar */
- if s != nil {
- if p.From.Offset&(1<<uint(v.Reg)) != 0 {
- return 1
- }
- if copysub(&p.To, v, s, true) {
- return 1
- }
- return 0
- }
-
- if copyau(&p.To, v) {
- if p.Scond&arm.C_WBIT != 0 {
- return 2
- }
- return 1
- }
-
- if p.From.Offset&(1<<uint(v.Reg)) != 0 {
- return 1 /* read/rar, write reglist */
- }
- } else {
- if s != nil {
- if p.To.Offset&(1<<uint(v.Reg)) != 0 {
- return 1
- }
- if copysub(&p.From, v, s, true) {
- return 1
- }
- return 0
- }
-
- if copyau(&p.From, v) {
- if p.Scond&arm.C_WBIT != 0 {
- return 2
- }
- if p.To.Offset&(1<<uint(v.Reg)) != 0 {
- return 4
- }
- return 1
- }
-
- if p.To.Offset&(1<<uint(v.Reg)) != 0 {
- return 3
- }
- }
-
- return 0
-
- case obj.ANOP, /* read,, write */
- arm.ASQRTD,
- arm.AMOVW,
- arm.AMOVF,
- arm.AMOVD,
- arm.AMOVH,
- arm.AMOVHS,
- arm.AMOVHU,
- arm.AMOVB,
- arm.AMOVBS,
- arm.AMOVBU,
- arm.AMOVFW,
- arm.AMOVWF,
- arm.AMOVDW,
- arm.AMOVWD,
- arm.AMOVFD,
- arm.AMOVDF:
- if p.Scond&(arm.C_WBIT|arm.C_PBIT) != 0 {
- if v.Type == obj.TYPE_REG {
- if p.From.Type == obj.TYPE_MEM || p.From.Type == obj.TYPE_SHIFT {
- if p.From.Reg == v.Reg {
- return 2
- }
- } else {
- if p.To.Reg == v.Reg {
- return 2
- }
- }
- }
- }
-
- if s != nil {
- if copysub(&p.From, v, s, true) {
- return 1
- }
- if !copyas(&p.To, v) {
- if copysub(&p.To, v, s, true) {
- return 1
- }
- }
- return 0
- }
-
- if copyas(&p.To, v) {
- if p.Scond != arm.C_SCOND_NONE {
- return 2
- }
- if copyau(&p.From, v) {
- return 4
- }
- return 3
- }
-
- if copyau(&p.From, v) {
- return 1
- }
- if copyau(&p.To, v) {
- return 1
- }
- return 0
-
- case arm.AMULLU, /* read, read, write, write */
- arm.AMULL,
- arm.AMULA,
- arm.AMVN:
- return 2
-
- case arm.AADD, /* read, read, write */
- arm.AADC,
- arm.ASUB,
- arm.ASBC,
- arm.ARSB,
- arm.ASLL,
- arm.ASRL,
- arm.ASRA,
- arm.AORR,
- arm.AAND,
- arm.AEOR,
- arm.AMUL,
- arm.AMULU,
- arm.ADIV,
- arm.ADIVU,
- arm.AMOD,
- arm.AMODU,
- arm.AADDF,
- arm.AADDD,
- arm.ASUBF,
- arm.ASUBD,
- arm.AMULF,
- arm.AMULD,
- arm.ADIVF,
- arm.ADIVD,
- obj.ACHECKNIL,
- /* read */
- arm.ACMPF, /* read, read, */
- arm.ACMPD,
- arm.ACMP,
- arm.ACMN,
- arm.ATST:
- /* read,, */
- if s != nil {
- if copysub(&p.From, v, s, true) {
- return 1
- }
- if copysub1(p, v, s, true) {
- return 1
- }
- if !copyas(&p.To, v) {
- if copysub(&p.To, v, s, true) {
- return 1
- }
- }
- return 0
- }
-
- if copyas(&p.To, v) {
- if p.Scond != arm.C_SCOND_NONE {
- return 2
- }
- if p.Reg == 0 {
- p.Reg = p.To.Reg
- }
- if copyau(&p.From, v) {
- return 4
- }
- if copyau1(p, v) {
- return 4
- }
- return 3
- }
-
- if copyau(&p.From, v) {
- return 1
- }
- if copyau1(p, v) {
- return 1
- }
- if copyau(&p.To, v) {
- return 1
- }
- return 0
-
- case arm.ABEQ, /* read, read */
- arm.ABNE,
- arm.ABCS,
- arm.ABHS,
- arm.ABCC,
- arm.ABLO,
- arm.ABMI,
- arm.ABPL,
- arm.ABVS,
- arm.ABVC,
- arm.ABHI,
- arm.ABLS,
- arm.ABGE,
- arm.ABLT,
- arm.ABGT,
- arm.ABLE:
- if s != nil {
- if copysub(&p.From, v, s, true) {
- return 1
- }
- if copysub1(p, v, s, true) {
- return 1
- }
- return 0
- }
-
- if copyau(&p.From, v) {
- return 1
- }
- if copyau1(p, v) {
- return 1
- }
- return 0
-
- case arm.AB: /* funny */
- if s != nil {
- if copysub(&p.To, v, s, true) {
- return 1
- }
- return 0
- }
- if copyau(&p.To, v) {
- return 1
- }
- return 0
-
- case obj.ARET: /* funny */
- if s != nil {
- return 1
- }
- return 3
-
- case arm.ABL: /* funny */
- if v.Type == obj.TYPE_REG {
- // TODO(rsc): REG_R0 and REG_F0 used to be
- // (when register numbers started at 0) exregoffset and exfregoffset,
- // which are unset entirely.
- // It's strange that this handles R0 and F0 differently from the other
- // registers. Possible failure to optimize?
- if arm.REG_R0 < v.Reg && v.Reg <= arm.REGEXT {
- return 2
- }
- if v.Reg == arm.REGARG {
- return 2
- }
- if arm.REG_F0 < v.Reg && v.Reg <= arm.FREGEXT {
- return 2
- }
- }
-
- if p.From.Type == obj.TYPE_REG && v.Type == obj.TYPE_REG && p.From.Reg == v.Reg {
- return 2
- }
-
- if s != nil {
- if copysub(&p.To, v, s, true) {
- return 1
- }
- return 0
- }
-
- if copyau(&p.To, v) {
- return 4
- }
- return 3
-
- // R0 is zero, used by DUFFZERO, cannot be substituted.
- // R1 is ptr to memory, used and set, cannot be substituted.
- case obj.ADUFFZERO:
- if v.Type == obj.TYPE_REG {
- if v.Reg == arm.REG_R0 {
- return 1
- }
- if v.Reg == arm.REG_R0+1 {
- return 2
- }
- }
-
- return 0
-
- // R0 is scratch, set by DUFFCOPY, cannot be substituted.
- // R1, R2 areptr to src, dst, used and set, cannot be substituted.
- case obj.ADUFFCOPY:
- if v.Type == obj.TYPE_REG {
- if v.Reg == arm.REG_R0 {
- return 3
- }
- if v.Reg == arm.REG_R0+1 || v.Reg == arm.REG_R0+2 {
- return 2
- }
- }
-
- return 0
-
- case obj.ATEXT: /* funny */
- if v.Type == obj.TYPE_REG {
- if v.Reg == arm.REGARG {
- return 3
- }
- }
- return 0
-
- case obj.APCDATA,
- obj.AFUNCDATA,
- obj.AVARDEF,
- obj.AVARKILL,
- obj.AVARLIVE,
- obj.AUSEFIELD:
- return 0
- }
-}
-
-/*
- * direct reference,
- * could be set/use depending on
- * semantics
- */
-func copyas(a *obj.Addr, v *obj.Addr) bool {
- if regtyp(v) {
- if a.Type == v.Type {
- if a.Reg == v.Reg {
- return true
- }
- }
- } else if v.Type == obj.TYPE_CONST { /* for constprop */
- if a.Type == v.Type {
- if a.Name == v.Name {
- if a.Sym == v.Sym {
- if a.Reg == v.Reg {
- if a.Offset == v.Offset {
- return true
- }
- }
- }
- }
- }
- }
-
- return false
-}
-
-func sameaddr(a *obj.Addr, v *obj.Addr) bool {
- if a.Type != v.Type {
- return false
- }
- if regtyp(v) && a.Reg == v.Reg {
- return true
- }
-
- // TODO(rsc): Change v->type to v->name and enable.
- //if(v->type == NAME_AUTO || v->type == NAME_PARAM) {
- // if(v->offset == a->offset)
- // return 1;
- //}
- return false
-}
-
-/*
- * either direct or indirect
- */
-func copyau(a *obj.Addr, v *obj.Addr) bool {
- if copyas(a, v) {
- return true
- }
- if v.Type == obj.TYPE_REG {
- if a.Type == obj.TYPE_ADDR && a.Reg != 0 {
- if a.Reg == v.Reg {
- return true
- }
- } else if a.Type == obj.TYPE_MEM {
- if a.Reg == v.Reg {
- return true
- }
- } else if a.Type == obj.TYPE_REGREG || a.Type == obj.TYPE_REGREG2 {
- if a.Reg == v.Reg {
- return true
- }
- if a.Offset == int64(v.Reg) {
- return true
- }
- } else if a.Type == obj.TYPE_SHIFT {
- if a.Offset&0xf == int64(v.Reg-arm.REG_R0) {
- return true
- }
- if (a.Offset&(1<<4) != 0) && (a.Offset>>8)&0xf == int64(v.Reg-arm.REG_R0) {
- return true
- }
- }
- }
-
- return false
-}
-
-/*
- * compare v to the center
- * register in p (p->reg)
- */
-func copyau1(p *obj.Prog, v *obj.Addr) bool {
- if v.Type == obj.TYPE_REG && v.Reg == 0 {
- return false
- }
- return p.Reg == v.Reg
-}
-
-// copysub substitute s for v in a.
-// copysub returns true on failure to substitute.
-// TODO(dfc) remove unused return value, remove calls with f=false as they do nothing.
-func copysub(a *obj.Addr, v *obj.Addr, s *obj.Addr, f bool) bool {
- if f && copyau(a, v) {
- if a.Type == obj.TYPE_SHIFT {
- if a.Offset&0xf == int64(v.Reg-arm.REG_R0) {
- a.Offset = a.Offset&^0xf | int64(s.Reg)&0xf
- }
- if (a.Offset&(1<<4) != 0) && (a.Offset>>8)&0xf == int64(v.Reg-arm.REG_R0) {
- a.Offset = a.Offset&^(0xf<<8) | (int64(s.Reg)&0xf)<<8
- }
- } else if a.Type == obj.TYPE_REGREG || a.Type == obj.TYPE_REGREG2 {
- if a.Offset == int64(v.Reg) {
- a.Offset = int64(s.Reg)
- }
- if a.Reg == v.Reg {
- a.Reg = s.Reg
- }
- } else {
- a.Reg = s.Reg
- }
- }
- return false
-}
-
-// TODO(dfc) remove unused return value, remove calls with f=false as they do nothing.
-func copysub1(p1 *obj.Prog, v *obj.Addr, s *obj.Addr, f bool) bool {
- if f && copyau1(p1, v) {
- p1.Reg = s.Reg
- }
- return false
-}
-
-var predinfo = []struct {
- opcode obj.As
- notopcode obj.As
- scond int
- notscond int
-}{
- {arm.ABEQ, arm.ABNE, 0x0, 0x1},
- {arm.ABNE, arm.ABEQ, 0x1, 0x0},
- {arm.ABCS, arm.ABCC, 0x2, 0x3},
- {arm.ABHS, arm.ABLO, 0x2, 0x3},
- {arm.ABCC, arm.ABCS, 0x3, 0x2},
- {arm.ABLO, arm.ABHS, 0x3, 0x2},
- {arm.ABMI, arm.ABPL, 0x4, 0x5},
- {arm.ABPL, arm.ABMI, 0x5, 0x4},
- {arm.ABVS, arm.ABVC, 0x6, 0x7},
- {arm.ABVC, arm.ABVS, 0x7, 0x6},
- {arm.ABHI, arm.ABLS, 0x8, 0x9},
- {arm.ABLS, arm.ABHI, 0x9, 0x8},
- {arm.ABGE, arm.ABLT, 0xA, 0xB},
- {arm.ABLT, arm.ABGE, 0xB, 0xA},
- {arm.ABGT, arm.ABLE, 0xC, 0xD},
- {arm.ABLE, arm.ABGT, 0xD, 0xC},
-}
-
-type Joininfo struct {
- start *gc.Flow
- last *gc.Flow
- end *gc.Flow
- len int
-}
-
-const (
- Join = iota
- Split
- End
- Branch
- Setcond
- Toolong
-)
-
-const (
- Falsecond = iota
- Truecond
- Delbranch
- Keepbranch
-)
-
-func isbranch(p *obj.Prog) bool {
- return (arm.ABEQ <= p.As) && (p.As <= arm.ABLE)
-}
-
-func predicable(p *obj.Prog) bool {
- switch p.As {
- case obj.ANOP,
- obj.AXXX,
- obj.AGLOBL,
- obj.ATEXT,
- arm.AWORD:
- return false
- }
-
- if isbranch(p) {
- return false
- }
- return true
-}
-
-/*
- * Depends on an analysis of the encodings performed by 5l.
- * These seem to be all of the opcodes that lead to the "S" bit
- * being set in the instruction encodings.
- *
- * C_SBIT may also have been set explicitly in p->scond.
- */
-func modifiescpsr(p *obj.Prog) bool {
- switch p.As {
- case arm.AMULLU,
- arm.AMULA,
- arm.AMULU,
- arm.ADIVU,
- arm.ATEQ,
- arm.ACMN,
- arm.ATST,
- arm.ACMP,
- arm.AMUL,
- arm.ADIV,
- arm.AMOD,
- arm.AMODU,
- arm.ABL:
- return true
- }
-
- if p.Scond&arm.C_SBIT != 0 {
- return true
- }
- return false
-}
-
-/*
- * Find the maximal chain of instructions starting with r which could
- * be executed conditionally
- */
-func joinsplit(r *gc.Flow, j *Joininfo) int {
- j.start = r
- j.last = r
- j.len = 0
- for {
- if r.P2 != nil && (r.P1 != nil || r.P2.P2link != nil) {
- j.end = r
- return Join
- }
-
- if r.S1 != nil && r.S2 != nil {
- j.end = r
- return Split
- }
-
- j.last = r
- if r.Prog.As != obj.ANOP {
- j.len++
- }
- if r.S1 == nil && r.S2 == nil {
- j.end = r.Link
- return End
- }
-
- if r.S2 != nil {
- j.end = r.S2
- return Branch
- }
-
- if modifiescpsr(r.Prog) {
- j.end = r.S1
- return Setcond
- }
-
- r = r.S1
- if j.len >= 4 {
- break
- }
- }
-
- j.end = r
- return Toolong
-}
-
-func successor(r *gc.Flow) *gc.Flow {
- if r.S1 != nil {
- return r.S1
- }
- return r.S2
-}
-
-func applypred(rstart *gc.Flow, j *Joininfo, cond int, branch int) {
- if j.len == 0 {
- return
- }
- var pred int
- if cond == Truecond {
- pred = predinfo[rstart.Prog.As-arm.ABEQ].scond
- } else {
- pred = predinfo[rstart.Prog.As-arm.ABEQ].notscond
- }
-
- for r := j.start; ; r = successor(r) {
- if r.Prog.As == arm.AB {
- if r != j.last || branch == Delbranch {
- excise(r)
- } else {
- if cond == Truecond {
- r.Prog.As = predinfo[rstart.Prog.As-arm.ABEQ].opcode
- } else {
- r.Prog.As = predinfo[rstart.Prog.As-arm.ABEQ].notopcode
- }
- }
- } else if predicable(r.Prog) {
- r.Prog.Scond = uint8(int(r.Prog.Scond&^arm.C_SCOND) | pred)
- }
- if r.S1 != r.Link {
- r.S1 = r.Link
- r.Link.P1 = r
- }
-
- if r == j.last {
- break
- }
- }
-}
-
-func predicate(g *gc.Graph) {
- var t1 int
- var t2 int
- var j1 Joininfo
- var j2 Joininfo
-
- for r := g.Start; r != nil; r = r.Link {
- if isbranch(r.Prog) {
- t1 = joinsplit(r.S1, &j1)
- t2 = joinsplit(r.S2, &j2)
- if j1.last.Link != j2.start {
- continue
- }
- if j1.end == j2.end {
- if (t1 == Branch && (t2 == Join || t2 == Setcond)) || (t2 == Join && (t1 == Join || t1 == Setcond)) {
- applypred(r, &j1, Falsecond, Delbranch)
- applypred(r, &j2, Truecond, Delbranch)
- excise(r)
- continue
- }
- }
-
- if t1 == End || t1 == Branch {
- applypred(r, &j1, Falsecond, Keepbranch)
- excise(r)
- continue
- }
- }
- }
-}
-
-func isdconst(a *obj.Addr) bool {
- return a.Type == obj.TYPE_CONST
-}
-
-func isfloatreg(a *obj.Addr) bool {
- return arm.REG_F0 <= a.Reg && a.Reg <= arm.REG_F15
-}
-
-func stackaddr(a *obj.Addr) bool {
- return regtyp(a) && a.Reg == arm.REGSP
-}
-
-func smallindir(a *obj.Addr, reg *obj.Addr) bool {
- return reg.Type == obj.TYPE_REG && a.Type == obj.TYPE_MEM && a.Reg == reg.Reg && 0 <= a.Offset && a.Offset < 4096
-}
-
-func excise(r *gc.Flow) {
- p := r.Prog
- obj.Nopout(p)
-}
diff --git a/src/cmd/compile/internal/arm/prog.go b/src/cmd/compile/internal/arm/prog.go
index f69548a..1dd7c98 100644
--- a/src/cmd/compile/internal/arm/prog.go
+++ b/src/cmd/compile/internal/arm/prog.go
@@ -21,14 +21,13 @@ const (
// Instructions not generated need not be listed.
// As an exception to that rule, we typically write down all the
// size variants of an operation even if we just use a subset.
-var progtable = [arm.ALAST & obj.AMask]obj.ProgInfo{
+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.ACHECKNIL: {Flags: gc.LeftRead},
obj.AVARDEF: {Flags: gc.Pseudo | gc.RightWrite},
obj.AVARKILL: {Flags: gc.Pseudo | gc.RightWrite},
obj.AVARLIVE: {Flags: gc.Pseudo | gc.LeftRead},
@@ -65,6 +64,7 @@ var progtable = [arm.ALAST & obj.AMask]obj.ProgInfo{
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},
@@ -79,6 +79,8 @@ var progtable = [arm.ALAST & obj.AMask]obj.ProgInfo{
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.
@@ -133,9 +135,8 @@ var progtable = [arm.ALAST & obj.AMask]obj.ProgInfo{
obj.ARET: {Flags: gc.Break},
}
-func proginfo(p *obj.Prog) {
- info := &p.Info
- *info = progtable[p.As&obj.AMask]
+func proginfo(p *obj.Prog) gc.ProgInfo {
+ info := progtable[p.As&obj.AMask]
if info.Flags == 0 {
gc.Fatalf("unknown instruction %v", p)
}
@@ -154,11 +155,5 @@ func proginfo(p *obj.Prog) {
info.Flags |= gc.RightRead
}
- switch p.As {
- case arm.ADIV,
- arm.ADIVU,
- arm.AMOD,
- arm.AMODU:
- info.Regset |= RtoB(arm.REG_R12)
- }
+ return info
}
diff --git a/src/cmd/compile/internal/arm/reg.go b/src/cmd/compile/internal/arm/reg.go
deleted file mode 100644
index 2313bc4..0000000
--- a/src/cmd/compile/internal/arm/reg.go
+++ /dev/null
@@ -1,136 +0,0 @@
-// Inferno utils/5c/reg.c
-// http://code.google.com/p/inferno-os/source/browse/utils/5c/reg.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth at terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth at terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// Portions Copyright © 2009 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-package arm
-
-import "cmd/internal/obj/arm"
-import "cmd/compile/internal/gc"
-
-const (
- NREGVAR = 32
-)
-
-var regname = []string{
- ".R0",
- ".R1",
- ".R2",
- ".R3",
- ".R4",
- ".R5",
- ".R6",
- ".R7",
- ".R8",
- ".R9",
- ".R10",
- ".R11",
- ".R12",
- ".R13",
- ".R14",
- ".R15",
- ".F0",
- ".F1",
- ".F2",
- ".F3",
- ".F4",
- ".F5",
- ".F6",
- ".F7",
- ".F8",
- ".F9",
- ".F10",
- ".F11",
- ".F12",
- ".F13",
- ".F14",
- ".F15",
-}
-
-func regnames(n *int) []string {
- *n = NREGVAR
- return regname
-}
-
-func excludedregs() uint64 {
- return RtoB(arm.REGSP) | RtoB(arm.REGLINK) | RtoB(arm.REGPC)
-}
-
-func doregbits(r int) uint64 {
- return 0
-}
-
-/*
- * bit reg
- * 0 R0
- * 1 R1
- * ... ...
- * 10 R10
- * 12 R12
- *
- * bit reg
- * 18 F2
- * 19 F3
- * ... ...
- * 31 F15
- */
-func RtoB(r int) uint64 {
- if arm.REG_R0 <= r && r <= arm.REG_R15 {
- if r >= arm.REGTMP-2 && r != arm.REG_R12 { // excluded R9 and R10 for m and g, but not R12
- return 0
- }
- return 1 << uint(r-arm.REG_R0)
- }
-
- if arm.REG_F0 <= r && r <= arm.REG_F15 {
- if r < arm.REG_F2 || r > arm.REG_F0+arm.NFREG-1 {
- return 0
- }
- return 1 << uint((r-arm.REG_F0)+16)
- }
-
- return 0
-}
-
-func BtoR(b uint64) int {
- // TODO Allow R0 and R1, but be careful with a 0 return
- // TODO Allow R9. Only R10 is reserved now (just g, not m).
- b &= 0x11fc // excluded R9 and R10 for m and g, but not R12
- if b == 0 {
- return 0
- }
- return gc.Bitno(b) + arm.REG_R0
-}
-
-func BtoF(b uint64) int {
- b &= 0xfffc0000
- if b == 0 {
- return 0
- }
- return gc.Bitno(b) - 16 + arm.REG_F0
-}
diff --git a/src/cmd/compile/internal/arm/ssa.go b/src/cmd/compile/internal/arm/ssa.go
index 8f466e3..5a69ed3 100644
--- a/src/cmd/compile/internal/arm/ssa.go
+++ b/src/cmd/compile/internal/arm/ssa.go
@@ -5,18 +5,116 @@
package arm
import (
+ "fmt"
+ "math"
+
"cmd/compile/internal/gc"
"cmd/compile/internal/ssa"
"cmd/internal/obj"
"cmd/internal/obj/arm"
)
-var ssaRegToReg = []int16{
- arm.REG_R0,
- arm.REG_R1,
- arm.REG_R2,
- arm.REG_R3,
- arm.REGSP, // aka R13
+// loadByType returns the load instruction of the given type.
+func loadByType(t ssa.Type) obj.As {
+ if t.IsFloat() {
+ switch t.Size() {
+ case 4:
+ return arm.AMOVF
+ case 8:
+ return arm.AMOVD
+ }
+ } else {
+ switch t.Size() {
+ case 1:
+ if t.IsSigned() {
+ return arm.AMOVB
+ } else {
+ return arm.AMOVBU
+ }
+ case 2:
+ if t.IsSigned() {
+ return arm.AMOVH
+ } else {
+ return arm.AMOVHU
+ }
+ case 4:
+ return arm.AMOVW
+ }
+ }
+ panic("bad load type")
+}
+
+// storeByType returns the store instruction of the given type.
+func storeByType(t ssa.Type) obj.As {
+ if t.IsFloat() {
+ switch t.Size() {
+ case 4:
+ return arm.AMOVF
+ case 8:
+ return arm.AMOVD
+ }
+ } else {
+ switch t.Size() {
+ case 1:
+ return arm.AMOVB
+ case 2:
+ return arm.AMOVH
+ case 4:
+ return arm.AMOVW
+ }
+ }
+ panic("bad store type")
+}
+
+// shift type is used as Offset in obj.TYPE_SHIFT operands to encode shifted register operands
+type shift int64
+
+// copied from ../../../internal/obj/util.go:/TYPE_SHIFT
+func (v shift) String() string {
+ op := "<<>>->@>"[((v>>5)&3)<<1:]
+ if v&(1<<4) != 0 {
+ // register shift
+ return fmt.Sprintf("R%d%c%cR%d", v&15, op[0], op[1], (v>>8)&15)
+ } else {
+ // constant shift
+ return fmt.Sprintf("R%d%c%c%d", v&15, op[0], op[1], (v>>7)&31)
+ }
+}
+
+// makeshift encodes a register shifted by a constant
+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)
+ p.From.Type = obj.TYPE_SHIFT
+ p.From.Offset = int64(makeshift(r1, typ, s))
+ p.Reg = r0
+ if r != 0 {
+ p.To.Type = obj.TYPE_REG
+ p.To.Reg = r
+ }
+ return p
+}
+
+// makeregshift encodes a register shifted by a register
+func makeregshift(r1 int16, typ int64, r2 int16) shift {
+ return shift(int64(r1&0xf) | typ | int64(r2&0xf)<<8 | 1<<4)
+}
+
+// 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)
+ p.From.Type = obj.TYPE_SHIFT
+ p.From.Offset = int64(makeregshift(r1, typ, r2))
+ p.Reg = r0
+ if r != 0 {
+ p.To.Type = obj.TYPE_REG
+ p.To.Reg = r
+ }
+ return p
}
func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
@@ -26,91 +124,528 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
// memory arg needs no code
case ssa.OpArg:
// input args need no code
- case ssa.OpSP, ssa.OpSB:
+ case ssa.OpSP, ssa.OpSB, ssa.OpGetG:
+ // nothing to do
+ case ssa.OpCopy, ssa.OpARMMOVWconvert, ssa.OpARMMOVWreg:
+ if v.Type.IsMemory() {
+ return
+ }
+ x := v.Args[0].Reg()
+ y := v.Reg()
+ if x == y {
+ return
+ }
+ as := arm.AMOVW
+ if v.Type.IsFloat() {
+ switch v.Type.Size() {
+ case 4:
+ as = arm.AMOVF
+ case 8:
+ as = arm.AMOVD
+ default:
+ panic("bad float size")
+ }
+ }
+ p := gc.Prog(as)
+ p.From.Type = obj.TYPE_REG
+ p.From.Reg = x
+ p.To.Type = obj.TYPE_REG
+ p.To.Reg = y
+ case ssa.OpARMMOVWnop:
+ if v.Reg() != v.Args[0].Reg() {
+ v.Fatalf("input[0] and output not in same register %s", v.LongString())
+ }
// nothing to do
- case ssa.OpCopy:
case ssa.OpLoadReg:
- // TODO: by type
- p := gc.Prog(arm.AMOVW)
- n, off := gc.AutoVar(v.Args[0])
- p.From.Type = obj.TYPE_MEM
- p.From.Node = n
- p.From.Sym = gc.Linksym(n.Sym)
- p.From.Offset = off
- if n.Class == gc.PPARAM || n.Class == gc.PPARAMOUT {
- p.From.Name = obj.NAME_PARAM
- p.From.Offset += n.Xoffset
- } else {
- p.From.Name = obj.NAME_AUTO
+ if v.Type.IsFlags() {
+ v.Fatalf("load flags not implemented: %v", v.LongString())
+ return
}
+ p := gc.Prog(loadByType(v.Type))
+ gc.AddrAuto(&p.From, v.Args[0])
p.To.Type = obj.TYPE_REG
- p.To.Reg = gc.SSARegNum(v)
-
+ p.To.Reg = v.Reg()
+ case ssa.OpPhi:
+ gc.CheckLoweredPhi(v)
case ssa.OpStoreReg:
- // TODO: by type
- p := gc.Prog(arm.AMOVW)
+ if v.Type.IsFlags() {
+ v.Fatalf("store flags not implemented: %v", v.LongString())
+ return
+ }
+ p := gc.Prog(storeByType(v.Type))
p.From.Type = obj.TYPE_REG
- p.From.Reg = gc.SSARegNum(v.Args[0])
- n, off := gc.AutoVar(v)
+ p.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.Node = n
- p.To.Sym = gc.Linksym(n.Sym)
- p.To.Offset = off
- if n.Class == gc.PPARAM || n.Class == gc.PPARAMOUT {
- p.To.Name = obj.NAME_PARAM
- p.To.Offset += n.Xoffset
- } else {
- p.To.Name = obj.NAME_AUTO
- }
- case ssa.OpARMADD:
- r := gc.SSARegNum(v)
- r1 := gc.SSARegNum(v.Args[0])
- r2 := gc.SSARegNum(v.Args[1])
+ p.To.Name = obj.NAME_EXTERN
+ p.To.Sym = obj.Linklookup(gc.Ctxt, "udiv", 0)
+ case ssa.OpARMADD,
+ ssa.OpARMADC,
+ ssa.OpARMSUB,
+ ssa.OpARMSBC,
+ ssa.OpARMRSB,
+ ssa.OpARMAND,
+ ssa.OpARMOR,
+ ssa.OpARMXOR,
+ ssa.OpARMBIC,
+ ssa.OpARMMUL,
+ ssa.OpARMADDF,
+ ssa.OpARMADDD,
+ ssa.OpARMSUBF,
+ ssa.OpARMSUBD,
+ ssa.OpARMMULF,
+ ssa.OpARMMULD,
+ ssa.OpARMDIVF,
+ ssa.OpARMDIVD:
+ r := v.Reg()
+ r1 := v.Args[0].Reg()
+ r2 := v.Args[1].Reg()
+ p := gc.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.OpARMADDS,
+ ssa.OpARMSUBS:
+ r := v.Reg0()
+ r1 := v.Args[0].Reg()
+ r2 := v.Args[1].Reg()
+ p := gc.Prog(v.Op.Asm())
+ p.Scond = arm.C_SBIT
+ 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.OpARMSLL,
+ ssa.OpARMSRL,
+ ssa.OpARMSRA:
+ r := v.Reg()
+ r1 := v.Args[0].Reg()
+ r2 := v.Args[1].Reg()
p := gc.Prog(v.Op.Asm())
p.From.Type = obj.TYPE_REG
- p.From.Reg = r1
- p.Reg = r2
+ p.From.Reg = r2
+ p.Reg = r1
+ p.To.Type = obj.TYPE_REG
+ p.To.Reg = r
+ case ssa.OpARMSRAcond:
+ // ARM shift instructions uses only the low-order byte of the shift amount
+ // generate conditional instructions to deal with large shifts
+ // flag is already set
+ // SRA.HS $31, Rarg0, Rdst // shift 31 bits to get the sign bit
+ // SRA.LO Rarg1, Rarg0, Rdst
+ r := v.Reg()
+ r1 := v.Args[0].Reg()
+ r2 := v.Args[1].Reg()
+ p := gc.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.Scond = arm.C_SCOND_LO
+ 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.OpARMADDconst:
+ case ssa.OpARMADDconst,
+ ssa.OpARMADCconst,
+ ssa.OpARMSUBconst,
+ ssa.OpARMSBCconst,
+ ssa.OpARMRSBconst,
+ ssa.OpARMRSCconst,
+ ssa.OpARMANDconst,
+ ssa.OpARMORconst,
+ ssa.OpARMXORconst,
+ ssa.OpARMBICconst,
+ ssa.OpARMSLLconst,
+ ssa.OpARMSRLconst,
+ ssa.OpARMSRAconst:
p := gc.Prog(v.Op.Asm())
p.From.Type = obj.TYPE_CONST
p.From.Offset = v.AuxInt
- if v.Aux != nil {
- panic("can't handle symbolic constant yet")
- }
- p.Reg = gc.SSARegNum(v.Args[0])
+ p.Reg = v.Args[0].Reg()
+ p.To.Type = obj.TYPE_REG
+ p.To.Reg = v.Reg()
+ case ssa.OpARMADDSconst,
+ ssa.OpARMSUBSconst,
+ ssa.OpARMRSBSconst:
+ p := gc.Prog(v.Op.Asm())
+ p.Scond = arm.C_SBIT
+ 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 = gc.SSARegNum(v)
+ p.To.Reg = v.Reg0()
+ case ssa.OpARMSRRconst:
+ genshift(arm.AMOVW, 0, v.Args[0].Reg(), v.Reg(), arm.SHIFT_RR, v.AuxInt)
+ case ssa.OpARMADDshiftLL,
+ ssa.OpARMADCshiftLL,
+ ssa.OpARMSUBshiftLL,
+ ssa.OpARMSBCshiftLL,
+ ssa.OpARMRSBshiftLL,
+ ssa.OpARMRSCshiftLL,
+ ssa.OpARMANDshiftLL,
+ 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)
+ 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.Scond = arm.C_SBIT
+ case ssa.OpARMADDshiftRL,
+ ssa.OpARMADCshiftRL,
+ ssa.OpARMSUBshiftRL,
+ ssa.OpARMSBCshiftRL,
+ ssa.OpARMRSBshiftRL,
+ ssa.OpARMRSCshiftRL,
+ ssa.OpARMANDshiftRL,
+ 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)
+ 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.Scond = arm.C_SBIT
+ case ssa.OpARMADDshiftRA,
+ ssa.OpARMADCshiftRA,
+ ssa.OpARMSUBshiftRA,
+ ssa.OpARMSBCshiftRA,
+ ssa.OpARMRSBshiftRA,
+ ssa.OpARMRSCshiftRA,
+ ssa.OpARMANDshiftRA,
+ 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)
+ 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.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)
+ case ssa.OpARMMVNshiftLL:
+ genshift(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)
+ case ssa.OpARMMVNshiftRA:
+ genshift(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)
+ case ssa.OpARMMVNshiftRLreg:
+ genregshift(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)
+ case ssa.OpARMADDshiftLLreg,
+ ssa.OpARMADCshiftLLreg,
+ ssa.OpARMSUBshiftLLreg,
+ ssa.OpARMSBCshiftLLreg,
+ ssa.OpARMRSBshiftLLreg,
+ ssa.OpARMRSCshiftLLreg,
+ ssa.OpARMANDshiftLLreg,
+ 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)
+ 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.Scond = arm.C_SBIT
+ case ssa.OpARMADDshiftRLreg,
+ ssa.OpARMADCshiftRLreg,
+ ssa.OpARMSUBshiftRLreg,
+ ssa.OpARMSBCshiftRLreg,
+ ssa.OpARMRSBshiftRLreg,
+ ssa.OpARMRSCshiftRLreg,
+ ssa.OpARMANDshiftRLreg,
+ 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)
+ 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.Scond = arm.C_SBIT
+ case ssa.OpARMADDshiftRAreg,
+ ssa.OpARMADCshiftRAreg,
+ ssa.OpARMSUBshiftRAreg,
+ ssa.OpARMSBCshiftRAreg,
+ ssa.OpARMRSBshiftRAreg,
+ ssa.OpARMRSCshiftRAreg,
+ ssa.OpARMANDshiftRAreg,
+ 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)
+ 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.Scond = arm.C_SBIT
+ case ssa.OpARMHMUL,
+ ssa.OpARMHMULU:
+ // 32-bit high multiplication
+ p := gc.Prog(v.Op.Asm())
+ p.From.Type = obj.TYPE_REG
+ p.From.Reg = v.Args[0].Reg()
+ p.Reg = v.Args[1].Reg()
+ p.To.Type = obj.TYPE_REGREG
+ p.To.Reg = v.Reg()
+ 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.From.Type = obj.TYPE_REG
+ p.From.Reg = v.Args[0].Reg()
+ p.Reg = v.Args[1].Reg()
+ p.To.Type = obj.TYPE_REGREG
+ 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.From.Type = obj.TYPE_REG
+ p.From.Reg = v.Args[0].Reg()
+ p.Reg = v.Args[1].Reg()
+ p.To.Type = obj.TYPE_REGREG2
+ 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.From.Type = obj.TYPE_CONST
p.From.Offset = v.AuxInt
p.To.Type = obj.TYPE_REG
- p.To.Reg = gc.SSARegNum(v)
- case ssa.OpARMCMP:
+ p.To.Reg = v.Reg()
+ case ssa.OpARMMOVFconst,
+ ssa.OpARMMOVDconst:
+ p := gc.Prog(v.Op.Asm())
+ p.From.Type = obj.TYPE_FCONST
+ p.From.Val = math.Float64frombits(uint64(v.AuxInt))
+ p.To.Type = obj.TYPE_REG
+ p.To.Reg = v.Reg()
+ case ssa.OpARMCMP,
+ ssa.OpARMCMN,
+ ssa.OpARMTST,
+ ssa.OpARMTEQ,
+ ssa.OpARMCMPF,
+ ssa.OpARMCMPD:
p := gc.Prog(v.Op.Asm())
p.From.Type = obj.TYPE_REG
// Special layout in ARM assembly
// Comparing to x86, the operands of ARM's CMP are reversed.
- p.From.Reg = gc.SSARegNum(v.Args[1])
- p.Reg = gc.SSARegNum(v.Args[0])
- case ssa.OpARMMOVWload:
+ p.From.Reg = v.Args[1].Reg()
+ p.Reg = v.Args[0].Reg()
+ case ssa.OpARMCMPconst,
+ ssa.OpARMCMNconst,
+ ssa.OpARMTSTconst,
+ ssa.OpARMTEQconst:
+ // Special layout in ARM assembly
+ p := gc.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.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)
+ case ssa.OpARMCMPshiftRL:
+ genshift(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)
+ case ssa.OpARMCMPshiftLLreg:
+ genregshift(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)
+ case ssa.OpARMCMPshiftRAreg:
+ genregshift(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.From.Type = obj.TYPE_ADDR
+ p.To.Type = obj.TYPE_REG
+ p.To.Reg = v.Reg()
+
+ var wantreg string
+ // MOVW $sym+off(base), R
+ // the assembler expands it as the following:
+ // - base is SP: add constant offset to SP (R13)
+ // when constant is large, tmp register (R11) may be used
+ // - base is SB: load external address from constant pool (use relocation)
+ switch v.Aux.(type) {
+ default:
+ v.Fatalf("aux is of unknown type %T", v.Aux)
+ case *ssa.ExternSymbol:
+ wantreg = "SB"
+ gc.AddAux(&p.From, v)
+ case *ssa.ArgSymbol, *ssa.AutoSymbol:
+ wantreg = "SP"
+ gc.AddAux(&p.From, v)
+ case nil:
+ // No sym, just MOVW $off(SP), R
+ wantreg = "SP"
+ p.From.Reg = arm.REGSP
+ p.From.Offset = v.AuxInt
+ }
+ if reg := v.Args[0].RegName(); reg != wantreg {
+ v.Fatalf("bad reg %s for symbol type %T, want %s", reg, v.Aux, wantreg)
+ }
+
+ case ssa.OpARMMOVBload,
+ ssa.OpARMMOVBUload,
+ ssa.OpARMMOVHload,
+ ssa.OpARMMOVHUload,
+ ssa.OpARMMOVWload,
+ ssa.OpARMMOVFload,
+ ssa.OpARMMOVDload:
p := gc.Prog(v.Op.Asm())
p.From.Type = obj.TYPE_MEM
- p.From.Reg = gc.SSARegNum(v.Args[0])
+ p.From.Reg = v.Args[0].Reg()
gc.AddAux(&p.From, v)
p.To.Type = obj.TYPE_REG
- p.To.Reg = gc.SSARegNum(v)
- case ssa.OpARMMOVWstore:
+ p.To.Reg = v.Reg()
+ case ssa.OpARMMOVBstore,
+ ssa.OpARMMOVHstore,
+ ssa.OpARMMOVWstore,
+ ssa.OpARMMOVFstore,
+ ssa.OpARMMOVDstore:
p := gc.Prog(v.Op.Asm())
p.From.Type = obj.TYPE_REG
- p.From.Reg = gc.SSARegNum(v.Args[1])
+ p.From.Reg = v.Args[1].Reg()
p.To.Type = obj.TYPE_MEM
- p.To.Reg = gc.SSARegNum(v.Args[0])
+ p.To.Reg = v.Args[0].Reg()
gc.AddAux(&p.To, v)
+ case ssa.OpARMMOVWloadidx:
+ // 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.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.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.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.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.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.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_AR, v.AuxInt))
+ case ssa.OpARMMOVBreg,
+ ssa.OpARMMOVBUreg,
+ ssa.OpARMMOVHreg,
+ ssa.OpARMMOVHUreg:
+ a := v.Args[0]
+ for a.Op == ssa.OpCopy || a.Op == ssa.OpARMMOVWreg || a.Op == ssa.OpARMMOVWnop {
+ a = a.Args[0]
+ }
+ if a.Op == ssa.OpLoadReg {
+ t := a.Type
+ switch {
+ case v.Op == ssa.OpARMMOVBreg && t.Size() == 1 && t.IsSigned(),
+ v.Op == ssa.OpARMMOVBUreg && t.Size() == 1 && !t.IsSigned(),
+ v.Op == ssa.OpARMMOVHreg && t.Size() == 2 && t.IsSigned(),
+ v.Op == ssa.OpARMMOVHUreg && t.Size() == 2 && !t.IsSigned():
+ // arg is a proper-typed load, already zero/sign-extended, don't extend again
+ if v.Reg() == v.Args[0].Reg() {
+ return
+ }
+ p := gc.Prog(arm.AMOVW)
+ p.From.Type = obj.TYPE_REG
+ p.From.Reg = v.Args[0].Reg()
+ p.To.Type = obj.TYPE_REG
+ p.To.Reg = v.Reg()
+ return
+ default:
+ }
+ }
+ fallthrough
+ case ssa.OpARMMVN,
+ ssa.OpARMCLZ,
+ ssa.OpARMSQRTD,
+ ssa.OpARMNEGF,
+ ssa.OpARMNEGD,
+ ssa.OpARMMOVWF,
+ ssa.OpARMMOVWD,
+ ssa.OpARMMOVFW,
+ ssa.OpARMMOVDW,
+ ssa.OpARMMOVFD,
+ ssa.OpARMMOVDF:
+ p := gc.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.OpARMMOVWUF,
+ ssa.OpARMMOVWUD,
+ ssa.OpARMMOVFWU,
+ ssa.OpARMMOVDWU:
+ p := gc.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.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.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:
- // TODO: deferreturn
+ 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
@@ -118,37 +653,279 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
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)
+ 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
+ }
+ case ssa.OpARMDUFFZERO:
+ p := gc.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.Offset = v.AuxInt
+ case ssa.OpARMDUFFCOPY:
+ p := gc.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.Offset = v.AuxInt
+ case ssa.OpARMLoweredNilCheck:
+ // Issue a load which will fault if arg is nil.
+ p := gc.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")
+ }
+ case ssa.OpARMLoweredZero:
+ // MOVW.P Rarg2, 4(R1)
+ // CMP Rarg1, R1
+ // BLE -2(PC)
+ // arg1 is the address of the last element to zero
+ // arg2 is known to be zero
+ // auxint is alignment
+ var sz int64
+ var mov obj.As
+ switch {
+ case v.AuxInt%4 == 0:
+ sz = 4
+ mov = arm.AMOVW
+ case v.AuxInt%2 == 0:
+ sz = 2
+ mov = arm.AMOVH
+ default:
+ sz = 1
+ mov = arm.AMOVB
+ }
+ p := gc.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.From.Type = obj.TYPE_REG
+ p2.From.Reg = v.Args[1].Reg()
+ p2.Reg = arm.REG_R1
+ p3 := gc.Prog(arm.ABLE)
+ p3.To.Type = obj.TYPE_BRANCH
+ gc.Patch(p3, p)
+ case ssa.OpARMLoweredMove:
+ // MOVW.P 4(R1), Rtmp
+ // MOVW.P Rtmp, 4(R2)
+ // CMP Rarg2, R1
+ // BLE -3(PC)
+ // arg2 is the address of the last element of src
+ // auxint is alignment
+ var sz int64
+ var mov obj.As
+ switch {
+ case v.AuxInt%4 == 0:
+ sz = 4
+ mov = arm.AMOVW
+ case v.AuxInt%2 == 0:
+ sz = 2
+ mov = arm.AMOVH
+ default:
+ sz = 1
+ mov = arm.AMOVB
+ }
+ p := gc.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.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.From.Type = obj.TYPE_REG
+ p3.From.Reg = v.Args[2].Reg()
+ p3.Reg = arm.REG_R1
+ p4 := gc.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.OpARMLessThan:
- v.Fatalf("pseudo-op made it to output: %s", v.LongString())
+ case ssa.OpKeepAlive:
+ gc.KeepAlive(v)
+ case ssa.OpARMEqual,
+ ssa.OpARMNotEqual,
+ ssa.OpARMLessThan,
+ ssa.OpARMLessEqual,
+ ssa.OpARMGreaterThan,
+ ssa.OpARMGreaterEqual,
+ ssa.OpARMLessThanU,
+ ssa.OpARMLessEqualU,
+ ssa.OpARMGreaterThanU,
+ ssa.OpARMGreaterEqualU:
+ // generate boolean values
+ // use conditional move
+ p := gc.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.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)
+ case ssa.OpARMFlagEQ,
+ ssa.OpARMFlagLT_ULT,
+ ssa.OpARMFlagLT_UGT,
+ ssa.OpARMFlagGT_ULT,
+ ssa.OpARMFlagGT_UGT:
+ 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())
default:
- v.Unimplementedf("genValue not implemented: %s", v.LongString())
+ v.Fatalf("genValue not implemented: %s", v.LongString())
}
}
+var condBits = map[ssa.Op]uint8{
+ ssa.OpARMEqual: arm.C_SCOND_EQ,
+ ssa.OpARMNotEqual: arm.C_SCOND_NE,
+ ssa.OpARMLessThan: arm.C_SCOND_LT,
+ ssa.OpARMLessThanU: arm.C_SCOND_LO,
+ ssa.OpARMLessEqual: arm.C_SCOND_LE,
+ ssa.OpARMLessEqualU: arm.C_SCOND_LS,
+ ssa.OpARMGreaterThan: arm.C_SCOND_GT,
+ ssa.OpARMGreaterThanU: arm.C_SCOND_HI,
+ ssa.OpARMGreaterEqual: arm.C_SCOND_GE,
+ ssa.OpARMGreaterEqualU: arm.C_SCOND_HS,
+}
+
+var blockJump = map[ssa.BlockKind]struct {
+ asm, invasm obj.As
+}{
+ ssa.BlockARMEQ: {arm.ABEQ, arm.ABNE},
+ ssa.BlockARMNE: {arm.ABNE, arm.ABEQ},
+ ssa.BlockARMLT: {arm.ABLT, arm.ABGE},
+ ssa.BlockARMGE: {arm.ABGE, arm.ABLT},
+ ssa.BlockARMLE: {arm.ABLE, arm.ABGT},
+ ssa.BlockARMGT: {arm.ABGT, arm.ABLE},
+ ssa.BlockARMULT: {arm.ABLO, arm.ABHS},
+ ssa.BlockARMUGE: {arm.ABHS, arm.ABLO},
+ ssa.BlockARMUGT: {arm.ABHI, arm.ABLS},
+ ssa.BlockARMULE: {arm.ABLS, arm.ABHI},
+}
+
func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) {
s.SetLineno(b.Line)
switch b.Kind {
- case ssa.BlockCall:
+ case ssa.BlockPlain:
if b.Succs[0].Block() != next {
p := gc.Prog(obj.AJMP)
p.To.Type = obj.TYPE_BRANCH
s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()})
}
- case ssa.BlockRet:
- gc.Prog(obj.ARET)
- case ssa.BlockARMLT:
- p := gc.Prog(arm.ABLT)
- p.To.Type = obj.TYPE_BRANCH
- s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()})
- p = gc.Prog(obj.AJMP)
+
+ case ssa.BlockDefer:
+ // defer returns in R0:
+ // 0 if we should continue executing
+ // 1 if we should jump to deferreturn call
+ p := gc.Prog(arm.ACMP)
+ p.From.Type = obj.TYPE_CONST
+ p.From.Offset = 0
+ p.Reg = arm.REG_R0
+ p = gc.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.To.Type = obj.TYPE_BRANCH
+ s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()})
+ }
+
+ case ssa.BlockExit:
+ gc.Prog(obj.AUNDEF) // tell plive.go that we never reach here
+
+ case ssa.BlockRet:
+ gc.Prog(obj.ARET)
+
+ case ssa.BlockRetJmp:
+ p := gc.Prog(obj.ARET)
+ p.To.Type = obj.TYPE_MEM
+ p.To.Name = obj.NAME_EXTERN
+ p.To.Sym = gc.Linksym(b.Aux.(*gc.Sym))
+
+ case ssa.BlockARMEQ, ssa.BlockARMNE,
+ ssa.BlockARMLT, ssa.BlockARMGE,
+ ssa.BlockARMLE, ssa.BlockARMGT,
+ ssa.BlockARMULT, ssa.BlockARMUGT,
+ ssa.BlockARMULE, ssa.BlockARMUGE:
+ jmp := blockJump[b.Kind]
+ var p *obj.Prog
+ switch next {
+ case b.Succs[0].Block():
+ p = gc.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.To.Type = obj.TYPE_BRANCH
+ s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()})
+ default:
+ p = gc.Prog(jmp.asm)
+ p.To.Type = obj.TYPE_BRANCH
+ s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()})
+ q := gc.Prog(obj.AJMP)
+ q.To.Type = obj.TYPE_BRANCH
+ s.Branches = append(s.Branches, gc.Branch{P: q, B: b.Succs[1].Block()})
+ }
+
+ default:
+ b.Fatalf("branch not implemented: %s. Control: %s", b.LongString(), b.Control.LongString())
}
}
diff --git a/src/cmd/compile/internal/arm64/cgen.go b/src/cmd/compile/internal/arm64/cgen.go
deleted file mode 100644
index 87f3498..0000000
--- a/src/cmd/compile/internal/arm64/cgen.go
+++ /dev/null
@@ -1,151 +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 arm64
-
-import (
- "cmd/compile/internal/gc"
- "cmd/internal/obj"
- "cmd/internal/obj/arm64"
-)
-
-func blockcopy(n, res *gc.Node, osrc, odst, w int64) {
- // determine alignment.
- // want to avoid unaligned access, so have to use
- // smaller operations for less aligned types.
- // for example moving [4]byte must use 4 MOVB not 1 MOVW.
- align := int(n.Type.Align)
-
- var op obj.As
- switch align {
- default:
- gc.Fatalf("sgen: invalid alignment %d for %v", align, n.Type)
-
- case 1:
- op = arm64.AMOVB
-
- case 2:
- op = arm64.AMOVH
-
- case 4:
- op = arm64.AMOVW
-
- case 8:
- op = arm64.AMOVD
- }
-
- if w%int64(align) != 0 {
- gc.Fatalf("sgen: unaligned size %d (align=%d) for %v", w, align, n.Type)
- }
- c := int32(w / int64(align))
-
- if osrc%int64(align) != 0 || odst%int64(align) != 0 {
- gc.Fatalf("sgen: unaligned offset src %d or dst %d (align %d)", osrc, odst, align)
- }
-
- // if we are copying forward on the stack and
- // the src and dst overlap, then reverse direction
- dir := align
-
- if osrc < odst && odst < osrc+w {
- dir = -dir
- }
-
- var dst gc.Node
- var src gc.Node
- if n.Ullman >= res.Ullman {
- gc.Agenr(n, &dst, res) // temporarily use dst
- gc.Regalloc(&src, gc.Types[gc.Tptr], nil)
- gins(arm64.AMOVD, &dst, &src)
- if res.Op == gc.ONAME {
- gc.Gvardef(res)
- }
- gc.Agen(res, &dst)
- } else {
- if res.Op == gc.ONAME {
- gc.Gvardef(res)
- }
- gc.Agenr(res, &dst, res)
- gc.Agenr(n, &src, nil)
- }
-
- var tmp gc.Node
- gc.Regalloc(&tmp, gc.Types[gc.Tptr], nil)
-
- // set up end marker
- var nend gc.Node
-
- // move src and dest to the end of block if necessary
- if dir < 0 {
- if c >= 4 {
- gc.Regalloc(&nend, gc.Types[gc.Tptr], nil)
- gins(arm64.AMOVD, &src, &nend)
- }
-
- p := gins(arm64.AADD, nil, &src)
- p.From.Type = obj.TYPE_CONST
- p.From.Offset = w
-
- p = gins(arm64.AADD, nil, &dst)
- p.From.Type = obj.TYPE_CONST
- p.From.Offset = w
- } else {
- p := gins(arm64.AADD, nil, &src)
- p.From.Type = obj.TYPE_CONST
- p.From.Offset = int64(-dir)
-
- p = gins(arm64.AADD, nil, &dst)
- p.From.Type = obj.TYPE_CONST
- p.From.Offset = int64(-dir)
-
- if c >= 4 {
- gc.Regalloc(&nend, gc.Types[gc.Tptr], nil)
- p := gins(arm64.AMOVD, &src, &nend)
- p.From.Type = obj.TYPE_ADDR
- p.From.Offset = w
- }
- }
-
- // move
- // TODO: enable duffcopy for larger copies.
- if c >= 4 {
- p := gins(op, &src, &tmp)
- p.From.Type = obj.TYPE_MEM
- p.From.Offset = int64(dir)
- p.Scond = arm64.C_XPRE
- ploop := p
-
- p = gins(op, &tmp, &dst)
- p.To.Type = obj.TYPE_MEM
- p.To.Offset = int64(dir)
- p.Scond = arm64.C_XPRE
-
- p = gcmp(arm64.ACMP, &src, &nend)
-
- gc.Patch(gc.Gbranch(arm64.ABNE, nil, 0), ploop)
- gc.Regfree(&nend)
- } else {
- // TODO(austin): Instead of generating ADD $-8,R8; ADD
- // $-8,R7; n*(MOVDU 8(R8),R9; MOVDU R9,8(R7);) just
- // generate the offsets directly and eliminate the
- // ADDs. That will produce shorter, more
- // pipeline-able code.
- var p *obj.Prog
- for ; c > 0; c-- {
- p = gins(op, &src, &tmp)
- p.From.Type = obj.TYPE_MEM
- p.From.Offset = int64(dir)
- p.Scond = arm64.C_XPRE
-
- p = gins(op, &tmp, &dst)
- p.To.Type = obj.TYPE_MEM
- p.To.Offset = int64(dir)
- p.Scond = arm64.C_XPRE
- }
- }
-
- gc.Regfree(&dst)
- gc.Regfree(&src)
- gc.Regfree(&tmp)
-}
diff --git a/src/cmd/compile/internal/arm64/galign.go b/src/cmd/compile/internal/arm64/galign.go
index 7acc4e0..20a67e3 100644
--- a/src/cmd/compile/internal/arm64/galign.go
+++ b/src/cmd/compile/internal/arm64/galign.go
@@ -6,61 +6,19 @@ package arm64
import (
"cmd/compile/internal/gc"
+ "cmd/compile/internal/ssa"
"cmd/internal/obj/arm64"
)
-func betypeinit() {
-}
-
-func Main() {
+func Init() {
gc.Thearch.LinkArch = &arm64.Linkarm64
gc.Thearch.REGSP = arm64.REGSP
- gc.Thearch.REGCTXT = arm64.REGCTXT
- gc.Thearch.REGCALLX = arm64.REGRT1
- gc.Thearch.REGCALLX2 = arm64.REGRT2
- gc.Thearch.REGRETURN = arm64.REG_R0
- gc.Thearch.REGMIN = arm64.REG_R0
- gc.Thearch.REGMAX = arm64.REG_R31
- gc.Thearch.REGZERO = arm64.REGZERO
- gc.Thearch.FREGMIN = arm64.REG_F0
- gc.Thearch.FREGMAX = arm64.REG_F31
gc.Thearch.MAXWIDTH = 1 << 50
- gc.Thearch.ReservedRegs = resvd
- gc.Thearch.Betypeinit = betypeinit
- gc.Thearch.Cgen_hmul = cgen_hmul
- gc.Thearch.AddSetCarry = AddSetCarry
- gc.Thearch.RightShiftWithCarry = RightShiftWithCarry
- gc.Thearch.Cgen_shift = cgen_shift
- gc.Thearch.Clearfat = clearfat
gc.Thearch.Defframe = defframe
- gc.Thearch.Dodiv = dodiv
- gc.Thearch.Excise = excise
- gc.Thearch.Expandchecks = expandchecks
- gc.Thearch.Getg = getg
- gc.Thearch.Gins = gins
- gc.Thearch.Ginscmp = ginscmp
- gc.Thearch.Ginscon = ginscon
- gc.Thearch.Ginsnop = ginsnop
- gc.Thearch.Gmove = gmove
- gc.Thearch.Peep = peep
gc.Thearch.Proginfo = proginfo
- gc.Thearch.Regtyp = regtyp
- gc.Thearch.Sameaddr = sameaddr
- gc.Thearch.Smallindir = smallindir
- gc.Thearch.Stackaddr = stackaddr
- gc.Thearch.Blockcopy = blockcopy
- gc.Thearch.Sudoaddable = sudoaddable
- gc.Thearch.Sudoclean = sudoclean
- gc.Thearch.Excludedregs = excludedregs
- gc.Thearch.RtoB = RtoB
- gc.Thearch.FtoB = RtoB
- gc.Thearch.BtoR = BtoR
- gc.Thearch.BtoF = BtoF
- gc.Thearch.Optoas = optoas
- gc.Thearch.Doregbits = doregbits
- gc.Thearch.Regnames = regnames
- gc.Main()
- gc.Exit(0)
+ gc.Thearch.SSAMarkMoves = func(s *gc.SSAGenState, b *ssa.Block) {}
+ gc.Thearch.SSAGenValue = ssaGenValue
+ gc.Thearch.SSAGenBlock = ssaGenBlock
}
diff --git a/src/cmd/compile/internal/arm64/ggen.go b/src/cmd/compile/internal/arm64/ggen.go
index bddfed6..16813b6 100644
--- a/src/cmd/compile/internal/arm64/ggen.go
+++ b/src/cmd/compile/internal/arm64/ggen.go
@@ -8,7 +8,6 @@ import (
"cmd/compile/internal/gc"
"cmd/internal/obj"
"cmd/internal/obj/arm64"
- "fmt"
)
func defframe(ptxt *obj.Prog) {
@@ -43,7 +42,7 @@ func defframe(ptxt *obj.Prog) {
gc.Fatalf("needzero class %d", n.Class)
}
if n.Type.Width%int64(gc.Widthptr) != 0 || n.Xoffset%int64(gc.Widthptr) != 0 || n.Type.Width == 0 {
- gc.Fatalf("var %v has size %d offset %d", gc.Nconv(n, gc.FmtLong), int(n.Type.Width), int(n.Xoffset))
+ 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) {
@@ -66,7 +65,7 @@ func defframe(ptxt *obj.Prog) {
zerorange(p, int64(frame), lo, hi)
}
-var darwin = obj.Getgoos() == "darwin"
+var darwin = obj.GOOS == "darwin"
func zerorange(p *obj.Prog, frame int64, lo int64, hi int64) *obj.Prog {
cnt := hi - lo
@@ -75,502 +74,36 @@ func zerorange(p *obj.Prog, frame int64, lo int64, hi int64) *obj.Prog {
}
if cnt < int64(4*gc.Widthptr) {
for i := int64(0); i < cnt; i += int64(gc.Widthptr) {
- p = appendpp(p, arm64.AMOVD, obj.TYPE_REG, arm64.REGZERO, 0, obj.TYPE_MEM, arm64.REGSP, 8+frame+lo+i)
+ p = gc.Appendpp(p, arm64.AMOVD, obj.TYPE_REG, arm64.REGZERO, 0, obj.TYPE_MEM, arm64.REGSP, 8+frame+lo+i)
}
} else if cnt <= int64(128*gc.Widthptr) && !darwin { // darwin ld64 cannot handle BR26 reloc with non-zero addend
- p = appendpp(p, arm64.AMOVD, obj.TYPE_REG, arm64.REGSP, 0, obj.TYPE_REG, arm64.REGRT1, 0)
- p = appendpp(p, arm64.AADD, obj.TYPE_CONST, 0, 8+frame+lo-8, obj.TYPE_REG, arm64.REGRT1, 0)
+ p = 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.Reg = arm64.REGRT1
- p = appendpp(p, obj.ADUFFZERO, obj.TYPE_NONE, 0, 0, obj.TYPE_MEM, 0, 0)
- f := gc.Sysfunc("duffzero")
- gc.Naddr(&p.To, f)
- gc.Afunclit(&p.To, f)
+ p = gc.Appendpp(p, obj.ADUFFZERO, obj.TYPE_NONE, 0, 0, obj.TYPE_MEM, 0, 0)
+ gc.Naddr(&p.To, gc.Sysfunc("duffzero"))
p.To.Offset = 4 * (128 - cnt/int64(gc.Widthptr))
} else {
- p = appendpp(p, arm64.AMOVD, obj.TYPE_CONST, 0, 8+frame+lo-8, obj.TYPE_REG, arm64.REGTMP, 0)
- p = appendpp(p, arm64.AMOVD, obj.TYPE_REG, arm64.REGSP, 0, obj.TYPE_REG, arm64.REGRT1, 0)
- p = appendpp(p, arm64.AADD, obj.TYPE_REG, arm64.REGTMP, 0, obj.TYPE_REG, arm64.REGRT1, 0)
+ p = 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.Reg = arm64.REGRT1
- p = appendpp(p, arm64.AMOVD, obj.TYPE_CONST, 0, cnt, obj.TYPE_REG, arm64.REGTMP, 0)
- p = appendpp(p, arm64.AADD, obj.TYPE_REG, arm64.REGTMP, 0, obj.TYPE_REG, arm64.REGRT2, 0)
+ p = 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.Reg = arm64.REGRT1
- p = appendpp(p, arm64.AMOVD, obj.TYPE_REG, arm64.REGZERO, 0, obj.TYPE_MEM, arm64.REGRT1, int64(gc.Widthptr))
+ p = gc.Appendpp(p, arm64.AMOVD, obj.TYPE_REG, arm64.REGZERO, 0, obj.TYPE_MEM, arm64.REGRT1, int64(gc.Widthptr))
p.Scond = arm64.C_XPRE
p1 := p
- p = appendpp(p, arm64.ACMP, obj.TYPE_REG, arm64.REGRT1, 0, obj.TYPE_NONE, 0, 0)
+ p = gc.Appendpp(p, arm64.ACMP, obj.TYPE_REG, arm64.REGRT1, 0, obj.TYPE_NONE, 0, 0)
p.Reg = arm64.REGRT2
- p = appendpp(p, arm64.ABNE, obj.TYPE_NONE, 0, 0, obj.TYPE_BRANCH, 0, 0)
+ p = gc.Appendpp(p, arm64.ABNE, obj.TYPE_NONE, 0, 0, obj.TYPE_BRANCH, 0, 0)
gc.Patch(p, p1)
}
return p
}
-func appendpp(p *obj.Prog, as obj.As, ftype obj.AddrType, freg int, foffset int64, ttype obj.AddrType, treg int, toffset int64) *obj.Prog {
- q := gc.Ctxt.NewProg()
- gc.Clearp(q)
- q.As = as
- q.Lineno = p.Lineno
- q.From.Type = ftype
- q.From.Reg = int16(freg)
- q.From.Offset = foffset
- q.To.Type = ttype
- q.To.Reg = int16(treg)
- q.To.Offset = toffset
- q.Link = p.Link
- p.Link = q
- return q
-}
-
func ginsnop() {
- var con gc.Node
- gc.Nodconst(&con, gc.Types[gc.TINT], 0)
- gins(arm64.AHINT, &con, nil)
-}
-
-var panicdiv *gc.Node
-
-/*
- * generate division.
- * generates one of:
- * res = nl / nr
- * res = nl % nr
- * according to op.
- */
-func dodiv(op gc.Op, nl *gc.Node, nr *gc.Node, res *gc.Node) {
- // Have to be careful about handling
- // most negative int divided by -1 correctly.
- // The hardware will generate undefined result.
- // Also need to explicitly trap on division on zero,
- // the hardware will silently generate undefined result.
- // DIVW will leave unpredictable result in higher 32-bit,
- // so always use DIVD/DIVDU.
- t := nl.Type
-
- t0 := t
- check := false
- if t.IsSigned() {
- check = true
- if gc.Isconst(nl, gc.CTINT) && nl.Int64() != -(1<<uint64(t.Width*8-1)) {
- check = false
- } else if gc.Isconst(nr, gc.CTINT) && nr.Int64() != -1 {
- check = false
- }
- }
-
- if t.Width < 8 {
- if t.IsSigned() {
- t = gc.Types[gc.TINT64]
- } else {
- t = gc.Types[gc.TUINT64]
- }
- check = false
- }
-
- a := optoas(gc.ODIV, t)
-
- var tl gc.Node
- gc.Regalloc(&tl, t0, nil)
- var tr gc.Node
- gc.Regalloc(&tr, t0, nil)
- if nl.Ullman >= nr.Ullman {
- gc.Cgen(nl, &tl)
- gc.Cgen(nr, &tr)
- } else {
- gc.Cgen(nr, &tr)
- gc.Cgen(nl, &tl)
- }
-
- if t != t0 {
- // Convert
- tl2 := tl
-
- tr2 := tr
- tl.Type = t
- tr.Type = t
- gmove(&tl2, &tl)
- gmove(&tr2, &tr)
- }
-
- // Handle divide-by-zero panic.
- p1 := gins(optoas(gc.OCMP, t), &tr, nil)
- p1.Reg = arm64.REGZERO
- p1 = gc.Gbranch(optoas(gc.ONE, t), nil, +1)
- if panicdiv == nil {
- panicdiv = gc.Sysfunc("panicdivide")
- }
- gc.Ginscall(panicdiv, -1)
- gc.Patch(p1, gc.Pc)
-
- var p2 *obj.Prog
- if check {
- var nm1 gc.Node
- gc.Nodconst(&nm1, t, -1)
- gcmp(optoas(gc.OCMP, t), &tr, &nm1)
- p1 := gc.Gbranch(optoas(gc.ONE, t), nil, +1)
- if op == gc.ODIV {
- // a / (-1) is -a.
- gins(optoas(gc.OMINUS, t), &tl, &tl)
-
- gmove(&tl, res)
- } else {
- // a % (-1) is 0.
- var nz gc.Node
- gc.Nodconst(&nz, t, 0)
-
- gmove(&nz, res)
- }
-
- p2 = gc.Gbranch(obj.AJMP, nil, 0)
- gc.Patch(p1, gc.Pc)
- }
-
- p1 = gins(a, &tr, &tl)
- if op == gc.ODIV {
- gc.Regfree(&tr)
- gmove(&tl, res)
- } else {
- // A%B = A-(A/B*B)
- var tm gc.Node
- gc.Regalloc(&tm, t, nil)
-
- // patch div to use the 3 register form
- // TODO(minux): add gins3?
- p1.Reg = p1.To.Reg
-
- p1.To.Reg = tm.Reg
- gins(optoas(gc.OMUL, t), &tr, &tm)
- gc.Regfree(&tr)
- gins(optoas(gc.OSUB, t), &tm, &tl)
- gc.Regfree(&tm)
- gmove(&tl, res)
- }
-
- gc.Regfree(&tl)
- if check {
- gc.Patch(p2, gc.Pc)
- }
-}
-
-// RightShiftWithCarry generates a constant unsigned
-// right shift with carry.
-//
-// res = n >> shift // with carry
-func RightShiftWithCarry(n *gc.Node, shift uint, res *gc.Node) {
- // Extra 1 is for carry bit.
- maxshift := uint(n.Type.Width*8 + 1)
- if shift == 0 {
- gmove(n, res)
- } else if shift < maxshift {
- // 1. clear rightmost bit of target
- var n1 gc.Node
- gc.Nodconst(&n1, n.Type, 1)
- gins(optoas(gc.ORSH, n.Type), &n1, n)
- gins(optoas(gc.OLSH, n.Type), &n1, n)
- // 2. add carry flag to target
- var n2 gc.Node
- gc.Nodconst(&n1, n.Type, 0)
- gc.Regalloc(&n2, n.Type, nil)
- gins(optoas(gc.OAS, n.Type), &n1, &n2)
- gins(arm64.AADC, &n2, n)
- // 3. right rotate 1 bit
- gc.Nodconst(&n1, n.Type, 1)
- gins(arm64.AROR, &n1, n)
-
- // ARM64 backend doesn't eliminate shifts by 0. It is manually checked here.
- if shift > 1 {
- var n3 gc.Node
- gc.Nodconst(&n3, n.Type, int64(shift-1))
- cgen_shift(gc.ORSH, true, n, &n3, res)
- } else {
- gmove(n, res)
- }
- gc.Regfree(&n2)
- } else {
- gc.Fatalf("RightShiftWithCarry: shift(%v) is bigger than max size(%v)", shift, maxshift)
- }
-}
-
-// AddSetCarry generates add and set carry.
-//
-// res = nl + nr // with carry flag set
-func AddSetCarry(nl *gc.Node, nr *gc.Node, res *gc.Node) {
- gins(arm64.AADDS, nl, nr)
- gmove(nr, res)
-}
-
-/*
- * generate high multiply:
- * res = (nl*nr) >> width
- */
-func cgen_hmul(nl *gc.Node, nr *gc.Node, res *gc.Node) {
- // largest ullman on left.
- if nl.Ullman < nr.Ullman {
- nl, nr = nr, nl
- }
-
- t := nl.Type
- w := t.Width * 8
- var n1 gc.Node
- gc.Cgenr(nl, &n1, res)
- var n2 gc.Node
- gc.Cgenr(nr, &n2, nil)
- switch gc.Simtype[t.Etype] {
- case gc.TINT8,
- gc.TINT16,
- gc.TINT32:
- gins(optoas(gc.OMUL, t), &n2, &n1)
- p := gins(arm64.AASR, nil, &n1)
- p.From.Type = obj.TYPE_CONST
- p.From.Offset = w
-
- case gc.TUINT8,
- gc.TUINT16,
- gc.TUINT32:
- gins(optoas(gc.OMUL, t), &n2, &n1)
- p := gins(arm64.ALSR, nil, &n1)
- p.From.Type = obj.TYPE_CONST
- p.From.Offset = w
-
- case gc.TINT64,
- gc.TUINT64:
- if t.IsSigned() {
- gins(arm64.ASMULH, &n2, &n1)
- } else {
- gins(arm64.AUMULH, &n2, &n1)
- }
-
- default:
- gc.Fatalf("cgen_hmul %v", t)
- }
-
- gc.Cgen(&n1, res)
- gc.Regfree(&n1)
- gc.Regfree(&n2)
-}
-
-/*
- * generate shift according to op, one of:
- * res = nl << nr
- * res = nl >> nr
- */
-func cgen_shift(op gc.Op, bounded bool, nl *gc.Node, nr *gc.Node, res *gc.Node) {
- a := optoas(op, nl.Type)
-
- if nr.Op == gc.OLITERAL {
- var n1 gc.Node
- gc.Regalloc(&n1, nl.Type, res)
- gc.Cgen(nl, &n1)
- sc := uint64(nr.Int64())
- if sc >= uint64(nl.Type.Width)*8 {
- // large shift gets 2 shifts by width-1
- var n3 gc.Node
- gc.Nodconst(&n3, gc.Types[gc.TUINT32], nl.Type.Width*8-1)
-
- gins(a, &n3, &n1)
- gins(a, &n3, &n1)
- } else {
- gins(a, nr, &n1)
- }
- gmove(&n1, res)
- gc.Regfree(&n1)
- return
- }
-
- if nl.Ullman >= gc.UINF {
- var n4 gc.Node
- gc.Tempname(&n4, nl.Type)
- gc.Cgen(nl, &n4)
- nl = &n4
- }
-
- if nr.Ullman >= gc.UINF {
- var n5 gc.Node
- gc.Tempname(&n5, nr.Type)
- gc.Cgen(nr, &n5)
- nr = &n5
- }
-
- // Allow either uint32 or uint64 as shift type,
- // to avoid unnecessary conversion from uint32 to uint64
- // just to do the comparison.
- tcount := gc.Types[gc.Simtype[nr.Type.Etype]]
-
- if tcount.Etype < gc.TUINT32 {
- tcount = gc.Types[gc.TUINT32]
- }
-
- var n1 gc.Node
- gc.Regalloc(&n1, nr.Type, nil) // to hold the shift type in CX
- var n3 gc.Node
- gc.Regalloc(&n3, tcount, &n1) // to clear high bits of CX
-
- var n2 gc.Node
- gc.Regalloc(&n2, nl.Type, res)
-
- if nl.Ullman >= nr.Ullman {
- gc.Cgen(nl, &n2)
- gc.Cgen(nr, &n1)
- gmove(&n1, &n3)
- } else {
- gc.Cgen(nr, &n1)
- gmove(&n1, &n3)
- gc.Cgen(nl, &n2)
- }
-
- gc.Regfree(&n3)
-
- // test and fix up large shifts
- if !bounded {
- gc.Nodconst(&n3, tcount, nl.Type.Width*8)
- gcmp(optoas(gc.OCMP, tcount), &n1, &n3)
- p1 := gc.Gbranch(optoas(gc.OLT, tcount), nil, +1)
- if op == gc.ORSH && nl.Type.IsSigned() {
- gc.Nodconst(&n3, gc.Types[gc.TUINT32], nl.Type.Width*8-1)
- gins(a, &n3, &n2)
- } else {
- gc.Nodconst(&n3, nl.Type, 0)
- gmove(&n3, &n2)
- }
-
- gc.Patch(p1, gc.Pc)
- }
-
- gins(a, &n1, &n2)
-
- gmove(&n2, res)
-
- gc.Regfree(&n1)
- gc.Regfree(&n2)
-}
-
-func clearfat(nl *gc.Node) {
- /* clear a fat object */
- if gc.Debug['g'] != 0 {
- fmt.Printf("clearfat %v (%v, size: %d)\n", nl, nl.Type, nl.Type.Width)
- }
-
- w := uint64(nl.Type.Width)
-
- // Avoid taking the address for simple enough types.
- if gc.Componentgen(nil, nl) {
- return
- }
-
- c := w % 8 // bytes
- q := w / 8 // dwords
-
- var r0 gc.Node
- gc.Nodreg(&r0, gc.Types[gc.TUINT64], arm64.REGZERO)
- var dst gc.Node
-
- // REGRT1 is reserved on arm64, see arm64/gsubr.go.
- gc.Nodreg(&dst, gc.Types[gc.Tptr], arm64.REGRT1)
- gc.Agen(nl, &dst)
-
- var boff uint64
- if q > 128 {
- p := gins(arm64.ASUB, nil, &dst)
- p.From.Type = obj.TYPE_CONST
- p.From.Offset = 8
-
- var end gc.Node
- gc.Regalloc(&end, gc.Types[gc.Tptr], nil)
- p = gins(arm64.AMOVD, &dst, &end)
- p.From.Type = obj.TYPE_ADDR
- p.From.Offset = int64(q * 8)
-
- p = gins(arm64.AMOVD, &r0, &dst)
- p.To.Type = obj.TYPE_MEM
- p.To.Offset = 8
- p.Scond = arm64.C_XPRE
- pl := p
-
- p = gcmp(arm64.ACMP, &dst, &end)
- gc.Patch(gc.Gbranch(arm64.ABNE, nil, 0), pl)
-
- gc.Regfree(&end)
-
- // The loop leaves R16 on the last zeroed dword
- boff = 8
- } else if q >= 4 && !darwin { // darwin ld64 cannot handle BR26 reloc with non-zero addend
- p := gins(arm64.ASUB, nil, &dst)
- p.From.Type = obj.TYPE_CONST
- p.From.Offset = 8
- f := gc.Sysfunc("duffzero")
- p = gins(obj.ADUFFZERO, nil, f)
- gc.Afunclit(&p.To, f)
-
- // 4 and 128 = magic constants: see ../../runtime/asm_arm64x.s
- p.To.Offset = int64(4 * (128 - q))
-
- // duffzero leaves R16 on the last zeroed dword
- boff = 8
- } else {
- var p *obj.Prog
- for t := uint64(0); t < q; t++ {
- p = gins(arm64.AMOVD, &r0, &dst)
- p.To.Type = obj.TYPE_MEM
- p.To.Offset = int64(8 * t)
- }
-
- boff = 8 * q
- }
-
- var p *obj.Prog
- for t := uint64(0); t < c; t++ {
- p = gins(arm64.AMOVB, &r0, &dst)
- p.To.Type = obj.TYPE_MEM
- p.To.Offset = int64(t + boff)
- }
-}
-
-// Called after regopt and peep have run.
-// Expand CHECKNIL pseudo-op into actual nil pointer check.
-func expandchecks(firstp *obj.Prog) {
- var p1 *obj.Prog
-
- for p := firstp; p != nil; p = p.Link {
- if gc.Debug_checknil != 0 && gc.Ctxt.Debugvlog != 0 {
- fmt.Printf("expandchecks: %v\n", p)
- }
- if p.As != obj.ACHECKNIL {
- continue
- }
- if gc.Debug_checknil != 0 && p.Lineno > 1 { // p->lineno==1 in generated wrappers
- gc.Warnl(p.Lineno, "generated nil check")
- }
- if p.From.Type != obj.TYPE_REG {
- gc.Fatalf("invalid nil check %v\n", p)
- }
-
- // check is
- // CBNZ arg, 2(PC)
- // MOVD ZR, 0(arg)
- p1 = gc.Ctxt.NewProg()
- gc.Clearp(p1)
- p1.Link = p.Link
- p.Link = p1
- p1.Lineno = p.Lineno
- p1.Pc = 9999
-
- p.As = arm64.ACBNZ
- p.To.Type = obj.TYPE_BRANCH
- p.To.Val = p1.Link
-
- // crash by write to memory address 0.
- p1.As = arm64.AMOVD
- p1.From.Type = obj.TYPE_REG
- p1.From.Reg = arm64.REGZERO
- p1.To.Type = obj.TYPE_MEM
- p1.To.Reg = p.From.Reg
- p1.To.Offset = 0
- }
-}
-
-// res = runtime.getg()
-func getg(res *gc.Node) {
- var n1 gc.Node
- gc.Nodreg(&n1, res.Type, arm64.REGG)
- gmove(&n1, res)
+ p := gc.Prog(arm64.AHINT)
+ p.From.Type = obj.TYPE_CONST
}
diff --git a/src/cmd/compile/internal/arm64/gsubr.go b/src/cmd/compile/internal/arm64/gsubr.go
deleted file mode 100644
index ddf2ed9..0000000
--- a/src/cmd/compile/internal/arm64/gsubr.go
+++ /dev/null
@@ -1,983 +0,0 @@
-// Derived from Inferno utils/6c/txt.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6c/txt.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth at terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth at terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// Portions Copyright © 2009 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-package arm64
-
-import (
- "cmd/compile/internal/gc"
- "cmd/internal/obj"
- "cmd/internal/obj/arm64"
- "fmt"
-)
-
-var resvd = []int{
- arm64.REGTMP,
- arm64.REGG,
- arm64.REGRT1,
- arm64.REGRT2,
- arm64.REG_R31, // REGZERO and REGSP
- arm64.FREGZERO,
- arm64.FREGHALF,
- arm64.FREGONE,
- arm64.FREGTWO,
-}
-
-/*
- * generate
- * as $c, n
- */
-func ginscon(as obj.As, c int64, n2 *gc.Node) {
- var n1 gc.Node
-
- gc.Nodconst(&n1, gc.Types[gc.TINT64], c)
-
- if as != arm64.AMOVD && (c < -arm64.BIG || c > arm64.BIG) || as == arm64.AMUL || n2 != nil && n2.Op != gc.OREGISTER {
- // cannot have more than 16-bit of immediate in ADD, etc.
- // instead, MOV into register first.
- var ntmp gc.Node
- gc.Regalloc(&ntmp, gc.Types[gc.TINT64], nil)
-
- gins(arm64.AMOVD, &n1, &ntmp)
- gins(as, &ntmp, n2)
- gc.Regfree(&ntmp)
- return
- }
-
- rawgins(as, &n1, n2)
-}
-
-/*
- * generate
- * as n, $c (CMP)
- */
-func ginscon2(as obj.As, n2 *gc.Node, c int64) {
- var n1 gc.Node
-
- gc.Nodconst(&n1, gc.Types[gc.TINT64], c)
-
- switch as {
- default:
- gc.Fatalf("ginscon2")
-
- case arm64.ACMP:
- if -arm64.BIG <= c && c <= arm64.BIG {
- gcmp(as, n2, &n1)
- return
- }
- }
-
- // MOV n1 into register first
- var ntmp gc.Node
- gc.Regalloc(&ntmp, gc.Types[gc.TINT64], nil)
-
- rawgins(arm64.AMOVD, &n1, &ntmp)
- gcmp(as, n2, &ntmp)
- gc.Regfree(&ntmp)
-}
-
-func ginscmp(op gc.Op, t *gc.Type, n1, n2 *gc.Node, likely int) *obj.Prog {
- if t.IsInteger() && n1.Op == gc.OLITERAL && n2.Op != gc.OLITERAL {
- // Reverse comparison to place constant last.
- op = gc.Brrev(op)
- n1, n2 = n2, n1
- }
-
- var r1, r2, g1, g2 gc.Node
- gc.Regalloc(&r1, t, n1)
- gc.Regalloc(&g1, n1.Type, &r1)
- gc.Cgen(n1, &g1)
- gmove(&g1, &r1)
- if t.IsInteger() && gc.Isconst(n2, gc.CTINT) {
- ginscon2(optoas(gc.OCMP, t), &r1, n2.Int64())
- } else {
- gc.Regalloc(&r2, t, n2)
- gc.Regalloc(&g2, n1.Type, &r2)
- gc.Cgen(n2, &g2)
- gmove(&g2, &r2)
- gcmp(optoas(gc.OCMP, t), &r1, &r2)
- gc.Regfree(&g2)
- gc.Regfree(&r2)
- }
- gc.Regfree(&g1)
- gc.Regfree(&r1)
- return gc.Gbranch(optoas(op, t), nil, likely)
-}
-
-/*
- * generate move:
- * t = f
- * hard part is conversions.
- */
-func gmove(f *gc.Node, t *gc.Node) {
- if gc.Debug['M'] != 0 {
- fmt.Printf("gmove %v -> %v\n", gc.Nconv(f, gc.FmtLong), gc.Nconv(t, gc.FmtLong))
- }
-
- ft := int(gc.Simsimtype(f.Type))
- tt := int(gc.Simsimtype(t.Type))
- cvt := t.Type
-
- if gc.Iscomplex[ft] || gc.Iscomplex[tt] {
- gc.Complexmove(f, t)
- return
- }
-
- // cannot have two memory operands
- var r1 gc.Node
- var a obj.As
- if gc.Ismem(f) && gc.Ismem(t) {
- goto hard
- }
-
- // convert constant to desired type
- if f.Op == gc.OLITERAL {
- var con gc.Node
- switch tt {
- default:
- f.Convconst(&con, t.Type)
-
- case gc.TINT32,
- gc.TINT16,
- gc.TINT8:
- var con gc.Node
- f.Convconst(&con, gc.Types[gc.TINT64])
- var r1 gc.Node
- gc.Regalloc(&r1, con.Type, t)
- gins(arm64.AMOVD, &con, &r1)
- gmove(&r1, t)
- gc.Regfree(&r1)
- return
-
- case gc.TUINT32,
- gc.TUINT16,
- gc.TUINT8:
- var con gc.Node
- f.Convconst(&con, gc.Types[gc.TUINT64])
- var r1 gc.Node
- gc.Regalloc(&r1, con.Type, t)
- gins(arm64.AMOVD, &con, &r1)
- gmove(&r1, t)
- gc.Regfree(&r1)
- return
- }
-
- f = &con
- ft = tt // so big switch will choose a simple mov
-
- // constants can't move directly to memory.
- if gc.Ismem(t) {
- goto hard
- }
- }
-
- // value -> value copy, first operand in memory.
- // any floating point operand requires register
- // src, so goto hard to copy to register first.
- if gc.Ismem(f) && ft != tt && (gc.Isfloat[ft] || gc.Isfloat[tt]) {
- cvt = gc.Types[ft]
- goto hard
- }
-
- // value -> value copy, only one memory operand.
- // figure out the instruction to use.
- // break out of switch for one-instruction gins.
- // goto rdst for "destination must be register".
- // goto hard for "convert to cvt type first".
- // otherwise handle and return.
-
- switch uint32(ft)<<16 | uint32(tt) {
- default:
- gc.Fatalf("gmove %v -> %v", gc.Tconv(f.Type, gc.FmtLong), gc.Tconv(t.Type, gc.FmtLong))
-
- /*
- * integer copy and truncate
- */
- case gc.TINT8<<16 | gc.TINT8, // same size
- gc.TUINT8<<16 | gc.TINT8,
- gc.TINT16<<16 | gc.TINT8,
- // truncate
- gc.TUINT16<<16 | gc.TINT8,
- gc.TINT32<<16 | gc.TINT8,
- gc.TUINT32<<16 | gc.TINT8,
- gc.TINT64<<16 | gc.TINT8,
- gc.TUINT64<<16 | gc.TINT8:
- a = arm64.AMOVB
-
- case gc.TINT8<<16 | gc.TUINT8, // same size
- gc.TUINT8<<16 | gc.TUINT8,
- gc.TINT16<<16 | gc.TUINT8,
- // truncate
- gc.TUINT16<<16 | gc.TUINT8,
- gc.TINT32<<16 | gc.TUINT8,
- gc.TUINT32<<16 | gc.TUINT8,
- gc.TINT64<<16 | gc.TUINT8,
- gc.TUINT64<<16 | gc.TUINT8:
- a = arm64.AMOVBU
-
- case gc.TINT16<<16 | gc.TINT16, // same size
- gc.TUINT16<<16 | gc.TINT16,
- gc.TINT32<<16 | gc.TINT16,
- // truncate
- gc.TUINT32<<16 | gc.TINT16,
- gc.TINT64<<16 | gc.TINT16,
- gc.TUINT64<<16 | gc.TINT16:
- a = arm64.AMOVH
-
- case gc.TINT16<<16 | gc.TUINT16, // same size
- gc.TUINT16<<16 | gc.TUINT16,
- gc.TINT32<<16 | gc.TUINT16,
- // truncate
- gc.TUINT32<<16 | gc.TUINT16,
- gc.TINT64<<16 | gc.TUINT16,
- gc.TUINT64<<16 | gc.TUINT16:
- a = arm64.AMOVHU
-
- case gc.TINT32<<16 | gc.TINT32, // same size
- gc.TUINT32<<16 | gc.TINT32,
- gc.TINT64<<16 | gc.TINT32,
- // truncate
- gc.TUINT64<<16 | gc.TINT32:
- a = arm64.AMOVW
-
- case gc.TINT32<<16 | gc.TUINT32, // same size
- gc.TUINT32<<16 | gc.TUINT32,
- gc.TINT64<<16 | gc.TUINT32,
- gc.TUINT64<<16 | gc.TUINT32:
- a = arm64.AMOVWU
-
- case gc.TINT64<<16 | gc.TINT64, // same size
- gc.TINT64<<16 | gc.TUINT64,
- gc.TUINT64<<16 | gc.TINT64,
- gc.TUINT64<<16 | gc.TUINT64:
- a = arm64.AMOVD
-
- /*
- * integer up-conversions
- */
- case gc.TINT8<<16 | gc.TINT16, // sign extend int8
- gc.TINT8<<16 | gc.TUINT16,
- gc.TINT8<<16 | gc.TINT32,
- gc.TINT8<<16 | gc.TUINT32,
- gc.TINT8<<16 | gc.TINT64,
- gc.TINT8<<16 | gc.TUINT64:
- a = arm64.AMOVB
-
- goto rdst
-
- case gc.TUINT8<<16 | gc.TINT16, // zero extend uint8
- gc.TUINT8<<16 | gc.TUINT16,
- gc.TUINT8<<16 | gc.TINT32,
- gc.TUINT8<<16 | gc.TUINT32,
- gc.TUINT8<<16 | gc.TINT64,
- gc.TUINT8<<16 | gc.TUINT64:
- a = arm64.AMOVBU
-
- goto rdst
-
- case gc.TINT16<<16 | gc.TINT32, // sign extend int16
- gc.TINT16<<16 | gc.TUINT32,
- gc.TINT16<<16 | gc.TINT64,
- gc.TINT16<<16 | gc.TUINT64:
- a = arm64.AMOVH
-
- goto rdst
-
- case gc.TUINT16<<16 | gc.TINT32, // zero extend uint16
- gc.TUINT16<<16 | gc.TUINT32,
- gc.TUINT16<<16 | gc.TINT64,
- gc.TUINT16<<16 | gc.TUINT64:
- a = arm64.AMOVHU
-
- goto rdst
-
- case gc.TINT32<<16 | gc.TINT64, // sign extend int32
- gc.TINT32<<16 | gc.TUINT64:
- a = arm64.AMOVW
-
- goto rdst
-
- case gc.TUINT32<<16 | gc.TINT64, // zero extend uint32
- gc.TUINT32<<16 | gc.TUINT64:
- a = arm64.AMOVWU
-
- goto rdst
-
- /*
- * float to integer
- */
- case gc.TFLOAT32<<16 | gc.TINT32:
- a = arm64.AFCVTZSSW
- goto rdst
-
- case gc.TFLOAT64<<16 | gc.TINT32:
- a = arm64.AFCVTZSDW
- goto rdst
-
- case gc.TFLOAT32<<16 | gc.TINT64:
- a = arm64.AFCVTZSS
- goto rdst
-
- case gc.TFLOAT64<<16 | gc.TINT64:
- a = arm64.AFCVTZSD
- goto rdst
-
- case gc.TFLOAT32<<16 | gc.TUINT32:
- a = arm64.AFCVTZUSW
- goto rdst
-
- case gc.TFLOAT64<<16 | gc.TUINT32:
- a = arm64.AFCVTZUDW
- goto rdst
-
- case gc.TFLOAT32<<16 | gc.TUINT64:
- a = arm64.AFCVTZUS
- goto rdst
-
- case gc.TFLOAT64<<16 | gc.TUINT64:
- a = arm64.AFCVTZUD
- goto rdst
-
- case gc.TFLOAT32<<16 | gc.TINT16,
- gc.TFLOAT32<<16 | gc.TINT8,
- gc.TFLOAT64<<16 | gc.TINT16,
- gc.TFLOAT64<<16 | gc.TINT8:
- cvt = gc.Types[gc.TINT32]
-
- goto hard
-
- case gc.TFLOAT32<<16 | gc.TUINT16,
- gc.TFLOAT32<<16 | gc.TUINT8,
- gc.TFLOAT64<<16 | gc.TUINT16,
- gc.TFLOAT64<<16 | gc.TUINT8:
- cvt = gc.Types[gc.TUINT32]
-
- goto hard
-
- /*
- * integer to float
- */
- case gc.TINT8<<16 | gc.TFLOAT32,
- gc.TINT16<<16 | gc.TFLOAT32,
- gc.TINT32<<16 | gc.TFLOAT32:
- a = arm64.ASCVTFWS
-
- goto rdst
-
- case gc.TINT8<<16 | gc.TFLOAT64,
- gc.TINT16<<16 | gc.TFLOAT64,
- gc.TINT32<<16 | gc.TFLOAT64:
- a = arm64.ASCVTFWD
-
- goto rdst
-
- case gc.TINT64<<16 | gc.TFLOAT32:
- a = arm64.ASCVTFS
- goto rdst
-
- case gc.TINT64<<16 | gc.TFLOAT64:
- a = arm64.ASCVTFD
- goto rdst
-
- case gc.TUINT8<<16 | gc.TFLOAT32,
- gc.TUINT16<<16 | gc.TFLOAT32,
- gc.TUINT32<<16 | gc.TFLOAT32:
- a = arm64.AUCVTFWS
-
- goto rdst
-
- case gc.TUINT8<<16 | gc.TFLOAT64,
- gc.TUINT16<<16 | gc.TFLOAT64,
- gc.TUINT32<<16 | gc.TFLOAT64:
- a = arm64.AUCVTFWD
-
- goto rdst
-
- case gc.TUINT64<<16 | gc.TFLOAT32:
- a = arm64.AUCVTFS
- goto rdst
-
- case gc.TUINT64<<16 | gc.TFLOAT64:
- a = arm64.AUCVTFD
- goto rdst
-
- /*
- * float to float
- */
- case gc.TFLOAT32<<16 | gc.TFLOAT32:
- a = arm64.AFMOVS
-
- case gc.TFLOAT64<<16 | gc.TFLOAT64:
- a = arm64.AFMOVD
-
- case gc.TFLOAT32<<16 | gc.TFLOAT64:
- a = arm64.AFCVTSD
- goto rdst
-
- case gc.TFLOAT64<<16 | gc.TFLOAT32:
- a = arm64.AFCVTDS
- goto rdst
- }
-
- gins(a, f, t)
- return
-
- // requires register destination
-rdst:
- gc.Regalloc(&r1, t.Type, t)
-
- gins(a, f, &r1)
- gmove(&r1, t)
- gc.Regfree(&r1)
- return
-
- // requires register intermediate
-hard:
- gc.Regalloc(&r1, cvt, t)
-
- gmove(f, &r1)
- gmove(&r1, t)
- gc.Regfree(&r1)
- return
-}
-
-// gins is called by the front end.
-// It synthesizes some multiple-instruction sequences
-// so the front end can stay simpler.
-func gins(as obj.As, f, t *gc.Node) *obj.Prog {
- if as >= obj.A_ARCHSPECIFIC {
- if x, ok := f.IntLiteral(); ok {
- ginscon(as, x, t)
- return nil // caller must not use
- }
- }
- if as == arm64.ACMP {
- if x, ok := t.IntLiteral(); ok {
- ginscon2(as, f, x)
- return nil // caller must not use
- }
- }
- return rawgins(as, f, t)
-}
-
-/*
- * generate one instruction:
- * as f, t
- */
-func rawgins(as obj.As, f *gc.Node, t *gc.Node) *obj.Prog {
- // TODO(austin): Add self-move test like in 6g (but be careful
- // of truncation moves)
-
- p := gc.Prog(as)
- gc.Naddr(&p.From, f)
- gc.Naddr(&p.To, t)
-
- switch as {
- case arm64.ACMP, arm64.AFCMPS, arm64.AFCMPD:
- if t != nil {
- if f.Op != gc.OREGISTER {
- gc.Fatalf("bad operands to gcmp")
- }
- p.From = p.To
- p.To = obj.Addr{}
- raddr(f, p)
- }
- }
-
- // Bad things the front end has done to us. Crash to find call stack.
- switch as {
- case arm64.AAND, arm64.AMUL:
- if p.From.Type == obj.TYPE_CONST {
- gc.Debug['h'] = 1
- gc.Fatalf("bad inst: %v", p)
- }
- case arm64.ACMP:
- if p.From.Type == obj.TYPE_MEM || p.To.Type == obj.TYPE_MEM {
- gc.Debug['h'] = 1
- gc.Fatalf("bad inst: %v", p)
- }
- }
-
- if gc.Debug['g'] != 0 {
- fmt.Printf("%v\n", p)
- }
-
- w := int32(0)
- switch as {
- case arm64.AMOVB,
- arm64.AMOVBU:
- w = 1
-
- case arm64.AMOVH,
- arm64.AMOVHU:
- w = 2
-
- case arm64.AMOVW,
- arm64.AMOVWU:
- w = 4
-
- case arm64.AMOVD:
- if p.From.Type == obj.TYPE_CONST || p.From.Type == obj.TYPE_ADDR {
- break
- }
- w = 8
- }
-
- if w != 0 && ((f != nil && p.From.Width < int64(w)) || (t != nil && p.To.Type != obj.TYPE_REG && p.To.Width > int64(w))) {
- gc.Dump("f", f)
- gc.Dump("t", t)
- gc.Fatalf("bad width: %v (%d, %d)\n", p, p.From.Width, p.To.Width)
- }
-
- return p
-}
-
-/*
- * insert n into reg slot of p
- */
-func raddr(n *gc.Node, p *obj.Prog) {
- var a obj.Addr
-
- gc.Naddr(&a, n)
- if a.Type != obj.TYPE_REG {
- if n != nil {
- gc.Fatalf("bad in raddr: %v", n.Op)
- } else {
- gc.Fatalf("bad in raddr: <null>")
- }
- p.Reg = 0
- } else {
- p.Reg = a.Reg
- }
-}
-
-func gcmp(as obj.As, lhs *gc.Node, rhs *gc.Node) *obj.Prog {
- if lhs.Op != gc.OREGISTER {
- gc.Fatalf("bad operands to gcmp: %v %v", lhs.Op, rhs.Op)
- }
-
- p := rawgins(as, rhs, nil)
- raddr(lhs, p)
- return p
-}
-
-/*
- * return Axxx for Oxxx on type t.
- */
-func optoas(op gc.Op, t *gc.Type) obj.As {
- if t == nil {
- gc.Fatalf("optoas: t is nil")
- }
-
- // avoid constant conversions in switches below
- const (
- OMINUS_ = uint32(gc.OMINUS) << 16
- OLSH_ = uint32(gc.OLSH) << 16
- ORSH_ = uint32(gc.ORSH) << 16
- OADD_ = uint32(gc.OADD) << 16
- OSUB_ = uint32(gc.OSUB) << 16
- OMUL_ = uint32(gc.OMUL) << 16
- ODIV_ = uint32(gc.ODIV) << 16
- OOR_ = uint32(gc.OOR) << 16
- OAND_ = uint32(gc.OAND) << 16
- OXOR_ = uint32(gc.OXOR) << 16
- OEQ_ = uint32(gc.OEQ) << 16
- ONE_ = uint32(gc.ONE) << 16
- OLT_ = uint32(gc.OLT) << 16
- OLE_ = uint32(gc.OLE) << 16
- OGE_ = uint32(gc.OGE) << 16
- OGT_ = uint32(gc.OGT) << 16
- OCMP_ = uint32(gc.OCMP) << 16
- OAS_ = uint32(gc.OAS) << 16
- OHMUL_ = uint32(gc.OHMUL) << 16
- OSQRT_ = uint32(gc.OSQRT) << 16
- )
-
- a := obj.AXXX
- switch uint32(op)<<16 | uint32(gc.Simtype[t.Etype]) {
- default:
- gc.Fatalf("optoas: no entry for op=%v type=%v", op, t)
-
- case OEQ_ | gc.TBOOL,
- OEQ_ | gc.TINT8,
- OEQ_ | gc.TUINT8,
- OEQ_ | gc.TINT16,
- OEQ_ | gc.TUINT16,
- OEQ_ | gc.TINT32,
- OEQ_ | gc.TUINT32,
- OEQ_ | gc.TINT64,
- OEQ_ | gc.TUINT64,
- OEQ_ | gc.TPTR32,
- OEQ_ | gc.TPTR64,
- OEQ_ | gc.TFLOAT32,
- OEQ_ | gc.TFLOAT64:
- a = arm64.ABEQ
-
- case ONE_ | gc.TBOOL,
- ONE_ | gc.TINT8,
- ONE_ | gc.TUINT8,
- ONE_ | gc.TINT16,
- ONE_ | gc.TUINT16,
- ONE_ | gc.TINT32,
- ONE_ | gc.TUINT32,
- ONE_ | gc.TINT64,
- ONE_ | gc.TUINT64,
- ONE_ | gc.TPTR32,
- ONE_ | gc.TPTR64,
- ONE_ | gc.TFLOAT32,
- ONE_ | gc.TFLOAT64:
- a = arm64.ABNE
-
- case OLT_ | gc.TINT8,
- OLT_ | gc.TINT16,
- OLT_ | gc.TINT32,
- OLT_ | gc.TINT64:
- a = arm64.ABLT
-
- case OLT_ | gc.TUINT8,
- OLT_ | gc.TUINT16,
- OLT_ | gc.TUINT32,
- OLT_ | gc.TUINT64,
- OLT_ | gc.TFLOAT32,
- OLT_ | gc.TFLOAT64:
- a = arm64.ABLO
-
- case OLE_ | gc.TINT8,
- OLE_ | gc.TINT16,
- OLE_ | gc.TINT32,
- OLE_ | gc.TINT64:
- a = arm64.ABLE
-
- case OLE_ | gc.TUINT8,
- OLE_ | gc.TUINT16,
- OLE_ | gc.TUINT32,
- OLE_ | gc.TUINT64,
- OLE_ | gc.TFLOAT32,
- OLE_ | gc.TFLOAT64:
- a = arm64.ABLS
-
- case OGT_ | gc.TINT8,
- OGT_ | gc.TINT16,
- OGT_ | gc.TINT32,
- OGT_ | gc.TINT64,
- OGT_ | gc.TFLOAT32,
- OGT_ | gc.TFLOAT64:
- a = arm64.ABGT
-
- case OGT_ | gc.TUINT8,
- OGT_ | gc.TUINT16,
- OGT_ | gc.TUINT32,
- OGT_ | gc.TUINT64:
- a = arm64.ABHI
-
- case OGE_ | gc.TINT8,
- OGE_ | gc.TINT16,
- OGE_ | gc.TINT32,
- OGE_ | gc.TINT64,
- OGE_ | gc.TFLOAT32,
- OGE_ | gc.TFLOAT64:
- a = arm64.ABGE
-
- case OGE_ | gc.TUINT8,
- OGE_ | gc.TUINT16,
- OGE_ | gc.TUINT32,
- OGE_ | gc.TUINT64:
- a = arm64.ABHS
-
- case OCMP_ | gc.TBOOL,
- OCMP_ | gc.TINT8,
- OCMP_ | gc.TINT16,
- OCMP_ | gc.TINT32,
- OCMP_ | gc.TPTR32,
- OCMP_ | gc.TINT64,
- OCMP_ | gc.TUINT8,
- OCMP_ | gc.TUINT16,
- OCMP_ | gc.TUINT32,
- OCMP_ | gc.TUINT64,
- OCMP_ | gc.TPTR64:
- a = arm64.ACMP
-
- case OCMP_ | gc.TFLOAT32:
- a = arm64.AFCMPS
-
- case OCMP_ | gc.TFLOAT64:
- a = arm64.AFCMPD
-
- case OAS_ | gc.TBOOL,
- OAS_ | gc.TINT8:
- a = arm64.AMOVB
-
- case OAS_ | gc.TUINT8:
- a = arm64.AMOVBU
-
- case OAS_ | gc.TINT16:
- a = arm64.AMOVH
-
- case OAS_ | gc.TUINT16:
- a = arm64.AMOVHU
-
- case OAS_ | gc.TINT32:
- a = arm64.AMOVW
-
- case OAS_ | gc.TUINT32,
- OAS_ | gc.TPTR32:
- a = arm64.AMOVWU
-
- case OAS_ | gc.TINT64,
- OAS_ | gc.TUINT64,
- OAS_ | gc.TPTR64:
- a = arm64.AMOVD
-
- case OAS_ | gc.TFLOAT32:
- a = arm64.AFMOVS
-
- case OAS_ | gc.TFLOAT64:
- a = arm64.AFMOVD
-
- case OADD_ | gc.TINT8,
- OADD_ | gc.TUINT8,
- OADD_ | gc.TINT16,
- OADD_ | gc.TUINT16,
- OADD_ | gc.TINT32,
- OADD_ | gc.TUINT32,
- OADD_ | gc.TPTR32,
- OADD_ | gc.TINT64,
- OADD_ | gc.TUINT64,
- OADD_ | gc.TPTR64:
- a = arm64.AADD
-
- case OADD_ | gc.TFLOAT32:
- a = arm64.AFADDS
-
- case OADD_ | gc.TFLOAT64:
- a = arm64.AFADDD
-
- case OSUB_ | gc.TINT8,
- OSUB_ | gc.TUINT8,
- OSUB_ | gc.TINT16,
- OSUB_ | gc.TUINT16,
- OSUB_ | gc.TINT32,
- OSUB_ | gc.TUINT32,
- OSUB_ | gc.TPTR32,
- OSUB_ | gc.TINT64,
- OSUB_ | gc.TUINT64,
- OSUB_ | gc.TPTR64:
- a = arm64.ASUB
-
- case OSUB_ | gc.TFLOAT32:
- a = arm64.AFSUBS
-
- case OSUB_ | gc.TFLOAT64:
- a = arm64.AFSUBD
-
- case OMINUS_ | gc.TINT8,
- OMINUS_ | gc.TUINT8,
- OMINUS_ | gc.TINT16,
- OMINUS_ | gc.TUINT16,
- OMINUS_ | gc.TINT32,
- OMINUS_ | gc.TUINT32,
- OMINUS_ | gc.TPTR32,
- OMINUS_ | gc.TINT64,
- OMINUS_ | gc.TUINT64,
- OMINUS_ | gc.TPTR64:
- a = arm64.ANEG
-
- case OMINUS_ | gc.TFLOAT32:
- a = arm64.AFNEGS
-
- case OMINUS_ | gc.TFLOAT64:
- a = arm64.AFNEGD
-
- case OAND_ | gc.TINT8,
- OAND_ | gc.TUINT8,
- OAND_ | gc.TINT16,
- OAND_ | gc.TUINT16,
- OAND_ | gc.TINT32,
- OAND_ | gc.TUINT32,
- OAND_ | gc.TPTR32,
- OAND_ | gc.TINT64,
- OAND_ | gc.TUINT64,
- OAND_ | gc.TPTR64:
- a = arm64.AAND
-
- case OOR_ | gc.TINT8,
- OOR_ | gc.TUINT8,
- OOR_ | gc.TINT16,
- OOR_ | gc.TUINT16,
- OOR_ | gc.TINT32,
- OOR_ | gc.TUINT32,
- OOR_ | gc.TPTR32,
- OOR_ | gc.TINT64,
- OOR_ | gc.TUINT64,
- OOR_ | gc.TPTR64:
- a = arm64.AORR
-
- case OXOR_ | gc.TINT8,
- OXOR_ | gc.TUINT8,
- OXOR_ | gc.TINT16,
- OXOR_ | gc.TUINT16,
- OXOR_ | gc.TINT32,
- OXOR_ | gc.TUINT32,
- OXOR_ | gc.TPTR32,
- OXOR_ | gc.TINT64,
- OXOR_ | gc.TUINT64,
- OXOR_ | gc.TPTR64:
- a = arm64.AEOR
-
- // TODO(minux): handle rotates
- //case CASE(OLROT, TINT8):
- //case CASE(OLROT, TUINT8):
- //case CASE(OLROT, TINT16):
- //case CASE(OLROT, TUINT16):
- //case CASE(OLROT, TINT32):
- //case CASE(OLROT, TUINT32):
- //case CASE(OLROT, TPTR32):
- //case CASE(OLROT, TINT64):
- //case CASE(OLROT, TUINT64):
- //case CASE(OLROT, TPTR64):
- // a = 0//???; RLDC?
- // break;
-
- case OLSH_ | gc.TINT8,
- OLSH_ | gc.TUINT8,
- OLSH_ | gc.TINT16,
- OLSH_ | gc.TUINT16,
- OLSH_ | gc.TINT32,
- OLSH_ | gc.TUINT32,
- OLSH_ | gc.TPTR32,
- OLSH_ | gc.TINT64,
- OLSH_ | gc.TUINT64,
- OLSH_ | gc.TPTR64:
- a = arm64.ALSL
-
- case ORSH_ | gc.TUINT8,
- ORSH_ | gc.TUINT16,
- ORSH_ | gc.TUINT32,
- ORSH_ | gc.TPTR32,
- ORSH_ | gc.TUINT64,
- ORSH_ | gc.TPTR64:
- a = arm64.ALSR
-
- case ORSH_ | gc.TINT8,
- ORSH_ | gc.TINT16,
- ORSH_ | gc.TINT32,
- ORSH_ | gc.TINT64:
- a = arm64.AASR
-
- case OHMUL_ | gc.TINT64:
- a = arm64.ASMULH
-
- case OHMUL_ | gc.TUINT64,
- OHMUL_ | gc.TPTR64:
- a = arm64.AUMULH
-
- case OMUL_ | gc.TINT8,
- OMUL_ | gc.TINT16,
- OMUL_ | gc.TINT32:
- a = arm64.ASMULL
-
- case OMUL_ | gc.TINT64:
- a = arm64.AMUL
-
- case OMUL_ | gc.TUINT8,
- OMUL_ | gc.TUINT16,
- OMUL_ | gc.TUINT32,
- OMUL_ | gc.TPTR32:
- // don't use word multiply, the high 32-bit are undefined.
- a = arm64.AUMULL
-
- case OMUL_ | gc.TUINT64,
- OMUL_ | gc.TPTR64:
- a = arm64.AMUL // for 64-bit multiplies, signedness doesn't matter.
-
- case OMUL_ | gc.TFLOAT32:
- a = arm64.AFMULS
-
- case OMUL_ | gc.TFLOAT64:
- a = arm64.AFMULD
-
- case ODIV_ | gc.TINT8,
- ODIV_ | gc.TINT16,
- ODIV_ | gc.TINT32,
- ODIV_ | gc.TINT64:
- a = arm64.ASDIV
-
- case ODIV_ | gc.TUINT8,
- ODIV_ | gc.TUINT16,
- ODIV_ | gc.TUINT32,
- ODIV_ | gc.TPTR32,
- ODIV_ | gc.TUINT64,
- ODIV_ | gc.TPTR64:
- a = arm64.AUDIV
-
- case ODIV_ | gc.TFLOAT32:
- a = arm64.AFDIVS
-
- case ODIV_ | gc.TFLOAT64:
- a = arm64.AFDIVD
-
- case OSQRT_ | gc.TFLOAT64:
- a = arm64.AFSQRTD
- }
-
- return a
-}
-
-const (
- ODynam = 1 << 0
- OAddable = 1 << 1
-)
-
-func xgen(n *gc.Node, a *gc.Node, o int) bool {
- // TODO(minux)
-
- return -1 != 0 /*TypeKind(100016)*/
-}
-
-func sudoclean() {
- return
-}
-
-/*
- * generate code to compute address of n,
- * a reference to a (perhaps nested) field inside
- * an array or struct.
- * return 0 on failure, 1 on success.
- * on success, leaves usable address in a.
- *
- * caller is responsible for calling sudoclean
- * after successful sudoaddable,
- * to release the register used for a.
- */
-func sudoaddable(as obj.As, n *gc.Node, a *obj.Addr) bool {
- // TODO(minux)
-
- *a = obj.Addr{}
- return false
-}
diff --git a/src/cmd/compile/internal/arm64/peep.go b/src/cmd/compile/internal/arm64/peep.go
deleted file mode 100644
index e32c264..0000000
--- a/src/cmd/compile/internal/arm64/peep.go
+++ /dev/null
@@ -1,797 +0,0 @@
-// Derived from Inferno utils/6c/peep.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6c/peep.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth at terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth at terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// Portions Copyright © 2009 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-package arm64
-
-import (
- "cmd/compile/internal/gc"
- "cmd/internal/obj"
- "cmd/internal/obj/arm64"
- "fmt"
-)
-
-var gactive uint32
-
-func peep(firstp *obj.Prog) {
- g := gc.Flowstart(firstp, nil)
- if g == nil {
- return
- }
- gactive = 0
-
- var p *obj.Prog
- var r *gc.Flow
- var t int
-loop1:
- if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
- gc.Dumpit("loop1", g.Start, 0)
- }
-
- t = 0
- for r = g.Start; r != nil; r = r.Link {
- p = r.Prog
-
- // TODO(minux) Handle smaller moves. arm and amd64
- // distinguish between moves that *must* sign/zero
- // extend and moves that don't care so they
- // can eliminate moves that don't care without
- // breaking moves that do care. This might let us
- // simplify or remove the next peep loop, too.
- if p.As == arm64.AMOVD || p.As == arm64.AFMOVD {
- if regtyp(&p.To) {
- // Try to eliminate reg->reg moves
- if regtyp(&p.From) {
- if p.From.Type == p.To.Type {
- if copyprop(r) {
- excise(r)
- t++
- } else if subprop(r) && copyprop(r) {
- excise(r)
- t++
- }
- }
- }
- }
- }
- }
-
- if t != 0 {
- goto loop1
- }
-
- /*
- * look for MOVB x,R; MOVB R,R (for small MOVs not handled above)
- */
- var p1 *obj.Prog
- var r1 *gc.Flow
- for r := g.Start; r != nil; r = r.Link {
- p = r.Prog
- switch p.As {
- default:
- continue
-
- case arm64.AMOVH,
- arm64.AMOVHU,
- arm64.AMOVB,
- arm64.AMOVBU,
- arm64.AMOVW,
- arm64.AMOVWU:
- if p.To.Type != obj.TYPE_REG {
- continue
- }
- }
-
- r1 = r.Link
- if r1 == nil {
- continue
- }
- p1 = r1.Prog
- if p1.As != p.As {
- continue
- }
- if p1.From.Type != obj.TYPE_REG || p1.From.Reg != p.To.Reg {
- continue
- }
- if p1.To.Type != obj.TYPE_REG || p1.To.Reg != p.To.Reg {
- continue
- }
- excise(r1)
- }
-
- if gc.Debug['D'] > 1 {
- goto ret /* allow following code improvement to be suppressed */
- }
-
- // MOVD $c, R'; ADD R', R (R' unused) -> ADD $c, R
- for r := g.Start; r != nil; r = r.Link {
- p = r.Prog
- switch p.As {
- default:
- continue
-
- case arm64.AMOVD:
- if p.To.Type != obj.TYPE_REG {
- continue
- }
- if p.From.Type != obj.TYPE_CONST {
- continue
- }
- if p.From.Offset < 0 || 4096 <= p.From.Offset {
- continue
- }
- }
- r1 = r.Link
- if r1 == nil {
- continue
- }
- p1 = r1.Prog
- if p1.As != arm64.AADD && p1.As != arm64.ASUB { // TODO(aram): also logical after we have bimm.
- continue
- }
- if p1.From.Type != obj.TYPE_REG || p1.From.Reg != p.To.Reg {
- continue
- }
- if p1.To.Type != obj.TYPE_REG {
- continue
- }
- if gc.Debug['P'] != 0 {
- fmt.Printf("encoding $%d directly into %v in:\n%v\n%v\n", p.From.Offset, obj.Aconv(p1.As), p, p1)
- }
- p1.From.Type = obj.TYPE_CONST
- p1.From = p.From
- excise(r)
- }
-
- /* TODO(minux):
- * look for OP x,y,R; CMP R, $0 -> OP.S x,y,R
- * when OP can set condition codes correctly
- */
-
-ret:
- gc.Flowend(g)
-}
-
-func excise(r *gc.Flow) {
- p := r.Prog
- if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
- fmt.Printf("%v ===delete===\n", p)
- }
- obj.Nopout(p)
- gc.Ostats.Ndelmov++
-}
-
-func regtyp(a *obj.Addr) bool {
- // TODO(rsc): Floating point register exclusions?
- return a.Type == obj.TYPE_REG && arm64.REG_R0 <= a.Reg && a.Reg <= arm64.REG_F31 && a.Reg != arm64.REGZERO
-}
-
-/*
- * the idea is to substitute
- * one register for another
- * from one MOV to another
- * MOV a, R1
- * ADD b, R1 / no use of R2
- * MOV R1, R2
- * would be converted to
- * MOV a, R2
- * ADD b, R2
- * MOV R2, R1
- * hopefully, then the former or latter MOV
- * will be eliminated by copy propagation.
- *
- * r0 (the argument, not the register) is the MOV at the end of the
- * above sequences. This returns 1 if it modified any instructions.
- */
-func subprop(r0 *gc.Flow) bool {
- p := r0.Prog
- v1 := &p.From
- if !regtyp(v1) {
- return false
- }
- v2 := &p.To
- if !regtyp(v2) {
- return false
- }
- for r := gc.Uniqp(r0); r != nil; r = gc.Uniqp(r) {
- if gc.Uniqs(r) == nil {
- break
- }
- p = r.Prog
- if p.As == obj.AVARDEF || p.As == obj.AVARKILL {
- continue
- }
- if p.Info.Flags&gc.Call != 0 {
- return false
- }
-
- if p.Info.Flags&(gc.RightRead|gc.RightWrite) == gc.RightWrite {
- if p.To.Type == v1.Type {
- if p.To.Reg == v1.Reg {
- copysub(&p.To, v1, v2, true)
- if gc.Debug['P'] != 0 {
- fmt.Printf("gotit: %v->%v\n%v", gc.Ctxt.Dconv(v1), gc.Ctxt.Dconv(v2), r.Prog)
- if p.From.Type == v2.Type {
- fmt.Printf(" excise")
- }
- fmt.Printf("\n")
- }
-
- for r = gc.Uniqs(r); r != r0; r = gc.Uniqs(r) {
- p = r.Prog
- copysub(&p.From, v1, v2, true)
- copysub1(p, v1, v2, true)
- copysub(&p.To, v1, v2, true)
- if gc.Debug['P'] != 0 {
- fmt.Printf("%v\n", r.Prog)
- }
- }
-
- v1.Reg, v2.Reg = v2.Reg, v1.Reg
- if gc.Debug['P'] != 0 {
- fmt.Printf("%v last\n", r.Prog)
- }
- return true
- }
- }
- }
-
- if copyau(&p.From, v2) || copyau1(p, v2) || copyau(&p.To, v2) {
- break
- }
- if copysub(&p.From, v1, v2, false) || copysub1(p, v1, v2, false) || copysub(&p.To, v1, v2, false) {
- break
- }
- }
-
- return false
-}
-
-/*
- * The idea is to remove redundant copies.
- * v1->v2 F=0
- * (use v2 s/v2/v1/)*
- * set v1 F=1
- * use v2 return fail (v1->v2 move must remain)
- * -----------------
- * v1->v2 F=0
- * (use v2 s/v2/v1/)*
- * set v1 F=1
- * set v2 return success (caller can remove v1->v2 move)
- */
-func copyprop(r0 *gc.Flow) bool {
- p := r0.Prog
- v1 := &p.From
- v2 := &p.To
- if copyas(v1, v2) {
- if gc.Debug['P'] != 0 {
- fmt.Printf("eliminating self-move: %v\n", r0.Prog)
- }
- return true
- }
-
- gactive++
- if gc.Debug['P'] != 0 {
- fmt.Printf("trying to eliminate %v->%v move from:\n%v\n", gc.Ctxt.Dconv(v1), gc.Ctxt.Dconv(v2), r0.Prog)
- }
- return copy1(v1, v2, r0.S1, false)
-}
-
-// copy1 replaces uses of v2 with v1 starting at r and returns 1 if
-// all uses were rewritten.
-func copy1(v1 *obj.Addr, v2 *obj.Addr, r *gc.Flow, f bool) bool {
- if uint32(r.Active) == gactive {
- if gc.Debug['P'] != 0 {
- fmt.Printf("act set; return 1\n")
- }
- return true
- }
-
- r.Active = int32(gactive)
- if gc.Debug['P'] != 0 {
- fmt.Printf("copy1 replace %v with %v f=%v\n", gc.Ctxt.Dconv(v2), gc.Ctxt.Dconv(v1), f)
- }
- for ; r != nil; r = r.S1 {
- p := r.Prog
- if gc.Debug['P'] != 0 {
- fmt.Printf("%v", p)
- }
- if !f && gc.Uniqp(r) == nil {
- // Multiple predecessors; conservatively
- // assume v1 was set on other path
- f = true
-
- if gc.Debug['P'] != 0 {
- fmt.Printf("; merge; f=%v", f)
- }
- }
-
- switch t := copyu(p, v2, nil); t {
- case 2: /* rar, can't split */
- if gc.Debug['P'] != 0 {
- fmt.Printf("; %v rar; return 0\n", gc.Ctxt.Dconv(v2))
- }
- return false
-
- case 3: /* set */
- if gc.Debug['P'] != 0 {
- fmt.Printf("; %v set; return 1\n", gc.Ctxt.Dconv(v2))
- }
- return true
-
- case 1, /* used, substitute */
- 4: /* use and set */
- if f {
- if gc.Debug['P'] == 0 {
- return false
- }
- if t == 4 {
- fmt.Printf("; %v used+set and f=%v; return 0\n", gc.Ctxt.Dconv(v2), f)
- } else {
- fmt.Printf("; %v used and f=%v; return 0\n", gc.Ctxt.Dconv(v2), f)
- }
- return false
- }
-
- if copyu(p, v2, v1) != 0 {
- if gc.Debug['P'] != 0 {
- fmt.Printf("; sub fail; return 0\n")
- }
- return false
- }
-
- if gc.Debug['P'] != 0 {
- fmt.Printf("; sub %v->%v\n => %v", gc.Ctxt.Dconv(v2), gc.Ctxt.Dconv(v1), p)
- }
- if t == 4 {
- if gc.Debug['P'] != 0 {
- fmt.Printf("; %v used+set; return 1\n", gc.Ctxt.Dconv(v2))
- }
- return true
- }
- }
-
- if !f {
- t := copyu(p, v1, nil)
- if t == 2 || t == 3 || t == 4 {
- f = true
- if gc.Debug['P'] != 0 {
- fmt.Printf("; %v set and !f; f=%v", gc.Ctxt.Dconv(v1), f)
- }
- }
- }
-
- if gc.Debug['P'] != 0 {
- fmt.Printf("\n")
- }
- if r.S2 != nil {
- if !copy1(v1, v2, r.S2, f) {
- return false
- }
- }
- }
- return true
-}
-
-// If s==nil, copyu returns the set/use of v in p; otherwise, it
-// modifies p to replace reads of v with reads of s and returns 0 for
-// success or non-zero for failure.
-//
-// If s==nil, copy returns one of the following values:
-// 1 if v only used
-// 2 if v is set and used in one address (read-alter-rewrite;
-// can't substitute)
-// 3 if v is only set
-// 4 if v is set in one address and used in another (so addresses
-// can be rewritten independently)
-// 0 otherwise (not touched)
-func copyu(p *obj.Prog, v *obj.Addr, s *obj.Addr) int {
- if p.From3Type() != obj.TYPE_NONE {
- // 7g never generates a from3
- fmt.Printf("copyu: from3 (%v) not implemented\n", gc.Ctxt.Dconv(p.From3))
- }
- if p.RegTo2 != obj.REG_NONE {
- // 7g never generates a to2
- fmt.Printf("copyu: RegTo2 (%v) not implemented\n", obj.Rconv(int(p.RegTo2)))
- }
-
- switch p.As {
- default:
- fmt.Printf("copyu: can't find %v\n", obj.Aconv(p.As))
- return 2
-
- case obj.ANOP, /* read p->from, write p->to */
- arm64.ANEG,
- arm64.AFNEGD,
- arm64.AFNEGS,
- arm64.AFSQRTD,
- arm64.AFCVTZSD,
- arm64.AFCVTZSS,
- arm64.AFCVTZSDW,
- arm64.AFCVTZSSW,
- arm64.AFCVTZUD,
- arm64.AFCVTZUS,
- arm64.AFCVTZUDW,
- arm64.AFCVTZUSW,
- arm64.AFCVTSD,
- arm64.AFCVTDS,
- arm64.ASCVTFD,
- arm64.ASCVTFS,
- arm64.ASCVTFWD,
- arm64.ASCVTFWS,
- arm64.AUCVTFD,
- arm64.AUCVTFS,
- arm64.AUCVTFWD,
- arm64.AUCVTFWS,
- arm64.AMOVB,
- arm64.AMOVBU,
- arm64.AMOVH,
- arm64.AMOVHU,
- arm64.AMOVW,
- arm64.AMOVWU,
- arm64.AMOVD,
- arm64.AFMOVS,
- arm64.AFMOVD:
- if p.Scond == 0 {
- if s != nil {
- if copysub(&p.From, v, s, true) {
- return 1
- }
-
- // Update only indirect uses of v in p->to
- if !copyas(&p.To, v) {
- if copysub(&p.To, v, s, true) {
- return 1
- }
- }
- return 0
- }
-
- if copyas(&p.To, v) {
- // Fix up implicit from
- if p.From.Type == obj.TYPE_NONE {
- p.From = p.To
- }
- if copyau(&p.From, v) {
- return 4
- }
- return 3
- }
-
- if copyau(&p.From, v) {
- return 1
- }
- if copyau(&p.To, v) {
- // p->to only indirectly uses v
- return 1
- }
-
- return 0
- }
-
- /* rar p->from, write p->to or read p->from, rar p->to */
- if p.From.Type == obj.TYPE_MEM {
- if copyas(&p.From, v) {
- // No s!=nil check; need to fail
- // anyway in that case
- return 2
- }
-
- if s != nil {
- if copysub(&p.To, v, s, true) {
- return 1
- }
- return 0
- }
-
- if copyas(&p.To, v) {
- return 3
- }
- } else if p.To.Type == obj.TYPE_MEM {
- if copyas(&p.To, v) {
- return 2
- }
- if s != nil {
- if copysub(&p.From, v, s, true) {
- return 1
- }
- return 0
- }
-
- if copyau(&p.From, v) {
- return 1
- }
- } else {
- fmt.Printf("copyu: bad %v\n", p)
- }
-
- return 0
-
- case arm64.AADD, /* read p->from, read p->reg, write p->to */
- arm64.AADDS,
- arm64.ASUB,
- arm64.AADC,
- arm64.AAND,
- arm64.AORR,
- arm64.AEOR,
- arm64.AROR,
- arm64.AMUL,
- arm64.ASMULL,
- arm64.AUMULL,
- arm64.ASMULH,
- arm64.AUMULH,
- arm64.ASDIV,
- arm64.AUDIV,
- arm64.ALSL,
- arm64.ALSR,
- arm64.AASR,
- arm64.AFADDD,
- arm64.AFADDS,
- arm64.AFSUBD,
- arm64.AFSUBS,
- arm64.AFMULD,
- arm64.AFMULS,
- arm64.AFDIVD,
- arm64.AFDIVS:
- if s != nil {
- if copysub(&p.From, v, s, true) {
- return 1
- }
- if copysub1(p, v, s, true) {
- return 1
- }
-
- // Update only indirect uses of v in p->to
- if !copyas(&p.To, v) {
- if copysub(&p.To, v, s, true) {
- return 1
- }
- }
- return 0
- }
-
- if copyas(&p.To, v) {
- if p.Reg == 0 {
- // Fix up implicit reg (e.g., ADD
- // R3,R4 -> ADD R3,R4,R4) so we can
- // update reg and to separately.
- p.Reg = p.To.Reg
- }
-
- if copyau(&p.From, v) {
- return 4
- }
- if copyau1(p, v) {
- return 4
- }
- return 3
- }
-
- if copyau(&p.From, v) {
- return 1
- }
- if copyau1(p, v) {
- return 1
- }
- if copyau(&p.To, v) {
- return 1
- }
- return 0
-
- case arm64.ABEQ,
- arm64.ABNE,
- arm64.ABGE,
- arm64.ABLT,
- arm64.ABGT,
- arm64.ABLE,
- arm64.ABLO,
- arm64.ABLS,
- arm64.ABHI,
- arm64.ABHS:
- return 0
-
- case obj.ACHECKNIL, /* read p->from */
- arm64.ACMP, /* read p->from, read p->reg */
- arm64.AFCMPD,
- arm64.AFCMPS:
- if s != nil {
- if copysub(&p.From, v, s, true) {
- return 1
- }
- if copysub1(p, v, s, true) {
- return 1
- }
- return 0
- }
-
- if copyau(&p.From, v) {
- return 1
- }
- if copyau1(p, v) {
- return 1
- }
- return 0
-
- case arm64.AB: /* read p->to */
- if s != nil {
- if copysub(&p.To, v, s, true) {
- return 1
- }
- return 0
- }
-
- if copyau(&p.To, v) {
- return 1
- }
- return 0
-
- case obj.ARET: /* funny */
- if s != nil {
- return 0
- }
-
- // All registers die at this point, so claim
- // everything is set (and not used).
- return 3
-
- case arm64.ABL: /* funny */
- if p.From.Type == obj.TYPE_REG && v.Type == obj.TYPE_REG && p.From.Reg == v.Reg {
- return 2
- }
-
- if s != nil {
- if copysub(&p.To, v, s, true) {
- return 1
- }
- return 0
- }
-
- if copyau(&p.To, v) {
- return 4
- }
- return 3
-
- // R31 is zero, used by DUFFZERO, cannot be substituted.
- // R16 is ptr to memory, used and set, cannot be substituted.
- case obj.ADUFFZERO:
- if v.Type == obj.TYPE_REG {
- if v.Reg == 31 {
- return 1
- }
- if v.Reg == 16 {
- return 2
- }
- }
-
- return 0
-
- // R16, R17 are ptr to src, dst, used and set, cannot be substituted.
- // R27 is scratch, set by DUFFCOPY, cannot be substituted.
- case obj.ADUFFCOPY:
- if v.Type == obj.TYPE_REG {
- if v.Reg == 16 || v.Reg == 17 {
- return 2
- }
- if v.Reg == 27 {
- return 3
- }
- }
-
- return 0
-
- case arm64.AHINT,
- obj.ATEXT,
- obj.APCDATA,
- obj.AFUNCDATA,
- obj.AVARDEF,
- obj.AVARKILL,
- obj.AVARLIVE,
- obj.AUSEFIELD:
- return 0
- }
-}
-
-// copyas returns true if a and v address the same register.
-//
-// If a is the from operand, this means this operation reads the
-// register in v. If a is the to operand, this means this operation
-// writes the register in v.
-func copyas(a *obj.Addr, v *obj.Addr) bool {
- return regtyp(v) && a.Type == v.Type && a.Reg == v.Reg
-}
-
-// copyau returns true if a either directly or indirectly addresses the
-// same register as v.
-//
-// If a is the from operand, this means this operation reads the
-// register in v. If a is the to operand, this means the operation
-// either reads or writes the register in v (if !copyas(a, v), then
-// the operation reads the register in v).
-func copyau(a *obj.Addr, v *obj.Addr) bool {
- if copyas(a, v) {
- return true
- }
- if v.Type == obj.TYPE_REG {
- if a.Type == obj.TYPE_MEM || (a.Type == obj.TYPE_ADDR && a.Reg != 0) {
- if v.Reg == a.Reg {
- return true
- }
- }
- }
- return false
-}
-
-// copyau1 returns true if p->reg references the same register as v and v
-// is a direct reference.
-func copyau1(p *obj.Prog, v *obj.Addr) bool {
- return regtyp(v) && v.Reg != 0 && p.Reg == v.Reg
-}
-
-// copysub replaces v with s in a if f==true or indicates it if could if f==false.
-// Returns true on failure to substitute (it always succeeds on arm64).
-// TODO(dfc) remove unused return value, remove calls with f=false as they do nothing.
-func copysub(a *obj.Addr, v *obj.Addr, s *obj.Addr, f bool) bool {
- if f && copyau(a, v) {
- a.Reg = s.Reg
- }
- return false
-}
-
-// copysub1 replaces v with s in p1->reg if f==true or indicates if it could if f==false.
-// Returns true on failure to substitute (it always succeeds on arm64).
-// TODO(dfc) remove unused return value, remove calls with f=false as they do nothing.
-func copysub1(p1 *obj.Prog, v *obj.Addr, s *obj.Addr, f bool) bool {
- if f && copyau1(p1, v) {
- p1.Reg = s.Reg
- }
- return false
-}
-
-func sameaddr(a *obj.Addr, v *obj.Addr) bool {
- if a.Type != v.Type {
- return false
- }
- if regtyp(v) && a.Reg == v.Reg {
- return true
- }
- if v.Type == obj.NAME_AUTO || v.Type == obj.NAME_PARAM {
- if v.Offset == a.Offset {
- return true
- }
- }
- return false
-}
-
-func smallindir(a *obj.Addr, reg *obj.Addr) bool {
- return reg.Type == obj.TYPE_REG && a.Type == obj.TYPE_MEM && a.Reg == reg.Reg && 0 <= a.Offset && a.Offset < 4096
-}
-
-func stackaddr(a *obj.Addr) bool {
- return a.Type == obj.TYPE_REG && a.Reg == arm64.REGSP
-}
diff --git a/src/cmd/compile/internal/arm64/prog.go b/src/cmd/compile/internal/arm64/prog.go
index d504d0f..5d3ec67 100644
--- a/src/cmd/compile/internal/arm64/prog.go
+++ b/src/cmd/compile/internal/arm64/prog.go
@@ -24,14 +24,13 @@ const (
// size variants of an operation even if we just use a subset.
//
// The table is formatted for 8-space tabs.
-var progtable = [arm64.ALAST & obj.AMask]obj.ProgInfo{
+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.ACHECKNIL: {Flags: gc.LeftRead},
obj.AVARDEF: {Flags: gc.Pseudo | gc.RightWrite},
obj.AVARKILL: {Flags: gc.Pseudo | gc.RightWrite},
obj.AVARLIVE: {Flags: gc.Pseudo | gc.LeftRead},
@@ -42,26 +41,46 @@ var progtable = [arm64.ALAST & obj.AMask]obj.ProgInfo{
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},
- arm64.AAND & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
- arm64.AORR & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
- arm64.AEOR & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
- arm64.AMUL & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
- arm64.ASMULL & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
- arm64.AUMULL & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
- arm64.ASMULH & obj.AMask: {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
- arm64.AUMULH & obj.AMask: {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
- arm64.ASDIV & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
- arm64.AUDIV & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
- arm64.ALSL & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
- arm64.ALSR & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
- arm64.AASR & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
- arm64.ACMP & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead},
- arm64.AADC & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite | gc.UseCarry},
- arm64.AROR & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
- arm64.AADDS & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite | gc.SetCarry},
+ 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},
@@ -103,39 +122,50 @@ var progtable = [arm64.ALAST & obj.AMask]obj.ProgInfo{
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.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},
- obj.ARET: {Flags: gc.Break},
- obj.ADUFFZERO: {Flags: gc.Call},
- obj.ADUFFCOPY: {Flags: gc.Call},
+ arm64.AB & obj.AMask: {Flags: gc.Jump | gc.Break},
+ arm64.ABL & obj.AMask: {Flags: gc.Call},
+ arm64.ABEQ & obj.AMask: {Flags: gc.Cjmp},
+ arm64.ABNE & obj.AMask: {Flags: gc.Cjmp},
+ arm64.ABGE & obj.AMask: {Flags: gc.Cjmp},
+ arm64.ABLT & obj.AMask: {Flags: gc.Cjmp},
+ arm64.ABGT & obj.AMask: {Flags: gc.Cjmp},
+ arm64.ABLE & obj.AMask: {Flags: gc.Cjmp},
+ arm64.ABLO & obj.AMask: {Flags: gc.Cjmp},
+ arm64.ABLS & obj.AMask: {Flags: gc.Cjmp},
+ arm64.ABHI & obj.AMask: {Flags: gc.Cjmp},
+ arm64.ABHS & obj.AMask: {Flags: gc.Cjmp},
+ arm64.ACBZ & obj.AMask: {Flags: gc.Cjmp},
+ arm64.ACBNZ & obj.AMask: {Flags: gc.Cjmp},
+ 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) {
- info := &p.Info
- *info = progtable[p.As&obj.AMask]
+func proginfo(p *obj.Prog) gc.ProgInfo {
+ info := progtable[p.As&obj.AMask]
if info.Flags == 0 {
gc.Fatalf("proginfo: unknown instruction %v", p)
}
@@ -145,34 +175,10 @@ func proginfo(p *obj.Prog) {
info.Flags |= gc.RightRead /*CanRegRead |*/
}
- if (p.From.Type == obj.TYPE_MEM || p.From.Type == obj.TYPE_ADDR) && p.From.Reg != 0 {
- info.Regindex |= RtoB(int(p.From.Reg))
- if p.Scond != 0 {
- info.Regset |= RtoB(int(p.From.Reg))
- }
- }
-
- if (p.To.Type == obj.TYPE_MEM || p.To.Type == obj.TYPE_ADDR) && p.To.Reg != 0 {
- info.Regindex |= RtoB(int(p.To.Reg))
- if p.Scond != 0 {
- info.Regset |= RtoB(int(p.To.Reg))
- }
- }
-
if p.From.Type == obj.TYPE_ADDR && p.From.Sym != nil && (info.Flags&gc.LeftRead != 0) {
info.Flags &^= gc.LeftRead
info.Flags |= gc.LeftAddr
}
- if p.As == obj.ADUFFZERO {
- info.Reguse |= RtoB(arm64.REGRT1)
- info.Regset |= RtoB(arm64.REGRT1)
- }
-
- if p.As == obj.ADUFFCOPY {
- // TODO(austin) Revisit when duffcopy is implemented
- info.Reguse |= RtoB(arm64.REGRT1) | RtoB(arm64.REGRT2) | RtoB(arm64.REG_R5)
-
- info.Regset |= RtoB(arm64.REGRT1) | RtoB(arm64.REGRT2)
- }
+ return info
}
diff --git a/src/cmd/compile/internal/arm64/reg.go b/src/cmd/compile/internal/arm64/reg.go
deleted file mode 100644
index 6e24dc2..0000000
--- a/src/cmd/compile/internal/arm64/reg.go
+++ /dev/null
@@ -1,169 +0,0 @@
-// Derived from Inferno utils/6c/reg.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6c/reg.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth at terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth at terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// Portions Copyright © 2009 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-package arm64
-
-import (
- "cmd/compile/internal/gc"
- "cmd/internal/obj/arm64"
-)
-
-const (
- NREGVAR = 64 /* 32 general + 32 floating */
-)
-
-var regname = []string{
- ".R0",
- ".R1",
- ".R2",
- ".R3",
- ".R4",
- ".R5",
- ".R6",
- ".R7",
- ".R8",
- ".R9",
- ".R10",
- ".R11",
- ".R12",
- ".R13",
- ".R14",
- ".R15",
- ".R16",
- ".R17",
- ".R18",
- ".R19",
- ".R20",
- ".R21",
- ".R22",
- ".R23",
- ".R24",
- ".R25",
- ".R26",
- ".R27",
- ".R28",
- ".R29",
- ".R30",
- ".R31",
- ".F0",
- ".F1",
- ".F2",
- ".F3",
- ".F4",
- ".F5",
- ".F6",
- ".F7",
- ".F8",
- ".F9",
- ".F10",
- ".F11",
- ".F12",
- ".F13",
- ".F14",
- ".F15",
- ".F16",
- ".F17",
- ".F18",
- ".F19",
- ".F20",
- ".F21",
- ".F22",
- ".F23",
- ".F24",
- ".F25",
- ".F26",
- ".F27",
- ".F28",
- ".F29",
- ".F30",
- ".F31",
-}
-
-func regnames(n *int) []string {
- *n = NREGVAR
- return regname
-}
-
-func excludedregs() uint64 {
- // Exclude registers with fixed functions
- regbits := RtoB(arm64.REGRT1) | RtoB(arm64.REGRT2) | RtoB(arm64.REGPR)
-
- // Exclude R26 - R31.
- for r := arm64.REGMAX + 1; r <= arm64.REGZERO; r++ {
- regbits |= RtoB(r)
- }
-
- // Also exclude floating point registers with fixed constants
- regbits |= RtoB(arm64.REG_F27) | RtoB(arm64.REG_F28) | RtoB(arm64.REG_F29) | RtoB(arm64.REG_F30) | RtoB(arm64.REG_F31)
-
- return regbits
-}
-
-func doregbits(r int) uint64 {
- return 0
-}
-
-/*
- * track register variables including external registers:
- * bit reg
- * 0 R0
- * 1 R1
- * ... ...
- * 31 R31
- * 32+0 F0
- * 32+1 F1
- * ... ...
- * 32+31 F31
- */
-func RtoB(r int) uint64 {
- if r >= arm64.REG_R0 && r <= arm64.REG_R31 {
- return 1 << uint(r-arm64.REG_R0)
- }
- if r >= arm64.REG_F0 && r <= arm64.REG_F31 {
- return 1 << uint(32+r-arm64.REG_F0)
- }
- return 0
-}
-
-func BtoR(b uint64) int {
- b &= 0xffffffff
- if b == 0 {
- return 0
- }
- return gc.Bitno(b) + arm64.REG_R0
-}
-
-func BtoF(b uint64) int {
- b >>= 32
- if b == 0 {
- return 0
- }
- return gc.Bitno(b) + arm64.REG_F0
-}
diff --git a/src/cmd/compile/internal/arm64/ssa.go b/src/cmd/compile/internal/arm64/ssa.go
new file mode 100644
index 0000000..5670ef8
--- /dev/null
+++ b/src/cmd/compile/internal/arm64/ssa.go
@@ -0,0 +1,844 @@
+// Copyright 2016 The Go Authors. 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 (
+ "math"
+
+ "cmd/compile/internal/gc"
+ "cmd/compile/internal/ssa"
+ "cmd/internal/obj"
+ "cmd/internal/obj/arm64"
+)
+
+// loadByType returns the load instruction of the given type.
+func loadByType(t ssa.Type) obj.As {
+ if t.IsFloat() {
+ switch t.Size() {
+ case 4:
+ return arm64.AFMOVS
+ case 8:
+ return arm64.AFMOVD
+ }
+ } else {
+ switch t.Size() {
+ case 1:
+ if t.IsSigned() {
+ return arm64.AMOVB
+ } else {
+ return arm64.AMOVBU
+ }
+ case 2:
+ if t.IsSigned() {
+ return arm64.AMOVH
+ } else {
+ return arm64.AMOVHU
+ }
+ case 4:
+ if t.IsSigned() {
+ return arm64.AMOVW
+ } else {
+ return arm64.AMOVWU
+ }
+ case 8:
+ return arm64.AMOVD
+ }
+ }
+ panic("bad load type")
+}
+
+// storeByType returns the store instruction of the given type.
+func storeByType(t ssa.Type) obj.As {
+ if t.IsFloat() {
+ switch t.Size() {
+ case 4:
+ return arm64.AFMOVS
+ case 8:
+ return arm64.AFMOVD
+ }
+ } else {
+ switch t.Size() {
+ case 1:
+ return arm64.AMOVB
+ case 2:
+ return arm64.AMOVH
+ case 4:
+ return arm64.AMOVW
+ case 8:
+ return arm64.AMOVD
+ }
+ }
+ panic("bad store type")
+}
+
+// makeshift encodes a register shifted by a constant, used as an Offset in Prog
+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)
+ p.From.Type = obj.TYPE_SHIFT
+ p.From.Offset = makeshift(r1, typ, s)
+ p.Reg = r0
+ if r != 0 {
+ p.To.Type = obj.TYPE_REG
+ p.To.Reg = r
+ }
+ return p
+}
+
+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
+ }
+ x := v.Args[0].Reg()
+ y := v.Reg()
+ if x == y {
+ return
+ }
+ as := arm64.AMOVD
+ if v.Type.IsFloat() {
+ switch v.Type.Size() {
+ case 4:
+ as = arm64.AFMOVS
+ case 8:
+ as = arm64.AFMOVD
+ default:
+ panic("bad float size")
+ }
+ }
+ p := gc.Prog(as)
+ p.From.Type = obj.TYPE_REG
+ p.From.Reg = x
+ p.To.Type = obj.TYPE_REG
+ p.To.Reg = y
+ case ssa.OpARM64MOVDnop:
+ if v.Reg() != v.Args[0].Reg() {
+ v.Fatalf("input[0] and output not in same register %s", v.LongString())
+ }
+ // nothing to do
+ case ssa.OpLoadReg:
+ if v.Type.IsFlags() {
+ v.Fatalf("load flags not implemented: %v", v.LongString())
+ return
+ }
+ p := gc.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.From.Type = obj.TYPE_REG
+ p.From.Reg = v.Args[0].Reg()
+ gc.AddrAuto(&p.To, v)
+ case ssa.OpARM64ADD,
+ ssa.OpARM64SUB,
+ ssa.OpARM64AND,
+ ssa.OpARM64OR,
+ ssa.OpARM64XOR,
+ ssa.OpARM64BIC,
+ ssa.OpARM64MUL,
+ ssa.OpARM64MULW,
+ ssa.OpARM64MULH,
+ ssa.OpARM64UMULH,
+ ssa.OpARM64MULL,
+ ssa.OpARM64UMULL,
+ ssa.OpARM64DIV,
+ ssa.OpARM64UDIV,
+ ssa.OpARM64DIVW,
+ ssa.OpARM64UDIVW,
+ ssa.OpARM64MOD,
+ ssa.OpARM64UMOD,
+ ssa.OpARM64MODW,
+ ssa.OpARM64UMODW,
+ ssa.OpARM64SLL,
+ ssa.OpARM64SRL,
+ ssa.OpARM64SRA,
+ ssa.OpARM64FADDS,
+ ssa.OpARM64FADDD,
+ ssa.OpARM64FSUBS,
+ ssa.OpARM64FSUBD,
+ ssa.OpARM64FMULS,
+ ssa.OpARM64FMULD,
+ ssa.OpARM64FDIVS,
+ ssa.OpARM64FDIVD:
+ r := v.Reg()
+ r1 := v.Args[0].Reg()
+ r2 := v.Args[1].Reg()
+ p := gc.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.OpARM64ADDconst,
+ ssa.OpARM64SUBconst,
+ ssa.OpARM64ANDconst,
+ ssa.OpARM64ORconst,
+ ssa.OpARM64XORconst,
+ ssa.OpARM64BICconst,
+ ssa.OpARM64SLLconst,
+ ssa.OpARM64SRLconst,
+ ssa.OpARM64SRAconst,
+ ssa.OpARM64RORconst,
+ ssa.OpARM64RORWconst:
+ p := gc.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.OpARM64ADDshiftLL,
+ ssa.OpARM64SUBshiftLL,
+ ssa.OpARM64ANDshiftLL,
+ 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)
+ 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)
+ 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)
+ case ssa.OpARM64MOVDconst:
+ p := gc.Prog(v.Op.Asm())
+ p.From.Type = obj.TYPE_CONST
+ p.From.Offset = v.AuxInt
+ p.To.Type = obj.TYPE_REG
+ p.To.Reg = v.Reg()
+ case ssa.OpARM64FMOVSconst,
+ ssa.OpARM64FMOVDconst:
+ p := gc.Prog(v.Op.Asm())
+ p.From.Type = obj.TYPE_FCONST
+ p.From.Val = math.Float64frombits(uint64(v.AuxInt))
+ p.To.Type = obj.TYPE_REG
+ p.To.Reg = v.Reg()
+ case ssa.OpARM64CMP,
+ ssa.OpARM64CMPW,
+ ssa.OpARM64CMN,
+ ssa.OpARM64CMNW,
+ ssa.OpARM64FCMPS,
+ ssa.OpARM64FCMPD:
+ p := gc.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.OpARM64CMPconst,
+ ssa.OpARM64CMPWconst,
+ ssa.OpARM64CMNconst,
+ ssa.OpARM64CMNWconst:
+ p := gc.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)
+ case ssa.OpARM64CMPshiftRL:
+ genshift(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)
+ case ssa.OpARM64MOVDaddr:
+ p := gc.Prog(arm64.AMOVD)
+ p.From.Type = obj.TYPE_ADDR
+ p.To.Type = obj.TYPE_REG
+ p.To.Reg = v.Reg()
+
+ var wantreg string
+ // MOVD $sym+off(base), R
+ // the assembler expands it as the following:
+ // - base is SP: add constant offset to SP (R13)
+ // when constant is large, tmp register (R11) may be used
+ // - base is SB: load external address from constant pool (use relocation)
+ switch v.Aux.(type) {
+ default:
+ v.Fatalf("aux is of unknown type %T", v.Aux)
+ case *ssa.ExternSymbol:
+ wantreg = "SB"
+ gc.AddAux(&p.From, v)
+ case *ssa.ArgSymbol, *ssa.AutoSymbol:
+ wantreg = "SP"
+ gc.AddAux(&p.From, v)
+ case nil:
+ // No sym, just MOVD $off(SP), R
+ wantreg = "SP"
+ p.From.Reg = arm64.REGSP
+ p.From.Offset = v.AuxInt
+ }
+ if reg := v.Args[0].RegName(); reg != wantreg {
+ v.Fatalf("bad reg %s for symbol type %T, want %s", reg, v.Aux, wantreg)
+ }
+ case ssa.OpARM64MOVBload,
+ ssa.OpARM64MOVBUload,
+ ssa.OpARM64MOVHload,
+ ssa.OpARM64MOVHUload,
+ ssa.OpARM64MOVWload,
+ ssa.OpARM64MOVWUload,
+ ssa.OpARM64MOVDload,
+ ssa.OpARM64FMOVSload,
+ ssa.OpARM64FMOVDload:
+ p := gc.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.OpARM64LDAR,
+ ssa.OpARM64LDARW:
+ p := gc.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.OpARM64MOVBstore,
+ ssa.OpARM64MOVHstore,
+ ssa.OpARM64MOVWstore,
+ ssa.OpARM64MOVDstore,
+ ssa.OpARM64FMOVSstore,
+ ssa.OpARM64FMOVDstore,
+ ssa.OpARM64STLR,
+ ssa.OpARM64STLRW:
+ p := gc.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.OpARM64MOVBstorezero,
+ ssa.OpARM64MOVHstorezero,
+ ssa.OpARM64MOVWstorezero,
+ ssa.OpARM64MOVDstorezero:
+ p := gc.Prog(v.Op.Asm())
+ p.From.Type = obj.TYPE_REG
+ p.From.Reg = arm64.REGZERO
+ p.To.Type = obj.TYPE_MEM
+ p.To.Reg = v.Args[0].Reg()
+ gc.AddAux(&p.To, v)
+ case ssa.OpARM64LoweredAtomicExchange64,
+ ssa.OpARM64LoweredAtomicExchange32:
+ // LDAXR (Rarg0), Rout
+ // STLXR Rarg1, (Rarg0), Rtmp
+ // CBNZ Rtmp, -2(PC)
+ ld := arm64.ALDAXR
+ st := arm64.ASTLXR
+ if v.Op == ssa.OpARM64LoweredAtomicExchange32 {
+ ld = arm64.ALDAXRW
+ st = arm64.ASTLXRW
+ }
+ r0 := v.Args[0].Reg()
+ r1 := v.Args[1].Reg()
+ out := v.Reg0()
+ p := gc.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.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.From.Type = obj.TYPE_REG
+ p2.From.Reg = arm64.REGTMP
+ p2.To.Type = obj.TYPE_BRANCH
+ gc.Patch(p2, p)
+ case ssa.OpARM64LoweredAtomicAdd64,
+ ssa.OpARM64LoweredAtomicAdd32:
+ // LDAXR (Rarg0), Rout
+ // ADD Rarg1, Rout
+ // STLXR Rout, (Rarg0), Rtmp
+ // CBNZ Rtmp, -3(PC)
+ ld := arm64.ALDAXR
+ st := arm64.ASTLXR
+ if v.Op == ssa.OpARM64LoweredAtomicAdd32 {
+ ld = arm64.ALDAXRW
+ st = arm64.ASTLXRW
+ }
+ r0 := v.Args[0].Reg()
+ r1 := v.Args[1].Reg()
+ out := v.Reg0()
+ p := gc.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.From.Type = obj.TYPE_REG
+ p1.From.Reg = r1
+ p1.To.Type = obj.TYPE_REG
+ p1.To.Reg = out
+ p2 := gc.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.From.Type = obj.TYPE_REG
+ p3.From.Reg = arm64.REGTMP
+ p3.To.Type = obj.TYPE_BRANCH
+ gc.Patch(p3, p)
+ case ssa.OpARM64LoweredAtomicCas64,
+ ssa.OpARM64LoweredAtomicCas32:
+ // LDAXR (Rarg0), Rtmp
+ // CMP Rarg1, Rtmp
+ // BNE 3(PC)
+ // STLXR Rarg2, (Rarg0), Rtmp
+ // CBNZ Rtmp, -4(PC)
+ // CSET EQ, Rout
+ ld := arm64.ALDAXR
+ st := arm64.ASTLXR
+ cmp := arm64.ACMP
+ if v.Op == ssa.OpARM64LoweredAtomicCas32 {
+ ld = arm64.ALDAXRW
+ st = arm64.ASTLXRW
+ cmp = arm64.ACMPW
+ }
+ r0 := v.Args[0].Reg()
+ r1 := v.Args[1].Reg()
+ r2 := v.Args[2].Reg()
+ out := v.Reg0()
+ p := gc.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.From.Type = obj.TYPE_REG
+ p1.From.Reg = r1
+ p1.Reg = arm64.REGTMP
+ p2 := gc.Prog(arm64.ABNE)
+ p2.To.Type = obj.TYPE_BRANCH
+ p3 := gc.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.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.From.Type = obj.TYPE_REG // assembler encodes conditional bits in Reg
+ p5.From.Reg = arm64.COND_EQ
+ p5.To.Type = obj.TYPE_REG
+ p5.To.Reg = out
+ gc.Patch(p2, p5)
+ case ssa.OpARM64LoweredAtomicAnd8,
+ ssa.OpARM64LoweredAtomicOr8:
+ // LDAXRB (Rarg0), Rtmp
+ // AND/OR Rarg1, Rtmp
+ // STLXRB Rtmp, (Rarg0), Rtmp
+ // CBNZ Rtmp, -3(PC)
+ r0 := v.Args[0].Reg()
+ r1 := v.Args[1].Reg()
+ p := gc.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.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.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.From.Type = obj.TYPE_REG
+ p3.From.Reg = arm64.REGTMP
+ p3.To.Type = obj.TYPE_BRANCH
+ gc.Patch(p3, p)
+ case ssa.OpARM64MOVBreg,
+ ssa.OpARM64MOVBUreg,
+ ssa.OpARM64MOVHreg,
+ ssa.OpARM64MOVHUreg,
+ ssa.OpARM64MOVWreg,
+ ssa.OpARM64MOVWUreg:
+ a := v.Args[0]
+ for a.Op == ssa.OpCopy || a.Op == ssa.OpARM64MOVDreg {
+ a = a.Args[0]
+ }
+ if a.Op == ssa.OpLoadReg {
+ t := a.Type
+ switch {
+ case v.Op == ssa.OpARM64MOVBreg && t.Size() == 1 && t.IsSigned(),
+ v.Op == ssa.OpARM64MOVBUreg && t.Size() == 1 && !t.IsSigned(),
+ v.Op == ssa.OpARM64MOVHreg && t.Size() == 2 && t.IsSigned(),
+ v.Op == ssa.OpARM64MOVHUreg && t.Size() == 2 && !t.IsSigned(),
+ v.Op == ssa.OpARM64MOVWreg && t.Size() == 4 && t.IsSigned(),
+ v.Op == ssa.OpARM64MOVWUreg && t.Size() == 4 && !t.IsSigned():
+ // arg is a proper-typed load, already zero/sign-extended, don't extend again
+ if v.Reg() == v.Args[0].Reg() {
+ return
+ }
+ p := gc.Prog(arm64.AMOVD)
+ p.From.Type = obj.TYPE_REG
+ p.From.Reg = v.Args[0].Reg()
+ p.To.Type = obj.TYPE_REG
+ p.To.Reg = v.Reg()
+ return
+ default:
+ }
+ }
+ fallthrough
+ case ssa.OpARM64MVN,
+ ssa.OpARM64NEG,
+ ssa.OpARM64FNEGS,
+ ssa.OpARM64FNEGD,
+ ssa.OpARM64FSQRTD,
+ ssa.OpARM64FCVTZSSW,
+ ssa.OpARM64FCVTZSDW,
+ ssa.OpARM64FCVTZUSW,
+ ssa.OpARM64FCVTZUDW,
+ ssa.OpARM64FCVTZSS,
+ ssa.OpARM64FCVTZSD,
+ ssa.OpARM64FCVTZUS,
+ ssa.OpARM64FCVTZUD,
+ ssa.OpARM64SCVTFWS,
+ ssa.OpARM64SCVTFWD,
+ ssa.OpARM64SCVTFS,
+ ssa.OpARM64SCVTFD,
+ ssa.OpARM64UCVTFWS,
+ ssa.OpARM64UCVTFWD,
+ ssa.OpARM64UCVTFS,
+ ssa.OpARM64UCVTFD,
+ ssa.OpARM64FCVTSD,
+ ssa.OpARM64FCVTDS,
+ ssa.OpARM64REV,
+ ssa.OpARM64REVW,
+ ssa.OpARM64REV16W,
+ ssa.OpARM64RBIT,
+ ssa.OpARM64RBITW,
+ ssa.OpARM64CLZ,
+ ssa.OpARM64CLZW:
+ p := gc.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.OpARM64CSELULT,
+ ssa.OpARM64CSELULT0:
+ r1 := int16(arm64.REGZERO)
+ if v.Op == ssa.OpARM64CSELULT {
+ r1 = v.Args[1].Reg()
+ }
+ p := gc.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()
+ p.From3 = &obj.Addr{Type: obj.TYPE_REG, Reg: r1}
+ p.To.Type = obj.TYPE_REG
+ p.To.Reg = v.Reg()
+ case ssa.OpARM64DUFFZERO:
+ // runtime.duffzero expects start address - 8 in R16
+ p := gc.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.To.Type = obj.TYPE_MEM
+ p.To.Name = obj.NAME_EXTERN
+ p.To.Sym = gc.Linksym(gc.Pkglookup("duffzero", gc.Runtimepkg))
+ 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.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.From.Type = obj.TYPE_REG
+ p2.From.Reg = v.Args[1].Reg()
+ p2.Reg = arm64.REG_R16
+ p3 := gc.Prog(arm64.ABLE)
+ p3.To.Type = obj.TYPE_BRANCH
+ gc.Patch(p3, p)
+ case ssa.OpARM64DUFFCOPY:
+ p := gc.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.Offset = v.AuxInt
+ case ssa.OpARM64LoweredMove:
+ // MOVD.P 8(R16), Rtmp
+ // MOVD.P Rtmp, 8(R17)
+ // CMP Rarg2, R16
+ // BLE -3(PC)
+ // arg2 is the address of the last element of src
+ p := gc.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.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.From.Type = obj.TYPE_REG
+ p3.From.Reg = v.Args[2].Reg()
+ p3.Reg = arm64.REG_R16
+ p4 := gc.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.OpARM64LoweredNilCheck:
+ // Issue a load which will fault if arg is nil.
+ p := gc.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")
+ }
+ 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,
+ ssa.OpARM64LessEqual,
+ ssa.OpARM64GreaterThan,
+ ssa.OpARM64GreaterEqual,
+ ssa.OpARM64LessThanU,
+ ssa.OpARM64LessEqualU,
+ ssa.OpARM64GreaterThanU,
+ ssa.OpARM64GreaterEqualU:
+ // generate boolean values using CSET
+ p := gc.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)
+ case ssa.OpARM64FlagEQ,
+ ssa.OpARM64FlagLT_ULT,
+ ssa.OpARM64FlagLT_UGT,
+ ssa.OpARM64FlagGT_ULT,
+ ssa.OpARM64FlagGT_UGT:
+ 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())
+ default:
+ v.Fatalf("genValue not implemented: %s", v.LongString())
+ }
+}
+
+var condBits = map[ssa.Op]int16{
+ ssa.OpARM64Equal: arm64.COND_EQ,
+ ssa.OpARM64NotEqual: arm64.COND_NE,
+ ssa.OpARM64LessThan: arm64.COND_LT,
+ ssa.OpARM64LessThanU: arm64.COND_LO,
+ ssa.OpARM64LessEqual: arm64.COND_LE,
+ ssa.OpARM64LessEqualU: arm64.COND_LS,
+ ssa.OpARM64GreaterThan: arm64.COND_GT,
+ ssa.OpARM64GreaterThanU: arm64.COND_HI,
+ ssa.OpARM64GreaterEqual: arm64.COND_GE,
+ ssa.OpARM64GreaterEqualU: arm64.COND_HS,
+}
+
+var blockJump = map[ssa.BlockKind]struct {
+ asm, invasm obj.As
+}{
+ ssa.BlockARM64EQ: {arm64.ABEQ, arm64.ABNE},
+ ssa.BlockARM64NE: {arm64.ABNE, arm64.ABEQ},
+ ssa.BlockARM64LT: {arm64.ABLT, arm64.ABGE},
+ ssa.BlockARM64GE: {arm64.ABGE, arm64.ABLT},
+ ssa.BlockARM64LE: {arm64.ABLE, arm64.ABGT},
+ ssa.BlockARM64GT: {arm64.ABGT, arm64.ABLE},
+ ssa.BlockARM64ULT: {arm64.ABLO, arm64.ABHS},
+ ssa.BlockARM64UGE: {arm64.ABHS, arm64.ABLO},
+ ssa.BlockARM64UGT: {arm64.ABHI, arm64.ABLS},
+ ssa.BlockARM64ULE: {arm64.ABLS, arm64.ABHI},
+ ssa.BlockARM64Z: {arm64.ACBZ, arm64.ACBNZ},
+ ssa.BlockARM64NZ: {arm64.ACBNZ, arm64.ACBZ},
+ ssa.BlockARM64ZW: {arm64.ACBZW, arm64.ACBNZW},
+ ssa.BlockARM64NZW: {arm64.ACBNZW, arm64.ACBZW},
+}
+
+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.To.Type = obj.TYPE_BRANCH
+ s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()})
+ }
+
+ case ssa.BlockDefer:
+ // defer returns in R0:
+ // 0 if we should continue executing
+ // 1 if we should jump to deferreturn call
+ p := gc.Prog(arm64.ACMP)
+ p.From.Type = obj.TYPE_CONST
+ p.From.Offset = 0
+ p.Reg = arm64.REG_R0
+ p = gc.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.To.Type = obj.TYPE_BRANCH
+ s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()})
+ }
+
+ case ssa.BlockExit:
+ gc.Prog(obj.AUNDEF) // tell plive.go that we never reach here
+
+ case ssa.BlockRet:
+ gc.Prog(obj.ARET)
+
+ case ssa.BlockRetJmp:
+ p := gc.Prog(obj.ARET)
+ p.To.Type = obj.TYPE_MEM
+ p.To.Name = obj.NAME_EXTERN
+ p.To.Sym = gc.Linksym(b.Aux.(*gc.Sym))
+
+ case ssa.BlockARM64EQ, ssa.BlockARM64NE,
+ ssa.BlockARM64LT, ssa.BlockARM64GE,
+ ssa.BlockARM64LE, ssa.BlockARM64GT,
+ ssa.BlockARM64ULT, ssa.BlockARM64UGT,
+ ssa.BlockARM64ULE, ssa.BlockARM64UGE,
+ ssa.BlockARM64Z, ssa.BlockARM64NZ,
+ ssa.BlockARM64ZW, ssa.BlockARM64NZW:
+ jmp := blockJump[b.Kind]
+ var p *obj.Prog
+ switch next {
+ case b.Succs[0].Block():
+ p = gc.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.To.Type = obj.TYPE_BRANCH
+ s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()})
+ default:
+ p = gc.Prog(jmp.asm)
+ p.To.Type = obj.TYPE_BRANCH
+ s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()})
+ q := gc.Prog(obj.AJMP)
+ q.To.Type = obj.TYPE_BRANCH
+ s.Branches = append(s.Branches, gc.Branch{P: q, B: b.Succs[1].Block()})
+ }
+ if !b.Control.Type.IsFlags() {
+ p.From.Type = obj.TYPE_REG
+ p.From.Reg = b.Control.Reg()
+ }
+
+ default:
+ b.Fatalf("branch not implemented: %s. Control: %s", b.LongString(), b.Control.LongString())
+ }
+}
diff --git a/src/cmd/compile/internal/big/accuracy_string.go b/src/cmd/compile/internal/big/accuracy_string.go
deleted file mode 100644
index 24ef7f1..0000000
--- a/src/cmd/compile/internal/big/accuracy_string.go
+++ /dev/null
@@ -1,17 +0,0 @@
-// generated by stringer -type=Accuracy; DO NOT EDIT
-
-package big
-
-import "fmt"
-
-const _Accuracy_name = "BelowExactAbove"
-
-var _Accuracy_index = [...]uint8{0, 5, 10, 15}
-
-func (i Accuracy) String() string {
- i -= -1
- if i < 0 || i+1 >= Accuracy(len(_Accuracy_index)) {
- return fmt.Sprintf("Accuracy(%d)", i+-1)
- }
- return _Accuracy_name[_Accuracy_index[i]:_Accuracy_index[i+1]]
-}
diff --git a/src/cmd/compile/internal/big/arith.go b/src/cmd/compile/internal/big/arith.go
deleted file mode 100644
index d7ea838..0000000
--- a/src/cmd/compile/internal/big/arith.go
+++ /dev/null
@@ -1,305 +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.
-
-// This file provides Go implementations of elementary multi-precision
-// arithmetic operations on word vectors. Needed for platforms without
-// assembly implementations of these routines.
-
-package big
-
-// A Word represents a single digit of a multi-precision unsigned integer.
-type Word uintptr
-
-const (
- // Compute the size _S of a Word in bytes.
- _m = ^Word(0)
- _logS = _m>>8&1 + _m>>16&1 + _m>>32&1
- _S = 1 << _logS
-
- _W = _S << 3 // word size in bits
- _B = 1 << _W // digit base
- _M = _B - 1 // digit mask
-
- _W2 = _W / 2 // half word size in bits
- _B2 = 1 << _W2 // half digit base
- _M2 = _B2 - 1 // half digit mask
-)
-
-// ----------------------------------------------------------------------------
-// Elementary operations on words
-//
-// These operations are used by the vector operations below.
-
-// z1<<_W + z0 = x+y+c, with c == 0 or 1
-func addWW_g(x, y, c Word) (z1, z0 Word) {
- yc := y + c
- z0 = x + yc
- if z0 < x || yc < y {
- z1 = 1
- }
- return
-}
-
-// z1<<_W + z0 = x-y-c, with c == 0 or 1
-func subWW_g(x, y, c Word) (z1, z0 Word) {
- yc := y + c
- z0 = x - yc
- if z0 > x || yc < y {
- z1 = 1
- }
- return
-}
-
-// z1<<_W + z0 = x*y
-// Adapted from Warren, Hacker's Delight, p. 132.
-func mulWW_g(x, y Word) (z1, z0 Word) {
- x0 := x & _M2
- x1 := x >> _W2
- y0 := y & _M2
- y1 := y >> _W2
- w0 := x0 * y0
- t := x1*y0 + w0>>_W2
- w1 := t & _M2
- w2 := t >> _W2
- w1 += x0 * y1
- z1 = x1*y1 + w2 + w1>>_W2
- z0 = x * y
- return
-}
-
-// z1<<_W + z0 = x*y + c
-func mulAddWWW_g(x, y, c Word) (z1, z0 Word) {
- z1, zz0 := mulWW_g(x, y)
- if z0 = zz0 + c; z0 < zz0 {
- z1++
- }
- return
-}
-
-// Length of x in bits.
-func bitLen_g(x Word) (n int) {
- for ; x >= 0x8000; x >>= 16 {
- n += 16
- }
- if x >= 0x80 {
- x >>= 8
- n += 8
- }
- if x >= 0x8 {
- x >>= 4
- n += 4
- }
- if x >= 0x2 {
- x >>= 2
- n += 2
- }
- if x >= 0x1 {
- n++
- }
- return
-}
-
-// log2 computes the integer binary logarithm of x.
-// The result is the integer n for which 2^n <= x < 2^(n+1).
-// If x == 0, the result is -1.
-func log2(x Word) int {
- return bitLen(x) - 1
-}
-
-// nlz returns the number of leading zeros in x.
-func nlz(x Word) uint {
- return uint(_W - bitLen(x))
-}
-
-// nlz64 returns the number of leading zeros in x.
-func nlz64(x uint64) uint {
- switch _W {
- case 32:
- w := x >> 32
- if w == 0 {
- return 32 + nlz(Word(x))
- }
- return nlz(Word(w))
- case 64:
- return nlz(Word(x))
- }
- panic("unreachable")
-}
-
-// q = (u1<<_W + u0 - r)/y
-// Adapted from Warren, Hacker's Delight, p. 152.
-func divWW_g(u1, u0, v Word) (q, r Word) {
- if u1 >= v {
- return 1<<_W - 1, 1<<_W - 1
- }
-
- s := nlz(v)
- v <<= s
-
- vn1 := v >> _W2
- vn0 := v & _M2
- un32 := u1<<s | u0>>(_W-s)
- un10 := u0 << s
- un1 := un10 >> _W2
- un0 := un10 & _M2
- q1 := un32 / vn1
- rhat := un32 - q1*vn1
-
- for q1 >= _B2 || q1*vn0 > _B2*rhat+un1 {
- q1--
- rhat += vn1
- if rhat >= _B2 {
- break
- }
- }
-
- un21 := un32*_B2 + un1 - q1*v
- q0 := un21 / vn1
- rhat = un21 - q0*vn1
-
- for q0 >= _B2 || q0*vn0 > _B2*rhat+un0 {
- q0--
- rhat += vn1
- if rhat >= _B2 {
- break
- }
- }
-
- return q1*_B2 + q0, (un21*_B2 + un0 - q0*v) >> s
-}
-
-// Keep for performance debugging.
-// Using addWW_g is likely slower.
-const use_addWW_g = false
-
-// The resulting carry c is either 0 or 1.
-func addVV_g(z, x, y []Word) (c Word) {
- if use_addWW_g {
- for i := range z {
- c, z[i] = addWW_g(x[i], y[i], c)
- }
- return
- }
-
- for i, xi := range x[:len(z)] {
- yi := y[i]
- zi := xi + yi + c
- z[i] = zi
- // see "Hacker's Delight", section 2-12 (overflow detection)
- c = (xi&yi | (xi|yi)&^zi) >> (_W - 1)
- }
- return
-}
-
-// The resulting carry c is either 0 or 1.
-func subVV_g(z, x, y []Word) (c Word) {
- if use_addWW_g {
- for i := range z {
- c, z[i] = subWW_g(x[i], y[i], c)
- }
- return
- }
-
- for i, xi := range x[:len(z)] {
- yi := y[i]
- zi := xi - yi - c
- z[i] = zi
- // see "Hacker's Delight", section 2-12 (overflow detection)
- c = (yi&^xi | (yi|^xi)&zi) >> (_W - 1)
- }
- return
-}
-
-// The resulting carry c is either 0 or 1.
-func addVW_g(z, x []Word, y Word) (c Word) {
- if use_addWW_g {
- c = y
- for i := range z {
- c, z[i] = addWW_g(x[i], c, 0)
- }
- return
- }
-
- c = y
- for i, xi := range x[:len(z)] {
- zi := xi + c
- z[i] = zi
- c = xi &^ zi >> (_W - 1)
- }
- return
-}
-
-func subVW_g(z, x []Word, y Word) (c Word) {
- if use_addWW_g {
- c = y
- for i := range z {
- c, z[i] = subWW_g(x[i], c, 0)
- }
- return
- }
-
- c = y
- for i, xi := range x[:len(z)] {
- zi := xi - c
- z[i] = zi
- c = (zi &^ xi) >> (_W - 1)
- }
- return
-}
-
-func shlVU_g(z, x []Word, s uint) (c Word) {
- if n := len(z); n > 0 {
- ŝ := _W - s
- w1 := x[n-1]
- c = w1 >> ŝ
- for i := n - 1; i > 0; i-- {
- w := w1
- w1 = x[i-1]
- z[i] = w<<s | w1>>ŝ
- }
- z[0] = w1 << s
- }
- return
-}
-
-func shrVU_g(z, x []Word, s uint) (c Word) {
- if n := len(z); n > 0 {
- ŝ := _W - s
- w1 := x[0]
- c = w1 << ŝ
- for i := 0; i < n-1; i++ {
- w := w1
- w1 = x[i+1]
- z[i] = w>>s | w1<<ŝ
- }
- z[n-1] = w1 >> s
- }
- return
-}
-
-func mulAddVWW_g(z, x []Word, y, r Word) (c Word) {
- c = r
- for i := range z {
- c, z[i] = mulAddWWW_g(x[i], y, c)
- }
- return
-}
-
-// TODO(gri) Remove use of addWW_g here and then we can remove addWW_g and subWW_g.
-func addMulVVW_g(z, x []Word, y Word) (c Word) {
- for i := range z {
- z1, z0 := mulAddWWW_g(x[i], y, z[i])
- c, z[i] = addWW_g(z0, c, 0)
- c += z1
- }
- return
-}
-
-func divWVW_g(z []Word, xn Word, x []Word, y Word) (r Word) {
- r = xn
- for i := len(z) - 1; i >= 0; i-- {
- z[i], r = divWW_g(r, x[i], y)
- }
- return
-}
diff --git a/src/cmd/compile/internal/big/arith_decl.go b/src/cmd/compile/internal/big/arith_decl.go
deleted file mode 100644
index d60b7f9..0000000
--- a/src/cmd/compile/internal/big/arith_decl.go
+++ /dev/null
@@ -1,53 +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 big
-
-func mulWW(x, y Word) (z1, z0 Word) {
- return mulWW_g(x, y)
-}
-
-func divWW(x1, x0, y Word) (q, r Word) {
- return divWW_g(x1, x0, y)
-}
-
-func addVV(z, x, y []Word) (c Word) {
- return addVV_g(z, x, y)
-}
-
-func subVV(z, x, y []Word) (c Word) {
- return subVV_g(z, x, y)
-}
-
-func addVW(z, x []Word, y Word) (c Word) {
- return addVW_g(z, x, y)
-}
-
-func subVW(z, x []Word, y Word) (c Word) {
- return subVW_g(z, x, y)
-}
-
-func shlVU(z, x []Word, s uint) (c Word) {
- return shlVU_g(z, x, s)
-}
-
-func shrVU(z, x []Word, s uint) (c Word) {
- return shrVU_g(z, x, s)
-}
-
-func mulAddVWW(z, x []Word, y, r Word) (c Word) {
- return mulAddVWW_g(z, x, y, r)
-}
-
-func addMulVVW(z, x []Word, y Word) (c Word) {
- return addMulVVW_g(z, x, y)
-}
-
-func divWVW(z []Word, xn Word, x []Word, y Word) (r Word) {
- return divWVW_g(z, xn, x, y)
-}
-
-func bitLen(x Word) (n int) {
- return bitLen_g(x)
-}
diff --git a/src/cmd/compile/internal/big/arith_test.go b/src/cmd/compile/internal/big/arith_test.go
deleted file mode 100644
index 7d2f69a..0000000
--- a/src/cmd/compile/internal/big/arith_test.go
+++ /dev/null
@@ -1,442 +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 big
-
-import (
- "math/rand"
- "testing"
-)
-
-type funWW func(x, y, c Word) (z1, z0 Word)
-type argWW struct {
- x, y, c, z1, z0 Word
-}
-
-var sumWW = []argWW{
- {0, 0, 0, 0, 0},
- {0, 1, 0, 0, 1},
- {0, 0, 1, 0, 1},
- {0, 1, 1, 0, 2},
- {12345, 67890, 0, 0, 80235},
- {12345, 67890, 1, 0, 80236},
- {_M, 1, 0, 1, 0},
- {_M, 0, 1, 1, 0},
- {_M, 1, 1, 1, 1},
- {_M, _M, 0, 1, _M - 1},
- {_M, _M, 1, 1, _M},
-}
-
-func testFunWW(t *testing.T, msg string, f funWW, a argWW) {
- z1, z0 := f(a.x, a.y, a.c)
- if z1 != a.z1 || z0 != a.z0 {
- t.Errorf("%s%+v\n\tgot z1:z0 = %#x:%#x; want %#x:%#x", msg, a, z1, z0, a.z1, a.z0)
- }
-}
-
-func TestFunWW(t *testing.T) {
- for _, a := range sumWW {
- arg := a
- testFunWW(t, "addWW_g", addWW_g, arg)
-
- arg = argWW{a.y, a.x, a.c, a.z1, a.z0}
- testFunWW(t, "addWW_g symmetric", addWW_g, arg)
-
- arg = argWW{a.z0, a.x, a.c, a.z1, a.y}
- testFunWW(t, "subWW_g", subWW_g, arg)
-
- arg = argWW{a.z0, a.y, a.c, a.z1, a.x}
- testFunWW(t, "subWW_g symmetric", subWW_g, arg)
- }
-}
-
-type funVV func(z, x, y []Word) (c Word)
-type argVV struct {
- z, x, y nat
- c Word
-}
-
-var sumVV = []argVV{
- {},
- {nat{0}, nat{0}, nat{0}, 0},
- {nat{1}, nat{1}, nat{0}, 0},
- {nat{0}, nat{_M}, nat{1}, 1},
- {nat{80235}, nat{12345}, nat{67890}, 0},
- {nat{_M - 1}, nat{_M}, nat{_M}, 1},
- {nat{0, 0, 0, 0}, nat{_M, _M, _M, _M}, nat{1, 0, 0, 0}, 1},
- {nat{0, 0, 0, _M}, nat{_M, _M, _M, _M - 1}, nat{1, 0, 0, 0}, 0},
- {nat{0, 0, 0, 0}, nat{_M, 0, _M, 0}, nat{1, _M, 0, _M}, 1},
-}
-
-func testFunVV(t *testing.T, msg string, f funVV, a argVV) {
- z := make(nat, len(a.z))
- c := f(z, a.x, a.y)
- for i, zi := range z {
- if zi != a.z[i] {
- t.Errorf("%s%+v\n\tgot z[%d] = %#x; want %#x", msg, a, i, zi, a.z[i])
- break
- }
- }
- if c != a.c {
- t.Errorf("%s%+v\n\tgot c = %#x; want %#x", msg, a, c, a.c)
- }
-}
-
-func TestFunVV(t *testing.T) {
- for _, a := range sumVV {
- arg := a
- testFunVV(t, "addVV_g", addVV_g, arg)
- testFunVV(t, "addVV", addVV, arg)
-
- arg = argVV{a.z, a.y, a.x, a.c}
- testFunVV(t, "addVV_g symmetric", addVV_g, arg)
- testFunVV(t, "addVV symmetric", addVV, arg)
-
- arg = argVV{a.x, a.z, a.y, a.c}
- testFunVV(t, "subVV_g", subVV_g, arg)
- testFunVV(t, "subVV", subVV, arg)
-
- arg = argVV{a.y, a.z, a.x, a.c}
- testFunVV(t, "subVV_g symmetric", subVV_g, arg)
- testFunVV(t, "subVV symmetric", subVV, arg)
- }
-}
-
-// Always the same seed for reproducible results.
-var rnd = rand.New(rand.NewSource(0))
-
-func rndW() Word {
- return Word(rnd.Int63()<<1 | rnd.Int63n(2))
-}
-
-func rndV(n int) []Word {
- v := make([]Word, n)
- for i := range v {
- v[i] = rndW()
- }
- return v
-}
-
-func benchmarkFunVV(b *testing.B, f funVV, n int) {
- x := rndV(n)
- y := rndV(n)
- z := make([]Word, n)
- b.SetBytes(int64(n * _W))
- b.ResetTimer()
- for i := 0; i < b.N; i++ {
- f(z, x, y)
- }
-}
-
-func BenchmarkAddVV_1(b *testing.B) { benchmarkFunVV(b, addVV, 1) }
-func BenchmarkAddVV_2(b *testing.B) { benchmarkFunVV(b, addVV, 2) }
-func BenchmarkAddVV_3(b *testing.B) { benchmarkFunVV(b, addVV, 3) }
-func BenchmarkAddVV_4(b *testing.B) { benchmarkFunVV(b, addVV, 4) }
-func BenchmarkAddVV_5(b *testing.B) { benchmarkFunVV(b, addVV, 5) }
-func BenchmarkAddVV_1e1(b *testing.B) { benchmarkFunVV(b, addVV, 1e1) }
-func BenchmarkAddVV_1e2(b *testing.B) { benchmarkFunVV(b, addVV, 1e2) }
-func BenchmarkAddVV_1e3(b *testing.B) { benchmarkFunVV(b, addVV, 1e3) }
-func BenchmarkAddVV_1e4(b *testing.B) { benchmarkFunVV(b, addVV, 1e4) }
-func BenchmarkAddVV_1e5(b *testing.B) { benchmarkFunVV(b, addVV, 1e5) }
-
-type funVW func(z, x []Word, y Word) (c Word)
-type argVW struct {
- z, x nat
- y Word
- c Word
-}
-
-var sumVW = []argVW{
- {},
- {nil, nil, 2, 2},
- {nat{0}, nat{0}, 0, 0},
- {nat{1}, nat{0}, 1, 0},
- {nat{1}, nat{1}, 0, 0},
- {nat{0}, nat{_M}, 1, 1},
- {nat{0, 0, 0, 0}, nat{_M, _M, _M, _M}, 1, 1},
- {nat{585}, nat{314}, 271, 0},
-}
-
-var lshVW = []argVW{
- {},
- {nat{0}, nat{0}, 0, 0},
- {nat{0}, nat{0}, 1, 0},
- {nat{0}, nat{0}, 20, 0},
-
- {nat{_M}, nat{_M}, 0, 0},
- {nat{_M << 1 & _M}, nat{_M}, 1, 1},
- {nat{_M << 20 & _M}, nat{_M}, 20, _M >> (_W - 20)},
-
- {nat{_M, _M, _M}, nat{_M, _M, _M}, 0, 0},
- {nat{_M << 1 & _M, _M, _M}, nat{_M, _M, _M}, 1, 1},
- {nat{_M << 20 & _M, _M, _M}, nat{_M, _M, _M}, 20, _M >> (_W - 20)},
-}
-
-var rshVW = []argVW{
- {},
- {nat{0}, nat{0}, 0, 0},
- {nat{0}, nat{0}, 1, 0},
- {nat{0}, nat{0}, 20, 0},
-
- {nat{_M}, nat{_M}, 0, 0},
- {nat{_M >> 1}, nat{_M}, 1, _M << (_W - 1) & _M},
- {nat{_M >> 20}, nat{_M}, 20, _M << (_W - 20) & _M},
-
- {nat{_M, _M, _M}, nat{_M, _M, _M}, 0, 0},
- {nat{_M, _M, _M >> 1}, nat{_M, _M, _M}, 1, _M << (_W - 1) & _M},
- {nat{_M, _M, _M >> 20}, nat{_M, _M, _M}, 20, _M << (_W - 20) & _M},
-}
-
-func testFunVW(t *testing.T, msg string, f funVW, a argVW) {
- z := make(nat, len(a.z))
- c := f(z, a.x, a.y)
- for i, zi := range z {
- if zi != a.z[i] {
- t.Errorf("%s%+v\n\tgot z[%d] = %#x; want %#x", msg, a, i, zi, a.z[i])
- break
- }
- }
- if c != a.c {
- t.Errorf("%s%+v\n\tgot c = %#x; want %#x", msg, a, c, a.c)
- }
-}
-
-func makeFunVW(f func(z, x []Word, s uint) (c Word)) funVW {
- return func(z, x []Word, s Word) (c Word) {
- return f(z, x, uint(s))
- }
-}
-
-func TestFunVW(t *testing.T) {
- for _, a := range sumVW {
- arg := a
- testFunVW(t, "addVW_g", addVW_g, arg)
- testFunVW(t, "addVW", addVW, arg)
-
- arg = argVW{a.x, a.z, a.y, a.c}
- testFunVW(t, "subVW_g", subVW_g, arg)
- testFunVW(t, "subVW", subVW, arg)
- }
-
- shlVW_g := makeFunVW(shlVU_g)
- shlVW := makeFunVW(shlVU)
- for _, a := range lshVW {
- arg := a
- testFunVW(t, "shlVU_g", shlVW_g, arg)
- testFunVW(t, "shlVU", shlVW, arg)
- }
-
- shrVW_g := makeFunVW(shrVU_g)
- shrVW := makeFunVW(shrVU)
- for _, a := range rshVW {
- arg := a
- testFunVW(t, "shrVU_g", shrVW_g, arg)
- testFunVW(t, "shrVU", shrVW, arg)
- }
-}
-
-func benchmarkFunVW(b *testing.B, f funVW, n int) {
- x := rndV(n)
- y := rndW()
- z := make([]Word, n)
- b.SetBytes(int64(n * _S))
- b.ResetTimer()
- for i := 0; i < b.N; i++ {
- f(z, x, y)
- }
-}
-
-func BenchmarkAddVW_1(b *testing.B) { benchmarkFunVW(b, addVW, 1) }
-func BenchmarkAddVW_2(b *testing.B) { benchmarkFunVW(b, addVW, 2) }
-func BenchmarkAddVW_3(b *testing.B) { benchmarkFunVW(b, addVW, 3) }
-func BenchmarkAddVW_4(b *testing.B) { benchmarkFunVW(b, addVW, 4) }
-func BenchmarkAddVW_5(b *testing.B) { benchmarkFunVW(b, addVW, 5) }
-func BenchmarkAddVW_1e1(b *testing.B) { benchmarkFunVW(b, addVW, 1e1) }
-func BenchmarkAddVW_1e2(b *testing.B) { benchmarkFunVW(b, addVW, 1e2) }
-func BenchmarkAddVW_1e3(b *testing.B) { benchmarkFunVW(b, addVW, 1e3) }
-func BenchmarkAddVW_1e4(b *testing.B) { benchmarkFunVW(b, addVW, 1e4) }
-func BenchmarkAddVW_1e5(b *testing.B) { benchmarkFunVW(b, addVW, 1e5) }
-
-type funVWW func(z, x []Word, y, r Word) (c Word)
-type argVWW struct {
- z, x nat
- y, r Word
- c Word
-}
-
-var prodVWW = []argVWW{
- {},
- {nat{0}, nat{0}, 0, 0, 0},
- {nat{991}, nat{0}, 0, 991, 0},
- {nat{0}, nat{_M}, 0, 0, 0},
- {nat{991}, nat{_M}, 0, 991, 0},
- {nat{0}, nat{0}, _M, 0, 0},
- {nat{991}, nat{0}, _M, 991, 0},
- {nat{1}, nat{1}, 1, 0, 0},
- {nat{992}, nat{1}, 1, 991, 0},
- {nat{22793}, nat{991}, 23, 0, 0},
- {nat{22800}, nat{991}, 23, 7, 0},
- {nat{0, 0, 0, 22793}, nat{0, 0, 0, 991}, 23, 0, 0},
- {nat{7, 0, 0, 22793}, nat{0, 0, 0, 991}, 23, 7, 0},
- {nat{0, 0, 0, 0}, nat{7893475, 7395495, 798547395, 68943}, 0, 0, 0},
- {nat{991, 0, 0, 0}, nat{7893475, 7395495, 798547395, 68943}, 0, 991, 0},
- {nat{0, 0, 0, 0}, nat{0, 0, 0, 0}, 894375984, 0, 0},
- {nat{991, 0, 0, 0}, nat{0, 0, 0, 0}, 894375984, 991, 0},
- {nat{_M << 1 & _M}, nat{_M}, 1 << 1, 0, _M >> (_W - 1)},
- {nat{_M<<1&_M + 1}, nat{_M}, 1 << 1, 1, _M >> (_W - 1)},
- {nat{_M << 7 & _M}, nat{_M}, 1 << 7, 0, _M >> (_W - 7)},
- {nat{_M<<7&_M + 1<<6}, nat{_M}, 1 << 7, 1 << 6, _M >> (_W - 7)},
- {nat{_M << 7 & _M, _M, _M, _M}, nat{_M, _M, _M, _M}, 1 << 7, 0, _M >> (_W - 7)},
- {nat{_M<<7&_M + 1<<6, _M, _M, _M}, nat{_M, _M, _M, _M}, 1 << 7, 1 << 6, _M >> (_W - 7)},
-}
-
-func testFunVWW(t *testing.T, msg string, f funVWW, a argVWW) {
- z := make(nat, len(a.z))
- c := f(z, a.x, a.y, a.r)
- for i, zi := range z {
- if zi != a.z[i] {
- t.Errorf("%s%+v\n\tgot z[%d] = %#x; want %#x", msg, a, i, zi, a.z[i])
- break
- }
- }
- if c != a.c {
- t.Errorf("%s%+v\n\tgot c = %#x; want %#x", msg, a, c, a.c)
- }
-}
-
-// TODO(gri) mulAddVWW and divWVW are symmetric operations but
-// their signature is not symmetric. Try to unify.
-
-type funWVW func(z []Word, xn Word, x []Word, y Word) (r Word)
-type argWVW struct {
- z nat
- xn Word
- x nat
- y Word
- r Word
-}
-
-func testFunWVW(t *testing.T, msg string, f funWVW, a argWVW) {
- z := make(nat, len(a.z))
- r := f(z, a.xn, a.x, a.y)
- for i, zi := range z {
- if zi != a.z[i] {
- t.Errorf("%s%+v\n\tgot z[%d] = %#x; want %#x", msg, a, i, zi, a.z[i])
- break
- }
- }
- if r != a.r {
- t.Errorf("%s%+v\n\tgot r = %#x; want %#x", msg, a, r, a.r)
- }
-}
-
-func TestFunVWW(t *testing.T) {
- for _, a := range prodVWW {
- arg := a
- testFunVWW(t, "mulAddVWW_g", mulAddVWW_g, arg)
- testFunVWW(t, "mulAddVWW", mulAddVWW, arg)
-
- if a.y != 0 && a.r < a.y {
- arg := argWVW{a.x, a.c, a.z, a.y, a.r}
- testFunWVW(t, "divWVW_g", divWVW_g, arg)
- testFunWVW(t, "divWVW", divWVW, arg)
- }
- }
-}
-
-var mulWWTests = []struct {
- x, y Word
- q, r Word
-}{
- {_M, _M, _M - 1, 1},
- // 32 bit only: {0xc47dfa8c, 50911, 0x98a4, 0x998587f4},
-}
-
-func TestMulWW(t *testing.T) {
- for i, test := range mulWWTests {
- q, r := mulWW_g(test.x, test.y)
- if q != test.q || r != test.r {
- t.Errorf("#%d got (%x, %x) want (%x, %x)", i, q, r, test.q, test.r)
- }
- }
-}
-
-var mulAddWWWTests = []struct {
- x, y, c Word
- q, r Word
-}{
- // TODO(agl): These will only work on 64-bit platforms.
- // {15064310297182388543, 0xe7df04d2d35d5d80, 13537600649892366549, 13644450054494335067, 10832252001440893781},
- // {15064310297182388543, 0xdab2f18048baa68d, 13644450054494335067, 12869334219691522700, 14233854684711418382},
- {_M, _M, 0, _M - 1, 1},
- {_M, _M, _M, _M, 0},
-}
-
-func TestMulAddWWW(t *testing.T) {
- for i, test := range mulAddWWWTests {
- q, r := mulAddWWW_g(test.x, test.y, test.c)
- if q != test.q || r != test.r {
- t.Errorf("#%d got (%x, %x) want (%x, %x)", i, q, r, test.q, test.r)
- }
- }
-}
-
-func benchmarkAddMulVVW(b *testing.B, n int) {
- x := rndV(n)
- y := rndW()
- z := make([]Word, n)
- b.SetBytes(int64(n * _W))
- b.ResetTimer()
- for i := 0; i < b.N; i++ {
- addMulVVW(z, x, y)
- }
-}
-
-func BenchmarkAddMulVVW_1(b *testing.B) { benchmarkAddMulVVW(b, 1) }
-func BenchmarkAddMulVVW_2(b *testing.B) { benchmarkAddMulVVW(b, 2) }
-func BenchmarkAddMulVVW_3(b *testing.B) { benchmarkAddMulVVW(b, 3) }
-func BenchmarkAddMulVVW_4(b *testing.B) { benchmarkAddMulVVW(b, 4) }
-func BenchmarkAddMulVVW_5(b *testing.B) { benchmarkAddMulVVW(b, 5) }
-func BenchmarkAddMulVVW_1e1(b *testing.B) { benchmarkAddMulVVW(b, 1e1) }
-func BenchmarkAddMulVVW_1e2(b *testing.B) { benchmarkAddMulVVW(b, 1e2) }
-func BenchmarkAddMulVVW_1e3(b *testing.B) { benchmarkAddMulVVW(b, 1e3) }
-func BenchmarkAddMulVVW_1e4(b *testing.B) { benchmarkAddMulVVW(b, 1e4) }
-func BenchmarkAddMulVVW_1e5(b *testing.B) { benchmarkAddMulVVW(b, 1e5) }
-
-func testWordBitLen(t *testing.T, fname string, f func(Word) int) {
- for i := 0; i <= _W; i++ {
- x := Word(1) << uint(i-1) // i == 0 => x == 0
- n := f(x)
- if n != i {
- t.Errorf("got %d; want %d for %s(%#x)", n, i, fname, x)
- }
- }
-}
-
-func TestWordBitLen(t *testing.T) {
- testWordBitLen(t, "bitLen", bitLen)
- testWordBitLen(t, "bitLen_g", bitLen_g)
-}
-
-// runs b.N iterations of bitLen called on a Word containing (1 << nbits)-1.
-func benchmarkBitLenN(b *testing.B, nbits uint) {
- testword := Word((uint64(1) << nbits) - 1)
- for i := 0; i < b.N; i++ {
- bitLen(testword)
- }
-}
-
-// Individual bitLen tests. Numbers chosen to examine both sides
-// of powers-of-two boundaries.
-func BenchmarkBitLen0(b *testing.B) { benchmarkBitLenN(b, 0) }
-func BenchmarkBitLen1(b *testing.B) { benchmarkBitLenN(b, 1) }
-func BenchmarkBitLen2(b *testing.B) { benchmarkBitLenN(b, 2) }
-func BenchmarkBitLen3(b *testing.B) { benchmarkBitLenN(b, 3) }
-func BenchmarkBitLen4(b *testing.B) { benchmarkBitLenN(b, 4) }
-func BenchmarkBitLen5(b *testing.B) { benchmarkBitLenN(b, 5) }
-func BenchmarkBitLen8(b *testing.B) { benchmarkBitLenN(b, 8) }
-func BenchmarkBitLen9(b *testing.B) { benchmarkBitLenN(b, 9) }
-func BenchmarkBitLen16(b *testing.B) { benchmarkBitLenN(b, 16) }
-func BenchmarkBitLen17(b *testing.B) { benchmarkBitLenN(b, 17) }
-func BenchmarkBitLen31(b *testing.B) { benchmarkBitLenN(b, 31) }
diff --git a/src/cmd/compile/internal/big/bits_test.go b/src/cmd/compile/internal/big/bits_test.go
deleted file mode 100644
index 985b60b..0000000
--- a/src/cmd/compile/internal/big/bits_test.go
+++ /dev/null
@@ -1,224 +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 implements the Bits type used for testing Float operations
-// via an independent (albeit slower) representations for floating-point
-// numbers.
-
-package big
-
-import (
- "fmt"
- "sort"
- "testing"
-)
-
-// A Bits value b represents a finite floating-point number x of the form
-//
-// x = 2**b[0] + 2**b[1] + ... 2**b[len(b)-1]
-//
-// The order of slice elements is not significant. Negative elements may be
-// used to form fractions. A Bits value is normalized if each b[i] occurs at
-// most once. For instance Bits{0, 0, 1} is not normalized but represents the
-// same floating-point number as Bits{2}, which is normalized. The zero (nil)
-// value of Bits is a ready to use Bits value and represents the value 0.
-type Bits []int
-
-func (x Bits) add(y Bits) Bits {
- return append(x, y...)
-}
-
-func (x Bits) mul(y Bits) Bits {
- var p Bits
- for _, x := range x {
- for _, y := range y {
- p = append(p, x+y)
- }
- }
- return p
-}
-
-func TestMulBits(t *testing.T) {
- for _, test := range []struct {
- x, y, want Bits
- }{
- {nil, nil, nil},
- {Bits{}, Bits{}, nil},
- {Bits{0}, Bits{0}, Bits{0}},
- {Bits{0}, Bits{1}, Bits{1}},
- {Bits{1}, Bits{1, 2, 3}, Bits{2, 3, 4}},
- {Bits{-1}, Bits{1}, Bits{0}},
- {Bits{-10, -1, 0, 1, 10}, Bits{1, 2, 3}, Bits{-9, -8, -7, 0, 1, 2, 1, 2, 3, 2, 3, 4, 11, 12, 13}},
- } {
- got := fmt.Sprintf("%v", test.x.mul(test.y))
- want := fmt.Sprintf("%v", test.want)
- if got != want {
- t.Errorf("%v * %v = %s; want %s", test.x, test.y, got, want)
- }
-
- }
-}
-
-// norm returns the normalized bits for x: It removes multiple equal entries
-// by treating them as an addition (e.g., Bits{5, 5} => Bits{6}), and it sorts
-// the result list for reproducible results.
-func (x Bits) norm() Bits {
- m := make(map[int]bool)
- for _, b := range x {
- for m[b] {
- m[b] = false
- b++
- }
- m[b] = true
- }
- var z Bits
- for b, set := range m {
- if set {
- z = append(z, b)
- }
- }
- sort.Ints([]int(z))
- return z
-}
-
-func TestNormBits(t *testing.T) {
- for _, test := range []struct {
- x, want Bits
- }{
- {nil, nil},
- {Bits{}, Bits{}},
- {Bits{0}, Bits{0}},
- {Bits{0, 0}, Bits{1}},
- {Bits{3, 1, 1}, Bits{2, 3}},
- {Bits{10, 9, 8, 7, 6, 6}, Bits{11}},
- } {
- got := fmt.Sprintf("%v", test.x.norm())
- want := fmt.Sprintf("%v", test.want)
- if got != want {
- t.Errorf("normBits(%v) = %s; want %s", test.x, got, want)
- }
-
- }
-}
-
-// round returns the Float value corresponding to x after rounding x
-// to prec bits according to mode.
-func (x Bits) round(prec uint, mode RoundingMode) *Float {
- x = x.norm()
-
- // determine range
- var min, max int
- for i, b := range x {
- if i == 0 || b < min {
- min = b
- }
- if i == 0 || b > max {
- max = b
- }
- }
- prec0 := uint(max + 1 - min)
- if prec >= prec0 {
- return x.Float()
- }
- // prec < prec0
-
- // determine bit 0, rounding, and sticky bit, and result bits z
- var bit0, rbit, sbit uint
- var z Bits
- r := max - int(prec)
- for _, b := range x {
- switch {
- case b == r:
- rbit = 1
- case b < r:
- sbit = 1
- default:
- // b > r
- if b == r+1 {
- bit0 = 1
- }
- z = append(z, b)
- }
- }
-
- // round
- f := z.Float() // rounded to zero
- if mode == ToNearestAway {
- panic("not yet implemented")
- }
- if mode == ToNearestEven && rbit == 1 && (sbit == 1 || sbit == 0 && bit0 != 0) || mode == AwayFromZero {
- // round away from zero
- f.SetMode(ToZero).SetPrec(prec)
- f.Add(f, Bits{int(r) + 1}.Float())
- }
- return f
-}
-
-// Float returns the *Float z of the smallest possible precision such that
-// z = sum(2**bits[i]), with i = range bits. If multiple bits[i] are equal,
-// they are added: Bits{0, 1, 0}.Float() == 2**0 + 2**1 + 2**0 = 4.
-func (bits Bits) Float() *Float {
- // handle 0
- if len(bits) == 0 {
- return new(Float)
- }
- // len(bits) > 0
-
- // determine lsb exponent
- var min int
- for i, b := range bits {
- if i == 0 || b < min {
- min = b
- }
- }
-
- // create bit pattern
- x := NewInt(0)
- for _, b := range bits {
- badj := b - min
- // propagate carry if necessary
- for x.Bit(badj) != 0 {
- x.SetBit(x, badj, 0)
- badj++
- }
- x.SetBit(x, badj, 1)
- }
-
- // create corresponding float
- z := new(Float).SetInt(x) // normalized
- if e := int64(z.exp) + int64(min); MinExp <= e && e <= MaxExp {
- z.exp = int32(e)
- } else {
- // this should never happen for our test cases
- panic("exponent out of range")
- }
- return z
-}
-
-func TestFromBits(t *testing.T) {
- for _, test := range []struct {
- bits Bits
- want string
- }{
- // all different bit numbers
- {nil, "0"},
- {Bits{0}, "0x.8p+1"},
- {Bits{1}, "0x.8p+2"},
- {Bits{-1}, "0x.8p+0"},
- {Bits{63}, "0x.8p+64"},
- {Bits{33, -30}, "0x.8000000000000001p+34"},
- {Bits{255, 0}, "0x.8000000000000000000000000000000000000000000000000000000000000001p+256"},
-
- // multiple equal bit numbers
- {Bits{0, 0}, "0x.8p+2"},
- {Bits{0, 0, 0, 0}, "0x.8p+3"},
- {Bits{0, 1, 0}, "0x.8p+3"},
- {append(Bits{2, 1, 0} /* 7 */, Bits{3, 1} /* 10 */ ...), "0x.88p+5" /* 17 */},
- } {
- f := test.bits.Float()
- if got := f.Text('p', 0); got != test.want {
- t.Errorf("setBits(%v) = %s; want %s", test.bits, got, test.want)
- }
- }
-}
diff --git a/src/cmd/compile/internal/big/calibrate_test.go b/src/cmd/compile/internal/big/calibrate_test.go
deleted file mode 100644
index f69ffbf..0000000
--- a/src/cmd/compile/internal/big/calibrate_test.go
+++ /dev/null
@@ -1,88 +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.
-
-// This file prints execution times for the Mul benchmark
-// given different Karatsuba thresholds. The result may be
-// used to manually fine-tune the threshold constant. The
-// results are somewhat fragile; use repeated runs to get
-// a clear picture.
-
-// Usage: go test -run=TestCalibrate -calibrate
-
-package big
-
-import (
- "flag"
- "fmt"
- "testing"
- "time"
-)
-
-var calibrate = flag.Bool("calibrate", false, "run calibration test")
-
-func karatsubaLoad(b *testing.B) {
- BenchmarkMul(b)
-}
-
-// measureKaratsuba returns the time to run a Karatsuba-relevant benchmark
-// given Karatsuba threshold th.
-func measureKaratsuba(th int) time.Duration {
- th, karatsubaThreshold = karatsubaThreshold, th
- res := testing.Benchmark(karatsubaLoad)
- karatsubaThreshold = th
- return time.Duration(res.NsPerOp())
-}
-
-func computeThresholds() {
- fmt.Printf("Multiplication times for varying Karatsuba thresholds\n")
- fmt.Printf("(run repeatedly for good results)\n")
-
- // determine Tk, the work load execution time using basic multiplication
- Tb := measureKaratsuba(1e9) // th == 1e9 => Karatsuba multiplication disabled
- fmt.Printf("Tb = %10s\n", Tb)
-
- // thresholds
- th := 4
- th1 := -1
- th2 := -1
-
- var deltaOld time.Duration
- for count := -1; count != 0 && th < 128; count-- {
- // determine Tk, the work load execution time using Karatsuba multiplication
- Tk := measureKaratsuba(th)
-
- // improvement over Tb
- delta := (Tb - Tk) * 100 / Tb
-
- fmt.Printf("th = %3d Tk = %10s %4d%%", th, Tk, delta)
-
- // determine break-even point
- if Tk < Tb && th1 < 0 {
- th1 = th
- fmt.Print(" break-even point")
- }
-
- // determine diminishing return
- if 0 < delta && delta < deltaOld && th2 < 0 {
- th2 = th
- fmt.Print(" diminishing return")
- }
- deltaOld = delta
-
- fmt.Println()
-
- // trigger counter
- if th1 >= 0 && th2 >= 0 && count < 0 {
- count = 10 // this many extra measurements after we got both thresholds
- }
-
- th++
- }
-}
-
-func TestCalibrate(t *testing.T) {
- if *calibrate {
- computeThresholds()
- }
-}
diff --git a/src/cmd/compile/internal/big/decimal.go b/src/cmd/compile/internal/big/decimal.go
deleted file mode 100644
index 2c0c9da..0000000
--- a/src/cmd/compile/internal/big/decimal.go
+++ /dev/null
@@ -1,266 +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 implements multi-precision decimal numbers.
-// The implementation is for float to decimal conversion only;
-// not general purpose use.
-// The only operations are precise conversion from binary to
-// decimal and rounding.
-//
-// The key observation and some code (shr) is borrowed from
-// strconv/decimal.go: conversion of binary fractional values can be done
-// precisely in multi-precision decimal because 2 divides 10 (required for
-// >> of mantissa); but conversion of decimal floating-point values cannot
-// be done precisely in binary representation.
-//
-// In contrast to strconv/decimal.go, only right shift is implemented in
-// decimal format - left shift can be done precisely in binary format.
-
-package big
-
-// A decimal represents an unsigned floating-point number in decimal representation.
-// The value of a non-zero decimal d is d.mant * 10**d.exp with 0.5 <= d.mant < 1,
-// with the most-significant mantissa digit at index 0. For the zero decimal, the
-// mantissa length and exponent are 0.
-// The zero value for decimal represents a ready-to-use 0.0.
-type decimal struct {
- mant []byte // mantissa ASCII digits, big-endian
- exp int // exponent
-}
-
-// at returns the i'th mantissa digit, starting with the most significant digit at 0.
-func (d *decimal) at(i int) byte {
- if 0 <= i && i < len(d.mant) {
- return d.mant[i]
- }
- return '0'
-}
-
-// Maximum shift amount that can be done in one pass without overflow.
-// A Word has _W bits and (1<<maxShift - 1)*10 + 9 must fit into Word.
-const maxShift = _W - 4
-
-// TODO(gri) Since we know the desired decimal precision when converting
-// a floating-point number, we may be able to limit the number of decimal
-// digits that need to be computed by init by providing an additional
-// precision argument and keeping track of when a number was truncated early
-// (equivalent of "sticky bit" in binary rounding).
-
-// TODO(gri) Along the same lines, enforce some limit to shift magnitudes
-// to avoid "infinitely" long running conversions (until we run out of space).
-
-// Init initializes x to the decimal representation of m << shift (for
-// shift >= 0), or m >> -shift (for shift < 0).
-func (x *decimal) init(m nat, shift int) {
- // special case 0
- if len(m) == 0 {
- x.mant = x.mant[:0]
- x.exp = 0
- return
- }
-
- // Optimization: If we need to shift right, first remove any trailing
- // zero bits from m to reduce shift amount that needs to be done in
- // decimal format (since that is likely slower).
- if shift < 0 {
- ntz := m.trailingZeroBits()
- s := uint(-shift)
- if s >= ntz {
- s = ntz // shift at most ntz bits
- }
- m = nat(nil).shr(m, s)
- shift += int(s)
- }
-
- // Do any shift left in binary representation.
- if shift > 0 {
- m = nat(nil).shl(m, uint(shift))
- shift = 0
- }
-
- // Convert mantissa into decimal representation.
- s := m.utoa(10)
- n := len(s)
- x.exp = n
- // Trim trailing zeros; instead the exponent is tracking
- // the decimal point independent of the number of digits.
- for n > 0 && s[n-1] == '0' {
- n--
- }
- x.mant = append(x.mant[:0], s[:n]...)
-
- // Do any (remaining) shift right in decimal representation.
- if shift < 0 {
- for shift < -maxShift {
- shr(x, maxShift)
- shift += maxShift
- }
- shr(x, uint(-shift))
- }
-}
-
-// shr implements x >> s, for s <= maxShift.
-func shr(x *decimal, s uint) {
- // Division by 1<<s using shift-and-subtract algorithm.
-
- // pick up enough leading digits to cover first shift
- r := 0 // read index
- var n Word
- for n>>s == 0 && r < len(x.mant) {
- ch := Word(x.mant[r])
- r++
- n = n*10 + ch - '0'
- }
- if n == 0 {
- // x == 0; shouldn't get here, but handle anyway
- x.mant = x.mant[:0]
- return
- }
- for n>>s == 0 {
- r++
- n *= 10
- }
- x.exp += 1 - r
-
- // read a digit, write a digit
- w := 0 // write index
- for r < len(x.mant) {
- ch := Word(x.mant[r])
- r++
- d := n >> s
- n -= d << s
- x.mant[w] = byte(d + '0')
- w++
- n = n*10 + ch - '0'
- }
-
- // write extra digits that still fit
- for n > 0 && w < len(x.mant) {
- d := n >> s
- n -= d << s
- x.mant[w] = byte(d + '0')
- w++
- n = n * 10
- }
- x.mant = x.mant[:w] // the number may be shorter (e.g. 1024 >> 10)
-
- // append additional digits that didn't fit
- for n > 0 {
- d := n >> s
- n -= d << s
- x.mant = append(x.mant, byte(d+'0'))
- n = n * 10
- }
-
- trim(x)
-}
-
-func (x *decimal) String() string {
- if len(x.mant) == 0 {
- return "0"
- }
-
- var buf []byte
- switch {
- case x.exp <= 0:
- // 0.00ddd
- buf = append(buf, "0."...)
- buf = appendZeros(buf, -x.exp)
- buf = append(buf, x.mant...)
-
- case /* 0 < */ x.exp < len(x.mant):
- // dd.ddd
- buf = append(buf, x.mant[:x.exp]...)
- buf = append(buf, '.')
- buf = append(buf, x.mant[x.exp:]...)
-
- default: // len(x.mant) <= x.exp
- // ddd00
- buf = append(buf, x.mant...)
- buf = appendZeros(buf, x.exp-len(x.mant))
- }
-
- return string(buf)
-}
-
-// appendZeros appends n 0 digits to buf and returns buf.
-func appendZeros(buf []byte, n int) []byte {
- for ; n > 0; n-- {
- buf = append(buf, '0')
- }
- return buf
-}
-
-// shouldRoundUp reports if x should be rounded up
-// if shortened to n digits. n must be a valid index
-// for x.mant.
-func shouldRoundUp(x *decimal, n int) bool {
- if x.mant[n] == '5' && n+1 == len(x.mant) {
- // exactly halfway - round to even
- return n > 0 && (x.mant[n-1]-'0')&1 != 0
- }
- // not halfway - digit tells all (x.mant has no trailing zeros)
- return x.mant[n] >= '5'
-}
-
-// round sets x to (at most) n mantissa digits by rounding it
-// to the nearest even value with n (or fever) mantissa digits.
-// If n < 0, x remains unchanged.
-func (x *decimal) round(n int) {
- if n < 0 || n >= len(x.mant) {
- return // nothing to do
- }
-
- if shouldRoundUp(x, n) {
- x.roundUp(n)
- } else {
- x.roundDown(n)
- }
-}
-
-func (x *decimal) roundUp(n int) {
- if n < 0 || n >= len(x.mant) {
- return // nothing to do
- }
- // 0 <= n < len(x.mant)
-
- // find first digit < '9'
- for n > 0 && x.mant[n-1] >= '9' {
- n--
- }
-
- if n == 0 {
- // all digits are '9's => round up to '1' and update exponent
- x.mant[0] = '1' // ok since len(x.mant) > n
- x.mant = x.mant[:1]
- x.exp++
- return
- }
-
- // n > 0 && x.mant[n-1] < '9'
- x.mant[n-1]++
- x.mant = x.mant[:n]
- // x already trimmed
-}
-
-func (x *decimal) roundDown(n int) {
- if n < 0 || n >= len(x.mant) {
- return // nothing to do
- }
- x.mant = x.mant[:n]
- trim(x)
-}
-
-// trim cuts off any trailing zeros from x's mantissa;
-// they are meaningless for the value of x.
-func trim(x *decimal) {
- i := len(x.mant)
- for i > 0 && x.mant[i-1] == '0' {
- i--
- }
- x.mant = x.mant[:i]
- if i == 0 {
- x.exp = 0
- }
-}
diff --git a/src/cmd/compile/internal/big/decimal_test.go b/src/cmd/compile/internal/big/decimal_test.go
deleted file mode 100644
index 15bdb18..0000000
--- a/src/cmd/compile/internal/big/decimal_test.go
+++ /dev/null
@@ -1,116 +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 big
-
-import "testing"
-
-func TestDecimalString(t *testing.T) {
- for _, test := range []struct {
- x decimal
- want string
- }{
- {want: "0"},
- {decimal{nil, 1000}, "0"}, // exponent of 0 is ignored
- {decimal{[]byte("12345"), 0}, "0.12345"},
- {decimal{[]byte("12345"), -3}, "0.00012345"},
- {decimal{[]byte("12345"), +3}, "123.45"},
- {decimal{[]byte("12345"), +10}, "1234500000"},
- } {
- if got := test.x.String(); got != test.want {
- t.Errorf("%v == %s; want %s", test.x, got, test.want)
- }
- }
-}
-
-func TestDecimalInit(t *testing.T) {
- for _, test := range []struct {
- x Word
- shift int
- want string
- }{
- {0, 0, "0"},
- {0, -100, "0"},
- {0, 100, "0"},
- {1, 0, "1"},
- {1, 10, "1024"},
- {1, 100, "1267650600228229401496703205376"},
- {1, -100, "0.0000000000000000000000000000007888609052210118054117285652827862296732064351090230047702789306640625"},
- {12345678, 8, "3160493568"},
- {12345678, -8, "48225.3046875"},
- {195312, 9, "99999744"},
- {1953125, 9, "1000000000"},
- } {
- var d decimal
- d.init(nat{test.x}.norm(), test.shift)
- if got := d.String(); got != test.want {
- t.Errorf("%d << %d == %s; want %s", test.x, test.shift, got, test.want)
- }
- }
-}
-
-func TestDecimalRounding(t *testing.T) {
- for _, test := range []struct {
- x uint64
- n int
- down, even, up string
- }{
- {0, 0, "0", "0", "0"},
- {0, 1, "0", "0", "0"},
-
- {1, 0, "0", "0", "10"},
- {5, 0, "0", "0", "10"},
- {9, 0, "0", "10", "10"},
-
- {15, 1, "10", "20", "20"},
- {45, 1, "40", "40", "50"},
- {95, 1, "90", "100", "100"},
-
- {12344999, 4, "12340000", "12340000", "12350000"},
- {12345000, 4, "12340000", "12340000", "12350000"},
- {12345001, 4, "12340000", "12350000", "12350000"},
- {23454999, 4, "23450000", "23450000", "23460000"},
- {23455000, 4, "23450000", "23460000", "23460000"},
- {23455001, 4, "23450000", "23460000", "23460000"},
-
- {99994999, 4, "99990000", "99990000", "100000000"},
- {99995000, 4, "99990000", "100000000", "100000000"},
- {99999999, 4, "99990000", "100000000", "100000000"},
-
- {12994999, 4, "12990000", "12990000", "13000000"},
- {12995000, 4, "12990000", "13000000", "13000000"},
- {12999999, 4, "12990000", "13000000", "13000000"},
- } {
- x := nat(nil).setUint64(test.x)
-
- var d decimal
- d.init(x, 0)
- d.roundDown(test.n)
- if got := d.String(); got != test.down {
- t.Errorf("roundDown(%d, %d) = %s; want %s", test.x, test.n, got, test.down)
- }
-
- d.init(x, 0)
- d.round(test.n)
- if got := d.String(); got != test.even {
- t.Errorf("round(%d, %d) = %s; want %s", test.x, test.n, got, test.even)
- }
-
- d.init(x, 0)
- d.roundUp(test.n)
- if got := d.String(); got != test.up {
- t.Errorf("roundUp(%d, %d) = %s; want %s", test.x, test.n, got, test.up)
- }
- }
-}
-
-func BenchmarkDecimalConversion(b *testing.B) {
- for i := 0; i < b.N; i++ {
- for shift := -100; shift <= +100; shift++ {
- var d decimal
- d.init(natOne, shift)
- d.String()
- }
- }
-}
diff --git a/src/cmd/compile/internal/big/example_rat_test.go b/src/cmd/compile/internal/big/example_rat_test.go
deleted file mode 100644
index ef06497..0000000
--- a/src/cmd/compile/internal/big/example_rat_test.go
+++ /dev/null
@@ -1,65 +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 big_test
-
-import (
- "cmd/compile/internal/big"
- "fmt"
-)
-
-// Use the classic continued fraction for e
-// e = [1; 0, 1, 1, 2, 1, 1, ... 2n, 1, 1, ...]
-// i.e., for the nth term, use
-// 1 if n mod 3 != 1
-// (n-1)/3 * 2 if n mod 3 == 1
-func recur(n, lim int64) *big.Rat {
- term := new(big.Rat)
- if n%3 != 1 {
- term.SetInt64(1)
- } else {
- term.SetInt64((n - 1) / 3 * 2)
- }
-
- if n > lim {
- return term
- }
-
- // Directly initialize frac as the fractional
- // inverse of the result of recur.
- frac := new(big.Rat).Inv(recur(n+1, lim))
-
- return term.Add(term, frac)
-}
-
-// This example demonstrates how to use big.Rat to compute the
-// first 15 terms in the sequence of rational convergents for
-// the constant e (base of natural logarithm).
-func Example_eConvergents() {
- for i := 1; i <= 15; i++ {
- r := recur(0, int64(i))
-
- // Print r both as a fraction and as a floating-point number.
- // Since big.Rat implements fmt.Formatter, we can use %-13s to
- // get a left-aligned string representation of the fraction.
- fmt.Printf("%-13s = %s\n", r, r.FloatString(8))
- }
-
- // Output:
- // 2/1 = 2.00000000
- // 3/1 = 3.00000000
- // 8/3 = 2.66666667
- // 11/4 = 2.75000000
- // 19/7 = 2.71428571
- // 87/32 = 2.71875000
- // 106/39 = 2.71794872
- // 193/71 = 2.71830986
- // 1264/465 = 2.71827957
- // 1457/536 = 2.71828358
- // 2721/1001 = 2.71828172
- // 23225/8544 = 2.71828184
- // 25946/9545 = 2.71828182
- // 49171/18089 = 2.71828183
- // 517656/190435 = 2.71828183
-}
diff --git a/src/cmd/compile/internal/big/example_test.go b/src/cmd/compile/internal/big/example_test.go
deleted file mode 100644
index 8a71a08..0000000
--- a/src/cmd/compile/internal/big/example_test.go
+++ /dev/null
@@ -1,128 +0,0 @@
-// Copyright 2012 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package big_test
-
-import (
- "cmd/compile/internal/big"
- "fmt"
- "log"
- "math"
-)
-
-func ExampleRat_SetString() {
- r := new(big.Rat)
- r.SetString("355/113")
- fmt.Println(r.FloatString(3))
- // Output: 3.142
-}
-
-func ExampleInt_SetString() {
- i := new(big.Int)
- i.SetString("644", 8) // octal
- fmt.Println(i)
- // Output: 420
-}
-
-func ExampleRat_Scan() {
- // The Scan function is rarely used directly;
- // the fmt package recognizes it as an implementation of fmt.Scanner.
- r := new(big.Rat)
- _, err := fmt.Sscan("1.5000", r)
- if err != nil {
- log.Println("error scanning value:", err)
- } else {
- fmt.Println(r)
- }
- // Output: 3/2
-}
-
-func ExampleInt_Scan() {
- // The Scan function is rarely used directly;
- // the fmt package recognizes it as an implementation of fmt.Scanner.
- i := new(big.Int)
- _, err := fmt.Sscan("18446744073709551617", i)
- if err != nil {
- log.Println("error scanning value:", err)
- } else {
- fmt.Println(i)
- }
- // Output: 18446744073709551617
-}
-
-// This example demonstrates how to use big.Int to compute the smallest
-// Fibonacci number with 100 decimal digits and to test whether it is prime.
-func Example_fibonacci() {
- // Initialize two big ints with the first two numbers in the sequence.
- a := big.NewInt(0)
- b := big.NewInt(1)
-
- // Initialize limit as 10^99, the smallest integer with 100 digits.
- var limit big.Int
- limit.Exp(big.NewInt(10), big.NewInt(99), nil)
-
- // Loop while a is smaller than 1e100.
- for a.Cmp(&limit) < 0 {
- // Compute the next Fibonacci number, storing it in a.
- a.Add(a, b)
- // Swap a and b so that b is the next number in the sequence.
- a, b = b, a
- }
- fmt.Println(a) // 100-digit Fibonacci number
-
- // Test a for primality.
- // (ProbablyPrimes' argument sets the number of Miller-Rabin
- // rounds to be performed. 20 is a good value.)
- fmt.Println(a.ProbablyPrime(20))
-
- // Output:
- // 1344719667586153181419716641724567886890850696275767987106294472017884974410332069524504824747437757
- // false
-}
-
-// This example shows how to use big.Float to compute the square root of 2 with
-// a precision of 200 bits, and how to print the result as a decimal number.
-func Example_sqrt2() {
- // We'll do computations with 200 bits of precision in the mantissa.
- const prec = 200
-
- // Compute the square root of 2 using Newton's Method. We start with
- // an initial estimate for sqrt(2), and then iterate:
- // x_{n+1} = 1/2 * ( x_n + (2.0 / x_n) )
-
- // Since Newton's Method doubles the number of correct digits at each
- // iteration, we need at least log_2(prec) steps.
- steps := int(math.Log2(prec))
-
- // Initialize values we need for the computation.
- two := new(big.Float).SetPrec(prec).SetInt64(2)
- half := new(big.Float).SetPrec(prec).SetFloat64(0.5)
-
- // Use 1 as the initial estimate.
- x := new(big.Float).SetPrec(prec).SetInt64(1)
-
- // We use t as a temporary variable. There's no need to set its precision
- // since big.Float values with unset (== 0) precision automatically assume
- // the largest precision of the arguments when used as the result (receiver)
- // of a big.Float operation.
- t := new(big.Float)
-
- // Iterate.
- for i := 0; i <= steps; i++ {
- t.Quo(two, x) // t = 2.0 / x_n
- t.Add(x, t) // t = x_n + (2.0 / x_n)
- x.Mul(half, t) // x_{n+1} = 0.5 * t
- }
-
- // We can use the usual fmt.Printf verbs since big.Float implements fmt.Formatter
- fmt.Printf("sqrt(2) = %.50f\n", x)
-
- // Print the error between 2 and x*x.
- t.Mul(x, x) // t = x*x
- fmt.Printf("error = %e\n", t.Sub(two, t))
-
- // Output:
- // sqrt(2) = 1.41421356237309504880168872420969807856967187537695
- // error = 0.000000e+00
-}
diff --git a/src/cmd/compile/internal/big/float.go b/src/cmd/compile/internal/big/float.go
deleted file mode 100644
index 4b8ad38..0000000
--- a/src/cmd/compile/internal/big/float.go
+++ /dev/null
@@ -1,1683 +0,0 @@
-// Copyright 2014 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// This file implements multi-precision floating-point numbers.
-// Like in the GNU MPFR library (http://www.mpfr.org/), operands
-// can be of mixed precision. Unlike MPFR, the rounding mode is
-// not specified with each operation, but with each operand. The
-// rounding mode of the result operand determines the rounding
-// mode of an operation. This is a from-scratch implementation.
-
-package big
-
-import (
- "fmt"
- "math"
-)
-
-const debugFloat = false // enable for debugging
-
-// A nonzero finite Float represents a multi-precision floating point number
-//
-// sign × mantissa × 2**exponent
-//
-// with 0.5 <= mantissa < 1.0, and MinExp <= exponent <= MaxExp.
-// A Float may also be zero (+0, -0) or infinite (+Inf, -Inf).
-// All Floats are ordered, and the ordering of two Floats x and y
-// is defined by x.Cmp(y).
-//
-// Each Float value also has a precision, rounding mode, and accuracy.
-// The precision is the maximum number of mantissa bits available to
-// represent the value. The rounding mode specifies how a result should
-// be rounded to fit into the mantissa bits, and accuracy describes the
-// rounding error with respect to the exact result.
-//
-// Unless specified otherwise, all operations (including setters) that
-// specify a *Float variable for the result (usually via the receiver
-// with the exception of MantExp), round the numeric result according
-// to the precision and rounding mode of the result variable.
-//
-// If the provided result precision is 0 (see below), it is set to the
-// precision of the argument with the largest precision value before any
-// rounding takes place, and the rounding mode remains unchanged. Thus,
-// uninitialized Floats provided as result arguments will have their
-// precision set to a reasonable value determined by the operands and
-// their mode is the zero value for RoundingMode (ToNearestEven).
-//
-// By setting the desired precision to 24 or 53 and using matching rounding
-// mode (typically ToNearestEven), Float operations produce the same results
-// as the corresponding float32 or float64 IEEE-754 arithmetic for operands
-// that correspond to normal (i.e., not denormal) float32 or float64 numbers.
-// Exponent underflow and overflow lead to a 0 or an Infinity for different
-// values than IEEE-754 because Float exponents have a much larger range.
-//
-// The zero (uninitialized) value for a Float is ready to use and represents
-// the number +0.0 exactly, with precision 0 and rounding mode ToNearestEven.
-//
-type Float struct {
- prec uint32
- mode RoundingMode
- acc Accuracy
- form form
- neg bool
- mant nat
- exp int32
-}
-
-// An ErrNaN panic is raised by a Float operation that would lead to
-// a NaN under IEEE-754 rules. An ErrNaN implements the error interface.
-type ErrNaN struct {
- msg string
-}
-
-func (err ErrNaN) Error() string {
- return err.msg
-}
-
-// NewFloat allocates and returns a new Float set to x,
-// with precision 53 and rounding mode ToNearestEven.
-// NewFloat panics with ErrNaN if x is a NaN.
-func NewFloat(x float64) *Float {
- if math.IsNaN(x) {
- panic(ErrNaN{"NewFloat(NaN)"})
- }
- return new(Float).SetFloat64(x)
-}
-
-// Exponent and precision limits.
-const (
- MaxExp = math.MaxInt32 // largest supported exponent
- MinExp = math.MinInt32 // smallest supported exponent
- MaxPrec = math.MaxUint32 // largest (theoretically) supported precision; likely memory-limited
-)
-
-// Internal representation: The mantissa bits x.mant of a nonzero finite
-// Float x are stored in a nat slice long enough to hold up to x.prec bits;
-// the slice may (but doesn't have to) be shorter if the mantissa contains
-// trailing 0 bits. x.mant is normalized if the msb of x.mant == 1 (i.e.,
-// the msb is shifted all the way "to the left"). Thus, if the mantissa has
-// trailing 0 bits or x.prec is not a multiple of the the Word size _W,
-// x.mant[0] has trailing zero bits. The msb of the mantissa corresponds
-// to the value 0.5; the exponent x.exp shifts the binary point as needed.
-//
-// A zero or non-finite Float x ignores x.mant and x.exp.
-//
-// x form neg mant exp
-// ----------------------------------------------------------
-// ±0 zero sign - -
-// 0 < |x| < +Inf finite sign mantissa exponent
-// ±Inf inf sign - -
-
-// A form value describes the internal representation.
-type form byte
-
-// The form value order is relevant - do not change!
-const (
- zero form = iota
- finite
- inf
-)
-
-// RoundingMode determines how a Float value is rounded to the
-// desired precision. Rounding may change the Float value; the
-// rounding error is described by the Float's Accuracy.
-type RoundingMode byte
-
-// These constants define supported rounding modes.
-const (
- ToNearestEven RoundingMode = iota // == IEEE 754-2008 roundTiesToEven
- ToNearestAway // == IEEE 754-2008 roundTiesToAway
- ToZero // == IEEE 754-2008 roundTowardZero
- AwayFromZero // no IEEE 754-2008 equivalent
- ToNegativeInf // == IEEE 754-2008 roundTowardNegative
- ToPositiveInf // == IEEE 754-2008 roundTowardPositive
-)
-
-//go:generate stringer -type=RoundingMode
-
-// Accuracy describes the rounding error produced by the most recent
-// operation that generated a Float value, relative to the exact value.
-type Accuracy int8
-
-// Constants describing the Accuracy of a Float.
-const (
- Below Accuracy = -1
- Exact Accuracy = 0
- Above Accuracy = +1
-)
-
-//go:generate stringer -type=Accuracy
-
-// SetPrec sets z's precision to prec and returns the (possibly) rounded
-// value of z. Rounding occurs according to z's rounding mode if the mantissa
-// cannot be represented in prec bits without loss of precision.
-// SetPrec(0) maps all finite values to ±0; infinite values remain unchanged.
-// If prec > MaxPrec, it is set to MaxPrec.
-func (z *Float) SetPrec(prec uint) *Float {
- z.acc = Exact // optimistically assume no rounding is needed
-
- // special case
- if prec == 0 {
- z.prec = 0
- if z.form == finite {
- // truncate z to 0
- z.acc = makeAcc(z.neg)
- z.form = zero
- }
- return z
- }
-
- // general case
- if prec > MaxPrec {
- prec = MaxPrec
- }
- old := z.prec
- z.prec = uint32(prec)
- if z.prec < old {
- z.round(0)
- }
- return z
-}
-
-func makeAcc(above bool) Accuracy {
- if above {
- return Above
- }
- return Below
-}
-
-// SetMode sets z's rounding mode to mode and returns an exact z.
-// z remains unchanged otherwise.
-// z.SetMode(z.Mode()) is a cheap way to set z's accuracy to Exact.
-func (z *Float) SetMode(mode RoundingMode) *Float {
- z.mode = mode
- z.acc = Exact
- return z
-}
-
-// Prec returns the mantissa precision of x in bits.
-// The result may be 0 for |x| == 0 and |x| == Inf.
-func (x *Float) Prec() uint {
- return uint(x.prec)
-}
-
-// MinPrec returns the minimum precision required to represent x exactly
-// (i.e., the smallest prec before x.SetPrec(prec) would start rounding x).
-// The result is 0 for |x| == 0 and |x| == Inf.
-func (x *Float) MinPrec() uint {
- if x.form != finite {
- return 0
- }
- return uint(len(x.mant))*_W - x.mant.trailingZeroBits()
-}
-
-// Mode returns the rounding mode of x.
-func (x *Float) Mode() RoundingMode {
- return x.mode
-}
-
-// Acc returns the accuracy of x produced by the most recent operation.
-func (x *Float) Acc() Accuracy {
- return x.acc
-}
-
-// Sign returns:
-//
-// -1 if x < 0
-// 0 if x is ±0
-// +1 if x > 0
-//
-func (x *Float) Sign() int {
- if debugFloat {
- x.validate()
- }
- if x.form == zero {
- return 0
- }
- if x.neg {
- return -1
- }
- return 1
-}
-
-// MantExp breaks x into its mantissa and exponent components
-// and returns the exponent. If a non-nil mant argument is
-// provided its value is set to the mantissa of x, with the
-// same precision and rounding mode as x. The components
-// satisfy x == mant × 2**exp, with 0.5 <= |mant| < 1.0.
-// Calling MantExp with a nil argument is an efficient way to
-// get the exponent of the receiver.
-//
-// Special cases are:
-//
-// ( ±0).MantExp(mant) = 0, with mant set to ±0
-// (±Inf).MantExp(mant) = 0, with mant set to ±Inf
-//
-// x and mant may be the same in which case x is set to its
-// mantissa value.
-func (x *Float) MantExp(mant *Float) (exp int) {
- if debugFloat {
- x.validate()
- }
- if x.form == finite {
- exp = int(x.exp)
- }
- if mant != nil {
- mant.Copy(x)
- if mant.form == finite {
- mant.exp = 0
- }
- }
- return
-}
-
-func (z *Float) setExpAndRound(exp int64, sbit uint) {
- if exp < MinExp {
- // underflow
- z.acc = makeAcc(z.neg)
- z.form = zero
- return
- }
-
- if exp > MaxExp {
- // overflow
- z.acc = makeAcc(!z.neg)
- z.form = inf
- return
- }
-
- z.form = finite
- z.exp = int32(exp)
- z.round(sbit)
-}
-
-// SetMantExp sets z to mant × 2**exp and and returns z.
-// The result z has the same precision and rounding mode
-// as mant. SetMantExp is an inverse of MantExp but does
-// not require 0.5 <= |mant| < 1.0. Specifically:
-//
-// mant := new(Float)
-// new(Float).SetMantExp(mant, x.MantExp(mant)).Cmp(x) == 0
-//
-// Special cases are:
-//
-// z.SetMantExp( ±0, exp) = ±0
-// z.SetMantExp(±Inf, exp) = ±Inf
-//
-// z and mant may be the same in which case z's exponent
-// is set to exp.
-func (z *Float) SetMantExp(mant *Float, exp int) *Float {
- if debugFloat {
- z.validate()
- mant.validate()
- }
- z.Copy(mant)
- if z.form != finite {
- return z
- }
- z.setExpAndRound(int64(z.exp)+int64(exp), 0)
- return z
-}
-
-// Signbit returns true if x is negative or negative zero.
-func (x *Float) Signbit() bool {
- return x.neg
-}
-
-// IsInf reports whether x is +Inf or -Inf.
-func (x *Float) IsInf() bool {
- return x.form == inf
-}
-
-// IsInt reports whether x is an integer.
-// ±Inf values are not integers.
-func (x *Float) IsInt() bool {
- if debugFloat {
- x.validate()
- }
- // special cases
- if x.form != finite {
- return x.form == zero
- }
- // x.form == finite
- if x.exp <= 0 {
- return false
- }
- // x.exp > 0
- return x.prec <= uint32(x.exp) || x.MinPrec() <= uint(x.exp) // not enough bits for fractional mantissa
-}
-
-// debugging support
-func (x *Float) validate() {
- if !debugFloat {
- // avoid performance bugs
- panic("validate called but debugFloat is not set")
- }
- if x.form != finite {
- return
- }
- m := len(x.mant)
- if m == 0 {
- panic("nonzero finite number with empty mantissa")
- }
- const msb = 1 << (_W - 1)
- if x.mant[m-1]&msb == 0 {
- panic(fmt.Sprintf("msb not set in last word %#x of %s", x.mant[m-1], x.Text('p', 0)))
- }
- if x.prec == 0 {
- panic("zero precision finite number")
- }
-}
-
-// round rounds z according to z.mode to z.prec bits and sets z.acc accordingly.
-// sbit must be 0 or 1 and summarizes any "sticky bit" information one might
-// have before calling round. z's mantissa must be normalized (with the msb set)
-// or empty.
-//
-// CAUTION: The rounding modes ToNegativeInf, ToPositiveInf are affected by the
-// sign of z. For correct rounding, the sign of z must be set correctly before
-// calling round.
-func (z *Float) round(sbit uint) {
- if debugFloat {
- z.validate()
- }
-
- z.acc = Exact
- if z.form != finite {
- // ±0 or ±Inf => nothing left to do
- return
- }
- // z.form == finite && len(z.mant) > 0
- // m > 0 implies z.prec > 0 (checked by validate)
-
- m := uint32(len(z.mant)) // present mantissa length in words
- bits := m * _W // present mantissa bits; bits > 0
- if bits <= z.prec {
- // mantissa fits => nothing to do
- return
- }
- // bits > z.prec
-
- // Rounding is based on two bits: the rounding bit (rbit) and the
- // sticky bit (sbit). The rbit is the bit immediately before the
- // z.prec leading mantissa bits (the "0.5"). The sbit is set if any
- // of the bits before the rbit are set (the "0.25", "0.125", etc.):
- //
- // rbit sbit => "fractional part"
- //
- // 0 0 == 0
- // 0 1 > 0 , < 0.5
- // 1 0 == 0.5
- // 1 1 > 0.5, < 1.0
-
- // bits > z.prec: mantissa too large => round
- r := uint(bits - z.prec - 1) // rounding bit position; r >= 0
- rbit := z.mant.bit(r) & 1 // rounding bit; be safe and ensure it's a single bit
- if sbit == 0 {
- // TODO(gri) if rbit != 0 we don't need to compute sbit for some rounding modes (optimization)
- sbit = z.mant.sticky(r)
- }
- sbit &= 1 // be safe and ensure it's a single bit
-
- // cut off extra words
- n := (z.prec + (_W - 1)) / _W // mantissa length in words for desired precision
- if m > n {
- copy(z.mant, z.mant[m-n:]) // move n last words to front
- z.mant = z.mant[:n]
- }
-
- // determine number of trailing zero bits (ntz) and compute lsb mask of mantissa's least-significant word
- ntz := n*_W - z.prec // 0 <= ntz < _W
- lsb := Word(1) << ntz
-
- // round if result is inexact
- if rbit|sbit != 0 {
- // Make rounding decision: The result mantissa is truncated ("rounded down")
- // by default. Decide if we need to increment, or "round up", the (unsigned)
- // mantissa.
- inc := false
- switch z.mode {
- case ToNegativeInf:
- inc = z.neg
- case ToZero:
- // nothing to do
- case ToNearestEven:
- inc = rbit != 0 && (sbit != 0 || z.mant[0]&lsb != 0)
- case ToNearestAway:
- inc = rbit != 0
- case AwayFromZero:
- inc = true
- case ToPositiveInf:
- inc = !z.neg
- default:
- panic("unreachable")
- }
-
- // A positive result (!z.neg) is Above the exact result if we increment,
- // and it's Below if we truncate (Exact results require no rounding).
- // For a negative result (z.neg) it is exactly the opposite.
- z.acc = makeAcc(inc != z.neg)
-
- if inc {
- // add 1 to mantissa
- if addVW(z.mant, z.mant, lsb) != 0 {
- // mantissa overflow => adjust exponent
- if z.exp >= MaxExp {
- // exponent overflow
- z.form = inf
- return
- }
- z.exp++
- // adjust mantissa: divide by 2 to compensate for exponent adjustment
- shrVU(z.mant, z.mant, 1)
- // set msb == carry == 1 from the mantissa overflow above
- const msb = 1 << (_W - 1)
- z.mant[n-1] |= msb
- }
- }
- }
-
- // zero out trailing bits in least-significant word
- z.mant[0] &^= lsb - 1
-
- if debugFloat {
- z.validate()
- }
-}
-
-func (z *Float) setBits64(neg bool, x uint64) *Float {
- if z.prec == 0 {
- z.prec = 64
- }
- z.acc = Exact
- z.neg = neg
- if x == 0 {
- z.form = zero
- return z
- }
- // x != 0
- z.form = finite
- s := nlz64(x)
- z.mant = z.mant.setUint64(x << s)
- z.exp = int32(64 - s) // always fits
- if z.prec < 64 {
- z.round(0)
- }
- return z
-}
-
-// SetUint64 sets z to the (possibly rounded) value of x and returns z.
-// If z's precision is 0, it is changed to 64 (and rounding will have
-// no effect).
-func (z *Float) SetUint64(x uint64) *Float {
- return z.setBits64(false, x)
-}
-
-// SetInt64 sets z to the (possibly rounded) value of x and returns z.
-// If z's precision is 0, it is changed to 64 (and rounding will have
-// no effect).
-func (z *Float) SetInt64(x int64) *Float {
- u := x
- if u < 0 {
- u = -u
- }
- // We cannot simply call z.SetUint64(uint64(u)) and change
- // the sign afterwards because the sign affects rounding.
- return z.setBits64(x < 0, uint64(u))
-}
-
-// SetFloat64 sets z to the (possibly rounded) value of x and returns z.
-// If z's precision is 0, it is changed to 53 (and rounding will have
-// no effect). SetFloat64 panics with ErrNaN if x is a NaN.
-func (z *Float) SetFloat64(x float64) *Float {
- if z.prec == 0 {
- z.prec = 53
- }
- if math.IsNaN(x) {
- panic(ErrNaN{"Float.SetFloat64(NaN)"})
- }
- z.acc = Exact
- z.neg = math.Signbit(x) // handle -0, -Inf correctly
- if x == 0 {
- z.form = zero
- return z
- }
- if math.IsInf(x, 0) {
- z.form = inf
- return z
- }
- // normalized x != 0
- z.form = finite
- fmant, exp := math.Frexp(x) // get normalized mantissa
- z.mant = z.mant.setUint64(1<<63 | math.Float64bits(fmant)<<11)
- z.exp = int32(exp) // always fits
- if z.prec < 53 {
- z.round(0)
- }
- return z
-}
-
-// fnorm normalizes mantissa m by shifting it to the left
-// such that the msb of the most-significant word (msw) is 1.
-// It returns the shift amount. It assumes that len(m) != 0.
-func fnorm(m nat) int64 {
- if debugFloat && (len(m) == 0 || m[len(m)-1] == 0) {
- panic("msw of mantissa is 0")
- }
- s := nlz(m[len(m)-1])
- if s > 0 {
- c := shlVU(m, m, s)
- if debugFloat && c != 0 {
- panic("nlz or shlVU incorrect")
- }
- }
- return int64(s)
-}
-
-// SetInt sets z to the (possibly rounded) value of x and returns z.
-// If z's precision is 0, it is changed to the larger of x.BitLen()
-// or 64 (and rounding will have no effect).
-func (z *Float) SetInt(x *Int) *Float {
- // TODO(gri) can be more efficient if z.prec > 0
- // but small compared to the size of x, or if there
- // are many trailing 0's.
- bits := uint32(x.BitLen())
- if z.prec == 0 {
- z.prec = umax32(bits, 64)
- }
- z.acc = Exact
- z.neg = x.neg
- if len(x.abs) == 0 {
- z.form = zero
- return z
- }
- // x != 0
- z.mant = z.mant.set(x.abs)
- fnorm(z.mant)
- z.setExpAndRound(int64(bits), 0)
- return z
-}
-
-// SetRat sets z to the (possibly rounded) value of x and returns z.
-// If z's precision is 0, it is changed to the largest of a.BitLen(),
-// b.BitLen(), or 64; with x = a/b.
-func (z *Float) SetRat(x *Rat) *Float {
- if x.IsInt() {
- return z.SetInt(x.Num())
- }
- var a, b Float
- a.SetInt(x.Num())
- b.SetInt(x.Denom())
- if z.prec == 0 {
- z.prec = umax32(a.prec, b.prec)
- }
- return z.Quo(&a, &b)
-}
-
-// SetInf sets z to the infinite Float -Inf if signbit is
-// set, or +Inf if signbit is not set, and returns z. The
-// precision of z is unchanged and the result is always
-// Exact.
-func (z *Float) SetInf(signbit bool) *Float {
- z.acc = Exact
- z.form = inf
- z.neg = signbit
- return z
-}
-
-// Set sets z to the (possibly rounded) value of x and returns z.
-// If z's precision is 0, it is changed to the precision of x
-// before setting z (and rounding will have no effect).
-// Rounding is performed according to z's precision and rounding
-// mode; and z's accuracy reports the result error relative to the
-// exact (not rounded) result.
-func (z *Float) Set(x *Float) *Float {
- if debugFloat {
- x.validate()
- }
- z.acc = Exact
- if z != x {
- z.form = x.form
- z.neg = x.neg
- if x.form == finite {
- z.exp = x.exp
- z.mant = z.mant.set(x.mant)
- }
- if z.prec == 0 {
- z.prec = x.prec
- } else if z.prec < x.prec {
- z.round(0)
- }
- }
- return z
-}
-
-// Copy sets z to x, with the same precision, rounding mode, and
-// accuracy as x, and returns z. x is not changed even if z and
-// x are the same.
-func (z *Float) Copy(x *Float) *Float {
- if debugFloat {
- x.validate()
- }
- if z != x {
- z.prec = x.prec
- z.mode = x.mode
- z.acc = x.acc
- z.form = x.form
- z.neg = x.neg
- if z.form == finite {
- z.mant = z.mant.set(x.mant)
- z.exp = x.exp
- }
- }
- return z
-}
-
-// msb32 returns the 32 most significant bits of x.
-func msb32(x nat) uint32 {
- i := len(x) - 1
- if i < 0 {
- return 0
- }
- if debugFloat && x[i]&(1<<(_W-1)) == 0 {
- panic("x not normalized")
- }
- switch _W {
- case 32:
- return uint32(x[i])
- case 64:
- return uint32(x[i] >> 32)
- }
- panic("unreachable")
-}
-
-// msb64 returns the 64 most significant bits of x.
-func msb64(x nat) uint64 {
- i := len(x) - 1
- if i < 0 {
- return 0
- }
- if debugFloat && x[i]&(1<<(_W-1)) == 0 {
- panic("x not normalized")
- }
- switch _W {
- case 32:
- v := uint64(x[i]) << 32
- if i > 0 {
- v |= uint64(x[i-1])
- }
- return v
- case 64:
- return uint64(x[i])
- }
- panic("unreachable")
-}
-
-// Uint64 returns the unsigned integer resulting from truncating x
-// towards zero. If 0 <= x <= math.MaxUint64, the result is Exact
-// if x is an integer and Below otherwise.
-// The result is (0, Above) for x < 0, and (math.MaxUint64, Below)
-// for x > math.MaxUint64.
-func (x *Float) Uint64() (uint64, Accuracy) {
- if debugFloat {
- x.validate()
- }
-
- switch x.form {
- case finite:
- if x.neg {
- return 0, Above
- }
- // 0 < x < +Inf
- if x.exp <= 0 {
- // 0 < x < 1
- return 0, Below
- }
- // 1 <= x < Inf
- if x.exp <= 64 {
- // u = trunc(x) fits into a uint64
- u := msb64(x.mant) >> (64 - uint32(x.exp))
- if x.MinPrec() <= 64 {
- return u, Exact
- }
- return u, Below // x truncated
- }
- // x too large
- return math.MaxUint64, Below
-
- case zero:
- return 0, Exact
-
- case inf:
- if x.neg {
- return 0, Above
- }
- return math.MaxUint64, Below
- }
-
- panic("unreachable")
-}
-
-// Int64 returns the integer resulting from truncating x towards zero.
-// If math.MinInt64 <= x <= math.MaxInt64, the result is Exact if x is
-// an integer, and Above (x < 0) or Below (x > 0) otherwise.
-// The result is (math.MinInt64, Above) for x < math.MinInt64,
-// and (math.MaxInt64, Below) for x > math.MaxInt64.
-func (x *Float) Int64() (int64, Accuracy) {
- if debugFloat {
- x.validate()
- }
-
- switch x.form {
- case finite:
- // 0 < |x| < +Inf
- acc := makeAcc(x.neg)
- if x.exp <= 0 {
- // 0 < |x| < 1
- return 0, acc
- }
- // x.exp > 0
-
- // 1 <= |x| < +Inf
- if x.exp <= 63 {
- // i = trunc(x) fits into an int64 (excluding math.MinInt64)
- i := int64(msb64(x.mant) >> (64 - uint32(x.exp)))
- if x.neg {
- i = -i
- }
- if x.MinPrec() <= uint(x.exp) {
- return i, Exact
- }
- return i, acc // x truncated
- }
- if x.neg {
- // check for special case x == math.MinInt64 (i.e., x == -(0.5 << 64))
- if x.exp == 64 && x.MinPrec() == 1 {
- acc = Exact
- }
- return math.MinInt64, acc
- }
- // x too large
- return math.MaxInt64, Below
-
- case zero:
- return 0, Exact
-
- case inf:
- if x.neg {
- return math.MinInt64, Above
- }
- return math.MaxInt64, Below
- }
-
- panic("unreachable")
-}
-
-// Float32 returns the float32 value nearest to x. If x is too small to be
-// represented by a float32 (|x| < math.SmallestNonzeroFloat32), the result
-// is (0, Below) or (-0, Above), respectively, depending on the sign of x.
-// If x is too large to be represented by a float32 (|x| > math.MaxFloat32),
-// the result is (+Inf, Above) or (-Inf, Below), depending on the sign of x.
-func (x *Float) Float32() (float32, Accuracy) {
- if debugFloat {
- x.validate()
- }
-
- switch x.form {
- case finite:
- // 0 < |x| < +Inf
-
- const (
- fbits = 32 // float size
- mbits = 23 // mantissa size (excluding implicit msb)
- ebits = fbits - mbits - 1 // 8 exponent size
- bias = 1<<(ebits-1) - 1 // 127 exponent bias
- dmin = 1 - bias - mbits // -149 smallest unbiased exponent (denormal)
- emin = 1 - bias // -126 smallest unbiased exponent (normal)
- emax = bias // 127 largest unbiased exponent (normal)
- )
-
- // Float mantissa m is 0.5 <= m < 1.0; compute exponent e for float32 mantissa.
- e := x.exp - 1 // exponent for normal mantissa m with 1.0 <= m < 2.0
-
- // Compute precision p for float32 mantissa.
- // If the exponent is too small, we have a denormal number before
- // rounding and fewer than p mantissa bits of precision available
- // (the exponent remains fixed but the mantissa gets shifted right).
- p := mbits + 1 // precision of normal float
- if e < emin {
- // recompute precision
- p = mbits + 1 - emin + int(e)
- // If p == 0, the mantissa of x is shifted so much to the right
- // that its msb falls immediately to the right of the float32
- // mantissa space. In other words, if the smallest denormal is
- // considered "1.0", for p == 0, the mantissa value m is >= 0.5.
- // If m > 0.5, it is rounded up to 1.0; i.e., the smallest denormal.
- // If m == 0.5, it is rounded down to even, i.e., 0.0.
- // If p < 0, the mantissa value m is <= "0.25" which is never rounded up.
- if p < 0 /* m <= 0.25 */ || p == 0 && x.mant.sticky(uint(len(x.mant))*_W-1) == 0 /* m == 0.5 */ {
- // underflow to ±0
- if x.neg {
- var z float32
- return -z, Above
- }
- return 0.0, Below
- }
- // otherwise, round up
- // We handle p == 0 explicitly because it's easy and because
- // Float.round doesn't support rounding to 0 bits of precision.
- if p == 0 {
- if x.neg {
- return -math.SmallestNonzeroFloat32, Below
- }
- return math.SmallestNonzeroFloat32, Above
- }
- }
- // p > 0
-
- // round
- var r Float
- r.prec = uint32(p)
- r.Set(x)
- e = r.exp - 1
-
- // Rounding may have caused r to overflow to ±Inf
- // (rounding never causes underflows to 0).
- // If the exponent is too large, also overflow to ±Inf.
- if r.form == inf || e > emax {
- // overflow
- if x.neg {
- return float32(math.Inf(-1)), Below
- }
- return float32(math.Inf(+1)), Above
- }
- // e <= emax
-
- // Determine sign, biased exponent, and mantissa.
- var sign, bexp, mant uint32
- if x.neg {
- sign = 1 << (fbits - 1)
- }
-
- // Rounding may have caused a denormal number to
- // become normal. Check again.
- if e < emin {
- // denormal number: recompute precision
- // Since rounding may have at best increased precision
- // and we have eliminated p <= 0 early, we know p > 0.
- // bexp == 0 for denormals
- p = mbits + 1 - emin + int(e)
- mant = msb32(r.mant) >> uint(fbits-p)
- } else {
- // normal number: emin <= e <= emax
- bexp = uint32(e+bias) << mbits
- mant = msb32(r.mant) >> ebits & (1<<mbits - 1) // cut off msb (implicit 1 bit)
- }
-
- return math.Float32frombits(sign | bexp | mant), r.acc
-
- case zero:
- if x.neg {
- var z float32
- return -z, Exact
- }
- return 0.0, Exact
-
- case inf:
- if x.neg {
- return float32(math.Inf(-1)), Exact
- }
- return float32(math.Inf(+1)), Exact
- }
-
- panic("unreachable")
-}
-
-// Float64 returns the float64 value nearest to x. If x is too small to be
-// represented by a float64 (|x| < math.SmallestNonzeroFloat64), the result
-// is (0, Below) or (-0, Above), respectively, depending on the sign of x.
-// If x is too large to be represented by a float64 (|x| > math.MaxFloat64),
-// the result is (+Inf, Above) or (-Inf, Below), depending on the sign of x.
-func (x *Float) Float64() (float64, Accuracy) {
- if debugFloat {
- x.validate()
- }
-
- switch x.form {
- case finite:
- // 0 < |x| < +Inf
-
- const (
- fbits = 64 // float size
- mbits = 52 // mantissa size (excluding implicit msb)
- ebits = fbits - mbits - 1 // 11 exponent size
- bias = 1<<(ebits-1) - 1 // 1023 exponent bias
- dmin = 1 - bias - mbits // -1074 smallest unbiased exponent (denormal)
- emin = 1 - bias // -1022 smallest unbiased exponent (normal)
- emax = bias // 1023 largest unbiased exponent (normal)
- )
-
- // Float mantissa m is 0.5 <= m < 1.0; compute exponent e for float64 mantissa.
- e := x.exp - 1 // exponent for normal mantissa m with 1.0 <= m < 2.0
-
- // Compute precision p for float64 mantissa.
- // If the exponent is too small, we have a denormal number before
- // rounding and fewer than p mantissa bits of precision available
- // (the exponent remains fixed but the mantissa gets shifted right).
- p := mbits + 1 // precision of normal float
- if e < emin {
- // recompute precision
- p = mbits + 1 - emin + int(e)
- // If p == 0, the mantissa of x is shifted so much to the right
- // that its msb falls immediately to the right of the float64
- // mantissa space. In other words, if the smallest denormal is
- // considered "1.0", for p == 0, the mantissa value m is >= 0.5.
- // If m > 0.5, it is rounded up to 1.0; i.e., the smallest denormal.
- // If m == 0.5, it is rounded down to even, i.e., 0.0.
- // If p < 0, the mantissa value m is <= "0.25" which is never rounded up.
- if p < 0 /* m <= 0.25 */ || p == 0 && x.mant.sticky(uint(len(x.mant))*_W-1) == 0 /* m == 0.5 */ {
- // underflow to ±0
- if x.neg {
- var z float64
- return -z, Above
- }
- return 0.0, Below
- }
- // otherwise, round up
- // We handle p == 0 explicitly because it's easy and because
- // Float.round doesn't support rounding to 0 bits of precision.
- if p == 0 {
- if x.neg {
- return -math.SmallestNonzeroFloat64, Below
- }
- return math.SmallestNonzeroFloat64, Above
- }
- }
- // p > 0
-
- // round
- var r Float
- r.prec = uint32(p)
- r.Set(x)
- e = r.exp - 1
-
- // Rounding may have caused r to overflow to ±Inf
- // (rounding never causes underflows to 0).
- // If the exponent is too large, also overflow to ±Inf.
- if r.form == inf || e > emax {
- // overflow
- if x.neg {
- return float64(math.Inf(-1)), Below
- }
- return float64(math.Inf(+1)), Above
- }
- // e <= emax
-
- // Determine sign, biased exponent, and mantissa.
- var sign, bexp, mant uint64
- if x.neg {
- sign = 1 << (fbits - 1)
- }
-
- // Rounding may have caused a denormal number to
- // become normal. Check again.
- if e < emin {
- // denormal number: recompute precision
- // Since rounding may have at best increased precision
- // and we have eliminated p <= 0 early, we know p > 0.
- // bexp == 0 for denormals
- p = mbits + 1 - emin + int(e)
- mant = msb64(r.mant) >> uint(fbits-p)
- } else {
- // normal number: emin <= e <= emax
- bexp = uint64(e+bias) << mbits
- mant = msb64(r.mant) >> ebits & (1<<mbits - 1) // cut off msb (implicit 1 bit)
- }
-
- return math.Float64frombits(sign | bexp | mant), r.acc
-
- case zero:
- if x.neg {
- var z float64
- return -z, Exact
- }
- return 0.0, Exact
-
- case inf:
- if x.neg {
- return math.Inf(-1), Exact
- }
- return math.Inf(+1), Exact
- }
-
- panic("unreachable")
-}
-
-// Int returns the result of truncating x towards zero;
-// or nil if x is an infinity.
-// The result is Exact if x.IsInt(); otherwise it is Below
-// for x > 0, and Above for x < 0.
-// If a non-nil *Int argument z is provided, Int stores
-// the result in z instead of allocating a new Int.
-func (x *Float) Int(z *Int) (*Int, Accuracy) {
- if debugFloat {
- x.validate()
- }
-
- if z == nil && x.form <= finite {
- z = new(Int)
- }
-
- switch x.form {
- case finite:
- // 0 < |x| < +Inf
- acc := makeAcc(x.neg)
- if x.exp <= 0 {
- // 0 < |x| < 1
- return z.SetInt64(0), acc
- }
- // x.exp > 0
-
- // 1 <= |x| < +Inf
- // determine minimum required precision for x
- allBits := uint(len(x.mant)) * _W
- exp := uint(x.exp)
- if x.MinPrec() <= exp {
- acc = Exact
- }
- // shift mantissa as needed
- if z == nil {
- z = new(Int)
- }
- z.neg = x.neg
- switch {
- case exp > allBits:
- z.abs = z.abs.shl(x.mant, exp-allBits)
- default:
- z.abs = z.abs.set(x.mant)
- case exp < allBits:
- z.abs = z.abs.shr(x.mant, allBits-exp)
- }
- return z, acc
-
- case zero:
- return z.SetInt64(0), Exact
-
- case inf:
- return nil, makeAcc(x.neg)
- }
-
- panic("unreachable")
-}
-
-// Rat returns the rational number corresponding to x;
-// or nil if x is an infinity.
-// The result is Exact if x is not an Inf.
-// If a non-nil *Rat argument z is provided, Rat stores
-// the result in z instead of allocating a new Rat.
-func (x *Float) Rat(z *Rat) (*Rat, Accuracy) {
- if debugFloat {
- x.validate()
- }
-
- if z == nil && x.form <= finite {
- z = new(Rat)
- }
-
- switch x.form {
- case finite:
- // 0 < |x| < +Inf
- allBits := int32(len(x.mant)) * _W
- // build up numerator and denominator
- z.a.neg = x.neg
- switch {
- case x.exp > allBits:
- z.a.abs = z.a.abs.shl(x.mant, uint(x.exp-allBits))
- z.b.abs = z.b.abs[:0] // == 1 (see Rat)
- // z already in normal form
- default:
- z.a.abs = z.a.abs.set(x.mant)
- z.b.abs = z.b.abs[:0] // == 1 (see Rat)
- // z already in normal form
- case x.exp < allBits:
- z.a.abs = z.a.abs.set(x.mant)
- t := z.b.abs.setUint64(1)
- z.b.abs = t.shl(t, uint(allBits-x.exp))
- z.norm()
- }
- return z, Exact
-
- case zero:
- return z.SetInt64(0), Exact
-
- case inf:
- return nil, makeAcc(x.neg)
- }
-
- panic("unreachable")
-}
-
-// Abs sets z to the (possibly rounded) value |x| (the absolute value of x)
-// and returns z.
-func (z *Float) Abs(x *Float) *Float {
- z.Set(x)
- z.neg = false
- return z
-}
-
-// Neg sets z to the (possibly rounded) value of x with its sign negated,
-// and returns z.
-func (z *Float) Neg(x *Float) *Float {
- z.Set(x)
- z.neg = !z.neg
- return z
-}
-
-func validateBinaryOperands(x, y *Float) {
- if !debugFloat {
- // avoid performance bugs
- panic("validateBinaryOperands called but debugFloat is not set")
- }
- if len(x.mant) == 0 {
- panic("empty mantissa for x")
- }
- if len(y.mant) == 0 {
- panic("empty mantissa for y")
- }
-}
-
-// z = x + y, ignoring signs of x and y for the addition
-// but using the sign of z for rounding the result.
-// x and y must have a non-empty mantissa and valid exponent.
-func (z *Float) uadd(x, y *Float) {
- // Note: This implementation requires 2 shifts most of the
- // time. It is also inefficient if exponents or precisions
- // differ by wide margins. The following article describes
- // an efficient (but much more complicated) implementation
- // compatible with the internal representation used here:
- //
- // Vincent Lefèvre: "The Generic Multiple-Precision Floating-
- // Point Addition With Exact Rounding (as in the MPFR Library)"
- // http://www.vinc17.net/research/papers/rnc6.pdf
-
- if debugFloat {
- validateBinaryOperands(x, y)
- }
-
- // compute exponents ex, ey for mantissa with "binary point"
- // on the right (mantissa.0) - use int64 to avoid overflow
- ex := int64(x.exp) - int64(len(x.mant))*_W
- ey := int64(y.exp) - int64(len(y.mant))*_W
-
- // TODO(gri) having a combined add-and-shift primitive
- // could make this code significantly faster
- switch {
- case ex < ey:
- // cannot re-use z.mant w/o testing for aliasing
- t := nat(nil).shl(y.mant, uint(ey-ex))
- z.mant = z.mant.add(x.mant, t)
- default:
- // ex == ey, no shift needed
- z.mant = z.mant.add(x.mant, y.mant)
- case ex > ey:
- // cannot re-use z.mant w/o testing for aliasing
- t := nat(nil).shl(x.mant, uint(ex-ey))
- z.mant = z.mant.add(t, y.mant)
- ex = ey
- }
- // len(z.mant) > 0
-
- z.setExpAndRound(ex+int64(len(z.mant))*_W-fnorm(z.mant), 0)
-}
-
-// z = x - y for |x| > |y|, ignoring signs of x and y for the subtraction
-// but using the sign of z for rounding the result.
-// x and y must have a non-empty mantissa and valid exponent.
-func (z *Float) usub(x, y *Float) {
- // This code is symmetric to uadd.
- // We have not factored the common code out because
- // eventually uadd (and usub) should be optimized
- // by special-casing, and the code will diverge.
-
- if debugFloat {
- validateBinaryOperands(x, y)
- }
-
- ex := int64(x.exp) - int64(len(x.mant))*_W
- ey := int64(y.exp) - int64(len(y.mant))*_W
-
- switch {
- case ex < ey:
- // cannot re-use z.mant w/o testing for aliasing
- t := nat(nil).shl(y.mant, uint(ey-ex))
- z.mant = t.sub(x.mant, t)
- default:
- // ex == ey, no shift needed
- z.mant = z.mant.sub(x.mant, y.mant)
- case ex > ey:
- // cannot re-use z.mant w/o testing for aliasing
- t := nat(nil).shl(x.mant, uint(ex-ey))
- z.mant = t.sub(t, y.mant)
- ex = ey
- }
-
- // operands may have canceled each other out
- if len(z.mant) == 0 {
- z.acc = Exact
- z.form = zero
- z.neg = false
- return
- }
- // len(z.mant) > 0
-
- z.setExpAndRound(ex+int64(len(z.mant))*_W-fnorm(z.mant), 0)
-}
-
-// z = x * y, ignoring signs of x and y for the multiplication
-// but using the sign of z for rounding the result.
-// x and y must have a non-empty mantissa and valid exponent.
-func (z *Float) umul(x, y *Float) {
- if debugFloat {
- validateBinaryOperands(x, y)
- }
-
- // Note: This is doing too much work if the precision
- // of z is less than the sum of the precisions of x
- // and y which is often the case (e.g., if all floats
- // have the same precision).
- // TODO(gri) Optimize this for the common case.
-
- e := int64(x.exp) + int64(y.exp)
- z.mant = z.mant.mul(x.mant, y.mant)
-
- z.setExpAndRound(e-fnorm(z.mant), 0)
-}
-
-// z = x / y, ignoring signs of x and y for the division
-// but using the sign of z for rounding the result.
-// x and y must have a non-empty mantissa and valid exponent.
-func (z *Float) uquo(x, y *Float) {
- if debugFloat {
- validateBinaryOperands(x, y)
- }
-
- // mantissa length in words for desired result precision + 1
- // (at least one extra bit so we get the rounding bit after
- // the division)
- n := int(z.prec/_W) + 1
-
- // compute adjusted x.mant such that we get enough result precision
- xadj := x.mant
- if d := n - len(x.mant) + len(y.mant); d > 0 {
- // d extra words needed => add d "0 digits" to x
- xadj = make(nat, len(x.mant)+d)
- copy(xadj[d:], x.mant)
- }
- // TODO(gri): If we have too many digits (d < 0), we should be able
- // to shorten x for faster division. But we must be extra careful
- // with rounding in that case.
-
- // Compute d before division since there may be aliasing of x.mant
- // (via xadj) or y.mant with z.mant.
- d := len(xadj) - len(y.mant)
-
- // divide
- var r nat
- z.mant, r = z.mant.div(nil, xadj, y.mant)
- e := int64(x.exp) - int64(y.exp) - int64(d-len(z.mant))*_W
-
- // The result is long enough to include (at least) the rounding bit.
- // If there's a non-zero remainder, the corresponding fractional part
- // (if it were computed), would have a non-zero sticky bit (if it were
- // zero, it couldn't have a non-zero remainder).
- var sbit uint
- if len(r) > 0 {
- sbit = 1
- }
-
- z.setExpAndRound(e-fnorm(z.mant), sbit)
-}
-
-// ucmp returns -1, 0, or +1, depending on whether
-// |x| < |y|, |x| == |y|, or |x| > |y|.
-// x and y must have a non-empty mantissa and valid exponent.
-func (x *Float) ucmp(y *Float) int {
- if debugFloat {
- validateBinaryOperands(x, y)
- }
-
- switch {
- case x.exp < y.exp:
- return -1
- case x.exp > y.exp:
- return +1
- }
- // x.exp == y.exp
-
- // compare mantissas
- i := len(x.mant)
- j := len(y.mant)
- for i > 0 || j > 0 {
- var xm, ym Word
- if i > 0 {
- i--
- xm = x.mant[i]
- }
- if j > 0 {
- j--
- ym = y.mant[j]
- }
- switch {
- case xm < ym:
- return -1
- case xm > ym:
- return +1
- }
- }
-
- return 0
-}
-
-// Handling of sign bit as defined by IEEE 754-2008, section 6.3:
-//
-// When neither the inputs nor result are NaN, the sign of a product or
-// quotient is the exclusive OR of the operands’ signs; the sign of a sum,
-// or of a difference x−y regarded as a sum x+(−y), differs from at most
-// one of the addends’ signs; and the sign of the result of conversions,
-// the quantize operation, the roundToIntegral operations, and the
-// roundToIntegralExact (see 5.3.1) is the sign of the first or only operand.
-// These rules shall apply even when operands or results are zero or infinite.
-//
-// When the sum of two operands with opposite signs (or the difference of
-// two operands with like signs) is exactly zero, the sign of that sum (or
-// difference) shall be +0 in all rounding-direction attributes except
-// roundTowardNegative; under that attribute, the sign of an exact zero
-// sum (or difference) shall be −0. However, x+x = x−(−x) retains the same
-// sign as x even when x is zero.
-//
-// See also: https://play.golang.org/p/RtH3UCt5IH
-
-// Add sets z to the rounded sum x+y and returns z. If z's precision is 0,
-// it is changed to the larger of x's or y's precision before the operation.
-// Rounding is performed according to z's precision and rounding mode; and
-// z's accuracy reports the result error relative to the exact (not rounded)
-// result. Add panics with ErrNaN if x and y are infinities with opposite
-// signs. The value of z is undefined in that case.
-//
-// BUG(gri) When rounding ToNegativeInf, the sign of Float values rounded to 0 is incorrect.
-func (z *Float) Add(x, y *Float) *Float {
- if debugFloat {
- x.validate()
- y.validate()
- }
-
- if z.prec == 0 {
- z.prec = umax32(x.prec, y.prec)
- }
-
- if x.form == finite && y.form == finite {
- // x + y (common case)
- z.neg = x.neg
- if x.neg == y.neg {
- // x + y == x + y
- // (-x) + (-y) == -(x + y)
- z.uadd(x, y)
- } else {
- // x + (-y) == x - y == -(y - x)
- // (-x) + y == y - x == -(x - y)
- if x.ucmp(y) > 0 {
- z.usub(x, y)
- } else {
- z.neg = !z.neg
- z.usub(y, x)
- }
- }
- return z
- }
-
- if x.form == inf && y.form == inf && x.neg != y.neg {
- // +Inf + -Inf
- // -Inf + +Inf
- // value of z is undefined but make sure it's valid
- z.acc = Exact
- z.form = zero
- z.neg = false
- panic(ErrNaN{"addition of infinities with opposite signs"})
- }
-
- if x.form == zero && y.form == zero {
- // ±0 + ±0
- z.acc = Exact
- z.form = zero
- z.neg = x.neg && y.neg // -0 + -0 == -0
- return z
- }
-
- if x.form == inf || y.form == zero {
- // ±Inf + y
- // x + ±0
- return z.Set(x)
- }
-
- // ±0 + y
- // x + ±Inf
- return z.Set(y)
-}
-
-// Sub sets z to the rounded difference x-y and returns z.
-// Precision, rounding, and accuracy reporting are as for Add.
-// Sub panics with ErrNaN if x and y are infinities with equal
-// signs. The value of z is undefined in that case.
-func (z *Float) Sub(x, y *Float) *Float {
- if debugFloat {
- x.validate()
- y.validate()
- }
-
- if z.prec == 0 {
- z.prec = umax32(x.prec, y.prec)
- }
-
- if x.form == finite && y.form == finite {
- // x - y (common case)
- z.neg = x.neg
- if x.neg != y.neg {
- // x - (-y) == x + y
- // (-x) - y == -(x + y)
- z.uadd(x, y)
- } else {
- // x - y == x - y == -(y - x)
- // (-x) - (-y) == y - x == -(x - y)
- if x.ucmp(y) > 0 {
- z.usub(x, y)
- } else {
- z.neg = !z.neg
- z.usub(y, x)
- }
- }
- return z
- }
-
- if x.form == inf && y.form == inf && x.neg == y.neg {
- // +Inf - +Inf
- // -Inf - -Inf
- // value of z is undefined but make sure it's valid
- z.acc = Exact
- z.form = zero
- z.neg = false
- panic(ErrNaN{"subtraction of infinities with equal signs"})
- }
-
- if x.form == zero && y.form == zero {
- // ±0 - ±0
- z.acc = Exact
- z.form = zero
- z.neg = x.neg && !y.neg // -0 - +0 == -0
- return z
- }
-
- if x.form == inf || y.form == zero {
- // ±Inf - y
- // x - ±0
- return z.Set(x)
- }
-
- // ±0 - y
- // x - ±Inf
- return z.Neg(y)
-}
-
-// Mul sets z to the rounded product x*y and returns z.
-// Precision, rounding, and accuracy reporting are as for Add.
-// Mul panics with ErrNaN if one operand is zero and the other
-// operand an infinity. The value of z is undefined in that case.
-func (z *Float) Mul(x, y *Float) *Float {
- if debugFloat {
- x.validate()
- y.validate()
- }
-
- if z.prec == 0 {
- z.prec = umax32(x.prec, y.prec)
- }
-
- z.neg = x.neg != y.neg
-
- if x.form == finite && y.form == finite {
- // x * y (common case)
- z.umul(x, y)
- return z
- }
-
- z.acc = Exact
- if x.form == zero && y.form == inf || x.form == inf && y.form == zero {
- // ±0 * ±Inf
- // ±Inf * ±0
- // value of z is undefined but make sure it's valid
- z.form = zero
- z.neg = false
- panic(ErrNaN{"multiplication of zero with infinity"})
- }
-
- if x.form == inf || y.form == inf {
- // ±Inf * y
- // x * ±Inf
- z.form = inf
- return z
- }
-
- // ±0 * y
- // x * ±0
- z.form = zero
- return z
-}
-
-// Quo sets z to the rounded quotient x/y and returns z.
-// Precision, rounding, and accuracy reporting are as for Add.
-// Quo panics with ErrNaN if both operands are zero or infinities.
-// The value of z is undefined in that case.
-func (z *Float) Quo(x, y *Float) *Float {
- if debugFloat {
- x.validate()
- y.validate()
- }
-
- if z.prec == 0 {
- z.prec = umax32(x.prec, y.prec)
- }
-
- z.neg = x.neg != y.neg
-
- if x.form == finite && y.form == finite {
- // x / y (common case)
- z.uquo(x, y)
- return z
- }
-
- z.acc = Exact
- if x.form == zero && y.form == zero || x.form == inf && y.form == inf {
- // ±0 / ±0
- // ±Inf / ±Inf
- // value of z is undefined but make sure it's valid
- z.form = zero
- z.neg = false
- panic(ErrNaN{"division of zero by zero or infinity by infinity"})
- }
-
- if x.form == zero || y.form == inf {
- // ±0 / y
- // x / ±Inf
- z.form = zero
- return z
- }
-
- // x / ±0
- // ±Inf / y
- z.form = inf
- return z
-}
-
-// Cmp compares x and y and returns:
-//
-// -1 if x < y
-// 0 if x == y (incl. -0 == 0, -Inf == -Inf, and +Inf == +Inf)
-// +1 if x > y
-//
-func (x *Float) Cmp(y *Float) int {
- if debugFloat {
- x.validate()
- y.validate()
- }
-
- mx := x.ord()
- my := y.ord()
- switch {
- case mx < my:
- return -1
- case mx > my:
- return +1
- }
- // mx == my
-
- // only if |mx| == 1 we have to compare the mantissae
- switch mx {
- case -1:
- return y.ucmp(x)
- case +1:
- return x.ucmp(y)
- }
-
- return 0
-}
-
-// ord classifies x and returns:
-//
-// -2 if -Inf == x
-// -1 if -Inf < x < 0
-// 0 if x == 0 (signed or unsigned)
-// +1 if 0 < x < +Inf
-// +2 if x == +Inf
-//
-func (x *Float) ord() int {
- var m int
- switch x.form {
- case finite:
- m = 1
- case zero:
- return 0
- case inf:
- m = 2
- }
- if x.neg {
- m = -m
- }
- return m
-}
-
-func umax32(x, y uint32) uint32 {
- if x > y {
- return x
- }
- return y
-}
diff --git a/src/cmd/compile/internal/big/float_test.go b/src/cmd/compile/internal/big/float_test.go
deleted file mode 100644
index 464619b..0000000
--- a/src/cmd/compile/internal/big/float_test.go
+++ /dev/null
@@ -1,1764 +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 big
-
-import (
- "fmt"
- "math"
- "strconv"
- "strings"
- "testing"
-)
-
-// Verify that ErrNaN implements the error interface.
-var _ error = ErrNaN{}
-
-func (x *Float) uint64() uint64 {
- u, acc := x.Uint64()
- if acc != Exact {
- panic(fmt.Sprintf("%s is not a uint64", x.Text('g', 10)))
- }
- return u
-}
-
-func (x *Float) int64() int64 {
- i, acc := x.Int64()
- if acc != Exact {
- panic(fmt.Sprintf("%s is not an int64", x.Text('g', 10)))
- }
- return i
-}
-
-func TestFloatZeroValue(t *testing.T) {
- // zero (uninitialized) value is a ready-to-use 0.0
- var x Float
- if s := x.Text('f', 1); s != "0.0" {
- t.Errorf("zero value = %s; want 0.0", s)
- }
-
- // zero value has precision 0
- if prec := x.Prec(); prec != 0 {
- t.Errorf("prec = %d; want 0", prec)
- }
-
- // zero value can be used in any and all positions of binary operations
- make := func(x int) *Float {
- var f Float
- if x != 0 {
- f.SetInt64(int64(x))
- }
- // x == 0 translates into the zero value
- return &f
- }
- for _, test := range []struct {
- z, x, y, want int
- opname rune
- op func(z, x, y *Float) *Float
- }{
- {0, 0, 0, 0, '+', (*Float).Add},
- {0, 1, 2, 3, '+', (*Float).Add},
- {1, 2, 0, 2, '+', (*Float).Add},
- {2, 0, 1, 1, '+', (*Float).Add},
-
- {0, 0, 0, 0, '-', (*Float).Sub},
- {0, 1, 2, -1, '-', (*Float).Sub},
- {1, 2, 0, 2, '-', (*Float).Sub},
- {2, 0, 1, -1, '-', (*Float).Sub},
-
- {0, 0, 0, 0, '*', (*Float).Mul},
- {0, 1, 2, 2, '*', (*Float).Mul},
- {1, 2, 0, 0, '*', (*Float).Mul},
- {2, 0, 1, 0, '*', (*Float).Mul},
-
- // {0, 0, 0, 0, '/', (*Float).Quo}, // panics
- {0, 2, 1, 2, '/', (*Float).Quo},
- {1, 2, 0, 0, '/', (*Float).Quo}, // = +Inf
- {2, 0, 1, 0, '/', (*Float).Quo},
- } {
- z := make(test.z)
- test.op(z, make(test.x), make(test.y))
- got := 0
- if !z.IsInf() {
- got = int(z.int64())
- }
- if got != test.want {
- t.Errorf("%d %c %d = %d; want %d", test.x, test.opname, test.y, got, test.want)
- }
- }
-
- // TODO(gri) test how precision is set for zero value results
-}
-
-func makeFloat(s string) *Float {
- x, _, err := ParseFloat(s, 0, 1000, ToNearestEven)
- if err != nil {
- panic(err)
- }
- return x
-}
-
-func TestFloatSetPrec(t *testing.T) {
- for _, test := range []struct {
- x string
- prec uint
- want string
- acc Accuracy
- }{
- // prec 0
- {"0", 0, "0", Exact},
- {"-0", 0, "-0", Exact},
- {"-Inf", 0, "-Inf", Exact},
- {"+Inf", 0, "+Inf", Exact},
- {"123", 0, "0", Below},
- {"-123", 0, "-0", Above},
-
- // prec at upper limit
- {"0", MaxPrec, "0", Exact},
- {"-0", MaxPrec, "-0", Exact},
- {"-Inf", MaxPrec, "-Inf", Exact},
- {"+Inf", MaxPrec, "+Inf", Exact},
-
- // just a few regular cases - general rounding is tested elsewhere
- {"1.5", 1, "2", Above},
- {"-1.5", 1, "-2", Below},
- {"123", 1e6, "123", Exact},
- {"-123", 1e6, "-123", Exact},
- } {
- x := makeFloat(test.x).SetPrec(test.prec)
- prec := test.prec
- if prec > MaxPrec {
- prec = MaxPrec
- }
- if got := x.Prec(); got != prec {
- t.Errorf("%s.SetPrec(%d).Prec() == %d; want %d", test.x, test.prec, got, prec)
- }
- if got, acc := x.String(), x.Acc(); got != test.want || acc != test.acc {
- t.Errorf("%s.SetPrec(%d) = %s (%s); want %s (%s)", test.x, test.prec, got, acc, test.want, test.acc)
- }
- }
-}
-
-func TestFloatMinPrec(t *testing.T) {
- const max = 100
- for _, test := range []struct {
- x string
- want uint
- }{
- {"0", 0},
- {"-0", 0},
- {"+Inf", 0},
- {"-Inf", 0},
- {"1", 1},
- {"2", 1},
- {"3", 2},
- {"0x8001", 16},
- {"0x8001p-1000", 16},
- {"0x8001p+1000", 16},
- {"0.1", max},
- } {
- x := makeFloat(test.x).SetPrec(max)
- if got := x.MinPrec(); got != test.want {
- t.Errorf("%s.MinPrec() = %d; want %d", test.x, got, test.want)
- }
- }
-}
-
-func TestFloatSign(t *testing.T) {
- for _, test := range []struct {
- x string
- s int
- }{
- {"-Inf", -1},
- {"-1", -1},
- {"-0", 0},
- {"+0", 0},
- {"+1", +1},
- {"+Inf", +1},
- } {
- x := makeFloat(test.x)
- s := x.Sign()
- if s != test.s {
- t.Errorf("%s.Sign() = %d; want %d", test.x, s, test.s)
- }
- }
-}
-
-// alike(x, y) is like x.Cmp(y) == 0 but also considers the sign of 0 (0 != -0).
-func alike(x, y *Float) bool {
- return x.Cmp(y) == 0 && x.Signbit() == y.Signbit()
-}
-
-func alike32(x, y float32) bool {
- // we can ignore NaNs
- return x == y && math.Signbit(float64(x)) == math.Signbit(float64(y))
-
-}
-
-func alike64(x, y float64) bool {
- // we can ignore NaNs
- return x == y && math.Signbit(x) == math.Signbit(y)
-
-}
-
-func TestFloatMantExp(t *testing.T) {
- for _, test := range []struct {
- x string
- mant string
- exp int
- }{
- {"0", "0", 0},
- {"+0", "0", 0},
- {"-0", "-0", 0},
- {"Inf", "+Inf", 0},
- {"+Inf", "+Inf", 0},
- {"-Inf", "-Inf", 0},
- {"1.5", "0.75", 1},
- {"1.024e3", "0.5", 11},
- {"-0.125", "-0.5", -2},
- } {
- x := makeFloat(test.x)
- mant := makeFloat(test.mant)
- m := new(Float)
- e := x.MantExp(m)
- if !alike(m, mant) || e != test.exp {
- t.Errorf("%s.MantExp() = %s, %d; want %s, %d", test.x, m.Text('g', 10), e, test.mant, test.exp)
- }
- }
-}
-
-func TestFloatMantExpAliasing(t *testing.T) {
- x := makeFloat("0.5p10")
- if e := x.MantExp(x); e != 10 {
- t.Fatalf("Float.MantExp aliasing error: got %d; want 10", e)
- }
- if want := makeFloat("0.5"); !alike(x, want) {
- t.Fatalf("Float.MantExp aliasing error: got %s; want %s", x.Text('g', 10), want.Text('g', 10))
- }
-}
-
-func TestFloatSetMantExp(t *testing.T) {
- for _, test := range []struct {
- frac string
- exp int
- z string
- }{
- {"0", 0, "0"},
- {"+0", 0, "0"},
- {"-0", 0, "-0"},
- {"Inf", 1234, "+Inf"},
- {"+Inf", -1234, "+Inf"},
- {"-Inf", -1234, "-Inf"},
- {"0", MinExp, "0"},
- {"0.25", MinExp, "+0"}, // exponent underflow
- {"-0.25", MinExp, "-0"}, // exponent underflow
- {"1", MaxExp, "+Inf"}, // exponent overflow
- {"2", MaxExp - 1, "+Inf"}, // exponent overflow
- {"0.75", 1, "1.5"},
- {"0.5", 11, "1024"},
- {"-0.5", -2, "-0.125"},
- {"32", 5, "1024"},
- {"1024", -10, "1"},
- } {
- frac := makeFloat(test.frac)
- want := makeFloat(test.z)
- var z Float
- z.SetMantExp(frac, test.exp)
- if !alike(&z, want) {
- t.Errorf("SetMantExp(%s, %d) = %s; want %s", test.frac, test.exp, z.Text('g', 10), test.z)
- }
- // test inverse property
- mant := new(Float)
- if z.SetMantExp(mant, want.MantExp(mant)).Cmp(want) != 0 {
- t.Errorf("Inverse property not satisfied: got %s; want %s", z.Text('g', 10), test.z)
- }
- }
-}
-
-func TestFloatPredicates(t *testing.T) {
- for _, test := range []struct {
- x string
- sign int
- signbit, inf bool
- }{
- {x: "-Inf", sign: -1, signbit: true, inf: true},
- {x: "-1", sign: -1, signbit: true},
- {x: "-0", signbit: true},
- {x: "0"},
- {x: "1", sign: 1},
- {x: "+Inf", sign: 1, inf: true},
- } {
- x := makeFloat(test.x)
- if got := x.Signbit(); got != test.signbit {
- t.Errorf("(%s).Signbit() = %v; want %v", test.x, got, test.signbit)
- }
- if got := x.Sign(); got != test.sign {
- t.Errorf("(%s).Sign() = %d; want %d", test.x, got, test.sign)
- }
- if got := x.IsInf(); got != test.inf {
- t.Errorf("(%s).IsInf() = %v; want %v", test.x, got, test.inf)
- }
- }
-}
-
-func TestFloatIsInt(t *testing.T) {
- for _, test := range []string{
- "0 int",
- "-0 int",
- "1 int",
- "-1 int",
- "0.5",
- "1.23",
- "1.23e1",
- "1.23e2 int",
- "0.000000001e+8",
- "0.000000001e+9 int",
- "1.2345e200 int",
- "Inf",
- "+Inf",
- "-Inf",
- } {
- s := strings.TrimSuffix(test, " int")
- want := s != test
- if got := makeFloat(s).IsInt(); got != want {
- t.Errorf("%s.IsInt() == %t", s, got)
- }
- }
-}
-
-func fromBinary(s string) int64 {
- x, err := strconv.ParseInt(s, 2, 64)
- if err != nil {
- panic(err)
- }
- return x
-}
-
-func toBinary(x int64) string {
- return strconv.FormatInt(x, 2)
-}
-
-func testFloatRound(t *testing.T, x, r int64, prec uint, mode RoundingMode) {
- // verify test data
- var ok bool
- switch mode {
- case ToNearestEven, ToNearestAway:
- ok = true // nothing to do for now
- case ToZero:
- if x < 0 {
- ok = r >= x
- } else {
- ok = r <= x
- }
- case AwayFromZero:
- if x < 0 {
- ok = r <= x
- } else {
- ok = r >= x
- }
- case ToNegativeInf:
- ok = r <= x
- case ToPositiveInf:
- ok = r >= x
- default:
- panic("unreachable")
- }
- if !ok {
- t.Fatalf("incorrect test data for prec = %d, %s: x = %s, r = %s", prec, mode, toBinary(x), toBinary(r))
- }
-
- // compute expected accuracy
- a := Exact
- switch {
- case r < x:
- a = Below
- case r > x:
- a = Above
- }
-
- // round
- f := new(Float).SetMode(mode).SetInt64(x).SetPrec(prec)
-
- // check result
- r1 := f.int64()
- p1 := f.Prec()
- a1 := f.Acc()
- if r1 != r || p1 != prec || a1 != a {
- t.Errorf("round %s (%d bits, %s) incorrect: got %s (%d bits, %s); want %s (%d bits, %s)",
- toBinary(x), prec, mode,
- toBinary(r1), p1, a1,
- toBinary(r), prec, a)
- return
- }
-
- // g and f should be the same
- // (rounding by SetPrec after SetInt64 using default precision
- // should be the same as rounding by SetInt64 after setting the
- // precision)
- g := new(Float).SetMode(mode).SetPrec(prec).SetInt64(x)
- if !alike(g, f) {
- t.Errorf("round %s (%d bits, %s) not symmetric: got %s and %s; want %s",
- toBinary(x), prec, mode,
- toBinary(g.int64()),
- toBinary(r1),
- toBinary(r),
- )
- return
- }
-
- // h and f should be the same
- // (repeated rounding should be idempotent)
- h := new(Float).SetMode(mode).SetPrec(prec).Set(f)
- if !alike(h, f) {
- t.Errorf("round %s (%d bits, %s) not idempotent: got %s and %s; want %s",
- toBinary(x), prec, mode,
- toBinary(h.int64()),
- toBinary(r1),
- toBinary(r),
- )
- return
- }
-}
-
-// TestFloatRound tests basic rounding.
-func TestFloatRound(t *testing.T) {
- for _, test := range []struct {
- prec uint
- x, zero, neven, naway, away string // input, results rounded to prec bits
- }{
- {5, "1000", "1000", "1000", "1000", "1000"},
- {5, "1001", "1001", "1001", "1001", "1001"},
- {5, "1010", "1010", "1010", "1010", "1010"},
- {5, "1011", "1011", "1011", "1011", "1011"},
- {5, "1100", "1100", "1100", "1100", "1100"},
- {5, "1101", "1101", "1101", "1101", "1101"},
- {5, "1110", "1110", "1110", "1110", "1110"},
- {5, "1111", "1111", "1111", "1111", "1111"},
-
- {4, "1000", "1000", "1000", "1000", "1000"},
- {4, "1001", "1001", "1001", "1001", "1001"},
- {4, "1010", "1010", "1010", "1010", "1010"},
- {4, "1011", "1011", "1011", "1011", "1011"},
- {4, "1100", "1100", "1100", "1100", "1100"},
- {4, "1101", "1101", "1101", "1101", "1101"},
- {4, "1110", "1110", "1110", "1110", "1110"},
- {4, "1111", "1111", "1111", "1111", "1111"},
-
- {3, "1000", "1000", "1000", "1000", "1000"},
- {3, "1001", "1000", "1000", "1010", "1010"},
- {3, "1010", "1010", "1010", "1010", "1010"},
- {3, "1011", "1010", "1100", "1100", "1100"},
- {3, "1100", "1100", "1100", "1100", "1100"},
- {3, "1101", "1100", "1100", "1110", "1110"},
- {3, "1110", "1110", "1110", "1110", "1110"},
- {3, "1111", "1110", "10000", "10000", "10000"},
-
- {3, "1000001", "1000000", "1000000", "1000000", "1010000"},
- {3, "1001001", "1000000", "1010000", "1010000", "1010000"},
- {3, "1010001", "1010000", "1010000", "1010000", "1100000"},
- {3, "1011001", "1010000", "1100000", "1100000", "1100000"},
- {3, "1100001", "1100000", "1100000", "1100000", "1110000"},
- {3, "1101001", "1100000", "1110000", "1110000", "1110000"},
- {3, "1110001", "1110000", "1110000", "1110000", "10000000"},
- {3, "1111001", "1110000", "10000000", "10000000", "10000000"},
-
- {2, "1000", "1000", "1000", "1000", "1000"},
- {2, "1001", "1000", "1000", "1000", "1100"},
- {2, "1010", "1000", "1000", "1100", "1100"},
- {2, "1011", "1000", "1100", "1100", "1100"},
- {2, "1100", "1100", "1100", "1100", "1100"},
- {2, "1101", "1100", "1100", "1100", "10000"},
- {2, "1110", "1100", "10000", "10000", "10000"},
- {2, "1111", "1100", "10000", "10000", "10000"},
-
- {2, "1000001", "1000000", "1000000", "1000000", "1100000"},
- {2, "1001001", "1000000", "1000000", "1000000", "1100000"},
- {2, "1010001", "1000000", "1100000", "1100000", "1100000"},
- {2, "1011001", "1000000", "1100000", "1100000", "1100000"},
- {2, "1100001", "1100000", "1100000", "1100000", "10000000"},
- {2, "1101001", "1100000", "1100000", "1100000", "10000000"},
- {2, "1110001", "1100000", "10000000", "10000000", "10000000"},
- {2, "1111001", "1100000", "10000000", "10000000", "10000000"},
-
- {1, "1000", "1000", "1000", "1000", "1000"},
- {1, "1001", "1000", "1000", "1000", "10000"},
- {1, "1010", "1000", "1000", "1000", "10000"},
- {1, "1011", "1000", "1000", "1000", "10000"},
- {1, "1100", "1000", "10000", "10000", "10000"},
- {1, "1101", "1000", "10000", "10000", "10000"},
- {1, "1110", "1000", "10000", "10000", "10000"},
- {1, "1111", "1000", "10000", "10000", "10000"},
-
- {1, "1000001", "1000000", "1000000", "1000000", "10000000"},
- {1, "1001001", "1000000", "1000000", "1000000", "10000000"},
- {1, "1010001", "1000000", "1000000", "1000000", "10000000"},
- {1, "1011001", "1000000", "1000000", "1000000", "10000000"},
- {1, "1100001", "1000000", "10000000", "10000000", "10000000"},
- {1, "1101001", "1000000", "10000000", "10000000", "10000000"},
- {1, "1110001", "1000000", "10000000", "10000000", "10000000"},
- {1, "1111001", "1000000", "10000000", "10000000", "10000000"},
- } {
- x := fromBinary(test.x)
- z := fromBinary(test.zero)
- e := fromBinary(test.neven)
- n := fromBinary(test.naway)
- a := fromBinary(test.away)
- prec := test.prec
-
- testFloatRound(t, x, z, prec, ToZero)
- testFloatRound(t, x, e, prec, ToNearestEven)
- testFloatRound(t, x, n, prec, ToNearestAway)
- testFloatRound(t, x, a, prec, AwayFromZero)
-
- testFloatRound(t, x, z, prec, ToNegativeInf)
- testFloatRound(t, x, a, prec, ToPositiveInf)
-
- testFloatRound(t, -x, -a, prec, ToNegativeInf)
- testFloatRound(t, -x, -z, prec, ToPositiveInf)
- }
-}
-
-// TestFloatRound24 tests that rounding a float64 to 24 bits
-// matches IEEE-754 rounding to nearest when converting a
-// float64 to a float32 (excluding denormal numbers).
-func TestFloatRound24(t *testing.T) {
- const x0 = 1<<26 - 0x10 // 11...110000 (26 bits)
- for d := 0; d <= 0x10; d++ {
- x := float64(x0 + d)
- f := new(Float).SetPrec(24).SetFloat64(x)
- got, _ := f.Float32()
- want := float32(x)
- if got != want {
- t.Errorf("Round(%g, 24) = %g; want %g", x, got, want)
- }
- }
-}
-
-func TestFloatSetUint64(t *testing.T) {
- for _, want := range []uint64{
- 0,
- 1,
- 2,
- 10,
- 100,
- 1<<32 - 1,
- 1 << 32,
- 1<<64 - 1,
- } {
- var f Float
- f.SetUint64(want)
- if got := f.uint64(); got != want {
- t.Errorf("got %#x (%s); want %#x", got, f.Text('p', 0), want)
- }
- }
-
- // test basic rounding behavior (exhaustive rounding testing is done elsewhere)
- const x uint64 = 0x8765432187654321 // 64 bits needed
- for prec := uint(1); prec <= 64; prec++ {
- f := new(Float).SetPrec(prec).SetMode(ToZero).SetUint64(x)
- got := f.uint64()
- want := x &^ (1<<(64-prec) - 1) // cut off (round to zero) low 64-prec bits
- if got != want {
- t.Errorf("got %#x (%s); want %#x", got, f.Text('p', 0), want)
- }
- }
-}
-
-func TestFloatSetInt64(t *testing.T) {
- for _, want := range []int64{
- 0,
- 1,
- 2,
- 10,
- 100,
- 1<<32 - 1,
- 1 << 32,
- 1<<63 - 1,
- } {
- for i := range [2]int{} {
- if i&1 != 0 {
- want = -want
- }
- var f Float
- f.SetInt64(want)
- if got := f.int64(); got != want {
- t.Errorf("got %#x (%s); want %#x", got, f.Text('p', 0), want)
- }
- }
- }
-
- // test basic rounding behavior (exhaustive rounding testing is done elsewhere)
- const x int64 = 0x7654321076543210 // 63 bits needed
- for prec := uint(1); prec <= 63; prec++ {
- f := new(Float).SetPrec(prec).SetMode(ToZero).SetInt64(x)
- got := f.int64()
- want := x &^ (1<<(63-prec) - 1) // cut off (round to zero) low 63-prec bits
- if got != want {
- t.Errorf("got %#x (%s); want %#x", got, f.Text('p', 0), want)
- }
- }
-}
-
-func TestFloatSetFloat64(t *testing.T) {
- for _, want := range []float64{
- 0,
- 1,
- 2,
- 12345,
- 1e10,
- 1e100,
- 3.14159265e10,
- 2.718281828e-123,
- 1.0 / 3,
- math.MaxFloat32,
- math.MaxFloat64,
- math.SmallestNonzeroFloat32,
- math.SmallestNonzeroFloat64,
- math.Inf(-1),
- math.Inf(0),
- -math.Inf(1),
- } {
- for i := range [2]int{} {
- if i&1 != 0 {
- want = -want
- }
- var f Float
- f.SetFloat64(want)
- if got, acc := f.Float64(); got != want || acc != Exact {
- t.Errorf("got %g (%s, %s); want %g (Exact)", got, f.Text('p', 0), acc, want)
- }
- }
- }
-
- // test basic rounding behavior (exhaustive rounding testing is done elsewhere)
- const x uint64 = 0x8765432143218 // 53 bits needed
- for prec := uint(1); prec <= 52; prec++ {
- f := new(Float).SetPrec(prec).SetMode(ToZero).SetFloat64(float64(x))
- got, _ := f.Float64()
- want := float64(x &^ (1<<(52-prec) - 1)) // cut off (round to zero) low 53-prec bits
- if got != want {
- t.Errorf("got %g (%s); want %g", got, f.Text('p', 0), want)
- }
- }
-
- // test NaN
- defer func() {
- if p, ok := recover().(ErrNaN); !ok {
- t.Errorf("got %v; want ErrNaN panic", p)
- }
- }()
- var f Float
- f.SetFloat64(math.NaN())
- // should not reach here
- t.Errorf("got %s; want ErrNaN panic", f.Text('p', 0))
-}
-
-func TestFloatSetInt(t *testing.T) {
- for _, want := range []string{
- "0",
- "1",
- "-1",
- "1234567890",
- "123456789012345678901234567890",
- "123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890",
- } {
- var x Int
- _, ok := x.SetString(want, 0)
- if !ok {
- t.Errorf("invalid integer %s", want)
- continue
- }
- n := x.BitLen()
-
- var f Float
- f.SetInt(&x)
-
- // check precision
- if n < 64 {
- n = 64
- }
- if prec := f.Prec(); prec != uint(n) {
- t.Errorf("got prec = %d; want %d", prec, n)
- }
-
- // check value
- got := f.Text('g', 100)
- if got != want {
- t.Errorf("got %s (%s); want %s", got, f.Text('p', 0), want)
- }
- }
-
- // TODO(gri) test basic rounding behavior
-}
-
-func TestFloatSetRat(t *testing.T) {
- for _, want := range []string{
- "0",
- "1",
- "-1",
- "1234567890",
- "123456789012345678901234567890",
- "123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890",
- "1.2",
- "3.14159265",
- // TODO(gri) expand
- } {
- var x Rat
- _, ok := x.SetString(want)
- if !ok {
- t.Errorf("invalid fraction %s", want)
- continue
- }
- n := max(x.Num().BitLen(), x.Denom().BitLen())
-
- var f1, f2 Float
- f2.SetPrec(1000)
- f1.SetRat(&x)
- f2.SetRat(&x)
-
- // check precision when set automatically
- if n < 64 {
- n = 64
- }
- if prec := f1.Prec(); prec != uint(n) {
- t.Errorf("got prec = %d; want %d", prec, n)
- }
-
- got := f2.Text('g', 100)
- if got != want {
- t.Errorf("got %s (%s); want %s", got, f2.Text('p', 0), want)
- }
- }
-}
-
-func TestFloatSetInf(t *testing.T) {
- var f Float
- for _, test := range []struct {
- signbit bool
- prec uint
- want string
- }{
- {false, 0, "+Inf"},
- {true, 0, "-Inf"},
- {false, 10, "+Inf"},
- {true, 30, "-Inf"},
- } {
- x := f.SetPrec(test.prec).SetInf(test.signbit)
- if got := x.String(); got != test.want || x.Prec() != test.prec {
- t.Errorf("SetInf(%v) = %s (prec = %d); want %s (prec = %d)", test.signbit, got, x.Prec(), test.want, test.prec)
- }
- }
-}
-
-func TestFloatUint64(t *testing.T) {
- for _, test := range []struct {
- x string
- out uint64
- acc Accuracy
- }{
- {"-Inf", 0, Above},
- {"-1", 0, Above},
- {"-1e-1000", 0, Above},
- {"-0", 0, Exact},
- {"0", 0, Exact},
- {"1e-1000", 0, Below},
- {"1", 1, Exact},
- {"1.000000000000000000001", 1, Below},
- {"12345.0", 12345, Exact},
- {"12345.000000000000000000001", 12345, Below},
- {"18446744073709551615", 18446744073709551615, Exact},
- {"18446744073709551615.000000000000000000001", math.MaxUint64, Below},
- {"18446744073709551616", math.MaxUint64, Below},
- {"1e10000", math.MaxUint64, Below},
- {"+Inf", math.MaxUint64, Below},
- } {
- x := makeFloat(test.x)
- out, acc := x.Uint64()
- if out != test.out || acc != test.acc {
- t.Errorf("%s: got %d (%s); want %d (%s)", test.x, out, acc, test.out, test.acc)
- }
- }
-}
-
-func TestFloatInt64(t *testing.T) {
- for _, test := range []struct {
- x string
- out int64
- acc Accuracy
- }{
- {"-Inf", math.MinInt64, Above},
- {"-1e10000", math.MinInt64, Above},
- {"-9223372036854775809", math.MinInt64, Above},
- {"-9223372036854775808.000000000000000000001", math.MinInt64, Above},
- {"-9223372036854775808", -9223372036854775808, Exact},
- {"-9223372036854775807.000000000000000000001", -9223372036854775807, Above},
- {"-9223372036854775807", -9223372036854775807, Exact},
- {"-12345.000000000000000000001", -12345, Above},
- {"-12345.0", -12345, Exact},
- {"-1.000000000000000000001", -1, Above},
- {"-1.5", -1, Above},
- {"-1", -1, Exact},
- {"-1e-1000", 0, Above},
- {"0", 0, Exact},
- {"1e-1000", 0, Below},
- {"1", 1, Exact},
- {"1.000000000000000000001", 1, Below},
- {"1.5", 1, Below},
- {"12345.0", 12345, Exact},
- {"12345.000000000000000000001", 12345, Below},
- {"9223372036854775807", 9223372036854775807, Exact},
- {"9223372036854775807.000000000000000000001", math.MaxInt64, Below},
- {"9223372036854775808", math.MaxInt64, Below},
- {"1e10000", math.MaxInt64, Below},
- {"+Inf", math.MaxInt64, Below},
- } {
- x := makeFloat(test.x)
- out, acc := x.Int64()
- if out != test.out || acc != test.acc {
- t.Errorf("%s: got %d (%s); want %d (%s)", test.x, out, acc, test.out, test.acc)
- }
- }
-}
-
-func TestFloatFloat32(t *testing.T) {
- for _, test := range []struct {
- x string
- out float32
- acc Accuracy
- }{
- {"0", 0, Exact},
-
- // underflow to zero
- {"1e-1000", 0, Below},
- {"0x0.000002p-127", 0, Below},
- {"0x.0000010p-126", 0, Below},
-
- // denormals
- {"1.401298464e-45", math.SmallestNonzeroFloat32, Above}, // rounded up to smallest denormal
- {"0x.ffffff8p-149", math.SmallestNonzeroFloat32, Above}, // rounded up to smallest denormal
- {"0x.0000018p-126", math.SmallestNonzeroFloat32, Above}, // rounded up to smallest denormal
- {"0x.0000020p-126", math.SmallestNonzeroFloat32, Exact},
- {"0x.8p-148", math.SmallestNonzeroFloat32, Exact},
- {"1p-149", math.SmallestNonzeroFloat32, Exact},
- {"0x.fffffep-126", math.Float32frombits(0x7fffff), Exact}, // largest denormal
-
- // special denormal cases (see issues 14553, 14651)
- {"0x0.0000001p-126", math.Float32frombits(0x00000000), Below}, // underflow to zero
- {"0x0.0000008p-126", math.Float32frombits(0x00000000), Below}, // underflow to zero
- {"0x0.0000010p-126", math.Float32frombits(0x00000000), Below}, // rounded down to even
- {"0x0.0000011p-126", math.Float32frombits(0x00000001), Above}, // rounded up to smallest denormal
- {"0x0.0000018p-126", math.Float32frombits(0x00000001), Above}, // rounded up to smallest denormal
-
- {"0x1.0000000p-149", math.Float32frombits(0x00000001), Exact}, // smallest denormal
- {"0x0.0000020p-126", math.Float32frombits(0x00000001), Exact}, // smallest denormal
- {"0x0.fffffe0p-126", math.Float32frombits(0x007fffff), Exact}, // largest denormal
- {"0x1.0000000p-126", math.Float32frombits(0x00800000), Exact}, // smallest normal
-
- {"0x0.8p-149", math.Float32frombits(0x000000000), Below}, // rounded down to even
- {"0x0.9p-149", math.Float32frombits(0x000000001), Above}, // rounded up to smallest denormal
- {"0x0.ap-149", math.Float32frombits(0x000000001), Above}, // rounded up to smallest denormal
- {"0x0.bp-149", math.Float32frombits(0x000000001), Above}, // rounded up to smallest denormal
- {"0x0.cp-149", math.Float32frombits(0x000000001), Above}, // rounded up to smallest denormal
-
- {"0x1.0p-149", math.Float32frombits(0x000000001), Exact}, // smallest denormal
- {"0x1.7p-149", math.Float32frombits(0x000000001), Below},
- {"0x1.8p-149", math.Float32frombits(0x000000002), Above},
- {"0x1.9p-149", math.Float32frombits(0x000000002), Above},
-
- {"0x2.0p-149", math.Float32frombits(0x000000002), Exact},
- {"0x2.8p-149", math.Float32frombits(0x000000002), Below}, // rounded down to even
- {"0x2.9p-149", math.Float32frombits(0x000000003), Above},
-
- {"0x3.0p-149", math.Float32frombits(0x000000003), Exact},
- {"0x3.7p-149", math.Float32frombits(0x000000003), Below},
- {"0x3.8p-149", math.Float32frombits(0x000000004), Above}, // rounded up to even
-
- {"0x4.0p-149", math.Float32frombits(0x000000004), Exact},
- {"0x4.8p-149", math.Float32frombits(0x000000004), Below}, // rounded down to even
- {"0x4.9p-149", math.Float32frombits(0x000000005), Above},
-
- // specific case from issue 14553
- {"0x7.7p-149", math.Float32frombits(0x000000007), Below},
- {"0x7.8p-149", math.Float32frombits(0x000000008), Above},
- {"0x7.9p-149", math.Float32frombits(0x000000008), Above},
-
- // normals
- {"0x.ffffffp-126", math.Float32frombits(0x00800000), Above}, // rounded up to smallest normal
- {"1p-126", math.Float32frombits(0x00800000), Exact}, // smallest normal
- {"0x1.fffffep-126", math.Float32frombits(0x00ffffff), Exact},
- {"0x1.ffffffp-126", math.Float32frombits(0x01000000), Above}, // rounded up
- {"1", 1, Exact},
- {"1.000000000000000000001", 1, Below},
- {"12345.0", 12345, Exact},
- {"12345.000000000000000000001", 12345, Below},
- {"0x1.fffffe0p127", math.MaxFloat32, Exact},
- {"0x1.fffffe8p127", math.MaxFloat32, Below},
-
- // overflow
- {"0x1.ffffff0p127", float32(math.Inf(+1)), Above},
- {"0x1p128", float32(math.Inf(+1)), Above},
- {"1e10000", float32(math.Inf(+1)), Above},
- {"0x1.ffffff0p2147483646", float32(math.Inf(+1)), Above}, // overflow in rounding
-
- // inf
- {"Inf", float32(math.Inf(+1)), Exact},
- } {
- for i := 0; i < 2; i++ {
- // test both signs
- tx, tout, tacc := test.x, test.out, test.acc
- if i != 0 {
- tx = "-" + tx
- tout = -tout
- tacc = -tacc
- }
-
- // conversion should match strconv where syntax is agreeable
- if f, err := strconv.ParseFloat(tx, 32); err == nil && !alike32(float32(f), tout) {
- t.Errorf("%s: got %g; want %g (incorrect test data)", tx, f, tout)
- }
-
- x := makeFloat(tx)
- out, acc := x.Float32()
- if !alike32(out, tout) || acc != tacc {
- t.Errorf("%s: got %g (%#08x, %s); want %g (%#08x, %s)", tx, out, math.Float32bits(out), acc, test.out, math.Float32bits(test.out), tacc)
- }
-
- // test that x.SetFloat64(float64(f)).Float32() == f
- var x2 Float
- out2, acc2 := x2.SetFloat64(float64(out)).Float32()
- if !alike32(out2, out) || acc2 != Exact {
- t.Errorf("idempotency test: got %g (%s); want %g (Exact)", out2, acc2, out)
- }
- }
- }
-}
-
-func TestFloatFloat64(t *testing.T) {
- const smallestNormalFloat64 = 2.2250738585072014e-308 // 1p-1022
- for _, test := range []struct {
- x string
- out float64
- acc Accuracy
- }{
- {"0", 0, Exact},
-
- // underflow to zero
- {"1e-1000", 0, Below},
- {"0x0.0000000000001p-1023", 0, Below},
- {"0x0.00000000000008p-1022", 0, Below},
-
- // denormals
- {"0x0.0000000000000cp-1022", math.SmallestNonzeroFloat64, Above}, // rounded up to smallest denormal
- {"0x0.00000000000010p-1022", math.SmallestNonzeroFloat64, Exact}, // smallest denormal
- {"0x.8p-1073", math.SmallestNonzeroFloat64, Exact},
- {"1p-1074", math.SmallestNonzeroFloat64, Exact},
- {"0x.fffffffffffffp-1022", math.Float64frombits(0x000fffffffffffff), Exact}, // largest denormal
-
- // special denormal cases (see issues 14553, 14651)
- {"0x0.00000000000001p-1022", math.Float64frombits(0x00000000000000000), Below}, // underflow to zero
- {"0x0.00000000000004p-1022", math.Float64frombits(0x00000000000000000), Below}, // underflow to zero
- {"0x0.00000000000008p-1022", math.Float64frombits(0x00000000000000000), Below}, // rounded down to even
- {"0x0.00000000000009p-1022", math.Float64frombits(0x00000000000000001), Above}, // rounded up to smallest denormal
- {"0x0.0000000000000ap-1022", math.Float64frombits(0x00000000000000001), Above}, // rounded up to smallest denormal
-
- {"0x0.8p-1074", math.Float64frombits(0x00000000000000000), Below}, // rounded down to even
- {"0x0.9p-1074", math.Float64frombits(0x00000000000000001), Above}, // rounded up to smallest denormal
- {"0x0.ap-1074", math.Float64frombits(0x00000000000000001), Above}, // rounded up to smallest denormal
- {"0x0.bp-1074", math.Float64frombits(0x00000000000000001), Above}, // rounded up to smallest denormal
- {"0x0.cp-1074", math.Float64frombits(0x00000000000000001), Above}, // rounded up to smallest denormal
-
- {"0x1.0p-1074", math.Float64frombits(0x00000000000000001), Exact},
- {"0x1.7p-1074", math.Float64frombits(0x00000000000000001), Below},
- {"0x1.8p-1074", math.Float64frombits(0x00000000000000002), Above},
- {"0x1.9p-1074", math.Float64frombits(0x00000000000000002), Above},
-
- {"0x2.0p-1074", math.Float64frombits(0x00000000000000002), Exact},
- {"0x2.8p-1074", math.Float64frombits(0x00000000000000002), Below}, // rounded down to even
- {"0x2.9p-1074", math.Float64frombits(0x00000000000000003), Above},
-
- {"0x3.0p-1074", math.Float64frombits(0x00000000000000003), Exact},
- {"0x3.7p-1074", math.Float64frombits(0x00000000000000003), Below},
- {"0x3.8p-1074", math.Float64frombits(0x00000000000000004), Above}, // rounded up to even
-
- {"0x4.0p-1074", math.Float64frombits(0x00000000000000004), Exact},
- {"0x4.8p-1074", math.Float64frombits(0x00000000000000004), Below}, // rounded down to even
- {"0x4.9p-1074", math.Float64frombits(0x00000000000000005), Above},
-
- // normals
- {"0x.fffffffffffff8p-1022", math.Float64frombits(0x0010000000000000), Above}, // rounded up to smallest normal
- {"1p-1022", math.Float64frombits(0x0010000000000000), Exact}, // smallest normal
- {"1", 1, Exact},
- {"1.000000000000000000001", 1, Below},
- {"12345.0", 12345, Exact},
- {"12345.000000000000000000001", 12345, Below},
- {"0x1.fffffffffffff0p1023", math.MaxFloat64, Exact},
- {"0x1.fffffffffffff4p1023", math.MaxFloat64, Below},
-
- // overflow
- {"0x1.fffffffffffff8p1023", math.Inf(+1), Above},
- {"0x1p1024", math.Inf(+1), Above},
- {"1e10000", math.Inf(+1), Above},
- {"0x1.fffffffffffff8p2147483646", math.Inf(+1), Above}, // overflow in rounding
- {"Inf", math.Inf(+1), Exact},
-
- // selected denormalized values that were handled incorrectly in the past
- {"0x.fffffffffffffp-1022", smallestNormalFloat64 - math.SmallestNonzeroFloat64, Exact},
- {"4503599627370495p-1074", smallestNormalFloat64 - math.SmallestNonzeroFloat64, Exact},
-
- // http://www.exploringbinary.com/php-hangs-on-numeric-value-2-2250738585072011e-308/
- {"2.2250738585072011e-308", 2.225073858507201e-308, Below},
- // http://www.exploringbinary.com/java-hangs-when-converting-2-2250738585072012e-308/
- {"2.2250738585072012e-308", 2.2250738585072014e-308, Above},
- } {
- for i := 0; i < 2; i++ {
- // test both signs
- tx, tout, tacc := test.x, test.out, test.acc
- if i != 0 {
- tx = "-" + tx
- tout = -tout
- tacc = -tacc
- }
-
- // conversion should match strconv where syntax is agreeable
- if f, err := strconv.ParseFloat(tx, 64); err == nil && !alike64(f, tout) {
- t.Errorf("%s: got %g; want %g (incorrect test data)", tx, f, tout)
- }
-
- x := makeFloat(tx)
- out, acc := x.Float64()
- if !alike64(out, tout) || acc != tacc {
- t.Errorf("%s: got %g (%#016x, %s); want %g (%#016x, %s)", tx, out, math.Float64bits(out), acc, test.out, math.Float64bits(test.out), tacc)
- }
-
- // test that x.SetFloat64(f).Float64() == f
- var x2 Float
- out2, acc2 := x2.SetFloat64(out).Float64()
- if !alike64(out2, out) || acc2 != Exact {
- t.Errorf("idempotency test: got %g (%s); want %g (Exact)", out2, acc2, out)
- }
- }
- }
-}
-
-func TestFloatInt(t *testing.T) {
- for _, test := range []struct {
- x string
- want string
- acc Accuracy
- }{
- {"0", "0", Exact},
- {"+0", "0", Exact},
- {"-0", "0", Exact},
- {"Inf", "nil", Below},
- {"+Inf", "nil", Below},
- {"-Inf", "nil", Above},
- {"1", "1", Exact},
- {"-1", "-1", Exact},
- {"1.23", "1", Below},
- {"-1.23", "-1", Above},
- {"123e-2", "1", Below},
- {"123e-3", "0", Below},
- {"123e-4", "0", Below},
- {"1e-1000", "0", Below},
- {"-1e-1000", "0", Above},
- {"1e+10", "10000000000", Exact},
- {"1e+100", "10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", Exact},
- } {
- x := makeFloat(test.x)
- res, acc := x.Int(nil)
- got := "nil"
- if res != nil {
- got = res.String()
- }
- if got != test.want || acc != test.acc {
- t.Errorf("%s: got %s (%s); want %s (%s)", test.x, got, acc, test.want, test.acc)
- }
- }
-
- // check that supplied *Int is used
- for _, f := range []string{"0", "1", "-1", "1234"} {
- x := makeFloat(f)
- i := new(Int)
- if res, _ := x.Int(i); res != i {
- t.Errorf("(%s).Int is not using supplied *Int", f)
- }
- }
-}
-
-func TestFloatRat(t *testing.T) {
- for _, test := range []struct {
- x, want string
- acc Accuracy
- }{
- {"0", "0/1", Exact},
- {"+0", "0/1", Exact},
- {"-0", "0/1", Exact},
- {"Inf", "nil", Below},
- {"+Inf", "nil", Below},
- {"-Inf", "nil", Above},
- {"1", "1/1", Exact},
- {"-1", "-1/1", Exact},
- {"1.25", "5/4", Exact},
- {"-1.25", "-5/4", Exact},
- {"1e10", "10000000000/1", Exact},
- {"1p10", "1024/1", Exact},
- {"-1p-10", "-1/1024", Exact},
- {"3.14159265", "7244019449799623199/2305843009213693952", Exact},
- } {
- x := makeFloat(test.x).SetPrec(64)
- res, acc := x.Rat(nil)
- got := "nil"
- if res != nil {
- got = res.String()
- }
- if got != test.want {
- t.Errorf("%s: got %s; want %s", test.x, got, test.want)
- continue
- }
- if acc != test.acc {
- t.Errorf("%s: got %s; want %s", test.x, acc, test.acc)
- continue
- }
-
- // inverse conversion
- if res != nil {
- got := new(Float).SetPrec(64).SetRat(res)
- if got.Cmp(x) != 0 {
- t.Errorf("%s: got %s; want %s", test.x, got, x)
- }
- }
- }
-
- // check that supplied *Rat is used
- for _, f := range []string{"0", "1", "-1", "1234"} {
- x := makeFloat(f)
- r := new(Rat)
- if res, _ := x.Rat(r); res != r {
- t.Errorf("(%s).Rat is not using supplied *Rat", f)
- }
- }
-}
-
-func TestFloatAbs(t *testing.T) {
- for _, test := range []string{
- "0",
- "1",
- "1234",
- "1.23e-2",
- "1e-1000",
- "1e1000",
- "Inf",
- } {
- p := makeFloat(test)
- a := new(Float).Abs(p)
- if !alike(a, p) {
- t.Errorf("%s: got %s; want %s", test, a.Text('g', 10), test)
- }
-
- n := makeFloat("-" + test)
- a.Abs(n)
- if !alike(a, p) {
- t.Errorf("-%s: got %s; want %s", test, a.Text('g', 10), test)
- }
- }
-}
-
-func TestFloatNeg(t *testing.T) {
- for _, test := range []string{
- "0",
- "1",
- "1234",
- "1.23e-2",
- "1e-1000",
- "1e1000",
- "Inf",
- } {
- p1 := makeFloat(test)
- n1 := makeFloat("-" + test)
- n2 := new(Float).Neg(p1)
- p2 := new(Float).Neg(n2)
- if !alike(n2, n1) {
- t.Errorf("%s: got %s; want %s", test, n2.Text('g', 10), n1.Text('g', 10))
- }
- if !alike(p2, p1) {
- t.Errorf("%s: got %s; want %s", test, p2.Text('g', 10), p1.Text('g', 10))
- }
- }
-}
-
-func TestFloatInc(t *testing.T) {
- const n = 10
- for _, prec := range precList {
- if 1<<prec < n {
- continue // prec must be large enough to hold all numbers from 0 to n
- }
- var x, one Float
- x.SetPrec(prec)
- one.SetInt64(1)
- for i := 0; i < n; i++ {
- x.Add(&x, &one)
- }
- if x.Cmp(new(Float).SetInt64(n)) != 0 {
- t.Errorf("prec = %d: got %s; want %d", prec, &x, n)
- }
- }
-}
-
-// Selected precisions with which to run various tests.
-var precList = [...]uint{1, 2, 5, 8, 10, 16, 23, 24, 32, 50, 53, 64, 100, 128, 500, 511, 512, 513, 1000, 10000}
-
-// Selected bits with which to run various tests.
-// Each entry is a list of bits representing a floating-point number (see fromBits).
-var bitsList = [...]Bits{
- {}, // = 0
- {0}, // = 1
- {1}, // = 2
- {-1}, // = 1/2
- {10}, // = 2**10 == 1024
- {-10}, // = 2**-10 == 1/1024
- {100, 10, 1}, // = 2**100 + 2**10 + 2**1
- {0, -1, -2, -10},
- // TODO(gri) add more test cases
-}
-
-// TestFloatAdd tests Float.Add/Sub by comparing the result of a "manual"
-// addition/subtraction of arguments represented by Bits values with the
-// respective Float addition/subtraction for a variety of precisions
-// and rounding modes.
-func TestFloatAdd(t *testing.T) {
- for _, xbits := range bitsList {
- for _, ybits := range bitsList {
- // exact values
- x := xbits.Float()
- y := ybits.Float()
- zbits := xbits.add(ybits)
- z := zbits.Float()
-
- for i, mode := range [...]RoundingMode{ToZero, ToNearestEven, AwayFromZero} {
- for _, prec := range precList {
- got := new(Float).SetPrec(prec).SetMode(mode)
- got.Add(x, y)
- want := zbits.round(prec, mode)
- if got.Cmp(want) != 0 {
- t.Errorf("i = %d, prec = %d, %s:\n\t %s %v\n\t+ %s %v\n\t= %s\n\twant %s",
- i, prec, mode, x, xbits, y, ybits, got, want)
- }
-
- got.Sub(z, x)
- want = ybits.round(prec, mode)
- if got.Cmp(want) != 0 {
- t.Errorf("i = %d, prec = %d, %s:\n\t %s %v\n\t- %s %v\n\t= %s\n\twant %s",
- i, prec, mode, z, zbits, x, xbits, got, want)
- }
- }
- }
- }
- }
-}
-
-// TestFloatAdd32 tests that Float.Add/Sub of numbers with
-// 24bit mantissa behaves like float32 addition/subtraction
-// (excluding denormal numbers).
-func TestFloatAdd32(t *testing.T) {
- // chose base such that we cross the mantissa precision limit
- const base = 1<<26 - 0x10 // 11...110000 (26 bits)
- for d := 0; d <= 0x10; d++ {
- for i := range [2]int{} {
- x0, y0 := float64(base), float64(d)
- if i&1 != 0 {
- x0, y0 = y0, x0
- }
-
- x := NewFloat(x0)
- y := NewFloat(y0)
- z := new(Float).SetPrec(24)
-
- z.Add(x, y)
- got, acc := z.Float32()
- want := float32(y0) + float32(x0)
- if got != want || acc != Exact {
- t.Errorf("d = %d: %g + %g = %g (%s); want %g (Exact)", d, x0, y0, got, acc, want)
- }
-
- z.Sub(z, y)
- got, acc = z.Float32()
- want = float32(want) - float32(y0)
- if got != want || acc != Exact {
- t.Errorf("d = %d: %g - %g = %g (%s); want %g (Exact)", d, x0+y0, y0, got, acc, want)
- }
- }
- }
-}
-
-// TestFloatAdd64 tests that Float.Add/Sub of numbers with
-// 53bit mantissa behaves like float64 addition/subtraction.
-func TestFloatAdd64(t *testing.T) {
- // chose base such that we cross the mantissa precision limit
- const base = 1<<55 - 0x10 // 11...110000 (55 bits)
- for d := 0; d <= 0x10; d++ {
- for i := range [2]int{} {
- x0, y0 := float64(base), float64(d)
- if i&1 != 0 {
- x0, y0 = y0, x0
- }
-
- x := NewFloat(x0)
- y := NewFloat(y0)
- z := new(Float).SetPrec(53)
-
- z.Add(x, y)
- got, acc := z.Float64()
- want := x0 + y0
- if got != want || acc != Exact {
- t.Errorf("d = %d: %g + %g = %g (%s); want %g (Exact)", d, x0, y0, got, acc, want)
- }
-
- z.Sub(z, y)
- got, acc = z.Float64()
- want -= y0
- if got != want || acc != Exact {
- t.Errorf("d = %d: %g - %g = %g (%s); want %g (Exact)", d, x0+y0, y0, got, acc, want)
- }
- }
- }
-}
-
-// TestFloatMul tests Float.Mul/Quo by comparing the result of a "manual"
-// multiplication/division of arguments represented by Bits values with the
-// respective Float multiplication/division for a variety of precisions
-// and rounding modes.
-func TestFloatMul(t *testing.T) {
- for _, xbits := range bitsList {
- for _, ybits := range bitsList {
- // exact values
- x := xbits.Float()
- y := ybits.Float()
- zbits := xbits.mul(ybits)
- z := zbits.Float()
-
- for i, mode := range [...]RoundingMode{ToZero, ToNearestEven, AwayFromZero} {
- for _, prec := range precList {
- got := new(Float).SetPrec(prec).SetMode(mode)
- got.Mul(x, y)
- want := zbits.round(prec, mode)
- if got.Cmp(want) != 0 {
- t.Errorf("i = %d, prec = %d, %s:\n\t %s %v\n\t* %s %v\n\t= %s\n\twant %s",
- i, prec, mode, x, xbits, y, ybits, got, want)
- }
-
- if x.Sign() == 0 {
- continue // ignore div-0 case (not invertable)
- }
- got.Quo(z, x)
- want = ybits.round(prec, mode)
- if got.Cmp(want) != 0 {
- t.Errorf("i = %d, prec = %d, %s:\n\t %s %v\n\t/ %s %v\n\t= %s\n\twant %s",
- i, prec, mode, z, zbits, x, xbits, got, want)
- }
- }
- }
- }
- }
-}
-
-// TestFloatMul64 tests that Float.Mul/Quo of numbers with
-// 53bit mantissa behaves like float64 multiplication/division.
-func TestFloatMul64(t *testing.T) {
- for _, test := range []struct {
- x, y float64
- }{
- {0, 0},
- {0, 1},
- {1, 1},
- {1, 1.5},
- {1.234, 0.5678},
- {2.718281828, 3.14159265358979},
- {2.718281828e10, 3.14159265358979e-32},
- {1.0 / 3, 1e200},
- } {
- for i := range [8]int{} {
- x0, y0 := test.x, test.y
- if i&1 != 0 {
- x0 = -x0
- }
- if i&2 != 0 {
- y0 = -y0
- }
- if i&4 != 0 {
- x0, y0 = y0, x0
- }
-
- x := NewFloat(x0)
- y := NewFloat(y0)
- z := new(Float).SetPrec(53)
-
- z.Mul(x, y)
- got, _ := z.Float64()
- want := x0 * y0
- if got != want {
- t.Errorf("%g * %g = %g; want %g", x0, y0, got, want)
- }
-
- if y0 == 0 {
- continue // avoid division-by-zero
- }
- z.Quo(z, y)
- got, _ = z.Float64()
- want /= y0
- if got != want {
- t.Errorf("%g / %g = %g; want %g", x0*y0, y0, got, want)
- }
- }
- }
-}
-
-func TestIssue6866(t *testing.T) {
- for _, prec := range precList {
- two := new(Float).SetPrec(prec).SetInt64(2)
- one := new(Float).SetPrec(prec).SetInt64(1)
- three := new(Float).SetPrec(prec).SetInt64(3)
- msix := new(Float).SetPrec(prec).SetInt64(-6)
- psix := new(Float).SetPrec(prec).SetInt64(+6)
-
- p := new(Float).SetPrec(prec)
- z1 := new(Float).SetPrec(prec)
- z2 := new(Float).SetPrec(prec)
-
- // z1 = 2 + 1.0/3*-6
- p.Quo(one, three)
- p.Mul(p, msix)
- z1.Add(two, p)
-
- // z2 = 2 - 1.0/3*+6
- p.Quo(one, three)
- p.Mul(p, psix)
- z2.Sub(two, p)
-
- if z1.Cmp(z2) != 0 {
- t.Fatalf("prec %d: got z1 = %s != z2 = %s; want z1 == z2\n", prec, z1, z2)
- }
- if z1.Sign() != 0 {
- t.Errorf("prec %d: got z1 = %s; want 0", prec, z1)
- }
- if z2.Sign() != 0 {
- t.Errorf("prec %d: got z2 = %s; want 0", prec, z2)
- }
- }
-}
-
-func TestFloatQuo(t *testing.T) {
- // TODO(gri) make the test vary these precisions
- preci := 200 // precision of integer part
- precf := 20 // precision of fractional part
-
- for i := 0; i < 8; i++ {
- // compute accurate (not rounded) result z
- bits := Bits{preci - 1}
- if i&3 != 0 {
- bits = append(bits, 0)
- }
- if i&2 != 0 {
- bits = append(bits, -1)
- }
- if i&1 != 0 {
- bits = append(bits, -precf)
- }
- z := bits.Float()
-
- // compute accurate x as z*y
- y := NewFloat(3.14159265358979323e123)
-
- x := new(Float).SetPrec(z.Prec() + y.Prec()).SetMode(ToZero)
- x.Mul(z, y)
-
- // leave for debugging
- // fmt.Printf("x = %s\ny = %s\nz = %s\n", x, y, z)
-
- if got := x.Acc(); got != Exact {
- t.Errorf("got acc = %s; want exact", got)
- }
-
- // round accurate z for a variety of precisions and
- // modes and compare against result of x / y.
- for _, mode := range [...]RoundingMode{ToZero, ToNearestEven, AwayFromZero} {
- for d := -5; d < 5; d++ {
- prec := uint(preci + d)
- got := new(Float).SetPrec(prec).SetMode(mode).Quo(x, y)
- want := bits.round(prec, mode)
- if got.Cmp(want) != 0 {
- t.Errorf("i = %d, prec = %d, %s:\n\t %s\n\t/ %s\n\t= %s\n\twant %s",
- i, prec, mode, x, y, got, want)
- }
- }
- }
- }
-}
-
-// TestFloatQuoSmoke tests all divisions x/y for values x, y in the range [-n, +n];
-// it serves as a smoke test for basic correctness of division.
-func TestFloatQuoSmoke(t *testing.T) {
- n := 1000
- if testing.Short() {
- n = 10
- }
-
- const dprec = 3 // max. precision variation
- const prec = 10 + dprec // enough bits to hold n precisely
- for x := -n; x <= n; x++ {
- for y := -n; y < n; y++ {
- if y == 0 {
- continue
- }
-
- a := float64(x)
- b := float64(y)
- c := a / b
-
- // vary operand precision (only ok as long as a, b can be represented correctly)
- for ad := -dprec; ad <= dprec; ad++ {
- for bd := -dprec; bd <= dprec; bd++ {
- A := new(Float).SetPrec(uint(prec + ad)).SetFloat64(a)
- B := new(Float).SetPrec(uint(prec + bd)).SetFloat64(b)
- C := new(Float).SetPrec(53).Quo(A, B) // C has float64 mantissa width
-
- cc, acc := C.Float64()
- if cc != c {
- t.Errorf("%g/%g = %s; want %.5g\n", a, b, C.Text('g', 5), c)
- continue
- }
- if acc != Exact {
- t.Errorf("%g/%g got %s result; want exact result", a, b, acc)
- }
- }
- }
- }
- }
-}
-
-// TestFloatArithmeticSpecialValues tests that Float operations produce the
-// correct results for combinations of zero (±0), finite (±1 and ±2.71828),
-// and infinite (±Inf) operands.
-func TestFloatArithmeticSpecialValues(t *testing.T) {
- zero := 0.0
- args := []float64{math.Inf(-1), -2.71828, -1, -zero, zero, 1, 2.71828, math.Inf(1)}
- xx := new(Float)
- yy := new(Float)
- got := new(Float)
- want := new(Float)
- for i := 0; i < 4; i++ {
- for _, x := range args {
- xx.SetFloat64(x)
- // check conversion is correct
- // (no need to do this for y, since we see exactly the
- // same values there)
- if got, acc := xx.Float64(); got != x || acc != Exact {
- t.Errorf("Float(%g) == %g (%s)", x, got, acc)
- }
- for _, y := range args {
- yy.SetFloat64(y)
- var (
- op string
- z float64
- f func(z, x, y *Float) *Float
- )
- switch i {
- case 0:
- op = "+"
- z = x + y
- f = (*Float).Add
- case 1:
- op = "-"
- z = x - y
- f = (*Float).Sub
- case 2:
- op = "*"
- z = x * y
- f = (*Float).Mul
- case 3:
- op = "/"
- z = x / y
- f = (*Float).Quo
- default:
- panic("unreachable")
- }
- var errnan bool // set if execution of f panicked with ErrNaN
- // protect execution of f
- func() {
- defer func() {
- if p := recover(); p != nil {
- _ = p.(ErrNaN) // re-panic if not ErrNaN
- errnan = true
- }
- }()
- f(got, xx, yy)
- }()
- if math.IsNaN(z) {
- if !errnan {
- t.Errorf("%5g %s %5g = %5s; want ErrNaN panic", x, op, y, got)
- }
- continue
- }
- if errnan {
- t.Errorf("%5g %s %5g panicked with ErrNan; want %5s", x, op, y, want)
- continue
- }
- want.SetFloat64(z)
- if !alike(got, want) {
- t.Errorf("%5g %s %5g = %5s; want %5s", x, op, y, got, want)
- }
- }
- }
- }
-}
-
-func TestFloatArithmeticOverflow(t *testing.T) {
- for _, test := range []struct {
- prec uint
- mode RoundingMode
- op byte
- x, y, want string
- acc Accuracy
- }{
- {4, ToNearestEven, '+', "0", "0", "0", Exact}, // smoke test
- {4, ToNearestEven, '+', "0x.8p+0", "0x.8p+0", "0x.8p+1", Exact}, // smoke test
-
- {4, ToNearestEven, '+', "0", "0x.8p2147483647", "0x.8p+2147483647", Exact},
- {4, ToNearestEven, '+', "0x.8p2147483500", "0x.8p2147483647", "0x.8p+2147483647", Below}, // rounded to zero
- {4, ToNearestEven, '+', "0x.8p2147483647", "0x.8p2147483647", "+Inf", Above}, // exponent overflow in +
- {4, ToNearestEven, '+', "-0x.8p2147483647", "-0x.8p2147483647", "-Inf", Below}, // exponent overflow in +
- {4, ToNearestEven, '-', "-0x.8p2147483647", "0x.8p2147483647", "-Inf", Below}, // exponent overflow in -
-
- {4, ToZero, '+', "0x.fp2147483647", "0x.8p2147483643", "0x.fp+2147483647", Below}, // rounded to zero
- {4, ToNearestEven, '+', "0x.fp2147483647", "0x.8p2147483643", "+Inf", Above}, // exponent overflow in rounding
- {4, AwayFromZero, '+', "0x.fp2147483647", "0x.8p2147483643", "+Inf", Above}, // exponent overflow in rounding
-
- {4, AwayFromZero, '-', "-0x.fp2147483647", "0x.8p2147483644", "-Inf", Below}, // exponent overflow in rounding
- {4, ToNearestEven, '-', "-0x.fp2147483647", "0x.8p2147483643", "-Inf", Below}, // exponent overflow in rounding
- {4, ToZero, '-', "-0x.fp2147483647", "0x.8p2147483643", "-0x.fp+2147483647", Above}, // rounded to zero
-
- {4, ToNearestEven, '+', "0", "0x.8p-2147483648", "0x.8p-2147483648", Exact},
- {4, ToNearestEven, '+', "0x.8p-2147483648", "0x.8p-2147483648", "0x.8p-2147483647", Exact},
-
- {4, ToNearestEven, '*', "1", "0x.8p2147483647", "0x.8p+2147483647", Exact},
- {4, ToNearestEven, '*', "2", "0x.8p2147483647", "+Inf", Above}, // exponent overflow in *
- {4, ToNearestEven, '*', "-2", "0x.8p2147483647", "-Inf", Below}, // exponent overflow in *
-
- {4, ToNearestEven, '/', "0.5", "0x.8p2147483647", "0x.8p-2147483646", Exact},
- {4, ToNearestEven, '/', "0x.8p+0", "0x.8p2147483647", "0x.8p-2147483646", Exact},
- {4, ToNearestEven, '/', "0x.8p-1", "0x.8p2147483647", "0x.8p-2147483647", Exact},
- {4, ToNearestEven, '/', "0x.8p-2", "0x.8p2147483647", "0x.8p-2147483648", Exact},
- {4, ToNearestEven, '/', "0x.8p-3", "0x.8p2147483647", "0", Below}, // exponent underflow in /
- } {
- x := makeFloat(test.x)
- y := makeFloat(test.y)
- z := new(Float).SetPrec(test.prec).SetMode(test.mode)
- switch test.op {
- case '+':
- z.Add(x, y)
- case '-':
- z.Sub(x, y)
- case '*':
- z.Mul(x, y)
- case '/':
- z.Quo(x, y)
- default:
- panic("unreachable")
- }
- if got := z.Text('p', 0); got != test.want || z.Acc() != test.acc {
- t.Errorf(
- "prec = %d (%s): %s %c %s = %s (%s); want %s (%s)",
- test.prec, test.mode, x.Text('p', 0), test.op, y.Text('p', 0), got, z.Acc(), test.want, test.acc,
- )
- }
- }
-}
-
-// TODO(gri) Add tests that check correctness in the presence of aliasing.
-
-// For rounding modes ToNegativeInf and ToPositiveInf, rounding is affected
-// by the sign of the value to be rounded. Test that rounding happens after
-// the sign of a result has been set.
-// This test uses specific values that are known to fail if rounding is
-// "factored" out before setting the result sign.
-func TestFloatArithmeticRounding(t *testing.T) {
- for _, test := range []struct {
- mode RoundingMode
- prec uint
- x, y, want int64
- op byte
- }{
- {ToZero, 3, -0x8, -0x1, -0x8, '+'},
- {AwayFromZero, 3, -0x8, -0x1, -0xa, '+'},
- {ToNegativeInf, 3, -0x8, -0x1, -0xa, '+'},
-
- {ToZero, 3, -0x8, 0x1, -0x8, '-'},
- {AwayFromZero, 3, -0x8, 0x1, -0xa, '-'},
- {ToNegativeInf, 3, -0x8, 0x1, -0xa, '-'},
-
- {ToZero, 3, -0x9, 0x1, -0x8, '*'},
- {AwayFromZero, 3, -0x9, 0x1, -0xa, '*'},
- {ToNegativeInf, 3, -0x9, 0x1, -0xa, '*'},
-
- {ToZero, 3, -0x9, 0x1, -0x8, '/'},
- {AwayFromZero, 3, -0x9, 0x1, -0xa, '/'},
- {ToNegativeInf, 3, -0x9, 0x1, -0xa, '/'},
- } {
- var x, y, z Float
- x.SetInt64(test.x)
- y.SetInt64(test.y)
- z.SetPrec(test.prec).SetMode(test.mode)
- switch test.op {
- case '+':
- z.Add(&x, &y)
- case '-':
- z.Sub(&x, &y)
- case '*':
- z.Mul(&x, &y)
- case '/':
- z.Quo(&x, &y)
- default:
- panic("unreachable")
- }
- if got, acc := z.Int64(); got != test.want || acc != Exact {
- t.Errorf("%s, %d bits: %d %c %d = %d (%s); want %d (Exact)",
- test.mode, test.prec, test.x, test.op, test.y, got, acc, test.want,
- )
- }
- }
-}
-
-// TestFloatCmpSpecialValues tests that Cmp produces the correct results for
-// combinations of zero (±0), finite (±1 and ±2.71828), and infinite (±Inf)
-// operands.
-func TestFloatCmpSpecialValues(t *testing.T) {
- zero := 0.0
- args := []float64{math.Inf(-1), -2.71828, -1, -zero, zero, 1, 2.71828, math.Inf(1)}
- xx := new(Float)
- yy := new(Float)
- for i := 0; i < 4; i++ {
- for _, x := range args {
- xx.SetFloat64(x)
- // check conversion is correct
- // (no need to do this for y, since we see exactly the
- // same values there)
- if got, acc := xx.Float64(); got != x || acc != Exact {
- t.Errorf("Float(%g) == %g (%s)", x, got, acc)
- }
- for _, y := range args {
- yy.SetFloat64(y)
- got := xx.Cmp(yy)
- want := 0
- switch {
- case x < y:
- want = -1
- case x > y:
- want = +1
- }
- if got != want {
- t.Errorf("(%g).Cmp(%g) = %v; want %v", x, y, got, want)
- }
- }
- }
- }
-}
diff --git a/src/cmd/compile/internal/big/floatconv.go b/src/cmd/compile/internal/big/floatconv.go
deleted file mode 100644
index a884df6..0000000
--- a/src/cmd/compile/internal/big/floatconv.go
+++ /dev/null
@@ -1,275 +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 implements string-to-Float conversion functions.
-
-package big
-
-import (
- "fmt"
- "io"
- "strings"
-)
-
-// SetString sets z to the value of s and returns z and a boolean indicating
-// success. s must be a floating-point number of the same format as accepted
-// by Parse, with base argument 0.
-func (z *Float) SetString(s string) (*Float, bool) {
- if f, _, err := z.Parse(s, 0); err == nil {
- return f, true
- }
- return nil, false
-}
-
-// scan is like Parse but reads the longest possible prefix representing a valid
-// floating point number from an io.ByteScanner rather than a string. It serves
-// as the implementation of Parse. It does not recognize ±Inf and does not expect
-// EOF at the end.
-func (z *Float) scan(r io.ByteScanner, base int) (f *Float, b int, err error) {
- prec := z.prec
- if prec == 0 {
- prec = 64
- }
-
- // A reasonable value in case of an error.
- z.form = zero
-
- // sign
- z.neg, err = scanSign(r)
- if err != nil {
- return
- }
-
- // mantissa
- var fcount int // fractional digit count; valid if <= 0
- z.mant, b, fcount, err = z.mant.scan(r, base, true)
- if err != nil {
- return
- }
-
- // exponent
- var exp int64
- var ebase int
- exp, ebase, err = scanExponent(r, true)
- if err != nil {
- return
- }
-
- // special-case 0
- if len(z.mant) == 0 {
- z.prec = prec
- z.acc = Exact
- z.form = zero
- f = z
- return
- }
- // len(z.mant) > 0
-
- // The mantissa may have a decimal point (fcount <= 0) and there
- // may be a nonzero exponent exp. The decimal point amounts to a
- // division by b**(-fcount). An exponent means multiplication by
- // ebase**exp. Finally, mantissa normalization (shift left) requires
- // a correcting multiplication by 2**(-shiftcount). Multiplications
- // are commutative, so we can apply them in any order as long as there
- // is no loss of precision. We only have powers of 2 and 10, and
- // we split powers of 10 into the product of the same powers of
- // 2 and 5. This reduces the size of the multiplication factor
- // needed for base-10 exponents.
-
- // normalize mantissa and determine initial exponent contributions
- exp2 := int64(len(z.mant))*_W - fnorm(z.mant)
- exp5 := int64(0)
-
- // determine binary or decimal exponent contribution of decimal point
- if fcount < 0 {
- // The mantissa has a "decimal" point ddd.dddd; and
- // -fcount is the number of digits to the right of '.'.
- // Adjust relevant exponent accordingly.
- d := int64(fcount)
- switch b {
- case 10:
- exp5 = d
- fallthrough // 10**e == 5**e * 2**e
- case 2:
- exp2 += d
- case 16:
- exp2 += d * 4 // hexadecimal digits are 4 bits each
- default:
- panic("unexpected mantissa base")
- }
- // fcount consumed - not needed anymore
- }
-
- // take actual exponent into account
- switch ebase {
- case 10:
- exp5 += exp
- fallthrough
- case 2:
- exp2 += exp
- default:
- panic("unexpected exponent base")
- }
- // exp consumed - not needed anymore
-
- // apply 2**exp2
- if MinExp <= exp2 && exp2 <= MaxExp {
- z.prec = prec
- z.form = finite
- z.exp = int32(exp2)
- f = z
- } else {
- err = fmt.Errorf("exponent overflow")
- return
- }
-
- if exp5 == 0 {
- // no decimal exponent contribution
- z.round(0)
- return
- }
- // exp5 != 0
-
- // apply 5**exp5
- p := new(Float).SetPrec(z.Prec() + 64) // use more bits for p -- TODO(gri) what is the right number?
- if exp5 < 0 {
- z.Quo(z, p.pow5(uint64(-exp5)))
- } else {
- z.Mul(z, p.pow5(uint64(exp5)))
- }
-
- return
-}
-
-// These powers of 5 fit into a uint64.
-//
-// for p, q := uint64(0), uint64(1); p < q; p, q = q, q*5 {
-// fmt.Println(q)
-// }
-//
-var pow5tab = [...]uint64{
- 1,
- 5,
- 25,
- 125,
- 625,
- 3125,
- 15625,
- 78125,
- 390625,
- 1953125,
- 9765625,
- 48828125,
- 244140625,
- 1220703125,
- 6103515625,
- 30517578125,
- 152587890625,
- 762939453125,
- 3814697265625,
- 19073486328125,
- 95367431640625,
- 476837158203125,
- 2384185791015625,
- 11920928955078125,
- 59604644775390625,
- 298023223876953125,
- 1490116119384765625,
- 7450580596923828125,
-}
-
-// pow5 sets z to 5**n and returns z.
-// n must not be negative.
-func (z *Float) pow5(n uint64) *Float {
- const m = uint64(len(pow5tab) - 1)
- if n <= m {
- return z.SetUint64(pow5tab[n])
- }
- // n > m
-
- z.SetUint64(pow5tab[m])
- n -= m
-
- // use more bits for f than for z
- // TODO(gri) what is the right number?
- f := new(Float).SetPrec(z.Prec() + 64).SetUint64(5)
-
- for n > 0 {
- if n&1 != 0 {
- z.Mul(z, f)
- }
- f.Mul(f, f)
- n >>= 1
- }
-
- return z
-}
-
-// Parse parses s which must contain a text representation of a floating-
-// point number with a mantissa in the given conversion base (the exponent
-// is always a decimal number), or a string representing an infinite value.
-//
-// It sets z to the (possibly rounded) value of the corresponding floating-
-// point value, and returns z, the actual base b, and an error err, if any.
-// If z's precision is 0, it is changed to 64 before rounding takes effect.
-// The number must be of the form:
-//
-// number = [ sign ] [ prefix ] mantissa [ exponent ] | infinity .
-// sign = "+" | "-" .
-// prefix = "0" ( "x" | "X" | "b" | "B" ) .
-// mantissa = digits | digits "." [ digits ] | "." digits .
-// exponent = ( "E" | "e" | "p" ) [ sign ] digits .
-// digits = digit { digit } .
-// digit = "0" ... "9" | "a" ... "z" | "A" ... "Z" .
-// infinity = [ sign ] ( "inf" | "Inf" ) .
-//
-// The base argument must be 0, 2, 10, or 16. Providing an invalid base
-// argument will lead to a run-time panic.
-//
-// For base 0, the number prefix determines the actual base: A prefix of
-// "0x" or "0X" selects base 16, and a "0b" or "0B" prefix selects
-// base 2; otherwise, the actual base is 10 and no prefix is accepted.
-// The octal prefix "0" is not supported (a leading "0" is simply
-// considered a "0").
-//
-// A "p" exponent indicates a binary (rather then decimal) exponent;
-// for instance "0x1.fffffffffffffp1023" (using base 0) represents the
-// maximum float64 value. For hexadecimal mantissae, the exponent must
-// be binary, if present (an "e" or "E" exponent indicator cannot be
-// distinguished from a mantissa digit).
-//
-// The returned *Float f is nil and the value of z is valid but not
-// defined if an error is reported.
-//
-func (z *Float) Parse(s string, base int) (f *Float, b int, err error) {
- // scan doesn't handle ±Inf
- if len(s) == 3 && (s == "Inf" || s == "inf") {
- f = z.SetInf(false)
- return
- }
- if len(s) == 4 && (s[0] == '+' || s[0] == '-') && (s[1:] == "Inf" || s[1:] == "inf") {
- f = z.SetInf(s[0] == '-')
- return
- }
-
- r := strings.NewReader(s)
- if f, b, err = z.scan(r, base); err != nil {
- return
- }
-
- // entire string must have been consumed
- if ch, err2 := r.ReadByte(); err2 == nil {
- err = fmt.Errorf("expected end of string, found %q", ch)
- } else if err2 != io.EOF {
- err = err2
- }
-
- return
-}
-
-// ParseFloat is like f.Parse(s, base) with f set to the given precision
-// and rounding mode.
-func ParseFloat(s string, base int, prec uint, mode RoundingMode) (f *Float, b int, err error) {
- return new(Float).SetPrec(prec).SetMode(mode).Parse(s, base)
-}
diff --git a/src/cmd/compile/internal/big/floatconv_test.go b/src/cmd/compile/internal/big/floatconv_test.go
deleted file mode 100644
index b6f9993..0000000
--- a/src/cmd/compile/internal/big/floatconv_test.go
+++ /dev/null
@@ -1,662 +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 big
-
-import (
- "fmt"
- "math"
- "strconv"
- "testing"
-)
-
-func TestFloatSetFloat64String(t *testing.T) {
- inf := math.Inf(0)
- nan := math.NaN()
-
- for _, test := range []struct {
- s string
- x float64 // NaNs represent invalid inputs
- }{
- // basics
- {"0", 0},
- {"-0", -0},
- {"+0", 0},
- {"1", 1},
- {"-1", -1},
- {"+1", 1},
- {"1.234", 1.234},
- {"-1.234", -1.234},
- {"+1.234", 1.234},
- {".1", 0.1},
- {"1.", 1},
- {"+1.", 1},
-
- // various zeros
- {"0e100", 0},
- {"-0e+100", 0},
- {"+0e-100", 0},
- {"0E100", 0},
- {"-0E+100", 0},
- {"+0E-100", 0},
-
- // various decimal exponent formats
- {"1.e10", 1e10},
- {"1e+10", 1e10},
- {"+1e-10", 1e-10},
- {"1E10", 1e10},
- {"1.E+10", 1e10},
- {"+1E-10", 1e-10},
-
- // infinities
- {"Inf", inf},
- {"+Inf", inf},
- {"-Inf", -inf},
- {"inf", inf},
- {"+inf", inf},
- {"-inf", -inf},
-
- // invalid numbers
- {"", nan},
- {"-", nan},
- {"0x", nan},
- {"0e", nan},
- {"1.2ef", nan},
- {"2..3", nan},
- {"123..", nan},
- {"infinity", nan},
- {"foobar", nan},
-
- // misc decimal values
- {"3.14159265", 3.14159265},
- {"-687436.79457e-245", -687436.79457e-245},
- {"-687436.79457E245", -687436.79457e245},
- {".0000000000000000000000000000000000000001", 1e-40},
- {"+10000000000000000000000000000000000000000e-0", 1e40},
-
- // decimal mantissa, binary exponent
- {"0p0", 0},
- {"-0p0", -0},
- {"1p10", 1 << 10},
- {"1p+10", 1 << 10},
- {"+1p-10", 1.0 / (1 << 10)},
- {"1024p-12", 0.25},
- {"-1p10", -1024},
- {"1.5p1", 3},
-
- // binary mantissa, decimal exponent
- {"0b0", 0},
- {"-0b0", -0},
- {"0b0e+10", 0},
- {"-0b0e-10", -0},
- {"0b1010", 10},
- {"0B1010E2", 1000},
- {"0b.1", 0.5},
- {"0b.001", 0.125},
- {"0b.001e3", 125},
-
- // binary mantissa, binary exponent
- {"0b0p+10", 0},
- {"-0b0p-10", -0},
- {"0b.1010p4", 10},
- {"0b1p-1", 0.5},
- {"0b001p-3", 0.125},
- {"0b.001p3", 1},
- {"0b0.01p2", 1},
-
- // hexadecimal mantissa and exponent
- {"0x0", 0},
- {"-0x0", -0},
- {"0x0p+10", 0},
- {"-0x0p-10", -0},
- {"0xff", 255},
- {"0X.8p1", 1},
- {"-0X0.00008p16", -0.5},
- {"0x0.0000000000001p-1022", math.SmallestNonzeroFloat64},
- {"0x1.fffffffffffffp1023", math.MaxFloat64},
- } {
- var x Float
- x.SetPrec(53)
- _, ok := x.SetString(test.s)
- if math.IsNaN(test.x) {
- // test.s is invalid
- if ok {
- t.Errorf("%s: want parse error", test.s)
- }
- continue
- }
- // test.s is valid
- if !ok {
- t.Errorf("%s: got parse error", test.s)
- continue
- }
- f, _ := x.Float64()
- want := new(Float).SetFloat64(test.x)
- if x.Cmp(want) != 0 {
- t.Errorf("%s: got %s (%v); want %v", test.s, &x, f, test.x)
- }
- }
-}
-
-func fdiv(a, b float64) float64 { return a / b }
-
-const (
- below1e23 = 99999999999999974834176
- above1e23 = 100000000000000008388608
-)
-
-func TestFloat64Text(t *testing.T) {
- for _, test := range []struct {
- x float64
- format byte
- prec int
- want string
- }{
- {0, 'f', 0, "0"},
- {math.Copysign(0, -1), 'f', 0, "-0"},
- {1, 'f', 0, "1"},
- {-1, 'f', 0, "-1"},
-
- {0.001, 'e', 0, "1e-03"},
- {0.459, 'e', 0, "5e-01"},
- {1.459, 'e', 0, "1e+00"},
- {2.459, 'e', 1, "2.5e+00"},
- {3.459, 'e', 2, "3.46e+00"},
- {4.459, 'e', 3, "4.459e+00"},
- {5.459, 'e', 4, "5.4590e+00"},
-
- {0.001, 'f', 0, "0"},
- {0.459, 'f', 0, "0"},
- {1.459, 'f', 0, "1"},
- {2.459, 'f', 1, "2.5"},
- {3.459, 'f', 2, "3.46"},
- {4.459, 'f', 3, "4.459"},
- {5.459, 'f', 4, "5.4590"},
-
- {0, 'b', 0, "0"},
- {math.Copysign(0, -1), 'b', 0, "-0"},
- {1.0, 'b', 0, "4503599627370496p-52"},
- {-1.0, 'b', 0, "-4503599627370496p-52"},
- {4503599627370496, 'b', 0, "4503599627370496p+0"},
-
- {0, 'p', 0, "0"},
- {math.Copysign(0, -1), 'p', 0, "-0"},
- {1024.0, 'p', 0, "0x.8p+11"},
- {-1024.0, 'p', 0, "-0x.8p+11"},
-
- // all test cases below from strconv/ftoa_test.go
- {1, 'e', 5, "1.00000e+00"},
- {1, 'f', 5, "1.00000"},
- {1, 'g', 5, "1"},
- {1, 'g', -1, "1"},
- {20, 'g', -1, "20"},
- {1234567.8, 'g', -1, "1.2345678e+06"},
- {200000, 'g', -1, "200000"},
- {2000000, 'g', -1, "2e+06"},
-
- // g conversion and zero suppression
- {400, 'g', 2, "4e+02"},
- {40, 'g', 2, "40"},
- {4, 'g', 2, "4"},
- {.4, 'g', 2, "0.4"},
- {.04, 'g', 2, "0.04"},
- {.004, 'g', 2, "0.004"},
- {.0004, 'g', 2, "0.0004"},
- {.00004, 'g', 2, "4e-05"},
- {.000004, 'g', 2, "4e-06"},
-
- {0, 'e', 5, "0.00000e+00"},
- {0, 'f', 5, "0.00000"},
- {0, 'g', 5, "0"},
- {0, 'g', -1, "0"},
-
- {-1, 'e', 5, "-1.00000e+00"},
- {-1, 'f', 5, "-1.00000"},
- {-1, 'g', 5, "-1"},
- {-1, 'g', -1, "-1"},
-
- {12, 'e', 5, "1.20000e+01"},
- {12, 'f', 5, "12.00000"},
- {12, 'g', 5, "12"},
- {12, 'g', -1, "12"},
-
- {123456700, 'e', 5, "1.23457e+08"},
- {123456700, 'f', 5, "123456700.00000"},
- {123456700, 'g', 5, "1.2346e+08"},
- {123456700, 'g', -1, "1.234567e+08"},
-
- {1.2345e6, 'e', 5, "1.23450e+06"},
- {1.2345e6, 'f', 5, "1234500.00000"},
- {1.2345e6, 'g', 5, "1.2345e+06"},
-
- {1e23, 'e', 17, "9.99999999999999916e+22"},
- {1e23, 'f', 17, "99999999999999991611392.00000000000000000"},
- {1e23, 'g', 17, "9.9999999999999992e+22"},
-
- {1e23, 'e', -1, "1e+23"},
- {1e23, 'f', -1, "100000000000000000000000"},
- {1e23, 'g', -1, "1e+23"},
-
- {below1e23, 'e', 17, "9.99999999999999748e+22"},
- {below1e23, 'f', 17, "99999999999999974834176.00000000000000000"},
- {below1e23, 'g', 17, "9.9999999999999975e+22"},
-
- {below1e23, 'e', -1, "9.999999999999997e+22"},
- {below1e23, 'f', -1, "99999999999999970000000"},
- {below1e23, 'g', -1, "9.999999999999997e+22"},
-
- {above1e23, 'e', 17, "1.00000000000000008e+23"},
- {above1e23, 'f', 17, "100000000000000008388608.00000000000000000"},
- {above1e23, 'g', 17, "1.0000000000000001e+23"},
-
- {above1e23, 'e', -1, "1.0000000000000001e+23"},
- {above1e23, 'f', -1, "100000000000000010000000"},
- {above1e23, 'g', -1, "1.0000000000000001e+23"},
-
- {5e-304 / 1e20, 'g', -1, "5e-324"},
- {-5e-304 / 1e20, 'g', -1, "-5e-324"},
- {fdiv(5e-304, 1e20), 'g', -1, "5e-324"}, // avoid constant arithmetic
- {fdiv(-5e-304, 1e20), 'g', -1, "-5e-324"}, // avoid constant arithmetic
-
- {32, 'g', -1, "32"},
- {32, 'g', 0, "3e+01"},
-
- {100, 'x', -1, "%x"},
-
- // {math.NaN(), 'g', -1, "NaN"}, // Float doesn't support NaNs
- // {-math.NaN(), 'g', -1, "NaN"}, // Float doesn't support NaNs
- {math.Inf(0), 'g', -1, "+Inf"},
- {math.Inf(-1), 'g', -1, "-Inf"},
- {-math.Inf(0), 'g', -1, "-Inf"},
-
- {-1, 'b', -1, "-4503599627370496p-52"},
-
- // fixed bugs
- {0.9, 'f', 1, "0.9"},
- {0.09, 'f', 1, "0.1"},
- {0.0999, 'f', 1, "0.1"},
- {0.05, 'f', 1, "0.1"},
- {0.05, 'f', 0, "0"},
- {0.5, 'f', 1, "0.5"},
- {0.5, 'f', 0, "0"},
- {1.5, 'f', 0, "2"},
-
- // http://www.exploringbinary.com/java-hangs-when-converting-2-2250738585072012e-308/
- {2.2250738585072012e-308, 'g', -1, "2.2250738585072014e-308"},
- // http://www.exploringbinary.com/php-hangs-on-numeric-value-2-2250738585072011e-308/
- {2.2250738585072011e-308, 'g', -1, "2.225073858507201e-308"},
-
- // Issue 2625.
- {383260575764816448, 'f', 0, "383260575764816448"},
- {383260575764816448, 'g', -1, "3.8326057576481645e+17"},
- } {
- // The test cases are from the strconv package which tests float64 values.
- // When formatting values with prec = -1 (shortest representation),
- // the actually available mantissa precision matters.
- // For denormalized values, that precision is < 53 (SetFloat64 default).
- // Compute and set the actual precision explicitly.
- f := new(Float).SetPrec(actualPrec(test.x)).SetFloat64(test.x)
- got := f.Text(test.format, test.prec)
- if got != test.want {
- t.Errorf("%v: got %s; want %s", test, got, test.want)
- continue
- }
-
- if test.format == 'b' && test.x == 0 {
- continue // 'b' format in strconv.Float requires knowledge of bias for 0.0
- }
- if test.format == 'p' {
- continue // 'p' format not supported in strconv.Format
- }
-
- // verify that Float format matches strconv format
- want := strconv.FormatFloat(test.x, test.format, test.prec, 64)
- if got != want {
- t.Errorf("%v: got %s; want %s (strconv)", test, got, want)
- }
- }
-}
-
-// 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 {
- // x is denormalized
- return 64 - nlz64(bits&(1<<52-1))
- }
- return 53
-}
-
-func TestFloatText(t *testing.T) {
- for _, test := range []struct {
- x string
- prec uint
- format byte
- digits int
- want string
- }{
- {"0", 10, 'f', 0, "0"},
- {"-0", 10, 'f', 0, "-0"},
- {"1", 10, 'f', 0, "1"},
- {"-1", 10, 'f', 0, "-1"},
-
- {"1.459", 100, 'e', 0, "1e+00"},
- {"2.459", 100, 'e', 1, "2.5e+00"},
- {"3.459", 100, 'e', 2, "3.46e+00"},
- {"4.459", 100, 'e', 3, "4.459e+00"},
- {"5.459", 100, 'e', 4, "5.4590e+00"},
-
- {"1.459", 100, 'E', 0, "1E+00"},
- {"2.459", 100, 'E', 1, "2.5E+00"},
- {"3.459", 100, 'E', 2, "3.46E+00"},
- {"4.459", 100, 'E', 3, "4.459E+00"},
- {"5.459", 100, 'E', 4, "5.4590E+00"},
-
- {"1.459", 100, 'f', 0, "1"},
- {"2.459", 100, 'f', 1, "2.5"},
- {"3.459", 100, 'f', 2, "3.46"},
- {"4.459", 100, 'f', 3, "4.459"},
- {"5.459", 100, 'f', 4, "5.4590"},
-
- {"1.459", 100, 'g', 0, "1"},
- {"2.459", 100, 'g', 1, "2"},
- {"3.459", 100, 'g', 2, "3.5"},
- {"4.459", 100, 'g', 3, "4.46"},
- {"5.459", 100, 'g', 4, "5.459"},
-
- {"1459", 53, 'g', 0, "1e+03"},
- {"2459", 53, 'g', 1, "2e+03"},
- {"3459", 53, 'g', 2, "3.5e+03"},
- {"4459", 53, 'g', 3, "4.46e+03"},
- {"5459", 53, 'g', 4, "5459"},
-
- {"1459", 53, 'G', 0, "1E+03"},
- {"2459", 53, 'G', 1, "2E+03"},
- {"3459", 53, 'G', 2, "3.5E+03"},
- {"4459", 53, 'G', 3, "4.46E+03"},
- {"5459", 53, 'G', 4, "5459"},
-
- {"3", 10, 'e', 40, "3.0000000000000000000000000000000000000000e+00"},
- {"3", 10, 'f', 40, "3.0000000000000000000000000000000000000000"},
- {"3", 10, 'g', 40, "3"},
-
- {"3e40", 100, 'e', 40, "3.0000000000000000000000000000000000000000e+40"},
- {"3e40", 100, 'f', 4, "30000000000000000000000000000000000000000.0000"},
- {"3e40", 100, 'g', 40, "3e+40"},
-
- // make sure "stupid" exponents don't stall the machine
- {"1e1000000", 64, 'p', 0, "0x.88b3a28a05eade3ap+3321929"},
- {"1e646456992", 64, 'p', 0, "0x.e883a0c5c8c7c42ap+2147483644"},
- {"1e646456993", 64, 'p', 0, "+Inf"},
- {"1e1000000000", 64, 'p', 0, "+Inf"},
- {"1e-1000000", 64, 'p', 0, "0x.efb4542cc8ca418ap-3321928"},
- {"1e-646456993", 64, 'p', 0, "0x.e17c8956983d9d59p-2147483647"},
- {"1e-646456994", 64, 'p', 0, "0"},
- {"1e-1000000000", 64, 'p', 0, "0"},
-
- // minimum and maximum values
- {"1p2147483646", 64, 'p', 0, "0x.8p+2147483647"},
- {"0x.8p2147483647", 64, 'p', 0, "0x.8p+2147483647"},
- {"0x.8p-2147483647", 64, 'p', 0, "0x.8p-2147483647"},
- {"1p-2147483649", 64, 'p', 0, "0x.8p-2147483648"},
-
- // TODO(gri) need tests for actual large Floats
-
- {"0", 53, 'b', 0, "0"},
- {"-0", 53, 'b', 0, "-0"},
- {"1.0", 53, 'b', 0, "4503599627370496p-52"},
- {"-1.0", 53, 'b', 0, "-4503599627370496p-52"},
- {"4503599627370496", 53, 'b', 0, "4503599627370496p+0"},
-
- // issue 9939
- {"3", 350, 'b', 0, "1720123961992553633708115671476565205597423741876210842803191629540192157066363606052513914832594264915968p-348"},
- {"03", 350, 'b', 0, "1720123961992553633708115671476565205597423741876210842803191629540192157066363606052513914832594264915968p-348"},
- {"3.", 350, 'b', 0, "1720123961992553633708115671476565205597423741876210842803191629540192157066363606052513914832594264915968p-348"},
- {"3.0", 350, 'b', 0, "1720123961992553633708115671476565205597423741876210842803191629540192157066363606052513914832594264915968p-348"},
- {"3.00", 350, 'b', 0, "1720123961992553633708115671476565205597423741876210842803191629540192157066363606052513914832594264915968p-348"},
- {"3.000", 350, 'b', 0, "1720123961992553633708115671476565205597423741876210842803191629540192157066363606052513914832594264915968p-348"},
-
- {"3", 350, 'p', 0, "0x.cp+2"},
- {"03", 350, 'p', 0, "0x.cp+2"},
- {"3.", 350, 'p', 0, "0x.cp+2"},
- {"3.0", 350, 'p', 0, "0x.cp+2"},
- {"3.00", 350, 'p', 0, "0x.cp+2"},
- {"3.000", 350, 'p', 0, "0x.cp+2"},
-
- {"0", 64, 'p', 0, "0"},
- {"-0", 64, 'p', 0, "-0"},
- {"1024.0", 64, 'p', 0, "0x.8p+11"},
- {"-1024.0", 64, 'p', 0, "-0x.8p+11"},
-
- // unsupported format
- {"3.14", 64, 'x', 0, "%x"},
- {"-3.14", 64, 'x', 0, "%x"},
- } {
- f, _, err := ParseFloat(test.x, 0, test.prec, ToNearestEven)
- if err != nil {
- t.Errorf("%v: %s", test, err)
- continue
- }
-
- got := f.Text(test.format, test.digits)
- if got != test.want {
- t.Errorf("%v: got %s; want %s", test, got, test.want)
- }
-
- // compare with strconv.FormatFloat output if possible
- // ('p' format is not supported by strconv.FormatFloat,
- // and its output for 0.0 prints a biased exponent value
- // as in 0p-1074 which makes no sense to emulate here)
- if test.prec == 53 && test.format != 'p' && f.Sign() != 0 {
- f64, acc := f.Float64()
- if acc != Exact {
- t.Errorf("%v: expected exact conversion to float64", test)
- continue
- }
- got := strconv.FormatFloat(f64, test.format, test.digits, 64)
- if got != test.want {
- t.Errorf("%v: got %s; want %s", test, got, test.want)
- }
- }
- }
-}
-
-func TestFloatFormat(t *testing.T) {
- for _, test := range []struct {
- format string
- value interface{} // float32, float64, or string (== 512bit *Float)
- want string
- }{
- // from fmt/fmt_test.go
- {"%+.3e", 0.0, "+0.000e+00"},
- {"%+.3e", 1.0, "+1.000e+00"},
- {"%+.3f", -1.0, "-1.000"},
- {"%+.3F", -1.0, "-1.000"},
- {"%+.3F", float32(-1.0), "-1.000"},
- {"%+07.2f", 1.0, "+001.00"},
- {"%+07.2f", -1.0, "-001.00"},
- {"%+10.2f", +1.0, " +1.00"},
- {"%+10.2f", -1.0, " -1.00"},
- {"% .3E", -1.0, "-1.000E+00"},
- {"% .3e", 1.0, " 1.000e+00"},
- {"%+.3g", 0.0, "+0"},
- {"%+.3g", 1.0, "+1"},
- {"%+.3g", -1.0, "-1"},
- {"% .3g", -1.0, "-1"},
- {"% .3g", 1.0, " 1"},
- {"%b", float32(1.0), "8388608p-23"},
- {"%b", 1.0, "4503599627370496p-52"},
-
- // from fmt/fmt_test.go: old test/fmt_test.go
- {"%e", 1.0, "1.000000e+00"},
- {"%e", 1234.5678e3, "1.234568e+06"},
- {"%e", 1234.5678e-8, "1.234568e-05"},
- {"%e", -7.0, "-7.000000e+00"},
- {"%e", -1e-9, "-1.000000e-09"},
- {"%f", 1234.5678e3, "1234567.800000"},
- {"%f", 1234.5678e-8, "0.000012"},
- {"%f", -7.0, "-7.000000"},
- {"%f", -1e-9, "-0.000000"},
- {"%g", 1234.5678e3, "1.2345678e+06"},
- {"%g", float32(1234.5678e3), "1.2345678e+06"},
- {"%g", 1234.5678e-8, "1.2345678e-05"},
- {"%g", -7.0, "-7"},
- {"%g", -1e-9, "-1e-09"},
- {"%g", float32(-1e-9), "-1e-09"},
- {"%E", 1.0, "1.000000E+00"},
- {"%E", 1234.5678e3, "1.234568E+06"},
- {"%E", 1234.5678e-8, "1.234568E-05"},
- {"%E", -7.0, "-7.000000E+00"},
- {"%E", -1e-9, "-1.000000E-09"},
- {"%G", 1234.5678e3, "1.2345678E+06"},
- {"%G", float32(1234.5678e3), "1.2345678E+06"},
- {"%G", 1234.5678e-8, "1.2345678E-05"},
- {"%G", -7.0, "-7"},
- {"%G", -1e-9, "-1E-09"},
- {"%G", float32(-1e-9), "-1E-09"},
-
- {"%20.6e", 1.2345e3, " 1.234500e+03"},
- {"%20.6e", 1.2345e-3, " 1.234500e-03"},
- {"%20e", 1.2345e3, " 1.234500e+03"},
- {"%20e", 1.2345e-3, " 1.234500e-03"},
- {"%20.8e", 1.2345e3, " 1.23450000e+03"},
- {"%20f", 1.23456789e3, " 1234.567890"},
- {"%20f", 1.23456789e-3, " 0.001235"},
- {"%20f", 12345678901.23456789, " 12345678901.234568"},
- {"%-20f", 1.23456789e3, "1234.567890 "},
- {"%20.8f", 1.23456789e3, " 1234.56789000"},
- {"%20.8f", 1.23456789e-3, " 0.00123457"},
- {"%g", 1.23456789e3, "1234.56789"},
- {"%g", 1.23456789e-3, "0.00123456789"},
- {"%g", 1.23456789e20, "1.23456789e+20"},
- {"%20e", math.Inf(1), " +Inf"},
- {"%-20f", math.Inf(-1), "-Inf "},
-
- // from fmt/fmt_test.go: comparison of padding rules with C printf
- {"%.2f", 1.0, "1.00"},
- {"%.2f", -1.0, "-1.00"},
- {"% .2f", 1.0, " 1.00"},
- {"% .2f", -1.0, "-1.00"},
- {"%+.2f", 1.0, "+1.00"},
- {"%+.2f", -1.0, "-1.00"},
- {"%7.2f", 1.0, " 1.00"},
- {"%7.2f", -1.0, " -1.00"},
- {"% 7.2f", 1.0, " 1.00"},
- {"% 7.2f", -1.0, " -1.00"},
- {"%+7.2f", 1.0, " +1.00"},
- {"%+7.2f", -1.0, " -1.00"},
- {"%07.2f", 1.0, "0001.00"},
- {"%07.2f", -1.0, "-001.00"},
- {"% 07.2f", 1.0, " 001.00"},
- {"% 07.2f", -1.0, "-001.00"},
- {"%+07.2f", 1.0, "+001.00"},
- {"%+07.2f", -1.0, "-001.00"},
-
- // from fmt/fmt_test.go: zero padding does not apply to infinities
- {"%020f", math.Inf(-1), " -Inf"},
- {"%020f", math.Inf(+1), " +Inf"},
- {"% 020f", math.Inf(-1), " -Inf"},
- {"% 020f", math.Inf(+1), " Inf"},
- {"%+020f", math.Inf(-1), " -Inf"},
- {"%+020f", math.Inf(+1), " +Inf"},
- {"%20f", -1.0, " -1.000000"},
-
- // handle %v like %g
- {"%v", 0.0, "0"},
- {"%v", -7.0, "-7"},
- {"%v", -1e-9, "-1e-09"},
- {"%v", float32(-1e-9), "-1e-09"},
- {"%010v", 0.0, "0000000000"},
-
- // *Float cases
- {"%.20f", "1e-20", "0.00000000000000000001"},
- {"%.20f", "-1e-20", "-0.00000000000000000001"},
- {"%30.20f", "-1e-20", " -0.00000000000000000001"},
- {"%030.20f", "-1e-20", "-00000000.00000000000000000001"},
- {"%030.20f", "+1e-20", "000000000.00000000000000000001"},
- {"% 030.20f", "+1e-20", " 00000000.00000000000000000001"},
-
- // erroneous formats
- {"%s", 1.0, "%!s(*big.Float=1)"},
- } {
- value := new(Float)
- switch v := test.value.(type) {
- case float32:
- value.SetPrec(24).SetFloat64(float64(v))
- case float64:
- value.SetPrec(53).SetFloat64(v)
- case string:
- value.SetPrec(512).Parse(v, 0)
- default:
- t.Fatalf("unsupported test value: %v (%T)", v, v)
- }
-
- if got := fmt.Sprintf(test.format, value); got != test.want {
- t.Errorf("%v: got %q; want %q", test, got, test.want)
- }
- }
-}
-
-func BenchmarkParseFloatSmallExp(b *testing.B) {
- for i := 0; i < b.N; i++ {
- for _, s := range []string{
- "1e0",
- "1e-1",
- "1e-2",
- "1e-3",
- "1e-4",
- "1e-5",
- "1e-10",
- "1e-20",
- "1e-50",
- "1e1",
- "1e2",
- "1e3",
- "1e4",
- "1e5",
- "1e10",
- "1e20",
- "1e50",
- } {
- var x Float
- _, _, err := x.Parse(s, 0)
- if err != nil {
- b.Fatalf("%s: %v", s, err)
- }
- }
- }
-}
-
-func BenchmarkParseFloatLargeExp(b *testing.B) {
- for i := 0; i < b.N; i++ {
- for _, s := range []string{
- "1e0",
- "1e-10",
- "1e-20",
- "1e-30",
- "1e-40",
- "1e-50",
- "1e-100",
- "1e-500",
- "1e-1000",
- "1e-5000",
- "1e-10000",
- "1e10",
- "1e20",
- "1e30",
- "1e40",
- "1e50",
- "1e100",
- "1e500",
- "1e1000",
- "1e5000",
- "1e10000",
- } {
- var x Float
- _, _, err := x.Parse(s, 0)
- if err != nil {
- b.Fatalf("%s: %v", s, err)
- }
- }
- }
-}
diff --git a/src/cmd/compile/internal/big/floatexample_test.go b/src/cmd/compile/internal/big/floatexample_test.go
deleted file mode 100644
index 83c6bda..0000000
--- a/src/cmd/compile/internal/big/floatexample_test.go
+++ /dev/null
@@ -1,141 +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 big_test
-
-import (
- "cmd/compile/internal/big"
- "fmt"
- "math"
-)
-
-func ExampleFloat_Add() {
- // Operating on numbers of different precision.
- var x, y, z big.Float
- x.SetInt64(1000) // x is automatically set to 64bit precision
- y.SetFloat64(2.718281828) // y is automatically set to 53bit precision
- z.SetPrec(32)
- z.Add(&x, &y)
- fmt.Printf("x = %.10g (%s, prec = %d, acc = %s)\n", &x, x.Text('p', 0), x.Prec(), x.Acc())
- fmt.Printf("y = %.10g (%s, prec = %d, acc = %s)\n", &y, y.Text('p', 0), y.Prec(), y.Acc())
- fmt.Printf("z = %.10g (%s, prec = %d, acc = %s)\n", &z, z.Text('p', 0), z.Prec(), z.Acc())
- // Output:
- // x = 1000 (0x.fap+10, prec = 64, acc = Exact)
- // y = 2.718281828 (0x.adf85458248cd8p+2, prec = 53, acc = Exact)
- // z = 1002.718282 (0x.faadf854p+10, prec = 32, acc = Below)
-}
-
-func Example_Shift() {
- // Implementing Float "shift" by modifying the (binary) exponents directly.
- for s := -5; s <= 5; s++ {
- x := big.NewFloat(0.5)
- x.SetMantExp(x, x.MantExp(nil)+s) // shift x by s
- fmt.Println(x)
- }
- // Output:
- // 0.015625
- // 0.03125
- // 0.0625
- // 0.125
- // 0.25
- // 0.5
- // 1
- // 2
- // 4
- // 8
- // 16
-}
-
-func ExampleFloat_Cmp() {
- inf := math.Inf(1)
- zero := 0.0
-
- operands := []float64{-inf, -1.2, -zero, 0, +1.2, +inf}
-
- fmt.Println(" x y cmp")
- fmt.Println("---------------")
- for _, x64 := range operands {
- x := big.NewFloat(x64)
- for _, y64 := range operands {
- y := big.NewFloat(y64)
- fmt.Printf("%4g %4g %3d\n", x, y, x.Cmp(y))
- }
- fmt.Println()
- }
-
- // Output:
- // x y cmp
- // ---------------
- // -Inf -Inf 0
- // -Inf -1.2 -1
- // -Inf -0 -1
- // -Inf 0 -1
- // -Inf 1.2 -1
- // -Inf +Inf -1
- //
- // -1.2 -Inf 1
- // -1.2 -1.2 0
- // -1.2 -0 -1
- // -1.2 0 -1
- // -1.2 1.2 -1
- // -1.2 +Inf -1
- //
- // -0 -Inf 1
- // -0 -1.2 1
- // -0 -0 0
- // -0 0 0
- // -0 1.2 -1
- // -0 +Inf -1
- //
- // 0 -Inf 1
- // 0 -1.2 1
- // 0 -0 0
- // 0 0 0
- // 0 1.2 -1
- // 0 +Inf -1
- //
- // 1.2 -Inf 1
- // 1.2 -1.2 1
- // 1.2 -0 1
- // 1.2 0 1
- // 1.2 1.2 0
- // 1.2 +Inf -1
- //
- // +Inf -Inf 1
- // +Inf -1.2 1
- // +Inf -0 1
- // +Inf 0 1
- // +Inf 1.2 1
- // +Inf +Inf 0
-}
-
-func ExampleRoundingMode() {
- operands := []float64{2.6, 2.5, 2.1, -2.1, -2.5, -2.6}
-
- fmt.Print(" x")
- for mode := big.ToNearestEven; mode <= big.ToPositiveInf; mode++ {
- fmt.Printf(" %s", mode)
- }
- fmt.Println()
-
- for _, f64 := range operands {
- fmt.Printf("%4g", f64)
- for mode := big.ToNearestEven; mode <= big.ToPositiveInf; mode++ {
- // sample operands above require 2 bits to represent mantissa
- // set binary precision to 2 to round them to integer values
- f := new(big.Float).SetPrec(2).SetMode(mode).SetFloat64(f64)
- fmt.Printf(" %*g", len(mode.String()), f)
- }
- fmt.Println()
- }
-
- // Output:
- // x ToNearestEven ToNearestAway ToZero AwayFromZero ToNegativeInf ToPositiveInf
- // 2.6 3 3 2 3 2 3
- // 2.5 2 3 2 3 2 3
- // 2.1 2 2 2 3 2 3
- // -2.1 -2 -2 -2 -3 -3 -2
- // -2.5 -2 -3 -2 -3 -3 -2
- // -2.6 -3 -3 -2 -3 -3 -2
-}
diff --git a/src/cmd/compile/internal/big/floatmarsh.go b/src/cmd/compile/internal/big/floatmarsh.go
deleted file mode 100644
index 44987ee..0000000
--- a/src/cmd/compile/internal/big/floatmarsh.go
+++ /dev/null
@@ -1,33 +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 implements encoding/decoding of Floats.
-
-package big
-
-import "fmt"
-
-// MarshalText implements the encoding.TextMarshaler interface.
-// Only the Float value is marshaled (in full precision), other
-// attributes such as precision or accuracy are ignored.
-func (x *Float) MarshalText() (text []byte, err error) {
- if x == nil {
- return []byte("<nil>"), nil
- }
- var buf []byte
- return x.Append(buf, 'g', -1), nil
-}
-
-// UnmarshalText implements the encoding.TextUnmarshaler interface.
-// The result is rounded per the precision and rounding mode of z.
-// If z's precision is 0, it is changed to 64 before rounding takes
-// effect.
-func (z *Float) UnmarshalText(text []byte) error {
- // TODO(gri): get rid of the []byte/string conversion
- _, _, err := z.Parse(string(text), 0)
- if err != nil {
- err = fmt.Errorf("math/big: cannot unmarshal %q into a *big.Float (%v)", text, err)
- }
- return err
-}
diff --git a/src/cmd/compile/internal/big/floatmarsh_test.go b/src/cmd/compile/internal/big/floatmarsh_test.go
deleted file mode 100644
index d7ef2fc..0000000
--- a/src/cmd/compile/internal/big/floatmarsh_test.go
+++ /dev/null
@@ -1,54 +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 big
-
-import (
- "encoding/json"
- "testing"
-)
-
-var floatVals = []string{
- "0",
- "1",
- "0.1",
- "2.71828",
- "1234567890",
- "3.14e1234",
- "3.14e-1234",
- "0.738957395793475734757349579759957975985497e100",
- "0.73895739579347546656564656573475734957975995797598589749859834759476745986795497e100",
- "inf",
- "Inf",
-}
-
-func TestFloatJSONEncoding(t *testing.T) {
- for _, test := range floatVals {
- for _, sign := range []string{"", "+", "-"} {
- for _, prec := range []uint{0, 1, 2, 10, 53, 64, 100, 1000} {
- x := sign + test
- var tx Float
- _, _, err := tx.SetPrec(prec).Parse(x, 0)
- if err != nil {
- t.Errorf("parsing of %s (prec = %d) failed (invalid test case): %v", x, prec, err)
- continue
- }
- b, err := json.Marshal(&tx)
- if err != nil {
- t.Errorf("marshaling of %v (prec = %d) failed: %v", &tx, prec, err)
- continue
- }
- var rx Float
- rx.SetPrec(prec)
- if err := json.Unmarshal(b, &rx); err != nil {
- t.Errorf("unmarshaling of %v (prec = %d) failed: %v", &tx, prec, err)
- continue
- }
- if rx.Cmp(&tx) != 0 {
- t.Errorf("JSON encoding of %v (prec = %d) failed: got %v want %v", &tx, prec, &rx, &tx)
- }
- }
- }
- }
-}
diff --git a/src/cmd/compile/internal/big/ftoa.go b/src/cmd/compile/internal/big/ftoa.go
deleted file mode 100644
index 624ea5e..0000000
--- a/src/cmd/compile/internal/big/ftoa.go
+++ /dev/null
@@ -1,456 +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 implements Float-to-string conversion functions.
-// It is closely following the corresponding implementation
-// in strconv/ftoa.go, but modified and simplified for Float.
-
-package big
-
-import (
- "bytes"
- "fmt"
- "strconv"
-)
-
-// Text converts the floating-point number x to a string according
-// to the given format and precision prec. The format is one of:
-//
-// 'e' -d.dddde±dd, decimal exponent, at least two (possibly 0) exponent digits
-// 'E' -d.ddddE±dd, decimal exponent, at least two (possibly 0) exponent digits
-// 'f' -ddddd.dddd, no exponent
-// 'g' like 'e' for large exponents, like 'f' otherwise
-// 'G' like 'E' for large exponents, like 'f' otherwise
-// 'b' -ddddddp±dd, binary exponent
-// 'p' -0x.dddp±dd, binary exponent, hexadecimal mantissa
-//
-// For the binary exponent formats, the mantissa is printed in normalized form:
-//
-// 'b' decimal integer mantissa using x.Prec() bits, or -0
-// 'p' hexadecimal fraction with 0.5 <= 0.mantissa < 1.0, or -0
-//
-// If format is a different character, Text returns a "%" followed by the
-// unrecognized format character.
-//
-// The precision prec controls the number of digits (excluding the exponent)
-// printed by the 'e', 'E', 'f', 'g', and 'G' formats. For 'e', 'E', and 'f'
-// it is the number of digits after the decimal point. For 'g' and 'G' it is
-// the total number of digits. A negative precision selects the smallest
-// number of decimal digits necessary to identify the value x uniquely using
-// x.Prec() mantissa bits.
-// The prec value is ignored for the 'b' or 'p' format.
-func (x *Float) Text(format byte, prec int) string {
- const extra = 10 // TODO(gri) determine a good/better value here
- return string(x.Append(make([]byte, 0, prec+extra), format, prec))
-}
-
-// String formats x like x.Text('g', 10).
-// (String must be called explicitly, Float.Format does not support %s verb.)
-func (x *Float) String() string {
- return x.Text('g', 10)
-}
-
-// Append appends to buf the string form of the floating-point number x,
-// as generated by x.Text, and returns the extended buffer.
-func (x *Float) Append(buf []byte, fmt byte, prec int) []byte {
- // sign
- if x.neg {
- buf = append(buf, '-')
- }
-
- // Inf
- if x.form == inf {
- if !x.neg {
- buf = append(buf, '+')
- }
- return append(buf, "Inf"...)
- }
-
- // pick off easy formats
- switch fmt {
- case 'b':
- return x.fmtB(buf)
- case 'p':
- return x.fmtP(buf)
- }
-
- // Algorithm:
- // 1) convert Float to multiprecision decimal
- // 2) round to desired precision
- // 3) read digits out and format
-
- // 1) convert Float to multiprecision decimal
- var d decimal // == 0.0
- if x.form == finite {
- // x != 0
- d.init(x.mant, int(x.exp)-x.mant.bitLen())
- }
-
- // 2) round to desired precision
- shortest := false
- if prec < 0 {
- shortest = true
- roundShortest(&d, x)
- // Precision for shortest representation mode.
- switch fmt {
- case 'e', 'E':
- prec = len(d.mant) - 1
- case 'f':
- prec = max(len(d.mant)-d.exp, 0)
- case 'g', 'G':
- prec = len(d.mant)
- }
- } else {
- // round appropriately
- switch fmt {
- case 'e', 'E':
- // one digit before and number of digits after decimal point
- d.round(1 + prec)
- case 'f':
- // number of digits before and after decimal point
- d.round(d.exp + prec)
- case 'g', 'G':
- if prec == 0 {
- prec = 1
- }
- d.round(prec)
- }
- }
-
- // 3) read digits out and format
- switch fmt {
- case 'e', 'E':
- return fmtE(buf, fmt, prec, d)
- case 'f':
- return fmtF(buf, prec, d)
- case 'g', 'G':
- // trim trailing fractional zeros in %e format
- eprec := prec
- if eprec > len(d.mant) && len(d.mant) >= d.exp {
- eprec = len(d.mant)
- }
- // %e is used if the exponent from the conversion
- // is less than -4 or greater than or equal to the precision.
- // If precision was the shortest possible, use eprec = 6 for
- // this decision.
- if shortest {
- eprec = 6
- }
- exp := d.exp - 1
- if exp < -4 || exp >= eprec {
- if prec > len(d.mant) {
- prec = len(d.mant)
- }
- return fmtE(buf, fmt+'e'-'g', prec-1, d)
- }
- if prec > d.exp {
- prec = len(d.mant)
- }
- return fmtF(buf, max(prec-d.exp, 0), d)
- }
-
- // unknown format
- if x.neg {
- buf = buf[:len(buf)-1] // sign was added prematurely - remove it again
- }
- return append(buf, '%', fmt)
-}
-
-func roundShortest(d *decimal, x *Float) {
- // if the mantissa is zero, the number is zero - stop now
- if len(d.mant) == 0 {
- return
- }
-
- // Approach: All numbers in the interval [x - 1/2ulp, x + 1/2ulp]
- // (possibly exclusive) round to x for the given precision of x.
- // Compute the lower and upper bound in decimal form and find the
- // shortest decimal number d such that lower <= d <= upper.
-
- // TODO(gri) strconv/ftoa.do describes a shortcut in some cases.
- // See if we can use it (in adjusted form) here as well.
-
- // 1) Compute normalized mantissa mant and exponent exp for x such
- // that the lsb of mant corresponds to 1/2 ulp for the precision of
- // x (i.e., for mant we want x.prec + 1 bits).
- mant := nat(nil).set(x.mant)
- exp := int(x.exp) - mant.bitLen()
- s := mant.bitLen() - int(x.prec+1)
- switch {
- case s < 0:
- mant = mant.shl(mant, uint(-s))
- case s > 0:
- mant = mant.shr(mant, uint(+s))
- }
- exp += s
- // x = mant * 2**exp with lsb(mant) == 1/2 ulp of x.prec
-
- // 2) Compute lower bound by subtracting 1/2 ulp.
- var lower decimal
- var tmp nat
- lower.init(tmp.sub(mant, natOne), exp)
-
- // 3) Compute upper bound by adding 1/2 ulp.
- var upper decimal
- upper.init(tmp.add(mant, natOne), exp)
-
- // The upper and lower bounds are possible outputs only if
- // the original mantissa is even, so that ToNearestEven rounding
- // would round to the original mantissa and not the neighbors.
- inclusive := mant[0]&2 == 0 // test bit 1 since original mantissa was shifted by 1
-
- // Now we can figure out the minimum number of digits required.
- // Walk along until d has distinguished itself from upper and lower.
- for i, m := range d.mant {
- l := lower.at(i)
- u := upper.at(i)
-
- // Okay to round down (truncate) if lower has a different digit
- // or if lower is inclusive and is exactly the result of rounding
- // down (i.e., and we have reached the final digit of lower).
- okdown := l != m || inclusive && i+1 == len(lower.mant)
-
- // Okay to round up if upper has a different digit and either upper
- // is inclusive or upper is bigger than the result of rounding up.
- okup := m != u && (inclusive || m+1 < u || i+1 < len(upper.mant))
-
- // If it's okay to do either, then round to the nearest one.
- // If it's okay to do only one, do it.
- switch {
- case okdown && okup:
- d.round(i + 1)
- return
- case okdown:
- d.roundDown(i + 1)
- return
- case okup:
- d.roundUp(i + 1)
- return
- }
- }
-}
-
-// %e: d.ddddde±dd
-func fmtE(buf []byte, fmt byte, prec int, d decimal) []byte {
- // first digit
- ch := byte('0')
- if len(d.mant) > 0 {
- ch = d.mant[0]
- }
- buf = append(buf, ch)
-
- // .moredigits
- if prec > 0 {
- buf = append(buf, '.')
- i := 1
- m := min(len(d.mant), prec+1)
- if i < m {
- buf = append(buf, d.mant[i:m]...)
- i = m
- }
- for ; i <= prec; i++ {
- buf = append(buf, '0')
- }
- }
-
- // e±
- buf = append(buf, fmt)
- var exp int64
- if len(d.mant) > 0 {
- exp = int64(d.exp) - 1 // -1 because first digit was printed before '.'
- }
- if exp < 0 {
- ch = '-'
- exp = -exp
- } else {
- ch = '+'
- }
- buf = append(buf, ch)
-
- // dd...d
- if exp < 10 {
- buf = append(buf, '0') // at least 2 exponent digits
- }
- return strconv.AppendInt(buf, exp, 10)
-}
-
-// %f: ddddddd.ddddd
-func fmtF(buf []byte, prec int, d decimal) []byte {
- // integer, padded with zeros as needed
- if d.exp > 0 {
- m := min(len(d.mant), d.exp)
- buf = append(buf, d.mant[:m]...)
- for ; m < d.exp; m++ {
- buf = append(buf, '0')
- }
- } else {
- buf = append(buf, '0')
- }
-
- // fraction
- if prec > 0 {
- buf = append(buf, '.')
- for i := 0; i < prec; i++ {
- buf = append(buf, d.at(d.exp+i))
- }
- }
-
- return buf
-}
-
-// fmtB appends the string of x in the format mantissa "p" exponent
-// with a decimal mantissa and a binary exponent, or 0" if x is zero,
-// and returns the extended buffer.
-// The mantissa is normalized such that is uses x.Prec() bits in binary
-// representation.
-// The sign of x is ignored, and x must not be an Inf.
-func (x *Float) fmtB(buf []byte) []byte {
- if x.form == zero {
- return append(buf, '0')
- }
-
- if debugFloat && x.form != finite {
- panic("non-finite float")
- }
- // x != 0
-
- // adjust mantissa to use exactly x.prec bits
- m := x.mant
- switch w := uint32(len(x.mant)) * _W; {
- case w < x.prec:
- m = nat(nil).shl(m, uint(x.prec-w))
- case w > x.prec:
- m = nat(nil).shr(m, uint(w-x.prec))
- }
-
- buf = append(buf, m.utoa(10)...)
- buf = append(buf, 'p')
- e := int64(x.exp) - int64(x.prec)
- if e >= 0 {
- buf = append(buf, '+')
- }
- return strconv.AppendInt(buf, e, 10)
-}
-
-// fmtP appends the string of x in the format "0x." mantissa "p" exponent
-// with a hexadecimal mantissa and a binary exponent, or "0" if x is zero,
-// and returns the extended buffer.
-// The mantissa is normalized such that 0.5 <= 0.mantissa < 1.0.
-// The sign of x is ignored, and x must not be an Inf.
-func (x *Float) fmtP(buf []byte) []byte {
- if x.form == zero {
- return append(buf, '0')
- }
-
- if debugFloat && x.form != finite {
- panic("non-finite float")
- }
- // x != 0
-
- // remove trailing 0 words early
- // (no need to convert to hex 0's and trim later)
- m := x.mant
- i := 0
- for i < len(m) && m[i] == 0 {
- i++
- }
- m = m[i:]
-
- buf = append(buf, "0x."...)
- buf = append(buf, bytes.TrimRight(m.utoa(16), "0")...)
- buf = append(buf, 'p')
- if x.exp >= 0 {
- buf = append(buf, '+')
- }
- return strconv.AppendInt(buf, int64(x.exp), 10)
-}
-
-func min(x, y int) int {
- if x < y {
- return x
- }
- return y
-}
-
-// Format implements fmt.Formatter. It accepts all the regular
-// formats for floating-point numbers ('b', 'e', 'E', 'f', 'F',
-// 'g', 'G') as well as 'p' and 'v'. See (*Float).Text for the
-// interpretation of 'p'. The 'v' format is handled like 'g'.
-// Format also supports specification of the minimum precision
-// in digits, the output field width, as well as the format flags
-// '+' and ' ' for sign control, '0' for space or zero padding,
-// and '-' for left or right justification. See the fmt package
-// for details.
-func (x *Float) Format(s fmt.State, format rune) {
- prec, hasPrec := s.Precision()
- if !hasPrec {
- prec = 6 // default precision for 'e', 'f'
- }
-
- switch format {
- case 'e', 'E', 'f', 'b', 'p':
- // nothing to do
- case 'F':
- // (*Float).Text doesn't support 'F'; handle like 'f'
- format = 'f'
- case 'v':
- // handle like 'g'
- format = 'g'
- fallthrough
- case 'g', 'G':
- if !hasPrec {
- prec = -1 // default precision for 'g', 'G'
- }
- default:
- fmt.Fprintf(s, "%%!%c(*big.Float=%s)", format, x.String())
- return
- }
- var buf []byte
- buf = x.Append(buf, byte(format), prec)
- if len(buf) == 0 {
- buf = []byte("?") // should never happen, but don't crash
- }
- // len(buf) > 0
-
- var sign string
- switch {
- case buf[0] == '-':
- sign = "-"
- buf = buf[1:]
- case buf[0] == '+':
- // +Inf
- sign = "+"
- if s.Flag(' ') {
- sign = " "
- }
- buf = buf[1:]
- case s.Flag('+'):
- sign = "+"
- case s.Flag(' '):
- sign = " "
- }
-
- var padding int
- if width, hasWidth := s.Width(); hasWidth && width > len(sign)+len(buf) {
- padding = width - len(sign) - len(buf)
- }
-
- switch {
- case s.Flag('0') && !x.IsInf():
- // 0-padding on left
- writeMultiple(s, sign, 1)
- writeMultiple(s, "0", padding)
- s.Write(buf)
- case s.Flag('-'):
- // padding on right
- writeMultiple(s, sign, 1)
- s.Write(buf)
- writeMultiple(s, " ", padding)
- default:
- // padding on left
- writeMultiple(s, " ", padding)
- writeMultiple(s, sign, 1)
- s.Write(buf)
- }
-}
diff --git a/src/cmd/compile/internal/big/gcd_test.go b/src/cmd/compile/internal/big/gcd_test.go
deleted file mode 100644
index c0b9f58..0000000
--- a/src/cmd/compile/internal/big/gcd_test.go
+++ /dev/null
@@ -1,47 +0,0 @@
-// Copyright 2012 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// This file implements a GCD benchmark.
-// Usage: go test math/big -test.bench GCD
-
-package big
-
-import (
- "math/rand"
- "testing"
-)
-
-// randInt returns a pseudo-random Int in the range [1<<(size-1), (1<<size) - 1]
-func randInt(r *rand.Rand, size uint) *Int {
- n := new(Int).Lsh(intOne, size-1)
- x := new(Int).Rand(r, n)
- return x.Add(x, n) // make sure result > 1<<(size-1)
-}
-
-func runGCD(b *testing.B, aSize, bSize uint) {
- b.StopTimer()
- var r = rand.New(rand.NewSource(1234))
- aa := randInt(r, aSize)
- bb := randInt(r, bSize)
- b.StartTimer()
- for i := 0; i < b.N; i++ {
- new(Int).GCD(nil, nil, aa, bb)
- }
-}
-
-func BenchmarkGCD10x10(b *testing.B) { runGCD(b, 10, 10) }
-func BenchmarkGCD10x100(b *testing.B) { runGCD(b, 10, 100) }
-func BenchmarkGCD10x1000(b *testing.B) { runGCD(b, 10, 1000) }
-func BenchmarkGCD10x10000(b *testing.B) { runGCD(b, 10, 10000) }
-func BenchmarkGCD10x100000(b *testing.B) { runGCD(b, 10, 100000) }
-func BenchmarkGCD100x100(b *testing.B) { runGCD(b, 100, 100) }
-func BenchmarkGCD100x1000(b *testing.B) { runGCD(b, 100, 1000) }
-func BenchmarkGCD100x10000(b *testing.B) { runGCD(b, 100, 10000) }
-func BenchmarkGCD100x100000(b *testing.B) { runGCD(b, 100, 100000) }
-func BenchmarkGCD1000x1000(b *testing.B) { runGCD(b, 1000, 1000) }
-func BenchmarkGCD1000x10000(b *testing.B) { runGCD(b, 1000, 10000) }
-func BenchmarkGCD1000x100000(b *testing.B) { runGCD(b, 1000, 100000) }
-func BenchmarkGCD10000x10000(b *testing.B) { runGCD(b, 10000, 10000) }
-func BenchmarkGCD10000x100000(b *testing.B) { runGCD(b, 10000, 100000) }
-func BenchmarkGCD100000x100000(b *testing.B) { runGCD(b, 100000, 100000) }
diff --git a/src/cmd/compile/internal/big/hilbert_test.go b/src/cmd/compile/internal/big/hilbert_test.go
deleted file mode 100644
index 1a84341..0000000
--- a/src/cmd/compile/internal/big/hilbert_test.go
+++ /dev/null
@@ -1,160 +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.
-
-// A little test program and benchmark for rational arithmetics.
-// Computes a Hilbert matrix, its inverse, multiplies them
-// and verifies that the product is the identity matrix.
-
-package big
-
-import (
- "fmt"
- "testing"
-)
-
-type matrix struct {
- n, m int
- a []*Rat
-}
-
-func (a *matrix) at(i, j int) *Rat {
- if !(0 <= i && i < a.n && 0 <= j && j < a.m) {
- panic("index out of range")
- }
- return a.a[i*a.m+j]
-}
-
-func (a *matrix) set(i, j int, x *Rat) {
- if !(0 <= i && i < a.n && 0 <= j && j < a.m) {
- panic("index out of range")
- }
- a.a[i*a.m+j] = x
-}
-
-func newMatrix(n, m int) *matrix {
- if !(0 <= n && 0 <= m) {
- panic("illegal matrix")
- }
- a := new(matrix)
- a.n = n
- a.m = m
- a.a = make([]*Rat, n*m)
- return a
-}
-
-func newUnit(n int) *matrix {
- a := newMatrix(n, n)
- for i := 0; i < n; i++ {
- for j := 0; j < n; j++ {
- x := NewRat(0, 1)
- if i == j {
- x.SetInt64(1)
- }
- a.set(i, j, x)
- }
- }
- return a
-}
-
-func newHilbert(n int) *matrix {
- a := newMatrix(n, n)
- for i := 0; i < n; i++ {
- for j := 0; j < n; j++ {
- a.set(i, j, NewRat(1, int64(i+j+1)))
- }
- }
- return a
-}
-
-func newInverseHilbert(n int) *matrix {
- a := newMatrix(n, n)
- for i := 0; i < n; i++ {
- for j := 0; j < n; j++ {
- x1 := new(Rat).SetInt64(int64(i + j + 1))
- x2 := new(Rat).SetInt(new(Int).Binomial(int64(n+i), int64(n-j-1)))
- x3 := new(Rat).SetInt(new(Int).Binomial(int64(n+j), int64(n-i-1)))
- x4 := new(Rat).SetInt(new(Int).Binomial(int64(i+j), int64(i)))
-
- x1.Mul(x1, x2)
- x1.Mul(x1, x3)
- x1.Mul(x1, x4)
- x1.Mul(x1, x4)
-
- if (i+j)&1 != 0 {
- x1.Neg(x1)
- }
-
- a.set(i, j, x1)
- }
- }
- return a
-}
-
-func (a *matrix) mul(b *matrix) *matrix {
- if a.m != b.n {
- panic("illegal matrix multiply")
- }
- c := newMatrix(a.n, b.m)
- for i := 0; i < c.n; i++ {
- for j := 0; j < c.m; j++ {
- x := NewRat(0, 1)
- for k := 0; k < a.m; k++ {
- x.Add(x, new(Rat).Mul(a.at(i, k), b.at(k, j)))
- }
- c.set(i, j, x)
- }
- }
- return c
-}
-
-func (a *matrix) eql(b *matrix) bool {
- if a.n != b.n || a.m != b.m {
- return false
- }
- for i := 0; i < a.n; i++ {
- for j := 0; j < a.m; j++ {
- if a.at(i, j).Cmp(b.at(i, j)) != 0 {
- return false
- }
- }
- }
- return true
-}
-
-func (a *matrix) String() string {
- s := ""
- for i := 0; i < a.n; i++ {
- for j := 0; j < a.m; j++ {
- s += fmt.Sprintf("\t%s", a.at(i, j))
- }
- s += "\n"
- }
- return s
-}
-
-func doHilbert(t *testing.T, n int) {
- a := newHilbert(n)
- b := newInverseHilbert(n)
- I := newUnit(n)
- ab := a.mul(b)
- if !ab.eql(I) {
- if t == nil {
- panic("Hilbert failed")
- }
- t.Errorf("a = %s\n", a)
- t.Errorf("b = %s\n", b)
- t.Errorf("a*b = %s\n", ab)
- t.Errorf("I = %s\n", I)
- }
-}
-
-func TestHilbert(t *testing.T) {
- doHilbert(t, 10)
-}
-
-func BenchmarkHilbert(b *testing.B) {
- for i := 0; i < b.N; i++ {
- doHilbert(nil, 10)
- }
-}
diff --git a/src/cmd/compile/internal/big/int.go b/src/cmd/compile/internal/big/int.go
deleted file mode 100644
index 67ab704..0000000
--- a/src/cmd/compile/internal/big/int.go
+++ /dev/null
@@ -1,934 +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.
-
-// This file implements signed multi-precision integers.
-
-package big
-
-import (
- "fmt"
- "io"
- "math/rand"
- "strings"
-)
-
-// An Int represents a signed multi-precision integer.
-// The zero value for an Int represents the value 0.
-type Int struct {
- neg bool // sign
- abs nat // absolute value of the integer
-}
-
-var intOne = &Int{false, natOne}
-
-// Sign returns:
-//
-// -1 if x < 0
-// 0 if x == 0
-// +1 if x > 0
-//
-func (x *Int) Sign() int {
- if len(x.abs) == 0 {
- return 0
- }
- if x.neg {
- return -1
- }
- return 1
-}
-
-// SetInt64 sets z to x and returns z.
-func (z *Int) SetInt64(x int64) *Int {
- neg := false
- if x < 0 {
- neg = true
- x = -x
- }
- z.abs = z.abs.setUint64(uint64(x))
- z.neg = neg
- return z
-}
-
-// SetUint64 sets z to x and returns z.
-func (z *Int) SetUint64(x uint64) *Int {
- z.abs = z.abs.setUint64(x)
- z.neg = false
- return z
-}
-
-// NewInt allocates and returns a new Int set to x.
-func NewInt(x int64) *Int {
- return new(Int).SetInt64(x)
-}
-
-// Set sets z to x and returns z.
-func (z *Int) Set(x *Int) *Int {
- if z != x {
- z.abs = z.abs.set(x.abs)
- z.neg = x.neg
- }
- return z
-}
-
-// Bits provides raw (unchecked but fast) access to x by returning its
-// absolute value as a little-endian Word slice. The result and x share
-// the same underlying array.
-// Bits is intended to support implementation of missing low-level Int
-// functionality outside this package; it should be avoided otherwise.
-func (x *Int) Bits() []Word {
- return x.abs
-}
-
-// SetBits provides raw (unchecked but fast) access to z by setting its
-// value to abs, interpreted as a little-endian Word slice, and returning
-// z. The result and abs share the same underlying array.
-// SetBits is intended to support implementation of missing low-level Int
-// functionality outside this package; it should be avoided otherwise.
-func (z *Int) SetBits(abs []Word) *Int {
- z.abs = nat(abs).norm()
- z.neg = false
- return z
-}
-
-// Abs sets z to |x| (the absolute value of x) and returns z.
-func (z *Int) Abs(x *Int) *Int {
- z.Set(x)
- z.neg = false
- return z
-}
-
-// Neg sets z to -x and returns z.
-func (z *Int) Neg(x *Int) *Int {
- z.Set(x)
- z.neg = len(z.abs) > 0 && !z.neg // 0 has no sign
- return z
-}
-
-// Add sets z to the sum x+y and returns z.
-func (z *Int) Add(x, y *Int) *Int {
- neg := x.neg
- if x.neg == y.neg {
- // x + y == x + y
- // (-x) + (-y) == -(x + y)
- z.abs = z.abs.add(x.abs, y.abs)
- } else {
- // x + (-y) == x - y == -(y - x)
- // (-x) + y == y - x == -(x - y)
- if x.abs.cmp(y.abs) >= 0 {
- z.abs = z.abs.sub(x.abs, y.abs)
- } else {
- neg = !neg
- z.abs = z.abs.sub(y.abs, x.abs)
- }
- }
- z.neg = len(z.abs) > 0 && neg // 0 has no sign
- return z
-}
-
-// Sub sets z to the difference x-y and returns z.
-func (z *Int) Sub(x, y *Int) *Int {
- neg := x.neg
- if x.neg != y.neg {
- // x - (-y) == x + y
- // (-x) - y == -(x + y)
- z.abs = z.abs.add(x.abs, y.abs)
- } else {
- // x - y == x - y == -(y - x)
- // (-x) - (-y) == y - x == -(x - y)
- if x.abs.cmp(y.abs) >= 0 {
- z.abs = z.abs.sub(x.abs, y.abs)
- } else {
- neg = !neg
- z.abs = z.abs.sub(y.abs, x.abs)
- }
- }
- z.neg = len(z.abs) > 0 && neg // 0 has no sign
- return z
-}
-
-// Mul sets z to the product x*y and returns z.
-func (z *Int) Mul(x, y *Int) *Int {
- // x * y == x * y
- // x * (-y) == -(x * y)
- // (-x) * y == -(x * y)
- // (-x) * (-y) == x * y
- z.abs = z.abs.mul(x.abs, y.abs)
- z.neg = len(z.abs) > 0 && x.neg != y.neg // 0 has no sign
- return z
-}
-
-// MulRange sets z to the product of all integers
-// in the range [a, b] inclusively and returns z.
-// If a > b (empty range), the result is 1.
-func (z *Int) MulRange(a, b int64) *Int {
- switch {
- case a > b:
- return z.SetInt64(1) // empty range
- case a <= 0 && b >= 0:
- return z.SetInt64(0) // range includes 0
- }
- // a <= b && (b < 0 || a > 0)
-
- neg := false
- if a < 0 {
- neg = (b-a)&1 == 0
- a, b = -b, -a
- }
-
- z.abs = z.abs.mulRange(uint64(a), uint64(b))
- z.neg = neg
- return z
-}
-
-// Binomial sets z to the binomial coefficient of (n, k) and returns z.
-func (z *Int) Binomial(n, k int64) *Int {
- // reduce the number of multiplications by reducing k
- if n/2 < k && k <= n {
- k = n - k // Binomial(n, k) == Binomial(n, n-k)
- }
- var a, b Int
- a.MulRange(n-k+1, n)
- b.MulRange(1, k)
- return z.Quo(&a, &b)
-}
-
-// Quo sets z to the quotient x/y for y != 0 and returns z.
-// If y == 0, a division-by-zero run-time panic occurs.
-// Quo implements truncated division (like Go); see QuoRem for more details.
-func (z *Int) Quo(x, y *Int) *Int {
- z.abs, _ = z.abs.div(nil, x.abs, y.abs)
- z.neg = len(z.abs) > 0 && x.neg != y.neg // 0 has no sign
- return z
-}
-
-// Rem sets z to the remainder x%y for y != 0 and returns z.
-// If y == 0, a division-by-zero run-time panic occurs.
-// Rem implements truncated modulus (like Go); see QuoRem for more details.
-func (z *Int) Rem(x, y *Int) *Int {
- _, z.abs = nat(nil).div(z.abs, x.abs, y.abs)
- z.neg = len(z.abs) > 0 && x.neg // 0 has no sign
- return z
-}
-
-// QuoRem sets z to the quotient x/y and r to the remainder x%y
-// and returns the pair (z, r) for y != 0.
-// If y == 0, a division-by-zero run-time panic occurs.
-//
-// QuoRem implements T-division and modulus (like Go):
-//
-// q = x/y with the result truncated to zero
-// r = x - y*q
-//
-// (See Daan Leijen, ``Division and Modulus for Computer Scientists''.)
-// See DivMod for Euclidean division and modulus (unlike Go).
-//
-func (z *Int) QuoRem(x, y, r *Int) (*Int, *Int) {
- z.abs, r.abs = z.abs.div(r.abs, x.abs, y.abs)
- z.neg, r.neg = len(z.abs) > 0 && x.neg != y.neg, len(r.abs) > 0 && x.neg // 0 has no sign
- return z, r
-}
-
-// Div sets z to the quotient x/y for y != 0 and returns z.
-// If y == 0, a division-by-zero run-time panic occurs.
-// Div implements Euclidean division (unlike Go); see DivMod for more details.
-func (z *Int) Div(x, y *Int) *Int {
- y_neg := y.neg // z may be an alias for y
- var r Int
- z.QuoRem(x, y, &r)
- if r.neg {
- if y_neg {
- z.Add(z, intOne)
- } else {
- z.Sub(z, intOne)
- }
- }
- return z
-}
-
-// Mod sets z to the modulus x%y for y != 0 and returns z.
-// If y == 0, a division-by-zero run-time panic occurs.
-// Mod implements Euclidean modulus (unlike Go); see DivMod for more details.
-func (z *Int) Mod(x, y *Int) *Int {
- y0 := y // save y
- if z == y || alias(z.abs, y.abs) {
- y0 = new(Int).Set(y)
- }
- var q Int
- q.QuoRem(x, y, z)
- if z.neg {
- if y0.neg {
- z.Sub(z, y0)
- } else {
- z.Add(z, y0)
- }
- }
- return z
-}
-
-// DivMod sets z to the quotient x div y and m to the modulus x mod y
-// and returns the pair (z, m) for y != 0.
-// If y == 0, a division-by-zero run-time panic occurs.
-//
-// DivMod implements Euclidean division and modulus (unlike Go):
-//
-// q = x div y such that
-// m = x - y*q with 0 <= m < |y|
-//
-// (See Raymond T. Boute, ``The Euclidean definition of the functions
-// div and mod''. ACM Transactions on Programming Languages and
-// Systems (TOPLAS), 14(2):127-144, New York, NY, USA, 4/1992.
-// ACM press.)
-// See QuoRem for T-division and modulus (like Go).
-//
-func (z *Int) DivMod(x, y, m *Int) (*Int, *Int) {
- y0 := y // save y
- if z == y || alias(z.abs, y.abs) {
- y0 = new(Int).Set(y)
- }
- z.QuoRem(x, y, m)
- if m.neg {
- if y0.neg {
- z.Add(z, intOne)
- m.Sub(m, y0)
- } else {
- z.Sub(z, intOne)
- m.Add(m, y0)
- }
- }
- return z, m
-}
-
-// Cmp compares x and y and returns:
-//
-// -1 if x < y
-// 0 if x == y
-// +1 if x > y
-//
-func (x *Int) Cmp(y *Int) (r int) {
- // x cmp y == x cmp y
- // x cmp (-y) == x
- // (-x) cmp y == y
- // (-x) cmp (-y) == -(x cmp y)
- switch {
- case x.neg == y.neg:
- r = x.abs.cmp(y.abs)
- if x.neg {
- r = -r
- }
- case x.neg:
- r = -1
- default:
- r = 1
- }
- return
-}
-
-// low32 returns the least significant 32 bits of z.
-func low32(z nat) uint32 {
- if len(z) == 0 {
- return 0
- }
- return uint32(z[0])
-}
-
-// low64 returns the least significant 64 bits of z.
-func low64(z nat) uint64 {
- if len(z) == 0 {
- return 0
- }
- v := uint64(z[0])
- if _W == 32 && len(z) > 1 {
- v |= uint64(z[1]) << 32
- }
- return v
-}
-
-// Int64 returns the int64 representation of x.
-// If x cannot be represented in an int64, the result is undefined.
-func (x *Int) Int64() int64 {
- v := int64(low64(x.abs))
- if x.neg {
- v = -v
- }
- return v
-}
-
-// Uint64 returns the uint64 representation of x.
-// If x cannot be represented in a uint64, the result is undefined.
-func (x *Int) Uint64() uint64 {
- return low64(x.abs)
-}
-
-// SetString sets z to the value of s, interpreted in the given base,
-// and returns z and a boolean indicating success. If SetString fails,
-// the value of z is undefined but the returned value is nil.
-//
-// The base argument must be 0 or a value between 2 and MaxBase. If the base
-// is 0, the string prefix determines the actual conversion base. A prefix of
-// ``0x'' or ``0X'' selects base 16; the ``0'' prefix selects base 8, and a
-// ``0b'' or ``0B'' prefix selects base 2. Otherwise the selected base is 10.
-//
-func (z *Int) SetString(s string, base int) (*Int, bool) {
- r := strings.NewReader(s)
- _, _, err := z.scan(r, base)
- if err != nil {
- return nil, false
- }
- _, err = r.ReadByte()
- if err != io.EOF {
- return nil, false
- }
- return z, true // err == io.EOF => scan consumed all of s
-}
-
-// SetBytes interprets buf as the bytes of a big-endian unsigned
-// integer, sets z to that value, and returns z.
-func (z *Int) SetBytes(buf []byte) *Int {
- z.abs = z.abs.setBytes(buf)
- z.neg = false
- return z
-}
-
-// Bytes returns the absolute value of x as a big-endian byte slice.
-func (x *Int) Bytes() []byte {
- buf := make([]byte, len(x.abs)*_S)
- return buf[x.abs.bytes(buf):]
-}
-
-// BitLen returns the length of the absolute value of x in bits.
-// The bit length of 0 is 0.
-func (x *Int) BitLen() int {
- return x.abs.bitLen()
-}
-
-// Exp sets z = x**y mod |m| (i.e. the sign of m is ignored), and returns z.
-// If y <= 0, the result is 1 mod |m|; if m == nil or m == 0, z = x**y.
-// See Knuth, volume 2, section 4.6.3.
-func (z *Int) Exp(x, y, m *Int) *Int {
- var yWords nat
- if !y.neg {
- yWords = y.abs
- }
- // y >= 0
-
- var mWords nat
- if m != nil {
- mWords = m.abs // m.abs may be nil for m == 0
- }
-
- z.abs = z.abs.expNN(x.abs, yWords, mWords)
- z.neg = len(z.abs) > 0 && x.neg && len(yWords) > 0 && yWords[0]&1 == 1 // 0 has no sign
- if z.neg && len(mWords) > 0 {
- // make modulus result positive
- z.abs = z.abs.sub(mWords, z.abs) // z == x**y mod |m| && 0 <= z < |m|
- z.neg = false
- }
-
- return z
-}
-
-// GCD sets z to the greatest common divisor of a and b, which both must
-// be > 0, and returns z.
-// If x and y are not nil, GCD sets x and y such that z = a*x + b*y.
-// If either a or b is <= 0, GCD sets z = x = y = 0.
-func (z *Int) GCD(x, y, a, b *Int) *Int {
- if a.Sign() <= 0 || b.Sign() <= 0 {
- z.SetInt64(0)
- if x != nil {
- x.SetInt64(0)
- }
- if y != nil {
- y.SetInt64(0)
- }
- return z
- }
- if x == nil && y == nil {
- return z.binaryGCD(a, b)
- }
-
- A := new(Int).Set(a)
- B := new(Int).Set(b)
-
- X := new(Int)
- Y := new(Int).SetInt64(1)
-
- lastX := new(Int).SetInt64(1)
- lastY := new(Int)
-
- q := new(Int)
- temp := new(Int)
-
- for len(B.abs) > 0 {
- r := new(Int)
- q, r = q.QuoRem(A, B, r)
-
- A, B = B, r
-
- temp.Set(X)
- X.Mul(X, q)
- X.neg = !X.neg
- X.Add(X, lastX)
- lastX.Set(temp)
-
- temp.Set(Y)
- Y.Mul(Y, q)
- Y.neg = !Y.neg
- Y.Add(Y, lastY)
- lastY.Set(temp)
- }
-
- if x != nil {
- *x = *lastX
- }
-
- if y != nil {
- *y = *lastY
- }
-
- *z = *A
- return z
-}
-
-// binaryGCD sets z to the greatest common divisor of a and b, which both must
-// be > 0, and returns z.
-// See Knuth, The Art of Computer Programming, Vol. 2, Section 4.5.2, Algorithm B.
-func (z *Int) binaryGCD(a, b *Int) *Int {
- u := z
- v := new(Int)
-
- // use one Euclidean iteration to ensure that u and v are approx. the same size
- switch {
- case len(a.abs) > len(b.abs):
- // must set v before u since u may be alias for a or b (was issue #11284)
- v.Rem(a, b)
- u.Set(b)
- case len(a.abs) < len(b.abs):
- v.Rem(b, a)
- u.Set(a)
- default:
- v.Set(b)
- u.Set(a)
- }
- // a, b must not be used anymore (may be aliases with u)
-
- // v might be 0 now
- if len(v.abs) == 0 {
- return u
- }
- // u > 0 && v > 0
-
- // determine largest k such that u = u' << k, v = v' << k
- k := u.abs.trailingZeroBits()
- if vk := v.abs.trailingZeroBits(); vk < k {
- k = vk
- }
- u.Rsh(u, k)
- v.Rsh(v, k)
-
- // determine t (we know that u > 0)
- t := new(Int)
- if u.abs[0]&1 != 0 {
- // u is odd
- t.Neg(v)
- } else {
- t.Set(u)
- }
-
- for len(t.abs) > 0 {
- // reduce t
- t.Rsh(t, t.abs.trailingZeroBits())
- if t.neg {
- v, t = t, v
- v.neg = len(v.abs) > 0 && !v.neg // 0 has no sign
- } else {
- u, t = t, u
- }
- t.Sub(u, v)
- }
-
- return z.Lsh(u, k)
-}
-
-// ProbablyPrime performs n Miller-Rabin tests to check whether x is prime.
-// If x is prime, it returns true.
-// If x is not prime, it returns false with probability at least 1 - ¼ⁿ.
-//
-// It is not suitable for judging primes that an adversary may have crafted
-// to fool this test.
-func (x *Int) ProbablyPrime(n int) bool {
- if n <= 0 {
- panic("non-positive n for ProbablyPrime")
- }
- return !x.neg && x.abs.probablyPrime(n)
-}
-
-// Rand sets z to a pseudo-random number in [0, n) and returns z.
-func (z *Int) Rand(rnd *rand.Rand, n *Int) *Int {
- z.neg = false
- if n.neg == true || len(n.abs) == 0 {
- z.abs = nil
- return z
- }
- z.abs = z.abs.random(rnd, n.abs, n.abs.bitLen())
- return z
-}
-
-// ModInverse sets z to the multiplicative inverse of g in the ring ℤ/nℤ
-// and returns z. If g and n are not relatively prime, the result is undefined.
-func (z *Int) ModInverse(g, n *Int) *Int {
- var d Int
- d.GCD(z, nil, g, n)
- // x and y are such that g*x + n*y = d. Since g and n are
- // relatively prime, d = 1. Taking that modulo n results in
- // g*x = 1, therefore x is the inverse element.
- if z.neg {
- z.Add(z, n)
- }
- return z
-}
-
-// Jacobi returns the Jacobi symbol (x/y), either +1, -1, or 0.
-// The y argument must be an odd integer.
-func Jacobi(x, y *Int) int {
- if len(y.abs) == 0 || y.abs[0]&1 == 0 {
- panic(fmt.Sprintf("big: invalid 2nd argument to Int.Jacobi: need odd integer but got %s", y))
- }
-
- // We use the formulation described in chapter 2, section 2.4,
- // "The Yacas Book of Algorithms":
- // http://yacas.sourceforge.net/Algo.book.pdf
-
- var a, b, c Int
- a.Set(x)
- b.Set(y)
- j := 1
-
- if b.neg {
- if a.neg {
- j = -1
- }
- b.neg = false
- }
-
- for {
- if b.Cmp(intOne) == 0 {
- return j
- }
- if len(a.abs) == 0 {
- return 0
- }
- a.Mod(&a, &b)
- if len(a.abs) == 0 {
- return 0
- }
- // a > 0
-
- // handle factors of 2 in 'a'
- s := a.abs.trailingZeroBits()
- if s&1 != 0 {
- bmod8 := b.abs[0] & 7
- if bmod8 == 3 || bmod8 == 5 {
- j = -j
- }
- }
- c.Rsh(&a, s) // a = 2^s*c
-
- // swap numerator and denominator
- if b.abs[0]&3 == 3 && c.abs[0]&3 == 3 {
- j = -j
- }
- a.Set(&b)
- b.Set(&c)
- }
-}
-
-// modSqrt3Mod4 uses the identity
-// (a^((p+1)/4))^2 mod p
-// == u^(p+1) mod p
-// == u^2 mod p
-// to calculate the square root of any quadratic residue mod p quickly for 3
-// mod 4 primes.
-func (z *Int) modSqrt3Mod4Prime(x, p *Int) *Int {
- z.Set(p) // z = p
- z.Add(z, intOne) // z = p + 1
- z.Rsh(z, 2) // z = (p + 1) / 4
- z.Exp(x, z, p) // z = x^z mod p
- return z
-}
-
-// modSqrtTonelliShanks uses the Tonelli-Shanks algorithm to find the square
-// root of a quadratic residue modulo any prime.
-func (z *Int) modSqrtTonelliShanks(x, p *Int) *Int {
- // Break p-1 into s*2^e such that s is odd.
- var s Int
- s.Sub(p, intOne)
- e := s.abs.trailingZeroBits()
- s.Rsh(&s, e)
-
- // find some non-square n
- var n Int
- n.SetInt64(2)
- for Jacobi(&n, p) != -1 {
- n.Add(&n, intOne)
- }
-
- // Core of the Tonelli-Shanks algorithm. Follows the description in
- // section 6 of "Square roots from 1; 24, 51, 10 to Dan Shanks" by Ezra
- // Brown:
- // https://www.maa.org/sites/default/files/pdf/upload_library/22/Polya/07468342.di020786.02p0470a.pdf
- var y, b, g, t Int
- y.Add(&s, intOne)
- y.Rsh(&y, 1)
- y.Exp(x, &y, p) // y = x^((s+1)/2)
- b.Exp(x, &s, p) // b = x^s
- g.Exp(&n, &s, p) // g = n^s
- r := e
- for {
- // find the least m such that ord_p(b) = 2^m
- var m uint
- t.Set(&b)
- for t.Cmp(intOne) != 0 {
- t.Mul(&t, &t).Mod(&t, p)
- m++
- }
-
- if m == 0 {
- return z.Set(&y)
- }
-
- t.SetInt64(0).SetBit(&t, int(r-m-1), 1).Exp(&g, &t, p)
- // t = g^(2^(r-m-1)) mod p
- g.Mul(&t, &t).Mod(&g, p) // g = g^(2^(r-m)) mod p
- y.Mul(&y, &t).Mod(&y, p)
- b.Mul(&b, &g).Mod(&b, p)
- r = m
- }
-}
-
-// ModSqrt sets z to a square root of x mod p if such a square root exists, and
-// returns z. The modulus p must be an odd prime. If x is not a square mod p,
-// ModSqrt leaves z unchanged and returns nil. This function panics if p is
-// not an odd integer.
-func (z *Int) ModSqrt(x, p *Int) *Int {
- switch Jacobi(x, p) {
- case -1:
- return nil // x is not a square mod p
- case 0:
- return z.SetInt64(0) // sqrt(0) mod p = 0
- case 1:
- break
- }
- if x.neg || x.Cmp(p) >= 0 { // ensure 0 <= x < p
- x = new(Int).Mod(x, p)
- }
-
- // Check whether p is 3 mod 4, and if so, use the faster algorithm.
- if len(p.abs) > 0 && p.abs[0]%4 == 3 {
- return z.modSqrt3Mod4Prime(x, p)
- }
- // Otherwise, use Tonelli-Shanks.
- return z.modSqrtTonelliShanks(x, p)
-}
-
-// Lsh sets z = x << n and returns z.
-func (z *Int) Lsh(x *Int, n uint) *Int {
- z.abs = z.abs.shl(x.abs, n)
- z.neg = x.neg
- return z
-}
-
-// Rsh sets z = x >> n and returns z.
-func (z *Int) Rsh(x *Int, n uint) *Int {
- if x.neg {
- // (-x) >> s == ^(x-1) >> s == ^((x-1) >> s) == -(((x-1) >> s) + 1)
- t := z.abs.sub(x.abs, natOne) // no underflow because |x| > 0
- t = t.shr(t, n)
- z.abs = t.add(t, natOne)
- z.neg = true // z cannot be zero if x is negative
- return z
- }
-
- z.abs = z.abs.shr(x.abs, n)
- z.neg = false
- return z
-}
-
-// Bit returns the value of the i'th bit of x. That is, it
-// returns (x>>i)&1. The bit index i must be >= 0.
-func (x *Int) Bit(i int) uint {
- if i == 0 {
- // optimization for common case: odd/even test of x
- if len(x.abs) > 0 {
- return uint(x.abs[0] & 1) // bit 0 is same for -x
- }
- return 0
- }
- if i < 0 {
- panic("negative bit index")
- }
- if x.neg {
- t := nat(nil).sub(x.abs, natOne)
- return t.bit(uint(i)) ^ 1
- }
-
- return x.abs.bit(uint(i))
-}
-
-// SetBit sets z to x, with x's i'th bit set to b (0 or 1).
-// That is, if b is 1 SetBit sets z = x | (1 << i);
-// if b is 0 SetBit sets z = x &^ (1 << i). If b is not 0 or 1,
-// SetBit will panic.
-func (z *Int) SetBit(x *Int, i int, b uint) *Int {
- if i < 0 {
- panic("negative bit index")
- }
- if x.neg {
- t := z.abs.sub(x.abs, natOne)
- t = t.setBit(t, uint(i), b^1)
- z.abs = t.add(t, natOne)
- z.neg = len(z.abs) > 0
- return z
- }
- z.abs = z.abs.setBit(x.abs, uint(i), b)
- z.neg = false
- return z
-}
-
-// And sets z = x & y and returns z.
-func (z *Int) And(x, y *Int) *Int {
- if x.neg == y.neg {
- if x.neg {
- // (-x) & (-y) == ^(x-1) & ^(y-1) == ^((x-1) | (y-1)) == -(((x-1) | (y-1)) + 1)
- x1 := nat(nil).sub(x.abs, natOne)
- y1 := nat(nil).sub(y.abs, natOne)
- z.abs = z.abs.add(z.abs.or(x1, y1), natOne)
- z.neg = true // z cannot be zero if x and y are negative
- return z
- }
-
- // x & y == x & y
- z.abs = z.abs.and(x.abs, y.abs)
- z.neg = false
- return z
- }
-
- // x.neg != y.neg
- if x.neg {
- x, y = y, x // & is symmetric
- }
-
- // x & (-y) == x & ^(y-1) == x &^ (y-1)
- y1 := nat(nil).sub(y.abs, natOne)
- z.abs = z.abs.andNot(x.abs, y1)
- z.neg = false
- return z
-}
-
-// AndNot sets z = x &^ y and returns z.
-func (z *Int) AndNot(x, y *Int) *Int {
- if x.neg == y.neg {
- if x.neg {
- // (-x) &^ (-y) == ^(x-1) &^ ^(y-1) == ^(x-1) & (y-1) == (y-1) &^ (x-1)
- x1 := nat(nil).sub(x.abs, natOne)
- y1 := nat(nil).sub(y.abs, natOne)
- z.abs = z.abs.andNot(y1, x1)
- z.neg = false
- return z
- }
-
- // x &^ y == x &^ y
- z.abs = z.abs.andNot(x.abs, y.abs)
- z.neg = false
- return z
- }
-
- if x.neg {
- // (-x) &^ y == ^(x-1) &^ y == ^(x-1) & ^y == ^((x-1) | y) == -(((x-1) | y) + 1)
- x1 := nat(nil).sub(x.abs, natOne)
- z.abs = z.abs.add(z.abs.or(x1, y.abs), natOne)
- z.neg = true // z cannot be zero if x is negative and y is positive
- return z
- }
-
- // x &^ (-y) == x &^ ^(y-1) == x & (y-1)
- y1 := nat(nil).sub(y.abs, natOne)
- z.abs = z.abs.and(x.abs, y1)
- z.neg = false
- return z
-}
-
-// Or sets z = x | y and returns z.
-func (z *Int) Or(x, y *Int) *Int {
- if x.neg == y.neg {
- if x.neg {
- // (-x) | (-y) == ^(x-1) | ^(y-1) == ^((x-1) & (y-1)) == -(((x-1) & (y-1)) + 1)
- x1 := nat(nil).sub(x.abs, natOne)
- y1 := nat(nil).sub(y.abs, natOne)
- z.abs = z.abs.add(z.abs.and(x1, y1), natOne)
- z.neg = true // z cannot be zero if x and y are negative
- return z
- }
-
- // x | y == x | y
- z.abs = z.abs.or(x.abs, y.abs)
- z.neg = false
- return z
- }
-
- // x.neg != y.neg
- if x.neg {
- x, y = y, x // | is symmetric
- }
-
- // x | (-y) == x | ^(y-1) == ^((y-1) &^ x) == -(^((y-1) &^ x) + 1)
- y1 := nat(nil).sub(y.abs, natOne)
- z.abs = z.abs.add(z.abs.andNot(y1, x.abs), natOne)
- z.neg = true // z cannot be zero if one of x or y is negative
- return z
-}
-
-// Xor sets z = x ^ y and returns z.
-func (z *Int) Xor(x, y *Int) *Int {
- if x.neg == y.neg {
- if x.neg {
- // (-x) ^ (-y) == ^(x-1) ^ ^(y-1) == (x-1) ^ (y-1)
- x1 := nat(nil).sub(x.abs, natOne)
- y1 := nat(nil).sub(y.abs, natOne)
- z.abs = z.abs.xor(x1, y1)
- z.neg = false
- return z
- }
-
- // x ^ y == x ^ y
- z.abs = z.abs.xor(x.abs, y.abs)
- z.neg = false
- return z
- }
-
- // x.neg != y.neg
- if x.neg {
- x, y = y, x // ^ is symmetric
- }
-
- // x ^ (-y) == x ^ ^(y-1) == ^(x ^ (y-1)) == -((x ^ (y-1)) + 1)
- y1 := nat(nil).sub(y.abs, natOne)
- z.abs = z.abs.add(z.abs.xor(x.abs, y1), natOne)
- z.neg = true // z cannot be zero if only one of x or y is negative
- return z
-}
-
-// Not sets z = ^x and returns z.
-func (z *Int) Not(x *Int) *Int {
- if x.neg {
- // ^(-x) == ^(^(x-1)) == x-1
- z.abs = z.abs.sub(x.abs, natOne)
- z.neg = false
- return z
- }
-
- // ^x == -x-1 == -(x+1)
- z.abs = z.abs.add(x.abs, natOne)
- z.neg = true // z cannot be zero if x is positive
- return z
-}
diff --git a/src/cmd/compile/internal/big/int_test.go b/src/cmd/compile/internal/big/int_test.go
deleted file mode 100644
index 45a3765..0000000
--- a/src/cmd/compile/internal/big/int_test.go
+++ /dev/null
@@ -1,1482 +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 big
-
-import (
- "bytes"
- "encoding/hex"
- "fmt"
- "math/rand"
- "testing"
- "testing/quick"
-)
-
-func isNormalized(x *Int) bool {
- if len(x.abs) == 0 {
- return !x.neg
- }
- // len(x.abs) > 0
- return x.abs[len(x.abs)-1] != 0
-}
-
-type funZZ func(z, x, y *Int) *Int
-type argZZ struct {
- z, x, y *Int
-}
-
-var sumZZ = []argZZ{
- {NewInt(0), NewInt(0), NewInt(0)},
- {NewInt(1), NewInt(1), NewInt(0)},
- {NewInt(1111111110), NewInt(123456789), NewInt(987654321)},
- {NewInt(-1), NewInt(-1), NewInt(0)},
- {NewInt(864197532), NewInt(-123456789), NewInt(987654321)},
- {NewInt(-1111111110), NewInt(-123456789), NewInt(-987654321)},
-}
-
-var prodZZ = []argZZ{
- {NewInt(0), NewInt(0), NewInt(0)},
- {NewInt(0), NewInt(1), NewInt(0)},
- {NewInt(1), NewInt(1), NewInt(1)},
- {NewInt(-991 * 991), NewInt(991), NewInt(-991)},
- // TODO(gri) add larger products
-}
-
-func TestSignZ(t *testing.T) {
- var zero Int
- for _, a := range sumZZ {
- s := a.z.Sign()
- e := a.z.Cmp(&zero)
- if s != e {
- t.Errorf("got %d; want %d for z = %v", s, e, a.z)
- }
- }
-}
-
-func TestSetZ(t *testing.T) {
- for _, a := range sumZZ {
- var z Int
- z.Set(a.z)
- if !isNormalized(&z) {
- t.Errorf("%v is not normalized", z)
- }
- if (&z).Cmp(a.z) != 0 {
- t.Errorf("got z = %v; want %v", z, a.z)
- }
- }
-}
-
-func TestAbsZ(t *testing.T) {
- var zero Int
- for _, a := range sumZZ {
- var z Int
- z.Abs(a.z)
- var e Int
- e.Set(a.z)
- if e.Cmp(&zero) < 0 {
- e.Sub(&zero, &e)
- }
- if z.Cmp(&e) != 0 {
- t.Errorf("got z = %v; want %v", z, e)
- }
- }
-}
-
-func testFunZZ(t *testing.T, msg string, f funZZ, a argZZ) {
- var z Int
- f(&z, a.x, a.y)
- if !isNormalized(&z) {
- t.Errorf("%s%v is not normalized", msg, z)
- }
- if (&z).Cmp(a.z) != 0 {
- t.Errorf("%s%+v\n\tgot z = %v; want %v", msg, a, &z, a.z)
- }
-}
-
-func TestSumZZ(t *testing.T) {
- AddZZ := func(z, x, y *Int) *Int { return z.Add(x, y) }
- SubZZ := func(z, x, y *Int) *Int { return z.Sub(x, y) }
- for _, a := range sumZZ {
- arg := a
- testFunZZ(t, "AddZZ", AddZZ, arg)
-
- arg = argZZ{a.z, a.y, a.x}
- testFunZZ(t, "AddZZ symmetric", AddZZ, arg)
-
- arg = argZZ{a.x, a.z, a.y}
- testFunZZ(t, "SubZZ", SubZZ, arg)
-
- arg = argZZ{a.y, a.z, a.x}
- testFunZZ(t, "SubZZ symmetric", SubZZ, arg)
- }
-}
-
-func TestProdZZ(t *testing.T) {
- MulZZ := func(z, x, y *Int) *Int { return z.Mul(x, y) }
- for _, a := range prodZZ {
- arg := a
- testFunZZ(t, "MulZZ", MulZZ, arg)
-
- arg = argZZ{a.z, a.y, a.x}
- testFunZZ(t, "MulZZ symmetric", MulZZ, arg)
- }
-}
-
-// mulBytes returns x*y via grade school multiplication. Both inputs
-// and the result are assumed to be in big-endian representation (to
-// match the semantics of Int.Bytes and Int.SetBytes).
-func mulBytes(x, y []byte) []byte {
- z := make([]byte, len(x)+len(y))
-
- // multiply
- k0 := len(z) - 1
- for j := len(y) - 1; j >= 0; j-- {
- d := int(y[j])
- if d != 0 {
- k := k0
- carry := 0
- for i := len(x) - 1; i >= 0; i-- {
- t := int(z[k]) + int(x[i])*d + carry
- z[k], carry = byte(t), t>>8
- k--
- }
- z[k] = byte(carry)
- }
- k0--
- }
-
- // normalize (remove leading 0's)
- i := 0
- for i < len(z) && z[i] == 0 {
- i++
- }
-
- return z[i:]
-}
-
-func checkMul(a, b []byte) bool {
- var x, y, z1 Int
- x.SetBytes(a)
- y.SetBytes(b)
- z1.Mul(&x, &y)
-
- var z2 Int
- z2.SetBytes(mulBytes(a, b))
-
- return z1.Cmp(&z2) == 0
-}
-
-func TestMul(t *testing.T) {
- if err := quick.Check(checkMul, nil); err != nil {
- t.Error(err)
- }
-}
-
-var mulRangesZ = []struct {
- a, b int64
- prod string
-}{
- // entirely positive ranges are covered by mulRangesN
- {-1, 1, "0"},
- {-2, -1, "2"},
- {-3, -2, "6"},
- {-3, -1, "-6"},
- {1, 3, "6"},
- {-10, -10, "-10"},
- {0, -1, "1"}, // empty range
- {-1, -100, "1"}, // empty range
- {-1, 1, "0"}, // range includes 0
- {-1e9, 0, "0"}, // range includes 0
- {-1e9, 1e9, "0"}, // range includes 0
- {-10, -1, "3628800"}, // 10!
- {-20, -2, "-2432902008176640000"}, // -20!
- {-99, -1,
- "-933262154439441526816992388562667004907159682643816214685929" +
- "638952175999932299156089414639761565182862536979208272237582" +
- "511852109168640000000000000000000000", // -99!
- },
-}
-
-func TestMulRangeZ(t *testing.T) {
- var tmp Int
- // test entirely positive ranges
- for i, r := range mulRangesN {
- prod := tmp.MulRange(int64(r.a), int64(r.b)).String()
- if prod != r.prod {
- t.Errorf("#%da: got %s; want %s", i, prod, r.prod)
- }
- }
- // test other ranges
- for i, r := range mulRangesZ {
- prod := tmp.MulRange(r.a, r.b).String()
- if prod != r.prod {
- t.Errorf("#%db: got %s; want %s", i, prod, r.prod)
- }
- }
-}
-
-func TestBinomial(t *testing.T) {
- var z Int
- for _, test := range []struct {
- n, k int64
- want string
- }{
- {0, 0, "1"},
- {0, 1, "0"},
- {1, 0, "1"},
- {1, 1, "1"},
- {1, 10, "0"},
- {4, 0, "1"},
- {4, 1, "4"},
- {4, 2, "6"},
- {4, 3, "4"},
- {4, 4, "1"},
- {10, 1, "10"},
- {10, 9, "10"},
- {10, 5, "252"},
- {11, 5, "462"},
- {11, 6, "462"},
- {100, 10, "17310309456440"},
- {100, 90, "17310309456440"},
- {1000, 10, "263409560461970212832400"},
- {1000, 990, "263409560461970212832400"},
- } {
- if got := z.Binomial(test.n, test.k).String(); got != test.want {
- t.Errorf("Binomial(%d, %d) = %s; want %s", test.n, test.k, got, test.want)
- }
- }
-}
-
-func BenchmarkBinomial(b *testing.B) {
- var z Int
- for i := b.N - 1; i >= 0; i-- {
- z.Binomial(1000, 990)
- }
-}
-
-// Examples from the Go Language Spec, section "Arithmetic operators"
-var divisionSignsTests = []struct {
- x, y int64
- q, r int64 // T-division
- d, m int64 // Euclidian division
-}{
- {5, 3, 1, 2, 1, 2},
- {-5, 3, -1, -2, -2, 1},
- {5, -3, -1, 2, -1, 2},
- {-5, -3, 1, -2, 2, 1},
- {1, 2, 0, 1, 0, 1},
- {8, 4, 2, 0, 2, 0},
-}
-
-func TestDivisionSigns(t *testing.T) {
- for i, test := range divisionSignsTests {
- x := NewInt(test.x)
- y := NewInt(test.y)
- q := NewInt(test.q)
- r := NewInt(test.r)
- d := NewInt(test.d)
- m := NewInt(test.m)
-
- q1 := new(Int).Quo(x, y)
- r1 := new(Int).Rem(x, y)
- if !isNormalized(q1) {
- t.Errorf("#%d Quo: %v is not normalized", i, *q1)
- }
- if !isNormalized(r1) {
- t.Errorf("#%d Rem: %v is not normalized", i, *r1)
- }
- if q1.Cmp(q) != 0 || r1.Cmp(r) != 0 {
- t.Errorf("#%d QuoRem: got (%s, %s), want (%s, %s)", i, q1, r1, q, r)
- }
-
- q2, r2 := new(Int).QuoRem(x, y, new(Int))
- if !isNormalized(q2) {
- t.Errorf("#%d Quo: %v is not normalized", i, *q2)
- }
- if !isNormalized(r2) {
- t.Errorf("#%d Rem: %v is not normalized", i, *r2)
- }
- if q2.Cmp(q) != 0 || r2.Cmp(r) != 0 {
- t.Errorf("#%d QuoRem: got (%s, %s), want (%s, %s)", i, q2, r2, q, r)
- }
-
- d1 := new(Int).Div(x, y)
- m1 := new(Int).Mod(x, y)
- if !isNormalized(d1) {
- t.Errorf("#%d Div: %v is not normalized", i, *d1)
- }
- if !isNormalized(m1) {
- t.Errorf("#%d Mod: %v is not normalized", i, *m1)
- }
- if d1.Cmp(d) != 0 || m1.Cmp(m) != 0 {
- t.Errorf("#%d DivMod: got (%s, %s), want (%s, %s)", i, d1, m1, d, m)
- }
-
- d2, m2 := new(Int).DivMod(x, y, new(Int))
- if !isNormalized(d2) {
- t.Errorf("#%d Div: %v is not normalized", i, *d2)
- }
- if !isNormalized(m2) {
- t.Errorf("#%d Mod: %v is not normalized", i, *m2)
- }
- if d2.Cmp(d) != 0 || m2.Cmp(m) != 0 {
- t.Errorf("#%d DivMod: got (%s, %s), want (%s, %s)", i, d2, m2, d, m)
- }
- }
-}
-
-func norm(x nat) nat {
- i := len(x)
- for i > 0 && x[i-1] == 0 {
- i--
- }
- return x[:i]
-}
-
-func TestBits(t *testing.T) {
- for _, test := range []nat{
- nil,
- {0},
- {1},
- {0, 1, 2, 3, 4},
- {4, 3, 2, 1, 0},
- {4, 3, 2, 1, 0, 0, 0, 0},
- } {
- var z Int
- z.neg = true
- got := z.SetBits(test)
- want := norm(test)
- if got.abs.cmp(want) != 0 {
- t.Errorf("SetBits(%v) = %v; want %v", test, got.abs, want)
- }
-
- if got.neg {
- t.Errorf("SetBits(%v): got negative result", test)
- }
-
- bits := nat(z.Bits())
- if bits.cmp(want) != 0 {
- t.Errorf("%v.Bits() = %v; want %v", z.abs, bits, want)
- }
- }
-}
-
-func checkSetBytes(b []byte) bool {
- hex1 := hex.EncodeToString(new(Int).SetBytes(b).Bytes())
- hex2 := hex.EncodeToString(b)
-
- for len(hex1) < len(hex2) {
- hex1 = "0" + hex1
- }
-
- for len(hex1) > len(hex2) {
- hex2 = "0" + hex2
- }
-
- return hex1 == hex2
-}
-
-func TestSetBytes(t *testing.T) {
- if err := quick.Check(checkSetBytes, nil); err != nil {
- t.Error(err)
- }
-}
-
-func checkBytes(b []byte) bool {
- // trim leading zero bytes since Bytes() won't return them
- // (was issue 12231)
- for len(b) > 0 && b[0] == 0 {
- b = b[1:]
- }
- b2 := new(Int).SetBytes(b).Bytes()
- return bytes.Equal(b, b2)
-}
-
-func TestBytes(t *testing.T) {
- if err := quick.Check(checkBytes, nil); err != nil {
- t.Error(err)
- }
-}
-
-func checkQuo(x, y []byte) bool {
- u := new(Int).SetBytes(x)
- v := new(Int).SetBytes(y)
-
- if len(v.abs) == 0 {
- return true
- }
-
- r := new(Int)
- q, r := new(Int).QuoRem(u, v, r)
-
- if r.Cmp(v) >= 0 {
- return false
- }
-
- uprime := new(Int).Set(q)
- uprime.Mul(uprime, v)
- uprime.Add(uprime, r)
-
- return uprime.Cmp(u) == 0
-}
-
-var quoTests = []struct {
- x, y string
- q, r string
-}{
- {
- "476217953993950760840509444250624797097991362735329973741718102894495832294430498335824897858659711275234906400899559094370964723884706254265559534144986498357",
- "9353930466774385905609975137998169297361893554149986716853295022578535724979483772383667534691121982974895531435241089241440253066816724367338287092081996",
- "50911",
- "1",
- },
- {
- "11510768301994997771168",
- "1328165573307167369775",
- "8",
- "885443715537658812968",
- },
-}
-
-func TestQuo(t *testing.T) {
- if err := quick.Check(checkQuo, nil); err != nil {
- t.Error(err)
- }
-
- for i, test := range quoTests {
- x, _ := new(Int).SetString(test.x, 10)
- y, _ := new(Int).SetString(test.y, 10)
- expectedQ, _ := new(Int).SetString(test.q, 10)
- expectedR, _ := new(Int).SetString(test.r, 10)
-
- r := new(Int)
- q, r := new(Int).QuoRem(x, y, r)
-
- if q.Cmp(expectedQ) != 0 || r.Cmp(expectedR) != 0 {
- t.Errorf("#%d got (%s, %s) want (%s, %s)", i, q, r, expectedQ, expectedR)
- }
- }
-}
-
-func TestQuoStepD6(t *testing.T) {
- // See Knuth, Volume 2, section 4.3.1, exercise 21. This code exercises
- // a code path which only triggers 1 in 10^{-19} cases.
-
- u := &Int{false, nat{0, 0, 1 + 1<<(_W-1), _M ^ (1 << (_W - 1))}}
- v := &Int{false, nat{5, 2 + 1<<(_W-1), 1 << (_W - 1)}}
-
- r := new(Int)
- q, r := new(Int).QuoRem(u, v, r)
- const expectedQ64 = "18446744073709551613"
- const expectedR64 = "3138550867693340382088035895064302439801311770021610913807"
- const expectedQ32 = "4294967293"
- const expectedR32 = "39614081266355540837921718287"
- if q.String() != expectedQ64 && q.String() != expectedQ32 ||
- r.String() != expectedR64 && r.String() != expectedR32 {
- t.Errorf("got (%s, %s) want (%s, %s) or (%s, %s)", q, r, expectedQ64, expectedR64, expectedQ32, expectedR32)
- }
-}
-
-var bitLenTests = []struct {
- in string
- out int
-}{
- {"-1", 1},
- {"0", 0},
- {"1", 1},
- {"2", 2},
- {"4", 3},
- {"0xabc", 12},
- {"0x8000", 16},
- {"0x80000000", 32},
- {"0x800000000000", 48},
- {"0x8000000000000000", 64},
- {"0x80000000000000000000", 80},
- {"-0x4000000000000000000000", 87},
-}
-
-func TestBitLen(t *testing.T) {
- for i, test := range bitLenTests {
- x, ok := new(Int).SetString(test.in, 0)
- if !ok {
- t.Errorf("#%d test input invalid: %s", i, test.in)
- continue
- }
-
- if n := x.BitLen(); n != test.out {
- t.Errorf("#%d got %d want %d", i, n, test.out)
- }
- }
-}
-
-var expTests = []struct {
- x, y, m string
- out string
-}{
- // y <= 0
- {"0", "0", "", "1"},
- {"1", "0", "", "1"},
- {"-10", "0", "", "1"},
- {"1234", "-1", "", "1"},
-
- // m == 1
- {"0", "0", "1", "0"},
- {"1", "0", "1", "0"},
- {"-10", "0", "1", "0"},
- {"1234", "-1", "1", "0"},
-
- // misc
- {"5", "1", "3", "2"},
- {"5", "-7", "", "1"},
- {"-5", "-7", "", "1"},
- {"5", "0", "", "1"},
- {"-5", "0", "", "1"},
- {"5", "1", "", "5"},
- {"-5", "1", "", "-5"},
- {"-5", "1", "7", "2"},
- {"-2", "3", "2", "0"},
- {"5", "2", "", "25"},
- {"1", "65537", "2", "1"},
- {"0x8000000000000000", "2", "", "0x40000000000000000000000000000000"},
- {"0x8000000000000000", "2", "6719", "4944"},
- {"0x8000000000000000", "3", "6719", "5447"},
- {"0x8000000000000000", "1000", "6719", "1603"},
- {"0x8000000000000000", "1000000", "6719", "3199"},
- {"0x8000000000000000", "-1000000", "6719", "1"},
-
- {"0xffffffffffffffffffffffffffffffff", "0x12345678123456781234567812345678123456789", "0x01112222333344445555666677778889", "0x36168FA1DB3AAE6C8CE647E137F97A"},
-
- {
- "2938462938472983472983659726349017249287491026512746239764525612965293865296239471239874193284792387498274256129746192347",
- "298472983472983471903246121093472394872319615612417471234712061",
- "29834729834729834729347290846729561262544958723956495615629569234729836259263598127342374289365912465901365498236492183464",
- "23537740700184054162508175125554701713153216681790245129157191391322321508055833908509185839069455749219131480588829346291",
- },
- // test case for issue 8822
- {
- "110012891183630896460173593721179634992505463752690475427779280061032468766887567357609056806046466243531968695727526232851404087554203740493176464281852700795553727635031156460546028675936629238941409408374795071949342675328316945655164667650254349023483145256274185156465881609558628390220513536530529470731360847807427297278748034576438481974995482975700269269275025056342970795272990042677697807685656954599452355868926270591788849987729893975050612063954555915037716775009312694775035 [...]
- "0xB08FFB20760FFED58FADA86DFEF71AD72AA0FA763219618FE022C197E54708BB1191C66470250FCE8879487507CEE41381CA4D932F81C2B3F1AB20B539D50DCD",
- "0xAC6BDB41324A9A9BF166DE5E1389582FAF72B6651987EE07FC3192943DB56050A37329CBB4A099ED8193E0757767A13DD52312AB4B03310DCD7F48A9DA04FD50E8083969EDB767B0CF6095179A163AB3661A05FBD5FAAAE82918A9962F0B93B855F97993EC975EEAA80D740ADBF4FF747359D041D5C33EA71D281E446B14773BCA97B43A23FB801676BD207A436C6481F1D2B9078717461A5B9D32E688F87748544523B524B0D57D5EA77A2775D2ECFA032CFBDBF52FB3786160279004E57AE6AF874E7303CE53299CCC041C7BC308D82A5698F3A8D0C38271AE35F8E9DBFBB694B5C803D89F7AE435DE236D525F54759B65E37 [...]
- "214842521977763024996399388837777103219931130979872010505011829095813593576185795667465563725893853616836105247305090413288550665149633855225708948390358847130516401714741865487135466864767613064364341464751401562843891818086750165768458333404948482836810888865842197505544080605567694866280290287207273932931116788263564804554339092335205041120744013761330771504712375494741491902420104695390064495966115766125739557543490423291306311282346379247864665857034884605402284774408534933920862 [...]
- },
- {
- "-0x1BCE04427D8032319A89E5C4136456671AC620883F2C4139E57F91307C485AD2D6204F4F87A58262652DB5DBBAC72B0613E51B835E7153BEC6068F5C8D696B74DBD18FEC316AEF73985CF0475663208EB46B4F17DD9DA55367B03323E5491A70997B90C059FB34809E6EE55BCFBD5F2F52233BFE62E6AA9E4E26A1D4C2439883D14F2633D55D8AA66A1ACD5595E778AC3A280517F1157989E70C1A437B849F1877B779CC3CDDEDE2DAA6594A6C66D181A00A5F777EE60596D8773998F6E988DEAE4CCA60E4DDCF9590543C89F74F603259FCAD71660D30294FBBE6490300F78A9D63FA660DC9417B8B9DDA28BEB3977B621B98 [...]
- "0xB08FFB20760FFED58FADA86DFEF71AD72AA0FA763219618FE022C197E54708BB1191C66470250FCE8879487507CEE41381CA4D932F81C2B3F1AB20B539D50DCD",
- "0xAC6BDB41324A9A9BF166DE5E1389582FAF72B6651987EE07FC3192943DB56050A37329CBB4A099ED8193E0757767A13DD52312AB4B03310DCD7F48A9DA04FD50E8083969EDB767B0CF6095179A163AB3661A05FBD5FAAAE82918A9962F0B93B855F97993EC975EEAA80D740ADBF4FF747359D041D5C33EA71D281E446B14773BCA97B43A23FB801676BD207A436C6481F1D2B9078717461A5B9D32E688F87748544523B524B0D57D5EA77A2775D2ECFA032CFBDBF52FB3786160279004E57AE6AF874E7303CE53299CCC041C7BC308D82A5698F3A8D0C38271AE35F8E9DBFBB694B5C803D89F7AE435DE236D525F54759B65E37 [...]
- "214842521977763024996399388837777103219931130979872010505011829095813593576185795667465563725893853616836105247305090413288550665149633855225708948390358847130516401714741865487135466864767613064364341464751401562843891818086750165768458333404948482836810888865842197505544080605567694866280290287207273932931116788263564804554339092335205041120744013761330771504712375494741491902420104695390064495966115766125739557543490423291306311282346379247864665857034884605402284774408534933920862 [...]
- },
-
- // test cases for issue 13907
- {"0xffffffff00000001", "0xffffffff00000001", "0xffffffff00000001", "0"},
- {"0xffffffffffffffff00000001", "0xffffffffffffffff00000001", "0xffffffffffffffff00000001", "0"},
- {"0xffffffffffffffffffffffff00000001", "0xffffffffffffffffffffffff00000001", "0xffffffffffffffffffffffff00000001", "0"},
- {"0xffffffffffffffffffffffffffffffff00000001", "0xffffffffffffffffffffffffffffffff00000001", "0xffffffffffffffffffffffffffffffff00000001", "0"},
-}
-
-func TestExp(t *testing.T) {
- for i, test := range expTests {
- x, ok1 := new(Int).SetString(test.x, 0)
- y, ok2 := new(Int).SetString(test.y, 0)
- out, ok3 := new(Int).SetString(test.out, 0)
-
- var ok4 bool
- var m *Int
-
- if len(test.m) == 0 {
- m, ok4 = nil, true
- } else {
- m, ok4 = new(Int).SetString(test.m, 0)
- }
-
- if !ok1 || !ok2 || !ok3 || !ok4 {
- t.Errorf("#%d: error in input", i)
- continue
- }
-
- z1 := new(Int).Exp(x, y, m)
- if !isNormalized(z1) {
- t.Errorf("#%d: %v is not normalized", i, *z1)
- }
- if z1.Cmp(out) != 0 {
- t.Errorf("#%d: got %x want %x", i, z1, out)
- }
-
- if m == nil {
- // The result should be the same as for m == 0;
- // specifically, there should be no div-zero panic.
- m = &Int{abs: nat{}} // m != nil && len(m.abs) == 0
- z2 := new(Int).Exp(x, y, m)
- if z2.Cmp(z1) != 0 {
- t.Errorf("#%d: got %x want %x", i, z2, z1)
- }
- }
- }
-}
-
-func checkGcd(aBytes, bBytes []byte) bool {
- x := new(Int)
- y := new(Int)
- a := new(Int).SetBytes(aBytes)
- b := new(Int).SetBytes(bBytes)
-
- d := new(Int).GCD(x, y, a, b)
- x.Mul(x, a)
- y.Mul(y, b)
- x.Add(x, y)
-
- return x.Cmp(d) == 0
-}
-
-var gcdTests = []struct {
- d, x, y, a, b string
-}{
- // a <= 0 || b <= 0
- {"0", "0", "0", "0", "0"},
- {"0", "0", "0", "0", "7"},
- {"0", "0", "0", "11", "0"},
- {"0", "0", "0", "-77", "35"},
- {"0", "0", "0", "64515", "-24310"},
- {"0", "0", "0", "-64515", "-24310"},
-
- {"1", "-9", "47", "120", "23"},
- {"7", "1", "-2", "77", "35"},
- {"935", "-3", "8", "64515", "24310"},
- {"935000000000000000", "-3", "8", "64515000000000000000", "24310000000000000000"},
- {"1", "-221", "22059940471369027483332068679400581064239780177629666810348940098015901108344", "98920366548084643601728869055592650835572950932266967461790948584315647051443", "991"},
-
- // test early exit (after one Euclidean iteration) in binaryGCD
- {"1", "", "", "1", "98920366548084643601728869055592650835572950932266967461790948584315647051443"},
-}
-
-func testGcd(t *testing.T, d, x, y, a, b *Int) {
- var X *Int
- if x != nil {
- X = new(Int)
- }
- var Y *Int
- if y != nil {
- Y = new(Int)
- }
-
- D := new(Int).GCD(X, Y, a, b)
- if D.Cmp(d) != 0 {
- t.Errorf("GCD(%s, %s): got d = %s, want %s", a, b, D, d)
- }
- if x != nil && X.Cmp(x) != 0 {
- t.Errorf("GCD(%s, %s): got x = %s, want %s", a, b, X, x)
- }
- if y != nil && Y.Cmp(y) != 0 {
- t.Errorf("GCD(%s, %s): got y = %s, want %s", a, b, Y, y)
- }
-
- // binaryGCD requires a > 0 && b > 0
- if a.Sign() <= 0 || b.Sign() <= 0 {
- return
- }
-
- D.binaryGCD(a, b)
- if D.Cmp(d) != 0 {
- t.Errorf("binaryGcd(%s, %s): got d = %s, want %s", a, b, D, d)
- }
-
- // check results in presence of aliasing (issue #11284)
- a2 := new(Int).Set(a)
- b2 := new(Int).Set(b)
- a2.binaryGCD(a2, b2) // result is same as 1st argument
- if a2.Cmp(d) != 0 {
- t.Errorf("binaryGcd(%s, %s): got d = %s, want %s", a, b, a2, d)
- }
-
- a2 = new(Int).Set(a)
- b2 = new(Int).Set(b)
- b2.binaryGCD(a2, b2) // result is same as 2nd argument
- if b2.Cmp(d) != 0 {
- t.Errorf("binaryGcd(%s, %s): got d = %s, want %s", a, b, b2, d)
- }
-}
-
-func TestGcd(t *testing.T) {
- for _, test := range gcdTests {
- d, _ := new(Int).SetString(test.d, 0)
- x, _ := new(Int).SetString(test.x, 0)
- y, _ := new(Int).SetString(test.y, 0)
- a, _ := new(Int).SetString(test.a, 0)
- b, _ := new(Int).SetString(test.b, 0)
-
- testGcd(t, d, nil, nil, a, b)
- testGcd(t, d, x, nil, a, b)
- testGcd(t, d, nil, y, a, b)
- testGcd(t, d, x, y, a, b)
- }
-
- if err := quick.Check(checkGcd, nil); err != nil {
- t.Error(err)
- }
-}
-
-var primes = []string{
- "2",
- "3",
- "5",
- "7",
- "11",
-
- "13756265695458089029",
- "13496181268022124907",
- "10953742525620032441",
- "17908251027575790097",
-
- // https://golang.org/issue/638
- "18699199384836356663",
-
- "98920366548084643601728869055592650835572950932266967461790948584315647051443",
- "94560208308847015747498523884063394671606671904944666360068158221458669711639",
-
- // http://primes.utm.edu/lists/small/small3.html
- "449417999055441493994709297093108513015373787049558499205492347871729927573118262811508386655998299074566974373711472560655026288668094291699357843464363003144674940345912431129144354948751003607115263071543163",
- "230975859993204150666423538988557839555560243929065415434980904258310530753006723857139742334640122533598517597674807096648905501653461687601339782814316124971547968912893214002992086353183070342498989426570593",
- "5521712099665906221540423207019333379125265462121169655563495403888449493493629943498064604536961775110765377745550377067893607246020694972959780839151452457728855382113555867743022746090187341871655890805971735385789993",
- "203956878356401977405765866929034577280193993314348263094772646453283062722701277632936616063144088173312372882677123879538709400158306567338328279154499698366071906766440037074217117805690872792848149112022286332144876183376326512083574821647933992961249917319836219304274280243803104015000563790123",
-
- // ECC primes: http://tools.ietf.org/html/draft-ladd-safecurves-02
- "3618502788666131106986593281521497120414687020801267626233049500247285301239", // Curve1174: 2^251-9
- "57896044618658097711785492504343953926634992332820282019728792003956564819949", // Curve25519: 2^255-19
- "9850501549098619803069760025035903451269934817616361666987073351061430442874302652853566563721228910201656997576599", // E-382: 2^382-105
- "42307582002575910332922579714097346549017899709713998034217522897561970639123926132812109468141778230245837569601494931472367", // Curve41417: 2^414-17
- "6864797660130609714981900799081393217269435300143305409394463459185543183397656052122559640661454554977296311391480858037121987999716643812574028291115057151", // E-521: 2^521-1
-}
-
-var composites = []string{
- "0",
- "1",
- "21284175091214687912771199898307297748211672914763848041968395774954376176754",
- "6084766654921918907427900243509372380954290099172559290432744450051395395951",
- "84594350493221918389213352992032324280367711247940675652888030554255915464401",
- "82793403787388584738507275144194252681",
-}
-
-func TestProbablyPrime(t *testing.T) {
- nreps := 20
- if testing.Short() {
- nreps = 1
- }
- for i, s := range primes {
- p, _ := new(Int).SetString(s, 10)
- if !p.ProbablyPrime(nreps) {
- t.Errorf("#%d prime found to be non-prime (%s)", i, s)
- }
- }
-
- for i, s := range composites {
- c, _ := new(Int).SetString(s, 10)
- if c.ProbablyPrime(nreps) {
- t.Errorf("#%d composite found to be prime (%s)", i, s)
- }
- if testing.Short() {
- break
- }
- }
-
- // check that ProbablyPrime panics if n <= 0
- c := NewInt(11) // a prime
- for _, n := range []int{-1, 0, 1} {
- func() {
- defer func() {
- if n <= 0 && recover() == nil {
- t.Fatalf("expected panic from ProbablyPrime(%d)", n)
- }
- }()
- if !c.ProbablyPrime(n) {
- t.Fatalf("%v should be a prime", c)
- }
- }()
- }
-}
-
-type intShiftTest struct {
- in string
- shift uint
- out string
-}
-
-var rshTests = []intShiftTest{
- {"0", 0, "0"},
- {"-0", 0, "0"},
- {"0", 1, "0"},
- {"0", 2, "0"},
- {"1", 0, "1"},
- {"1", 1, "0"},
- {"1", 2, "0"},
- {"2", 0, "2"},
- {"2", 1, "1"},
- {"-1", 0, "-1"},
- {"-1", 1, "-1"},
- {"-1", 10, "-1"},
- {"-100", 2, "-25"},
- {"-100", 3, "-13"},
- {"-100", 100, "-1"},
- {"4294967296", 0, "4294967296"},
- {"4294967296", 1, "2147483648"},
- {"4294967296", 2, "1073741824"},
- {"18446744073709551616", 0, "18446744073709551616"},
- {"18446744073709551616", 1, "9223372036854775808"},
- {"18446744073709551616", 2, "4611686018427387904"},
- {"18446744073709551616", 64, "1"},
- {"340282366920938463463374607431768211456", 64, "18446744073709551616"},
- {"340282366920938463463374607431768211456", 128, "1"},
-}
-
-func TestRsh(t *testing.T) {
- for i, test := range rshTests {
- in, _ := new(Int).SetString(test.in, 10)
- expected, _ := new(Int).SetString(test.out, 10)
- out := new(Int).Rsh(in, test.shift)
-
- if !isNormalized(out) {
- t.Errorf("#%d: %v is not normalized", i, *out)
- }
- if out.Cmp(expected) != 0 {
- t.Errorf("#%d: got %s want %s", i, out, expected)
- }
- }
-}
-
-func TestRshSelf(t *testing.T) {
- for i, test := range rshTests {
- z, _ := new(Int).SetString(test.in, 10)
- expected, _ := new(Int).SetString(test.out, 10)
- z.Rsh(z, test.shift)
-
- if !isNormalized(z) {
- t.Errorf("#%d: %v is not normalized", i, *z)
- }
- if z.Cmp(expected) != 0 {
- t.Errorf("#%d: got %s want %s", i, z, expected)
- }
- }
-}
-
-var lshTests = []intShiftTest{
- {"0", 0, "0"},
- {"0", 1, "0"},
- {"0", 2, "0"},
- {"1", 0, "1"},
- {"1", 1, "2"},
- {"1", 2, "4"},
- {"2", 0, "2"},
- {"2", 1, "4"},
- {"2", 2, "8"},
- {"-87", 1, "-174"},
- {"4294967296", 0, "4294967296"},
- {"4294967296", 1, "8589934592"},
- {"4294967296", 2, "17179869184"},
- {"18446744073709551616", 0, "18446744073709551616"},
- {"9223372036854775808", 1, "18446744073709551616"},
- {"4611686018427387904", 2, "18446744073709551616"},
- {"1", 64, "18446744073709551616"},
- {"18446744073709551616", 64, "340282366920938463463374607431768211456"},
- {"1", 128, "340282366920938463463374607431768211456"},
-}
-
-func TestLsh(t *testing.T) {
- for i, test := range lshTests {
- in, _ := new(Int).SetString(test.in, 10)
- expected, _ := new(Int).SetString(test.out, 10)
- out := new(Int).Lsh(in, test.shift)
-
- if !isNormalized(out) {
- t.Errorf("#%d: %v is not normalized", i, *out)
- }
- if out.Cmp(expected) != 0 {
- t.Errorf("#%d: got %s want %s", i, out, expected)
- }
- }
-}
-
-func TestLshSelf(t *testing.T) {
- for i, test := range lshTests {
- z, _ := new(Int).SetString(test.in, 10)
- expected, _ := new(Int).SetString(test.out, 10)
- z.Lsh(z, test.shift)
-
- if !isNormalized(z) {
- t.Errorf("#%d: %v is not normalized", i, *z)
- }
- if z.Cmp(expected) != 0 {
- t.Errorf("#%d: got %s want %s", i, z, expected)
- }
- }
-}
-
-func TestLshRsh(t *testing.T) {
- for i, test := range rshTests {
- in, _ := new(Int).SetString(test.in, 10)
- out := new(Int).Lsh(in, test.shift)
- out = out.Rsh(out, test.shift)
-
- if !isNormalized(out) {
- t.Errorf("#%d: %v is not normalized", i, *out)
- }
- if in.Cmp(out) != 0 {
- t.Errorf("#%d: got %s want %s", i, out, in)
- }
- }
- for i, test := range lshTests {
- in, _ := new(Int).SetString(test.in, 10)
- out := new(Int).Lsh(in, test.shift)
- out.Rsh(out, test.shift)
-
- if !isNormalized(out) {
- t.Errorf("#%d: %v is not normalized", i, *out)
- }
- if in.Cmp(out) != 0 {
- t.Errorf("#%d: got %s want %s", i, out, in)
- }
- }
-}
-
-var int64Tests = []int64{
- 0,
- 1,
- -1,
- 4294967295,
- -4294967295,
- 4294967296,
- -4294967296,
- 9223372036854775807,
- -9223372036854775807,
- -9223372036854775808,
-}
-
-func TestInt64(t *testing.T) {
- for i, testVal := range int64Tests {
- in := NewInt(testVal)
- out := in.Int64()
-
- if out != testVal {
- t.Errorf("#%d got %d want %d", i, out, testVal)
- }
- }
-}
-
-var uint64Tests = []uint64{
- 0,
- 1,
- 4294967295,
- 4294967296,
- 8589934591,
- 8589934592,
- 9223372036854775807,
- 9223372036854775808,
- 18446744073709551615, // 1<<64 - 1
-}
-
-func TestUint64(t *testing.T) {
- in := new(Int)
- for i, testVal := range uint64Tests {
- in.SetUint64(testVal)
- out := in.Uint64()
-
- if out != testVal {
- t.Errorf("#%d got %d want %d", i, out, testVal)
- }
-
- str := fmt.Sprint(testVal)
- strOut := in.String()
- if strOut != str {
- t.Errorf("#%d.String got %s want %s", i, strOut, str)
- }
- }
-}
-
-var bitwiseTests = []struct {
- x, y string
- and, or, xor, andNot string
-}{
- {"0x00", "0x00", "0x00", "0x00", "0x00", "0x00"},
- {"0x00", "0x01", "0x00", "0x01", "0x01", "0x00"},
- {"0x01", "0x00", "0x00", "0x01", "0x01", "0x01"},
- {"-0x01", "0x00", "0x00", "-0x01", "-0x01", "-0x01"},
- {"-0xaf", "-0x50", "-0xf0", "-0x0f", "0xe1", "0x41"},
- {"0x00", "-0x01", "0x00", "-0x01", "-0x01", "0x00"},
- {"0x01", "0x01", "0x01", "0x01", "0x00", "0x00"},
- {"-0x01", "-0x01", "-0x01", "-0x01", "0x00", "0x00"},
- {"0x07", "0x08", "0x00", "0x0f", "0x0f", "0x07"},
- {"0x05", "0x0f", "0x05", "0x0f", "0x0a", "0x00"},
- {"0xff", "-0x0a", "0xf6", "-0x01", "-0xf7", "0x09"},
- {"0x013ff6", "0x9a4e", "0x1a46", "0x01bffe", "0x01a5b8", "0x0125b0"},
- {"-0x013ff6", "0x9a4e", "0x800a", "-0x0125b2", "-0x01a5bc", "-0x01c000"},
- {"-0x013ff6", "-0x9a4e", "-0x01bffe", "-0x1a46", "0x01a5b8", "0x8008"},
- {
- "0x1000009dc6e3d9822cba04129bcbe3401",
- "0xb9bd7d543685789d57cb918e833af352559021483cdb05cc21fd",
- "0x1000001186210100001000009048c2001",
- "0xb9bd7d543685789d57cb918e8bfeff7fddb2ebe87dfbbdfe35fd",
- "0xb9bd7d543685789d57ca918e8ae69d6fcdb2eae87df2b97215fc",
- "0x8c40c2d8822caa04120b8321400",
- },
- {
- "0x1000009dc6e3d9822cba04129bcbe3401",
- "-0xb9bd7d543685789d57cb918e833af352559021483cdb05cc21fd",
- "0x8c40c2d8822caa04120b8321401",
- "-0xb9bd7d543685789d57ca918e82229142459020483cd2014001fd",
- "-0xb9bd7d543685789d57ca918e8ae69d6fcdb2eae87df2b97215fe",
- "0x1000001186210100001000009048c2000",
- },
- {
- "-0x1000009dc6e3d9822cba04129bcbe3401",
- "-0xb9bd7d543685789d57cb918e833af352559021483cdb05cc21fd",
- "-0xb9bd7d543685789d57cb918e8bfeff7fddb2ebe87dfbbdfe35fd",
- "-0x1000001186210100001000009048c2001",
- "0xb9bd7d543685789d57ca918e8ae69d6fcdb2eae87df2b97215fc",
- "0xb9bd7d543685789d57ca918e82229142459020483cd2014001fc",
- },
-}
-
-type bitFun func(z, x, y *Int) *Int
-
-func testBitFun(t *testing.T, msg string, f bitFun, x, y *Int, exp string) {
- expected := new(Int)
- expected.SetString(exp, 0)
-
- out := f(new(Int), x, y)
- if out.Cmp(expected) != 0 {
- t.Errorf("%s: got %s want %s", msg, out, expected)
- }
-}
-
-func testBitFunSelf(t *testing.T, msg string, f bitFun, x, y *Int, exp string) {
- self := new(Int)
- self.Set(x)
- expected := new(Int)
- expected.SetString(exp, 0)
-
- self = f(self, self, y)
- if self.Cmp(expected) != 0 {
- t.Errorf("%s: got %s want %s", msg, self, expected)
- }
-}
-
-func altBit(x *Int, i int) uint {
- z := new(Int).Rsh(x, uint(i))
- z = z.And(z, NewInt(1))
- if z.Cmp(new(Int)) != 0 {
- return 1
- }
- return 0
-}
-
-func altSetBit(z *Int, x *Int, i int, b uint) *Int {
- one := NewInt(1)
- m := one.Lsh(one, uint(i))
- switch b {
- case 1:
- return z.Or(x, m)
- case 0:
- return z.AndNot(x, m)
- }
- panic("set bit is not 0 or 1")
-}
-
-func testBitset(t *testing.T, x *Int) {
- n := x.BitLen()
- z := new(Int).Set(x)
- z1 := new(Int).Set(x)
- for i := 0; i < n+10; i++ {
- old := z.Bit(i)
- old1 := altBit(z1, i)
- if old != old1 {
- t.Errorf("bitset: inconsistent value for Bit(%s, %d), got %v want %v", z1, i, old, old1)
- }
- z := new(Int).SetBit(z, i, 1)
- z1 := altSetBit(new(Int), z1, i, 1)
- if z.Bit(i) == 0 {
- t.Errorf("bitset: bit %d of %s got 0 want 1", i, x)
- }
- if z.Cmp(z1) != 0 {
- t.Errorf("bitset: inconsistent value after SetBit 1, got %s want %s", z, z1)
- }
- z.SetBit(z, i, 0)
- altSetBit(z1, z1, i, 0)
- if z.Bit(i) != 0 {
- t.Errorf("bitset: bit %d of %s got 1 want 0", i, x)
- }
- if z.Cmp(z1) != 0 {
- t.Errorf("bitset: inconsistent value after SetBit 0, got %s want %s", z, z1)
- }
- altSetBit(z1, z1, i, old)
- z.SetBit(z, i, old)
- if z.Cmp(z1) != 0 {
- t.Errorf("bitset: inconsistent value after SetBit old, got %s want %s", z, z1)
- }
- }
- if z.Cmp(x) != 0 {
- t.Errorf("bitset: got %s want %s", z, x)
- }
-}
-
-var bitsetTests = []struct {
- x string
- i int
- b uint
-}{
- {"0", 0, 0},
- {"0", 200, 0},
- {"1", 0, 1},
- {"1", 1, 0},
- {"-1", 0, 1},
- {"-1", 200, 1},
- {"0x2000000000000000000000000000", 108, 0},
- {"0x2000000000000000000000000000", 109, 1},
- {"0x2000000000000000000000000000", 110, 0},
- {"-0x2000000000000000000000000001", 108, 1},
- {"-0x2000000000000000000000000001", 109, 0},
- {"-0x2000000000000000000000000001", 110, 1},
-}
-
-func TestBitSet(t *testing.T) {
- for _, test := range bitwiseTests {
- x := new(Int)
- x.SetString(test.x, 0)
- testBitset(t, x)
- x = new(Int)
- x.SetString(test.y, 0)
- testBitset(t, x)
- }
- for i, test := range bitsetTests {
- x := new(Int)
- x.SetString(test.x, 0)
- b := x.Bit(test.i)
- if b != test.b {
- t.Errorf("#%d got %v want %v", i, b, test.b)
- }
- }
- z := NewInt(1)
- z.SetBit(NewInt(0), 2, 1)
- if z.Cmp(NewInt(4)) != 0 {
- t.Errorf("destination leaked into result; got %s want 4", z)
- }
-}
-
-func BenchmarkBitset(b *testing.B) {
- z := new(Int)
- z.SetBit(z, 512, 1)
- b.ResetTimer()
- b.StartTimer()
- for i := b.N - 1; i >= 0; i-- {
- z.SetBit(z, i&512, 1)
- }
-}
-
-func BenchmarkBitsetNeg(b *testing.B) {
- z := NewInt(-1)
- z.SetBit(z, 512, 0)
- b.ResetTimer()
- b.StartTimer()
- for i := b.N - 1; i >= 0; i-- {
- z.SetBit(z, i&512, 0)
- }
-}
-
-func BenchmarkBitsetOrig(b *testing.B) {
- z := new(Int)
- altSetBit(z, z, 512, 1)
- b.ResetTimer()
- b.StartTimer()
- for i := b.N - 1; i >= 0; i-- {
- altSetBit(z, z, i&512, 1)
- }
-}
-
-func BenchmarkBitsetNegOrig(b *testing.B) {
- z := NewInt(-1)
- altSetBit(z, z, 512, 0)
- b.ResetTimer()
- b.StartTimer()
- for i := b.N - 1; i >= 0; i-- {
- altSetBit(z, z, i&512, 0)
- }
-}
-
-// tri generates the trinomial 2**(n*2) - 2**n - 1, which is always 3 mod 4 and
-// 7 mod 8, so that 2 is always a quadratic residue.
-func tri(n uint) *Int {
- x := NewInt(1)
- x.Lsh(x, n)
- x2 := new(Int).Lsh(x, n)
- x2.Sub(x2, x)
- x2.Sub(x2, intOne)
- return x2
-}
-
-func BenchmarkModSqrt225_Tonelli(b *testing.B) {
- p := tri(225)
- x := NewInt(2)
- for i := 0; i < b.N; i++ {
- x.SetUint64(2)
- x.modSqrtTonelliShanks(x, p)
- }
-}
-
-func BenchmarkModSqrt224_3Mod4(b *testing.B) {
- p := tri(225)
- x := new(Int).SetUint64(2)
- for i := 0; i < b.N; i++ {
- x.SetUint64(2)
- x.modSqrt3Mod4Prime(x, p)
- }
-}
-
-func BenchmarkModSqrt5430_Tonelli(b *testing.B) {
- p := tri(5430)
- x := new(Int).SetUint64(2)
- for i := 0; i < b.N; i++ {
- x.SetUint64(2)
- x.modSqrtTonelliShanks(x, p)
- }
-}
-
-func BenchmarkModSqrt5430_3Mod4(b *testing.B) {
- p := tri(5430)
- x := new(Int).SetUint64(2)
- for i := 0; i < b.N; i++ {
- x.SetUint64(2)
- x.modSqrt3Mod4Prime(x, p)
- }
-}
-
-func TestBitwise(t *testing.T) {
- x := new(Int)
- y := new(Int)
- for _, test := range bitwiseTests {
- x.SetString(test.x, 0)
- y.SetString(test.y, 0)
-
- testBitFun(t, "and", (*Int).And, x, y, test.and)
- testBitFunSelf(t, "and", (*Int).And, x, y, test.and)
- testBitFun(t, "andNot", (*Int).AndNot, x, y, test.andNot)
- testBitFunSelf(t, "andNot", (*Int).AndNot, x, y, test.andNot)
- testBitFun(t, "or", (*Int).Or, x, y, test.or)
- testBitFunSelf(t, "or", (*Int).Or, x, y, test.or)
- testBitFun(t, "xor", (*Int).Xor, x, y, test.xor)
- testBitFunSelf(t, "xor", (*Int).Xor, x, y, test.xor)
- }
-}
-
-var notTests = []struct {
- in string
- out string
-}{
- {"0", "-1"},
- {"1", "-2"},
- {"7", "-8"},
- {"0", "-1"},
- {"-81910", "81909"},
- {
- "298472983472983471903246121093472394872319615612417471234712061",
- "-298472983472983471903246121093472394872319615612417471234712062",
- },
-}
-
-func TestNot(t *testing.T) {
- in := new(Int)
- out := new(Int)
- expected := new(Int)
- for i, test := range notTests {
- in.SetString(test.in, 10)
- expected.SetString(test.out, 10)
- out = out.Not(in)
- if out.Cmp(expected) != 0 {
- t.Errorf("#%d: got %s want %s", i, out, expected)
- }
- out = out.Not(out)
- if out.Cmp(in) != 0 {
- t.Errorf("#%d: got %s want %s", i, out, in)
- }
- }
-}
-
-var modInverseTests = []struct {
- element string
- modulus string
-}{
- {"1234567", "458948883992"},
- {"239487239847", "2410312426921032588552076022197566074856950548502459942654116941958108831682612228890093858261341614673227141477904012196503648957050582631942730706805009223062734745341073406696246014589361659774041027169249453200378729434170325843778659198143763193776859869524088940195577346119843545301547043747207749969763750084308926339295559968882457872412993810129130294592999947926365264059284647209730384947211681434464714438488520940127459844288859336526896320919633919"},
-}
-
-func TestModInverse(t *testing.T) {
- var element, modulus, gcd, inverse Int
- one := NewInt(1)
- for i, test := range modInverseTests {
- (&element).SetString(test.element, 10)
- (&modulus).SetString(test.modulus, 10)
- (&inverse).ModInverse(&element, &modulus)
- (&inverse).Mul(&inverse, &element)
- (&inverse).Mod(&inverse, &modulus)
- if (&inverse).Cmp(one) != 0 {
- t.Errorf("#%d: failed (e·e^(-1)=%s)", i, &inverse)
- }
- }
- // exhaustive test for small values
- for n := 2; n < 100; n++ {
- (&modulus).SetInt64(int64(n))
- for x := 1; x < n; x++ {
- (&element).SetInt64(int64(x))
- (&gcd).GCD(nil, nil, &element, &modulus)
- if (&gcd).Cmp(one) != 0 {
- continue
- }
- (&inverse).ModInverse(&element, &modulus)
- (&inverse).Mul(&inverse, &element)
- (&inverse).Mod(&inverse, &modulus)
- if (&inverse).Cmp(one) != 0 {
- t.Errorf("ModInverse(%d,%d)*%d%%%d=%d, not 1", &element, &modulus, &element, &modulus, &inverse)
- }
- }
- }
-}
-
-// testModSqrt is a helper for TestModSqrt,
-// which checks that ModSqrt can compute a square-root of elt^2.
-func testModSqrt(t *testing.T, elt, mod, sq, sqrt *Int) bool {
- var sqChk, sqrtChk, sqrtsq Int
- sq.Mul(elt, elt)
- sq.Mod(sq, mod)
- z := sqrt.ModSqrt(sq, mod)
- if z != sqrt {
- t.Errorf("ModSqrt returned wrong value %s", z)
- }
-
- // test ModSqrt arguments outside the range [0,mod)
- sqChk.Add(sq, mod)
- z = sqrtChk.ModSqrt(&sqChk, mod)
- if z != &sqrtChk || z.Cmp(sqrt) != 0 {
- t.Errorf("ModSqrt returned inconsistent value %s", z)
- }
- sqChk.Sub(sq, mod)
- z = sqrtChk.ModSqrt(&sqChk, mod)
- if z != &sqrtChk || z.Cmp(sqrt) != 0 {
- t.Errorf("ModSqrt returned inconsistent value %s", z)
- }
-
- // make sure we actually got a square root
- if sqrt.Cmp(elt) == 0 {
- return true // we found the "desired" square root
- }
- sqrtsq.Mul(sqrt, sqrt) // make sure we found the "other" one
- sqrtsq.Mod(&sqrtsq, mod)
- return sq.Cmp(&sqrtsq) == 0
-}
-
-func TestModSqrt(t *testing.T) {
- var elt, mod, modx4, sq, sqrt Int
- r := rand.New(rand.NewSource(9))
- for i, s := range primes[1:] { // skip 2, use only odd primes
- mod.SetString(s, 10)
- modx4.Lsh(&mod, 2)
-
- // test a few random elements per prime
- for x := 1; x < 5; x++ {
- elt.Rand(r, &modx4)
- elt.Sub(&elt, &mod) // test range [-mod, 3*mod)
- if !testModSqrt(t, &elt, &mod, &sq, &sqrt) {
- t.Errorf("#%d: failed (sqrt(e) = %s)", i, &sqrt)
- }
- }
-
- if testing.Short() && i > 2 {
- break
- }
- }
-
- if testing.Short() {
- return
- }
-
- // exhaustive test for small values
- for n := 3; n < 100; n++ {
- mod.SetInt64(int64(n))
- if !mod.ProbablyPrime(10) {
- continue
- }
- isSquare := make([]bool, n)
-
- // test all the squares
- for x := 1; x < n; x++ {
- elt.SetInt64(int64(x))
- if !testModSqrt(t, &elt, &mod, &sq, &sqrt) {
- t.Errorf("#%d: failed (sqrt(%d,%d) = %s)", x, &elt, &mod, &sqrt)
- }
- isSquare[sq.Uint64()] = true
- }
-
- // test all non-squares
- for x := 1; x < n; x++ {
- sq.SetInt64(int64(x))
- z := sqrt.ModSqrt(&sq, &mod)
- if !isSquare[x] && z != nil {
- t.Errorf("#%d: failed (sqrt(%d,%d) = nil)", x, &sqrt, &mod)
- }
- }
- }
-}
-
-func TestJacobi(t *testing.T) {
- testCases := []struct {
- x, y int64
- result int
- }{
- {0, 1, 1},
- {0, -1, 1},
- {1, 1, 1},
- {1, -1, 1},
- {0, 5, 0},
- {1, 5, 1},
- {2, 5, -1},
- {-2, 5, -1},
- {2, -5, -1},
- {-2, -5, 1},
- {3, 5, -1},
- {5, 5, 0},
- {-5, 5, 0},
- {6, 5, 1},
- {6, -5, 1},
- {-6, 5, 1},
- {-6, -5, -1},
- }
-
- var x, y Int
-
- for i, test := range testCases {
- x.SetInt64(test.x)
- y.SetInt64(test.y)
- expected := test.result
- actual := Jacobi(&x, &y)
- if actual != expected {
- t.Errorf("#%d: Jacobi(%d, %d) = %d, but expected %d", i, test.x, test.y, actual, expected)
- }
- }
-}
-
-func TestJacobiPanic(t *testing.T) {
- const failureMsg = "test failure"
- defer func() {
- msg := recover()
- if msg == nil || msg == failureMsg {
- panic(msg)
- }
- t.Log(msg)
- }()
- x := NewInt(1)
- y := NewInt(2)
- // Jacobi should panic when the second argument is even.
- Jacobi(x, y)
- panic(failureMsg)
-}
-
-func TestIssue2607(t *testing.T) {
- // This code sequence used to hang.
- n := NewInt(10)
- n.Rand(rand.New(rand.NewSource(9)), n)
-}
diff --git a/src/cmd/compile/internal/big/intconv.go b/src/cmd/compile/internal/big/intconv.go
deleted file mode 100644
index daf674a..0000000
--- a/src/cmd/compile/internal/big/intconv.go
+++ /dev/null
@@ -1,248 +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 implements int-to-string conversion functions.
-
-package big
-
-import (
- "errors"
- "fmt"
- "io"
-)
-
-// TODO(gri) Should rename itoa to utoa (there's no sign). That
-// would permit the introduction of itoa which is like utoa but
-// reserves a byte for a possible sign that's passed in. That
-// would permit Int.Text to be implemented w/o the need for
-// string copy if the number is negative.
-
-// Text returns the string representation of x in the given base.
-// Base must be between 2 and 36, inclusive. The result uses the
-// lower-case letters 'a' to 'z' for digit values >= 10. No base
-// prefix (such as "0x") is added to the string.
-func (x *Int) Text(base int) string {
- if x == nil {
- return "<nil>"
- }
- return string(x.abs.itoa(x.neg, base))
-}
-
-// Append appends the string representation of x, as generated by
-// x.Text(base), to buf and returns the extended buffer.
-func (x *Int) Append(buf []byte, base int) []byte {
- if x == nil {
- return append(buf, "<nil>"...)
- }
- return append(buf, x.abs.itoa(x.neg, base)...)
-}
-
-func (x *Int) String() string {
- return x.Text(10)
-}
-
-// write count copies of text to s
-func writeMultiple(s fmt.State, text string, count int) {
- if len(text) > 0 {
- b := []byte(text)
- for ; count > 0; count-- {
- s.Write(b)
- }
- }
-}
-
-// Format implements fmt.Formatter. It accepts the formats
-// 'b' (binary), 'o' (octal), 'd' (decimal), 'x' (lowercase
-// hexadecimal), and 'X' (uppercase hexadecimal).
-// Also supported are the full suite of package fmt's format
-// flags for integral types, including '+' and ' ' for sign
-// control, '#' for leading zero in octal and for hexadecimal,
-// a leading "0x" or "0X" for "%#x" and "%#X" respectively,
-// specification of minimum digits precision, output field
-// width, space or zero padding, and '-' for left or right
-// justification.
-//
-func (x *Int) Format(s fmt.State, ch rune) {
- // determine base
- var base int
- switch ch {
- case 'b':
- base = 2
- case 'o':
- base = 8
- case 'd', 's', 'v':
- base = 10
- case 'x', 'X':
- base = 16
- default:
- // unknown format
- fmt.Fprintf(s, "%%!%c(big.Int=%s)", ch, x.String())
- return
- }
-
- if x == nil {
- fmt.Fprint(s, "<nil>")
- return
- }
-
- // determine sign character
- sign := ""
- switch {
- case x.neg:
- sign = "-"
- case s.Flag('+'): // supersedes ' ' when both specified
- sign = "+"
- case s.Flag(' '):
- sign = " "
- }
-
- // determine prefix characters for indicating output base
- prefix := ""
- if s.Flag('#') {
- switch ch {
- case 'o': // octal
- prefix = "0"
- case 'x': // hexadecimal
- prefix = "0x"
- case 'X':
- prefix = "0X"
- }
- }
-
- digits := x.abs.utoa(base)
- if ch == 'X' {
- // faster than bytes.ToUpper
- for i, d := range digits {
- if 'a' <= d && d <= 'z' {
- digits[i] = 'A' + (d - 'a')
- }
- }
- }
-
- // number of characters for the three classes of number padding
- var left int // space characters to left of digits for right justification ("%8d")
- var zeros int // zero characters (actually cs[0]) as left-most digits ("%.8d")
- var right int // space characters to right of digits for left justification ("%-8d")
-
- // determine number padding from precision: the least number of digits to output
- precision, precisionSet := s.Precision()
- if precisionSet {
- switch {
- case len(digits) < precision:
- zeros = precision - len(digits) // count of zero padding
- case len(digits) == 1 && digits[0] == '0' && precision == 0:
- return // print nothing if zero value (x == 0) and zero precision ("." or ".0")
- }
- }
-
- // determine field pad from width: the least number of characters to output
- length := len(sign) + len(prefix) + zeros + len(digits)
- if width, widthSet := s.Width(); widthSet && length < width { // pad as specified
- switch d := width - length; {
- case s.Flag('-'):
- // pad on the right with spaces; supersedes '0' when both specified
- right = d
- case s.Flag('0') && !precisionSet:
- // pad with zeros unless precision also specified
- zeros = d
- default:
- // pad on the left with spaces
- left = d
- }
- }
-
- // print number as [left pad][sign][prefix][zero pad][digits][right pad]
- writeMultiple(s, " ", left)
- writeMultiple(s, sign, 1)
- writeMultiple(s, prefix, 1)
- writeMultiple(s, "0", zeros)
- s.Write(digits)
- writeMultiple(s, " ", right)
-}
-
-// scan sets z to the integer value corresponding to the longest possible prefix
-// read from r representing a signed integer number in a given conversion base.
-// It returns z, the actual conversion base used, and an error, if any. In the
-// error case, the value of z is undefined but the returned value is nil. The
-// syntax follows the syntax of integer literals in Go.
-//
-// The base argument must be 0 or a value from 2 through MaxBase. If the base
-// is 0, the string prefix determines the actual conversion base. A prefix of
-// ``0x'' or ``0X'' selects base 16; the ``0'' prefix selects base 8, and a
-// ``0b'' or ``0B'' prefix selects base 2. Otherwise the selected base is 10.
-//
-func (z *Int) scan(r io.ByteScanner, base int) (*Int, int, error) {
- // determine sign
- neg, err := scanSign(r)
- if err != nil {
- return nil, 0, err
- }
-
- // determine mantissa
- z.abs, base, _, err = z.abs.scan(r, base, false)
- if err != nil {
- return nil, base, err
- }
- z.neg = len(z.abs) > 0 && neg // 0 has no sign
-
- return z, base, nil
-}
-
-func scanSign(r io.ByteScanner) (neg bool, err error) {
- var ch byte
- if ch, err = r.ReadByte(); err != nil {
- return false, err
- }
- switch ch {
- case '-':
- neg = true
- case '+':
- // nothing to do
- default:
- r.UnreadByte()
- }
- return
-}
-
-// byteReader is a local wrapper around fmt.ScanState;
-// it implements the ByteReader interface.
-type byteReader struct {
- fmt.ScanState
-}
-
-func (r byteReader) ReadByte() (byte, error) {
- ch, size, err := r.ReadRune()
- if size != 1 && err == nil {
- err = fmt.Errorf("invalid rune %#U", ch)
- }
- return byte(ch), err
-}
-
-func (r byteReader) UnreadByte() error {
- return r.UnreadRune()
-}
-
-// Scan is a support routine for fmt.Scanner; it sets z to the value of
-// the scanned number. It accepts the formats 'b' (binary), 'o' (octal),
-// 'd' (decimal), 'x' (lowercase hexadecimal), and 'X' (uppercase hexadecimal).
-func (z *Int) Scan(s fmt.ScanState, ch rune) error {
- s.SkipSpace() // skip leading space characters
- base := 0
- switch ch {
- case 'b':
- base = 2
- case 'o':
- base = 8
- case 'd':
- base = 10
- case 'x', 'X':
- base = 16
- case 's', 'v':
- // let scan determine the base
- default:
- return errors.New("Int.Scan: invalid verb")
- }
- _, _, err := z.scan(byteReader{s}, base)
- return err
-}
diff --git a/src/cmd/compile/internal/big/intconv_test.go b/src/cmd/compile/internal/big/intconv_test.go
deleted file mode 100644
index 5142081..0000000
--- a/src/cmd/compile/internal/big/intconv_test.go
+++ /dev/null
@@ -1,391 +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 big
-
-import (
- "bytes"
- "fmt"
- "testing"
-)
-
-var stringTests = []struct {
- in string
- out string
- base int
- val int64
- ok bool
-}{
- {in: ""},
- {in: "a"},
- {in: "z"},
- {in: "+"},
- {in: "-"},
- {in: "0b"},
- {in: "0x"},
- {in: "2", base: 2},
- {in: "0b2", base: 0},
- {in: "08"},
- {in: "8", base: 8},
- {in: "0xg", base: 0},
- {in: "g", base: 16},
- {"0", "0", 0, 0, true},
- {"0", "0", 10, 0, true},
- {"0", "0", 16, 0, true},
- {"+0", "0", 0, 0, true},
- {"-0", "0", 0, 0, true},
- {"10", "10", 0, 10, true},
- {"10", "10", 10, 10, true},
- {"10", "10", 16, 16, true},
- {"-10", "-10", 16, -16, true},
- {"+10", "10", 16, 16, true},
- {"0x10", "16", 0, 16, true},
- {in: "0x10", base: 16},
- {"-0x10", "-16", 0, -16, true},
- {"+0x10", "16", 0, 16, true},
- {"00", "0", 0, 0, true},
- {"0", "0", 8, 0, true},
- {"07", "7", 0, 7, true},
- {"7", "7", 8, 7, true},
- {"023", "19", 0, 19, true},
- {"23", "23", 8, 19, true},
- {"cafebabe", "cafebabe", 16, 0xcafebabe, true},
- {"0b0", "0", 0, 0, true},
- {"-111", "-111", 2, -7, true},
- {"-0b111", "-7", 0, -7, true},
- {"0b1001010111", "599", 0, 0x257, true},
- {"1001010111", "1001010111", 2, 0x257, true},
-}
-
-func TestIntText(t *testing.T) {
- z := new(Int)
- for _, test := range stringTests {
- if !test.ok {
- continue
- }
-
- _, ok := z.SetString(test.in, test.base)
- if !ok {
- t.Errorf("%v: failed to parse", test)
- continue
- }
-
- base := test.base
- if base == 0 {
- base = 10
- }
-
- if got := z.Text(base); got != test.out {
- t.Errorf("%v: got %s; want %s", test, got, test.out)
- }
- }
-}
-
-func TestAppendText(t *testing.T) {
- z := new(Int)
- var buf []byte
- for _, test := range stringTests {
- if !test.ok {
- continue
- }
-
- _, ok := z.SetString(test.in, test.base)
- if !ok {
- t.Errorf("%v: failed to parse", test)
- continue
- }
-
- base := test.base
- if base == 0 {
- base = 10
- }
-
- i := len(buf)
- buf = z.Append(buf, base)
- if got := string(buf[i:]); got != test.out {
- t.Errorf("%v: got %s; want %s", test, got, test.out)
- }
- }
-}
-
-func format(base int) string {
- switch base {
- case 2:
- return "%b"
- case 8:
- return "%o"
- case 16:
- return "%x"
- }
- return "%d"
-}
-
-func TestGetString(t *testing.T) {
- z := new(Int)
- for i, test := range stringTests {
- if !test.ok {
- continue
- }
- z.SetInt64(test.val)
-
- if test.base == 10 {
- if got := z.String(); got != test.out {
- t.Errorf("#%da got %s; want %s", i, got, test.out)
- }
- }
-
- if got := fmt.Sprintf(format(test.base), z); got != test.out {
- t.Errorf("#%db got %s; want %s", i, got, test.out)
- }
- }
-}
-
-func TestSetString(t *testing.T) {
- tmp := new(Int)
- for i, test := range stringTests {
- // initialize to a non-zero value so that issues with parsing
- // 0 are detected
- tmp.SetInt64(1234567890)
- n1, ok1 := new(Int).SetString(test.in, test.base)
- n2, ok2 := tmp.SetString(test.in, test.base)
- expected := NewInt(test.val)
- if ok1 != test.ok || ok2 != test.ok {
- t.Errorf("#%d (input '%s') ok incorrect (should be %t)", i, test.in, test.ok)
- continue
- }
- if !ok1 {
- if n1 != nil {
- t.Errorf("#%d (input '%s') n1 != nil", i, test.in)
- }
- continue
- }
- if !ok2 {
- if n2 != nil {
- t.Errorf("#%d (input '%s') n2 != nil", i, test.in)
- }
- continue
- }
-
- if ok1 && !isNormalized(n1) {
- t.Errorf("#%d (input '%s'): %v is not normalized", i, test.in, *n1)
- }
- if ok2 && !isNormalized(n2) {
- t.Errorf("#%d (input '%s'): %v is not normalized", i, test.in, *n2)
- }
-
- if n1.Cmp(expected) != 0 {
- t.Errorf("#%d (input '%s') got: %s want: %d", i, test.in, n1, test.val)
- }
- if n2.Cmp(expected) != 0 {
- t.Errorf("#%d (input '%s') got: %s want: %d", i, test.in, n2, test.val)
- }
- }
-}
-
-var formatTests = []struct {
- input string
- format string
- output string
-}{
- {"<nil>", "%x", "<nil>"},
- {"<nil>", "%#x", "<nil>"},
- {"<nil>", "%#y", "%!y(big.Int=<nil>)"},
-
- {"10", "%b", "1010"},
- {"10", "%o", "12"},
- {"10", "%d", "10"},
- {"10", "%v", "10"},
- {"10", "%x", "a"},
- {"10", "%X", "A"},
- {"-10", "%X", "-A"},
- {"10", "%y", "%!y(big.Int=10)"},
- {"-10", "%y", "%!y(big.Int=-10)"},
-
- {"10", "%#b", "1010"},
- {"10", "%#o", "012"},
- {"10", "%#d", "10"},
- {"10", "%#v", "10"},
- {"10", "%#x", "0xa"},
- {"10", "%#X", "0XA"},
- {"-10", "%#X", "-0XA"},
- {"10", "%#y", "%!y(big.Int=10)"},
- {"-10", "%#y", "%!y(big.Int=-10)"},
-
- {"1234", "%d", "1234"},
- {"1234", "%3d", "1234"},
- {"1234", "%4d", "1234"},
- {"-1234", "%d", "-1234"},
- {"1234", "% 5d", " 1234"},
- {"1234", "%+5d", "+1234"},
- {"1234", "%-5d", "1234 "},
- {"1234", "%x", "4d2"},
- {"1234", "%X", "4D2"},
- {"-1234", "%3x", "-4d2"},
- {"-1234", "%4x", "-4d2"},
- {"-1234", "%5x", " -4d2"},
- {"-1234", "%-5x", "-4d2 "},
- {"1234", "%03d", "1234"},
- {"1234", "%04d", "1234"},
- {"1234", "%05d", "01234"},
- {"1234", "%06d", "001234"},
- {"-1234", "%06d", "-01234"},
- {"1234", "%+06d", "+01234"},
- {"1234", "% 06d", " 01234"},
- {"1234", "%-6d", "1234 "},
- {"1234", "%-06d", "1234 "},
- {"-1234", "%-06d", "-1234 "},
-
- {"1234", "%.3d", "1234"},
- {"1234", "%.4d", "1234"},
- {"1234", "%.5d", "01234"},
- {"1234", "%.6d", "001234"},
- {"-1234", "%.3d", "-1234"},
- {"-1234", "%.4d", "-1234"},
- {"-1234", "%.5d", "-01234"},
- {"-1234", "%.6d", "-001234"},
-
- {"1234", "%8.3d", " 1234"},
- {"1234", "%8.4d", " 1234"},
- {"1234", "%8.5d", " 01234"},
- {"1234", "%8.6d", " 001234"},
- {"-1234", "%8.3d", " -1234"},
- {"-1234", "%8.4d", " -1234"},
- {"-1234", "%8.5d", " -01234"},
- {"-1234", "%8.6d", " -001234"},
-
- {"1234", "%+8.3d", " +1234"},
- {"1234", "%+8.4d", " +1234"},
- {"1234", "%+8.5d", " +01234"},
- {"1234", "%+8.6d", " +001234"},
- {"-1234", "%+8.3d", " -1234"},
- {"-1234", "%+8.4d", " -1234"},
- {"-1234", "%+8.5d", " -01234"},
- {"-1234", "%+8.6d", " -001234"},
-
- {"1234", "% 8.3d", " 1234"},
- {"1234", "% 8.4d", " 1234"},
- {"1234", "% 8.5d", " 01234"},
- {"1234", "% 8.6d", " 001234"},
- {"-1234", "% 8.3d", " -1234"},
- {"-1234", "% 8.4d", " -1234"},
- {"-1234", "% 8.5d", " -01234"},
- {"-1234", "% 8.6d", " -001234"},
-
- {"1234", "%.3x", "4d2"},
- {"1234", "%.4x", "04d2"},
- {"1234", "%.5x", "004d2"},
- {"1234", "%.6x", "0004d2"},
- {"-1234", "%.3x", "-4d2"},
- {"-1234", "%.4x", "-04d2"},
- {"-1234", "%.5x", "-004d2"},
- {"-1234", "%.6x", "-0004d2"},
-
- {"1234", "%8.3x", " 4d2"},
- {"1234", "%8.4x", " 04d2"},
- {"1234", "%8.5x", " 004d2"},
- {"1234", "%8.6x", " 0004d2"},
- {"-1234", "%8.3x", " -4d2"},
- {"-1234", "%8.4x", " -04d2"},
- {"-1234", "%8.5x", " -004d2"},
- {"-1234", "%8.6x", " -0004d2"},
-
- {"1234", "%+8.3x", " +4d2"},
- {"1234", "%+8.4x", " +04d2"},
- {"1234", "%+8.5x", " +004d2"},
- {"1234", "%+8.6x", " +0004d2"},
- {"-1234", "%+8.3x", " -4d2"},
- {"-1234", "%+8.4x", " -04d2"},
- {"-1234", "%+8.5x", " -004d2"},
- {"-1234", "%+8.6x", " -0004d2"},
-
- {"1234", "% 8.3x", " 4d2"},
- {"1234", "% 8.4x", " 04d2"},
- {"1234", "% 8.5x", " 004d2"},
- {"1234", "% 8.6x", " 0004d2"},
- {"1234", "% 8.7x", " 00004d2"},
- {"1234", "% 8.8x", " 000004d2"},
- {"-1234", "% 8.3x", " -4d2"},
- {"-1234", "% 8.4x", " -04d2"},
- {"-1234", "% 8.5x", " -004d2"},
- {"-1234", "% 8.6x", " -0004d2"},
- {"-1234", "% 8.7x", "-00004d2"},
- {"-1234", "% 8.8x", "-000004d2"},
-
- {"1234", "%-8.3d", "1234 "},
- {"1234", "%-8.4d", "1234 "},
- {"1234", "%-8.5d", "01234 "},
- {"1234", "%-8.6d", "001234 "},
- {"1234", "%-8.7d", "0001234 "},
- {"1234", "%-8.8d", "00001234"},
- {"-1234", "%-8.3d", "-1234 "},
- {"-1234", "%-8.4d", "-1234 "},
- {"-1234", "%-8.5d", "-01234 "},
- {"-1234", "%-8.6d", "-001234 "},
- {"-1234", "%-8.7d", "-0001234"},
- {"-1234", "%-8.8d", "-00001234"},
-
- {"16777215", "%b", "111111111111111111111111"}, // 2**24 - 1
-
- {"0", "%.d", ""},
- {"0", "%.0d", ""},
- {"0", "%3.d", ""},
-}
-
-func TestFormat(t *testing.T) {
- for i, test := range formatTests {
- var x *Int
- if test.input != "<nil>" {
- var ok bool
- x, ok = new(Int).SetString(test.input, 0)
- if !ok {
- t.Errorf("#%d failed reading input %s", i, test.input)
- }
- }
- output := fmt.Sprintf(test.format, x)
- if output != test.output {
- t.Errorf("#%d got %q; want %q, {%q, %q, %q}", i, output, test.output, test.input, test.format, test.output)
- }
- }
-}
-
-var scanTests = []struct {
- input string
- format string
- output string
- remaining int
-}{
- {"1010", "%b", "10", 0},
- {"0b1010", "%v", "10", 0},
- {"12", "%o", "10", 0},
- {"012", "%v", "10", 0},
- {"10", "%d", "10", 0},
- {"10", "%v", "10", 0},
- {"a", "%x", "10", 0},
- {"0xa", "%v", "10", 0},
- {"A", "%X", "10", 0},
- {"-A", "%X", "-10", 0},
- {"+0b1011001", "%v", "89", 0},
- {"0xA", "%v", "10", 0},
- {"0 ", "%v", "0", 1},
- {"2+3", "%v", "2", 2},
- {"0XABC 12", "%v", "2748", 3},
-}
-
-func TestScan(t *testing.T) {
- var buf bytes.Buffer
- for i, test := range scanTests {
- x := new(Int)
- buf.Reset()
- buf.WriteString(test.input)
- if _, err := fmt.Fscanf(&buf, test.format, x); err != nil {
- t.Errorf("#%d error: %s", i, err)
- }
- if x.String() != test.output {
- t.Errorf("#%d got %s; want %s", i, x.String(), test.output)
- }
- if buf.Len() != test.remaining {
- t.Errorf("#%d got %d bytes remaining; want %d", i, buf.Len(), test.remaining)
- }
- }
-}
diff --git a/src/cmd/compile/internal/big/intmarsh.go b/src/cmd/compile/internal/big/intmarsh.go
deleted file mode 100644
index 4ff57b6..0000000
--- a/src/cmd/compile/internal/big/intmarsh.go
+++ /dev/null
@@ -1,74 +0,0 @@
-// Copyright 2015 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// This file implements encoding/decoding of Ints.
-
-package big
-
-import "fmt"
-
-// Gob codec version. Permits backward-compatible changes to the encoding.
-const intGobVersion byte = 1
-
-// GobEncode implements the gob.GobEncoder interface.
-func (x *Int) GobEncode() ([]byte, error) {
- if x == nil {
- return nil, nil
- }
- buf := make([]byte, 1+len(x.abs)*_S) // extra byte for version and sign bit
- i := x.abs.bytes(buf) - 1 // i >= 0
- b := intGobVersion << 1 // make space for sign bit
- if x.neg {
- b |= 1
- }
- buf[i] = b
- return buf[i:], nil
-}
-
-// GobDecode implements the gob.GobDecoder interface.
-func (z *Int) GobDecode(buf []byte) error {
- if len(buf) == 0 {
- // Other side sent a nil or default value.
- *z = Int{}
- return nil
- }
- b := buf[0]
- if b>>1 != intGobVersion {
- return fmt.Errorf("Int.GobDecode: encoding version %d not supported", b>>1)
- }
- z.neg = b&1 != 0
- z.abs = z.abs.setBytes(buf[1:])
- return nil
-}
-
-// MarshalText implements the encoding.TextMarshaler interface.
-func (x *Int) MarshalText() (text []byte, err error) {
- if x == nil {
- return []byte("<nil>"), nil
- }
- return x.abs.itoa(x.neg, 10), nil
-}
-
-// UnmarshalText implements the encoding.TextUnmarshaler interface.
-func (z *Int) UnmarshalText(text []byte) error {
- // TODO(gri): get rid of the []byte/string conversion
- if _, ok := z.SetString(string(text), 0); !ok {
- return fmt.Errorf("math/big: cannot unmarshal %q into a *big.Int", text)
- }
- return nil
-}
-
-// The JSON marshallers are only here for API backward compatibility
-// (programs that explicitly look for these two methods). JSON works
-// fine with the TextMarshaler only.
-
-// MarshalJSON implements the json.Marshaler interface.
-func (x *Int) MarshalJSON() ([]byte, error) {
- return x.MarshalText()
-}
-
-// UnmarshalJSON implements the json.Unmarshaler interface.
-func (z *Int) UnmarshalJSON(text []byte) error {
- return z.UnmarshalText(text)
-}
diff --git a/src/cmd/compile/internal/big/intmarsh_test.go b/src/cmd/compile/internal/big/intmarsh_test.go
deleted file mode 100644
index f82956c..0000000
--- a/src/cmd/compile/internal/big/intmarsh_test.go
+++ /dev/null
@@ -1,121 +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 big
-
-import (
- "bytes"
- "encoding/gob"
- "encoding/json"
- "encoding/xml"
- "testing"
-)
-
-var encodingTests = []string{
- "0",
- "1",
- "2",
- "10",
- "1000",
- "1234567890",
- "298472983472983471903246121093472394872319615612417471234712061",
-}
-
-func TestIntGobEncoding(t *testing.T) {
- var medium bytes.Buffer
- enc := gob.NewEncoder(&medium)
- dec := gob.NewDecoder(&medium)
- for _, test := range encodingTests {
- for _, sign := range []string{"", "+", "-"} {
- x := sign + test
- medium.Reset() // empty buffer for each test case (in case of failures)
- var tx Int
- tx.SetString(x, 10)
- if err := enc.Encode(&tx); err != nil {
- t.Errorf("encoding of %s failed: %s", &tx, err)
- continue
- }
- var rx Int
- if err := dec.Decode(&rx); err != nil {
- t.Errorf("decoding of %s failed: %s", &tx, err)
- continue
- }
- if rx.Cmp(&tx) != 0 {
- t.Errorf("transmission of %s failed: got %s want %s", &tx, &rx, &tx)
- }
- }
- }
-}
-
-// Sending a nil Int pointer (inside a slice) on a round trip through gob should yield a zero.
-// TODO: top-level nils.
-func TestGobEncodingNilIntInSlice(t *testing.T) {
- buf := new(bytes.Buffer)
- enc := gob.NewEncoder(buf)
- dec := gob.NewDecoder(buf)
-
- var in = make([]*Int, 1)
- err := enc.Encode(&in)
- if err != nil {
- t.Errorf("gob encode failed: %q", err)
- }
- var out []*Int
- err = dec.Decode(&out)
- if err != nil {
- t.Fatalf("gob decode failed: %q", err)
- }
- if len(out) != 1 {
- t.Fatalf("wrong len; want 1 got %d", len(out))
- }
- var zero Int
- if out[0].Cmp(&zero) != 0 {
- t.Fatalf("transmission of (*Int)(nil) failed: got %s want 0", out)
- }
-}
-
-func TestIntJSONEncoding(t *testing.T) {
- for _, test := range encodingTests {
- for _, sign := range []string{"", "+", "-"} {
- x := sign + test
- var tx Int
- tx.SetString(x, 10)
- b, err := json.Marshal(&tx)
- if err != nil {
- t.Errorf("marshaling of %s failed: %s", &tx, err)
- continue
- }
- var rx Int
- if err := json.Unmarshal(b, &rx); err != nil {
- t.Errorf("unmarshaling of %s failed: %s", &tx, err)
- continue
- }
- if rx.Cmp(&tx) != 0 {
- t.Errorf("JSON encoding of %s failed: got %s want %s", &tx, &rx, &tx)
- }
- }
- }
-}
-
-func TestIntXMLEncoding(t *testing.T) {
- for _, test := range encodingTests {
- for _, sign := range []string{"", "+", "-"} {
- x := sign + test
- var tx Int
- tx.SetString(x, 0)
- b, err := xml.Marshal(&tx)
- if err != nil {
- t.Errorf("marshaling of %s failed: %s", &tx, err)
- continue
- }
- var rx Int
- if err := xml.Unmarshal(b, &rx); err != nil {
- t.Errorf("unmarshaling of %s failed: %s", &tx, err)
- continue
- }
- if rx.Cmp(&tx) != 0 {
- t.Errorf("XML encoding of %s failed: got %s want %s", &tx, &rx, &tx)
- }
- }
- }
-}
diff --git a/src/cmd/compile/internal/big/nat.go b/src/cmd/compile/internal/big/nat.go
deleted file mode 100644
index 7668b64..0000000
--- a/src/cmd/compile/internal/big/nat.go
+++ /dev/null
@@ -1,1282 +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.
-
-// This file implements unsigned multi-precision integers (natural
-// numbers). They are the building blocks for the implementation
-// of signed integers, rationals, and floating-point numbers.
-
-package big
-
-import "math/rand"
-
-// An unsigned integer x of the form
-//
-// x = x[n-1]*_B^(n-1) + x[n-2]*_B^(n-2) + ... + x[1]*_B + x[0]
-//
-// with 0 <= x[i] < _B and 0 <= i < n is stored in a slice of length n,
-// with the digits x[i] as the slice elements.
-//
-// A number is normalized if the slice contains no leading 0 digits.
-// During arithmetic operations, denormalized values may occur but are
-// always normalized before returning the final result. The normalized
-// representation of 0 is the empty or nil slice (length = 0).
-//
-type nat []Word
-
-var (
- natOne = nat{1}
- natTwo = nat{2}
- natTen = nat{10}
-)
-
-func (z nat) clear() {
- for i := range z {
- z[i] = 0
- }
-}
-
-func (z nat) norm() nat {
- i := len(z)
- for i > 0 && z[i-1] == 0 {
- i--
- }
- return z[0:i]
-}
-
-func (z nat) make(n int) nat {
- if n <= cap(z) {
- return z[:n] // reuse z
- }
- // Choosing a good value for e has significant performance impact
- // because it increases the chance that a value can be reused.
- const e = 4 // extra capacity
- return make(nat, n, n+e)
-}
-
-func (z nat) setWord(x Word) nat {
- if x == 0 {
- return z[:0]
- }
- z = z.make(1)
- z[0] = x
- return z
-}
-
-func (z nat) setUint64(x uint64) nat {
- // single-digit values
- if w := Word(x); uint64(w) == x {
- return z.setWord(w)
- }
-
- // compute number of words n required to represent x
- n := 0
- for t := x; t > 0; t >>= _W {
- n++
- }
-
- // split x into n words
- z = z.make(n)
- for i := range z {
- z[i] = Word(x & _M)
- x >>= _W
- }
-
- return z
-}
-
-func (z nat) set(x nat) nat {
- z = z.make(len(x))
- copy(z, x)
- return z
-}
-
-func (z nat) add(x, y nat) nat {
- m := len(x)
- n := len(y)
-
- switch {
- case m < n:
- return z.add(y, x)
- case m == 0:
- // n == 0 because m >= n; result is 0
- return z[:0]
- case n == 0:
- // result is x
- return z.set(x)
- }
- // m > 0
-
- z = z.make(m + 1)
- c := addVV(z[0:n], x, y)
- if m > n {
- c = addVW(z[n:m], x[n:], c)
- }
- z[m] = c
-
- return z.norm()
-}
-
-func (z nat) sub(x, y nat) nat {
- m := len(x)
- n := len(y)
-
- switch {
- case m < n:
- panic("underflow")
- case m == 0:
- // n == 0 because m >= n; result is 0
- return z[:0]
- case n == 0:
- // result is x
- return z.set(x)
- }
- // m > 0
-
- z = z.make(m)
- c := subVV(z[0:n], x, y)
- if m > n {
- c = subVW(z[n:], x[n:], c)
- }
- if c != 0 {
- panic("underflow")
- }
-
- return z.norm()
-}
-
-func (x nat) cmp(y nat) (r int) {
- m := len(x)
- n := len(y)
- if m != n || m == 0 {
- switch {
- case m < n:
- r = -1
- case m > n:
- r = 1
- }
- return
- }
-
- i := m - 1
- for i > 0 && x[i] == y[i] {
- i--
- }
-
- switch {
- case x[i] < y[i]:
- r = -1
- case x[i] > y[i]:
- r = 1
- }
- return
-}
-
-func (z nat) mulAddWW(x nat, y, r Word) nat {
- m := len(x)
- if m == 0 || y == 0 {
- return z.setWord(r) // result is r
- }
- // m > 0
-
- z = z.make(m + 1)
- z[m] = mulAddVWW(z[0:m], x, y, r)
-
- return z.norm()
-}
-
-// basicMul multiplies x and y and leaves the result in z.
-// The (non-normalized) result is placed in z[0 : len(x) + len(y)].
-func basicMul(z, x, y nat) {
- z[0 : len(x)+len(y)].clear() // initialize z
- for i, d := range y {
- if d != 0 {
- z[len(x)+i] = addMulVVW(z[i:i+len(x)], x, d)
- }
- }
-}
-
-// montgomery computes z mod m = x*y*2**(-n*_W) mod m,
-// assuming k = -1/m mod 2**_W.
-// z is used for storing the result which is returned;
-// z must not alias x, y or m.
-// See Gueron, "Efficient Software Implementations of Modular Exponentiation".
-// https://eprint.iacr.org/2011/239.pdf
-// In the terminology of that paper, this is an "Almost Montgomery Multiplication":
-// x and y are required to satisfy 0 <= z < 2**(n*_W) and then the result
-// z is guaranteed to satisfy 0 <= z < 2**(n*_W), but it may not be < m.
-func (z nat) montgomery(x, y, m nat, k Word, n int) nat {
- // This code assumes x, y, m are all the same length, n.
- // (required by addMulVVW and the for loop).
- // It also assumes that x, y are already reduced mod m,
- // or else the result will not be properly reduced.
- if len(x) != n || len(y) != n || len(m) != n {
- panic("math/big: mismatched montgomery number lengths")
- }
- z = z.make(n)
- z.clear()
- var c Word
- for i := 0; i < n; i++ {
- d := y[i]
- c2 := addMulVVW(z, x, d)
- t := z[0] * k
- c3 := addMulVVW(z, m, t)
- copy(z, z[1:])
- cx := c + c2
- cy := cx + c3
- z[n-1] = cy
- if cx < c2 || cy < c3 {
- c = 1
- } else {
- c = 0
- }
- }
- if c != 0 {
- subVV(z, z, m)
- }
- return z
-}
-
-// Fast version of z[0:n+n>>1].add(z[0:n+n>>1], x[0:n]) w/o bounds checks.
-// Factored out for readability - do not use outside karatsuba.
-func karatsubaAdd(z, x nat, n int) {
- if c := addVV(z[0:n], z, x); c != 0 {
- addVW(z[n:n+n>>1], z[n:], c)
- }
-}
-
-// Like karatsubaAdd, but does subtract.
-func karatsubaSub(z, x nat, n int) {
- if c := subVV(z[0:n], z, x); c != 0 {
- subVW(z[n:n+n>>1], z[n:], c)
- }
-}
-
-// Operands that are shorter than karatsubaThreshold are multiplied using
-// "grade school" multiplication; for longer operands the Karatsuba algorithm
-// is used.
-var karatsubaThreshold int = 40 // computed by calibrate.go
-
-// karatsuba multiplies x and y and leaves the result in z.
-// Both x and y must have the same length n and n must be a
-// power of 2. The result vector z must have len(z) >= 6*n.
-// The (non-normalized) result is placed in z[0 : 2*n].
-func karatsuba(z, x, y nat) {
- n := len(y)
-
- // Switch to basic multiplication if numbers are odd or small.
- // (n is always even if karatsubaThreshold is even, but be
- // conservative)
- if n&1 != 0 || n < karatsubaThreshold || n < 2 {
- basicMul(z, x, y)
- return
- }
- // n&1 == 0 && n >= karatsubaThreshold && n >= 2
-
- // Karatsuba multiplication is based on the observation that
- // for two numbers x and y with:
- //
- // x = x1*b + x0
- // y = y1*b + y0
- //
- // the product x*y can be obtained with 3 products z2, z1, z0
- // instead of 4:
- //
- // x*y = x1*y1*b*b + (x1*y0 + x0*y1)*b + x0*y0
- // = z2*b*b + z1*b + z0
- //
- // with:
- //
- // xd = x1 - x0
- // yd = y0 - y1
- //
- // z1 = xd*yd + z2 + z0
- // = (x1-x0)*(y0 - y1) + z2 + z0
- // = x1*y0 - x1*y1 - x0*y0 + x0*y1 + z2 + z0
- // = x1*y0 - z2 - z0 + x0*y1 + z2 + z0
- // = x1*y0 + x0*y1
-
- // split x, y into "digits"
- n2 := n >> 1 // n2 >= 1
- x1, x0 := x[n2:], x[0:n2] // x = x1*b + y0
- y1, y0 := y[n2:], y[0:n2] // y = y1*b + y0
-
- // z is used for the result and temporary storage:
- //
- // 6*n 5*n 4*n 3*n 2*n 1*n 0*n
- // z = [z2 copy|z0 copy| xd*yd | yd:xd | x1*y1 | x0*y0 ]
- //
- // For each recursive call of karatsuba, an unused slice of
- // z is passed in that has (at least) half the length of the
- // caller's z.
-
- // compute z0 and z2 with the result "in place" in z
- karatsuba(z, x0, y0) // z0 = x0*y0
- karatsuba(z[n:], x1, y1) // z2 = x1*y1
-
- // compute xd (or the negative value if underflow occurs)
- s := 1 // sign of product xd*yd
- xd := z[2*n : 2*n+n2]
- if subVV(xd, x1, x0) != 0 { // x1-x0
- s = -s
- subVV(xd, x0, x1) // x0-x1
- }
-
- // compute yd (or the negative value if underflow occurs)
- yd := z[2*n+n2 : 3*n]
- if subVV(yd, y0, y1) != 0 { // y0-y1
- s = -s
- subVV(yd, y1, y0) // y1-y0
- }
-
- // p = (x1-x0)*(y0-y1) == x1*y0 - x1*y1 - x0*y0 + x0*y1 for s > 0
- // p = (x0-x1)*(y0-y1) == x0*y0 - x0*y1 - x1*y0 + x1*y1 for s < 0
- p := z[n*3:]
- karatsuba(p, xd, yd)
-
- // save original z2:z0
- // (ok to use upper half of z since we're done recursing)
- r := z[n*4:]
- copy(r, z[:n*2])
-
- // add up all partial products
- //
- // 2*n n 0
- // z = [ z2 | z0 ]
- // + [ z0 ]
- // + [ z2 ]
- // + [ p ]
- //
- karatsubaAdd(z[n2:], r, n)
- karatsubaAdd(z[n2:], r[n:], n)
- if s > 0 {
- karatsubaAdd(z[n2:], p, n)
- } else {
- karatsubaSub(z[n2:], p, n)
- }
-}
-
-// alias reports whether x and y share the same base array.
-func alias(x, y nat) bool {
- return cap(x) > 0 && cap(y) > 0 && &x[0:cap(x)][cap(x)-1] == &y[0:cap(y)][cap(y)-1]
-}
-
-// addAt implements z += x<<(_W*i); z must be long enough.
-// (we don't use nat.add because we need z to stay the same
-// slice, and we don't need to normalize z after each addition)
-func addAt(z, x nat, i int) {
- if n := len(x); n > 0 {
- if c := addVV(z[i:i+n], z[i:], x); c != 0 {
- j := i + n
- if j < len(z) {
- addVW(z[j:], z[j:], c)
- }
- }
- }
-}
-
-func max(x, y int) int {
- if x > y {
- return x
- }
- return y
-}
-
-// karatsubaLen computes an approximation to the maximum k <= n such that
-// k = p<<i for a number p <= karatsubaThreshold and an i >= 0. Thus, the
-// result is the largest number that can be divided repeatedly by 2 before
-// becoming about the value of karatsubaThreshold.
-func karatsubaLen(n int) int {
- i := uint(0)
- for n > karatsubaThreshold {
- n >>= 1
- i++
- }
- return n << i
-}
-
-func (z nat) mul(x, y nat) nat {
- m := len(x)
- n := len(y)
-
- switch {
- case m < n:
- return z.mul(y, x)
- case m == 0 || n == 0:
- return z[:0]
- case n == 1:
- return z.mulAddWW(x, y[0], 0)
- }
- // m >= n > 1
-
- // determine if z can be reused
- if alias(z, x) || alias(z, y) {
- z = nil // z is an alias for x or y - cannot reuse
- }
-
- // use basic multiplication if the numbers are small
- if n < karatsubaThreshold {
- z = z.make(m + n)
- basicMul(z, x, y)
- return z.norm()
- }
- // m >= n && n >= karatsubaThreshold && n >= 2
-
- // determine Karatsuba length k such that
- //
- // x = xh*b + x0 (0 <= x0 < b)
- // y = yh*b + y0 (0 <= y0 < b)
- // b = 1<<(_W*k) ("base" of digits xi, yi)
- //
- k := karatsubaLen(n)
- // k <= n
-
- // multiply x0 and y0 via Karatsuba
- x0 := x[0:k] // x0 is not normalized
- y0 := y[0:k] // y0 is not normalized
- z = z.make(max(6*k, m+n)) // enough space for karatsuba of x0*y0 and full result of x*y
- karatsuba(z, x0, y0)
- z = z[0 : m+n] // z has final length but may be incomplete
- z[2*k:].clear() // upper portion of z is garbage (and 2*k <= m+n since k <= n <= m)
-
- // If xh != 0 or yh != 0, add the missing terms to z. For
- //
- // xh = xi*b^i + ... + x2*b^2 + x1*b (0 <= xi < b)
- // yh = y1*b (0 <= y1 < b)
- //
- // the missing terms are
- //
- // x0*y1*b and xi*y0*b^i, xi*y1*b^(i+1) for i > 0
- //
- // since all the yi for i > 1 are 0 by choice of k: If any of them
- // were > 0, then yh >= b^2 and thus y >= b^2. Then k' = k*2 would
- // be a larger valid threshold contradicting the assumption about k.
- //
- if k < n || m != n {
- var t nat
-
- // add x0*y1*b
- x0 := x0.norm()
- y1 := y[k:] // y1 is normalized because y is
- t = t.mul(x0, y1) // update t so we don't lose t's underlying array
- addAt(z, t, k)
-
- // add xi*y0<<i, xi*y1*b<<(i+k)
- y0 := y0.norm()
- for i := k; i < len(x); i += k {
- xi := x[i:]
- if len(xi) > k {
- xi = xi[:k]
- }
- xi = xi.norm()
- t = t.mul(xi, y0)
- addAt(z, t, i)
- t = t.mul(xi, y1)
- addAt(z, t, i+k)
- }
- }
-
- return z.norm()
-}
-
-// mulRange computes the product of all the unsigned integers in the
-// range [a, b] inclusively. If a > b (empty range), the result is 1.
-func (z nat) mulRange(a, b uint64) nat {
- switch {
- case a == 0:
- // cut long ranges short (optimization)
- return z.setUint64(0)
- case a > b:
- return z.setUint64(1)
- case a == b:
- return z.setUint64(a)
- case a+1 == b:
- return z.mul(nat(nil).setUint64(a), nat(nil).setUint64(b))
- }
- m := (a + b) / 2
- return z.mul(nat(nil).mulRange(a, m), nat(nil).mulRange(m+1, b))
-}
-
-// q = (x-r)/y, with 0 <= r < y
-func (z nat) divW(x nat, y Word) (q nat, r Word) {
- m := len(x)
- switch {
- case y == 0:
- panic("division by zero")
- case y == 1:
- q = z.set(x) // result is x
- return
- case m == 0:
- q = z[:0] // result is 0
- return
- }
- // m > 0
- z = z.make(m)
- r = divWVW(z, 0, x, y)
- q = z.norm()
- return
-}
-
-func (z nat) div(z2, u, v nat) (q, r nat) {
- if len(v) == 0 {
- panic("division by zero")
- }
-
- if u.cmp(v) < 0 {
- q = z[:0]
- r = z2.set(u)
- return
- }
-
- if len(v) == 1 {
- var r2 Word
- q, r2 = z.divW(u, v[0])
- r = z2.setWord(r2)
- return
- }
-
- q, r = z.divLarge(z2, u, v)
- return
-}
-
-// q = (uIn-r)/v, with 0 <= r < y
-// Uses z as storage for q, and u as storage for r if possible.
-// See Knuth, Volume 2, section 4.3.1, Algorithm D.
-// Preconditions:
-// len(v) >= 2
-// len(uIn) >= len(v)
-func (z nat) divLarge(u, uIn, v nat) (q, r nat) {
- n := len(v)
- m := len(uIn) - n
-
- // determine if z can be reused
- // TODO(gri) should find a better solution - this if statement
- // is very costly (see e.g. time pidigits -s -n 10000)
- if alias(z, uIn) || alias(z, v) {
- z = nil // z is an alias for uIn or v - cannot reuse
- }
- q = z.make(m + 1)
-
- qhatv := make(nat, n+1)
- if alias(u, uIn) || alias(u, v) {
- u = nil // u is an alias for uIn or v - cannot reuse
- }
- u = u.make(len(uIn) + 1)
- u.clear() // TODO(gri) no need to clear if we allocated a new u
-
- // D1.
- shift := nlz(v[n-1])
- if shift > 0 {
- // do not modify v, it may be used by another goroutine simultaneously
- v1 := make(nat, n)
- shlVU(v1, v, shift)
- v = v1
- }
- u[len(uIn)] = shlVU(u[0:len(uIn)], uIn, shift)
-
- // D2.
- for j := m; j >= 0; j-- {
- // D3.
- qhat := Word(_M)
- if u[j+n] != v[n-1] {
- var rhat Word
- qhat, rhat = divWW(u[j+n], u[j+n-1], v[n-1])
-
- // x1 | x2 = q̂v_{n-2}
- x1, x2 := mulWW(qhat, v[n-2])
- // test if q̂v_{n-2} > br̂ + u_{j+n-2}
- for greaterThan(x1, x2, rhat, u[j+n-2]) {
- qhat--
- prevRhat := rhat
- rhat += v[n-1]
- // v[n-1] >= 0, so this tests for overflow.
- if rhat < prevRhat {
- break
- }
- x1, x2 = mulWW(qhat, v[n-2])
- }
- }
-
- // D4.
- qhatv[n] = mulAddVWW(qhatv[0:n], v, qhat, 0)
-
- c := subVV(u[j:j+len(qhatv)], u[j:], qhatv)
- if c != 0 {
- c := addVV(u[j:j+n], u[j:], v)
- u[j+n] += c
- qhat--
- }
-
- q[j] = qhat
- }
-
- q = q.norm()
- shrVU(u, u, shift)
- r = u.norm()
-
- return q, r
-}
-
-// Length of x in bits. x must be normalized.
-func (x nat) bitLen() int {
- if i := len(x) - 1; i >= 0 {
- return i*_W + bitLen(x[i])
- }
- return 0
-}
-
-const deBruijn32 = 0x077CB531
-
-var deBruijn32Lookup = []byte{
- 0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8,
- 31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9,
-}
-
-const deBruijn64 = 0x03f79d71b4ca8b09
-
-var deBruijn64Lookup = []byte{
- 0, 1, 56, 2, 57, 49, 28, 3, 61, 58, 42, 50, 38, 29, 17, 4,
- 62, 47, 59, 36, 45, 43, 51, 22, 53, 39, 33, 30, 24, 18, 12, 5,
- 63, 55, 48, 27, 60, 41, 37, 16, 46, 35, 44, 21, 52, 32, 23, 11,
- 54, 26, 40, 15, 34, 20, 31, 10, 25, 14, 19, 9, 13, 8, 7, 6,
-}
-
-// trailingZeroBits returns the number of consecutive least significant zero
-// bits of x.
-func trailingZeroBits(x Word) uint {
- // x & -x leaves only the right-most bit set in the word. Let k be the
- // index of that bit. Since only a single bit is set, the value is two
- // to the power of k. Multiplying by a power of two is equivalent to
- // left shifting, in this case by k bits. The de Bruijn constant is
- // such that all six bit, consecutive substrings are distinct.
- // Therefore, if we have a left shifted version of this constant we can
- // find by how many bits it was shifted by looking at which six bit
- // substring ended up at the top of the word.
- // (Knuth, volume 4, section 7.3.1)
- switch _W {
- case 32:
- return uint(deBruijn32Lookup[((x&-x)*deBruijn32)>>27])
- case 64:
- return uint(deBruijn64Lookup[((x&-x)*(deBruijn64&_M))>>58])
- default:
- panic("unknown word size")
- }
-}
-
-// trailingZeroBits returns the number of consecutive least significant zero
-// bits of x.
-func (x nat) trailingZeroBits() uint {
- if len(x) == 0 {
- return 0
- }
- var i uint
- for x[i] == 0 {
- i++
- }
- // x[i] != 0
- return i*_W + trailingZeroBits(x[i])
-}
-
-// z = x << s
-func (z nat) shl(x nat, s uint) nat {
- m := len(x)
- if m == 0 {
- return z[:0]
- }
- // m > 0
-
- n := m + int(s/_W)
- z = z.make(n + 1)
- z[n] = shlVU(z[n-m:n], x, s%_W)
- z[0 : n-m].clear()
-
- return z.norm()
-}
-
-// z = x >> s
-func (z nat) shr(x nat, s uint) nat {
- m := len(x)
- n := m - int(s/_W)
- if n <= 0 {
- return z[:0]
- }
- // n > 0
-
- z = z.make(n)
- shrVU(z, x[m-n:], s%_W)
-
- return z.norm()
-}
-
-func (z nat) setBit(x nat, i uint, b uint) nat {
- j := int(i / _W)
- m := Word(1) << (i % _W)
- n := len(x)
- switch b {
- case 0:
- z = z.make(n)
- copy(z, x)
- if j >= n {
- // no need to grow
- return z
- }
- z[j] &^= m
- return z.norm()
- case 1:
- if j >= n {
- z = z.make(j + 1)
- z[n:].clear()
- } else {
- z = z.make(n)
- }
- copy(z, x)
- z[j] |= m
- // no need to normalize
- return z
- }
- panic("set bit is not 0 or 1")
-}
-
-// bit returns the value of the i'th bit, with lsb == bit 0.
-func (x nat) bit(i uint) uint {
- j := i / _W
- if j >= uint(len(x)) {
- return 0
- }
- // 0 <= j < len(x)
- return uint(x[j] >> (i % _W) & 1)
-}
-
-// sticky returns 1 if there's a 1 bit within the
-// i least significant bits, otherwise it returns 0.
-func (x nat) sticky(i uint) uint {
- j := i / _W
- if j >= uint(len(x)) {
- if len(x) == 0 {
- return 0
- }
- return 1
- }
- // 0 <= j < len(x)
- for _, x := range x[:j] {
- if x != 0 {
- return 1
- }
- }
- if x[j]<<(_W-i%_W) != 0 {
- return 1
- }
- return 0
-}
-
-func (z nat) and(x, y nat) nat {
- m := len(x)
- n := len(y)
- if m > n {
- m = n
- }
- // m <= n
-
- z = z.make(m)
- for i := 0; i < m; i++ {
- z[i] = x[i] & y[i]
- }
-
- return z.norm()
-}
-
-func (z nat) andNot(x, y nat) nat {
- m := len(x)
- n := len(y)
- if n > m {
- n = m
- }
- // m >= n
-
- z = z.make(m)
- for i := 0; i < n; i++ {
- z[i] = x[i] &^ y[i]
- }
- copy(z[n:m], x[n:m])
-
- return z.norm()
-}
-
-func (z nat) or(x, y nat) nat {
- m := len(x)
- n := len(y)
- s := x
- if m < n {
- n, m = m, n
- s = y
- }
- // m >= n
-
- z = z.make(m)
- for i := 0; i < n; i++ {
- z[i] = x[i] | y[i]
- }
- copy(z[n:m], s[n:m])
-
- return z.norm()
-}
-
-func (z nat) xor(x, y nat) nat {
- m := len(x)
- n := len(y)
- s := x
- if m < n {
- n, m = m, n
- s = y
- }
- // m >= n
-
- z = z.make(m)
- for i := 0; i < n; i++ {
- z[i] = x[i] ^ y[i]
- }
- copy(z[n:m], s[n:m])
-
- return z.norm()
-}
-
-// greaterThan reports whether (x1<<_W + x2) > (y1<<_W + y2)
-func greaterThan(x1, x2, y1, y2 Word) bool {
- return x1 > y1 || x1 == y1 && x2 > y2
-}
-
-// modW returns x % d.
-func (x nat) modW(d Word) (r Word) {
- // TODO(agl): we don't actually need to store the q value.
- var q nat
- q = q.make(len(x))
- return divWVW(q, 0, x, d)
-}
-
-// random creates a random integer in [0..limit), using the space in z if
-// possible. n is the bit length of limit.
-func (z nat) random(rand *rand.Rand, limit nat, n int) nat {
- if alias(z, limit) {
- z = nil // z is an alias for limit - cannot reuse
- }
- z = z.make(len(limit))
-
- bitLengthOfMSW := uint(n % _W)
- if bitLengthOfMSW == 0 {
- bitLengthOfMSW = _W
- }
- mask := Word((1 << bitLengthOfMSW) - 1)
-
- for {
- switch _W {
- case 32:
- for i := range z {
- z[i] = Word(rand.Uint32())
- }
- case 64:
- for i := range z {
- z[i] = Word(rand.Uint32()) | Word(rand.Uint32())<<32
- }
- default:
- panic("unknown word size")
- }
- z[len(limit)-1] &= mask
- if z.cmp(limit) < 0 {
- break
- }
- }
-
- return z.norm()
-}
-
-// If m != 0 (i.e., len(m) != 0), expNN sets z to x**y mod m;
-// otherwise it sets z to x**y. The result is the value of z.
-func (z nat) expNN(x, y, m nat) nat {
- if alias(z, x) || alias(z, y) {
- // We cannot allow in-place modification of x or y.
- z = nil
- }
-
- // x**y mod 1 == 0
- if len(m) == 1 && m[0] == 1 {
- return z.setWord(0)
- }
- // m == 0 || m > 1
-
- // x**0 == 1
- if len(y) == 0 {
- return z.setWord(1)
- }
- // y > 0
-
- // x**1 mod m == x mod m
- if len(y) == 1 && y[0] == 1 && len(m) != 0 {
- _, z = z.div(z, x, m)
- return z
- }
- // y > 1
-
- if len(m) != 0 {
- // We likely end up being as long as the modulus.
- z = z.make(len(m))
- }
- z = z.set(x)
-
- // If the base is non-trivial and the exponent is large, we use
- // 4-bit, windowed exponentiation. This involves precomputing 14 values
- // (x^2...x^15) but then reduces the number of multiply-reduces by a
- // third. Even for a 32-bit exponent, this reduces the number of
- // operations. Uses Montgomery method for odd moduli.
- if len(x) > 1 && len(y) > 1 && len(m) > 0 {
- if m[0]&1 == 1 {
- return z.expNNMontgomery(x, y, m)
- }
- return z.expNNWindowed(x, y, m)
- }
-
- v := y[len(y)-1] // v > 0 because y is normalized and y > 0
- shift := nlz(v) + 1
- v <<= shift
- var q nat
-
- const mask = 1 << (_W - 1)
-
- // We walk through the bits of the exponent one by one. Each time we
- // see a bit, we square, thus doubling the power. If the bit is a one,
- // we also multiply by x, thus adding one to the power.
-
- w := _W - int(shift)
- // zz and r are used to avoid allocating in mul and div as
- // otherwise the arguments would alias.
- var zz, r nat
- for j := 0; j < w; j++ {
- zz = zz.mul(z, z)
- zz, z = z, zz
-
- if v&mask != 0 {
- zz = zz.mul(z, x)
- zz, z = z, zz
- }
-
- if len(m) != 0 {
- zz, r = zz.div(r, z, m)
- zz, r, q, z = q, z, zz, r
- }
-
- v <<= 1
- }
-
- for i := len(y) - 2; i >= 0; i-- {
- v = y[i]
-
- for j := 0; j < _W; j++ {
- zz = zz.mul(z, z)
- zz, z = z, zz
-
- if v&mask != 0 {
- zz = zz.mul(z, x)
- zz, z = z, zz
- }
-
- if len(m) != 0 {
- zz, r = zz.div(r, z, m)
- zz, r, q, z = q, z, zz, r
- }
-
- v <<= 1
- }
- }
-
- return z.norm()
-}
-
-// expNNWindowed calculates x**y mod m using a fixed, 4-bit window.
-func (z nat) expNNWindowed(x, y, m nat) nat {
- // zz and r are used to avoid allocating in mul and div as otherwise
- // the arguments would alias.
- var zz, r nat
-
- const n = 4
- // powers[i] contains x^i.
- var powers [1 << n]nat
- powers[0] = natOne
- powers[1] = x
- for i := 2; i < 1<<n; i += 2 {
- p2, p, p1 := &powers[i/2], &powers[i], &powers[i+1]
- *p = p.mul(*p2, *p2)
- zz, r = zz.div(r, *p, m)
- *p, r = r, *p
- *p1 = p1.mul(*p, x)
- zz, r = zz.div(r, *p1, m)
- *p1, r = r, *p1
- }
-
- z = z.setWord(1)
-
- for i := len(y) - 1; i >= 0; i-- {
- yi := y[i]
- for j := 0; j < _W; j += n {
- if i != len(y)-1 || j != 0 {
- // Unrolled loop for significant performance
- // gain. Use go test -bench=".*" in crypto/rsa
- // to check performance before making changes.
- zz = zz.mul(z, z)
- zz, z = z, zz
- zz, r = zz.div(r, z, m)
- z, r = r, z
-
- zz = zz.mul(z, z)
- zz, z = z, zz
- zz, r = zz.div(r, z, m)
- z, r = r, z
-
- zz = zz.mul(z, z)
- zz, z = z, zz
- zz, r = zz.div(r, z, m)
- z, r = r, z
-
- zz = zz.mul(z, z)
- zz, z = z, zz
- zz, r = zz.div(r, z, m)
- z, r = r, z
- }
-
- zz = zz.mul(z, powers[yi>>(_W-n)])
- zz, z = z, zz
- zz, r = zz.div(r, z, m)
- z, r = r, z
-
- yi <<= n
- }
- }
-
- return z.norm()
-}
-
-// expNNMontgomery calculates x**y mod m using a fixed, 4-bit window.
-// Uses Montgomery representation.
-func (z nat) expNNMontgomery(x, y, m nat) nat {
- numWords := len(m)
-
- // We want the lengths of x and m to be equal.
- // It is OK if x >= m as long as len(x) == len(m).
- if len(x) > numWords {
- _, x = nat(nil).div(nil, x, m)
- // Note: now len(x) <= numWords, not guaranteed ==.
- }
- if len(x) < numWords {
- rr := make(nat, numWords)
- copy(rr, x)
- x = rr
- }
-
- // Ideally the precomputations would be performed outside, and reused
- // k0 = -m**-1 mod 2**_W. Algorithm from: Dumas, J.G. "On Newton–Raphson
- // Iteration for Multiplicative Inverses Modulo Prime Powers".
- k0 := 2 - m[0]
- t := m[0] - 1
- for i := 1; i < _W; i <<= 1 {
- t *= t
- k0 *= (t + 1)
- }
- k0 = -k0
-
- // RR = 2**(2*_W*len(m)) mod m
- RR := nat(nil).setWord(1)
- zz := nat(nil).shl(RR, uint(2*numWords*_W))
- _, RR = RR.div(RR, zz, m)
- if len(RR) < numWords {
- zz = zz.make(numWords)
- copy(zz, RR)
- RR = zz
- }
- // one = 1, with equal length to that of m
- one := make(nat, numWords)
- one[0] = 1
-
- const n = 4
- // powers[i] contains x^i
- var powers [1 << n]nat
- powers[0] = powers[0].montgomery(one, RR, m, k0, numWords)
- powers[1] = powers[1].montgomery(x, RR, m, k0, numWords)
- for i := 2; i < 1<<n; i++ {
- powers[i] = powers[i].montgomery(powers[i-1], powers[1], m, k0, numWords)
- }
-
- // initialize z = 1 (Montgomery 1)
- z = z.make(numWords)
- copy(z, powers[0])
-
- zz = zz.make(numWords)
-
- // same windowed exponent, but with Montgomery multiplications
- for i := len(y) - 1; i >= 0; i-- {
- yi := y[i]
- for j := 0; j < _W; j += n {
- if i != len(y)-1 || j != 0 {
- zz = zz.montgomery(z, z, m, k0, numWords)
- z = z.montgomery(zz, zz, m, k0, numWords)
- zz = zz.montgomery(z, z, m, k0, numWords)
- z = z.montgomery(zz, zz, m, k0, numWords)
- }
- zz = zz.montgomery(z, powers[yi>>(_W-n)], m, k0, numWords)
- z, zz = zz, z
- yi <<= n
- }
- }
- // convert to regular number
- zz = zz.montgomery(z, one, m, k0, numWords)
-
- // One last reduction, just in case.
- // See golang.org/issue/13907.
- if zz.cmp(m) >= 0 {
- // Common case is m has high bit set; in that case,
- // since zz is the same length as m, there can be just
- // one multiple of m to remove. Just subtract.
- // We think that the subtract should be sufficient in general,
- // so do that unconditionally, but double-check,
- // in case our beliefs are wrong.
- // The div is not expected to be reached.
- zz = zz.sub(zz, m)
- if zz.cmp(m) >= 0 {
- _, zz = nat(nil).div(nil, zz, m)
- }
- }
-
- return zz.norm()
-}
-
-// probablyPrime performs n Miller-Rabin tests to check whether x is prime.
-// If x is prime, it returns true.
-// If x is not prime, it returns false with probability at least 1 - ¼ⁿ.
-//
-// It is not suitable for judging primes that an adversary may have crafted
-// to fool this test.
-func (n nat) probablyPrime(reps int) bool {
- if len(n) == 0 {
- return false
- }
-
- if len(n) == 1 {
- if n[0] < 2 {
- return false
- }
-
- if n[0]%2 == 0 {
- return n[0] == 2
- }
-
- // We have to exclude these cases because we reject all
- // multiples of these numbers below.
- switch n[0] {
- case 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53:
- return true
- }
- }
-
- if n[0]&1 == 0 {
- return false // n is even
- }
-
- const primesProduct32 = 0xC0CFD797 // Π {p ∈ primes, 2 < p <= 29}
- const primesProduct64 = 0xE221F97C30E94E1D // Π {p ∈ primes, 2 < p <= 53}
-
- var r Word
- switch _W {
- case 32:
- r = n.modW(primesProduct32)
- case 64:
- r = n.modW(primesProduct64 & _M)
- default:
- panic("Unknown word size")
- }
-
- if r%3 == 0 || r%5 == 0 || r%7 == 0 || r%11 == 0 ||
- r%13 == 0 || r%17 == 0 || r%19 == 0 || r%23 == 0 || r%29 == 0 {
- return false
- }
-
- if _W == 64 && (r%31 == 0 || r%37 == 0 || r%41 == 0 ||
- r%43 == 0 || r%47 == 0 || r%53 == 0) {
- return false
- }
-
- nm1 := nat(nil).sub(n, natOne)
- // determine q, k such that nm1 = q << k
- k := nm1.trailingZeroBits()
- q := nat(nil).shr(nm1, k)
-
- nm3 := nat(nil).sub(nm1, natTwo)
- rand := rand.New(rand.NewSource(int64(n[0])))
-
- var x, y, quotient nat
- nm3Len := nm3.bitLen()
-
-NextRandom:
- for i := 0; i < reps; i++ {
- x = x.random(rand, nm3, nm3Len)
- x = x.add(x, natTwo)
- y = y.expNN(x, q, n)
- if y.cmp(natOne) == 0 || y.cmp(nm1) == 0 {
- continue
- }
- for j := uint(1); j < k; j++ {
- y = y.mul(y, y)
- quotient, y = quotient.div(y, y, n)
- if y.cmp(nm1) == 0 {
- continue NextRandom
- }
- if y.cmp(natOne) == 0 {
- return false
- }
- }
- return false
- }
-
- return true
-}
-
-// bytes writes the value of z into buf using big-endian encoding.
-// len(buf) must be >= len(z)*_S. The value of z is encoded in the
-// slice buf[i:]. The number i of unused bytes at the beginning of
-// buf is returned as result.
-func (z nat) bytes(buf []byte) (i int) {
- i = len(buf)
- for _, d := range z {
- for j := 0; j < _S; j++ {
- i--
- buf[i] = byte(d)
- d >>= 8
- }
- }
-
- for i < len(buf) && buf[i] == 0 {
- i++
- }
-
- return
-}
-
-// setBytes interprets buf as the bytes of a big-endian unsigned
-// integer, sets z to that value, and returns z.
-func (z nat) setBytes(buf []byte) nat {
- z = z.make((len(buf) + _S - 1) / _S)
-
- k := 0
- s := uint(0)
- var d Word
- for i := len(buf); i > 0; i-- {
- d |= Word(buf[i-1]) << s
- if s += 8; s == _S*8 {
- z[k] = d
- k++
- s = 0
- d = 0
- }
- }
- if k < len(z) {
- z[k] = d
- }
-
- return z.norm()
-}
diff --git a/src/cmd/compile/internal/big/nat_test.go b/src/cmd/compile/internal/big/nat_test.go
deleted file mode 100644
index 563ccb3..0000000
--- a/src/cmd/compile/internal/big/nat_test.go
+++ /dev/null
@@ -1,654 +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 big
-
-import (
- "runtime"
- "strings"
- "testing"
-)
-
-var cmpTests = []struct {
- x, y nat
- r int
-}{
- {nil, nil, 0},
- {nil, nat(nil), 0},
- {nat(nil), nil, 0},
- {nat(nil), nat(nil), 0},
- {nat{0}, nat{0}, 0},
- {nat{0}, nat{1}, -1},
- {nat{1}, nat{0}, 1},
- {nat{1}, nat{1}, 0},
- {nat{0, _M}, nat{1}, 1},
- {nat{1}, nat{0, _M}, -1},
- {nat{1, _M}, nat{0, _M}, 1},
- {nat{0, _M}, nat{1, _M}, -1},
- {nat{16, 571956, 8794, 68}, nat{837, 9146, 1, 754489}, -1},
- {nat{34986, 41, 105, 1957}, nat{56, 7458, 104, 1957}, 1},
-}
-
-func TestCmp(t *testing.T) {
- for i, a := range cmpTests {
- r := a.x.cmp(a.y)
- if r != a.r {
- t.Errorf("#%d got r = %v; want %v", i, r, a.r)
- }
- }
-}
-
-type funNN func(z, x, y nat) nat
-type argNN struct {
- z, x, y nat
-}
-
-var sumNN = []argNN{
- {},
- {nat{1}, nil, nat{1}},
- {nat{1111111110}, nat{123456789}, nat{987654321}},
- {nat{0, 0, 0, 1}, nil, nat{0, 0, 0, 1}},
- {nat{0, 0, 0, 1111111110}, nat{0, 0, 0, 123456789}, nat{0, 0, 0, 987654321}},
- {nat{0, 0, 0, 1}, nat{0, 0, _M}, nat{0, 0, 1}},
-}
-
-var prodNN = []argNN{
- {},
- {nil, nil, nil},
- {nil, nat{991}, nil},
- {nat{991}, nat{991}, nat{1}},
- {nat{991 * 991}, nat{991}, nat{991}},
- {nat{0, 0, 991 * 991}, nat{0, 991}, nat{0, 991}},
- {nat{1 * 991, 2 * 991, 3 * 991, 4 * 991}, nat{1, 2, 3, 4}, nat{991}},
- {nat{4, 11, 20, 30, 20, 11, 4}, nat{1, 2, 3, 4}, nat{4, 3, 2, 1}},
- // 3^100 * 3^28 = 3^128
- {
- natFromString("11790184577738583171520872861412518665678211592275841109096961"),
- natFromString("515377520732011331036461129765621272702107522001"),
- natFromString("22876792454961"),
- },
- // z = 111....1 (70000 digits)
- // x = 10^(99*700) + ... + 10^1400 + 10^700 + 1
- // y = 111....1 (700 digits, larger than Karatsuba threshold on 32-bit and 64-bit)
- {
- natFromString(strings.Repeat("1", 70000)),
- natFromString("1" + strings.Repeat(strings.Repeat("0", 699)+"1", 99)),
- natFromString(strings.Repeat("1", 700)),
- },
- // z = 111....1 (20000 digits)
- // x = 10^10000 + 1
- // y = 111....1 (10000 digits)
- {
- natFromString(strings.Repeat("1", 20000)),
- natFromString("1" + strings.Repeat("0", 9999) + "1"),
- natFromString(strings.Repeat("1", 10000)),
- },
-}
-
-func natFromString(s string) nat {
- x, _, _, err := nat(nil).scan(strings.NewReader(s), 0, false)
- if err != nil {
- panic(err)
- }
- return x
-}
-
-func TestSet(t *testing.T) {
- for _, a := range sumNN {
- z := nat(nil).set(a.z)
- if z.cmp(a.z) != 0 {
- t.Errorf("got z = %v; want %v", z, a.z)
- }
- }
-}
-
-func testFunNN(t *testing.T, msg string, f funNN, a argNN) {
- z := f(nil, a.x, a.y)
- if z.cmp(a.z) != 0 {
- t.Errorf("%s%+v\n\tgot z = %v; want %v", msg, a, z, a.z)
- }
-}
-
-func TestFunNN(t *testing.T) {
- for _, a := range sumNN {
- arg := a
- testFunNN(t, "add", nat.add, arg)
-
- arg = argNN{a.z, a.y, a.x}
- testFunNN(t, "add symmetric", nat.add, arg)
-
- arg = argNN{a.x, a.z, a.y}
- testFunNN(t, "sub", nat.sub, arg)
-
- arg = argNN{a.y, a.z, a.x}
- testFunNN(t, "sub symmetric", nat.sub, arg)
- }
-
- for _, a := range prodNN {
- arg := a
- testFunNN(t, "mul", nat.mul, arg)
-
- arg = argNN{a.z, a.y, a.x}
- testFunNN(t, "mul symmetric", nat.mul, arg)
- }
-}
-
-var mulRangesN = []struct {
- a, b uint64
- prod string
-}{
- {0, 0, "0"},
- {1, 1, "1"},
- {1, 2, "2"},
- {1, 3, "6"},
- {10, 10, "10"},
- {0, 100, "0"},
- {0, 1e9, "0"},
- {1, 0, "1"}, // empty range
- {100, 1, "1"}, // empty range
- {1, 10, "3628800"}, // 10!
- {1, 20, "2432902008176640000"}, // 20!
- {1, 100,
- "933262154439441526816992388562667004907159682643816214685929" +
- "638952175999932299156089414639761565182862536979208272237582" +
- "51185210916864000000000000000000000000", // 100!
- },
-}
-
-func TestMulRangeN(t *testing.T) {
- for i, r := range mulRangesN {
- prod := string(nat(nil).mulRange(r.a, r.b).utoa(10))
- if prod != r.prod {
- t.Errorf("#%d: got %s; want %s", i, prod, r.prod)
- }
- }
-}
-
-// allocBytes returns the number of bytes allocated by invoking f.
-func allocBytes(f func()) uint64 {
- var stats runtime.MemStats
- runtime.ReadMemStats(&stats)
- t := stats.TotalAlloc
- f()
- runtime.ReadMemStats(&stats)
- return stats.TotalAlloc - t
-}
-
-// TestMulUnbalanced tests that multiplying numbers of different lengths
-// does not cause deep recursion and in turn allocate too much memory.
-// Test case for issue 3807.
-func TestMulUnbalanced(t *testing.T) {
- defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(1))
- x := rndNat(50000)
- y := rndNat(40)
- allocSize := allocBytes(func() {
- nat(nil).mul(x, y)
- })
- inputSize := uint64(len(x)+len(y)) * _S
- if ratio := allocSize / uint64(inputSize); ratio > 10 {
- t.Errorf("multiplication uses too much memory (%d > %d times the size of inputs)", allocSize, ratio)
- }
-}
-
-func rndNat(n int) nat {
- return nat(rndV(n)).norm()
-}
-
-func BenchmarkMul(b *testing.B) {
- mulx := rndNat(1e4)
- muly := rndNat(1e4)
- b.ResetTimer()
- for i := 0; i < b.N; i++ {
- var z nat
- z.mul(mulx, muly)
- }
-}
-
-func TestNLZ(t *testing.T) {
- var x Word = _B >> 1
- for i := 0; i <= _W; i++ {
- if int(nlz(x)) != i {
- t.Errorf("failed at %x: got %d want %d", x, nlz(x), i)
- }
- x >>= 1
- }
-}
-
-type shiftTest struct {
- in nat
- shift uint
- out nat
-}
-
-var leftShiftTests = []shiftTest{
- {nil, 0, nil},
- {nil, 1, nil},
- {natOne, 0, natOne},
- {natOne, 1, natTwo},
- {nat{1 << (_W - 1)}, 1, nat{0}},
- {nat{1 << (_W - 1), 0}, 1, nat{0, 1}},
-}
-
-func TestShiftLeft(t *testing.T) {
- for i, test := range leftShiftTests {
- var z nat
- z = z.shl(test.in, test.shift)
- for j, d := range test.out {
- if j >= len(z) || z[j] != d {
- t.Errorf("#%d: got: %v want: %v", i, z, test.out)
- break
- }
- }
- }
-}
-
-var rightShiftTests = []shiftTest{
- {nil, 0, nil},
- {nil, 1, nil},
- {natOne, 0, natOne},
- {natOne, 1, nil},
- {natTwo, 1, natOne},
- {nat{0, 1}, 1, nat{1 << (_W - 1)}},
- {nat{2, 1, 1}, 1, nat{1<<(_W-1) + 1, 1 << (_W - 1)}},
-}
-
-func TestShiftRight(t *testing.T) {
- for i, test := range rightShiftTests {
- var z nat
- z = z.shr(test.in, test.shift)
- for j, d := range test.out {
- if j >= len(z) || z[j] != d {
- t.Errorf("#%d: got: %v want: %v", i, z, test.out)
- break
- }
- }
- }
-}
-
-type modWTest struct {
- in string
- dividend string
- out string
-}
-
-var modWTests32 = []modWTest{
- {"23492635982634928349238759823742", "252341", "220170"},
-}
-
-var modWTests64 = []modWTest{
- {"6527895462947293856291561095690465243862946", "524326975699234", "375066989628668"},
-}
-
-func runModWTests(t *testing.T, tests []modWTest) {
- for i, test := range tests {
- in, _ := new(Int).SetString(test.in, 10)
- d, _ := new(Int).SetString(test.dividend, 10)
- out, _ := new(Int).SetString(test.out, 10)
-
- r := in.abs.modW(d.abs[0])
- if r != out.abs[0] {
- t.Errorf("#%d failed: got %d want %s", i, r, out)
- }
- }
-}
-
-func TestModW(t *testing.T) {
- if _W >= 32 {
- runModWTests(t, modWTests32)
- }
- if _W >= 64 {
- runModWTests(t, modWTests64)
- }
-}
-
-func TestTrailingZeroBits(t *testing.T) {
- // test 0 case explicitly
- if n := trailingZeroBits(0); n != 0 {
- t.Errorf("got trailingZeroBits(0) = %d; want 0", n)
- }
-
- x := Word(1)
- for i := uint(0); i < _W; i++ {
- n := trailingZeroBits(x)
- if n != i {
- t.Errorf("got trailingZeroBits(%#x) = %d; want %d", x, n, i%_W)
- }
- x <<= 1
- }
-
- // test 0 case explicitly
- if n := nat(nil).trailingZeroBits(); n != 0 {
- t.Errorf("got nat(nil).trailingZeroBits() = %d; want 0", n)
- }
-
- y := nat(nil).set(natOne)
- for i := uint(0); i <= 3*_W; i++ {
- n := y.trailingZeroBits()
- if n != i {
- t.Errorf("got 0x%s.trailingZeroBits() = %d; want %d", y.utoa(16), n, i)
- }
- y = y.shl(y, 1)
- }
-}
-
-var montgomeryTests = []struct {
- x, y, m string
- k0 uint64
- out32, out64 string
-}{
- {
- "0xffffffffffffffffffffffffffffffffffffffffffffffffe",
- "0xffffffffffffffffffffffffffffffffffffffffffffffffe",
- "0xfffffffffffffffffffffffffffffffffffffffffffffffff",
- 1,
- "0x1000000000000000000000000000000000000000000",
- "0x10000000000000000000000000000000000",
- },
- {
- "0x000000000ffffff5",
- "0x000000000ffffff0",
- "0x0000000010000001",
- 0xff0000000fffffff,
- "0x000000000bfffff4",
- "0x0000000003400001",
- },
- {
- "0x0000000080000000",
- "0x00000000ffffffff",
- "0x1000000000000001",
- 0xfffffffffffffff,
- "0x0800000008000001",
- "0x0800000008000001",
- },
- {
- "0x0000000080000000",
- "0x0000000080000000",
- "0xffffffff00000001",
- 0xfffffffeffffffff,
- "0xbfffffff40000001",
- "0xbfffffff40000001",
- },
- {
- "0x0000000080000000",
- "0x0000000080000000",
- "0x00ffffff00000001",
- 0xfffffeffffffff,
- "0xbfffff40000001",
- "0xbfffff40000001",
- },
- {
- "0x0000000080000000",
- "0x0000000080000000",
- "0x0000ffff00000001",
- 0xfffeffffffff,
- "0xbfff40000001",
- "0xbfff40000001",
- },
- {
- "0x3321ffffffffffffffffffffffffffff00000000000022222623333333332bbbb888c0",
- "0x3321ffffffffffffffffffffffffffff00000000000022222623333333332bbbb888c0",
- "0x33377fffffffffffffffffffffffffffffffffffffffffffff0000000000022222eee1",
- 0xdecc8f1249812adf,
- "0x04eb0e11d72329dc0915f86784820fc403275bf2f6620a20e0dd344c5cd0875e50deb5",
- "0x0d7144739a7d8e11d72329dc0915f86784820fc403275bf2f61ed96f35dd34dbb3d6a0",
- },
- {
- "0x10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffff00000000000022222223333333333444444444",
- "0x10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffff999999999999999aaabbbbbbbbcccccccccccc",
- "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff33377fffffffffffffffffffffffffffffffffffffffffffff0000000000022222eee1",
- 0xdecc8f1249812adf,
- "0x5c0d52f451aec609b15da8e5e5626c4eaa88723bdeac9d25ca9b961269400410ca208a16af9c2fb07d7a11c7772cba02c22f9711078d51a3797eb18e691295293284d988e349fa6deba46b25a4ecd9f715",
- "0x92fcad4b5c0d52f451aec609b15da8e5e5626c4eaa88723bdeac9d25ca9b961269400410ca208a16af9c2fb07d799c32fe2f3cc5422f9711078d51a3797eb18e691295293284d8f5e69caf6decddfe1df6",
- },
-}
-
-func TestMontgomery(t *testing.T) {
- one := NewInt(1)
- _B := new(Int).Lsh(one, _W)
- for i, test := range montgomeryTests {
- x := natFromString(test.x)
- y := natFromString(test.y)
- m := natFromString(test.m)
- for len(x) < len(m) {
- x = append(x, 0)
- }
- for len(y) < len(m) {
- y = append(y, 0)
- }
-
- if x.cmp(m) > 0 {
- _, r := nat(nil).div(nil, x, m)
- t.Errorf("#%d: x > m (0x%s > 0x%s; use 0x%s)", i, x.utoa(16), m.utoa(16), r.utoa(16))
- }
- if y.cmp(m) > 0 {
- _, r := nat(nil).div(nil, x, m)
- t.Errorf("#%d: y > m (0x%s > 0x%s; use 0x%s)", i, y.utoa(16), m.utoa(16), r.utoa(16))
- }
-
- var out nat
- if _W == 32 {
- out = natFromString(test.out32)
- } else {
- out = natFromString(test.out64)
- }
-
- // t.Logf("#%d: len=%d\n", i, len(m))
-
- // check output in table
- xi := &Int{abs: x}
- yi := &Int{abs: y}
- mi := &Int{abs: m}
- p := new(Int).Mod(new(Int).Mul(xi, new(Int).Mul(yi, new(Int).ModInverse(new(Int).Lsh(one, uint(len(m))*_W), mi))), mi)
- if out.cmp(p.abs.norm()) != 0 {
- t.Errorf("#%d: out in table=0x%s, computed=0x%s", i, out.utoa(16), p.abs.norm().utoa(16))
- }
-
- // check k0 in table
- k := new(Int).Mod(&Int{abs: m}, _B)
- k = new(Int).Sub(_B, k)
- k = new(Int).Mod(k, _B)
- k0 := Word(new(Int).ModInverse(k, _B).Uint64())
- if k0 != Word(test.k0) {
- t.Errorf("#%d: k0 in table=%#x, computed=%#x\n", i, test.k0, k0)
- }
-
- // check montgomery with correct k0 produces correct output
- z := nat(nil).montgomery(x, y, m, k0, len(m))
- z = z.norm()
- if z.cmp(out) != 0 {
- t.Errorf("#%d: got 0x%s want 0x%s", i, z.utoa(16), out.utoa(16))
- }
- }
-}
-
-var expNNTests = []struct {
- x, y, m string
- out string
-}{
- {"0", "0", "0", "1"},
- {"0", "0", "1", "0"},
- {"1", "1", "1", "0"},
- {"2", "1", "1", "0"},
- {"2", "2", "1", "0"},
- {"10", "100000000000", "1", "0"},
- {"0x8000000000000000", "2", "", "0x40000000000000000000000000000000"},
- {"0x8000000000000000", "2", "6719", "4944"},
- {"0x8000000000000000", "3", "6719", "5447"},
- {"0x8000000000000000", "1000", "6719", "1603"},
- {"0x8000000000000000", "1000000", "6719", "3199"},
- {
- "2938462938472983472983659726349017249287491026512746239764525612965293865296239471239874193284792387498274256129746192347",
- "298472983472983471903246121093472394872319615612417471234712061",
- "29834729834729834729347290846729561262544958723956495615629569234729836259263598127342374289365912465901365498236492183464",
- "23537740700184054162508175125554701713153216681790245129157191391322321508055833908509185839069455749219131480588829346291",
- },
- {
- "11521922904531591643048817447554701904414021819823889996244743037378330903763518501116638828335352811871131385129455853417360623007349090150042001944696604737499160174391019030572483602867266711107136838523916077674888297896995042968746762200926853379",
- "426343618817810911523",
- "444747819283133684179",
- "42",
- },
-}
-
-func TestExpNN(t *testing.T) {
- for i, test := range expNNTests {
- x := natFromString(test.x)
- y := natFromString(test.y)
- out := natFromString(test.out)
-
- var m nat
- if len(test.m) > 0 {
- m = natFromString(test.m)
- }
-
- z := nat(nil).expNN(x, y, m)
- if z.cmp(out) != 0 {
- t.Errorf("#%d got %s want %s", i, z.utoa(10), out.utoa(10))
- }
- }
-}
-
-func ExpHelper(b *testing.B, x, y Word) {
- var z nat
- for i := 0; i < b.N; i++ {
- z.expWW(x, y)
- }
-}
-
-func BenchmarkExp3Power0x10(b *testing.B) { ExpHelper(b, 3, 0x10) }
-func BenchmarkExp3Power0x40(b *testing.B) { ExpHelper(b, 3, 0x40) }
-func BenchmarkExp3Power0x100(b *testing.B) { ExpHelper(b, 3, 0x100) }
-func BenchmarkExp3Power0x400(b *testing.B) { ExpHelper(b, 3, 0x400) }
-func BenchmarkExp3Power0x1000(b *testing.B) { ExpHelper(b, 3, 0x1000) }
-func BenchmarkExp3Power0x4000(b *testing.B) { ExpHelper(b, 3, 0x4000) }
-func BenchmarkExp3Power0x10000(b *testing.B) { ExpHelper(b, 3, 0x10000) }
-func BenchmarkExp3Power0x40000(b *testing.B) { ExpHelper(b, 3, 0x40000) }
-func BenchmarkExp3Power0x100000(b *testing.B) { ExpHelper(b, 3, 0x100000) }
-func BenchmarkExp3Power0x400000(b *testing.B) { ExpHelper(b, 3, 0x400000) }
-
-func fibo(n int) nat {
- switch n {
- case 0:
- return nil
- case 1:
- return nat{1}
- }
- f0 := fibo(0)
- f1 := fibo(1)
- var f2 nat
- for i := 1; i < n; i++ {
- f2 = f2.add(f0, f1)
- f0, f1, f2 = f1, f2, f0
- }
- return f1
-}
-
-var fiboNums = []string{
- "0",
- "55",
- "6765",
- "832040",
- "102334155",
- "12586269025",
- "1548008755920",
- "190392490709135",
- "23416728348467685",
- "2880067194370816120",
- "354224848179261915075",
-}
-
-func TestFibo(t *testing.T) {
- for i, want := range fiboNums {
- n := i * 10
- got := string(fibo(n).utoa(10))
- if got != want {
- t.Errorf("fibo(%d) failed: got %s want %s", n, got, want)
- }
- }
-}
-
-func BenchmarkFibo(b *testing.B) {
- for i := 0; i < b.N; i++ {
- fibo(1e0)
- fibo(1e1)
- fibo(1e2)
- fibo(1e3)
- fibo(1e4)
- fibo(1e5)
- }
-}
-
-var bitTests = []struct {
- x string
- i uint
- want uint
-}{
- {"0", 0, 0},
- {"0", 1, 0},
- {"0", 1000, 0},
-
- {"0x1", 0, 1},
- {"0x10", 0, 0},
- {"0x10", 3, 0},
- {"0x10", 4, 1},
- {"0x10", 5, 0},
-
- {"0x8000000000000000", 62, 0},
- {"0x8000000000000000", 63, 1},
- {"0x8000000000000000", 64, 0},
-
- {"0x3" + strings.Repeat("0", 32), 127, 0},
- {"0x3" + strings.Repeat("0", 32), 128, 1},
- {"0x3" + strings.Repeat("0", 32), 129, 1},
- {"0x3" + strings.Repeat("0", 32), 130, 0},
-}
-
-func TestBit(t *testing.T) {
- for i, test := range bitTests {
- x := natFromString(test.x)
- if got := x.bit(test.i); got != test.want {
- t.Errorf("#%d: %s.bit(%d) = %v; want %v", i, test.x, test.i, got, test.want)
- }
- }
-}
-
-var stickyTests = []struct {
- x string
- i uint
- want uint
-}{
- {"0", 0, 0},
- {"0", 1, 0},
- {"0", 1000, 0},
-
- {"0x1", 0, 0},
- {"0x1", 1, 1},
-
- {"0x1350", 0, 0},
- {"0x1350", 4, 0},
- {"0x1350", 5, 1},
-
- {"0x8000000000000000", 63, 0},
- {"0x8000000000000000", 64, 1},
-
- {"0x1" + strings.Repeat("0", 100), 400, 0},
- {"0x1" + strings.Repeat("0", 100), 401, 1},
-}
-
-func TestSticky(t *testing.T) {
- for i, test := range stickyTests {
- x := natFromString(test.x)
- if got := x.sticky(test.i); got != test.want {
- t.Errorf("#%d: %s.sticky(%d) = %v; want %v", i, test.x, test.i, got, test.want)
- }
- if test.want == 1 {
- // all subsequent i's should also return 1
- for d := uint(1); d <= 3; d++ {
- if got := x.sticky(test.i + d); got != 1 {
- t.Errorf("#%d: %s.sticky(%d) = %v; want %v", i, test.x, test.i+d, got, 1)
- }
- }
- }
- }
-}
diff --git a/src/cmd/compile/internal/big/natconv.go b/src/cmd/compile/internal/big/natconv.go
deleted file mode 100644
index d2ce667..0000000
--- a/src/cmd/compile/internal/big/natconv.go
+++ /dev/null
@@ -1,492 +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 implements nat-to-string conversion functions.
-
-package big
-
-import (
- "errors"
- "fmt"
- "io"
- "math"
- "sync"
-)
-
-const digits = "0123456789abcdefghijklmnopqrstuvwxyz"
-
-// Note: MaxBase = len(digits), but it must remain a rune constant
-// for API compatibility.
-
-// MaxBase is the largest number base accepted for string conversions.
-const MaxBase = 'z' - 'a' + 10 + 1
-
-// maxPow returns (b**n, n) such that b**n is the largest power b**n <= _M.
-// For instance maxPow(10) == (1e19, 19) for 19 decimal digits in a 64bit Word.
-// In other words, at most n digits in base b fit into a Word.
-// TODO(gri) replace this with a table, generated at build time.
-func maxPow(b Word) (p Word, n int) {
- p, n = b, 1 // assuming b <= _M
- for max := _M / b; p <= max; {
- // p == b**n && p <= max
- p *= b
- n++
- }
- // p == b**n && p <= _M
- return
-}
-
-// pow returns x**n for n > 0, and 1 otherwise.
-func pow(x Word, n int) (p Word) {
- // n == sum of bi * 2**i, for 0 <= i < imax, and bi is 0 or 1
- // thus x**n == product of x**(2**i) for all i where bi == 1
- // (Russian Peasant Method for exponentiation)
- p = 1
- for n > 0 {
- if n&1 != 0 {
- p *= x
- }
- x *= x
- n >>= 1
- }
- return
-}
-
-// scan scans the number corresponding to the longest possible prefix
-// from r representing an unsigned number in a given conversion base.
-// It returns the corresponding natural number res, the actual base b,
-// a digit count, and a read or syntax error err, if any.
-//
-// number = [ prefix ] mantissa .
-// prefix = "0" [ "x" | "X" | "b" | "B" ] .
-// mantissa = digits | digits "." [ digits ] | "." digits .
-// digits = digit { digit } .
-// digit = "0" ... "9" | "a" ... "z" | "A" ... "Z" .
-//
-// Unless fracOk is set, the base argument must be 0 or a value between
-// 2 and MaxBase. If fracOk is set, the base argument must be one of
-// 0, 2, 10, or 16. Providing an invalid base argument leads to a run-
-// time panic.
-//
-// For base 0, the number prefix determines the actual base: A prefix of
-// ``0x'' or ``0X'' selects base 16; if fracOk is not set, the ``0'' prefix
-// selects base 8, and a ``0b'' or ``0B'' prefix selects base 2. Otherwise
-// the selected base is 10 and no prefix is accepted.
-//
-// If fracOk is set, an octal prefix is ignored (a leading ``0'' simply
-// stands for a zero digit), and a period followed by a fractional part
-// is permitted. The result value is computed as if there were no period
-// present; and the count value is used to determine the fractional part.
-//
-// A result digit count > 0 corresponds to the number of (non-prefix) digits
-// parsed. A digit count <= 0 indicates the presence of a period (if fracOk
-// is set, only), and -count is the number of fractional digits found.
-// In this case, the actual value of the scanned number is res * b**count.
-//
-func (z nat) scan(r io.ByteScanner, base int, fracOk bool) (res nat, b, count int, err error) {
- // reject illegal bases
- baseOk := base == 0 ||
- !fracOk && 2 <= base && base <= MaxBase ||
- fracOk && (base == 2 || base == 10 || base == 16)
- if !baseOk {
- panic(fmt.Sprintf("illegal number base %d", base))
- }
-
- // one char look-ahead
- ch, err := r.ReadByte()
- if err != nil {
- return
- }
-
- // determine actual base
- b = base
- if base == 0 {
- // actual base is 10 unless there's a base prefix
- b = 10
- if ch == '0' {
- count = 1
- switch ch, err = r.ReadByte(); err {
- case nil:
- // possibly one of 0x, 0X, 0b, 0B
- if !fracOk {
- b = 8
- }
- switch ch {
- case 'x', 'X':
- b = 16
- case 'b', 'B':
- b = 2
- }
- switch b {
- case 16, 2:
- count = 0 // prefix is not counted
- if ch, err = r.ReadByte(); err != nil {
- // io.EOF is also an error in this case
- return
- }
- case 8:
- count = 0 // prefix is not counted
- }
- case io.EOF:
- // input is "0"
- res = z[:0]
- err = nil
- return
- default:
- // read error
- return
- }
- }
- }
-
- // convert string
- // Algorithm: Collect digits in groups of at most n digits in di
- // and then use mulAddWW for every such group to add them to the
- // result.
- z = z[:0]
- b1 := Word(b)
- bn, n := maxPow(b1) // at most n digits in base b1 fit into Word
- di := Word(0) // 0 <= di < b1**i < bn
- i := 0 // 0 <= i < n
- dp := -1 // position of decimal point
- for {
- if fracOk && ch == '.' {
- fracOk = false
- dp = count
- // advance
- if ch, err = r.ReadByte(); err != nil {
- if err == io.EOF {
- err = nil
- break
- }
- return
- }
- }
-
- // convert rune into digit value d1
- var d1 Word
- switch {
- case '0' <= ch && ch <= '9':
- d1 = Word(ch - '0')
- case 'a' <= ch && ch <= 'z':
- d1 = Word(ch - 'a' + 10)
- case 'A' <= ch && ch <= 'Z':
- d1 = Word(ch - 'A' + 10)
- default:
- d1 = MaxBase + 1
- }
- if d1 >= b1 {
- r.UnreadByte() // ch does not belong to number anymore
- break
- }
- count++
-
- // collect d1 in di
- di = di*b1 + d1
- i++
-
- // if di is "full", add it to the result
- if i == n {
- z = z.mulAddWW(z, bn, di)
- di = 0
- i = 0
- }
-
- // advance
- if ch, err = r.ReadByte(); err != nil {
- if err == io.EOF {
- err = nil
- break
- }
- return
- }
- }
-
- if count == 0 {
- // no digits found
- switch {
- case base == 0 && b == 8:
- // there was only the octal prefix 0 (possibly followed by digits > 7);
- // count as one digit and return base 10, not 8
- count = 1
- b = 10
- case base != 0 || b != 8:
- // there was neither a mantissa digit nor the octal prefix 0
- err = errors.New("syntax error scanning number")
- }
- return
- }
- // count > 0
-
- // add remaining digits to result
- if i > 0 {
- z = z.mulAddWW(z, pow(b1, i), di)
- }
- res = z.norm()
-
- // adjust for fraction, if any
- if dp >= 0 {
- // 0 <= dp <= count > 0
- count = dp - count
- }
-
- return
-}
-
-// utoa converts x to an ASCII representation in the given base;
-// base must be between 2 and MaxBase, inclusive.
-func (x nat) utoa(base int) []byte {
- return x.itoa(false, base)
-}
-
-// itoa is like utoa but it prepends a '-' if neg && x != 0.
-func (x nat) itoa(neg bool, base int) []byte {
- if base < 2 || base > MaxBase {
- panic("invalid base")
- }
-
- // x == 0
- if len(x) == 0 {
- return []byte("0")
- }
- // len(x) > 0
-
- // allocate buffer for conversion
- i := int(float64(x.bitLen())/math.Log2(float64(base))) + 1 // off by 1 at most
- if neg {
- i++
- }
- s := make([]byte, i)
-
- // 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
- mask := Word(1<<shift - 1)
- w := x[0] // current word
- nbits := uint(_W) // number of unprocessed bits in w
-
- // convert less-significant words (include leading zeros)
- for k := 1; k < len(x); k++ {
- // convert full digits
- for nbits >= shift {
- i--
- s[i] = digits[w&mask]
- w >>= shift
- nbits -= shift
- }
-
- // convert any partial leading digit and advance to next word
- if nbits == 0 {
- // no partial digit remaining, just advance
- w = x[k]
- nbits = _W
- } else {
- // partial digit in current word w (== x[k-1]) and next word x[k]
- w |= x[k] << nbits
- i--
- s[i] = digits[w&mask]
-
- // advance
- w = x[k] >> (shift - nbits)
- nbits = _W - (shift - nbits)
- }
- }
-
- // convert digits of most-significant word w (omit leading zeros)
- for w != 0 {
- i--
- s[i] = digits[w&mask]
- w >>= shift
- }
-
- } else {
- bb, ndigits := maxPow(Word(b))
-
- // construct table of successive squares of bb*leafSize to use in subdivisions
- // result (table != nil) <=> (len(x) > leafSize > 0)
- table := divisors(len(x), b, ndigits, bb)
-
- // preserve x, create local copy for use by convertWords
- q := nat(nil).set(x)
-
- // convert q to string s in base b
- q.convertWords(s, b, ndigits, bb, table)
-
- // strip leading zeros
- // (x != 0; thus s must contain at least one non-zero digit
- // and the loop will terminate)
- i = 0
- for s[i] == '0' {
- i++
- }
- }
-
- if neg {
- i--
- s[i] = '-'
- }
-
- return s[i:]
-}
-
-// Convert words of q to base b digits in s. If q is large, it is recursively "split in half"
-// by nat/nat division using tabulated divisors. Otherwise, it is converted iteratively using
-// repeated nat/Word division.
-//
-// The iterative method processes n Words by n divW() calls, each of which visits every Word in the
-// incrementally shortened q for a total of n + (n-1) + (n-2) ... + 2 + 1, or n(n+1)/2 divW()'s.
-// Recursive conversion divides q by its approximate square root, yielding two parts, each half
-// the size of q. Using the iterative method on both halves means 2 * (n/2)(n/2 + 1)/2 divW()'s
-// plus the expensive long div(). Asymptotically, the ratio is favorable at 1/2 the divW()'s, and
-// is made better by splitting the subblocks recursively. Best is to split blocks until one more
-// split would take longer (because of the nat/nat div()) than the twice as many divW()'s of the
-// iterative approach. This threshold is represented by leafSize. Benchmarking of leafSize in the
-// range 2..64 shows that values of 8 and 16 work well, with a 4x speedup at medium lengths and
-// ~30x for 20000 digits. Use nat_test.go's BenchmarkLeafSize tests to optimize leafSize for
-// specific hardware.
-//
-func (q nat) convertWords(s []byte, b Word, ndigits int, bb Word, table []divisor) {
- // split larger blocks recursively
- if table != nil {
- // len(q) > leafSize > 0
- var r nat
- index := len(table) - 1
- for len(q) > leafSize {
- // find divisor close to sqrt(q) if possible, but in any case < q
- maxLength := q.bitLen() // ~= log2 q, or at of least largest possible q of this bit length
- minLength := maxLength >> 1 // ~= log2 sqrt(q)
- for index > 0 && table[index-1].nbits > minLength {
- index-- // desired
- }
- if table[index].nbits >= maxLength && table[index].bbb.cmp(q) >= 0 {
- index--
- if index < 0 {
- panic("internal inconsistency")
- }
- }
-
- // split q into the two digit number (q'*bbb + r) to form independent subblocks
- q, r = q.div(r, q, table[index].bbb)
-
- // convert subblocks and collect results in s[:h] and s[h:]
- h := len(s) - table[index].ndigits
- r.convertWords(s[h:], b, ndigits, bb, table[0:index])
- s = s[:h] // == q.convertWords(s, b, ndigits, bb, table[0:index+1])
- }
- }
-
- // having split any large blocks now process the remaining (small) block iteratively
- i := len(s)
- var r Word
- if b == 10 {
- // hard-coding for 10 here speeds this up by 1.25x (allows for / and % by constants)
- for len(q) > 0 {
- // extract least significant, base bb "digit"
- q, r = q.divW(q, bb)
- for j := 0; j < ndigits && i > 0; j++ {
- i--
- // avoid % computation since r%10 == r - int(r/10)*10;
- // this appears to be faster for BenchmarkString10000Base10
- // and smaller strings (but a bit slower for larger ones)
- t := r / 10
- s[i] = '0' + byte(r-t<<3-t-t) // TODO(gri) replace w/ t*10 once compiler produces better code
- r = t
- }
- }
- } else {
- for len(q) > 0 {
- // extract least significant, base bb "digit"
- q, r = q.divW(q, bb)
- for j := 0; j < ndigits && i > 0; j++ {
- i--
- s[i] = digits[r%b]
- r /= b
- }
- }
- }
-
- // prepend high-order zeros
- for i > 0 { // while need more leading zeros
- i--
- s[i] = '0'
- }
-}
-
-// Split blocks greater than leafSize Words (or set to 0 to disable recursive conversion)
-// Benchmark and configure leafSize using: go test -bench="Leaf"
-// 8 and 16 effective on 3.0 GHz Xeon "Clovertown" CPU (128 byte cache lines)
-// 8 and 16 effective on 2.66 GHz Core 2 Duo "Penryn" CPU
-var leafSize int = 8 // number of Word-size binary values treat as a monolithic block
-
-type divisor struct {
- bbb nat // divisor
- nbits int // bit length of divisor (discounting leading zeros) ~= log2(bbb)
- ndigits int // digit length of divisor in terms of output base digits
-}
-
-var cacheBase10 struct {
- sync.Mutex
- table [64]divisor // cached divisors for base 10
-}
-
-// expWW computes x**y
-func (z nat) expWW(x, y Word) nat {
- return z.expNN(nat(nil).setWord(x), nat(nil).setWord(y), nil)
-}
-
-// construct table of powers of bb*leafSize to use in subdivisions
-func divisors(m int, b Word, ndigits int, bb Word) []divisor {
- // only compute table when recursive conversion is enabled and x is large
- if leafSize == 0 || m <= leafSize {
- return nil
- }
-
- // determine k where (bb**leafSize)**(2**k) >= sqrt(x)
- k := 1
- for words := leafSize; words < m>>1 && k < len(cacheBase10.table); words <<= 1 {
- k++
- }
-
- // reuse and extend existing table of divisors or create new table as appropriate
- var table []divisor // for b == 10, table overlaps with cacheBase10.table
- if b == 10 {
- cacheBase10.Lock()
- table = cacheBase10.table[0:k] // reuse old table for this conversion
- } else {
- table = make([]divisor, k) // create new table for this conversion
- }
-
- // extend table
- if table[k-1].ndigits == 0 {
- // add new entries as needed
- var larger nat
- for i := 0; i < k; i++ {
- if table[i].ndigits == 0 {
- if i == 0 {
- table[0].bbb = nat(nil).expWW(bb, Word(leafSize))
- table[0].ndigits = ndigits * leafSize
- } else {
- table[i].bbb = nat(nil).mul(table[i-1].bbb, table[i-1].bbb)
- table[i].ndigits = 2 * table[i-1].ndigits
- }
-
- // optimization: exploit aggregated extra bits in macro blocks
- larger = nat(nil).set(table[i].bbb)
- for mulAddVWW(larger, larger, b, 0) == 0 {
- table[i].bbb = table[i].bbb.set(larger)
- table[i].ndigits++
- }
-
- table[i].nbits = table[i].bbb.bitLen()
- }
- }
- }
-
- if b == 10 {
- cacheBase10.Unlock()
- }
-
- return table
-}
diff --git a/src/cmd/compile/internal/big/natconv_test.go b/src/cmd/compile/internal/big/natconv_test.go
deleted file mode 100644
index 028e5a8..0000000
--- a/src/cmd/compile/internal/big/natconv_test.go
+++ /dev/null
@@ -1,422 +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 big
-
-import (
- "bytes"
- "io"
- "strings"
- "testing"
-)
-
-func itoa(x nat, base int) []byte {
- // special cases
- switch {
- case base < 2:
- panic("illegal base")
- case len(x) == 0:
- return []byte("0")
- }
-
- // allocate buffer for conversion
- i := x.bitLen()/log2(Word(base)) + 1 // +1: round up
- s := make([]byte, i)
-
- // don't destroy x
- q := nat(nil).set(x)
-
- // convert
- for len(q) > 0 {
- i--
- var r Word
- q, r = q.divW(q, Word(base))
- s[i] = digits[r]
- }
-
- return s[i:]
-}
-
-var strTests = []struct {
- x nat // nat value to be converted
- b int // conversion base
- s string // expected result
-}{
- {nil, 2, "0"},
- {nat{1}, 2, "1"},
- {nat{0xc5}, 2, "11000101"},
- {nat{03271}, 8, "3271"},
- {nat{10}, 10, "10"},
- {nat{1234567890}, 10, "1234567890"},
- {nat{0xdeadbeef}, 16, "deadbeef"},
- {nat{0x229be7}, 17, "1a2b3c"},
- {nat{0x309663e6}, 32, "o9cov6"},
-}
-
-func TestString(t *testing.T) {
- // test invalid base explicitly
- var panicStr string
- func() {
- defer func() {
- panicStr = recover().(string)
- }()
- natOne.utoa(1)
- }()
- if panicStr != "invalid base" {
- t.Errorf("expected panic for invalid base")
- }
-
- for _, a := range strTests {
- s := string(a.x.utoa(a.b))
- if s != a.s {
- t.Errorf("string%+v\n\tgot s = %s; want %s", a, s, a.s)
- }
-
- x, b, _, err := nat(nil).scan(strings.NewReader(a.s), a.b, false)
- if x.cmp(a.x) != 0 {
- t.Errorf("scan%+v\n\tgot z = %v; want %v", a, x, a.x)
- }
- if b != a.b {
- t.Errorf("scan%+v\n\tgot b = %d; want %d", a, b, a.b)
- }
- if err != nil {
- t.Errorf("scan%+v\n\tgot error = %s", a, err)
- }
- }
-}
-
-var natScanTests = []struct {
- s string // string to be scanned
- base int // input base
- frac bool // fraction ok
- x nat // expected nat
- b int // expected base
- count int // expected digit count
- ok bool // expected success
- next rune // next character (or 0, if at EOF)
-}{
- // error: no mantissa
- {},
- {s: "?"},
- {base: 10},
- {base: 36},
- {s: "?", base: 10},
- {s: "0x"},
- {s: "345", base: 2},
-
- // error: incorrect use of decimal point
- {s: ".0"},
- {s: ".0", base: 10},
- {s: ".", base: 0},
- {s: "0x.0"},
-
- // no errors
- {"0", 0, false, nil, 10, 1, true, 0},
- {"0", 10, false, nil, 10, 1, true, 0},
- {"0", 36, false, nil, 36, 1, true, 0},
- {"1", 0, false, nat{1}, 10, 1, true, 0},
- {"1", 10, false, nat{1}, 10, 1, true, 0},
- {"0 ", 0, false, nil, 10, 1, true, ' '},
- {"08", 0, false, nil, 10, 1, true, '8'},
- {"08", 10, false, nat{8}, 10, 2, true, 0},
- {"018", 0, false, nat{1}, 8, 1, true, '8'},
- {"0b1", 0, false, nat{1}, 2, 1, true, 0},
- {"0b11000101", 0, false, nat{0xc5}, 2, 8, true, 0},
- {"03271", 0, false, nat{03271}, 8, 4, true, 0},
- {"10ab", 0, false, nat{10}, 10, 2, true, 'a'},
- {"1234567890", 0, false, nat{1234567890}, 10, 10, true, 0},
- {"xyz", 36, false, nat{(33*36+34)*36 + 35}, 36, 3, true, 0},
- {"xyz?", 36, false, nat{(33*36+34)*36 + 35}, 36, 3, true, '?'},
- {"0x", 16, false, nil, 16, 1, true, 'x'},
- {"0xdeadbeef", 0, false, nat{0xdeadbeef}, 16, 8, true, 0},
- {"0XDEADBEEF", 0, false, nat{0xdeadbeef}, 16, 8, true, 0},
-
- // no errors, decimal point
- {"0.", 0, false, nil, 10, 1, true, '.'},
- {"0.", 10, true, nil, 10, 0, true, 0},
- {"0.1.2", 10, true, nat{1}, 10, -1, true, '.'},
- {".000", 10, true, nil, 10, -3, true, 0},
- {"12.3", 10, true, nat{123}, 10, -1, true, 0},
- {"012.345", 10, true, nat{12345}, 10, -3, true, 0},
-}
-
-func TestScanBase(t *testing.T) {
- for _, a := range natScanTests {
- r := strings.NewReader(a.s)
- x, b, count, err := nat(nil).scan(r, a.base, a.frac)
- if err == nil && !a.ok {
- t.Errorf("scan%+v\n\texpected error", a)
- }
- if err != nil {
- if a.ok {
- t.Errorf("scan%+v\n\tgot error = %s", a, err)
- }
- continue
- }
- if x.cmp(a.x) != 0 {
- t.Errorf("scan%+v\n\tgot z = %v; want %v", a, x, a.x)
- }
- if b != a.b {
- t.Errorf("scan%+v\n\tgot b = %d; want %d", a, b, a.base)
- }
- if count != a.count {
- t.Errorf("scan%+v\n\tgot count = %d; want %d", a, count, a.count)
- }
- next, _, err := r.ReadRune()
- if err == io.EOF {
- next = 0
- err = nil
- }
- if err == nil && next != a.next {
- t.Errorf("scan%+v\n\tgot next = %q; want %q", a, next, a.next)
- }
- }
-}
-
-var pi = "3" +
- "14159265358979323846264338327950288419716939937510582097494459230781640628620899862803482534211706798214808651" +
- "32823066470938446095505822317253594081284811174502841027019385211055596446229489549303819644288109756659334461" +
- "28475648233786783165271201909145648566923460348610454326648213393607260249141273724587006606315588174881520920" +
- "96282925409171536436789259036001133053054882046652138414695194151160943305727036575959195309218611738193261179" +
- "31051185480744623799627495673518857527248912279381830119491298336733624406566430860213949463952247371907021798" +
- "60943702770539217176293176752384674818467669405132000568127145263560827785771342757789609173637178721468440901" +
- "22495343014654958537105079227968925892354201995611212902196086403441815981362977477130996051870721134999999837" +
- "29780499510597317328160963185950244594553469083026425223082533446850352619311881710100031378387528865875332083" +
- "81420617177669147303598253490428755468731159562863882353787593751957781857780532171226806613001927876611195909" +
- "21642019893809525720106548586327886593615338182796823030195203530185296899577362259941389124972177528347913151" +
- "55748572424541506959508295331168617278558890750983817546374649393192550604009277016711390098488240128583616035" +
- "63707660104710181942955596198946767837449448255379774726847104047534646208046684259069491293313677028989152104" +
- "75216205696602405803815019351125338243003558764024749647326391419927260426992279678235478163600934172164121992" +
- "45863150302861829745557067498385054945885869269956909272107975093029553211653449872027559602364806654991198818" +
- "34797753566369807426542527862551818417574672890977772793800081647060016145249192173217214772350141441973568548" +
- "16136115735255213347574184946843852332390739414333454776241686251898356948556209921922218427255025425688767179" +
- "04946016534668049886272327917860857843838279679766814541009538837863609506800642251252051173929848960841284886" +
- "26945604241965285022210661186306744278622039194945047123713786960956364371917287467764657573962413890865832645" +
- "99581339047802759009946576407895126946839835259570982582262052248940772671947826848260147699090264013639443745" +
- "53050682034962524517493996514314298091906592509372216964615157098583874105978859597729754989301617539284681382" +
- "68683868942774155991855925245953959431049972524680845987273644695848653836736222626099124608051243884390451244" +
- "13654976278079771569143599770012961608944169486855584840635342207222582848864815845602850601684273945226746767" +
- "88952521385225499546667278239864565961163548862305774564980355936345681743241125150760694794510965960940252288" +
- "79710893145669136867228748940560101503308617928680920874760917824938589009714909675985261365549781893129784821" +
- "68299894872265880485756401427047755513237964145152374623436454285844479526586782105114135473573952311342716610" +
- "21359695362314429524849371871101457654035902799344037420073105785390621983874478084784896833214457138687519435" +
- "06430218453191048481005370614680674919278191197939952061419663428754440643745123718192179998391015919561814675" +
- "14269123974894090718649423196156794520809514655022523160388193014209376213785595663893778708303906979207734672" +
- "21825625996615014215030680384477345492026054146659252014974428507325186660021324340881907104863317346496514539" +
- "05796268561005508106658796998163574736384052571459102897064140110971206280439039759515677157700420337869936007" +
- "23055876317635942187312514712053292819182618612586732157919841484882916447060957527069572209175671167229109816" +
- "90915280173506712748583222871835209353965725121083579151369882091444210067510334671103141267111369908658516398" +
- "31501970165151168517143765761835155650884909989859982387345528331635507647918535893226185489632132933089857064" +
- "20467525907091548141654985946163718027098199430992448895757128289059232332609729971208443357326548938239119325" +
- "97463667305836041428138830320382490375898524374417029132765618093773444030707469211201913020330380197621101100" +
- "44929321516084244485963766983895228684783123552658213144957685726243344189303968642624341077322697802807318915" +
- "44110104468232527162010526522721116603966655730925471105578537634668206531098965269186205647693125705863566201" +
- "85581007293606598764861179104533488503461136576867532494416680396265797877185560845529654126654085306143444318" +
- "58676975145661406800700237877659134401712749470420562230538994561314071127000407854733269939081454664645880797" +
- "27082668306343285878569830523580893306575740679545716377525420211495576158140025012622859413021647155097925923" +
- "09907965473761255176567513575178296664547791745011299614890304639947132962107340437518957359614589019389713111" +
- "79042978285647503203198691514028708085990480109412147221317947647772622414254854540332157185306142288137585043" +
- "06332175182979866223717215916077166925474873898665494945011465406284336639379003976926567214638530673609657120" +
- "91807638327166416274888800786925602902284721040317211860820419000422966171196377921337575114959501566049631862" +
- "94726547364252308177036751590673502350728354056704038674351362222477158915049530984448933309634087807693259939" +
- "78054193414473774418426312986080998886874132604721569516239658645730216315981931951673538129741677294786724229" +
- "24654366800980676928238280689964004824354037014163149658979409243237896907069779422362508221688957383798623001" +
- "59377647165122893578601588161755782973523344604281512627203734314653197777416031990665541876397929334419521541" +
- "34189948544473456738316249934191318148092777710386387734317720754565453220777092120190516609628049092636019759" +
- "88281613323166636528619326686336062735676303544776280350450777235547105859548702790814356240145171806246436267" +
- "94561275318134078330336254232783944975382437205835311477119926063813346776879695970309833913077109870408591337"
-
-// Test case for BenchmarkScanPi.
-func TestScanPi(t *testing.T) {
- var x nat
- z, _, _, err := x.scan(strings.NewReader(pi), 10, false)
- if err != nil {
- t.Errorf("scanning pi: %s", err)
- }
- if s := string(z.utoa(10)); s != pi {
- t.Errorf("scanning pi: got %s", s)
- }
-}
-
-func TestScanPiParallel(t *testing.T) {
- const n = 2
- c := make(chan int)
- for i := 0; i < n; i++ {
- go func() {
- TestScanPi(t)
- c <- 0
- }()
- }
- for i := 0; i < n; i++ {
- <-c
- }
-}
-
-func BenchmarkScanPi(b *testing.B) {
- for i := 0; i < b.N; i++ {
- var x nat
- x.scan(strings.NewReader(pi), 10, false)
- }
-}
-
-func BenchmarkStringPiParallel(b *testing.B) {
- var x nat
- x, _, _, _ = x.scan(strings.NewReader(pi), 0, false)
- if string(x.utoa(10)) != pi {
- panic("benchmark incorrect: conversion failed")
- }
- b.RunParallel(func(pb *testing.PB) {
- for pb.Next() {
- x.utoa(10)
- }
- })
-}
-
-func BenchmarkScan10Base2(b *testing.B) { ScanHelper(b, 2, 10, 10) }
-func BenchmarkScan100Base2(b *testing.B) { ScanHelper(b, 2, 10, 100) }
-func BenchmarkScan1000Base2(b *testing.B) { ScanHelper(b, 2, 10, 1000) }
-func BenchmarkScan10000Base2(b *testing.B) { ScanHelper(b, 2, 10, 10000) }
-func BenchmarkScan100000Base2(b *testing.B) { ScanHelper(b, 2, 10, 100000) }
-
-func BenchmarkScan10Base8(b *testing.B) { ScanHelper(b, 8, 10, 10) }
-func BenchmarkScan100Base8(b *testing.B) { ScanHelper(b, 8, 10, 100) }
-func BenchmarkScan1000Base8(b *testing.B) { ScanHelper(b, 8, 10, 1000) }
-func BenchmarkScan10000Base8(b *testing.B) { ScanHelper(b, 8, 10, 10000) }
-func BenchmarkScan100000Base8(b *testing.B) { ScanHelper(b, 8, 10, 100000) }
-
-func BenchmarkScan10Base10(b *testing.B) { ScanHelper(b, 10, 10, 10) }
-func BenchmarkScan100Base10(b *testing.B) { ScanHelper(b, 10, 10, 100) }
-func BenchmarkScan1000Base10(b *testing.B) { ScanHelper(b, 10, 10, 1000) }
-func BenchmarkScan10000Base10(b *testing.B) { ScanHelper(b, 10, 10, 10000) }
-func BenchmarkScan100000Base10(b *testing.B) { ScanHelper(b, 10, 10, 100000) }
-
-func BenchmarkScan10Base16(b *testing.B) { ScanHelper(b, 16, 10, 10) }
-func BenchmarkScan100Base16(b *testing.B) { ScanHelper(b, 16, 10, 100) }
-func BenchmarkScan1000Base16(b *testing.B) { ScanHelper(b, 16, 10, 1000) }
-func BenchmarkScan10000Base16(b *testing.B) { ScanHelper(b, 16, 10, 10000) }
-func BenchmarkScan100000Base16(b *testing.B) { ScanHelper(b, 16, 10, 100000) }
-
-func ScanHelper(b *testing.B, base int, x, y Word) {
- b.StopTimer()
- var z nat
- z = z.expWW(x, y)
-
- s := z.utoa(base)
- if t := itoa(z, base); !bytes.Equal(s, t) {
- b.Fatalf("scanning: got %s; want %s", s, t)
- }
- b.StartTimer()
-
- for i := 0; i < b.N; i++ {
- z.scan(bytes.NewReader(s), base, false)
- }
-}
-
-func BenchmarkString10Base2(b *testing.B) { StringHelper(b, 2, 10, 10) }
-func BenchmarkString100Base2(b *testing.B) { StringHelper(b, 2, 10, 100) }
-func BenchmarkString1000Base2(b *testing.B) { StringHelper(b, 2, 10, 1000) }
-func BenchmarkString10000Base2(b *testing.B) { StringHelper(b, 2, 10, 10000) }
-func BenchmarkString100000Base2(b *testing.B) { StringHelper(b, 2, 10, 100000) }
-
-func BenchmarkString10Base8(b *testing.B) { StringHelper(b, 8, 10, 10) }
-func BenchmarkString100Base8(b *testing.B) { StringHelper(b, 8, 10, 100) }
-func BenchmarkString1000Base8(b *testing.B) { StringHelper(b, 8, 10, 1000) }
-func BenchmarkString10000Base8(b *testing.B) { StringHelper(b, 8, 10, 10000) }
-func BenchmarkString100000Base8(b *testing.B) { StringHelper(b, 8, 10, 100000) }
-
-func BenchmarkString10Base10(b *testing.B) { StringHelper(b, 10, 10, 10) }
-func BenchmarkString100Base10(b *testing.B) { StringHelper(b, 10, 10, 100) }
-func BenchmarkString1000Base10(b *testing.B) { StringHelper(b, 10, 10, 1000) }
-func BenchmarkString10000Base10(b *testing.B) { StringHelper(b, 10, 10, 10000) }
-func BenchmarkString100000Base10(b *testing.B) { StringHelper(b, 10, 10, 100000) }
-
-func BenchmarkString10Base16(b *testing.B) { StringHelper(b, 16, 10, 10) }
-func BenchmarkString100Base16(b *testing.B) { StringHelper(b, 16, 10, 100) }
-func BenchmarkString1000Base16(b *testing.B) { StringHelper(b, 16, 10, 1000) }
-func BenchmarkString10000Base16(b *testing.B) { StringHelper(b, 16, 10, 10000) }
-func BenchmarkString100000Base16(b *testing.B) { StringHelper(b, 16, 10, 100000) }
-
-func StringHelper(b *testing.B, base int, x, y Word) {
- b.StopTimer()
- var z nat
- z = z.expWW(x, y)
- z.utoa(base) // warm divisor cache
- b.StartTimer()
-
- for i := 0; i < b.N; i++ {
- _ = z.utoa(base)
- }
-}
-
-func BenchmarkLeafSize0(b *testing.B) { LeafSizeHelper(b, 10, 0) } // test without splitting
-func BenchmarkLeafSize1(b *testing.B) { LeafSizeHelper(b, 10, 1) }
-func BenchmarkLeafSize2(b *testing.B) { LeafSizeHelper(b, 10, 2) }
-func BenchmarkLeafSize3(b *testing.B) { LeafSizeHelper(b, 10, 3) }
-func BenchmarkLeafSize4(b *testing.B) { LeafSizeHelper(b, 10, 4) }
-func BenchmarkLeafSize5(b *testing.B) { LeafSizeHelper(b, 10, 5) }
-func BenchmarkLeafSize6(b *testing.B) { LeafSizeHelper(b, 10, 6) }
-func BenchmarkLeafSize7(b *testing.B) { LeafSizeHelper(b, 10, 7) }
-func BenchmarkLeafSize8(b *testing.B) { LeafSizeHelper(b, 10, 8) }
-func BenchmarkLeafSize9(b *testing.B) { LeafSizeHelper(b, 10, 9) }
-func BenchmarkLeafSize10(b *testing.B) { LeafSizeHelper(b, 10, 10) }
-func BenchmarkLeafSize11(b *testing.B) { LeafSizeHelper(b, 10, 11) }
-func BenchmarkLeafSize12(b *testing.B) { LeafSizeHelper(b, 10, 12) }
-func BenchmarkLeafSize13(b *testing.B) { LeafSizeHelper(b, 10, 13) }
-func BenchmarkLeafSize14(b *testing.B) { LeafSizeHelper(b, 10, 14) }
-func BenchmarkLeafSize15(b *testing.B) { LeafSizeHelper(b, 10, 15) }
-func BenchmarkLeafSize16(b *testing.B) { LeafSizeHelper(b, 10, 16) }
-func BenchmarkLeafSize32(b *testing.B) { LeafSizeHelper(b, 10, 32) } // try some large lengths
-func BenchmarkLeafSize64(b *testing.B) { LeafSizeHelper(b, 10, 64) }
-
-func LeafSizeHelper(b *testing.B, base, size int) {
- b.StopTimer()
- originalLeafSize := leafSize
- resetTable(cacheBase10.table[:])
- leafSize = size
- b.StartTimer()
-
- for d := 1; d <= 10000; d *= 10 {
- b.StopTimer()
- var z nat
- z = z.expWW(Word(base), Word(d)) // build target number
- _ = z.utoa(base) // warm divisor cache
- b.StartTimer()
-
- for i := 0; i < b.N; i++ {
- _ = z.utoa(base)
- }
- }
-
- b.StopTimer()
- resetTable(cacheBase10.table[:])
- leafSize = originalLeafSize
- b.StartTimer()
-}
-
-func resetTable(table []divisor) {
- if table != nil && table[0].bbb != nil {
- for i := 0; i < len(table); i++ {
- table[i].bbb = nil
- table[i].nbits = 0
- table[i].ndigits = 0
- }
- }
-}
-
-func TestStringPowers(t *testing.T) {
- var p Word
- for b := 2; b <= 16; b++ {
- for p = 0; p <= 512; p++ {
- x := nat(nil).expWW(Word(b), p)
- xs := x.utoa(b)
- xs2 := itoa(x, b)
- if !bytes.Equal(xs, xs2) {
- t.Errorf("failed at %d ** %d in base %d: %s != %s", b, p, b, xs, xs2)
- }
- }
- if b >= 3 && testing.Short() {
- break
- }
- }
-}
diff --git a/src/cmd/compile/internal/big/rat.go b/src/cmd/compile/internal/big/rat.go
deleted file mode 100644
index 56ce33d..0000000
--- a/src/cmd/compile/internal/big/rat.go
+++ /dev/null
@@ -1,510 +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.
-
-// This file implements multi-precision rational numbers.
-
-package big
-
-import (
- "fmt"
- "math"
-)
-
-// A Rat represents a quotient a/b of arbitrary precision.
-// The zero value for a Rat represents the value 0.
-type Rat struct {
- // To make zero values for Rat work w/o initialization,
- // a zero value of b (len(b) == 0) acts like b == 1.
- // a.neg determines the sign of the Rat, b.neg is ignored.
- a, b Int
-}
-
-// NewRat creates a new Rat with numerator a and denominator b.
-func NewRat(a, b int64) *Rat {
- return new(Rat).SetFrac64(a, b)
-}
-
-// SetFloat64 sets z to exactly f and returns z.
-// If f is not finite, SetFloat returns nil.
-func (z *Rat) SetFloat64(f float64) *Rat {
- const expMask = 1<<11 - 1
- bits := math.Float64bits(f)
- mantissa := bits & (1<<52 - 1)
- exp := int((bits >> 52) & expMask)
- switch exp {
- case expMask: // non-finite
- return nil
- case 0: // denormal
- exp -= 1022
- default: // normal
- mantissa |= 1 << 52
- exp -= 1023
- }
-
- shift := 52 - exp
-
- // Optimization (?): partially pre-normalise.
- for mantissa&1 == 0 && shift > 0 {
- mantissa >>= 1
- shift--
- }
-
- z.a.SetUint64(mantissa)
- z.a.neg = f < 0
- z.b.Set(intOne)
- if shift > 0 {
- z.b.Lsh(&z.b, uint(shift))
- } else {
- z.a.Lsh(&z.a, uint(-shift))
- }
- return z.norm()
-}
-
-// quotToFloat32 returns the non-negative float32 value
-// nearest to the quotient a/b, using round-to-even in
-// halfway cases. It does not mutate its arguments.
-// Preconditions: b is non-zero; a and b have no common factors.
-func quotToFloat32(a, b nat) (f float32, exact bool) {
- const (
- // float size in bits
- Fsize = 32
-
- // mantissa
- Msize = 23
- Msize1 = Msize + 1 // incl. implicit 1
- Msize2 = Msize1 + 1
-
- // exponent
- Esize = Fsize - Msize1
- Ebias = 1<<(Esize-1) - 1
- Emin = 1 - Ebias
- Emax = Ebias
- )
-
- // TODO(adonovan): specialize common degenerate cases: 1.0, integers.
- alen := a.bitLen()
- if alen == 0 {
- return 0, true
- }
- blen := b.bitLen()
- if blen == 0 {
- panic("division by zero")
- }
-
- // 1. Left-shift A or B such that quotient A/B is in [1<<Msize1, 1<<(Msize2+1)
- // (Msize2 bits if A < B when they are left-aligned, Msize2+1 bits if A >= B).
- // This is 2 or 3 more than the float32 mantissa field width of Msize:
- // - the optional extra bit is shifted away in step 3 below.
- // - the high-order 1 is omitted in "normal" representation;
- // - the low-order 1 will be used during rounding then discarded.
- exp := alen - blen
- var a2, b2 nat
- a2 = a2.set(a)
- b2 = b2.set(b)
- if shift := Msize2 - exp; shift > 0 {
- a2 = a2.shl(a2, uint(shift))
- } else if shift < 0 {
- b2 = b2.shl(b2, uint(-shift))
- }
-
- // 2. Compute quotient and remainder (q, r). NB: due to the
- // extra shift, the low-order bit of q is logically the
- // high-order bit of r.
- var q nat
- q, r := q.div(a2, a2, b2) // (recycle a2)
- mantissa := low32(q)
- haveRem := len(r) > 0 // mantissa&1 && !haveRem => remainder is exactly half
-
- // 3. If quotient didn't fit in Msize2 bits, redo division by b2<<1
- // (in effect---we accomplish this incrementally).
- if mantissa>>Msize2 == 1 {
- if mantissa&1 == 1 {
- haveRem = true
- }
- mantissa >>= 1
- exp++
- }
- if mantissa>>Msize1 != 1 {
- panic(fmt.Sprintf("expected exactly %d bits of result", Msize2))
- }
-
- // 4. Rounding.
- if Emin-Msize <= exp && exp <= Emin {
- // Denormal case; lose 'shift' bits of precision.
- shift := uint(Emin - (exp - 1)) // [1..Esize1)
- lostbits := mantissa & (1<<shift - 1)
- haveRem = haveRem || lostbits != 0
- mantissa >>= shift
- exp = 2 - Ebias // == exp + shift
- }
- // Round q using round-half-to-even.
- exact = !haveRem
- if mantissa&1 != 0 {
- exact = false
- if haveRem || mantissa&2 != 0 {
- if mantissa++; mantissa >= 1<<Msize2 {
- // Complete rollover 11...1 => 100...0, so shift is safe
- mantissa >>= 1
- exp++
- }
- }
- }
- mantissa >>= 1 // discard rounding bit. Mantissa now scaled by 1<<Msize1.
-
- f = float32(math.Ldexp(float64(mantissa), exp-Msize1))
- if math.IsInf(float64(f), 0) {
- exact = false
- }
- return
-}
-
-// quotToFloat64 returns the non-negative float64 value
-// nearest to the quotient a/b, using round-to-even in
-// halfway cases. It does not mutate its arguments.
-// Preconditions: b is non-zero; a and b have no common factors.
-func quotToFloat64(a, b nat) (f float64, exact bool) {
- const (
- // float size in bits
- Fsize = 64
-
- // mantissa
- Msize = 52
- Msize1 = Msize + 1 // incl. implicit 1
- Msize2 = Msize1 + 1
-
- // exponent
- Esize = Fsize - Msize1
- Ebias = 1<<(Esize-1) - 1
- Emin = 1 - Ebias
- Emax = Ebias
- )
-
- // TODO(adonovan): specialize common degenerate cases: 1.0, integers.
- alen := a.bitLen()
- if alen == 0 {
- return 0, true
- }
- blen := b.bitLen()
- if blen == 0 {
- panic("division by zero")
- }
-
- // 1. Left-shift A or B such that quotient A/B is in [1<<Msize1, 1<<(Msize2+1)
- // (Msize2 bits if A < B when they are left-aligned, Msize2+1 bits if A >= B).
- // This is 2 or 3 more than the float64 mantissa field width of Msize:
- // - the optional extra bit is shifted away in step 3 below.
- // - the high-order 1 is omitted in "normal" representation;
- // - the low-order 1 will be used during rounding then discarded.
- exp := alen - blen
- var a2, b2 nat
- a2 = a2.set(a)
- b2 = b2.set(b)
- if shift := Msize2 - exp; shift > 0 {
- a2 = a2.shl(a2, uint(shift))
- } else if shift < 0 {
- b2 = b2.shl(b2, uint(-shift))
- }
-
- // 2. Compute quotient and remainder (q, r). NB: due to the
- // extra shift, the low-order bit of q is logically the
- // high-order bit of r.
- var q nat
- q, r := q.div(a2, a2, b2) // (recycle a2)
- mantissa := low64(q)
- haveRem := len(r) > 0 // mantissa&1 && !haveRem => remainder is exactly half
-
- // 3. If quotient didn't fit in Msize2 bits, redo division by b2<<1
- // (in effect---we accomplish this incrementally).
- if mantissa>>Msize2 == 1 {
- if mantissa&1 == 1 {
- haveRem = true
- }
- mantissa >>= 1
- exp++
- }
- if mantissa>>Msize1 != 1 {
- panic(fmt.Sprintf("expected exactly %d bits of result", Msize2))
- }
-
- // 4. Rounding.
- if Emin-Msize <= exp && exp <= Emin {
- // Denormal case; lose 'shift' bits of precision.
- shift := uint(Emin - (exp - 1)) // [1..Esize1)
- lostbits := mantissa & (1<<shift - 1)
- haveRem = haveRem || lostbits != 0
- mantissa >>= shift
- exp = 2 - Ebias // == exp + shift
- }
- // Round q using round-half-to-even.
- exact = !haveRem
- if mantissa&1 != 0 {
- exact = false
- if haveRem || mantissa&2 != 0 {
- if mantissa++; mantissa >= 1<<Msize2 {
- // Complete rollover 11...1 => 100...0, so shift is safe
- mantissa >>= 1
- exp++
- }
- }
- }
- mantissa >>= 1 // discard rounding bit. Mantissa now scaled by 1<<Msize1.
-
- f = math.Ldexp(float64(mantissa), exp-Msize1)
- if math.IsInf(f, 0) {
- exact = false
- }
- return
-}
-
-// Float32 returns the nearest float32 value for x and a bool indicating
-// whether f represents x exactly. If the magnitude of x is too large to
-// be represented by a float32, f is an infinity and exact is false.
-// The sign of f always matches the sign of x, even if f == 0.
-func (x *Rat) Float32() (f float32, exact bool) {
- b := x.b.abs
- if len(b) == 0 {
- b = b.set(natOne) // materialize denominator
- }
- f, exact = quotToFloat32(x.a.abs, b)
- if x.a.neg {
- f = -f
- }
- return
-}
-
-// Float64 returns the nearest float64 value for x and a bool indicating
-// whether f represents x exactly. If the magnitude of x is too large to
-// be represented by a float64, f is an infinity and exact is false.
-// The sign of f always matches the sign of x, even if f == 0.
-func (x *Rat) Float64() (f float64, exact bool) {
- b := x.b.abs
- if len(b) == 0 {
- b = b.set(natOne) // materialize denominator
- }
- f, exact = quotToFloat64(x.a.abs, b)
- if x.a.neg {
- f = -f
- }
- return
-}
-
-// SetFrac sets z to a/b and returns z.
-func (z *Rat) SetFrac(a, b *Int) *Rat {
- z.a.neg = a.neg != b.neg
- babs := b.abs
- if len(babs) == 0 {
- panic("division by zero")
- }
- if &z.a == b || alias(z.a.abs, babs) {
- babs = nat(nil).set(babs) // make a copy
- }
- z.a.abs = z.a.abs.set(a.abs)
- z.b.abs = z.b.abs.set(babs)
- return z.norm()
-}
-
-// SetFrac64 sets z to a/b and returns z.
-func (z *Rat) SetFrac64(a, b int64) *Rat {
- z.a.SetInt64(a)
- if b == 0 {
- panic("division by zero")
- }
- if b < 0 {
- b = -b
- z.a.neg = !z.a.neg
- }
- z.b.abs = z.b.abs.setUint64(uint64(b))
- return z.norm()
-}
-
-// SetInt sets z to x (by making a copy of x) and returns z.
-func (z *Rat) SetInt(x *Int) *Rat {
- z.a.Set(x)
- z.b.abs = z.b.abs[:0]
- return z
-}
-
-// SetInt64 sets z to x and returns z.
-func (z *Rat) SetInt64(x int64) *Rat {
- z.a.SetInt64(x)
- z.b.abs = z.b.abs[:0]
- return z
-}
-
-// Set sets z to x (by making a copy of x) and returns z.
-func (z *Rat) Set(x *Rat) *Rat {
- if z != x {
- z.a.Set(&x.a)
- z.b.Set(&x.b)
- }
- return z
-}
-
-// Abs sets z to |x| (the absolute value of x) and returns z.
-func (z *Rat) Abs(x *Rat) *Rat {
- z.Set(x)
- z.a.neg = false
- return z
-}
-
-// Neg sets z to -x and returns z.
-func (z *Rat) Neg(x *Rat) *Rat {
- z.Set(x)
- z.a.neg = len(z.a.abs) > 0 && !z.a.neg // 0 has no sign
- return z
-}
-
-// Inv sets z to 1/x and returns z.
-func (z *Rat) Inv(x *Rat) *Rat {
- if len(x.a.abs) == 0 {
- panic("division by zero")
- }
- z.Set(x)
- a := z.b.abs
- if len(a) == 0 {
- a = a.set(natOne) // materialize numerator
- }
- b := z.a.abs
- if b.cmp(natOne) == 0 {
- b = b[:0] // normalize denominator
- }
- z.a.abs, z.b.abs = a, b // sign doesn't change
- return z
-}
-
-// Sign returns:
-//
-// -1 if x < 0
-// 0 if x == 0
-// +1 if x > 0
-//
-func (x *Rat) Sign() int {
- return x.a.Sign()
-}
-
-// IsInt reports whether the denominator of x is 1.
-func (x *Rat) IsInt() bool {
- return len(x.b.abs) == 0 || x.b.abs.cmp(natOne) == 0
-}
-
-// Num returns the numerator of x; it may be <= 0.
-// The result is a reference to x's numerator; it
-// may change if a new value is assigned to x, and vice versa.
-// The sign of the numerator corresponds to the sign of x.
-func (x *Rat) Num() *Int {
- return &x.a
-}
-
-// Denom returns the denominator of x; it is always > 0.
-// The result is a reference to x's denominator; it
-// may change if a new value is assigned to x, and vice versa.
-func (x *Rat) Denom() *Int {
- x.b.neg = false // the result is always >= 0
- if len(x.b.abs) == 0 {
- x.b.abs = x.b.abs.set(natOne) // materialize denominator
- }
- return &x.b
-}
-
-func (z *Rat) norm() *Rat {
- switch {
- case len(z.a.abs) == 0:
- // z == 0 - normalize sign and denominator
- z.a.neg = false
- z.b.abs = z.b.abs[:0]
- case len(z.b.abs) == 0:
- // z is normalized int - nothing to do
- case z.b.abs.cmp(natOne) == 0:
- // z is int - normalize denominator
- z.b.abs = z.b.abs[:0]
- default:
- neg := z.a.neg
- z.a.neg = false
- z.b.neg = false
- if f := NewInt(0).binaryGCD(&z.a, &z.b); f.Cmp(intOne) != 0 {
- z.a.abs, _ = z.a.abs.div(nil, z.a.abs, f.abs)
- z.b.abs, _ = z.b.abs.div(nil, z.b.abs, f.abs)
- if z.b.abs.cmp(natOne) == 0 {
- // z is int - normalize denominator
- z.b.abs = z.b.abs[:0]
- }
- }
- z.a.neg = neg
- }
- return z
-}
-
-// mulDenom sets z to the denominator product x*y (by taking into
-// account that 0 values for x or y must be interpreted as 1) and
-// returns z.
-func mulDenom(z, x, y nat) nat {
- switch {
- case len(x) == 0:
- return z.set(y)
- case len(y) == 0:
- return z.set(x)
- }
- return z.mul(x, y)
-}
-
-// scaleDenom computes x*f.
-// If f == 0 (zero value of denominator), the result is (a copy of) x.
-func scaleDenom(x *Int, f nat) *Int {
- var z Int
- if len(f) == 0 {
- return z.Set(x)
- }
- z.abs = z.abs.mul(x.abs, f)
- z.neg = x.neg
- return &z
-}
-
-// Cmp compares x and y and returns:
-//
-// -1 if x < y
-// 0 if x == y
-// +1 if x > y
-//
-func (x *Rat) Cmp(y *Rat) int {
- return scaleDenom(&x.a, y.b.abs).Cmp(scaleDenom(&y.a, x.b.abs))
-}
-
-// Add sets z to the sum x+y and returns z.
-func (z *Rat) Add(x, y *Rat) *Rat {
- a1 := scaleDenom(&x.a, y.b.abs)
- a2 := scaleDenom(&y.a, x.b.abs)
- z.a.Add(a1, a2)
- z.b.abs = mulDenom(z.b.abs, x.b.abs, y.b.abs)
- return z.norm()
-}
-
-// Sub sets z to the difference x-y and returns z.
-func (z *Rat) Sub(x, y *Rat) *Rat {
- a1 := scaleDenom(&x.a, y.b.abs)
- a2 := scaleDenom(&y.a, x.b.abs)
- z.a.Sub(a1, a2)
- z.b.abs = mulDenom(z.b.abs, x.b.abs, y.b.abs)
- return z.norm()
-}
-
-// Mul sets z to the product x*y and returns z.
-func (z *Rat) Mul(x, y *Rat) *Rat {
- z.a.Mul(&x.a, &y.a)
- z.b.abs = mulDenom(z.b.abs, x.b.abs, y.b.abs)
- return z.norm()
-}
-
-// Quo sets z to the quotient x/y and returns z.
-// If y == 0, a division-by-zero run-time panic occurs.
-func (z *Rat) Quo(x, y *Rat) *Rat {
- if len(y.a.abs) == 0 {
- panic("division by zero")
- }
- a := scaleDenom(&x.a, y.b.abs)
- b := scaleDenom(&y.a, x.b.abs)
- z.a.abs = a.abs
- z.b.abs = b.abs
- z.a.neg = a.neg != b.neg
- return z.norm()
-}
diff --git a/src/cmd/compile/internal/big/rat_test.go b/src/cmd/compile/internal/big/rat_test.go
deleted file mode 100644
index 3a06fca..0000000
--- a/src/cmd/compile/internal/big/rat_test.go
+++ /dev/null
@@ -1,622 +0,0 @@
-// Copyright 2010 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package big
-
-import (
- "math"
- "testing"
-)
-
-func TestZeroRat(t *testing.T) {
- var x, y, z Rat
- y.SetFrac64(0, 42)
-
- if x.Cmp(&y) != 0 {
- t.Errorf("x and y should be both equal and zero")
- }
-
- if s := x.String(); s != "0/1" {
- t.Errorf("got x = %s, want 0/1", s)
- }
-
- if s := x.RatString(); s != "0" {
- t.Errorf("got x = %s, want 0", s)
- }
-
- z.Add(&x, &y)
- if s := z.RatString(); s != "0" {
- t.Errorf("got x+y = %s, want 0", s)
- }
-
- z.Sub(&x, &y)
- if s := z.RatString(); s != "0" {
- t.Errorf("got x-y = %s, want 0", s)
- }
-
- z.Mul(&x, &y)
- if s := z.RatString(); s != "0" {
- t.Errorf("got x*y = %s, want 0", s)
- }
-
- // check for division by zero
- defer func() {
- if s := recover(); s == nil || s.(string) != "division by zero" {
- panic(s)
- }
- }()
- z.Quo(&x, &y)
-}
-
-func TestRatSign(t *testing.T) {
- zero := NewRat(0, 1)
- for _, a := range setStringTests {
- x, ok := new(Rat).SetString(a.in)
- if !ok {
- continue
- }
- s := x.Sign()
- e := x.Cmp(zero)
- if s != e {
- t.Errorf("got %d; want %d for z = %v", s, e, &x)
- }
- }
-}
-
-var ratCmpTests = []struct {
- rat1, rat2 string
- out int
-}{
- {"0", "0/1", 0},
- {"1/1", "1", 0},
- {"-1", "-2/2", 0},
- {"1", "0", 1},
- {"0/1", "1/1", -1},
- {"-5/1434770811533343057144", "-5/1434770811533343057145", -1},
- {"49832350382626108453/8964749413", "49832350382626108454/8964749413", -1},
- {"-37414950961700930/7204075375675961", "37414950961700930/7204075375675961", -1},
- {"37414950961700930/7204075375675961", "74829901923401860/14408150751351922", 0},
-}
-
-func TestRatCmp(t *testing.T) {
- for i, test := range ratCmpTests {
- x, _ := new(Rat).SetString(test.rat1)
- y, _ := new(Rat).SetString(test.rat2)
-
- out := x.Cmp(y)
- if out != test.out {
- t.Errorf("#%d got out = %v; want %v", i, out, test.out)
- }
- }
-}
-
-func TestIsInt(t *testing.T) {
- one := NewInt(1)
- for _, a := range setStringTests {
- x, ok := new(Rat).SetString(a.in)
- if !ok {
- continue
- }
- i := x.IsInt()
- e := x.Denom().Cmp(one) == 0
- if i != e {
- t.Errorf("got IsInt(%v) == %v; want %v", x, i, e)
- }
- }
-}
-
-func TestRatAbs(t *testing.T) {
- zero := new(Rat)
- for _, a := range setStringTests {
- x, ok := new(Rat).SetString(a.in)
- if !ok {
- continue
- }
- e := new(Rat).Set(x)
- if e.Cmp(zero) < 0 {
- e.Sub(zero, e)
- }
- z := new(Rat).Abs(x)
- if z.Cmp(e) != 0 {
- t.Errorf("got Abs(%v) = %v; want %v", x, z, e)
- }
- }
-}
-
-func TestRatNeg(t *testing.T) {
- zero := new(Rat)
- for _, a := range setStringTests {
- x, ok := new(Rat).SetString(a.in)
- if !ok {
- continue
- }
- e := new(Rat).Sub(zero, x)
- z := new(Rat).Neg(x)
- if z.Cmp(e) != 0 {
- t.Errorf("got Neg(%v) = %v; want %v", x, z, e)
- }
- }
-}
-
-func TestRatInv(t *testing.T) {
- zero := new(Rat)
- for _, a := range setStringTests {
- x, ok := new(Rat).SetString(a.in)
- if !ok {
- continue
- }
- if x.Cmp(zero) == 0 {
- continue // avoid division by zero
- }
- e := new(Rat).SetFrac(x.Denom(), x.Num())
- z := new(Rat).Inv(x)
- if z.Cmp(e) != 0 {
- t.Errorf("got Inv(%v) = %v; want %v", x, z, e)
- }
- }
-}
-
-type ratBinFun func(z, x, y *Rat) *Rat
-type ratBinArg struct {
- x, y, z string
-}
-
-func testRatBin(t *testing.T, i int, name string, f ratBinFun, a ratBinArg) {
- x, _ := new(Rat).SetString(a.x)
- y, _ := new(Rat).SetString(a.y)
- z, _ := new(Rat).SetString(a.z)
- out := f(new(Rat), x, y)
-
- if out.Cmp(z) != 0 {
- t.Errorf("%s #%d got %s want %s", name, i, out, z)
- }
-}
-
-var ratBinTests = []struct {
- x, y string
- sum, prod string
-}{
- {"0", "0", "0", "0"},
- {"0", "1", "1", "0"},
- {"-1", "0", "-1", "0"},
- {"-1", "1", "0", "-1"},
- {"1", "1", "2", "1"},
- {"1/2", "1/2", "1", "1/4"},
- {"1/4", "1/3", "7/12", "1/12"},
- {"2/5", "-14/3", "-64/15", "-28/15"},
- {"4707/49292519774798173060", "-3367/70976135186689855734", "84058377121001851123459/1749296273614329067191168098769082663020", "-1760941/388732505247628681598037355282018369560"},
- {"-61204110018146728334/3", "-31052192278051565633/2", "-215564796870448153567/6", "950260896245257153059642991192710872711/3"},
- {"-854857841473707320655/4237645934602118692642972629634714039", "-18/31750379913563777419", "-27/133467566250814981", "15387441146526731771790/134546868362786310073779084329032722548987800600710485341"},
- {"618575745270541348005638912139/19198433543745179392300736", "-19948846211000086/637313996471", "27674141753240653/30123979153216", "-6169936206128396568797607742807090270137721977/6117715203873571641674006593837351328"},
- {"-3/26206484091896184128", "5/2848423294177090248", "15310893822118706237/9330894968229805033368778458685147968", "-5/24882386581946146755650075889827061248"},
- {"26946729/330400702820", "41563965/225583428284", "1238218672302860271/4658307703098666660055", "224002580204097/14906584649915733312176"},
- {"-8259900599013409474/7", "-84829337473700364773/56707961321161574960", "-468402123685491748914621885145127724451/396955729248131024720", "350340947706464153265156004876107029701/198477864624065512360"},
- {"575775209696864/1320203974639986246357", "29/712593081308", "410331716733912717985762465/940768218243776489278275419794956", "808/45524274987585732633"},
- {"1786597389946320496771/2066653520653241", "6269770/1992362624741777", "3559549865190272133656109052308126637/4117523232840525481453983149257", "8967230/3296219033"},
- {"-36459180403360509753/32150500941194292113930", "9381566963714/9633539", "301622077145533298008420642898530153/309723104686531919656937098270", "-3784609207827/3426986245"},
-}
-
-func TestRatBin(t *testing.T) {
- for i, test := range ratBinTests {
- arg := ratBinArg{test.x, test.y, test.sum}
- testRatBin(t, i, "Add", (*Rat).Add, arg)
-
- arg = ratBinArg{test.y, test.x, test.sum}
- testRatBin(t, i, "Add symmetric", (*Rat).Add, arg)
-
- arg = ratBinArg{test.sum, test.x, test.y}
- testRatBin(t, i, "Sub", (*Rat).Sub, arg)
-
- arg = ratBinArg{test.sum, test.y, test.x}
- testRatBin(t, i, "Sub symmetric", (*Rat).Sub, arg)
-
- arg = ratBinArg{test.x, test.y, test.prod}
- testRatBin(t, i, "Mul", (*Rat).Mul, arg)
-
- arg = ratBinArg{test.y, test.x, test.prod}
- testRatBin(t, i, "Mul symmetric", (*Rat).Mul, arg)
-
- if test.x != "0" {
- arg = ratBinArg{test.prod, test.x, test.y}
- testRatBin(t, i, "Quo", (*Rat).Quo, arg)
- }
-
- if test.y != "0" {
- arg = ratBinArg{test.prod, test.y, test.x}
- testRatBin(t, i, "Quo symmetric", (*Rat).Quo, arg)
- }
- }
-}
-
-func TestIssue820(t *testing.T) {
- x := NewRat(3, 1)
- y := NewRat(2, 1)
- z := y.Quo(x, y)
- q := NewRat(3, 2)
- if z.Cmp(q) != 0 {
- t.Errorf("got %s want %s", z, q)
- }
-
- y = NewRat(3, 1)
- x = NewRat(2, 1)
- z = y.Quo(x, y)
- q = NewRat(2, 3)
- if z.Cmp(q) != 0 {
- t.Errorf("got %s want %s", z, q)
- }
-
- x = NewRat(3, 1)
- z = x.Quo(x, x)
- q = NewRat(3, 3)
- if z.Cmp(q) != 0 {
- t.Errorf("got %s want %s", z, q)
- }
-}
-
-var setFrac64Tests = []struct {
- a, b int64
- out string
-}{
- {0, 1, "0"},
- {0, -1, "0"},
- {1, 1, "1"},
- {-1, 1, "-1"},
- {1, -1, "-1"},
- {-1, -1, "1"},
- {-9223372036854775808, -9223372036854775808, "1"},
-}
-
-func TestRatSetFrac64Rat(t *testing.T) {
- for i, test := range setFrac64Tests {
- x := new(Rat).SetFrac64(test.a, test.b)
- if x.RatString() != test.out {
- t.Errorf("#%d got %s want %s", i, x.RatString(), test.out)
- }
- }
-}
-
-func TestIssue2379(t *testing.T) {
- // 1) no aliasing
- q := NewRat(3, 2)
- x := new(Rat)
- x.SetFrac(NewInt(3), NewInt(2))
- if x.Cmp(q) != 0 {
- t.Errorf("1) got %s want %s", x, q)
- }
-
- // 2) aliasing of numerator
- x = NewRat(2, 3)
- x.SetFrac(NewInt(3), x.Num())
- if x.Cmp(q) != 0 {
- t.Errorf("2) got %s want %s", x, q)
- }
-
- // 3) aliasing of denominator
- x = NewRat(2, 3)
- x.SetFrac(x.Denom(), NewInt(2))
- if x.Cmp(q) != 0 {
- t.Errorf("3) got %s want %s", x, q)
- }
-
- // 4) aliasing of numerator and denominator
- x = NewRat(2, 3)
- x.SetFrac(x.Denom(), x.Num())
- if x.Cmp(q) != 0 {
- t.Errorf("4) got %s want %s", x, q)
- }
-
- // 5) numerator and denominator are the same
- q = NewRat(1, 1)
- x = new(Rat)
- n := NewInt(7)
- x.SetFrac(n, n)
- if x.Cmp(q) != 0 {
- t.Errorf("5) got %s want %s", x, q)
- }
-}
-
-func TestIssue3521(t *testing.T) {
- a := new(Int)
- b := new(Int)
- a.SetString("64375784358435883458348587", 0)
- b.SetString("4789759874531", 0)
-
- // 0) a raw zero value has 1 as denominator
- zero := new(Rat)
- one := NewInt(1)
- if zero.Denom().Cmp(one) != 0 {
- t.Errorf("0) got %s want %s", zero.Denom(), one)
- }
-
- // 1a) a zero value remains zero independent of denominator
- x := new(Rat)
- x.Denom().Set(new(Int).Neg(b))
- if x.Cmp(zero) != 0 {
- t.Errorf("1a) got %s want %s", x, zero)
- }
-
- // 1b) a zero value may have a denominator != 0 and != 1
- x.Num().Set(a)
- qab := new(Rat).SetFrac(a, b)
- if x.Cmp(qab) != 0 {
- t.Errorf("1b) got %s want %s", x, qab)
- }
-
- // 2a) an integral value becomes a fraction depending on denominator
- x.SetFrac64(10, 2)
- x.Denom().SetInt64(3)
- q53 := NewRat(5, 3)
- if x.Cmp(q53) != 0 {
- t.Errorf("2a) got %s want %s", x, q53)
- }
-
- // 2b) an integral value becomes a fraction depending on denominator
- x = NewRat(10, 2)
- x.Denom().SetInt64(3)
- if x.Cmp(q53) != 0 {
- t.Errorf("2b) got %s want %s", x, q53)
- }
-
- // 3) changing the numerator/denominator of a Rat changes the Rat
- x.SetFrac(a, b)
- a = x.Num()
- b = x.Denom()
- a.SetInt64(5)
- b.SetInt64(3)
- if x.Cmp(q53) != 0 {
- t.Errorf("3) got %s want %s", x, q53)
- }
-}
-
-func TestFloat32Distribution(t *testing.T) {
- // Generate a distribution of (sign, mantissa, exp) values
- // broader than the float32 range, and check Rat.Float32()
- // always picks the closest float32 approximation.
- var add = []int64{
- 0,
- 1,
- 3,
- 5,
- 7,
- 9,
- 11,
- }
- var winc, einc = uint64(1), 1 // soak test (~1.5s on x86-64)
- if testing.Short() {
- winc, einc = 5, 15 // quick test (~60ms on x86-64)
- }
-
- for _, sign := range "+-" {
- for _, a := range add {
- for wid := uint64(0); wid < 30; wid += winc {
- b := 1<<wid + a
- if sign == '-' {
- b = -b
- }
- for exp := -150; exp < 150; exp += einc {
- num, den := NewInt(b), NewInt(1)
- if exp > 0 {
- num.Lsh(num, uint(exp))
- } else {
- den.Lsh(den, uint(-exp))
- }
- r := new(Rat).SetFrac(num, den)
- f, _ := r.Float32()
-
- if !checkIsBestApprox32(t, f, r) {
- // Append context information.
- t.Errorf("(input was mantissa %#x, exp %d; f = %g (%b); f ~ %g; r = %v)",
- b, exp, f, f, math.Ldexp(float64(b), exp), r)
- }
-
- checkNonLossyRoundtrip32(t, f)
- }
- }
- }
- }
-}
-
-func TestFloat64Distribution(t *testing.T) {
- // Generate a distribution of (sign, mantissa, exp) values
- // broader than the float64 range, and check Rat.Float64()
- // always picks the closest float64 approximation.
- var add = []int64{
- 0,
- 1,
- 3,
- 5,
- 7,
- 9,
- 11,
- }
- var winc, einc = uint64(1), 1 // soak test (~75s on x86-64)
- if testing.Short() {
- winc, einc = 10, 500 // quick test (~12ms on x86-64)
- }
-
- for _, sign := range "+-" {
- for _, a := range add {
- for wid := uint64(0); wid < 60; wid += winc {
- b := 1<<wid + a
- if sign == '-' {
- b = -b
- }
- for exp := -1100; exp < 1100; exp += einc {
- num, den := NewInt(b), NewInt(1)
- if exp > 0 {
- num.Lsh(num, uint(exp))
- } else {
- den.Lsh(den, uint(-exp))
- }
- r := new(Rat).SetFrac(num, den)
- f, _ := r.Float64()
-
- if !checkIsBestApprox64(t, f, r) {
- // Append context information.
- t.Errorf("(input was mantissa %#x, exp %d; f = %g (%b); f ~ %g; r = %v)",
- b, exp, f, f, math.Ldexp(float64(b), exp), r)
- }
-
- checkNonLossyRoundtrip64(t, f)
- }
- }
- }
- }
-}
-
-// TestSetFloat64NonFinite checks that SetFloat64 of a non-finite value
-// returns nil.
-func TestSetFloat64NonFinite(t *testing.T) {
- for _, f := range []float64{math.NaN(), math.Inf(+1), math.Inf(-1)} {
- var r Rat
- if r2 := r.SetFloat64(f); r2 != nil {
- t.Errorf("SetFloat64(%g) was %v, want nil", f, r2)
- }
- }
-}
-
-// checkNonLossyRoundtrip32 checks that a float->Rat->float roundtrip is
-// non-lossy for finite f.
-func checkNonLossyRoundtrip32(t *testing.T, f float32) {
- if !isFinite(float64(f)) {
- return
- }
- r := new(Rat).SetFloat64(float64(f))
- if r == nil {
- t.Errorf("Rat.SetFloat64(float64(%g) (%b)) == nil", f, f)
- return
- }
- f2, exact := r.Float32()
- if f != f2 || !exact {
- t.Errorf("Rat.SetFloat64(float64(%g)).Float32() = %g (%b), %v, want %g (%b), %v; delta = %b",
- f, f2, f2, exact, f, f, true, f2-f)
- }
-}
-
-// checkNonLossyRoundtrip64 checks that a float->Rat->float roundtrip is
-// non-lossy for finite f.
-func checkNonLossyRoundtrip64(t *testing.T, f float64) {
- if !isFinite(f) {
- return
- }
- r := new(Rat).SetFloat64(f)
- if r == nil {
- t.Errorf("Rat.SetFloat64(%g (%b)) == nil", f, f)
- return
- }
- f2, exact := r.Float64()
- if f != f2 || !exact {
- t.Errorf("Rat.SetFloat64(%g).Float64() = %g (%b), %v, want %g (%b), %v; delta = %b",
- f, f2, f2, exact, f, f, true, f2-f)
- }
-}
-
-// delta returns the absolute difference between r and f.
-func delta(r *Rat, f float64) *Rat {
- d := new(Rat).Sub(r, new(Rat).SetFloat64(f))
- return d.Abs(d)
-}
-
-// checkIsBestApprox32 checks that f is the best possible float32
-// approximation of r.
-// Returns true on success.
-func checkIsBestApprox32(t *testing.T, f float32, r *Rat) bool {
- if math.Abs(float64(f)) >= math.MaxFloat32 {
- // Cannot check +Inf, -Inf, nor the float next to them (MaxFloat32).
- // But we have tests for these special cases.
- return true
- }
-
- // r must be strictly between f0 and f1, the floats bracketing f.
- f0 := math.Nextafter32(f, float32(math.Inf(-1)))
- f1 := math.Nextafter32(f, float32(math.Inf(+1)))
-
- // For f to be correct, r must be closer to f than to f0 or f1.
- df := delta(r, float64(f))
- df0 := delta(r, float64(f0))
- df1 := delta(r, float64(f1))
- if df.Cmp(df0) > 0 {
- t.Errorf("Rat(%v).Float32() = %g (%b), but previous float32 %g (%b) is closer", r, f, f, f0, f0)
- return false
- }
- if df.Cmp(df1) > 0 {
- t.Errorf("Rat(%v).Float32() = %g (%b), but next float32 %g (%b) is closer", r, f, f, f1, f1)
- return false
- }
- if df.Cmp(df0) == 0 && !isEven32(f) {
- t.Errorf("Rat(%v).Float32() = %g (%b); halfway should have rounded to %g (%b) instead", r, f, f, f0, f0)
- return false
- }
- if df.Cmp(df1) == 0 && !isEven32(f) {
- t.Errorf("Rat(%v).Float32() = %g (%b); halfway should have rounded to %g (%b) instead", r, f, f, f1, f1)
- return false
- }
- return true
-}
-
-// checkIsBestApprox64 checks that f is the best possible float64
-// approximation of r.
-// Returns true on success.
-func checkIsBestApprox64(t *testing.T, f float64, r *Rat) bool {
- if math.Abs(f) >= math.MaxFloat64 {
- // Cannot check +Inf, -Inf, nor the float next to them (MaxFloat64).
- // But we have tests for these special cases.
- return true
- }
-
- // r must be strictly between f0 and f1, the floats bracketing f.
- f0 := math.Nextafter(f, math.Inf(-1))
- f1 := math.Nextafter(f, math.Inf(+1))
-
- // For f to be correct, r must be closer to f than to f0 or f1.
- df := delta(r, f)
- df0 := delta(r, f0)
- df1 := delta(r, f1)
- if df.Cmp(df0) > 0 {
- t.Errorf("Rat(%v).Float64() = %g (%b), but previous float64 %g (%b) is closer", r, f, f, f0, f0)
- return false
- }
- if df.Cmp(df1) > 0 {
- t.Errorf("Rat(%v).Float64() = %g (%b), but next float64 %g (%b) is closer", r, f, f, f1, f1)
- return false
- }
- if df.Cmp(df0) == 0 && !isEven64(f) {
- t.Errorf("Rat(%v).Float64() = %g (%b); halfway should have rounded to %g (%b) instead", r, f, f, f0, f0)
- return false
- }
- if df.Cmp(df1) == 0 && !isEven64(f) {
- t.Errorf("Rat(%v).Float64() = %g (%b); halfway should have rounded to %g (%b) instead", r, f, f, f1, f1)
- return false
- }
- return true
-}
-
-func isEven32(f float32) bool { return math.Float32bits(f)&1 == 0 }
-func isEven64(f float64) bool { return math.Float64bits(f)&1 == 0 }
-
-func TestIsFinite(t *testing.T) {
- finites := []float64{
- 1.0 / 3,
- 4891559871276714924261e+222,
- math.MaxFloat64,
- math.SmallestNonzeroFloat64,
- -math.MaxFloat64,
- -math.SmallestNonzeroFloat64,
- }
- for _, f := range finites {
- if !isFinite(f) {
- t.Errorf("!IsFinite(%g (%b))", f, f)
- }
- }
- nonfinites := []float64{
- math.NaN(),
- math.Inf(-1),
- math.Inf(+1),
- }
- for _, f := range nonfinites {
- if isFinite(f) {
- t.Errorf("IsFinite(%g, (%b))", f, f)
- }
- }
-}
diff --git a/src/cmd/compile/internal/big/ratconv.go b/src/cmd/compile/internal/big/ratconv.go
deleted file mode 100644
index 57df124..0000000
--- a/src/cmd/compile/internal/big/ratconv.go
+++ /dev/null
@@ -1,264 +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 implements rat-to-string conversion functions.
-
-package big
-
-import (
- "errors"
- "fmt"
- "io"
- "strconv"
- "strings"
-)
-
-func ratTok(ch rune) bool {
- return strings.ContainsRune("+-/0123456789.eE", ch)
-}
-
-// Scan is a support routine for fmt.Scanner. It accepts the formats
-// 'e', 'E', 'f', 'F', 'g', 'G', and 'v'. All formats are equivalent.
-func (z *Rat) Scan(s fmt.ScanState, ch rune) error {
- tok, err := s.Token(true, ratTok)
- if err != nil {
- return err
- }
- if !strings.ContainsRune("efgEFGv", ch) {
- return errors.New("Rat.Scan: invalid verb")
- }
- if _, ok := z.SetString(string(tok)); !ok {
- return errors.New("Rat.Scan: invalid syntax")
- }
- return nil
-}
-
-// SetString sets z to the value of s and returns z and a boolean indicating
-// success. s can be given as a fraction "a/b" or as a floating-point number
-// optionally followed by an exponent. If the operation failed, the value of
-// z is undefined but the returned value is nil.
-func (z *Rat) SetString(s string) (*Rat, bool) {
- if len(s) == 0 {
- return nil, false
- }
- // len(s) > 0
-
- // parse fraction a/b, if any
- if sep := strings.Index(s, "/"); sep >= 0 {
- if _, ok := z.a.SetString(s[:sep], 0); !ok {
- return nil, false
- }
- s = s[sep+1:]
- var err error
- if z.b.abs, _, _, err = z.b.abs.scan(strings.NewReader(s), 0, false); err != nil {
- return nil, false
- }
- if len(z.b.abs) == 0 {
- return nil, false
- }
- return z.norm(), true
- }
-
- // parse floating-point number
- r := strings.NewReader(s)
-
- // sign
- neg, err := scanSign(r)
- if err != nil {
- return nil, false
- }
-
- // mantissa
- var ecorr int
- z.a.abs, _, ecorr, err = z.a.abs.scan(r, 10, true)
- if err != nil {
- return nil, false
- }
-
- // exponent
- var exp int64
- exp, _, err = scanExponent(r, false)
- if err != nil {
- return nil, false
- }
-
- // there should be no unread characters left
- if _, err = r.ReadByte(); err != io.EOF {
- return nil, false
- }
-
- // correct exponent
- if ecorr < 0 {
- exp += int64(ecorr)
- }
-
- // compute exponent power
- expabs := exp
- if expabs < 0 {
- expabs = -expabs
- }
- powTen := nat(nil).expNN(natTen, nat(nil).setWord(Word(expabs)), nil)
-
- // complete fraction
- if exp < 0 {
- z.b.abs = powTen
- z.norm()
- } else {
- z.a.abs = z.a.abs.mul(z.a.abs, powTen)
- z.b.abs = z.b.abs[:0]
- }
-
- z.a.neg = neg && len(z.a.abs) > 0 // 0 has no sign
-
- return z, true
-}
-
-// scanExponent scans the longest possible prefix of r representing a decimal
-// ('e', 'E') or binary ('p') exponent, if any. It returns the exponent, the
-// exponent base (10 or 2), or a read or syntax error, if any.
-//
-// exponent = ( "E" | "e" | "p" ) [ sign ] digits .
-// sign = "+" | "-" .
-// digits = digit { digit } .
-// digit = "0" ... "9" .
-//
-// A binary exponent is only permitted if binExpOk is set.
-func scanExponent(r io.ByteScanner, binExpOk bool) (exp int64, base int, err error) {
- base = 10
-
- var ch byte
- if ch, err = r.ReadByte(); err != nil {
- if err == io.EOF {
- err = nil // no exponent; same as e0
- }
- return
- }
-
- switch ch {
- case 'e', 'E':
- // ok
- case 'p':
- if binExpOk {
- base = 2
- break // ok
- }
- fallthrough // binary exponent not permitted
- default:
- r.UnreadByte()
- return // no exponent; same as e0
- }
-
- var neg bool
- if neg, err = scanSign(r); err != nil {
- return
- }
-
- var digits []byte
- if neg {
- digits = append(digits, '-')
- }
-
- // no need to use nat.scan for exponent digits
- // since we only care about int64 values - the
- // from-scratch scan is easy enough and faster
- for i := 0; ; i++ {
- if ch, err = r.ReadByte(); err != nil {
- if err != io.EOF || i == 0 {
- return
- }
- err = nil
- break // i > 0
- }
- if ch < '0' || '9' < ch {
- if i == 0 {
- r.UnreadByte()
- err = fmt.Errorf("invalid exponent (missing digits)")
- return
- }
- break // i > 0
- }
- digits = append(digits, byte(ch))
- }
- // i > 0 => we have at least one digit
-
- exp, err = strconv.ParseInt(string(digits), 10, 64)
- return
-}
-
-// String returns a string representation of x in the form "a/b" (even if b == 1).
-func (x *Rat) String() string {
- var buf []byte
- buf = x.a.Append(buf, 10)
- buf = append(buf, '/')
- if len(x.b.abs) != 0 {
- buf = x.b.Append(buf, 10)
- } else {
- buf = append(buf, '1')
- }
- return string(buf)
-}
-
-// RatString returns a string representation of x in the form "a/b" if b != 1,
-// and in the form "a" if b == 1.
-func (x *Rat) RatString() string {
- if x.IsInt() {
- return x.a.String()
- }
- return x.String()
-}
-
-// FloatString returns a string representation of x in decimal form with prec
-// digits of precision after the decimal point. The last digit is rounded to
-// nearest, with halves rounded away from zero.
-func (x *Rat) FloatString(prec int) string {
- var buf []byte
-
- if x.IsInt() {
- buf = x.a.Append(buf, 10)
- if prec > 0 {
- buf = append(buf, '.')
- for i := prec; i > 0; i-- {
- buf = append(buf, '0')
- }
- }
- return string(buf)
- }
- // x.b.abs != 0
-
- q, r := nat(nil).div(nat(nil), x.a.abs, x.b.abs)
-
- p := natOne
- if prec > 0 {
- p = nat(nil).expNN(natTen, nat(nil).setUint64(uint64(prec)), nil)
- }
-
- r = r.mul(r, p)
- r, r2 := r.div(nat(nil), r, x.b.abs)
-
- // see if we need to round up
- r2 = r2.add(r2, r2)
- if x.b.abs.cmp(r2) <= 0 {
- r = r.add(r, natOne)
- if r.cmp(p) >= 0 {
- q = nat(nil).add(q, natOne)
- r = nat(nil).sub(r, p)
- }
- }
-
- if x.a.neg {
- buf = append(buf, '-')
- }
- buf = append(buf, q.utoa(10)...) // itoa ignores sign if q == 0
-
- if prec > 0 {
- buf = append(buf, '.')
- rs := r.utoa(10)
- for i := prec - len(rs); i > 0; i-- {
- buf = append(buf, '0')
- }
- buf = append(buf, rs...)
- }
-
- return string(buf)
-}
diff --git a/src/cmd/compile/internal/big/ratconv_test.go b/src/cmd/compile/internal/big/ratconv_test.go
deleted file mode 100644
index 17bda47..0000000
--- a/src/cmd/compile/internal/big/ratconv_test.go
+++ /dev/null
@@ -1,453 +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 big
-
-import (
- "bytes"
- "fmt"
- "math"
- "strconv"
- "strings"
- "testing"
-)
-
-type StringTest struct {
- in, out string
- ok bool
-}
-
-var setStringTests = []StringTest{
- {"0", "0", true},
- {"-0", "0", true},
- {"1", "1", true},
- {"-1", "-1", true},
- {"1.", "1", true},
- {"1e0", "1", true},
- {"1.e1", "10", true},
- {in: "1e"},
- {in: "1.e"},
- {in: "1e+14e-5"},
- {in: "1e4.5"},
- {in: "r"},
- {in: "a/b"},
- {in: "a.b"},
- {"-0.1", "-1/10", true},
- {"-.1", "-1/10", true},
- {"2/4", "1/2", true},
- {".25", "1/4", true},
- {"-1/5", "-1/5", true},
- {"8129567.7690E14", "812956776900000000000", true},
- {"78189e+4", "781890000", true},
- {"553019.8935e+8", "55301989350000", true},
- {"98765432109876543210987654321e-10", "98765432109876543210987654321/10000000000", true},
- {"9877861857500000E-7", "3951144743/4", true},
- {"2169378.417e-3", "2169378417/1000000", true},
- {"884243222337379604041632732738665534", "884243222337379604041632732738665534", true},
- {"53/70893980658822810696", "53/70893980658822810696", true},
- {"106/141787961317645621392", "53/70893980658822810696", true},
- {"204211327800791583.81095", "4084226556015831676219/20000", true},
- {in: "1/0"},
-}
-
-// These are not supported by fmt.Fscanf.
-var setStringTests2 = []StringTest{
- {"0x10", "16", true},
- {"-010/1", "-8", true}, // TODO(gri) should we even permit octal here?
- {"-010.", "-10", true},
- {"0x10/0x20", "1/2", true},
- {"0b1000/3", "8/3", true},
- // TODO(gri) add more tests
-}
-
-func TestRatSetString(t *testing.T) {
- var tests []StringTest
- tests = append(tests, setStringTests...)
- tests = append(tests, setStringTests2...)
-
- for i, test := range tests {
- x, ok := new(Rat).SetString(test.in)
-
- if ok {
- if !test.ok {
- t.Errorf("#%d SetString(%q) expected failure", i, test.in)
- } else if x.RatString() != test.out {
- t.Errorf("#%d SetString(%q) got %s want %s", i, test.in, x.RatString(), test.out)
- }
- } else if x != nil {
- t.Errorf("#%d SetString(%q) got %p want nil", i, test.in, x)
- }
- }
-}
-
-func TestRatScan(t *testing.T) {
- var buf bytes.Buffer
- for i, test := range setStringTests {
- x := new(Rat)
- buf.Reset()
- buf.WriteString(test.in)
-
- _, err := fmt.Fscanf(&buf, "%v", x)
- if err == nil != test.ok {
- if test.ok {
- t.Errorf("#%d (%s) error: %s", i, test.in, err)
- } else {
- t.Errorf("#%d (%s) expected error", i, test.in)
- }
- continue
- }
- if err == nil && x.RatString() != test.out {
- t.Errorf("#%d got %s want %s", i, x.RatString(), test.out)
- }
- }
-}
-
-var floatStringTests = []struct {
- in string
- prec int
- out string
-}{
- {"0", 0, "0"},
- {"0", 4, "0.0000"},
- {"1", 0, "1"},
- {"1", 2, "1.00"},
- {"-1", 0, "-1"},
- {"0.05", 1, "0.1"},
- {"-0.05", 1, "-0.1"},
- {".25", 2, "0.25"},
- {".25", 1, "0.3"},
- {".25", 3, "0.250"},
- {"-1/3", 3, "-0.333"},
- {"-2/3", 4, "-0.6667"},
- {"0.96", 1, "1.0"},
- {"0.999", 2, "1.00"},
- {"0.9", 0, "1"},
- {".25", -1, "0"},
- {".55", -1, "1"},
-}
-
-func TestFloatString(t *testing.T) {
- for i, test := range floatStringTests {
- x, _ := new(Rat).SetString(test.in)
-
- if x.FloatString(test.prec) != test.out {
- t.Errorf("#%d got %s want %s", i, x.FloatString(test.prec), test.out)
- }
- }
-}
-
-// Test inputs to Rat.SetString. The prefix "long:" causes the test
-// to be skipped in --test.short mode. (The threshold is about 500us.)
-var float64inputs = []string{
- // Constants plundered from strconv/testfp.txt.
-
- // Table 1: Stress Inputs for Conversion to 53-bit Binary, < 1/2 ULP
- "5e+125",
- "69e+267",
- "999e-026",
- "7861e-034",
- "75569e-254",
- "928609e-261",
- "9210917e+080",
- "84863171e+114",
- "653777767e+273",
- "5232604057e-298",
- "27235667517e-109",
- "653532977297e-123",
- "3142213164987e-294",
- "46202199371337e-072",
- "231010996856685e-073",
- "9324754620109615e+212",
- "78459735791271921e+049",
- "272104041512242479e+200",
- "6802601037806061975e+198",
- "20505426358836677347e-221",
- "836168422905420598437e-234",
- "4891559871276714924261e+222",
-
- // Table 2: Stress Inputs for Conversion to 53-bit Binary, > 1/2 ULP
- "9e-265",
- "85e-037",
- "623e+100",
- "3571e+263",
- "81661e+153",
- "920657e-023",
- "4603285e-024",
- "87575437e-309",
- "245540327e+122",
- "6138508175e+120",
- "83356057653e+193",
- "619534293513e+124",
- "2335141086879e+218",
- "36167929443327e-159",
- "609610927149051e-255",
- "3743626360493413e-165",
- "94080055902682397e-242",
- "899810892172646163e+283",
- "7120190517612959703e+120",
- "25188282901709339043e-252",
- "308984926168550152811e-052",
- "6372891218502368041059e+064",
-
- // Table 14: Stress Inputs for Conversion to 24-bit Binary, <1/2 ULP
- "5e-20",
- "67e+14",
- "985e+15",
- "7693e-42",
- "55895e-16",
- "996622e-44",
- "7038531e-32",
- "60419369e-46",
- "702990899e-20",
- "6930161142e-48",
- "25933168707e+13",
- "596428896559e+20",
-
- // Table 15: Stress Inputs for Conversion to 24-bit Binary, >1/2 ULP
- "3e-23",
- "57e+18",
- "789e-35",
- "2539e-18",
- "76173e+28",
- "887745e-11",
- "5382571e-37",
- "82381273e-35",
- "750486563e-38",
- "3752432815e-39",
- "75224575729e-45",
- "459926601011e+15",
-
- // Constants plundered from strconv/atof_test.go.
-
- "0",
- "1",
- "+1",
- "1e23",
- "1E23",
- "100000000000000000000000",
- "1e-100",
- "123456700",
- "99999999999999974834176",
- "100000000000000000000001",
- "100000000000000008388608",
- "100000000000000016777215",
- "100000000000000016777216",
- "-1",
- "-0.1",
- "-0", // NB: exception made for this input
- "1e-20",
- "625e-3",
-
- // largest float64
- "1.7976931348623157e308",
- "-1.7976931348623157e308",
- // next float64 - too large
- "1.7976931348623159e308",
- "-1.7976931348623159e308",
- // the border is ...158079
- // borderline - okay
- "1.7976931348623158e308",
- "-1.7976931348623158e308",
- // borderline - too large
- "1.797693134862315808e308",
- "-1.797693134862315808e308",
-
- // a little too large
- "1e308",
- "2e308",
- "1e309",
-
- // way too large
- "1e310",
- "-1e310",
- "1e400",
- "-1e400",
- "long:1e400000",
- "long:-1e400000",
-
- // denormalized
- "1e-305",
- "1e-306",
- "1e-307",
- "1e-308",
- "1e-309",
- "1e-310",
- "1e-322",
- // smallest denormal
- "5e-324",
- "4e-324",
- "3e-324",
- // too small
- "2e-324",
- // way too small
- "1e-350",
- "long:1e-400000",
- // way too small, negative
- "-1e-350",
- "long:-1e-400000",
-
- // try to overflow exponent
- // [Disabled: too slow and memory-hungry with rationals.]
- // "1e-4294967296",
- // "1e+4294967296",
- // "1e-18446744073709551616",
- // "1e+18446744073709551616",
-
- // http://www.exploringbinary.com/java-hangs-when-converting-2-2250738585072012e-308/
- "2.2250738585072012e-308",
- // http://www.exploringbinary.com/php-hangs-on-numeric-value-2-2250738585072011e-308/
- "2.2250738585072011e-308",
-
- // A very large number (initially wrongly parsed by the fast algorithm).
- "4.630813248087435e+307",
-
- // A different kind of very large number.
- "22.222222222222222",
- "long:2." + strings.Repeat("2", 4000) + "e+1",
-
- // Exactly halfway between 1 and math.Nextafter(1, 2).
- // Round to even (down).
- "1.00000000000000011102230246251565404236316680908203125",
- // Slightly lower; still round down.
- "1.00000000000000011102230246251565404236316680908203124",
- // Slightly higher; round up.
- "1.00000000000000011102230246251565404236316680908203126",
- // Slightly higher, but you have to read all the way to the end.
- "long:1.00000000000000011102230246251565404236316680908203125" + strings.Repeat("0", 10000) + "1",
-
- // Smallest denormal, 2^(-1022-52)
- "4.940656458412465441765687928682213723651e-324",
- // Half of smallest denormal, 2^(-1022-53)
- "2.470328229206232720882843964341106861825e-324",
- // A little more than the exact half of smallest denormal
- // 2^-1075 + 2^-1100. (Rounds to 1p-1074.)
- "2.470328302827751011111470718709768633275e-324",
- // The exact halfway between smallest normal and largest denormal:
- // 2^-1022 - 2^-1075. (Rounds to 2^-1022.)
- "2.225073858507201136057409796709131975935e-308",
-
- "1152921504606846975", // 1<<60 - 1
- "-1152921504606846975", // -(1<<60 - 1)
- "1152921504606846977", // 1<<60 + 1
- "-1152921504606846977", // -(1<<60 + 1)
-
- "1/3",
-}
-
-// isFinite reports whether f represents a finite rational value.
-// It is equivalent to !math.IsNan(f) && !math.IsInf(f, 0).
-func isFinite(f float64) bool {
- return math.Abs(f) <= math.MaxFloat64
-}
-
-func TestFloat32SpecialCases(t *testing.T) {
- for _, input := range float64inputs {
- if strings.HasPrefix(input, "long:") {
- if testing.Short() {
- continue
- }
- input = input[len("long:"):]
- }
-
- r, ok := new(Rat).SetString(input)
- if !ok {
- t.Errorf("Rat.SetString(%q) failed", input)
- continue
- }
- f, exact := r.Float32()
-
- // 1. Check string -> Rat -> float32 conversions are
- // consistent with strconv.ParseFloat.
- // Skip this check if the input uses "a/b" rational syntax.
- if !strings.Contains(input, "/") {
- e64, _ := strconv.ParseFloat(input, 32)
- e := float32(e64)
-
- // Careful: negative Rats too small for
- // float64 become -0, but Rat obviously cannot
- // preserve the sign from SetString("-0").
- switch {
- case math.Float32bits(e) == math.Float32bits(f):
- // Ok: bitwise equal.
- case f == 0 && r.Num().BitLen() == 0:
- // Ok: Rat(0) is equivalent to both +/- float64(0).
- default:
- t.Errorf("strconv.ParseFloat(%q) = %g (%b), want %g (%b); delta = %g", input, e, e, f, f, f-e)
- }
- }
-
- if !isFinite(float64(f)) {
- continue
- }
-
- // 2. Check f is best approximation to r.
- if !checkIsBestApprox32(t, f, r) {
- // Append context information.
- t.Errorf("(input was %q)", input)
- }
-
- // 3. Check f->R->f roundtrip is non-lossy.
- checkNonLossyRoundtrip32(t, f)
-
- // 4. Check exactness using slow algorithm.
- if wasExact := new(Rat).SetFloat64(float64(f)).Cmp(r) == 0; wasExact != exact {
- t.Errorf("Rat.SetString(%q).Float32().exact = %t, want %t", input, exact, wasExact)
- }
- }
-}
-
-func TestFloat64SpecialCases(t *testing.T) {
- for _, input := range float64inputs {
- if strings.HasPrefix(input, "long:") {
- if testing.Short() {
- continue
- }
- input = input[len("long:"):]
- }
-
- r, ok := new(Rat).SetString(input)
- if !ok {
- t.Errorf("Rat.SetString(%q) failed", input)
- continue
- }
- f, exact := r.Float64()
-
- // 1. Check string -> Rat -> float64 conversions are
- // consistent with strconv.ParseFloat.
- // Skip this check if the input uses "a/b" rational syntax.
- if !strings.Contains(input, "/") {
- e, _ := strconv.ParseFloat(input, 64)
-
- // Careful: negative Rats too small for
- // float64 become -0, but Rat obviously cannot
- // preserve the sign from SetString("-0").
- switch {
- case math.Float64bits(e) == math.Float64bits(f):
- // Ok: bitwise equal.
- case f == 0 && r.Num().BitLen() == 0:
- // Ok: Rat(0) is equivalent to both +/- float64(0).
- default:
- t.Errorf("strconv.ParseFloat(%q) = %g (%b), want %g (%b); delta = %g", input, e, e, f, f, f-e)
- }
- }
-
- if !isFinite(f) {
- continue
- }
-
- // 2. Check f is best approximation to r.
- if !checkIsBestApprox64(t, f, r) {
- // Append context information.
- t.Errorf("(input was %q)", input)
- }
-
- // 3. Check f->R->f roundtrip is non-lossy.
- checkNonLossyRoundtrip64(t, f)
-
- // 4. Check exactness using slow algorithm.
- if wasExact := new(Rat).SetFloat64(f).Cmp(r) == 0; wasExact != exact {
- t.Errorf("Rat.SetString(%q).Float64().exact = %t, want %t", input, exact, wasExact)
- }
- }
-}
diff --git a/src/cmd/compile/internal/big/ratmarsh.go b/src/cmd/compile/internal/big/ratmarsh.go
deleted file mode 100644
index b82e8d4..0000000
--- a/src/cmd/compile/internal/big/ratmarsh.go
+++ /dev/null
@@ -1,73 +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 implements encoding/decoding of Rats.
-
-package big
-
-import (
- "encoding/binary"
- "errors"
- "fmt"
-)
-
-// Gob codec version. Permits backward-compatible changes to the encoding.
-const ratGobVersion byte = 1
-
-// GobEncode implements the gob.GobEncoder interface.
-func (x *Rat) GobEncode() ([]byte, error) {
- if x == nil {
- return nil, nil
- }
- buf := make([]byte, 1+4+(len(x.a.abs)+len(x.b.abs))*_S) // extra bytes for version and sign bit (1), and numerator length (4)
- i := x.b.abs.bytes(buf)
- j := x.a.abs.bytes(buf[:i])
- n := i - j
- if int(uint32(n)) != n {
- // this should never happen
- return nil, errors.New("Rat.GobEncode: numerator too large")
- }
- binary.BigEndian.PutUint32(buf[j-4:j], uint32(n))
- j -= 1 + 4
- b := ratGobVersion << 1 // make space for sign bit
- if x.a.neg {
- b |= 1
- }
- buf[j] = b
- return buf[j:], nil
-}
-
-// GobDecode implements the gob.GobDecoder interface.
-func (z *Rat) GobDecode(buf []byte) error {
- if len(buf) == 0 {
- // Other side sent a nil or default value.
- *z = Rat{}
- return nil
- }
- b := buf[0]
- if b>>1 != ratGobVersion {
- return fmt.Errorf("Rat.GobDecode: encoding version %d not supported", b>>1)
- }
- const j = 1 + 4
- i := j + binary.BigEndian.Uint32(buf[j-4:j])
- z.a.neg = b&1 != 0
- z.a.abs = z.a.abs.setBytes(buf[j:i])
- z.b.abs = z.b.abs.setBytes(buf[i:])
- return nil
-}
-
-// MarshalText implements the encoding.TextMarshaler interface.
-func (x *Rat) MarshalText() (text []byte, err error) {
- // TODO(gri): get rid of the []byte/string conversion
- return []byte(x.RatString()), nil
-}
-
-// UnmarshalText implements the encoding.TextUnmarshaler interface.
-func (z *Rat) UnmarshalText(text []byte) error {
- // TODO(gri): get rid of the []byte/string conversion
- if _, ok := z.SetString(string(text)); !ok {
- return fmt.Errorf("math/big: cannot unmarshal %q into a *big.Rat", text)
- }
- return nil
-}
diff --git a/src/cmd/compile/internal/big/ratmarsh_test.go b/src/cmd/compile/internal/big/ratmarsh_test.go
deleted file mode 100644
index 351d109..0000000
--- a/src/cmd/compile/internal/big/ratmarsh_test.go
+++ /dev/null
@@ -1,125 +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 big
-
-import (
- "bytes"
- "encoding/gob"
- "encoding/json"
- "encoding/xml"
- "testing"
-)
-
-func TestRatGobEncoding(t *testing.T) {
- var medium bytes.Buffer
- enc := gob.NewEncoder(&medium)
- dec := gob.NewDecoder(&medium)
- for _, test := range encodingTests {
- medium.Reset() // empty buffer for each test case (in case of failures)
- var tx Rat
- tx.SetString(test + ".14159265")
- if err := enc.Encode(&tx); err != nil {
- t.Errorf("encoding of %s failed: %s", &tx, err)
- continue
- }
- var rx Rat
- if err := dec.Decode(&rx); err != nil {
- t.Errorf("decoding of %s failed: %s", &tx, err)
- continue
- }
- if rx.Cmp(&tx) != 0 {
- t.Errorf("transmission of %s failed: got %s want %s", &tx, &rx, &tx)
- }
- }
-}
-
-// Sending a nil Rat pointer (inside a slice) on a round trip through gob should yield a zero.
-// TODO: top-level nils.
-func TestGobEncodingNilRatInSlice(t *testing.T) {
- buf := new(bytes.Buffer)
- enc := gob.NewEncoder(buf)
- dec := gob.NewDecoder(buf)
-
- var in = make([]*Rat, 1)
- err := enc.Encode(&in)
- if err != nil {
- t.Errorf("gob encode failed: %q", err)
- }
- var out []*Rat
- err = dec.Decode(&out)
- if err != nil {
- t.Fatalf("gob decode failed: %q", err)
- }
- if len(out) != 1 {
- t.Fatalf("wrong len; want 1 got %d", len(out))
- }
- var zero Rat
- if out[0].Cmp(&zero) != 0 {
- t.Fatalf("transmission of (*Int)(nil) failed: got %s want 0", out)
- }
-}
-
-var ratNums = []string{
- "-141592653589793238462643383279502884197169399375105820974944592307816406286",
- "-1415926535897932384626433832795028841971",
- "-141592653589793",
- "-1",
- "0",
- "1",
- "141592653589793",
- "1415926535897932384626433832795028841971",
- "141592653589793238462643383279502884197169399375105820974944592307816406286",
-}
-
-var ratDenoms = []string{
- "1",
- "718281828459045",
- "7182818284590452353602874713526624977572",
- "718281828459045235360287471352662497757247093699959574966967627724076630353",
-}
-
-func TestRatJSONEncoding(t *testing.T) {
- for _, num := range ratNums {
- for _, denom := range ratDenoms {
- var tx Rat
- tx.SetString(num + "/" + denom)
- b, err := json.Marshal(&tx)
- if err != nil {
- t.Errorf("marshaling of %s failed: %s", &tx, err)
- continue
- }
- var rx Rat
- if err := json.Unmarshal(b, &rx); err != nil {
- t.Errorf("unmarshaling of %s failed: %s", &tx, err)
- continue
- }
- if rx.Cmp(&tx) != 0 {
- t.Errorf("JSON encoding of %s failed: got %s want %s", &tx, &rx, &tx)
- }
- }
- }
-}
-
-func TestRatXMLEncoding(t *testing.T) {
- for _, num := range ratNums {
- for _, denom := range ratDenoms {
- var tx Rat
- tx.SetString(num + "/" + denom)
- b, err := xml.Marshal(&tx)
- if err != nil {
- t.Errorf("marshaling of %s failed: %s", &tx, err)
- continue
- }
- var rx Rat
- if err := xml.Unmarshal(b, &rx); err != nil {
- t.Errorf("unmarshaling of %s failed: %s", &tx, err)
- continue
- }
- if rx.Cmp(&tx) != 0 {
- t.Errorf("XML encoding of %s failed: got %s want %s", &tx, &rx, &tx)
- }
- }
- }
-}
diff --git a/src/cmd/compile/internal/big/roundingmode_string.go b/src/cmd/compile/internal/big/roundingmode_string.go
deleted file mode 100644
index 05024b8..0000000
--- a/src/cmd/compile/internal/big/roundingmode_string.go
+++ /dev/null
@@ -1,16 +0,0 @@
-// generated by stringer -type=RoundingMode; DO NOT EDIT
-
-package big
-
-import "fmt"
-
-const _RoundingMode_name = "ToNearestEvenToNearestAwayToZeroAwayFromZeroToNegativeInfToPositiveInf"
-
-var _RoundingMode_index = [...]uint8{0, 13, 26, 32, 44, 57, 70}
-
-func (i RoundingMode) String() string {
- if i+1 >= RoundingMode(len(_RoundingMode_index)) {
- return fmt.Sprintf("RoundingMode(%d)", i)
- }
- return _RoundingMode_name[_RoundingMode_index[i]:_RoundingMode_index[i+1]]
-}
diff --git a/src/cmd/compile/internal/big/vendor.bash b/src/cmd/compile/internal/big/vendor.bash
deleted file mode 100755
index ac3ec9b..0000000
--- a/src/cmd/compile/internal/big/vendor.bash
+++ /dev/null
@@ -1,31 +0,0 @@
-#!/usr/bin/env bash
-
-# Copyright 2015 The Go Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style
-# license that can be found in the LICENSE file.
-
-# Run this script to obtain an up-to-date vendored version of math/big.
-
-BIGDIR=../../../../math/big
-
-# Start from scratch.
-rm *.go
-
-# We don't want any assembly files.
-cp $BIGDIR/*.go .
-
-# Use pure Go arith ops w/o build tag.
-sed 's|^// \+build math_big_pure_go$||' arith_decl_pure.go > arith_decl.go
-rm arith_decl_pure.go
-
-# Import vendored math/big in external tests (e.g., floatexample_test.go).
-for f in *_test.go; do
- sed 's|"math/big"|"cmd/compile/internal/big"|' $f > foo.go
- mv foo.go $f
-done
-
-# gofmt to clean up after sed
-gofmt -w .
-
-# Test that it works
-go test -short
diff --git a/src/cmd/compile/internal/gc/alg.go b/src/cmd/compile/internal/gc/alg.go
index 136612d..8113710 100644
--- a/src/cmd/compile/internal/gc/alg.go
+++ b/src/cmd/compile/internal/gc/alg.go
@@ -191,20 +191,20 @@ func genhash(sym *Sym, t *Type) {
markdcl()
// func sym(p *T, h uintptr) uintptr
- fn := Nod(ODCLFUNC, nil, nil)
+ fn := nod(ODCLFUNC, nil, nil)
fn.Func.Nname = newname(sym)
fn.Func.Nname.Class = PFUNC
- tfn := Nod(OTFUNC, nil, nil)
+ tfn := nod(OTFUNC, nil, nil)
fn.Func.Nname.Name.Param.Ntype = tfn
- n := Nod(ODCLFIELD, newname(Lookup("p")), typenod(Ptrto(t)))
+ n := nod(ODCLFIELD, newname(lookup("p")), typenod(ptrto(t)))
tfn.List.Append(n)
np := n.Left
- n = Nod(ODCLFIELD, newname(Lookup("h")), typenod(Types[TUINTPTR]))
+ n = nod(ODCLFIELD, newname(lookup("h")), typenod(Types[TUINTPTR]))
tfn.List.Append(n)
nh := n.Left
- n = Nod(ODCLFIELD, nil, typenod(Types[TUINTPTR])) // return value
+ n = nod(ODCLFIELD, nil, typenod(Types[TUINTPTR])) // return value
tfn.Rlist.Append(n)
funchdr(fn)
@@ -223,8 +223,8 @@ func genhash(sym *Sym, t *Type) {
// pure memory.
hashel := hashfor(t.Elem())
- n := Nod(ORANGE, nil, Nod(OIND, np, nil))
- ni := newname(Lookup("i"))
+ n := nod(ORANGE, nil, nod(OIND, np, nil))
+ ni := newname(lookup("i"))
ni.Type = Types[TINT]
n.List.Set1(ni)
n.Colas = true
@@ -232,15 +232,15 @@ func genhash(sym *Sym, t *Type) {
ni = n.List.First()
// h = hashel(&p[i], h)
- call := Nod(OCALL, hashel, nil)
+ call := nod(OCALL, hashel, nil)
- nx := Nod(OINDEX, np, ni)
+ nx := nod(OINDEX, np, ni)
nx.Bounded = true
- na := Nod(OADDR, nx, nil)
+ na := nod(OADDR, nx, nil)
na.Etype = 1 // no escape to heap
call.List.Append(na)
call.List.Append(nh)
- n.Nbody.Append(Nod(OAS, nh, call))
+ n.Nbody.Append(nod(OAS, nh, call))
fn.Nbody.Append(n)
@@ -259,13 +259,13 @@ func genhash(sym *Sym, t *Type) {
// Hash non-memory fields with appropriate hash function.
if !f.Type.IsRegularMemory() {
hashel := hashfor(f.Type)
- call := Nod(OCALL, hashel, nil)
- nx := NodSym(OXDOT, np, f.Sym) // TODO: fields from other packages?
- na := Nod(OADDR, nx, nil)
+ call := nod(OCALL, hashel, nil)
+ nx := nodSym(OXDOT, np, f.Sym) // TODO: fields from other packages?
+ na := nod(OADDR, nx, nil)
na.Etype = 1 // no escape to heap
call.List.Append(na)
call.List.Append(nh)
- fn.Nbody.Append(Nod(OAS, nh, call))
+ fn.Nbody.Append(nod(OAS, nh, call))
i++
continue
}
@@ -275,20 +275,20 @@ func genhash(sym *Sym, t *Type) {
// h = hashel(&p.first, size, h)
hashel := hashmem(f.Type)
- call := Nod(OCALL, hashel, nil)
- nx := NodSym(OXDOT, np, f.Sym) // TODO: fields from other packages?
- na := Nod(OADDR, nx, nil)
+ call := nod(OCALL, hashel, nil)
+ nx := nodSym(OXDOT, np, f.Sym) // TODO: fields from other packages?
+ na := nod(OADDR, nx, nil)
na.Etype = 1 // no escape to heap
call.List.Append(na)
call.List.Append(nh)
- call.List.Append(Nodintconst(size))
- fn.Nbody.Append(Nod(OAS, nh, call))
+ call.List.Append(nodintconst(size))
+ fn.Nbody.Append(nod(OAS, nh, call))
i = next
}
}
- r := Nod(ORETURN, nil, nil)
+ r := nod(ORETURN, nil, nil)
r.List.Append(nh)
fn.Nbody.Append(r)
@@ -313,9 +313,9 @@ func genhash(sym *Sym, t *Type) {
old_safemode := safemode
safemode = false
- Disable_checknil++
+ disable_checknil++
funccompile(fn)
- Disable_checknil--
+ disable_checknil--
safemode = old_safemode
}
@@ -346,10 +346,10 @@ func hashfor(t *Type) *Node {
n := newname(sym)
n.Class = PFUNC
- tfn := Nod(OTFUNC, nil, nil)
- tfn.List.Append(Nod(ODCLFIELD, nil, typenod(Ptrto(t))))
- tfn.List.Append(Nod(ODCLFIELD, nil, typenod(Types[TUINTPTR])))
- tfn.Rlist.Append(Nod(ODCLFIELD, nil, typenod(Types[TUINTPTR])))
+ tfn := nod(OTFUNC, nil, nil)
+ tfn.List.Append(nod(ODCLFIELD, nil, typenod(ptrto(t))))
+ tfn.List.Append(nod(ODCLFIELD, nil, typenod(Types[TUINTPTR])))
+ tfn.Rlist.Append(nod(ODCLFIELD, nil, typenod(Types[TUINTPTR])))
tfn = typecheck(tfn, Etype)
n.Type = tfn.Type
return n
@@ -367,20 +367,20 @@ func geneq(sym *Sym, t *Type) {
markdcl()
// func sym(p, q *T) bool
- fn := Nod(ODCLFUNC, nil, nil)
+ fn := nod(ODCLFUNC, nil, nil)
fn.Func.Nname = newname(sym)
fn.Func.Nname.Class = PFUNC
- tfn := Nod(OTFUNC, nil, nil)
+ tfn := nod(OTFUNC, nil, nil)
fn.Func.Nname.Name.Param.Ntype = tfn
- n := Nod(ODCLFIELD, newname(Lookup("p")), typenod(Ptrto(t)))
+ n := nod(ODCLFIELD, newname(lookup("p")), typenod(ptrto(t)))
tfn.List.Append(n)
np := n.Left
- n = Nod(ODCLFIELD, newname(Lookup("q")), typenod(Ptrto(t)))
+ n = nod(ODCLFIELD, newname(lookup("q")), typenod(ptrto(t)))
tfn.List.Append(n)
nq := n.Left
- n = Nod(ODCLFIELD, nil, typenod(Types[TBOOL]))
+ n = nod(ODCLFIELD, nil, typenod(Types[TBOOL]))
tfn.Rlist.Append(n)
funchdr(fn)
@@ -399,9 +399,9 @@ func geneq(sym *Sym, t *Type) {
// pure memory. Even if we unrolled the range loop,
// each iteration would be a function call, so don't bother
// unrolling.
- nrange := Nod(ORANGE, nil, Nod(OIND, np, nil))
+ nrange := nod(ORANGE, nil, nod(OIND, np, nil))
- ni := newname(Lookup("i"))
+ ni := newname(lookup("i"))
ni.Type = Types[TINT]
nrange.List.Set1(ni)
nrange.Colas = true
@@ -409,23 +409,23 @@ func geneq(sym *Sym, t *Type) {
ni = nrange.List.First()
// if p[i] != q[i] { return false }
- nx := Nod(OINDEX, np, ni)
+ nx := nod(OINDEX, np, ni)
nx.Bounded = true
- ny := Nod(OINDEX, nq, ni)
+ ny := nod(OINDEX, nq, ni)
ny.Bounded = true
- nif := Nod(OIF, nil, nil)
- nif.Left = Nod(ONE, nx, ny)
- r := Nod(ORETURN, nil, nil)
- r.List.Append(Nodbool(false))
+ nif := nod(OIF, nil, nil)
+ nif.Left = nod(ONE, nx, ny)
+ r := nod(ORETURN, nil, nil)
+ r.List.Append(nodbool(false))
nif.Nbody.Append(r)
nrange.Nbody.Append(nif)
fn.Nbody.Append(nrange)
// return true
- ret := Nod(ORETURN, nil, nil)
- ret.List.Append(Nodbool(true))
+ ret := nod(ORETURN, nil, nil)
+ ret.List.Append(nodbool(true))
fn.Nbody.Append(ret)
case TSTRUCT:
@@ -435,7 +435,7 @@ func geneq(sym *Sym, t *Type) {
cond = n
return
}
- cond = Nod(OANDAND, cond, n)
+ cond = nod(OANDAND, cond, n)
}
// Walk the struct using memequal for runs of AMEM
@@ -474,10 +474,10 @@ func geneq(sym *Sym, t *Type) {
}
if cond == nil {
- cond = Nodbool(true)
+ cond = nodbool(true)
}
- ret := Nod(ORETURN, nil, nil)
+ ret := nod(ORETURN, nil, nil)
ret.List.Append(cond)
fn.Nbody.Append(ret)
}
@@ -507,39 +507,39 @@ 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++
+ disable_checknil++
funccompile(fn)
safemode = old_safemode
- Disable_checknil--
+ disable_checknil--
}
// eqfield returns the node
// p.field == q.field
func eqfield(p *Node, q *Node, field *Sym) *Node {
- nx := NodSym(OXDOT, p, field)
- ny := NodSym(OXDOT, q, field)
- ne := Nod(OEQ, nx, ny)
+ nx := nodSym(OXDOT, p, field)
+ ny := nodSym(OXDOT, q, field)
+ ne := nod(OEQ, nx, ny)
return ne
}
// eqmem returns the node
// memequal(&p.field, &q.field [, size])
func eqmem(p *Node, q *Node, field *Sym, size int64) *Node {
- nx := Nod(OADDR, NodSym(OXDOT, p, field), nil)
+ nx := nod(OADDR, nodSym(OXDOT, p, field), nil)
nx.Etype = 1 // does not escape
- ny := Nod(OADDR, NodSym(OXDOT, q, field), nil)
+ ny := nod(OADDR, nodSym(OXDOT, q, field), nil)
ny.Etype = 1 // does not escape
nx = typecheck(nx, Erv)
ny = typecheck(ny, Erv)
fn, needsize := eqmemfunc(size, nx.Type.Elem())
- call := Nod(OCALL, fn, nil)
+ call := nod(OCALL, fn, nil)
call.List.Append(nx)
call.List.Append(ny)
if needsize {
- call.List.Append(Nodintconst(size))
+ call.List.Append(nodintconst(size))
}
return call
diff --git a/src/cmd/compile/internal/gc/align.go b/src/cmd/compile/internal/gc/align.go
index 2b62405..eee801f 100644
--- a/src/cmd/compile/internal/gc/align.go
+++ b/src/cmd/compile/internal/gc/align.go
@@ -21,7 +21,7 @@ func offmod(t *Type) {
f.Offset = int64(o)
o += int32(Widthptr)
if int64(o) >= Thearch.MAXWIDTH {
- Yyerror("interface too large")
+ yyerror("interface too large")
o = int32(Widthptr)
}
}
@@ -75,7 +75,7 @@ func widstruct(errtype *Type, t *Type, o int64, flag int) int64 {
}
o += w
if o >= Thearch.MAXWIDTH {
- Yyerror("type %v too large", Tconv(errtype, FmtLong))
+ yyerror("type %L too large", errtype)
o = 8 // small but nonzero
}
}
@@ -148,8 +148,8 @@ func dowidth(t *Type) {
// simtype == 0 during bootstrap
default:
- if Simtype[t.Etype] != 0 {
- et = Simtype[t.Etype]
+ if simtype[t.Etype] != 0 {
+ et = simtype[t.Etype]
}
}
@@ -169,10 +169,14 @@ func dowidth(t *Type) {
case TINT32, TUINT32, TFLOAT32:
w = 4
- case TINT64, TUINT64, TFLOAT64, TCOMPLEX64:
+ case TINT64, TUINT64, TFLOAT64:
w = 8
t.Align = uint8(Widthreg)
+ case TCOMPLEX64:
+ w = 8
+ t.Align = 4
+
case TCOMPLEX128:
w = 16
t.Align = uint8(Widthreg)
@@ -208,7 +212,7 @@ func dowidth(t *Type) {
t1 := t.ChanArgs()
dowidth(t1) // just in case
if t1.Elem().Width >= 1<<16 {
- Yyerror("channel element type too large (>64kB)")
+ yyerror("channel element type too large (>64kB)")
}
t.Width = 1
@@ -219,16 +223,13 @@ func dowidth(t *Type) {
case TFORW: // should have been filled in
if !t.Broke {
- Yyerror("invalid recursive type %v", t)
+ yyerror("invalid recursive type %v", t)
}
w = 1 // anything will do
- // dummy type; should be replaced before use.
case TANY:
- if Debug['A'] == 0 {
- Fatalf("dowidth any")
- }
- w = 1 // anything will do
+ // dummy type; should be replaced before use.
+ Fatalf("dowidth any")
case TSTRING:
if sizeof_String == 0 {
@@ -243,7 +244,7 @@ func dowidth(t *Type) {
}
if t.isDDDArray() {
if !t.Broke {
- Yyerror("use of [...] array outside of array literal")
+ yyerror("use of [...] array outside of array literal")
t.Broke = true
}
break
@@ -253,7 +254,7 @@ func dowidth(t *Type) {
if t.Elem().Width != 0 {
cap := (uint64(Thearch.MAXWIDTH) - 1) / uint64(t.Elem().Width)
if uint64(t.NumElem()) > cap {
- Yyerror("type %v larger than address space", Tconv(t, FmtLong))
+ yyerror("type %L larger than address space", t)
}
}
w = t.NumElem() * t.Elem().Width
@@ -295,7 +296,7 @@ func dowidth(t *Type) {
}
if Widthptr == 4 && w != int64(int32(w)) {
- Yyerror("type %v too large", t)
+ yyerror("type %v too large", t)
}
t.Width = w
@@ -378,22 +379,3 @@ func resumecheckwidth() {
defercalc = 0
}
-
-// compute total size of f's in/out arguments.
-func Argsize(t *Type) int {
- var w int64
-
- for _, p := range recvsParamsResults {
- for _, f := range p(t).Fields().Slice() {
- if x := f.End(); x > w {
- w = x
- }
- }
- }
-
- w = Rnd(w, int64(Widthptr))
- if int64(int(w)) != w {
- Fatalf("argsize too big")
- }
- return int(w)
-}
diff --git a/src/cmd/compile/internal/gc/asm_test.go b/src/cmd/compile/internal/gc/asm_test.go
index 21b5910..2e5d7e7 100644
--- a/src/cmd/compile/internal/gc/asm_test.go
+++ b/src/cmd/compile/internal/gc/asm_test.go
@@ -20,8 +20,10 @@ import (
// TestAssembly checks to make sure the assembly generated for
// functions contains certain expected instructions.
-// Note: this test will fail if -ssa=0.
func TestAssembly(t *testing.T) {
+ 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.
@@ -34,7 +36,7 @@ func TestAssembly(t *testing.T) {
defer os.RemoveAll(dir)
for _, test := range asmTests {
- asm := compileToAsm(dir, test.arch, fmt.Sprintf(template, test.function))
+ 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]
@@ -49,7 +51,7 @@ func TestAssembly(t *testing.T) {
// compile compiles the package pkg for architecture arch and
// returns the generated assembly. dir is a scratch directory.
-func compileToAsm(dir, arch, pkg string) string {
+func compileToAsm(t *testing.T, dir, goarch, goos, pkg string) string {
// Create source.
src := filepath.Join(dir, "test.go")
f, err := os.Create(src)
@@ -59,9 +61,27 @@ func compileToAsm(dir, arch, pkg string) string {
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("go", "tool", "compile", "-S", "-o", filepath.Join(dir, "out.o"), src)
- cmd.Env = mergeEnvLists([]string{"GOARCH=" + arch}, os.Environ())
+ 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))
+ }
+
+ // 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())
cmd.Stdout = &stdout
cmd.Stderr = &stderr
if err := cmd.Run(); err != nil {
@@ -82,6 +102,8 @@ package main
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
@@ -89,19 +111,100 @@ type asmTest struct {
}
var asmTests = [...]asmTest{
- {"amd64", `
+ {"amd64", "linux", `
func f(x int) int {
return x * 64
}
`,
[]string{"\tSHLQ\t\\$6,"},
},
- {"amd64", `
+ {"amd64", "linux", `
func f(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)
+}
+`,
+ []string{"\tMOVQ\t\\(.*\\),"},
+ },
+ {"amd64", "linux", `
+import "encoding/binary"
+func f(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)
+}
+`,
+ []string{"\tMOVL\t\\(.*\\),"},
+ },
+ {"amd64", "linux", `
+import "encoding/binary"
+func f(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)
+}
+`,
+ []string{"\tBSWAPQ\t"},
+ },
+ {"amd64", "linux", `
+import "encoding/binary"
+func f(b []byte, i int) uint64 {
+ return binary.BigEndian.Uint64(b[i:])
+}
+`,
+ []string{"\tBSWAPQ\t"},
+ },
+ {"amd64", "linux", `
+import "encoding/binary"
+func f(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:])
+}
+`,
+ []string{"\tBSWAPL\t"},
+ },
+ {"386", "linux", `
+import "encoding/binary"
+func f(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:])
+}
+`,
+ []string{"\tMOVL\t\\(.*\\)\\(.*\\*1\\),"},
+ },
}
// mergeEnvLists merges the two environment lists such that
@@ -139,7 +242,7 @@ func TestLineNumber(t *testing.T) {
t.Fatalf("could not write file: %v", err)
}
- cmd := exec.Command("go", "tool", "compile", "-S", "-o", filepath.Join(dir, "out.o"), src)
+ cmd := exec.Command(testenv.GoToolPath(t), "tool", "compile", "-S", "-o", filepath.Join(dir, "out.o"), src)
out, err := cmd.CombinedOutput()
if err != nil {
t.Fatalf("fail to run go tool compile: %v", err)
diff --git a/src/cmd/compile/internal/gc/bexport.go b/src/cmd/compile/internal/gc/bexport.go
index 38e035e..1da5b69 100644
--- a/src/cmd/compile/internal/gc/bexport.go
+++ b/src/cmd/compile/internal/gc/bexport.go
@@ -3,16 +3,17 @@
// license that can be found in the LICENSE file.
// Binary package export.
-// (see fmt.go, parser.go as "documentation" for how to use/setup data structures)
/*
1) Export data encoding principles:
The export data is a serialized description of the graph of exported
-"objects": constants, types, variables, and functions. In general,
-types - but also objects referred to from inlined function bodies -
-can be reexported and so we need to know which package they are coming
-from. Therefore, packages are also part of the export graph.
+"objects": constants, types, variables, and functions. Aliases may be
+directly reexported, and unaliased types may be indirectly reexported
+(as part of the type of a directly exported object). More generally,
+objects referred to from inlined function bodies can be reexported.
+We need to know which package declares these reexported objects, and
+therefore packages are also part of the export graph.
The roots of the graph are two lists of objects. The 1st list (phase 1,
see Export) contains all objects that are exported at the package level.
@@ -30,9 +31,9 @@ function bodies. The format of this representation is compiler specific.
The graph is serialized in in-order fashion, starting with the roots.
Each object in the graph is serialized by writing its fields sequentially.
-If the field is a pointer to another object, that object is serialized,
-recursively. Otherwise the field is written. Non-pointer fields are all
-encoded as integer or string values.
+If the field is a pointer to another object, that object is serialized in
+place, recursively. Otherwise the field is written in place. Non-pointer
+fields are all encoded as integer or string values.
Some objects (packages, types) may be referred to more than once. When
reaching an object that was not serialized before, an integer _index_
@@ -43,7 +44,7 @@ If the object was already serialized, the encoding is simply the object
index >= 0. An importer can trivially determine if an object needs to
be read in for the first time (tag < 0) and entered into the respective
object table, or if the object was seen already (index >= 0), in which
-case the index is used to look up the object in a table.
+case the index is used to look up the object in the respective table.
Before exporting or importing, the type tables are populated with the
predeclared types (int, string, error, unsafe.Pointer, etc.). This way
@@ -51,13 +52,16 @@ they are automatically encoded with a known and fixed type index.
2) Encoding format:
-The export data starts with a single byte indicating the encoding format
-(compact, or with debugging information), followed by a version string
-(so we can evolve the encoding if need be), and then the package object
-for the exported package (with an empty path).
+The export data starts with two newline-terminated strings: a version
+string and either an empty string, or "debug", when emitting the debug
+format. These strings are followed by version-specific encoding options.
-After this header, two lists of objects and the list of inlined function
-bodies follows.
+(The Go1.7 version starts with a couple of bytes specifying the format.
+That format encoding is no longer used but is supported to avoid spurious
+errors when importing old installed package files.)
+
+This header is followed by the package object for the exported package,
+two lists of objects, and the list of inlined function bodies.
The encoding of objects is straight-forward: Constants, variables, and
functions start with their name, type, and possibly a value. Named types
@@ -66,6 +70,9 @@ same type was imported before via another import, the importer must use
the previously imported type pointer so that we have exactly one version
(i.e., one pointer) for each named type (and read but discard the current
type encoding). Unnamed types simply encode their respective fields.
+Aliases are encoded starting with their name followed by the qualified
+identifier denoting the original (aliased) object, which was exported
+earlier.
In the encoding, some lists start with the list length. Some lists are
terminated with an end marker (usually for lists where we may not know
@@ -77,7 +84,8 @@ Strings are canonicalized similar to objects that may occur multiple times:
If the string was exported already, it is represented by its index only.
Otherwise, the export data starts with the negative string length (negative,
so we can distinguish from string index), followed by the string bytes.
-The empty string is mapped to index 0.
+The empty string is mapped to index 0. (The initial format string is an
+exception; it is encoded as the string bytes followed by a newline).
The exporter and importer are completely symmetric in implementation: For
each encoding routine there is a matching and symmetric decoding routine.
@@ -97,30 +105,8 @@ compatibility with both the last release of the compiler, and with the
corresponding compiler at tip. That change is necessarily more involved,
as it must switch based on the version number in the export data file.
-It is recommended to turn on debugFormat when working on format changes
-as it will help finding encoding/decoding inconsistencies quickly.
-
-Special care must be taken to update builtin.go when the export format
-changes: builtin.go contains the export data obtained by compiling the
-builtin/runtime.go and builtin/unsafe.go files; those compilations in
-turn depend on importing the data in builtin.go. Thus, when the export
-data format changes, the compiler must be able to import the data in
-builtin.go even if its format has not yet changed. Proceed in several
-steps as follows:
-
-- Change the exporter to use the new format, and use a different version
- string as well.
-- Update the importer accordingly, but accept both the old and the new
- format depending on the version string.
-- all.bash should pass at this point.
-- Run mkbuiltin.go: this will create a new builtin.go using the new
- export format.
-- go test -run Builtin should pass at this point.
-- Remove importer support for the old export format and (maybe) revert
- the version string again (it's only needed to mark the transition).
-- all.bash should still pass.
-
-Don't forget to set debugFormat to false.
+It is recommended to turn on debugFormat temporarily when working on format
+changes as it will help finding encoding/decoding inconsistencies quickly.
*/
package gc
@@ -128,9 +114,9 @@ package gc
import (
"bufio"
"bytes"
- "cmd/compile/internal/big"
"encoding/binary"
"fmt"
+ "math/big"
"sort"
"strings"
)
@@ -153,13 +139,12 @@ const debugFormat = false // default: false
// TODO(gri) disable and remove once there is only one export format again
const forceObjFileStability = true
-// Supported export format versions.
-// TODO(gri) Make this more systematic (issue #16244).
-const (
- exportVersion0 = "v0"
- exportVersion1 = "v1"
- exportVersion = exportVersion1
-)
+// Current export format version. Increase with each format change.
+// 3: added aliasTag and export of aliases
+// 2: removed unused bool in ODCL export
+// 1: header format change (more regular), export package for _ struct fields
+// 0: Go1.7 encoding
+const exportVersion = 3
// exportInlined enables the export of inlined function bodies and related
// dependencies. The compiler should work w/o any loss of functionality with
@@ -174,8 +159,8 @@ const exportInlined = true // default: true
// errors.
// If disabled, only named types are tracked, possibly leading to slightly
// less efficient encoding in rare cases. It also prevents the export of
-// some corner-case type declarations (but those are not handled correctly
-// with with the textual export format either).
+// 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
const trackAllTypes = false
@@ -197,59 +182,37 @@ 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.
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),
- // don't emit pos info for builtin packages
- // (not needed and avoids path name diffs in builtin.go between
- // Windows and non-Windows machines, exposed via builtin_test.go)
- posInfoFormat: Debug['A'] == 0,
+ out: out,
+ strIndex: map[string]int{"": 0}, // empty string is mapped to 0
+ pkgIndex: make(map[*Pkg]int),
+ typIndex: make(map[*Type]int),
+ posInfoFormat: true,
trace: trace,
}
- // TODO(gri) clean up the ad-hoc encoding of the file format below
- // (we need this so we can read the builtin package export data
- // easily w/o being affected by format changes)
-
- // first byte indicates low-level encoding format
- var format byte = 'c' // compact
+ // write version info
+ // The version string must start with "version %d" where %d is the version
+ // number. Additional debugging information may follow after a blank; that
+ // text is ignored by the importer.
+ p.rawStringln(fmt.Sprintf("version %d", exportVersion))
+ var debug string
if debugFormat {
- format = 'd'
- }
- p.rawByte(format)
-
- format = 'n' // track named types only
- if trackAllTypes {
- format = 'a'
+ debug = "debug"
}
- p.rawByte(format)
-
- // posInfo exported or not?
+ p.rawStringln(debug) // cannot use p.bool since it's affected by debugFormat; also want to see this clearly
+ p.bool(trackAllTypes)
p.bool(p.posInfoFormat)
// --- generic export data ---
- if p.trace {
- p.tracef("\n--- package ---\n")
- if p.indent != 0 {
- Fatalf("exporter: incorrect indentation %d", p.indent)
- }
- }
-
- if p.trace {
- p.tracef("version = ")
- }
- p.string(exportVersion)
- if p.trace {
- p.tracef("\n")
- }
-
// populate type map with predeclared "known" types
predecl := predeclared()
for index, typ := range predecl {
@@ -343,7 +306,6 @@ func export(out *bufio.Writer, trace bool) int {
}
// write compiler-specific flags
- p.bool(safemode)
if p.trace {
p.tracef("\n")
}
@@ -388,6 +350,11 @@ func export(out *bufio.Writer, trace bool) int {
if p.trace {
p.tracef("\n")
}
+
+ if sym.Flags&SymAlias != 0 {
+ Fatalf("exporter: unexpected alias %v in inlined function body", sym)
+ }
+
p.obj(sym)
objcount++
}
@@ -417,7 +384,7 @@ func export(out *bufio.Writer, trace bool) int {
// function has inlineable body:
// write index and body
if p.trace {
- p.tracef("\n----\nfunc { %s }\n", hconv(f.Inl, FmtSharp))
+ p.tracef("\n----\nfunc { %#v }\n", f.Inl)
}
p.int(i)
p.stmtList(f.Inl)
@@ -479,16 +446,41 @@ func unidealType(typ *Type, val Val) *Type {
}
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)
+ }
+
// Exported objects may be from different packages because they
- // may be re-exported as depencies when exporting inlined function
- // bodies. Thus, exported object names must be fully qualified.
+ // may be re-exported via an exported alias or as dependencies in
+ // exported inlined function bodies. Thus, exported object names
+ // must be fully qualified.
//
- // TODO(gri) This can only happen if exportInlined is enabled
- // (default), and during phase 2 of object export. Objects exported
- // in phase 1 (compiler-indendepent objects) are by definition only
- // the objects from the current package and not pulled in via inlined
- // function bodies. In that case the package qualifier is not needed.
- // Possible space optimization.
+ // (This can only happen for aliased objects or during phase 2
+ // (exportInlined enabled) of object export. Unaliased Objects
+ // exported in phase 1 (compiler-indendepent objects) are by
+ // definition only the objects from the current package and not
+ // pulled in via inlined function bodies. In that case the package
+ // qualifier is not needed. Possible space optimization.)
n := sym.Def
switch n.Op {
@@ -732,14 +724,7 @@ func (p *exporter) typ(t *Type) {
p.paramList(sig.Recvs(), inlineable)
p.paramList(sig.Params(), inlineable)
p.paramList(sig.Results(), inlineable)
-
- // for issue #16243
- // We make this conditional for 1.7 to avoid consistency problems
- // with installed packages compiled with an older version.
- // TODO(gri) Clean up after 1.7 is out (issue #16244)
- if exportVersion == exportVersion1 {
- p.bool(m.Nointerface)
- }
+ p.bool(m.Nointerface) // record go:nointerface pragma value (see also #16243)
var f *Func
if inlineable {
@@ -790,11 +775,39 @@ 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)
@@ -807,14 +820,11 @@ func (p *exporter) typ(t *Type) {
p.typ(t.Elem())
default:
- Fatalf("exporter: unexpected type: %s (Etype = %d)", Tconv(t, 0), t.Etype)
+ Fatalf("exporter: unexpected type: %v (Etype = %d)", t, t.Etype)
}
}
func (p *exporter) qualifiedName(sym *Sym) {
- if strings.Contains(sym.Name, ".") {
- Fatalf("exporter: invalid symbol name: %s", sym.Name)
- }
p.string(sym.Name)
p.pkg(sym.Pkg)
}
@@ -836,7 +846,7 @@ func (p *exporter) fieldList(t *Type) {
func (p *exporter) field(f *Field) {
p.pos(f.Nname)
- p.fieldName(f.Sym, f)
+ p.fieldName(f)
p.typ(f.Type)
p.string(f.Note)
}
@@ -858,37 +868,24 @@ func (p *exporter) methodList(t *Type) {
func (p *exporter) method(m *Field) {
p.pos(m.Nname)
- p.fieldName(m.Sym, m)
+ p.fieldName(m)
p.paramList(m.Type.Params(), false)
p.paramList(m.Type.Results(), false)
}
-// fieldName is like qualifiedName but it doesn't record the package
-// for blank (_) or exported names.
-func (p *exporter) fieldName(sym *Sym, t *Field) {
- if t != nil && sym != t.Sym {
- Fatalf("exporter: invalid fieldName parameters")
- }
-
- name := sym.Name
- if t != nil {
- if t.Embedded == 0 {
- name = sym.Name
- } else if bname := basetypeName(t.Type); bname != "" && !exportname(bname) {
- // anonymous field with unexported base type name: use "?" as field name
- // (bname != "" per spec, but we are conservative in case of errors)
- name = "?"
- } else {
- name = ""
+// fieldName is like qualifiedName but it doesn't record the package for exported names.
+func (p *exporter) fieldName(t *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
}
}
-
- if strings.Contains(name, ".") {
- Fatalf("exporter: invalid symbol name: %s", name)
- }
p.string(name)
- if name == "?" || name != "_" && name != "" && !exportname(name) {
- p.pkg(sym.Pkg)
+ if name != "" && !exportname(name) {
+ p.pkg(t.Sym.Pkg)
}
}
@@ -897,10 +894,8 @@ func basetypeName(t *Type) string {
if s == nil && t.IsPtr() {
s = t.Elem().Sym // deref
}
+ // s should exist, but be conservative
if s != nil {
- if strings.Contains(s.Name, ".") {
- Fatalf("exporter: invalid symbol name: %s", s.Name)
- }
return s.Name
}
return ""
@@ -1034,7 +1029,7 @@ func (p *exporter) value(x Val) {
p.tag(tag)
case *Mpint:
- if Minintval[TINT64].Cmp(x) <= 0 && x.Cmp(Maxintval[TINT64]) <= 0 {
+ if minintval[TINT64].Cmp(x) <= 0 && x.Cmp(maxintval[TINT64]) <= 0 {
// common case: x fits into an int64 - use compact encoding
p.tag(int64Tag)
p.int64(x.Int64())
@@ -1172,8 +1167,8 @@ func (p *exporter) elemList(list Nodes) {
if p.trace {
p.tracef("\n")
}
- p.fieldSym(n.Left.Sym, false)
- p.expr(n.Right)
+ p.fieldSym(n.Sym, false)
+ p.expr(n.Left)
}
}
@@ -1206,9 +1201,6 @@ func (p *exporter) expr(n *Node) {
// case ODDDARG:
// unimplemented - handled by default case
- // case OREGISTER:
- // unimplemented - handled by default case
-
case OLITERAL:
if n.Val().Ctype() == CTNIL && n.Orig != nil && n.Orig != n {
p.expr(n.Orig)
@@ -1276,7 +1268,7 @@ func (p *exporter) expr(n *Node) {
p.typ(n.Type)
p.elemList(n.List) // special handling of field names
- case OARRAYLIT, OMAPLIT:
+ case OARRAYLIT, OSLICELIT, OMAPLIT:
p.op(OCOMPLIT)
p.typ(n.Type)
p.exprList(n.List)
@@ -1285,6 +1277,9 @@ func (p *exporter) expr(n *Node) {
p.op(OKEY)
p.exprsOrNil(n.Left, n.Right)
+ // case OSTRUCTKEY:
+ // unreachable - handled in case OSTRUCTLIT by elemList
+
// case OCALLPART:
// unimplemented - handled by default case
@@ -1405,8 +1400,8 @@ func (p *exporter) expr(n *Node) {
p.op(ODCLCONST)
default:
- Fatalf("cannot export %s (%d) node\n"+
- "==> please file an issue and assign to gri@\n", n.Op, n.Op)
+ Fatalf("cannot export %v (%d) node\n"+
+ "==> please file an issue and assign to gri@\n", n.Op, int(n.Op))
}
}
@@ -1436,17 +1431,7 @@ func (p *exporter) stmt(n *Node) {
switch op := n.Op; op {
case ODCL:
p.op(ODCL)
- switch n.Left.Class {
- case PPARAM, PPARAMOUT, PAUTO, PAUTOHEAP:
- // TODO(gri) when is this not PAUTO?
- // Also, originally this didn't look like
- // the default case. Investigate.
- fallthrough
- default:
- // TODO(gri) Can we ever reach here?
- p.bool(false)
- p.sym(n.Left)
- }
+ p.sym(n.Left)
p.typ(n.Left.Type)
// case ODCLFIELD:
@@ -1531,7 +1516,7 @@ func (p *exporter) stmt(n *Node) {
p.expr(n.Left)
default:
- Fatalf("exporter: CANNOT EXPORT: %s\nPlease notify gri@\n", n.Op)
+ Fatalf("exporter: CANNOT EXPORT: %v\nPlease notify gri@\n", n.Op)
}
}
@@ -1623,7 +1608,7 @@ func (p *exporter) bool(b bool) bool {
func (p *exporter) op(op Op) {
if p.trace {
p.tracef("[")
- defer p.tracef("= %s] ", op)
+ defer p.tracef("= %v] ", op)
}
p.int(int(op))
@@ -1706,7 +1691,7 @@ func (p *exporter) marker(m byte) {
p.rawInt64(int64(p.written))
}
-// rawInt64 should only be used by low-level encoders
+// rawInt64 should only be used by low-level encoders.
func (p *exporter) rawInt64(x int64) {
var tmp [binary.MaxVarintLen64]byte
n := binary.PutVarint(tmp[:], x)
@@ -1715,6 +1700,14 @@ func (p *exporter) rawInt64(x int64) {
}
}
+// rawStringln should only be used to emit the initial version string.
+func (p *exporter) rawStringln(s string) {
+ for i := 0; i < len(s); i++ {
+ p.rawByte(s[i])
+ }
+ p.rawByte('\n')
+}
+
// rawByte is the bottleneck interface to write to p.out.
// rawByte escapes b as follows (any encoding does that
// hides '$'):
@@ -1803,6 +1796,9 @@ const (
stringTag
nilTag
unknownTag // not used by gc (only appears in packages with errors)
+
+ // Aliases
+ aliasTag
)
// Debugging support.
@@ -1838,6 +1834,9 @@ var tagString = [...]string{
-stringTag: "string",
-nilTag: "nil",
-unknownTag: "unknown",
+
+ // Aliases
+ -aliasTag: "alias",
}
// untype returns the "pseudo" untyped type for a Ctype (import/export use only).
diff --git a/src/cmd/compile/internal/gc/bimport.go b/src/cmd/compile/internal/gc/bimport.go
index 2b666cc..1d66841 100644
--- a/src/cmd/compile/internal/gc/bimport.go
+++ b/src/cmd/compile/internal/gc/bimport.go
@@ -10,9 +10,11 @@ package gc
import (
"bufio"
- "cmd/compile/internal/big"
"encoding/binary"
"fmt"
+ "math/big"
+ "strconv"
+ "strings"
)
// The overall structure of Import is symmetric to Export: For each
@@ -23,7 +25,7 @@ import (
type importer struct {
in *bufio.Reader
buf []byte // reused for reading strings
- version string
+ version int // export format version
// object lists, in order of deserialization
strList []string
@@ -49,30 +51,56 @@ type importer struct {
func Import(in *bufio.Reader) {
p := importer{
in: in,
+ version: -1, // unknown version
strList: []string{""}, // empty string is mapped to 0
}
- // read low-level encoding format
- switch format := p.rawByte(); format {
- case 'c':
- // compact format - nothing to do
- case 'd':
- p.debugFormat = true
- default:
- Fatalf("importer: invalid encoding format in export data: got %q; want 'c' or 'd'", format)
+ // read version info
+ var versionstr string
+ if b := p.rawByte(); b == 'c' || b == 'd' {
+ // Go1.7 encoding; first byte encodes low-level
+ // encoding format (compact vs debug).
+ // For backward-compatibility only (avoid problems with
+ // old installed packages). Newly compiled packages use
+ // the extensible format string.
+ // TODO(gri) Remove this support eventually; after Go1.8.
+ if b == 'd' {
+ p.debugFormat = true
+ }
+ p.trackAllTypes = p.rawByte() == 'a'
+ p.posInfoFormat = p.bool()
+ versionstr = p.string()
+ if versionstr == "v1" {
+ p.version = 0
+ }
+ } else {
+ // Go1.8 extensible encoding
+ // read version string and extract version number (ignore anything after the version number)
+ versionstr = p.rawStringln(b)
+ if s := strings.SplitN(versionstr, " ", 3); len(s) >= 2 && s[0] == "version" {
+ if v, err := strconv.Atoi(s[1]); err == nil && v > 0 {
+ p.version = v
+ }
+ }
}
- p.trackAllTypes = p.rawByte() == 'a'
-
- p.posInfoFormat = p.bool()
+ // read version specific flags - extend as necessary
+ switch p.version {
+ // case 4:
+ // ...
+ // fallthrough
+ case 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)
+ }
// --- generic export data ---
- p.version = p.string()
- if p.version != exportVersion0 && p.version != exportVersion1 {
- Fatalf("importer: unknown export data version: %s", p.version)
- }
-
// populate typList with predeclared "known" types
p.typList = append(p.typList, predeclared()...)
@@ -80,7 +108,6 @@ func Import(in *bufio.Reader) {
p.pkg()
// defer some type-checking until all types are read in completely
- // (parser.go:import_package)
tcok := typecheckok
typecheckok = true
defercheckwidth()
@@ -100,16 +127,13 @@ func Import(in *bufio.Reader) {
// self-verification
if count := p.int(); count != objcount {
- Fatalf("importer: got %d objects; want %d", objcount, count)
+ formatErrorf("got %d objects; want %d", objcount, count)
}
// --- compiler-specific export data ---
// read compiler-specific flags
- // read but ignore safemode bit (see issue #15772)
- p.bool() // formerly: importpkg.Safe = p.bool()
-
// phase 2
objcount = 0
for {
@@ -123,12 +147,12 @@ func Import(in *bufio.Reader) {
// self-verification
if count := p.int(); count != objcount {
- Fatalf("importer: got %d objects; want %d", objcount, count)
+ formatErrorf("got %d objects; want %d", objcount, count)
}
// read inlineable functions bodies
if dclcontext != PEXTERN {
- Fatalf("importer: unexpected context %d", dclcontext)
+ formatErrorf("unexpected context %d", dclcontext)
}
objcount = 0
@@ -140,12 +164,12 @@ func Import(in *bufio.Reader) {
// don't process the same function twice
if i <= i0 {
- Fatalf("importer: index not increasing: %d <= %d", i, i0)
+ formatErrorf("index not increasing: %d <= %d", i, i0)
}
i0 = i
- if Funcdepth != 0 {
- Fatalf("importer: unexpected Funcdepth %d", Funcdepth)
+ if funcdepth != 0 {
+ formatErrorf("unexpected Funcdepth %d", funcdepth)
}
// Note: In the original code, funchdr and funcbody are called for
@@ -163,7 +187,7 @@ func Import(in *bufio.Reader) {
// (not doing so can cause significant performance
// degradation due to unnecessary calls to empty
// functions).
- body = []*Node{Nod(OEMPTY, nil, nil)}
+ body = []*Node{nod(OEMPTY, nil, nil)}
}
f.Func.Inl.Set(body)
funcbody(f)
@@ -179,11 +203,11 @@ func Import(in *bufio.Reader) {
// self-verification
if count := p.int(); count != objcount {
- Fatalf("importer: got %d functions; want %d", objcount, count)
+ formatErrorf("got %d functions; want %d", objcount, count)
}
if dclcontext != PEXTERN {
- Fatalf("importer: unexpected context %d", dclcontext)
+ formatErrorf("unexpected context %d", dclcontext)
}
p.verifyTypes()
@@ -196,19 +220,32 @@ func Import(in *bufio.Reader) {
testdclstack() // debugging only
}
+func 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...))
+ errorexit()
+}
+
func (p *importer) verifyTypes() {
for _, pair := range p.cmpList {
pt := pair.pt
t := pair.t
- if !Eqtype(pt.Orig, t) {
- // TODO(gri) Is this a possible regular error (stale files)
- // or can this only happen if export/import is flawed?
- // (if the latter, change to Fatalf here)
- Yyerror("inconsistent definition for type %v during import\n\t%v (in %q)\n\t%v (in %q)", pt.Sym, Tconv(pt, FmtLong), pt.Sym.Importdef.Path, Tconv(t, FmtLong), importpkg.Path)
+ 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)
}
}
}
+// numImport tracks how often a package with a given name is imported.
+// It is used to provide a better error message (by using the package
+// path to disambiguate) if a package that appears multiple times with
+// the same name appears in an error message.
+var numImport = make(map[string]int)
+
func (p *importer) pkg() *Pkg {
// if the package was seen before, i is its index (>= 0)
i := p.tagOrIndex()
@@ -218,7 +255,7 @@ func (p *importer) pkg() *Pkg {
// otherwise, i is the package tag (< 0)
if i != packageTag {
- Fatalf("importer: expected package tag, found tag = %d", i)
+ formatErrorf("expected package tag, found tag = %d", i)
}
// read package data
@@ -227,21 +264,21 @@ func (p *importer) pkg() *Pkg {
// we should never see an empty package name
if name == "" {
- Fatalf("importer: empty package name for path %q", path)
+ formatErrorf("empty package name for path %q", path)
}
// we should never see a bad import path
if isbadimport(path) {
- Fatalf("importer: bad package path %q for package %s", path, name)
+ 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) {
- Fatalf("importer: package path %q for pkg index %d", path, len(p.pkgList))
+ formatErrorf("package path %q for pkg index %d", path, len(p.pkgList))
}
- // see importimport (export.go)
+ // add package to pkgList
pkg := importpkg
if path != "" {
pkg = mkpkg(path)
@@ -250,10 +287,10 @@ func (p *importer) pkg() *Pkg {
pkg.Name = name
numImport[name]++
} else if pkg.Name != name {
- Yyerror("importer: conflicting package names %s and %s for path %q", pkg.Name, name, path)
+ yyerror("conflicting package names %s and %s for path %q", pkg.Name, name, path)
}
- if incannedimport == 0 && myimportpath != "" && path == myimportpath {
- Yyerror("import %q: package depends on %q (import cycle)", importpkg.Path, path)
+ if myimportpath != "" && path == myimportpath {
+ yyerror("import %q: package depends on %q (import cycle)", importpkg.Path, path)
errorexit()
}
p.pkgList = append(p.pkgList, pkg)
@@ -293,12 +330,12 @@ func (p *importer) obj(tag int) {
params := p.paramList()
result := p.paramList()
- sig := functype(nil, params, result)
+ sig := functypefield(nil, params, result)
importsym(sym, ONAME)
if sym.Def != nil && sym.Def.Op == ONAME {
// function was imported before (via another import)
- if !Eqtype(sig, sym.Def.Type) {
- Fatalf("importer: inconsistent definition for func %v during import\n\t%v\n\t%v", sym, sym.Def.Type, sig)
+ 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)
}
p.funcList = append(p.funcList, nil)
break
@@ -317,8 +354,19 @@ func (p *importer) obj(tag int) {
}
}
+ 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:
- Fatalf("importer: unexpected object (tag = %d)", tag)
+ formatErrorf("unexpected object (tag = %d)", tag)
}
}
@@ -351,35 +399,29 @@ func (p *importer) newtyp(etype EType) *Type {
return t
}
-// This is like the function importtype but it delays the
-// type identity check for types that have been seen already.
-// importer.importtype and importtype and (export.go) need to
-// remain in sync.
+// importtype declares that pt, an imported named type, has underlying type t.
func (p *importer) importtype(pt, t *Type) {
- // override declaration in unsafe.go for Pointer.
- // there is no way in Go code to define unsafe.Pointer
- // so we have to supply it.
- if incannedimport != 0 && importpkg.Name == "unsafe" && pt.Nod.Sym.Name == "Pointer" {
- t = Types[TUNSAFEPTR]
- }
-
if pt.Etype == TFORW {
- n := pt.Nod
- copytype(pt.Nod, t)
- pt.Nod = n // unzero nod
+ n := pt.nod
+ copytype(pt.nod, t)
+ pt.nod = n // unzero nod
pt.Sym.Importdef = importpkg
pt.Sym.Lastlineno = lineno
declare(n, PEXTERN)
checkwidth(pt)
} else {
- // pt.Orig and t must be identical. Since t may not be
- // fully set up yet, collect the types and verify identity
- // later.
- p.cmpList = append(p.cmpList, struct{ pt, t *Type }{pt, t})
+ // 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})
+ } 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)
+ }
}
if Debug['E'] != 0 {
- fmt.Printf("import type %v %v\n", pt, Tconv(t, FmtLong))
+ fmt.Printf("import type %v %L\n", pt, t)
}
}
@@ -394,24 +436,15 @@ func (p *importer) typ() *Type {
var t *Type
switch i {
case namedTag:
- // parser.go:hidden_importsym
p.pos()
tsym := p.qualifiedName()
- // parser.go:hidden_pkgtype
t = pkgtype(tsym)
p.typList = append(p.typList, t)
// read underlying type
- // parser.go:hidden_type
t0 := p.typ()
- if p.trackAllTypes {
- // If we track all types, we cannot check equality of previously
- // imported types until later. Use customized version of importtype.
- p.importtype(t, t0)
- } else {
- importtype(t, t0)
- }
+ p.importtype(t, t0)
// interfaces don't have associated methods
if t0.IsInterface() {
@@ -425,24 +458,30 @@ func (p *importer) typ() *Type {
// read associated methods
for i := p.int(); i > 0; i-- {
- // parser.go:hidden_fndcl
-
p.pos()
sym := p.fieldSym()
+ // during import unexported method names should be in the type's package
+ if !exportname(sym.Name) && sym.Pkg != tsym.Pkg {
+ Fatalf("imported method name %+v in wrong package %s\n", sym, tsym.Pkg.Name)
+ }
+
recv := p.paramList() // TODO(gri) do we need a full param list for the receiver?
params := p.paramList()
result := p.paramList()
+ nointerface := p.bool()
- nointerface := false
- if p.version == exportVersion1 {
- nointerface = p.bool()
+ base := recv[0].Type
+ star := false
+ if base.IsPtr() {
+ base = base.Elem()
+ star = true
}
- n := methodname1(newname(sym), recv[0].Right)
- n.Type = functype(recv[0], params, result)
+ n := methodname0(sym, star, base.Sym)
+ n.Type = functypefield(recv[0], params, result)
checkwidth(n.Type)
- addmethod(sym, n.Type, tsym.Pkg, false, nointerface)
+ addmethod(sym, n.Type, false, nointerface)
p.funcList = append(p.funcList, n)
importlist = append(importlist, n)
@@ -480,7 +519,8 @@ func (p *importer) typ() *Type {
case structTag:
t = p.newtyp(TSTRUCT)
- tostruct0(t, p.fieldList())
+ t.SetFields(p.fieldList())
+ checkwidth(t)
case pointerTag:
t = p.newtyp(Tptr)
@@ -490,14 +530,15 @@ func (p *importer) typ() *Type {
t = p.newtyp(TFUNC)
params := p.paramList()
result := p.paramList()
- functype0(t, nil, params, result)
+ functypefield0(t, nil, params, result)
case interfaceTag:
t = p.newtyp(TINTER)
if p.int() != 0 {
- Fatalf("importer: unexpected embedded interface")
+ formatErrorf("unexpected embedded interface")
}
- tointerface0(t, p.methodList())
+ t.SetFields(p.methodList())
+ checkwidth(t)
case mapTag:
t = p.newtyp(TMAP)
@@ -512,11 +553,11 @@ func (p *importer) typ() *Type {
ct.Elem = p.typ()
default:
- Fatalf("importer: unexpected type (tag = %d)", i)
+ formatErrorf("unexpected type (tag = %d)", i)
}
if t == nil {
- Fatalf("importer: nil type (type tag = %d)", i)
+ formatErrorf("nil type (type tag = %d)", i)
}
return t
@@ -528,10 +569,9 @@ func (p *importer) qualifiedName() *Sym {
return pkg.Lookup(name)
}
-// parser.go:hidden_structdcl_list
-func (p *importer) fieldList() (fields []*Node) {
+func (p *importer) fieldList() (fields []*Field) {
if n := p.int(); n > 0 {
- fields = make([]*Node, n)
+ fields = make([]*Field, n)
for i := range fields {
fields[i] = p.field()
}
@@ -539,38 +579,34 @@ func (p *importer) fieldList() (fields []*Node) {
return
}
-// parser.go:hidden_structdcl
-func (p *importer) field() *Node {
+func (p *importer) field() *Field {
p.pos()
sym := p.fieldName()
typ := p.typ()
note := p.string()
- var n *Node
- if sym.Name != "" {
- n = Nod(ODCLFIELD, newname(sym), typenod(typ))
- } else {
+ f := newField()
+ if sym.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
}
- pkg := importpkg
- if sym != nil {
- pkg = sym.Pkg
- }
- n = embedded(s, pkg)
- n.Right = typenod(typ)
+ sym = sym.Pkg.Lookup(s.Name)
+ f.Embedded = 1
}
- n.SetVal(Val{U: note})
- return n
+ f.Sym = sym
+ f.Nname = newname(sym)
+ f.Type = typ
+ f.Note = note
+
+ return f
}
-// parser.go:hidden_interfacedcl_list
-func (p *importer) methodList() (methods []*Node) {
+func (p *importer) methodList() (methods []*Field) {
if n := p.int(); n > 0 {
- methods = make([]*Node, n)
+ methods = make([]*Field, n)
for i := range methods {
methods[i] = p.method()
}
@@ -578,25 +614,28 @@ func (p *importer) methodList() (methods []*Node) {
return
}
-// parser.go:hidden_interfacedcl
-func (p *importer) method() *Node {
+func (p *importer) method() *Field {
p.pos()
sym := p.fieldName()
params := p.paramList()
result := p.paramList()
- return Nod(ODCLFIELD, newname(sym), typenod(functype(fakethis(), params, result)))
+
+ f := newField()
+ f.Sym = sym
+ f.Nname = newname(sym)
+ f.Type = functypefield(fakethisfield(), params, result)
+ return f
}
-// parser.go:sym,hidden_importsym
func (p *importer) fieldName() *Sym {
name := p.string()
+ if p.version == 0 && name == "_" {
+ // version 0 didn't export a package for _ fields
+ // but used the builtin package instead
+ return builtinpkg.Lookup(name)
+ }
pkg := localpkg
- if name == "_" {
- // During imports, unqualified non-exported identifiers are from builtinpkg
- // (see parser.go:sym). The binary exporter only exports blank as a non-exported
- // identifier without qualification.
- pkg = builtinpkg
- } else if name == "?" || name != "" && !exportname(name) {
+ if name != "" && !exportname(name) {
if name == "?" {
name = ""
}
@@ -605,8 +644,7 @@ func (p *importer) fieldName() *Sym {
return pkg.Lookup(name)
}
-// parser.go:ohidden_funarg_list
-func (p *importer) paramList() []*Node {
+func (p *importer) paramList() []*Field {
i := p.int()
if i == 0 {
return nil
@@ -618,31 +656,26 @@ func (p *importer) paramList() []*Node {
named = false
}
// i > 0
- n := make([]*Node, i)
- for i := range n {
- n[i] = p.param(named)
+ fs := make([]*Field, i)
+ for i := range fs {
+ fs[i] = p.param(named)
}
- return n
+ return fs
}
-// parser.go:hidden_funarg
-func (p *importer) param(named bool) *Node {
- typ := p.typ()
-
- isddd := false
- if typ.Etype == TDDDFIELD {
+func (p *importer) param(named bool) *Field {
+ f := newField()
+ f.Type = p.typ()
+ if f.Type.Etype == TDDDFIELD {
// TDDDFIELD indicates wrapped ... slice type
- typ = typSlice(typ.DDDField())
- isddd = true
+ f.Type = typSlice(f.Type.DDDField())
+ f.Isddd = true
}
- n := Nod(ODCLFIELD, nil, typenod(typ))
- n.Isddd = isddd
-
if named {
name := p.string()
if name == "" {
- Fatalf("importer: expected named parameter")
+ formatErrorf("expected named parameter")
}
// TODO(gri) Supply function/method package rather than
// encoding the package for each parameter repeatedly.
@@ -650,14 +683,15 @@ func (p *importer) param(named bool) *Node {
if name != "_" {
pkg = p.pkg()
}
- n.Left = newname(pkg.Lookup(name))
+ f.Sym = pkg.Lookup(name)
+ f.Nname = newname(f.Sym)
}
// TODO(gri) This is compiler-specific (escape info).
// Move into compiler-specific section eventually?
- n.SetVal(Val{U: p.string()})
+ f.Note = p.string()
- return n
+ return f
}
func (p *importer) value(typ *Type) (x Val) {
@@ -696,18 +730,18 @@ func (p *importer) value(typ *Type) (x Val) {
x.U = p.string()
case unknownTag:
- Fatalf("importer: unknown constant (importing package with errors)")
+ formatErrorf("unknown constant (importing package with errors)")
case nilTag:
x.U = new(NilVal)
default:
- Fatalf("importer: unexpected value tag %d", tag)
+ formatErrorf("unexpected value tag %d", tag)
}
// verify ideal type
if typ.IsUntyped() && untype(x.Ctype()) != typ {
- Fatalf("importer: value %v and type %v don't match", x, typ)
+ formatErrorf("value %v and type %v don't match", x, typ)
}
return
@@ -778,7 +812,8 @@ func (p *importer) elemList() []*Node {
c := p.int()
list := make([]*Node, c)
for i := range list {
- list[i] = Nod(OKEY, mkname(p.fieldSym()), p.expr())
+ s := p.fieldSym()
+ list[i] = nodSym(OSTRUCTKEY, p.expr(), s)
}
return list
}
@@ -801,14 +836,20 @@ func (p *importer) node() *Node {
// case ODDDARG:
// unimplemented
- // case OREGISTER:
- // unimplemented
-
case OLITERAL:
typ := p.typ()
n := nodlit(p.value(typ))
if !typ.IsUntyped() {
- conv := Nod(OCALL, typenod(typ), nil)
+ // 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
+ }
+ conv := nod(OCALL, typenod(typ), nil)
conv.List.Set1(n)
n = conv
}
@@ -837,30 +878,33 @@ func (p *importer) node() *Node {
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 = nod(OIND, n.Right, nil)
n.Right.Implicit = true
} else {
- n = Nod(OADDR, n, nil)
+ n = nod(OADDR, n, nil)
}
}
return n
case OSTRUCTLIT:
- n := Nod(OCOMPLIT, nil, typenod(p.typ()))
+ n := nod(OCOMPLIT, nil, typenod(p.typ()))
n.List.Set(p.elemList()) // special handling of field names
return n
- // case OARRAYLIT, OMAPLIT:
+ // case OARRAYLIT, OSLICELIT, OMAPLIT:
// unreachable - mapped to case OCOMPLIT below by exporter
case OCOMPLIT:
- n := Nod(OCOMPLIT, nil, typenod(p.typ()))
+ n := nod(OCOMPLIT, nil, typenod(p.typ()))
n.List.Set(p.exprList())
return n
case OKEY:
left, right := p.exprsOrNil()
- return Nod(OKEY, left, right)
+ return nod(OKEY, left, right)
+
+ // case OSTRUCTKEY:
+ // unreachable - handled in case OSTRUCTLIT by elemList
// case OCALLPART:
// unimplemented
@@ -870,13 +914,13 @@ func (p *importer) node() *Node {
case OXDOT:
// see parser.new_dotname
- return NodSym(OXDOT, p.expr(), p.fieldSym())
+ return nodSym(OXDOT, p.expr(), p.fieldSym())
// case ODOTTYPE, ODOTTYPE2:
// unreachable - mapped to case ODOTTYPE below by exporter
case ODOTTYPE:
- n := Nod(ODOTTYPE, p.expr(), nil)
+ n := nod(ODOTTYPE, p.expr(), nil)
if p.bool() {
n.Right = p.expr()
} else {
@@ -888,10 +932,10 @@ func (p *importer) node() *Node {
// unreachable - mapped to cases below by exporter
case OINDEX:
- return Nod(op, p.expr(), p.expr())
+ return nod(op, p.expr(), p.expr())
case OSLICE, OSLICE3:
- n := Nod(op, p.expr(), nil)
+ n := nod(op, p.expr(), nil)
low, high := p.exprsOrNil()
var max *Node
if n.Op.IsSlice3() {
@@ -904,7 +948,7 @@ func (p *importer) node() *Node {
// unreachable - mapped to OCONV case below by exporter
case OCONV:
- n := Nod(OCALL, typenod(p.typ()), nil)
+ n := nod(OCALL, typenod(p.typ()), nil)
n.List.Set(p.exprList())
return n
@@ -920,7 +964,7 @@ func (p *importer) node() *Node {
// unreachable - mapped to OCALL case below by exporter
case OCALL:
- n := Nod(OCALL, p.expr(), nil)
+ n := nod(OCALL, p.expr(), nil)
n.List.Set(p.exprList())
n.Isddd = p.bool()
return n
@@ -933,18 +977,18 @@ func (p *importer) node() *Node {
// unary expressions
case OPLUS, OMINUS, OADDR, OCOM, OIND, ONOT, ORECV:
- return Nod(op, p.expr(), nil)
+ return nod(op, p.expr(), nil)
// binary expressions
case OADD, OAND, OANDAND, OANDNOT, ODIV, OEQ, OGE, OGT, OLE, OLT,
OLSH, OMOD, OMUL, ONE, OOR, OOROR, ORSH, OSEND, OSUB, OXOR:
- return Nod(op, p.expr(), p.expr())
+ return nod(op, p.expr(), p.expr())
case OADDSTR:
list := p.exprList()
x := list[0]
for _, y := range list[1:] {
- x = Nod(OADD, x, y)
+ x = nod(OADD, x, y)
}
return x
@@ -953,19 +997,19 @@ func (p *importer) node() *Node {
case ODCLCONST:
// TODO(gri) these should not be exported in the first place
- return Nod(OEMPTY, nil, nil)
+ return nod(OEMPTY, nil, nil)
// --------------------------------------------------------------------
// statements
case ODCL:
- var lhs *Node
- if p.bool() {
- lhs = p.expr()
- } else {
- lhs = dclname(p.sym())
+ if p.version < 2 {
+ // versions 0 and 1 exported a bool here but it
+ // was always false - simply ignore in this case
+ p.bool()
}
- // TODO(gri) avoid list created here!
- return liststmt(variter([]*Node{lhs}, typenod(p.typ()), nil))
+ lhs := dclname(p.sym())
+ typ := typenod(p.typ())
+ return liststmt(variter([]*Node{lhs}, typ, nil)) // TODO(gri) avoid list creation
// case ODCLFIELD:
// unimplemented
@@ -974,14 +1018,14 @@ func (p *importer) node() *Node {
// unreachable - mapped to OAS case below by exporter
case OAS:
- return Nod(OAS, p.expr(), p.expr())
+ return nod(OAS, p.expr(), p.expr())
case OASOP:
- n := Nod(OASOP, nil, nil)
+ n := nod(OASOP, nil, nil)
n.Etype = EType(p.int())
n.Left = p.expr()
if !p.bool() {
- n.Right = Nodintconst(1)
+ n.Right = nodintconst(1)
n.Implicit = true
} else {
n.Right = p.expr()
@@ -992,13 +1036,13 @@ func (p *importer) node() *Node {
// unreachable - mapped to OAS2 case below by exporter
case OAS2:
- n := Nod(OAS2, nil, nil)
+ n := nod(OAS2, nil, nil)
n.List.Set(p.exprList())
n.Rlist.Set(p.exprList())
return n
case ORETURN:
- n := Nod(ORETURN, nil, nil)
+ n := nod(ORETURN, nil, nil)
n.List.Set(p.exprList())
return n
@@ -1006,11 +1050,11 @@ func (p *importer) node() *Node {
// unreachable - generated by compiler for trampolin routines (not exported)
case OPROC, ODEFER:
- return Nod(op, p.expr(), nil)
+ return nod(op, p.expr(), nil)
case OIF:
markdcl()
- n := Nod(OIF, nil, nil)
+ n := nod(OIF, nil, nil)
n.Ninit.Set(p.stmtList())
n.Left = p.expr()
n.Nbody.Set(p.stmtList())
@@ -1020,7 +1064,7 @@ func (p *importer) node() *Node {
case OFOR:
markdcl()
- n := Nod(OFOR, nil, nil)
+ n := nod(OFOR, nil, nil)
n.Ninit.Set(p.stmtList())
n.Left, n.Right = p.exprsOrNil()
n.Nbody.Set(p.stmtList())
@@ -1029,7 +1073,7 @@ func (p *importer) node() *Node {
case ORANGE:
markdcl()
- n := Nod(ORANGE, nil, nil)
+ n := nod(ORANGE, nil, nil)
n.List.Set(p.stmtList())
n.Right = p.expr()
n.Nbody.Set(p.stmtList())
@@ -1038,7 +1082,7 @@ func (p *importer) node() *Node {
case OSELECT, OSWITCH:
markdcl()
- n := Nod(op, nil, nil)
+ n := nod(op, nil, nil)
n.Ninit.Set(p.stmtList())
n.Left, _ = p.exprsOrNil()
n.List.Set(p.stmtList())
@@ -1050,7 +1094,7 @@ func (p *importer) node() *Node {
case OXCASE:
markdcl()
- n := Nod(OXCASE, nil, nil)
+ n := nod(OXCASE, nil, nil)
n.Xoffset = int64(block)
n.List.Set(p.exprList())
// TODO(gri) eventually we must declare variables for type switch
@@ -1063,7 +1107,7 @@ func (p *importer) node() *Node {
// unreachable - mapped to OXFALL case below by exporter
case OXFALL:
- n := Nod(OXFALL, nil, nil)
+ n := nod(OXFALL, nil, nil)
n.Xoffset = int64(block)
return n
@@ -1072,13 +1116,13 @@ func (p *importer) node() *Node {
if left != nil {
left = newname(left.Sym)
}
- return Nod(op, left, nil)
+ return nod(op, left, nil)
// case OEMPTY:
// unreachable - not emitted by exporter
case OGOTO, OLABEL:
- n := Nod(op, newname(p.expr().Sym), nil)
+ n := nod(op, newname(p.expr().Sym), nil)
n.Sym = dclstack // context, for goto restrictions
return n
@@ -1086,14 +1130,14 @@ func (p *importer) node() *Node {
return nil
default:
- Fatalf("cannot import %s (%d) node\n"+
- "==> please file an issue and assign to gri@\n", op, op)
+ Fatalf("cannot import %v (%d) node\n"+
+ "==> please file an issue and assign to gri@\n", op, int(op))
panic("unreachable") // satisfy compiler
}
}
func builtinCall(op Op) *Node {
- return Nod(OCALL, mkname(builtinpkg.Lookup(goopnames[op])), nil)
+ return nod(OCALL, mkname(builtinpkg.Lookup(goopnames[op])), nil)
}
func (p *importer) exprsOrNil() (a, b *Node) {
@@ -1147,7 +1191,7 @@ func (p *importer) tagOrIndex() int {
func (p *importer) int() int {
x := p.int64()
if int64(int(x)) != x {
- Fatalf("importer: exported integer too large")
+ formatErrorf("exported integer too large")
}
return int(x)
}
@@ -1186,24 +1230,34 @@ func (p *importer) string() string {
func (p *importer) marker(want byte) {
if got := p.rawByte(); got != want {
- Fatalf("importer: incorrect marker: got %c; want %c (pos = %d)", got, want, p.read)
+ formatErrorf("incorrect marker: got %c; want %c (pos = %d)", got, want, p.read)
}
pos := p.read
if n := int(p.rawInt64()); n != pos {
- Fatalf("importer: incorrect position: got %d; want %d", n, pos)
+ formatErrorf("incorrect position: got %d; want %d", n, pos)
}
}
-// rawInt64 should only be used by low-level decoders
+// rawInt64 should only be used by low-level decoders.
func (p *importer) rawInt64() int64 {
i, err := binary.ReadVarint(p)
if err != nil {
- Fatalf("importer: read error: %v", err)
+ formatErrorf("read error: %v", err)
}
return i
}
+// rawStringln should only be used to read the initial version string.
+func (p *importer) rawStringln(b byte) string {
+ p.buf = p.buf[:0]
+ for b != '\n' {
+ p.buf = append(p.buf, b)
+ b = p.rawByte()
+ }
+ return string(p.buf)
+}
+
// needed for binary.ReadVarint in rawInt64
func (p *importer) ReadByte() (byte, error) {
return p.rawByte(), nil
@@ -1216,13 +1270,13 @@ func (p *importer) rawByte() byte {
c, err := p.in.ReadByte()
p.read++
if err != nil {
- Fatalf("importer: read error: %v", err)
+ formatErrorf("read error: %v", err)
}
if c == '|' {
c, err = p.in.ReadByte()
p.read++
if err != nil {
- Fatalf("importer: read error: %v", err)
+ formatErrorf("read error: %v", err)
}
switch c {
case 'S':
@@ -1230,7 +1284,7 @@ func (p *importer) rawByte() byte {
case '|':
// nothing to do
default:
- Fatalf("importer: unexpected escape sequence in export data")
+ formatErrorf("unexpected escape sequence in export data")
}
}
return c
diff --git a/src/cmd/compile/internal/gc/builtin.go b/src/cmd/compile/internal/gc/builtin.go
index c1a6418..e02e2fe 100644
--- a/src/cmd/compile/internal/gc/builtin.go
+++ b/src/cmd/compile/internal/gc/builtin.go
@@ -2,109 +2,238 @@
package gc
-const runtimeimport = "" +
- "cn\x00\x03v1\x01\rruntime\x00\t\x11newobject\x00\x02\x17\"\vtyp·2\x00\x00" +
- "\x01\x17:\x00\t\x13panicindex\x00\x00\x00\t\x13panicslice\x00\x00\x00\t\x15pani" +
- "cdivide\x00\x00\x00\t\x15throwreturn\x00\x00\x00\t\x11throwinit\x00\x00\x00" +
- "\t\x11panicwrap\x00\x05 \x00 \x00 \x00\x00\t\rgopanic\x00\x01\x1b\x00\x00\x00\x00\t\x11go" +
- "recover\x00\x01\x17\b\x00\x01\x1b\x00\x00\x00\t\x11printbool\x00\x01\x00\x00\x00\t\x13print" +
- "float\x00\x01\x1a\x00\x00\t\x0fprintint\x00\x01\n\x00\x00\t\x0fprinthex\x00\x01\x14\x00\x00" +
- "\t\x11printuint\x00\x01\x14\x00\x00\t\x17printcomplex\x00\x01\x1e\x00\x00\t\x15pri" +
- "ntstring\x00\x01 \x00\x00\t\x17printpointer\x00\x01:\x00\x00\t\x13printi" +
- "face\x00\x01:\x00\x00\t\x13printeface\x00\x01:\x00\x00\t\x13printslice\x00\x01" +
- ":\x00\x00\t\rprintnl\x00\x00\x00\t\rprintsp\x00\x00\x00\t\x11printlock\x00\x00" +
- "\x00\t\x15printunlock\x00\x00\x00\t\x19concatstring2\x00\x05\x17\x0f@\"\x00 " +
- "\x00 \x00\x01 \x00\t\x19concatstring3\x00\a\x17\x0f@\"\x00 \x00 \x00 \x00\x01 \x00\t\x19c" +
- "oncatstring4\x00\t\x17\x0f@\"\x00 \x00 \x00 \x00 \x00\x01 \x00\t\x19concatst" +
- "ring5\x00\v\x17\x0f@\"\x00 \x00 \x00 \x00 \x00 \x00\x01 \x00\t\x19concatstrings" +
- "\x00\x03\x17\x0f@\"\x00\x11 \x00\x01 \x00\t\x11cmpstring\x00\x03 \x00 \x00\x01\x02\x00\t\x0feqstr" +
- "ing\x00\x03 \x00 \x00\x01\x00\x00\t\x11intstring\x00\x03\x17\x0f\b\"\x00\n\x00\x01 \x00\t!sli" +
- "cebytetostring\x00\x03\x17\x0f@\"\x00\x11\"\x00\x01 \x00\t'slicebyteto" +
- "stringtmp\x00\x01\x11\"\x00\x01 \x00\t!slicerunetostring\x00\x03\x17\x0f" +
- "@\"\x00\x11|S\x00\x01 \x00\t!stringtoslicebyte\x00\x03\x17\x0f@\"\x00 \x00\x01\x11" +
- "\"\x00\t'stringtoslicebytetmp\x00\x01 \x00\x01\x11\"\x00\t!string" +
- "toslicerune\x00\x03\x17\x0f@|S\x00 \x00\x01\x11|S\x00\t\x13stringiter\x00\x03" +
- " \x00\x02\x00\x01\x02\x00\t\x15stringiter2\x00\x03 \x00\x02\x00\x04\x02\rretk·1\x00\x00|S" +
- "\rretv·2\x00\x00\t\x11slicecopy\x00\x06:\tto·2\x00\x00:\tfr·3\x00" +
- "\x00\x16\vwid·4\x00\x1bunsafe-uintptr\x01\x02\x00\t\x1dslicestrin" +
- "gcopy\x00\x04:^\x00\x00:`\x00\x00\x01\x02\x00\t\rconvI2E\x00\x02:\relem·2\x00\x00" +
- "\x02:\vret·1\x00\x00\t\rconvI2I\x00\x04\x17\"\b\x00\x00:\relem·3\x00\x00\x02:" +
- "l\x00\x00\t\rconvT2E\x00\x06\x17\"\b\x00\x00\x17:p\x00\x00\x17:\vbuf·4\x00\x00\x02:l\x00\x00" +
- "\t\rconvT2I\x00\x06\x17\"\vtab·2\x00\x00\x17:p\x00\x00\x17:t\x00\x00\x02:l\x00\x00\t\x11a" +
- "ssertE2E\x00\x06\x17\"\vtyp·1\x00\x00:\x0fiface·2\x00\x00\x17:\vret\xc2" +
- "\xb73\x00\x00\x00\t\x13assertE2E2\x00\x06\x17\"\b\x00\x00:\x0fiface·3\x00\x00\x17:\vr" +
- "et·4\x00\x00\x01\x00\x00\t\x11assertE2I\x00\x06\x17\"||\x00\x00:~\x00\x00\x17:\x80\x01\x00\x00\x00" +
- "\t\x13assertE2I2\x00\x06\x17\"\b\x00\x00:\x84\x01\x00\x00\x17:\x86\x01\x00\x00\x01\x00\x00\t\x11asser" +
- "tE2T\x00\x06\x17\"||\x00\x00:~\x00\x00\x17:\x80\x01\x00\x00\x00\t\x13assertE2T2\x00\x06\x17\"\b" +
- "\x00\x00:\x84\x01\x00\x00\x17:\x86\x01\x00\x00\x01\x00\x00\t\x11assertI2E\x00\x06\x17\"||\x00\x00:~\x00\x00\x17" +
- ":\x80\x01\x00\x00\x00\t\x13assertI2E2\x00\x06\x17\"\b\x00\x00:\x84\x01\x00\x00\x17:\x86\x01\x00\x00\x01\x00\x00\t" +
- "\x11assertI2I\x00\x06\x17\"||\x00\x00:~\x00\x00\x17:\x80\x01\x00\x00\x00\t\x13assertI2I" +
- "2\x00\x06\x17\"\b\x00\x00:\x84\x01\x00\x00\x17:\x86\x01\x00\x00\x01\x00\x00\t\x11assertI2T\x00\x06\x17\"||\x00" +
- "\x00:~\x00\x00\x17:\x80\x01\x00\x00\x00\t\x13assertI2T2\x00\x06\x17\"\b\x00\x00:\x84\x01\x00\x00\x17:\x86\x01" +
- "\x00\x00\x01\x00\x00\t\x17panicdottype\x00\x06\x17\"\rhave·1\x00\x00\x17\"\rwant" +
- "·2\x00\x00\x17\"\x84\x01\x00\x00\x00\t\rifaceeq\x00\x04:\ti1·2\x00\x00:\ti2·3\x00" +
- "\x00\x02\x00l\x00\x00\t\refaceeq\x00\x04:\xa4\x01\x00\x00:\xa6\x01\x00\x00\x02\x00l\x00\x00\t\rmakema" +
- "p\x00\b\x17\"\x13mapType·2\x00\x00\n\rhint·3\x00\x00\x17:\x11mapbuf·" +
- "4\x00\x00\x17:\x17bucketbuf·5\x00\x00\x02\x1d::\rhmap·1\x00\x00\t\x13mapa" +
- "ccess1\x00\x06\x17\"\xac\x01\x00\x00\x1d::\rhmap·3\x00\x00\x17:\vkey·4\x00\x00\x02\x17" +
- ":\vval·1\x00\x00\t!mapaccess1_fast32\x00\x06\x17\"\xac\x01\x00\x00\x1d::" +
- "\xb8\x01\x00\x00:\xba\x01\x00\x00\x02\x17:\xbc\x01\x00\x00\t!mapaccess1_fast64\x00\x06\x17\"\xac" +
- "\x01\x00\x00\x1d::\xb8\x01\x00\x00:\xba\x01\x00\x00\x02\x17:\xbc\x01\x00\x00\t#mapaccess1_fasts" +
- "tr\x00\x06\x17\"\xac\x01\x00\x00\x1d::\xb8\x01\x00\x00:\xba\x01\x00\x00\x02\x17:\xbc\x01\x00\x00\t\x1bmapaccess" +
- "1_fat\x00\b\x17\"\xac\x01\x00\x00\x1d::\xb8\x01\x00\x00\x17:\xba\x01\x00\x00\x17\"\rzero·5\x00\x00\x02\x17" +
- ":\xbc\x01\x00\x00\t\x13mapaccess2\x00\x06\x17\"\x13mapType·3\x00\x00\x1d::\rhm" +
- "ap·4\x00\x00\x17:\vkey·5\x00\x00\x04\x17:\xbc\x01\x00\x00\x00\rpres·2\x00\x00\t!ma" +
- "paccess2_fast32\x00\x06\x17\"\xca\x01\x00\x00\x1d::\xcc\x01\x00\x00:\xce\x01\x00\x00\x04\x17:\xbc\x01" +
- "\x00\x00\x00\xd0\x01\x00\x00\t!mapaccess2_fast64\x00\x06\x17\"\xca\x01\x00\x00\x1d::\xcc\x01\x00" +
- "\x00:\xce\x01\x00\x00\x04\x17:\xbc\x01\x00\x00\x00\xd0\x01\x00\x00\t#mapaccess2_faststr\x00\x06" +
- "\x17\"\xca\x01\x00\x00\x1d::\xcc\x01\x00\x00:\xce\x01\x00\x00\x04\x17:\xbc\x01\x00\x00\x00\xd0\x01\x00\x00\t\x1bmapacces" +
- "s2_fat\x00\b\x17\"\xca\x01\x00\x00\x1d::\xcc\x01\x00\x00\x17:\xce\x01\x00\x00\x17\"\rzero·6\x00\x00\x04" +
- "\x17:\xbc\x01\x00\x00\x00\xd0\x01\x00\x00\t\x13mapassign1\x00\b\x17\"\x13mapType·1\x00\x00" +
- "\x1d::\rhmap·2\x00\x00\x17:\vkey·3\x00\x00\x17:\vval·4\x00\x00\x00\t\x15ma" +
- "piterinit\x00\x06\x17\"\xde\x01\x00\x00\x1d::\xe0\x01\x00\x00\x17:\x0fhiter·3\x00\x00\x00\t\x11" +
- "mapdelete\x00\x06\x17\"\xde\x01\x00\x00\x1d::\xe0\x01\x00\x00\x17:\xe2\x01\x00\x00\x00\t\x15mapiter" +
- "next\x00\x02\x17:\x0fhiter·1\x00\x00\x00\t\x0fmakechan\x00\x04\x17\"\x15chanT" +
- "ype·2\x00\x00\n\xae\x01\x00\x00\x02\x1f\x06:\x0fhchan·1\x00\x00\t\x11chanrecv1\x00" +
- "\x06\x17\"\x15chanType·1\x00\x00\x1f\x02:\x0fhchan·2\x00\x00\x17:p\x00\x00\x00\t\x11c" +
- "hanrecv2\x00\x06\x17\"\xf2\x01\x00\x00\x1f\x02:\x0fhchan·3\x00\x00\x17:\relem·4" +
- "\x00\x00\x01\x00\x00\t\x11chansend1\x00\x06\x17\"\xf8\x01\x00\x00\x1f\x04:\xfa\x01\x00\x00\x17:p\x00\x00\x00\t\x11c" +
- "losechan\x00\x02:\xf4\x01\x00\x00\x00\a\x17writeBarrier\x00\x15\x06\renable" +
- "d\x00\x00\x00\vneeded\x00\x00\x00\x05cgo\x00\x00\x00\t\x1dwritebarrierptr\x00\x04" +
- "\x17:\vdst·1\x00\x00:\vsrc·2\x00\x00\x00\t\x17typedmemmove\x00\x06\x17\"" +
- "||\x00\x00\x17:\vdst·2\x00\x00\x17:\vsrc·3\x00\x00\x00\t\x1btypedslicec" +
- "opy\x00\x06\x17\"\b\x00\x00:\vdst·3\x00\x00:\vsrc·4\x00\x00\x01\x02\x00\t\x17selec" +
- "tnbsend\x00\x06\x17\"\xf2\x01\x00\x00\x1f\x04:\xfe\x01\x00\x00\x17:\x80\x02\x00\x00\x01\x00\x00\t\x17selectn" +
- "brecv\x00\x06\x17\"\xf2\x01\x00\x00\x17:p\x00\x00\x1f\x02:\x0fhchan·4\x00\x00\x01\x00\x00\t\x19sel" +
- "ectnbrecv2\x00\b\x17\"\xf2\x01\x00\x00\x17:p\x00\x00\x17\x00\x15received·4\x00\x00\x1f" +
- "\x02:\x0fhchan·5\x00\x00\x01\x00\x00\t\x11newselect\x00\x06\x17\"\vsel·1\x00\x00" +
- "\n\x13selsize·2\x00\x00\b\rsize·3\x00\x00\x00\t\x13selectsend\x00\x06" +
- "\x17\"\vsel·2\x00\x00\x1f\x04:\xfe\x01\x00\x00\x17:\x80\x02\x00\x00\x02\x00\x15selected·1\x00\x00" +
- "\t\x13selectrecv\x00\x06\x17\"\xb6\x02\x00\x00\x1f\x02:\xfe\x01\x00\x00\x17:\x80\x02\x00\x00\x02\x00\xb8\x02\x00\x00\t" +
- "\x15selectrecv2\x00\b\x17\"\xb6\x02\x00\x00\x1f\x02:\xfe\x01\x00\x00\x17:\x80\x02\x00\x00\x17\x00\x15rece" +
- "ived·5\x00\x00\x02\x00\xb8\x02\x00\x00\t\x19selectdefault\x00\x02\x17\"\xb6\x02\x00\x00\x02\x00" +
- "\xb8\x02\x00\x00\t\x0fselectgo\x00\x02\x17\"\xae\x02\x00\x00\x00\t\tblock\x00\x00\x00\t\x11makes" +
- "lice\x00\x06\x17\"\b\x00\x00\n\vnel·3\x00\x00\n\vcap·4\x00\x00\x02\x11:\vary·" +
- "1\x00\x00\t\x11growslice\x00\x06\x17\"\b\x00\x00\x11:\vold·3\x00\x00\x02\xca\x02\x00\x00\x02\x11:" +
- "\xcc\x02\x00\x00\t\rmemmove\x00\x06\x17:\tto·1\x00\x00\x17:\vfrm·2\x00\x00\x16\x11le" +
- "ngth·3\x00d\x00\t\vmemclr\x00\x04\x17\"\vptr·1\x00\x00\x16\x11length\xc2" +
- "\xb72\x00d\x00\t\x0fmemequal\x00\x06\x17:\ax·2\x00\x00\x17:\ay·3\x00\x00\x16\rsiz" +
- "e·4\x00d\x01\x00\x00\t\x11memequal8\x00\x04\x17:\xe2\x02\x00\x00\x17:\xe4\x02\x00\x00\x01\x00\x00\t\x13m" +
- "emequal16\x00\x04\x17:\xe2\x02\x00\x00\x17:\xe4\x02\x00\x00\x01\x00\x00\t\x13memequal32\x00\x04" +
- "\x17:\xe2\x02\x00\x00\x17:\xe4\x02\x00\x00\x01\x00\x00\t\x13memequal64\x00\x04\x17:\xe2\x02\x00\x00\x17:\xe4\x02\x00" +
- "\x00\x01\x00\x00\t\x15memequal128\x00\x04\x17:\xe2\x02\x00\x00\x17:\xe4\x02\x00\x00\x01\x00\x00\t\x0fint6" +
- "4div\x00\x03\n\x00\n\x00\x01\n\x00\t\x11uint64div\x00\x03\x14\x00\x14\x00\x01\x14\x00\t\x0fint64" +
- "mod\x00\x03\n\x00\n\x00\x01\n\x00\t\x11uint64mod\x00\x03\x14\x00\x14\x00\x01\x14\x00\t\x1bfloat6" +
- "4toint64\x00\x01\x1a\x00\x01\n\x00\t\x1dfloat64touint64\x00\x01\x1a\x00\x01\x14\x00\t" +
- "\x1bint64tofloat64\x00\x01\n\x00\x01\x1a\x00\t\x1duint64tofloat64\x00" +
- "\x01\x14\x00\x01\x1a\x00\t\x19complex128div\x00\x04\x1e\vnum·2\x00\x00\x1e\vden·" +
- "3\x00\x00\x02\x1e\vquo·1\x00\x00\t\x19racefuncenter\x00\x01\x16d\x00\t\x17race" +
- "funcexit\x00\x00\x00\t\x0fraceread\x00\x01\x16d\x00\t\x11racewrite\x00\x01\x16" +
- "d\x00\t\x19racereadrange\x00\x04\x16\raddr·1\x00d\x16\rsize·2\x00" +
- "d\x00\t\x1bracewriterange\x00\x04\x16\x94\x03\x00d\x16\x96\x03\x00d\x00\t\x0fmsanrea" +
- "d\x00\x04\x16\x94\x03\x00d\x16\x96\x03\x00d\x00\t\x11msanwrite\x00\x04\x16\x94\x03\x00d\x16\x96\x03\x00d\x00\v\xf4" +
- "\x01\x02\v\x00\x01\x00\n$$\n"
+var runtimeDecls = [...]struct {
+ name string
+ tag int
+ typ int
+}{
+ {"newobject", funcTag, 4},
+ {"panicindex", funcTag, 5},
+ {"panicslice", funcTag, 5},
+ {"panicdivide", funcTag, 5},
+ {"throwinit", funcTag, 5},
+ {"panicwrap", funcTag, 7},
+ {"gopanic", funcTag, 9},
+ {"gorecover", funcTag, 12},
+ {"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},
+ {"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},
+ {"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},
+ {"racefuncexit", funcTag, 5},
+ {"raceread", funcTag, 106},
+ {"racewrite", funcTag, 106},
+ {"racereadrange", funcTag, 107},
+ {"racewriterange", funcTag, 107},
+ {"msanread", funcTag, 107},
+ {"msanwrite", funcTag, 107},
+}
-const unsafeimport = "" +
- "cn\x00\x03v1\x01\vunsafe\x00\x05\r\rPointer\x00\x16\x00\t\x0fOffsetof\x00\x01" +
- ":\x00\x01\x16\x00\t\vSizeof\x00\x01:\x00\x01\x16\x00\t\rAlignof\x00\x01:\x00\x01\x16\x00\v\b\x00\v" +
- "\x00\x01\x00\n$$\n"
+func runtimeTypes() []*Type {
+ var typs [108]*Type
+ typs[0] = bytetype
+ typs[1] = typPtr(typs[0])
+ typs[2] = Types[TANY]
+ typs[3] = typPtr(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[14] = functype(nil, []*Node{anonfield(typs[13])}, nil)
+ typs[15] = Types[TFLOAT64]
+ typs[16] = functype(nil, []*Node{anonfield(typs[15])}, nil)
+ typs[17] = Types[TINT64]
+ typs[18] = functype(nil, []*Node{anonfield(typs[17])}, nil)
+ typs[19] = Types[TUINT64]
+ typs[20] = functype(nil, []*Node{anonfield(typs[19])}, nil)
+ typs[21] = Types[TCOMPLEX128]
+ 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)
+ return typs[:]
+}
diff --git a/src/cmd/compile/internal/gc/builtin/runtime.go b/src/cmd/compile/internal/gc/builtin/runtime.go
index e9316cb..98e25fe 100644
--- a/src/cmd/compile/internal/gc/builtin/runtime.go
+++ b/src/cmd/compile/internal/gc/builtin/runtime.go
@@ -16,7 +16,6 @@ func newobject(typ *byte) *any
func panicindex()
func panicslice()
func panicdivide()
-func throwreturn()
func throwinit()
func panicwrap(string, string, string)
@@ -52,33 +51,23 @@ func slicebytetostring(*[32]byte, []byte) string
func slicebytetostringtmp([]byte) string
func slicerunetostring(*[32]byte, []rune) string
func stringtoslicebyte(*[32]byte, string) []byte
-func stringtoslicebytetmp(string) []byte
func stringtoslicerune(*[32]rune, string) []rune
-func stringiter(string, int) int
-func stringiter2(string, int) (retk int, retv rune)
+func decoderune(string, int) (retv rune, retk int)
func slicecopy(to any, fr any, wid uintptr) int
func slicestringcopy(to any, fr any) int
// interface conversions
-func convI2E(elem any) (ret any)
func convI2I(typ *byte, elem any) (ret any)
-func convT2E(typ *byte, elem, buf *any) (ret any)
-func convT2I(tab *byte, elem, buf *any) (ret any)
+func convT2E(typ *byte, elem *any) (ret any)
+func convT2I(tab *byte, elem *any) (ret any)
// interface type assertions x.(T)
-func assertE2E(typ *byte, iface any, ret *any)
-func assertE2E2(typ *byte, iface any, ret *any) bool
-func assertE2I(typ *byte, iface any, ret *any)
-func assertE2I2(typ *byte, iface any, ret *any) bool
-func assertE2T(typ *byte, iface any, ret *any)
-func assertE2T2(typ *byte, iface any, ret *any) bool
-func assertI2E(typ *byte, iface any, ret *any)
-func assertI2E2(typ *byte, iface any, ret *any) bool
-func assertI2I(typ *byte, iface any, ret *any)
-func assertI2I2(typ *byte, iface any, ret *any) bool
-func assertI2T(typ *byte, iface any, ret *any)
-func assertI2T2(typ *byte, iface any, ret *any) bool
+func 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 panicnildottype(want *byte)
func ifaceeq(i1 any, i2 any) (ret bool)
func efaceeq(i1 any, i2 any) (ret bool)
@@ -95,7 +84,7 @@ func mapaccess2_fast32(mapType *byte, hmap map[any]any, key any) (val *any, pres
func mapaccess2_fast64(mapType *byte, hmap map[any]any, key any) (val *any, pres bool)
func mapaccess2_faststr(mapType *byte, hmap map[any]any, key any) (val *any, pres bool)
func mapaccess2_fat(mapType *byte, hmap map[any]any, key *any, zero *byte) (val *any, pres bool)
-func mapassign1(mapType *byte, hmap map[any]any, key *any, val *any)
+func mapassign(mapType *byte, hmap map[any]any, key *any) (val *any)
func mapiterinit(mapType *byte, hmap map[any]any, hiter *any)
func mapdelete(mapType *byte, hmap map[any]any, key *any)
func mapiternext(hiter *any)
@@ -117,6 +106,7 @@ func writebarrierptr(dst *any, src any)
// *byte is really *runtime.Type
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
@@ -131,10 +121,12 @@ func selectdefault(sel *byte) (selected bool)
func selectgo(sel *byte)
func block()
-func makeslice(typ *byte, nel int64, cap int64) (ary []any)
+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 memclr(ptr *byte, length uintptr)
+func memclrNoHeapPointers(ptr *byte, length uintptr)
+func memclrHasPointers(ptr *byte, length uintptr)
func memequal(x, y *any, size uintptr) bool
func memequal8(x, y *any) bool
@@ -150,8 +142,10 @@ func int64mod(int64, int64) int64
func uint64mod(uint64, uint64) uint64
func float64toint64(float64) int64
func float64touint64(float64) uint64
+func float64touint32(float64) uint32
func int64tofloat64(int64) float64
func uint64tofloat64(uint64) float64
+func uint32tofloat64(uint32) float64
func complex128div(num complex128, den complex128) (quo complex128)
diff --git a/src/cmd/compile/internal/gc/builtin/unsafe.go b/src/cmd/compile/internal/gc/builtin/unsafe.go
deleted file mode 100644
index 6e25db6..0000000
--- a/src/cmd/compile/internal/gc/builtin/unsafe.go
+++ /dev/null
@@ -1,18 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// NOTE: If you change this file you must run "go generate"
-// to update builtin.go. This is not done automatically
-// to avoid depending on having a working compiler binary.
-
-// +build ignore
-
-package unsafe
-
-type Pointer uintptr // not really; filled in by compiler
-
-// return types here are ignored; see unsafe.go
-func Offsetof(any) uintptr
-func Sizeof(any) uintptr
-func Alignof(any) uintptr
diff --git a/src/cmd/compile/internal/gc/builtin_test.go b/src/cmd/compile/internal/gc/builtin_test.go
index 94111e6..31b0785 100644
--- a/src/cmd/compile/internal/gc/builtin_test.go
+++ b/src/cmd/compile/internal/gc/builtin_test.go
@@ -20,7 +20,7 @@ func TestBuiltin(t *testing.T) {
t.Fatal(err)
}
- new, err := exec.Command("go", "run", "mkbuiltin.go", "-stdout").Output()
+ new, err := exec.Command(testenv.GoToolPath(t), "run", "mkbuiltin.go", "-stdout").Output()
if err != nil {
t.Fatal(err)
}
diff --git a/src/cmd/compile/internal/gc/bv.go b/src/cmd/compile/internal/gc/bv.go
index d1c2192..183105f 100644
--- a/src/cmd/compile/internal/gc/bv.go
+++ b/src/cmd/compile/internal/gc/bv.go
@@ -4,8 +4,6 @@
package gc
-import "fmt"
-
const (
WORDBITS = 32
WORDMASK = WORDBITS - 1
@@ -44,14 +42,7 @@ func (b *bulkBvec) next() bvec {
return out
}
-// difference
-func bvandnot(dst bvec, src1 bvec, src2 bvec) {
- for i, x := range src1.b {
- dst.b[i] = x &^ src2.b[i]
- }
-}
-
-func bveq(bv1 bvec, bv2 bvec) bool {
+func (bv1 bvec) Eq(bv2 bvec) bool {
if bv1.n != bv2.n {
Fatalf("bvequal: lengths %d and %d are not equal", bv1.n, bv2.n)
}
@@ -63,22 +54,31 @@ func bveq(bv1 bvec, bv2 bvec) bool {
return true
}
-func bvcopy(dst bvec, src bvec) {
+func (dst bvec) Copy(src bvec) {
for i, x := range src.b {
dst.b[i] = x
}
}
-func bvget(bv bvec, i int32) int {
+func (bv bvec) Get(i int32) bool {
if i < 0 || i >= bv.n {
Fatalf("bvget: index %d is out of bounds with length %d\n", i, bv.n)
}
- return int((bv.b[i>>WORDSHIFT] >> uint(i&WORDMASK)) & 1)
+ mask := uint32(1 << uint(i%WORDBITS))
+ return bv.b[i>>WORDSHIFT]&mask != 0
+}
+
+func (bv bvec) Set(i int32) {
+ if i < 0 || i >= bv.n {
+ Fatalf("bvset: index %d is out of bounds with length %d\n", i, bv.n)
+ }
+ mask := uint32(1 << uint(i%WORDBITS))
+ bv.b[i/WORDBITS] |= mask
}
// bvnext returns the smallest index >= i for which bvget(bv, i) == 1.
// If there is no such index, bvnext returns -1.
-func bvnext(bv bvec, i int32) int32 {
+func (bv bvec) Next(i int32) int32 {
if i >= bv.n {
return -1
}
@@ -107,7 +107,7 @@ func bvnext(bv bvec, i int32) int32 {
return i
}
-func bvisempty(bv bvec) bool {
+func (bv bvec) IsEmpty() bool {
for i := int32(0); i < bv.n; i += WORDBITS {
if bv.b[i>>WORDSHIFT] != 0 {
return false
@@ -116,7 +116,7 @@ func bvisempty(bv bvec) bool {
return true
}
-func bvnot(bv bvec) {
+func (bv bvec) Not() {
i := int32(0)
w := int32(0)
for ; i < bv.n; i, w = i+WORDBITS, w+1 {
@@ -125,36 +125,41 @@ func bvnot(bv bvec) {
}
// union
-func bvor(dst bvec, src1 bvec, src2 bvec) {
+func (dst bvec) Or(src1, src2 bvec) {
for i, x := range src1.b {
dst.b[i] = x | src2.b[i]
}
}
// intersection
-func bvand(dst bvec, src1 bvec, src2 bvec) {
+func (dst bvec) And(src1, src2 bvec) {
for i, x := range src1.b {
dst.b[i] = x & src2.b[i]
}
}
-func bvprint(bv bvec) {
- fmt.Printf("#*")
- for i := int32(0); i < bv.n; i++ {
- fmt.Printf("%d", bvget(bv, i))
+// difference
+func (dst bvec) AndNot(src1, src2 bvec) {
+ for i, x := range src1.b {
+ dst.b[i] = x &^ src2.b[i]
}
}
-func bvresetall(bv bvec) {
- for i := range bv.b {
- bv.b[i] = 0
+func (bv bvec) String() string {
+ s := make([]byte, 2+bv.n)
+ copy(s, "#*")
+ for i := int32(0); i < bv.n; i++ {
+ ch := byte('0')
+ if bv.Get(i) {
+ ch = '1'
+ }
+ s[2+i] = ch
}
+ return string(s)
}
-func bvset(bv bvec, i int32) {
- if i < 0 || i >= bv.n {
- Fatalf("bvset: index %d is out of bounds with length %d\n", i, bv.n)
+func (bv bvec) Clear() {
+ for i := range bv.b {
+ bv.b[i] = 0
}
- mask := uint32(1 << uint(i%WORDBITS))
- bv.b[i/WORDBITS] |= mask
}
diff --git a/src/cmd/compile/internal/gc/cgen.go b/src/cmd/compile/internal/gc/cgen.go
deleted file mode 100644
index 74fe463..0000000
--- a/src/cmd/compile/internal/gc/cgen.go
+++ /dev/null
@@ -1,3600 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package gc
-
-import (
- "cmd/internal/obj"
- "cmd/internal/obj/ppc64"
- "cmd/internal/sys"
- "fmt"
-)
-
-// generate:
-// res = n;
-// simplifies and calls Thearch.Gmove.
-// if wb is true, need to emit write barriers.
-func Cgen(n, res *Node) {
- cgen_wb(n, res, false)
-}
-
-func cgen_wb(n, res *Node, wb bool) {
- if Debug['g'] != 0 {
- op := "cgen"
- if wb {
- op = "cgen_wb"
- }
- Dump("\n"+op+"-n", n)
- Dump(op+"-res", res)
- }
-
- if n == nil || n.Type == nil {
- return
- }
-
- if res == nil || res.Type == nil {
- Fatalf("cgen: res nil")
- }
-
- for n.Op == OCONVNOP {
- n = n.Left
- }
-
- switch n.Op {
- case OSLICE, OSLICEARR, OSLICESTR, OSLICE3, OSLICE3ARR:
- cgen_slice(n, res, wb)
- return
-
- case OEFACE:
- if res.Op != ONAME || !res.Addable || wb {
- var n1 Node
- Tempname(&n1, n.Type)
- Cgen_eface(n, &n1)
- cgen_wb(&n1, res, wb)
- } else {
- Cgen_eface(n, res)
- }
- return
-
- case ODOTTYPE:
- cgen_dottype(n, res, nil, wb)
- return
-
- case OAPPEND:
- cgen_append(n, res)
- return
- }
-
- if n.Ullman >= UINF {
- if n.Op == OINDREG {
- Fatalf("cgen: this is going to miscompile")
- }
- if res.Ullman >= UINF {
- var n1 Node
- Tempname(&n1, n.Type)
- Cgen(n, &n1)
- cgen_wb(&n1, res, wb)
- return
- }
- }
-
- if Isfat(n.Type) {
- if n.Type.Width < 0 {
- Fatalf("forgot to compute width for %v", n.Type)
- }
- sgen_wb(n, res, n.Type.Width, wb)
- return
- }
-
- if !res.Addable {
- if n.Ullman > res.Ullman {
- if Ctxt.Arch.RegSize == 4 && Is64(n.Type) {
- var n1 Node
- Tempname(&n1, n.Type)
- Cgen(n, &n1)
- cgen_wb(&n1, res, wb)
- return
- }
-
- var n1 Node
- Regalloc(&n1, n.Type, res)
- Cgen(n, &n1)
- if n1.Ullman > res.Ullman {
- Dump("n1", &n1)
- Dump("res", res)
- Fatalf("loop in cgen")
- }
-
- cgen_wb(&n1, res, wb)
- Regfree(&n1)
- return
- }
-
- if res.Ullman < UINF {
- if Complexop(n, res) {
- Complexgen(n, res)
- return
- }
-
- f := true // gen through register
- switch n.Op {
- case OLITERAL:
- if Smallintconst(n) {
- f = false
- }
-
- case OREGISTER:
- f = false
- }
-
- if !n.Type.IsComplex() && Ctxt.Arch.RegSize == 8 && !wb {
- a := Thearch.Optoas(OAS, res.Type)
- var addr obj.Addr
- if Thearch.Sudoaddable(a, res, &addr) {
- var p1 *obj.Prog
- if f {
- var n2 Node
- Regalloc(&n2, res.Type, nil)
- Cgen(n, &n2)
- p1 = Thearch.Gins(a, &n2, nil)
- Regfree(&n2)
- } else {
- p1 = Thearch.Gins(a, n, nil)
- }
- p1.To = addr
- if Debug['g'] != 0 {
- fmt.Printf("%v [ignore previous line]\n", p1)
- }
- Thearch.Sudoclean()
- return
- }
- }
- }
-
- if Ctxt.Arch.Family == sys.I386 {
- // no registers to speak of
- var n1, n2 Node
- Tempname(&n1, n.Type)
- Cgen(n, &n1)
- Igen(res, &n2, nil)
- cgen_wb(&n1, &n2, wb)
- Regfree(&n2)
- return
- }
-
- var n1 Node
- Igen(res, &n1, nil)
- cgen_wb(n, &n1, wb)
- Regfree(&n1)
- return
- }
-
- // update addressability for string, slice
- // can't do in walk because n->left->addable
- // changes if n->left is an escaping local variable.
- switch n.Op {
- case OSPTR, OLEN:
- if n.Left.Type.IsSlice() || n.Left.Type.IsString() {
- n.Addable = n.Left.Addable
- }
-
- case OCAP:
- if n.Left.Type.IsSlice() {
- n.Addable = n.Left.Addable
- }
-
- case OITAB:
- n.Addable = n.Left.Addable
- }
-
- if wb {
- if Simtype[res.Type.Etype] != Tptr {
- Fatalf("cgen_wb of type %v", res.Type)
- }
- if n.Ullman >= UINF {
- var n1 Node
- Tempname(&n1, n.Type)
- Cgen(n, &n1)
- n = &n1
- }
- cgen_wbptr(n, res)
- return
- }
-
- // Write barrier now handled. Code below this line can ignore wb.
-
- if Ctxt.Arch.Family == sys.ARM { // TODO(rsc): Maybe more often?
- // if both are addressable, move
- if n.Addable && res.Addable {
- if Is64(n.Type) || Is64(res.Type) || n.Op == OREGISTER || res.Op == OREGISTER || n.Type.IsComplex() || res.Type.IsComplex() {
- Thearch.Gmove(n, res)
- } else {
- var n1 Node
- Regalloc(&n1, n.Type, nil)
- Thearch.Gmove(n, &n1)
- Cgen(&n1, res)
- Regfree(&n1)
- }
-
- return
- }
-
- // if both are not addressable, use a temporary.
- if !n.Addable && !res.Addable {
- // could use regalloc here sometimes,
- // but have to check for ullman >= UINF.
- var n1 Node
- Tempname(&n1, n.Type)
- Cgen(n, &n1)
- Cgen(&n1, res)
- return
- }
-
- // if result is not addressable directly but n is,
- // compute its address and then store via the address.
- if !res.Addable {
- var n1 Node
- Igen(res, &n1, nil)
- Cgen(n, &n1)
- Regfree(&n1)
- return
- }
- }
-
- if Complexop(n, res) {
- Complexgen(n, res)
- return
- }
-
- if Ctxt.Arch.InFamily(sys.AMD64, sys.I386, sys.S390X) && n.Addable {
- Thearch.Gmove(n, res)
- return
- }
-
- if Ctxt.Arch.InFamily(sys.ARM64, sys.MIPS64, sys.PPC64) {
- // if both are addressable, move
- if n.Addable {
- if n.Op == OREGISTER || res.Op == OREGISTER {
- Thearch.Gmove(n, res)
- } else {
- var n1 Node
- Regalloc(&n1, n.Type, nil)
- Thearch.Gmove(n, &n1)
- Cgen(&n1, res)
- Regfree(&n1)
- }
- return
- }
- }
-
- // if n is sudoaddable generate addr and move
- if Ctxt.Arch.Family == sys.ARM && !Is64(n.Type) && !Is64(res.Type) && !n.Type.IsComplex() && !res.Type.IsComplex() {
- a := Thearch.Optoas(OAS, n.Type)
- var addr obj.Addr
- if Thearch.Sudoaddable(a, n, &addr) {
- if res.Op != OREGISTER {
- var n2 Node
- Regalloc(&n2, res.Type, nil)
- p1 := Thearch.Gins(a, nil, &n2)
- p1.From = addr
- if Debug['g'] != 0 {
- fmt.Printf("%v [ignore previous line]\n", p1)
- }
- Thearch.Gmove(&n2, res)
- Regfree(&n2)
- } else {
- p1 := Thearch.Gins(a, nil, res)
- p1.From = addr
- if Debug['g'] != 0 {
- fmt.Printf("%v [ignore previous line]\n", p1)
- }
- }
- Thearch.Sudoclean()
- return
- }
- }
-
- nl := n.Left
- nr := n.Right
-
- if nl != nil && nl.Ullman >= UINF {
- if nr != nil && nr.Ullman >= UINF {
- var n1 Node
- Tempname(&n1, nl.Type)
- Cgen(nl, &n1)
- n2 := *n
- n2.Left = &n1
- Cgen(&n2, res)
- return
- }
- }
-
- // 64-bit ops are hard on 32-bit machine.
- if Ctxt.Arch.RegSize == 4 && (Is64(n.Type) || Is64(res.Type) || n.Left != nil && Is64(n.Left.Type)) {
- switch n.Op {
- // math goes to cgen64.
- case OMINUS,
- OCOM,
- OADD,
- OSUB,
- OMUL,
- OLROT,
- OLSH,
- ORSH,
- OAND,
- OOR,
- OXOR:
- Thearch.Cgen64(n, res)
- return
- }
- }
-
- if Thearch.Cgen_float != nil && nl != nil && n.Type.IsFloat() && nl.Type.IsFloat() {
- Thearch.Cgen_float(n, res)
- return
- }
-
- if !n.Type.IsComplex() && Ctxt.Arch.RegSize == 8 {
- a := Thearch.Optoas(OAS, n.Type)
- var addr obj.Addr
- if Thearch.Sudoaddable(a, n, &addr) {
- if res.Op == OREGISTER {
- p1 := Thearch.Gins(a, nil, res)
- p1.From = addr
- } else {
- var n2 Node
- Regalloc(&n2, n.Type, nil)
- p1 := Thearch.Gins(a, nil, &n2)
- p1.From = addr
- Thearch.Gins(a, &n2, res)
- Regfree(&n2)
- }
-
- Thearch.Sudoclean()
- return
- }
- }
-
- var a obj.As
- switch n.Op {
- default:
- Dump("cgen", n)
- Dump("cgen-res", res)
- Fatalf("cgen: unknown op %v", Nconv(n, FmtShort|FmtSign))
-
- case OOROR, OANDAND,
- OEQ, ONE,
- OLT, OLE,
- OGE, OGT,
- ONOT:
- Bvgen(n, res, true)
- return
-
- case OPLUS:
- Cgen(nl, res)
- return
-
- // unary
- case OCOM:
- a := Thearch.Optoas(OXOR, nl.Type)
-
- var n1 Node
- Regalloc(&n1, nl.Type, nil)
- Cgen(nl, &n1)
- var n2 Node
- Nodconst(&n2, nl.Type, -1)
- Thearch.Gins(a, &n2, &n1)
- cgen_norm(n, &n1, res)
- return
-
- case OMINUS:
- if nl.Type.IsFloat() {
- nr = Nodintconst(-1)
- nr = convlit(nr, n.Type)
- a = Thearch.Optoas(OMUL, nl.Type)
- goto sbop
- }
-
- a := Thearch.Optoas(n.Op, nl.Type)
- // unary
- var n1 Node
- Regalloc(&n1, nl.Type, res)
-
- Cgen(nl, &n1)
- if Ctxt.Arch.Family == sys.ARM {
- var n2 Node
- Nodconst(&n2, nl.Type, 0)
- Thearch.Gins(a, &n2, &n1)
- } else if Ctxt.Arch.Family == sys.ARM64 {
- Thearch.Gins(a, &n1, &n1)
- } else {
- Thearch.Gins(a, nil, &n1)
- }
- cgen_norm(n, &n1, res)
- return
-
- case OSQRT:
- var n1 Node
- Regalloc(&n1, nl.Type, res)
- Cgen(n.Left, &n1)
- Thearch.Gins(Thearch.Optoas(OSQRT, nl.Type), &n1, &n1)
- Thearch.Gmove(&n1, res)
- Regfree(&n1)
- return
-
- case OGETG:
- Thearch.Getg(res)
- return
-
- // symmetric binary
- case OAND,
- OOR,
- OXOR,
- OADD,
- OMUL:
- if n.Op == OMUL && Thearch.Cgen_bmul != nil && Thearch.Cgen_bmul(n.Op, nl, nr, res) {
- break
- }
- a = Thearch.Optoas(n.Op, nl.Type)
- goto sbop
-
- // asymmetric binary
- case OSUB:
- a = Thearch.Optoas(n.Op, nl.Type)
- goto abop
-
- case OHMUL:
- Thearch.Cgen_hmul(nl, nr, res)
-
- case OCONV:
- if Eqtype(n.Type, nl.Type) || Noconv(n.Type, nl.Type) {
- Cgen(nl, res)
- return
- }
-
- if Ctxt.Arch.Family == sys.I386 {
- var n1 Node
- var n2 Node
- Tempname(&n2, n.Type)
- Mgen(nl, &n1, res)
- Thearch.Gmove(&n1, &n2)
- Thearch.Gmove(&n2, res)
- Mfree(&n1)
- break
- }
-
- var n1 Node
- var n2 Node
- if Ctxt.Arch.Family == sys.ARM {
- if nl.Addable && !Is64(nl.Type) {
- Regalloc(&n1, nl.Type, res)
- Thearch.Gmove(nl, &n1)
- } else {
- if n.Type.Width > int64(Widthptr) || Is64(nl.Type) || nl.Type.IsFloat() {
- Tempname(&n1, nl.Type)
- } else {
- Regalloc(&n1, nl.Type, res)
- }
- Cgen(nl, &n1)
- }
- if n.Type.Width > int64(Widthptr) || Is64(n.Type) || n.Type.IsFloat() {
- Tempname(&n2, n.Type)
- } else {
- Regalloc(&n2, n.Type, nil)
- }
- } else {
- if n.Type.Width > nl.Type.Width {
- // If loading from memory, do conversion during load,
- // so as to avoid use of 8-bit register in, say, int(*byteptr).
- switch nl.Op {
- case ODOT, ODOTPTR, OINDEX, OIND, ONAME:
- Igen(nl, &n1, res)
- Regalloc(&n2, n.Type, res)
- Thearch.Gmove(&n1, &n2)
- Thearch.Gmove(&n2, res)
- Regfree(&n2)
- Regfree(&n1)
- return
- }
- }
- Regalloc(&n1, nl.Type, res)
- Regalloc(&n2, n.Type, &n1)
- Cgen(nl, &n1)
- }
-
- // if we do the conversion n1 -> n2 here
- // reusing the register, then gmove won't
- // have to allocate its own register.
- Thearch.Gmove(&n1, &n2)
- Thearch.Gmove(&n2, res)
- if n2.Op == OREGISTER {
- Regfree(&n2)
- }
- if n1.Op == OREGISTER {
- Regfree(&n1)
- }
-
- case ODOT,
- ODOTPTR,
- OINDEX,
- OIND:
- var n1 Node
- Igen(n, &n1, res)
-
- Thearch.Gmove(&n1, res)
- Regfree(&n1)
-
- // interface table is first word of interface value
- case OITAB:
- var n1 Node
- Igen(nl, &n1, res)
-
- n1.Type = n.Type
- Thearch.Gmove(&n1, res)
- Regfree(&n1)
-
- case OSPTR:
- // pointer is the first word of string or slice.
- if Isconst(nl, CTSTR) {
- var n1 Node
- Regalloc(&n1, Types[Tptr], res)
- p1 := Thearch.Gins(Thearch.Optoas(OAS, n1.Type), nil, &n1)
- Datastring(nl.Val().U.(string), &p1.From)
- p1.From.Type = obj.TYPE_ADDR
- Thearch.Gmove(&n1, res)
- Regfree(&n1)
- break
- }
-
- var n1 Node
- Igen(nl, &n1, res)
- n1.Type = n.Type
- Thearch.Gmove(&n1, res)
- Regfree(&n1)
-
- case OLEN:
- if nl.Type.IsMap() || nl.Type.IsChan() {
- // map and chan have len in the first int-sized word.
- // a zero pointer means zero length
- var n1 Node
- Regalloc(&n1, Types[Tptr], res)
-
- Cgen(nl, &n1)
-
- var n2 Node
- Nodconst(&n2, Types[Tptr], 0)
- p1 := Thearch.Ginscmp(OEQ, Types[Tptr], &n1, &n2, 0)
-
- n2 = n1
- n2.Op = OINDREG
- n2.Type = Types[Simtype[TINT]]
- Thearch.Gmove(&n2, &n1)
-
- Patch(p1, Pc)
-
- Thearch.Gmove(&n1, res)
- Regfree(&n1)
- break
- }
-
- if nl.Type.IsString() || nl.Type.IsSlice() {
- // both slice and string have len one pointer into the struct.
- // a zero pointer means zero length
- var n1 Node
- Igen(nl, &n1, res)
-
- n1.Type = Types[Simtype[TUINT]]
- n1.Xoffset += int64(Array_nel)
- Thearch.Gmove(&n1, res)
- Regfree(&n1)
- break
- }
-
- Fatalf("cgen: OLEN: unknown type %v", Tconv(nl.Type, FmtLong))
-
- case OCAP:
- if nl.Type.IsChan() {
- // chan has cap in the second int-sized word.
- // a zero pointer means zero length
- var n1 Node
- Regalloc(&n1, Types[Tptr], res)
-
- Cgen(nl, &n1)
-
- var n2 Node
- Nodconst(&n2, Types[Tptr], 0)
- p1 := Thearch.Ginscmp(OEQ, Types[Tptr], &n1, &n2, 0)
-
- n2 = n1
- n2.Op = OINDREG
- n2.Xoffset = int64(Widthint)
- n2.Type = Types[Simtype[TINT]]
- Thearch.Gmove(&n2, &n1)
-
- Patch(p1, Pc)
-
- Thearch.Gmove(&n1, res)
- Regfree(&n1)
- break
- }
-
- if nl.Type.IsSlice() {
- var n1 Node
- Igen(nl, &n1, res)
- n1.Type = Types[Simtype[TUINT]]
- n1.Xoffset += int64(Array_cap)
- Thearch.Gmove(&n1, res)
- Regfree(&n1)
- break
- }
-
- Fatalf("cgen: OCAP: unknown type %v", Tconv(nl.Type, FmtLong))
-
- case OADDR:
- if n.Bounded { // let race detector avoid nil checks
- Disable_checknil++
- }
- Agen(nl, res)
- if n.Bounded {
- Disable_checknil--
- }
-
- case OCALLMETH:
- cgen_callmeth(n, 0)
- cgen_callret(n, res)
-
- case OCALLINTER:
- cgen_callinter(n, res, 0)
- cgen_callret(n, res)
-
- case OCALLFUNC:
- cgen_call(n, 0)
- cgen_callret(n, res)
-
- case OMOD, ODIV:
- if n.Type.IsFloat() || Thearch.Dodiv == nil {
- a = Thearch.Optoas(n.Op, nl.Type)
- goto abop
- }
-
- if nl.Ullman >= nr.Ullman {
- var n1 Node
- Regalloc(&n1, nl.Type, res)
- Cgen(nl, &n1)
- cgen_div(n.Op, &n1, nr, res)
- Regfree(&n1)
- } else {
- var n2 Node
- if !Smallintconst(nr) {
- Regalloc(&n2, nr.Type, res)
- Cgen(nr, &n2)
- } else {
- n2 = *nr
- }
-
- cgen_div(n.Op, nl, &n2, res)
- if n2.Op != OLITERAL {
- Regfree(&n2)
- }
- }
-
- case OLSH, ORSH, OLROT:
- Thearch.Cgen_shift(n.Op, n.Bounded, nl, nr, res)
- }
-
- return
-
- // put simplest on right - we'll generate into left
- // and then adjust it using the computation of right.
- // constants and variables have the same ullman
- // count, so look for constants specially.
- //
- // an integer constant we can use as an immediate
- // is simpler than a variable - we can use the immediate
- // in the adjustment instruction directly - so it goes
- // on the right.
- //
- // other constants, like big integers or floating point
- // constants, require a mov into a register, so those
- // might as well go on the left, so we can reuse that
- // register for the computation.
-sbop: // symmetric binary
- if nl.Ullman < nr.Ullman || (nl.Ullman == nr.Ullman && (Smallintconst(nl) || (nr.Op == OLITERAL && !Smallintconst(nr)))) {
- nl, nr = nr, nl
- }
-
-abop: // asymmetric binary
- var n1 Node
- var n2 Node
- if Ctxt.Arch.Family == sys.I386 {
- // no registers, sigh
- if Smallintconst(nr) {
- var n1 Node
- Mgen(nl, &n1, res)
- var n2 Node
- Regalloc(&n2, nl.Type, &n1)
- Thearch.Gmove(&n1, &n2)
- Thearch.Gins(a, nr, &n2)
- Thearch.Gmove(&n2, res)
- Regfree(&n2)
- Mfree(&n1)
- } else if nl.Ullman >= nr.Ullman {
- var nt Node
- Tempname(&nt, nl.Type)
- Cgen(nl, &nt)
- var n2 Node
- Mgen(nr, &n2, nil)
- var n1 Node
- Regalloc(&n1, nl.Type, res)
- Thearch.Gmove(&nt, &n1)
- Thearch.Gins(a, &n2, &n1)
- Thearch.Gmove(&n1, res)
- Regfree(&n1)
- Mfree(&n2)
- } else {
- var n2 Node
- Regalloc(&n2, nr.Type, res)
- Cgen(nr, &n2)
- var n1 Node
- Regalloc(&n1, nl.Type, nil)
- Cgen(nl, &n1)
- Thearch.Gins(a, &n2, &n1)
- Regfree(&n2)
- Thearch.Gmove(&n1, res)
- Regfree(&n1)
- }
- return
- }
-
- if nl.Ullman >= nr.Ullman {
- Regalloc(&n1, nl.Type, res)
- Cgen(nl, &n1)
-
- if Smallintconst(nr) && Ctxt.Arch.Family != sys.MIPS64 && Ctxt.Arch.Family != sys.ARM && Ctxt.Arch.Family != sys.ARM64 && Ctxt.Arch.Family != sys.PPC64 { // TODO(rsc): Check opcode for arm
- n2 = *nr
- } else {
- Regalloc(&n2, nr.Type, nil)
- Cgen(nr, &n2)
- }
- } else {
- if Smallintconst(nr) && Ctxt.Arch.Family != sys.MIPS64 && Ctxt.Arch.Family != sys.ARM && Ctxt.Arch.Family != sys.ARM64 && Ctxt.Arch.Family != sys.PPC64 { // TODO(rsc): Check opcode for arm
- n2 = *nr
- } else {
- Regalloc(&n2, nr.Type, res)
- Cgen(nr, &n2)
- }
-
- Regalloc(&n1, nl.Type, nil)
- Cgen(nl, &n1)
- }
-
- Thearch.Gins(a, &n2, &n1)
- if n2.Op != OLITERAL {
- Regfree(&n2)
- }
- cgen_norm(n, &n1, res)
-}
-
-var sys_wbptr *Node
-
-func cgen_wbptr(n, res *Node) {
- if Curfn != nil {
- if Curfn.Func.Pragma&Nowritebarrier != 0 {
- Yyerror("write barrier prohibited")
- }
- if Curfn.Func.WBLineno == 0 {
- Curfn.Func.WBLineno = lineno
- }
- }
- if Debug_wb > 0 {
- Warn("write barrier")
- }
-
- var dst, src Node
- Igen(res, &dst, nil)
- if n.Op == OREGISTER {
- src = *n
- Regrealloc(&src)
- } else {
- Cgenr(n, &src, nil)
- }
-
- wbVar := syslook("writeBarrier")
- wbEnabled := NodSym(ODOT, wbVar, wbVar.Type.Field(0).Sym)
- wbEnabled = typecheck(wbEnabled, Erv)
- pbr := Thearch.Ginscmp(ONE, Types[TUINT8], wbEnabled, Nodintconst(0), -1)
- Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), &src, &dst)
- pjmp := Gbranch(obj.AJMP, nil, 0)
- Patch(pbr, Pc)
- var adst Node
- Agenr(&dst, &adst, &dst)
- p := Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), &adst, nil)
- a := &p.To
- a.Type = obj.TYPE_MEM
- a.Reg = int16(Thearch.REGSP)
- a.Offset = Ctxt.FixedFrameSize()
- p2 := Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), &src, nil)
- p2.To = p.To
- p2.To.Offset += int64(Widthptr)
- Regfree(&adst)
- if sys_wbptr == nil {
- sys_wbptr = writebarrierfn("writebarrierptr", Types[Tptr], Types[Tptr])
- }
- Ginscall(sys_wbptr, 0)
- Patch(pjmp, Pc)
-
- Regfree(&dst)
- Regfree(&src)
-}
-
-func cgen_wbfat(n, res *Node) {
- if Curfn != nil {
- if Curfn.Func.Pragma&Nowritebarrier != 0 {
- Yyerror("write barrier prohibited")
- }
- if Curfn.Func.WBLineno == 0 {
- Curfn.Func.WBLineno = lineno
- }
- }
- if Debug_wb > 0 {
- Warn("write barrier")
- }
- needType := true
- funcName := "typedmemmove"
- var dst, src Node
- if n.Ullman >= res.Ullman {
- Agenr(n, &src, nil)
- Agenr(res, &dst, nil)
- } else {
- Agenr(res, &dst, nil)
- Agenr(n, &src, nil)
- }
- p := Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), &dst, nil)
- a := &p.To
- a.Type = obj.TYPE_MEM
- a.Reg = int16(Thearch.REGSP)
- a.Offset = Ctxt.FixedFrameSize()
- if needType {
- a.Offset += int64(Widthptr)
- }
- p2 := Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), &src, nil)
- p2.To = p.To
- p2.To.Offset += int64(Widthptr)
- Regfree(&dst)
- if needType {
- src.Type = Types[Tptr]
- Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), typename(n.Type), &src)
- p3 := Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), &src, nil)
- p3.To = p2.To
- p3.To.Offset -= 2 * int64(Widthptr)
- }
- Regfree(&src)
- Ginscall(writebarrierfn(funcName, Types[Tptr], Types[Tptr]), 0)
-}
-
-// cgen_norm moves n1 to res, truncating to expected type if necessary.
-// n1 is a register, and cgen_norm frees it.
-func cgen_norm(n, n1, res *Node) {
- switch Ctxt.Arch.Family {
- case sys.AMD64, sys.I386:
- // We use sized math, so the result is already truncated.
- default:
- switch n.Op {
- case OADD, OSUB, OMUL, ODIV, OCOM, OMINUS:
- // TODO(rsc): What about left shift?
- Thearch.Gins(Thearch.Optoas(OAS, n.Type), n1, n1)
- }
- }
-
- Thearch.Gmove(n1, res)
- Regfree(n1)
-}
-
-func Mgen(n *Node, n1 *Node, rg *Node) {
- n1.Op = OEMPTY
-
- if n.Addable {
- *n1 = *n
- if n1.Op == OREGISTER || n1.Op == OINDREG {
- reg[n.Reg-int16(Thearch.REGMIN)]++
- }
- return
- }
-
- Tempname(n1, n.Type)
- Cgen(n, n1)
- if n.Type.Width <= int64(Widthptr) || n.Type.IsFloat() {
- n2 := *n1
- Regalloc(n1, n.Type, rg)
- Thearch.Gmove(&n2, n1)
- }
-}
-
-func Mfree(n *Node) {
- if n.Op == OREGISTER {
- Regfree(n)
- }
-}
-
-// allocate a register (reusing res if possible) and generate
-// a = n
-// The caller must call Regfree(a).
-func Cgenr(n *Node, a *Node, res *Node) {
- if Debug['g'] != 0 {
- Dump("cgenr-n", n)
- }
-
- if Isfat(n.Type) {
- Fatalf("cgenr on fat node")
- }
-
- if n.Addable {
- Regalloc(a, n.Type, res)
- Thearch.Gmove(n, a)
- return
- }
-
- switch n.Op {
- case ONAME,
- ODOT,
- ODOTPTR,
- OINDEX,
- OCALLFUNC,
- OCALLMETH,
- OCALLINTER:
- var n1 Node
- Igen(n, &n1, res)
- Regalloc(a, n.Type, &n1)
- Thearch.Gmove(&n1, a)
- Regfree(&n1)
-
- default:
- Regalloc(a, n.Type, res)
- Cgen(n, a)
- }
-}
-
-// allocate a register (reusing res if possible) and generate
-// a = &n
-// The caller must call Regfree(a).
-// The generated code checks that the result is not nil.
-func Agenr(n *Node, a *Node, res *Node) {
- if Debug['g'] != 0 {
- Dump("\nagenr-n", n)
- }
-
- nl := n.Left
- nr := n.Right
-
- switch n.Op {
- case ODOT, ODOTPTR, OCALLFUNC, OCALLMETH, OCALLINTER:
- var n1 Node
- Igen(n, &n1, res)
- Regalloc(a, Types[Tptr], &n1)
- Agen(&n1, a)
- Regfree(&n1)
-
- case OIND:
- Cgenr(n.Left, a, res)
- if !n.Left.NonNil {
- Cgen_checknil(a)
- } else if Debug_checknil != 0 && n.Lineno > 1 {
- Warnl(n.Lineno, "removed nil check")
- }
-
- case OINDEX:
- if Ctxt.Arch.Family == sys.ARM {
- var p2 *obj.Prog // to be patched to panicindex.
- w := uint32(n.Type.Width)
- bounded := Debug['B'] != 0 || n.Bounded
- var n1 Node
- var n3 Node
- if nr.Addable {
- var tmp Node
- if !Isconst(nr, CTINT) {
- Tempname(&tmp, Types[TINT32])
- }
- if !Isconst(nl, CTSTR) {
- Agenr(nl, &n3, res)
- }
- if !Isconst(nr, CTINT) {
- p2 = Thearch.Cgenindex(nr, &tmp, bounded)
- Regalloc(&n1, tmp.Type, nil)
- Thearch.Gmove(&tmp, &n1)
- }
- } else if nl.Addable {
- if !Isconst(nr, CTINT) {
- var tmp Node
- Tempname(&tmp, Types[TINT32])
- p2 = Thearch.Cgenindex(nr, &tmp, bounded)
- Regalloc(&n1, tmp.Type, nil)
- Thearch.Gmove(&tmp, &n1)
- }
-
- if !Isconst(nl, CTSTR) {
- Agenr(nl, &n3, res)
- }
- } else {
- var tmp Node
- Tempname(&tmp, Types[TINT32])
- p2 = Thearch.Cgenindex(nr, &tmp, bounded)
- nr = &tmp
- if !Isconst(nl, CTSTR) {
- Agenr(nl, &n3, res)
- }
- Regalloc(&n1, tmp.Type, nil)
- Thearch.Gins(Thearch.Optoas(OAS, tmp.Type), &tmp, &n1)
- }
-
- // &a is in &n3 (allocated in res)
- // i is in &n1 (if not constant)
- // w is width
-
- // constant index
- if Isconst(nr, CTINT) {
- if Isconst(nl, CTSTR) {
- Fatalf("constant string constant index")
- }
- v := uint64(nr.Int64())
- var n2 Node
- if nl.Type.IsSlice() || nl.Type.IsString() {
- if Debug['B'] == 0 && !n.Bounded {
- n1 = n3
- n1.Op = OINDREG
- n1.Type = Types[Tptr]
- n1.Xoffset = int64(Array_nel)
- Nodconst(&n2, Types[TUINT32], int64(v))
- p1 := Thearch.Ginscmp(OGT, Types[TUINT32], &n1, &n2, +1)
- Ginscall(Panicindex, -1)
- Patch(p1, Pc)
- }
-
- n1 = n3
- n1.Op = OINDREG
- n1.Type = Types[Tptr]
- n1.Xoffset = int64(Array_array)
- Thearch.Gmove(&n1, &n3)
- }
-
- Nodconst(&n2, Types[Tptr], int64(v*uint64(w)))
- Thearch.Gins(Thearch.Optoas(OADD, Types[Tptr]), &n2, &n3)
- *a = n3
- break
- }
-
- var n2 Node
- Regalloc(&n2, Types[TINT32], &n1) // i
- Thearch.Gmove(&n1, &n2)
- Regfree(&n1)
-
- var n4 Node
- if Debug['B'] == 0 && !n.Bounded {
- // check bounds
- if Isconst(nl, CTSTR) {
- Nodconst(&n4, Types[TUINT32], int64(len(nl.Val().U.(string))))
- } else if nl.Type.IsSlice() || nl.Type.IsString() {
- n1 = n3
- n1.Op = OINDREG
- n1.Type = Types[Tptr]
- n1.Xoffset = int64(Array_nel)
- Regalloc(&n4, Types[TUINT32], nil)
- Thearch.Gmove(&n1, &n4)
- } else {
- Nodconst(&n4, Types[TUINT32], nl.Type.NumElem())
- }
- p1 := Thearch.Ginscmp(OLT, Types[TUINT32], &n2, &n4, +1)
- if n4.Op == OREGISTER {
- Regfree(&n4)
- }
- if p2 != nil {
- Patch(p2, Pc)
- }
- Ginscall(Panicindex, -1)
- Patch(p1, Pc)
- }
-
- if Isconst(nl, CTSTR) {
- Regalloc(&n3, Types[Tptr], res)
- p1 := Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), nil, &n3)
- Datastring(nl.Val().U.(string), &p1.From)
- p1.From.Type = obj.TYPE_ADDR
- } else if nl.Type.IsSlice() || nl.Type.IsString() {
- n1 = n3
- n1.Op = OINDREG
- n1.Type = Types[Tptr]
- n1.Xoffset = int64(Array_array)
- Thearch.Gmove(&n1, &n3)
- }
-
- if w == 0 {
- // nothing to do
- } else if Thearch.AddIndex != nil && Thearch.AddIndex(&n2, int64(w), &n3) {
- // done by back end
- } else if w == 1 {
- Thearch.Gins(Thearch.Optoas(OADD, Types[Tptr]), &n2, &n3)
- } else {
- if w&(w-1) == 0 {
- // Power of 2. Use shift.
- Thearch.Ginscon(Thearch.Optoas(OLSH, Types[TUINT32]), int64(log2(uint64(w))), &n2)
- } else {
- // Not a power of 2. Use multiply.
- Regalloc(&n4, Types[TUINT32], nil)
- Nodconst(&n1, Types[TUINT32], int64(w))
- Thearch.Gmove(&n1, &n4)
- Thearch.Gins(Thearch.Optoas(OMUL, Types[TUINT32]), &n4, &n2)
- Regfree(&n4)
- }
- Thearch.Gins(Thearch.Optoas(OADD, Types[Tptr]), &n2, &n3)
- }
- *a = n3
- Regfree(&n2)
- break
- }
- if Ctxt.Arch.Family == sys.I386 {
- var p2 *obj.Prog // to be patched to panicindex.
- w := uint32(n.Type.Width)
- bounded := Debug['B'] != 0 || n.Bounded
- var n3 Node
- var tmp Node
- var n1 Node
- if nr.Addable {
- // Generate &nl first, and move nr into register.
- if !Isconst(nl, CTSTR) {
- Igen(nl, &n3, res)
- }
- if !Isconst(nr, CTINT) {
- p2 = Thearch.Igenindex(nr, &tmp, bounded)
- Regalloc(&n1, tmp.Type, nil)
- Thearch.Gmove(&tmp, &n1)
- }
- } else if nl.Addable {
- // Generate nr first, and move &nl into register.
- if !Isconst(nr, CTINT) {
- p2 = Thearch.Igenindex(nr, &tmp, bounded)
- Regalloc(&n1, tmp.Type, nil)
- Thearch.Gmove(&tmp, &n1)
- }
-
- if !Isconst(nl, CTSTR) {
- Igen(nl, &n3, res)
- }
- } else {
- p2 = Thearch.Igenindex(nr, &tmp, bounded)
- nr = &tmp
- if !Isconst(nl, CTSTR) {
- Igen(nl, &n3, res)
- }
- Regalloc(&n1, tmp.Type, nil)
- Thearch.Gins(Thearch.Optoas(OAS, tmp.Type), &tmp, &n1)
- }
-
- // For fixed array we really want the pointer in n3.
- var n2 Node
- if nl.Type.IsArray() {
- Regalloc(&n2, Types[Tptr], &n3)
- Agen(&n3, &n2)
- Regfree(&n3)
- n3 = n2
- }
-
- // &a[0] is in n3 (allocated in res)
- // i is in n1 (if not constant)
- // len(a) is in nlen (if needed)
- // w is width
-
- // constant index
- if Isconst(nr, CTINT) {
- if Isconst(nl, CTSTR) {
- Fatalf("constant string constant index") // front end should handle
- }
- v := uint64(nr.Int64())
- if nl.Type.IsSlice() || nl.Type.IsString() {
- if Debug['B'] == 0 && !n.Bounded {
- nlen := n3
- nlen.Type = Types[TUINT32]
- nlen.Xoffset += int64(Array_nel)
- Nodconst(&n2, Types[TUINT32], int64(v))
- p1 := Thearch.Ginscmp(OGT, Types[TUINT32], &nlen, &n2, +1)
- Ginscall(Panicindex, -1)
- Patch(p1, Pc)
- }
- }
-
- // Load base pointer in n2 = n3.
- Regalloc(&n2, Types[Tptr], &n3)
-
- n3.Type = Types[Tptr]
- n3.Xoffset += int64(Array_array)
- Thearch.Gmove(&n3, &n2)
- Regfree(&n3)
- if v*uint64(w) != 0 {
- Nodconst(&n1, Types[Tptr], int64(v*uint64(w)))
- Thearch.Gins(Thearch.Optoas(OADD, Types[Tptr]), &n1, &n2)
- }
- *a = n2
- break
- }
-
- // i is in register n1, extend to 32 bits.
- t := Types[TUINT32]
-
- if n1.Type.IsSigned() {
- t = Types[TINT32]
- }
-
- Regalloc(&n2, t, &n1) // i
- Thearch.Gmove(&n1, &n2)
- Regfree(&n1)
-
- if Debug['B'] == 0 && !n.Bounded {
- // check bounds
- t := Types[TUINT32]
-
- var nlen Node
- if Isconst(nl, CTSTR) {
- Nodconst(&nlen, t, int64(len(nl.Val().U.(string))))
- } else if nl.Type.IsSlice() || nl.Type.IsString() {
- nlen = n3
- nlen.Type = t
- nlen.Xoffset += int64(Array_nel)
- } else {
- Nodconst(&nlen, t, nl.Type.NumElem())
- }
-
- p1 := Thearch.Ginscmp(OLT, t, &n2, &nlen, +1)
- if p2 != nil {
- Patch(p2, Pc)
- }
- Ginscall(Panicindex, -1)
- Patch(p1, Pc)
- }
-
- if Isconst(nl, CTSTR) {
- Regalloc(&n3, Types[Tptr], res)
- p1 := Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), nil, &n3)
- Datastring(nl.Val().U.(string), &p1.From)
- p1.From.Type = obj.TYPE_ADDR
- Thearch.Gins(Thearch.Optoas(OADD, n3.Type), &n2, &n3)
- goto indexdone1
- }
-
- // Load base pointer in n3.
- Regalloc(&tmp, Types[Tptr], &n3)
-
- if nl.Type.IsSlice() || nl.Type.IsString() {
- n3.Type = Types[Tptr]
- n3.Xoffset += int64(Array_array)
- Thearch.Gmove(&n3, &tmp)
- }
-
- Regfree(&n3)
- n3 = tmp
-
- if w == 0 {
- // nothing to do
- } else if Thearch.AddIndex != nil && Thearch.AddIndex(&n2, int64(w), &n3) {
- // done by back end
- } else if w == 1 {
- Thearch.Gins(Thearch.Optoas(OADD, Types[Tptr]), &n2, &n3)
- } else {
- if w&(w-1) == 0 {
- // Power of 2. Use shift.
- Thearch.Ginscon(Thearch.Optoas(OLSH, Types[TUINT32]), int64(log2(uint64(w))), &n2)
- } else {
- // Not a power of 2. Use multiply.
- Thearch.Ginscon(Thearch.Optoas(OMUL, Types[TUINT32]), int64(w), &n2)
- }
- Thearch.Gins(Thearch.Optoas(OADD, Types[Tptr]), &n2, &n3)
- }
-
- indexdone1:
- *a = n3
- Regfree(&n2)
- break
- }
-
- freelen := 0
- w := uint64(n.Type.Width)
-
- // Generate the non-addressable child first.
- var n3 Node
- var nlen Node
- var tmp Node
- var n1 Node
- if nr.Addable {
- goto irad
- }
- if nl.Addable {
- Cgenr(nr, &n1, nil)
- if !Isconst(nl, CTSTR) {
- if nl.Type.IsArray() {
- Agenr(nl, &n3, res)
- } else {
- Igen(nl, &nlen, res)
- freelen = 1
- nlen.Type = Types[Tptr]
- nlen.Xoffset += int64(Array_array)
- Regalloc(&n3, Types[Tptr], res)
- Thearch.Gmove(&nlen, &n3)
- nlen.Type = Types[Simtype[TUINT]]
- nlen.Xoffset += int64(Array_nel) - int64(Array_array)
- }
- }
-
- goto index
- }
-
- Tempname(&tmp, nr.Type)
- Cgen(nr, &tmp)
- nr = &tmp
-
- irad:
- if !Isconst(nl, CTSTR) {
- if nl.Type.IsArray() {
- Agenr(nl, &n3, res)
- } else {
- if !nl.Addable {
- if res != nil && res.Op == OREGISTER { // give up res, which we don't need yet.
- Regfree(res)
- }
-
- // igen will need an addressable node.
- var tmp2 Node
- Tempname(&tmp2, nl.Type)
- Cgen(nl, &tmp2)
- nl = &tmp2
-
- if res != nil && res.Op == OREGISTER { // reacquire res
- Regrealloc(res)
- }
- }
-
- Igen(nl, &nlen, res)
- freelen = 1
- nlen.Type = Types[Tptr]
- nlen.Xoffset += int64(Array_array)
- Regalloc(&n3, Types[Tptr], res)
- Thearch.Gmove(&nlen, &n3)
- nlen.Type = Types[Simtype[TUINT]]
- nlen.Xoffset += int64(Array_nel) - int64(Array_array)
- }
- }
-
- if !Isconst(nr, CTINT) {
- Cgenr(nr, &n1, nil)
- }
-
- goto index
-
- // &a is in &n3 (allocated in res)
- // i is in &n1 (if not constant)
- // len(a) is in nlen (if needed)
- // w is width
-
- // constant index
- index:
- if Isconst(nr, CTINT) {
- if Isconst(nl, CTSTR) {
- Fatalf("constant string constant index") // front end should handle
- }
- v := uint64(nr.Int64())
- if nl.Type.IsSlice() || nl.Type.IsString() {
- if Debug['B'] == 0 && !n.Bounded {
- p1 := Thearch.Ginscmp(OGT, Types[Simtype[TUINT]], &nlen, Nodintconst(int64(v)), +1)
- Ginscall(Panicindex, -1)
- Patch(p1, Pc)
- }
-
- Regfree(&nlen)
- }
-
- if v*w != 0 {
- Thearch.Ginscon(Thearch.Optoas(OADD, Types[Tptr]), int64(v*w), &n3)
- }
- *a = n3
- break
- }
-
- // type of the index
- t := Types[TUINT64]
-
- if n1.Type.IsSigned() {
- t = Types[TINT64]
- }
-
- var n2 Node
- Regalloc(&n2, t, &n1) // i
- Thearch.Gmove(&n1, &n2)
- Regfree(&n1)
-
- if Debug['B'] == 0 && !n.Bounded {
- // check bounds
- t = Types[Simtype[TUINT]]
-
- if Is64(nr.Type) {
- t = Types[TUINT64]
- }
- if Isconst(nl, CTSTR) {
- Nodconst(&nlen, t, int64(len(nl.Val().U.(string))))
- } else if nl.Type.IsSlice() || nl.Type.IsString() {
- // nlen already initialized
- } else {
- Nodconst(&nlen, t, nl.Type.NumElem())
- }
-
- p1 := Thearch.Ginscmp(OLT, t, &n2, &nlen, +1)
- Ginscall(Panicindex, -1)
- Patch(p1, Pc)
- }
-
- if Isconst(nl, CTSTR) {
- Regalloc(&n3, Types[Tptr], res)
- p1 := Thearch.Gins(Thearch.Optoas(OAS, n3.Type), nil, &n3) // XXX was LEAQ!
- Datastring(nl.Val().U.(string), &p1.From)
- p1.From.Type = obj.TYPE_ADDR
- Thearch.Gins(Thearch.Optoas(OADD, n3.Type), &n2, &n3)
- goto indexdone
- }
-
- if w == 0 {
- // nothing to do
- } else if Thearch.AddIndex != nil && Thearch.AddIndex(&n2, int64(w), &n3) {
- // done by back end
- } else if w == 1 {
- Thearch.Gins(Thearch.Optoas(OADD, Types[Tptr]), &n2, &n3)
- } else {
- if w&(w-1) == 0 {
- // Power of 2. Use shift.
- Thearch.Ginscon(Thearch.Optoas(OLSH, t), int64(log2(w)), &n2)
- } else {
- // Not a power of 2. Use multiply.
- Thearch.Ginscon(Thearch.Optoas(OMUL, t), int64(w), &n2)
- }
- Thearch.Gins(Thearch.Optoas(OADD, Types[Tptr]), &n2, &n3)
- }
-
- indexdone:
- *a = n3
- Regfree(&n2)
- if freelen != 0 {
- Regfree(&nlen)
- }
-
- default:
- Regalloc(a, Types[Tptr], res)
- Agen(n, a)
- }
-}
-
-// log2 returns the logarithm base 2 of n. n must be a power of 2.
-func log2(n uint64) int {
- x := 0
- for n>>uint(x) != 1 {
- x++
- }
- return x
-}
-
-// generate:
-// res = &n;
-// The generated code checks that the result is not nil.
-func Agen(n *Node, res *Node) {
- if Debug['g'] != 0 {
- Dump("\nagen-res", res)
- Dump("agen-r", n)
- }
-
- if n == nil || n.Type == nil {
- return
- }
-
- for n.Op == OCONVNOP {
- n = n.Left
- }
-
- if Isconst(n, CTNIL) && n.Type.Width > int64(Widthptr) {
- // Use of a nil interface or nil slice.
- // Create a temporary we can take the address of and read.
- // The generated code is just going to panic, so it need not
- // be terribly efficient. See issue 3670.
- var n1 Node
- Tempname(&n1, n.Type)
-
- Gvardef(&n1)
- Thearch.Clearfat(&n1)
- var n2 Node
- Regalloc(&n2, Types[Tptr], res)
- var n3 Node
- n3.Op = OADDR
- n3.Left = &n1
- Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), &n3, &n2)
- Thearch.Gmove(&n2, res)
- Regfree(&n2)
- return
- }
-
- if n.Op == OINDREG && n.Xoffset == 0 {
- // Generate MOVW R0, R1 instead of MOVW $0(R0), R1.
- // This allows better move propagation in the back ends
- // (and maybe it helps the processor).
- n1 := *n
- n1.Op = OREGISTER
- n1.Type = res.Type
- Thearch.Gmove(&n1, res)
- return
- }
-
- if n.Addable {
- if n.Op == OREGISTER {
- Fatalf("agen OREGISTER")
- }
- var n1 Node
- n1.Op = OADDR
- n1.Left = n
- var n2 Node
- Regalloc(&n2, Types[Tptr], res)
- Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), &n1, &n2)
- Thearch.Gmove(&n2, res)
- Regfree(&n2)
- return
- }
-
- nl := n.Left
-
- switch n.Op {
- default:
- Dump("bad agen", n)
- Fatalf("agen: unknown op %v", Nconv(n, FmtShort|FmtSign))
-
- case OCALLMETH:
- cgen_callmeth(n, 0)
- cgen_aret(n, res)
-
- case OCALLINTER:
- cgen_callinter(n, res, 0)
- cgen_aret(n, res)
-
- case OCALLFUNC:
- cgen_call(n, 0)
- cgen_aret(n, res)
-
- case OEFACE, ODOTTYPE, OSLICE, OSLICEARR, OSLICESTR, OSLICE3, OSLICE3ARR:
- var n1 Node
- Tempname(&n1, n.Type)
- Cgen(n, &n1)
- Agen(&n1, res)
-
- case OINDEX:
- var n1 Node
- Agenr(n, &n1, res)
- Thearch.Gmove(&n1, res)
- Regfree(&n1)
-
- case OIND:
- Cgen(nl, res)
- if !nl.NonNil {
- Cgen_checknil(res)
- } else if Debug_checknil != 0 && n.Lineno > 1 {
- Warnl(n.Lineno, "removed nil check")
- }
-
- case ODOT:
- Agen(nl, res)
- if n.Xoffset != 0 {
- addOffset(res, n.Xoffset)
- }
-
- case ODOTPTR:
- Cgen(nl, res)
- if !nl.NonNil {
- Cgen_checknil(res)
- } else if Debug_checknil != 0 && n.Lineno > 1 {
- Warnl(n.Lineno, "removed nil check")
- }
- if n.Xoffset != 0 {
- addOffset(res, n.Xoffset)
- }
- }
-}
-
-func addOffset(res *Node, offset int64) {
- if Ctxt.Arch.InFamily(sys.AMD64, sys.I386) {
- Thearch.Gins(Thearch.Optoas(OADD, Types[Tptr]), Nodintconst(offset), res)
- return
- }
-
- var n1, n2 Node
- Regalloc(&n1, Types[Tptr], nil)
- Thearch.Gmove(res, &n1)
- Regalloc(&n2, Types[Tptr], nil)
- Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), Nodintconst(offset), &n2)
- Thearch.Gins(Thearch.Optoas(OADD, Types[Tptr]), &n2, &n1)
- Thearch.Gmove(&n1, res)
- Regfree(&n1)
- Regfree(&n2)
-}
-
-// Igen computes the address &n, stores it in a register r,
-// and rewrites a to refer to *r. The chosen r may be the
-// stack pointer, it may be borrowed from res, or it may
-// be a newly allocated register. The caller must call Regfree(a)
-// to free r when the address is no longer needed.
-// The generated code ensures that &n is not nil.
-func Igen(n *Node, a *Node, res *Node) {
- if Debug['g'] != 0 {
- Dump("\nigen-n", n)
- }
-
- switch n.Op {
- case ONAME:
- if n.Class == PAUTOHEAP {
- Dump("igen", n)
- Fatalf("bad name")
- }
- *a = *n
- return
-
- case OINDREG:
- // Increase the refcount of the register so that igen's caller
- // has to call Regfree.
- if n.Reg != int16(Thearch.REGSP) {
- reg[n.Reg-int16(Thearch.REGMIN)]++
- }
- *a = *n
- return
-
- case ODOT:
- Igen(n.Left, a, res)
- a.Xoffset += n.Xoffset
- a.Type = n.Type
- Fixlargeoffset(a)
- return
-
- case ODOTPTR:
- Cgenr(n.Left, a, res)
- if !n.Left.NonNil {
- Cgen_checknil(a)
- } else if Debug_checknil != 0 && n.Lineno > 1 {
- Warnl(n.Lineno, "removed nil check")
- }
- a.Op = OINDREG
- a.Xoffset += n.Xoffset
- a.Type = n.Type
- Fixlargeoffset(a)
- return
-
- case OCALLFUNC, OCALLMETH, OCALLINTER:
- switch n.Op {
- case OCALLFUNC:
- cgen_call(n, 0)
-
- case OCALLMETH:
- cgen_callmeth(n, 0)
-
- case OCALLINTER:
- cgen_callinter(n, nil, 0)
- }
-
- fp := n.Left.Type.Results().Field(0)
- *a = Node{}
- a.Op = OINDREG
- a.Reg = int16(Thearch.REGSP)
- a.Addable = true
- a.Xoffset = fp.Offset + Ctxt.FixedFrameSize()
- a.Type = n.Type
- return
-
- case OINDEX:
- // Index of fixed-size array by constant can
- // put the offset in the addressing.
- // Could do the same for slice except that we need
- // to use the real index for the bounds checking.
- if n.Left.Type.IsArray() || (n.Left.Type.IsPtr() && n.Left.Left.Type.IsArray()) {
- if Isconst(n.Right, CTINT) {
- // Compute &a.
- if !n.Left.Type.IsPtr() {
- Igen(n.Left, a, res)
- } else {
- var n1 Node
- Igen(n.Left, &n1, res)
- Cgen_checknil(&n1)
- Regalloc(a, Types[Tptr], res)
- Thearch.Gmove(&n1, a)
- Regfree(&n1)
- a.Op = OINDREG
- }
-
- // Compute &a[i] as &a + i*width.
- a.Type = n.Type
-
- a.Xoffset += n.Right.Int64() * n.Type.Width
- Fixlargeoffset(a)
- return
- }
- }
- }
-
- Agenr(n, a, res)
- a.Op = OINDREG
- a.Type = n.Type
-}
-
-// Bgen generates code for branches:
-//
-// if n == wantTrue {
-// goto to
-// }
-func Bgen(n *Node, wantTrue bool, likely int, to *obj.Prog) {
- bgenx(n, nil, wantTrue, likely, to)
-}
-
-// Bvgen generates code for calculating boolean values:
-// res = n == wantTrue
-func Bvgen(n, res *Node, wantTrue bool) {
- if Thearch.Ginsboolval == nil {
- // Direct value generation not implemented for this architecture.
- // Implement using jumps.
- bvgenjump(n, res, wantTrue, true)
- return
- }
- bgenx(n, res, wantTrue, 0, nil)
-}
-
-// bvgenjump implements boolean value generation using jumps:
-// if n == wantTrue {
-// res = 1
-// } else {
-// res = 0
-// }
-// geninit controls whether n's Ninit is generated.
-func bvgenjump(n, res *Node, wantTrue, geninit bool) {
- init := n.Ninit
- if !geninit {
- n.Ninit.Set(nil)
- }
- p1 := Gbranch(obj.AJMP, nil, 0)
- p2 := Pc
- Thearch.Gmove(Nodbool(true), res)
- p3 := Gbranch(obj.AJMP, nil, 0)
- Patch(p1, Pc)
- Bgen(n, wantTrue, 0, p2)
- Thearch.Gmove(Nodbool(false), res)
- Patch(p3, Pc)
- n.Ninit.MoveNodes(&init)
-}
-
-// bgenx is the backend for Bgen and Bvgen.
-// If res is nil, it generates a branch.
-// Otherwise, it generates a boolean value.
-func bgenx(n, res *Node, wantTrue bool, likely int, to *obj.Prog) {
- if Debug['g'] != 0 {
- fmt.Printf("\nbgenx wantTrue=%t likely=%d to=%v\n", wantTrue, likely, to)
- Dump("n", n)
- Dump("res", res)
- }
-
- genval := res != nil
-
- if n == nil {
- n = Nodbool(true)
- }
-
- Genlist(n.Ninit)
-
- if n.Type == nil {
- n = convlit(n, Types[TBOOL])
- if n.Type == nil {
- return
- }
- }
-
- if !n.Type.IsBoolean() {
- Fatalf("bgen: bad type %v for %v", n.Type, n.Op)
- }
-
- for n.Op == OCONVNOP {
- n = n.Left
- Genlist(n.Ninit)
- }
-
- if Thearch.Bgen_float != nil && n.Left != nil && n.Left.Type.IsFloat() {
- if genval {
- bvgenjump(n, res, wantTrue, false)
- return
- }
- Thearch.Bgen_float(n, wantTrue, likely, to)
- return
- }
-
- switch n.Op {
- default:
- if genval {
- Cgen(n, res)
- if !wantTrue {
- Thearch.Gins(Thearch.Optoas(OXOR, Types[TUINT8]), Nodintconst(1), res)
- }
- return
- }
-
- var tmp Node
- Regalloc(&tmp, n.Type, nil)
- Cgen(n, &tmp)
- bgenNonZero(&tmp, nil, wantTrue, likely, to)
- Regfree(&tmp)
- return
-
- case ONAME:
- // Some architectures might need a temporary or other help here,
- // but they don't support direct generation of a bool value yet.
- // We can fix that as we go.
- mayNeedTemp := Ctxt.Arch.InFamily(sys.ARM, sys.ARM64, sys.MIPS64, sys.PPC64, sys.S390X)
-
- if genval {
- if mayNeedTemp {
- Fatalf("genval ONAMES not fully implemented")
- }
- Cgen(n, res)
- if !wantTrue {
- Thearch.Gins(Thearch.Optoas(OXOR, Types[TUINT8]), Nodintconst(1), res)
- }
- return
- }
-
- if n.Addable && !mayNeedTemp {
- // no need for a temporary
- bgenNonZero(n, nil, wantTrue, likely, to)
- return
- }
- var tmp Node
- Regalloc(&tmp, n.Type, nil)
- Cgen(n, &tmp)
- bgenNonZero(&tmp, nil, wantTrue, likely, to)
- Regfree(&tmp)
- return
-
- case OLITERAL:
- // n is a constant.
- if !Isconst(n, CTBOOL) {
- Fatalf("bgen: non-bool const %v\n", Nconv(n, FmtLong))
- }
- if genval {
- Cgen(Nodbool(wantTrue == n.Val().U.(bool)), res)
- return
- }
- // If n == wantTrue, jump; otherwise do nothing.
- if wantTrue == n.Val().U.(bool) {
- Patch(Gbranch(obj.AJMP, nil, likely), to)
- }
- return
-
- case OANDAND, OOROR:
- and := (n.Op == OANDAND) == wantTrue
- if genval {
- p1 := Gbranch(obj.AJMP, nil, 0)
- p2 := Gbranch(obj.AJMP, nil, 0)
- Patch(p2, Pc)
- Cgen(Nodbool(!and), res)
- p3 := Gbranch(obj.AJMP, nil, 0)
- Patch(p1, Pc)
- Bgen(n.Left, wantTrue != and, 0, p2)
- Bvgen(n.Right, res, wantTrue)
- Patch(p3, Pc)
- return
- }
-
- if and {
- p1 := Gbranch(obj.AJMP, nil, 0)
- p2 := Gbranch(obj.AJMP, nil, 0)
- Patch(p1, Pc)
- Bgen(n.Left, !wantTrue, -likely, p2)
- Bgen(n.Right, !wantTrue, -likely, p2)
- p1 = Gbranch(obj.AJMP, nil, 0)
- Patch(p1, to)
- Patch(p2, Pc)
- } else {
- Bgen(n.Left, wantTrue, likely, to)
- Bgen(n.Right, wantTrue, likely, to)
- }
- return
-
- case ONOT: // unary
- if n.Left == nil || n.Left.Type == nil {
- return
- }
- bgenx(n.Left, res, !wantTrue, likely, to)
- return
-
- case OEQ, ONE, OLT, OGT, OLE, OGE:
- if n.Left == nil || n.Left.Type == nil || n.Right == nil || n.Right.Type == nil {
- return
- }
- }
-
- // n.Op is one of OEQ, ONE, OLT, OGT, OLE, OGE
- nl := n.Left
- nr := n.Right
- op := n.Op
-
- if !wantTrue {
- if nr.Type.IsFloat() {
- // Brcom is not valid on floats when NaN is involved.
- ll := n.Ninit // avoid re-genning Ninit
- n.Ninit.Set(nil)
- if genval {
- bgenx(n, res, true, likely, to)
- Thearch.Gins(Thearch.Optoas(OXOR, Types[TUINT8]), Nodintconst(1), res) // res = !res
- n.Ninit.Set(ll.Slice())
- return
- }
- p1 := Gbranch(obj.AJMP, nil, 0)
- p2 := Gbranch(obj.AJMP, nil, 0)
- Patch(p1, Pc)
- bgenx(n, res, true, -likely, p2)
- Patch(Gbranch(obj.AJMP, nil, 0), to)
- Patch(p2, Pc)
- n.Ninit.Set(ll.Slice())
- return
- }
-
- op = Brcom(op)
- }
- wantTrue = true
-
- // make simplest on right
- if nl.Op == OLITERAL || (nl.Ullman < nr.Ullman && nl.Ullman < UINF) {
- op = Brrev(op)
- nl, nr = nr, nl
- }
-
- if nl.Type.IsSlice() || nl.Type.IsInterface() {
- // front end should only leave cmp to literal nil
- if (op != OEQ && op != ONE) || nr.Op != OLITERAL {
- if nl.Type.IsSlice() {
- Yyerror("illegal slice comparison")
- } else {
- Yyerror("illegal interface comparison")
- }
- return
- }
-
- var ptr Node
- Igen(nl, &ptr, nil)
- if nl.Type.IsSlice() {
- ptr.Xoffset += int64(Array_array)
- }
- ptr.Type = Types[Tptr]
- var tmp Node
- Regalloc(&tmp, ptr.Type, &ptr)
- Cgen(&ptr, &tmp)
- Regfree(&ptr)
- bgenNonZero(&tmp, res, op == OEQ != wantTrue, likely, to)
- Regfree(&tmp)
- return
- }
-
- if nl.Type.IsComplex() {
- complexbool(op, nl, nr, res, wantTrue, likely, to)
- return
- }
-
- if Ctxt.Arch.RegSize == 4 && Is64(nr.Type) {
- if genval {
- // TODO: Teach Cmp64 to generate boolean values and remove this.
- bvgenjump(n, res, wantTrue, false)
- return
- }
- if !nl.Addable || Isconst(nl, CTINT) {
- nl = CgenTemp(nl)
- }
- if !nr.Addable {
- nr = CgenTemp(nr)
- }
- Thearch.Cmp64(nl, nr, op, likely, to)
- return
- }
-
- if nr.Ullman >= UINF {
- var n1 Node
- Regalloc(&n1, nl.Type, nil)
- Cgen(nl, &n1)
- nl = &n1
-
- var tmp Node
- Tempname(&tmp, nl.Type)
- Thearch.Gmove(&n1, &tmp)
- Regfree(&n1)
-
- var n2 Node
- Regalloc(&n2, nr.Type, nil)
- Cgen(nr, &n2)
- nr = &n2
-
- Regalloc(&n1, nl.Type, nil)
- Cgen(&tmp, &n1)
- Regfree(&n1)
- Regfree(&n2)
- } else {
- var n1 Node
- if !nl.Addable && Ctxt.Arch.Family == sys.I386 {
- Tempname(&n1, nl.Type)
- } else {
- Regalloc(&n1, nl.Type, nil)
- defer Regfree(&n1)
- }
- Cgen(nl, &n1)
- nl = &n1
-
- if Smallintconst(nr) && Ctxt.Arch.Family != sys.MIPS64 && Ctxt.Arch.Family != sys.PPC64 {
- Thearch.Gins(Thearch.Optoas(OCMP, nr.Type), nl, nr)
- bins(nr.Type, res, op, likely, to)
- return
- }
-
- if !nr.Addable && Ctxt.Arch.Family == sys.I386 {
- nr = CgenTemp(nr)
- }
-
- var n2 Node
- Regalloc(&n2, nr.Type, nil)
- Cgen(nr, &n2)
- nr = &n2
- Regfree(&n2)
- }
-
- l, r := nl, nr
-
- // On x86, only < and <= work right with NaN; reverse if needed
- if Ctxt.Arch.Family == sys.AMD64 && nl.Type.IsFloat() && (op == OGT || op == OGE) {
- l, r = r, l
- op = Brrev(op)
- }
-
- // MIPS does not have CMP instruction
- if Ctxt.Arch.Family == sys.MIPS64 {
- p := Thearch.Ginscmp(op, nr.Type, l, r, likely)
- Patch(p, to)
- return
- }
-
- // Do the comparison.
- Thearch.Gins(Thearch.Optoas(OCMP, nr.Type), l, r)
-
- // Handle floating point special cases.
- // Note that 8g has Bgen_float and is handled above.
- if nl.Type.IsFloat() {
- switch Ctxt.Arch.Family {
- case sys.ARM:
- if genval {
- Fatalf("genval 5g Isfloat special cases not implemented")
- }
- switch n.Op {
- case ONE:
- Patch(Gbranch(Thearch.Optoas(OPS, nr.Type), nr.Type, likely), to)
- Patch(Gbranch(Thearch.Optoas(op, nr.Type), nr.Type, likely), to)
- default:
- p := Gbranch(Thearch.Optoas(OPS, nr.Type), nr.Type, -likely)
- Patch(Gbranch(Thearch.Optoas(op, nr.Type), nr.Type, likely), to)
- Patch(p, Pc)
- }
- return
- case sys.AMD64:
- switch n.Op {
- case OEQ:
- // neither NE nor P
- if genval {
- var reg Node
- Regalloc(®, Types[TBOOL], nil)
- Thearch.Ginsboolval(Thearch.Optoas(OEQ, nr.Type), ®)
- Thearch.Ginsboolval(Thearch.Optoas(OPC, nr.Type), res)
- Thearch.Gins(Thearch.Optoas(OAND, Types[TBOOL]), ®, res)
- Regfree(®)
- } else {
- p1 := Gbranch(Thearch.Optoas(ONE, nr.Type), nil, -likely)
- p2 := Gbranch(Thearch.Optoas(OPS, nr.Type), nil, -likely)
- Patch(Gbranch(obj.AJMP, nil, 0), to)
- Patch(p1, Pc)
- Patch(p2, Pc)
- }
- return
- case ONE:
- // either NE or P
- if genval {
- var reg Node
- Regalloc(®, Types[TBOOL], nil)
- Thearch.Ginsboolval(Thearch.Optoas(ONE, nr.Type), ®)
- Thearch.Ginsboolval(Thearch.Optoas(OPS, nr.Type), res)
- Thearch.Gins(Thearch.Optoas(OOR, Types[TBOOL]), ®, res)
- Regfree(®)
- } else {
- Patch(Gbranch(Thearch.Optoas(ONE, nr.Type), nil, likely), to)
- Patch(Gbranch(Thearch.Optoas(OPS, nr.Type), nil, likely), to)
- }
- return
- }
- case sys.ARM64, sys.PPC64:
- if genval {
- Fatalf("genval 7g, 9g Isfloat special cases not implemented")
- }
- switch n.Op {
- // On arm64 and ppc64, <= and >= mishandle NaN. Must decompose into < or > and =.
- // TODO(josh): Convert a <= b to b > a instead?
- case OLE, OGE:
- if op == OLE {
- op = OLT
- } else {
- op = OGT
- }
- Patch(Gbranch(Thearch.Optoas(op, nr.Type), nr.Type, likely), to)
- Patch(Gbranch(Thearch.Optoas(OEQ, nr.Type), nr.Type, likely), to)
- return
- }
- }
- }
-
- // Not a special case. Insert the conditional jump or value gen.
- bins(nr.Type, res, op, likely, to)
-}
-
-func bgenNonZero(n, res *Node, wantTrue bool, likely int, to *obj.Prog) {
- // TODO: Optimize on systems that can compare to zero easily.
- var op Op = ONE
- if !wantTrue {
- op = OEQ
- }
-
- // MIPS does not have CMP instruction
- if Thearch.LinkArch.Family == sys.MIPS64 {
- p := Gbranch(Thearch.Optoas(op, n.Type), n.Type, likely)
- Naddr(&p.From, n)
- Patch(p, to)
- return
- }
-
- var zero Node
- Nodconst(&zero, n.Type, 0)
- Thearch.Gins(Thearch.Optoas(OCMP, n.Type), n, &zero)
- bins(n.Type, res, op, likely, to)
-}
-
-// bins inserts an instruction to handle the result of a compare.
-// If res is non-nil, it inserts appropriate value generation instructions.
-// If res is nil, it inserts a branch to to.
-func bins(typ *Type, res *Node, op Op, likely int, to *obj.Prog) {
- a := Thearch.Optoas(op, typ)
- if res != nil {
- // value gen
- Thearch.Ginsboolval(a, res)
- } else {
- // jump
- Patch(Gbranch(a, typ, likely), to)
- }
-}
-
-// stkof returns n's offset from SP if n is on the stack
-// (either a local variable or the return value from a function call
-// or the arguments to a function call).
-// If n is not on the stack, stkof returns -1000.
-// If n is on the stack but in an unknown location
-// (due to array index arithmetic), stkof returns +1000.
-//
-// NOTE(rsc): It is possible that the ODOT and OINDEX cases
-// are not relevant here, since it shouldn't be possible for them
-// to be involved in an overlapping copy. Only function results
-// from one call and the arguments to the next can overlap in
-// any non-trivial way. If they can be dropped, then this function
-// becomes much simpler and also more trustworthy.
-// The fact that it works at all today is probably due to the fact
-// that ODOT and OINDEX are irrelevant.
-func stkof(n *Node) int64 {
- switch n.Op {
- case OINDREG:
- if n.Reg != int16(Thearch.REGSP) {
- return -1000 // not on stack
- }
- return n.Xoffset
-
- case ODOT:
- t := n.Left.Type
- if t.IsPtr() {
- break
- }
- off := stkof(n.Left)
- if off == -1000 || off == +1000 {
- return off
- }
- return off + n.Xoffset
-
- case OINDEX:
- t := n.Left.Type
- if !t.IsArray() {
- break
- }
- off := stkof(n.Left)
- if off == -1000 || off == +1000 {
- return off
- }
- if Isconst(n.Right, CTINT) {
- return off + t.Elem().Width*n.Right.Int64()
- }
- return +1000 // on stack but not sure exactly where
-
- case OCALLMETH, OCALLINTER, OCALLFUNC:
- t := n.Left.Type
- if t.IsPtr() {
- t = t.Elem()
- }
-
- f := t.Results().Field(0)
- if f != nil {
- return f.Offset + Ctxt.FixedFrameSize()
- }
- }
-
- // botch - probably failing to recognize address
- // arithmetic on the above. eg INDEX and DOT
- return -1000 // not on stack
-}
-
-// block copy:
-// memmove(&ns, &n, w);
-// if wb is true, needs write barrier.
-func sgen_wb(n *Node, ns *Node, w int64, wb bool) {
- if Debug['g'] != 0 {
- op := "sgen"
- if wb {
- op = "sgen-wb"
- }
- fmt.Printf("\n%s w=%d\n", op, w)
- Dump("r", n)
- Dump("res", ns)
- }
-
- if n.Ullman >= UINF && ns.Ullman >= UINF {
- Fatalf("sgen UINF")
- }
-
- if w < 0 {
- Fatalf("sgen copy %d", w)
- }
-
- // If copying .args, that's all the results, so record definition sites
- // for them for the liveness analysis.
- if ns.Op == ONAME && ns.Sym.Name == ".args" {
- for _, ln := range Curfn.Func.Dcl {
- if ln.Class == PPARAMOUT {
- Gvardef(ln)
- }
- }
- }
-
- // Avoid taking the address for simple enough types.
- if componentgen_wb(n, ns, wb) {
- return
- }
-
- if w == 0 {
- // evaluate side effects only
- var nodr Node
- Regalloc(&nodr, Types[Tptr], nil)
- Agen(ns, &nodr)
- Agen(n, &nodr)
- Regfree(&nodr)
- return
- }
-
- // offset on the stack
- osrc := stkof(n)
- odst := stkof(ns)
-
- if odst != -1000 {
- // on stack, write barrier not needed after all
- wb = false
- }
-
- if osrc != -1000 && odst != -1000 && (osrc == 1000 || odst == 1000) || wb && osrc != -1000 {
- // osrc and odst both on stack, and at least one is in
- // an unknown position. Could generate code to test
- // for forward/backward copy, but instead just copy
- // to a temporary location first.
- //
- // OR: write barrier needed and source is on stack.
- // Invoking the write barrier will use the stack to prepare its call.
- // Copy to temporary.
- var tmp Node
- Tempname(&tmp, n.Type)
- sgen_wb(n, &tmp, w, false)
- sgen_wb(&tmp, ns, w, wb)
- return
- }
-
- if wb {
- cgen_wbfat(n, ns)
- return
- }
-
- Thearch.Blockcopy(n, ns, osrc, odst, w)
-}
-
-// generate:
-// call f
-// proc=-1 normal call but no return
-// proc=0 normal call
-// proc=1 goroutine run in new proc
-// proc=2 defer call save away stack
-// proc=3 normal call to C pointer (not Go func value)
-func Ginscall(f *Node, proc int) {
- if f.Type != nil {
- extra := int32(0)
- if proc == 1 || proc == 2 {
- extra = 2 * int32(Widthptr)
- }
- Setmaxarg(f.Type, extra)
- }
-
- switch proc {
- default:
- Fatalf("Ginscall: bad proc %d", proc)
-
- case 0, // normal call
- -1: // normal call but no return
- if f.Op == ONAME && f.Class == PFUNC {
- if f == Deferreturn {
- // Deferred calls will appear to be returning to the CALL
- // deferreturn(SB) that we are about to emit. However, the
- // stack scanning code will think that the instruction
- // before the CALL is executing. To avoid the scanning
- // code making bad assumptions (both cosmetic such as
- // showing the wrong line number and fatal, such as being
- // confused over whether a stack slot contains a pointer
- // or a scalar) 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()
-
- if Thearch.LinkArch.Family == sys.PPC64 {
- // On ppc64, when compiling Go into position
- // independent code on ppc64le we insert an
- // instruction to reload the TOC pointer from the
- // 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.
- if Ctxt.Flag_shared {
- p := Thearch.Gins(ppc64.AMOVD, nil, nil)
- 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 {
- Thearch.Ginsnop()
- }
- }
- }
-
- p := Thearch.Gins(obj.ACALL, nil, f)
- Afunclit(&p.To, f)
- if proc == -1 || Noreturn(p) {
- Thearch.Gins(obj.AUNDEF, nil, nil)
- }
- break
- }
-
- var reg Node
- Nodreg(®, Types[Tptr], Thearch.REGCTXT)
- var r1 Node
- Nodreg(&r1, Types[Tptr], Thearch.REGCALLX)
- Thearch.Gmove(f, ®)
- reg.Op = OINDREG
- Thearch.Gmove(®, &r1)
- reg.Op = OREGISTER
- Thearch.Gins(obj.ACALL, ®, &r1)
-
- case 3: // normal call of c function pointer
- Thearch.Gins(obj.ACALL, nil, f)
-
- case 1, // call in new proc (go)
- 2: // deferred call (defer)
- var stk Node
-
- // size of arguments at 0(SP)
- stk.Op = OINDREG
- stk.Reg = int16(Thearch.REGSP)
- stk.Xoffset = Ctxt.FixedFrameSize()
- Thearch.Ginscon(Thearch.Optoas(OAS, Types[TINT32]), int64(Argsize(f.Type)), &stk)
-
- // FuncVal* at 8(SP)
- stk.Xoffset = int64(Widthptr) + Ctxt.FixedFrameSize()
-
- var reg Node
- Nodreg(®, Types[Tptr], Thearch.REGCALLX2)
- Thearch.Gmove(f, ®)
- Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), ®, &stk)
-
- if proc == 1 {
- Ginscall(Newproc, 0)
- } else {
- if !hasdefer {
- Fatalf("hasdefer=0 but has defer")
- }
- Ginscall(Deferproc, 0)
- }
-
- if proc == 2 {
- Nodreg(®, Types[TINT32], Thearch.REGRETURN)
- p := Thearch.Ginscmp(OEQ, Types[TINT32], ®, Nodintconst(0), +1)
- cgen_ret(nil)
- Patch(p, Pc)
- }
- }
-}
-
-// n is call to interface method.
-// generate res = n.
-func cgen_callinter(n *Node, res *Node, proc int) {
- i := n.Left
- if i.Op != ODOTINTER {
- Fatalf("cgen_callinter: not ODOTINTER %v", i.Op)
- }
-
- i = i.Left // interface
-
- if !i.Addable {
- var tmpi Node
- Tempname(&tmpi, i.Type)
- Cgen(i, &tmpi)
- i = &tmpi
- }
-
- Genlist(n.List) // assign the args
-
- // i is now addable, prepare an indirected
- // register to hold its address.
- var nodi Node
- Igen(i, &nodi, res) // REG = &inter
-
- var nodsp Node
- Nodindreg(&nodsp, Types[Tptr], Thearch.REGSP)
- nodsp.Xoffset = Ctxt.FixedFrameSize()
- if proc != 0 {
- nodsp.Xoffset += 2 * int64(Widthptr) // leave room for size & fn
- }
- nodi.Type = Types[Tptr]
- nodi.Xoffset += int64(Widthptr)
- Cgen(&nodi, &nodsp) // {0, 8(nacl), or 16}(SP) = 8(REG) -- i.data
-
- var nodo Node
- Regalloc(&nodo, Types[Tptr], res)
-
- nodi.Type = Types[Tptr]
- nodi.Xoffset -= int64(Widthptr)
- Cgen(&nodi, &nodo) // REG = 0(REG) -- i.tab
- Regfree(&nodi)
-
- var nodr Node
- Regalloc(&nodr, Types[Tptr], &nodo)
- if n.Left.Xoffset == BADWIDTH {
- Fatalf("cgen_callinter: badwidth")
- }
- Cgen_checknil(&nodo) // in case offset is huge
- nodo.Op = OINDREG
- nodo.Xoffset = n.Left.Xoffset + 3*int64(Widthptr) + 8
- if proc == 0 {
- // plain call: use direct c function pointer - more efficient
- Cgen(&nodo, &nodr) // REG = 32+offset(REG) -- i.tab->fun[f]
- proc = 3
- } else {
- // go/defer. generate go func value.
- Agen(&nodo, &nodr) // REG = &(32+offset(REG)) -- i.tab->fun[f]
- }
-
- nodr.Type = n.Left.Type
- Ginscall(&nodr, proc)
-
- Regfree(&nodr)
- Regfree(&nodo)
-}
-
-// generate function call;
-// proc=0 normal call
-// proc=1 goroutine run in new proc
-// proc=2 defer call save away stack
-func cgen_call(n *Node, proc int) {
- if n == nil {
- return
- }
-
- var afun Node
- if n.Left.Ullman >= UINF {
- // if name involves a fn call
- // precompute the address of the fn
- Tempname(&afun, Types[Tptr])
-
- Cgen(n.Left, &afun)
- }
-
- Genlist(n.List) // assign the args
- t := n.Left.Type
-
- // call tempname pointer
- if n.Left.Ullman >= UINF {
- var nod Node
- Regalloc(&nod, Types[Tptr], nil)
- Cgen_as(&nod, &afun)
- nod.Type = t
- Ginscall(&nod, proc)
- Regfree(&nod)
- return
- }
-
- // call pointer
- if n.Left.Op != ONAME || n.Left.Class != PFUNC {
- var nod Node
- Regalloc(&nod, Types[Tptr], nil)
- Cgen_as(&nod, n.Left)
- nod.Type = t
- Ginscall(&nod, proc)
- Regfree(&nod)
- return
- }
-
- // call direct
- n.Left.Name.Method = true
-
- Ginscall(n.Left, proc)
-}
-
-// call to n has already been generated.
-// generate:
-// res = return value from call.
-func cgen_callret(n *Node, res *Node) {
- t := n.Left.Type
- if t.Etype == TPTR32 || t.Etype == TPTR64 {
- t = t.Elem()
- }
-
- fp := t.Results().Field(0)
- if fp == nil {
- Fatalf("cgen_callret: nil")
- }
-
- var nod Node
- nod.Op = OINDREG
- nod.Reg = int16(Thearch.REGSP)
- nod.Addable = true
-
- nod.Xoffset = fp.Offset + Ctxt.FixedFrameSize()
- nod.Type = fp.Type
- Cgen_as(res, &nod)
-}
-
-// call to n has already been generated.
-// generate:
-// res = &return value from call.
-func cgen_aret(n *Node, res *Node) {
- t := n.Left.Type
- if t.IsPtr() {
- t = t.Elem()
- }
-
- fp := t.Results().Field(0)
- if fp == nil {
- Fatalf("cgen_aret: nil")
- }
-
- var nod1 Node
- nod1.Op = OINDREG
- nod1.Reg = int16(Thearch.REGSP)
- nod1.Addable = true
- nod1.Xoffset = fp.Offset + Ctxt.FixedFrameSize()
- nod1.Type = fp.Type
-
- if res.Op != OREGISTER {
- var nod2 Node
- Regalloc(&nod2, Types[Tptr], res)
- Agen(&nod1, &nod2)
- Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), &nod2, res)
- Regfree(&nod2)
- } else {
- Agen(&nod1, res)
- }
-}
-
-// generate return.
-// n->left is assignments to return values.
-func cgen_ret(n *Node) {
- if n != nil {
- Genlist(n.List) // copy out args
- }
- if hasdefer {
- Ginscall(Deferreturn, 0)
- }
- Genlist(Curfn.Func.Exit)
- p := Thearch.Gins(obj.ARET, nil, nil)
- if n != nil && n.Op == ORETJMP {
- p.To.Type = obj.TYPE_MEM
- p.To.Name = obj.NAME_EXTERN
- p.To.Sym = Linksym(n.Left.Sym)
- }
-}
-
-// hasHMUL64 reports whether the architecture supports 64-bit
-// signed and unsigned high multiplication (OHMUL).
-func hasHMUL64() bool {
- switch Ctxt.Arch.Family {
- case sys.AMD64, sys.S390X, sys.ARM64:
- return true
- case sys.ARM, sys.I386, sys.MIPS64, sys.PPC64:
- return false
- }
- Fatalf("unknown architecture")
- return false
-}
-
-// hasRROTC64 reports whether the architecture supports 64-bit
-// rotate through carry instructions (ORROTC).
-func hasRROTC64() bool {
- switch Ctxt.Arch.Family {
- case sys.AMD64:
- return true
- case sys.ARM, sys.ARM64, sys.I386, sys.MIPS64, sys.PPC64, sys.S390X:
- return false
- }
- Fatalf("unknown architecture")
- return false
-}
-
-func hasRightShiftWithCarry() bool {
- switch Ctxt.Arch.Family {
- case sys.ARM64:
- return true
- case sys.AMD64, sys.ARM, sys.I386, sys.MIPS64, sys.PPC64, sys.S390X:
- return false
- }
- Fatalf("unknown architecture")
- return false
-}
-
-func hasAddSetCarry() bool {
- switch Ctxt.Arch.Family {
- case sys.ARM64:
- return true
- case sys.AMD64, sys.ARM, sys.I386, sys.MIPS64, sys.PPC64, sys.S390X:
- return false
- }
- Fatalf("unknown architecture")
- return false
-}
-
-// generate division according to op, one of:
-// res = nl / nr
-// res = nl % nr
-func cgen_div(op Op, nl *Node, nr *Node, res *Node) {
- var w int
-
- // Architectures need to support 64-bit high multiplications
- // (OHMUL) in order to perform divide by constant optimizations.
- if nr.Op != OLITERAL || !hasHMUL64() {
- goto longdiv
- }
- w = int(nl.Type.Width * 8)
-
- // Front end handled 32-bit division. We only need to handle 64-bit.
- // Try to do division using multiplication: (2^w)/d.
- // See Hacker's Delight, chapter 10.
- switch Simtype[nl.Type.Etype] {
- default:
- goto longdiv
-
- case TUINT64:
- var m Magic
- m.W = w
- m.Ud = uint64(nr.Int64())
- Umagic(&m)
- if m.Bad != 0 {
- break
- }
-
- // In order to add the numerator we need to be able to
- // avoid overflow. This is done by shifting the result of the
- // addition right by 1 and inserting the carry bit into
- // the MSB. For now this needs the RROTC instruction.
- // TODO(mundaym): Hacker's Delight 2nd ed. chapter 10 proposes
- // an alternative sequence of instructions for architectures
- // (TODO: MIPS64, PPC64, S390X) that do not have a shift
- // right with carry instruction.
- if m.Ua != 0 && !hasRROTC64() && !hasRightShiftWithCarry() {
- goto longdiv
- }
- if op == OMOD {
- goto longmod
- }
-
- var n1 Node
- Cgenr(nl, &n1, nil)
- var n2 Node
- Nodconst(&n2, nl.Type, int64(m.Um))
- var n3 Node
- Regalloc(&n3, nl.Type, res)
- Thearch.Cgen_hmul(&n1, &n2, &n3)
-
- if m.Ua != 0 {
- // Need to add numerator accounting for overflow.
- if hasAddSetCarry() {
- Thearch.AddSetCarry(&n1, &n3, &n3)
- } else {
- Thearch.Gins(Thearch.Optoas(OADD, nl.Type), &n1, &n3)
- }
-
- if !hasRROTC64() {
- Thearch.RightShiftWithCarry(&n3, uint(m.S), &n3)
- } else {
- Nodconst(&n2, nl.Type, 1)
- Thearch.Gins(Thearch.Optoas(ORROTC, nl.Type), &n2, &n3)
- Nodconst(&n2, nl.Type, int64(m.S)-1)
- Thearch.Gins(Thearch.Optoas(ORSH, nl.Type), &n2, &n3)
- }
- } else {
- Nodconst(&n2, nl.Type, int64(m.S))
- Thearch.Gins(Thearch.Optoas(ORSH, nl.Type), &n2, &n3) // shift dx
- }
-
- Thearch.Gmove(&n3, res)
- Regfree(&n1)
- Regfree(&n3)
- return
-
- case TINT64:
- var m Magic
- m.W = w
- m.Sd = nr.Int64()
- Smagic(&m)
- if m.Bad != 0 {
- break
- }
- if op == OMOD {
- goto longmod
- }
-
- var n1 Node
- Cgenr(nl, &n1, res)
- var n2 Node
- Nodconst(&n2, nl.Type, m.Sm)
- var n3 Node
- Regalloc(&n3, nl.Type, nil)
- Thearch.Cgen_hmul(&n1, &n2, &n3)
-
- if m.Sm < 0 {
- // Need to add numerator (cannot overflow).
- Thearch.Gins(Thearch.Optoas(OADD, nl.Type), &n1, &n3)
- }
-
- Nodconst(&n2, nl.Type, int64(m.S))
- Thearch.Gins(Thearch.Optoas(ORSH, nl.Type), &n2, &n3) // shift n3
-
- Nodconst(&n2, nl.Type, int64(w)-1)
-
- Thearch.Gins(Thearch.Optoas(ORSH, nl.Type), &n2, &n1) // -1 iff num is neg
- Thearch.Gins(Thearch.Optoas(OSUB, nl.Type), &n1, &n3) // added
-
- if m.Sd < 0 {
- // This could probably be removed by factoring it into
- // the multiplier.
- Thearch.Gins(Thearch.Optoas(OMINUS, nl.Type), nil, &n3)
- }
-
- Thearch.Gmove(&n3, res)
- Regfree(&n1)
- Regfree(&n3)
- return
- }
-
- goto longdiv
-
- // Division and mod using (slow) hardware instruction.
-longdiv:
- Thearch.Dodiv(op, nl, nr, res)
-
- return
-
- // Mod using formula A%B = A-(A/B*B) but
- // we know that there is a fast algorithm for A/B.
-longmod:
- var n1 Node
- Regalloc(&n1, nl.Type, res)
-
- Cgen(nl, &n1)
- var n2 Node
- Regalloc(&n2, nl.Type, nil)
- cgen_div(ODIV, &n1, nr, &n2)
- a := Thearch.Optoas(OMUL, nl.Type)
-
- if !Smallintconst(nr) {
- var n3 Node
- Regalloc(&n3, nl.Type, nil)
- Cgen(nr, &n3)
- Thearch.Gins(a, &n3, &n2)
- Regfree(&n3)
- } else {
- Thearch.Gins(a, nr, &n2)
- }
- Thearch.Gins(Thearch.Optoas(OSUB, nl.Type), &n2, &n1)
- Thearch.Gmove(&n1, res)
- Regfree(&n1)
- Regfree(&n2)
-}
-
-func Fixlargeoffset(n *Node) {
- if n == nil {
- return
- }
- if n.Op != OINDREG {
- return
- }
- if n.Reg == int16(Thearch.REGSP) { // stack offset cannot be large
- return
- }
- if n.Xoffset != int64(int32(n.Xoffset)) {
- // offset too large, add to register instead.
- a := *n
-
- a.Op = OREGISTER
- a.Type = Types[Tptr]
- a.Xoffset = 0
- Cgen_checknil(&a)
- Thearch.Ginscon(Thearch.Optoas(OADD, Types[Tptr]), n.Xoffset, &a)
- n.Xoffset = 0
- }
-}
-
-func cgen_append(n, res *Node) {
- if Debug['g'] != 0 {
- Dump("cgen_append-n", n)
- Dump("cgen_append-res", res)
- }
- for _, n1 := range n.List.Slice() {
- if n1.Ullman >= UINF {
- Fatalf("append with function call arguments")
- }
- }
-
- // res = append(src, x, y, z)
- //
- // If res and src are the same, we can avoid writing to base and cap
- // unless we grow the underlying array.
- needFullUpdate := !samesafeexpr(res, n.List.First())
-
- // Copy src triple into base, len, cap.
- base := temp(Types[Tptr])
- len := temp(Types[TUINT])
- cap := temp(Types[TUINT])
-
- var src Node
- Igen(n.List.First(), &src, nil)
- src.Type = Types[Tptr]
- Thearch.Gmove(&src, base)
- src.Type = Types[TUINT]
- src.Xoffset += int64(Widthptr)
- Thearch.Gmove(&src, len)
- src.Xoffset += int64(Widthptr)
- Thearch.Gmove(&src, cap)
-
- // if len+argc <= cap goto L1
- var rlen Node
- Regalloc(&rlen, Types[TUINT], nil)
- Thearch.Gmove(len, &rlen)
- Thearch.Ginscon(Thearch.Optoas(OADD, Types[TUINT]), int64(n.List.Len()-1), &rlen)
- p := Thearch.Ginscmp(OLE, Types[TUINT], &rlen, cap, +1)
- // Note: rlen and src are Regrealloc'ed below at the target of the
- // branch we just emitted; do not reuse these Go variables for
- // other purposes. They need to still describe the same things
- // below that they describe right here.
- Regfree(&src)
-
- // base, len, cap = growslice(type, base, len, cap, newlen)
- var arg Node
- arg.Op = OINDREG
- arg.Reg = int16(Thearch.REGSP)
- arg.Addable = true
- arg.Xoffset = Ctxt.FixedFrameSize()
- arg.Type = Ptrto(Types[TUINT8])
- Cgen(typename(res.Type.Elem()), &arg)
- arg.Xoffset += int64(Widthptr)
-
- arg.Type = Types[Tptr]
- Cgen(base, &arg)
- arg.Xoffset += int64(Widthptr)
-
- arg.Type = Types[TUINT]
- Cgen(len, &arg)
- arg.Xoffset += int64(Widthptr)
-
- arg.Type = Types[TUINT]
- Cgen(cap, &arg)
- arg.Xoffset += int64(Widthptr)
-
- arg.Type = Types[TUINT]
- Cgen(&rlen, &arg)
- arg.Xoffset += int64(Widthptr)
- Regfree(&rlen)
-
- fn := syslook("growslice")
- fn = substArgTypes(fn, res.Type.Elem(), res.Type.Elem())
- Ginscall(fn, 0)
-
- if Widthptr == 4 && Widthreg == 8 {
- arg.Xoffset += 4
- }
-
- arg.Type = Types[Tptr]
- Cgen(&arg, base)
- arg.Xoffset += int64(Widthptr)
-
- arg.Type = Types[TUINT]
- Cgen(&arg, len)
- arg.Xoffset += int64(Widthptr)
-
- arg.Type = Types[TUINT]
- Cgen(&arg, cap)
-
- // Update res with base, len+argc, cap.
- if needFullUpdate {
- if Debug_append > 0 {
- Warn("append: full update")
- }
- Patch(p, Pc)
- }
- if res.Op == ONAME {
- Gvardef(res)
- }
- var dst, r1 Node
- Igen(res, &dst, nil)
- dst.Type = Types[TUINT]
- dst.Xoffset += int64(Widthptr)
- Regalloc(&r1, Types[TUINT], nil)
- Thearch.Gmove(len, &r1)
- Thearch.Ginscon(Thearch.Optoas(OADD, Types[TUINT]), int64(n.List.Len()-1), &r1)
- Thearch.Gmove(&r1, &dst)
- Regfree(&r1)
- dst.Xoffset += int64(Widthptr)
- Thearch.Gmove(cap, &dst)
- dst.Type = Types[Tptr]
- dst.Xoffset -= 2 * int64(Widthptr)
- cgen_wb(base, &dst, needwritebarrier(&dst, base))
- Regfree(&dst)
-
- if !needFullUpdate {
- if Debug_append > 0 {
- Warn("append: len-only update")
- }
- // goto L2;
- // L1:
- // update len only
- // L2:
- q := Gbranch(obj.AJMP, nil, 0)
- Patch(p, Pc)
- // At the goto above, src refers to cap and rlen holds the new len
- if src.Op == OREGISTER || src.Op == OINDREG {
- Regrealloc(&src)
- }
- Regrealloc(&rlen)
- src.Xoffset -= int64(Widthptr)
- Thearch.Gmove(&rlen, &src)
- Regfree(&src)
- Regfree(&rlen)
- Patch(q, Pc)
- }
-
- // Copy data into place.
- // Could do write barrier check around entire copy instead of each element.
- // Could avoid reloading registers on each iteration if we know the cgen_wb
- // is not going to use a write barrier.
- i := 0
- var r2 Node
- for _, n2 := range n.List.Slice()[1:] {
- Regalloc(&r1, Types[Tptr], nil)
- Thearch.Gmove(base, &r1)
- Regalloc(&r2, Types[TUINT], nil)
- Thearch.Gmove(len, &r2)
- if i > 0 {
- Thearch.Gins(Thearch.Optoas(OADD, Types[TUINT]), Nodintconst(int64(i)), &r2)
- }
- w := res.Type.Elem().Width
- if Thearch.AddIndex != nil && Thearch.AddIndex(&r2, w, &r1) {
- // r1 updated by back end
- } else if w == 1 {
- Thearch.Gins(Thearch.Optoas(OADD, Types[Tptr]), &r2, &r1)
- } else {
- Thearch.Ginscon(Thearch.Optoas(OMUL, Types[TUINT]), w, &r2)
- Thearch.Gins(Thearch.Optoas(OADD, Types[Tptr]), &r2, &r1)
- }
- Regfree(&r2)
-
- r1.Op = OINDREG
- r1.Type = res.Type.Elem()
- cgen_wb(n2, &r1, needwritebarrier(&r1, n2))
- Regfree(&r1)
- i++
- }
-}
-
-// Generate res = n, where n is x[i:j] or x[i:j:k].
-// If wb is true, need write barrier updating res's base pointer.
-// On systems with 32-bit ints, i, j, k are guaranteed to be 32-bit values.
-func cgen_slice(n, res *Node, wb bool) {
- if Debug['g'] != 0 {
- Dump("cgen_slice-n", n)
- Dump("cgen_slice-res", res)
- }
-
- needFullUpdate := !samesafeexpr(n.Left, res)
-
- // orderexpr has made sure that x is safe (but possibly expensive)
- // and i, j, k are cheap. On a system with registers (anything but 386)
- // we can evaluate x first and then know we have enough registers
- // for i, j, k as well.
- var x, xbase, xlen, xcap, i, j, k Node
- if n.Op != OSLICEARR && n.Op != OSLICE3ARR {
- Igen(n.Left, &x, nil)
- }
-
- indexRegType := Types[TUINT]
- if Widthreg > Widthptr { // amd64p32
- indexRegType = Types[TUINT64]
- }
-
- // On most systems, we use registers.
- // The 386 has basically no registers, so substitute functions
- // that can work with temporaries instead.
- regalloc := Regalloc
- ginscon := Thearch.Ginscon
- gins := Thearch.Gins
- if Thearch.LinkArch.Family == sys.I386 {
- regalloc = func(n *Node, t *Type, reuse *Node) {
- Tempname(n, t)
- }
- ginscon = func(as obj.As, c int64, n *Node) {
- var n1 Node
- Regalloc(&n1, n.Type, n)
- Thearch.Gmove(n, &n1)
- Thearch.Ginscon(as, c, &n1)
- Thearch.Gmove(&n1, n)
- Regfree(&n1)
- }
- gins = func(as obj.As, f, t *Node) *obj.Prog {
- var n1 Node
- Regalloc(&n1, t.Type, t)
- Thearch.Gmove(t, &n1)
- Thearch.Gins(as, f, &n1)
- Thearch.Gmove(&n1, t)
- Regfree(&n1)
- return nil
- }
- }
-
- panics := make([]*obj.Prog, 0, 6) // 3 loads + 3 checks
-
- loadlen := func() {
- if xlen.Op != 0 {
- return
- }
- if n.Op == OSLICEARR || n.Op == OSLICE3ARR {
- Nodconst(&xlen, indexRegType, n.Left.Type.Elem().NumElem())
- return
- }
- if n.Op == OSLICESTR && Isconst(n.Left, CTSTR) {
- Nodconst(&xlen, indexRegType, int64(len(n.Left.Val().U.(string))))
- return
- }
- regalloc(&xlen, indexRegType, nil)
- x.Xoffset += int64(Widthptr)
- x.Type = Types[TUINT]
- Thearch.Gmove(&x, &xlen)
- x.Xoffset -= int64(Widthptr)
- }
-
- loadcap := func() {
- if xcap.Op != 0 {
- return
- }
- if n.Op == OSLICEARR || n.Op == OSLICE3ARR || n.Op == OSLICESTR {
- loadlen()
- xcap = xlen
- if xcap.Op == OREGISTER {
- Regrealloc(&xcap)
- }
- return
- }
- regalloc(&xcap, indexRegType, nil)
- x.Xoffset += 2 * int64(Widthptr)
- x.Type = Types[TUINT]
- Thearch.Gmove(&x, &xcap)
- x.Xoffset -= 2 * int64(Widthptr)
- }
-
- x1, x2, x3 := n.SliceBounds() // unevaluated index arguments
-
- // load computes src into targ, but if src refers to the len or cap of n.Left,
- // load copies those from xlen, xcap, loading xlen if needed.
- // If targ.Op == OREGISTER on return, it must be Regfreed,
- // but it should not be modified without first checking whether it is
- // xlen or xcap's register.
- load := func(src, targ *Node) {
- if src == nil {
- return
- }
- switch src.Op {
- case OLITERAL:
- *targ = *src
- return
- case OLEN:
- // NOTE(rsc): This doesn't actually trigger, because order.go
- // has pulled all the len and cap calls into separate assignments
- // to temporaries. There are tests in test/sliceopt.go that could
- // be enabled if this is fixed.
- if samesafeexpr(n.Left, src.Left) {
- if Debug_slice > 0 {
- Warn("slice: reuse len")
- }
- loadlen()
- *targ = xlen
- if targ.Op == OREGISTER {
- Regrealloc(targ)
- }
- return
- }
- case OCAP:
- // NOTE(rsc): This doesn't actually trigger; see note in case OLEN above.
- if samesafeexpr(n.Left, src.Left) {
- if Debug_slice > 0 {
- Warn("slice: reuse cap")
- }
- loadcap()
- *targ = xcap
- if targ.Op == OREGISTER {
- Regrealloc(targ)
- }
- return
- }
- }
- if i.Op != 0 && samesafeexpr(x1, src) {
- if Debug_slice > 0 {
- Warn("slice: reuse 1st index")
- }
- *targ = i
- if targ.Op == OREGISTER {
- Regrealloc(targ)
- }
- return
- }
- if j.Op != 0 && samesafeexpr(x2, src) {
- if Debug_slice > 0 {
- Warn("slice: reuse 2nd index")
- }
- *targ = j
- if targ.Op == OREGISTER {
- Regrealloc(targ)
- }
- return
- }
- if Thearch.Cgenindex != nil {
- regalloc(targ, indexRegType, nil)
- p := Thearch.Cgenindex(src, targ, false)
- if p != nil {
- panics = append(panics, p)
- }
- } else if Thearch.Igenindex != nil {
- p := Thearch.Igenindex(src, targ, false)
- if p != nil {
- panics = append(panics, p)
- }
- } else {
- regalloc(targ, indexRegType, nil)
- var tmp Node
- Cgenr(src, &tmp, targ)
- Thearch.Gmove(&tmp, targ)
- Regfree(&tmp)
- }
- }
-
- load(x1, &i)
- load(x2, &j)
- load(x3, &k)
-
- // i defaults to 0.
- if i.Op == 0 {
- Nodconst(&i, indexRegType, 0)
- }
-
- // j defaults to len(x)
- if j.Op == 0 {
- loadlen()
- j = xlen
- if j.Op == OREGISTER {
- Regrealloc(&j)
- }
- }
-
- // k defaults to cap(x)
- // Only need to load it if we're recalculating cap or doing a full update.
- if k.Op == 0 && n.Op != OSLICESTR && (!iszero(&i) || needFullUpdate) {
- loadcap()
- k = xcap
- if k.Op == OREGISTER {
- Regrealloc(&k)
- }
- }
-
- // Check constant indexes for negative values, and against constant length if known.
- // The func obvious below checks for out-of-order constant indexes.
- var bound int64 = -1
- if n.Op == OSLICEARR || n.Op == OSLICE3ARR {
- bound = n.Left.Type.Elem().NumElem()
- } else if n.Op == OSLICESTR && Isconst(n.Left, CTSTR) {
- bound = int64(len(n.Left.Val().U.(string)))
- }
- if Isconst(&i, CTINT) {
- if i.Val().U.(*Mpint).CmpInt64(0) < 0 || bound >= 0 && i.Val().U.(*Mpint).CmpInt64(bound) > 0 {
- Yyerror("slice index out of bounds")
- }
- }
- if Isconst(&j, CTINT) {
- if j.Val().U.(*Mpint).CmpInt64(0) < 0 || bound >= 0 && j.Val().U.(*Mpint).CmpInt64(bound) > 0 {
- Yyerror("slice index out of bounds")
- }
- }
- if Isconst(&k, CTINT) {
- if k.Val().U.(*Mpint).CmpInt64(0) < 0 || bound >= 0 && k.Val().U.(*Mpint).CmpInt64(bound) > 0 {
- Yyerror("slice index out of bounds")
- }
- }
-
- // same reports whether n1 and n2 are the same register or constant.
- same := func(n1, n2 *Node) bool {
- return n1.Op == OREGISTER && n2.Op == OREGISTER && n1.Reg == n2.Reg ||
- n1.Op == ONAME && n2.Op == ONAME && n1.Orig == n2.Orig && n1.Type == n2.Type && n1.Xoffset == n2.Xoffset ||
- n1.Op == OLITERAL && n2.Op == OLITERAL && n1.Val().U.(*Mpint).Cmp(n2.Val().U.(*Mpint)) == 0
- }
-
- // obvious reports whether n1 <= n2 is obviously true,
- // and it calls Yyerror if n1 <= n2 is obviously false.
- obvious := func(n1, n2 *Node) bool {
- if Debug['B'] != 0 { // -B disables bounds checks
- return true
- }
- if same(n1, n2) {
- return true // n1 == n2
- }
- if iszero(n1) {
- return true // using unsigned compare, so 0 <= n2 always true
- }
- if xlen.Op != 0 && same(n1, &xlen) && xcap.Op != 0 && same(n2, &xcap) {
- return true // len(x) <= cap(x) always true
- }
- if Isconst(n1, CTINT) && Isconst(n2, CTINT) {
- if n1.Val().U.(*Mpint).Cmp(n2.Val().U.(*Mpint)) <= 0 {
- return true // n1, n2 constants such that n1 <= n2
- }
- Yyerror("slice index out of bounds")
- return true
- }
- return false
- }
-
- compare := func(n1, n2 *Node) {
- // n1 might be a 64-bit constant, even on 32-bit architectures,
- // but it will be represented in 32 bits.
- if Ctxt.Arch.RegSize == 4 && Is64(n1.Type) {
- if n1.Val().U.(*Mpint).CmpInt64(1<<31) >= 0 {
- Fatalf("missed slice out of bounds check")
- }
- var tmp Node
- Nodconst(&tmp, indexRegType, n1.Int64())
- n1 = &tmp
- }
- p := Thearch.Ginscmp(OGT, indexRegType, n1, n2, -1)
- panics = append(panics, p)
- }
-
- loadcap()
- max := &xcap
- if k.Op != 0 && (n.Op == OSLICE3 || n.Op == OSLICE3ARR) {
- if obvious(&k, max) {
- if Debug_slice > 0 {
- Warn("slice: omit check for 3rd index")
- }
- } else {
- compare(&k, max)
- }
- max = &k
- }
- if j.Op != 0 {
- if obvious(&j, max) {
- if Debug_slice > 0 {
- Warn("slice: omit check for 2nd index")
- }
- } else {
- compare(&j, max)
- }
- max = &j
- }
- if i.Op != 0 {
- if obvious(&i, max) {
- if Debug_slice > 0 {
- Warn("slice: omit check for 1st index")
- }
- } else {
- compare(&i, max)
- }
- max = &i
- }
- if k.Op != 0 && i.Op != 0 {
- obvious(&i, &k) // emit compile-time error for x[3:n:2]
- }
-
- if len(panics) > 0 {
- p := Gbranch(obj.AJMP, nil, 0)
- for _, q := range panics {
- Patch(q, Pc)
- }
- Ginscall(panicslice, -1)
- Patch(p, Pc)
- }
-
- // Checks are done.
- // Compute new len as j-i, cap as k-i.
- // If i and j are same register, len is constant 0.
- // If i and k are same register, cap is constant 0.
- // If j and k are same register, len and cap are same.
-
- // Done with xlen and xcap.
- // Now safe to modify j and k even if they alias xlen, xcap.
- if xlen.Op == OREGISTER {
- Regfree(&xlen)
- }
- if xcap.Op == OREGISTER {
- Regfree(&xcap)
- }
-
- // are j and k the same value?
- sameJK := same(&j, &k)
-
- if i.Op != 0 {
- // j -= i
- if same(&i, &j) {
- if Debug_slice > 0 {
- Warn("slice: result len == 0")
- }
- if j.Op == OREGISTER {
- Regfree(&j)
- }
- Nodconst(&j, indexRegType, 0)
- } else {
- switch j.Op {
- case OLITERAL:
- if Isconst(&i, CTINT) {
- Nodconst(&j, indexRegType, j.Int64()-i.Int64())
- if Debug_slice > 0 {
- Warn("slice: result len == %d", j.Int64())
- }
- break
- }
- fallthrough
- case ONAME:
- if !istemp(&j) {
- var r Node
- regalloc(&r, indexRegType, nil)
- Thearch.Gmove(&j, &r)
- j = r
- }
- fallthrough
- case OREGISTER:
- if i.Op == OLITERAL {
- v := i.Int64()
- if v != 0 {
- ginscon(Thearch.Optoas(OSUB, indexRegType), v, &j)
- }
- } else {
- gins(Thearch.Optoas(OSUB, indexRegType), &i, &j)
- }
- }
- }
-
- // k -= i if k different from j and cap is needed.j
- // (The modifications to j above cannot affect i: if j and i were aliased,
- // we replace j with a constant 0 instead of doing a subtraction,
- // leaving i unmodified.)
- if k.Op == 0 {
- if Debug_slice > 0 && n.Op != OSLICESTR {
- Warn("slice: result cap not computed")
- }
- // no need
- } else if same(&i, &k) {
- if k.Op == OREGISTER {
- Regfree(&k)
- }
- Nodconst(&k, indexRegType, 0)
- if Debug_slice > 0 {
- Warn("slice: result cap == 0")
- }
- } else if sameJK {
- if Debug_slice > 0 {
- Warn("slice: result cap == result len")
- }
- // k and j were the same value; make k-i the same as j-i.
- if k.Op == OREGISTER {
- Regfree(&k)
- }
- k = j
- if k.Op == OREGISTER {
- Regrealloc(&k)
- }
- } else {
- switch k.Op {
- case OLITERAL:
- if Isconst(&i, CTINT) {
- Nodconst(&k, indexRegType, k.Int64()-i.Int64())
- if Debug_slice > 0 {
- Warn("slice: result cap == %d", k.Int64())
- }
- break
- }
- fallthrough
- case ONAME:
- if !istemp(&k) {
- var r Node
- regalloc(&r, indexRegType, nil)
- Thearch.Gmove(&k, &r)
- k = r
- }
- fallthrough
- case OREGISTER:
- if same(&i, &k) {
- Regfree(&k)
- Nodconst(&k, indexRegType, 0)
- if Debug_slice > 0 {
- Warn("slice: result cap == 0")
- }
- } else if i.Op == OLITERAL {
- v := i.Int64()
- if v != 0 {
- ginscon(Thearch.Optoas(OSUB, indexRegType), v, &k)
- }
- } else {
- gins(Thearch.Optoas(OSUB, indexRegType), &i, &k)
- }
- }
- }
- }
-
- adjustBase := true
- if i.Op == 0 || iszero(&i) {
- if Debug_slice > 0 {
- Warn("slice: skip base adjustment for 1st index 0")
- }
- adjustBase = false
- } else if k.Op != 0 && iszero(&k) || k.Op == 0 && iszero(&j) {
- if Debug_slice > 0 {
- if n.Op == OSLICESTR {
- Warn("slice: skip base adjustment for string len == 0")
- } else {
- Warn("slice: skip base adjustment for cap == 0")
- }
- }
- adjustBase = false
- }
-
- if !adjustBase && !needFullUpdate {
- if Debug_slice > 0 {
- if k.Op != 0 {
- Warn("slice: len/cap-only update")
- } else {
- Warn("slice: len-only update")
- }
- }
- if i.Op == OREGISTER {
- Regfree(&i)
- }
- // Write len (and cap if needed) back to x.
- x.Xoffset += int64(Widthptr)
- x.Type = Types[TUINT]
- Thearch.Gmove(&j, &x)
- x.Xoffset -= int64(Widthptr)
- if k.Op != 0 {
- x.Xoffset += 2 * int64(Widthptr)
- x.Type = Types[TUINT]
- Thearch.Gmove(&k, &x)
- x.Xoffset -= 2 * int64(Widthptr)
- }
- Regfree(&x)
- } else {
- // Compute new base. May smash i.
- if n.Op == OSLICEARR || n.Op == OSLICE3ARR {
- Cgenr(n.Left, &xbase, nil)
- Cgen_checknil(&xbase)
- } else {
- var ptr *Type
- if n.Op == OSLICESTR {
- ptr = ptrToUint8
- } else {
- ptr = Ptrto(n.Type.Elem())
- }
- regalloc(&xbase, ptr, nil)
- x.Type = xbase.Type
- Thearch.Gmove(&x, &xbase)
- Regfree(&x)
- }
- if i.Op != 0 && adjustBase {
- // Branch around the base adjustment if the resulting cap will be 0.
- var p *obj.Prog
- size := &k
- if k.Op == 0 {
- size = &j
- }
- if Isconst(size, CTINT) {
- // zero was checked above, must be non-zero.
- } else {
- var tmp Node
- Nodconst(&tmp, indexRegType, 0)
- p = Thearch.Ginscmp(OEQ, indexRegType, size, &tmp, -1)
- }
- var w int64
- if n.Op == OSLICESTR {
- w = 1 // res is string, elem size is 1 (byte)
- } else {
- w = res.Type.Elem().Width // res is []T, elem size is T.width
- }
- if Isconst(&i, CTINT) {
- ginscon(Thearch.Optoas(OADD, xbase.Type), i.Int64()*w, &xbase)
- } else if Thearch.AddIndex != nil && Thearch.AddIndex(&i, w, &xbase) {
- // done by back end
- } else if w == 1 {
- gins(Thearch.Optoas(OADD, xbase.Type), &i, &xbase)
- } else {
- if i.Op == ONAME && !istemp(&i) {
- var tmp Node
- Tempname(&tmp, i.Type)
- Thearch.Gmove(&i, &tmp)
- i = tmp
- }
- ginscon(Thearch.Optoas(OMUL, i.Type), w, &i)
- gins(Thearch.Optoas(OADD, xbase.Type), &i, &xbase)
- }
- if p != nil {
- Patch(p, Pc)
- }
- }
- if i.Op == OREGISTER {
- Regfree(&i)
- }
-
- // Write len, cap, base to result.
- if res.Op == ONAME {
- Gvardef(res)
- }
- Igen(res, &x, nil)
- x.Xoffset += int64(Widthptr)
- x.Type = Types[TUINT]
- Thearch.Gmove(&j, &x)
- x.Xoffset -= int64(Widthptr)
- if k.Op != 0 {
- x.Xoffset += 2 * int64(Widthptr)
- Thearch.Gmove(&k, &x)
- x.Xoffset -= 2 * int64(Widthptr)
- }
- x.Type = xbase.Type
- cgen_wb(&xbase, &x, wb)
- Regfree(&xbase)
- Regfree(&x)
- }
-
- if j.Op == OREGISTER {
- Regfree(&j)
- }
- if k.Op == OREGISTER {
- Regfree(&k)
- }
-}
diff --git a/src/cmd/compile/internal/gc/closure.go b/src/cmd/compile/internal/gc/closure.go
index 66c710f..5183510 100644
--- a/src/cmd/compile/internal/gc/closure.go
+++ b/src/cmd/compile/internal/gc/closure.go
@@ -10,12 +10,9 @@ import (
// function literals aka closures
func closurehdr(ntype *Node) {
- var name *Node
- var a *Node
-
- n := Nod(OCLOSURE, nil, nil)
+ n := nod(OCLOSURE, nil, nil)
n.Func.Ntype = ntype
- n.Func.Depth = Funcdepth
+ n.Func.Depth = funcdepth
n.Func.Outerfunc = Curfn
funchdr(n)
@@ -31,11 +28,11 @@ func closurehdr(ntype *Node) {
ntype.List.Set(nil)
ntype.Rlist.Set(nil)
for _, n1 := range n.List.Slice() {
- name = n1.Left
+ name := n1.Left
if name != nil {
name = newname(name.Sym)
}
- a = Nod(ODCLFIELD, name, n1.Right)
+ a := nod(ODCLFIELD, name, n1.Right)
a.Isddd = n1.Isddd
if name != nil {
name.Isddd = a.Isddd
@@ -43,17 +40,17 @@ func closurehdr(ntype *Node) {
ntype.List.Append(a)
}
for _, n2 := range n.Rlist.Slice() {
- name = n2.Left
+ name := n2.Left
if name != nil {
name = newname(name.Sym)
}
- ntype.Rlist.Append(Nod(ODCLFIELD, name, n2.Right))
+ ntype.Rlist.Append(nod(ODCLFIELD, name, n2.Right))
}
}
func closurebody(body []*Node) *Node {
if len(body) == 0 {
- body = []*Node{Nod(OEMPTY, nil, nil)}
+ body = []*Node{nod(OEMPTY, nil, nil)}
}
func_ := Curfn
@@ -110,7 +107,7 @@ func typecheckclosure(func_ *Node, top int) {
if !n.Name.Captured {
n.Name.Captured = true
if n.Name.Decldepth == 0 {
- Fatalf("typecheckclosure: var %v does not have decldepth assigned", Nconv(n, FmtShort))
+ Fatalf("typecheckclosure: var %S does not have decldepth assigned", n)
}
// Ignore assignments to the variable in straightline code
@@ -164,14 +161,15 @@ func closurename(n *Node) *Sym {
gen := 0
outer := ""
prefix := ""
- if n.Func.Outerfunc == nil {
+ switch {
+ case n.Func.Outerfunc == nil:
// Global closure.
outer = "glob."
prefix = "func"
closurename_closgen++
gen = closurename_closgen
- } else if n.Func.Outerfunc.Op == ODCLFUNC {
+ case n.Func.Outerfunc.Op == ODCLFUNC:
// The outermost closure inside of a named function.
outer = n.Func.Outerfunc.Func.Nname.Sym.Name
@@ -187,30 +185,30 @@ func closurename(n *Node) *Sym {
closurename_closgen++
gen = closurename_closgen
}
- } else if n.Func.Outerfunc.Op == OCLOSURE {
+ case n.Func.Outerfunc.Op == OCLOSURE:
// Nested closure, recurse.
outer = closurename(n.Func.Outerfunc).Name
prefix = ""
n.Func.Outerfunc.Func.Closgen++
gen = n.Func.Outerfunc.Func.Closgen
- } else {
- Fatalf("closurename called for %v", Nconv(n, FmtShort))
+ default:
+ Fatalf("closurename called for %S", n)
}
- n.Sym = Lookupf("%s.%s%d", outer, prefix, gen)
+ n.Sym = lookupf("%s.%s%d", outer, prefix, gen)
return n.Sym
}
func makeclosure(func_ *Node) *Node {
// wrap body in external function
// that begins by reading closure parameters.
- xtype := Nod(OTFUNC, nil, nil)
+ xtype := nod(OTFUNC, nil, nil)
xtype.List.Set(func_.List.Slice())
xtype.Rlist.Set(func_.Rlist.Slice())
// create the function
- xfunc := Nod(ODCLFUNC, nil, nil)
+ xfunc := nod(ODCLFUNC, nil, nil)
xfunc.Func.Nname = newfuncname(closurename(func_))
xfunc.Func.Nname.Sym.Flags |= SymExported // disable export
@@ -220,7 +218,9 @@ func makeclosure(func_ *Node) *Node {
xfunc.Func.Nname.Name.Funcdepth = func_.Func.Depth
xfunc.Func.Depth = func_.Func.Depth
xfunc.Func.Endlineno = func_.Func.Endlineno
- makefuncsym(xfunc.Func.Nname.Sym)
+ if Ctxt.Flag_dynlink {
+ makefuncsym(xfunc.Func.Nname.Sym)
+ }
xfunc.Nbody.Set(func_.Nbody.Slice())
xfunc.Func.Dcl = append(func_.Func.Dcl, xfunc.Func.Dcl...)
@@ -276,7 +276,7 @@ func capturevars(xfunc *Node) {
v.Name.Byval = true
} else {
outermost.Addrtaken = true
- outer = Nod(OADDR, outer, nil)
+ outer = nod(OADDR, outer, nil)
}
if Debug['m'] > 1 {
@@ -344,8 +344,8 @@ func transformclosure(xfunc *Node) {
// 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 := newname(lookupf("&%s", v.Sym.Name))
+ addr.Type = ptrto(v.Type)
addr.Class = PPARAM
v.Name.Heapaddr = addr
fld.Nname = addr
@@ -374,19 +374,17 @@ func transformclosure(xfunc *Node) {
// The closure is not called, so it is going to stay as closure.
var body []*Node
offset := int64(Widthptr)
- var addr *Node
- var cv *Node
for _, v := range func_.Func.Cvars.Slice() {
if v.Op == OXXX {
continue
}
// cv refers to the field inside of closure OSTRUCTLIT.
- cv = Nod(OCLOSUREVAR, nil, nil)
+ cv := nod(OCLOSUREVAR, nil, nil)
cv.Type = v.Type
if !v.Name.Byval {
- cv.Type = Ptrto(v.Type)
+ cv.Type = ptrto(v.Type)
}
offset = Rnd(offset, int64(cv.Type.Align))
cv.Xoffset = offset
@@ -397,21 +395,21 @@ func transformclosure(xfunc *Node) {
v.Class = PAUTO
v.Ullman = 1
xfunc.Func.Dcl = append(xfunc.Func.Dcl, v)
- body = append(body, Nod(OAS, v, cv))
+ 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 := newname(lookupf("&%s", v.Sym.Name))
+ addr.Name.Param.Ntype = nod(OIND, typenod(v.Type), nil)
addr.Class = PAUTO
addr.Used = true
addr.Name.Curfn = xfunc
xfunc.Func.Dcl = append(xfunc.Func.Dcl, addr)
v.Name.Heapaddr = addr
if v.Name.Byval {
- cv = Nod(OADDR, cv, nil)
+ cv = nod(OADDR, cv, nil)
}
- body = append(body, Nod(OAS, addr, cv))
+ body = append(body, nod(OAS, addr, cv))
}
}
@@ -478,28 +476,27 @@ func walkclosure(func_ *Node, init *Nodes) *Node {
// the struct is unnamed so that closures in multiple packages with the
// same struct type can share the descriptor.
- typ := Nod(OTSTRUCT, nil, nil)
+ typ := nod(OTSTRUCT, nil, nil)
- typ.List.Set1(Nod(ODCLFIELD, newname(Lookup(".F")), typenod(Types[TUINTPTR])))
- var typ1 *Node
+ typ.List.Set1(nod(ODCLFIELD, newname(lookup(".F")), typenod(Types[TUINTPTR])))
for _, v := range func_.Func.Cvars.Slice() {
if v.Op == OXXX {
continue
}
- typ1 = typenod(v.Type)
+ typ1 := typenod(v.Type)
if !v.Name.Byval {
- typ1 = Nod(OIND, typ1, nil)
+ typ1 = nod(OIND, typ1, nil)
}
- typ.List.Append(Nod(ODCLFIELD, newname(v.Sym), typ1))
+ typ.List.Append(nod(ODCLFIELD, newname(v.Sym), typ1))
}
- clos := Nod(OCOMPLIT, nil, Nod(OIND, typ, nil))
+ clos := nod(OCOMPLIT, nil, nod(OIND, typ, nil))
clos.Esc = func_.Esc
clos.Right.Implicit = true
- clos.List.Set(append([]*Node{Nod(OCFUNC, func_.Func.Closure.Func.Nname, nil)}, func_.Func.Enter.Slice()...))
+ clos.List.Set(append([]*Node{nod(OCFUNC, func_.Func.Closure.Func.Nname, nil)}, func_.Func.Enter.Slice()...))
// Force type conversion from *struct to the func type.
- clos = Nod(OCONVNOP, clos, nil)
+ clos = nod(OCONVNOP, clos, nil)
clos.Type = func_.Type
@@ -545,9 +542,9 @@ func makepartialcall(fn *Node, t0 *Type, meth *Sym) *Node {
rcvrtype := fn.Left.Type
if exportname(meth.Name) {
- p = fmt.Sprintf("(%v).%s-fm", Tconv(rcvrtype, FmtLeft|FmtShort), meth.Name)
+ p = fmt.Sprintf("(%-S).%s-fm", rcvrtype, meth.Name)
} else {
- p = fmt.Sprintf("(%v).(%v)-fm", Tconv(rcvrtype, FmtLeft|FmtShort), sconv(meth, FmtLeft))
+ p = fmt.Sprintf("(%-S).(%-v)-fm", rcvrtype, meth)
}
basetype := rcvrtype
if rcvrtype.IsPtr() {
@@ -578,22 +575,18 @@ func makepartialcall(fn *Node, t0 *Type, meth *Sym) *Node {
savecurfn := Curfn
Curfn = nil
- xtype := Nod(OTFUNC, nil, nil)
- i := 0
+ xtype := nod(OTFUNC, nil, nil)
var l []*Node
var callargs []*Node
ddd := false
- xfunc := Nod(ODCLFUNC, nil, nil)
+ xfunc := nod(ODCLFUNC, nil, nil)
Curfn = xfunc
- var fld *Node
- var n *Node
- for _, t := range t0.Params().Fields().Slice() {
- n = newname(LookupN("a", i))
- i++
+ for i, t := range t0.Params().Fields().Slice() {
+ n := newname(lookupN("a", i))
n.Class = PPARAM
xfunc.Func.Dcl = append(xfunc.Func.Dcl, n)
callargs = append(callargs, n)
- fld = Nod(ODCLFIELD, n, typenod(t.Type))
+ fld := nod(ODCLFIELD, n, typenod(t.Type))
if t.Isddd {
fld.Isddd = true
ddd = true
@@ -603,16 +596,14 @@ func makepartialcall(fn *Node, t0 *Type, meth *Sym) *Node {
}
xtype.List.Set(l)
- i = 0
l = nil
var retargs []*Node
- for _, t := range t0.Results().Fields().Slice() {
- n = newname(LookupN("r", i))
- i++
+ for i, t := range t0.Results().Fields().Slice() {
+ n := newname(lookupN("r", i))
n.Class = PPARAMOUT
xfunc.Func.Dcl = append(xfunc.Func.Dcl, n)
retargs = append(retargs, n)
- l = append(l, Nod(ODCLFIELD, n, typenod(t.Type)))
+ l = append(l, nod(ODCLFIELD, n, typenod(t.Type)))
}
xtype.Rlist.Set(l)
@@ -627,14 +618,14 @@ func makepartialcall(fn *Node, t0 *Type, meth *Sym) *Node {
// Declare and initialize variable holding receiver.
xfunc.Func.Needctxt = true
- cv := Nod(OCLOSUREVAR, nil, nil)
+ 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 := nod(ONAME, nil, nil)
+ ptr.Sym = lookup("rcvr")
ptr.Class = PAUTO
ptr.Addable = true
ptr.Ullman = 1
@@ -645,23 +636,23 @@ func makepartialcall(fn *Node, t0 *Type, meth *Sym) *Node {
var body []*Node
if rcvrtype.IsPtr() || rcvrtype.IsInterface() {
ptr.Name.Param.Ntype = typenod(rcvrtype)
- body = append(body, Nod(OAS, ptr, cv))
+ body = append(body, nod(OAS, ptr, cv))
} else {
- ptr.Name.Param.Ntype = typenod(Ptrto(rcvrtype))
- body = append(body, Nod(OAS, ptr, Nod(OADDR, cv, nil)))
+ ptr.Name.Param.Ntype = typenod(ptrto(rcvrtype))
+ body = append(body, nod(OAS, ptr, nod(OADDR, cv, nil)))
}
- call := Nod(OCALL, NodSym(OXDOT, ptr, meth), nil)
+ call := nod(OCALL, nodSym(OXDOT, ptr, meth), nil)
call.List.Set(callargs)
call.Isddd = ddd
if t0.Results().NumFields() == 0 {
body = append(body, call)
} else {
- n := Nod(OAS2, nil, nil)
+ n := nod(OAS2, nil, nil)
n.List.Set(retargs)
n.Rlist.Set1(call)
body = append(body, n)
- n = Nod(ORETURN, nil, nil)
+ n = nod(ORETURN, nil, nil)
body = append(body, n)
}
@@ -691,18 +682,18 @@ func walkpartialcall(n *Node, init *Nodes) *Node {
checknil(n.Left, init)
}
- 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 := 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)))
- clos := Nod(OCOMPLIT, nil, Nod(OIND, typ, nil))
+ clos := nod(OCOMPLIT, nil, nod(OIND, typ, nil))
clos.Esc = n.Esc
clos.Right.Implicit = true
- clos.List.Set1(Nod(OCFUNC, n.Func.Nname, nil))
+ clos.List.Set1(nod(OCFUNC, n.Func.Nname, nil))
clos.List.Append(n.Left)
// Force type conversion from *struct to the func type.
- clos = Nod(OCONVNOP, clos, nil)
+ clos = nod(OCONVNOP, clos, nil)
clos.Type = n.Type
diff --git a/src/cmd/compile/internal/gc/const.go b/src/cmd/compile/internal/gc/const.go
index 882daec..2b25558 100644
--- a/src/cmd/compile/internal/gc/const.go
+++ b/src/cmd/compile/internal/gc/const.go
@@ -4,11 +4,7 @@
package gc
-import (
- "cmd/compile/internal/big"
- "cmd/internal/obj"
- "strings"
-)
+import "strings"
// Ctype describes the constant kind of an "ideal" (untyped) constant.
type Ctype int8
@@ -61,21 +57,57 @@ func (v Val) Ctype() Ctype {
}
}
-type NilVal struct{}
+func eqval(a, b Val) bool {
+ if a.Ctype() != b.Ctype() {
+ return false
+ }
+ switch x := a.U.(type) {
+ default:
+ Fatalf("unexpected Ctype for %T", a.U)
+ panic("not reached")
+ case *NilVal:
+ return true
+ case bool:
+ y := b.U.(bool)
+ return x == y
+ case *Mpint:
+ y := b.U.(*Mpint)
+ return x.Cmp(y) == 0
+ case *Mpflt:
+ y := b.U.(*Mpflt)
+ return x.Cmp(y) == 0
+ case *Mpcplx:
+ y := b.U.(*Mpcplx)
+ return x.Real.Cmp(&y.Real) == 0 && x.Imag.Cmp(&y.Imag) == 0
+ case string:
+ y := b.U.(string)
+ return x == y
+ }
+}
-// IntLiteral returns the Node's literal value as an integer.
-func (n *Node) IntLiteral() (x int64, ok bool) {
- switch {
- case n == nil:
- return
- case Isconst(n, CTINT):
- return n.Int64(), true
- case Isconst(n, CTBOOL):
- return int64(obj.Bool2int(n.Bool())), true
+// Interface returns the constant value stored in v as an interface{}.
+// It returns int64s for ints and runes, float64s for floats,
+// complex128s for complex values, and nil for constant nils.
+func (v Val) Interface() interface{} {
+ switch x := v.U.(type) {
+ default:
+ Fatalf("unexpected Interface for %T", v.U)
+ panic("not reached")
+ case *NilVal:
+ return nil
+ case bool, string:
+ return x
+ case *Mpint:
+ return x.Int64()
+ case *Mpflt:
+ return x.Float64()
+ case *Mpcplx:
+ return complex(x.Real.Float64(), x.Imag.Float64())
}
- return
}
+type NilVal struct{}
+
// Int64 returns n as an int64.
// n must be an integer or rune constant.
func (n *Node) Int64() int64 {
@@ -85,33 +117,6 @@ func (n *Node) Int64() int64 {
return n.Val().U.(*Mpint).Int64()
}
-// SetInt sets n's value to i.
-// n must be an integer constant.
-func (n *Node) SetInt(i int64) {
- if !Isconst(n, CTINT) {
- Fatalf("SetInt(%v)", n)
- }
- n.Val().U.(*Mpint).SetInt64(i)
-}
-
-// SetBigInt sets n's value to x.
-// n must be an integer constant.
-func (n *Node) SetBigInt(x *big.Int) {
- if !Isconst(n, CTINT) {
- Fatalf("SetBigInt(%v)", n)
- }
- n.Val().U.(*Mpint).Val.Set(x)
-}
-
-// Bool returns n as an bool.
-// n must be an boolean constant.
-func (n *Node) Bool() bool {
- if !Isconst(n, CTBOOL) {
- Fatalf("Int(%v)", n)
- }
- return n.Val().U.(bool)
-}
-
// truncate float literal fv to 32-bit or 64-bit precision
// according to type; return truncated value.
func truncfltlit(oldv *Mpflt, t *Type) *Mpflt {
@@ -141,13 +146,6 @@ func truncfltlit(oldv *Mpflt, t *Type) *Mpflt {
return fv
}
-// NegOne returns a Node of type t with value -1.
-func NegOne(t *Type) *Node {
- n := Nodintconst(-1)
- n = convlit(n, t)
- return n
-}
-
// canReuseNode indicates whether it is known to be safe
// to reuse a Node.
type canReuseNode bool
@@ -216,7 +214,7 @@ func convlit1(n *Node, t *Type, explicit bool, reuse canReuseNode) *Node {
n.SetVal(toint(n.Val()))
}
if t != nil && !t.IsInteger() {
- Yyerror("invalid operation: %v (shift of type %v)", n, t)
+ yyerror("invalid operation: %v (shift of type %v)", n, t)
t = nil
}
@@ -247,7 +245,7 @@ func convlit1(n *Node, t *Type, explicit bool, reuse canReuseNode) *Node {
}
// avoided repeated calculations, errors
- if Eqtype(n.Type, t) {
+ if eqtype(n.Type, t) {
return n
}
@@ -293,7 +291,7 @@ func convlit1(n *Node, t *Type, explicit bool, reuse canReuseNode) *Node {
TUNSAFEPTR:
break
- // A nil literal may be converted to uintptr
+ // A nil literal may be converted to uintptr
// if it is an unsafe.Pointer
case TUINTPTR:
if n.Type.Etype == TUNSAFEPTR {
@@ -314,7 +312,7 @@ func convlit1(n *Node, t *Type, explicit bool, reuse canReuseNode) *Node {
goto bad
}
ct := n.Val().Ctype()
- if Isint[et] {
+ if isInt[et] {
switch ct {
default:
goto bad
@@ -326,7 +324,7 @@ func convlit1(n *Node, t *Type, explicit bool, reuse canReuseNode) *Node {
case CTINT:
overflow(n.Val(), t)
}
- } else if Isfloat[et] {
+ } else if isFloat[et] {
switch ct {
default:
goto bad
@@ -338,7 +336,7 @@ func convlit1(n *Node, t *Type, explicit bool, reuse canReuseNode) *Node {
case CTFLT:
n.SetVal(Val{truncfltlit(n.Val().U.(*Mpflt), t)})
}
- } else if Iscomplex[et] {
+ } else if isComplex[et] {
switch ct {
default:
goto bad
@@ -361,11 +359,11 @@ func convlit1(n *Node, t *Type, explicit bool, reuse canReuseNode) *Node {
return n
bad:
- if n.Diag == 0 {
+ if !n.Diag {
if !t.Broke {
- Yyerror("cannot convert %v to type %v", n, t)
+ yyerror("cannot convert %v to type %v", n, t)
}
- n.Diag = 1
+ n.Diag = true
}
if n.Type.IsUntyped() {
@@ -426,7 +424,7 @@ func toflt(v Val) Val {
f := newMpflt()
f.Set(&u.Real)
if u.Imag.CmpFloat64(0) != 0 {
- Yyerror("constant %v%vi truncated to real", fconv(&u.Real, FmtSharp), fconv(&u.Imag, FmtSharp|FmtSign))
+ yyerror("constant %v%vi truncated to real", fconv(&u.Real, FmtSharp), fconv(&u.Imag, FmtSharp|FmtSign))
}
v.U = f
}
@@ -451,17 +449,17 @@ func toint(v Val) Val {
if u.Val.IsInt() {
msg = "constant %v overflows integer"
}
- Yyerror(msg, fconv(u, FmtSharp))
+ yyerror(msg, fconv(u, FmtSharp))
}
v.U = i
case *Mpcplx:
i := new(Mpint)
if i.SetFloat(&u.Real) < 0 {
- Yyerror("constant %v%vi truncated to integer", fconv(&u.Real, FmtSharp), fconv(&u.Imag, FmtSharp|FmtSign))
+ 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))
+ yyerror("constant %v%vi truncated to real", fconv(&u.Real, FmtSharp), fconv(&u.Imag, FmtSharp|FmtSign))
}
v.U = i
}
@@ -475,7 +473,7 @@ func doesoverflow(v Val, t *Type) bool {
if !t.IsInteger() {
Fatalf("overflow: %v integer constant", t)
}
- return u.Cmp(Minintval[t.Etype]) < 0 || u.Cmp(Maxintval[t.Etype]) > 0
+ return u.Cmp(minintval[t.Etype]) < 0 || u.Cmp(maxintval[t.Etype]) > 0
case *Mpflt:
if !t.IsFloat() {
@@ -507,7 +505,7 @@ func overflow(v Val, t *Type) {
}
if doesoverflow(v, t) {
- Yyerror("constant %s overflows %v", vconv(v, 0), t)
+ yyerror("constant %v overflows %v", v, t)
}
}
@@ -515,7 +513,7 @@ func tostr(v Val) Val {
switch u := v.U.(type) {
case *Mpint:
var i int64 = 0xFFFD
- if u.Cmp(Minintval[TUINT32]) >= 0 && u.Cmp(Maxintval[TUINT32]) <= 0 {
+ if u.Cmp(minintval[TUINT32]) >= 0 && u.Cmp(maxintval[TUINT32]) <= 0 {
i = u.Int64()
}
v.U = string(i)
@@ -546,7 +544,7 @@ func Isconst(n *Node, ct Ctype) bool {
func saveorig(n *Node) *Node {
if n == n.Orig {
// duplicate node for n->orig.
- n1 := Nod(OLITERAL, nil, nil)
+ n1 := nod(OLITERAL, nil, nil)
n.Orig = n1
*n1 = *n
@@ -636,7 +634,7 @@ func evconst(n *Node) {
return
}
wl := nl.Type.Etype
- if Isint[wl] || Isfloat[wl] || Iscomplex[wl] {
+ if isInt[wl] || isFloat[wl] || isComplex[wl] {
wl = TIDEAL
}
@@ -694,9 +692,9 @@ func evconst(n *Node) {
switch uint32(n.Op)<<16 | uint32(v.Ctype()) {
default:
- if n.Diag == 0 {
- Yyerror("illegal constant expression %v %v", n.Op, nl.Type)
- n.Diag = 1
+ if !n.Diag {
+ yyerror("illegal constant expression %v %v", n.Op, nl.Type)
+ n.Diag = true
}
return
@@ -746,7 +744,7 @@ func evconst(n *Node) {
TUINT64,
TUINT,
TUINTPTR:
- b.Set(Maxintval[et])
+ b.Set(maxintval[et])
}
v.U.(*Mpint).Xor(&b)
@@ -779,12 +777,15 @@ func evconst(n *Node) {
return
}
wr = nr.Type.Etype
- if Isint[wr] || Isfloat[wr] || Iscomplex[wr] {
+ if isInt[wr] || isFloat[wr] || isComplex[wr] {
wr = TIDEAL
}
// check for compatible general types (numeric, string, etc)
if wl != wr {
+ if wl == TINTER || wr == TINTER {
+ goto setfalse
+ }
goto illegal
}
@@ -806,7 +807,7 @@ func evconst(n *Node) {
goto illegal
}
- // right must be unsigned.
+ // right must be unsigned.
// left can be ideal.
case OLSH, ORSH:
nr = defaultlit(nr, Types[TUINT])
@@ -890,7 +891,7 @@ func evconst(n *Node) {
case ODIV_ | CTINT_,
ODIV_ | CTRUNE_:
if rv.U.(*Mpint).CmpInt64(0) == 0 {
- Yyerror("division by zero")
+ yyerror("division by zero")
v.U.(*Mpint).SetOverflow()
break
}
@@ -900,7 +901,7 @@ func evconst(n *Node) {
case OMOD_ | CTINT_,
OMOD_ | CTRUNE_:
if rv.U.(*Mpint).CmpInt64(0) == 0 {
- Yyerror("division by zero")
+ yyerror("division by zero")
v.U.(*Mpint).SetOverflow()
break
}
@@ -942,19 +943,19 @@ func evconst(n *Node) {
case ODIV_ | CTFLT_:
if rv.U.(*Mpflt).CmpFloat64(0) == 0 {
- Yyerror("division by zero")
+ yyerror("division by zero")
v.U.(*Mpflt).SetFloat64(1.0)
break
}
v.U.(*Mpflt).Quo(rv.U.(*Mpflt))
- // The default case above would print 'ideal % ideal',
+ // The default case above would print 'ideal % ideal',
// which is not quite an ideal error.
case OMOD_ | CTFLT_:
- if n.Diag == 0 {
- Yyerror("illegal constant expression: floating-point %% operation")
- n.Diag = 1
+ if !n.Diag {
+ yyerror("illegal constant expression: floating-point %% operation")
+ n.Diag = true
}
return
@@ -972,7 +973,7 @@ func evconst(n *Node) {
case ODIV_ | CTCPLX_:
if rv.U.(*Mpcplx).Real.CmpFloat64(0) == 0 && rv.U.(*Mpcplx).Imag.CmpFloat64(0) == 0 {
- Yyerror("complex division by zero")
+ yyerror("complex division by zero")
rv.U.(*Mpcplx).Real.SetFloat64(1.0)
rv.U.(*Mpcplx).Imag.SetFloat64(0.0)
break
@@ -1160,7 +1161,7 @@ ret:
return
settrue:
- nn = Nodbool(true)
+ nn = nodbool(true)
nn.Orig = saveorig(n)
if !iscmp[n.Op] {
nn.Type = nl.Type
@@ -1169,7 +1170,7 @@ settrue:
return
setfalse:
- nn = Nodbool(false)
+ nn = nodbool(false)
nn.Orig = saveorig(n)
if !iscmp[n.Op] {
nn.Type = nl.Type
@@ -1178,14 +1179,14 @@ setfalse:
return
illegal:
- if n.Diag == 0 {
- Yyerror("illegal constant expression: %v %v %v", nl.Type, n.Op, nr.Type)
- n.Diag = 1
+ if !n.Diag {
+ yyerror("illegal constant expression: %v %v %v", nl.Type, n.Op, nr.Type)
+ n.Diag = true
}
}
func nodlit(v Val) *Node {
- n := Nod(OLITERAL, nil, nil)
+ n := nod(OLITERAL, nil, nil)
n.SetVal(v)
switch v.Ctype() {
default:
@@ -1212,7 +1213,7 @@ func nodcplxlit(r Val, i Val) *Node {
i = toflt(i)
c := new(Mpcplx)
- n := Nod(OLITERAL, nil, nil)
+ n := nod(OLITERAL, nil, nil)
n.Type = Types[TIDEAL]
n.SetVal(Val{c})
@@ -1319,9 +1320,9 @@ func defaultlitreuse(n *Node, t *Type, reuse canReuseNode) *Node {
if n.Val().Ctype() == CTNIL {
lineno = lno
- if n.Diag == 0 {
- Yyerror("use of untyped nil")
- n.Diag = 1
+ if !n.Diag {
+ yyerror("use of untyped nil")
+ n.Diag = true
}
n.Type = nil
@@ -1334,10 +1335,10 @@ func defaultlitreuse(n *Node, t *Type, reuse canReuseNode) *Node {
break
}
- Yyerror("defaultlit: unknown literal: %v", n)
+ yyerror("defaultlit: unknown literal: %v", n)
case CTxxx:
- Fatalf("defaultlit: idealkind is CTxxx: %v", Nconv(n, FmtSign))
+ Fatalf("defaultlit: idealkind is CTxxx: %+v", n)
case CTBOOL:
t1 := Types[TBOOL]
@@ -1454,9 +1455,9 @@ func strlit(n *Node) string {
return n.Val().U.(string)
}
-func Smallintconst(n *Node) bool {
+func smallintconst(n *Node) bool {
if n.Op == OLITERAL && Isconst(n, CTINT) && n.Type != nil {
- switch Simtype[n.Type.Etype] {
+ switch simtype[n.Type.Etype] {
case TINT8,
TUINT8,
TINT16,
@@ -1468,122 +1469,33 @@ func Smallintconst(n *Node) bool {
return true
case TIDEAL, TINT64, TUINT64, TPTR64:
- if n.Val().U.(*Mpint).Cmp(Minintval[TINT32]) < 0 || n.Val().U.(*Mpint).Cmp(Maxintval[TINT32]) > 0 {
- break
+ v, ok := n.Val().U.(*Mpint)
+ if ok && v.Cmp(minintval[TINT32]) > 0 && v.Cmp(maxintval[TINT32]) < 0 {
+ return true
}
- return true
}
}
return false
}
-func nonnegconst(n *Node) int {
- if n.Op == OLITERAL && n.Type != nil {
- switch Simtype[n.Type.Etype] {
- // check negative and 2^31
- case TINT8,
- TUINT8,
- TINT16,
- TUINT16,
- TINT32,
- TUINT32,
- TINT64,
- TUINT64,
- TIDEAL:
- if n.Val().U.(*Mpint).Cmp(Minintval[TUINT32]) < 0 || n.Val().U.(*Mpint).Cmp(Maxintval[TINT32]) > 0 {
- break
- }
- return int(n.Int64())
- }
- }
-
- return -1
-}
-
-// convert x to type et and back to int64
-// for sign extension and truncation.
-func iconv(x int64, et EType) int64 {
- switch et {
- case TINT8:
- x = int64(int8(x))
-
- case TUINT8:
- x = int64(uint8(x))
-
- case TINT16:
- x = int64(int16(x))
-
- case TUINT16:
- x = int64(uint64(x))
-
- case TINT32:
- x = int64(int32(x))
-
- case TUINT32:
- x = int64(uint32(x))
-
- case TINT64, TUINT64:
- break
- }
-
- return x
-}
-
-// Convconst converts constant node n to type t and
-// places the result in con.
-func (n *Node) Convconst(con *Node, t *Type) {
- tt := Simsimtype(t)
-
- // copy the constant for conversion
- Nodconst(con, Types[TINT8], 0)
-
- con.Type = t
- con.SetVal(n.Val())
-
- if Isint[tt] {
- con.SetVal(Val{new(Mpint)})
- var i int64
- switch n.Val().Ctype() {
- default:
- Fatalf("convconst ctype=%d %v", n.Val().Ctype(), Tconv(t, FmtLong))
-
- case CTINT, CTRUNE:
- i = n.Int64()
-
- case CTBOOL:
- i = int64(obj.Bool2int(n.Val().U.(bool)))
-
- case CTNIL:
- i = 0
- }
-
- i = iconv(i, tt)
- con.Val().U.(*Mpint).SetInt64(i)
- return
- }
-
- if Isfloat[tt] {
- con.SetVal(toflt(con.Val()))
- if con.Val().Ctype() != CTFLT {
- Fatalf("convconst ctype=%d %v", con.Val().Ctype(), t)
- }
- if tt == TFLOAT32 {
- con.SetVal(Val{truncfltlit(con.Val().U.(*Mpflt), t)})
- }
- return
+// nonnegintconst checks if Node n contains a constant expression
+// representable as a non-negative small integer, and returns its
+// (integer) value if that's the case. Otherwise, it returns -1.
+func nonnegintconst(n *Node) int64 {
+ if n.Op != OLITERAL {
+ return -1
}
- if Iscomplex[tt] {
- con.SetVal(tocplx(con.Val()))
- if tt == TCOMPLEX64 {
- con.Val().U.(*Mpcplx).Real = *truncfltlit(&con.Val().U.(*Mpcplx).Real, Types[TFLOAT32])
- con.Val().U.(*Mpcplx).Imag = *truncfltlit(&con.Val().U.(*Mpcplx).Imag, Types[TFLOAT32])
- }
- return
+ // toint will leave n.Val unchanged if it's not castable to an
+ // 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 {
+ return -1
}
- Fatalf("convconst %v constant", Tconv(t, FmtLong))
+ return vi.Int64()
}
// complex multiply v *= rv
@@ -1745,19 +1657,8 @@ func isgoconst(n *Node) bool {
return true
}
- // Only constant calls are unsafe.Alignof, Offsetof, and Sizeof.
- case OCALL:
- l := n.Left
-
- for l.Op == OPAREN {
- l = l.Left
- }
- if l.Op != ONAME || l.Sym.Pkg != unsafepkg {
- break
- }
- if l.Sym.Name == "Alignof" || l.Sym.Name == "Offsetof" || l.Sym.Name == "Sizeof" {
- return true
- }
+ case OALIGNOF, OOFFSETOF, OSIZEOF:
+ return true
}
//dump("nonconst", n);
diff --git a/src/cmd/compile/internal/gc/constFold_test.go b/src/cmd/compile/internal/gc/constFold_test.go
index ef6a3c1..fe57717 100644
--- a/src/cmd/compile/internal/gc/constFold_test.go
+++ b/src/cmd/compile/internal/gc/constFold_test.go
@@ -8,85 +8,85 @@ func TestConstFolduint64add(t *testing.T) {
y = 0
r = x + y
if r != 0 {
- t.Errorf("0 + 0 = %d, want 0", r)
+ t.Errorf("0 %s 0 = %d, want 0", "+", r)
}
y = 1
r = x + y
if r != 1 {
- t.Errorf("0 + 1 = %d, want 1", r)
+ t.Errorf("0 %s 1 = %d, want 1", "+", r)
}
y = 4294967296
r = x + y
if r != 4294967296 {
- t.Errorf("0 + 4294967296 = %d, want 4294967296", r)
+ t.Errorf("0 %s 4294967296 = %d, want 4294967296", "+", r)
}
y = 18446744073709551615
r = x + y
if r != 18446744073709551615 {
- t.Errorf("0 + 18446744073709551615 = %d, want 18446744073709551615", r)
+ t.Errorf("0 %s 18446744073709551615 = %d, want 18446744073709551615", "+", r)
}
x = 1
y = 0
r = x + y
if r != 1 {
- t.Errorf("1 + 0 = %d, want 1", r)
+ t.Errorf("1 %s 0 = %d, want 1", "+", r)
}
y = 1
r = x + y
if r != 2 {
- t.Errorf("1 + 1 = %d, want 2", r)
+ t.Errorf("1 %s 1 = %d, want 2", "+", r)
}
y = 4294967296
r = x + y
if r != 4294967297 {
- t.Errorf("1 + 4294967296 = %d, want 4294967297", r)
+ t.Errorf("1 %s 4294967296 = %d, want 4294967297", "+", r)
}
y = 18446744073709551615
r = x + y
if r != 0 {
- t.Errorf("1 + 18446744073709551615 = %d, want 0", r)
+ t.Errorf("1 %s 18446744073709551615 = %d, want 0", "+", r)
}
x = 4294967296
y = 0
r = x + y
if r != 4294967296 {
- t.Errorf("4294967296 + 0 = %d, want 4294967296", r)
+ t.Errorf("4294967296 %s 0 = %d, want 4294967296", "+", r)
}
y = 1
r = x + y
if r != 4294967297 {
- t.Errorf("4294967296 + 1 = %d, want 4294967297", r)
+ t.Errorf("4294967296 %s 1 = %d, want 4294967297", "+", r)
}
y = 4294967296
r = x + y
if r != 8589934592 {
- t.Errorf("4294967296 + 4294967296 = %d, want 8589934592", r)
+ t.Errorf("4294967296 %s 4294967296 = %d, want 8589934592", "+", r)
}
y = 18446744073709551615
r = x + y
if r != 4294967295 {
- t.Errorf("4294967296 + 18446744073709551615 = %d, want 4294967295", r)
+ t.Errorf("4294967296 %s 18446744073709551615 = %d, want 4294967295", "+", r)
}
x = 18446744073709551615
y = 0
r = x + y
if r != 18446744073709551615 {
- t.Errorf("18446744073709551615 + 0 = %d, want 18446744073709551615", r)
+ t.Errorf("18446744073709551615 %s 0 = %d, want 18446744073709551615", "+", r)
}
y = 1
r = x + y
if r != 0 {
- t.Errorf("18446744073709551615 + 1 = %d, want 0", r)
+ t.Errorf("18446744073709551615 %s 1 = %d, want 0", "+", r)
}
y = 4294967296
r = x + y
if r != 4294967295 {
- t.Errorf("18446744073709551615 + 4294967296 = %d, want 4294967295", r)
+ t.Errorf("18446744073709551615 %s 4294967296 = %d, want 4294967295", "+", r)
}
y = 18446744073709551615
r = x + y
if r != 18446744073709551614 {
- t.Errorf("18446744073709551615 + 18446744073709551615 = %d, want 18446744073709551614", r)
+ t.Errorf("18446744073709551615 %s 18446744073709551615 = %d, want 18446744073709551614", "+", r)
}
}
func TestConstFolduint64sub(t *testing.T) {
@@ -95,85 +95,85 @@ func TestConstFolduint64sub(t *testing.T) {
y = 0
r = x - y
if r != 0 {
- t.Errorf("0 - 0 = %d, want 0", r)
+ t.Errorf("0 %s 0 = %d, want 0", "-", r)
}
y = 1
r = x - y
if r != 18446744073709551615 {
- t.Errorf("0 - 1 = %d, want 18446744073709551615", r)
+ t.Errorf("0 %s 1 = %d, want 18446744073709551615", "-", r)
}
y = 4294967296
r = x - y
if r != 18446744069414584320 {
- t.Errorf("0 - 4294967296 = %d, want 18446744069414584320", r)
+ t.Errorf("0 %s 4294967296 = %d, want 18446744069414584320", "-", r)
}
y = 18446744073709551615
r = x - y
if r != 1 {
- t.Errorf("0 - 18446744073709551615 = %d, want 1", r)
+ t.Errorf("0 %s 18446744073709551615 = %d, want 1", "-", r)
}
x = 1
y = 0
r = x - y
if r != 1 {
- t.Errorf("1 - 0 = %d, want 1", r)
+ t.Errorf("1 %s 0 = %d, want 1", "-", r)
}
y = 1
r = x - y
if r != 0 {
- t.Errorf("1 - 1 = %d, want 0", r)
+ t.Errorf("1 %s 1 = %d, want 0", "-", r)
}
y = 4294967296
r = x - y
if r != 18446744069414584321 {
- t.Errorf("1 - 4294967296 = %d, want 18446744069414584321", r)
+ t.Errorf("1 %s 4294967296 = %d, want 18446744069414584321", "-", r)
}
y = 18446744073709551615
r = x - y
if r != 2 {
- t.Errorf("1 - 18446744073709551615 = %d, want 2", r)
+ t.Errorf("1 %s 18446744073709551615 = %d, want 2", "-", r)
}
x = 4294967296
y = 0
r = x - y
if r != 4294967296 {
- t.Errorf("4294967296 - 0 = %d, want 4294967296", r)
+ t.Errorf("4294967296 %s 0 = %d, want 4294967296", "-", r)
}
y = 1
r = x - y
if r != 4294967295 {
- t.Errorf("4294967296 - 1 = %d, want 4294967295", r)
+ t.Errorf("4294967296 %s 1 = %d, want 4294967295", "-", r)
}
y = 4294967296
r = x - y
if r != 0 {
- t.Errorf("4294967296 - 4294967296 = %d, want 0", r)
+ t.Errorf("4294967296 %s 4294967296 = %d, want 0", "-", r)
}
y = 18446744073709551615
r = x - y
if r != 4294967297 {
- t.Errorf("4294967296 - 18446744073709551615 = %d, want 4294967297", r)
+ t.Errorf("4294967296 %s 18446744073709551615 = %d, want 4294967297", "-", r)
}
x = 18446744073709551615
y = 0
r = x - y
if r != 18446744073709551615 {
- t.Errorf("18446744073709551615 - 0 = %d, want 18446744073709551615", r)
+ t.Errorf("18446744073709551615 %s 0 = %d, want 18446744073709551615", "-", r)
}
y = 1
r = x - y
if r != 18446744073709551614 {
- t.Errorf("18446744073709551615 - 1 = %d, want 18446744073709551614", r)
+ t.Errorf("18446744073709551615 %s 1 = %d, want 18446744073709551614", "-", r)
}
y = 4294967296
r = x - y
if r != 18446744069414584319 {
- t.Errorf("18446744073709551615 - 4294967296 = %d, want 18446744069414584319", r)
+ t.Errorf("18446744073709551615 %s 4294967296 = %d, want 18446744069414584319", "-", r)
}
y = 18446744073709551615
r = x - y
if r != 0 {
- t.Errorf("18446744073709551615 - 18446744073709551615 = %d, want 0", r)
+ t.Errorf("18446744073709551615 %s 18446744073709551615 = %d, want 0", "-", r)
}
}
func TestConstFolduint64div(t *testing.T) {
@@ -182,65 +182,65 @@ func TestConstFolduint64div(t *testing.T) {
y = 1
r = x / y
if r != 0 {
- t.Errorf("0 / 1 = %d, want 0", r)
+ t.Errorf("0 %s 1 = %d, want 0", "/", r)
}
y = 4294967296
r = x / y
if r != 0 {
- t.Errorf("0 / 4294967296 = %d, want 0", r)
+ t.Errorf("0 %s 4294967296 = %d, want 0", "/", r)
}
y = 18446744073709551615
r = x / y
if r != 0 {
- t.Errorf("0 / 18446744073709551615 = %d, want 0", r)
+ t.Errorf("0 %s 18446744073709551615 = %d, want 0", "/", r)
}
x = 1
y = 1
r = x / y
if r != 1 {
- t.Errorf("1 / 1 = %d, want 1", r)
+ t.Errorf("1 %s 1 = %d, want 1", "/", r)
}
y = 4294967296
r = x / y
if r != 0 {
- t.Errorf("1 / 4294967296 = %d, want 0", r)
+ t.Errorf("1 %s 4294967296 = %d, want 0", "/", r)
}
y = 18446744073709551615
r = x / y
if r != 0 {
- t.Errorf("1 / 18446744073709551615 = %d, want 0", r)
+ t.Errorf("1 %s 18446744073709551615 = %d, want 0", "/", r)
}
x = 4294967296
y = 1
r = x / y
if r != 4294967296 {
- t.Errorf("4294967296 / 1 = %d, want 4294967296", r)
+ t.Errorf("4294967296 %s 1 = %d, want 4294967296", "/", r)
}
y = 4294967296
r = x / y
if r != 1 {
- t.Errorf("4294967296 / 4294967296 = %d, want 1", r)
+ t.Errorf("4294967296 %s 4294967296 = %d, want 1", "/", r)
}
y = 18446744073709551615
r = x / y
if r != 0 {
- t.Errorf("4294967296 / 18446744073709551615 = %d, want 0", r)
+ t.Errorf("4294967296 %s 18446744073709551615 = %d, want 0", "/", r)
}
x = 18446744073709551615
y = 1
r = x / y
if r != 18446744073709551615 {
- t.Errorf("18446744073709551615 / 1 = %d, want 18446744073709551615", r)
+ t.Errorf("18446744073709551615 %s 1 = %d, want 18446744073709551615", "/", r)
}
y = 4294967296
r = x / y
if r != 4294967295 {
- t.Errorf("18446744073709551615 / 4294967296 = %d, want 4294967295", r)
+ t.Errorf("18446744073709551615 %s 4294967296 = %d, want 4294967295", "/", r)
}
y = 18446744073709551615
r = x / y
if r != 1 {
- t.Errorf("18446744073709551615 / 18446744073709551615 = %d, want 1", r)
+ t.Errorf("18446744073709551615 %s 18446744073709551615 = %d, want 1", "/", r)
}
}
func TestConstFolduint64mul(t *testing.T) {
@@ -249,85 +249,85 @@ func TestConstFolduint64mul(t *testing.T) {
y = 0
r = x * y
if r != 0 {
- t.Errorf("0 * 0 = %d, want 0", r)
+ t.Errorf("0 %s 0 = %d, want 0", "*", r)
}
y = 1
r = x * y
if r != 0 {
- t.Errorf("0 * 1 = %d, want 0", r)
+ t.Errorf("0 %s 1 = %d, want 0", "*", r)
}
y = 4294967296
r = x * y
if r != 0 {
- t.Errorf("0 * 4294967296 = %d, want 0", r)
+ t.Errorf("0 %s 4294967296 = %d, want 0", "*", r)
}
y = 18446744073709551615
r = x * y
if r != 0 {
- t.Errorf("0 * 18446744073709551615 = %d, want 0", r)
+ t.Errorf("0 %s 18446744073709551615 = %d, want 0", "*", r)
}
x = 1
y = 0
r = x * y
if r != 0 {
- t.Errorf("1 * 0 = %d, want 0", r)
+ t.Errorf("1 %s 0 = %d, want 0", "*", r)
}
y = 1
r = x * y
if r != 1 {
- t.Errorf("1 * 1 = %d, want 1", r)
+ t.Errorf("1 %s 1 = %d, want 1", "*", r)
}
y = 4294967296
r = x * y
if r != 4294967296 {
- t.Errorf("1 * 4294967296 = %d, want 4294967296", r)
+ t.Errorf("1 %s 4294967296 = %d, want 4294967296", "*", r)
}
y = 18446744073709551615
r = x * y
if r != 18446744073709551615 {
- t.Errorf("1 * 18446744073709551615 = %d, want 18446744073709551615", r)
+ t.Errorf("1 %s 18446744073709551615 = %d, want 18446744073709551615", "*", r)
}
x = 4294967296
y = 0
r = x * y
if r != 0 {
- t.Errorf("4294967296 * 0 = %d, want 0", r)
+ t.Errorf("4294967296 %s 0 = %d, want 0", "*", r)
}
y = 1
r = x * y
if r != 4294967296 {
- t.Errorf("4294967296 * 1 = %d, want 4294967296", r)
+ t.Errorf("4294967296 %s 1 = %d, want 4294967296", "*", r)
}
y = 4294967296
r = x * y
if r != 0 {
- t.Errorf("4294967296 * 4294967296 = %d, want 0", r)
+ t.Errorf("4294967296 %s 4294967296 = %d, want 0", "*", r)
}
y = 18446744073709551615
r = x * y
if r != 18446744069414584320 {
- t.Errorf("4294967296 * 18446744073709551615 = %d, want 18446744069414584320", r)
+ t.Errorf("4294967296 %s 18446744073709551615 = %d, want 18446744069414584320", "*", r)
}
x = 18446744073709551615
y = 0
r = x * y
if r != 0 {
- t.Errorf("18446744073709551615 * 0 = %d, want 0", r)
+ t.Errorf("18446744073709551615 %s 0 = %d, want 0", "*", r)
}
y = 1
r = x * y
if r != 18446744073709551615 {
- t.Errorf("18446744073709551615 * 1 = %d, want 18446744073709551615", r)
+ t.Errorf("18446744073709551615 %s 1 = %d, want 18446744073709551615", "*", r)
}
y = 4294967296
r = x * y
if r != 18446744069414584320 {
- t.Errorf("18446744073709551615 * 4294967296 = %d, want 18446744069414584320", r)
+ t.Errorf("18446744073709551615 %s 4294967296 = %d, want 18446744069414584320", "*", r)
}
y = 18446744073709551615
r = x * y
if r != 1 {
- t.Errorf("18446744073709551615 * 18446744073709551615 = %d, want 1", r)
+ t.Errorf("18446744073709551615 %s 18446744073709551615 = %d, want 1", "*", r)
}
}
func TestConstFolduint64mod(t *testing.T) {
@@ -336,65 +336,65 @@ func TestConstFolduint64mod(t *testing.T) {
y = 1
r = x % y
if r != 0 {
- t.Errorf("0 % 1 = %d, want 0", r)
+ t.Errorf("0 %s 1 = %d, want 0", "%", r)
}
y = 4294967296
r = x % y
if r != 0 {
- t.Errorf("0 % 4294967296 = %d, want 0", r)
+ t.Errorf("0 %s 4294967296 = %d, want 0", "%", r)
}
y = 18446744073709551615
r = x % y
if r != 0 {
- t.Errorf("0 % 18446744073709551615 = %d, want 0", r)
+ t.Errorf("0 %s 18446744073709551615 = %d, want 0", "%", r)
}
x = 1
y = 1
r = x % y
if r != 0 {
- t.Errorf("1 % 1 = %d, want 0", r)
+ t.Errorf("1 %s 1 = %d, want 0", "%", r)
}
y = 4294967296
r = x % y
if r != 1 {
- t.Errorf("1 % 4294967296 = %d, want 1", r)
+ t.Errorf("1 %s 4294967296 = %d, want 1", "%", r)
}
y = 18446744073709551615
r = x % y
if r != 1 {
- t.Errorf("1 % 18446744073709551615 = %d, want 1", r)
+ t.Errorf("1 %s 18446744073709551615 = %d, want 1", "%", r)
}
x = 4294967296
y = 1
r = x % y
if r != 0 {
- t.Errorf("4294967296 % 1 = %d, want 0", r)
+ t.Errorf("4294967296 %s 1 = %d, want 0", "%", r)
}
y = 4294967296
r = x % y
if r != 0 {
- t.Errorf("4294967296 % 4294967296 = %d, want 0", r)
+ t.Errorf("4294967296 %s 4294967296 = %d, want 0", "%", r)
}
y = 18446744073709551615
r = x % y
if r != 4294967296 {
- t.Errorf("4294967296 % 18446744073709551615 = %d, want 4294967296", r)
+ t.Errorf("4294967296 %s 18446744073709551615 = %d, want 4294967296", "%", r)
}
x = 18446744073709551615
y = 1
r = x % y
if r != 0 {
- t.Errorf("18446744073709551615 % 1 = %d, want 0", r)
+ t.Errorf("18446744073709551615 %s 1 = %d, want 0", "%", r)
}
y = 4294967296
r = x % y
if r != 4294967295 {
- t.Errorf("18446744073709551615 % 4294967296 = %d, want 4294967295", r)
+ t.Errorf("18446744073709551615 %s 4294967296 = %d, want 4294967295", "%", r)
}
y = 18446744073709551615
r = x % y
if r != 0 {
- t.Errorf("18446744073709551615 % 18446744073709551615 = %d, want 0", r)
+ t.Errorf("18446744073709551615 %s 18446744073709551615 = %d, want 0", "%", r)
}
}
func TestConstFoldint64add(t *testing.T) {
@@ -403,415 +403,415 @@ func TestConstFoldint64add(t *testing.T) {
y = -9223372036854775808
r = x + y
if r != 0 {
- t.Errorf("-9223372036854775808 + -9223372036854775808 = %d, want 0", r)
+ t.Errorf("-9223372036854775808 %s -9223372036854775808 = %d, want 0", "+", r)
}
y = -9223372036854775807
r = x + y
if r != 1 {
- t.Errorf("-9223372036854775808 + -9223372036854775807 = %d, want 1", r)
+ t.Errorf("-9223372036854775808 %s -9223372036854775807 = %d, want 1", "+", r)
}
y = -4294967296
r = x + y
if r != 9223372032559808512 {
- t.Errorf("-9223372036854775808 + -4294967296 = %d, want 9223372032559808512", r)
+ t.Errorf("-9223372036854775808 %s -4294967296 = %d, want 9223372032559808512", "+", r)
}
y = -1
r = x + y
if r != 9223372036854775807 {
- t.Errorf("-9223372036854775808 + -1 = %d, want 9223372036854775807", r)
+ t.Errorf("-9223372036854775808 %s -1 = %d, want 9223372036854775807", "+", r)
}
y = 0
r = x + y
if r != -9223372036854775808 {
- t.Errorf("-9223372036854775808 + 0 = %d, want -9223372036854775808", r)
+ t.Errorf("-9223372036854775808 %s 0 = %d, want -9223372036854775808", "+", r)
}
y = 1
r = x + y
if r != -9223372036854775807 {
- t.Errorf("-9223372036854775808 + 1 = %d, want -9223372036854775807", r)
+ t.Errorf("-9223372036854775808 %s 1 = %d, want -9223372036854775807", "+", r)
}
y = 4294967296
r = x + y
if r != -9223372032559808512 {
- t.Errorf("-9223372036854775808 + 4294967296 = %d, want -9223372032559808512", r)
+ t.Errorf("-9223372036854775808 %s 4294967296 = %d, want -9223372032559808512", "+", r)
}
y = 9223372036854775806
r = x + y
if r != -2 {
- t.Errorf("-9223372036854775808 + 9223372036854775806 = %d, want -2", r)
+ t.Errorf("-9223372036854775808 %s 9223372036854775806 = %d, want -2", "+", r)
}
y = 9223372036854775807
r = x + y
if r != -1 {
- t.Errorf("-9223372036854775808 + 9223372036854775807 = %d, want -1", r)
+ t.Errorf("-9223372036854775808 %s 9223372036854775807 = %d, want -1", "+", r)
}
x = -9223372036854775807
y = -9223372036854775808
r = x + y
if r != 1 {
- t.Errorf("-9223372036854775807 + -9223372036854775808 = %d, want 1", r)
+ t.Errorf("-9223372036854775807 %s -9223372036854775808 = %d, want 1", "+", r)
}
y = -9223372036854775807
r = x + y
if r != 2 {
- t.Errorf("-9223372036854775807 + -9223372036854775807 = %d, want 2", r)
+ t.Errorf("-9223372036854775807 %s -9223372036854775807 = %d, want 2", "+", r)
}
y = -4294967296
r = x + y
if r != 9223372032559808513 {
- t.Errorf("-9223372036854775807 + -4294967296 = %d, want 9223372032559808513", r)
+ t.Errorf("-9223372036854775807 %s -4294967296 = %d, want 9223372032559808513", "+", r)
}
y = -1
r = x + y
if r != -9223372036854775808 {
- t.Errorf("-9223372036854775807 + -1 = %d, want -9223372036854775808", r)
+ t.Errorf("-9223372036854775807 %s -1 = %d, want -9223372036854775808", "+", r)
}
y = 0
r = x + y
if r != -9223372036854775807 {
- t.Errorf("-9223372036854775807 + 0 = %d, want -9223372036854775807", r)
+ t.Errorf("-9223372036854775807 %s 0 = %d, want -9223372036854775807", "+", r)
}
y = 1
r = x + y
if r != -9223372036854775806 {
- t.Errorf("-9223372036854775807 + 1 = %d, want -9223372036854775806", r)
+ t.Errorf("-9223372036854775807 %s 1 = %d, want -9223372036854775806", "+", r)
}
y = 4294967296
r = x + y
if r != -9223372032559808511 {
- t.Errorf("-9223372036854775807 + 4294967296 = %d, want -9223372032559808511", r)
+ t.Errorf("-9223372036854775807 %s 4294967296 = %d, want -9223372032559808511", "+", r)
}
y = 9223372036854775806
r = x + y
if r != -1 {
- t.Errorf("-9223372036854775807 + 9223372036854775806 = %d, want -1", r)
+ t.Errorf("-9223372036854775807 %s 9223372036854775806 = %d, want -1", "+", r)
}
y = 9223372036854775807
r = x + y
if r != 0 {
- t.Errorf("-9223372036854775807 + 9223372036854775807 = %d, want 0", r)
+ t.Errorf("-9223372036854775807 %s 9223372036854775807 = %d, want 0", "+", r)
}
x = -4294967296
y = -9223372036854775808
r = x + y
if r != 9223372032559808512 {
- t.Errorf("-4294967296 + -9223372036854775808 = %d, want 9223372032559808512", r)
+ t.Errorf("-4294967296 %s -9223372036854775808 = %d, want 9223372032559808512", "+", r)
}
y = -9223372036854775807
r = x + y
if r != 9223372032559808513 {
- t.Errorf("-4294967296 + -9223372036854775807 = %d, want 9223372032559808513", r)
+ t.Errorf("-4294967296 %s -9223372036854775807 = %d, want 9223372032559808513", "+", r)
}
y = -4294967296
r = x + y
if r != -8589934592 {
- t.Errorf("-4294967296 + -4294967296 = %d, want -8589934592", r)
+ t.Errorf("-4294967296 %s -4294967296 = %d, want -8589934592", "+", r)
}
y = -1
r = x + y
if r != -4294967297 {
- t.Errorf("-4294967296 + -1 = %d, want -4294967297", r)
+ t.Errorf("-4294967296 %s -1 = %d, want -4294967297", "+", r)
}
y = 0
r = x + y
if r != -4294967296 {
- t.Errorf("-4294967296 + 0 = %d, want -4294967296", r)
+ t.Errorf("-4294967296 %s 0 = %d, want -4294967296", "+", r)
}
y = 1
r = x + y
if r != -4294967295 {
- t.Errorf("-4294967296 + 1 = %d, want -4294967295", r)
+ t.Errorf("-4294967296 %s 1 = %d, want -4294967295", "+", r)
}
y = 4294967296
r = x + y
if r != 0 {
- t.Errorf("-4294967296 + 4294967296 = %d, want 0", r)
+ t.Errorf("-4294967296 %s 4294967296 = %d, want 0", "+", r)
}
y = 9223372036854775806
r = x + y
if r != 9223372032559808510 {
- t.Errorf("-4294967296 + 9223372036854775806 = %d, want 9223372032559808510", r)
+ t.Errorf("-4294967296 %s 9223372036854775806 = %d, want 9223372032559808510", "+", r)
}
y = 9223372036854775807
r = x + y
if r != 9223372032559808511 {
- t.Errorf("-4294967296 + 9223372036854775807 = %d, want 9223372032559808511", r)
+ t.Errorf("-4294967296 %s 9223372036854775807 = %d, want 9223372032559808511", "+", r)
}
x = -1
y = -9223372036854775808
r = x + y
if r != 9223372036854775807 {
- t.Errorf("-1 + -9223372036854775808 = %d, want 9223372036854775807", r)
+ t.Errorf("-1 %s -9223372036854775808 = %d, want 9223372036854775807", "+", r)
}
y = -9223372036854775807
r = x + y
if r != -9223372036854775808 {
- t.Errorf("-1 + -9223372036854775807 = %d, want -9223372036854775808", r)
+ t.Errorf("-1 %s -9223372036854775807 = %d, want -9223372036854775808", "+", r)
}
y = -4294967296
r = x + y
if r != -4294967297 {
- t.Errorf("-1 + -4294967296 = %d, want -4294967297", r)
+ t.Errorf("-1 %s -4294967296 = %d, want -4294967297", "+", r)
}
y = -1
r = x + y
if r != -2 {
- t.Errorf("-1 + -1 = %d, want -2", r)
+ t.Errorf("-1 %s -1 = %d, want -2", "+", r)
}
y = 0
r = x + y
if r != -1 {
- t.Errorf("-1 + 0 = %d, want -1", r)
+ t.Errorf("-1 %s 0 = %d, want -1", "+", r)
}
y = 1
r = x + y
if r != 0 {
- t.Errorf("-1 + 1 = %d, want 0", r)
+ t.Errorf("-1 %s 1 = %d, want 0", "+", r)
}
y = 4294967296
r = x + y
if r != 4294967295 {
- t.Errorf("-1 + 4294967296 = %d, want 4294967295", r)
+ t.Errorf("-1 %s 4294967296 = %d, want 4294967295", "+", r)
}
y = 9223372036854775806
r = x + y
if r != 9223372036854775805 {
- t.Errorf("-1 + 9223372036854775806 = %d, want 9223372036854775805", r)
+ t.Errorf("-1 %s 9223372036854775806 = %d, want 9223372036854775805", "+", r)
}
y = 9223372036854775807
r = x + y
if r != 9223372036854775806 {
- t.Errorf("-1 + 9223372036854775807 = %d, want 9223372036854775806", r)
+ t.Errorf("-1 %s 9223372036854775807 = %d, want 9223372036854775806", "+", r)
}
x = 0
y = -9223372036854775808
r = x + y
if r != -9223372036854775808 {
- t.Errorf("0 + -9223372036854775808 = %d, want -9223372036854775808", r)
+ t.Errorf("0 %s -9223372036854775808 = %d, want -9223372036854775808", "+", r)
}
y = -9223372036854775807
r = x + y
if r != -9223372036854775807 {
- t.Errorf("0 + -9223372036854775807 = %d, want -9223372036854775807", r)
+ t.Errorf("0 %s -9223372036854775807 = %d, want -9223372036854775807", "+", r)
}
y = -4294967296
r = x + y
if r != -4294967296 {
- t.Errorf("0 + -4294967296 = %d, want -4294967296", r)
+ t.Errorf("0 %s -4294967296 = %d, want -4294967296", "+", r)
}
y = -1
r = x + y
if r != -1 {
- t.Errorf("0 + -1 = %d, want -1", r)
+ t.Errorf("0 %s -1 = %d, want -1", "+", r)
}
y = 0
r = x + y
if r != 0 {
- t.Errorf("0 + 0 = %d, want 0", r)
+ t.Errorf("0 %s 0 = %d, want 0", "+", r)
}
y = 1
r = x + y
if r != 1 {
- t.Errorf("0 + 1 = %d, want 1", r)
+ t.Errorf("0 %s 1 = %d, want 1", "+", r)
}
y = 4294967296
r = x + y
if r != 4294967296 {
- t.Errorf("0 + 4294967296 = %d, want 4294967296", r)
+ t.Errorf("0 %s 4294967296 = %d, want 4294967296", "+", r)
}
y = 9223372036854775806
r = x + y
if r != 9223372036854775806 {
- t.Errorf("0 + 9223372036854775806 = %d, want 9223372036854775806", r)
+ t.Errorf("0 %s 9223372036854775806 = %d, want 9223372036854775806", "+", r)
}
y = 9223372036854775807
r = x + y
if r != 9223372036854775807 {
- t.Errorf("0 + 9223372036854775807 = %d, want 9223372036854775807", r)
+ t.Errorf("0 %s 9223372036854775807 = %d, want 9223372036854775807", "+", r)
}
x = 1
y = -9223372036854775808
r = x + y
if r != -9223372036854775807 {
- t.Errorf("1 + -9223372036854775808 = %d, want -9223372036854775807", r)
+ t.Errorf("1 %s -9223372036854775808 = %d, want -9223372036854775807", "+", r)
}
y = -9223372036854775807
r = x + y
if r != -9223372036854775806 {
- t.Errorf("1 + -9223372036854775807 = %d, want -9223372036854775806", r)
+ t.Errorf("1 %s -9223372036854775807 = %d, want -9223372036854775806", "+", r)
}
y = -4294967296
r = x + y
if r != -4294967295 {
- t.Errorf("1 + -4294967296 = %d, want -4294967295", r)
+ t.Errorf("1 %s -4294967296 = %d, want -4294967295", "+", r)
}
y = -1
r = x + y
if r != 0 {
- t.Errorf("1 + -1 = %d, want 0", r)
+ t.Errorf("1 %s -1 = %d, want 0", "+", r)
}
y = 0
r = x + y
if r != 1 {
- t.Errorf("1 + 0 = %d, want 1", r)
+ t.Errorf("1 %s 0 = %d, want 1", "+", r)
}
y = 1
r = x + y
if r != 2 {
- t.Errorf("1 + 1 = %d, want 2", r)
+ t.Errorf("1 %s 1 = %d, want 2", "+", r)
}
y = 4294967296
r = x + y
if r != 4294967297 {
- t.Errorf("1 + 4294967296 = %d, want 4294967297", r)
+ t.Errorf("1 %s 4294967296 = %d, want 4294967297", "+", r)
}
y = 9223372036854775806
r = x + y
if r != 9223372036854775807 {
- t.Errorf("1 + 9223372036854775806 = %d, want 9223372036854775807", r)
+ t.Errorf("1 %s 9223372036854775806 = %d, want 9223372036854775807", "+", r)
}
y = 9223372036854775807
r = x + y
if r != -9223372036854775808 {
- t.Errorf("1 + 9223372036854775807 = %d, want -9223372036854775808", r)
+ t.Errorf("1 %s 9223372036854775807 = %d, want -9223372036854775808", "+", r)
}
x = 4294967296
y = -9223372036854775808
r = x + y
if r != -9223372032559808512 {
- t.Errorf("4294967296 + -9223372036854775808 = %d, want -9223372032559808512", r)
+ t.Errorf("4294967296 %s -9223372036854775808 = %d, want -9223372032559808512", "+", r)
}
y = -9223372036854775807
r = x + y
if r != -9223372032559808511 {
- t.Errorf("4294967296 + -9223372036854775807 = %d, want -9223372032559808511", r)
+ t.Errorf("4294967296 %s -9223372036854775807 = %d, want -9223372032559808511", "+", r)
}
y = -4294967296
r = x + y
if r != 0 {
- t.Errorf("4294967296 + -4294967296 = %d, want 0", r)
+ t.Errorf("4294967296 %s -4294967296 = %d, want 0", "+", r)
}
y = -1
r = x + y
if r != 4294967295 {
- t.Errorf("4294967296 + -1 = %d, want 4294967295", r)
+ t.Errorf("4294967296 %s -1 = %d, want 4294967295", "+", r)
}
y = 0
r = x + y
if r != 4294967296 {
- t.Errorf("4294967296 + 0 = %d, want 4294967296", r)
+ t.Errorf("4294967296 %s 0 = %d, want 4294967296", "+", r)
}
y = 1
r = x + y
if r != 4294967297 {
- t.Errorf("4294967296 + 1 = %d, want 4294967297", r)
+ t.Errorf("4294967296 %s 1 = %d, want 4294967297", "+", r)
}
y = 4294967296
r = x + y
if r != 8589934592 {
- t.Errorf("4294967296 + 4294967296 = %d, want 8589934592", r)
+ t.Errorf("4294967296 %s 4294967296 = %d, want 8589934592", "+", r)
}
y = 9223372036854775806
r = x + y
if r != -9223372032559808514 {
- t.Errorf("4294967296 + 9223372036854775806 = %d, want -9223372032559808514", r)
+ t.Errorf("4294967296 %s 9223372036854775806 = %d, want -9223372032559808514", "+", r)
}
y = 9223372036854775807
r = x + y
if r != -9223372032559808513 {
- t.Errorf("4294967296 + 9223372036854775807 = %d, want -9223372032559808513", r)
+ t.Errorf("4294967296 %s 9223372036854775807 = %d, want -9223372032559808513", "+", r)
}
x = 9223372036854775806
y = -9223372036854775808
r = x + y
if r != -2 {
- t.Errorf("9223372036854775806 + -9223372036854775808 = %d, want -2", r)
+ t.Errorf("9223372036854775806 %s -9223372036854775808 = %d, want -2", "+", r)
}
y = -9223372036854775807
r = x + y
if r != -1 {
- t.Errorf("9223372036854775806 + -9223372036854775807 = %d, want -1", r)
+ t.Errorf("9223372036854775806 %s -9223372036854775807 = %d, want -1", "+", r)
}
y = -4294967296
r = x + y
if r != 9223372032559808510 {
- t.Errorf("9223372036854775806 + -4294967296 = %d, want 9223372032559808510", r)
+ t.Errorf("9223372036854775806 %s -4294967296 = %d, want 9223372032559808510", "+", r)
}
y = -1
r = x + y
if r != 9223372036854775805 {
- t.Errorf("9223372036854775806 + -1 = %d, want 9223372036854775805", r)
+ t.Errorf("9223372036854775806 %s -1 = %d, want 9223372036854775805", "+", r)
}
y = 0
r = x + y
if r != 9223372036854775806 {
- t.Errorf("9223372036854775806 + 0 = %d, want 9223372036854775806", r)
+ t.Errorf("9223372036854775806 %s 0 = %d, want 9223372036854775806", "+", r)
}
y = 1
r = x + y
if r != 9223372036854775807 {
- t.Errorf("9223372036854775806 + 1 = %d, want 9223372036854775807", r)
+ t.Errorf("9223372036854775806 %s 1 = %d, want 9223372036854775807", "+", r)
}
y = 4294967296
r = x + y
if r != -9223372032559808514 {
- t.Errorf("9223372036854775806 + 4294967296 = %d, want -9223372032559808514", r)
+ t.Errorf("9223372036854775806 %s 4294967296 = %d, want -9223372032559808514", "+", r)
}
y = 9223372036854775806
r = x + y
if r != -4 {
- t.Errorf("9223372036854775806 + 9223372036854775806 = %d, want -4", r)
+ t.Errorf("9223372036854775806 %s 9223372036854775806 = %d, want -4", "+", r)
}
y = 9223372036854775807
r = x + y
if r != -3 {
- t.Errorf("9223372036854775806 + 9223372036854775807 = %d, want -3", r)
+ t.Errorf("9223372036854775806 %s 9223372036854775807 = %d, want -3", "+", r)
}
x = 9223372036854775807
y = -9223372036854775808
r = x + y
if r != -1 {
- t.Errorf("9223372036854775807 + -9223372036854775808 = %d, want -1", r)
+ t.Errorf("9223372036854775807 %s -9223372036854775808 = %d, want -1", "+", r)
}
y = -9223372036854775807
r = x + y
if r != 0 {
- t.Errorf("9223372036854775807 + -9223372036854775807 = %d, want 0", r)
+ t.Errorf("9223372036854775807 %s -9223372036854775807 = %d, want 0", "+", r)
}
y = -4294967296
r = x + y
if r != 9223372032559808511 {
- t.Errorf("9223372036854775807 + -4294967296 = %d, want 9223372032559808511", r)
+ t.Errorf("9223372036854775807 %s -4294967296 = %d, want 9223372032559808511", "+", r)
}
y = -1
r = x + y
if r != 9223372036854775806 {
- t.Errorf("9223372036854775807 + -1 = %d, want 9223372036854775806", r)
+ t.Errorf("9223372036854775807 %s -1 = %d, want 9223372036854775806", "+", r)
}
y = 0
r = x + y
if r != 9223372036854775807 {
- t.Errorf("9223372036854775807 + 0 = %d, want 9223372036854775807", r)
+ t.Errorf("9223372036854775807 %s 0 = %d, want 9223372036854775807", "+", r)
}
y = 1
r = x + y
if r != -9223372036854775808 {
- t.Errorf("9223372036854775807 + 1 = %d, want -9223372036854775808", r)
+ t.Errorf("9223372036854775807 %s 1 = %d, want -9223372036854775808", "+", r)
}
y = 4294967296
r = x + y
if r != -9223372032559808513 {
- t.Errorf("9223372036854775807 + 4294967296 = %d, want -9223372032559808513", r)
+ t.Errorf("9223372036854775807 %s 4294967296 = %d, want -9223372032559808513", "+", r)
}
y = 9223372036854775806
r = x + y
if r != -3 {
- t.Errorf("9223372036854775807 + 9223372036854775806 = %d, want -3", r)
+ t.Errorf("9223372036854775807 %s 9223372036854775806 = %d, want -3", "+", r)
}
y = 9223372036854775807
r = x + y
if r != -2 {
- t.Errorf("9223372036854775807 + 9223372036854775807 = %d, want -2", r)
+ t.Errorf("9223372036854775807 %s 9223372036854775807 = %d, want -2", "+", r)
}
}
func TestConstFoldint64sub(t *testing.T) {
@@ -820,415 +820,415 @@ func TestConstFoldint64sub(t *testing.T) {
y = -9223372036854775808
r = x - y
if r != 0 {
- t.Errorf("-9223372036854775808 - -9223372036854775808 = %d, want 0", r)
+ t.Errorf("-9223372036854775808 %s -9223372036854775808 = %d, want 0", "-", r)
}
y = -9223372036854775807
r = x - y
if r != -1 {
- t.Errorf("-9223372036854775808 - -9223372036854775807 = %d, want -1", r)
+ t.Errorf("-9223372036854775808 %s -9223372036854775807 = %d, want -1", "-", r)
}
y = -4294967296
r = x - y
if r != -9223372032559808512 {
- t.Errorf("-9223372036854775808 - -4294967296 = %d, want -9223372032559808512", r)
+ t.Errorf("-9223372036854775808 %s -4294967296 = %d, want -9223372032559808512", "-", r)
}
y = -1
r = x - y
if r != -9223372036854775807 {
- t.Errorf("-9223372036854775808 - -1 = %d, want -9223372036854775807", r)
+ t.Errorf("-9223372036854775808 %s -1 = %d, want -9223372036854775807", "-", r)
}
y = 0
r = x - y
if r != -9223372036854775808 {
- t.Errorf("-9223372036854775808 - 0 = %d, want -9223372036854775808", r)
+ t.Errorf("-9223372036854775808 %s 0 = %d, want -9223372036854775808", "-", r)
}
y = 1
r = x - y
if r != 9223372036854775807 {
- t.Errorf("-9223372036854775808 - 1 = %d, want 9223372036854775807", r)
+ t.Errorf("-9223372036854775808 %s 1 = %d, want 9223372036854775807", "-", r)
}
y = 4294967296
r = x - y
if r != 9223372032559808512 {
- t.Errorf("-9223372036854775808 - 4294967296 = %d, want 9223372032559808512", r)
+ t.Errorf("-9223372036854775808 %s 4294967296 = %d, want 9223372032559808512", "-", r)
}
y = 9223372036854775806
r = x - y
if r != 2 {
- t.Errorf("-9223372036854775808 - 9223372036854775806 = %d, want 2", r)
+ t.Errorf("-9223372036854775808 %s 9223372036854775806 = %d, want 2", "-", r)
}
y = 9223372036854775807
r = x - y
if r != 1 {
- t.Errorf("-9223372036854775808 - 9223372036854775807 = %d, want 1", r)
+ t.Errorf("-9223372036854775808 %s 9223372036854775807 = %d, want 1", "-", r)
}
x = -9223372036854775807
y = -9223372036854775808
r = x - y
if r != 1 {
- t.Errorf("-9223372036854775807 - -9223372036854775808 = %d, want 1", r)
+ t.Errorf("-9223372036854775807 %s -9223372036854775808 = %d, want 1", "-", r)
}
y = -9223372036854775807
r = x - y
if r != 0 {
- t.Errorf("-9223372036854775807 - -9223372036854775807 = %d, want 0", r)
+ t.Errorf("-9223372036854775807 %s -9223372036854775807 = %d, want 0", "-", r)
}
y = -4294967296
r = x - y
if r != -9223372032559808511 {
- t.Errorf("-9223372036854775807 - -4294967296 = %d, want -9223372032559808511", r)
+ t.Errorf("-9223372036854775807 %s -4294967296 = %d, want -9223372032559808511", "-", r)
}
y = -1
r = x - y
if r != -9223372036854775806 {
- t.Errorf("-9223372036854775807 - -1 = %d, want -9223372036854775806", r)
+ t.Errorf("-9223372036854775807 %s -1 = %d, want -9223372036854775806", "-", r)
}
y = 0
r = x - y
if r != -9223372036854775807 {
- t.Errorf("-9223372036854775807 - 0 = %d, want -9223372036854775807", r)
+ t.Errorf("-9223372036854775807 %s 0 = %d, want -9223372036854775807", "-", r)
}
y = 1
r = x - y
if r != -9223372036854775808 {
- t.Errorf("-9223372036854775807 - 1 = %d, want -9223372036854775808", r)
+ t.Errorf("-9223372036854775807 %s 1 = %d, want -9223372036854775808", "-", r)
}
y = 4294967296
r = x - y
if r != 9223372032559808513 {
- t.Errorf("-9223372036854775807 - 4294967296 = %d, want 9223372032559808513", r)
+ t.Errorf("-9223372036854775807 %s 4294967296 = %d, want 9223372032559808513", "-", r)
}
y = 9223372036854775806
r = x - y
if r != 3 {
- t.Errorf("-9223372036854775807 - 9223372036854775806 = %d, want 3", r)
+ t.Errorf("-9223372036854775807 %s 9223372036854775806 = %d, want 3", "-", r)
}
y = 9223372036854775807
r = x - y
if r != 2 {
- t.Errorf("-9223372036854775807 - 9223372036854775807 = %d, want 2", r)
+ t.Errorf("-9223372036854775807 %s 9223372036854775807 = %d, want 2", "-", r)
}
x = -4294967296
y = -9223372036854775808
r = x - y
if r != 9223372032559808512 {
- t.Errorf("-4294967296 - -9223372036854775808 = %d, want 9223372032559808512", r)
+ t.Errorf("-4294967296 %s -9223372036854775808 = %d, want 9223372032559808512", "-", r)
}
y = -9223372036854775807
r = x - y
if r != 9223372032559808511 {
- t.Errorf("-4294967296 - -9223372036854775807 = %d, want 9223372032559808511", r)
+ t.Errorf("-4294967296 %s -9223372036854775807 = %d, want 9223372032559808511", "-", r)
}
y = -4294967296
r = x - y
if r != 0 {
- t.Errorf("-4294967296 - -4294967296 = %d, want 0", r)
+ t.Errorf("-4294967296 %s -4294967296 = %d, want 0", "-", r)
}
y = -1
r = x - y
if r != -4294967295 {
- t.Errorf("-4294967296 - -1 = %d, want -4294967295", r)
+ t.Errorf("-4294967296 %s -1 = %d, want -4294967295", "-", r)
}
y = 0
r = x - y
if r != -4294967296 {
- t.Errorf("-4294967296 - 0 = %d, want -4294967296", r)
+ t.Errorf("-4294967296 %s 0 = %d, want -4294967296", "-", r)
}
y = 1
r = x - y
if r != -4294967297 {
- t.Errorf("-4294967296 - 1 = %d, want -4294967297", r)
+ t.Errorf("-4294967296 %s 1 = %d, want -4294967297", "-", r)
}
y = 4294967296
r = x - y
if r != -8589934592 {
- t.Errorf("-4294967296 - 4294967296 = %d, want -8589934592", r)
+ t.Errorf("-4294967296 %s 4294967296 = %d, want -8589934592", "-", r)
}
y = 9223372036854775806
r = x - y
if r != 9223372032559808514 {
- t.Errorf("-4294967296 - 9223372036854775806 = %d, want 9223372032559808514", r)
+ t.Errorf("-4294967296 %s 9223372036854775806 = %d, want 9223372032559808514", "-", r)
}
y = 9223372036854775807
r = x - y
if r != 9223372032559808513 {
- t.Errorf("-4294967296 - 9223372036854775807 = %d, want 9223372032559808513", r)
+ t.Errorf("-4294967296 %s 9223372036854775807 = %d, want 9223372032559808513", "-", r)
}
x = -1
y = -9223372036854775808
r = x - y
if r != 9223372036854775807 {
- t.Errorf("-1 - -9223372036854775808 = %d, want 9223372036854775807", r)
+ t.Errorf("-1 %s -9223372036854775808 = %d, want 9223372036854775807", "-", r)
}
y = -9223372036854775807
r = x - y
if r != 9223372036854775806 {
- t.Errorf("-1 - -9223372036854775807 = %d, want 9223372036854775806", r)
+ t.Errorf("-1 %s -9223372036854775807 = %d, want 9223372036854775806", "-", r)
}
y = -4294967296
r = x - y
if r != 4294967295 {
- t.Errorf("-1 - -4294967296 = %d, want 4294967295", r)
+ t.Errorf("-1 %s -4294967296 = %d, want 4294967295", "-", r)
}
y = -1
r = x - y
if r != 0 {
- t.Errorf("-1 - -1 = %d, want 0", r)
+ t.Errorf("-1 %s -1 = %d, want 0", "-", r)
}
y = 0
r = x - y
if r != -1 {
- t.Errorf("-1 - 0 = %d, want -1", r)
+ t.Errorf("-1 %s 0 = %d, want -1", "-", r)
}
y = 1
r = x - y
if r != -2 {
- t.Errorf("-1 - 1 = %d, want -2", r)
+ t.Errorf("-1 %s 1 = %d, want -2", "-", r)
}
y = 4294967296
r = x - y
if r != -4294967297 {
- t.Errorf("-1 - 4294967296 = %d, want -4294967297", r)
+ t.Errorf("-1 %s 4294967296 = %d, want -4294967297", "-", r)
}
y = 9223372036854775806
r = x - y
if r != -9223372036854775807 {
- t.Errorf("-1 - 9223372036854775806 = %d, want -9223372036854775807", r)
+ t.Errorf("-1 %s 9223372036854775806 = %d, want -9223372036854775807", "-", r)
}
y = 9223372036854775807
r = x - y
if r != -9223372036854775808 {
- t.Errorf("-1 - 9223372036854775807 = %d, want -9223372036854775808", r)
+ t.Errorf("-1 %s 9223372036854775807 = %d, want -9223372036854775808", "-", r)
}
x = 0
y = -9223372036854775808
r = x - y
if r != -9223372036854775808 {
- t.Errorf("0 - -9223372036854775808 = %d, want -9223372036854775808", r)
+ t.Errorf("0 %s -9223372036854775808 = %d, want -9223372036854775808", "-", r)
}
y = -9223372036854775807
r = x - y
if r != 9223372036854775807 {
- t.Errorf("0 - -9223372036854775807 = %d, want 9223372036854775807", r)
+ t.Errorf("0 %s -9223372036854775807 = %d, want 9223372036854775807", "-", r)
}
y = -4294967296
r = x - y
if r != 4294967296 {
- t.Errorf("0 - -4294967296 = %d, want 4294967296", r)
+ t.Errorf("0 %s -4294967296 = %d, want 4294967296", "-", r)
}
y = -1
r = x - y
if r != 1 {
- t.Errorf("0 - -1 = %d, want 1", r)
+ t.Errorf("0 %s -1 = %d, want 1", "-", r)
}
y = 0
r = x - y
if r != 0 {
- t.Errorf("0 - 0 = %d, want 0", r)
+ t.Errorf("0 %s 0 = %d, want 0", "-", r)
}
y = 1
r = x - y
if r != -1 {
- t.Errorf("0 - 1 = %d, want -1", r)
+ t.Errorf("0 %s 1 = %d, want -1", "-", r)
}
y = 4294967296
r = x - y
if r != -4294967296 {
- t.Errorf("0 - 4294967296 = %d, want -4294967296", r)
+ t.Errorf("0 %s 4294967296 = %d, want -4294967296", "-", r)
}
y = 9223372036854775806
r = x - y
if r != -9223372036854775806 {
- t.Errorf("0 - 9223372036854775806 = %d, want -9223372036854775806", r)
+ t.Errorf("0 %s 9223372036854775806 = %d, want -9223372036854775806", "-", r)
}
y = 9223372036854775807
r = x - y
if r != -9223372036854775807 {
- t.Errorf("0 - 9223372036854775807 = %d, want -9223372036854775807", r)
+ t.Errorf("0 %s 9223372036854775807 = %d, want -9223372036854775807", "-", r)
}
x = 1
y = -9223372036854775808
r = x - y
if r != -9223372036854775807 {
- t.Errorf("1 - -9223372036854775808 = %d, want -9223372036854775807", r)
+ t.Errorf("1 %s -9223372036854775808 = %d, want -9223372036854775807", "-", r)
}
y = -9223372036854775807
r = x - y
if r != -9223372036854775808 {
- t.Errorf("1 - -9223372036854775807 = %d, want -9223372036854775808", r)
+ t.Errorf("1 %s -9223372036854775807 = %d, want -9223372036854775808", "-", r)
}
y = -4294967296
r = x - y
if r != 4294967297 {
- t.Errorf("1 - -4294967296 = %d, want 4294967297", r)
+ t.Errorf("1 %s -4294967296 = %d, want 4294967297", "-", r)
}
y = -1
r = x - y
if r != 2 {
- t.Errorf("1 - -1 = %d, want 2", r)
+ t.Errorf("1 %s -1 = %d, want 2", "-", r)
}
y = 0
r = x - y
if r != 1 {
- t.Errorf("1 - 0 = %d, want 1", r)
+ t.Errorf("1 %s 0 = %d, want 1", "-", r)
}
y = 1
r = x - y
if r != 0 {
- t.Errorf("1 - 1 = %d, want 0", r)
+ t.Errorf("1 %s 1 = %d, want 0", "-", r)
}
y = 4294967296
r = x - y
if r != -4294967295 {
- t.Errorf("1 - 4294967296 = %d, want -4294967295", r)
+ t.Errorf("1 %s 4294967296 = %d, want -4294967295", "-", r)
}
y = 9223372036854775806
r = x - y
if r != -9223372036854775805 {
- t.Errorf("1 - 9223372036854775806 = %d, want -9223372036854775805", r)
+ t.Errorf("1 %s 9223372036854775806 = %d, want -9223372036854775805", "-", r)
}
y = 9223372036854775807
r = x - y
if r != -9223372036854775806 {
- t.Errorf("1 - 9223372036854775807 = %d, want -9223372036854775806", r)
+ t.Errorf("1 %s 9223372036854775807 = %d, want -9223372036854775806", "-", r)
}
x = 4294967296
y = -9223372036854775808
r = x - y
if r != -9223372032559808512 {
- t.Errorf("4294967296 - -9223372036854775808 = %d, want -9223372032559808512", r)
+ t.Errorf("4294967296 %s -9223372036854775808 = %d, want -9223372032559808512", "-", r)
}
y = -9223372036854775807
r = x - y
if r != -9223372032559808513 {
- t.Errorf("4294967296 - -9223372036854775807 = %d, want -9223372032559808513", r)
+ t.Errorf("4294967296 %s -9223372036854775807 = %d, want -9223372032559808513", "-", r)
}
y = -4294967296
r = x - y
if r != 8589934592 {
- t.Errorf("4294967296 - -4294967296 = %d, want 8589934592", r)
+ t.Errorf("4294967296 %s -4294967296 = %d, want 8589934592", "-", r)
}
y = -1
r = x - y
if r != 4294967297 {
- t.Errorf("4294967296 - -1 = %d, want 4294967297", r)
+ t.Errorf("4294967296 %s -1 = %d, want 4294967297", "-", r)
}
y = 0
r = x - y
if r != 4294967296 {
- t.Errorf("4294967296 - 0 = %d, want 4294967296", r)
+ t.Errorf("4294967296 %s 0 = %d, want 4294967296", "-", r)
}
y = 1
r = x - y
if r != 4294967295 {
- t.Errorf("4294967296 - 1 = %d, want 4294967295", r)
+ t.Errorf("4294967296 %s 1 = %d, want 4294967295", "-", r)
}
y = 4294967296
r = x - y
if r != 0 {
- t.Errorf("4294967296 - 4294967296 = %d, want 0", r)
+ t.Errorf("4294967296 %s 4294967296 = %d, want 0", "-", r)
}
y = 9223372036854775806
r = x - y
if r != -9223372032559808510 {
- t.Errorf("4294967296 - 9223372036854775806 = %d, want -9223372032559808510", r)
+ t.Errorf("4294967296 %s 9223372036854775806 = %d, want -9223372032559808510", "-", r)
}
y = 9223372036854775807
r = x - y
if r != -9223372032559808511 {
- t.Errorf("4294967296 - 9223372036854775807 = %d, want -9223372032559808511", r)
+ t.Errorf("4294967296 %s 9223372036854775807 = %d, want -9223372032559808511", "-", r)
}
x = 9223372036854775806
y = -9223372036854775808
r = x - y
if r != -2 {
- t.Errorf("9223372036854775806 - -9223372036854775808 = %d, want -2", r)
+ t.Errorf("9223372036854775806 %s -9223372036854775808 = %d, want -2", "-", r)
}
y = -9223372036854775807
r = x - y
if r != -3 {
- t.Errorf("9223372036854775806 - -9223372036854775807 = %d, want -3", r)
+ t.Errorf("9223372036854775806 %s -9223372036854775807 = %d, want -3", "-", r)
}
y = -4294967296
r = x - y
if r != -9223372032559808514 {
- t.Errorf("9223372036854775806 - -4294967296 = %d, want -9223372032559808514", r)
+ t.Errorf("9223372036854775806 %s -4294967296 = %d, want -9223372032559808514", "-", r)
}
y = -1
r = x - y
if r != 9223372036854775807 {
- t.Errorf("9223372036854775806 - -1 = %d, want 9223372036854775807", r)
+ t.Errorf("9223372036854775806 %s -1 = %d, want 9223372036854775807", "-", r)
}
y = 0
r = x - y
if r != 9223372036854775806 {
- t.Errorf("9223372036854775806 - 0 = %d, want 9223372036854775806", r)
+ t.Errorf("9223372036854775806 %s 0 = %d, want 9223372036854775806", "-", r)
}
y = 1
r = x - y
if r != 9223372036854775805 {
- t.Errorf("9223372036854775806 - 1 = %d, want 9223372036854775805", r)
+ t.Errorf("9223372036854775806 %s 1 = %d, want 9223372036854775805", "-", r)
}
y = 4294967296
r = x - y
if r != 9223372032559808510 {
- t.Errorf("9223372036854775806 - 4294967296 = %d, want 9223372032559808510", r)
+ t.Errorf("9223372036854775806 %s 4294967296 = %d, want 9223372032559808510", "-", r)
}
y = 9223372036854775806
r = x - y
if r != 0 {
- t.Errorf("9223372036854775806 - 9223372036854775806 = %d, want 0", r)
+ t.Errorf("9223372036854775806 %s 9223372036854775806 = %d, want 0", "-", r)
}
y = 9223372036854775807
r = x - y
if r != -1 {
- t.Errorf("9223372036854775806 - 9223372036854775807 = %d, want -1", r)
+ t.Errorf("9223372036854775806 %s 9223372036854775807 = %d, want -1", "-", r)
}
x = 9223372036854775807
y = -9223372036854775808
r = x - y
if r != -1 {
- t.Errorf("9223372036854775807 - -9223372036854775808 = %d, want -1", r)
+ t.Errorf("9223372036854775807 %s -9223372036854775808 = %d, want -1", "-", r)
}
y = -9223372036854775807
r = x - y
if r != -2 {
- t.Errorf("9223372036854775807 - -9223372036854775807 = %d, want -2", r)
+ t.Errorf("9223372036854775807 %s -9223372036854775807 = %d, want -2", "-", r)
}
y = -4294967296
r = x - y
if r != -9223372032559808513 {
- t.Errorf("9223372036854775807 - -4294967296 = %d, want -9223372032559808513", r)
+ t.Errorf("9223372036854775807 %s -4294967296 = %d, want -9223372032559808513", "-", r)
}
y = -1
r = x - y
if r != -9223372036854775808 {
- t.Errorf("9223372036854775807 - -1 = %d, want -9223372036854775808", r)
+ t.Errorf("9223372036854775807 %s -1 = %d, want -9223372036854775808", "-", r)
}
y = 0
r = x - y
if r != 9223372036854775807 {
- t.Errorf("9223372036854775807 - 0 = %d, want 9223372036854775807", r)
+ t.Errorf("9223372036854775807 %s 0 = %d, want 9223372036854775807", "-", r)
}
y = 1
r = x - y
if r != 9223372036854775806 {
- t.Errorf("9223372036854775807 - 1 = %d, want 9223372036854775806", r)
+ t.Errorf("9223372036854775807 %s 1 = %d, want 9223372036854775806", "-", r)
}
y = 4294967296
r = x - y
if r != 9223372032559808511 {
- t.Errorf("9223372036854775807 - 4294967296 = %d, want 9223372032559808511", r)
+ t.Errorf("9223372036854775807 %s 4294967296 = %d, want 9223372032559808511", "-", r)
}
y = 9223372036854775806
r = x - y
if r != 1 {
- t.Errorf("9223372036854775807 - 9223372036854775806 = %d, want 1", r)
+ t.Errorf("9223372036854775807 %s 9223372036854775806 = %d, want 1", "-", r)
}
y = 9223372036854775807
r = x - y
if r != 0 {
- t.Errorf("9223372036854775807 - 9223372036854775807 = %d, want 0", r)
+ t.Errorf("9223372036854775807 %s 9223372036854775807 = %d, want 0", "-", r)
}
}
func TestConstFoldint64div(t *testing.T) {
@@ -1237,370 +1237,370 @@ func TestConstFoldint64div(t *testing.T) {
y = -9223372036854775808
r = x / y
if r != 1 {
- t.Errorf("-9223372036854775808 / -9223372036854775808 = %d, want 1", r)
+ t.Errorf("-9223372036854775808 %s -9223372036854775808 = %d, want 1", "/", r)
}
y = -9223372036854775807
r = x / y
if r != 1 {
- t.Errorf("-9223372036854775808 / -9223372036854775807 = %d, want 1", r)
+ t.Errorf("-9223372036854775808 %s -9223372036854775807 = %d, want 1", "/", r)
}
y = -4294967296
r = x / y
if r != 2147483648 {
- t.Errorf("-9223372036854775808 / -4294967296 = %d, want 2147483648", r)
+ t.Errorf("-9223372036854775808 %s -4294967296 = %d, want 2147483648", "/", r)
}
y = -1
r = x / y
if r != -9223372036854775808 {
- t.Errorf("-9223372036854775808 / -1 = %d, want -9223372036854775808", r)
+ t.Errorf("-9223372036854775808 %s -1 = %d, want -9223372036854775808", "/", r)
}
y = 1
r = x / y
if r != -9223372036854775808 {
- t.Errorf("-9223372036854775808 / 1 = %d, want -9223372036854775808", r)
+ t.Errorf("-9223372036854775808 %s 1 = %d, want -9223372036854775808", "/", r)
}
y = 4294967296
r = x / y
if r != -2147483648 {
- t.Errorf("-9223372036854775808 / 4294967296 = %d, want -2147483648", r)
+ t.Errorf("-9223372036854775808 %s 4294967296 = %d, want -2147483648", "/", r)
}
y = 9223372036854775806
r = x / y
if r != -1 {
- t.Errorf("-9223372036854775808 / 9223372036854775806 = %d, want -1", r)
+ t.Errorf("-9223372036854775808 %s 9223372036854775806 = %d, want -1", "/", r)
}
y = 9223372036854775807
r = x / y
if r != -1 {
- t.Errorf("-9223372036854775808 / 9223372036854775807 = %d, want -1", r)
+ t.Errorf("-9223372036854775808 %s 9223372036854775807 = %d, want -1", "/", r)
}
x = -9223372036854775807
y = -9223372036854775808
r = x / y
if r != 0 {
- t.Errorf("-9223372036854775807 / -9223372036854775808 = %d, want 0", r)
+ t.Errorf("-9223372036854775807 %s -9223372036854775808 = %d, want 0", "/", r)
}
y = -9223372036854775807
r = x / y
if r != 1 {
- t.Errorf("-9223372036854775807 / -9223372036854775807 = %d, want 1", r)
+ t.Errorf("-9223372036854775807 %s -9223372036854775807 = %d, want 1", "/", r)
}
y = -4294967296
r = x / y
if r != 2147483647 {
- t.Errorf("-9223372036854775807 / -4294967296 = %d, want 2147483647", r)
+ t.Errorf("-9223372036854775807 %s -4294967296 = %d, want 2147483647", "/", r)
}
y = -1
r = x / y
if r != 9223372036854775807 {
- t.Errorf("-9223372036854775807 / -1 = %d, want 9223372036854775807", r)
+ t.Errorf("-9223372036854775807 %s -1 = %d, want 9223372036854775807", "/", r)
}
y = 1
r = x / y
if r != -9223372036854775807 {
- t.Errorf("-9223372036854775807 / 1 = %d, want -9223372036854775807", r)
+ t.Errorf("-9223372036854775807 %s 1 = %d, want -9223372036854775807", "/", r)
}
y = 4294967296
r = x / y
if r != -2147483647 {
- t.Errorf("-9223372036854775807 / 4294967296 = %d, want -2147483647", r)
+ t.Errorf("-9223372036854775807 %s 4294967296 = %d, want -2147483647", "/", r)
}
y = 9223372036854775806
r = x / y
if r != -1 {
- t.Errorf("-9223372036854775807 / 9223372036854775806 = %d, want -1", r)
+ t.Errorf("-9223372036854775807 %s 9223372036854775806 = %d, want -1", "/", r)
}
y = 9223372036854775807
r = x / y
if r != -1 {
- t.Errorf("-9223372036854775807 / 9223372036854775807 = %d, want -1", r)
+ t.Errorf("-9223372036854775807 %s 9223372036854775807 = %d, want -1", "/", r)
}
x = -4294967296
y = -9223372036854775808
r = x / y
if r != 0 {
- t.Errorf("-4294967296 / -9223372036854775808 = %d, want 0", r)
+ t.Errorf("-4294967296 %s -9223372036854775808 = %d, want 0", "/", r)
}
y = -9223372036854775807
r = x / y
if r != 0 {
- t.Errorf("-4294967296 / -9223372036854775807 = %d, want 0", r)
+ t.Errorf("-4294967296 %s -9223372036854775807 = %d, want 0", "/", r)
}
y = -4294967296
r = x / y
if r != 1 {
- t.Errorf("-4294967296 / -4294967296 = %d, want 1", r)
+ t.Errorf("-4294967296 %s -4294967296 = %d, want 1", "/", r)
}
y = -1
r = x / y
if r != 4294967296 {
- t.Errorf("-4294967296 / -1 = %d, want 4294967296", r)
+ t.Errorf("-4294967296 %s -1 = %d, want 4294967296", "/", r)
}
y = 1
r = x / y
if r != -4294967296 {
- t.Errorf("-4294967296 / 1 = %d, want -4294967296", r)
+ t.Errorf("-4294967296 %s 1 = %d, want -4294967296", "/", r)
}
y = 4294967296
r = x / y
if r != -1 {
- t.Errorf("-4294967296 / 4294967296 = %d, want -1", r)
+ t.Errorf("-4294967296 %s 4294967296 = %d, want -1", "/", r)
}
y = 9223372036854775806
r = x / y
if r != 0 {
- t.Errorf("-4294967296 / 9223372036854775806 = %d, want 0", r)
+ t.Errorf("-4294967296 %s 9223372036854775806 = %d, want 0", "/", r)
}
y = 9223372036854775807
r = x / y
if r != 0 {
- t.Errorf("-4294967296 / 9223372036854775807 = %d, want 0", r)
+ t.Errorf("-4294967296 %s 9223372036854775807 = %d, want 0", "/", r)
}
x = -1
y = -9223372036854775808
r = x / y
if r != 0 {
- t.Errorf("-1 / -9223372036854775808 = %d, want 0", r)
+ t.Errorf("-1 %s -9223372036854775808 = %d, want 0", "/", r)
}
y = -9223372036854775807
r = x / y
if r != 0 {
- t.Errorf("-1 / -9223372036854775807 = %d, want 0", r)
+ t.Errorf("-1 %s -9223372036854775807 = %d, want 0", "/", r)
}
y = -4294967296
r = x / y
if r != 0 {
- t.Errorf("-1 / -4294967296 = %d, want 0", r)
+ t.Errorf("-1 %s -4294967296 = %d, want 0", "/", r)
}
y = -1
r = x / y
if r != 1 {
- t.Errorf("-1 / -1 = %d, want 1", r)
+ t.Errorf("-1 %s -1 = %d, want 1", "/", r)
}
y = 1
r = x / y
if r != -1 {
- t.Errorf("-1 / 1 = %d, want -1", r)
+ t.Errorf("-1 %s 1 = %d, want -1", "/", r)
}
y = 4294967296
r = x / y
if r != 0 {
- t.Errorf("-1 / 4294967296 = %d, want 0", r)
+ t.Errorf("-1 %s 4294967296 = %d, want 0", "/", r)
}
y = 9223372036854775806
r = x / y
if r != 0 {
- t.Errorf("-1 / 9223372036854775806 = %d, want 0", r)
+ t.Errorf("-1 %s 9223372036854775806 = %d, want 0", "/", r)
}
y = 9223372036854775807
r = x / y
if r != 0 {
- t.Errorf("-1 / 9223372036854775807 = %d, want 0", r)
+ t.Errorf("-1 %s 9223372036854775807 = %d, want 0", "/", r)
}
x = 0
y = -9223372036854775808
r = x / y
if r != 0 {
- t.Errorf("0 / -9223372036854775808 = %d, want 0", r)
+ t.Errorf("0 %s -9223372036854775808 = %d, want 0", "/", r)
}
y = -9223372036854775807
r = x / y
if r != 0 {
- t.Errorf("0 / -9223372036854775807 = %d, want 0", r)
+ t.Errorf("0 %s -9223372036854775807 = %d, want 0", "/", r)
}
y = -4294967296
r = x / y
if r != 0 {
- t.Errorf("0 / -4294967296 = %d, want 0", r)
+ t.Errorf("0 %s -4294967296 = %d, want 0", "/", r)
}
y = -1
r = x / y
if r != 0 {
- t.Errorf("0 / -1 = %d, want 0", r)
+ t.Errorf("0 %s -1 = %d, want 0", "/", r)
}
y = 1
r = x / y
if r != 0 {
- t.Errorf("0 / 1 = %d, want 0", r)
+ t.Errorf("0 %s 1 = %d, want 0", "/", r)
}
y = 4294967296
r = x / y
if r != 0 {
- t.Errorf("0 / 4294967296 = %d, want 0", r)
+ t.Errorf("0 %s 4294967296 = %d, want 0", "/", r)
}
y = 9223372036854775806
r = x / y
if r != 0 {
- t.Errorf("0 / 9223372036854775806 = %d, want 0", r)
+ t.Errorf("0 %s 9223372036854775806 = %d, want 0", "/", r)
}
y = 9223372036854775807
r = x / y
if r != 0 {
- t.Errorf("0 / 9223372036854775807 = %d, want 0", r)
+ t.Errorf("0 %s 9223372036854775807 = %d, want 0", "/", r)
}
x = 1
y = -9223372036854775808
r = x / y
if r != 0 {
- t.Errorf("1 / -9223372036854775808 = %d, want 0", r)
+ t.Errorf("1 %s -9223372036854775808 = %d, want 0", "/", r)
}
y = -9223372036854775807
r = x / y
if r != 0 {
- t.Errorf("1 / -9223372036854775807 = %d, want 0", r)
+ t.Errorf("1 %s -9223372036854775807 = %d, want 0", "/", r)
}
y = -4294967296
r = x / y
if r != 0 {
- t.Errorf("1 / -4294967296 = %d, want 0", r)
+ t.Errorf("1 %s -4294967296 = %d, want 0", "/", r)
}
y = -1
r = x / y
if r != -1 {
- t.Errorf("1 / -1 = %d, want -1", r)
+ t.Errorf("1 %s -1 = %d, want -1", "/", r)
}
y = 1
r = x / y
if r != 1 {
- t.Errorf("1 / 1 = %d, want 1", r)
+ t.Errorf("1 %s 1 = %d, want 1", "/", r)
}
y = 4294967296
r = x / y
if r != 0 {
- t.Errorf("1 / 4294967296 = %d, want 0", r)
+ t.Errorf("1 %s 4294967296 = %d, want 0", "/", r)
}
y = 9223372036854775806
r = x / y
if r != 0 {
- t.Errorf("1 / 9223372036854775806 = %d, want 0", r)
+ t.Errorf("1 %s 9223372036854775806 = %d, want 0", "/", r)
}
y = 9223372036854775807
r = x / y
if r != 0 {
- t.Errorf("1 / 9223372036854775807 = %d, want 0", r)
+ t.Errorf("1 %s 9223372036854775807 = %d, want 0", "/", r)
}
x = 4294967296
y = -9223372036854775808
r = x / y
if r != 0 {
- t.Errorf("4294967296 / -9223372036854775808 = %d, want 0", r)
+ t.Errorf("4294967296 %s -9223372036854775808 = %d, want 0", "/", r)
}
y = -9223372036854775807
r = x / y
if r != 0 {
- t.Errorf("4294967296 / -9223372036854775807 = %d, want 0", r)
+ t.Errorf("4294967296 %s -9223372036854775807 = %d, want 0", "/", r)
}
y = -4294967296
r = x / y
if r != -1 {
- t.Errorf("4294967296 / -4294967296 = %d, want -1", r)
+ t.Errorf("4294967296 %s -4294967296 = %d, want -1", "/", r)
}
y = -1
r = x / y
if r != -4294967296 {
- t.Errorf("4294967296 / -1 = %d, want -4294967296", r)
+ t.Errorf("4294967296 %s -1 = %d, want -4294967296", "/", r)
}
y = 1
r = x / y
if r != 4294967296 {
- t.Errorf("4294967296 / 1 = %d, want 4294967296", r)
+ t.Errorf("4294967296 %s 1 = %d, want 4294967296", "/", r)
}
y = 4294967296
r = x / y
if r != 1 {
- t.Errorf("4294967296 / 4294967296 = %d, want 1", r)
+ t.Errorf("4294967296 %s 4294967296 = %d, want 1", "/", r)
}
y = 9223372036854775806
r = x / y
if r != 0 {
- t.Errorf("4294967296 / 9223372036854775806 = %d, want 0", r)
+ t.Errorf("4294967296 %s 9223372036854775806 = %d, want 0", "/", r)
}
y = 9223372036854775807
r = x / y
if r != 0 {
- t.Errorf("4294967296 / 9223372036854775807 = %d, want 0", r)
+ t.Errorf("4294967296 %s 9223372036854775807 = %d, want 0", "/", r)
}
x = 9223372036854775806
y = -9223372036854775808
r = x / y
if r != 0 {
- t.Errorf("9223372036854775806 / -9223372036854775808 = %d, want 0", r)
+ t.Errorf("9223372036854775806 %s -9223372036854775808 = %d, want 0", "/", r)
}
y = -9223372036854775807
r = x / y
if r != 0 {
- t.Errorf("9223372036854775806 / -9223372036854775807 = %d, want 0", r)
+ t.Errorf("9223372036854775806 %s -9223372036854775807 = %d, want 0", "/", r)
}
y = -4294967296
r = x / y
if r != -2147483647 {
- t.Errorf("9223372036854775806 / -4294967296 = %d, want -2147483647", r)
+ t.Errorf("9223372036854775806 %s -4294967296 = %d, want -2147483647", "/", r)
}
y = -1
r = x / y
if r != -9223372036854775806 {
- t.Errorf("9223372036854775806 / -1 = %d, want -9223372036854775806", r)
+ t.Errorf("9223372036854775806 %s -1 = %d, want -9223372036854775806", "/", r)
}
y = 1
r = x / y
if r != 9223372036854775806 {
- t.Errorf("9223372036854775806 / 1 = %d, want 9223372036854775806", r)
+ t.Errorf("9223372036854775806 %s 1 = %d, want 9223372036854775806", "/", r)
}
y = 4294967296
r = x / y
if r != 2147483647 {
- t.Errorf("9223372036854775806 / 4294967296 = %d, want 2147483647", r)
+ t.Errorf("9223372036854775806 %s 4294967296 = %d, want 2147483647", "/", r)
}
y = 9223372036854775806
r = x / y
if r != 1 {
- t.Errorf("9223372036854775806 / 9223372036854775806 = %d, want 1", r)
+ t.Errorf("9223372036854775806 %s 9223372036854775806 = %d, want 1", "/", r)
}
y = 9223372036854775807
r = x / y
if r != 0 {
- t.Errorf("9223372036854775806 / 9223372036854775807 = %d, want 0", r)
+ t.Errorf("9223372036854775806 %s 9223372036854775807 = %d, want 0", "/", r)
}
x = 9223372036854775807
y = -9223372036854775808
r = x / y
if r != 0 {
- t.Errorf("9223372036854775807 / -9223372036854775808 = %d, want 0", r)
+ t.Errorf("9223372036854775807 %s -9223372036854775808 = %d, want 0", "/", r)
}
y = -9223372036854775807
r = x / y
if r != -1 {
- t.Errorf("9223372036854775807 / -9223372036854775807 = %d, want -1", r)
+ t.Errorf("9223372036854775807 %s -9223372036854775807 = %d, want -1", "/", r)
}
y = -4294967296
r = x / y
if r != -2147483647 {
- t.Errorf("9223372036854775807 / -4294967296 = %d, want -2147483647", r)
+ t.Errorf("9223372036854775807 %s -4294967296 = %d, want -2147483647", "/", r)
}
y = -1
r = x / y
if r != -9223372036854775807 {
- t.Errorf("9223372036854775807 / -1 = %d, want -9223372036854775807", r)
+ t.Errorf("9223372036854775807 %s -1 = %d, want -9223372036854775807", "/", r)
}
y = 1
r = x / y
if r != 9223372036854775807 {
- t.Errorf("9223372036854775807 / 1 = %d, want 9223372036854775807", r)
+ t.Errorf("9223372036854775807 %s 1 = %d, want 9223372036854775807", "/", r)
}
y = 4294967296
r = x / y
if r != 2147483647 {
- t.Errorf("9223372036854775807 / 4294967296 = %d, want 2147483647", r)
+ t.Errorf("9223372036854775807 %s 4294967296 = %d, want 2147483647", "/", r)
}
y = 9223372036854775806
r = x / y
if r != 1 {
- t.Errorf("9223372036854775807 / 9223372036854775806 = %d, want 1", r)
+ t.Errorf("9223372036854775807 %s 9223372036854775806 = %d, want 1", "/", r)
}
y = 9223372036854775807
r = x / y
if r != 1 {
- t.Errorf("9223372036854775807 / 9223372036854775807 = %d, want 1", r)
+ t.Errorf("9223372036854775807 %s 9223372036854775807 = %d, want 1", "/", r)
}
}
func TestConstFoldint64mul(t *testing.T) {
@@ -1609,415 +1609,415 @@ func TestConstFoldint64mul(t *testing.T) {
y = -9223372036854775808
r = x * y
if r != 0 {
- t.Errorf("-9223372036854775808 * -9223372036854775808 = %d, want 0", r)
+ t.Errorf("-9223372036854775808 %s -9223372036854775808 = %d, want 0", "*", r)
}
y = -9223372036854775807
r = x * y
if r != -9223372036854775808 {
- t.Errorf("-9223372036854775808 * -9223372036854775807 = %d, want -9223372036854775808", r)
+ t.Errorf("-9223372036854775808 %s -9223372036854775807 = %d, want -9223372036854775808", "*", r)
}
y = -4294967296
r = x * y
if r != 0 {
- t.Errorf("-9223372036854775808 * -4294967296 = %d, want 0", r)
+ t.Errorf("-9223372036854775808 %s -4294967296 = %d, want 0", "*", r)
}
y = -1
r = x * y
if r != -9223372036854775808 {
- t.Errorf("-9223372036854775808 * -1 = %d, want -9223372036854775808", r)
+ t.Errorf("-9223372036854775808 %s -1 = %d, want -9223372036854775808", "*", r)
}
y = 0
r = x * y
if r != 0 {
- t.Errorf("-9223372036854775808 * 0 = %d, want 0", r)
+ t.Errorf("-9223372036854775808 %s 0 = %d, want 0", "*", r)
}
y = 1
r = x * y
if r != -9223372036854775808 {
- t.Errorf("-9223372036854775808 * 1 = %d, want -9223372036854775808", r)
+ t.Errorf("-9223372036854775808 %s 1 = %d, want -9223372036854775808", "*", r)
}
y = 4294967296
r = x * y
if r != 0 {
- t.Errorf("-9223372036854775808 * 4294967296 = %d, want 0", r)
+ t.Errorf("-9223372036854775808 %s 4294967296 = %d, want 0", "*", r)
}
y = 9223372036854775806
r = x * y
if r != 0 {
- t.Errorf("-9223372036854775808 * 9223372036854775806 = %d, want 0", r)
+ t.Errorf("-9223372036854775808 %s 9223372036854775806 = %d, want 0", "*", r)
}
y = 9223372036854775807
r = x * y
if r != -9223372036854775808 {
- t.Errorf("-9223372036854775808 * 9223372036854775807 = %d, want -9223372036854775808", r)
+ t.Errorf("-9223372036854775808 %s 9223372036854775807 = %d, want -9223372036854775808", "*", r)
}
x = -9223372036854775807
y = -9223372036854775808
r = x * y
if r != -9223372036854775808 {
- t.Errorf("-9223372036854775807 * -9223372036854775808 = %d, want -9223372036854775808", r)
+ t.Errorf("-9223372036854775807 %s -9223372036854775808 = %d, want -9223372036854775808", "*", r)
}
y = -9223372036854775807
r = x * y
if r != 1 {
- t.Errorf("-9223372036854775807 * -9223372036854775807 = %d, want 1", r)
+ t.Errorf("-9223372036854775807 %s -9223372036854775807 = %d, want 1", "*", r)
}
y = -4294967296
r = x * y
if r != -4294967296 {
- t.Errorf("-9223372036854775807 * -4294967296 = %d, want -4294967296", r)
+ t.Errorf("-9223372036854775807 %s -4294967296 = %d, want -4294967296", "*", r)
}
y = -1
r = x * y
if r != 9223372036854775807 {
- t.Errorf("-9223372036854775807 * -1 = %d, want 9223372036854775807", r)
+ t.Errorf("-9223372036854775807 %s -1 = %d, want 9223372036854775807", "*", r)
}
y = 0
r = x * y
if r != 0 {
- t.Errorf("-9223372036854775807 * 0 = %d, want 0", r)
+ t.Errorf("-9223372036854775807 %s 0 = %d, want 0", "*", r)
}
y = 1
r = x * y
if r != -9223372036854775807 {
- t.Errorf("-9223372036854775807 * 1 = %d, want -9223372036854775807", r)
+ t.Errorf("-9223372036854775807 %s 1 = %d, want -9223372036854775807", "*", r)
}
y = 4294967296
r = x * y
if r != 4294967296 {
- t.Errorf("-9223372036854775807 * 4294967296 = %d, want 4294967296", r)
+ t.Errorf("-9223372036854775807 %s 4294967296 = %d, want 4294967296", "*", r)
}
y = 9223372036854775806
r = x * y
if r != 9223372036854775806 {
- t.Errorf("-9223372036854775807 * 9223372036854775806 = %d, want 9223372036854775806", r)
+ t.Errorf("-9223372036854775807 %s 9223372036854775806 = %d, want 9223372036854775806", "*", r)
}
y = 9223372036854775807
r = x * y
if r != -1 {
- t.Errorf("-9223372036854775807 * 9223372036854775807 = %d, want -1", r)
+ t.Errorf("-9223372036854775807 %s 9223372036854775807 = %d, want -1", "*", r)
}
x = -4294967296
y = -9223372036854775808
r = x * y
if r != 0 {
- t.Errorf("-4294967296 * -9223372036854775808 = %d, want 0", r)
+ t.Errorf("-4294967296 %s -9223372036854775808 = %d, want 0", "*", r)
}
y = -9223372036854775807
r = x * y
if r != -4294967296 {
- t.Errorf("-4294967296 * -9223372036854775807 = %d, want -4294967296", r)
+ t.Errorf("-4294967296 %s -9223372036854775807 = %d, want -4294967296", "*", r)
}
y = -4294967296
r = x * y
if r != 0 {
- t.Errorf("-4294967296 * -4294967296 = %d, want 0", r)
+ t.Errorf("-4294967296 %s -4294967296 = %d, want 0", "*", r)
}
y = -1
r = x * y
if r != 4294967296 {
- t.Errorf("-4294967296 * -1 = %d, want 4294967296", r)
+ t.Errorf("-4294967296 %s -1 = %d, want 4294967296", "*", r)
}
y = 0
r = x * y
if r != 0 {
- t.Errorf("-4294967296 * 0 = %d, want 0", r)
+ t.Errorf("-4294967296 %s 0 = %d, want 0", "*", r)
}
y = 1
r = x * y
if r != -4294967296 {
- t.Errorf("-4294967296 * 1 = %d, want -4294967296", r)
+ t.Errorf("-4294967296 %s 1 = %d, want -4294967296", "*", r)
}
y = 4294967296
r = x * y
if r != 0 {
- t.Errorf("-4294967296 * 4294967296 = %d, want 0", r)
+ t.Errorf("-4294967296 %s 4294967296 = %d, want 0", "*", r)
}
y = 9223372036854775806
r = x * y
if r != 8589934592 {
- t.Errorf("-4294967296 * 9223372036854775806 = %d, want 8589934592", r)
+ t.Errorf("-4294967296 %s 9223372036854775806 = %d, want 8589934592", "*", r)
}
y = 9223372036854775807
r = x * y
if r != 4294967296 {
- t.Errorf("-4294967296 * 9223372036854775807 = %d, want 4294967296", r)
+ t.Errorf("-4294967296 %s 9223372036854775807 = %d, want 4294967296", "*", r)
}
x = -1
y = -9223372036854775808
r = x * y
if r != -9223372036854775808 {
- t.Errorf("-1 * -9223372036854775808 = %d, want -9223372036854775808", r)
+ t.Errorf("-1 %s -9223372036854775808 = %d, want -9223372036854775808", "*", r)
}
y = -9223372036854775807
r = x * y
if r != 9223372036854775807 {
- t.Errorf("-1 * -9223372036854775807 = %d, want 9223372036854775807", r)
+ t.Errorf("-1 %s -9223372036854775807 = %d, want 9223372036854775807", "*", r)
}
y = -4294967296
r = x * y
if r != 4294967296 {
- t.Errorf("-1 * -4294967296 = %d, want 4294967296", r)
+ t.Errorf("-1 %s -4294967296 = %d, want 4294967296", "*", r)
}
y = -1
r = x * y
if r != 1 {
- t.Errorf("-1 * -1 = %d, want 1", r)
+ t.Errorf("-1 %s -1 = %d, want 1", "*", r)
}
y = 0
r = x * y
if r != 0 {
- t.Errorf("-1 * 0 = %d, want 0", r)
+ t.Errorf("-1 %s 0 = %d, want 0", "*", r)
}
y = 1
r = x * y
if r != -1 {
- t.Errorf("-1 * 1 = %d, want -1", r)
+ t.Errorf("-1 %s 1 = %d, want -1", "*", r)
}
y = 4294967296
r = x * y
if r != -4294967296 {
- t.Errorf("-1 * 4294967296 = %d, want -4294967296", r)
+ t.Errorf("-1 %s 4294967296 = %d, want -4294967296", "*", r)
}
y = 9223372036854775806
r = x * y
if r != -9223372036854775806 {
- t.Errorf("-1 * 9223372036854775806 = %d, want -9223372036854775806", r)
+ t.Errorf("-1 %s 9223372036854775806 = %d, want -9223372036854775806", "*", r)
}
y = 9223372036854775807
r = x * y
if r != -9223372036854775807 {
- t.Errorf("-1 * 9223372036854775807 = %d, want -9223372036854775807", r)
+ t.Errorf("-1 %s 9223372036854775807 = %d, want -9223372036854775807", "*", r)
}
x = 0
y = -9223372036854775808
r = x * y
if r != 0 {
- t.Errorf("0 * -9223372036854775808 = %d, want 0", r)
+ t.Errorf("0 %s -9223372036854775808 = %d, want 0", "*", r)
}
y = -9223372036854775807
r = x * y
if r != 0 {
- t.Errorf("0 * -9223372036854775807 = %d, want 0", r)
+ t.Errorf("0 %s -9223372036854775807 = %d, want 0", "*", r)
}
y = -4294967296
r = x * y
if r != 0 {
- t.Errorf("0 * -4294967296 = %d, want 0", r)
+ t.Errorf("0 %s -4294967296 = %d, want 0", "*", r)
}
y = -1
r = x * y
if r != 0 {
- t.Errorf("0 * -1 = %d, want 0", r)
+ t.Errorf("0 %s -1 = %d, want 0", "*", r)
}
y = 0
r = x * y
if r != 0 {
- t.Errorf("0 * 0 = %d, want 0", r)
+ t.Errorf("0 %s 0 = %d, want 0", "*", r)
}
y = 1
r = x * y
if r != 0 {
- t.Errorf("0 * 1 = %d, want 0", r)
+ t.Errorf("0 %s 1 = %d, want 0", "*", r)
}
y = 4294967296
r = x * y
if r != 0 {
- t.Errorf("0 * 4294967296 = %d, want 0", r)
+ t.Errorf("0 %s 4294967296 = %d, want 0", "*", r)
}
y = 9223372036854775806
r = x * y
if r != 0 {
- t.Errorf("0 * 9223372036854775806 = %d, want 0", r)
+ t.Errorf("0 %s 9223372036854775806 = %d, want 0", "*", r)
}
y = 9223372036854775807
r = x * y
if r != 0 {
- t.Errorf("0 * 9223372036854775807 = %d, want 0", r)
+ t.Errorf("0 %s 9223372036854775807 = %d, want 0", "*", r)
}
x = 1
y = -9223372036854775808
r = x * y
if r != -9223372036854775808 {
- t.Errorf("1 * -9223372036854775808 = %d, want -9223372036854775808", r)
+ t.Errorf("1 %s -9223372036854775808 = %d, want -9223372036854775808", "*", r)
}
y = -9223372036854775807
r = x * y
if r != -9223372036854775807 {
- t.Errorf("1 * -9223372036854775807 = %d, want -9223372036854775807", r)
+ t.Errorf("1 %s -9223372036854775807 = %d, want -9223372036854775807", "*", r)
}
y = -4294967296
r = x * y
if r != -4294967296 {
- t.Errorf("1 * -4294967296 = %d, want -4294967296", r)
+ t.Errorf("1 %s -4294967296 = %d, want -4294967296", "*", r)
}
y = -1
r = x * y
if r != -1 {
- t.Errorf("1 * -1 = %d, want -1", r)
+ t.Errorf("1 %s -1 = %d, want -1", "*", r)
}
y = 0
r = x * y
if r != 0 {
- t.Errorf("1 * 0 = %d, want 0", r)
+ t.Errorf("1 %s 0 = %d, want 0", "*", r)
}
y = 1
r = x * y
if r != 1 {
- t.Errorf("1 * 1 = %d, want 1", r)
+ t.Errorf("1 %s 1 = %d, want 1", "*", r)
}
y = 4294967296
r = x * y
if r != 4294967296 {
- t.Errorf("1 * 4294967296 = %d, want 4294967296", r)
+ t.Errorf("1 %s 4294967296 = %d, want 4294967296", "*", r)
}
y = 9223372036854775806
r = x * y
if r != 9223372036854775806 {
- t.Errorf("1 * 9223372036854775806 = %d, want 9223372036854775806", r)
+ t.Errorf("1 %s 9223372036854775806 = %d, want 9223372036854775806", "*", r)
}
y = 9223372036854775807
r = x * y
if r != 9223372036854775807 {
- t.Errorf("1 * 9223372036854775807 = %d, want 9223372036854775807", r)
+ t.Errorf("1 %s 9223372036854775807 = %d, want 9223372036854775807", "*", r)
}
x = 4294967296
y = -9223372036854775808
r = x * y
if r != 0 {
- t.Errorf("4294967296 * -9223372036854775808 = %d, want 0", r)
+ t.Errorf("4294967296 %s -9223372036854775808 = %d, want 0", "*", r)
}
y = -9223372036854775807
r = x * y
if r != 4294967296 {
- t.Errorf("4294967296 * -9223372036854775807 = %d, want 4294967296", r)
+ t.Errorf("4294967296 %s -9223372036854775807 = %d, want 4294967296", "*", r)
}
y = -4294967296
r = x * y
if r != 0 {
- t.Errorf("4294967296 * -4294967296 = %d, want 0", r)
+ t.Errorf("4294967296 %s -4294967296 = %d, want 0", "*", r)
}
y = -1
r = x * y
if r != -4294967296 {
- t.Errorf("4294967296 * -1 = %d, want -4294967296", r)
+ t.Errorf("4294967296 %s -1 = %d, want -4294967296", "*", r)
}
y = 0
r = x * y
if r != 0 {
- t.Errorf("4294967296 * 0 = %d, want 0", r)
+ t.Errorf("4294967296 %s 0 = %d, want 0", "*", r)
}
y = 1
r = x * y
if r != 4294967296 {
- t.Errorf("4294967296 * 1 = %d, want 4294967296", r)
+ t.Errorf("4294967296 %s 1 = %d, want 4294967296", "*", r)
}
y = 4294967296
r = x * y
if r != 0 {
- t.Errorf("4294967296 * 4294967296 = %d, want 0", r)
+ t.Errorf("4294967296 %s 4294967296 = %d, want 0", "*", r)
}
y = 9223372036854775806
r = x * y
if r != -8589934592 {
- t.Errorf("4294967296 * 9223372036854775806 = %d, want -8589934592", r)
+ t.Errorf("4294967296 %s 9223372036854775806 = %d, want -8589934592", "*", r)
}
y = 9223372036854775807
r = x * y
if r != -4294967296 {
- t.Errorf("4294967296 * 9223372036854775807 = %d, want -4294967296", r)
+ t.Errorf("4294967296 %s 9223372036854775807 = %d, want -4294967296", "*", r)
}
x = 9223372036854775806
y = -9223372036854775808
r = x * y
if r != 0 {
- t.Errorf("9223372036854775806 * -9223372036854775808 = %d, want 0", r)
+ t.Errorf("9223372036854775806 %s -9223372036854775808 = %d, want 0", "*", r)
}
y = -9223372036854775807
r = x * y
if r != 9223372036854775806 {
- t.Errorf("9223372036854775806 * -9223372036854775807 = %d, want 9223372036854775806", r)
+ t.Errorf("9223372036854775806 %s -9223372036854775807 = %d, want 9223372036854775806", "*", r)
}
y = -4294967296
r = x * y
if r != 8589934592 {
- t.Errorf("9223372036854775806 * -4294967296 = %d, want 8589934592", r)
+ t.Errorf("9223372036854775806 %s -4294967296 = %d, want 8589934592", "*", r)
}
y = -1
r = x * y
if r != -9223372036854775806 {
- t.Errorf("9223372036854775806 * -1 = %d, want -9223372036854775806", r)
+ t.Errorf("9223372036854775806 %s -1 = %d, want -9223372036854775806", "*", r)
}
y = 0
r = x * y
if r != 0 {
- t.Errorf("9223372036854775806 * 0 = %d, want 0", r)
+ t.Errorf("9223372036854775806 %s 0 = %d, want 0", "*", r)
}
y = 1
r = x * y
if r != 9223372036854775806 {
- t.Errorf("9223372036854775806 * 1 = %d, want 9223372036854775806", r)
+ t.Errorf("9223372036854775806 %s 1 = %d, want 9223372036854775806", "*", r)
}
y = 4294967296
r = x * y
if r != -8589934592 {
- t.Errorf("9223372036854775806 * 4294967296 = %d, want -8589934592", r)
+ t.Errorf("9223372036854775806 %s 4294967296 = %d, want -8589934592", "*", r)
}
y = 9223372036854775806
r = x * y
if r != 4 {
- t.Errorf("9223372036854775806 * 9223372036854775806 = %d, want 4", r)
+ t.Errorf("9223372036854775806 %s 9223372036854775806 = %d, want 4", "*", r)
}
y = 9223372036854775807
r = x * y
if r != -9223372036854775806 {
- t.Errorf("9223372036854775806 * 9223372036854775807 = %d, want -9223372036854775806", r)
+ t.Errorf("9223372036854775806 %s 9223372036854775807 = %d, want -9223372036854775806", "*", r)
}
x = 9223372036854775807
y = -9223372036854775808
r = x * y
if r != -9223372036854775808 {
- t.Errorf("9223372036854775807 * -9223372036854775808 = %d, want -9223372036854775808", r)
+ t.Errorf("9223372036854775807 %s -9223372036854775808 = %d, want -9223372036854775808", "*", r)
}
y = -9223372036854775807
r = x * y
if r != -1 {
- t.Errorf("9223372036854775807 * -9223372036854775807 = %d, want -1", r)
+ t.Errorf("9223372036854775807 %s -9223372036854775807 = %d, want -1", "*", r)
}
y = -4294967296
r = x * y
if r != 4294967296 {
- t.Errorf("9223372036854775807 * -4294967296 = %d, want 4294967296", r)
+ t.Errorf("9223372036854775807 %s -4294967296 = %d, want 4294967296", "*", r)
}
y = -1
r = x * y
if r != -9223372036854775807 {
- t.Errorf("9223372036854775807 * -1 = %d, want -9223372036854775807", r)
+ t.Errorf("9223372036854775807 %s -1 = %d, want -9223372036854775807", "*", r)
}
y = 0
r = x * y
if r != 0 {
- t.Errorf("9223372036854775807 * 0 = %d, want 0", r)
+ t.Errorf("9223372036854775807 %s 0 = %d, want 0", "*", r)
}
y = 1
r = x * y
if r != 9223372036854775807 {
- t.Errorf("9223372036854775807 * 1 = %d, want 9223372036854775807", r)
+ t.Errorf("9223372036854775807 %s 1 = %d, want 9223372036854775807", "*", r)
}
y = 4294967296
r = x * y
if r != -4294967296 {
- t.Errorf("9223372036854775807 * 4294967296 = %d, want -4294967296", r)
+ t.Errorf("9223372036854775807 %s 4294967296 = %d, want -4294967296", "*", r)
}
y = 9223372036854775806
r = x * y
if r != -9223372036854775806 {
- t.Errorf("9223372036854775807 * 9223372036854775806 = %d, want -9223372036854775806", r)
+ t.Errorf("9223372036854775807 %s 9223372036854775806 = %d, want -9223372036854775806", "*", r)
}
y = 9223372036854775807
r = x * y
if r != 1 {
- t.Errorf("9223372036854775807 * 9223372036854775807 = %d, want 1", r)
+ t.Errorf("9223372036854775807 %s 9223372036854775807 = %d, want 1", "*", r)
}
}
func TestConstFoldint64mod(t *testing.T) {
@@ -2026,370 +2026,370 @@ func TestConstFoldint64mod(t *testing.T) {
y = -9223372036854775808
r = x % y
if r != 0 {
- t.Errorf("-9223372036854775808 % -9223372036854775808 = %d, want 0", r)
+ t.Errorf("-9223372036854775808 %s -9223372036854775808 = %d, want 0", "%", r)
}
y = -9223372036854775807
r = x % y
if r != -1 {
- t.Errorf("-9223372036854775808 % -9223372036854775807 = %d, want -1", r)
+ t.Errorf("-9223372036854775808 %s -9223372036854775807 = %d, want -1", "%", r)
}
y = -4294967296
r = x % y
if r != 0 {
- t.Errorf("-9223372036854775808 % -4294967296 = %d, want 0", r)
+ t.Errorf("-9223372036854775808 %s -4294967296 = %d, want 0", "%", r)
}
y = -1
r = x % y
if r != 0 {
- t.Errorf("-9223372036854775808 % -1 = %d, want 0", r)
+ t.Errorf("-9223372036854775808 %s -1 = %d, want 0", "%", r)
}
y = 1
r = x % y
if r != 0 {
- t.Errorf("-9223372036854775808 % 1 = %d, want 0", r)
+ t.Errorf("-9223372036854775808 %s 1 = %d, want 0", "%", r)
}
y = 4294967296
r = x % y
if r != 0 {
- t.Errorf("-9223372036854775808 % 4294967296 = %d, want 0", r)
+ t.Errorf("-9223372036854775808 %s 4294967296 = %d, want 0", "%", r)
}
y = 9223372036854775806
r = x % y
if r != -2 {
- t.Errorf("-9223372036854775808 % 9223372036854775806 = %d, want -2", r)
+ t.Errorf("-9223372036854775808 %s 9223372036854775806 = %d, want -2", "%", r)
}
y = 9223372036854775807
r = x % y
if r != -1 {
- t.Errorf("-9223372036854775808 % 9223372036854775807 = %d, want -1", r)
+ t.Errorf("-9223372036854775808 %s 9223372036854775807 = %d, want -1", "%", r)
}
x = -9223372036854775807
y = -9223372036854775808
r = x % y
if r != -9223372036854775807 {
- t.Errorf("-9223372036854775807 % -9223372036854775808 = %d, want -9223372036854775807", r)
+ t.Errorf("-9223372036854775807 %s -9223372036854775808 = %d, want -9223372036854775807", "%", r)
}
y = -9223372036854775807
r = x % y
if r != 0 {
- t.Errorf("-9223372036854775807 % -9223372036854775807 = %d, want 0", r)
+ t.Errorf("-9223372036854775807 %s -9223372036854775807 = %d, want 0", "%", r)
}
y = -4294967296
r = x % y
if r != -4294967295 {
- t.Errorf("-9223372036854775807 % -4294967296 = %d, want -4294967295", r)
+ t.Errorf("-9223372036854775807 %s -4294967296 = %d, want -4294967295", "%", r)
}
y = -1
r = x % y
if r != 0 {
- t.Errorf("-9223372036854775807 % -1 = %d, want 0", r)
+ t.Errorf("-9223372036854775807 %s -1 = %d, want 0", "%", r)
}
y = 1
r = x % y
if r != 0 {
- t.Errorf("-9223372036854775807 % 1 = %d, want 0", r)
+ t.Errorf("-9223372036854775807 %s 1 = %d, want 0", "%", r)
}
y = 4294967296
r = x % y
if r != -4294967295 {
- t.Errorf("-9223372036854775807 % 4294967296 = %d, want -4294967295", r)
+ t.Errorf("-9223372036854775807 %s 4294967296 = %d, want -4294967295", "%", r)
}
y = 9223372036854775806
r = x % y
if r != -1 {
- t.Errorf("-9223372036854775807 % 9223372036854775806 = %d, want -1", r)
+ t.Errorf("-9223372036854775807 %s 9223372036854775806 = %d, want -1", "%", r)
}
y = 9223372036854775807
r = x % y
if r != 0 {
- t.Errorf("-9223372036854775807 % 9223372036854775807 = %d, want 0", r)
+ t.Errorf("-9223372036854775807 %s 9223372036854775807 = %d, want 0", "%", r)
}
x = -4294967296
y = -9223372036854775808
r = x % y
if r != -4294967296 {
- t.Errorf("-4294967296 % -9223372036854775808 = %d, want -4294967296", r)
+ t.Errorf("-4294967296 %s -9223372036854775808 = %d, want -4294967296", "%", r)
}
y = -9223372036854775807
r = x % y
if r != -4294967296 {
- t.Errorf("-4294967296 % -9223372036854775807 = %d, want -4294967296", r)
+ t.Errorf("-4294967296 %s -9223372036854775807 = %d, want -4294967296", "%", r)
}
y = -4294967296
r = x % y
if r != 0 {
- t.Errorf("-4294967296 % -4294967296 = %d, want 0", r)
+ t.Errorf("-4294967296 %s -4294967296 = %d, want 0", "%", r)
}
y = -1
r = x % y
if r != 0 {
- t.Errorf("-4294967296 % -1 = %d, want 0", r)
+ t.Errorf("-4294967296 %s -1 = %d, want 0", "%", r)
}
y = 1
r = x % y
if r != 0 {
- t.Errorf("-4294967296 % 1 = %d, want 0", r)
+ t.Errorf("-4294967296 %s 1 = %d, want 0", "%", r)
}
y = 4294967296
r = x % y
if r != 0 {
- t.Errorf("-4294967296 % 4294967296 = %d, want 0", r)
+ t.Errorf("-4294967296 %s 4294967296 = %d, want 0", "%", r)
}
y = 9223372036854775806
r = x % y
if r != -4294967296 {
- t.Errorf("-4294967296 % 9223372036854775806 = %d, want -4294967296", r)
+ t.Errorf("-4294967296 %s 9223372036854775806 = %d, want -4294967296", "%", r)
}
y = 9223372036854775807
r = x % y
if r != -4294967296 {
- t.Errorf("-4294967296 % 9223372036854775807 = %d, want -4294967296", r)
+ t.Errorf("-4294967296 %s 9223372036854775807 = %d, want -4294967296", "%", r)
}
x = -1
y = -9223372036854775808
r = x % y
if r != -1 {
- t.Errorf("-1 % -9223372036854775808 = %d, want -1", r)
+ t.Errorf("-1 %s -9223372036854775808 = %d, want -1", "%", r)
}
y = -9223372036854775807
r = x % y
if r != -1 {
- t.Errorf("-1 % -9223372036854775807 = %d, want -1", r)
+ t.Errorf("-1 %s -9223372036854775807 = %d, want -1", "%", r)
}
y = -4294967296
r = x % y
if r != -1 {
- t.Errorf("-1 % -4294967296 = %d, want -1", r)
+ t.Errorf("-1 %s -4294967296 = %d, want -1", "%", r)
}
y = -1
r = x % y
if r != 0 {
- t.Errorf("-1 % -1 = %d, want 0", r)
+ t.Errorf("-1 %s -1 = %d, want 0", "%", r)
}
y = 1
r = x % y
if r != 0 {
- t.Errorf("-1 % 1 = %d, want 0", r)
+ t.Errorf("-1 %s 1 = %d, want 0", "%", r)
}
y = 4294967296
r = x % y
if r != -1 {
- t.Errorf("-1 % 4294967296 = %d, want -1", r)
+ t.Errorf("-1 %s 4294967296 = %d, want -1", "%", r)
}
y = 9223372036854775806
r = x % y
if r != -1 {
- t.Errorf("-1 % 9223372036854775806 = %d, want -1", r)
+ t.Errorf("-1 %s 9223372036854775806 = %d, want -1", "%", r)
}
y = 9223372036854775807
r = x % y
if r != -1 {
- t.Errorf("-1 % 9223372036854775807 = %d, want -1", r)
+ t.Errorf("-1 %s 9223372036854775807 = %d, want -1", "%", r)
}
x = 0
y = -9223372036854775808
r = x % y
if r != 0 {
- t.Errorf("0 % -9223372036854775808 = %d, want 0", r)
+ t.Errorf("0 %s -9223372036854775808 = %d, want 0", "%", r)
}
y = -9223372036854775807
r = x % y
if r != 0 {
- t.Errorf("0 % -9223372036854775807 = %d, want 0", r)
+ t.Errorf("0 %s -9223372036854775807 = %d, want 0", "%", r)
}
y = -4294967296
r = x % y
if r != 0 {
- t.Errorf("0 % -4294967296 = %d, want 0", r)
+ t.Errorf("0 %s -4294967296 = %d, want 0", "%", r)
}
y = -1
r = x % y
if r != 0 {
- t.Errorf("0 % -1 = %d, want 0", r)
+ t.Errorf("0 %s -1 = %d, want 0", "%", r)
}
y = 1
r = x % y
if r != 0 {
- t.Errorf("0 % 1 = %d, want 0", r)
+ t.Errorf("0 %s 1 = %d, want 0", "%", r)
}
y = 4294967296
r = x % y
if r != 0 {
- t.Errorf("0 % 4294967296 = %d, want 0", r)
+ t.Errorf("0 %s 4294967296 = %d, want 0", "%", r)
}
y = 9223372036854775806
r = x % y
if r != 0 {
- t.Errorf("0 % 9223372036854775806 = %d, want 0", r)
+ t.Errorf("0 %s 9223372036854775806 = %d, want 0", "%", r)
}
y = 9223372036854775807
r = x % y
if r != 0 {
- t.Errorf("0 % 9223372036854775807 = %d, want 0", r)
+ t.Errorf("0 %s 9223372036854775807 = %d, want 0", "%", r)
}
x = 1
y = -9223372036854775808
r = x % y
if r != 1 {
- t.Errorf("1 % -9223372036854775808 = %d, want 1", r)
+ t.Errorf("1 %s -9223372036854775808 = %d, want 1", "%", r)
}
y = -9223372036854775807
r = x % y
if r != 1 {
- t.Errorf("1 % -9223372036854775807 = %d, want 1", r)
+ t.Errorf("1 %s -9223372036854775807 = %d, want 1", "%", r)
}
y = -4294967296
r = x % y
if r != 1 {
- t.Errorf("1 % -4294967296 = %d, want 1", r)
+ t.Errorf("1 %s -4294967296 = %d, want 1", "%", r)
}
y = -1
r = x % y
if r != 0 {
- t.Errorf("1 % -1 = %d, want 0", r)
+ t.Errorf("1 %s -1 = %d, want 0", "%", r)
}
y = 1
r = x % y
if r != 0 {
- t.Errorf("1 % 1 = %d, want 0", r)
+ t.Errorf("1 %s 1 = %d, want 0", "%", r)
}
y = 4294967296
r = x % y
if r != 1 {
- t.Errorf("1 % 4294967296 = %d, want 1", r)
+ t.Errorf("1 %s 4294967296 = %d, want 1", "%", r)
}
y = 9223372036854775806
r = x % y
if r != 1 {
- t.Errorf("1 % 9223372036854775806 = %d, want 1", r)
+ t.Errorf("1 %s 9223372036854775806 = %d, want 1", "%", r)
}
y = 9223372036854775807
r = x % y
if r != 1 {
- t.Errorf("1 % 9223372036854775807 = %d, want 1", r)
+ t.Errorf("1 %s 9223372036854775807 = %d, want 1", "%", r)
}
x = 4294967296
y = -9223372036854775808
r = x % y
if r != 4294967296 {
- t.Errorf("4294967296 % -9223372036854775808 = %d, want 4294967296", r)
+ t.Errorf("4294967296 %s -9223372036854775808 = %d, want 4294967296", "%", r)
}
y = -9223372036854775807
r = x % y
if r != 4294967296 {
- t.Errorf("4294967296 % -9223372036854775807 = %d, want 4294967296", r)
+ t.Errorf("4294967296 %s -9223372036854775807 = %d, want 4294967296", "%", r)
}
y = -4294967296
r = x % y
if r != 0 {
- t.Errorf("4294967296 % -4294967296 = %d, want 0", r)
+ t.Errorf("4294967296 %s -4294967296 = %d, want 0", "%", r)
}
y = -1
r = x % y
if r != 0 {
- t.Errorf("4294967296 % -1 = %d, want 0", r)
+ t.Errorf("4294967296 %s -1 = %d, want 0", "%", r)
}
y = 1
r = x % y
if r != 0 {
- t.Errorf("4294967296 % 1 = %d, want 0", r)
+ t.Errorf("4294967296 %s 1 = %d, want 0", "%", r)
}
y = 4294967296
r = x % y
if r != 0 {
- t.Errorf("4294967296 % 4294967296 = %d, want 0", r)
+ t.Errorf("4294967296 %s 4294967296 = %d, want 0", "%", r)
}
y = 9223372036854775806
r = x % y
if r != 4294967296 {
- t.Errorf("4294967296 % 9223372036854775806 = %d, want 4294967296", r)
+ t.Errorf("4294967296 %s 9223372036854775806 = %d, want 4294967296", "%", r)
}
y = 9223372036854775807
r = x % y
if r != 4294967296 {
- t.Errorf("4294967296 % 9223372036854775807 = %d, want 4294967296", r)
+ t.Errorf("4294967296 %s 9223372036854775807 = %d, want 4294967296", "%", r)
}
x = 9223372036854775806
y = -9223372036854775808
r = x % y
if r != 9223372036854775806 {
- t.Errorf("9223372036854775806 % -9223372036854775808 = %d, want 9223372036854775806", r)
+ t.Errorf("9223372036854775806 %s -9223372036854775808 = %d, want 9223372036854775806", "%", r)
}
y = -9223372036854775807
r = x % y
if r != 9223372036854775806 {
- t.Errorf("9223372036854775806 % -9223372036854775807 = %d, want 9223372036854775806", r)
+ t.Errorf("9223372036854775806 %s -9223372036854775807 = %d, want 9223372036854775806", "%", r)
}
y = -4294967296
r = x % y
if r != 4294967294 {
- t.Errorf("9223372036854775806 % -4294967296 = %d, want 4294967294", r)
+ t.Errorf("9223372036854775806 %s -4294967296 = %d, want 4294967294", "%", r)
}
y = -1
r = x % y
if r != 0 {
- t.Errorf("9223372036854775806 % -1 = %d, want 0", r)
+ t.Errorf("9223372036854775806 %s -1 = %d, want 0", "%", r)
}
y = 1
r = x % y
if r != 0 {
- t.Errorf("9223372036854775806 % 1 = %d, want 0", r)
+ t.Errorf("9223372036854775806 %s 1 = %d, want 0", "%", r)
}
y = 4294967296
r = x % y
if r != 4294967294 {
- t.Errorf("9223372036854775806 % 4294967296 = %d, want 4294967294", r)
+ t.Errorf("9223372036854775806 %s 4294967296 = %d, want 4294967294", "%", r)
}
y = 9223372036854775806
r = x % y
if r != 0 {
- t.Errorf("9223372036854775806 % 9223372036854775806 = %d, want 0", r)
+ t.Errorf("9223372036854775806 %s 9223372036854775806 = %d, want 0", "%", r)
}
y = 9223372036854775807
r = x % y
if r != 9223372036854775806 {
- t.Errorf("9223372036854775806 % 9223372036854775807 = %d, want 9223372036854775806", r)
+ t.Errorf("9223372036854775806 %s 9223372036854775807 = %d, want 9223372036854775806", "%", r)
}
x = 9223372036854775807
y = -9223372036854775808
r = x % y
if r != 9223372036854775807 {
- t.Errorf("9223372036854775807 % -9223372036854775808 = %d, want 9223372036854775807", r)
+ t.Errorf("9223372036854775807 %s -9223372036854775808 = %d, want 9223372036854775807", "%", r)
}
y = -9223372036854775807
r = x % y
if r != 0 {
- t.Errorf("9223372036854775807 % -9223372036854775807 = %d, want 0", r)
+ t.Errorf("9223372036854775807 %s -9223372036854775807 = %d, want 0", "%", r)
}
y = -4294967296
r = x % y
if r != 4294967295 {
- t.Errorf("9223372036854775807 % -4294967296 = %d, want 4294967295", r)
+ t.Errorf("9223372036854775807 %s -4294967296 = %d, want 4294967295", "%", r)
}
y = -1
r = x % y
if r != 0 {
- t.Errorf("9223372036854775807 % -1 = %d, want 0", r)
+ t.Errorf("9223372036854775807 %s -1 = %d, want 0", "%", r)
}
y = 1
r = x % y
if r != 0 {
- t.Errorf("9223372036854775807 % 1 = %d, want 0", r)
+ t.Errorf("9223372036854775807 %s 1 = %d, want 0", "%", r)
}
y = 4294967296
r = x % y
if r != 4294967295 {
- t.Errorf("9223372036854775807 % 4294967296 = %d, want 4294967295", r)
+ t.Errorf("9223372036854775807 %s 4294967296 = %d, want 4294967295", "%", r)
}
y = 9223372036854775806
r = x % y
if r != 1 {
- t.Errorf("9223372036854775807 % 9223372036854775806 = %d, want 1", r)
+ t.Errorf("9223372036854775807 %s 9223372036854775806 = %d, want 1", "%", r)
}
y = 9223372036854775807
r = x % y
if r != 0 {
- t.Errorf("9223372036854775807 % 9223372036854775807 = %d, want 0", r)
+ t.Errorf("9223372036854775807 %s 9223372036854775807 = %d, want 0", "%", r)
}
}
func TestConstFolduint32add(t *testing.T) {
@@ -2398,49 +2398,49 @@ func TestConstFolduint32add(t *testing.T) {
y = 0
r = x + y
if r != 0 {
- t.Errorf("0 + 0 = %d, want 0", r)
+ t.Errorf("0 %s 0 = %d, want 0", "+", r)
}
y = 1
r = x + y
if r != 1 {
- t.Errorf("0 + 1 = %d, want 1", r)
+ t.Errorf("0 %s 1 = %d, want 1", "+", r)
}
y = 4294967295
r = x + y
if r != 4294967295 {
- t.Errorf("0 + 4294967295 = %d, want 4294967295", r)
+ t.Errorf("0 %s 4294967295 = %d, want 4294967295", "+", r)
}
x = 1
y = 0
r = x + y
if r != 1 {
- t.Errorf("1 + 0 = %d, want 1", r)
+ t.Errorf("1 %s 0 = %d, want 1", "+", r)
}
y = 1
r = x + y
if r != 2 {
- t.Errorf("1 + 1 = %d, want 2", r)
+ t.Errorf("1 %s 1 = %d, want 2", "+", r)
}
y = 4294967295
r = x + y
if r != 0 {
- t.Errorf("1 + 4294967295 = %d, want 0", r)
+ t.Errorf("1 %s 4294967295 = %d, want 0", "+", r)
}
x = 4294967295
y = 0
r = x + y
if r != 4294967295 {
- t.Errorf("4294967295 + 0 = %d, want 4294967295", r)
+ t.Errorf("4294967295 %s 0 = %d, want 4294967295", "+", r)
}
y = 1
r = x + y
if r != 0 {
- t.Errorf("4294967295 + 1 = %d, want 0", r)
+ t.Errorf("4294967295 %s 1 = %d, want 0", "+", r)
}
y = 4294967295
r = x + y
if r != 4294967294 {
- t.Errorf("4294967295 + 4294967295 = %d, want 4294967294", r)
+ t.Errorf("4294967295 %s 4294967295 = %d, want 4294967294", "+", r)
}
}
func TestConstFolduint32sub(t *testing.T) {
@@ -2449,49 +2449,49 @@ func TestConstFolduint32sub(t *testing.T) {
y = 0
r = x - y
if r != 0 {
- t.Errorf("0 - 0 = %d, want 0", r)
+ t.Errorf("0 %s 0 = %d, want 0", "-", r)
}
y = 1
r = x - y
if r != 4294967295 {
- t.Errorf("0 - 1 = %d, want 4294967295", r)
+ t.Errorf("0 %s 1 = %d, want 4294967295", "-", r)
}
y = 4294967295
r = x - y
if r != 1 {
- t.Errorf("0 - 4294967295 = %d, want 1", r)
+ t.Errorf("0 %s 4294967295 = %d, want 1", "-", r)
}
x = 1
y = 0
r = x - y
if r != 1 {
- t.Errorf("1 - 0 = %d, want 1", r)
+ t.Errorf("1 %s 0 = %d, want 1", "-", r)
}
y = 1
r = x - y
if r != 0 {
- t.Errorf("1 - 1 = %d, want 0", r)
+ t.Errorf("1 %s 1 = %d, want 0", "-", r)
}
y = 4294967295
r = x - y
if r != 2 {
- t.Errorf("1 - 4294967295 = %d, want 2", r)
+ t.Errorf("1 %s 4294967295 = %d, want 2", "-", r)
}
x = 4294967295
y = 0
r = x - y
if r != 4294967295 {
- t.Errorf("4294967295 - 0 = %d, want 4294967295", r)
+ t.Errorf("4294967295 %s 0 = %d, want 4294967295", "-", r)
}
y = 1
r = x - y
if r != 4294967294 {
- t.Errorf("4294967295 - 1 = %d, want 4294967294", r)
+ t.Errorf("4294967295 %s 1 = %d, want 4294967294", "-", r)
}
y = 4294967295
r = x - y
if r != 0 {
- t.Errorf("4294967295 - 4294967295 = %d, want 0", r)
+ t.Errorf("4294967295 %s 4294967295 = %d, want 0", "-", r)
}
}
func TestConstFolduint32div(t *testing.T) {
@@ -2500,34 +2500,34 @@ func TestConstFolduint32div(t *testing.T) {
y = 1
r = x / y
if r != 0 {
- t.Errorf("0 / 1 = %d, want 0", r)
+ t.Errorf("0 %s 1 = %d, want 0", "/", r)
}
y = 4294967295
r = x / y
if r != 0 {
- t.Errorf("0 / 4294967295 = %d, want 0", r)
+ t.Errorf("0 %s 4294967295 = %d, want 0", "/", r)
}
x = 1
y = 1
r = x / y
if r != 1 {
- t.Errorf("1 / 1 = %d, want 1", r)
+ t.Errorf("1 %s 1 = %d, want 1", "/", r)
}
y = 4294967295
r = x / y
if r != 0 {
- t.Errorf("1 / 4294967295 = %d, want 0", r)
+ t.Errorf("1 %s 4294967295 = %d, want 0", "/", r)
}
x = 4294967295
y = 1
r = x / y
if r != 4294967295 {
- t.Errorf("4294967295 / 1 = %d, want 4294967295", r)
+ t.Errorf("4294967295 %s 1 = %d, want 4294967295", "/", r)
}
y = 4294967295
r = x / y
if r != 1 {
- t.Errorf("4294967295 / 4294967295 = %d, want 1", r)
+ t.Errorf("4294967295 %s 4294967295 = %d, want 1", "/", r)
}
}
func TestConstFolduint32mul(t *testing.T) {
@@ -2536,49 +2536,49 @@ func TestConstFolduint32mul(t *testing.T) {
y = 0
r = x * y
if r != 0 {
- t.Errorf("0 * 0 = %d, want 0", r)
+ t.Errorf("0 %s 0 = %d, want 0", "*", r)
}
y = 1
r = x * y
if r != 0 {
- t.Errorf("0 * 1 = %d, want 0", r)
+ t.Errorf("0 %s 1 = %d, want 0", "*", r)
}
y = 4294967295
r = x * y
if r != 0 {
- t.Errorf("0 * 4294967295 = %d, want 0", r)
+ t.Errorf("0 %s 4294967295 = %d, want 0", "*", r)
}
x = 1
y = 0
r = x * y
if r != 0 {
- t.Errorf("1 * 0 = %d, want 0", r)
+ t.Errorf("1 %s 0 = %d, want 0", "*", r)
}
y = 1
r = x * y
if r != 1 {
- t.Errorf("1 * 1 = %d, want 1", r)
+ t.Errorf("1 %s 1 = %d, want 1", "*", r)
}
y = 4294967295
r = x * y
if r != 4294967295 {
- t.Errorf("1 * 4294967295 = %d, want 4294967295", r)
+ t.Errorf("1 %s 4294967295 = %d, want 4294967295", "*", r)
}
x = 4294967295
y = 0
r = x * y
if r != 0 {
- t.Errorf("4294967295 * 0 = %d, want 0", r)
+ t.Errorf("4294967295 %s 0 = %d, want 0", "*", r)
}
y = 1
r = x * y
if r != 4294967295 {
- t.Errorf("4294967295 * 1 = %d, want 4294967295", r)
+ t.Errorf("4294967295 %s 1 = %d, want 4294967295", "*", r)
}
y = 4294967295
r = x * y
if r != 1 {
- t.Errorf("4294967295 * 4294967295 = %d, want 1", r)
+ t.Errorf("4294967295 %s 4294967295 = %d, want 1", "*", r)
}
}
func TestConstFolduint32mod(t *testing.T) {
@@ -2587,34 +2587,34 @@ func TestConstFolduint32mod(t *testing.T) {
y = 1
r = x % y
if r != 0 {
- t.Errorf("0 % 1 = %d, want 0", r)
+ t.Errorf("0 %s 1 = %d, want 0", "%", r)
}
y = 4294967295
r = x % y
if r != 0 {
- t.Errorf("0 % 4294967295 = %d, want 0", r)
+ t.Errorf("0 %s 4294967295 = %d, want 0", "%", r)
}
x = 1
y = 1
r = x % y
if r != 0 {
- t.Errorf("1 % 1 = %d, want 0", r)
+ t.Errorf("1 %s 1 = %d, want 0", "%", r)
}
y = 4294967295
r = x % y
if r != 1 {
- t.Errorf("1 % 4294967295 = %d, want 1", r)
+ t.Errorf("1 %s 4294967295 = %d, want 1", "%", r)
}
x = 4294967295
y = 1
r = x % y
if r != 0 {
- t.Errorf("4294967295 % 1 = %d, want 0", r)
+ t.Errorf("4294967295 %s 1 = %d, want 0", "%", r)
}
y = 4294967295
r = x % y
if r != 0 {
- t.Errorf("4294967295 % 4294967295 = %d, want 0", r)
+ t.Errorf("4294967295 %s 4294967295 = %d, want 0", "%", r)
}
}
func TestConstFoldint32add(t *testing.T) {
@@ -2623,187 +2623,187 @@ func TestConstFoldint32add(t *testing.T) {
y = -2147483648
r = x + y
if r != 0 {
- t.Errorf("-2147483648 + -2147483648 = %d, want 0", r)
+ t.Errorf("-2147483648 %s -2147483648 = %d, want 0", "+", r)
}
y = -2147483647
r = x + y
if r != 1 {
- t.Errorf("-2147483648 + -2147483647 = %d, want 1", r)
+ t.Errorf("-2147483648 %s -2147483647 = %d, want 1", "+", r)
}
y = -1
r = x + y
if r != 2147483647 {
- t.Errorf("-2147483648 + -1 = %d, want 2147483647", r)
+ t.Errorf("-2147483648 %s -1 = %d, want 2147483647", "+", r)
}
y = 0
r = x + y
if r != -2147483648 {
- t.Errorf("-2147483648 + 0 = %d, want -2147483648", r)
+ t.Errorf("-2147483648 %s 0 = %d, want -2147483648", "+", r)
}
y = 1
r = x + y
if r != -2147483647 {
- t.Errorf("-2147483648 + 1 = %d, want -2147483647", r)
+ t.Errorf("-2147483648 %s 1 = %d, want -2147483647", "+", r)
}
y = 2147483647
r = x + y
if r != -1 {
- t.Errorf("-2147483648 + 2147483647 = %d, want -1", r)
+ t.Errorf("-2147483648 %s 2147483647 = %d, want -1", "+", r)
}
x = -2147483647
y = -2147483648
r = x + y
if r != 1 {
- t.Errorf("-2147483647 + -2147483648 = %d, want 1", r)
+ t.Errorf("-2147483647 %s -2147483648 = %d, want 1", "+", r)
}
y = -2147483647
r = x + y
if r != 2 {
- t.Errorf("-2147483647 + -2147483647 = %d, want 2", r)
+ t.Errorf("-2147483647 %s -2147483647 = %d, want 2", "+", r)
}
y = -1
r = x + y
if r != -2147483648 {
- t.Errorf("-2147483647 + -1 = %d, want -2147483648", r)
+ t.Errorf("-2147483647 %s -1 = %d, want -2147483648", "+", r)
}
y = 0
r = x + y
if r != -2147483647 {
- t.Errorf("-2147483647 + 0 = %d, want -2147483647", r)
+ t.Errorf("-2147483647 %s 0 = %d, want -2147483647", "+", r)
}
y = 1
r = x + y
if r != -2147483646 {
- t.Errorf("-2147483647 + 1 = %d, want -2147483646", r)
+ t.Errorf("-2147483647 %s 1 = %d, want -2147483646", "+", r)
}
y = 2147483647
r = x + y
if r != 0 {
- t.Errorf("-2147483647 + 2147483647 = %d, want 0", r)
+ t.Errorf("-2147483647 %s 2147483647 = %d, want 0", "+", r)
}
x = -1
y = -2147483648
r = x + y
if r != 2147483647 {
- t.Errorf("-1 + -2147483648 = %d, want 2147483647", r)
+ t.Errorf("-1 %s -2147483648 = %d, want 2147483647", "+", r)
}
y = -2147483647
r = x + y
if r != -2147483648 {
- t.Errorf("-1 + -2147483647 = %d, want -2147483648", r)
+ t.Errorf("-1 %s -2147483647 = %d, want -2147483648", "+", r)
}
y = -1
r = x + y
if r != -2 {
- t.Errorf("-1 + -1 = %d, want -2", r)
+ t.Errorf("-1 %s -1 = %d, want -2", "+", r)
}
y = 0
r = x + y
if r != -1 {
- t.Errorf("-1 + 0 = %d, want -1", r)
+ t.Errorf("-1 %s 0 = %d, want -1", "+", r)
}
y = 1
r = x + y
if r != 0 {
- t.Errorf("-1 + 1 = %d, want 0", r)
+ t.Errorf("-1 %s 1 = %d, want 0", "+", r)
}
y = 2147483647
r = x + y
if r != 2147483646 {
- t.Errorf("-1 + 2147483647 = %d, want 2147483646", r)
+ t.Errorf("-1 %s 2147483647 = %d, want 2147483646", "+", r)
}
x = 0
y = -2147483648
r = x + y
if r != -2147483648 {
- t.Errorf("0 + -2147483648 = %d, want -2147483648", r)
+ t.Errorf("0 %s -2147483648 = %d, want -2147483648", "+", r)
}
y = -2147483647
r = x + y
if r != -2147483647 {
- t.Errorf("0 + -2147483647 = %d, want -2147483647", r)
+ t.Errorf("0 %s -2147483647 = %d, want -2147483647", "+", r)
}
y = -1
r = x + y
if r != -1 {
- t.Errorf("0 + -1 = %d, want -1", r)
+ t.Errorf("0 %s -1 = %d, want -1", "+", r)
}
y = 0
r = x + y
if r != 0 {
- t.Errorf("0 + 0 = %d, want 0", r)
+ t.Errorf("0 %s 0 = %d, want 0", "+", r)
}
y = 1
r = x + y
if r != 1 {
- t.Errorf("0 + 1 = %d, want 1", r)
+ t.Errorf("0 %s 1 = %d, want 1", "+", r)
}
y = 2147483647
r = x + y
if r != 2147483647 {
- t.Errorf("0 + 2147483647 = %d, want 2147483647", r)
+ t.Errorf("0 %s 2147483647 = %d, want 2147483647", "+", r)
}
x = 1
y = -2147483648
r = x + y
if r != -2147483647 {
- t.Errorf("1 + -2147483648 = %d, want -2147483647", r)
+ t.Errorf("1 %s -2147483648 = %d, want -2147483647", "+", r)
}
y = -2147483647
r = x + y
if r != -2147483646 {
- t.Errorf("1 + -2147483647 = %d, want -2147483646", r)
+ t.Errorf("1 %s -2147483647 = %d, want -2147483646", "+", r)
}
y = -1
r = x + y
if r != 0 {
- t.Errorf("1 + -1 = %d, want 0", r)
+ t.Errorf("1 %s -1 = %d, want 0", "+", r)
}
y = 0
r = x + y
if r != 1 {
- t.Errorf("1 + 0 = %d, want 1", r)
+ t.Errorf("1 %s 0 = %d, want 1", "+", r)
}
y = 1
r = x + y
if r != 2 {
- t.Errorf("1 + 1 = %d, want 2", r)
+ t.Errorf("1 %s 1 = %d, want 2", "+", r)
}
y = 2147483647
r = x + y
if r != -2147483648 {
- t.Errorf("1 + 2147483647 = %d, want -2147483648", r)
+ t.Errorf("1 %s 2147483647 = %d, want -2147483648", "+", r)
}
x = 2147483647
y = -2147483648
r = x + y
if r != -1 {
- t.Errorf("2147483647 + -2147483648 = %d, want -1", r)
+ t.Errorf("2147483647 %s -2147483648 = %d, want -1", "+", r)
}
y = -2147483647
r = x + y
if r != 0 {
- t.Errorf("2147483647 + -2147483647 = %d, want 0", r)
+ t.Errorf("2147483647 %s -2147483647 = %d, want 0", "+", r)
}
y = -1
r = x + y
if r != 2147483646 {
- t.Errorf("2147483647 + -1 = %d, want 2147483646", r)
+ t.Errorf("2147483647 %s -1 = %d, want 2147483646", "+", r)
}
y = 0
r = x + y
if r != 2147483647 {
- t.Errorf("2147483647 + 0 = %d, want 2147483647", r)
+ t.Errorf("2147483647 %s 0 = %d, want 2147483647", "+", r)
}
y = 1
r = x + y
if r != -2147483648 {
- t.Errorf("2147483647 + 1 = %d, want -2147483648", r)
+ t.Errorf("2147483647 %s 1 = %d, want -2147483648", "+", r)
}
y = 2147483647
r = x + y
if r != -2 {
- t.Errorf("2147483647 + 2147483647 = %d, want -2", r)
+ t.Errorf("2147483647 %s 2147483647 = %d, want -2", "+", r)
}
}
func TestConstFoldint32sub(t *testing.T) {
@@ -2812,187 +2812,187 @@ func TestConstFoldint32sub(t *testing.T) {
y = -2147483648
r = x - y
if r != 0 {
- t.Errorf("-2147483648 - -2147483648 = %d, want 0", r)
+ t.Errorf("-2147483648 %s -2147483648 = %d, want 0", "-", r)
}
y = -2147483647
r = x - y
if r != -1 {
- t.Errorf("-2147483648 - -2147483647 = %d, want -1", r)
+ t.Errorf("-2147483648 %s -2147483647 = %d, want -1", "-", r)
}
y = -1
r = x - y
if r != -2147483647 {
- t.Errorf("-2147483648 - -1 = %d, want -2147483647", r)
+ t.Errorf("-2147483648 %s -1 = %d, want -2147483647", "-", r)
}
y = 0
r = x - y
if r != -2147483648 {
- t.Errorf("-2147483648 - 0 = %d, want -2147483648", r)
+ t.Errorf("-2147483648 %s 0 = %d, want -2147483648", "-", r)
}
y = 1
r = x - y
if r != 2147483647 {
- t.Errorf("-2147483648 - 1 = %d, want 2147483647", r)
+ t.Errorf("-2147483648 %s 1 = %d, want 2147483647", "-", r)
}
y = 2147483647
r = x - y
if r != 1 {
- t.Errorf("-2147483648 - 2147483647 = %d, want 1", r)
+ t.Errorf("-2147483648 %s 2147483647 = %d, want 1", "-", r)
}
x = -2147483647
y = -2147483648
r = x - y
if r != 1 {
- t.Errorf("-2147483647 - -2147483648 = %d, want 1", r)
+ t.Errorf("-2147483647 %s -2147483648 = %d, want 1", "-", r)
}
y = -2147483647
r = x - y
if r != 0 {
- t.Errorf("-2147483647 - -2147483647 = %d, want 0", r)
+ t.Errorf("-2147483647 %s -2147483647 = %d, want 0", "-", r)
}
y = -1
r = x - y
if r != -2147483646 {
- t.Errorf("-2147483647 - -1 = %d, want -2147483646", r)
+ t.Errorf("-2147483647 %s -1 = %d, want -2147483646", "-", r)
}
y = 0
r = x - y
if r != -2147483647 {
- t.Errorf("-2147483647 - 0 = %d, want -2147483647", r)
+ t.Errorf("-2147483647 %s 0 = %d, want -2147483647", "-", r)
}
y = 1
r = x - y
if r != -2147483648 {
- t.Errorf("-2147483647 - 1 = %d, want -2147483648", r)
+ t.Errorf("-2147483647 %s 1 = %d, want -2147483648", "-", r)
}
y = 2147483647
r = x - y
if r != 2 {
- t.Errorf("-2147483647 - 2147483647 = %d, want 2", r)
+ t.Errorf("-2147483647 %s 2147483647 = %d, want 2", "-", r)
}
x = -1
y = -2147483648
r = x - y
if r != 2147483647 {
- t.Errorf("-1 - -2147483648 = %d, want 2147483647", r)
+ t.Errorf("-1 %s -2147483648 = %d, want 2147483647", "-", r)
}
y = -2147483647
r = x - y
if r != 2147483646 {
- t.Errorf("-1 - -2147483647 = %d, want 2147483646", r)
+ t.Errorf("-1 %s -2147483647 = %d, want 2147483646", "-", r)
}
y = -1
r = x - y
if r != 0 {
- t.Errorf("-1 - -1 = %d, want 0", r)
+ t.Errorf("-1 %s -1 = %d, want 0", "-", r)
}
y = 0
r = x - y
if r != -1 {
- t.Errorf("-1 - 0 = %d, want -1", r)
+ t.Errorf("-1 %s 0 = %d, want -1", "-", r)
}
y = 1
r = x - y
if r != -2 {
- t.Errorf("-1 - 1 = %d, want -2", r)
+ t.Errorf("-1 %s 1 = %d, want -2", "-", r)
}
y = 2147483647
r = x - y
if r != -2147483648 {
- t.Errorf("-1 - 2147483647 = %d, want -2147483648", r)
+ t.Errorf("-1 %s 2147483647 = %d, want -2147483648", "-", r)
}
x = 0
y = -2147483648
r = x - y
if r != -2147483648 {
- t.Errorf("0 - -2147483648 = %d, want -2147483648", r)
+ t.Errorf("0 %s -2147483648 = %d, want -2147483648", "-", r)
}
y = -2147483647
r = x - y
if r != 2147483647 {
- t.Errorf("0 - -2147483647 = %d, want 2147483647", r)
+ t.Errorf("0 %s -2147483647 = %d, want 2147483647", "-", r)
}
y = -1
r = x - y
if r != 1 {
- t.Errorf("0 - -1 = %d, want 1", r)
+ t.Errorf("0 %s -1 = %d, want 1", "-", r)
}
y = 0
r = x - y
if r != 0 {
- t.Errorf("0 - 0 = %d, want 0", r)
+ t.Errorf("0 %s 0 = %d, want 0", "-", r)
}
y = 1
r = x - y
if r != -1 {
- t.Errorf("0 - 1 = %d, want -1", r)
+ t.Errorf("0 %s 1 = %d, want -1", "-", r)
}
y = 2147483647
r = x - y
if r != -2147483647 {
- t.Errorf("0 - 2147483647 = %d, want -2147483647", r)
+ t.Errorf("0 %s 2147483647 = %d, want -2147483647", "-", r)
}
x = 1
y = -2147483648
r = x - y
if r != -2147483647 {
- t.Errorf("1 - -2147483648 = %d, want -2147483647", r)
+ t.Errorf("1 %s -2147483648 = %d, want -2147483647", "-", r)
}
y = -2147483647
r = x - y
if r != -2147483648 {
- t.Errorf("1 - -2147483647 = %d, want -2147483648", r)
+ t.Errorf("1 %s -2147483647 = %d, want -2147483648", "-", r)
}
y = -1
r = x - y
if r != 2 {
- t.Errorf("1 - -1 = %d, want 2", r)
+ t.Errorf("1 %s -1 = %d, want 2", "-", r)
}
y = 0
r = x - y
if r != 1 {
- t.Errorf("1 - 0 = %d, want 1", r)
+ t.Errorf("1 %s 0 = %d, want 1", "-", r)
}
y = 1
r = x - y
if r != 0 {
- t.Errorf("1 - 1 = %d, want 0", r)
+ t.Errorf("1 %s 1 = %d, want 0", "-", r)
}
y = 2147483647
r = x - y
if r != -2147483646 {
- t.Errorf("1 - 2147483647 = %d, want -2147483646", r)
+ t.Errorf("1 %s 2147483647 = %d, want -2147483646", "-", r)
}
x = 2147483647
y = -2147483648
r = x - y
if r != -1 {
- t.Errorf("2147483647 - -2147483648 = %d, want -1", r)
+ t.Errorf("2147483647 %s -2147483648 = %d, want -1", "-", r)
}
y = -2147483647
r = x - y
if r != -2 {
- t.Errorf("2147483647 - -2147483647 = %d, want -2", r)
+ t.Errorf("2147483647 %s -2147483647 = %d, want -2", "-", r)
}
y = -1
r = x - y
if r != -2147483648 {
- t.Errorf("2147483647 - -1 = %d, want -2147483648", r)
+ t.Errorf("2147483647 %s -1 = %d, want -2147483648", "-", r)
}
y = 0
r = x - y
if r != 2147483647 {
- t.Errorf("2147483647 - 0 = %d, want 2147483647", r)
+ t.Errorf("2147483647 %s 0 = %d, want 2147483647", "-", r)
}
y = 1
r = x - y
if r != 2147483646 {
- t.Errorf("2147483647 - 1 = %d, want 2147483646", r)
+ t.Errorf("2147483647 %s 1 = %d, want 2147483646", "-", r)
}
y = 2147483647
r = x - y
if r != 0 {
- t.Errorf("2147483647 - 2147483647 = %d, want 0", r)
+ t.Errorf("2147483647 %s 2147483647 = %d, want 0", "-", r)
}
}
func TestConstFoldint32div(t *testing.T) {
@@ -3001,157 +3001,157 @@ func TestConstFoldint32div(t *testing.T) {
y = -2147483648
r = x / y
if r != 1 {
- t.Errorf("-2147483648 / -2147483648 = %d, want 1", r)
+ t.Errorf("-2147483648 %s -2147483648 = %d, want 1", "/", r)
}
y = -2147483647
r = x / y
if r != 1 {
- t.Errorf("-2147483648 / -2147483647 = %d, want 1", r)
+ t.Errorf("-2147483648 %s -2147483647 = %d, want 1", "/", r)
}
y = -1
r = x / y
if r != -2147483648 {
- t.Errorf("-2147483648 / -1 = %d, want -2147483648", r)
+ t.Errorf("-2147483648 %s -1 = %d, want -2147483648", "/", r)
}
y = 1
r = x / y
if r != -2147483648 {
- t.Errorf("-2147483648 / 1 = %d, want -2147483648", r)
+ t.Errorf("-2147483648 %s 1 = %d, want -2147483648", "/", r)
}
y = 2147483647
r = x / y
if r != -1 {
- t.Errorf("-2147483648 / 2147483647 = %d, want -1", r)
+ t.Errorf("-2147483648 %s 2147483647 = %d, want -1", "/", r)
}
x = -2147483647
y = -2147483648
r = x / y
if r != 0 {
- t.Errorf("-2147483647 / -2147483648 = %d, want 0", r)
+ t.Errorf("-2147483647 %s -2147483648 = %d, want 0", "/", r)
}
y = -2147483647
r = x / y
if r != 1 {
- t.Errorf("-2147483647 / -2147483647 = %d, want 1", r)
+ t.Errorf("-2147483647 %s -2147483647 = %d, want 1", "/", r)
}
y = -1
r = x / y
if r != 2147483647 {
- t.Errorf("-2147483647 / -1 = %d, want 2147483647", r)
+ t.Errorf("-2147483647 %s -1 = %d, want 2147483647", "/", r)
}
y = 1
r = x / y
if r != -2147483647 {
- t.Errorf("-2147483647 / 1 = %d, want -2147483647", r)
+ t.Errorf("-2147483647 %s 1 = %d, want -2147483647", "/", r)
}
y = 2147483647
r = x / y
if r != -1 {
- t.Errorf("-2147483647 / 2147483647 = %d, want -1", r)
+ t.Errorf("-2147483647 %s 2147483647 = %d, want -1", "/", r)
}
x = -1
y = -2147483648
r = x / y
if r != 0 {
- t.Errorf("-1 / -2147483648 = %d, want 0", r)
+ t.Errorf("-1 %s -2147483648 = %d, want 0", "/", r)
}
y = -2147483647
r = x / y
if r != 0 {
- t.Errorf("-1 / -2147483647 = %d, want 0", r)
+ t.Errorf("-1 %s -2147483647 = %d, want 0", "/", r)
}
y = -1
r = x / y
if r != 1 {
- t.Errorf("-1 / -1 = %d, want 1", r)
+ t.Errorf("-1 %s -1 = %d, want 1", "/", r)
}
y = 1
r = x / y
if r != -1 {
- t.Errorf("-1 / 1 = %d, want -1", r)
+ t.Errorf("-1 %s 1 = %d, want -1", "/", r)
}
y = 2147483647
r = x / y
if r != 0 {
- t.Errorf("-1 / 2147483647 = %d, want 0", r)
+ t.Errorf("-1 %s 2147483647 = %d, want 0", "/", r)
}
x = 0
y = -2147483648
r = x / y
if r != 0 {
- t.Errorf("0 / -2147483648 = %d, want 0", r)
+ t.Errorf("0 %s -2147483648 = %d, want 0", "/", r)
}
y = -2147483647
r = x / y
if r != 0 {
- t.Errorf("0 / -2147483647 = %d, want 0", r)
+ t.Errorf("0 %s -2147483647 = %d, want 0", "/", r)
}
y = -1
r = x / y
if r != 0 {
- t.Errorf("0 / -1 = %d, want 0", r)
+ t.Errorf("0 %s -1 = %d, want 0", "/", r)
}
y = 1
r = x / y
if r != 0 {
- t.Errorf("0 / 1 = %d, want 0", r)
+ t.Errorf("0 %s 1 = %d, want 0", "/", r)
}
y = 2147483647
r = x / y
if r != 0 {
- t.Errorf("0 / 2147483647 = %d, want 0", r)
+ t.Errorf("0 %s 2147483647 = %d, want 0", "/", r)
}
x = 1
y = -2147483648
r = x / y
if r != 0 {
- t.Errorf("1 / -2147483648 = %d, want 0", r)
+ t.Errorf("1 %s -2147483648 = %d, want 0", "/", r)
}
y = -2147483647
r = x / y
if r != 0 {
- t.Errorf("1 / -2147483647 = %d, want 0", r)
+ t.Errorf("1 %s -2147483647 = %d, want 0", "/", r)
}
y = -1
r = x / y
if r != -1 {
- t.Errorf("1 / -1 = %d, want -1", r)
+ t.Errorf("1 %s -1 = %d, want -1", "/", r)
}
y = 1
r = x / y
if r != 1 {
- t.Errorf("1 / 1 = %d, want 1", r)
+ t.Errorf("1 %s 1 = %d, want 1", "/", r)
}
y = 2147483647
r = x / y
if r != 0 {
- t.Errorf("1 / 2147483647 = %d, want 0", r)
+ t.Errorf("1 %s 2147483647 = %d, want 0", "/", r)
}
x = 2147483647
y = -2147483648
r = x / y
if r != 0 {
- t.Errorf("2147483647 / -2147483648 = %d, want 0", r)
+ t.Errorf("2147483647 %s -2147483648 = %d, want 0", "/", r)
}
y = -2147483647
r = x / y
if r != -1 {
- t.Errorf("2147483647 / -2147483647 = %d, want -1", r)
+ t.Errorf("2147483647 %s -2147483647 = %d, want -1", "/", r)
}
y = -1
r = x / y
if r != -2147483647 {
- t.Errorf("2147483647 / -1 = %d, want -2147483647", r)
+ t.Errorf("2147483647 %s -1 = %d, want -2147483647", "/", r)
}
y = 1
r = x / y
if r != 2147483647 {
- t.Errorf("2147483647 / 1 = %d, want 2147483647", r)
+ t.Errorf("2147483647 %s 1 = %d, want 2147483647", "/", r)
}
y = 2147483647
r = x / y
if r != 1 {
- t.Errorf("2147483647 / 2147483647 = %d, want 1", r)
+ t.Errorf("2147483647 %s 2147483647 = %d, want 1", "/", r)
}
}
func TestConstFoldint32mul(t *testing.T) {
@@ -3160,187 +3160,187 @@ func TestConstFoldint32mul(t *testing.T) {
y = -2147483648
r = x * y
if r != 0 {
- t.Errorf("-2147483648 * -2147483648 = %d, want 0", r)
+ t.Errorf("-2147483648 %s -2147483648 = %d, want 0", "*", r)
}
y = -2147483647
r = x * y
if r != -2147483648 {
- t.Errorf("-2147483648 * -2147483647 = %d, want -2147483648", r)
+ t.Errorf("-2147483648 %s -2147483647 = %d, want -2147483648", "*", r)
}
y = -1
r = x * y
if r != -2147483648 {
- t.Errorf("-2147483648 * -1 = %d, want -2147483648", r)
+ t.Errorf("-2147483648 %s -1 = %d, want -2147483648", "*", r)
}
y = 0
r = x * y
if r != 0 {
- t.Errorf("-2147483648 * 0 = %d, want 0", r)
+ t.Errorf("-2147483648 %s 0 = %d, want 0", "*", r)
}
y = 1
r = x * y
if r != -2147483648 {
- t.Errorf("-2147483648 * 1 = %d, want -2147483648", r)
+ t.Errorf("-2147483648 %s 1 = %d, want -2147483648", "*", r)
}
y = 2147483647
r = x * y
if r != -2147483648 {
- t.Errorf("-2147483648 * 2147483647 = %d, want -2147483648", r)
+ t.Errorf("-2147483648 %s 2147483647 = %d, want -2147483648", "*", r)
}
x = -2147483647
y = -2147483648
r = x * y
if r != -2147483648 {
- t.Errorf("-2147483647 * -2147483648 = %d, want -2147483648", r)
+ t.Errorf("-2147483647 %s -2147483648 = %d, want -2147483648", "*", r)
}
y = -2147483647
r = x * y
if r != 1 {
- t.Errorf("-2147483647 * -2147483647 = %d, want 1", r)
+ t.Errorf("-2147483647 %s -2147483647 = %d, want 1", "*", r)
}
y = -1
r = x * y
if r != 2147483647 {
- t.Errorf("-2147483647 * -1 = %d, want 2147483647", r)
+ t.Errorf("-2147483647 %s -1 = %d, want 2147483647", "*", r)
}
y = 0
r = x * y
if r != 0 {
- t.Errorf("-2147483647 * 0 = %d, want 0", r)
+ t.Errorf("-2147483647 %s 0 = %d, want 0", "*", r)
}
y = 1
r = x * y
if r != -2147483647 {
- t.Errorf("-2147483647 * 1 = %d, want -2147483647", r)
+ t.Errorf("-2147483647 %s 1 = %d, want -2147483647", "*", r)
}
y = 2147483647
r = x * y
if r != -1 {
- t.Errorf("-2147483647 * 2147483647 = %d, want -1", r)
+ t.Errorf("-2147483647 %s 2147483647 = %d, want -1", "*", r)
}
x = -1
y = -2147483648
r = x * y
if r != -2147483648 {
- t.Errorf("-1 * -2147483648 = %d, want -2147483648", r)
+ t.Errorf("-1 %s -2147483648 = %d, want -2147483648", "*", r)
}
y = -2147483647
r = x * y
if r != 2147483647 {
- t.Errorf("-1 * -2147483647 = %d, want 2147483647", r)
+ t.Errorf("-1 %s -2147483647 = %d, want 2147483647", "*", r)
}
y = -1
r = x * y
if r != 1 {
- t.Errorf("-1 * -1 = %d, want 1", r)
+ t.Errorf("-1 %s -1 = %d, want 1", "*", r)
}
y = 0
r = x * y
if r != 0 {
- t.Errorf("-1 * 0 = %d, want 0", r)
+ t.Errorf("-1 %s 0 = %d, want 0", "*", r)
}
y = 1
r = x * y
if r != -1 {
- t.Errorf("-1 * 1 = %d, want -1", r)
+ t.Errorf("-1 %s 1 = %d, want -1", "*", r)
}
y = 2147483647
r = x * y
if r != -2147483647 {
- t.Errorf("-1 * 2147483647 = %d, want -2147483647", r)
+ t.Errorf("-1 %s 2147483647 = %d, want -2147483647", "*", r)
}
x = 0
y = -2147483648
r = x * y
if r != 0 {
- t.Errorf("0 * -2147483648 = %d, want 0", r)
+ t.Errorf("0 %s -2147483648 = %d, want 0", "*", r)
}
y = -2147483647
r = x * y
if r != 0 {
- t.Errorf("0 * -2147483647 = %d, want 0", r)
+ t.Errorf("0 %s -2147483647 = %d, want 0", "*", r)
}
y = -1
r = x * y
if r != 0 {
- t.Errorf("0 * -1 = %d, want 0", r)
+ t.Errorf("0 %s -1 = %d, want 0", "*", r)
}
y = 0
r = x * y
if r != 0 {
- t.Errorf("0 * 0 = %d, want 0", r)
+ t.Errorf("0 %s 0 = %d, want 0", "*", r)
}
y = 1
r = x * y
if r != 0 {
- t.Errorf("0 * 1 = %d, want 0", r)
+ t.Errorf("0 %s 1 = %d, want 0", "*", r)
}
y = 2147483647
r = x * y
if r != 0 {
- t.Errorf("0 * 2147483647 = %d, want 0", r)
+ t.Errorf("0 %s 2147483647 = %d, want 0", "*", r)
}
x = 1
y = -2147483648
r = x * y
if r != -2147483648 {
- t.Errorf("1 * -2147483648 = %d, want -2147483648", r)
+ t.Errorf("1 %s -2147483648 = %d, want -2147483648", "*", r)
}
y = -2147483647
r = x * y
if r != -2147483647 {
- t.Errorf("1 * -2147483647 = %d, want -2147483647", r)
+ t.Errorf("1 %s -2147483647 = %d, want -2147483647", "*", r)
}
y = -1
r = x * y
if r != -1 {
- t.Errorf("1 * -1 = %d, want -1", r)
+ t.Errorf("1 %s -1 = %d, want -1", "*", r)
}
y = 0
r = x * y
if r != 0 {
- t.Errorf("1 * 0 = %d, want 0", r)
+ t.Errorf("1 %s 0 = %d, want 0", "*", r)
}
y = 1
r = x * y
if r != 1 {
- t.Errorf("1 * 1 = %d, want 1", r)
+ t.Errorf("1 %s 1 = %d, want 1", "*", r)
}
y = 2147483647
r = x * y
if r != 2147483647 {
- t.Errorf("1 * 2147483647 = %d, want 2147483647", r)
+ t.Errorf("1 %s 2147483647 = %d, want 2147483647", "*", r)
}
x = 2147483647
y = -2147483648
r = x * y
if r != -2147483648 {
- t.Errorf("2147483647 * -2147483648 = %d, want -2147483648", r)
+ t.Errorf("2147483647 %s -2147483648 = %d, want -2147483648", "*", r)
}
y = -2147483647
r = x * y
if r != -1 {
- t.Errorf("2147483647 * -2147483647 = %d, want -1", r)
+ t.Errorf("2147483647 %s -2147483647 = %d, want -1", "*", r)
}
y = -1
r = x * y
if r != -2147483647 {
- t.Errorf("2147483647 * -1 = %d, want -2147483647", r)
+ t.Errorf("2147483647 %s -1 = %d, want -2147483647", "*", r)
}
y = 0
r = x * y
if r != 0 {
- t.Errorf("2147483647 * 0 = %d, want 0", r)
+ t.Errorf("2147483647 %s 0 = %d, want 0", "*", r)
}
y = 1
r = x * y
if r != 2147483647 {
- t.Errorf("2147483647 * 1 = %d, want 2147483647", r)
+ t.Errorf("2147483647 %s 1 = %d, want 2147483647", "*", r)
}
y = 2147483647
r = x * y
if r != 1 {
- t.Errorf("2147483647 * 2147483647 = %d, want 1", r)
+ t.Errorf("2147483647 %s 2147483647 = %d, want 1", "*", r)
}
}
func TestConstFoldint32mod(t *testing.T) {
@@ -3349,157 +3349,157 @@ func TestConstFoldint32mod(t *testing.T) {
y = -2147483648
r = x % y
if r != 0 {
- t.Errorf("-2147483648 % -2147483648 = %d, want 0", r)
+ t.Errorf("-2147483648 %s -2147483648 = %d, want 0", "%", r)
}
y = -2147483647
r = x % y
if r != -1 {
- t.Errorf("-2147483648 % -2147483647 = %d, want -1", r)
+ t.Errorf("-2147483648 %s -2147483647 = %d, want -1", "%", r)
}
y = -1
r = x % y
if r != 0 {
- t.Errorf("-2147483648 % -1 = %d, want 0", r)
+ t.Errorf("-2147483648 %s -1 = %d, want 0", "%", r)
}
y = 1
r = x % y
if r != 0 {
- t.Errorf("-2147483648 % 1 = %d, want 0", r)
+ t.Errorf("-2147483648 %s 1 = %d, want 0", "%", r)
}
y = 2147483647
r = x % y
if r != -1 {
- t.Errorf("-2147483648 % 2147483647 = %d, want -1", r)
+ t.Errorf("-2147483648 %s 2147483647 = %d, want -1", "%", r)
}
x = -2147483647
y = -2147483648
r = x % y
if r != -2147483647 {
- t.Errorf("-2147483647 % -2147483648 = %d, want -2147483647", r)
+ t.Errorf("-2147483647 %s -2147483648 = %d, want -2147483647", "%", r)
}
y = -2147483647
r = x % y
if r != 0 {
- t.Errorf("-2147483647 % -2147483647 = %d, want 0", r)
+ t.Errorf("-2147483647 %s -2147483647 = %d, want 0", "%", r)
}
y = -1
r = x % y
if r != 0 {
- t.Errorf("-2147483647 % -1 = %d, want 0", r)
+ t.Errorf("-2147483647 %s -1 = %d, want 0", "%", r)
}
y = 1
r = x % y
if r != 0 {
- t.Errorf("-2147483647 % 1 = %d, want 0", r)
+ t.Errorf("-2147483647 %s 1 = %d, want 0", "%", r)
}
y = 2147483647
r = x % y
if r != 0 {
- t.Errorf("-2147483647 % 2147483647 = %d, want 0", r)
+ t.Errorf("-2147483647 %s 2147483647 = %d, want 0", "%", r)
}
x = -1
y = -2147483648
r = x % y
if r != -1 {
- t.Errorf("-1 % -2147483648 = %d, want -1", r)
+ t.Errorf("-1 %s -2147483648 = %d, want -1", "%", r)
}
y = -2147483647
r = x % y
if r != -1 {
- t.Errorf("-1 % -2147483647 = %d, want -1", r)
+ t.Errorf("-1 %s -2147483647 = %d, want -1", "%", r)
}
y = -1
r = x % y
if r != 0 {
- t.Errorf("-1 % -1 = %d, want 0", r)
+ t.Errorf("-1 %s -1 = %d, want 0", "%", r)
}
y = 1
r = x % y
if r != 0 {
- t.Errorf("-1 % 1 = %d, want 0", r)
+ t.Errorf("-1 %s 1 = %d, want 0", "%", r)
}
y = 2147483647
r = x % y
if r != -1 {
- t.Errorf("-1 % 2147483647 = %d, want -1", r)
+ t.Errorf("-1 %s 2147483647 = %d, want -1", "%", r)
}
x = 0
y = -2147483648
r = x % y
if r != 0 {
- t.Errorf("0 % -2147483648 = %d, want 0", r)
+ t.Errorf("0 %s -2147483648 = %d, want 0", "%", r)
}
y = -2147483647
r = x % y
if r != 0 {
- t.Errorf("0 % -2147483647 = %d, want 0", r)
+ t.Errorf("0 %s -2147483647 = %d, want 0", "%", r)
}
y = -1
r = x % y
if r != 0 {
- t.Errorf("0 % -1 = %d, want 0", r)
+ t.Errorf("0 %s -1 = %d, want 0", "%", r)
}
y = 1
r = x % y
if r != 0 {
- t.Errorf("0 % 1 = %d, want 0", r)
+ t.Errorf("0 %s 1 = %d, want 0", "%", r)
}
y = 2147483647
r = x % y
if r != 0 {
- t.Errorf("0 % 2147483647 = %d, want 0", r)
+ t.Errorf("0 %s 2147483647 = %d, want 0", "%", r)
}
x = 1
y = -2147483648
r = x % y
if r != 1 {
- t.Errorf("1 % -2147483648 = %d, want 1", r)
+ t.Errorf("1 %s -2147483648 = %d, want 1", "%", r)
}
y = -2147483647
r = x % y
if r != 1 {
- t.Errorf("1 % -2147483647 = %d, want 1", r)
+ t.Errorf("1 %s -2147483647 = %d, want 1", "%", r)
}
y = -1
r = x % y
if r != 0 {
- t.Errorf("1 % -1 = %d, want 0", r)
+ t.Errorf("1 %s -1 = %d, want 0", "%", r)
}
y = 1
r = x % y
if r != 0 {
- t.Errorf("1 % 1 = %d, want 0", r)
+ t.Errorf("1 %s 1 = %d, want 0", "%", r)
}
y = 2147483647
r = x % y
if r != 1 {
- t.Errorf("1 % 2147483647 = %d, want 1", r)
+ t.Errorf("1 %s 2147483647 = %d, want 1", "%", r)
}
x = 2147483647
y = -2147483648
r = x % y
if r != 2147483647 {
- t.Errorf("2147483647 % -2147483648 = %d, want 2147483647", r)
+ t.Errorf("2147483647 %s -2147483648 = %d, want 2147483647", "%", r)
}
y = -2147483647
r = x % y
if r != 0 {
- t.Errorf("2147483647 % -2147483647 = %d, want 0", r)
+ t.Errorf("2147483647 %s -2147483647 = %d, want 0", "%", r)
}
y = -1
r = x % y
if r != 0 {
- t.Errorf("2147483647 % -1 = %d, want 0", r)
+ t.Errorf("2147483647 %s -1 = %d, want 0", "%", r)
}
y = 1
r = x % y
if r != 0 {
- t.Errorf("2147483647 % 1 = %d, want 0", r)
+ t.Errorf("2147483647 %s 1 = %d, want 0", "%", r)
}
y = 2147483647
r = x % y
if r != 0 {
- t.Errorf("2147483647 % 2147483647 = %d, want 0", r)
+ t.Errorf("2147483647 %s 2147483647 = %d, want 0", "%", r)
}
}
func TestConstFolduint16add(t *testing.T) {
@@ -3508,49 +3508,49 @@ func TestConstFolduint16add(t *testing.T) {
y = 0
r = x + y
if r != 0 {
- t.Errorf("0 + 0 = %d, want 0", r)
+ t.Errorf("0 %s 0 = %d, want 0", "+", r)
}
y = 1
r = x + y
if r != 1 {
- t.Errorf("0 + 1 = %d, want 1", r)
+ t.Errorf("0 %s 1 = %d, want 1", "+", r)
}
y = 65535
r = x + y
if r != 65535 {
- t.Errorf("0 + 65535 = %d, want 65535", r)
+ t.Errorf("0 %s 65535 = %d, want 65535", "+", r)
}
x = 1
y = 0
r = x + y
if r != 1 {
- t.Errorf("1 + 0 = %d, want 1", r)
+ t.Errorf("1 %s 0 = %d, want 1", "+", r)
}
y = 1
r = x + y
if r != 2 {
- t.Errorf("1 + 1 = %d, want 2", r)
+ t.Errorf("1 %s 1 = %d, want 2", "+", r)
}
y = 65535
r = x + y
if r != 0 {
- t.Errorf("1 + 65535 = %d, want 0", r)
+ t.Errorf("1 %s 65535 = %d, want 0", "+", r)
}
x = 65535
y = 0
r = x + y
if r != 65535 {
- t.Errorf("65535 + 0 = %d, want 65535", r)
+ t.Errorf("65535 %s 0 = %d, want 65535", "+", r)
}
y = 1
r = x + y
if r != 0 {
- t.Errorf("65535 + 1 = %d, want 0", r)
+ t.Errorf("65535 %s 1 = %d, want 0", "+", r)
}
y = 65535
r = x + y
if r != 65534 {
- t.Errorf("65535 + 65535 = %d, want 65534", r)
+ t.Errorf("65535 %s 65535 = %d, want 65534", "+", r)
}
}
func TestConstFolduint16sub(t *testing.T) {
@@ -3559,49 +3559,49 @@ func TestConstFolduint16sub(t *testing.T) {
y = 0
r = x - y
if r != 0 {
- t.Errorf("0 - 0 = %d, want 0", r)
+ t.Errorf("0 %s 0 = %d, want 0", "-", r)
}
y = 1
r = x - y
if r != 65535 {
- t.Errorf("0 - 1 = %d, want 65535", r)
+ t.Errorf("0 %s 1 = %d, want 65535", "-", r)
}
y = 65535
r = x - y
if r != 1 {
- t.Errorf("0 - 65535 = %d, want 1", r)
+ t.Errorf("0 %s 65535 = %d, want 1", "-", r)
}
x = 1
y = 0
r = x - y
if r != 1 {
- t.Errorf("1 - 0 = %d, want 1", r)
+ t.Errorf("1 %s 0 = %d, want 1", "-", r)
}
y = 1
r = x - y
if r != 0 {
- t.Errorf("1 - 1 = %d, want 0", r)
+ t.Errorf("1 %s 1 = %d, want 0", "-", r)
}
y = 65535
r = x - y
if r != 2 {
- t.Errorf("1 - 65535 = %d, want 2", r)
+ t.Errorf("1 %s 65535 = %d, want 2", "-", r)
}
x = 65535
y = 0
r = x - y
if r != 65535 {
- t.Errorf("65535 - 0 = %d, want 65535", r)
+ t.Errorf("65535 %s 0 = %d, want 65535", "-", r)
}
y = 1
r = x - y
if r != 65534 {
- t.Errorf("65535 - 1 = %d, want 65534", r)
+ t.Errorf("65535 %s 1 = %d, want 65534", "-", r)
}
y = 65535
r = x - y
if r != 0 {
- t.Errorf("65535 - 65535 = %d, want 0", r)
+ t.Errorf("65535 %s 65535 = %d, want 0", "-", r)
}
}
func TestConstFolduint16div(t *testing.T) {
@@ -3610,34 +3610,34 @@ func TestConstFolduint16div(t *testing.T) {
y = 1
r = x / y
if r != 0 {
- t.Errorf("0 / 1 = %d, want 0", r)
+ t.Errorf("0 %s 1 = %d, want 0", "/", r)
}
y = 65535
r = x / y
if r != 0 {
- t.Errorf("0 / 65535 = %d, want 0", r)
+ t.Errorf("0 %s 65535 = %d, want 0", "/", r)
}
x = 1
y = 1
r = x / y
if r != 1 {
- t.Errorf("1 / 1 = %d, want 1", r)
+ t.Errorf("1 %s 1 = %d, want 1", "/", r)
}
y = 65535
r = x / y
if r != 0 {
- t.Errorf("1 / 65535 = %d, want 0", r)
+ t.Errorf("1 %s 65535 = %d, want 0", "/", r)
}
x = 65535
y = 1
r = x / y
if r != 65535 {
- t.Errorf("65535 / 1 = %d, want 65535", r)
+ t.Errorf("65535 %s 1 = %d, want 65535", "/", r)
}
y = 65535
r = x / y
if r != 1 {
- t.Errorf("65535 / 65535 = %d, want 1", r)
+ t.Errorf("65535 %s 65535 = %d, want 1", "/", r)
}
}
func TestConstFolduint16mul(t *testing.T) {
@@ -3646,49 +3646,49 @@ func TestConstFolduint16mul(t *testing.T) {
y = 0
r = x * y
if r != 0 {
- t.Errorf("0 * 0 = %d, want 0", r)
+ t.Errorf("0 %s 0 = %d, want 0", "*", r)
}
y = 1
r = x * y
if r != 0 {
- t.Errorf("0 * 1 = %d, want 0", r)
+ t.Errorf("0 %s 1 = %d, want 0", "*", r)
}
y = 65535
r = x * y
if r != 0 {
- t.Errorf("0 * 65535 = %d, want 0", r)
+ t.Errorf("0 %s 65535 = %d, want 0", "*", r)
}
x = 1
y = 0
r = x * y
if r != 0 {
- t.Errorf("1 * 0 = %d, want 0", r)
+ t.Errorf("1 %s 0 = %d, want 0", "*", r)
}
y = 1
r = x * y
if r != 1 {
- t.Errorf("1 * 1 = %d, want 1", r)
+ t.Errorf("1 %s 1 = %d, want 1", "*", r)
}
y = 65535
r = x * y
if r != 65535 {
- t.Errorf("1 * 65535 = %d, want 65535", r)
+ t.Errorf("1 %s 65535 = %d, want 65535", "*", r)
}
x = 65535
y = 0
r = x * y
if r != 0 {
- t.Errorf("65535 * 0 = %d, want 0", r)
+ t.Errorf("65535 %s 0 = %d, want 0", "*", r)
}
y = 1
r = x * y
if r != 65535 {
- t.Errorf("65535 * 1 = %d, want 65535", r)
+ t.Errorf("65535 %s 1 = %d, want 65535", "*", r)
}
y = 65535
r = x * y
if r != 1 {
- t.Errorf("65535 * 65535 = %d, want 1", r)
+ t.Errorf("65535 %s 65535 = %d, want 1", "*", r)
}
}
func TestConstFolduint16mod(t *testing.T) {
@@ -3697,34 +3697,34 @@ func TestConstFolduint16mod(t *testing.T) {
y = 1
r = x % y
if r != 0 {
- t.Errorf("0 % 1 = %d, want 0", r)
+ t.Errorf("0 %s 1 = %d, want 0", "%", r)
}
y = 65535
r = x % y
if r != 0 {
- t.Errorf("0 % 65535 = %d, want 0", r)
+ t.Errorf("0 %s 65535 = %d, want 0", "%", r)
}
x = 1
y = 1
r = x % y
if r != 0 {
- t.Errorf("1 % 1 = %d, want 0", r)
+ t.Errorf("1 %s 1 = %d, want 0", "%", r)
}
y = 65535
r = x % y
if r != 1 {
- t.Errorf("1 % 65535 = %d, want 1", r)
+ t.Errorf("1 %s 65535 = %d, want 1", "%", r)
}
x = 65535
y = 1
r = x % y
if r != 0 {
- t.Errorf("65535 % 1 = %d, want 0", r)
+ t.Errorf("65535 %s 1 = %d, want 0", "%", r)
}
y = 65535
r = x % y
if r != 0 {
- t.Errorf("65535 % 65535 = %d, want 0", r)
+ t.Errorf("65535 %s 65535 = %d, want 0", "%", r)
}
}
func TestConstFoldint16add(t *testing.T) {
@@ -3733,253 +3733,253 @@ func TestConstFoldint16add(t *testing.T) {
y = -32768
r = x + y
if r != 0 {
- t.Errorf("-32768 + -32768 = %d, want 0", r)
+ t.Errorf("-32768 %s -32768 = %d, want 0", "+", r)
}
y = -32767
r = x + y
if r != 1 {
- t.Errorf("-32768 + -32767 = %d, want 1", r)
+ t.Errorf("-32768 %s -32767 = %d, want 1", "+", r)
}
y = -1
r = x + y
if r != 32767 {
- t.Errorf("-32768 + -1 = %d, want 32767", r)
+ t.Errorf("-32768 %s -1 = %d, want 32767", "+", r)
}
y = 0
r = x + y
if r != -32768 {
- t.Errorf("-32768 + 0 = %d, want -32768", r)
+ t.Errorf("-32768 %s 0 = %d, want -32768", "+", r)
}
y = 1
r = x + y
if r != -32767 {
- t.Errorf("-32768 + 1 = %d, want -32767", r)
+ t.Errorf("-32768 %s 1 = %d, want -32767", "+", r)
}
y = 32766
r = x + y
if r != -2 {
- t.Errorf("-32768 + 32766 = %d, want -2", r)
+ t.Errorf("-32768 %s 32766 = %d, want -2", "+", r)
}
y = 32767
r = x + y
if r != -1 {
- t.Errorf("-32768 + 32767 = %d, want -1", r)
+ t.Errorf("-32768 %s 32767 = %d, want -1", "+", r)
}
x = -32767
y = -32768
r = x + y
if r != 1 {
- t.Errorf("-32767 + -32768 = %d, want 1", r)
+ t.Errorf("-32767 %s -32768 = %d, want 1", "+", r)
}
y = -32767
r = x + y
if r != 2 {
- t.Errorf("-32767 + -32767 = %d, want 2", r)
+ t.Errorf("-32767 %s -32767 = %d, want 2", "+", r)
}
y = -1
r = x + y
if r != -32768 {
- t.Errorf("-32767 + -1 = %d, want -32768", r)
+ t.Errorf("-32767 %s -1 = %d, want -32768", "+", r)
}
y = 0
r = x + y
if r != -32767 {
- t.Errorf("-32767 + 0 = %d, want -32767", r)
+ t.Errorf("-32767 %s 0 = %d, want -32767", "+", r)
}
y = 1
r = x + y
if r != -32766 {
- t.Errorf("-32767 + 1 = %d, want -32766", r)
+ t.Errorf("-32767 %s 1 = %d, want -32766", "+", r)
}
y = 32766
r = x + y
if r != -1 {
- t.Errorf("-32767 + 32766 = %d, want -1", r)
+ t.Errorf("-32767 %s 32766 = %d, want -1", "+", r)
}
y = 32767
r = x + y
if r != 0 {
- t.Errorf("-32767 + 32767 = %d, want 0", r)
+ t.Errorf("-32767 %s 32767 = %d, want 0", "+", r)
}
x = -1
y = -32768
r = x + y
if r != 32767 {
- t.Errorf("-1 + -32768 = %d, want 32767", r)
+ t.Errorf("-1 %s -32768 = %d, want 32767", "+", r)
}
y = -32767
r = x + y
if r != -32768 {
- t.Errorf("-1 + -32767 = %d, want -32768", r)
+ t.Errorf("-1 %s -32767 = %d, want -32768", "+", r)
}
y = -1
r = x + y
if r != -2 {
- t.Errorf("-1 + -1 = %d, want -2", r)
+ t.Errorf("-1 %s -1 = %d, want -2", "+", r)
}
y = 0
r = x + y
if r != -1 {
- t.Errorf("-1 + 0 = %d, want -1", r)
+ t.Errorf("-1 %s 0 = %d, want -1", "+", r)
}
y = 1
r = x + y
if r != 0 {
- t.Errorf("-1 + 1 = %d, want 0", r)
+ t.Errorf("-1 %s 1 = %d, want 0", "+", r)
}
y = 32766
r = x + y
if r != 32765 {
- t.Errorf("-1 + 32766 = %d, want 32765", r)
+ t.Errorf("-1 %s 32766 = %d, want 32765", "+", r)
}
y = 32767
r = x + y
if r != 32766 {
- t.Errorf("-1 + 32767 = %d, want 32766", r)
+ t.Errorf("-1 %s 32767 = %d, want 32766", "+", r)
}
x = 0
y = -32768
r = x + y
if r != -32768 {
- t.Errorf("0 + -32768 = %d, want -32768", r)
+ t.Errorf("0 %s -32768 = %d, want -32768", "+", r)
}
y = -32767
r = x + y
if r != -32767 {
- t.Errorf("0 + -32767 = %d, want -32767", r)
+ t.Errorf("0 %s -32767 = %d, want -32767", "+", r)
}
y = -1
r = x + y
if r != -1 {
- t.Errorf("0 + -1 = %d, want -1", r)
+ t.Errorf("0 %s -1 = %d, want -1", "+", r)
}
y = 0
r = x + y
if r != 0 {
- t.Errorf("0 + 0 = %d, want 0", r)
+ t.Errorf("0 %s 0 = %d, want 0", "+", r)
}
y = 1
r = x + y
if r != 1 {
- t.Errorf("0 + 1 = %d, want 1", r)
+ t.Errorf("0 %s 1 = %d, want 1", "+", r)
}
y = 32766
r = x + y
if r != 32766 {
- t.Errorf("0 + 32766 = %d, want 32766", r)
+ t.Errorf("0 %s 32766 = %d, want 32766", "+", r)
}
y = 32767
r = x + y
if r != 32767 {
- t.Errorf("0 + 32767 = %d, want 32767", r)
+ t.Errorf("0 %s 32767 = %d, want 32767", "+", r)
}
x = 1
y = -32768
r = x + y
if r != -32767 {
- t.Errorf("1 + -32768 = %d, want -32767", r)
+ t.Errorf("1 %s -32768 = %d, want -32767", "+", r)
}
y = -32767
r = x + y
if r != -32766 {
- t.Errorf("1 + -32767 = %d, want -32766", r)
+ t.Errorf("1 %s -32767 = %d, want -32766", "+", r)
}
y = -1
r = x + y
if r != 0 {
- t.Errorf("1 + -1 = %d, want 0", r)
+ t.Errorf("1 %s -1 = %d, want 0", "+", r)
}
y = 0
r = x + y
if r != 1 {
- t.Errorf("1 + 0 = %d, want 1", r)
+ t.Errorf("1 %s 0 = %d, want 1", "+", r)
}
y = 1
r = x + y
if r != 2 {
- t.Errorf("1 + 1 = %d, want 2", r)
+ t.Errorf("1 %s 1 = %d, want 2", "+", r)
}
y = 32766
r = x + y
if r != 32767 {
- t.Errorf("1 + 32766 = %d, want 32767", r)
+ t.Errorf("1 %s 32766 = %d, want 32767", "+", r)
}
y = 32767
r = x + y
if r != -32768 {
- t.Errorf("1 + 32767 = %d, want -32768", r)
+ t.Errorf("1 %s 32767 = %d, want -32768", "+", r)
}
x = 32766
y = -32768
r = x + y
if r != -2 {
- t.Errorf("32766 + -32768 = %d, want -2", r)
+ t.Errorf("32766 %s -32768 = %d, want -2", "+", r)
}
y = -32767
r = x + y
if r != -1 {
- t.Errorf("32766 + -32767 = %d, want -1", r)
+ t.Errorf("32766 %s -32767 = %d, want -1", "+", r)
}
y = -1
r = x + y
if r != 32765 {
- t.Errorf("32766 + -1 = %d, want 32765", r)
+ t.Errorf("32766 %s -1 = %d, want 32765", "+", r)
}
y = 0
r = x + y
if r != 32766 {
- t.Errorf("32766 + 0 = %d, want 32766", r)
+ t.Errorf("32766 %s 0 = %d, want 32766", "+", r)
}
y = 1
r = x + y
if r != 32767 {
- t.Errorf("32766 + 1 = %d, want 32767", r)
+ t.Errorf("32766 %s 1 = %d, want 32767", "+", r)
}
y = 32766
r = x + y
if r != -4 {
- t.Errorf("32766 + 32766 = %d, want -4", r)
+ t.Errorf("32766 %s 32766 = %d, want -4", "+", r)
}
y = 32767
r = x + y
if r != -3 {
- t.Errorf("32766 + 32767 = %d, want -3", r)
+ t.Errorf("32766 %s 32767 = %d, want -3", "+", r)
}
x = 32767
y = -32768
r = x + y
if r != -1 {
- t.Errorf("32767 + -32768 = %d, want -1", r)
+ t.Errorf("32767 %s -32768 = %d, want -1", "+", r)
}
y = -32767
r = x + y
if r != 0 {
- t.Errorf("32767 + -32767 = %d, want 0", r)
+ t.Errorf("32767 %s -32767 = %d, want 0", "+", r)
}
y = -1
r = x + y
if r != 32766 {
- t.Errorf("32767 + -1 = %d, want 32766", r)
+ t.Errorf("32767 %s -1 = %d, want 32766", "+", r)
}
y = 0
r = x + y
if r != 32767 {
- t.Errorf("32767 + 0 = %d, want 32767", r)
+ t.Errorf("32767 %s 0 = %d, want 32767", "+", r)
}
y = 1
r = x + y
if r != -32768 {
- t.Errorf("32767 + 1 = %d, want -32768", r)
+ t.Errorf("32767 %s 1 = %d, want -32768", "+", r)
}
y = 32766
r = x + y
if r != -3 {
- t.Errorf("32767 + 32766 = %d, want -3", r)
+ t.Errorf("32767 %s 32766 = %d, want -3", "+", r)
}
y = 32767
r = x + y
if r != -2 {
- t.Errorf("32767 + 32767 = %d, want -2", r)
+ t.Errorf("32767 %s 32767 = %d, want -2", "+", r)
}
}
func TestConstFoldint16sub(t *testing.T) {
@@ -3988,253 +3988,253 @@ func TestConstFoldint16sub(t *testing.T) {
y = -32768
r = x - y
if r != 0 {
- t.Errorf("-32768 - -32768 = %d, want 0", r)
+ t.Errorf("-32768 %s -32768 = %d, want 0", "-", r)
}
y = -32767
r = x - y
if r != -1 {
- t.Errorf("-32768 - -32767 = %d, want -1", r)
+ t.Errorf("-32768 %s -32767 = %d, want -1", "-", r)
}
y = -1
r = x - y
if r != -32767 {
- t.Errorf("-32768 - -1 = %d, want -32767", r)
+ t.Errorf("-32768 %s -1 = %d, want -32767", "-", r)
}
y = 0
r = x - y
if r != -32768 {
- t.Errorf("-32768 - 0 = %d, want -32768", r)
+ t.Errorf("-32768 %s 0 = %d, want -32768", "-", r)
}
y = 1
r = x - y
if r != 32767 {
- t.Errorf("-32768 - 1 = %d, want 32767", r)
+ t.Errorf("-32768 %s 1 = %d, want 32767", "-", r)
}
y = 32766
r = x - y
if r != 2 {
- t.Errorf("-32768 - 32766 = %d, want 2", r)
+ t.Errorf("-32768 %s 32766 = %d, want 2", "-", r)
}
y = 32767
r = x - y
if r != 1 {
- t.Errorf("-32768 - 32767 = %d, want 1", r)
+ t.Errorf("-32768 %s 32767 = %d, want 1", "-", r)
}
x = -32767
y = -32768
r = x - y
if r != 1 {
- t.Errorf("-32767 - -32768 = %d, want 1", r)
+ t.Errorf("-32767 %s -32768 = %d, want 1", "-", r)
}
y = -32767
r = x - y
if r != 0 {
- t.Errorf("-32767 - -32767 = %d, want 0", r)
+ t.Errorf("-32767 %s -32767 = %d, want 0", "-", r)
}
y = -1
r = x - y
if r != -32766 {
- t.Errorf("-32767 - -1 = %d, want -32766", r)
+ t.Errorf("-32767 %s -1 = %d, want -32766", "-", r)
}
y = 0
r = x - y
if r != -32767 {
- t.Errorf("-32767 - 0 = %d, want -32767", r)
+ t.Errorf("-32767 %s 0 = %d, want -32767", "-", r)
}
y = 1
r = x - y
if r != -32768 {
- t.Errorf("-32767 - 1 = %d, want -32768", r)
+ t.Errorf("-32767 %s 1 = %d, want -32768", "-", r)
}
y = 32766
r = x - y
if r != 3 {
- t.Errorf("-32767 - 32766 = %d, want 3", r)
+ t.Errorf("-32767 %s 32766 = %d, want 3", "-", r)
}
y = 32767
r = x - y
if r != 2 {
- t.Errorf("-32767 - 32767 = %d, want 2", r)
+ t.Errorf("-32767 %s 32767 = %d, want 2", "-", r)
}
x = -1
y = -32768
r = x - y
if r != 32767 {
- t.Errorf("-1 - -32768 = %d, want 32767", r)
+ t.Errorf("-1 %s -32768 = %d, want 32767", "-", r)
}
y = -32767
r = x - y
if r != 32766 {
- t.Errorf("-1 - -32767 = %d, want 32766", r)
+ t.Errorf("-1 %s -32767 = %d, want 32766", "-", r)
}
y = -1
r = x - y
if r != 0 {
- t.Errorf("-1 - -1 = %d, want 0", r)
+ t.Errorf("-1 %s -1 = %d, want 0", "-", r)
}
y = 0
r = x - y
if r != -1 {
- t.Errorf("-1 - 0 = %d, want -1", r)
+ t.Errorf("-1 %s 0 = %d, want -1", "-", r)
}
y = 1
r = x - y
if r != -2 {
- t.Errorf("-1 - 1 = %d, want -2", r)
+ t.Errorf("-1 %s 1 = %d, want -2", "-", r)
}
y = 32766
r = x - y
if r != -32767 {
- t.Errorf("-1 - 32766 = %d, want -32767", r)
+ t.Errorf("-1 %s 32766 = %d, want -32767", "-", r)
}
y = 32767
r = x - y
if r != -32768 {
- t.Errorf("-1 - 32767 = %d, want -32768", r)
+ t.Errorf("-1 %s 32767 = %d, want -32768", "-", r)
}
x = 0
y = -32768
r = x - y
if r != -32768 {
- t.Errorf("0 - -32768 = %d, want -32768", r)
+ t.Errorf("0 %s -32768 = %d, want -32768", "-", r)
}
y = -32767
r = x - y
if r != 32767 {
- t.Errorf("0 - -32767 = %d, want 32767", r)
+ t.Errorf("0 %s -32767 = %d, want 32767", "-", r)
}
y = -1
r = x - y
if r != 1 {
- t.Errorf("0 - -1 = %d, want 1", r)
+ t.Errorf("0 %s -1 = %d, want 1", "-", r)
}
y = 0
r = x - y
if r != 0 {
- t.Errorf("0 - 0 = %d, want 0", r)
+ t.Errorf("0 %s 0 = %d, want 0", "-", r)
}
y = 1
r = x - y
if r != -1 {
- t.Errorf("0 - 1 = %d, want -1", r)
+ t.Errorf("0 %s 1 = %d, want -1", "-", r)
}
y = 32766
r = x - y
if r != -32766 {
- t.Errorf("0 - 32766 = %d, want -32766", r)
+ t.Errorf("0 %s 32766 = %d, want -32766", "-", r)
}
y = 32767
r = x - y
if r != -32767 {
- t.Errorf("0 - 32767 = %d, want -32767", r)
+ t.Errorf("0 %s 32767 = %d, want -32767", "-", r)
}
x = 1
y = -32768
r = x - y
if r != -32767 {
- t.Errorf("1 - -32768 = %d, want -32767", r)
+ t.Errorf("1 %s -32768 = %d, want -32767", "-", r)
}
y = -32767
r = x - y
if r != -32768 {
- t.Errorf("1 - -32767 = %d, want -32768", r)
+ t.Errorf("1 %s -32767 = %d, want -32768", "-", r)
}
y = -1
r = x - y
if r != 2 {
- t.Errorf("1 - -1 = %d, want 2", r)
+ t.Errorf("1 %s -1 = %d, want 2", "-", r)
}
y = 0
r = x - y
if r != 1 {
- t.Errorf("1 - 0 = %d, want 1", r)
+ t.Errorf("1 %s 0 = %d, want 1", "-", r)
}
y = 1
r = x - y
if r != 0 {
- t.Errorf("1 - 1 = %d, want 0", r)
+ t.Errorf("1 %s 1 = %d, want 0", "-", r)
}
y = 32766
r = x - y
if r != -32765 {
- t.Errorf("1 - 32766 = %d, want -32765", r)
+ t.Errorf("1 %s 32766 = %d, want -32765", "-", r)
}
y = 32767
r = x - y
if r != -32766 {
- t.Errorf("1 - 32767 = %d, want -32766", r)
+ t.Errorf("1 %s 32767 = %d, want -32766", "-", r)
}
x = 32766
y = -32768
r = x - y
if r != -2 {
- t.Errorf("32766 - -32768 = %d, want -2", r)
+ t.Errorf("32766 %s -32768 = %d, want -2", "-", r)
}
y = -32767
r = x - y
if r != -3 {
- t.Errorf("32766 - -32767 = %d, want -3", r)
+ t.Errorf("32766 %s -32767 = %d, want -3", "-", r)
}
y = -1
r = x - y
if r != 32767 {
- t.Errorf("32766 - -1 = %d, want 32767", r)
+ t.Errorf("32766 %s -1 = %d, want 32767", "-", r)
}
y = 0
r = x - y
if r != 32766 {
- t.Errorf("32766 - 0 = %d, want 32766", r)
+ t.Errorf("32766 %s 0 = %d, want 32766", "-", r)
}
y = 1
r = x - y
if r != 32765 {
- t.Errorf("32766 - 1 = %d, want 32765", r)
+ t.Errorf("32766 %s 1 = %d, want 32765", "-", r)
}
y = 32766
r = x - y
if r != 0 {
- t.Errorf("32766 - 32766 = %d, want 0", r)
+ t.Errorf("32766 %s 32766 = %d, want 0", "-", r)
}
y = 32767
r = x - y
if r != -1 {
- t.Errorf("32766 - 32767 = %d, want -1", r)
+ t.Errorf("32766 %s 32767 = %d, want -1", "-", r)
}
x = 32767
y = -32768
r = x - y
if r != -1 {
- t.Errorf("32767 - -32768 = %d, want -1", r)
+ t.Errorf("32767 %s -32768 = %d, want -1", "-", r)
}
y = -32767
r = x - y
if r != -2 {
- t.Errorf("32767 - -32767 = %d, want -2", r)
+ t.Errorf("32767 %s -32767 = %d, want -2", "-", r)
}
y = -1
r = x - y
if r != -32768 {
- t.Errorf("32767 - -1 = %d, want -32768", r)
+ t.Errorf("32767 %s -1 = %d, want -32768", "-", r)
}
y = 0
r = x - y
if r != 32767 {
- t.Errorf("32767 - 0 = %d, want 32767", r)
+ t.Errorf("32767 %s 0 = %d, want 32767", "-", r)
}
y = 1
r = x - y
if r != 32766 {
- t.Errorf("32767 - 1 = %d, want 32766", r)
+ t.Errorf("32767 %s 1 = %d, want 32766", "-", r)
}
y = 32766
r = x - y
if r != 1 {
- t.Errorf("32767 - 32766 = %d, want 1", r)
+ t.Errorf("32767 %s 32766 = %d, want 1", "-", r)
}
y = 32767
r = x - y
if r != 0 {
- t.Errorf("32767 - 32767 = %d, want 0", r)
+ t.Errorf("32767 %s 32767 = %d, want 0", "-", r)
}
}
func TestConstFoldint16div(t *testing.T) {
@@ -4243,218 +4243,218 @@ func TestConstFoldint16div(t *testing.T) {
y = -32768
r = x / y
if r != 1 {
- t.Errorf("-32768 / -32768 = %d, want 1", r)
+ t.Errorf("-32768 %s -32768 = %d, want 1", "/", r)
}
y = -32767
r = x / y
if r != 1 {
- t.Errorf("-32768 / -32767 = %d, want 1", r)
+ t.Errorf("-32768 %s -32767 = %d, want 1", "/", r)
}
y = -1
r = x / y
if r != -32768 {
- t.Errorf("-32768 / -1 = %d, want -32768", r)
+ t.Errorf("-32768 %s -1 = %d, want -32768", "/", r)
}
y = 1
r = x / y
if r != -32768 {
- t.Errorf("-32768 / 1 = %d, want -32768", r)
+ t.Errorf("-32768 %s 1 = %d, want -32768", "/", r)
}
y = 32766
r = x / y
if r != -1 {
- t.Errorf("-32768 / 32766 = %d, want -1", r)
+ t.Errorf("-32768 %s 32766 = %d, want -1", "/", r)
}
y = 32767
r = x / y
if r != -1 {
- t.Errorf("-32768 / 32767 = %d, want -1", r)
+ t.Errorf("-32768 %s 32767 = %d, want -1", "/", r)
}
x = -32767
y = -32768
r = x / y
if r != 0 {
- t.Errorf("-32767 / -32768 = %d, want 0", r)
+ t.Errorf("-32767 %s -32768 = %d, want 0", "/", r)
}
y = -32767
r = x / y
if r != 1 {
- t.Errorf("-32767 / -32767 = %d, want 1", r)
+ t.Errorf("-32767 %s -32767 = %d, want 1", "/", r)
}
y = -1
r = x / y
if r != 32767 {
- t.Errorf("-32767 / -1 = %d, want 32767", r)
+ t.Errorf("-32767 %s -1 = %d, want 32767", "/", r)
}
y = 1
r = x / y
if r != -32767 {
- t.Errorf("-32767 / 1 = %d, want -32767", r)
+ t.Errorf("-32767 %s 1 = %d, want -32767", "/", r)
}
y = 32766
r = x / y
if r != -1 {
- t.Errorf("-32767 / 32766 = %d, want -1", r)
+ t.Errorf("-32767 %s 32766 = %d, want -1", "/", r)
}
y = 32767
r = x / y
if r != -1 {
- t.Errorf("-32767 / 32767 = %d, want -1", r)
+ t.Errorf("-32767 %s 32767 = %d, want -1", "/", r)
}
x = -1
y = -32768
r = x / y
if r != 0 {
- t.Errorf("-1 / -32768 = %d, want 0", r)
+ t.Errorf("-1 %s -32768 = %d, want 0", "/", r)
}
y = -32767
r = x / y
if r != 0 {
- t.Errorf("-1 / -32767 = %d, want 0", r)
+ t.Errorf("-1 %s -32767 = %d, want 0", "/", r)
}
y = -1
r = x / y
if r != 1 {
- t.Errorf("-1 / -1 = %d, want 1", r)
+ t.Errorf("-1 %s -1 = %d, want 1", "/", r)
}
y = 1
r = x / y
if r != -1 {
- t.Errorf("-1 / 1 = %d, want -1", r)
+ t.Errorf("-1 %s 1 = %d, want -1", "/", r)
}
y = 32766
r = x / y
if r != 0 {
- t.Errorf("-1 / 32766 = %d, want 0", r)
+ t.Errorf("-1 %s 32766 = %d, want 0", "/", r)
}
y = 32767
r = x / y
if r != 0 {
- t.Errorf("-1 / 32767 = %d, want 0", r)
+ t.Errorf("-1 %s 32767 = %d, want 0", "/", r)
}
x = 0
y = -32768
r = x / y
if r != 0 {
- t.Errorf("0 / -32768 = %d, want 0", r)
+ t.Errorf("0 %s -32768 = %d, want 0", "/", r)
}
y = -32767
r = x / y
if r != 0 {
- t.Errorf("0 / -32767 = %d, want 0", r)
+ t.Errorf("0 %s -32767 = %d, want 0", "/", r)
}
y = -1
r = x / y
if r != 0 {
- t.Errorf("0 / -1 = %d, want 0", r)
+ t.Errorf("0 %s -1 = %d, want 0", "/", r)
}
y = 1
r = x / y
if r != 0 {
- t.Errorf("0 / 1 = %d, want 0", r)
+ t.Errorf("0 %s 1 = %d, want 0", "/", r)
}
y = 32766
r = x / y
if r != 0 {
- t.Errorf("0 / 32766 = %d, want 0", r)
+ t.Errorf("0 %s 32766 = %d, want 0", "/", r)
}
y = 32767
r = x / y
if r != 0 {
- t.Errorf("0 / 32767 = %d, want 0", r)
+ t.Errorf("0 %s 32767 = %d, want 0", "/", r)
}
x = 1
y = -32768
r = x / y
if r != 0 {
- t.Errorf("1 / -32768 = %d, want 0", r)
+ t.Errorf("1 %s -32768 = %d, want 0", "/", r)
}
y = -32767
r = x / y
if r != 0 {
- t.Errorf("1 / -32767 = %d, want 0", r)
+ t.Errorf("1 %s -32767 = %d, want 0", "/", r)
}
y = -1
r = x / y
if r != -1 {
- t.Errorf("1 / -1 = %d, want -1", r)
+ t.Errorf("1 %s -1 = %d, want -1", "/", r)
}
y = 1
r = x / y
if r != 1 {
- t.Errorf("1 / 1 = %d, want 1", r)
+ t.Errorf("1 %s 1 = %d, want 1", "/", r)
}
y = 32766
r = x / y
if r != 0 {
- t.Errorf("1 / 32766 = %d, want 0", r)
+ t.Errorf("1 %s 32766 = %d, want 0", "/", r)
}
y = 32767
r = x / y
if r != 0 {
- t.Errorf("1 / 32767 = %d, want 0", r)
+ t.Errorf("1 %s 32767 = %d, want 0", "/", r)
}
x = 32766
y = -32768
r = x / y
if r != 0 {
- t.Errorf("32766 / -32768 = %d, want 0", r)
+ t.Errorf("32766 %s -32768 = %d, want 0", "/", r)
}
y = -32767
r = x / y
if r != 0 {
- t.Errorf("32766 / -32767 = %d, want 0", r)
+ t.Errorf("32766 %s -32767 = %d, want 0", "/", r)
}
y = -1
r = x / y
if r != -32766 {
- t.Errorf("32766 / -1 = %d, want -32766", r)
+ t.Errorf("32766 %s -1 = %d, want -32766", "/", r)
}
y = 1
r = x / y
if r != 32766 {
- t.Errorf("32766 / 1 = %d, want 32766", r)
+ t.Errorf("32766 %s 1 = %d, want 32766", "/", r)
}
y = 32766
r = x / y
if r != 1 {
- t.Errorf("32766 / 32766 = %d, want 1", r)
+ t.Errorf("32766 %s 32766 = %d, want 1", "/", r)
}
y = 32767
r = x / y
if r != 0 {
- t.Errorf("32766 / 32767 = %d, want 0", r)
+ t.Errorf("32766 %s 32767 = %d, want 0", "/", r)
}
x = 32767
y = -32768
r = x / y
if r != 0 {
- t.Errorf("32767 / -32768 = %d, want 0", r)
+ t.Errorf("32767 %s -32768 = %d, want 0", "/", r)
}
y = -32767
r = x / y
if r != -1 {
- t.Errorf("32767 / -32767 = %d, want -1", r)
+ t.Errorf("32767 %s -32767 = %d, want -1", "/", r)
}
y = -1
r = x / y
if r != -32767 {
- t.Errorf("32767 / -1 = %d, want -32767", r)
+ t.Errorf("32767 %s -1 = %d, want -32767", "/", r)
}
y = 1
r = x / y
if r != 32767 {
- t.Errorf("32767 / 1 = %d, want 32767", r)
+ t.Errorf("32767 %s 1 = %d, want 32767", "/", r)
}
y = 32766
r = x / y
if r != 1 {
- t.Errorf("32767 / 32766 = %d, want 1", r)
+ t.Errorf("32767 %s 32766 = %d, want 1", "/", r)
}
y = 32767
r = x / y
if r != 1 {
- t.Errorf("32767 / 32767 = %d, want 1", r)
+ t.Errorf("32767 %s 32767 = %d, want 1", "/", r)
}
}
func TestConstFoldint16mul(t *testing.T) {
@@ -4463,253 +4463,253 @@ func TestConstFoldint16mul(t *testing.T) {
y = -32768
r = x * y
if r != 0 {
- t.Errorf("-32768 * -32768 = %d, want 0", r)
+ t.Errorf("-32768 %s -32768 = %d, want 0", "*", r)
}
y = -32767
r = x * y
if r != -32768 {
- t.Errorf("-32768 * -32767 = %d, want -32768", r)
+ t.Errorf("-32768 %s -32767 = %d, want -32768", "*", r)
}
y = -1
r = x * y
if r != -32768 {
- t.Errorf("-32768 * -1 = %d, want -32768", r)
+ t.Errorf("-32768 %s -1 = %d, want -32768", "*", r)
}
y = 0
r = x * y
if r != 0 {
- t.Errorf("-32768 * 0 = %d, want 0", r)
+ t.Errorf("-32768 %s 0 = %d, want 0", "*", r)
}
y = 1
r = x * y
if r != -32768 {
- t.Errorf("-32768 * 1 = %d, want -32768", r)
+ t.Errorf("-32768 %s 1 = %d, want -32768", "*", r)
}
y = 32766
r = x * y
if r != 0 {
- t.Errorf("-32768 * 32766 = %d, want 0", r)
+ t.Errorf("-32768 %s 32766 = %d, want 0", "*", r)
}
y = 32767
r = x * y
if r != -32768 {
- t.Errorf("-32768 * 32767 = %d, want -32768", r)
+ t.Errorf("-32768 %s 32767 = %d, want -32768", "*", r)
}
x = -32767
y = -32768
r = x * y
if r != -32768 {
- t.Errorf("-32767 * -32768 = %d, want -32768", r)
+ t.Errorf("-32767 %s -32768 = %d, want -32768", "*", r)
}
y = -32767
r = x * y
if r != 1 {
- t.Errorf("-32767 * -32767 = %d, want 1", r)
+ t.Errorf("-32767 %s -32767 = %d, want 1", "*", r)
}
y = -1
r = x * y
if r != 32767 {
- t.Errorf("-32767 * -1 = %d, want 32767", r)
+ t.Errorf("-32767 %s -1 = %d, want 32767", "*", r)
}
y = 0
r = x * y
if r != 0 {
- t.Errorf("-32767 * 0 = %d, want 0", r)
+ t.Errorf("-32767 %s 0 = %d, want 0", "*", r)
}
y = 1
r = x * y
if r != -32767 {
- t.Errorf("-32767 * 1 = %d, want -32767", r)
+ t.Errorf("-32767 %s 1 = %d, want -32767", "*", r)
}
y = 32766
r = x * y
if r != 32766 {
- t.Errorf("-32767 * 32766 = %d, want 32766", r)
+ t.Errorf("-32767 %s 32766 = %d, want 32766", "*", r)
}
y = 32767
r = x * y
if r != -1 {
- t.Errorf("-32767 * 32767 = %d, want -1", r)
+ t.Errorf("-32767 %s 32767 = %d, want -1", "*", r)
}
x = -1
y = -32768
r = x * y
if r != -32768 {
- t.Errorf("-1 * -32768 = %d, want -32768", r)
+ t.Errorf("-1 %s -32768 = %d, want -32768", "*", r)
}
y = -32767
r = x * y
if r != 32767 {
- t.Errorf("-1 * -32767 = %d, want 32767", r)
+ t.Errorf("-1 %s -32767 = %d, want 32767", "*", r)
}
y = -1
r = x * y
if r != 1 {
- t.Errorf("-1 * -1 = %d, want 1", r)
+ t.Errorf("-1 %s -1 = %d, want 1", "*", r)
}
y = 0
r = x * y
if r != 0 {
- t.Errorf("-1 * 0 = %d, want 0", r)
+ t.Errorf("-1 %s 0 = %d, want 0", "*", r)
}
y = 1
r = x * y
if r != -1 {
- t.Errorf("-1 * 1 = %d, want -1", r)
+ t.Errorf("-1 %s 1 = %d, want -1", "*", r)
}
y = 32766
r = x * y
if r != -32766 {
- t.Errorf("-1 * 32766 = %d, want -32766", r)
+ t.Errorf("-1 %s 32766 = %d, want -32766", "*", r)
}
y = 32767
r = x * y
if r != -32767 {
- t.Errorf("-1 * 32767 = %d, want -32767", r)
+ t.Errorf("-1 %s 32767 = %d, want -32767", "*", r)
}
x = 0
y = -32768
r = x * y
if r != 0 {
- t.Errorf("0 * -32768 = %d, want 0", r)
+ t.Errorf("0 %s -32768 = %d, want 0", "*", r)
}
y = -32767
r = x * y
if r != 0 {
- t.Errorf("0 * -32767 = %d, want 0", r)
+ t.Errorf("0 %s -32767 = %d, want 0", "*", r)
}
y = -1
r = x * y
if r != 0 {
- t.Errorf("0 * -1 = %d, want 0", r)
+ t.Errorf("0 %s -1 = %d, want 0", "*", r)
}
y = 0
r = x * y
if r != 0 {
- t.Errorf("0 * 0 = %d, want 0", r)
+ t.Errorf("0 %s 0 = %d, want 0", "*", r)
}
y = 1
r = x * y
if r != 0 {
- t.Errorf("0 * 1 = %d, want 0", r)
+ t.Errorf("0 %s 1 = %d, want 0", "*", r)
}
y = 32766
r = x * y
if r != 0 {
- t.Errorf("0 * 32766 = %d, want 0", r)
+ t.Errorf("0 %s 32766 = %d, want 0", "*", r)
}
y = 32767
r = x * y
if r != 0 {
- t.Errorf("0 * 32767 = %d, want 0", r)
+ t.Errorf("0 %s 32767 = %d, want 0", "*", r)
}
x = 1
y = -32768
r = x * y
if r != -32768 {
- t.Errorf("1 * -32768 = %d, want -32768", r)
+ t.Errorf("1 %s -32768 = %d, want -32768", "*", r)
}
y = -32767
r = x * y
if r != -32767 {
- t.Errorf("1 * -32767 = %d, want -32767", r)
+ t.Errorf("1 %s -32767 = %d, want -32767", "*", r)
}
y = -1
r = x * y
if r != -1 {
- t.Errorf("1 * -1 = %d, want -1", r)
+ t.Errorf("1 %s -1 = %d, want -1", "*", r)
}
y = 0
r = x * y
if r != 0 {
- t.Errorf("1 * 0 = %d, want 0", r)
+ t.Errorf("1 %s 0 = %d, want 0", "*", r)
}
y = 1
r = x * y
if r != 1 {
- t.Errorf("1 * 1 = %d, want 1", r)
+ t.Errorf("1 %s 1 = %d, want 1", "*", r)
}
y = 32766
r = x * y
if r != 32766 {
- t.Errorf("1 * 32766 = %d, want 32766", r)
+ t.Errorf("1 %s 32766 = %d, want 32766", "*", r)
}
y = 32767
r = x * y
if r != 32767 {
- t.Errorf("1 * 32767 = %d, want 32767", r)
+ t.Errorf("1 %s 32767 = %d, want 32767", "*", r)
}
x = 32766
y = -32768
r = x * y
if r != 0 {
- t.Errorf("32766 * -32768 = %d, want 0", r)
+ t.Errorf("32766 %s -32768 = %d, want 0", "*", r)
}
y = -32767
r = x * y
if r != 32766 {
- t.Errorf("32766 * -32767 = %d, want 32766", r)
+ t.Errorf("32766 %s -32767 = %d, want 32766", "*", r)
}
y = -1
r = x * y
if r != -32766 {
- t.Errorf("32766 * -1 = %d, want -32766", r)
+ t.Errorf("32766 %s -1 = %d, want -32766", "*", r)
}
y = 0
r = x * y
if r != 0 {
- t.Errorf("32766 * 0 = %d, want 0", r)
+ t.Errorf("32766 %s 0 = %d, want 0", "*", r)
}
y = 1
r = x * y
if r != 32766 {
- t.Errorf("32766 * 1 = %d, want 32766", r)
+ t.Errorf("32766 %s 1 = %d, want 32766", "*", r)
}
y = 32766
r = x * y
if r != 4 {
- t.Errorf("32766 * 32766 = %d, want 4", r)
+ t.Errorf("32766 %s 32766 = %d, want 4", "*", r)
}
y = 32767
r = x * y
if r != -32766 {
- t.Errorf("32766 * 32767 = %d, want -32766", r)
+ t.Errorf("32766 %s 32767 = %d, want -32766", "*", r)
}
x = 32767
y = -32768
r = x * y
if r != -32768 {
- t.Errorf("32767 * -32768 = %d, want -32768", r)
+ t.Errorf("32767 %s -32768 = %d, want -32768", "*", r)
}
y = -32767
r = x * y
if r != -1 {
- t.Errorf("32767 * -32767 = %d, want -1", r)
+ t.Errorf("32767 %s -32767 = %d, want -1", "*", r)
}
y = -1
r = x * y
if r != -32767 {
- t.Errorf("32767 * -1 = %d, want -32767", r)
+ t.Errorf("32767 %s -1 = %d, want -32767", "*", r)
}
y = 0
r = x * y
if r != 0 {
- t.Errorf("32767 * 0 = %d, want 0", r)
+ t.Errorf("32767 %s 0 = %d, want 0", "*", r)
}
y = 1
r = x * y
if r != 32767 {
- t.Errorf("32767 * 1 = %d, want 32767", r)
+ t.Errorf("32767 %s 1 = %d, want 32767", "*", r)
}
y = 32766
r = x * y
if r != -32766 {
- t.Errorf("32767 * 32766 = %d, want -32766", r)
+ t.Errorf("32767 %s 32766 = %d, want -32766", "*", r)
}
y = 32767
r = x * y
if r != 1 {
- t.Errorf("32767 * 32767 = %d, want 1", r)
+ t.Errorf("32767 %s 32767 = %d, want 1", "*", r)
}
}
func TestConstFoldint16mod(t *testing.T) {
@@ -4718,218 +4718,218 @@ func TestConstFoldint16mod(t *testing.T) {
y = -32768
r = x % y
if r != 0 {
- t.Errorf("-32768 % -32768 = %d, want 0", r)
+ t.Errorf("-32768 %s -32768 = %d, want 0", "%", r)
}
y = -32767
r = x % y
if r != -1 {
- t.Errorf("-32768 % -32767 = %d, want -1", r)
+ t.Errorf("-32768 %s -32767 = %d, want -1", "%", r)
}
y = -1
r = x % y
if r != 0 {
- t.Errorf("-32768 % -1 = %d, want 0", r)
+ t.Errorf("-32768 %s -1 = %d, want 0", "%", r)
}
y = 1
r = x % y
if r != 0 {
- t.Errorf("-32768 % 1 = %d, want 0", r)
+ t.Errorf("-32768 %s 1 = %d, want 0", "%", r)
}
y = 32766
r = x % y
if r != -2 {
- t.Errorf("-32768 % 32766 = %d, want -2", r)
+ t.Errorf("-32768 %s 32766 = %d, want -2", "%", r)
}
y = 32767
r = x % y
if r != -1 {
- t.Errorf("-32768 % 32767 = %d, want -1", r)
+ t.Errorf("-32768 %s 32767 = %d, want -1", "%", r)
}
x = -32767
y = -32768
r = x % y
if r != -32767 {
- t.Errorf("-32767 % -32768 = %d, want -32767", r)
+ t.Errorf("-32767 %s -32768 = %d, want -32767", "%", r)
}
y = -32767
r = x % y
if r != 0 {
- t.Errorf("-32767 % -32767 = %d, want 0", r)
+ t.Errorf("-32767 %s -32767 = %d, want 0", "%", r)
}
y = -1
r = x % y
if r != 0 {
- t.Errorf("-32767 % -1 = %d, want 0", r)
+ t.Errorf("-32767 %s -1 = %d, want 0", "%", r)
}
y = 1
r = x % y
if r != 0 {
- t.Errorf("-32767 % 1 = %d, want 0", r)
+ t.Errorf("-32767 %s 1 = %d, want 0", "%", r)
}
y = 32766
r = x % y
if r != -1 {
- t.Errorf("-32767 % 32766 = %d, want -1", r)
+ t.Errorf("-32767 %s 32766 = %d, want -1", "%", r)
}
y = 32767
r = x % y
if r != 0 {
- t.Errorf("-32767 % 32767 = %d, want 0", r)
+ t.Errorf("-32767 %s 32767 = %d, want 0", "%", r)
}
x = -1
y = -32768
r = x % y
if r != -1 {
- t.Errorf("-1 % -32768 = %d, want -1", r)
+ t.Errorf("-1 %s -32768 = %d, want -1", "%", r)
}
y = -32767
r = x % y
if r != -1 {
- t.Errorf("-1 % -32767 = %d, want -1", r)
+ t.Errorf("-1 %s -32767 = %d, want -1", "%", r)
}
y = -1
r = x % y
if r != 0 {
- t.Errorf("-1 % -1 = %d, want 0", r)
+ t.Errorf("-1 %s -1 = %d, want 0", "%", r)
}
y = 1
r = x % y
if r != 0 {
- t.Errorf("-1 % 1 = %d, want 0", r)
+ t.Errorf("-1 %s 1 = %d, want 0", "%", r)
}
y = 32766
r = x % y
if r != -1 {
- t.Errorf("-1 % 32766 = %d, want -1", r)
+ t.Errorf("-1 %s 32766 = %d, want -1", "%", r)
}
y = 32767
r = x % y
if r != -1 {
- t.Errorf("-1 % 32767 = %d, want -1", r)
+ t.Errorf("-1 %s 32767 = %d, want -1", "%", r)
}
x = 0
y = -32768
r = x % y
if r != 0 {
- t.Errorf("0 % -32768 = %d, want 0", r)
+ t.Errorf("0 %s -32768 = %d, want 0", "%", r)
}
y = -32767
r = x % y
if r != 0 {
- t.Errorf("0 % -32767 = %d, want 0", r)
+ t.Errorf("0 %s -32767 = %d, want 0", "%", r)
}
y = -1
r = x % y
if r != 0 {
- t.Errorf("0 % -1 = %d, want 0", r)
+ t.Errorf("0 %s -1 = %d, want 0", "%", r)
}
y = 1
r = x % y
if r != 0 {
- t.Errorf("0 % 1 = %d, want 0", r)
+ t.Errorf("0 %s 1 = %d, want 0", "%", r)
}
y = 32766
r = x % y
if r != 0 {
- t.Errorf("0 % 32766 = %d, want 0", r)
+ t.Errorf("0 %s 32766 = %d, want 0", "%", r)
}
y = 32767
r = x % y
if r != 0 {
- t.Errorf("0 % 32767 = %d, want 0", r)
+ t.Errorf("0 %s 32767 = %d, want 0", "%", r)
}
x = 1
y = -32768
r = x % y
if r != 1 {
- t.Errorf("1 % -32768 = %d, want 1", r)
+ t.Errorf("1 %s -32768 = %d, want 1", "%", r)
}
y = -32767
r = x % y
if r != 1 {
- t.Errorf("1 % -32767 = %d, want 1", r)
+ t.Errorf("1 %s -32767 = %d, want 1", "%", r)
}
y = -1
r = x % y
if r != 0 {
- t.Errorf("1 % -1 = %d, want 0", r)
+ t.Errorf("1 %s -1 = %d, want 0", "%", r)
}
y = 1
r = x % y
if r != 0 {
- t.Errorf("1 % 1 = %d, want 0", r)
+ t.Errorf("1 %s 1 = %d, want 0", "%", r)
}
y = 32766
r = x % y
if r != 1 {
- t.Errorf("1 % 32766 = %d, want 1", r)
+ t.Errorf("1 %s 32766 = %d, want 1", "%", r)
}
y = 32767
r = x % y
if r != 1 {
- t.Errorf("1 % 32767 = %d, want 1", r)
+ t.Errorf("1 %s 32767 = %d, want 1", "%", r)
}
x = 32766
y = -32768
r = x % y
if r != 32766 {
- t.Errorf("32766 % -32768 = %d, want 32766", r)
+ t.Errorf("32766 %s -32768 = %d, want 32766", "%", r)
}
y = -32767
r = x % y
if r != 32766 {
- t.Errorf("32766 % -32767 = %d, want 32766", r)
+ t.Errorf("32766 %s -32767 = %d, want 32766", "%", r)
}
y = -1
r = x % y
if r != 0 {
- t.Errorf("32766 % -1 = %d, want 0", r)
+ t.Errorf("32766 %s -1 = %d, want 0", "%", r)
}
y = 1
r = x % y
if r != 0 {
- t.Errorf("32766 % 1 = %d, want 0", r)
+ t.Errorf("32766 %s 1 = %d, want 0", "%", r)
}
y = 32766
r = x % y
if r != 0 {
- t.Errorf("32766 % 32766 = %d, want 0", r)
+ t.Errorf("32766 %s 32766 = %d, want 0", "%", r)
}
y = 32767
r = x % y
if r != 32766 {
- t.Errorf("32766 % 32767 = %d, want 32766", r)
+ t.Errorf("32766 %s 32767 = %d, want 32766", "%", r)
}
x = 32767
y = -32768
r = x % y
if r != 32767 {
- t.Errorf("32767 % -32768 = %d, want 32767", r)
+ t.Errorf("32767 %s -32768 = %d, want 32767", "%", r)
}
y = -32767
r = x % y
if r != 0 {
- t.Errorf("32767 % -32767 = %d, want 0", r)
+ t.Errorf("32767 %s -32767 = %d, want 0", "%", r)
}
y = -1
r = x % y
if r != 0 {
- t.Errorf("32767 % -1 = %d, want 0", r)
+ t.Errorf("32767 %s -1 = %d, want 0", "%", r)
}
y = 1
r = x % y
if r != 0 {
- t.Errorf("32767 % 1 = %d, want 0", r)
+ t.Errorf("32767 %s 1 = %d, want 0", "%", r)
}
y = 32766
r = x % y
if r != 1 {
- t.Errorf("32767 % 32766 = %d, want 1", r)
+ t.Errorf("32767 %s 32766 = %d, want 1", "%", r)
}
y = 32767
r = x % y
if r != 0 {
- t.Errorf("32767 % 32767 = %d, want 0", r)
+ t.Errorf("32767 %s 32767 = %d, want 0", "%", r)
}
}
func TestConstFolduint8add(t *testing.T) {
@@ -4938,49 +4938,49 @@ func TestConstFolduint8add(t *testing.T) {
y = 0
r = x + y
if r != 0 {
- t.Errorf("0 + 0 = %d, want 0", r)
+ t.Errorf("0 %s 0 = %d, want 0", "+", r)
}
y = 1
r = x + y
if r != 1 {
- t.Errorf("0 + 1 = %d, want 1", r)
+ t.Errorf("0 %s 1 = %d, want 1", "+", r)
}
y = 255
r = x + y
if r != 255 {
- t.Errorf("0 + 255 = %d, want 255", r)
+ t.Errorf("0 %s 255 = %d, want 255", "+", r)
}
x = 1
y = 0
r = x + y
if r != 1 {
- t.Errorf("1 + 0 = %d, want 1", r)
+ t.Errorf("1 %s 0 = %d, want 1", "+", r)
}
y = 1
r = x + y
if r != 2 {
- t.Errorf("1 + 1 = %d, want 2", r)
+ t.Errorf("1 %s 1 = %d, want 2", "+", r)
}
y = 255
r = x + y
if r != 0 {
- t.Errorf("1 + 255 = %d, want 0", r)
+ t.Errorf("1 %s 255 = %d, want 0", "+", r)
}
x = 255
y = 0
r = x + y
if r != 255 {
- t.Errorf("255 + 0 = %d, want 255", r)
+ t.Errorf("255 %s 0 = %d, want 255", "+", r)
}
y = 1
r = x + y
if r != 0 {
- t.Errorf("255 + 1 = %d, want 0", r)
+ t.Errorf("255 %s 1 = %d, want 0", "+", r)
}
y = 255
r = x + y
if r != 254 {
- t.Errorf("255 + 255 = %d, want 254", r)
+ t.Errorf("255 %s 255 = %d, want 254", "+", r)
}
}
func TestConstFolduint8sub(t *testing.T) {
@@ -4989,49 +4989,49 @@ func TestConstFolduint8sub(t *testing.T) {
y = 0
r = x - y
if r != 0 {
- t.Errorf("0 - 0 = %d, want 0", r)
+ t.Errorf("0 %s 0 = %d, want 0", "-", r)
}
y = 1
r = x - y
if r != 255 {
- t.Errorf("0 - 1 = %d, want 255", r)
+ t.Errorf("0 %s 1 = %d, want 255", "-", r)
}
y = 255
r = x - y
if r != 1 {
- t.Errorf("0 - 255 = %d, want 1", r)
+ t.Errorf("0 %s 255 = %d, want 1", "-", r)
}
x = 1
y = 0
r = x - y
if r != 1 {
- t.Errorf("1 - 0 = %d, want 1", r)
+ t.Errorf("1 %s 0 = %d, want 1", "-", r)
}
y = 1
r = x - y
if r != 0 {
- t.Errorf("1 - 1 = %d, want 0", r)
+ t.Errorf("1 %s 1 = %d, want 0", "-", r)
}
y = 255
r = x - y
if r != 2 {
- t.Errorf("1 - 255 = %d, want 2", r)
+ t.Errorf("1 %s 255 = %d, want 2", "-", r)
}
x = 255
y = 0
r = x - y
if r != 255 {
- t.Errorf("255 - 0 = %d, want 255", r)
+ t.Errorf("255 %s 0 = %d, want 255", "-", r)
}
y = 1
r = x - y
if r != 254 {
- t.Errorf("255 - 1 = %d, want 254", r)
+ t.Errorf("255 %s 1 = %d, want 254", "-", r)
}
y = 255
r = x - y
if r != 0 {
- t.Errorf("255 - 255 = %d, want 0", r)
+ t.Errorf("255 %s 255 = %d, want 0", "-", r)
}
}
func TestConstFolduint8div(t *testing.T) {
@@ -5040,34 +5040,34 @@ func TestConstFolduint8div(t *testing.T) {
y = 1
r = x / y
if r != 0 {
- t.Errorf("0 / 1 = %d, want 0", r)
+ t.Errorf("0 %s 1 = %d, want 0", "/", r)
}
y = 255
r = x / y
if r != 0 {
- t.Errorf("0 / 255 = %d, want 0", r)
+ t.Errorf("0 %s 255 = %d, want 0", "/", r)
}
x = 1
y = 1
r = x / y
if r != 1 {
- t.Errorf("1 / 1 = %d, want 1", r)
+ t.Errorf("1 %s 1 = %d, want 1", "/", r)
}
y = 255
r = x / y
if r != 0 {
- t.Errorf("1 / 255 = %d, want 0", r)
+ t.Errorf("1 %s 255 = %d, want 0", "/", r)
}
x = 255
y = 1
r = x / y
if r != 255 {
- t.Errorf("255 / 1 = %d, want 255", r)
+ t.Errorf("255 %s 1 = %d, want 255", "/", r)
}
y = 255
r = x / y
if r != 1 {
- t.Errorf("255 / 255 = %d, want 1", r)
+ t.Errorf("255 %s 255 = %d, want 1", "/", r)
}
}
func TestConstFolduint8mul(t *testing.T) {
@@ -5076,49 +5076,49 @@ func TestConstFolduint8mul(t *testing.T) {
y = 0
r = x * y
if r != 0 {
- t.Errorf("0 * 0 = %d, want 0", r)
+ t.Errorf("0 %s 0 = %d, want 0", "*", r)
}
y = 1
r = x * y
if r != 0 {
- t.Errorf("0 * 1 = %d, want 0", r)
+ t.Errorf("0 %s 1 = %d, want 0", "*", r)
}
y = 255
r = x * y
if r != 0 {
- t.Errorf("0 * 255 = %d, want 0", r)
+ t.Errorf("0 %s 255 = %d, want 0", "*", r)
}
x = 1
y = 0
r = x * y
if r != 0 {
- t.Errorf("1 * 0 = %d, want 0", r)
+ t.Errorf("1 %s 0 = %d, want 0", "*", r)
}
y = 1
r = x * y
if r != 1 {
- t.Errorf("1 * 1 = %d, want 1", r)
+ t.Errorf("1 %s 1 = %d, want 1", "*", r)
}
y = 255
r = x * y
if r != 255 {
- t.Errorf("1 * 255 = %d, want 255", r)
+ t.Errorf("1 %s 255 = %d, want 255", "*", r)
}
x = 255
y = 0
r = x * y
if r != 0 {
- t.Errorf("255 * 0 = %d, want 0", r)
+ t.Errorf("255 %s 0 = %d, want 0", "*", r)
}
y = 1
r = x * y
if r != 255 {
- t.Errorf("255 * 1 = %d, want 255", r)
+ t.Errorf("255 %s 1 = %d, want 255", "*", r)
}
y = 255
r = x * y
if r != 1 {
- t.Errorf("255 * 255 = %d, want 1", r)
+ t.Errorf("255 %s 255 = %d, want 1", "*", r)
}
}
func TestConstFolduint8mod(t *testing.T) {
@@ -5127,34 +5127,34 @@ func TestConstFolduint8mod(t *testing.T) {
y = 1
r = x % y
if r != 0 {
- t.Errorf("0 % 1 = %d, want 0", r)
+ t.Errorf("0 %s 1 = %d, want 0", "%", r)
}
y = 255
r = x % y
if r != 0 {
- t.Errorf("0 % 255 = %d, want 0", r)
+ t.Errorf("0 %s 255 = %d, want 0", "%", r)
}
x = 1
y = 1
r = x % y
if r != 0 {
- t.Errorf("1 % 1 = %d, want 0", r)
+ t.Errorf("1 %s 1 = %d, want 0", "%", r)
}
y = 255
r = x % y
if r != 1 {
- t.Errorf("1 % 255 = %d, want 1", r)
+ t.Errorf("1 %s 255 = %d, want 1", "%", r)
}
x = 255
y = 1
r = x % y
if r != 0 {
- t.Errorf("255 % 1 = %d, want 0", r)
+ t.Errorf("255 %s 1 = %d, want 0", "%", r)
}
y = 255
r = x % y
if r != 0 {
- t.Errorf("255 % 255 = %d, want 0", r)
+ t.Errorf("255 %s 255 = %d, want 0", "%", r)
}
}
func TestConstFoldint8add(t *testing.T) {
@@ -5163,253 +5163,253 @@ func TestConstFoldint8add(t *testing.T) {
y = -128
r = x + y
if r != 0 {
- t.Errorf("-128 + -128 = %d, want 0", r)
+ t.Errorf("-128 %s -128 = %d, want 0", "+", r)
}
y = -127
r = x + y
if r != 1 {
- t.Errorf("-128 + -127 = %d, want 1", r)
+ t.Errorf("-128 %s -127 = %d, want 1", "+", r)
}
y = -1
r = x + y
if r != 127 {
- t.Errorf("-128 + -1 = %d, want 127", r)
+ t.Errorf("-128 %s -1 = %d, want 127", "+", r)
}
y = 0
r = x + y
if r != -128 {
- t.Errorf("-128 + 0 = %d, want -128", r)
+ t.Errorf("-128 %s 0 = %d, want -128", "+", r)
}
y = 1
r = x + y
if r != -127 {
- t.Errorf("-128 + 1 = %d, want -127", r)
+ t.Errorf("-128 %s 1 = %d, want -127", "+", r)
}
y = 126
r = x + y
if r != -2 {
- t.Errorf("-128 + 126 = %d, want -2", r)
+ t.Errorf("-128 %s 126 = %d, want -2", "+", r)
}
y = 127
r = x + y
if r != -1 {
- t.Errorf("-128 + 127 = %d, want -1", r)
+ t.Errorf("-128 %s 127 = %d, want -1", "+", r)
}
x = -127
y = -128
r = x + y
if r != 1 {
- t.Errorf("-127 + -128 = %d, want 1", r)
+ t.Errorf("-127 %s -128 = %d, want 1", "+", r)
}
y = -127
r = x + y
if r != 2 {
- t.Errorf("-127 + -127 = %d, want 2", r)
+ t.Errorf("-127 %s -127 = %d, want 2", "+", r)
}
y = -1
r = x + y
if r != -128 {
- t.Errorf("-127 + -1 = %d, want -128", r)
+ t.Errorf("-127 %s -1 = %d, want -128", "+", r)
}
y = 0
r = x + y
if r != -127 {
- t.Errorf("-127 + 0 = %d, want -127", r)
+ t.Errorf("-127 %s 0 = %d, want -127", "+", r)
}
y = 1
r = x + y
if r != -126 {
- t.Errorf("-127 + 1 = %d, want -126", r)
+ t.Errorf("-127 %s 1 = %d, want -126", "+", r)
}
y = 126
r = x + y
if r != -1 {
- t.Errorf("-127 + 126 = %d, want -1", r)
+ t.Errorf("-127 %s 126 = %d, want -1", "+", r)
}
y = 127
r = x + y
if r != 0 {
- t.Errorf("-127 + 127 = %d, want 0", r)
+ t.Errorf("-127 %s 127 = %d, want 0", "+", r)
}
x = -1
y = -128
r = x + y
if r != 127 {
- t.Errorf("-1 + -128 = %d, want 127", r)
+ t.Errorf("-1 %s -128 = %d, want 127", "+", r)
}
y = -127
r = x + y
if r != -128 {
- t.Errorf("-1 + -127 = %d, want -128", r)
+ t.Errorf("-1 %s -127 = %d, want -128", "+", r)
}
y = -1
r = x + y
if r != -2 {
- t.Errorf("-1 + -1 = %d, want -2", r)
+ t.Errorf("-1 %s -1 = %d, want -2", "+", r)
}
y = 0
r = x + y
if r != -1 {
- t.Errorf("-1 + 0 = %d, want -1", r)
+ t.Errorf("-1 %s 0 = %d, want -1", "+", r)
}
y = 1
r = x + y
if r != 0 {
- t.Errorf("-1 + 1 = %d, want 0", r)
+ t.Errorf("-1 %s 1 = %d, want 0", "+", r)
}
y = 126
r = x + y
if r != 125 {
- t.Errorf("-1 + 126 = %d, want 125", r)
+ t.Errorf("-1 %s 126 = %d, want 125", "+", r)
}
y = 127
r = x + y
if r != 126 {
- t.Errorf("-1 + 127 = %d, want 126", r)
+ t.Errorf("-1 %s 127 = %d, want 126", "+", r)
}
x = 0
y = -128
r = x + y
if r != -128 {
- t.Errorf("0 + -128 = %d, want -128", r)
+ t.Errorf("0 %s -128 = %d, want -128", "+", r)
}
y = -127
r = x + y
if r != -127 {
- t.Errorf("0 + -127 = %d, want -127", r)
+ t.Errorf("0 %s -127 = %d, want -127", "+", r)
}
y = -1
r = x + y
if r != -1 {
- t.Errorf("0 + -1 = %d, want -1", r)
+ t.Errorf("0 %s -1 = %d, want -1", "+", r)
}
y = 0
r = x + y
if r != 0 {
- t.Errorf("0 + 0 = %d, want 0", r)
+ t.Errorf("0 %s 0 = %d, want 0", "+", r)
}
y = 1
r = x + y
if r != 1 {
- t.Errorf("0 + 1 = %d, want 1", r)
+ t.Errorf("0 %s 1 = %d, want 1", "+", r)
}
y = 126
r = x + y
if r != 126 {
- t.Errorf("0 + 126 = %d, want 126", r)
+ t.Errorf("0 %s 126 = %d, want 126", "+", r)
}
y = 127
r = x + y
if r != 127 {
- t.Errorf("0 + 127 = %d, want 127", r)
+ t.Errorf("0 %s 127 = %d, want 127", "+", r)
}
x = 1
y = -128
r = x + y
if r != -127 {
- t.Errorf("1 + -128 = %d, want -127", r)
+ t.Errorf("1 %s -128 = %d, want -127", "+", r)
}
y = -127
r = x + y
if r != -126 {
- t.Errorf("1 + -127 = %d, want -126", r)
+ t.Errorf("1 %s -127 = %d, want -126", "+", r)
}
y = -1
r = x + y
if r != 0 {
- t.Errorf("1 + -1 = %d, want 0", r)
+ t.Errorf("1 %s -1 = %d, want 0", "+", r)
}
y = 0
r = x + y
if r != 1 {
- t.Errorf("1 + 0 = %d, want 1", r)
+ t.Errorf("1 %s 0 = %d, want 1", "+", r)
}
y = 1
r = x + y
if r != 2 {
- t.Errorf("1 + 1 = %d, want 2", r)
+ t.Errorf("1 %s 1 = %d, want 2", "+", r)
}
y = 126
r = x + y
if r != 127 {
- t.Errorf("1 + 126 = %d, want 127", r)
+ t.Errorf("1 %s 126 = %d, want 127", "+", r)
}
y = 127
r = x + y
if r != -128 {
- t.Errorf("1 + 127 = %d, want -128", r)
+ t.Errorf("1 %s 127 = %d, want -128", "+", r)
}
x = 126
y = -128
r = x + y
if r != -2 {
- t.Errorf("126 + -128 = %d, want -2", r)
+ t.Errorf("126 %s -128 = %d, want -2", "+", r)
}
y = -127
r = x + y
if r != -1 {
- t.Errorf("126 + -127 = %d, want -1", r)
+ t.Errorf("126 %s -127 = %d, want -1", "+", r)
}
y = -1
r = x + y
if r != 125 {
- t.Errorf("126 + -1 = %d, want 125", r)
+ t.Errorf("126 %s -1 = %d, want 125", "+", r)
}
y = 0
r = x + y
if r != 126 {
- t.Errorf("126 + 0 = %d, want 126", r)
+ t.Errorf("126 %s 0 = %d, want 126", "+", r)
}
y = 1
r = x + y
if r != 127 {
- t.Errorf("126 + 1 = %d, want 127", r)
+ t.Errorf("126 %s 1 = %d, want 127", "+", r)
}
y = 126
r = x + y
if r != -4 {
- t.Errorf("126 + 126 = %d, want -4", r)
+ t.Errorf("126 %s 126 = %d, want -4", "+", r)
}
y = 127
r = x + y
if r != -3 {
- t.Errorf("126 + 127 = %d, want -3", r)
+ t.Errorf("126 %s 127 = %d, want -3", "+", r)
}
x = 127
y = -128
r = x + y
if r != -1 {
- t.Errorf("127 + -128 = %d, want -1", r)
+ t.Errorf("127 %s -128 = %d, want -1", "+", r)
}
y = -127
r = x + y
if r != 0 {
- t.Errorf("127 + -127 = %d, want 0", r)
+ t.Errorf("127 %s -127 = %d, want 0", "+", r)
}
y = -1
r = x + y
if r != 126 {
- t.Errorf("127 + -1 = %d, want 126", r)
+ t.Errorf("127 %s -1 = %d, want 126", "+", r)
}
y = 0
r = x + y
if r != 127 {
- t.Errorf("127 + 0 = %d, want 127", r)
+ t.Errorf("127 %s 0 = %d, want 127", "+", r)
}
y = 1
r = x + y
if r != -128 {
- t.Errorf("127 + 1 = %d, want -128", r)
+ t.Errorf("127 %s 1 = %d, want -128", "+", r)
}
y = 126
r = x + y
if r != -3 {
- t.Errorf("127 + 126 = %d, want -3", r)
+ t.Errorf("127 %s 126 = %d, want -3", "+", r)
}
y = 127
r = x + y
if r != -2 {
- t.Errorf("127 + 127 = %d, want -2", r)
+ t.Errorf("127 %s 127 = %d, want -2", "+", r)
}
}
func TestConstFoldint8sub(t *testing.T) {
@@ -5418,253 +5418,253 @@ func TestConstFoldint8sub(t *testing.T) {
y = -128
r = x - y
if r != 0 {
- t.Errorf("-128 - -128 = %d, want 0", r)
+ t.Errorf("-128 %s -128 = %d, want 0", "-", r)
}
y = -127
r = x - y
if r != -1 {
- t.Errorf("-128 - -127 = %d, want -1", r)
+ t.Errorf("-128 %s -127 = %d, want -1", "-", r)
}
y = -1
r = x - y
if r != -127 {
- t.Errorf("-128 - -1 = %d, want -127", r)
+ t.Errorf("-128 %s -1 = %d, want -127", "-", r)
}
y = 0
r = x - y
if r != -128 {
- t.Errorf("-128 - 0 = %d, want -128", r)
+ t.Errorf("-128 %s 0 = %d, want -128", "-", r)
}
y = 1
r = x - y
if r != 127 {
- t.Errorf("-128 - 1 = %d, want 127", r)
+ t.Errorf("-128 %s 1 = %d, want 127", "-", r)
}
y = 126
r = x - y
if r != 2 {
- t.Errorf("-128 - 126 = %d, want 2", r)
+ t.Errorf("-128 %s 126 = %d, want 2", "-", r)
}
y = 127
r = x - y
if r != 1 {
- t.Errorf("-128 - 127 = %d, want 1", r)
+ t.Errorf("-128 %s 127 = %d, want 1", "-", r)
}
x = -127
y = -128
r = x - y
if r != 1 {
- t.Errorf("-127 - -128 = %d, want 1", r)
+ t.Errorf("-127 %s -128 = %d, want 1", "-", r)
}
y = -127
r = x - y
if r != 0 {
- t.Errorf("-127 - -127 = %d, want 0", r)
+ t.Errorf("-127 %s -127 = %d, want 0", "-", r)
}
y = -1
r = x - y
if r != -126 {
- t.Errorf("-127 - -1 = %d, want -126", r)
+ t.Errorf("-127 %s -1 = %d, want -126", "-", r)
}
y = 0
r = x - y
if r != -127 {
- t.Errorf("-127 - 0 = %d, want -127", r)
+ t.Errorf("-127 %s 0 = %d, want -127", "-", r)
}
y = 1
r = x - y
if r != -128 {
- t.Errorf("-127 - 1 = %d, want -128", r)
+ t.Errorf("-127 %s 1 = %d, want -128", "-", r)
}
y = 126
r = x - y
if r != 3 {
- t.Errorf("-127 - 126 = %d, want 3", r)
+ t.Errorf("-127 %s 126 = %d, want 3", "-", r)
}
y = 127
r = x - y
if r != 2 {
- t.Errorf("-127 - 127 = %d, want 2", r)
+ t.Errorf("-127 %s 127 = %d, want 2", "-", r)
}
x = -1
y = -128
r = x - y
if r != 127 {
- t.Errorf("-1 - -128 = %d, want 127", r)
+ t.Errorf("-1 %s -128 = %d, want 127", "-", r)
}
y = -127
r = x - y
if r != 126 {
- t.Errorf("-1 - -127 = %d, want 126", r)
+ t.Errorf("-1 %s -127 = %d, want 126", "-", r)
}
y = -1
r = x - y
if r != 0 {
- t.Errorf("-1 - -1 = %d, want 0", r)
+ t.Errorf("-1 %s -1 = %d, want 0", "-", r)
}
y = 0
r = x - y
if r != -1 {
- t.Errorf("-1 - 0 = %d, want -1", r)
+ t.Errorf("-1 %s 0 = %d, want -1", "-", r)
}
y = 1
r = x - y
if r != -2 {
- t.Errorf("-1 - 1 = %d, want -2", r)
+ t.Errorf("-1 %s 1 = %d, want -2", "-", r)
}
y = 126
r = x - y
if r != -127 {
- t.Errorf("-1 - 126 = %d, want -127", r)
+ t.Errorf("-1 %s 126 = %d, want -127", "-", r)
}
y = 127
r = x - y
if r != -128 {
- t.Errorf("-1 - 127 = %d, want -128", r)
+ t.Errorf("-1 %s 127 = %d, want -128", "-", r)
}
x = 0
y = -128
r = x - y
if r != -128 {
- t.Errorf("0 - -128 = %d, want -128", r)
+ t.Errorf("0 %s -128 = %d, want -128", "-", r)
}
y = -127
r = x - y
if r != 127 {
- t.Errorf("0 - -127 = %d, want 127", r)
+ t.Errorf("0 %s -127 = %d, want 127", "-", r)
}
y = -1
r = x - y
if r != 1 {
- t.Errorf("0 - -1 = %d, want 1", r)
+ t.Errorf("0 %s -1 = %d, want 1", "-", r)
}
y = 0
r = x - y
if r != 0 {
- t.Errorf("0 - 0 = %d, want 0", r)
+ t.Errorf("0 %s 0 = %d, want 0", "-", r)
}
y = 1
r = x - y
if r != -1 {
- t.Errorf("0 - 1 = %d, want -1", r)
+ t.Errorf("0 %s 1 = %d, want -1", "-", r)
}
y = 126
r = x - y
if r != -126 {
- t.Errorf("0 - 126 = %d, want -126", r)
+ t.Errorf("0 %s 126 = %d, want -126", "-", r)
}
y = 127
r = x - y
if r != -127 {
- t.Errorf("0 - 127 = %d, want -127", r)
+ t.Errorf("0 %s 127 = %d, want -127", "-", r)
}
x = 1
y = -128
r = x - y
if r != -127 {
- t.Errorf("1 - -128 = %d, want -127", r)
+ t.Errorf("1 %s -128 = %d, want -127", "-", r)
}
y = -127
r = x - y
if r != -128 {
- t.Errorf("1 - -127 = %d, want -128", r)
+ t.Errorf("1 %s -127 = %d, want -128", "-", r)
}
y = -1
r = x - y
if r != 2 {
- t.Errorf("1 - -1 = %d, want 2", r)
+ t.Errorf("1 %s -1 = %d, want 2", "-", r)
}
y = 0
r = x - y
if r != 1 {
- t.Errorf("1 - 0 = %d, want 1", r)
+ t.Errorf("1 %s 0 = %d, want 1", "-", r)
}
y = 1
r = x - y
if r != 0 {
- t.Errorf("1 - 1 = %d, want 0", r)
+ t.Errorf("1 %s 1 = %d, want 0", "-", r)
}
y = 126
r = x - y
if r != -125 {
- t.Errorf("1 - 126 = %d, want -125", r)
+ t.Errorf("1 %s 126 = %d, want -125", "-", r)
}
y = 127
r = x - y
if r != -126 {
- t.Errorf("1 - 127 = %d, want -126", r)
+ t.Errorf("1 %s 127 = %d, want -126", "-", r)
}
x = 126
y = -128
r = x - y
if r != -2 {
- t.Errorf("126 - -128 = %d, want -2", r)
+ t.Errorf("126 %s -128 = %d, want -2", "-", r)
}
y = -127
r = x - y
if r != -3 {
- t.Errorf("126 - -127 = %d, want -3", r)
+ t.Errorf("126 %s -127 = %d, want -3", "-", r)
}
y = -1
r = x - y
if r != 127 {
- t.Errorf("126 - -1 = %d, want 127", r)
+ t.Errorf("126 %s -1 = %d, want 127", "-", r)
}
y = 0
r = x - y
if r != 126 {
- t.Errorf("126 - 0 = %d, want 126", r)
+ t.Errorf("126 %s 0 = %d, want 126", "-", r)
}
y = 1
r = x - y
if r != 125 {
- t.Errorf("126 - 1 = %d, want 125", r)
+ t.Errorf("126 %s 1 = %d, want 125", "-", r)
}
y = 126
r = x - y
if r != 0 {
- t.Errorf("126 - 126 = %d, want 0", r)
+ t.Errorf("126 %s 126 = %d, want 0", "-", r)
}
y = 127
r = x - y
if r != -1 {
- t.Errorf("126 - 127 = %d, want -1", r)
+ t.Errorf("126 %s 127 = %d, want -1", "-", r)
}
x = 127
y = -128
r = x - y
if r != -1 {
- t.Errorf("127 - -128 = %d, want -1", r)
+ t.Errorf("127 %s -128 = %d, want -1", "-", r)
}
y = -127
r = x - y
if r != -2 {
- t.Errorf("127 - -127 = %d, want -2", r)
+ t.Errorf("127 %s -127 = %d, want -2", "-", r)
}
y = -1
r = x - y
if r != -128 {
- t.Errorf("127 - -1 = %d, want -128", r)
+ t.Errorf("127 %s -1 = %d, want -128", "-", r)
}
y = 0
r = x - y
if r != 127 {
- t.Errorf("127 - 0 = %d, want 127", r)
+ t.Errorf("127 %s 0 = %d, want 127", "-", r)
}
y = 1
r = x - y
if r != 126 {
- t.Errorf("127 - 1 = %d, want 126", r)
+ t.Errorf("127 %s 1 = %d, want 126", "-", r)
}
y = 126
r = x - y
if r != 1 {
- t.Errorf("127 - 126 = %d, want 1", r)
+ t.Errorf("127 %s 126 = %d, want 1", "-", r)
}
y = 127
r = x - y
if r != 0 {
- t.Errorf("127 - 127 = %d, want 0", r)
+ t.Errorf("127 %s 127 = %d, want 0", "-", r)
}
}
func TestConstFoldint8div(t *testing.T) {
@@ -5673,218 +5673,218 @@ func TestConstFoldint8div(t *testing.T) {
y = -128
r = x / y
if r != 1 {
- t.Errorf("-128 / -128 = %d, want 1", r)
+ t.Errorf("-128 %s -128 = %d, want 1", "/", r)
}
y = -127
r = x / y
if r != 1 {
- t.Errorf("-128 / -127 = %d, want 1", r)
+ t.Errorf("-128 %s -127 = %d, want 1", "/", r)
}
y = -1
r = x / y
if r != -128 {
- t.Errorf("-128 / -1 = %d, want -128", r)
+ t.Errorf("-128 %s -1 = %d, want -128", "/", r)
}
y = 1
r = x / y
if r != -128 {
- t.Errorf("-128 / 1 = %d, want -128", r)
+ t.Errorf("-128 %s 1 = %d, want -128", "/", r)
}
y = 126
r = x / y
if r != -1 {
- t.Errorf("-128 / 126 = %d, want -1", r)
+ t.Errorf("-128 %s 126 = %d, want -1", "/", r)
}
y = 127
r = x / y
if r != -1 {
- t.Errorf("-128 / 127 = %d, want -1", r)
+ t.Errorf("-128 %s 127 = %d, want -1", "/", r)
}
x = -127
y = -128
r = x / y
if r != 0 {
- t.Errorf("-127 / -128 = %d, want 0", r)
+ t.Errorf("-127 %s -128 = %d, want 0", "/", r)
}
y = -127
r = x / y
if r != 1 {
- t.Errorf("-127 / -127 = %d, want 1", r)
+ t.Errorf("-127 %s -127 = %d, want 1", "/", r)
}
y = -1
r = x / y
if r != 127 {
- t.Errorf("-127 / -1 = %d, want 127", r)
+ t.Errorf("-127 %s -1 = %d, want 127", "/", r)
}
y = 1
r = x / y
if r != -127 {
- t.Errorf("-127 / 1 = %d, want -127", r)
+ t.Errorf("-127 %s 1 = %d, want -127", "/", r)
}
y = 126
r = x / y
if r != -1 {
- t.Errorf("-127 / 126 = %d, want -1", r)
+ t.Errorf("-127 %s 126 = %d, want -1", "/", r)
}
y = 127
r = x / y
if r != -1 {
- t.Errorf("-127 / 127 = %d, want -1", r)
+ t.Errorf("-127 %s 127 = %d, want -1", "/", r)
}
x = -1
y = -128
r = x / y
if r != 0 {
- t.Errorf("-1 / -128 = %d, want 0", r)
+ t.Errorf("-1 %s -128 = %d, want 0", "/", r)
}
y = -127
r = x / y
if r != 0 {
- t.Errorf("-1 / -127 = %d, want 0", r)
+ t.Errorf("-1 %s -127 = %d, want 0", "/", r)
}
y = -1
r = x / y
if r != 1 {
- t.Errorf("-1 / -1 = %d, want 1", r)
+ t.Errorf("-1 %s -1 = %d, want 1", "/", r)
}
y = 1
r = x / y
if r != -1 {
- t.Errorf("-1 / 1 = %d, want -1", r)
+ t.Errorf("-1 %s 1 = %d, want -1", "/", r)
}
y = 126
r = x / y
if r != 0 {
- t.Errorf("-1 / 126 = %d, want 0", r)
+ t.Errorf("-1 %s 126 = %d, want 0", "/", r)
}
y = 127
r = x / y
if r != 0 {
- t.Errorf("-1 / 127 = %d, want 0", r)
+ t.Errorf("-1 %s 127 = %d, want 0", "/", r)
}
x = 0
y = -128
r = x / y
if r != 0 {
- t.Errorf("0 / -128 = %d, want 0", r)
+ t.Errorf("0 %s -128 = %d, want 0", "/", r)
}
y = -127
r = x / y
if r != 0 {
- t.Errorf("0 / -127 = %d, want 0", r)
+ t.Errorf("0 %s -127 = %d, want 0", "/", r)
}
y = -1
r = x / y
if r != 0 {
- t.Errorf("0 / -1 = %d, want 0", r)
+ t.Errorf("0 %s -1 = %d, want 0", "/", r)
}
y = 1
r = x / y
if r != 0 {
- t.Errorf("0 / 1 = %d, want 0", r)
+ t.Errorf("0 %s 1 = %d, want 0", "/", r)
}
y = 126
r = x / y
if r != 0 {
- t.Errorf("0 / 126 = %d, want 0", r)
+ t.Errorf("0 %s 126 = %d, want 0", "/", r)
}
y = 127
r = x / y
if r != 0 {
- t.Errorf("0 / 127 = %d, want 0", r)
+ t.Errorf("0 %s 127 = %d, want 0", "/", r)
}
x = 1
y = -128
r = x / y
if r != 0 {
- t.Errorf("1 / -128 = %d, want 0", r)
+ t.Errorf("1 %s -128 = %d, want 0", "/", r)
}
y = -127
r = x / y
if r != 0 {
- t.Errorf("1 / -127 = %d, want 0", r)
+ t.Errorf("1 %s -127 = %d, want 0", "/", r)
}
y = -1
r = x / y
if r != -1 {
- t.Errorf("1 / -1 = %d, want -1", r)
+ t.Errorf("1 %s -1 = %d, want -1", "/", r)
}
y = 1
r = x / y
if r != 1 {
- t.Errorf("1 / 1 = %d, want 1", r)
+ t.Errorf("1 %s 1 = %d, want 1", "/", r)
}
y = 126
r = x / y
if r != 0 {
- t.Errorf("1 / 126 = %d, want 0", r)
+ t.Errorf("1 %s 126 = %d, want 0", "/", r)
}
y = 127
r = x / y
if r != 0 {
- t.Errorf("1 / 127 = %d, want 0", r)
+ t.Errorf("1 %s 127 = %d, want 0", "/", r)
}
x = 126
y = -128
r = x / y
if r != 0 {
- t.Errorf("126 / -128 = %d, want 0", r)
+ t.Errorf("126 %s -128 = %d, want 0", "/", r)
}
y = -127
r = x / y
if r != 0 {
- t.Errorf("126 / -127 = %d, want 0", r)
+ t.Errorf("126 %s -127 = %d, want 0", "/", r)
}
y = -1
r = x / y
if r != -126 {
- t.Errorf("126 / -1 = %d, want -126", r)
+ t.Errorf("126 %s -1 = %d, want -126", "/", r)
}
y = 1
r = x / y
if r != 126 {
- t.Errorf("126 / 1 = %d, want 126", r)
+ t.Errorf("126 %s 1 = %d, want 126", "/", r)
}
y = 126
r = x / y
if r != 1 {
- t.Errorf("126 / 126 = %d, want 1", r)
+ t.Errorf("126 %s 126 = %d, want 1", "/", r)
}
y = 127
r = x / y
if r != 0 {
- t.Errorf("126 / 127 = %d, want 0", r)
+ t.Errorf("126 %s 127 = %d, want 0", "/", r)
}
x = 127
y = -128
r = x / y
if r != 0 {
- t.Errorf("127 / -128 = %d, want 0", r)
+ t.Errorf("127 %s -128 = %d, want 0", "/", r)
}
y = -127
r = x / y
if r != -1 {
- t.Errorf("127 / -127 = %d, want -1", r)
+ t.Errorf("127 %s -127 = %d, want -1", "/", r)
}
y = -1
r = x / y
if r != -127 {
- t.Errorf("127 / -1 = %d, want -127", r)
+ t.Errorf("127 %s -1 = %d, want -127", "/", r)
}
y = 1
r = x / y
if r != 127 {
- t.Errorf("127 / 1 = %d, want 127", r)
+ t.Errorf("127 %s 1 = %d, want 127", "/", r)
}
y = 126
r = x / y
if r != 1 {
- t.Errorf("127 / 126 = %d, want 1", r)
+ t.Errorf("127 %s 126 = %d, want 1", "/", r)
}
y = 127
r = x / y
if r != 1 {
- t.Errorf("127 / 127 = %d, want 1", r)
+ t.Errorf("127 %s 127 = %d, want 1", "/", r)
}
}
func TestConstFoldint8mul(t *testing.T) {
@@ -5893,253 +5893,253 @@ func TestConstFoldint8mul(t *testing.T) {
y = -128
r = x * y
if r != 0 {
- t.Errorf("-128 * -128 = %d, want 0", r)
+ t.Errorf("-128 %s -128 = %d, want 0", "*", r)
}
y = -127
r = x * y
if r != -128 {
- t.Errorf("-128 * -127 = %d, want -128", r)
+ t.Errorf("-128 %s -127 = %d, want -128", "*", r)
}
y = -1
r = x * y
if r != -128 {
- t.Errorf("-128 * -1 = %d, want -128", r)
+ t.Errorf("-128 %s -1 = %d, want -128", "*", r)
}
y = 0
r = x * y
if r != 0 {
- t.Errorf("-128 * 0 = %d, want 0", r)
+ t.Errorf("-128 %s 0 = %d, want 0", "*", r)
}
y = 1
r = x * y
if r != -128 {
- t.Errorf("-128 * 1 = %d, want -128", r)
+ t.Errorf("-128 %s 1 = %d, want -128", "*", r)
}
y = 126
r = x * y
if r != 0 {
- t.Errorf("-128 * 126 = %d, want 0", r)
+ t.Errorf("-128 %s 126 = %d, want 0", "*", r)
}
y = 127
r = x * y
if r != -128 {
- t.Errorf("-128 * 127 = %d, want -128", r)
+ t.Errorf("-128 %s 127 = %d, want -128", "*", r)
}
x = -127
y = -128
r = x * y
if r != -128 {
- t.Errorf("-127 * -128 = %d, want -128", r)
+ t.Errorf("-127 %s -128 = %d, want -128", "*", r)
}
y = -127
r = x * y
if r != 1 {
- t.Errorf("-127 * -127 = %d, want 1", r)
+ t.Errorf("-127 %s -127 = %d, want 1", "*", r)
}
y = -1
r = x * y
if r != 127 {
- t.Errorf("-127 * -1 = %d, want 127", r)
+ t.Errorf("-127 %s -1 = %d, want 127", "*", r)
}
y = 0
r = x * y
if r != 0 {
- t.Errorf("-127 * 0 = %d, want 0", r)
+ t.Errorf("-127 %s 0 = %d, want 0", "*", r)
}
y = 1
r = x * y
if r != -127 {
- t.Errorf("-127 * 1 = %d, want -127", r)
+ t.Errorf("-127 %s 1 = %d, want -127", "*", r)
}
y = 126
r = x * y
if r != 126 {
- t.Errorf("-127 * 126 = %d, want 126", r)
+ t.Errorf("-127 %s 126 = %d, want 126", "*", r)
}
y = 127
r = x * y
if r != -1 {
- t.Errorf("-127 * 127 = %d, want -1", r)
+ t.Errorf("-127 %s 127 = %d, want -1", "*", r)
}
x = -1
y = -128
r = x * y
if r != -128 {
- t.Errorf("-1 * -128 = %d, want -128", r)
+ t.Errorf("-1 %s -128 = %d, want -128", "*", r)
}
y = -127
r = x * y
if r != 127 {
- t.Errorf("-1 * -127 = %d, want 127", r)
+ t.Errorf("-1 %s -127 = %d, want 127", "*", r)
}
y = -1
r = x * y
if r != 1 {
- t.Errorf("-1 * -1 = %d, want 1", r)
+ t.Errorf("-1 %s -1 = %d, want 1", "*", r)
}
y = 0
r = x * y
if r != 0 {
- t.Errorf("-1 * 0 = %d, want 0", r)
+ t.Errorf("-1 %s 0 = %d, want 0", "*", r)
}
y = 1
r = x * y
if r != -1 {
- t.Errorf("-1 * 1 = %d, want -1", r)
+ t.Errorf("-1 %s 1 = %d, want -1", "*", r)
}
y = 126
r = x * y
if r != -126 {
- t.Errorf("-1 * 126 = %d, want -126", r)
+ t.Errorf("-1 %s 126 = %d, want -126", "*", r)
}
y = 127
r = x * y
if r != -127 {
- t.Errorf("-1 * 127 = %d, want -127", r)
+ t.Errorf("-1 %s 127 = %d, want -127", "*", r)
}
x = 0
y = -128
r = x * y
if r != 0 {
- t.Errorf("0 * -128 = %d, want 0", r)
+ t.Errorf("0 %s -128 = %d, want 0", "*", r)
}
y = -127
r = x * y
if r != 0 {
- t.Errorf("0 * -127 = %d, want 0", r)
+ t.Errorf("0 %s -127 = %d, want 0", "*", r)
}
y = -1
r = x * y
if r != 0 {
- t.Errorf("0 * -1 = %d, want 0", r)
+ t.Errorf("0 %s -1 = %d, want 0", "*", r)
}
y = 0
r = x * y
if r != 0 {
- t.Errorf("0 * 0 = %d, want 0", r)
+ t.Errorf("0 %s 0 = %d, want 0", "*", r)
}
y = 1
r = x * y
if r != 0 {
- t.Errorf("0 * 1 = %d, want 0", r)
+ t.Errorf("0 %s 1 = %d, want 0", "*", r)
}
y = 126
r = x * y
if r != 0 {
- t.Errorf("0 * 126 = %d, want 0", r)
+ t.Errorf("0 %s 126 = %d, want 0", "*", r)
}
y = 127
r = x * y
if r != 0 {
- t.Errorf("0 * 127 = %d, want 0", r)
+ t.Errorf("0 %s 127 = %d, want 0", "*", r)
}
x = 1
y = -128
r = x * y
if r != -128 {
- t.Errorf("1 * -128 = %d, want -128", r)
+ t.Errorf("1 %s -128 = %d, want -128", "*", r)
}
y = -127
r = x * y
if r != -127 {
- t.Errorf("1 * -127 = %d, want -127", r)
+ t.Errorf("1 %s -127 = %d, want -127", "*", r)
}
y = -1
r = x * y
if r != -1 {
- t.Errorf("1 * -1 = %d, want -1", r)
+ t.Errorf("1 %s -1 = %d, want -1", "*", r)
}
y = 0
r = x * y
if r != 0 {
- t.Errorf("1 * 0 = %d, want 0", r)
+ t.Errorf("1 %s 0 = %d, want 0", "*", r)
}
y = 1
r = x * y
if r != 1 {
- t.Errorf("1 * 1 = %d, want 1", r)
+ t.Errorf("1 %s 1 = %d, want 1", "*", r)
}
y = 126
r = x * y
if r != 126 {
- t.Errorf("1 * 126 = %d, want 126", r)
+ t.Errorf("1 %s 126 = %d, want 126", "*", r)
}
y = 127
r = x * y
if r != 127 {
- t.Errorf("1 * 127 = %d, want 127", r)
+ t.Errorf("1 %s 127 = %d, want 127", "*", r)
}
x = 126
y = -128
r = x * y
if r != 0 {
- t.Errorf("126 * -128 = %d, want 0", r)
+ t.Errorf("126 %s -128 = %d, want 0", "*", r)
}
y = -127
r = x * y
if r != 126 {
- t.Errorf("126 * -127 = %d, want 126", r)
+ t.Errorf("126 %s -127 = %d, want 126", "*", r)
}
y = -1
r = x * y
if r != -126 {
- t.Errorf("126 * -1 = %d, want -126", r)
+ t.Errorf("126 %s -1 = %d, want -126", "*", r)
}
y = 0
r = x * y
if r != 0 {
- t.Errorf("126 * 0 = %d, want 0", r)
+ t.Errorf("126 %s 0 = %d, want 0", "*", r)
}
y = 1
r = x * y
if r != 126 {
- t.Errorf("126 * 1 = %d, want 126", r)
+ t.Errorf("126 %s 1 = %d, want 126", "*", r)
}
y = 126
r = x * y
if r != 4 {
- t.Errorf("126 * 126 = %d, want 4", r)
+ t.Errorf("126 %s 126 = %d, want 4", "*", r)
}
y = 127
r = x * y
if r != -126 {
- t.Errorf("126 * 127 = %d, want -126", r)
+ t.Errorf("126 %s 127 = %d, want -126", "*", r)
}
x = 127
y = -128
r = x * y
if r != -128 {
- t.Errorf("127 * -128 = %d, want -128", r)
+ t.Errorf("127 %s -128 = %d, want -128", "*", r)
}
y = -127
r = x * y
if r != -1 {
- t.Errorf("127 * -127 = %d, want -1", r)
+ t.Errorf("127 %s -127 = %d, want -1", "*", r)
}
y = -1
r = x * y
if r != -127 {
- t.Errorf("127 * -1 = %d, want -127", r)
+ t.Errorf("127 %s -1 = %d, want -127", "*", r)
}
y = 0
r = x * y
if r != 0 {
- t.Errorf("127 * 0 = %d, want 0", r)
+ t.Errorf("127 %s 0 = %d, want 0", "*", r)
}
y = 1
r = x * y
if r != 127 {
- t.Errorf("127 * 1 = %d, want 127", r)
+ t.Errorf("127 %s 1 = %d, want 127", "*", r)
}
y = 126
r = x * y
if r != -126 {
- t.Errorf("127 * 126 = %d, want -126", r)
+ t.Errorf("127 %s 126 = %d, want -126", "*", r)
}
y = 127
r = x * y
if r != 1 {
- t.Errorf("127 * 127 = %d, want 1", r)
+ t.Errorf("127 %s 127 = %d, want 1", "*", r)
}
}
func TestConstFoldint8mod(t *testing.T) {
@@ -6148,218 +6148,218 @@ func TestConstFoldint8mod(t *testing.T) {
y = -128
r = x % y
if r != 0 {
- t.Errorf("-128 % -128 = %d, want 0", r)
+ t.Errorf("-128 %s -128 = %d, want 0", "%", r)
}
y = -127
r = x % y
if r != -1 {
- t.Errorf("-128 % -127 = %d, want -1", r)
+ t.Errorf("-128 %s -127 = %d, want -1", "%", r)
}
y = -1
r = x % y
if r != 0 {
- t.Errorf("-128 % -1 = %d, want 0", r)
+ t.Errorf("-128 %s -1 = %d, want 0", "%", r)
}
y = 1
r = x % y
if r != 0 {
- t.Errorf("-128 % 1 = %d, want 0", r)
+ t.Errorf("-128 %s 1 = %d, want 0", "%", r)
}
y = 126
r = x % y
if r != -2 {
- t.Errorf("-128 % 126 = %d, want -2", r)
+ t.Errorf("-128 %s 126 = %d, want -2", "%", r)
}
y = 127
r = x % y
if r != -1 {
- t.Errorf("-128 % 127 = %d, want -1", r)
+ t.Errorf("-128 %s 127 = %d, want -1", "%", r)
}
x = -127
y = -128
r = x % y
if r != -127 {
- t.Errorf("-127 % -128 = %d, want -127", r)
+ t.Errorf("-127 %s -128 = %d, want -127", "%", r)
}
y = -127
r = x % y
if r != 0 {
- t.Errorf("-127 % -127 = %d, want 0", r)
+ t.Errorf("-127 %s -127 = %d, want 0", "%", r)
}
y = -1
r = x % y
if r != 0 {
- t.Errorf("-127 % -1 = %d, want 0", r)
+ t.Errorf("-127 %s -1 = %d, want 0", "%", r)
}
y = 1
r = x % y
if r != 0 {
- t.Errorf("-127 % 1 = %d, want 0", r)
+ t.Errorf("-127 %s 1 = %d, want 0", "%", r)
}
y = 126
r = x % y
if r != -1 {
- t.Errorf("-127 % 126 = %d, want -1", r)
+ t.Errorf("-127 %s 126 = %d, want -1", "%", r)
}
y = 127
r = x % y
if r != 0 {
- t.Errorf("-127 % 127 = %d, want 0", r)
+ t.Errorf("-127 %s 127 = %d, want 0", "%", r)
}
x = -1
y = -128
r = x % y
if r != -1 {
- t.Errorf("-1 % -128 = %d, want -1", r)
+ t.Errorf("-1 %s -128 = %d, want -1", "%", r)
}
y = -127
r = x % y
if r != -1 {
- t.Errorf("-1 % -127 = %d, want -1", r)
+ t.Errorf("-1 %s -127 = %d, want -1", "%", r)
}
y = -1
r = x % y
if r != 0 {
- t.Errorf("-1 % -1 = %d, want 0", r)
+ t.Errorf("-1 %s -1 = %d, want 0", "%", r)
}
y = 1
r = x % y
if r != 0 {
- t.Errorf("-1 % 1 = %d, want 0", r)
+ t.Errorf("-1 %s 1 = %d, want 0", "%", r)
}
y = 126
r = x % y
if r != -1 {
- t.Errorf("-1 % 126 = %d, want -1", r)
+ t.Errorf("-1 %s 126 = %d, want -1", "%", r)
}
y = 127
r = x % y
if r != -1 {
- t.Errorf("-1 % 127 = %d, want -1", r)
+ t.Errorf("-1 %s 127 = %d, want -1", "%", r)
}
x = 0
y = -128
r = x % y
if r != 0 {
- t.Errorf("0 % -128 = %d, want 0", r)
+ t.Errorf("0 %s -128 = %d, want 0", "%", r)
}
y = -127
r = x % y
if r != 0 {
- t.Errorf("0 % -127 = %d, want 0", r)
+ t.Errorf("0 %s -127 = %d, want 0", "%", r)
}
y = -1
r = x % y
if r != 0 {
- t.Errorf("0 % -1 = %d, want 0", r)
+ t.Errorf("0 %s -1 = %d, want 0", "%", r)
}
y = 1
r = x % y
if r != 0 {
- t.Errorf("0 % 1 = %d, want 0", r)
+ t.Errorf("0 %s 1 = %d, want 0", "%", r)
}
y = 126
r = x % y
if r != 0 {
- t.Errorf("0 % 126 = %d, want 0", r)
+ t.Errorf("0 %s 126 = %d, want 0", "%", r)
}
y = 127
r = x % y
if r != 0 {
- t.Errorf("0 % 127 = %d, want 0", r)
+ t.Errorf("0 %s 127 = %d, want 0", "%", r)
}
x = 1
y = -128
r = x % y
if r != 1 {
- t.Errorf("1 % -128 = %d, want 1", r)
+ t.Errorf("1 %s -128 = %d, want 1", "%", r)
}
y = -127
r = x % y
if r != 1 {
- t.Errorf("1 % -127 = %d, want 1", r)
+ t.Errorf("1 %s -127 = %d, want 1", "%", r)
}
y = -1
r = x % y
if r != 0 {
- t.Errorf("1 % -1 = %d, want 0", r)
+ t.Errorf("1 %s -1 = %d, want 0", "%", r)
}
y = 1
r = x % y
if r != 0 {
- t.Errorf("1 % 1 = %d, want 0", r)
+ t.Errorf("1 %s 1 = %d, want 0", "%", r)
}
y = 126
r = x % y
if r != 1 {
- t.Errorf("1 % 126 = %d, want 1", r)
+ t.Errorf("1 %s 126 = %d, want 1", "%", r)
}
y = 127
r = x % y
if r != 1 {
- t.Errorf("1 % 127 = %d, want 1", r)
+ t.Errorf("1 %s 127 = %d, want 1", "%", r)
}
x = 126
y = -128
r = x % y
if r != 126 {
- t.Errorf("126 % -128 = %d, want 126", r)
+ t.Errorf("126 %s -128 = %d, want 126", "%", r)
}
y = -127
r = x % y
if r != 126 {
- t.Errorf("126 % -127 = %d, want 126", r)
+ t.Errorf("126 %s -127 = %d, want 126", "%", r)
}
y = -1
r = x % y
if r != 0 {
- t.Errorf("126 % -1 = %d, want 0", r)
+ t.Errorf("126 %s -1 = %d, want 0", "%", r)
}
y = 1
r = x % y
if r != 0 {
- t.Errorf("126 % 1 = %d, want 0", r)
+ t.Errorf("126 %s 1 = %d, want 0", "%", r)
}
y = 126
r = x % y
if r != 0 {
- t.Errorf("126 % 126 = %d, want 0", r)
+ t.Errorf("126 %s 126 = %d, want 0", "%", r)
}
y = 127
r = x % y
if r != 126 {
- t.Errorf("126 % 127 = %d, want 126", r)
+ t.Errorf("126 %s 127 = %d, want 126", "%", r)
}
x = 127
y = -128
r = x % y
if r != 127 {
- t.Errorf("127 % -128 = %d, want 127", r)
+ t.Errorf("127 %s -128 = %d, want 127", "%", r)
}
y = -127
r = x % y
if r != 0 {
- t.Errorf("127 % -127 = %d, want 0", r)
+ t.Errorf("127 %s -127 = %d, want 0", "%", r)
}
y = -1
r = x % y
if r != 0 {
- t.Errorf("127 % -1 = %d, want 0", r)
+ t.Errorf("127 %s -1 = %d, want 0", "%", r)
}
y = 1
r = x % y
if r != 0 {
- t.Errorf("127 % 1 = %d, want 0", r)
+ t.Errorf("127 %s 1 = %d, want 0", "%", r)
}
y = 126
r = x % y
if r != 1 {
- t.Errorf("127 % 126 = %d, want 1", r)
+ t.Errorf("127 %s 126 = %d, want 1", "%", r)
}
y = 127
r = x % y
if r != 0 {
- t.Errorf("127 % 127 = %d, want 0", r)
+ t.Errorf("127 %s 127 = %d, want 0", "%", r)
}
}
func TestConstFolduint64uint64lsh(t *testing.T) {
@@ -6369,85 +6369,85 @@ func TestConstFolduint64uint64lsh(t *testing.T) {
y = 0
r = x << y
if r != 0 {
- t.Errorf("0 << 0 = %d, want 0", r)
+ t.Errorf("0 %s 0 = %d, want 0", "<<", r)
}
y = 1
r = x << y
if r != 0 {
- t.Errorf("0 << 1 = %d, want 0", r)
+ t.Errorf("0 %s 1 = %d, want 0", "<<", r)
}
y = 4294967296
r = x << y
if r != 0 {
- t.Errorf("0 << 4294967296 = %d, want 0", r)
+ t.Errorf("0 %s 4294967296 = %d, want 0", "<<", r)
}
y = 18446744073709551615
r = x << y
if r != 0 {
- t.Errorf("0 << 18446744073709551615 = %d, want 0", r)
+ t.Errorf("0 %s 18446744073709551615 = %d, want 0", "<<", r)
}
x = 1
y = 0
r = x << y
if r != 1 {
- t.Errorf("1 << 0 = %d, want 1", r)
+ t.Errorf("1 %s 0 = %d, want 1", "<<", r)
}
y = 1
r = x << y
if r != 2 {
- t.Errorf("1 << 1 = %d, want 2", r)
+ t.Errorf("1 %s 1 = %d, want 2", "<<", r)
}
y = 4294967296
r = x << y
if r != 0 {
- t.Errorf("1 << 4294967296 = %d, want 0", r)
+ t.Errorf("1 %s 4294967296 = %d, want 0", "<<", r)
}
y = 18446744073709551615
r = x << y
if r != 0 {
- t.Errorf("1 << 18446744073709551615 = %d, want 0", r)
+ t.Errorf("1 %s 18446744073709551615 = %d, want 0", "<<", r)
}
x = 4294967296
y = 0
r = x << y
if r != 4294967296 {
- t.Errorf("4294967296 << 0 = %d, want 4294967296", r)
+ t.Errorf("4294967296 %s 0 = %d, want 4294967296", "<<", r)
}
y = 1
r = x << y
if r != 8589934592 {
- t.Errorf("4294967296 << 1 = %d, want 8589934592", r)
+ t.Errorf("4294967296 %s 1 = %d, want 8589934592", "<<", r)
}
y = 4294967296
r = x << y
if r != 0 {
- t.Errorf("4294967296 << 4294967296 = %d, want 0", r)
+ t.Errorf("4294967296 %s 4294967296 = %d, want 0", "<<", r)
}
y = 18446744073709551615
r = x << y
if r != 0 {
- t.Errorf("4294967296 << 18446744073709551615 = %d, want 0", r)
+ t.Errorf("4294967296 %s 18446744073709551615 = %d, want 0", "<<", r)
}
x = 18446744073709551615
y = 0
r = x << y
if r != 18446744073709551615 {
- t.Errorf("18446744073709551615 << 0 = %d, want 18446744073709551615", r)
+ t.Errorf("18446744073709551615 %s 0 = %d, want 18446744073709551615", "<<", r)
}
y = 1
r = x << y
if r != 18446744073709551614 {
- t.Errorf("18446744073709551615 << 1 = %d, want 18446744073709551614", r)
+ t.Errorf("18446744073709551615 %s 1 = %d, want 18446744073709551614", "<<", r)
}
y = 4294967296
r = x << y
if r != 0 {
- t.Errorf("18446744073709551615 << 4294967296 = %d, want 0", r)
+ t.Errorf("18446744073709551615 %s 4294967296 = %d, want 0", "<<", r)
}
y = 18446744073709551615
r = x << y
if r != 0 {
- t.Errorf("18446744073709551615 << 18446744073709551615 = %d, want 0", r)
+ t.Errorf("18446744073709551615 %s 18446744073709551615 = %d, want 0", "<<", r)
}
}
func TestConstFolduint64uint64rsh(t *testing.T) {
@@ -6457,85 +6457,85 @@ func TestConstFolduint64uint64rsh(t *testing.T) {
y = 0
r = x >> y
if r != 0 {
- t.Errorf("0 >> 0 = %d, want 0", r)
+ t.Errorf("0 %s 0 = %d, want 0", ">>", r)
}
y = 1
r = x >> y
if r != 0 {
- t.Errorf("0 >> 1 = %d, want 0", r)
+ t.Errorf("0 %s 1 = %d, want 0", ">>", r)
}
y = 4294967296
r = x >> y
if r != 0 {
- t.Errorf("0 >> 4294967296 = %d, want 0", r)
+ t.Errorf("0 %s 4294967296 = %d, want 0", ">>", r)
}
y = 18446744073709551615
r = x >> y
if r != 0 {
- t.Errorf("0 >> 18446744073709551615 = %d, want 0", r)
+ t.Errorf("0 %s 18446744073709551615 = %d, want 0", ">>", r)
}
x = 1
y = 0
r = x >> y
if r != 1 {
- t.Errorf("1 >> 0 = %d, want 1", r)
+ t.Errorf("1 %s 0 = %d, want 1", ">>", r)
}
y = 1
r = x >> y
if r != 0 {
- t.Errorf("1 >> 1 = %d, want 0", r)
+ t.Errorf("1 %s 1 = %d, want 0", ">>", r)
}
y = 4294967296
r = x >> y
if r != 0 {
- t.Errorf("1 >> 4294967296 = %d, want 0", r)
+ t.Errorf("1 %s 4294967296 = %d, want 0", ">>", r)
}
y = 18446744073709551615
r = x >> y
if r != 0 {
- t.Errorf("1 >> 18446744073709551615 = %d, want 0", r)
+ t.Errorf("1 %s 18446744073709551615 = %d, want 0", ">>", r)
}
x = 4294967296
y = 0
r = x >> y
if r != 4294967296 {
- t.Errorf("4294967296 >> 0 = %d, want 4294967296", r)
+ t.Errorf("4294967296 %s 0 = %d, want 4294967296", ">>", r)
}
y = 1
r = x >> y
if r != 2147483648 {
- t.Errorf("4294967296 >> 1 = %d, want 2147483648", r)
+ t.Errorf("4294967296 %s 1 = %d, want 2147483648", ">>", r)
}
y = 4294967296
r = x >> y
if r != 0 {
- t.Errorf("4294967296 >> 4294967296 = %d, want 0", r)
+ t.Errorf("4294967296 %s 4294967296 = %d, want 0", ">>", r)
}
y = 18446744073709551615
r = x >> y
if r != 0 {
- t.Errorf("4294967296 >> 18446744073709551615 = %d, want 0", r)
+ t.Errorf("4294967296 %s 18446744073709551615 = %d, want 0", ">>", r)
}
x = 18446744073709551615
y = 0
r = x >> y
if r != 18446744073709551615 {
- t.Errorf("18446744073709551615 >> 0 = %d, want 18446744073709551615", r)
+ t.Errorf("18446744073709551615 %s 0 = %d, want 18446744073709551615", ">>", r)
}
y = 1
r = x >> y
if r != 9223372036854775807 {
- t.Errorf("18446744073709551615 >> 1 = %d, want 9223372036854775807", r)
+ t.Errorf("18446744073709551615 %s 1 = %d, want 9223372036854775807", ">>", r)
}
y = 4294967296
r = x >> y
if r != 0 {
- t.Errorf("18446744073709551615 >> 4294967296 = %d, want 0", r)
+ t.Errorf("18446744073709551615 %s 4294967296 = %d, want 0", ">>", r)
}
y = 18446744073709551615
r = x >> y
if r != 0 {
- t.Errorf("18446744073709551615 >> 18446744073709551615 = %d, want 0", r)
+ t.Errorf("18446744073709551615 %s 18446744073709551615 = %d, want 0", ">>", r)
}
}
func TestConstFolduint64uint32lsh(t *testing.T) {
@@ -6545,65 +6545,65 @@ func TestConstFolduint64uint32lsh(t *testing.T) {
y = 0
r = x << y
if r != 0 {
- t.Errorf("0 << 0 = %d, want 0", r)
+ t.Errorf("0 %s 0 = %d, want 0", "<<", r)
}
y = 1
r = x << y
if r != 0 {
- t.Errorf("0 << 1 = %d, want 0", r)
+ t.Errorf("0 %s 1 = %d, want 0", "<<", r)
}
y = 4294967295
r = x << y
if r != 0 {
- t.Errorf("0 << 4294967295 = %d, want 0", r)
+ t.Errorf("0 %s 4294967295 = %d, want 0", "<<", r)
}
x = 1
y = 0
r = x << y
if r != 1 {
- t.Errorf("1 << 0 = %d, want 1", r)
+ t.Errorf("1 %s 0 = %d, want 1", "<<", r)
}
y = 1
r = x << y
if r != 2 {
- t.Errorf("1 << 1 = %d, want 2", r)
+ t.Errorf("1 %s 1 = %d, want 2", "<<", r)
}
y = 4294967295
r = x << y
if r != 0 {
- t.Errorf("1 << 4294967295 = %d, want 0", r)
+ t.Errorf("1 %s 4294967295 = %d, want 0", "<<", r)
}
x = 4294967296
y = 0
r = x << y
if r != 4294967296 {
- t.Errorf("4294967296 << 0 = %d, want 4294967296", r)
+ t.Errorf("4294967296 %s 0 = %d, want 4294967296", "<<", r)
}
y = 1
r = x << y
if r != 8589934592 {
- t.Errorf("4294967296 << 1 = %d, want 8589934592", r)
+ t.Errorf("4294967296 %s 1 = %d, want 8589934592", "<<", r)
}
y = 4294967295
r = x << y
if r != 0 {
- t.Errorf("4294967296 << 4294967295 = %d, want 0", r)
+ t.Errorf("4294967296 %s 4294967295 = %d, want 0", "<<", r)
}
x = 18446744073709551615
y = 0
r = x << y
if r != 18446744073709551615 {
- t.Errorf("18446744073709551615 << 0 = %d, want 18446744073709551615", r)
+ t.Errorf("18446744073709551615 %s 0 = %d, want 18446744073709551615", "<<", r)
}
y = 1
r = x << y
if r != 18446744073709551614 {
- t.Errorf("18446744073709551615 << 1 = %d, want 18446744073709551614", r)
+ t.Errorf("18446744073709551615 %s 1 = %d, want 18446744073709551614", "<<", r)
}
y = 4294967295
r = x << y
if r != 0 {
- t.Errorf("18446744073709551615 << 4294967295 = %d, want 0", r)
+ t.Errorf("18446744073709551615 %s 4294967295 = %d, want 0", "<<", r)
}
}
func TestConstFolduint64uint32rsh(t *testing.T) {
@@ -6613,65 +6613,65 @@ func TestConstFolduint64uint32rsh(t *testing.T) {
y = 0
r = x >> y
if r != 0 {
- t.Errorf("0 >> 0 = %d, want 0", r)
+ t.Errorf("0 %s 0 = %d, want 0", ">>", r)
}
y = 1
r = x >> y
if r != 0 {
- t.Errorf("0 >> 1 = %d, want 0", r)
+ t.Errorf("0 %s 1 = %d, want 0", ">>", r)
}
y = 4294967295
r = x >> y
if r != 0 {
- t.Errorf("0 >> 4294967295 = %d, want 0", r)
+ t.Errorf("0 %s 4294967295 = %d, want 0", ">>", r)
}
x = 1
y = 0
r = x >> y
if r != 1 {
- t.Errorf("1 >> 0 = %d, want 1", r)
+ t.Errorf("1 %s 0 = %d, want 1", ">>", r)
}
y = 1
r = x >> y
if r != 0 {
- t.Errorf("1 >> 1 = %d, want 0", r)
+ t.Errorf("1 %s 1 = %d, want 0", ">>", r)
}
y = 4294967295
r = x >> y
if r != 0 {
- t.Errorf("1 >> 4294967295 = %d, want 0", r)
+ t.Errorf("1 %s 4294967295 = %d, want 0", ">>", r)
}
x = 4294967296
y = 0
r = x >> y
if r != 4294967296 {
- t.Errorf("4294967296 >> 0 = %d, want 4294967296", r)
+ t.Errorf("4294967296 %s 0 = %d, want 4294967296", ">>", r)
}
y = 1
r = x >> y
if r != 2147483648 {
- t.Errorf("4294967296 >> 1 = %d, want 2147483648", r)
+ t.Errorf("4294967296 %s 1 = %d, want 2147483648", ">>", r)
}
y = 4294967295
r = x >> y
if r != 0 {
- t.Errorf("4294967296 >> 4294967295 = %d, want 0", r)
+ t.Errorf("4294967296 %s 4294967295 = %d, want 0", ">>", r)
}
x = 18446744073709551615
y = 0
r = x >> y
if r != 18446744073709551615 {
- t.Errorf("18446744073709551615 >> 0 = %d, want 18446744073709551615", r)
+ t.Errorf("18446744073709551615 %s 0 = %d, want 18446744073709551615", ">>", r)
}
y = 1
r = x >> y
if r != 9223372036854775807 {
- t.Errorf("18446744073709551615 >> 1 = %d, want 9223372036854775807", r)
+ t.Errorf("18446744073709551615 %s 1 = %d, want 9223372036854775807", ">>", r)
}
y = 4294967295
r = x >> y
if r != 0 {
- t.Errorf("18446744073709551615 >> 4294967295 = %d, want 0", r)
+ t.Errorf("18446744073709551615 %s 4294967295 = %d, want 0", ">>", r)
}
}
func TestConstFolduint64uint16lsh(t *testing.T) {
@@ -6681,65 +6681,65 @@ func TestConstFolduint64uint16lsh(t *testing.T) {
y = 0
r = x << y
if r != 0 {
- t.Errorf("0 << 0 = %d, want 0", r)
+ t.Errorf("0 %s 0 = %d, want 0", "<<", r)
}
y = 1
r = x << y
if r != 0 {
- t.Errorf("0 << 1 = %d, want 0", r)
+ t.Errorf("0 %s 1 = %d, want 0", "<<", r)
}
y = 65535
r = x << y
if r != 0 {
- t.Errorf("0 << 65535 = %d, want 0", r)
+ t.Errorf("0 %s 65535 = %d, want 0", "<<", r)
}
x = 1
y = 0
r = x << y
if r != 1 {
- t.Errorf("1 << 0 = %d, want 1", r)
+ t.Errorf("1 %s 0 = %d, want 1", "<<", r)
}
y = 1
r = x << y
if r != 2 {
- t.Errorf("1 << 1 = %d, want 2", r)
+ t.Errorf("1 %s 1 = %d, want 2", "<<", r)
}
y = 65535
r = x << y
if r != 0 {
- t.Errorf("1 << 65535 = %d, want 0", r)
+ t.Errorf("1 %s 65535 = %d, want 0", "<<", r)
}
x = 4294967296
y = 0
r = x << y
if r != 4294967296 {
- t.Errorf("4294967296 << 0 = %d, want 4294967296", r)
+ t.Errorf("4294967296 %s 0 = %d, want 4294967296", "<<", r)
}
y = 1
r = x << y
if r != 8589934592 {
- t.Errorf("4294967296 << 1 = %d, want 8589934592", r)
+ t.Errorf("4294967296 %s 1 = %d, want 8589934592", "<<", r)
}
y = 65535
r = x << y
if r != 0 {
- t.Errorf("4294967296 << 65535 = %d, want 0", r)
+ t.Errorf("4294967296 %s 65535 = %d, want 0", "<<", r)
}
x = 18446744073709551615
y = 0
r = x << y
if r != 18446744073709551615 {
- t.Errorf("18446744073709551615 << 0 = %d, want 18446744073709551615", r)
+ t.Errorf("18446744073709551615 %s 0 = %d, want 18446744073709551615", "<<", r)
}
y = 1
r = x << y
if r != 18446744073709551614 {
- t.Errorf("18446744073709551615 << 1 = %d, want 18446744073709551614", r)
+ t.Errorf("18446744073709551615 %s 1 = %d, want 18446744073709551614", "<<", r)
}
y = 65535
r = x << y
if r != 0 {
- t.Errorf("18446744073709551615 << 65535 = %d, want 0", r)
+ t.Errorf("18446744073709551615 %s 65535 = %d, want 0", "<<", r)
}
}
func TestConstFolduint64uint16rsh(t *testing.T) {
@@ -6749,65 +6749,65 @@ func TestConstFolduint64uint16rsh(t *testing.T) {
y = 0
r = x >> y
if r != 0 {
- t.Errorf("0 >> 0 = %d, want 0", r)
+ t.Errorf("0 %s 0 = %d, want 0", ">>", r)
}
y = 1
r = x >> y
if r != 0 {
- t.Errorf("0 >> 1 = %d, want 0", r)
+ t.Errorf("0 %s 1 = %d, want 0", ">>", r)
}
y = 65535
r = x >> y
if r != 0 {
- t.Errorf("0 >> 65535 = %d, want 0", r)
+ t.Errorf("0 %s 65535 = %d, want 0", ">>", r)
}
x = 1
y = 0
r = x >> y
if r != 1 {
- t.Errorf("1 >> 0 = %d, want 1", r)
+ t.Errorf("1 %s 0 = %d, want 1", ">>", r)
}
y = 1
r = x >> y
if r != 0 {
- t.Errorf("1 >> 1 = %d, want 0", r)
+ t.Errorf("1 %s 1 = %d, want 0", ">>", r)
}
y = 65535
r = x >> y
if r != 0 {
- t.Errorf("1 >> 65535 = %d, want 0", r)
+ t.Errorf("1 %s 65535 = %d, want 0", ">>", r)
}
x = 4294967296
y = 0
r = x >> y
if r != 4294967296 {
- t.Errorf("4294967296 >> 0 = %d, want 4294967296", r)
+ t.Errorf("4294967296 %s 0 = %d, want 4294967296", ">>", r)
}
y = 1
r = x >> y
if r != 2147483648 {
- t.Errorf("4294967296 >> 1 = %d, want 2147483648", r)
+ t.Errorf("4294967296 %s 1 = %d, want 2147483648", ">>", r)
}
y = 65535
r = x >> y
if r != 0 {
- t.Errorf("4294967296 >> 65535 = %d, want 0", r)
+ t.Errorf("4294967296 %s 65535 = %d, want 0", ">>", r)
}
x = 18446744073709551615
y = 0
r = x >> y
if r != 18446744073709551615 {
- t.Errorf("18446744073709551615 >> 0 = %d, want 18446744073709551615", r)
+ t.Errorf("18446744073709551615 %s 0 = %d, want 18446744073709551615", ">>", r)
}
y = 1
r = x >> y
if r != 9223372036854775807 {
- t.Errorf("18446744073709551615 >> 1 = %d, want 9223372036854775807", r)
+ t.Errorf("18446744073709551615 %s 1 = %d, want 9223372036854775807", ">>", r)
}
y = 65535
r = x >> y
if r != 0 {
- t.Errorf("18446744073709551615 >> 65535 = %d, want 0", r)
+ t.Errorf("18446744073709551615 %s 65535 = %d, want 0", ">>", r)
}
}
func TestConstFolduint64uint8lsh(t *testing.T) {
@@ -6817,65 +6817,65 @@ func TestConstFolduint64uint8lsh(t *testing.T) {
y = 0
r = x << y
if r != 0 {
- t.Errorf("0 << 0 = %d, want 0", r)
+ t.Errorf("0 %s 0 = %d, want 0", "<<", r)
}
y = 1
r = x << y
if r != 0 {
- t.Errorf("0 << 1 = %d, want 0", r)
+ t.Errorf("0 %s 1 = %d, want 0", "<<", r)
}
y = 255
r = x << y
if r != 0 {
- t.Errorf("0 << 255 = %d, want 0", r)
+ t.Errorf("0 %s 255 = %d, want 0", "<<", r)
}
x = 1
y = 0
r = x << y
if r != 1 {
- t.Errorf("1 << 0 = %d, want 1", r)
+ t.Errorf("1 %s 0 = %d, want 1", "<<", r)
}
y = 1
r = x << y
if r != 2 {
- t.Errorf("1 << 1 = %d, want 2", r)
+ t.Errorf("1 %s 1 = %d, want 2", "<<", r)
}
y = 255
r = x << y
if r != 0 {
- t.Errorf("1 << 255 = %d, want 0", r)
+ t.Errorf("1 %s 255 = %d, want 0", "<<", r)
}
x = 4294967296
y = 0
r = x << y
if r != 4294967296 {
- t.Errorf("4294967296 << 0 = %d, want 4294967296", r)
+ t.Errorf("4294967296 %s 0 = %d, want 4294967296", "<<", r)
}
y = 1
r = x << y
if r != 8589934592 {
- t.Errorf("4294967296 << 1 = %d, want 8589934592", r)
+ t.Errorf("4294967296 %s 1 = %d, want 8589934592", "<<", r)
}
y = 255
r = x << y
if r != 0 {
- t.Errorf("4294967296 << 255 = %d, want 0", r)
+ t.Errorf("4294967296 %s 255 = %d, want 0", "<<", r)
}
x = 18446744073709551615
y = 0
r = x << y
if r != 18446744073709551615 {
- t.Errorf("18446744073709551615 << 0 = %d, want 18446744073709551615", r)
+ t.Errorf("18446744073709551615 %s 0 = %d, want 18446744073709551615", "<<", r)
}
y = 1
r = x << y
if r != 18446744073709551614 {
- t.Errorf("18446744073709551615 << 1 = %d, want 18446744073709551614", r)
+ t.Errorf("18446744073709551615 %s 1 = %d, want 18446744073709551614", "<<", r)
}
y = 255
r = x << y
if r != 0 {
- t.Errorf("18446744073709551615 << 255 = %d, want 0", r)
+ t.Errorf("18446744073709551615 %s 255 = %d, want 0", "<<", r)
}
}
func TestConstFolduint64uint8rsh(t *testing.T) {
@@ -6885,65 +6885,65 @@ func TestConstFolduint64uint8rsh(t *testing.T) {
y = 0
r = x >> y
if r != 0 {
- t.Errorf("0 >> 0 = %d, want 0", r)
+ t.Errorf("0 %s 0 = %d, want 0", ">>", r)
}
y = 1
r = x >> y
if r != 0 {
- t.Errorf("0 >> 1 = %d, want 0", r)
+ t.Errorf("0 %s 1 = %d, want 0", ">>", r)
}
y = 255
r = x >> y
if r != 0 {
- t.Errorf("0 >> 255 = %d, want 0", r)
+ t.Errorf("0 %s 255 = %d, want 0", ">>", r)
}
x = 1
y = 0
r = x >> y
if r != 1 {
- t.Errorf("1 >> 0 = %d, want 1", r)
+ t.Errorf("1 %s 0 = %d, want 1", ">>", r)
}
y = 1
r = x >> y
if r != 0 {
- t.Errorf("1 >> 1 = %d, want 0", r)
+ t.Errorf("1 %s 1 = %d, want 0", ">>", r)
}
y = 255
r = x >> y
if r != 0 {
- t.Errorf("1 >> 255 = %d, want 0", r)
+ t.Errorf("1 %s 255 = %d, want 0", ">>", r)
}
x = 4294967296
y = 0
r = x >> y
if r != 4294967296 {
- t.Errorf("4294967296 >> 0 = %d, want 4294967296", r)
+ t.Errorf("4294967296 %s 0 = %d, want 4294967296", ">>", r)
}
y = 1
r = x >> y
if r != 2147483648 {
- t.Errorf("4294967296 >> 1 = %d, want 2147483648", r)
+ t.Errorf("4294967296 %s 1 = %d, want 2147483648", ">>", r)
}
y = 255
r = x >> y
if r != 0 {
- t.Errorf("4294967296 >> 255 = %d, want 0", r)
+ t.Errorf("4294967296 %s 255 = %d, want 0", ">>", r)
}
x = 18446744073709551615
y = 0
r = x >> y
if r != 18446744073709551615 {
- t.Errorf("18446744073709551615 >> 0 = %d, want 18446744073709551615", r)
+ t.Errorf("18446744073709551615 %s 0 = %d, want 18446744073709551615", ">>", r)
}
y = 1
r = x >> y
if r != 9223372036854775807 {
- t.Errorf("18446744073709551615 >> 1 = %d, want 9223372036854775807", r)
+ t.Errorf("18446744073709551615 %s 1 = %d, want 9223372036854775807", ">>", r)
}
y = 255
r = x >> y
if r != 0 {
- t.Errorf("18446744073709551615 >> 255 = %d, want 0", r)
+ t.Errorf("18446744073709551615 %s 255 = %d, want 0", ">>", r)
}
}
func TestConstFoldint64uint64lsh(t *testing.T) {
@@ -6953,190 +6953,190 @@ func TestConstFoldint64uint64lsh(t *testing.T) {
y = 0
r = x << y
if r != -9223372036854775808 {
- t.Errorf("-9223372036854775808 << 0 = %d, want -9223372036854775808", r)
+ t.Errorf("-9223372036854775808 %s 0 = %d, want -9223372036854775808", "<<", r)
}
y = 1
r = x << y
if r != 0 {
- t.Errorf("-9223372036854775808 << 1 = %d, want 0", r)
+ t.Errorf("-9223372036854775808 %s 1 = %d, want 0", "<<", r)
}
y = 4294967296
r = x << y
if r != 0 {
- t.Errorf("-9223372036854775808 << 4294967296 = %d, want 0", r)
+ t.Errorf("-9223372036854775808 %s 4294967296 = %d, want 0", "<<", r)
}
y = 18446744073709551615
r = x << y
if r != 0 {
- t.Errorf("-9223372036854775808 << 18446744073709551615 = %d, want 0", r)
+ t.Errorf("-9223372036854775808 %s 18446744073709551615 = %d, want 0", "<<", r)
}
x = -9223372036854775807
y = 0
r = x << y
if r != -9223372036854775807 {
- t.Errorf("-9223372036854775807 << 0 = %d, want -9223372036854775807", r)
+ t.Errorf("-9223372036854775807 %s 0 = %d, want -9223372036854775807", "<<", r)
}
y = 1
r = x << y
if r != 2 {
- t.Errorf("-9223372036854775807 << 1 = %d, want 2", r)
+ t.Errorf("-9223372036854775807 %s 1 = %d, want 2", "<<", r)
}
y = 4294967296
r = x << y
if r != 0 {
- t.Errorf("-9223372036854775807 << 4294967296 = %d, want 0", r)
+ t.Errorf("-9223372036854775807 %s 4294967296 = %d, want 0", "<<", r)
}
y = 18446744073709551615
r = x << y
if r != 0 {
- t.Errorf("-9223372036854775807 << 18446744073709551615 = %d, want 0", r)
+ t.Errorf("-9223372036854775807 %s 18446744073709551615 = %d, want 0", "<<", r)
}
x = -4294967296
y = 0
r = x << y
if r != -4294967296 {
- t.Errorf("-4294967296 << 0 = %d, want -4294967296", r)
+ t.Errorf("-4294967296 %s 0 = %d, want -4294967296", "<<", r)
}
y = 1
r = x << y
if r != -8589934592 {
- t.Errorf("-4294967296 << 1 = %d, want -8589934592", r)
+ t.Errorf("-4294967296 %s 1 = %d, want -8589934592", "<<", r)
}
y = 4294967296
r = x << y
if r != 0 {
- t.Errorf("-4294967296 << 4294967296 = %d, want 0", r)
+ t.Errorf("-4294967296 %s 4294967296 = %d, want 0", "<<", r)
}
y = 18446744073709551615
r = x << y
if r != 0 {
- t.Errorf("-4294967296 << 18446744073709551615 = %d, want 0", r)
+ t.Errorf("-4294967296 %s 18446744073709551615 = %d, want 0", "<<", r)
}
x = -1
y = 0
r = x << y
if r != -1 {
- t.Errorf("-1 << 0 = %d, want -1", r)
+ t.Errorf("-1 %s 0 = %d, want -1", "<<", r)
}
y = 1
r = x << y
if r != -2 {
- t.Errorf("-1 << 1 = %d, want -2", r)
+ t.Errorf("-1 %s 1 = %d, want -2", "<<", r)
}
y = 4294967296
r = x << y
if r != 0 {
- t.Errorf("-1 << 4294967296 = %d, want 0", r)
+ t.Errorf("-1 %s 4294967296 = %d, want 0", "<<", r)
}
y = 18446744073709551615
r = x << y
if r != 0 {
- t.Errorf("-1 << 18446744073709551615 = %d, want 0", r)
+ t.Errorf("-1 %s 18446744073709551615 = %d, want 0", "<<", r)
}
x = 0
y = 0
r = x << y
if r != 0 {
- t.Errorf("0 << 0 = %d, want 0", r)
+ t.Errorf("0 %s 0 = %d, want 0", "<<", r)
}
y = 1
r = x << y
if r != 0 {
- t.Errorf("0 << 1 = %d, want 0", r)
+ t.Errorf("0 %s 1 = %d, want 0", "<<", r)
}
y = 4294967296
r = x << y
if r != 0 {
- t.Errorf("0 << 4294967296 = %d, want 0", r)
+ t.Errorf("0 %s 4294967296 = %d, want 0", "<<", r)
}
y = 18446744073709551615
r = x << y
if r != 0 {
- t.Errorf("0 << 18446744073709551615 = %d, want 0", r)
+ t.Errorf("0 %s 18446744073709551615 = %d, want 0", "<<", r)
}
x = 1
y = 0
r = x << y
if r != 1 {
- t.Errorf("1 << 0 = %d, want 1", r)
+ t.Errorf("1 %s 0 = %d, want 1", "<<", r)
}
y = 1
r = x << y
if r != 2 {
- t.Errorf("1 << 1 = %d, want 2", r)
+ t.Errorf("1 %s 1 = %d, want 2", "<<", r)
}
y = 4294967296
r = x << y
if r != 0 {
- t.Errorf("1 << 4294967296 = %d, want 0", r)
+ t.Errorf("1 %s 4294967296 = %d, want 0", "<<", r)
}
y = 18446744073709551615
r = x << y
if r != 0 {
- t.Errorf("1 << 18446744073709551615 = %d, want 0", r)
+ t.Errorf("1 %s 18446744073709551615 = %d, want 0", "<<", r)
}
x = 4294967296
y = 0
r = x << y
if r != 4294967296 {
- t.Errorf("4294967296 << 0 = %d, want 4294967296", r)
+ t.Errorf("4294967296 %s 0 = %d, want 4294967296", "<<", r)
}
y = 1
r = x << y
if r != 8589934592 {
- t.Errorf("4294967296 << 1 = %d, want 8589934592", r)
+ t.Errorf("4294967296 %s 1 = %d, want 8589934592", "<<", r)
}
y = 4294967296
r = x << y
if r != 0 {
- t.Errorf("4294967296 << 4294967296 = %d, want 0", r)
+ t.Errorf("4294967296 %s 4294967296 = %d, want 0", "<<", r)
}
y = 18446744073709551615
r = x << y
if r != 0 {
- t.Errorf("4294967296 << 18446744073709551615 = %d, want 0", r)
+ t.Errorf("4294967296 %s 18446744073709551615 = %d, want 0", "<<", r)
}
x = 9223372036854775806
y = 0
r = x << y
if r != 9223372036854775806 {
- t.Errorf("9223372036854775806 << 0 = %d, want 9223372036854775806", r)
+ t.Errorf("9223372036854775806 %s 0 = %d, want 9223372036854775806", "<<", r)
}
y = 1
r = x << y
if r != -4 {
- t.Errorf("9223372036854775806 << 1 = %d, want -4", r)
+ t.Errorf("9223372036854775806 %s 1 = %d, want -4", "<<", r)
}
y = 4294967296
r = x << y
if r != 0 {
- t.Errorf("9223372036854775806 << 4294967296 = %d, want 0", r)
+ t.Errorf("9223372036854775806 %s 4294967296 = %d, want 0", "<<", r)
}
y = 18446744073709551615
r = x << y
if r != 0 {
- t.Errorf("9223372036854775806 << 18446744073709551615 = %d, want 0", r)
+ t.Errorf("9223372036854775806 %s 18446744073709551615 = %d, want 0", "<<", r)
}
x = 9223372036854775807
y = 0
r = x << y
if r != 9223372036854775807 {
- t.Errorf("9223372036854775807 << 0 = %d, want 9223372036854775807", r)
+ t.Errorf("9223372036854775807 %s 0 = %d, want 9223372036854775807", "<<", r)
}
y = 1
r = x << y
if r != -2 {
- t.Errorf("9223372036854775807 << 1 = %d, want -2", r)
+ t.Errorf("9223372036854775807 %s 1 = %d, want -2", "<<", r)
}
y = 4294967296
r = x << y
if r != 0 {
- t.Errorf("9223372036854775807 << 4294967296 = %d, want 0", r)
+ t.Errorf("9223372036854775807 %s 4294967296 = %d, want 0", "<<", r)
}
y = 18446744073709551615
r = x << y
if r != 0 {
- t.Errorf("9223372036854775807 << 18446744073709551615 = %d, want 0", r)
+ t.Errorf("9223372036854775807 %s 18446744073709551615 = %d, want 0", "<<", r)
}
}
func TestConstFoldint64uint64rsh(t *testing.T) {
@@ -7146,190 +7146,190 @@ func TestConstFoldint64uint64rsh(t *testing.T) {
y = 0
r = x >> y
if r != -9223372036854775808 {
- t.Errorf("-9223372036854775808 >> 0 = %d, want -9223372036854775808", r)
+ t.Errorf("-9223372036854775808 %s 0 = %d, want -9223372036854775808", ">>", r)
}
y = 1
r = x >> y
if r != -4611686018427387904 {
- t.Errorf("-9223372036854775808 >> 1 = %d, want -4611686018427387904", r)
+ t.Errorf("-9223372036854775808 %s 1 = %d, want -4611686018427387904", ">>", r)
}
y = 4294967296
r = x >> y
if r != -1 {
- t.Errorf("-9223372036854775808 >> 4294967296 = %d, want -1", r)
+ t.Errorf("-9223372036854775808 %s 4294967296 = %d, want -1", ">>", r)
}
y = 18446744073709551615
r = x >> y
if r != -1 {
- t.Errorf("-9223372036854775808 >> 18446744073709551615 = %d, want -1", r)
+ t.Errorf("-9223372036854775808 %s 18446744073709551615 = %d, want -1", ">>", r)
}
x = -9223372036854775807
y = 0
r = x >> y
if r != -9223372036854775807 {
- t.Errorf("-9223372036854775807 >> 0 = %d, want -9223372036854775807", r)
+ t.Errorf("-9223372036854775807 %s 0 = %d, want -9223372036854775807", ">>", r)
}
y = 1
r = x >> y
if r != -4611686018427387904 {
- t.Errorf("-9223372036854775807 >> 1 = %d, want -4611686018427387904", r)
+ t.Errorf("-9223372036854775807 %s 1 = %d, want -4611686018427387904", ">>", r)
}
y = 4294967296
r = x >> y
if r != -1 {
- t.Errorf("-9223372036854775807 >> 4294967296 = %d, want -1", r)
+ t.Errorf("-9223372036854775807 %s 4294967296 = %d, want -1", ">>", r)
}
y = 18446744073709551615
r = x >> y
if r != -1 {
- t.Errorf("-9223372036854775807 >> 18446744073709551615 = %d, want -1", r)
+ t.Errorf("-9223372036854775807 %s 18446744073709551615 = %d, want -1", ">>", r)
}
x = -4294967296
y = 0
r = x >> y
if r != -4294967296 {
- t.Errorf("-4294967296 >> 0 = %d, want -4294967296", r)
+ t.Errorf("-4294967296 %s 0 = %d, want -4294967296", ">>", r)
}
y = 1
r = x >> y
if r != -2147483648 {
- t.Errorf("-4294967296 >> 1 = %d, want -2147483648", r)
+ t.Errorf("-4294967296 %s 1 = %d, want -2147483648", ">>", r)
}
y = 4294967296
r = x >> y
if r != -1 {
- t.Errorf("-4294967296 >> 4294967296 = %d, want -1", r)
+ t.Errorf("-4294967296 %s 4294967296 = %d, want -1", ">>", r)
}
y = 18446744073709551615
r = x >> y
if r != -1 {
- t.Errorf("-4294967296 >> 18446744073709551615 = %d, want -1", r)
+ t.Errorf("-4294967296 %s 18446744073709551615 = %d, want -1", ">>", r)
}
x = -1
y = 0
r = x >> y
if r != -1 {
- t.Errorf("-1 >> 0 = %d, want -1", r)
+ t.Errorf("-1 %s 0 = %d, want -1", ">>", r)
}
y = 1
r = x >> y
if r != -1 {
- t.Errorf("-1 >> 1 = %d, want -1", r)
+ t.Errorf("-1 %s 1 = %d, want -1", ">>", r)
}
y = 4294967296
r = x >> y
if r != -1 {
- t.Errorf("-1 >> 4294967296 = %d, want -1", r)
+ t.Errorf("-1 %s 4294967296 = %d, want -1", ">>", r)
}
y = 18446744073709551615
r = x >> y
if r != -1 {
- t.Errorf("-1 >> 18446744073709551615 = %d, want -1", r)
+ t.Errorf("-1 %s 18446744073709551615 = %d, want -1", ">>", r)
}
x = 0
y = 0
r = x >> y
if r != 0 {
- t.Errorf("0 >> 0 = %d, want 0", r)
+ t.Errorf("0 %s 0 = %d, want 0", ">>", r)
}
y = 1
r = x >> y
if r != 0 {
- t.Errorf("0 >> 1 = %d, want 0", r)
+ t.Errorf("0 %s 1 = %d, want 0", ">>", r)
}
y = 4294967296
r = x >> y
if r != 0 {
- t.Errorf("0 >> 4294967296 = %d, want 0", r)
+ t.Errorf("0 %s 4294967296 = %d, want 0", ">>", r)
}
y = 18446744073709551615
r = x >> y
if r != 0 {
- t.Errorf("0 >> 18446744073709551615 = %d, want 0", r)
+ t.Errorf("0 %s 18446744073709551615 = %d, want 0", ">>", r)
}
x = 1
y = 0
r = x >> y
if r != 1 {
- t.Errorf("1 >> 0 = %d, want 1", r)
+ t.Errorf("1 %s 0 = %d, want 1", ">>", r)
}
y = 1
r = x >> y
if r != 0 {
- t.Errorf("1 >> 1 = %d, want 0", r)
+ t.Errorf("1 %s 1 = %d, want 0", ">>", r)
}
y = 4294967296
r = x >> y
if r != 0 {
- t.Errorf("1 >> 4294967296 = %d, want 0", r)
+ t.Errorf("1 %s 4294967296 = %d, want 0", ">>", r)
}
y = 18446744073709551615
r = x >> y
if r != 0 {
- t.Errorf("1 >> 18446744073709551615 = %d, want 0", r)
+ t.Errorf("1 %s 18446744073709551615 = %d, want 0", ">>", r)
}
x = 4294967296
y = 0
r = x >> y
if r != 4294967296 {
- t.Errorf("4294967296 >> 0 = %d, want 4294967296", r)
+ t.Errorf("4294967296 %s 0 = %d, want 4294967296", ">>", r)
}
y = 1
r = x >> y
if r != 2147483648 {
- t.Errorf("4294967296 >> 1 = %d, want 2147483648", r)
+ t.Errorf("4294967296 %s 1 = %d, want 2147483648", ">>", r)
}
y = 4294967296
r = x >> y
if r != 0 {
- t.Errorf("4294967296 >> 4294967296 = %d, want 0", r)
+ t.Errorf("4294967296 %s 4294967296 = %d, want 0", ">>", r)
}
y = 18446744073709551615
r = x >> y
if r != 0 {
- t.Errorf("4294967296 >> 18446744073709551615 = %d, want 0", r)
+ t.Errorf("4294967296 %s 18446744073709551615 = %d, want 0", ">>", r)
}
x = 9223372036854775806
y = 0
r = x >> y
if r != 9223372036854775806 {
- t.Errorf("9223372036854775806 >> 0 = %d, want 9223372036854775806", r)
+ t.Errorf("9223372036854775806 %s 0 = %d, want 9223372036854775806", ">>", r)
}
y = 1
r = x >> y
if r != 4611686018427387903 {
- t.Errorf("9223372036854775806 >> 1 = %d, want 4611686018427387903", r)
+ t.Errorf("9223372036854775806 %s 1 = %d, want 4611686018427387903", ">>", r)
}
y = 4294967296
r = x >> y
if r != 0 {
- t.Errorf("9223372036854775806 >> 4294967296 = %d, want 0", r)
+ t.Errorf("9223372036854775806 %s 4294967296 = %d, want 0", ">>", r)
}
y = 18446744073709551615
r = x >> y
if r != 0 {
- t.Errorf("9223372036854775806 >> 18446744073709551615 = %d, want 0", r)
+ t.Errorf("9223372036854775806 %s 18446744073709551615 = %d, want 0", ">>", r)
}
x = 9223372036854775807
y = 0
r = x >> y
if r != 9223372036854775807 {
- t.Errorf("9223372036854775807 >> 0 = %d, want 9223372036854775807", r)
+ t.Errorf("9223372036854775807 %s 0 = %d, want 9223372036854775807", ">>", r)
}
y = 1
r = x >> y
if r != 4611686018427387903 {
- t.Errorf("9223372036854775807 >> 1 = %d, want 4611686018427387903", r)
+ t.Errorf("9223372036854775807 %s 1 = %d, want 4611686018427387903", ">>", r)
}
y = 4294967296
r = x >> y
if r != 0 {
- t.Errorf("9223372036854775807 >> 4294967296 = %d, want 0", r)
+ t.Errorf("9223372036854775807 %s 4294967296 = %d, want 0", ">>", r)
}
y = 18446744073709551615
r = x >> y
if r != 0 {
- t.Errorf("9223372036854775807 >> 18446744073709551615 = %d, want 0", r)
+ t.Errorf("9223372036854775807 %s 18446744073709551615 = %d, want 0", ">>", r)
}
}
func TestConstFoldint64uint32lsh(t *testing.T) {
@@ -7339,145 +7339,145 @@ func TestConstFoldint64uint32lsh(t *testing.T) {
y = 0
r = x << y
if r != -9223372036854775808 {
- t.Errorf("-9223372036854775808 << 0 = %d, want -9223372036854775808", r)
+ t.Errorf("-9223372036854775808 %s 0 = %d, want -9223372036854775808", "<<", r)
}
y = 1
r = x << y
if r != 0 {
- t.Errorf("-9223372036854775808 << 1 = %d, want 0", r)
+ t.Errorf("-9223372036854775808 %s 1 = %d, want 0", "<<", r)
}
y = 4294967295
r = x << y
if r != 0 {
- t.Errorf("-9223372036854775808 << 4294967295 = %d, want 0", r)
+ t.Errorf("-9223372036854775808 %s 4294967295 = %d, want 0", "<<", r)
}
x = -9223372036854775807
y = 0
r = x << y
if r != -9223372036854775807 {
- t.Errorf("-9223372036854775807 << 0 = %d, want -9223372036854775807", r)
+ t.Errorf("-9223372036854775807 %s 0 = %d, want -9223372036854775807", "<<", r)
}
y = 1
r = x << y
if r != 2 {
- t.Errorf("-9223372036854775807 << 1 = %d, want 2", r)
+ t.Errorf("-9223372036854775807 %s 1 = %d, want 2", "<<", r)
}
y = 4294967295
r = x << y
if r != 0 {
- t.Errorf("-9223372036854775807 << 4294967295 = %d, want 0", r)
+ t.Errorf("-9223372036854775807 %s 4294967295 = %d, want 0", "<<", r)
}
x = -4294967296
y = 0
r = x << y
if r != -4294967296 {
- t.Errorf("-4294967296 << 0 = %d, want -4294967296", r)
+ t.Errorf("-4294967296 %s 0 = %d, want -4294967296", "<<", r)
}
y = 1
r = x << y
if r != -8589934592 {
- t.Errorf("-4294967296 << 1 = %d, want -8589934592", r)
+ t.Errorf("-4294967296 %s 1 = %d, want -8589934592", "<<", r)
}
y = 4294967295
r = x << y
if r != 0 {
- t.Errorf("-4294967296 << 4294967295 = %d, want 0", r)
+ t.Errorf("-4294967296 %s 4294967295 = %d, want 0", "<<", r)
}
x = -1
y = 0
r = x << y
if r != -1 {
- t.Errorf("-1 << 0 = %d, want -1", r)
+ t.Errorf("-1 %s 0 = %d, want -1", "<<", r)
}
y = 1
r = x << y
if r != -2 {
- t.Errorf("-1 << 1 = %d, want -2", r)
+ t.Errorf("-1 %s 1 = %d, want -2", "<<", r)
}
y = 4294967295
r = x << y
if r != 0 {
- t.Errorf("-1 << 4294967295 = %d, want 0", r)
+ t.Errorf("-1 %s 4294967295 = %d, want 0", "<<", r)
}
x = 0
y = 0
r = x << y
if r != 0 {
- t.Errorf("0 << 0 = %d, want 0", r)
+ t.Errorf("0 %s 0 = %d, want 0", "<<", r)
}
y = 1
r = x << y
if r != 0 {
- t.Errorf("0 << 1 = %d, want 0", r)
+ t.Errorf("0 %s 1 = %d, want 0", "<<", r)
}
y = 4294967295
r = x << y
if r != 0 {
- t.Errorf("0 << 4294967295 = %d, want 0", r)
+ t.Errorf("0 %s 4294967295 = %d, want 0", "<<", r)
}
x = 1
y = 0
r = x << y
if r != 1 {
- t.Errorf("1 << 0 = %d, want 1", r)
+ t.Errorf("1 %s 0 = %d, want 1", "<<", r)
}
y = 1
r = x << y
if r != 2 {
- t.Errorf("1 << 1 = %d, want 2", r)
+ t.Errorf("1 %s 1 = %d, want 2", "<<", r)
}
y = 4294967295
r = x << y
if r != 0 {
- t.Errorf("1 << 4294967295 = %d, want 0", r)
+ t.Errorf("1 %s 4294967295 = %d, want 0", "<<", r)
}
x = 4294967296
y = 0
r = x << y
if r != 4294967296 {
- t.Errorf("4294967296 << 0 = %d, want 4294967296", r)
+ t.Errorf("4294967296 %s 0 = %d, want 4294967296", "<<", r)
}
y = 1
r = x << y
if r != 8589934592 {
- t.Errorf("4294967296 << 1 = %d, want 8589934592", r)
+ t.Errorf("4294967296 %s 1 = %d, want 8589934592", "<<", r)
}
y = 4294967295
r = x << y
if r != 0 {
- t.Errorf("4294967296 << 4294967295 = %d, want 0", r)
+ t.Errorf("4294967296 %s 4294967295 = %d, want 0", "<<", r)
}
x = 9223372036854775806
y = 0
r = x << y
if r != 9223372036854775806 {
- t.Errorf("9223372036854775806 << 0 = %d, want 9223372036854775806", r)
+ t.Errorf("9223372036854775806 %s 0 = %d, want 9223372036854775806", "<<", r)
}
y = 1
r = x << y
if r != -4 {
- t.Errorf("9223372036854775806 << 1 = %d, want -4", r)
+ t.Errorf("9223372036854775806 %s 1 = %d, want -4", "<<", r)
}
y = 4294967295
r = x << y
if r != 0 {
- t.Errorf("9223372036854775806 << 4294967295 = %d, want 0", r)
+ t.Errorf("9223372036854775806 %s 4294967295 = %d, want 0", "<<", r)
}
x = 9223372036854775807
y = 0
r = x << y
if r != 9223372036854775807 {
- t.Errorf("9223372036854775807 << 0 = %d, want 9223372036854775807", r)
+ t.Errorf("9223372036854775807 %s 0 = %d, want 9223372036854775807", "<<", r)
}
y = 1
r = x << y
if r != -2 {
- t.Errorf("9223372036854775807 << 1 = %d, want -2", r)
+ t.Errorf("9223372036854775807 %s 1 = %d, want -2", "<<", r)
}
y = 4294967295
r = x << y
if r != 0 {
- t.Errorf("9223372036854775807 << 4294967295 = %d, want 0", r)
+ t.Errorf("9223372036854775807 %s 4294967295 = %d, want 0", "<<", r)
}
}
func TestConstFoldint64uint32rsh(t *testing.T) {
@@ -7487,145 +7487,145 @@ func TestConstFoldint64uint32rsh(t *testing.T) {
y = 0
r = x >> y
if r != -9223372036854775808 {
- t.Errorf("-9223372036854775808 >> 0 = %d, want -9223372036854775808", r)
+ t.Errorf("-9223372036854775808 %s 0 = %d, want -9223372036854775808", ">>", r)
}
y = 1
r = x >> y
if r != -4611686018427387904 {
- t.Errorf("-9223372036854775808 >> 1 = %d, want -4611686018427387904", r)
+ t.Errorf("-9223372036854775808 %s 1 = %d, want -4611686018427387904", ">>", r)
}
y = 4294967295
r = x >> y
if r != -1 {
- t.Errorf("-9223372036854775808 >> 4294967295 = %d, want -1", r)
+ t.Errorf("-9223372036854775808 %s 4294967295 = %d, want -1", ">>", r)
}
x = -9223372036854775807
y = 0
r = x >> y
if r != -9223372036854775807 {
- t.Errorf("-9223372036854775807 >> 0 = %d, want -9223372036854775807", r)
+ t.Errorf("-9223372036854775807 %s 0 = %d, want -9223372036854775807", ">>", r)
}
y = 1
r = x >> y
if r != -4611686018427387904 {
- t.Errorf("-9223372036854775807 >> 1 = %d, want -4611686018427387904", r)
+ t.Errorf("-9223372036854775807 %s 1 = %d, want -4611686018427387904", ">>", r)
}
y = 4294967295
r = x >> y
if r != -1 {
- t.Errorf("-9223372036854775807 >> 4294967295 = %d, want -1", r)
+ t.Errorf("-9223372036854775807 %s 4294967295 = %d, want -1", ">>", r)
}
x = -4294967296
y = 0
r = x >> y
if r != -4294967296 {
- t.Errorf("-4294967296 >> 0 = %d, want -4294967296", r)
+ t.Errorf("-4294967296 %s 0 = %d, want -4294967296", ">>", r)
}
y = 1
r = x >> y
if r != -2147483648 {
- t.Errorf("-4294967296 >> 1 = %d, want -2147483648", r)
+ t.Errorf("-4294967296 %s 1 = %d, want -2147483648", ">>", r)
}
y = 4294967295
r = x >> y
if r != -1 {
- t.Errorf("-4294967296 >> 4294967295 = %d, want -1", r)
+ t.Errorf("-4294967296 %s 4294967295 = %d, want -1", ">>", r)
}
x = -1
y = 0
r = x >> y
if r != -1 {
- t.Errorf("-1 >> 0 = %d, want -1", r)
+ t.Errorf("-1 %s 0 = %d, want -1", ">>", r)
}
y = 1
r = x >> y
if r != -1 {
- t.Errorf("-1 >> 1 = %d, want -1", r)
+ t.Errorf("-1 %s 1 = %d, want -1", ">>", r)
}
y = 4294967295
r = x >> y
if r != -1 {
- t.Errorf("-1 >> 4294967295 = %d, want -1", r)
+ t.Errorf("-1 %s 4294967295 = %d, want -1", ">>", r)
}
x = 0
y = 0
r = x >> y
if r != 0 {
- t.Errorf("0 >> 0 = %d, want 0", r)
+ t.Errorf("0 %s 0 = %d, want 0", ">>", r)
}
y = 1
r = x >> y
if r != 0 {
- t.Errorf("0 >> 1 = %d, want 0", r)
+ t.Errorf("0 %s 1 = %d, want 0", ">>", r)
}
y = 4294967295
r = x >> y
if r != 0 {
- t.Errorf("0 >> 4294967295 = %d, want 0", r)
+ t.Errorf("0 %s 4294967295 = %d, want 0", ">>", r)
}
x = 1
y = 0
r = x >> y
if r != 1 {
- t.Errorf("1 >> 0 = %d, want 1", r)
+ t.Errorf("1 %s 0 = %d, want 1", ">>", r)
}
y = 1
r = x >> y
if r != 0 {
- t.Errorf("1 >> 1 = %d, want 0", r)
+ t.Errorf("1 %s 1 = %d, want 0", ">>", r)
}
y = 4294967295
r = x >> y
if r != 0 {
- t.Errorf("1 >> 4294967295 = %d, want 0", r)
+ t.Errorf("1 %s 4294967295 = %d, want 0", ">>", r)
}
x = 4294967296
y = 0
r = x >> y
if r != 4294967296 {
- t.Errorf("4294967296 >> 0 = %d, want 4294967296", r)
+ t.Errorf("4294967296 %s 0 = %d, want 4294967296", ">>", r)
}
y = 1
r = x >> y
if r != 2147483648 {
- t.Errorf("4294967296 >> 1 = %d, want 2147483648", r)
+ t.Errorf("4294967296 %s 1 = %d, want 2147483648", ">>", r)
}
y = 4294967295
r = x >> y
if r != 0 {
- t.Errorf("4294967296 >> 4294967295 = %d, want 0", r)
+ t.Errorf("4294967296 %s 4294967295 = %d, want 0", ">>", r)
}
x = 9223372036854775806
y = 0
r = x >> y
if r != 9223372036854775806 {
- t.Errorf("9223372036854775806 >> 0 = %d, want 9223372036854775806", r)
+ t.Errorf("9223372036854775806 %s 0 = %d, want 9223372036854775806", ">>", r)
}
y = 1
r = x >> y
if r != 4611686018427387903 {
- t.Errorf("9223372036854775806 >> 1 = %d, want 4611686018427387903", r)
+ t.Errorf("9223372036854775806 %s 1 = %d, want 4611686018427387903", ">>", r)
}
y = 4294967295
r = x >> y
if r != 0 {
- t.Errorf("9223372036854775806 >> 4294967295 = %d, want 0", r)
+ t.Errorf("9223372036854775806 %s 4294967295 = %d, want 0", ">>", r)
}
x = 9223372036854775807
y = 0
r = x >> y
if r != 9223372036854775807 {
- t.Errorf("9223372036854775807 >> 0 = %d, want 9223372036854775807", r)
+ t.Errorf("9223372036854775807 %s 0 = %d, want 9223372036854775807", ">>", r)
}
y = 1
r = x >> y
if r != 4611686018427387903 {
- t.Errorf("9223372036854775807 >> 1 = %d, want 4611686018427387903", r)
+ t.Errorf("9223372036854775807 %s 1 = %d, want 4611686018427387903", ">>", r)
}
y = 4294967295
r = x >> y
if r != 0 {
- t.Errorf("9223372036854775807 >> 4294967295 = %d, want 0", r)
+ t.Errorf("9223372036854775807 %s 4294967295 = %d, want 0", ">>", r)
}
}
func TestConstFoldint64uint16lsh(t *testing.T) {
@@ -7635,145 +7635,145 @@ func TestConstFoldint64uint16lsh(t *testing.T) {
y = 0
r = x << y
if r != -9223372036854775808 {
- t.Errorf("-9223372036854775808 << 0 = %d, want -9223372036854775808", r)
+ t.Errorf("-9223372036854775808 %s 0 = %d, want -9223372036854775808", "<<", r)
}
y = 1
r = x << y
if r != 0 {
- t.Errorf("-9223372036854775808 << 1 = %d, want 0", r)
+ t.Errorf("-9223372036854775808 %s 1 = %d, want 0", "<<", r)
}
y = 65535
r = x << y
if r != 0 {
- t.Errorf("-9223372036854775808 << 65535 = %d, want 0", r)
+ t.Errorf("-9223372036854775808 %s 65535 = %d, want 0", "<<", r)
}
x = -9223372036854775807
y = 0
r = x << y
if r != -9223372036854775807 {
- t.Errorf("-9223372036854775807 << 0 = %d, want -9223372036854775807", r)
+ t.Errorf("-9223372036854775807 %s 0 = %d, want -9223372036854775807", "<<", r)
}
y = 1
r = x << y
if r != 2 {
- t.Errorf("-9223372036854775807 << 1 = %d, want 2", r)
+ t.Errorf("-9223372036854775807 %s 1 = %d, want 2", "<<", r)
}
y = 65535
r = x << y
if r != 0 {
- t.Errorf("-9223372036854775807 << 65535 = %d, want 0", r)
+ t.Errorf("-9223372036854775807 %s 65535 = %d, want 0", "<<", r)
}
x = -4294967296
y = 0
r = x << y
if r != -4294967296 {
- t.Errorf("-4294967296 << 0 = %d, want -4294967296", r)
+ t.Errorf("-4294967296 %s 0 = %d, want -4294967296", "<<", r)
}
y = 1
r = x << y
if r != -8589934592 {
- t.Errorf("-4294967296 << 1 = %d, want -8589934592", r)
+ t.Errorf("-4294967296 %s 1 = %d, want -8589934592", "<<", r)
}
y = 65535
r = x << y
if r != 0 {
- t.Errorf("-4294967296 << 65535 = %d, want 0", r)
+ t.Errorf("-4294967296 %s 65535 = %d, want 0", "<<", r)
}
x = -1
y = 0
r = x << y
if r != -1 {
- t.Errorf("-1 << 0 = %d, want -1", r)
+ t.Errorf("-1 %s 0 = %d, want -1", "<<", r)
}
y = 1
r = x << y
if r != -2 {
- t.Errorf("-1 << 1 = %d, want -2", r)
+ t.Errorf("-1 %s 1 = %d, want -2", "<<", r)
}
y = 65535
r = x << y
if r != 0 {
- t.Errorf("-1 << 65535 = %d, want 0", r)
+ t.Errorf("-1 %s 65535 = %d, want 0", "<<", r)
}
x = 0
y = 0
r = x << y
if r != 0 {
- t.Errorf("0 << 0 = %d, want 0", r)
+ t.Errorf("0 %s 0 = %d, want 0", "<<", r)
}
y = 1
r = x << y
if r != 0 {
- t.Errorf("0 << 1 = %d, want 0", r)
+ t.Errorf("0 %s 1 = %d, want 0", "<<", r)
}
y = 65535
r = x << y
if r != 0 {
- t.Errorf("0 << 65535 = %d, want 0", r)
+ t.Errorf("0 %s 65535 = %d, want 0", "<<", r)
}
x = 1
y = 0
r = x << y
if r != 1 {
- t.Errorf("1 << 0 = %d, want 1", r)
+ t.Errorf("1 %s 0 = %d, want 1", "<<", r)
}
y = 1
r = x << y
if r != 2 {
- t.Errorf("1 << 1 = %d, want 2", r)
+ t.Errorf("1 %s 1 = %d, want 2", "<<", r)
}
y = 65535
r = x << y
if r != 0 {
- t.Errorf("1 << 65535 = %d, want 0", r)
+ t.Errorf("1 %s 65535 = %d, want 0", "<<", r)
}
x = 4294967296
y = 0
r = x << y
if r != 4294967296 {
- t.Errorf("4294967296 << 0 = %d, want 4294967296", r)
+ t.Errorf("4294967296 %s 0 = %d, want 4294967296", "<<", r)
}
y = 1
r = x << y
if r != 8589934592 {
- t.Errorf("4294967296 << 1 = %d, want 8589934592", r)
+ t.Errorf("4294967296 %s 1 = %d, want 8589934592", "<<", r)
}
y = 65535
r = x << y
if r != 0 {
- t.Errorf("4294967296 << 65535 = %d, want 0", r)
+ t.Errorf("4294967296 %s 65535 = %d, want 0", "<<", r)
}
x = 9223372036854775806
y = 0
r = x << y
if r != 9223372036854775806 {
- t.Errorf("9223372036854775806 << 0 = %d, want 9223372036854775806", r)
+ t.Errorf("9223372036854775806 %s 0 = %d, want 9223372036854775806", "<<", r)
}
y = 1
r = x << y
if r != -4 {
- t.Errorf("9223372036854775806 << 1 = %d, want -4", r)
+ t.Errorf("9223372036854775806 %s 1 = %d, want -4", "<<", r)
}
y = 65535
r = x << y
if r != 0 {
- t.Errorf("9223372036854775806 << 65535 = %d, want 0", r)
+ t.Errorf("9223372036854775806 %s 65535 = %d, want 0", "<<", r)
}
x = 9223372036854775807
y = 0
r = x << y
if r != 9223372036854775807 {
- t.Errorf("9223372036854775807 << 0 = %d, want 9223372036854775807", r)
+ t.Errorf("9223372036854775807 %s 0 = %d, want 9223372036854775807", "<<", r)
}
y = 1
r = x << y
if r != -2 {
- t.Errorf("9223372036854775807 << 1 = %d, want -2", r)
+ t.Errorf("9223372036854775807 %s 1 = %d, want -2", "<<", r)
}
y = 65535
r = x << y
if r != 0 {
- t.Errorf("9223372036854775807 << 65535 = %d, want 0", r)
+ t.Errorf("9223372036854775807 %s 65535 = %d, want 0", "<<", r)
}
}
func TestConstFoldint64uint16rsh(t *testing.T) {
@@ -7783,145 +7783,145 @@ func TestConstFoldint64uint16rsh(t *testing.T) {
y = 0
r = x >> y
if r != -9223372036854775808 {
- t.Errorf("-9223372036854775808 >> 0 = %d, want -9223372036854775808", r)
+ t.Errorf("-9223372036854775808 %s 0 = %d, want -9223372036854775808", ">>", r)
}
y = 1
r = x >> y
if r != -4611686018427387904 {
- t.Errorf("-9223372036854775808 >> 1 = %d, want -4611686018427387904", r)
+ t.Errorf("-9223372036854775808 %s 1 = %d, want -4611686018427387904", ">>", r)
}
y = 65535
r = x >> y
if r != -1 {
- t.Errorf("-9223372036854775808 >> 65535 = %d, want -1", r)
+ t.Errorf("-9223372036854775808 %s 65535 = %d, want -1", ">>", r)
}
x = -9223372036854775807
y = 0
r = x >> y
if r != -9223372036854775807 {
- t.Errorf("-9223372036854775807 >> 0 = %d, want -9223372036854775807", r)
+ t.Errorf("-9223372036854775807 %s 0 = %d, want -9223372036854775807", ">>", r)
}
y = 1
r = x >> y
if r != -4611686018427387904 {
- t.Errorf("-9223372036854775807 >> 1 = %d, want -4611686018427387904", r)
+ t.Errorf("-9223372036854775807 %s 1 = %d, want -4611686018427387904", ">>", r)
}
y = 65535
r = x >> y
if r != -1 {
- t.Errorf("-9223372036854775807 >> 65535 = %d, want -1", r)
+ t.Errorf("-9223372036854775807 %s 65535 = %d, want -1", ">>", r)
}
x = -4294967296
y = 0
r = x >> y
if r != -4294967296 {
- t.Errorf("-4294967296 >> 0 = %d, want -4294967296", r)
+ t.Errorf("-4294967296 %s 0 = %d, want -4294967296", ">>", r)
}
y = 1
r = x >> y
if r != -2147483648 {
- t.Errorf("-4294967296 >> 1 = %d, want -2147483648", r)
+ t.Errorf("-4294967296 %s 1 = %d, want -2147483648", ">>", r)
}
y = 65535
r = x >> y
if r != -1 {
- t.Errorf("-4294967296 >> 65535 = %d, want -1", r)
+ t.Errorf("-4294967296 %s 65535 = %d, want -1", ">>", r)
}
x = -1
y = 0
r = x >> y
if r != -1 {
- t.Errorf("-1 >> 0 = %d, want -1", r)
+ t.Errorf("-1 %s 0 = %d, want -1", ">>", r)
}
y = 1
r = x >> y
if r != -1 {
- t.Errorf("-1 >> 1 = %d, want -1", r)
+ t.Errorf("-1 %s 1 = %d, want -1", ">>", r)
}
y = 65535
r = x >> y
if r != -1 {
- t.Errorf("-1 >> 65535 = %d, want -1", r)
+ t.Errorf("-1 %s 65535 = %d, want -1", ">>", r)
}
x = 0
y = 0
r = x >> y
if r != 0 {
- t.Errorf("0 >> 0 = %d, want 0", r)
+ t.Errorf("0 %s 0 = %d, want 0", ">>", r)
}
y = 1
r = x >> y
if r != 0 {
- t.Errorf("0 >> 1 = %d, want 0", r)
+ t.Errorf("0 %s 1 = %d, want 0", ">>", r)
}
y = 65535
r = x >> y
if r != 0 {
- t.Errorf("0 >> 65535 = %d, want 0", r)
+ t.Errorf("0 %s 65535 = %d, want 0", ">>", r)
}
x = 1
y = 0
r = x >> y
if r != 1 {
- t.Errorf("1 >> 0 = %d, want 1", r)
+ t.Errorf("1 %s 0 = %d, want 1", ">>", r)
}
y = 1
r = x >> y
if r != 0 {
- t.Errorf("1 >> 1 = %d, want 0", r)
+ t.Errorf("1 %s 1 = %d, want 0", ">>", r)
}
y = 65535
r = x >> y
if r != 0 {
- t.Errorf("1 >> 65535 = %d, want 0", r)
+ t.Errorf("1 %s 65535 = %d, want 0", ">>", r)
}
x = 4294967296
y = 0
r = x >> y
if r != 4294967296 {
- t.Errorf("4294967296 >> 0 = %d, want 4294967296", r)
+ t.Errorf("4294967296 %s 0 = %d, want 4294967296", ">>", r)
}
y = 1
r = x >> y
if r != 2147483648 {
- t.Errorf("4294967296 >> 1 = %d, want 2147483648", r)
+ t.Errorf("4294967296 %s 1 = %d, want 2147483648", ">>", r)
}
y = 65535
r = x >> y
if r != 0 {
- t.Errorf("4294967296 >> 65535 = %d, want 0", r)
+ t.Errorf("4294967296 %s 65535 = %d, want 0", ">>", r)
}
x = 9223372036854775806
y = 0
r = x >> y
if r != 9223372036854775806 {
- t.Errorf("9223372036854775806 >> 0 = %d, want 9223372036854775806", r)
+ t.Errorf("9223372036854775806 %s 0 = %d, want 9223372036854775806", ">>", r)
}
y = 1
r = x >> y
if r != 4611686018427387903 {
- t.Errorf("9223372036854775806 >> 1 = %d, want 4611686018427387903", r)
+ t.Errorf("9223372036854775806 %s 1 = %d, want 4611686018427387903", ">>", r)
}
y = 65535
r = x >> y
if r != 0 {
- t.Errorf("9223372036854775806 >> 65535 = %d, want 0", r)
+ t.Errorf("9223372036854775806 %s 65535 = %d, want 0", ">>", r)
}
x = 9223372036854775807
y = 0
r = x >> y
if r != 9223372036854775807 {
- t.Errorf("9223372036854775807 >> 0 = %d, want 9223372036854775807", r)
+ t.Errorf("9223372036854775807 %s 0 = %d, want 9223372036854775807", ">>", r)
}
y = 1
r = x >> y
if r != 4611686018427387903 {
- t.Errorf("9223372036854775807 >> 1 = %d, want 4611686018427387903", r)
+ t.Errorf("9223372036854775807 %s 1 = %d, want 4611686018427387903", ">>", r)
}
y = 65535
r = x >> y
if r != 0 {
- t.Errorf("9223372036854775807 >> 65535 = %d, want 0", r)
+ t.Errorf("9223372036854775807 %s 65535 = %d, want 0", ">>", r)
}
}
func TestConstFoldint64uint8lsh(t *testing.T) {
@@ -7931,145 +7931,145 @@ func TestConstFoldint64uint8lsh(t *testing.T) {
y = 0
r = x << y
if r != -9223372036854775808 {
- t.Errorf("-9223372036854775808 << 0 = %d, want -9223372036854775808", r)
+ t.Errorf("-9223372036854775808 %s 0 = %d, want -9223372036854775808", "<<", r)
}
y = 1
r = x << y
if r != 0 {
- t.Errorf("-9223372036854775808 << 1 = %d, want 0", r)
+ t.Errorf("-9223372036854775808 %s 1 = %d, want 0", "<<", r)
}
y = 255
r = x << y
if r != 0 {
- t.Errorf("-9223372036854775808 << 255 = %d, want 0", r)
+ t.Errorf("-9223372036854775808 %s 255 = %d, want 0", "<<", r)
}
x = -9223372036854775807
y = 0
r = x << y
if r != -9223372036854775807 {
- t.Errorf("-9223372036854775807 << 0 = %d, want -9223372036854775807", r)
+ t.Errorf("-9223372036854775807 %s 0 = %d, want -9223372036854775807", "<<", r)
}
y = 1
r = x << y
if r != 2 {
- t.Errorf("-9223372036854775807 << 1 = %d, want 2", r)
+ t.Errorf("-9223372036854775807 %s 1 = %d, want 2", "<<", r)
}
y = 255
r = x << y
if r != 0 {
- t.Errorf("-9223372036854775807 << 255 = %d, want 0", r)
+ t.Errorf("-9223372036854775807 %s 255 = %d, want 0", "<<", r)
}
x = -4294967296
y = 0
r = x << y
if r != -4294967296 {
- t.Errorf("-4294967296 << 0 = %d, want -4294967296", r)
+ t.Errorf("-4294967296 %s 0 = %d, want -4294967296", "<<", r)
}
y = 1
r = x << y
if r != -8589934592 {
- t.Errorf("-4294967296 << 1 = %d, want -8589934592", r)
+ t.Errorf("-4294967296 %s 1 = %d, want -8589934592", "<<", r)
}
y = 255
r = x << y
if r != 0 {
- t.Errorf("-4294967296 << 255 = %d, want 0", r)
+ t.Errorf("-4294967296 %s 255 = %d, want 0", "<<", r)
}
x = -1
y = 0
r = x << y
if r != -1 {
- t.Errorf("-1 << 0 = %d, want -1", r)
+ t.Errorf("-1 %s 0 = %d, want -1", "<<", r)
}
y = 1
r = x << y
if r != -2 {
- t.Errorf("-1 << 1 = %d, want -2", r)
+ t.Errorf("-1 %s 1 = %d, want -2", "<<", r)
}
y = 255
r = x << y
if r != 0 {
- t.Errorf("-1 << 255 = %d, want 0", r)
+ t.Errorf("-1 %s 255 = %d, want 0", "<<", r)
}
x = 0
y = 0
r = x << y
if r != 0 {
- t.Errorf("0 << 0 = %d, want 0", r)
+ t.Errorf("0 %s 0 = %d, want 0", "<<", r)
}
y = 1
r = x << y
if r != 0 {
- t.Errorf("0 << 1 = %d, want 0", r)
+ t.Errorf("0 %s 1 = %d, want 0", "<<", r)
}
y = 255
r = x << y
if r != 0 {
- t.Errorf("0 << 255 = %d, want 0", r)
+ t.Errorf("0 %s 255 = %d, want 0", "<<", r)
}
x = 1
y = 0
r = x << y
if r != 1 {
- t.Errorf("1 << 0 = %d, want 1", r)
+ t.Errorf("1 %s 0 = %d, want 1", "<<", r)
}
y = 1
r = x << y
if r != 2 {
- t.Errorf("1 << 1 = %d, want 2", r)
+ t.Errorf("1 %s 1 = %d, want 2", "<<", r)
}
y = 255
r = x << y
if r != 0 {
- t.Errorf("1 << 255 = %d, want 0", r)
+ t.Errorf("1 %s 255 = %d, want 0", "<<", r)
}
x = 4294967296
y = 0
r = x << y
if r != 4294967296 {
- t.Errorf("4294967296 << 0 = %d, want 4294967296", r)
+ t.Errorf("4294967296 %s 0 = %d, want 4294967296", "<<", r)
}
y = 1
r = x << y
if r != 8589934592 {
- t.Errorf("4294967296 << 1 = %d, want 8589934592", r)
+ t.Errorf("4294967296 %s 1 = %d, want 8589934592", "<<", r)
}
y = 255
r = x << y
if r != 0 {
- t.Errorf("4294967296 << 255 = %d, want 0", r)
+ t.Errorf("4294967296 %s 255 = %d, want 0", "<<", r)
}
x = 9223372036854775806
y = 0
r = x << y
if r != 9223372036854775806 {
- t.Errorf("9223372036854775806 << 0 = %d, want 9223372036854775806", r)
+ t.Errorf("9223372036854775806 %s 0 = %d, want 9223372036854775806", "<<", r)
}
y = 1
r = x << y
if r != -4 {
- t.Errorf("9223372036854775806 << 1 = %d, want -4", r)
+ t.Errorf("9223372036854775806 %s 1 = %d, want -4", "<<", r)
}
y = 255
r = x << y
if r != 0 {
- t.Errorf("9223372036854775806 << 255 = %d, want 0", r)
+ t.Errorf("9223372036854775806 %s 255 = %d, want 0", "<<", r)
}
x = 9223372036854775807
y = 0
r = x << y
if r != 9223372036854775807 {
- t.Errorf("9223372036854775807 << 0 = %d, want 9223372036854775807", r)
+ t.Errorf("9223372036854775807 %s 0 = %d, want 9223372036854775807", "<<", r)
}
y = 1
r = x << y
if r != -2 {
- t.Errorf("9223372036854775807 << 1 = %d, want -2", r)
+ t.Errorf("9223372036854775807 %s 1 = %d, want -2", "<<", r)
}
y = 255
r = x << y
if r != 0 {
- t.Errorf("9223372036854775807 << 255 = %d, want 0", r)
+ t.Errorf("9223372036854775807 %s 255 = %d, want 0", "<<", r)
}
}
func TestConstFoldint64uint8rsh(t *testing.T) {
@@ -8079,145 +8079,145 @@ func TestConstFoldint64uint8rsh(t *testing.T) {
y = 0
r = x >> y
if r != -9223372036854775808 {
- t.Errorf("-9223372036854775808 >> 0 = %d, want -9223372036854775808", r)
+ t.Errorf("-9223372036854775808 %s 0 = %d, want -9223372036854775808", ">>", r)
}
y = 1
r = x >> y
if r != -4611686018427387904 {
- t.Errorf("-9223372036854775808 >> 1 = %d, want -4611686018427387904", r)
+ t.Errorf("-9223372036854775808 %s 1 = %d, want -4611686018427387904", ">>", r)
}
y = 255
r = x >> y
if r != -1 {
- t.Errorf("-9223372036854775808 >> 255 = %d, want -1", r)
+ t.Errorf("-9223372036854775808 %s 255 = %d, want -1", ">>", r)
}
x = -9223372036854775807
y = 0
r = x >> y
if r != -9223372036854775807 {
- t.Errorf("-9223372036854775807 >> 0 = %d, want -9223372036854775807", r)
+ t.Errorf("-9223372036854775807 %s 0 = %d, want -9223372036854775807", ">>", r)
}
y = 1
r = x >> y
if r != -4611686018427387904 {
- t.Errorf("-9223372036854775807 >> 1 = %d, want -4611686018427387904", r)
+ t.Errorf("-9223372036854775807 %s 1 = %d, want -4611686018427387904", ">>", r)
}
y = 255
r = x >> y
if r != -1 {
- t.Errorf("-9223372036854775807 >> 255 = %d, want -1", r)
+ t.Errorf("-9223372036854775807 %s 255 = %d, want -1", ">>", r)
}
x = -4294967296
y = 0
r = x >> y
if r != -4294967296 {
- t.Errorf("-4294967296 >> 0 = %d, want -4294967296", r)
+ t.Errorf("-4294967296 %s 0 = %d, want -4294967296", ">>", r)
}
y = 1
r = x >> y
if r != -2147483648 {
- t.Errorf("-4294967296 >> 1 = %d, want -2147483648", r)
+ t.Errorf("-4294967296 %s 1 = %d, want -2147483648", ">>", r)
}
y = 255
r = x >> y
if r != -1 {
- t.Errorf("-4294967296 >> 255 = %d, want -1", r)
+ t.Errorf("-4294967296 %s 255 = %d, want -1", ">>", r)
}
x = -1
y = 0
r = x >> y
if r != -1 {
- t.Errorf("-1 >> 0 = %d, want -1", r)
+ t.Errorf("-1 %s 0 = %d, want -1", ">>", r)
}
y = 1
r = x >> y
if r != -1 {
- t.Errorf("-1 >> 1 = %d, want -1", r)
+ t.Errorf("-1 %s 1 = %d, want -1", ">>", r)
}
y = 255
r = x >> y
if r != -1 {
- t.Errorf("-1 >> 255 = %d, want -1", r)
+ t.Errorf("-1 %s 255 = %d, want -1", ">>", r)
}
x = 0
y = 0
r = x >> y
if r != 0 {
- t.Errorf("0 >> 0 = %d, want 0", r)
+ t.Errorf("0 %s 0 = %d, want 0", ">>", r)
}
y = 1
r = x >> y
if r != 0 {
- t.Errorf("0 >> 1 = %d, want 0", r)
+ t.Errorf("0 %s 1 = %d, want 0", ">>", r)
}
y = 255
r = x >> y
if r != 0 {
- t.Errorf("0 >> 255 = %d, want 0", r)
+ t.Errorf("0 %s 255 = %d, want 0", ">>", r)
}
x = 1
y = 0
r = x >> y
if r != 1 {
- t.Errorf("1 >> 0 = %d, want 1", r)
+ t.Errorf("1 %s 0 = %d, want 1", ">>", r)
}
y = 1
r = x >> y
if r != 0 {
- t.Errorf("1 >> 1 = %d, want 0", r)
+ t.Errorf("1 %s 1 = %d, want 0", ">>", r)
}
y = 255
r = x >> y
if r != 0 {
- t.Errorf("1 >> 255 = %d, want 0", r)
+ t.Errorf("1 %s 255 = %d, want 0", ">>", r)
}
x = 4294967296
y = 0
r = x >> y
if r != 4294967296 {
- t.Errorf("4294967296 >> 0 = %d, want 4294967296", r)
+ t.Errorf("4294967296 %s 0 = %d, want 4294967296", ">>", r)
}
y = 1
r = x >> y
if r != 2147483648 {
- t.Errorf("4294967296 >> 1 = %d, want 2147483648", r)
+ t.Errorf("4294967296 %s 1 = %d, want 2147483648", ">>", r)
}
y = 255
r = x >> y
if r != 0 {
- t.Errorf("4294967296 >> 255 = %d, want 0", r)
+ t.Errorf("4294967296 %s 255 = %d, want 0", ">>", r)
}
x = 9223372036854775806
y = 0
r = x >> y
if r != 9223372036854775806 {
- t.Errorf("9223372036854775806 >> 0 = %d, want 9223372036854775806", r)
+ t.Errorf("9223372036854775806 %s 0 = %d, want 9223372036854775806", ">>", r)
}
y = 1
r = x >> y
if r != 4611686018427387903 {
- t.Errorf("9223372036854775806 >> 1 = %d, want 4611686018427387903", r)
+ t.Errorf("9223372036854775806 %s 1 = %d, want 4611686018427387903", ">>", r)
}
y = 255
r = x >> y
if r != 0 {
- t.Errorf("9223372036854775806 >> 255 = %d, want 0", r)
+ t.Errorf("9223372036854775806 %s 255 = %d, want 0", ">>", r)
}
x = 9223372036854775807
y = 0
r = x >> y
if r != 9223372036854775807 {
- t.Errorf("9223372036854775807 >> 0 = %d, want 9223372036854775807", r)
+ t.Errorf("9223372036854775807 %s 0 = %d, want 9223372036854775807", ">>", r)
}
y = 1
r = x >> y
if r != 4611686018427387903 {
- t.Errorf("9223372036854775807 >> 1 = %d, want 4611686018427387903", r)
+ t.Errorf("9223372036854775807 %s 1 = %d, want 4611686018427387903", ">>", r)
}
y = 255
r = x >> y
if r != 0 {
- t.Errorf("9223372036854775807 >> 255 = %d, want 0", r)
+ t.Errorf("9223372036854775807 %s 255 = %d, want 0", ">>", r)
}
}
func TestConstFolduint32uint64lsh(t *testing.T) {
@@ -8227,64 +8227,64 @@ func TestConstFolduint32uint64lsh(t *testing.T) {
y = 0
r = x << y
if r != 0 {
- t.Errorf("0 << 0 = %d, want 0", r)
+ t.Errorf("0 %s 0 = %d, want 0", "<<", r)
}
y = 1
r = x << y
if r != 0 {
- t.Errorf("0 << 1 = %d, want 0", r)
+ t.Errorf("0 %s 1 = %d, want 0", "<<", r)
}
y = 4294967296
r = x << y
if r != 0 {
- t.Errorf("0 << 4294967296 = %d, want 0", r)
+ t.Errorf("0 %s 4294967296 = %d, want 0", "<<", r)
}
y = 18446744073709551615
r = x << y
if r != 0 {
- t.Errorf("0 << 18446744073709551615 = %d, want 0", r)
+ t.Errorf("0 %s 18446744073709551615 = %d, want 0", "<<", r)
}
x = 1
y = 0
r = x << y
if r != 1 {
- t.Errorf("1 << 0 = %d, want 1", r)
+ t.Errorf("1 %s 0 = %d, want 1", "<<", r)
}
y = 1
r = x << y
if r != 2 {
- t.Errorf("1 << 1 = %d, want 2", r)
+ t.Errorf("1 %s 1 = %d, want 2", "<<", r)
}
y = 4294967296
r = x << y
if r != 0 {
- t.Errorf("1 << 4294967296 = %d, want 0", r)
+ t.Errorf("1 %s 4294967296 = %d, want 0", "<<", r)
}
y = 18446744073709551615
r = x << y
if r != 0 {
- t.Errorf("1 << 18446744073709551615 = %d, want 0", r)
+ t.Errorf("1 %s 18446744073709551615 = %d, want 0", "<<", r)
}
x = 4294967295
y = 0
r = x << y
if r != 4294967295 {
- t.Errorf("4294967295 << 0 = %d, want 4294967295", r)
+ t.Errorf("4294967295 %s 0 = %d, want 4294967295", "<<", r)
}
y = 1
r = x << y
if r != 4294967294 {
- t.Errorf("4294967295 << 1 = %d, want 4294967294", r)
+ t.Errorf("4294967295 %s 1 = %d, want 4294967294", "<<", r)
}
y = 4294967296
r = x << y
if r != 0 {
- t.Errorf("4294967295 << 4294967296 = %d, want 0", r)
+ t.Errorf("4294967295 %s 4294967296 = %d, want 0", "<<", r)
}
y = 18446744073709551615
r = x << y
if r != 0 {
- t.Errorf("4294967295 << 18446744073709551615 = %d, want 0", r)
+ t.Errorf("4294967295 %s 18446744073709551615 = %d, want 0", "<<", r)
}
}
func TestConstFolduint32uint64rsh(t *testing.T) {
@@ -8294,64 +8294,64 @@ func TestConstFolduint32uint64rsh(t *testing.T) {
y = 0
r = x >> y
if r != 0 {
- t.Errorf("0 >> 0 = %d, want 0", r)
+ t.Errorf("0 %s 0 = %d, want 0", ">>", r)
}
y = 1
r = x >> y
if r != 0 {
- t.Errorf("0 >> 1 = %d, want 0", r)
+ t.Errorf("0 %s 1 = %d, want 0", ">>", r)
}
y = 4294967296
r = x >> y
if r != 0 {
- t.Errorf("0 >> 4294967296 = %d, want 0", r)
+ t.Errorf("0 %s 4294967296 = %d, want 0", ">>", r)
}
y = 18446744073709551615
r = x >> y
if r != 0 {
- t.Errorf("0 >> 18446744073709551615 = %d, want 0", r)
+ t.Errorf("0 %s 18446744073709551615 = %d, want 0", ">>", r)
}
x = 1
y = 0
r = x >> y
if r != 1 {
- t.Errorf("1 >> 0 = %d, want 1", r)
+ t.Errorf("1 %s 0 = %d, want 1", ">>", r)
}
y = 1
r = x >> y
if r != 0 {
- t.Errorf("1 >> 1 = %d, want 0", r)
+ t.Errorf("1 %s 1 = %d, want 0", ">>", r)
}
y = 4294967296
r = x >> y
if r != 0 {
- t.Errorf("1 >> 4294967296 = %d, want 0", r)
+ t.Errorf("1 %s 4294967296 = %d, want 0", ">>", r)
}
y = 18446744073709551615
r = x >> y
if r != 0 {
- t.Errorf("1 >> 18446744073709551615 = %d, want 0", r)
+ t.Errorf("1 %s 18446744073709551615 = %d, want 0", ">>", r)
}
x = 4294967295
y = 0
r = x >> y
if r != 4294967295 {
- t.Errorf("4294967295 >> 0 = %d, want 4294967295", r)
+ t.Errorf("4294967295 %s 0 = %d, want 4294967295", ">>", r)
}
y = 1
r = x >> y
if r != 2147483647 {
- t.Errorf("4294967295 >> 1 = %d, want 2147483647", r)
+ t.Errorf("4294967295 %s 1 = %d, want 2147483647", ">>", r)
}
y = 4294967296
r = x >> y
if r != 0 {
- t.Errorf("4294967295 >> 4294967296 = %d, want 0", r)
+ t.Errorf("4294967295 %s 4294967296 = %d, want 0", ">>", r)
}
y = 18446744073709551615
r = x >> y
if r != 0 {
- t.Errorf("4294967295 >> 18446744073709551615 = %d, want 0", r)
+ t.Errorf("4294967295 %s 18446744073709551615 = %d, want 0", ">>", r)
}
}
func TestConstFolduint32uint32lsh(t *testing.T) {
@@ -8361,49 +8361,49 @@ func TestConstFolduint32uint32lsh(t *testing.T) {
y = 0
r = x << y
if r != 0 {
- t.Errorf("0 << 0 = %d, want 0", r)
+ t.Errorf("0 %s 0 = %d, want 0", "<<", r)
}
y = 1
r = x << y
if r != 0 {
- t.Errorf("0 << 1 = %d, want 0", r)
+ t.Errorf("0 %s 1 = %d, want 0", "<<", r)
}
y = 4294967295
r = x << y
if r != 0 {
- t.Errorf("0 << 4294967295 = %d, want 0", r)
+ t.Errorf("0 %s 4294967295 = %d, want 0", "<<", r)
}
x = 1
y = 0
r = x << y
if r != 1 {
- t.Errorf("1 << 0 = %d, want 1", r)
+ t.Errorf("1 %s 0 = %d, want 1", "<<", r)
}
y = 1
r = x << y
if r != 2 {
- t.Errorf("1 << 1 = %d, want 2", r)
+ t.Errorf("1 %s 1 = %d, want 2", "<<", r)
}
y = 4294967295
r = x << y
if r != 0 {
- t.Errorf("1 << 4294967295 = %d, want 0", r)
+ t.Errorf("1 %s 4294967295 = %d, want 0", "<<", r)
}
x = 4294967295
y = 0
r = x << y
if r != 4294967295 {
- t.Errorf("4294967295 << 0 = %d, want 4294967295", r)
+ t.Errorf("4294967295 %s 0 = %d, want 4294967295", "<<", r)
}
y = 1
r = x << y
if r != 4294967294 {
- t.Errorf("4294967295 << 1 = %d, want 4294967294", r)
+ t.Errorf("4294967295 %s 1 = %d, want 4294967294", "<<", r)
}
y = 4294967295
r = x << y
if r != 0 {
- t.Errorf("4294967295 << 4294967295 = %d, want 0", r)
+ t.Errorf("4294967295 %s 4294967295 = %d, want 0", "<<", r)
}
}
func TestConstFolduint32uint32rsh(t *testing.T) {
@@ -8413,49 +8413,49 @@ func TestConstFolduint32uint32rsh(t *testing.T) {
y = 0
r = x >> y
if r != 0 {
- t.Errorf("0 >> 0 = %d, want 0", r)
+ t.Errorf("0 %s 0 = %d, want 0", ">>", r)
}
y = 1
r = x >> y
if r != 0 {
- t.Errorf("0 >> 1 = %d, want 0", r)
+ t.Errorf("0 %s 1 = %d, want 0", ">>", r)
}
y = 4294967295
r = x >> y
if r != 0 {
- t.Errorf("0 >> 4294967295 = %d, want 0", r)
+ t.Errorf("0 %s 4294967295 = %d, want 0", ">>", r)
}
x = 1
y = 0
r = x >> y
if r != 1 {
- t.Errorf("1 >> 0 = %d, want 1", r)
+ t.Errorf("1 %s 0 = %d, want 1", ">>", r)
}
y = 1
r = x >> y
if r != 0 {
- t.Errorf("1 >> 1 = %d, want 0", r)
+ t.Errorf("1 %s 1 = %d, want 0", ">>", r)
}
y = 4294967295
r = x >> y
if r != 0 {
- t.Errorf("1 >> 4294967295 = %d, want 0", r)
+ t.Errorf("1 %s 4294967295 = %d, want 0", ">>", r)
}
x = 4294967295
y = 0
r = x >> y
if r != 4294967295 {
- t.Errorf("4294967295 >> 0 = %d, want 4294967295", r)
+ t.Errorf("4294967295 %s 0 = %d, want 4294967295", ">>", r)
}
y = 1
r = x >> y
if r != 2147483647 {
- t.Errorf("4294967295 >> 1 = %d, want 2147483647", r)
+ t.Errorf("4294967295 %s 1 = %d, want 2147483647", ">>", r)
}
y = 4294967295
r = x >> y
if r != 0 {
- t.Errorf("4294967295 >> 4294967295 = %d, want 0", r)
+ t.Errorf("4294967295 %s 4294967295 = %d, want 0", ">>", r)
}
}
func TestConstFolduint32uint16lsh(t *testing.T) {
@@ -8465,49 +8465,49 @@ func TestConstFolduint32uint16lsh(t *testing.T) {
y = 0
r = x << y
if r != 0 {
- t.Errorf("0 << 0 = %d, want 0", r)
+ t.Errorf("0 %s 0 = %d, want 0", "<<", r)
}
y = 1
r = x << y
if r != 0 {
- t.Errorf("0 << 1 = %d, want 0", r)
+ t.Errorf("0 %s 1 = %d, want 0", "<<", r)
}
y = 65535
r = x << y
if r != 0 {
- t.Errorf("0 << 65535 = %d, want 0", r)
+ t.Errorf("0 %s 65535 = %d, want 0", "<<", r)
}
x = 1
y = 0
r = x << y
if r != 1 {
- t.Errorf("1 << 0 = %d, want 1", r)
+ t.Errorf("1 %s 0 = %d, want 1", "<<", r)
}
y = 1
r = x << y
if r != 2 {
- t.Errorf("1 << 1 = %d, want 2", r)
+ t.Errorf("1 %s 1 = %d, want 2", "<<", r)
}
y = 65535
r = x << y
if r != 0 {
- t.Errorf("1 << 65535 = %d, want 0", r)
+ t.Errorf("1 %s 65535 = %d, want 0", "<<", r)
}
x = 4294967295
y = 0
r = x << y
if r != 4294967295 {
- t.Errorf("4294967295 << 0 = %d, want 4294967295", r)
+ t.Errorf("4294967295 %s 0 = %d, want 4294967295", "<<", r)
}
y = 1
r = x << y
if r != 4294967294 {
- t.Errorf("4294967295 << 1 = %d, want 4294967294", r)
+ t.Errorf("4294967295 %s 1 = %d, want 4294967294", "<<", r)
}
y = 65535
r = x << y
if r != 0 {
- t.Errorf("4294967295 << 65535 = %d, want 0", r)
+ t.Errorf("4294967295 %s 65535 = %d, want 0", "<<", r)
}
}
func TestConstFolduint32uint16rsh(t *testing.T) {
@@ -8517,49 +8517,49 @@ func TestConstFolduint32uint16rsh(t *testing.T) {
y = 0
r = x >> y
if r != 0 {
- t.Errorf("0 >> 0 = %d, want 0", r)
+ t.Errorf("0 %s 0 = %d, want 0", ">>", r)
}
y = 1
r = x >> y
if r != 0 {
- t.Errorf("0 >> 1 = %d, want 0", r)
+ t.Errorf("0 %s 1 = %d, want 0", ">>", r)
}
y = 65535
r = x >> y
if r != 0 {
- t.Errorf("0 >> 65535 = %d, want 0", r)
+ t.Errorf("0 %s 65535 = %d, want 0", ">>", r)
}
x = 1
y = 0
r = x >> y
if r != 1 {
- t.Errorf("1 >> 0 = %d, want 1", r)
+ t.Errorf("1 %s 0 = %d, want 1", ">>", r)
}
y = 1
r = x >> y
if r != 0 {
- t.Errorf("1 >> 1 = %d, want 0", r)
+ t.Errorf("1 %s 1 = %d, want 0", ">>", r)
}
y = 65535
r = x >> y
if r != 0 {
- t.Errorf("1 >> 65535 = %d, want 0", r)
+ t.Errorf("1 %s 65535 = %d, want 0", ">>", r)
}
x = 4294967295
y = 0
r = x >> y
if r != 4294967295 {
- t.Errorf("4294967295 >> 0 = %d, want 4294967295", r)
+ t.Errorf("4294967295 %s 0 = %d, want 4294967295", ">>", r)
}
y = 1
r = x >> y
if r != 2147483647 {
- t.Errorf("4294967295 >> 1 = %d, want 2147483647", r)
+ t.Errorf("4294967295 %s 1 = %d, want 2147483647", ">>", r)
}
y = 65535
r = x >> y
if r != 0 {
- t.Errorf("4294967295 >> 65535 = %d, want 0", r)
+ t.Errorf("4294967295 %s 65535 = %d, want 0", ">>", r)
}
}
func TestConstFolduint32uint8lsh(t *testing.T) {
@@ -8569,49 +8569,49 @@ func TestConstFolduint32uint8lsh(t *testing.T) {
y = 0
r = x << y
if r != 0 {
- t.Errorf("0 << 0 = %d, want 0", r)
+ t.Errorf("0 %s 0 = %d, want 0", "<<", r)
}
y = 1
r = x << y
if r != 0 {
- t.Errorf("0 << 1 = %d, want 0", r)
+ t.Errorf("0 %s 1 = %d, want 0", "<<", r)
}
y = 255
r = x << y
if r != 0 {
- t.Errorf("0 << 255 = %d, want 0", r)
+ t.Errorf("0 %s 255 = %d, want 0", "<<", r)
}
x = 1
y = 0
r = x << y
if r != 1 {
- t.Errorf("1 << 0 = %d, want 1", r)
+ t.Errorf("1 %s 0 = %d, want 1", "<<", r)
}
y = 1
r = x << y
if r != 2 {
- t.Errorf("1 << 1 = %d, want 2", r)
+ t.Errorf("1 %s 1 = %d, want 2", "<<", r)
}
y = 255
r = x << y
if r != 0 {
- t.Errorf("1 << 255 = %d, want 0", r)
+ t.Errorf("1 %s 255 = %d, want 0", "<<", r)
}
x = 4294967295
y = 0
r = x << y
if r != 4294967295 {
- t.Errorf("4294967295 << 0 = %d, want 4294967295", r)
+ t.Errorf("4294967295 %s 0 = %d, want 4294967295", "<<", r)
}
y = 1
r = x << y
if r != 4294967294 {
- t.Errorf("4294967295 << 1 = %d, want 4294967294", r)
+ t.Errorf("4294967295 %s 1 = %d, want 4294967294", "<<", r)
}
y = 255
r = x << y
if r != 0 {
- t.Errorf("4294967295 << 255 = %d, want 0", r)
+ t.Errorf("4294967295 %s 255 = %d, want 0", "<<", r)
}
}
func TestConstFolduint32uint8rsh(t *testing.T) {
@@ -8621,49 +8621,49 @@ func TestConstFolduint32uint8rsh(t *testing.T) {
y = 0
r = x >> y
if r != 0 {
- t.Errorf("0 >> 0 = %d, want 0", r)
+ t.Errorf("0 %s 0 = %d, want 0", ">>", r)
}
y = 1
r = x >> y
if r != 0 {
- t.Errorf("0 >> 1 = %d, want 0", r)
+ t.Errorf("0 %s 1 = %d, want 0", ">>", r)
}
y = 255
r = x >> y
if r != 0 {
- t.Errorf("0 >> 255 = %d, want 0", r)
+ t.Errorf("0 %s 255 = %d, want 0", ">>", r)
}
x = 1
y = 0
r = x >> y
if r != 1 {
- t.Errorf("1 >> 0 = %d, want 1", r)
+ t.Errorf("1 %s 0 = %d, want 1", ">>", r)
}
y = 1
r = x >> y
if r != 0 {
- t.Errorf("1 >> 1 = %d, want 0", r)
+ t.Errorf("1 %s 1 = %d, want 0", ">>", r)
}
y = 255
r = x >> y
if r != 0 {
- t.Errorf("1 >> 255 = %d, want 0", r)
+ t.Errorf("1 %s 255 = %d, want 0", ">>", r)
}
x = 4294967295
y = 0
r = x >> y
if r != 4294967295 {
- t.Errorf("4294967295 >> 0 = %d, want 4294967295", r)
+ t.Errorf("4294967295 %s 0 = %d, want 4294967295", ">>", r)
}
y = 1
r = x >> y
if r != 2147483647 {
- t.Errorf("4294967295 >> 1 = %d, want 2147483647", r)
+ t.Errorf("4294967295 %s 1 = %d, want 2147483647", ">>", r)
}
y = 255
r = x >> y
if r != 0 {
- t.Errorf("4294967295 >> 255 = %d, want 0", r)
+ t.Errorf("4294967295 %s 255 = %d, want 0", ">>", r)
}
}
func TestConstFoldint32uint64lsh(t *testing.T) {
@@ -8673,127 +8673,127 @@ func TestConstFoldint32uint64lsh(t *testing.T) {
y = 0
r = x << y
if r != -2147483648 {
- t.Errorf("-2147483648 << 0 = %d, want -2147483648", r)
+ t.Errorf("-2147483648 %s 0 = %d, want -2147483648", "<<", r)
}
y = 1
r = x << y
if r != 0 {
- t.Errorf("-2147483648 << 1 = %d, want 0", r)
+ t.Errorf("-2147483648 %s 1 = %d, want 0", "<<", r)
}
y = 4294967296
r = x << y
if r != 0 {
- t.Errorf("-2147483648 << 4294967296 = %d, want 0", r)
+ t.Errorf("-2147483648 %s 4294967296 = %d, want 0", "<<", r)
}
y = 18446744073709551615
r = x << y
if r != 0 {
- t.Errorf("-2147483648 << 18446744073709551615 = %d, want 0", r)
+ t.Errorf("-2147483648 %s 18446744073709551615 = %d, want 0", "<<", r)
}
x = -2147483647
y = 0
r = x << y
if r != -2147483647 {
- t.Errorf("-2147483647 << 0 = %d, want -2147483647", r)
+ t.Errorf("-2147483647 %s 0 = %d, want -2147483647", "<<", r)
}
y = 1
r = x << y
if r != 2 {
- t.Errorf("-2147483647 << 1 = %d, want 2", r)
+ t.Errorf("-2147483647 %s 1 = %d, want 2", "<<", r)
}
y = 4294967296
r = x << y
if r != 0 {
- t.Errorf("-2147483647 << 4294967296 = %d, want 0", r)
+ t.Errorf("-2147483647 %s 4294967296 = %d, want 0", "<<", r)
}
y = 18446744073709551615
r = x << y
if r != 0 {
- t.Errorf("-2147483647 << 18446744073709551615 = %d, want 0", r)
+ t.Errorf("-2147483647 %s 18446744073709551615 = %d, want 0", "<<", r)
}
x = -1
y = 0
r = x << y
if r != -1 {
- t.Errorf("-1 << 0 = %d, want -1", r)
+ t.Errorf("-1 %s 0 = %d, want -1", "<<", r)
}
y = 1
r = x << y
if r != -2 {
- t.Errorf("-1 << 1 = %d, want -2", r)
+ t.Errorf("-1 %s 1 = %d, want -2", "<<", r)
}
y = 4294967296
r = x << y
if r != 0 {
- t.Errorf("-1 << 4294967296 = %d, want 0", r)
+ t.Errorf("-1 %s 4294967296 = %d, want 0", "<<", r)
}
y = 18446744073709551615
r = x << y
if r != 0 {
- t.Errorf("-1 << 18446744073709551615 = %d, want 0", r)
+ t.Errorf("-1 %s 18446744073709551615 = %d, want 0", "<<", r)
}
x = 0
y = 0
r = x << y
if r != 0 {
- t.Errorf("0 << 0 = %d, want 0", r)
+ t.Errorf("0 %s 0 = %d, want 0", "<<", r)
}
y = 1
r = x << y
if r != 0 {
- t.Errorf("0 << 1 = %d, want 0", r)
+ t.Errorf("0 %s 1 = %d, want 0", "<<", r)
}
y = 4294967296
r = x << y
if r != 0 {
- t.Errorf("0 << 4294967296 = %d, want 0", r)
+ t.Errorf("0 %s 4294967296 = %d, want 0", "<<", r)
}
y = 18446744073709551615
r = x << y
if r != 0 {
- t.Errorf("0 << 18446744073709551615 = %d, want 0", r)
+ t.Errorf("0 %s 18446744073709551615 = %d, want 0", "<<", r)
}
x = 1
y = 0
r = x << y
if r != 1 {
- t.Errorf("1 << 0 = %d, want 1", r)
+ t.Errorf("1 %s 0 = %d, want 1", "<<", r)
}
y = 1
r = x << y
if r != 2 {
- t.Errorf("1 << 1 = %d, want 2", r)
+ t.Errorf("1 %s 1 = %d, want 2", "<<", r)
}
y = 4294967296
r = x << y
if r != 0 {
- t.Errorf("1 << 4294967296 = %d, want 0", r)
+ t.Errorf("1 %s 4294967296 = %d, want 0", "<<", r)
}
y = 18446744073709551615
r = x << y
if r != 0 {
- t.Errorf("1 << 18446744073709551615 = %d, want 0", r)
+ t.Errorf("1 %s 18446744073709551615 = %d, want 0", "<<", r)
}
x = 2147483647
y = 0
r = x << y
if r != 2147483647 {
- t.Errorf("2147483647 << 0 = %d, want 2147483647", r)
+ t.Errorf("2147483647 %s 0 = %d, want 2147483647", "<<", r)
}
y = 1
r = x << y
if r != -2 {
- t.Errorf("2147483647 << 1 = %d, want -2", r)
+ t.Errorf("2147483647 %s 1 = %d, want -2", "<<", r)
}
y = 4294967296
r = x << y
if r != 0 {
- t.Errorf("2147483647 << 4294967296 = %d, want 0", r)
+ t.Errorf("2147483647 %s 4294967296 = %d, want 0", "<<", r)
}
y = 18446744073709551615
r = x << y
if r != 0 {
- t.Errorf("2147483647 << 18446744073709551615 = %d, want 0", r)
+ t.Errorf("2147483647 %s 18446744073709551615 = %d, want 0", "<<", r)
}
}
func TestConstFoldint32uint64rsh(t *testing.T) {
@@ -8803,127 +8803,127 @@ func TestConstFoldint32uint64rsh(t *testing.T) {
y = 0
r = x >> y
if r != -2147483648 {
- t.Errorf("-2147483648 >> 0 = %d, want -2147483648", r)
+ t.Errorf("-2147483648 %s 0 = %d, want -2147483648", ">>", r)
}
y = 1
r = x >> y
if r != -1073741824 {
- t.Errorf("-2147483648 >> 1 = %d, want -1073741824", r)
+ t.Errorf("-2147483648 %s 1 = %d, want -1073741824", ">>", r)
}
y = 4294967296
r = x >> y
if r != -1 {
- t.Errorf("-2147483648 >> 4294967296 = %d, want -1", r)
+ t.Errorf("-2147483648 %s 4294967296 = %d, want -1", ">>", r)
}
y = 18446744073709551615
r = x >> y
if r != -1 {
- t.Errorf("-2147483648 >> 18446744073709551615 = %d, want -1", r)
+ t.Errorf("-2147483648 %s 18446744073709551615 = %d, want -1", ">>", r)
}
x = -2147483647
y = 0
r = x >> y
if r != -2147483647 {
- t.Errorf("-2147483647 >> 0 = %d, want -2147483647", r)
+ t.Errorf("-2147483647 %s 0 = %d, want -2147483647", ">>", r)
}
y = 1
r = x >> y
if r != -1073741824 {
- t.Errorf("-2147483647 >> 1 = %d, want -1073741824", r)
+ t.Errorf("-2147483647 %s 1 = %d, want -1073741824", ">>", r)
}
y = 4294967296
r = x >> y
if r != -1 {
- t.Errorf("-2147483647 >> 4294967296 = %d, want -1", r)
+ t.Errorf("-2147483647 %s 4294967296 = %d, want -1", ">>", r)
}
y = 18446744073709551615
r = x >> y
if r != -1 {
- t.Errorf("-2147483647 >> 18446744073709551615 = %d, want -1", r)
+ t.Errorf("-2147483647 %s 18446744073709551615 = %d, want -1", ">>", r)
}
x = -1
y = 0
r = x >> y
if r != -1 {
- t.Errorf("-1 >> 0 = %d, want -1", r)
+ t.Errorf("-1 %s 0 = %d, want -1", ">>", r)
}
y = 1
r = x >> y
if r != -1 {
- t.Errorf("-1 >> 1 = %d, want -1", r)
+ t.Errorf("-1 %s 1 = %d, want -1", ">>", r)
}
y = 4294967296
r = x >> y
if r != -1 {
- t.Errorf("-1 >> 4294967296 = %d, want -1", r)
+ t.Errorf("-1 %s 4294967296 = %d, want -1", ">>", r)
}
y = 18446744073709551615
r = x >> y
if r != -1 {
- t.Errorf("-1 >> 18446744073709551615 = %d, want -1", r)
+ t.Errorf("-1 %s 18446744073709551615 = %d, want -1", ">>", r)
}
x = 0
y = 0
r = x >> y
if r != 0 {
- t.Errorf("0 >> 0 = %d, want 0", r)
+ t.Errorf("0 %s 0 = %d, want 0", ">>", r)
}
y = 1
r = x >> y
if r != 0 {
- t.Errorf("0 >> 1 = %d, want 0", r)
+ t.Errorf("0 %s 1 = %d, want 0", ">>", r)
}
y = 4294967296
r = x >> y
if r != 0 {
- t.Errorf("0 >> 4294967296 = %d, want 0", r)
+ t.Errorf("0 %s 4294967296 = %d, want 0", ">>", r)
}
y = 18446744073709551615
r = x >> y
if r != 0 {
- t.Errorf("0 >> 18446744073709551615 = %d, want 0", r)
+ t.Errorf("0 %s 18446744073709551615 = %d, want 0", ">>", r)
}
x = 1
y = 0
r = x >> y
if r != 1 {
- t.Errorf("1 >> 0 = %d, want 1", r)
+ t.Errorf("1 %s 0 = %d, want 1", ">>", r)
}
y = 1
r = x >> y
if r != 0 {
- t.Errorf("1 >> 1 = %d, want 0", r)
+ t.Errorf("1 %s 1 = %d, want 0", ">>", r)
}
y = 4294967296
r = x >> y
if r != 0 {
- t.Errorf("1 >> 4294967296 = %d, want 0", r)
+ t.Errorf("1 %s 4294967296 = %d, want 0", ">>", r)
}
y = 18446744073709551615
r = x >> y
if r != 0 {
- t.Errorf("1 >> 18446744073709551615 = %d, want 0", r)
+ t.Errorf("1 %s 18446744073709551615 = %d, want 0", ">>", r)
}
x = 2147483647
y = 0
r = x >> y
if r != 2147483647 {
- t.Errorf("2147483647 >> 0 = %d, want 2147483647", r)
+ t.Errorf("2147483647 %s 0 = %d, want 2147483647", ">>", r)
}
y = 1
r = x >> y
if r != 1073741823 {
- t.Errorf("2147483647 >> 1 = %d, want 1073741823", r)
+ t.Errorf("2147483647 %s 1 = %d, want 1073741823", ">>", r)
}
y = 4294967296
r = x >> y
if r != 0 {
- t.Errorf("2147483647 >> 4294967296 = %d, want 0", r)
+ t.Errorf("2147483647 %s 4294967296 = %d, want 0", ">>", r)
}
y = 18446744073709551615
r = x >> y
if r != 0 {
- t.Errorf("2147483647 >> 18446744073709551615 = %d, want 0", r)
+ t.Errorf("2147483647 %s 18446744073709551615 = %d, want 0", ">>", r)
}
}
func TestConstFoldint32uint32lsh(t *testing.T) {
@@ -8933,97 +8933,97 @@ func TestConstFoldint32uint32lsh(t *testing.T) {
y = 0
r = x << y
if r != -2147483648 {
- t.Errorf("-2147483648 << 0 = %d, want -2147483648", r)
+ t.Errorf("-2147483648 %s 0 = %d, want -2147483648", "<<", r)
}
y = 1
r = x << y
if r != 0 {
- t.Errorf("-2147483648 << 1 = %d, want 0", r)
+ t.Errorf("-2147483648 %s 1 = %d, want 0", "<<", r)
}
y = 4294967295
r = x << y
if r != 0 {
- t.Errorf("-2147483648 << 4294967295 = %d, want 0", r)
+ t.Errorf("-2147483648 %s 4294967295 = %d, want 0", "<<", r)
}
x = -2147483647
y = 0
r = x << y
if r != -2147483647 {
- t.Errorf("-2147483647 << 0 = %d, want -2147483647", r)
+ t.Errorf("-2147483647 %s 0 = %d, want -2147483647", "<<", r)
}
y = 1
r = x << y
if r != 2 {
- t.Errorf("-2147483647 << 1 = %d, want 2", r)
+ t.Errorf("-2147483647 %s 1 = %d, want 2", "<<", r)
}
y = 4294967295
r = x << y
if r != 0 {
- t.Errorf("-2147483647 << 4294967295 = %d, want 0", r)
+ t.Errorf("-2147483647 %s 4294967295 = %d, want 0", "<<", r)
}
x = -1
y = 0
r = x << y
if r != -1 {
- t.Errorf("-1 << 0 = %d, want -1", r)
+ t.Errorf("-1 %s 0 = %d, want -1", "<<", r)
}
y = 1
r = x << y
if r != -2 {
- t.Errorf("-1 << 1 = %d, want -2", r)
+ t.Errorf("-1 %s 1 = %d, want -2", "<<", r)
}
y = 4294967295
r = x << y
if r != 0 {
- t.Errorf("-1 << 4294967295 = %d, want 0", r)
+ t.Errorf("-1 %s 4294967295 = %d, want 0", "<<", r)
}
x = 0
y = 0
r = x << y
if r != 0 {
- t.Errorf("0 << 0 = %d, want 0", r)
+ t.Errorf("0 %s 0 = %d, want 0", "<<", r)
}
y = 1
r = x << y
if r != 0 {
- t.Errorf("0 << 1 = %d, want 0", r)
+ t.Errorf("0 %s 1 = %d, want 0", "<<", r)
}
y = 4294967295
r = x << y
if r != 0 {
- t.Errorf("0 << 4294967295 = %d, want 0", r)
+ t.Errorf("0 %s 4294967295 = %d, want 0", "<<", r)
}
x = 1
y = 0
r = x << y
if r != 1 {
- t.Errorf("1 << 0 = %d, want 1", r)
+ t.Errorf("1 %s 0 = %d, want 1", "<<", r)
}
y = 1
r = x << y
if r != 2 {
- t.Errorf("1 << 1 = %d, want 2", r)
+ t.Errorf("1 %s 1 = %d, want 2", "<<", r)
}
y = 4294967295
r = x << y
if r != 0 {
- t.Errorf("1 << 4294967295 = %d, want 0", r)
+ t.Errorf("1 %s 4294967295 = %d, want 0", "<<", r)
}
x = 2147483647
y = 0
r = x << y
if r != 2147483647 {
- t.Errorf("2147483647 << 0 = %d, want 2147483647", r)
+ t.Errorf("2147483647 %s 0 = %d, want 2147483647", "<<", r)
}
y = 1
r = x << y
if r != -2 {
- t.Errorf("2147483647 << 1 = %d, want -2", r)
+ t.Errorf("2147483647 %s 1 = %d, want -2", "<<", r)
}
y = 4294967295
r = x << y
if r != 0 {
- t.Errorf("2147483647 << 4294967295 = %d, want 0", r)
+ t.Errorf("2147483647 %s 4294967295 = %d, want 0", "<<", r)
}
}
func TestConstFoldint32uint32rsh(t *testing.T) {
@@ -9033,97 +9033,97 @@ func TestConstFoldint32uint32rsh(t *testing.T) {
y = 0
r = x >> y
if r != -2147483648 {
- t.Errorf("-2147483648 >> 0 = %d, want -2147483648", r)
+ t.Errorf("-2147483648 %s 0 = %d, want -2147483648", ">>", r)
}
y = 1
r = x >> y
if r != -1073741824 {
- t.Errorf("-2147483648 >> 1 = %d, want -1073741824", r)
+ t.Errorf("-2147483648 %s 1 = %d, want -1073741824", ">>", r)
}
y = 4294967295
r = x >> y
if r != -1 {
- t.Errorf("-2147483648 >> 4294967295 = %d, want -1", r)
+ t.Errorf("-2147483648 %s 4294967295 = %d, want -1", ">>", r)
}
x = -2147483647
y = 0
r = x >> y
if r != -2147483647 {
- t.Errorf("-2147483647 >> 0 = %d, want -2147483647", r)
+ t.Errorf("-2147483647 %s 0 = %d, want -2147483647", ">>", r)
}
y = 1
r = x >> y
if r != -1073741824 {
- t.Errorf("-2147483647 >> 1 = %d, want -1073741824", r)
+ t.Errorf("-2147483647 %s 1 = %d, want -1073741824", ">>", r)
}
y = 4294967295
r = x >> y
if r != -1 {
- t.Errorf("-2147483647 >> 4294967295 = %d, want -1", r)
+ t.Errorf("-2147483647 %s 4294967295 = %d, want -1", ">>", r)
}
x = -1
y = 0
r = x >> y
if r != -1 {
- t.Errorf("-1 >> 0 = %d, want -1", r)
+ t.Errorf("-1 %s 0 = %d, want -1", ">>", r)
}
y = 1
r = x >> y
if r != -1 {
- t.Errorf("-1 >> 1 = %d, want -1", r)
+ t.Errorf("-1 %s 1 = %d, want -1", ">>", r)
}
y = 4294967295
r = x >> y
if r != -1 {
- t.Errorf("-1 >> 4294967295 = %d, want -1", r)
+ t.Errorf("-1 %s 4294967295 = %d, want -1", ">>", r)
}
x = 0
y = 0
r = x >> y
if r != 0 {
- t.Errorf("0 >> 0 = %d, want 0", r)
+ t.Errorf("0 %s 0 = %d, want 0", ">>", r)
}
y = 1
r = x >> y
if r != 0 {
- t.Errorf("0 >> 1 = %d, want 0", r)
+ t.Errorf("0 %s 1 = %d, want 0", ">>", r)
}
y = 4294967295
r = x >> y
if r != 0 {
- t.Errorf("0 >> 4294967295 = %d, want 0", r)
+ t.Errorf("0 %s 4294967295 = %d, want 0", ">>", r)
}
x = 1
y = 0
r = x >> y
if r != 1 {
- t.Errorf("1 >> 0 = %d, want 1", r)
+ t.Errorf("1 %s 0 = %d, want 1", ">>", r)
}
y = 1
r = x >> y
if r != 0 {
- t.Errorf("1 >> 1 = %d, want 0", r)
+ t.Errorf("1 %s 1 = %d, want 0", ">>", r)
}
y = 4294967295
r = x >> y
if r != 0 {
- t.Errorf("1 >> 4294967295 = %d, want 0", r)
+ t.Errorf("1 %s 4294967295 = %d, want 0", ">>", r)
}
x = 2147483647
y = 0
r = x >> y
if r != 2147483647 {
- t.Errorf("2147483647 >> 0 = %d, want 2147483647", r)
+ t.Errorf("2147483647 %s 0 = %d, want 2147483647", ">>", r)
}
y = 1
r = x >> y
if r != 1073741823 {
- t.Errorf("2147483647 >> 1 = %d, want 1073741823", r)
+ t.Errorf("2147483647 %s 1 = %d, want 1073741823", ">>", r)
}
y = 4294967295
r = x >> y
if r != 0 {
- t.Errorf("2147483647 >> 4294967295 = %d, want 0", r)
+ t.Errorf("2147483647 %s 4294967295 = %d, want 0", ">>", r)
}
}
func TestConstFoldint32uint16lsh(t *testing.T) {
@@ -9133,97 +9133,97 @@ func TestConstFoldint32uint16lsh(t *testing.T) {
y = 0
r = x << y
if r != -2147483648 {
- t.Errorf("-2147483648 << 0 = %d, want -2147483648", r)
+ t.Errorf("-2147483648 %s 0 = %d, want -2147483648", "<<", r)
}
y = 1
r = x << y
if r != 0 {
- t.Errorf("-2147483648 << 1 = %d, want 0", r)
+ t.Errorf("-2147483648 %s 1 = %d, want 0", "<<", r)
}
y = 65535
r = x << y
if r != 0 {
- t.Errorf("-2147483648 << 65535 = %d, want 0", r)
+ t.Errorf("-2147483648 %s 65535 = %d, want 0", "<<", r)
}
x = -2147483647
y = 0
r = x << y
if r != -2147483647 {
- t.Errorf("-2147483647 << 0 = %d, want -2147483647", r)
+ t.Errorf("-2147483647 %s 0 = %d, want -2147483647", "<<", r)
}
y = 1
r = x << y
if r != 2 {
- t.Errorf("-2147483647 << 1 = %d, want 2", r)
+ t.Errorf("-2147483647 %s 1 = %d, want 2", "<<", r)
}
y = 65535
r = x << y
if r != 0 {
- t.Errorf("-2147483647 << 65535 = %d, want 0", r)
+ t.Errorf("-2147483647 %s 65535 = %d, want 0", "<<", r)
}
x = -1
y = 0
r = x << y
if r != -1 {
- t.Errorf("-1 << 0 = %d, want -1", r)
+ t.Errorf("-1 %s 0 = %d, want -1", "<<", r)
}
y = 1
r = x << y
if r != -2 {
- t.Errorf("-1 << 1 = %d, want -2", r)
+ t.Errorf("-1 %s 1 = %d, want -2", "<<", r)
}
y = 65535
r = x << y
if r != 0 {
- t.Errorf("-1 << 65535 = %d, want 0", r)
+ t.Errorf("-1 %s 65535 = %d, want 0", "<<", r)
}
x = 0
y = 0
r = x << y
if r != 0 {
- t.Errorf("0 << 0 = %d, want 0", r)
+ t.Errorf("0 %s 0 = %d, want 0", "<<", r)
}
y = 1
r = x << y
if r != 0 {
- t.Errorf("0 << 1 = %d, want 0", r)
+ t.Errorf("0 %s 1 = %d, want 0", "<<", r)
}
y = 65535
r = x << y
if r != 0 {
- t.Errorf("0 << 65535 = %d, want 0", r)
+ t.Errorf("0 %s 65535 = %d, want 0", "<<", r)
}
x = 1
y = 0
r = x << y
if r != 1 {
- t.Errorf("1 << 0 = %d, want 1", r)
+ t.Errorf("1 %s 0 = %d, want 1", "<<", r)
}
y = 1
r = x << y
if r != 2 {
- t.Errorf("1 << 1 = %d, want 2", r)
+ t.Errorf("1 %s 1 = %d, want 2", "<<", r)
}
y = 65535
r = x << y
if r != 0 {
- t.Errorf("1 << 65535 = %d, want 0", r)
+ t.Errorf("1 %s 65535 = %d, want 0", "<<", r)
}
x = 2147483647
y = 0
r = x << y
if r != 2147483647 {
- t.Errorf("2147483647 << 0 = %d, want 2147483647", r)
+ t.Errorf("2147483647 %s 0 = %d, want 2147483647", "<<", r)
}
y = 1
r = x << y
if r != -2 {
- t.Errorf("2147483647 << 1 = %d, want -2", r)
+ t.Errorf("2147483647 %s 1 = %d, want -2", "<<", r)
}
y = 65535
r = x << y
if r != 0 {
- t.Errorf("2147483647 << 65535 = %d, want 0", r)
+ t.Errorf("2147483647 %s 65535 = %d, want 0", "<<", r)
}
}
func TestConstFoldint32uint16rsh(t *testing.T) {
@@ -9233,97 +9233,97 @@ func TestConstFoldint32uint16rsh(t *testing.T) {
y = 0
r = x >> y
if r != -2147483648 {
- t.Errorf("-2147483648 >> 0 = %d, want -2147483648", r)
+ t.Errorf("-2147483648 %s 0 = %d, want -2147483648", ">>", r)
}
y = 1
r = x >> y
if r != -1073741824 {
- t.Errorf("-2147483648 >> 1 = %d, want -1073741824", r)
+ t.Errorf("-2147483648 %s 1 = %d, want -1073741824", ">>", r)
}
y = 65535
r = x >> y
if r != -1 {
- t.Errorf("-2147483648 >> 65535 = %d, want -1", r)
+ t.Errorf("-2147483648 %s 65535 = %d, want -1", ">>", r)
}
x = -2147483647
y = 0
r = x >> y
if r != -2147483647 {
- t.Errorf("-2147483647 >> 0 = %d, want -2147483647", r)
+ t.Errorf("-2147483647 %s 0 = %d, want -2147483647", ">>", r)
}
y = 1
r = x >> y
if r != -1073741824 {
- t.Errorf("-2147483647 >> 1 = %d, want -1073741824", r)
+ t.Errorf("-2147483647 %s 1 = %d, want -1073741824", ">>", r)
}
y = 65535
r = x >> y
if r != -1 {
- t.Errorf("-2147483647 >> 65535 = %d, want -1", r)
+ t.Errorf("-2147483647 %s 65535 = %d, want -1", ">>", r)
}
x = -1
y = 0
r = x >> y
if r != -1 {
- t.Errorf("-1 >> 0 = %d, want -1", r)
+ t.Errorf("-1 %s 0 = %d, want -1", ">>", r)
}
y = 1
r = x >> y
if r != -1 {
- t.Errorf("-1 >> 1 = %d, want -1", r)
+ t.Errorf("-1 %s 1 = %d, want -1", ">>", r)
}
y = 65535
r = x >> y
if r != -1 {
- t.Errorf("-1 >> 65535 = %d, want -1", r)
+ t.Errorf("-1 %s 65535 = %d, want -1", ">>", r)
}
x = 0
y = 0
r = x >> y
if r != 0 {
- t.Errorf("0 >> 0 = %d, want 0", r)
+ t.Errorf("0 %s 0 = %d, want 0", ">>", r)
}
y = 1
r = x >> y
if r != 0 {
- t.Errorf("0 >> 1 = %d, want 0", r)
+ t.Errorf("0 %s 1 = %d, want 0", ">>", r)
}
y = 65535
r = x >> y
if r != 0 {
- t.Errorf("0 >> 65535 = %d, want 0", r)
+ t.Errorf("0 %s 65535 = %d, want 0", ">>", r)
}
x = 1
y = 0
r = x >> y
if r != 1 {
- t.Errorf("1 >> 0 = %d, want 1", r)
+ t.Errorf("1 %s 0 = %d, want 1", ">>", r)
}
y = 1
r = x >> y
if r != 0 {
- t.Errorf("1 >> 1 = %d, want 0", r)
+ t.Errorf("1 %s 1 = %d, want 0", ">>", r)
}
y = 65535
r = x >> y
if r != 0 {
- t.Errorf("1 >> 65535 = %d, want 0", r)
+ t.Errorf("1 %s 65535 = %d, want 0", ">>", r)
}
x = 2147483647
y = 0
r = x >> y
if r != 2147483647 {
- t.Errorf("2147483647 >> 0 = %d, want 2147483647", r)
+ t.Errorf("2147483647 %s 0 = %d, want 2147483647", ">>", r)
}
y = 1
r = x >> y
if r != 1073741823 {
- t.Errorf("2147483647 >> 1 = %d, want 1073741823", r)
+ t.Errorf("2147483647 %s 1 = %d, want 1073741823", ">>", r)
}
y = 65535
r = x >> y
if r != 0 {
- t.Errorf("2147483647 >> 65535 = %d, want 0", r)
+ t.Errorf("2147483647 %s 65535 = %d, want 0", ">>", r)
}
}
func TestConstFoldint32uint8lsh(t *testing.T) {
@@ -9333,97 +9333,97 @@ func TestConstFoldint32uint8lsh(t *testing.T) {
y = 0
r = x << y
if r != -2147483648 {
- t.Errorf("-2147483648 << 0 = %d, want -2147483648", r)
+ t.Errorf("-2147483648 %s 0 = %d, want -2147483648", "<<", r)
}
y = 1
r = x << y
if r != 0 {
- t.Errorf("-2147483648 << 1 = %d, want 0", r)
+ t.Errorf("-2147483648 %s 1 = %d, want 0", "<<", r)
}
y = 255
r = x << y
if r != 0 {
- t.Errorf("-2147483648 << 255 = %d, want 0", r)
+ t.Errorf("-2147483648 %s 255 = %d, want 0", "<<", r)
}
x = -2147483647
y = 0
r = x << y
if r != -2147483647 {
- t.Errorf("-2147483647 << 0 = %d, want -2147483647", r)
+ t.Errorf("-2147483647 %s 0 = %d, want -2147483647", "<<", r)
}
y = 1
r = x << y
if r != 2 {
- t.Errorf("-2147483647 << 1 = %d, want 2", r)
+ t.Errorf("-2147483647 %s 1 = %d, want 2", "<<", r)
}
y = 255
r = x << y
if r != 0 {
- t.Errorf("-2147483647 << 255 = %d, want 0", r)
+ t.Errorf("-2147483647 %s 255 = %d, want 0", "<<", r)
}
x = -1
y = 0
r = x << y
if r != -1 {
- t.Errorf("-1 << 0 = %d, want -1", r)
+ t.Errorf("-1 %s 0 = %d, want -1", "<<", r)
}
y = 1
r = x << y
if r != -2 {
- t.Errorf("-1 << 1 = %d, want -2", r)
+ t.Errorf("-1 %s 1 = %d, want -2", "<<", r)
}
y = 255
r = x << y
if r != 0 {
- t.Errorf("-1 << 255 = %d, want 0", r)
+ t.Errorf("-1 %s 255 = %d, want 0", "<<", r)
}
x = 0
y = 0
r = x << y
if r != 0 {
- t.Errorf("0 << 0 = %d, want 0", r)
+ t.Errorf("0 %s 0 = %d, want 0", "<<", r)
}
y = 1
r = x << y
if r != 0 {
- t.Errorf("0 << 1 = %d, want 0", r)
+ t.Errorf("0 %s 1 = %d, want 0", "<<", r)
}
y = 255
r = x << y
if r != 0 {
- t.Errorf("0 << 255 = %d, want 0", r)
+ t.Errorf("0 %s 255 = %d, want 0", "<<", r)
}
x = 1
y = 0
r = x << y
if r != 1 {
- t.Errorf("1 << 0 = %d, want 1", r)
+ t.Errorf("1 %s 0 = %d, want 1", "<<", r)
}
y = 1
r = x << y
if r != 2 {
- t.Errorf("1 << 1 = %d, want 2", r)
+ t.Errorf("1 %s 1 = %d, want 2", "<<", r)
}
y = 255
r = x << y
if r != 0 {
- t.Errorf("1 << 255 = %d, want 0", r)
+ t.Errorf("1 %s 255 = %d, want 0", "<<", r)
}
x = 2147483647
y = 0
r = x << y
if r != 2147483647 {
- t.Errorf("2147483647 << 0 = %d, want 2147483647", r)
+ t.Errorf("2147483647 %s 0 = %d, want 2147483647", "<<", r)
}
y = 1
r = x << y
if r != -2 {
- t.Errorf("2147483647 << 1 = %d, want -2", r)
+ t.Errorf("2147483647 %s 1 = %d, want -2", "<<", r)
}
y = 255
r = x << y
if r != 0 {
- t.Errorf("2147483647 << 255 = %d, want 0", r)
+ t.Errorf("2147483647 %s 255 = %d, want 0", "<<", r)
}
}
func TestConstFoldint32uint8rsh(t *testing.T) {
@@ -9433,97 +9433,97 @@ func TestConstFoldint32uint8rsh(t *testing.T) {
y = 0
r = x >> y
if r != -2147483648 {
- t.Errorf("-2147483648 >> 0 = %d, want -2147483648", r)
+ t.Errorf("-2147483648 %s 0 = %d, want -2147483648", ">>", r)
}
y = 1
r = x >> y
if r != -1073741824 {
- t.Errorf("-2147483648 >> 1 = %d, want -1073741824", r)
+ t.Errorf("-2147483648 %s 1 = %d, want -1073741824", ">>", r)
}
y = 255
r = x >> y
if r != -1 {
- t.Errorf("-2147483648 >> 255 = %d, want -1", r)
+ t.Errorf("-2147483648 %s 255 = %d, want -1", ">>", r)
}
x = -2147483647
y = 0
r = x >> y
if r != -2147483647 {
- t.Errorf("-2147483647 >> 0 = %d, want -2147483647", r)
+ t.Errorf("-2147483647 %s 0 = %d, want -2147483647", ">>", r)
}
y = 1
r = x >> y
if r != -1073741824 {
- t.Errorf("-2147483647 >> 1 = %d, want -1073741824", r)
+ t.Errorf("-2147483647 %s 1 = %d, want -1073741824", ">>", r)
}
y = 255
r = x >> y
if r != -1 {
- t.Errorf("-2147483647 >> 255 = %d, want -1", r)
+ t.Errorf("-2147483647 %s 255 = %d, want -1", ">>", r)
}
x = -1
y = 0
r = x >> y
if r != -1 {
- t.Errorf("-1 >> 0 = %d, want -1", r)
+ t.Errorf("-1 %s 0 = %d, want -1", ">>", r)
}
y = 1
r = x >> y
if r != -1 {
- t.Errorf("-1 >> 1 = %d, want -1", r)
+ t.Errorf("-1 %s 1 = %d, want -1", ">>", r)
}
y = 255
r = x >> y
if r != -1 {
- t.Errorf("-1 >> 255 = %d, want -1", r)
+ t.Errorf("-1 %s 255 = %d, want -1", ">>", r)
}
x = 0
y = 0
r = x >> y
if r != 0 {
- t.Errorf("0 >> 0 = %d, want 0", r)
+ t.Errorf("0 %s 0 = %d, want 0", ">>", r)
}
y = 1
r = x >> y
if r != 0 {
- t.Errorf("0 >> 1 = %d, want 0", r)
+ t.Errorf("0 %s 1 = %d, want 0", ">>", r)
}
y = 255
r = x >> y
if r != 0 {
- t.Errorf("0 >> 255 = %d, want 0", r)
+ t.Errorf("0 %s 255 = %d, want 0", ">>", r)
}
x = 1
y = 0
r = x >> y
if r != 1 {
- t.Errorf("1 >> 0 = %d, want 1", r)
+ t.Errorf("1 %s 0 = %d, want 1", ">>", r)
}
y = 1
r = x >> y
if r != 0 {
- t.Errorf("1 >> 1 = %d, want 0", r)
+ t.Errorf("1 %s 1 = %d, want 0", ">>", r)
}
y = 255
r = x >> y
if r != 0 {
- t.Errorf("1 >> 255 = %d, want 0", r)
+ t.Errorf("1 %s 255 = %d, want 0", ">>", r)
}
x = 2147483647
y = 0
r = x >> y
if r != 2147483647 {
- t.Errorf("2147483647 >> 0 = %d, want 2147483647", r)
+ t.Errorf("2147483647 %s 0 = %d, want 2147483647", ">>", r)
}
y = 1
r = x >> y
if r != 1073741823 {
- t.Errorf("2147483647 >> 1 = %d, want 1073741823", r)
+ t.Errorf("2147483647 %s 1 = %d, want 1073741823", ">>", r)
}
y = 255
r = x >> y
if r != 0 {
- t.Errorf("2147483647 >> 255 = %d, want 0", r)
+ t.Errorf("2147483647 %s 255 = %d, want 0", ">>", r)
}
}
func TestConstFolduint16uint64lsh(t *testing.T) {
@@ -9533,64 +9533,64 @@ func TestConstFolduint16uint64lsh(t *testing.T) {
y = 0
r = x << y
if r != 0 {
- t.Errorf("0 << 0 = %d, want 0", r)
+ t.Errorf("0 %s 0 = %d, want 0", "<<", r)
}
y = 1
r = x << y
if r != 0 {
- t.Errorf("0 << 1 = %d, want 0", r)
+ t.Errorf("0 %s 1 = %d, want 0", "<<", r)
}
y = 4294967296
r = x << y
if r != 0 {
- t.Errorf("0 << 4294967296 = %d, want 0", r)
+ t.Errorf("0 %s 4294967296 = %d, want 0", "<<", r)
}
y = 18446744073709551615
r = x << y
if r != 0 {
- t.Errorf("0 << 18446744073709551615 = %d, want 0", r)
+ t.Errorf("0 %s 18446744073709551615 = %d, want 0", "<<", r)
}
x = 1
y = 0
r = x << y
if r != 1 {
- t.Errorf("1 << 0 = %d, want 1", r)
+ t.Errorf("1 %s 0 = %d, want 1", "<<", r)
}
y = 1
r = x << y
if r != 2 {
- t.Errorf("1 << 1 = %d, want 2", r)
+ t.Errorf("1 %s 1 = %d, want 2", "<<", r)
}
y = 4294967296
r = x << y
if r != 0 {
- t.Errorf("1 << 4294967296 = %d, want 0", r)
+ t.Errorf("1 %s 4294967296 = %d, want 0", "<<", r)
}
y = 18446744073709551615
r = x << y
if r != 0 {
- t.Errorf("1 << 18446744073709551615 = %d, want 0", r)
+ t.Errorf("1 %s 18446744073709551615 = %d, want 0", "<<", r)
}
x = 65535
y = 0
r = x << y
if r != 65535 {
- t.Errorf("65535 << 0 = %d, want 65535", r)
+ t.Errorf("65535 %s 0 = %d, want 65535", "<<", r)
}
y = 1
r = x << y
if r != 65534 {
- t.Errorf("65535 << 1 = %d, want 65534", r)
+ t.Errorf("65535 %s 1 = %d, want 65534", "<<", r)
}
y = 4294967296
r = x << y
if r != 0 {
- t.Errorf("65535 << 4294967296 = %d, want 0", r)
+ t.Errorf("65535 %s 4294967296 = %d, want 0", "<<", r)
}
y = 18446744073709551615
r = x << y
if r != 0 {
- t.Errorf("65535 << 18446744073709551615 = %d, want 0", r)
+ t.Errorf("65535 %s 18446744073709551615 = %d, want 0", "<<", r)
}
}
func TestConstFolduint16uint64rsh(t *testing.T) {
@@ -9600,64 +9600,64 @@ func TestConstFolduint16uint64rsh(t *testing.T) {
y = 0
r = x >> y
if r != 0 {
- t.Errorf("0 >> 0 = %d, want 0", r)
+ t.Errorf("0 %s 0 = %d, want 0", ">>", r)
}
y = 1
r = x >> y
if r != 0 {
- t.Errorf("0 >> 1 = %d, want 0", r)
+ t.Errorf("0 %s 1 = %d, want 0", ">>", r)
}
y = 4294967296
r = x >> y
if r != 0 {
- t.Errorf("0 >> 4294967296 = %d, want 0", r)
+ t.Errorf("0 %s 4294967296 = %d, want 0", ">>", r)
}
y = 18446744073709551615
r = x >> y
if r != 0 {
- t.Errorf("0 >> 18446744073709551615 = %d, want 0", r)
+ t.Errorf("0 %s 18446744073709551615 = %d, want 0", ">>", r)
}
x = 1
y = 0
r = x >> y
if r != 1 {
- t.Errorf("1 >> 0 = %d, want 1", r)
+ t.Errorf("1 %s 0 = %d, want 1", ">>", r)
}
y = 1
r = x >> y
if r != 0 {
- t.Errorf("1 >> 1 = %d, want 0", r)
+ t.Errorf("1 %s 1 = %d, want 0", ">>", r)
}
y = 4294967296
r = x >> y
if r != 0 {
- t.Errorf("1 >> 4294967296 = %d, want 0", r)
+ t.Errorf("1 %s 4294967296 = %d, want 0", ">>", r)
}
y = 18446744073709551615
r = x >> y
if r != 0 {
- t.Errorf("1 >> 18446744073709551615 = %d, want 0", r)
+ t.Errorf("1 %s 18446744073709551615 = %d, want 0", ">>", r)
}
x = 65535
y = 0
r = x >> y
if r != 65535 {
- t.Errorf("65535 >> 0 = %d, want 65535", r)
+ t.Errorf("65535 %s 0 = %d, want 65535", ">>", r)
}
y = 1
r = x >> y
if r != 32767 {
- t.Errorf("65535 >> 1 = %d, want 32767", r)
+ t.Errorf("65535 %s 1 = %d, want 32767", ">>", r)
}
y = 4294967296
r = x >> y
if r != 0 {
- t.Errorf("65535 >> 4294967296 = %d, want 0", r)
+ t.Errorf("65535 %s 4294967296 = %d, want 0", ">>", r)
}
y = 18446744073709551615
r = x >> y
if r != 0 {
- t.Errorf("65535 >> 18446744073709551615 = %d, want 0", r)
+ t.Errorf("65535 %s 18446744073709551615 = %d, want 0", ">>", r)
}
}
func TestConstFolduint16uint32lsh(t *testing.T) {
@@ -9667,49 +9667,49 @@ func TestConstFolduint16uint32lsh(t *testing.T) {
y = 0
r = x << y
if r != 0 {
- t.Errorf("0 << 0 = %d, want 0", r)
+ t.Errorf("0 %s 0 = %d, want 0", "<<", r)
}
y = 1
r = x << y
if r != 0 {
- t.Errorf("0 << 1 = %d, want 0", r)
+ t.Errorf("0 %s 1 = %d, want 0", "<<", r)
}
y = 4294967295
r = x << y
if r != 0 {
- t.Errorf("0 << 4294967295 = %d, want 0", r)
+ t.Errorf("0 %s 4294967295 = %d, want 0", "<<", r)
}
x = 1
y = 0
r = x << y
if r != 1 {
- t.Errorf("1 << 0 = %d, want 1", r)
+ t.Errorf("1 %s 0 = %d, want 1", "<<", r)
}
y = 1
r = x << y
if r != 2 {
- t.Errorf("1 << 1 = %d, want 2", r)
+ t.Errorf("1 %s 1 = %d, want 2", "<<", r)
}
y = 4294967295
r = x << y
if r != 0 {
- t.Errorf("1 << 4294967295 = %d, want 0", r)
+ t.Errorf("1 %s 4294967295 = %d, want 0", "<<", r)
}
x = 65535
y = 0
r = x << y
if r != 65535 {
- t.Errorf("65535 << 0 = %d, want 65535", r)
+ t.Errorf("65535 %s 0 = %d, want 65535", "<<", r)
}
y = 1
r = x << y
if r != 65534 {
- t.Errorf("65535 << 1 = %d, want 65534", r)
+ t.Errorf("65535 %s 1 = %d, want 65534", "<<", r)
}
y = 4294967295
r = x << y
if r != 0 {
- t.Errorf("65535 << 4294967295 = %d, want 0", r)
+ t.Errorf("65535 %s 4294967295 = %d, want 0", "<<", r)
}
}
func TestConstFolduint16uint32rsh(t *testing.T) {
@@ -9719,49 +9719,49 @@ func TestConstFolduint16uint32rsh(t *testing.T) {
y = 0
r = x >> y
if r != 0 {
- t.Errorf("0 >> 0 = %d, want 0", r)
+ t.Errorf("0 %s 0 = %d, want 0", ">>", r)
}
y = 1
r = x >> y
if r != 0 {
- t.Errorf("0 >> 1 = %d, want 0", r)
+ t.Errorf("0 %s 1 = %d, want 0", ">>", r)
}
y = 4294967295
r = x >> y
if r != 0 {
- t.Errorf("0 >> 4294967295 = %d, want 0", r)
+ t.Errorf("0 %s 4294967295 = %d, want 0", ">>", r)
}
x = 1
y = 0
r = x >> y
if r != 1 {
- t.Errorf("1 >> 0 = %d, want 1", r)
+ t.Errorf("1 %s 0 = %d, want 1", ">>", r)
}
y = 1
r = x >> y
if r != 0 {
- t.Errorf("1 >> 1 = %d, want 0", r)
+ t.Errorf("1 %s 1 = %d, want 0", ">>", r)
}
y = 4294967295
r = x >> y
if r != 0 {
- t.Errorf("1 >> 4294967295 = %d, want 0", r)
+ t.Errorf("1 %s 4294967295 = %d, want 0", ">>", r)
}
x = 65535
y = 0
r = x >> y
if r != 65535 {
- t.Errorf("65535 >> 0 = %d, want 65535", r)
+ t.Errorf("65535 %s 0 = %d, want 65535", ">>", r)
}
y = 1
r = x >> y
if r != 32767 {
- t.Errorf("65535 >> 1 = %d, want 32767", r)
+ t.Errorf("65535 %s 1 = %d, want 32767", ">>", r)
}
y = 4294967295
r = x >> y
if r != 0 {
- t.Errorf("65535 >> 4294967295 = %d, want 0", r)
+ t.Errorf("65535 %s 4294967295 = %d, want 0", ">>", r)
}
}
func TestConstFolduint16uint16lsh(t *testing.T) {
@@ -9771,49 +9771,49 @@ func TestConstFolduint16uint16lsh(t *testing.T) {
y = 0
r = x << y
if r != 0 {
- t.Errorf("0 << 0 = %d, want 0", r)
+ t.Errorf("0 %s 0 = %d, want 0", "<<", r)
}
y = 1
r = x << y
if r != 0 {
- t.Errorf("0 << 1 = %d, want 0", r)
+ t.Errorf("0 %s 1 = %d, want 0", "<<", r)
}
y = 65535
r = x << y
if r != 0 {
- t.Errorf("0 << 65535 = %d, want 0", r)
+ t.Errorf("0 %s 65535 = %d, want 0", "<<", r)
}
x = 1
y = 0
r = x << y
if r != 1 {
- t.Errorf("1 << 0 = %d, want 1", r)
+ t.Errorf("1 %s 0 = %d, want 1", "<<", r)
}
y = 1
r = x << y
if r != 2 {
- t.Errorf("1 << 1 = %d, want 2", r)
+ t.Errorf("1 %s 1 = %d, want 2", "<<", r)
}
y = 65535
r = x << y
if r != 0 {
- t.Errorf("1 << 65535 = %d, want 0", r)
+ t.Errorf("1 %s 65535 = %d, want 0", "<<", r)
}
x = 65535
y = 0
r = x << y
if r != 65535 {
- t.Errorf("65535 << 0 = %d, want 65535", r)
+ t.Errorf("65535 %s 0 = %d, want 65535", "<<", r)
}
y = 1
r = x << y
if r != 65534 {
- t.Errorf("65535 << 1 = %d, want 65534", r)
+ t.Errorf("65535 %s 1 = %d, want 65534", "<<", r)
}
y = 65535
r = x << y
if r != 0 {
- t.Errorf("65535 << 65535 = %d, want 0", r)
+ t.Errorf("65535 %s 65535 = %d, want 0", "<<", r)
}
}
func TestConstFolduint16uint16rsh(t *testing.T) {
@@ -9823,49 +9823,49 @@ func TestConstFolduint16uint16rsh(t *testing.T) {
y = 0
r = x >> y
if r != 0 {
- t.Errorf("0 >> 0 = %d, want 0", r)
+ t.Errorf("0 %s 0 = %d, want 0", ">>", r)
}
y = 1
r = x >> y
if r != 0 {
- t.Errorf("0 >> 1 = %d, want 0", r)
+ t.Errorf("0 %s 1 = %d, want 0", ">>", r)
}
y = 65535
r = x >> y
if r != 0 {
- t.Errorf("0 >> 65535 = %d, want 0", r)
+ t.Errorf("0 %s 65535 = %d, want 0", ">>", r)
}
x = 1
y = 0
r = x >> y
if r != 1 {
- t.Errorf("1 >> 0 = %d, want 1", r)
+ t.Errorf("1 %s 0 = %d, want 1", ">>", r)
}
y = 1
r = x >> y
if r != 0 {
- t.Errorf("1 >> 1 = %d, want 0", r)
+ t.Errorf("1 %s 1 = %d, want 0", ">>", r)
}
y = 65535
r = x >> y
if r != 0 {
- t.Errorf("1 >> 65535 = %d, want 0", r)
+ t.Errorf("1 %s 65535 = %d, want 0", ">>", r)
}
x = 65535
y = 0
r = x >> y
if r != 65535 {
- t.Errorf("65535 >> 0 = %d, want 65535", r)
+ t.Errorf("65535 %s 0 = %d, want 65535", ">>", r)
}
y = 1
r = x >> y
if r != 32767 {
- t.Errorf("65535 >> 1 = %d, want 32767", r)
+ t.Errorf("65535 %s 1 = %d, want 32767", ">>", r)
}
y = 65535
r = x >> y
if r != 0 {
- t.Errorf("65535 >> 65535 = %d, want 0", r)
+ t.Errorf("65535 %s 65535 = %d, want 0", ">>", r)
}
}
func TestConstFolduint16uint8lsh(t *testing.T) {
@@ -9875,49 +9875,49 @@ func TestConstFolduint16uint8lsh(t *testing.T) {
y = 0
r = x << y
if r != 0 {
- t.Errorf("0 << 0 = %d, want 0", r)
+ t.Errorf("0 %s 0 = %d, want 0", "<<", r)
}
y = 1
r = x << y
if r != 0 {
- t.Errorf("0 << 1 = %d, want 0", r)
+ t.Errorf("0 %s 1 = %d, want 0", "<<", r)
}
y = 255
r = x << y
if r != 0 {
- t.Errorf("0 << 255 = %d, want 0", r)
+ t.Errorf("0 %s 255 = %d, want 0", "<<", r)
}
x = 1
y = 0
r = x << y
if r != 1 {
- t.Errorf("1 << 0 = %d, want 1", r)
+ t.Errorf("1 %s 0 = %d, want 1", "<<", r)
}
y = 1
r = x << y
if r != 2 {
- t.Errorf("1 << 1 = %d, want 2", r)
+ t.Errorf("1 %s 1 = %d, want 2", "<<", r)
}
y = 255
r = x << y
if r != 0 {
- t.Errorf("1 << 255 = %d, want 0", r)
+ t.Errorf("1 %s 255 = %d, want 0", "<<", r)
}
x = 65535
y = 0
r = x << y
if r != 65535 {
- t.Errorf("65535 << 0 = %d, want 65535", r)
+ t.Errorf("65535 %s 0 = %d, want 65535", "<<", r)
}
y = 1
r = x << y
if r != 65534 {
- t.Errorf("65535 << 1 = %d, want 65534", r)
+ t.Errorf("65535 %s 1 = %d, want 65534", "<<", r)
}
y = 255
r = x << y
if r != 0 {
- t.Errorf("65535 << 255 = %d, want 0", r)
+ t.Errorf("65535 %s 255 = %d, want 0", "<<", r)
}
}
func TestConstFolduint16uint8rsh(t *testing.T) {
@@ -9927,49 +9927,49 @@ func TestConstFolduint16uint8rsh(t *testing.T) {
y = 0
r = x >> y
if r != 0 {
- t.Errorf("0 >> 0 = %d, want 0", r)
+ t.Errorf("0 %s 0 = %d, want 0", ">>", r)
}
y = 1
r = x >> y
if r != 0 {
- t.Errorf("0 >> 1 = %d, want 0", r)
+ t.Errorf("0 %s 1 = %d, want 0", ">>", r)
}
y = 255
r = x >> y
if r != 0 {
- t.Errorf("0 >> 255 = %d, want 0", r)
+ t.Errorf("0 %s 255 = %d, want 0", ">>", r)
}
x = 1
y = 0
r = x >> y
if r != 1 {
- t.Errorf("1 >> 0 = %d, want 1", r)
+ t.Errorf("1 %s 0 = %d, want 1", ">>", r)
}
y = 1
r = x >> y
if r != 0 {
- t.Errorf("1 >> 1 = %d, want 0", r)
+ t.Errorf("1 %s 1 = %d, want 0", ">>", r)
}
y = 255
r = x >> y
if r != 0 {
- t.Errorf("1 >> 255 = %d, want 0", r)
+ t.Errorf("1 %s 255 = %d, want 0", ">>", r)
}
x = 65535
y = 0
r = x >> y
if r != 65535 {
- t.Errorf("65535 >> 0 = %d, want 65535", r)
+ t.Errorf("65535 %s 0 = %d, want 65535", ">>", r)
}
y = 1
r = x >> y
if r != 32767 {
- t.Errorf("65535 >> 1 = %d, want 32767", r)
+ t.Errorf("65535 %s 1 = %d, want 32767", ">>", r)
}
y = 255
r = x >> y
if r != 0 {
- t.Errorf("65535 >> 255 = %d, want 0", r)
+ t.Errorf("65535 %s 255 = %d, want 0", ">>", r)
}
}
func TestConstFoldint16uint64lsh(t *testing.T) {
@@ -9979,148 +9979,148 @@ func TestConstFoldint16uint64lsh(t *testing.T) {
y = 0
r = x << y
if r != -32768 {
- t.Errorf("-32768 << 0 = %d, want -32768", r)
+ t.Errorf("-32768 %s 0 = %d, want -32768", "<<", r)
}
y = 1
r = x << y
if r != 0 {
- t.Errorf("-32768 << 1 = %d, want 0", r)
+ t.Errorf("-32768 %s 1 = %d, want 0", "<<", r)
}
y = 4294967296
r = x << y
if r != 0 {
- t.Errorf("-32768 << 4294967296 = %d, want 0", r)
+ t.Errorf("-32768 %s 4294967296 = %d, want 0", "<<", r)
}
y = 18446744073709551615
r = x << y
if r != 0 {
- t.Errorf("-32768 << 18446744073709551615 = %d, want 0", r)
+ t.Errorf("-32768 %s 18446744073709551615 = %d, want 0", "<<", r)
}
x = -32767
y = 0
r = x << y
if r != -32767 {
- t.Errorf("-32767 << 0 = %d, want -32767", r)
+ t.Errorf("-32767 %s 0 = %d, want -32767", "<<", r)
}
y = 1
r = x << y
if r != 2 {
- t.Errorf("-32767 << 1 = %d, want 2", r)
+ t.Errorf("-32767 %s 1 = %d, want 2", "<<", r)
}
y = 4294967296
r = x << y
if r != 0 {
- t.Errorf("-32767 << 4294967296 = %d, want 0", r)
+ t.Errorf("-32767 %s 4294967296 = %d, want 0", "<<", r)
}
y = 18446744073709551615
r = x << y
if r != 0 {
- t.Errorf("-32767 << 18446744073709551615 = %d, want 0", r)
+ t.Errorf("-32767 %s 18446744073709551615 = %d, want 0", "<<", r)
}
x = -1
y = 0
r = x << y
if r != -1 {
- t.Errorf("-1 << 0 = %d, want -1", r)
+ t.Errorf("-1 %s 0 = %d, want -1", "<<", r)
}
y = 1
r = x << y
if r != -2 {
- t.Errorf("-1 << 1 = %d, want -2", r)
+ t.Errorf("-1 %s 1 = %d, want -2", "<<", r)
}
y = 4294967296
r = x << y
if r != 0 {
- t.Errorf("-1 << 4294967296 = %d, want 0", r)
+ t.Errorf("-1 %s 4294967296 = %d, want 0", "<<", r)
}
y = 18446744073709551615
r = x << y
if r != 0 {
- t.Errorf("-1 << 18446744073709551615 = %d, want 0", r)
+ t.Errorf("-1 %s 18446744073709551615 = %d, want 0", "<<", r)
}
x = 0
y = 0
r = x << y
if r != 0 {
- t.Errorf("0 << 0 = %d, want 0", r)
+ t.Errorf("0 %s 0 = %d, want 0", "<<", r)
}
y = 1
r = x << y
if r != 0 {
- t.Errorf("0 << 1 = %d, want 0", r)
+ t.Errorf("0 %s 1 = %d, want 0", "<<", r)
}
y = 4294967296
r = x << y
if r != 0 {
- t.Errorf("0 << 4294967296 = %d, want 0", r)
+ t.Errorf("0 %s 4294967296 = %d, want 0", "<<", r)
}
y = 18446744073709551615
r = x << y
if r != 0 {
- t.Errorf("0 << 18446744073709551615 = %d, want 0", r)
+ t.Errorf("0 %s 18446744073709551615 = %d, want 0", "<<", r)
}
x = 1
y = 0
r = x << y
if r != 1 {
- t.Errorf("1 << 0 = %d, want 1", r)
+ t.Errorf("1 %s 0 = %d, want 1", "<<", r)
}
y = 1
r = x << y
if r != 2 {
- t.Errorf("1 << 1 = %d, want 2", r)
+ t.Errorf("1 %s 1 = %d, want 2", "<<", r)
}
y = 4294967296
r = x << y
if r != 0 {
- t.Errorf("1 << 4294967296 = %d, want 0", r)
+ t.Errorf("1 %s 4294967296 = %d, want 0", "<<", r)
}
y = 18446744073709551615
r = x << y
if r != 0 {
- t.Errorf("1 << 18446744073709551615 = %d, want 0", r)
+ t.Errorf("1 %s 18446744073709551615 = %d, want 0", "<<", r)
}
x = 32766
y = 0
r = x << y
if r != 32766 {
- t.Errorf("32766 << 0 = %d, want 32766", r)
+ t.Errorf("32766 %s 0 = %d, want 32766", "<<", r)
}
y = 1
r = x << y
if r != -4 {
- t.Errorf("32766 << 1 = %d, want -4", r)
+ t.Errorf("32766 %s 1 = %d, want -4", "<<", r)
}
y = 4294967296
r = x << y
if r != 0 {
- t.Errorf("32766 << 4294967296 = %d, want 0", r)
+ t.Errorf("32766 %s 4294967296 = %d, want 0", "<<", r)
}
y = 18446744073709551615
r = x << y
if r != 0 {
- t.Errorf("32766 << 18446744073709551615 = %d, want 0", r)
+ t.Errorf("32766 %s 18446744073709551615 = %d, want 0", "<<", r)
}
x = 32767
y = 0
r = x << y
if r != 32767 {
- t.Errorf("32767 << 0 = %d, want 32767", r)
+ t.Errorf("32767 %s 0 = %d, want 32767", "<<", r)
}
y = 1
r = x << y
if r != -2 {
- t.Errorf("32767 << 1 = %d, want -2", r)
+ t.Errorf("32767 %s 1 = %d, want -2", "<<", r)
}
y = 4294967296
r = x << y
if r != 0 {
- t.Errorf("32767 << 4294967296 = %d, want 0", r)
+ t.Errorf("32767 %s 4294967296 = %d, want 0", "<<", r)
}
y = 18446744073709551615
r = x << y
if r != 0 {
- t.Errorf("32767 << 18446744073709551615 = %d, want 0", r)
+ t.Errorf("32767 %s 18446744073709551615 = %d, want 0", "<<", r)
}
}
func TestConstFoldint16uint64rsh(t *testing.T) {
@@ -10130,148 +10130,148 @@ func TestConstFoldint16uint64rsh(t *testing.T) {
y = 0
r = x >> y
if r != -32768 {
- t.Errorf("-32768 >> 0 = %d, want -32768", r)
+ t.Errorf("-32768 %s 0 = %d, want -32768", ">>", r)
}
y = 1
r = x >> y
if r != -16384 {
- t.Errorf("-32768 >> 1 = %d, want -16384", r)
+ t.Errorf("-32768 %s 1 = %d, want -16384", ">>", r)
}
y = 4294967296
r = x >> y
if r != -1 {
- t.Errorf("-32768 >> 4294967296 = %d, want -1", r)
+ t.Errorf("-32768 %s 4294967296 = %d, want -1", ">>", r)
}
y = 18446744073709551615
r = x >> y
if r != -1 {
- t.Errorf("-32768 >> 18446744073709551615 = %d, want -1", r)
+ t.Errorf("-32768 %s 18446744073709551615 = %d, want -1", ">>", r)
}
x = -32767
y = 0
r = x >> y
if r != -32767 {
- t.Errorf("-32767 >> 0 = %d, want -32767", r)
+ t.Errorf("-32767 %s 0 = %d, want -32767", ">>", r)
}
y = 1
r = x >> y
if r != -16384 {
- t.Errorf("-32767 >> 1 = %d, want -16384", r)
+ t.Errorf("-32767 %s 1 = %d, want -16384", ">>", r)
}
y = 4294967296
r = x >> y
if r != -1 {
- t.Errorf("-32767 >> 4294967296 = %d, want -1", r)
+ t.Errorf("-32767 %s 4294967296 = %d, want -1", ">>", r)
}
y = 18446744073709551615
r = x >> y
if r != -1 {
- t.Errorf("-32767 >> 18446744073709551615 = %d, want -1", r)
+ t.Errorf("-32767 %s 18446744073709551615 = %d, want -1", ">>", r)
}
x = -1
y = 0
r = x >> y
if r != -1 {
- t.Errorf("-1 >> 0 = %d, want -1", r)
+ t.Errorf("-1 %s 0 = %d, want -1", ">>", r)
}
y = 1
r = x >> y
if r != -1 {
- t.Errorf("-1 >> 1 = %d, want -1", r)
+ t.Errorf("-1 %s 1 = %d, want -1", ">>", r)
}
y = 4294967296
r = x >> y
if r != -1 {
- t.Errorf("-1 >> 4294967296 = %d, want -1", r)
+ t.Errorf("-1 %s 4294967296 = %d, want -1", ">>", r)
}
y = 18446744073709551615
r = x >> y
if r != -1 {
- t.Errorf("-1 >> 18446744073709551615 = %d, want -1", r)
+ t.Errorf("-1 %s 18446744073709551615 = %d, want -1", ">>", r)
}
x = 0
y = 0
r = x >> y
if r != 0 {
- t.Errorf("0 >> 0 = %d, want 0", r)
+ t.Errorf("0 %s 0 = %d, want 0", ">>", r)
}
y = 1
r = x >> y
if r != 0 {
- t.Errorf("0 >> 1 = %d, want 0", r)
+ t.Errorf("0 %s 1 = %d, want 0", ">>", r)
}
y = 4294967296
r = x >> y
if r != 0 {
- t.Errorf("0 >> 4294967296 = %d, want 0", r)
+ t.Errorf("0 %s 4294967296 = %d, want 0", ">>", r)
}
y = 18446744073709551615
r = x >> y
if r != 0 {
- t.Errorf("0 >> 18446744073709551615 = %d, want 0", r)
+ t.Errorf("0 %s 18446744073709551615 = %d, want 0", ">>", r)
}
x = 1
y = 0
r = x >> y
if r != 1 {
- t.Errorf("1 >> 0 = %d, want 1", r)
+ t.Errorf("1 %s 0 = %d, want 1", ">>", r)
}
y = 1
r = x >> y
if r != 0 {
- t.Errorf("1 >> 1 = %d, want 0", r)
+ t.Errorf("1 %s 1 = %d, want 0", ">>", r)
}
y = 4294967296
r = x >> y
if r != 0 {
- t.Errorf("1 >> 4294967296 = %d, want 0", r)
+ t.Errorf("1 %s 4294967296 = %d, want 0", ">>", r)
}
y = 18446744073709551615
r = x >> y
if r != 0 {
- t.Errorf("1 >> 18446744073709551615 = %d, want 0", r)
+ t.Errorf("1 %s 18446744073709551615 = %d, want 0", ">>", r)
}
x = 32766
y = 0
r = x >> y
if r != 32766 {
- t.Errorf("32766 >> 0 = %d, want 32766", r)
+ t.Errorf("32766 %s 0 = %d, want 32766", ">>", r)
}
y = 1
r = x >> y
if r != 16383 {
- t.Errorf("32766 >> 1 = %d, want 16383", r)
+ t.Errorf("32766 %s 1 = %d, want 16383", ">>", r)
}
y = 4294967296
r = x >> y
if r != 0 {
- t.Errorf("32766 >> 4294967296 = %d, want 0", r)
+ t.Errorf("32766 %s 4294967296 = %d, want 0", ">>", r)
}
y = 18446744073709551615
r = x >> y
if r != 0 {
- t.Errorf("32766 >> 18446744073709551615 = %d, want 0", r)
+ t.Errorf("32766 %s 18446744073709551615 = %d, want 0", ">>", r)
}
x = 32767
y = 0
r = x >> y
if r != 32767 {
- t.Errorf("32767 >> 0 = %d, want 32767", r)
+ t.Errorf("32767 %s 0 = %d, want 32767", ">>", r)
}
y = 1
r = x >> y
if r != 16383 {
- t.Errorf("32767 >> 1 = %d, want 16383", r)
+ t.Errorf("32767 %s 1 = %d, want 16383", ">>", r)
}
y = 4294967296
r = x >> y
if r != 0 {
- t.Errorf("32767 >> 4294967296 = %d, want 0", r)
+ t.Errorf("32767 %s 4294967296 = %d, want 0", ">>", r)
}
y = 18446744073709551615
r = x >> y
if r != 0 {
- t.Errorf("32767 >> 18446744073709551615 = %d, want 0", r)
+ t.Errorf("32767 %s 18446744073709551615 = %d, want 0", ">>", r)
}
}
func TestConstFoldint16uint32lsh(t *testing.T) {
@@ -10281,113 +10281,113 @@ func TestConstFoldint16uint32lsh(t *testing.T) {
y = 0
r = x << y
if r != -32768 {
- t.Errorf("-32768 << 0 = %d, want -32768", r)
+ t.Errorf("-32768 %s 0 = %d, want -32768", "<<", r)
}
y = 1
r = x << y
if r != 0 {
- t.Errorf("-32768 << 1 = %d, want 0", r)
+ t.Errorf("-32768 %s 1 = %d, want 0", "<<", r)
}
y = 4294967295
r = x << y
if r != 0 {
- t.Errorf("-32768 << 4294967295 = %d, want 0", r)
+ t.Errorf("-32768 %s 4294967295 = %d, want 0", "<<", r)
}
x = -32767
y = 0
r = x << y
if r != -32767 {
- t.Errorf("-32767 << 0 = %d, want -32767", r)
+ t.Errorf("-32767 %s 0 = %d, want -32767", "<<", r)
}
y = 1
r = x << y
if r != 2 {
- t.Errorf("-32767 << 1 = %d, want 2", r)
+ t.Errorf("-32767 %s 1 = %d, want 2", "<<", r)
}
y = 4294967295
r = x << y
if r != 0 {
- t.Errorf("-32767 << 4294967295 = %d, want 0", r)
+ t.Errorf("-32767 %s 4294967295 = %d, want 0", "<<", r)
}
x = -1
y = 0
r = x << y
if r != -1 {
- t.Errorf("-1 << 0 = %d, want -1", r)
+ t.Errorf("-1 %s 0 = %d, want -1", "<<", r)
}
y = 1
r = x << y
if r != -2 {
- t.Errorf("-1 << 1 = %d, want -2", r)
+ t.Errorf("-1 %s 1 = %d, want -2", "<<", r)
}
y = 4294967295
r = x << y
if r != 0 {
- t.Errorf("-1 << 4294967295 = %d, want 0", r)
+ t.Errorf("-1 %s 4294967295 = %d, want 0", "<<", r)
}
x = 0
y = 0
r = x << y
if r != 0 {
- t.Errorf("0 << 0 = %d, want 0", r)
+ t.Errorf("0 %s 0 = %d, want 0", "<<", r)
}
y = 1
r = x << y
if r != 0 {
- t.Errorf("0 << 1 = %d, want 0", r)
+ t.Errorf("0 %s 1 = %d, want 0", "<<", r)
}
y = 4294967295
r = x << y
if r != 0 {
- t.Errorf("0 << 4294967295 = %d, want 0", r)
+ t.Errorf("0 %s 4294967295 = %d, want 0", "<<", r)
}
x = 1
y = 0
r = x << y
if r != 1 {
- t.Errorf("1 << 0 = %d, want 1", r)
+ t.Errorf("1 %s 0 = %d, want 1", "<<", r)
}
y = 1
r = x << y
if r != 2 {
- t.Errorf("1 << 1 = %d, want 2", r)
+ t.Errorf("1 %s 1 = %d, want 2", "<<", r)
}
y = 4294967295
r = x << y
if r != 0 {
- t.Errorf("1 << 4294967295 = %d, want 0", r)
+ t.Errorf("1 %s 4294967295 = %d, want 0", "<<", r)
}
x = 32766
y = 0
r = x << y
if r != 32766 {
- t.Errorf("32766 << 0 = %d, want 32766", r)
+ t.Errorf("32766 %s 0 = %d, want 32766", "<<", r)
}
y = 1
r = x << y
if r != -4 {
- t.Errorf("32766 << 1 = %d, want -4", r)
+ t.Errorf("32766 %s 1 = %d, want -4", "<<", r)
}
y = 4294967295
r = x << y
if r != 0 {
- t.Errorf("32766 << 4294967295 = %d, want 0", r)
+ t.Errorf("32766 %s 4294967295 = %d, want 0", "<<", r)
}
x = 32767
y = 0
r = x << y
if r != 32767 {
- t.Errorf("32767 << 0 = %d, want 32767", r)
+ t.Errorf("32767 %s 0 = %d, want 32767", "<<", r)
}
y = 1
r = x << y
if r != -2 {
- t.Errorf("32767 << 1 = %d, want -2", r)
+ t.Errorf("32767 %s 1 = %d, want -2", "<<", r)
}
y = 4294967295
r = x << y
if r != 0 {
- t.Errorf("32767 << 4294967295 = %d, want 0", r)
+ t.Errorf("32767 %s 4294967295 = %d, want 0", "<<", r)
}
}
func TestConstFoldint16uint32rsh(t *testing.T) {
@@ -10397,113 +10397,113 @@ func TestConstFoldint16uint32rsh(t *testing.T) {
y = 0
r = x >> y
if r != -32768 {
- t.Errorf("-32768 >> 0 = %d, want -32768", r)
+ t.Errorf("-32768 %s 0 = %d, want -32768", ">>", r)
}
y = 1
r = x >> y
if r != -16384 {
- t.Errorf("-32768 >> 1 = %d, want -16384", r)
+ t.Errorf("-32768 %s 1 = %d, want -16384", ">>", r)
}
y = 4294967295
r = x >> y
if r != -1 {
- t.Errorf("-32768 >> 4294967295 = %d, want -1", r)
+ t.Errorf("-32768 %s 4294967295 = %d, want -1", ">>", r)
}
x = -32767
y = 0
r = x >> y
if r != -32767 {
- t.Errorf("-32767 >> 0 = %d, want -32767", r)
+ t.Errorf("-32767 %s 0 = %d, want -32767", ">>", r)
}
y = 1
r = x >> y
if r != -16384 {
- t.Errorf("-32767 >> 1 = %d, want -16384", r)
+ t.Errorf("-32767 %s 1 = %d, want -16384", ">>", r)
}
y = 4294967295
r = x >> y
if r != -1 {
- t.Errorf("-32767 >> 4294967295 = %d, want -1", r)
+ t.Errorf("-32767 %s 4294967295 = %d, want -1", ">>", r)
}
x = -1
y = 0
r = x >> y
if r != -1 {
- t.Errorf("-1 >> 0 = %d, want -1", r)
+ t.Errorf("-1 %s 0 = %d, want -1", ">>", r)
}
y = 1
r = x >> y
if r != -1 {
- t.Errorf("-1 >> 1 = %d, want -1", r)
+ t.Errorf("-1 %s 1 = %d, want -1", ">>", r)
}
y = 4294967295
r = x >> y
if r != -1 {
- t.Errorf("-1 >> 4294967295 = %d, want -1", r)
+ t.Errorf("-1 %s 4294967295 = %d, want -1", ">>", r)
}
x = 0
y = 0
r = x >> y
if r != 0 {
- t.Errorf("0 >> 0 = %d, want 0", r)
+ t.Errorf("0 %s 0 = %d, want 0", ">>", r)
}
y = 1
r = x >> y
if r != 0 {
- t.Errorf("0 >> 1 = %d, want 0", r)
+ t.Errorf("0 %s 1 = %d, want 0", ">>", r)
}
y = 4294967295
r = x >> y
if r != 0 {
- t.Errorf("0 >> 4294967295 = %d, want 0", r)
+ t.Errorf("0 %s 4294967295 = %d, want 0", ">>", r)
}
x = 1
y = 0
r = x >> y
if r != 1 {
- t.Errorf("1 >> 0 = %d, want 1", r)
+ t.Errorf("1 %s 0 = %d, want 1", ">>", r)
}
y = 1
r = x >> y
if r != 0 {
- t.Errorf("1 >> 1 = %d, want 0", r)
+ t.Errorf("1 %s 1 = %d, want 0", ">>", r)
}
y = 4294967295
r = x >> y
if r != 0 {
- t.Errorf("1 >> 4294967295 = %d, want 0", r)
+ t.Errorf("1 %s 4294967295 = %d, want 0", ">>", r)
}
x = 32766
y = 0
r = x >> y
if r != 32766 {
- t.Errorf("32766 >> 0 = %d, want 32766", r)
+ t.Errorf("32766 %s 0 = %d, want 32766", ">>", r)
}
y = 1
r = x >> y
if r != 16383 {
- t.Errorf("32766 >> 1 = %d, want 16383", r)
+ t.Errorf("32766 %s 1 = %d, want 16383", ">>", r)
}
y = 4294967295
r = x >> y
if r != 0 {
- t.Errorf("32766 >> 4294967295 = %d, want 0", r)
+ t.Errorf("32766 %s 4294967295 = %d, want 0", ">>", r)
}
x = 32767
y = 0
r = x >> y
if r != 32767 {
- t.Errorf("32767 >> 0 = %d, want 32767", r)
+ t.Errorf("32767 %s 0 = %d, want 32767", ">>", r)
}
y = 1
r = x >> y
if r != 16383 {
- t.Errorf("32767 >> 1 = %d, want 16383", r)
+ t.Errorf("32767 %s 1 = %d, want 16383", ">>", r)
}
y = 4294967295
r = x >> y
if r != 0 {
- t.Errorf("32767 >> 4294967295 = %d, want 0", r)
+ t.Errorf("32767 %s 4294967295 = %d, want 0", ">>", r)
}
}
func TestConstFoldint16uint16lsh(t *testing.T) {
@@ -10513,113 +10513,113 @@ func TestConstFoldint16uint16lsh(t *testing.T) {
y = 0
r = x << y
if r != -32768 {
- t.Errorf("-32768 << 0 = %d, want -32768", r)
+ t.Errorf("-32768 %s 0 = %d, want -32768", "<<", r)
}
y = 1
r = x << y
if r != 0 {
- t.Errorf("-32768 << 1 = %d, want 0", r)
+ t.Errorf("-32768 %s 1 = %d, want 0", "<<", r)
}
y = 65535
r = x << y
if r != 0 {
- t.Errorf("-32768 << 65535 = %d, want 0", r)
+ t.Errorf("-32768 %s 65535 = %d, want 0", "<<", r)
}
x = -32767
y = 0
r = x << y
if r != -32767 {
- t.Errorf("-32767 << 0 = %d, want -32767", r)
+ t.Errorf("-32767 %s 0 = %d, want -32767", "<<", r)
}
y = 1
r = x << y
if r != 2 {
- t.Errorf("-32767 << 1 = %d, want 2", r)
+ t.Errorf("-32767 %s 1 = %d, want 2", "<<", r)
}
y = 65535
r = x << y
if r != 0 {
- t.Errorf("-32767 << 65535 = %d, want 0", r)
+ t.Errorf("-32767 %s 65535 = %d, want 0", "<<", r)
}
x = -1
y = 0
r = x << y
if r != -1 {
- t.Errorf("-1 << 0 = %d, want -1", r)
+ t.Errorf("-1 %s 0 = %d, want -1", "<<", r)
}
y = 1
r = x << y
if r != -2 {
- t.Errorf("-1 << 1 = %d, want -2", r)
+ t.Errorf("-1 %s 1 = %d, want -2", "<<", r)
}
y = 65535
r = x << y
if r != 0 {
- t.Errorf("-1 << 65535 = %d, want 0", r)
+ t.Errorf("-1 %s 65535 = %d, want 0", "<<", r)
}
x = 0
y = 0
r = x << y
if r != 0 {
- t.Errorf("0 << 0 = %d, want 0", r)
+ t.Errorf("0 %s 0 = %d, want 0", "<<", r)
}
y = 1
r = x << y
if r != 0 {
- t.Errorf("0 << 1 = %d, want 0", r)
+ t.Errorf("0 %s 1 = %d, want 0", "<<", r)
}
y = 65535
r = x << y
if r != 0 {
- t.Errorf("0 << 65535 = %d, want 0", r)
+ t.Errorf("0 %s 65535 = %d, want 0", "<<", r)
}
x = 1
y = 0
r = x << y
if r != 1 {
- t.Errorf("1 << 0 = %d, want 1", r)
+ t.Errorf("1 %s 0 = %d, want 1", "<<", r)
}
y = 1
r = x << y
if r != 2 {
- t.Errorf("1 << 1 = %d, want 2", r)
+ t.Errorf("1 %s 1 = %d, want 2", "<<", r)
}
y = 65535
r = x << y
if r != 0 {
- t.Errorf("1 << 65535 = %d, want 0", r)
+ t.Errorf("1 %s 65535 = %d, want 0", "<<", r)
}
x = 32766
y = 0
r = x << y
if r != 32766 {
- t.Errorf("32766 << 0 = %d, want 32766", r)
+ t.Errorf("32766 %s 0 = %d, want 32766", "<<", r)
}
y = 1
r = x << y
if r != -4 {
- t.Errorf("32766 << 1 = %d, want -4", r)
+ t.Errorf("32766 %s 1 = %d, want -4", "<<", r)
}
y = 65535
r = x << y
if r != 0 {
- t.Errorf("32766 << 65535 = %d, want 0", r)
+ t.Errorf("32766 %s 65535 = %d, want 0", "<<", r)
}
x = 32767
y = 0
r = x << y
if r != 32767 {
- t.Errorf("32767 << 0 = %d, want 32767", r)
+ t.Errorf("32767 %s 0 = %d, want 32767", "<<", r)
}
y = 1
r = x << y
if r != -2 {
- t.Errorf("32767 << 1 = %d, want -2", r)
+ t.Errorf("32767 %s 1 = %d, want -2", "<<", r)
}
y = 65535
r = x << y
if r != 0 {
- t.Errorf("32767 << 65535 = %d, want 0", r)
+ t.Errorf("32767 %s 65535 = %d, want 0", "<<", r)
}
}
func TestConstFoldint16uint16rsh(t *testing.T) {
@@ -10629,113 +10629,113 @@ func TestConstFoldint16uint16rsh(t *testing.T) {
y = 0
r = x >> y
if r != -32768 {
- t.Errorf("-32768 >> 0 = %d, want -32768", r)
+ t.Errorf("-32768 %s 0 = %d, want -32768", ">>", r)
}
y = 1
r = x >> y
if r != -16384 {
- t.Errorf("-32768 >> 1 = %d, want -16384", r)
+ t.Errorf("-32768 %s 1 = %d, want -16384", ">>", r)
}
y = 65535
r = x >> y
if r != -1 {
- t.Errorf("-32768 >> 65535 = %d, want -1", r)
+ t.Errorf("-32768 %s 65535 = %d, want -1", ">>", r)
}
x = -32767
y = 0
r = x >> y
if r != -32767 {
- t.Errorf("-32767 >> 0 = %d, want -32767", r)
+ t.Errorf("-32767 %s 0 = %d, want -32767", ">>", r)
}
y = 1
r = x >> y
if r != -16384 {
- t.Errorf("-32767 >> 1 = %d, want -16384", r)
+ t.Errorf("-32767 %s 1 = %d, want -16384", ">>", r)
}
y = 65535
r = x >> y
if r != -1 {
- t.Errorf("-32767 >> 65535 = %d, want -1", r)
+ t.Errorf("-32767 %s 65535 = %d, want -1", ">>", r)
}
x = -1
y = 0
r = x >> y
if r != -1 {
- t.Errorf("-1 >> 0 = %d, want -1", r)
+ t.Errorf("-1 %s 0 = %d, want -1", ">>", r)
}
y = 1
r = x >> y
if r != -1 {
- t.Errorf("-1 >> 1 = %d, want -1", r)
+ t.Errorf("-1 %s 1 = %d, want -1", ">>", r)
}
y = 65535
r = x >> y
if r != -1 {
- t.Errorf("-1 >> 65535 = %d, want -1", r)
+ t.Errorf("-1 %s 65535 = %d, want -1", ">>", r)
}
x = 0
y = 0
r = x >> y
if r != 0 {
- t.Errorf("0 >> 0 = %d, want 0", r)
+ t.Errorf("0 %s 0 = %d, want 0", ">>", r)
}
y = 1
r = x >> y
if r != 0 {
- t.Errorf("0 >> 1 = %d, want 0", r)
+ t.Errorf("0 %s 1 = %d, want 0", ">>", r)
}
y = 65535
r = x >> y
if r != 0 {
- t.Errorf("0 >> 65535 = %d, want 0", r)
+ t.Errorf("0 %s 65535 = %d, want 0", ">>", r)
}
x = 1
y = 0
r = x >> y
if r != 1 {
- t.Errorf("1 >> 0 = %d, want 1", r)
+ t.Errorf("1 %s 0 = %d, want 1", ">>", r)
}
y = 1
r = x >> y
if r != 0 {
- t.Errorf("1 >> 1 = %d, want 0", r)
+ t.Errorf("1 %s 1 = %d, want 0", ">>", r)
}
y = 65535
r = x >> y
if r != 0 {
- t.Errorf("1 >> 65535 = %d, want 0", r)
+ t.Errorf("1 %s 65535 = %d, want 0", ">>", r)
}
x = 32766
y = 0
r = x >> y
if r != 32766 {
- t.Errorf("32766 >> 0 = %d, want 32766", r)
+ t.Errorf("32766 %s 0 = %d, want 32766", ">>", r)
}
y = 1
r = x >> y
if r != 16383 {
- t.Errorf("32766 >> 1 = %d, want 16383", r)
+ t.Errorf("32766 %s 1 = %d, want 16383", ">>", r)
}
y = 65535
r = x >> y
if r != 0 {
- t.Errorf("32766 >> 65535 = %d, want 0", r)
+ t.Errorf("32766 %s 65535 = %d, want 0", ">>", r)
}
x = 32767
y = 0
r = x >> y
if r != 32767 {
- t.Errorf("32767 >> 0 = %d, want 32767", r)
+ t.Errorf("32767 %s 0 = %d, want 32767", ">>", r)
}
y = 1
r = x >> y
if r != 16383 {
- t.Errorf("32767 >> 1 = %d, want 16383", r)
+ t.Errorf("32767 %s 1 = %d, want 16383", ">>", r)
}
y = 65535
r = x >> y
if r != 0 {
- t.Errorf("32767 >> 65535 = %d, want 0", r)
+ t.Errorf("32767 %s 65535 = %d, want 0", ">>", r)
}
}
func TestConstFoldint16uint8lsh(t *testing.T) {
@@ -10745,113 +10745,113 @@ func TestConstFoldint16uint8lsh(t *testing.T) {
y = 0
r = x << y
if r != -32768 {
- t.Errorf("-32768 << 0 = %d, want -32768", r)
+ t.Errorf("-32768 %s 0 = %d, want -32768", "<<", r)
}
y = 1
r = x << y
if r != 0 {
- t.Errorf("-32768 << 1 = %d, want 0", r)
+ t.Errorf("-32768 %s 1 = %d, want 0", "<<", r)
}
y = 255
r = x << y
if r != 0 {
- t.Errorf("-32768 << 255 = %d, want 0", r)
+ t.Errorf("-32768 %s 255 = %d, want 0", "<<", r)
}
x = -32767
y = 0
r = x << y
if r != -32767 {
- t.Errorf("-32767 << 0 = %d, want -32767", r)
+ t.Errorf("-32767 %s 0 = %d, want -32767", "<<", r)
}
y = 1
r = x << y
if r != 2 {
- t.Errorf("-32767 << 1 = %d, want 2", r)
+ t.Errorf("-32767 %s 1 = %d, want 2", "<<", r)
}
y = 255
r = x << y
if r != 0 {
- t.Errorf("-32767 << 255 = %d, want 0", r)
+ t.Errorf("-32767 %s 255 = %d, want 0", "<<", r)
}
x = -1
y = 0
r = x << y
if r != -1 {
- t.Errorf("-1 << 0 = %d, want -1", r)
+ t.Errorf("-1 %s 0 = %d, want -1", "<<", r)
}
y = 1
r = x << y
if r != -2 {
- t.Errorf("-1 << 1 = %d, want -2", r)
+ t.Errorf("-1 %s 1 = %d, want -2", "<<", r)
}
y = 255
r = x << y
if r != 0 {
- t.Errorf("-1 << 255 = %d, want 0", r)
+ t.Errorf("-1 %s 255 = %d, want 0", "<<", r)
}
x = 0
y = 0
r = x << y
if r != 0 {
- t.Errorf("0 << 0 = %d, want 0", r)
+ t.Errorf("0 %s 0 = %d, want 0", "<<", r)
}
y = 1
r = x << y
if r != 0 {
- t.Errorf("0 << 1 = %d, want 0", r)
+ t.Errorf("0 %s 1 = %d, want 0", "<<", r)
}
y = 255
r = x << y
if r != 0 {
- t.Errorf("0 << 255 = %d, want 0", r)
+ t.Errorf("0 %s 255 = %d, want 0", "<<", r)
}
x = 1
y = 0
r = x << y
if r != 1 {
- t.Errorf("1 << 0 = %d, want 1", r)
+ t.Errorf("1 %s 0 = %d, want 1", "<<", r)
}
y = 1
r = x << y
if r != 2 {
- t.Errorf("1 << 1 = %d, want 2", r)
+ t.Errorf("1 %s 1 = %d, want 2", "<<", r)
}
y = 255
r = x << y
if r != 0 {
- t.Errorf("1 << 255 = %d, want 0", r)
+ t.Errorf("1 %s 255 = %d, want 0", "<<", r)
}
x = 32766
y = 0
r = x << y
if r != 32766 {
- t.Errorf("32766 << 0 = %d, want 32766", r)
+ t.Errorf("32766 %s 0 = %d, want 32766", "<<", r)
}
y = 1
r = x << y
if r != -4 {
- t.Errorf("32766 << 1 = %d, want -4", r)
+ t.Errorf("32766 %s 1 = %d, want -4", "<<", r)
}
y = 255
r = x << y
if r != 0 {
- t.Errorf("32766 << 255 = %d, want 0", r)
+ t.Errorf("32766 %s 255 = %d, want 0", "<<", r)
}
x = 32767
y = 0
r = x << y
if r != 32767 {
- t.Errorf("32767 << 0 = %d, want 32767", r)
+ t.Errorf("32767 %s 0 = %d, want 32767", "<<", r)
}
y = 1
r = x << y
if r != -2 {
- t.Errorf("32767 << 1 = %d, want -2", r)
+ t.Errorf("32767 %s 1 = %d, want -2", "<<", r)
}
y = 255
r = x << y
if r != 0 {
- t.Errorf("32767 << 255 = %d, want 0", r)
+ t.Errorf("32767 %s 255 = %d, want 0", "<<", r)
}
}
func TestConstFoldint16uint8rsh(t *testing.T) {
@@ -10861,113 +10861,113 @@ func TestConstFoldint16uint8rsh(t *testing.T) {
y = 0
r = x >> y
if r != -32768 {
- t.Errorf("-32768 >> 0 = %d, want -32768", r)
+ t.Errorf("-32768 %s 0 = %d, want -32768", ">>", r)
}
y = 1
r = x >> y
if r != -16384 {
- t.Errorf("-32768 >> 1 = %d, want -16384", r)
+ t.Errorf("-32768 %s 1 = %d, want -16384", ">>", r)
}
y = 255
r = x >> y
if r != -1 {
- t.Errorf("-32768 >> 255 = %d, want -1", r)
+ t.Errorf("-32768 %s 255 = %d, want -1", ">>", r)
}
x = -32767
y = 0
r = x >> y
if r != -32767 {
- t.Errorf("-32767 >> 0 = %d, want -32767", r)
+ t.Errorf("-32767 %s 0 = %d, want -32767", ">>", r)
}
y = 1
r = x >> y
if r != -16384 {
- t.Errorf("-32767 >> 1 = %d, want -16384", r)
+ t.Errorf("-32767 %s 1 = %d, want -16384", ">>", r)
}
y = 255
r = x >> y
if r != -1 {
- t.Errorf("-32767 >> 255 = %d, want -1", r)
+ t.Errorf("-32767 %s 255 = %d, want -1", ">>", r)
}
x = -1
y = 0
r = x >> y
if r != -1 {
- t.Errorf("-1 >> 0 = %d, want -1", r)
+ t.Errorf("-1 %s 0 = %d, want -1", ">>", r)
}
y = 1
r = x >> y
if r != -1 {
- t.Errorf("-1 >> 1 = %d, want -1", r)
+ t.Errorf("-1 %s 1 = %d, want -1", ">>", r)
}
y = 255
r = x >> y
if r != -1 {
- t.Errorf("-1 >> 255 = %d, want -1", r)
+ t.Errorf("-1 %s 255 = %d, want -1", ">>", r)
}
x = 0
y = 0
r = x >> y
if r != 0 {
- t.Errorf("0 >> 0 = %d, want 0", r)
+ t.Errorf("0 %s 0 = %d, want 0", ">>", r)
}
y = 1
r = x >> y
if r != 0 {
- t.Errorf("0 >> 1 = %d, want 0", r)
+ t.Errorf("0 %s 1 = %d, want 0", ">>", r)
}
y = 255
r = x >> y
if r != 0 {
- t.Errorf("0 >> 255 = %d, want 0", r)
+ t.Errorf("0 %s 255 = %d, want 0", ">>", r)
}
x = 1
y = 0
r = x >> y
if r != 1 {
- t.Errorf("1 >> 0 = %d, want 1", r)
+ t.Errorf("1 %s 0 = %d, want 1", ">>", r)
}
y = 1
r = x >> y
if r != 0 {
- t.Errorf("1 >> 1 = %d, want 0", r)
+ t.Errorf("1 %s 1 = %d, want 0", ">>", r)
}
y = 255
r = x >> y
if r != 0 {
- t.Errorf("1 >> 255 = %d, want 0", r)
+ t.Errorf("1 %s 255 = %d, want 0", ">>", r)
}
x = 32766
y = 0
r = x >> y
if r != 32766 {
- t.Errorf("32766 >> 0 = %d, want 32766", r)
+ t.Errorf("32766 %s 0 = %d, want 32766", ">>", r)
}
y = 1
r = x >> y
if r != 16383 {
- t.Errorf("32766 >> 1 = %d, want 16383", r)
+ t.Errorf("32766 %s 1 = %d, want 16383", ">>", r)
}
y = 255
r = x >> y
if r != 0 {
- t.Errorf("32766 >> 255 = %d, want 0", r)
+ t.Errorf("32766 %s 255 = %d, want 0", ">>", r)
}
x = 32767
y = 0
r = x >> y
if r != 32767 {
- t.Errorf("32767 >> 0 = %d, want 32767", r)
+ t.Errorf("32767 %s 0 = %d, want 32767", ">>", r)
}
y = 1
r = x >> y
if r != 16383 {
- t.Errorf("32767 >> 1 = %d, want 16383", r)
+ t.Errorf("32767 %s 1 = %d, want 16383", ">>", r)
}
y = 255
r = x >> y
if r != 0 {
- t.Errorf("32767 >> 255 = %d, want 0", r)
+ t.Errorf("32767 %s 255 = %d, want 0", ">>", r)
}
}
func TestConstFolduint8uint64lsh(t *testing.T) {
@@ -10977,64 +10977,64 @@ func TestConstFolduint8uint64lsh(t *testing.T) {
y = 0
r = x << y
if r != 0 {
- t.Errorf("0 << 0 = %d, want 0", r)
+ t.Errorf("0 %s 0 = %d, want 0", "<<", r)
}
y = 1
r = x << y
if r != 0 {
- t.Errorf("0 << 1 = %d, want 0", r)
+ t.Errorf("0 %s 1 = %d, want 0", "<<", r)
}
y = 4294967296
r = x << y
if r != 0 {
- t.Errorf("0 << 4294967296 = %d, want 0", r)
+ t.Errorf("0 %s 4294967296 = %d, want 0", "<<", r)
}
y = 18446744073709551615
r = x << y
if r != 0 {
- t.Errorf("0 << 18446744073709551615 = %d, want 0", r)
+ t.Errorf("0 %s 18446744073709551615 = %d, want 0", "<<", r)
}
x = 1
y = 0
r = x << y
if r != 1 {
- t.Errorf("1 << 0 = %d, want 1", r)
+ t.Errorf("1 %s 0 = %d, want 1", "<<", r)
}
y = 1
r = x << y
if r != 2 {
- t.Errorf("1 << 1 = %d, want 2", r)
+ t.Errorf("1 %s 1 = %d, want 2", "<<", r)
}
y = 4294967296
r = x << y
if r != 0 {
- t.Errorf("1 << 4294967296 = %d, want 0", r)
+ t.Errorf("1 %s 4294967296 = %d, want 0", "<<", r)
}
y = 18446744073709551615
r = x << y
if r != 0 {
- t.Errorf("1 << 18446744073709551615 = %d, want 0", r)
+ t.Errorf("1 %s 18446744073709551615 = %d, want 0", "<<", r)
}
x = 255
y = 0
r = x << y
if r != 255 {
- t.Errorf("255 << 0 = %d, want 255", r)
+ t.Errorf("255 %s 0 = %d, want 255", "<<", r)
}
y = 1
r = x << y
if r != 254 {
- t.Errorf("255 << 1 = %d, want 254", r)
+ t.Errorf("255 %s 1 = %d, want 254", "<<", r)
}
y = 4294967296
r = x << y
if r != 0 {
- t.Errorf("255 << 4294967296 = %d, want 0", r)
+ t.Errorf("255 %s 4294967296 = %d, want 0", "<<", r)
}
y = 18446744073709551615
r = x << y
if r != 0 {
- t.Errorf("255 << 18446744073709551615 = %d, want 0", r)
+ t.Errorf("255 %s 18446744073709551615 = %d, want 0", "<<", r)
}
}
func TestConstFolduint8uint64rsh(t *testing.T) {
@@ -11044,64 +11044,64 @@ func TestConstFolduint8uint64rsh(t *testing.T) {
y = 0
r = x >> y
if r != 0 {
- t.Errorf("0 >> 0 = %d, want 0", r)
+ t.Errorf("0 %s 0 = %d, want 0", ">>", r)
}
y = 1
r = x >> y
if r != 0 {
- t.Errorf("0 >> 1 = %d, want 0", r)
+ t.Errorf("0 %s 1 = %d, want 0", ">>", r)
}
y = 4294967296
r = x >> y
if r != 0 {
- t.Errorf("0 >> 4294967296 = %d, want 0", r)
+ t.Errorf("0 %s 4294967296 = %d, want 0", ">>", r)
}
y = 18446744073709551615
r = x >> y
if r != 0 {
- t.Errorf("0 >> 18446744073709551615 = %d, want 0", r)
+ t.Errorf("0 %s 18446744073709551615 = %d, want 0", ">>", r)
}
x = 1
y = 0
r = x >> y
if r != 1 {
- t.Errorf("1 >> 0 = %d, want 1", r)
+ t.Errorf("1 %s 0 = %d, want 1", ">>", r)
}
y = 1
r = x >> y
if r != 0 {
- t.Errorf("1 >> 1 = %d, want 0", r)
+ t.Errorf("1 %s 1 = %d, want 0", ">>", r)
}
y = 4294967296
r = x >> y
if r != 0 {
- t.Errorf("1 >> 4294967296 = %d, want 0", r)
+ t.Errorf("1 %s 4294967296 = %d, want 0", ">>", r)
}
y = 18446744073709551615
r = x >> y
if r != 0 {
- t.Errorf("1 >> 18446744073709551615 = %d, want 0", r)
+ t.Errorf("1 %s 18446744073709551615 = %d, want 0", ">>", r)
}
x = 255
y = 0
r = x >> y
if r != 255 {
- t.Errorf("255 >> 0 = %d, want 255", r)
+ t.Errorf("255 %s 0 = %d, want 255", ">>", r)
}
y = 1
r = x >> y
if r != 127 {
- t.Errorf("255 >> 1 = %d, want 127", r)
+ t.Errorf("255 %s 1 = %d, want 127", ">>", r)
}
y = 4294967296
r = x >> y
if r != 0 {
- t.Errorf("255 >> 4294967296 = %d, want 0", r)
+ t.Errorf("255 %s 4294967296 = %d, want 0", ">>", r)
}
y = 18446744073709551615
r = x >> y
if r != 0 {
- t.Errorf("255 >> 18446744073709551615 = %d, want 0", r)
+ t.Errorf("255 %s 18446744073709551615 = %d, want 0", ">>", r)
}
}
func TestConstFolduint8uint32lsh(t *testing.T) {
@@ -11111,49 +11111,49 @@ func TestConstFolduint8uint32lsh(t *testing.T) {
y = 0
r = x << y
if r != 0 {
- t.Errorf("0 << 0 = %d, want 0", r)
+ t.Errorf("0 %s 0 = %d, want 0", "<<", r)
}
y = 1
r = x << y
if r != 0 {
- t.Errorf("0 << 1 = %d, want 0", r)
+ t.Errorf("0 %s 1 = %d, want 0", "<<", r)
}
y = 4294967295
r = x << y
if r != 0 {
- t.Errorf("0 << 4294967295 = %d, want 0", r)
+ t.Errorf("0 %s 4294967295 = %d, want 0", "<<", r)
}
x = 1
y = 0
r = x << y
if r != 1 {
- t.Errorf("1 << 0 = %d, want 1", r)
+ t.Errorf("1 %s 0 = %d, want 1", "<<", r)
}
y = 1
r = x << y
if r != 2 {
- t.Errorf("1 << 1 = %d, want 2", r)
+ t.Errorf("1 %s 1 = %d, want 2", "<<", r)
}
y = 4294967295
r = x << y
if r != 0 {
- t.Errorf("1 << 4294967295 = %d, want 0", r)
+ t.Errorf("1 %s 4294967295 = %d, want 0", "<<", r)
}
x = 255
y = 0
r = x << y
if r != 255 {
- t.Errorf("255 << 0 = %d, want 255", r)
+ t.Errorf("255 %s 0 = %d, want 255", "<<", r)
}
y = 1
r = x << y
if r != 254 {
- t.Errorf("255 << 1 = %d, want 254", r)
+ t.Errorf("255 %s 1 = %d, want 254", "<<", r)
}
y = 4294967295
r = x << y
if r != 0 {
- t.Errorf("255 << 4294967295 = %d, want 0", r)
+ t.Errorf("255 %s 4294967295 = %d, want 0", "<<", r)
}
}
func TestConstFolduint8uint32rsh(t *testing.T) {
@@ -11163,49 +11163,49 @@ func TestConstFolduint8uint32rsh(t *testing.T) {
y = 0
r = x >> y
if r != 0 {
- t.Errorf("0 >> 0 = %d, want 0", r)
+ t.Errorf("0 %s 0 = %d, want 0", ">>", r)
}
y = 1
r = x >> y
if r != 0 {
- t.Errorf("0 >> 1 = %d, want 0", r)
+ t.Errorf("0 %s 1 = %d, want 0", ">>", r)
}
y = 4294967295
r = x >> y
if r != 0 {
- t.Errorf("0 >> 4294967295 = %d, want 0", r)
+ t.Errorf("0 %s 4294967295 = %d, want 0", ">>", r)
}
x = 1
y = 0
r = x >> y
if r != 1 {
- t.Errorf("1 >> 0 = %d, want 1", r)
+ t.Errorf("1 %s 0 = %d, want 1", ">>", r)
}
y = 1
r = x >> y
if r != 0 {
- t.Errorf("1 >> 1 = %d, want 0", r)
+ t.Errorf("1 %s 1 = %d, want 0", ">>", r)
}
y = 4294967295
r = x >> y
if r != 0 {
- t.Errorf("1 >> 4294967295 = %d, want 0", r)
+ t.Errorf("1 %s 4294967295 = %d, want 0", ">>", r)
}
x = 255
y = 0
r = x >> y
if r != 255 {
- t.Errorf("255 >> 0 = %d, want 255", r)
+ t.Errorf("255 %s 0 = %d, want 255", ">>", r)
}
y = 1
r = x >> y
if r != 127 {
- t.Errorf("255 >> 1 = %d, want 127", r)
+ t.Errorf("255 %s 1 = %d, want 127", ">>", r)
}
y = 4294967295
r = x >> y
if r != 0 {
- t.Errorf("255 >> 4294967295 = %d, want 0", r)
+ t.Errorf("255 %s 4294967295 = %d, want 0", ">>", r)
}
}
func TestConstFolduint8uint16lsh(t *testing.T) {
@@ -11215,49 +11215,49 @@ func TestConstFolduint8uint16lsh(t *testing.T) {
y = 0
r = x << y
if r != 0 {
- t.Errorf("0 << 0 = %d, want 0", r)
+ t.Errorf("0 %s 0 = %d, want 0", "<<", r)
}
y = 1
r = x << y
if r != 0 {
- t.Errorf("0 << 1 = %d, want 0", r)
+ t.Errorf("0 %s 1 = %d, want 0", "<<", r)
}
y = 65535
r = x << y
if r != 0 {
- t.Errorf("0 << 65535 = %d, want 0", r)
+ t.Errorf("0 %s 65535 = %d, want 0", "<<", r)
}
x = 1
y = 0
r = x << y
if r != 1 {
- t.Errorf("1 << 0 = %d, want 1", r)
+ t.Errorf("1 %s 0 = %d, want 1", "<<", r)
}
y = 1
r = x << y
if r != 2 {
- t.Errorf("1 << 1 = %d, want 2", r)
+ t.Errorf("1 %s 1 = %d, want 2", "<<", r)
}
y = 65535
r = x << y
if r != 0 {
- t.Errorf("1 << 65535 = %d, want 0", r)
+ t.Errorf("1 %s 65535 = %d, want 0", "<<", r)
}
x = 255
y = 0
r = x << y
if r != 255 {
- t.Errorf("255 << 0 = %d, want 255", r)
+ t.Errorf("255 %s 0 = %d, want 255", "<<", r)
}
y = 1
r = x << y
if r != 254 {
- t.Errorf("255 << 1 = %d, want 254", r)
+ t.Errorf("255 %s 1 = %d, want 254", "<<", r)
}
y = 65535
r = x << y
if r != 0 {
- t.Errorf("255 << 65535 = %d, want 0", r)
+ t.Errorf("255 %s 65535 = %d, want 0", "<<", r)
}
}
func TestConstFolduint8uint16rsh(t *testing.T) {
@@ -11267,49 +11267,49 @@ func TestConstFolduint8uint16rsh(t *testing.T) {
y = 0
r = x >> y
if r != 0 {
- t.Errorf("0 >> 0 = %d, want 0", r)
+ t.Errorf("0 %s 0 = %d, want 0", ">>", r)
}
y = 1
r = x >> y
if r != 0 {
- t.Errorf("0 >> 1 = %d, want 0", r)
+ t.Errorf("0 %s 1 = %d, want 0", ">>", r)
}
y = 65535
r = x >> y
if r != 0 {
- t.Errorf("0 >> 65535 = %d, want 0", r)
+ t.Errorf("0 %s 65535 = %d, want 0", ">>", r)
}
x = 1
y = 0
r = x >> y
if r != 1 {
- t.Errorf("1 >> 0 = %d, want 1", r)
+ t.Errorf("1 %s 0 = %d, want 1", ">>", r)
}
y = 1
r = x >> y
if r != 0 {
- t.Errorf("1 >> 1 = %d, want 0", r)
+ t.Errorf("1 %s 1 = %d, want 0", ">>", r)
}
y = 65535
r = x >> y
if r != 0 {
- t.Errorf("1 >> 65535 = %d, want 0", r)
+ t.Errorf("1 %s 65535 = %d, want 0", ">>", r)
}
x = 255
y = 0
r = x >> y
if r != 255 {
- t.Errorf("255 >> 0 = %d, want 255", r)
+ t.Errorf("255 %s 0 = %d, want 255", ">>", r)
}
y = 1
r = x >> y
if r != 127 {
- t.Errorf("255 >> 1 = %d, want 127", r)
+ t.Errorf("255 %s 1 = %d, want 127", ">>", r)
}
y = 65535
r = x >> y
if r != 0 {
- t.Errorf("255 >> 65535 = %d, want 0", r)
+ t.Errorf("255 %s 65535 = %d, want 0", ">>", r)
}
}
func TestConstFolduint8uint8lsh(t *testing.T) {
@@ -11319,49 +11319,49 @@ func TestConstFolduint8uint8lsh(t *testing.T) {
y = 0
r = x << y
if r != 0 {
- t.Errorf("0 << 0 = %d, want 0", r)
+ t.Errorf("0 %s 0 = %d, want 0", "<<", r)
}
y = 1
r = x << y
if r != 0 {
- t.Errorf("0 << 1 = %d, want 0", r)
+ t.Errorf("0 %s 1 = %d, want 0", "<<", r)
}
y = 255
r = x << y
if r != 0 {
- t.Errorf("0 << 255 = %d, want 0", r)
+ t.Errorf("0 %s 255 = %d, want 0", "<<", r)
}
x = 1
y = 0
r = x << y
if r != 1 {
- t.Errorf("1 << 0 = %d, want 1", r)
+ t.Errorf("1 %s 0 = %d, want 1", "<<", r)
}
y = 1
r = x << y
if r != 2 {
- t.Errorf("1 << 1 = %d, want 2", r)
+ t.Errorf("1 %s 1 = %d, want 2", "<<", r)
}
y = 255
r = x << y
if r != 0 {
- t.Errorf("1 << 255 = %d, want 0", r)
+ t.Errorf("1 %s 255 = %d, want 0", "<<", r)
}
x = 255
y = 0
r = x << y
if r != 255 {
- t.Errorf("255 << 0 = %d, want 255", r)
+ t.Errorf("255 %s 0 = %d, want 255", "<<", r)
}
y = 1
r = x << y
if r != 254 {
- t.Errorf("255 << 1 = %d, want 254", r)
+ t.Errorf("255 %s 1 = %d, want 254", "<<", r)
}
y = 255
r = x << y
if r != 0 {
- t.Errorf("255 << 255 = %d, want 0", r)
+ t.Errorf("255 %s 255 = %d, want 0", "<<", r)
}
}
func TestConstFolduint8uint8rsh(t *testing.T) {
@@ -11371,49 +11371,49 @@ func TestConstFolduint8uint8rsh(t *testing.T) {
y = 0
r = x >> y
if r != 0 {
- t.Errorf("0 >> 0 = %d, want 0", r)
+ t.Errorf("0 %s 0 = %d, want 0", ">>", r)
}
y = 1
r = x >> y
if r != 0 {
- t.Errorf("0 >> 1 = %d, want 0", r)
+ t.Errorf("0 %s 1 = %d, want 0", ">>", r)
}
y = 255
r = x >> y
if r != 0 {
- t.Errorf("0 >> 255 = %d, want 0", r)
+ t.Errorf("0 %s 255 = %d, want 0", ">>", r)
}
x = 1
y = 0
r = x >> y
if r != 1 {
- t.Errorf("1 >> 0 = %d, want 1", r)
+ t.Errorf("1 %s 0 = %d, want 1", ">>", r)
}
y = 1
r = x >> y
if r != 0 {
- t.Errorf("1 >> 1 = %d, want 0", r)
+ t.Errorf("1 %s 1 = %d, want 0", ">>", r)
}
y = 255
r = x >> y
if r != 0 {
- t.Errorf("1 >> 255 = %d, want 0", r)
+ t.Errorf("1 %s 255 = %d, want 0", ">>", r)
}
x = 255
y = 0
r = x >> y
if r != 255 {
- t.Errorf("255 >> 0 = %d, want 255", r)
+ t.Errorf("255 %s 0 = %d, want 255", ">>", r)
}
y = 1
r = x >> y
if r != 127 {
- t.Errorf("255 >> 1 = %d, want 127", r)
+ t.Errorf("255 %s 1 = %d, want 127", ">>", r)
}
y = 255
r = x >> y
if r != 0 {
- t.Errorf("255 >> 255 = %d, want 0", r)
+ t.Errorf("255 %s 255 = %d, want 0", ">>", r)
}
}
func TestConstFoldint8uint64lsh(t *testing.T) {
@@ -11423,148 +11423,148 @@ func TestConstFoldint8uint64lsh(t *testing.T) {
y = 0
r = x << y
if r != -128 {
- t.Errorf("-128 << 0 = %d, want -128", r)
+ t.Errorf("-128 %s 0 = %d, want -128", "<<", r)
}
y = 1
r = x << y
if r != 0 {
- t.Errorf("-128 << 1 = %d, want 0", r)
+ t.Errorf("-128 %s 1 = %d, want 0", "<<", r)
}
y = 4294967296
r = x << y
if r != 0 {
- t.Errorf("-128 << 4294967296 = %d, want 0", r)
+ t.Errorf("-128 %s 4294967296 = %d, want 0", "<<", r)
}
y = 18446744073709551615
r = x << y
if r != 0 {
- t.Errorf("-128 << 18446744073709551615 = %d, want 0", r)
+ t.Errorf("-128 %s 18446744073709551615 = %d, want 0", "<<", r)
}
x = -127
y = 0
r = x << y
if r != -127 {
- t.Errorf("-127 << 0 = %d, want -127", r)
+ t.Errorf("-127 %s 0 = %d, want -127", "<<", r)
}
y = 1
r = x << y
if r != 2 {
- t.Errorf("-127 << 1 = %d, want 2", r)
+ t.Errorf("-127 %s 1 = %d, want 2", "<<", r)
}
y = 4294967296
r = x << y
if r != 0 {
- t.Errorf("-127 << 4294967296 = %d, want 0", r)
+ t.Errorf("-127 %s 4294967296 = %d, want 0", "<<", r)
}
y = 18446744073709551615
r = x << y
if r != 0 {
- t.Errorf("-127 << 18446744073709551615 = %d, want 0", r)
+ t.Errorf("-127 %s 18446744073709551615 = %d, want 0", "<<", r)
}
x = -1
y = 0
r = x << y
if r != -1 {
- t.Errorf("-1 << 0 = %d, want -1", r)
+ t.Errorf("-1 %s 0 = %d, want -1", "<<", r)
}
y = 1
r = x << y
if r != -2 {
- t.Errorf("-1 << 1 = %d, want -2", r)
+ t.Errorf("-1 %s 1 = %d, want -2", "<<", r)
}
y = 4294967296
r = x << y
if r != 0 {
- t.Errorf("-1 << 4294967296 = %d, want 0", r)
+ t.Errorf("-1 %s 4294967296 = %d, want 0", "<<", r)
}
y = 18446744073709551615
r = x << y
if r != 0 {
- t.Errorf("-1 << 18446744073709551615 = %d, want 0", r)
+ t.Errorf("-1 %s 18446744073709551615 = %d, want 0", "<<", r)
}
x = 0
y = 0
r = x << y
if r != 0 {
- t.Errorf("0 << 0 = %d, want 0", r)
+ t.Errorf("0 %s 0 = %d, want 0", "<<", r)
}
y = 1
r = x << y
if r != 0 {
- t.Errorf("0 << 1 = %d, want 0", r)
+ t.Errorf("0 %s 1 = %d, want 0", "<<", r)
}
y = 4294967296
r = x << y
if r != 0 {
- t.Errorf("0 << 4294967296 = %d, want 0", r)
+ t.Errorf("0 %s 4294967296 = %d, want 0", "<<", r)
}
y = 18446744073709551615
r = x << y
if r != 0 {
- t.Errorf("0 << 18446744073709551615 = %d, want 0", r)
+ t.Errorf("0 %s 18446744073709551615 = %d, want 0", "<<", r)
}
x = 1
y = 0
r = x << y
if r != 1 {
- t.Errorf("1 << 0 = %d, want 1", r)
+ t.Errorf("1 %s 0 = %d, want 1", "<<", r)
}
y = 1
r = x << y
if r != 2 {
- t.Errorf("1 << 1 = %d, want 2", r)
+ t.Errorf("1 %s 1 = %d, want 2", "<<", r)
}
y = 4294967296
r = x << y
if r != 0 {
- t.Errorf("1 << 4294967296 = %d, want 0", r)
+ t.Errorf("1 %s 4294967296 = %d, want 0", "<<", r)
}
y = 18446744073709551615
r = x << y
if r != 0 {
- t.Errorf("1 << 18446744073709551615 = %d, want 0", r)
+ t.Errorf("1 %s 18446744073709551615 = %d, want 0", "<<", r)
}
x = 126
y = 0
r = x << y
if r != 126 {
- t.Errorf("126 << 0 = %d, want 126", r)
+ t.Errorf("126 %s 0 = %d, want 126", "<<", r)
}
y = 1
r = x << y
if r != -4 {
- t.Errorf("126 << 1 = %d, want -4", r)
+ t.Errorf("126 %s 1 = %d, want -4", "<<", r)
}
y = 4294967296
r = x << y
if r != 0 {
- t.Errorf("126 << 4294967296 = %d, want 0", r)
+ t.Errorf("126 %s 4294967296 = %d, want 0", "<<", r)
}
y = 18446744073709551615
r = x << y
if r != 0 {
- t.Errorf("126 << 18446744073709551615 = %d, want 0", r)
+ t.Errorf("126 %s 18446744073709551615 = %d, want 0", "<<", r)
}
x = 127
y = 0
r = x << y
if r != 127 {
- t.Errorf("127 << 0 = %d, want 127", r)
+ t.Errorf("127 %s 0 = %d, want 127", "<<", r)
}
y = 1
r = x << y
if r != -2 {
- t.Errorf("127 << 1 = %d, want -2", r)
+ t.Errorf("127 %s 1 = %d, want -2", "<<", r)
}
y = 4294967296
r = x << y
if r != 0 {
- t.Errorf("127 << 4294967296 = %d, want 0", r)
+ t.Errorf("127 %s 4294967296 = %d, want 0", "<<", r)
}
y = 18446744073709551615
r = x << y
if r != 0 {
- t.Errorf("127 << 18446744073709551615 = %d, want 0", r)
+ t.Errorf("127 %s 18446744073709551615 = %d, want 0", "<<", r)
}
}
func TestConstFoldint8uint64rsh(t *testing.T) {
@@ -11574,148 +11574,148 @@ func TestConstFoldint8uint64rsh(t *testing.T) {
y = 0
r = x >> y
if r != -128 {
- t.Errorf("-128 >> 0 = %d, want -128", r)
+ t.Errorf("-128 %s 0 = %d, want -128", ">>", r)
}
y = 1
r = x >> y
if r != -64 {
- t.Errorf("-128 >> 1 = %d, want -64", r)
+ t.Errorf("-128 %s 1 = %d, want -64", ">>", r)
}
y = 4294967296
r = x >> y
if r != -1 {
- t.Errorf("-128 >> 4294967296 = %d, want -1", r)
+ t.Errorf("-128 %s 4294967296 = %d, want -1", ">>", r)
}
y = 18446744073709551615
r = x >> y
if r != -1 {
- t.Errorf("-128 >> 18446744073709551615 = %d, want -1", r)
+ t.Errorf("-128 %s 18446744073709551615 = %d, want -1", ">>", r)
}
x = -127
y = 0
r = x >> y
if r != -127 {
- t.Errorf("-127 >> 0 = %d, want -127", r)
+ t.Errorf("-127 %s 0 = %d, want -127", ">>", r)
}
y = 1
r = x >> y
if r != -64 {
- t.Errorf("-127 >> 1 = %d, want -64", r)
+ t.Errorf("-127 %s 1 = %d, want -64", ">>", r)
}
y = 4294967296
r = x >> y
if r != -1 {
- t.Errorf("-127 >> 4294967296 = %d, want -1", r)
+ t.Errorf("-127 %s 4294967296 = %d, want -1", ">>", r)
}
y = 18446744073709551615
r = x >> y
if r != -1 {
- t.Errorf("-127 >> 18446744073709551615 = %d, want -1", r)
+ t.Errorf("-127 %s 18446744073709551615 = %d, want -1", ">>", r)
}
x = -1
y = 0
r = x >> y
if r != -1 {
- t.Errorf("-1 >> 0 = %d, want -1", r)
+ t.Errorf("-1 %s 0 = %d, want -1", ">>", r)
}
y = 1
r = x >> y
if r != -1 {
- t.Errorf("-1 >> 1 = %d, want -1", r)
+ t.Errorf("-1 %s 1 = %d, want -1", ">>", r)
}
y = 4294967296
r = x >> y
if r != -1 {
- t.Errorf("-1 >> 4294967296 = %d, want -1", r)
+ t.Errorf("-1 %s 4294967296 = %d, want -1", ">>", r)
}
y = 18446744073709551615
r = x >> y
if r != -1 {
- t.Errorf("-1 >> 18446744073709551615 = %d, want -1", r)
+ t.Errorf("-1 %s 18446744073709551615 = %d, want -1", ">>", r)
}
x = 0
y = 0
r = x >> y
if r != 0 {
- t.Errorf("0 >> 0 = %d, want 0", r)
+ t.Errorf("0 %s 0 = %d, want 0", ">>", r)
}
y = 1
r = x >> y
if r != 0 {
- t.Errorf("0 >> 1 = %d, want 0", r)
+ t.Errorf("0 %s 1 = %d, want 0", ">>", r)
}
y = 4294967296
r = x >> y
if r != 0 {
- t.Errorf("0 >> 4294967296 = %d, want 0", r)
+ t.Errorf("0 %s 4294967296 = %d, want 0", ">>", r)
}
y = 18446744073709551615
r = x >> y
if r != 0 {
- t.Errorf("0 >> 18446744073709551615 = %d, want 0", r)
+ t.Errorf("0 %s 18446744073709551615 = %d, want 0", ">>", r)
}
x = 1
y = 0
r = x >> y
if r != 1 {
- t.Errorf("1 >> 0 = %d, want 1", r)
+ t.Errorf("1 %s 0 = %d, want 1", ">>", r)
}
y = 1
r = x >> y
if r != 0 {
- t.Errorf("1 >> 1 = %d, want 0", r)
+ t.Errorf("1 %s 1 = %d, want 0", ">>", r)
}
y = 4294967296
r = x >> y
if r != 0 {
- t.Errorf("1 >> 4294967296 = %d, want 0", r)
+ t.Errorf("1 %s 4294967296 = %d, want 0", ">>", r)
}
y = 18446744073709551615
r = x >> y
if r != 0 {
- t.Errorf("1 >> 18446744073709551615 = %d, want 0", r)
+ t.Errorf("1 %s 18446744073709551615 = %d, want 0", ">>", r)
}
x = 126
y = 0
r = x >> y
if r != 126 {
- t.Errorf("126 >> 0 = %d, want 126", r)
+ t.Errorf("126 %s 0 = %d, want 126", ">>", r)
}
y = 1
r = x >> y
if r != 63 {
- t.Errorf("126 >> 1 = %d, want 63", r)
+ t.Errorf("126 %s 1 = %d, want 63", ">>", r)
}
y = 4294967296
r = x >> y
if r != 0 {
- t.Errorf("126 >> 4294967296 = %d, want 0", r)
+ t.Errorf("126 %s 4294967296 = %d, want 0", ">>", r)
}
y = 18446744073709551615
r = x >> y
if r != 0 {
- t.Errorf("126 >> 18446744073709551615 = %d, want 0", r)
+ t.Errorf("126 %s 18446744073709551615 = %d, want 0", ">>", r)
}
x = 127
y = 0
r = x >> y
if r != 127 {
- t.Errorf("127 >> 0 = %d, want 127", r)
+ t.Errorf("127 %s 0 = %d, want 127", ">>", r)
}
y = 1
r = x >> y
if r != 63 {
- t.Errorf("127 >> 1 = %d, want 63", r)
+ t.Errorf("127 %s 1 = %d, want 63", ">>", r)
}
y = 4294967296
r = x >> y
if r != 0 {
- t.Errorf("127 >> 4294967296 = %d, want 0", r)
+ t.Errorf("127 %s 4294967296 = %d, want 0", ">>", r)
}
y = 18446744073709551615
r = x >> y
if r != 0 {
- t.Errorf("127 >> 18446744073709551615 = %d, want 0", r)
+ t.Errorf("127 %s 18446744073709551615 = %d, want 0", ">>", r)
}
}
func TestConstFoldint8uint32lsh(t *testing.T) {
@@ -11725,113 +11725,113 @@ func TestConstFoldint8uint32lsh(t *testing.T) {
y = 0
r = x << y
if r != -128 {
- t.Errorf("-128 << 0 = %d, want -128", r)
+ t.Errorf("-128 %s 0 = %d, want -128", "<<", r)
}
y = 1
r = x << y
if r != 0 {
- t.Errorf("-128 << 1 = %d, want 0", r)
+ t.Errorf("-128 %s 1 = %d, want 0", "<<", r)
}
y = 4294967295
r = x << y
if r != 0 {
- t.Errorf("-128 << 4294967295 = %d, want 0", r)
+ t.Errorf("-128 %s 4294967295 = %d, want 0", "<<", r)
}
x = -127
y = 0
r = x << y
if r != -127 {
- t.Errorf("-127 << 0 = %d, want -127", r)
+ t.Errorf("-127 %s 0 = %d, want -127", "<<", r)
}
y = 1
r = x << y
if r != 2 {
- t.Errorf("-127 << 1 = %d, want 2", r)
+ t.Errorf("-127 %s 1 = %d, want 2", "<<", r)
}
y = 4294967295
r = x << y
if r != 0 {
- t.Errorf("-127 << 4294967295 = %d, want 0", r)
+ t.Errorf("-127 %s 4294967295 = %d, want 0", "<<", r)
}
x = -1
y = 0
r = x << y
if r != -1 {
- t.Errorf("-1 << 0 = %d, want -1", r)
+ t.Errorf("-1 %s 0 = %d, want -1", "<<", r)
}
y = 1
r = x << y
if r != -2 {
- t.Errorf("-1 << 1 = %d, want -2", r)
+ t.Errorf("-1 %s 1 = %d, want -2", "<<", r)
}
y = 4294967295
r = x << y
if r != 0 {
- t.Errorf("-1 << 4294967295 = %d, want 0", r)
+ t.Errorf("-1 %s 4294967295 = %d, want 0", "<<", r)
}
x = 0
y = 0
r = x << y
if r != 0 {
- t.Errorf("0 << 0 = %d, want 0", r)
+ t.Errorf("0 %s 0 = %d, want 0", "<<", r)
}
y = 1
r = x << y
if r != 0 {
- t.Errorf("0 << 1 = %d, want 0", r)
+ t.Errorf("0 %s 1 = %d, want 0", "<<", r)
}
y = 4294967295
r = x << y
if r != 0 {
- t.Errorf("0 << 4294967295 = %d, want 0", r)
+ t.Errorf("0 %s 4294967295 = %d, want 0", "<<", r)
}
x = 1
y = 0
r = x << y
if r != 1 {
- t.Errorf("1 << 0 = %d, want 1", r)
+ t.Errorf("1 %s 0 = %d, want 1", "<<", r)
}
y = 1
r = x << y
if r != 2 {
- t.Errorf("1 << 1 = %d, want 2", r)
+ t.Errorf("1 %s 1 = %d, want 2", "<<", r)
}
y = 4294967295
r = x << y
if r != 0 {
- t.Errorf("1 << 4294967295 = %d, want 0", r)
+ t.Errorf("1 %s 4294967295 = %d, want 0", "<<", r)
}
x = 126
y = 0
r = x << y
if r != 126 {
- t.Errorf("126 << 0 = %d, want 126", r)
+ t.Errorf("126 %s 0 = %d, want 126", "<<", r)
}
y = 1
r = x << y
if r != -4 {
- t.Errorf("126 << 1 = %d, want -4", r)
+ t.Errorf("126 %s 1 = %d, want -4", "<<", r)
}
y = 4294967295
r = x << y
if r != 0 {
- t.Errorf("126 << 4294967295 = %d, want 0", r)
+ t.Errorf("126 %s 4294967295 = %d, want 0", "<<", r)
}
x = 127
y = 0
r = x << y
if r != 127 {
- t.Errorf("127 << 0 = %d, want 127", r)
+ t.Errorf("127 %s 0 = %d, want 127", "<<", r)
}
y = 1
r = x << y
if r != -2 {
- t.Errorf("127 << 1 = %d, want -2", r)
+ t.Errorf("127 %s 1 = %d, want -2", "<<", r)
}
y = 4294967295
r = x << y
if r != 0 {
- t.Errorf("127 << 4294967295 = %d, want 0", r)
+ t.Errorf("127 %s 4294967295 = %d, want 0", "<<", r)
}
}
func TestConstFoldint8uint32rsh(t *testing.T) {
@@ -11841,113 +11841,113 @@ func TestConstFoldint8uint32rsh(t *testing.T) {
y = 0
r = x >> y
if r != -128 {
- t.Errorf("-128 >> 0 = %d, want -128", r)
+ t.Errorf("-128 %s 0 = %d, want -128", ">>", r)
}
y = 1
r = x >> y
if r != -64 {
- t.Errorf("-128 >> 1 = %d, want -64", r)
+ t.Errorf("-128 %s 1 = %d, want -64", ">>", r)
}
y = 4294967295
r = x >> y
if r != -1 {
- t.Errorf("-128 >> 4294967295 = %d, want -1", r)
+ t.Errorf("-128 %s 4294967295 = %d, want -1", ">>", r)
}
x = -127
y = 0
r = x >> y
if r != -127 {
- t.Errorf("-127 >> 0 = %d, want -127", r)
+ t.Errorf("-127 %s 0 = %d, want -127", ">>", r)
}
y = 1
r = x >> y
if r != -64 {
- t.Errorf("-127 >> 1 = %d, want -64", r)
+ t.Errorf("-127 %s 1 = %d, want -64", ">>", r)
}
y = 4294967295
r = x >> y
if r != -1 {
- t.Errorf("-127 >> 4294967295 = %d, want -1", r)
+ t.Errorf("-127 %s 4294967295 = %d, want -1", ">>", r)
}
x = -1
y = 0
r = x >> y
if r != -1 {
- t.Errorf("-1 >> 0 = %d, want -1", r)
+ t.Errorf("-1 %s 0 = %d, want -1", ">>", r)
}
y = 1
r = x >> y
if r != -1 {
- t.Errorf("-1 >> 1 = %d, want -1", r)
+ t.Errorf("-1 %s 1 = %d, want -1", ">>", r)
}
y = 4294967295
r = x >> y
if r != -1 {
- t.Errorf("-1 >> 4294967295 = %d, want -1", r)
+ t.Errorf("-1 %s 4294967295 = %d, want -1", ">>", r)
}
x = 0
y = 0
r = x >> y
if r != 0 {
- t.Errorf("0 >> 0 = %d, want 0", r)
+ t.Errorf("0 %s 0 = %d, want 0", ">>", r)
}
y = 1
r = x >> y
if r != 0 {
- t.Errorf("0 >> 1 = %d, want 0", r)
+ t.Errorf("0 %s 1 = %d, want 0", ">>", r)
}
y = 4294967295
r = x >> y
if r != 0 {
- t.Errorf("0 >> 4294967295 = %d, want 0", r)
+ t.Errorf("0 %s 4294967295 = %d, want 0", ">>", r)
}
x = 1
y = 0
r = x >> y
if r != 1 {
- t.Errorf("1 >> 0 = %d, want 1", r)
+ t.Errorf("1 %s 0 = %d, want 1", ">>", r)
}
y = 1
r = x >> y
if r != 0 {
- t.Errorf("1 >> 1 = %d, want 0", r)
+ t.Errorf("1 %s 1 = %d, want 0", ">>", r)
}
y = 4294967295
r = x >> y
if r != 0 {
- t.Errorf("1 >> 4294967295 = %d, want 0", r)
+ t.Errorf("1 %s 4294967295 = %d, want 0", ">>", r)
}
x = 126
y = 0
r = x >> y
if r != 126 {
- t.Errorf("126 >> 0 = %d, want 126", r)
+ t.Errorf("126 %s 0 = %d, want 126", ">>", r)
}
y = 1
r = x >> y
if r != 63 {
- t.Errorf("126 >> 1 = %d, want 63", r)
+ t.Errorf("126 %s 1 = %d, want 63", ">>", r)
}
y = 4294967295
r = x >> y
if r != 0 {
- t.Errorf("126 >> 4294967295 = %d, want 0", r)
+ t.Errorf("126 %s 4294967295 = %d, want 0", ">>", r)
}
x = 127
y = 0
r = x >> y
if r != 127 {
- t.Errorf("127 >> 0 = %d, want 127", r)
+ t.Errorf("127 %s 0 = %d, want 127", ">>", r)
}
y = 1
r = x >> y
if r != 63 {
- t.Errorf("127 >> 1 = %d, want 63", r)
+ t.Errorf("127 %s 1 = %d, want 63", ">>", r)
}
y = 4294967295
r = x >> y
if r != 0 {
- t.Errorf("127 >> 4294967295 = %d, want 0", r)
+ t.Errorf("127 %s 4294967295 = %d, want 0", ">>", r)
}
}
func TestConstFoldint8uint16lsh(t *testing.T) {
@@ -11957,113 +11957,113 @@ func TestConstFoldint8uint16lsh(t *testing.T) {
y = 0
r = x << y
if r != -128 {
- t.Errorf("-128 << 0 = %d, want -128", r)
+ t.Errorf("-128 %s 0 = %d, want -128", "<<", r)
}
y = 1
r = x << y
if r != 0 {
- t.Errorf("-128 << 1 = %d, want 0", r)
+ t.Errorf("-128 %s 1 = %d, want 0", "<<", r)
}
y = 65535
r = x << y
if r != 0 {
- t.Errorf("-128 << 65535 = %d, want 0", r)
+ t.Errorf("-128 %s 65535 = %d, want 0", "<<", r)
}
x = -127
y = 0
r = x << y
if r != -127 {
- t.Errorf("-127 << 0 = %d, want -127", r)
+ t.Errorf("-127 %s 0 = %d, want -127", "<<", r)
}
y = 1
r = x << y
if r != 2 {
- t.Errorf("-127 << 1 = %d, want 2", r)
+ t.Errorf("-127 %s 1 = %d, want 2", "<<", r)
}
y = 65535
r = x << y
if r != 0 {
- t.Errorf("-127 << 65535 = %d, want 0", r)
+ t.Errorf("-127 %s 65535 = %d, want 0", "<<", r)
}
x = -1
y = 0
r = x << y
if r != -1 {
- t.Errorf("-1 << 0 = %d, want -1", r)
+ t.Errorf("-1 %s 0 = %d, want -1", "<<", r)
}
y = 1
r = x << y
if r != -2 {
- t.Errorf("-1 << 1 = %d, want -2", r)
+ t.Errorf("-1 %s 1 = %d, want -2", "<<", r)
}
y = 65535
r = x << y
if r != 0 {
- t.Errorf("-1 << 65535 = %d, want 0", r)
+ t.Errorf("-1 %s 65535 = %d, want 0", "<<", r)
}
x = 0
y = 0
r = x << y
if r != 0 {
- t.Errorf("0 << 0 = %d, want 0", r)
+ t.Errorf("0 %s 0 = %d, want 0", "<<", r)
}
y = 1
r = x << y
if r != 0 {
- t.Errorf("0 << 1 = %d, want 0", r)
+ t.Errorf("0 %s 1 = %d, want 0", "<<", r)
}
y = 65535
r = x << y
if r != 0 {
- t.Errorf("0 << 65535 = %d, want 0", r)
+ t.Errorf("0 %s 65535 = %d, want 0", "<<", r)
}
x = 1
y = 0
r = x << y
if r != 1 {
- t.Errorf("1 << 0 = %d, want 1", r)
+ t.Errorf("1 %s 0 = %d, want 1", "<<", r)
}
y = 1
r = x << y
if r != 2 {
- t.Errorf("1 << 1 = %d, want 2", r)
+ t.Errorf("1 %s 1 = %d, want 2", "<<", r)
}
y = 65535
r = x << y
if r != 0 {
- t.Errorf("1 << 65535 = %d, want 0", r)
+ t.Errorf("1 %s 65535 = %d, want 0", "<<", r)
}
x = 126
y = 0
r = x << y
if r != 126 {
- t.Errorf("126 << 0 = %d, want 126", r)
+ t.Errorf("126 %s 0 = %d, want 126", "<<", r)
}
y = 1
r = x << y
if r != -4 {
- t.Errorf("126 << 1 = %d, want -4", r)
+ t.Errorf("126 %s 1 = %d, want -4", "<<", r)
}
y = 65535
r = x << y
if r != 0 {
- t.Errorf("126 << 65535 = %d, want 0", r)
+ t.Errorf("126 %s 65535 = %d, want 0", "<<", r)
}
x = 127
y = 0
r = x << y
if r != 127 {
- t.Errorf("127 << 0 = %d, want 127", r)
+ t.Errorf("127 %s 0 = %d, want 127", "<<", r)
}
y = 1
r = x << y
if r != -2 {
- t.Errorf("127 << 1 = %d, want -2", r)
+ t.Errorf("127 %s 1 = %d, want -2", "<<", r)
}
y = 65535
r = x << y
if r != 0 {
- t.Errorf("127 << 65535 = %d, want 0", r)
+ t.Errorf("127 %s 65535 = %d, want 0", "<<", r)
}
}
func TestConstFoldint8uint16rsh(t *testing.T) {
@@ -12073,113 +12073,113 @@ func TestConstFoldint8uint16rsh(t *testing.T) {
y = 0
r = x >> y
if r != -128 {
- t.Errorf("-128 >> 0 = %d, want -128", r)
+ t.Errorf("-128 %s 0 = %d, want -128", ">>", r)
}
y = 1
r = x >> y
if r != -64 {
- t.Errorf("-128 >> 1 = %d, want -64", r)
+ t.Errorf("-128 %s 1 = %d, want -64", ">>", r)
}
y = 65535
r = x >> y
if r != -1 {
- t.Errorf("-128 >> 65535 = %d, want -1", r)
+ t.Errorf("-128 %s 65535 = %d, want -1", ">>", r)
}
x = -127
y = 0
r = x >> y
if r != -127 {
- t.Errorf("-127 >> 0 = %d, want -127", r)
+ t.Errorf("-127 %s 0 = %d, want -127", ">>", r)
}
y = 1
r = x >> y
if r != -64 {
- t.Errorf("-127 >> 1 = %d, want -64", r)
+ t.Errorf("-127 %s 1 = %d, want -64", ">>", r)
}
y = 65535
r = x >> y
if r != -1 {
- t.Errorf("-127 >> 65535 = %d, want -1", r)
+ t.Errorf("-127 %s 65535 = %d, want -1", ">>", r)
}
x = -1
y = 0
r = x >> y
if r != -1 {
- t.Errorf("-1 >> 0 = %d, want -1", r)
+ t.Errorf("-1 %s 0 = %d, want -1", ">>", r)
}
y = 1
r = x >> y
if r != -1 {
- t.Errorf("-1 >> 1 = %d, want -1", r)
+ t.Errorf("-1 %s 1 = %d, want -1", ">>", r)
}
y = 65535
r = x >> y
if r != -1 {
- t.Errorf("-1 >> 65535 = %d, want -1", r)
+ t.Errorf("-1 %s 65535 = %d, want -1", ">>", r)
}
x = 0
y = 0
r = x >> y
if r != 0 {
- t.Errorf("0 >> 0 = %d, want 0", r)
+ t.Errorf("0 %s 0 = %d, want 0", ">>", r)
}
y = 1
r = x >> y
if r != 0 {
- t.Errorf("0 >> 1 = %d, want 0", r)
+ t.Errorf("0 %s 1 = %d, want 0", ">>", r)
}
y = 65535
r = x >> y
if r != 0 {
- t.Errorf("0 >> 65535 = %d, want 0", r)
+ t.Errorf("0 %s 65535 = %d, want 0", ">>", r)
}
x = 1
y = 0
r = x >> y
if r != 1 {
- t.Errorf("1 >> 0 = %d, want 1", r)
+ t.Errorf("1 %s 0 = %d, want 1", ">>", r)
}
y = 1
r = x >> y
if r != 0 {
- t.Errorf("1 >> 1 = %d, want 0", r)
+ t.Errorf("1 %s 1 = %d, want 0", ">>", r)
}
y = 65535
r = x >> y
if r != 0 {
- t.Errorf("1 >> 65535 = %d, want 0", r)
+ t.Errorf("1 %s 65535 = %d, want 0", ">>", r)
}
x = 126
y = 0
r = x >> y
if r != 126 {
- t.Errorf("126 >> 0 = %d, want 126", r)
+ t.Errorf("126 %s 0 = %d, want 126", ">>", r)
}
y = 1
r = x >> y
if r != 63 {
- t.Errorf("126 >> 1 = %d, want 63", r)
+ t.Errorf("126 %s 1 = %d, want 63", ">>", r)
}
y = 65535
r = x >> y
if r != 0 {
- t.Errorf("126 >> 65535 = %d, want 0", r)
+ t.Errorf("126 %s 65535 = %d, want 0", ">>", r)
}
x = 127
y = 0
r = x >> y
if r != 127 {
- t.Errorf("127 >> 0 = %d, want 127", r)
+ t.Errorf("127 %s 0 = %d, want 127", ">>", r)
}
y = 1
r = x >> y
if r != 63 {
- t.Errorf("127 >> 1 = %d, want 63", r)
+ t.Errorf("127 %s 1 = %d, want 63", ">>", r)
}
y = 65535
r = x >> y
if r != 0 {
- t.Errorf("127 >> 65535 = %d, want 0", r)
+ t.Errorf("127 %s 65535 = %d, want 0", ">>", r)
}
}
func TestConstFoldint8uint8lsh(t *testing.T) {
@@ -12189,113 +12189,113 @@ func TestConstFoldint8uint8lsh(t *testing.T) {
y = 0
r = x << y
if r != -128 {
- t.Errorf("-128 << 0 = %d, want -128", r)
+ t.Errorf("-128 %s 0 = %d, want -128", "<<", r)
}
y = 1
r = x << y
if r != 0 {
- t.Errorf("-128 << 1 = %d, want 0", r)
+ t.Errorf("-128 %s 1 = %d, want 0", "<<", r)
}
y = 255
r = x << y
if r != 0 {
- t.Errorf("-128 << 255 = %d, want 0", r)
+ t.Errorf("-128 %s 255 = %d, want 0", "<<", r)
}
x = -127
y = 0
r = x << y
if r != -127 {
- t.Errorf("-127 << 0 = %d, want -127", r)
+ t.Errorf("-127 %s 0 = %d, want -127", "<<", r)
}
y = 1
r = x << y
if r != 2 {
- t.Errorf("-127 << 1 = %d, want 2", r)
+ t.Errorf("-127 %s 1 = %d, want 2", "<<", r)
}
y = 255
r = x << y
if r != 0 {
- t.Errorf("-127 << 255 = %d, want 0", r)
+ t.Errorf("-127 %s 255 = %d, want 0", "<<", r)
}
x = -1
y = 0
r = x << y
if r != -1 {
- t.Errorf("-1 << 0 = %d, want -1", r)
+ t.Errorf("-1 %s 0 = %d, want -1", "<<", r)
}
y = 1
r = x << y
if r != -2 {
- t.Errorf("-1 << 1 = %d, want -2", r)
+ t.Errorf("-1 %s 1 = %d, want -2", "<<", r)
}
y = 255
r = x << y
if r != 0 {
- t.Errorf("-1 << 255 = %d, want 0", r)
+ t.Errorf("-1 %s 255 = %d, want 0", "<<", r)
}
x = 0
y = 0
r = x << y
if r != 0 {
- t.Errorf("0 << 0 = %d, want 0", r)
+ t.Errorf("0 %s 0 = %d, want 0", "<<", r)
}
y = 1
r = x << y
if r != 0 {
- t.Errorf("0 << 1 = %d, want 0", r)
+ t.Errorf("0 %s 1 = %d, want 0", "<<", r)
}
y = 255
r = x << y
if r != 0 {
- t.Errorf("0 << 255 = %d, want 0", r)
+ t.Errorf("0 %s 255 = %d, want 0", "<<", r)
}
x = 1
y = 0
r = x << y
if r != 1 {
- t.Errorf("1 << 0 = %d, want 1", r)
+ t.Errorf("1 %s 0 = %d, want 1", "<<", r)
}
y = 1
r = x << y
if r != 2 {
- t.Errorf("1 << 1 = %d, want 2", r)
+ t.Errorf("1 %s 1 = %d, want 2", "<<", r)
}
y = 255
r = x << y
if r != 0 {
- t.Errorf("1 << 255 = %d, want 0", r)
+ t.Errorf("1 %s 255 = %d, want 0", "<<", r)
}
x = 126
y = 0
r = x << y
if r != 126 {
- t.Errorf("126 << 0 = %d, want 126", r)
+ t.Errorf("126 %s 0 = %d, want 126", "<<", r)
}
y = 1
r = x << y
if r != -4 {
- t.Errorf("126 << 1 = %d, want -4", r)
+ t.Errorf("126 %s 1 = %d, want -4", "<<", r)
}
y = 255
r = x << y
if r != 0 {
- t.Errorf("126 << 255 = %d, want 0", r)
+ t.Errorf("126 %s 255 = %d, want 0", "<<", r)
}
x = 127
y = 0
r = x << y
if r != 127 {
- t.Errorf("127 << 0 = %d, want 127", r)
+ t.Errorf("127 %s 0 = %d, want 127", "<<", r)
}
y = 1
r = x << y
if r != -2 {
- t.Errorf("127 << 1 = %d, want -2", r)
+ t.Errorf("127 %s 1 = %d, want -2", "<<", r)
}
y = 255
r = x << y
if r != 0 {
- t.Errorf("127 << 255 = %d, want 0", r)
+ t.Errorf("127 %s 255 = %d, want 0", "<<", r)
}
}
func TestConstFoldint8uint8rsh(t *testing.T) {
@@ -12305,113 +12305,113 @@ func TestConstFoldint8uint8rsh(t *testing.T) {
y = 0
r = x >> y
if r != -128 {
- t.Errorf("-128 >> 0 = %d, want -128", r)
+ t.Errorf("-128 %s 0 = %d, want -128", ">>", r)
}
y = 1
r = x >> y
if r != -64 {
- t.Errorf("-128 >> 1 = %d, want -64", r)
+ t.Errorf("-128 %s 1 = %d, want -64", ">>", r)
}
y = 255
r = x >> y
if r != -1 {
- t.Errorf("-128 >> 255 = %d, want -1", r)
+ t.Errorf("-128 %s 255 = %d, want -1", ">>", r)
}
x = -127
y = 0
r = x >> y
if r != -127 {
- t.Errorf("-127 >> 0 = %d, want -127", r)
+ t.Errorf("-127 %s 0 = %d, want -127", ">>", r)
}
y = 1
r = x >> y
if r != -64 {
- t.Errorf("-127 >> 1 = %d, want -64", r)
+ t.Errorf("-127 %s 1 = %d, want -64", ">>", r)
}
y = 255
r = x >> y
if r != -1 {
- t.Errorf("-127 >> 255 = %d, want -1", r)
+ t.Errorf("-127 %s 255 = %d, want -1", ">>", r)
}
x = -1
y = 0
r = x >> y
if r != -1 {
- t.Errorf("-1 >> 0 = %d, want -1", r)
+ t.Errorf("-1 %s 0 = %d, want -1", ">>", r)
}
y = 1
r = x >> y
if r != -1 {
- t.Errorf("-1 >> 1 = %d, want -1", r)
+ t.Errorf("-1 %s 1 = %d, want -1", ">>", r)
}
y = 255
r = x >> y
if r != -1 {
- t.Errorf("-1 >> 255 = %d, want -1", r)
+ t.Errorf("-1 %s 255 = %d, want -1", ">>", r)
}
x = 0
y = 0
r = x >> y
if r != 0 {
- t.Errorf("0 >> 0 = %d, want 0", r)
+ t.Errorf("0 %s 0 = %d, want 0", ">>", r)
}
y = 1
r = x >> y
if r != 0 {
- t.Errorf("0 >> 1 = %d, want 0", r)
+ t.Errorf("0 %s 1 = %d, want 0", ">>", r)
}
y = 255
r = x >> y
if r != 0 {
- t.Errorf("0 >> 255 = %d, want 0", r)
+ t.Errorf("0 %s 255 = %d, want 0", ">>", r)
}
x = 1
y = 0
r = x >> y
if r != 1 {
- t.Errorf("1 >> 0 = %d, want 1", r)
+ t.Errorf("1 %s 0 = %d, want 1", ">>", r)
}
y = 1
r = x >> y
if r != 0 {
- t.Errorf("1 >> 1 = %d, want 0", r)
+ t.Errorf("1 %s 1 = %d, want 0", ">>", r)
}
y = 255
r = x >> y
if r != 0 {
- t.Errorf("1 >> 255 = %d, want 0", r)
+ t.Errorf("1 %s 255 = %d, want 0", ">>", r)
}
x = 126
y = 0
r = x >> y
if r != 126 {
- t.Errorf("126 >> 0 = %d, want 126", r)
+ t.Errorf("126 %s 0 = %d, want 126", ">>", r)
}
y = 1
r = x >> y
if r != 63 {
- t.Errorf("126 >> 1 = %d, want 63", r)
+ t.Errorf("126 %s 1 = %d, want 63", ">>", r)
}
y = 255
r = x >> y
if r != 0 {
- t.Errorf("126 >> 255 = %d, want 0", r)
+ t.Errorf("126 %s 255 = %d, want 0", ">>", r)
}
x = 127
y = 0
r = x >> y
if r != 127 {
- t.Errorf("127 >> 0 = %d, want 127", r)
+ t.Errorf("127 %s 0 = %d, want 127", ">>", r)
}
y = 1
r = x >> y
if r != 63 {
- t.Errorf("127 >> 1 = %d, want 63", r)
+ t.Errorf("127 %s 1 = %d, want 63", ">>", r)
}
y = 255
r = x >> y
if r != 0 {
- t.Errorf("127 >> 255 = %d, want 0", r)
+ t.Errorf("127 %s 255 = %d, want 0", ">>", r)
}
}
func TestConstFoldCompareuint64(t *testing.T) {
diff --git a/src/cmd/compile/internal/gc/cplx.go b/src/cmd/compile/internal/gc/cplx.go
deleted file mode 100644
index 96a1dfb..0000000
--- a/src/cmd/compile/internal/gc/cplx.go
+++ /dev/null
@@ -1,474 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package gc
-
-import "cmd/internal/obj"
-
-func overlap_cplx(f *Node, t *Node) bool {
- // check whether f and t could be overlapping stack references.
- // not exact, because it's hard to check for the stack register
- // in portable code. close enough: worst case we will allocate
- // an extra temporary and the registerizer will clean it up.
- return f.Op == OINDREG && t.Op == OINDREG && f.Xoffset+f.Type.Width >= t.Xoffset && t.Xoffset+t.Type.Width >= f.Xoffset
-}
-
-func complexbool(op Op, nl, nr, res *Node, wantTrue bool, likely int, to *obj.Prog) {
- // make both sides addable in ullman order
- if nr != nil {
- if nl.Ullman > nr.Ullman && !nl.Addable {
- nl = CgenTemp(nl)
- }
-
- if !nr.Addable {
- nr = CgenTemp(nr)
- }
- }
- if !nl.Addable {
- nl = CgenTemp(nl)
- }
-
- // Break nl and nr into real and imaginary components.
- var lreal, limag, rreal, rimag Node
- subnode(&lreal, &limag, nl)
- subnode(&rreal, &rimag, nr)
-
- // build tree
- // if branching:
- // real(l) == real(r) && imag(l) == imag(r)
- // if generating a value, use a branch-free version:
- // real(l) == real(r) & imag(l) == imag(r)
- realeq := Node{
- Op: OEQ,
- Left: &lreal,
- Right: &rreal,
- Type: Types[TBOOL],
- }
- imageq := Node{
- Op: OEQ,
- Left: &limag,
- Right: &rimag,
- Type: Types[TBOOL],
- }
- and := Node{
- Op: OANDAND,
- Left: &realeq,
- Right: &imageq,
- Type: Types[TBOOL],
- }
-
- if res != nil {
- // generating a value
- and.Op = OAND
- if op == ONE {
- and.Op = OOR
- realeq.Op = ONE
- imageq.Op = ONE
- }
- Bvgen(&and, res, true)
- return
- }
-
- // generating a branch
- if op == ONE {
- wantTrue = !wantTrue
- }
-
- Bgen(&and, wantTrue, likely, to)
-}
-
-// break addable nc-complex into nr-real and ni-imaginary
-func subnode(nr *Node, ni *Node, nc *Node) {
- if !nc.Addable {
- Fatalf("subnode not addable")
- }
-
- tc := Simsimtype(nc.Type)
- tc = cplxsubtype(tc)
- t := Types[tc]
-
- if nc.Op == OLITERAL {
- u := nc.Val().U.(*Mpcplx)
- nodfconst(nr, t, &u.Real)
- nodfconst(ni, t, &u.Imag)
- return
- }
-
- *nr = *nc
- nr.Type = t
-
- *ni = *nc
- ni.Type = t
- ni.Xoffset += t.Width
-}
-
-// generate code res = -nl
-func minus(nl *Node, res *Node) {
- var ra Node
- ra.Op = OMINUS
- ra.Left = nl
- ra.Type = nl.Type
- Cgen(&ra, res)
-}
-
-// build and execute tree
-// real(res) = -real(nl)
-// imag(res) = -imag(nl)
-func complexminus(nl *Node, res *Node) {
- var n1 Node
- var n2 Node
- var n5 Node
- var n6 Node
-
- subnode(&n1, &n2, nl)
- subnode(&n5, &n6, res)
-
- minus(&n1, &n5)
- minus(&n2, &n6)
-}
-
-// build and execute tree
-// real(res) = real(nl) op real(nr)
-// imag(res) = imag(nl) op imag(nr)
-func complexadd(op Op, nl *Node, nr *Node, res *Node) {
- var n1 Node
- var n2 Node
- var n3 Node
- var n4 Node
- var n5 Node
- var n6 Node
-
- subnode(&n1, &n2, nl)
- subnode(&n3, &n4, nr)
- subnode(&n5, &n6, res)
-
- var ra Node
- ra.Op = op
- ra.Left = &n1
- ra.Right = &n3
- ra.Type = n1.Type
- Cgen(&ra, &n5)
-
- ra = Node{}
- ra.Op = op
- ra.Left = &n2
- ra.Right = &n4
- ra.Type = n2.Type
- Cgen(&ra, &n6)
-}
-
-// build and execute tree
-// tmp = real(nl)*real(nr) - imag(nl)*imag(nr)
-// imag(res) = real(nl)*imag(nr) + imag(nl)*real(nr)
-// real(res) = tmp
-func complexmul(nl *Node, nr *Node, res *Node) {
- var n1 Node
- var n2 Node
- var n3 Node
- var n4 Node
- var n5 Node
- var n6 Node
- var tmp Node
-
- subnode(&n1, &n2, nl)
- subnode(&n3, &n4, nr)
- subnode(&n5, &n6, res)
- Tempname(&tmp, n5.Type)
-
- // real part -> tmp
- var rm1 Node
-
- rm1.Op = OMUL
- rm1.Left = &n1
- rm1.Right = &n3
- rm1.Type = n1.Type
-
- var rm2 Node
- rm2.Op = OMUL
- rm2.Left = &n2
- rm2.Right = &n4
- rm2.Type = n2.Type
-
- var ra Node
- ra.Op = OSUB
- ra.Left = &rm1
- ra.Right = &rm2
- ra.Type = rm1.Type
- Cgen(&ra, &tmp)
-
- // imag part
- rm1 = Node{}
-
- rm1.Op = OMUL
- rm1.Left = &n1
- rm1.Right = &n4
- rm1.Type = n1.Type
-
- rm2 = Node{}
- rm2.Op = OMUL
- rm2.Left = &n2
- rm2.Right = &n3
- rm2.Type = n2.Type
-
- ra = Node{}
- ra.Op = OADD
- ra.Left = &rm1
- ra.Right = &rm2
- ra.Type = rm1.Type
- Cgen(&ra, &n6)
-
- // tmp ->real part
- Cgen(&tmp, &n5)
-}
-
-func nodfconst(n *Node, t *Type, fval *Mpflt) {
- *n = Node{}
- n.Op = OLITERAL
- n.Addable = true
- ullmancalc(n)
- n.SetVal(Val{fval})
- n.Type = t
-
- if !t.IsFloat() {
- Fatalf("nodfconst: bad type %v", t)
- }
-}
-
-func Complexop(n *Node, res *Node) bool {
- if n != nil && n.Type != nil {
- if n.Type.IsComplex() {
- goto maybe
- }
- }
-
- if res != nil && res.Type != nil {
- if res.Type.IsComplex() {
- goto maybe
- }
- }
-
- if n.Op == OREAL || n.Op == OIMAG {
- //dump("\ncomplex-yes", n);
- return true
- }
-
- //dump("\ncomplex-no", n);
- return false
-
-maybe:
- switch n.Op {
- case OCONV, // implemented ops
- OADD,
- OSUB,
- OMUL,
- OMINUS,
- OCOMPLEX,
- OREAL,
- OIMAG:
- //dump("\ncomplex-yes", n);
- return true
-
- case ODOT,
- ODOTPTR,
- OINDEX,
- OIND,
- ONAME:
- //dump("\ncomplex-yes", n);
- return true
- }
-
- //dump("\ncomplex-no", n);
- return false
-}
-
-func Complexmove(f *Node, t *Node) {
- if Debug['g'] != 0 {
- Dump("\ncomplexmove-f", f)
- Dump("complexmove-t", t)
- }
-
- if !t.Addable {
- Fatalf("complexmove: to not addable")
- }
-
- ft := Simsimtype(f.Type)
- tt := Simsimtype(t.Type)
- // complex to complex move/convert.
- // make f addable.
- // also use temporary if possible stack overlap.
- if (ft == TCOMPLEX64 || ft == TCOMPLEX128) && (tt == TCOMPLEX64 || tt == TCOMPLEX128) {
- if !f.Addable || overlap_cplx(f, t) {
- var tmp Node
- Tempname(&tmp, f.Type)
- Complexmove(f, &tmp)
- f = &tmp
- }
-
- var n1 Node
- var n2 Node
- subnode(&n1, &n2, f)
- var n4 Node
- var n3 Node
- subnode(&n3, &n4, t)
-
- Cgen(&n1, &n3)
- Cgen(&n2, &n4)
- } else {
- Fatalf("complexmove: unknown conversion: %v -> %v\n", f.Type, t.Type)
- }
-}
-
-func Complexgen(n *Node, res *Node) {
- if Debug['g'] != 0 {
- Dump("\ncomplexgen-n", n)
- Dump("complexgen-res", res)
- }
-
- for n.Op == OCONVNOP {
- n = n.Left
- }
-
- // pick off float/complex opcodes
- switch n.Op {
- case OCOMPLEX:
- if res.Addable {
- var n1 Node
- var n2 Node
- subnode(&n1, &n2, res)
- var tmp Node
- Tempname(&tmp, n1.Type)
- Cgen(n.Left, &tmp)
- Cgen(n.Right, &n2)
- Cgen(&tmp, &n1)
- return
- }
-
- case OREAL, OIMAG:
- nl := n.Left
- if !nl.Addable {
- var tmp Node
- Tempname(&tmp, nl.Type)
- Complexgen(nl, &tmp)
- nl = &tmp
- }
-
- var n1 Node
- var n2 Node
- subnode(&n1, &n2, nl)
- if n.Op == OREAL {
- Cgen(&n1, res)
- return
- }
-
- Cgen(&n2, res)
- return
- }
-
- // perform conversion from n to res
- tl := Simsimtype(res.Type)
-
- tl = cplxsubtype(tl)
- tr := Simsimtype(n.Type)
- tr = cplxsubtype(tr)
- if tl != tr {
- if !n.Addable {
- var n1 Node
- Tempname(&n1, n.Type)
- Complexmove(n, &n1)
- n = &n1
- }
-
- Complexmove(n, res)
- return
- }
-
- if !res.Addable {
- var n1 Node
- Igen(res, &n1, nil)
- Cgen(n, &n1)
- Regfree(&n1)
- return
- }
-
- if n.Addable {
- Complexmove(n, res)
- return
- }
-
- switch n.Op {
- default:
- Dump("complexgen: unknown op", n)
- Fatalf("complexgen: unknown op %v", n.Op)
-
- case ODOT,
- ODOTPTR,
- OINDEX,
- OIND,
- OCALLFUNC,
- OCALLMETH,
- OCALLINTER:
- var n1 Node
- Igen(n, &n1, res)
-
- Complexmove(&n1, res)
- Regfree(&n1)
- return
-
- case OCONV,
- OADD,
- OSUB,
- OMUL,
- OMINUS,
- OCOMPLEX,
- OREAL,
- OIMAG:
- break
- }
-
- nl := n.Left
- if nl == nil {
- return
- }
- nr := n.Right
-
- // make both sides addable in ullman order
- var tnl Node
- if nr != nil {
- if nl.Ullman > nr.Ullman && !nl.Addable {
- Tempname(&tnl, nl.Type)
- Cgen(nl, &tnl)
- nl = &tnl
- }
-
- if !nr.Addable {
- var tnr Node
- Tempname(&tnr, nr.Type)
- Cgen(nr, &tnr)
- nr = &tnr
- }
- }
-
- if !nl.Addable {
- Tempname(&tnl, nl.Type)
- Cgen(nl, &tnl)
- nl = &tnl
- }
-
- switch n.Op {
- default:
- Fatalf("complexgen: unknown op %v", n.Op)
-
- case OCONV:
- Complexmove(nl, res)
-
- case OMINUS:
- complexminus(nl, res)
-
- case OADD, OSUB:
- complexadd(n.Op, nl, nr, res)
-
- case OMUL:
- complexmul(nl, nr, res)
- }
-}
diff --git a/src/cmd/compile/internal/gc/dcl.go b/src/cmd/compile/internal/gc/dcl.go
index a4b98ec..3cdd71d 100644
--- a/src/cmd/compile/internal/gc/dcl.go
+++ b/src/cmd/compile/internal/gc/dcl.go
@@ -106,7 +106,7 @@ func testdclstack() {
if nerrors != 0 {
errorexit()
}
- Yyerror("mark left on the stack")
+ yyerror("mark left on the stack")
}
}
}
@@ -121,7 +121,8 @@ func redeclare(s *Sym, where string) {
tmp = s.Pkg.Path
}
pkgstr := tmp
- Yyerror("%v redeclared %s\n"+"\tprevious declaration during import %q", s, where, pkgstr)
+ yyerror("%v redeclared %s\n"+
+ "\tprevious declaration during import %q", s, where, pkgstr)
} else {
line1 := lineno
line2 := s.Lastlineno
@@ -135,7 +136,8 @@ func redeclare(s *Sym, where string) {
line1 = s.Lastlineno
}
- yyerrorl(line1, "%v redeclared %s\n"+"\tprevious declaration at %v", s, where, linestr(line2))
+ yyerrorl(line1, "%v redeclared %s\n"+
+ "\tprevious declaration at %v", s, where, linestr(line2))
}
}
@@ -165,11 +167,11 @@ func declare(n *Node, ctxt Class) {
// kludgy: typecheckok means we're past parsing. Eg genwrapper may declare out of package names later.
if importpkg == nil && !typecheckok && s.Pkg != localpkg {
- Yyerror("cannot declare name %v", s)
+ yyerror("cannot declare name %v", s)
}
if ctxt == PEXTERN && s.Name == "init" {
- Yyerror("cannot declare init - must be func")
+ yyerror("cannot declare init - must be func")
}
gen := 0
@@ -209,7 +211,7 @@ func declare(n *Node, ctxt Class) {
s.Lastlineno = lineno
s.Def = n
n.Name.Vargen = int32(gen)
- n.Name.Funcdepth = Funcdepth
+ n.Name.Funcdepth = funcdepth
n.Class = ctxt
autoexport(n, ctxt)
@@ -233,7 +235,7 @@ func variter(vl []*Node, t *Node, el []*Node) []*Node {
if len(el) == 1 && len(vl) > 1 {
e := el[0]
- as2 := Nod(OAS2, nil, nil)
+ as2 := nod(OAS2, nil, nil)
as2.List.Set(vl)
as2.Rlist.Set1(e)
for _, v := range vl {
@@ -241,8 +243,8 @@ func variter(vl []*Node, t *Node, el []*Node) []*Node {
declare(v, dclcontext)
v.Name.Param.Ntype = t
v.Name.Defn = as2
- if Funcdepth > 0 {
- init = append(init, Nod(ODCL, v, nil))
+ if funcdepth > 0 {
+ init = append(init, nod(ODCL, v, nil))
}
}
@@ -253,7 +255,7 @@ func variter(vl []*Node, t *Node, el []*Node) []*Node {
var e *Node
if doexpr {
if len(el) == 0 {
- Yyerror("missing expression in var declaration")
+ yyerror("missing expression in var declaration")
break
}
e = el[0]
@@ -264,11 +266,11 @@ func variter(vl []*Node, t *Node, el []*Node) []*Node {
declare(v, dclcontext)
v.Name.Param.Ntype = t
- if e != nil || Funcdepth > 0 || isblank(v) {
- if Funcdepth > 0 {
- init = append(init, Nod(ODCL, v, nil))
+ if e != nil || funcdepth > 0 || isblank(v) {
+ if funcdepth > 0 {
+ init = append(init, nod(ODCL, v, nil))
}
- e = Nod(OAS, v, e)
+ e = nod(OAS, v, e)
init = append(init, e)
if e.Right != nil {
v.Name.Defn = e
@@ -277,7 +279,7 @@ func variter(vl []*Node, t *Node, el []*Node) []*Node {
}
if len(el) != 0 {
- Yyerror("extra expression in var declaration")
+ yyerror("extra expression in var declaration")
}
return init
}
@@ -288,7 +290,7 @@ 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")
+ yyerror("const declaration cannot have type without expression")
}
cl = lastconst
t = lasttype
@@ -302,7 +304,7 @@ func constiter(vl []*Node, t *Node, cl []*Node) []*Node {
var vv []*Node
for _, v := range vl {
if len(clcopy) == 0 {
- Yyerror("missing value in const declaration")
+ yyerror("missing value in const declaration")
break
}
@@ -315,11 +317,11 @@ func constiter(vl []*Node, t *Node, cl []*Node) []*Node {
v.Name.Param.Ntype = t
v.Name.Defn = c
- vv = append(vv, Nod(ODCLCONST, v, nil))
+ vv = append(vv, nod(ODCLCONST, v, nil))
}
if len(clcopy) != 0 {
- Yyerror("extra expression in const declaration")
+ yyerror("extra expression in const declaration")
}
iota_ += 1
return vv
@@ -330,10 +332,21 @@ 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
+}
- n := Nod(ONAME, nil, nil)
+// newnoname returns a new ONONAME Node associated with symbol s.
+func newnoname(s *Sym) *Node {
+ if s == nil {
+ Fatalf("newnoname nil")
+ }
+ n := nod(ONONAME, nil, nil)
n.Sym = s
- n.Type = nil
n.Addable = true
n.Ullman = 1
n.Xoffset = 0
@@ -345,7 +358,7 @@ func newname(s *Sym) *Node {
func newfuncname(s *Sym) *Node {
n := newname(s)
n.Func = new(Func)
- n.Func.FCurfn = Curfn
+ n.Func.IsHiddenClosure = Curfn != nil
return n
}
@@ -361,13 +374,21 @@ func typenod(t *Type) *Node {
// if we copied another type with *t = *u
// then t->nod might be out of date, so
// check t->nod->type too
- if t.Nod == nil || t.Nod.Type != t {
- t.Nod = Nod(OTYPE, nil, nil)
- t.Nod.Type = t
- t.Nod.Sym = t.Sym
+ if t.nod == nil || t.nod.Type != t {
+ t.nod = nod(OTYPE, nil, nil)
+ t.nod.Type = t
+ t.nod.Sym = t.Sym
}
- return t.Nod
+ return t.nod
+}
+
+func anonfield(typ *Type) *Node {
+ return nod(ODCLFIELD, nil, typenod(typ))
+}
+
+func namedfield(s string, typ *Type) *Node {
+ return nod(ODCLFIELD, newname(lookup(s)), typenod(typ))
}
// oldname returns the Node that declares symbol s in the current scope.
@@ -378,13 +399,12 @@ func oldname(s *Sym) *Node {
// Maybe a top-level declaration will come along later to
// define s. resolve will check s.Def again once all input
// source has been processed.
- n = newname(s)
- n.Op = ONONAME
- n.Name.Iota = iota_ // save current iota value in const declarations
+ n = newnoname(s)
+ n.SetIota(iota_) // save current iota value in const declarations
return n
}
- if Curfn != nil && n.Op == ONAME && n.Name.Funcdepth > 0 && n.Name.Funcdepth != Funcdepth {
+ if Curfn != nil && n.Op == ONAME && n.Name.Funcdepth > 0 && n.Name.Funcdepth != funcdepth {
// Inner func is referring to var in outer func.
//
// TODO(rsc): If there is an outer variable x and we
@@ -392,9 +412,9 @@ func oldname(s *Sym) *Node {
// the := it looks like a reference to the outer x so we'll
// make x a closure variable unnecessarily.
c := n.Name.Param.Innermost
- if c == nil || c.Name.Funcdepth != Funcdepth {
+ 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 = nod(ONAME, nil, nil)
c.Sym = s
c.Class = PAUTOHEAP
c.setIsClosureVar(true)
@@ -402,7 +422,7 @@ func oldname(s *Sym) *Node {
c.Name.Defn = n
c.Addable = false
c.Ullman = 2
- c.Name.Funcdepth = Funcdepth
+ c.Name.Funcdepth = funcdepth
// Link into list of active closure variables.
// Popped from list in func closurebody.
@@ -454,7 +474,7 @@ func colasdefn(left []*Node, defn *Node) {
if n.Sym.Flags&SymUniq == 0 {
yyerrorl(defn.Lineno, "%v repeated on left side of :=", n.Sym)
- n.Diag++
+ n.Diag = true
nerr++
continue
}
@@ -468,7 +488,7 @@ func colasdefn(left []*Node, defn *Node) {
n = newname(n.Sym)
declare(n, dclcontext)
n.Name.Defn = defn
- defn.Ninit.Append(Nod(ODCL, n, nil))
+ defn.Ninit.Append(nod(ODCL, n, nil))
left[i] = n
}
@@ -477,23 +497,6 @@ func colasdefn(left []*Node, defn *Node) {
}
}
-func colas(left, right []*Node, lno int32) *Node {
- n := Nod(OAS, nil, nil) // assume common case
- n.Colas = true
- n.Lineno = lno // set before calling colasdefn for correct error line
- colasdefn(left, n) // modifies left, call before using left[0] in common case
- if len(left) == 1 && len(right) == 1 {
- // common case
- n.Left = left[0]
- n.Right = right[0]
- } else {
- n.Op = OAS2
- n.List.Set(left)
- n.Rlist.Set(right)
- }
- return n
-}
-
// declare the arguments in an
// interface field declaration.
func ifacedcl(n *Node) {
@@ -502,23 +505,8 @@ func ifacedcl(n *Node) {
}
if isblank(n.Left) {
- Yyerror("methods must have a unique non-blank name")
+ yyerror("methods must have a unique non-blank name")
}
-
- n.Func = new(Func)
- n.Func.FCurfn = Curfn
- dclcontext = PPARAM
-
- funcstart(n)
- funcargs(n.Right)
-
- // funcbody is normally called after the parser has
- // seen the body of a function but since an interface
- // field declaration does not have a body, we must
- // call it now to pop the current declaration context.
- dclcontext = PAUTO
-
- funcbody(n)
}
// declare the function proper
@@ -527,11 +515,11 @@ func ifacedcl(n *Node) {
// returns in auto-declaration context.
func funchdr(n *Node) {
// change the declaration context from extern to auto
- if Funcdepth == 0 && dclcontext != PEXTERN {
+ if funcdepth == 0 && dclcontext != PEXTERN {
Fatalf("funchdr: dclcontext = %d", dclcontext)
}
- if importpkg == nil && n.Func.Nname != nil {
+ if Ctxt.Flag_dynlink && importpkg == nil && n.Func.Nname != nil {
makefuncsym(n.Func.Nname.Sym)
}
@@ -601,7 +589,7 @@ func funcargs(nt *Node) {
if n.Left == nil {
// Name so that escape analysis can track it. ~r stands for 'result'.
- n.Left = newname(LookupN("~r", gen))
+ n.Left = newname(lookupN("~r", gen))
gen++
}
@@ -619,7 +607,7 @@ func funcargs(nt *Node) {
// Having multiple names causes too much confusion in later passes.
nn := *n.Left
nn.Orig = &nn
- nn.Sym = LookupN("~b", gen)
+ nn.Sym = lookupN("~b", gen)
gen++
n.Left = &nn
}
@@ -670,14 +658,14 @@ func funcargs2(t *Type) {
}
var funcstack []*Node // stack of previous values of Curfn
-var Funcdepth int32 // len(funcstack) during parsing, but then forced to be the same later during compilation
+var funcdepth int32 // len(funcstack) during parsing, but then forced to be the same later during compilation
// start the function.
// called before funcargs; undone at end of funcbody.
func funcstart(n *Node) {
markdcl()
funcstack = append(funcstack, Curfn)
- Funcdepth++
+ funcdepth++
Curfn = n
}
@@ -691,8 +679,8 @@ func funcbody(n *Node) {
}
popdcl()
funcstack, Curfn = funcstack[:len(funcstack)-1], funcstack[len(funcstack)-1]
- Funcdepth--
- if Funcdepth == 0 {
+ funcdepth--
+ if funcdepth == 0 {
dclcontext = PEXTERN
}
}
@@ -711,7 +699,7 @@ func typedcl0(s *Sym) *Node {
func typedcl1(n *Node, t *Node, local bool) *Node {
n.Name.Param.Ntype = t
n.Local = local
- return Nod(ODCLTYPE, n, nil)
+ return nod(ODCLTYPE, n, nil)
}
// structs, functions, and methods.
@@ -724,12 +712,12 @@ func checkembeddedtype(t *Type) {
if t.Sym == nil && t.IsPtr() {
t = t.Elem()
if t.IsInterface() {
- Yyerror("embedded type cannot be a pointer to interface")
+ yyerror("embedded type cannot be a pointer to interface")
}
}
if t.IsPtr() || t.IsUnsafePtr() {
- Yyerror("embedded type cannot be a pointer")
+ yyerror("embedded type cannot be a pointer")
} else if t.Etype == TFORW && t.ForwardType().Embedlineno == 0 {
t.ForwardType().Embedlineno = lineno
}
@@ -768,7 +756,7 @@ func structfield(n *Node) *Field {
case string:
f.Note = u
default:
- Yyerror("field annotation must be string")
+ yyerror("field annotation must be string")
case nil:
// noop
}
@@ -796,7 +784,7 @@ func checkdupfields(what string, ts ...*Type) {
}
if seen[f.Sym] {
lineno = f.Nname.Lineno
- Yyerror("duplicate %s %s", what, f.Sym.Name)
+ yyerror("duplicate %s %s", what, f.Sym.Name)
continue
}
seen[f.Sym] = true
@@ -858,6 +846,22 @@ func tofunargs(l []*Node, funarg Funarg) *Type {
return t
}
+func tofunargsfield(fields []*Field, funarg Funarg) *Type {
+ t := typ(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
+ }
+ }
+ t.SetFields(fields)
+ return t
+}
+
func interfacefield(n *Node) *Field {
lno := lineno
lineno = n.Lineno
@@ -867,7 +871,7 @@ func interfacefield(n *Node) *Field {
}
if n.Val().Ctype() != CTxxx {
- Yyerror("interface method cannot have annotation")
+ yyerror("interface method cannot have annotation")
}
f := newField()
@@ -902,11 +906,11 @@ func interfacefield(n *Node) *Field {
break
case TFORW:
- Yyerror("interface type loop involving %v", n.Type)
+ yyerror("interface type loop involving %v", n.Type)
f.Broke = true
default:
- Yyerror("interface contains embedded non-interface %v", n.Type)
+ yyerror("interface contains embedded non-interface %v", n.Type)
f.Broke = true
}
}
@@ -982,40 +986,42 @@ func embedded(s *Sym, pkg *Pkg) *Node {
var n *Node
if exportname(name) {
- n = newname(Lookup(name))
+ n = newname(lookup(name))
} else if s.Pkg == builtinpkg {
// The name of embedded builtins belongs to pkg.
n = newname(Pkglookup(name, pkg))
} else {
n = newname(Pkglookup(name, s.Pkg))
}
- n = Nod(ODCLFIELD, n, oldname(s))
+ n = nod(ODCLFIELD, n, oldname(s))
n.Embedded = 1
return n
}
+// thisT is the singleton type used for interface method receivers.
+var thisT *Type
+
func fakethis() *Node {
- n := Nod(ODCLFIELD, nil, typenod(Ptrto(typ(TSTRUCT))))
- return n
+ if thisT == nil {
+ thisT = ptrto(typ(TSTRUCT))
+ }
+ return nod(ODCLFIELD, nil, typenod(thisT))
+}
+
+func fakethisfield() *Field {
+ if thisT == nil {
+ thisT = ptrto(typ(TSTRUCT))
+ }
+ f := newField()
+ f.Type = thisT
+ return f
}
// Is this field a method on an interface?
-// Those methods have an anonymous *struct{} as the receiver.
+// Those methods have thisT as the receiver.
// (See fakethis above.)
func isifacemethod(f *Type) bool {
- rcvr := f.Recv()
- if rcvr.Sym != nil {
- return false
- }
- t := rcvr.Type
- if !t.IsPtr() {
- return false
- }
- t = t.Elem()
- if t.Sym != nil || !t.IsStruct() || t.NumFields() != 0 {
- return false
- }
- return true
+ return f.Recv().Type == thisT
}
// turn a parsed function declaration into a type
@@ -1034,9 +1040,9 @@ func functype0(t *Type, this *Node, in, out []*Node) {
if this != nil {
rcvr = []*Node{this}
}
- *t.RecvsP() = tofunargs(rcvr, FunargRcvr)
- *t.ResultsP() = tofunargs(out, FunargResults)
- *t.ParamsP() = tofunargs(in, FunargParams)
+ t.FuncType().Receiver = tofunargs(rcvr, FunargRcvr)
+ t.FuncType().Results = tofunargs(out, FunargResults)
+ t.FuncType().Params = tofunargs(in, FunargParams)
checkdupfields("argument", t.Recvs(), t.Results(), t.Params())
@@ -1053,6 +1059,30 @@ func functype0(t *Type, this *Node, in, out []*Node) {
}
}
+func functypefield(this *Field, in, out []*Field) *Type {
+ t := typ(TFUNC)
+ functypefield0(t, this, in, out)
+ return t
+}
+
+func functypefield0(t *Type, this *Field, in, out []*Field) {
+ var rcvr []*Field
+ if this != nil {
+ rcvr = []*Field{this}
+ }
+ t.FuncType().Receiver = tofunargsfield(rcvr, FunargRcvr)
+ t.FuncType().Results = tofunargsfield(out, FunargRcvr)
+ t.FuncType().Params = tofunargsfield(in, 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 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
func methodsym(nsym *Sym, t0 *Type, iface int) *Sym {
@@ -1082,7 +1112,7 @@ func methodsym(nsym *Sym, t0 *Type, iface int) *Sym {
// 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 = ptrto(t)
}
suffix = ""
@@ -1095,15 +1125,15 @@ func methodsym(nsym *Sym, t0 *Type, iface int) *Sym {
if (spkg == nil || nsym.Pkg != spkg) && !exportname(nsym.Name) {
if t0.Sym == nil && t0.IsPtr() {
- p = fmt.Sprintf("(%v).%s.%s%s", Tconv(t0, FmtLeft|FmtShort), nsym.Pkg.Prefix, nsym.Name, suffix)
+ p = fmt.Sprintf("(%-S).%s.%s%s", t0, nsym.Pkg.Prefix, nsym.Name, suffix)
} else {
- p = fmt.Sprintf("%v.%s.%s%s", Tconv(t0, FmtLeft|FmtShort), nsym.Pkg.Prefix, nsym.Name, suffix)
+ p = fmt.Sprintf("%-S.%s.%s%s", t0, nsym.Pkg.Prefix, nsym.Name, suffix)
}
} else {
if t0.Sym == nil && t0.IsPtr() {
- p = fmt.Sprintf("(%v).%s%s", Tconv(t0, FmtLeft|FmtShort), nsym.Name, suffix)
+ p = fmt.Sprintf("(%-S).%s%s", t0, nsym.Name, suffix)
} else {
- p = fmt.Sprintf("%v.%s%s", Tconv(t0, FmtLeft|FmtShort), nsym.Name, suffix)
+ p = fmt.Sprintf("%-S.%s%s", t0, nsym.Name, suffix)
}
}
@@ -1119,50 +1149,45 @@ func methodsym(nsym *Sym, t0 *Type, iface int) *Sym {
return s
bad:
- Yyerror("illegal receiver type: %v", t0)
+ yyerror("illegal receiver type: %v", t0)
return nil
}
-func methodname(n *Node, t *Type) *Node {
- s := methodsym(n.Sym, t, 0)
- if s == nil {
- return n
- }
- return newname(s)
-}
-
-func methodname1(n *Node, t *Node) *Node {
- star := ""
+func methodname(n *Node, t *Node) *Node {
+ star := false
if t.Op == OIND {
- star = "*"
+ star = true
t = t.Left
}
- if t.Sym == nil || isblank(n) {
- return newfuncname(n.Sym)
+ return methodname0(n.Sym, star, t.Sym)
+}
+
+func methodname0(s *Sym, star bool, tsym *Sym) *Node {
+ if tsym == nil || isblanksym(s) {
+ return newfuncname(s)
}
var p string
- if star != "" {
- p = fmt.Sprintf("(%s%v).%v", star, t.Sym, n.Sym)
+ if star {
+ p = fmt.Sprintf("(*%v).%v", tsym, s)
} else {
- p = fmt.Sprintf("%v.%v", t.Sym, n.Sym)
+ p = fmt.Sprintf("%v.%v", tsym, s)
}
- if exportname(t.Sym.Name) {
- n = newfuncname(Lookup(p))
+ if exportname(tsym.Name) {
+ s = lookup(p)
} else {
- n = newfuncname(Pkglookup(p, t.Sym.Pkg))
+ s = Pkglookup(p, tsym.Pkg)
}
- return n
+ return newfuncname(s)
}
// Add a method, declared as a function.
// - msym is the method symbol
// - t is function type (with receiver)
-// - tpkg is the package of the type declaring the method during import, or nil (ignored) --- for verification only
-func addmethod(msym *Sym, t *Type, tpkg *Pkg, local, nointerface bool) {
+func addmethod(msym *Sym, t *Type, local, nointerface bool) {
// get field sym
if msym == nil {
Fatalf("no method symbol")
@@ -1171,56 +1196,41 @@ func addmethod(msym *Sym, t *Type, tpkg *Pkg, local, nointerface bool) {
// get parent type sym
rf := t.Recv() // ptr to this structure
if rf == nil {
- Yyerror("missing receiver")
+ yyerror("missing receiver")
return
}
- pa := rf.Type // base type
- mt := methtype(pa, 1)
- if mt == nil {
- t = pa
- if t == nil { // rely on typecheck having complained before
- return
- }
- if t != nil {
- if t.IsPtr() {
- if t.Sym != nil {
- Yyerror("invalid receiver type %v (%v is a pointer type)", pa, t)
- return
- }
-
- t = t.Elem()
- }
-
- if t.Broke { // rely on typecheck having complained before
- return
- }
- if t.Sym == nil {
- Yyerror("invalid receiver type %v (%v is an unnamed type)", pa, t)
- return
- }
-
- if t.IsPtr() {
- Yyerror("invalid receiver type %v (%v is a pointer type)", pa, t)
- return
- }
-
- if t.IsInterface() {
- Yyerror("invalid receiver type %v (%v is an interface type)", pa, t)
+ mt := methtype(rf.Type)
+ if mt == nil || mt.Sym == nil {
+ pa := rf.Type
+ t := pa
+ if t != nil && t.IsPtr() {
+ if t.Sym != nil {
+ yyerror("invalid receiver type %v (%v is a pointer type)", pa, t)
return
}
+ t = t.Elem()
}
- // Should have picked off all the reasons above,
- // but just in case, fall back to generic error.
- Yyerror("invalid receiver type %v (%v / %v)", pa, Tconv(pa, FmtLong), Tconv(t, FmtLong))
-
+ switch {
+ 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)
+ case t.IsPtr():
+ yyerror("invalid receiver type %v (%v is a pointer type)", pa, t)
+ case t.IsInterface():
+ yyerror("invalid receiver type %v (%v is an interface type)", pa, t)
+ default:
+ // Should have picked off all the reasons above,
+ // but just in case, fall back to generic error.
+ yyerror("invalid receiver type %v (%L / %L)", pa, pa, t)
+ }
return
}
- pa = mt
- if local && !pa.Local {
- Yyerror("cannot define new methods on non-local type %v", pa)
+ if local && !mt.Local {
+ yyerror("cannot define new methods on non-local type %v", mt)
return
}
@@ -1228,39 +1238,34 @@ func addmethod(msym *Sym, t *Type, tpkg *Pkg, local, nointerface bool) {
return
}
- if pa.IsStruct() {
- for _, f := range pa.Fields().Slice() {
+ if mt.IsStruct() {
+ for _, f := range mt.Fields().Slice() {
if f.Sym == msym {
- Yyerror("type %v has both field and method named %v", pa, msym)
+ yyerror("type %v has both field and method named %v", mt, msym)
return
}
}
}
- n := Nod(ODCLFIELD, newname(msym), nil)
- n.Type = t
-
- for _, f := range pa.Methods().Slice() {
+ for _, f := range mt.Methods().Slice() {
if msym.Name != f.Sym.Name {
continue
}
- // Eqtype only checks that incoming and result parameters match,
+ // eqtype only checks that incoming and result parameters match,
// so explicitly check that the receiver parameters match too.
- if !Eqtype(t, f.Type) || !Eqtype(t.Recv().Type, f.Type.Recv().Type) {
- Yyerror("method redeclared: %v.%v\n\t%v\n\t%v", pa, msym, f.Type, t)
+ if !eqtype(t, f.Type) || !eqtype(t.Recv().Type, f.Type.Recv().Type) {
+ yyerror("method redeclared: %v.%v\n\t%v\n\t%v", mt, msym, f.Type, t)
}
return
}
- f := structfield(n)
+ f := newField()
+ f.Sym = msym
+ f.Nname = newname(msym)
+ f.Type = t
f.Nointerface = nointerface
- // during import unexported method names should be in the type's package
- if tpkg != nil && f.Sym != nil && !exportname(f.Sym.Name) && f.Sym.Pkg != tpkg {
- Fatalf("imported method name %v in wrong package %s\n", sconv(f.Sym, FmtSign), tpkg.Name)
- }
-
- pa.Methods().Append(f)
+ mt.Methods().Append(f)
}
func funccompile(n *Node) {
@@ -1283,19 +1288,16 @@ func funccompile(n *Node) {
Stksize = 0
dclcontext = PAUTO
- Funcdepth = n.Func.Depth + 1
+ funcdepth = n.Func.Depth + 1
compile(n)
Curfn = nil
- Pc = nil
- continpc = nil
- breakpc = nil
- Funcdepth = 0
+ pc = nil
+ funcdepth = 0
dclcontext = PEXTERN
if nerrors != 0 {
// If we have compile errors, ignore any assembler/linker errors.
Ctxt.DiagFunc = func(string, ...interface{}) {}
}
- flushdata()
obj.Flushplist(Ctxt) // convert from Prog list to machine code
}
@@ -1305,6 +1307,11 @@ func funcsym(s *Sym) *Sym {
}
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
}
@@ -1347,7 +1354,7 @@ 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 {
+ if n.Func.WBLineno != 0 && n.Func.Pragma&Yeswritebarrierrec == 0 {
c.best[n] = nowritebarrierrecCall{target: nil, depth: 0, lineno: n.Func.WBLineno}
}
}
@@ -1359,6 +1366,12 @@ func checknowritebarrierrec() {
for _ = range list {
c.stable = false
for _, n := range list {
+ if n.Func.Pragma&Yeswritebarrierrec != 0 {
+ // Don't propagate write
+ // barrier up to a
+ // yeswritebarrierrec function.
+ continue
+ }
if n.Func.WBLineno == 0 {
c.curfn = n
c.visitcodelist(n.Nbody)
@@ -1423,9 +1436,6 @@ func (c *nowritebarrierrecChecker) visitcall(n *Node) {
if fn == nil || fn.Op != ONAME || fn.Class != PFUNC || fn.Name.Defn == nil {
return
}
- if (compiling_runtime || fn.Sym.Pkg == Runtimepkg) && fn.Sym.Name == "allocm" {
- return
- }
defn := fn.Name.Defn
fnbest, ok := c.best[defn]
diff --git a/src/cmd/compile/internal/gc/esc.go b/src/cmd/compile/internal/gc/esc.go
index 69b5964..4f37ff0 100644
--- a/src/cmd/compile/internal/gc/esc.go
+++ b/src/cmd/compile/internal/gc/esc.go
@@ -14,11 +14,11 @@ import (
// or single non-recursive functions, bottom up.
//
// Finding these sets is finding strongly connected components
-// in the static call graph. The algorithm for doing that is taken
-// from Sedgewick, Algorithms, Second Edition, p. 482, with two
-// adaptations.
+// by reverse topological order in the static call graph.
+// 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->curfn != N) 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 +58,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.FCurfn == nil {
+ if n.Op == ODCLFUNC && !n.Func.IsHiddenClosure {
v.visit(n)
}
}
@@ -78,11 +78,11 @@ 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.FCurfn == nil {
+ 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 n->walkgen+1.
- // If visitcodelist found its way back to n->walkgen, then this
+ // The original min passed to visitcodelist was v.nodeID[n]+1.
+ // If visitcodelist found its way back to v.nodeID[n], then this
// block is a set of mutually recursive functions.
// Otherwise it's just a lone function that does not recurse.
recursive := min == id
@@ -160,7 +160,7 @@ func (v *bottomUpVisitor) visitcode(n *Node, min uint32) uint32 {
//
// First escfunc, esc and escassign recurse over the ast of each
// function to dig out flow(dst,src) edges between any
-// pointer-containing nodes and store them in dst->escflowsrc. For
+// pointer-containing nodes and store them in e.nodeEscState(dst).Flowsrc. For
// variables assigned to a variable in an outer scope or used as a
// return value, they store a flow(theSink, src) edge to a fake node
// 'the Sink'. For variables referenced in closures, an edge
@@ -302,6 +302,7 @@ func (l Level) guaranteedDereference() int {
// heap allocation.
type EscStep struct {
src, dst *Node // the endpoints of this edge in the escape-to-heap chain.
+ where *Node // sometimes the endpoints don't match source locations; set 'where' to make that right
parent *EscStep // used in flood to record path
why string // explanation for this step in the escape-to-heap chain
busy bool // used in prevent to snip cycles.
@@ -309,10 +310,10 @@ type EscStep struct {
type NodeEscState struct {
Curfn *Node
- Escflowsrc []EscStep // flow(this, src)
- Escretval Nodes // on OCALLxxx, list of dummy return values
- Escloopdepth int32 // -1: global, 0: return variables, 1:function top level, increased inside function for every loop or label to mark scopes
- Esclevel Level
+ Flowsrc []EscStep // flow(this, src)
+ Retval Nodes // on OCALLxxx, list of dummy return values
+ Loopdepth int32 // -1: global, 0: return variables, 1:function top level, increased inside function for every loop or label to mark scopes
+ Level Level
Walkgen uint32
Maxextraloopdepth int32
}
@@ -324,8 +325,9 @@ func (e *EscState) nodeEscState(n *Node) *NodeEscState {
if n.Opt() != nil {
Fatalf("nodeEscState: opt in use (%T)", n.Opt())
}
- nE := new(NodeEscState)
- nE.Curfn = Curfn
+ nE := &NodeEscState{
+ Curfn: Curfn,
+ }
n.SetOpt(nE)
e.opts = append(e.opts, n)
return nE
@@ -337,7 +339,7 @@ func (e *EscState) track(n *Node) {
}
n.Esc = EscNone // until proven otherwise
nE := e.nodeEscState(n)
- nE.Escloopdepth = e.loopdepth
+ nE.Loopdepth = e.loopdepth
e.noesc = append(e.noesc, n)
}
@@ -346,12 +348,9 @@ func (e *EscState) track(n *Node) {
// EscNever which is sticky, eX < eY means that eY is more exposed
// than eX, and hence replaces it in a conservative analysis.
const (
- EscUnknown = iota
- EscNone // Does not escape to heap, result, or parameters.
- EscReturn // Is returned or reachable from returned.
- EscScope // Allocated in an inner loop scope, assigned to an outer loop scope,
- // which allows the construction of non-escaping but arbitrarily large linked
- // data structures (i.e., not eligible for allocation in a fixed-size stack frame).
+ EscUnknown = iota
+ EscNone // Does not escape to heap, result, or parameters.
+ EscReturn // Is returned or reachable from returned.
EscHeap // Reachable from the heap
EscNever // By construction will not escape.
EscBits = 3
@@ -364,10 +363,10 @@ const (
// escMax returns the maximum of an existing escape value
// (and its additional parameter flow flags) and a new escape type.
func escMax(e, etype uint16) uint16 {
- if e&EscMask >= EscScope {
+ if e&EscMask >= EscHeap {
// normalize
if e&^EscMask != 0 {
- Fatalf("Escape information had unexpected return encoding bits (w/ EscScope, EscHeap, EscNever), e&EscMask=%v", e&EscMask)
+ Fatalf("Escape information had unexpected return encoding bits (w/ EscHeap, EscNever), e&EscMask=%v", e&EscMask)
}
}
if e&EscMask > etype {
@@ -409,6 +408,17 @@ type EscState struct {
walkgen uint32
}
+func newEscState(recursive bool) *EscState {
+ e := new(EscState)
+ e.theSink.Op = ONAME
+ e.theSink.Orig = &e.theSink
+ e.theSink.Class = PEXTERN
+ e.theSink.Sym = lookup(".sink")
+ e.nodeEscState(&e.theSink).Loopdepth = -1
+ e.recursive = recursive
+ return e
+}
+
func (e *EscState) stepWalk(dst, src *Node, why string, parent *EscStep) *EscStep {
// TODO: keep a cache of these, mark entry/exit in escwalk to avoid allocation
// Or perhaps never mind, since it is disabled unless printing is on.
@@ -426,11 +436,27 @@ func (e *EscState) stepAssign(step *EscStep, dst, src *Node, why string) *EscSte
return nil
}
if step != nil { // Caller may have known better.
+ if step.why == "" {
+ step.why = why
+ }
+ if step.dst == nil {
+ step.dst = dst
+ }
+ if step.src == nil {
+ step.src = src
+ }
return step
}
return &EscStep{src: src, dst: dst, why: why}
}
+func (e *EscState) stepAssignWhere(dst, src *Node, why string, where *Node) *EscStep {
+ if Debug['m'] == 0 {
+ return nil
+ }
+ return &EscStep{src: src, dst: dst, why: why, where: where}
+}
+
// funcSym returns fn.Func.Nname.Sym if no nils are encountered along the way.
func funcSym(fn *Node) *Sym {
if fn == nil || fn.Func.Nname == nil {
@@ -446,14 +472,7 @@ func (e *EscState) curfnSym(n *Node) *Sym {
}
func escAnalyze(all []*Node, recursive bool) {
- var es EscState
- e := &es
- e.theSink.Op = ONAME
- e.theSink.Orig = &e.theSink
- e.theSink.Class = PEXTERN
- e.theSink.Sym = Lookup(".sink")
- e.nodeEscState(&e.theSink).Escloopdepth = -1
- e.recursive = recursive
+ e := newEscState(recursive)
for _, n := range all {
if n.Op == ODCLFUNC {
@@ -464,11 +483,11 @@ func escAnalyze(all []*Node, recursive bool) {
// flow-analyze functions
for _, n := range all {
if n.Op == ODCLFUNC {
- escfunc(e, n)
+ e.escfunc(n)
}
}
- // print("escapes: %d e->dsts, %d edges\n", e->dstcount, e->edgecount);
+ // print("escapes: %d e.dsts, %d edges\n", e.dstcount, e.edgecount);
// visit the upstream of each dst, mark address nodes with
// addrescapes, mark parameters unsafe
@@ -477,7 +496,7 @@ func escAnalyze(all []*Node, recursive bool) {
escapes[i] = n.Esc
}
for _, n := range e.dsts {
- escflood(e, n)
+ e.escflood(n)
}
for {
done := true
@@ -488,7 +507,7 @@ func escAnalyze(all []*Node, recursive bool) {
Warnl(n.Lineno, "Reflooding %v %S", e.curfnSym(n), n)
}
escapes[i] = n.Esc
- escflood(e, n)
+ e.escflood(n)
}
}
if done {
@@ -499,46 +518,47 @@ func escAnalyze(all []*Node, recursive bool) {
// for all top level functions, tag the typenodes corresponding to the param nodes
for _, n := range all {
if n.Op == ODCLFUNC {
- esctag(e, n)
+ e.esctag(n)
}
}
if Debug['m'] != 0 {
for _, n := range e.noesc {
if n.Esc == EscNone {
- Warnl(n.Lineno, "%v %v does not escape", e.curfnSym(n), Nconv(n, FmtShort))
+ Warnl(n.Lineno, "%v %S does not escape", e.curfnSym(n), n)
}
}
}
+
for _, x := range e.opts {
x.SetOpt(nil)
}
}
-func escfunc(e *EscState, func_ *Node) {
- // print("escfunc %N %s\n", func->nname, e->recursive?"(recursive)":"");
- if func_.Esc != 1 {
- Fatalf("repeat escfunc %v", func_.Func.Nname)
+func (e *EscState) escfunc(fn *Node) {
+ // print("escfunc %N %s\n", fn.Func.Nname, e.recursive?"(recursive)":"");
+ if fn.Esc != EscFuncPlanned {
+ Fatalf("repeat escfunc %v", fn.Func.Nname)
}
- func_.Esc = EscFuncStarted
+ fn.Esc = EscFuncStarted
saveld := e.loopdepth
e.loopdepth = 1
savefn := Curfn
- Curfn = func_
+ Curfn = fn
for _, ln := range Curfn.Func.Dcl {
if ln.Op != ONAME {
continue
}
- llNE := e.nodeEscState(ln)
+ lnE := e.nodeEscState(ln)
switch ln.Class {
// out params are in a loopdepth between the sink and all local variables
case PPARAMOUT:
- llNE.Escloopdepth = 0
+ lnE.Loopdepth = 0
case PPARAM:
- llNE.Escloopdepth = 1
+ lnE.Loopdepth = 1
if ln.Type != nil && !haspointers(ln.Type) {
break
}
@@ -555,52 +575,53 @@ func escfunc(e *EscState, func_ *Node) {
if e.recursive {
for _, ln := range Curfn.Func.Dcl {
if ln.Op == ONAME && ln.Class == PPARAMOUT {
- escflows(e, &e.theSink, ln, e.stepAssign(nil, ln, ln, "returned from recursive function"))
+ e.escflows(&e.theSink, ln, e.stepAssign(nil, ln, ln, "returned from recursive function"))
}
}
}
- escloopdepthlist(e, Curfn.Nbody)
- esclist(e, Curfn.Nbody, Curfn)
+ e.escloopdepthlist(Curfn.Nbody)
+ e.esclist(Curfn.Nbody, Curfn)
Curfn = savefn
e.loopdepth = saveld
}
-// Mark labels that have no backjumps to them as not increasing e->loopdepth.
-// Walk hasn't generated (goto|label)->left->sym->label yet, so we'll cheat
+// Mark labels that have no backjumps to them as not increasing e.loopdepth.
+// Walk hasn't generated (goto|label).Left.Sym.Label yet, so we'll cheat
// and set it to one of the following two. Then in esc we'll clear it again.
-var looping Label
-
-var nonlooping Label
+var (
+ looping Node
+ nonlooping Node
+)
-func escloopdepthlist(e *EscState, l Nodes) {
+func (e *EscState) escloopdepthlist(l Nodes) {
for _, n := range l.Slice() {
- escloopdepth(e, n)
+ e.escloopdepth(n)
}
}
-func escloopdepth(e *EscState, n *Node) {
+func (e *EscState) escloopdepth(n *Node) {
if n == nil {
return
}
- escloopdepthlist(e, n.Ninit)
+ e.escloopdepthlist(n.Ninit)
switch n.Op {
case OLABEL:
if n.Left == nil || n.Left.Sym == nil {
- Fatalf("esc:label without label: %v", Nconv(n, FmtSign))
+ Fatalf("esc:label without label: %+v", n)
}
// Walk will complain about this label being already defined, but that's not until
// after escape analysis. in the future, maybe pull label & goto analysis out of walk and put before esc
- // if(n->left->sym->label != nil)
+ // if(n.Left.Sym.Label != nil)
// fatal("escape analysis messed up analyzing label: %+N", n);
n.Left.Sym.Label = &nonlooping
case OGOTO:
if n.Left == nil || n.Left.Sym == nil {
- Fatalf("esc:goto without label: %v", Nconv(n, FmtSign))
+ Fatalf("esc:goto without label: %+v", n)
}
// If we come past one that's uninitialized, this must be a (harmless) forward jump
@@ -610,34 +631,28 @@ func escloopdepth(e *EscState, n *Node) {
}
}
- escloopdepth(e, n.Left)
- escloopdepth(e, n.Right)
- escloopdepthlist(e, n.List)
- escloopdepthlist(e, n.Nbody)
- escloopdepthlist(e, n.Rlist)
+ e.escloopdepth(n.Left)
+ e.escloopdepth(n.Right)
+ e.escloopdepthlist(n.List)
+ e.escloopdepthlist(n.Nbody)
+ e.escloopdepthlist(n.Rlist)
}
-func esclist(e *EscState, l Nodes, up *Node) {
+func (e *EscState) esclist(l Nodes, parent *Node) {
for _, n := range l.Slice() {
- esc(e, n, up)
+ e.esc(n, parent)
}
}
-func esc(e *EscState, n *Node, up *Node) {
+func (e *EscState) esc(n *Node, parent *Node) {
if n == nil {
return
}
- if n.Type == structkey {
- // This is the left side of x:y in a struct literal.
- // x is syntax, not an expression.
- // See #14405.
- return
- }
lno := setlineno(n)
// ninit logically runs at a different loopdepth than the rest of the for loop.
- esclist(e, n.Ninit, n)
+ e.esclist(n.Ninit, n)
if n.Op == OFOR || n.Op == ORANGE {
e.loopdepth++
@@ -651,7 +666,7 @@ func esc(e *EscState, n *Node, up *Node) {
for _, n1 := range n.List.Slice() { // cases
// it.N().Rlist is the variable per case
if n1.Rlist.Len() != 0 {
- e.nodeEscState(n1.Rlist.First()).Escloopdepth = e.loopdepth
+ e.nodeEscState(n1.Rlist.First()).Loopdepth = e.loopdepth
}
}
}
@@ -667,14 +682,14 @@ func esc(e *EscState, n *Node, up *Node) {
}
n.Esc = EscHeap
addrescapes(n)
- escassignSinkNilWhy(e, n, n, "too large for stack") // TODO category: tooLarge
+ e.escassignSinkWhy(n, n, "too large for stack") // TODO category: tooLarge
}
- esc(e, n.Left, n)
- esc(e, n.Right, n)
- esclist(e, n.Nbody, n)
- esclist(e, n.List, n)
- esclist(e, n.Rlist, n)
+ e.esc(n.Left, n)
+ e.esc(n.Right, n)
+ e.esclist(n.Nbody, n)
+ e.esclist(n.List, n)
+ e.esclist(n.Rlist, n)
if n.Op == OFOR || n.Op == ORANGE {
e.loopdepth--
@@ -688,7 +703,7 @@ func esc(e *EscState, n *Node, up *Node) {
// Record loop depth at declaration.
case ODCL:
if n.Left != nil {
- e.nodeEscState(n.Left).Escloopdepth = e.loopdepth
+ e.nodeEscState(n.Left).Loopdepth = e.loopdepth
}
case OLABEL:
@@ -704,7 +719,7 @@ func esc(e *EscState, n *Node, up *Node) {
}
// See case OLABEL in escloopdepth above
- // else if(n->left->sym->label == nil)
+ // else if(n.Left.Sym.Label == nil)
// fatal("escape analysis missed or messed up a label: %+N", n);
n.Left.Sym.Label = nil
@@ -717,10 +732,10 @@ func esc(e *EscState, n *Node, up *Node) {
// it is also a dereference, because it is implicitly
// dereferenced (see #12588)
if n.Type.IsArray() &&
- !(n.Right.Type.IsPtr() && Eqtype(n.Right.Type.Elem(), n.Type)) {
- escassignNilWhy(e, n.List.Second(), n.Right, "range")
+ !(n.Right.Type.IsPtr() && eqtype(n.Right.Type.Elem(), n.Type)) {
+ e.escassignWhyWhere(n.List.Second(), n.Right, "range", n)
} else {
- escassignDereference(e, n.List.Second(), n.Right, e.stepAssign(nil, n.List.Second(), n.Right, "range-deref"))
+ e.escassignDereference(n.List.Second(), n.Right, e.stepAssignWhere(n.List.Second(), n.Right, "range-deref", n))
}
}
@@ -731,12 +746,12 @@ func esc(e *EscState, n *Node, up *Node) {
// n.Left.Right is the argument of the .(type),
// it.N().Rlist is the variable per case
if n2.Rlist.Len() != 0 {
- escassignNilWhy(e, n2.Rlist.First(), n.Left.Right, "switch case")
+ e.escassignWhyWhere(n2.Rlist.First(), n.Left.Right, "switch case", n)
}
}
}
- // Filter out the following special case.
+ // Filter out the following special case.
//
// func (b *Buffer) Foo() {
// n, m := ...
@@ -763,31 +778,31 @@ func esc(e *EscState, n *Node, up *Node) {
// b escapes as well. If we ignore such OSLICEARR, we will conclude
// that b does not escape when b contents do.
if Debug['m'] != 0 {
- Warnl(n.Lineno, "%v ignoring self-assignment to %v", e.curfnSym(n), Nconv(n.Left, FmtShort))
+ Warnl(n.Lineno, "%v ignoring self-assignment to %S", e.curfnSym(n), n.Left)
}
break
}
- escassign(e, n.Left, n.Right, nil)
+ e.escassign(n.Left, n.Right, e.stepAssignWhere(nil, nil, "", n))
case OAS2: // x,y = a,b
if n.List.Len() == n.Rlist.Len() {
rs := n.Rlist.Slice()
for i, n := range n.List.Slice() {
- escassignNilWhy(e, n, rs[i], "assign-pair")
+ e.escassignWhyWhere(n, rs[i], "assign-pair", n)
}
}
case OAS2RECV: // v, ok = <-ch
- escassignNilWhy(e, n.List.First(), n.Rlist.First(), "assign-pair-receive")
+ e.escassignWhyWhere(n.List.First(), n.Rlist.First(), "assign-pair-receive", n)
case OAS2MAPR: // v, ok = m[k]
- escassignNilWhy(e, n.List.First(), n.Rlist.First(), "assign-pair-mapr")
+ e.escassignWhyWhere(n.List.First(), n.Rlist.First(), "assign-pair-mapr", n)
case OAS2DOTTYPE: // v, ok = x.(type)
- escassignNilWhy(e, n.List.First(), n.Rlist.First(), "assign-pair-dot-type")
+ e.escassignWhyWhere(n.List.First(), n.Rlist.First(), "assign-pair-dot-type", n)
case OSEND: // ch <- x
- escassignSinkNilWhy(e, n, n.Right, "send")
+ e.escassignSinkWhy(n, n.Right, "send")
case ODEFER:
if e.loopdepth == 1 { // top level
@@ -796,128 +811,136 @@ func esc(e *EscState, n *Node, up *Node) {
// arguments leak out of scope
// TODO: leak to a dummy node instead
// defer f(x) - f and x escape
- escassignSinkNilWhy(e, n, n.Left.Left, "defer func")
+ e.escassignSinkWhy(n, n.Left.Left, "defer func")
- escassignSinkNilWhy(e, n, n.Left.Right, "defer func ...") // ODDDARG for call
+ e.escassignSinkWhy(n, n.Left.Right, "defer func ...") // ODDDARG for call
for _, n4 := range n.Left.List.Slice() {
- escassignSinkNilWhy(e, n, n4, "defer func arg")
+ e.escassignSinkWhy(n, n4, "defer func arg")
}
case OPROC:
// go f(x) - f and x escape
- escassignSinkNilWhy(e, n, n.Left.Left, "go func")
+ e.escassignSinkWhy(n, n.Left.Left, "go func")
- escassignSinkNilWhy(e, n, n.Left.Right, "go func ...") // ODDDARG for call
+ e.escassignSinkWhy(n, n.Left.Right, "go func ...") // ODDDARG for call
for _, n4 := range n.Left.List.Slice() {
- escassignSinkNilWhy(e, n, n4, "go func arg")
+ e.escassignSinkWhy(n, n4, "go func arg")
}
case OCALLMETH, OCALLFUNC, OCALLINTER:
- esccall(e, n, up)
+ e.esccall(n, parent)
- // esccall already done on n->rlist->n. tie it's escretval to n->list
+ // esccall already done on n.Rlist.First(). tie it's Retval to n.List
case OAS2FUNC: // x,y = f()
- rs := e.nodeEscState(n.Rlist.First()).Escretval.Slice()
+ rs := e.nodeEscState(n.Rlist.First()).Retval.Slice()
for i, n := range n.List.Slice() {
if i >= len(rs) {
break
}
- escassignNilWhy(e, n, rs[i], "assign-pair-func-call")
+ e.escassignWhyWhere(n, rs[i], "assign-pair-func-call", n)
}
if n.List.Len() != len(rs) {
Fatalf("esc oas2func")
}
case ORETURN:
- ll := n.List
- if n.List.Len() == 1 && Curfn.Type.Results().NumFields() > 1 {
+ retList := n.List
+ if retList.Len() == 1 && Curfn.Type.Results().NumFields() > 1 {
// OAS2FUNC in disguise
- // esccall already done on n->list->n
- // tie n->list->n->escretval to curfn->dcl PPARAMOUT's
- ll = e.nodeEscState(n.List.First()).Escretval
+ // esccall already done on n.List.First()
+ // tie e.nodeEscState(n.List.First()).Retval to Curfn.Func.Dcl PPARAMOUT's
+ retList = e.nodeEscState(n.List.First()).Retval
}
i := 0
for _, lrn := range Curfn.Func.Dcl {
- if i >= ll.Len() {
+ if i >= retList.Len() {
break
}
if lrn.Op != ONAME || lrn.Class != PPARAMOUT {
continue
}
- escassignNilWhy(e, lrn, ll.Index(i), "return")
+ e.escassignWhyWhere(lrn, retList.Index(i), "return", n)
i++
}
- if i < ll.Len() {
+ if i < retList.Len() {
Fatalf("esc return list")
}
// Argument could leak through recover.
case OPANIC:
- escassignSinkNilWhy(e, n, n.Left, "panic")
+ e.escassignSinkWhy(n, n.Left, "panic")
case OAPPEND:
if !n.Isddd {
for _, nn := range n.List.Slice()[1:] {
- escassignSinkNilWhy(e, n, nn, "appended to slice") // lose track of assign to dereference
+ e.escassignSinkWhy(n, nn, "appended to slice") // lose track of assign to dereference
}
} else {
// append(slice1, slice2...) -- slice2 itself does not escape, but contents do.
slice2 := n.List.Second()
- escassignDereference(e, &e.theSink, slice2, e.stepAssign(nil, n, slice2, "appended slice...")) // lose track of assign of dereference
+ 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...) %v", e.curfnSym(n), Nconv(n, FmtShort))
+ Warnl(n.Lineno, "%v special treatment of append(slice1, slice2...) %S", e.curfnSym(n), n)
}
}
- escassignDereference(e, &e.theSink, n.List.First(), e.stepAssign(nil, n, n.List.First(), "appendee slice")) // The original elements are now leaked, too
+ e.escassignDereference(&e.theSink, n.List.First(), e.stepAssignWhere(n, n.List.First(), "appendee slice", n)) // The original elements are now leaked, too
case OCOPY:
- escassignDereference(e, &e.theSink, n.Right, e.stepAssign(nil, n, n.Right, "copied slice")) // lose track of assign of dereference
+ e.escassignDereference(&e.theSink, n.Right, e.stepAssignWhere(n, n.Right, "copied slice", n)) // lose track of assign of dereference
case OCONV, OCONVNOP:
- escassignNilWhy(e, n, n.Left, "converted")
+ e.escassignWhyWhere(n, n.Left, "converted", n)
case OCONVIFACE:
e.track(n)
- escassignNilWhy(e, n, n.Left, "interface-converted")
+ e.escassignWhyWhere(n, n.Left, "interface-converted", n)
case OARRAYLIT:
- why := "array literal element"
- if n.Type.IsSlice() {
- // Slice itself is not leaked until proven otherwise
- e.track(n)
- why = "slice literal element"
+ // Link values to array
+ for _, n2 := range n.List.Slice() {
+ if n2.Op == OKEY {
+ n2 = n2.Right
+ }
+ e.escassign(n, n2, e.stepAssignWhere(n, n2, "array literal element", n))
}
- // Link values to array/slice
- for _, n5 := range n.List.Slice() {
- escassign(e, n, n5.Right, e.stepAssign(nil, n, n5.Right, why))
+
+ 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
+ }
+ e.escassign(n, n2, e.stepAssignWhere(n, n2, "slice literal element", n))
}
// Link values to struct.
case OSTRUCTLIT:
for _, n6 := range n.List.Slice() {
- escassignNilWhy(e, n, n6.Right, "struct literal element")
+ e.escassignWhyWhere(n, n6.Left, "struct literal element", n)
}
case OPTRLIT:
e.track(n)
// Link OSTRUCTLIT to OPTRLIT; if OPTRLIT escapes, OSTRUCTLIT elements do too.
- escassignNilWhy(e, n, n.Left, "pointer literal [assign]")
+ e.escassignWhyWhere(n, n.Left, "pointer literal [assign]", n)
case OCALLPART:
e.track(n)
// Contents make it to memory, lose track.
- escassignSinkNilWhy(e, n, n.Left, "call part")
+ e.escassignSinkWhy(n, n.Left, "call part")
case OMAPLIT:
e.track(n)
// Keys and values make it to memory, lose track.
for _, n7 := range n.List.Slice() {
- escassignSinkNilWhy(e, n, n7.Left, "map literal key")
- escassignSinkNilWhy(e, n, n7.Right, "map literal value")
+ e.escassignSinkWhy(n, n7.Left, "map literal key")
+ e.escassignSinkWhy(n, n7.Right, "map literal value")
}
case OCLOSURE:
@@ -928,13 +951,13 @@ func esc(e *EscState, n *Node, up *Node) {
}
a := v.Name.Defn
if !v.Name.Byval {
- a = Nod(OADDR, a, nil)
+ a = nod(OADDR, a, nil)
a.Lineno = v.Lineno
- e.nodeEscState(a).Escloopdepth = e.loopdepth
+ e.nodeEscState(a).Loopdepth = e.loopdepth
a = typecheck(a, Erv)
}
- escassignNilWhy(e, n, a, "captured by a closure")
+ e.escassignWhyWhere(n, a, "captured by a closure", n)
}
fallthrough
@@ -966,11 +989,11 @@ func esc(e *EscState, n *Node, up *Node) {
case PAUTO:
nE := e.nodeEscState(n)
leftE := e.nodeEscState(n.Left)
- if leftE.Escloopdepth != 0 {
- nE.Escloopdepth = leftE.Escloopdepth
+ if leftE.Loopdepth != 0 {
+ nE.Loopdepth = leftE.Loopdepth
}
- // PPARAM is loop depth 1 always.
+ // PPARAM is loop depth 1 always.
// PPARAMOUT is loop depth 0 for writes
// but considered loop depth 1 for address-of,
// so that writing the address of one result
@@ -978,7 +1001,7 @@ func esc(e *EscState, n *Node, up *Node) {
// first result move to the heap.
case PPARAM, PPARAMOUT:
nE := e.nodeEscState(n)
- nE.Escloopdepth = 1
+ nE.Loopdepth = 1
}
}
}
@@ -986,40 +1009,50 @@ func esc(e *EscState, n *Node, up *Node) {
lineno = lno
}
-// escassignNilWhy bundles a common case of
-// escassign(e, dst, src, e.stepAssign(nil, dst, src, reason))
-func escassignNilWhy(e *EscState, dst, src *Node, reason string) {
+// escassignWhyWhere bundles a common case of
+// escassign(e, dst, src, e.stepAssignWhere(dst, src, reason, where))
+func (e *EscState) escassignWhyWhere(dst, src *Node, reason string, where *Node) {
var step *EscStep
if Debug['m'] != 0 {
- step = e.stepAssign(nil, dst, src, reason)
+ step = e.stepAssignWhere(dst, src, reason, where)
}
- escassign(e, dst, src, step)
+ e.escassign(dst, src, step)
}
-// escassignSinkNilWhy bundles a common case of
+// escassignSinkWhy bundles a common case of
// escassign(e, &e.theSink, src, e.stepAssign(nil, dst, src, reason))
-func escassignSinkNilWhy(e *EscState, dst, src *Node, reason string) {
+func (e *EscState) escassignSinkWhy(dst, src *Node, reason string) {
var step *EscStep
if Debug['m'] != 0 {
step = e.stepAssign(nil, dst, src, reason)
}
- escassign(e, &e.theSink, src, step)
+ e.escassign(&e.theSink, src, step)
+}
+
+// escassignSinkWhyWhere is escassignSinkWhy but includes a call site
+// for accurate location reporting.
+func (e *EscState) escassignSinkWhyWhere(dst, src *Node, reason string, call *Node) {
+ var step *EscStep
+ if Debug['m'] != 0 {
+ step = e.stepAssignWhere(dst, src, reason, call)
+ }
+ e.escassign(&e.theSink, src, step)
}
// Assert that expr somehow gets assigned to dst, if non nil. for
// dst==nil, any name node expr still must be marked as being
// evaluated in curfn. For expr==nil, dst must still be examined for
// evaluations inside it (e.g *f(x) = y)
-func escassign(e *EscState, dst, src *Node, step *EscStep) {
+func (e *EscState) escassign(dst, src *Node, step *EscStep) {
if isblank(dst) || dst == nil || src == nil || src.Op == ONONAME || src.Op == OXXX {
return
}
if Debug['m'] > 2 {
- fmt.Printf("%v:[%d] %v escassign: %v(%v)[%v] = %v(%v)[%v]\n",
+ fmt.Printf("%v:[%d] %v escassign: %S(%0j)[%v] = %S(%0j)[%v]\n",
linestr(lineno), e.loopdepth, funcSym(Curfn),
- Nconv(dst, FmtShort), jconv(dst, FmtShort), dst.Op,
- Nconv(src, FmtShort), jconv(src, FmtShort), src.Op)
+ dst, dst, dst.Op,
+ src, src, src.Op)
}
setlineno(dst)
@@ -1028,13 +1061,14 @@ func escassign(e *EscState, dst, src *Node, step *EscStep) {
dstwhy := "assigned"
// Analyze lhs of assignment.
- // Replace dst with e->theSink if we can't track it.
+ // Replace dst with &e.theSink if we can't track it.
switch dst.Op {
default:
Dump("dst", dst)
Fatalf("escassign: unexpected dst")
case OARRAYLIT,
+ OSLICELIT,
OCLOSURE,
OCONV,
OCONVIFACE,
@@ -1044,7 +1078,6 @@ func escassign(e *EscState, dst, src *Node, step *EscStep) {
OPTRLIT,
ODDDARG,
OCALLPART:
- break
case ONAME:
if dst.Class == PEXTERN {
@@ -1053,12 +1086,12 @@ func escassign(e *EscState, dst, src *Node, step *EscStep) {
}
case ODOT: // treat "dst.x = src" as "dst = src"
- escassign(e, dst.Left, src, e.stepAssign(step, originalDst, src, "dot-equals"))
+ e.escassign(dst.Left, src, e.stepAssign(step, originalDst, src, "dot-equals"))
return
case OINDEX:
if dst.Left.Type.IsArray() {
- escassign(e, dst.Left, src, e.stepAssign(step, originalDst, src, "array-element-equals"))
+ e.escassign(dst.Left, src, e.stepAssign(step, originalDst, src, "array-element-equals"))
return
}
@@ -1075,7 +1108,7 @@ func escassign(e *EscState, dst, src *Node, step *EscStep) {
// lose track of key and value
case OINDEXMAP:
- escassign(e, &e.theSink, dst.Right, e.stepAssign(nil, originalDst, src, "key of map put"))
+ e.escassign(&e.theSink, dst.Right, e.stepAssign(nil, originalDst, src, "key of map put"))
dstwhy = "value of map put"
dst = &e.theSink
}
@@ -1091,6 +1124,7 @@ func escassign(e *EscState, dst, src *Node, step *EscStep) {
ODDDARG,
OPTRLIT,
OARRAYLIT,
+ OSLICELIT,
OMAPLIT,
OSTRUCTLIT,
OMAKECHAN,
@@ -1105,22 +1139,22 @@ func escassign(e *EscState, dst, src *Node, step *EscStep) {
OCALLPART,
ORUNESTR,
OCONVIFACE:
- escflows(e, dst, src, e.stepAssign(step, originalDst, src, dstwhy))
+ e.escflows(dst, src, e.stepAssign(step, originalDst, src, dstwhy))
case OCLOSURE:
// OCLOSURE is lowered to OPTRLIT,
// insert OADDR to account for the additional indirection.
- a := Nod(OADDR, src, nil)
+ a := nod(OADDR, src, nil)
a.Lineno = src.Lineno
- e.nodeEscState(a).Escloopdepth = e.nodeEscState(src).Escloopdepth
- a.Type = Ptrto(src.Type)
- escflows(e, dst, a, e.stepAssign(nil, originalDst, src, dstwhy))
+ e.nodeEscState(a).Loopdepth = e.nodeEscState(src).Loopdepth
+ a.Type = ptrto(src.Type)
+ e.escflows(dst, a, e.stepAssign(nil, originalDst, src, dstwhy))
// Flowing multiple returns to a single dst happens when
// analyzing "go f(g())": here g() flows to sink (issue 4529).
case OCALLMETH, OCALLFUNC, OCALLINTER:
- for _, n := range e.nodeEscState(src).Escretval.Slice() {
- escflows(e, dst, n, e.stepAssign(nil, originalDst, n, dstwhy))
+ for _, n := range e.nodeEscState(src).Retval.Slice() {
+ e.escflows(dst, n, e.stepAssign(nil, originalDst, n, dstwhy))
}
// A non-pointer escaping from a struct does not concern us.
@@ -1136,35 +1170,35 @@ func escassign(e *EscState, dst, src *Node, step *EscStep) {
ODOTMETH,
// treat recv.meth as a value with recv in it, only happens in ODEFER and OPROC
// iface.method already leaks iface in esccall, no need to put in extra ODOTINTER edge here
- ODOTTYPE2,
OSLICE,
OSLICE3,
OSLICEARR,
OSLICE3ARR,
OSLICESTR:
// Conversions, field access, slice all preserve the input value.
- escassign(e, dst, src.Left, e.stepAssign(step, originalDst, src, dstwhy))
+ e.escassign(dst, src.Left, e.stepAssign(step, originalDst, src, dstwhy))
- case ODOTTYPE:
+ case ODOTTYPE,
+ ODOTTYPE2:
if src.Type != nil && !haspointers(src.Type) {
break
}
- escassign(e, dst, src.Left, e.stepAssign(step, originalDst, src, dstwhy))
+ e.escassign(dst, src.Left, e.stepAssign(step, originalDst, src, dstwhy))
case OAPPEND:
// Append returns first argument.
// Subsequent arguments are already leaked because they are operands to append.
- escassign(e, dst, src.List.First(), e.stepAssign(step, dst, src.List.First(), dstwhy))
+ e.escassign(dst, src.List.First(), e.stepAssign(step, dst, src.List.First(), dstwhy))
case OINDEX:
// Index of array preserves input value.
if src.Left.Type.IsArray() {
- escassign(e, dst, src.Left, e.stepAssign(step, originalDst, src, dstwhy))
+ e.escassign(dst, src.Left, e.stepAssign(step, originalDst, src, dstwhy))
} else {
- escflows(e, dst, src, e.stepAssign(step, originalDst, src, dstwhy))
+ e.escflows(dst, src, e.stepAssign(step, originalDst, src, dstwhy))
}
- // Might be pointer arithmetic, in which case
+ // Might be pointer arithmetic, in which case
// the operands flow into the result.
// TODO(rsc): Decide what the story is here. This is unsettling.
case OADD,
@@ -1181,9 +1215,9 @@ func escassign(e *EscState, dst, src *Node, step *EscStep) {
OPLUS,
OMINUS,
OCOM:
- escassign(e, dst, src.Left, e.stepAssign(step, originalDst, src, dstwhy))
+ e.escassign(dst, src.Left, e.stepAssign(step, originalDst, src, dstwhy))
- escassign(e, dst, src.Right, e.stepAssign(step, originalDst, src, dstwhy))
+ e.escassign(dst, src.Right, e.stepAssign(step, originalDst, src, dstwhy))
}
e.pdepth--
@@ -1203,8 +1237,6 @@ var tags [1 << (bitsPerOutputInTag + EscReturnBits)]string
func mktag(mask int) string {
switch mask & EscMask {
case EscNone, EscReturn:
- break
-
default:
Fatalf("escape mktag")
}
@@ -1256,9 +1288,6 @@ func describeEscape(em uint16) string {
if em&EscMask == EscReturn {
s = "EscReturn"
}
- if em&EscMask == EscScope {
- s = "EscScope"
- }
if em&EscContentEscapes != 0 {
if s != "" {
s += " "
@@ -1287,19 +1316,19 @@ func describeEscape(em uint16) string {
// escassignfromtag models the input-to-output assignment flow of one of a function
// calls arguments, where the flow is encoded in "note".
-func escassignfromtag(e *EscState, note string, dsts Nodes, src *Node) uint16 {
+func (e *EscState) escassignfromtag(note string, dsts Nodes, src, call *Node) uint16 {
em := parsetag(note)
if src.Op == OLITERAL {
return em
}
if Debug['m'] > 3 {
- fmt.Printf("%v::assignfromtag:: src=%v, em=%s\n",
- linestr(lineno), Nconv(src, FmtShort), describeEscape(em))
+ fmt.Printf("%v::assignfromtag:: src=%S, em=%s\n",
+ linestr(lineno), src, describeEscape(em))
}
if em == EscUnknown {
- escassignSinkNilWhy(e, src, src, "passed to function[unknown]")
+ e.escassignSinkWhyWhere(src, src, "passed to call[argument escapes]", call)
return em
}
@@ -1310,7 +1339,7 @@ func escassignfromtag(e *EscState, note string, dsts Nodes, src *Node) uint16 {
// If content inside parameter (reached via indirection)
// escapes to heap, mark as such.
if em&EscContentEscapes != 0 {
- escassign(e, &e.theSink, e.addDereference(src), e.stepAssign(nil, src, src, "passed to function[content escapes]"))
+ e.escassign(&e.theSink, e.addDereference(src), e.stepAssignWhere(src, src, "passed to call[argument content escapes]", call))
}
em0 := em
@@ -1327,7 +1356,7 @@ func escassignfromtag(e *EscState, note string, dsts Nodes, src *Node) uint16 {
for i := uint16(0); i < embits-1; i++ {
n = e.addDereference(n) // encode level>0 as indirections
}
- escassign(e, dsts.Index(dstsi), n, e.stepAssign(nil, dsts.Index(dstsi), src, "passed-to-and-returned-from-function"))
+ e.escassign(dsts.Index(dstsi), n, e.stepAssignWhere(dsts.Index(dstsi), src, "passed-to-and-returned-from-call", call))
}
dstsi++
}
@@ -1341,19 +1370,19 @@ func escassignfromtag(e *EscState, note string, dsts Nodes, src *Node) uint16 {
return em0
}
-func escassignDereference(e *EscState, dst *Node, src *Node, step *EscStep) {
+func (e *EscState) escassignDereference(dst *Node, src *Node, step *EscStep) {
if src.Op == OLITERAL {
return
}
- escassign(e, dst, e.addDereference(src), step)
+ e.escassign(dst, e.addDereference(src), step)
}
// addDereference constructs a suitable OIND note applied to src.
// Because this is for purposes of escape accounting, not execution,
// some semantically dubious node combinations are (currently) possible.
func (e *EscState) addDereference(n *Node) *Node {
- ind := Nod(OIND, n, nil)
- e.nodeEscState(ind).Escloopdepth = e.nodeEscState(n).Escloopdepth
+ ind := nod(OIND, n, nil)
+ e.nodeEscState(ind).Loopdepth = e.nodeEscState(n).Loopdepth
ind.Lineno = n.Lineno
t := n.Type
if t.IsKind(Tptr) {
@@ -1400,147 +1429,145 @@ func escNoteOutputParamFlow(e uint16, vargen int32, level Level) uint16 {
return (e &^ (bitsMaskForTag << shift)) | encodedFlow
}
-func initEscretval(e *EscState, n *Node, fntype *Type) {
- i := 0
- nE := e.nodeEscState(n)
- nE.Escretval.Set(nil) // Suspect this is not nil for indirect calls.
- for _, t := range fntype.Results().Fields().Slice() {
- src := Nod(ONAME, nil, nil)
+func (e *EscState) initEscRetval(call *Node, fntype *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)
- i++
- src.Sym = Lookup(buf)
- src.Type = t.Type
- src.Class = PAUTO
- src.Name.Curfn = Curfn
- e.nodeEscState(src).Escloopdepth = e.loopdepth
- src.Used = true
- src.Lineno = n.Lineno
- nE.Escretval.Append(src)
+ ret.Sym = lookup(buf)
+ ret.Type = f.Type
+ ret.Class = PAUTO
+ ret.Name.Curfn = Curfn
+ e.nodeEscState(ret).Loopdepth = e.loopdepth
+ ret.Used = true
+ ret.Lineno = call.Lineno
+ cE.Retval.Append(ret)
}
}
// This is a bit messier than fortunate, pulled out of esc's big
-// switch for clarity. We either have the paramnodes, which may be
+// switch for clarity. We either have the paramnodes, which may be
// connected to other things through flows or we have the parameter type
// nodes, which may be marked "noescape". Navigating the ast is slightly
// different for methods vs plain functions and for imported vs
// this-package
-func esccall(e *EscState, n *Node, up *Node) {
+func (e *EscState) esccall(call *Node, parent *Node) {
var fntype *Type
var indirect bool
var fn *Node
- switch n.Op {
+ switch call.Op {
default:
Fatalf("esccall")
case OCALLFUNC:
- fn = n.Left
+ fn = call.Left
fntype = fn.Type
indirect = fn.Op != ONAME || fn.Class != PFUNC
case OCALLMETH:
- fn = n.Left.Sym.Def
+ fn = call.Left.Sym.Def
if fn != nil {
fntype = fn.Type
} else {
- fntype = n.Left.Type
+ fntype = call.Left.Type
}
case OCALLINTER:
- fntype = n.Left.Type
+ fntype = call.Left.Type
indirect = true
}
- ll := n.List
- if n.List.Len() == 1 {
- a := n.List.First()
- if a.Type.IsFuncArgStruct() { // f(g())
- ll = e.nodeEscState(a).Escretval
+ argList := call.List
+ if argList.Len() == 1 {
+ arg := argList.First()
+ if arg.Type.IsFuncArgStruct() { // f(g())
+ argList = e.nodeEscState(arg).Retval
}
}
+ args := argList.Slice()
+
if indirect {
// We know nothing!
// Leak all the parameters
- for _, n1 := range ll.Slice() {
- escassignSinkNilWhy(e, n, n1, "parameter to indirect call")
+ for _, arg := range args {
+ e.escassignSinkWhy(call, arg, "parameter to indirect call")
if Debug['m'] > 3 {
- fmt.Printf("%v::esccall:: indirect call <- %v, untracked\n", linestr(lineno), Nconv(n1, FmtShort))
+ fmt.Printf("%v::esccall:: indirect call <- %S, untracked\n", linestr(lineno), arg)
}
}
// Set up bogus outputs
- initEscretval(e, n, fntype)
+ e.initEscRetval(call, fntype)
// If there is a receiver, it also leaks to heap.
- if n.Op != OCALLFUNC {
- t := fntype.Recv()
- src := n.Left.Left
- if haspointers(t.Type) {
- escassignSinkNilWhy(e, n, src, "receiver in indirect call")
+ if call.Op != OCALLFUNC {
+ rf := fntype.Recv()
+ r := call.Left.Left
+ if haspointers(rf.Type) {
+ e.escassignSinkWhy(call, r, "receiver in indirect call")
}
} else { // indirect and OCALLFUNC = could be captured variables, too. (#14409)
- ll := e.nodeEscState(n).Escretval.Slice()
- for _, llN := range ll {
- escassignDereference(e, llN, fn, e.stepAssign(nil, llN, fn, "captured by called closure"))
+ rets := e.nodeEscState(call).Retval.Slice()
+ for _, ret := range rets {
+ e.escassignDereference(ret, fn, e.stepAssignWhere(ret, fn, "captured by called closure", call))
}
}
return
}
- nE := e.nodeEscState(n)
+ cE := e.nodeEscState(call)
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:: %v in recursive group\n", linestr(lineno), Nconv(n, FmtShort))
+ fmt.Printf("%v::esccall:: %S in recursive group\n", linestr(lineno), call)
}
// function in same mutually recursive group. Incorporate into flow graph.
- // print("esc local fn: %N\n", fn->ntype);
- if fn.Name.Defn.Esc == EscFuncUnknown || nE.Escretval.Len() != 0 {
+ // print("esc local fn: %N\n", fn.Func.Ntype);
+ if fn.Name.Defn.Esc == EscFuncUnknown || cE.Retval.Len() != 0 {
Fatalf("graph inconsistency")
}
- lls := ll.Slice()
sawRcvr := false
- var src *Node
- for _, n2 := range fn.Name.Defn.Func.Dcl {
- switch n2.Class {
+ for _, n := range fn.Name.Defn.Func.Dcl {
+ switch n.Class {
case PPARAM:
- if n.Op != OCALLFUNC && !sawRcvr {
- escassignNilWhy(e, n2, n.Left.Left, "call receiver")
+ if call.Op != OCALLFUNC && !sawRcvr {
+ e.escassignWhyWhere(n, call.Left.Left, "call receiver", call)
sawRcvr = true
continue
}
- if len(lls) == 0 {
+ if len(args) == 0 {
continue
}
- src = lls[0]
- if n2.Isddd && !n.Isddd {
+ arg := args[0]
+ if n.Isddd && !call.Isddd {
// Introduce ODDDARG node to represent ... allocation.
- src = Nod(ODDDARG, nil, nil)
- arr := typArray(n2.Type.Elem(), int64(len(lls)))
- src.Type = Ptrto(arr) // make pointer so it will be tracked
- src.Lineno = n.Lineno
- e.track(src)
- n.Right = src
+ 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
+ e.track(arg)
+ call.Right = arg
}
- escassignNilWhy(e, n2, src, "arg to recursive call")
- if src != lls[0] {
+ e.escassignWhyWhere(n, arg, "arg to recursive call", call) // TODO this message needs help.
+ if arg != args[0] {
// "..." arguments are untracked
- for _, n2 := range lls {
+ for _, a := range args {
if Debug['m'] > 3 {
- fmt.Printf("%v::esccall:: ... <- %v, untracked\n", linestr(lineno), Nconv(n2, FmtShort))
+ fmt.Printf("%v::esccall:: ... <- %S, untracked\n", linestr(lineno), a)
}
- escassignSinkNilWhy(e, src, n2, "... arg to recursive call")
+ e.escassignSinkWhyWhere(arg, a, "... arg to recursive call", call)
}
// No more PPARAM processing, but keep
// going for PPARAMOUT.
- lls = nil
+ args = nil
continue
}
- lls = lls[1:]
+ args = args[1:]
case PPARAMOUT:
- nE.Escretval.Append(n2)
+ cE.Retval.Append(n)
}
}
@@ -1548,48 +1575,48 @@ func esccall(e *EscState, n *Node, up *Node) {
}
// Imported or completely analyzed function. Use the escape tags.
- if nE.Escretval.Len() != 0 {
- Fatalf("esc already decorated call %v\n", Nconv(n, FmtSign))
+ if cE.Retval.Len() != 0 {
+ Fatalf("esc already decorated call %+v\n", call)
}
if Debug['m'] > 3 {
- fmt.Printf("%v::esccall:: %v not recursive\n", linestr(lineno), Nconv(n, FmtShort))
+ fmt.Printf("%v::esccall:: %S not recursive\n", linestr(lineno), call)
}
// set up out list on this call node with dummy auto ONAMES in the current (calling) function.
- initEscretval(e, n, fntype)
+ e.initEscRetval(call, fntype)
- // print("esc analyzed fn: %#N (%+T) returning (%+H)\n", fn, fntype, n->escretval);
+ // print("esc analyzed fn: %#N (%+T) returning (%+H)\n", fn, fntype, e.nodeEscState(call).Retval);
// Receiver.
- if n.Op != OCALLFUNC {
- t := fntype.Recv()
- src := n.Left.Left
- if haspointers(t.Type) {
- escassignfromtag(e, t.Note, nE.Escretval, src)
+ if call.Op != OCALLFUNC {
+ rf := fntype.Recv()
+ r := call.Left.Left
+ if haspointers(rf.Type) {
+ e.escassignfromtag(rf.Note, cE.Retval, r, call)
}
}
- var src *Node
- note := ""
+ var arg *Node
+ var note string
+ param, it := iterFields(fntype.Params())
i := 0
- lls := ll.Slice()
- for t, it := IterFields(fntype.Params()); i < len(lls); i++ {
- src = lls[i]
- note = t.Note
- if t.Isddd && !n.Isddd {
+ for ; i < len(args); i++ {
+ arg = args[i]
+ note = param.Note
+ if param.Isddd && !call.Isddd {
// Introduce ODDDARG node to represent ... allocation.
- src = Nod(ODDDARG, nil, nil)
- src.Lineno = n.Lineno
- arr := typArray(t.Type.Elem(), int64(len(lls)-i))
- src.Type = Ptrto(arr) // make pointer so it will be tracked
- e.track(src)
- n.Right = src
+ 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
+ e.track(arg)
+ call.Right = arg
}
- if haspointers(t.Type) {
- if escassignfromtag(e, note, nE.Escretval, src) == EscNone && up.Op != ODEFER && up.Op != OPROC {
- a := src
+ 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
}
@@ -1600,13 +1627,14 @@ func esccall(e *EscState, n *Node, up *Node) {
// synthesizing this expression can be reclaimed when
// the function returns.
// This 'noescape' is even stronger than the usual esc == EscNone.
- // src->esc == EscNone means that src does not escape the current function.
- // src->noescape = 1 here means that src does not escape this statement
+ // 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
@@ -1614,34 +1642,34 @@ func esccall(e *EscState, n *Node, up *Node) {
}
}
- if src != lls[i] {
- // This occurs when function parameter type Isddd and n not Isddd
+ if arg != args[i] {
+ // This occurs when function parameter field Isddd and call not Isddd
break
}
if note == uintptrEscapesTag {
- escassignSinkNilWhy(e, src, src, "escaping uintptr")
+ e.escassignSinkWhy(arg, arg, "escaping uintptr")
}
- t = it.Next()
+ param = it.Next()
}
// Store arguments into slice for ... arg.
- for ; i < len(lls); i++ {
+ for ; i < len(args); i++ {
if Debug['m'] > 3 {
- fmt.Printf("%v::esccall:: ... <- %v\n", linestr(lineno), Nconv(lls[i], FmtShort))
+ fmt.Printf("%v::esccall:: ... <- %S\n", linestr(lineno), args[i])
}
if note == uintptrEscapesTag {
- escassignSinkNilWhy(e, src, lls[i], "arg to uintptrescapes ...")
+ e.escassignSinkWhyWhere(arg, args[i], "arg to uintptrescapes ...", call)
} else {
- escassignNilWhy(e, src, lls[i], "arg to ...")
+ e.escassignWhyWhere(arg, args[i], "arg to ...", call)
}
}
}
// escflows records the link src->dst in dst, throwing out some quick wins,
// and also ensuring that dst is noted as a flow destination.
-func escflows(e *EscState, dst, src *Node, why *EscStep) {
+func (e *EscState) escflows(dst, src *Node, why *EscStep) {
if dst == nil || src == nil || dst == src {
return
}
@@ -1652,11 +1680,11 @@ func escflows(e *EscState, dst, src *Node, why *EscStep) {
}
if Debug['m'] > 3 {
- fmt.Printf("%v::flows:: %v <- %v\n", linestr(lineno), Nconv(dst, FmtShort), Nconv(src, FmtShort))
+ fmt.Printf("%v::flows:: %S <- %S\n", linestr(lineno), dst, src)
}
dstE := e.nodeEscState(dst)
- if len(dstE.Escflowsrc) == 0 {
+ if len(dstE.Flowsrc) == 0 {
e.dsts = append(e.dsts, dst)
e.dstcount++
}
@@ -1664,11 +1692,11 @@ func escflows(e *EscState, dst, src *Node, why *EscStep) {
e.edgecount++
if why == nil {
- dstE.Escflowsrc = append(dstE.Escflowsrc, EscStep{src: src})
+ dstE.Flowsrc = append(dstE.Flowsrc, EscStep{src: src})
} else {
starwhy := *why
starwhy.src = src // TODO: need to reconcile this w/ needs of explanations.
- dstE.Escflowsrc = append(dstE.Escflowsrc, starwhy)
+ dstE.Flowsrc = append(dstE.Flowsrc, starwhy)
}
}
@@ -1678,27 +1706,26 @@ func escflows(e *EscState, dst, src *Node, why *EscStep) {
// so this address doesn't leak (yet).
// If level == 0, it means the /value/ of this node can reach the root of this flood.
// so if this node is an OADDR, its argument should be marked as escaping iff
-// its currfn/e->loopdepth are different from the flood's root.
+// its currfn/e.loopdepth are different from the flood's root.
// Once an object has been moved to the heap, all of its upstream should be considered
// escaping to the global scope.
-func escflood(e *EscState, dst *Node) {
+func (e *EscState) escflood(dst *Node) {
switch dst.Op {
case ONAME, OCLOSURE:
- break
-
default:
return
}
dstE := e.nodeEscState(dst)
if Debug['m'] > 2 {
- fmt.Printf("\nescflood:%d: dst %v scope:%v[%d]\n", e.walkgen, Nconv(dst, FmtShort), e.curfnSym(dst), dstE.Escloopdepth)
+ fmt.Printf("\nescflood:%d: dst %S scope:%v[%d]\n", e.walkgen, dst, e.curfnSym(dst), dstE.Loopdepth)
}
- for i, l := range dstE.Escflowsrc {
+ for i := range dstE.Flowsrc {
e.walkgen++
- dstE.Escflowsrc[i].parent = nil
- escwalk(e, levelFrom(0), dst, l.src, &dstE.Escflowsrc[i])
+ s := &dstE.Flowsrc[i]
+ s.parent = nil
+ e.escwalk(levelFrom(0), dst, s.src, s)
}
}
@@ -1723,10 +1750,14 @@ func (es *EscStep) describe(src *Node) {
// case it is step.dst.
nextDest := step.parent
dst := step.dst
+ where := step.where
if nextDest != nil {
dst = nextDest.src
}
- Warnl(src.Lineno, "\tfrom %s (%s) at %s", dst, step.why, dst.Line())
+ if where == nil {
+ where = dst
+ }
+ Warnl(src.Lineno, "\tfrom %v (%s) at %s", dst, step.why, where.Line())
}
for step := step0; step != nil && step.busy; step = step.parent {
step.busy = false
@@ -1735,11 +1766,11 @@ func (es *EscStep) describe(src *Node) {
const NOTALOOPDEPTH = -1
-func escwalk(e *EscState, level Level, dst *Node, src *Node, step *EscStep) {
- escwalkBody(e, level, dst, src, step, NOTALOOPDEPTH)
+func (e *EscState) escwalk(level Level, dst *Node, src *Node, step *EscStep) {
+ e.escwalkBody(level, dst, src, step, NOTALOOPDEPTH)
}
-func escwalkBody(e *EscState, level Level, dst *Node, src *Node, step *EscStep, extraloopdepth int32) {
+func (e *EscState) escwalkBody(level Level, dst *Node, src *Node, step *EscStep, extraloopdepth int32) {
if src.Op == OLITERAL {
return
}
@@ -1748,12 +1779,12 @@ func escwalkBody(e *EscState, level Level, dst *Node, src *Node, step *EscStep,
// Esclevels are vectors, do not compare as integers,
// and must use "min" of old and new to guarantee
// convergence.
- level = level.min(srcE.Esclevel)
- if level == srcE.Esclevel {
+ level = level.min(srcE.Level)
+ if level == srcE.Level {
// Have we been here already with an extraloopdepth,
// or is the extraloopdepth provided no improvement on
// what's already been seen?
- if srcE.Maxextraloopdepth >= extraloopdepth || srcE.Escloopdepth >= extraloopdepth {
+ if srcE.Maxextraloopdepth >= extraloopdepth || srcE.Loopdepth >= extraloopdepth {
return
}
srcE.Maxextraloopdepth = extraloopdepth
@@ -1763,16 +1794,16 @@ func escwalkBody(e *EscState, level Level, dst *Node, src *Node, step *EscStep,
}
srcE.Walkgen = e.walkgen
- srcE.Esclevel = level
- modSrcLoopdepth := srcE.Escloopdepth
+ srcE.Level = level
+ modSrcLoopdepth := srcE.Loopdepth
if extraloopdepth > modSrcLoopdepth {
modSrcLoopdepth = extraloopdepth
}
if Debug['m'] > 2 {
- fmt.Printf("escwalk: level:%d depth:%d %.*s op=%v %v(%v) scope:%v[%d] extraloopdepth=%v\n",
- level, e.pdepth, e.pdepth, "\t\t\t\t\t\t\t\t\t\t", src.Op, Nconv(src, FmtShort), jconv(src, FmtShort), e.curfnSym(src), srcE.Escloopdepth, extraloopdepth)
+ fmt.Printf("escwalk: level:%d depth:%d %.*s op=%v %S(%0j) scope:%v[%d] extraloopdepth=%v\n",
+ level, e.pdepth, e.pdepth, "\t\t\t\t\t\t\t\t\t\t", src.Op, src, src, e.curfnSym(src), srcE.Loopdepth, extraloopdepth)
}
e.pdepth++
@@ -1782,7 +1813,7 @@ func escwalkBody(e *EscState, level Level, dst *Node, src *Node, step *EscStep,
var osrcesc uint16 // used to prevent duplicate error messages
dstE := e.nodeEscState(dst)
- if funcOutputAndInput(dst, src) && src.Esc&EscMask < EscScope && dst.Esc != EscHeap {
+ if funcOutputAndInput(dst, src) && src.Esc&EscMask < EscHeap && dst.Esc != EscHeap {
// This case handles:
// 1. return in
// 2. return &in
@@ -1790,10 +1821,10 @@ func escwalkBody(e *EscState, level Level, dst *Node, src *Node, step *EscStep,
// 4. return *in
if Debug['m'] != 0 {
if Debug['m'] <= 2 {
- Warnl(src.Lineno, "leaking param: %v to result %v level=%v", Nconv(src, FmtShort), dst.Sym, level.int())
+ Warnl(src.Lineno, "leaking param: %S to result %v level=%v", src, dst.Sym, level.int())
step.describe(src)
} else {
- Warnl(src.Lineno, "leaking param: %v to result %v level=%v", Nconv(src, FmtShort), dst.Sym, level)
+ Warnl(src.Lineno, "leaking param: %S to result %v level=%v", src, dst.Sym, level)
}
}
if src.Esc&EscMask != EscReturn {
@@ -1806,45 +1837,44 @@ func escwalkBody(e *EscState, 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 < EscScope &&
+ 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: %v", Nconv(src, FmtShort))
+ Warnl(src.Lineno, "mark escaped content: %S", src)
step.describe(src)
}
}
- leaks = level.int() <= 0 && level.guaranteedDereference() <= 0 && dstE.Escloopdepth < modSrcLoopdepth
+ leaks = level.int() <= 0 && level.guaranteedDereference() <= 0 && dstE.Loopdepth < modSrcLoopdepth
leaks = leaks || level.int() <= 0 && dst.Esc&EscMask == EscHeap
osrcesc = src.Esc
switch src.Op {
case ONAME:
- if src.Class == PPARAM && (leaks || dstE.Escloopdepth < 0) && src.Esc&EscMask < EscScope {
+ 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: %v", Nconv(src, FmtShort))
+ Warnl(src.Lineno, "leaking param content: %S", src)
step.describe(src)
}
} else {
- Warnl(src.Lineno, "leaking param content: %v level=%v dst.eld=%v src.eld=%v dst=%v",
- Nconv(src, FmtShort), level, dstE.Escloopdepth, modSrcLoopdepth, Nconv(dst, FmtShort))
+ Warnl(src.Lineno, "leaking param content: %S level=%v dst.eld=%v src.eld=%v dst=%S",
+ src, level, dstE.Loopdepth, modSrcLoopdepth, dst)
}
}
} else {
- src.Esc = EscScope
+ src.Esc = EscHeap
if Debug['m'] != 0 {
-
if Debug['m'] <= 2 {
- Warnl(src.Lineno, "leaking param: %v", Nconv(src, FmtShort))
+ Warnl(src.Lineno, "leaking param: %S", src)
step.describe(src)
} else {
- Warnl(src.Lineno, "leaking param: %v level=%v dst.eld=%v src.eld=%v dst=%v",
- Nconv(src, FmtShort), level, dstE.Escloopdepth, modSrcLoopdepth, Nconv(dst, FmtShort))
+ Warnl(src.Lineno, "leaking param: %S level=%v dst.eld=%v src.eld=%v dst=%S",
+ src, level, dstE.Loopdepth, modSrcLoopdepth, dst)
}
}
}
@@ -1854,10 +1884,10 @@ func escwalkBody(e *EscState, level Level, dst *Node, src *Node, step *EscStep,
// original variable.
if src.isClosureVar() {
if leaks && Debug['m'] != 0 {
- Warnl(src.Lineno, "leaking closure reference %v", Nconv(src, FmtShort))
+ Warnl(src.Lineno, "leaking closure reference %S", src)
step.describe(src)
}
- escwalk(e, level, dst, src.Name.Defn, e.stepWalk(dst, src.Name.Defn, "closure-var", step))
+ e.escwalk(level, dst, src.Name.Defn, e.stepWalk(dst, src.Name.Defn, "closure-var", step))
}
case OPTRLIT, OADDR:
@@ -1873,28 +1903,28 @@ func escwalkBody(e *EscState, 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, "%v escapes to heap, level=%v, dst=%v dst.eld=%v, src.eld=%v",
- Nconv(p, FmtShort), level, dst, dstE.Escloopdepth, modSrcLoopdepth)
+ Warnl(src.Lineno, "%S escapes to heap, level=%v, dst=%v dst.eld=%v, src.eld=%v",
+ p, level, dst, dstE.Loopdepth, modSrcLoopdepth)
} else {
- Warnl(src.Lineno, "%v escapes to heap", Nconv(p, FmtShort))
+ Warnl(src.Lineno, "%S escapes to heap", p)
step.describe(src)
}
}
addrescapes(src.Left)
- escwalkBody(e, level.dec(), dst, src.Left, e.stepWalk(dst, src.Left, why, step), modSrcLoopdepth)
+ e.escwalkBody(level.dec(), dst, src.Left, e.stepWalk(dst, src.Left, why, step), modSrcLoopdepth)
extraloopdepth = modSrcLoopdepth // passes to recursive case, seems likely a no-op
} else {
- escwalk(e, level.dec(), dst, src.Left, e.stepWalk(dst, src.Left, why, step))
+ e.escwalk(level.dec(), dst, src.Left, e.stepWalk(dst, src.Left, why, step))
}
case OAPPEND:
- escwalk(e, level, dst, src.List.First(), e.stepWalk(dst, src.List.First(), "append-first-arg", step))
+ e.escwalk(level, dst, src.List.First(), e.stepWalk(dst, src.List.First(), "append-first-arg", step))
case ODDDARG:
if leaks {
src.Esc = EscHeap
if Debug['m'] != 0 && osrcesc != src.Esc {
- Warnl(src.Lineno, "%v escapes to heap", Nconv(src, FmtShort))
+ Warnl(src.Lineno, "%S escapes to heap", src)
step.describe(src)
}
extraloopdepth = modSrcLoopdepth
@@ -1902,12 +1932,12 @@ func escwalkBody(e *EscState, level Level, dst *Node, src *Node, step *EscStep,
// similar to a slice arraylit and its args.
level = level.dec()
- case OARRAYLIT:
- if src.Type.IsArray() {
- break
- }
+ case OSLICELIT:
for _, n1 := range src.List.Slice() {
- escwalk(e, level.dec(), dst, n1.Right, e.stepWalk(dst, n1.Right, "slice-literal-element", step))
+ if n1.Op == OKEY {
+ n1 = n1.Right
+ }
+ e.escwalk(level.dec(), dst, n1, e.stepWalk(dst, n1, "slice-literal-element", step))
}
fallthrough
@@ -1929,7 +1959,7 @@ func escwalkBody(e *EscState, level Level, dst *Node, src *Node, step *EscStep,
if leaks {
src.Esc = EscHeap
if Debug['m'] != 0 && osrcesc != src.Esc {
- Warnl(src.Lineno, "%v escapes to heap", Nconv(src, FmtShort))
+ Warnl(src.Lineno, "%S escapes to heap", src)
step.describe(src)
}
extraloopdepth = modSrcLoopdepth
@@ -1937,7 +1967,7 @@ func escwalkBody(e *EscState, level Level, dst *Node, src *Node, step *EscStep,
case ODOT,
ODOTTYPE:
- escwalk(e, level, dst, src.Left, e.stepWalk(dst, src.Left, "dot", step))
+ e.escwalk(level, dst, src.Left, e.stepWalk(dst, src.Left, "dot", step))
case
OSLICE,
@@ -1945,21 +1975,21 @@ func escwalkBody(e *EscState, level Level, dst *Node, src *Node, step *EscStep,
OSLICE3,
OSLICE3ARR,
OSLICESTR:
- escwalk(e, level, dst, src.Left, e.stepWalk(dst, src.Left, "slice", step))
+ e.escwalk(level, dst, src.Left, e.stepWalk(dst, src.Left, "slice", step))
case OINDEX:
if src.Left.Type.IsArray() {
- escwalk(e, level, dst, src.Left, e.stepWalk(dst, src.Left, "fixed-array-index-of", step))
+ e.escwalk(level, dst, src.Left, e.stepWalk(dst, src.Left, "fixed-array-index-of", step))
break
}
fallthrough
case ODOTPTR:
- escwalk(e, level.inc(), dst, src.Left, e.stepWalk(dst, src.Left, "dot of pointer", step))
+ e.escwalk(level.inc(), dst, src.Left, e.stepWalk(dst, src.Left, "dot of pointer", step))
case OINDEXMAP:
- escwalk(e, level.inc(), dst, src.Left, e.stepWalk(dst, src.Left, "map index", step))
+ e.escwalk(level.inc(), dst, src.Left, e.stepWalk(dst, src.Left, "map index", step))
case OIND:
- escwalk(e, level.inc(), dst, src.Left, e.stepWalk(dst, src.Left, "indirection", step))
+ e.escwalk(level.inc(), dst, src.Left, e.stepWalk(dst, src.Left, "indirection", step))
// In this case a link went directly to a call, but should really go
// to the dummy .outN outputs that were created for the call that
@@ -1967,23 +1997,25 @@ func escwalkBody(e *EscState, level Level, dst *Node, src *Node, step *EscStep,
// See e.g. #10466
// This can only happen with functions returning a single result.
case OCALLMETH, OCALLFUNC, OCALLINTER:
- if srcE.Escretval.Len() != 0 {
+ if srcE.Retval.Len() != 0 {
if Debug['m'] > 2 {
- fmt.Printf("%v:[%d] dst %v escwalk replace src: %v with %v\n",
+ fmt.Printf("%v:[%d] dst %S escwalk replace src: %S with %S\n",
linestr(lineno), e.loopdepth,
- Nconv(dst, FmtShort), Nconv(src, FmtShort), Nconv(srcE.Escretval.First(), FmtShort))
+ dst, src, srcE.Retval.First())
}
- src = srcE.Escretval.First()
+ src = srcE.Retval.First()
srcE = e.nodeEscState(src)
}
}
recurse:
level = level.copy()
- for i, ll := range srcE.Escflowsrc {
- srcE.Escflowsrc[i].parent = step
- escwalkBody(e, level, dst, ll.src, &srcE.Escflowsrc[i], extraloopdepth)
- srcE.Escflowsrc[i].parent = nil
+
+ for i := range srcE.Flowsrc {
+ s := &srcE.Flowsrc[i]
+ s.parent = step
+ e.escwalkBody(level, dst, s.src, s, extraloopdepth)
+ s.parent = nil
}
e.pdepth--
@@ -2000,8 +2032,8 @@ var unsafeUintptrTag = "unsafe-uintptr"
// marked go:uintptrescapes.
const uintptrEscapesTag = "uintptr-escapes"
-func esctag(e *EscState, func_ *Node) {
- func_.Esc = EscFuncTagged
+func (e *EscState) esctag(fn *Node) {
+ fn.Esc = EscFuncTagged
name := func(s *Sym, narg int) string {
if s != nil {
@@ -2012,11 +2044,11 @@ func esctag(e *EscState, func_ *Node) {
// External functions are assumed unsafe,
// unless //go:noescape is given before the declaration.
- if func_.Nbody.Len() == 0 {
- if func_.Noescape {
- for _, t := range func_.Type.Params().Fields().Slice() {
- if haspointers(t.Type) {
- t.Note = mktag(EscNone)
+ if fn.Nbody.Len() == 0 {
+ if fn.Noescape {
+ for _, f := range fn.Type.Params().Fields().Slice() {
+ if haspointers(f.Type) {
+ f.Note = mktag(EscNone)
}
}
}
@@ -2028,44 +2060,41 @@ func esctag(e *EscState, func_ *Node) {
// but we are reusing the ability to annotate an individual function
// argument and pass those annotations along to importing code.
narg := 0
- for _, t := range func_.Type.Params().Fields().Slice() {
+ for _, f := range fn.Type.Params().Fields().Slice() {
narg++
- if t.Type.Etype == TUINTPTR {
+ if f.Type.Etype == TUINTPTR {
if Debug['m'] != 0 {
- Warnl(func_.Lineno, "%v assuming %v is unsafe uintptr", funcSym(func_), name(t.Sym, narg))
+ Warnl(fn.Lineno, "%v assuming %v is unsafe uintptr", funcSym(fn), name(f.Sym, narg))
}
- t.Note = unsafeUintptrTag
+ f.Note = unsafeUintptrTag
}
}
return
}
- if func_.Func.Pragma&UintptrEscapes != 0 {
+ if fn.Func.Pragma&UintptrEscapes != 0 {
narg := 0
- for _, t := range func_.Type.Params().Fields().Slice() {
+ for _, f := range fn.Type.Params().Fields().Slice() {
narg++
- if t.Type.Etype == TUINTPTR {
+ if f.Type.Etype == TUINTPTR {
if Debug['m'] != 0 {
- Warnl(func_.Lineno, "%v marking %v as escaping uintptr", funcSym(func_), name(t.Sym, narg))
+ Warnl(fn.Lineno, "%v marking %v as escaping uintptr", funcSym(fn), name(f.Sym, narg))
}
- t.Note = uintptrEscapesTag
+ f.Note = uintptrEscapesTag
}
- if t.Isddd && t.Type.Elem().Etype == TUINTPTR {
+ if f.Isddd && f.Type.Elem().Etype == TUINTPTR {
// final argument is ...uintptr.
if Debug['m'] != 0 {
- Warnl(func_.Lineno, "%v marking %v as escaping ...uintptr", funcSym(func_), name(t.Sym, narg))
+ Warnl(fn.Lineno, "%v marking %v as escaping ...uintptr", funcSym(fn), name(f.Sym, narg))
}
- t.Note = uintptrEscapesTag
+ f.Note = uintptrEscapesTag
}
}
}
- savefn := Curfn
- Curfn = func_
-
- for _, ln := range Curfn.Func.Dcl {
+ for _, ln := range fn.Func.Dcl {
if ln.Op != ONAME {
continue
}
@@ -2079,11 +2108,7 @@ func esctag(e *EscState, func_ *Node) {
}
}
- case EscHeap, // touched by escflood, moved to heap
- EscScope: // touched by escflood, value leaves scope
- break
+ case EscHeap: // touched by escflood, moved to heap
}
}
-
- Curfn = savefn
}
diff --git a/src/cmd/compile/internal/gc/export.go b/src/cmd/compile/internal/gc/export.go
index 911ef0f..b4c15e4 100644
--- a/src/cmd/compile/internal/gc/export.go
+++ b/src/cmd/compile/internal/gc/export.go
@@ -9,14 +9,12 @@ import (
"bytes"
"cmd/internal/bio"
"fmt"
- "sort"
"unicode"
"unicode/utf8"
)
var (
- newexport bool // if set, use new export format
- Debug_export int // if set, print debugging information about export data
+ Debug_export int // if set, print debugging information about export data
exportsize int
)
@@ -37,16 +35,21 @@ func exportsym(n *Node) {
}
if n.Sym.Flags&(SymExport|SymPackage) != 0 {
if n.Sym.Flags&SymPackage != 0 {
- Yyerror("export/package mismatch: %v", n.Sym)
+ yyerror("export/package mismatch: %v", n.Sym)
}
return
}
n.Sym.Flags |= SymExport
-
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)
+ }
+
exportlist = append(exportlist, n)
}
@@ -84,8 +87,7 @@ func autoexport(n *Node, ctxt Class) {
return
}
- // -A is for cmd/gc/mkbuiltin script, so export everything
- if Debug['A'] != 0 || exportname(n.Sym.Name) || initname(n.Sym.Name) {
+ if exportname(n.Sym.Name) || initname(n.Sym.Name) {
exportsym(n)
}
if asmhdr != "" && n.Sym.Pkg == localpkg && n.Sym.Flags&SymAsm == 0 {
@@ -94,18 +96,6 @@ func autoexport(n *Node, ctxt Class) {
}
}
-func dumppkg(p *Pkg) {
- if p == nil || p == localpkg || p.Exported || p == builtinpkg {
- return
- }
- p.Exported = true
- suffix := ""
- if !p.Direct {
- suffix = " // indirect"
- }
- exportf("\timport %s %q%s\n", p.Name, p.Path, suffix)
-}
-
// Look for anything we need for the inline body
func reexportdeplist(ll Nodes) {
for _, n := range ll.Slice() {
@@ -130,7 +120,7 @@ func reexportdep(n *Node) {
}
// nodes for method calls.
- if n.Type == nil || n.Type.Recv() != nil {
+ if n.Type == nil || n.IsMethod() {
break
}
fallthrough
@@ -196,6 +186,7 @@ func reexportdep(n *Node) {
ODOTTYPE2,
OSTRUCTLIT,
OARRAYLIT,
+ OSLICELIT,
OPTRLIT,
OMAKEMAP,
OMAKESLICE,
@@ -224,53 +215,6 @@ func reexportdep(n *Node) {
reexportdeplist(n.Nbody)
}
-func dumpexportconst(s *Sym) {
- n := typecheck(s.Def, Erv)
- if n == nil || n.Op != OLITERAL {
- Fatalf("dumpexportconst: oconst nil: %v", s)
- }
-
- t := n.Type // may or may not be specified
- dumpexporttype(t)
-
- if t != nil && !t.IsUntyped() {
- exportf("\tconst %v %v = %v\n", sconv(s, FmtSharp), Tconv(t, FmtSharp), vconv(n.Val(), FmtSharp))
- } else {
- exportf("\tconst %v = %v\n", sconv(s, FmtSharp), vconv(n.Val(), FmtSharp))
- }
-}
-
-func dumpexportvar(s *Sym) {
- n := s.Def
- n = typecheck(n, Erv|Ecall)
- if n == nil || n.Type == nil {
- Yyerror("variable exported but not defined: %v", s)
- return
- }
-
- t := n.Type
- dumpexporttype(t)
-
- if t.Etype == TFUNC && n.Class == PFUNC {
- if n.Func != nil && n.Func.Inl.Len() != 0 {
- // when lazily typechecking inlined bodies, some re-exported ones may not have been typechecked yet.
- // currently that can leave unresolved ONONAMEs in import-dot-ed packages in the wrong package
- if Debug['l'] < 2 {
- typecheckinl(n)
- }
-
- // NOTE: The space after %#S here is necessary for ld's export data parser.
- exportf("\tfunc %v %v { %v }\n", sconv(s, FmtSharp), Tconv(t, FmtShort|FmtSharp), hconv(n.Func.Inl, FmtSharp|FmtBody))
-
- reexportdeplist(n.Func.Inl)
- } else {
- exportf("\tfunc %v %v\n", sconv(s, FmtSharp), Tconv(t, FmtShort|FmtSharp))
- }
- } else {
- exportf("\tvar %v %v\n", sconv(s, FmtSharp), Tconv(t, FmtSharp))
- }
-}
-
// methodbyname sorts types by symbol name.
type methodbyname []*Field
@@ -278,167 +222,44 @@ func (x methodbyname) Len() int { return len(x) }
func (x methodbyname) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
func (x methodbyname) Less(i, j int) bool { return x[i].Sym.Name < x[j].Sym.Name }
-func dumpexporttype(t *Type) {
- if t == nil {
- return
- }
- if t.Printed || t == Types[t.Etype] || t == bytetype || t == runetype || t == errortype {
- return
- }
- t.Printed = true
-
- if t.Sym != nil {
- dumppkg(t.Sym.Pkg)
- }
-
- switch t.Etype {
- case TSTRUCT, TINTER:
- for _, f := range t.Fields().Slice() {
- dumpexporttype(f.Type)
- }
- case TFUNC:
- dumpexporttype(t.Recvs())
- dumpexporttype(t.Results())
- dumpexporttype(t.Params())
- case TMAP:
- dumpexporttype(t.Val())
- dumpexporttype(t.Key())
- case TARRAY, TCHAN, TPTR32, TPTR64, TSLICE:
- dumpexporttype(t.Elem())
- }
-
- if t.Sym == nil {
- return
- }
-
- var m []*Field
- for _, f := range t.Methods().Slice() {
- dumpexporttype(f.Type)
- m = append(m, f)
- }
- sort.Sort(methodbyname(m))
-
- exportf("\ttype %v %v\n", sconv(t.Sym, FmtSharp), Tconv(t, FmtSharp|FmtLong))
- for _, f := range m {
- if f.Nointerface {
- exportf("\t//go:nointerface\n")
- }
- if f.Type.Nname() != nil && f.Type.Nname().Func.Inl.Len() != 0 { // nname was set by caninl
-
- // when lazily typechecking inlined bodies, some re-exported ones may not have been typechecked yet.
- // currently that can leave unresolved ONONAMEs in import-dot-ed packages in the wrong package
- if Debug['l'] < 2 {
- typecheckinl(f.Type.Nname())
- }
- exportf("\tfunc %v %v %v { %v }\n", Tconv(f.Type.Recvs(), FmtSharp), sconv(f.Sym, FmtShort|FmtByte|FmtSharp), Tconv(f.Type, FmtShort|FmtSharp), hconv(f.Type.Nname().Func.Inl, FmtSharp|FmtBody))
- reexportdeplist(f.Type.Nname().Func.Inl)
- } else {
- exportf("\tfunc %v %v %v\n", Tconv(f.Type.Recvs(), FmtSharp), sconv(f.Sym, FmtShort|FmtByte|FmtSharp), Tconv(f.Type, FmtShort|FmtSharp))
- }
- }
-}
-
-func dumpsym(s *Sym) {
- if s.Flags&SymExported != 0 {
- return
- }
- s.Flags |= SymExported
-
- if s.Def == nil {
- Yyerror("unknown export symbol: %v", s)
- return
- }
-
- // print("dumpsym %O %+S\n", s->def->op, s);
- dumppkg(s.Pkg)
-
- switch s.Def.Op {
- default:
- Yyerror("unexpected export symbol: %v %v", s.Def.Op, s)
-
- case OLITERAL:
- dumpexportconst(s)
-
- case OTYPE:
- if s.Def.Type.Etype == TFORW {
- Yyerror("export of incomplete type %v", s)
- } else {
- dumpexporttype(s.Def.Type)
- }
-
- case ONAME:
- dumpexportvar(s)
- }
-}
-
func dumpexport() {
if buildid != "" {
exportf("build id %q\n", buildid)
}
size := 0 // size of export section without enclosing markers
- if newexport {
- // binary export
- // The linker also looks for the $$ marker - use char after $$ to distinguish format.
- exportf("\n$$B\n") // indicate binary format
- if debugFormat {
- // save a copy of the export data
- var copy bytes.Buffer
- bcopy := bufio.NewWriter(©)
- size = export(bcopy, Debug_export != 0)
- bcopy.Flush() // flushing to bytes.Buffer cannot fail
- if n, err := bout.Write(copy.Bytes()); n != size || err != nil {
- Fatalf("error writing export data: got %d bytes, want %d bytes, err = %v", n, size, err)
- }
- // export data must contain no '$' so that we can find the end by searching for "$$"
- if bytes.IndexByte(copy.Bytes(), '$') >= 0 {
- Fatalf("export data contains $")
- }
-
- // 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(©)) // must not die
- importpkg = nil
- pkgs = savedPkgs
- pkgMap = savedPkgMap
- } else {
- size = export(bout.Writer, Debug_export != 0)
- }
- exportf("\n$$\n")
- } else {
- // textual export
- lno := lineno
-
- exportf("\n$$\n") // indicate textual format
- exportsize = 0
- exportf("package %s", localpkg.Name)
- if safemode {
- exportf(" safe")
- }
- exportf("\n")
-
- for _, p := range pkgs {
- if p.Direct {
- dumppkg(p)
- }
+ // The linker also looks for the $$ marker - use char after $$ to distinguish format.
+ exportf("\n$$B\n") // indicate binary export format
+ if debugFormat {
+ // save a copy of the export data
+ var copy bytes.Buffer
+ bcopy := bufio.NewWriter(©)
+ size = export(bcopy, Debug_export != 0)
+ bcopy.Flush() // flushing to bytes.Buffer cannot fail
+ if n, err := bout.Write(copy.Bytes()); n != size || err != nil {
+ Fatalf("error writing export data: got %d bytes, want %d bytes, err = %v", n, size, err)
}
-
- // exportlist grows during iteration - cannot use range
- for i := 0; i < len(exportlist); i++ {
- n := exportlist[i]
- lineno = n.Lineno
- dumpsym(n.Sym)
+ // export data must contain no '$' so that we can find the end by searching for "$$"
+ // TODO(gri) is this still needed?
+ if bytes.IndexByte(copy.Bytes(), '$') >= 0 {
+ Fatalf("export data contains $")
}
- size = exportsize
- exportf("\n$$\n")
- lineno = lno
+ // 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(©)) // must not die
+ importpkg = nil
+ pkgs = savedPkgs
+ pkgMap = savedPkgMap
+ } else {
+ size = export(bout.Writer, Debug_export != 0)
}
+ exportf("\n$$\n")
if Debug_export != 0 {
fmt.Printf("export data size = %d bytes\n", size)
@@ -454,7 +275,7 @@ func importsym(s *Sym, op Op) {
// mark the symbol so it is not reexported
if s.Def == nil {
- if Debug['A'] != 0 || exportname(s.Name) || initname(s.Name) {
+ if exportname(s.Name) || initname(s.Name) {
s.Flags |= SymExport
} else {
s.Flags |= SymPackage // package scope
@@ -474,39 +295,11 @@ func pkgtype(s *Sym) *Type {
}
if s.Def.Type == nil {
- Yyerror("pkgtype %v", s)
+ yyerror("pkgtype %v", s)
}
return s.Def.Type
}
-// numImport tracks how often a package with a given name is imported.
-// It is used to provide a better error message (by using the package
-// path to disambiguate) if a package that appears multiple times with
-// the same name appears in an error message.
-var numImport = make(map[string]int)
-
-func importimport(s *Sym, path string) {
- // Informational: record package name
- // associated with import path, for use in
- // human-readable messages.
-
- if isbadimport(path) {
- errorexit()
- }
- p := mkpkg(path)
- if p.Name == "" {
- p.Name = s.Name
- numImport[s.Name]++
- } else if p.Name != s.Name {
- Yyerror("conflicting names %s and %s for package %q", p.Name, s.Name, p.Path)
- }
-
- if incannedimport == 0 && myimportpath != "" && path == myimportpath {
- Yyerror("import %q: package depends on %q (import cycle)", importpkg.Path, path)
- errorexit()
- }
-}
-
// 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)
@@ -517,7 +310,7 @@ func importconst(s *Sym, t *Type, n *Node) {
}
if n.Op != OLITERAL {
- Yyerror("expression must be a constant")
+ yyerror("expression must be a constant")
return
}
@@ -539,10 +332,10 @@ func importconst(s *Sym, t *Type, n *Node) {
func importvar(s *Sym, t *Type) {
importsym(s, ONAME)
if s.Def != nil && s.Def.Op == ONAME {
- if Eqtype(t, s.Def.Type) {
+ if eqtype(t, s.Def.Type) {
return
}
- Yyerror("inconsistent definition for var %v during import\n\t%v (in %q)\n\t%v (in %q)", s, s.Def.Type, s.Importdef.Path, t, importpkg.Path)
+ yyerror("inconsistent definition for var %v during import\n\t%v (in %q)\n\t%v (in %q)", s, s.Def.Type, s.Importdef.Path, t, importpkg.Path)
}
n := newname(s)
@@ -551,33 +344,7 @@ func importvar(s *Sym, t *Type) {
declare(n, PEXTERN)
if Debug['E'] != 0 {
- fmt.Printf("import var %v %v\n", s, Tconv(t, FmtLong))
- }
-}
-
-// importtype and importer.importtype (bimport.go) need to remain in sync.
-func importtype(pt *Type, t *Type) {
- // override declaration in unsafe.go for Pointer.
- // there is no way in Go code to define unsafe.Pointer
- // so we have to supply it.
- if incannedimport != 0 && importpkg.Name == "unsafe" && pt.Nod.Sym.Name == "Pointer" {
- t = Types[TUNSAFEPTR]
- }
-
- if pt.Etype == TFORW {
- n := pt.Nod
- copytype(pt.Nod, t)
- pt.Nod = n // unzero nod
- pt.Sym.Importdef = importpkg
- pt.Sym.Lastlineno = lineno
- declare(n, PEXTERN)
- checkwidth(pt)
- } else if !Eqtype(pt.Orig, t) {
- Yyerror("inconsistent definition for type %v during import\n\t%v (in %q)\n\t%v (in %q)", pt.Sym, Tconv(pt, FmtLong), pt.Sym.Importdef.Path, Tconv(t, FmtLong), importpkg.Path)
- }
-
- if Debug['E'] != 0 {
- fmt.Printf("import type %v %v\n", pt, Tconv(t, FmtLong))
+ fmt.Printf("import var %v %L\n", s, t)
}
}
@@ -593,7 +360,7 @@ func dumpasmhdr() {
}
switch n.Op {
case OLITERAL:
- fmt.Fprintf(b, "#define const_%s %v\n", n.Sym.Name, vconv(n.Val(), FmtSharp))
+ fmt.Fprintf(b, "#define const_%s %#v\n", n.Sym.Name, n.Val())
case OTYPE:
t := n.Type
diff --git a/src/cmd/compile/internal/gc/fixedbugs_test.go b/src/cmd/compile/internal/gc/fixedbugs_test.go
index 19b1d9a..095b816 100644
--- a/src/cmd/compile/internal/gc/fixedbugs_test.go
+++ b/src/cmd/compile/internal/gc/fixedbugs_test.go
@@ -18,7 +18,7 @@ func makeT() T {
var g T
-var sink []byte
+var sink interface{}
func TestIssue15854(t *testing.T) {
for i := 0; i < 10000; i++ {
diff --git a/src/cmd/compile/internal/gc/float_test.go b/src/cmd/compile/internal/gc/float_test.go
index c761e96..4fdcc7e 100644
--- a/src/cmd/compile/internal/gc/float_test.go
+++ b/src/cmd/compile/internal/gc/float_test.go
@@ -74,6 +74,27 @@ func cvt8(a float32) int32 {
return int32(a)
}
+// make sure to cover int, uint cases (issue #16738)
+//go:noinline
+func cvt9(a float64) int {
+ return int(a)
+}
+
+//go:noinline
+func cvt10(a float64) uint {
+ return uint(a)
+}
+
+//go:noinline
+func cvt11(a float32) int {
+ return int(a)
+}
+
+//go:noinline
+func cvt12(a float32) uint {
+ return uint(a)
+}
+
func TestFloatConvert(t *testing.T) {
if got := cvt1(3.5); got != 3 {
t.Errorf("cvt1 got %d, wanted 3", got)
@@ -99,4 +120,16 @@ func TestFloatConvert(t *testing.T) {
if got := cvt8(3.5); got != 3 {
t.Errorf("cvt8 got %d, wanted 3", got)
}
+ if got := cvt9(3.5); got != 3 {
+ t.Errorf("cvt9 got %d, wanted 3", got)
+ }
+ if got := cvt10(3.5); got != 3 {
+ t.Errorf("cvt10 got %d, wanted 3", got)
+ }
+ if got := cvt11(3.5); got != 3 {
+ t.Errorf("cvt11 got %d, wanted 3", got)
+ }
+ if got := cvt12(3.5); got != 3 {
+ t.Errorf("cvt12 got %d, wanted 3", got)
+ }
}
diff --git a/src/cmd/compile/internal/gc/fmt.go b/src/cmd/compile/internal/gc/fmt.go
index 3d26a1d..fffce44 100644
--- a/src/cmd/compile/internal/gc/fmt.go
+++ b/src/cmd/compile/internal/gc/fmt.go
@@ -5,8 +5,6 @@
package gc
import (
- "bytes"
- "cmd/internal/obj"
"fmt"
"strconv"
"strings"
@@ -18,120 +16,138 @@ import (
// See the respective function's documentation for details.
type FmtFlag int
-const (
- FmtWidth FmtFlag = 1 << iota
- FmtLeft // "-"
- FmtSharp // "#"
- FmtSign // "+"
- FmtUnsigned // "u"
- FmtShort // "h"
- FmtLong // "l"
- FmtComma // ","
- FmtByte // "hh"
- FmtBody // for printing export bodies
+// 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)
+ FmtShort // verb == 'S' (historic: h flag)
+ FmtLong // verb == 'L' (historic: l flag)
+ FmtComma // '.' (== hasPrec) (historic: , flag)
+ FmtByte // '0' (historic: hh flag)
)
+// fmtFlag computes the (internal) FmtFlag
+// value given the fmt.State and format verb.
+func fmtFlag(s fmt.State, verb rune) FmtFlag {
+ var flag FmtFlag
+ if s.Flag('-') {
+ flag |= FmtLeft
+ }
+ if s.Flag('#') {
+ flag |= FmtSharp
+ }
+ if s.Flag('+') {
+ flag |= FmtSign
+ }
+ if s.Flag(' ') {
+ flag |= FmtUnsigned
+ }
+ if _, ok := s.Precision(); ok {
+ flag |= FmtComma
+ }
+ if s.Flag('0') {
+ flag |= FmtByte
+ }
+ switch verb {
+ case 'S':
+ flag |= FmtShort
+ case 'L':
+ flag |= FmtLong
+ }
+ return flag
+}
+
+// Format conversions:
+// TODO(gri) verify these; eliminate those not used anymore
//
-// Format conversions
-// %L int Line numbers
-//
-// %E int etype values (aka 'Kind')
-//
-// %O int Node Opcodes
-// Flags: "%#O": print go syntax. (automatic unless fmtmode == FDbg)
-//
-// %J Node* Node details
-// Flags: "%hJ" suppresses things not relevant until walk.
-//
-// %V Val* Constant values
+// %v Op Node opcodes
+// Flags: #: print Go syntax (automatic unless fmtmode == FDbg)
//
-// %S Sym* Symbols
-// Flags: +,- #: mode (see below)
-// "%hS" unqualified identifier in any mode
-// "%hhS" in export mode: unqualified identifier if exported, qualified if not
+// %j *Node Node details
+// Flags: 0: suppresses things not relevant until walk
//
-// %T Type* Types
-// Flags: +,- #: mode (see below)
-// 'l' definition instead of name.
-// 'h' omit "func" and receiver in function types
-// 'u' (only in -/Sym mode) print type identifiers wit package name instead of prefix.
+// %v *Val Constant values
//
-// %N Node* Nodes
-// Flags: +,- #: mode (see below)
-// 'h' (only in +/debug mode) suppress recursion
-// 'l' (only in Error mode) print "foo (type Bar)"
+// %v *Sym Symbols
+// %S unqualified identifier in any mode
+// Flags: +,- #: mode (see below)
+// 0: in export mode: unqualified identifier if exported, qualified if not
//
-// %H Nodes Nodes
-// Flags: those of %N
-// ',' separate items with ',' instead of ';'
+// %v *Type Types
+// %S omit "func" and receiver in function types
+// %L definition instead of name.
+// Flags: +,- #: mode (see below)
+// ' ' (only in -/Sym mode) print type identifiers wit package name instead of prefix.
//
-// In mparith2.go and mparith3.go:
-// %B Mpint* Big integers
-// %F Mpflt* Big floats
+// %v *Node Nodes
+// %S (only in +/debug mode) suppress recursion
+// %L (only in Error mode) print "foo (type Bar)"
+// Flags: +,- #: mode (see below)
//
-// %S, %T and %N obey use the following flags to set the format mode:
+// %v Nodes Node lists
+// Flags: those of *Node
+// .: separate items with ',' instead of ';'
+
+// *Sym, *Type, and *Node types use the flags below to set the format mode
const (
FErr = iota
FDbg
- FExp
FTypeId
)
var fmtmode int = FErr
-var fmtpkgpfx int // %uT stickyness
+var fmtpkgpfx int // "% v" stickyness for *Type objects
-var fmtbody bool
-
-//
-// E.g. for %S: %+S %#S %-S print an identifier properly qualified for debug/export/internal mode.
+// The mode flags '+', '-', and '#' are sticky; they persist through
+// recursions of *Node, *Type, and *Sym values. The ' ' flag is
+// sticky only on *Type recursions and only used in %-/*Sym mode.
//
-// The mode flags +, - and # are sticky, meaning they persist through
-// recursions of %N, %T and %S, but not the h and l flags. The u flag is
-// sticky only on %T recursions and only used in %-/Sym mode.
+// Example: given a *Sym: %+v %#v %-v print an identifier properly qualified for debug/export/internal mode
-//
// Useful format combinations:
+// TODO(gri): verify these
//
-// %+N %+H multiline recursive debug dump of node/nodelist
-// %+hN %+hH non recursive debug dump
-//
-// %#N %#T export format
-// %#lT type definition instead of name
-// %#hT omit"func" and receiver in function signature
+// *Node, Nodes:
+// %+v multiline recursive debug dump of *Node/Nodes
+// %+S non-recursive debug dump
//
-// %lN "foo (type Bar)" for error messages
+// *Node:
+// %#v Go format
+// %L "foo (type Bar)" for error messages
//
-// %-T type identifiers
-// %-hT type identifiers without "func" and arg names in type signatures (methodsym)
-// %-uT type identifiers with package name instead of prefix (typesym, dcommontype, typehash)
+// *Type:
+// %#v Go format
+// %#L type definition instead of name
+// %#S omit"func" and receiver in function signature
//
+// %-v type identifiers
+// %-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, fb bool) {
+func setfmode(flags *FmtFlag) (fm int) {
fm = fmtmode
- fb = fmtbody
if *flags&FmtSign != 0 {
fmtmode = FDbg
} else if *flags&FmtSharp != 0 {
- fmtmode = FExp
+ // ignore (textual export format no longer supported)
} else if *flags&FmtLeft != 0 {
fmtmode = FTypeId
}
- if *flags&FmtBody != 0 {
- fmtbody = true
- }
-
- *flags &^= (FmtSharp | FmtLeft | FmtSign | FmtBody)
+ *flags &^= (FmtSharp | FmtLeft | FmtSign)
return
}
-// Fmt "%L": Linenumbers
-
var goopnames = []string{
OADDR: "&",
OADD: "+",
OADDSTR: "+",
+ OALIGNOF: "unsafe.Alignof",
OANDAND: "&&",
OANDNOT: "&^",
OAND: "&",
@@ -172,6 +188,7 @@ var goopnames = []string{
ONEW: "new",
ONE: "!=",
ONOT: "!",
+ OOFFSETOF: "unsafe.Offsetof",
OOROR: "||",
OOR: "|",
OPANIC: "panic",
@@ -186,6 +203,7 @@ var goopnames = []string{
ORSH: ">>",
OSELECT: "select",
OSEND: "<-",
+ OSIZEOF: "unsafe.Sizeof",
OSUB: "-",
OSWITCH: "switch",
OXOR: "^",
@@ -193,25 +211,37 @@ var goopnames = []string{
}
func (o Op) String() string {
- return oconv(o, 0)
+ return fmt.Sprint(o)
}
func (o Op) GoString() string {
- return oconv(o, FmtSharp)
+ return fmt.Sprintf("%#v", o)
}
-func oconv(o Op, flag FmtFlag) string {
+func (o Op) Format(s fmt.State, verb rune) {
+ switch verb {
+ case 'v':
+ o.oconv(s, fmtFlag(s, verb))
+
+ 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 {
if o >= 0 && int(o) < len(goopnames) && goopnames[o] != "" {
- return goopnames[o]
+ fmt.Fprint(s, goopnames[o])
+ return
}
}
if o >= 0 && int(o) < len(opnames) && opnames[o] != "" {
- return opnames[o]
+ fmt.Fprint(s, opnames[o])
+ return
}
- return fmt.Sprintf("O-%d", o)
+ fmt.Fprintf(s, "O-%d", int(o))
}
var classnames = []string{
@@ -224,49 +254,60 @@ var classnames = []string{
"PFUNC",
}
-// Fmt "%J": Node details.
-func jconv(n *Node, flag FmtFlag) string {
- var buf bytes.Buffer
+func (n *Node) Format(s fmt.State, verb rune) {
+ switch verb {
+ case 'v', 'S', 'L':
+ n.Nconv(s, fmtFlag(s, verb))
+
+ case 'j':
+ n.jconv(s, fmtFlag(s, verb))
+
+ default:
+ fmt.Fprintf(s, "%%!%c(*Node=%p)", verb, n)
+ }
+}
+// *Node details
+func (n *Node) jconv(s fmt.State, flag FmtFlag) {
c := flag & FmtShort
if c == 0 && n.Ullman != 0 {
- fmt.Fprintf(&buf, " u(%d)", n.Ullman)
+ fmt.Fprintf(s, " u(%d)", n.Ullman)
}
if c == 0 && n.Addable {
- fmt.Fprintf(&buf, " a(%v)", n.Addable)
+ fmt.Fprintf(s, " a(%v)", n.Addable)
}
if c == 0 && n.Name != nil && n.Name.Vargen != 0 {
- fmt.Fprintf(&buf, " g(%d)", n.Name.Vargen)
+ fmt.Fprintf(s, " g(%d)", n.Name.Vargen)
}
if n.Lineno != 0 {
- fmt.Fprintf(&buf, " l(%d)", n.Lineno)
+ fmt.Fprintf(s, " l(%d)", n.Lineno)
}
if c == 0 && n.Xoffset != BADWIDTH {
- fmt.Fprintf(&buf, " x(%d%+d)", n.Xoffset, stkdelta[n])
+ fmt.Fprintf(s, " x(%d)", n.Xoffset)
}
if n.Class != 0 {
if int(n.Class) < len(classnames) {
- fmt.Fprintf(&buf, " class(%s)", classnames[n.Class])
+ fmt.Fprintf(s, " class(%s)", classnames[n.Class])
} else {
- fmt.Fprintf(&buf, " class(%d?)", n.Class)
+ fmt.Fprintf(s, " class(%d?)", n.Class)
}
}
if n.Colas {
- fmt.Fprintf(&buf, " colas(%v)", n.Colas)
+ fmt.Fprintf(s, " colas(%v)", n.Colas)
}
if n.Name != nil && n.Name.Funcdepth != 0 {
- fmt.Fprintf(&buf, " f(%d)", n.Name.Funcdepth)
+ fmt.Fprintf(s, " f(%d)", n.Name.Funcdepth)
}
if n.Func != nil && n.Func.Depth != 0 {
- fmt.Fprintf(&buf, " ff(%d)", n.Func.Depth)
+ fmt.Fprintf(s, " ff(%d)", n.Func.Depth)
}
switch n.Esc {
@@ -274,125 +315,141 @@ func jconv(n *Node, flag FmtFlag) string {
break
case EscHeap:
- buf.WriteString(" esc(h)")
-
- case EscScope:
- buf.WriteString(" esc(s)")
+ fmt.Fprint(s, " esc(h)")
case EscNone:
- buf.WriteString(" esc(no)")
+ fmt.Fprint(s, " esc(no)")
case EscNever:
if c == 0 {
- buf.WriteString(" esc(N)")
+ fmt.Fprint(s, " esc(N)")
}
default:
- fmt.Fprintf(&buf, " esc(%d)", n.Esc)
+ fmt.Fprintf(s, " esc(%d)", n.Esc)
}
- if e, ok := n.Opt().(*NodeEscState); ok && e.Escloopdepth != 0 {
- fmt.Fprintf(&buf, " ld(%d)", e.Escloopdepth)
+ if e, ok := n.Opt().(*NodeEscState); ok && e.Loopdepth != 0 {
+ fmt.Fprintf(s, " ld(%d)", e.Loopdepth)
}
if c == 0 && n.Typecheck != 0 {
- fmt.Fprintf(&buf, " tc(%d)", n.Typecheck)
+ fmt.Fprintf(s, " tc(%d)", n.Typecheck)
}
- if c == 0 && n.Dodata != 0 {
- fmt.Fprintf(&buf, " dd(%d)", n.Dodata)
+ if c == 0 && n.IsStatic {
+ fmt.Fprint(s, " static")
}
if n.Isddd {
- fmt.Fprintf(&buf, " isddd(%v)", n.Isddd)
+ fmt.Fprintf(s, " isddd(%v)", n.Isddd)
}
if n.Implicit {
- fmt.Fprintf(&buf, " implicit(%v)", n.Implicit)
+ fmt.Fprintf(s, " implicit(%v)", n.Implicit)
}
if n.Embedded != 0 {
- fmt.Fprintf(&buf, " embedded(%d)", n.Embedded)
+ fmt.Fprintf(s, " embedded(%d)", n.Embedded)
}
if n.Addrtaken {
- buf.WriteString(" addrtaken")
+ fmt.Fprint(s, " addrtaken")
}
if n.Assigned {
- buf.WriteString(" assigned")
+ fmt.Fprint(s, " assigned")
}
if n.Bounded {
- buf.WriteString(" bounded")
+ fmt.Fprint(s, " bounded")
}
if n.NonNil {
- buf.WriteString(" nonnil")
+ fmt.Fprint(s, " nonnil")
}
if c == 0 && n.Used {
- fmt.Fprintf(&buf, " used(%v)", n.Used)
+ fmt.Fprintf(s, " used(%v)", n.Used)
+ }
+}
+
+func (v Val) Format(s fmt.State, verb rune) {
+ switch verb {
+ case 'v':
+ v.vconv(s, fmtFlag(s, verb))
+
+ default:
+ fmt.Fprintf(s, "%%!%c(Val=%T)", verb, v)
}
- return buf.String()
}
-// Fmt "%V": Values
-func vconv(v Val, flag FmtFlag) string {
+func (v Val) vconv(s fmt.State, flag FmtFlag) {
switch u := v.U.(type) {
case *Mpint:
if !u.Rune {
- if (flag&FmtSharp != 0) || fmtmode == FExp {
- return bconv(u, FmtSharp)
+ if flag&FmtSharp != 0 {
+ fmt.Fprint(s, bconv(u, FmtSharp))
+ return
}
- return bconv(u, 0)
+ fmt.Fprint(s, bconv(u, 0))
+ return
}
- x := u.Int64()
- if ' ' <= x && x < utf8.RuneSelf && x != '\\' && x != '\'' {
- return fmt.Sprintf("'%c'", int(x))
- }
- if 0 <= x && x < 1<<16 {
- return fmt.Sprintf("'\\u%04x'", uint(int(x)))
- }
- if 0 <= x && x <= utf8.MaxRune {
- return fmt.Sprintf("'\\U%08x'", uint64(x))
+ switch x := u.Int64(); {
+ case ' ' <= x && x < utf8.RuneSelf && x != '\\' && x != '\'':
+ fmt.Fprintf(s, "'%c'", int(x))
+
+ case 0 <= x && x < 1<<16:
+ fmt.Fprintf(s, "'\\u%04x'", uint(int(x)))
+
+ case 0 <= x && x <= utf8.MaxRune:
+ fmt.Fprintf(s, "'\\U%08x'", uint64(x))
+
+ default:
+ fmt.Fprintf(s, "('\\x00' + %v)", u)
}
- return fmt.Sprintf("('\\x00' + %v)", u)
case *Mpflt:
- if (flag&FmtSharp != 0) || fmtmode == FExp {
- return fconv(u, 0)
+ if flag&FmtSharp != 0 {
+ fmt.Fprint(s, fconv(u, 0))
+ return
}
- return fconv(u, FmtSharp)
+ fmt.Fprint(s, fconv(u, FmtSharp))
+ return
case *Mpcplx:
- if (flag&FmtSharp != 0) || fmtmode == FExp {
- return fmt.Sprintf("(%v+%vi)", &u.Real, &u.Imag)
- }
- if v.U.(*Mpcplx).Real.CmpFloat64(0) == 0 {
- return fmt.Sprintf("%vi", fconv(&u.Imag, FmtSharp))
- }
- if v.U.(*Mpcplx).Imag.CmpFloat64(0) == 0 {
- return fconv(&u.Real, FmtSharp)
- }
- if v.U.(*Mpcplx).Imag.CmpFloat64(0) < 0 {
- return fmt.Sprintf("(%v%vi)", fconv(&u.Real, FmtSharp), fconv(&u.Imag, FmtSharp))
+ switch {
+ case flag&FmtSharp != 0:
+ fmt.Fprintf(s, "(%v+%vi)", &u.Real, &u.Imag)
+
+ case v.U.(*Mpcplx).Real.CmpFloat64(0) == 0:
+ fmt.Fprintf(s, "%vi", fconv(&u.Imag, FmtSharp))
+
+ case v.U.(*Mpcplx).Imag.CmpFloat64(0) == 0:
+ fmt.Fprint(s, fconv(&u.Real, FmtSharp))
+
+ case v.U.(*Mpcplx).Imag.CmpFloat64(0) < 0:
+ fmt.Fprintf(s, "(%v%vi)", fconv(&u.Real, FmtSharp), fconv(&u.Imag, FmtSharp))
+
+ default:
+ fmt.Fprintf(s, "(%v+%vi)", fconv(&u.Real, FmtSharp), fconv(&u.Imag, FmtSharp))
}
- return fmt.Sprintf("(%v+%vi)", fconv(&u.Real, FmtSharp), fconv(&u.Imag, FmtSharp))
case string:
- return strconv.Quote(u)
+ fmt.Fprint(s, strconv.Quote(u))
case bool:
+ t := "false"
if u {
- return "true"
+ t = "true"
}
- return "false"
+ fmt.Fprint(s, t)
case *NilVal:
- return "nil"
- }
+ fmt.Fprint(s, "nil")
- return fmt.Sprintf("<ctype=%d>", v.Ctype())
+ default:
+ fmt.Fprintf(s, "<ctype=%d>", v.Ctype())
+ }
}
/*
@@ -451,8 +508,7 @@ func (et EType) String() string {
return fmt.Sprintf("E-%d", et)
}
-// Fmt "%S": syms
-func symfmt(s *Sym, flag FmtFlag) string {
+func (s *Sym) symfmt(flag FmtFlag) string {
if s.Pkg != nil && flag&FmtShort == 0 {
switch fmtmode {
case FErr: // This is for the user
@@ -474,31 +530,22 @@ func symfmt(s *Sym, flag FmtFlag) string {
return s.Pkg.Name + "." + s.Name // dcommontype, typehash
}
return s.Pkg.Prefix + "." + s.Name // (methodsym), typesym, weaksym
-
- case FExp:
- if s.Name != "" && s.Name[0] == '.' {
- Fatalf("exporting synthetic symbol %s", s.Name)
- }
- if s.Pkg != builtinpkg {
- return fmt.Sprintf("@%q.%s", s.Pkg.Path, s.Name)
- }
}
}
if flag&FmtByte != 0 {
// FmtByte (hh) implies FmtShort (h)
// skip leading "type." in method name
- p := s.Name
- if i := strings.LastIndex(s.Name, "."); i >= 0 {
- p = s.Name[i+1:]
+ name := s.Name
+ if i := strings.LastIndex(name, "."); i >= 0 {
+ name = name[i+1:]
}
- // exportname needs to see the name without the prefix too.
- if (fmtmode == FExp && !exportname(p)) || fmtmode == FDbg {
- return fmt.Sprintf("@%q.%s", s.Pkg.Path, p)
+ if fmtmode == FDbg {
+ return fmt.Sprintf("@%q.%s", s.Pkg.Path, name)
}
- return p
+ return name
}
return s.Name
@@ -528,7 +575,7 @@ var basicnames = []string{
TBLANK: "blank",
}
-func typefmt(t *Type, flag FmtFlag) string {
+func (t *Type) typefmt(flag FmtFlag) string {
if t == nil {
return "<T>"
}
@@ -536,7 +583,7 @@ func typefmt(t *Type, flag FmtFlag) string {
if t == bytetype || t == runetype {
// in %-T mode collapse rune and byte with their originals.
if fmtmode != FTypeId {
- return sconv(t.Sym, FmtShort)
+ return t.Sym.sconv(FmtShort)
}
t = Types[t.Etype]
}
@@ -551,23 +598,21 @@ func typefmt(t *Type, flag FmtFlag) string {
case FTypeId:
if flag&FmtShort != 0 {
if t.Vargen != 0 {
- return fmt.Sprintf("%v·%d", sconv(t.Sym, FmtShort), t.Vargen)
+ return fmt.Sprintf("%v·%d", t.Sym.sconv(FmtShort), t.Vargen)
}
- return sconv(t.Sym, FmtShort)
+ return t.Sym.sconv(FmtShort)
}
if flag&FmtUnsigned != 0 {
- return sconv(t.Sym, FmtUnsigned)
+ return t.Sym.sconv(FmtUnsigned)
}
- fallthrough
- case FExp:
if t.Sym.Pkg == localpkg && t.Vargen != 0 {
return fmt.Sprintf("%v·%d", t.Sym, t.Vargen)
}
}
- return sconv(t.Sym, 0)
+ return t.Sym.String()
}
if int(t.Etype) < len(basicnames) && basicnames[t.Etype] != "" {
@@ -580,7 +625,7 @@ func typefmt(t *Type, flag FmtFlag) string {
if fmtmode == FDbg {
fmtmode = 0
- str := t.Etype.String() + "-" + typefmt(t, flag)
+ str := t.Etype.String() + "-" + t.typefmt(flag)
fmtmode = FDbg
return str
}
@@ -588,7 +633,7 @@ func typefmt(t *Type, flag FmtFlag) string {
switch t.Etype {
case TPTR32, TPTR64:
if fmtmode == FTypeId && (flag&FmtShort != 0) {
- return "*" + Tconv(t.Elem(), FmtShort)
+ return "*" + t.Elem().tconv(FmtShort)
}
return "*" + t.Elem().String()
@@ -619,62 +664,61 @@ func typefmt(t *Type, flag FmtFlag) string {
return "map[" + t.Key().String() + "]" + t.Val().String()
case TINTER:
- var buf bytes.Buffer
- buf.WriteString("interface {")
+ if t.IsEmptyInterface() {
+ return "interface {}"
+ }
+ buf := make([]byte, 0, 64)
+ buf = append(buf, "interface {"...)
for i, f := range t.Fields().Slice() {
if i != 0 {
- buf.WriteString(";")
+ buf = append(buf, ';')
}
- buf.WriteString(" ")
+ buf = append(buf, ' ')
switch {
case f.Sym == nil:
// Check first that a symbol is defined for this type.
// Wrong interface definitions may have types lacking a symbol.
break
case exportname(f.Sym.Name):
- buf.WriteString(sconv(f.Sym, FmtShort))
+ buf = append(buf, f.Sym.sconv(FmtShort)...)
default:
- buf.WriteString(sconv(f.Sym, FmtUnsigned))
+ buf = append(buf, f.Sym.sconv(FmtUnsigned)...)
}
- buf.WriteString(Tconv(f.Type, FmtShort))
+ buf = append(buf, f.Type.tconv(FmtShort)...)
}
if t.NumFields() != 0 {
- buf.WriteString(" ")
+ buf = append(buf, ' ')
}
- buf.WriteString("}")
- return buf.String()
+ buf = append(buf, '}')
+ return string(buf)
case TFUNC:
- var buf bytes.Buffer
+ buf := make([]byte, 0, 64)
if flag&FmtShort != 0 {
// no leading func
} else {
if t.Recv() != nil {
- buf.WriteString("method")
- buf.WriteString(Tconv(t.Recvs(), 0))
- buf.WriteString(" ")
+ buf = append(buf, "method"...)
+ buf = append(buf, t.Recvs().String()...)
+ buf = append(buf, ' ')
}
- buf.WriteString("func")
+ buf = append(buf, "func"...)
}
- buf.WriteString(Tconv(t.Params(), 0))
+ buf = append(buf, t.Params().String()...)
switch t.Results().NumFields() {
case 0:
- break
+ // nothing to do
case 1:
- if fmtmode != FExp {
- buf.WriteString(" ")
- buf.WriteString(Tconv(t.Results().Field(0).Type, 0)) // struct->field->field's type
- break
- }
- fallthrough
+ buf = append(buf, ' ')
+ buf = append(buf, t.Results().Field(0).Type.String()...) // struct->field->field's type
default:
- buf.WriteString(" ")
- buf.WriteString(Tconv(t.Results(), 0))
+ buf = append(buf, ' ')
+ buf = append(buf, t.Results().String()...)
}
- return buf.String()
+ return string(buf)
case TSTRUCT:
if m := t.StructType().Map; m != nil {
@@ -693,38 +737,38 @@ func typefmt(t *Type, flag FmtFlag) string {
return "map.iter[" + m.Key().String() + "]" + m.Val().String()
}
- Yyerror("unknown internal map type")
+ yyerror("unknown internal map type")
}
- var buf bytes.Buffer
+ buf := make([]byte, 0, 64)
if t.IsFuncArgStruct() {
- buf.WriteString("(")
+ buf = append(buf, '(')
var flag1 FmtFlag
if fmtmode == FTypeId || fmtmode == 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.WriteString(", ")
+ buf = append(buf, ", "...)
}
- buf.WriteString(Fldconv(f, flag1))
+ buf = append(buf, fldconv(f, flag1)...)
}
- buf.WriteString(")")
+ buf = append(buf, ')')
} else {
- buf.WriteString("struct {")
+ buf = append(buf, "struct {"...)
for i, f := range t.Fields().Slice() {
if i != 0 {
- buf.WriteString(";")
+ buf = append(buf, ';')
}
- buf.WriteString(" ")
- buf.WriteString(Fldconv(f, FmtLong))
+ buf = append(buf, ' ')
+ buf = append(buf, fldconv(f, FmtLong)...)
}
if t.NumFields() != 0 {
- buf.WriteString(" ")
+ buf = append(buf, ' ')
}
- buf.WriteString("}")
+ buf = append(buf, '}')
}
- return buf.String()
+ return string(buf)
case TFORW:
if t.Sym != nil {
@@ -733,25 +777,15 @@ func typefmt(t *Type, flag FmtFlag) string {
return "undefined"
case TUNSAFEPTR:
- if fmtmode == FExp {
- return "@\"unsafe\".Pointer"
- }
return "unsafe.Pointer"
case TDDDFIELD:
- if fmtmode == FExp {
- Fatalf("cannot use TDDDFIELD with old exporter")
- }
return fmt.Sprintf("%v <%v> %v", t.Etype, t.Sym, t.DDDField())
case Txxx:
return "Txxx"
}
- if fmtmode == FExp {
- Fatalf("missing %v case during export", t.Etype)
- }
-
// Don't know how to handle - fall back to detailed prints.
return fmt.Sprintf("%v <%v> %v", t.Etype, t.Sym, t.Elem())
}
@@ -766,9 +800,7 @@ func stmtwithinit(op Op) bool {
return false
}
-func stmtfmt(n *Node) string {
- var f string
-
+func (n *Node) stmtfmt(s fmt.State) {
// 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
@@ -784,150 +816,155 @@ func stmtfmt(n *Node) string {
extrablock := complexinit && stmtwithinit(n.Op)
if extrablock {
- f += "{"
+ fmt.Fprint(s, "{")
}
if complexinit {
- f += fmt.Sprintf(" %v; ", n.Ninit)
+ fmt.Fprintf(s, " %v; ", n.Ninit)
}
switch n.Op {
case ODCL:
- if fmtmode == FExp {
- switch n.Left.Class {
- case PPARAM, PPARAMOUT, PAUTO, PAUTOHEAP:
- f += fmt.Sprintf("var %v %v", n.Left, n.Left.Type)
- goto ret
- }
- }
-
- f += fmt.Sprintf("var %v %v", n.Left.Sym, n.Left.Type)
+ fmt.Fprintf(s, "var %v %v", n.Left.Sym, n.Left.Type)
case ODCLFIELD:
if n.Left != nil {
- f += fmt.Sprintf("%v %v", n.Left, n.Right)
+ fmt.Fprintf(s, "%v %v", n.Left, n.Right)
} else {
- f += Nconv(n.Right, 0)
+ fmt.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 fmtmode == FExp && n.Right == nil {
- break
- }
-
if n.Colas && !complexinit {
- f += fmt.Sprintf("%v := %v", n.Left, n.Right)
+ fmt.Fprintf(s, "%v := %v", n.Left, n.Right)
} else {
- f += fmt.Sprintf("%v = %v", n.Left, n.Right)
+ fmt.Fprintf(s, "%v = %v", n.Left, n.Right)
}
case OASOP:
if n.Implicit {
if Op(n.Etype) == OADD {
- f += fmt.Sprintf("%v++", n.Left)
+ fmt.Fprintf(s, "%v++", n.Left)
} else {
- f += fmt.Sprintf("%v--", n.Left)
+ fmt.Fprintf(s, "%v--", n.Left)
}
break
}
- f += fmt.Sprintf("%v %#v= %v", n.Left, Op(n.Etype), n.Right)
+ fmt.Fprintf(s, "%v %#v= %v", n.Left, Op(n.Etype), n.Right)
case OAS2:
if n.Colas && !complexinit {
- f += fmt.Sprintf("%v := %v", hconv(n.List, FmtComma), hconv(n.Rlist, FmtComma))
+ fmt.Fprintf(s, "%.v := %.v", n.List, n.Rlist)
break
}
fallthrough
case OAS2DOTTYPE, OAS2FUNC, OAS2MAPR, OAS2RECV:
- f += fmt.Sprintf("%v = %v", hconv(n.List, FmtComma), hconv(n.Rlist, FmtComma))
+ fmt.Fprintf(s, "%.v = %.v", n.List, n.Rlist)
case ORETURN:
- f += fmt.Sprintf("return %v", hconv(n.List, FmtComma))
+ fmt.Fprintf(s, "return %.v", n.List)
case ORETJMP:
- f += fmt.Sprintf("retjmp %v", n.Sym)
+ fmt.Fprintf(s, "retjmp %v", n.Sym)
case OPROC:
- f += fmt.Sprintf("go %v", n.Left)
+ fmt.Fprintf(s, "go %v", n.Left)
case ODEFER:
- f += fmt.Sprintf("defer %v", n.Left)
+ fmt.Fprintf(s, "defer %v", n.Left)
case OIF:
if simpleinit {
- f += fmt.Sprintf("if %v; %v { %v }", n.Ninit.First(), n.Left, n.Nbody)
+ fmt.Fprintf(s, "if %v; %v { %v }", n.Ninit.First(), n.Left, n.Nbody)
} else {
- f += fmt.Sprintf("if %v { %v }", n.Left, n.Nbody)
+ fmt.Fprintf(s, "if %v { %v }", n.Left, n.Nbody)
}
if n.Rlist.Len() != 0 {
- f += fmt.Sprintf(" else { %v }", n.Rlist)
+ fmt.Fprintf(s, " else { %v }", n.Rlist)
}
case OFOR:
if fmtmode == FErr { // TODO maybe only if FmtShort, same below
- f += "for loop"
+ fmt.Fprint(s, "for loop")
break
}
- f += "for"
+ fmt.Fprint(s, "for")
if simpleinit {
- f += fmt.Sprintf(" %v;", n.Ninit.First())
+ fmt.Fprintf(s, " %v;", n.Ninit.First())
} else if n.Right != nil {
- f += " ;"
+ fmt.Fprint(s, " ;")
}
if n.Left != nil {
- f += fmt.Sprintf(" %v", n.Left)
+ fmt.Fprintf(s, " %v", n.Left)
}
if n.Right != nil {
- f += fmt.Sprintf("; %v", n.Right)
+ fmt.Fprintf(s, "; %v", n.Right)
} else if simpleinit {
- f += ";"
+ fmt.Fprint(s, ";")
}
- f += fmt.Sprintf(" { %v }", n.Nbody)
+ fmt.Fprintf(s, " { %v }", n.Nbody)
case ORANGE:
if fmtmode == FErr {
- f += "for loop"
+ fmt.Fprint(s, "for loop")
break
}
if n.List.Len() == 0 {
- f += fmt.Sprintf("for range %v { %v }", n.Right, n.Nbody)
+ fmt.Fprintf(s, "for range %v { %v }", n.Right, n.Nbody)
break
}
- f += fmt.Sprintf("for %v = range %v { %v }", hconv(n.List, FmtComma), n.Right, n.Nbody)
+ fmt.Fprintf(s, "for %.v = range %v { %v }", n.List, n.Right, n.Nbody)
case OSELECT, OSWITCH:
if fmtmode == FErr {
- f += fmt.Sprintf("%v statement", n.Op)
+ fmt.Fprintf(s, "%v statement", n.Op)
break
}
- f += n.Op.GoString() // %#v
+ fmt.Fprint(s, n.Op.GoString()) // %#v
if simpleinit {
- f += fmt.Sprintf(" %v;", n.Ninit.First())
+ fmt.Fprintf(s, " %v;", n.Ninit.First())
}
if n.Left != nil {
- f += fmt.Sprintf(" %s ", Nconv(n.Left, 0))
+ fmt.Fprintf(s, " %v ", n.Left)
}
- f += fmt.Sprintf(" { %v }", n.List)
+ fmt.Fprintf(s, " { %v }", n.List)
- case OCASE, OXCASE:
+ case OXCASE:
if n.List.Len() != 0 {
- f += fmt.Sprintf("case %v: %v", hconv(n.List, FmtComma), n.Nbody)
+ fmt.Fprintf(s, "case %.v", n.List)
} else {
- f += fmt.Sprintf("default: %v", n.Nbody)
+ fmt.Fprint(s, "default")
+ }
+ fmt.Fprintf(s, ": %v", n.Nbody)
+
+ case OCASE:
+ switch {
+ case n.Left != nil:
+ // single element
+ fmt.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())
+ default:
+ fmt.Fprint(s, "default")
}
+ fmt.Fprintf(s, ": %v", n.Nbody)
case OBREAK,
OCONTINUE,
@@ -935,30 +972,29 @@ func stmtfmt(n *Node) string {
OFALL,
OXFALL:
if n.Left != nil {
- f += fmt.Sprintf("%#v %v", n.Op, n.Left)
+ fmt.Fprintf(s, "%#v %v", n.Op, n.Left)
} else {
- f += n.Op.GoString() // %#v
+ fmt.Fprint(s, n.Op.GoString()) // %#v
}
case OEMPTY:
break
case OLABEL:
- f += fmt.Sprintf("%v: ", n.Left)
+ fmt.Fprintf(s, "%v: ", n.Left)
}
-ret:
if extrablock {
- f += "}"
+ fmt.Fprint(s, "}")
}
-
- return f
}
var opprec = []int{
+ OALIGNOF: 8,
OAPPEND: 8,
OARRAYBYTESTR: 8,
OARRAYLIT: 8,
+ OSLICELIT: 8,
OARRAYRUNESTR: 8,
OCALLFUNC: 8,
OCALLINTER: 8,
@@ -980,12 +1016,14 @@ var opprec = []int{
ONAME: 8,
ONEW: 8,
ONONAME: 8,
+ OOFFSETOF: 8,
OPACK: 8,
OPANIC: 8,
OPAREN: 8,
OPRINTN: 8,
OPRINT: 8,
ORUNESTR: 8,
+ OSIZEOF: 8,
OSTRARRAYBYTE: 8,
OSTRARRAYRUNE: 8,
OSTRUCTLIT: 8,
@@ -1069,13 +1107,14 @@ var opprec = []int{
OEND: 0,
}
-func exprfmt(n *Node, prec int) string {
+func (n *Node) exprfmt(s fmt.State, prec int) {
for n != nil && n.Implicit && (n.Op == OIND || n.Op == OADDR) {
n = n.Left
}
if n == nil {
- return "<N>"
+ fmt.Fprint(s, "<N>")
+ return
}
nprec := opprec[n.Op]
@@ -1084,254 +1123,206 @@ func exprfmt(n *Node, prec int) string {
}
if prec > nprec {
- return fmt.Sprintf("(%v)", n)
+ fmt.Fprintf(s, "(%v)", n)
+ return
}
switch n.Op {
case OPAREN:
- return fmt.Sprintf("(%v)", n.Left)
+ fmt.Fprintf(s, "(%v)", n.Left)
case ODDDARG:
- return "... argument"
-
- case OREGISTER:
- return obj.Rconv(int(n.Reg))
+ fmt.Fprint(s, "... argument")
case OLITERAL: // this is a bit of a mess
if fmtmode == FErr {
if n.Orig != nil && n.Orig != n {
- return exprfmt(n.Orig, prec)
+ n.Orig.exprfmt(s, prec)
+ return
}
if n.Sym != nil {
- return sconv(n.Sym, 0)
+ fmt.Fprint(s, n.Sym.String())
+ return
}
}
if n.Val().Ctype() == CTNIL && n.Orig != nil && n.Orig != n {
- return exprfmt(n.Orig, prec)
+ n.Orig.exprfmt(s, prec)
+ return
}
if n.Type != nil && n.Type.Etype != TIDEAL && n.Type.Etype != TNIL && n.Type != idealbool && n.Type != idealstring {
// Need parens when type begins with what might
// be misinterpreted as a unary operator: * or <-.
if n.Type.IsPtr() || (n.Type.IsChan() && n.Type.ChanDir() == Crecv) {
- return fmt.Sprintf("(%v)(%v)", n.Type, vconv(n.Val(), 0))
+ fmt.Fprintf(s, "(%v)(%v)", n.Type, n.Val())
+ return
} else {
- return fmt.Sprintf("%v(%v)", n.Type, vconv(n.Val(), 0))
+ fmt.Fprintf(s, "%v(%v)", n.Type, n.Val())
+ return
}
}
- return vconv(n.Val(), 0)
+ fmt.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 == FExp || fmtmode == FErr) && n.Sym != nil && n.Sym.Name[0] == '~' && n.Sym.Name[1] == 'b' {
- return "_"
- }
- if fmtmode == FExp && n.Sym != nil && !isblank(n) && n.Name.Vargen > 0 {
- return fmt.Sprintf("%v·%d", n.Sym, n.Name.Vargen)
- }
-
- // Special case: explicit name of func (*T) method(...) is turned into pkg.(*T).method,
- // but for export, this should be rendered as (*pkg.T).meth.
- // These nodes have the special property that they are names with a left OTYPE and a right ONAME.
- if fmtmode == FExp && n.Left != nil && n.Left.Op == OTYPE && n.Right != nil && n.Right.Op == ONAME {
- if n.Left.Type.IsPtr() {
- return fmt.Sprintf("(%v).%v", n.Left.Type, sconv(n.Right.Sym, FmtShort|FmtByte))
- } else {
- return fmt.Sprintf("%v.%v", n.Left.Type, sconv(n.Right.Sym, FmtShort|FmtByte))
- }
+ if fmtmode == FErr && n.Sym != nil && n.Sym.Name[0] == '~' && n.Sym.Name[1] == 'b' {
+ fmt.Fprint(s, "_")
+ return
}
fallthrough
-
case OPACK, ONONAME:
- return sconv(n.Sym, 0)
+ fmt.Fprint(s, n.Sym.String())
case OTYPE:
if n.Type == nil && n.Sym != nil {
- return sconv(n.Sym, 0)
+ fmt.Fprint(s, n.Sym.String())
+ return
}
- return Tconv(n.Type, 0)
+ fmt.Fprintf(s, "%v", n.Type)
case OTARRAY:
if n.Left != nil {
- return fmt.Sprintf("[]%v", n.Left)
+ fmt.Fprintf(s, "[]%v", n.Left)
+ return
}
- return fmt.Sprintf("[]%v", n.Right) // happens before typecheck
+ fmt.Fprintf(s, "[]%v", n.Right) // happens before typecheck
case OTMAP:
- return fmt.Sprintf("map[%v]%v", n.Left, n.Right)
+ fmt.Fprintf(s, "map[%v]%v", n.Left, n.Right)
case OTCHAN:
switch ChanDir(n.Etype) {
case Crecv:
- return fmt.Sprintf("<-chan %v", n.Left)
+ fmt.Fprintf(s, "<-chan %v", n.Left)
case Csend:
- return fmt.Sprintf("chan<- %v", n.Left)
+ fmt.Fprintf(s, "chan<- %v", n.Left)
default:
if n.Left != nil && n.Left.Op == OTCHAN && n.Left.Sym == nil && ChanDir(n.Left.Etype) == Crecv {
- return fmt.Sprintf("chan (%v)", n.Left)
+ fmt.Fprintf(s, "chan (%v)", n.Left)
} else {
- return fmt.Sprintf("chan %v", n.Left)
+ fmt.Fprintf(s, "chan %v", n.Left)
}
}
case OTSTRUCT:
- return "<struct>"
+ fmt.Fprint(s, "<struct>")
case OTINTER:
- return "<inter>"
+ fmt.Fprint(s, "<inter>")
case OTFUNC:
- return "<func>"
+ fmt.Fprint(s, "<func>")
case OCLOSURE:
if fmtmode == FErr {
- return "func literal"
+ fmt.Fprint(s, "func literal")
+ return
}
if n.Nbody.Len() != 0 {
- return fmt.Sprintf("%v { %v }", n.Type, n.Nbody)
+ fmt.Fprintf(s, "%v { %v }", n.Type, n.Nbody)
+ return
}
- return fmt.Sprintf("%v { %v }", n.Type, n.Func.Closure.Nbody)
+ fmt.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 {
if ptrlit {
- return fmt.Sprintf("&%v literal", n.Right.Type.Elem())
+ fmt.Fprintf(s, "&%v literal", n.Right.Type.Elem())
+ return
} else {
- return fmt.Sprintf("%v literal", n.Right.Type)
+ fmt.Fprintf(s, "%v literal", n.Right.Type)
+ return
}
}
- return "composite literal"
+ fmt.Fprint(s, "composite literal")
+ return
}
-
- if fmtmode == FExp && ptrlit {
- // typecheck has overwritten OIND by OTYPE with pointer type.
- return fmt.Sprintf("(&%v{ %v })", n.Right.Type.Elem(), hconv(n.List, FmtComma))
- }
-
- return fmt.Sprintf("(%v{ %v })", n.Right, hconv(n.List, FmtComma))
+ fmt.Fprintf(s, "(%v{ %.v })", n.Right, n.List)
case OPTRLIT:
- if fmtmode == FExp && n.Left.Implicit {
- return Nconv(n.Left, 0)
- }
- return fmt.Sprintf("&%v", n.Left)
+ fmt.Fprintf(s, "&%v", n.Left)
- case OSTRUCTLIT:
- if fmtmode == FExp { // requires special handling of field names
- var f string
- if n.Implicit {
- f += "{"
- } else {
- f += fmt.Sprintf("(%v{", n.Type)
- }
- for i1, n1 := range n.List.Slice() {
- f += fmt.Sprintf(" %v:%v", sconv(n1.Left.Sym, FmtShort|FmtByte), n1.Right)
-
- if i1+1 < n.List.Len() {
- f += ","
- } else {
- f += " "
- }
- }
-
- if !n.Implicit {
- f += "})"
- return f
- }
- f += "}"
- return f
- }
- fallthrough
-
- case OARRAYLIT, OMAPLIT:
+ case OSTRUCTLIT, OARRAYLIT, OSLICELIT, OMAPLIT:
if fmtmode == FErr {
- return fmt.Sprintf("%v literal", n.Type)
+ fmt.Fprintf(s, "%v literal", n.Type)
+ return
}
- if fmtmode == FExp && n.Implicit {
- return fmt.Sprintf("{ %v }", hconv(n.List, FmtComma))
- }
- return fmt.Sprintf("(%v{ %v })", n.Type, hconv(n.List, FmtComma))
+ fmt.Fprintf(s, "(%v{ %.v })", n.Type, n.List)
case OKEY:
if n.Left != nil && n.Right != nil {
- if fmtmode == FExp && n.Left.Type == structkey {
- // requires special handling of field names
- return fmt.Sprintf("%v:%v", sconv(n.Left.Sym, FmtShort|FmtByte), n.Right)
- } else {
- return fmt.Sprintf("%v:%v", n.Left, n.Right)
- }
+ fmt.Fprintf(s, "%v:%v", n.Left, n.Right)
+ return
}
if n.Left == nil && n.Right != nil {
- return fmt.Sprintf(":%v", n.Right)
+ fmt.Fprintf(s, ":%v", n.Right)
+ return
}
if n.Left != nil && n.Right == nil {
- return fmt.Sprintf("%v:", n.Left)
+ fmt.Fprintf(s, "%v:", n.Left)
+ return
}
- return ":"
+ fmt.Fprint(s, ":")
+
+ case OSTRUCTKEY:
+ fmt.Fprintf(s, "%v:%v", n.Sym, n.Left)
case OCALLPART:
- var f string
- f += exprfmt(n.Left, nprec)
+ n.Left.exprfmt(s, nprec)
if n.Right == nil || n.Right.Sym == nil {
- f += ".<nil>"
- return f
+ fmt.Fprint(s, ".<nil>")
+ return
}
- f += fmt.Sprintf(".%v", sconv(n.Right.Sym, FmtShort|FmtByte))
- return f
+ fmt.Fprintf(s, ".%0S", n.Right.Sym)
case OXDOT, ODOT, ODOTPTR, ODOTINTER, ODOTMETH:
- var f string
- f += exprfmt(n.Left, nprec)
+ n.Left.exprfmt(s, nprec)
if n.Sym == nil {
- f += ".<nil>"
- return f
+ fmt.Fprint(s, ".<nil>")
+ return
}
- f += fmt.Sprintf(".%v", sconv(n.Sym, FmtShort|FmtByte))
- return f
+ fmt.Fprintf(s, ".%0S", n.Sym)
case ODOTTYPE, ODOTTYPE2:
- var f string
- f += exprfmt(n.Left, nprec)
+ n.Left.exprfmt(s, nprec)
if n.Right != nil {
- f += fmt.Sprintf(".(%v)", n.Right)
- return f
+ fmt.Fprintf(s, ".(%v)", n.Right)
+ return
}
- f += fmt.Sprintf(".(%v)", n.Type)
- return f
+ fmt.Fprintf(s, ".(%v)", n.Type)
case OINDEX, OINDEXMAP:
- return fmt.Sprintf("%s[%v]", exprfmt(n.Left, nprec), n.Right)
+ n.Left.exprfmt(s, nprec)
+ fmt.Fprintf(s, "[%v]", n.Right)
case OSLICE, OSLICESTR, OSLICEARR, OSLICE3, OSLICE3ARR:
- var buf bytes.Buffer
- buf.WriteString(exprfmt(n.Left, nprec))
- buf.WriteString("[")
+ n.Left.exprfmt(s, nprec)
+ fmt.Fprint(s, "[")
low, high, max := n.SliceBounds()
if low != nil {
- buf.WriteString(low.String())
+ fmt.Fprint(s, low.String())
}
- buf.WriteString(":")
+ fmt.Fprint(s, ":")
if high != nil {
- buf.WriteString(high.String())
+ fmt.Fprint(s, high.String())
}
if n.Op.IsSlice3() {
- buf.WriteString(":")
+ fmt.Fprint(s, ":")
if max != nil {
- buf.WriteString(max.String())
+ fmt.Fprint(s, max.String())
}
}
- buf.WriteString("]")
- return buf.String()
+ fmt.Fprint(s, "]")
case OCOPY, OCOMPLEX:
- return fmt.Sprintf("%#v(%v, %v)", n.Op, n.Left, n.Right)
+ fmt.Fprintf(s, "%#v(%v, %v)", n.Op, n.Left, n.Right)
case OCONV,
OCONVIFACE,
@@ -1342,12 +1333,14 @@ func exprfmt(n *Node, prec int) string {
OSTRARRAYRUNE,
ORUNESTR:
if n.Type == nil || n.Type.Sym == nil {
- return fmt.Sprintf("(%v)(%v)", n.Type, n.Left)
+ fmt.Fprintf(s, "(%v)(%v)", n.Type, n.Left)
+ return
}
if n.Left != nil {
- return fmt.Sprintf("%v(%v)", n.Type, n.Left)
+ fmt.Fprintf(s, "%v(%v)", n.Type, n.Left)
+ return
}
- return fmt.Sprintf("%v(%v)", n.Type, hconv(n.List, FmtComma))
+ fmt.Fprintf(s, "%v(%.v)", n.Type, n.List)
case OREAL,
OIMAG,
@@ -1360,37 +1353,43 @@ func exprfmt(n *Node, prec int) string {
ONEW,
OPANIC,
ORECOVER,
+ OALIGNOF,
+ OOFFSETOF,
+ OSIZEOF,
OPRINT,
OPRINTN:
if n.Left != nil {
- return fmt.Sprintf("%#v(%v)", n.Op, n.Left)
+ fmt.Fprintf(s, "%#v(%v)", n.Op, n.Left)
+ return
}
if n.Isddd {
- return fmt.Sprintf("%#v(%v...)", n.Op, hconv(n.List, FmtComma))
+ fmt.Fprintf(s, "%#v(%.v...)", n.Op, n.List)
+ return
}
- return fmt.Sprintf("%#v(%v)", n.Op, hconv(n.List, FmtComma))
+ fmt.Fprintf(s, "%#v(%.v)", n.Op, n.List)
case OCALL, OCALLFUNC, OCALLINTER, OCALLMETH, OGETG:
- var f string
- f += exprfmt(n.Left, nprec)
+ n.Left.exprfmt(s, nprec)
if n.Isddd {
- f += fmt.Sprintf("(%v...)", hconv(n.List, FmtComma))
- return f
+ fmt.Fprintf(s, "(%.v...)", n.List)
+ return
}
- f += fmt.Sprintf("(%v)", hconv(n.List, FmtComma))
- return f
+ fmt.Fprintf(s, "(%.v)", n.List)
case OMAKEMAP, OMAKECHAN, OMAKESLICE:
if n.List.Len() != 0 { // pre-typecheck
- return fmt.Sprintf("make(%v, %v)", n.Type, hconv(n.List, FmtComma))
+ fmt.Fprintf(s, "make(%v, %.v)", n.Type, n.List)
+ return
}
if n.Right != nil {
- return fmt.Sprintf("make(%v, %v, %v)", n.Type, n.Left, n.Right)
+ fmt.Fprintf(s, "make(%v, %v, %v)", n.Type, n.Left, n.Right)
+ return
}
if n.Left != nil && (n.Op == OMAKESLICE || !n.Left.Type.IsUntyped()) {
- return fmt.Sprintf("make(%v, %v)", n.Type, n.Left)
+ fmt.Fprintf(s, "make(%v, %v)", n.Type, n.Left)
+ return
}
- return fmt.Sprintf("make(%v)", n.Type)
+ fmt.Fprintf(s, "make(%v)", n.Type)
// Unary
case OPLUS,
@@ -1400,12 +1399,11 @@ func exprfmt(n *Node, prec int) string {
OIND,
ONOT,
ORECV:
- f := n.Op.GoString() // %#v
+ fmt.Fprint(s, n.Op.GoString()) // %#v
if n.Left.Op == n.Op {
- f += " "
+ fmt.Fprint(s, " ")
}
- f += exprfmt(n.Left, nprec+1)
- return f
+ n.Left.exprfmt(s, nprec+1)
// Binary
case OADD,
@@ -1428,175 +1426,161 @@ func exprfmt(n *Node, prec int) string {
OSEND,
OSUB,
OXOR:
- var f string
- f += exprfmt(n.Left, nprec)
-
- f += fmt.Sprintf(" %#v ", n.Op)
- f += exprfmt(n.Right, nprec+1)
- return f
+ n.Left.exprfmt(s, nprec)
+ fmt.Fprintf(s, " %#v ", n.Op)
+ n.Right.exprfmt(s, nprec+1)
case OADDSTR:
- var f string
i := 0
for _, n1 := range n.List.Slice() {
if i != 0 {
- f += " + "
+ fmt.Fprint(s, " + ")
}
- f += exprfmt(n1, nprec)
+ n1.exprfmt(s, nprec)
i++
}
- return f
-
case OCMPSTR, OCMPIFACE:
- var f string
- f += exprfmt(n.Left, nprec)
+ n.Left.exprfmt(s, nprec)
// TODO(marvin): Fix Node.EType type union.
- f += fmt.Sprintf(" %#v ", Op(n.Etype))
- f += exprfmt(n.Right, nprec+1)
- return f
+ fmt.Fprintf(s, " %#v ", Op(n.Etype))
+ n.Right.exprfmt(s, nprec+1)
- case ODCLCONST:
- // if exporting, DCLCONST should just be removed as its usage
- // has already been replaced with literals
- if fmtbody {
- return ""
- }
+ default:
+ fmt.Fprintf(s, "<node %v>", n.Op)
}
-
- return fmt.Sprintf("<node %v>", n.Op)
}
-func nodefmt(n *Node, flag FmtFlag) string {
+func (n *Node) nodefmt(s fmt.State, flag FmtFlag) {
t := n.Type
// we almost always want the original, except in export mode for literals
// this saves the importer some work, and avoids us having to redo some
// special casing for package unsafe
- if (fmtmode != FExp || n.Op != OLITERAL) && n.Orig != nil {
+ if n.Op != OLITERAL && n.Orig != nil {
n = n.Orig
}
if flag&FmtLong != 0 && t != nil {
if t.Etype == TNIL {
- return "nil"
+ fmt.Fprint(s, "nil")
} else {
- return fmt.Sprintf("%v (type %v)", n, t)
+ fmt.Fprintf(s, "%v (type %v)", n, t)
}
+ return
}
// TODO inlining produces expressions with ninits. we can't print these yet.
if opprec[n.Op] < 0 {
- return stmtfmt(n)
+ n.stmtfmt(s)
+ return
}
- return exprfmt(n, 0)
-}
-
-var dumpdepth int
-
-func indent(buf *bytes.Buffer) {
- buf.WriteString("\n")
- for i := 0; i < dumpdepth; i++ {
- buf.WriteString(". ")
- }
+ n.exprfmt(s, 0)
}
-func nodedump(n *Node, flag FmtFlag) string {
+func (n *Node) nodedump(s fmt.State, flag FmtFlag) {
if n == nil {
- return ""
+ return
}
recur := flag&FmtShort == 0
- var buf bytes.Buffer
if recur {
- indent(&buf)
+ indent(s)
if dumpdepth > 10 {
- buf.WriteString("...")
- return buf.String()
+ fmt.Fprint(s, "...")
+ return
}
if n.Ninit.Len() != 0 {
- fmt.Fprintf(&buf, "%v-init%v", n.Op, n.Ninit)
- indent(&buf)
+ fmt.Fprintf(s, "%v-init%v", n.Op, n.Ninit)
+ indent(s)
}
}
switch n.Op {
default:
- fmt.Fprintf(&buf, "%v%v", n.Op, jconv(n, 0))
+ fmt.Fprintf(s, "%v%j", n.Op, n)
- case OREGISTER, OINDREG:
- fmt.Fprintf(&buf, "%v-%v%v", n.Op, obj.Rconv(int(n.Reg)), jconv(n, 0))
+ case OINDREGSP:
+ fmt.Fprintf(s, "%v-SP%j", n.Op, n)
case OLITERAL:
- fmt.Fprintf(&buf, "%v-%v%v", n.Op, vconv(n.Val(), 0), jconv(n, 0))
+ fmt.Fprintf(s, "%v-%v%j", n.Op, n.Val(), n)
case ONAME, ONONAME:
if n.Sym != nil {
- fmt.Fprintf(&buf, "%v-%v%v", n.Op, n.Sym, jconv(n, 0))
+ fmt.Fprintf(s, "%v-%v%j", n.Op, n.Sym, n)
} else {
- fmt.Fprintf(&buf, "%v%v", n.Op, jconv(n, 0))
+ fmt.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(&buf)
- fmt.Fprintf(&buf, "%v-ntype%v", n.Op, n.Name.Param.Ntype)
+ indent(s)
+ fmt.Fprintf(s, "%v-ntype%v", n.Op, n.Name.Param.Ntype)
}
case OASOP:
- fmt.Fprintf(&buf, "%v-%v%v", n.Op, Op(n.Etype), jconv(n, 0))
+ fmt.Fprintf(s, "%v-%v%j", n.Op, Op(n.Etype), n)
case OTYPE:
- fmt.Fprintf(&buf, "%v %v%v type=%v", n.Op, n.Sym, jconv(n, 0), n.Type)
+ fmt.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(&buf)
- fmt.Fprintf(&buf, "%v-ntype%v", n.Op, n.Name.Param.Ntype)
+ indent(s)
+ fmt.Fprintf(s, "%v-ntype%v", n.Op, n.Name.Param.Ntype)
}
}
if n.Sym != nil && n.Op != ONAME {
- fmt.Fprintf(&buf, " %v", n.Sym)
+ fmt.Fprintf(s, " %v", n.Sym)
}
if n.Type != nil {
- fmt.Fprintf(&buf, " %v", n.Type)
+ fmt.Fprintf(s, " %v", n.Type)
}
if recur {
if n.Left != nil {
- buf.WriteString(Nconv(n.Left, 0))
+ fmt.Fprintf(s, "%v", n.Left)
}
if n.Right != nil {
- buf.WriteString(Nconv(n.Right, 0))
+ fmt.Fprintf(s, "%v", n.Right)
}
if n.List.Len() != 0 {
- indent(&buf)
- fmt.Fprintf(&buf, "%v-list%v", n.Op, n.List)
+ indent(s)
+ fmt.Fprintf(s, "%v-list%v", n.Op, n.List)
}
if n.Rlist.Len() != 0 {
- indent(&buf)
- fmt.Fprintf(&buf, "%v-rlist%v", n.Op, n.Rlist)
+ indent(s)
+ fmt.Fprintf(s, "%v-rlist%v", n.Op, n.Rlist)
}
if n.Nbody.Len() != 0 {
- indent(&buf)
- fmt.Fprintf(&buf, "%v-body%v", n.Op, n.Nbody)
+ indent(s)
+ fmt.Fprintf(s, "%v-body%v", n.Op, n.Nbody)
}
}
+}
+
+// "%S" suppresses qualifying with package
+func (s *Sym) Format(f fmt.State, verb rune) {
+ switch verb {
+ case 'v', 'S':
+ fmt.Fprint(f, s.sconv(fmtFlag(f, verb)))
- return buf.String()
+ default:
+ fmt.Fprintf(f, "%%!%c(*Sym=%p)", verb, s)
+ }
}
func (s *Sym) String() string {
- return sconv(s, 0)
+ return s.sconv(0)
}
-// Fmt "%S": syms
-// Flags: "%hS" suppresses qualifying with package
-func sconv(s *Sym, flag FmtFlag) string {
+// See #16897 before changing the implementation of sconv.
+func (s *Sym) sconv(flag FmtFlag) string {
if flag&FmtLong != 0 {
panic("linksymfmt")
}
@@ -1610,25 +1594,24 @@ func sconv(s *Sym, flag FmtFlag) string {
}
sf := flag
- sm, sb := setfmode(&flag)
- str := symfmt(s, flag)
+ sm := setfmode(&flag)
+ str := s.symfmt(flag)
flag = sf
fmtmode = sm
- fmtbody = sb
return str
}
func (t *Type) String() string {
- return Tconv(t, 0)
+ return t.tconv(0)
}
-func Fldconv(f *Field, flag FmtFlag) string {
+func fldconv(f *Field, flag FmtFlag) string {
if f == nil {
return "<T>"
}
sf := flag
- sm, sb := setfmode(&flag)
+ sm := setfmode(&flag)
if fmtmode == FTypeId && (sf&FmtUnsigned != 0) {
fmtpkgpfx++
@@ -1643,14 +1626,14 @@ 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 || fmtmode == FExp) && f.Nname != nil {
+ if fmtmode == FErr && f.Nname != nil {
if f.Nname.Orig != nil {
s = f.Nname.Orig.Sym
if s != nil && s.Name[0] == '~' {
if s.Name[1] == 'r' { // originally an unnamed result
s = nil
} else if s.Name[1] == 'b' { // originally the blank identifier _
- s = Lookup("_")
+ s = lookup("_")
}
}
} else {
@@ -1660,26 +1643,23 @@ func Fldconv(f *Field, flag FmtFlag) string {
if s != nil && f.Embedded == 0 {
if f.Funarg != FunargNone {
- name = Nconv(f.Nname, 0)
+ name = f.Nname.String()
} else if flag&FmtLong != 0 {
- name = sconv(s, FmtShort|FmtByte) // qualify non-exported names (used on structs, not on funarg)
- } else {
- name = sconv(s, 0)
- }
- } else if fmtmode == FExp {
- if f.Embedded != 0 && s.Pkg != nil && len(s.Pkg.Path) > 0 {
- name = fmt.Sprintf("@%q.?", s.Pkg.Path)
+ name = fmt.Sprintf("%0S", s)
+ if !exportname(name) && flag&FmtUnsigned == 0 {
+ name = s.String() // qualify non-exported names (used on structs, not on funarg)
+ }
} else {
- name = "?"
+ name = s.String()
}
}
}
var typ string
if f.Isddd {
- typ = "..." + Tconv(f.Type.Elem(), 0)
+ typ = fmt.Sprintf("...%v", f.Type.Elem())
} else {
- typ = Tconv(f.Type, 0)
+ typ = fmt.Sprintf("%v", f.Type)
}
str := typ
@@ -1687,12 +1667,7 @@ func Fldconv(f *Field, flag FmtFlag) string {
str = name + " " + typ
}
- // The fmtbody flag is intended to suppress escape analysis annotations
- // when printing a function type used in a function body.
- // (The escape analysis tags do not apply to func vars.)
- // But it must not suppress struct field tags.
- // See golang.org/issue/13777 and golang.org/issue/14331.
- if flag&FmtShort == 0 && (!fmtbody || f.Funarg == FunargNone) && f.Note != "" {
+ if flag&FmtShort == 0 && f.Funarg == FunargNone && f.Note != "" {
str += " " + strconv.Quote(f.Note)
}
@@ -1701,16 +1676,25 @@ func Fldconv(f *Field, flag FmtFlag) string {
}
flag = sf
- fmtbody = sb
fmtmode = sm
return str
}
-// Fmt "%T": types.
-// Flags: 'l' print definition, not name
-// 'h' omit 'func' and receiver from function types, short type names
-// 'u' package name, not prefix (FTypeId mode, sticky)
-func Tconv(t *Type, flag FmtFlag) string {
+// "%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) {
+ switch verb {
+ case 'v', 'S', 'L':
+ fmt.Fprint(s, t.tconv(fmtFlag(s, verb)))
+
+ default:
+ fmt.Fprintf(s, "%%!%c(*Type=%p)", verb, t)
+ }
+}
+
+// See #16897 before changing the implementation of tconv.
+func (t *Type) tconv(flag FmtFlag) string {
if t == nil {
return "<T>"
}
@@ -1721,7 +1705,7 @@ func Tconv(t *Type, flag FmtFlag) string {
t.Trecur++
sf := flag
- sm, sb := setfmode(&flag)
+ sm := setfmode(&flag)
if fmtmode == FTypeId && (sf&FmtUnsigned != 0) {
fmtpkgpfx++
@@ -1730,66 +1714,73 @@ func Tconv(t *Type, flag FmtFlag) string {
flag |= FmtUnsigned
}
- str := typefmt(t, flag)
+ str := t.typefmt(flag)
if fmtmode == FTypeId && (sf&FmtUnsigned != 0) {
fmtpkgpfx--
}
flag = sf
- fmtbody = sb
fmtmode = sm
t.Trecur--
return str
}
func (n *Node) String() string {
- return Nconv(n, 0)
+ return fmt.Sprint(n)
}
-// Fmt '%N': Nodes.
-// Flags: 'l' suffix with "(type %T)" where possible
-// '+h' in debug mode, don't recurse, no multiline output
-func Nconv(n *Node, flag FmtFlag) string {
+// "%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) {
if n == nil {
- return "<N>"
+ fmt.Fprint(s, "<N>")
+ return
}
+
sf := flag
- sm, sb := setfmode(&flag)
+ sm := setfmode(&flag)
- var str string
switch fmtmode {
- case FErr, FExp:
- str = nodefmt(n, flag)
+ case FErr:
+ n.nodefmt(s, flag)
case FDbg:
dumpdepth++
- str = nodedump(n, flag)
+ n.nodedump(s, flag)
dumpdepth--
default:
- Fatalf("unhandled %%N mode")
+ Fatalf("unhandled %%N mode: %d", fmtmode)
}
flag = sf
- fmtbody = sb
fmtmode = sm
- return str
+}
+
+func (l Nodes) Format(s fmt.State, verb rune) {
+ switch verb {
+ case 'v':
+ l.hconv(s, fmtFlag(s, verb))
+
+ default:
+ fmt.Fprintf(s, "%%!%c(Nodes)", verb)
+ }
}
func (n Nodes) String() string {
- return hconv(n, 0)
+ return fmt.Sprint(n)
}
-// Fmt '%H': Nodes.
-// Flags: all those of %N plus ',': separate with comma's instead of semicolons.
-func hconv(l Nodes, flag FmtFlag) 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 {
- return "<nil>"
+ fmt.Fprint(s, "<nil>")
+ return
}
sf := flag
- sm, sb := setfmode(&flag)
+ sm := setfmode(&flag)
sep := "; "
if fmtmode == FDbg {
sep = "\n"
@@ -1797,24 +1788,32 @@ func hconv(l Nodes, flag FmtFlag) string {
sep = ", "
}
- var buf bytes.Buffer
for i, n := range l.Slice() {
- buf.WriteString(Nconv(n, 0))
+ fmt.Fprint(s, n)
if i+1 < l.Len() {
- buf.WriteString(sep)
+ fmt.Fprint(s, sep)
}
}
flag = sf
- fmtbody = sb
fmtmode = sm
- return buf.String()
}
func dumplist(s string, l Nodes) {
- fmt.Printf("%s%v\n", s, hconv(l, FmtSign))
+ fmt.Printf("%s%+v\n", s, l)
}
func Dump(s string, n *Node) {
- fmt.Printf("%s [%p]%v\n", s, n, Nconv(n, FmtSign))
+ fmt.Printf("%s [%p]%+v\n", s, n, n)
+}
+
+// TODO(gri) make variable local somehow
+var dumpdepth int
+
+// indent prints indentation to s.
+func indent(s fmt.State) {
+ fmt.Fprint(s, "\n")
+ for i := 0; i < dumpdepth; i++ {
+ fmt.Fprint(s, ". ")
+ }
}
diff --git a/src/cmd/compile/internal/gc/gen.go b/src/cmd/compile/internal/gc/gen.go
index fc0003d..c3d2c44 100644
--- a/src/cmd/compile/internal/gc/gen.go
+++ b/src/cmd/compile/internal/gc/gen.go
@@ -6,14 +6,7 @@
package gc
-import (
- "cmd/internal/obj"
- "cmd/internal/sys"
- "fmt"
-)
-
-// TODO: labellist should become part of a "compilation state" for functions.
-var labellist []*Label
+import "fmt"
func Sysfunc(name string) *Node {
n := newname(Pkglookup(name, Runtimepkg))
@@ -103,30 +96,13 @@ func (n *Node) isParamHeapCopy() bool {
return n.Op == ONAME && n.Class == PAUTOHEAP && n.Name.Param.Stackcopy != nil
}
-// paramClass reports the parameter class (PPARAM or PPARAMOUT)
-// of the node, which may be an unmoved on-stack parameter
-// or the on-heap or on-stack copy of a parameter that moved to the heap.
-// If the node is not a parameter, paramClass returns Pxxx.
-func (n *Node) paramClass() Class {
- if n.Op != ONAME {
- return Pxxx
- }
- if n.Class == PPARAM || n.Class == PPARAMOUT {
- return n.Class
- }
- if n.isParamHeapCopy() {
- return n.Name.Param.Stackcopy.Class
- }
- return Pxxx
-}
-
// moveToHeap records the parameter or local variable n as moved to the heap.
func moveToHeap(n *Node) {
if Debug['r'] != 0 {
Dump("MOVE", n)
}
if compiling_runtime {
- Yyerror("%v escapes to heap, not allowed in runtime.", n)
+ yyerror("%v escapes to heap, not allowed in runtime.", n)
}
if n.Class == PAUTOHEAP {
Dump("n", n)
@@ -135,10 +111,15 @@ func moveToHeap(n *Node) {
// 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 := 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.
@@ -151,15 +132,12 @@ func moveToHeap(n *Node) {
// 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 := nod(ONAME, nil, nil)
stackcopy.Sym = n.Sym
stackcopy.Type = n.Type
stackcopy.Xoffset = n.Xoffset
stackcopy.Class = n.Class
stackcopy.Name.Heapaddr = heapaddr
- if n.Class == PPARAM {
- stackcopy.SetNotLiveAtEnd(true)
- }
if n.Class == PPARAMOUT {
// Make sure the pointer to the heap copy is kept live throughout the function.
// The function could panic at any point, and then a defer could recover.
@@ -203,492 +181,27 @@ func moveToHeap(n *Node) {
}
}
-func clearlabels() {
- for _, l := range labellist {
- l.Sym.Label = nil
- }
- labellist = labellist[:0]
-}
-
-func newlab(n *Node) *Label {
- s := n.Left.Sym
- lab := s.Label
- if lab == nil {
- lab = new(Label)
- lab.Sym = s
- s.Label = lab
- labellist = append(labellist, lab)
- }
-
- if n.Op == OLABEL {
- if lab.Def != nil {
- Yyerror("label %v already defined at %v", s, lab.Def.Line())
- } else {
- lab.Def = n
- }
- } else {
- lab.Use = append(lab.Use, n)
- }
-
- return lab
-}
-
-// There is a copy of checkgoto in the new SSA backend.
-// Please keep them in sync.
-func checkgoto(from *Node, to *Node) {
- if from.Sym == to.Sym {
- return
- }
-
- nf := 0
- for fs := from.Sym; fs != nil; fs = fs.Link {
- nf++
- }
- nt := 0
- for fs := to.Sym; fs != nil; fs = fs.Link {
- nt++
- }
- fs := from.Sym
- for ; nf > nt; nf-- {
- fs = fs.Link
- }
- if fs != to.Sym {
- lno := lineno
- setlineno(from)
-
- // decide what to complain about.
- // prefer to complain about 'into block' over declarations,
- // so scan backward to find most recent block or else dcl.
- var block *Sym
-
- var dcl *Sym
- ts := to.Sym
- for ; nt > nf; nt-- {
- if ts.Pkg == nil {
- block = ts
- } else {
- dcl = ts
- }
- ts = ts.Link
- }
-
- for ts != fs {
- if ts.Pkg == nil {
- block = ts
- } else {
- dcl = ts
- }
- ts = ts.Link
- fs = fs.Link
- }
-
- if block != nil {
- Yyerror("goto %v jumps into block starting at %v", from.Left.Sym, linestr(block.Lastlineno))
- } else {
- Yyerror("goto %v jumps over declaration of %v at %v", from.Left.Sym, dcl, linestr(dcl.Lastlineno))
- }
- lineno = lno
- }
-}
-
-func stmtlabel(n *Node) *Label {
- if n.Sym != nil {
- lab := n.Sym.Label
- if lab != nil {
- if lab.Def != nil {
- if lab.Def.Name.Defn == n {
- return lab
- }
- }
- }
- }
- return nil
-}
-
-// compile statements
-func Genlist(l Nodes) {
- for _, n := range l.Slice() {
- gen(n)
- }
-}
-
-// generate code to start new proc running call n.
-func cgen_proc(n *Node, proc int) {
- switch n.Left.Op {
- default:
- Fatalf("cgen_proc: unknown call %v", n.Left.Op)
-
- case OCALLMETH:
- cgen_callmeth(n.Left, proc)
-
- case OCALLINTER:
- cgen_callinter(n.Left, nil, proc)
-
- case OCALLFUNC:
- cgen_call(n.Left, proc)
- }
-}
-
-// generate declaration.
-// have to allocate heap copy
-// for escaped variables.
-func cgen_dcl(n *Node) {
- if Debug['g'] != 0 {
- Dump("\ncgen-dcl", n)
- }
- if n.Op != ONAME {
- Dump("cgen_dcl", n)
- Fatalf("cgen_dcl")
- }
-
- if n.Class == PAUTOHEAP {
- Fatalf("cgen_dcl %v", n)
- }
-}
-
-// generate discard of value
-func cgen_discard(nr *Node) {
- if nr == nil {
- return
- }
-
- switch nr.Op {
- case ONAME:
- if nr.Class != PAUTOHEAP && nr.Class != PEXTERN && nr.Class != PFUNC {
- gused(nr)
- }
-
- // unary
- case OADD,
- OAND,
- ODIV,
- OEQ,
- OGE,
- OGT,
- OLE,
- OLSH,
- OLT,
- OMOD,
- OMUL,
- ONE,
- OOR,
- ORSH,
- OSUB,
- OXOR:
- cgen_discard(nr.Left)
-
- cgen_discard(nr.Right)
-
- // binary
- case OCAP,
- OCOM,
- OLEN,
- OMINUS,
- ONOT,
- OPLUS:
- cgen_discard(nr.Left)
-
- case OIND:
- Cgen_checknil(nr.Left)
-
- // special enough to just evaluate
- default:
- var tmp Node
- Tempname(&tmp, nr.Type)
-
- Cgen_as(&tmp, nr)
- gused(&tmp)
- }
-}
-
-// clearslim generates code to zero a slim node.
-func Clearslim(n *Node) {
- var z Node
- z.Op = OLITERAL
- z.Type = n.Type
- z.Addable = true
-
- switch Simtype[n.Type.Etype] {
- case TCOMPLEX64, TCOMPLEX128:
- z.SetVal(Val{new(Mpcplx)})
- z.Val().U.(*Mpcplx).Real.SetFloat64(0.0)
- z.Val().U.(*Mpcplx).Imag.SetFloat64(0.0)
-
- case TFLOAT32, TFLOAT64:
- var zero Mpflt
- zero.SetFloat64(0.0)
- z.SetVal(Val{&zero})
-
- case TPTR32, TPTR64, TCHAN, TMAP:
- z.SetVal(Val{new(NilVal)})
-
- case TBOOL:
- z.SetVal(Val{false})
-
- case TINT8,
- TINT16,
- TINT32,
- TINT64,
- TUINT8,
- TUINT16,
- TUINT32,
- TUINT64:
- z.SetVal(Val{new(Mpint)})
- z.Val().U.(*Mpint).SetInt64(0)
-
- default:
- Fatalf("clearslim called on type %v", n.Type)
- }
-
- ullmancalc(&z)
- Cgen(&z, n)
-}
-
-// generate:
-// res = iface{typ, data}
-// n->left is typ
-// n->right is data
-func Cgen_eface(n *Node, res *Node) {
- // the right node of an eface may contain function calls that uses res as an argument,
- // so it's important that it is done first
-
- tmp := temp(Types[Tptr])
- Cgen(n.Right, tmp)
-
- Gvardef(res)
-
- dst := *res
- dst.Type = Types[Tptr]
- dst.Xoffset += int64(Widthptr)
- Cgen(tmp, &dst)
-
- dst.Xoffset -= int64(Widthptr)
- Cgen(n.Left, &dst)
-}
-
-// generate one of:
-// res, resok = x.(T)
-// res = x.(T) (when resok == nil)
-// n.Left is x
-// n.Type is T
-func cgen_dottype(n *Node, res, resok *Node, wb bool) {
- if Debug_typeassert > 0 {
- Warn("type assertion inlined")
- }
- // iface := n.Left
- // r1 := iword(iface)
- // if n.Left is non-empty interface {
- // r1 = *r1
- // }
- // if r1 == T {
- // res = idata(iface)
- // resok = true
- // } else {
- // assert[EI]2T(x, T, nil) // (when resok == nil; does not return)
- // resok = false // (when resok != nil)
- // }
- //
- var iface Node
- Igen(n.Left, &iface, res)
- var r1, r2 Node
- byteptr := Ptrto(Types[TUINT8]) // type used in runtime prototypes for runtime type (*byte)
- Regalloc(&r1, byteptr, nil)
- iface.Type = byteptr
- Cgen(&iface, &r1)
- if !n.Left.Type.IsEmptyInterface() {
- // Holding itab, want concrete type in second word.
- p := Thearch.Ginscmp(OEQ, byteptr, &r1, Nodintconst(0), -1)
- r2 = r1
- r2.Op = OINDREG
- r2.Xoffset = int64(Widthptr)
- Cgen(&r2, &r1)
- Patch(p, Pc)
- }
- Regalloc(&r2, byteptr, nil)
- Cgen(typename(n.Type), &r2)
- p := Thearch.Ginscmp(ONE, byteptr, &r1, &r2, -1)
- Regfree(&r2) // not needed for success path; reclaimed on one failure path
- iface.Xoffset += int64(Widthptr)
- Cgen(&iface, &r1)
- Regfree(&iface)
-
- if resok == nil {
- r1.Type = res.Type
- cgen_wb(&r1, res, wb)
- q := Gbranch(obj.AJMP, nil, 0)
- Patch(p, Pc)
- Regrealloc(&r2) // reclaim from above, for this failure path
- fn := syslook("panicdottype")
- dowidth(fn.Type)
- call := Nod(OCALLFUNC, fn, nil)
- r1.Type = byteptr
- r2.Type = byteptr
- call.List.Set([]*Node{&r1, &r2, typename(n.Left.Type)})
- call.List.Set(ascompatte(OCALLFUNC, call, false, fn.Type.Params(), call.List.Slice(), 0, nil))
- gen(call)
- Regfree(&r1)
- Regfree(&r2)
- Thearch.Gins(obj.AUNDEF, nil, nil)
- Patch(q, Pc)
- } else {
- // This half is handling the res, resok = x.(T) case,
- // which is called from gen, not cgen, and is consequently fussier
- // about blank assignments. We have to avoid calling cgen for those.
- r1.Type = res.Type
- if !isblank(res) {
- cgen_wb(&r1, res, wb)
- }
- Regfree(&r1)
- if !isblank(resok) {
- Cgen(Nodbool(true), resok)
- }
- q := Gbranch(obj.AJMP, nil, 0)
- Patch(p, Pc)
- if !isblank(res) {
- n := nodnil()
- n.Type = res.Type
- Cgen(n, res)
- }
- if !isblank(resok) {
- Cgen(Nodbool(false), resok)
- }
- Patch(q, Pc)
- }
-}
-
-// generate:
-// res, resok = x.(T)
-// n.Left is x
-// n.Type is T
-func Cgen_As2dottype(n, res, resok *Node) {
- if Debug_typeassert > 0 {
- Warn("type assertion inlined")
- }
- // iface := n.Left
- // r1 := iword(iface)
- // if n.Left is non-empty interface {
- // r1 = *r1
- // }
- // if r1 == T {
- // res = idata(iface)
- // resok = true
- // } else {
- // res = nil
- // resok = false
- // }
- //
- var iface Node
- Igen(n.Left, &iface, nil)
- var r1, r2 Node
- byteptr := Ptrto(Types[TUINT8]) // type used in runtime prototypes for runtime type (*byte)
- Regalloc(&r1, byteptr, res)
- iface.Type = byteptr
- Cgen(&iface, &r1)
- if !n.Left.Type.IsEmptyInterface() {
- // Holding itab, want concrete type in second word.
- p := Thearch.Ginscmp(OEQ, byteptr, &r1, Nodintconst(0), -1)
- r2 = r1
- r2.Op = OINDREG
- r2.Xoffset = int64(Widthptr)
- Cgen(&r2, &r1)
- Patch(p, Pc)
- }
- Regalloc(&r2, byteptr, nil)
- Cgen(typename(n.Type), &r2)
- p := Thearch.Ginscmp(ONE, byteptr, &r1, &r2, -1)
- iface.Type = n.Type
- iface.Xoffset += int64(Widthptr)
- Cgen(&iface, &r1)
- if iface.Op != 0 {
- Regfree(&iface)
- }
- Cgen(&r1, res)
- q := Gbranch(obj.AJMP, nil, 0)
- Patch(p, Pc)
-
- fn := syslook("panicdottype")
- dowidth(fn.Type)
- call := Nod(OCALLFUNC, fn, nil)
- call.List.Set([]*Node{&r1, &r2, typename(n.Left.Type)})
- call.List.Set(ascompatte(OCALLFUNC, call, false, fn.Type.Params(), call.List.Slice(), 0, nil))
- gen(call)
- Regfree(&r1)
- Regfree(&r2)
- Thearch.Gins(obj.AUNDEF, nil, nil)
- Patch(q, Pc)
-}
-
-// gather series of offsets
-// >=0 is direct addressed field
-// <0 is pointer to next field (+1)
-func Dotoffset(n *Node, oary []int64, nn **Node) int {
- var i int
-
- switch n.Op {
- case ODOT:
- if n.Xoffset == BADWIDTH {
- Dump("bad width in dotoffset", n)
- Fatalf("bad width in dotoffset")
- }
-
- i = Dotoffset(n.Left, oary, nn)
- if i > 0 {
- if oary[i-1] >= 0 {
- oary[i-1] += n.Xoffset
- } else {
- oary[i-1] -= n.Xoffset
- }
- break
- }
-
- if i < 10 {
- oary[i] = n.Xoffset
- i++
- }
-
- case ODOTPTR:
- if n.Xoffset == BADWIDTH {
- Dump("bad width in dotoffset", n)
- Fatalf("bad width in dotoffset")
- }
-
- i = Dotoffset(n.Left, oary, nn)
- if i < 10 {
- oary[i] = -(n.Xoffset + 1)
- i++
- }
-
- default:
- *nn = n
- return 0
- }
-
- if i >= 10 {
- *nn = nil
- }
- return i
-}
-
-// make a new off the books
-func Tempname(nn *Node, t *Type) {
+// make a new Node off the books
+func tempname(nn *Node, t *Type) {
if Curfn == nil {
Fatalf("no curfn for tempname")
}
if Curfn.Func.Closure != nil && Curfn.Op == OCLOSURE {
- Dump("Tempname", Curfn)
+ Dump("tempname", Curfn)
Fatalf("adding tempname to wrong closure function")
}
if t == nil {
- Yyerror("tempname called with nil type")
+ yyerror("tempname called with nil type")
t = Types[TINT32]
}
// give each tmp a different name so that there
- // a chance to registerizer them
- s := LookupN("autotmp_", statuniqgen)
+ // 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 := nod(ONAME, nil, nil)
n.Sym = s
s.Def = n
n.Type = t
@@ -697,6 +210,7 @@ func Tempname(nn *Node, t *Type) {
n.Ullman = 1
n.Esc = EscNever
n.Name.Curfn = Curfn
+ n.Name.AutoTemp = true
Curfn.Func.Dcl = append(Curfn.Func.Dcl, n)
dowidth(t)
@@ -706,620 +220,7 @@ func Tempname(nn *Node, t *Type) {
func temp(t *Type) *Node {
var n Node
- Tempname(&n, t)
+ tempname(&n, t)
n.Sym.Def.Used = true
return n.Orig
}
-
-func gen(n *Node) {
- //dump("gen", n);
-
- lno := setlineno(n)
-
- wasregalloc := Anyregalloc()
-
- if n == nil {
- goto ret
- }
-
- if n.Ninit.Len() > 0 {
- Genlist(n.Ninit)
- }
-
- setlineno(n)
-
- switch n.Op {
- default:
- Fatalf("gen: unknown op %v", Nconv(n, FmtShort|FmtSign))
-
- case OCASE,
- OFALL,
- OXCASE,
- OXFALL,
- ODCLCONST,
- ODCLFUNC,
- ODCLTYPE:
- break
-
- case OEMPTY:
- break
-
- case OBLOCK:
- Genlist(n.List)
-
- case OLABEL:
- if isblanksym(n.Left.Sym) {
- break
- }
-
- lab := newlab(n)
-
- // if there are pending gotos, resolve them all to the current pc.
- var p2 *obj.Prog
- for p1 := lab.Gotopc; p1 != nil; p1 = p2 {
- p2 = unpatch(p1)
- Patch(p1, Pc)
- }
-
- lab.Gotopc = nil
- if lab.Labelpc == nil {
- lab.Labelpc = Pc
- }
-
- if n.Name.Defn != nil {
- switch n.Name.Defn.Op {
- // so stmtlabel can find the label
- case OFOR, OSWITCH, OSELECT:
- n.Name.Defn.Sym = lab.Sym
- }
- }
-
- // if label is defined, emit jump to it.
- // otherwise save list of pending gotos in lab->gotopc.
- // the list is linked through the normal jump target field
- // to avoid a second list. (the jumps are actually still
- // valid code, since they're just going to another goto
- // to the same label. we'll unwind it when we learn the pc
- // of the label in the OLABEL case above.)
- case OGOTO:
- lab := newlab(n)
-
- if lab.Labelpc != nil {
- gjmp(lab.Labelpc)
- } else {
- lab.Gotopc = gjmp(lab.Gotopc)
- }
-
- case OBREAK:
- if n.Left != nil {
- lab := n.Left.Sym.Label
- if lab == nil {
- Yyerror("break label not defined: %v", n.Left.Sym)
- break
- }
-
- lab.Used = true
- if lab.Breakpc == nil {
- Yyerror("invalid break label %v", n.Left.Sym)
- break
- }
-
- gjmp(lab.Breakpc)
- break
- }
-
- if breakpc == nil {
- Yyerror("break is not in a loop")
- break
- }
-
- gjmp(breakpc)
-
- case OCONTINUE:
- if n.Left != nil {
- lab := n.Left.Sym.Label
- if lab == nil {
- Yyerror("continue label not defined: %v", n.Left.Sym)
- break
- }
-
- lab.Used = true
- if lab.Continpc == nil {
- Yyerror("invalid continue label %v", n.Left.Sym)
- break
- }
-
- gjmp(lab.Continpc)
- break
- }
-
- if continpc == nil {
- Yyerror("continue is not in a loop")
- break
- }
-
- gjmp(continpc)
-
- case OFOR:
- sbreak := breakpc
- p1 := gjmp(nil) // goto test
- breakpc = gjmp(nil) // break: goto done
- scontin := continpc
- continpc = Pc
-
- // define break and continue labels
- lab := stmtlabel(n)
- if lab != nil {
- lab.Breakpc = breakpc
- lab.Continpc = continpc
- }
-
- gen(n.Right) // contin: incr
- Patch(p1, Pc) // test:
- Bgen(n.Left, false, -1, breakpc) // if(!test) goto break
- Genlist(n.Nbody) // body
- gjmp(continpc)
- Patch(breakpc, Pc) // done:
- continpc = scontin
- breakpc = sbreak
- if lab != nil {
- lab.Breakpc = nil
- lab.Continpc = nil
- }
-
- case OIF:
- p1 := gjmp(nil) // goto test
- p2 := gjmp(nil) // p2: goto else
- Patch(p1, Pc) // test:
- Bgen(n.Left, false, int(-n.Likely), p2) // if(!test) goto p2
- Genlist(n.Nbody) // then
- p3 := gjmp(nil) // goto done
- Patch(p2, Pc) // else:
- Genlist(n.Rlist) // else
- Patch(p3, Pc) // done:
-
- case OSWITCH:
- sbreak := breakpc
- p1 := gjmp(nil) // goto test
- breakpc = gjmp(nil) // break: goto done
-
- // define break label
- lab := stmtlabel(n)
- if lab != nil {
- lab.Breakpc = breakpc
- }
-
- Patch(p1, Pc) // test:
- Genlist(n.Nbody) // switch(test) body
- Patch(breakpc, Pc) // done:
- breakpc = sbreak
- if lab != nil {
- lab.Breakpc = nil
- }
-
- case OSELECT:
- sbreak := breakpc
- p1 := gjmp(nil) // goto test
- breakpc = gjmp(nil) // break: goto done
-
- // define break label
- lab := stmtlabel(n)
- if lab != nil {
- lab.Breakpc = breakpc
- }
-
- Patch(p1, Pc) // test:
- Genlist(n.Nbody) // select() body
- Patch(breakpc, Pc) // done:
- breakpc = sbreak
- if lab != nil {
- lab.Breakpc = nil
- }
-
- case ODCL:
- cgen_dcl(n.Left)
-
- case OAS:
- if gen_as_init(n, false) {
- break
- }
- Cgen_as(n.Left, n.Right)
-
- case OASWB:
- Cgen_as_wb(n.Left, n.Right, true)
-
- case OAS2DOTTYPE:
- cgen_dottype(n.Rlist.First(), n.List.First(), n.List.Second(), needwritebarrier(n.List.First(), n.Rlist.First()))
-
- case OCALLMETH:
- cgen_callmeth(n, 0)
-
- case OCALLINTER:
- cgen_callinter(n, nil, 0)
-
- case OCALLFUNC:
- cgen_call(n, 0)
-
- case OPROC:
- cgen_proc(n, 1)
-
- case ODEFER:
- cgen_proc(n, 2)
-
- case ORETURN, ORETJMP:
- cgen_ret(n)
-
- // Function calls turned into compiler intrinsics.
- // At top level, can just ignore the call and make sure to preserve side effects in the argument, if any.
- case OGETG:
- // nothing
- case OSQRT:
- cgen_discard(n.Left)
-
- case OCHECKNIL:
- Cgen_checknil(n.Left)
-
- case OVARKILL:
- Gvarkill(n.Left)
-
- case OVARLIVE:
- Gvarlive(n.Left)
- }
-
-ret:
- if Anyregalloc() != wasregalloc {
- Dump("node", n)
- Fatalf("registers left allocated")
- }
-
- lineno = lno
-}
-
-func Cgen_as(nl, nr *Node) {
- Cgen_as_wb(nl, nr, false)
-}
-
-func Cgen_as_wb(nl, nr *Node, wb bool) {
- if Debug['g'] != 0 {
- op := "cgen_as"
- if wb {
- op = "cgen_as_wb"
- }
- Dump(op, nl)
- Dump(op+" = ", nr)
- }
-
- for nr != nil && nr.Op == OCONVNOP {
- nr = nr.Left
- }
-
- if nl == nil || isblank(nl) {
- cgen_discard(nr)
- return
- }
-
- if nr == nil || iszero(nr) {
- tl := nl.Type
- if tl == nil {
- return
- }
- if Isfat(tl) {
- if nl.Op == ONAME {
- Gvardef(nl)
- }
- Thearch.Clearfat(nl)
- return
- }
-
- Clearslim(nl)
- return
- }
-
- tl := nl.Type
- if tl == nil {
- return
- }
-
- cgen_wb(nr, nl, wb)
-}
-
-func cgen_callmeth(n *Node, proc int) {
- // generate a rewrite in n2 for the method call
- // (p.f)(...) goes to (f)(p,...)
-
- l := n.Left
-
- if l.Op != ODOTMETH {
- Fatalf("cgen_callmeth: not dotmethod: %v", l)
- }
-
- n2 := *n
- n2.Op = OCALLFUNC
- n2.Left = newname(l.Sym)
- n2.Left.Type = l.Type
-
- if n2.Left.Op == ONAME {
- n2.Left.Class = PFUNC
- }
- cgen_call(&n2, proc)
-}
-
-// CgenTemp creates a temporary node, assigns n to it, and returns it.
-func CgenTemp(n *Node) *Node {
- var tmp Node
- Tempname(&tmp, n.Type)
- Cgen(n, &tmp)
- return &tmp
-}
-
-func checklabels() {
- for _, lab := range labellist {
- if lab.Def == nil {
- for _, n := range lab.Use {
- yyerrorl(n.Lineno, "label %v not defined", lab.Sym)
- }
- continue
- }
-
- if lab.Use == nil && !lab.Used {
- yyerrorl(lab.Def.Lineno, "label %v defined and not used", lab.Sym)
- continue
- }
-
- if lab.Gotopc != nil {
- Fatalf("label %v never resolved", lab.Sym)
- }
- for _, n := range lab.Use {
- checkgoto(n, lab.Def)
- }
- }
-}
-
-// Componentgen copies a composite value by moving its individual components.
-// Slices, strings and interfaces are supported. Small structs or arrays with
-// elements of basic type are also supported.
-// nr is nil when assigning a zero value.
-func Componentgen(nr, nl *Node) bool {
- return componentgen_wb(nr, nl, false)
-}
-
-// componentgen_wb is like componentgen but if wb==true emits write barriers for pointer updates.
-func componentgen_wb(nr, nl *Node, wb bool) bool {
- // Don't generate any code for complete copy of a variable into itself.
- // It's useless, and the VARDEF will incorrectly mark the old value as dead.
- // (This check assumes that the arguments passed to componentgen did not
- // themselves come from Igen, or else we could have Op==ONAME but
- // with a Type and Xoffset describing an individual field, not the entire
- // variable.)
- if nl.Op == ONAME && nl == nr {
- return true
- }
-
- // Count number of moves required to move components.
- // If using write barrier, can only emit one pointer.
- // TODO(rsc): Allow more pointers, for reflect.Value.
- const maxMoves = 8
- n := 0
- numPtr := 0
- visitComponents(nl.Type, 0, func(t *Type, offset int64) bool {
- n++
- if Simtype[t.Etype] == Tptr && t != itable {
- numPtr++
- }
- return n <= maxMoves && (!wb || numPtr <= 1)
- })
- if n > maxMoves || wb && numPtr > 1 {
- return false
- }
-
- // Must call emitVardef after evaluating rhs but before writing to lhs.
- emitVardef := func() {
- // Emit vardef if needed.
- if nl.Op == ONAME {
- switch nl.Type.Etype {
- case TARRAY, TSLICE, TSTRING, TINTER, TSTRUCT:
- Gvardef(nl)
- }
- }
- }
-
- isConstString := Isconst(nr, CTSTR)
-
- if !cadable(nl) && nr != nil && !cadable(nr) && !isConstString {
- return false
- }
-
- var nodl Node
- if cadable(nl) {
- nodl = *nl
- } else {
- if nr != nil && !cadable(nr) && !isConstString {
- return false
- }
- if nr == nil || isConstString || nl.Ullman >= nr.Ullman {
- Igen(nl, &nodl, nil)
- defer Regfree(&nodl)
- }
- }
- lbase := nodl.Xoffset
-
- // Special case: zeroing.
- var nodr Node
- if nr == nil {
- // When zeroing, prepare a register containing zero.
- // TODO(rsc): Check that this is actually generating the best code.
- if Thearch.REGZERO != 0 {
- // cpu has a dedicated zero register
- Nodreg(&nodr, Types[TUINT], Thearch.REGZERO)
- } else {
- // no dedicated zero register
- var zero Node
- Nodconst(&zero, nl.Type, 0)
- Regalloc(&nodr, Types[TUINT], nil)
- Thearch.Gmove(&zero, &nodr)
- defer Regfree(&nodr)
- }
-
- emitVardef()
- visitComponents(nl.Type, 0, func(t *Type, offset int64) bool {
- nodl.Type = t
- nodl.Xoffset = lbase + offset
- nodr.Type = t
- if t.IsFloat() {
- // TODO(rsc): Cache zero register like we do for integers?
- Clearslim(&nodl)
- } else {
- Thearch.Gmove(&nodr, &nodl)
- }
- return true
- })
- return true
- }
-
- // Special case: assignment of string constant.
- if isConstString {
- emitVardef()
-
- // base
- nodl.Type = Ptrto(Types[TUINT8])
- Regalloc(&nodr, Types[Tptr], nil)
- p := Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), nil, &nodr)
- Datastring(nr.Val().U.(string), &p.From)
- p.From.Type = obj.TYPE_ADDR
- Thearch.Gmove(&nodr, &nodl)
- Regfree(&nodr)
-
- // length
- nodl.Type = Types[Simtype[TUINT]]
- nodl.Xoffset += int64(Array_nel) - int64(Array_array)
- Nodconst(&nodr, nodl.Type, int64(len(nr.Val().U.(string))))
- Thearch.Gmove(&nodr, &nodl)
- return true
- }
-
- // General case: copy nl = nr.
- nodr = *nr
- if !cadable(nr) {
- if nr.Ullman >= UINF && nodl.Op == OINDREG {
- Fatalf("miscompile")
- }
- Igen(nr, &nodr, nil)
- defer Regfree(&nodr)
- }
- rbase := nodr.Xoffset
-
- if nodl.Op == 0 {
- Igen(nl, &nodl, nil)
- defer Regfree(&nodl)
- lbase = nodl.Xoffset
- }
-
- emitVardef()
- var (
- ptrType *Type
- ptrOffset int64
- )
- visitComponents(nl.Type, 0, func(t *Type, offset int64) bool {
- if wb && Simtype[t.Etype] == Tptr && t != itable {
- if ptrType != nil {
- Fatalf("componentgen_wb %v", Tconv(nl.Type, 0))
- }
- ptrType = t
- ptrOffset = offset
- return true
- }
- nodl.Type = t
- nodl.Xoffset = lbase + offset
- nodr.Type = t
- nodr.Xoffset = rbase + offset
- Thearch.Gmove(&nodr, &nodl)
- return true
- })
- if ptrType != nil {
- nodl.Type = ptrType
- nodl.Xoffset = lbase + ptrOffset
- nodr.Type = ptrType
- nodr.Xoffset = rbase + ptrOffset
- cgen_wbptr(&nodr, &nodl)
- }
- return true
-}
-
-// visitComponents walks the individual components of the type t,
-// walking into array elements, struct fields, the real and imaginary
-// parts of complex numbers, and on 32-bit systems the high and
-// low halves of 64-bit integers.
-// It calls f for each such component, passing the component (aka element)
-// type and memory offset, assuming t starts at startOffset.
-// If f ever returns false, visitComponents returns false without any more
-// calls to f. Otherwise visitComponents returns true.
-func visitComponents(t *Type, startOffset int64, f func(elem *Type, elemOffset int64) bool) bool {
- switch t.Etype {
- case TINT64:
- if Widthreg == 8 {
- break
- }
- // NOTE: Assuming little endian (signed top half at offset 4).
- // We don't have any 32-bit big-endian systems.
- if !Thearch.LinkArch.InFamily(sys.ARM, sys.I386) {
- Fatalf("unknown 32-bit architecture")
- }
- return f(Types[TUINT32], startOffset) &&
- f(Types[TINT32], startOffset+4)
-
- case TUINT64:
- if Widthreg == 8 {
- break
- }
- return f(Types[TUINT32], startOffset) &&
- f(Types[TUINT32], startOffset+4)
-
- case TCOMPLEX64:
- return f(Types[TFLOAT32], startOffset) &&
- f(Types[TFLOAT32], startOffset+4)
-
- case TCOMPLEX128:
- return f(Types[TFLOAT64], startOffset) &&
- f(Types[TFLOAT64], startOffset+8)
-
- case TINTER:
- return f(itable, startOffset) &&
- f(Ptrto(Types[TUINT8]), startOffset+int64(Widthptr))
-
- case TSTRING:
- return f(Ptrto(Types[TUINT8]), startOffset) &&
- f(Types[Simtype[TUINT]], startOffset+int64(Widthptr))
-
- case TSLICE:
- return f(Ptrto(t.Elem()), startOffset+int64(Array_array)) &&
- f(Types[Simtype[TUINT]], startOffset+int64(Array_nel)) &&
- f(Types[Simtype[TUINT]], startOffset+int64(Array_cap))
-
- case TARRAY:
- // Short-circuit [1e6]struct{}.
- if t.Elem().Width == 0 {
- return true
- }
-
- for i := int64(0); i < t.NumElem(); i++ {
- if !visitComponents(t.Elem(), startOffset+i*t.Elem().Width, f) {
- return false
- }
- }
- return true
-
- case TSTRUCT:
- for _, field := range t.Fields().Slice() {
- if !visitComponents(field.Type, startOffset+field.Offset, f) {
- return false
- }
- }
- return true
- }
- return f(t, startOffset)
-}
-
-func cadable(n *Node) bool {
- // Note: Not sure why you can have n.Op == ONAME without n.Addable, but you can.
- return n.Addable && n.Op == ONAME
-}
diff --git a/src/cmd/compile/internal/gc/global_test.go b/src/cmd/compile/internal/gc/global_test.go
index f0139e7..857cf96 100644
--- a/src/cmd/compile/internal/gc/global_test.go
+++ b/src/cmd/compile/internal/gc/global_test.go
@@ -47,14 +47,14 @@ func main() {
dst := filepath.Join(dir, "test")
// Compile source.
- cmd := exec.Command("go", "build", "-o", dst, src)
+ cmd := exec.Command(testenv.GoToolPath(t), "build", "-o", dst, src)
out, err := cmd.CombinedOutput()
if err != nil {
log.Fatalf("could not build target: %v", err)
}
// Check destination to see if scanf code was included.
- cmd = exec.Command("go", "tool", "nm", dst)
+ cmd = exec.Command(testenv.GoToolPath(t), "tool", "nm", dst)
out, err = cmd.CombinedOutput()
if err != nil {
log.Fatalf("could not read target: %v", err)
@@ -91,7 +91,7 @@ func main() {
f.Close()
// Compile source.
- cmd := exec.Command("go", "build", "-gcflags", "-S", "-o", filepath.Join(dir, "test"), src)
+ cmd := exec.Command(testenv.GoToolPath(t), "build", "-gcflags", "-S", "-o", filepath.Join(dir, "test"), src)
out, err := cmd.CombinedOutput()
if err != nil {
log.Fatalf("could not build target: %v", err)
diff --git a/src/cmd/compile/internal/gc/go.go b/src/cmd/compile/internal/gc/go.go
index 2e4caca..ff33e9c 100644
--- a/src/cmd/compile/internal/gc/go.go
+++ b/src/cmd/compile/internal/gc/go.go
@@ -5,7 +5,6 @@
package gc
import (
- "bufio"
"cmd/compile/internal/ssa"
"cmd/internal/bio"
"cmd/internal/obj"
@@ -23,9 +22,7 @@ type Pkg struct {
Pathsym *obj.LSym
Prefix string // escaped path for use in symbol table
Imported bool // export data of this package was parsed
- Exported bool // import line written in export data
Direct bool // imported directly
- Safe bool // whether the package is marked as safe
Syms map[string]*Sym
}
@@ -33,7 +30,7 @@ type Pkg struct {
// an object declared within a package, but Syms are also used to name internal
// synthesized objects.
//
-// As a special exception, field and method names that are exported use the Sym
+// 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.
@@ -45,31 +42,17 @@ type Sym struct {
// saved and restored by dcopy
Pkg *Pkg
- Name string // variable name
+ 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 *Label // corresponding label (ephemeral)
- Origpkg *Pkg // original package for . import
+ Label *Node // corresponding label (ephemeral)
+ Origpkg *Pkg // original package for . import
Lsym *obj.LSym
Fsym *Sym // funcsym
}
-type Label struct {
- Sym *Sym
- Def *Node
- Use []*Node
-
- // for use during gen
- Gotopc *obj.Prog // pointer to unresolved gotos
- Labelpc *obj.Prog // pointer to code
- Breakpc *obj.Prog // pointer to code
- Continpc *obj.Prog // pointer to code
-
- Used bool
-}
-
type SymFlags uint8
const (
@@ -80,6 +63,7 @@ const (
SymSiggen
SymAsm
SymAlgGen
+ SymAlias // alias, original is Sym.Def.Sym
)
// The Class of a variable/function describes the "storage class"
@@ -108,11 +92,11 @@ const (
// uchar nel[4]; // number of elements
// uchar cap[4]; // allocated number of elements
// } Array;
-var Array_array int // runtime offsetof(Array,array) - same for String
+var array_array int // runtime offsetof(Array,array) - same for String
-var Array_nel int // runtime offsetof(Array,nel) - same for String
+var array_nel int // runtime offsetof(Array,nel) - same for String
-var Array_cap int // runtime offsetof(Array,cap)
+var array_cap int // runtime offsetof(Array,cap)
var sizeof_Array int // runtime sizeof(Array)
@@ -135,8 +119,12 @@ var linkobj string
var bout *bio.Writer
+// nerrors is the number of compiler errors reported
+// since the last call to saveerrors.
var nerrors int
+// nsavederrors is the total number of compiler errors
+// reported before the last call to saveerrors.
var nsavederrors int
var nsyntaxerrors int
@@ -156,8 +144,6 @@ var Debug_typeassert int
var localpkg *Pkg // package being compiled
-var autopkg *Pkg // fake package for allocating auto variables
-
var importpkg *Pkg // package being imported
var itabpkg *Pkg // fake pkg for itab entries
@@ -187,13 +173,13 @@ var localimport string
var asmhdr string
-var Simtype [NTYPE]EType
+var simtype [NTYPE]EType
var (
isforw [NTYPE]bool
- Isint [NTYPE]bool
- Isfloat [NTYPE]bool
- Iscomplex [NTYPE]bool
+ isInt [NTYPE]bool
+ isFloat [NTYPE]bool
+ isComplex [NTYPE]bool
issimple [NTYPE]bool
)
@@ -215,9 +201,9 @@ var (
iscmp [OEND]bool
)
-var Minintval [NTYPE]*Mpint
+var minintval [NTYPE]*Mpint
-var Maxintval [NTYPE]*Mpint
+var maxintval [NTYPE]*Mpint
var minfltval [NTYPE]*Mpflt
@@ -233,11 +219,9 @@ var funcsyms []*Node
var dclcontext Class // PEXTERN/PAUTO
-var incannedimport int
-
var statuniqgen int // name generator for static temps
-var iota_ int32
+var iota_ int64
var lastconst []*Node
@@ -289,19 +273,13 @@ var Ctxt *obj.Link
var writearchive bool
-var bstdout *bufio.Writer
-
var Nacl bool
-var continpc *obj.Prog
-
-var breakpc *obj.Prog
-
-var Pc *obj.Prog
+var pc *obj.Prog
var nodfp *Node
-var Disable_checknil int
+var disable_checknil int
// interface to back end
@@ -359,89 +337,20 @@ const (
// Instruction updates whichever of from/to is type D_OREG. (ppc64)
PostInc = 1 << 29
+
+ // Optional 3rd input operand, only ever read.
+ From3Read = 1 << 30
)
type Arch struct {
LinkArch *obj.LinkArch
- REGSP int
- REGCTXT int
- REGCALLX int // BX
- REGCALLX2 int // AX
- REGRETURN int // AX
- REGMIN int
- REGMAX int
- REGZERO int // architectural zero register, if available
- FREGMIN int
- FREGMAX int
- MAXWIDTH int64
- ReservedRegs []int
-
- AddIndex func(*Node, int64, *Node) bool // optional
- Betypeinit func()
- Bgen_float func(*Node, bool, int, *obj.Prog) // optional
- Cgen64 func(*Node, *Node) // only on 32-bit systems
- Cgenindex func(*Node, *Node, bool) *obj.Prog
- Cgen_bmul func(Op, *Node, *Node, *Node) bool
- Cgen_float func(*Node, *Node) // optional
- Cgen_hmul func(*Node, *Node, *Node)
- RightShiftWithCarry func(*Node, uint, *Node) // only on systems without RROTC instruction
- AddSetCarry func(*Node, *Node, *Node) // only on systems when ADD does not update carry flag
- Cgen_shift func(Op, bool, *Node, *Node, *Node)
- Clearfat func(*Node)
- Cmp64 func(*Node, *Node, Op, int, *obj.Prog) // only on 32-bit systems
- Defframe func(*obj.Prog)
- Dodiv func(Op, *Node, *Node, *Node)
- Excise func(*Flow)
- Expandchecks func(*obj.Prog)
- Getg func(*Node)
- Gins func(obj.As, *Node, *Node) *obj.Prog
-
- // Ginscmp generates code comparing n1 to n2 and jumping away if op is satisfied.
- // The returned prog should be Patch'ed with the jump target.
- // If op is not satisfied, code falls through to the next emitted instruction.
- // Likely is the branch prediction hint: +1 for likely, -1 for unlikely, 0 for no opinion.
- //
- // Ginscmp must be able to handle all kinds of arguments for n1 and n2,
- // not just simple registers, although it can assume that there are no
- // function calls needed during the evaluation, and on 32-bit systems
- // the values are guaranteed not to be 64-bit values, so no in-memory
- // temporaries are necessary.
- Ginscmp func(op Op, t *Type, n1, n2 *Node, likely int) *obj.Prog
-
- // Ginsboolval inserts instructions to convert the result
- // of a just-completed comparison to a boolean value.
- // The first argument is the conditional jump instruction
- // corresponding to the desired value.
- // The second argument is the destination.
- // If not present, Ginsboolval will be emulated with jumps.
- Ginsboolval func(obj.As, *Node)
-
- Ginscon func(obj.As, int64, *Node)
- Ginsnop func()
- Gmove func(*Node, *Node)
- Igenindex func(*Node, *Node, bool) *obj.Prog
- Peep func(*obj.Prog)
- Proginfo func(*obj.Prog) // fills in Prog.Info
- Regtyp func(*obj.Addr) bool
- Sameaddr func(*obj.Addr, *obj.Addr) bool
- Smallindir func(*obj.Addr, *obj.Addr) bool
- Stackaddr func(*obj.Addr) bool
- Blockcopy func(*Node, *Node, int64, int64, int64)
- Sudoaddable func(obj.As, *Node, *obj.Addr) bool
- Sudoclean func()
- Excludedregs func() uint64
- RtoB func(int) uint64
- FtoB func(int) uint64
- BtoR func(uint64) int
- BtoF func(uint64) int
- Optoas func(Op, *Type) obj.As
- Doregbits func(int) uint64
- Regnames func(*int) []string
- Use387 bool // should 8g use 387 FP instructions instead of sse2.
-
- // SSARegToReg maps ssa register numbers to obj register numbers.
- SSARegToReg []int16
+ REGSP int
+ MAXWIDTH int64
+
+ Defframe func(*obj.Prog)
+ Proginfo func(*obj.Prog) ProgInfo
+ Use387 bool // should 8g use 387 FP instructions instead of sse2.
// SSAMarkMoves marks any MOVXconst ops that need to avoid clobbering flags.
SSAMarkMoves func(*SSAGenState, *ssa.Block)
@@ -458,23 +367,18 @@ var pcloc int32
var Thearch Arch
-var Newproc *Node
-
-var Deferproc *Node
-
-var Deferreturn *Node
-
-var Panicindex *Node
-
-var panicslice *Node
-
-var panicdivide *Node
-
-var throwreturn *Node
-
-var growslice *Node
-
-var writebarrierptr *Node
-var typedmemmove *Node
-
-var panicdottype *Node
+var (
+ Newproc,
+ Deferproc,
+ Deferreturn,
+ panicindex,
+ panicslice,
+ panicdivide,
+ growslice,
+ panicdottype,
+ panicnildottype,
+ assertE2I,
+ assertE2I2,
+ assertI2I,
+ assertI2I2 *Node
+)
diff --git a/src/cmd/compile/internal/gc/gsubr.go b/src/cmd/compile/internal/gc/gsubr.go
index 4943d9d..1e86363 100644
--- a/src/cmd/compile/internal/gc/gsubr.go
+++ b/src/cmd/compile/internal/gc/gsubr.go
@@ -1,5 +1,5 @@
// Derived from Inferno utils/6c/txt.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6c/txt.c
+// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6c/txt.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth at terzarima.net)
@@ -30,96 +30,15 @@
package gc
-import (
- "cmd/internal/obj"
- "cmd/internal/sys"
- "fmt"
- "runtime"
- "strings"
-)
-
-var (
- ddumped bool
- dfirst *obj.Prog
- dpc *obj.Prog
-)
-
-// Is this node a memory operand?
-func Ismem(n *Node) bool {
- switch n.Op {
- case OITAB,
- OSPTR,
- OLEN,
- OCAP,
- OINDREG,
- ONAME,
- OCLOSUREVAR:
- return true
-
- case OADDR:
- // amd64 and s390x use PC relative addressing.
- // TODO(rsc): not sure why ppc64 needs this too.
- return Thearch.LinkArch.InFamily(sys.AMD64, sys.PPC64, sys.S390X)
- }
-
- return false
-}
-
-func Samereg(a *Node, b *Node) bool {
- if a == nil || b == nil {
- return false
- }
- if a.Op != OREGISTER {
- return false
- }
- if b.Op != OREGISTER {
- return false
- }
- if a.Reg != b.Reg {
- return false
- }
- return true
-}
-
-func Gbranch(as obj.As, t *Type, likely int) *obj.Prog {
- p := Prog(as)
- p.To.Type = obj.TYPE_BRANCH
- p.To.Val = nil
- if as != obj.AJMP && likely != 0 && !Thearch.LinkArch.InFamily(sys.PPC64, sys.ARM64, sys.MIPS64, sys.S390X) {
- p.From.Type = obj.TYPE_CONST
- if likely > 0 {
- p.From.Offset = 1
- }
- }
-
- if Debug['g'] != 0 {
- fmt.Printf("%v\n", p)
- }
-
- return p
-}
+import "cmd/internal/obj"
func Prog(as obj.As) *obj.Prog {
var p *obj.Prog
- if as == obj.AGLOBL {
- if ddumped {
- Fatalf("already dumped data")
- }
- if dpc == nil {
- dpc = Ctxt.NewProg()
- dfirst = dpc
- }
-
- p = dpc
- dpc = Ctxt.NewProg()
- p.Link = dpc
- } else {
- p = Pc
- Pc = Ctxt.NewProg()
- Clearp(Pc)
- p.Link = Pc
- }
+ p = pc
+ pc = Ctxt.NewProg()
+ Clearp(pc)
+ p.Link = pc
if lineno == 0 && Debug['K'] != 0 {
Warn("prog: line 0")
@@ -130,31 +49,6 @@ func Prog(as obj.As) *obj.Prog {
return p
}
-func Nodreg(n *Node, t *Type, r int) {
- if t == nil {
- Fatalf("nodreg: t nil")
- }
-
- *n = Node{}
- n.Op = OREGISTER
- n.Addable = true
- ullmancalc(n)
- n.Reg = int16(r)
- n.Type = t
-}
-
-func Nodindreg(n *Node, t *Type, r int) {
- Nodreg(n, t, r)
- n.Op = OINDREG
-}
-
-func Afunclit(a *obj.Addr, n *Node) {
- if a.Type == obj.TYPE_ADDR && a.Name == obj.NAME_EXTERN {
- a.Type = obj.TYPE_MEM
- a.Sym = Linksym(n.Sym)
- }
-}
-
func Clearp(p *obj.Prog) {
obj.Nopout(p)
p.As = obj.AEND
@@ -162,77 +56,33 @@ func Clearp(p *obj.Prog) {
pcloc++
}
-func dumpdata() {
- ddumped = true
- if dfirst == nil {
- return
- }
- newplist()
- *Pc = *dfirst
- Pc = dpc
- Clearp(Pc)
-}
-
-func flushdata() {
- if dfirst == nil {
- return
- }
- newplist()
- *Pc = *dfirst
- Pc = dpc
- Clearp(Pc)
- dfirst = nil
- dpc = nil
-}
-
-// Fixup instructions after allocauto (formerly compactframe) has moved all autos around.
-func fixautoused(p *obj.Prog) {
- for lp := &p; ; {
- p = *lp
- if p == nil {
- break
- }
- if p.As == obj.ATYPE && p.From.Node != nil && p.From.Name == obj.NAME_AUTO && !((p.From.Node).(*Node)).Used {
- *lp = p.Link
- continue
- }
-
- if (p.As == obj.AVARDEF || p.As == obj.AVARKILL || p.As == obj.AVARLIVE) && p.To.Node != nil && !((p.To.Node).(*Node)).Used {
- // Cannot remove VARDEF instruction, because - unlike TYPE handled above -
- // VARDEFs are interspersed with other code, and a jump might be using the
- // VARDEF as a target. Replace with a no-op instead. A later pass will remove
- // the no-ops.
- obj.Nopout(p)
-
- continue
- }
-
- if p.From.Name == obj.NAME_AUTO && p.From.Node != nil {
- p.From.Offset += stkdelta[p.From.Node.(*Node)]
- }
-
- if p.To.Name == obj.NAME_AUTO && p.To.Node != nil {
- p.To.Offset += stkdelta[p.To.Node.(*Node)]
- }
-
- lp = &p.Link
- }
+func 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)
+ q.As = as
+ q.Lineno = p.Lineno
+ q.From.Type = ftype
+ q.From.Reg = freg
+ q.From.Offset = foffset
+ q.To.Type = ttype
+ q.To.Reg = treg
+ q.To.Offset = toffset
+ q.Link = p.Link
+ p.Link = q
+ return q
}
func ggloblnod(nam *Node) {
- p := Thearch.Gins(obj.AGLOBL, nam, nil)
- p.Lineno = nam.Lineno
- p.From.Sym.Gotype = Linksym(ngotype(nam))
- p.To.Sym = nil
- p.To.Type = obj.TYPE_CONST
- p.To.Offset = nam.Type.Width
- p.From3 = new(obj.Addr)
+ s := Linksym(nam.Sym)
+ s.Gotype = Linksym(ngotype(nam))
+ flags := 0
if nam.Name.Readonly {
- p.From3.Offset = obj.RODATA
+ flags = obj.RODATA
}
if nam.Type != nil && !haspointers(nam.Type) {
- p.From3.Offset |= obj.NOPTR
+ flags |= obj.NOPTR
}
+ Ctxt.Globl(s, nam.Type.Width, flags)
}
func ggloblsym(s *Sym, width int32, flags int16) {
@@ -240,40 +90,21 @@ func ggloblsym(s *Sym, width int32, flags int16) {
}
func ggloblLSym(s *obj.LSym, width int32, flags int16) {
- p := Thearch.Gins(obj.AGLOBL, nil, nil)
- p.From.Type = obj.TYPE_MEM
- p.From.Name = obj.NAME_EXTERN
- p.From.Sym = s
if flags&obj.LOCAL != 0 {
- p.From.Sym.Local = true
+ s.Set(obj.AttrLocal, true)
flags &^= obj.LOCAL
}
- p.To.Type = obj.TYPE_CONST
- p.To.Offset = int64(width)
- p.From3 = new(obj.Addr)
- p.From3.Offset = int64(flags)
-}
-
-func gjmp(to *obj.Prog) *obj.Prog {
- p := Gbranch(obj.AJMP, nil, 0)
- if to != nil {
- Patch(p, to)
- }
- return p
+ Ctxt.Globl(s, int64(width), int(flags))
}
func gtrack(s *Sym) {
- p := Thearch.Gins(obj.AUSEFIELD, nil, nil)
+ p := Gins(obj.AUSEFIELD, nil, nil)
p.From.Type = obj.TYPE_MEM
p.From.Name = obj.NAME_EXTERN
p.From.Sym = Linksym(s)
}
-func gused(n *Node) {
- Thearch.Gins(obj.ANOP, n, nil) // used
-}
-
-func Isfat(t *Type) bool {
+func isfat(t *Type) bool {
if t != nil {
switch t.Etype {
case TSTRUCT, TARRAY, TSLICE, TSTRING,
@@ -285,23 +116,6 @@ func Isfat(t *Type) bool {
return false
}
-// Sweep the prog list to mark any used nodes.
-func markautoused(p *obj.Prog) {
- for ; p != nil; p = p.Link {
- if p.As == obj.ATYPE || p.As == obj.AVARDEF || p.As == obj.AVARKILL {
- continue
- }
-
- if p.From.Node != nil {
- ((p.From.Node).(*Node)).Used = true
- }
-
- if p.To.Node != nil {
- ((p.To.Node).(*Node)).Used = true
- }
- }
-}
-
// Naddr rewrites a to refer to n.
// It assumes that a is zeroed on entry.
func Naddr(a *obj.Addr, n *Node) {
@@ -309,208 +123,50 @@ func Naddr(a *obj.Addr, n *Node) {
return
}
- if n.Type != nil && n.Type.Etype != TIDEAL {
- // TODO(rsc): This is undone by the selective clearing of width below,
- // to match architectures that were not as aggressive in setting width
- // during naddr. Those widths must be cleared to avoid triggering
- // failures in gins when it detects real but heretofore latent (and one
- // hopes innocuous) type mismatches.
- // The type mismatches should be fixed and the clearing below removed.
- dowidth(n.Type)
-
- a.Width = n.Type.Width
- }
-
- switch n.Op {
- default:
- a := a // copy to let escape into Ctxt.Dconv
+ if n.Op != ONAME {
Debug['h'] = 1
Dump("naddr", n)
Fatalf("naddr: bad %v %v", n.Op, Ctxt.Dconv(a))
+ }
- case OREGISTER:
- a.Type = obj.TYPE_REG
- a.Reg = n.Reg
- a.Sym = nil
- if Thearch.LinkArch.Family == sys.I386 { // TODO(rsc): Never clear a->width.
- a.Width = 0
- }
-
- case OINDREG:
- a.Type = obj.TYPE_MEM
- a.Reg = n.Reg
- a.Sym = Linksym(n.Sym)
- a.Offset = n.Xoffset
- if a.Offset != int64(int32(a.Offset)) {
- Yyerror("offset %d too large for OINDREG", a.Offset)
- }
- if Thearch.LinkArch.Family == sys.I386 { // TODO(rsc): Never clear a->width.
- a.Width = 0
- }
-
- case OCLOSUREVAR:
- if !Curfn.Func.Needctxt {
- Fatalf("closurevar without needctxt")
- }
- a.Type = obj.TYPE_MEM
- a.Reg = int16(Thearch.REGCTXT)
- a.Sym = nil
- a.Offset = n.Xoffset
-
- case OCFUNC:
- Naddr(a, n.Left)
- a.Sym = Linksym(n.Left.Sym)
-
- case ONAME:
- a.Etype = 0
- if n.Type != nil {
- a.Etype = uint8(Simtype[n.Type.Etype])
- }
- a.Offset = n.Xoffset
- s := n.Sym
- a.Node = n.Orig
-
- //if(a->node >= (Node*)&n)
- // fatal("stack node");
- if s == nil {
- s = Lookup(".noname")
- }
- if n.Name.Method && n.Type != nil && n.Type.Sym != nil && n.Type.Sym.Pkg != nil {
- s = Pkglookup(s.Name, n.Type.Sym.Pkg)
- }
-
- a.Type = obj.TYPE_MEM
- switch n.Class {
- default:
- Fatalf("naddr: ONAME class %v %d\n", n.Sym, n.Class)
-
- case PEXTERN:
- a.Name = obj.NAME_EXTERN
-
- case PAUTO:
- a.Name = obj.NAME_AUTO
-
- case PPARAM, PPARAMOUT:
- a.Name = obj.NAME_PARAM
-
- case PFUNC:
- a.Name = obj.NAME_EXTERN
- a.Type = obj.TYPE_ADDR
- a.Width = int64(Widthptr)
- s = funcsym(s)
- }
-
- a.Sym = Linksym(s)
-
- case ODOT:
- // A special case to make write barriers more efficient.
- // Taking the address of the first field of a named struct
- // is the same as taking the address of the struct.
- if !n.Left.Type.IsStruct() || n.Left.Type.Field(0).Sym != n.Sym {
- Debug['h'] = 1
- Dump("naddr", n)
- Fatalf("naddr: bad %v %v", n.Op, Ctxt.Dconv(a))
- }
- Naddr(a, n.Left)
-
- case OLITERAL:
- if Thearch.LinkArch.Family == sys.I386 {
- a.Width = 0
- }
- switch u := n.Val().U.(type) {
- default:
- Fatalf("naddr: const %v", Tconv(n.Type, FmtLong))
-
- case *Mpflt:
- a.Type = obj.TYPE_FCONST
- a.Val = u.Float64()
-
- case *Mpint:
- a.Sym = nil
- a.Type = obj.TYPE_CONST
- a.Offset = u.Int64()
-
- case string:
- datagostring(u, a)
-
- case bool:
- a.Sym = nil
- a.Type = obj.TYPE_CONST
- a.Offset = int64(obj.Bool2int(u))
-
- case *NilVal:
- a.Sym = nil
- a.Type = obj.TYPE_CONST
- a.Offset = 0
- }
-
- case OADDR:
- Naddr(a, n.Left)
- a.Etype = uint8(Tptr)
- if !Thearch.LinkArch.InFamily(sys.MIPS64, sys.ARM, sys.ARM64, sys.PPC64, sys.S390X) { // TODO(rsc): Do this even for these architectures.
- a.Width = int64(Widthptr)
- }
- if a.Type != obj.TYPE_MEM {
- a := a // copy to let escape into Ctxt.Dconv
- Fatalf("naddr: OADDR %v (from %v)", Ctxt.Dconv(a), n.Left.Op)
- }
- a.Type = obj.TYPE_ADDR
-
- // itable of interface value
- case OITAB:
- Naddr(a, n.Left)
+ a.Offset = n.Xoffset
+ s := n.Sym
+ a.Node = n.Orig
- if a.Type == obj.TYPE_CONST && a.Offset == 0 {
- break // itab(nil)
- }
- a.Etype = uint8(Tptr)
- a.Width = int64(Widthptr)
+ if s == nil {
+ Fatalf("naddr: nil sym %v", n)
+ }
- // pointer in a string or slice
- case OSPTR:
- Naddr(a, n.Left)
+ a.Type = obj.TYPE_MEM
+ switch n.Class {
+ default:
+ Fatalf("naddr: ONAME class %v %d\n", n.Sym, n.Class)
- if a.Type == obj.TYPE_CONST && a.Offset == 0 {
- break // ptr(nil)
- }
- a.Etype = uint8(Simtype[Tptr])
- a.Offset += int64(Array_array)
- a.Width = int64(Widthptr)
+ case PEXTERN, PFUNC:
+ a.Name = obj.NAME_EXTERN
- // len of string or slice
- case OLEN:
- Naddr(a, n.Left)
+ case PAUTO:
+ a.Name = obj.NAME_AUTO
- if a.Type == obj.TYPE_CONST && a.Offset == 0 {
- break // len(nil)
- }
- a.Etype = uint8(Simtype[TUINT])
- a.Offset += int64(Array_nel)
- if Thearch.LinkArch.Family != sys.ARM { // TODO(rsc): Do this even on arm.
- a.Width = int64(Widthint)
- }
+ case PPARAM, PPARAMOUT:
+ a.Name = obj.NAME_PARAM
+ }
- // cap of string or slice
- case OCAP:
- Naddr(a, n.Left)
+ a.Sym = Linksym(s)
+}
- if a.Type == obj.TYPE_CONST && a.Offset == 0 {
- break // cap(nil)
- }
- a.Etype = uint8(Simtype[TUINT])
- a.Offset += int64(Array_cap)
- if Thearch.LinkArch.Family != sys.ARM { // TODO(rsc): Do this even on arm.
- a.Width = int64(Widthint)
- }
- }
+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
+ pc = Ctxt.NewProg()
+ Clearp(pc)
+ pl.Firstpc = pc
return pl
}
@@ -545,8 +201,8 @@ func nodarg(t interface{}, fp int) *Node {
funarg = t.StructType().Funarg
// Build fake variable name for whole arg struct.
- n = Nod(ONAME, nil, nil)
- n.Sym = Lookup(".args")
+ n = nod(ONAME, nil, nil)
+ n.Sym = lookup(".args")
n.Type = t
first := t.Field(0)
if first == nil {
@@ -594,7 +250,7 @@ func nodarg(t interface{}, fp int) *Node {
// 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 = nod(ONAME, nil, nil)
n.Type = t.Type
n.Sym = t.Sym
if t.Offset == BADWIDTH {
@@ -609,7 +265,7 @@ func nodarg(t interface{}, fp int) *Node {
// or else the assignment to _ will be
// discarded during code generation.
if isblank(n) {
- n.Sym = Lookup("__")
+ n.Sym = lookup("__")
}
switch fp {
@@ -617,8 +273,7 @@ func nodarg(t interface{}, fp int) *Node {
Fatalf("bad fp")
case 0: // preparing arguments for call
- n.Op = OINDREG
- n.Reg = int16(Thearch.REGSP)
+ n.Op = OINDREGSP
n.Xoffset += Ctxt.FixedFrameSize()
case 1: // reading arguments inside call
@@ -641,246 +296,17 @@ func Patch(p *obj.Prog, to *obj.Prog) {
p.To.Offset = to.Pc
}
-func unpatch(p *obj.Prog) *obj.Prog {
- if p.To.Type != obj.TYPE_BRANCH {
- Fatalf("unpatch: not a branch")
- }
- q, _ := p.To.Val.(*obj.Prog)
- p.To.Val = nil
- p.To.Offset = 0
- return q
-}
-
-var reg [100]int // count of references to reg
-var regstk [100][]byte // allocation sites, when -v is given
-
-func GetReg(r int) int {
- return reg[r-Thearch.REGMIN]
-}
-func SetReg(r, v int) {
- reg[r-Thearch.REGMIN] = v
-}
-
-func ginit() {
- for r := range reg {
- reg[r] = 1
- }
-
- for r := Thearch.REGMIN; r <= Thearch.REGMAX; r++ {
- reg[r-Thearch.REGMIN] = 0
- }
- for r := Thearch.FREGMIN; r <= Thearch.FREGMAX; r++ {
- reg[r-Thearch.REGMIN] = 0
- }
-
- for _, r := range Thearch.ReservedRegs {
- reg[r-Thearch.REGMIN] = 1
- }
-}
-
-func gclean() {
- for _, r := range Thearch.ReservedRegs {
- reg[r-Thearch.REGMIN]--
- }
-
- for r := Thearch.REGMIN; r <= Thearch.REGMAX; r++ {
- n := reg[r-Thearch.REGMIN]
- if n != 0 {
- if Debug['v'] != 0 {
- Regdump()
- }
- Yyerror("reg %v left allocated", obj.Rconv(r))
- }
- }
-
- for r := Thearch.FREGMIN; r <= Thearch.FREGMAX; r++ {
- n := reg[r-Thearch.REGMIN]
- if n != 0 {
- if Debug['v'] != 0 {
- Regdump()
- }
- Yyerror("reg %v left allocated", obj.Rconv(r))
- }
- }
-}
-
-func Anyregalloc() bool {
- n := 0
- for r := Thearch.REGMIN; r <= Thearch.REGMAX; r++ {
- if reg[r-Thearch.REGMIN] == 0 {
- n++
- }
- }
- return n > len(Thearch.ReservedRegs)
-}
-
-// allocate register of type t, leave in n.
-// if o != N, o may be reusable register.
-// caller must Regfree(n).
-func Regalloc(n *Node, t *Type, o *Node) {
- if t == nil {
- Fatalf("regalloc: t nil")
- }
- et := Simtype[t.Etype]
- if Ctxt.Arch.RegSize == 4 && (et == TINT64 || et == TUINT64) {
- Fatalf("regalloc 64bit")
- }
-
- var i int
-Switch:
- switch et {
+// 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("regalloc: unknown type %v", t)
-
- case TINT8, TUINT8, TINT16, TUINT16, TINT32, TUINT32, TINT64, TUINT64, TPTR32, TPTR64, TBOOL:
- if o != nil && o.Op == OREGISTER {
- i = int(o.Reg)
- if Thearch.REGMIN <= i && i <= Thearch.REGMAX {
- break Switch
- }
- }
- for i = Thearch.REGMIN; i <= Thearch.REGMAX; i++ {
- if reg[i-Thearch.REGMIN] == 0 {
- break Switch
- }
- }
- Flusherrors()
- Regdump()
- Fatalf("out of fixed registers")
-
- case TFLOAT32, TFLOAT64:
- if Thearch.Use387 {
- i = Thearch.FREGMIN // x86.REG_F0
- break Switch
- }
- if o != nil && o.Op == OREGISTER {
- i = int(o.Reg)
- if Thearch.FREGMIN <= i && i <= Thearch.FREGMAX {
- break Switch
- }
- }
- for i = Thearch.FREGMIN; i <= Thearch.FREGMAX; i++ {
- if reg[i-Thearch.REGMIN] == 0 { // note: REGMIN, not FREGMIN
- break Switch
- }
- }
- Flusherrors()
- Regdump()
- Fatalf("out of floating registers")
-
- case TCOMPLEX64, TCOMPLEX128:
- Tempname(n, t)
- return
- }
-
- ix := i - Thearch.REGMIN
- if reg[ix] == 0 && Debug['v'] > 0 {
- if regstk[ix] == nil {
- regstk[ix] = make([]byte, 4096)
- }
- stk := regstk[ix]
- n := runtime.Stack(stk[:cap(stk)], false)
- regstk[ix] = stk[:n]
- }
- reg[ix]++
- Nodreg(n, t, i)
-}
-
-func Regfree(n *Node) {
- if n.Op == ONAME {
- return
- }
- if n.Op != OREGISTER && n.Op != OINDREG {
- Fatalf("regfree: not a register")
- }
- i := int(n.Reg)
- if i == Thearch.REGSP {
- return
- }
- switch {
- case Thearch.REGMIN <= i && i <= Thearch.REGMAX,
- Thearch.FREGMIN <= i && i <= Thearch.FREGMAX:
- // ok
- default:
- Fatalf("regfree: reg out of range")
- }
-
- i -= Thearch.REGMIN
- if reg[i] <= 0 {
- Fatalf("regfree: reg not allocated")
- }
- reg[i]--
- if reg[i] == 0 {
- regstk[i] = regstk[i][:0]
- }
-}
-
-// Reginuse reports whether r is in use.
-func Reginuse(r int) bool {
- switch {
- case Thearch.REGMIN <= r && r <= Thearch.REGMAX,
- Thearch.FREGMIN <= r && r <= Thearch.FREGMAX:
- // ok
- default:
- Fatalf("reginuse: reg out of range")
+ Fatalf("unhandled gins op %v", as)
}
- return reg[r-Thearch.REGMIN] > 0
-}
-
-// Regrealloc(n) undoes the effect of Regfree(n),
-// so that a register can be given up but then reclaimed.
-func Regrealloc(n *Node) {
- if n.Op != OREGISTER && n.Op != OINDREG {
- Fatalf("regrealloc: not a register")
- }
- i := int(n.Reg)
- if i == Thearch.REGSP {
- return
- }
- switch {
- case Thearch.REGMIN <= i && i <= Thearch.REGMAX,
- Thearch.FREGMIN <= i && i <= Thearch.FREGMAX:
- // ok
- default:
- Fatalf("regrealloc: reg out of range")
- }
-
- i -= Thearch.REGMIN
- if reg[i] == 0 && Debug['v'] > 0 {
- if regstk[i] == nil {
- regstk[i] = make([]byte, 4096)
- }
- stk := regstk[i]
- n := runtime.Stack(stk[:cap(stk)], false)
- regstk[i] = stk[:n]
- }
- reg[i]++
-}
-
-func Regdump() {
- if Debug['v'] == 0 {
- fmt.Printf("run compiler with -v for register allocation sites\n")
- return
- }
-
- dump := func(r int) {
- stk := regstk[r-Thearch.REGMIN]
- if len(stk) == 0 {
- return
- }
- fmt.Printf("reg %v allocated at:\n", obj.Rconv(r))
- fmt.Printf("\t%s\n", strings.Replace(strings.TrimSpace(string(stk)), "\n", "\n\t", -1))
- }
-
- for r := Thearch.REGMIN; r <= Thearch.REGMAX; r++ {
- if reg[r-Thearch.REGMIN] != 0 {
- dump(r)
- }
- }
- for r := Thearch.FREGMIN; r <= Thearch.FREGMAX; r++ {
- if reg[r-Thearch.REGMIN] == 0 {
- dump(r)
- }
- }
+ p := Prog(as)
+ Naddr(&p.From, f)
+ Naddr(&p.To, t)
+ return p
}
diff --git a/src/cmd/compile/internal/gc/iface_test.go b/src/cmd/compile/internal/gc/iface_test.go
new file mode 100644
index 0000000..21c6587
--- /dev/null
+++ b/src/cmd/compile/internal/gc/iface_test.go
@@ -0,0 +1,128 @@
+// Copyright 2016 The Go Authors. 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 to make sure we make copies of the values we
+// put in interfaces.
+
+import (
+ "testing"
+)
+
+var x int
+
+func TestEfaceConv1(t *testing.T) {
+ a := 5
+ i := interface{}(a)
+ a += 2
+ if got := i.(int); got != 5 {
+ t.Errorf("wanted 5, got %d\n", got)
+ }
+}
+
+func TestEfaceConv2(t *testing.T) {
+ a := 5
+ sink = &a
+ i := interface{}(a)
+ a += 2
+ if got := i.(int); got != 5 {
+ t.Errorf("wanted 5, got %d\n", got)
+ }
+}
+
+func TestEfaceConv3(t *testing.T) {
+ x = 5
+ if got := e2int3(x); got != 5 {
+ t.Errorf("wanted 5, got %d\n", got)
+ }
+}
+
+//go:noinline
+func e2int3(i interface{}) int {
+ x = 7
+ return i.(int)
+}
+
+func TestEfaceConv4(t *testing.T) {
+ a := 5
+ if got := e2int4(a, &a); got != 5 {
+ t.Errorf("wanted 5, got %d\n", got)
+ }
+}
+
+//go:noinline
+func e2int4(i interface{}, p *int) int {
+ *p = 7
+ return i.(int)
+}
+
+type Int int
+
+var y Int
+
+type I interface {
+ foo()
+}
+
+func (i Int) foo() {
+}
+
+func TestIfaceConv1(t *testing.T) {
+ a := Int(5)
+ i := interface{}(a)
+ a += 2
+ if got := i.(Int); got != 5 {
+ t.Errorf("wanted 5, got %d\n", int(got))
+ }
+}
+
+func TestIfaceConv2(t *testing.T) {
+ a := Int(5)
+ sink = &a
+ i := interface{}(a)
+ a += 2
+ if got := i.(Int); got != 5 {
+ t.Errorf("wanted 5, got %d\n", int(got))
+ }
+}
+
+func TestIfaceConv3(t *testing.T) {
+ y = 5
+ if got := i2Int3(y); got != 5 {
+ t.Errorf("wanted 5, got %d\n", int(got))
+ }
+}
+
+//go:noinline
+func i2Int3(i I) Int {
+ y = 7
+ return i.(Int)
+}
+
+func TestIfaceConv4(t *testing.T) {
+ a := Int(5)
+ if got := i2Int4(a, &a); got != 5 {
+ t.Errorf("wanted 5, got %d\n", int(got))
+ }
+}
+
+//go:noinline
+func i2Int4(i I, p *Int) Int {
+ *p = 7
+ return i.(Int)
+}
+
+func BenchmarkEfaceInteger(b *testing.B) {
+ sum := 0
+ for i := 0; i < b.N; i++ {
+ sum += i2int(i)
+ }
+ sink = sum
+}
+
+//go:noinline
+func i2int(i interface{}) int {
+ return i.(int)
+}
diff --git a/src/cmd/compile/internal/gc/init.go b/src/cmd/compile/internal/gc/init.go
index 67a050a..5693052 100644
--- a/src/cmd/compile/internal/gc/init.go
+++ b/src/cmd/compile/internal/gc/init.go
@@ -4,19 +4,6 @@
package gc
-// case OADD:
-// if(n->right->op == OLITERAL) {
-// v = n->right->vconst;
-// naddr(n->left, a, canemitcode);
-// } else
-// if(n->left->op == OLITERAL) {
-// v = n->left->vconst;
-// naddr(n->right, a, canemitcode);
-// } else
-// goto bad;
-// a->offset += v;
-// break;
-
// a function named init is a special case.
// it is called by the initialization before
// main is run. to make it unique within a
@@ -27,7 +14,7 @@ var renameinit_initgen int
func renameinit() *Sym {
renameinit_initgen++
- return LookupN("init.", renameinit_initgen)
+ return lookupN("init.", renameinit_initgen)
}
// hand-craft the following initialization code
@@ -70,7 +57,7 @@ func anyinit(n []*Node) bool {
}
// is there an explicit init function
- s := Lookup("init.1")
+ s := lookup("init.1")
if s.Def != nil {
return true
@@ -88,11 +75,6 @@ func anyinit(n []*Node) bool {
}
func fninit(n []*Node) {
- if Debug['A'] != 0 {
- // sys.go or unsafe.go during compiler build
- return
- }
-
nf := initfix(n)
if !anyinit(nf) {
return
@@ -101,40 +83,40 @@ func fninit(n []*Node) {
var r []*Node
// (1)
- gatevar := newname(Lookup("initdone·"))
+ gatevar := newname(lookup("initdone·"))
addvar(gatevar, Types[TUINT8], PEXTERN)
// (2)
Maxarg = 0
- fn := Nod(ODCLFUNC, nil, nil)
- initsym := Lookup("init")
+ 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)
+ fn.Func.Nname.Name.Param.Ntype = nod(OTFUNC, nil, nil)
declare(fn.Func.Nname, PFUNC)
funchdr(fn)
// (3)
- a := Nod(OIF, nil, nil)
- a.Left = Nod(OGT, gatevar, Nodintconst(1))
+ a := nod(OIF, nil, nil)
+ a.Left = nod(OGT, gatevar, nodintconst(1))
a.Likely = 1
r = append(r, a)
// (3a)
- a.Nbody.Set1(Nod(ORETURN, nil, nil))
+ a.Nbody.Set1(nod(ORETURN, nil, nil))
// (4)
- b := Nod(OIF, nil, nil)
- b.Left = Nod(OEQ, gatevar, Nodintconst(1))
+ b := nod(OIF, nil, nil)
+ b.Left = nod(OEQ, gatevar, nodintconst(1))
// this actually isn't likely, but code layout is better
// like this: no JMP needed after the call.
b.Likely = 1
r = append(r, b)
// (4a)
- b.Nbody.Set1(Nod(OCALL, syslook("throwinit"), nil))
+ b.Nbody.Set1(nod(OCALL, syslook("throwinit"), nil))
// (5)
- a = Nod(OAS, gatevar, Nodintconst(1))
+ a = nod(OAS, gatevar, nodintconst(1))
r = append(r, a)
@@ -142,7 +124,7 @@ func fninit(n []*Node) {
for _, s := range initSyms {
if s.Def != nil && s != initsym {
// could check that it is fn of no args/returns
- a = Nod(OCALL, s.Def, nil)
+ a = nod(OCALL, s.Def, nil)
r = append(r, a)
}
}
@@ -153,21 +135,21 @@ func fninit(n []*Node) {
// (8)
// could check that it is fn of no args/returns
for i := 1; ; i++ {
- s := LookupN("init.", i)
+ s := lookupN("init.", i)
if s.Def == nil {
break
}
- a = Nod(OCALL, s.Def, nil)
+ a = nod(OCALL, s.Def, nil)
r = append(r, a)
}
// (9)
- a = Nod(OAS, gatevar, Nodintconst(2))
+ a = nod(OAS, gatevar, nodintconst(2))
r = append(r, a)
// (10)
- a = Nod(ORETURN, nil, nil)
+ a = nod(ORETURN, nil, nil)
r = append(r, a)
exportsym(fn.Func.Nname)
diff --git a/src/cmd/compile/internal/gc/inl.go b/src/cmd/compile/internal/gc/inl.go
index 0c1b050..d8f1f24 100644
--- a/src/cmd/compile/internal/gc/inl.go
+++ b/src/cmd/compile/internal/gc/inl.go
@@ -32,7 +32,7 @@ import "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 {
- if fn.Type.Recv() != nil {
+ if fn.IsMethod() {
// method
rcvr := fn.Type.Recv().Type
@@ -40,7 +40,7 @@ func fnpkg(fn *Node) *Pkg {
rcvr = rcvr.Elem()
}
if rcvr.Sym == nil {
- Fatalf("receiver with no sym: [%v] %v (%v)", fn.Sym, Nconv(fn, FmtLong), rcvr)
+ Fatalf("receiver with no sym: [%v] %L (%v)", fn.Sym, fn, rcvr)
}
return rcvr.Sym.Pkg
}
@@ -65,7 +65,7 @@ func typecheckinl(fn *Node) {
}
if Debug['m'] > 2 || Debug_export != 0 {
- fmt.Printf("typecheck import [%v] %v { %v }\n", fn.Sym, Nconv(fn, FmtLong), hconv(fn.Func.Inl, FmtSharp))
+ fmt.Printf("typecheck import [%v] %L { %#v }\n", fn.Sym, fn, fn.Func.Inl)
}
save_safemode := safemode
@@ -89,16 +89,27 @@ func caninl(fn *Node) {
Fatalf("caninl %v", fn)
}
if fn.Func.Nname == nil {
- Fatalf("caninl no nname %v", Nconv(fn, FmtSign))
+ Fatalf("caninl no nname %+v", fn)
+ }
+
+ var reason string // reason, if any, that the function was not inlined
+ if Debug['m'] > 1 {
+ defer func() {
+ if reason != "" {
+ fmt.Printf("%v: cannot inline %v: %s\n", fn.Line(), fn.Func.Nname, reason)
+ }
+ }()
}
// If marked "go:noinline", don't inline
if fn.Func.Pragma&Noinline != 0 {
+ reason = "marked go:noinline"
return
}
// If fn has no body (is defined outside of Go), cannot inline it.
if fn.Nbody.Len() == 0 {
+ reason = "no function body"
return
}
@@ -111,6 +122,7 @@ func caninl(fn *Node) {
f := fn.Type.Params().Fields()
if len := f.Len(); len > 0 {
if t := f.Index(len - 1); t.Isddd {
+ reason = "has ... args"
return
}
}
@@ -123,12 +135,17 @@ func caninl(fn *Node) {
// The example that we observed is inlining of LockOSThread,
// which lead to false race reports on m contents.
if instrumenting && myimportpath == "runtime" {
+ reason = "instrumenting and is runtime function"
return
}
const maxBudget = 80
budget := int32(maxBudget) // allowed hairyness
- if ishairylist(fn.Nbody, &budget) || budget < 0 {
+ if ishairylist(fn.Nbody, &budget, &reason) {
+ return
+ }
+ if budget < 0 {
+ reason = "function too complex"
return
}
@@ -148,7 +165,7 @@ func caninl(fn *Node) {
fn.Type.SetNname(n)
if Debug['m'] > 1 {
- fmt.Printf("%v: can inline %v as: %v { %v }\n", fn.Line(), Nconv(n, FmtSharp), Tconv(fn.Type, FmtSharp), hconv(n.Func.Inl, FmtSharp))
+ fmt.Printf("%v: can inline %#v as: %#v { %#v }\n", fn.Line(), n, fn.Type, n.Func.Inl)
} else if Debug['m'] != 0 {
fmt.Printf("%v: can inline %v\n", fn.Line(), n)
}
@@ -157,16 +174,16 @@ func caninl(fn *Node) {
}
// Look for anything we want to punt on.
-func ishairylist(ll Nodes, budget *int32) bool {
+func ishairylist(ll Nodes, budget *int32, reason *string) bool {
for _, n := range ll.Slice() {
- if ishairy(n, budget) {
+ if ishairy(n, budget, reason) {
return true
}
}
return false
}
-func ishairy(n *Node, budget *int32) bool {
+func ishairy(n *Node, budget *int32, reason *string) bool {
if n == nil {
return false
}
@@ -179,13 +196,14 @@ func ishairy(n *Node, budget *int32) bool {
break
}
- if n.Left.Op == ONAME && n.Left.Left != nil && n.Left.Left.Op == OTYPE && n.Left.Right != nil && n.Left.Right.Op == ONAME { // methods called as functions
+ if n.isMethodCalledAsFunction() {
if d := n.Left.Sym.Def; d != nil && d.Func.Inl.Len() != 0 {
*budget -= d.Func.InlCost
break
}
}
if Debug['l'] < 4 {
+ *reason = "non-leaf function"
return true
}
@@ -193,22 +211,24 @@ func ishairy(n *Node, budget *int32) bool {
case OCALLMETH:
t := n.Left.Type
if t == nil {
- Fatalf("no function type for [%p] %v\n", n.Left, Nconv(n.Left, FmtSign))
+ Fatalf("no function type for [%p] %+v\n", n.Left, n.Left)
}
if t.Nname() == nil {
- Fatalf("no function definition for [%p] %v\n", t, Tconv(t, FmtSign))
+ Fatalf("no function definition for [%p] %+v\n", t, t)
}
if inlfn := t.Nname().Func; inlfn.Inl.Len() != 0 {
*budget -= inlfn.InlCost
break
}
if Debug['l'] < 4 {
+ *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()
return true
}
@@ -223,12 +243,25 @@ func ishairy(n *Node, budget *int32) bool {
ODCLTYPE, // can't print yet
OBREAK,
ORETJMP:
+ *reason = "unhandled op " + n.Op.String()
return true
}
(*budget)--
+ // TODO(mdempsky/josharian): Hacks to appease toolstash; remove.
+ // See issue 17566 and CL 31674 for discussion.
+ switch n.Op {
+ case OSTRUCTKEY:
+ (*budget)--
+ case OSLICE, OSLICEARR, OSLICESTR:
+ (*budget)--
+ case OSLICE3, OSLICE3ARR:
+ *budget -= 2
+ }
- return *budget < 0 || ishairy(n.Left, budget) || ishairy(n.Right, budget) || ishairylist(n.List, budget) || ishairylist(n.Rlist, budget) || ishairylist(n.Ninit, budget) || ishairylist(n.Nbody, budget)
+ 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)
}
// Inlcopy and inlcopylist recursively copy the body of a function.
@@ -304,7 +337,7 @@ func inlconv2expr(n *Node) *Node {
// statements.
func inlconv2list(n *Node) []*Node {
if n.Op != OINLCALL || n.Rlist.Len() == 0 {
- Fatalf("inlconv2list %v\n", Nconv(n, FmtSign))
+ Fatalf("inlconv2list %+v\n", n)
}
s := n.Rlist.Slice()
@@ -342,12 +375,11 @@ func inlnode(n *Node) *Node {
case ODEFER, OPROC:
switch n.Left.Op {
case OCALLFUNC, OCALLMETH:
- // TODO(marvin): Fix Node.EType type union.
- n.Left.Etype = EType(n.Op)
+ n.Left.setNoInline(true)
}
fallthrough
- // TODO do them here (or earlier),
+ // TODO do them here (or earlier),
// so escape analysis can avoid more heapmoves.
case OCLOSURE:
return n
@@ -385,7 +417,7 @@ func inlnode(n *Node) *Node {
}
}
- // if we just replaced arg in f(arg()) or return arg with an inlined call
+ // 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,
@@ -402,7 +434,7 @@ func inlnode(n *Node) *Node {
default:
s := n.List.Slice()
for i1, n1 := range s {
- if n1.Op == OINLCALL {
+ if n1 != nil && n1.Op == OINLCALL {
s[i1] = inlconv2expr(s[i1])
}
}
@@ -445,8 +477,7 @@ func inlnode(n *Node) *Node {
// switch at the top of this function.
switch n.Op {
case OCALLFUNC, OCALLMETH:
- // TODO(marvin): Fix Node.EType type union.
- if n.Etype == EType(OPROC) || n.Etype == EType(ODEFER) {
+ if n.noInline() {
return n
}
}
@@ -454,28 +485,26 @@ func inlnode(n *Node) *Node {
switch n.Op {
case OCALLFUNC:
if Debug['m'] > 3 {
- fmt.Printf("%v:call to func %v\n", n.Line(), Nconv(n.Left, FmtSign))
+ fmt.Printf("%v:call to func %+v\n", n.Line(), n.Left)
}
- if n.Left.Func != nil && n.Left.Func.Inl.Len() != 0 && !isIntrinsicCall1(n) { // normal case
+ 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.Left.Op == ONAME && n.Left.Left != nil && n.Left.Left.Op == OTYPE && n.Left.Right != nil && n.Left.Right.Op == ONAME { // methods called as functions
- if n.Left.Sym.Def != nil {
- n = mkinlcall(n, n.Left.Sym.Def, n.Isddd)
- }
+ } else if n.isMethodCalledAsFunction() && n.Left.Sym.Def != nil {
+ n = mkinlcall(n, n.Left.Sym.Def, n.Isddd)
}
case OCALLMETH:
if Debug['m'] > 3 {
- fmt.Printf("%v:call to meth %v\n", n.Line(), Nconv(n.Left.Right, FmtLong))
+ fmt.Printf("%v:call to meth %L\n", n.Line(), n.Left.Right)
}
// typecheck should have resolved ODOTMETH->type, whose nname points to the actual function.
if n.Left.Type == nil {
- Fatalf("no function type for [%p] %v\n", n.Left, Nconv(n.Left, FmtSign))
+ Fatalf("no function type for [%p] %+v\n", n.Left, n.Left)
}
if n.Left.Type.Nname() == nil {
- Fatalf("no function definition for [%p] %v\n", n.Left.Type, Tconv(n.Left.Type, FmtSign))
+ Fatalf("no function definition for [%p] %+v\n", n.Left.Type, n.Left.Type)
}
n = mkinlcall(n, n.Left.Type.Nname(), n.Isddd)
@@ -502,12 +531,13 @@ func mkinlcall(n *Node, fn *Node, isddd bool) *Node {
return n
}
-func tinlvar(t *Field) *Node {
+func tinlvar(t *Field, inlvars map[*Node]*Node) *Node {
if t.Nname != nil && !isblank(t.Nname) {
- if t.Nname.Name.Inlvar == nil {
+ inlvar := inlvars[t.Nname]
+ if inlvar == nil {
Fatalf("missing inlvar for %v\n", t.Nname)
}
- return t.Nname.Name.Inlvar
+ return inlvar
}
return typecheck(nblank, Erv|Easgn)
@@ -531,19 +561,21 @@ func mkinlcall1(n *Node, fn *Node, isddd bool) *Node {
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
if Debug['m'] > 1 {
- fmt.Printf("%v: inlining call to %v %v { %v }\n", n.Line(), fn.Sym, Tconv(fn.Type, FmtSharp), hconv(fn.Func.Inl, FmtSharp))
+ 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(), Nconv(n, FmtSign))
+ fmt.Printf("%v: Before inlining: %+v\n", n.Line(), n)
}
ninit := n.Ninit
@@ -571,9 +603,9 @@ func mkinlcall1(n *Node, fn *Node, isddd bool) *Node {
continue
}
if ln.Op == ONAME {
- ln.Name.Inlvar = typecheck(inlvar(ln), Erv)
+ 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, ln.Name.Inlvar, nil))
+ ninit.Append(nod(ODCL, inlvars[ln], nil))
}
}
}
@@ -584,32 +616,32 @@ func mkinlcall1(n *Node, fn *Node, isddd bool) *Node {
if t != nil && t.Nname != nil && !isblank(t.Nname) {
m = inlvar(t.Nname)
m = typecheck(m, Erv)
- t.Nname.Name.Inlvar = m
+ inlvars[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))
+ ninit.Append(nod(ODCL, m, nil))
retvars = append(retvars, m)
}
// assign receiver.
- if fn.Type.Recv() != nil && n.Left.Op == ODOTMETH {
+ 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) && t.Nname.Name.Inlvar == nil {
+ 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", Nconv(n, FmtSign))
+ Fatalf("method call without receiver: %+v", n)
}
if t == nil {
- Fatalf("method call unknown receiver type: %v", Nconv(n, FmtSign))
+ Fatalf("method call unknown receiver type: %+v", n)
}
- as := Nod(OAS, tinlvar(t), n.Left.Left)
+ as := nod(OAS, tinlvar(t, inlvars), n.Left.Left)
if as != nil {
as = typecheck(as, Etop)
ninit.Append(as)
@@ -654,28 +686,28 @@ func mkinlcall1(n *Node, fn *Node, isddd bool) *Node {
}
// assign arguments to the parameters' temp names
- as := Nod(OAS2, nil, nil)
+ 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.Type.Recv() != nil && n.Left.Op != ODOTMETH {
+ 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", Nconv(n, FmtSign))
+ 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) && t.Nname.Name.Inlvar == nil {
+ 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", Nconv(n, FmtSign))
+ Fatalf("method call unknown receiver type: %+v", n)
}
- as.List.Append(tinlvar(t))
+ as.List.Append(tinlvar(t, inlvars))
li++
}
@@ -689,7 +721,7 @@ func mkinlcall1(n *Node, fn *Node, isddd bool) *Node {
var i int
for _, t := range fn.Type.Params().Fields().Slice() {
if variadic && t.Isddd {
- vararg = tinlvar(t)
+ vararg = tinlvar(t, inlvars)
for i = 0; i < varargcount && li < n.List.Len(); i++ {
m = argvar(varargtype, i)
varargs = append(varargs, m)
@@ -699,11 +731,11 @@ func mkinlcall1(n *Node, fn *Node, isddd bool) *Node {
break
}
- as.List.Append(tinlvar(t))
+ as.List.Append(tinlvar(t, inlvars))
}
} else {
// match arguments except final variadic (unless the call is dotted itself)
- t, it := IterFields(fn.Type.Params())
+ t, it := iterFields(fn.Type.Params())
for t != nil {
if li >= n.List.Len() {
break
@@ -711,14 +743,14 @@ func mkinlcall1(n *Node, fn *Node, isddd bool) *Node {
if variadic && t.Isddd {
break
}
- as.List.Append(tinlvar(t))
+ as.List.Append(tinlvar(t, inlvars))
t = it.Next()
li++
}
// match varargcount arguments with variadic parameters.
if variadic && t != nil && t.Isddd {
- vararg = tinlvar(t)
+ vararg = tinlvar(t, inlvars)
var i int
for i = 0; i < varargcount && li < n.List.Len(); i++ {
m = argvar(varargtype, i)
@@ -733,7 +765,7 @@ func mkinlcall1(n *Node, fn *Node, isddd bool) *Node {
}
if li < n.List.Len() || t != nil {
- Fatalf("arg count mismatch: %v vs %v\n", Tconv(fn.Type.Params(), FmtSharp), hconv(n.List, FmtComma))
+ Fatalf("arg count mismatch: %#v vs %.v\n", fn.Type.Params(), n.List)
}
}
@@ -744,15 +776,14 @@ func mkinlcall1(n *Node, fn *Node, isddd bool) *Node {
// turn the variadic args into a slice.
if variadic {
- as = Nod(OAS, vararg, nil)
+ as = nod(OAS, vararg, nil)
if varargcount == 0 {
as.Right = nodnil()
as.Right.Type = varargtype
} else {
- vararrtype := typArray(varargtype.Elem(), int64(varargcount))
- as.Right = Nod(OCOMPLIT, nil, typenod(vararrtype))
+ varslicetype := typSlice(varargtype.Elem())
+ as.Right = nod(OCOMPLIT, nil, typenod(varslicetype))
as.Right.List.Set(varargs)
- as.Right = Nod(OSLICE, as.Right, nil)
}
as = typecheck(as, Etop)
@@ -761,29 +792,33 @@ func mkinlcall1(n *Node, fn *Node, isddd bool) *Node {
// zero the outparams
for _, n := range retvars {
- as = Nod(OAS, n, nil)
+ as = nod(OAS, n, nil)
as = typecheck(as, Etop)
ninit.Append(as)
}
- retlabel := newlabel_inl()
+ retlabel := autolabel(".i")
+ retlabel.Etype = 1 // flag 'safe' for escape analysis (no backjumps)
+
inlgen++
subst := inlsubst{
retlabel: retlabel,
retvars: retvars,
+ inlvars: inlvars,
}
body := subst.list(fn.Func.Inl)
- body = append(body, Nod(OGOTO, retlabel, nil)) // avoid 'not used' when function doesn't have return
- body = append(body, Nod(OLABEL, retlabel, nil))
+ lab := nod(OLABEL, retlabel, nil)
+ lab.Used = true // avoid 'not used' when function doesn't have return
+ body = append(body, lab)
typecheckslice(body, Etop)
//dumplist("ninit post", ninit);
- call := Nod(OINLCALL, nil, nil)
+ call := nod(OINLCALL, nil, nil)
call.Ninit.Set(ninit.Slice())
call.Nbody.Set(body)
@@ -821,7 +856,7 @@ func mkinlcall1(n *Node, fn *Node, isddd bool) *Node {
fn.Func.Inl.Set(body)
if Debug['m'] > 2 {
- fmt.Printf("%v: After inlining %v\n\n", n.Line(), Nconv(n, FmtSign))
+ fmt.Printf("%v: After inlining %+v\n\n", n.Line(), n)
}
return n
@@ -832,7 +867,7 @@ func mkinlcall1(n *Node, fn *Node, isddd bool) *Node {
// PPARAM's, PAUTOS and PPARAMOUTs of the called function.
func inlvar(var_ *Node) *Node {
if Debug['m'] > 3 {
- fmt.Printf("inlvar %v\n", Nconv(var_, FmtSign))
+ fmt.Printf("inlvar %+v\n", var_)
}
n := newname(var_.Sym)
@@ -842,20 +877,13 @@ func inlvar(var_ *Node) *Node {
n.Name.Curfn = Curfn // the calling function, not the called one
n.Addrtaken = var_.Addrtaken
- // This may no longer be necessary now that we run escape analysis
- // after wrapper generation, but for 1.5 this is conservatively left
- // unchanged. See bugs 11053 and 9537.
- if var_.Esc == EscHeap {
- addrescapes(n)
- }
-
Curfn.Func.Dcl = 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 {
- n := newname(LookupN("~r", i))
+ n := newname(lookupN("~r", i))
n.Type = t.Type
n.Class = PAUTO
n.Used = true
@@ -867,7 +895,7 @@ 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 {
- n := newname(LookupN("~arg", i))
+ n := newname(lookupN("~arg", i))
n.Type = t.Elem()
n.Class = PAUTO
n.Used = true
@@ -876,15 +904,6 @@ func argvar(t *Type, i int) *Node {
return n
}
-var newlabel_inl_label int
-
-func newlabel_inl() *Node {
- newlabel_inl_label++
- n := newname(LookupN(".inlret", newlabel_inl_label))
- n.Etype = 1 // flag 'safe' for escape analysis (no backjumps)
- return n
-}
-
// The inlsubst type implements the actual inlining of a single
// function call.
type inlsubst struct {
@@ -893,6 +912,8 @@ type inlsubst struct {
// Temporary result variables.
retvars []*Node
+
+ inlvars map[*Node]*Node
}
// list inlines a list of nodes.
@@ -915,15 +936,15 @@ func (subst *inlsubst) node(n *Node) *Node {
switch n.Op {
case ONAME:
- if n.Name.Inlvar != nil { // These will be set during inlnode
+ if inlvar := subst.inlvars[n]; inlvar != nil { // These will be set during inlnode
if Debug['m'] > 2 {
- fmt.Printf("substituting name %v -> %v\n", Nconv(n, FmtSign), Nconv(n.Name.Inlvar, FmtSign))
+ fmt.Printf("substituting name %+v -> %+v\n", n, inlvar)
}
- return n.Name.Inlvar
+ return inlvar
}
if Debug['m'] > 2 {
- fmt.Printf("not substituting name %v\n", Nconv(n, FmtSign))
+ fmt.Printf("not substituting name %+v\n", n)
}
return n
@@ -934,12 +955,12 @@ func (subst *inlsubst) node(n *Node) *Node {
// dump("Return before substitution", n);
case ORETURN:
- m := Nod(OGOTO, subst.retlabel, nil)
+ m := nod(OGOTO, subst.retlabel, nil)
m.Ninit.Set(subst.list(n.Ninit))
if len(subst.retvars) != 0 && n.List.Len() != 0 {
- as := Nod(OAS2, nil, nil)
+ as := nod(OAS2, nil, nil)
// Make a shallow copy of retvars.
// Otherwise OINLCALL.Rlist will be the same list,
@@ -959,20 +980,20 @@ func (subst *inlsubst) node(n *Node) *Node {
return m
case OGOTO, OLABEL:
- m := Nod(OXXX, nil, nil)
+ m := nod(OXXX, nil, nil)
*m = *n
m.Ninit.Set(nil)
p := fmt.Sprintf("%s·%d", n.Left.Sym.Name, inlgen)
- m.Left = newname(Lookup(p))
+ m.Left = newname(lookup(p))
return m
default:
- m := Nod(OXXX, nil, nil)
+ m := nod(OXXX, nil, nil)
*m = *n
m.Ninit.Set(nil)
if n.Op == OCLOSURE {
- Fatalf("cannot inline function containing closure: %v", Nconv(n, FmtSign))
+ Fatalf("cannot inline function containing closure: %+v", n)
}
m.Left = subst.node(n.Left)
@@ -1010,3 +1031,7 @@ func setlno(n *Node, lno int32) {
setlnolist(n.Ninit, lno)
setlnolist(n.Nbody, lno)
}
+
+func (n *Node) isMethodCalledAsFunction() bool {
+ return n.Left.Op == ONAME && n.Left.Left != nil && n.Left.Left.Op == OTYPE && n.Left.Right != nil && n.Left.Right.Op == ONAME
+}
diff --git a/src/cmd/compile/internal/gc/lex.go b/src/cmd/compile/internal/gc/lex.go
index f38819d..87f9bf2 100644
--- a/src/cmd/compile/internal/gc/lex.go
+++ b/src/cmd/compile/internal/gc/lex.go
@@ -5,20 +5,10 @@
package gc
import (
- "bufio"
- "bytes"
+ "cmd/compile/internal/syntax"
"cmd/internal/obj"
"fmt"
- "io"
- "strconv"
"strings"
- "unicode"
- "unicode/utf8"
-)
-
-const (
- EOF = -1
- BOM = 0xFEFF
)
// lexlineno is the line number _after_ the most recently read rune.
@@ -28,22 +18,10 @@ var lexlineno int32
// lineno is the line number at the start of the most recently lexed token.
var lineno int32
-var lexbuf bytes.Buffer
-var strbuf bytes.Buffer
-var litbuf string // LLITERAL value for use in syntax error messages
-
func isSpace(c rune) bool {
return c == ' ' || c == '\t' || c == '\n' || c == '\r'
}
-func isLetter(c rune) bool {
- return 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' || c == '_'
-}
-
-func isDigit(c rune) bool {
- return '0' <= c && c <= '9'
-}
-
func isQuoted(s string) bool {
return len(s) >= 2 && s[0] == '"' && s[len(s)-1] == '"'
}
@@ -60,791 +38,82 @@ func plan9quote(s string) string {
return s
}
-type Pragma uint16
-
-const (
- Nointerface Pragma = 1 << iota
- Noescape // func parameters don't escape
- Norace // func must not have race detector annotations
- Nosplit // func should not execute on separate stack
- Noinline // func should not be inlined
- Systemstack // func must run on system stack
- Nowritebarrier // emit compiler error instead of write barrier
- Nowritebarrierrec // error on write barrier in this or recursive callees
- CgoUnsafeArgs // treat a pointer to one arg as a pointer to them all
- UintptrEscapes // pointers converted to uintptr escape
-)
-
-type lexer struct {
- // source
- bin *bufio.Reader
- prevlineno int32 // line no. of most recently read character
-
- nlsemi bool // if set, '\n' and EOF translate to ';'
-
- // pragma flags
- // accumulated by lexer; reset by parser
- pragma Pragma
-
- // current token
- tok int32
- sym_ *Sym // valid if tok == LNAME
- val Val // valid if tok == LLITERAL
- op Op // valid if tok == LOPER, LASOP, or LINCOP, or prec > 0
- prec OpPrec // operator precedence; 0 if not a binary operator
-}
-
-type OpPrec int
-
-const (
- // Precedences of binary operators (must be > 0).
- PCOMM OpPrec = 1 + iota
- POROR
- PANDAND
- PCMP
- PADD
- PMUL
-)
+type Pragma syntax.Pragma
const (
- // The value of single-char tokens is just their character's Unicode value.
- // They are all below utf8.RuneSelf. Shift other tokens up to avoid conflicts.
-
- // names and literals
- LNAME = utf8.RuneSelf + iota
- LLITERAL
-
- // operator-based operations
- LOPER
- LASOP
- LINCOP
-
- // miscellaneous
- LCOLAS
- LCOMM
- LDDD
-
- // keywords
- LBREAK
- LCASE
- LCHAN
- LCONST
- LCONTINUE
- LDEFAULT
- LDEFER
- LELSE
- LFALL
- LFOR
- LFUNC
- LGO
- LGOTO
- LIF
- LIMPORT
- LINTERFACE
- LMAP
- LPACKAGE
- LRANGE
- LRETURN
- LSELECT
- LSTRUCT
- LSWITCH
- LTYPE
- LVAR
-
- LIGNORE
+ // 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
+
+ // Runtime-only func pragmas.
+ // See ../../../../runtime/README.md for detailed descriptions.
+ Systemstack // func must run on system stack
+ Nowritebarrier // emit compiler error instead of write barrier
+ Nowritebarrierrec // error on write barrier in this or recursive callees
+ Yeswritebarrierrec // cancels Nowritebarrierrec in this function and callees
+
+ // Runtime-only type pragmas
+ NotInHeap // values of this type must not be heap allocated
)
-var lexn = map[rune]string{
- LNAME: "NAME",
- LLITERAL: "LITERAL",
-
- LOPER: "OPER",
- LASOP: "ASOP",
- LINCOP: "INCOP",
-
- LCOLAS: "COLAS",
- LCOMM: "COMM",
- LDDD: "DDD",
-
- LBREAK: "BREAK",
- LCASE: "CASE",
- LCHAN: "CHAN",
- LCONST: "CONST",
- LCONTINUE: "CONTINUE",
- LDEFAULT: "DEFAULT",
- LDEFER: "DEFER",
- LELSE: "ELSE",
- LFALL: "FALL",
- LFOR: "FOR",
- LFUNC: "FUNC",
- LGO: "GO",
- LGOTO: "GOTO",
- LIF: "IF",
- LIMPORT: "IMPORT",
- LINTERFACE: "INTERFACE",
- LMAP: "MAP",
- LPACKAGE: "PACKAGE",
- LRANGE: "RANGE",
- LRETURN: "RETURN",
- LSELECT: "SELECT",
- LSTRUCT: "STRUCT",
- LSWITCH: "SWITCH",
- LTYPE: "TYPE",
- LVAR: "VAR",
-
- // LIGNORE is never escaping lexer.next
-}
-
-func lexname(lex rune) string {
- if s, ok := lexn[lex]; ok {
- return s
- }
- return fmt.Sprintf("LEX-%d", lex)
-}
-
-func (l *lexer) next() {
- nlsemi := l.nlsemi
- l.nlsemi = false
- l.prec = 0
-
-l0:
- // skip white space
- c := l.getr()
- for isSpace(c) {
- if c == '\n' && nlsemi {
- if Debug['x'] != 0 {
- fmt.Printf("lex: implicit semi\n")
- }
- // Insert implicit semicolon on previous line,
- // before the newline character.
- lineno = lexlineno - 1
- l.tok = ';'
- return
- }
- c = l.getr()
- }
-
- // start of token
- lineno = lexlineno
-
- // identifiers and keywords
- // (for better error messages consume all chars >= utf8.RuneSelf for identifiers)
- if isLetter(c) || c >= utf8.RuneSelf {
- l.ident(c)
- if l.tok == LIGNORE {
- goto l0
- }
- return
- }
- // c < utf8.RuneSelf
-
- var c1 rune
- var op Op
- var prec OpPrec
-
- switch c {
- case EOF:
- l.ungetr()
- // Treat EOF as "end of line" for the purposes
- // of inserting a semicolon.
- if nlsemi {
- if Debug['x'] != 0 {
- fmt.Printf("lex: implicit semi\n")
- }
- l.tok = ';'
- return
- }
- l.tok = -1
- return
-
- case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
- l.number(c)
- return
-
- case '.':
- c1 = l.getr()
- if isDigit(c1) {
- l.ungetr()
- l.number('.')
- return
- }
-
- if c1 == '.' {
- p, err := l.bin.Peek(1)
- if err == nil && p[0] == '.' {
- l.getr()
- c = LDDD
- goto lx
- }
-
- l.ungetr()
- c1 = '.'
- }
-
- case '"':
- l.stdString()
- return
-
- case '`':
- l.rawString()
- return
-
- case '\'':
- l.rune()
- return
-
- case '/':
- c1 = l.getr()
- if c1 == '*' {
- c = l.getr()
- for {
- if c == '*' {
- c = l.getr()
- if c == '/' {
- break
- }
- continue
- }
- if c == EOF {
- Yyerror("eof in comment")
- errorexit()
- }
- c = l.getr()
- }
-
- // A comment containing newlines acts like a newline.
- if lexlineno > lineno && nlsemi {
- if Debug['x'] != 0 {
- fmt.Printf("lex: implicit semi\n")
- }
- l.tok = ';'
- return
- }
- goto l0
- }
-
- if c1 == '/' {
- c = l.getlinepragma()
- for {
- if c == '\n' || c == EOF {
- l.ungetr()
- goto l0
- }
-
- c = l.getr()
- }
- }
-
- op = ODIV
- prec = PMUL
- goto binop1
-
- case ':':
- c1 = l.getr()
- if c1 == '=' {
- c = LCOLAS
- goto lx
- }
-
- case '*':
- op = OMUL
- prec = PMUL
- goto binop
-
- case '%':
- op = OMOD
- prec = PMUL
- goto binop
-
- case '+':
- op = OADD
- goto incop
-
- case '-':
- op = OSUB
- goto incop
-
- case '>':
- c = LOPER
- c1 = l.getr()
- if c1 == '>' {
- op = ORSH
- prec = PMUL
- goto binop
- }
-
- l.prec = PCMP
- if c1 == '=' {
- l.op = OGE
- goto lx
- }
- l.op = OGT
-
- case '<':
- c = LOPER
- c1 = l.getr()
- if c1 == '<' {
- op = OLSH
- prec = PMUL
- goto binop
- }
-
- if c1 == '-' {
- c = LCOMM
- // Not a binary operator, but parsed as one
- // so we can give a good error message when used
- // in an expression context.
- l.prec = PCOMM
- l.op = OSEND
- goto lx
- }
-
- l.prec = PCMP
- if c1 == '=' {
- l.op = OLE
- goto lx
- }
- l.op = OLT
-
- case '=':
- c1 = l.getr()
- if c1 == '=' {
- c = LOPER
- l.prec = PCMP
- l.op = OEQ
- goto lx
- }
-
- case '!':
- c1 = l.getr()
- if c1 == '=' {
- c = LOPER
- l.prec = PCMP
- l.op = ONE
- goto lx
- }
-
- case '&':
- c1 = l.getr()
- if c1 == '&' {
- c = LOPER
- l.prec = PANDAND
- l.op = OANDAND
- goto lx
- }
-
- if c1 == '^' {
- c = LOPER
- op = OANDNOT
- prec = PMUL
- goto binop
- }
-
- op = OAND
- prec = PMUL
- goto binop1
-
- case '|':
- c1 = l.getr()
- if c1 == '|' {
- c = LOPER
- l.prec = POROR
- l.op = OOROR
- goto lx
- }
-
- op = OOR
- prec = PADD
- goto binop1
-
- case '^':
- op = OXOR
- prec = PADD
- goto binop
-
- case '(', '[', '{', ',', ';':
- goto lx
-
- case ')', ']', '}':
- l.nlsemi = true
- goto lx
-
- case '#', '$', '?', '@', '\\':
- if importpkg != nil {
- goto lx
- }
- fallthrough
-
- default:
- // anything else is illegal
- Yyerror("syntax error: illegal character %#U", c)
- goto l0
- }
-
- l.ungetr()
-
-lx:
- if Debug['x'] != 0 {
- if c >= utf8.RuneSelf {
- fmt.Printf("%v lex: TOKEN %s\n", linestr(lineno), lexname(c))
- } else {
- fmt.Printf("%v lex: TOKEN '%c'\n", linestr(lineno), c)
- }
- }
-
- l.tok = c
- return
-
-incop:
- c1 = l.getr()
- if c1 == c {
- l.nlsemi = true
- l.op = op
- c = LINCOP
- goto lx
- }
- prec = PADD
- goto binop1
-
-binop:
- c1 = l.getr()
-binop1:
- if c1 != '=' {
- l.ungetr()
- l.op = op
- l.prec = prec
- goto lx
- }
-
- l.op = op
- if Debug['x'] != 0 {
- fmt.Printf("lex: TOKEN ASOP %s=\n", goopnames[op])
- }
- l.tok = LASOP
-}
-
-func (l *lexer) ident(c rune) {
- cp := &lexbuf
- cp.Reset()
-
- // accelerate common case (7bit ASCII)
- for isLetter(c) || isDigit(c) {
- cp.WriteByte(byte(c))
- c = l.getr()
- }
-
- // general case
- for {
- if c >= utf8.RuneSelf {
- if unicode.IsLetter(c) || c == '_' || unicode.IsDigit(c) || importpkg != nil && c == 0xb7 {
- if cp.Len() == 0 && unicode.IsDigit(c) {
- Yyerror("identifier cannot begin with digit %#U", c)
- }
- } else {
- Yyerror("invalid identifier character %#U", c)
- }
- cp.WriteRune(c)
- } else if isLetter(c) || isDigit(c) {
- cp.WriteByte(byte(c))
- } else {
- break
- }
- c = l.getr()
- }
-
- cp = nil
- l.ungetr()
-
- name := lexbuf.Bytes()
-
- if len(name) >= 2 {
- if tok, ok := keywords[string(name)]; ok {
- if Debug['x'] != 0 {
- fmt.Printf("lex: %s\n", lexname(tok))
- }
- switch tok {
- case LBREAK, LCONTINUE, LFALL, LRETURN:
- l.nlsemi = true
- }
- l.tok = tok
- return
- }
- }
-
- s := LookupBytes(name)
- if Debug['x'] != 0 {
- fmt.Printf("lex: ident %s\n", s)
- }
- l.sym_ = s
- l.nlsemi = true
- l.tok = LNAME
-}
-
-var keywords = map[string]int32{
- "break": LBREAK,
- "case": LCASE,
- "chan": LCHAN,
- "const": LCONST,
- "continue": LCONTINUE,
- "default": LDEFAULT,
- "defer": LDEFER,
- "else": LELSE,
- "fallthrough": LFALL,
- "for": LFOR,
- "func": LFUNC,
- "go": LGO,
- "goto": LGOTO,
- "if": LIF,
- "import": LIMPORT,
- "interface": LINTERFACE,
- "map": LMAP,
- "package": LPACKAGE,
- "range": LRANGE,
- "return": LRETURN,
- "select": LSELECT,
- "struct": LSTRUCT,
- "switch": LSWITCH,
- "type": LTYPE,
- "var": LVAR,
-
- // 💩
- "notwithstanding": LIGNORE,
- "thetruthofthematter": LIGNORE,
- "despiteallobjections": LIGNORE,
- "whereas": LIGNORE,
- "insofaras": LIGNORE,
-}
-
-func (l *lexer) number(c rune) {
- cp := &lexbuf
- cp.Reset()
-
- // parse mantissa before decimal point or exponent
- isInt := false
- malformedOctal := false
- if c != '.' {
- if c != '0' {
- // decimal or float
- for isDigit(c) {
- cp.WriteByte(byte(c))
- c = l.getr()
- }
-
- } else {
- // c == 0
- cp.WriteByte('0')
- c = l.getr()
- if c == 'x' || c == 'X' {
- isInt = true // must be int
- cp.WriteByte(byte(c))
- c = l.getr()
- for isDigit(c) || 'a' <= c && c <= 'f' || 'A' <= c && c <= 'F' {
- cp.WriteByte(byte(c))
- c = l.getr()
- }
- if lexbuf.Len() == 2 {
- Yyerror("malformed hex constant")
- }
- } else {
- // decimal 0, octal, or float
- for isDigit(c) {
- if c > '7' {
- malformedOctal = true
- }
- cp.WriteByte(byte(c))
- c = l.getr()
- }
- }
- }
- }
-
- // unless we have a hex number, parse fractional part or exponent, if any
- var str string
- if !isInt {
- isInt = true // assume int unless proven otherwise
-
- // fraction
- if c == '.' {
- isInt = false
- cp.WriteByte('.')
- c = l.getr()
- for isDigit(c) {
- cp.WriteByte(byte(c))
- c = l.getr()
- }
- // Falling through to exponent parsing here permits invalid
- // floating-point numbers with fractional mantissa and base-2
- // (p or P) exponent. We don't care because base-2 exponents
- // can only show up in machine-generated textual export data
- // which will use correct formatting.
- }
-
- // exponent
- // base-2 exponent (p or P) is only allowed in export data (see #9036)
- // TODO(gri) Once we switch to binary import data, importpkg will
- // always be nil in this function. Simplify the code accordingly.
- if c == 'e' || c == 'E' || importpkg != nil && (c == 'p' || c == 'P') {
- isInt = false
- cp.WriteByte(byte(c))
- c = l.getr()
- if c == '+' || c == '-' {
- cp.WriteByte(byte(c))
- c = l.getr()
- }
- if !isDigit(c) {
- Yyerror("malformed floating point constant exponent")
- }
- for isDigit(c) {
- cp.WriteByte(byte(c))
- c = l.getr()
- }
- }
-
- // imaginary constant
- if c == 'i' {
- str = lexbuf.String()
- x := new(Mpcplx)
- x.Real.SetFloat64(0.0)
- x.Imag.SetString(str)
- if x.Imag.Val.IsInf() {
- Yyerror("overflow in imaginary constant")
- x.Imag.SetFloat64(0.0)
- }
- l.val.U = x
-
- if Debug['x'] != 0 {
- fmt.Printf("lex: imaginary literal\n")
- }
- goto done
- }
- }
-
- l.ungetr()
-
- if isInt {
- if malformedOctal {
- Yyerror("malformed octal constant")
- }
-
- str = lexbuf.String()
- x := new(Mpint)
- x.SetString(str)
- if x.Ovf {
- Yyerror("overflow in constant")
- x.SetInt64(0)
- }
- l.val.U = x
-
- if Debug['x'] != 0 {
- fmt.Printf("lex: integer literal\n")
- }
-
- } else { // float
-
- str = lexbuf.String()
- x := newMpflt()
- x.SetString(str)
- if x.Val.IsInf() {
- Yyerror("overflow in float constant")
- x.SetFloat64(0.0)
- }
- l.val.U = x
-
- if Debug['x'] != 0 {
- fmt.Printf("lex: floating literal\n")
- }
- }
-
-done:
- litbuf = "" // lazily initialized in (*parser).syntax_error
- l.nlsemi = true
- l.tok = LLITERAL
-}
-
-func (l *lexer) stdString() {
- lexbuf.Reset()
- lexbuf.WriteString(`"<string>"`)
-
- cp := &strbuf
- cp.Reset()
-
- for {
- r, b, ok := l.onechar('"')
- if !ok {
- break
- }
- if r == 0 {
- cp.WriteByte(b)
- } else {
- cp.WriteRune(r)
- }
- }
-
- l.val.U = internString(cp.Bytes())
- if Debug['x'] != 0 {
- fmt.Printf("lex: string literal\n")
- }
- litbuf = "string literal"
- l.nlsemi = true
- l.tok = LLITERAL
-}
-
-func (l *lexer) rawString() {
- lexbuf.Reset()
- lexbuf.WriteString("`<string>`")
-
- cp := &strbuf
- cp.Reset()
-
- for {
- c := l.getr()
- if c == '\r' {
- continue
- }
- if c == EOF {
- Yyerror("eof in string")
- break
- }
- if c == '`' {
- break
- }
- cp.WriteRune(c)
- }
-
- l.val.U = internString(cp.Bytes())
- if Debug['x'] != 0 {
- fmt.Printf("lex: string literal\n")
- }
- litbuf = "string literal"
- l.nlsemi = true
- l.tok = LLITERAL
-}
-
-func (l *lexer) rune() {
- r, b, ok := l.onechar('\'')
- if !ok {
- Yyerror("empty character literal or unescaped ' in character literal")
- r = '\''
- }
- if r == 0 {
- r = rune(b)
- }
-
- if c := l.getr(); c != '\'' {
- Yyerror("missing '")
- l.ungetr()
- }
-
- x := new(Mpint)
- l.val.U = x
- x.SetInt64(int64(r))
- x.Rune = true
- if Debug['x'] != 0 {
- fmt.Printf("lex: codepoint literal\n")
- }
- litbuf = "rune literal"
- l.nlsemi = true
- l.tok = LLITERAL
+func pragmaValue(verb string) Pragma {
+ switch verb {
+ case "go:nointerface":
+ if obj.Fieldtrack_enabled != 0 {
+ return Nointerface
+ }
+ case "go:noescape":
+ return Noescape
+ case "go:norace":
+ return Norace
+ case "go:nosplit":
+ return Nosplit
+ 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
+ case "go:uintptrescapes":
+ // For the next function declared in the file
+ // any uintptr arguments may be pointer values
+ // converted to uintptr. This directive
+ // ensures that the referenced allocated
+ // object, if any, is retained and not moved
+ // until the call completes, even though from
+ // the types alone it would appear that the
+ // object is no longer needed during the
+ // call. The conversion to uintptr must appear
+ // in the argument list.
+ // Used in syscall/dll_windows.go.
+ return UintptrEscapes
+ case "go:notinheap":
+ return NotInHeap
+ }
+ return 0
}
var internedStrings = map[string]string{}
@@ -858,148 +127,6 @@ func internString(b []byte) string {
return s
}
-// read and interpret syntax that looks like
-// //line parse.y:15
-// as a discontinuity in sequential line numbers.
-// the next line of input comes from parse.y:15
-func (l *lexer) getlinepragma() rune {
- c := l.getr()
- if c == 'g' { // check for //go: directive
- cp := &lexbuf
- cp.Reset()
- cp.WriteByte('g') // already read
- for {
- c = l.getr()
- if c == EOF || c >= utf8.RuneSelf {
- return c
- }
- if c == '\n' {
- break
- }
- cp.WriteByte(byte(c))
- }
- cp = nil
-
- text := strings.TrimSuffix(lexbuf.String(), "\r")
-
- if strings.HasPrefix(text, "go:cgo_") {
- pragcgobuf += pragcgo(text)
- }
-
- verb := text
- if i := strings.Index(text, " "); i >= 0 {
- verb = verb[:i]
- }
-
- switch verb {
- case "go:linkname":
- if !imported_unsafe {
- Yyerror("//go:linkname only allowed in Go files that import \"unsafe\"")
- }
- f := strings.Fields(text)
- if len(f) != 3 {
- Yyerror("usage: //go:linkname localname linkname")
- break
- }
- Lookup(f[1]).Linkname = f[2]
- case "go:nointerface":
- if obj.Fieldtrack_enabled != 0 {
- l.pragma |= Nointerface
- }
- case "go:noescape":
- l.pragma |= Noescape
- case "go:norace":
- l.pragma |= Norace
- case "go:nosplit":
- l.pragma |= Nosplit
- case "go:noinline":
- l.pragma |= Noinline
- case "go:systemstack":
- if !compiling_runtime {
- Yyerror("//go:systemstack only allowed in runtime")
- }
- l.pragma |= Systemstack
- case "go:nowritebarrier":
- if !compiling_runtime {
- Yyerror("//go:nowritebarrier only allowed in runtime")
- }
- l.pragma |= Nowritebarrier
- case "go:nowritebarrierrec":
- if !compiling_runtime {
- Yyerror("//go:nowritebarrierrec only allowed in runtime")
- }
- l.pragma |= Nowritebarrierrec | Nowritebarrier // implies Nowritebarrier
- case "go:cgo_unsafe_args":
- l.pragma |= CgoUnsafeArgs
- case "go:uintptrescapes":
- // For the next function declared in the file
- // any uintptr arguments may be pointer values
- // converted to uintptr. This directive
- // ensures that the referenced allocated
- // object, if any, is retained and not moved
- // until the call completes, even though from
- // the types alone it would appear that the
- // object is no longer needed during the
- // call. The conversion to uintptr must appear
- // in the argument list.
- // Used in syscall/dll_windows.go.
- l.pragma |= UintptrEscapes
- }
- return c
- }
-
- // check for //line directive
- if c != 'l' {
- return c
- }
- for i := 1; i < 5; i++ {
- c = l.getr()
- if c != rune("line "[i]) {
- return c
- }
- }
-
- cp := &lexbuf
- cp.Reset()
- linep := 0
- for {
- c = l.getr()
- if c == EOF {
- return c
- }
- if c == '\n' {
- break
- }
- if c == ' ' {
- continue
- }
- if c == ':' {
- linep = cp.Len() + 1
- }
- cp.WriteByte(byte(c))
- }
- cp = nil
-
- if linep == 0 {
- return c
- }
- text := strings.TrimSuffix(lexbuf.String(), "\r")
- n, err := strconv.Atoi(text[linep:])
- if err != nil {
- return c // todo: make this an error instead? it is almost certainly a bug.
- }
- if n > 1e8 {
- Yyerror("line number out of range")
- errorexit()
- }
- if n <= 0 {
- return c
- }
-
- linehistupdate(text[:linep-1], n)
- return c
-}
-
func pragcgo(text string) string {
f := pragmaFields(text)
@@ -1017,7 +144,7 @@ func pragcgo(text string) string {
return fmt.Sprintln(verb, local, remote)
default:
- Yyerror(`usage: //go:%s local [remote]`, verb)
+ yyerror(`usage: //go:%s local [remote]`, verb)
}
case "cgo_import_dynamic":
switch {
@@ -1037,7 +164,7 @@ func pragcgo(text string) string {
return fmt.Sprintln(verb, local, remote, library)
default:
- Yyerror(`usage: //go:cgo_import_dynamic local [remote ["library"]]`)
+ yyerror(`usage: //go:cgo_import_dynamic local [remote ["library"]]`)
}
case "cgo_import_static":
switch {
@@ -1046,7 +173,7 @@ func pragcgo(text string) string {
return fmt.Sprintln(verb, local)
default:
- Yyerror(`usage: //go:cgo_import_static local`)
+ yyerror(`usage: //go:cgo_import_static local`)
}
case "cgo_dynamic_linker":
switch {
@@ -1055,7 +182,7 @@ func pragcgo(text string) string {
return fmt.Sprintln(verb, path)
default:
- Yyerror(`usage: //go:cgo_dynamic_linker "path"`)
+ yyerror(`usage: //go:cgo_dynamic_linker "path"`)
}
case "cgo_ldflag":
switch {
@@ -1064,7 +191,7 @@ func pragcgo(text string) string {
return fmt.Sprintln(verb, arg)
default:
- Yyerror(`usage: //go:cgo_ldflag "arg"`)
+ yyerror(`usage: //go:cgo_ldflag "arg"`)
}
}
return ""
@@ -1109,150 +236,3 @@ func pragmaFields(s string) []string {
}
return a
}
-
-func (l *lexer) getr() rune {
-redo:
- l.prevlineno = lexlineno
- r, w, err := l.bin.ReadRune()
- if err != nil {
- if err != io.EOF {
- Fatalf("io error: %v", err)
- }
- return -1
- }
- switch r {
- case 0:
- yyerrorl(lexlineno, "illegal NUL byte")
- case '\n':
- if importpkg == nil {
- lexlineno++
- }
- case utf8.RuneError:
- if w == 1 {
- yyerrorl(lexlineno, "illegal UTF-8 sequence")
- }
- case BOM:
- yyerrorl(lexlineno, "Unicode (UTF-8) BOM in middle of file")
- goto redo
- }
-
- return r
-}
-
-func (l *lexer) ungetr() {
- l.bin.UnreadRune()
- lexlineno = l.prevlineno
-}
-
-// onechar lexes a single character within a rune or interpreted string literal,
-// handling escape sequences as necessary.
-func (l *lexer) onechar(quote rune) (r rune, b byte, ok bool) {
- c := l.getr()
- switch c {
- case EOF:
- Yyerror("eof in string")
- l.ungetr()
- return
-
- case '\n':
- Yyerror("newline in string")
- l.ungetr()
- return
-
- case '\\':
- break
-
- case quote:
- return
-
- default:
- return c, 0, true
- }
-
- c = l.getr()
- switch c {
- case 'x':
- return 0, byte(l.hexchar(2)), true
-
- case 'u':
- return l.unichar(4), 0, true
-
- case 'U':
- return l.unichar(8), 0, true
-
- case '0', '1', '2', '3', '4', '5', '6', '7':
- x := c - '0'
- for i := 2; i > 0; i-- {
- c = l.getr()
- if c >= '0' && c <= '7' {
- x = x*8 + c - '0'
- continue
- }
-
- Yyerror("non-octal character in escape sequence: %c", c)
- l.ungetr()
- }
-
- if x > 255 {
- Yyerror("octal escape value > 255: %d", x)
- }
-
- return 0, byte(x), true
-
- case 'a':
- c = '\a'
- case 'b':
- c = '\b'
- case 'f':
- c = '\f'
- case 'n':
- c = '\n'
- case 'r':
- c = '\r'
- case 't':
- c = '\t'
- case 'v':
- c = '\v'
- case '\\':
- c = '\\'
-
- default:
- if c != quote {
- Yyerror("unknown escape sequence: %c", c)
- }
- }
-
- return c, 0, true
-}
-
-func (l *lexer) unichar(n int) rune {
- x := l.hexchar(n)
- if x > utf8.MaxRune || 0xd800 <= x && x < 0xe000 {
- Yyerror("invalid Unicode code point in escape sequence: %#x", x)
- x = utf8.RuneError
- }
- return rune(x)
-}
-
-func (l *lexer) hexchar(n int) uint32 {
- var x uint32
-
- for ; n > 0; n-- {
- var d uint32
- switch c := l.getr(); {
- case isDigit(c):
- d = uint32(c - '0')
- case 'a' <= c && c <= 'f':
- d = uint32(c - 'a' + 10)
- case 'A' <= c && c <= 'F':
- d = uint32(c - 'A' + 10)
- default:
- Yyerror("non-hex character in escape sequence: %c", c)
- l.ungetr()
- return x
- }
- x = x*16 + d
- }
-
- return x
-}
diff --git a/src/cmd/compile/internal/gc/magic.go b/src/cmd/compile/internal/gc/magic.go
index f8eb182..4da30c4 100644
--- a/src/cmd/compile/internal/gc/magic.go
+++ b/src/cmd/compile/internal/gc/magic.go
@@ -25,7 +25,7 @@ type Magic struct {
// magic number for signed division
// see hacker's delight chapter 10
-func Smagic(m *Magic) {
+func smagic(m *Magic) {
var mask uint64
m.Bad = 0
@@ -120,7 +120,7 @@ func Smagic(m *Magic) {
// magic number for unsigned division
// see hacker's delight chapter 10
-func Umagic(m *Magic) {
+func umagic(m *Magic) {
var mask uint64
m.Bad = 0
diff --git a/src/cmd/compile/internal/gc/main.go b/src/cmd/compile/internal/gc/main.go
index b4df7ed..75f58a7 100644
--- a/src/cmd/compile/internal/gc/main.go
+++ b/src/cmd/compile/internal/gc/main.go
@@ -8,6 +8,7 @@ package gc
import (
"bufio"
+ "bytes"
"cmd/compile/internal/ssa"
"cmd/internal/obj"
"cmd/internal/sys"
@@ -25,9 +26,6 @@ import (
var imported_unsafe bool
var (
- goos string
- goarch string
- goroot string
buildid string
)
@@ -49,7 +47,7 @@ var debugtab = []struct {
}{
{"append", &Debug_append}, // print information about append compilation
{"closure", &Debug_closure}, // print information about closure compilation
- {"disablenil", &Disable_checknil}, // disable nil checks
+ {"disablenil", &disable_checknil}, // disable nil checks
{"gcprog", &Debug_gcprog}, // print dump of GC programs
{"nil", &Debug_checknil}, // print information about nil checks
{"panic", &Debug_panic}, // do not hide any compiler panic
@@ -86,7 +84,7 @@ func doversion() {
if p != "" {
sep = " "
}
- fmt.Printf("compile version %s%s%s\n", obj.Getgoversion(), sep, p)
+ fmt.Printf("compile version %s%s%s\n", obj.Version, sep, p)
os.Exit(0)
}
@@ -96,20 +94,24 @@ func supportsDynlink(arch *sys.Arch) bool {
return arch.InFamily(sys.AMD64, sys.ARM, sys.ARM64, sys.I386, sys.PPC64, sys.S390X)
}
+// timing data for compiler phases
+var timings Timings
+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() {
- defer hidePanic()
+ timings.Start("fe", "init")
- goarch = obj.Getgoarch()
+ defer hidePanic()
Ctxt = obj.Linknew(Thearch.LinkArch)
- Ctxt.DiagFunc = Yyerror
- bstdout = bufio.NewWriter(os.Stdout)
- Ctxt.Bso = bstdout
+ Ctxt.DiagFunc = yyerror
+ Ctxt.Bso = bufio.NewWriter(os.Stdout)
localpkg = mkpkg("")
localpkg.Prefix = "\"\""
- autopkg = mkpkg("")
- autopkg.Prefix = "\"\""
// pseudo-package, for scoping
builtinpkg = mkpkg("go.builtin")
@@ -144,26 +146,19 @@ func Main() {
mappkg.Name = "go.map"
mappkg.Prefix = "go.map"
- goroot = obj.Getgoroot()
- goos = obj.Getgoos()
-
- Nacl = goos == "nacl"
+ Nacl = obj.GOOS == "nacl"
if Nacl {
flag_largemodel = true
}
flag.BoolVar(&compiling_runtime, "+", false, "compiling runtime")
obj.Flagcount("%", "debug non-static initializers", &Debug['%'])
- obj.Flagcount("A", "for bootstrapping, allow 'any' type", &Debug['A'])
obj.Flagcount("B", "disable bounds checking", &Debug['B'])
flag.StringVar(&localimport, "D", "", "set relative `path` for local imports")
obj.Flagcount("E", "debug symbol export", &Debug['E'])
obj.Flagfn1("I", "add `directory` to import search path", addidir)
obj.Flagcount("K", "debug missing line numbers", &Debug['K'])
- obj.Flagcount("M", "debug move generation", &Debug['M'])
obj.Flagcount("N", "disable optimizations", &Debug['N'])
- obj.Flagcount("P", "debug peephole optimizer", &Debug['P'])
- obj.Flagcount("R", "debug register optimizer", &Debug['R'])
obj.Flagcount("S", "print assembly listing", &Debug['S'])
obj.Flagfn0("V", "print compiler version", doversion)
obj.Flagcount("W", "debug parse tree after type checking", &Debug['W'])
@@ -173,7 +168,6 @@ func Main() {
flag.StringVar(&debugstr, "d", "", "print debug information about items in `list`")
obj.Flagcount("e", "no limit on number of errors reported", &Debug['e'])
obj.Flagcount("f", "debug stack frames", &Debug['f'])
- obj.Flagcount("g", "debug code generation", &Debug['g'])
obj.Flagcount("h", "halt on error", &Debug['h'])
obj.Flagcount("i", "debug line number stack", &Debug['i'])
obj.Flagfn1("importmap", "add `definition` of the form source=actual to import map", addImportMap)
@@ -184,7 +178,6 @@ func Main() {
obj.Flagcount("live", "debug liveness analysis", &debuglive)
obj.Flagcount("m", "print optimization decisions", &Debug['m'])
flag.BoolVar(&flag_msan, "msan", false, "build code compatible with C/C++ memory sanitizer")
- flag.BoolVar(&newexport, "newexport", true, "use new export format") // TODO(gri) remove eventually (issue 15323)
flag.BoolVar(&nolocalimports, "nolocalimports", false, "reject local (relative) imports")
flag.StringVar(&outfile, "o", "", "write output to `file`")
flag.StringVar(&myimportpath, "p", "", "set expected package import `path`")
@@ -197,7 +190,6 @@ func Main() {
obj.Flagcount("v", "increase debug verbosity", &Debug['v'])
obj.Flagcount("w", "debug type checking", &Debug['w'])
flag.BoolVar(&use_writebarrier, "wb", true, "enable write barrier")
- obj.Flagcount("x", "debug lexer", &Debug['x'])
var flag_shared bool
var flag_dynlink bool
if supportsDynlink(Thearch.LinkArch.Arch) {
@@ -210,7 +202,8 @@ func Main() {
flag.StringVar(&cpuprofile, "cpuprofile", "", "write cpu profile to `file`")
flag.StringVar(&memprofile, "memprofile", "", "write memory profile to `file`")
flag.Int64Var(&memprofilerate, "memprofilerate", 0, "set runtime.MemProfileRate to `rate`")
- flag.BoolVar(&ssaEnabled, "ssa", true, "use SSA backend to generate code")
+ flag.StringVar(&traceprofile, "traceprofile", "", "write an execution trace to `file`")
+ flag.StringVar(&benchfile, "bench", "", "append benchmark times to `file`")
obj.Flagparse(usage)
Ctxt.Flag_shared = flag_dynlink || flag_shared
@@ -248,6 +241,7 @@ func Main() {
continue
}
val := 1
+ valstring := ""
if i := strings.Index(name, "="); i >= 0 {
var err error
val, err = strconv.Atoi(name[i+1:])
@@ -255,6 +249,9 @@ func Main() {
log.Fatalf("invalid debug value %v", name)
}
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 {
@@ -275,7 +272,7 @@ func Main() {
flag = phase[i+1:]
phase = phase[:i]
}
- err := ssa.PhaseOption(phase, flag, val)
+ err := ssa.PhaseOption(phase, flag, val, valstring)
if err != "" {
log.Fatalf(err)
}
@@ -293,7 +290,6 @@ func Main() {
Debug['l'] = 1 - Debug['l']
}
- Thearch.Betypeinit()
Widthint = Thearch.LinkArch.IntSize
Widthptr = Thearch.LinkArch.PtrSize
Widthreg = Thearch.LinkArch.RegSize
@@ -305,33 +301,17 @@ func Main() {
nerrors = 0
lexlineno = 1
+ timings.Start("fe", "loadsys")
loadsys()
+ timings.Start("fe", "parse")
+ lexlineno0 := lexlineno
for _, infile = range flag.Args() {
- if trace && Debug['x'] != 0 {
- fmt.Printf("--- %s ---\n", infile)
- }
-
linehistpush(infile)
-
- f, err := os.Open(infile)
- if err != nil {
- fmt.Printf("open %s: %v\n", infile, err)
- errorexit()
- }
- bin := bufio.NewReader(f)
-
- // Skip initial BOM if present.
- if r, _, _ := bin.ReadRune(); r != BOM {
- bin.UnreadRune()
- }
-
block = 1
iota_ = -1000000
-
imported_unsafe = false
-
- parse_file(bin)
+ parseFile(infile)
if nsyntaxerrors != 0 {
errorexit()
}
@@ -340,10 +320,10 @@ func Main() {
// for the line history to work, and which then has to be corrected elsewhere,
// just add a line here.
lexlineno++
-
linehistpop()
- f.Close()
}
+ timings.Stop()
+ timings.AddEvent(int64(lexlineno-lexlineno0), "lines")
testdclstack()
mkpackage(localpkg.Name) // final import not used checks
@@ -362,6 +342,7 @@ func Main() {
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)
@@ -372,6 +353,7 @@ func Main() {
// To check interface assignments, depends on phase 1.
// 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)
@@ -381,6 +363,8 @@ func Main() {
// Phase 3: Type check function bodies.
// Don't use range--typecheck can add closures to xtop.
+ 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]
@@ -391,12 +375,15 @@ func Main() {
if nerrors != 0 {
Curfn.Nbody.Set(nil) // type errors; do not compile
}
+ fcount++
}
}
+ timings.AddEvent(fcount, "funcs")
// Phase 4: Decide how to capture closed variables.
// This needs to run before escape analysis,
// because variables captured by value do not escape.
+ timings.Start("fe", "capturevars")
for _, n := range xtop {
if n.Op == ODCLFUNC && n.Func.Closure != nil {
Curfn = n
@@ -411,6 +398,7 @@ func Main() {
}
// Phase 5: Inlining
+ timings.Start("fe", "inlining")
if Debug['l'] > 1 {
// Typecheck imported function bodies if debug['l'] > 1,
// otherwise lazily when used or re-exported.
@@ -430,10 +418,14 @@ func Main() {
// Find functions that can be inlined and clone them before walk expands them.
visitBottomUp(xtop, func(list []*Node, recursive bool) {
for _, n := range list {
- if n.Op == ODCLFUNC {
+ if !recursive {
caninl(n)
- inlcalls(n)
+ } else {
+ if Debug['m'] > 1 {
+ fmt.Printf("%v: cannot inline %v: recursive\n", n.Line(), n.Func.Nname)
+ }
}
+ inlcalls(n)
}
})
}
@@ -446,11 +438,13 @@ func Main() {
// or else the stack copier will not update it.
// Large values are also moved off stack in escape analysis;
// because large values may contain pointers, it must happen early.
+ 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
@@ -462,11 +456,15 @@ func Main() {
// 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++
}
}
+ timings.AddEvent(fcount, "funcs")
if nsavederrors+nerrors == 0 {
fninit(xtop)
@@ -477,6 +475,7 @@ func Main() {
}
// Phase 9: Check external declarations.
+ timings.Start("be", "externaldcls")
for i, n := range externdcl {
if n.Op == ONAME {
externdcl[i] = typecheck(externdcl[i], Erv)
@@ -487,8 +486,9 @@ func Main() {
errorexit()
}
+ // Write object data to disk.
+ timings.Start("be", "dumpobj")
dumpobj()
-
if asmhdr != "" {
dumpasmhdr()
}
@@ -497,7 +497,37 @@ func Main() {
errorexit()
}
- Flusherrors()
+ flusherrors()
+ timings.Stop()
+
+ if benchfile != "" {
+ if err := writebench(benchfile); err != nil {
+ log.Fatalf("cannot write benchmark data: %v", err)
+ }
+ }
+}
+
+func writebench(filename string) error {
+ f, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666)
+ if err != nil {
+ return err
+ }
+
+ var buf bytes.Buffer
+ fmt.Fprintln(&buf, "commit:", obj.Version)
+ fmt.Fprintln(&buf, "goos:", runtime.GOOS)
+ fmt.Fprintln(&buf, "goarch:", runtime.GOARCH)
+ timings.Write(&buf, "BenchmarkCompile:"+myimportpath+":")
+
+ n, err := f.Write(buf.Bytes())
+ if err != nil {
+ return err
+ }
+ if n != buf.Len() {
+ panic("bad writer")
+ }
+
+ return f.Close()
}
var importMap = map[string]string{}
@@ -592,7 +622,7 @@ func findpkg(name string) (file string, ok bool) {
// don't want to see "encoding/../encoding/base64"
// as different from "encoding/base64".
if q := path.Clean(name); q != name {
- Yyerror("non-canonical import path %q (should be %q)", name, q)
+ yyerror("non-canonical import path %q (should be %q)", name, q)
return "", false
}
@@ -607,7 +637,7 @@ func findpkg(name string) (file string, ok bool) {
}
}
- if goroot != "" {
+ if obj.GOROOT != "" {
suffix := ""
suffixsep := ""
if flag_installsuffix != "" {
@@ -621,11 +651,11 @@ func findpkg(name string) (file string, ok bool) {
suffix = "msan"
}
- file = fmt.Sprintf("%s/pkg/%s_%s%s%s/%s.a", goroot, goos, goarch, suffixsep, suffix, name)
+ file = fmt.Sprintf("%s/pkg/%s_%s%s%s/%s.a", obj.GOROOT, obj.GOOS, obj.GOARCH, suffixsep, suffix, name)
if _, err := os.Stat(file); err == nil {
return file, true
}
- file = fmt.Sprintf("%s/pkg/%s_%s%s%s/%s.o", goroot, goos, goarch, suffixsep, suffix, name)
+ file = fmt.Sprintf("%s/pkg/%s_%s%s%s/%s.o", obj.GOROOT, obj.GOOS, obj.GOARCH, suffixsep, suffix, name)
if _, err := os.Stat(file); err == nil {
return file, true
}
@@ -634,39 +664,37 @@ func findpkg(name string) (file string, ok bool) {
return "", false
}
-// loadsys loads the definitions for the low-level runtime and unsafe functions,
+// loadsys loads the definitions for the low-level runtime functions,
// so that the compiler can generate calls to them,
-// but does not make the names "runtime" or "unsafe" visible as packages.
+// but does not make them visible to user code.
func loadsys() {
- if Debug['A'] != 0 {
- return
- }
-
block = 1
iota_ = -1000000
- incannedimport = 1
-
- // The first byte in the binary export format is a 'c' or 'd'
- // specifying the encoding format. We could just check that
- // byte, but this is a perhaps more robust. Also, it is not
- // speed-critical.
- // TODO(gri) simplify once textual export format has gone
- if strings.HasPrefix(runtimeimport, "package") {
- // textual export format
- importpkg = Runtimepkg
- parse_import(bufio.NewReader(strings.NewReader(runtimeimport)), nil)
- importpkg = unsafepkg
- parse_import(bufio.NewReader(strings.NewReader(unsafeimport)), nil)
- } else {
- // binary export format
- importpkg = Runtimepkg
- Import(bufio.NewReader(strings.NewReader(runtimeimport)))
- importpkg = unsafepkg
- Import(bufio.NewReader(strings.NewReader(unsafeimport)))
+
+ importpkg = Runtimepkg
+ typecheckok = true
+ defercheckwidth()
+
+ typs := runtimeTypes()
+ for _, d := range runtimeDecls {
+ sym := Pkglookup(d.name, importpkg)
+ typ := typs[d.typ]
+ switch d.tag {
+ case funcTag:
+ importsym(sym, ONAME)
+ n := newfuncname(sym)
+ n.Type = typ
+ declare(n, PFUNC)
+ case varTag:
+ importvar(sym, typ)
+ default:
+ Fatalf("unhandled declaration tag %v", d.tag)
+ }
}
+ typecheckok = false
+ resumecheckwidth()
importpkg = nil
- incannedimport = 0
}
func importfile(f *Val, indent []byte) {
@@ -676,12 +704,12 @@ func importfile(f *Val, indent []byte) {
path_, ok := f.U.(string)
if !ok {
- Yyerror("import statement not a string")
+ yyerror("import statement not a string")
return
}
if len(path_) == 0 {
- Yyerror("import path is empty")
+ yyerror("import path is empty")
return
}
@@ -694,12 +722,12 @@ func importfile(f *Val, indent []byte) {
// the main package, just as we reserve the import
// path "math" to identify the standard math package.
if path_ == "main" {
- Yyerror("cannot import \"main\"")
+ yyerror("cannot import \"main\"")
errorexit()
}
if myimportpath != "" && path_ == myimportpath {
- Yyerror("import %q while compiling that package (import cycle)", path_)
+ yyerror("import %q while compiling that package (import cycle)", path_)
errorexit()
}
@@ -709,7 +737,7 @@ func importfile(f *Val, indent []byte) {
if path_ == "unsafe" {
if safemode {
- Yyerror("cannot import package unsafe")
+ yyerror("cannot import package unsafe")
errorexit()
}
@@ -720,7 +748,7 @@ func importfile(f *Val, indent []byte) {
if islocalname(path_) {
if path_[0] == '/' {
- Yyerror("import path cannot be absolute path")
+ yyerror("import path cannot be absolute path")
return
}
@@ -737,7 +765,7 @@ func importfile(f *Val, indent []byte) {
file, found := findpkg(path_)
if !found {
- Yyerror("can't find import: %q", path_)
+ yyerror("can't find import: %q", path_)
errorexit()
}
@@ -751,7 +779,7 @@ func importfile(f *Val, indent []byte) {
impf, err := os.Open(file)
if err != nil {
- Yyerror("can't open import: %q: %v", path_, err)
+ yyerror("can't open import: %q: %v", path_, err)
errorexit()
}
defer impf.Close()
@@ -759,7 +787,7 @@ func importfile(f *Val, indent []byte) {
if strings.HasSuffix(file, ".a") {
if !skiptopkgdef(imp) {
- Yyerror("import %s: not a package file", file)
+ yyerror("import %s: not a package file", file)
errorexit()
}
}
@@ -775,18 +803,19 @@ func importfile(f *Val, indent []byte) {
if p != "empty archive" {
if !strings.HasPrefix(p, "go object ") {
- Yyerror("import %s: not a go object file: %s", file, p)
+ yyerror("import %s: not a go object file: %s", file, p)
errorexit()
}
- q := fmt.Sprintf("%s %s %s %s", obj.Getgoos(), obj.Getgoarch(), obj.Getgoversion(), obj.Expstring())
+ q := fmt.Sprintf("%s %s %s %s", obj.GOOS, obj.GOARCH, obj.Version, obj.Expstring())
if p[10:] != q {
- Yyerror("import %s: object is [%s] expected [%s]", file, p[10:], q)
+ yyerror("import %s: object is [%s] expected [%s]", file, p[10:], q)
errorexit()
}
}
// process header lines
+ safe := false
for {
p, err = imp.ReadString('\n')
if err != nil {
@@ -796,18 +825,21 @@ func importfile(f *Val, indent []byte) {
break // header ends with blank line
}
if strings.HasPrefix(p, "safe") {
- importpkg.Safe = true
+ safe = true
break // ok to ignore rest
}
}
+ if safemode && !safe {
+ 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
// In the importfile, if we find:
- // $$\n (old format): position the input right after $$\n and return
- // $$B\n (new format): import directly, then feed the lexer a dummy statement
+ // $$\n (textual format): not supported anymore
+ // $$B\n (binary format) : import directly, then feed the lexer a dummy statement
// look for $$
var c byte
@@ -831,11 +863,9 @@ func importfile(f *Val, indent []byte) {
switch c {
case '\n':
- // old export format
- parse_import(imp, indent)
+ yyerror("cannot import %s: old export format no longer supported (recompile library)", path_)
case 'B':
- // new export format
if Debug_export != 0 {
fmt.Printf("importing %s (%s)\n", path_, file)
}
@@ -843,13 +873,9 @@ func importfile(f *Val, indent []byte) {
Import(imp)
default:
- Yyerror("no import in %q", path_)
+ yyerror("no import in %q", path_)
errorexit()
}
-
- if safemode && !importpkg.Safe {
- Yyerror("cannot import unsafe package %q", importpkg.Path)
- }
}
func pkgnotused(lineno int32, path string, name string) {
@@ -873,12 +899,12 @@ func pkgnotused(lineno int32, path string, name string) {
func mkpackage(pkgname string) {
if localpkg.Name == "" {
if pkgname == "_" {
- Yyerror("invalid package name _")
+ yyerror("invalid package name _")
}
localpkg.Name = pkgname
} else {
if pkgname != localpkg.Name {
- Yyerror("package %s; expected %s", pkgname, localpkg.Name)
+ yyerror("package %s; expected %s", pkgname, localpkg.Name)
}
for _, s := range localpkg.Syms {
if s.Def == nil {
@@ -897,7 +923,7 @@ func mkpackage(pkgname string) {
continue
}
- if s.Def.Sym != s {
+ 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 {
diff --git a/src/cmd/compile/internal/gc/mkbuiltin.go b/src/cmd/compile/internal/gc/mkbuiltin.go
index 58cbd24..995f5be 100644
--- a/src/cmd/compile/internal/gc/mkbuiltin.go
+++ b/src/cmd/compile/internal/gc/mkbuiltin.go
@@ -1,25 +1,28 @@
-// Copyright 2009 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 ignore
-// Generate builtin.go from builtin/runtime.go and builtin/unsafe.go.
-// Run this after changing builtin/runtime.go and builtin/unsafe.go
-// or after changing the export metadata format in the compiler.
-// Either way, you need to have a working compiler binary first.
-// See bexport.go for how to make an export metadata format change.
+// Generate builtin.go from builtin/runtime.go.
+
package main
import (
"bytes"
"flag"
"fmt"
+ "go/ast"
+ "go/format"
+ "go/parser"
+ "go/token"
"io"
"io/ioutil"
"log"
"os"
- "os/exec"
+ "path/filepath"
+ "strconv"
+ "strings"
)
var stdout = flag.Bool("stdout", false, "write to stdout instead of builtin.go")
@@ -29,85 +32,181 @@ func main() {
var b bytes.Buffer
fmt.Fprintln(&b, "// AUTO-GENERATED by mkbuiltin.go; DO NOT EDIT")
- fmt.Fprintln(&b, "")
+ fmt.Fprintln(&b)
fmt.Fprintln(&b, "package gc")
mkbuiltin(&b, "runtime")
- mkbuiltin(&b, "unsafe")
- var err error
+ out, err := format.Source(b.Bytes())
+ if err != nil {
+ log.Fatal(err)
+ }
if *stdout {
- _, err = os.Stdout.Write(b.Bytes())
+ _, err = os.Stdout.Write(out)
} else {
- err = ioutil.WriteFile("builtin.go", b.Bytes(), 0666)
+ err = ioutil.WriteFile("builtin.go", out, 0666)
}
if err != nil {
log.Fatal(err)
}
}
-// Compile .go file, import data from .o file, and write Go string version.
func mkbuiltin(w io.Writer, name string) {
- args := []string{"tool", "compile", "-A"}
- if name == "runtime" {
- args = append(args, "-u")
+ fset := token.NewFileSet()
+ f, err := parser.ParseFile(fset, filepath.Join("builtin", name+".go"), nil, 0)
+ if err != nil {
+ log.Fatal(err)
}
- args = append(args, "builtin/"+name+".go")
- if err := exec.Command("go", args...).Run(); err != nil {
- log.Fatal(err)
+ var interner typeInterner
+
+ fmt.Fprintf(w, "var %sDecls = [...]struct { name string; tag int; typ int }{\n", name)
+ for _, decl := range f.Decls {
+ switch decl := decl.(type) {
+ case *ast.FuncDecl:
+ if decl.Recv != nil {
+ log.Fatal("methods unsupported")
+ }
+ if decl.Body != nil {
+ log.Fatal("unexpected function body")
+ }
+ fmt.Fprintf(w, "{%q, funcTag, %d},\n", decl.Name.Name, interner.intern(decl.Type))
+ case *ast.GenDecl:
+ if decl.Tok != token.VAR {
+ log.Fatal("unhandled declaration kind", decl.Tok)
+ }
+ for _, spec := range decl.Specs {
+ spec := spec.(*ast.ValueSpec)
+ if len(spec.Values) != 0 {
+ log.Fatal("unexpected values")
+ }
+ typ := interner.intern(spec.Type)
+ for _, name := range spec.Names {
+ fmt.Fprintf(w, "{%q, varTag, %d},\n", name.Name, typ)
+ }
+ }
+ default:
+ log.Fatal("unhandled decl type", decl)
+ }
}
- obj := name + ".o"
- defer os.Remove(obj)
+ fmt.Fprintln(w, "}")
- b, err := ioutil.ReadFile(obj)
- if err != nil {
- log.Fatal(err)
+ fmt.Fprintln(w)
+ fmt.Fprintf(w, "func %sTypes() []*Type {\n", name)
+ fmt.Fprintf(w, "var typs [%d]*Type\n", len(interner.typs))
+ for i, typ := range interner.typs {
+ fmt.Fprintf(w, "typs[%d] = %s\n", i, typ)
}
+ fmt.Fprintln(w, "return typs[:]")
+ fmt.Fprintln(w, "}")
+}
+
+// typeInterner maps Go type expressions to compiler code that
+// constructs the denoted type. It recognizes and reuses common
+// subtype expressions.
+type typeInterner struct {
+ typs []string
+ hash map[string]int
+}
- // Look for $$B that introduces binary export data.
- textual := false // TODO(gri) remove once we switched to binary export format
- i := bytes.Index(b, []byte("\n$$B\n"))
- if i < 0 {
- // Look for $$ that introduces textual export data.
- i = bytes.Index(b, []byte("\n$$\n"))
- if i < 0 {
- log.Fatal("did not find beginning of export data")
+func (i *typeInterner) intern(t ast.Expr) int {
+ x := i.mktype(t)
+ v, ok := i.hash[x]
+ if !ok {
+ v = len(i.typs)
+ if i.hash == nil {
+ i.hash = make(map[string]int)
}
- textual = true
- i-- // textual data doesn't have B
+ i.hash[x] = v
+ i.typs = append(i.typs, x)
}
- b = b[i+5:]
+ return v
+}
+
+func (i *typeInterner) subtype(t ast.Expr) string {
+ return fmt.Sprintf("typs[%d]", i.intern(t))
+}
+
+func (i *typeInterner) mktype(t ast.Expr) string {
+ switch t := t.(type) {
+ case *ast.Ident:
+ switch t.Name {
+ case "byte":
+ return "bytetype"
+ case "rune":
+ return "runetype"
+ }
+ return fmt.Sprintf("Types[T%s]", strings.ToUpper(t.Name))
+
+ case *ast.ArrayType:
+ if t.Len == nil {
+ return fmt.Sprintf("typSlice(%s)", i.subtype(t.Elt))
+ }
+ return fmt.Sprintf("typArray(%s, %d)", i.subtype(t.Elt), intconst(t.Len))
+ case *ast.ChanType:
+ dir := "Cboth"
+ switch t.Dir {
+ case ast.SEND:
+ dir = "Csend"
+ case ast.RECV:
+ dir = "Crecv"
+ }
+ return fmt.Sprintf("typChan(%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]"
+ case *ast.MapType:
+ return fmt.Sprintf("typMap(%s, %s)", i.subtype(t.Key), i.subtype(t.Value))
+ case *ast.StarExpr:
+ return fmt.Sprintf("typPtr(%s)", i.subtype(t.X))
+ case *ast.StructType:
+ return fmt.Sprintf("tostruct(%s)", i.fields(t.Fields, true))
- // Look for $$ that closes export data.
- i = bytes.Index(b, []byte("\n$$\n"))
- if i < 0 {
- log.Fatal("did not find end of export data")
+ default:
+ log.Fatalf("unhandled type: %#v", t)
+ panic("unreachable")
}
- b = b[:i+4]
-
- // Process and reformat export data.
- fmt.Fprintf(w, "\nconst %simport = \"\"", name)
- if textual {
- for _, p := range bytes.SplitAfter(b, []byte("\n")) {
- // Chop leading white space.
- p = bytes.TrimLeft(p, " \t")
- if len(p) == 0 {
- continue
+}
+
+func (i *typeInterner) fields(fl *ast.FieldList, keepNames bool) string {
+ if fl == nil || len(fl.List) == 0 {
+ return "nil"
+ }
+ var res []string
+ for _, f := range fl.List {
+ typ := i.subtype(f.Type)
+ if len(f.Names) == 0 {
+ res = append(res, fmt.Sprintf("anonfield(%s)", typ))
+ } else {
+ for _, name := range f.Names {
+ if keepNames {
+ res = append(res, fmt.Sprintf("namedfield(%q, %s)", name.Name, typ))
+ } else {
+ res = append(res, fmt.Sprintf("anonfield(%s)", typ))
+ }
}
+ }
+ }
+ return fmt.Sprintf("[]*Node{%s}", strings.Join(res, ", "))
+}
- fmt.Fprintf(w, " +\n\t%q", p)
+func intconst(e ast.Expr) int64 {
+ switch e := e.(type) {
+ case *ast.BasicLit:
+ if e.Kind != token.INT {
+ log.Fatalf("expected INT, got %v", e.Kind)
}
- } else {
- const n = 40 // number of bytes per line
- for len(b) > 0 {
- i := len(b)
- if i > n {
- i = n
- }
- fmt.Fprintf(w, " +\n\t%q", b[:i])
- b = b[i:]
+ x, err := strconv.ParseInt(e.Value, 0, 64)
+ if err != nil {
+ log.Fatal(err)
}
+ return x
+ default:
+ log.Fatalf("unhandled expr: %#v", e)
+ panic("unreachable")
}
- fmt.Fprintf(w, "\n")
}
diff --git a/src/cmd/compile/internal/gc/mpfloat.go b/src/cmd/compile/internal/gc/mpfloat.go
index a0f15a9..c851022 100644
--- a/src/cmd/compile/internal/gc/mpfloat.go
+++ b/src/cmd/compile/internal/gc/mpfloat.go
@@ -5,9 +5,9 @@
package gc
import (
- "cmd/compile/internal/big"
"fmt"
"math"
+ "math/big"
)
// implements float arithmetic
@@ -128,7 +128,7 @@ func (a *Mpflt) Float64() float64 {
// check for overflow
if math.IsInf(x, 0) && nsavederrors+nerrors == 0 {
- Yyerror("mpgetflt ovf")
+ yyerror("ovf in Mpflt Float64")
}
return x + 0 // avoid -0 (should not be needed, but be conservative)
@@ -140,7 +140,7 @@ func (a *Mpflt) Float32() float64 {
// check for overflow
if math.IsInf(x, 0) && nsavederrors+nerrors == 0 {
- Yyerror("mpgetflt32 ovf")
+ yyerror("ovf in Mpflt Float32")
}
return x + 0 // avoid -0 (should not be needed, but be conservative)
@@ -187,13 +187,13 @@ func (a *Mpflt) SetString(as string) {
// - 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)
+ yyerror("malformed constant: %s", as)
a.Val.SetFloat64(0)
return
}
if f.IsInf() {
- Yyerror("constant too large: %s", as)
+ yyerror("constant too large: %s", as)
a.Val.SetFloat64(0)
return
}
diff --git a/src/cmd/compile/internal/gc/mpint.go b/src/cmd/compile/internal/gc/mpint.go
index fe37baa..fba8260 100644
--- a/src/cmd/compile/internal/gc/mpint.go
+++ b/src/cmd/compile/internal/gc/mpint.go
@@ -5,8 +5,8 @@
package gc
import (
- "cmd/compile/internal/big"
"fmt"
+ "math/big"
)
// implements integer arithmetic
@@ -71,7 +71,7 @@ func (a *Mpint) SetFloat(b *Mpflt) int {
func (a *Mpint) Add(b *Mpint) {
if a.Ovf || b.Ovf {
if nsavederrors+nerrors == 0 {
- Yyerror("ovf in mpaddfixfix")
+ yyerror("ovf in Mpint Add")
}
a.SetOverflow()
return
@@ -80,14 +80,14 @@ func (a *Mpint) Add(b *Mpint) {
a.Val.Add(&a.Val, &b.Val)
if a.checkOverflow(0) {
- Yyerror("constant addition overflow")
+ yyerror("constant addition overflow")
}
}
func (a *Mpint) Sub(b *Mpint) {
if a.Ovf || b.Ovf {
if nsavederrors+nerrors == 0 {
- Yyerror("ovf in mpsubfixfix")
+ yyerror("ovf in Mpint Sub")
}
a.SetOverflow()
return
@@ -96,14 +96,14 @@ func (a *Mpint) Sub(b *Mpint) {
a.Val.Sub(&a.Val, &b.Val)
if a.checkOverflow(0) {
- Yyerror("constant subtraction overflow")
+ yyerror("constant subtraction overflow")
}
}
func (a *Mpint) Mul(b *Mpint) {
if a.Ovf || b.Ovf {
if nsavederrors+nerrors == 0 {
- Yyerror("ovf in mpmulfixfix")
+ yyerror("ovf in Mpint Mul")
}
a.SetOverflow()
return
@@ -112,14 +112,14 @@ func (a *Mpint) Mul(b *Mpint) {
a.Val.Mul(&a.Val, &b.Val)
if a.checkOverflow(0) {
- Yyerror("constant multiplication overflow")
+ yyerror("constant multiplication overflow")
}
}
func (a *Mpint) Quo(b *Mpint) {
if a.Ovf || b.Ovf {
if nsavederrors+nerrors == 0 {
- Yyerror("ovf in mpdivfixfix")
+ yyerror("ovf in Mpint Quo")
}
a.SetOverflow()
return
@@ -129,14 +129,14 @@ func (a *Mpint) Quo(b *Mpint) {
if a.checkOverflow(0) {
// can only happen for div-0 which should be checked elsewhere
- Yyerror("constant division overflow")
+ yyerror("constant division overflow")
}
}
func (a *Mpint) Rem(b *Mpint) {
if a.Ovf || b.Ovf {
if nsavederrors+nerrors == 0 {
- Yyerror("ovf in mpmodfixfix")
+ yyerror("ovf in Mpint Rem")
}
a.SetOverflow()
return
@@ -146,14 +146,14 @@ func (a *Mpint) Rem(b *Mpint) {
if a.checkOverflow(0) {
// should never happen
- Yyerror("constant modulo overflow")
+ yyerror("constant modulo overflow")
}
}
func (a *Mpint) Or(b *Mpint) {
if a.Ovf || b.Ovf {
if nsavederrors+nerrors == 0 {
- Yyerror("ovf in mporfixfix")
+ yyerror("ovf in Mpint Or")
}
a.SetOverflow()
return
@@ -165,7 +165,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 mpandfixfix")
+ yyerror("ovf in Mpint And")
}
a.SetOverflow()
return
@@ -177,7 +177,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 mpandnotfixfix")
+ yyerror("ovf in Mpint AndNot")
}
a.SetOverflow()
return
@@ -189,7 +189,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 mpxorfixfix")
+ yyerror("ovf in Mpint Xor")
}
a.SetOverflow()
return
@@ -201,7 +201,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 mplshfixfix")
+ yyerror("ovf in Mpint Lsh")
}
a.SetOverflow()
return
@@ -213,13 +213,13 @@ func (a *Mpint) Lsh(b *Mpint) {
if s < 0 {
msg = "invalid negative shift count"
}
- Yyerror("%s: %d", msg, s)
+ yyerror("%s: %d", msg, s)
a.SetInt64(0)
return
}
if a.checkOverflow(int(s)) {
- Yyerror("constant shift overflow")
+ yyerror("constant shift overflow")
return
}
a.Val.Lsh(&a.Val, uint(s))
@@ -228,7 +228,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 mprshfixfix")
+ yyerror("ovf in Mpint Rsh")
}
a.SetOverflow()
return
@@ -236,7 +236,7 @@ func (a *Mpint) Rsh(b *Mpint) {
s := b.Int64()
if s < 0 {
- Yyerror("invalid negative shift count: %d", s)
+ yyerror("invalid negative shift count: %d", s)
if a.Val.Sign() < 0 {
a.SetInt64(-1)
} else {
@@ -266,7 +266,7 @@ func (a *Mpint) Neg() {
func (a *Mpint) Int64() int64 {
if a.Ovf {
if nsavederrors+nerrors == 0 {
- Yyerror("constant overflow")
+ yyerror("constant overflow")
}
return 0
}
@@ -288,12 +288,12 @@ func (a *Mpint) SetString(as string) {
// - malformed octal constant
// - malformed decimal constant
// TODO(gri) use different conversion function
- Yyerror("malformed integer constant: %s", as)
+ yyerror("malformed integer constant: %s", as)
a.Val.SetUint64(0)
return
}
if a.checkOverflow(0) {
- Yyerror("constant too large: %s", as)
+ yyerror("constant too large: %s", as)
}
}
diff --git a/src/cmd/compile/internal/gc/noder.go b/src/cmd/compile/internal/gc/noder.go
new file mode 100644
index 0000000..f9de48a
--- /dev/null
+++ b/src/cmd/compile/internal/gc/noder.go
@@ -0,0 +1,1083 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gc
+
+import (
+ "fmt"
+ "os"
+ "strconv"
+ "strings"
+ "unicode/utf8"
+
+ "cmd/compile/internal/syntax"
+)
+
+func parseFile(filename string) {
+ src, err := os.Open(filename)
+ if err != nil {
+ fmt.Println(err)
+ errorexit()
+ }
+ defer src.Close()
+
+ p := noder{baseline: lexlineno}
+ file, _ := syntax.Parse(src, p.error, p.pragma, 0) // errors are tracked via p.error
+
+ p.file(file)
+
+ 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\""})
+ }
+ }
+
+ if nsyntaxerrors == 0 {
+ testdclstack()
+ }
+}
+
+// noder transforms package syntax's AST into a Nod tree.
+type noder struct {
+ baseline int32
+ linknames []int // tracks //go:linkname lines
+}
+
+func (p *noder) file(file *syntax.File) {
+ p.lineno(file.PkgName)
+ mkpackage(file.PkgName.Value)
+
+ xtop = append(xtop, p.decls(file.DeclList)...)
+
+ lexlineno = p.baseline + int32(file.Lines) - 1
+ lineno = lexlineno
+}
+
+func (p *noder) decls(decls []syntax.Decl) (l []*Node) {
+ var lastConstGroup *syntax.Group
+ var lastConstRHS []*Node
+ var iotaVal int64
+
+ for _, decl := range decls {
+ p.lineno(decl)
+ switch decl := decl.(type) {
+ case *syntax.ImportDecl:
+ p.importDecl(decl)
+
+ case *syntax.VarDecl:
+ 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
+
+ case *syntax.TypeDecl:
+ l = append(l, p.typeDecl(decl))
+
+ case *syntax.FuncDecl:
+ l = append(l, p.funcDecl(decl))
+
+ default:
+ panic("unhandled Decl")
+ }
+ }
+
+ return
+}
+
+func (p *noder) importDecl(imp *syntax.ImportDecl) {
+ val := p.basicLit(imp.Path)
+ importfile(&val, nil)
+ ipkg := importpkg
+ importpkg = nil
+
+ if ipkg == nil {
+ if nerrors == 0 {
+ Fatalf("phase error in import")
+ }
+ return
+ }
+
+ ipkg.Direct = true
+
+ var my *Sym
+ if imp.LocalPkgName != nil {
+ my = p.name(imp.LocalPkgName)
+ } else {
+ my = lookup(ipkg.Name)
+ }
+
+ pack := p.nod(imp, OPACK, nil, nil)
+ pack.Sym = my
+ pack.Name.Pkg = ipkg
+
+ if my.Name == "." {
+ importdot(ipkg, pack)
+ return
+ }
+ if my.Name == "init" {
+ yyerrorl(pack.Lineno, "cannot import package as init - init must be a func")
+ return
+ }
+ if my.Name == "_" {
+ return
+ }
+ if my.Def != nil {
+ lineno = pack.Lineno
+ redeclare(my, "as imported package name")
+ }
+ my.Def = pack
+ my.Lastlineno = pack.Lineno
+ 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)
+ }
+
+ var exprs []*Node
+ if decl.Values != nil {
+ exprs = p.exprList(decl.Values)
+ }
+
+ p.lineno(decl)
+ return variter(names, typ, exprs)
+}
+
+func (p *noder) constDecl(decl *syntax.ConstDecl) []*Node {
+ names := p.declNames(decl.NameList)
+
+ var typ *Node
+ if decl.Type != nil {
+ typ = p.typeExpr(decl.Type)
+ }
+
+ var exprs []*Node
+ if decl.Values != nil {
+ exprs = p.exprList(decl.Values)
+ }
+
+ return constiter(names, typ, exprs)
+}
+
+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)
+ }
+
+ return typedcl1(name, typ, true)
+}
+
+func (p *noder) declNames(names []*syntax.Name) []*Node {
+ var nodes []*Node
+ for _, name := range names {
+ nodes = append(nodes, p.declName(name))
+ }
+ return nodes
+}
+
+func (p *noder) declName(name *syntax.Name) *Node {
+ // TODO(mdempsky): Set lineno?
+ return dclname(p.name(name))
+}
+
+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")
+ }
+ }
+
+ 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")
+ }
+ }
+
+ 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.Nname.Name.Defn = f
+ f.Func.Nname.Name.Param.Ntype = t // TODO: check if nname already has an ntype
+
+ declare(f.Func.Nname, PFUNC)
+ funchdr(f)
+ return f
+}
+
+func (p *noder) signature(recv *syntax.Field, typ *syntax.FuncType) *Node {
+ n := p.nod(typ, OTFUNC, nil, nil)
+ if recv != nil {
+ n.Left = p.param(recv, false, false)
+ }
+ n.List.Set(p.params(typ.ParamList, true))
+ n.Rlist.Set(p.params(typ.ResultList, false))
+ return n
+}
+
+func (p *noder) params(params []*syntax.Field, dddOk bool) []*Node {
+ var nodes []*Node
+ for i, param := range params {
+ p.lineno(param)
+ nodes = append(nodes, p.param(param, dddOk, i+1 == len(params)))
+ }
+ return nodes
+}
+
+func (p *noder) param(param *syntax.Field, dddOk, final bool) *Node {
+ var name *Node
+ if param.Name != nil {
+ name = p.newname(param.Name)
+ }
+
+ typ := p.typeExpr(param.Type)
+ n := p.nod(param, ODCLFIELD, name, typ)
+
+ // rewrite ...T parameter
+ if typ.Op == ODDD {
+ if !dddOk {
+ yyerror("cannot use ... in receiver or result parameter list")
+ } else if !final {
+ yyerror("can only use ... with final parameter in list")
+ }
+ typ.Op = OTARRAY
+ typ.Right = typ.Left
+ typ.Left = nil
+ n.Isddd = true
+ if n.Left != nil {
+ n.Left.Isddd = true
+ }
+ }
+
+ return n
+}
+
+func (p *noder) exprList(expr syntax.Expr) []*Node {
+ if list, ok := expr.(*syntax.ListExpr); ok {
+ return p.exprs(list.ElemList)
+ }
+ return []*Node{p.expr(expr)}
+}
+
+func (p *noder) exprs(exprs []syntax.Expr) []*Node {
+ var nodes []*Node
+ for _, expr := range exprs {
+ nodes = append(nodes, p.expr(expr))
+ }
+ return nodes
+}
+
+func (p *noder) expr(expr syntax.Expr) *Node {
+ p.lineno(expr)
+ switch expr := expr.(type) {
+ case nil:
+ return nil
+ case *syntax.Name:
+ return p.mkname(expr)
+ case *syntax.BasicLit:
+ return p.setlineno(expr, nodlit(p.basicLit(expr)))
+
+ case *syntax.CompositeLit:
+ n := p.nod(expr, OCOMPLIT, nil, nil)
+ if expr.Type != nil {
+ n.Right = p.expr(expr.Type)
+ }
+ l := p.exprs(expr.ElemList)
+ for i, e := range l {
+ l[i] = p.wrapname(expr.ElemList[i], e)
+ }
+ n.List.Set(l)
+ lineno = p.baseline + int32(expr.EndLine) - 1
+ 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))
+ 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
+ return oldname(restrictlookup(expr.Sel.Value, obj.Name.Pkg))
+ }
+ return p.setlineno(expr, nodSym(OXDOT, obj, p.name(expr.Sel)))
+ case *syntax.IndexExpr:
+ return p.nod(expr, OINDEX, p.expr(expr.X), p.expr(expr.Index))
+ case *syntax.SliceExpr:
+ op := OSLICE
+ if expr.Full {
+ op = OSLICE3
+ }
+ n := p.nod(expr, op, p.expr(expr.X), nil)
+ var index [3]*Node
+ for i, x := range expr.Index {
+ if x != nil {
+ index[i] = p.expr(x)
+ }
+ }
+ n.SetSliceBounds(index[0], index[1], index[2])
+ return n
+ case *syntax.AssertExpr:
+ if expr.Type == nil {
+ panic("unexpected AssertExpr")
+ }
+ // TODO(mdempsky): parser.pexpr uses p.expr(), but
+ // seems like the type field should be parsed with
+ // ntype? Shrug, doesn't matter here.
+ return p.nod(expr, ODOTTYPE, p.expr(expr.X), p.expr(expr.Type))
+ case *syntax.Operation:
+ x := p.expr(expr.X)
+ if expr.Y == nil {
+ if expr.Op == syntax.And {
+ x = unparen(x) // TODO(mdempsky): Needed?
+ if x.Op == OCOMPLIT {
+ // Special case for &T{...}: turn into (*T){...}.
+ // TODO(mdempsky): Switch back to p.nod after we
+ // get rid of gcCompat.
+ x.Right = nod(OIND, x.Right, nil)
+ x.Right.Implicit = true
+ return x
+ }
+ }
+ return p.nod(expr, p.unOp(expr.Op), x, nil)
+ }
+ return p.nod(expr, p.binOp(expr.Op), x, p.expr(expr.Y))
+ case *syntax.CallExpr:
+ n := p.nod(expr, OCALL, p.expr(expr.Fun), nil)
+ n.List.Set(p.exprs(expr.ArgList))
+ n.Isddd = expr.HasDots
+ return n
+
+ case *syntax.ArrayType:
+ var len *Node
+ if expr.Len != nil {
+ len = p.expr(expr.Len)
+ } else {
+ len = p.nod(expr, ODDD, nil, nil)
+ }
+ return p.nod(expr, OTARRAY, len, p.typeExpr(expr.Elem))
+ case *syntax.SliceType:
+ return p.nod(expr, OTARRAY, nil, p.typeExpr(expr.Elem))
+ case *syntax.DotsType:
+ return p.nod(expr, ODDD, p.typeExpr(expr.Elem), nil)
+ case *syntax.StructType:
+ return p.structType(expr)
+ case *syntax.InterfaceType:
+ return p.interfaceType(expr)
+ case *syntax.FuncType:
+ return p.signature(nil, expr)
+ case *syntax.MapType:
+ 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))
+ return n
+
+ case *syntax.TypeSwitchGuard:
+ n := p.nod(expr, OTYPESW, nil, p.expr(expr.X))
+ if expr.Lhs != nil {
+ n.Left = p.declName(expr.Lhs)
+ if isblank(n.Left) {
+ yyerror("invalid variable name %v in type switch", n.Left)
+ }
+ }
+ return n
+ }
+ panic("unhandled Expr")
+}
+
+func (p *noder) typeExpr(typ syntax.Expr) *Node {
+ // TODO(mdempsky): Be stricter? typecheck should handle errors anyway.
+ return p.expr(typ)
+}
+
+func (p *noder) chanDir(dir syntax.ChanDir) ChanDir {
+ switch dir {
+ case 0:
+ return Cboth
+ case syntax.SendOnly:
+ return Csend
+ case syntax.RecvOnly:
+ return Crecv
+ }
+ panic("unhandled ChanDir")
+}
+
+func (p *noder) structType(expr *syntax.StructType) *Node {
+ var l []*Node
+ for i, field := range expr.FieldList {
+ p.lineno(field)
+ var n *Node
+ if field.Name == nil {
+ n = p.embedded(field.Type)
+ } else {
+ n = p.nod(field, ODCLFIELD, p.newname(field.Name), p.typeExpr(field.Type))
+ }
+ if i < len(expr.TagList) && expr.TagList[i] != nil {
+ n.SetVal(p.basicLit(expr.TagList[i]))
+ }
+ l = append(l, n)
+ }
+
+ p.lineno(expr)
+ n := p.nod(expr, OTSTRUCT, nil, nil)
+ n.List.Set(l)
+ return n
+}
+
+func (p *noder) interfaceType(expr *syntax.InterfaceType) *Node {
+ var l []*Node
+ for _, method := range expr.MethodList {
+ p.lineno(method)
+ var n *Node
+ if method.Name == nil {
+ n = p.nod(method, ODCLFIELD, nil, oldname(p.packname(method.Type)))
+ } else {
+ mname := p.newname(method.Name)
+ sig := p.typeExpr(method.Type)
+ sig.Left = fakethis()
+ n = p.nod(method, ODCLFIELD, mname, sig)
+ ifacedcl(n)
+ }
+ l = append(l, n)
+ }
+
+ n := p.nod(expr, OTINTER, nil, nil)
+ n.List.Set(l)
+ return n
+}
+
+func (p *noder) packname(expr syntax.Expr) *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
+ }
+ return name
+ case *syntax.SelectorExpr:
+ name := p.name(expr.X.(*syntax.Name))
+ var pkg *Pkg
+ if name.Def == nil || name.Def.Op != OPACK {
+ yyerror("%v is not a package", name)
+ pkg = localpkg
+ } else {
+ name.Def.Used = true
+ pkg = name.Def.Name.Pkg
+ }
+ return restrictlookup(expr.Sel.Value, pkg)
+ }
+ panic(fmt.Sprintf("unexpected packname: %#v", expr))
+}
+
+func (p *noder) embedded(typ syntax.Expr) *Node {
+ op, isStar := typ.(*syntax.Operation)
+ if isStar {
+ if op.Op != syntax.Mul || op.Y != nil {
+ panic("unexpected Operation")
+ }
+ typ = op.X
+ }
+ n := embedded(p.packname(typ), localpkg)
+ if isStar {
+ n.Right = p.nod(op, OIND, n.Right, nil)
+ }
+ return n
+}
+
+func (p *noder) stmts(stmts []syntax.Stmt) []*Node {
+ var nodes []*Node
+ for _, stmt := range stmts {
+ s := p.stmt(stmt)
+ if s == nil {
+ } else if s.Op == OBLOCK && s.Ninit.Len() == 0 {
+ nodes = append(nodes, s.List.Slice()...)
+ } else {
+ nodes = append(nodes, s)
+ }
+ }
+ return nodes
+}
+
+func (p *noder) stmt(stmt syntax.Stmt) *Node {
+ p.lineno(stmt)
+ switch stmt := stmt.(type) {
+ case *syntax.EmptyStmt:
+ return nil
+ case *syntax.LabeledStmt:
+ return p.labeledStmt(stmt)
+ case *syntax.BlockStmt:
+ return p.body(stmt.Body)
+ case *syntax.ExprStmt:
+ return p.wrapname(stmt, p.expr(stmt.X))
+ case *syntax.SendStmt:
+ return p.nod(stmt, OSEND, p.expr(stmt.Chan), p.expr(stmt.Value))
+ case *syntax.DeclStmt:
+ return liststmt(p.decls(stmt.DeclList))
+ 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))
+ return n
+ }
+
+ lhs := p.exprList(stmt.Lhs)
+ rhs := p.exprList(stmt.Rhs)
+
+ n := p.nod(stmt, OAS, nil, nil) // assume common case
+
+ if stmt.Op == syntax.Def {
+ n.Colas = true
+ colasdefn(lhs, n) // modifies lhs, call before using lhs[0] in common case
+ }
+
+ if len(lhs) == 1 && len(rhs) == 1 {
+ // common case
+ n.Left = lhs[0]
+ n.Right = rhs[0]
+ } else {
+ n.Op = OAS2
+ n.List.Set(lhs)
+ n.Rlist.Set(rhs)
+ }
+ return n
+
+ case *syntax.BranchStmt:
+ var op Op
+ switch stmt.Tok {
+ case syntax.Break:
+ op = OBREAK
+ case syntax.Continue:
+ op = OCONTINUE
+ case syntax.Fallthrough:
+ op = OXFALL
+ case syntax.Goto:
+ op = OGOTO
+ default:
+ panic("unhandled BranchStmt")
+ }
+ n := p.nod(stmt, op, nil, nil)
+ 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)
+ }
+ return n
+ case *syntax.CallStmt:
+ var op Op
+ switch stmt.Tok {
+ case syntax.Defer:
+ op = ODEFER
+ case syntax.Go:
+ op = OPROC
+ default:
+ panic("unhandled CallStmt")
+ }
+ return p.nod(stmt, op, p.expr(stmt.Call), nil)
+ case *syntax.ReturnStmt:
+ var results []*Node
+ if stmt.Results != nil {
+ results = p.exprList(stmt.Results)
+ }
+ n := p.nod(stmt, ORETURN, nil, nil)
+ n.List.Set(results)
+ if n.List.Len() == 0 && Curfn != nil {
+ for _, ln := range Curfn.Func.Dcl {
+ if ln.Class == PPARAM {
+ continue
+ }
+ if ln.Class != PPARAMOUT {
+ break
+ }
+ if ln.Sym.Def != ln {
+ yyerror("%s is shadowed during return", ln.Sym.Name)
+ }
+ }
+ }
+ return n
+ case *syntax.IfStmt:
+ return p.ifStmt(stmt)
+ case *syntax.ForStmt:
+ return p.forStmt(stmt)
+ case *syntax.SwitchStmt:
+ return p.switchStmt(stmt)
+ case *syntax.SelectStmt:
+ return p.selectStmt(stmt)
+ }
+ 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()
+ return nodes
+}
+
+func (p *noder) ifStmt(stmt *syntax.IfStmt) *Node {
+ markdcl()
+ n := p.nod(stmt, OIF, nil, nil)
+ if stmt.Init != nil {
+ n.Ninit.Set1(p.stmt(stmt.Init))
+ }
+ if stmt.Cond != nil {
+ n.Left = p.expr(stmt.Cond)
+ }
+ n.Nbody.Set(p.bodyList(stmt.Then))
+ if stmt.Else != nil {
+ e := p.stmt(stmt.Else)
+ if e.Op == OBLOCK && e.Ninit.Len() == 0 {
+ n.Rlist.Set(e.List.Slice())
+ } else {
+ n.Rlist.Set1(e)
+ }
+ }
+ popdcl()
+ return n
+}
+
+func (p *noder) forStmt(stmt *syntax.ForStmt) *Node {
+ markdcl()
+ var n *Node
+ if r, ok := stmt.Init.(*syntax.RangeClause); ok {
+ if stmt.Cond != nil || stmt.Post != nil {
+ panic("unexpected RangeClause")
+ }
+
+ n = p.nod(r, ORANGE, nil, p.expr(r.X))
+ if r.Lhs != nil {
+ lhs := p.exprList(r.Lhs)
+ n.List.Set(lhs)
+ if r.Def {
+ n.Colas = true
+ colasdefn(lhs, n)
+ }
+ }
+ } else {
+ n = p.nod(stmt, OFOR, nil, nil)
+ if stmt.Init != nil {
+ n.Ninit.Set1(p.stmt(stmt.Init))
+ }
+ if stmt.Cond != nil {
+ n.Left = p.expr(stmt.Cond)
+ }
+ if stmt.Post != nil {
+ n.Right = p.stmt(stmt.Post)
+ }
+ }
+ n.Nbody.Set(p.bodyList(stmt.Body))
+ popdcl()
+ return n
+}
+
+func (p *noder) switchStmt(stmt *syntax.SwitchStmt) *Node {
+ markdcl()
+ n := p.nod(stmt, OSWITCH, nil, nil)
+ if stmt.Init != nil {
+ n.Ninit.Set1(p.stmt(stmt.Init))
+ }
+ if stmt.Tag != nil {
+ n.Left = p.expr(stmt.Tag)
+ }
+
+ tswitch := n.Left
+ if tswitch != nil && (tswitch.Op != OTYPESW || tswitch.Left == nil) {
+ tswitch = nil
+ }
+
+ n.List.Set(p.caseClauses(stmt.Body, tswitch))
+
+ popdcl()
+ return n
+}
+
+func (p *noder) caseClauses(clauses []*syntax.CaseClause, tswitch *Node) []*Node {
+ var nodes []*Node
+ for _, clause := range clauses {
+ p.lineno(clause)
+ markdcl()
+ n := p.nod(clause, OXCASE, nil, nil)
+ if clause.Cases != nil {
+ n.List.Set(p.exprList(clause.Cases))
+ }
+ if tswitch != nil {
+ nn := newname(tswitch.Left.Sym)
+ declare(nn, dclcontext)
+ n.Rlist.Set1(nn)
+ // keep track of the instances for reporting unused
+ nn.Name.Defn = tswitch
+ }
+ n.Xoffset = int64(block)
+ n.Nbody.Set(p.stmts(clause.Body))
+ popdcl()
+ nodes = append(nodes, n)
+ }
+ return nodes
+}
+
+func (p *noder) selectStmt(stmt *syntax.SelectStmt) *Node {
+ n := p.nod(stmt, OSELECT, nil, nil)
+ n.List.Set(p.commClauses(stmt.Body))
+ return n
+}
+
+func (p *noder) commClauses(clauses []*syntax.CommClause) []*Node {
+ var nodes []*Node
+ for _, clause := range clauses {
+ p.lineno(clause)
+ markdcl()
+ n := p.nod(clause, OXCASE, nil, nil)
+ if clause.Comm != nil {
+ n.List.Set1(p.stmt(clause.Comm))
+ }
+ n.Xoffset = int64(block)
+ n.Nbody.Set(p.stmts(clause.Body))
+ popdcl()
+ nodes = append(nodes, n)
+ }
+ 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.
+ ls = p.stmt(label.Stmt)
+ }
+
+ lhs.Name.Defn = ls
+ l := []*Node{lhs}
+ if ls != nil {
+ if ls.Op == OBLOCK && ls.Ninit.Len() == 0 {
+ l = append(l, ls.List.Slice()...)
+ } else {
+ l = append(l, ls)
+ }
+ }
+ return liststmt(l)
+}
+
+var unOps = [...]Op{
+ syntax.Recv: ORECV,
+ syntax.Mul: OIND,
+ syntax.And: OADDR,
+
+ syntax.Not: ONOT,
+ syntax.Xor: OCOM,
+ syntax.Add: OPLUS,
+ syntax.Sub: OMINUS,
+}
+
+func (p *noder) unOp(op syntax.Operator) Op {
+ if uint64(op) >= uint64(len(unOps)) || unOps[op] == 0 {
+ panic("invalid Operator")
+ }
+ return unOps[op]
+}
+
+var binOps = [...]Op{
+ syntax.OrOr: OOROR,
+ syntax.AndAnd: OANDAND,
+
+ syntax.Eql: OEQ,
+ syntax.Neq: ONE,
+ syntax.Lss: OLT,
+ syntax.Leq: OLE,
+ syntax.Gtr: OGT,
+ syntax.Geq: OGE,
+
+ syntax.Add: OADD,
+ syntax.Sub: OSUB,
+ syntax.Or: OOR,
+ syntax.Xor: OXOR,
+
+ syntax.Mul: OMUL,
+ syntax.Div: ODIV,
+ syntax.Rem: OMOD,
+ syntax.And: OAND,
+ syntax.AndNot: OANDNOT,
+ syntax.Shl: OLSH,
+ syntax.Shr: ORSH,
+}
+
+func (p *noder) binOp(op syntax.Operator) Op {
+ if uint64(op) >= uint64(len(binOps)) || binOps[op] == 0 {
+ panic("invalid Operator")
+ }
+ return binOps[op]
+}
+
+func (p *noder) basicLit(lit *syntax.BasicLit) Val {
+ // TODO: Don't try to convert if we had syntax errors (conversions may fail).
+ // Use dummy values so we can continue to compile. Eventually, use a
+ // form of "unknown" literals that are ignored during type-checking so
+ // we can continue type-checking w/o spurious follow-up errors.
+ switch s := lit.Value; lit.Kind {
+ case syntax.IntLit:
+ x := new(Mpint)
+ x.SetString(s)
+ return Val{U: x}
+
+ case syntax.FloatLit:
+ x := newMpflt()
+ x.SetString(s)
+ return Val{U: x}
+
+ case syntax.ImagLit:
+ x := new(Mpcplx)
+ x.Imag.SetString(strings.TrimSuffix(s, "i"))
+ return Val{U: x}
+
+ case syntax.RuneLit:
+ var r rune
+ if u, err := strconv.Unquote(s); err == nil && len(u) > 0 {
+ // Package syntax already reported any errors.
+ // Check for them again though because 0 is a
+ // better fallback value for invalid rune
+ // literals than 0xFFFD.
+ if len(u) == 1 {
+ r = rune(u[0])
+ } else {
+ r, _ = utf8.DecodeRuneInString(u)
+ }
+ }
+ x := new(Mpint)
+ x.SetInt64(int64(r))
+ x.Rune = true
+ return Val{U: x}
+
+ case syntax.StringLit:
+ if len(s) > 0 && s[0] == '`' {
+ // strip carriage returns from raw string
+ s = strings.Replace(s, "\r", "", -1)
+ }
+ // Ignore errors because package syntax already reported them.
+ u, _ := strconv.Unquote(s)
+ return Val{U: u}
+
+ default:
+ panic("unhandled BasicLit kind")
+ }
+}
+
+func (p *noder) name(name *syntax.Name) *Sym {
+ return lookup(name.Value)
+}
+
+func (p *noder) mkname(name *syntax.Name) *Node {
+ // TODO(mdempsky): Set line number?
+ return mkname(p.name(name))
+}
+
+func (p *noder) newname(name *syntax.Name) *Node {
+ // TODO(mdempsky): Set line number?
+ return newname(p.name(name))
+}
+
+func (p *noder) wrapname(n syntax.Node, x *Node) *Node {
+ // These nodes do not carry line numbers.
+ // Introduce a wrapper node to give them the correct line.
+ switch x.Op {
+ case OTYPE, OLITERAL:
+ if x.Sym == nil {
+ break
+ }
+ fallthrough
+ case ONAME, ONONAME, OPACK:
+ x = p.nod(n, OPAREN, x, nil)
+ x.Implicit = true
+ }
+ return x
+}
+
+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 {
+ // TODO(mdempsky): Shouldn't happen. Fix package syntax.
+ return dst
+ }
+ dst.Lineno = p.baseline + l - 1
+ return dst
+}
+
+func (p *noder) lineno(n syntax.Node) {
+ if n == nil {
+ return
+ }
+ l := int32(n.Line())
+ if l == 0 {
+ // TODO(mdempsky): Shouldn't happen. Fix package syntax.
+ return
+ }
+ lineno = p.baseline + l - 1
+}
+
+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)
+}
+
+func (p *noder) pragma(pos, line int, text string) syntax.Pragma {
+ switch {
+ case strings.HasPrefix(text, "line "):
+ i := strings.IndexByte(text, ':')
+ 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)
+
+ 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"})
+ break
+ }
+ lookup(f[1]).Linkname = f[2]
+
+ case strings.HasPrefix(text, "go:cgo_"):
+ pragcgobuf += pragcgo(text)
+ fallthrough // because of //go:cgo_unsafe_args
+ default:
+ verb := text
+ if i := strings.Index(text, " "); i >= 0 {
+ verb = verb[:i]
+ }
+ return syntax.Pragma(pragmaValue(verb))
+ }
+
+ return 0
+}
+
+func mkname(sym *Sym) *Node {
+ n := oldname(sym)
+ if n.Name != nil && n.Name.Pack != nil {
+ n.Name.Pack.Used = true
+ }
+ return n
+}
+
+func unparen(x *Node) *Node {
+ for x.Op == OPAREN {
+ x = x.Left
+ }
+ return x
+}
diff --git a/src/cmd/compile/internal/gc/obj.go b/src/cmd/compile/internal/gc/obj.go
index b5c06d1..08ed560 100644
--- a/src/cmd/compile/internal/gc/obj.go
+++ b/src/cmd/compile/internal/gc/obj.go
@@ -53,7 +53,7 @@ func dumpobj1(outfile string, mode int) {
var err error
bout, err = bio.Create(outfile)
if err != nil {
- Flusherrors()
+ flusherrors()
fmt.Printf("can't create %s: %v\n", outfile, err)
errorexit()
}
@@ -68,7 +68,7 @@ func dumpobj1(outfile string, mode int) {
}
printheader := func() {
- fmt.Fprintf(bout, "go object %s %s %s %s\n", obj.Getgoos(), obj.Getgoarch(), obj.Getgoversion(), obj.Expstring())
+ fmt.Fprintf(bout, "go object %s %s %s %s\n", obj.GOOS, obj.GOARCH, obj.Version, obj.Expstring())
if buildid != "" {
fmt.Fprintf(bout, "build id %q\n", buildid)
}
@@ -130,6 +130,7 @@ func dumpobj1(outfile string, mode int) {
externs := len(externdcl)
dumpglobls()
+ dumpptabs()
dumptypestructs()
// Dump extra globals.
@@ -146,7 +147,6 @@ func dumpobj1(outfile string, mode int) {
ggloblsym(zero, int32(zerosize), obj.DUPOK|obj.RODATA)
}
- dumpdata()
obj.Writeobjdirect(Ctxt, bout.Writer)
if writearchive {
@@ -163,6 +163,35 @@ func dumpobj1(outfile string, mode int) {
bout.Close()
}
+func dumpptabs() {
+ if !Ctxt.Flag_dynlink || localpkg.Name != "main" {
+ return
+ }
+ for _, exportn := range exportlist {
+ s := exportn.Sym
+ n := s.Def
+ if n == nil {
+ continue
+ }
+ if n.Op != ONAME {
+ continue
+ }
+ if !exportname(s.Name) {
+ continue
+ }
+ if s.Pkg.Name != "main" {
+ continue
+ }
+ if n.Type.Etype == TFUNC && n.Class == PFUNC {
+ // function
+ ptabs = append(ptabs, ptabEntry{s: s, t: s.Def.Type})
+ } else {
+ // variable
+ ptabs = append(ptabs, ptabEntry{s: s, t: typPtr(s.Def.Type)})
+ }
+ }
+}
+
func dumpglobls() {
// add globals
for _, n := range externdcl {
@@ -242,18 +271,16 @@ func duintptr(s *Sym, off int, v uint64) int {
return duintxx(s, off, v, Widthptr)
}
-// stringConstantSyms holds the pair of symbols we create for a
-// constant string.
-type stringConstantSyms struct {
- hdr *obj.LSym // string header
- data *obj.LSym // actual string data
+func dbvec(s *Sym, 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]
+ off = duint8(s, off, uint8(word>>(uint(j)%32)))
+ }
+ return off
}
-// stringConstants maps from the symbol name we use for the string
-// contents to the pair of linker symbols for that string.
-var stringConstants = make(map[string]stringConstantSyms, 100)
-
-func stringsym(s string) (hdr, data *obj.LSym) {
+func stringsym(s string) (data *obj.LSym) {
var symname string
if len(s) > 100 {
// Huge strings are hashed to avoid long names in object files.
@@ -270,33 +297,15 @@ func stringsym(s string) (hdr, data *obj.LSym) {
const prefix = "go.string."
symdataname := prefix + symname
- // All the strings have the same prefix, so ignore it for map
- // purposes, but use a slice of the symbol name string to
- // reduce long-term memory overhead.
- key := symdataname[len(prefix):]
-
- if syms, ok := stringConstants[key]; ok {
- return syms.hdr, syms.data
- }
-
- symhdrname := "go.string.hdr." + symname
-
- symhdr := obj.Linklookup(Ctxt, symhdrname, 0)
symdata := obj.Linklookup(Ctxt, symdataname, 0)
- stringConstants[key] = stringConstantSyms{symhdr, symdata}
-
- // string header
- off := 0
- off = dsymptrLSym(symhdr, off, symdata, 0)
- off = duintxxLSym(symhdr, off, uint64(len(s)), Widthint)
- ggloblLSym(symhdr, int32(off), obj.DUPOK|obj.RODATA|obj.LOCAL)
-
- // string data
- off = dsnameLSym(symdata, 0, s)
- ggloblLSym(symdata, int32(off), obj.DUPOK|obj.RODATA|obj.LOCAL)
+ if !symdata.SeenGlobl() {
+ // string data
+ off := dsnameLSym(symdata, 0, s)
+ ggloblLSym(symdata, int32(off), obj.DUPOK|obj.RODATA|obj.LOCAL)
+ }
- return symhdr, symdata
+ return symdata
}
var slicebytes_gen int
@@ -319,42 +328,6 @@ func slicebytes(nam *Node, s string, len int) {
duintxx(nam.Sym, off, uint64(len), Widthint)
}
-func Datastring(s string, a *obj.Addr) {
- _, symdata := stringsym(s)
- a.Type = obj.TYPE_MEM
- a.Name = obj.NAME_EXTERN
- a.Sym = symdata
- a.Offset = 0
- a.Etype = uint8(Simtype[TINT])
-}
-
-func datagostring(sval string, a *obj.Addr) {
- symhdr, _ := stringsym(sval)
- a.Type = obj.TYPE_MEM
- a.Name = obj.NAME_EXTERN
- a.Sym = symhdr
- a.Offset = 0
- a.Etype = uint8(TSTRING)
-}
-
-func dgostringptr(s *Sym, off int, str string) int {
- if str == "" {
- return duintptr(s, off, 0)
- }
- return dgostrlitptr(s, off, &str)
-}
-
-func dgostrlitptr(s *Sym, off int, lit *string) int {
- if lit == nil {
- return duintptr(s, off, 0)
- }
- off = int(Rnd(int64(off), int64(Widthptr)))
- symhdr, _ := stringsym(*lit)
- Linksym(s).WriteAddr(Ctxt, int64(off), Widthptr, symhdr, 0)
- off += Widthptr
- return off
-}
-
func dsname(s *Sym, off int, t string) int {
return dsnameLSym(Linksym(s), off, t)
}
@@ -381,6 +354,12 @@ func dsymptrOffLSym(s *obj.LSym, off int, x *obj.LSym, xoff int) int {
return off
}
+func dsymptrWeakOffLSym(s *obj.LSym, off int, x *obj.LSym) int {
+ s.WriteWeakOff(Ctxt, int64(off), x, 0)
+ off += 4
+ return off
+}
+
func gdata(nam *Node, nr *Node, wid int) {
if nam.Op != ONAME {
Fatalf("gdata nam op %v", nam.Op)
@@ -388,25 +367,19 @@ func gdata(nam *Node, nr *Node, wid int) {
if nam.Sym == nil {
Fatalf("gdata nil nam sym")
}
+ s := Linksym(nam.Sym)
switch nr.Op {
case OLITERAL:
switch u := nr.Val().U.(type) {
- case *Mpcplx:
- gdatacomplex(nam, u)
-
- case string:
- gdatastring(nam, u)
-
case bool:
i := int64(obj.Bool2int(u))
- Linksym(nam.Sym).WriteInt(Ctxt, nam.Xoffset, wid, i)
+ s.WriteInt(Ctxt, nam.Xoffset, wid, i)
case *Mpint:
- Linksym(nam.Sym).WriteInt(Ctxt, nam.Xoffset, wid, u.Int64())
+ s.WriteInt(Ctxt, nam.Xoffset, wid, u.Int64())
case *Mpflt:
- s := Linksym(nam.Sym)
f := u.Float64()
switch nam.Type.Etype {
case TFLOAT32:
@@ -415,47 +388,41 @@ func gdata(nam *Node, nr *Node, wid int) {
s.WriteFloat64(Ctxt, nam.Xoffset, f)
}
+ case *Mpcplx:
+ r := u.Real.Float64()
+ i := u.Imag.Float64()
+ switch nam.Type.Etype {
+ case TCOMPLEX64:
+ s.WriteFloat32(Ctxt, nam.Xoffset, float32(r))
+ s.WriteFloat32(Ctxt, nam.Xoffset+4, float32(i))
+ case TCOMPLEX128:
+ s.WriteFloat64(Ctxt, nam.Xoffset, r)
+ s.WriteFloat64(Ctxt, nam.Xoffset+8, i)
+ }
+
+ case string:
+ symdata := stringsym(u)
+ s.WriteAddr(Ctxt, nam.Xoffset, Widthptr, symdata, 0)
+ s.WriteInt(Ctxt, nam.Xoffset+int64(Widthptr), Widthint, int64(len(u)))
+
default:
Fatalf("gdata unhandled OLITERAL %v", nr)
}
case OADDR:
if nr.Left.Op != ONAME {
- Fatalf("gdata ADDR left op %s", nr.Left.Op)
+ Fatalf("gdata ADDR left op %v", nr.Left.Op)
}
to := nr.Left
- Linksym(nam.Sym).WriteAddr(Ctxt, nam.Xoffset, wid, Linksym(to.Sym), to.Xoffset)
+ s.WriteAddr(Ctxt, nam.Xoffset, wid, Linksym(to.Sym), to.Xoffset)
case ONAME:
if nr.Class != PFUNC {
Fatalf("gdata NAME not PFUNC %d", nr.Class)
}
- Linksym(nam.Sym).WriteAddr(Ctxt, nam.Xoffset, wid, Linksym(funcsym(nr.Sym)), nr.Xoffset)
+ s.WriteAddr(Ctxt, nam.Xoffset, wid, Linksym(funcsym(nr.Sym)), nr.Xoffset)
default:
Fatalf("gdata unhandled op %v %v\n", nr, nr.Op)
}
}
-
-func gdatacomplex(nam *Node, cval *Mpcplx) {
- t := Types[cplxsubtype(nam.Type.Etype)]
- r := cval.Real.Float64()
- i := cval.Imag.Float64()
- s := Linksym(nam.Sym)
-
- switch t.Etype {
- case TFLOAT32:
- s.WriteFloat32(Ctxt, nam.Xoffset, float32(r))
- s.WriteFloat32(Ctxt, nam.Xoffset+4, float32(i))
- case TFLOAT64:
- s.WriteFloat64(Ctxt, nam.Xoffset, r)
- s.WriteFloat64(Ctxt, nam.Xoffset+8, i)
- }
-}
-
-func gdatastring(nam *Node, sval string) {
- s := Linksym(nam.Sym)
- _, symdata := stringsym(sval)
- s.WriteAddr(Ctxt, nam.Xoffset, Widthptr, symdata, 0)
- s.WriteInt(Ctxt, nam.Xoffset+int64(Widthptr), Widthint, int64(len(sval)))
-}
diff --git a/src/cmd/compile/internal/gc/opnames.go b/src/cmd/compile/internal/gc/opnames.go
index bcdae6c..bd56506 100644
--- a/src/cmd/compile/internal/gc/opnames.go
+++ b/src/cmd/compile/internal/gc/opnames.go
@@ -48,6 +48,7 @@ var opnames = []string{
OMAPLIT: "MAPLIT",
OSTRUCTLIT: "STRUCTLIT",
OARRAYLIT: "ARRAYLIT",
+ OSLICELIT: "SLICELIT",
OPTRLIT: "PTRLIT",
OCONV: "CONV",
OCONVIFACE: "CONVIFACE",
@@ -76,6 +77,7 @@ var opnames = []string{
OINDEX: "INDEX",
OINDEXMAP: "INDEXMAP",
OKEY: "KEY",
+ OSTRUCTKEY: "STRUCTKEY",
OLEN: "LEN",
OMAKE: "MAKE",
OMAKECHAN: "MAKECHAN",
@@ -143,14 +145,14 @@ var opnames = []string{
OINLCALL: "INLCALL",
OEFACE: "EFACE",
OITAB: "ITAB",
+ OIDATA: "IDATA",
OSPTR: "SPTR",
OCLOSUREVAR: "CLOSUREVAR",
OCFUNC: "CFUNC",
OCHECKNIL: "CHECKNIL",
OVARKILL: "VARKILL",
OVARLIVE: "VARLIVE",
- OREGISTER: "REGISTER",
- OINDREG: "INDREG",
+ OINDREGSP: "INDREGSP",
OCMP: "CMP",
ODEC: "DEC",
OINC: "INC",
diff --git a/src/cmd/compile/internal/gc/order.go b/src/cmd/compile/internal/gc/order.go
index f3b1028..e3d65e5 100644
--- a/src/cmd/compile/internal/gc/order.go
+++ b/src/cmd/compile/internal/gc/order.go
@@ -6,7 +6,6 @@ package gc
import (
"fmt"
- "strings"
)
// Rewrite tree to use separate statements to enforce
@@ -62,7 +61,7 @@ func order(fn *Node) {
func ordertemp(t *Type, order *Order, clear bool) *Node {
var_ := temp(t)
if clear {
- a := Nod(OAS, var_, nil)
+ a := nod(OAS, var_, nil)
a = typecheck(a, Etop)
order.out = append(order.out, a)
}
@@ -85,7 +84,7 @@ func ordertemp(t *Type, order *Order, clear bool) *Node {
// to be filled in.)
func ordercopyexpr(n *Node, t *Type, order *Order, clear int) *Node {
var_ := ordertemp(t, order, clear != 0)
- a := Nod(OAS, var_, n)
+ a := nod(OAS, var_, n)
a = typecheck(a, Etop)
order.out = append(order.out, a)
return var_
@@ -170,14 +169,6 @@ func ordersafeexpr(n *Node, order *Order) *Node {
}
}
-// Istemp reports whether n is a temporary variable.
-func istemp(n *Node) bool {
- if n.Op != ONAME {
- return false
- }
- return strings.HasPrefix(n.Sym.Name, "autotmp_")
-}
-
// Isaddrokay reports whether it is okay to pass n's address to runtime routines.
// Taking the address of a variable makes the liveness and optimization analyses
// lose track of where the variable's lifetime ends. To avoid hurting the analyses
@@ -185,12 +176,12 @@ func istemp(n *Node) bool {
// because we emit explicit VARKILL instructions marking the end of those
// temporaries' lifetimes.
func isaddrokay(n *Node) bool {
- return islvalue(n) && (n.Op != ONAME || n.Class == PEXTERN || istemp(n))
+ return islvalue(n) && (n.Op != ONAME || n.Class == PEXTERN || n.IsAutoTmp())
}
-// Orderaddrtemp ensures that *np is okay to pass by address to runtime routines.
-// If the original argument *np is not okay, orderaddrtemp creates a tmp, emits
-// tmp = *np, and then sets *np to the tmp variable.
+// 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.
func orderaddrtemp(n *Node, order *Order) *Node {
if isaddrokay(n) {
return n
@@ -222,11 +213,11 @@ func cleantempnopop(mark ordermarker, order *Order, out *[]*Node) {
if n.Name.Keepalive {
n.Name.Keepalive = false
n.Addrtaken = true // ensure SSA keeps the n variable
- kill = Nod(OVARLIVE, n, nil)
+ kill = nod(OVARLIVE, n, nil)
kill = typecheck(kill, Etop)
*out = append(*out, kill)
}
- kill = Nod(OVARKILL, n, nil)
+ kill = nod(OVARKILL, n, nil)
kill = typecheck(kill, Etop)
*out = append(*out, kill)
}
@@ -336,7 +327,7 @@ func copyret(n *Node, order *Order) []*Node {
l2 = append(l2, tmp)
}
- as := Nod(OAS2, nil, nil)
+ as := nod(OAS2, nil, nil)
as.List.Set(l1)
as.Rlist.Set1(n)
as = typecheck(as, Etop)
@@ -363,7 +354,7 @@ func ordercall(n *Node, order *Order) {
ordercallargs(&n.List, order)
if n.Op == OCALLFUNC {
- t, it := IterFields(n.Left.Type.Params())
+ 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
@@ -395,13 +386,8 @@ func ordercall(n *Node, order *Order) {
}
// Ordermapassign appends n to order->out, introducing temporaries
-// to make sure that all map assignments have the form m[k] = x,
-// where x is addressable.
-// (Orderexpr has already been called on n, so we know k is addressable.)
-//
-// If n is m[k] = x where x is not addressable, the rewrite is:
-// tmp = x
-// m[k] = tmp
+// to make sure that all map assignments have the form m[k] = x.
+// (Note: orderexpr has already been called on n, so we know k is addressable.)
//
// If n is the multiple assignment form ..., m[k], ... = ..., the rewrite is
// t1 = m
@@ -428,10 +414,10 @@ func ordermapassign(n *Node, order *Order) {
// We call writebarrierfat only for values > 4 pointers long. See walk.go.
// TODO(mdempsky): writebarrierfat doesn't exist anymore, but removing that
// logic causes net/http's tests to become flaky; see CL 21242.
- if (n.Left.Op == OINDEXMAP || (needwritebarrier(n.Left, n.Right) && n.Left.Type.Width > int64(4*Widthptr))) && !isaddrokay(n.Right) {
+ 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 := nod(OAS, m, n.Left)
a = typecheck(a, Etop)
order.out = append(order.out, a)
}
@@ -443,21 +429,21 @@ func ordermapassign(n *Node, order *Order) {
for i1, n1 := range n.List.Slice() {
if n1.Op == OINDEXMAP {
m = n1
- if !istemp(m.Left) {
+ if !m.Left.IsAutoTmp() {
m.Left = ordercopyexpr(m.Left, m.Left.Type, order, 0)
}
- if !istemp(m.Right) {
+ if !m.Right.IsAutoTmp() {
m.Right = ordercopyexpr(m.Right, m.Right.Type, order, 0)
}
n.List.SetIndex(i1, ordertemp(m.Type, order, false))
- a = Nod(OAS, m, n.List.Index(i1))
+ a = nod(OAS, m, n.List.Index(i1))
a = typecheck(a, Etop)
post = append(post, a)
} else if instrumenting && n.Op == OAS2FUNC && !isblank(n.List.Index(i1)) {
m = n.List.Index(i1)
t := ordertemp(m.Type, order, false)
n.List.SetIndex(i1, t)
- a = Nod(OAS, m, t)
+ a = nod(OAS, m, t)
a = typecheck(a, Etop)
post = append(post, a)
}
@@ -530,7 +516,7 @@ func orderstmt(n *Node, order *Order) {
}
tmp1 = ordercopyexpr(tmp1, n.Left.Type, order, 0)
// TODO(marvin): Fix Node.EType type union.
- n.Right = Nod(Op(n.Etype), tmp1, n.Right)
+ n.Right = nod(Op(n.Etype), tmp1, n.Right)
n.Right = typecheck(n.Right, Erv)
n.Right = orderexpr(n.Right, order, nil)
n.Etype = 0
@@ -538,7 +524,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,
// and make sure OINDEXMAP is not copied out.
case OAS2MAPR:
t := marktemp(order)
@@ -556,7 +542,7 @@ func orderstmt(n *Node, order *Order) {
ordermapassign(n, order)
cleantemp(t, order)
- // Special: avoid copy of func call n->rlist->n.
+ // Special: avoid copy of func call n->rlist->n.
case OAS2FUNC:
t := marktemp(order)
@@ -565,7 +551,7 @@ func orderstmt(n *Node, order *Order) {
ordermapassign(n, order)
cleantemp(t, order)
- // Special: use temporary variables to hold result,
+ // Special: use temporary variables to hold result,
// so that assertI2Tetc can take address of temporary.
// No temporary for blank assignment.
case OAS2DOTTYPE:
@@ -573,21 +559,34 @@ 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)
- if isblank(n.List.First()) {
- order.out = append(order.out, n)
- } else {
+
+ var tmp1, tmp2 *Node
+ if !isblank(n.List.First()) {
typ := n.Rlist.First().Type
- tmp1 := ordertemp(typ, order, haspointers(typ))
- order.out = append(order.out, n)
- r := Nod(OAS, n.List.First(), tmp1)
+ 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.Set([]*Node{tmp1, n.List.Second()})
+ 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)
}
cleantemp(t, order)
- // Special: use temporary variables to hold result,
+ // Special: use temporary variables to hold result,
// so that chanrecv can take address of temporary.
case OAS2RECV:
t := marktemp(order)
@@ -596,27 +595,22 @@ func orderstmt(n *Node, order *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()))
- var tmp2 *Node
- if !isblank(n.List.Second()) {
- tmp2 = ordertemp(n.List.Second().Type, order, false)
- } else {
- tmp2 = ordertemp(Types[TBOOL], order, false)
- }
+ tmp2 := ordertemp(Types[TBOOL], order, false)
order.out = append(order.out, n)
- r := Nod(OAS, n.List.First(), tmp1)
+ r := nod(OAS, n.List.First(), tmp1)
r = typecheck(r, Etop)
ordermapassign(r, order)
- r = Nod(OAS, n.List.Second(), tmp2)
+ r = okas(n.List.Second(), tmp2)
r = typecheck(r, Etop)
ordermapassign(r, order)
n.List.Set([]*Node{tmp1, tmp2})
cleantemp(t, order)
- // Special: does not save n onto out.
+ // Special: does not save n onto out.
case OBLOCK, OEMPTY:
orderstmtlist(n.List, order)
- // Special: n->left is not an expression; save as is.
+ // Special: n->left is not an expression; save as is.
case OBREAK,
OCONTINUE,
ODCL,
@@ -629,7 +623,7 @@ func orderstmt(n *Node, order *Order) {
ORETJMP:
order.out = append(order.out, n)
- // Special: handle call arguments.
+ // Special: handle call arguments.
case OCALLFUNC, OCALLINTER, OCALLMETH:
t := marktemp(order)
@@ -637,7 +631,7 @@ func orderstmt(n *Node, order *Order) {
order.out = append(order.out, n)
cleantemp(t, order)
- // Special: order arguments to inner call but not call itself.
+ // Special: order arguments to inner call but not call itself.
case ODEFER, OPROC:
t := marktemp(order)
@@ -668,7 +662,7 @@ func orderstmt(n *Node, order *Order) {
order.out = append(order.out, n)
cleantemp(t, order)
- // Clean temporaries from condition evaluation at
+ // Clean temporaries from condition evaluation at
// beginning of loop body and after for statement.
case OFOR:
t := marktemp(order)
@@ -676,13 +670,13 @@ func orderstmt(n *Node, order *Order) {
n.Left = orderexprinplace(n.Left, order)
var l []*Node
cleantempnopop(t, order, &l)
- n.Nbody.Set(append(l, n.Nbody.Slice()...))
+ n.Nbody.Prepend(l...)
orderblockNodes(&n.Nbody)
n.Right = orderstmtinplace(n.Right)
order.out = append(order.out, n)
cleantemp(t, order)
- // Clean temporaries from condition at
+ // Clean temporaries from condition at
// beginning of both branches.
case OIF:
t := marktemp(order)
@@ -690,16 +684,16 @@ func orderstmt(n *Node, order *Order) {
n.Left = orderexprinplace(n.Left, order)
var l []*Node
cleantempnopop(t, order, &l)
- n.Nbody.Set(append(l, n.Nbody.Slice()...))
+ n.Nbody.Prepend(l...)
l = nil
cleantempnopop(t, order, &l)
- n.Rlist.Set(append(l, n.Rlist.Slice()...))
+ n.Rlist.Prepend(l...)
poptemp(t, order)
orderblockNodes(&n.Nbody)
n.Rlist.Set(orderblock(n.Rlist))
order.out = append(order.out, n)
- // Special: argument will be converted to interface using convT2E
+ // Special: argument will be converted to interface using convT2E
// so make sure it is an addressable temporary.
case OPANIC:
t := marktemp(order)
@@ -749,7 +743,7 @@ func orderstmt(n *Node, order *Order) {
r := n.Right
if r.Type.IsString() && r.Type != Types[TSTRING] {
- r = Nod(OCONV, r, nil)
+ r = nod(OCONV, r, nil)
r.Type = Types[TSTRING]
r = typecheck(r, Erv)
}
@@ -807,7 +801,7 @@ func orderstmt(n *Node, order *Order) {
if r != nil {
switch r.Op {
default:
- Yyerror("unknown op in select %v", r.Op)
+ yyerror("unknown op in select %v", r.Op)
Dump("select case", r)
// If this is case x := <-ch or case x, y := <-ch, the case has
@@ -829,7 +823,7 @@ func orderstmt(n *Node, order *Order) {
}
if r.Ninit.Len() != 0 {
- Yyerror("ninit on select recv")
+ yyerror("ninit on select recv")
dumplist("ninit", r.Ninit)
}
@@ -860,13 +854,13 @@ func orderstmt(n *Node, order *Order) {
tmp1 = r.Left
if r.Colas {
- tmp2 = Nod(ODCL, tmp1, nil)
+ 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()))
- tmp2 = Nod(OAS, tmp1, r.Left)
+ tmp2 = nod(OAS, tmp1, r.Left)
tmp2 = typecheck(tmp2, Etop)
n2.Ninit.Append(tmp2)
}
@@ -877,13 +871,13 @@ func orderstmt(n *Node, order *Order) {
if r.List.Len() != 0 {
tmp1 = r.List.First()
if r.Colas {
- tmp2 = Nod(ODCL, tmp1, nil)
+ tmp2 = nod(ODCL, tmp1, nil)
tmp2 = typecheck(tmp2, Etop)
n2.Ninit.Append(tmp2)
}
- r.List.Set1(ordertemp(tmp1.Type, order, false))
- tmp2 = Nod(OAS, tmp1, r.List.First())
+ r.List.Set1(ordertemp(Types[TBOOL], order, false))
+ tmp2 = okas(tmp1, r.List.First())
tmp2 = typecheck(tmp2, Etop)
n2.Ninit.Append(tmp2)
}
@@ -891,7 +885,7 @@ func orderstmt(n *Node, order *Order) {
case OSEND:
if r.Ninit.Len() != 0 {
- Yyerror("ninit on select send")
+ yyerror("ninit on select send")
dumplist("ninit", r.Ninit)
}
@@ -899,11 +893,11 @@ func orderstmt(n *Node, order *Order) {
// r->left is c, r->right is x, both are always evaluated.
r.Left = orderexpr(r.Left, order, nil)
- if !istemp(r.Left) {
+ if !r.Left.IsAutoTmp() {
r.Left = ordercopyexpr(r.Left, r.Left.Type, order, 0)
}
r.Right = orderexpr(r.Right, order, nil)
- if !istemp(r.Right) {
+ if !r.Right.IsAutoTmp() {
r.Right = ordercopyexpr(r.Right, r.Right.Type, order, 0)
}
}
@@ -917,14 +911,14 @@ func orderstmt(n *Node, order *Order) {
for _, n3 := range n.List.Slice() {
s := n3.Ninit.Slice()
cleantempnopop(t, order, &s)
- n3.Nbody.Set(append(s, n3.Nbody.Slice()...))
+ n3.Nbody.Prepend(s...)
n3.Ninit.Set(nil)
}
order.out = append(order.out, n)
poptemp(t, order)
- // Special: value being sent is passed as a pointer; make it addressable.
+ // Special: value being sent is passed as a pointer; make it addressable.
case OSEND:
t := marktemp(order)
@@ -934,7 +928,7 @@ func orderstmt(n *Node, order *Order) {
order.out = append(order.out, n)
cleantemp(t, order)
- // TODO(rsc): Clean temporaries more aggressively.
+ // TODO(rsc): Clean temporaries more aggressively.
// Note that because walkswitch will rewrite some of the
// switch into a binary search, this is not as easy as it looks.
// (If we ran that code here we could invoke orderstmt on
@@ -1002,7 +996,7 @@ func orderexpr(n *Node, order *Order, lhs *Node) *Node {
orderexprlist(n.List, order)
orderexprlist(n.Rlist, order)
- // Addition of strings turns into a function call.
+ // Addition of strings turns into a function call.
// Allocate a temporary to hold the strings.
// Fewer than 5 strings use direct runtime helpers.
case OADDSTR:
@@ -1053,8 +1047,14 @@ func orderexpr(n *Node, order *Order, lhs *Node) *Node {
// key must be addressable
case OINDEXMAP:
n.Left = orderexpr(n.Left, order, nil)
-
n.Right = orderexpr(n.Right, order, nil)
+ needCopy := false
+
+ if n.Etype == 0 && instrumenting {
+ // Race detector needs the copy so it can
+ // call treecopy on the result.
+ needCopy = true
+ }
// For x = m[string(k)] where k is []byte, the allocation of
// backing bytes for the string can be avoided by reusing
@@ -1068,16 +1068,17 @@ func orderexpr(n *Node, order *Order, lhs *Node) *Node {
// conversion (by the ordercopyexpr a few lines below).
if n.Etype == 0 && n.Right.Op == OARRAYBYTESTR {
n.Right.Op = OARRAYBYTESTRTMP
+ needCopy = true
}
+ // Map calls need to take the address of the key.
n.Right = orderaddrtemp(n.Right, order)
- if n.Etype == 0 {
- // use of value (not being assigned);
- // make copy in temporary.
+
+ if needCopy {
n = ordercopyexpr(n, n.Type, order, 0)
}
- // concrete type (not interface) argument must be addressable
+ // concrete type (not interface) argument must be addressable
// temporary to pass to runtime.
case OCONVIFACE:
n.Left = orderexpr(n.Left, order, nil)
@@ -1110,7 +1111,7 @@ func orderexpr(n *Node, order *Order, lhs *Node) *Node {
var s []*Node
cleantempnopop(mark, order, &s)
- n.Right.Ninit.Set(append(s, n.Right.Ninit.Slice()...))
+ n.Right.Ninit.Prepend(s...)
n.Right = orderexprinplace(n.Right, order)
case OCALLFUNC,
@@ -1160,7 +1161,7 @@ func orderexpr(n *Node, order *Order, lhs *Node) *Node {
prealloc[n] = ordertemp(Types[TUINT8], order, false) // walk will fill in correct type
}
- case OARRAYLIT, OCALLPART:
+ case OARRAYLIT, OSLICELIT, OCALLPART:
n.Left = orderexpr(n.Left, order, nil)
n.Right = orderexpr(n.Right, order, nil)
orderexprlist(n.List, order)
@@ -1180,10 +1181,10 @@ func orderexpr(n *Node, order *Order, lhs *Node) *Node {
case ODOTTYPE, ODOTTYPE2:
n.Left = orderexpr(n.Left, order, nil)
- // TODO(rsc): The Isfat is for consistency with componentgen and walkexpr.
+ // TODO(rsc): The isfat is for consistency with componentgen and walkexpr.
// It needs to be removed in all three places.
// That would allow inlining x.(struct{*int}) the same as x.(*int).
- if !isdirectiface(n.Type) || Isfat(n.Type) || instrumenting {
+ if !isdirectiface(n.Type) || isfat(n.Type) || instrumenting {
n = ordercopyexpr(n, n.Type, order, 1)
}
@@ -1206,3 +1207,12 @@ func orderexpr(n *Node, order *Order, lhs *Node) *Node {
lineno = lno
return n
}
+
+// okas creates and returns an assignment of val to ok,
+// including an explicit conversion if necessary.
+func okas(ok, val *Node) *Node {
+ if !isblank(ok) {
+ val = conv(val, ok.Type)
+ }
+ return nod(OAS, ok, val)
+}
diff --git a/src/cmd/compile/internal/gc/parser.go b/src/cmd/compile/internal/gc/parser.go
deleted file mode 100644
index 3897db9..0000000
--- a/src/cmd/compile/internal/gc/parser.go
+++ /dev/null
@@ -1,3353 +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 gc
-
-// The recursive-descent parser is built around a slighty modified grammar
-// of Go to accommodate for the constraints imposed by strict one token look-
-// ahead, and for better error handling. Subsequent checks of the constructed
-// syntax tree restrict the language accepted by the compiler to proper Go.
-//
-// Semicolons are inserted by the lexer. The parser uses one-token look-ahead
-// to handle optional commas and semicolons before a closing ) or } .
-
-import (
- "bufio"
- "fmt"
- "strconv"
- "strings"
-)
-
-const trace = false // if set, parse tracing can be enabled with -x
-
-// parse_import parses the export data of a package that is imported.
-func parse_import(bin *bufio.Reader, indent []byte) {
- newparser(bin, indent).import_package()
-}
-
-// parse_file parses a single Go source file.
-func parse_file(bin *bufio.Reader) {
- newparser(bin, nil).file()
-}
-
-type parser struct {
- lexer
- fnest int // function nesting level (for error handling)
- xnest int // expression nesting level (for complit ambiguity resolution)
- indent []byte // tracing support
-
- // TODO(gri) remove this once we switch to binary export format
- structpkg *Pkg // for verification in addmethod only
-}
-
-// newparser returns a new parser ready to parse from src.
-// indent is the initial indentation for tracing output.
-func newparser(src *bufio.Reader, indent []byte) *parser {
- var p parser
- p.bin = src
- p.indent = indent
- p.next()
- return &p
-}
-
-func (p *parser) got(tok int32) bool {
- if p.tok == tok {
- p.next()
- return true
- }
- return false
-}
-
-func (p *parser) want(tok int32) {
- if !p.got(tok) {
- p.syntax_error("expecting " + tokstring(tok))
- p.advance()
- }
-}
-
-// ----------------------------------------------------------------------------
-// Syntax error handling
-
-func (p *parser) syntax_error(msg string) {
- if trace && Debug['x'] != 0 {
- defer p.trace("syntax_error (" + msg + ")")()
- }
-
- if p.tok == EOF && nerrors > 0 {
- return // avoid meaningless follow-up errors
- }
-
- // add punctuation etc. as needed to msg
- switch {
- case msg == "":
- // nothing to do
- case strings.HasPrefix(msg, "in"), strings.HasPrefix(msg, "at"), strings.HasPrefix(msg, "after"):
- msg = " " + msg
- case strings.HasPrefix(msg, "expecting"):
- msg = ", " + msg
- default:
- // plain error - we don't care about current token
- Yyerror("syntax error: %s", msg)
- return
- }
-
- // determine token string
- var tok string
- switch p.tok {
- case LNAME:
- if p.sym_ != nil && p.sym_.Name != "" {
- tok = p.sym_.Name
- } else {
- tok = "name"
- }
- case LLITERAL:
- if litbuf == "" {
- litbuf = "literal " + lexbuf.String()
- }
- tok = litbuf
- case LOPER:
- tok = goopnames[p.op]
- case LASOP:
- tok = goopnames[p.op] + "="
- case LINCOP:
- tok = goopnames[p.op] + goopnames[p.op]
- default:
- tok = tokstring(p.tok)
- }
-
- Yyerror("syntax error: unexpected %s", tok+msg)
-}
-
-// Like syntax_error, but reports error at given line rather than current lexer line.
-func (p *parser) syntax_error_at(lno int32, msg string) {
- defer func(lno int32) {
- lineno = lno
- }(lineno)
- lineno = lno
- p.syntax_error(msg)
-}
-
-// The stoplist contains keywords that start a statement.
-// They are good synchronization points in case of syntax
-// errors and (usually) shouldn't be skipped over.
-var stoplist = map[int32]bool{
- LBREAK: true,
- LCONST: true,
- LCONTINUE: true,
- LDEFER: true,
- LFALL: true,
- LFOR: true,
- LFUNC: true,
- LGO: true,
- LGOTO: true,
- LIF: true,
- LRETURN: true,
- LSELECT: true,
- LSWITCH: true,
- LTYPE: true,
- LVAR: true,
-}
-
-// Advance consumes tokens until it finds a token of the stop- or followlist.
-// The stoplist is only considered if we are inside a function (p.fnest > 0).
-// The followlist is the list of valid tokens that can follow a production;
-// if it is empty, exactly one token is consumed to ensure progress.
-func (p *parser) advance(followlist ...int32) {
- if len(followlist) == 0 {
- p.next()
- return
- }
- for p.tok != EOF {
- if p.fnest > 0 && stoplist[p.tok] {
- return
- }
- for _, follow := range followlist {
- if p.tok == follow {
- return
- }
- }
- p.next()
- }
-}
-
-func tokstring(tok int32) string {
- switch tok {
- case EOF:
- return "EOF"
- case ',':
- return "comma"
- case ';':
- return "semicolon or newline"
- }
- if 0 <= tok && tok < 128 {
- // get invisibles properly backslashed
- s := strconv.QuoteRune(tok)
- if n := len(s); n > 0 && s[0] == '\'' && s[n-1] == '\'' {
- s = s[1 : n-1]
- }
- return s
- }
- if s := tokstrings[tok]; s != "" {
- return s
- }
- // catchall
- return fmt.Sprintf("tok-%v", tok)
-}
-
-var tokstrings = map[int32]string{
- LNAME: "NAME",
- LLITERAL: "LITERAL",
-
- LOPER: "op",
- LASOP: "op=",
- LINCOP: "opop",
-
- LCOLAS: ":=",
- LCOMM: "<-",
- LDDD: "...",
-
- LBREAK: "break",
- LCASE: "case",
- LCHAN: "chan",
- LCONST: "const",
- LCONTINUE: "continue",
- LDEFAULT: "default",
- LDEFER: "defer",
- LELSE: "else",
- LFALL: "fallthrough",
- LFOR: "for",
- LFUNC: "func",
- LGO: "go",
- LGOTO: "goto",
- LIF: "if",
- LIMPORT: "import",
- LINTERFACE: "interface",
- LMAP: "map",
- LPACKAGE: "package",
- LRANGE: "range",
- LRETURN: "return",
- LSELECT: "select",
- LSTRUCT: "struct",
- LSWITCH: "switch",
- LTYPE: "type",
- LVAR: "var",
-}
-
-// usage: defer p.trace(msg)()
-func (p *parser) trace(msg string) func() {
- fmt.Printf("%5d: %s%s (\n", lineno, p.indent, msg)
- const tab = ". "
- p.indent = append(p.indent, tab...)
- return func() {
- p.indent = p.indent[:len(p.indent)-len(tab)]
- if x := recover(); x != nil {
- panic(x) // skip print_trace
- }
- fmt.Printf("%5d: %s)\n", lineno, p.indent)
- }
-}
-
-// ----------------------------------------------------------------------------
-// Parsing package files
-//
-// 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.
-
-// SourceFile = PackageClause ";" { ImportDecl ";" } { TopLevelDecl ";" } .
-func (p *parser) file() {
- if trace && Debug['x'] != 0 {
- defer p.trace("file")()
- }
-
- p.package_()
- p.want(';')
-
- for p.tok == LIMPORT {
- p.import_()
- p.want(';')
- }
-
- xtop = append(xtop, p.xdcl_list()...)
-
- p.want(EOF)
-}
-
-// PackageClause = "package" PackageName .
-// PackageName = identifier .
-func (p *parser) package_() {
- if trace && Debug['x'] != 0 {
- defer p.trace("package_")()
- }
-
- if !p.got(LPACKAGE) {
- p.syntax_error("package statement must be first")
- errorexit()
- }
- mkpackage(p.sym().Name)
-}
-
-// ImportDecl = "import" ( ImportSpec | "(" { ImportSpec ";" } ")" ) .
-func (p *parser) import_() {
- if trace && Debug['x'] != 0 {
- defer p.trace("import_")()
- }
-
- p.want(LIMPORT)
- if p.got('(') {
- for p.tok != EOF && p.tok != ')' {
- p.importdcl()
- if !p.osemi(')') {
- break
- }
- }
- p.want(')')
- } else {
- p.importdcl()
- }
-}
-
-// ImportSpec = [ "." | PackageName ] ImportPath .
-// ImportPath = string_lit .
-func (p *parser) importdcl() {
- if trace && Debug['x'] != 0 {
- defer p.trace("importdcl")()
- }
-
- var my *Sym
- switch p.tok {
- case LNAME, '@', '?':
- // import with given name
- my = p.sym()
-
- case '.':
- // import into my name space
- my = Lookup(".")
- p.next()
- }
-
- if p.tok != LLITERAL {
- p.syntax_error("missing import path; require quoted string")
- p.advance(';', ')')
- return
- }
-
- line := lineno
-
- // We need to clear importpkg before calling p.next(),
- // otherwise it will affect lexlineno.
- // TODO(mdempsky): Fix this clumsy API.
- importfile(&p.val, p.indent)
- ipkg := importpkg
- importpkg = nil
-
- p.next()
- if ipkg == nil {
- if nerrors == 0 {
- Fatalf("phase error in import")
- }
- return
- }
-
- ipkg.Direct = true
-
- if my == nil {
- my = Lookup(ipkg.Name)
- }
-
- pack := Nod(OPACK, nil, nil)
- pack.Sym = my
- pack.Name.Pkg = ipkg
- pack.Lineno = line
-
- if strings.HasPrefix(my.Name, ".") {
- importdot(ipkg, pack)
- return
- }
- if my.Name == "init" {
- lineno = line
- Yyerror("cannot import package as init - init must be a func")
- return
- }
- if my.Name == "_" {
- return
- }
- if my.Def != nil {
- lineno = line
- redeclare(my, "as imported package name")
- }
- my.Def = pack
- my.Lastlineno = line
- my.Block = 1 // at top level
-}
-
-// import_package parses the header of an imported package as exported
-// in textual format from another package.
-func (p *parser) import_package() {
- if trace && Debug['x'] != 0 {
- defer p.trace("import_package")()
- }
-
- p.want(LPACKAGE)
- var name string
- if p.tok == LNAME {
- name = p.sym_.Name
- p.next()
- } else {
- p.import_error()
- }
-
- // read but skip "safe" bit (see issue #15772)
- if p.tok == LNAME {
- p.next()
- }
- p.want(';')
-
- if importpkg.Name == "" {
- importpkg.Name = name
- numImport[name]++
- } else if importpkg.Name != name {
- Yyerror("conflicting names %s and %s for package %q", importpkg.Name, name, importpkg.Path)
- }
-
- typecheckok = true
- defercheckwidth()
-
- p.hidden_import_list()
- p.want('$')
- // don't read past 2nd '$'
- if p.tok != '$' {
- p.import_error()
- }
-
- resumecheckwidth()
- typecheckok = false
-}
-
-// Declaration = ConstDecl | TypeDecl | VarDecl .
-// ConstDecl = "const" ( ConstSpec | "(" { ConstSpec ";" } ")" ) .
-// TypeDecl = "type" ( TypeSpec | "(" { TypeSpec ";" } ")" ) .
-// VarDecl = "var" ( VarSpec | "(" { VarSpec ";" } ")" ) .
-func (p *parser) common_dcl() []*Node {
- if trace && Debug['x'] != 0 {
- defer p.trace("common_dcl")()
- }
-
- var dcl func() []*Node
- switch p.tok {
- case LVAR:
- dcl = p.vardcl
-
- case LCONST:
- iota_ = 0
- dcl = p.constdcl
-
- case LTYPE:
- dcl = p.typedcl
-
- default:
- panic("unreachable")
- }
-
- p.next()
- var s []*Node
- if p.got('(') {
- for p.tok != EOF && p.tok != ')' {
- s = append(s, dcl()...)
- if !p.osemi(')') {
- break
- }
- }
- p.want(')')
- } else {
- s = dcl()
- }
-
- iota_ = -100000
- lastconst = nil
-
- return s
-}
-
-// VarSpec = IdentifierList ( Type [ "=" ExpressionList ] | "=" ExpressionList ) .
-func (p *parser) vardcl() []*Node {
- if trace && Debug['x'] != 0 {
- defer p.trace("vardcl")()
- }
-
- names := p.dcl_name_list()
- var typ *Node
- var exprs []*Node
- if p.got('=') {
- exprs = p.expr_list()
- } else {
- typ = p.ntype()
- if p.got('=') {
- exprs = p.expr_list()
- }
- }
-
- return variter(names, typ, exprs)
-}
-
-// ConstSpec = IdentifierList [ [ Type ] "=" ExpressionList ] .
-func (p *parser) constdcl() []*Node {
- if trace && Debug['x'] != 0 {
- defer p.trace("constdcl")()
- }
-
- names := p.dcl_name_list()
- var typ *Node
- var exprs []*Node
- if p.tok != EOF && p.tok != ';' && p.tok != ')' {
- typ = p.try_ntype()
- if p.got('=') {
- exprs = p.expr_list()
- }
- }
-
- return constiter(names, typ, exprs)
-}
-
-// TypeSpec = identifier Type .
-func (p *parser) typedcl() []*Node {
- if trace && Debug['x'] != 0 {
- defer p.trace("typedcl")()
- }
-
- name := typedcl0(p.sym())
-
- typ := p.try_ntype()
- // handle case where type is missing
- if typ == nil {
- p.syntax_error("in type declaration")
- p.advance(';', ')')
- }
-
- return []*Node{typedcl1(name, typ, true)}
-}
-
-// SimpleStmt = EmptyStmt | ExpressionStmt | SendStmt | IncDecStmt | Assignment | ShortVarDecl .
-//
-// simple_stmt may return missing_stmt if labelOk is set.
-func (p *parser) simple_stmt(labelOk, rangeOk bool) *Node {
- if trace && Debug['x'] != 0 {
- defer p.trace("simple_stmt")()
- }
-
- if rangeOk && p.got(LRANGE) {
- // LRANGE expr
- r := Nod(ORANGE, nil, p.expr())
- r.Etype = 0 // := flag
- return r
- }
-
- lhs := p.expr_list()
-
- if len(lhs) == 1 && p.tok != '=' && p.tok != LCOLAS && p.tok != LRANGE {
- // expr
- lhs := lhs[0]
- switch p.tok {
- case LASOP:
- // expr LASOP expr
- op := p.op
- p.next()
- rhs := p.expr()
-
- stmt := Nod(OASOP, lhs, rhs)
- stmt.Etype = EType(op) // rathole to pass opcode
- return stmt
-
- case LINCOP:
- // expr LINCOP
- p.next()
-
- stmt := Nod(OASOP, lhs, Nodintconst(1))
- stmt.Implicit = true
- stmt.Etype = EType(p.op)
- return stmt
-
- case ':':
- // labelname ':' stmt
- if labelOk {
- // If we have a labelname, it was parsed by operand
- // (calling p.name()) and given an ONAME, ONONAME, OTYPE, OPACK, or OLITERAL node.
- // We only have a labelname if there is a symbol (was issue 14006).
- switch lhs.Op {
- case ONAME, ONONAME, OTYPE, OPACK, OLITERAL:
- if lhs.Sym != nil {
- lhs = newname(lhs.Sym)
- break
- }
- fallthrough
- default:
- p.syntax_error("expecting semicolon or newline or }")
- // we already progressed, no need to advance
- }
- lhs := Nod(OLABEL, lhs, nil)
- lhs.Sym = dclstack // context, for goto restrictions
- p.next() // consume ':' after making label node for correct lineno
- return p.labeled_stmt(lhs)
- }
- fallthrough
-
- default:
- // expr
- // Since a bare name used as an expression is an error,
- // introduce a wrapper node where necessary to give the
- // correct line.
- return wrapname(lhs)
- }
- }
-
- // expr_list
- switch p.tok {
- case '=':
- p.next()
- if rangeOk && p.got(LRANGE) {
- // expr_list '=' LRANGE expr
- r := Nod(ORANGE, nil, p.expr())
- r.List.Set(lhs)
- r.Etype = 0 // := flag
- return r
- }
-
- // expr_list '=' expr_list
- rhs := p.expr_list()
-
- if len(lhs) == 1 && len(rhs) == 1 {
- // simple
- return Nod(OAS, lhs[0], rhs[0])
- }
- // multiple
- stmt := Nod(OAS2, nil, nil)
- stmt.List.Set(lhs)
- stmt.Rlist.Set(rhs)
- return stmt
-
- case LCOLAS:
- lno := lineno
- p.next()
-
- if rangeOk && p.got(LRANGE) {
- // expr_list LCOLAS LRANGE expr
- r := Nod(ORANGE, nil, p.expr())
- r.List.Set(lhs)
- r.Colas = true
- colasdefn(lhs, r)
- return r
- }
-
- // expr_list LCOLAS expr_list
- rhs := p.expr_list()
-
- if rhs[0].Op == OTYPESW {
- ts := Nod(OTYPESW, nil, rhs[0].Right)
- if len(rhs) > 1 {
- Yyerror("expr.(type) must be alone in list")
- }
- if len(lhs) > 1 {
- Yyerror("argument count mismatch: %d = %d", len(lhs), 1)
- } else if (lhs[0].Op != ONAME && lhs[0].Op != OTYPE && lhs[0].Op != ONONAME && (lhs[0].Op != OLITERAL || lhs[0].Name == nil)) || isblank(lhs[0]) {
- Yyerror("invalid variable name %s in type switch", lhs[0])
- } else {
- ts.Left = dclname(lhs[0].Sym)
- } // it's a colas, so must not re-use an oldname
- return ts
- }
- return colas(lhs, rhs, lno)
-
- default:
- p.syntax_error("expecting := or = or comma")
- p.advance(';', '}')
- return nil
- }
-}
-
-// LabeledStmt = Label ":" Statement .
-// Label = identifier .
-func (p *parser) labeled_stmt(label *Node) *Node {
- if trace && Debug['x'] != 0 {
- defer p.trace("labeled_stmt")()
- }
-
- var ls *Node // labeled statement
- if p.tok != '}' && p.tok != EOF {
- ls = p.stmt()
- if ls == missing_stmt {
- // report error at line of ':' token
- p.syntax_error_at(label.Lineno, "missing statement after label")
- // we are already at the end of the labeled statement - no need to advance
- return missing_stmt
- }
- }
-
- label.Name.Defn = ls
- l := []*Node{label}
- if ls != nil {
- if ls.Op == OBLOCK && ls.Ninit.Len() == 0 {
- l = append(l, ls.List.Slice()...)
- } else {
- l = append(l, ls)
- }
- }
- return liststmt(l)
-}
-
-// case_ parses a superset of switch and select statement cases.
-// Later checks restrict the syntax to valid forms.
-//
-// ExprSwitchCase = "case" ExpressionList | "default" .
-// TypeSwitchCase = "case" TypeList | "default" .
-// TypeList = Type { "," Type } .
-// CommCase = "case" ( SendStmt | RecvStmt ) | "default" .
-// RecvStmt = [ ExpressionList "=" | IdentifierList ":=" ] RecvExpr .
-// RecvExpr = Expression .
-func (p *parser) case_(tswitch *Node) *Node {
- if trace && Debug['x'] != 0 {
- defer p.trace("case_")()
- }
-
- switch p.tok {
- case LCASE:
- p.next()
- cases := p.expr_list() // expr_or_type_list
- switch p.tok {
- case ':':
- // LCASE expr_or_type_list ':'
-
- // will be converted to OCASE
- // right will point to next case
- // done in casebody()
- markdcl() // matching popdcl in caseblock
- stmt := Nod(OXCASE, nil, nil)
- stmt.List.Set(cases)
- if tswitch != nil {
- if n := tswitch.Left; n != nil {
- // type switch - declare variable
- nn := newname(n.Sym)
- declare(nn, dclcontext)
- stmt.Rlist.Set1(nn)
-
- // keep track of the instances for reporting unused
- nn.Name.Defn = tswitch
- }
- }
-
- p.next() // consume ':' after declaring type switch var for correct lineno
- return stmt
-
- case '=':
- // LCASE expr_or_type_list '=' expr ':'
- p.next()
- rhs := p.expr()
-
- // will be converted to OCASE
- // right will point to next case
- // done in casebody()
- markdcl() // matching popdcl in caseblock
- stmt := Nod(OXCASE, nil, nil)
- var n *Node
- if len(cases) == 1 {
- n = Nod(OAS, cases[0], rhs)
- } else {
- n = Nod(OAS2, nil, nil)
- n.List.Set(cases)
- n.Rlist.Set1(rhs)
- }
- stmt.List.Set1(n)
-
- p.want(':') // consume ':' after declaring select cases for correct lineno
- return stmt
-
- case LCOLAS:
- // LCASE expr_or_type_list LCOLAS expr ':'
- lno := lineno
- p.next()
- rhs := p.expr()
-
- // will be converted to OCASE
- // right will point to next case
- // done in casebody()
- markdcl() // matching popdcl in caseblock
- stmt := Nod(OXCASE, nil, nil)
- stmt.List.Set1(colas(cases, []*Node{rhs}, lno))
-
- p.want(':') // consume ':' after declaring select cases for correct lineno
- return stmt
-
- default:
- markdcl() // for matching popdcl in caseblock
- stmt := Nod(OXCASE, nil, nil) // don't return nil
- p.syntax_error("expecting := or = or : or comma")
- p.advance(LCASE, LDEFAULT, '}')
- return stmt
- }
-
- case LDEFAULT:
- // LDEFAULT ':'
- p.next()
-
- markdcl() // matching popdcl in caseblock
- stmt := Nod(OXCASE, nil, nil)
- if tswitch != nil {
- if n := tswitch.Left; n != nil {
- // type switch - declare variable
- nn := newname(n.Sym)
- declare(nn, dclcontext)
- stmt.Rlist.Set1(nn)
-
- // keep track of the instances for reporting unused
- nn.Name.Defn = tswitch
- }
- }
-
- p.want(':') // consume ':' after declaring type switch var for correct lineno
- return stmt
-
- default:
- markdcl() // matching popdcl in caseblock
- stmt := Nod(OXCASE, nil, nil) // don't return nil
- p.syntax_error("expecting case or default or }")
- p.advance(LCASE, LDEFAULT, '}')
- return stmt
- }
-}
-
-// Block = "{" StatementList "}" .
-// StatementList = { Statement ";" } .
-func (p *parser) compound_stmt() *Node {
- if trace && Debug['x'] != 0 {
- defer p.trace("compound_stmt")()
- }
-
- markdcl()
- p.want('{')
- l := p.stmt_list()
- p.want('}')
- popdcl()
-
- if len(l) == 0 {
- return Nod(OEMPTY, nil, nil)
- }
- return liststmt(l)
-}
-
-// caseblock parses a superset of switch and select clauses.
-//
-// ExprCaseClause = ExprSwitchCase ":" StatementList .
-// TypeCaseClause = TypeSwitchCase ":" StatementList .
-// CommClause = CommCase ":" StatementList .
-func (p *parser) caseblock(tswitch *Node) *Node {
- if trace && Debug['x'] != 0 {
- defer p.trace("caseblock")()
- }
-
- stmt := p.case_(tswitch) // does markdcl
- stmt.Xoffset = int64(block)
- stmt.Nbody.Set(p.stmt_list())
-
- popdcl()
-
- return stmt
-}
-
-// caseblock_list parses a superset of switch and select clause lists.
-func (p *parser) caseblock_list(tswitch *Node) (l []*Node) {
- if trace && Debug['x'] != 0 {
- defer p.trace("caseblock_list")()
- }
-
- if !p.got('{') {
- p.syntax_error("missing { after switch clause")
- p.advance(LCASE, LDEFAULT, '}')
- }
-
- for p.tok != EOF && p.tok != '}' {
- l = append(l, p.caseblock(tswitch))
- }
- p.want('}')
- return
-}
-
-// loop_body parses if and for statement bodies.
-func (p *parser) loop_body(context string) []*Node {
- if trace && Debug['x'] != 0 {
- defer p.trace("loop_body")()
- }
-
- markdcl()
- if !p.got('{') {
- p.syntax_error("missing { after " + context)
- p.advance(LNAME, '}')
- }
-
- body := p.stmt_list()
- popdcl()
- p.want('}')
-
- return body
-}
-
-// for_header parses the header portion of a for statement.
-//
-// ForStmt = "for" [ Condition | ForClause | RangeClause ] Block .
-// Condition = Expression .
-func (p *parser) for_header() *Node {
- if trace && Debug['x'] != 0 {
- defer p.trace("for_header")()
- }
-
- init, cond, post := p.header(true)
-
- if init != nil || post != nil {
- // init ; test ; incr
- if post != nil && post.Colas {
- Yyerror("cannot declare in the for-increment")
- }
- h := Nod(OFOR, nil, nil)
- if init != nil {
- h.Ninit.Set1(init)
- }
- h.Left = cond
- h.Right = post
- return h
- }
-
- if cond != nil && cond.Op == ORANGE {
- // range_stmt - handled by pexpr
- return cond
- }
-
- // normal test
- h := Nod(OFOR, nil, nil)
- h.Left = cond
- return h
-}
-
-func (p *parser) for_body() *Node {
- if trace && Debug['x'] != 0 {
- defer p.trace("for_body")()
- }
-
- stmt := p.for_header()
- body := p.loop_body("for clause")
-
- stmt.Nbody.Append(body...)
- return stmt
-}
-
-// ForStmt = "for" [ Condition | ForClause | RangeClause ] Block .
-func (p *parser) for_stmt() *Node {
- if trace && Debug['x'] != 0 {
- defer p.trace("for_stmt")()
- }
-
- p.want(LFOR)
- markdcl()
- body := p.for_body()
- popdcl()
-
- return body
-}
-
-// header parses a combination of if, switch, and for statement headers:
-//
-// Header = [ InitStmt ";" ] [ Expression ] .
-// Header = [ InitStmt ] ";" [ Condition ] ";" [ PostStmt ] . // for_stmt only
-// InitStmt = SimpleStmt .
-// PostStmt = SimpleStmt .
-func (p *parser) header(for_stmt bool) (init, cond, post *Node) {
- if p.tok == '{' {
- return
- }
-
- outer := p.xnest
- p.xnest = -1
-
- if p.tok != ';' {
- // accept potential vardcl but complain
- // (for test/syntax/forvar.go)
- if for_stmt && p.tok == LVAR {
- Yyerror("var declaration not allowed in for initializer")
- p.next()
- }
- init = p.simple_stmt(false, for_stmt)
- // If we have a range clause, we are done.
- if for_stmt && init.Op == ORANGE {
- cond = init
- init = nil
-
- p.xnest = outer
- return
- }
- }
- if p.got(';') {
- if for_stmt {
- if p.tok != ';' {
- cond = p.simple_stmt(false, false)
- }
- p.want(';')
- if p.tok != '{' {
- post = p.simple_stmt(false, false)
- }
- } else if p.tok != '{' {
- cond = p.simple_stmt(false, false)
- }
- } else {
- cond = init
- init = nil
- }
-
- p.xnest = outer
- return
-}
-
-func (p *parser) if_header() *Node {
- if trace && Debug['x'] != 0 {
- defer p.trace("if_header")()
- }
-
- init, cond, _ := p.header(false)
- h := Nod(OIF, nil, nil)
- if init != nil {
- h.Ninit.Set1(init)
- }
- h.Left = cond
- return h
-}
-
-// IfStmt = "if" [ SimpleStmt ";" ] Expression Block [ "else" ( IfStmt | Block ) ] .
-func (p *parser) if_stmt() *Node {
- if trace && Debug['x'] != 0 {
- defer p.trace("if_stmt")()
- }
-
- p.want(LIF)
-
- markdcl()
-
- stmt := p.if_header()
- if stmt.Left == nil {
- Yyerror("missing condition in if statement")
- }
-
- stmt.Nbody.Set(p.loop_body("if clause"))
-
- if p.got(LELSE) {
- switch p.tok {
- case LIF:
- stmt.Rlist.Set1(p.if_stmt())
- case '{':
- cs := p.compound_stmt()
- if cs.Op == OBLOCK && cs.Ninit.Len() == 0 {
- stmt.Rlist.Set(cs.List.Slice())
- } else {
- stmt.Rlist.Set1(cs)
- }
- default:
- p.syntax_error("else must be followed by if or statement block")
- p.advance(LNAME, '}')
- }
- }
-
- popdcl()
- return stmt
-}
-
-// switch_stmt parses both expression and type switch statements.
-//
-// SwitchStmt = ExprSwitchStmt | TypeSwitchStmt .
-// ExprSwitchStmt = "switch" [ SimpleStmt ";" ] [ Expression ] "{" { ExprCaseClause } "}" .
-// TypeSwitchStmt = "switch" [ SimpleStmt ";" ] TypeSwitchGuard "{" { TypeCaseClause } "}" .
-func (p *parser) switch_stmt() *Node {
- if trace && Debug['x'] != 0 {
- defer p.trace("switch_stmt")()
- }
-
- p.want(LSWITCH)
- markdcl()
-
- hdr := p.if_header()
- hdr.Op = OSWITCH
-
- tswitch := hdr.Left
- if tswitch != nil && tswitch.Op != OTYPESW {
- tswitch = nil
- }
-
- hdr.List.Set(p.caseblock_list(tswitch))
- popdcl()
-
- return hdr
-}
-
-// SelectStmt = "select" "{" { CommClause } "}" .
-func (p *parser) select_stmt() *Node {
- if trace && Debug['x'] != 0 {
- defer p.trace("select_stmt")()
- }
-
- p.want(LSELECT)
- hdr := Nod(OSELECT, nil, nil)
- hdr.List.Set(p.caseblock_list(nil))
- return hdr
-}
-
-// Expression = UnaryExpr | Expression binary_op Expression .
-func (p *parser) bexpr(prec OpPrec) *Node {
- // don't trace bexpr - only leads to overly nested trace output
-
- // prec is precedence of the prior/enclosing binary operator (if any),
- // so we only want to parse tokens of greater precedence.
-
- x := p.uexpr()
- for p.prec > prec {
- op, prec1 := p.op, p.prec
- p.next()
- x = Nod(op, x, p.bexpr(prec1))
- }
- return x
-}
-
-func (p *parser) expr() *Node {
- if trace && Debug['x'] != 0 {
- defer p.trace("expr")()
- }
-
- return p.bexpr(0)
-}
-
-func unparen(x *Node) *Node {
- for x.Op == OPAREN {
- x = x.Left
- }
- return x
-}
-
-// UnaryExpr = PrimaryExpr | unary_op UnaryExpr .
-func (p *parser) uexpr() *Node {
- if trace && Debug['x'] != 0 {
- defer p.trace("uexpr")()
- }
-
- var op Op
- switch p.tok {
- case '*':
- op = OIND
-
- case '&':
- p.next()
- // uexpr may have returned a parenthesized composite literal
- // (see comment in operand) - remove parentheses if any
- x := unparen(p.uexpr())
- if x.Op == OCOMPLIT {
- // Special case for &T{...}: turn into (*T){...}.
- x.Right = Nod(OIND, x.Right, nil)
- x.Right.Implicit = true
- } else {
- x = Nod(OADDR, x, nil)
- }
- return x
-
- case '+':
- op = OPLUS
-
- case '-':
- op = OMINUS
-
- case '!':
- op = ONOT
-
- case '^':
- op = OCOM
-
- case LCOMM:
- // receive op (<-x) or receive-only channel (<-chan E)
- p.next()
-
- // If the next token is LCHAN we still don't know if it is
- // a channel (<-chan int) or a receive op (<-chan int(ch)).
- // We only know once we have found the end of the uexpr.
-
- x := p.uexpr()
-
- // There are two cases:
- //
- // <-chan... => <-x is a channel type
- // <-x => <-x is a receive operation
- //
- // In the first case, <- must be re-associated with
- // the channel type parsed already:
- //
- // <-(chan E) => (<-chan E)
- // <-(chan<-E) => (<-chan (<-E))
-
- if x.Op == OTCHAN {
- // x is a channel type => re-associate <-
- dir := Csend
- t := x
- for ; t.Op == OTCHAN && dir == Csend; t = t.Left {
- dir = ChanDir(t.Etype)
- if dir == Crecv {
- // t is type <-chan E but <-<-chan E is not permitted
- // (report same error as for "type _ <-<-chan E")
- p.syntax_error("unexpected <-, expecting chan")
- // already progressed, no need to advance
- }
- t.Etype = EType(Crecv)
- }
- if dir == Csend {
- // channel dir is <- but channel element E is not a channel
- // (report same error as for "type _ <-chan<-E")
- p.syntax_error(fmt.Sprintf("unexpected %v, expecting chan", t))
- // already progressed, no need to advance
- }
- return x
- }
-
- // x is not a channel type => we have a receive op
- return Nod(ORECV, x, nil)
-
- default:
- return p.pexpr(false)
- }
-
- // simple uexpr
- p.next()
- return Nod(op, p.uexpr(), nil)
-}
-
-// pseudocall parses call-like statements that can be preceded by 'defer' and 'go'.
-func (p *parser) pseudocall() *Node {
- if trace && Debug['x'] != 0 {
- defer p.trace("pseudocall")()
- }
-
- x := p.pexpr(p.tok == '(') // keep_parens so we can report error below
- switch x.Op {
- case OCALL:
- return x
- case OPAREN:
- Yyerror("expression in go/defer must not be parenthesized")
- // already progressed, no need to advance
- default:
- Yyerror("expression in go/defer must be function call")
- // already progressed, no need to advance
- }
- return nil
-}
-
-// Operand = Literal | OperandName | MethodExpr | "(" Expression ")" .
-// Literal = BasicLit | CompositeLit | FunctionLit .
-// BasicLit = int_lit | float_lit | imaginary_lit | rune_lit | string_lit .
-// OperandName = identifier | QualifiedIdent.
-func (p *parser) operand(keep_parens bool) *Node {
- if trace && Debug['x'] != 0 {
- defer p.trace("operand")()
- }
-
- switch p.tok {
- case LLITERAL:
- x := nodlit(p.val)
- p.next()
- return x
-
- case LNAME, '@', '?':
- return p.name()
-
- case '(':
- p.next()
- p.xnest++
- x := p.expr() // expr_or_type
- p.xnest--
- p.want(')')
-
- // Optimization: Record presence of ()'s only where needed
- // for error reporting. Don't bother in other cases; it is
- // just a waste of memory and time.
-
- // Parentheses are not permitted on lhs of := .
- switch x.Op {
- case ONAME, ONONAME, OPACK, OTYPE, OLITERAL, OTYPESW:
- keep_parens = true
- }
-
- // Parentheses are not permitted around T in a composite
- // literal T{}. If the next token is a {, assume x is a
- // composite literal type T (it may not be, { could be
- // the opening brace of a block, but we don't know yet).
- if p.tok == '{' {
- keep_parens = true
- }
-
- // Parentheses are also not permitted around the expression
- // in a go/defer statement. In that case, operand is called
- // with keep_parens set.
- if keep_parens {
- x = Nod(OPAREN, x, nil)
- }
- return x
-
- case LFUNC:
- t := p.ntype() // fntype
- if p.tok == '{' {
- // fnlitdcl
- closurehdr(t)
- // fnliteral
- p.next() // consume '{'
- p.fnest++
- p.xnest++
- body := p.stmt_list()
- p.xnest--
- p.fnest--
- p.want('}')
- return closurebody(body)
- }
- return t
-
- case '[', LCHAN, LMAP, LSTRUCT, LINTERFACE:
- return p.ntype() // othertype
-
- case '{':
- // common case: p.header is missing simple_stmt before { in if, for, switch
- p.syntax_error("missing operand")
- // '{' will be consumed in pexpr - no need to consume it here
- return nil
-
- default:
- p.syntax_error("expecting expression")
- p.advance()
- return nil
- }
-
- // Syntactically, composite literals are operands. Because a complit
- // type may be a qualified identifier which is handled by pexpr
- // (together with selector expressions), complits are parsed there
- // as well (operand is only called from pexpr).
-}
-
-// PrimaryExpr =
-// Operand |
-// Conversion |
-// PrimaryExpr Selector |
-// PrimaryExpr Index |
-// PrimaryExpr Slice |
-// PrimaryExpr TypeAssertion |
-// PrimaryExpr Arguments .
-//
-// Selector = "." identifier .
-// Index = "[" Expression "]" .
-// Slice = "[" ( [ Expression ] ":" [ Expression ] ) |
-// ( [ Expression ] ":" Expression ":" Expression )
-// "]" .
-// TypeAssertion = "." "(" Type ")" .
-// Arguments = "(" [ ( ExpressionList | Type [ "," ExpressionList ] ) [ "..." ] [ "," ] ] ")" .
-func (p *parser) pexpr(keep_parens bool) *Node {
- if trace && Debug['x'] != 0 {
- defer p.trace("pexpr")()
- }
-
- x := p.operand(keep_parens)
-
-loop:
- for {
- switch p.tok {
- case '.':
- p.next()
- switch p.tok {
- case LNAME, '@', '?':
- // pexpr '.' sym
- x = p.new_dotname(x)
-
- case '(':
- p.next()
- switch p.tok {
- default:
- // pexpr '.' '(' expr_or_type ')'
- t := p.expr() // expr_or_type
- p.want(')')
- x = Nod(ODOTTYPE, x, t)
-
- case LTYPE:
- // pexpr '.' '(' LTYPE ')'
- p.next()
- p.want(')')
- x = Nod(OTYPESW, nil, x)
- }
-
- default:
- p.syntax_error("expecting name or (")
- p.advance(';', '}')
- }
-
- case '[':
- p.next()
- p.xnest++
- var index [3]*Node
- if p.tok != ':' {
- index[0] = p.expr()
- }
- ncol := 0
- for ncol < len(index)-1 && p.got(':') {
- ncol++
- if p.tok != EOF && p.tok != ':' && p.tok != ']' {
- index[ncol] = p.expr()
- }
- }
- p.xnest--
- p.want(']')
-
- switch ncol {
- case 0:
- i := index[0]
- if i == nil {
- Yyerror("missing index in index expression")
- }
- x = Nod(OINDEX, x, i)
- case 1:
- x = Nod(OSLICE, x, nil)
- x.SetSliceBounds(index[0], index[1], nil)
- case 2:
- if index[1] == nil {
- Yyerror("middle index required in 3-index slice")
- }
- if index[2] == nil {
- Yyerror("final index required in 3-index slice")
- }
- x = Nod(OSLICE3, x, nil)
- x.SetSliceBounds(index[0], index[1], index[2])
-
- default:
- panic("unreachable")
- }
-
- case '(':
- // convtype '(' expr ocomma ')'
- args, ddd := p.arg_list()
-
- // call or conversion
- x = Nod(OCALL, x, nil)
- x.List.Set(args)
- x.Isddd = ddd
-
- case '{':
- // 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
- complit_ok := false
- switch t.Op {
- case ONAME, ONONAME, OTYPE, OPACK, OXDOT, ODOT:
- if p.xnest >= 0 {
- // x is considered a comptype
- complit_ok = true
- }
- case OTARRAY, OTSTRUCT, OTMAP:
- // x is a comptype
- complit_ok = true
- }
- if !complit_ok {
- break loop
- }
- if t != x {
- p.syntax_error("cannot parenthesize type in composite literal")
- // already progressed, no need to advance
- }
- n := p.complitexpr()
- n.Right = x
- x = n
-
- default:
- break loop
- }
- }
-
- return x
-}
-
-// KeyedElement = [ Key ":" ] Element .
-func (p *parser) keyval() *Node {
- if trace && Debug['x'] != 0 {
- defer p.trace("keyval")()
- }
-
- // A composite literal commonly spans several lines,
- // so the line number on errors may be misleading.
- // Wrap values (but not keys!) that don't carry line
- // numbers.
-
- x := p.bare_complitexpr()
-
- if p.got(':') {
- // key ':' value
- return Nod(OKEY, x, wrapname(p.bare_complitexpr()))
- }
-
- // value
- return wrapname(x)
-}
-
-func wrapname(x *Node) *Node {
- // These nodes do not carry line numbers.
- // Introduce a wrapper node to give the correct line.
- switch x.Op {
- case ONAME, ONONAME, OTYPE, OPACK, OLITERAL:
- x = Nod(OPAREN, x, nil)
- x.Implicit = true
- }
- return x
-}
-
-// Element = Expression | LiteralValue .
-func (p *parser) bare_complitexpr() *Node {
- if trace && Debug['x'] != 0 {
- defer p.trace("bare_complitexpr")()
- }
-
- if p.tok == '{' {
- // '{' start_complit braced_keyval_list '}'
- return p.complitexpr()
- }
-
- return p.expr()
-}
-
-// LiteralValue = "{" [ ElementList [ "," ] ] "}" .
-func (p *parser) complitexpr() *Node {
- if trace && Debug['x'] != 0 {
- defer p.trace("complitexpr")()
- }
-
- // make node early so we get the right line number
- n := Nod(OCOMPLIT, nil, nil)
-
- p.want('{')
- p.xnest++
-
- var l []*Node
- for p.tok != EOF && p.tok != '}' {
- l = append(l, p.keyval())
- if !p.ocomma('}') {
- break
- }
- }
-
- p.xnest--
- p.want('}')
-
- n.List.Set(l)
- return n
-}
-
-// names and types
-// newname is used before declared
-// oldname is used after declared
-func (p *parser) new_name(sym *Sym) *Node {
- if trace && Debug['x'] != 0 {
- defer p.trace("new_name")()
- }
-
- if sym != nil {
- return newname(sym)
- }
- return nil
-}
-
-func (p *parser) dcl_name() *Node {
- if trace && Debug['x'] != 0 {
- defer p.trace("dcl_name")()
- }
-
- symlineno := lineno
- sym := p.sym()
- if sym == nil {
- yyerrorl(symlineno, "invalid declaration")
- return nil
- }
- return dclname(sym)
-}
-
-func (p *parser) onew_name() *Node {
- if trace && Debug['x'] != 0 {
- defer p.trace("onew_name")()
- }
-
- switch p.tok {
- case LNAME, '@', '?':
- return p.new_name(p.sym())
- }
- return nil
-}
-
-func (p *parser) sym() *Sym {
- switch p.tok {
- case LNAME:
- s := p.sym_ // from localpkg
- p.next()
- // during imports, unqualified non-exported identifiers are from builtinpkg
- if importpkg != nil && !exportname(s.Name) {
- s = Pkglookup(s.Name, builtinpkg)
- }
- return s
-
- case '@':
- return p.hidden_importsym()
-
- case '?':
- p.next()
- return nil
-
- default:
- p.syntax_error("expecting name")
- p.advance()
- return new(Sym)
- }
-}
-
-func mkname(sym *Sym) *Node {
- n := oldname(sym)
- if n.Name != nil && n.Name.Pack != nil {
- n.Name.Pack.Used = true
- }
- return n
-}
-
-func (p *parser) name() *Node {
- if trace && Debug['x'] != 0 {
- defer p.trace("name")()
- }
-
- return mkname(p.sym())
-}
-
-// [ "..." ] Type
-func (p *parser) dotdotdot() *Node {
- if trace && Debug['x'] != 0 {
- defer p.trace("dotdotdot")()
- }
-
- p.want(LDDD)
- if typ := p.try_ntype(); typ != nil {
- return Nod(ODDD, typ, nil)
- }
-
- Yyerror("final argument in variadic function missing type")
- return Nod(ODDD, typenod(typ(TINTER)), nil)
-}
-
-func (p *parser) ntype() *Node {
- if trace && Debug['x'] != 0 {
- defer p.trace("ntype")()
- }
-
- if typ := p.try_ntype(); typ != nil {
- return typ
- }
-
- p.syntax_error("")
- p.advance()
- return nil
-}
-
-// signature parses a function signature and returns an OTFUNC node.
-//
-// Signature = Parameters [ Result ] .
-func (p *parser) signature(recv *Node) *Node {
- if trace && Debug['x'] != 0 {
- defer p.trace("signature")()
- }
-
- params := p.param_list(true)
-
- var result []*Node
- if p.tok == '(' {
- result = p.param_list(false)
- } else if t := p.try_ntype(); t != nil {
- result = []*Node{Nod(ODCLFIELD, nil, t)}
- }
-
- typ := Nod(OTFUNC, recv, nil)
- typ.List.Set(params)
- typ.Rlist.Set(result)
-
- return typ
-}
-
-// try_ntype is like ntype but it returns nil if there was no type
-// instead of reporting an error.
-//
-// Type = TypeName | TypeLit | "(" Type ")" .
-// TypeName = identifier | QualifiedIdent .
-// TypeLit = ArrayType | StructType | PointerType | FunctionType | InterfaceType |
-// SliceType | MapType | ChannelType .
-func (p *parser) try_ntype() *Node {
- if trace && Debug['x'] != 0 {
- defer p.trace("try_ntype")()
- }
-
- switch p.tok {
- case LCOMM:
- // recvchantype
- p.next()
- p.want(LCHAN)
- t := Nod(OTCHAN, p.chan_elem(), nil)
- t.Etype = EType(Crecv)
- return t
-
- case LFUNC:
- // fntype
- p.next()
- return p.signature(nil)
-
- case '[':
- // '[' oexpr ']' ntype
- // '[' LDDD ']' ntype
- p.next()
- p.xnest++
- var len *Node
- if p.tok != ']' {
- if p.got(LDDD) {
- len = Nod(ODDD, nil, nil)
- } else {
- len = p.expr()
- }
- }
- p.xnest--
- p.want(']')
- return Nod(OTARRAY, len, p.ntype())
-
- case LCHAN:
- // LCHAN non_recvchantype
- // LCHAN LCOMM ntype
- p.next()
- var dir = EType(Cboth)
- if p.got(LCOMM) {
- dir = EType(Csend)
- }
- t := Nod(OTCHAN, p.chan_elem(), nil)
- t.Etype = dir
- return t
-
- case LMAP:
- // LMAP '[' ntype ']' ntype
- p.next()
- p.want('[')
- key := p.ntype()
- p.want(']')
- val := p.ntype()
- return Nod(OTMAP, key, val)
-
- case LSTRUCT:
- return p.structtype()
-
- case LINTERFACE:
- return p.interfacetype()
-
- case '*':
- // ptrtype
- p.next()
- return Nod(OIND, p.ntype(), nil)
-
- case LNAME, '@', '?':
- return p.dotname()
-
- case '(':
- p.next()
- t := p.ntype()
- p.want(')')
- return t
-
- default:
- return nil
- }
-}
-
-func (p *parser) chan_elem() *Node {
- if trace && Debug['x'] != 0 {
- defer p.trace("chan_elem")()
- }
-
- if typ := p.try_ntype(); typ != nil {
- return typ
- }
-
- p.syntax_error("missing channel element type")
- // assume element type is simply absent - don't advance
- return nil
-}
-
-func (p *parser) new_dotname(obj *Node) *Node {
- if trace && Debug['x'] != 0 {
- defer p.trace("new_dotname")()
- }
-
- sel := p.sym()
- if obj.Op == OPACK {
- s := restrictlookup(sel.Name, obj.Name.Pkg)
- obj.Used = true
- return oldname(s)
- }
- return NodSym(OXDOT, obj, sel)
-}
-
-func (p *parser) dotname() *Node {
- if trace && Debug['x'] != 0 {
- defer p.trace("dotname")()
- }
-
- name := p.name()
- if p.got('.') {
- return p.new_dotname(name)
- }
- return name
-}
-
-// StructType = "struct" "{" { FieldDecl ";" } "}" .
-func (p *parser) structtype() *Node {
- if trace && Debug['x'] != 0 {
- defer p.trace("structtype")()
- }
-
- p.want(LSTRUCT)
- p.want('{')
- var l []*Node
- for p.tok != EOF && p.tok != '}' {
- l = append(l, p.structdcl()...)
- if !p.osemi('}') {
- break
- }
- }
- p.want('}')
-
- t := Nod(OTSTRUCT, nil, nil)
- t.List.Set(l)
- return t
-}
-
-// InterfaceType = "interface" "{" { MethodSpec ";" } "}" .
-func (p *parser) interfacetype() *Node {
- if trace && Debug['x'] != 0 {
- defer p.trace("interfacetype")()
- }
-
- p.want(LINTERFACE)
- p.want('{')
- var l []*Node
- for p.tok != EOF && p.tok != '}' {
- l = append(l, p.interfacedcl())
- if !p.osemi('}') {
- break
- }
- }
- p.want('}')
-
- t := Nod(OTINTER, nil, nil)
- t.List.Set(l)
- return t
-}
-
-// Function stuff.
-// All in one place to show how crappy it all is.
-
-func (p *parser) xfndcl() *Node {
- if trace && Debug['x'] != 0 {
- defer p.trace("xfndcl")()
- }
-
- p.want(LFUNC)
- f := p.fndcl()
- body := p.fnbody()
-
- if f == nil {
- return nil
- }
-
- f.Nbody.Set(body)
- f.Noescape = p.pragma&Noescape != 0
- if f.Noescape && len(body) != 0 {
- Yyerror("can only use //go:noescape with external func implementations")
- }
- f.Func.Pragma = p.pragma
- f.Func.Endlineno = lineno
-
- funcbody(f)
-
- return f
-}
-
-// FunctionDecl = "func" FunctionName ( Function | Signature ) .
-// FunctionName = identifier .
-// Function = Signature FunctionBody .
-// MethodDecl = "func" Receiver MethodName ( Function | Signature ) .
-// Receiver = Parameters .
-func (p *parser) fndcl() *Node {
- if trace && Debug['x'] != 0 {
- defer p.trace("fndcl")()
- }
-
- switch p.tok {
- case LNAME, '@', '?':
- // FunctionName Signature
- name := p.sym()
- t := p.signature(nil)
-
- 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")
- }
- }
-
- 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")
- }
- }
-
- f := Nod(ODCLFUNC, nil, nil)
- 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
- declare(f.Func.Nname, PFUNC)
-
- funchdr(f)
- return f
-
- case '(':
- // Receiver MethodName Signature
- rparam := p.param_list(false)
- var recv *Node
- if len(rparam) > 0 {
- recv = rparam[0]
- }
- name := p.sym()
- t := p.signature(recv)
-
- // check after parsing header for fault-tolerance
- if recv == nil {
- Yyerror("method has no receiver")
- return nil
- }
-
- if len(rparam) > 1 {
- Yyerror("method has multiple receivers")
- return nil
- }
-
- if recv.Op != ODCLFIELD {
- Yyerror("bad receiver in method")
- return nil
- }
-
- f := Nod(ODCLFUNC, nil, nil)
- f.Func.Shortname = newfuncname(name)
- f.Func.Nname = methodname1(f.Func.Shortname, recv.Right)
- f.Func.Nname.Name.Defn = f
- f.Func.Nname.Name.Param.Ntype = t
- declare(f.Func.Nname, PFUNC)
-
- funchdr(f)
- return f
-
- default:
- p.syntax_error("expecting name or (")
- p.advance('{', ';')
- return nil
- }
-}
-
-func (p *parser) hidden_fndcl() *Node {
- if trace && Debug['x'] != 0 {
- defer p.trace("hidden_fndcl")()
- }
-
- switch p.tok {
- default:
- // hidden_pkg_importsym '(' ohidden_funarg_list ')' ohidden_funres
- s1 := p.hidden_pkg_importsym()
- p.want('(')
- s3 := p.ohidden_funarg_list()
- p.want(')')
- s5 := p.ohidden_funres()
-
- s := s1
- t := functype(nil, s3, s5)
-
- importsym(s, ONAME)
- if s.Def != nil && s.Def.Op == ONAME {
- if Eqtype(t, s.Def.Type) {
- dclcontext = PDISCARD // since we skip funchdr below
- return nil
- }
- Yyerror("inconsistent definition for func %v during import\n\t%v\n\t%v", s, s.Def.Type, t)
- }
-
- ss := newfuncname(s)
- ss.Type = t
- declare(ss, PFUNC)
-
- funchdr(ss)
- return ss
-
- case '(':
- // '(' hidden_funarg_list ')' sym '(' ohidden_funarg_list ')' ohidden_funres
- p.next()
- s2 := p.hidden_funarg_list()
- p.want(')')
- s4 := p.sym()
- p.want('(')
- s6 := p.ohidden_funarg_list()
- p.want(')')
- s8 := p.ohidden_funres()
-
- ss := methodname1(newname(s4), s2[0].Right)
- ss.Type = functype(s2[0], s6, s8)
-
- checkwidth(ss.Type)
- addmethod(s4, ss.Type, p.structpkg, false, p.pragma&Nointerface != 0)
- p.pragma = 0
- funchdr(ss)
-
- // inl.C's inlnode in on a dotmeth node expects to find the inlineable body as
- // (dotmeth's type).Nname.Inl, and dotmeth's type has been pulled
- // out by typecheck's lookdot as this $$.ttype. So by providing
- // this back link here we avoid special casing there.
- ss.Type.SetNname(ss)
- return ss
- }
-}
-
-// FunctionBody = Block .
-func (p *parser) fnbody() []*Node {
- if trace && Debug['x'] != 0 {
- defer p.trace("fnbody")()
- }
-
- if p.got('{') {
- p.fnest++
- body := p.stmt_list()
- p.fnest--
- p.want('}')
- if body == nil {
- body = []*Node{Nod(OEMPTY, nil, nil)}
- }
- return body
- }
-
- return nil
-}
-
-// Declaration = ConstDecl | TypeDecl | VarDecl .
-// TopLevelDecl = Declaration | FunctionDecl | MethodDecl .
-func (p *parser) xdcl_list() (l []*Node) {
- if trace && Debug['x'] != 0 {
- defer p.trace("xdcl_list")()
- }
-
- for p.tok != EOF {
- switch p.tok {
- case LVAR, LCONST, LTYPE:
- l = append(l, p.common_dcl()...)
-
- case LFUNC:
- l = append(l, p.xfndcl())
-
- default:
- if p.tok == '{' && len(l) != 0 && l[len(l)-1].Op == ODCLFUNC && l[len(l)-1].Nbody.Len() == 0 {
- // opening { of function declaration on next line
- p.syntax_error("unexpected semicolon or newline before {")
- } else {
- p.syntax_error("non-declaration statement outside function body")
- }
- p.advance(LVAR, LCONST, LTYPE, LFUNC)
- continue
- }
-
- // Reset p.pragma BEFORE advancing to the next token (consuming ';')
- // since comments before may set pragmas for the next function decl.
- p.pragma = 0
-
- if p.tok != EOF && !p.got(';') {
- p.syntax_error("after top level declaration")
- p.advance(LVAR, LCONST, LTYPE, LFUNC)
- }
- }
-
- if nsyntaxerrors == 0 {
- testdclstack()
- }
- return
-}
-
-// FieldDecl = (IdentifierList Type | AnonymousField) [ Tag ] .
-// AnonymousField = [ "*" ] TypeName .
-// Tag = string_lit .
-func (p *parser) structdcl() []*Node {
- if trace && Debug['x'] != 0 {
- defer p.trace("structdcl")()
- }
-
- var sym *Sym
- switch p.tok {
- case LNAME:
- sym = p.sym_
- p.next()
- if sym == nil {
- panic("unreachable") // we must have a sym for LNAME
- }
- if p.tok == '.' || p.tok == LLITERAL || p.tok == ';' || p.tok == '}' {
- // embed oliteral
- field := p.embed(sym)
- tag := p.oliteral()
-
- field.SetVal(tag)
- return []*Node{field}
- }
-
- // LNAME belongs to first *Sym of new_name_list
- //
- // during imports, unqualified non-exported identifiers are from builtinpkg
- if importpkg != nil && !exportname(sym.Name) {
- sym = Pkglookup(sym.Name, builtinpkg)
- if sym == nil {
- p.import_error()
- }
- }
- fallthrough
-
- case '@', '?':
- // new_name_list ntype oliteral
- fields := p.new_name_list(sym)
- typ := p.ntype()
- tag := p.oliteral()
-
- if len(fields) == 0 || fields[0].Sym.Name == "?" {
- // ? symbol, during import
- n := typ
- if n.Op == OIND {
- n = n.Left
- }
- n = embedded(n.Sym, importpkg)
- n.Right = typ
- n.SetVal(tag)
- return []*Node{n}
- }
-
- for i, n := range fields {
- fields[i] = Nod(ODCLFIELD, n, typ)
- fields[i].SetVal(tag)
- }
- return fields
-
- case '(':
- p.next()
- if p.got('*') {
- // '(' '*' embed ')' oliteral
- field := p.embed(nil)
- p.want(')')
- tag := p.oliteral()
-
- field.Right = Nod(OIND, field.Right, nil)
- field.SetVal(tag)
- Yyerror("cannot parenthesize embedded type")
- return []*Node{field}
-
- } else {
- // '(' embed ')' oliteral
- field := p.embed(nil)
- p.want(')')
- tag := p.oliteral()
-
- field.SetVal(tag)
- Yyerror("cannot parenthesize embedded type")
- return []*Node{field}
- }
-
- case '*':
- p.next()
- if p.got('(') {
- // '*' '(' embed ')' oliteral
- field := p.embed(nil)
- p.want(')')
- tag := p.oliteral()
-
- field.Right = Nod(OIND, field.Right, nil)
- field.SetVal(tag)
- Yyerror("cannot parenthesize embedded type")
- return []*Node{field}
-
- } else {
- // '*' embed oliteral
- field := p.embed(nil)
- tag := p.oliteral()
-
- field.Right = Nod(OIND, field.Right, nil)
- field.SetVal(tag)
- return []*Node{field}
- }
-
- default:
- p.syntax_error("expecting field name or embedded type")
- p.advance(';', '}')
- return nil
- }
-}
-
-func (p *parser) oliteral() (v Val) {
- if p.tok == LLITERAL {
- v = p.val
- p.next()
- }
- return
-}
-
-func (p *parser) packname(name *Sym) *Sym {
- if trace && Debug['x'] != 0 {
- defer p.trace("embed")()
- }
-
- if name != nil {
- // LNAME was already consumed and is coming in as name
- } else if p.tok == LNAME {
- name = p.sym_
- p.next()
- } else {
- p.syntax_error("expecting name")
- p.advance('.', ';', '}')
- name = new(Sym)
- }
-
- if p.got('.') {
- // LNAME '.' sym
- s := p.sym()
-
- var pkg *Pkg
- if name.Def == nil || name.Def.Op != OPACK {
- Yyerror("%v is not a package", name)
- pkg = localpkg
- } else {
- name.Def.Used = true
- pkg = name.Def.Name.Pkg
- }
- return restrictlookup(s.Name, pkg)
- }
-
- // LNAME
- if n := oldname(name); n.Name != nil && n.Name.Pack != nil {
- n.Name.Pack.Used = true
- }
- return name
-}
-
-func (p *parser) embed(sym *Sym) *Node {
- if trace && Debug['x'] != 0 {
- defer p.trace("embed")()
- }
-
- pkgname := p.packname(sym)
- return embedded(pkgname, localpkg)
-}
-
-// MethodSpec = MethodName Signature | InterfaceTypeName .
-// MethodName = identifier .
-// InterfaceTypeName = TypeName .
-func (p *parser) interfacedcl() *Node {
- if trace && Debug['x'] != 0 {
- defer p.trace("interfacedcl")()
- }
-
- switch p.tok {
- case LNAME:
- sym := p.sym_
- p.next()
-
- // accept potential name list but complain
- hasNameList := false
- for p.got(',') {
- p.sym()
- hasNameList = true
- }
- if hasNameList {
- p.syntax_error("name list not allowed in interface type")
- // already progressed, no need to advance
- }
-
- if p.tok != '(' {
- // packname
- pname := p.packname(sym)
- return Nod(ODCLFIELD, nil, oldname(pname))
- }
-
- // MethodName Signature
- mname := newname(sym)
- sig := p.signature(fakethis())
-
- meth := Nod(ODCLFIELD, mname, sig)
- ifacedcl(meth)
- return meth
-
- case '@', '?':
- // MethodName Signature
- //
- // We arrive here when parsing an interface type declared inside
- // an exported and inlineable function and the interface declares
- // unexported methods (which are then package-qualified).
- //
- // Since the compiler always flattens embedded interfaces, we
- // will never see an embedded package-qualified interface in export
- // data; i.e., when we reach here we know it must be a method.
- //
- // See also issue 14164.
- mname := newname(p.sym())
- sig := p.signature(fakethis())
-
- meth := Nod(ODCLFIELD, mname, sig)
- ifacedcl(meth)
- return meth
-
- case '(':
- p.next()
- pname := p.packname(nil)
- p.want(')')
- n := Nod(ODCLFIELD, nil, oldname(pname))
- Yyerror("cannot parenthesize embedded type")
- return n
-
- default:
- p.syntax_error("")
- p.advance(';', '}')
- return nil
- }
-}
-
-// param parses and returns a function parameter list entry which may be
-// a parameter name and type pair (name, typ), a single type (nil, typ),
-// or a single name (name, nil). In the last case, the name may still be
-// a type name. The result is (nil, nil) in case of a syntax error.
-//
-// [ParameterName] Type
-func (p *parser) param() (name *Sym, typ *Node) {
- if trace && Debug['x'] != 0 {
- defer p.trace("param")()
- }
-
- switch p.tok {
- case LNAME, '@', '?':
- name = p.sym() // nil if p.tok == '?' (importing only)
- switch p.tok {
- case LCOMM, LFUNC, '[', LCHAN, LMAP, LSTRUCT, LINTERFACE, '*', LNAME, '@', '?', '(':
- // sym name_or_type
- typ = p.ntype()
-
- case LDDD:
- // sym dotdotdot
- typ = p.dotdotdot()
-
- default:
- // name_or_type
- if p.got('.') {
- // a qualified name cannot be a parameter name
- typ = p.new_dotname(mkname(name))
- name = nil
- }
- }
-
- case LDDD:
- // dotdotdot
- typ = p.dotdotdot()
-
- case LCOMM, LFUNC, '[', LCHAN, LMAP, LSTRUCT, LINTERFACE, '*', '(':
- // name_or_type
- typ = p.ntype()
-
- default:
- p.syntax_error("expecting )")
- p.advance(',', ')')
- }
-
- return
-}
-
-// Parameters = "(" [ ParameterList [ "," ] ] ")" .
-// ParameterList = ParameterDecl { "," ParameterDecl } .
-// ParameterDecl = [ IdentifierList ] [ "..." ] Type .
-func (p *parser) param_list(dddOk bool) []*Node {
- if trace && Debug['x'] != 0 {
- defer p.trace("param_list")()
- }
-
- type param struct {
- name *Sym
- typ *Node
- }
- var params []param
- var named int // number of parameters that have a name and type
-
- p.want('(')
- for p.tok != EOF && p.tok != ')' {
- name, typ := p.param()
- params = append(params, param{name, typ})
- if name != nil && typ != nil {
- named++
- }
- if !p.ocomma(')') {
- break
- }
- }
- p.want(')')
- // 0 <= named <= len(params)
-
- // There are 3 cases:
- //
- // 1) named == 0:
- // No parameter list entry has both a name and a type; i.e. there are only
- // unnamed parameters. Any name must be a type name; they are "converted"
- // to types when creating the final parameter list.
- // In case of a syntax error, there is neither a name nor a type.
- // Nil checks take care of this.
- //
- // 2) named == len(names):
- // All parameter list entries have both a name and a type.
- //
- // 3) Otherwise:
- if named != 0 && named != len(params) {
- // Some parameter list entries have both a name and a type:
- // Distribute types backwards and check that there are no
- // mixed named and unnamed parameters.
- var T *Node // type T in a parameter sequence: a, b, c T
- for i := len(params) - 1; i >= 0; i-- {
- p := ¶ms[i]
- if t := p.typ; t != nil {
- // explicit type: use type for earlier parameters
- T = t
- // an explicitly typed entry must have a name
- // TODO(gri) remove extra importpkg == nil check below
- // after switch to binary eport format
- // Exported inlined function bodies containing function
- // literals may print parameter names as '?' resulting
- // in nil *Sym and thus nil names. Don't report an error
- // in this case.
- if p.name == nil && importpkg == nil {
- T = nil // error
- }
- } else {
- // no explicit type: use type of next parameter
- p.typ = T
- }
- if T == nil {
- Yyerror("mixed named and unnamed function parameters")
- break
- }
- }
- // Unless there was an error, now all parameter entries have a type.
- }
-
- // create final parameter list
- list := make([]*Node, len(params))
- for i, p := range params {
- // create dcl node
- var name, typ *Node
- if p.typ != nil {
- typ = p.typ
- if p.name != nil {
- // name must be a parameter name
- name = newname(p.name)
- }
- } else if p.name != nil {
- // p.name must be a type name (or nil in case of syntax error)
- typ = mkname(p.name)
- }
- n := Nod(ODCLFIELD, name, typ)
-
- // rewrite ...T parameter
- if typ != nil && typ.Op == ODDD {
- if !dddOk {
- Yyerror("cannot use ... in receiver or result parameter list")
- } else if i+1 < len(params) {
- Yyerror("can only use ... with final parameter in list")
- }
- typ.Op = OTARRAY
- typ.Right = typ.Left
- typ.Left = nil
- n.Isddd = true
- if n.Left != nil {
- n.Left.Isddd = true
- }
- }
-
- list[i] = n
- }
-
- return list
-}
-
-var missing_stmt = Nod(OXXX, nil, nil)
-
-// 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() *Node {
- if trace && Debug['x'] != 0 {
- defer p.trace("stmt")()
- }
-
- switch p.tok {
- case '{':
- return p.compound_stmt()
-
- case LVAR, LCONST, LTYPE:
- return liststmt(p.common_dcl())
-
- case LNAME, '@', '?', LLITERAL, LFUNC, '(', // operands
- '[', LSTRUCT, LMAP, LCHAN, LINTERFACE, // composite types
- '+', '-', '*', '&', '^', LCOMM, '!': // unary operators
- return p.simple_stmt(true, false)
-
- case LFOR:
- return p.for_stmt()
-
- case LSWITCH:
- return p.switch_stmt()
-
- case LSELECT:
- return p.select_stmt()
-
- case LIF:
- return p.if_stmt()
-
- case LFALL:
- p.next()
- // will be converted to OFALL
- stmt := Nod(OXFALL, nil, nil)
- stmt.Xoffset = int64(block)
- return stmt
-
- case LBREAK:
- p.next()
- return Nod(OBREAK, p.onew_name(), nil)
-
- case LCONTINUE:
- p.next()
- return Nod(OCONTINUE, p.onew_name(), nil)
-
- case LGO:
- p.next()
- return Nod(OPROC, p.pseudocall(), nil)
-
- case LDEFER:
- p.next()
- return Nod(ODEFER, p.pseudocall(), nil)
-
- case LGOTO:
- p.next()
- stmt := Nod(OGOTO, p.new_name(p.sym()), nil)
- stmt.Sym = dclstack // context, for goto restrictions
- return stmt
-
- case LRETURN:
- p.next()
- var results []*Node
- if p.tok != ';' && p.tok != '}' {
- results = p.expr_list()
- }
-
- stmt := Nod(ORETURN, nil, nil)
- stmt.List.Set(results)
- if stmt.List.Len() == 0 && Curfn != nil {
- for _, ln := range Curfn.Func.Dcl {
- if ln.Class == PPARAM {
- continue
- }
- if ln.Class != PPARAMOUT {
- break
- }
- if ln.Sym.Def != ln {
- Yyerror("%s is shadowed during return", ln.Sym.Name)
- }
- }
- }
-
- return stmt
-
- case ';':
- return nil
-
- default:
- return missing_stmt
- }
-}
-
-// StatementList = { Statement ";" } .
-func (p *parser) stmt_list() (l []*Node) {
- if trace && Debug['x'] != 0 {
- defer p.trace("stmt_list")()
- }
-
- for p.tok != EOF && p.tok != '}' && p.tok != LCASE && p.tok != LDEFAULT {
- s := p.stmt()
- if s == missing_stmt {
- break
- }
- if s == nil {
- } else if s.Op == OBLOCK && s.Ninit.Len() == 0 {
- l = append(l, s.List.Slice()...)
- } else {
- l = append(l, s)
- }
- // customized version of osemi:
- // ';' is optional before a closing ')' or '}'
- if p.tok == ')' || p.tok == '}' {
- continue
- }
- if !p.got(';') {
- p.syntax_error("at end of statement")
- p.advance(';', '}')
- }
- }
- return
-}
-
-// IdentifierList = identifier { "," identifier } .
-//
-// If first != nil we have the first symbol already.
-func (p *parser) new_name_list(first *Sym) []*Node {
- if trace && Debug['x'] != 0 {
- defer p.trace("new_name_list")()
- }
-
- if first == nil {
- first = p.sym() // may still be nil
- }
- var l []*Node
- n := p.new_name(first)
- if n != nil {
- l = append(l, n)
- }
- for p.got(',') {
- n = p.new_name(p.sym())
- if n != nil {
- l = append(l, n)
- }
- }
- return l
-}
-
-// IdentifierList = identifier { "," identifier } .
-func (p *parser) dcl_name_list() []*Node {
- if trace && Debug['x'] != 0 {
- defer p.trace("dcl_name_list")()
- }
-
- s := []*Node{p.dcl_name()}
- for p.got(',') {
- s = append(s, p.dcl_name())
- }
- return s
-}
-
-// ExpressionList = Expression { "," Expression } .
-func (p *parser) expr_list() []*Node {
- if trace && Debug['x'] != 0 {
- defer p.trace("expr_list")()
- }
-
- l := []*Node{p.expr()}
- for p.got(',') {
- l = append(l, p.expr())
- }
- return l
-}
-
-// Arguments = "(" [ ( ExpressionList | Type [ "," ExpressionList ] ) [ "..." ] [ "," ] ] ")" .
-func (p *parser) arg_list() (l []*Node, ddd bool) {
- if trace && Debug['x'] != 0 {
- defer p.trace("arg_list")()
- }
-
- p.want('(')
- p.xnest++
-
- for p.tok != EOF && p.tok != ')' && !ddd {
- l = append(l, p.expr()) // expr_or_type
- ddd = p.got(LDDD)
- if !p.ocomma(')') {
- break
- }
- }
-
- p.xnest--
- p.want(')')
-
- return
-}
-
-// osemi parses an optional semicolon.
-func (p *parser) osemi(follow int32) bool {
- switch p.tok {
- case ';':
- p.next()
- return true
-
- case ')', '}':
- // semicolon is optional before ) or }
- return true
- }
-
- p.syntax_error("expecting semicolon, newline, or " + tokstring(follow))
- p.advance(follow)
- return false
-}
-
-// ocomma parses an optional comma.
-func (p *parser) ocomma(follow int32) bool {
- switch p.tok {
- case ',':
- p.next()
- return true
-
- case ')', '}':
- // comma is optional before ) or }
- return true
- }
-
- p.syntax_error("expecting comma or " + tokstring(follow))
- p.advance(follow)
- return false
-}
-
-// ----------------------------------------------------------------------------
-// Importing packages
-
-func (p *parser) import_error() {
- p.syntax_error("in export data of imported package")
- p.next()
-}
-
-// The methods below reflect a 1:1 translation of the original (and now defunct)
-// go.y yacc productions. They could be simplified significantly and also use better
-// variable names. However, we will be able to delete them once we enable the
-// new export format by default, so it's not worth the effort (issue 13241).
-
-func (p *parser) hidden_importsym() *Sym {
- if trace && Debug['x'] != 0 {
- defer p.trace("hidden_importsym")()
- }
-
- p.want('@')
- var s2 Val
- if p.tok == LLITERAL {
- s2 = p.val
- p.next()
- } else {
- p.import_error()
- }
- p.want('.')
-
- switch p.tok {
- case LNAME:
- s4 := p.sym_
- p.next()
-
- var p *Pkg
-
- if s2.U.(string) == "" {
- p = importpkg
- } else {
- if isbadimport(s2.U.(string)) {
- errorexit()
- }
- p = mkpkg(s2.U.(string))
- }
- return Pkglookup(s4.Name, p)
-
- case '?':
- p.next()
-
- var p *Pkg
-
- if s2.U.(string) == "" {
- p = importpkg
- } else {
- if isbadimport(s2.U.(string)) {
- errorexit()
- }
- p = mkpkg(s2.U.(string))
- }
- return Pkglookup("?", p)
-
- default:
- p.import_error()
- return nil
- }
-}
-
-func (p *parser) ohidden_funarg_list() []*Node {
- if trace && Debug['x'] != 0 {
- defer p.trace("ohidden_funarg_list")()
- }
-
- var ss []*Node
- if p.tok != ')' {
- ss = p.hidden_funarg_list()
- }
- return ss
-}
-
-func (p *parser) ohidden_structdcl_list() []*Node {
- if trace && Debug['x'] != 0 {
- defer p.trace("ohidden_structdcl_list")()
- }
-
- var ss []*Node
- if p.tok != '}' {
- ss = p.hidden_structdcl_list()
- }
- return ss
-}
-
-func (p *parser) ohidden_interfacedcl_list() []*Node {
- if trace && Debug['x'] != 0 {
- defer p.trace("ohidden_interfacedcl_list")()
- }
-
- var ss []*Node
- if p.tok != '}' {
- ss = p.hidden_interfacedcl_list()
- }
- return ss
-}
-
-// import syntax from package header
-func (p *parser) hidden_import() {
- if trace && Debug['x'] != 0 {
- defer p.trace("hidden_import")()
- }
-
- switch p.tok {
- case LIMPORT:
- // LIMPORT LNAME LLITERAL ';'
- p.next()
- var s2 *Sym
- if p.tok == LNAME {
- s2 = p.sym_
- p.next()
- } else {
- p.import_error()
- }
- var s3 Val
- if p.tok == LLITERAL {
- s3 = p.val
- p.next()
- } else {
- p.import_error()
- }
- p.want(';')
-
- importimport(s2, s3.U.(string))
-
- case LVAR:
- // LVAR hidden_pkg_importsym hidden_type ';'
- p.next()
- s2 := p.hidden_pkg_importsym()
- s3 := p.hidden_type()
- p.want(';')
-
- importvar(s2, s3)
-
- case LCONST:
- // LCONST hidden_pkg_importsym '=' hidden_constant ';'
- // LCONST hidden_pkg_importsym hidden_type '=' hidden_constant ';'
- p.next()
- s2 := p.hidden_pkg_importsym()
- var s3 *Type = Types[TIDEAL]
- if p.tok != '=' {
- s3 = p.hidden_type()
- }
- p.want('=')
- s4 := p.hidden_constant()
- p.want(';')
-
- importconst(s2, s3, s4)
-
- case LTYPE:
- // LTYPE hidden_pkgtype hidden_type ';'
- p.next()
- s2 := p.hidden_pkgtype()
- s3 := p.hidden_type()
- p.want(';')
-
- importtype(s2, s3)
-
- case LFUNC:
- // LFUNC hidden_fndcl fnbody ';'
- p.next()
- s2 := p.hidden_fndcl()
- s3 := p.fnbody()
- p.want(';')
-
- if s2 == nil {
- dclcontext = PEXTERN // since we skip the funcbody below
- return
- }
-
- s2.Func.Inl.Set(s3)
-
- funcbody(s2)
- importlist = append(importlist, s2)
-
- if Debug['E'] > 0 {
- fmt.Printf("import [%q] func %v \n", importpkg.Path, s2)
- if Debug['m'] > 2 && s2.Func.Inl.Len() != 0 {
- fmt.Printf("inl body:%v\n", s2.Func.Inl)
- }
- }
-
- default:
- p.import_error()
- }
-}
-
-func (p *parser) hidden_pkg_importsym() *Sym {
- if trace && Debug['x'] != 0 {
- defer p.trace("hidden_pkg_importsym")()
- }
-
- s := p.hidden_importsym()
- p.structpkg = s.Pkg
- return s
-}
-
-func (p *parser) hidden_pkgtype() *Type {
- if trace && Debug['x'] != 0 {
- defer p.trace("hidden_pkgtype")()
- }
-
- return pkgtype(p.hidden_pkg_importsym())
-}
-
-// ----------------------------------------------------------------------------
-// Importing types
-
-func (p *parser) hidden_type() *Type {
- if trace && Debug['x'] != 0 {
- defer p.trace("hidden_type")()
- }
-
- switch p.tok {
- default:
- return p.hidden_type_misc()
- case LCOMM:
- return p.hidden_type_recv_chan()
- case LFUNC:
- return p.hidden_type_func()
- }
-}
-
-func (p *parser) hidden_type_non_recv_chan() *Type {
- if trace && Debug['x'] != 0 {
- defer p.trace("hidden_type_non_recv_chan")()
- }
-
- switch p.tok {
- default:
- return p.hidden_type_misc()
- case LFUNC:
- return p.hidden_type_func()
- }
-}
-
-func (p *parser) hidden_type_misc() *Type {
- if trace && Debug['x'] != 0 {
- defer p.trace("hidden_type_misc")()
- }
-
- switch p.tok {
- case '@':
- // hidden_importsym
- s1 := p.hidden_importsym()
- return pkgtype(s1)
-
- case LNAME:
- // LNAME
- s1 := p.sym_
- p.next()
-
- // predefined name like uint8
- s1 = Pkglookup(s1.Name, builtinpkg)
- if s1.Def == nil || s1.Def.Op != OTYPE {
- Yyerror("%s is not a type", s1.Name)
- return nil
- } else {
- return s1.Def.Type
- }
-
- case '[':
- // '[' ']' hidden_type
- // '[' LLITERAL ']' hidden_type
- p.next()
- var s2 *Node
- if p.tok == LLITERAL {
- s2 = nodlit(p.val)
- p.next()
- }
- p.want(']')
- s4 := p.hidden_type()
-
- return aindex(s2, s4)
-
- case LMAP:
- // LMAP '[' hidden_type ']' hidden_type
- p.next()
- p.want('[')
- s3 := p.hidden_type()
- p.want(']')
- s5 := p.hidden_type()
-
- return typMap(s3, s5)
-
- case LSTRUCT:
- // LSTRUCT '{' ohidden_structdcl_list '}'
- p.next()
- p.want('{')
- s3 := p.ohidden_structdcl_list()
- p.want('}')
-
- return tostruct(s3)
-
- case LINTERFACE:
- // LINTERFACE '{' ohidden_interfacedcl_list '}'
- p.next()
- p.want('{')
- s3 := p.ohidden_interfacedcl_list()
- p.want('}')
-
- return tointerface(s3)
-
- case '*':
- // '*' hidden_type
- p.next()
- s2 := p.hidden_type()
- return Ptrto(s2)
-
- case LCHAN:
- p.next()
- switch p.tok {
- default:
- // LCHAN hidden_type_non_recv_chan
- s2 := p.hidden_type_non_recv_chan()
- ss := typChan(s2, Cboth)
- return ss
-
- case '(':
- // LCHAN '(' hidden_type_recv_chan ')'
- p.next()
- s3 := p.hidden_type_recv_chan()
- p.want(')')
- ss := typChan(s3, Cboth)
- return ss
-
- case LCOMM:
- // LCHAN hidden_type
- p.next()
- s3 := p.hidden_type()
- ss := typChan(s3, Csend)
- return ss
- }
-
- default:
- p.import_error()
- return nil
- }
-}
-
-func (p *parser) hidden_type_recv_chan() *Type {
- if trace && Debug['x'] != 0 {
- defer p.trace("hidden_type_recv_chan")()
- }
-
- p.want(LCOMM)
- p.want(LCHAN)
- s3 := p.hidden_type()
-
- ss := typChan(s3, Crecv)
- return ss
-}
-
-func (p *parser) hidden_type_func() *Type {
- if trace && Debug['x'] != 0 {
- defer p.trace("hidden_type_func")()
- }
-
- p.want(LFUNC)
- p.want('(')
- s3 := p.ohidden_funarg_list()
- p.want(')')
- s5 := p.ohidden_funres()
-
- return functype(nil, s3, s5)
-}
-
-func (p *parser) hidden_funarg() *Node {
- if trace && Debug['x'] != 0 {
- defer p.trace("hidden_funarg")()
- }
-
- s1 := p.sym()
- switch p.tok {
- default:
- s2 := p.hidden_type()
- s3 := p.oliteral()
-
- ss := Nod(ODCLFIELD, nil, typenod(s2))
- if s1 != nil {
- ss.Left = newname(s1)
- }
- ss.SetVal(s3)
- return ss
-
- case LDDD:
- p.next()
- s3 := p.hidden_type()
- s4 := p.oliteral()
-
- t := typSlice(s3)
-
- ss := Nod(ODCLFIELD, nil, typenod(t))
- if s1 != nil {
- ss.Left = newname(s1)
- }
- ss.Isddd = true
- ss.SetVal(s4)
-
- return ss
- }
-}
-
-func (p *parser) hidden_structdcl() *Node {
- if trace && Debug['x'] != 0 {
- defer p.trace("hidden_structdcl")()
- }
-
- s1 := p.sym()
- s2 := p.hidden_type()
- s3 := p.oliteral()
-
- var ss *Node
- if s1 != nil && s1.Name != "?" {
- ss = Nod(ODCLFIELD, newname(s1), typenod(s2))
- ss.SetVal(s3)
- } else {
- s := s2.Sym
- if s == nil && s2.IsPtr() {
- s = s2.Elem().Sym
- }
- pkg := importpkg
- if s1 != nil {
- pkg = s1.Pkg
- }
- ss = embedded(s, pkg)
- ss.Right = typenod(s2)
- ss.SetVal(s3)
- }
-
- return ss
-}
-
-func (p *parser) hidden_interfacedcl() *Node {
- if trace && Debug['x'] != 0 {
- defer p.trace("hidden_interfacedcl")()
- }
-
- // The original (now defunct) grammar in go.y accepted both a method
- // or an (embedded) type:
- //
- // hidden_interfacedcl:
- // sym '(' ohidden_funarg_list ')' ohidden_funres
- // {
- // $$ = Nod(ODCLFIELD, newname($1), typenod(functype(fakethis(), $3, $5)));
- // }
- // | hidden_type
- // {
- // $$ = Nod(ODCLFIELD, nil, typenod($1));
- // }
- //
- // But the current textual export code only exports (inlined) methods,
- // even if the methods came from embedded interfaces. Furthermore, in
- // the original grammar, hidden_type may also start with a sym (LNAME
- // or '@'), complicating matters further. Since we never have embedded
- // types, only parse methods here.
-
- s1 := p.sym()
- p.want('(')
- s3 := p.ohidden_funarg_list()
- p.want(')')
- s5 := p.ohidden_funres()
-
- return Nod(ODCLFIELD, newname(s1), typenod(functype(fakethis(), s3, s5)))
-}
-
-func (p *parser) ohidden_funres() []*Node {
- if trace && Debug['x'] != 0 {
- defer p.trace("ohidden_funres")()
- }
-
- switch p.tok {
- default:
- return nil
-
- case '(', '@', LNAME, '[', LMAP, LSTRUCT, LINTERFACE, '*', LCHAN, LCOMM, LFUNC:
- return p.hidden_funres()
- }
-}
-
-func (p *parser) hidden_funres() []*Node {
- if trace && Debug['x'] != 0 {
- defer p.trace("hidden_funres")()
- }
-
- switch p.tok {
- case '(':
- p.next()
- s2 := p.ohidden_funarg_list()
- p.want(')')
- return s2
-
- default:
- s1 := p.hidden_type()
- return []*Node{Nod(ODCLFIELD, nil, typenod(s1))}
- }
-}
-
-// ----------------------------------------------------------------------------
-// Importing constants
-
-func (p *parser) hidden_literal() *Node {
- if trace && Debug['x'] != 0 {
- defer p.trace("hidden_literal")()
- }
-
- switch p.tok {
- case LLITERAL:
- ss := nodlit(p.val)
- p.next()
- return ss
-
- case '-':
- p.next()
- if p.tok == LLITERAL {
- ss := nodlit(p.val)
- p.next()
- switch u := ss.Val().U.(type) {
- case *Mpint:
- u.Neg()
- case *Mpflt:
- u.Neg()
- case *Mpcplx:
- u.Real.Neg()
- u.Imag.Neg()
- default:
- Yyerror("bad negated constant")
- }
- return ss
- } else {
- p.import_error()
- return nil
- }
-
- case LNAME, '@', '?':
- s1 := p.sym()
- ss := oldname(Pkglookup(s1.Name, builtinpkg))
- if ss.Op != OLITERAL {
- Yyerror("bad constant %v", ss.Sym)
- }
- return ss
-
- default:
- p.import_error()
- return nil
- }
-}
-
-func (p *parser) hidden_constant() *Node {
- if trace && Debug['x'] != 0 {
- defer p.trace("hidden_constant")()
- }
-
- switch p.tok {
- default:
- return p.hidden_literal()
- case '(':
- p.next()
- s2 := p.hidden_literal()
- p.want('+')
- s4 := p.hidden_literal()
- p.want(')')
-
- if s2.Val().Ctype() == CTRUNE && s4.Val().Ctype() == CTINT {
- ss := s2
- s2.Val().U.(*Mpint).Add(s4.Val().U.(*Mpint))
- return ss
- }
- s4.Val().U.(*Mpcplx).Real = s4.Val().U.(*Mpcplx).Imag
- s4.Val().U.(*Mpcplx).Imag.SetFloat64(0.0)
- return nodcplxlit(s2.Val(), s4.Val())
- }
-}
-
-func (p *parser) hidden_import_list() {
- if trace && Debug['x'] != 0 {
- defer p.trace("hidden_import_list")()
- }
-
- for p.tok != '$' {
- p.hidden_import()
- }
-}
-
-func (p *parser) hidden_funarg_list() []*Node {
- if trace && Debug['x'] != 0 {
- defer p.trace("hidden_funarg_list")()
- }
-
- s1 := p.hidden_funarg()
- ss := []*Node{s1}
- for p.got(',') {
- s3 := p.hidden_funarg()
- ss = append(ss, s3)
- }
- return ss
-}
-
-func (p *parser) hidden_structdcl_list() []*Node {
- if trace && Debug['x'] != 0 {
- defer p.trace("hidden_structdcl_list")()
- }
-
- s1 := p.hidden_structdcl()
- ss := []*Node{s1}
- for p.got(';') {
- s3 := p.hidden_structdcl()
- ss = append(ss, s3)
- }
- return ss
-}
-
-func (p *parser) hidden_interfacedcl_list() []*Node {
- if trace && Debug['x'] != 0 {
- defer p.trace("hidden_interfacedcl_list")()
- }
-
- s1 := p.hidden_interfacedcl()
- ss := []*Node{s1}
- for p.got(';') {
- s3 := p.hidden_interfacedcl()
- ss = append(ss, s3)
- }
- return ss
-}
diff --git a/src/cmd/compile/internal/gc/pgen.go b/src/cmd/compile/internal/gc/pgen.go
index da2e675..acea790 100644
--- a/src/cmd/compile/internal/gc/pgen.go
+++ b/src/cmd/compile/internal/gc/pgen.go
@@ -18,14 +18,12 @@ import (
var makefuncdatasym_nsym int
func makefuncdatasym(nameprefix string, funcdatakind int64) *Sym {
- var nod Node
-
- sym := LookupN(nameprefix, makefuncdatasym_nsym)
+ sym := lookupN(nameprefix, makefuncdatasym_nsym)
makefuncdatasym_nsym++
pnod := newname(sym)
pnod.Class = PEXTERN
- Nodconst(&nod, Types[TINT32], funcdatakind)
- Thearch.Gins(obj.AFUNCDATA, &nod, pnod)
+ p := Gins(obj.AFUNCDATA, nil, pnod)
+ Addrconst(&p.From, funcdatakind)
return sym
}
@@ -90,16 +88,21 @@ func gvardefx(n *Node, as obj.As) {
Fatalf("gvardef nil")
}
if n.Op != ONAME {
- Yyerror("gvardef %#v; %v", n.Op, n)
+ 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 {
- Thearch.Gins(as, n, nil)
+ Gins(as, n, nil)
} else {
- Thearch.Gins(as, nil, n)
+ Gins(as, nil, n)
}
}
}
@@ -133,7 +136,7 @@ func emitptrargsmap() {
if Curfn.Func.Nname.Sym.Name == "_" {
return
}
- sym := Lookup(fmt.Sprintf("%s.args_stackmap", Curfn.Func.Nname.Sym.Name))
+ sym := lookup(fmt.Sprintf("%s.args_stackmap", Curfn.Func.Nname.Sym.Name))
nptr := int(Curfn.Type.ArgWidth() / int64(Widthptr))
bv := bvalloc(int32(nptr) * 2)
@@ -144,7 +147,7 @@ func emitptrargsmap() {
off := duint32(sym, 0, uint32(nbitmap))
off = duint32(sym, off, uint32(bv.n))
var xoffset int64
- if Curfn.Type.Recv() != nil {
+ if Curfn.IsMethod() {
xoffset = 0
onebitwalktype1(Curfn.Type.Recvs(), &xoffset, bv)
}
@@ -154,15 +157,11 @@ func emitptrargsmap() {
onebitwalktype1(Curfn.Type.Params(), &xoffset, bv)
}
- for j := 0; int32(j) < bv.n; j += 32 {
- off = duint32(sym, off, bv.b[j/32])
- }
+ off = dbvec(sym, off, bv)
if Curfn.Type.Results().NumFields() > 0 {
xoffset = 0
onebitwalktype1(Curfn.Type.Results(), &xoffset, bv)
- for j := 0; int32(j) < bv.n; j += 32 {
- off = duint32(sym, off, bv.b[j/32])
- }
+ off = dbvec(sym, off, bv)
}
ggloblsym(sym, int32(off), obj.RODATA|obj.LOCAL)
@@ -217,20 +216,12 @@ func (s byStackVar) Len() int { return len(s) }
func (s byStackVar) Less(i, j int) bool { return cmpstackvarlt(s[i], s[j]) }
func (s byStackVar) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
-// stkdelta records the stack offset delta for a node
-// during the compaction of the stack frame to remove
-// unused stack slots.
-var stkdelta = map[*Node]int64{}
+var scratchFpMem *Node
-// TODO(lvd) find out where the PAUTO/OLITERAL nodes come from.
-func allocauto(ptxt *obj.Prog) {
+func (s *ssaExport) AllocFrame(f *ssa.Func) {
Stksize = 0
stkptrsize = 0
- if len(Curfn.Func.Dcl) == 0 {
- return
- }
-
// Mark the PAUTO's unused.
for _, ln := range Curfn.Func.Dcl {
if ln.Class == PAUTO {
@@ -238,37 +229,48 @@ func allocauto(ptxt *obj.Prog) {
}
}
- markautoused(ptxt)
+ for _, l := range f.RegAlloc {
+ if ls, ok := l.(ssa.LocalSlot); ok {
+ ls.N.(*Node).Used = true
+ }
- sort.Sort(byStackVar(Curfn.Func.Dcl))
+ }
- // Unused autos are at the end, chop 'em off.
- n := Curfn.Func.Dcl[0]
- if n.Class == PAUTO && n.Op == ONAME && !n.Used {
- // No locals used at all
- Curfn.Func.Dcl = nil
+ scratchUsed := false
+ for _, b := range f.Blocks {
+ for _, v := range b.Values {
+ switch a := v.Aux.(type) {
+ case *ssa.ArgSymbol:
+ a.Node.(*Node).Used = true
+ case *ssa.AutoSymbol:
+ a.Node.(*Node).Used = true
+ }
- fixautoused(ptxt)
- return
+ if !scratchUsed {
+ scratchUsed = v.Op.UsesScratch()
+ }
+ }
}
- for i := 1; i < len(Curfn.Func.Dcl); i++ {
- n = Curfn.Func.Dcl[i]
- if n.Class == PAUTO && n.Op == ONAME && !n.Used {
- Curfn.Func.Dcl = Curfn.Func.Dcl[:i]
- break
- }
+ if f.Config.NeedsFpScratch {
+ scratchFpMem = temp(Types[TUINT64])
+ scratchFpMem.Used = scratchUsed
}
- // Reassign stack offsets of the locals that are still there.
- var w int64
- for _, n := range Curfn.Func.Dcl {
- if n.Class != PAUTO || n.Op != ONAME {
+ sort.Sort(byStackVar(Curfn.Func.Dcl))
+
+ // Reassign stack offsets of the locals that are used.
+ for i, n := range Curfn.Func.Dcl {
+ if n.Op != ONAME || n.Class != PAUTO {
continue
}
+ if !n.Used {
+ Curfn.Func.Dcl = Curfn.Func.Dcl[:i]
+ break
+ }
dowidth(n.Type)
- w = n.Type.Width
+ w := n.Type.Width
if w >= Thearch.MAXWIDTH || w < 0 {
Fatalf("bad width")
}
@@ -277,58 +279,19 @@ func allocauto(ptxt *obj.Prog) {
if haspointers(n.Type) {
stkptrsize = Stksize
}
- if Thearch.LinkArch.InFamily(sys.MIPS64, sys.ARM, sys.ARM64, sys.PPC64, sys.S390X) {
+ if Thearch.LinkArch.InFamily(sys.MIPS, sys.MIPS64, sys.ARM, sys.ARM64, sys.PPC64, sys.S390X) {
Stksize = Rnd(Stksize, int64(Widthptr))
}
if Stksize >= 1<<31 {
setlineno(Curfn)
- Yyerror("stack frame too large (>2GB)")
+ yyerror("stack frame too large (>2GB)")
}
- stkdelta[n] = -Stksize - n.Xoffset
+ n.Xoffset = -Stksize
}
Stksize = Rnd(Stksize, int64(Widthreg))
stkptrsize = Rnd(stkptrsize, int64(Widthreg))
-
- fixautoused(ptxt)
-
- // The debug information needs accurate offsets on the symbols.
- for _, ln := range Curfn.Func.Dcl {
- if ln.Class != PAUTO || ln.Op != ONAME {
- continue
- }
- ln.Xoffset += stkdelta[ln]
- delete(stkdelta, ln)
- }
-}
-
-func Cgen_checknil(n *Node) {
- if Disable_checknil != 0 {
- return
- }
-
- // Ideally we wouldn't see any integer types here, but we do.
- if n.Type == nil || (!n.Type.IsPtr() && !n.Type.IsInteger() && n.Type.Etype != TUNSAFEPTR) {
- Dump("checknil", n)
- Fatalf("bad checknil")
- }
-
- // Most architectures require that the address to be checked is
- // in a register (it could be in memory).
- needsReg := !Thearch.LinkArch.InFamily(sys.AMD64, sys.I386)
-
- // Move the address to be checked into a register if necessary.
- if (needsReg && n.Op != OREGISTER) || !n.Addable || n.Op == OLITERAL {
- var reg Node
- Regalloc(®, Types[Tptr], n)
- Cgen(n, ®)
- Thearch.Gins(obj.ACHECKNIL, ®, nil)
- Regfree(®)
- return
- }
-
- Thearch.Gins(obj.ACHECKNIL, n, nil)
}
func compile(fn *Node) {
@@ -336,14 +299,16 @@ func compile(fn *Node) {
Newproc = Sysfunc("newproc")
Deferproc = Sysfunc("deferproc")
Deferreturn = Sysfunc("deferreturn")
- Panicindex = Sysfunc("panicindex")
+ panicindex = Sysfunc("panicindex")
panicslice = Sysfunc("panicslice")
panicdivide = Sysfunc("panicdivide")
- throwreturn = Sysfunc("throwreturn")
growslice = Sysfunc("growslice")
- writebarrierptr = Sysfunc("writebarrierptr")
- typedmemmove = Sysfunc("typedmemmove")
panicdottype = Sysfunc("panicdottype")
+ panicnildottype = Sysfunc("panicnildottype")
+ assertE2I = Sysfunc("assertE2I")
+ assertE2I2 = Sysfunc("assertE2I2")
+ assertI2I = Sysfunc("assertI2I")
+ assertI2I2 = Sysfunc("assertI2I2")
}
defer func(lno int32) {
@@ -355,29 +320,23 @@ func compile(fn *Node) {
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)
+ yyerror("missing function body for %q", fn.Func.Nname.Sym.Name)
return
}
- if Debug['A'] != 0 {
- return
- }
emitptrargsmap()
return
}
saveerrors()
- // set up domain for labels
- clearlabels()
-
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 := nod(OAS, t.Nname, nil)
n = typecheck(n, Etop)
- Curfn.Nbody.Set(append([]*Node{n}, Curfn.Nbody.Slice()...))
+ Curfn.Nbody.Prepend(n)
}
}
}
@@ -400,27 +359,20 @@ func compile(fn *Node) {
}
// Build an SSA backend function.
- var ssafn *ssa.Func
- if shouldssa(Curfn) {
- ssafn = buildssa(Curfn)
+ ssafn := buildssa(Curfn)
+ if nerrors != 0 {
+ return
}
- continpc = nil
- breakpc = nil
-
- pl := newplist()
- pl.Name = Linksym(Curfn.Func.Nname.Sym)
+ newplist()
setlineno(Curfn)
- var nod1 Node
- Nodconst(&nod1, Types[TINT32], 0)
nam := Curfn.Func.Nname
if isblank(nam) {
nam = nil
}
- ptxt := Thearch.Gins(obj.ATEXT, nam, &nod1)
- Afunclit(&ptxt.From, Curfn.Func.Nname)
+ ptxt := Gins(obj.ATEXT, nam, nil)
ptxt.From3 = new(obj.Addr)
if fn.Func.Dupok {
ptxt.From3.Offset |= obj.DUPOK
@@ -438,7 +390,7 @@ func compile(fn *Node) {
ptxt.From3.Offset |= obj.REFLECTMETHOD
}
if fn.Func.Pragma&Systemstack != 0 {
- ptxt.From.Sym.Cfunc = true
+ ptxt.From.Sym.Set(obj.AttrCFunc, true)
}
// Clumsy but important.
@@ -450,8 +402,6 @@ func compile(fn *Node) {
}
}
- ginit()
-
gcargs := makefuncdatasym("gcargs·", obj.FUNCDATA_ArgsPointerMaps)
gclocals := makefuncdatasym("gclocals·", obj.FUNCDATA_LocalsPointerMaps)
@@ -471,19 +421,24 @@ func compile(fn *Node) {
continue
}
switch n.Class {
- case PAUTO, PPARAM, PPARAMOUT:
- Nodconst(&nod1, Types[TUINTPTR], n.Type.Width)
- p := Thearch.Gins(obj.ATYPE, n, &nod1)
- p.From.Gotype = Linksym(ngotype(n))
+ case PAUTO:
+ if !n.Used {
+ continue
+ }
+ 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))
}
}
- if ssafn != nil {
- genssa(ssafn, ptxt, gcargs, gclocals)
- ssafn.Free()
- } else {
- genlegacy(ptxt, gcargs, gclocals)
- }
+ genssa(ssafn, ptxt, gcargs, gclocals)
+ ssafn.Free()
}
type symByName []*Sym
@@ -491,70 +446,3 @@ type symByName []*Sym
func (a symByName) Len() int { return len(a) }
func (a symByName) Less(i, j int) bool { return a[i].Name < a[j].Name }
func (a symByName) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
-
-// genlegacy compiles Curfn using the legacy non-SSA code generator.
-func genlegacy(ptxt *obj.Prog, gcargs, gclocals *Sym) {
- Genlist(Curfn.Func.Enter)
- Genlist(Curfn.Nbody)
- gclean()
- checklabels()
- if nerrors != 0 {
- return
- }
- if Curfn.Func.Endlineno != 0 {
- lineno = Curfn.Func.Endlineno
- }
-
- if Curfn.Type.Results().NumFields() != 0 {
- Ginscall(throwreturn, 0)
- }
-
- ginit()
-
- // TODO: Determine when the final cgen_ret can be omitted. Perhaps always?
- cgen_ret(nil)
-
- if hasdefer {
- // deferreturn pretends to have one uintptr argument.
- // Reserve space for it so stack scanner is happy.
- if Maxarg < int64(Widthptr) {
- Maxarg = int64(Widthptr)
- }
- }
-
- gclean()
- if nerrors != 0 {
- return
- }
-
- Pc.As = obj.ARET // overwrite AEND
- Pc.Lineno = lineno
-
- fixjmp(ptxt)
- if Debug['N'] == 0 || Debug['R'] != 0 || Debug['P'] != 0 {
- regopt(ptxt)
- nilopt(ptxt)
- }
-
- Thearch.Expandchecks(ptxt)
-
- allocauto(ptxt)
-
- setlineno(Curfn)
- if Stksize+Maxarg > 1<<31 {
- Yyerror("stack frame too large (>2GB)")
- return
- }
-
- // Emit garbage collection symbols.
- liveness(Curfn, ptxt, gcargs, gclocals)
-
- Thearch.Defframe(ptxt)
-
- if Debug['f'] != 0 {
- frame(0)
- }
-
- // Remove leftover instrumentation from the instruction stream.
- removevardef(ptxt)
-}
diff --git a/src/cmd/compile/internal/gc/phi.go b/src/cmd/compile/internal/gc/phi.go
new file mode 100644
index 0000000..0d4dbb5
--- /dev/null
+++ b/src/cmd/compile/internal/gc/phi.go
@@ -0,0 +1,521 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gc
+
+import (
+ "cmd/compile/internal/ssa"
+ "container/heap"
+ "fmt"
+)
+
+// This file contains the algorithm to place phi nodes in a function.
+// For small functions, we use Braun, Buchwald, Hack, Leißa, Mallon, and Zwinkau.
+// http://pp.info.uni-karlsruhe.de/uploads/publikationen/braun13cc.pdf
+// For large functions, we use Sreedhar & Gao: A Linear Time Algorithm for Placing Φ-Nodes.
+// http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.8.1979&rep=rep1&type=pdf
+
+const smallBlocks = 500
+
+const debugPhi = false
+
+// insertPhis finds all the places in the function where a phi is
+// necessary and inserts them.
+// Uses FwdRef ops to find all uses of variables, and s.defvars to find
+// all definitions.
+// Phi values are inserted, and all FwdRefs are changed to a Copy
+// of the appropriate phi or definition.
+// TODO: make this part of cmd/compile/internal/ssa somehow?
+func (s *state) insertPhis() {
+ if len(s.f.Blocks) <= smallBlocks {
+ sps := simplePhiState{s: s, f: s.f, defvars: s.defvars}
+ sps.insertPhis()
+ return
+ }
+ ps := phiState{s: s, f: s.f, defvars: s.defvars}
+ ps.insertPhis()
+}
+
+type phiState struct {
+ s *state // SSA state
+ f *ssa.Func // function to work on
+ defvars []map[*Node]*ssa.Value // defined variables at end of each block
+
+ varnum map[*Node]int32 // variable numbering
+
+ // properties of the dominator tree
+ idom []*ssa.Block // dominator parents
+ tree []domBlock // dominator child+sibling
+ level []int32 // level in dominator tree (0 = root or unreachable, 1 = children of root, ...)
+
+ // scratch locations
+ priq blockHeap // priority queue of blocks, higher level (toward leaves) = higher priority
+ q []*ssa.Block // inner loop queue
+ queued *sparseSet // has been put in q
+ hasPhi *sparseSet // has a phi
+ hasDef *sparseSet // has a write of the variable we're processing
+
+ // miscellaneous
+ placeholder *ssa.Value // dummy value to use as a "not set yet" placeholder.
+}
+
+func (s *phiState) insertPhis() {
+ if debugPhi {
+ fmt.Println(s.f.String())
+ }
+
+ // Find all the variables for which we need to match up reads & writes.
+ // This step prunes any basic-block-only variables from consideration.
+ // Generate a numbering for these variables.
+ s.varnum = map[*Node]int32{}
+ var vars []*Node
+ var vartypes []ssa.Type
+ for _, b := range s.f.Blocks {
+ for _, v := range b.Values {
+ if v.Op != ssa.OpFwdRef {
+ continue
+ }
+ var_ := v.Aux.(*Node)
+
+ // Optimization: look back 1 block for the definition.
+ if len(b.Preds) == 1 {
+ c := b.Preds[0].Block()
+ if w := s.defvars[c.ID][var_]; w != nil {
+ v.Op = ssa.OpCopy
+ v.Aux = nil
+ v.AddArg(w)
+ continue
+ }
+ }
+
+ if _, ok := s.varnum[var_]; ok {
+ continue
+ }
+ s.varnum[var_] = int32(len(vartypes))
+ if debugPhi {
+ fmt.Printf("var%d = %v\n", len(vartypes), var_)
+ }
+ vars = append(vars, var_)
+ vartypes = append(vartypes, v.Type)
+ }
+ }
+
+ if len(vartypes) == 0 {
+ return
+ }
+
+ // Find all definitions of the variables we need to process.
+ // defs[n] contains all the blocks in which variable number n is assigned.
+ defs := make([][]*ssa.Block, len(vartypes))
+ for _, b := range s.f.Blocks {
+ for var_ := range s.defvars[b.ID] { // TODO: encode defvars some other way (explicit ops)? make defvars[n] a slice instead of a map.
+ if n, ok := s.varnum[var_]; ok {
+ defs[n] = append(defs[n], b)
+ }
+ }
+ }
+
+ // Make dominator tree.
+ s.idom = s.f.Idom()
+ s.tree = make([]domBlock, s.f.NumBlocks())
+ for _, b := range s.f.Blocks {
+ p := s.idom[b.ID]
+ if p != nil {
+ s.tree[b.ID].sibling = s.tree[p.ID].firstChild
+ s.tree[p.ID].firstChild = b
+ }
+ }
+ // Compute levels in dominator tree.
+ // With parent pointers we can do a depth-first walk without
+ // any auxiliary storage.
+ s.level = make([]int32, s.f.NumBlocks())
+ b := s.f.Entry
+levels:
+ for {
+ if p := s.idom[b.ID]; p != nil {
+ s.level[b.ID] = s.level[p.ID] + 1
+ if debugPhi {
+ fmt.Printf("level %s = %d\n", b, s.level[b.ID])
+ }
+ }
+ if c := s.tree[b.ID].firstChild; c != nil {
+ b = c
+ continue
+ }
+ for {
+ if c := s.tree[b.ID].sibling; c != nil {
+ b = c
+ continue levels
+ }
+ b = s.idom[b.ID]
+ if b == nil {
+ break levels
+ }
+ }
+ }
+
+ // Allocate scratch locations.
+ s.priq.level = s.level
+ s.q = make([]*ssa.Block, 0, s.f.NumBlocks())
+ 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)
+
+ // Generate phi ops for each variable.
+ for n := range vartypes {
+ s.insertVarPhis(n, vars[n], defs[n], vartypes[n])
+ }
+
+ // Resolve FwdRefs to the correct write or phi.
+ s.resolveFwdRefs()
+
+ // Erase variable numbers stored in AuxInt fields of phi ops. They are no longer needed.
+ for _, b := range s.f.Blocks {
+ for _, v := range b.Values {
+ if v.Op == ssa.OpPhi {
+ v.AuxInt = 0
+ }
+ }
+ }
+}
+
+func (s *phiState) insertVarPhis(n int, var_ *Node, defs []*ssa.Block, typ ssa.Type) {
+ priq := &s.priq
+ q := s.q
+ queued := s.queued
+ queued.clear()
+ hasPhi := s.hasPhi
+ hasPhi.clear()
+ hasDef := s.hasDef
+ hasDef.clear()
+
+ // Add defining blocks to priority queue.
+ for _, b := range defs {
+ priq.a = append(priq.a, b)
+ hasDef.add(b.ID)
+ if debugPhi {
+ fmt.Printf("def of var%d in %s\n", n, b)
+ }
+ }
+ heap.Init(priq)
+
+ // Visit blocks defining variable n, from deepest to shallowest.
+ for len(priq.a) > 0 {
+ currentRoot := heap.Pop(priq).(*ssa.Block)
+ if debugPhi {
+ fmt.Printf("currentRoot %s\n", currentRoot)
+ }
+ // Walk subtree below definition.
+ // Skip subtrees we've done in previous iterations.
+ // Find edges exiting tree dominated by definition (the dominance frontier).
+ // Insert phis at target blocks.
+ if queued.contains(currentRoot.ID) {
+ s.s.Fatalf("root already in queue")
+ }
+ q = append(q, currentRoot)
+ queued.add(currentRoot.ID)
+ for len(q) > 0 {
+ b := q[len(q)-1]
+ q = q[:len(q)-1]
+ if debugPhi {
+ fmt.Printf(" processing %s\n", b)
+ }
+
+ 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] {
+ // 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?
+ // 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++ {
+ v.AddArg(s.placeholder) // Actual args will be filled in by resolveFwdRefs.
+ }
+ if debugPhi {
+ fmt.Printf("new phi for var%d in %s: %s\n", n, c, v)
+ }
+ if !hasDef.contains(c.ID) {
+ // There's now a new definition of this variable in block c.
+ // Add it to the priority queue to explore.
+ heap.Push(priq, c)
+ hasDef.add(c.ID)
+ }
+ }
+ }
+
+ // Visit children if they have not been visited yet.
+ for c := s.tree[b.ID].firstChild; c != nil; c = s.tree[c.ID].sibling {
+ if !queued.contains(c.ID) {
+ q = append(q, c)
+ queued.add(c.ID)
+ }
+ }
+ }
+ }
+}
+
+// resolveFwdRefs links all FwdRef uses up to their nearest dominating definition.
+func (s *phiState) resolveFwdRefs() {
+ // Do a depth-first walk of the dominator tree, keeping track
+ // of the most-recently-seen value for each variable.
+
+ // Map from variable ID to SSA value at the current point of the walk.
+ values := make([]*ssa.Value, len(s.varnum))
+ for i := range values {
+ values[i] = s.placeholder
+ }
+
+ // Stack of work to do.
+ type stackEntry struct {
+ b *ssa.Block // block to explore
+
+ // variable/value pair to reinstate on exit
+ n int32 // variable ID
+ v *ssa.Value
+
+ // Note: only one of b or n,v will be set.
+ }
+ var stk []stackEntry
+
+ stk = append(stk, stackEntry{b: s.f.Entry})
+ for len(stk) > 0 {
+ work := stk[len(stk)-1]
+ stk = stk[:len(stk)-1]
+
+ b := work.b
+ if b == nil {
+ // On exit from a block, this case will undo any assignments done below.
+ values[work.n] = work.v
+ continue
+ }
+
+ // Process phis as new defs. They come before FwdRefs in this block.
+ for _, v := range b.Values {
+ if v.Op != ssa.OpPhi {
+ continue
+ }
+ n := int32(v.AuxInt)
+ // Remember the old assignment so we can undo it when we exit b.
+ stk = append(stk, stackEntry{n: n, v: values[n]})
+ // Record the new assignment.
+ values[n] = v
+ }
+
+ // Replace a FwdRef op with the current incoming value for its variable.
+ for _, v := range b.Values {
+ if v.Op != ssa.OpFwdRef {
+ continue
+ }
+ n := s.varnum[v.Aux.(*Node)]
+ v.Op = ssa.OpCopy
+ v.Aux = nil
+ v.AddArg(values[n])
+ }
+
+ // Establish values for variables defined in b.
+ for var_, v := range s.defvars[b.ID] {
+ n, ok := s.varnum[var_]
+ if !ok {
+ // some variable not live across a basic block boundary.
+ continue
+ }
+ // Remember the old assignment so we can undo it when we exit b.
+ stk = append(stk, stackEntry{n: n, v: values[n]})
+ // Record the new assignment.
+ values[n] = v
+ }
+
+ // Replace phi args in successors with the current incoming value.
+ for _, e := range b.Succs {
+ c, i := e.Block(), e.Index()
+ for j := len(c.Values) - 1; j >= 0; j-- {
+ v := c.Values[j]
+ 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])
+ }
+ }
+
+ // Walk children in dominator tree.
+ for c := s.tree[b.ID].firstChild; c != nil; c = s.tree[c.ID].sibling {
+ stk = append(stk, stackEntry{b: c})
+ }
+ }
+}
+
+// domBlock contains extra per-block information to record the dominator tree.
+type domBlock struct {
+ firstChild *ssa.Block // first child of block in dominator tree
+ sibling *ssa.Block // next child of parent in dominator tree
+}
+
+// A block heap is used as a priority queue to implement the PiggyBank
+// from Sreedhar and Gao. That paper uses an array which is better
+// asymptotically but worse in the common case when the PiggyBank
+// holds a sparse set of blocks.
+type blockHeap struct {
+ a []*ssa.Block // block IDs in heap
+ level []int32 // depth in dominator tree (static, used for determining priority)
+}
+
+func (h *blockHeap) Len() int { return len(h.a) }
+func (h *blockHeap) Swap(i, j int) { a := h.a; a[i], a[j] = a[j], a[i] }
+
+func (h *blockHeap) Push(x interface{}) {
+ v := x.(*ssa.Block)
+ h.a = append(h.a, v)
+}
+func (h *blockHeap) Pop() interface{} {
+ old := h.a
+ n := len(old)
+ x := old[n-1]
+ h.a = old[:n-1]
+ return x
+}
+func (h *blockHeap) Less(i, j int) bool {
+ return h.level[h.a[i].ID] > h.level[h.a[j].ID]
+}
+
+// TODO: stop walking the iterated domininance frontier when
+// the variable is dead. Maybe detect that by checking if the
+// node we're on is reverse dominated by all the reads?
+// Reverse dominated by the highest common successor of all the reads?
+
+// copy of ../ssa/sparseset.go
+// TODO: move this file to ../ssa, then use sparseSet there.
+type sparseSet struct {
+ dense []ssa.ID
+ sparse []int32
+}
+
+// newSparseSet returns a sparseSet that can represent
+// integers between 0 and n-1
+func newSparseSet(n int) *sparseSet {
+ return &sparseSet{dense: nil, sparse: make([]int32, n)}
+}
+
+func (s *sparseSet) contains(x ssa.ID) bool {
+ i := s.sparse[x]
+ return i < int32(len(s.dense)) && s.dense[i] == x
+}
+
+func (s *sparseSet) add(x ssa.ID) {
+ i := s.sparse[x]
+ if i < int32(len(s.dense)) && s.dense[i] == x {
+ return
+ }
+ s.dense = append(s.dense, x)
+ s.sparse[x] = int32(len(s.dense)) - 1
+}
+
+func (s *sparseSet) clear() {
+ s.dense = s.dense[:0]
+}
+
+// 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
+}
+
+func (s *simplePhiState) insertPhis() {
+ // Find FwdRef ops.
+ for _, b := range s.f.Blocks {
+ for _, v := range b.Values {
+ if v.Op != ssa.OpFwdRef {
+ continue
+ }
+ s.fwdrefs = append(s.fwdrefs, v)
+ var_ := v.Aux.(*Node)
+ if _, ok := s.defvars[b.ID][var_]; !ok {
+ s.defvars[b.ID][var_] = v // treat FwdDefs as definitions.
+ }
+ }
+ }
+
+ var args []*ssa.Value
+
+loop:
+ for len(s.fwdrefs) > 0 {
+ v := s.fwdrefs[len(s.fwdrefs)-1]
+ 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.
+ // It doesn't matter what we use here as long as it is well-formed.
+ v.Op = ssa.OpUnknown
+ v.Aux = nil
+ continue
+ }
+ // 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))
+ }
+
+ // Decide if we need a phi or not. We need a phi if there
+ // are two different args (which are both not v).
+ var w *ssa.Value
+ for _, a := range args {
+ if a == v {
+ continue // self-reference
+ }
+ if a == w {
+ continue // already have this witness
+ }
+ if w != nil {
+ // two witnesses, need a phi value
+ v.Op = ssa.OpPhi
+ v.AddArgs(args...)
+ v.Aux = nil
+ continue loop
+ }
+ w = a // save witness
+ }
+ if w == nil {
+ s.s.Fatalf("no witness for reachable phi %s", v)
+ }
+ // One witness. Make v a copy of w.
+ v.Op = ssa.OpCopy
+ v.Aux = nil
+ v.AddArg(w)
+ }
+}
+
+// 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 {
+ for {
+ if v := s.defvars[b.ID][var_]; v != nil {
+ return v
+ }
+ // The variable is not defined by b and we haven't looked it up yet.
+ // If b has exactly one predecessor, loop to look it up there.
+ // Otherwise, give up and insert a new FwdRef and resolve it later.
+ if len(b.Preds) != 1 {
+ break
+ }
+ b = b.Preds[0].Block()
+ }
+ // Generate a FwdRef for the variable and return that.
+ v := b.NewValue0A(line, ssa.OpFwdRef, t, var_)
+ s.defvars[b.ID][var_] = v
+ s.s.addNamedValue(var_, v)
+ s.fwdrefs = append(s.fwdrefs, v)
+ return v
+}
diff --git a/src/cmd/compile/internal/gc/plive.go b/src/cmd/compile/internal/gc/plive.go
index ca0421d..5fa8645 100644
--- a/src/cmd/compile/internal/gc/plive.go
+++ b/src/cmd/compile/internal/gc/plive.go
@@ -96,18 +96,35 @@ type Liveness struct {
livepointers []bvec
}
+// 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
+}
+
// Constructs a new basic block containing a single instruction.
func newblock(prog *obj.Prog) *BasicBlock {
if prog == nil {
Fatalf("newblock: prog cannot be nil")
}
- result := new(BasicBlock)
+ // 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 = make([]*BasicBlock, 0, 2)
- result.succ = make([]*BasicBlock, 0, 2)
+ result.pred = b.pred[:0]
+ result.succ = b.succ[:0]
return result
}
@@ -400,7 +417,6 @@ func newcfg(firstp *obj.Prog) []*BasicBlock {
bb := newblock(firstp)
cfg = append(cfg, bb)
for p := firstp; p != nil && p.As != obj.AEND; p = p.Link {
- Thearch.Proginfo(p)
if p.To.Type == obj.TYPE_BRANCH {
if p.To.Val == nil {
Fatalf("prog branch to nil")
@@ -538,54 +554,46 @@ func isfunny(n *Node) bool {
// initialized, because any use of a variable must come after its
// initialization.
func progeffects(prog *obj.Prog, vars []*Node, uevar bvec, varkill bvec, avarinit bvec) {
- bvresetall(uevar)
- bvresetall(varkill)
- bvresetall(avarinit)
+ 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 implicitly read all the arguments. For
- // the sake of correctness, out arguments must be read. For the
- // sake of backtrace quality, we read in arguments as well.
- //
- // A return instruction with a p.to is a tail return, which brings
- // the stack pointer back up (if it ever went down) and then jumps
- // to a new function entirely. That form of instruction must read
- // all the parameters for correctness, and similarly it must not
- // read the out arguments - they won't be set until the new
- // function runs.
+ // Return instructions read all of the out arguments.
for i, node := range vars {
switch node.Class {
- case PPARAM:
- if !node.NotLiveAtEnd() {
- bvset(uevar, int32(i))
- }
-
- // If the result had its address taken, it is being tracked
+ // If the result had its address taken, it is being tracked
// by the avarinit code, which does not use uevar.
// If we added it to uevar too, we'd not see any kill
// and decide that the variable was live entry, which it is not.
// So only use uevar in the non-addrtaken case.
- // The p.to.type == thearch.D_NONE limits the bvset to
- // non-tail-call return instructions; see note above
- // the for loop for details.
+ // 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 {
- bvset(uevar, int32(i))
+ uevar.Set(int32(i))
}
}
}
return
}
- if prog.As == obj.AJMP && prog.To.Type == obj.TYPE_MEM && prog.To.Name == obj.NAME_EXTERN {
- // This is a tail call. Ensure the arguments are still alive.
- // See issue 16016.
- for i, node := range vars {
- if node.Class == PPARAM {
- bvset(uevar, int32(i))
- }
- }
- }
if prog.As == obj.ATEXT {
// A text instruction marks the entry point to a function and
@@ -594,29 +602,31 @@ func progeffects(prog *obj.Prog, vars []*Node, uevar bvec, varkill bvec, avarini
switch node.Class {
case PPARAM:
if node.Addrtaken {
- bvset(avarinit, int32(i))
+ avarinit.Set(int32(i))
}
- bvset(varkill, int32(i))
+ varkill.Set(int32(i))
}
}
return
}
- if prog.Info.Flags&(LeftRead|LeftWrite|LeftAddr) != 0 {
+ 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 {
- bvset(avarinit, pos)
+ avarinit.Set(pos)
} else {
- if prog.Info.Flags&(LeftRead|LeftAddr) != 0 {
- bvset(uevar, pos)
+ if info.Flags&(LeftRead|LeftAddr) != 0 {
+ uevar.Set(pos)
}
- if prog.Info.Flags&LeftWrite != 0 {
- if !Isfat(n.Type) {
- bvset(varkill, pos)
+ if info.Flags&LeftWrite != 0 {
+ if !isfat(n.Type) {
+ varkill.Set(pos)
}
}
}
@@ -624,17 +634,31 @@ func progeffects(prog *obj.Prog, vars []*Node, uevar bvec, varkill bvec, avarini
}
}
- if prog.Info.Flags&(RightRead|RightWrite|RightAddr) != 0 {
+ 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 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 {
- bvset(avarinit, pos)
+ avarinit.Set(pos)
}
if prog.As == obj.AVARDEF || prog.As == obj.AVARKILL {
- bvset(varkill, pos)
+ varkill.Set(pos)
}
} else {
// RightRead is a read, obviously.
@@ -645,12 +669,12 @@ func progeffects(prog *obj.Prog, vars []*Node, uevar bvec, varkill bvec, avarini
// It is not a read. It is equivalent to RightWrite except that
// having the RightAddr bit set keeps the registerizer from
// trying to substitute a register for the memory location.
- if (prog.Info.Flags&RightRead != 0) || prog.Info.Flags&(RightAddr|RightWrite) == RightAddr {
- bvset(uevar, pos)
+ if (info.Flags&RightRead != 0) || info.Flags&(RightAddr|RightWrite) == RightAddr {
+ uevar.Set(pos)
}
- if prog.Info.Flags&RightWrite != 0 {
- if !Isfat(n.Type) || prog.As == obj.AVARDEF {
- bvset(varkill, pos)
+ if info.Flags&RightWrite != 0 {
+ if !isfat(n.Type) || prog.As == obj.AVARDEF {
+ varkill.Set(pos)
}
}
}
@@ -704,14 +728,10 @@ func newliveness(fn *Node, ptxt *obj.Prog, cfg []*BasicBlock, vars []*Node) *Liv
}
func printeffects(p *obj.Prog, uevar bvec, varkill bvec, avarinit bvec) {
- fmt.Printf("effects of %v", p)
- fmt.Printf("\nuevar: ")
- bvprint(uevar)
- fmt.Printf("\nvarkill: ")
- bvprint(varkill)
- fmt.Printf("\navarinit: ")
- bvprint(avarinit)
- fmt.Printf("\n")
+ 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
@@ -733,7 +753,7 @@ func printnode(node *Node) {
func printvars(name string, bv bvec, vars []*Node) {
fmt.Printf("%s:", name)
for i, node := range vars {
- if bvget(bv, int32(i)) != 0 {
+ if bv.Get(int32(i)) {
printnode(node)
}
}
@@ -771,8 +791,7 @@ func livenessprintblock(lv *Liveness, bb *BasicBlock) {
if prog.As == obj.APCDATA && prog.From.Offset == obj.PCDATA_StackMapIndex {
pos := int32(prog.To.Offset)
live := lv.livepointers[pos]
- fmt.Printf(" ")
- bvprint(live)
+ fmt.Printf(" %s", live.String())
}
fmt.Printf("\n")
@@ -806,7 +825,7 @@ func checkauto(fn *Node, p *obj.Prog, n *Node) {
for _, ln := range fn.Func.Dcl {
fmt.Printf("\t%v (%p; class=%d)\n", ln, ln, ln.Class)
}
- Yyerror("checkauto: invariant lost")
+ yyerror("checkauto: invariant lost")
}
func checkparam(fn *Node, p *obj.Prog, n *Node) {
@@ -823,7 +842,7 @@ func checkparam(fn *Node, p *obj.Prog, n *Node) {
for _, ln := range fn.Func.Dcl {
fmt.Printf("\t%v (%p; class=%d)\n", ln, ln, ln.Class)
}
- Yyerror("checkparam: invariant lost")
+ yyerror("checkparam: invariant lost")
}
func checkprog(fn *Node, p *obj.Prog) {
@@ -855,7 +874,7 @@ func checkptxt(fn *Node, firstp *obj.Prog) {
if false {
fmt.Printf("analyzing '%v'\n", p)
}
- if p.As != obj.AGLOBL && p.As != obj.ATYPE {
+ if p.As != obj.ATYPE {
checkprog(fn, p)
}
}
@@ -898,7 +917,7 @@ func onebitwalktype1(t *Type, xoffset *int64, bv bvec) {
if *xoffset&int64(Widthptr-1) != 0 {
Fatalf("onebitwalktype1: invalid alignment, %v", t)
}
- bvset(bv, int32(*xoffset/int64(Widthptr))) // pointer
+ bv.Set(int32(*xoffset / int64(Widthptr))) // pointer
*xoffset += t.Width
case TSTRING:
@@ -906,7 +925,7 @@ func onebitwalktype1(t *Type, xoffset *int64, bv bvec) {
if *xoffset&int64(Widthptr-1) != 0 {
Fatalf("onebitwalktype1: invalid alignment, %v", t)
}
- bvset(bv, int32(*xoffset/int64(Widthptr))) //pointer in first slot
+ bv.Set(int32(*xoffset / int64(Widthptr))) //pointer in first slot
*xoffset += t.Width
case TINTER:
@@ -916,8 +935,8 @@ func onebitwalktype1(t *Type, xoffset *int64, bv bvec) {
if *xoffset&int64(Widthptr-1) != 0 {
Fatalf("onebitwalktype1: invalid alignment, %v", t)
}
- bvset(bv, int32(*xoffset/int64(Widthptr))) // pointer in first slot
- bvset(bv, int32(*xoffset/int64(Widthptr)+1)) // pointer in second slot
+ bv.Set(int32(*xoffset / int64(Widthptr))) // pointer in first slot
+ bv.Set(int32(*xoffset/int64(Widthptr) + 1)) // pointer in second slot
*xoffset += t.Width
case TSLICE:
@@ -925,7 +944,7 @@ func onebitwalktype1(t *Type, xoffset *int64, bv bvec) {
if *xoffset&int64(Widthptr-1) != 0 {
Fatalf("onebitwalktype1: invalid TARRAY alignment, %v", t)
}
- bvset(bv, int32(*xoffset/int64(Widthptr))) // pointer in first slot (BitsPointer)
+ bv.Set(int32(*xoffset / int64(Widthptr))) // pointer in first slot (BitsPointer)
*xoffset += t.Width
case TARRAY:
@@ -966,7 +985,7 @@ func onebitlivepointermap(lv *Liveness, liveout bvec, vars []*Node, args bvec, l
var xoffset int64
for i := int32(0); ; i++ {
- i = bvnext(liveout, i)
+ i = liveout.Next(i)
if i < 0 {
break
}
@@ -1025,22 +1044,22 @@ func livenessprologue(lv *Liveness) {
if debuglive >= 3 {
printeffects(p, uevar, varkill, avarinit)
}
- bvor(bb.varkill, bb.varkill, varkill)
- bvandnot(bb.uevar, bb.uevar, varkill)
- bvor(bb.uevar, bb.uevar, uevar)
+ 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.
- bvresetall(varkill)
+ varkill.Clear()
for p := bb.first; ; p = p.Link {
progeffects(p, lv.vars, uevar, varkill, avarinit)
if debuglive >= 3 {
printeffects(p, uevar, varkill, avarinit)
}
- bvandnot(bb.avarinit, bb.avarinit, varkill)
- bvor(bb.avarinit, bb.avarinit, avarinit)
+ bb.avarinit.AndNot(bb.avarinit, varkill)
+ bb.avarinit.Or(bb.avarinit, avarinit)
if p == bb.last {
break
}
@@ -1063,41 +1082,41 @@ func livenesssolve(lv *Liveness) {
// avarinitany says the addressed var is initialized along some path reaching the block exit.
for i, bb := range lv.cfg {
if i == 0 {
- bvcopy(bb.avarinitall, bb.avarinit)
+ bb.avarinitall.Copy(bb.avarinit)
} else {
- bvresetall(bb.avarinitall)
- bvnot(bb.avarinitall)
+ bb.avarinitall.Clear()
+ bb.avarinitall.Not()
}
- bvcopy(bb.avarinitany, bb.avarinit)
+ bb.avarinitany.Copy(bb.avarinit)
}
for change := true; change; {
change = false
for _, bb := range lv.cfg {
- bvresetall(any)
- bvresetall(all)
+ any.Clear()
+ all.Clear()
for j, pred := range bb.pred {
if j == 0 {
- bvcopy(any, pred.avarinitany)
- bvcopy(all, pred.avarinitall)
+ any.Copy(pred.avarinitany)
+ all.Copy(pred.avarinitall)
} else {
- bvor(any, any, pred.avarinitany)
- bvand(all, all, pred.avarinitall)
+ any.Or(any, pred.avarinitany)
+ all.And(all, pred.avarinitall)
}
}
- bvandnot(any, any, bb.varkill)
- bvandnot(all, all, bb.varkill)
- bvor(any, any, bb.avarinit)
- bvor(all, all, bb.avarinit)
- if !bveq(any, bb.avarinitany) {
+ 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) {
change = true
- bvcopy(bb.avarinitany, any)
+ bb.avarinitany.Copy(any)
}
- if !bveq(all, bb.avarinitall) {
+ if !all.Eq(bb.avarinitall) {
change = true
- bvcopy(bb.avarinitall, all)
+ bb.avarinitall.Copy(all)
}
}
}
@@ -1118,14 +1137,14 @@ func livenesssolve(lv *Liveness) {
// if it is live on input to some successor.
//
// out[b] = \bigcup_{s \in succ[b]} in[s]
- bvresetall(newliveout)
+ newliveout.Clear()
for _, succ := range bb.succ {
- bvor(newliveout, newliveout, succ.livein)
+ newliveout.Or(newliveout, succ.livein)
}
- if !bveq(bb.liveout, newliveout) {
+ if !bb.liveout.Eq(newliveout) {
change = true
- bvcopy(bb.liveout, newliveout)
+ bb.liveout.Copy(newliveout)
}
// A variable is live on input to this block
@@ -1133,9 +1152,9 @@ func livenesssolve(lv *Liveness) {
// not set by the code in this block.
//
// in[b] = uevar[b] \cup (out[b] \setminus varkill[b])
- bvandnot(newlivein, bb.liveout, bb.varkill)
+ newlivein.AndNot(bb.liveout, bb.varkill)
- bvor(bb.livein, newlivein, bb.uevar)
+ bb.livein.Or(newlivein, bb.uevar)
}
}
}
@@ -1146,14 +1165,14 @@ func islive(n *Node, args bvec, locals bvec) bool {
switch n.Class {
case PPARAM, PPARAMOUT:
for i := 0; int64(i) < n.Type.Width/int64(Widthptr); i++ {
- if bvget(args, int32(n.Xoffset/int64(Widthptr)+int64(i))) != 0 {
+ 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 bvget(locals, int32((n.Xoffset+stkptrsize)/int64(Widthptr)+int64(i))) != 0 {
+ if locals.Get(int32((n.Xoffset+stkptrsize)/int64(Widthptr) + int64(i))) {
return true
}
}
@@ -1173,17 +1192,18 @@ func livenessepilogue(lv *Liveness) {
avarinit := bvalloc(nvars)
any := bvalloc(nvars)
all := bvalloc(nvars)
- ambig := bvalloc(localswords())
+ pparamout := bvalloc(localswords())
- // Set ambig bit for the pointers to heap-allocated pparamout variables.
- // These are implicitly read by post-deferreturn code and thus must be
- // kept live throughout the function (if there is any defer that recovers).
+ // 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 {
if n.IsOutputParamHeapAddr() {
n.Name.Needzero = true
xoffset := n.Xoffset + stkptrsize
- onebitwalktype1(n.Type, &xoffset, ambig)
+ onebitwalktype1(n.Type, &xoffset, pparamout)
}
}
}
@@ -1192,17 +1212,17 @@ func livenessepilogue(lv *Liveness) {
// Compute avarinitany and avarinitall for entry to block.
// This duplicates information known during livenesssolve
// but avoids storing two more vectors for each block.
- bvresetall(any)
+ any.Clear()
- bvresetall(all)
+ all.Clear()
for j := 0; j < len(bb.pred); j++ {
pred := bb.pred[j]
if j == 0 {
- bvcopy(any, pred.avarinitany)
- bvcopy(all, pred.avarinitall)
+ any.Copy(pred.avarinitany)
+ all.Copy(pred.avarinitall)
} else {
- bvor(any, any, pred.avarinitany)
- bvand(all, all, pred.avarinitall)
+ any.Or(any, pred.avarinitany)
+ all.And(all, pred.avarinitall)
}
}
@@ -1211,35 +1231,30 @@ func livenessepilogue(lv *Liveness) {
// Seed the maps with information about the addrtaken variables.
for p := bb.first; ; p = p.Link {
progeffects(p, lv.vars, uevar, varkill, avarinit)
- bvandnot(any, any, varkill)
- bvandnot(all, all, varkill)
- bvor(any, any, avarinit)
- bvor(all, all, avarinit)
+ 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.
- bvresetall(livein)
+ livein.Clear()
- bvandnot(liveout, any, all)
- if !bvisempty(liveout) {
+ liveout.AndNot(any, all)
+ if !liveout.IsEmpty() {
for pos := int32(0); pos < liveout.n; pos++ {
- if bvget(liveout, pos) == 0 {
+ if !liveout.Get(pos) {
continue
}
- bvset(all, pos) // silence future warnings in this block
+ 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: %v is ambiguously live", Curfn.Func.Nname, Nconv(n, FmtLong))
+ Warnl(p.Lineno, "%v: %L is ambiguously live", Curfn.Func.Nname, n)
}
-
- // Record in 'ambiguous' bitmap.
- xoffset := n.Xoffset + stkptrsize
-
- onebitwalktype1(n.Type, &xoffset, ambig)
}
}
}
@@ -1296,7 +1311,7 @@ func livenessepilogue(lv *Liveness) {
Fatalf("livenessepilogue")
}
- bvcopy(livein, bb.liveout)
+ 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
@@ -1304,9 +1319,9 @@ func livenessepilogue(lv *Liveness) {
// Propagate liveness information
progeffects(p, lv.vars, uevar, varkill, avarinit)
- bvcopy(liveout, livein)
- bvandnot(livein, liveout, varkill)
- bvor(livein, livein, uevar)
+ 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)
@@ -1324,12 +1339,12 @@ func livenessepilogue(lv *Liveness) {
// input parameters.
if p.As == obj.ATEXT {
for j := int32(0); j < liveout.n; j++ {
- if bvget(liveout, j) == 0 {
+ if !liveout.Get(j) {
continue
}
n := lv.vars[j]
if n.Class != PPARAM {
- yyerrorl(p.Lineno, "internal error: %v %v recorded as live on entry, p.Pc=%v", Curfn.Func.Nname, Nconv(n, FmtLong), p.Pc)
+ yyerrorl(p.Lineno, "internal error: %v %L recorded as live on entry, p.Pc=%v", Curfn.Func.Nname, n, p.Pc)
}
}
}
@@ -1340,11 +1355,9 @@ func livenessepilogue(lv *Liveness) {
locals := lv.livepointers[pos]
onebitlivepointermap(lv, liveout, lv.vars, args, locals)
- // Ambiguously live variables are zeroed immediately after
- // function entry. Mark them live for all the non-entry bitmaps
- // so that GODEBUG=gcdead=1 mode does not poison them.
+ // Mark pparamout variables (as described above)
if p.As == obj.ACALL {
- bvor(locals, locals, ambig)
+ locals.Or(locals, pparamout)
}
// Show live pointer bitmaps.
@@ -1423,7 +1436,7 @@ func livenessepilogue(lv *Liveness) {
}
}
- Flusherrors()
+ flusherrors()
}
// FNV-1 hash function constants.
@@ -1496,7 +1509,7 @@ func livenesscompact(lv *Liveness) {
}
jlocal := lv.livepointers[j]
jarg := lv.argslivepointers[j]
- if bveq(local, jlocal) && bveq(arg, jarg) {
+ if local.Eq(jlocal) && arg.Eq(jarg) {
remap[i] = j
goto Next
}
@@ -1539,7 +1552,7 @@ func livenesscompact(lv *Liveness) {
func printbitset(printed bool, name string, vars []*Node, bits bvec) bool {
started := false
for i, n := range vars {
- if bvget(bits, int32(i)) == 0 {
+ if !bits.Get(int32(i)) {
continue
}
if !started {
@@ -1662,7 +1675,7 @@ func livenessprintdebug(lv *Liveness) {
// Dumps a slice of bitmaps to a symbol as a sequence of uint32 values. The
// first word dumped is the total number of bitmaps. The second word is the
// length of the bitmaps. All bitmaps are assumed to be of equal length. The
-// words that are followed are the raw bitmap words.
+// 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
@@ -1674,22 +1687,13 @@ func onebitwritesymbol(arr []bvec, sym *Sym) {
if bv.b == nil {
break
}
- for j := 0; int32(j) < bv.n; j += 32 {
- word := bv.b[j/32]
-
- // Runtime reads the bitmaps as byte arrays. Oblige.
- off = duint8(sym, off, uint8(word))
-
- off = duint8(sym, off, uint8(word>>8))
- off = duint8(sym, off, uint8(word>>16))
- off = duint8(sym, off, uint8(word>>24))
- }
+ 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.Dupok = true
+ ls.Set(obj.AttrDuplicateOK, true)
sv := obj.SymVer{Name: ls.Name, Version: 0}
ls2, ok := Ctxt.Hash[sv]
if ok {
diff --git a/src/cmd/compile/internal/gc/popt.go b/src/cmd/compile/internal/gc/popt.go
deleted file mode 100644
index 8e2a7ba..0000000
--- a/src/cmd/compile/internal/gc/popt.go
+++ /dev/null
@@ -1,1094 +0,0 @@
-// Derived from Inferno utils/6c/gc.h
-// http://code.google.com/p/inferno-os/source/browse/utils/6c/gc.h
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth at terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth at terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// Portions Copyright © 2009 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-// "Portable" optimizations.
-
-package gc
-
-import (
- "cmd/internal/obj"
- "fmt"
- "sort"
- "strings"
-)
-
-type OptStats struct {
- Ncvtreg int32
- Nspill int32
- Nreload int32
- Ndelmov int32
- Nvar int32
- Naddr int32
-}
-
-var Ostats OptStats
-
-var noreturn_symlist [10]*Sym
-
-// p is a call instruction. Does the call fail to return?
-func Noreturn(p *obj.Prog) bool {
- if noreturn_symlist[0] == nil {
- noreturn_symlist[0] = Pkglookup("panicindex", Runtimepkg)
- noreturn_symlist[1] = Pkglookup("panicslice", Runtimepkg)
- noreturn_symlist[2] = Pkglookup("throwinit", Runtimepkg)
- noreturn_symlist[3] = Pkglookup("gopanic", Runtimepkg)
- noreturn_symlist[4] = Pkglookup("panicwrap", Runtimepkg)
- noreturn_symlist[5] = Pkglookup("throwreturn", Runtimepkg)
- noreturn_symlist[6] = Pkglookup("selectgo", Runtimepkg)
- noreturn_symlist[7] = Pkglookup("block", Runtimepkg)
- }
-
- if p.To.Node == nil {
- return false
- }
- s := ((p.To.Node).(*Node)).Sym
- if s == nil {
- return false
- }
- for i := 0; noreturn_symlist[i] != nil; i++ {
- if s == noreturn_symlist[i] {
- return true
- }
- }
- return false
-}
-
-// JMP chasing and removal.
-//
-// The code generator depends on being able to write out jump
-// instructions that it can jump to now but fill in later.
-// the linker will resolve them nicely, but they make the code
-// longer and more difficult to follow during debugging.
-// Remove them.
-
-// what instruction does a JMP to p eventually land on?
-func chasejmp(p *obj.Prog, jmploop *int) *obj.Prog {
- n := 0
- for p != nil && p.As == obj.AJMP && p.To.Type == obj.TYPE_BRANCH {
- n++
- if n > 10 {
- *jmploop = 1
- break
- }
-
- p = p.To.Val.(*obj.Prog)
- }
-
- return p
-}
-
-// reuse reg pointer for mark/sweep state.
-// leave reg==nil at end because alive==nil.
-var alive interface{} = nil
-var dead interface{} = 1
-
-// mark all code reachable from firstp as alive
-func mark(firstp *obj.Prog) {
- for p := firstp; p != nil; p = p.Link {
- if p.Opt != dead {
- break
- }
- p.Opt = alive
- if p.As != obj.ACALL && p.To.Type == obj.TYPE_BRANCH && p.To.Val.(*obj.Prog) != nil {
- mark(p.To.Val.(*obj.Prog))
- }
- if p.As == obj.AJMP || p.As == obj.ARET || p.As == obj.AUNDEF {
- break
- }
- }
-}
-
-func fixjmp(firstp *obj.Prog) {
- if Debug['R'] != 0 && Debug['v'] != 0 {
- fmt.Printf("\nfixjmp\n")
- }
-
- // pass 1: resolve jump to jump, mark all code as dead.
- jmploop := 0
-
- for p := firstp; p != nil; p = p.Link {
- if Debug['R'] != 0 && Debug['v'] != 0 {
- fmt.Printf("%v\n", p)
- }
- if p.As != obj.ACALL && p.To.Type == obj.TYPE_BRANCH && p.To.Val.(*obj.Prog) != nil && p.To.Val.(*obj.Prog).As == obj.AJMP {
- if Debug['N'] == 0 {
- p.To.Val = chasejmp(p.To.Val.(*obj.Prog), &jmploop)
- if Debug['R'] != 0 && Debug['v'] != 0 {
- fmt.Printf("->%v\n", p)
- }
- }
- }
-
- p.Opt = dead
- }
- if Debug['R'] != 0 && Debug['v'] != 0 {
- fmt.Printf("\n")
- }
-
- // pass 2: mark all reachable code alive
- mark(firstp)
-
- // pass 3: delete dead code (mostly JMPs).
- var last *obj.Prog
-
- for p := firstp; p != nil; p = p.Link {
- if p.Opt == dead {
- if p.Link == nil && p.As == obj.ARET && last != nil && last.As != obj.ARET {
- // This is the final ARET, and the code so far doesn't have one.
- // Let it stay. The register allocator assumes that all live code in
- // the function can be traversed by starting at all the RET instructions
- // and following predecessor links. If we remove the final RET,
- // this assumption will not hold in the case of an infinite loop
- // at the end of a function.
- // Keep the RET but mark it dead for the liveness analysis.
- p.Mode = 1
- } else {
- if Debug['R'] != 0 && Debug['v'] != 0 {
- fmt.Printf("del %v\n", p)
- }
- continue
- }
- }
-
- if last != nil {
- last.Link = p
- }
- last = p
- }
-
- last.Link = nil
-
- // pass 4: elide JMP to next instruction.
- // only safe if there are no jumps to JMPs anymore.
- if jmploop == 0 && Debug['N'] == 0 {
- var last *obj.Prog
- for p := firstp; p != nil; p = p.Link {
- if p.As == obj.AJMP && p.To.Type == obj.TYPE_BRANCH && p.To.Val == p.Link {
- if Debug['R'] != 0 && Debug['v'] != 0 {
- fmt.Printf("del %v\n", p)
- }
- continue
- }
-
- if last != nil {
- last.Link = p
- }
- last = p
- }
-
- last.Link = nil
- }
-
- if Debug['R'] != 0 && Debug['v'] != 0 {
- fmt.Printf("\n")
- for p := firstp; p != nil; p = p.Link {
- fmt.Printf("%v\n", p)
- }
- fmt.Printf("\n")
- }
-}
-
-// Control flow analysis. The Flow structures hold predecessor and successor
-// information as well as basic loop analysis.
-//
-// graph = Flowstart(firstp, nil)
-// ... use flow graph ...
-// Flowend(graph) // free graph
-//
-// Typical uses of the flow graph are to iterate over all the flow-relevant instructions:
-//
-// for f := graph.Start; f != nil; f = f.Link {}
-//
-// or, given an instruction f, to iterate over all the predecessors, which is
-// f.P1 and this list:
-//
-// for f2 := f.P2; f2 != nil; f2 = f2.P2link {}
-//
-// The second argument (newData) to Flowstart specifies a func to create object
-// for every f.Data field, for use by the client.
-// If newData is nil, f.Data will be nil.
-
-type Graph struct {
- Start *Flow
- Num int
-
- // After calling flowrpo, rpo lists the flow nodes in reverse postorder,
- // and each non-dead Flow node f has g->rpo[f->rpo] == f.
- Rpo []*Flow
-}
-
-type Flow struct {
- Prog *obj.Prog // actual instruction
- P1 *Flow // predecessors of this instruction: p1,
- P2 *Flow // and then p2 linked though p2link.
- P2link *Flow
- S1 *Flow // successors of this instruction (at most two: s1 and s2).
- S2 *Flow
- Link *Flow // next instruction in function code
-
- Active int32 // usable by client
-
- Id int32 // sequence number in flow graph
- Rpo int32 // reverse post ordering
- Loop uint16 // x5 for every loop
- Refset bool // diagnostic generated
-
- Data interface{} // for use by client
-}
-
-var flowmark int
-
-// MaxFlowProg is the maximum size program (counted in instructions)
-// for which the flow code will build a graph. Functions larger than this limit
-// will not have flow graphs and consequently will not be optimized.
-const MaxFlowProg = 50000
-
-var ffcache []Flow // reusable []Flow, to reduce allocation
-
-func growffcache(n int) {
- if n > cap(ffcache) {
- n = (n * 5) / 4
- if n > MaxFlowProg {
- n = MaxFlowProg
- }
- ffcache = make([]Flow, n)
- }
- ffcache = ffcache[:n]
-}
-
-func Flowstart(firstp *obj.Prog, newData func() interface{}) *Graph {
- // Count and mark instructions to annotate.
- nf := 0
-
- for p := firstp; p != nil; p = p.Link {
- p.Opt = nil // should be already, but just in case
- Thearch.Proginfo(p)
- if p.Info.Flags&Skip != 0 {
- continue
- }
- p.Opt = &flowmark
- nf++
- }
-
- if nf == 0 {
- return nil
- }
-
- if nf >= MaxFlowProg {
- if Debug['v'] != 0 {
- Warn("%v is too big (%d instructions)", Curfn.Func.Nname.Sym, nf)
- }
- return nil
- }
-
- // Allocate annotations and assign to instructions.
- graph := new(Graph)
-
- growffcache(nf)
- ff := ffcache
- start := &ff[0]
- id := 0
- var last *Flow
- for p := firstp; p != nil; p = p.Link {
- if p.Opt == nil {
- continue
- }
- f := &ff[0]
- ff = ff[1:]
- p.Opt = f
- f.Prog = p
- if last != nil {
- last.Link = f
- }
- last = f
- if newData != nil {
- f.Data = newData()
- }
- f.Id = int32(id)
- id++
- }
-
- // Fill in pred/succ information.
- var f1 *Flow
- var p *obj.Prog
- for f := start; f != nil; f = f.Link {
- p = f.Prog
- if p.Info.Flags&Break == 0 {
- f1 = f.Link
- f.S1 = f1
- f1.P1 = f
- }
-
- if p.To.Type == obj.TYPE_BRANCH {
- if p.To.Val == nil {
- Fatalf("pnil %v", p)
- }
- f1 = p.To.Val.(*obj.Prog).Opt.(*Flow)
- if f1 == nil {
- Fatalf("fnil %v / %v", p, p.To.Val.(*obj.Prog))
- }
- if f1 == f {
- //fatal("self loop %v", p);
- continue
- }
-
- f.S2 = f1
- f.P2link = f1.P2
- f1.P2 = f
- }
- }
-
- graph.Start = start
- graph.Num = nf
- return graph
-}
-
-func Flowend(graph *Graph) {
- for f := graph.Start; f != nil; f = f.Link {
- f.Prog.Info.Flags = 0 // drop cached proginfo
- f.Prog.Opt = nil
- }
- clear := ffcache[:graph.Num]
- for i := range clear {
- clear[i] = Flow{}
- }
-}
-
-// find looping structure
-//
-// 1) find reverse postordering
-// 2) find approximate dominators,
-// the actual dominators if the flow graph is reducible
-// otherwise, dominators plus some other non-dominators.
-// See Matthew S. Hecht and Jeffrey D. Ullman,
-// "Analysis of a Simple Algorithm for Global Data Flow Problems",
-// Conf. Record of ACM Symp. on Principles of Prog. Langs, Boston, Massachusetts,
-// Oct. 1-3, 1973, pp. 207-217.
-// 3) find all nodes with a predecessor dominated by the current node.
-// such a node is a loop head.
-// recursively, all preds with a greater rpo number are in the loop
-func postorder(r *Flow, rpo2r []*Flow, n int32) int32 {
- r.Rpo = 1
- r1 := r.S1
- if r1 != nil && r1.Rpo == 0 {
- n = postorder(r1, rpo2r, n)
- }
- r1 = r.S2
- if r1 != nil && r1.Rpo == 0 {
- n = postorder(r1, rpo2r, n)
- }
- rpo2r[n] = r
- n++
- return n
-}
-
-func rpolca(idom []int32, rpo1 int32, rpo2 int32) int32 {
- if rpo1 == -1 {
- return rpo2
- }
- var t int32
- for rpo1 != rpo2 {
- if rpo1 > rpo2 {
- t = rpo2
- rpo2 = rpo1
- rpo1 = t
- }
-
- for rpo1 < rpo2 {
- t = idom[rpo2]
- if t >= rpo2 {
- Fatalf("bad idom")
- }
- rpo2 = t
- }
- }
-
- return rpo1
-}
-
-func doms(idom []int32, r int32, s int32) bool {
- for s > r {
- s = idom[s]
- }
- return s == r
-}
-
-func loophead(idom []int32, r *Flow) bool {
- src := r.Rpo
- if r.P1 != nil && doms(idom, src, r.P1.Rpo) {
- return true
- }
- for r = r.P2; r != nil; r = r.P2link {
- if doms(idom, src, r.Rpo) {
- return true
- }
- }
- return false
-}
-
-func loopmark(rpo2r **Flow, head int32, r *Flow) {
- if r.Rpo < head || r.Active == head {
- return
- }
- r.Active = head
- r.Loop += LOOP
- if r.P1 != nil {
- loopmark(rpo2r, head, r.P1)
- }
- for r = r.P2; r != nil; r = r.P2link {
- loopmark(rpo2r, head, r)
- }
-}
-
-func flowrpo(g *Graph) {
- g.Rpo = make([]*Flow, g.Num)
- idom := make([]int32, g.Num)
-
- for r1 := g.Start; r1 != nil; r1 = r1.Link {
- r1.Active = 0
- }
-
- rpo2r := g.Rpo
- d := postorder(g.Start, rpo2r, 0)
- nr := int32(g.Num)
- if d > nr {
- Fatalf("too many reg nodes %d %d", d, nr)
- }
- nr = d
- var r1 *Flow
- for i := int32(0); i < nr/2; i++ {
- r1 = rpo2r[i]
- rpo2r[i] = rpo2r[nr-1-i]
- rpo2r[nr-1-i] = r1
- }
-
- for i := int32(0); i < nr; i++ {
- rpo2r[i].Rpo = i
- }
-
- idom[0] = 0
- var me int32
- for i := int32(0); i < nr; i++ {
- r1 = rpo2r[i]
- me = r1.Rpo
- d = -1
-
- // rpo2r[r.Rpo] == r protects against considering dead code,
- // which has r.Rpo == 0.
- if r1.P1 != nil && rpo2r[r1.P1.Rpo] == r1.P1 && r1.P1.Rpo < me {
- d = r1.P1.Rpo
- }
- for r1 = r1.P2; r1 != nil; r1 = r1.P2link {
- if rpo2r[r1.Rpo] == r1 && r1.Rpo < me {
- d = rpolca(idom, d, r1.Rpo)
- }
- }
- idom[i] = d
- }
-
- for i := int32(0); i < nr; i++ {
- r1 = rpo2r[i]
- r1.Loop++
- if r1.P2 != nil && loophead(idom, r1) {
- loopmark(&rpo2r[0], i, r1)
- }
- }
-
- for r1 := g.Start; r1 != nil; r1 = r1.Link {
- r1.Active = 0
- }
-}
-
-func Uniqp(r *Flow) *Flow {
- r1 := r.P1
- if r1 == nil {
- r1 = r.P2
- if r1 == nil || r1.P2link != nil {
- return nil
- }
- } else if r.P2 != nil {
- return nil
- }
- return r1
-}
-
-func Uniqs(r *Flow) *Flow {
- r1 := r.S1
- if r1 == nil {
- r1 = r.S2
- if r1 == nil {
- return nil
- }
- } else if r.S2 != nil {
- return nil
- }
- return r1
-}
-
-// The compilers assume they can generate temporary variables
-// as needed to preserve the right semantics or simplify code
-// generation and the back end will still generate good code.
-// This results in a large number of ephemeral temporary variables.
-// Merge temps with non-overlapping lifetimes and equal types using the
-// greedy algorithm in Poletto and Sarkar, "Linear Scan Register Allocation",
-// ACM TOPLAS 1999.
-
-type TempVar struct {
- node *Node
- def *Flow // definition of temp var
- use *Flow // use list, chained through Flow.data
- merge *TempVar // merge var with this one
- start int64 // smallest Prog.pc in live range
- end int64 // largest Prog.pc in live range
- addr bool // address taken - no accurate end
- removed bool // removed from program
-}
-
-// startcmp sorts TempVars by start, then id, then symbol name.
-type startcmp []*TempVar
-
-func (x startcmp) Len() int { return len(x) }
-func (x startcmp) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
-func (x startcmp) Less(i, j int) bool {
- a := x[i]
- b := x[j]
-
- if a.start < b.start {
- return true
- }
- if a.start > b.start {
- return false
- }
-
- // Order what's left by id or symbol name,
- // just so that sort is forced into a specific ordering,
- // so that the result of the sort does not depend on
- // the sort implementation.
- if a.def != b.def {
- return int(a.def.Id-b.def.Id) < 0
- }
- if a.node != b.node {
- return a.node.Sym.Name < b.node.Sym.Name
- }
- return false
-}
-
-// Is n available for merging?
-func canmerge(n *Node) bool {
- return n.Class == PAUTO && strings.HasPrefix(n.Sym.Name, "autotmp")
-}
-
-func mergetemp(firstp *obj.Prog) {
- const (
- debugmerge = 0
- )
-
- g := Flowstart(firstp, nil)
- if g == nil {
- return
- }
-
- // Build list of all mergeable variables.
- var vars []*TempVar
- for _, n := range Curfn.Func.Dcl {
- if canmerge(n) {
- v := &TempVar{}
- vars = append(vars, v)
- n.SetOpt(v)
- v.node = n
- }
- }
-
- // Build list of uses.
- // We assume that the earliest reference to a temporary is its definition.
- // This is not true of variables in general but our temporaries are all
- // single-use (that's why we have so many!).
- for f := g.Start; f != nil; f = f.Link {
- p := f.Prog
- if p.From.Node != nil && ((p.From.Node).(*Node)).Opt() != nil && p.To.Node != nil && ((p.To.Node).(*Node)).Opt() != nil {
- Fatalf("double node %v", p)
- }
- var v *TempVar
- n, _ := p.From.Node.(*Node)
- if n != nil {
- v, _ = n.Opt().(*TempVar)
- }
- if v == nil {
- n, _ = p.To.Node.(*Node)
- if n != nil {
- v, _ = n.Opt().(*TempVar)
- }
- }
- if v != nil {
- if v.def == nil {
- v.def = f
- }
- f.Data = v.use
- v.use = f
- if n == p.From.Node && (p.Info.Flags&LeftAddr != 0) {
- v.addr = true
- }
- }
- }
-
- if debugmerge > 1 && Debug['v'] != 0 {
- Dumpit("before", g.Start, 0)
- }
-
- nkill := 0
-
- // Special case.
- for _, v := range vars {
- if v.addr {
- continue
- }
-
- // Used in only one instruction, which had better be a write.
- f := v.use
- if f != nil && f.Data.(*Flow) == nil {
- p := f.Prog
- if p.To.Node == v.node && (p.Info.Flags&RightWrite != 0) && p.Info.Flags&RightRead == 0 {
- p.As = obj.ANOP
- p.To = obj.Addr{}
- v.removed = true
- if debugmerge > 0 && Debug['v'] != 0 {
- fmt.Printf("drop write-only %v\n", v.node.Sym)
- }
- } else {
- Fatalf("temp used and not set: %v", p)
- }
- nkill++
- continue
- }
-
- // Written in one instruction, read in the next, otherwise unused,
- // no jumps to the next instruction. Happens mainly in 386 compiler.
- f = v.use
- if f != nil && f.Link == f.Data.(*Flow) && (f.Data.(*Flow)).Data.(*Flow) == nil && Uniqp(f.Link) == f {
- p := f.Prog
- p1 := f.Link.Prog
- const (
- SizeAny = SizeB | SizeW | SizeL | SizeQ | SizeF | SizeD
- )
- if p.From.Node == v.node && p1.To.Node == v.node && (p.Info.Flags&Move != 0) && (p.Info.Flags|p1.Info.Flags)&(LeftAddr|RightAddr) == 0 && p.Info.Flags&SizeAny == p1.Info.Flags&SizeAny {
- p1.From = p.From
- Thearch.Excise(f)
- v.removed = true
- if debugmerge > 0 && Debug['v'] != 0 {
- fmt.Printf("drop immediate-use %v\n", v.node.Sym)
- }
- }
-
- nkill++
- continue
- }
- }
-
- // Traverse live range of each variable to set start, end.
- // Each flood uses a new value of gen so that we don't have
- // to clear all the r.Active words after each variable.
- gen := uint32(0)
-
- for _, v := range vars {
- gen++
- for f := v.use; f != nil; f = f.Data.(*Flow) {
- mergewalk(v, f, gen)
- }
- if v.addr {
- gen++
- for f := v.use; f != nil; f = f.Data.(*Flow) {
- varkillwalk(v, f, gen)
- }
- }
- }
-
- // Sort variables by start.
- bystart := make([]*TempVar, len(vars))
- copy(bystart, vars)
- sort.Sort(startcmp(bystart))
-
- // List of in-use variables, sorted by end, so that the ones that
- // will last the longest are the earliest ones in the array.
- // The tail inuse[nfree:] holds no-longer-used variables.
- // In theory we should use a sorted tree so that insertions are
- // guaranteed O(log n) and then the loop is guaranteed O(n log n).
- // In practice, it doesn't really matter.
- inuse := make([]*TempVar, len(bystart))
-
- ninuse := 0
- nfree := len(bystart)
- for _, v := range bystart {
- if debugmerge > 0 && Debug['v'] != 0 {
- fmt.Printf("consider %v: removed=%t\n", Nconv(v.node, FmtSharp), v.removed)
- }
-
- if v.removed {
- continue
- }
-
- // Expire no longer in use.
- for ninuse > 0 && inuse[ninuse-1].end < v.start {
- ninuse--
- nfree--
- inuse[nfree] = inuse[ninuse]
- }
-
- if debugmerge > 0 && Debug['v'] != 0 {
- fmt.Printf("consider %v: removed=%t nfree=%d nvar=%d\n", Nconv(v.node, FmtSharp), v.removed, nfree, len(bystart))
- }
-
- // Find old temp to reuse if possible.
- t := v.node.Type
-
- for j := nfree; j < len(inuse); j++ {
- v1 := inuse[j]
- if debugmerge > 0 && Debug['v'] != 0 {
- fmt.Printf("consider %v: maybe %v: type=%v,%v addrtaken=%v,%v\n", Nconv(v.node, FmtSharp), Nconv(v1.node, FmtSharp), t, v1.node.Type, v.node.Addrtaken, v1.node.Addrtaken)
- }
-
- // Require the types to match but also require the addrtaken bits to match.
- // If a variable's address is taken, that disables registerization for the individual
- // words of the variable (for example, the base,len,cap of a slice).
- // We don't want to merge a non-addressed var with an addressed one and
- // inhibit registerization of the former.
- if Eqtype(t, v1.node.Type) && v.node.Addrtaken == v1.node.Addrtaken {
- inuse[j] = inuse[nfree]
- nfree++
- if v1.merge != nil {
- v.merge = v1.merge
- } else {
- v.merge = v1
- }
- nkill++
- break
- }
- }
-
- // Sort v into inuse.
- j := ninuse
- ninuse++
-
- for j > 0 && inuse[j-1].end < v.end {
- inuse[j] = inuse[j-1]
- j--
- }
-
- inuse[j] = v
- }
-
- if debugmerge > 0 && Debug['v'] != 0 {
- fmt.Printf("%v [%d - %d]\n", Curfn.Func.Nname.Sym, len(vars), nkill)
- for _, v := range vars {
- fmt.Printf("var %v %v %d-%d", Nconv(v.node, FmtSharp), v.node.Type, v.start, v.end)
- if v.addr {
- fmt.Printf(" addr=true")
- }
- if v.removed {
- fmt.Printf(" removed=true")
- }
- if v.merge != nil {
- fmt.Printf(" merge %v", Nconv(v.merge.node, FmtSharp))
- }
- if v.start == v.end && v.def != nil {
- fmt.Printf(" %v", v.def.Prog)
- }
- fmt.Printf("\n")
- }
-
- if debugmerge > 1 && Debug['v'] != 0 {
- Dumpit("after", g.Start, 0)
- }
- }
-
- // Update node references to use merged temporaries.
- for f := g.Start; f != nil; f = f.Link {
- p := f.Prog
- n, _ := p.From.Node.(*Node)
- if n != nil {
- v, _ := n.Opt().(*TempVar)
- if v != nil && v.merge != nil {
- p.From.Node = v.merge.node
- }
- }
- n, _ = p.To.Node.(*Node)
- if n != nil {
- v, _ := n.Opt().(*TempVar)
- if v != nil && v.merge != nil {
- p.To.Node = v.merge.node
- }
- }
- }
-
- // Delete merged nodes from declaration list.
- dcl := make([]*Node, 0, len(Curfn.Func.Dcl)-nkill)
- for _, n := range Curfn.Func.Dcl {
- v, _ := n.Opt().(*TempVar)
- if v != nil && (v.merge != nil || v.removed) {
- continue
- }
- dcl = append(dcl, n)
- }
- Curfn.Func.Dcl = dcl
-
- // Clear aux structures.
- for _, v := range vars {
- v.node.SetOpt(nil)
- }
-
- Flowend(g)
-}
-
-func mergewalk(v *TempVar, f0 *Flow, gen uint32) {
- var p *obj.Prog
- var f1 *Flow
-
- for f1 = f0; f1 != nil; f1 = f1.P1 {
- if uint32(f1.Active) == gen {
- break
- }
- f1.Active = int32(gen)
- p = f1.Prog
- if v.end < p.Pc {
- v.end = p.Pc
- }
- if f1 == v.def {
- v.start = p.Pc
- break
- }
- }
-
- var f2 *Flow
- for f := f0; f != f1; f = f.P1 {
- for f2 = f.P2; f2 != nil; f2 = f2.P2link {
- mergewalk(v, f2, gen)
- }
- }
-}
-
-func varkillwalk(v *TempVar, f0 *Flow, gen uint32) {
- var p *obj.Prog
- var f1 *Flow
-
- for f1 = f0; f1 != nil; f1 = f1.S1 {
- if uint32(f1.Active) == gen {
- break
- }
- f1.Active = int32(gen)
- p = f1.Prog
- if v.end < p.Pc {
- v.end = p.Pc
- }
- if v.start > p.Pc {
- v.start = p.Pc
- }
- if p.As == obj.ARET || (p.As == obj.AVARKILL && p.To.Node == v.node) {
- break
- }
- }
-
- for f := f0; f != f1; f = f.S1 {
- varkillwalk(v, f.S2, gen)
- }
-}
-
-// Eliminate redundant nil pointer checks.
-//
-// The code generation pass emits a CHECKNIL for every possibly nil pointer.
-// This pass removes a CHECKNIL if every predecessor path has already
-// checked this value for nil.
-//
-// Simple backwards flood from check to definition.
-// Run prog loop backward from end of program to beginning to avoid quadratic
-// behavior removing a run of checks.
-//
-// Assume that stack variables with address not taken can be loaded multiple times
-// from memory without being rechecked. Other variables need to be checked on
-// each load.
-
-var killed int // f.Data is either nil or &killed
-
-func nilopt(firstp *obj.Prog) {
- g := Flowstart(firstp, nil)
- if g == nil {
- return
- }
-
- if Debug_checknil > 1 { // || strcmp(curfn->nname->sym->name, "f1") == 0
- Dumpit("nilopt", g.Start, 0)
- }
-
- ncheck := 0
- nkill := 0
- var p *obj.Prog
- for f := g.Start; f != nil; f = f.Link {
- p = f.Prog
- if p.As != obj.ACHECKNIL || !Thearch.Regtyp(&p.From) {
- continue
- }
- ncheck++
- if Thearch.Stackaddr(&p.From) {
- if Debug_checknil != 0 && p.Lineno > 1 {
- Warnl(p.Lineno, "removed nil check of SP address")
- }
- f.Data = &killed
- continue
- }
-
- nilwalkfwd(f)
- if f.Data != nil {
- if Debug_checknil != 0 && p.Lineno > 1 {
- Warnl(p.Lineno, "removed nil check before indirect")
- }
- continue
- }
-
- nilwalkback(f)
- if f.Data != nil {
- if Debug_checknil != 0 && p.Lineno > 1 {
- Warnl(p.Lineno, "removed repeated nil check")
- }
- continue
- }
- }
-
- for f := g.Start; f != nil; f = f.Link {
- if f.Data != nil {
- nkill++
- Thearch.Excise(f)
- }
- }
-
- Flowend(g)
-
- if Debug_checknil > 1 {
- fmt.Printf("%v: removed %d of %d nil checks\n", Curfn.Func.Nname.Sym, nkill, ncheck)
- }
-}
-
-func nilwalkback(fcheck *Flow) {
- for f := fcheck; f != nil; f = Uniqp(f) {
- p := f.Prog
- if (p.Info.Flags&RightWrite != 0) && Thearch.Sameaddr(&p.To, &fcheck.Prog.From) {
- // Found initialization of value we're checking for nil.
- // without first finding the check, so this one is unchecked.
- return
- }
-
- if f != fcheck && p.As == obj.ACHECKNIL && Thearch.Sameaddr(&p.From, &fcheck.Prog.From) {
- fcheck.Data = &killed
- return
- }
- }
-}
-
-// Here is a more complex version that scans backward across branches.
-// It assumes fcheck->kill = 1 has been set on entry, and its job is to find a reason
-// to keep the check (setting fcheck->kill = 0).
-// It doesn't handle copying of aggregates as well as I would like,
-// nor variables with their address taken,
-// and it's too subtle to turn on this late in Go 1.2. Perhaps for Go 1.3.
-/*
-for(f1 = f0; f1 != nil; f1 = f1->p1) {
- if(f1->active == gen)
- break;
- f1->active = gen;
- p = f1->prog;
-
- // If same check, stop this loop but still check
- // alternate predecessors up to this point.
- if(f1 != fcheck && p->as == ACHECKNIL && thearch.sameaddr(&p->from, &fcheck->prog->from))
- break;
-
- if((p.Info.flags & RightWrite) && thearch.sameaddr(&p->to, &fcheck->prog->from)) {
- // Found initialization of value we're checking for nil.
- // without first finding the check, so this one is unchecked.
- fcheck->kill = 0;
- return;
- }
-
- if(f1->p1 == nil && f1->p2 == nil) {
- print("lost pred for %v\n", fcheck->prog);
- for(f1=f0; f1!=nil; f1=f1->p1) {
- thearch.proginfo(&info, f1->prog);
- print("\t%v %d %d %D %D\n", r1->prog, info.flags&RightWrite, thearch.sameaddr(&f1->prog->to, &fcheck->prog->from), &f1->prog->to, &fcheck->prog->from);
- }
- fatal("lost pred trail");
- }
-}
-
-for(f = f0; f != f1; f = f->p1)
- for(f2 = f->p2; f2 != nil; f2 = f2->p2link)
- nilwalkback(fcheck, f2, gen);
-*/
-
-func nilwalkfwd(fcheck *Flow) {
- // If the path down from rcheck dereferences the address
- // (possibly with a small offset) before writing to memory
- // and before any subsequent checks, it's okay to wait for
- // that implicit check. Only consider this basic block to
- // avoid problems like:
- // _ = *x // should panic
- // for {} // no writes but infinite loop may be considered visible
-
- var last *Flow
- for f := Uniqs(fcheck); f != nil; f = Uniqs(f) {
- p := f.Prog
- if (p.Info.Flags&LeftRead != 0) && Thearch.Smallindir(&p.From, &fcheck.Prog.From) {
- fcheck.Data = &killed
- return
- }
-
- if (p.Info.Flags&(RightRead|RightWrite) != 0) && Thearch.Smallindir(&p.To, &fcheck.Prog.From) {
- fcheck.Data = &killed
- return
- }
-
- // Stop if another nil check happens.
- if p.As == obj.ACHECKNIL {
- return
- }
-
- // Stop if value is lost.
- if (p.Info.Flags&RightWrite != 0) && Thearch.Sameaddr(&p.To, &fcheck.Prog.From) {
- return
- }
-
- // Stop if memory write.
- if (p.Info.Flags&RightWrite != 0) && !Thearch.Regtyp(&p.To) {
- return
- }
-
- // Stop if we jump backward.
- if last != nil && f.Id <= last.Id {
- return
- }
- last = f
- }
-}
diff --git a/src/cmd/compile/internal/gc/racewalk.go b/src/cmd/compile/internal/gc/racewalk.go
index ad2bba9..bfb82b9 100644
--- a/src/cmd/compile/internal/gc/racewalk.go
+++ b/src/cmd/compile/internal/gc/racewalk.go
@@ -69,9 +69,10 @@ func instrument(fn *Node) {
nodpc.Type = Types[TUINTPTR]
nodpc.Xoffset = int64(-Widthptr)
nd := mkcall("racefuncenter", nil, nil, &nodpc)
- fn.Func.Enter.Set(append([]*Node{nd}, fn.Func.Enter.Slice()...))
+ fn.Func.Enter.Prepend(nd)
nd = mkcall("racefuncexit", nil, nil)
fn.Func.Exit.Append(nd)
+ fn.Func.Dcl = append(fn.Func.Dcl, &nodpc)
}
if Debug['W'] != 0 {
@@ -144,36 +145,21 @@ func instrumentnode(np **Node, init *Nodes, wr int, skip int) {
goto ret
case OBLOCK:
- var out []*Node
ls := n.List.Slice()
- for i := 0; i < len(ls); i++ {
- switch ls[i].Op {
- case OCALLFUNC, OCALLMETH, OCALLINTER:
- instrumentnode(&ls[i], &ls[i].Ninit, 0, 0)
- out = append(out, ls[i])
- // Scan past OAS nodes copying results off stack.
- // Those must not be instrumented, because the
- // instrumentation calls will smash the results.
- // The assignments are to temporaries, so they cannot
- // be involved in races and need not be instrumented.
- for i+1 < len(ls) && ls[i+1].Op == OAS && iscallret(ls[i+1].Right) {
- i++
- out = append(out, ls[i])
- }
- default:
- var outn Nodes
- outn.Set(out)
- instrumentnode(&ls[i], &outn, 0, 0)
- if ls[i].Op != OAS && ls[i].Op != OASWB && ls[i].Op != OAS2FUNC || ls[i].Ninit.Len() == 0 {
- out = append(outn.Slice(), ls[i])
- } else {
- // Splice outn onto end of ls[i].Ninit
- ls[i].Ninit.AppendNodes(&outn)
- out = append(out, ls[i])
- }
+ afterCall := false
+ for i := range ls {
+ op := ls[i].Op
+ // Scan past OAS nodes copying results off stack.
+ // Those must not be instrumented, because the
+ // instrumentation calls will smash the results.
+ // The assignments are to temporaries, so they cannot
+ // be involved in races and need not be instrumented.
+ if afterCall && op == OAS && iscallret(ls[i].Right) {
+ continue
}
+ instrumentnode(&ls[i], &ls[i].Ninit, 0, 0)
+ afterCall = (op == OCALLFUNC || op == OCALLMETH || op == OCALLINTER)
}
- n.List.Set(out)
goto ret
case ODEFER:
@@ -188,7 +174,7 @@ func instrumentnode(np **Node, init *Nodes, wr int, skip int) {
instrumentnode(&n.Left, init, 0, 0)
goto ret
- // Instrument dst argument of runtime.writebarrier* calls
+ // Instrument dst argument of runtime.writebarrier* calls
// as we do not instrument runtime code.
// typedslicecopy is instrumented in runtime.
case OCALLFUNC:
@@ -229,9 +215,9 @@ func instrumentnode(np **Node, init *Nodes, wr int, skip int) {
case OSPTR, OLEN, OCAP:
instrumentnode(&n.Left, init, 0, 0)
if n.Left.Type.IsMap() {
- n1 := Nod(OCONVNOP, n.Left, nil)
- n1.Type = Ptrto(Types[TUINT8])
- n1 = Nod(OIND, n1, nil)
+ n1 := nod(OCONVNOP, n.Left, nil)
+ n1.Type = ptrto(Types[TUINT8])
+ n1 = nod(OIND, n1, nil)
n1 = typecheck(n1, Erv)
callinstr(&n1, init, 0, skip)
}
@@ -314,11 +300,6 @@ func instrumentnode(np **Node, init *Nodes, wr int, skip int) {
n.SetSliceBounds(low, high, max)
goto ret
- case OKEY:
- instrumentnode(&n.Left, init, 0, 0)
- instrumentnode(&n.Right, init, 0, 0)
- goto ret
-
case OADDR:
instrumentnode(&n.Left, init, 0, 1)
goto ret
@@ -329,7 +310,20 @@ func instrumentnode(np **Node, init *Nodes, wr int, skip int) {
goto ret
- case OITAB:
+ case OITAB, OIDATA:
+ instrumentnode(&n.Left, init, 0, 0)
+ goto ret
+
+ case OSTRARRAYBYTETMP:
+ instrumentnode(&n.Left, init, 0, 0)
+ goto ret
+
+ case OAS2DOTTYPE:
+ instrumentnode(&n.Left, init, 1, 0)
+ instrumentnode(&n.Right, init, 0, 0)
+ goto ret
+
+ case ODOTTYPE, ODOTTYPE2:
instrumentnode(&n.Left, init, 0, 0)
goto ret
@@ -360,31 +354,29 @@ func instrumentnode(np **Node, init *Nodes, wr int, skip int) {
// lowered to call
OCMPSTR,
OADDSTR,
- ODOTTYPE,
- ODOTTYPE2,
- OAS2DOTTYPE,
OCALLPART,
// lowered to PTRLIT
OCLOSURE, // lowered to PTRLIT
ORANGE, // lowered to ordinary for loop
OARRAYLIT, // lowered to assignments
+ OSLICELIT,
OMAPLIT,
OSTRUCTLIT,
OAS2,
OAS2RECV,
OAS2MAPR,
OASOP:
- Yyerror("instrument: %v must be lowered by now", n.Op)
+ 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)
+ yyerror("instrument: %v cannot exist now", n.Op)
goto ret
case OGETG:
- Yyerror("instrument: OGETG can happen only in runtime which we don't instrument")
+ yyerror("instrument: OGETG can happen only in runtime which we don't instrument")
goto ret
case OFOR:
@@ -421,7 +413,7 @@ func instrumentnode(np **Node, init *Nodes, wr int, skip int) {
OCHECKNIL, // always followed by a read.
OCLOSUREVAR, // immutable pointer to captured variable
ODOTMETH, // either part of CALLMETH or CALLPART (lowered to PTRLIT)
- OINDREG, // at this stage, only n(SP) nodes from nodarg
+ OINDREGSP, // at this stage, only n(SP) nodes from nodarg
ODCL, // declarations (without value) cannot be races
ODCLCONST,
ODCLTYPE,
@@ -451,7 +443,7 @@ func isartificial(n *Node) bool {
}
// autotmp's are always local
- if strings.HasPrefix(n.Sym.Name, "autotmp_") {
+ if n.IsAutoTmp() {
return true
}
@@ -472,8 +464,8 @@ func isartificial(n *Node) bool {
func callinstr(np **Node, init *Nodes, wr int, skip int) bool {
n := *np
- //print("callinstr for %+N [ %O ] etype=%E class=%d\n",
- // n, n->op, n->type ? n->type->etype : -1, n->class);
+ //fmt.Printf("callinstr for %v [ %v ] etype=%v class=%v\n",
+ // n, n.Op, n.Type.Etype, n.Class)
if skip != 0 || n.Type == nil || n.Type.Etype >= TIDEAL {
return false
@@ -517,7 +509,7 @@ func callinstr(np **Node, init *Nodes, wr int, skip int) bool {
if w == BADWIDTH {
Fatalf("instrument: %v badwidth", t)
}
- f = mkcall(name, nil, init, uintptraddr(n), Nodintconst(w))
+ f = mkcall(name, nil, init, uintptraddr(n), nodintconst(w))
} else if flag_race && (t.IsStruct() || t.IsArray()) {
name := "racereadrange"
if wr != 0 {
@@ -529,7 +521,7 @@ func callinstr(np **Node, init *Nodes, wr int, skip int) bool {
if w == BADWIDTH {
Fatalf("instrument: %v badwidth", t)
}
- f = mkcall(name, nil, init, uintptraddr(n), Nodintconst(w))
+ f = mkcall(name, nil, init, uintptraddr(n), nodintconst(w))
} else if flag_race {
name := "raceread"
if wr != 0 {
@@ -577,7 +569,7 @@ func makeaddable(n *Node) {
}
func uintptraddr(n *Node) *Node {
- r := Nod(OADDR, n, nil)
+ r := nod(OADDR, n, nil)
r.Bounded = true
r = conv(r, Types[TUNSAFEPTR])
r = conv(r, Types[TUINTPTR])
@@ -585,13 +577,13 @@ func uintptraddr(n *Node) *Node {
}
func detachexpr(n *Node, init *Nodes) *Node {
- addr := Nod(OADDR, n, nil)
- l := temp(Ptrto(n.Type))
- as := Nod(OAS, l, addr)
+ addr := nod(OADDR, n, nil)
+ l := temp(ptrto(n.Type))
+ as := nod(OAS, l, addr)
as = typecheck(as, Etop)
as = walkexpr(as, init)
init.Append(as)
- ind := Nod(OIND, l, nil)
+ ind := nod(OIND, l, nil)
ind = typecheck(ind, Erv)
ind = walkexpr(ind, init)
return ind
@@ -637,7 +629,7 @@ func appendinit(np **Node, init Nodes) {
// There may be multiple refs to this node;
// introduce OCONVNOP to hold init list.
case ONAME, OLITERAL:
- n = Nod(OCONVNOP, n, nil)
+ n = nod(OCONVNOP, n, nil)
n.Type = n.Left.Type
n.Typecheck = 1
diff --git a/src/cmd/compile/internal/gc/range.go b/src/cmd/compile/internal/gc/range.go
index 9d3f79c..b590474 100644
--- a/src/cmd/compile/internal/gc/range.go
+++ b/src/cmd/compile/internal/gc/range.go
@@ -4,6 +4,8 @@
package gc
+import "unicode/utf8"
+
// range
func typecheckrange(n *Node) {
var toomany int
@@ -46,7 +48,7 @@ func typecheckrange(n *Node) {
toomany = 0
switch t.Etype {
default:
- Yyerror("cannot range over %v", Nconv(n.Right, FmtLong))
+ yyerror("cannot range over %L", n.Right)
goto out
case TARRAY, TSLICE:
@@ -59,7 +61,7 @@ func typecheckrange(n *Node) {
case TCHAN:
if !t.ChanDir().CanRecv() {
- Yyerror("invalid operation: range %v (receive from send-only type %v)", n.Right, n.Right.Type)
+ yyerror("invalid operation: range %v (receive from send-only type %v)", n.Right, n.Right.Type)
goto out
}
@@ -75,7 +77,7 @@ func typecheckrange(n *Node) {
}
if n.List.Len() > 2 || toomany != 0 {
- Yyerror("too many variables in range")
+ yyerror("too many variables in range")
}
v1 = nil
@@ -102,7 +104,7 @@ func typecheckrange(n *Node) {
if v1.Name != nil && v1.Name.Defn == n {
v1.Type = t1
} else if v1.Type != nil && assignop(t1, v1.Type, &why) == 0 {
- Yyerror("cannot assign type %v to %v in range%s", t1, Nconv(v1, FmtLong), why)
+ yyerror("cannot assign type %v to %L in range%s", t1, v1, why)
}
checkassign(n, v1)
}
@@ -111,7 +113,7 @@ func typecheckrange(n *Node) {
if v2.Name != nil && v2.Name.Defn == n {
v2.Type = t2
} else if v2.Type != nil && assignop(t2, v2.Type, &why) == 0 {
- Yyerror("cannot assign type %v to %v in range%s", t2, Nconv(v2, FmtLong), why)
+ yyerror("cannot assign type %v to %L in range%s", t2, v2, why)
}
checkassign(n, v2)
}
@@ -177,25 +179,25 @@ func walkrange(n *Node) {
hn := temp(Types[TINT])
var hp *Node
- init = append(init, Nod(OAS, hv1, nil))
- init = append(init, Nod(OAS, hn, Nod(OLEN, ha, nil)))
+ init = append(init, nod(OAS, hv1, nil))
+ init = append(init, nod(OAS, hn, nod(OLEN, ha, nil)))
if v2 != nil {
- hp = temp(Ptrto(n.Type.Elem()))
- tmp := Nod(OINDEX, ha, Nodintconst(0))
+ hp = temp(ptrto(n.Type.Elem()))
+ tmp := nod(OINDEX, ha, nodintconst(0))
tmp.Bounded = true
- init = append(init, Nod(OAS, hp, Nod(OADDR, tmp, nil)))
+ init = append(init, nod(OAS, hp, nod(OADDR, tmp, nil)))
}
- n.Left = Nod(OLT, hv1, hn)
- n.Right = Nod(OAS, hv1, Nod(OADD, hv1, Nodintconst(1)))
+ n.Left = nod(OLT, hv1, hn)
+ n.Right = nod(OAS, hv1, nod(OADD, hv1, nodintconst(1)))
if v1 == nil {
body = nil
} else if v2 == nil {
- body = []*Node{Nod(OAS, v1, hv1)}
+ body = []*Node{nod(OAS, v1, hv1)}
} else {
- a := Nod(OAS2, nil, nil)
+ a := nod(OAS2, nil, nil)
a.List.Set([]*Node{v1, v2})
- a.Rlist.Set([]*Node{hv1, Nod(OIND, hp, nil)})
+ a.Rlist.Set([]*Node{hv1, nod(OIND, hp, nil)})
body = []*Node{a}
// Advance pointer as part of increment.
@@ -206,13 +208,13 @@ func walkrange(n *Node) {
// Advancing during the increment ensures that the pointer p only points
// pass the end of the array during the final "p++; i++; if(i >= len(x)) break;",
// after which p is dead, so it cannot confuse the collector.
- tmp := Nod(OADD, hp, Nodintconst(t.Elem().Width))
+ tmp := nod(OADD, hp, nodintconst(t.Elem().Width))
tmp.Type = hp.Type
tmp.Typecheck = 1
tmp.Right.Type = Types[Tptr]
tmp.Right.Typecheck = 1
- a = Nod(OAS, hp, tmp)
+ a = nod(OAS, hp, tmp)
a = typecheck(a, Etop)
n.Right.Ninit.Set1(a)
}
@@ -232,23 +234,23 @@ func walkrange(n *Node) {
fn := syslook("mapiterinit")
fn = substArgTypes(fn, t.Key(), t.Val(), th)
- init = append(init, mkcall1(fn, nil, nil, typename(t), ha, Nod(OADDR, hit, nil)))
- n.Left = Nod(ONE, NodSym(ODOT, hit, keysym), nodnil())
+ init = append(init, mkcall1(fn, nil, nil, typename(t), ha, nod(OADDR, hit, nil)))
+ n.Left = nod(ONE, nodSym(ODOT, hit, keysym), nodnil())
fn = syslook("mapiternext")
fn = substArgTypes(fn, th)
- n.Right = mkcall1(fn, nil, nil, Nod(OADDR, hit, nil))
+ n.Right = mkcall1(fn, nil, nil, nod(OADDR, hit, nil))
- key := NodSym(ODOT, hit, keysym)
- key = Nod(OIND, key, nil)
+ key := nodSym(ODOT, hit, keysym)
+ key = nod(OIND, key, nil)
if v1 == nil {
body = nil
} else if v2 == nil {
- body = []*Node{Nod(OAS, v1, key)}
+ body = []*Node{nod(OAS, v1, key)}
} else {
- val := NodSym(ODOT, hit, valsym)
- val = Nod(OIND, val, nil)
- a := Nod(OAS2, nil, nil)
+ 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})
body = []*Node{a}
@@ -263,56 +265,85 @@ func walkrange(n *Node) {
hv1 := temp(t.Elem())
hv1.Typecheck = 1
if haspointers(t.Elem()) {
- init = append(init, Nod(OAS, hv1, nil))
+ init = append(init, nod(OAS, hv1, nil))
}
hb := temp(Types[TBOOL])
- n.Left = Nod(ONE, hb, Nodbool(false))
- a := Nod(OAS2RECV, nil, nil)
+ n.Left = nod(ONE, hb, nodbool(false))
+ a := nod(OAS2RECV, nil, nil)
a.Typecheck = 1
a.List.Set([]*Node{hv1, hb})
- a.Rlist.Set1(Nod(ORECV, ha, nil))
+ a.Rlist.Set1(nod(ORECV, ha, nil))
n.Left.Ninit.Set1(a)
if v1 == nil {
body = nil
} else {
- body = []*Node{Nod(OAS, v1, hv1)}
+ body = []*Node{nod(OAS, v1, hv1)}
}
// Zero hv1. This prevents hv1 from being the sole, inaccessible
// reference to an otherwise GC-able value during the next channel receive.
// See issue 15281.
- body = append(body, Nod(OAS, hv1, nil))
+ body = append(body, nod(OAS, hv1, nil))
case TSTRING:
+ // Transform string range statements like "for v1, v2 = range a" into
+ //
+ // ha := a
+ // for hv1 := 0; hv1 < len(ha); {
+ // v1 = hv1
+ // hv2 := rune(ha[hv1])
+ // if hv2 < utf8.RuneSelf {
+ // hv1++
+ // } else {
+ // hv2, hv1 = decoderune(ha, hv1)
+ // }
+ // v2 = hv2
+ // // original body
+ // }
+
// orderstmt arranged for a copy of the string variable.
ha := a
- ohv1 := temp(Types[TINT])
-
hv1 := temp(Types[TINT])
- init = append(init, Nod(OAS, hv1, nil))
+ hv2 := temp(runetype)
- var a *Node
- var hv2 *Node
- if v2 == nil {
- a = Nod(OAS, hv1, mkcall("stringiter", Types[TINT], nil, ha, hv1))
- } else {
- hv2 = temp(runetype)
- a = Nod(OAS2, nil, nil)
- a.List.Set([]*Node{hv1, hv2})
- fn := syslook("stringiter2")
- a.Rlist.Set1(mkcall1(fn, fn.Type.Results(), nil, ha, hv1))
- }
+ // hv1 := 0
+ init = append(init, nod(OAS, hv1, nil))
- n.Left = Nod(ONE, hv1, Nodintconst(0))
- n.Left.Ninit.Set([]*Node{Nod(OAS, ohv1, hv1), a})
+ // hv1 < len(ha)
+ n.Left = nod(OLT, hv1, nod(OLEN, ha, nil))
- body = nil
if v1 != nil {
- body = []*Node{Nod(OAS, v1, ohv1)}
+ // v1 = hv1
+ body = append(body, nod(OAS, v1, hv1))
}
+
+ // hv2 := ha[hv1]
+ nind := nod(OINDEX, ha, hv1)
+ nind.Bounded = true
+ body = append(body, nod(OAS, hv2, conv(nind, runetype)))
+
+ // if hv2 < utf8.RuneSelf
+ nif := nod(OIF, nil, nil)
+ nif.Left = nod(OLT, nind, nodintconst(utf8.RuneSelf))
+
+ // hv1++
+ nif.Nbody.Set1(nod(OAS, hv1, nod(OADD, hv1, nodintconst(1))))
+
+ // } else {
+ eif := nod(OAS2, nil, nil)
+ nif.Rlist.Set1(eif)
+
+ // hv2, hv1 = decoderune(ha, hv1)
+ eif.List.Set2(hv2, hv1)
+ fn := syslook("decoderune")
+ eif.Rlist.Set1(mkcall1(fn, fn.Type.Results(), nil, ha, hv1))
+
+ body = append(body, nif)
+
if v2 != nil {
- body = append(body, Nod(OAS, v2, hv2))
+ // v2 = hv2
+ body = append(body, nod(OAS, v2, hv2))
}
}
@@ -323,7 +354,7 @@ func walkrange(n *Node) {
n.Left = typecheck(n.Left, Erv)
n.Right = typecheck(n.Right, Etop)
typecheckslice(body, Etop)
- n.Nbody.Set(append(body, n.Nbody.Slice()...))
+ n.Nbody.Prepend(body...)
n = walkstmt(n)
lineno = lno
@@ -366,39 +397,45 @@ func memclrrange(n, v1, v2, a *Node) bool {
// if len(a) != 0 {
// hp = &a[0]
// hn = len(a)*sizeof(elem(a))
- // memclr(hp, hn)
+ // memclr{NoHeap,Has}Pointers(hp, hn)
// i = len(a) - 1
// }
n.Op = OIF
n.Nbody.Set(nil)
- n.Left = Nod(ONE, Nod(OLEN, a, nil), Nodintconst(0))
+ n.Left = nod(ONE, nod(OLEN, a, nil), nodintconst(0))
// hp = &a[0]
- hp := temp(Ptrto(Types[TUINT8]))
+ hp := temp(ptrto(Types[TUINT8]))
- tmp := Nod(OINDEX, a, Nodintconst(0))
+ tmp := nod(OINDEX, a, nodintconst(0))
tmp.Bounded = true
- tmp = Nod(OADDR, tmp, nil)
- tmp = Nod(OCONVNOP, tmp, nil)
- tmp.Type = Ptrto(Types[TUINT8])
- n.Nbody.Append(Nod(OAS, hp, tmp))
+ tmp = nod(OADDR, tmp, nil)
+ tmp = nod(OCONVNOP, tmp, nil)
+ tmp.Type = ptrto(Types[TUINT8])
+ n.Nbody.Append(nod(OAS, hp, tmp))
// hn = len(a) * sizeof(elem(a))
hn := temp(Types[TUINTPTR])
- tmp = Nod(OLEN, a, nil)
- tmp = Nod(OMUL, tmp, Nodintconst(elemsize))
+ tmp = nod(OLEN, a, nil)
+ tmp = nod(OMUL, tmp, nodintconst(elemsize))
tmp = conv(tmp, Types[TUINTPTR])
- n.Nbody.Append(Nod(OAS, hn, tmp))
-
- // memclr(hp, hn)
- fn := mkcall("memclr", nil, nil, hp, hn)
+ n.Nbody.Append(nod(OAS, hn, tmp))
+
+ var fn *Node
+ if haspointers(a.Type.Elem()) {
+ // memclrHasPointers(hp, hn)
+ fn = mkcall("memclrHasPointers", nil, nil, hp, hn)
+ } else {
+ // memclrNoHeapPointers(hp, hn)
+ fn = mkcall("memclrNoHeapPointers", nil, nil, hp, hn)
+ }
n.Nbody.Append(fn)
// i = len(a) - 1
- v1 = Nod(OAS, v1, Nod(OSUB, Nod(OLEN, a, nil), Nodintconst(1)))
+ v1 = nod(OAS, v1, nod(OSUB, nod(OLEN, a, nil), nodintconst(1)))
n.Nbody.Append(v1)
diff --git a/src/cmd/compile/internal/gc/reflect.go b/src/cmd/compile/internal/gc/reflect.go
index cff1acc..4f9d92e 100644
--- a/src/cmd/compile/internal/gc/reflect.go
+++ b/src/cmd/compile/internal/gc/reflect.go
@@ -18,9 +18,15 @@ type itabEntry struct {
sym *Sym
}
+type ptabEntry struct {
+ s *Sym
+ t *Type
+}
+
// runtime interface and reflection data structures
var signatlist []*Node
var itabs []itabEntry
+var ptabs []ptabEntry
type Sig struct {
name string
@@ -96,10 +102,10 @@ func mapbucket(t *Type) *Type {
dowidth(keytype)
dowidth(valtype)
if keytype.Width > MAXKEYSIZE {
- keytype = Ptrto(keytype)
+ keytype = ptrto(keytype)
}
if valtype.Width > MAXVALSIZE {
- valtype = Ptrto(valtype)
+ valtype = ptrto(valtype)
}
field := make([]*Field, 0, 5)
@@ -143,7 +149,7 @@ 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)
+ otyp := ptrto(bucket)
if !haspointers(t.Val()) && !haspointers(t.Key()) && t.Val().Width <= MAXVALSIZE && t.Key().Width <= MAXKEYSIZE {
otyp = Types[TUINTPTR]
}
@@ -159,7 +165,7 @@ func mapbucket(t *Type) *Type {
// 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)
+ yyerror("bad math in mapbucket for %v", t)
}
t.MapType().Bucket = bucket
@@ -176,20 +182,22 @@ func hmap(t *Type) *Type {
}
bucket := mapbucket(t)
- var field [8]*Field
- field[0] = makefield("count", Types[TINT])
- field[1] = makefield("flags", Types[TUINT8])
- field[2] = makefield("B", Types[TUINT8])
- field[3] = makefield("hash0", Types[TUINT32])
- field[4] = makefield("buckets", Ptrto(bucket))
- field[5] = makefield("oldbuckets", Ptrto(bucket))
- field[6] = makefield("nevacuate", Types[TUINTPTR])
- field[7] = makefield("overflow", Types[TUNSAFEPTR])
+ 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
- h.SetFields(field[:])
+ h.SetFields(fields)
dowidth(h)
t.MapType().Hmap = h
h.StructType().Map = t
@@ -218,12 +226,12 @@ func hiter(t *Type) *Type {
// }
// must match ../../../../runtime/hashmap.go:hiter.
var field [12]*Field
- field[0] = makefield("key", Ptrto(t.Key()))
- field[1] = makefield("val", Ptrto(t.Val()))
- field[2] = makefield("t", Ptrto(Types[TUINT8]))
- field[3] = makefield("h", Ptrto(hmap(t)))
- field[4] = makefield("buckets", Ptrto(mapbucket(t)))
- field[5] = makefield("bptr", Ptrto(mapbucket(t)))
+ 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])
@@ -237,7 +245,7 @@ func hiter(t *Type) *Type {
i.SetFields(field[:])
dowidth(i)
if i.Width != int64(12*Widthptr) {
- Yyerror("hash_iter size not correct %d %d", i.Width, 12*Widthptr)
+ yyerror("hash_iter size not correct %d %d", i.Width, 12*Widthptr)
}
t.MapType().Hiter = i
i.StructType().Map = t
@@ -249,14 +257,14 @@ func hiter(t *Type) *Type {
func methodfunc(f *Type, receiver *Type) *Type {
var in []*Node
if receiver != nil {
- d := Nod(ODCLFIELD, nil, nil)
+ d := nod(ODCLFIELD, nil, nil)
d.Type = receiver
in = append(in, d)
}
var d *Node
for _, t := range f.Params().Fields().Slice() {
- d = Nod(ODCLFIELD, nil, nil)
+ d = nod(ODCLFIELD, nil, nil)
d.Type = t.Type
d.Isddd = t.Isddd
in = append(in, d)
@@ -264,7 +272,7 @@ func methodfunc(f *Type, receiver *Type) *Type {
var out []*Node
for _, t := range f.Results().Fields().Slice() {
- d = Nod(ODCLFIELD, nil, nil)
+ d = nod(ODCLFIELD, nil, nil)
d.Type = t.Type
out = append(out, d)
}
@@ -282,7 +290,7 @@ func methodfunc(f *Type, receiver *Type) *Type {
// Generates stub functions as needed.
func methods(t *Type) []*Sig {
// method type
- mt := methtype(t, 0)
+ mt := methtype(t)
if mt == nil {
return nil
@@ -293,7 +301,7 @@ func methods(t *Type) []*Sig {
it := t
if !isdirectiface(it) {
- it = Ptrto(t)
+ it = ptrto(t)
}
// make list of methods for t,
@@ -346,7 +354,7 @@ func methods(t *Type) []*Sig {
if sig.isym.Flags&SymSiggen == 0 {
sig.isym.Flags |= SymSiggen
- if !Eqtype(this, it) || this.Width < Types[Tptr].Width {
+ if !eqtype(this, it) || this.Width < Types[Tptr].Width {
compiling_wrappers = 1
genwrapper(it, f, sig.isym, 1)
compiling_wrappers = 0
@@ -355,7 +363,7 @@ func methods(t *Type) []*Sig {
if sig.tsym.Flags&SymSiggen == 0 {
sig.tsym.Flags |= SymSiggen
- if !Eqtype(this, t) {
+ if !eqtype(this, t) {
compiling_wrappers = 1
genwrapper(t, f, sig.tsym, 0)
compiling_wrappers = 0
@@ -486,26 +494,31 @@ func dgopkgpathOffLSym(s *obj.LSym, ot int, pkg *Pkg) int {
}
// isExportedField reports whether a struct field is exported.
-func isExportedField(ft *Field) bool {
+// It also returns the package to use for PkgPath for an unexported field.
+func isExportedField(ft *Field) (bool, *Pkg) {
if ft.Sym != nil && ft.Embedded == 0 {
- return exportname(ft.Sym.Name)
+ return exportname(ft.Sym.Name), ft.Sym.Pkg
} else {
if ft.Type.Sym != nil &&
(ft.Type.Sym.Pkg == builtinpkg || !exportname(ft.Type.Sym.Name)) {
- return false
+ return false, ft.Type.Sym.Pkg
} else {
- return true
+ return true, nil
}
}
}
// dnameField dumps a reflect.name for a struct field.
-func dnameField(s *Sym, ot int, ft *Field) int {
+func dnameField(s *Sym, ot int, spkg *Pkg, ft *Field) int {
var name string
if ft.Sym != nil && ft.Embedded == 0 {
name = ft.Sym.Name
}
- nsym := dname(name, ft.Note, nil, isExportedField(ft))
+ isExported, fpkg := isExportedField(ft)
+ if isExported || fpkg == spkg {
+ fpkg = nil
+ }
+ nsym := dname(name, ft.Note, fpkg, isExported)
return dsymptrLSym(Linksym(s), ot, nsym, 0)
}
@@ -595,7 +608,7 @@ func dextratype(s *Sym, ot int, t *Type, dataAdd int) int {
}
noff := int(Rnd(int64(ot), int64(Widthptr)))
if noff != ot {
- Fatalf("unexpected alignment in dextratype for %s", t)
+ Fatalf("unexpected alignment in dextratype for %v", t)
}
for _, a := range m {
@@ -607,10 +620,10 @@ func dextratype(s *Sym, ot int, t *Type, dataAdd int) int {
dataAdd += uncommonSize(t)
mcount := len(m)
if mcount != int(uint16(mcount)) {
- Fatalf("too many methods on %s: %d", t, mcount)
+ Fatalf("too many methods on %v: %d", t, mcount)
}
if dataAdd != int(uint32(dataAdd)) {
- Fatalf("methods are too far away on %s: %d", t, dataAdd)
+ Fatalf("methods are too far away on %v: %d", t, dataAdd)
}
ot = duint16(s, ot, uint16(mcount))
@@ -821,9 +834,13 @@ func dcommontype(s *Sym, ot int, t *Type) int {
algsym = dalgsym(t)
}
+ sptrWeak := true
var sptr *Sym
- tptr := Ptrto(t)
- if !t.IsPtr() && (t.Sym != nil || methods(tptr) != nil) {
+ if !t.IsPtr() || t.ptrTo != nil {
+ tptr := ptrto(t)
+ if t.Sym != nil || methods(tptr) != nil {
+ sptrWeak = false
+ }
sptr = dtypesym(tptr)
}
@@ -858,7 +875,7 @@ func dcommontype(s *Sym, ot int, t *Type) int {
}
exported := false
- p := Tconv(t, FmtLeft|FmtUnsigned)
+ p := t.tconv(FmtLeft | FmtUnsigned)
// If we're writing out type T,
// we are very likely to write out type *T as well.
// Use the string "*T"[1:] for "T", so that the two
@@ -910,32 +927,37 @@ func dcommontype(s *Sym, ot int, t *Type) int {
nsym := dname(p, "", nil, exported)
ot = dsymptrOffLSym(Linksym(s), ot, nsym, 0) // str
+ // ptrToThis
if sptr == nil {
ot = duint32(s, ot, 0)
+ } else if sptrWeak {
+ ot = dsymptrWeakOffLSym(Linksym(s), ot, Linksym(sptr))
} else {
- ot = dsymptrOffLSym(Linksym(s), ot, Linksym(sptr), 0) // ptrToThis
+ ot = dsymptrOffLSym(Linksym(s), ot, Linksym(sptr), 0)
}
return ot
}
func typesym(t *Type) *Sym {
- return Pkglookup(Tconv(t, FmtLeft), typepkg)
+ name := t.tconv(FmtLeft)
+
+ // Use a separate symbol name for Noalg types for #17752.
+ if a, bad := algtype1(t); a == ANOEQ && bad.Noalg {
+ name = "noalg." + name
+ }
+
+ return Pkglookup(name, typepkg)
}
// tracksym returns the symbol for tracking use of field/method f, assumed
// to be a member of struct/interface type t.
func tracksym(t *Type, f *Field) *Sym {
- return Pkglookup(Tconv(t, FmtLeft)+"."+f.Sym.Name, trackpkg)
-}
-
-func typelinkLSym(t *Type) *obj.LSym {
- name := "go.typelink." + Tconv(t, FmtLeft) // complete, unambiguous type name
- return obj.Linklookup(Ctxt, name, 0)
+ return Pkglookup(t.tconv(FmtLeft)+"."+f.Sym.Name, trackpkg)
}
func typesymprefix(prefix string, t *Type) *Sym {
- p := prefix + "." + Tconv(t, FmtLeft)
+ p := prefix + "." + t.tconv(FmtLeft)
s := Pkglookup(p, typepkg)
//print("algsym: %s -> %+S\n", p, s);
@@ -963,8 +985,8 @@ func typenamesym(t *Type) *Sym {
func typename(t *Type) *Node {
s := typenamesym(t)
- n := Nod(OADDR, s.Def, nil)
- n.Type = Ptrto(s.Def.Type)
+ n := nod(OADDR, s.Def, nil)
+ n.Type = ptrto(s.Def.Type)
n.Addable = true
n.Ullman = 2
n.Typecheck = 1
@@ -972,10 +994,11 @@ func typename(t *Type) *Node {
}
func itabname(t, itype *Type) *Node {
- if t == nil || (t.IsPtr() && t.Elem() == nil) || t.IsUntyped() {
- Fatalf("itabname %v", t)
+ if t == nil || (t.IsPtr() && t.Elem() == nil) || t.IsUntyped() || !itype.IsInterface() || itype.IsEmptyInterface() {
+ Fatalf("itabname(%v, %v)", t, itype)
}
- s := Pkglookup(Tconv(t, FmtLeft)+","+Tconv(itype, FmtLeft), itabpkg)
+ s := Pkglookup(t.tconv(FmtLeft)+","+itype.tconv(FmtLeft), itabpkg)
+ Linksym(s).Set(obj.AttrLocal, true)
if s.Def == nil {
n := newname(s)
n.Type = Types[TUINT8]
@@ -986,8 +1009,8 @@ func itabname(t, itype *Type) *Node {
itabs = append(itabs, itabEntry{t: t, itype: itype, sym: s})
}
- n := Nod(OADDR, s.Def, nil)
- n.Type = Ptrto(s.Def.Type)
+ n := nod(OADDR, s.Def, nil)
+ n.Type = ptrto(s.Def.Type)
n.Addable = true
n.Ullman = 2
n.Typecheck = 1
@@ -1301,6 +1324,15 @@ ok:
pkg := localpkg
if t.Sym != nil {
pkg = t.Sym.Pkg
+ } else {
+ // Unnamed type. Grab the package from the first field, if any.
+ for _, f := range t.Fields().Slice() {
+ if f.Embedded != 0 {
+ continue
+ }
+ pkg = f.Sym.Pkg
+ break
+ }
}
ot = dgopkgpath(s, ot, pkg)
ot = dsymptr(s, ot, s, ot+Widthptr+2*Widthint+uncommonSize(t))
@@ -1312,7 +1344,7 @@ ok:
for _, f := range t.Fields().Slice() {
// ../../../../runtime/type.go:/structField
- ot = dnameField(s, ot, f)
+ ot = dnameField(s, ot, pkg, f)
ot = dsymptr(s, ot, dtypesym(f.Type), 0)
ot = duintptr(s, ot, uint64(f.Offset))
}
@@ -1321,8 +1353,6 @@ ok:
ot = dextratypeData(s, ot, t)
ggloblsym(s, int32(ot), int16(dupok|obj.RODATA))
- // generate typelink.foo pointing at s = type.foo.
- //
// The linker will leave a table of all the typelinks for
// types in the binary, so the runtime can find them.
//
@@ -1340,11 +1370,7 @@ ok:
keep = true
}
}
- if keep {
- slink := typelinkLSym(t)
- dsymptrOffLSym(slink, 0, Linksym(s), 0)
- ggloblLSym(slink, 4, int16(dupok|obj.RODATA))
- }
+ s.Lsym.Set(obj.AttrMakeTypelink, keep)
return s
}
@@ -1368,7 +1394,7 @@ func dumptypestructs() {
t := n.Type
dtypesym(t)
if t.Sym != nil {
- dtypesym(Ptrto(t))
+ dtypesym(ptrto(t))
}
}
@@ -1389,11 +1415,36 @@ func dumptypestructs() {
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.sym, int32(o), int16(obj.DUPOK|obj.NOPTR|obj.LOCAL))
- ilink := Pkglookup(Tconv(i.t, FmtLeft)+","+Tconv(i.itype, FmtLeft), itablinkpkg)
+ ilink := Pkglookup(i.t.tconv(FmtLeft)+","+i.itype.tconv(FmtLeft), itablinkpkg)
dsymptr(ilink, 0, i.sym, 0)
- ggloblsym(ilink, int32(Widthptr), int16(obj.DUPOK|obj.RODATA))
+ ggloblsym(ilink, int32(Widthptr), int16(obj.DUPOK|obj.RODATA|obj.LOCAL))
+ }
+
+ // process ptabs
+ if localpkg.Name == "main" && len(ptabs) > 0 {
+ ot := 0
+ s := obj.Linklookup(Ctxt, "go.plugin.tabs", 0)
+ for _, p := range ptabs {
+ // Dump ptab symbol into go.pluginsym package.
+ //
+ // type ptab struct {
+ // name nameOff
+ // 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)
+ }
+ ggloblLSym(s, int32(ot), int16(obj.RODATA))
+
+ ot = 0
+ s = obj.Linklookup(Ctxt, "go.plugin.exports", 0)
+ for _, p := range ptabs {
+ ot = dsymptrLSym(s, ot, Linksym(p.s), 0)
+ }
+ ggloblLSym(s, int32(ot), int16(obj.RODATA))
}
// generate import strings for imported packages
@@ -1416,16 +1467,16 @@ func dumptypestructs() {
// but using runtime means fewer copies in .6 files.
if myimportpath == "runtime" {
for i := EType(1); i <= TBOOL; i++ {
- dtypesym(Ptrto(Types[i]))
+ dtypesym(ptrto(Types[i]))
}
- dtypesym(Ptrto(Types[TSTRING]))
- dtypesym(Ptrto(Types[TUNSAFEPTR]))
+ dtypesym(ptrto(Types[TSTRING]))
+ dtypesym(ptrto(Types[TUNSAFEPTR]))
// emit type structs for error and func(error) string.
// The latter is the type of an auto-generated wrapper.
- dtypesym(Ptrto(errortype))
+ dtypesym(ptrto(errortype))
- dtypesym(functype(nil, []*Node{Nod(ODCLFIELD, nil, typenod(errortype))}, []*Node{Nod(ODCLFIELD, nil, typenod(Types[TSTRING]))}))
+ dtypesym(functype(nil, []*Node{nod(ODCLFIELD, nil, typenod(errortype))}, []*Node{nod(ODCLFIELD, nil, typenod(Types[TSTRING]))}))
// add paths for runtime and main, which 6l imports implicitly.
dimportpath(Runtimepkg)
@@ -1597,7 +1648,7 @@ func fillptrmask(t *Type, ptrmask []byte) {
nptr := typeptrdata(t) / int64(Widthptr)
for i := int64(0); i < nptr; i++ {
- if bvget(vec, int32(i)) == 1 {
+ if vec.Get(int32(i)) {
ptrmask[i/8] |= 1 << (uint(i) % 8)
}
}
@@ -1727,8 +1778,8 @@ func zeroaddr(size int64) *Node {
x.Typecheck = 1
s.Def = x
}
- z := Nod(OADDR, s.Def, nil)
- z.Type = Ptrto(Types[TUINT8])
+ z := nod(OADDR, s.Def, nil)
+ z.Type = ptrto(Types[TUINT8])
z.Addable = true
z.Typecheck = 1
return z
diff --git a/src/cmd/compile/internal/gc/reg.go b/src/cmd/compile/internal/gc/reg.go
deleted file mode 100644
index a80d72b..0000000
--- a/src/cmd/compile/internal/gc/reg.go
+++ /dev/null
@@ -1,1532 +0,0 @@
-// Derived from Inferno utils/6c/reg.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6c/reg.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth at terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth at terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// Portions Copyright © 2009 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-package gc
-
-import (
- "bytes"
- "cmd/internal/obj"
- "cmd/internal/sys"
- "fmt"
- "sort"
- "strings"
-)
-
-// A Var represents a single variable that may be stored in a register.
-// That variable may itself correspond to a hardware register,
-// to represent the use of registers in the unoptimized instruction stream.
-type Var struct {
- offset int64
- node *Node
- nextinnode *Var
- width int
- id int // index in vars
- name int8
- etype EType
- addr int8
-}
-
-// Bits represents a set of Vars, stored as a bit set of var numbers
-// (the index in vars, or equivalently v.id).
-type Bits struct {
- b [BITS]uint64
-}
-
-const (
- BITS = 3
- NVAR = BITS * 64
-)
-
-var (
- vars [NVAR]Var // variables under consideration
- nvar int // number of vars
-
- regbits uint64 // bits for hardware registers
-
- zbits Bits // zero
- externs Bits // global variables
- params Bits // function parameters and results
- ivar Bits // function parameters (inputs)
- ovar Bits // function results (outputs)
- consts Bits // constant values
- addrs Bits // variables with address taken
-)
-
-// A Reg is a wrapper around a single Prog (one instruction) that holds
-// register optimization information while the optimizer runs.
-// r->prog is the instruction.
-type Reg struct {
- set Bits // regopt variables written by this instruction.
- use1 Bits // regopt variables read by prog->from.
- use2 Bits // regopt variables read by prog->to.
-
- // refahead/refbehind are the regopt variables whose current
- // value may be used in the following/preceding instructions
- // up to a CALL (or the value is clobbered).
- refbehind Bits
- refahead Bits
-
- // calahead/calbehind are similar, but for variables in
- // instructions that are reachable after hitting at least one
- // CALL.
- calbehind Bits
- calahead Bits
-
- regdiff Bits
- act Bits
- regu uint64 // register used bitmap
-}
-
-// A Rgn represents a single regopt variable over a region of code
-// where a register could potentially be dedicated to that variable.
-// The code encompassed by a Rgn is defined by the flow graph,
-// starting at enter, flood-filling forward while varno is refahead
-// and backward while varno is refbehind, and following branches.
-// A single variable may be represented by multiple disjoint Rgns and
-// each Rgn may choose a different register for that variable.
-// Registers are allocated to regions greedily in order of descending
-// cost.
-type Rgn struct {
- enter *Flow
- cost int16
- varno int16
- regno int16
-}
-
-// The Plan 9 C compilers used a limit of 600 regions,
-// but the yacc-generated parser in y.go has 3100 regions.
-// We set MaxRgn large enough to handle that.
-// There's not a huge cost to having too many regions:
-// the main processing traces the live area for each variable,
-// which is limited by the number of variables times the area,
-// not the raw region count. If there are many regions, they
-// are almost certainly small and easy to trace.
-// The only operation that scales with region count is the
-// sorting by cost, which uses sort.Sort and is therefore
-// guaranteed n log n.
-const MaxRgn = 6000
-
-var (
- region []Rgn
- nregion int
-)
-
-type rcmp []Rgn
-
-func (x rcmp) Len() int {
- return len(x)
-}
-
-func (x rcmp) Swap(i, j int) {
- x[i], x[j] = x[j], x[i]
-}
-
-func (x rcmp) Less(i, j int) bool {
- p1 := &x[i]
- p2 := &x[j]
- if p1.cost != p2.cost {
- return int(p2.cost)-int(p1.cost) < 0
- }
- if p1.varno != p2.varno {
- return int(p2.varno)-int(p1.varno) < 0
- }
- if p1.enter != p2.enter {
- return int(p2.enter.Id-p1.enter.Id) < 0
- }
- return false
-}
-
-func setaddrs(bit Bits) {
- var i int
- var n int
- var v *Var
- var node *Node
-
- for bany(&bit) {
- // convert each bit to a variable
- i = bnum(&bit)
-
- node = vars[i].node
- n = int(vars[i].name)
- biclr(&bit, uint(i))
-
- // disable all pieces of that variable
- for i = 0; i < nvar; i++ {
- v = &vars[i]
- if v.node == node && int(v.name) == n {
- v.addr = 2
- }
- }
- }
-}
-
-var regnodes [64]*Node
-
-func walkvardef(n *Node, f *Flow, active int) {
- var f1 *Flow
- var bn int
- var v *Var
-
- for f1 = f; f1 != nil; f1 = f1.S1 {
- if f1.Active == int32(active) {
- break
- }
- f1.Active = int32(active)
- if f1.Prog.As == obj.AVARKILL && f1.Prog.To.Node == n {
- break
- }
- for v, _ = n.Opt().(*Var); v != nil; v = v.nextinnode {
- bn = v.id
- biset(&(f1.Data.(*Reg)).act, uint(bn))
- }
-
- if f1.Prog.As == obj.ACALL {
- break
- }
- }
-
- for f2 := f; f2 != f1; f2 = f2.S1 {
- if f2.S2 != nil {
- walkvardef(n, f2.S2, active)
- }
- }
-}
-
-// add mov b,rn
-// just after r
-func addmove(r *Flow, bn int, rn int, f int) {
- p1 := Ctxt.NewProg()
- Clearp(p1)
- p1.Pc = 9999
-
- p := r.Prog
- p1.Link = p.Link
- p.Link = p1
- p1.Lineno = p.Lineno
-
- v := &vars[bn]
-
- a := &p1.To
- a.Offset = v.offset
- a.Etype = uint8(v.etype)
- a.Type = obj.TYPE_MEM
- a.Name = v.name
- a.Node = v.node
- a.Sym = Linksym(v.node.Sym)
-
- /* NOTE(rsc): 9g did
- if(a->etype == TARRAY)
- a->type = TYPE_ADDR;
- else if(a->sym == nil)
- a->type = TYPE_CONST;
- */
- p1.As = Thearch.Optoas(OAS, Types[uint8(v.etype)])
-
- // TODO(rsc): Remove special case here.
- if Thearch.LinkArch.InFamily(sys.MIPS64, sys.ARM, sys.ARM64, sys.PPC64) && v.etype == TBOOL {
- p1.As = Thearch.Optoas(OAS, Types[TUINT8])
- }
- p1.From.Type = obj.TYPE_REG
- p1.From.Reg = int16(rn)
- p1.From.Name = obj.NAME_NONE
- if f == 0 {
- p1.From = *a
- *a = obj.Addr{}
- a.Type = obj.TYPE_REG
- a.Reg = int16(rn)
- }
-
- if Debug['R'] != 0 && Debug['v'] != 0 {
- fmt.Printf("%v ===add=== %v\n", p, p1)
- }
- Ostats.Nspill++
-}
-
-func overlap_reg(o1 int64, w1 int, o2 int64, w2 int) bool {
- t1 := o1 + int64(w1)
- t2 := o2 + int64(w2)
-
- if t1 <= o2 || t2 <= o1 {
- return false
- }
-
- return true
-}
-
-func mkvar(f *Flow, a *obj.Addr) Bits {
- // mark registers used
- if a.Type == obj.TYPE_NONE {
- return zbits
- }
-
- r := f.Data.(*Reg)
- r.use1.b[0] |= Thearch.Doregbits(int(a.Index)) // TODO: Use RtoB
-
- var n int
- switch a.Type {
- default:
- regu := Thearch.Doregbits(int(a.Reg)) | Thearch.RtoB(int(a.Reg)) // TODO: Use RtoB
- if regu == 0 {
- return zbits
- }
- bit := zbits
- bit.b[0] = regu
- return bit
-
- // TODO(rsc): Remove special case here.
- case obj.TYPE_ADDR:
- var bit Bits
- if Thearch.LinkArch.InFamily(sys.MIPS64, sys.ARM, sys.ARM64, sys.PPC64) {
- goto memcase
- }
- a.Type = obj.TYPE_MEM
- bit = mkvar(f, a)
- setaddrs(bit)
- a.Type = obj.TYPE_ADDR
- Ostats.Naddr++
- return zbits
-
- memcase:
- fallthrough
-
- case obj.TYPE_MEM:
- if r != nil {
- r.use1.b[0] |= Thearch.RtoB(int(a.Reg))
- }
-
- /* NOTE: 5g did
- if(r->f.prog->scond & (C_PBIT|C_WBIT))
- r->set.b[0] |= RtoB(a->reg);
- */
- switch a.Name {
- default:
- // Note: This case handles NAME_EXTERN and NAME_STATIC.
- // We treat these as requiring eager writes to memory, due to
- // the possibility of a fault handler looking at them, so there is
- // not much point in registerizing the loads.
- // If we later choose the set of candidate variables from a
- // larger list, these cases could be deprioritized instead of
- // removed entirely.
- return zbits
-
- case obj.NAME_PARAM,
- obj.NAME_AUTO:
- n = int(a.Name)
- }
- }
-
- node, _ := a.Node.(*Node)
- if node == nil || node.Op != ONAME || node.Orig == nil {
- return zbits
- }
- node = node.Orig
- if node.Orig != node {
- Fatalf("%v: bad node", Ctxt.Dconv(a))
- }
- if node.Sym == nil || node.Sym.Name[0] == '.' {
- return zbits
- }
- et := EType(a.Etype)
- o := a.Offset
- w := a.Width
- if w < 0 {
- Fatalf("bad width %d for %v", w, Ctxt.Dconv(a))
- }
-
- flag := 0
- var v *Var
- for i := 0; i < nvar; i++ {
- v = &vars[i]
- if v.node == node && int(v.name) == n {
- if v.offset == o {
- if v.etype == et {
- if int64(v.width) == w {
- // TODO(rsc): Remove special case for arm here.
- if flag == 0 || Thearch.LinkArch.Family != sys.ARM {
- return blsh(uint(i))
- }
- }
- }
- }
-
- // if they overlap, disable both
- if overlap_reg(v.offset, v.width, o, int(w)) {
- // print("disable overlap %s %d %d %d %d, %E != %E\n", s->name, v->offset, v->width, o, w, v->etype, et);
- v.addr = 1
-
- flag = 1
- }
- }
- }
-
- switch et {
- case 0, TFUNC:
- return zbits
- }
-
- if nvar >= NVAR {
- if Debug['w'] > 1 && node != nil {
- Fatalf("variable not optimized: %v", Nconv(node, FmtSharp))
- }
- if Debug['v'] > 0 {
- Warn("variable not optimized: %v", Nconv(node, FmtSharp))
- }
-
- // If we're not tracking a word in a variable, mark the rest as
- // having its address taken, so that we keep the whole thing
- // live at all calls. otherwise we might optimize away part of
- // a variable but not all of it.
- var v *Var
- for i := 0; i < nvar; i++ {
- v = &vars[i]
- if v.node == node {
- v.addr = 1
- }
- }
-
- return zbits
- }
-
- i := nvar
- nvar++
- v = &vars[i]
- v.id = i
- v.offset = o
- v.name = int8(n)
- v.etype = et
- v.width = int(w)
- v.addr = int8(flag) // funny punning
- v.node = node
-
- // node->opt is the head of a linked list
- // of Vars within the given Node, so that
- // we can start at a Var and find all the other
- // Vars in the same Go variable.
- v.nextinnode, _ = node.Opt().(*Var)
-
- node.SetOpt(v)
-
- bit := blsh(uint(i))
- if n == obj.NAME_EXTERN || n == obj.NAME_STATIC {
- for z := 0; z < BITS; z++ {
- externs.b[z] |= bit.b[z]
- }
- }
- if n == obj.NAME_PARAM {
- for z := 0; z < BITS; z++ {
- params.b[z] |= bit.b[z]
- }
- }
-
- if node.Class == PPARAM {
- for z := 0; z < BITS; z++ {
- ivar.b[z] |= bit.b[z]
- }
- }
- if node.Class == PPARAMOUT {
- for z := 0; z < BITS; z++ {
- ovar.b[z] |= bit.b[z]
- }
- }
-
- // Treat values with their address taken as live at calls,
- // because the garbage collector's liveness analysis in plive.go does.
- // These must be consistent or else we will elide stores and the garbage
- // collector will see uninitialized data.
- // The typical case where our own analysis is out of sync is when the
- // node appears to have its address taken but that code doesn't actually
- // get generated and therefore doesn't show up as an address being
- // taken when we analyze the instruction stream.
- // One instance of this case is when a closure uses the same name as
- // an outer variable for one of its own variables declared with :=.
- // The parser flags the outer variable as possibly shared, and therefore
- // sets addrtaken, even though it ends up not being actually shared.
- // If we were better about _ elision, _ = &x would suffice too.
- // The broader := in a closure problem is mentioned in a comment in
- // closure.go:/^typecheckclosure and dcl.go:/^oldname.
- if node.Addrtaken {
- v.addr = 1
- }
-
- // Disable registerization for globals, because:
- // (1) we might panic at any time and we want the recovery code
- // to see the latest values (issue 1304).
- // (2) we don't know what pointers might point at them and we want
- // loads via those pointers to see updated values and vice versa (issue 7995).
- //
- // Disable registerization for results if using defer, because the deferred func
- // might recover and return, causing the current values to be used.
- if node.Class == PEXTERN || (hasdefer && node.Class == PPARAMOUT) {
- v.addr = 1
- }
-
- if Debug['R'] != 0 {
- fmt.Printf("bit=%2d et=%v w=%d+%d %v %v flag=%d\n", i, et, o, w, Nconv(node, FmtSharp), Ctxt.Dconv(a), v.addr)
- }
- Ostats.Nvar++
-
- return bit
-}
-
-var change int
-
-func prop(f *Flow, ref Bits, cal Bits) {
- var f1 *Flow
- var r1 *Reg
- var z int
- var i int
- var v *Var
- var v1 *Var
-
- for f1 = f; f1 != nil; f1 = f1.P1 {
- r1 = f1.Data.(*Reg)
- for z = 0; z < BITS; z++ {
- ref.b[z] |= r1.refahead.b[z]
- if ref.b[z] != r1.refahead.b[z] {
- r1.refahead.b[z] = ref.b[z]
- change = 1
- }
-
- cal.b[z] |= r1.calahead.b[z]
- if cal.b[z] != r1.calahead.b[z] {
- r1.calahead.b[z] = cal.b[z]
- change = 1
- }
- }
-
- switch f1.Prog.As {
- case obj.ACALL:
- if Noreturn(f1.Prog) {
- break
- }
-
- // Mark all input variables (ivar) as used, because that's what the
- // liveness bitmaps say. The liveness bitmaps say that so that a
- // panic will not show stale values in the parameter dump.
- // Mark variables with a recent VARDEF (r1->act) as used,
- // so that the optimizer flushes initializations to memory,
- // so that if a garbage collection happens during this CALL,
- // the collector will see initialized memory. Again this is to
- // match what the liveness bitmaps say.
- for z = 0; z < BITS; z++ {
- cal.b[z] |= ref.b[z] | externs.b[z] | ivar.b[z] | r1.act.b[z]
- ref.b[z] = 0
- }
-
- // cal.b is the current approximation of what's live across the call.
- // Every bit in cal.b is a single stack word. For each such word,
- // find all the other tracked stack words in the same Go variable
- // (struct/slice/string/interface) and mark them live too.
- // This is necessary because the liveness analysis for the garbage
- // collector works at variable granularity, not at word granularity.
- // It is fundamental for slice/string/interface: the garbage collector
- // needs the whole value, not just some of the words, in order to
- // interpret the other bits correctly. Specifically, slice needs a consistent
- // ptr and cap, string needs a consistent ptr and len, and interface
- // needs a consistent type word and data word.
- for z = 0; z < BITS; z++ {
- if cal.b[z] == 0 {
- continue
- }
- for i = 0; i < 64; i++ {
- if z*64+i >= nvar || (cal.b[z]>>uint(i))&1 == 0 {
- continue
- }
- v = &vars[z*64+i]
- if v.node.Opt() == nil { // v represents fixed register, not Go variable
- continue
- }
-
- // v->node->opt is the head of a linked list of Vars
- // corresponding to tracked words from the Go variable v->node.
- // Walk the list and set all the bits.
- // For a large struct this could end up being quadratic:
- // after the first setting, the outer loop (for z, i) would see a 1 bit
- // for all of the remaining words in the struct, and for each such
- // word would go through and turn on all the bits again.
- // To avoid the quadratic behavior, we only turn on the bits if
- // v is the head of the list or if the head's bit is not yet turned on.
- // This will set the bits at most twice, keeping the overall loop linear.
- v1, _ = v.node.Opt().(*Var)
-
- if v == v1 || !btest(&cal, uint(v1.id)) {
- for ; v1 != nil; v1 = v1.nextinnode {
- biset(&cal, uint(v1.id))
- }
- }
- }
- }
-
- case obj.ATEXT:
- for z = 0; z < BITS; z++ {
- cal.b[z] = 0
- ref.b[z] = 0
- }
-
- case obj.ARET:
- for z = 0; z < BITS; z++ {
- cal.b[z] = externs.b[z] | ovar.b[z]
- ref.b[z] = 0
- }
- }
-
- for z = 0; z < BITS; z++ {
- ref.b[z] = ref.b[z]&^r1.set.b[z] | r1.use1.b[z] | r1.use2.b[z]
- cal.b[z] &^= (r1.set.b[z] | r1.use1.b[z] | r1.use2.b[z])
- r1.refbehind.b[z] = ref.b[z]
- r1.calbehind.b[z] = cal.b[z]
- }
-
- if f1.Active != 0 {
- break
- }
- f1.Active = 1
- }
-
- var r *Reg
- var f2 *Flow
- for ; f != f1; f = f.P1 {
- r = f.Data.(*Reg)
- for f2 = f.P2; f2 != nil; f2 = f2.P2link {
- prop(f2, r.refbehind, r.calbehind)
- }
- }
-}
-
-func synch(f *Flow, dif Bits) {
- var r1 *Reg
- var z int
-
- for f1 := f; f1 != nil; f1 = f1.S1 {
- r1 = f1.Data.(*Reg)
- for z = 0; z < BITS; z++ {
- dif.b[z] = dif.b[z]&^(^r1.refbehind.b[z]&r1.refahead.b[z]) | r1.set.b[z] | r1.regdiff.b[z]
- if dif.b[z] != r1.regdiff.b[z] {
- r1.regdiff.b[z] = dif.b[z]
- change = 1
- }
- }
-
- if f1.Active != 0 {
- break
- }
- f1.Active = 1
- for z = 0; z < BITS; z++ {
- dif.b[z] &^= (^r1.calbehind.b[z] & r1.calahead.b[z])
- }
- if f1.S2 != nil {
- synch(f1.S2, dif)
- }
- }
-}
-
-func allreg(b uint64, r *Rgn) uint64 {
- v := &vars[r.varno]
- r.regno = 0
- switch v.etype {
- default:
- Fatalf("unknown etype %d/%v", Bitno(b), v.etype)
-
- case TINT8,
- TUINT8,
- TINT16,
- TUINT16,
- TINT32,
- TUINT32,
- TINT64,
- TUINT64,
- TINT,
- TUINT,
- TUINTPTR,
- TBOOL,
- TPTR32,
- TPTR64:
- i := Thearch.BtoR(^b)
- if i != 0 && r.cost > 0 {
- r.regno = int16(i)
- return Thearch.RtoB(i)
- }
-
- case TFLOAT32, TFLOAT64:
- i := Thearch.BtoF(^b)
- if i != 0 && r.cost > 0 {
- r.regno = int16(i)
- return Thearch.FtoB(i)
- }
- }
-
- return 0
-}
-
-func LOAD(r *Reg, z int) uint64 {
- return ^r.refbehind.b[z] & r.refahead.b[z]
-}
-
-func STORE(r *Reg, z int) uint64 {
- return ^r.calbehind.b[z] & r.calahead.b[z]
-}
-
-// Cost parameters
-const (
- CLOAD = 5 // cost of load
- CREF = 5 // cost of reference if not registerized
- LOOP = 3 // loop execution count (applied in popt.go)
-)
-
-func paint1(f *Flow, bn int) {
- z := bn / 64
- bb := uint64(1 << uint(bn%64))
- r := f.Data.(*Reg)
- if r.act.b[z]&bb != 0 {
- return
- }
- var f1 *Flow
- var r1 *Reg
- for {
- if r.refbehind.b[z]&bb == 0 {
- break
- }
- f1 = f.P1
- if f1 == nil {
- break
- }
- r1 = f1.Data.(*Reg)
- if r1.refahead.b[z]&bb == 0 {
- break
- }
- if r1.act.b[z]&bb != 0 {
- break
- }
- f = f1
- r = r1
- }
-
- if LOAD(r, z)&^(r.set.b[z]&^(r.use1.b[z]|r.use2.b[z]))&bb != 0 {
- change -= CLOAD * int(f.Loop)
- }
-
- for {
- r.act.b[z] |= bb
-
- if f.Prog.As != obj.ANOP { // don't give credit for NOPs
- if r.use1.b[z]&bb != 0 {
- change += CREF * int(f.Loop)
- }
- if (r.use2.b[z]|r.set.b[z])&bb != 0 {
- change += CREF * int(f.Loop)
- }
- }
-
- if STORE(r, z)&r.regdiff.b[z]&bb != 0 {
- change -= CLOAD * int(f.Loop)
- }
-
- if r.refbehind.b[z]&bb != 0 {
- for f1 = f.P2; f1 != nil; f1 = f1.P2link {
- if (f1.Data.(*Reg)).refahead.b[z]&bb != 0 {
- paint1(f1, bn)
- }
- }
- }
-
- if r.refahead.b[z]&bb == 0 {
- break
- }
- f1 = f.S2
- if f1 != nil {
- if (f1.Data.(*Reg)).refbehind.b[z]&bb != 0 {
- paint1(f1, bn)
- }
- }
- f = f.S1
- if f == nil {
- break
- }
- r = f.Data.(*Reg)
- if r.act.b[z]&bb != 0 {
- break
- }
- if r.refbehind.b[z]&bb == 0 {
- break
- }
- }
-}
-
-func paint2(f *Flow, bn int, depth int) uint64 {
- z := bn / 64
- bb := uint64(1 << uint(bn%64))
- vreg := regbits
- r := f.Data.(*Reg)
- if r.act.b[z]&bb == 0 {
- return vreg
- }
- var r1 *Reg
- var f1 *Flow
- for {
- if r.refbehind.b[z]&bb == 0 {
- break
- }
- f1 = f.P1
- if f1 == nil {
- break
- }
- r1 = f1.Data.(*Reg)
- if r1.refahead.b[z]&bb == 0 {
- break
- }
- if r1.act.b[z]&bb == 0 {
- break
- }
- f = f1
- r = r1
- }
-
- for {
- if Debug['R'] != 0 && Debug['v'] != 0 {
- fmt.Printf(" paint2 %d %v\n", depth, f.Prog)
- }
-
- r.act.b[z] &^= bb
-
- vreg |= r.regu
-
- if r.refbehind.b[z]&bb != 0 {
- for f1 = f.P2; f1 != nil; f1 = f1.P2link {
- if (f1.Data.(*Reg)).refahead.b[z]&bb != 0 {
- vreg |= paint2(f1, bn, depth+1)
- }
- }
- }
-
- if r.refahead.b[z]&bb == 0 {
- break
- }
- f1 = f.S2
- if f1 != nil {
- if (f1.Data.(*Reg)).refbehind.b[z]&bb != 0 {
- vreg |= paint2(f1, bn, depth+1)
- }
- }
- f = f.S1
- if f == nil {
- break
- }
- r = f.Data.(*Reg)
- if r.act.b[z]&bb == 0 {
- break
- }
- if r.refbehind.b[z]&bb == 0 {
- break
- }
- }
-
- return vreg
-}
-
-func paint3(f *Flow, bn int, rb uint64, rn int) {
- z := bn / 64
- bb := uint64(1 << uint(bn%64))
- r := f.Data.(*Reg)
- if r.act.b[z]&bb != 0 {
- return
- }
- var r1 *Reg
- var f1 *Flow
- for {
- if r.refbehind.b[z]&bb == 0 {
- break
- }
- f1 = f.P1
- if f1 == nil {
- break
- }
- r1 = f1.Data.(*Reg)
- if r1.refahead.b[z]&bb == 0 {
- break
- }
- if r1.act.b[z]&bb != 0 {
- break
- }
- f = f1
- r = r1
- }
-
- if LOAD(r, z)&^(r.set.b[z]&^(r.use1.b[z]|r.use2.b[z]))&bb != 0 {
- addmove(f, bn, rn, 0)
- }
- var p *obj.Prog
- for {
- r.act.b[z] |= bb
- p = f.Prog
-
- if r.use1.b[z]&bb != 0 {
- if Debug['R'] != 0 && Debug['v'] != 0 {
- fmt.Printf("%v", p)
- }
- addreg(&p.From, rn)
- if Debug['R'] != 0 && Debug['v'] != 0 {
- fmt.Printf(" ===change== %v\n", p)
- }
- }
-
- if (r.use2.b[z]|r.set.b[z])&bb != 0 {
- if Debug['R'] != 0 && Debug['v'] != 0 {
- fmt.Printf("%v", p)
- }
- addreg(&p.To, rn)
- if Debug['R'] != 0 && Debug['v'] != 0 {
- fmt.Printf(" ===change== %v\n", p)
- }
- }
-
- if STORE(r, z)&r.regdiff.b[z]&bb != 0 {
- addmove(f, bn, rn, 1)
- }
- r.regu |= rb
-
- if r.refbehind.b[z]&bb != 0 {
- for f1 = f.P2; f1 != nil; f1 = f1.P2link {
- if (f1.Data.(*Reg)).refahead.b[z]&bb != 0 {
- paint3(f1, bn, rb, rn)
- }
- }
- }
-
- if r.refahead.b[z]&bb == 0 {
- break
- }
- f1 = f.S2
- if f1 != nil {
- if (f1.Data.(*Reg)).refbehind.b[z]&bb != 0 {
- paint3(f1, bn, rb, rn)
- }
- }
- f = f.S1
- if f == nil {
- break
- }
- r = f.Data.(*Reg)
- if r.act.b[z]&bb != 0 {
- break
- }
- if r.refbehind.b[z]&bb == 0 {
- break
- }
- }
-}
-
-func addreg(a *obj.Addr, rn int) {
- a.Sym = nil
- a.Node = nil
- a.Offset = 0
- a.Type = obj.TYPE_REG
- a.Reg = int16(rn)
- a.Name = 0
-
- Ostats.Ncvtreg++
-}
-
-func dumpone(f *Flow, isreg int) {
- fmt.Printf("%d:%v", f.Loop, f.Prog)
- if isreg != 0 {
- r := f.Data.(*Reg)
- var bit Bits
- for z := 0; z < BITS; z++ {
- bit.b[z] = r.set.b[z] | r.use1.b[z] | r.use2.b[z] | r.refbehind.b[z] | r.refahead.b[z] | r.calbehind.b[z] | r.calahead.b[z] | r.regdiff.b[z] | r.act.b[z] | 0
- }
- if bany(&bit) {
- fmt.Printf("\t")
- if bany(&r.set) {
- fmt.Printf(" s:%v", &r.set)
- }
- if bany(&r.use1) {
- fmt.Printf(" u1:%v", &r.use1)
- }
- if bany(&r.use2) {
- fmt.Printf(" u2:%v", &r.use2)
- }
- if bany(&r.refbehind) {
- fmt.Printf(" rb:%v ", &r.refbehind)
- }
- if bany(&r.refahead) {
- fmt.Printf(" ra:%v ", &r.refahead)
- }
- if bany(&r.calbehind) {
- fmt.Printf(" cb:%v ", &r.calbehind)
- }
- if bany(&r.calahead) {
- fmt.Printf(" ca:%v ", &r.calahead)
- }
- if bany(&r.regdiff) {
- fmt.Printf(" d:%v ", &r.regdiff)
- }
- if bany(&r.act) {
- fmt.Printf(" a:%v ", &r.act)
- }
- }
- }
-
- fmt.Printf("\n")
-}
-
-func Dumpit(str string, r0 *Flow, isreg int) {
- var r1 *Flow
-
- fmt.Printf("\n%s\n", str)
- for r := r0; r != nil; r = r.Link {
- dumpone(r, isreg)
- r1 = r.P2
- if r1 != nil {
- fmt.Printf("\tpred:")
- for ; r1 != nil; r1 = r1.P2link {
- fmt.Printf(" %.4d", uint(int(r1.Prog.Pc)))
- }
- if r.P1 != nil {
- fmt.Printf(" (and %.4d)", uint(int(r.P1.Prog.Pc)))
- } else {
- fmt.Printf(" (only)")
- }
- fmt.Printf("\n")
- }
-
- // Print successors if it's not just the next one
- if r.S1 != r.Link || r.S2 != nil {
- fmt.Printf("\tsucc:")
- if r.S1 != nil {
- fmt.Printf(" %.4d", uint(int(r.S1.Prog.Pc)))
- }
- if r.S2 != nil {
- fmt.Printf(" %.4d", uint(int(r.S2.Prog.Pc)))
- }
- fmt.Printf("\n")
- }
- }
-}
-
-func regopt(firstp *obj.Prog) {
- mergetemp(firstp)
-
- // control flow is more complicated in generated go code
- // than in generated c code. define pseudo-variables for
- // registers, so we have complete register usage information.
- var nreg int
- regnames := Thearch.Regnames(&nreg)
-
- nvar = nreg
- for i := 0; i < nreg; i++ {
- vars[i] = Var{}
- }
- for i := 0; i < nreg; i++ {
- if regnodes[i] == nil {
- regnodes[i] = newname(Lookup(regnames[i]))
- }
- vars[i].node = regnodes[i]
- }
-
- regbits = Thearch.Excludedregs()
- externs = zbits
- params = zbits
- consts = zbits
- addrs = zbits
- ivar = zbits
- ovar = zbits
-
- // pass 1
- // build aux data structure
- // allocate pcs
- // find use and set of variables
- g := Flowstart(firstp, func() interface{} { return new(Reg) })
- if g == nil {
- for i := 0; i < nvar; i++ {
- vars[i].node.SetOpt(nil)
- }
- return
- }
-
- firstf := g.Start
-
- for f := firstf; f != nil; f = f.Link {
- p := f.Prog
- // AVARLIVE must be considered a use, do not skip it.
- // Otherwise the variable will be optimized away,
- // and the whole point of AVARLIVE is to keep it on the stack.
- if p.As == obj.AVARDEF || p.As == obj.AVARKILL {
- continue
- }
-
- // Avoid making variables for direct-called functions.
- if p.As == obj.ACALL && p.To.Type == obj.TYPE_MEM && p.To.Name == obj.NAME_EXTERN {
- continue
- }
-
- // from vs to doesn't matter for registers.
- r := f.Data.(*Reg)
- r.use1.b[0] |= p.Info.Reguse | p.Info.Regindex
- r.set.b[0] |= p.Info.Regset
-
- bit := mkvar(f, &p.From)
- if bany(&bit) {
- if p.Info.Flags&LeftAddr != 0 {
- setaddrs(bit)
- }
- if p.Info.Flags&LeftRead != 0 {
- for z := 0; z < BITS; z++ {
- r.use1.b[z] |= bit.b[z]
- }
- }
- if p.Info.Flags&LeftWrite != 0 {
- for z := 0; z < BITS; z++ {
- r.set.b[z] |= bit.b[z]
- }
- }
- }
-
- // Compute used register for reg
- if p.Info.Flags&RegRead != 0 {
- r.use1.b[0] |= Thearch.RtoB(int(p.Reg))
- }
-
- // Currently we never generate three register forms.
- // If we do, this will need to change.
- if p.From3Type() != obj.TYPE_NONE && p.From3Type() != obj.TYPE_CONST {
- Fatalf("regopt not implemented for from3")
- }
-
- bit = mkvar(f, &p.To)
- if bany(&bit) {
- if p.Info.Flags&RightAddr != 0 {
- setaddrs(bit)
- }
- if p.Info.Flags&RightRead != 0 {
- for z := 0; z < BITS; z++ {
- r.use2.b[z] |= bit.b[z]
- }
- }
- if p.Info.Flags&RightWrite != 0 {
- for z := 0; z < BITS; z++ {
- r.set.b[z] |= bit.b[z]
- }
- }
- }
- }
-
- for i := 0; i < nvar; i++ {
- v := &vars[i]
- if v.addr != 0 {
- bit := blsh(uint(i))
- for z := 0; z < BITS; z++ {
- addrs.b[z] |= bit.b[z]
- }
- }
-
- if Debug['R'] != 0 && Debug['v'] != 0 {
- fmt.Printf("bit=%2d addr=%d et=%v w=%-2d s=%v + %d\n", i, v.addr, v.etype, v.width, v.node, v.offset)
- }
- }
-
- if Debug['R'] != 0 && Debug['v'] != 0 {
- Dumpit("pass1", firstf, 1)
- }
-
- // pass 2
- // find looping structure
- flowrpo(g)
-
- if Debug['R'] != 0 && Debug['v'] != 0 {
- Dumpit("pass2", firstf, 1)
- }
-
- // pass 2.5
- // iterate propagating fat vardef covering forward
- // r->act records vars with a VARDEF since the last CALL.
- // (r->act will be reused in pass 5 for something else,
- // but we'll be done with it by then.)
- active := 0
-
- for f := firstf; f != nil; f = f.Link {
- f.Active = 0
- r := f.Data.(*Reg)
- r.act = zbits
- }
-
- for f := firstf; f != nil; f = f.Link {
- p := f.Prog
- if p.As == obj.AVARDEF && Isfat(((p.To.Node).(*Node)).Type) && ((p.To.Node).(*Node)).Opt() != nil {
- active++
- walkvardef(p.To.Node.(*Node), f, active)
- }
- }
-
- // pass 3
- // iterate propagating usage
- // back until flow graph is complete
- var f1 *Flow
- var i int
- var f *Flow
-loop1:
- change = 0
-
- for f = firstf; f != nil; f = f.Link {
- f.Active = 0
- }
- for f = firstf; f != nil; f = f.Link {
- if f.Prog.As == obj.ARET {
- prop(f, zbits, zbits)
- }
- }
-
- // pick up unreachable code
-loop11:
- i = 0
-
- for f = firstf; f != nil; f = f1 {
- f1 = f.Link
- if f1 != nil && f1.Active != 0 && f.Active == 0 {
- prop(f, zbits, zbits)
- i = 1
- }
- }
-
- if i != 0 {
- goto loop11
- }
- if change != 0 {
- goto loop1
- }
-
- if Debug['R'] != 0 && Debug['v'] != 0 {
- Dumpit("pass3", firstf, 1)
- }
-
- // pass 4
- // iterate propagating register/variable synchrony
- // forward until graph is complete
-loop2:
- change = 0
-
- for f = firstf; f != nil; f = f.Link {
- f.Active = 0
- }
- synch(firstf, zbits)
- if change != 0 {
- goto loop2
- }
-
- if Debug['R'] != 0 && Debug['v'] != 0 {
- Dumpit("pass4", firstf, 1)
- }
-
- // pass 4.5
- // move register pseudo-variables into regu.
- mask := uint64((1 << uint(nreg)) - 1)
- for f := firstf; f != nil; f = f.Link {
- r := f.Data.(*Reg)
- r.regu = (r.refbehind.b[0] | r.set.b[0]) & mask
- r.set.b[0] &^= mask
- r.use1.b[0] &^= mask
- r.use2.b[0] &^= mask
- r.refbehind.b[0] &^= mask
- r.refahead.b[0] &^= mask
- r.calbehind.b[0] &^= mask
- r.calahead.b[0] &^= mask
- r.regdiff.b[0] &^= mask
- r.act.b[0] &^= mask
- }
-
- if Debug['R'] != 0 && Debug['v'] != 0 {
- Dumpit("pass4.5", firstf, 1)
- }
-
- // pass 5
- // isolate regions
- // calculate costs (paint1)
- var bit Bits
- if f := firstf; f != nil {
- r := f.Data.(*Reg)
- for z := 0; z < BITS; z++ {
- bit.b[z] = (r.refahead.b[z] | r.calahead.b[z]) &^ (externs.b[z] | params.b[z] | addrs.b[z] | consts.b[z])
- }
- if bany(&bit) && !f.Refset {
- // should never happen - all variables are preset
- if Debug['w'] != 0 {
- fmt.Printf("%v: used and not set: %v\n", f.Prog.Line(), &bit)
- }
- f.Refset = true
- }
- }
-
- for f := firstf; f != nil; f = f.Link {
- (f.Data.(*Reg)).act = zbits
- }
- nregion = 0
- region = region[:0]
- for f := firstf; f != nil; f = f.Link {
- r := f.Data.(*Reg)
- for z := 0; z < BITS; z++ {
- bit.b[z] = r.set.b[z] &^ (r.refahead.b[z] | r.calahead.b[z] | addrs.b[z])
- }
- if bany(&bit) && !f.Refset {
- if Debug['w'] != 0 {
- fmt.Printf("%v: set and not used: %v\n", f.Prog.Line(), &bit)
- }
- f.Refset = true
- Thearch.Excise(f)
- }
-
- for z := 0; z < BITS; z++ {
- bit.b[z] = LOAD(r, z) &^ (r.act.b[z] | addrs.b[z])
- }
- for bany(&bit) {
- i = bnum(&bit)
- change = 0
- paint1(f, i)
- biclr(&bit, uint(i))
- if change <= 0 {
- continue
- }
- if nregion >= MaxRgn {
- nregion++
- continue
- }
-
- region = append(region, Rgn{
- enter: f,
- cost: int16(change),
- varno: int16(i),
- })
- nregion++
- }
- }
-
- if false && Debug['v'] != 0 && strings.Contains(Curfn.Func.Nname.Sym.Name, "Parse") {
- Warn("regions: %d\n", nregion)
- }
- if nregion >= MaxRgn {
- if Debug['v'] != 0 {
- Warn("too many regions: %d\n", nregion)
- }
- nregion = MaxRgn
- }
-
- sort.Sort(rcmp(region[:nregion]))
-
- if Debug['R'] != 0 && Debug['v'] != 0 {
- Dumpit("pass5", firstf, 1)
- }
-
- // pass 6
- // determine used registers (paint2)
- // replace code (paint3)
- if Debug['R'] != 0 && Debug['v'] != 0 {
- fmt.Printf("\nregisterizing\n")
- }
- for i := 0; i < nregion; i++ {
- rgp := ®ion[i]
- if Debug['R'] != 0 && Debug['v'] != 0 {
- fmt.Printf("region %d: cost %d varno %d enter %d\n", i, rgp.cost, rgp.varno, rgp.enter.Prog.Pc)
- }
- bit = blsh(uint(rgp.varno))
- usedreg := paint2(rgp.enter, int(rgp.varno), 0)
- vreg := allreg(usedreg, rgp)
- if rgp.regno != 0 {
- if Debug['R'] != 0 && Debug['v'] != 0 {
- v := &vars[rgp.varno]
- fmt.Printf("registerize %v+%d (bit=%2d et=%v) in %v usedreg=%#x vreg=%#x\n", v.node, v.offset, rgp.varno, v.etype, obj.Rconv(int(rgp.regno)), usedreg, vreg)
- }
-
- paint3(rgp.enter, int(rgp.varno), vreg, int(rgp.regno))
- }
- }
-
- // free aux structures. peep allocates new ones.
- for i := 0; i < nvar; i++ {
- vars[i].node.SetOpt(nil)
- }
- Flowend(g)
- firstf = nil
-
- if Debug['R'] != 0 && Debug['v'] != 0 {
- // Rebuild flow graph, since we inserted instructions
- g := Flowstart(firstp, nil)
- firstf = g.Start
- Dumpit("pass6", firstf, 0)
- Flowend(g)
- firstf = nil
- }
-
- // pass 7
- // peep-hole on basic block
- if Debug['R'] == 0 || Debug['P'] != 0 {
- Thearch.Peep(firstp)
- }
-
- // eliminate nops
- for p := firstp; p != nil; p = p.Link {
- for p.Link != nil && p.Link.As == obj.ANOP {
- p.Link = p.Link.Link
- }
- if p.To.Type == obj.TYPE_BRANCH {
- for p.To.Val.(*obj.Prog) != nil && p.To.Val.(*obj.Prog).As == obj.ANOP {
- p.To.Val = p.To.Val.(*obj.Prog).Link
- }
- }
- }
-
- if Debug['R'] != 0 {
- if Ostats.Ncvtreg != 0 || Ostats.Nspill != 0 || Ostats.Nreload != 0 || Ostats.Ndelmov != 0 || Ostats.Nvar != 0 || Ostats.Naddr != 0 || false {
- fmt.Printf("\nstats\n")
- }
-
- if Ostats.Ncvtreg != 0 {
- fmt.Printf("\t%4d cvtreg\n", Ostats.Ncvtreg)
- }
- if Ostats.Nspill != 0 {
- fmt.Printf("\t%4d spill\n", Ostats.Nspill)
- }
- if Ostats.Nreload != 0 {
- fmt.Printf("\t%4d reload\n", Ostats.Nreload)
- }
- if Ostats.Ndelmov != 0 {
- fmt.Printf("\t%4d delmov\n", Ostats.Ndelmov)
- }
- if Ostats.Nvar != 0 {
- fmt.Printf("\t%4d var\n", Ostats.Nvar)
- }
- if Ostats.Naddr != 0 {
- fmt.Printf("\t%4d addr\n", Ostats.Naddr)
- }
-
- Ostats = OptStats{}
- }
-}
-
-// bany reports whether any bits in a are set.
-func bany(a *Bits) bool {
- for _, x := range &a.b { // & to avoid making a copy of a.b
- if x != 0 {
- return true
- }
- }
- return false
-}
-
-// bnum reports the lowest index of a 1 bit in a.
-func bnum(a *Bits) int {
- for i, x := range &a.b { // & to avoid making a copy of a.b
- if x != 0 {
- return 64*i + Bitno(x)
- }
- }
-
- Fatalf("bad in bnum")
- return 0
-}
-
-// blsh returns a Bits with 1 at index n, 0 elsewhere (1<<n).
-func blsh(n uint) Bits {
- c := zbits
- c.b[n/64] = 1 << (n % 64)
- return c
-}
-
-// btest reports whether bit n is 1.
-func btest(a *Bits, n uint) bool {
- return a.b[n/64]&(1<<(n%64)) != 0
-}
-
-// biset sets bit n to 1.
-func biset(a *Bits, n uint) {
- a.b[n/64] |= 1 << (n % 64)
-}
-
-// biclr sets bit n to 0.
-func biclr(a *Bits, n uint) {
- a.b[n/64] &^= (1 << (n % 64))
-}
-
-// Bitno reports the lowest index of a 1 bit in b.
-// It calls Fatalf if there is no 1 bit.
-func Bitno(b uint64) int {
- if b == 0 {
- Fatalf("bad in bitno")
- }
- n := 0
- if b&(1<<32-1) == 0 {
- n += 32
- b >>= 32
- }
- if b&(1<<16-1) == 0 {
- n += 16
- b >>= 16
- }
- if b&(1<<8-1) == 0 {
- n += 8
- b >>= 8
- }
- if b&(1<<4-1) == 0 {
- n += 4
- b >>= 4
- }
- if b&(1<<2-1) == 0 {
- n += 2
- b >>= 2
- }
- if b&1 == 0 {
- n++
- }
- return n
-}
-
-// String returns a space-separated list of the variables represented by bits.
-func (bits Bits) String() string {
- // Note: This method takes a value receiver, both for convenience
- // and to make it safe to modify the bits as we process them.
- // Even so, most prints above use &bits, because then the value
- // being stored in the interface{} is a pointer and does not require
- // an allocation and copy to create the interface{}.
- var buf bytes.Buffer
- sep := ""
- for bany(&bits) {
- i := bnum(&bits)
- buf.WriteString(sep)
- sep = " "
- v := &vars[i]
- if v.node == nil || v.node.Sym == nil {
- fmt.Fprintf(&buf, "$%d", i)
- } else {
- fmt.Fprintf(&buf, "%s(%d)", v.node.Sym.Name, i)
- if v.offset != 0 {
- fmt.Fprintf(&buf, "%+d", v.offset)
- }
- }
- biclr(&bits, uint(i))
- }
- return buf.String()
-}
diff --git a/src/cmd/compile/internal/gc/select.go b/src/cmd/compile/internal/gc/select.go
index 120a9b8..d999190 100644
--- a/src/cmd/compile/internal/gc/select.go
+++ b/src/cmd/compile/internal/gc/select.go
@@ -24,12 +24,12 @@ func typecheckselect(sel *Node) {
if ncase.List.Len() == 0 {
// default
if def != nil {
- Yyerror("multiple defaults in select (first at %v)", def.Line())
+ yyerror("multiple defaults in select (first at %v)", def.Line())
} else {
def = ncase
}
} else if ncase.List.Len() > 1 {
- Yyerror("select cases cannot be lists")
+ yyerror("select cases cannot be lists")
} else {
ncase.List.SetIndex(0, typecheck(ncase.List.Index(0), Etop))
n = ncase.List.Index(0)
@@ -38,9 +38,9 @@ func typecheckselect(sel *Node) {
setlineno(n)
switch n.Op {
default:
- Yyerror("select case must be receive, send or assign recv")
+ yyerror("select case must be receive, send or assign recv")
- // convert x = <-c into OSELRECV(x, <-c).
+ // convert x = <-c into OSELRECV(x, <-c).
// remove implicit conversions; the eventual assignment
// will reintroduce them.
case OAS:
@@ -49,7 +49,7 @@ func typecheckselect(sel *Node) {
}
if n.Right.Op != ORECV {
- Yyerror("select assignment must have receive on right hand side")
+ yyerror("select assignment must have receive on right hand side")
break
}
@@ -58,7 +58,7 @@ func typecheckselect(sel *Node) {
// convert x, ok = <-c into OSELRECV2(x, <-c) with ntest=ok
case OAS2RECV:
if n.Rlist.First().Op != ORECV {
- Yyerror("select assignment must have receive on right hand side")
+ yyerror("select assignment must have receive on right hand side")
break
}
@@ -70,7 +70,7 @@ func typecheckselect(sel *Node) {
// convert <-c into OSELRECV(N, <-c)
case ORECV:
- n = Nod(OSELRECV, nil, n)
+ n = nod(OSELRECV, nil, n)
n.Typecheck = 1
ncase.Left = n
@@ -143,7 +143,7 @@ func walkselect(sel *Node) {
}
n.Op = OAS2
- n.List.Set(append([]*Node{n.Left}, n.List.Slice()...))
+ n.List.Prepend(n.Left)
n.Rlist.Set1(n.Right)
n.Right = nil
n.Left = nil
@@ -152,9 +152,9 @@ func walkselect(sel *Node) {
}
// if ch == nil { block() }; n;
- a := Nod(OIF, nil, nil)
+ a := nod(OIF, nil, nil)
- a.Left = Nod(OEQ, ch, nodnil())
+ a.Left = nod(OEQ, ch, nodnil())
var ln Nodes
ln.Set(l)
a.Nbody.Set1(mkcall("block", nil, &ln))
@@ -179,7 +179,7 @@ func walkselect(sel *Node) {
}
switch n.Op {
case OSEND:
- n.Right = Nod(OADDR, n.Right, nil)
+ n.Right = nod(OADDR, n.Right, nil)
n.Right = typecheck(n.Right, Erv)
case OSELRECV, OSELRECV2:
@@ -187,14 +187,14 @@ 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, nod(OADDR, n.List.First(), nil))
n.List.SetIndex(0, typecheck(n.List.Index(0), Erv))
}
if n.Left == nil {
n.Left = nodnil()
} else {
- n.Left = Nod(OADDR, n.Left, nil)
+ n.Left = nod(OADDR, n.Left, nil)
n.Left = typecheck(n.Left, Erv)
}
}
@@ -214,7 +214,7 @@ func walkselect(sel *Node) {
n := cas.Left
setlineno(n)
- r := Nod(OIF, nil, nil)
+ r := nod(OIF, nil, nil)
r.Ninit.Set(cas.Ninit.Slice())
switch n.Op {
default:
@@ -228,7 +228,7 @@ func walkselect(sel *Node) {
// if c != nil && selectnbrecv(&v, c) { body } else { default body }
case OSELRECV:
- r = Nod(OIF, nil, nil)
+ r = nod(OIF, nil, nil)
r.Ninit.Set(cas.Ninit.Slice())
ch := n.Right.Left
@@ -236,7 +236,7 @@ func walkselect(sel *Node) {
// if c != nil && selectnbrecv2(&v, c) { body } else { default body }
case OSELRECV2:
- r = Nod(OIF, nil, nil)
+ r = nod(OIF, nil, nil)
r.Ninit.Set(cas.Ninit.Slice())
ch := n.Right.Left
@@ -257,18 +257,18 @@ func walkselect(sel *Node) {
setlineno(sel)
selv = temp(selecttype(int32(sel.Xoffset)))
- r = Nod(OAS, selv, nil)
+ 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]))
- r = mkcall("newselect", nil, nil, var_, Nodintconst(selv.Type.Width), Nodintconst(sel.Xoffset))
+ var_ = conv(conv(nod(OADDR, selv, nil), Types[TUNSAFEPTR]), ptrto(Types[TUINT8]))
+ r = mkcall("newselect", nil, nil, var_, nodintconst(selv.Type.Width), nodintconst(sel.Xoffset))
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 = nod(OIF, nil, nil)
r.Ninit.Set(cas.Ninit.Slice())
cas.Ninit.Set(nil)
if n != nil {
@@ -299,10 +299,10 @@ func walkselect(sel *Node) {
}
// selv is no longer alive after use.
- r.Nbody.Append(Nod(OVARKILL, selv, nil))
+ r.Nbody.Append(nod(OVARKILL, selv, nil))
r.Nbody.AppendNodes(&cas.Nbody)
- r.Nbody.Append(Nod(OBREAK, nil, nil))
+ r.Nbody.Append(nod(OBREAK, nil, nil))
init = append(init, r)
}
@@ -323,29 +323,29 @@ func selecttype(size int32) *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 := 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 := 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
diff --git a/src/cmd/compile/internal/gc/sinit.go b/src/cmd/compile/internal/gc/sinit.go
index 4469d71..1192f3f 100644
--- a/src/cmd/compile/internal/gc/sinit.go
+++ b/src/cmd/compile/internal/gc/sinit.go
@@ -4,9 +4,7 @@
package gc
-import (
- "fmt"
-)
+import "fmt"
// static initialization
const (
@@ -164,7 +162,7 @@ func foundinitloop(node, visited *Node) {
// those errors probably confused us and
// there might not be a loop. Let the user
// fix those first.
- Flusherrors()
+ flusherrors()
if nerrors > 0 {
errorexit()
}
@@ -201,7 +199,7 @@ func init2(n *Node, out *[]*Node) {
}
if n.Op == ONAME && n.Ninit.Len() != 0 {
- Fatalf("name %v with ninit: %v\n", n.Sym, Nconv(n, FmtSign))
+ Fatalf("name %v with ninit: %+v\n", n.Sym, n)
}
init1(n, out)
@@ -288,7 +286,7 @@ func staticcopy(l *Node, r *Node, out *[]*Node) bool {
orig := r
r = r.Name.Defn.Right
- for r.Op == OCONVNOP {
+ for r.Op == OCONVNOP && !eqtype(r.Type, l.Type) {
r = r.Left
}
@@ -297,7 +295,7 @@ func staticcopy(l *Node, r *Node, out *[]*Node) bool {
if staticcopy(l, r, out) {
return true
}
- *out = append(*out, Nod(OAS, l, r))
+ *out = append(*out, nod(OAS, l, r))
return true
case OLITERAL:
@@ -316,33 +314,26 @@ func staticcopy(l *Node, r *Node, out *[]*Node) bool {
case OPTRLIT:
switch r.Left.Op {
- //dump("not static addr", r);
- default:
- break
-
+ case OARRAYLIT, OSLICELIT, OSTRUCTLIT, OMAPLIT:
// copy pointer
- case OARRAYLIT, OSTRUCTLIT, OMAPLIT:
- gdata(l, Nod(OADDR, inittemps[r], nil), int(l.Type.Width))
-
+ gdata(l, nod(OADDR, inittemps[r], nil), int(l.Type.Width))
return true
}
- case OARRAYLIT:
- if r.Type.IsSlice() {
- // copy slice
- a := inittemps[r]
+ case OSLICELIT:
+ // copy slice
+ a := inittemps[r]
- 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)
- n.Xoffset = l.Xoffset + int64(Array_cap)
- gdata(&n, r.Right, Widthint)
- return true
- }
- fallthrough
- case OSTRUCTLIT:
+ 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)
+ n.Xoffset = l.Xoffset + int64(array_cap)
+ gdata(&n, r.Right, Widthint)
+ return true
+
+ case OARRAYLIT, OSTRUCTLIT:
p := initplans[r]
n := *l
@@ -353,20 +344,20 @@ func staticcopy(l *Node, r *Node, out *[]*Node) bool {
if e.Expr.Op == OLITERAL {
gdata(&n, e.Expr, int(n.Type.Width))
} else {
- ll := Nod(OXXX, nil, nil)
+ ll := nod(OXXX, nil, nil)
*ll = n
ll.Orig = ll // completely separate copy
if !staticassign(ll, e.Expr, out) {
// Requires computation, but we're
// copying someone else's computation.
- rr := Nod(OXXX, nil, nil)
+ rr := nod(OXXX, nil, nil)
*rr = *orig
rr.Orig = rr // completely separate copy
rr.Type = ll.Type
rr.Xoffset += e.Xoffset
setlineno(rr)
- *out = append(*out, Nod(OAS, ll, rr))
+ *out = append(*out, nod(OAS, ll, rr))
}
}
}
@@ -405,16 +396,16 @@ func staticassign(l *Node, r *Node, out *[]*Node) bool {
case OPTRLIT:
switch r.Left.Op {
- case OARRAYLIT, OMAPLIT, OSTRUCTLIT:
+ case OARRAYLIT, OSLICELIT, OMAPLIT, OSTRUCTLIT:
// Init pointer.
- a := staticname(r.Left.Type, 1)
+ a := staticname(r.Left.Type)
inittemps[r] = a
- gdata(l, Nod(OADDR, a, nil), int(l.Type.Width))
+ gdata(l, nod(OADDR, a, nil), int(l.Type.Width))
// Init underlying literal.
if !staticassign(a, r.Left, out) {
- *out = append(*out, Nod(OAS, a, r.Left))
+ *out = append(*out, nod(OAS, a, r.Left))
}
return true
}
@@ -427,28 +418,26 @@ func staticassign(l *Node, r *Node, out *[]*Node) bool {
return true
}
- case OARRAYLIT:
+ case OSLICELIT:
initplan(r)
- if r.Type.IsSlice() {
- // Init slice.
- bound := r.Right.Int64()
- ta := typArray(r.Type.Elem(), bound)
- a := staticname(ta, 1)
- 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)
- n.Xoffset = l.Xoffset + int64(Array_cap)
- gdata(&n, r.Right, Widthint)
-
- // Fall through to init underlying array.
- l = a
- }
+ // Init slice.
+ bound := r.Right.Int64()
+ ta := typArray(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)
+ n.Xoffset = l.Xoffset + int64(array_cap)
+ gdata(&n, r.Right, Widthint)
+
+ // Fall through to init underlying array.
+ l = a
fallthrough
- case OSTRUCTLIT:
+ case OARRAYLIT, OSTRUCTLIT:
initplan(r)
p := initplans[r]
@@ -461,11 +450,11 @@ func staticassign(l *Node, r *Node, out *[]*Node) bool {
gdata(&n, e.Expr, int(n.Type.Width))
} else {
setlineno(e.Expr)
- a := Nod(OXXX, nil, nil)
+ a := nod(OXXX, nil, nil)
*a = n
a.Orig = a // completely separate copy
if !staticassign(a, e.Expr, out) {
- *out = append(*out, Nod(OAS, a, e.Expr))
+ *out = append(*out, nod(OAS, a, e.Expr))
}
}
}
@@ -473,7 +462,6 @@ func staticassign(l *Node, r *Node, out *[]*Node) bool {
return true
case OMAPLIT:
- // TODO: Table-driven map insert.
break
case OCLOSURE:
@@ -489,23 +477,102 @@ func staticassign(l *Node, r *Node, out *[]*Node) bool {
} else {
closuredebugruntimecheck(r)
}
+
+ case OCONVIFACE:
+ // This logic is mirrored in isStaticCompositeLiteral.
+ // If you change something here, change it there, and vice versa.
+
+ // Determine the underlying concrete type and value we are converting from.
+ val := r
+ for val.Op == OCONVIFACE {
+ val = val.Left
+ }
+ if val.Type.IsInterface() {
+ // val is an interface type.
+ // If val is nil, we can statically initialize l;
+ // both words are zero and so there no work to do, so report success.
+ // If val is non-nil, we have no concrete type to record,
+ // and we won't be able to statically initialize its value, so report failure.
+ return Isconst(val, CTNIL)
+ }
+
+ var itab *Node
+ if l.Type.IsEmptyInterface() {
+ itab = typename(val.Type)
+ } else {
+ itab = itabname(val.Type, l.Type)
+ }
+
+ // Create a copy of l to modify while we emit data.
+ n := *l
+
+ // Emit itab, advance offset.
+ gdata(&n, itab, Widthptr)
+ n.Xoffset += int64(Widthptr)
+
+ // Emit data.
+ if isdirectiface(val.Type) {
+ if Isconst(val, CTNIL) {
+ // Nil is zero, nothing to do.
+ return true
+ }
+ // Copy val directly into n.
+ n.Type = val.Type
+ setlineno(val)
+ a := nod(OXXX, nil, nil)
+ *a = n
+ a.Orig = a
+ if !staticassign(a, val, out) {
+ *out = append(*out, nod(OAS, a, val))
+ }
+ } else {
+ // Construct temp to hold val, write pointer to temp into n.
+ a := staticname(val.Type)
+ inittemps[val] = a
+ if !staticassign(a, val, out) {
+ *out = append(*out, nod(OAS, a, val))
+ }
+ ptr := nod(OADDR, a, nil)
+ n.Type = ptrto(val.Type)
+ gdata(&n, ptr, Widthptr)
+ }
+
+ return true
}
//dump("not static", r);
return false
}
+// initContext is the context in which static data is populated.
+// It is either in an init function or in any other function.
+// Static data populated in an init function will be written either
+// zero times (as a readonly, static data symbol) or
+// one time (during init function execution).
+// Either way, there is no opportunity for races or further modification,
+// so the data can be written to a (possibly readonly) data symbol.
+// Static data populated in any other function needs to be local to
+// that function to allow multiple instances of that function
+// to execute concurrently without clobbering each others' data.
+type initContext uint8
+
+const (
+ inInitFunction initContext = iota
+ inNonInitFunction
+)
+
// from here down is the walk analysis
// of composite literals.
// most of the work is to generate
// data statements for the constant
// part of the composite literal.
-func staticname(t *Type, ctxt int) *Node {
- n := newname(LookupN("statictmp_", statuniqgen))
+
+// staticname returns a name backed by a static data symbol.
+// Callers should set n.Name.Readonly = true on the
+// returned node for readonly nodes.
+func staticname(t *Type) *Node {
+ n := newname(lookupN("statictmp_", statuniqgen))
statuniqgen++
- if ctxt == 0 {
- n.Name.Readonly = true
- }
addvar(n, t, PEXTERN)
return n
}
@@ -520,7 +587,7 @@ func (n *Node) isSimpleName() bool {
}
func litas(l *Node, r *Node, init *Nodes) {
- a := Nod(OAS, l, r)
+ a := nod(OAS, l, r)
a = typecheck(a, Etop)
a = walkexpr(a, init)
init.Append(a)
@@ -534,7 +601,9 @@ const (
initConst // contains some constant values, which may be written into data symbols
)
-func getdyn(n *Node, top int) initGenType {
+// getdyn calculates the initGenType for n.
+// If top is false, getdyn is recursing.
+func getdyn(n *Node, top bool) initGenType {
switch n.Op {
default:
if isliteral(n) {
@@ -542,18 +611,23 @@ func getdyn(n *Node, top int) initGenType {
}
return initDynamic
- case OARRAYLIT:
- if top == 0 && n.Type.IsSlice() {
+ case OSLICELIT:
+ if !top {
return initDynamic
}
- case OSTRUCTLIT:
+ case OARRAYLIT, OSTRUCTLIT:
}
var mode initGenType
for _, n1 := range n.List.Slice() {
- value := n1.Right
- mode |= getdyn(value, 0)
+ switch n1.Op {
+ case OKEY:
+ n1 = n1.Right
+ case OSTRUCTKEY:
+ n1 = n1.Left
+ }
+ mode |= getdyn(n1, false)
if mode == initDynamic|initConst {
break
}
@@ -564,174 +638,156 @@ func getdyn(n *Node, top int) initGenType {
// isStaticCompositeLiteral reports whether n is a compile-time constant.
func isStaticCompositeLiteral(n *Node) bool {
switch n.Op {
+ case OSLICELIT:
+ return false
case OARRAYLIT:
- if n.Type.IsSlice() {
- return false
+ for _, r := range n.List.Slice() {
+ if r.Op == OKEY {
+ r = r.Right
+ }
+ if !isStaticCompositeLiteral(r) {
+ return false
+ }
}
+ return true
case OSTRUCTLIT:
+ for _, r := range n.List.Slice() {
+ if r.Op != OSTRUCTKEY {
+ Fatalf("isStaticCompositeLiteral: rhs not OSTRUCTKEY: %v", r)
+ }
+ if !isStaticCompositeLiteral(r.Left) {
+ return false
+ }
+ }
+ return true
case OLITERAL:
return true
- default:
- return false
- }
- for _, r := range n.List.Slice() {
- if r.Op != OKEY {
- Fatalf("isStaticCompositeLiteral: rhs not OKEY: %v", r)
+ case OCONVIFACE:
+ // See staticassign's OCONVIFACE case for comments.
+ val := n
+ for val.Op == OCONVIFACE {
+ val = val.Left
}
- index := r.Left
- if n.Op == OARRAYLIT && index.Op != OLITERAL {
- return false
+ if val.Type.IsInterface() {
+ return Isconst(val, CTNIL)
}
- value := r.Right
- if !isStaticCompositeLiteral(value) {
- return false
+ if isdirectiface(val.Type) && Isconst(val, CTNIL) {
+ return true
}
+ return isStaticCompositeLiteral(val)
}
- return true
+ return false
}
-func structlit(ctxt int, pass int, n *Node, var_ *Node, init *Nodes) {
- for _, r := range n.List.Slice() {
- if r.Op != OKEY {
- Fatalf("structlit: rhs not OKEY: %v", r)
- }
- index := r.Left
- value := r.Right
-
- switch value.Op {
- case OARRAYLIT:
- if value.Type.IsSlice() {
- if pass == 1 && ctxt != 0 {
- a := NodSym(ODOT, var_, index.Sym)
- slicelit(ctxt, value, a, init)
- } else if pass == 2 && ctxt == 0 {
- a := NodSym(ODOT, var_, index.Sym)
- slicelit(ctxt, value, a, init)
- } else if pass == 3 {
- break
- }
- continue
- }
-
- a := NodSym(ODOT, var_, index.Sym)
- arraylit(ctxt, pass, value, a, init)
- continue
+// initKind is a kind of static initialization: static, dynamic, or local.
+// Static initialization represents literals and
+// literal components of composite literals.
+// Dynamic initialization represents non-literals and
+// non-literal components of composite literals.
+// LocalCode initializion represents initialization
+// that occurs purely in generated code local to the function of use.
+// Initialization code is sometimes generated in passes,
+// first static then dynamic.
+type initKind uint8
- case OSTRUCTLIT:
- a := NodSym(ODOT, var_, index.Sym)
- structlit(ctxt, pass, value, a, init)
- continue
- }
+const (
+ initKindStatic initKind = iota + 1
+ initKindDynamic
+ initKindLocalCode
+)
- if isliteral(value) {
- if pass == 2 {
- continue
+// fixedlit handles struct, array, and slice literals.
+// TODO: expand documentation.
+func fixedlit(ctxt initContext, kind initKind, n *Node, var_ *Node, init *Nodes) {
+ var splitnode func(*Node) (a *Node, value *Node)
+ switch n.Op {
+ case OARRAYLIT, OSLICELIT:
+ var k int64
+ splitnode = func(r *Node) (*Node, *Node) {
+ if r.Op == OKEY {
+ k = nonnegintconst(r.Left)
+ r = r.Right
}
- } else if pass == 1 {
- continue
+ a := nod(OINDEX, var_, nodintconst(k))
+ k++
+ return a, r
}
-
- // build list of var.field = expr
- setlineno(value)
- a := NodSym(ODOT, var_, index.Sym)
-
- a = Nod(OAS, a, value)
- a = typecheck(a, Etop)
- if pass == 1 {
- a = walkexpr(a, init) // add any assignments in r to top
- if a.Op != OAS {
- Fatalf("structlit: not as")
+ case OSTRUCTLIT:
+ splitnode = func(r *Node) (*Node, *Node) {
+ if r.Op != OSTRUCTKEY {
+ Fatalf("fixedlit: rhs not OSTRUCTKEY: %v", r)
}
- a.Dodata = 2
- } else {
- a = orderstmtinplace(a)
- a = walkstmt(a)
+ return nodSym(ODOT, var_, r.Sym), r.Left
}
-
- init.Append(a)
+ default:
+ Fatalf("fixedlit bad op: %v", n.Op)
}
-}
-func arraylit(ctxt int, pass int, n *Node, var_ *Node, init *Nodes) {
for _, r := range n.List.Slice() {
- if r.Op != OKEY {
- Fatalf("arraylit: rhs not OKEY: %v", r)
- }
- index := r.Left
- value := r.Right
+ a, value := splitnode(r)
switch value.Op {
- case OARRAYLIT:
- if value.Type.IsSlice() {
- if pass == 1 && ctxt != 0 {
- a := Nod(OINDEX, var_, index)
- slicelit(ctxt, value, a, init)
- } else if pass == 2 && ctxt == 0 {
- a := Nod(OINDEX, var_, index)
- slicelit(ctxt, value, a, init)
- } else if pass == 3 {
- break
- }
+ case OSLICELIT:
+ if (kind == initKindStatic && ctxt == inNonInitFunction) || (kind == initKindDynamic && ctxt == inInitFunction) {
+ slicelit(ctxt, value, a, init)
continue
}
- a := Nod(OINDEX, var_, index)
- arraylit(ctxt, pass, value, a, init)
- continue
-
- case OSTRUCTLIT:
- a := Nod(OINDEX, var_, index)
- structlit(ctxt, pass, value, a, init)
+ case OARRAYLIT, OSTRUCTLIT:
+ fixedlit(ctxt, kind, value, a, init)
continue
}
- if isliteral(index) && isliteral(value) {
- if pass == 2 {
- continue
- }
- } else if pass == 1 {
+ islit := isliteral(value)
+ if (kind == initKindStatic && !islit) || (kind == initKindDynamic && islit) {
continue
}
- // build list of var[index] = value
+ // build list of assignments: var[index] = expr
setlineno(value)
- a := Nod(OINDEX, var_, index)
-
- a = Nod(OAS, a, value)
+ a = nod(OAS, a, value)
a = typecheck(a, Etop)
- if pass == 1 {
- a = walkexpr(a, init)
+ 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("arraylit: not as")
+ Fatalf("fixedlit: not as, is %v", a)
}
- a.Dodata = 2
- } else {
+ a.IsStatic = true
+ case initKindDynamic, initKindLocalCode:
a = orderstmtinplace(a)
a = walkstmt(a)
+ default:
+ Fatalf("fixedlit: bad kind %d", kind)
}
init.Append(a)
}
}
-func slicelit(ctxt int, n *Node, var_ *Node, init *Nodes) {
+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())
dowidth(t)
- if ctxt != 0 {
+ if ctxt == inNonInitFunction {
// put everything into static array
- vstat := staticname(t, ctxt)
+ vstat := staticname(t)
- arraylit(ctxt, 1, n, vstat, init)
- arraylit(ctxt, 2, n, vstat, init)
+ fixedlit(ctxt, initKindStatic, n, vstat, init)
+ fixedlit(ctxt, initKindDynamic, n, vstat, init)
// copy static to slice
- a := Nod(OSLICE, vstat, nil)
+ a := nod(OSLICE, vstat, nil)
- a = Nod(OAS, var_, a)
+ a = nod(OAS, var_, a)
a = typecheck(a, Etop)
- a.Dodata = 2
+ a.IsStatic = true
init.Append(a)
return
}
@@ -759,14 +815,17 @@ func slicelit(ctxt int, n *Node, var_ *Node, init *Nodes) {
// make static initialized array (1),(2)
var vstat *Node
- mode := getdyn(n, 1)
+ mode := getdyn(n, true)
if mode&initConst != 0 {
- vstat = staticname(t, ctxt)
- arraylit(ctxt, 1, n, vstat, init)
+ vstat = staticname(t)
+ if ctxt == inInitFunction {
+ vstat.Name.Readonly = true
+ }
+ fixedlit(ctxt, initKindStatic, n, vstat, init)
}
// make new auto *array (3 declare)
- vauto := temp(Ptrto(t))
+ vauto := temp(ptrto(t))
// set auto to point at new temp or heap (3 assign)
var a *Node
@@ -775,74 +834,72 @@ func slicelit(ctxt int, n *Node, var_ *Node, init *Nodes) {
x.Type = t
if vstat == nil {
- a = Nod(OAS, x, nil)
+ a = nod(OAS, x, nil)
a = typecheck(a, Etop)
init.Append(a) // zero new temp
}
- a = Nod(OADDR, x, nil)
+ a = nod(OADDR, x, nil)
} else if n.Esc == EscNone {
a = temp(t)
if vstat == nil {
- a = Nod(OAS, temp(t), nil)
+ a = nod(OAS, temp(t), nil)
a = typecheck(a, Etop)
init.Append(a) // zero new temp
a = a.Left
}
- a = Nod(OADDR, a, nil)
+ a = nod(OADDR, a, nil)
} else {
- a = Nod(ONEW, nil, nil)
+ a = nod(ONEW, nil, nil)
a.List.Set1(typenod(t))
}
- a = Nod(OAS, vauto, a)
+ a = nod(OAS, vauto, a)
a = typecheck(a, Etop)
a = walkexpr(a, init)
init.Append(a)
if vstat != nil {
// copy static to heap (4)
- a = Nod(OIND, vauto, nil)
+ a = nod(OIND, vauto, nil)
- a = Nod(OAS, a, vstat)
+ a = nod(OAS, a, vstat)
a = typecheck(a, Etop)
a = walkexpr(a, init)
init.Append(a)
}
// put dynamics into array (5)
+ var index int64
for _, r := range n.List.Slice() {
- if r.Op != OKEY {
- Fatalf("slicelit: rhs not OKEY: %v", r)
+ value := r
+ if r.Op == OKEY {
+ index = nonnegintconst(r.Left)
+ value = r.Right
}
- index := r.Left
- value := r.Right
- a := Nod(OINDEX, vauto, index)
+ a := nod(OINDEX, vauto, nodintconst(index))
a.Bounded = true
+ index++
// TODO need to check bounds?
switch value.Op {
- case OARRAYLIT:
- if value.Type.IsSlice() {
- break
- }
- arraylit(ctxt, 2, value, a, init)
- continue
+ case OSLICELIT:
+ break
- case OSTRUCTLIT:
- structlit(ctxt, 2, value, a, init)
+ case OARRAYLIT, OSTRUCTLIT:
+ fixedlit(ctxt, initKindDynamic, value, a, init)
continue
}
- if isliteral(index) && isliteral(value) {
+ if isliteral(value) {
continue
}
// build list of vauto[c] = expr
setlineno(value)
- a = Nod(OAS, a, value)
+ a = nod(OAS, a, value)
a = typecheck(a, Etop)
a = orderstmtinplace(a)
@@ -851,7 +908,7 @@ func slicelit(ctxt int, n *Node, var_ *Node, init *Nodes) {
}
// make slice out of heap (6)
- a = Nod(OAS, var_, Nod(OSLICE, vauto, nil))
+ a = nod(OAS, var_, nod(OSLICE, vauto, nil))
a = typecheck(a, Etop)
a = orderstmtinplace(a)
@@ -859,15 +916,13 @@ func slicelit(ctxt int, n *Node, var_ *Node, init *Nodes) {
init.Append(a)
}
-func maplit(ctxt int, n *Node, var_ *Node, init *Nodes) {
- ctxt = 0
-
+func maplit(n *Node, m *Node, init *Nodes) {
// make the map var
nerr := nerrors
- a := Nod(OMAKE, nil, nil)
- a.List.Set1(typenod(n.Type))
- litas(var_, a, init)
+ a := nod(OMAKE, nil, nil)
+ a.List.Set2(typenod(n.Type), nodintconst(int64(len(n.List.Slice()))))
+ litas(m, a, init)
// count the initializers
b := 0
@@ -884,32 +939,19 @@ func maplit(ctxt int, n *Node, var_ *Node, init *Nodes) {
}
if b != 0 {
- // build type [count]struct { a Tindex, b Tvalue }
- t := n.Type
- tk := t.Key()
- tv := t.Val()
-
- syma := Lookup("a")
- symb := Lookup("b")
-
- var fields [2]*Field
- fields[0] = newField()
- fields[0].Type = tk
- fields[0].Sym = syma
- fields[1] = newField()
- fields[1].Type = tv
- fields[1].Sym = symb
-
- tstruct := typ(TSTRUCT)
- tstruct.SetFields(fields[:])
-
- tarr := typArray(tstruct, int64(b))
+ // build types [count]Tindex and [count]Tvalue
+ tk := typArray(n.Type.Key(), int64(b))
+ tv := typArray(n.Type.Val(), int64(b))
// TODO(josharian): suppress alg generation for these types?
- dowidth(tarr)
+ dowidth(tk)
+ dowidth(tv)
- // make and initialize static array
- vstat := staticname(tarr, ctxt)
+ // make and initialize static arrays
+ vstatk := staticname(tk)
+ vstatk.Name.Readonly = true
+ vstatv := staticname(tv)
+ vstatv.Name.Readonly = true
b := int64(0)
for _, r := range n.List.Slice() {
@@ -920,61 +962,52 @@ func maplit(ctxt int, n *Node, var_ *Node, init *Nodes) {
value := r.Right
if isliteral(index) && isliteral(value) {
- // build vstat[b].a = key;
+ // build vstatk[b] = index
setlineno(index)
- a = Nodintconst(b)
-
- a = Nod(OINDEX, vstat, a)
- a = NodSym(ODOT, a, syma)
- a = Nod(OAS, a, index)
- a = typecheck(a, Etop)
- a = walkexpr(a, init)
- a.Dodata = 2
- init.Append(a)
-
- // build vstat[b].b = value;
+ 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)
- a = Nodintconst(b)
-
- a = Nod(OINDEX, vstat, a)
- a = NodSym(ODOT, a, symb)
- a = Nod(OAS, a, value)
- a = typecheck(a, Etop)
- a = walkexpr(a, init)
- a.Dodata = 2
- init.Append(a)
+ 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++
}
}
// loop adding structure elements to map
- // for i = 0; i < len(vstat); i++ {
- // map[vstat[i].a] = vstat[i].b
+ // for i = 0; i < len(vstatk); i++ {
+ // map[vstatk[i]] = vstatv[i]
// }
- index := temp(Types[TINT])
-
- a = Nod(OINDEX, vstat, index)
- a.Bounded = true
- a = NodSym(ODOT, a, symb)
-
- r := Nod(OINDEX, vstat, index)
- r.Bounded = true
- r = NodSym(ODOT, r, syma)
- r = Nod(OINDEX, var_, r)
+ i := temp(Types[TINT])
+ rhs := nod(OINDEX, vstatv, i)
+ rhs.Bounded = true
- r = Nod(OAS, r, a)
+ kidx := nod(OINDEX, vstatk, i)
+ kidx.Bounded = true
+ lhs := nod(OINDEX, m, kidx)
- a = Nod(OFOR, nil, nil)
- a.Nbody.Set1(r)
+ zero := nod(OAS, i, nodintconst(0))
+ cond := nod(OLT, i, nodintconst(tk.NumElem()))
+ incr := nod(OAS, i, nod(OADD, i, nodintconst(1)))
+ body := nod(OAS, lhs, rhs)
- a.Ninit.Set1(Nod(OAS, index, Nodintconst(0)))
- a.Left = Nod(OLT, index, Nodintconst(tarr.NumElem()))
- a.Right = Nod(OAS, index, Nod(OADD, index, Nodintconst(1)))
+ loop := nod(OFOR, cond, incr)
+ loop.Nbody.Set1(body)
+ loop.Ninit.Set1(zero)
- a = typecheck(a, Etop)
- a = walkstmt(a)
- init.Append(a)
+ loop = typecheck(loop, Etop)
+ loop = walkstmt(loop)
+ init.Append(loop)
}
// put in dynamic entries one-at-a-time
@@ -993,23 +1026,24 @@ func maplit(ctxt int, n *Node, var_ *Node, init *Nodes) {
// build list of var[c] = expr.
// use temporary so that mapassign1 can have addressable key, val.
if key == nil {
- key = temp(var_.Type.Key())
- val = temp(var_.Type.Val())
+ key = temp(m.Type.Key())
+ val = temp(m.Type.Val())
}
- setlineno(r.Left)
- a = Nod(OAS, key, r.Left)
+ setlineno(index)
+ a = nod(OAS, key, index)
a = typecheck(a, Etop)
a = walkstmt(a)
init.Append(a)
- setlineno(r.Right)
- a = Nod(OAS, val, r.Right)
+
+ setlineno(value)
+ a = nod(OAS, val, value)
a = typecheck(a, Etop)
a = walkstmt(a)
init.Append(a)
setlineno(val)
- a = Nod(OAS, Nod(OINDEX, var_, key), val)
+ a = nod(OAS, nod(OINDEX, m, key), val)
a = typecheck(a, Etop)
a = walkstmt(a)
init.Append(a)
@@ -1020,16 +1054,16 @@ func maplit(ctxt int, n *Node, var_ *Node, init *Nodes) {
}
if key != nil {
- a = Nod(OVARKILL, key, nil)
+ a = nod(OVARKILL, key, nil)
a = typecheck(a, Etop)
init.Append(a)
- a = Nod(OVARKILL, val, nil)
+ a = nod(OVARKILL, val, nil)
a = typecheck(a, Etop)
init.Append(a)
}
}
-func anylit(ctxt int, n *Node, var_ *Node, init *Nodes) {
+func anylit(n *Node, var_ *Node, init *Nodes) {
t := n.Type
switch n.Op {
default:
@@ -1042,154 +1076,109 @@ func anylit(ctxt int, n *Node, var_ *Node, init *Nodes) {
var r *Node
if n.Right != nil {
- r = Nod(OADDR, n.Right, nil)
+ r = nod(OADDR, n.Right, nil)
r = typecheck(r, Erv)
} else {
- r = Nod(ONEW, nil, nil)
+ r = nod(ONEW, nil, nil)
r.Typecheck = 1
r.Type = t
r.Esc = n.Esc
}
r = walkexpr(r, init)
- a := Nod(OAS, var_, r)
+ a := nod(OAS, var_, r)
a = typecheck(a, Etop)
init.Append(a)
- var_ = Nod(OIND, var_, nil)
+ var_ = nod(OIND, var_, nil)
var_ = typecheck(var_, Erv|Easgn)
- anylit(ctxt, n.Left, var_, init)
+ anylit(n.Left, var_, init)
- case OSTRUCTLIT:
- if !t.IsStruct() {
- Fatalf("anylit: not struct")
+ case OSTRUCTLIT, OARRAYLIT:
+ if !t.IsStruct() && !t.IsArray() {
+ Fatalf("anylit: not struct/array")
}
if var_.isSimpleName() && n.List.Len() > 4 {
- if ctxt == 0 {
- // lay out static data
- vstat := staticname(t, ctxt)
+ // lay out static data
+ vstat := staticname(t)
+ vstat.Name.Readonly = true
- structlit(ctxt, 1, n, vstat, init)
-
- // copy static to var
- a := Nod(OAS, var_, vstat)
-
- a = typecheck(a, Etop)
- a = walkexpr(a, init)
- init.Append(a)
-
- // add expressions to automatic
- structlit(ctxt, 2, n, var_, init)
-
- break
+ ctxt := inInitFunction
+ if n.Op == OARRAYLIT {
+ ctxt = inNonInitFunction
}
+ fixedlit(ctxt, initKindStatic, n, vstat, init)
- structlit(ctxt, 1, n, var_, init)
- structlit(ctxt, 2, n, var_, init)
- break
- }
+ // copy static to var
+ a := nod(OAS, var_, vstat)
- // initialize of not completely specified
- if var_.isSimpleName() || n.List.Len() < t.NumFields() {
- a := Nod(OAS, var_, nil)
a = typecheck(a, Etop)
a = walkexpr(a, init)
init.Append(a)
- }
-
- structlit(ctxt, 3, n, var_, init)
- case OARRAYLIT:
- if t.IsSlice() {
- slicelit(ctxt, n, var_, init)
+ // add expressions to automatic
+ fixedlit(inInitFunction, initKindDynamic, n, var_, init)
break
}
- if !t.IsArray() {
- Fatalf("anylit: not array")
- }
-
- if var_.isSimpleName() && n.List.Len() > 4 {
- if ctxt == 0 {
- // lay out static data
- vstat := staticname(t, ctxt)
- arraylit(1, 1, n, vstat, init)
-
- // copy static to automatic
- a := Nod(OAS, var_, vstat)
-
- a = typecheck(a, Etop)
- a = walkexpr(a, init)
- init.Append(a)
-
- // add expressions to automatic
- arraylit(ctxt, 2, n, var_, init)
-
- break
- }
-
- arraylit(ctxt, 1, n, var_, init)
- arraylit(ctxt, 2, n, var_, init)
- break
+ var components int64
+ if n.Op == OARRAYLIT {
+ components = t.NumElem()
+ } else {
+ components = int64(t.NumFields())
}
-
- // initialize of not completely specified
- if var_.isSimpleName() || int64(n.List.Len()) < t.NumElem() {
- a := Nod(OAS, var_, nil)
+ // initialization of an array or struct with unspecified components (missing fields or arrays)
+ if var_.isSimpleName() || int64(n.List.Len()) < components {
+ a := nod(OAS, var_, nil)
a = typecheck(a, Etop)
a = walkexpr(a, init)
init.Append(a)
}
- arraylit(ctxt, 3, n, var_, init)
+ fixedlit(inInitFunction, initKindLocalCode, n, var_, init)
+
+ case OSLICELIT:
+ slicelit(inInitFunction, n, var_, init)
case OMAPLIT:
if !t.IsMap() {
Fatalf("anylit: not map")
}
- maplit(ctxt, n, var_, init)
+ maplit(n, var_, init)
}
}
func oaslit(n *Node, init *Nodes) bool {
if n.Left == nil || n.Right == nil {
- // not a special composit literal assignment
+ // not a special composite literal assignment
return false
}
if n.Left.Type == nil || n.Right.Type == nil {
- // not a special composit literal assignment
+ // not a special composite literal assignment
return false
}
if !n.Left.isSimpleName() {
- // not a special composit literal assignment
+ // not a special composite literal assignment
return false
}
- if !Eqtype(n.Left.Type, n.Right.Type) {
- // not a special composit literal assignment
+ if !eqtype(n.Left.Type, n.Right.Type) {
+ // not a special composite literal assignment
return false
}
- // context is init() function.
- // implies generated data executed
- // exactly once and not subject to races.
- ctxt := 0
-
- // if(n->dodata == 1)
- // ctxt = 1;
-
switch n.Right.Op {
default:
- // not a special composit literal assignment
+ // not a special composite literal assignment
return false
- case OSTRUCTLIT, OARRAYLIT, OMAPLIT:
+ case OSTRUCTLIT, OARRAYLIT, OSLICELIT, OMAPLIT:
if vmatch1(n.Left, n.Right) {
- // not a special composit literal assignment
+ // not a special composite literal assignment
return false
}
- anylit(ctxt, n.Right, n.Left, init)
+ anylit(n.Right, n.Left, init)
}
n.Op = OEMPTY
@@ -1198,7 +1187,7 @@ func oaslit(n *Node, init *Nodes) bool {
}
func getlit(lit *Node) int {
- if Smallintconst(lit) {
+ if smallintconst(lit) {
return int(lit.Int64())
}
return -1
@@ -1257,20 +1246,23 @@ func initplan(n *Node) {
default:
Fatalf("initplan")
- case OARRAYLIT:
+ case OARRAYLIT, OSLICELIT:
+ var k int64
for _, a := range n.List.Slice() {
- if a.Op != OKEY || !Smallintconst(a.Left) {
- Fatalf("initplan arraylit")
+ if a.Op == OKEY {
+ k = nonnegintconst(a.Left)
+ a = a.Right
}
- addvalue(p, n.Type.Elem().Width*a.Left.Int64(), a.Right)
+ addvalue(p, k*n.Type.Elem().Width, a)
+ k++
}
case OSTRUCTLIT:
for _, a := range n.List.Slice() {
- if a.Op != OKEY || a.Left.Type != structkey {
- Fatalf("initplan structlit")
+ if a.Op != OSTRUCTKEY {
+ Fatalf("initplan fixedlit")
}
- addvalue(p, a.Left.Xoffset, a.Right)
+ addvalue(p, a.Xoffset, a.Left)
}
case OMAPLIT:
@@ -1327,13 +1319,19 @@ func iszero(n *Node) bool {
}
case OARRAYLIT:
- if n.Type.IsSlice() {
- break
+ for _, n1 := range n.List.Slice() {
+ if n1.Op == OKEY {
+ n1 = n1.Right
+ }
+ if !iszero(n1) {
+ return false
+ }
}
- fallthrough
+ return true
+
case OSTRUCTLIT:
for _, n1 := range n.List.Slice() {
- if !iszero(n1.Right) {
+ if !iszero(n1.Left) {
return false
}
}
@@ -1344,22 +1342,22 @@ func iszero(n *Node) bool {
}
func isvaluelit(n *Node) bool {
- return (n.Op == OARRAYLIT && n.Type.IsArray()) || n.Op == OSTRUCTLIT
+ 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.Dodata == 2 {
+ if !success && n.IsStatic {
Dump("\ngen_as_init", n)
- Fatalf("gen_as_init couldn't make data statement")
+ Fatalf("gen_as_init couldn't generate static data")
}
return success
}
func genAsInitNoCheck(n *Node, reportOnly bool) bool {
- if n.Dodata == 0 {
+ if !n.IsStatic {
return false
}
@@ -1370,7 +1368,7 @@ func genAsInitNoCheck(n *Node, reportOnly bool) bool {
return stataddr(&nam, nl) && nam.Class == PEXTERN
}
- if nr.Type == nil || !Eqtype(nl.Type, nr.Type) {
+ if nr.Type == nil || !eqtype(nl.Type, nr.Type) {
return false
}
@@ -1411,47 +1409,24 @@ func genAsInitNoCheck(n *Node, reportOnly bool) bool {
}
if !reportOnly {
- nam.Xoffset += int64(Array_array)
+ nam.Xoffset += int64(array_array)
gdata(&nam, ptr, Widthptr)
- nam.Xoffset += int64(Array_nel) - int64(Array_array)
+ 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)
+ nam.Xoffset += int64(array_cap) - int64(array_nel)
gdata(&nam, &nod1, Widthint)
}
return true
case OLITERAL:
- break
- }
-
- switch nr.Type.Etype {
- default:
- return false
-
- case TBOOL, TINT8, TUINT8, TINT16, TUINT16,
- TINT32, TUINT32, TINT64, TUINT64,
- TINT, TUINT, TUINTPTR,
- TPTR32, TPTR64,
- TFLOAT32, TFLOAT64:
if !reportOnly {
gdata(&nam, nr, int(nr.Type.Width))
}
-
- case TCOMPLEX64, TCOMPLEX128:
- if !reportOnly {
- gdatacomplex(&nam, nr.Val().U.(*Mpcplx))
- }
-
- case TSTRING:
- if !reportOnly {
- gdatastring(&nam, nr.Val().U.(string))
- }
+ return true
}
-
- return true
}
diff --git a/src/cmd/compile/internal/gc/sizeof_test.go b/src/cmd/compile/internal/gc/sizeof_test.go
index c474c47..b86188c 100644
--- a/src/cmd/compile/internal/gc/sizeof_test.go
+++ b/src/cmd/compile/internal/gc/sizeof_test.go
@@ -22,12 +22,12 @@ func TestSizeof(t *testing.T) {
_32bit uintptr // size on 32bit platforms
_64bit uintptr // size on 64bit platforms
}{
- {Flow{}, 52, 88},
{Func{}, 92, 160},
- {Name{}, 52, 80},
+ {Name{}, 44, 72},
+ {Param{}, 24, 48},
{Node{}, 92, 144},
{Sym{}, 60, 112},
- {Type{}, 52, 80},
+ {Type{}, 60, 96},
{MapType{}, 20, 40},
{ForwardType{}, 16, 32},
{FuncType{}, 28, 48},
diff --git a/src/cmd/compile/internal/gc/sparselocatephifunctions.go b/src/cmd/compile/internal/gc/sparselocatephifunctions.go
deleted file mode 100644
index 43cc50b..0000000
--- a/src/cmd/compile/internal/gc/sparselocatephifunctions.go
+++ /dev/null
@@ -1,202 +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 gc
-
-import (
- "cmd/compile/internal/ssa"
- "fmt"
- "math"
-)
-
-// sparseDefState contains a Go map from ONAMEs (*Node) to sparse definition trees, and
-// a search helper for the CFG's dominator tree in which those definitions are embedded.
-// Once initialized, given a use of an ONAME within a block, the ssa definition for
-// that ONAME can be discovered in time roughly proportional to the log of the number
-// of SSA definitions of that ONAME (thus avoiding pathological quadratic behavior for
-// very large programs). The helper contains state (a dominator tree numbering) common
-// to all the sparse definition trees, as well as some necessary data obtained from
-// the ssa package.
-//
-// This algorithm has improved asymptotic complexity, but the constant factor is
-// rather large and thus it is only preferred for very large inputs containing
-// 1000s of blocks and variables.
-type sparseDefState struct {
- helper *ssa.SparseTreeHelper // contains one copy of information needed to do sparse mapping
- defmapForOname map[*Node]*onameDefs // for each ONAME, its definition set (normal and phi)
-}
-
-// onameDefs contains a record of definitions (ordinary and implied phi function) for a single OName.
-// stm is the set of definitions for the OName.
-// firstdef and lastuse are postorder block numberings that
-// conservatively bracket the entire lifetime of the OName.
-type onameDefs struct {
- stm *ssa.SparseTreeMap
- // firstdef and lastuse define an interval in the postorder numbering
- // that is guaranteed to include the entire lifetime of an ONAME.
- // In the postorder numbering, math.MaxInt32 is before anything,
- // and 0 is after-or-equal all exit nodes and infinite loops.
- firstdef int32 // the first definition of this ONAME *in the postorder numbering*
- lastuse int32 // the last use of this ONAME *in the postorder numbering*
-}
-
-// defsFor finds or creates-and-inserts-in-map the definition information
-// (sparse tree and live range) for a given OName.
-func (m *sparseDefState) defsFor(n *Node) *onameDefs {
- d := m.defmapForOname[n]
- if d != nil {
- return d
- }
- // Reminder: firstdef/lastuse are postorder indices, not block indices,
- // so these default values define an empty interval, not the entire one.
- d = &onameDefs{stm: m.helper.NewTree(), firstdef: 0, lastuse: math.MaxInt32}
- m.defmapForOname[n] = d
- return d
-}
-
-// Insert adds a definition at b (with specified before/within/after adjustment)
-// to sparse tree onameDefs. The lifetime is extended as necessary.
-func (m *sparseDefState) Insert(tree *onameDefs, b *ssa.Block, adjust int32) {
- bponum := m.helper.Ponums[b.ID]
- if bponum > tree.firstdef {
- tree.firstdef = bponum
- }
- tree.stm.Insert(b, adjust, b, m.helper)
-}
-
-// Use updates tree to record a use within b, extending the lifetime as necessary.
-func (m *sparseDefState) Use(tree *onameDefs, b *ssa.Block) {
- bponum := m.helper.Ponums[b.ID]
- if bponum < tree.lastuse {
- tree.lastuse = bponum
- }
-}
-
-// locatePotentialPhiFunctions finds all the places where phi functions
-// will be inserted into a program and records those and ordinary definitions
-// in a "map" (not a Go map) that given an OName and use site, returns the
-// SSA definition for that OName that will reach the use site (that is,
-// the use site's nearest def/phi site in the dominator tree.)
-func (s *state) locatePotentialPhiFunctions(fn *Node) *sparseDefState {
- // s.config.SparsePhiCutoff() is compared with product of numblocks and numvalues,
- // if product is smaller than cutoff, use old non-sparse method.
- // cutoff == 0 implies all sparse
- // cutoff == uint(-1) implies all non-sparse
- if uint64(s.f.NumValues())*uint64(s.f.NumBlocks()) < s.config.SparsePhiCutoff() {
- return nil
- }
-
- helper := ssa.NewSparseTreeHelper(s.f)
- po := helper.Po // index by block.ID to obtain postorder # of block.
- trees := make(map[*Node]*onameDefs)
- dm := &sparseDefState{defmapForOname: trees, helper: helper}
-
- // Process params, taking note of their special lifetimes
- b := s.f.Entry
- for _, n := range fn.Func.Dcl {
- switch n.Class {
- case PPARAM, PPARAMOUT:
- t := dm.defsFor(n)
- dm.Insert(t, b, ssa.AdjustBefore) // define param at entry block
- if n.Class == PPARAMOUT {
- dm.Use(t, po[0]) // Explicitly use PPARAMOUT at very last block
- }
- default:
- }
- }
-
- // Process memory variable.
- t := dm.defsFor(&memVar)
- dm.Insert(t, b, ssa.AdjustBefore) // define memory at entry block
- dm.Use(t, po[0]) // Explicitly use memory at last block
-
- // Next load the map w/ basic definitions for ONames recorded per-block
- // Iterate over po to avoid unreachable blocks.
- for i := len(po) - 1; i >= 0; i-- {
- b := po[i]
- m := s.defvars[b.ID]
- for n := range m { // no specified order, but per-node trees are independent.
- t := dm.defsFor(n)
- dm.Insert(t, b, ssa.AdjustWithin)
- }
- }
-
- // Find last use of each variable
- for _, v := range s.fwdRefs {
- b := v.Block
- name := v.Aux.(*Node)
- t := dm.defsFor(name)
- dm.Use(t, b)
- }
-
- for _, t := range trees {
- // iterating over names in the outer loop
- for change := true; change; {
- change = false
- for i := t.firstdef; i >= t.lastuse; i-- {
- // Iterating in reverse of post-order reduces number of 'change' iterations;
- // all possible forward flow goes through each time.
- b := po[i]
- // Within tree t, would a use at b require a phi function to ensure a single definition?
- // TODO: perhaps more efficient to record specific use sites instead of range?
- if len(b.Preds) < 2 {
- continue // no phi possible
- }
- phi := t.stm.Find(b, ssa.AdjustWithin, helper) // Look for defs in earlier block or AdjustBefore in this one.
- if phi != nil && phi.(*ssa.Block) == b {
- continue // has a phi already in this block.
- }
- var defseen interface{}
- // Do preds see different definitions? if so, need a phi function.
- for _, e := range b.Preds {
- p := e.Block()
- dm.Use(t, p) // always count phi pred as "use"; no-op except for loop edges, which matter.
- x := t.stm.Find(p, ssa.AdjustAfter, helper) // Look for defs reaching or within predecessors.
- if x == nil { // nil def from a predecessor means a backedge that will be visited soon.
- continue
- }
- if defseen == nil {
- defseen = x
- }
- if defseen != x {
- // Need to insert a phi function here because predecessors's definitions differ.
- change = true
- // Phi insertion is at AdjustBefore, visible with find in same block at AdjustWithin or AdjustAfter.
- dm.Insert(t, b, ssa.AdjustBefore)
- break
- }
- }
- }
- }
- }
- return dm
-}
-
-// FindBetterDefiningBlock tries to find a better block for a definition of OName name
-// reaching (or within) p than p itself. If it cannot, it returns p instead.
-// This aids in more efficient location of phi functions, since it can skip over
-// branch code that might contain a definition of name if it actually does not.
-func (m *sparseDefState) FindBetterDefiningBlock(name *Node, p *ssa.Block) *ssa.Block {
- if m == nil {
- return p
- }
- t := m.defmapForOname[name]
- // For now this is fail-soft, since the old algorithm still works using the unimproved block.
- if t == nil {
- return p
- }
- x := t.stm.Find(p, ssa.AdjustAfter, m.helper)
- if x == nil {
- return p
- }
- b := x.(*ssa.Block)
- if b == nil {
- return p
- }
- return b
-}
-
-func (d *onameDefs) String() string {
- return fmt.Sprintf("onameDefs:first=%d,last=%d,tree=%s", d.firstdef, d.lastuse, d.stm.String())
-}
diff --git a/src/cmd/compile/internal/gc/ssa.go b/src/cmd/compile/internal/gc/ssa.go
index 62ea44f..55ee3c0 100644
--- a/src/cmd/compile/internal/gc/ssa.go
+++ b/src/cmd/compile/internal/gc/ssa.go
@@ -6,83 +6,29 @@ package gc
import (
"bytes"
+ "encoding/binary"
"fmt"
"html"
"os"
- "strings"
+ "sort"
"cmd/compile/internal/ssa"
"cmd/internal/obj"
"cmd/internal/sys"
)
-var ssaEnabled = true
-
var ssaConfig *ssa.Config
var ssaExp ssaExport
func initssa() *ssa.Config {
- ssaExp.unimplemented = false
- ssaExp.mustImplement = true
if ssaConfig == nil {
ssaConfig = ssa.NewConfig(Thearch.LinkArch.Name, &ssaExp, Ctxt, Debug['N'] == 0)
- }
- return ssaConfig
-}
-
-func shouldssa(fn *Node) bool {
- switch Thearch.LinkArch.Name {
- default:
- // Only available for testing.
- if os.Getenv("SSATEST") == "" {
- return false
+ if Thearch.LinkArch.Name == "386" {
+ ssaConfig.Set387(Thearch.Use387)
}
- // Generally available.
- case "amd64":
- }
- if !ssaEnabled {
- return false
- }
-
- // Environment variable control of SSA CG
- // 1. IF GOSSAFUNC == current function name THEN
- // compile this function with SSA and log output to ssa.html
-
- // 2. IF GOSSAHASH == "" THEN
- // compile this function (and everything else) with SSA
-
- // 3. IF GOSSAHASH == "n" or "N"
- // IF GOSSAPKG == current package name THEN
- // compile this function (and everything in this package) with SSA
- // ELSE
- // use the old back end for this function.
- // This is for compatibility with existing test harness and should go away.
-
- // 4. IF GOSSAHASH is a suffix of the binary-rendered SHA1 hash of the function name THEN
- // compile this function with SSA
- // ELSE
- // compile this function with the old back end.
-
- // Plan is for 3 to be removed when the tests are revised.
- // SSA is now default, and is disabled by setting
- // GOSSAHASH to n or N, or selectively with strings of
- // 0 and 1.
-
- name := fn.Func.Nname.Sym.Name
-
- funcname := os.Getenv("GOSSAFUNC")
- if funcname != "" {
- // If GOSSAFUNC is set, compile only that function.
- return name == funcname
}
-
- pkg := os.Getenv("GOSSAPKG")
- if pkg != "" {
- // If GOSSAPKG is set, compile only that package.
- return localpkg.Name == pkg
- }
-
- return initssa().DebugHashMatch("GOSSAHASH", name)
+ ssaConfig.HTML = nil
+ return ssaConfig
}
// buildssa builds an SSA function.
@@ -120,6 +66,7 @@ func buildssa(fn *Node) *ssa.Func {
s.f.Name = name
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
@@ -127,11 +74,6 @@ func buildssa(fn *Node) *ssa.Func {
s.config.HTML = ssa.NewHTMLWriter("ssa.html", s.config, name)
// TODO: generate and print a mapping from nodes to values and blocks
}
- defer func() {
- if !printssa {
- s.config.HTML.Close()
- }
- }()
// Allocate starting block
s.f.Entry = s.f.NewBlock(ssa.BlockPlain)
@@ -139,6 +81,7 @@ func buildssa(fn *Node) *ssa.Func {
// Allocate starting values
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])
@@ -154,17 +97,13 @@ func buildssa(fn *Node) *ssa.Func {
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)
+ s.decladdrs[n] = s.entryNewValue1A(ssa.OpAddr, ptrto(n.Type), aux, s.sp)
if n.Class == PPARAMOUT && s.canSSA(n) {
// Save ssa-able PPARAMOUT variables so we can
// store them back to the stack at the end of
// the function.
s.returns = append(s.returns, n)
}
- if n.Class == PPARAM && s.canSSA(n) && n.Type.IsPtrShaped() {
- s.ptrargs = append(s.ptrargs, n)
- n.SetNotLiveAtEnd(true) // SSA takes care of this explicitly
- }
case PAUTO:
// processed at each use, to prevent Addr coming
// before the decl.
@@ -173,13 +112,28 @@ func buildssa(fn *Node) *ssa.Func {
case PFUNC:
// local function - already handled by frontend
default:
- s.Unimplementedf("local variable with class %s unimplemented", classnames[n.Class])
+ s.Fatalf("local variable with class %s unimplemented", classnames[n.Class])
}
}
+ // Populate 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)
+ }
+ s.vars[n] = v
+ }
+
// Convert the AST-based IR to the SSA-based IR
- s.stmts(fn.Func.Enter)
- s.stmts(fn.Nbody)
+ s.stmtList(fn.Func.Enter)
+ s.stmtList(fn.Nbody)
// fallthrough to exit
if s.curBlock != nil {
@@ -190,7 +144,7 @@ func buildssa(fn *Node) *ssa.Func {
// Check that we used all labels
for name, lab := range s.labels {
- if !lab.used() && !lab.reported {
+ if !lab.used() && !lab.reported && !lab.defNode.Used {
yyerrorl(lab.defNode.Lineno, "label %v defined and not used", name)
lab.reported = true
}
@@ -214,16 +168,7 @@ func buildssa(fn *Node) *ssa.Func {
return nil
}
- prelinkNumvars := s.f.NumValues()
- sparseDefState := s.locatePotentialPhiFunctions(fn)
-
- // Link up variable uses to variable definitions
- s.linkForwardReferences(sparseDefState)
-
- if ssa.BuildStats > 0 {
- s.f.LogStat("build", s.f.NumBlocks(), "blocks", prelinkNumvars, "vars_before",
- s.f.NumValues(), "vars_after", prelinkNumvars*s.f.NumBlocks(), "ssa_phi_loc_cutoff_score")
- }
+ s.insertPhis()
// Don't carry reference this around longer than necessary
s.exitCode = Nodes{}
@@ -260,8 +205,14 @@ type state struct {
// variable assignments in the current block (map from variable symbol to ssa value)
// *Node is the unique identifier (an ONAME Node) for the variable.
+ // TODO: keep a single varnum map, then make all of these maps slices instead?
vars map[*Node]*ssa.Value
+ // fwdVars are variables that are used before they are defined in the current block.
+ // This map exists just to coalesce multiple references into a single FwdRef op.
+ // *Node is the unique identifier (an ONAME Node) for the variable.
+ fwdVars map[*Node]*ssa.Value
+
// all defined variables at the end of each block. Indexed by block ID.
defvars []map[*Node]*ssa.Value
@@ -283,15 +234,11 @@ type state struct {
// Used to deduplicate panic calls.
panics map[funcLine]*ssa.Block
- // list of FwdRef values.
- fwdRefs []*ssa.Value
-
// list of PPARAMOUT (return) variables.
returns []*Node
- // list of PPARAM SSA-able pointer-shaped args. We ensure these are live
- // throughout the function to help users avoid premature finalizers.
- ptrargs []*Node
+ // A dummy value used during phi construction.
+ placeholder *ssa.Value
cgoUnsafeArgs bool
noWB bool
@@ -331,12 +278,9 @@ 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) Unimplementedf(msg string, args ...interface{}) {
- s.config.Unimplementedf(s.peekLine(), msg, args...)
-}
+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() }
@@ -350,9 +294,7 @@ var (
newlenVar = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "newlen"}}
capVar = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "cap"}}
typVar = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "typ"}}
- idataVar = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "idata"}}
okVar = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "ok"}}
- deltaVar = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "delta"}}
)
// startBlock sets the current block we're generating code in to b.
@@ -362,6 +304,9 @@ func (s *state) startBlock(b *ssa.Block) {
}
s.curBlock = b
s.vars = map[*Node]*ssa.Value{}
+ for n := range s.fwdVars {
+ delete(s.fwdVars, n)
+ }
}
// endBlock marks the end of generating code for the current block.
@@ -459,6 +404,11 @@ func (s *state) newValue3I(op ssa.Op, t ssa.Type, aux int64, arg0, arg1, arg2 *s
return s.curBlock.NewValue3I(s.peekLine(), 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)
+}
+
// 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)
@@ -530,20 +480,14 @@ func (s *state) constInt(t ssa.Type, c int64) *ssa.Value {
return s.constInt32(t, int32(c))
}
-func (s *state) stmts(a Nodes) {
- for _, x := range a.Slice() {
- s.stmt(x)
- }
-}
-
-// ssaStmtList converts the statement n to SSA and adds it to s.
+// stmtList converts the statement list n to SSA and adds it to s.
func (s *state) stmtList(l Nodes) {
for _, n := range l.Slice() {
s.stmt(n)
}
}
-// ssaStmt converts the statement n to SSA and adds it to s.
+// stmt converts the statement n to SSA and adds it to s.
func (s *state) stmt(n *Node) {
s.pushLine(n.Lineno)
defer s.popLine()
@@ -568,18 +512,26 @@ func (s *state) stmt(n *Node) {
case OEMPTY, ODCLCONST, ODCLTYPE, OFALL:
// Expression statements
- case OCALLFUNC, OCALLMETH, OCALLINTER:
+ case OCALLFUNC:
+ if isIntrinsicCall(n) {
+ s.intrinsicCall(n)
+ return
+ }
+ fallthrough
+
+ case OCALLMETH, OCALLINTER:
s.call(n, callNormal)
- if n.Op == OCALLFUNC && n.Left.Op == ONAME && n.Left.Class == PFUNC &&
- (compiling_runtime && n.Left.Sym.Name == "throw" ||
- n.Left.Sym.Pkg == Runtimepkg && (n.Left.Sym.Name == "gopanic" || n.Left.Sym.Name == "selectgo" || n.Left.Sym.Name == "block")) {
- m := s.mem()
- b := s.endBlock()
- b.Kind = ssa.BlockExit
- b.SetControl(m)
- // TODO: never rewrite OPANIC to OCALLFUNC in the
- // first place. Need to wait until all backends
- // go through SSA.
+ 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") {
+ m := s.mem()
+ b := s.endBlock()
+ b.Kind = ssa.BlockExit
+ b.SetControl(m)
+ // TODO: never rewrite OPANIC to OCALLFUNC in the
+ // first place. Need to wait until all backends
+ // go through SSA.
+ }
}
case ODEFER:
s.call(n.Left, callDefer)
@@ -588,10 +540,41 @@ func (s *state) stmt(n *Node) {
case OAS2DOTTYPE:
res, resok := s.dottype(n.Rlist.First(), true)
- s.assign(n.List.First(), res, needwritebarrier(n.List.First(), n.Rlist.First()), false, n.Lineno, 0, false)
+ deref := false
+ if !canSSAType(n.Rlist.First().Type) {
+ if res.Op != ssa.OpLoad {
+ s.Fatalf("dottype of non-load")
+ }
+ mem := s.mem()
+ if mem.Op == ssa.OpVarKill {
+ mem = mem.Args[0]
+ }
+ if res.Args[1] != mem {
+ s.Fatalf("memory no longer live from 2-result dottype load")
+ }
+ 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)
return
+ case OAS2FUNC:
+ // We come here only when it is an intrinsic call returning two values.
+ if !isIntrinsicCall(n.Rlist.First()) {
+ s.Fatalf("non-intrinsic AS2FUNC not expanded %v", n.Rlist.First())
+ }
+ 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)
+ return
+
case ODCL:
if n.Left.Class == PAUTOHEAP {
Fatalf("DCL %v", n)
@@ -687,7 +670,7 @@ func (s *state) stmt(n *Node) {
rhs := n.Right
if rhs != nil {
switch rhs.Op {
- case OSTRUCTLIT, OARRAYLIT:
+ case OSTRUCTLIT, OARRAYLIT, OSLICELIT:
// All literals with nonzero fields have already been
// rewritten during walk. Any that remain are just T{}
// or equivalents. Use the zero value.
@@ -701,15 +684,24 @@ func (s *state) stmt(n *Node) {
// If the slice can be SSA'd, it'll be on the stack,
// so there will be no write barriers,
// so there's no need to attempt to prevent them.
- if samesafeexpr(n.Left, rhs.List.First()) && !s.canSSA(n.Left) {
- s.append(rhs, true)
- return
+ if samesafeexpr(n.Left, rhs.List.First()) {
+ if !s.canSSA(n.Left) {
+ if Debug_append > 0 {
+ Warnl(n.Lineno, "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)")
+ }
+ }
}
}
}
var r *ssa.Value
var isVolatile bool
- needwb := n.Op == OASWB && rhs != nil
+ needwb := n.Op == OASWB
deref := !canSSAType(t)
if deref {
if rhs == nil {
@@ -724,7 +716,7 @@ func (s *state) stmt(n *Node) {
r = s.expr(rhs)
}
}
- if rhs != nil && rhs.Op == OAPPEND {
+ 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?
@@ -778,7 +770,7 @@ func (s *state) stmt(n *Node) {
}
s.startBlock(bThen)
- s.stmts(n.Nbody)
+ s.stmtList(n.Nbody)
if b := s.endBlock(); b != nil {
b.AddEdgeTo(bEnd)
}
@@ -888,7 +880,7 @@ func (s *state) stmt(n *Node) {
// generate body
s.startBlock(bBody)
- s.stmts(n.Nbody)
+ s.stmtList(n.Nbody)
// tear down continue/break
s.continueTo = prevContinue
@@ -927,7 +919,7 @@ func (s *state) stmt(n *Node) {
}
// generate body code
- s.stmts(n.Nbody)
+ s.stmtList(n.Nbody)
s.breakTo = prevBreak
if lab != nil {
@@ -955,7 +947,7 @@ func (s *state) stmt(n *Node) {
case OVARLIVE:
// Insert a varlive op to record that a variable is still live.
if !n.Left.Addrtaken {
- s.Fatalf("VARLIVE variable %s must have Addrtaken set", n.Left)
+ s.Fatalf("VARLIVE variable %v must have Addrtaken set", n.Left)
}
s.vars[&memVar] = s.newValue1A(ssa.OpVarLive, ssa.TypeMem, n.Left, s.mem())
@@ -963,8 +955,11 @@ func (s *state) stmt(n *Node) {
p := s.expr(n.Left)
s.nilCheck(p)
+ case OSQRT:
+ s.expr(n.Left)
+
default:
- s.Unimplementedf("unhandled stmt %s", n.Op)
+ s.Fatalf("unhandled stmt %v", n.Op)
}
}
@@ -978,7 +973,7 @@ func (s *state) exit() *ssa.Block {
// Run exit code. Typically, this code copies heap-allocated PPARAMOUT
// variables back to the stack.
- s.stmts(s.exitCode)
+ s.stmtList(s.exitCode)
// Store SSAable PPARAMOUT variables back to stack locations.
for _, n := range s.returns {
@@ -991,16 +986,6 @@ func (s *state) exit() *ssa.Block {
// currently.
}
- // Keep input pointer args live until the return. This is a bandaid
- // fix for 1.7 for what will become in 1.8 explicit runtime.KeepAlive calls.
- // For <= 1.7 we guarantee that pointer input arguments live to the end of
- // the function to prevent premature (from the user's point of view)
- // execution of finalizers. See issue 15277.
- // TODO: remove for 1.8?
- for _, n := range s.ptrargs {
- s.vars[&memVar] = s.newValue2(ssa.OpKeepAlive, ssa.TypeMem, s.variable(n, n.Type), s.mem())
- }
-
// Do actual return.
m := s.mem()
b := s.endBlock()
@@ -1146,6 +1131,7 @@ var opToSSA = map[opAndType]ssa.Op{
opAndType{OEQ, TFUNC}: ssa.OpEqPtr,
opAndType{OEQ, TMAP}: ssa.OpEqPtr,
opAndType{OEQ, TCHAN}: ssa.OpEqPtr,
+ opAndType{OEQ, TPTR32}: ssa.OpEqPtr,
opAndType{OEQ, TPTR64}: ssa.OpEqPtr,
opAndType{OEQ, TUINTPTR}: ssa.OpEqPtr,
opAndType{OEQ, TUNSAFEPTR}: ssa.OpEqPtr,
@@ -1166,6 +1152,7 @@ var opToSSA = map[opAndType]ssa.Op{
opAndType{ONE, TFUNC}: ssa.OpNeqPtr,
opAndType{ONE, TMAP}: ssa.OpNeqPtr,
opAndType{ONE, TCHAN}: ssa.OpNeqPtr,
+ opAndType{ONE, TPTR32}: ssa.OpNeqPtr,
opAndType{ONE, TPTR64}: ssa.OpNeqPtr,
opAndType{ONE, TUINTPTR}: ssa.OpNeqPtr,
opAndType{ONE, TUNSAFEPTR}: ssa.OpNeqPtr,
@@ -1251,7 +1238,7 @@ func (s *state) ssaOp(op Op, t *Type) ssa.Op {
etype := s.concreteEtype(t)
x, ok := opToSSA[opAndType{op, etype}]
if !ok {
- s.Unimplementedf("unhandled binary op %s %s", op, etype)
+ s.Fatalf("unhandled binary op %v %s", op, etype)
}
return x
}
@@ -1330,6 +1317,23 @@ var fpConvOpToSSA = map[twoTypes]twoOpsAndType{
twoTypes{TFLOAT32, TFLOAT64}: twoOpsAndType{ssa.OpCvt32Fto64F, ssa.OpCopy, TFLOAT64},
}
+// this map is used only for 32-bit arch, and only includes the difference
+// on 32-bit arch, don't use int64<->float conversion for uint32
+var fpConvOpToSSA32 = map[twoTypes]twoOpsAndType{
+ twoTypes{TUINT32, TFLOAT32}: twoOpsAndType{ssa.OpCopy, ssa.OpCvt32Uto32F, TUINT32},
+ twoTypes{TUINT32, TFLOAT64}: twoOpsAndType{ssa.OpCopy, ssa.OpCvt32Uto64F, TUINT32},
+ twoTypes{TFLOAT32, TUINT32}: twoOpsAndType{ssa.OpCvt32Fto32U, ssa.OpCopy, TUINT32},
+ twoTypes{TFLOAT64, TUINT32}: twoOpsAndType{ssa.OpCvt64Fto32U, ssa.OpCopy, TUINT32},
+}
+
+// uint64<->float conversions, only on machines that have intructions for that
+var uint64fpConvOpToSSA = map[twoTypes]twoOpsAndType{
+ twoTypes{TUINT64, TFLOAT32}: twoOpsAndType{ssa.OpCopy, ssa.OpCvt64Uto32F, TUINT64},
+ twoTypes{TUINT64, TFLOAT64}: twoOpsAndType{ssa.OpCopy, ssa.OpCvt64Uto64F, TUINT64},
+ twoTypes{TFLOAT32, TUINT64}: twoOpsAndType{ssa.OpCvt32Fto64U, ssa.OpCopy, TUINT64},
+ twoTypes{TFLOAT64, TUINT64}: twoOpsAndType{ssa.OpCvt64Fto64U, ssa.OpCopy, TUINT64},
+}
+
var shiftOpToSSA = map[opAndTwoTypes]ssa.Op{
opAndTwoTypes{OLSH, TINT8, TUINT8}: ssa.OpLsh8x8,
opAndTwoTypes{OLSH, TUINT8, TUINT8}: ssa.OpLsh8x8,
@@ -1409,7 +1413,7 @@ func (s *state) ssaShiftOp(op Op, t *Type, u *Type) ssa.Op {
etype2 := s.concreteEtype(u)
x, ok := shiftOpToSSA[opAndTwoTypes{op, etype1, etype2}]
if !ok {
- s.Unimplementedf("unhandled shift op %s etype=%s/%s", op, etype1, etype2)
+ s.Fatalf("unhandled shift op %v etype=%s/%s", op, etype1, etype2)
}
return x
}
@@ -1418,7 +1422,7 @@ func (s *state) ssaRotateOp(op Op, t *Type) ssa.Op {
etype1 := s.concreteEtype(t)
x, ok := opToSSA[opAndType{op, etype1}]
if !ok {
- s.Unimplementedf("unhandled rotate op %s etype=%s", op, etype1)
+ s.Fatalf("unhandled rotate op %v etype=%s", op, etype1)
}
return x
}
@@ -1434,6 +1438,16 @@ func (s *state) expr(n *Node) *ssa.Value {
s.stmtList(n.Ninit)
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)
+ 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)
+ 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})
return s.entryNewValue1A(ssa.OpAddr, n.Type, aux, s.sb)
@@ -1442,7 +1456,7 @@ func (s *state) expr(n *Node) *ssa.Value {
// "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)
+ return s.entryNewValue1A(ssa.OpAddr, ptrto(n.Type), aux, s.sb)
}
if s.canSSA(n) {
return s.variable(n, n.Type)
@@ -1516,7 +1530,7 @@ func (s *state) expr(n *Node) *ssa.Value {
}
default:
- s.Unimplementedf("unhandled OLITERAL %v", n.Val().Ctype())
+ s.Fatalf("unhandled OLITERAL %v", n.Val().Ctype())
return nil
}
case OCONVNOP:
@@ -1602,7 +1616,7 @@ func (s *state) expr(n *Node) *ssa.Value {
case 84:
op = ssa.OpTrunc64to32
default:
- s.Fatalf("weird integer truncation %s -> %s", ft, tt)
+ s.Fatalf("weird integer truncation %v -> %v", ft, tt)
}
} else if ft.IsSigned() {
// sign extension
@@ -1620,7 +1634,7 @@ func (s *state) expr(n *Node) *ssa.Value {
case 48:
op = ssa.OpSignExt32to64
default:
- s.Fatalf("bad integer sign extension %s -> %s", ft, tt)
+ s.Fatalf("bad integer sign extension %v -> %v", ft, tt)
}
} else {
// zero extension
@@ -1638,7 +1652,7 @@ func (s *state) expr(n *Node) *ssa.Value {
case 48:
op = ssa.OpZeroExt32to64
default:
- s.Fatalf("weird integer sign extension %s -> %s", ft, tt)
+ s.Fatalf("weird integer sign extension %v -> %v", ft, tt)
}
}
return s.newValue1(op, n.Type, x)
@@ -1646,8 +1660,39 @@ 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 conv1, ok1 := fpConvOpToSSA32[twoTypes{s.concreteEtype(ft), s.concreteEtype(tt)}]; ok1 {
+ conv = conv1
+ }
+ }
+ if Thearch.LinkArch.Name == "arm64" {
+ if conv1, ok1 := uint64fpConvOpToSSA[twoTypes{s.concreteEtype(ft), s.concreteEtype(tt)}]; ok1 {
+ conv = conv1
+ }
+ }
+
+ 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 {
+ return s.uint32Tofloat32(n, x, ft, tt)
+ }
+ if tt.Size() == 8 {
+ return s.uint32Tofloat64(n, x, ft, tt)
+ }
+ } else if tt.Size() == 4 && tt.IsInteger() && !tt.IsSigned() {
+ // ft is float32 or float64, and tt is unsigned integer
+ if ft.Size() == 4 {
+ return s.float32ToUint32(n, x, ft, tt)
+ }
+ if ft.Size() == 8 {
+ return s.float64ToUint32(n, x, ft, tt)
+ }
+ }
+ }
+
if !ok {
- s.Fatalf("weird float conversion %s -> %s", ft, tt)
+ s.Fatalf("weird float conversion %v -> %v", ft, tt)
}
op1, op2, it := conv.op1, conv.op2, conv.intermediateType
@@ -1666,23 +1711,23 @@ func (s *state) expr(n *Node) *ssa.Value {
}
// Tricky 64-bit unsigned cases.
if ft.IsInteger() {
- // therefore tt is float32 or float64, and ft is also unsigned
+ // tt is float32 or float64, and ft is also unsigned
if tt.Size() == 4 {
return s.uint64Tofloat32(n, x, ft, tt)
}
if tt.Size() == 8 {
return s.uint64Tofloat64(n, x, ft, tt)
}
- s.Fatalf("weird unsigned integer to float conversion %s -> %s", ft, tt)
+ s.Fatalf("weird unsigned integer to float conversion %v -> %v", ft, tt)
}
- // therefore ft is float32 or float64, and tt is unsigned integer
+ // ft is float32 or float64, and tt is unsigned integer
if ft.Size() == 4 {
return s.float32ToUint64(n, x, ft, tt)
}
if ft.Size() == 8 {
return s.float64ToUint64(n, x, ft, tt)
}
- s.Fatalf("weird float to unsigned integer conversion %s -> %s", ft, tt)
+ s.Fatalf("weird float to unsigned integer conversion %v -> %v", ft, tt)
return nil
}
@@ -1695,7 +1740,7 @@ func (s *state) expr(n *Node) *ssa.Value {
} else if ft.Size() == 16 && tt.Size() == 8 {
op = ssa.OpCvt64Fto32F
} else {
- s.Fatalf("weird complex conversion %s -> %s", ft, tt)
+ s.Fatalf("weird complex conversion %v -> %v", ft, tt)
}
ftp := floatForComplex(ft)
ttp := floatForComplex(tt)
@@ -1704,7 +1749,7 @@ func (s *state) expr(n *Node) *ssa.Value {
s.newValue1(op, ttp, s.newValue1(ssa.OpComplexImag, ftp, x)))
}
- s.Unimplementedf("unhandled OCONV %s -> %s", n.Left.Type.Etype, n.Type.Etype)
+ s.Fatalf("unhandled OCONV %s -> %s", n.Left.Type.Etype, n.Type.Etype)
return nil
case ODOTTYPE:
@@ -1720,14 +1765,14 @@ func (s *state) expr(n *Node) *ssa.Value {
op := s.ssaOp(OEQ, pt)
r := s.newValue2(op, Types[TBOOL], s.newValue1(ssa.OpComplexReal, pt, a), s.newValue1(ssa.OpComplexReal, pt, b))
i := s.newValue2(op, Types[TBOOL], s.newValue1(ssa.OpComplexImag, pt, a), s.newValue1(ssa.OpComplexImag, pt, b))
- c := s.newValue2(ssa.OpAnd8, Types[TBOOL], r, i)
+ c := s.newValue2(ssa.OpAndB, Types[TBOOL], r, i)
switch n.Op {
case OEQ:
return c
case ONE:
return s.newValue1(ssa.OpNot, Types[TBOOL], c)
default:
- s.Fatalf("ordered complex compare %s", n.Op)
+ s.Fatalf("ordered complex compare %v", n.Op)
}
}
return s.newValue2(s.ssaOp(n.Op, n.Left.Type), Types[TBOOL], a, b)
@@ -1810,19 +1855,12 @@ func (s *state) expr(n *Node) *ssa.Value {
}
if n.Type.IsFloat() {
return s.newValue2(s.ssaOp(n.Op, n.Type), a.Type, a, b)
- } else {
- // do a size-appropriate check for zero
- cmp := s.newValue2(s.ssaOp(ONE, n.Type), Types[TBOOL], b, s.zeroVal(n.Type))
- s.check(cmp, panicdivide)
- return s.newValue2(s.ssaOp(n.Op, n.Type), a.Type, a, b)
}
+ return s.intDivide(n, a, b)
case OMOD:
a := s.expr(n.Left)
b := s.expr(n.Right)
- // do a size-appropriate check for zero
- cmp := s.newValue2(s.ssaOp(ONE, n.Type), Types[TBOOL], b, s.zeroVal(n.Type))
- s.check(cmp, panicdivide)
- return s.newValue2(s.ssaOp(n.Op, n.Type), a.Type, a, b)
+ return s.intDivide(n, a, b)
case OADD, OSUB:
a := s.expr(n.Left)
b := s.expr(n.Right)
@@ -1923,12 +1961,8 @@ func (s *state) expr(n *Node) *ssa.Value {
// Note we know the volatile result is false because you can't write &f() in Go.
return a
- case OINDREG:
- if int(n.Reg) != Thearch.REGSP {
- s.Unimplementedf("OINDREG of non-SP register %s in expr: %v", obj.Rconv(int(n.Reg)), n)
- return nil
- }
- addr := s.entryNewValue1I(ssa.OpOffPtr, Ptrto(n.Type), n.Xoffset, s.sp)
+ case OINDREGSP:
+ addr := s.entryNewValue1I(ssa.OpOffPtr, ptrto(n.Type), n.Xoffset, s.sp)
return s.newValue2(ssa.OpLoad, n.Type, addr, s.mem())
case OIND:
@@ -1952,14 +1986,20 @@ func (s *state) expr(n *Node) *ssa.Value {
case OINDEX:
switch {
case n.Left.Type.IsString():
+ 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()])))
+ }
a := s.expr(n.Left)
i := s.expr(n.Right)
- i = s.extendIndex(i)
+ i = s.extendIndex(i, panicindex)
if !n.Bounded {
len := s.newValue1(ssa.OpStringLen, Types[TINT], a)
s.boundsCheck(i, len)
}
- ptrtyp := Ptrto(Types[TUINT8])
+ ptrtyp := ptrto(Types[TUINT8])
ptr := s.newValue1(ssa.OpStringPtr, ptrtyp, a)
if Isconst(n.Right, CTINT) {
ptr = s.newValue1I(ssa.OpOffPtr, ptrtyp, n.Right.Int64(), ptr)
@@ -1971,7 +2011,22 @@ func (s *state) expr(n *Node) *ssa.Value {
p, _ := s.addr(n, false)
return s.newValue2(ssa.OpLoad, n.Left.Type.Elem(), p, s.mem())
case n.Left.Type.IsArray():
- // TODO: fix when we can SSA arrays of length 1.
+ if bound := n.Left.Type.NumElem(); bound <= 1 {
+ // SSA can handle arrays of length at most 1.
+ a := s.expr(n.Left)
+ i := s.expr(n.Right)
+ if bound == 0 {
+ // Bounds check will never succeed. Might as well
+ // use constants for the bounds check.
+ z := s.constInt(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))
+ return s.newValue1I(ssa.OpArraySelect, n.Type, 0, a)
+ }
p, _ := s.addr(n, false)
return s.newValue2(ssa.OpLoad, n.Left.Type.Elem(), p, s.mem())
default:
@@ -2007,35 +2062,13 @@ func (s *state) expr(n *Node) *ssa.Value {
a := s.expr(n.Left)
return s.newValue1(ssa.OpITab, n.Type, a)
+ case OIDATA:
+ a := s.expr(n.Left)
+ return s.newValue1(ssa.OpIData, n.Type, a)
+
case OEFACE:
tab := s.expr(n.Left)
data := s.expr(n.Right)
- // The frontend allows putting things like struct{*byte} in
- // the data portion of an eface. But we don't want struct{*byte}
- // as a register type because (among other reasons) the liveness
- // analysis is confused by the "fat" variables that result from
- // such types being spilled.
- // So here we ensure that we are selecting the underlying pointer
- // when we build an eface.
- // TODO: get rid of this now that structs can be SSA'd?
- for !data.Type.IsPtrShaped() {
- switch {
- case data.Type.IsArray():
- data = s.newValue1I(ssa.OpArrayIndex, data.Type.ElemType(), 0, data)
- case data.Type.IsStruct():
- for i := data.Type.NumFields() - 1; i >= 0; i-- {
- f := data.Type.FieldType(i)
- if f.Size() == 0 {
- // eface type could also be struct{p *byte; q [0]int}
- continue
- }
- data = s.newValue1I(ssa.OpStructSelect, f, int64(i), data)
- break
- }
- default:
- s.Fatalf("type being put into an eface isn't a pointer")
- }
- }
return s.newValue2(ssa.OpIMake, n.Type, tab, data)
case OSLICE, OSLICEARR, OSLICE3, OSLICE3ARR:
@@ -2043,13 +2076,13 @@ func (s *state) expr(n *Node) *ssa.Value {
var i, j, k *ssa.Value
low, high, max := n.SliceBounds()
if low != nil {
- i = s.extendIndex(s.expr(low))
+ i = s.extendIndex(s.expr(low), panicslice)
}
if high != nil {
- j = s.extendIndex(s.expr(high))
+ j = s.extendIndex(s.expr(high), panicslice)
}
if max != nil {
- k = s.extendIndex(s.expr(max))
+ k = s.extendIndex(s.expr(max), panicslice)
}
p, l, c := s.slice(n.Left.Type, v, i, j, k)
return s.newValue3(ssa.OpSliceMake, n.Type, p, l, c)
@@ -2059,17 +2092,17 @@ func (s *state) expr(n *Node) *ssa.Value {
var i, j *ssa.Value
low, high, _ := n.SliceBounds()
if low != nil {
- i = s.extendIndex(s.expr(low))
+ i = s.extendIndex(s.expr(low), panicslice)
}
if high != nil {
- j = s.extendIndex(s.expr(high))
+ j = s.extendIndex(s.expr(high), panicslice)
}
p, l, _ := s.slice(n.Left.Type, v, i, j, nil)
return s.newValue2(ssa.OpStringMake, n.Type, p, l)
case OCALLFUNC:
- if isIntrinsicCall1(n) {
- return s.intrinsicCall1(n)
+ if isIntrinsicCall(n) {
+ return s.intrinsicCall(n)
}
fallthrough
@@ -2084,7 +2117,7 @@ func (s *state) expr(n *Node) *ssa.Value {
return s.append(n, false)
default:
- s.Unimplementedf("unhandled expr %s", n.Op)
+ s.Fatalf("unhandled expr %v", n.Op)
return nil
}
}
@@ -2130,7 +2163,7 @@ func (s *state) append(n *Node, inplace bool) *ssa.Value {
// *(ptr+len+2) = e3
et := n.Type.Elem()
- pt := Ptrto(et)
+ pt := ptrto(et)
// Evaluate slice
sn := n.List.First() // the slice node is the first in the list
@@ -2182,9 +2215,13 @@ func (s *state) append(n *Node, inplace bool) *ssa.Value {
// 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)
+ capaddr := s.newValue1I(ssa.OpOffPtr, pt, int64(array_cap), addr)
s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, s.config.IntSize, capaddr, r[2], s.mem())
- s.insertWBstore(pt, addr, r[0], n.Lineno, 0)
+ 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)
+ }
// 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
@@ -2203,7 +2240,7 @@ func (s *state) append(n *Node, inplace bool) *ssa.Value {
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)
+ 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())
}
@@ -2246,7 +2283,7 @@ func (s *state) append(n *Node, inplace bool) *ssa.Value {
if haspointers(et) {
s.insertWBmove(et, addr, arg.v, n.Lineno, arg.isVolatile)
} else {
- s.vars[&memVar] = s.newValue3I(ssa.OpMove, ssa.TypeMem, et.Size(), addr, arg.v, s.mem())
+ s.vars[&memVar] = s.newValue3I(ssa.OpMove, ssa.TypeMem, sizeAlignAuxInt(et), addr, arg.v, s.mem())
}
}
}
@@ -2329,7 +2366,7 @@ func (s *state) assign(left *Node, right *ssa.Value, wb, deref bool, line int32,
dowidth(t)
if s.canSSA(left) {
if deref {
- s.Fatalf("can SSA LHS %s but not RHS %s", left, right)
+ s.Fatalf("can SSA LHS %v but not RHS %s", left, right)
}
if left.Op == ODOT {
// We're assigning to a field of an ssa-able value.
@@ -2366,6 +2403,30 @@ func (s *state) assign(left *Node, right *ssa.Value, wb, deref bool, line int32,
// TODO: do we need to update named values here?
return
}
+ if left.Op == OINDEX && left.Left.Type.IsArray() {
+ // We're assigning to an element of an ssa-able array.
+ // a[i] = v
+ t := left.Left.Type
+ n := t.NumElem()
+
+ i := s.expr(left.Right) // index
+ 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)
+ s.boundsCheck(z, z)
+ return
+ }
+ if n != 1 {
+ s.Fatalf("assigning to non-1-length array")
+ }
+ // Rewrite to a = [1]{v}
+ i = s.extendIndex(i, panicindex)
+ s.boundsCheck(i, s.constInt(Types[TINT], 1))
+ v := s.newValue1(ssa.OpArrayMake1, t, right)
+ s.assign(left.Left, v, false, false, line, 0, rightIsVolatile)
+ return
+ }
// Update variable assignment.
s.vars[left] = right
s.addNamedValue(left, right)
@@ -2378,19 +2439,19 @@ func (s *state) assign(left *Node, right *ssa.Value, wb, deref bool, line int32,
}
if deref {
// Treat as a mem->mem move.
- if right == nil {
- s.vars[&memVar] = s.newValue2I(ssa.OpZero, ssa.TypeMem, t.Size(), addr, s.mem())
+ if wb && !ssa.IsStackAddr(addr) {
+ s.insertWBmove(t, addr, right, line, rightIsVolatile)
return
}
- if wb {
- s.insertWBmove(t, addr, right, line, rightIsVolatile)
+ if right == nil {
+ s.vars[&memVar] = s.newValue2I(ssa.OpZero, ssa.TypeMem, sizeAlignAuxInt(t), addr, s.mem())
return
}
- s.vars[&memVar] = s.newValue3I(ssa.OpMove, ssa.TypeMem, t.Size(), addr, right, s.mem())
+ s.vars[&memVar] = s.newValue3I(ssa.OpMove, ssa.TypeMem, sizeAlignAuxInt(t), addr, right, s.mem())
return
}
// Treat as a store.
- if wb {
+ 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.
@@ -2424,7 +2485,7 @@ func (s *state) zeroVal(t *Type) *ssa.Value {
case 8:
return s.constInt64(t, 0)
default:
- s.Fatalf("bad sized integer type %s", t)
+ s.Fatalf("bad sized integer type %v", t)
}
case t.IsFloat():
switch t.Size() {
@@ -2433,7 +2494,7 @@ func (s *state) zeroVal(t *Type) *ssa.Value {
case 8:
return s.constFloat64(t, 0)
default:
- s.Fatalf("bad sized float type %s", t)
+ s.Fatalf("bad sized float type %v", t)
}
case t.IsComplex():
switch t.Size() {
@@ -2444,7 +2505,7 @@ func (s *state) zeroVal(t *Type) *ssa.Value {
z := s.constFloat64(Types[TFLOAT64], 0)
return s.entryNewValue2(ssa.OpComplexMake, t, z, z)
default:
- s.Fatalf("bad sized complex type %s", t)
+ s.Fatalf("bad sized complex type %v", t)
}
case t.IsString():
@@ -2464,8 +2525,15 @@ func (s *state) zeroVal(t *Type) *ssa.Value {
v.AddArg(s.zeroVal(t.FieldType(i).(*Type)))
}
return v
+ case t.IsArray():
+ switch t.NumElem() {
+ case 0:
+ return s.entryNewValue0(ssa.OpArrayMake0, t)
+ case 1:
+ return s.entryNewValue1(ssa.OpArrayMake1, t, s.zeroVal(t.Elem()))
+ }
}
- s.Unimplementedf("zero for type %v not implemented", t)
+ s.Fatalf("zero for type %v not implemented", t)
return nil
}
@@ -2477,73 +2545,371 @@ const (
callGo
)
-// isSSAIntrinsic1 returns true if n is a call to a recognized 1-arg intrinsic
-// that can be handled by the SSA backend.
-// SSA uses this, but so does the front end to see if should not
-// inline a function because it is a candidate for intrinsic
-// substitution.
-func isSSAIntrinsic1(s *Sym) bool {
- // The test below is not quite accurate -- in the event that
- // a function is disabled on a per-function basis, for example
- // because of hash-keyed binary failure search, SSA might be
- // disabled for that function but it would not be noted here,
- // and thus an inlining would not occur (in practice, inlining
- // so far has only been noticed for Bswap32 and the 16-bit count
- // leading/trailing instructions, but heuristics might change
- // in the future or on different architectures).
- if !ssaEnabled || ssa.IntrinsicsDisable || Thearch.LinkArch.Family != sys.AMD64 {
- return false
+// 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
+}
+
+// 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 {
+ pkg string
+ fn string
+ size int
+}
+
+// disableForInstrumenting returns nil when instrumenting, fn otherwise
+func disableForInstrumenting(fn intrinsicBuilder) intrinsicBuilder {
+ if instrumenting {
+ return nil
}
- if s != nil && s.Pkg != nil && s.Pkg.Path == "runtime/internal/sys" {
- switch s.Name {
- case
- "Ctz64", "Ctz32", "Ctz16",
- "Bswap64", "Bswap32":
- return true
- }
+ 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
+ }
+ 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())
+ return nil
+ },
+
+ /******** 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())
+ 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())
+ 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())
+ 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())
+ 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())
+ 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"}],
+ }
+
+ /******** 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: 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"}]
+
+ /******** 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)
+}
+
+// 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 {
+ if ssa.IntrinsicsDisable {
+ return nil
+ }
+ if sym == nil || sym.Pkg == nil {
+ return nil
}
- return false
+ 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
+ }
+ return intrinsics.ptrSized[sizedIntrinsicKey{pkg, fn, Widthptr}]
}
-func isIntrinsicCall1(n *Node) bool {
+func isIntrinsicCall(n *Node) bool {
if n == nil || n.Left == nil {
return false
}
- return isSSAIntrinsic1(n.Left.Sym)
+ return findIntrinsic(n.Left.Sym) != nil
}
-// intrinsicFirstArg extracts arg from n.List and eval
-func (s *state) intrinsicFirstArg(n *Node) *ssa.Value {
- x := n.List.First()
- if x.Op == OAS {
- x = x.Right
+// intrinsicCall converts a call to a recognized intrinsic function into the intrinsic SSA operation.
+func (s *state) intrinsicCall(n *Node) *ssa.Value {
+ v := findIntrinsic(n.Left.Sym)(s, n, s.intrinsicArgs(n))
+ if ssa.IntrinsicsDebug > 0 {
+ x := v
+ if x == nil {
+ x = s.mem()
+ }
+ 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())
}
- return s.expr(x)
+ return v
}
-// intrinsicCall1 converts a call to a recognized 1-arg intrinsic
-// into the intrinsic
-func (s *state) intrinsicCall1(n *Node) *ssa.Value {
- var result *ssa.Value
- switch n.Left.Sym.Name {
- case "Ctz64":
- result = s.newValue1(ssa.OpCtz64, Types[TUINT64], s.intrinsicFirstArg(n))
- case "Ctz32":
- result = s.newValue1(ssa.OpCtz32, Types[TUINT32], s.intrinsicFirstArg(n))
- case "Ctz16":
- result = s.newValue1(ssa.OpCtz16, Types[TUINT16], s.intrinsicFirstArg(n))
- case "Bswap64":
- result = s.newValue1(ssa.OpBswap64, Types[TUINT64], s.intrinsicFirstArg(n))
- case "Bswap32":
- result = s.newValue1(ssa.OpBswap32, Types[TUINT32], s.intrinsicFirstArg(n))
- }
- if result == nil {
- Fatalf("Unknown special call: %v", n.Left.Sym)
+type callArg struct {
+ offset int64
+ v *ssa.Value
+}
+type byOffset []callArg
+
+func (x byOffset) Len() int { return len(x) }
+func (x byOffset) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
+func (x byOffset) Less(i, j int) bool {
+ return x[i].offset < x[j].offset
+}
+
+// intrinsicArgs extracts args from n, evaluates them to SSA values, and returns them.
+func (s *state) intrinsicArgs(n *Node) []*ssa.Value {
+ // This code is complicated because of how walk transforms calls. For a call node,
+ // each entry in n.List is either an assignment to OINDREGSP which actually
+ // stores an arg, or an assignment to a temporary which computes an arg
+ // which is later assigned.
+ // The args can also be out of order.
+ // TODO: when walk goes away someday, this code can go away also.
+ var args []callArg
+ temps := map[*Node]*ssa.Value{}
+ for _, a := range n.List.Slice() {
+ if a.Op != OAS {
+ s.Fatalf("non-assignment as a function argument %s", opnames[a.Op])
+ }
+ l, r := a.Left, a.Right
+ switch l.Op {
+ case ONAME:
+ // Evaluate and store to "temporary".
+ // Walk ensures these temporaries are dead outside of n.
+ temps[l] = s.expr(r)
+ case OINDREGSP:
+ // Store a value to an argument slot.
+ var v *ssa.Value
+ if x, ok := temps[r]; ok {
+ // This is a previously computed temporary.
+ v = x
+ } else {
+ // This is an explicit value; evaluate it.
+ v = s.expr(r)
+ }
+ args = append(args, callArg{l.Xoffset, v})
+ default:
+ s.Fatalf("function argument assignment target not allowed: %s", opnames[l.Op])
+ }
}
- if ssa.IntrinsicsDebug > 0 {
- Warnl(n.Lineno, "intrinsic substitution for %v with %s", n.Left.Sym.Name, result.LongString())
+ sort.Sort(byOffset(args))
+ res := make([]*ssa.Value, len(args))
+ for i, a := range args {
+ res[i] = a.v
}
- return result
+ return res
}
// Calls the function n using the specified call type.
@@ -2569,9 +2935,15 @@ func (s *state) call(n *Node, k callKind) *ssa.Value {
sym = fn.Sym
break
}
+ // Make a name n2 for the function.
+ // fn.Sym might be sync.(*Mutex).Unlock.
+ // 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.
closure = s.expr(n2)
// Note: receiver is already assigned in n.List, so we don't
// want to set it here.
@@ -2585,7 +2957,7 @@ func (s *state) call(n *Node, k callKind) *ssa.Value {
s.nilCheck(itab)
}
itabidx := fn.Xoffset + 3*int64(Widthptr) + 8 // offset of fun field in runtime.itab
- itab = s.newValue1I(ssa.OpOffPtr, Types[TUINTPTR], itabidx, itab)
+ itab = s.newValue1I(ssa.OpOffPtr, ptrto(Types[TUINTPTR]), itabidx, itab)
if k == callNormal {
codeptr = s.newValue2(ssa.OpLoad, Types[TUINTPTR], itab, s.mem())
} else {
@@ -2608,22 +2980,23 @@ func (s *state) call(n *Node, k callKind) *ssa.Value {
if k != callNormal {
argStart += int64(2 * Widthptr)
}
- addr := s.entryNewValue1I(ssa.OpOffPtr, Types[TUINTPTR], argStart, s.sp)
+ 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())
}
// Defer/go args
if k != callNormal {
// Write argsize and closure (args to Newproc/Deferproc).
+ argStart := Ctxt.FixedFrameSize()
argsize := s.constInt32(Types[TUINT32], int32(stksize))
- s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, 4, s.sp, argsize, s.mem())
- addr := s.entryNewValue1I(ssa.OpOffPtr, Ptrto(Types[TUINTPTR]), int64(Widthptr), s.sp)
+ 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())
stksize += 2 * int64(Widthptr)
}
// call target
- bNext := s.f.NewBlock(ssa.BlockPlain)
var call *ssa.Value
switch {
case k == callDefer:
@@ -2638,39 +3011,34 @@ func (s *state) call(n *Node, k callKind) *ssa.Value {
case sym != nil:
call = s.newValue1A(ssa.OpStaticCall, ssa.TypeMem, sym, s.mem())
default:
- Fatalf("bad call type %s %v", n.Op, n)
+ Fatalf("bad call type %v %v", n.Op, n)
}
call.AuxInt = stksize // Call operations carry the argsize of the callee along with them
-
- // Finish call block
s.vars[&memVar] = call
- b := s.endBlock()
- b.Kind = ssa.BlockCall
- b.SetControl(call)
- b.AddEdgeTo(bNext)
+
+ // Finish block for defers
if k == callDefer {
- // Add recover edge to exit code.
+ b := s.endBlock()
b.Kind = ssa.BlockDefer
+ b.SetControl(call)
+ bNext := s.f.NewBlock(ssa.BlockPlain)
+ b.AddEdgeTo(bNext)
+ // Add recover edge to exit code.
r := s.f.NewBlock(ssa.BlockPlain)
s.startBlock(r)
s.exit()
b.AddEdgeTo(r)
b.Likely = ssa.BranchLikely
+ s.startBlock(bNext)
}
- // Start exit block, find address of result.
- s.startBlock(bNext)
- // Keep input pointer args live across calls. This is a bandaid until 1.8.
- for _, n := range s.ptrargs {
- s.vars[&memVar] = s.newValue2(ssa.OpKeepAlive, ssa.TypeMem, s.variable(n, n.Type), s.mem())
- }
res := n.Left.Type.Results()
if res.NumFields() == 0 || k != callNormal {
// call has no return value. Continue with the next statement.
return nil
}
fp := res.Field(0)
- return s.entryNewValue1I(ssa.OpOffPtr, Ptrto(fp.Type), fp.Offset+Ctxt.FixedFrameSize(), s.sp)
+ return s.entryNewValue1I(ssa.OpOffPtr, ptrto(fp.Type), fp.Offset+Ctxt.FixedFrameSize(), s.sp)
}
// etypesign returns the signed-ness of e, for integer/pointer etypes.
@@ -2711,7 +3079,7 @@ func (s *state) lookupSymbol(n *Node, sym interface{}) interface{} {
// 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)
+ t := ptrto(n.Type)
switch n.Op {
case ONAME:
switch n.Class {
@@ -2730,9 +3098,8 @@ func (s *state) addr(n *Node, bounded bool) (*ssa.Value, bool) {
if v != nil {
return v, false
}
- if n.String() == ".fp" {
- // Special arg that points to the frame pointer.
- // (Used by the race detector, others?)
+ 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
}
@@ -2747,22 +3114,18 @@ func (s *state) addr(n *Node, bounded bool) (*ssa.Value, bool) {
aux := s.lookupSymbol(n, &ssa.ArgSymbol{Typ: n.Type, Node: n})
return s.newValue1A(ssa.OpAddr, t, aux, s.sp), false
default:
- s.Unimplementedf("variable address class %v not implemented", classnames[n.Class])
+ s.Fatalf("variable address class %v not implemented", classnames[n.Class])
return nil, false
}
- case OINDREG:
- // indirect off a register
+ case OINDREGSP:
+ // indirect off REGSP
// used for storing/loading arguments/returns to/from callees
- if int(n.Reg) != Thearch.REGSP {
- s.Unimplementedf("OINDREG of non-SP register %s in addr: %v", obj.Rconv(int(n.Reg)), n)
- return nil, false
- }
return s.entryNewValue1I(ssa.OpOffPtr, t, n.Xoffset, s.sp), true
case OINDEX:
if n.Left.Type.IsSlice() {
a := s.expr(n.Left)
i := s.expr(n.Right)
- i = s.extendIndex(i)
+ i = s.extendIndex(i, panicindex)
len := s.newValue1(ssa.OpSliceLen, Types[TINT], a)
if !n.Bounded {
s.boundsCheck(i, len)
@@ -2772,12 +3135,12 @@ func (s *state) addr(n *Node, bounded bool) (*ssa.Value, bool) {
} else { // array
a, isVolatile := s.addr(n.Left, bounded)
i := s.expr(n.Right)
- i = s.extendIndex(i)
+ i = s.extendIndex(i, panicindex)
len := s.constInt(Types[TINT], n.Left.Type.NumElem())
if !n.Bounded {
s.boundsCheck(i, len)
}
- return s.newValue2(ssa.OpPtrIndex, Ptrto(n.Left.Type.Elem()), a, i), isVolatile
+ return s.newValue2(ssa.OpPtrIndex, ptrto(n.Left.Type.Elem()), a, i), isVolatile
}
case OIND:
return s.exprPtr(n.Left, bounded, n.Lineno), false
@@ -2789,15 +3152,23 @@ func (s *state) addr(n *Node, bounded bool) (*ssa.Value, bool) {
return s.newValue1I(ssa.OpOffPtr, t, n.Xoffset, p), false
case OCLOSUREVAR:
return s.newValue1I(ssa.OpOffPtr, t, n.Xoffset,
- s.entryNewValue0(ssa.OpGetClosurePtr, Ptrto(Types[TUINT8]))), false
+ s.entryNewValue0(ssa.OpGetClosurePtr, ptrto(Types[TUINT8]))), false
case OCONVNOP:
addr, isVolatile := s.addr(n.Left, bounded)
return s.newValue1(ssa.OpCopy, t, addr), isVolatile // ensure that addr has the right type
case OCALLFUNC, OCALLINTER, OCALLMETH:
return s.call(n, callNormal), true
-
+ case ODOTTYPE:
+ v, _ := s.dottype(n, false)
+ if v.Op != ssa.OpLoad {
+ s.Fatalf("dottype of non-load")
+ }
+ if v.Args[1] != s.mem() {
+ s.Fatalf("memory no longer live from dottype load")
+ }
+ return v.Args[0], false
default:
- s.Unimplementedf("unhandled addr %v", n.Op)
+ s.Fatalf("unhandled addr %v", n.Op)
return nil, false
}
}
@@ -2808,7 +3179,7 @@ func (s *state) canSSA(n *Node) bool {
if Debug['N'] != 0 {
return false
}
- for n.Op == ODOT {
+ for n.Op == ODOT || (n.Op == OINDEX && n.Left.Type.IsArray()) {
n = n.Left
}
if n.Op != ONAME {
@@ -2860,11 +3231,15 @@ func canSSAType(t *Type) bool {
}
switch t.Etype {
case TARRAY:
- // We can't do arrays because dynamic indexing is
+ // We can't do larger arrays because dynamic indexing is
// not supported on SSA variables.
- // TODO: maybe allow if length is <=1? All indexes
- // are constant? Might be good for the arrays
- // introduced by the compiler for variadic functions.
+ // TODO: allow if all indexes are constant.
+ if t.NumElem() == 0 {
+ return true
+ }
+ if t.NumElem() == 1 {
+ return canSSAType(t.Elem())
+ }
return false
case TSTRUCT:
if t.NumFields() > ssa.MaxStruct {
@@ -2895,51 +3270,42 @@ func (s *state) exprPtr(n *Node, bounded bool, lineno int32) *ssa.Value {
}
// nilCheck generates nil pointer checking code.
-// Starts a new block on return, unless nil checks are disabled.
// Used only for automatically inserted nil checks,
// not for user code like 'x != nil'.
func (s *state) nilCheck(ptr *ssa.Value) {
- if Disable_checknil != 0 {
+ if disable_checknil != 0 {
return
}
- chk := s.newValue2(ssa.OpNilCheck, ssa.TypeVoid, ptr, s.mem())
- b := s.endBlock()
- b.Kind = ssa.BlockCheck
- b.SetControl(chk)
- bNext := s.f.NewBlock(ssa.BlockPlain)
- b.AddEdgeTo(bNext)
- s.startBlock(bNext)
+ s.newValue2(ssa.OpNilCheck, ssa.TypeVoid, ptr, s.mem())
}
// boundsCheck generates bounds checking code. Checks if 0 <= idx < len, branches to exit if not.
// Starts a new block on return.
+// idx is already converted to full int width.
func (s *state) boundsCheck(idx, len *ssa.Value) {
if Debug['B'] != 0 {
return
}
- // TODO: convert index to full width?
- // TODO: if index is 64-bit and we're compiling to 32-bit, check that high 32 bits are zero.
// bounds check
cmp := s.newValue2(ssa.OpIsInBounds, Types[TBOOL], idx, len)
- s.check(cmp, Panicindex)
+ s.check(cmp, panicindex)
}
// sliceBoundsCheck generates slice bounds checking code. Checks if 0 <= idx <= len, branches to exit if not.
// Starts a new block on return.
+// idx and len are already converted to full int width.
func (s *state) sliceBoundsCheck(idx, len *ssa.Value) {
if Debug['B'] != 0 {
return
}
- // TODO: convert index to full width?
- // TODO: if index is 64-bit and we're compiling to 32-bit, check that high 32 bits are zero.
// bounds check
cmp := s.newValue2(ssa.OpIsSliceInBounds, Types[TBOOL], idx, len)
s.check(cmp, panicslice)
}
-// If cmp (a bool) is true, panic using the given function.
+// If cmp (a bool) is false, panic using the given function.
func (s *state) check(cmp *ssa.Value, fn *Node) {
b := s.endBlock()
b.Kind = ssa.BlockIf
@@ -2961,53 +3327,61 @@ func (s *state) check(cmp *ssa.Value, fn *Node) {
s.startBlock(bNext)
}
+func (s *state) intDivide(n *Node, a, b *ssa.Value) *ssa.Value {
+ needcheck := true
+ switch b.Op {
+ case ssa.OpConst8, ssa.OpConst16, ssa.OpConst32, ssa.OpConst64:
+ if b.AuxInt != 0 {
+ needcheck = false
+ }
+ }
+ if needcheck {
+ // do a size-appropriate check for zero
+ cmp := s.newValue2(s.ssaOp(ONE, n.Type), Types[TBOOL], b, s.zeroVal(n.Type))
+ s.check(cmp, panicdivide)
+ }
+ return s.newValue2(s.ssaOp(n.Op, n.Type), a.Type, a, b)
+}
+
// rtcall issues a call to the given runtime function fn with the listed args.
// Returns a slice of results of the given result types.
// The call is added to the end of the current block.
// If returns is false, the block is marked as an exit block.
-// If returns is true, the block is marked as a call block. A new block
-// is started to load the return values.
func (s *state) rtcall(fn *Node, returns bool, results []*Type, args ...*ssa.Value) []*ssa.Value {
// Write args to the stack
- var off int64 // TODO: arch-dependent starting offset?
+ 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, Types[TUINTPTR], off, s.sp)
+ ptr = s.newValue1I(ssa.OpOffPtr, t.PtrTo(), off, s.sp)
}
size := t.Size()
s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, size, ptr, arg, s.mem())
off += size
}
off = Rnd(off, int64(Widthptr))
+ if Thearch.LinkArch.Name == "amd64p32" {
+ // amd64p32 wants 8-byte alignment of the start of the return values.
+ off = Rnd(off, 8)
+ }
// Issue call
call := s.newValue1A(ssa.OpStaticCall, ssa.TypeMem, fn.Sym, s.mem())
s.vars[&memVar] = call
- // Finish block
- b := s.endBlock()
if !returns {
+ // Finish block
+ b := s.endBlock()
b.Kind = ssa.BlockExit
b.SetControl(call)
- call.AuxInt = off
+ call.AuxInt = off - Ctxt.FixedFrameSize()
if len(results) > 0 {
Fatalf("panic call can't have results")
}
return nil
}
- b.Kind = ssa.BlockCall
- b.SetControl(call)
- bNext := s.f.NewBlock(ssa.BlockPlain)
- b.AddEdgeTo(bNext)
- s.startBlock(bNext)
-
- // Keep input pointer args live across calls. This is a bandaid until 1.8.
- for _, n := range s.ptrargs {
- s.vars[&memVar] = s.newValue2(ssa.OpKeepAlive, ssa.TypeMem, s.variable(n, n.Type), s.mem())
- }
// Load results
res := make([]*ssa.Value, len(results))
@@ -3015,7 +3389,7 @@ func (s *state) rtcall(fn *Node, returns bool, results []*Type, args ...*ssa.Val
off = Rnd(off, t.Alignment())
ptr := s.sp
if off != 0 {
- ptr = s.newValue1I(ssa.OpOffPtr, Types[TUINTPTR], off, s.sp)
+ ptr = s.newValue1I(ssa.OpOffPtr, ptrto(t), off, s.sp)
}
res[i] = s.newValue2(ssa.OpLoad, t, ptr, s.mem())
off += t.Size()
@@ -3030,67 +3404,51 @@ func (s *state) rtcall(fn *Node, returns bool, results []*Type, args ...*ssa.Val
// 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.Fatalf("write barrier prohibited")
+ s.Error("write barrier prohibited")
}
if s.WBLineno == 0 {
s.WBLineno = left.Line
}
- bThen := s.f.NewBlock(ssa.BlockPlain)
- bElse := s.f.NewBlock(ssa.BlockPlain)
- bEnd := s.f.NewBlock(ssa.BlockPlain)
- aux := &ssa.ExternSymbol{Typ: Types[TBOOL], Sym: syslook("writeBarrier").Sym}
- flagaddr := s.newValue1A(ssa.OpAddr, Ptrto(Types[TUINT32]), aux, s.sb)
- // TODO: select the .enabled field. It is currently first, so not needed for now.
- // Load word, test byte, avoiding partial register write from load byte.
- flag := s.newValue2(ssa.OpLoad, Types[TUINT32], flagaddr, s.mem())
- flag = s.newValue1(ssa.OpTrunc64to8, Types[TBOOL], flag)
- b := s.endBlock()
- b.Kind = ssa.BlockIf
- b.Likely = ssa.BranchUnlikely
- b.SetControl(flag)
- b.AddEdgeTo(bThen)
- b.AddEdgeTo(bElse)
-
- s.startBlock(bThen)
-
- if !rightIsVolatile {
- // Issue typedmemmove call.
- taddr := s.newValue1A(ssa.OpAddr, Types[TUINTPTR], &ssa.ExternSymbol{Typ: Types[TUINTPTR], Sym: typenamesym(t)}, s.sb)
- s.rtcall(typedmemmove, true, nil, taddr, left, right)
+ var val *ssa.Value
+ if right == nil {
+ val = s.newValue2I(ssa.OpZeroWB, ssa.TypeMem, sizeAlignAuxInt(t), left, s.mem())
} else {
- // Copy to temp location if the source is volatile (will be clobbered by
- // a function call). Marshaling the args to typedmemmove might clobber the
- // value we're trying to move.
- tmp := temp(t)
- s.vars[&memVar] = s.newValue1A(ssa.OpVarDef, ssa.TypeMem, tmp, s.mem())
- tmpaddr, _ := s.addr(tmp, true)
- s.vars[&memVar] = s.newValue3I(ssa.OpMove, ssa.TypeMem, t.Size(), tmpaddr, right, s.mem())
- // Issue typedmemmove call.
- taddr := s.newValue1A(ssa.OpAddr, Types[TUINTPTR], &ssa.ExternSymbol{Typ: Types[TUINTPTR], Sym: typenamesym(t)}, s.sb)
- s.rtcall(typedmemmove, true, nil, taddr, left, tmpaddr)
- // Mark temp as dead.
- s.vars[&memVar] = s.newValue1A(ssa.OpVarKill, ssa.TypeMem, tmp, s.mem())
+ 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())
}
- s.endBlock().AddEdgeTo(bEnd)
-
- s.startBlock(bElse)
- s.vars[&memVar] = s.newValue3I(ssa.OpMove, ssa.TypeMem, t.Size(), left, right, s.mem())
- s.endBlock().AddEdgeTo(bEnd)
+ val.Aux = &ssa.ExternSymbol{Typ: Types[TUINTPTR], Sym: typenamesym(t)}
+ s.vars[&memVar] = val
- s.startBlock(bEnd)
-
- if Debug_wb > 0 {
- Warnl(line, "write barrier")
- }
+ // 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.
@@ -3104,45 +3462,21 @@ func (s *state) insertWBstore(t *Type, left, right *ssa.Value, line int32, skip
// }
if s.noWB {
- s.Fatalf("write barrier prohibited")
+ s.Error("write barrier prohibited")
}
if s.WBLineno == 0 {
s.WBLineno = left.Line
}
s.storeTypeScalars(t, left, right, skip)
-
- bThen := s.f.NewBlock(ssa.BlockPlain)
- bElse := s.f.NewBlock(ssa.BlockPlain)
- bEnd := s.f.NewBlock(ssa.BlockPlain)
-
- aux := &ssa.ExternSymbol{Typ: Types[TBOOL], Sym: syslook("writeBarrier").Sym}
- flagaddr := s.newValue1A(ssa.OpAddr, Ptrto(Types[TUINT32]), aux, s.sb)
- // TODO: select the .enabled field. It is currently first, so not needed for now.
- // Load word, test byte, avoiding partial register write from load byte.
- flag := s.newValue2(ssa.OpLoad, Types[TUINT32], flagaddr, s.mem())
- flag = s.newValue1(ssa.OpTrunc64to8, Types[TBOOL], flag)
- b := s.endBlock()
- b.Kind = ssa.BlockIf
- b.Likely = ssa.BranchUnlikely
- b.SetControl(flag)
- b.AddEdgeTo(bThen)
- b.AddEdgeTo(bElse)
-
- // Issue write barriers for pointer writes.
- s.startBlock(bThen)
s.storeTypePtrsWB(t, left, right)
- s.endBlock().AddEdgeTo(bEnd)
-
- // Issue regular stores for pointer writes.
- s.startBlock(bElse)
- s.storeTypePtrs(t, left, right)
- s.endBlock().AddEdgeTo(bEnd)
- s.startBlock(bEnd)
-
- if Debug_wb > 0 {
- Warnl(line, "write barrier")
- }
+ // 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.
@@ -3157,22 +3491,22 @@ func (s *state) storeTypeScalars(t *Type, left, right *ssa.Value, skip skipMask)
return
}
len := s.newValue1(ssa.OpStringLen, Types[TINT], right)
- lenAddr := s.newValue1I(ssa.OpOffPtr, Ptrto(Types[TINT]), s.config.IntSize, left)
+ lenAddr := s.newValue1I(ssa.OpOffPtr, ptrto(Types[TINT]), s.config.IntSize, left)
s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, s.config.IntSize, lenAddr, len, s.mem())
case t.IsSlice():
if skip&skipLen == 0 {
len := s.newValue1(ssa.OpSliceLen, Types[TINT], right)
- lenAddr := s.newValue1I(ssa.OpOffPtr, Ptrto(Types[TINT]), s.config.IntSize, left)
+ lenAddr := s.newValue1I(ssa.OpOffPtr, ptrto(Types[TINT]), s.config.IntSize, left)
s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, s.config.IntSize, lenAddr, len, s.mem())
}
if skip&skipCap == 0 {
cap := s.newValue1(ssa.OpSliceCap, Types[TINT], right)
- capAddr := s.newValue1I(ssa.OpOffPtr, Ptrto(Types[TINT]), 2*s.config.IntSize, left)
+ capAddr := s.newValue1I(ssa.OpOffPtr, ptrto(Types[TINT]), 2*s.config.IntSize, left)
s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, s.config.IntSize, capAddr, cap, s.mem())
}
case t.IsInterface():
// itab field doesn't need a write barrier (even though it is a pointer).
- itab := s.newValue1(ssa.OpITab, Ptrto(Types[TUINT8]), right)
+ itab := s.newValue1(ssa.OpITab, ptrto(Types[TUINT8]), right)
s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, s.config.IntSize, left, itab, s.mem())
case t.IsStruct():
n := t.NumFields()
@@ -3182,8 +3516,12 @@ func (s *state) storeTypeScalars(t *Type, left, right *ssa.Value, skip skipMask)
val := s.newValue1I(ssa.OpStructSelect, ft, int64(i), right)
s.storeTypeScalars(ft.(*Type), addr, val, 0)
}
+ case t.IsArray() && t.NumElem() == 0:
+ // nothing
+ case t.IsArray() && t.NumElem() == 1:
+ s.storeTypeScalars(t.Elem(), left, s.newValue1I(ssa.OpArraySelect, t.Elem(), 0, right), 0)
default:
- s.Fatalf("bad write barrier type %s", t)
+ s.Fatalf("bad write barrier type %v", t)
}
}
@@ -3193,15 +3531,15 @@ func (s *state) storeTypePtrs(t *Type, left, right *ssa.Value) {
case t.IsPtrShaped():
s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, s.config.PtrSize, left, right, s.mem())
case t.IsString():
- ptr := s.newValue1(ssa.OpStringPtr, Ptrto(Types[TUINT8]), right)
+ ptr := s.newValue1(ssa.OpStringPtr, ptrto(Types[TUINT8]), right)
s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, s.config.PtrSize, left, ptr, s.mem())
case t.IsSlice():
- ptr := s.newValue1(ssa.OpSlicePtr, Ptrto(Types[TUINT8]), right)
+ ptr := s.newValue1(ssa.OpSlicePtr, ptrto(Types[TUINT8]), right)
s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, s.config.PtrSize, left, ptr, s.mem())
case t.IsInterface():
// itab field is treated as a scalar.
- idata := s.newValue1(ssa.OpIData, Ptrto(Types[TUINT8]), right)
- idataAddr := s.newValue1I(ssa.OpOffPtr, Ptrto(Types[TUINT8]), s.config.PtrSize, left)
+ idata := s.newValue1(ssa.OpIData, ptrto(Types[TUINT8]), right)
+ idataAddr := s.newValue1I(ssa.OpOffPtr, ptrto(Types[TUINT8]), s.config.PtrSize, left)
s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, s.config.PtrSize, idataAddr, idata, s.mem())
case t.IsStruct():
n := t.NumFields()
@@ -3214,26 +3552,31 @@ func (s *state) storeTypePtrs(t *Type, left, right *ssa.Value) {
val := s.newValue1I(ssa.OpStructSelect, ft, int64(i), right)
s.storeTypePtrs(ft.(*Type), addr, val)
}
+ case t.IsArray() && t.NumElem() == 0:
+ // nothing
+ case t.IsArray() && t.NumElem() == 1:
+ s.storeTypePtrs(t.Elem(), left, s.newValue1I(ssa.OpArraySelect, t.Elem(), 0, right))
default:
- s.Fatalf("bad write barrier type %s", t)
+ s.Fatalf("bad write barrier type %v", t)
}
}
-// do *left = right with a write barrier for all pointer parts of t.
+// 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.rtcall(writebarrierptr, true, nil, left, right)
+ 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.rtcall(writebarrierptr, true, nil, left, ptr)
+ 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.rtcall(writebarrierptr, true, nil, left, ptr)
+ 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():
- idata := s.newValue1(ssa.OpIData, Ptrto(Types[TUINT8]), right)
- idataAddr := s.newValue1I(ssa.OpOffPtr, Ptrto(Types[TUINT8]), s.config.PtrSize, left)
- s.rtcall(writebarrierptr, true, nil, idataAddr, idata)
+ // 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++ {
@@ -3245,8 +3588,12 @@ func (s *state) storeTypePtrsWB(t *Type, left, right *ssa.Value) {
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 %s", t)
+ s.Fatalf("bad write barrier type %v", t)
}
}
@@ -3263,13 +3610,13 @@ func (s *state) slice(t *Type, v, i, j, k *ssa.Value) (p, l, c *ssa.Value) {
switch {
case t.IsSlice():
elemtype = t.Elem()
- ptrtype = Ptrto(elemtype)
+ ptrtype = ptrto(elemtype)
ptr = s.newValue1(ssa.OpSlicePtr, ptrtype, v)
len = s.newValue1(ssa.OpSliceLen, Types[TINT], v)
cap = s.newValue1(ssa.OpSliceCap, Types[TINT], v)
case t.IsString():
elemtype = Types[TUINT8]
- ptrtype = Ptrto(elemtype)
+ ptrtype = ptrto(elemtype)
ptr = s.newValue1(ssa.OpStringPtr, ptrtype, v)
len = s.newValue1(ssa.OpStringLen, Types[TINT], v)
cap = len
@@ -3278,7 +3625,7 @@ func (s *state) slice(t *Type, v, i, j, k *ssa.Value) (p, l, c *ssa.Value) {
s.Fatalf("bad ptr to array in slice %v\n", t)
}
elemtype = t.Elem().Elem()
- ptrtype = Ptrto(elemtype)
+ ptrtype = ptrto(elemtype)
s.nilCheck(v)
ptr = v
len = s.constInt(Types[TINT], t.Elem().NumElem())
@@ -3308,19 +3655,17 @@ func (s *state) slice(t *Type, v, i, j, k *ssa.Value) (p, l, c *ssa.Value) {
}
// Generate the following code assuming that indexes are in bounds.
- // The conditional is to make sure that we don't generate a slice
+ // The masking is to make sure that we don't generate a slice
// that points to the next object in memory.
- // rlen = j-i
- // rcap = k-i
- // delta = i*elemsize
- // if rcap == 0 {
- // delta = 0
- // }
- // rptr = p+delta
+ // rlen = j - i
+ // rcap = k - i
+ // delta = i * elemsize
+ // 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])
- eqOp := s.ssaOp(OEQ, Types[TINT])
mulOp := s.ssaOp(OMUL, Types[TINT])
+ andOp := s.ssaOp(OAND, Types[TINT])
rlen := s.newValue2(subOp, Types[TINT], j, i)
var rcap *ssa.Value
switch {
@@ -3335,47 +3680,30 @@ func (s *state) slice(t *Type, v, i, j, k *ssa.Value) (p, l, c *ssa.Value) {
rcap = s.newValue2(subOp, Types[TINT], k, i)
}
- // delta = # of elements to offset pointer by.
- s.vars[&deltaVar] = i
-
- // Generate code to set delta=0 if the resulting capacity is zero.
- if !((i.Op == ssa.OpConst64 && i.AuxInt == 0) ||
- (i.Op == ssa.OpConst32 && int32(i.AuxInt) == 0)) {
- cmp := s.newValue2(eqOp, Types[TBOOL], rcap, zero)
-
- b := s.endBlock()
- b.Kind = ssa.BlockIf
- b.Likely = ssa.BranchUnlikely
- b.SetControl(cmp)
-
- // Generate block which zeros the delta variable.
- nz := s.f.NewBlock(ssa.BlockPlain)
- b.AddEdgeTo(nz)
- s.startBlock(nz)
- s.vars[&deltaVar] = zero
- s.endBlock()
-
- // All done.
- merge := s.f.NewBlock(ssa.BlockPlain)
- b.AddEdgeTo(merge)
- nz.AddEdgeTo(merge)
- s.startBlock(merge)
-
- // TODO: use conditional moves somehow?
+ var rptr *ssa.Value
+ if (i.Op == ssa.OpConst64 || i.Op == ssa.OpConst32) && i.AuxInt == 0 {
+ // No pointer arithmetic necessary.
+ rptr = ptr
+ } else {
+ // delta = # of bytes to offset pointer by.
+ delta := s.newValue2(mulOp, Types[TINT], i, s.constInt(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)
+ // Compute rptr = ptr + delta
+ rptr = s.newValue2(ssa.OpAddPtr, ptrtype, ptr, delta)
}
- // Compute rptr = ptr + delta * elemsize
- rptr := s.newValue2(ssa.OpAddPtr, ptrtype, ptr, s.newValue2(mulOp, Types[TINT], s.variable(&deltaVar, Types[TINT]), s.constInt(Types[TINT], elemtype.Width)))
- delete(s.vars, &deltaVar)
return rptr, rlen, rcap
}
-type u2fcvtTab struct {
+type u642fcvtTab struct {
geq, cvt2F, and, rsh, or, add ssa.Op
one func(*state, ssa.Type, int64) *ssa.Value
}
-var u64_f64 u2fcvtTab = u2fcvtTab{
+var u64_f64 u642fcvtTab = u642fcvtTab{
geq: ssa.OpGeq64,
cvt2F: ssa.OpCvt64to64F,
and: ssa.OpAnd64,
@@ -3385,7 +3713,7 @@ var u64_f64 u2fcvtTab = u2fcvtTab{
one: (*state).constInt64,
}
-var u64_f32 u2fcvtTab = u2fcvtTab{
+var u64_f32 u642fcvtTab = u642fcvtTab{
geq: ssa.OpGeq64,
cvt2F: ssa.OpCvt64to32F,
and: ssa.OpAnd64,
@@ -3395,29 +3723,15 @@ var u64_f32 u2fcvtTab = u2fcvtTab{
one: (*state).constInt64,
}
-// Excess generality on a machine with 64-bit integer registers.
-// Not used on AMD64.
-var u32_f32 u2fcvtTab = u2fcvtTab{
- geq: ssa.OpGeq32,
- cvt2F: ssa.OpCvt32to32F,
- and: ssa.OpAnd32,
- rsh: ssa.OpRsh32Ux32,
- or: ssa.OpOr32,
- add: ssa.OpAdd32F,
- one: func(s *state, t ssa.Type, x int64) *ssa.Value {
- return s.constInt32(t, int32(x))
- },
-}
-
func (s *state) uint64Tofloat64(n *Node, x *ssa.Value, ft, tt *Type) *ssa.Value {
- return s.uintTofloat(&u64_f64, n, x, ft, tt)
+ return s.uint64Tofloat(&u64_f64, n, x, ft, tt)
}
func (s *state) uint64Tofloat32(n *Node, x *ssa.Value, ft, tt *Type) *ssa.Value {
- return s.uintTofloat(&u64_f32, n, x, ft, tt)
+ return s.uint64Tofloat(&u64_f32, n, x, ft, tt)
}
-func (s *state) uintTofloat(cvttab *u2fcvtTab, n *Node, x *ssa.Value, ft, tt *Type) *ssa.Value {
+func (s *state) uint64Tofloat(cvttab *u642fcvtTab, n *Node, x *ssa.Value, ft, tt *Type) *ssa.Value {
// if x >= 0 {
// result = (floatY) x
// } else {
@@ -3476,6 +3790,66 @@ func (s *state) uintTofloat(cvttab *u2fcvtTab, n *Node, x *ssa.Value, ft, tt *Ty
return s.variable(n, n.Type)
}
+type u322fcvtTab struct {
+ cvtI2F, cvtF2F ssa.Op
+}
+
+var u32_f64 u322fcvtTab = u322fcvtTab{
+ cvtI2F: ssa.OpCvt32to64F,
+ cvtF2F: ssa.OpCopy,
+}
+
+var u32_f32 u322fcvtTab = u322fcvtTab{
+ cvtI2F: ssa.OpCvt32to32F,
+ cvtF2F: ssa.OpCvt64Fto32F,
+}
+
+func (s *state) uint32Tofloat64(n *Node, x *ssa.Value, ft, tt *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 {
+ 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 {
+ // if x >= 0 {
+ // result = floatY(x)
+ // } else {
+ // result = floatY(float64(x) + (1<<32))
+ // }
+ cmp := s.newValue2(ssa.OpGeq32, Types[TBOOL], x, s.zeroVal(ft))
+ b := s.endBlock()
+ b.Kind = ssa.BlockIf
+ b.SetControl(cmp)
+ b.Likely = ssa.BranchLikely
+
+ bThen := s.f.NewBlock(ssa.BlockPlain)
+ bElse := s.f.NewBlock(ssa.BlockPlain)
+ bAfter := s.f.NewBlock(ssa.BlockPlain)
+
+ b.AddEdgeTo(bThen)
+ s.startBlock(bThen)
+ a0 := s.newValue1(cvttab.cvtI2F, tt, x)
+ s.vars[n] = a0
+ s.endBlock()
+ bThen.AddEdgeTo(bAfter)
+
+ 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)
+ a3 := s.newValue1(cvttab.cvtF2F, tt, a2)
+
+ s.vars[n] = a3
+ s.endBlock()
+ bElse.AddEdgeTo(bAfter)
+
+ s.startBlock(bAfter)
+ return s.variable(n, n.Type)
+}
+
// referenceTypeBuiltin generates code for the len/cap builtins for maps and channels.
func (s *state) referenceTypeBuiltin(n *Node, x *ssa.Value) *ssa.Value {
if !n.Left.Type.IsMap() && !n.Left.Type.IsChan() {
@@ -3528,22 +3902,50 @@ func (s *state) referenceTypeBuiltin(n *Node, x *ssa.Value) *ssa.Value {
}
type f2uCvtTab struct {
- ltf, cvt2U, subf ssa.Op
- value func(*state, ssa.Type, float64) *ssa.Value
+ ltf, cvt2U, subf, or ssa.Op
+ floatValue func(*state, ssa.Type, float64) *ssa.Value
+ intValue func(*state, ssa.Type, int64) *ssa.Value
+ cutoff uint64
}
var f32_u64 f2uCvtTab = f2uCvtTab{
- ltf: ssa.OpLess32F,
- cvt2U: ssa.OpCvt32Fto64,
- subf: ssa.OpSub32F,
- value: (*state).constFloat32,
+ ltf: ssa.OpLess32F,
+ cvt2U: ssa.OpCvt32Fto64,
+ subf: ssa.OpSub32F,
+ or: ssa.OpOr64,
+ floatValue: (*state).constFloat32,
+ intValue: (*state).constInt64,
+ cutoff: 9223372036854775808,
}
var f64_u64 f2uCvtTab = f2uCvtTab{
- ltf: ssa.OpLess64F,
- cvt2U: ssa.OpCvt64Fto64,
- subf: ssa.OpSub64F,
- value: (*state).constFloat64,
+ ltf: ssa.OpLess64F,
+ cvt2U: ssa.OpCvt64Fto64,
+ subf: ssa.OpSub64F,
+ or: ssa.OpOr64,
+ floatValue: (*state).constFloat64,
+ intValue: (*state).constInt64,
+ cutoff: 9223372036854775808,
+}
+
+var f32_u32 f2uCvtTab = f2uCvtTab{
+ ltf: ssa.OpLess32F,
+ cvt2U: ssa.OpCvt32Fto32,
+ 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)) },
+ cutoff: 2147483648,
+}
+
+var f64_u32 f2uCvtTab = f2uCvtTab{
+ ltf: ssa.OpLess64F,
+ cvt2U: ssa.OpCvt64Fto32,
+ 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)) },
+ cutoff: 2147483648,
}
func (s *state) float32ToUint64(n *Node, x *ssa.Value, ft, tt *Type) *ssa.Value {
@@ -3553,16 +3955,25 @@ func (s *state) float64ToUint64(n *Node, x *ssa.Value, ft, tt *Type) *ssa.Value
return s.floatToUint(&f64_u64, n, x, ft, tt)
}
+func (s *state) float32ToUint32(n *Node, x *ssa.Value, ft, tt *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 {
+ 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 {
- // if x < 9223372036854775808.0 {
+ // cutoff:=1<<(intY_Size-1)
+ // if x < floatX(cutoff) {
// result = uintY(x)
// } else {
- // y = x - 9223372036854775808.0
+ // y = x - floatX(cutoff)
// z = uintY(y)
- // result = z | -9223372036854775808
+ // result = z | -(cutoff)
// }
- twoToThe63 := cvttab.value(s, ft, 9223372036854775808.0)
- cmp := s.newValue2(cvttab.ltf, Types[TBOOL], x, twoToThe63)
+ cutoff := cvttab.floatValue(s, ft, float64(cvttab.cutoff))
+ cmp := s.newValue2(cvttab.ltf, Types[TBOOL], x, cutoff)
b := s.endBlock()
b.Kind = ssa.BlockIf
b.SetControl(cmp)
@@ -3581,10 +3992,10 @@ func (s *state) floatToUint(cvttab *f2uCvtTab, n *Node, x *ssa.Value, ft, tt *Ty
b.AddEdgeTo(bElse)
s.startBlock(bElse)
- y := s.newValue2(cvttab.subf, ft, x, twoToThe63)
+ y := s.newValue2(cvttab.subf, ft, x, cutoff)
y = s.newValue1(cvttab.cvt2U, tt, y)
- z := s.constInt64(tt, -9223372036854775808)
- a1 := s.newValue2(ssa.OpOr64, tt, y, z)
+ z := cvttab.intValue(s, tt, int64(-cvttab.cutoff))
+ a1 := s.newValue2(cvttab.or, tt, y, z)
s.vars[n] = a1
s.endBlock()
bElse.AddEdgeTo(bAfter)
@@ -3594,20 +4005,20 @@ func (s *state) floatToUint(cvttab *f2uCvtTab, n *Node, x *ssa.Value, ft, tt *Ty
}
// ifaceType returns the value for the word containing the type.
-// n is the node for the interface expression.
+// t is the type of the interface expression.
// v is the corresponding value.
-func (s *state) ifaceType(n *Node, v *ssa.Value) *ssa.Value {
- byteptr := Ptrto(Types[TUINT8]) // type used in runtime prototypes for runtime type (*byte)
+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 n.Type.IsEmptyInterface() {
- // Have *eface. The type is the first word in the struct.
+ 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.
+ // 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
@@ -3639,18 +4050,120 @@ func (s *state) ifaceType(n *Node, v *ssa.Value) *ssa.Value {
// commaok indicates whether to panic or return a bool.
// If commaok is false, resok will be nil.
func (s *state) dottype(n *Node, commaok bool) (res, resok *ssa.Value) {
- iface := s.expr(n.Left)
- typ := s.ifaceType(n.Left, iface) // actual concrete type
+ iface := s.expr(n.Left) // input interface
target := s.expr(typename(n.Type)) // target type
- if !isdirectiface(n.Type) {
- // walk rewrites ODOTTYPE/OAS2DOTTYPE into runtime calls except for this case.
- Fatalf("dottype needs a direct iface type %s", n.Type)
+ byteptr := ptrto(Types[TUINT8])
+
+ 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")
+ }
+
+ // 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))
+
+ if n.Left.Type.IsEmptyInterface() && commaok {
+ // Converting empty interface to empty interface with ,ok is just a nil check.
+ return iface, cond
+ }
+
+ // Branch on nilness.
+ b := s.endBlock()
+ b.Kind = ssa.BlockIf
+ b.SetControl(cond)
+ b.Likely = ssa.BranchLikely
+ bOk := s.f.NewBlock(ssa.BlockPlain)
+ bFail := s.f.NewBlock(ssa.BlockPlain)
+ b.AddEdgeTo(bOk)
+ b.AddEdgeTo(bFail)
+
+ if !commaok {
+ // On failure, panic by calling panicnildottype.
+ s.startBlock(bFail)
+ s.rtcall(panicnildottype, false, nil, target)
+
+ // On success, return (perhaps modified) input interface.
+ s.startBlock(bOk)
+ if n.Left.Type.IsEmptyInterface() {
+ res = iface // Use input interface unchanged.
+ return
+ }
+ // Load type out of itab, build interface with existing idata.
+ off := s.newValue1I(ssa.OpOffPtr, byteptr, int64(Widthptr), itab)
+ typ := s.newValue2(ssa.OpLoad, byteptr, off, s.mem())
+ idata := s.newValue1(ssa.OpIData, n.Type, iface)
+ res = s.newValue2(ssa.OpIMake, n.Type, typ, idata)
+ return
+ }
+
+ s.startBlock(bOk)
+ // nonempty -> empty
+ // Need to load type from itab
+ off := s.newValue1I(ssa.OpOffPtr, byteptr, int64(Widthptr), itab)
+ s.vars[&typVar] = s.newValue2(ssa.OpLoad, byteptr, off, s.mem())
+ s.endBlock()
+
+ // itab is nil, might as well use that as the nil result.
+ s.startBlock(bFail)
+ s.vars[&typVar] = itab
+ s.endBlock()
+
+ // Merge point.
+ bEnd := s.f.NewBlock(ssa.BlockPlain)
+ bOk.AddEdgeTo(bEnd)
+ bFail.AddEdgeTo(bEnd)
+ s.startBlock(bEnd)
+ idata := s.newValue1(ssa.OpIData, n.Type, iface)
+ res = s.newValue2(ssa.OpIMake, n.Type, s.variable(&typVar, byteptr), idata)
+ resok = cond
+ delete(s.vars, &typVar)
+ return
+ }
+ // converting to a nonempty interface needs a runtime call.
+ if Debug_typeassert > 0 {
+ Warnl(n.Lineno, "type assertion not inlined")
+ }
+ if n.Left.Type.IsEmptyInterface() {
+ if commaok {
+ call := s.rtcall(assertE2I2, true, []*Type{n.Type, Types[TBOOL]}, target, iface)
+ return call[0], call[1]
+ }
+ return s.rtcall(assertE2I, true, []*Type{n.Type}, target, iface)[0], nil
+ }
+ if commaok {
+ call := s.rtcall(assertI2I2, true, []*Type{n.Type, Types[TBOOL]}, target, iface)
+ return call[0], call[1]
+ }
+ return s.rtcall(assertI2I, true, []*Type{n.Type}, target, iface)[0], nil
}
if Debug_typeassert > 0 {
Warnl(n.Lineno, "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
+
+ if Debug_typeassert > 0 {
+ Warnl(n.Lineno, "type assertion inlined")
+ }
+
+ var tmp *Node // temporary for use with large types
+ var addr *ssa.Value // address of tmp
+ 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())
+ }
+
// 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)
@@ -3659,8 +4172,6 @@ func (s *state) dottype(n *Node, commaok bool) (res, resok *ssa.Value) {
b.SetControl(cond)
b.Likely = ssa.BranchLikely
- byteptr := Ptrto(Types[TUINT8])
-
bOk := s.f.NewBlock(ssa.BlockPlain)
bFail := s.f.NewBlock(ssa.BlockPlain)
b.AddEdgeTo(bOk)
@@ -3672,34 +4183,60 @@ func (s *state) dottype(n *Node, commaok bool) (res, resok *ssa.Value) {
taddr := s.newValue1A(ssa.OpAddr, byteptr, &ssa.ExternSymbol{Typ: byteptr, Sym: typenamesym(n.Left.Type)}, s.sb)
s.rtcall(panicdottype, false, nil, typ, target, taddr)
- // on success, return idata field
+ // on success, return data from interface
s.startBlock(bOk)
- return s.newValue1(ssa.OpIData, n.Type, iface), nil
+ if direct {
+ return s.newValue1(ssa.OpIData, n.Type, iface), nil
+ }
+ p := s.newValue1(ssa.OpIData, ptrto(n.Type), iface)
+ return s.newValue2(ssa.OpLoad, n.Type, p, s.mem()), nil
}
// commaok is the more complicated case because we have
// a control flow merge point.
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"}}
// type assertion succeeded
s.startBlock(bOk)
- s.vars[&idataVar] = s.newValue1(ssa.OpIData, n.Type, iface)
+ if tmp == nil {
+ if direct {
+ s.vars[valVar] = s.newValue1(ssa.OpIData, n.Type, iface)
+ } else {
+ p := s.newValue1(ssa.OpIData, ptrto(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())
+ }
s.vars[&okVar] = s.constBool(true)
s.endBlock()
bOk.AddEdgeTo(bEnd)
// type assertion failed
s.startBlock(bFail)
- s.vars[&idataVar] = s.constNil(byteptr)
+ 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())
+ }
s.vars[&okVar] = s.constBool(false)
s.endBlock()
bFail.AddEdgeTo(bEnd)
// merge point
s.startBlock(bEnd)
- res = s.variable(&idataVar, byteptr)
+ if tmp == nil {
+ res = s.variable(valVar, n.Type)
+ 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())
+ }
resok = s.variable(&okVar, Types[TBOOL])
- delete(s.vars, &idataVar)
delete(s.vars, &okVar)
return res, resok
}
@@ -3765,139 +4302,37 @@ func (s *state) checkgoto(from *Node, to *Node) {
// variable returns the value of a variable at the current location.
func (s *state) variable(name *Node, t ssa.Type) *ssa.Value {
v := s.vars[name]
- if v == nil {
- v = s.newValue0A(ssa.OpFwdRef, t, name)
- s.fwdRefs = append(s.fwdRefs, v)
- s.vars[name] = v
- s.addNamedValue(name, v)
- }
- return v
-}
-
-func (s *state) mem() *ssa.Value {
- return s.variable(&memVar, ssa.TypeMem)
-}
-
-func (s *state) linkForwardReferences(dm *sparseDefState) {
-
- // Build SSA graph. Each variable on its first use in a basic block
- // leaves a FwdRef in that block representing the incoming value
- // of that variable. This function links that ref up with possible definitions,
- // inserting Phi values as needed. This is essentially the algorithm
- // described by Braun, Buchwald, Hack, Leißa, Mallon, and Zwinkau:
- // http://pp.info.uni-karlsruhe.de/uploads/publikationen/braun13cc.pdf
- // Differences:
- // - We use FwdRef nodes to postpone phi building until the CFG is
- // completely built. That way we can avoid the notion of "sealed"
- // blocks.
- // - Phi optimization is a separate pass (in ../ssa/phielim.go).
- for len(s.fwdRefs) > 0 {
- v := s.fwdRefs[len(s.fwdRefs)-1]
- s.fwdRefs = s.fwdRefs[:len(s.fwdRefs)-1]
- s.resolveFwdRef(v, dm)
- }
-}
-
-// resolveFwdRef modifies v to be the variable's value at the start of its block.
-// v must be a FwdRef op.
-func (s *state) resolveFwdRef(v *ssa.Value, dm *sparseDefState) {
- b := v.Block
- name := v.Aux.(*Node)
- v.Aux = nil
- if b == s.f.Entry {
- // Live variable at start of function.
- if s.canSSA(name) {
- if strings.HasPrefix(name.Sym.Name, "autotmp_") {
- // It's likely that this is an uninitialized variable in the entry block.
- s.Fatalf("Treating auto as if it were arg, func %s, node %v, value %v", b.Func.Name, name, v)
- }
- v.Op = ssa.OpArg
- v.Aux = name
- return
- }
- // Not SSAable. Load it.
- addr := s.decladdrs[name]
- if addr == nil {
- // TODO: closure args reach here.
- s.Unimplementedf("unhandled closure arg %s at entry to function %s", name, b.Func.Name)
- }
- if _, ok := addr.Aux.(*ssa.ArgSymbol); !ok {
- s.Fatalf("variable live at start of function %s is not an argument %s", b.Func.Name, name)
- }
- v.Op = ssa.OpLoad
- v.AddArgs(addr, s.startmem)
- return
- }
- if len(b.Preds) == 0 {
- // This block is dead; we have no predecessors and we're not the entry block.
- // It doesn't matter what we use here as long as it is well-formed.
- v.Op = ssa.OpUnknown
- return
- }
- // Find variable value on each predecessor.
- var argstore [4]*ssa.Value
- args := argstore[:0]
- for _, e := range b.Preds {
- p := e.Block()
- p = dm.FindBetterDefiningBlock(name, p) // try sparse improvement on p
- args = append(args, s.lookupVarOutgoing(p, v.Type, name, v.Line))
- }
-
- // Decide if we need a phi or not. We need a phi if there
- // are two different args (which are both not v).
- var w *ssa.Value
- for _, a := range args {
- if a == v {
- continue // self-reference
- }
- if a == w {
- continue // already have this witness
- }
- if w != nil {
- // two witnesses, need a phi value
- v.Op = ssa.OpPhi
- v.AddArgs(args...)
- return
- }
- w = a // save witness
+ if v != nil {
+ return v
}
- if w == nil {
- s.Fatalf("no witness for reachable phi %s", v)
+ v = s.fwdVars[name]
+ if v != nil {
+ return v
}
- // One witness. Make v a copy of w.
- v.Op = ssa.OpCopy
- v.AddArg(w)
-}
-// lookupVarOutgoing finds the variable's value at the end of block b.
-func (s *state) lookupVarOutgoing(b *ssa.Block, t ssa.Type, name *Node, line int32) *ssa.Value {
- for {
- if v, ok := s.defvars[b.ID][name]; ok {
- return v
- }
- // The variable is not defined by b and we haven't looked it up yet.
- // If b has exactly one predecessor, loop to look it up there.
- // Otherwise, give up and insert a new FwdRef and resolve it later.
- if len(b.Preds) != 1 {
- break
- }
- b = b.Preds[0].Block()
+ if s.curBlock == s.f.Entry {
+ // No variable should be live at entry.
+ s.Fatalf("Value live at entry. It shouldn't be. func %s, node %v, value %v", s.f.Name, name, v)
}
- // Generate a FwdRef for the variable and return that.
- v := b.NewValue0A(line, ssa.OpFwdRef, t, name)
- s.fwdRefs = append(s.fwdRefs, v)
- s.defvars[b.ID][name] = v
+ // Make a FwdRef, which records a value that's live on block input.
+ // We'll find the matching definition as part of insertPhis.
+ v = s.newValue0A(ssa.OpFwdRef, t, name)
+ s.fwdVars[name] = v
s.addNamedValue(name, v)
return v
}
+func (s *state) mem() *ssa.Value {
+ return s.variable(&memVar, ssa.TypeMem)
+}
+
func (s *state) addNamedValue(n *Node, v *ssa.Value) {
if n.Class == Pxxx {
// Don't track our dummy nodes (&memVar etc.).
return
}
- if strings.HasPrefix(n.Sym.Name, "autotmp_") {
- // Don't track autotmp_ variables.
+ if n.IsAutoTmp() {
+ // Don't track temporary variables.
return
}
if n.Class == PPARAMOUT {
@@ -3906,7 +4341,7 @@ func (s *state) addNamedValue(n *Node, v *ssa.Value) {
return
}
if n.Class == PAUTO && n.Xoffset != 0 {
- s.Fatalf("AUTO var with offset %s %d", n, n.Xoffset)
+ s.Fatalf("AUTO var with offset %v %d", n, n.Xoffset)
}
loc := ssa.LocalSlot{N: n, Type: n.Type, Off: 0}
values, ok := s.f.NamedValues[loc]
@@ -3930,11 +4365,16 @@ type SSAGenState struct {
// bstart remembers where each block starts (indexed by block ID)
bstart []*obj.Prog
+
+ // 387 port: maps from SSE registers (REG_X?) to 387 registers (REG_F?)
+ 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
}
// Pc returns the current Prog.
func (s *SSAGenState) Pc() *obj.Prog {
- return Pc
+ return pc
}
// SetLineno sets the current source line number.
@@ -3948,10 +4388,6 @@ func genssa(f *ssa.Func, ptxt *obj.Prog, gcargs, gclocals *Sym) {
var s SSAGenState
e := f.Config.Frontend().(*ssaExport)
- // We're about to emit a bunch of Progs.
- // Since the only way to get here is to explicitly request it,
- // just fail on unimplemented instead of trying to unwind our mess.
- e.mustImplement = true
// Remember where each block starts.
s.bstart = make([]*obj.Prog, f.NumBlocks())
@@ -3963,36 +4399,43 @@ 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[pc] = f.Blocks[0]
+ }
+
+ if Thearch.Use387 {
+ s.SSEto387 = map[int16]int16{}
}
+ s.ScratchFpMem = scratchFpMem
+ scratchFpMem = nil
+
// Emit basic blocks
for i, b := range f.Blocks {
- s.bstart[b.ID] = Pc
+ s.bstart[b.ID] = pc
// Emit values in block
Thearch.SSAMarkMoves(&s, b)
for _, v := range b.Values {
- x := Pc
+ x := pc
Thearch.SSAGenValue(&s, v)
if logProgs {
- for ; x != Pc; x = x.Link {
+ for ; x != pc; x = x.Link {
valueProgs[x] = v
}
}
}
// Emit control flow instructions for block
var next *ssa.Block
- if i < len(f.Blocks)-1 && (Debug['N'] == 0 || b.Kind == ssa.BlockCall) {
+ if i < len(f.Blocks)-1 && Debug['N'] == 0 {
// If -N, leave next==nil so every block with successors
// ends in a JMP (except call blocks - plive doesn't like
// select{send,recv} followed by a JMP call). Helps keep
// line numbers for otherwise empty blocks.
next = f.Blocks[i+1]
}
- x := Pc
+ x := pc
Thearch.SSAGenBlock(&s, b, next)
if logProgs {
- for ; x != Pc; x = x.Link {
+ for ; x != pc; x = x.Link {
blockProgs[x] = b
}
}
@@ -4050,9 +4493,6 @@ func genssa(f *ssa.Func, ptxt *obj.Prog, gcargs, gclocals *Sym) {
}
}
- // Allocate stack frame
- allocauto(ptxt)
-
// Generate gc bitmaps.
liveness(Curfn, ptxt, gcargs, gclocals)
@@ -4066,20 +4506,7 @@ func genssa(f *ssa.Func, ptxt *obj.Prog, gcargs, gclocals *Sym) {
removevardef(ptxt)
f.Config.HTML.Close()
-}
-
-// movZero generates a register indirect move with a 0 immediate and keeps track of bytes left and next offset
-func movZero(as obj.As, width int64, nbytes int64, offset int64, regnum int16) (nleft int64, noff int64) {
- p := Prog(as)
- // TODO: use zero register on archs that support it.
- p.From.Type = obj.TYPE_CONST
- p.From.Offset = 0
- p.To.Type = obj.TYPE_MEM
- p.To.Reg = regnum
- p.To.Offset = offset
- offset += width
- nleft = nbytes - width
- return nleft, offset
+ f.Config.HTML = nil
}
type FloatingEQNEJump struct {
@@ -4128,12 +4555,25 @@ func SSAGenFPJump(s *SSAGenState, b, next *ssa.Block, jumps *[2][2]FloatingEQNEJ
}
}
+func AuxOffset(v *ssa.Value) (offset int64) {
+ if v.Aux == nil {
+ return 0
+ }
+ switch sym := v.Aux.(type) {
+
+ case *ssa.AutoSymbol:
+ n := sym.Node.(*Node)
+ return n.Xoffset
+ }
+ return 0
+}
+
// AddAux adds the offset in the aux fields (AuxInt and Aux) of v to a.
func AddAux(a *obj.Addr, v *ssa.Value) {
AddAux2(a, v, v.AuxInt)
}
func AddAux2(a *obj.Addr, v *ssa.Value, offset int64) {
- if a.Type != obj.TYPE_MEM {
+ if a.Type != obj.TYPE_MEM && a.Type != obj.TYPE_ADDR {
v.Fatalf("bad AddAux addr %v", a)
}
// add integer offset
@@ -4160,28 +4600,39 @@ func AddAux2(a *obj.Addr, v *ssa.Value, offset int64) {
a.Name = obj.NAME_PARAM
a.Node = n
a.Sym = Linksym(n.Orig.Sym)
- a.Offset += n.Xoffset // TODO: why do I have to add this here? I don't for auto variables.
+ 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.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.
-func (s *state) extendIndex(v *ssa.Value) *ssa.Value {
+// 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 {
size := v.Type.Size()
if size == s.config.IntSize {
return v
}
if size > s.config.IntSize {
- // TODO: truncate 64-bit indexes on 32-bit pointer archs. We'd need to test
- // the high word and branch to out-of-bounds failure if it is not 0.
- s.Unimplementedf("64->32 index truncation not implemented")
- return v
+ // 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))
+ s.check(cmp, panicfn)
+ }
+ return s.newValue1(ssa.OpTrunc64to32, Types[TINT], v)
}
// Extend value to the required size
@@ -4220,17 +4671,52 @@ func (s *state) extendIndex(v *ssa.Value) *ssa.Value {
return s.newValue1(op, Types[TINT], v)
}
-// SSARegNum returns the register (in cmd/internal/obj numbering) to
-// which v has been allocated. Panics if v is not assigned to a
-// register.
-// TODO: Make this panic again once it stops happening routinely.
-func SSARegNum(v *ssa.Value) int16 {
- reg := v.Block.Func.RegAlloc[v.ID]
- if reg == nil {
- v.Unimplementedf("nil regnum for value: %s\n%s\n", v.LongString(), v.Block.Func)
- return 0
+// CheckLoweredPhi checks that regalloc and stackalloc correctly handled phi values.
+// Called during ssaGenValue.
+func CheckLoweredPhi(v *ssa.Value) {
+ if v.Op != ssa.OpPhi {
+ v.Fatalf("CheckLoweredPhi called with non-phi value: %v", v.LongString())
+ }
+ if v.Type.IsMemory() {
+ return
+ }
+ f := v.Block.Func
+ loc := f.RegAlloc[v.ID]
+ for _, a := range v.Args {
+ if aloc := f.RegAlloc[a.ID]; aloc != loc { // TODO: .Equal() instead?
+ v.Fatalf("phi arg at different location than phi: %v @ %v, but arg %v @ %v\n%s\n", v, loc, a, aloc, v.Block.Func)
+ }
+ }
+}
+
+// CheckLoweredGetClosurePtr checks that v is the first instruction in the function's entry block.
+// The output of LoweredGetClosurePtr is generally hardwired to the correct register.
+// That register contains the closure pointer on closure entry.
+func CheckLoweredGetClosurePtr(v *ssa.Value) {
+ entry := v.Block.Func.Entry
+ if entry != v.Block || entry.Values[0] != v {
+ Fatalf("in %s, badly placed LoweredGetClosurePtr: %v %v", v.Block.Func.Name, v.Block, v)
}
- return Thearch.SSARegToReg[reg.(*ssa.Register).Num]
+}
+
+// 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
@@ -4243,6 +4729,31 @@ func AutoVar(v *ssa.Value) (*Node, int64) {
return loc.N.(*Node), loc.Off
}
+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.Offset = n.Xoffset + off
+ if n.Class == PPARAM || n.Class == PPARAMOUT {
+ a.Name = obj.NAME_PARAM
+ } else {
+ a.Name = obj.NAME_AUTO
+ }
+}
+
+func (s *SSAGenState) AddrScratch(a *obj.Addr) {
+ if s.ScratchFpMem == nil {
+ panic("no scratch memory available; forgot to declare usesScratch for Op?")
+ }
+ 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.Offset = s.ScratchFpMem.Xoffset
+}
+
// fieldIdx finds the index of the field referred to by the ODOT node n.
func fieldIdx(n *Node) int {
t := n.Left.Type
@@ -4262,7 +4773,7 @@ func fieldIdx(n *Node) int {
}
return i
}
- panic(fmt.Sprintf("can't find field in expr %s\n", n))
+ panic(fmt.Sprintf("can't find field in expr %v\n", n))
// TODO: keep the result of this function somewhere in the ODOT Node
// so we don't have to recompute it each time we need it.
@@ -4270,9 +4781,7 @@ func fieldIdx(n *Node) int {
// ssaExport exports a bunch of compiler services for the ssa backend.
type ssaExport struct {
- log bool
- unimplemented bool
- mustImplement bool
+ log bool
}
func (s *ssaExport) TypeBool() ssa.Type { return Types[TBOOL] }
@@ -4289,25 +4798,24 @@ 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]) }
+func (s *ssaExport) TypeBytePtr() ssa.Type { return ptrto(Types[TUINT8]) }
// StringData returns a symbol (a *Sym wrapped in an interface) which
// is the data component of a global string constant containing s.
func (*ssaExport) StringData(s string) interface{} {
// TODO: is idealstring correct? It might not matter...
- _, data := stringsym(s)
+ data := stringsym(s)
return &ssa.ExternSymbol{Typ: idealstring, Sym: data}
}
func (e *ssaExport) Auto(t ssa.Type) ssa.GCNode {
- n := temp(t.(*Type)) // Note: adds new auto to Curfn.Func.Dcl list
- e.mustImplement = true // This modifies the input to SSA, so we want to make sure we succeed from here!
+ n := temp(t.(*Type)) // Note: adds new auto to Curfn.Func.Dcl list
return n
}
func (e *ssaExport) SplitString(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot) {
n := name.N.(*Node)
- ptrType := Ptrto(Types[TUINT8])
+ ptrType := ptrto(Types[TUINT8])
lenType := Types[TINT]
if n.Class == PAUTO && !n.Addrtaken {
// Split this string up into two separate variables.
@@ -4321,7 +4829,7 @@ func (e *ssaExport) SplitString(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlo
func (e *ssaExport) SplitInterface(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot) {
n := name.N.(*Node)
- t := Ptrto(Types[TUINT8])
+ t := ptrto(Types[TUINT8])
if n.Class == PAUTO && !n.Addrtaken {
// Split this interface up into two separate variables.
f := ".itab"
@@ -4338,7 +4846,7 @@ func (e *ssaExport) SplitInterface(name ssa.LocalSlot) (ssa.LocalSlot, ssa.Local
func (e *ssaExport) SplitSlice(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot, ssa.LocalSlot) {
n := name.N.(*Node)
- ptrType := Ptrto(name.Type.ElemType().(*Type))
+ ptrType := ptrto(name.Type.ElemType().(*Type))
lenType := Types[TINT]
if n.Class == PAUTO && !n.Addrtaken {
// Split this slice up into three separate variables.
@@ -4372,6 +4880,27 @@ func (e *ssaExport) SplitComplex(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSl
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) {
+ n := name.N.(*Node)
+ var t *Type
+ if name.Type.IsSigned() {
+ t = Types[TINT32]
+ } else {
+ t = Types[TUINT32]
+ }
+ 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}
+ }
+ // 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}
+ }
+ return ssa.LocalSlot{N: n, Type: t, Off: name.Off + 4}, ssa.LocalSlot{N: n, Type: Types[TUINT32], Off: name.Off}
+}
+
func (e *ssaExport) SplitStruct(name ssa.LocalSlot, i int) ssa.LocalSlot {
n := name.N.(*Node)
st := name.Type
@@ -4386,11 +4915,26 @@ func (e *ssaExport) SplitStruct(name ssa.LocalSlot, i int) ssa.LocalSlot {
return ssa.LocalSlot{N: n, Type: ft, Off: name.Off + st.FieldOff(i)}
}
+func (e *ssaExport) 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)
+ return ssa.LocalSlot{N: x, Type: et, Off: 0}
+ }
+ return ssa.LocalSlot{N: n, Type: et, Off: name.Off}
+}
+
// 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: autopkg}
- n := Nod(ONAME, nil, nil)
+ s := &Sym{Name: name, Pkg: localpkg}
+ n := nod(ONAME, nil, nil)
s.Def = n
s.Def.Used = true
n.Sym = s
@@ -4404,8 +4948,6 @@ func (e *ssaExport) namedAuto(name string, typ ssa.Type) ssa.GCNode {
Curfn.Func.Dcl = append(Curfn.Func.Dcl, n)
dowidth(t)
- e.mustImplement = true
-
return n
}
@@ -4419,8 +4961,7 @@ func (e *ssaExport) Line(line int32) string {
// Log logs a message from the compiler.
func (e *ssaExport) Logf(msg string, args ...interface{}) {
- // If e was marked as unimplemented, anything could happen. Ignore.
- if e.log && !e.unimplemented {
+ if e.log {
fmt.Printf(msg, args...)
}
}
@@ -4431,26 +4972,8 @@ func (e *ssaExport) Log() bool {
// Fatal reports a compiler error and exits.
func (e *ssaExport) Fatalf(line int32, msg string, args ...interface{}) {
- // If e was marked as unimplemented, anything could happen. Ignore.
- if !e.unimplemented {
- lineno = line
- Fatalf(msg, args...)
- }
-}
-
-// Unimplemented reports that the function cannot be compiled.
-// It will be removed once SSA work is complete.
-func (e *ssaExport) Unimplementedf(line int32, msg string, args ...interface{}) {
- if e.mustImplement {
- lineno = line
- Fatalf(msg, args...)
- }
- const alwaysLog = false // enable to calculate top unimplemented features
- if !e.unimplemented && (e.log || alwaysLog) {
- // first implementation failure, print explanation
- fmt.Printf("SSA unimplemented: "+msg+"\n", args...)
- }
- e.unimplemented = true
+ lineno = line
+ Fatalf(msg, args...)
}
// Warnl reports a "warning", which is usually flag-triggered
@@ -4463,6 +4986,14 @@ func (e *ssaExport) Debug_checknil() bool {
return Debug_checknil != 0
}
+func (e *ssaExport) Debug_wb() bool {
+ return Debug_wb != 0
+}
+
+func (e *ssaExport) Syslook(name string) interface{} {
+ return syslook(name).Sym
+}
+
func (n *Node) Typ() ssa.Type {
return n.Type
}
diff --git a/src/cmd/compile/internal/gc/ssa_test.go b/src/cmd/compile/internal/gc/ssa_test.go
index c89917d..1aebd90 100644
--- a/src/cmd/compile/internal/gc/ssa_test.go
+++ b/src/cmd/compile/internal/gc/ssa_test.go
@@ -9,7 +9,6 @@ import (
"internal/testenv"
"os/exec"
"path/filepath"
- "runtime"
"strings"
"testing"
)
@@ -17,15 +16,17 @@ import (
// TODO: move all these tests elsewhere?
// Perhaps teach test/run.go how to run them with a new action verb.
func runTest(t *testing.T, filename string) {
+ t.Parallel()
doTest(t, filename, "run")
}
func buildTest(t *testing.T, filename string) {
+ t.Parallel()
doTest(t, filename, "build")
}
func doTest(t *testing.T, filename string, kind string) {
testenv.MustHaveGoBuild(t)
var stdout, stderr bytes.Buffer
- cmd := exec.Command("go", kind, filepath.Join("testdata", filename))
+ cmd := exec.Command(testenv.GoToolPath(t), kind, filepath.Join("testdata", filename))
cmd.Stdout = &stdout
cmd.Stderr = &stderr
if err := cmd.Run(); err != nil {
@@ -40,66 +41,63 @@ func doTest(t *testing.T, filename string, kind string) {
}
// TestShortCircuit tests OANDAND and OOROR expressions and short circuiting.
-func TestShortCircuit(t *testing.T) { runTest(t, "short_ssa.go") }
+func TestShortCircuit(t *testing.T) { runTest(t, "short.go") }
// TestBreakContinue tests that continue and break statements do what they say.
-func TestBreakContinue(t *testing.T) { runTest(t, "break_ssa.go") }
+func TestBreakContinue(t *testing.T) { runTest(t, "break.go") }
// TestTypeAssertion tests type assertions.
-func TestTypeAssertion(t *testing.T) { runTest(t, "assert_ssa.go") }
+func TestTypeAssertion(t *testing.T) { runTest(t, "assert.go") }
// TestArithmetic tests that both backends have the same result for arithmetic expressions.
-func TestArithmetic(t *testing.T) {
- if runtime.GOARCH == "386" {
- t.Skip("legacy 386 compiler can't handle this test")
- }
- runTest(t, "arith_ssa.go")
-}
+func TestArithmetic(t *testing.T) { runTest(t, "arith.go") }
// TestFP tests that both backends have the same result for floating point expressions.
-func TestFP(t *testing.T) { runTest(t, "fp_ssa.go") }
+func TestFP(t *testing.T) { runTest(t, "fp.go") }
// TestArithmeticBoundary tests boundary results for arithmetic operations.
-func TestArithmeticBoundary(t *testing.T) { runTest(t, "arithBoundary_ssa.go") }
+func TestArithmeticBoundary(t *testing.T) { runTest(t, "arithBoundary.go") }
// TestArithmeticConst tests results for arithmetic operations against constants.
-func TestArithmeticConst(t *testing.T) { runTest(t, "arithConst_ssa.go") }
+func TestArithmeticConst(t *testing.T) { runTest(t, "arithConst.go") }
-func TestChan(t *testing.T) { runTest(t, "chan_ssa.go") }
+func TestChan(t *testing.T) { runTest(t, "chan.go") }
-func TestCompound(t *testing.T) { runTest(t, "compound_ssa.go") }
+func TestCompound(t *testing.T) { runTest(t, "compound.go") }
-func TestCtl(t *testing.T) { runTest(t, "ctl_ssa.go") }
+func TestCtl(t *testing.T) { runTest(t, "ctl.go") }
-func TestLoadStore(t *testing.T) { runTest(t, "loadstore_ssa.go") }
+func TestLoadStore(t *testing.T) { runTest(t, "loadstore.go") }
-func TestMap(t *testing.T) { runTest(t, "map_ssa.go") }
+func TestMap(t *testing.T) { runTest(t, "map.go") }
-func TestRegalloc(t *testing.T) { runTest(t, "regalloc_ssa.go") }
+func TestRegalloc(t *testing.T) { runTest(t, "regalloc.go") }
-func TestString(t *testing.T) { runTest(t, "string_ssa.go") }
+func TestString(t *testing.T) { runTest(t, "string.go") }
-func TestDeferNoReturn(t *testing.T) { buildTest(t, "deferNoReturn_ssa.go") }
+func TestDeferNoReturn(t *testing.T) { buildTest(t, "deferNoReturn.go") }
// TestClosure tests closure related behavior.
-func TestClosure(t *testing.T) { runTest(t, "closure_ssa.go") }
+func TestClosure(t *testing.T) { runTest(t, "closure.go") }
-func TestArray(t *testing.T) { runTest(t, "array_ssa.go") }
+func TestArray(t *testing.T) { runTest(t, "array.go") }
-func TestAppend(t *testing.T) { runTest(t, "append_ssa.go") }
+func TestAppend(t *testing.T) { runTest(t, "append.go") }
-func TestZero(t *testing.T) { runTest(t, "zero_ssa.go") }
+func TestZero(t *testing.T) { runTest(t, "zero.go") }
-func TestAddressed(t *testing.T) { runTest(t, "addressed_ssa.go") }
+func TestAddressed(t *testing.T) { runTest(t, "addressed.go") }
-func TestCopy(t *testing.T) { runTest(t, "copy_ssa.go") }
+func TestCopy(t *testing.T) { runTest(t, "copy.go") }
-func TestUnsafe(t *testing.T) { runTest(t, "unsafe_ssa.go") }
+func TestUnsafe(t *testing.T) { runTest(t, "unsafe.go") }
-func TestPhi(t *testing.T) { runTest(t, "phi_ssa.go") }
+func TestPhi(t *testing.T) { runTest(t, "phi.go") }
func TestSlice(t *testing.T) { runTest(t, "slice.go") }
func TestNamedReturn(t *testing.T) { runTest(t, "namedReturn.go") }
func TestDuplicateLoad(t *testing.T) { runTest(t, "dupLoad.go") }
+
+func TestSqrt(t *testing.T) { runTest(t, "sqrt_const.go") }
diff --git a/src/cmd/compile/internal/gc/subr.go b/src/cmd/compile/internal/gc/subr.go
index 1db1cba..a53ba1f 100644
--- a/src/cmd/compile/internal/gc/subr.go
+++ b/src/cmd/compile/internal/gc/subr.go
@@ -27,7 +27,7 @@ type Error struct {
var errors []Error
func errorexit() {
- Flusherrors()
+ flusherrors()
if outfile != "" {
os.Remove(outfile)
}
@@ -58,8 +58,10 @@ func (x byLineno) Len() int { return len(x) }
func (x byLineno) Less(i, j int) bool { return x[i].lineno < x[j].lineno }
func (x byLineno) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
-func Flusherrors() {
- bstdout.Flush()
+// flusherrors sorts errors seen so far by line number, prints them to stdout,
+// and empties the errors array.
+func flusherrors() {
+ Ctxt.Bso.Flush()
if len(errors) == 0 {
return
}
@@ -74,7 +76,7 @@ func Flusherrors() {
func hcrash() {
if Debug['h'] != 0 {
- Flusherrors()
+ flusherrors()
if outfile != "" {
os.Remove(outfile)
}
@@ -108,7 +110,7 @@ func yyerrorl(line int32, format string, args ...interface{}) {
lasterror.syntax = line
} else {
// only one of multiple equal non-syntax errors per line
- // (Flusherrors shows only one of them, so we filter them
+ // (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.)
@@ -124,13 +126,13 @@ func yyerrorl(line int32, format string, args ...interface{}) {
hcrash()
nerrors++
if nsavederrors+nerrors >= 10 && Debug['e'] == 0 {
- Flusherrors()
+ flusherrors()
fmt.Printf("%v: too many errors\n", linestr(line))
errorexit()
}
}
-func Yyerror(format string, args ...interface{}) {
+func yyerror(format string, args ...interface{}) {
yyerrorl(lineno, format, args...)
}
@@ -143,19 +145,19 @@ func Warn(fmt_ string, args ...interface{}) {
func Warnl(line int32, fmt_ string, args ...interface{}) {
adderr(line, fmt_, args...)
if Debug['m'] != 0 {
- Flusherrors()
+ flusherrors()
}
}
func Fatalf(fmt_ string, args ...interface{}) {
- Flusherrors()
+ flusherrors()
fmt.Printf("%v: internal compiler error: ", linestr(lineno))
fmt.Printf(fmt_, args...)
fmt.Printf("\n")
// If this is a released compiler version, ask for a bug report.
- if strings.HasPrefix(obj.Getgoversion(), "release") {
+ if strings.HasPrefix(obj.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")
@@ -202,10 +204,10 @@ func setlineno(n *Node) int32 {
lno := lineno
if n != nil {
switch n.Op {
- case ONAME, OTYPE, OPACK:
+ case ONAME, OPACK:
break
- case OLITERAL:
+ case OLITERAL, OTYPE:
if n.Sym != nil {
break
}
@@ -225,25 +227,44 @@ func setlineno(n *Node) int32 {
return lno
}
-func Lookup(name string) *Sym {
+func lookup(name string) *Sym {
return localpkg.Lookup(name)
}
-func Lookupf(format string, a ...interface{}) *Sym {
- return Lookup(fmt.Sprintf(format, a...))
+func lookupf(format string, a ...interface{}) *Sym {
+ return lookup(fmt.Sprintf(format, a...))
}
-func LookupBytes(name []byte) *Sym {
+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 {
+// lookupN looks up the symbol starting with prefix and ending with
+// the decimal n. If prefix is too long, lookupN panics.
+func lookupN(prefix string, n int) *Sym {
var buf [20]byte // plenty long enough for all current users
copy(buf[:], prefix)
b := strconv.AppendInt(buf[:len(prefix)], int64(n), 10)
- return LookupBytes(b)
+ return lookupBytes(b)
+}
+
+// autolabel generates a new Name node for use with
+// an automatically generated label.
+// prefix is a short mnemonic (e.g. ".s" for switch)
+// to help with debugging.
+// It should begin with "." to avoid conflicts with
+// user labels.
+func autolabel(prefix string) *Node {
+ if prefix[0] != '.' {
+ Fatalf("autolabel prefix must start with '.', have %q", prefix)
+ }
+ fn := Curfn
+ if Curfn == nil {
+ Fatalf("autolabel outside function")
+ }
+ n := fn.Func.Label
+ fn.Func.Label++
+ return newname(lookupN(prefix, int(n)))
}
var initSyms []*Sym
@@ -288,7 +309,7 @@ func Pkglookup(name string, pkg *Pkg) *Sym {
func restrictlookup(name string, pkg *Pkg) *Sym {
if !exportname(name) && pkg != localpkg {
- Yyerror("cannot refer to unexported name %s.%s", pkg.Name, name)
+ yyerror("cannot refer to unexported name %s.%s", pkg.Name, name)
}
return Pkglookup(name, pkg)
}
@@ -307,7 +328,7 @@ func importdot(opkg *Pkg, pack *Node) {
if !exportname(s.Name) || strings.ContainsRune(s.Name, 0xb7) { // 0xb7 = center dot
continue
}
- s1 = Lookup(s.Name)
+ s1 = lookup(s.Name)
if s1.Def != nil {
pkgerror = fmt.Sprintf("during import %q", opkg.Path)
redeclare(s1, pkgerror)
@@ -331,7 +352,7 @@ func importdot(opkg *Pkg, pack *Node) {
}
}
-func Nod(op Op, nleft *Node, nright *Node) *Node {
+func nod(op Op, nleft *Node, nright *Node) *Node {
n := new(Node)
n.Op = op
n.Left = nleft
@@ -342,19 +363,12 @@ func Nod(op Op, nleft *Node, nright *Node) *Node {
switch op {
case OCLOSURE, ODCLFUNC:
n.Func = new(Func)
- n.Func.FCurfn = Curfn
+ n.Func.IsHiddenClosure = Curfn != nil
case ONAME:
n.Name = new(Name)
n.Name.Param = new(Param)
case OLABEL, OPACK:
n.Name = new(Name)
- case ODCLFIELD:
- if nleft != nil {
- n.Name = nleft.Name
- } else {
- n.Name = new(Name)
- n.Name.Param = new(Param)
- }
}
if n.Name != nil {
n.Name.Curfn = Curfn
@@ -362,10 +376,10 @@ func Nod(op Op, nleft *Node, nright *Node) *Node {
return n
}
-// NodSym makes a Node with Op op and with the Left field set to left
+// nodSym makes a Node with Op op and with the Left field set to left
// and the Sym field set to sym. This is for ODOT and friends.
-func NodSym(op Op, left *Node, sym *Sym) *Node {
- n := Nod(op, left, nil)
+func nodSym(op Op, left *Node, sym *Sym) *Node {
+ n := nod(op, left, nil)
n.Sym = sym
return n
}
@@ -374,7 +388,7 @@ func saveorignode(n *Node) {
if n.Orig != nil {
return
}
- norig := Nod(n.Op, nil, nil)
+ norig := nod(n.Op, nil, nil)
*norig = *n
n.Orig = norig
}
@@ -408,8 +422,8 @@ func (x methcmp) Less(i, j int) bool {
return false
}
-func Nodintconst(v int64) *Node {
- c := Nod(OLITERAL, nil, nil)
+func nodintconst(v int64) *Node {
+ c := nod(OLITERAL, nil, nil)
c.Addable = true
c.SetVal(Val{new(Mpint)})
c.Val().U.(*Mpint).SetInt64(v)
@@ -419,7 +433,7 @@ func Nodintconst(v int64) *Node {
}
func nodfltconst(v *Mpflt) *Node {
- c := Nod(OLITERAL, nil, nil)
+ c := nod(OLITERAL, nil, nil)
c.Addable = true
c.SetVal(Val{newMpflt()})
c.Val().U.(*Mpflt).Set(v)
@@ -443,43 +457,19 @@ func Nodconst(n *Node, t *Type, v int64) {
}
func nodnil() *Node {
- c := Nodintconst(0)
+ c := nodintconst(0)
c.SetVal(Val{new(NilVal)})
c.Type = Types[TNIL]
return c
}
-func Nodbool(b bool) *Node {
- c := Nodintconst(0)
+func nodbool(b bool) *Node {
+ c := nodintconst(0)
c.SetVal(Val{b})
c.Type = idealbool
return c
}
-func aindex(b *Node, t *Type) *Type {
- hasbound := false
- var bound int64
- b = typecheck(b, Erv)
- if b != nil {
- switch consttype(b) {
- default:
- Yyerror("array bound must be an integer expression")
-
- case CTINT, CTRUNE:
- hasbound = true
- bound = b.Int64()
- if bound < 0 {
- Yyerror("array bound must be non negative")
- }
- }
- }
-
- if !hasbound {
- return typSlice(t)
- }
- return typArray(t, bound)
-}
-
// 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
@@ -507,7 +497,7 @@ func treecopy(n *Node, lineno int32) *Node {
return &m
case ONONAME:
- if n.Sym == Lookup("iota") {
+ 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
@@ -516,9 +506,7 @@ func treecopy(n *Node, lineno int32) *Node {
if lineno != 0 {
m.Lineno = lineno
}
- m.Name = new(Name)
- *m.Name = *n.Name
- m.Name.Iota = iota_
+ m.SetIota(iota_)
return &m
}
return n
@@ -570,14 +558,15 @@ func isblanksym(s *Sym) bool {
return s != nil && s.Name == "_"
}
-// given receiver of type t (t == r or t == *r)
-// return type to hang methods off (r).
-func methtype(t *Type, mustname int) *Type {
+// 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 {
if t == nil {
return nil
}
- // strip away pointer if it's there
+ // Strip away pointer if it's there.
if t.IsPtr() {
if t.Sym != nil {
return nil
@@ -588,29 +577,20 @@ func methtype(t *Type, mustname int) *Type {
}
}
- // need a type name
- if t.Sym == nil && (mustname != 0 || !t.IsStruct()) {
+ // Must be a named type or anonymous struct.
+ if t.Sym == nil && !t.IsStruct() {
return nil
}
- // check types
- if !issimple[t.Etype] {
- switch t.Etype {
- default:
- return nil
-
- case TSTRUCT,
- TARRAY,
- TSLICE,
- TMAP,
- TCHAN,
- TSTRING,
- TFUNC:
- break
- }
+ // Check types.
+ if issimple[t.Etype] {
+ return t
}
-
- return t
+ switch t.Etype {
+ case TARRAY, TCHAN, TFUNC, TMAP, TSLICE, TSTRING, TSTRUCT:
+ return t
+ }
+ return nil
}
func cplxsubtype(et EType) EType {
@@ -626,14 +606,19 @@ func cplxsubtype(et EType) EType {
return 0
}
-// Eqtype reports whether t1 and t2 are identical, following the spec rules.
+// eqtype reports whether t1 and t2 are identical, following the spec rules.
//
// Any cyclic type must go through a named type, and if one is
// named, it is only identical to the other if they are the same
// pointer (t1 == t2), so there's no chance of chasing cycles
// ad infinitum, so no need for a depth counter.
-func Eqtype(t1, t2 *Type) bool {
- return eqtype1(t1, t2, nil)
+func eqtype(t1, t2 *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 {
+ return eqtype1(t1, t2, false, nil)
}
type typePair struct {
@@ -641,7 +626,7 @@ type typePair struct {
t2 *Type
}
-func eqtype1(t1, t2 *Type, assumedEqual map[typePair]struct{}) bool {
+func eqtype1(t1, t2 *Type, cmpTags bool, assumedEqual map[typePair]struct{}) bool {
if t1 == t2 {
return true
}
@@ -670,10 +655,10 @@ func eqtype1(t1, t2 *Type, assumedEqual map[typePair]struct{}) bool {
switch t1.Etype {
case TINTER, TSTRUCT:
- t1, i1 := IterFields(t1)
- t2, i2 := IterFields(t2)
+ t1, i1 := iterFields(t1)
+ t2, i2 := iterFields(t2)
for ; t1 != nil && t2 != nil; t1, t2 = i1.Next(), i2.Next() {
- if t1.Sym != t2.Sym || t1.Embedded != t2.Embedded || !eqtype1(t1.Type, t2.Type, assumedEqual) || t1.Note != t2.Note {
+ if t1.Sym != t2.Sym || t1.Embedded != t2.Embedded || !eqtype1(t1.Type, t2.Type, cmpTags, assumedEqual) || cmpTags && t1.Note != t2.Note {
return false
}
}
@@ -689,10 +674,10 @@ func eqtype1(t1, t2 *Type, assumedEqual map[typePair]struct{}) bool {
// equality, because they're never relevant.
for _, f := range paramsResults {
// Loop over fields in structs, ignoring argument names.
- ta, ia := IterFields(f(t1))
- tb, ib := IterFields(f(t2))
+ ta, ia := iterFields(f(t1))
+ tb, ib := iterFields(f(t2))
for ; ta != nil && tb != nil; ta, tb = ia.Next(), ib.Next() {
- if ta.Isddd != tb.Isddd || !eqtype1(ta.Type, tb.Type, assumedEqual) {
+ if ta.Isddd != tb.Isddd || !eqtype1(ta.Type, tb.Type, cmpTags, assumedEqual) {
return false
}
}
@@ -713,13 +698,13 @@ func eqtype1(t1, t2 *Type, assumedEqual map[typePair]struct{}) bool {
}
case TMAP:
- if !eqtype1(t1.Key(), t2.Key(), assumedEqual) {
+ if !eqtype1(t1.Key(), t2.Key(), cmpTags, assumedEqual) {
return false
}
- return eqtype1(t1.Val(), t2.Val(), assumedEqual)
+ return eqtype1(t1.Val(), t2.Val(), cmpTags, assumedEqual)
}
- return eqtype1(t1.Elem(), t2.Elem(), assumedEqual)
+ return eqtype1(t1.Elem(), t2.Elem(), cmpTags, assumedEqual)
}
// Are t1 and t2 equal struct types when field names are ignored?
@@ -730,10 +715,10 @@ func eqtypenoname(t1 *Type, t2 *Type) bool {
return false
}
- f1, i1 := IterFields(t1)
- f2, i2 := IterFields(t2)
+ f1, i1 := iterFields(t1)
+ f2, i2 := iterFields(t2)
for {
- if !Eqtype(f1.Type, f2.Type) {
+ if !eqtype(f1.Type, f2.Type) {
return false
}
if f1 == nil {
@@ -755,7 +740,7 @@ func assignop(src *Type, dst *Type, why *string) Op {
// TODO(rsc,lvd): This behaves poorly in the presence of inlining.
// https://golang.org/issue/2795
if safemode && importpkg == nil && src != nil && src.Etype == TUNSAFEPTR {
- Yyerror("cannot use unsafe.Pointer")
+ yyerror("cannot use unsafe.Pointer")
errorexit()
}
@@ -767,7 +752,7 @@ func assignop(src *Type, dst *Type, why *string) Op {
}
// 1. src type is identical to dst.
- if Eqtype(src, dst) {
+ if eqtype(src, dst) {
return OCONVNOP
}
@@ -776,7 +761,7 @@ func assignop(src *Type, dst *Type, why *string) Op {
// both are empty interface types.
// For assignable but different non-empty interface types,
// we want to recompute the itab.
- if Eqtype(src.Orig, dst.Orig) && (src.Sym == nil || dst.Sym == nil || src.IsEmptyInterface()) {
+ if eqtype(src.Orig, dst.Orig) && (src.Sym == nil || dst.Sym == nil || src.IsEmptyInterface()) {
return OCONVNOP
}
@@ -799,11 +784,13 @@ func assignop(src *Type, dst *Type, why *string) Op {
} else if have != nil && have.Sym == missing.Sym && have.Nointerface {
*why = fmt.Sprintf(":\n\t%v does not implement %v (%v method is marked 'nointerface')", src, dst, missing.Sym)
} else if have != nil && have.Sym == missing.Sym {
- *why = fmt.Sprintf(":\n\t%v does not implement %v (wrong type for %v method)\n"+"\t\thave %v%v\n\t\twant %v%v", src, dst, missing.Sym, have.Sym, Tconv(have.Type, FmtShort|FmtByte), missing.Sym, Tconv(missing.Type, FmtShort|FmtByte))
+ *why = fmt.Sprintf(":\n\t%v does not implement %v (wrong type for %v method)\n"+
+ "\t\thave %v%0S\n\t\twant %v%0S", src, dst, missing.Sym, have.Sym, have.Type, missing.Sym, missing.Type)
} else if ptr != 0 {
*why = fmt.Sprintf(":\n\t%v does not implement %v (%v method has pointer receiver)", src, dst, missing.Sym)
} else if have != nil {
- *why = fmt.Sprintf(":\n\t%v does not implement %v (missing %v method)\n"+"\t\thave %v%v\n\t\twant %v%v", src, dst, missing.Sym, have.Sym, Tconv(have.Type, FmtShort|FmtByte), missing.Sym, Tconv(missing.Type, FmtShort|FmtByte))
+ *why = fmt.Sprintf(":\n\t%v does not implement %v (missing %v method)\n"+
+ "\t\thave %v%0S\n\t\twant %v%0S", src, dst, missing.Sym, have.Sym, have.Type, missing.Sym, missing.Type)
} else {
*why = fmt.Sprintf(":\n\t%v does not implement %v (missing %v method)", src, dst, missing.Sym)
}
@@ -832,7 +819,7 @@ func assignop(src *Type, dst *Type, why *string) Op {
// 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 Eqtype(src.Elem(), dst.Elem()) && (src.Sym == nil || dst.Sym == nil) {
+ if eqtype(src.Elem(), dst.Elem()) && (src.Sym == nil || dst.Sym == nil) {
return OCONVNOP
}
}
@@ -876,6 +863,16 @@ func convertop(src *Type, dst *Type, why *string) Op {
return 0
}
+ // 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 why != nil {
+ *why = fmt.Sprintf(":\n\t%v is go:notinheap, but %v is not", dst.Elem(), src.Elem())
+ }
+ return 0
+ }
+
// 1. src can be assigned to dst.
op := assignop(src, dst, why)
if op != 0 {
@@ -893,22 +890,22 @@ func convertop(src *Type, dst *Type, why *string) Op {
*why = ""
}
- // 2. src and dst have identical underlying types.
- if Eqtype(src.Orig, dst.Orig) {
+ // 2. Ignoring struct tags, src and dst have identical underlying types.
+ if eqtypeIgnoreTags(src.Orig, dst.Orig) {
return OCONVNOP
}
- // 3. src and dst are unnamed pointer types
- // and their base types have identical underlying types.
+ // 3. src and dst are unnamed pointer types and, ignoring struct tags,
+ // their base types have identical underlying types.
if src.IsPtr() && dst.IsPtr() && src.Sym == nil && dst.Sym == nil {
- if Eqtype(src.Elem().Orig, dst.Elem().Orig) {
+ if eqtypeIgnoreTags(src.Elem().Orig, dst.Elem().Orig) {
return OCONVNOP
}
}
// 4. src and dst are both integer or floating point types.
if (src.IsInteger() || src.IsFloat()) && (dst.IsInteger() || dst.IsFloat()) {
- if Simtype[src.Etype] == Simtype[dst.Etype] {
+ if simtype[src.Etype] == simtype[dst.Etype] {
return OCONVNOP
}
return OCONV
@@ -916,7 +913,7 @@ func convertop(src *Type, dst *Type, why *string) Op {
// 5. src and dst are both complex types.
if src.IsComplex() && dst.IsComplex() {
- if Simtype[src.Etype] == Simtype[dst.Etype] {
+ if simtype[src.Etype] == simtype[dst.Etype] {
return OCONVNOP
}
return OCONV
@@ -972,13 +969,14 @@ func assignconvfn(n *Node, t *Type, context func() string) *Node {
}
if t.Etype == TBLANK && n.Type.Etype == TNIL {
- Yyerror("use of untyped nil")
+ yyerror("use of untyped nil")
}
old := n
- old.Diag++ // silence errors about n; we'll issue one below
+ od := old.Diag
+ old.Diag = true // silence errors about n; we'll issue one below
n = defaultlit(n, t)
- old.Diag--
+ old.Diag = od
if t.Etype == TBLANK {
return n
}
@@ -987,7 +985,7 @@ func assignconvfn(n *Node, t *Type, context func() string) *Node {
// if the next step is non-bool (like interface{}).
if n.Type == idealbool && !t.IsBoolean() {
if n.Op == ONAME || n.Op == OLITERAL {
- r := Nod(OCONVNOP, n, nil)
+ r := nod(OCONVNOP, n, nil)
r.Type = Types[TBOOL]
r.Typecheck = 1
r.Implicit = true
@@ -995,18 +993,18 @@ func assignconvfn(n *Node, t *Type, context func() string) *Node {
}
}
- if Eqtype(n.Type, t) {
+ if eqtype(n.Type, t) {
return n
}
var why string
op := assignop(n.Type, t, &why)
if op == 0 {
- Yyerror("cannot use %v as type %v in %s%s", Nconv(n, FmtLong), t, context(), why)
+ yyerror("cannot use %L as type %v in %s%s", n, t, context(), why)
op = OCONV
}
- r := Nod(op, n, nil)
+ r := nod(op, n, nil)
r.Type = t
r.Typecheck = 1
r.Implicit = true
@@ -1014,38 +1012,28 @@ func assignconvfn(n *Node, t *Type, context func() string) *Node {
return r
}
-// Is this a 64-bit type?
-func Is64(t *Type) bool {
- if t == nil {
- return false
- }
- switch Simtype[t.Etype] {
- case TINT64, TUINT64, TPTR64:
- return true
- }
-
- return false
+// IsMethod reports whether n is a method.
+// n must be a function or a method.
+func (n *Node) IsMethod() bool {
+ return n.Type.Recv() != nil
}
// SliceBounds returns n's slice bounds: low, high, and max in expr[low:high:max].
// n must be a slice expression. max is nil if n is a simple slice expression.
func (n *Node) SliceBounds() (low, high, max *Node) {
+ if n.List.Len() == 0 {
+ return nil, nil, nil
+ }
+
switch n.Op {
case OSLICE, OSLICEARR, OSLICESTR:
- if n.Right == nil {
- return nil, nil, nil
- }
- if n.Right.Op != OKEY {
- Fatalf("SliceBounds right %s", opnames[n.Right.Op])
- }
- return n.Right.Left, n.Right.Right, nil
+ s := n.List.Slice()
+ return s[0], s[1], nil
case OSLICE3, OSLICE3ARR:
- if n.Right.Op != OKEY || n.Right.Right.Op != OKEY {
- Fatalf("SliceBounds right %s %s", opnames[n.Right.Op], opnames[n.Right.Right.Op])
- }
- return n.Right.Left, n.Right.Right.Left, n.Right.Right.Right
+ s := n.List.Slice()
+ return s[0], s[1], s[2]
}
- Fatalf("SliceBounds op %s: %v", n.Op, n)
+ Fatalf("SliceBounds op %v: %v", n.Op, n)
return nil, nil, nil
}
@@ -1055,25 +1043,34 @@ func (n *Node) SetSliceBounds(low, high, max *Node) {
switch n.Op {
case OSLICE, OSLICEARR, OSLICESTR:
if max != nil {
- Fatalf("SetSliceBounds %s given three bounds", n.Op)
+ Fatalf("SetSliceBounds %v given three bounds", n.Op)
}
- if n.Right == nil {
- n.Right = Nod(OKEY, low, high)
+ s := n.List.Slice()
+ if s == nil {
+ if low == nil && high == nil {
+ return
+ }
+ n.List.Set([]*Node{low, high})
return
}
- n.Right.Left = low
- n.Right.Right = high
+ s[0] = low
+ s[1] = high
return
case OSLICE3, OSLICE3ARR:
- if n.Right == nil {
- n.Right = Nod(OKEY, low, Nod(OKEY, high, max))
+ s := n.List.Slice()
+ if s == nil {
+ if low == nil && high == nil && max == nil {
+ return
+ }
+ n.List.Set([]*Node{low, high, max})
+ return
}
- n.Right.Left = low
- n.Right.Right.Left = high
- n.Right.Right.Right = max
+ s[0] = low
+ s[1] = high
+ s[2] = max
return
}
- Fatalf("SetSliceBounds op %s: %v", n.Op, n)
+ Fatalf("SetSliceBounds op %v: %v", n.Op, n)
}
// IsSlice3 reports whether o is a slice3 op (OSLICE3, OSLICE3ARR).
@@ -1089,34 +1086,6 @@ func (o Op) IsSlice3() bool {
return false
}
-// Is a conversion between t1 and t2 a no-op?
-func Noconv(t1 *Type, t2 *Type) bool {
- e1 := Simtype[t1.Etype]
- e2 := Simtype[t2.Etype]
-
- switch e1 {
- case TINT8, TUINT8:
- return e2 == TINT8 || e2 == TUINT8
-
- case TINT16, TUINT16:
- return e2 == TINT16 || e2 == TUINT16
-
- case TINT32, TUINT32, TPTR32:
- return e2 == TINT32 || e2 == TUINT32 || e2 == TPTR32
-
- case TINT64, TUINT64, TPTR64:
- return e2 == TINT64 || e2 == TUINT64 || e2 == TPTR64
-
- case TFLOAT32:
- return e2 == TFLOAT32
-
- case TFLOAT64:
- return e2 == TFLOAT64
- }
-
- return false
-}
-
func syslook(name string) *Node {
s := Pkglookup(name, Runtimepkg)
if s == nil || s.Def == nil {
@@ -1128,56 +1097,25 @@ func syslook(name string) *Node {
// typehash computes a hash value for type t to use in type switch
// statements.
func typehash(t *Type) uint32 {
- // Tconv already contains all the necessary logic to generate
- // a representation that completely describes the type, so using
+ // 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.
- p := Tconv(t, FmtLeft|FmtUnsigned)
+ // See the comments in exprSwitch.checkDupCases.
+ p := t.tconv(FmtLeft | FmtUnsigned)
// Using MD5 is overkill, but reduces accidental collisions.
h := md5.Sum([]byte(p))
return binary.LittleEndian.Uint32(h[:4])
}
-var initPtrtoDone bool
-
-var (
- ptrToUint8 *Type
- ptrToAny *Type
- ptrToString *Type
- ptrToBool *Type
- ptrToInt32 *Type
-)
-
-func initPtrto() {
- ptrToUint8 = typPtr(Types[TUINT8])
- ptrToAny = typPtr(Types[TANY])
- ptrToString = typPtr(Types[TSTRING])
- ptrToBool = typPtr(Types[TBOOL])
- ptrToInt32 = typPtr(Types[TINT32])
-}
-
-// Ptrto returns the Type *t.
+// ptrto returns the Type *t.
// The returned struct must not be modified.
-func Ptrto(t *Type) *Type {
+func ptrto(t *Type) *Type {
if Tptr == 0 {
Fatalf("ptrto: no tptr")
}
- // Reduce allocations by pre-creating common cases.
- if !initPtrtoDone {
- initPtrto()
- initPtrtoDone = true
- }
- switch t {
- case Types[TUINT8]:
- return ptrToUint8
- case Types[TINT32]:
- return ptrToInt32
- case Types[TANY]:
- return ptrToAny
- case Types[TSTRING]:
- return ptrToString
- case Types[TBOOL]:
- return ptrToBool
+ if t == nil {
+ Fatalf("ptrto: nil ptr")
}
return typPtr(t)
}
@@ -1229,7 +1167,7 @@ func ullmancalc(n *Node) {
}
switch n.Op {
- case OREGISTER, OLITERAL, ONAME:
+ case OLITERAL, ONAME:
ul = 1
if n.Class == PAUTOHEAP {
ul++
@@ -1246,6 +1184,12 @@ func ullmancalc(n *Node) {
ul = UINF
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
+ goto out
}
ul = 1
@@ -1289,12 +1233,12 @@ func badtype(op Op, tl *Type, tr *Type) {
}
s := fmt_
- Yyerror("illegal types for operand: %v%s", op, s)
+ yyerror("illegal types for operand: %v%s", op, s)
}
-// Brcom returns !(op).
-// For example, Brcom(==) is !=.
-func Brcom(op Op) Op {
+// brcom returns !(op).
+// For example, brcom(==) is !=.
+func brcom(op Op) Op {
switch op {
case OEQ:
return ONE
@@ -1313,9 +1257,9 @@ func Brcom(op Op) Op {
return op
}
-// Brrev returns reverse(op).
+// brrev returns reverse(op).
// For example, Brrev(<) is >.
-func Brrev(op Op) Op {
+func brrev(op Op) Op {
switch op {
case OEQ:
return OEQ
@@ -1355,7 +1299,7 @@ func safeexpr(n *Node, init *Nodes) *Node {
if l == n.Left {
return n
}
- r := Nod(OXXX, nil, nil)
+ r := nod(OXXX, nil, nil)
*r = *n
r.Left = l
r = typecheck(r, Erv)
@@ -1367,7 +1311,7 @@ func safeexpr(n *Node, init *Nodes) *Node {
if l == n.Left {
return n
}
- a := Nod(OXXX, nil, nil)
+ a := nod(OXXX, nil, nil)
*a = *n
a.Left = l
a = walkexpr(a, init)
@@ -1379,14 +1323,14 @@ func safeexpr(n *Node, init *Nodes) *Node {
if l == n.Left && r == n.Right {
return n
}
- a := Nod(OXXX, nil, nil)
+ a := nod(OXXX, nil, nil)
*a = *n
a.Left = l
a.Right = r
a = walkexpr(a, init)
return a
- case OSTRUCTLIT, OARRAYLIT:
+ case OSTRUCTLIT, OARRAYLIT, OSLICELIT:
if isStaticCompositeLiteral(n) {
return n
}
@@ -1401,7 +1345,7 @@ func safeexpr(n *Node, init *Nodes) *Node {
func copyexpr(n *Node, t *Type, init *Nodes) *Node {
l := temp(t)
- a := Nod(OAS, l, n)
+ a := nod(OAS, l, n)
a = typecheck(a, Etop)
a = walkexpr(a, init)
init.Append(a)
@@ -1419,21 +1363,6 @@ func cheapexpr(n *Node, init *Nodes) *Node {
return copyexpr(n, n.Type, init)
}
-func Setmaxarg(t *Type, extra int32) {
- dowidth(t)
- w := t.ArgWidth()
- if w >= Thearch.MAXWIDTH {
- Fatalf("bad argwid %v", t)
- }
- w += int64(extra)
- if w >= Thearch.MAXWIDTH {
- Fatalf("bad argwid %d + %v", extra, t)
- }
- if w > Maxarg {
- Maxarg = w
- }
-}
-
// Code to resolve elided DOTs in embedded types.
// A Dlist stores a pointer to a TFIELD Type embedded within
@@ -1468,7 +1397,7 @@ func lookdot0(s *Sym, t *Type, save **Field, ignorecase bool) int {
}
}
- u = methtype(t, 0)
+ u = methtype(t)
if u != nil {
for _, f := range u.Methods().Slice() {
if f.Embedded == 0 && (f.Sym == s || (ignorecase && strings.EqualFold(f.Sym.Name, s.Name))) {
@@ -1570,7 +1499,9 @@ 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)
- n.Diag |= n.Left.Diag
+ if n.Left.Diag {
+ n.Diag = true
+ }
t := n.Left.Type
if t == nil {
return n
@@ -1589,11 +1520,11 @@ func adddot(n *Node) *Node {
case path != nil:
// rebuild elided dots
for c := len(path) - 1; c >= 0; c-- {
- n.Left = NodSym(ODOT, n.Left, path[c].field.Sym)
+ n.Left = nodSym(ODOT, n.Left, path[c].field.Sym)
n.Left.Implicit = true
}
case ambig:
- Yyerror("ambiguous selector %v", n)
+ yyerror("ambiguous selector %v", n)
n.Left = nil
}
@@ -1634,7 +1565,7 @@ func expand0(t *Type, followptr bool) {
return
}
- u = methtype(t, 0)
+ u = methtype(t)
if u != nil {
for _, f := range u.Methods().Slice() {
if f.Sym.Flags&SymUniq != 0 {
@@ -1738,11 +1669,11 @@ func structargs(tl *Type, mustname bool) []*Node {
// invent a name so that we can refer to it in the trampoline
buf := fmt.Sprintf(".anon%d", gen)
gen++
- n = newname(Lookup(buf))
+ n = newname(lookup(buf))
} else if t.Sym != nil {
n = newname(t.Sym)
}
- a := Nod(ODCLFIELD, n, typenod(t.Type))
+ a := nod(ODCLFIELD, n, typenod(t.Type))
a.Isddd = t.Isddd
if n != nil {
n.Isddd = t.Isddd
@@ -1794,12 +1725,12 @@ func genwrapper(rcvr *Type, method *Field, newnam *Sym, iface int) {
dclcontext = PEXTERN
markdcl()
- this := Nod(ODCLFIELD, newname(Lookup(".this")), typenod(rcvr))
+ this := nod(ODCLFIELD, newname(lookup(".this")), typenod(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)
+ t := nod(OTFUNC, nil, nil)
l := []*Node{this}
if iface != 0 && rcvr.Width < Types[Tptr].Width {
// Building method for interface table and receiver
@@ -1808,14 +1739,14 @@ func genwrapper(rcvr *Type, method *Field, newnam *Sym, iface int) {
// 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))
+ pad := nod(ODCLFIELD, newname(lookup(".pad")), typenod(tpad))
l = append(l, pad)
}
t.List.Set(append(l, in...))
t.Rlist.Set(out)
- fn := Nod(ODCLFUNC, nil, nil)
+ fn := nod(ODCLFUNC, nil, nil)
fn.Func.Nname = newname(newnam)
fn.Func.Nname.Name.Defn = fn
fn.Func.Nname.Name.Param.Ntype = t
@@ -1836,9 +1767,9 @@ func genwrapper(rcvr *Type, method *Field, newnam *Sym, iface int) {
// generate nil pointer check for better error
if rcvr.IsPtr() && rcvr.Elem() == methodrcvr {
// generating wrapper from *T to T.
- n := Nod(OIF, nil, nil)
+ n := nod(OIF, nil, nil)
- n.Left = Nod(OEQ, this.Left, nodnil())
+ n.Left = nod(OEQ, this.Left, nodnil())
// these strings are already in the reflect tables,
// so no space cost to use them here.
@@ -1851,13 +1782,13 @@ func genwrapper(rcvr *Type, method *Field, newnam *Sym, iface int) {
l = append(l, nodlit(v))
v.U = method.Sym.Name
l = append(l, nodlit(v)) // method name
- call := Nod(OCALL, syslook("panicwrap"), nil)
+ call := nod(OCALL, syslook("panicwrap"), nil)
call.List.Set(l)
n.Nbody.Set1(call)
fn.Nbody.Append(n)
}
- dot := adddot(NodSym(OXDOT, this.Left, method.Sym))
+ dot := adddot(nodSym(OXDOT, this.Left, method.Sym))
// generate call
// It's not possible to use a tail call when dynamic linking on ppc64le. The
@@ -1871,21 +1802,21 @@ func genwrapper(rcvr *Type, method *Field, newnam *Sym, iface int) {
dot = dot.Left // skip final .M
// TODO(mdempsky): Remove dependency on dotlist.
if !dotlist[0].field.Type.IsPtr() {
- dot = Nod(OADDR, dot, nil)
+ dot = nod(OADDR, dot, nil)
}
- as := Nod(OAS, this.Left, Nod(OCONVNOP, dot, nil))
+ as := nod(OAS, this.Left, nod(OCONVNOP, dot, nil))
as.Right.Type = rcvr
fn.Nbody.Append(as)
- n := Nod(ORETJMP, nil, nil)
+ n := nod(ORETJMP, nil, nil)
n.Left = newname(methodsym(method.Sym, methodrcvr, 0))
fn.Nbody.Append(n)
} else {
fn.Func.Wrapper = true // ignore frame for panic+recover matching
- call := Nod(OCALL, dot, nil)
+ call := nod(OCALL, dot, nil)
call.List.Set(args)
call.Isddd = isddd
if method.Type.Results().NumFields() > 0 {
- n := Nod(ORETURN, nil, nil)
+ n := nod(ORETURN, nil, nil)
n.List.Set1(call)
call = n
}
@@ -1921,11 +1852,11 @@ func hashmem(t *Type) *Node {
n := newname(sym)
n.Class = PFUNC
- tfn := Nod(OTFUNC, nil, nil)
- tfn.List.Append(Nod(ODCLFIELD, nil, typenod(Ptrto(t))))
- tfn.List.Append(Nod(ODCLFIELD, nil, typenod(Types[TUINTPTR])))
- tfn.List.Append(Nod(ODCLFIELD, nil, typenod(Types[TUINTPTR])))
- tfn.Rlist.Append(Nod(ODCLFIELD, nil, typenod(Types[TUINTPTR])))
+ 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 = typecheck(tfn, Etype)
n.Type = tfn.Type
return n
@@ -1942,7 +1873,7 @@ func ifacelookdot(s *Sym, t *Type, followptr *bool, ignorecase bool) *Field {
path, ambig := dotpath(s, t, &m, ignorecase)
if path == nil {
if ambig {
- Yyerror("%v.%v is ambiguous", t, s)
+ yyerror("%v.%v is ambiguous", t, s)
}
return nil
}
@@ -1955,7 +1886,7 @@ func ifacelookdot(s *Sym, t *Type, followptr *bool, ignorecase bool) *Field {
}
if m.Type.Etype != TFUNC || m.Type.Recv() == nil {
- Yyerror("%v.%v is a field, not a method", t, s)
+ yyerror("%v.%v is a field, not a method", t, s)
return nil
}
@@ -1976,7 +1907,7 @@ func implements(t, iface *Type, m, samename **Field, ptr *int) bool {
for _, im := range iface.Fields().Slice() {
for _, tm := range t.Fields().Slice() {
if tm.Sym == im.Sym {
- if Eqtype(tm.Type, im.Type) {
+ if eqtype(tm.Type, im.Type) {
goto found
}
*m = im
@@ -1996,7 +1927,7 @@ func implements(t, iface *Type, m, samename **Field, ptr *int) bool {
return true
}
- t = methtype(t, 0)
+ t = methtype(t)
if t != nil {
expandmeth(t)
}
@@ -2006,7 +1937,7 @@ func implements(t, iface *Type, m, samename **Field, ptr *int) bool {
}
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)
}
@@ -2022,7 +1953,7 @@ func implements(t, iface *Type, m, samename **Field, ptr *int) bool {
if rcvr.IsPtr() && !t0.IsPtr() && !followptr && !isifacemethod(tm.Type) {
if false && Debug['r'] != 0 {
- Yyerror("interface pointer mismatch")
+ yyerror("interface pointer mismatch")
}
*m = im
@@ -2043,7 +1974,7 @@ func Simsimtype(t *Type) EType {
return 0
}
- et := Simtype[t.Etype]
+ et := simtype[t.Etype]
switch et {
case TPTR32:
et = TUINT32
@@ -2067,7 +1998,7 @@ func listtreecopy(l []*Node, lineno int32) []*Node {
}
func liststmt(l []*Node) *Node {
- n := Nod(OBLOCK, nil, nil)
+ n := nod(OBLOCK, nil, nil)
n.List.Set(l)
if len(l) != 0 {
n.Lineno = l[0].Lineno
@@ -2111,37 +2042,6 @@ func powtwo(n *Node) int {
return -1
}
-// return the unsigned type for
-// a signed integer type.
-// returns T if input is not a
-// signed integer type.
-func tounsigned(t *Type) *Type {
- // this is types[et+1], but not sure
- // that this relation is immutable
- switch t.Etype {
- default:
- fmt.Printf("tounsigned: unknown type %v\n", t)
- t = nil
-
- case TINT:
- t = Types[TUINT]
-
- case TINT8:
- t = Types[TUINT8]
-
- case TINT16:
- t = Types[TUINT16]
-
- case TINT32:
- t = Types[TUINT32]
-
- case TINT64:
- t = Types[TUINT64]
- }
-
- return t
-}
-
func ngotype(n *Node) *Sym {
if n.Type != nil {
return typenamesym(n.Type)
@@ -2204,12 +2104,12 @@ func addinit(n *Node, init []*Node) *Node {
// There may be multiple refs to this node;
// introduce OCONVNOP to hold init list.
case ONAME, OLITERAL:
- n = Nod(OCONVNOP, n, nil)
+ n = nod(OCONVNOP, n, nil)
n.Type = n.Left.Type
n.Typecheck = 1
}
- n.Ninit.Set(append(init, n.Ninit.Slice()...))
+ n.Ninit.Prepend(init...)
n.Ullman = UINF
return n
}
@@ -2221,40 +2121,40 @@ var reservedimports = []string{
func isbadimport(path string) bool {
if strings.Contains(path, "\x00") {
- Yyerror("import path contains NUL")
+ yyerror("import path contains NUL")
return true
}
for _, ri := range reservedimports {
if path == ri {
- Yyerror("import path %q is reserved and cannot be used", path)
+ yyerror("import path %q is reserved and cannot be used", path)
return true
}
}
for _, r := range path {
if r == utf8.RuneError {
- Yyerror("import path contains invalid UTF-8 sequence: %q", path)
+ yyerror("import path contains invalid UTF-8 sequence: %q", path)
return true
}
if r < 0x20 || r == 0x7f {
- Yyerror("import path contains control character: %q", path)
+ yyerror("import path contains control character: %q", path)
return true
}
if r == '\\' {
- Yyerror("import path contains backslash; use slash: %q", path)
+ yyerror("import path contains backslash; use slash: %q", path)
return true
}
if unicode.IsSpace(r) {
- Yyerror("import path contains space character: %q", path)
+ yyerror("import path contains space character: %q", path)
return true
}
if strings.ContainsRune("!\"#$%&'()*,:;<=>?[]^`{|}", r) {
- Yyerror("import path contains invalid character '%c': %q", r, path)
+ yyerror("import path contains invalid character '%c': %q", r, path)
return true
}
}
@@ -2265,11 +2165,11 @@ func isbadimport(path string) bool {
func checknil(x *Node, init *Nodes) {
x = walkexpr(x, nil) // caller has not done this yet
if x.Type.IsInterface() {
- x = Nod(OITAB, x, nil)
+ x = nod(OITAB, x, nil)
x = typecheck(x, Erv)
}
- n := Nod(OCHECKNIL, x, nil)
+ n := nod(OCHECKNIL, x, nil)
n.Typecheck = 1
init.Append(n)
}
@@ -2298,6 +2198,35 @@ func isdirectiface(t *Type) bool {
return false
}
+// 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.Xoffset = int64(Widthptr) // offset of _type in runtime.itab
+ typ.Bounded = 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 {
+ ptr := nodSym(OIDATA, n, nil)
+ if isdirectiface(t) {
+ ptr.Type = t
+ ptr.Typecheck = 1
+ return ptr
+ }
+ ptr.Type = ptrto(t)
+ ptr.Bounded = true
+ ptr.Typecheck = 1
+ ind := nod(OIND, ptr, nil)
+ ind.Type = t
+ ind.Typecheck = 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.
diff --git a/src/cmd/compile/internal/gc/swt.go b/src/cmd/compile/internal/gc/swt.go
index 4940c97..3d3496d 100644
--- a/src/cmd/compile/internal/gc/swt.go
+++ b/src/cmd/compile/internal/gc/swt.go
@@ -4,36 +4,20 @@
package gc
-import (
- "sort"
- "strconv"
-)
+import "sort"
const (
// expression switch
switchKindExpr = iota // switch a {...} or switch 5 {...}
switchKindTrue // switch true {...} or switch {...}
switchKindFalse // switch false {...}
-
- // type switch
- switchKindType // switch a.(type) {...}
)
const (
- caseKindDefault = iota // default:
-
- // expression switch
- caseKindExprConst // case 5:
- caseKindExprVar // case x:
-
- // type switch
- caseKindTypeNil // case nil:
- caseKindTypeConst // case time.Time: (concrete type, has type hash)
- caseKindTypeVar // case io.Reader: (interface type)
+ binarySearchMin = 4 // minimum number of cases for binary search
+ integerRangeMin = 2 // minimum size of integer ranges
)
-const binarySearchMin = 4 // minimum number of cases for binary search
-
// An exprSwitch walks an expression switch.
type exprSwitch struct {
exprname *Node // node for the expression being switched on
@@ -52,7 +36,18 @@ type caseClause struct {
node *Node // points at case statement
ordinal int // position in switch
hash uint32 // hash of a type switch
- typ uint8 // type of case
+ // isconst indicates whether this case clause is a constant,
+ // for the purposes of the switch code generation.
+ // For expression switches, that's generally literals (case 5:, not case x:).
+ // For type switches, that's concrete types (case time.Time:), not interfaces (case io.Reader:).
+ isconst bool
+}
+
+// caseClauses are all the case clauses in a switch statement.
+type caseClauses struct {
+ list []caseClause // general cases
+ defjmp *Node // OGOTO for default case or OBREAK if no default case present
+ niljmp *Node // OGOTO for nil type case in a type switch
}
// typecheckswitch typechecks a switch statement.
@@ -70,7 +65,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 %v", Nconv(n.Left.Right, FmtLong))
+ yyerror("cannot type switch on non-interface value %L", n.Left.Right)
}
} else {
// expression switch
@@ -85,14 +80,14 @@ func typecheckswitch(n *Node) {
if t != nil {
switch {
case !okforeq[t.Etype]:
- Yyerror("cannot switch on %v", Nconv(n.Left, FmtLong))
+ yyerror("cannot switch on %L", n.Left)
case t.IsSlice():
nilonly = "slice"
case t.IsArray() && !t.IsComparable():
- Yyerror("cannot switch on %v", Nconv(n.Left, FmtLong))
+ yyerror("cannot switch on %L", n.Left)
case t.IsStruct():
if f := t.IncomparableField(); f != nil {
- Yyerror("cannot switch on %v (struct containing %v cannot be compared)", Nconv(n.Left, FmtLong), f.Type)
+ yyerror("cannot switch on %L (struct containing %v cannot be compared)", n.Left, f.Type)
}
case t.Etype == TFUNC:
nilonly = "func"
@@ -110,7 +105,8 @@ func typecheckswitch(n *Node) {
if ncase.List.Len() == 0 {
// default
if def != nil {
- Yyerror("multiple defaults in switch (first at %v)", def.Line())
+ setlineno(ncase)
+ yyerror("multiple defaults in switch (first at %v)", def.Line())
} else {
def = ncase
}
@@ -131,17 +127,17 @@ func typecheckswitch(n *Node) {
n1 = ls[i1]
switch {
case n1.Op == OTYPE:
- Yyerror("type %v is not an expression", n1.Type)
+ yyerror("type %v is not an expression", n1.Type)
case n1.Type != nil && assignop(n1.Type, t, nil) == 0 && assignop(t, n1.Type, nil) == 0:
if n.Left != nil {
- Yyerror("invalid case %v in switch on %v (mismatched types %v and %v)", n1, n.Left, n1.Type, t)
+ yyerror("invalid case %v in switch on %v (mismatched types %v and %v)", n1, n.Left, n1.Type, t)
} else {
- Yyerror("invalid case %v in switch (mismatched types %v and bool)", n1, n1.Type)
+ yyerror("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)
+ yyerror("invalid case %v in switch (can only compare %s %v to nil)", n1, nilonly, n.Left)
case t.IsInterface() && !n1.Type.IsInterface() && !n1.Type.IsComparable():
- Yyerror("invalid case %v in switch (incomparable type)", Nconv(n1, FmtLong))
+ yyerror("invalid case %L in switch (incomparable type)", n1)
}
// type switch
@@ -152,20 +148,22 @@ func typecheckswitch(n *Node) {
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())
+ yyerror("multiple nil cases in type switch (first at %v)", niltype.Line())
} else {
niltype = ncase
}
case n1.Op != OTYPE && n1.Type != nil: // should this be ||?
- Yyerror("%v is not a type", Nconv(n1, FmtLong))
+ yyerror("%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: %v cannot have dynamic type %v"+" (wrong type for %v method)\n\thave %v%v\n\twant %v%v", Nconv(n.Left.Right, FmtLong), n1.Type, missing.Sym, have.Sym, Tconv(have.Type, FmtShort), missing.Sym, Tconv(missing.Type, FmtShort))
+ yyerror("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: %v cannot have dynamic type %v"+" (missing %v method)", Nconv(n.Left.Right, FmtLong), n1.Type, missing.Sym)
+ yyerror("impossible type switch case: %L cannot have dynamic type %v"+
+ " (missing %v method)", n.Left.Right, n1.Type, missing.Sym)
}
}
}
@@ -199,7 +197,7 @@ func typecheckswitch(n *Node) {
func walkswitch(sw *Node) {
// convert switch {...} to switch true {...}
if sw.Left == nil {
- sw.Left = Nodbool(true)
+ sw.Left = nodbool(true)
sw.Left = typecheck(sw.Left, Erv)
}
@@ -240,31 +238,25 @@ func (s *exprSwitch) walk(sw *Node) {
// convert the switch into OIF statements
var cas []*Node
if s.kind == switchKindTrue || s.kind == switchKindFalse {
- s.exprname = Nodbool(s.kind == switchKindTrue)
+ s.exprname = nodbool(s.kind == switchKindTrue)
} else if consttype(cond) >= 0 {
// leave constants to enable dead code elimination (issue 9608)
s.exprname = cond
} else {
s.exprname = temp(cond.Type)
- cas = []*Node{Nod(OAS, s.exprname, cond)}
+ cas = []*Node{nod(OAS, s.exprname, cond)}
typecheckslice(cas, Etop)
}
- // enumerate the cases, and lop off the default case
- cc := caseClauses(sw, s.kind)
+ // Enumerate the cases and prepare the default case.
+ clauses := s.genCaseClauses(sw.List.Slice())
sw.List.Set(nil)
- var def *Node
- if len(cc) > 0 && cc[0].typ == caseKindDefault {
- def = cc[0].node.Right
- cc = cc[1:]
- } else {
- def = Nod(OBREAK, nil, nil)
- }
+ cc := clauses.list
// handle the cases in order
for len(cc) > 0 {
// deal with expressions one at a time
- if !okforcmp[t.Etype] || cc[0].typ != caseKindExprConst {
+ if !okforcmp[t.Etype] || !cc[0].isconst {
a := s.walkCases(cc[:1])
cas = append(cas, a)
cc = cc[1:]
@@ -273,11 +265,11 @@ func (s *exprSwitch) walk(sw *Node) {
// do binary search on runs of constants
var run int
- for run = 1; run < len(cc) && cc[run].typ == caseKindExprConst; run++ {
+ for run = 1; run < len(cc) && cc[run].isconst; run++ {
}
// sort and compile constants
- sort.Sort(caseClauseByExpr(cc[:run]))
+ sort.Sort(caseClauseByConstVal(cc[:run]))
a := s.walkCases(cc[:run])
cas = append(cas, a)
cc = cc[run:]
@@ -285,14 +277,14 @@ func (s *exprSwitch) walk(sw *Node) {
// handle default case
if nerrors == 0 {
- cas = append(cas, def)
- sw.Nbody.Set(append(cas, sw.Nbody.Slice()...))
+ cas = append(cas, clauses.defjmp)
+ sw.Nbody.Prepend(cas...)
walkstmtlist(sw.Nbody.Slice())
}
}
// walkCases generates an AST implementing the cases in cc.
-func (s *exprSwitch) walkCases(cc []*caseClause) *Node {
+func (s *exprSwitch) walkCases(cc []caseClause) *Node {
if len(cc) < binarySearchMin {
// linear search
var cas []*Node
@@ -300,15 +292,26 @@ func (s *exprSwitch) walkCases(cc []*caseClause) *Node {
n := c.node
lno := setlineno(n)
- a := Nod(OIF, nil, nil)
- if (s.kind != switchKindTrue && s.kind != switchKindFalse) || assignop(n.Left.Type, s.exprname.Type, nil) == OCONVIFACE || assignop(s.exprname.Type, n.Left.Type, nil) == OCONVIFACE {
- a.Left = Nod(OEQ, s.exprname, n.Left) // if name == val
+ a := nod(OIF, nil, nil)
+ if rng := n.List.Slice(); rng != nil {
+ // Integer range.
+ // exprname is a temp or a constant,
+ // so it is safe to evaluate twice.
+ // In most cases, this conjunction will be
+ // rewritten by walkinrange into a single comparison.
+ low := nod(OGE, s.exprname, rng[0])
+ high := nod(OLE, s.exprname, rng[1])
+ a.Left = nod(OANDAND, low, high)
+ a.Left = typecheck(a.Left, Erv)
+ a.Left = walkexpr(a.Left, nil) // give walk the opportunity to optimize the range check
+ } else if (s.kind != switchKindTrue && s.kind != switchKindFalse) || assignop(n.Left.Type, s.exprname.Type, nil) == OCONVIFACE || assignop(s.exprname.Type, n.Left.Type, nil) == OCONVIFACE {
+ a.Left = nod(OEQ, s.exprname, n.Left) // if name == val
a.Left = typecheck(a.Left, Erv)
} else if s.kind == switchKindTrue {
a.Left = n.Left // if val
} else {
// s.kind == switchKindFalse
- a.Left = Nod(ONOT, n.Left, nil) // if !val
+ a.Left = nod(ONOT, n.Left, nil) // if !val
a.Left = typecheck(a.Left, Erv)
}
a.Nbody.Set1(n.Right) // goto l
@@ -321,14 +324,20 @@ func (s *exprSwitch) walkCases(cc []*caseClause) *Node {
// find the middle and recur
half := len(cc) / 2
- a := Nod(OIF, nil, nil)
- mid := cc[half-1].node.Left
- le := Nod(OLE, s.exprname, mid)
+ a := nod(OIF, nil, nil)
+ n := cc[half-1].node
+ var mid *Node
+ if rng := n.List.Slice(); rng != nil {
+ mid = rng[1] // high end of range
+ } else {
+ mid = n.Left
+ }
+ le := nod(OLE, s.exprname, mid)
if Isconst(mid, CTSTR) {
- // Search by length and then by value; see exprcmp.
- lenlt := Nod(OLT, Nod(OLEN, s.exprname, nil), Nod(OLEN, mid, nil))
- leneq := Nod(OEQ, Nod(OLEN, s.exprname, nil), Nod(OLEN, mid, nil))
- a.Left = Nod(OOROR, lenlt, Nod(OANDAND, leneq, le))
+ // Search by length and then by value; see caseClauseByConstVal.
+ lenlt := nod(OLT, nod(OLEN, s.exprname, nil), nod(OLEN, mid, nil))
+ leneq := nod(OEQ, nod(OLEN, s.exprname, nil), nod(OLEN, mid, nil))
+ a.Left = nod(OOROR, lenlt, nod(OANDAND, leneq, le))
} else {
a.Left = le
}
@@ -351,7 +360,7 @@ func casebody(sw *Node, typeswvar *Node) {
var cas []*Node // cases
var stat []*Node // statements
var def *Node // defaults
- br := Nod(OBREAK, nil, nil)
+ br := nod(OBREAK, nil, nil)
for i, n := range sw.List.Slice() {
setlineno(n)
@@ -361,51 +370,103 @@ func casebody(sw *Node, typeswvar *Node) {
n.Op = OCASE
needvar := n.List.Len() != 1 || n.List.First().Op == OLITERAL
- jmp := Nod(OGOTO, newCaseLabel(), nil)
- if n.List.Len() == 0 {
+ jmp := nod(OGOTO, autolabel(".s"), nil)
+ switch n.List.Len() {
+ case 0:
+ // default
if def != nil {
- Yyerror("more than one default case")
+ yyerror("more than one default case")
}
// reuse original default case
n.Right = jmp
def = n
- }
-
- if n.List.Len() == 1 {
+ case 1:
// one case -- reuse OCASE node
n.Left = n.List.First()
n.Right = jmp
n.List.Set(nil)
cas = append(cas, n)
- } else {
- // expand multi-valued cases
- for _, n1 := range n.List.Slice() {
- cas = append(cas, Nod(OCASE, n1, jmp))
+ default:
+ // Expand multi-valued cases and detect ranges of integer cases.
+ if typeswvar != nil || sw.Left.Type.IsInterface() || !n.List.First().Type.IsInteger() || n.List.Len() < integerRangeMin {
+ // Can't use integer ranges. Expand each case into a separate node.
+ for _, n1 := range n.List.Slice() {
+ cas = append(cas, nod(OCASE, n1, jmp))
+ }
+ break
+ }
+ // Find integer ranges within runs of constants.
+ s := n.List.Slice()
+ j := 0
+ for j < len(s) {
+ // Find a run of constants.
+ var run int
+ for run = j; run < len(s) && Isconst(s[run], CTINT); run++ {
+ }
+ if run-j >= integerRangeMin {
+ // Search for integer ranges in s[j:run].
+ // Typechecking is done, so all values are already in an appropriate range.
+ search := s[j:run]
+ sort.Sort(constIntNodesByVal(search))
+ for beg, end := 0, 1; end <= len(search); end++ {
+ if end < len(search) && search[end].Int64() == search[end-1].Int64()+1 {
+ continue
+ }
+ if end-beg >= integerRangeMin {
+ // Record range in List.
+ c := nod(OCASE, nil, jmp)
+ c.List.Set2(search[beg], search[end-1])
+ cas = append(cas, c)
+ } else {
+ // Not large enough for range; record separately.
+ for _, n := range search[beg:end] {
+ cas = append(cas, nod(OCASE, n, jmp))
+ }
+ }
+ beg = end
+ }
+ j = run
+ }
+ // Advance to next constant, adding individual non-constant
+ // or as-yet-unhandled constant cases as we go.
+ for ; j < len(s) && (j < run || !Isconst(s[j], CTINT)); j++ {
+ cas = append(cas, nod(OCASE, s[j], jmp))
+ }
}
}
- stat = append(stat, Nod(OLABEL, jmp.Left, nil))
+ stat = append(stat, nod(OLABEL, jmp.Left, nil))
if typeswvar != nil && needvar && n.Rlist.Len() != 0 {
l := []*Node{
- Nod(ODCL, n.Rlist.First(), nil),
- Nod(OAS, n.Rlist.First(), typeswvar),
+ nod(ODCL, n.Rlist.First(), nil),
+ nod(OAS, n.Rlist.First(), typeswvar),
}
typecheckslice(l, Etop)
stat = append(stat, l...)
}
stat = append(stat, n.Nbody.Slice()...)
+ // Search backwards for the index of the fallthrough
+ // statement. Do not assume it'll be in the last
+ // position, since in some cases (e.g. when the statement
+ // list contains autotmp_ variables), one or more OVARKILL
+ // nodes will be at the end of the list.
+ fallIndex := len(stat) - 1
+ for stat[fallIndex].Op == OVARKILL {
+ fallIndex--
+ }
+ last := stat[fallIndex]
+
// botch - shouldn't fall through declaration
- last := stat[len(stat)-1]
if last.Xoffset == n.Xoffset && last.Op == OXFALL {
if typeswvar != nil {
setlineno(last)
- Yyerror("cannot fallthrough in type switch")
+ yyerror("cannot fallthrough in type switch")
}
if i+1 >= sw.List.Len() {
setlineno(last)
- Yyerror("cannot fallthrough final case in switch")
+ yyerror("cannot fallthrough final case in switch")
}
last.Op = OFALL
@@ -424,94 +485,188 @@ func casebody(sw *Node, typeswvar *Node) {
lineno = lno
}
-// nSwitchLabel is the number of switch labels generated.
-// This should be per-function, but it is a global counter for now.
-var nSwitchLabel int
+// genCaseClauses generates the caseClauses value for clauses.
+func (s *exprSwitch) genCaseClauses(clauses []*Node) caseClauses {
+ var cc caseClauses
+ for _, n := range clauses {
+ if n.Left == nil && n.List.Len() == 0 {
+ // default case
+ if cc.defjmp != nil {
+ Fatalf("duplicate default case not detected during typechecking")
+ }
+ cc.defjmp = n.Right
+ continue
+ }
+ c := caseClause{node: n, ordinal: len(cc.list)}
+ if n.List.Len() > 0 {
+ c.isconst = true
+ }
+ switch consttype(n.Left) {
+ case CTFLT, CTINT, CTRUNE, CTSTR:
+ c.isconst = true
+ }
+ cc.list = append(cc.list, c)
+ }
-func newCaseLabel() *Node {
- label := strconv.Itoa(nSwitchLabel)
- nSwitchLabel++
- return newname(Lookup(label))
+ if cc.defjmp == nil {
+ cc.defjmp = nod(OBREAK, nil, nil)
+ }
+
+ // diagnose duplicate cases
+ s.checkDupCases(cc.list)
+ return cc
}
-// caseClauses generates a slice of caseClauses
-// corresponding to the clauses in the switch statement sw.
-// Kind is the kind of switch statement.
-func caseClauses(sw *Node, kind int) []*caseClause {
- var cc []*caseClause
- for _, n := range sw.List.Slice() {
- c := new(caseClause)
- cc = append(cc, c)
- c.ordinal = len(cc)
- c.node = n
-
- if n.Left == nil {
- c.typ = caseKindDefault
+// genCaseClauses generates the caseClauses value for clauses.
+func (s *typeSwitch) genCaseClauses(clauses []*Node) caseClauses {
+ var cc caseClauses
+ for _, n := range clauses {
+ switch {
+ case n.Left == nil:
+ // default case
+ if cc.defjmp != nil {
+ Fatalf("duplicate default case not detected during typechecking")
+ }
+ cc.defjmp = n.Right
+ continue
+ case n.Left.Op == OLITERAL:
+ // nil case in type switch
+ if cc.niljmp != nil {
+ Fatalf("duplicate nil case not detected during typechecking")
+ }
+ cc.niljmp = n.Right
continue
}
- if kind == switchKindType {
- // type switch
- switch {
- case n.Left.Op == OLITERAL:
- c.typ = caseKindTypeNil
- case n.Left.Type.IsInterface():
- c.typ = caseKindTypeVar
- default:
- c.typ = caseKindTypeConst
- c.hash = typehash(n.Left.Type)
- }
- } else {
- // expression switch
- switch consttype(n.Left) {
- case CTFLT, CTINT, CTRUNE, CTSTR:
- c.typ = caseKindExprConst
- default:
- c.typ = caseKindExprVar
- }
+ // general case
+ c := caseClause{
+ node: n,
+ ordinal: len(cc.list),
+ isconst: !n.Left.Type.IsInterface(),
+ hash: typehash(n.Left.Type),
}
+ cc.list = append(cc.list, c)
}
- if cc == nil {
- return nil
+ if cc.defjmp == nil {
+ cc.defjmp = nod(OBREAK, nil, nil)
}
- // sort by value and diagnose duplicate cases
- if kind == switchKindType {
- // type switch
- sort.Sort(caseClauseByType(cc))
- for i, c1 := range cc {
- if c1.typ == caseKindTypeNil || c1.typ == caseKindDefault {
- break
+ // diagnose duplicate cases
+ s.checkDupCases(cc.list)
+ return cc
+}
+
+func (s *typeSwitch) checkDupCases(cc []caseClause) {
+ if len(cc) < 2 {
+ return
+ }
+ // We store seen types in a map keyed by type hash.
+ // It is possible, but very unlikely, for multiple distinct types to have the same hash.
+ seen := make(map[uint32][]*Node)
+ // To avoid many small allocations of length 1 slices,
+ // also set up a single large slice to slice into.
+ nn := make([]*Node, 0, len(cc))
+Outer:
+ for _, c := range cc {
+ prev, ok := seen[c.hash]
+ if !ok {
+ // First entry for this hash.
+ nn = append(nn, c.node)
+ seen[c.hash] = nn[len(nn)-1 : len(nn):len(nn)]
+ continue
+ }
+ 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())
+ // avoid double-reporting errors
+ continue Outer
}
- for _, c2 := range cc[i+1:] {
- if c2.typ == caseKindTypeNil || c2.typ == caseKindDefault || c1.hash != c2.hash {
- break
+ }
+ seen[c.hash] = append(seen[c.hash], c.node)
+ }
+}
+
+func (s *exprSwitch) checkDupCases(cc []caseClause) {
+ if len(cc) < 2 {
+ 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() {
+ seen := make(map[interface{}]*Node)
+ for _, c := range cc {
+ switch {
+ case c.node.Left != nil:
+ // Single constant.
+
+ // 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
+ // (2) it would disallow useful things like
+ // 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 {
+ continue
}
- if Eqtype(c1.node.Left.Type, c2.node.Left.Type) {
- yyerrorl(c2.node.Lineno, "duplicate case %v in type switch\n\tprevious case at %v", c2.node.Left.Type, c1.node.Line())
+
+ val := c.node.Left.Val().Interface()
+ prev, dup := seen[val]
+ if !dup {
+ seen[val] = c.node
+ 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)
}
}
- } else {
- // expression switch
- sort.Sort(caseClauseByExpr(cc))
- for i, c1 := range cc {
- if i+1 == len(cc) {
- break
- }
- c2 := cc[i+1]
- if exprcmp(c1, c2) != 0 {
- continue
- }
- setlineno(c2.node)
- Yyerror("duplicate case %v in switch\n\tprevious case at %v", c1.node.Left, c1.node.Line())
+ return
+ }
+ // s's expression is an interface. This is fairly rare, so keep this simple.
+ // Duplicates are only duplicates if they have the same type and the same value.
+ type typeVal struct {
+ typ string
+ 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
+ }
+ setlineno(c.node)
+ yyerror("duplicate case %v in switch\n\tprevious case at %v", prev.Left, prev.Line())
}
-
- // put list back in processing order
- sort.Sort(caseClauseByOrd(cc))
- return cc
}
// walk generates an AST that implements sw,
@@ -529,13 +684,13 @@ func (s *typeSwitch) walk(sw *Node) {
}
if cond.Right == nil {
setlineno(sw)
- Yyerror("type switch must have an assignment")
+ yyerror("type switch must have an assignment")
return
}
cond.Right = walkexpr(cond.Right, &sw.Ninit)
if !cond.Right.Type.IsInterface() {
- Yyerror("type switch must be on an interface")
+ yyerror("type switch must be on an interface")
return
}
@@ -544,7 +699,7 @@ func (s *typeSwitch) walk(sw *Node) {
// predeclare temporary variables and the boolean var
s.facename = temp(cond.Right.Type)
- a := Nod(OAS, s.facename, cond.Right)
+ a := nod(OAS, s.facename, cond.Right)
a = typecheck(a, Etop)
cas = append(cas, a)
@@ -557,20 +712,9 @@ func (s *typeSwitch) walk(sw *Node) {
// set up labels and jumps
casebody(sw, s.facename)
- cc := caseClauses(sw, switchKindType)
+ clauses := s.genCaseClauses(sw.List.Slice())
sw.List.Set(nil)
- var def *Node
- if len(cc) > 0 && cc[0].typ == caseKindDefault {
- def = cc[0].node.Right
- cc = cc[1:]
- } else {
- def = Nod(OBREAK, nil, nil)
- }
- var typenil *Node
- if len(cc) > 0 && cc[0].typ == caseKindTypeNil {
- typenil = cc[0].node.Right
- cc = cc[1:]
- }
+ def := clauses.defjmp
// For empty interfaces, do:
// if e._type == nil {
@@ -580,21 +724,21 @@ func (s *typeSwitch) walk(sw *Node) {
// Use a similar strategy for non-empty interfaces.
// Get interface descriptor word.
- typ := Nod(OITAB, s.facename, nil)
+ typ := nod(OITAB, s.facename, nil)
// Check for nil first.
- i := Nod(OIF, nil, nil)
- i.Left = Nod(OEQ, typ, nodnil())
- if typenil != nil {
+ i := nod(OIF, nil, nil)
+ i.Left = nod(OEQ, typ, nodnil())
+ if clauses.niljmp != nil {
// Do explicit nil case right here.
- i.Nbody.Set1(typenil)
+ i.Nbody.Set1(clauses.niljmp)
} else {
// Jump to default case.
- lbl := newCaseLabel()
- i.Nbody.Set1(Nod(OGOTO, lbl, nil))
+ lbl := autolabel(".s")
+ 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 := nod(OBLOCK, nil, nil)
+ blk.List.Set([]*Node{nod(OLABEL, lbl, nil), def})
def = blk
}
i.Left = typecheck(i.Left, Erv)
@@ -602,36 +746,28 @@ func (s *typeSwitch) walk(sw *Node) {
if !cond.Right.Type.IsEmptyInterface() {
// Load type from itab.
- typ = NodSym(ODOTPTR, typ, nil)
- typ.Type = Ptrto(Types[TUINT8])
- typ.Typecheck = 1
- typ.Xoffset = int64(Widthptr) // offset of _type in runtime.itab
- typ.Bounded = true // guaranteed not to fault
+ typ = itabType(typ)
}
// Load hash from type.
- h := NodSym(ODOTPTR, typ, nil)
+ h := nodSym(ODOTPTR, typ, nil)
h.Type = Types[TUINT32]
h.Typecheck = 1
h.Xoffset = int64(2 * Widthptr) // offset of hash in runtime._type
h.Bounded = true // guaranteed not to fault
- a = Nod(OAS, s.hashname, h)
+ a = nod(OAS, s.hashname, h)
a = typecheck(a, Etop)
cas = append(cas, a)
+ cc := clauses.list
+
// insert type equality check into each case block
for _, c := range cc {
- n := c.node
- switch c.typ {
- case caseKindTypeVar, caseKindTypeConst:
- n.Right = s.typeone(n)
- default:
- Fatalf("typeSwitch with bad kind: %d", c.typ)
- }
+ c.node.Right = s.typeone(c.node)
}
// generate list of if statements, binary search for constant sequences
for len(cc) > 0 {
- if cc[0].typ != caseKindTypeConst {
+ if !cc[0].isconst {
n := cc[0].node
cas = append(cas, n.Right)
cc = cc[1:]
@@ -640,7 +776,7 @@ func (s *typeSwitch) walk(sw *Node) {
// identify run of constants
var run int
- for run = 1; run < len(cc) && cc[run].typ == caseKindTypeConst; run++ {
+ for run = 1; run < len(cc) && cc[run].isconst; run++ {
}
// sort by hash
@@ -674,7 +810,7 @@ func (s *typeSwitch) walk(sw *Node) {
// handle default case
if nerrors == 0 {
cas = append(cas, def)
- sw.Nbody.Set(append(cas, sw.Nbody.Slice()...))
+ sw.Nbody.Prepend(cas...)
sw.List.Set(nil)
walkstmtlist(sw.Nbody.Slice())
}
@@ -690,21 +826,21 @@ func (s *typeSwitch) typeone(t *Node) *Node {
nblank = typecheck(nblank, Erv|Easgn)
} else {
name = t.Rlist.First()
- init = []*Node{Nod(ODCL, name, nil)}
- a := Nod(OAS, name, nil)
+ init = []*Node{nod(ODCL, name, nil)}
+ a := nod(OAS, name, nil)
a = typecheck(a, Etop)
init = append(init, a)
}
- a := Nod(OAS2, nil, nil)
+ a := nod(OAS2, nil, nil)
a.List.Set([]*Node{name, s.okname}) // name, ok =
- b := Nod(ODOTTYPE, s.facename, nil)
+ 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)
- c := Nod(OIF, nil, nil)
+ c := nod(OIF, nil, nil)
c.Left = s.okname
c.Nbody.Set1(t.Right) // if ok { goto l }
@@ -712,16 +848,16 @@ func (s *typeSwitch) typeone(t *Node) *Node {
}
// walkCases generates an AST implementing the cases in cc.
-func (s *typeSwitch) walkCases(cc []*caseClause) *Node {
+func (s *typeSwitch) walkCases(cc []caseClause) *Node {
if len(cc) < binarySearchMin {
var cas []*Node
for _, c := range cc {
n := c.node
- if c.typ != caseKindTypeConst {
+ if !c.isconst {
Fatalf("typeSwitch walkCases")
}
- a := Nod(OIF, nil, nil)
- a.Left = Nod(OEQ, s.hashname, Nodintconst(int64(c.hash)))
+ a := nod(OIF, nil, nil)
+ a.Left = nod(OEQ, s.hashname, nodintconst(int64(c.hash)))
a.Left = typecheck(a.Left, Erv)
a.Nbody.Set1(n.Right)
cas = append(cas, a)
@@ -731,123 +867,78 @@ func (s *typeSwitch) walkCases(cc []*caseClause) *Node {
// find the middle and recur
half := len(cc) / 2
- a := Nod(OIF, nil, nil)
- a.Left = Nod(OLE, s.hashname, Nodintconst(int64(cc[half-1].hash)))
+ a := nod(OIF, nil, nil)
+ a.Left = nod(OLE, s.hashname, nodintconst(int64(cc[half-1].hash)))
a.Left = typecheck(a.Left, Erv)
a.Nbody.Set1(s.walkCases(cc[:half]))
a.Rlist.Set1(s.walkCases(cc[half:]))
return a
}
-type caseClauseByOrd []*caseClause
-
-func (x caseClauseByOrd) Len() int { return len(x) }
-func (x caseClauseByOrd) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
-func (x caseClauseByOrd) Less(i, j int) bool {
- c1, c2 := x[i], x[j]
- switch {
- // sort default first
- case c1.typ == caseKindDefault:
- return true
- case c2.typ == caseKindDefault:
- return false
-
- // sort nil second
- case c1.typ == caseKindTypeNil:
- return true
- case c2.typ == caseKindTypeNil:
- return false
- }
-
- // sort by ordinal
- return c1.ordinal < c2.ordinal
-}
-
-type caseClauseByExpr []*caseClause
-
-func (x caseClauseByExpr) Len() int { return len(x) }
-func (x caseClauseByExpr) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
-func (x caseClauseByExpr) Less(i, j int) bool {
- return exprcmp(x[i], x[j]) < 0
-}
-
-func exprcmp(c1, c2 *caseClause) int {
- // sort non-constants last
- if c1.typ != caseKindExprConst {
- return +1
- }
- if c2.typ != caseKindExprConst {
- return -1
+// caseClauseByConstVal sorts clauses by constant value to enable binary search.
+type caseClauseByConstVal []caseClause
+
+func (x caseClauseByConstVal) Len() int { return len(x) }
+func (x caseClauseByConstVal) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
+func (x caseClauseByConstVal) Less(i, j int) bool {
+ // n1 and n2 might be individual constants or integer ranges.
+ // We have checked for duplicates already,
+ // so ranges can be safely represented by any value in the range.
+ n1 := x[i].node
+ var v1 interface{}
+ if s := n1.List.Slice(); s != nil {
+ v1 = s[0].Val().U
+ } else {
+ v1 = n1.Left.Val().U
}
- n1 := c1.node.Left
- n2 := c2.node.Left
-
- // sort by type (for switches on interface)
- ct := n1.Val().Ctype()
- if ct > n2.Val().Ctype() {
- return +1
- }
- if ct < n2.Val().Ctype() {
- return -1
- }
- if !Eqtype(n1.Type, n2.Type) {
- if n1.Type.Vargen > n2.Type.Vargen {
- return +1
- } else {
- return -1
- }
+ n2 := x[j].node
+ var v2 interface{}
+ if s := n2.List.Slice(); s != nil {
+ v2 = s[0].Val().U
+ } else {
+ v2 = n2.Left.Val().U
}
- // sort by constant value to enable binary search
- switch ct {
- case CTFLT:
- return n1.Val().U.(*Mpflt).Cmp(n2.Val().U.(*Mpflt))
- case CTINT, CTRUNE:
- return n1.Val().U.(*Mpint).Cmp(n2.Val().U.(*Mpint))
- case CTSTR:
+ switch v1 := v1.(type) {
+ case *Mpflt:
+ return v1.Cmp(v2.(*Mpflt)) < 0
+ case *Mpint:
+ return v1.Cmp(v2.(*Mpint)) < 0
+ case string:
// Sort strings by length and then by value.
// It is much cheaper to compare lengths than values,
// and all we need here is consistency.
// We respect this sorting in exprSwitch.walkCases.
- a := n1.Val().U.(string)
- b := n2.Val().U.(string)
- if len(a) < len(b) {
- return -1
+ a := v1
+ b := v2.(string)
+ if len(a) != len(b) {
+ return len(a) < len(b)
}
- if len(a) > len(b) {
- return +1
- }
- if a == b {
- return 0
- }
- if a < b {
- return -1
- }
- return +1
+ return a < b
}
- return 0
+ Fatalf("caseClauseByConstVal passed bad clauses %v < %v", x[i].node.Left, x[j].node.Left)
+ return false
}
-type caseClauseByType []*caseClause
+type caseClauseByType []caseClause
func (x caseClauseByType) Len() int { return len(x) }
func (x caseClauseByType) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
func (x caseClauseByType) Less(i, j int) bool {
c1, c2 := x[i], x[j]
- switch {
- // sort non-constants last
- case c1.typ != caseKindTypeConst:
- return false
- case c2.typ != caseKindTypeConst:
- return true
-
- // sort by hash code
- case c1.hash != c2.hash:
+ // sort by hash code, then ordinal (for the rare case of hash collisions)
+ if c1.hash != c2.hash {
return c1.hash < c2.hash
}
-
- // sort by ordinal
return c1.ordinal < c2.ordinal
}
+
+type constIntNodesByVal []*Node
+
+func (x constIntNodesByVal) Len() int { return len(x) }
+func (x constIntNodesByVal) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
+func (x constIntNodesByVal) Less(i, j int) bool {
+ return x[i].Val().U.(*Mpint).Cmp(x[j].Val().U.(*Mpint)) < 0
+}
diff --git a/src/cmd/compile/internal/gc/swt_test.go b/src/cmd/compile/internal/gc/swt_test.go
index c1ee895..4139898 100644
--- a/src/cmd/compile/internal/gc/swt_test.go
+++ b/src/cmd/compile/internal/gc/swt_test.go
@@ -5,140 +5,42 @@
package gc
import (
- "cmd/compile/internal/big"
+ "math/big"
"testing"
)
-func TestExprcmp(t *testing.T) {
- testdata := []struct {
- a, b caseClause
- want int
+func nodrune(r rune) *Node {
+ return nodlit(Val{&Mpint{Val: *big.NewInt(int64(r)), Rune: true}})
+}
+
+func nodflt(f float64) *Node {
+ return nodlit(Val{&Mpflt{Val: *big.NewFloat(f)}})
+}
+
+func TestCaseClauseByConstVal(t *testing.T) {
+ tests := []struct {
+ a, b *Node
}{
- // Non-constants.
- {
- caseClause{node: Nod(OXXX, nil, nil), typ: caseKindExprVar},
- caseClause{node: Nod(OXXX, nil, nil), typ: caseKindExprConst},
- +1,
- },
- {
- caseClause{node: Nod(OXXX, nil, nil), typ: caseKindExprConst},
- caseClause{node: Nod(OXXX, nil, nil), typ: caseKindExprVar},
- -1,
- },
- // Type switches
- {
- caseClause{node: Nod(OXXX, Nodintconst(0), nil), typ: caseKindExprConst},
- caseClause{node: Nod(OXXX, Nodbool(true), nil), typ: caseKindExprConst},
- -1,
- },
- {
- caseClause{node: Nod(OXXX, Nodbool(true), nil), typ: caseKindExprConst},
- caseClause{node: Nod(OXXX, Nodintconst(1), nil), typ: caseKindExprConst},
- +1,
- },
- {
- caseClause{node: Nod(OXXX, &Node{Type: &Type{Etype: TBOOL, Vargen: 1}}, nil), typ: caseKindExprConst},
- caseClause{node: Nod(OXXX, &Node{Type: &Type{Etype: TINT, Vargen: 0}}, nil), typ: caseKindExprConst},
- +1,
- },
- {
- caseClause{node: Nod(OXXX, &Node{Type: &Type{Etype: TBOOL, Vargen: 1}}, nil), typ: caseKindExprConst},
- caseClause{node: Nod(OXXX, &Node{Type: &Type{Etype: TINT, Vargen: 1}}, nil), typ: caseKindExprConst},
- -1,
- },
- {
- caseClause{node: Nod(OXXX, &Node{Type: &Type{Etype: TBOOL, Vargen: 0}}, nil), typ: caseKindExprConst},
- caseClause{node: Nod(OXXX, &Node{Type: &Type{Etype: TINT, Vargen: 1}}, nil), typ: caseKindExprConst},
- -1,
- },
- // Constant values.
// CTFLT
- {
- caseClause{node: Nod(OXXX, nodlit(Val{&Mpflt{Val: *big.NewFloat(0.1)}}), nil), typ: caseKindExprConst},
- caseClause{node: Nod(OXXX, nodlit(Val{&Mpflt{Val: *big.NewFloat(0.2)}}), nil), typ: caseKindExprConst},
- -1,
- },
- {
- caseClause{node: Nod(OXXX, nodlit(Val{&Mpflt{Val: *big.NewFloat(0.1)}}), nil), typ: caseKindExprConst},
- caseClause{node: Nod(OXXX, nodlit(Val{&Mpflt{Val: *big.NewFloat(0.1)}}), nil), typ: caseKindExprConst},
- 0,
- },
- {
- caseClause{node: Nod(OXXX, nodlit(Val{&Mpflt{Val: *big.NewFloat(0.2)}}), nil), typ: caseKindExprConst},
- caseClause{node: Nod(OXXX, nodlit(Val{&Mpflt{Val: *big.NewFloat(0.1)}}), nil), typ: caseKindExprConst},
- +1,
- },
+ {nodflt(0.1), nodflt(0.2)},
// CTINT
- {
- caseClause{node: Nod(OXXX, Nodintconst(0), nil), typ: caseKindExprConst},
- caseClause{node: Nod(OXXX, Nodintconst(1), nil), typ: caseKindExprConst},
- -1,
- },
- {
- caseClause{node: Nod(OXXX, Nodintconst(1), nil), typ: caseKindExprConst},
- caseClause{node: Nod(OXXX, Nodintconst(1), nil), typ: caseKindExprConst},
- 0,
- },
- {
- caseClause{node: Nod(OXXX, Nodintconst(1), nil), typ: caseKindExprConst},
- caseClause{node: Nod(OXXX, Nodintconst(0), nil), typ: caseKindExprConst},
- +1,
- },
+ {nodintconst(0), nodintconst(1)},
// CTRUNE
- {
- caseClause{node: Nod(OXXX, nodlit(Val{&Mpint{Val: *big.NewInt('a'), Rune: true}}), nil), typ: caseKindExprConst},
- caseClause{node: Nod(OXXX, nodlit(Val{&Mpint{Val: *big.NewInt('b'), Rune: true}}), nil), typ: caseKindExprConst},
- -1,
- },
- {
- caseClause{node: Nod(OXXX, nodlit(Val{&Mpint{Val: *big.NewInt('b'), Rune: true}}), nil), typ: caseKindExprConst},
- caseClause{node: Nod(OXXX, nodlit(Val{&Mpint{Val: *big.NewInt('b'), Rune: true}}), nil), typ: caseKindExprConst},
- 0,
- },
- {
- caseClause{node: Nod(OXXX, nodlit(Val{&Mpint{Val: *big.NewInt('b'), Rune: true}}), nil), typ: caseKindExprConst},
- caseClause{node: Nod(OXXX, nodlit(Val{&Mpint{Val: *big.NewInt('a'), Rune: true}}), nil), typ: caseKindExprConst},
- +1,
- },
+ {nodrune('a'), nodrune('b')},
// CTSTR
- {
- caseClause{node: Nod(OXXX, nodlit(Val{"ab"}), nil), typ: caseKindExprConst},
- caseClause{node: Nod(OXXX, nodlit(Val{"abc"}), nil), typ: caseKindExprConst},
- -1,
- },
- {
- caseClause{node: Nod(OXXX, nodlit(Val{"abc"}), nil), typ: caseKindExprConst},
- caseClause{node: Nod(OXXX, nodlit(Val{"xyz"}), nil), typ: caseKindExprConst},
- -1,
- },
- {
- caseClause{node: Nod(OXXX, nodlit(Val{"abc"}), nil), typ: caseKindExprConst},
- caseClause{node: Nod(OXXX, nodlit(Val{"abc"}), nil), typ: caseKindExprConst},
- 0,
- },
- {
- caseClause{node: Nod(OXXX, nodlit(Val{"abc"}), nil), typ: caseKindExprConst},
- caseClause{node: Nod(OXXX, nodlit(Val{"ab"}), nil), typ: caseKindExprConst},
- +1,
- },
- {
- caseClause{node: Nod(OXXX, nodlit(Val{"xyz"}), nil), typ: caseKindExprConst},
- caseClause{node: Nod(OXXX, nodlit(Val{"abc"}), nil), typ: caseKindExprConst},
- +1,
- },
- // Everything else should compare equal.
- {
- caseClause{node: Nod(OXXX, nodnil(), nil), typ: caseKindExprConst},
- caseClause{node: Nod(OXXX, nodnil(), nil), typ: caseKindExprConst},
- 0,
- },
+ {nodlit(Val{"ab"}), nodlit(Val{"abc"})},
+ {nodlit(Val{"ab"}), nodlit(Val{"xyz"})},
+ {nodlit(Val{"abc"}), nodlit(Val{"xyz"})},
}
- for i, d := range testdata {
- got := exprcmp(&d.a, &d.b)
- if d.want != got {
- t.Errorf("%d: exprcmp(a, b) = %d; want %d", i, got, d.want)
- t.Logf("\ta = caseClause{node: %#v, typ: %#v}", d.a.node, d.a.typ)
- t.Logf("\tb = caseClause{node: %#v, typ: %#v}", d.b.node, d.b.typ)
+ for i, test := range tests {
+ a := caseClause{node: nod(OXXX, test.a, nil)}
+ b := caseClause{node: nod(OXXX, test.b, nil)}
+ s := caseClauseByConstVal{a, b}
+ if less := s.Less(0, 1); !less {
+ t.Errorf("%d: caseClauseByConstVal(%v, %v) = false", i, test.a, test.b)
+ }
+ if less := s.Less(1, 0); less {
+ t.Errorf("%d: caseClauseByConstVal(%v, %v) = true", i, test.a, test.b)
}
}
}
diff --git a/src/cmd/compile/internal/gc/syntax.go b/src/cmd/compile/internal/gc/syntax.go
index fab8697..8b06d3a 100644
--- a/src/cmd/compile/internal/gc/syntax.go
+++ b/src/cmd/compile/internal/gc/syntax.go
@@ -33,39 +33,36 @@ type Node struct {
Sym *Sym // various
E interface{} // Opt or Val, see methods below
- // Various. Usually an offset into a struct. For example, ONAME nodes
- // that refer to local variables use it to identify their stack frame
- // position. ODOT, ODOTPTR, and OINDREG use it to indicate offset
- // relative to their base address. ONAME nodes on the left side of an
- // OKEY within an OSTRUCTLIT use it to store the named field's offset.
- // OXCASE and OXFALL use it to validate the use of fallthrough.
+ // Various. Usually an offset into a struct. For example:
+ // - ONAME nodes that refer to local variables use it to identify their stack frame position.
+ // - ODOT, ODOTPTR, and 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
// Possibly still more uses. If you find any, document them.
Xoffset int64
Lineno int32
- // OREGISTER, OINDREG
- Reg int16
-
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
+ 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 uint8 // already printed error about this
+ 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
- Typecheck uint8
+ Walkdef uint8 // tracks state during typecheckdef; 2 == loop detected
+ Typecheck uint8 // tracks state during typechecking; 2 == loop detected
Local bool
- Dodata uint8
+ IsStatic bool // whether this Node will be converted to purely static data
Initorder uint8
- Used bool
+ 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
@@ -75,11 +72,20 @@ type Node struct {
flags uint8 // TODO: store more bool fields in this flag field
}
+// IsAutoTmp indicates if n was created by the compiler as a temporary,
+// based on the setting of the .AutoTemp flag in n's Name.
+func (n *Node) IsAutoTmp() bool {
+ if n == nil || n.Op != ONAME {
+ return false
+ }
+ return n.Name.AutoTemp
+}
+
const (
hasBreak = 1 << iota
- notLiveAtEnd
isClosureVar
isOutputParamHeapAddr
+ noInline // used internally by inliner to indicate that a function call should not be inlined; set for OCALLFUNC and OCALLMETH only
)
func (n *Node) HasBreak() bool {
@@ -92,16 +98,6 @@ func (n *Node) SetHasBreak(b bool) {
n.flags &^= hasBreak
}
}
-func (n *Node) NotLiveAtEnd() bool {
- return n.flags¬LiveAtEnd != 0
-}
-func (n *Node) SetNotLiveAtEnd(b bool) {
- if b {
- n.flags |= notLiveAtEnd
- } else {
- n.flags &^= notLiveAtEnd
- }
-}
func (n *Node) isClosureVar() bool {
return n.flags&isClosureVar != 0
}
@@ -112,6 +108,16 @@ func (n *Node) setIsClosureVar(b bool) {
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
@@ -166,25 +172,31 @@ func (n *Node) SetOpt(x interface{}) {
n.E = x
}
-// Name holds Node fields used only by named nodes (ONAME, OPACK, OLABEL, ODCLFIELD, some OLITERAL).
+func (n *Node) Iota() int64 {
+ return n.Xoffset
+}
+
+func (n *Node) SetIota(x int64) {
+ n.Xoffset = x
+}
+
+// Name holds Node fields used only by named nodes (ONAME, 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?)
- Inlvar *Node // ONAME substitute while inlining (could move to Param?)
Defn *Node // initializing assignment
Curfn *Node // function for local variables
- Param *Param // additional fields for ONAME, ODCLFIELD
+ 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.
- Iota int32 // value if this name is iota
Funcdepth int32
- Method bool // OCALLMETH name
Readonly bool
Captured bool // is the variable captured by a closure
Byval bool // is the variable captured by value or by reference
Needzero bool // if it contains pointers, needs to be zeroed on function entry
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)
}
type Param struct {
@@ -267,6 +279,11 @@ type Param struct {
// and x.Innermost/Outer means x.Name.Param.Innermost/Outer.
Innermost *Node
Outer *Node
+
+ // OTYPE pragmas
+ //
+ // TODO: Should Func pragmas also be stored on the Name?
+ Pragma Pragma
}
// Func holds Node fields used only with function-like nodes.
@@ -283,21 +300,23 @@ type Func struct {
Ntype *Node // signature
Top int // top context (Ecall, Eproc, etc)
Closure *Node // OCLOSURE <-> ODCLFUNC
- FCurfn *Node
Nname *Node
Inl Nodes // copy of the body for use in inlining
InlCost int32
Depth int32
+ Label int32 // largest auto-generated label in this function
+
Endlineno int32
WBLineno int32 // line number of first write barrier
- Pragma Pragma // go:xxx function annotations
- Dupok bool // duplicate definitions ok
- Wrapper bool // is method wrapper
- Needctxt bool // function uses context register (has closure variables)
- ReflectMethod bool // function calls reflect.Type.Method or MethodByName
+ 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
}
type Op uint8
@@ -349,7 +368,8 @@ const (
OCOMPLIT // Right{List} (composite literal, not yet lowered to specific form)
OMAPLIT // Type{List} (composite literal, Type is map)
OSTRUCTLIT // Type{List} (composite literal, Type is struct)
- OARRAYLIT // Type{List} (composite literal, Type is array or slice)
+ OARRAYLIT // Type{List} (composite literal, Type is array)
+ OSLICELIT // Type{List} (composite literal, Type is slice)
OPTRLIT // &Left (left is composite literal)
OCONV // Type(Left) (type conversion)
OCONVIFACE // Type(Left) (type conversion, to interface)
@@ -380,8 +400,8 @@ const (
OIND // *Left
OINDEX // Left[Right] (index of array or slice)
OINDEXMAP // Left[Right] (index of map)
- OKEY // Left:Right (key:value in struct/array/map literal, or slice index pair)
- _ // was OPARAM, but cannot remove without breaking binary blob in builtin.go
+ OKEY // Left:Right (key:value in struct/array/map literal)
+ OSTRUCTKEY // Sym:Left (key:value in struct literal, after type checking)
OLEN // len(Left)
OMAKE // make(List) (before type checking converts to one of the following)
OMAKECHAN // make(Type, Left) (type is chan)
@@ -405,11 +425,11 @@ const (
OPRINTN // println(List)
OPAREN // (Left)
OSEND // Left <- Right
- OSLICE // Left[Right.Left : Right.Right] (Left is untypechecked or slice; Right.Op==OKEY)
- OSLICEARR // Left[Right.Left : Right.Right] (Left is array)
- OSLICESTR // Left[Right.Left : Right.Right] (Left is string)
- OSLICE3 // Left[R.Left : R.R.Left : R.R.R] (R=Right; Left is untypedchecked or slice; R.Op and R.R.Op==OKEY)
- OSLICE3ARR // Left[R.Left : R.R.Left : R.R.R] (R=Right; Left is array; R.Op and R.R.Op==OKEY)
+ OSLICE // Left[List[0] : List[1]] (Left is untypechecked or slice)
+ OSLICEARR // Left[List[0] : List[1]] (Left is array)
+ OSLICESTR // Left[List[0] : List[1]] (Left is string)
+ OSLICE3 // Left[List[0] : List[1] : List[2]] (Left is untypedchecked or slice)
+ OSLICE3ARR // Left[List[0] : List[1] : List[2]] (Left is array)
ORECOVER // recover()
ORECV // <-Left
ORUNESTR // Type(Left) (Type is string, Left is rune)
@@ -419,11 +439,14 @@ const (
OREAL // real(Left)
OIMAG // imag(Left)
OCOMPLEX // complex(Left, Right)
+ OALIGNOF // unsafe.Alignof(Left)
+ OOFFSETOF // unsafe.Offsetof(Left)
+ OSIZEOF // unsafe.Sizeof(Left)
// statements
OBLOCK // { List } (block of code)
OBREAK // break
- OCASE // case List: Nbody (select case after processing; List==nil means default)
+ OCASE // case Left or List[0]..List[1]: Nbody (select case after processing; Left==nil and List==nil means default)
OXCASE // case List: Nbody (select case before processing; List==nil means default)
OCONTINUE // continue
ODEFER // defer Left (Left must be call)
@@ -455,16 +478,14 @@ const (
OINLCALL // intermediary representation of an inlined call.
OEFACE // itable and data words of an empty-interface value.
OITAB // itable word of an interface value.
+ OIDATA // data word of an interface value in Left
OSPTR // base pointer of a slice or string.
OCLOSUREVAR // variable reference at beginning of closure function
OCFUNC // reference to c function pointer (not go func value)
OCHECKNIL // emit code to ensure pointer/interface not nil
OVARKILL // variable is dead
OVARLIVE // variable is alive
-
- // thearch-specific registers
- OREGISTER // a register, such as AX.
- OINDREG // offset plus indirect of a register, such as 8(SP).
+ OINDREGSP // offset plus indirect of REGSP, such as 8(SP).
// arch-specific opcodes
OCMP // compare: ACMP.
@@ -543,6 +564,11 @@ func (n *Nodes) Set1(node *Node) {
n.slice = &[]*Node{node}
}
+// Set2 sets n to a slice containing two nodes.
+func (n *Nodes) Set2(n1, n2 *Node) {
+ n.slice = &[]*Node{n1, n2}
+}
+
// MoveNodes sets n to the contents of n2, then clears n2.
func (n *Nodes) MoveNodes(n2 *Nodes) {
n.slice = n2.slice
@@ -564,15 +590,29 @@ 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 {
- if len(a) > 0 {
- n.slice = &a
- }
+ n.slice = &a
} else {
*n.slice = append(*n.slice, a...)
}
}
+// Prepend prepends entries to Nodes.
+// If a slice is passed in, this will take ownership of it.
+func (n *Nodes) Prepend(a ...*Node) {
+ if len(a) == 0 {
+ return
+ }
+ if n.slice == nil {
+ n.slice = &a
+ } else {
+ *n.slice = append(a, *n.slice...)
+ }
+}
+
// AppendNodes appends the contents of *n2 to n, then clears n2.
func (n *Nodes) AppendNodes(n2 *Nodes) {
switch {
diff --git a/src/cmd/compile/internal/gc/testdata/addressed_ssa.go b/src/cmd/compile/internal/gc/testdata/addressed.go
similarity index 100%
rename from src/cmd/compile/internal/gc/testdata/addressed_ssa.go
rename to src/cmd/compile/internal/gc/testdata/addressed.go
diff --git a/src/cmd/compile/internal/gc/testdata/append_ssa.go b/src/cmd/compile/internal/gc/testdata/append.go
similarity index 100%
rename from src/cmd/compile/internal/gc/testdata/append_ssa.go
rename to src/cmd/compile/internal/gc/testdata/append.go
diff --git a/src/cmd/compile/internal/gc/testdata/arith.go b/src/cmd/compile/internal/gc/testdata/arith.go
new file mode 100644
index 0000000..d850ce2
--- /dev/null
+++ b/src/cmd/compile/internal/gc/testdata/arith.go
@@ -0,0 +1,1020 @@
+// run
+
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Tests arithmetic expressions
+
+package main
+
+import "fmt"
+
+const (
+ y = 0x0fffFFFF
+)
+
+//go:noinline
+func lshNop1(x uint64) uint64 {
+ // two outer shifts should be removed
+ return (((x << 5) >> 2) << 2)
+}
+
+//go:noinline
+func lshNop2(x uint64) uint64 {
+ return (((x << 5) >> 2) << 3)
+}
+
+//go:noinline
+func lshNop3(x uint64) uint64 {
+ return (((x << 5) >> 2) << 6)
+}
+
+//go:noinline
+func lshNotNop(x uint64) uint64 {
+ // outer shift can't be removed
+ return (((x << 5) >> 2) << 1)
+}
+
+//go:noinline
+func rshNop1(x uint64) uint64 {
+ return (((x >> 5) << 2) >> 2)
+}
+
+//go:noinline
+func rshNop2(x uint64) uint64 {
+ return (((x >> 5) << 2) >> 3)
+}
+
+//go:noinline
+func rshNop3(x uint64) uint64 {
+ return (((x >> 5) << 2) >> 6)
+}
+
+//go:noinline
+func rshNotNop(x uint64) uint64 {
+ return (((x >> 5) << 2) >> 1)
+}
+
+func testShiftRemoval() {
+ allSet := ^uint64(0)
+ if want, got := uint64(0x7ffffffffffffff), rshNop1(allSet); want != got {
+ println("testShiftRemoval rshNop1 failed, wanted", want, "got", got)
+ failed = true
+ }
+ if want, got := uint64(0x3ffffffffffffff), rshNop2(allSet); want != got {
+ println("testShiftRemoval rshNop2 failed, wanted", want, "got", got)
+ failed = true
+ }
+ if want, got := uint64(0x7fffffffffffff), rshNop3(allSet); want != got {
+ println("testShiftRemoval rshNop3 failed, wanted", want, "got", got)
+ failed = true
+ }
+ if want, got := uint64(0xffffffffffffffe), rshNotNop(allSet); want != got {
+ println("testShiftRemoval rshNotNop failed, wanted", want, "got", got)
+ failed = true
+ }
+ if want, got := uint64(0xffffffffffffffe0), lshNop1(allSet); want != got {
+ println("testShiftRemoval lshNop1 failed, wanted", want, "got", got)
+ failed = true
+ }
+ if want, got := uint64(0xffffffffffffffc0), lshNop2(allSet); want != got {
+ println("testShiftRemoval lshNop2 failed, wanted", want, "got", got)
+ failed = true
+ }
+ if want, got := uint64(0xfffffffffffffe00), lshNop3(allSet); want != got {
+ println("testShiftRemoval lshNop3 failed, wanted", want, "got", got)
+ failed = true
+ }
+ if want, got := uint64(0x7ffffffffffffff0), lshNotNop(allSet); want != got {
+ println("testShiftRemoval lshNotNop failed, wanted", want, "got", got)
+ failed = true
+ }
+}
+
+//go:noinline
+func parseLE64(b []byte) uint64 {
+ // skip the first two bytes, and parse the remaining 8 as a uint64
+ return uint64(b[2]) | uint64(b[3])<<8 | uint64(b[4])<<16 | uint64(b[5])<<24 |
+ uint64(b[6])<<32 | uint64(b[7])<<40 | uint64(b[8])<<48 | uint64(b[9])<<56
+}
+
+//go:noinline
+func parseLE32(b []byte) uint32 {
+ return uint32(b[2]) | uint32(b[3])<<8 | uint32(b[4])<<16 | uint32(b[5])<<24
+}
+
+//go:noinline
+func parseLE16(b []byte) uint16 {
+ return uint16(b[2]) | uint16(b[3])<<8
+}
+
+// testLoadCombine tests for issue #14694 where load combining didn't respect the pointer offset.
+func testLoadCombine() {
+ testData := []byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09}
+ if want, got := uint64(0x0908070605040302), parseLE64(testData); want != got {
+ println("testLoadCombine failed, wanted", want, "got", got)
+ failed = true
+ }
+ if want, got := uint32(0x05040302), parseLE32(testData); want != got {
+ println("testLoadCombine failed, wanted", want, "got", got)
+ failed = true
+ }
+ if want, got := uint16(0x0302), parseLE16(testData); want != got {
+ println("testLoadCombine failed, wanted", want, "got", got)
+ failed = true
+ }
+}
+
+var loadSymData = [...]byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}
+
+func testLoadSymCombine() {
+ w2 := uint16(0x0201)
+ g2 := uint16(loadSymData[0]) | uint16(loadSymData[1])<<8
+ if g2 != w2 {
+ println("testLoadSymCombine failed, wanted", w2, "got", g2)
+ failed = true
+ }
+ w4 := uint32(0x04030201)
+ g4 := uint32(loadSymData[0]) | uint32(loadSymData[1])<<8 |
+ uint32(loadSymData[2])<<16 | uint32(loadSymData[3])<<24
+ if g4 != w4 {
+ println("testLoadSymCombine failed, wanted", w4, "got", g4)
+ failed = true
+ }
+ w8 := uint64(0x0807060504030201)
+ g8 := uint64(loadSymData[0]) | uint64(loadSymData[1])<<8 |
+ uint64(loadSymData[2])<<16 | uint64(loadSymData[3])<<24 |
+ uint64(loadSymData[4])<<32 | uint64(loadSymData[5])<<40 |
+ uint64(loadSymData[6])<<48 | uint64(loadSymData[7])<<56
+ if g8 != w8 {
+ println("testLoadSymCombine failed, wanted", w8, "got", g8)
+ failed = true
+ }
+}
+
+//go:noinline
+func invalidAdd_ssa(x uint32) uint32 {
+ return x + y + y + y + y + y + y + y + y + y + y + y + y + y + y + y + y + y
+}
+
+//go:noinline
+func invalidSub_ssa(x uint32) uint32 {
+ return x - y - y - y - y - y - y - y - y - y - y - y - y - y - y - y - y - y
+}
+
+//go:noinline
+func invalidMul_ssa(x uint32) uint32 {
+ return x * y * y * y * y * y * y * y * y * y * y * y * y * y * y * y * y * y
+}
+
+// testLargeConst tests a situation where larger than 32 bit consts were passed to ADDL
+// causing an invalid instruction error.
+func testLargeConst() {
+ if want, got := uint32(268435440), invalidAdd_ssa(1); want != got {
+ println("testLargeConst add failed, wanted", want, "got", got)
+ failed = true
+ }
+ if want, got := uint32(4026531858), invalidSub_ssa(1); want != got {
+ println("testLargeConst sub failed, wanted", want, "got", got)
+ failed = true
+ }
+ if want, got := uint32(268435455), invalidMul_ssa(1); want != got {
+ println("testLargeConst mul failed, wanted", want, "got", got)
+ failed = true
+ }
+}
+
+// testArithRshConst ensures that "const >> const" right shifts correctly perform
+// sign extension on the lhs constant
+func testArithRshConst() {
+ wantu := uint64(0x4000000000000000)
+ if got := arithRshuConst_ssa(); got != wantu {
+ println("arithRshuConst failed, wanted", wantu, "got", got)
+ failed = true
+ }
+
+ wants := int64(-0x4000000000000000)
+ if got := arithRshConst_ssa(); got != wants {
+ println("arithRshuConst failed, wanted", wants, "got", got)
+ failed = true
+ }
+}
+
+//go:noinline
+func arithRshuConst_ssa() uint64 {
+ y := uint64(0x8000000000000001)
+ z := uint64(1)
+ return uint64(y >> z)
+}
+
+//go:noinline
+func arithRshConst_ssa() int64 {
+ y := int64(-0x8000000000000000)
+ z := uint64(1)
+ return int64(y >> z)
+}
+
+//go:noinline
+func arithConstShift_ssa(x int64) int64 {
+ return x >> 100
+}
+
+// testArithConstShift tests that right shift by large constants preserve
+// the sign of the input.
+func testArithConstShift() {
+ want := int64(-1)
+ if got := arithConstShift_ssa(-1); want != got {
+ println("arithConstShift_ssa(-1) failed, wanted", want, "got", got)
+ failed = true
+ }
+ want = 0
+ if got := arithConstShift_ssa(1); want != got {
+ println("arithConstShift_ssa(1) failed, wanted", want, "got", got)
+ failed = true
+ }
+}
+
+// overflowConstShift_ssa verifes that constant folding for shift
+// doesn't wrap (i.e. x << MAX_INT << 1 doesn't get folded to x << 0).
+//go:noinline
+func overflowConstShift64_ssa(x int64) int64 {
+ return x << uint64(0xffffffffffffffff) << uint64(1)
+}
+
+//go:noinline
+func overflowConstShift32_ssa(x int64) int32 {
+ return int32(x) << uint32(0xffffffff) << uint32(1)
+}
+
+//go:noinline
+func overflowConstShift16_ssa(x int64) int16 {
+ return int16(x) << uint16(0xffff) << uint16(1)
+}
+
+//go:noinline
+func overflowConstShift8_ssa(x int64) int8 {
+ return int8(x) << uint8(0xff) << uint8(1)
+}
+
+func testOverflowConstShift() {
+ want := int64(0)
+ for x := int64(-127); x < int64(127); x++ {
+ got := overflowConstShift64_ssa(x)
+ if want != got {
+ fmt.Printf("overflowShift64 failed, wanted %d got %d\n", want, got)
+ }
+ got = int64(overflowConstShift32_ssa(x))
+ if want != got {
+ fmt.Printf("overflowShift32 failed, wanted %d got %d\n", want, got)
+ }
+ got = int64(overflowConstShift16_ssa(x))
+ if want != got {
+ fmt.Printf("overflowShift16 failed, wanted %d got %d\n", want, got)
+ }
+ got = int64(overflowConstShift8_ssa(x))
+ if want != got {
+ fmt.Printf("overflowShift8 failed, wanted %d got %d\n", want, got)
+ }
+ }
+}
+
+// test64BitConstMult tests that rewrite rules don't fold 64 bit constants
+// into multiply instructions.
+func test64BitConstMult() {
+ want := int64(103079215109)
+ if got := test64BitConstMult_ssa(1, 2); want != got {
+ println("test64BitConstMult failed, wanted", want, "got", got)
+ failed = true
+ }
+}
+
+//go:noinline
+func test64BitConstMult_ssa(a, b int64) int64 {
+ return 34359738369*a + b*34359738370
+}
+
+// test64BitConstAdd tests that rewrite rules don't fold 64 bit constants
+// into add instructions.
+func test64BitConstAdd() {
+ want := int64(3567671782835376650)
+ if got := test64BitConstAdd_ssa(1, 2); want != got {
+ println("test64BitConstAdd failed, wanted", want, "got", got)
+ failed = true
+ }
+}
+
+//go:noinline
+func test64BitConstAdd_ssa(a, b int64) int64 {
+ return a + 575815584948629622 + b + 2991856197886747025
+}
+
+// testRegallocCVSpill tests that regalloc spills a value whose last use is the
+// current value.
+func testRegallocCVSpill() {
+ want := int8(-9)
+ if got := testRegallocCVSpill_ssa(1, 2, 3, 4); want != got {
+ println("testRegallocCVSpill failed, wanted", want, "got", got)
+ failed = true
+ }
+}
+
+//go:noinline
+func testRegallocCVSpill_ssa(a, b, c, d int8) int8 {
+ return a + -32 + b + 63*c*-87*d
+}
+
+func testBitwiseLogic() {
+ a, b := uint32(57623283), uint32(1314713839)
+ if want, got := uint32(38551779), testBitwiseAnd_ssa(a, b); want != got {
+ println("testBitwiseAnd failed, wanted", want, "got", got)
+ failed = true
+ }
+ if want, got := uint32(1333785343), testBitwiseOr_ssa(a, b); want != got {
+ println("testBitwiseOr failed, wanted", want, "got", got)
+ failed = true
+ }
+ if want, got := uint32(1295233564), testBitwiseXor_ssa(a, b); want != got {
+ println("testBitwiseXor failed, wanted", want, "got", got)
+ failed = true
+ }
+ if want, got := int32(832), testBitwiseLsh_ssa(13, 4, 2); want != got {
+ println("testBitwiseLsh failed, wanted", want, "got", got)
+ failed = true
+ }
+ if want, got := int32(0), testBitwiseLsh_ssa(13, 25, 15); want != got {
+ println("testBitwiseLsh failed, wanted", want, "got", got)
+ failed = true
+ }
+ if want, got := int32(0), testBitwiseLsh_ssa(-13, 25, 15); want != got {
+ println("testBitwiseLsh failed, wanted", want, "got", got)
+ failed = true
+ }
+ if want, got := int32(-13), testBitwiseRsh_ssa(-832, 4, 2); want != got {
+ println("testBitwiseRsh failed, wanted", want, "got", got)
+ failed = true
+ }
+ if want, got := int32(0), testBitwiseRsh_ssa(13, 25, 15); want != got {
+ println("testBitwiseRsh failed, wanted", want, "got", got)
+ failed = true
+ }
+ if want, got := int32(-1), testBitwiseRsh_ssa(-13, 25, 15); want != got {
+ println("testBitwiseRsh failed, wanted", want, "got", got)
+ failed = true
+ }
+ if want, got := uint32(0x3ffffff), testBitwiseRshU_ssa(0xffffffff, 4, 2); want != got {
+ println("testBitwiseRshU failed, wanted", want, "got", got)
+ failed = true
+ }
+ if want, got := uint32(0), testBitwiseRshU_ssa(13, 25, 15); want != got {
+ println("testBitwiseRshU failed, wanted", want, "got", got)
+ failed = true
+ }
+ if want, got := uint32(0), testBitwiseRshU_ssa(0x8aaaaaaa, 25, 15); want != got {
+ println("testBitwiseRshU failed, wanted", want, "got", got)
+ failed = true
+ }
+}
+
+//go:noinline
+func testBitwiseAnd_ssa(a, b uint32) uint32 {
+ return a & b
+}
+
+//go:noinline
+func testBitwiseOr_ssa(a, b uint32) uint32 {
+ return a | b
+}
+
+//go:noinline
+func testBitwiseXor_ssa(a, b uint32) uint32 {
+ return a ^ b
+}
+
+//go:noinline
+func testBitwiseLsh_ssa(a int32, b, c uint32) int32 {
+ return a << b << c
+}
+
+//go:noinline
+func testBitwiseRsh_ssa(a int32, b, c uint32) int32 {
+ return a >> b >> c
+}
+
+//go:noinline
+func testBitwiseRshU_ssa(a uint32, b, c uint32) uint32 {
+ return a >> b >> c
+}
+
+//go:noinline
+func testShiftCX_ssa() int {
+ v1 := uint8(3)
+ v4 := (v1 * v1) ^ v1 | v1 - v1 - v1&v1 ^ uint8(3+2) + v1*1>>0 - v1 | 1 | v1<<(2*3|0-0*0^1)
+ v5 := v4>>(3-0-uint(3)) | v1 | v1 + v1 ^ v4<<(0+1|3&1)<<(uint64(1)<<0*2*0<<0) ^ v1
+ v6 := v5 ^ (v1+v1)*v1 | v1 | v1*v1>>(v1&v1)>>(uint(1)<<0*uint(3)>>1)*v1<<2*v1<<v1 - v1>>2 | (v4 - v1) ^ v1 + v1 ^ v1>>1 | v1 + v1 - v1 ^ v1
+ v7 := v6 & v5 << 0
+ v1++
+ v11 := 2&1 ^ 0 + 3 | int(0^0)<<1>>(1*0*3) ^ 0*0 ^ 3&0*3&3 ^ 3*3 ^ 1 ^ int(2)<<(2*3) + 2 | 2 | 2 ^ 2 + 1 | 3 | 0 ^ int(1)>>1 ^ 2 // int
+ v7--
+ return int(uint64(2*1)<<(3-2)<<uint(3>>v7)-2)&v11 | v11 - int(2)<<0>>(2-1)*(v11*0&v11<<1<<(uint8(2)+v4))
+}
+
+func testShiftCX() {
+ want := 141
+ if got := testShiftCX_ssa(); want != got {
+ println("testShiftCX failed, wanted", want, "got", got)
+ failed = true
+ }
+}
+
+// testSubqToNegq ensures that the SUBQ -> NEGQ translation works correctly.
+func testSubqToNegq() {
+ want := int64(-318294940372190156)
+ if got := testSubqToNegq_ssa(1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2); want != got {
+ println("testSubqToNegq failed, wanted", want, "got", got)
+ failed = true
+ }
+}
+
+//go:noinline
+func testSubqToNegq_ssa(a, b, c, d, e, f, g, h, i, j, k int64) int64 {
+ return a + 8207351403619448057 - b - 1779494519303207690 + c*8810076340510052032*d - 4465874067674546219 - e*4361839741470334295 - f + 8688847565426072650*g*8065564729145417479
+}
+
+func testOcom() {
+ want1, want2 := int32(0x55555555), int32(-0x55555556)
+ if got1, got2 := testOcom_ssa(0x55555555, 0x55555555); want1 != got1 || want2 != got2 {
+ println("testSubqToNegq failed, wanted", want1, "and", want2,
+ "got", got1, "and", got2)
+ failed = true
+ }
+}
+
+//go:noinline
+func testOcom_ssa(a, b int32) (int32, int32) {
+ return ^^^^a, ^^^^^b
+}
+
+func lrot1_ssa(w uint8, x uint16, y uint32, z uint64) (a uint8, b uint16, c uint32, d uint64) {
+ a = (w << 5) | (w >> 3)
+ b = (x << 13) | (x >> 3)
+ c = (y << 29) | (y >> 3)
+ d = (z << 61) | (z >> 3)
+ return
+}
+
+//go:noinline
+func lrot2_ssa(w, n uint32) uint32 {
+ // Want to be sure that a "rotate by 32" which
+ // is really 0 | (w >> 0) == w
+ // is correctly compiled.
+ return (w << n) | (w >> (32 - n))
+}
+
+//go:noinline
+func lrot3_ssa(w uint32) uint32 {
+ // Want to be sure that a "rotate by 32" which
+ // is really 0 | (w >> 0) == w
+ // is correctly compiled.
+ return (w << 32) | (w >> (32 - 32))
+}
+
+func testLrot() {
+ wantA, wantB, wantC, wantD := uint8(0xe1), uint16(0xe001),
+ uint32(0xe0000001), uint64(0xe000000000000001)
+ a, b, c, d := lrot1_ssa(0xf, 0xf, 0xf, 0xf)
+ if a != wantA || b != wantB || c != wantC || d != wantD {
+ println("lrot1_ssa(0xf, 0xf, 0xf, 0xf)=",
+ wantA, wantB, wantC, wantD, ", got", a, b, c, d)
+ failed = true
+ }
+ x := lrot2_ssa(0xb0000001, 32)
+ wantX := uint32(0xb0000001)
+ if x != wantX {
+ println("lrot2_ssa(0xb0000001, 32)=",
+ wantX, ", got", x)
+ failed = true
+ }
+ x = lrot3_ssa(0xb0000001)
+ if x != wantX {
+ println("lrot3_ssa(0xb0000001)=",
+ wantX, ", got", x)
+ failed = true
+ }
+
+}
+
+//go:noinline
+func sub1_ssa() uint64 {
+ v1 := uint64(3) // uint64
+ return v1*v1 - (v1&v1)&v1
+}
+
+//go:noinline
+func sub2_ssa() uint8 {
+ v1 := uint8(0)
+ v3 := v1 + v1 + v1 ^ v1 | 3 + v1 ^ v1 | v1 ^ v1
+ v1-- // dev.ssa doesn't see this one
+ return v1 ^ v1*v1 - v3
+}
+
+func testSubConst() {
+ x1 := sub1_ssa()
+ want1 := uint64(6)
+ if x1 != want1 {
+ println("sub1_ssa()=", want1, ", got", x1)
+ failed = true
+ }
+ x2 := sub2_ssa()
+ want2 := uint8(251)
+ if x2 != want2 {
+ println("sub2_ssa()=", want2, ", got", x2)
+ failed = true
+ }
+}
+
+//go:noinline
+func orPhi_ssa(a bool, x int) int {
+ v := 0
+ if a {
+ v = -1
+ } else {
+ v = -1
+ }
+ return x | v
+}
+
+func testOrPhi() {
+ if want, got := -1, orPhi_ssa(true, 4); got != want {
+ println("orPhi_ssa(true, 4)=", got, " want ", want)
+ }
+ if want, got := -1, orPhi_ssa(false, 0); got != want {
+ println("orPhi_ssa(false, 0)=", got, " want ", want)
+ }
+}
+
+//go:noinline
+func addshiftLL_ssa(a, b uint32) uint32 {
+ return a + b<<3
+}
+
+//go:noinline
+func subshiftLL_ssa(a, b uint32) uint32 {
+ return a - b<<3
+}
+
+//go:noinline
+func rsbshiftLL_ssa(a, b uint32) uint32 {
+ return a<<3 - b
+}
+
+//go:noinline
+func andshiftLL_ssa(a, b uint32) uint32 {
+ return a & (b << 3)
+}
+
+//go:noinline
+func orshiftLL_ssa(a, b uint32) uint32 {
+ return a | b<<3
+}
+
+//go:noinline
+func xorshiftLL_ssa(a, b uint32) uint32 {
+ return a ^ b<<3
+}
+
+//go:noinline
+func bicshiftLL_ssa(a, b uint32) uint32 {
+ return a &^ (b << 3)
+}
+
+//go:noinline
+func notshiftLL_ssa(a uint32) uint32 {
+ return ^(a << 3)
+}
+
+//go:noinline
+func addshiftRL_ssa(a, b uint32) uint32 {
+ return a + b>>3
+}
+
+//go:noinline
+func subshiftRL_ssa(a, b uint32) uint32 {
+ return a - b>>3
+}
+
+//go:noinline
+func rsbshiftRL_ssa(a, b uint32) uint32 {
+ return a>>3 - b
+}
+
+//go:noinline
+func andshiftRL_ssa(a, b uint32) uint32 {
+ return a & (b >> 3)
+}
+
+//go:noinline
+func orshiftRL_ssa(a, b uint32) uint32 {
+ return a | b>>3
+}
+
+//go:noinline
+func xorshiftRL_ssa(a, b uint32) uint32 {
+ return a ^ b>>3
+}
+
+//go:noinline
+func bicshiftRL_ssa(a, b uint32) uint32 {
+ return a &^ (b >> 3)
+}
+
+//go:noinline
+func notshiftRL_ssa(a uint32) uint32 {
+ return ^(a >> 3)
+}
+
+//go:noinline
+func addshiftRA_ssa(a, b int32) int32 {
+ return a + b>>3
+}
+
+//go:noinline
+func subshiftRA_ssa(a, b int32) int32 {
+ return a - b>>3
+}
+
+//go:noinline
+func rsbshiftRA_ssa(a, b int32) int32 {
+ return a>>3 - b
+}
+
+//go:noinline
+func andshiftRA_ssa(a, b int32) int32 {
+ return a & (b >> 3)
+}
+
+//go:noinline
+func orshiftRA_ssa(a, b int32) int32 {
+ return a | b>>3
+}
+
+//go:noinline
+func xorshiftRA_ssa(a, b int32) int32 {
+ return a ^ b>>3
+}
+
+//go:noinline
+func bicshiftRA_ssa(a, b int32) int32 {
+ return a &^ (b >> 3)
+}
+
+//go:noinline
+func notshiftRA_ssa(a int32) int32 {
+ return ^(a >> 3)
+}
+
+//go:noinline
+func addshiftLLreg_ssa(a, b uint32, s uint8) uint32 {
+ return a + b<<s
+}
+
+//go:noinline
+func subshiftLLreg_ssa(a, b uint32, s uint8) uint32 {
+ return a - b<<s
+}
+
+//go:noinline
+func rsbshiftLLreg_ssa(a, b uint32, s uint8) uint32 {
+ return a<<s - b
+}
+
+//go:noinline
+func andshiftLLreg_ssa(a, b uint32, s uint8) uint32 {
+ return a & (b << s)
+}
+
+//go:noinline
+func orshiftLLreg_ssa(a, b uint32, s uint8) uint32 {
+ return a | b<<s
+}
+
+//go:noinline
+func xorshiftLLreg_ssa(a, b uint32, s uint8) uint32 {
+ return a ^ b<<s
+}
+
+//go:noinline
+func bicshiftLLreg_ssa(a, b uint32, s uint8) uint32 {
+ return a &^ (b << s)
+}
+
+//go:noinline
+func notshiftLLreg_ssa(a uint32, s uint8) uint32 {
+ return ^(a << s)
+}
+
+//go:noinline
+func addshiftRLreg_ssa(a, b uint32, s uint8) uint32 {
+ return a + b>>s
+}
+
+//go:noinline
+func subshiftRLreg_ssa(a, b uint32, s uint8) uint32 {
+ return a - b>>s
+}
+
+//go:noinline
+func rsbshiftRLreg_ssa(a, b uint32, s uint8) uint32 {
+ return a>>s - b
+}
+
+//go:noinline
+func andshiftRLreg_ssa(a, b uint32, s uint8) uint32 {
+ return a & (b >> s)
+}
+
+//go:noinline
+func orshiftRLreg_ssa(a, b uint32, s uint8) uint32 {
+ return a | b>>s
+}
+
+//go:noinline
+func xorshiftRLreg_ssa(a, b uint32, s uint8) uint32 {
+ return a ^ b>>s
+}
+
+//go:noinline
+func bicshiftRLreg_ssa(a, b uint32, s uint8) uint32 {
+ return a &^ (b >> s)
+}
+
+//go:noinline
+func notshiftRLreg_ssa(a uint32, s uint8) uint32 {
+ return ^(a >> s)
+}
+
+//go:noinline
+func addshiftRAreg_ssa(a, b int32, s uint8) int32 {
+ return a + b>>s
+}
+
+//go:noinline
+func subshiftRAreg_ssa(a, b int32, s uint8) int32 {
+ return a - b>>s
+}
+
+//go:noinline
+func rsbshiftRAreg_ssa(a, b int32, s uint8) int32 {
+ return a>>s - b
+}
+
+//go:noinline
+func andshiftRAreg_ssa(a, b int32, s uint8) int32 {
+ return a & (b >> s)
+}
+
+//go:noinline
+func orshiftRAreg_ssa(a, b int32, s uint8) int32 {
+ return a | b>>s
+}
+
+//go:noinline
+func xorshiftRAreg_ssa(a, b int32, s uint8) int32 {
+ return a ^ b>>s
+}
+
+//go:noinline
+func bicshiftRAreg_ssa(a, b int32, s uint8) int32 {
+ return a &^ (b >> s)
+}
+
+//go:noinline
+func notshiftRAreg_ssa(a int32, s uint8) int32 {
+ return ^(a >> s)
+}
+
+// test ARM shifted ops
+func testShiftedOps() {
+ a, b := uint32(10), uint32(42)
+ if want, got := a+b<<3, addshiftLL_ssa(a, b); got != want {
+ println("addshiftLL_ssa(10, 42) =", got, " want ", want)
+ failed = true
+ }
+ if want, got := a-b<<3, subshiftLL_ssa(a, b); got != want {
+ println("subshiftLL_ssa(10, 42) =", got, " want ", want)
+ failed = true
+ }
+ if want, got := a<<3-b, rsbshiftLL_ssa(a, b); got != want {
+ println("rsbshiftLL_ssa(10, 42) =", got, " want ", want)
+ failed = true
+ }
+ if want, got := a&(b<<3), andshiftLL_ssa(a, b); got != want {
+ println("andshiftLL_ssa(10, 42) =", got, " want ", want)
+ failed = true
+ }
+ if want, got := a|b<<3, orshiftLL_ssa(a, b); got != want {
+ println("orshiftLL_ssa(10, 42) =", got, " want ", want)
+ failed = true
+ }
+ if want, got := a^b<<3, xorshiftLL_ssa(a, b); got != want {
+ println("xorshiftLL_ssa(10, 42) =", got, " want ", want)
+ failed = true
+ }
+ if want, got := a&^(b<<3), bicshiftLL_ssa(a, b); got != want {
+ println("bicshiftLL_ssa(10, 42) =", got, " want ", want)
+ failed = true
+ }
+ if want, got := ^(a << 3), notshiftLL_ssa(a); got != want {
+ println("notshiftLL_ssa(10) =", got, " want ", want)
+ failed = true
+ }
+ if want, got := a+b>>3, addshiftRL_ssa(a, b); got != want {
+ println("addshiftRL_ssa(10, 42) =", got, " want ", want)
+ failed = true
+ }
+ if want, got := a-b>>3, subshiftRL_ssa(a, b); got != want {
+ println("subshiftRL_ssa(10, 42) =", got, " want ", want)
+ failed = true
+ }
+ if want, got := a>>3-b, rsbshiftRL_ssa(a, b); got != want {
+ println("rsbshiftRL_ssa(10, 42) =", got, " want ", want)
+ failed = true
+ }
+ if want, got := a&(b>>3), andshiftRL_ssa(a, b); got != want {
+ println("andshiftRL_ssa(10, 42) =", got, " want ", want)
+ failed = true
+ }
+ if want, got := a|b>>3, orshiftRL_ssa(a, b); got != want {
+ println("orshiftRL_ssa(10, 42) =", got, " want ", want)
+ failed = true
+ }
+ if want, got := a^b>>3, xorshiftRL_ssa(a, b); got != want {
+ println("xorshiftRL_ssa(10, 42) =", got, " want ", want)
+ failed = true
+ }
+ if want, got := a&^(b>>3), bicshiftRL_ssa(a, b); got != want {
+ println("bicshiftRL_ssa(10, 42) =", got, " want ", want)
+ failed = true
+ }
+ if want, got := ^(a >> 3), notshiftRL_ssa(a); got != want {
+ println("notshiftRL_ssa(10) =", got, " want ", want)
+ failed = true
+ }
+ c, d := int32(10), int32(-42)
+ if want, got := c+d>>3, addshiftRA_ssa(c, d); got != want {
+ println("addshiftRA_ssa(10, -42) =", got, " want ", want)
+ failed = true
+ }
+ if want, got := c-d>>3, subshiftRA_ssa(c, d); got != want {
+ println("subshiftRA_ssa(10, -42) =", got, " want ", want)
+ failed = true
+ }
+ if want, got := c>>3-d, rsbshiftRA_ssa(c, d); got != want {
+ println("rsbshiftRA_ssa(10, -42) =", got, " want ", want)
+ failed = true
+ }
+ if want, got := c&(d>>3), andshiftRA_ssa(c, d); got != want {
+ println("andshiftRA_ssa(10, -42) =", got, " want ", want)
+ failed = true
+ }
+ if want, got := c|d>>3, orshiftRA_ssa(c, d); got != want {
+ println("orshiftRA_ssa(10, -42) =", got, " want ", want)
+ failed = true
+ }
+ if want, got := c^d>>3, xorshiftRA_ssa(c, d); got != want {
+ println("xorshiftRA_ssa(10, -42) =", got, " want ", want)
+ failed = true
+ }
+ if want, got := c&^(d>>3), bicshiftRA_ssa(c, d); got != want {
+ println("bicshiftRA_ssa(10, -42) =", got, " want ", want)
+ failed = true
+ }
+ if want, got := ^(d >> 3), notshiftRA_ssa(d); got != want {
+ println("notshiftRA_ssa(-42) =", got, " want ", want)
+ failed = true
+ }
+ s := uint8(3)
+ if want, got := a+b<<s, addshiftLLreg_ssa(a, b, s); got != want {
+ println("addshiftLLreg_ssa(10, 42, 3) =", got, " want ", want)
+ failed = true
+ }
+ if want, got := a-b<<s, subshiftLLreg_ssa(a, b, s); got != want {
+ println("subshiftLLreg_ssa(10, 42, 3) =", got, " want ", want)
+ failed = true
+ }
+ if want, got := a<<s-b, rsbshiftLLreg_ssa(a, b, s); got != want {
+ println("rsbshiftLLreg_ssa(10, 42, 3) =", got, " want ", want)
+ failed = true
+ }
+ if want, got := a&(b<<s), andshiftLLreg_ssa(a, b, s); got != want {
+ println("andshiftLLreg_ssa(10, 42, 3) =", got, " want ", want)
+ failed = true
+ }
+ if want, got := a|b<<s, orshiftLLreg_ssa(a, b, s); got != want {
+ println("orshiftLLreg_ssa(10, 42, 3) =", got, " want ", want)
+ failed = true
+ }
+ if want, got := a^b<<s, xorshiftLLreg_ssa(a, b, s); got != want {
+ println("xorshiftLLreg_ssa(10, 42, 3) =", got, " want ", want)
+ failed = true
+ }
+ if want, got := a&^(b<<s), bicshiftLLreg_ssa(a, b, s); got != want {
+ println("bicshiftLLreg_ssa(10, 42, 3) =", got, " want ", want)
+ failed = true
+ }
+ if want, got := ^(a << s), notshiftLLreg_ssa(a, s); got != want {
+ println("notshiftLLreg_ssa(10) =", got, " want ", want)
+ failed = true
+ }
+ if want, got := a+b>>s, addshiftRLreg_ssa(a, b, s); got != want {
+ println("addshiftRLreg_ssa(10, 42, 3) =", got, " want ", want)
+ failed = true
+ }
+ if want, got := a-b>>s, subshiftRLreg_ssa(a, b, s); got != want {
+ println("subshiftRLreg_ssa(10, 42, 3) =", got, " want ", want)
+ failed = true
+ }
+ if want, got := a>>s-b, rsbshiftRLreg_ssa(a, b, s); got != want {
+ println("rsbshiftRLreg_ssa(10, 42, 3) =", got, " want ", want)
+ failed = true
+ }
+ if want, got := a&(b>>s), andshiftRLreg_ssa(a, b, s); got != want {
+ println("andshiftRLreg_ssa(10, 42, 3) =", got, " want ", want)
+ failed = true
+ }
+ if want, got := a|b>>s, orshiftRLreg_ssa(a, b, s); got != want {
+ println("orshiftRLreg_ssa(10, 42, 3) =", got, " want ", want)
+ failed = true
+ }
+ if want, got := a^b>>s, xorshiftRLreg_ssa(a, b, s); got != want {
+ println("xorshiftRLreg_ssa(10, 42, 3) =", got, " want ", want)
+ failed = true
+ }
+ if want, got := a&^(b>>s), bicshiftRLreg_ssa(a, b, s); got != want {
+ println("bicshiftRLreg_ssa(10, 42, 3) =", got, " want ", want)
+ failed = true
+ }
+ if want, got := ^(a >> s), notshiftRLreg_ssa(a, s); got != want {
+ println("notshiftRLreg_ssa(10) =", got, " want ", want)
+ failed = true
+ }
+ if want, got := c+d>>s, addshiftRAreg_ssa(c, d, s); got != want {
+ println("addshiftRAreg_ssa(10, -42, 3) =", got, " want ", want)
+ failed = true
+ }
+ if want, got := c-d>>s, subshiftRAreg_ssa(c, d, s); got != want {
+ println("subshiftRAreg_ssa(10, -42, 3) =", got, " want ", want)
+ failed = true
+ }
+ if want, got := c>>s-d, rsbshiftRAreg_ssa(c, d, s); got != want {
+ println("rsbshiftRAreg_ssa(10, -42, 3) =", got, " want ", want)
+ failed = true
+ }
+ if want, got := c&(d>>s), andshiftRAreg_ssa(c, d, s); got != want {
+ println("andshiftRAreg_ssa(10, -42, 3) =", got, " want ", want)
+ failed = true
+ }
+ if want, got := c|d>>s, orshiftRAreg_ssa(c, d, s); got != want {
+ println("orshiftRAreg_ssa(10, -42, 3) =", got, " want ", want)
+ failed = true
+ }
+ if want, got := c^d>>s, xorshiftRAreg_ssa(c, d, s); got != want {
+ println("xorshiftRAreg_ssa(10, -42, 3) =", got, " want ", want)
+ failed = true
+ }
+ if want, got := c&^(d>>s), bicshiftRAreg_ssa(c, d, s); got != want {
+ println("bicshiftRAreg_ssa(10, -42, 3) =", got, " want ", want)
+ failed = true
+ }
+ if want, got := ^(d >> s), notshiftRAreg_ssa(d, s); got != want {
+ println("notshiftRAreg_ssa(-42, 3) =", got, " want ", want)
+ failed = true
+ }
+}
+
+var failed = false
+
+func main() {
+
+ test64BitConstMult()
+ test64BitConstAdd()
+ testRegallocCVSpill()
+ testSubqToNegq()
+ testBitwiseLogic()
+ testOcom()
+ testLrot()
+ testShiftCX()
+ testSubConst()
+ testOverflowConstShift()
+ testArithConstShift()
+ testArithRshConst()
+ testLargeConst()
+ testLoadCombine()
+ testLoadSymCombine()
+ testShiftRemoval()
+ testShiftedOps()
+
+ if failed {
+ panic("failed")
+ }
+}
diff --git a/src/cmd/compile/internal/gc/testdata/arithBoundary_ssa.go b/src/cmd/compile/internal/gc/testdata/arithBoundary.go
similarity index 100%
rename from src/cmd/compile/internal/gc/testdata/arithBoundary_ssa.go
rename to src/cmd/compile/internal/gc/testdata/arithBoundary.go
diff --git a/src/cmd/compile/internal/gc/testdata/arithConst_ssa.go b/src/cmd/compile/internal/gc/testdata/arithConst.go
similarity index 100%
rename from src/cmd/compile/internal/gc/testdata/arithConst_ssa.go
rename to src/cmd/compile/internal/gc/testdata/arithConst.go
diff --git a/src/cmd/compile/internal/gc/testdata/arith_ssa.go b/src/cmd/compile/internal/gc/testdata/arith_ssa.go
deleted file mode 100644
index 7c82bbd..0000000
--- a/src/cmd/compile/internal/gc/testdata/arith_ssa.go
+++ /dev/null
@@ -1,580 +0,0 @@
-// run
-
-// Copyright 2015 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// Tests arithmetic expressions
-
-package main
-
-import "fmt"
-
-const (
- y = 0x0fffFFFF
-)
-
-//go:noinline
-func lshNop1(x uint64) uint64 {
- // two outer shifts should be removed
- return (((x << 5) >> 2) << 2)
-}
-
-//go:noinline
-func lshNop2(x uint64) uint64 {
- return (((x << 5) >> 2) << 3)
-}
-
-//go:noinline
-func lshNop3(x uint64) uint64 {
- return (((x << 5) >> 2) << 6)
-}
-
-//go:noinline
-func lshNotNop(x uint64) uint64 {
- // outer shift can't be removed
- return (((x << 5) >> 2) << 1)
-}
-
-//go:noinline
-func rshNop1(x uint64) uint64 {
- return (((x >> 5) << 2) >> 2)
-}
-
-//go:noinline
-func rshNop2(x uint64) uint64 {
- return (((x >> 5) << 2) >> 3)
-}
-
-//go:noinline
-func rshNop3(x uint64) uint64 {
- return (((x >> 5) << 2) >> 6)
-}
-
-//go:noinline
-func rshNotNop(x uint64) uint64 {
- return (((x >> 5) << 2) >> 1)
-}
-
-func testShiftRemoval() {
- allSet := ^uint64(0)
- if want, got := uint64(0x7ffffffffffffff), rshNop1(allSet); want != got {
- println("testShiftRemoval rshNop1 failed, wanted", want, "got", got)
- failed = true
- }
- if want, got := uint64(0x3ffffffffffffff), rshNop2(allSet); want != got {
- println("testShiftRemoval rshNop2 failed, wanted", want, "got", got)
- failed = true
- }
- if want, got := uint64(0x7fffffffffffff), rshNop3(allSet); want != got {
- println("testShiftRemoval rshNop3 failed, wanted", want, "got", got)
- failed = true
- }
- if want, got := uint64(0xffffffffffffffe), rshNotNop(allSet); want != got {
- println("testShiftRemoval rshNotNop failed, wanted", want, "got", got)
- failed = true
- }
- if want, got := uint64(0xffffffffffffffe0), lshNop1(allSet); want != got {
- println("testShiftRemoval lshNop1 failed, wanted", want, "got", got)
- failed = true
- }
- if want, got := uint64(0xffffffffffffffc0), lshNop2(allSet); want != got {
- println("testShiftRemoval lshNop2 failed, wanted", want, "got", got)
- failed = true
- }
- if want, got := uint64(0xfffffffffffffe00), lshNop3(allSet); want != got {
- println("testShiftRemoval lshNop3 failed, wanted", want, "got", got)
- failed = true
- }
- if want, got := uint64(0x7ffffffffffffff0), lshNotNop(allSet); want != got {
- println("testShiftRemoval lshNotNop failed, wanted", want, "got", got)
- failed = true
- }
-}
-
-//go:noinline
-func parseLE64(b []byte) uint64 {
- // skip the first two bytes, and parse the remaining 8 as a uint64
- return uint64(b[2]) | uint64(b[3])<<8 | uint64(b[4])<<16 | uint64(b[5])<<24 |
- uint64(b[6])<<32 | uint64(b[7])<<40 | uint64(b[8])<<48 | uint64(b[9])<<56
-}
-
-//go:noinline
-func parseLE32(b []byte) uint32 {
- return uint32(b[2]) | uint32(b[3])<<8 | uint32(b[4])<<16 | uint32(b[5])<<24
-}
-
-//go:noinline
-func parseLE16(b []byte) uint16 {
- return uint16(b[2]) | uint16(b[3])<<8
-}
-
-// testLoadCombine tests for issue #14694 where load combining didn't respect the pointer offset.
-func testLoadCombine() {
- testData := []byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09}
- if want, got := uint64(0x0908070605040302), parseLE64(testData); want != got {
- println("testLoadCombine failed, wanted", want, "got", got)
- failed = true
- }
- if want, got := uint32(0x05040302), parseLE32(testData); want != got {
- println("testLoadCombine failed, wanted", want, "got", got)
- failed = true
- }
- if want, got := uint16(0x0302), parseLE16(testData); want != got {
- println("testLoadCombine failed, wanted", want, "got", got)
- failed = true
- }
-}
-
-var loadSymData = [...]byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}
-
-func testLoadSymCombine() {
- w2 := uint16(0x0201)
- g2 := uint16(loadSymData[0]) | uint16(loadSymData[1])<<8
- if g2 != w2 {
- println("testLoadSymCombine failed, wanted", w2, "got", g2)
- failed = true
- }
- w4 := uint32(0x04030201)
- g4 := uint32(loadSymData[0]) | uint32(loadSymData[1])<<8 |
- uint32(loadSymData[2])<<16 | uint32(loadSymData[3])<<24
- if g4 != w4 {
- println("testLoadSymCombine failed, wanted", w4, "got", g4)
- failed = true
- }
- w8 := uint64(0x0807060504030201)
- g8 := uint64(loadSymData[0]) | uint64(loadSymData[1])<<8 |
- uint64(loadSymData[2])<<16 | uint64(loadSymData[3])<<24 |
- uint64(loadSymData[4])<<32 | uint64(loadSymData[5])<<40 |
- uint64(loadSymData[6])<<48 | uint64(loadSymData[7])<<56
- if g8 != w8 {
- println("testLoadSymCombine failed, wanted", w8, "got", g8)
- failed = true
- }
-}
-
-//go:noinline
-func invalidAdd_ssa(x uint32) uint32 {
- return x + y + y + y + y + y + y + y + y + y + y + y + y + y + y + y + y + y
-}
-
-//go:noinline
-func invalidSub_ssa(x uint32) uint32 {
- return x - y - y - y - y - y - y - y - y - y - y - y - y - y - y - y - y - y
-}
-
-//go:noinline
-func invalidMul_ssa(x uint32) uint32 {
- return x * y * y * y * y * y * y * y * y * y * y * y * y * y * y * y * y * y
-}
-
-// testLargeConst tests a situation where larger than 32 bit consts were passed to ADDL
-// causing an invalid instruction error.
-func testLargeConst() {
- if want, got := uint32(268435440), invalidAdd_ssa(1); want != got {
- println("testLargeConst add failed, wanted", want, "got", got)
- failed = true
- }
- if want, got := uint32(4026531858), invalidSub_ssa(1); want != got {
- println("testLargeConst sub failed, wanted", want, "got", got)
- failed = true
- }
- if want, got := uint32(268435455), invalidMul_ssa(1); want != got {
- println("testLargeConst mul failed, wanted", want, "got", got)
- failed = true
- }
-}
-
-// testArithRshConst ensures that "const >> const" right shifts correctly perform
-// sign extension on the lhs constant
-func testArithRshConst() {
- wantu := uint64(0x4000000000000000)
- if got := arithRshuConst_ssa(); got != wantu {
- println("arithRshuConst failed, wanted", wantu, "got", got)
- failed = true
- }
-
- wants := int64(-0x4000000000000000)
- if got := arithRshConst_ssa(); got != wants {
- println("arithRshuConst failed, wanted", wants, "got", got)
- failed = true
- }
-}
-
-//go:noinline
-func arithRshuConst_ssa() uint64 {
- y := uint64(0x8000000000000001)
- z := uint64(1)
- return uint64(y >> z)
-}
-
-//go:noinline
-func arithRshConst_ssa() int64 {
- y := int64(-0x8000000000000000)
- z := uint64(1)
- return int64(y >> z)
-}
-
-//go:noinline
-func arithConstShift_ssa(x int64) int64 {
- return x >> 100
-}
-
-// testArithConstShift tests that right shift by large constants preserve
-// the sign of the input.
-func testArithConstShift() {
- want := int64(-1)
- if got := arithConstShift_ssa(-1); want != got {
- println("arithConstShift_ssa(-1) failed, wanted", want, "got", got)
- failed = true
- }
- want = 0
- if got := arithConstShift_ssa(1); want != got {
- println("arithConstShift_ssa(1) failed, wanted", want, "got", got)
- failed = true
- }
-}
-
-// overflowConstShift_ssa verifes that constant folding for shift
-// doesn't wrap (i.e. x << MAX_INT << 1 doesn't get folded to x << 0).
-//go:noinline
-func overflowConstShift64_ssa(x int64) int64 {
- return x << uint64(0xffffffffffffffff) << uint64(1)
-}
-
-//go:noinline
-func overflowConstShift32_ssa(x int64) int32 {
- return int32(x) << uint32(0xffffffff) << uint32(1)
-}
-
-//go:noinline
-func overflowConstShift16_ssa(x int64) int16 {
- return int16(x) << uint16(0xffff) << uint16(1)
-}
-
-//go:noinline
-func overflowConstShift8_ssa(x int64) int8 {
- return int8(x) << uint8(0xff) << uint8(1)
-}
-
-func testOverflowConstShift() {
- want := int64(0)
- for x := int64(-127); x < int64(127); x++ {
- got := overflowConstShift64_ssa(x)
- if want != got {
- fmt.Printf("overflowShift64 failed, wanted %d got %d\n", want, got)
- }
- got = int64(overflowConstShift32_ssa(x))
- if want != got {
- fmt.Printf("overflowShift32 failed, wanted %d got %d\n", want, got)
- }
- got = int64(overflowConstShift16_ssa(x))
- if want != got {
- fmt.Printf("overflowShift16 failed, wanted %d got %d\n", want, got)
- }
- got = int64(overflowConstShift8_ssa(x))
- if want != got {
- fmt.Printf("overflowShift8 failed, wanted %d got %d\n", want, got)
- }
- }
-}
-
-// test64BitConstMult tests that rewrite rules don't fold 64 bit constants
-// into multiply instructions.
-func test64BitConstMult() {
- want := int64(103079215109)
- if got := test64BitConstMult_ssa(1, 2); want != got {
- println("test64BitConstMult failed, wanted", want, "got", got)
- failed = true
- }
-}
-
-//go:noinline
-func test64BitConstMult_ssa(a, b int64) int64 {
- return 34359738369*a + b*34359738370
-}
-
-// test64BitConstAdd tests that rewrite rules don't fold 64 bit constants
-// into add instructions.
-func test64BitConstAdd() {
- want := int64(3567671782835376650)
- if got := test64BitConstAdd_ssa(1, 2); want != got {
- println("test64BitConstAdd failed, wanted", want, "got", got)
- failed = true
- }
-}
-
-//go:noinline
-func test64BitConstAdd_ssa(a, b int64) int64 {
- return a + 575815584948629622 + b + 2991856197886747025
-}
-
-// testRegallocCVSpill tests that regalloc spills a value whose last use is the
-// current value.
-func testRegallocCVSpill() {
- want := int8(-9)
- if got := testRegallocCVSpill_ssa(1, 2, 3, 4); want != got {
- println("testRegallocCVSpill failed, wanted", want, "got", got)
- failed = true
- }
-}
-
-//go:noinline
-func testRegallocCVSpill_ssa(a, b, c, d int8) int8 {
- return a + -32 + b + 63*c*-87*d
-}
-
-func testBitwiseLogic() {
- a, b := uint32(57623283), uint32(1314713839)
- if want, got := uint32(38551779), testBitwiseAnd_ssa(a, b); want != got {
- println("testBitwiseAnd failed, wanted", want, "got", got)
- failed = true
- }
- if want, got := uint32(1333785343), testBitwiseOr_ssa(a, b); want != got {
- println("testBitwiseOr failed, wanted", want, "got", got)
- failed = true
- }
- if want, got := uint32(1295233564), testBitwiseXor_ssa(a, b); want != got {
- println("testBitwiseXor failed, wanted", want, "got", got)
- failed = true
- }
- if want, got := int32(832), testBitwiseLsh_ssa(13, 4, 2); want != got {
- println("testBitwiseLsh failed, wanted", want, "got", got)
- failed = true
- }
- if want, got := int32(0), testBitwiseLsh_ssa(13, 25, 15); want != got {
- println("testBitwiseLsh failed, wanted", want, "got", got)
- failed = true
- }
- if want, got := int32(0), testBitwiseLsh_ssa(-13, 25, 15); want != got {
- println("testBitwiseLsh failed, wanted", want, "got", got)
- failed = true
- }
- if want, got := int32(-13), testBitwiseRsh_ssa(-832, 4, 2); want != got {
- println("testBitwiseRsh failed, wanted", want, "got", got)
- failed = true
- }
- if want, got := int32(0), testBitwiseRsh_ssa(13, 25, 15); want != got {
- println("testBitwiseRsh failed, wanted", want, "got", got)
- failed = true
- }
- if want, got := int32(-1), testBitwiseRsh_ssa(-13, 25, 15); want != got {
- println("testBitwiseRsh failed, wanted", want, "got", got)
- failed = true
- }
- if want, got := uint32(0x3ffffff), testBitwiseRshU_ssa(0xffffffff, 4, 2); want != got {
- println("testBitwiseRshU failed, wanted", want, "got", got)
- failed = true
- }
- if want, got := uint32(0), testBitwiseRshU_ssa(13, 25, 15); want != got {
- println("testBitwiseRshU failed, wanted", want, "got", got)
- failed = true
- }
- if want, got := uint32(0), testBitwiseRshU_ssa(0x8aaaaaaa, 25, 15); want != got {
- println("testBitwiseRshU failed, wanted", want, "got", got)
- failed = true
- }
-}
-
-//go:noinline
-func testBitwiseAnd_ssa(a, b uint32) uint32 {
- return a & b
-}
-
-//go:noinline
-func testBitwiseOr_ssa(a, b uint32) uint32 {
- return a | b
-}
-
-//go:noinline
-func testBitwiseXor_ssa(a, b uint32) uint32 {
- return a ^ b
-}
-
-//go:noinline
-func testBitwiseLsh_ssa(a int32, b, c uint32) int32 {
- return a << b << c
-}
-
-//go:noinline
-func testBitwiseRsh_ssa(a int32, b, c uint32) int32 {
- return a >> b >> c
-}
-
-//go:noinline
-func testBitwiseRshU_ssa(a uint32, b, c uint32) uint32 {
- return a >> b >> c
-}
-
-//go:noinline
-func testShiftCX_ssa() int {
- v1 := uint8(3)
- v4 := (v1 * v1) ^ v1 | v1 - v1 - v1&v1 ^ uint8(3+2) + v1*1>>0 - v1 | 1 | v1<<(2*3|0-0*0^1)
- v5 := v4>>(3-0-uint(3)) | v1 | v1 + v1 ^ v4<<(0+1|3&1)<<(uint64(1)<<0*2*0<<0) ^ v1
- v6 := v5 ^ (v1+v1)*v1 | v1 | v1*v1>>(v1&v1)>>(uint(1)<<0*uint(3)>>1)*v1<<2*v1<<v1 - v1>>2 | (v4 - v1) ^ v1 + v1 ^ v1>>1 | v1 + v1 - v1 ^ v1
- v7 := v6 & v5 << 0
- v1++
- v11 := 2&1 ^ 0 + 3 | int(0^0)<<1>>(1*0*3) ^ 0*0 ^ 3&0*3&3 ^ 3*3 ^ 1 ^ int(2)<<(2*3) + 2 | 2 | 2 ^ 2 + 1 | 3 | 0 ^ int(1)>>1 ^ 2 // int
- v7--
- return int(uint64(2*1)<<(3-2)<<uint(3>>v7)-2)&v11 | v11 - int(2)<<0>>(2-1)*(v11*0&v11<<1<<(uint8(2)+v4))
-}
-
-func testShiftCX() {
- want := 141
- if got := testShiftCX_ssa(); want != got {
- println("testShiftCX failed, wanted", want, "got", got)
- failed = true
- }
-}
-
-// testSubqToNegq ensures that the SUBQ -> NEGQ translation works correctly.
-func testSubqToNegq() {
- want := int64(-318294940372190156)
- if got := testSubqToNegq_ssa(1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2); want != got {
- println("testSubqToNegq failed, wanted", want, "got", got)
- failed = true
- }
-}
-
-//go:noinline
-func testSubqToNegq_ssa(a, b, c, d, e, f, g, h, i, j, k int64) int64 {
- return a + 8207351403619448057 - b - 1779494519303207690 + c*8810076340510052032*d - 4465874067674546219 - e*4361839741470334295 - f + 8688847565426072650*g*8065564729145417479
-}
-
-func testOcom() {
- want1, want2 := int32(0x55555555), int32(-0x55555556)
- if got1, got2 := testOcom_ssa(0x55555555, 0x55555555); want1 != got1 || want2 != got2 {
- println("testSubqToNegq failed, wanted", want1, "and", want2,
- "got", got1, "and", got2)
- failed = true
- }
-}
-
-//go:noinline
-func testOcom_ssa(a, b int32) (int32, int32) {
- return ^^^^a, ^^^^^b
-}
-
-func lrot1_ssa(w uint8, x uint16, y uint32, z uint64) (a uint8, b uint16, c uint32, d uint64) {
- a = (w << 5) | (w >> 3)
- b = (x << 13) | (x >> 3)
- c = (y << 29) | (y >> 3)
- d = (z << 61) | (z >> 3)
- return
-}
-
-//go:noinline
-func lrot2_ssa(w, n uint32) uint32 {
- // Want to be sure that a "rotate by 32" which
- // is really 0 | (w >> 0) == w
- // is correctly compiled.
- return (w << n) | (w >> (32 - n))
-}
-
-//go:noinline
-func lrot3_ssa(w uint32) uint32 {
- // Want to be sure that a "rotate by 32" which
- // is really 0 | (w >> 0) == w
- // is correctly compiled.
- return (w << 32) | (w >> (32 - 32))
-}
-
-func testLrot() {
- wantA, wantB, wantC, wantD := uint8(0xe1), uint16(0xe001),
- uint32(0xe0000001), uint64(0xe000000000000001)
- a, b, c, d := lrot1_ssa(0xf, 0xf, 0xf, 0xf)
- if a != wantA || b != wantB || c != wantC || d != wantD {
- println("lrot1_ssa(0xf, 0xf, 0xf, 0xf)=",
- wantA, wantB, wantC, wantD, ", got", a, b, c, d)
- failed = true
- }
- x := lrot2_ssa(0xb0000001, 32)
- wantX := uint32(0xb0000001)
- if x != wantX {
- println("lrot2_ssa(0xb0000001, 32)=",
- wantX, ", got", x)
- failed = true
- }
- x = lrot3_ssa(0xb0000001)
- if x != wantX {
- println("lrot3_ssa(0xb0000001)=",
- wantX, ", got", x)
- failed = true
- }
-
-}
-
-//go:noinline
-func sub1_ssa() uint64 {
- v1 := uint64(3) // uint64
- return v1*v1 - (v1&v1)&v1
-}
-
-//go:noinline
-func sub2_ssa() uint8 {
- v1 := uint8(0)
- v3 := v1 + v1 + v1 ^ v1 | 3 + v1 ^ v1 | v1 ^ v1
- v1-- // dev.ssa doesn't see this one
- return v1 ^ v1*v1 - v3
-}
-
-func testSubConst() {
- x1 := sub1_ssa()
- want1 := uint64(6)
- if x1 != want1 {
- println("sub1_ssa()=", want1, ", got", x1)
- failed = true
- }
- x2 := sub2_ssa()
- want2 := uint8(251)
- if x2 != want2 {
- println("sub2_ssa()=", want2, ", got", x2)
- failed = true
- }
-}
-
-//go:noinline
-func orPhi_ssa(a bool, x int) int {
- v := 0
- if a {
- v = -1
- } else {
- v = -1
- }
- return x | v
-}
-
-func testOrPhi() {
- if want, got := -1, orPhi_ssa(true, 4); got != want {
- println("orPhi_ssa(true, 4)=", got, " want ", want)
- }
- if want, got := -1, orPhi_ssa(false, 0); got != want {
- println("orPhi_ssa(false, 0)=", got, " want ", want)
- }
-}
-
-var failed = false
-
-func main() {
-
- test64BitConstMult()
- test64BitConstAdd()
- testRegallocCVSpill()
- testSubqToNegq()
- testBitwiseLogic()
- testOcom()
- testLrot()
- testShiftCX()
- testSubConst()
- testOverflowConstShift()
- testArithConstShift()
- testArithRshConst()
- testLargeConst()
- testLoadCombine()
- testLoadSymCombine()
- testShiftRemoval()
-
- if failed {
- panic("failed")
- }
-}
diff --git a/src/cmd/compile/internal/gc/testdata/array_ssa.go b/src/cmd/compile/internal/gc/testdata/array.go
similarity index 100%
rename from src/cmd/compile/internal/gc/testdata/array_ssa.go
rename to src/cmd/compile/internal/gc/testdata/array.go
diff --git a/src/cmd/compile/internal/gc/testdata/assert_ssa.go b/src/cmd/compile/internal/gc/testdata/assert.go
similarity index 100%
rename from src/cmd/compile/internal/gc/testdata/assert_ssa.go
rename to src/cmd/compile/internal/gc/testdata/assert.go
diff --git a/src/cmd/compile/internal/gc/testdata/break_ssa.go b/src/cmd/compile/internal/gc/testdata/break.go
similarity index 100%
rename from src/cmd/compile/internal/gc/testdata/break_ssa.go
rename to src/cmd/compile/internal/gc/testdata/break.go
diff --git a/src/cmd/compile/internal/gc/testdata/chan_ssa.go b/src/cmd/compile/internal/gc/testdata/chan.go
similarity index 100%
rename from src/cmd/compile/internal/gc/testdata/chan_ssa.go
rename to src/cmd/compile/internal/gc/testdata/chan.go
diff --git a/src/cmd/compile/internal/gc/testdata/closure_ssa.go b/src/cmd/compile/internal/gc/testdata/closure.go
similarity index 100%
rename from src/cmd/compile/internal/gc/testdata/closure_ssa.go
rename to src/cmd/compile/internal/gc/testdata/closure.go
diff --git a/src/cmd/compile/internal/gc/testdata/cmp_ssa.go b/src/cmd/compile/internal/gc/testdata/cmp.go
similarity index 100%
rename from src/cmd/compile/internal/gc/testdata/cmp_ssa.go
rename to src/cmd/compile/internal/gc/testdata/cmp.go
diff --git a/src/cmd/compile/internal/gc/testdata/compound_ssa.go b/src/cmd/compile/internal/gc/testdata/compound.go
similarity index 100%
rename from src/cmd/compile/internal/gc/testdata/compound_ssa.go
rename to src/cmd/compile/internal/gc/testdata/compound.go
diff --git a/src/cmd/compile/internal/gc/testdata/copy_ssa.go b/src/cmd/compile/internal/gc/testdata/copy.go
similarity index 100%
rename from src/cmd/compile/internal/gc/testdata/copy_ssa.go
rename to src/cmd/compile/internal/gc/testdata/copy.go
diff --git a/src/cmd/compile/internal/gc/testdata/ctl_ssa.go b/src/cmd/compile/internal/gc/testdata/ctl.go
similarity index 100%
rename from src/cmd/compile/internal/gc/testdata/ctl_ssa.go
rename to src/cmd/compile/internal/gc/testdata/ctl.go
diff --git a/src/cmd/compile/internal/gc/testdata/deferNoReturn_ssa.go b/src/cmd/compile/internal/gc/testdata/deferNoReturn.go
similarity index 100%
rename from src/cmd/compile/internal/gc/testdata/deferNoReturn_ssa.go
rename to src/cmd/compile/internal/gc/testdata/deferNoReturn.go
diff --git a/src/cmd/compile/internal/gc/testdata/divbyzero_ssa.go b/src/cmd/compile/internal/gc/testdata/divbyzero.go
similarity index 100%
rename from src/cmd/compile/internal/gc/testdata/divbyzero_ssa.go
rename to src/cmd/compile/internal/gc/testdata/divbyzero.go
diff --git a/src/cmd/compile/internal/gc/testdata/fp_ssa.go b/src/cmd/compile/internal/gc/testdata/fp.go
similarity index 100%
rename from src/cmd/compile/internal/gc/testdata/fp_ssa.go
rename to src/cmd/compile/internal/gc/testdata/fp.go
diff --git a/src/cmd/compile/internal/gc/testdata/gen/arithBoundaryGen.go b/src/cmd/compile/internal/gc/testdata/gen/arithBoundaryGen.go
index be0aad5..866431e 100644
--- a/src/cmd/compile/internal/gc/testdata/gen/arithBoundaryGen.go
+++ b/src/cmd/compile/internal/gc/testdata/gen/arithBoundaryGen.go
@@ -5,7 +5,7 @@
// This program generates a test to verify that the standard arithmetic
// operators properly handle some special cases. The test file should be
// generated with a known working version of go.
-// launch with `go run arithBoundaryGen.go` a file called arithBoundary_ssa.go
+// launch with `go run arithBoundaryGen.go` a file called arithBoundary.go
// will be written into the parent directory containing the tests
package main
@@ -207,7 +207,7 @@ func main() {
}
// write to file
- err = ioutil.WriteFile("../arithBoundary_ssa.go", src, 0666)
+ err = ioutil.WriteFile("../arithBoundary.go", src, 0666)
if err != nil {
log.Fatalf("can't write output: %v\n", err)
}
diff --git a/src/cmd/compile/internal/gc/testdata/gen/arithConstGen.go b/src/cmd/compile/internal/gc/testdata/gen/arithConstGen.go
index 5559050..97434ea 100644
--- a/src/cmd/compile/internal/gc/testdata/gen/arithConstGen.go
+++ b/src/cmd/compile/internal/gc/testdata/gen/arithConstGen.go
@@ -5,7 +5,7 @@
// This program generates a test to verify that the standard arithmetic
// operators properly handle const cases. The test file should be
// generated with a known working version of go.
-// launch with `go run arithConstGen.go` a file called arithConst_ssa.go
+// launch with `go run arithConstGen.go` a file called arithConst.go
// will be written into the parent directory containing the tests
package main
@@ -295,7 +295,7 @@ func main() {
}
// write to file
- err = ioutil.WriteFile("../arithConst_ssa.go", src, 0666)
+ err = ioutil.WriteFile("../arithConst.go", src, 0666)
if err != nil {
log.Fatalf("can't write output: %v\n", err)
}
diff --git a/src/cmd/compile/internal/gc/testdata/gen/constFoldGen.go b/src/cmd/compile/internal/gc/testdata/gen/constFoldGen.go
index 28cdcc3..f266749 100644
--- a/src/cmd/compile/internal/gc/testdata/gen/constFoldGen.go
+++ b/src/cmd/compile/internal/gc/testdata/gen/constFoldGen.go
@@ -144,7 +144,7 @@ func main() {
fmt.Fprintf(w, "\tr = x %s y\n", o.symbol)
want := ansU(c, d, s.name, o.symbol)
fmt.Fprintf(w, "\tif r != %s {\n", want)
- fmt.Fprintf(w, "\t\tt.Errorf(\"%d %s %d = %%d, want %s\", r)\n", c, o.symbol, d, want)
+ fmt.Fprintf(w, "\t\tt.Errorf(\"%d %%s %d = %%d, want %s\", %q, r)\n", c, d, want, o.symbol)
fmt.Fprintf(w, "\t}\n")
}
}
@@ -159,7 +159,7 @@ func main() {
fmt.Fprintf(w, "\tr = x %s y\n", o.symbol)
want := ansS(c, d, s.name, o.symbol)
fmt.Fprintf(w, "\tif r != %s {\n", want)
- fmt.Fprintf(w, "\t\tt.Errorf(\"%d %s %d = %%d, want %s\", r)\n", c, o.symbol, d, want)
+ fmt.Fprintf(w, "\t\tt.Errorf(\"%d %%s %d = %%d, want %s\", %q, r)\n", c, d, want, o.symbol)
fmt.Fprintf(w, "\t}\n")
}
}
@@ -188,7 +188,7 @@ func main() {
fmt.Fprintf(w, "\tr = x %s y\n", o.symbol)
want := ansU(c, d, ls.name, o.symbol)
fmt.Fprintf(w, "\tif r != %s {\n", want)
- fmt.Fprintf(w, "\t\tt.Errorf(\"%d %s %d = %%d, want %s\", r)\n", c, o.symbol, d, want)
+ fmt.Fprintf(w, "\t\tt.Errorf(\"%d %%s %d = %%d, want %s\", %q, r)\n", c, d, want, o.symbol)
fmt.Fprintf(w, "\t}\n")
}
}
@@ -200,7 +200,7 @@ func main() {
fmt.Fprintf(w, "\tr = x %s y\n", o.symbol)
want := ansS(c, int64(d), ls.name, o.symbol)
fmt.Fprintf(w, "\tif r != %s {\n", want)
- fmt.Fprintf(w, "\t\tt.Errorf(\"%d %s %d = %%d, want %s\", r)\n", c, o.symbol, d, want)
+ fmt.Fprintf(w, "\t\tt.Errorf(\"%d %%s %d = %%d, want %s\", %q, r)\n", c, d, want, o.symbol)
fmt.Fprintf(w, "\t}\n")
}
}
diff --git a/src/cmd/compile/internal/gc/testdata/gen/copyGen.go b/src/cmd/compile/internal/gc/testdata/gen/copyGen.go
index a699fac..2d2240c 100644
--- a/src/cmd/compile/internal/gc/testdata/gen/copyGen.go
+++ b/src/cmd/compile/internal/gc/testdata/gen/copyGen.go
@@ -15,7 +15,7 @@ import (
// This program generates tests to verify that copying operations
// copy the data they are supposed to and clobber no adjacent values.
-// run as `go run copyGen.go`. A file called copy_ssa.go
+// run as `go run copyGen.go`. A file called copy.go
// will be written into the parent directory containing the tests.
var sizes = [...]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 15, 16, 17, 23, 24, 25, 31, 32, 33, 63, 64, 65, 1023, 1024, 1025, 1024 + 7, 1024 + 8, 1024 + 9, 1024 + 15, 1024 + 16, 1024 + 17}
@@ -86,7 +86,7 @@ func main() {
}
// write to file
- err = ioutil.WriteFile("../copy_ssa.go", src, 0666)
+ err = ioutil.WriteFile("../copy.go", src, 0666)
if err != nil {
log.Fatalf("can't write output: %v\n", err)
}
diff --git a/src/cmd/compile/internal/gc/testdata/gen/zeroGen.go b/src/cmd/compile/internal/gc/testdata/gen/zeroGen.go
index 90e8029..6482f07 100644
--- a/src/cmd/compile/internal/gc/testdata/gen/zeroGen.go
+++ b/src/cmd/compile/internal/gc/testdata/gen/zeroGen.go
@@ -15,7 +15,7 @@ import (
// This program generates tests to verify that zeroing operations
// zero the data they are supposed to and clobber no adjacent values.
-// run as `go run zeroGen.go`. A file called zero_ssa.go
+// run as `go run zeroGen.go`. A file called zero.go
// will be written into the parent directory containing the tests.
var sizes = [...]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 15, 16, 17, 23, 24, 25, 31, 32, 33, 63, 64, 65, 1023, 1024, 1025}
@@ -81,7 +81,7 @@ func main() {
}
// write to file
- err = ioutil.WriteFile("../zero_ssa.go", src, 0666)
+ err = ioutil.WriteFile("../zero.go", src, 0666)
if err != nil {
log.Fatalf("can't write output: %v\n", err)
}
diff --git a/src/cmd/compile/internal/gc/testdata/loadstore_ssa.go b/src/cmd/compile/internal/gc/testdata/loadstore.go
similarity index 100%
rename from src/cmd/compile/internal/gc/testdata/loadstore_ssa.go
rename to src/cmd/compile/internal/gc/testdata/loadstore.go
diff --git a/src/cmd/compile/internal/gc/testdata/map_ssa.go b/src/cmd/compile/internal/gc/testdata/map.go
similarity index 100%
rename from src/cmd/compile/internal/gc/testdata/map_ssa.go
rename to src/cmd/compile/internal/gc/testdata/map.go
diff --git a/src/cmd/compile/internal/gc/testdata/phi_ssa.go b/src/cmd/compile/internal/gc/testdata/phi.go
similarity index 100%
rename from src/cmd/compile/internal/gc/testdata/phi_ssa.go
rename to src/cmd/compile/internal/gc/testdata/phi.go
diff --git a/src/cmd/compile/internal/gc/testdata/regalloc_ssa.go b/src/cmd/compile/internal/gc/testdata/regalloc.go
similarity index 100%
rename from src/cmd/compile/internal/gc/testdata/regalloc_ssa.go
rename to src/cmd/compile/internal/gc/testdata/regalloc.go
diff --git a/src/cmd/compile/internal/gc/testdata/short_ssa.go b/src/cmd/compile/internal/gc/testdata/short.go
similarity index 100%
rename from src/cmd/compile/internal/gc/testdata/short_ssa.go
rename to src/cmd/compile/internal/gc/testdata/short.go
diff --git a/src/cmd/compile/internal/gc/testdata/sqrt_const.go b/src/cmd/compile/internal/gc/testdata/sqrt_const.go
new file mode 100644
index 0000000..1f25d9a
--- /dev/null
+++ b/src/cmd/compile/internal/gc/testdata/sqrt_const.go
@@ -0,0 +1,59 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "fmt"
+ "math"
+)
+
+var tests = [...]struct {
+ name string
+ in float64 // used for error messages, not an input
+ got float64
+ want float64
+}{
+ {"sqrt0", 0, math.Sqrt(0), 0},
+ {"sqrt1", 1, math.Sqrt(1), 1},
+ {"sqrt2", 2, math.Sqrt(2), math.Sqrt2},
+ {"sqrt4", 4, math.Sqrt(4), 2},
+ {"sqrt100", 100, math.Sqrt(100), 10},
+ {"sqrt101", 101, math.Sqrt(101), 10.04987562112089},
+}
+
+var nanTests = [...]struct {
+ name string
+ in float64 // used for error messages, not an input
+ got float64
+}{
+ {"sqrtNaN", math.NaN(), math.Sqrt(math.NaN())},
+ {"sqrtNegative", -1, math.Sqrt(-1)},
+ {"sqrtNegInf", math.Inf(-1), math.Sqrt(math.Inf(-1))},
+}
+
+var failed = false
+
+func main() {
+ for _, test := range tests {
+ if test.got != test.want {
+ fmt.Printf("%s: math.Sqrt(%f): got %f, want %f\n", test.name, test.in, test.got, test.want)
+ failed = true
+ }
+ }
+ for _, test := range nanTests {
+ if math.IsNaN(test.got) != true {
+ fmt.Printf("%s: math.Sqrt(%f): got %f, want NaN\n", test.name, test.in, test.got)
+ failed = true
+ }
+ }
+ if got := math.Sqrt(math.Inf(1)); !math.IsInf(got, 1) {
+ fmt.Printf("math.Sqrt(+Inf), got %f, want +Inf\n", got)
+ failed = true
+ }
+
+ if failed {
+ panic("failed")
+ }
+}
diff --git a/src/cmd/compile/internal/gc/testdata/string.go b/src/cmd/compile/internal/gc/testdata/string.go
new file mode 100644
index 0000000..897e874
--- /dev/null
+++ b/src/cmd/compile/internal/gc/testdata/string.go
@@ -0,0 +1,224 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// string_ssa.go tests string operations.
+package main
+
+var failed = false
+
+//go:noinline
+func testStringSlice1_ssa(a string, i, j int) string {
+ return a[i:]
+}
+
+//go:noinline
+func testStringSlice2_ssa(a string, i, j int) string {
+ return a[:j]
+}
+
+//go:noinline
+func testStringSlice12_ssa(a string, i, j int) string {
+ return a[i:j]
+}
+
+func testStringSlice() {
+ tests := [...]struct {
+ fn func(string, int, int) string
+ s string
+ low, high int
+ want string
+ }{
+ // -1 means the value is not used.
+ {testStringSlice1_ssa, "foobar", 0, -1, "foobar"},
+ {testStringSlice1_ssa, "foobar", 3, -1, "bar"},
+ {testStringSlice1_ssa, "foobar", 6, -1, ""},
+ {testStringSlice2_ssa, "foobar", -1, 0, ""},
+ {testStringSlice2_ssa, "foobar", -1, 3, "foo"},
+ {testStringSlice2_ssa, "foobar", -1, 6, "foobar"},
+ {testStringSlice12_ssa, "foobar", 0, 6, "foobar"},
+ {testStringSlice12_ssa, "foobar", 0, 0, ""},
+ {testStringSlice12_ssa, "foobar", 6, 6, ""},
+ {testStringSlice12_ssa, "foobar", 1, 5, "ooba"},
+ {testStringSlice12_ssa, "foobar", 3, 3, ""},
+ {testStringSlice12_ssa, "", 0, 0, ""},
+ }
+
+ for i, t := range tests {
+ if got := t.fn(t.s, t.low, t.high); t.want != got {
+ println("#", i, " ", t.s, "[", t.low, ":", t.high, "] = ", got, " want ", t.want)
+ failed = true
+ }
+ }
+}
+
+type prefix struct {
+ prefix string
+}
+
+func (p *prefix) slice_ssa() {
+ p.prefix = p.prefix[:3]
+}
+
+//go:noinline
+func testStructSlice() {
+ p := &prefix{"prefix"}
+ p.slice_ssa()
+ if "pre" != p.prefix {
+ println("wrong field slice: wanted %s got %s", "pre", p.prefix)
+ failed = true
+ }
+}
+
+func testStringSlicePanic() {
+ defer func() {
+ if r := recover(); r != nil {
+ println("paniced as expected")
+ }
+ }()
+
+ str := "foobar"
+ println("got ", testStringSlice12_ssa(str, 3, 9))
+ println("expected to panic, but didn't")
+ failed = true
+}
+
+const _Accuracy_name = "BelowExactAbove"
+
+var _Accuracy_index = [...]uint8{0, 5, 10, 15}
+
+//go:noinline
+func testSmallIndexType_ssa(i int) string {
+ return _Accuracy_name[_Accuracy_index[i]:_Accuracy_index[i+1]]
+}
+
+func testSmallIndexType() {
+ tests := []struct {
+ i int
+ want string
+ }{
+ {0, "Below"},
+ {1, "Exact"},
+ {2, "Above"},
+ }
+
+ for i, t := range tests {
+ if got := testSmallIndexType_ssa(t.i); got != t.want {
+ println("#", i, "got ", got, ", wanted", t.want)
+ failed = true
+ }
+ }
+}
+
+//go:noinline
+func testInt64Index_ssa(s string, i int64) byte {
+ return s[i]
+}
+
+//go:noinline
+func testInt64Slice_ssa(s string, i, j int64) string {
+ return s[i:j]
+}
+
+func testInt64Index() {
+ tests := []struct {
+ i int64
+ j int64
+ b byte
+ s string
+ }{
+ {0, 5, 'B', "Below"},
+ {5, 10, 'E', "Exact"},
+ {10, 15, 'A', "Above"},
+ }
+
+ str := "BelowExactAbove"
+ for i, t := range tests {
+ if got := testInt64Index_ssa(str, t.i); got != t.b {
+ println("#", i, "got ", got, ", wanted", t.b)
+ failed = true
+ }
+ if got := testInt64Slice_ssa(str, t.i, t.j); got != t.s {
+ println("#", i, "got ", got, ", wanted", t.s)
+ failed = true
+ }
+ }
+}
+
+func testInt64IndexPanic() {
+ defer func() {
+ if r := recover(); r != nil {
+ println("paniced as expected")
+ }
+ }()
+
+ str := "foobar"
+ println("got ", testInt64Index_ssa(str, 1<<32+1))
+ println("expected to panic, but didn't")
+ failed = true
+}
+
+func testInt64SlicePanic() {
+ defer func() {
+ if r := recover(); r != nil {
+ println("paniced as expected")
+ }
+ }()
+
+ str := "foobar"
+ println("got ", testInt64Slice_ssa(str, 1<<32, 1<<32+1))
+ println("expected to panic, but didn't")
+ failed = true
+}
+
+//go:noinline
+func testStringElem_ssa(s string, i int) byte {
+ return s[i]
+}
+
+func testStringElem() {
+ tests := []struct {
+ s string
+ i int
+ n byte
+ }{
+ {"foobar", 3, 98},
+ {"foobar", 0, 102},
+ {"foobar", 5, 114},
+ }
+ for _, t := range tests {
+ if got := testStringElem_ssa(t.s, t.i); got != t.n {
+ print("testStringElem \"", t.s, "\"[", t.i, "]=", got, ", wanted ", t.n, "\n")
+ failed = true
+ }
+ }
+}
+
+//go:noinline
+func testStringElemConst_ssa(i int) byte {
+ s := "foobar"
+ return s[i]
+}
+
+func testStringElemConst() {
+ if got := testStringElemConst_ssa(3); got != 98 {
+ println("testStringElemConst=", got, ", wanted 98")
+ failed = true
+ }
+}
+
+func main() {
+ testStringSlice()
+ testStringSlicePanic()
+ testStructSlice()
+ testSmallIndexType()
+ testStringElem()
+ testStringElemConst()
+ testInt64Index()
+ testInt64IndexPanic()
+ testInt64SlicePanic()
+
+ if failed {
+ panic("failed")
+ }
+}
diff --git a/src/cmd/compile/internal/gc/testdata/string_ssa.go b/src/cmd/compile/internal/gc/testdata/string_ssa.go
deleted file mode 100644
index b47c2f1..0000000
--- a/src/cmd/compile/internal/gc/testdata/string_ssa.go
+++ /dev/null
@@ -1,160 +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.
-
-// string_ssa.go tests string operations.
-package main
-
-var failed = false
-
-//go:noinline
-func testStringSlice1_ssa(a string, i, j int) string {
- return a[i:]
-}
-
-//go:noinline
-func testStringSlice2_ssa(a string, i, j int) string {
- return a[:j]
-}
-
-//go:noinline
-func testStringSlice12_ssa(a string, i, j int) string {
- return a[i:j]
-}
-
-func testStringSlice() {
- tests := [...]struct {
- fn func(string, int, int) string
- s string
- low, high int
- want string
- }{
- // -1 means the value is not used.
- {testStringSlice1_ssa, "foobar", 0, -1, "foobar"},
- {testStringSlice1_ssa, "foobar", 3, -1, "bar"},
- {testStringSlice1_ssa, "foobar", 6, -1, ""},
- {testStringSlice2_ssa, "foobar", -1, 0, ""},
- {testStringSlice2_ssa, "foobar", -1, 3, "foo"},
- {testStringSlice2_ssa, "foobar", -1, 6, "foobar"},
- {testStringSlice12_ssa, "foobar", 0, 6, "foobar"},
- {testStringSlice12_ssa, "foobar", 0, 0, ""},
- {testStringSlice12_ssa, "foobar", 6, 6, ""},
- {testStringSlice12_ssa, "foobar", 1, 5, "ooba"},
- {testStringSlice12_ssa, "foobar", 3, 3, ""},
- {testStringSlice12_ssa, "", 0, 0, ""},
- }
-
- for i, t := range tests {
- if got := t.fn(t.s, t.low, t.high); t.want != got {
- println("#", i, " ", t.s, "[", t.low, ":", t.high, "] = ", got, " want ", t.want)
- failed = true
- }
- }
-}
-
-type prefix struct {
- prefix string
-}
-
-func (p *prefix) slice_ssa() {
- p.prefix = p.prefix[:3]
-}
-
-//go:noinline
-func testStructSlice() {
- p := &prefix{"prefix"}
- p.slice_ssa()
- if "pre" != p.prefix {
- println("wrong field slice: wanted %s got %s", "pre", p.prefix)
- failed = true
- }
-}
-
-func testStringSlicePanic() {
- defer func() {
- if r := recover(); r != nil {
- println("paniced as expected")
- }
- }()
-
- str := "foobar"
- println("got ", testStringSlice12_ssa(str, 3, 9))
- println("expected to panic, but didn't")
- failed = true
-}
-
-const _Accuracy_name = "BelowExactAbove"
-
-var _Accuracy_index = [...]uint8{0, 5, 10, 15}
-
-//go:noinline
-func testSmallIndexType_ssa(i int) string {
- return _Accuracy_name[_Accuracy_index[i]:_Accuracy_index[i+1]]
-}
-
-func testSmallIndexType() {
- tests := []struct {
- i int
- want string
- }{
- {0, "Below"},
- {1, "Exact"},
- {2, "Above"},
- }
-
- for i, t := range tests {
- if got := testSmallIndexType_ssa(t.i); got != t.want {
- println("#", i, "got ", got, ", wanted", t.want)
- failed = true
- }
- }
-}
-
-//go:noinline
-func testStringElem_ssa(s string, i int) byte {
- return s[i]
-}
-
-func testStringElem() {
- tests := []struct {
- s string
- i int
- n byte
- }{
- {"foobar", 3, 98},
- {"foobar", 0, 102},
- {"foobar", 5, 114},
- }
- for _, t := range tests {
- if got := testStringElem_ssa(t.s, t.i); got != t.n {
- print("testStringElem \"", t.s, "\"[", t.i, "]=", got, ", wanted ", t.n, "\n")
- failed = true
- }
- }
-}
-
-//go:noinline
-func testStringElemConst_ssa(i int) byte {
- s := "foobar"
- return s[i]
-}
-
-func testStringElemConst() {
- if got := testStringElemConst_ssa(3); got != 98 {
- println("testStringElemConst=", got, ", wanted 98")
- failed = true
- }
-}
-
-func main() {
- testStringSlice()
- testStringSlicePanic()
- testStructSlice()
- testSmallIndexType()
- testStringElem()
- testStringElemConst()
-
- if failed {
- panic("failed")
- }
-}
diff --git a/src/cmd/compile/internal/gc/testdata/unsafe_ssa.go b/src/cmd/compile/internal/gc/testdata/unsafe.go
similarity index 100%
rename from src/cmd/compile/internal/gc/testdata/unsafe_ssa.go
rename to src/cmd/compile/internal/gc/testdata/unsafe.go
diff --git a/src/cmd/compile/internal/gc/testdata/zero_ssa.go b/src/cmd/compile/internal/gc/testdata/zero.go
similarity index 100%
rename from src/cmd/compile/internal/gc/testdata/zero_ssa.go
rename to src/cmd/compile/internal/gc/testdata/zero.go
diff --git a/src/cmd/compile/internal/gc/timings.go b/src/cmd/compile/internal/gc/timings.go
new file mode 100644
index 0000000..56b3899
--- /dev/null
+++ b/src/cmd/compile/internal/gc/timings.go
@@ -0,0 +1,235 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gc
+
+import (
+ "fmt"
+ "io"
+ "strings"
+ "time"
+)
+
+// Timings collects the execution times of labeled phases
+// which are added trough a sequence of Start/Stop calls.
+// Events may be associated with each phase via AddEvent.
+type Timings struct {
+ list []timestamp
+ events map[int][]*event // lazily allocated
+}
+
+type timestamp struct {
+ time time.Time
+ label string
+ start bool
+}
+
+type event struct {
+ size int64 // count or amount of data processed (allocations, data size, lines, funcs, ...)
+ unit string // unit of size measure (count, MB, lines, funcs, ...)
+}
+
+func (t *Timings) append(labels []string, start bool) {
+ t.list = append(t.list, timestamp{time.Now(), strings.Join(labels, ":"), start})
+}
+
+// Start marks the beginning of a new phase and implicitly stops the previous phase.
+// The phase name is the colon-separated concatenation of the labels.
+func (t *Timings) Start(labels ...string) {
+ t.append(labels, true)
+}
+
+// Stop marks the end of a phase and implicitly starts a new phase.
+// The labels are added to the labels of the ended phase.
+func (t *Timings) Stop(labels ...string) {
+ t.append(labels, false)
+}
+
+// AddEvent associates an event, i.e., a count, or an amount of data,
+// with the most recently started or stopped phase; or the very first
+// phase if Start or Stop hasn't been called yet. The unit specifies
+// the unit of measurement (e.g., MB, lines, no. of funcs, etc.).
+func (t *Timings) AddEvent(size int64, unit string) {
+ m := t.events
+ if m == nil {
+ m = make(map[int][]*event)
+ t.events = m
+ }
+ i := len(t.list)
+ if i > 0 {
+ i--
+ }
+ m[i] = append(m[i], &event{size, unit})
+}
+
+// Write prints the phase times to w.
+// The prefix is printed at the start of each line.
+func (t *Timings) Write(w io.Writer, prefix string) {
+ if len(t.list) > 0 {
+ var lines lines
+
+ // group of phases with shared non-empty label prefix
+ var group struct {
+ label string // label prefix
+ tot time.Duration // accumulated phase time
+ size int // number of phases collected in group
+ }
+
+ // accumulated time between Stop/Start timestamps
+ var unaccounted time.Duration
+
+ // process Start/Stop timestamps
+ pt := &t.list[0] // previous timestamp
+ tot := t.list[len(t.list)-1].time.Sub(pt.time)
+ for i := 1; i < len(t.list); i++ {
+ qt := &t.list[i] // current timestamp
+ dt := qt.time.Sub(pt.time)
+
+ var label string
+ var events []*event
+ if pt.start {
+ // previous phase started
+ label = pt.label
+ events = t.events[i-1]
+ if qt.start {
+ // start implicitly ended previous phase; nothing to do
+ } else {
+ // stop ended previous phase; append stop labels, if any
+ if qt.label != "" {
+ label += ":" + qt.label
+ }
+ // events associated with stop replace prior events
+ if e := t.events[i]; e != nil {
+ events = e
+ }
+ }
+ } else {
+ // previous phase stopped
+ if qt.start {
+ // between a stopped and started phase; unaccounted time
+ unaccounted += dt
+ } else {
+ // previous stop implicitly started current phase
+ label = qt.label
+ events = t.events[i]
+ }
+ }
+ if label != "" {
+ // add phase to existing group, or start a new group
+ l := commonPrefix(group.label, label)
+ if group.size == 1 && l != "" || group.size > 1 && l == group.label {
+ // add to existing group
+ group.label = l
+ group.tot += dt
+ group.size++
+ } else {
+ // start a new group
+ if group.size > 1 {
+ lines.add(prefix+group.label+"subtotal", 1, group.tot, tot, nil)
+ }
+ group.label = label
+ group.tot = dt
+ group.size = 1
+ }
+
+ // write phase
+ lines.add(prefix+label, 1, dt, tot, events)
+ }
+
+ pt = qt
+ }
+
+ if group.size > 1 {
+ lines.add(prefix+group.label+"subtotal", 1, group.tot, tot, nil)
+ }
+
+ if unaccounted != 0 {
+ lines.add(prefix+"unaccounted", 1, unaccounted, tot, nil)
+ }
+
+ lines.add(prefix+"total", 1, tot, tot, nil)
+
+ lines.write(w)
+ }
+}
+
+func commonPrefix(a, b string) string {
+ i := 0
+ for i < len(a) && i < len(b) && a[i] == b[i] {
+ i++
+ }
+ return a[:i]
+}
+
+type lines [][]string
+
+func (lines *lines) add(label string, n int, dt, tot time.Duration, events []*event) {
+ var line []string
+ add := func(format string, args ...interface{}) {
+ line = append(line, fmt.Sprintf(format, args...))
+ }
+
+ add("%s", label)
+ add(" %d", n)
+ add(" %d ns/op", dt)
+ add(" %.2f %%", float64(dt)/float64(tot)*100)
+
+ for _, e := range events {
+ add(" %d", e.size)
+ add(" %s", e.unit)
+ add(" %d", int64(float64(e.size)/dt.Seconds()+0.5))
+ add(" %s/s", e.unit)
+ }
+
+ *lines = append(*lines, line)
+}
+
+func (lines lines) write(w io.Writer) {
+ // determine column widths and contents
+ var widths []int
+ var number []bool
+ for _, line := range lines {
+ for i, col := range line {
+ if i < len(widths) {
+ if len(col) > widths[i] {
+ widths[i] = len(col)
+ }
+ } else {
+ widths = append(widths, len(col))
+ number = append(number, isnumber(col)) // first line determines column contents
+ }
+ }
+ }
+
+ // make column widths a multiple of align for more stable output
+ const align = 1 // set to a value > 1 to enable
+ if align > 1 {
+ for i, w := range widths {
+ w += align - 1
+ widths[i] = w - w%align
+ }
+ }
+
+ // print lines taking column widths and contents into account
+ for _, line := range lines {
+ for i, col := range line {
+ format := "%-*s"
+ if number[i] {
+ format = "%*s" // numbers are right-aligned
+ }
+ fmt.Fprintf(w, format, widths[i], col)
+ }
+ fmt.Fprintln(w)
+ }
+}
+
+func isnumber(s string) bool {
+ for _, ch := range s {
+ if ch <= ' ' {
+ continue // ignore leading whitespace
+ }
+ return '0' <= ch && ch <= '9' || ch == '.' || ch == '-' || ch == '+'
+ }
+ return false
+}
diff --git a/src/cmd/compile/internal/gc/trace.go b/src/cmd/compile/internal/gc/trace.go
new file mode 100644
index 0000000..ed4b5a2
--- /dev/null
+++ b/src/cmd/compile/internal/gc/trace.go
@@ -0,0 +1,27 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build go1.7
+
+package gc
+
+import (
+ "os"
+ tracepkg "runtime/trace"
+)
+
+func init() {
+ traceHandler = traceHandlerGo17
+}
+
+func traceHandlerGo17(traceprofile string) {
+ f, err := os.Create(traceprofile)
+ if err != nil {
+ Fatalf("%v", err)
+ }
+ if err := tracepkg.Start(f); err != nil {
+ Fatalf("%v", err)
+ }
+ atExit(tracepkg.Stop)
+}
diff --git a/src/cmd/compile/internal/gc/type.go b/src/cmd/compile/internal/gc/type.go
index ab13df6..29048f1 100644
--- a/src/cmd/compile/internal/gc/type.go
+++ b/src/cmd/compile/internal/gc/type.go
@@ -143,9 +143,12 @@ type Type struct {
methods Fields
allMethods Fields
- Nod *Node // canonical OTYPE node
+ 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
@@ -153,11 +156,11 @@ type Type struct {
Etype EType // kind of type
Noalg bool // suppress hash and eq algorithm generation
Trecur uint8 // to detect loops
- Printed bool // prevent duplicate export printing
Local bool // created in this file
Deferwidth bool
Broke bool // broken type definition.
Align uint8 // the required alignment of this type, in bytes
+ NotInHeap bool // type cannot be heap allocated
}
// MapType contains Type fields specific to maps.
@@ -412,13 +415,22 @@ func typArray(elem *Type, bound int64) *Type {
}
t := typ(TARRAY)
t.Extra = &ArrayType{Elem: elem, Bound: bound}
+ t.NotInHeap = elem.NotInHeap
return t
}
-// typSlice returns a new slice Type.
+// 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
}
@@ -426,6 +438,7 @@ func typSlice(elem *Type) *Type {
func typDDDArray(elem *Type) *Type {
t := typ(TARRAY)
t.Extra = &ArrayType{Elem: elem, Bound: -1}
+ t.NotInHeap = elem.NotInHeap
return t
}
@@ -447,12 +460,20 @@ func typMap(k, v *Type) *Type {
return t
}
-// typPtr returns a new pointer type pointing to 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
}
@@ -561,18 +582,10 @@ func substAny(t *Type, types *[]*Type) *Type {
params := substAny(t.Params(), types)
results := substAny(t.Results(), types)
if recvs != t.Recvs() || params != t.Params() || results != t.Results() {
- // Note that this code has to be aware of the
- // representation underlying Recvs/Results/Params.
- if recvs == t.Recvs() {
- recvs = recvs.Copy()
- }
- if results == t.Results() {
- results = results.Copy()
- }
t = t.Copy()
- *t.RecvsP() = recvs
- *t.ResultsP() = results
- *t.ParamsP() = params
+ t.FuncType().Receiver = recvs
+ t.FuncType().Results = results
+ t.FuncType().Params = params
}
case TSTRUCT:
@@ -646,9 +659,9 @@ type Iter struct {
s []*Field
}
-// IterFields returns the first field or method in struct or interface type t
+// 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) {
+func iterFields(t *Type) (*Field, Iter) {
return t.Fields().Iter()
}
@@ -677,30 +690,9 @@ func (t *Type) wantEtype(et EType) {
}
}
-func (t *Type) wantEtype2(et1, et2 EType) {
- if t.Etype != et1 && t.Etype != et2 {
- Fatalf("want %v or %v, but have %v", et1, et2, t)
- }
-}
-
-func (t *Type) RecvsP() **Type {
- t.wantEtype(TFUNC)
- return &t.Extra.(*FuncType).Receiver
-}
-
-func (t *Type) ParamsP() **Type {
- t.wantEtype(TFUNC)
- return &t.Extra.(*FuncType).Params
-}
-
-func (t *Type) ResultsP() **Type {
- t.wantEtype(TFUNC)
- return &t.Extra.(*FuncType).Results
-}
-
-func (t *Type) Recvs() *Type { return *t.RecvsP() }
-func (t *Type) Params() *Type { return *t.ParamsP() }
-func (t *Type) Results() *Type { return *t.ResultsP() }
+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 {
@@ -833,6 +825,17 @@ func (t *Type) FieldSlice() []*Field {
// 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)
}
@@ -922,7 +925,7 @@ func (r *Sym) cmpsym(s *Sym) ssa.Cmp {
// 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
+ // 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
@@ -1008,8 +1011,8 @@ func (t *Type) cmp(x *Type) ssa.Cmp {
fallthrough
case TINTER:
- t1, ti := IterFields(t)
- x1, xi := IterFields(x)
+ 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)
@@ -1032,8 +1035,8 @@ func (t *Type) cmp(x *Type) ssa.Cmp {
case TFUNC:
for _, f := range recvsParamsResults {
// Loop over fields in structs, ignoring argument names.
- ta, ia := IterFields(f(t))
- tb, ib := IterFields(f(x))
+ 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)
@@ -1059,7 +1062,7 @@ func (t *Type) cmp(x *Type) ssa.Cmp {
}
default:
- e := fmt.Sprintf("Do not know how to compare %s with %s", t, x)
+ e := fmt.Sprintf("Do not know how to compare %v with %v", t, x)
panic(e)
}
@@ -1076,6 +1079,28 @@ 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:
@@ -1160,7 +1185,7 @@ func (t *Type) ElemType() ssa.Type {
return t.Elem()
}
func (t *Type) PtrTo() ssa.Type {
- return Ptrto(t)
+ return ptrto(t)
}
func (t *Type) NumFields() int {
@@ -1207,6 +1232,7 @@ func (t *Type) ChanDir() ChanDir {
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 {
diff --git a/src/cmd/compile/internal/gc/typecheck.go b/src/cmd/compile/internal/gc/typecheck.go
index c8ee941..23c60fa 100644
--- a/src/cmd/compile/internal/gc/typecheck.go
+++ b/src/cmd/compile/internal/gc/typecheck.go
@@ -35,8 +35,8 @@ func resolve(n *Node) *Node {
if r != nil {
if r.Op != OIOTA {
n = r
- } else if n.Name.Iota >= 0 {
- n = Nodintconst(int64(n.Name.Iota))
+ } else if n.Iota() >= 0 {
+ n = nodintconst(n.Iota())
}
}
}
@@ -157,12 +157,12 @@ func typecheck(n *Node, top int) *Node {
// We can already diagnose variables used as types.
case ONAME:
if top&(Erv|Etype) == Etype {
- Yyerror("%v is not a type", n)
+ yyerror("%v is not a type", n)
}
case OLITERAL:
if top&(Erv|Etype) == Etype {
- Yyerror("%v is not a type", n)
+ yyerror("%v is not a type", n)
break
}
sprint_depchain(&fmt_, typecheck_tcstack, n, n)
@@ -175,7 +175,7 @@ func typecheck(n *Node, top int) *Node {
x := typecheck_tcstack[i]
fmt_ += fmt.Sprintf("\n\t%v %v", x.Line(), x)
}
- Yyerror("typechecking loop involving %v%s", n, fmt_)
+ yyerror("typechecking loop involving %v%s", n, fmt_)
}
lineno = lno
@@ -258,7 +258,7 @@ func typecheck1(n *Node, top int) *Node {
default:
if n.Sym != nil {
if n.Op == ONAME && n.Etype != 0 && top&Ecall == 0 {
- Yyerror("use of builtin %v not in function call", n.Sym)
+ yyerror("use of builtin %v not in function call", n.Sym)
n.Type = nil
return n
}
@@ -305,7 +305,7 @@ OpSwitch:
if top&Easgn == 0 {
// not a write to the variable
if isblank(n) {
- Yyerror("cannot use _ as value")
+ yyerror("cannot use _ as value")
n.Type = nil
return n
}
@@ -313,17 +313,11 @@ OpSwitch:
n.Used = true
}
- if top&Ecall == 0 && isunsafebuiltin(n) {
- Yyerror("%v is not an expression, must be called", n)
- n.Type = nil
- return n
- }
-
ok |= Erv
break OpSwitch
case OPACK:
- Yyerror("use of package %v without selector", n.Sym)
+ yyerror("use of package %v without selector", n.Sym)
n.Type = nil
return n
@@ -340,53 +334,48 @@ OpSwitch:
case OTARRAY:
ok |= Etype
- var t *Type
- l := n.Left
- r := n.Right
- r = typecheck(r, Etype)
+ r := typecheck(n.Right, Etype)
if r.Type == nil {
n.Type = nil
return n
}
- if l == nil {
+ var t *Type
+ if n.Left == nil {
t = typSlice(r.Type)
- } else if l.Op == ODDD {
- t = typDDDArray(r.Type)
- if top&Ecomplit == 0 && n.Diag == 0 {
- t.Broke = true
- n.Diag = 1
- Yyerror("use of [...] array outside of array literal")
+ } else if n.Left.Op == ODDD {
+ if top&Ecomplit == 0 {
+ if !n.Diag {
+ n.Diag = true
+ yyerror("use of [...] array outside of array literal")
+ }
+ n.Type = nil
+ return n
}
+ t = typDDDArray(r.Type)
} else {
- n.Left = typecheck(n.Left, Erv)
+ n.Left = indexlit(typecheck(n.Left, Erv))
l := n.Left
- var v Val
- switch consttype(l) {
- case CTINT, CTRUNE:
- v = l.Val()
-
- case CTFLT:
- v = toint(l.Val())
-
- default:
+ if consttype(l) != CTINT {
if l.Type != nil && l.Type.IsInteger() && l.Op != OLITERAL {
- Yyerror("non-constant array bound %v", l)
+ yyerror("non-constant array bound %v", l)
} else {
- Yyerror("invalid array bound %v", l)
+ yyerror("invalid array bound %v", l)
}
n.Type = nil
return n
}
+ v := l.Val()
if doesoverflow(v, Types[TINT]) {
- Yyerror("array bound is too large")
+ yyerror("array bound is too large")
n.Type = nil
return n
}
+
bound := v.U.(*Mpint).Int64()
if bound < 0 {
- Yyerror("array bound must be non-negative")
+ yyerror("array bound must be non-negative")
n.Type = nil
return n
}
@@ -411,6 +400,12 @@ OpSwitch:
n.Type = nil
return n
}
+ if l.Type.NotInHeap {
+ yyerror("go:notinheap map key not allowed")
+ }
+ if r.Type.NotInHeap {
+ yyerror("go:notinheap map value not allowed")
+ }
n.Op = OTYPE
n.Type = typMap(l.Type, r.Type)
@@ -422,7 +417,7 @@ OpSwitch:
mapqueue = append(mapqueue, mapqueueval{l, n.Lineno})
} else if bad.Etype != TANY {
// no need to queue, key is already bad
- Yyerror("invalid map key type %v", l.Type)
+ yyerror("invalid map key type %v", l.Type)
}
}
n.Left = nil
@@ -436,6 +431,9 @@ OpSwitch:
n.Type = nil
return n
}
+ 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.
n.Op = OTYPE
n.Type = t
@@ -483,14 +481,14 @@ OpSwitch:
if l.Op == OTYPE {
ok |= Etype
n.Op = OTYPE
- n.Type = Ptrto(l.Type)
+ n.Type = ptrto(l.Type)
n.Left = nil
break OpSwitch
}
if !t.IsPtr() {
if top&(Erv|Etop) != 0 {
- Yyerror("invalid indirect of %v", Nconv(n.Left, FmtLong))
+ yyerror("invalid indirect of %L", n.Left)
n.Type = nil
return n
}
@@ -539,7 +537,7 @@ OpSwitch:
return n
}
if n.Implicit && !okforarith[l.Type.Etype] {
- Yyerror("invalid operation: %v (non-numeric type %v)", n, l.Type)
+ yyerror("invalid operation: %v (non-numeric type %v)", n, l.Type)
n.Type = nil
return n
}
@@ -562,14 +560,14 @@ OpSwitch:
n.Right = r
t := r.Type
if !t.IsInteger() || t.IsSigned() {
- Yyerror("invalid operation: %v (shift count type %v, must be unsigned integer)", n, r.Type)
+ yyerror("invalid operation: %v (shift count type %v, must be unsigned integer)", n, r.Type)
n.Type = nil
return n
}
t = l.Type
if t != nil && t.Etype != TIDEAL && !t.IsInteger() {
- Yyerror("invalid operation: %v (shift of type %v)", n, t)
+ yyerror("invalid operation: %v (shift of type %v)", n, t)
n.Type = nil
return n
}
@@ -599,7 +597,7 @@ OpSwitch:
et = TINT
}
var aop Op = OXXX
- if iscmp[n.Op] && t.Etype != TIDEAL && !Eqtype(l.Type, r.Type) {
+ if iscmp[n.Op] && t.Etype != TIDEAL && !eqtype(l.Type, r.Type) {
// comparison is okay as long as one side is
// assignable to the other. convert so they have
// the same type.
@@ -611,14 +609,14 @@ OpSwitch:
aop = assignop(l.Type, r.Type, nil)
if aop != 0 {
if r.Type.IsInterface() && !l.Type.IsInterface() && !l.Type.IsComparable() {
- Yyerror("invalid operation: %v (operator %v not defined on %s)", n, op, typekind(l.Type))
+ yyerror("invalid operation: %v (operator %v not defined on %s)", n, op, typekind(l.Type))
n.Type = nil
return n
}
dowidth(l.Type)
if r.Type.IsInterface() == l.Type.IsInterface() || l.Type.Width >= 1<<16 {
- l = Nod(aop, l, nil)
+ l = nod(aop, l, nil)
l.Type = r.Type
l.Typecheck = 1
n.Left = l
@@ -633,14 +631,14 @@ OpSwitch:
aop = assignop(r.Type, l.Type, nil)
if aop != 0 {
if l.Type.IsInterface() && !r.Type.IsInterface() && !r.Type.IsComparable() {
- Yyerror("invalid operation: %v (operator %v not defined on %s)", n, op, typekind(r.Type))
+ yyerror("invalid operation: %v (operator %v not defined on %s)", n, op, typekind(r.Type))
n.Type = nil
return n
}
dowidth(r.Type)
if r.Type.IsInterface() == l.Type.IsInterface() || r.Type.Width >= 1<<16 {
- r = Nod(aop, r, nil)
+ r = nod(aop, r, nil)
r.Type = l.Type
r.Typecheck = 1
n.Right = r
@@ -654,17 +652,17 @@ OpSwitch:
et = t.Etype
}
- if t.Etype != TIDEAL && !Eqtype(l.Type, r.Type) {
+ if t.Etype != TIDEAL && !eqtype(l.Type, r.Type) {
l, r = defaultlit2(l, r, true)
if r.Type.IsInterface() == l.Type.IsInterface() || aop == 0 {
- Yyerror("invalid operation: %v (mismatched types %v and %v)", n, l.Type, r.Type)
+ yyerror("invalid operation: %v (mismatched types %v and %v)", n, l.Type, r.Type)
n.Type = nil
return n
}
}
if !okfor[op][et] {
- Yyerror("invalid operation: %v (operator %v not defined on %s)", n, op, typekind(t))
+ yyerror("invalid operation: %v (operator %v not defined on %s)", n, op, typekind(t))
n.Type = nil
return n
}
@@ -672,32 +670,32 @@ 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() {
- Yyerror("invalid operation: %v (%v cannot be compared)", n, l.Type)
+ yyerror("invalid operation: %v (%v cannot be compared)", n, l.Type)
n.Type = nil
return n
}
if l.Type.IsSlice() && !isnil(l) && !isnil(r) {
- Yyerror("invalid operation: %v (slice can only be compared to nil)", n)
+ yyerror("invalid operation: %v (slice can only be compared to nil)", n)
n.Type = nil
return n
}
if l.Type.IsMap() && !isnil(l) && !isnil(r) {
- Yyerror("invalid operation: %v (map can only be compared to nil)", n)
+ yyerror("invalid operation: %v (map can only be compared to nil)", n)
n.Type = nil
return n
}
if l.Type.Etype == TFUNC && !isnil(l) && !isnil(r) {
- Yyerror("invalid operation: %v (func can only be compared to nil)", n)
+ yyerror("invalid operation: %v (func can only be compared to nil)", n)
n.Type = nil
return n
}
if l.Type.IsStruct() {
if f := l.Type.IncomparableField(); f != nil {
- Yyerror("invalid operation: %v (struct containing %v cannot be compared)", n, f.Type)
+ yyerror("invalid operation: %v (struct containing %v cannot be compared)", n, f.Type)
n.Type = nil
return n
}
@@ -755,7 +753,7 @@ OpSwitch:
if (op == ODIV || op == OMOD) && Isconst(r, CTINT) {
if r.Val().U.(*Mpint).CmpInt64(0) == 0 {
- Yyerror("division by zero")
+ yyerror("division by zero")
n.Type = nil
return n
}
@@ -774,7 +772,7 @@ OpSwitch:
return n
}
if !okfor[n.Op][t.Etype] {
- Yyerror("invalid operation: %v %v", n.Op, t)
+ yyerror("invalid operation: %v %v", n.Op, t)
n.Type = nil
return n
}
@@ -815,7 +813,7 @@ OpSwitch:
n.Type = nil
return n
}
- n.Type = Ptrto(t)
+ n.Type = ptrto(t)
break OpSwitch
case OCOMPLIT:
@@ -852,16 +850,16 @@ OpSwitch:
if n.Left.Op == OTYPE {
if !looktypedot(n, t, 0) {
if looktypedot(n, t, 1) {
- Yyerror("%v undefined (cannot refer to unexported method %v)", n, n.Sym)
+ yyerror("%v undefined (cannot refer to unexported method %v)", n, n.Sym)
} else {
- Yyerror("%v undefined (type %v has no method %v)", n, t, n.Sym)
+ yyerror("%v undefined (type %v has no method %v)", n, t, n.Sym)
}
n.Type = nil
return n
}
- if n.Type.Etype != TFUNC || n.Type.Recv() == nil {
- Yyerror("type %v has no method %v", n.Left.Type, sconv(n.Right.Sym, FmtShort))
+ if n.Type.Etype != TFUNC || !n.IsMethod() {
+ yyerror("type %v has no method %S", n.Left.Type, n.Right.Sym)
n.Type = nil
return n
}
@@ -889,7 +887,7 @@ OpSwitch:
}
if isblanksym(n.Sym) {
- Yyerror("cannot refer to blank field or method")
+ yyerror("cannot refer to blank field or method")
n.Type = nil
return n
}
@@ -898,21 +896,21 @@ OpSwitch:
// Legitimate field or method lookup failed, try to explain the error
switch {
case t.IsEmptyInterface():
- Yyerror("%v undefined (type %v is interface with no methods)", n, n.Left.Type)
+ yyerror("%v undefined (type %v is interface with no methods)", n, n.Left.Type)
case t.IsPtr() && t.Elem().IsInterface():
// Pointer to interface is almost always a mistake.
- Yyerror("%v undefined (type %v is pointer to interface, not interface)", n, n.Left.Type)
+ yyerror("%v undefined (type %v is pointer to interface, not interface)", n, n.Left.Type)
case lookdot(n, t, 1) != nil:
// Field or method matches by name, but it is not exported.
- Yyerror("%v undefined (cannot refer to unexported field or method %v)", n, n.Sym)
+ yyerror("%v undefined (cannot refer to unexported field or method %v)", n, n.Sym)
default:
if mt := lookdot(n, t, 2); mt != nil { // Case-insensitive lookup.
- Yyerror("%v undefined (type %v has no field or method %v, but does have %v)", n, n.Left.Type, n.Sym, mt.Sym)
+ yyerror("%v undefined (type %v has no field or method %v, but does have %v)", n, n.Left.Type, n.Sym, mt.Sym)
} else {
- Yyerror("%v undefined (type %v has no field or method %v)", n, n.Left.Type, n.Sym)
+ yyerror("%v undefined (type %v has no field or method %v)", n, n.Left.Type, n.Sym)
}
}
n.Type = nil
@@ -945,7 +943,7 @@ OpSwitch:
return n
}
if !t.IsInterface() {
- Yyerror("invalid type assertion: %v (non-interface type %v on left)", n, t)
+ yyerror("invalid type assertion: %v (non-interface type %v on left)", n, t)
n.Type = nil
return n
}
@@ -964,13 +962,15 @@ OpSwitch:
var ptr int
if !implements(n.Type, t, &missing, &have, &ptr) {
if have != nil && have.Sym == missing.Sym {
- Yyerror("impossible type assertion:\n\t%v does not implement %v (wrong type for %v method)\n"+"\t\thave %v%v\n\t\twant %v%v", n.Type, t, missing.Sym, have.Sym, Tconv(have.Type, FmtShort|FmtByte), missing.Sym, Tconv(missing.Type, FmtShort|FmtByte))
+ yyerror("impossible type assertion:\n\t%v does not implement %v (wrong type for %v method)\n"+
+ "\t\thave %v%0S\n\t\twant %v%0S", n.Type, t, missing.Sym, have.Sym, have.Type, missing.Sym, missing.Type)
} else if ptr != 0 {
- Yyerror("impossible type assertion:\n\t%v does not implement %v (%v method has pointer receiver)", n.Type, t, missing.Sym)
+ yyerror("impossible type assertion:\n\t%v does not implement %v (%v method has pointer receiver)", n.Type, t, missing.Sym)
} else if have != nil {
- Yyerror("impossible type assertion:\n\t%v does not implement %v (missing %v method)\n"+"\t\thave %v%v\n\t\twant %v%v", n.Type, t, missing.Sym, have.Sym, Tconv(have.Type, FmtShort|FmtByte), missing.Sym, Tconv(missing.Type, FmtShort|FmtByte))
+ yyerror("impossible type assertion:\n\t%v does not implement %v (missing %v method)\n"+
+ "\t\thave %v%0S\n\t\twant %v%0S", n.Type, t, missing.Sym, have.Sym, have.Type, missing.Sym, missing.Type)
} else {
- Yyerror("impossible type assertion:\n\t%v does not implement %v (missing %v method)", n.Type, t, missing.Sym)
+ yyerror("impossible type assertion:\n\t%v does not implement %v (missing %v method)", n.Type, t, missing.Sym)
}
n.Type = nil
return n
@@ -994,7 +994,7 @@ OpSwitch:
}
switch t.Etype {
default:
- Yyerror("invalid operation: %v (type %v does not support indexing)", n, t)
+ yyerror("invalid operation: %v (type %v does not support indexing)", n, t)
n.Type = nil
return n
@@ -1013,20 +1013,20 @@ OpSwitch:
}
if n.Right.Type != nil && !n.Right.Type.IsInteger() {
- Yyerror("non-integer %s index %v", why, n.Right)
+ yyerror("non-integer %s index %v", why, n.Right)
break
}
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)
+ yyerror("invalid %s index %v (index must be non-negative)", why, n.Right)
} else if t.IsArray() && x >= t.NumElem() {
- Yyerror("invalid array index %v (out of bounds for %d-element array)", n.Right, t.NumElem())
+ yyerror("invalid array index %v (out of bounds for %d-element array)", n.Right, t.NumElem())
} else if Isconst(n.Left, CTSTR) && x >= int64(len(n.Left.Val().U.(string))) {
- Yyerror("invalid string index %v (out of bounds for %d-byte string)", n.Right, len(n.Left.Val().U.(string)))
- } else if n.Right.Val().U.(*Mpint).Cmp(Maxintval[TINT]) > 0 {
- Yyerror("invalid %s index %v (index too large)", why, n.Right)
+ yyerror("invalid string index %v (out of bounds for %d-byte string)", n.Right, len(n.Left.Val().U.(string)))
+ } else if n.Right.Val().U.(*Mpint).Cmp(maxintval[TINT]) > 0 {
+ yyerror("invalid %s index %v (index too large)", why, n.Right)
}
}
@@ -1053,13 +1053,13 @@ OpSwitch:
return n
}
if !t.IsChan() {
- Yyerror("invalid operation: %v (receive from non-chan type %v)", n, t)
+ yyerror("invalid operation: %v (receive from non-chan type %v)", n, t)
n.Type = nil
return n
}
if !t.ChanDir().CanRecv() {
- Yyerror("invalid operation: %v (receive from send-only type %v)", n, t)
+ yyerror("invalid operation: %v (receive from send-only type %v)", n, t)
n.Type = nil
return n
}
@@ -1080,13 +1080,13 @@ OpSwitch:
return n
}
if !t.IsChan() {
- Yyerror("invalid operation: %v (send to non-chan type %v)", n, t)
+ yyerror("invalid operation: %v (send to non-chan type %v)", n, t)
n.Type = nil
return n
}
if !t.ChanDir().CanSend() {
- Yyerror("invalid operation: %v (send to receive-only type %v)", n, t)
+ yyerror("invalid operation: %v (send to receive-only type %v)", n, t)
n.Type = nil
return n
}
@@ -1121,12 +1121,12 @@ OpSwitch:
l := n.Left
if l.Type.IsArray() {
if !islvalue(n.Left) {
- Yyerror("invalid operation %v (slice of unaddressable value)", n)
+ yyerror("invalid operation %v (slice of unaddressable value)", n)
n.Type = nil
return n
}
- n.Left = Nod(OADDR, n.Left, nil)
+ n.Left = nod(OADDR, n.Left, nil)
n.Left.Implicit = true
n.Left = typecheck(n.Left, Erv)
l = n.Left
@@ -1140,7 +1140,7 @@ OpSwitch:
var tp *Type
if t.IsString() {
if hasmax {
- Yyerror("invalid operation %v (3-index slice of string)", n)
+ yyerror("invalid operation %v (3-index slice of string)", n)
n.Type = nil
return n
}
@@ -1158,7 +1158,7 @@ OpSwitch:
} else if t.IsSlice() {
n.Type = t
} else {
- Yyerror("cannot slice %v (type %v)", l, t)
+ yyerror("cannot slice %v (type %v)", l, t)
n.Type = nil
return n
}
@@ -1183,33 +1183,22 @@ OpSwitch:
// call and call like
case OCALL:
- l := n.Left
-
- if l.Op == ONAME {
- r := unsafenmagic(n)
- if r != nil {
- if n.Isddd {
- Yyerror("invalid use of ... with builtin %v", l)
- }
- n = r
- n = typecheck1(n, top)
- return n
- }
+ n.Left = typecheck(n.Left, Erv|Etype|Ecall)
+ if n.Left.Diag {
+ n.Diag = true
}
- n.Left = typecheck(n.Left, Erv|Etype|Ecall)
- n.Diag |= n.Left.Diag
- l = n.Left
+ l := n.Left
+
if l.Op == ONAME && l.Etype != 0 {
// TODO(marvin): Fix Node.EType type union.
if n.Isddd && Op(l.Etype) != OAPPEND {
- Yyerror("invalid use of ... with builtin %v", l)
+ yyerror("invalid use of ... with builtin %v", l)
}
// builtin: OLEN, OCAP, etc.
// TODO(marvin): Fix Node.EType type union.
n.Op = Op(l.Etype)
-
n.Left = n.Right
n.Right = nil
n = typecheck1(n, top)
@@ -1221,9 +1210,9 @@ OpSwitch:
if l.Op == OTYPE {
if n.Isddd || l.Type.isDDDArray() {
if !l.Type.Broke {
- Yyerror("invalid use of ... in type conversion to %v", l.Type)
+ yyerror("invalid use of ... in type conversion to %v", l.Type)
}
- n.Diag = 1
+ n.Diag = true
}
// pick off before type-checking arguments
@@ -1267,14 +1256,14 @@ OpSwitch:
// It isn't necessary, so just do a sanity check.
tp := t.Recv().Type
- if l.Left == nil || !Eqtype(l.Left.Type, tp) {
+ if l.Left == nil || !eqtype(l.Left.Type, tp) {
Fatalf("method receiver")
}
default:
n.Op = OCALLFUNC
if t.Etype != TFUNC {
- Yyerror("cannot call non-function %v (type %v)", l, t)
+ yyerror("cannot call non-function %v (type %v)", l, t)
n.Type = nil
return n
}
@@ -1304,7 +1293,7 @@ OpSwitch:
// multiple return
if top&(Efnstruct|Etop) == 0 {
- Yyerror("multiple-value %v() in single-value context", l)
+ yyerror("multiple-value %v() in single-value context", l)
break OpSwitch
}
@@ -1312,6 +1301,21 @@ OpSwitch:
break OpSwitch
+ case OALIGNOF, OOFFSETOF, OSIZEOF:
+ ok |= Erv
+ if !onearg(n, "%v", n.Op) {
+ n.Type = nil
+ return n
+ }
+
+ // any side effects disappear; ignore init
+ var r Node
+ Nodconst(&r, Types[TUINTPTR], evalunsafe(n))
+ r.Orig = n
+ n = &r
+
+ break OpSwitch
+
case OCAP, OLEN, OREAL, OIMAG:
ok |= Erv
if !onearg(n, "%v", n.Op) {
@@ -1380,7 +1384,7 @@ OpSwitch:
break OpSwitch
badcall1:
- Yyerror("invalid argument %v for %v", Nconv(n.Left, FmtLong), n.Op)
+ yyerror("invalid argument %L for %v", n.Left, n.Op)
n.Type = nil
return n
@@ -1391,14 +1395,18 @@ OpSwitch:
if n.List.Len() == 1 {
typecheckslice(n.List.Slice(), Efnstruct)
if n.List.First().Op != OCALLFUNC && n.List.First().Op != OCALLMETH {
- Yyerror("invalid operation: complex expects two arguments")
+ yyerror("invalid operation: complex expects two arguments")
n.Type = nil
return n
}
t := n.List.First().Left.Type
+ if !t.IsKind(TFUNC) {
+ // Bail. This error will be reported elsewhere.
+ return n
+ }
if t.Results().NumFields() != 2 {
- Yyerror("invalid operation: complex expects two arguments, %v returns %d results", n.List.First(), t.Results().NumFields())
+ yyerror("invalid operation: complex expects two arguments, %v returns %d results", n.List.First(), t.Results().NumFields())
n.Type = nil
return n
}
@@ -1428,8 +1436,8 @@ OpSwitch:
n.Right = r
}
- if !Eqtype(l.Type, r.Type) {
- Yyerror("invalid operation: %v (mismatched types %v and %v)", n, l.Type, r.Type)
+ if !eqtype(l.Type, r.Type) {
+ yyerror("invalid operation: %v (mismatched types %v and %v)", n, l.Type, r.Type)
n.Type = nil
return n
}
@@ -1437,7 +1445,7 @@ OpSwitch:
var t *Type
switch l.Type.Etype {
default:
- Yyerror("invalid operation: %v (arguments have type %v, expected floating-point)", n, l.Type)
+ yyerror("invalid operation: %v (arguments have type %v, expected floating-point)", n, l.Type)
n.Type = nil
return n
@@ -1476,13 +1484,13 @@ OpSwitch:
return n
}
if !t.IsChan() {
- Yyerror("invalid operation: %v (non-chan type %v)", n, t)
+ yyerror("invalid operation: %v (non-chan type %v)", n, t)
n.Type = nil
return n
}
if !t.ChanDir().CanSend() {
- Yyerror("invalid operation: %v (cannot close receive-only channel)", n)
+ yyerror("invalid operation: %v (cannot close receive-only channel)", n)
n.Type = nil
return n
}
@@ -1493,19 +1501,19 @@ OpSwitch:
case ODELETE:
args := n.List
if args.Len() == 0 {
- Yyerror("missing arguments to delete")
+ yyerror("missing arguments to delete")
n.Type = nil
return n
}
if args.Len() == 1 {
- Yyerror("missing second (key) argument to delete")
+ yyerror("missing second (key) argument to delete")
n.Type = nil
return n
}
if args.Len() != 2 {
- Yyerror("too many arguments to delete")
+ yyerror("too many arguments to delete")
n.Type = nil
return n
}
@@ -1515,7 +1523,7 @@ OpSwitch:
l := args.First()
r := args.Second()
if l.Type != nil && !l.Type.IsMap() {
- Yyerror("first argument to delete must be map; have %v", Tconv(l.Type, FmtLong))
+ yyerror("first argument to delete must be map; have %L", l.Type)
n.Type = nil
return n
}
@@ -1527,7 +1535,7 @@ OpSwitch:
ok |= Erv
args := n.List
if args.Len() == 0 {
- Yyerror("missing arguments to append")
+ yyerror("missing arguments to append")
n.Type = nil
return n
}
@@ -1554,25 +1562,25 @@ OpSwitch:
n.Type = t
if !t.IsSlice() {
if Isconst(args.First(), CTNIL) {
- Yyerror("first argument to append must be typed slice; have untyped nil")
+ yyerror("first argument to append must be typed slice; have untyped nil")
n.Type = nil
return n
}
- Yyerror("first argument to append must be slice; have %v", Tconv(t, FmtLong))
+ yyerror("first argument to append must be slice; have %L", t)
n.Type = nil
return n
}
if n.Isddd {
if args.Len() == 1 {
- Yyerror("cannot use ... on first argument to append")
+ yyerror("cannot use ... on first argument to append")
n.Type = nil
return n
}
if args.Len() != 2 {
- Yyerror("too many arguments to append")
+ yyerror("too many arguments to append")
n.Type = nil
return n
}
@@ -1587,10 +1595,10 @@ OpSwitch:
}
if funarg != nil {
- _, it := IterFields(funarg) // Skip first field
+ _, it := iterFields(funarg) // Skip first field
for t := it.Next(); t != nil; t = it.Next() {
if assignop(t.Type, n.Type.Elem(), nil) == 0 {
- Yyerror("cannot append %v value to []%v", t.Type, n.Type.Elem())
+ yyerror("cannot append %v value to []%v", t.Type, n.Type.Elem())
}
}
} else {
@@ -1609,13 +1617,13 @@ OpSwitch:
ok |= Etop | Erv
args := n.List
if args.Len() < 2 {
- Yyerror("missing arguments to copy")
+ yyerror("missing arguments to copy")
n.Type = nil
return n
}
if args.Len() > 2 {
- Yyerror("too many arguments to copy")
+ yyerror("too many arguments to copy")
n.Type = nil
return n
}
@@ -1639,28 +1647,28 @@ 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(), bytetype) {
break OpSwitch
}
- Yyerror("arguments to copy have different element types: %v and string", Tconv(n.Left.Type, FmtLong))
+ yyerror("arguments to copy have different element types: %L and string", n.Left.Type)
n.Type = nil
return n
}
if !n.Left.Type.IsSlice() || !n.Right.Type.IsSlice() {
if !n.Left.Type.IsSlice() && !n.Right.Type.IsSlice() {
- Yyerror("arguments to copy must be slices; have %v, %v", Tconv(n.Left.Type, FmtLong), Tconv(n.Right.Type, FmtLong))
+ yyerror("arguments to copy must be slices; have %L, %L", n.Left.Type, n.Right.Type)
} else if !n.Left.Type.IsSlice() {
- Yyerror("first argument to copy should be slice; have %v", Tconv(n.Left.Type, FmtLong))
+ yyerror("first argument to copy should be slice; have %L", n.Left.Type)
} else {
- Yyerror("second argument to copy should be slice or string; have %v", Tconv(n.Right.Type, FmtLong))
+ yyerror("second argument to copy should be slice or string; have %L", n.Right.Type)
}
n.Type = nil
return n
}
- if !Eqtype(n.Left.Type.Elem(), n.Right.Type.Elem()) {
- Yyerror("arguments to copy have different element types: %v and %v", Tconv(n.Left.Type, FmtLong), Tconv(n.Right.Type, FmtLong))
+ if !eqtype(n.Left.Type.Elem(), n.Right.Type.Elem()) {
+ yyerror("arguments to copy have different element types: %L and %L", n.Left.Type, n.Right.Type)
n.Type = nil
return n
}
@@ -1680,9 +1688,9 @@ OpSwitch:
var why string
n.Op = convertop(t, n.Type, &why)
if n.Op == 0 {
- if n.Diag == 0 && !n.Type.Broke {
- Yyerror("cannot convert %v to type %v%s", Nconv(n.Left, FmtLong), n.Type, why)
- n.Diag = 1
+ if !n.Diag && !n.Type.Broke {
+ yyerror("cannot convert %L to type %v%s", n.Left, n.Type, why)
+ n.Diag = true
}
n.Op = OCONV
@@ -1691,7 +1699,7 @@ OpSwitch:
switch n.Op {
case OCONVNOP:
if n.Left.Op == OLITERAL {
- r := Nod(OXXX, nil, nil)
+ r := nod(OXXX, nil, nil)
n.Op = OCONV
n.Orig = r
*r = *n
@@ -1699,7 +1707,7 @@ OpSwitch:
n.SetVal(n.Left.Val())
}
- // do not use stringtoarraylit.
+ // do not use stringtoarraylit.
// generated code and compiler memory footprint is better without it.
case OSTRARRAYBYTE:
break
@@ -1716,7 +1724,7 @@ OpSwitch:
ok |= Erv
args := n.List.Slice()
if len(args) == 0 {
- Yyerror("missing argument to make")
+ yyerror("missing argument to make")
n.Type = nil
return n
}
@@ -1733,13 +1741,13 @@ OpSwitch:
i := 1
switch t.Etype {
default:
- Yyerror("cannot make type %v", t)
+ yyerror("cannot make type %v", t)
n.Type = nil
return n
case TSLICE:
if i >= len(args) {
- Yyerror("missing len argument to make(%v)", t)
+ yyerror("missing len argument to make(%v)", t)
n.Type = nil
return n
}
@@ -1763,7 +1771,7 @@ OpSwitch:
return n
}
if Isconst(l, CTINT) && r != nil && Isconst(r, CTINT) && l.Val().U.(*Mpint).Cmp(r.Val().U.(*Mpint)) > 0 {
- Yyerror("len larger than cap in make(%v)", t)
+ yyerror("len larger than cap in make(%v)", t)
n.Type = nil
return n
}
@@ -1788,7 +1796,7 @@ OpSwitch:
}
n.Left = l
} else {
- n.Left = Nodintconst(0)
+ n.Left = nodintconst(0)
}
n.Op = OMAKEMAP
@@ -1809,13 +1817,13 @@ OpSwitch:
}
n.Left = l
} else {
- n.Left = Nodintconst(0)
+ n.Left = nodintconst(0)
}
n.Op = OMAKECHAN
}
if i < len(args) {
- Yyerror("too many arguments to make(%v)", t)
+ yyerror("too many arguments to make(%v)", t)
n.Op = OMAKE
n.Type = nil
return n
@@ -1828,7 +1836,7 @@ OpSwitch:
ok |= Erv
args := n.List
if args.Len() == 0 {
- Yyerror("missing argument to new")
+ yyerror("missing argument to new")
n.Type = nil
return n
}
@@ -1841,13 +1849,13 @@ OpSwitch:
return n
}
if args.Len() > 1 {
- Yyerror("too many arguments to new(%v)", t)
+ yyerror("too many arguments to new(%v)", t)
n.Type = nil
return n
}
n.Left = l
- n.Type = Ptrto(t)
+ n.Type = ptrto(t)
break OpSwitch
case OPRINT, OPRINTN:
@@ -1882,7 +1890,7 @@ OpSwitch:
case ORECOVER:
ok |= Erv | Etop
if n.List.Len() != 0 {
- Yyerror("too many arguments to recover")
+ yyerror("too many arguments to recover")
n.Type = nil
return n
}
@@ -1909,7 +1917,13 @@ OpSwitch:
if !t.IsInterface() {
Fatalf("OITAB of %v", t)
}
- n.Type = Ptrto(Types[TUINTPTR])
+ n.Type = ptrto(Types[TUINTPTR])
+ break OpSwitch
+
+ case OIDATA:
+ // Whoever creates the OIDATA node must know a priori the concrete type at that moment,
+ // usually by just having checked the OITAB.
+ Fatalf("cannot typecheck interface data %v", n)
break OpSwitch
case OSPTR:
@@ -1924,9 +1938,9 @@ OpSwitch:
Fatalf("OSPTR of %v", t)
}
if t.IsString() {
- n.Type = Ptrto(Types[TUINT8])
+ n.Type = ptrto(Types[TUINT8])
} else {
- n.Type = Ptrto(t.Elem())
+ n.Type = ptrto(t.Elem())
}
break OpSwitch
@@ -1952,7 +1966,7 @@ OpSwitch:
typecheckas(n)
// Code that creates temps does not bother to set defn, so do it here.
- if n.Left.Op == ONAME && strings.HasPrefix(n.Left.Sym.Name, "autotmp_") {
+ if n.Left.Op == ONAME && n.Left.IsAutoTmp() {
n.Left.Name.Defn = n
}
break OpSwitch
@@ -1981,7 +1995,7 @@ OpSwitch:
case ODEFER:
ok |= Etop
n.Left = typecheck(n.Left, Etop|Erv)
- if n.Left.Diag == 0 {
+ if !n.Left.Diag {
checkdefergo(n)
}
break OpSwitch
@@ -2000,7 +2014,7 @@ OpSwitch:
if n.Left != nil {
t := n.Left.Type
if t != nil && !t.IsBoolean() {
- Yyerror("non-bool %v used as for condition", Nconv(n.Left, FmtLong))
+ yyerror("non-bool %L used as for condition", n.Left)
}
}
n.Right = typecheck(n.Right, Etop)
@@ -2015,7 +2029,7 @@ OpSwitch:
if n.Left != nil {
t := n.Left.Type
if t != nil && !t.IsBoolean() {
- Yyerror("non-bool %v used as if condition", Nconv(n.Left, FmtLong))
+ yyerror("non-bool %L used as if condition", n.Left)
}
}
typecheckslice(n.Nbody.Slice(), Etop)
@@ -2030,7 +2044,7 @@ OpSwitch:
typecheckslice(n.List.Slice(), Erv)
}
if Curfn == nil {
- Yyerror("return outside function")
+ yyerror("return outside function")
n.Type = nil
return n
}
@@ -2061,7 +2075,7 @@ OpSwitch:
break OpSwitch
case OTYPESW:
- Yyerror("use of .(type) outside type switch")
+ yyerror("use of .(type) outside type switch")
n.Type = nil
return n
@@ -2084,8 +2098,12 @@ OpSwitch:
case ODCLTYPE:
ok |= Etop
n.Left = typecheck(n.Left, Etype)
- if incannedimport == 0 {
- checkwidth(n.Left.Type)
+ checkwidth(n.Left.Type)
+ 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).
+ yyerror("type %v must be go:notinheap", n.Left.Type)
}
break OpSwitch
}
@@ -2102,34 +2120,34 @@ OpSwitch:
}
}
- if safemode && incannedimport == 0 && importpkg == nil && compiling_wrappers == 0 && t != nil && t.Etype == TUNSAFEPTR {
- Yyerror("cannot use unsafe.Pointer")
+ if safemode && importpkg == nil && compiling_wrappers == 0 && t != nil && t.Etype == TUNSAFEPTR {
+ yyerror("cannot use unsafe.Pointer")
}
evconst(n)
if n.Op == OTYPE && top&Etype == 0 {
- Yyerror("type %v is not an expression", n.Type)
+ yyerror("type %v is not an expression", n.Type)
n.Type = nil
return n
}
if top&(Erv|Etype) == Etype && n.Op != OTYPE {
- Yyerror("%v is not a type", n)
+ yyerror("%v is not a type", n)
n.Type = nil
return n
}
// TODO(rsc): simplify
if (top&(Ecall|Erv|Etype) != 0) && top&Etop == 0 && ok&(Erv|Etype|Ecall) == 0 {
- Yyerror("%v used as value", n)
+ yyerror("%v used as value", n)
n.Type = nil
return n
}
if (top&Etop != 0) && top&(Ecall|Erv|Etype) == 0 && ok&Etop == 0 {
- if n.Diag == 0 {
- Yyerror("%v evaluated but not used", n)
- n.Diag = 1
+ if !n.Diag {
+ yyerror("%v evaluated but not used", n)
+ n.Diag = true
}
n.Type = nil
@@ -2149,22 +2167,22 @@ func checksliceindex(l *Node, r *Node, tp *Type) bool {
return false
}
if !t.IsInteger() {
- Yyerror("invalid slice index %v (type %v)", r, t)
+ yyerror("invalid slice index %v (type %v)", r, t)
return false
}
if r.Op == OLITERAL {
if r.Int64() < 0 {
- Yyerror("invalid slice index %v (index must be non-negative)", r)
+ yyerror("invalid slice index %v (index must be non-negative)", r)
return false
} else if tp != nil && tp.NumElem() > 0 && r.Int64() > tp.NumElem() {
- Yyerror("invalid slice index %v (out of bounds for %d-element array)", r, tp.NumElem())
+ yyerror("invalid slice index %v (out of bounds for %d-element array)", r, tp.NumElem())
return false
} else if Isconst(l, CTSTR) && r.Int64() > int64(len(l.Val().U.(string))) {
- Yyerror("invalid slice index %v (out of bounds for %d-byte string)", r, len(l.Val().U.(string)))
+ yyerror("invalid slice index %v (out of bounds for %d-byte string)", r, len(l.Val().U.(string)))
return false
- } else if r.Val().U.(*Mpint).Cmp(Maxintval[TINT]) > 0 {
- Yyerror("invalid slice index %v (index too large)", r)
+ } else if r.Val().U.(*Mpint).Cmp(maxintval[TINT]) > 0 {
+ yyerror("invalid slice index %v (index too large)", r)
return false
}
}
@@ -2174,7 +2192,7 @@ func checksliceindex(l *Node, r *Node, tp *Type) bool {
func checksliceconst(lo *Node, hi *Node) bool {
if lo != nil && hi != nil && lo.Op == OLITERAL && hi.Op == OLITERAL && lo.Val().U.(*Mpint).Cmp(hi.Val().U.(*Mpint)) > 0 {
- Yyerror("invalid slice index: %v > %v", lo, hi)
+ yyerror("invalid slice index: %v > %v", lo, hi)
return false
}
@@ -2216,7 +2234,7 @@ func checkdefergo(n *Node) {
if n.Left.Orig != nil && n.Left.Orig.Op == OCONV {
break
}
- Yyerror("%s discards result of %v", what, n.Left)
+ yyerror("%s discards result of %v", what, n.Left)
return
}
@@ -2226,12 +2244,11 @@ func checkdefergo(n *Node) {
return
}
- if n.Diag == 0 {
+ if !n.Diag {
// The syntax made sure it was a call, so this must be
// a conversion.
- n.Diag = 1
-
- Yyerror("%s requires function call, not conversion", what)
+ n.Diag = true
+ yyerror("%s requires function call, not conversion", what)
}
}
@@ -2250,7 +2267,7 @@ func implicitstar(n *Node) *Node {
if !t.IsArray() {
return n
}
- n = Nod(OIND, n, nil)
+ n = nod(OIND, n, nil)
n.Implicit = true
n = typecheck(n, Erv)
return n
@@ -2262,13 +2279,13 @@ func onearg(n *Node, f string, args ...interface{}) bool {
}
if n.List.Len() == 0 {
p := fmt.Sprintf(f, args...)
- Yyerror("missing argument to %s: %v", p, n)
+ yyerror("missing argument to %s: %v", p, n)
return false
}
if n.List.Len() > 1 {
p := fmt.Sprintf(f, args...)
- Yyerror("too many arguments to %s: %v", p, n)
+ yyerror("too many arguments to %s: %v", p, n)
n.Left = n.List.First()
n.List.Set(nil)
return false
@@ -2284,19 +2301,19 @@ func twoarg(n *Node) bool {
return true
}
if n.List.Len() == 0 {
- Yyerror("missing argument to %v - %v", n.Op, n)
+ yyerror("missing argument to %v - %v", n.Op, n)
return false
}
n.Left = n.List.First()
if n.List.Len() == 1 {
- Yyerror("missing argument to %v - %v", n.Op, n)
+ yyerror("missing argument to %v - %v", n.Op, n)
n.List.Set(nil)
return false
}
if n.List.Len() > 2 {
- Yyerror("too many arguments to %v - %v", n.Op, n)
+ yyerror("too many arguments to %v - %v", n.Op, n)
n.List.Set(nil)
return false
}
@@ -2320,11 +2337,11 @@ func lookdot1(errnode *Node, s *Sym, t *Type, fs *Fields, dostrcmp int) *Field {
}
if r != nil {
if errnode != nil {
- Yyerror("ambiguous selector %v", errnode)
+ yyerror("ambiguous selector %v", errnode)
} else if t.IsPtr() {
- Yyerror("ambiguous selector (%v).%v", t, s)
+ yyerror("ambiguous selector (%v).%v", t, s)
} else {
- Yyerror("ambiguous selector %v.%v", t, s)
+ yyerror("ambiguous selector %v.%v", t, s)
}
break
}
@@ -2353,7 +2370,7 @@ func looktypedot(n *Node, t *Type, dostrcmp int) bool {
// Find the base type: methtype will fail if t
// is not of the form T or *T.
- mt := methtype(t, 0)
+ mt := methtype(t)
if mt == nil {
return false
}
@@ -2366,7 +2383,7 @@ func looktypedot(n *Node, t *Type, dostrcmp int) bool {
// disallow T.m if m requires *T receiver
if f2.Type.Recv().Type.IsPtr() && !t.IsPtr() && f2.Embedded != 2 && !isifacemethod(f2.Type) {
- Yyerror("invalid method expression %v (needs pointer receiver: (*%v).%v)", n, t, sconv(f2.Sym, FmtShort))
+ yyerror("invalid method expression %v (needs pointer receiver: (*%v).%S)", n, t, f2.Sym)
return false
}
@@ -2404,7 +2421,7 @@ func lookdot(n *Node, t *Type, dostrcmp int) *Field {
var f2 *Field
if n.Left.Type == t || n.Left.Type.Sym == nil {
- mt := methtype(t, 0)
+ mt := methtype(t)
if mt != nil {
// Use f2->method, not f2->xmethod: adddot has
// already inserted all the necessary embedded dots.
@@ -2418,7 +2435,7 @@ func lookdot(n *Node, t *Type, dostrcmp int) *Field {
return f1
}
if f2 != nil {
- Yyerror("%v is both field and method", n.Sym)
+ yyerror("%v is both field and method", n.Sym)
}
if f1.Offset == BADWIDTH {
Fatalf("lookdot badwidth %v %p", f1, f1)
@@ -2430,7 +2447,7 @@ func lookdot(n *Node, t *Type, dostrcmp int) *Field {
}
if t.IsInterface() {
if n.Left.Type.IsPtr() {
- n.Left = Nod(OIND, n.Left, nil) // implicitstar
+ n.Left = nod(OIND, n.Left, nil) // implicitstar
n.Left.Implicit = true
n.Left = typecheck(n.Left, Erv)
}
@@ -2449,24 +2466,24 @@ func lookdot(n *Node, t *Type, dostrcmp int) *Field {
tt := n.Left.Type
dowidth(tt)
rcvr := f2.Type.Recv().Type
- if !Eqtype(rcvr, tt) {
- if rcvr.Etype == Tptr && Eqtype(rcvr.Elem(), tt) {
+ if !eqtype(rcvr, tt) {
+ if rcvr.Etype == Tptr && eqtype(rcvr.Elem(), tt) {
checklvalue(n.Left, "call pointer method on")
- n.Left = Nod(OADDR, n.Left, nil)
+ n.Left = nod(OADDR, n.Left, nil)
n.Left.Implicit = true
n.Left = typecheck(n.Left, Etype|Erv)
- } else if tt.Etype == Tptr && rcvr.Etype != Tptr && Eqtype(tt.Elem(), rcvr) {
- n.Left = Nod(OIND, n.Left, nil)
+ } else if tt.Etype == Tptr && rcvr.Etype != Tptr && eqtype(tt.Elem(), rcvr) {
+ n.Left = nod(OIND, n.Left, nil)
n.Left.Implicit = true
n.Left = typecheck(n.Left, Etype|Erv)
- } else if tt.Etype == Tptr && tt.Elem().Etype == Tptr && Eqtype(derefall(tt), derefall(rcvr)) {
- Yyerror("calling method %v with receiver %v requires explicit dereference", n.Sym, Nconv(n.Left, FmtLong))
+ } else if tt.Etype == Tptr && tt.Elem().Etype == Tptr && eqtype(derefall(tt), derefall(rcvr)) {
+ yyerror("calling method %v with receiver %L requires explicit dereference", n.Sym, n.Left)
for tt.Etype == Tptr {
// Stop one level early for method with pointer receiver.
if rcvr.Etype == Tptr && tt.Elem().Etype != Tptr {
break
}
- n.Left = Nod(OIND, n.Left, nil)
+ n.Left = nod(OIND, n.Left, nil)
n.Left.Implicit = true
n.Left = typecheck(n.Left, Etype|Erv)
tt = tt.Elem()
@@ -2504,7 +2521,7 @@ func lookdot(n *Node, t *Type, dostrcmp int) *Field {
func nokeys(l Nodes) bool {
for _, n := range l.Slice() {
- if n.Op == OKEY {
+ if n.Op == OKEY || n.Op == OSTRUCTKEY {
return false
}
}
@@ -2551,16 +2568,16 @@ func typecheckaste(op Op, call *Node, isddd bool, tstruct *Type, nl Nodes, desc
}
}
- tn, it := IterFields(n.Type)
+ tn, it := iterFields(n.Type)
var why string
for _, tl := range tstruct.Fields().Slice() {
if tl.Isddd {
for ; tn != nil; tn = it.Next() {
if assignop(tn.Type, tl.Type.Elem(), &why) == 0 {
if call != nil {
- Yyerror("cannot use %v as type %v in argument to %v%s", tn.Type, tl.Type.Elem(), call, why)
+ yyerror("cannot use %v as type %v in argument to %v%s", tn.Type, tl.Type.Elem(), call, why)
} else {
- Yyerror("cannot use %v as type %v in %s%s", tn.Type, tl.Type.Elem(), desc(), why)
+ yyerror("cannot use %v as type %v in %s%s", tn.Type, tl.Type.Elem(), desc(), why)
}
}
}
@@ -2573,9 +2590,9 @@ func typecheckaste(op Op, call *Node, isddd bool, tstruct *Type, nl Nodes, desc
}
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)
+ yyerror("cannot use %v as type %v in argument to %v%s", tn.Type, tl.Type, call, why)
} else {
- Yyerror("cannot use %v as type %v in %s%s", tn.Type, tl.Type, desc(), why)
+ yyerror("cannot use %v as type %v in %s%s", tn.Type, tl.Type, desc(), why)
}
}
@@ -2660,9 +2677,9 @@ func typecheckaste(op Op, call *Node, isddd bool, tstruct *Type, nl Nodes, desc
}
if isddd {
if call != nil {
- Yyerror("invalid use of ... in call to %v", call)
+ yyerror("invalid use of ... in call to %v", call)
} else {
- Yyerror("invalid use of ... in %v", op)
+ yyerror("invalid use of ... in %v", op)
}
}
@@ -2671,21 +2688,21 @@ out:
return
notenough:
- if n == nil || n.Diag == 0 {
+ if n == nil || !n.Diag {
if call != nil {
// call is the expression being called, not the overall call.
// Method expressions have the form T.M, and the compiler has
// rewritten those to ONAME nodes but left T in Left.
if call.Op == ONAME && call.Left != nil && call.Left.Op == OTYPE {
- Yyerror("not enough arguments in call to method expression %v", call)
+ yyerror("not enough arguments in call to method expression %v\n\thave %s\n\twant %v", call, nl.retsigerr(isddd), tstruct)
} else {
- Yyerror("not enough arguments in call to %v", call)
+ yyerror("not enough arguments in call to %v\n\thave %s\n\twant %v", call, nl.retsigerr(isddd), tstruct)
}
} else {
- Yyerror("not enough arguments to %v", op)
+ yyerror("not enough arguments to %v\n\thave %s\n\twant %v", op, nl.retsigerr(isddd), tstruct)
}
if n != nil {
- n.Diag = 1
+ n.Diag = true
}
}
@@ -2693,21 +2710,63 @@ notenough:
toomany:
if call != nil {
- Yyerror("too many arguments in call to %v", call)
+ yyerror("too many arguments in call to %v\n\thave %s\n\twant %v", call, nl.retsigerr(isddd), tstruct)
} else {
- Yyerror("too many arguments to %v", op)
+ yyerror("too many arguments to %v\n\thave %s\n\twant %v", op, nl.retsigerr(isddd), tstruct)
}
goto out
}
-// type check composite
-func fielddup(n *Node, hash map[string]bool) {
- if n.Op != ONAME {
- Fatalf("fielddup: not ONAME")
+// 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 {
+ switch t {
+ default:
+ return t.String()
+
+ case Types[TIDEAL]:
+ // "untyped number" is not commonly used
+ // outside of the compiler, so let's use "number".
+ return "number"
+
+ case idealstring:
+ return "string"
+
+ case idealbool:
+ return "bool"
+ }
+}
+
+// retsigerr returns the signature of the types
+// at the respective return call site of a function.
+func (nl Nodes) retsigerr(isddd bool) string {
+ if nl.Len() < 1 {
+ return "()"
+ }
+
+ 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())
+ }
+ } else {
+ for _, n := range nl.Slice() {
+ typeStrings = append(typeStrings, n.Type.sigrepr())
+ }
}
- name := n.Sym.Name
+
+ ddd := ""
+ if isddd {
+ ddd = "..."
+ }
+ return fmt.Sprintf("(%s%s)", strings.Join(typeStrings, ", "), ddd)
+}
+
+// type check composite
+func fielddup(name string, hash map[string]bool) {
if hash[name] {
- Yyerror("duplicate field name in struct literal: %s", name)
+ yyerror("duplicate field name in struct literal: %s", name)
return
}
hash[name] = true
@@ -2753,7 +2812,7 @@ func keydup(n *Node, hash map[uint32][]*Node) {
if a.Op == OCONVIFACE && orign.Op == OCONVIFACE {
a = a.Left
}
- if !Eqtype(a.Type, n.Type) {
+ if !eqtype(a.Type, n.Type) {
continue
}
cmp.Right = a
@@ -2763,7 +2822,7 @@ func keydup(n *Node, hash map[uint32][]*Node) {
continue
}
if cmp.Val().U.(bool) {
- Yyerror("duplicate key %v in map literal", n)
+ yyerror("duplicate key %v in map literal", n)
return
}
}
@@ -2771,19 +2830,6 @@ func keydup(n *Node, hash map[uint32][]*Node) {
hash[h] = append(hash[h], orign)
}
-func indexdup(n *Node, hash map[int64]*Node) {
- if n.Op != OLITERAL {
- Fatalf("indexdup: not OLITERAL")
- }
-
- v := n.Int64()
- if hash[v] != nil {
- Yyerror("duplicate index in array literal: %d", v)
- return
- }
- hash[v] = n
-}
-
// iscomptype reports whether type t is a composite literal type
// or a pointer to one.
func iscomptype(t *Type) bool {
@@ -2810,17 +2856,12 @@ func pushtype(n *Node, t *Type) {
n.Right.Implicit = true // * is okay
} else if Debug['s'] != 0 {
n.Right = typecheck(n.Right, Etype)
- if n.Right.Type != nil && Eqtype(n.Right.Type, t) {
+ if n.Right.Type != nil && eqtype(n.Right.Type, t) {
fmt.Printf("%v: redundant type: %v\n", n.Line(), t)
}
}
}
-// Marker type so esc, fmt, and sinit can recognize the LHS of an OKEY node
-// in a struct literal.
-// TODO(mdempsky): Find a nicer solution.
-var structkey = typ(Txxx)
-
// The result of typecheckcomplit MUST be assigned back to n, e.g.
// n.Left = typecheckcomplit(n.Left)
func typecheckcomplit(n *Node) *Node {
@@ -2833,13 +2874,13 @@ func typecheckcomplit(n *Node) *Node {
if n.List.Len() != 0 {
setlineno(n.List.First())
}
- Yyerror("missing type in composite literal")
+ yyerror("missing type in composite literal")
n.Type = nil
return n
}
// Save original node (including n->right)
- norig := Nod(n.Op, nil, nil)
+ norig := nod(n.Op, nil, nil)
*norig = *n
@@ -2858,14 +2899,14 @@ func typecheckcomplit(n *Node) *Node {
// For better or worse, we don't allow pointers as the composite literal type,
// except when using the &T syntax, which sets implicit on the OIND.
if !n.Right.Implicit {
- Yyerror("invalid pointer type %v for composite literal (use &%v instead)", t, t.Elem())
+ yyerror("invalid pointer type %v for composite literal (use &%v instead)", t, t.Elem())
n.Type = nil
return n
}
// Also, the underlying type must be a struct, map, slice, or array.
if !iscomptype(t) {
- Yyerror("invalid pointer type %v for composite literal", t)
+ yyerror("invalid pointer type %v for composite literal", t)
n.Type = nil
return n
}
@@ -2873,84 +2914,86 @@ func typecheckcomplit(n *Node) *Node {
t = t.Elem()
}
- var r *Node
switch t.Etype {
default:
- Yyerror("invalid type for composite literal: %v", t)
+ yyerror("invalid type for composite literal: %v", t)
n.Type = nil
case TARRAY, TSLICE:
- // Only allocate hash if there are some key/value pairs.
- var hash map[int64]*Node
+ // If there are key/value pairs, create a map to keep seen
+ // keys so we can check for duplicate indices.
+ var indices map[int64]bool
for _, n1 := range n.List.Slice() {
if n1.Op == OKEY {
- hash = make(map[int64]*Node)
+ indices = make(map[int64]bool)
break
}
}
- length := int64(0)
- i := 0
+
+ var length, i int64
checkBounds := t.IsArray() && !t.isDDDArray()
- for i2, n2 := range n.List.Slice() {
- l := n2
+ nl := n.List.Slice()
+ for i2, l := range nl {
setlineno(l)
- if l.Op != OKEY {
- l = Nod(OKEY, Nodintconst(int64(i)), l)
- l.Left.Type = Types[TINT]
- l.Left.Typecheck = 1
- n.List.SetIndex(i2, l)
+ vp := &nl[i2]
+ if l.Op == OKEY {
+ l.Left = typecheck(l.Left, Erv)
+ evconst(l.Left)
+ i = nonnegintconst(l.Left)
+ if i < 0 && !l.Left.Diag {
+ yyerror("index must be non-negative integer constant")
+ l.Left.Diag = true
+ i = -(1 << 30) // stay negative for a while
+ }
+ vp = &l.Right
}
- l.Left = typecheck(l.Left, Erv)
- evconst(l.Left)
- i = nonnegconst(l.Left)
- if i < 0 && l.Left.Diag == 0 {
- Yyerror("index must be non-negative integer constant")
- l.Left.Diag = 1
- i = -(1 << 30) // stay negative for a while
+ if i >= 0 && indices != nil {
+ if indices[i] {
+ yyerror("duplicate index in array literal: %d", i)
+ } else {
+ indices[i] = true
+ }
}
- if i >= 0 && hash != nil {
- indexdup(l.Left, hash)
- }
+ r := *vp
+ pushtype(r, t.Elem())
+ r = typecheck(r, Erv)
+ r = defaultlit(r, t.Elem())
+ *vp = assignconv(r, t.Elem(), "array or slice literal")
+
i++
- if int64(i) > length {
- length = int64(i)
+ if i > length {
+ length = i
if checkBounds && length > t.NumElem() {
setlineno(l)
- Yyerror("array index %d out of bounds [0:%d]", length-1, t.NumElem())
+ yyerror("array index %d out of bounds [0:%d]", length-1, t.NumElem())
checkBounds = false
}
}
-
- r = l.Right
- pushtype(r, t.Elem())
- r = typecheck(r, Erv)
- r = defaultlit(r, t.Elem())
- l.Right = assignconv(r, t.Elem(), "array or slice literal")
}
if t.isDDDArray() {
t.SetNumElem(length)
}
if t.IsSlice() {
- n.Right = Nodintconst(length)
+ n.Right = nodintconst(length)
+ n.Op = OSLICELIT
+ } else {
+ n.Op = OARRAYLIT
}
- n.Op = OARRAYLIT
case TMAP:
hash := make(map[uint32][]*Node)
- var l *Node
- for i3, n3 := range n.List.Slice() {
- l = n3
+ for i3, l := range n.List.Slice() {
setlineno(l)
if l.Op != OKEY {
n.List.SetIndex(i3, typecheck(n.List.Index(i3), Erv))
- Yyerror("missing key in map literal")
+ yyerror("missing key in map literal")
continue
}
- r = l.Left
+ r := l.Left
pushtype(r, t.Key())
r = typecheck(r, Erv)
r = defaultlit(r, t.Key())
@@ -2975,9 +3018,8 @@ func typecheckcomplit(n *Node) *Node {
bad := 0
if n.List.Len() != 0 && nokeys(n.List) {
// simple list of variables
- f, it := IterFields(t)
+ f, it := iterFields(t)
- var s *Sym
ls := n.List.Slice()
for i1, n1 := range ls {
setlineno(n1)
@@ -2985,28 +3027,26 @@ func typecheckcomplit(n *Node) *Node {
n1 = ls[i1]
if f == nil {
if bad == 0 {
- Yyerror("too many values in struct initializer")
+ yyerror("too many values in struct initializer")
}
bad++
continue
}
- s = f.Sym
+ 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)
+ yyerror("implicit assignment of unexported field '%s' in %v literal", s.Name, t)
}
// No pushtype allowed here. Must name fields for that.
n1 = assignconv(n1, f.Type, "field value")
- n1 = Nod(OKEY, newname(f.Sym), n1)
- n1.Left.Type = structkey
- n1.Left.Xoffset = f.Offset
- n1.Left.Typecheck = 1
+ n1 = nodSym(OSTRUCTKEY, n1, f.Sym)
+ n1.Xoffset = f.Offset
ls[i1] = n1
f = it.Next()
}
if f != nil {
- Yyerror("too few values in struct initializer")
+ yyerror("too few values in struct initializer")
}
} else {
hash := make(map[string]bool)
@@ -3015,55 +3055,57 @@ func typecheckcomplit(n *Node) *Node {
ls := n.List.Slice()
for i, l := range ls {
setlineno(l)
- if l.Op != OKEY {
- if bad == 0 {
- Yyerror("mixture of field:value and value initializers")
- }
- bad++
- ls[i] = typecheck(ls[i], Erv)
- continue
- }
- s := l.Left.Sym
+ if l.Op == OKEY {
+ key := l.Left
+
+ l.Op = OSTRUCTKEY
+ l.Left = l.Right
+ l.Right = nil
+
+ // An OXDOT uses the Sym field to hold
+ // the field to the right of the dot,
+ // so s will be non-nil, but an OXDOT
+ // is never a valid struct literal key.
+ if key.Sym == nil || key.Op == OXDOT {
+ yyerror("invalid field name %v in struct initializer", key)
+ l.Left = typecheck(l.Left, Erv)
+ continue
+ }
- // An OXDOT uses the Sym field to hold
- // the field to the right of the dot,
- // so s will be non-nil, but an OXDOT
- // is never a valid struct literal key.
- if s == nil || l.Left.Op == OXDOT {
- Yyerror("invalid field name %v in struct initializer", l.Left)
- l.Right = typecheck(l.Right, Erv)
- continue
+ // Sym might have resolved to name in other top-level
+ // package, because of import dot. Redirect to correct sym
+ // before we do the lookup.
+ s := key.Sym
+ if s.Pkg != localpkg && exportname(s.Name) {
+ s1 := lookup(s.Name)
+ if s1.Origpkg == s.Pkg {
+ s = s1
+ }
+ }
+ l.Sym = s
}
- // Sym might have resolved to name in other top-level
- // package, because of import dot. Redirect to correct sym
- // before we do the lookup.
- if s.Pkg != localpkg && exportname(s.Name) {
- s1 := Lookup(s.Name)
- if s1.Origpkg == s.Pkg {
- s = s1
+ if l.Op != OSTRUCTKEY {
+ if bad == 0 {
+ yyerror("mixture of field:value and value initializers")
}
+ bad++
+ ls[i] = typecheck(ls[i], Erv)
+ continue
}
- f := lookdot1(nil, s, t, t.Fields(), 0)
+ f := lookdot1(nil, l.Sym, t, t.Fields(), 0)
if f == nil {
- Yyerror("unknown %v field '%v' in struct literal", t, s)
+ yyerror("unknown field '%v' in struct literal of type %v", l.Sym, t)
continue
}
-
- l.Left = newname(s)
- l.Left.Type = structkey
- l.Left.Xoffset = f.Offset
- l.Left.Typecheck = 1
- s = f.Sym
- fielddup(newname(s), hash)
- r = l.Right
+ fielddup(f.Sym.Name, hash)
+ l.Xoffset = f.Offset
// No pushtype allowed here. Tried and rejected.
- r = typecheck(r, Erv)
-
- l.Right = assignconv(r, f.Type, "field value")
+ l.Left = typecheck(l.Left, Erv)
+ l.Left = assignconv(l.Left, f.Type, "field value")
}
}
@@ -3071,13 +3113,12 @@ func typecheckcomplit(n *Node) *Node {
}
if nerr != nerrors {
- n.Type = nil
return n
}
n.Orig = norig
if n.Type.IsPtr() {
- n = Nod(OPTRLIT, n, nil)
+ n = nod(OPTRLIT, n, nil)
n.Typecheck = 1
n.Type = n.Left.Type
n.Left.Type = t
@@ -3117,7 +3158,7 @@ func islvalue(n *Node) bool {
func checklvalue(n *Node, verb string) {
if !islvalue(n) {
- Yyerror("cannot %s %v", verb, n)
+ yyerror("cannot %s %v", verb, n)
}
}
@@ -3153,11 +3194,11 @@ func checkassign(stmt *Node, n *Node) {
}
if n.Op == ODOT && n.Left.Op == OINDEXMAP {
- Yyerror("cannot assign to struct field %v in map", n)
+ yyerror("cannot assign to struct field %v in map", n)
return
}
- Yyerror("cannot assign to %v", n)
+ yyerror("cannot assign to %v", n)
}
func checkassignlist(stmt *Node, l Nodes) {
@@ -3169,7 +3210,7 @@ func checkassignlist(stmt *Node, l Nodes) {
// Check whether l and r are the same side effect-free expression,
// so that it is safe to reuse one instead of computing both.
func samesafeexpr(l *Node, r *Node) bool {
- if l.Op != r.Op || !Eqtype(l.Type, r.Type) {
+ if l.Op != r.Op || !eqtype(l.Type, r.Type) {
return false
}
@@ -3180,11 +3221,19 @@ func samesafeexpr(l *Node, r *Node) bool {
case ODOT, ODOTPTR:
return l.Sym != nil && r.Sym != nil && l.Sym == r.Sym && samesafeexpr(l.Left, r.Left)
- case OIND:
+ case OIND, OCONVNOP:
return samesafeexpr(l.Left, r.Left)
+ case OCONV:
+ // Some conversions can't be reused, such as []byte(str).
+ // Allow only numeric-ish types. This is a bit conservative.
+ return issimple[l.Type.Etype] && samesafeexpr(l.Left, r.Left)
+
case OINDEX:
return samesafeexpr(l.Left, r.Left) && samesafeexpr(l.Right, r.Right)
+
+ case OLITERAL:
+ return eqval(l.Val(), r.Val())
}
return false
@@ -3234,7 +3283,7 @@ func checkassignto(src *Type, dst *Node) {
var why string
if assignop(src, dst.Type, &why) == 0 {
- Yyerror("cannot assign %v to %v in multiple assignment%s", src, Nconv(dst, FmtLong), why)
+ yyerror("cannot assign %v to %L in multiple assignment%s", src, dst, why)
return
}
}
@@ -3298,7 +3347,7 @@ func typecheckas2(n *Node) {
goto mismatch
}
n.Op = OAS2FUNC
- t, s := IterFields(r.Type)
+ t, s := iterFields(r.Type)
for _, n3 := range n.List.Slice() {
if t.Type != nil && n3.Type != nil {
checkassignto(t.Type, n3)
@@ -3350,7 +3399,7 @@ func typecheckas2(n *Node) {
}
mismatch:
- Yyerror("assignment count mismatch: %d = %d", cl, cr)
+ yyerror("assignment count mismatch: %d = %d", cl, cr)
// second half of dance
out:
@@ -3365,6 +3414,12 @@ 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) {
+ ln.Name.Decldepth = 1
+ }
+ }
+
n.Func.Nname = typecheck(n.Func.Nname, Erv|Easgn)
t := n.Func.Nname.Type
if t == nil {
@@ -3374,13 +3429,7 @@ func typecheckfunc(n *Node) {
t.SetNname(n.Func.Nname)
rcvr := t.Recv()
if rcvr != nil && n.Func.Shortname != nil {
- addmethod(n.Func.Shortname.Sym, t, nil, true, n.Func.Pragma&Nointerface != 0)
- }
-
- for _, ln := range n.Func.Dcl {
- if ln.Op == ONAME && (ln.Class == PPARAM || ln.Class == PPARAMOUT) {
- ln.Name.Decldepth = 1
- }
+ addmethod(n.Func.Shortname.Sym, t, true, n.Func.Pragma&Nointerface != 0)
}
}
@@ -3396,18 +3445,18 @@ func stringtoarraylit(n *Node) *Node {
if n.Type.Elem().Etype == TUINT8 {
// []byte
for i := 0; i < len(s); i++ {
- l = append(l, Nod(OKEY, Nodintconst(int64(i)), Nodintconst(int64(s[0]))))
+ l = append(l, nod(OKEY, nodintconst(int64(i)), nodintconst(int64(s[0]))))
}
} else {
// []rune
i := 0
for _, r := range s {
- l = append(l, Nod(OKEY, Nodintconst(int64(i)), Nodintconst(int64(r))))
+ l = append(l, nod(OKEY, nodintconst(int64(i)), nodintconst(int64(r))))
i++
}
}
- nn := Nod(OCOMPLIT, nil, typenod(n.Type))
+ nn := nod(OCOMPLIT, nil, typenod(n.Type))
nn.List.Set(l)
nn = typecheck(nn, Erv)
return nn
@@ -3424,7 +3473,7 @@ func domethod(n *Node) {
// type check failed; leave empty func
// TODO(mdempsky): Fix Type rekinding.
n.Type.Etype = TFUNC
- n.Type.Nod = nil
+ n.Type.nod = nil
return
}
@@ -3444,7 +3493,7 @@ func domethod(n *Node) {
// TODO(mdempsky): Fix Type rekinding.
*n.Type = *nt.Type
- n.Type.Nod = nil
+ n.Type.nod = nil
checkwidth(n.Type)
}
@@ -3466,6 +3515,9 @@ func copytype(n *Node, t *Type) {
embedlineno := n.Type.ForwardType().Embedlineno
l := n.Type.ForwardType().Copyto
+ ptrTo := n.Type.ptrTo
+ sliceOf := n.Type.sliceOf
+
// TODO(mdempsky): Fix Type rekinding.
*n.Type = *t
@@ -3477,9 +3529,15 @@ func copytype(n *Node, t *Type) {
}
t.methods = Fields{}
t.allMethods = Fields{}
- t.Nod = nil
- t.Printed = false
+ t.nod = nil
t.Deferwidth = false
+ t.ptrTo = ptrTo
+ 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
+ }
// Update nodes waiting on this type.
for _, n := range l {
@@ -3492,7 +3550,7 @@ func copytype(n *Node, t *Type) {
if embedlineno != 0 {
lineno = embedlineno
if t.IsPtr() || t.IsUnsafePtr() {
- Yyerror("embedded type cannot be a pointer")
+ yyerror("embedded type cannot be a pointer")
}
}
@@ -3508,13 +3566,13 @@ func typecheckdeftype(n *Node) {
n.Name.Param.Ntype = typecheck(n.Name.Param.Ntype, Etype)
t := n.Name.Param.Ntype.Type
if t == nil {
- n.Diag = 1
+ n.Diag = true
n.Type = nil
goto ret
}
if n.Type == nil {
- n.Diag = 1
+ n.Diag = true
goto ret
}
@@ -3544,7 +3602,7 @@ ret:
for _, e := range mapqueue {
lineno = e.lno
if !e.n.Type.IsComparable() {
- Yyerror("invalid map key type %v", e.n.Type)
+ yyerror("invalid map key type %v", e.n.Type)
}
}
mapqueue = nil
@@ -3568,15 +3626,15 @@ func typecheckdef(n *Node) *Node {
setlineno(n)
if n.Op == ONONAME {
- if n.Diag == 0 {
- n.Diag = 1
+ if !n.Diag {
+ n.Diag = true
if n.Lineno != 0 {
lineno = n.Lineno
}
// Note: adderrorname looks for this string and
// adds context about the outer expression
- Yyerror("undefined: %v", n.Sym)
+ yyerror("undefined: %v", n.Sym)
}
return n
@@ -3588,7 +3646,7 @@ func typecheckdef(n *Node) *Node {
typecheckdefstack = append(typecheckdefstack, n)
if n.Walkdef == 2 {
- Flusherrors()
+ flusherrors()
fmt.Printf("typecheckdef loop:")
for i := len(typecheckdefstack) - 1; i >= 0; i-- {
n := typecheckdefstack[i]
@@ -3608,9 +3666,8 @@ func typecheckdef(n *Node) *Node {
default:
Fatalf("typecheckdef %v", n.Op)
- // not really syms
- case OGOTO, OLABEL:
- break
+ case OGOTO, OLABEL, OPACK:
+ // nothing to do here
case OLITERAL:
if n.Name.Param.Ntype != nil {
@@ -3618,7 +3675,7 @@ func typecheckdef(n *Node) *Node {
n.Type = n.Name.Param.Ntype.Type
n.Name.Param.Ntype = nil
if n.Type == nil {
- n.Diag = 1
+ n.Diag = true
goto ret
}
}
@@ -3628,19 +3685,19 @@ func typecheckdef(n *Node) *Node {
if e == nil {
lineno = n.Lineno
Dump("typecheckdef nil defn", n)
- Yyerror("xxx")
+ yyerror("xxx")
}
e = typecheck(e, Erv)
if Isconst(e, CTNIL) {
- Yyerror("const initializer cannot be nil")
+ yyerror("const initializer cannot be nil")
goto ret
}
if e.Type != nil && e.Op != OLITERAL || !isgoconst(e) {
- if e.Diag == 0 {
- Yyerror("const initializer %v is not a constant", e)
- e.Diag = 1
+ if !e.Diag {
+ yyerror("const initializer %v is not a constant", e)
+ e.Diag = true
}
goto ret
@@ -3649,12 +3706,12 @@ func typecheckdef(n *Node) *Node {
t := n.Type
if t != nil {
if !okforconst[t.Etype] {
- Yyerror("invalid constant type %v", t)
+ yyerror("invalid constant type %v", t)
goto ret
}
- if !e.Type.IsUntyped() && !Eqtype(t, e.Type) {
- Yyerror("cannot use %v as type %v in const initializer", Nconv(e, FmtLong), t)
+ if !e.Type.IsUntyped() && !eqtype(t, e.Type) {
+ yyerror("cannot use %L as type %v in const initializer", e, t)
goto ret
}
@@ -3669,7 +3726,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 = 1
+ n.Diag = true
goto ret
}
}
@@ -3718,10 +3775,6 @@ func typecheckdef(n *Node) *Node {
if Curfn != nil {
resumecheckwidth()
}
-
- // nothing to see here
- case OPACK:
- break
}
ret:
@@ -3741,37 +3794,27 @@ ret:
}
func checkmake(t *Type, arg string, n *Node) bool {
- if n.Op == OLITERAL {
- switch n.Val().Ctype() {
- case CTINT, CTRUNE, CTFLT, CTCPLX:
- n.SetVal(toint(n.Val()))
- if n.Val().U.(*Mpint).CmpInt64(0) < 0 {
- Yyerror("negative %s argument in make(%v)", arg, t)
- return false
- }
-
- if n.Val().U.(*Mpint).Cmp(Maxintval[TINT]) > 0 {
- Yyerror("%s argument too large in make(%v)", arg, t)
- return false
- }
-
- // Delay defaultlit until after we've checked range, to avoid
- // a redundant "constant NNN overflows int" error.
- n = defaultlit(n, Types[TINT])
-
- return true
-
- default:
- break
- }
- }
-
if !n.Type.IsInteger() && n.Type.Etype != TIDEAL {
- Yyerror("non-integer %s argument in make(%v) - %v", arg, t, n.Type)
+ yyerror("non-integer %s argument in make(%v) - %v", arg, t, n.Type)
return false
}
- // Defaultlit still necessary for non-constant: n might be 1<<k.
+ // Do range checks for constants before defaultlit
+ // to avoid redundant "constant NNN overflows int" errors.
+ switch consttype(n) {
+ case CTINT, CTRUNE, CTFLT, CTCPLX:
+ n.SetVal(toint(n.Val()))
+ if n.Val().U.(*Mpint).CmpInt64(0) < 0 {
+ yyerror("negative %s argument in make(%v)", arg, t)
+ return false
+ }
+ if n.Val().U.(*Mpint).Cmp(maxintval[TINT]) > 0 {
+ yyerror("%s argument too large in make(%v)", arg, t)
+ return false
+ }
+ }
+
+ // defaultlit is necessary for non-constants too: n might be 1.1<<k.
n = defaultlit(n, Types[TINT])
return true
@@ -3791,7 +3834,7 @@ func markbreak(n *Node, implicit *Node) {
} else {
lab := n.Left.Sym.Label
if lab != nil {
- lab.Def.SetHasBreak(true)
+ lab.SetHasBreak(true)
}
}
@@ -3816,12 +3859,13 @@ func markbreaklist(l Nodes, implicit *Node) {
s := l.Slice()
for i := 0; i < len(s); i++ {
n := s[i]
+ if n == nil {
+ continue
+ }
if n.Op == OLABEL && i+1 < len(s) && n.Name.Defn == s[i+1] {
switch n.Name.Defn.Op {
case OFOR, OSWITCH, OTYPESW, OSELECT, ORANGE:
- lab := new(Label)
- lab.Def = n.Name.Defn
- n.Left.Sym.Label = lab
+ n.Left.Sym.Label = n.Name.Defn
markbreak(n.Name.Defn, n.Name.Defn)
n.Left.Sym.Label = nil
i++
diff --git a/src/cmd/compile/internal/gc/universe.go b/src/cmd/compile/internal/gc/universe.go
index 270d4c3..30c9c37 100644
--- a/src/cmd/compile/internal/gc/universe.go
+++ b/src/cmd/compile/internal/gc/universe.go
@@ -27,7 +27,6 @@ var basicTypes = [...]struct {
{"complex128", TCOMPLEX128},
{"bool", TBOOL},
{"string", TSTRING},
- {"any", TANY},
}
var typedefs = [...]struct {
@@ -63,6 +62,15 @@ var builtinFuncs = [...]struct {
{"recover", ORECOVER},
}
+var unsafeFuncs = [...]struct {
+ name string
+ op Op
+}{
+ {"Alignof", OALIGNOF},
+ {"Offsetof", OOFFSETOF},
+ {"Sizeof", OSIZEOF},
+}
+
// initUniverse initializes the universe block.
func initUniverse() {
lexinit()
@@ -94,29 +102,37 @@ func lexinit() {
for _, s := range builtinFuncs {
// TODO(marvin): Fix Node.EType type union.
s2 := Pkglookup(s.name, builtinpkg)
- s2.Def = Nod(ONAME, nil, nil)
+ s2.Def = nod(ONAME, nil, nil)
+ s2.Def.Sym = s2
+ s2.Def.Etype = 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)
}
idealstring = typ(TSTRING)
idealbool = typ(TBOOL)
+ Types[TANY] = typ(TANY)
s := Pkglookup("true", builtinpkg)
- s.Def = Nodbool(true)
- s.Def.Sym = Lookup("true")
+ s.Def = nodbool(true)
+ s.Def.Sym = lookup("true")
s.Def.Name = new(Name)
s.Def.Type = idealbool
s = Pkglookup("false", builtinpkg)
- s.Def = Nodbool(false)
- s.Def.Sym = Lookup("false")
+ s.Def = nodbool(false)
+ s.Def.Sym = lookup("false")
s.Def.Name = new(Name)
s.Def.Type = idealbool
- s = Lookup("_")
+ s = lookup("_")
s.Block = -100
- s.Def = Nod(ONAME, nil, nil)
+ s.Def = nod(ONAME, nil, nil)
s.Def.Sym = s
Types[TBLANK] = typ(TBLANK)
s.Def.Type = Types[TBLANK]
@@ -124,7 +140,7 @@ func lexinit() {
s = Pkglookup("_", builtinpkg)
s.Block = -100
- s.Def = Nod(ONAME, nil, nil)
+ s.Def = nod(ONAME, nil, nil)
s.Def.Sym = s
Types[TBLANK] = typ(TBLANK)
s.Def.Type = Types[TBLANK]
@@ -138,7 +154,7 @@ func lexinit() {
s.Def.Name = new(Name)
s = Pkglookup("iota", builtinpkg)
- s.Def = Nod(OIOTA, nil, nil)
+ s.Def = nod(OIOTA, nil, nil)
s.Def.Sym = s
s.Def.Name = new(Name)
}
@@ -149,7 +165,7 @@ func typeinit() {
}
for et := EType(0); et < NTYPE; et++ {
- Simtype[et] = et
+ simtype[et] = et
}
Types[TPTR32] = typ(TPTR32)
@@ -163,7 +179,6 @@ func typeinit() {
t.Sym = Pkglookup("Pointer", unsafepkg)
t.Sym.Def = typenod(t)
t.Sym.Def.Name = new(Name)
-
dowidth(Types[TUNSAFEPTR])
Tptr = TPTR32
@@ -172,23 +187,23 @@ func typeinit() {
}
for et := TINT8; et <= TUINT64; et++ {
- Isint[et] = true
+ isInt[et] = true
}
- Isint[TINT] = true
- Isint[TUINT] = true
- Isint[TUINTPTR] = true
+ isInt[TINT] = true
+ isInt[TUINT] = true
+ isInt[TUINTPTR] = true
- Isfloat[TFLOAT32] = true
- Isfloat[TFLOAT64] = true
+ isFloat[TFLOAT32] = true
+ isFloat[TFLOAT64] = true
- Iscomplex[TCOMPLEX64] = true
- Iscomplex[TCOMPLEX128] = true
+ isComplex[TCOMPLEX64] = true
+ isComplex[TCOMPLEX128] = true
isforw[TFORW] = true
// initialize okfor
for et := EType(0); et < NTYPE; et++ {
- if Isint[et] || et == TIDEAL {
+ if isInt[et] || et == TIDEAL {
okforeq[et] = true
okforcmp[et] = true
okforarith[et] = true
@@ -196,11 +211,11 @@ func typeinit() {
okforand[et] = true
okforconst[et] = true
issimple[et] = true
- Minintval[et] = new(Mpint)
- Maxintval[et] = new(Mpint)
+ minintval[et] = new(Mpint)
+ maxintval[et] = new(Mpint)
}
- if Isfloat[et] {
+ if isFloat[et] {
okforeq[et] = true
okforcmp[et] = true
okforadd[et] = true
@@ -211,7 +226,7 @@ func typeinit() {
maxfltval[et] = newMpflt()
}
- if Iscomplex[et] {
+ if isComplex[et] {
okforeq[et] = true
okforadd[et] = true
okforarith[et] = true
@@ -303,19 +318,19 @@ func typeinit() {
iscmp[OEQ] = true
iscmp[ONE] = true
- Maxintval[TINT8].SetString("0x7f")
- Minintval[TINT8].SetString("-0x80")
- Maxintval[TINT16].SetString("0x7fff")
- Minintval[TINT16].SetString("-0x8000")
- Maxintval[TINT32].SetString("0x7fffffff")
- Minintval[TINT32].SetString("-0x80000000")
- Maxintval[TINT64].SetString("0x7fffffffffffffff")
- Minintval[TINT64].SetString("-0x8000000000000000")
+ maxintval[TINT8].SetString("0x7f")
+ minintval[TINT8].SetString("-0x80")
+ maxintval[TINT16].SetString("0x7fff")
+ minintval[TINT16].SetString("-0x8000")
+ maxintval[TINT32].SetString("0x7fffffff")
+ minintval[TINT32].SetString("-0x80000000")
+ maxintval[TINT64].SetString("0x7fffffffffffffff")
+ minintval[TINT64].SetString("-0x8000000000000000")
- Maxintval[TUINT8].SetString("0xff")
- Maxintval[TUINT16].SetString("0xffff")
- Maxintval[TUINT32].SetString("0xffffffff")
- Maxintval[TUINT64].SetString("0xffffffffffffffff")
+ maxintval[TUINT8].SetString("0xff")
+ maxintval[TUINT16].SetString("0xffff")
+ maxintval[TUINT32].SetString("0xffffffff")
+ maxintval[TUINT64].SetString("0xffffffffffffffff")
// f is valid float if min < f < max. (min and max are not themselves valid.)
maxfltval[TFLOAT32].SetString("33554431p103") // 2^24-1 p (127-23) + 1/2 ulp
@@ -338,19 +353,19 @@ func typeinit() {
Types[TINTER] = typ(TINTER)
// simple aliases
- Simtype[TMAP] = Tptr
+ simtype[TMAP] = Tptr
- Simtype[TCHAN] = Tptr
- Simtype[TFUNC] = Tptr
- Simtype[TUNSAFEPTR] = Tptr
+ simtype[TCHAN] = Tptr
+ simtype[TFUNC] = Tptr
+ simtype[TUNSAFEPTR] = Tptr
- Array_array = int(Rnd(0, int64(Widthptr)))
- Array_nel = int(Rnd(int64(Array_array)+int64(Widthptr), int64(Widthint)))
- Array_cap = int(Rnd(int64(Array_nel)+int64(Widthint), int64(Widthint)))
- sizeof_Array = int(Rnd(int64(Array_cap)+int64(Widthint), int64(Widthptr)))
+ array_array = int(Rnd(0, int64(Widthptr)))
+ array_nel = int(Rnd(int64(array_array)+int64(Widthptr), int64(Widthint)))
+ array_cap = int(Rnd(int64(array_nel)+int64(Widthint), int64(Widthint)))
+ sizeof_Array = int(Rnd(int64(array_cap)+int64(Widthint), int64(Widthptr)))
// string is same as slice wo the cap
- sizeof_String = int(Rnd(int64(Array_nel)+int64(Widthint), int64(Widthptr)))
+ sizeof_String = int(Rnd(int64(array_nel)+int64(Widthint), int64(Widthptr)))
dowidth(Types[TSTRING])
dowidth(idealstring)
@@ -359,32 +374,16 @@ func typeinit() {
}
func makeErrorInterface() *Type {
- rcvr := typ(TSTRUCT)
- rcvr.StructType().Funarg = FunargRcvr
field := newField()
- field.Type = Ptrto(typ(TSTRUCT))
- rcvr.SetFields([]*Field{field})
-
- in := typ(TSTRUCT)
- in.StructType().Funarg = FunargParams
-
- out := typ(TSTRUCT)
- out.StructType().Funarg = FunargResults
- field = newField()
field.Type = Types[TSTRING]
- out.SetFields([]*Field{field})
-
- f := typ(TFUNC)
- *f.RecvsP() = rcvr
- *f.ResultsP() = out
- *f.ParamsP() = in
+ f := functypefield(fakethisfield(), nil, []*Field{field})
- t := typ(TINTER)
field = newField()
- field.Sym = Lookup("Error")
+ field.Sym = lookup("Error")
field.Type = f
- t.SetFields([]*Field{field})
+ t := typ(TINTER)
+ t.SetFields([]*Field{field})
return t
}
@@ -422,11 +421,11 @@ func lexinit1() {
sameas = s.sameas64
}
- Simtype[s.etype] = sameas
+ simtype[s.etype] = sameas
minfltval[s.etype] = minfltval[sameas]
maxfltval[s.etype] = maxfltval[sameas]
- Minintval[s.etype] = Minintval[sameas]
- Maxintval[s.etype] = Maxintval[sameas]
+ minintval[s.etype] = minintval[sameas]
+ maxintval[s.etype] = maxintval[sameas]
t := typ(s.etype)
t.Sym = s1
@@ -446,10 +445,10 @@ func finishUniverse() {
// package block rather than emitting a redeclared symbol error.
for _, s := range builtinpkg.Syms {
- if s.Def == nil || (s.Name == "any" && Debug['A'] == 0) {
+ if s.Def == nil {
continue
}
- s1 := Lookup(s.Name)
+ s1 := lookup(s.Name)
if s1.Def != nil {
continue
}
@@ -458,9 +457,9 @@ func finishUniverse() {
s1.Block = s.Block
}
- nodfp = Nod(ONAME, nil, nil)
+ nodfp = nod(ONAME, nil, nil)
nodfp.Type = Types[TINT32]
nodfp.Xoffset = 0
nodfp.Class = PPARAM
- nodfp.Sym = Lookup(".fp")
+ nodfp.Sym = lookup(".fp")
}
diff --git a/src/cmd/compile/internal/gc/unsafe.go b/src/cmd/compile/internal/gc/unsafe.go
index fc6ed1f..0ae97b4 100644
--- a/src/cmd/compile/internal/gc/unsafe.go
+++ b/src/cmd/compile/internal/gc/unsafe.go
@@ -4,126 +4,71 @@
package gc
-// unsafenmagic rewrites calls to package unsafe's functions into constants.
-func unsafenmagic(nn *Node) *Node {
- fn := nn.Left
- args := nn.List
-
- if safemode || fn == nil || fn.Op != ONAME {
- return nil
- }
- s := fn.Sym
- if s == nil {
- return nil
- }
- if s.Pkg != unsafepkg {
- return nil
- }
-
- if args.Len() == 0 {
- Yyerror("missing argument for %v", s)
- return nil
- }
-
- r := args.First()
-
- var v int64
- switch s.Name {
- case "Alignof", "Sizeof":
- r = typecheck(r, Erv)
- r = defaultlit(r, nil)
- tr := r.Type
+// evalunsafe evaluates a package unsafe operation and returns the result.
+func evalunsafe(n *Node) int64 {
+ switch n.Op {
+ case OALIGNOF, OSIZEOF:
+ n.Left = typecheck(n.Left, Erv)
+ n.Left = defaultlit(n.Left, nil)
+ tr := n.Left.Type
if tr == nil {
- goto bad
+ yyerror("invalid expression %v", n)
+ return 0
}
dowidth(tr)
- if s.Name == "Alignof" {
- v = int64(tr.Align)
- } else {
- v = tr.Width
+ if n.Op == OALIGNOF {
+ return int64(tr.Align)
}
+ return tr.Width
- case "Offsetof":
+ case OOFFSETOF:
// must be a selector.
- if r.Op != OXDOT {
- goto bad
+ if n.Left.Op != OXDOT {
+ yyerror("invalid expression %v", n)
+ return 0
}
// Remember base of selector to find it back after dot insertion.
// Since r->left may be mutated by typechecking, check it explicitly
// first to track it correctly.
- r.Left = typecheck(r.Left, Erv)
- base := r.Left
+ n.Left.Left = typecheck(n.Left.Left, Erv)
+ base := n.Left.Left
- r = typecheck(r, Erv)
- switch r.Op {
+ n.Left = typecheck(n.Left, Erv)
+ switch n.Left.Op {
case ODOT, ODOTPTR:
break
case OCALLPART:
- Yyerror("invalid expression %v: argument is a method value", nn)
- goto ret
+ yyerror("invalid expression %v: argument is a method value", n)
+ return 0
default:
- goto bad
+ yyerror("invalid expression %v", n)
+ return 0
}
// Sum offsets for dots until we reach base.
- for r1 := r; r1 != base; r1 = r1.Left {
- switch r1.Op {
+ var v int64
+ for r := n.Left; r != base; r = r.Left {
+ switch r.Op {
case ODOTPTR:
// For Offsetof(s.f), s may itself be a pointer,
// but accessing f must not otherwise involve
// indirection via embedded pointer types.
- if r1.Left != base {
- Yyerror("invalid expression %v: selector implies indirection of embedded %v", nn, r1.Left)
- goto ret
+ if r.Left != base {
+ yyerror("invalid expression %v: selector implies indirection of embedded %v", n, r.Left)
+ return 0
}
fallthrough
case ODOT:
- v += r1.Xoffset
+ v += r.Xoffset
default:
- Dump("unsafenmagic", r)
- Fatalf("impossible %#v node after dot insertion", r1.Op)
- goto bad
+ Dump("unsafenmagic", n.Left)
+ Fatalf("impossible %#v node after dot insertion", r.Op)
}
}
-
- default:
- return nil
+ return v
}
- if args.Len() > 1 {
- Yyerror("extra arguments for %v", s)
- }
- goto ret
-
-bad:
- Yyerror("invalid expression %v", nn)
-
-ret:
- // any side effects disappear; ignore init
- var val Val
- val.U = new(Mpint)
- val.U.(*Mpint).SetInt64(v)
- n := Nod(OLITERAL, nil, nil)
- n.Orig = nn
- n.SetVal(val)
- n.Type = Types[TUINTPTR]
- nn.Type = Types[TUINTPTR]
- return n
-}
-
-func isunsafebuiltin(n *Node) bool {
- if n == nil || n.Op != ONAME || n.Sym == nil || n.Sym.Pkg != unsafepkg {
- return false
- }
- if n.Sym.Name == "Sizeof" {
- return true
- }
- if n.Sym.Name == "Offsetof" {
- return true
- }
- if n.Sym.Name == "Alignof" {
- return true
- }
- return false
+ Fatalf("unexpected op %v", n.Op)
+ return 0
}
diff --git a/src/cmd/compile/internal/gc/util.go b/src/cmd/compile/internal/gc/util.go
index 18e990a..bb5cede 100644
--- a/src/cmd/compile/internal/gc/util.go
+++ b/src/cmd/compile/internal/gc/util.go
@@ -16,7 +16,7 @@ func (n *Node) Line() string {
var atExitFuncs []func()
-func AtExit(f func()) {
+func atExit(f func()) {
atExitFuncs = append(atExitFuncs, f)
}
@@ -33,6 +33,8 @@ var (
cpuprofile string
memprofile string
memprofilerate int64
+ traceprofile string
+ traceHandler func(string)
)
func startProfile() {
@@ -44,7 +46,7 @@ func startProfile() {
if err := pprof.StartCPUProfile(f); err != nil {
Fatalf("%v", err)
}
- AtExit(pprof.StopCPUProfile)
+ atExit(pprof.StopCPUProfile)
}
if memprofile != "" {
if memprofilerate != 0 {
@@ -54,11 +56,14 @@ func startProfile() {
if err != nil {
Fatalf("%v", err)
}
- AtExit(func() {
+ atExit(func() {
runtime.GC() // profile all outstanding allocations
if err := pprof.WriteHeapProfile(f); err != nil {
Fatalf("%v", err)
}
})
}
+ 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 66eb7e9..8248d50 100644
--- a/src/cmd/compile/internal/gc/walk.go
+++ b/src/cmd/compile/internal/gc/walk.go
@@ -50,11 +50,11 @@ func walk(fn *Node) {
continue
}
lineno = defn.Left.Lineno
- Yyerror("%v declared and not used", ln.Sym)
+ yyerror("%v declared and not used", ln.Sym)
defn.Left.Used = true // suppress repeats
} else {
lineno = ln.Lineno
- Yyerror("%v declared and not used", ln.Sym)
+ yyerror("%v declared and not used", ln.Sym)
}
}
@@ -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")
+ yyerror("call arg not assignment")
}
lhs = arg.Left
if lhs.Op == ONAME {
@@ -128,8 +128,8 @@ func adjustargs(n *Node, adjust int) {
continue
}
- if lhs.Op != OINDREG {
- Yyerror("call argument store does not use OINDREG")
+ if lhs.Op != OINDREGSP {
+ yyerror("call argument store does not use OINDREGSP")
}
// can't really check this in machine-indep code.
@@ -145,7 +145,7 @@ func walkstmt(n *Node) *Node {
if n == nil {
return n
}
- if n.Dodata == 2 { // don't walk, generated by anylit.
+ if n.IsStatic { // don't walk, generated by anylit.
return n
}
@@ -156,9 +156,9 @@ func walkstmt(n *Node) *Node {
switch n.Op {
default:
if n.Op == ONAME {
- Yyerror("%v is not a top level statement", n.Sym)
+ yyerror("%v is not a top level statement", n.Sym)
} else {
- Yyerror("%v is not a top level statement", n.Op)
+ yyerror("%v is not a top level statement", n.Op)
}
Dump("nottop", n)
@@ -184,7 +184,7 @@ func walkstmt(n *Node) *Node {
ORECOVER,
OGETG:
if n.Typecheck == 0 {
- Fatalf("missing typecheck: %v", Nconv(n, FmtSign))
+ Fatalf("missing typecheck: %+v", n)
}
wascopy := n.Op == OCOPY
init := n.Ninit
@@ -195,11 +195,11 @@ func walkstmt(n *Node) *Node {
n.Op = OEMPTY // don't leave plain values as statements.
}
- // special case for a receive where we throw away
+ // special case for a receive where we throw away
// the value received.
case ORECV:
if n.Typecheck == 0 {
- Fatalf("missing typecheck: %v", Nconv(n, FmtSign))
+ Fatalf("missing typecheck: %+v", n)
}
init := n.Ninit
n.Ninit.Set(nil)
@@ -226,12 +226,12 @@ func walkstmt(n *Node) *Node {
v := n.Left
if v.Class == PAUTOHEAP {
if compiling_runtime {
- Yyerror("%v escapes to heap, not allowed in runtime.", v)
+ 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 := nod(OAS, v.Name.Heapaddr, prealloc[v])
nn.Colas = true
nn = typecheck(nn, Etop)
return walkstmt(nn)
@@ -241,7 +241,7 @@ func walkstmt(n *Node) *Node {
walkstmtlist(n.List.Slice())
case OXCASE:
- Yyerror("case statement out of place")
+ yyerror("case statement out of place")
n.Op = OCASE
fallthrough
@@ -314,7 +314,7 @@ func walkstmt(n *Node) *Node {
}
if cl == PPARAMOUT {
if ln.isParamStackCopy() {
- ln = walkexpr(typecheck(Nod(OIND, ln.Name.Heapaddr, nil), Erv), nil)
+ ln = walkexpr(typecheck(nod(OIND, ln.Name.Heapaddr, nil), Erv), nil)
}
rl = append(rl, ln)
}
@@ -361,12 +361,12 @@ func walkstmt(n *Node) *Node {
walkrange(n)
case OXFALL:
- Yyerror("fallthrough statement out of place")
+ yyerror("fallthrough statement out of place")
n.Op = OFALL
}
if n.Op == ONAME {
- Fatalf("walkstmt ended up with name: %v", Nconv(n, FmtSign))
+ Fatalf("walkstmt ended up with name: %+v", n)
}
return n
}
@@ -382,7 +382,7 @@ func isSmallMakeSlice(n *Node) bool {
}
t := n.Type
- return Smallintconst(l) && Smallintconst(r) && (t.Elem().Width == 0 || r.Int64() < (1<<16)/t.Elem().Width)
+ return smallintconst(l) && smallintconst(r) && (t.Elem().Width == 0 || r.Int64() < (1<<16)/t.Elem().Width)
}
// walk the whole tree of the body of an
@@ -410,16 +410,14 @@ func walkexprlistcheap(s []*Node, init *Nodes) {
}
}
-// Build name of function: convI2E etc.
+// Build name of function for interface conversion.
// Not all names are possible
-// (e.g., we'll never generate convE2E or convE2I).
+// (e.g., we'll never generate convE2E or convE2I or convI2E).
func convFuncName(from, to *Type) string {
tkind := to.iet()
switch from.iet() {
case 'I':
switch tkind {
- case 'E':
- return "convI2E"
case 'I':
return "convI2I"
}
@@ -435,38 +433,6 @@ func convFuncName(from, to *Type) string {
panic("unreachable")
}
-// Build name of function: assertI2E etc.
-// If with2suffix is true, the form ending in "2" is returned".
-func assertFuncName(from, to *Type, with2suffix bool) string {
- l := len("assertX2X2")
- if !with2suffix {
- l--
- }
- tkind := to.iet()
- switch from.iet() {
- case 'E':
- switch tkind {
- case 'I':
- return "assertE2I2"[:l]
- case 'E':
- return "assertE2E2"[:l]
- case 'T':
- return "assertE2T2"[:l]
- }
- case 'I':
- switch tkind {
- case 'I':
- return "assertI2I2"[:l]
- case 'E':
- return "assertI2E2"[:l]
- case 'T':
- return "assertI2T2"[:l]
- }
- }
- Fatalf("unknown assert func %c2%c", from.iet(), to.iet())
- panic("unreachable")
-}
-
// The result of walkexpr MUST be assigned back to n, e.g.
// n.Left = walkexpr(n.Left, init)
func walkexpr(n *Node, init *Nodes) *Node {
@@ -486,13 +452,6 @@ func walkexpr(n *Node, init *Nodes) *Node {
init.AppendNodes(&n.Ninit)
}
- // annoying case - not typechecked
- if n.Op == OKEY {
- n.Left = walkexpr(n.Left, init)
- n.Right = walkexpr(n.Right, init)
- return n
- }
-
lno := setlineno(n)
if Debug['w'] > 1 {
@@ -500,24 +459,26 @@ func walkexpr(n *Node, init *Nodes) *Node {
}
if n.Typecheck != 1 {
- Fatalf("missed typecheck: %v\n", Nconv(n, FmtSign))
+ Fatalf("missed typecheck: %+v", n)
}
if n.Op == ONAME && n.Class == PAUTOHEAP {
- nn := Nod(OIND, n.Name.Heapaddr, nil)
+ nn := nod(OIND, n.Name.Heapaddr, nil)
nn = typecheck(nn, Erv)
- return walkexpr(nn, init)
+ nn = walkexpr(nn, init)
+ nn.Left.NonNil = true
+ return nn
}
opswitch:
switch n.Op {
default:
Dump("walk", n)
- Fatalf("walkexpr: switch 1 unknown op %v", Nconv(n, FmtShort|FmtSign))
+ Fatalf("walkexpr: switch 1 unknown op %+S", n)
case OTYPE,
ONONAME,
- OINDREG,
+ OINDREGSP,
OEMPTY,
OGETG:
@@ -553,7 +514,7 @@ opswitch:
n.Left = walkexpr(n.Left, init)
n.Right = walkexpr(n.Right, init)
- case OSPTR, OITAB:
+ case OSPTR, OITAB, OIDATA:
n.Left = walkexpr(n.Left, init)
case OLEN, OCAP:
@@ -629,6 +590,7 @@ opswitch:
n.Right = walkexpr(n.Right, &ll)
n.Right = addinit(n.Right, ll.Slice())
+ n = walkinrange(n, init)
case OPRINT, OPRINTN:
walkexprlist(n.List.Slice(), init)
@@ -638,7 +600,7 @@ opswitch:
n = mkcall("gopanic", nil, init, n.Left)
case ORECOVER:
- n = mkcall("gorecover", n.Type, init, Nod(OADDR, nodfp, nil))
+ n = mkcall("gorecover", n.Type, init, nod(OADDR, nodfp, nil))
case OLITERAL:
n.Addable = true
@@ -666,7 +628,7 @@ opswitch:
// transformclosure already did all preparation work.
// Prepend captured variables to argument list.
- n.List.Set(append(n.Left.Func.Enter.Slice(), n.List.Slice()...))
+ n.List.Prepend(n.Left.Func.Enter.Slice()...)
n.Left.Func.Enter.Set(nil)
@@ -690,8 +652,9 @@ 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" {
- if Thearch.LinkArch.InFamily(sys.AMD64, sys.ARM, sys.ARM64, sys.PPC64, sys.S390X) {
+ 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)
@@ -726,7 +689,8 @@ opswitch:
break
}
- if n.Right == nil || iszero(n.Right) && !instrumenting {
+ if n.Right == nil {
+ // TODO(austin): Check all "implicit zeroing"
break
}
@@ -734,40 +698,12 @@ opswitch:
default:
n.Right = walkexpr(n.Right, init)
- case ODOTTYPE:
- // TODO(rsc): The Isfat is for consistency with componentgen and orderexpr.
- // It needs to be removed in all three places.
- // That would allow inlining x.(struct{*int}) the same as x.(*int).
- if isdirectiface(n.Right.Type) && !Isfat(n.Right.Type) && !instrumenting {
- // handled directly during cgen
- n.Right = walkexpr(n.Right, init)
- break
- }
-
- // x = i.(T); n.Left is x, n.Right.Left is i.
- // orderstmt made sure x is addressable.
- n.Right.Left = walkexpr(n.Right.Left, init)
-
- n1 := Nod(OADDR, n.Left, nil)
- r := n.Right // i.(T)
-
- if Debug_typeassert > 0 {
- Warn("type assertion not inlined")
- }
-
- fn := syslook(assertFuncName(r.Left.Type, r.Type, false))
- fn = substArgTypes(fn, r.Left.Type, r.Type)
-
- n = mkcall1(fn, nil, init, typename(r.Type), r.Left, n1)
- n = walkexpr(n, init)
- break opswitch
-
case ORECV:
// x = <-c; n.Left is x, n.Right.Left is c.
// orderstmt made sure x is addressable.
n.Right.Left = walkexpr(n.Right.Left, init)
- n1 := Nod(OADDR, n.Left, nil)
+ 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 = walkexpr(n, init)
@@ -776,6 +712,9 @@ opswitch:
case OAPPEND:
// x = append(...)
r := n.Right
+ if r.Type.Elem().NotInHeap {
+ yyerror("%v is go:notinheap; heap allocation disallowed", r.Type.Elem())
+ }
if r.Isddd {
r = appendslice(r, init) // also works for append(slice, string).
} else {
@@ -792,9 +731,9 @@ opswitch:
}
if n.Left != nil && n.Right != nil {
- dd := n.Dodata
+ static := n.IsStatic
n = convas(n, init)
- n.Dodata = dd
+ n.IsStatic = static
n = applywritebarrier(n)
}
@@ -809,7 +748,7 @@ opswitch:
}
n = liststmt(ll)
- // a,b,... = fn()
+ // a,b,... = fn()
case OAS2FUNC:
init.AppendNodes(&n.Ninit)
@@ -817,13 +756,19 @@ opswitch:
walkexprlistsafe(n.List.Slice(), init)
r = walkexpr(r, init)
- ll := ascompatet(n.Op, n.List, r.Type, 0, init)
+ if isIntrinsicCall(r) {
+ n.Rlist.Set1(r)
+ break
+ }
+ init.Append(r)
+
+ ll := ascompatet(n.Op, n.List, r.Type)
for i, n := range ll {
ll[i] = applywritebarrier(n)
}
- n = liststmt(append([]*Node{r}, ll...))
+ n = liststmt(ll)
- // x, y = <-c
+ // x, y = <-c
// orderstmt made sure x is addressable.
case OAS2RECV:
init.AppendNodes(&n.Ninit)
@@ -835,12 +780,13 @@ opswitch:
if isblank(n.List.First()) {
n1 = nodnil()
} else {
- n1 = Nod(OADDR, n.List.First(), nil)
+ n1 = nod(OADDR, n.List.First(), nil)
}
n1.Etype = 1 // addr does not escape
fn := chanfn("chanrecv2", 2, r.Left.Type)
- r = mkcall1(fn, n.List.Second().Type, init, typename(r.Left.Type), r.Left, n1)
- n = Nod(OAS, n.List.Second(), r)
+ ok := n.List.Second()
+ call := mkcall1(fn, ok.Type, init, typename(r.Left.Type), r.Left, n1)
+ n = nod(OAS, ok, call)
n = typecheck(n, Etop)
// a,b = m[i];
@@ -871,7 +817,7 @@ opswitch:
} else {
// standard version takes key by reference
// orderexpr made sure key is addressable.
- key = Nod(OADDR, r.Right, nil)
+ key = nod(OADDR, r.Right, nil)
p = "mapaccess2"
}
@@ -895,21 +841,21 @@ opswitch:
// mapaccess2* returns a typed bool, but due to spec changes,
// the boolean result of i.(T) is now untyped so we make it the
// same type as the variable on the lhs.
- if !isblank(n.List.Second()) {
- r.Type.Field(1).Type = n.List.Second().Type
+ if ok := n.List.Second(); !isblank(ok) && ok.Type.IsBoolean() {
+ r.Type.Field(1).Type = ok.Type
}
n.Rlist.Set1(r)
n.Op = OAS2FUNC
// don't generate a = *var if a is _
if !isblank(a) {
- var_ := temp(Ptrto(t.Val()))
+ var_ := temp(ptrto(t.Val()))
var_.Typecheck = 1
var_.NonNil = true // mapaccess always returns a non-nil pointer
n.List.SetIndex(0, var_)
n = walkexpr(n, init)
init.Append(n)
- n = Nod(OAS, a, Nod(OIND, var_, nil))
+ n = nod(OAS, a, nod(OIND, var_, nil))
}
n = typecheck(n, Etop)
@@ -923,88 +869,17 @@ opswitch:
key = walkexpr(key, init)
// orderstmt made sure key is addressable.
- key = Nod(OADDR, key, nil)
+ key = nod(OADDR, key, nil)
t := map_.Type
n = mkcall1(mapfndel("mapdelete", t), nil, init, typename(t), map_, key)
case OAS2DOTTYPE:
- e := n.Rlist.First() // i.(T)
- // TODO(rsc): The Isfat is for consistency with componentgen and orderexpr.
- // It needs to be removed in all three places.
- // That would allow inlining x.(struct{*int}) the same as x.(*int).
- if isdirectiface(e.Type) && !Isfat(e.Type) && !instrumenting {
- // handled directly during gen.
- walkexprlistsafe(n.List.Slice(), init)
- e.Left = walkexpr(e.Left, init)
- break
- }
-
- // res, ok = i.(T)
- // orderstmt made sure a is addressable.
- init.AppendNodes(&n.Ninit)
-
walkexprlistsafe(n.List.Slice(), init)
+ e := n.Rlist.First() // i.(T)
e.Left = walkexpr(e.Left, init)
- t := e.Type // T
- from := e.Left // i
-
- oktype := Types[TBOOL]
- ok := n.List.Second()
- if !isblank(ok) {
- oktype = ok.Type
- }
-
- fromKind := from.Type.iet()
- toKind := t.iet()
-
- // Avoid runtime calls in a few cases of the form _, ok := i.(T).
- // This is faster and shorter and allows the corresponding assertX2X2
- // routines to skip nil checks on their last argument.
- if isblank(n.List.First()) {
- var fast *Node
- switch {
- case fromKind == 'E' && toKind == 'T':
- tab := Nod(OITAB, from, nil) // type:eface::tab:iface
- typ := Nod(OCONVNOP, typename(t), nil)
- typ.Type = Ptrto(Types[TUINTPTR])
- fast = Nod(OEQ, tab, typ)
- case fromKind == 'I' && toKind == 'E',
- fromKind == 'E' && toKind == 'E':
- tab := Nod(OITAB, from, nil)
- fast = Nod(ONE, nodnil(), tab)
- }
- if fast != nil {
- if Debug_typeassert > 0 {
- Warn("type assertion (ok only) inlined")
- }
- n = Nod(OAS, ok, fast)
- n = typecheck(n, Etop)
- break
- }
- }
-
- var resptr *Node // &res
- if isblank(n.List.First()) {
- resptr = nodnil()
- } else {
- resptr = Nod(OADDR, n.List.First(), nil)
- }
- resptr.Etype = 1 // addr does not escape
-
- if Debug_typeassert > 0 {
- Warn("type assertion not inlined")
- }
- fn := syslook(assertFuncName(from.Type, t, true))
- fn = substArgTypes(fn, from.Type, t)
- call := mkcall1(fn, oktype, init, typename(t), from, resptr)
- n = Nod(OAS, ok, call)
- n = typecheck(n, Etop)
case ODOTTYPE, ODOTTYPE2:
- if !isdirectiface(n.Type) || Isfat(n.Type) {
- Fatalf("walkexpr ODOTTYPE") // should see inside OAS only
- }
n.Left = walkexpr(n.Left, init)
case OCONVIFACE:
@@ -1018,12 +893,59 @@ opswitch:
} else {
t = itabname(n.Left.Type, n.Type)
}
- l := Nod(OEFACE, t, n.Left)
+ l := nod(OEFACE, t, n.Left)
l.Type = n.Type
l.Typecheck = 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))
+ 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.Type = n.Type
+ l.Typecheck = n.Typecheck
+ n = l
+ break
+ }
+
+ // Implement interface to empty interface conversion.
+ // tmp = i.itab
+ // if tmp != nil {
+ // tmp = tmp.type
+ // }
+ // e = iface{tmp, i.data}
+ if n.Type.IsEmptyInterface() && n.Left.Type.IsInterface() && !n.Left.Type.IsEmptyInterface() {
+ // Evaluate the input interface.
+ c := temp(n.Left.Type)
+ init.Append(nod(OAS, c, n.Left))
+
+ // Get the itab out of the interface.
+ tmp := temp(ptrto(Types[TUINT8]))
+ init.Append(nod(OAS, tmp, typecheck(nod(OITAB, c, nil), Erv)))
+
+ // Get the type out of the itab.
+ nif := nod(OIF, typecheck(nod(ONE, tmp, nodnil()), Erv), nil)
+ nif.Nbody.Set1(nod(OAS, tmp, itabType(tmp)))
+ init.Append(nif)
+
+ // Build the result.
+ e := nod(OEFACE, tmp, ifaceData(c, ptrto(Types[TUINT8])))
+ e.Type = n.Type // assign type manually, typecheck doesn't understand OEFACE.
+ e.Typecheck = 1
+ n = e
+ break
+ }
var ll []*Node
if n.Type.IsEmptyInterface() {
@@ -1048,38 +970,23 @@ opswitch:
// with non-interface cases, is not visible to orderstmt, so we
// have to fall back on allocating a temp here.
if islvalue(n.Left) {
- ll = append(ll, Nod(OADDR, n.Left, nil))
+ ll = append(ll, nod(OADDR, n.Left, nil))
} else {
- ll = append(ll, Nod(OADDR, copyexpr(n.Left, n.Left.Type, init), nil))
+ ll = append(ll, nod(OADDR, copyexpr(n.Left, n.Left.Type, init), nil))
}
dowidth(n.Left.Type)
- r := nodnil()
- if n.Esc == EscNone && n.Left.Type.Width <= 1024 {
- // Allocate stack buffer for value stored in interface.
- r = temp(n.Left.Type)
- r = Nod(OAS, r, nil) // zero temp
- r = typecheck(r, Etop)
- init.Append(r)
- r = Nod(OADDR, r.Left, nil)
- r = typecheck(r, Erv)
- }
- ll = append(ll, r)
}
fn := syslook(convFuncName(n.Left.Type, n.Type))
- if !n.Left.Type.IsInterface() {
- fn = substArgTypes(fn, n.Left.Type, n.Left.Type, n.Type)
- } else {
- fn = substArgTypes(fn, n.Left.Type, n.Type)
- }
+ fn = substArgTypes(fn, n.Left.Type, n.Type)
dowidth(fn.Type)
- n = Nod(OCALL, fn, nil)
+ n = nod(OCALL, fn, nil)
n.List.Set(ll)
n = typecheck(n, Erv)
n = walkexpr(n, init)
case OCONV, OCONVNOP:
- if Thearch.LinkArch.Family == sys.ARM {
+ 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]))
@@ -1094,12 +1001,45 @@ opswitch:
if n.Type.IsFloat() {
if n.Left.Type.Etype == TINT64 {
- n = mkcall("int64tofloat64", n.Type, init, conv(n.Left, Types[TINT64]))
+ n = conv(mkcall("int64tofloat64", Types[TFLOAT64], init, conv(n.Left, Types[TINT64])), n.Type)
break
}
if n.Left.Type.Etype == TUINT64 {
- n = mkcall("uint64tofloat64", n.Type, init, conv(n.Left, Types[TUINT64]))
+ n = conv(mkcall("uint64tofloat64", Types[TFLOAT64], init, conv(n.Left, Types[TUINT64])), n.Type)
+ break
+ }
+ }
+ }
+
+ 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]))
+ break
+ }
+
+ if n.Type.Etype == TUINT64 {
+ n = mkcall("float64touint64", n.Type, init, conv(n.Left, 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]))
+ 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)
+ break
+ }
+
+ if n.Left.Type.Etype == TUINT64 {
+ n = conv(mkcall("uint64tofloat64", Types[TFLOAT64], init, conv(n.Left, 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)
break
}
}
@@ -1110,7 +1050,7 @@ opswitch:
case OANDNOT:
n.Left = walkexpr(n.Left, init)
n.Op = OAND
- n.Right = Nod(OCOM, n.Right, nil)
+ n.Right = nod(OCOM, n.Right, nil)
n.Right = typecheck(n.Right, Erv)
n.Right = walkexpr(n.Right, init)
@@ -1126,7 +1066,7 @@ opswitch:
// rewrite complex div into function call.
et := n.Left.Type.Etype
- if Iscomplex[et] && n.Op == ODIV {
+ if isComplex[et] && n.Op == ODIV {
t := n.Type
n = mkcall("complex128div", Types[TCOMPLEX128], init, conv(n.Left, Types[TCOMPLEX128]), conv(n.Right, Types[TCOMPLEX128]))
n = conv(n, t)
@@ -1134,7 +1074,7 @@ opswitch:
}
// Nothing to do for float divisions.
- if Isfloat[et] {
+ if isFloat[et] {
break
}
@@ -1185,75 +1125,69 @@ opswitch:
if Debug['m'] != 0 && n.Bounded && !Isconst(n.Right, CTINT) {
Warn("index bounds check elided")
}
- if Smallintconst(n.Right) && !n.Bounded {
- Yyerror("index out of bounds")
+ if smallintconst(n.Right) && !n.Bounded {
+ yyerror("index out of bounds")
}
} else if Isconst(n.Left, CTSTR) {
n.Bounded = bounded(r, int64(len(n.Left.Val().U.(string))))
if Debug['m'] != 0 && n.Bounded && !Isconst(n.Right, CTINT) {
Warn("index bounds check elided")
}
- if Smallintconst(n.Right) {
- if !n.Bounded {
- Yyerror("index out of bounds")
- } else {
- // replace "abc"[1] with 'b'.
- // delayed until now because "abc"[1] is not
- // an ideal constant.
- v := n.Right.Int64()
-
- Nodconst(n, n.Type, int64(n.Left.Val().U.(string)[v]))
- n.Typecheck = 1
- }
+ if smallintconst(n.Right) && !n.Bounded {
+ yyerror("index out of bounds")
}
}
if Isconst(n.Right, CTINT) {
- if n.Right.Val().U.(*Mpint).CmpInt64(0) < 0 || n.Right.Val().U.(*Mpint).Cmp(Maxintval[TINT]) > 0 {
- Yyerror("index out of bounds")
+ if n.Right.Val().U.(*Mpint).CmpInt64(0) < 0 || n.Right.Val().U.(*Mpint).Cmp(maxintval[TINT]) > 0 {
+ yyerror("index out of bounds")
}
}
case OINDEXMAP:
- if n.Etype == 1 {
- break
- }
+ // Replace m[k] with *map{access1,assign}(maptype, m, &k)
n.Left = walkexpr(n.Left, init)
n.Right = walkexpr(n.Right, init)
-
- t := n.Left.Type
- 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"
+ map_ := n.Left
+ key := n.Right
+ 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)
+ } 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"
+ }
}
- }
- var key *Node
- if p != "" {
- // fast versions take key by value
- key = n.Right
- } else {
- // standard version takes key by reference.
- // orderexpr made sure key is addressable.
- key = Nod(OADDR, n.Right, nil)
- p = "mapaccess1"
- }
+ if p == "" {
+ // 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), n.Left, key)
- } else {
- p = "mapaccess1_fat"
- z := zeroaddr(w)
- n = mkcall1(mapfn(p, t), Ptrto(t.Val()), init, typename(t), n.Left, key, z)
+ 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)
+ } else {
+ p = "mapaccess1_fat"
+ z := zeroaddr(w)
+ n = mkcall1(mapfn(p, t), ptrto(t.Val()), init, typename(t), map_, key, z)
+ }
}
- n.NonNil = true // mapaccess always returns a non-nil pointer
- n = Nod(OIND, n, nil)
+ n.Type = ptrto(t.Val())
+ n.NonNil = true // mapaccess1* and mapassign always return non-nil pointers.
+ n = nod(OIND, n, nil)
n.Type = t.Val()
n.Typecheck = 1
@@ -1294,34 +1228,21 @@ opswitch:
Fatalf("large ONEW with EscNone: %v", n)
}
r := temp(n.Type.Elem())
- r = Nod(OAS, r, nil) // zero temp
+ r = nod(OAS, r, nil) // zero temp
r = typecheck(r, Etop)
init.Append(r)
- r = Nod(OADDR, r.Left, nil)
+ r = nod(OADDR, r.Left, nil)
r = typecheck(r, Erv)
n = r
} else {
n = callnew(n.Type.Elem())
}
- // If one argument to the comparison is an empty string,
- // comparing the lengths instead will yield the same result
- // without the function call.
case OCMPSTR:
- if (Isconst(n.Left, CTSTR) && len(n.Left.Val().U.(string)) == 0) || (Isconst(n.Right, CTSTR) && len(n.Right.Val().U.(string)) == 0) {
- // TODO(marvin): Fix Node.EType type union.
- r := Nod(Op(n.Etype), Nod(OLEN, n.Left, nil), Nod(OLEN, n.Right, nil))
- r = typecheck(r, Erv)
- r = walkexpr(r, init)
- r.Type = n.Type
- n = r
- break
- }
-
// s + "badgerbadgerbadger" == "badgerbadgerbadger"
if (Op(n.Etype) == OEQ || Op(n.Etype) == ONE) && Isconst(n.Right, CTSTR) && n.Left.Op == OADDSTR && n.Left.List.Len() == 2 && Isconst(n.Left.List.Second(), CTSTR) && strlit(n.Right) == strlit(n.Left.List.Second()) {
// TODO(marvin): Fix Node.EType type union.
- r := Nod(Op(n.Etype), Nod(OLEN, n.Left.List.First(), nil), Nodintconst(0))
+ r := nod(Op(n.Etype), nod(OLEN, n.Left.List.First(), nil), nodintconst(0))
r = typecheck(r, Erv)
r = walkexpr(r, init)
r.Type = n.Type
@@ -1329,12 +1250,61 @@ opswitch:
break
}
+ // Rewrite comparisons to short constant strings as length+byte-wise comparisons.
+ var cs, ncs *Node // const string, non-const string
+ switch {
+ case Isconst(n.Left, CTSTR) && Isconst(n.Right, CTSTR):
+ // ignore; will be constant evaluated
+ case Isconst(n.Left, CTSTR):
+ cs = n.Left
+ ncs = n.Right
+ case Isconst(n.Right, CTSTR):
+ cs = n.Right
+ ncs = n.Left
+ }
+ if cs != nil {
+ cmp := Op(n.Etype)
+ // maxRewriteLen was chosen empirically.
+ // It is the value that minimizes cmd/go file size
+ // across most architectures.
+ // See the commit description for CL 26758 for details.
+ maxRewriteLen := 6
+ var and Op
+ switch cmp {
+ case OEQ:
+ and = OANDAND
+ case ONE:
+ and = OOROR
+ default:
+ // Don't do byte-wise comparisons for <, <=, etc.
+ // They're fairly complicated.
+ // Length-only checks are ok, though.
+ maxRewriteLen = 0
+ }
+ if s := cs.Val().U.(string); len(s) <= maxRewriteLen {
+ if len(s) > 0 {
+ ncs = safeexpr(ncs, init)
+ }
+ // 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))
+ }
+ r = typecheck(r, Erv)
+ r = walkexpr(r, init)
+ r.Type = n.Type
+ n = r
+ break
+ }
+ }
+
var r *Node
// TODO(marvin): Fix Node.EType type union.
if Op(n.Etype) == OEQ || Op(n.Etype) == ONE {
// prepare for rewrite below
n.Left = cheapexpr(n.Left, init)
-
n.Right = cheapexpr(n.Right, init)
r = mkcall("eqstring", Types[TBOOL], init, conv(n.Left, Types[TSTRING]), conv(n.Right, Types[TSTRING]))
@@ -1344,12 +1314,11 @@ opswitch:
// TODO(marvin): Fix Node.EType type union.
if Op(n.Etype) == OEQ {
// len(left) == len(right) && eqstring(left, right)
- r = Nod(OANDAND, Nod(OEQ, Nod(OLEN, n.Left, nil), Nod(OLEN, n.Right, nil)), r)
+ r = nod(OANDAND, nod(OEQ, nod(OLEN, n.Left, nil), nod(OLEN, n.Right, nil)), r)
} else {
// len(left) != len(right) || !eqstring(left, right)
- r = Nod(ONOT, r, nil)
-
- r = Nod(OOROR, Nod(ONE, Nod(OLEN, n.Left, nil), Nod(OLEN, n.Right, nil)), r)
+ r = nod(ONOT, r, nil)
+ r = nod(OOROR, nod(ONE, nod(OLEN, n.Left, nil), nod(OLEN, n.Right, nil)), r)
}
r = typecheck(r, Erv)
@@ -1357,9 +1326,8 @@ opswitch:
} else {
// sys_cmpstring(s1, s2) :: 0
r = mkcall("cmpstring", Types[TINT], init, conv(n.Left, Types[TSTRING]), conv(n.Right, Types[TSTRING]))
-
// TODO(marvin): Fix Node.EType type union.
- r = Nod(Op(n.Etype), r, Nodintconst(0))
+ r = nod(Op(n.Etype), r, nodintconst(0))
}
r = typecheck(r, Erv)
@@ -1377,7 +1345,7 @@ opswitch:
Fatalf("append outside assignment")
case OCOPY:
- n = copyany(n, init, instrumenting)
+ n = copyany(n, init, instrumenting && !compiling_runtime)
// cannot use chanfn - closechan takes any, not chan any
case OCLOSE:
@@ -1398,20 +1366,20 @@ opswitch:
// Allocate hmap buffer on stack.
var_ := temp(hmap(t))
- a = Nod(OAS, var_, nil) // zero temp
+ a = nod(OAS, var_, nil) // zero temp
a = typecheck(a, Etop)
init.Append(a)
- a = Nod(OADDR, var_, nil)
+ a = nod(OADDR, var_, nil)
// Allocate one bucket on stack.
// Maximum key/value size is 128 bytes, larger objects
// are stored with an indirection. So max bucket size is 2048+eps.
var_ = temp(mapbucket(t))
- r = Nod(OAS, var_, nil) // zero temp
+ r = nod(OAS, var_, nil) // zero temp
r = typecheck(r, Etop)
init.Append(r)
- r = Nod(OADDR, var_, nil)
+ r = nod(OADDR, var_, nil)
}
fn := syslook("makemap")
@@ -1432,31 +1400,51 @@ opswitch:
}
// var arr [r]T
// n = arr[:l]
- t = aindex(r, t.Elem()) // [r]T
+ t = typArray(t.Elem(), nonnegintconst(r)) // [r]T
var_ := temp(t)
- a := Nod(OAS, var_, nil) // zero temp
+ a := nod(OAS, var_, nil) // zero temp
a = typecheck(a, Etop)
init.Append(a)
- r := Nod(OSLICE, var_, nil) // arr[:l]
+ r := nod(OSLICE, var_, nil) // arr[:l]
r.SetSliceBounds(nil, l, nil)
r = conv(r, n.Type) // in case n.Type is named.
r = typecheck(r, Erv)
r = walkexpr(r, init)
n = r
} else {
- // makeslice(et *Type, nel int64, max int64) (ary []any)
- fn := syslook("makeslice")
+ // n escapes; set up a call to makeslice.
+ // 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 {
+ yyerror("%v is go:notinheap; heap allocation disallowed", t.Elem())
+ }
+
+ len, cap := l, r
+
+ fnname := "makeslice64"
+ argtype := 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
+ // will be handled by the negative range checks in makeslice during runtime.
+ 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]
+ }
+ fn := syslook(fnname)
fn = substArgTypes(fn, t.Elem()) // any-1
- n = mkcall1(fn, n.Type, init, typename(t.Elem()), conv(l, Types[TINT64]), conv(r, Types[TINT64]))
+ n = mkcall1(fn, t, init, typename(t.Elem()), conv(len, argtype), conv(cap, argtype))
}
case ORUNESTR:
a := nodnil()
if n.Esc == EscNone {
- t := aindex(Nodintconst(4), Types[TUINT8])
+ t := typArray(Types[TUINT8], 4)
var_ := temp(t)
- a = Nod(OADDR, var_, nil)
+ a = nod(OADDR, var_, nil)
}
// intstring(*[4]byte, rune)
@@ -1466,9 +1454,9 @@ opswitch:
a := nodnil()
if n.Esc == EscNone {
// Create temporary buffer for string on stack.
- t := aindex(Nodintconst(tmpstringbufsize), Types[TUINT8])
+ t := typArray(Types[TUINT8], tmpstringbufsize)
- a = Nod(OADDR, temp(t), nil)
+ a = nod(OADDR, temp(t), nil)
}
// slicebytetostring(*[32]byte, []byte) string;
@@ -1476,6 +1464,14 @@ opswitch:
// slicebytetostringtmp([]byte) string;
case OARRAYBYTESTRTMP:
+ n.Left = walkexpr(n.Left, init)
+
+ if !instrumenting {
+ // Let the backend handle OARRAYBYTESTRTMP directly
+ // to avoid a function call to slicebytetostringtmp.
+ break
+ }
+
n = mkcall("slicebytetostringtmp", n.Type, init, n.Left)
// slicerunetostring(*[32]byte, []rune) string;
@@ -1484,9 +1480,9 @@ opswitch:
if n.Esc == EscNone {
// Create temporary buffer for string on stack.
- t := aindex(Nodintconst(tmpstringbufsize), Types[TUINT8])
+ t := typArray(Types[TUINT8], tmpstringbufsize)
- a = Nod(OADDR, temp(t), nil)
+ a = nod(OADDR, temp(t), nil)
}
n = mkcall("slicerunetostring", n.Type, init, a, n.Left)
@@ -1497,16 +1493,22 @@ opswitch:
if n.Esc == EscNone {
// Create temporary buffer for slice on stack.
- t := aindex(Nodintconst(tmpstringbufsize), Types[TUINT8])
+ t := typArray(Types[TUINT8], tmpstringbufsize)
- a = Nod(OADDR, temp(t), nil)
+ a = nod(OADDR, temp(t), nil)
}
n = mkcall("stringtoslicebyte", n.Type, init, a, conv(n.Left, Types[TSTRING]))
- // stringtoslicebytetmp(string) []byte;
case OSTRARRAYBYTETMP:
- n = mkcall("stringtoslicebytetmp", n.Type, init, conv(n.Left, Types[TSTRING]))
+ // []byte(string) conversion that creates a slice
+ // referring to the actual string bytes.
+ // This conversion is handled later by the backend and
+ // is only for use by internal compiler optimizations
+ // that know that the slice won't be mutated.
+ // The only such case today is:
+ // for i, c := range []byte(string)
+ n.Left = walkexpr(n.Left, init)
// stringtoslicerune(*[32]rune, string) []rune
case OSTRARRAYRUNE:
@@ -1514,16 +1516,16 @@ opswitch:
if n.Esc == EscNone {
// Create temporary buffer for slice on stack.
- t := aindex(Nodintconst(tmpstringbufsize), Types[TINT32])
+ t := typArray(Types[TINT32], tmpstringbufsize)
- a = Nod(OADDR, temp(t), nil)
+ a = nod(OADDR, temp(t), nil)
}
n = mkcall("stringtoslicerune", n.Type, init, a, n.Left)
// ifaceeq(i1 any-1, i2 any-2) (ret bool);
case OCMPIFACE:
- if !Eqtype(n.Left.Type, n.Right.Type) {
+ if !eqtype(n.Left.Type, n.Right.Type) {
Fatalf("ifaceeq %v %v %v", n.Op, n.Left.Type, n.Right.Type)
}
var fn *Node
@@ -1539,44 +1541,41 @@ opswitch:
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)
+ r = nod(ONOT, r, nil)
}
// check itable/type before full compare.
// TODO(marvin): Fix Node.EType type union.
if Op(n.Etype) == OEQ {
- r = Nod(OANDAND, Nod(OEQ, Nod(OITAB, n.Left, nil), Nod(OITAB, n.Right, nil)), r)
+ r = nod(OANDAND, nod(OEQ, nod(OITAB, n.Left, nil), nod(OITAB, n.Right, nil)), r)
} else {
- r = Nod(OOROR, Nod(ONE, Nod(OITAB, n.Left, nil), Nod(OITAB, n.Right, nil)), r)
+ r = nod(OOROR, nod(ONE, nod(OITAB, n.Left, nil), nod(OITAB, n.Right, nil)), r)
}
r = typecheck(r, Erv)
r = walkexpr(r, init)
r.Type = n.Type
n = r
- case OARRAYLIT, OMAPLIT, OSTRUCTLIT, OPTRLIT:
+ case OARRAYLIT, OSLICELIT, OMAPLIT, OSTRUCTLIT, OPTRLIT:
if isStaticCompositeLiteral(n) {
// n can be directly represented in the read-only data section.
// Make direct reference to the static data. See issue 12841.
- vstat := staticname(n.Type, 0)
- if n.Op == OSTRUCTLIT {
- structlit(0, 1, n, vstat, init)
- } else {
- arraylit(0, 1, n, vstat, init)
- }
+ vstat := staticname(n.Type)
+ vstat.Name.Readonly = true
+ fixedlit(inInitFunction, initKindStatic, n, vstat, init)
n = vstat
n = typecheck(n, Erv)
break
}
var_ := temp(n.Type)
- anylit(0, n, var_, init)
+ anylit(n, var_, init)
n = var_
case OSEND:
n1 := n.Right
n1 = assignconv(n1, n.Left.Type.Elem(), "chan send")
n1 = walkexpr(n1, init)
- n1 = Nod(OADDR, n1, nil)
+ n1 = nod(OADDR, n1, nil)
n = mkcall1(chanfn("chansend1", 2, n.Left.Type), nil, init, typename(n.Left.Type), n.Left, n1)
case OCLOSURE:
@@ -1630,7 +1629,7 @@ func reduceSlice(n *Node) *Node {
func ascompatee1(op Op, l *Node, r *Node, init *Nodes) *Node {
// convas will turn map assigns into function calls,
// making it impossible for reorder3 to work.
- n := Nod(OAS, l, r)
+ n := nod(OAS, l, r)
if l.Op == OINDEXMAP {
return n
@@ -1670,7 +1669,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]", hconv(nln, FmtSign), op, hconv(nrn, FmtSign), len(nl), len(nr), Curfn.Func.Nname.Sym.Name)
+ yyerror("error in shape across %+v %v %+v / %d %d [%s]", nln, op, nrn, len(nl), len(nr), Curfn.Func.Nname.Sym.Name)
}
return nn
}
@@ -1687,7 +1686,7 @@ func fncall(l *Node, rt *Type) bool {
if needwritebarrier(l, &r) {
return true
}
- if Eqtype(l.Type, rt) {
+ if eqtype(l.Type, rt) {
return false
}
return true
@@ -1696,10 +1695,10 @@ 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, fp int, init *Nodes) []*Node {
- r, saver := IterFields(nr)
+func ascompatet(op Op, nl Nodes, nr *Type) []*Node {
+ r, saver := iterFields(nr)
- var nn, mm []*Node
+ var nn, mm Nodes
var ullmanOverflow bool
var i int
for i = 0; i < nl.Len(); i++ {
@@ -1718,32 +1717,32 @@ func ascompatet(op Op, nl Nodes, nr *Type, fp int, init *Nodes) []*Node {
if fncall(l, r.Type) {
tmp := temp(r.Type)
tmp = typecheck(tmp, Erv)
- a := Nod(OAS, l, tmp)
- a = convas(a, init)
- mm = append(mm, a)
+ a := nod(OAS, l, tmp)
+ a = convas(a, &mm)
+ mm.Append(a)
l = tmp
}
- a := Nod(OAS, l, nodarg(r, fp))
- a = convas(a, init)
+ a := nod(OAS, l, nodarg(r, 0))
+ a = convas(a, &nn)
ullmancalc(a)
if a.Ullman >= UINF {
Dump("ascompatet ucount", a)
ullmanOverflow = true
}
- nn = append(nn, a)
+ nn.Append(a)
r = saver.Next()
}
if i < nl.Len() || r != nil {
- Yyerror("ascompatet: assignment count mismatch: %d = %d", nl.Len(), nr.NumFields())
+ yyerror("ascompatet: assignment count mismatch: %d = %d", nl.Len(), nr.NumFields())
}
if ullmanOverflow {
Fatalf("ascompatet: too many function calls evaluating parameters")
}
- return append(nn, mm...)
+ return append(nn.Slice(), mm.Slice()...)
}
// package all the arguments that match a ... T parameter into a []T.
@@ -1754,14 +1753,13 @@ func mkdotargslice(lr0, nn []*Node, l *Field, fp int, init *Nodes, ddd *Node) []
}
tslice := typSlice(l.Type.Elem())
- tslice.Noalg = true
var n *Node
if len(lr0) == 0 {
n = nodnil()
n.Type = tslice
} else {
- n = Nod(OCOMPLIT, nil, typenod(tslice))
+ n = nod(OCOMPLIT, nil, typenod(tslice))
if ddd != nil && prealloc[ddd] != nil {
prealloc[n] = prealloc[ddd] // temporary to use
}
@@ -1774,7 +1772,7 @@ func mkdotargslice(lr0, nn []*Node, l *Field, fp int, init *Nodes, ddd *Node) []
n = walkexpr(n, init)
}
- a := Nod(OAS, nodarg(l, fp), n)
+ a := nod(OAS, nodarg(l, fp), n)
nn = append(nn, convas(a, init))
return nn
}
@@ -1786,7 +1784,7 @@ func dumptypes(nl *Type, what string) string {
if s != "" {
s += ", "
}
- s += Fldconv(l, 0)
+ s += fldconv(l, 0)
}
if s == "" {
s = fmt.Sprintf("[no arguments %s]", what)
@@ -1800,7 +1798,7 @@ func dumpnodetypes(l []*Node, what string) string {
if s != "" {
s += ", "
}
- s += Tconv(r.Type, 0)
+ s += r.Type.String()
}
if s == "" {
s = fmt.Sprintf("[no arguments %s]", what)
@@ -1814,7 +1812,7 @@ func dumpnodetypes(l []*Node, what string) string {
// 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)
+ l, savel := iterFields(nl)
var r *Node
if len(lr) > 0 {
r = lr[0]
@@ -1826,9 +1824,9 @@ func ascompatte(op Op, call *Node, isddd bool, nl *Type, lr []*Node, fp int, ini
// optimization - can do block copy
if eqtypenoname(r.Type, nl) {
arg := nodarg(nl, fp)
- r = Nod(OCONVNOP, r, nil)
+ r = nod(OCONVNOP, r, nil)
r.Type = arg.Type
- nn = []*Node{convas(Nod(OAS, arg, r), init)}
+ nn = []*Node{convas(nod(OAS, arg, r), init)}
goto ret
}
@@ -1841,7 +1839,7 @@ func ascompatte(op Op, call *Node, isddd bool, nl *Type, lr []*Node, fp int, ini
alist = append(alist, tmp)
}
- a := Nod(OAS2, nil, nil)
+ a := nod(OAS2, nil, nil)
a.List.Set(alist)
a.Rlist.Set(lr)
a = typecheck(a, Etop)
@@ -1849,7 +1847,7 @@ func ascompatte(op Op, call *Node, isddd bool, nl *Type, lr []*Node, fp int, ini
init.Append(a)
lr = alist
r = lr[0]
- l, savel = IterFields(nl)
+ l, savel = iterFields(nl)
}
for {
@@ -1858,15 +1856,15 @@ func ascompatte(op Op, call *Node, isddd bool, nl *Type, lr []*Node, fp int, ini
ll := savel.Next()
if ll != nil {
- Yyerror("... must be last argument")
+ 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)
+ 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
@@ -1885,16 +1883,16 @@ func ascompatte(op Op, call *Node, isddd bool, nl *Type, lr []*Node, fp int, ini
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)
+ 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)
+ yyerror("too many arguments to %v\n\t%s\n\t%s", op, l1, l2)
}
}
break
}
- a := Nod(OAS, nodarg(l, fp), r)
+ a := nod(OAS, nodarg(l, fp), r)
a = convas(a, init)
nn = append(nn, a)
@@ -1975,7 +1973,7 @@ func walkprint(nn *Node, init *Nodes) *Node {
} else if n.Type.IsSlice() {
on = syslook("printslice")
on = substArgTypes(on, n.Type) // any-1
- } else if Isint[et] {
+ } else if isInt[et] {
if et == TUINT64 {
if (t.Sym.Pkg == Runtimepkg || compiling_runtime) && t.Sym.Name == "hex" {
on = syslook("printhex")
@@ -1985,9 +1983,9 @@ func walkprint(nn *Node, init *Nodes) *Node {
} else {
on = syslook("printint")
}
- } else if Isfloat[et] {
+ } else if isFloat[et] {
on = syslook("printfloat")
- } else if Iscomplex[et] {
+ } else if isComplex[et] {
on = syslook("printcomplex")
} else if et == TBOOL {
on = syslook("printbool")
@@ -2000,12 +1998,12 @@ func walkprint(nn *Node, init *Nodes) *Node {
t = on.Type.Params().Field(0).Type
- if !Eqtype(t, n.Type) {
- n = Nod(OCONV, n, nil)
+ if !eqtype(t, n.Type) {
+ n = nod(OCONV, n, nil)
n.Type = t
}
- r = Nod(OCALL, on, nil)
+ r = nod(OCALL, on, nil)
r.List.Append(n)
calls = append(calls, r)
}
@@ -2019,7 +2017,7 @@ func walkprint(nn *Node, init *Nodes) *Node {
typecheckslice(calls, Etop)
walkexprlist(calls, init)
- r = Nod(OEMPTY, nil, nil)
+ r = nod(OEMPTY, nil, nil)
r = typecheck(r, Etop)
r = walkexpr(r, init)
r.Ninit.Set(calls)
@@ -2027,17 +2025,20 @@ func walkprint(nn *Node, init *Nodes) *Node {
}
func callnew(t *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 := mkcall1(fn, ptrto(t), nil, typename(t))
v.NonNil = true
return v
}
func iscallret(n *Node) bool {
n = outervalue(n)
- return n.Op == OINDREG && n.Reg == int16(Thearch.REGSP)
+ return n.Op == OINDREGSP
}
func isstack(n *Node) bool {
@@ -2045,7 +2046,7 @@ func isstack(n *Node) bool {
// If n is *autotmp and autotmp = &foo, replace n with foo.
// We introduce such temps when initializing struct literals.
- if n.Op == OIND && n.Left.Op == ONAME && strings.HasPrefix(n.Left.Sym.Name, "autotmp_") {
+ if n.Op == OIND && n.Left.Op == ONAME && n.Left.IsAutoTmp() {
defn := n.Left.Name.Defn
if defn != nil && defn.Op == OAS && defn.Right.Op == OADDR {
n = defn.Right.Left
@@ -2053,8 +2054,8 @@ func isstack(n *Node) bool {
}
switch n.Op {
- case OINDREG:
- return n.Reg == int16(Thearch.REGSP)
+ case OINDREGSP:
+ return true
case ONAME:
switch n.Class {
@@ -2066,20 +2067,6 @@ func isstack(n *Node) bool {
return false
}
-func isglobal(n *Node) bool {
- n = outervalue(n)
-
- switch n.Op {
- case ONAME:
- switch n.Class {
- case PEXTERN:
- return true
- }
- }
-
- return false
-}
-
// Do we need a write barrier for the assignment l = r?
func needwritebarrier(l *Node, r *Node) bool {
if !use_writebarrier {
@@ -2102,11 +2089,20 @@ func needwritebarrier(l *Node, r *Node) bool {
return false
}
- // No write barrier for implicit zeroing.
- if r == nil {
+ // 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 {
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.
@@ -2114,15 +2110,13 @@ func needwritebarrier(l *Node, r *Node) bool {
r = r.Left
}
- // No write barrier for zeroing or initialization to constant.
- if iszero(r) || r.Op == OLITERAL {
- return false
- }
-
- // No write barrier for storing static (read-only) data.
- if r.Op == ONAME && strings.HasPrefix(r.Sym.Name, "statictmp_") {
- return false
- }
+ // 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
+ // static data, a global (variable or function), or the stack.
+ // The nil optimization could be particularly useful for
+ // 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.
@@ -2130,18 +2124,6 @@ func needwritebarrier(l *Node, r *Node) bool {
return false
}
- // No write barrier for storing address of global, which
- // is live no matter what.
- if r.Op == OADDR && isglobal(r.Left) {
- return false
- }
-
- // No write barrier for storing global function, which is live
- // no matter what.
- if r.Op == ONAME && r.Class == PFUNC {
- return false
- }
-
// Otherwise, be conservative and use write barrier.
return true
}
@@ -2151,7 +2133,7 @@ func needwritebarrier(l *Node, r *Node) bool {
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", Nconv(n.Left, 0))
+ Warnl(n.Lineno, "marking %v for barrier", n.Left)
}
n.Op = OASWB
return n
@@ -2183,23 +2165,7 @@ func convas(n *Node, init *Nodes) *Node {
goto out
}
- if n.Left.Op == OINDEXMAP {
- map_ := n.Left.Left
- key := n.Left.Right
- val := n.Right
- map_ = walkexpr(map_, init)
- key = walkexpr(key, init)
- val = walkexpr(val, init)
-
- // orderexpr made sure key and val are addressable.
- key = Nod(OADDR, key, nil)
-
- val = Nod(OADDR, val, nil)
- n = mkcall1(mapfn("mapassign1", map_.Type), nil, init, typename(map_.Type), map_, key, val)
- goto out
- }
-
- if !Eqtype(lt, rt) {
+ if !eqtype(lt, rt) {
n.Right = assignconv(n.Right, lt, "assignment")
n.Right = walkexpr(n.Right, init)
}
@@ -2251,7 +2217,7 @@ func reorder1(all []*Node) []*Node {
// make assignment of fncall to tempname
a = temp(n.Right.Type)
- a = Nod(OAS, a, n.Right)
+ a = nod(OAS, a, n.Right)
g = append(g, a)
// put normal arg assignment on list
@@ -2340,7 +2306,7 @@ func reorder3save(n *Node, all []*Node, i int, early *[]*Node) *Node {
}
q := temp(n.Type)
- q = Nod(OAS, q, n)
+ q = nod(OAS, q, n)
q = typecheck(q, Etop)
*early = append(*early, q)
return q.Left
@@ -2537,7 +2503,7 @@ func vmatch1(l *Node, r *Node) bool {
case PPARAM, PAUTO:
break
- // assignment to non-stack variable
+ // assignment to non-stack variable
// must be delayed if right has function calls.
default:
if r.Ullman >= UINF {
@@ -2578,7 +2544,7 @@ func paramstoheap(params *Type) []*Node {
// 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))
+ nn = append(nn, nod(OAS, nodarg(t, 1), nil))
}
v := t.Nname
@@ -2590,9 +2556,9 @@ func paramstoheap(params *Type) []*Node {
}
if stackcopy := v.Name.Param.Stackcopy; stackcopy != nil {
- nn = append(nn, walkstmt(Nod(ODCL, v, nil)))
+ nn = append(nn, walkstmt(nod(ODCL, v, nil)))
if stackcopy.Class == PPARAM {
- nn = append(nn, walkstmt(typecheck(Nod(OAS, v, stackcopy), Etop)))
+ nn = append(nn, walkstmt(typecheck(nod(OAS, v, stackcopy), Etop)))
}
}
}
@@ -2610,7 +2576,7 @@ func returnsfromheap(params *Type) []*Node {
continue
}
if stackcopy := v.Name.Param.Stackcopy; stackcopy != nil && stackcopy.Class == PPARAMOUT {
- nn = append(nn, walkstmt(typecheck(Nod(OAS, stackcopy, v), Etop)))
+ nn = append(nn, walkstmt(typecheck(nod(OAS, stackcopy, v), Etop)))
}
}
@@ -2639,7 +2605,7 @@ func vmkcall(fn *Node, t *Type, init *Nodes, va []*Node) *Node {
n := fn.Type.Params().NumFields()
- r := Nod(OCALL, fn, nil)
+ r := nod(OCALL, fn, nil)
r.List.Set(va[:n])
if fn.Type.Results().NumFields() > 0 {
r = typecheck(r, Erv|Efnstruct)
@@ -2660,10 +2626,10 @@ func mkcall1(fn *Node, t *Type, init *Nodes, args ...*Node) *Node {
}
func conv(n *Node, t *Type) *Node {
- if Eqtype(n.Type, t) {
+ if eqtype(n.Type, t) {
return n
}
- n = Nod(OCONV, n, nil)
+ n = nod(OCONV, n, nil)
n.Type = t
n = typecheck(n, Erv)
return n
@@ -2714,7 +2680,7 @@ func addstr(n *Node, init *Nodes) *Node {
c := n.List.Len()
if c < 2 {
- Yyerror("addstr count %d too small", c)
+ yyerror("addstr count %d too small", c)
}
buf := nodnil()
@@ -2729,9 +2695,9 @@ 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 := aindex(Nodintconst(tmpstringbufsize), Types[TUINT8])
+ t := typArray(Types[TUINT8], tmpstringbufsize)
- buf = Nod(OADDR, temp(t), nil)
+ buf = nod(OADDR, temp(t), nil)
}
}
@@ -2751,7 +2717,7 @@ func addstr(n *Node, init *Nodes) *Node {
fn = "concatstrings"
t := typSlice(Types[TSTRING])
- slice := Nod(OCOMPLIT, nil, typenod(t))
+ slice := nod(OCOMPLIT, nil, typenod(t))
if prealloc[n] != nil {
prealloc[slice] = prealloc[n]
}
@@ -2761,7 +2727,7 @@ func addstr(n *Node, init *Nodes) *Node {
}
cat := syslook(fn)
- r := Nod(OCALL, cat, nil)
+ r := nod(OCALL, cat, nil)
r.List.Set(args)
r = typecheck(r, Erv)
r = walkexpr(r, init)
@@ -2802,15 +2768,15 @@ func appendslice(n *Node, init *Nodes) *Node {
// var s []T
s := temp(l1.Type)
- l = append(l, Nod(OAS, s, l1)) // s = l1
+ l = append(l, nod(OAS, s, l1)) // s = l1
// n := len(s) + len(l2)
nn := temp(Types[TINT])
- l = append(l, Nod(OAS, nn, Nod(OADD, Nod(OLEN, s, nil), Nod(OLEN, l2, nil))))
+ 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 := 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]
@@ -2819,19 +2785,19 @@ func appendslice(n *Node, init *Nodes) *Node {
fn = substArgTypes(fn, s.Type.Elem(), s.Type.Elem())
// s = growslice(T, s, n)
- nif.Nbody.Set1(Nod(OAS, s, mkcall1(fn, s.Type, &nif.Ninit, typename(s.Type.Elem()), s, nn)))
+ nif.Nbody.Set1(nod(OAS, s, mkcall1(fn, s.Type, &nif.Ninit, typename(s.Type.Elem()), s, nn)))
l = append(l, nif)
// s = s[:n]
- nt := Nod(OSLICE, s, nil)
+ nt := nod(OSLICE, s, nil)
nt.SetSliceBounds(nil, nn, nil)
nt.Etype = 1
- l = append(l, Nod(OAS, s, nt))
+ l = append(l, nod(OAS, s, nt))
if haspointers(l1.Type.Elem()) {
// copy(s[len(l1):], l2)
- nptr1 := Nod(OSLICE, s, nil)
- nptr1.SetSliceBounds(Nod(OLEN, l1, nil), nil, nil)
+ nptr1 := nod(OSLICE, s, nil)
+ nptr1.SetSliceBounds(nod(OLEN, l1, nil), nil, nil)
nptr1.Etype = 1
nptr2 := l2
fn := syslook("typedslicecopy")
@@ -2840,11 +2806,11 @@ func appendslice(n *Node, init *Nodes) *Node {
ln.Set(l)
nt := mkcall1(fn, Types[TINT], &ln, typename(l1.Type.Elem()), nptr1, nptr2)
l = append(ln.Slice(), nt)
- } else if instrumenting {
+ } else if instrumenting && !compiling_runtime {
// rely on runtime to instrument copy.
// copy(s[len(l1):], l2)
- nptr1 := Nod(OSLICE, s, nil)
- nptr1.SetSliceBounds(Nod(OLEN, l1, nil), nil, nil)
+ nptr1 := nod(OSLICE, s, nil)
+ nptr1.SetSliceBounds(nod(OLEN, l1, nil), nil, nil)
nptr1.Etype = 1
nptr2 := l2
var fn *Node
@@ -2856,25 +2822,25 @@ 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[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 := nod(OINDEX, s, nod(OLEN, l1, nil))
nptr1.Bounded = true
- nptr1 = Nod(OADDR, nptr1, nil)
+ nptr1 = nod(OADDR, nptr1, nil)
- nptr2 := Nod(OSPTR, l2, nil)
+ nptr2 := nod(OSPTR, l2, nil)
fn := syslook("memmove")
fn = substArgTypes(fn, s.Type.Elem(), s.Type.Elem())
var ln Nodes
ln.Set(l)
- nwid := cheapexpr(conv(Nod(OLEN, l2, nil), Types[TUINTPTR]), &ln)
+ nwid := cheapexpr(conv(nod(OLEN, l2, nil), Types[TUINTPTR]), &ln)
- nwid = Nod(OMUL, nwid, Nodintconst(s.Type.Elem().Width))
+ nwid = nod(OMUL, nwid, nodintconst(s.Type.Elem().Width))
nt := mkcall1(fn, nil, &ln, nptr1, nptr2, nwid)
l = append(ln.Slice(), nt)
}
@@ -2933,43 +2899,43 @@ func walkappend(n *Node, init *Nodes, dst *Node) *Node {
// General case, with no function calls left as arguments.
// Leave for gen, except that instrumentation requires old form.
- if !instrumenting {
+ if !instrumenting || compiling_runtime {
return n
}
var l []*Node
ns := temp(nsrc.Type)
- l = append(l, Nod(OAS, ns, nsrc)) // s = src
+ l = append(l, nod(OAS, ns, nsrc)) // s = src
- na := Nodintconst(int64(argc)) // const argc
- nx := Nod(OIF, nil, nil) // if cap(s) - len(s) < argc
- nx.Left = Nod(OLT, Nod(OSUB, Nod(OCAP, ns, nil), Nod(OLEN, ns, nil)), na)
+ na := nodintconst(int64(argc)) // const argc
+ nx := nod(OIF, nil, nil) // if cap(s) - len(s) < argc
+ nx.Left = nod(OLT, nod(OSUB, nod(OCAP, ns, nil), nod(OLEN, ns, nil)), na)
fn := syslook("growslice") // growslice(<type>, old []T, mincap int) (ret []T)
fn = substArgTypes(fn, ns.Type.Elem(), ns.Type.Elem())
- nx.Nbody.Set1(Nod(OAS, ns,
+ nx.Nbody.Set1(nod(OAS, ns,
mkcall1(fn, ns.Type, &nx.Ninit, typename(ns.Type.Elem()), ns,
- Nod(OADD, Nod(OLEN, ns, nil), na))))
+ nod(OADD, nod(OLEN, ns, nil), na))))
l = append(l, nx)
nn := temp(Types[TINT])
- l = append(l, Nod(OAS, nn, Nod(OLEN, ns, nil))) // n = len(s)
+ l = append(l, nod(OAS, nn, nod(OLEN, ns, nil))) // n = len(s)
- nx = Nod(OSLICE, ns, nil) // ...s[:n+argc]
- nx.SetSliceBounds(nil, Nod(OADD, nn, na), nil)
+ nx = nod(OSLICE, ns, nil) // ...s[:n+argc]
+ nx.SetSliceBounds(nil, nod(OADD, nn, na), nil)
nx.Etype = 1
- l = append(l, Nod(OAS, ns, nx)) // s = s[:n+argc]
+ l = append(l, nod(OAS, ns, nx)) // s = s[:n+argc]
ls = n.List.Slice()[1:]
for i, n := range ls {
- nx = Nod(OINDEX, ns, nn) // s[n] ...
+ nx = nod(OINDEX, ns, nn) // s[n] ...
nx.Bounded = true
- l = append(l, Nod(OAS, nx, n)) // s[n] = arg
+ 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
+ l = append(l, nod(OAS, nn, nod(OADD, nn, nodintconst(1)))) // n = n + 1
}
}
@@ -3004,7 +2970,7 @@ func copyany(n *Node, init *Nodes, runtimecall bool) *Node {
fn = syslook("slicecopy")
}
fn = substArgTypes(fn, n.Left.Type, n.Right.Type)
- return mkcall1(fn, n.Type, init, n.Left, n.Right, Nodintconst(n.Left.Type.Elem().Width))
+ return mkcall1(fn, n.Type, init, n.Left, n.Right, nodintconst(n.Left.Type.Elem().Width))
}
n.Left = walkexpr(n.Left, init)
@@ -3012,22 +2978,22 @@ func copyany(n *Node, init *Nodes, runtimecall bool) *Node {
nl := temp(n.Left.Type)
nr := temp(n.Right.Type)
var l []*Node
- l = append(l, Nod(OAS, nl, n.Left))
- l = append(l, Nod(OAS, nr, n.Right))
+ l = append(l, nod(OAS, nl, n.Left))
+ l = append(l, nod(OAS, nr, n.Right))
- nfrm := Nod(OSPTR, nr, nil)
- nto := Nod(OSPTR, nl, nil)
+ nfrm := nod(OSPTR, nr, nil)
+ nto := nod(OSPTR, nl, nil)
nlen := temp(Types[TINT])
// n = len(to)
- l = append(l, Nod(OAS, nlen, Nod(OLEN, nl, nil)))
+ l = append(l, nod(OAS, nlen, nod(OLEN, nl, nil)))
// if n > len(frm) { n = len(frm) }
- nif := Nod(OIF, nil, nil)
+ nif := nod(OIF, nil, nil)
- nif.Left = Nod(OGT, nlen, Nod(OLEN, nr, nil))
- nif.Nbody.Append(Nod(OAS, nlen, Nod(OLEN, nr, nil)))
+ nif.Left = nod(OGT, nlen, nod(OLEN, nr, nil))
+ nif.Nbody.Append(nod(OAS, nlen, nod(OLEN, nr, nil)))
l = append(l, nif)
// Call memmove.
@@ -3035,8 +3001,8 @@ func copyany(n *Node, init *Nodes, runtimecall bool) *Node {
fn = substArgTypes(fn, nl.Type.Elem(), nl.Type.Elem())
nwid := temp(Types[TUINTPTR])
- l = append(l, Nod(OAS, nwid, conv(nlen, Types[TUINTPTR])))
- nwid = Nod(OMUL, nwid, Nodintconst(nl.Type.Elem().Width))
+ l = append(l, nod(OAS, nwid, conv(nlen, Types[TUINTPTR])))
+ nwid = nod(OMUL, nwid, nodintconst(nl.Type.Elem().Width))
l = append(l, mkcall1(fn, nil, init, nto, nfrm, nwid))
typecheckslice(l, Etop)
@@ -3060,10 +3026,10 @@ func eqfor(t *Type, needsize *int) *Node {
sym := typesymprefix(".eq", t)
n := newname(sym)
n.Class = PFUNC
- ntype := Nod(OTFUNC, nil, nil)
- ntype.List.Append(Nod(ODCLFIELD, nil, typenod(Ptrto(t))))
- ntype.List.Append(Nod(ODCLFIELD, nil, typenod(Ptrto(t))))
- ntype.Rlist.Append(Nod(ODCLFIELD, nil, typenod(Types[TBOOL])))
+ ntype := nod(OTFUNC, nil, nil)
+ ntype.List.Append(nod(ODCLFIELD, nil, typenod(ptrto(t))))
+ ntype.List.Append(nod(ODCLFIELD, nil, typenod(ptrto(t))))
+ ntype.Rlist.Append(nod(ODCLFIELD, nil, typenod(Types[TBOOL])))
ntype = typecheck(ntype, Etype)
n.Type = ntype.Type
*needsize = 0
@@ -3078,14 +3044,9 @@ func eqfor(t *Type, needsize *int) *Node {
func walkcompare(n *Node, init *Nodes) *Node {
// Given interface value l and concrete value r, rewrite
// l == r
- // to
- // x, ok := l.(type(r)); ok && x == r
- // Handle != similarly.
- // This avoids the allocation that would be required
- // to convert r to l for comparison.
- var l *Node
-
- var r *Node
+ // into types-equal && data-equal.
+ // This is efficient, avoids allocations, and avoids runtime calls.
+ var l, r *Node
if n.Left.Type.IsInterface() && !n.Right.Type.IsInterface() {
l = n.Left
r = n.Right
@@ -3095,48 +3056,52 @@ func walkcompare(n *Node, init *Nodes) *Node {
}
if l != nil {
- x := temp(r.Type)
- if haspointers(r.Type) {
- a := Nod(OAS, x, nil)
- a = typecheck(a, Etop)
- init.Append(a)
- }
- ok := temp(Types[TBOOL])
-
- // l.(type(r))
- a := Nod(ODOTTYPE, l, nil)
-
- a.Type = r.Type
-
- // x, ok := l.(type(r))
- expr := Nod(OAS2, nil, nil)
-
- expr.List.Append(x)
- expr.List.Append(ok)
- expr.Rlist.Append(a)
- expr = typecheck(expr, Etop)
- expr = walkexpr(expr, init)
-
- if n.Op == OEQ {
- r = Nod(OANDAND, ok, Nod(OEQ, x, r))
+ // Handle both == and !=.
+ eq := n.Op
+ var andor Op
+ if eq == OEQ {
+ andor = OANDAND
} else {
- r = Nod(OOROR, Nod(ONOT, ok, nil), Nod(ONE, x, r))
- }
- init.Append(expr)
- n = finishcompare(n, r, init)
+ andor = OOROR
+ }
+ // Check for types equal.
+ // For empty interface, this is:
+ // l.tab == type(r)
+ // For non-empty interface, this is:
+ // l.tab != nil && l.tab._type == type(r)
+ var eqtype *Node
+ tab := nod(OITAB, l, nil)
+ rtyp := typename(r.Type)
+ if l.Type.IsEmptyInterface() {
+ tab.Type = ptrto(Types[TUINT8])
+ tab.Typecheck = 1
+ eqtype = nod(eq, tab, rtyp)
+ } else {
+ nonnil := nod(brcom(eq), nodnil(), tab)
+ match := nod(eq, itabType(tab), rtyp)
+ eqtype = nod(andor, nonnil, match)
+ }
+ // Check for data equal.
+ eqdata := nod(eq, ifaceData(l, r.Type), r)
+ // Put it all together.
+ expr := nod(andor, eqtype, eqdata)
+ n = finishcompare(n, expr, init)
return n
}
// Must be comparison of array or struct.
// Otherwise back end handles it.
+ // While we're here, decide whether to
+ // inline or call an eq alg.
t := n.Left.Type
-
+ var inline bool
switch t.Etype {
default:
return n
-
- case TARRAY, TSTRUCT:
- break
+ case TARRAY:
+ inline = t.NumElem() <= 1 || (t.NumElem() <= 4 && issimple[t.Elem().Etype])
+ case TSTRUCT:
+ inline = t.NumFields() <= 4
}
cmpl := n.Left
@@ -3152,103 +3117,75 @@ func walkcompare(n *Node, init *Nodes) *Node {
Fatalf("arguments of comparison must be lvalues - %v %v", cmpl, cmpr)
}
- l = temp(Ptrto(t))
- a := Nod(OAS, l, Nod(OADDR, cmpl, nil))
- a.Right.Etype = 1 // addr does not escape
- a = typecheck(a, Etop)
- init.Append(a)
-
- r = temp(Ptrto(t))
- a = Nod(OAS, r, Nod(OADDR, cmpr, nil))
- a.Right.Etype = 1 // addr does not escape
- a = typecheck(a, Etop)
- init.Append(a)
+ // Chose not to inline. Call equality function directly.
+ if !inline {
+ // eq algs take pointers
+ pl := temp(ptrto(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))
+ ar := nod(OAS, pr, nod(OADDR, cmpr, nil))
+ ar.Right.Etype = 1 // addr does not escape
+ ar = typecheck(ar, Etop)
+ init.Append(ar)
+
+ var needsize int
+ call := nod(OCALL, eqfor(t, &needsize), nil)
+ call.List.Append(pl)
+ call.List.Append(pr)
+ if needsize != 0 {
+ call.List.Append(nodintconst(t.Width))
+ }
+ res := call
+ if n.Op != OEQ {
+ res = nod(ONOT, res, nil)
+ }
+ n = finishcompare(n, res, init)
+ return n
+ }
- var andor Op = OANDAND
+ // inline: build boolean expression comparing element by element
+ andor := OANDAND
if n.Op == ONE {
andor = OOROR
}
-
var expr *Node
- if t.Etype == TARRAY && t.NumElem() <= 4 && issimple[t.Elem().Etype] {
- // Four or fewer elements of a basic type.
- // Unroll comparisons.
- var li *Node
- var ri *Node
- for i := 0; int64(i) < t.NumElem(); i++ {
- li = Nod(OINDEX, l, Nodintconst(int64(i)))
- ri = Nod(OINDEX, r, Nodintconst(int64(i)))
- a = Nod(n.Op, li, ri)
- if expr == nil {
- expr = a
- } else {
- expr = Nod(andor, expr, a)
- }
- }
-
+ compare := func(el, er *Node) {
+ a := nod(n.Op, el, er)
if expr == nil {
- expr = Nodbool(n.Op == OEQ)
- }
- n = finishcompare(n, expr, init)
- return n
- }
-
- if t.Etype == TARRAY {
- // Zero- or single-element array, of any type.
- switch t.NumElem() {
- case 0:
- n = finishcompare(n, Nodbool(n.Op == OEQ), init)
- return n
- case 1:
- l0 := Nod(OINDEX, l, Nodintconst(0))
- r0 := Nod(OINDEX, r, Nodintconst(0))
- a := Nod(n.Op, l0, r0)
- n = finishcompare(n, a, init)
- return n
+ expr = a
+ } else {
+ expr = nod(andor, expr, a)
}
}
-
- if t.IsStruct() && t.NumFields() <= 4 {
- // Struct of four or fewer fields.
- // Inline comparisons.
- var li *Node
- var ri *Node
- for _, t1 := range t.Fields().Slice() {
- if isblanksym(t1.Sym) {
+ cmpl = safeexpr(cmpl, init)
+ cmpr = safeexpr(cmpr, init)
+ if t.IsStruct() {
+ for _, f := range t.Fields().Slice() {
+ sym := f.Sym
+ if isblanksym(sym) {
continue
}
- li = NodSym(OXDOT, l, t1.Sym)
- ri = NodSym(OXDOT, r, t1.Sym)
- a = Nod(n.Op, li, ri)
- if expr == nil {
- expr = a
- } else {
- expr = Nod(andor, expr, a)
- }
+ compare(
+ nodSym(OXDOT, cmpl, sym),
+ nodSym(OXDOT, cmpr, sym),
+ )
}
-
- if expr == nil {
- expr = Nodbool(n.Op == OEQ)
+ } else {
+ for i := 0; int64(i) < t.NumElem(); i++ {
+ compare(
+ nod(OINDEX, cmpl, nodintconst(int64(i))),
+ nod(OINDEX, cmpr, nodintconst(int64(i))),
+ )
}
- n = finishcompare(n, expr, init)
- return n
}
-
- // Chose not to inline. Call equality function directly.
- var needsize int
- call := Nod(OCALL, eqfor(t, &needsize), nil)
-
- call.List.Append(l)
- call.List.Append(r)
- if needsize != 0 {
- call.List.Append(Nodintconst(t.Width))
+ if expr == nil {
+ expr = nodbool(n.Op == OEQ)
}
- r = call
- if n.Op != OEQ {
- r = Nod(ONOT, r, nil)
- }
-
- n = finishcompare(n, r, init)
+ n = finishcompare(n, expr, init)
return n
}
@@ -3261,7 +3198,7 @@ func finishcompare(n, r *Node, init *Nodes) *Node {
nn = walkexpr(nn, init)
r = nn
if r.Type != n.Type {
- r = Nod(OCONVNOP, r, nil)
+ r = nod(OCONVNOP, r, nil)
r.Type = n.Type
r.Typecheck = 1
nn = r
@@ -3303,7 +3240,7 @@ func samecheap(a *Node, b *Node) bool {
// The result of walkrotate MUST be assigned back to n, e.g.
// n.Left = walkrotate(n.Left)
func walkrotate(n *Node) *Node {
- if Thearch.LinkArch.InFamily(sys.MIPS64, sys.ARM64, sys.PPC64) {
+ if Thearch.LinkArch.InFamily(sys.MIPS, sys.MIPS64, sys.PPC64) {
return n
}
@@ -3328,7 +3265,7 @@ func walkrotate(n *Node) *Node {
return n
}
- if Smallintconst(l.Right) && Smallintconst(r.Right) {
+ if smallintconst(l.Right) && smallintconst(r.Right) {
sl := int(l.Right.Int64())
if sl >= 0 {
sr := int(r.Right.Int64())
@@ -3357,6 +3294,137 @@ func walkrotate(n *Node) *Node {
return n
}
+// isIntOrdering reports whether n is a <, ≤, >, or ≥ ordering between integers.
+func (n *Node) isIntOrdering() bool {
+ switch n.Op {
+ case OLE, OLT, OGE, OGT:
+ default:
+ return false
+ }
+ return n.Left.Type.IsInteger() && n.Right.Type.IsInteger()
+}
+
+// walkinrange optimizes integer-in-range checks, such as 4 <= x && x < 10.
+// n must be an OANDAND or OOROR node.
+// The result of walkinrange MUST be assigned back to n, e.g.
+// n.Left = walkinrange(n.Left)
+func walkinrange(n *Node, init *Nodes) *Node {
+ // We are looking for something equivalent to a opl b OP b opr c, where:
+ // * a, b, and c have integer type
+ // * b is side-effect-free
+ // * opl and opr are each < or ≤
+ // * OP is &&
+ l := n.Left
+ r := n.Right
+ if !l.isIntOrdering() || !r.isIntOrdering() {
+ return n
+ }
+
+ // Find b, if it exists, and rename appropriately.
+ // Input is: l.Left l.Op l.Right ANDAND/OROR r.Left r.Op r.Right
+ // Output is: a opl b(==x) ANDAND/OROR b(==x) opr c
+ a, opl, b := l.Left, l.Op, l.Right
+ x, opr, c := r.Left, r.Op, r.Right
+ for i := 0; ; i++ {
+ if samesafeexpr(b, x) {
+ break
+ }
+ if i == 3 {
+ // Tried all permutations and couldn't find an appropriate b == x.
+ return n
+ }
+ if i&1 == 0 {
+ a, opl, b = b, brrev(opl), a
+ } else {
+ x, opr, c = c, brrev(opr), x
+ }
+ }
+
+ // If n.Op is ||, apply de Morgan.
+ // Negate the internal ops now; we'll negate the top level op at the end.
+ // Henceforth assume &&.
+ negateResult := n.Op == OOROR
+ if negateResult {
+ opl = brcom(opl)
+ opr = brcom(opr)
+ }
+
+ cmpdir := func(o Op) int {
+ switch o {
+ case OLE, OLT:
+ return -1
+ case OGE, OGT:
+ return +1
+ }
+ Fatalf("walkinrange cmpdir %v", o)
+ return 0
+ }
+ if cmpdir(opl) != cmpdir(opr) {
+ // Not a range check; something like b < a && b < c.
+ return n
+ }
+
+ switch opl {
+ case OGE, OGT:
+ // We have something like a > b && b ≥ c.
+ // Switch and reverse ops and rename constants,
+ // to make it look like a ≤ b && b < c.
+ a, c = c, a
+ opl, opr = brrev(opr), brrev(opl)
+ }
+
+ // We must ensure that c-a is non-negative.
+ // For now, require a and c to be constants.
+ // In the future, we could also support a == 0 and c == len/cap(...).
+ // Unfortunately, by this point, most len/cap expressions have been
+ // stored into temporary variables.
+ if !Isconst(a, CTINT) || !Isconst(c, CTINT) {
+ return n
+ }
+
+ if opl == OLT {
+ // We have a < b && ...
+ // We need a ≤ b && ... to safely use unsigned comparison tricks.
+ // If a is not the maximum constant for b's type,
+ // we can increment a and switch to ≤.
+ if a.Int64() >= maxintval[b.Type.Etype].Int64() {
+ return n
+ }
+ a = nodintconst(a.Int64() + 1)
+ opl = OLE
+ }
+
+ bound := c.Int64() - a.Int64()
+ if bound < 0 {
+ // Bad news. Something like 5 <= x && x < 3.
+ // Rare in practice, and we still need to generate side-effects,
+ // so just leave it alone.
+ return n
+ }
+
+ // We have a ≤ b && b < c (or a ≤ b && b ≤ c).
+ // 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()
+ lhs := conv(nod(OSUB, b, a), ut)
+ rhs := nodintconst(bound)
+ if negateResult {
+ // Negate top level.
+ opr = brcom(opr)
+ }
+ cmp := nod(opr, lhs, rhs)
+ cmp.Lineno = n.Lineno
+ cmp = addinit(cmp, l.Ninit.Slice())
+ cmp = addinit(cmp, r.Ninit.Slice())
+ // Typecheck the AST rooted at cmp...
+ cmp = typecheck(cmp, Erv)
+ // ...but then reset cmp's type to match n's type.
+ cmp.Type = n.Type
+ cmp = walkexpr(cmp, init)
+ 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)
@@ -3415,11 +3483,11 @@ func walkmul(n *Node, init *Nodes) *Node {
goto ret
}
- n = Nod(OLSH, nl, Nodintconst(int64(pow)))
+ n = nod(OLSH, nl, nodintconst(int64(pow)))
ret:
if neg != 0 {
- n = Nod(OMINUS, n, nil)
+ n = nod(OMINUS, n, nil)
}
n = typecheck(n, Erv)
@@ -3434,11 +3502,6 @@ ret:
func walkdiv(n *Node, init *Nodes) *Node {
// if >= 0, nr is 1<<pow // 1 if nr is negative.
- // TODO(minux)
- if Thearch.LinkArch.InFamily(sys.MIPS64, sys.PPC64) {
- return n
- }
-
if n.Right.Op != OLITERAL {
return n
}
@@ -3475,10 +3538,10 @@ func walkdiv(n *Node, init *Nodes) *Node {
if nl.Type.IsSigned() {
m.Sd = nr.Int64()
- Smagic(&m)
+ smagic(&m)
} else {
m.Ud = uint64(nr.Int64())
- Umagic(&m)
+ umagic(&m)
}
if m.Bad != 0 {
@@ -3489,24 +3552,14 @@ func walkdiv(n *Node, init *Nodes) *Node {
// for modulo too.
if n.Op == OMOD {
// rewrite as A%B = A - (A/B*B).
- n1 := Nod(ODIV, nl, nr)
+ n1 := nod(ODIV, nl, nr)
- n2 := Nod(OMUL, n1, nr)
- n = Nod(OSUB, nl, n2)
+ n2 := nod(OMUL, n1, nr)
+ n = nod(OSUB, nl, n2)
goto ret
}
- // TODO(zhongwei) Test shows that TUINT8, TINT8, TUINT16 and TINT16's "quick division" method
- // on current arm64 backend is slower than hardware div instruction on ARM64 due to unnecessary
- // data movement between registers. It could be enabled when generated code is good enough.
- if Thearch.LinkArch.Family == sys.ARM64 {
- switch Simtype[nl.Type.Etype] {
- case TUINT8, TINT8, TUINT16, TINT16:
- return n
- }
- }
-
- switch Simtype[nl.Type.Etype] {
+ switch simtype[nl.Type.Etype] {
default:
return n
@@ -3515,12 +3568,12 @@ func walkdiv(n *Node, init *Nodes) *Node {
var nc Node
Nodconst(&nc, nl.Type, int64(m.Um))
- n1 := Nod(OHMUL, nl, &nc)
+ 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] {
+ switch simtype[nl.Type.Etype] {
default:
return n
@@ -3539,19 +3592,19 @@ func walkdiv(n *Node, init *Nodes) *Node {
// add numerator (might overflow).
// n2 = (n1 + nl)
- n2 := Nod(OADD, conv(n1, twide), conv(nl, twide))
+ 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)
+ 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)
+ n = nod(ORSH, n1, &nc)
}
// n1 = nl * magic >> w
@@ -3559,29 +3612,29 @@ func walkdiv(n *Node, init *Nodes) *Node {
var nc Node
Nodconst(&nc, nl.Type, m.Sm)
- n1 := Nod(OHMUL, nl, &nc)
+ n1 := nod(OHMUL, nl, &nc)
n1 = typecheck(n1, Erv)
if m.Sm < 0 {
// add the numerator.
- n1 = Nod(OADD, n1, nl)
+ 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)
+ 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)
+ 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)
+ n = nod(OMINUS, n, nil)
}
}
@@ -3611,31 +3664,31 @@ func walkdiv(n *Node, init *Nodes) *Node {
// 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.
+ 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)
+ n2 := nod(OSUB, nl, n1)
var nc Node
Nodconst(&nc, nl.Type, 1)
- n3 := Nod(OAND, n2, &nc)
- n = Nod(OADD, n3, n1)
+ 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 := 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)
+ n3 := nod(OADD, nl, n2)
+ n4 := nod(OAND, n3, &nc)
+ n = nod(OSUB, n4, n2)
}
break
@@ -3645,31 +3698,31 @@ func walkdiv(n *Node, init *Nodes) *Node {
// 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.
+ 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)
+ 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, tounsigned(nl.Type)), &nc)
- n.Left = Nod(OADD, nl, conv(n2, nl.Type))
+ 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))
+ Nodconst(&n2, Types[simtype[TUINT]], int64(pow))
n.Right = &n2
n.Typecheck = 0
}
if s != 0 {
- n = Nod(OMINUS, n, nil)
+ n = nod(OMINUS, n, nil)
}
break
}
@@ -3684,7 +3737,7 @@ func walkdiv(n *Node, init *Nodes) *Node {
// n = nl >> pow
n.Op = ORSH
- Nodconst(&nc, Types[Simtype[TUINT]], int64(pow))
+ Nodconst(&nc, Types[simtype[TUINT]], int64(pow))
}
n.Typecheck = 0
@@ -3708,7 +3761,7 @@ func bounded(n *Node, max int64) bool {
sign := n.Type.IsSigned()
bits := int32(8 * n.Type.Width)
- if Smallintconst(n) {
+ if smallintconst(n) {
v := n.Int64()
return 0 <= v && v < max
}
@@ -3716,9 +3769,9 @@ func bounded(n *Node, max int64) bool {
switch n.Op {
case OAND:
v := int64(-1)
- if Smallintconst(n.Left) {
+ if smallintconst(n.Left) {
v = n.Left.Int64()
- } else if Smallintconst(n.Right) {
+ } else if smallintconst(n.Right) {
v = n.Right.Int64()
}
@@ -3727,7 +3780,7 @@ func bounded(n *Node, max int64) bool {
}
case OMOD:
- if !sign && Smallintconst(n.Right) {
+ if !sign && smallintconst(n.Right) {
v := n.Right.Int64()
if 0 <= v && v <= max {
return true
@@ -3735,7 +3788,7 @@ func bounded(n *Node, max int64) bool {
}
case ODIV:
- if !sign && Smallintconst(n.Right) {
+ if !sign && smallintconst(n.Right) {
v := n.Right.Int64()
for bits > 0 && v >= 2 {
bits--
@@ -3744,7 +3797,7 @@ func bounded(n *Node, max int64) bool {
}
case ORSH:
- if !sign && Smallintconst(n.Right) {
+ if !sign && smallintconst(n.Right) {
v := n.Right.Int64()
if v > int64(bits) {
return true
@@ -3795,7 +3848,7 @@ func usemethod(n *Node) {
return
}
}
- if Tconv(res0.Type, 0) != "reflect.Method" {
+ if res0.Type.String() != "reflect.Method" {
return
}
@@ -3837,10 +3890,10 @@ func usefield(n *Node) {
outer = outer.Elem()
}
if outer.Sym == nil {
- Yyerror("tracked field must be in named struct type")
+ yyerror("tracked field must be in named struct type")
}
if !exportname(field.Sym.Name) {
- Yyerror("tracked field must be exported (upper case)")
+ yyerror("tracked field must be exported (upper case)")
}
sym := tracksym(outer, field)
@@ -3892,6 +3945,7 @@ func candiscard(n *Node) bool {
OMAPLIT,
OSTRUCTLIT,
OARRAYLIT,
+ OSLICELIT,
OPTRLIT,
OCONV,
OCONVIFACE,
@@ -3904,6 +3958,7 @@ func candiscard(n *Node) bool {
OGT,
OGE,
OKEY,
+ OSTRUCTKEY,
OLEN,
OMUL,
OLSH,
@@ -3970,7 +4025,7 @@ func walkprintfunc(n *Node, init *Nodes) *Node {
init.AppendNodes(&n.Ninit)
}
- t := Nod(OTFUNC, nil, nil)
+ t := nod(OTFUNC, nil, nil)
num := 0
var printargs []*Node
var a *Node
@@ -3978,15 +4033,15 @@ 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 = nod(ODCLFIELD, newname(lookup(buf)), typenod(n1.Type))
t.List.Append(a)
printargs = append(printargs, a.Left)
}
- fn := Nod(ODCLFUNC, nil, nil)
+ fn := nod(ODCLFUNC, nil, nil)
walkprintfunc_prgen++
buf = fmt.Sprintf("print·%d", walkprintfunc_prgen)
- fn.Func.Nname = newname(Lookup(buf))
+ fn.Func.Nname = newname(lookup(buf))
fn.Func.Nname.Name.Defn = fn
fn.Func.Nname.Name.Param.Ntype = t
declare(fn.Func.Nname, PFUNC)
@@ -3995,7 +4050,7 @@ func walkprintfunc(n *Node, init *Nodes) *Node {
Curfn = nil
funchdr(fn)
- a = Nod(n.Op, nil, nil)
+ a = nod(n.Op, nil, nil)
a.List.Set(printargs)
a = typecheck(a, Etop)
a = walkstmt(a)
@@ -4009,7 +4064,7 @@ func walkprintfunc(n *Node, init *Nodes) *Node {
xtop = append(xtop, fn)
Curfn = oldfn
- a = Nod(OCALL, nil, nil)
+ a = nod(OCALL, nil, nil)
a.Left = fn.Func.Nname
a.List.Set(n.List.Slice())
a = typecheck(a, Etop)
diff --git a/src/cmd/compile/internal/mips/galign.go b/src/cmd/compile/internal/mips/galign.go
new file mode 100644
index 0000000..39f5d2b
--- /dev/null
+++ b/src/cmd/compile/internal/mips/galign.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 mips
+
+import (
+ "cmd/compile/internal/gc"
+ "cmd/compile/internal/ssa"
+ "cmd/internal/obj"
+ "cmd/internal/obj/mips"
+)
+
+func Init() {
+ gc.Thearch.LinkArch = &mips.Linkmips
+ if obj.GOARCH == "mipsle" {
+ gc.Thearch.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
+}
diff --git a/src/cmd/compile/internal/mips/ggen.go b/src/cmd/compile/internal/mips/ggen.go
new file mode 100644
index 0000000..ec540f8
--- /dev/null
+++ b/src/cmd/compile/internal/mips/ggen.go
@@ -0,0 +1,101 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package mips
+
+import (
+ "cmd/compile/internal/gc"
+ "cmd/internal/obj"
+ "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 {
+
+ 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)
+ }
+ } else {
+ //fmt.Printf("zerorange frame:%v, lo: %v, hi:%v \n", frame ,lo, hi)
+ // ADD $(FIXED_FRAME+frame+lo-4), SP, r1
+ // ADD $cnt, r1, r2
+ // loop:
+ // 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.Reg = mips.REGSP
+ p = gc.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))
+ 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.Reg = mips.REGRT2
+ gc.Patch(p, p1)
+ }
+
+ return p
+}
+
+func ginsnop() {
+ p := gc.Prog(mips.ANOR)
+ p.From.Type = obj.TYPE_REG
+ p.From.Reg = mips.REG_R0
+ p.To.Type = obj.TYPE_REG
+ p.To.Reg = mips.REG_R0
+}
diff --git a/src/cmd/compile/internal/mips/prog.go b/src/cmd/compile/internal/mips/prog.go
new file mode 100644
index 0000000..32805f0
--- /dev/null
+++ b/src/cmd/compile/internal/mips/prog.go
@@ -0,0 +1,157 @@
+// Copyright 2016 The Go Authors. 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
new file mode 100644
index 0000000..aef1f90
--- /dev/null
+++ b/src/cmd/compile/internal/mips/ssa.go
@@ -0,0 +1,907 @@
+// Copyright 2016 The Go Authors. 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 (
+ "math"
+
+ "cmd/compile/internal/gc"
+ "cmd/compile/internal/ssa"
+ "cmd/internal/obj"
+ "cmd/internal/obj/mips"
+)
+
+// isFPreg returns whether r is an FP register
+func isFPreg(r int16) bool {
+ return mips.REG_F0 <= r && r <= mips.REG_F31
+}
+
+// isHILO returns whether r is HI or LO register
+func isHILO(r int16) bool {
+ return r == mips.REG_HI || r == mips.REG_LO
+}
+
+// loadByType returns the load instruction of the given type.
+func loadByType(t ssa.Type, r int16) obj.As {
+ if isFPreg(r) {
+ if t.Size() == 4 { // float32 or int32
+ return mips.AMOVF
+ } else { // float64 or int64
+ return mips.AMOVD
+ }
+ } else {
+ switch t.Size() {
+ case 1:
+ if t.IsSigned() {
+ return mips.AMOVB
+ } else {
+ return mips.AMOVBU
+ }
+ case 2:
+ if t.IsSigned() {
+ return mips.AMOVH
+ } else {
+ return mips.AMOVHU
+ }
+ case 4:
+ return mips.AMOVW
+ }
+ }
+ panic("bad load type")
+}
+
+// storeByType returns the store instruction of the given type.
+func storeByType(t ssa.Type, r int16) obj.As {
+ if isFPreg(r) {
+ if t.Size() == 4 { // float32 or int32
+ return mips.AMOVF
+ } else { // float64 or int64
+ return mips.AMOVD
+ }
+ } else {
+ switch t.Size() {
+ case 1:
+ return mips.AMOVB
+ case 2:
+ return mips.AMOVH
+ case 4:
+ return mips.AMOVW
+ }
+ }
+ panic("bad store type")
+}
+
+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() {
+ return
+ }
+ x := v.Args[0].Reg()
+ y := v.Reg()
+ if x == y {
+ return
+ }
+ as := mips.AMOVW
+ if isFPreg(x) && isFPreg(y) {
+ as = mips.AMOVF
+ if t.Size() == 8 {
+ as = mips.AMOVD
+ }
+ }
+
+ p := gc.Prog(as)
+ p.From.Type = obj.TYPE_REG
+ p.From.Reg = x
+ p.To.Type = obj.TYPE_REG
+ p.To.Reg = y
+ 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.From.Type = obj.TYPE_REG
+ p.From.Reg = mips.REGTMP
+ p.To.Type = obj.TYPE_REG
+ p.To.Reg = y
+ }
+ case ssa.OpMIPSMOVWnop:
+ if v.Reg() != v.Args[0].Reg() {
+ v.Fatalf("input[0] and output not in same register %s", v.LongString())
+ }
+ // nothing to do
+ case ssa.OpLoadReg:
+ if v.Type.IsFlags() {
+ v.Fatalf("load flags not implemented: %v", v.LongString())
+ return
+ }
+ r := v.Reg()
+ p := gc.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.From.Type = obj.TYPE_REG
+ p.From.Reg = mips.REGTMP
+ p.To.Type = obj.TYPE_REG
+ p.To.Reg = r
+ }
+ case ssa.OpStoreReg:
+ if v.Type.IsFlags() {
+ v.Fatalf("store flags not implemented: %v", v.LongString())
+ return
+ }
+ r := v.Args[0].Reg()
+ if isHILO(r) {
+ // cannot directly store, move to TMP and store
+ p := gc.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.From.Type = obj.TYPE_REG
+ p.From.Reg = r
+ gc.AddrAuto(&p.To, v)
+ case ssa.OpMIPSADD,
+ ssa.OpMIPSSUB,
+ ssa.OpMIPSAND,
+ ssa.OpMIPSOR,
+ ssa.OpMIPSXOR,
+ ssa.OpMIPSNOR,
+ ssa.OpMIPSSLL,
+ ssa.OpMIPSSRL,
+ ssa.OpMIPSSRA,
+ ssa.OpMIPSADDF,
+ ssa.OpMIPSADDD,
+ ssa.OpMIPSSUBF,
+ ssa.OpMIPSSUBD,
+ ssa.OpMIPSMULF,
+ ssa.OpMIPSMULD,
+ ssa.OpMIPSDIVF,
+ ssa.OpMIPSDIVD,
+ ssa.OpMIPSMUL:
+ p := gc.Prog(v.Op.Asm())
+ p.From.Type = obj.TYPE_REG
+ p.From.Reg = v.Args[1].Reg()
+ p.Reg = v.Args[0].Reg()
+ p.To.Type = obj.TYPE_REG
+ p.To.Reg = v.Reg()
+ case ssa.OpMIPSSGT,
+ ssa.OpMIPSSGTU:
+ p := gc.Prog(v.Op.Asm())
+ p.From.Type = obj.TYPE_REG
+ p.From.Reg = v.Args[0].Reg()
+ p.Reg = v.Args[1].Reg()
+ p.To.Type = obj.TYPE_REG
+ p.To.Reg = v.Reg()
+ case ssa.OpMIPSSGTzero,
+ ssa.OpMIPSSGTUzero:
+ p := gc.Prog(v.Op.Asm())
+ p.From.Type = obj.TYPE_REG
+ p.From.Reg = v.Args[0].Reg()
+ p.Reg = mips.REGZERO
+ p.To.Type = obj.TYPE_REG
+ p.To.Reg = v.Reg()
+ case ssa.OpMIPSADDconst,
+ ssa.OpMIPSSUBconst,
+ ssa.OpMIPSANDconst,
+ ssa.OpMIPSORconst,
+ ssa.OpMIPSXORconst,
+ ssa.OpMIPSNORconst,
+ ssa.OpMIPSSLLconst,
+ ssa.OpMIPSSRLconst,
+ ssa.OpMIPSSRAconst,
+ ssa.OpMIPSSGTconst,
+ ssa.OpMIPSSGTUconst:
+ p := gc.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.OpMIPSMULT,
+ ssa.OpMIPSMULTU,
+ ssa.OpMIPSDIV,
+ ssa.OpMIPSDIVU:
+ // result in hi,lo
+ p := gc.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.From.Type = obj.TYPE_CONST
+ p.From.Offset = v.AuxInt
+ p.To.Type = obj.TYPE_REG
+ p.To.Reg = r
+ 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.From.Type = obj.TYPE_REG
+ p.From.Reg = mips.REGTMP
+ p.To.Type = obj.TYPE_REG
+ p.To.Reg = r
+ }
+ case ssa.OpMIPSMOVFconst,
+ ssa.OpMIPSMOVDconst:
+ p := gc.Prog(v.Op.Asm())
+ p.From.Type = obj.TYPE_FCONST
+ p.From.Val = math.Float64frombits(uint64(v.AuxInt))
+ p.To.Type = obj.TYPE_REG
+ p.To.Reg = v.Reg()
+ case ssa.OpMIPSCMOVZ:
+ 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.From.Type = obj.TYPE_REG
+ p.From.Reg = v.Args[2].Reg()
+ p.Reg = v.Args[1].Reg()
+ p.To.Type = obj.TYPE_REG
+ p.To.Reg = v.Reg()
+ case ssa.OpMIPSCMOVZzero:
+ 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.From.Type = obj.TYPE_REG
+ p.From.Reg = v.Args[1].Reg()
+ p.Reg = mips.REGZERO
+ p.To.Type = obj.TYPE_REG
+ p.To.Reg = v.Reg()
+ case ssa.OpMIPSCMPEQF,
+ ssa.OpMIPSCMPEQD,
+ ssa.OpMIPSCMPGEF,
+ ssa.OpMIPSCMPGED,
+ ssa.OpMIPSCMPGTF,
+ ssa.OpMIPSCMPGTD:
+ p := gc.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.From.Type = obj.TYPE_ADDR
+ var wantreg string
+ // MOVW $sym+off(base), R
+ // the assembler expands it as the following:
+ // - base is SP: add constant offset to SP (R29)
+ // when constant is large, tmp register (R23) may be used
+ // - base is SB: load external address with relocation
+ switch v.Aux.(type) {
+ default:
+ v.Fatalf("aux is of unknown type %T", v.Aux)
+ case *ssa.ExternSymbol:
+ wantreg = "SB"
+ gc.AddAux(&p.From, v)
+ case *ssa.ArgSymbol, *ssa.AutoSymbol:
+ wantreg = "SP"
+ gc.AddAux(&p.From, v)
+ case nil:
+ // No sym, just MOVW $off(SP), R
+ wantreg = "SP"
+ p.From.Reg = mips.REGSP
+ p.From.Offset = v.AuxInt
+ }
+ if reg := v.Args[0].RegName(); reg != wantreg {
+ v.Fatalf("bad reg %s for symbol type %T, want %s", reg, v.Aux, wantreg)
+ }
+ p.To.Type = obj.TYPE_REG
+ p.To.Reg = v.Reg()
+ case ssa.OpMIPSMOVBload,
+ ssa.OpMIPSMOVBUload,
+ ssa.OpMIPSMOVHload,
+ ssa.OpMIPSMOVHUload,
+ ssa.OpMIPSMOVWload,
+ ssa.OpMIPSMOVFload,
+ ssa.OpMIPSMOVDload:
+ p := gc.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.OpMIPSMOVBstore,
+ ssa.OpMIPSMOVHstore,
+ ssa.OpMIPSMOVWstore,
+ ssa.OpMIPSMOVFstore,
+ ssa.OpMIPSMOVDstore:
+ p := gc.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.OpMIPSMOVBstorezero,
+ ssa.OpMIPSMOVHstorezero,
+ ssa.OpMIPSMOVWstorezero:
+ p := gc.Prog(v.Op.Asm())
+ 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.AddAux(&p.To, v)
+ case ssa.OpMIPSMOVBreg,
+ ssa.OpMIPSMOVBUreg,
+ ssa.OpMIPSMOVHreg,
+ ssa.OpMIPSMOVHUreg:
+ a := v.Args[0]
+ for a.Op == ssa.OpCopy || a.Op == ssa.OpMIPSMOVWreg || a.Op == ssa.OpMIPSMOVWnop {
+ a = a.Args[0]
+ }
+ if a.Op == ssa.OpLoadReg {
+ t := a.Type
+ switch {
+ case v.Op == ssa.OpMIPSMOVBreg && t.Size() == 1 && t.IsSigned(),
+ v.Op == ssa.OpMIPSMOVBUreg && t.Size() == 1 && !t.IsSigned(),
+ v.Op == ssa.OpMIPSMOVHreg && t.Size() == 2 && t.IsSigned(),
+ v.Op == ssa.OpMIPSMOVHUreg && t.Size() == 2 && !t.IsSigned():
+ // arg is a proper-typed load, already zero/sign-extended, don't extend again
+ if v.Reg() == v.Args[0].Reg() {
+ return
+ }
+ p := gc.Prog(mips.AMOVW)
+ p.From.Type = obj.TYPE_REG
+ p.From.Reg = v.Args[0].Reg()
+ p.To.Type = obj.TYPE_REG
+ p.To.Reg = v.Reg()
+ return
+ default:
+ }
+ }
+ fallthrough
+ case ssa.OpMIPSMOVWF,
+ ssa.OpMIPSMOVWD,
+ ssa.OpMIPSTRUNCFW,
+ ssa.OpMIPSTRUNCDW,
+ ssa.OpMIPSMOVFD,
+ ssa.OpMIPSMOVDF,
+ ssa.OpMIPSNEGF,
+ ssa.OpMIPSNEGD,
+ ssa.OpMIPSSQRTD,
+ ssa.OpMIPSCLZ:
+ p := gc.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.From.Type = obj.TYPE_REG
+ p.From.Reg = v.Args[0].Reg()
+ p.Reg = mips.REGZERO
+ p.To.Type = obj.TYPE_REG
+ p.To.Reg = v.Reg()
+ case ssa.OpMIPSLoweredZero:
+ // SUBU $4, R1
+ // MOVW R0, 4(R1)
+ // ADDU $4, R1
+ // BNE Rarg1, R1, -2(PC)
+ // arg1 is the address of the last element to zero
+ var sz int64
+ var mov obj.As
+ switch {
+ case v.AuxInt%4 == 0:
+ sz = 4
+ mov = mips.AMOVW
+ case v.AuxInt%2 == 0:
+ sz = 2
+ mov = mips.AMOVH
+ default:
+ sz = 1
+ mov = mips.AMOVB
+ }
+ p := gc.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.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.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.From.Type = obj.TYPE_REG
+ p4.From.Reg = v.Args[1].Reg()
+ p4.Reg = mips.REG_R1
+ p4.To.Type = obj.TYPE_BRANCH
+ gc.Patch(p4, p2)
+ case ssa.OpMIPSLoweredMove:
+ // SUBU $4, R1
+ // MOVW 4(R1), Rtmp
+ // MOVW Rtmp, (R2)
+ // ADDU $4, R1
+ // ADDU $4, R2
+ // BNE Rarg2, R1, -4(PC)
+ // arg2 is the address of the last element of src
+ var sz int64
+ var mov obj.As
+ switch {
+ case v.AuxInt%4 == 0:
+ sz = 4
+ mov = mips.AMOVW
+ case v.AuxInt%2 == 0:
+ sz = 2
+ mov = mips.AMOVH
+ default:
+ sz = 1
+ mov = mips.AMOVB
+ }
+ p := gc.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.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.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.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.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.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.OpMIPSLoweredAtomicLoad:
+ gc.Prog(mips.ASYNC)
+
+ p := gc.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)
+ case ssa.OpMIPSLoweredAtomicStore:
+ gc.Prog(mips.ASYNC)
+
+ p := gc.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)
+ case ssa.OpMIPSLoweredAtomicStorezero:
+ gc.Prog(mips.ASYNC)
+
+ p := gc.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)
+ case ssa.OpMIPSLoweredAtomicExchange:
+ // SYNC
+ // MOVW Rarg1, Rtmp
+ // LL (Rarg0), Rout
+ // SC Rtmp, (Rarg0)
+ // BEQ Rtmp, -3(PC)
+ // SYNC
+ gc.Prog(mips.ASYNC)
+
+ p := gc.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.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.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.From.Type = obj.TYPE_REG
+ p3.From.Reg = mips.REGTMP
+ p3.To.Type = obj.TYPE_BRANCH
+ gc.Patch(p3, p)
+
+ gc.Prog(mips.ASYNC)
+ case ssa.OpMIPSLoweredAtomicAdd:
+ // SYNC
+ // LL (Rarg0), Rout
+ // ADDU Rarg1, Rout, Rtmp
+ // SC Rtmp, (Rarg0)
+ // BEQ Rtmp, -3(PC)
+ // SYNC
+ // ADDU Rarg1, Rout
+ gc.Prog(mips.ASYNC)
+
+ p := gc.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.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.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.From.Type = obj.TYPE_REG
+ p3.From.Reg = mips.REGTMP
+ p3.To.Type = obj.TYPE_BRANCH
+ gc.Patch(p3, p)
+
+ gc.Prog(mips.ASYNC)
+
+ p4 := gc.Prog(mips.AADDU)
+ p4.From.Type = obj.TYPE_REG
+ p4.From.Reg = v.Args[1].Reg()
+ p4.Reg = v.Reg0()
+ p4.To.Type = obj.TYPE_REG
+ p4.To.Reg = v.Reg0()
+
+ case ssa.OpMIPSLoweredAtomicAddconst:
+ // SYNC
+ // LL (Rarg0), Rout
+ // ADDU $auxInt, Rout, Rtmp
+ // SC Rtmp, (Rarg0)
+ // BEQ Rtmp, -3(PC)
+ // SYNC
+ // ADDU $auxInt, Rout
+ gc.Prog(mips.ASYNC)
+
+ p := gc.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.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.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.From.Type = obj.TYPE_REG
+ p3.From.Reg = mips.REGTMP
+ p3.To.Type = obj.TYPE_BRANCH
+ gc.Patch(p3, p)
+
+ gc.Prog(mips.ASYNC)
+
+ p4 := gc.Prog(mips.AADDU)
+ p4.From.Type = obj.TYPE_CONST
+ p4.From.Offset = v.AuxInt
+ p4.Reg = v.Reg0()
+ p4.To.Type = obj.TYPE_REG
+ p4.To.Reg = v.Reg0()
+
+ case ssa.OpMIPSLoweredAtomicAnd,
+ ssa.OpMIPSLoweredAtomicOr:
+ // SYNC
+ // LL (Rarg0), Rtmp
+ // AND/OR Rarg1, Rtmp
+ // SC Rtmp, (Rarg0)
+ // BEQ Rtmp, -3(PC)
+ // SYNC
+ gc.Prog(mips.ASYNC)
+
+ p := gc.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.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.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.From.Type = obj.TYPE_REG
+ p3.From.Reg = mips.REGTMP
+ p3.To.Type = obj.TYPE_BRANCH
+ gc.Patch(p3, p)
+
+ gc.Prog(mips.ASYNC)
+
+ case ssa.OpMIPSLoweredAtomicCas:
+ // MOVW $0, Rout
+ // SYNC
+ // LL (Rarg0), Rtmp
+ // BNE Rtmp, Rarg1, 4(PC)
+ // MOVW Rarg2, Rout
+ // SC Rout, (Rarg0)
+ // BEQ Rout, -4(PC)
+ // SYNC
+ p := gc.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)
+
+ p1 := gc.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.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.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.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.From.Type = obj.TYPE_REG
+ p5.From.Reg = v.Reg0()
+ p5.To.Type = obj.TYPE_BRANCH
+ gc.Patch(p5, p1)
+
+ gc.Prog(mips.ASYNC)
+
+ p6 := gc.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.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")
+ }
+ case ssa.OpMIPSFPFlagTrue,
+ ssa.OpMIPSFPFlagFalse:
+ // MOVW $1, r
+ // CMOVF R0, r
+
+ cmov := mips.ACMOVF
+ if v.Op == ssa.OpMIPSFPFlagFalse {
+ cmov = mips.ACMOVT
+ }
+ p := gc.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.From.Type = obj.TYPE_REG
+ p1.From.Reg = mips.REGZERO
+ p1.To.Type = obj.TYPE_REG
+ p1.To.Reg = v.Reg()
+
+ case ssa.OpMIPSLoweredGetClosurePtr:
+ // Closure pointer is R22 (mips.REGCTXT).
+ gc.CheckLoweredGetClosurePtr(v)
+ default:
+ v.Fatalf("genValue not implemented: %s", v.LongString())
+ }
+}
+
+var blockJump = map[ssa.BlockKind]struct {
+ asm, invasm obj.As
+}{
+ ssa.BlockMIPSEQ: {mips.ABEQ, mips.ABNE},
+ ssa.BlockMIPSNE: {mips.ABNE, mips.ABEQ},
+ ssa.BlockMIPSLTZ: {mips.ABLTZ, mips.ABGEZ},
+ ssa.BlockMIPSGEZ: {mips.ABGEZ, mips.ABLTZ},
+ ssa.BlockMIPSLEZ: {mips.ABLEZ, mips.ABGTZ},
+ ssa.BlockMIPSGTZ: {mips.ABGTZ, mips.ABLEZ},
+ ssa.BlockMIPSFPT: {mips.ABFPT, mips.ABFPF},
+ ssa.BlockMIPSFPF: {mips.ABFPF, mips.ABFPT},
+}
+
+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.To.Type = obj.TYPE_BRANCH
+ s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()})
+ }
+ case ssa.BlockDefer:
+ // defer returns in R1:
+ // 0 if we should continue executing
+ // 1 if we should jump to deferreturn call
+ p := gc.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.To.Type = obj.TYPE_BRANCH
+ s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()})
+ }
+ case ssa.BlockExit:
+ gc.Prog(obj.AUNDEF) // tell plive.go that we never reach here
+ case ssa.BlockRet:
+ gc.Prog(obj.ARET)
+ case ssa.BlockRetJmp:
+ p := gc.Prog(obj.ARET)
+ p.To.Type = obj.TYPE_MEM
+ p.To.Name = obj.NAME_EXTERN
+ p.To.Sym = gc.Linksym(b.Aux.(*gc.Sym))
+ case ssa.BlockMIPSEQ, ssa.BlockMIPSNE,
+ ssa.BlockMIPSLTZ, ssa.BlockMIPSGEZ,
+ ssa.BlockMIPSLEZ, ssa.BlockMIPSGTZ,
+ ssa.BlockMIPSFPT, ssa.BlockMIPSFPF:
+ jmp := blockJump[b.Kind]
+ var p *obj.Prog
+ switch next {
+ case b.Succs[0].Block():
+ p = gc.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.To.Type = obj.TYPE_BRANCH
+ s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()})
+ default:
+ p = gc.Prog(jmp.asm)
+ p.To.Type = obj.TYPE_BRANCH
+ s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()})
+ q := gc.Prog(obj.AJMP)
+ q.To.Type = obj.TYPE_BRANCH
+ s.Branches = append(s.Branches, gc.Branch{P: q, B: b.Succs[1].Block()})
+ }
+ if !b.Control.Type.IsFlags() {
+ p.From.Type = obj.TYPE_REG
+ p.From.Reg = b.Control.Reg()
+ }
+ default:
+ b.Fatalf("branch not implemented: %s. Control: %s", b.LongString(), b.Control.LongString())
+ }
+}
diff --git a/src/cmd/compile/internal/mips64/cgen.go b/src/cmd/compile/internal/mips64/cgen.go
deleted file mode 100644
index 998afea..0000000
--- a/src/cmd/compile/internal/mips64/cgen.go
+++ /dev/null
@@ -1,157 +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 mips64
-
-import (
- "cmd/compile/internal/gc"
- "cmd/internal/obj"
- "cmd/internal/obj/mips"
-)
-
-func blockcopy(n, res *gc.Node, osrc, odst, w int64) {
- // determine alignment.
- // want to avoid unaligned access, so have to use
- // smaller operations for less aligned types.
- // for example moving [4]byte must use 4 MOVB not 1 MOVW.
- align := int(n.Type.Align)
-
- var op obj.As
- switch align {
- default:
- gc.Fatalf("sgen: invalid alignment %d for %v", align, n.Type)
-
- case 1:
- op = mips.AMOVB
-
- case 2:
- op = mips.AMOVH
-
- case 4:
- op = mips.AMOVW
-
- case 8:
- op = mips.AMOVV
- }
-
- if w%int64(align) != 0 {
- gc.Fatalf("sgen: unaligned size %d (align=%d) for %v", w, align, n.Type)
- }
- c := int32(w / int64(align))
-
- // if we are copying forward on the stack and
- // the src and dst overlap, then reverse direction
- dir := align
-
- if osrc < odst && odst < osrc+w {
- dir = -dir
- }
-
- var dst gc.Node
- var src gc.Node
- if n.Ullman >= res.Ullman {
- gc.Agenr(n, &dst, res) // temporarily use dst
- gc.Regalloc(&src, gc.Types[gc.Tptr], nil)
- gins(mips.AMOVV, &dst, &src)
- if res.Op == gc.ONAME {
- gc.Gvardef(res)
- }
- gc.Agen(res, &dst)
- } else {
- if res.Op == gc.ONAME {
- gc.Gvardef(res)
- }
- gc.Agenr(res, &dst, res)
- gc.Agenr(n, &src, nil)
- }
-
- var tmp gc.Node
- gc.Regalloc(&tmp, gc.Types[gc.Tptr], nil)
-
- // set up end marker
- var nend gc.Node
-
- // move src and dest to the end of block if necessary
- if dir < 0 {
- if c >= 4 {
- gc.Regalloc(&nend, gc.Types[gc.Tptr], nil)
- gins(mips.AMOVV, &src, &nend)
- }
-
- p := gins(mips.AADDV, nil, &src)
- p.From.Type = obj.TYPE_CONST
- p.From.Offset = w
-
- p = gins(mips.AADDV, nil, &dst)
- p.From.Type = obj.TYPE_CONST
- p.From.Offset = w
- } else {
- p := gins(mips.AADDV, nil, &src)
- p.From.Type = obj.TYPE_CONST
- p.From.Offset = int64(-dir)
-
- p = gins(mips.AADDV, nil, &dst)
- p.From.Type = obj.TYPE_CONST
- p.From.Offset = int64(-dir)
-
- if c >= 4 {
- gc.Regalloc(&nend, gc.Types[gc.Tptr], nil)
- p := gins(mips.AMOVV, &src, &nend)
- p.From.Type = obj.TYPE_ADDR
- p.From.Offset = w
- }
- }
-
- // move
- // TODO: enable duffcopy for larger copies.
- if c >= 4 {
- p := gins(op, &src, &tmp)
- p.From.Type = obj.TYPE_MEM
- p.From.Offset = int64(dir)
- ploop := p
-
- p = gins(mips.AADDV, nil, &src)
- p.From.Type = obj.TYPE_CONST
- p.From.Offset = int64(dir)
-
- p = gins(op, &tmp, &dst)
- p.To.Type = obj.TYPE_MEM
- p.To.Offset = int64(dir)
-
- p = gins(mips.AADDV, nil, &dst)
- p.From.Type = obj.TYPE_CONST
- p.From.Offset = int64(dir)
-
- gc.Patch(ginsbranch(mips.ABNE, nil, &src, &nend, 0), ploop)
- gc.Regfree(&nend)
- } else {
- // TODO: Instead of generating ADDV $-8,R8; ADDV
- // $-8,R7; n*(MOVV 8(R8),R9; ADDV $8,R8; MOVV R9,8(R7);
- // ADDV $8,R7;) just generate the offsets directly and
- // eliminate the ADDs. That will produce shorter, more
- // pipeline-able code.
- var p *obj.Prog
- for ; c > 0; c-- {
- p = gins(op, &src, &tmp)
- p.From.Type = obj.TYPE_MEM
- p.From.Offset = int64(dir)
-
- p = gins(mips.AADDV, nil, &src)
- p.From.Type = obj.TYPE_CONST
- p.From.Offset = int64(dir)
-
- p = gins(op, &tmp, &dst)
- p.To.Type = obj.TYPE_MEM
- p.To.Offset = int64(dir)
-
- p = gins(mips.AADDV, nil, &dst)
- p.From.Type = obj.TYPE_CONST
- p.From.Offset = int64(dir)
- }
- }
-
- gc.Regfree(&dst)
- gc.Regfree(&src)
- gc.Regfree(&tmp)
-}
diff --git a/src/cmd/compile/internal/mips64/galign.go b/src/cmd/compile/internal/mips64/galign.go
index 22890c8..4a36a4c 100644
--- a/src/cmd/compile/internal/mips64/galign.go
+++ b/src/cmd/compile/internal/mips64/galign.go
@@ -6,62 +6,23 @@ package mips64
import (
"cmd/compile/internal/gc"
+ "cmd/compile/internal/ssa"
"cmd/internal/obj"
"cmd/internal/obj/mips"
)
-func betypeinit() {
-}
-
-func Main() {
+func Init() {
gc.Thearch.LinkArch = &mips.Linkmips64
- if obj.Getgoarch() == "mips64le" {
+ if obj.GOARCH == "mips64le" {
gc.Thearch.LinkArch = &mips.Linkmips64le
}
gc.Thearch.REGSP = mips.REGSP
- gc.Thearch.REGCTXT = mips.REGCTXT
- gc.Thearch.REGCALLX = mips.REG_R1
- gc.Thearch.REGCALLX2 = mips.REG_R2
- gc.Thearch.REGRETURN = mips.REGRET
- gc.Thearch.REGMIN = mips.REG_R0
- gc.Thearch.REGMAX = mips.REG_R31
- gc.Thearch.FREGMIN = mips.REG_F0
- gc.Thearch.FREGMAX = mips.REG_F31
gc.Thearch.MAXWIDTH = 1 << 50
- gc.Thearch.ReservedRegs = resvd
- gc.Thearch.Betypeinit = betypeinit
- gc.Thearch.Cgen_hmul = cgen_hmul
- gc.Thearch.Cgen_shift = cgen_shift
- gc.Thearch.Clearfat = clearfat
gc.Thearch.Defframe = defframe
- gc.Thearch.Dodiv = dodiv
- gc.Thearch.Excise = excise
- gc.Thearch.Expandchecks = expandchecks
- gc.Thearch.Getg = getg
- gc.Thearch.Gins = gins
- gc.Thearch.Ginscmp = ginscmp
- gc.Thearch.Ginscon = ginscon
- gc.Thearch.Ginsnop = ginsnop
- gc.Thearch.Gmove = gmove
- gc.Thearch.Peep = peep
gc.Thearch.Proginfo = proginfo
- gc.Thearch.Regtyp = regtyp
- gc.Thearch.Sameaddr = sameaddr
- gc.Thearch.Smallindir = smallindir
- gc.Thearch.Stackaddr = stackaddr
- gc.Thearch.Blockcopy = blockcopy
- gc.Thearch.Sudoaddable = sudoaddable
- gc.Thearch.Sudoclean = sudoclean
- gc.Thearch.Excludedregs = excludedregs
- gc.Thearch.RtoB = RtoB
- gc.Thearch.FtoB = RtoB
- gc.Thearch.BtoR = BtoR
- gc.Thearch.BtoF = BtoF
- gc.Thearch.Optoas = optoas
- gc.Thearch.Doregbits = doregbits
- gc.Thearch.Regnames = regnames
- gc.Main()
- gc.Exit(0)
+ gc.Thearch.SSAMarkMoves = func(s *gc.SSAGenState, b *ssa.Block) {}
+ gc.Thearch.SSAGenValue = ssaGenValue
+ gc.Thearch.SSAGenBlock = ssaGenBlock
}
diff --git a/src/cmd/compile/internal/mips64/ggen.go b/src/cmd/compile/internal/mips64/ggen.go
index e0c4de2..2af4a8b 100644
--- a/src/cmd/compile/internal/mips64/ggen.go
+++ b/src/cmd/compile/internal/mips64/ggen.go
@@ -8,7 +8,6 @@ import (
"cmd/compile/internal/gc"
"cmd/internal/obj"
"cmd/internal/obj/mips"
- "fmt"
)
func defframe(ptxt *obj.Prog) {
@@ -36,7 +35,7 @@ func defframe(ptxt *obj.Prog) {
gc.Fatalf("needzero class %d", n.Class)
}
if n.Type.Width%int64(gc.Widthptr) != 0 || n.Xoffset%int64(gc.Widthptr) != 0 || n.Type.Width == 0 {
- gc.Fatalf("var %v has size %d offset %d", gc.Nconv(n, gc.FmtLong), int(n.Type.Width), int(n.Xoffset))
+ 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) {
@@ -66,18 +65,13 @@ func zerorange(p *obj.Prog, frame int64, lo int64, hi int64) *obj.Prog {
}
if cnt < int64(4*gc.Widthptr) {
for i := int64(0); i < cnt; i += int64(gc.Widthptr) {
- p = appendpp(p, mips.AMOVV, obj.TYPE_REG, mips.REGZERO, 0, obj.TYPE_MEM, mips.REGSP, 8+frame+lo+i)
+ p = gc.Appendpp(p, mips.AMOVV, obj.TYPE_REG, mips.REGZERO, 0, obj.TYPE_MEM, mips.REGSP, 8+frame+lo+i)
}
- // TODO(dfc): https://golang.org/issue/12108
- // If DUFFZERO is used inside a tail call (see genwrapper) it will
- // overwrite the link register.
- } else if false && cnt <= int64(128*gc.Widthptr) {
- p = appendpp(p, mips.AADDV, obj.TYPE_CONST, 0, 8+frame+lo-8, obj.TYPE_REG, mips.REGRT1, 0)
+ } 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.Reg = mips.REGSP
- p = appendpp(p, obj.ADUFFZERO, obj.TYPE_NONE, 0, 0, obj.TYPE_MEM, 0, 0)
- f := gc.Sysfunc("duffzero")
- gc.Naddr(&p.To, f)
- gc.Afunclit(&p.To, f)
+ p = gc.Appendpp(p, obj.ADUFFZERO, obj.TYPE_NONE, 0, 0, obj.TYPE_MEM, 0, 0)
+ gc.Naddr(&p.To, gc.Sysfunc("duffzero"))
p.To.Offset = 8 * (128 - cnt/int64(gc.Widthptr))
} else {
// ADDV $(8+frame+lo-8), SP, r1
@@ -86,14 +80,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 = appendpp(p, mips.AADDV, obj.TYPE_CONST, 0, 8+frame+lo-8, obj.TYPE_REG, mips.REGRT1, 0)
+ p = gc.Appendpp(p, mips.AADDV, obj.TYPE_CONST, 0, 8+frame+lo-8, obj.TYPE_REG, mips.REGRT1, 0)
p.Reg = mips.REGSP
- p = appendpp(p, mips.AADDV, obj.TYPE_CONST, 0, cnt, obj.TYPE_REG, mips.REGRT2, 0)
+ p = gc.Appendpp(p, mips.AADDV, obj.TYPE_CONST, 0, cnt, obj.TYPE_REG, mips.REGRT2, 0)
p.Reg = mips.REGRT1
- p = appendpp(p, mips.AMOVV, obj.TYPE_REG, mips.REGZERO, 0, obj.TYPE_MEM, mips.REGRT1, int64(gc.Widthptr))
+ p = gc.Appendpp(p, mips.AMOVV, obj.TYPE_REG, mips.REGZERO, 0, obj.TYPE_MEM, mips.REGRT1, int64(gc.Widthptr))
p1 := p
- p = appendpp(p, mips.AADDV, obj.TYPE_CONST, 0, int64(gc.Widthptr), obj.TYPE_REG, mips.REGRT1, 0)
- p = appendpp(p, mips.ABNE, obj.TYPE_REG, mips.REGRT1, 0, obj.TYPE_BRANCH, 0, 0)
+ 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.Reg = mips.REGRT2
gc.Patch(p, p1)
}
@@ -101,391 +95,10 @@ func zerorange(p *obj.Prog, frame int64, lo int64, hi int64) *obj.Prog {
return p
}
-func appendpp(p *obj.Prog, as obj.As, ftype obj.AddrType, freg int, foffset int64, ttype obj.AddrType, treg int, toffset int64) *obj.Prog {
- q := gc.Ctxt.NewProg()
- gc.Clearp(q)
- q.As = as
- q.Lineno = p.Lineno
- q.From.Type = ftype
- q.From.Reg = int16(freg)
- q.From.Offset = foffset
- q.To.Type = ttype
- q.To.Reg = int16(treg)
- q.To.Offset = toffset
- q.Link = p.Link
- p.Link = q
- return q
-}
-
func ginsnop() {
- var reg gc.Node
- gc.Nodreg(®, gc.Types[gc.TINT], mips.REG_R0)
- gins(mips.ANOR, ®, ®)
-}
-
-var panicdiv *gc.Node
-
-/*
- * generate division.
- * generates one of:
- * res = nl / nr
- * res = nl % nr
- * according to op.
- */
-func dodiv(op gc.Op, nl *gc.Node, nr *gc.Node, res *gc.Node) {
- t := nl.Type
-
- t0 := t
-
- if t.Width < 8 {
- if t.IsSigned() {
- t = gc.Types[gc.TINT64]
- } else {
- t = gc.Types[gc.TUINT64]
- }
- }
-
- a := optoas(gc.ODIV, t)
-
- var tl gc.Node
- gc.Regalloc(&tl, t0, nil)
- var tr gc.Node
- gc.Regalloc(&tr, t0, nil)
- if nl.Ullman >= nr.Ullman {
- gc.Cgen(nl, &tl)
- gc.Cgen(nr, &tr)
- } else {
- gc.Cgen(nr, &tr)
- gc.Cgen(nl, &tl)
- }
-
- if t != t0 {
- // Convert
- tl2 := tl
-
- tr2 := tr
- tl.Type = t
- tr.Type = t
- gmove(&tl2, &tl)
- gmove(&tr2, &tr)
- }
-
- // Handle divide-by-zero panic.
- p1 := ginsbranch(mips.ABNE, nil, &tr, nil, 0)
- if panicdiv == nil {
- panicdiv = gc.Sysfunc("panicdivide")
- }
- gc.Ginscall(panicdiv, -1)
- gc.Patch(p1, gc.Pc)
-
- gins3(a, &tr, &tl, nil)
- gc.Regfree(&tr)
- if op == gc.ODIV {
- var lo gc.Node
- gc.Nodreg(&lo, gc.Types[gc.TUINT64], mips.REG_LO)
- gins(mips.AMOVV, &lo, &tl)
- } else { // remainder in REG_HI
- var hi gc.Node
- gc.Nodreg(&hi, gc.Types[gc.TUINT64], mips.REG_HI)
- gins(mips.AMOVV, &hi, &tl)
- }
- gmove(&tl, res)
- gc.Regfree(&tl)
-}
-
-/*
- * generate high multiply:
- * res = (nl*nr) >> width
- */
-func cgen_hmul(nl *gc.Node, nr *gc.Node, res *gc.Node) {
- // largest ullman on left.
- if nl.Ullman < nr.Ullman {
- nl, nr = nr, nl
- }
-
- t := nl.Type
- w := t.Width * 8
- var n1 gc.Node
- gc.Cgenr(nl, &n1, res)
- var n2 gc.Node
- gc.Cgenr(nr, &n2, nil)
- switch gc.Simtype[t.Etype] {
- case gc.TINT8,
- gc.TINT16,
- gc.TINT32:
- gins3(optoas(gc.OMUL, t), &n2, &n1, nil)
- var lo gc.Node
- gc.Nodreg(&lo, gc.Types[gc.TUINT64], mips.REG_LO)
- gins(mips.AMOVV, &lo, &n1)
- p := gins(mips.ASRAV, nil, &n1)
- p.From.Type = obj.TYPE_CONST
- p.From.Offset = w
-
- case gc.TUINT8,
- gc.TUINT16,
- gc.TUINT32:
- gins3(optoas(gc.OMUL, t), &n2, &n1, nil)
- var lo gc.Node
- gc.Nodreg(&lo, gc.Types[gc.TUINT64], mips.REG_LO)
- gins(mips.AMOVV, &lo, &n1)
- p := gins(mips.ASRLV, nil, &n1)
- p.From.Type = obj.TYPE_CONST
- p.From.Offset = w
-
- case gc.TINT64,
- gc.TUINT64:
- if t.IsSigned() {
- gins3(mips.AMULV, &n2, &n1, nil)
- } else {
- gins3(mips.AMULVU, &n2, &n1, nil)
- }
- var hi gc.Node
- gc.Nodreg(&hi, gc.Types[gc.TUINT64], mips.REG_HI)
- gins(mips.AMOVV, &hi, &n1)
-
- default:
- gc.Fatalf("cgen_hmul %v", t)
- }
-
- gc.Cgen(&n1, res)
- gc.Regfree(&n1)
- gc.Regfree(&n2)
-}
-
-/*
- * generate shift according to op, one of:
- * res = nl << nr
- * res = nl >> nr
- */
-func cgen_shift(op gc.Op, bounded bool, nl *gc.Node, nr *gc.Node, res *gc.Node) {
- a := optoas(op, nl.Type)
-
- if nr.Op == gc.OLITERAL {
- var n1 gc.Node
- gc.Regalloc(&n1, nl.Type, res)
- gc.Cgen(nl, &n1)
- sc := uint64(nr.Int64())
- if sc >= uint64(nl.Type.Width*8) {
- // large shift gets 2 shifts by width-1
- var n3 gc.Node
- gc.Nodconst(&n3, gc.Types[gc.TUINT32], nl.Type.Width*8-1)
-
- gins(a, &n3, &n1)
- gins(a, &n3, &n1)
- } else {
- gins(a, nr, &n1)
- }
- gmove(&n1, res)
- gc.Regfree(&n1)
- return
- }
-
- if nl.Ullman >= gc.UINF {
- var n4 gc.Node
- gc.Tempname(&n4, nl.Type)
- gc.Cgen(nl, &n4)
- nl = &n4
- }
-
- if nr.Ullman >= gc.UINF {
- var n5 gc.Node
- gc.Tempname(&n5, nr.Type)
- gc.Cgen(nr, &n5)
- nr = &n5
- }
-
- // Allow either uint32 or uint64 as shift type,
- // to avoid unnecessary conversion from uint32 to uint64
- // just to do the comparison.
- tcount := gc.Types[gc.Simtype[nr.Type.Etype]]
-
- if tcount.Etype < gc.TUINT32 {
- tcount = gc.Types[gc.TUINT32]
- }
-
- var n1 gc.Node
- gc.Regalloc(&n1, nr.Type, nil) // to hold the shift type in CX
- var n3 gc.Node
- gc.Regalloc(&n3, tcount, &n1) // to clear high bits of CX
-
- var n2 gc.Node
- gc.Regalloc(&n2, nl.Type, res)
-
- if nl.Ullman >= nr.Ullman {
- gc.Cgen(nl, &n2)
- gc.Cgen(nr, &n1)
- gmove(&n1, &n3)
- } else {
- gc.Cgen(nr, &n1)
- gmove(&n1, &n3)
- gc.Cgen(nl, &n2)
- }
-
- gc.Regfree(&n3)
-
- // test and fix up large shifts
- if !bounded {
- var rtmp gc.Node
- gc.Nodreg(&rtmp, tcount, mips.REGTMP)
- gc.Nodconst(&n3, tcount, nl.Type.Width*8)
- gins3(mips.ASGTU, &n3, &n1, &rtmp)
- p1 := ginsbranch(mips.ABNE, nil, &rtmp, nil, 0)
- if op == gc.ORSH && nl.Type.IsSigned() {
- gc.Nodconst(&n3, gc.Types[gc.TUINT32], nl.Type.Width*8-1)
- gins(a, &n3, &n2)
- } else {
- gc.Nodconst(&n3, nl.Type, 0)
- gmove(&n3, &n2)
- }
-
- gc.Patch(p1, gc.Pc)
- }
-
- gins(a, &n1, &n2)
-
- gmove(&n2, res)
-
- gc.Regfree(&n1)
- gc.Regfree(&n2)
-}
-
-func clearfat(nl *gc.Node) {
- /* clear a fat object */
- if gc.Debug['g'] != 0 {
- fmt.Printf("clearfat %v (%v, size: %d)\n", nl, nl.Type, nl.Type.Width)
- }
-
- w := uint64(nl.Type.Width)
-
- // Avoid taking the address for simple enough types.
- if gc.Componentgen(nil, nl) {
- return
- }
-
- c := w % 8 // bytes
- q := w / 8 // dwords
-
- if gc.Reginuse(mips.REGRT1) {
- gc.Fatalf("%v in use during clearfat", obj.Rconv(mips.REGRT1))
- }
-
- var r0 gc.Node
- gc.Nodreg(&r0, gc.Types[gc.TUINT64], mips.REGZERO)
- var dst gc.Node
- gc.Nodreg(&dst, gc.Types[gc.Tptr], mips.REGRT1)
- gc.Regrealloc(&dst)
- gc.Agen(nl, &dst)
-
- var boff uint64
- if q > 128 {
- p := gins(mips.ASUBV, nil, &dst)
- p.From.Type = obj.TYPE_CONST
- p.From.Offset = 8
-
- var end gc.Node
- gc.Regalloc(&end, gc.Types[gc.Tptr], nil)
- p = gins(mips.AMOVV, &dst, &end)
- p.From.Type = obj.TYPE_ADDR
- p.From.Offset = int64(q * 8)
-
- p = gins(mips.AMOVV, &r0, &dst)
- p.To.Type = obj.TYPE_MEM
- p.To.Offset = 8
- pl := p
-
- p = gins(mips.AADDV, nil, &dst)
- p.From.Type = obj.TYPE_CONST
- p.From.Offset = 8
-
- gc.Patch(ginsbranch(mips.ABNE, nil, &dst, &end, 0), pl)
-
- gc.Regfree(&end)
-
- // The loop leaves R1 on the last zeroed dword
- boff = 8
- // TODO(dfc): https://golang.org/issue/12108
- // If DUFFZERO is used inside a tail call (see genwrapper) it will
- // overwrite the link register.
- } else if false && q >= 4 {
- p := gins(mips.ASUBV, nil, &dst)
- p.From.Type = obj.TYPE_CONST
- p.From.Offset = 8
- f := gc.Sysfunc("duffzero")
- p = gins(obj.ADUFFZERO, nil, f)
- gc.Afunclit(&p.To, f)
-
- // 8 and 128 = magic constants: see ../../runtime/asm_mips64x.s
- p.To.Offset = int64(8 * (128 - q))
-
- // duffzero leaves R1 on the last zeroed dword
- boff = 8
- } else {
- var p *obj.Prog
- for t := uint64(0); t < q; t++ {
- p = gins(mips.AMOVV, &r0, &dst)
- p.To.Type = obj.TYPE_MEM
- p.To.Offset = int64(8 * t)
- }
-
- boff = 8 * q
- }
-
- var p *obj.Prog
- for t := uint64(0); t < c; t++ {
- p = gins(mips.AMOVB, &r0, &dst)
- p.To.Type = obj.TYPE_MEM
- p.To.Offset = int64(t + boff)
- }
-
- gc.Regfree(&dst)
-}
-
-// Called after regopt and peep have run.
-// Expand CHECKNIL pseudo-op into actual nil pointer check.
-func expandchecks(firstp *obj.Prog) {
- var p1 *obj.Prog
-
- for p := firstp; p != nil; p = p.Link {
- if gc.Debug_checknil != 0 && gc.Ctxt.Debugvlog != 0 {
- fmt.Printf("expandchecks: %v\n", p)
- }
- if p.As != obj.ACHECKNIL {
- continue
- }
- if gc.Debug_checknil != 0 && p.Lineno > 1 { // p->lineno==1 in generated wrappers
- gc.Warnl(p.Lineno, "generated nil check")
- }
- if p.From.Type != obj.TYPE_REG {
- gc.Fatalf("invalid nil check %v\n", p)
- }
-
- // check is
- // BNE arg, 2(PC)
- // MOVV R0, 0(R0)
- p1 = gc.Ctxt.NewProg()
- gc.Clearp(p1)
- p1.Link = p.Link
- p.Link = p1
- p1.Lineno = p.Lineno
- p1.Pc = 9999
-
- p.As = mips.ABNE
- p.To.Type = obj.TYPE_BRANCH
- p.To.Val = p1.Link
-
- // crash by write to memory address 0.
- p1.As = mips.AMOVV
- p1.From.Type = obj.TYPE_REG
- p1.From.Reg = mips.REGZERO
- p1.To.Type = obj.TYPE_MEM
- p1.To.Reg = mips.REGZERO
- p1.To.Offset = 0
- }
-}
-
-// res = runtime.getg()
-func getg(res *gc.Node) {
- var n1 gc.Node
- gc.Nodreg(&n1, res.Type, mips.REGG)
- gmove(&n1, res)
+ p := gc.Prog(mips.ANOR)
+ p.From.Type = obj.TYPE_REG
+ p.From.Reg = mips.REG_R0
+ p.To.Type = obj.TYPE_REG
+ p.To.Reg = mips.REG_R0
}
diff --git a/src/cmd/compile/internal/mips64/gsubr.go b/src/cmd/compile/internal/mips64/gsubr.go
deleted file mode 100644
index eb56d8b..0000000
--- a/src/cmd/compile/internal/mips64/gsubr.go
+++ /dev/null
@@ -1,1071 +0,0 @@
-// Derived from Inferno utils/6c/txt.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6c/txt.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth at terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth at terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// Portions Copyright © 2009 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-package mips64
-
-import (
- "cmd/compile/internal/big"
- "cmd/compile/internal/gc"
- "cmd/internal/obj"
- "cmd/internal/obj/mips"
- "fmt"
-)
-
-var resvd = []int{
- mips.REGZERO,
- mips.REGSP, // reserved for SP
- mips.REGSB, // reserved for SB
- mips.REGLINK, // reserved for link
- mips.REGG,
- mips.REGTMP,
- mips.REG_R26, // kernel
- mips.REG_R27, // kernel
- mips.FREGZERO,
- mips.FREGHALF,
- mips.FREGONE,
- mips.FREGTWO,
-}
-
-/*
- * generate
- * as $c, n
- */
-func ginscon(as obj.As, c int64, n2 *gc.Node) {
- var n1 gc.Node
-
- gc.Nodconst(&n1, gc.Types[gc.TINT64], c)
-
- if as != mips.AMOVV && (c < -mips.BIG || c > mips.BIG) || n2.Op != gc.OREGISTER || as == mips.AMUL || as == mips.AMULU || as == mips.AMULV || as == mips.AMULVU {
- // cannot have more than 16-bit of immediate in ADD, etc.
- // instead, MOV into register first.
- var ntmp gc.Node
- gc.Regalloc(&ntmp, gc.Types[gc.TINT64], nil)
-
- rawgins(mips.AMOVV, &n1, &ntmp)
- rawgins(as, &ntmp, n2)
- gc.Regfree(&ntmp)
- return
- }
-
- rawgins(as, &n1, n2)
-}
-
-// generate branch
-// n1, n2 are registers
-func ginsbranch(as obj.As, t *gc.Type, n1, n2 *gc.Node, likely int) *obj.Prog {
- p := gc.Gbranch(as, t, likely)
- gc.Naddr(&p.From, n1)
- if n2 != nil {
- p.Reg = n2.Reg
- }
- return p
-}
-
-func ginscmp(op gc.Op, t *gc.Type, n1, n2 *gc.Node, likely int) *obj.Prog {
- if !t.IsFloat() && (op == gc.OLT || op == gc.OGE) {
- // swap nodes to fit SGT instruction
- n1, n2 = n2, n1
- }
- if t.IsFloat() && (op == gc.OLT || op == gc.OLE) {
- // swap nodes to fit CMPGT, CMPGE instructions and reverse relation
- n1, n2 = n2, n1
- if op == gc.OLT {
- op = gc.OGT
- } else {
- op = gc.OGE
- }
- }
-
- var r1, r2, g1, g2 gc.Node
- gc.Regalloc(&r1, t, n1)
- gc.Regalloc(&g1, n1.Type, &r1)
- gc.Cgen(n1, &g1)
- gmove(&g1, &r1)
-
- gc.Regalloc(&r2, t, n2)
- gc.Regalloc(&g2, n1.Type, &r2)
- gc.Cgen(n2, &g2)
- gmove(&g2, &r2)
-
- var p *obj.Prog
- var ntmp gc.Node
- gc.Nodreg(&ntmp, gc.Types[gc.TINT], mips.REGTMP)
-
- switch gc.Simtype[t.Etype] {
- case gc.TINT8,
- gc.TINT16,
- gc.TINT32,
- gc.TINT64:
- if op == gc.OEQ || op == gc.ONE {
- p = ginsbranch(optoas(op, t), nil, &r1, &r2, likely)
- } else {
- gins3(mips.ASGT, &r1, &r2, &ntmp)
-
- p = ginsbranch(optoas(op, t), nil, &ntmp, nil, likely)
- }
-
- case gc.TBOOL,
- gc.TUINT8,
- gc.TUINT16,
- gc.TUINT32,
- gc.TUINT64,
- gc.TPTR32,
- gc.TPTR64:
- if op == gc.OEQ || op == gc.ONE {
- p = ginsbranch(optoas(op, t), nil, &r1, &r2, likely)
- } else {
- gins3(mips.ASGTU, &r1, &r2, &ntmp)
-
- p = ginsbranch(optoas(op, t), nil, &ntmp, nil, likely)
- }
-
- case gc.TFLOAT32:
- switch op {
- default:
- gc.Fatalf("ginscmp: no entry for op=%s type=%v", op, t)
-
- case gc.OEQ,
- gc.ONE:
- gins3(mips.ACMPEQF, &r1, &r2, nil)
-
- case gc.OGE:
- gins3(mips.ACMPGEF, &r1, &r2, nil)
-
- case gc.OGT:
- gins3(mips.ACMPGTF, &r1, &r2, nil)
- }
- p = gc.Gbranch(optoas(op, t), nil, likely)
-
- case gc.TFLOAT64:
- switch op {
- default:
- gc.Fatalf("ginscmp: no entry for op=%s type=%v", op, t)
-
- case gc.OEQ,
- gc.ONE:
- gins3(mips.ACMPEQD, &r1, &r2, nil)
-
- case gc.OGE:
- gins3(mips.ACMPGED, &r1, &r2, nil)
-
- case gc.OGT:
- gins3(mips.ACMPGTD, &r1, &r2, nil)
- }
- p = gc.Gbranch(optoas(op, t), nil, likely)
- }
-
- gc.Regfree(&g2)
- gc.Regfree(&r2)
- gc.Regfree(&g1)
- gc.Regfree(&r1)
-
- return p
-}
-
-// set up nodes representing 2^63
-var (
- bigi gc.Node
- bigf gc.Node
- bignodes_did bool
-)
-
-func bignodes() {
- if bignodes_did {
- return
- }
- bignodes_did = true
-
- var i big.Int
- i.SetInt64(1)
- i.Lsh(&i, 63)
-
- gc.Nodconst(&bigi, gc.Types[gc.TUINT64], 0)
- bigi.SetBigInt(&i)
-
- bigi.Convconst(&bigf, gc.Types[gc.TFLOAT64])
-}
-
-/*
- * generate move:
- * t = f
- * hard part is conversions.
- */
-func gmove(f *gc.Node, t *gc.Node) {
- if gc.Debug['M'] != 0 {
- fmt.Printf("gmove %v -> %v\n", gc.Nconv(f, gc.FmtLong), gc.Nconv(t, gc.FmtLong))
- }
-
- ft := int(gc.Simsimtype(f.Type))
- tt := int(gc.Simsimtype(t.Type))
- cvt := t.Type
-
- if gc.Iscomplex[ft] || gc.Iscomplex[tt] {
- gc.Complexmove(f, t)
- return
- }
-
- // cannot have two memory operands
- var r2 gc.Node
- var r1 gc.Node
- var a obj.As
- if gc.Ismem(f) && gc.Ismem(t) {
- goto hard
- }
-
- // convert constant to desired type
- if f.Op == gc.OLITERAL {
- var con gc.Node
- switch tt {
- default:
- f.Convconst(&con, t.Type)
-
- case gc.TINT32,
- gc.TINT16,
- gc.TINT8:
- var con gc.Node
- f.Convconst(&con, gc.Types[gc.TINT64])
- var r1 gc.Node
- gc.Regalloc(&r1, con.Type, t)
- gins(mips.AMOVV, &con, &r1)
- gmove(&r1, t)
- gc.Regfree(&r1)
- return
-
- case gc.TUINT32,
- gc.TUINT16,
- gc.TUINT8:
- var con gc.Node
- f.Convconst(&con, gc.Types[gc.TUINT64])
- var r1 gc.Node
- gc.Regalloc(&r1, con.Type, t)
- gins(mips.AMOVV, &con, &r1)
- gmove(&r1, t)
- gc.Regfree(&r1)
- return
- }
-
- f = &con
- ft = tt // so big switch will choose a simple mov
-
- // constants can't move directly to memory.
- if gc.Ismem(t) {
- goto hard
- }
- }
-
- // value -> value copy, first operand in memory.
- // any floating point operand requires register
- // src, so goto hard to copy to register first.
- if gc.Ismem(f) && ft != tt && (gc.Isfloat[ft] || gc.Isfloat[tt]) {
- cvt = gc.Types[ft]
- goto hard
- }
-
- // value -> value copy, only one memory operand.
- // figure out the instruction to use.
- // break out of switch for one-instruction gins.
- // goto rdst for "destination must be register".
- // goto hard for "convert to cvt type first".
- // otherwise handle and return.
-
- switch uint32(ft)<<16 | uint32(tt) {
- default:
- gc.Fatalf("gmove %v -> %v", gc.Tconv(f.Type, gc.FmtLong), gc.Tconv(t.Type, gc.FmtLong))
-
- /*
- * integer copy and truncate
- */
- case gc.TINT8<<16 | gc.TINT8, // same size
- gc.TUINT8<<16 | gc.TINT8,
- gc.TINT16<<16 | gc.TINT8, // truncate
- gc.TUINT16<<16 | gc.TINT8,
- gc.TINT32<<16 | gc.TINT8,
- gc.TUINT32<<16 | gc.TINT8,
- gc.TINT64<<16 | gc.TINT8,
- gc.TUINT64<<16 | gc.TINT8:
- a = mips.AMOVB
-
- case gc.TINT8<<16 | gc.TUINT8, // same size
- gc.TUINT8<<16 | gc.TUINT8,
- gc.TINT16<<16 | gc.TUINT8, // truncate
- gc.TUINT16<<16 | gc.TUINT8,
- gc.TINT32<<16 | gc.TUINT8,
- gc.TUINT32<<16 | gc.TUINT8,
- gc.TINT64<<16 | gc.TUINT8,
- gc.TUINT64<<16 | gc.TUINT8:
- a = mips.AMOVBU
-
- case gc.TINT16<<16 | gc.TINT16, // same size
- gc.TUINT16<<16 | gc.TINT16,
- gc.TINT32<<16 | gc.TINT16, // truncate
- gc.TUINT32<<16 | gc.TINT16,
- gc.TINT64<<16 | gc.TINT16,
- gc.TUINT64<<16 | gc.TINT16:
- a = mips.AMOVH
-
- case gc.TINT16<<16 | gc.TUINT16, // same size
- gc.TUINT16<<16 | gc.TUINT16,
- gc.TINT32<<16 | gc.TUINT16, // truncate
- gc.TUINT32<<16 | gc.TUINT16,
- gc.TINT64<<16 | gc.TUINT16,
- gc.TUINT64<<16 | gc.TUINT16:
- a = mips.AMOVHU
-
- case gc.TINT32<<16 | gc.TINT32, // same size
- gc.TUINT32<<16 | gc.TINT32,
- gc.TINT64<<16 | gc.TINT32, // truncate
- gc.TUINT64<<16 | gc.TINT32:
- a = mips.AMOVW
-
- case gc.TINT32<<16 | gc.TUINT32, // same size
- gc.TUINT32<<16 | gc.TUINT32,
- gc.TINT64<<16 | gc.TUINT32, // truncate
- gc.TUINT64<<16 | gc.TUINT32:
- a = mips.AMOVWU
-
- case gc.TINT64<<16 | gc.TINT64, // same size
- gc.TINT64<<16 | gc.TUINT64,
- gc.TUINT64<<16 | gc.TINT64,
- gc.TUINT64<<16 | gc.TUINT64:
- a = mips.AMOVV
-
- /*
- * integer up-conversions
- */
- case gc.TINT8<<16 | gc.TINT16, // sign extend int8
- gc.TINT8<<16 | gc.TUINT16,
- gc.TINT8<<16 | gc.TINT32,
- gc.TINT8<<16 | gc.TUINT32,
- gc.TINT8<<16 | gc.TINT64,
- gc.TINT8<<16 | gc.TUINT64:
- a = mips.AMOVB
-
- goto rdst
-
- case gc.TUINT8<<16 | gc.TINT16, // zero extend uint8
- gc.TUINT8<<16 | gc.TUINT16,
- gc.TUINT8<<16 | gc.TINT32,
- gc.TUINT8<<16 | gc.TUINT32,
- gc.TUINT8<<16 | gc.TINT64,
- gc.TUINT8<<16 | gc.TUINT64:
- a = mips.AMOVBU
-
- goto rdst
-
- case gc.TINT16<<16 | gc.TINT32, // sign extend int16
- gc.TINT16<<16 | gc.TUINT32,
- gc.TINT16<<16 | gc.TINT64,
- gc.TINT16<<16 | gc.TUINT64:
- a = mips.AMOVH
-
- goto rdst
-
- case gc.TUINT16<<16 | gc.TINT32, // zero extend uint16
- gc.TUINT16<<16 | gc.TUINT32,
- gc.TUINT16<<16 | gc.TINT64,
- gc.TUINT16<<16 | gc.TUINT64:
- a = mips.AMOVHU
-
- goto rdst
-
- case gc.TINT32<<16 | gc.TINT64, // sign extend int32
- gc.TINT32<<16 | gc.TUINT64:
- a = mips.AMOVW
-
- goto rdst
-
- case gc.TUINT32<<16 | gc.TINT64, // zero extend uint32
- gc.TUINT32<<16 | gc.TUINT64:
- a = mips.AMOVWU
-
- goto rdst
-
- //warn("gmove: convert float to int not implemented: %N -> %N\n", f, t);
- //return;
- // algorithm is:
- // if small enough, use native float64 -> int64 conversion.
- // otherwise, subtract 2^63, convert, and add it back.
- /*
- * float to integer
- */
- case gc.TFLOAT32<<16 | gc.TINT32,
- gc.TFLOAT64<<16 | gc.TINT32,
- gc.TFLOAT32<<16 | gc.TINT64,
- gc.TFLOAT64<<16 | gc.TINT64,
- gc.TFLOAT32<<16 | gc.TINT16,
- gc.TFLOAT32<<16 | gc.TINT8,
- gc.TFLOAT32<<16 | gc.TUINT16,
- gc.TFLOAT32<<16 | gc.TUINT8,
- gc.TFLOAT64<<16 | gc.TINT16,
- gc.TFLOAT64<<16 | gc.TINT8,
- gc.TFLOAT64<<16 | gc.TUINT16,
- gc.TFLOAT64<<16 | gc.TUINT8,
- gc.TFLOAT32<<16 | gc.TUINT32,
- gc.TFLOAT64<<16 | gc.TUINT32,
- gc.TFLOAT32<<16 | gc.TUINT64,
- gc.TFLOAT64<<16 | gc.TUINT64:
- bignodes()
-
- gc.Regalloc(&r1, gc.Types[gc.TFLOAT64], nil)
- gmove(f, &r1)
- if tt == gc.TUINT64 {
- gc.Regalloc(&r2, gc.Types[gc.TFLOAT64], nil)
- gmove(&bigf, &r2)
- gins3(mips.ACMPGED, &r1, &r2, nil)
- p1 := gc.Gbranch(mips.ABFPF, nil, 0)
- gins(mips.ASUBD, &r2, &r1)
- gc.Patch(p1, gc.Pc)
- gc.Regfree(&r2)
- }
-
- gc.Regalloc(&r2, gc.Types[gc.TINT64], t)
- gins(mips.ATRUNCDV, &r1, &r1)
- gins(mips.AMOVV, &r1, &r2)
- gc.Regfree(&r1)
-
- if tt == gc.TUINT64 {
- p1 := gc.Gbranch(mips.ABFPF, nil, 0) // use FCR0 here again
- gc.Nodreg(&r1, gc.Types[gc.TINT64], mips.REGTMP)
- gmove(&bigi, &r1)
- gins(mips.AADDVU, &r1, &r2)
- gc.Patch(p1, gc.Pc)
- }
-
- gmove(&r2, t)
- gc.Regfree(&r2)
- return
-
- //warn("gmove: convert int to float not implemented: %N -> %N\n", f, t);
- //return;
- // algorithm is:
- // if small enough, use native int64 -> float64 conversion.
- // otherwise, halve (x -> (x>>1)|(x&1)), convert, and double.
- /*
- * integer to float
- */
- case gc.TINT32<<16 | gc.TFLOAT32,
- gc.TINT32<<16 | gc.TFLOAT64,
- gc.TINT64<<16 | gc.TFLOAT32,
- gc.TINT64<<16 | gc.TFLOAT64,
- gc.TINT16<<16 | gc.TFLOAT32,
- gc.TINT16<<16 | gc.TFLOAT64,
- gc.TINT8<<16 | gc.TFLOAT32,
- gc.TINT8<<16 | gc.TFLOAT64,
- gc.TUINT16<<16 | gc.TFLOAT32,
- gc.TUINT16<<16 | gc.TFLOAT64,
- gc.TUINT8<<16 | gc.TFLOAT32,
- gc.TUINT8<<16 | gc.TFLOAT64,
- gc.TUINT32<<16 | gc.TFLOAT32,
- gc.TUINT32<<16 | gc.TFLOAT64,
- gc.TUINT64<<16 | gc.TFLOAT32,
- gc.TUINT64<<16 | gc.TFLOAT64:
- bignodes()
-
- var rtmp gc.Node
- gc.Regalloc(&r1, gc.Types[gc.TINT64], nil)
- gmove(f, &r1)
- if ft == gc.TUINT64 {
- gc.Nodreg(&rtmp, gc.Types[gc.TUINT64], mips.REGTMP)
- gmove(&bigi, &rtmp)
- gins(mips.AAND, &r1, &rtmp)
- p1 := ginsbranch(mips.ABEQ, nil, &rtmp, nil, 0)
- var r3 gc.Node
- gc.Regalloc(&r3, gc.Types[gc.TUINT64], nil)
- p2 := gins3(mips.AAND, nil, &r1, &r3)
- p2.From.Type = obj.TYPE_CONST
- p2.From.Offset = 1
- p3 := gins(mips.ASRLV, nil, &r1)
- p3.From.Type = obj.TYPE_CONST
- p3.From.Offset = 1
- gins(mips.AOR, &r3, &r1)
- gc.Regfree(&r3)
- gc.Patch(p1, gc.Pc)
- }
-
- gc.Regalloc(&r2, gc.Types[gc.TFLOAT64], t)
- gins(mips.AMOVV, &r1, &r2)
- gins(mips.AMOVVD, &r2, &r2)
- gc.Regfree(&r1)
-
- if ft == gc.TUINT64 {
- p1 := ginsbranch(mips.ABEQ, nil, &rtmp, nil, 0)
- gc.Nodreg(&r1, gc.Types[gc.TFLOAT64], mips.FREGTWO)
- gins(mips.AMULD, &r1, &r2)
- gc.Patch(p1, gc.Pc)
- }
-
- gmove(&r2, t)
- gc.Regfree(&r2)
- return
-
- /*
- * float to float
- */
- case gc.TFLOAT32<<16 | gc.TFLOAT32:
- a = mips.AMOVF
-
- case gc.TFLOAT64<<16 | gc.TFLOAT64:
- a = mips.AMOVD
-
- case gc.TFLOAT32<<16 | gc.TFLOAT64:
- a = mips.AMOVFD
- goto rdst
-
- case gc.TFLOAT64<<16 | gc.TFLOAT32:
- a = mips.AMOVDF
- goto rdst
- }
-
- gins(a, f, t)
- return
-
- // requires register destination
-rdst:
- {
- gc.Regalloc(&r1, t.Type, t)
-
- gins(a, f, &r1)
- gmove(&r1, t)
- gc.Regfree(&r1)
- return
- }
-
- // requires register intermediate
-hard:
- gc.Regalloc(&r1, cvt, t)
-
- gmove(f, &r1)
- gmove(&r1, t)
- gc.Regfree(&r1)
- return
-}
-
-// gins is called by the front end.
-// It synthesizes some multiple-instruction sequences
-// so the front end can stay simpler.
-func gins(as obj.As, f, t *gc.Node) *obj.Prog {
- if as >= obj.A_ARCHSPECIFIC {
- if x, ok := f.IntLiteral(); ok {
- ginscon(as, x, t)
- return nil // caller must not use
- }
- }
- return rawgins(as, f, t)
-}
-
-/*
- * generate one instruction:
- * as f, r, t
- * r must be register, if not nil
- */
-func gins3(as obj.As, f, r, t *gc.Node) *obj.Prog {
- p := rawgins(as, f, t)
- if r != nil {
- p.Reg = r.Reg
- }
- return p
-}
-
-/*
- * generate one instruction:
- * as f, t
- */
-func rawgins(as obj.As, f *gc.Node, t *gc.Node) *obj.Prog {
- // TODO(austin): Add self-move test like in 6g (but be careful
- // of truncation moves)
-
- p := gc.Prog(as)
- gc.Naddr(&p.From, f)
- gc.Naddr(&p.To, t)
-
- switch as {
- case obj.ACALL:
- if p.To.Type == obj.TYPE_REG {
- // Allow front end to emit CALL REG, and rewrite into CALL (REG).
- p.From = obj.Addr{}
- p.To.Type = obj.TYPE_MEM
- p.To.Offset = 0
-
- if gc.Debug['g'] != 0 {
- fmt.Printf("%v\n", p)
- }
-
- return p
- }
-
- // Bad things the front end has done to us. Crash to find call stack.
- case mips.AAND:
- if p.From.Type == obj.TYPE_CONST {
- gc.Debug['h'] = 1
- gc.Fatalf("bad inst: %v", p)
- }
- case mips.ASGT, mips.ASGTU:
- if p.From.Type == obj.TYPE_MEM || p.To.Type == obj.TYPE_MEM {
- gc.Debug['h'] = 1
- gc.Fatalf("bad inst: %v", p)
- }
-
- // Special cases
- case mips.AMUL, mips.AMULU, mips.AMULV, mips.AMULVU:
- if p.From.Type == obj.TYPE_CONST {
- gc.Debug['h'] = 1
- gc.Fatalf("bad inst: %v", p)
- }
-
- pp := gc.Prog(mips.AMOVV)
- pp.From.Type = obj.TYPE_REG
- pp.From.Reg = mips.REG_LO
- pp.To = p.To
-
- p.Reg = p.To.Reg
- p.To = obj.Addr{}
-
- case mips.ASUBVU:
- // unary
- if f == nil {
- p.From = p.To
- p.Reg = mips.REGZERO
- }
- }
-
- if gc.Debug['g'] != 0 {
- fmt.Printf("%v\n", p)
- }
-
- w := int32(0)
- switch as {
- case mips.AMOVB,
- mips.AMOVBU:
- w = 1
-
- case mips.AMOVH,
- mips.AMOVHU:
- w = 2
-
- case mips.AMOVW,
- mips.AMOVWU:
- w = 4
-
- case mips.AMOVV:
- if p.From.Type == obj.TYPE_CONST || p.From.Type == obj.TYPE_ADDR {
- break
- }
- w = 8
- }
-
- if w != 0 && ((f != nil && p.From.Width < int64(w)) || (t != nil && p.To.Type != obj.TYPE_REG && p.To.Width > int64(w))) {
- gc.Dump("f", f)
- gc.Dump("t", t)
- gc.Fatalf("bad width: %v (%d, %d)\n", p, p.From.Width, p.To.Width)
- }
-
- return p
-}
-
-/*
- * return Axxx for Oxxx on type t.
- */
-func optoas(op gc.Op, t *gc.Type) obj.As {
- if t == nil {
- gc.Fatalf("optoas: t is nil")
- }
-
- // avoid constant conversions in switches below
- const (
- OMINUS_ = uint32(gc.OMINUS) << 16
- OLSH_ = uint32(gc.OLSH) << 16
- ORSH_ = uint32(gc.ORSH) << 16
- OADD_ = uint32(gc.OADD) << 16
- OSUB_ = uint32(gc.OSUB) << 16
- OMUL_ = uint32(gc.OMUL) << 16
- ODIV_ = uint32(gc.ODIV) << 16
- OOR_ = uint32(gc.OOR) << 16
- OAND_ = uint32(gc.OAND) << 16
- OXOR_ = uint32(gc.OXOR) << 16
- OEQ_ = uint32(gc.OEQ) << 16
- ONE_ = uint32(gc.ONE) << 16
- OLT_ = uint32(gc.OLT) << 16
- OLE_ = uint32(gc.OLE) << 16
- OGE_ = uint32(gc.OGE) << 16
- OGT_ = uint32(gc.OGT) << 16
- OCMP_ = uint32(gc.OCMP) << 16
- OAS_ = uint32(gc.OAS) << 16
- OHMUL_ = uint32(gc.OHMUL) << 16
- )
-
- a := obj.AXXX
- switch uint32(op)<<16 | uint32(gc.Simtype[t.Etype]) {
- default:
- gc.Fatalf("optoas: no entry for op=%s type=%v", op, t)
-
- case OEQ_ | gc.TBOOL,
- OEQ_ | gc.TINT8,
- OEQ_ | gc.TUINT8,
- OEQ_ | gc.TINT16,
- OEQ_ | gc.TUINT16,
- OEQ_ | gc.TINT32,
- OEQ_ | gc.TUINT32,
- OEQ_ | gc.TINT64,
- OEQ_ | gc.TUINT64,
- OEQ_ | gc.TPTR32,
- OEQ_ | gc.TPTR64:
- a = mips.ABEQ
-
- case OEQ_ | gc.TFLOAT32, // ACMPEQF
- OEQ_ | gc.TFLOAT64: // ACMPEQD
- a = mips.ABFPT
-
- case ONE_ | gc.TBOOL,
- ONE_ | gc.TINT8,
- ONE_ | gc.TUINT8,
- ONE_ | gc.TINT16,
- ONE_ | gc.TUINT16,
- ONE_ | gc.TINT32,
- ONE_ | gc.TUINT32,
- ONE_ | gc.TINT64,
- ONE_ | gc.TUINT64,
- ONE_ | gc.TPTR32,
- ONE_ | gc.TPTR64:
- a = mips.ABNE
-
- case ONE_ | gc.TFLOAT32, // ACMPEQF
- ONE_ | gc.TFLOAT64: // ACMPEQD
- a = mips.ABFPF
-
- case OLT_ | gc.TINT8, // ASGT
- OLT_ | gc.TINT16,
- OLT_ | gc.TINT32,
- OLT_ | gc.TINT64,
- OLT_ | gc.TUINT8, // ASGTU
- OLT_ | gc.TUINT16,
- OLT_ | gc.TUINT32,
- OLT_ | gc.TUINT64:
- a = mips.ABNE
-
- case OLT_ | gc.TFLOAT32, // ACMPGEF
- OLT_ | gc.TFLOAT64: // ACMPGED
- a = mips.ABFPT
-
- case OLE_ | gc.TINT8, // ASGT
- OLE_ | gc.TINT16,
- OLE_ | gc.TINT32,
- OLE_ | gc.TINT64,
- OLE_ | gc.TUINT8, // ASGTU
- OLE_ | gc.TUINT16,
- OLE_ | gc.TUINT32,
- OLE_ | gc.TUINT64:
- a = mips.ABEQ
-
- case OLE_ | gc.TFLOAT32, // ACMPGTF
- OLE_ | gc.TFLOAT64: // ACMPGTD
- a = mips.ABFPT
-
- case OGT_ | gc.TINT8, // ASGT
- OGT_ | gc.TINT16,
- OGT_ | gc.TINT32,
- OGT_ | gc.TINT64,
- OGT_ | gc.TUINT8, // ASGTU
- OGT_ | gc.TUINT16,
- OGT_ | gc.TUINT32,
- OGT_ | gc.TUINT64:
- a = mips.ABNE
-
- case OGT_ | gc.TFLOAT32, // ACMPGTF
- OGT_ | gc.TFLOAT64: // ACMPGTD
- a = mips.ABFPT
-
- case OGE_ | gc.TINT8, // ASGT
- OGE_ | gc.TINT16,
- OGE_ | gc.TINT32,
- OGE_ | gc.TINT64,
- OGE_ | gc.TUINT8, // ASGTU
- OGE_ | gc.TUINT16,
- OGE_ | gc.TUINT32,
- OGE_ | gc.TUINT64:
- a = mips.ABEQ
-
- case OGE_ | gc.TFLOAT32, // ACMPGEF
- OGE_ | gc.TFLOAT64: // ACMPGED
- a = mips.ABFPT
-
- case OAS_ | gc.TBOOL,
- OAS_ | gc.TINT8:
- a = mips.AMOVB
-
- case OAS_ | gc.TUINT8:
- a = mips.AMOVBU
-
- case OAS_ | gc.TINT16:
- a = mips.AMOVH
-
- case OAS_ | gc.TUINT16:
- a = mips.AMOVHU
-
- case OAS_ | gc.TINT32:
- a = mips.AMOVW
-
- case OAS_ | gc.TUINT32,
- OAS_ | gc.TPTR32:
- a = mips.AMOVWU
-
- case OAS_ | gc.TINT64,
- OAS_ | gc.TUINT64,
- OAS_ | gc.TPTR64:
- a = mips.AMOVV
-
- case OAS_ | gc.TFLOAT32:
- a = mips.AMOVF
-
- case OAS_ | gc.TFLOAT64:
- a = mips.AMOVD
-
- case OADD_ | gc.TINT8,
- OADD_ | gc.TUINT8,
- OADD_ | gc.TINT16,
- OADD_ | gc.TUINT16,
- OADD_ | gc.TINT32,
- OADD_ | gc.TUINT32,
- OADD_ | gc.TPTR32:
- a = mips.AADDU
-
- case OADD_ | gc.TINT64,
- OADD_ | gc.TUINT64,
- OADD_ | gc.TPTR64:
- a = mips.AADDVU
-
- case OADD_ | gc.TFLOAT32:
- a = mips.AADDF
-
- case OADD_ | gc.TFLOAT64:
- a = mips.AADDD
-
- case OSUB_ | gc.TINT8,
- OSUB_ | gc.TUINT8,
- OSUB_ | gc.TINT16,
- OSUB_ | gc.TUINT16,
- OSUB_ | gc.TINT32,
- OSUB_ | gc.TUINT32,
- OSUB_ | gc.TPTR32:
- a = mips.ASUBU
-
- case OSUB_ | gc.TINT64,
- OSUB_ | gc.TUINT64,
- OSUB_ | gc.TPTR64:
- a = mips.ASUBVU
-
- case OSUB_ | gc.TFLOAT32:
- a = mips.ASUBF
-
- case OSUB_ | gc.TFLOAT64:
- a = mips.ASUBD
-
- case OMINUS_ | gc.TINT8,
- OMINUS_ | gc.TUINT8,
- OMINUS_ | gc.TINT16,
- OMINUS_ | gc.TUINT16,
- OMINUS_ | gc.TINT32,
- OMINUS_ | gc.TUINT32,
- OMINUS_ | gc.TPTR32,
- OMINUS_ | gc.TINT64,
- OMINUS_ | gc.TUINT64,
- OMINUS_ | gc.TPTR64:
- a = mips.ASUBVU
-
- case OAND_ | gc.TINT8,
- OAND_ | gc.TUINT8,
- OAND_ | gc.TINT16,
- OAND_ | gc.TUINT16,
- OAND_ | gc.TINT32,
- OAND_ | gc.TUINT32,
- OAND_ | gc.TPTR32,
- OAND_ | gc.TINT64,
- OAND_ | gc.TUINT64,
- OAND_ | gc.TPTR64:
- a = mips.AAND
-
- case OOR_ | gc.TINT8,
- OOR_ | gc.TUINT8,
- OOR_ | gc.TINT16,
- OOR_ | gc.TUINT16,
- OOR_ | gc.TINT32,
- OOR_ | gc.TUINT32,
- OOR_ | gc.TPTR32,
- OOR_ | gc.TINT64,
- OOR_ | gc.TUINT64,
- OOR_ | gc.TPTR64:
- a = mips.AOR
-
- case OXOR_ | gc.TINT8,
- OXOR_ | gc.TUINT8,
- OXOR_ | gc.TINT16,
- OXOR_ | gc.TUINT16,
- OXOR_ | gc.TINT32,
- OXOR_ | gc.TUINT32,
- OXOR_ | gc.TPTR32,
- OXOR_ | gc.TINT64,
- OXOR_ | gc.TUINT64,
- OXOR_ | gc.TPTR64:
- a = mips.AXOR
-
- // TODO(minux): handle rotates
- //case CASE(OLROT, TINT8):
- //case CASE(OLROT, TUINT8):
- //case CASE(OLROT, TINT16):
- //case CASE(OLROT, TUINT16):
- //case CASE(OLROT, TINT32):
- //case CASE(OLROT, TUINT32):
- //case CASE(OLROT, TPTR32):
- //case CASE(OLROT, TINT64):
- //case CASE(OLROT, TUINT64):
- //case CASE(OLROT, TPTR64):
- // a = 0//???; RLDC?
- // break;
-
- case OLSH_ | gc.TINT8,
- OLSH_ | gc.TUINT8,
- OLSH_ | gc.TINT16,
- OLSH_ | gc.TUINT16,
- OLSH_ | gc.TINT32,
- OLSH_ | gc.TUINT32,
- OLSH_ | gc.TPTR32,
- OLSH_ | gc.TINT64,
- OLSH_ | gc.TUINT64,
- OLSH_ | gc.TPTR64:
- a = mips.ASLLV
-
- case ORSH_ | gc.TUINT8,
- ORSH_ | gc.TUINT16,
- ORSH_ | gc.TUINT32,
- ORSH_ | gc.TPTR32,
- ORSH_ | gc.TUINT64,
- ORSH_ | gc.TPTR64:
- a = mips.ASRLV
-
- case ORSH_ | gc.TINT8,
- ORSH_ | gc.TINT16,
- ORSH_ | gc.TINT32,
- ORSH_ | gc.TINT64:
- a = mips.ASRAV
-
- // TODO(minux): handle rotates
- //case CASE(ORROTC, TINT8):
- //case CASE(ORROTC, TUINT8):
- //case CASE(ORROTC, TINT16):
- //case CASE(ORROTC, TUINT16):
- //case CASE(ORROTC, TINT32):
- //case CASE(ORROTC, TUINT32):
- //case CASE(ORROTC, TINT64):
- //case CASE(ORROTC, TUINT64):
- // a = 0//??? RLDC??
- // break;
-
- case OHMUL_ | gc.TINT64:
- a = mips.AMULV
-
- case OHMUL_ | gc.TUINT64,
- OHMUL_ | gc.TPTR64:
- a = mips.AMULVU
-
- case OMUL_ | gc.TINT8,
- OMUL_ | gc.TINT16,
- OMUL_ | gc.TINT32,
- OMUL_ | gc.TINT64:
- a = mips.AMULV
-
- case OMUL_ | gc.TUINT8,
- OMUL_ | gc.TUINT16,
- OMUL_ | gc.TUINT32,
- OMUL_ | gc.TPTR32,
- OMUL_ | gc.TUINT64,
- OMUL_ | gc.TPTR64:
- a = mips.AMULVU
-
- case OMUL_ | gc.TFLOAT32:
- a = mips.AMULF
-
- case OMUL_ | gc.TFLOAT64:
- a = mips.AMULD
-
- case ODIV_ | gc.TINT8,
- ODIV_ | gc.TINT16,
- ODIV_ | gc.TINT32,
- ODIV_ | gc.TINT64:
- a = mips.ADIVV
-
- case ODIV_ | gc.TUINT8,
- ODIV_ | gc.TUINT16,
- ODIV_ | gc.TUINT32,
- ODIV_ | gc.TPTR32,
- ODIV_ | gc.TUINT64,
- ODIV_ | gc.TPTR64:
- a = mips.ADIVVU
-
- case ODIV_ | gc.TFLOAT32:
- a = mips.ADIVF
-
- case ODIV_ | gc.TFLOAT64:
- a = mips.ADIVD
- }
-
- return a
-}
-
-const (
- ODynam = 1 << 0
- OAddable = 1 << 1
-)
-
-func xgen(n *gc.Node, a *gc.Node, o int) bool {
- // TODO(minux)
-
- return -1 != 0 /*TypeKind(100016)*/
-}
-
-func sudoclean() {
- return
-}
-
-/*
- * generate code to compute address of n,
- * a reference to a (perhaps nested) field inside
- * an array or struct.
- * return 0 on failure, 1 on success.
- * on success, leaves usable address in a.
- *
- * caller is responsible for calling sudoclean
- * after successful sudoaddable,
- * to release the register used for a.
- */
-func sudoaddable(as obj.As, n *gc.Node, a *obj.Addr) bool {
- // TODO(minux)
-
- *a = obj.Addr{}
- return false
-}
diff --git a/src/cmd/compile/internal/mips64/peep.go b/src/cmd/compile/internal/mips64/peep.go
deleted file mode 100644
index 6bb5158..0000000
--- a/src/cmd/compile/internal/mips64/peep.go
+++ /dev/null
@@ -1,772 +0,0 @@
-// Derived from Inferno utils/6c/peep.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6c/peep.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth at terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth at terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// Portions Copyright © 2009 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-package mips64
-
-import (
- "cmd/compile/internal/gc"
- "cmd/internal/obj"
- "cmd/internal/obj/mips"
- "fmt"
-)
-
-var gactive uint32
-
-func peep(firstp *obj.Prog) {
- g := gc.Flowstart(firstp, nil)
- if g == nil {
- return
- }
- gactive = 0
-
- var p *obj.Prog
- var r *gc.Flow
- var t int
-loop1:
- if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
- gc.Dumpit("loop1", g.Start, 0)
- }
-
- t = 0
- for r = g.Start; r != nil; r = r.Link {
- p = r.Prog
-
- // TODO(austin) Handle smaller moves. arm and amd64
- // distinguish between moves that moves that *must*
- // sign/zero extend and moves that don't care so they
- // can eliminate moves that don't care without
- // breaking moves that do care. This might let us
- // simplify or remove the next peep loop, too.
- if p.As == mips.AMOVV || p.As == mips.AMOVF || p.As == mips.AMOVD {
- if regtyp(&p.To) {
- // Try to eliminate reg->reg moves
- if regtyp(&p.From) {
- if isfreg(&p.From) == isfreg(&p.To) {
- if copyprop(r) {
- excise(r)
- t++
- } else if subprop(r) && copyprop(r) {
- excise(r)
- t++
- }
- }
- }
-
- // Convert uses to $0 to uses of R0 and
- // propagate R0
- if regzer(&p.From) {
- if p.To.Type == obj.TYPE_REG && !isfreg(&p.To) {
- p.From.Type = obj.TYPE_REG
- p.From.Reg = mips.REGZERO
- if copyprop(r) {
- excise(r)
- t++
- } else if subprop(r) && copyprop(r) {
- excise(r)
- t++
- }
- }
- }
- }
- }
- }
-
- if t != 0 {
- goto loop1
- }
-
- /*
- * look for MOVB x,R; MOVB R,R (for small MOVs not handled above)
- */
- var p1 *obj.Prog
- var r1 *gc.Flow
- for r := g.Start; r != nil; r = r.Link {
- p = r.Prog
- switch p.As {
- default:
- continue
-
- case mips.AMOVH,
- mips.AMOVHU,
- mips.AMOVB,
- mips.AMOVBU,
- mips.AMOVW,
- mips.AMOVWU:
- if p.To.Type != obj.TYPE_REG {
- continue
- }
- }
-
- r1 = r.Link
- if r1 == nil {
- continue
- }
- p1 = r1.Prog
- if p1.As != p.As {
- continue
- }
- if p1.From.Type != obj.TYPE_REG || p1.From.Reg != p.To.Reg {
- continue
- }
- if p1.To.Type != obj.TYPE_REG || p1.To.Reg != p.To.Reg {
- continue
- }
- excise(r1)
- }
-
- gc.Flowend(g)
-}
-
-func excise(r *gc.Flow) {
- p := r.Prog
- if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
- fmt.Printf("%v ===delete===\n", p)
- }
- obj.Nopout(p)
- gc.Ostats.Ndelmov++
-}
-
-// regzer returns true if a's value is 0 (a is R0 or $0)
-func regzer(a *obj.Addr) bool {
- if a.Type == obj.TYPE_CONST || a.Type == obj.TYPE_ADDR {
- if a.Sym == nil && a.Reg == 0 {
- if a.Offset == 0 {
- return true
- }
- }
- }
- return a.Type == obj.TYPE_REG && a.Reg == mips.REGZERO
-}
-
-func regtyp(a *obj.Addr) bool {
- // TODO(rsc): Floating point register exclusions?
- return a.Type == obj.TYPE_REG && mips.REG_R0 <= a.Reg && a.Reg <= mips.REG_F31 && a.Reg != mips.REGZERO
-}
-
-func isfreg(a *obj.Addr) bool {
- return mips.REG_F0 <= a.Reg && a.Reg <= mips.REG_F31
-}
-
-/*
- * the idea is to substitute
- * one register for another
- * from one MOV to another
- * MOV a, R1
- * ADD b, R1 / no use of R2
- * MOV R1, R2
- * would be converted to
- * MOV a, R2
- * ADD b, R2
- * MOV R2, R1
- * hopefully, then the former or latter MOV
- * will be eliminated by copy propagation.
- *
- * r0 (the argument, not the register) is the MOV at the end of the
- * above sequences. This returns 1 if it modified any instructions.
- */
-func subprop(r0 *gc.Flow) bool {
- p := r0.Prog
- v1 := &p.From
- if !regtyp(v1) {
- return false
- }
- v2 := &p.To
- if !regtyp(v2) {
- return false
- }
- for r := gc.Uniqp(r0); r != nil; r = gc.Uniqp(r) {
- if gc.Uniqs(r) == nil {
- break
- }
- p = r.Prog
- if p.As == obj.AVARDEF || p.As == obj.AVARKILL {
- continue
- }
- if p.Info.Flags&gc.Call != 0 {
- return false
- }
-
- if p.Info.Flags&(gc.RightRead|gc.RightWrite) == gc.RightWrite {
- if p.To.Type == v1.Type {
- if p.To.Reg == v1.Reg {
- copysub(&p.To, v1, v2, true)
- if gc.Debug['P'] != 0 {
- fmt.Printf("gotit: %v->%v\n%v", gc.Ctxt.Dconv(v1), gc.Ctxt.Dconv(v2), r.Prog)
- if p.From.Type == v2.Type {
- fmt.Printf(" excise")
- }
- fmt.Printf("\n")
- }
-
- for r = gc.Uniqs(r); r != r0; r = gc.Uniqs(r) {
- p = r.Prog
- copysub(&p.From, v1, v2, true)
- copysub1(p, v1, v2, true)
- copysub(&p.To, v1, v2, true)
- if gc.Debug['P'] != 0 {
- fmt.Printf("%v\n", r.Prog)
- }
- }
-
- v1.Reg, v2.Reg = v2.Reg, v1.Reg
- if gc.Debug['P'] != 0 {
- fmt.Printf("%v last\n", r.Prog)
- }
- return true
- }
- }
- }
-
- if copyau(&p.From, v2) || copyau1(p, v2) || copyau(&p.To, v2) {
- break
- }
- if copysub(&p.From, v1, v2, false) || copysub1(p, v1, v2, false) || copysub(&p.To, v1, v2, false) {
- break
- }
- }
-
- return false
-}
-
-/*
- * The idea is to remove redundant copies.
- * v1->v2 F=0
- * (use v2 s/v2/v1/)*
- * set v1 F=1
- * use v2 return fail (v1->v2 move must remain)
- * -----------------
- * v1->v2 F=0
- * (use v2 s/v2/v1/)*
- * set v1 F=1
- * set v2 return success (caller can remove v1->v2 move)
- */
-func copyprop(r0 *gc.Flow) bool {
- p := r0.Prog
- v1 := &p.From
- v2 := &p.To
- if copyas(v1, v2) {
- if gc.Debug['P'] != 0 {
- fmt.Printf("eliminating self-move: %v\n", r0.Prog)
- }
- return true
- }
-
- gactive++
- if gc.Debug['P'] != 0 {
- fmt.Printf("trying to eliminate %v->%v move from:\n%v\n", gc.Ctxt.Dconv(v1), gc.Ctxt.Dconv(v2), r0.Prog)
- }
- return copy1(v1, v2, r0.S1, false)
-}
-
-// copy1 replaces uses of v2 with v1 starting at r and returns true if
-// all uses were rewritten.
-func copy1(v1 *obj.Addr, v2 *obj.Addr, r *gc.Flow, f bool) bool {
- if uint32(r.Active) == gactive {
- if gc.Debug['P'] != 0 {
- fmt.Printf("act set; return 1\n")
- }
- return true
- }
-
- r.Active = int32(gactive)
- if gc.Debug['P'] != 0 {
- fmt.Printf("copy1 replace %v with %v f=%v\n", gc.Ctxt.Dconv(v2), gc.Ctxt.Dconv(v1), f)
- }
- for ; r != nil; r = r.S1 {
- p := r.Prog
- if gc.Debug['P'] != 0 {
- fmt.Printf("%v", p)
- }
- if !f && gc.Uniqp(r) == nil {
- // Multiple predecessors; conservatively
- // assume v1 was set on other path
- f = true
-
- if gc.Debug['P'] != 0 {
- fmt.Printf("; merge; f=%v", f)
- }
- }
-
- switch t := copyu(p, v2, nil); t {
- case 2: /* rar, can't split */
- if gc.Debug['P'] != 0 {
- fmt.Printf("; %v rar; return 0\n", gc.Ctxt.Dconv(v2))
- }
- return false
-
- case 3: /* set */
- if gc.Debug['P'] != 0 {
- fmt.Printf("; %v set; return 1\n", gc.Ctxt.Dconv(v2))
- }
- return true
-
- case 1, /* used, substitute */
- 4: /* use and set */
- if f {
- if gc.Debug['P'] == 0 {
- return false
- }
- if t == 4 {
- fmt.Printf("; %v used+set and f=%v; return 0\n", gc.Ctxt.Dconv(v2), f)
- } else {
- fmt.Printf("; %v used and f=%v; return 0\n", gc.Ctxt.Dconv(v2), f)
- }
- return false
- }
-
- if copyu(p, v2, v1) != 0 {
- if gc.Debug['P'] != 0 {
- fmt.Printf("; sub fail; return 0\n")
- }
- return false
- }
-
- if gc.Debug['P'] != 0 {
- fmt.Printf("; sub %v->%v\n => %v", gc.Ctxt.Dconv(v2), gc.Ctxt.Dconv(v1), p)
- }
- if t == 4 {
- if gc.Debug['P'] != 0 {
- fmt.Printf("; %v used+set; return 1\n", gc.Ctxt.Dconv(v2))
- }
- return true
- }
- }
-
- if !f {
- t := copyu(p, v1, nil)
- if t == 2 || t == 3 || t == 4 {
- f = true
- if gc.Debug['P'] != 0 {
- fmt.Printf("; %v set and !f; f=%v", gc.Ctxt.Dconv(v1), f)
- }
- }
- }
-
- if gc.Debug['P'] != 0 {
- fmt.Printf("\n")
- }
- if r.S2 != nil {
- if !copy1(v1, v2, r.S2, f) {
- return false
- }
- }
- }
-
- return true
-}
-
-// If s==nil, copyu returns the set/use of v in p; otherwise, it
-// modifies p to replace reads of v with reads of s and returns 0 for
-// success or non-zero for failure.
-//
-// If s==nil, copy returns one of the following values:
-// 1 if v only used
-// 2 if v is set and used in one address (read-alter-rewrite;
-// can't substitute)
-// 3 if v is only set
-// 4 if v is set in one address and used in another (so addresses
-// can be rewritten independently)
-// 0 otherwise (not touched)
-func copyu(p *obj.Prog, v *obj.Addr, s *obj.Addr) int {
- if p.From3Type() != obj.TYPE_NONE {
- // never generates a from3
- fmt.Printf("copyu: from3 (%v) not implemented\n", gc.Ctxt.Dconv(p.From3))
- }
-
- switch p.As {
- default:
- fmt.Printf("copyu: can't find %v\n", obj.Aconv(p.As))
- return 2
-
- case obj.ANOP, /* read p->from, write p->to */
- mips.AMOVV,
- mips.AMOVF,
- mips.AMOVD,
- mips.AMOVH,
- mips.AMOVHU,
- mips.AMOVB,
- mips.AMOVBU,
- mips.AMOVW,
- mips.AMOVWU,
- mips.AMOVFD,
- mips.AMOVDF,
- mips.AMOVDW,
- mips.AMOVWD,
- mips.AMOVFW,
- mips.AMOVWF,
- mips.AMOVDV,
- mips.AMOVVD,
- mips.AMOVFV,
- mips.AMOVVF,
- mips.ATRUNCFV,
- mips.ATRUNCDV,
- mips.ATRUNCFW,
- mips.ATRUNCDW:
- if s != nil {
- if copysub(&p.From, v, s, true) {
- return 1
- }
-
- // Update only indirect uses of v in p->to
- if !copyas(&p.To, v) {
- if copysub(&p.To, v, s, true) {
- return 1
- }
- }
- return 0
- }
-
- if copyas(&p.To, v) {
- // Fix up implicit from
- if p.From.Type == obj.TYPE_NONE {
- p.From = p.To
- }
- if copyau(&p.From, v) {
- return 4
- }
- return 3
- }
-
- if copyau(&p.From, v) {
- return 1
- }
- if copyau(&p.To, v) {
- // p->to only indirectly uses v
- return 1
- }
-
- return 0
-
- case mips.ASGT, /* read p->from, read p->reg, write p->to */
- mips.ASGTU,
-
- mips.AADD,
- mips.AADDU,
- mips.ASUB,
- mips.ASUBU,
- mips.ASLL,
- mips.ASRL,
- mips.ASRA,
- mips.AOR,
- mips.ANOR,
- mips.AAND,
- mips.AXOR,
-
- mips.AADDV,
- mips.AADDVU,
- mips.ASUBV,
- mips.ASUBVU,
- mips.ASLLV,
- mips.ASRLV,
- mips.ASRAV,
-
- mips.AADDF,
- mips.AADDD,
- mips.ASUBF,
- mips.ASUBD,
- mips.AMULF,
- mips.AMULD,
- mips.ADIVF,
- mips.ADIVD:
- if s != nil {
- if copysub(&p.From, v, s, true) {
- return 1
- }
- if copysub1(p, v, s, true) {
- return 1
- }
-
- // Update only indirect uses of v in p->to
- if !copyas(&p.To, v) {
- if copysub(&p.To, v, s, true) {
- return 1
- }
- }
- return 0
- }
-
- if copyas(&p.To, v) {
- if p.Reg == 0 {
- // Fix up implicit reg (e.g., ADD
- // R3,R4 -> ADD R3,R4,R4) so we can
- // update reg and to separately.
- p.Reg = p.To.Reg
- }
-
- if copyau(&p.From, v) {
- return 4
- }
- if copyau1(p, v) {
- return 4
- }
- return 3
- }
-
- if copyau(&p.From, v) {
- return 1
- }
- if copyau1(p, v) {
- return 1
- }
- if copyau(&p.To, v) {
- return 1
- }
- return 0
-
- case obj.ACHECKNIL, /* read p->from */
- mips.ABEQ, /* read p->from, read p->reg */
- mips.ABNE,
- mips.ABGTZ,
- mips.ABGEZ,
- mips.ABLTZ,
- mips.ABLEZ,
-
- mips.ACMPEQD,
- mips.ACMPEQF,
- mips.ACMPGED,
- mips.ACMPGEF,
- mips.ACMPGTD,
- mips.ACMPGTF,
- mips.ABFPF,
- mips.ABFPT,
-
- mips.AMUL,
- mips.AMULU,
- mips.ADIV,
- mips.ADIVU,
- mips.AMULV,
- mips.AMULVU,
- mips.ADIVV,
- mips.ADIVVU:
- if s != nil {
- if copysub(&p.From, v, s, true) {
- return 1
- }
- if copysub1(p, v, s, true) {
- return 1
- }
- return 0
- }
-
- if copyau(&p.From, v) {
- return 1
- }
- if copyau1(p, v) {
- return 1
- }
- return 0
-
- case mips.AJMP: /* read p->to */
- if s != nil {
- if copysub(&p.To, v, s, true) {
- return 1
- }
- return 0
- }
-
- if copyau(&p.To, v) {
- return 1
- }
- return 0
-
- case mips.ARET: /* funny */
- if s != nil {
- return 0
- }
-
- // All registers die at this point, so claim
- // everything is set (and not used).
- return 3
-
- case mips.AJAL: /* funny */
- if v.Type == obj.TYPE_REG {
- // TODO(rsc): REG_R0 and REG_F0 used to be
- // (when register numbers started at 0) exregoffset and exfregoffset,
- // which are unset entirely.
- // It's strange that this handles R0 and F0 differently from the other
- // registers. Possible failure to optimize?
- if mips.REG_R0 < v.Reg && v.Reg <= mips.REG_R31 {
- return 2
- }
- if v.Reg == mips.REGARG {
- return 2
- }
- if mips.REG_F0 < v.Reg && v.Reg <= mips.REG_F31 {
- return 2
- }
- }
-
- if p.From.Type == obj.TYPE_REG && v.Type == obj.TYPE_REG && p.From.Reg == v.Reg {
- return 2
- }
-
- if s != nil {
- if copysub(&p.To, v, s, true) {
- return 1
- }
- return 0
- }
-
- if copyau(&p.To, v) {
- return 4
- }
- return 3
-
- // R0 is zero, used by DUFFZERO, cannot be substituted.
- // R1 is ptr to memory, used and set, cannot be substituted.
- case obj.ADUFFZERO:
- if v.Type == obj.TYPE_REG {
- if v.Reg == 0 {
- return 1
- }
- if v.Reg == 1 {
- return 2
- }
- }
-
- return 0
-
- // R1, R2 are ptr to src, dst, used and set, cannot be substituted.
- // R3 is scratch, set by DUFFCOPY, cannot be substituted.
- case obj.ADUFFCOPY:
- if v.Type == obj.TYPE_REG {
- if v.Reg == 1 || v.Reg == 2 {
- return 2
- }
- if v.Reg == 3 {
- return 3
- }
- }
-
- return 0
-
- case obj.ATEXT: /* funny */
- if v.Type == obj.TYPE_REG {
- if v.Reg == mips.REGARG {
- return 3
- }
- }
- return 0
-
- case obj.APCDATA,
- obj.AFUNCDATA,
- obj.AVARDEF,
- obj.AVARKILL,
- obj.AVARLIVE,
- obj.AUSEFIELD:
- return 0
- }
-}
-
-// copyas returns 1 if a and v address the same register.
-//
-// If a is the from operand, this means this operation reads the
-// register in v. If a is the to operand, this means this operation
-// writes the register in v.
-func copyas(a *obj.Addr, v *obj.Addr) bool {
- if regtyp(v) {
- if a.Type == v.Type {
- if a.Reg == v.Reg {
- return true
- }
- }
- }
- return false
-}
-
-// copyau returns 1 if a either directly or indirectly addresses the
-// same register as v.
-//
-// If a is the from operand, this means this operation reads the
-// register in v. If a is the to operand, this means the operation
-// either reads or writes the register in v (if !copyas(a, v), then
-// the operation reads the register in v).
-func copyau(a *obj.Addr, v *obj.Addr) bool {
- if copyas(a, v) {
- return true
- }
- if v.Type == obj.TYPE_REG {
- if a.Type == obj.TYPE_MEM || (a.Type == obj.TYPE_ADDR && a.Reg != 0) {
- if v.Reg == a.Reg {
- return true
- }
- }
- }
- return false
-}
-
-// copyau1 returns true if p->reg references the same register as v and v
-// is a direct reference.
-func copyau1(p *obj.Prog, v *obj.Addr) bool {
- return regtyp(v) && v.Reg != 0 && p.Reg == v.Reg
-}
-
-// copysub replaces v with s in a if f==true or indicates it if could if f==false.
-// Returns true on failure to substitute (it always succeeds on mips).
-// TODO(dfc) remove unused return value, remove calls with f=false as they do nothing.
-func copysub(a *obj.Addr, v *obj.Addr, s *obj.Addr, f bool) bool {
- if f && copyau(a, v) {
- a.Reg = s.Reg
- }
- return false
-}
-
-// copysub1 replaces v with s in p1->reg if f==true or indicates if it could if f==false.
-// Returns true on failure to substitute (it always succeeds on mips).
-// TODO(dfc) remove unused return value, remove calls with f=false as they do nothing.
-func copysub1(p1 *obj.Prog, v *obj.Addr, s *obj.Addr, f bool) bool {
- if f && copyau1(p1, v) {
- p1.Reg = s.Reg
- }
- return false
-}
-
-func sameaddr(a *obj.Addr, v *obj.Addr) bool {
- if a.Type != v.Type {
- return false
- }
- if regtyp(v) && a.Reg == v.Reg {
- return true
- }
- if v.Type == obj.NAME_AUTO || v.Type == obj.NAME_PARAM {
- if v.Offset == a.Offset {
- return true
- }
- }
- return false
-}
-
-func smallindir(a *obj.Addr, reg *obj.Addr) bool {
- return reg.Type == obj.TYPE_REG && a.Type == obj.TYPE_MEM && a.Reg == reg.Reg && 0 <= a.Offset && a.Offset < 4096
-}
-
-func stackaddr(a *obj.Addr) bool {
- return a.Type == obj.TYPE_REG && a.Reg == mips.REGSP
-}
diff --git a/src/cmd/compile/internal/mips64/prog.go b/src/cmd/compile/internal/mips64/prog.go
index caf8482..74c735c 100644
--- a/src/cmd/compile/internal/mips64/prog.go
+++ b/src/cmd/compile/internal/mips64/prog.go
@@ -24,14 +24,13 @@ const (
// size variants of an operation even if we just use a subset.
//
// The table is formatted for 8-space tabs.
-var progtable = [mips.ALAST & obj.AMask]obj.ProgInfo{
+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.ACHECKNIL: {Flags: gc.LeftRead},
obj.AVARDEF: {Flags: gc.Pseudo | gc.RightWrite},
obj.AVARKILL: {Flags: gc.Pseudo | gc.RightWrite},
obj.AVARLIVE: {Flags: gc.Pseudo | gc.LeftRead},
@@ -135,9 +134,8 @@ var progtable = [mips.ALAST & obj.AMask]obj.ProgInfo{
obj.ADUFFCOPY: {Flags: gc.Call},
}
-func proginfo(p *obj.Prog) {
- info := &p.Info
- *info = progtable[p.As&obj.AMask]
+func proginfo(p *obj.Prog) gc.ProgInfo {
+ info := progtable[p.As&obj.AMask]
if info.Flags == 0 {
gc.Fatalf("proginfo: unknown instruction %v", p)
}
@@ -147,28 +145,10 @@ func proginfo(p *obj.Prog) {
info.Flags |= gc.RightRead /*CanRegRead |*/
}
- if (p.From.Type == obj.TYPE_MEM || p.From.Type == obj.TYPE_ADDR) && p.From.Reg != 0 {
- info.Regindex |= RtoB(int(p.From.Reg))
- }
-
- if (p.To.Type == obj.TYPE_MEM || p.To.Type == obj.TYPE_ADDR) && p.To.Reg != 0 {
- info.Regindex |= RtoB(int(p.To.Reg))
- }
-
if p.From.Type == obj.TYPE_ADDR && p.From.Sym != nil && (info.Flags&gc.LeftRead != 0) {
info.Flags &^= gc.LeftRead
info.Flags |= gc.LeftAddr
}
- if p.As == obj.ADUFFZERO {
- info.Reguse |= 1<<0 | RtoB(mips.REGRT1)
- info.Regset |= RtoB(mips.REGRT1)
- }
-
- if p.As == obj.ADUFFCOPY {
- // TODO(austin) Revisit when duffcopy is implemented
- info.Reguse |= RtoB(mips.REGRT1) | RtoB(mips.REGRT2) | RtoB(mips.REG_R3)
-
- info.Regset |= RtoB(mips.REGRT1) | RtoB(mips.REGRT2)
- }
+ return info
}
diff --git a/src/cmd/compile/internal/mips64/reg.go b/src/cmd/compile/internal/mips64/reg.go
deleted file mode 100644
index 2d2a773..0000000
--- a/src/cmd/compile/internal/mips64/reg.go
+++ /dev/null
@@ -1,162 +0,0 @@
-// Derived from Inferno utils/6c/reg.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6c/reg.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth at terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth at terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// Portions Copyright © 2009 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-package mips64
-
-import "cmd/internal/obj/mips"
-import "cmd/compile/internal/gc"
-
-const (
- NREGVAR = 64 /* 32 general + 32 floating */
-)
-
-var regname = []string{
- ".R0",
- ".R1",
- ".R2",
- ".R3",
- ".R4",
- ".R5",
- ".R6",
- ".R7",
- ".R8",
- ".R9",
- ".R10",
- ".R11",
- ".R12",
- ".R13",
- ".R14",
- ".R15",
- ".R16",
- ".R17",
- ".R18",
- ".R19",
- ".R20",
- ".R21",
- ".R22",
- ".R23",
- ".R24",
- ".R25",
- ".R26",
- ".R27",
- ".R28",
- ".R29",
- ".R30",
- ".R31",
- ".F0",
- ".F1",
- ".F2",
- ".F3",
- ".F4",
- ".F5",
- ".F6",
- ".F7",
- ".F8",
- ".F9",
- ".F10",
- ".F11",
- ".F12",
- ".F13",
- ".F14",
- ".F15",
- ".F16",
- ".F17",
- ".F18",
- ".F19",
- ".F20",
- ".F21",
- ".F22",
- ".F23",
- ".F24",
- ".F25",
- ".F26",
- ".F27",
- ".F28",
- ".F29",
- ".F30",
- ".F31",
-}
-
-func regnames(n *int) []string {
- *n = NREGVAR
- return regname
-}
-
-func excludedregs() uint64 {
- // Exclude registers with fixed functions
- regbits := 1<<0 | RtoB(mips.REGSP) | RtoB(mips.REGG) | RtoB(mips.REGSB) | RtoB(mips.REGTMP) | RtoB(mips.REGLINK) | RtoB(mips.REG_R26) | RtoB(mips.REG_R27)
-
- // Also exclude floating point registers with fixed constants
- regbits |= RtoB(mips.FREGZERO) | RtoB(mips.FREGHALF) | RtoB(mips.FREGONE) | RtoB(mips.FREGTWO)
-
- return regbits
-}
-
-func doregbits(r int) uint64 {
- return 0
-}
-
-/*
- * track register variables including external registers:
- * bit reg
- * 0 R0
- * 1 R1
- * ... ...
- * 31 R31
- * 32+0 F0
- * 32+1 F1
- * ... ...
- * 32+31 F31
- */
-func RtoB(r int) uint64 {
- if r > mips.REG_R0 && r <= mips.REG_R31 {
- return 1 << uint(r-mips.REG_R0)
- }
- if r >= mips.REG_F0 && r <= mips.REG_F31 {
- return 1 << uint(32+r-mips.REG_F0)
- }
- return 0
-}
-
-func BtoR(b uint64) int {
- b &= 0xffffffff
- if b == 0 {
- return 0
- }
- return gc.Bitno(b) + mips.REG_R0
-}
-
-func BtoF(b uint64) int {
- b >>= 32
- if b == 0 {
- return 0
- }
- return gc.Bitno(b) + mips.REG_F0
-}
diff --git a/src/cmd/compile/internal/mips64/ssa.go b/src/cmd/compile/internal/mips64/ssa.go
new file mode 100644
index 0000000..1432c6c
--- /dev/null
+++ b/src/cmd/compile/internal/mips64/ssa.go
@@ -0,0 +1,672 @@
+// Copyright 2016 The Go Authors. 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 (
+ "math"
+
+ "cmd/compile/internal/gc"
+ "cmd/compile/internal/ssa"
+ "cmd/internal/obj"
+ "cmd/internal/obj/mips"
+)
+
+// isFPreg returns whether r is an FP register
+func isFPreg(r int16) bool {
+ return mips.REG_F0 <= r && r <= mips.REG_F31
+}
+
+// isHILO returns whether r is HI or LO register
+func isHILO(r int16) bool {
+ return r == mips.REG_HI || r == mips.REG_LO
+}
+
+// loadByType returns the load instruction of the given type.
+func loadByType(t ssa.Type, r int16) obj.As {
+ if isFPreg(r) {
+ if t.Size() == 4 { // float32 or int32
+ return mips.AMOVF
+ } else { // float64 or int64
+ return mips.AMOVD
+ }
+ } else {
+ switch t.Size() {
+ case 1:
+ if t.IsSigned() {
+ return mips.AMOVB
+ } else {
+ return mips.AMOVBU
+ }
+ case 2:
+ if t.IsSigned() {
+ return mips.AMOVH
+ } else {
+ return mips.AMOVHU
+ }
+ case 4:
+ if t.IsSigned() {
+ return mips.AMOVW
+ } else {
+ return mips.AMOVWU
+ }
+ case 8:
+ return mips.AMOVV
+ }
+ }
+ panic("bad load type")
+}
+
+// storeByType returns the store instruction of the given type.
+func storeByType(t ssa.Type, r int16) obj.As {
+ if isFPreg(r) {
+ if t.Size() == 4 { // float32 or int32
+ return mips.AMOVF
+ } else { // float64 or int64
+ return mips.AMOVD
+ }
+ } else {
+ switch t.Size() {
+ case 1:
+ return mips.AMOVB
+ case 2:
+ return mips.AMOVH
+ case 4:
+ return mips.AMOVW
+ case 8:
+ return mips.AMOVV
+ }
+ }
+ panic("bad store type")
+}
+
+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
+ }
+ x := v.Args[0].Reg()
+ y := v.Reg()
+ if x == y {
+ return
+ }
+ as := mips.AMOVV
+ if isFPreg(x) && isFPreg(y) {
+ as = mips.AMOVD
+ }
+ p := gc.Prog(as)
+ p.From.Type = obj.TYPE_REG
+ p.From.Reg = x
+ p.To.Type = obj.TYPE_REG
+ p.To.Reg = y
+ 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.From.Type = obj.TYPE_REG
+ p.From.Reg = mips.REGTMP
+ p.To.Type = obj.TYPE_REG
+ p.To.Reg = y
+ }
+ case ssa.OpMIPS64MOVVnop:
+ if v.Reg() != v.Args[0].Reg() {
+ v.Fatalf("input[0] and output not in same register %s", v.LongString())
+ }
+ // nothing to do
+ case ssa.OpLoadReg:
+ if v.Type.IsFlags() {
+ v.Fatalf("load flags not implemented: %v", v.LongString())
+ return
+ }
+ r := v.Reg()
+ p := gc.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.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())
+ return
+ }
+ r := v.Args[0].Reg()
+ if isHILO(r) {
+ // cannot directly store, move to TMP and store
+ p := gc.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.From.Type = obj.TYPE_REG
+ p.From.Reg = r
+ gc.AddrAuto(&p.To, v)
+ case ssa.OpMIPS64ADDV,
+ ssa.OpMIPS64SUBV,
+ ssa.OpMIPS64AND,
+ ssa.OpMIPS64OR,
+ ssa.OpMIPS64XOR,
+ ssa.OpMIPS64NOR,
+ ssa.OpMIPS64SLLV,
+ ssa.OpMIPS64SRLV,
+ ssa.OpMIPS64SRAV,
+ ssa.OpMIPS64ADDF,
+ ssa.OpMIPS64ADDD,
+ ssa.OpMIPS64SUBF,
+ ssa.OpMIPS64SUBD,
+ ssa.OpMIPS64MULF,
+ ssa.OpMIPS64MULD,
+ ssa.OpMIPS64DIVF,
+ ssa.OpMIPS64DIVD:
+ p := gc.Prog(v.Op.Asm())
+ p.From.Type = obj.TYPE_REG
+ p.From.Reg = v.Args[1].Reg()
+ p.Reg = v.Args[0].Reg()
+ p.To.Type = obj.TYPE_REG
+ p.To.Reg = v.Reg()
+ case ssa.OpMIPS64SGT,
+ ssa.OpMIPS64SGTU:
+ p := gc.Prog(v.Op.Asm())
+ p.From.Type = obj.TYPE_REG
+ p.From.Reg = v.Args[0].Reg()
+ p.Reg = v.Args[1].Reg()
+ p.To.Type = obj.TYPE_REG
+ p.To.Reg = v.Reg()
+ case ssa.OpMIPS64ADDVconst,
+ ssa.OpMIPS64SUBVconst,
+ ssa.OpMIPS64ANDconst,
+ ssa.OpMIPS64ORconst,
+ ssa.OpMIPS64XORconst,
+ ssa.OpMIPS64NORconst,
+ ssa.OpMIPS64SLLVconst,
+ ssa.OpMIPS64SRLVconst,
+ ssa.OpMIPS64SRAVconst,
+ ssa.OpMIPS64SGTconst,
+ ssa.OpMIPS64SGTUconst:
+ p := gc.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.OpMIPS64MULV,
+ ssa.OpMIPS64MULVU,
+ ssa.OpMIPS64DIVV,
+ ssa.OpMIPS64DIVVU:
+ // result in hi,lo
+ p := gc.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.From.Type = obj.TYPE_CONST
+ p.From.Offset = v.AuxInt
+ p.To.Type = obj.TYPE_REG
+ p.To.Reg = r
+ 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.From.Type = obj.TYPE_REG
+ p.From.Reg = mips.REGTMP
+ p.To.Type = obj.TYPE_REG
+ p.To.Reg = r
+ }
+ case ssa.OpMIPS64MOVFconst,
+ ssa.OpMIPS64MOVDconst:
+ p := gc.Prog(v.Op.Asm())
+ p.From.Type = obj.TYPE_FCONST
+ p.From.Val = math.Float64frombits(uint64(v.AuxInt))
+ p.To.Type = obj.TYPE_REG
+ p.To.Reg = v.Reg()
+ case ssa.OpMIPS64CMPEQF,
+ ssa.OpMIPS64CMPEQD,
+ ssa.OpMIPS64CMPGEF,
+ ssa.OpMIPS64CMPGED,
+ ssa.OpMIPS64CMPGTF,
+ ssa.OpMIPS64CMPGTD:
+ p := gc.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.From.Type = obj.TYPE_ADDR
+ var wantreg string
+ // MOVV $sym+off(base), R
+ // the assembler expands it as the following:
+ // - base is SP: add constant offset to SP (R29)
+ // when constant is large, tmp register (R23) may be used
+ // - base is SB: load external address with relocation
+ switch v.Aux.(type) {
+ default:
+ v.Fatalf("aux is of unknown type %T", v.Aux)
+ case *ssa.ExternSymbol:
+ wantreg = "SB"
+ gc.AddAux(&p.From, v)
+ case *ssa.ArgSymbol, *ssa.AutoSymbol:
+ wantreg = "SP"
+ gc.AddAux(&p.From, v)
+ case nil:
+ // No sym, just MOVV $off(SP), R
+ wantreg = "SP"
+ p.From.Reg = mips.REGSP
+ p.From.Offset = v.AuxInt
+ }
+ if reg := v.Args[0].RegName(); reg != wantreg {
+ v.Fatalf("bad reg %s for symbol type %T, want %s", reg, v.Aux, wantreg)
+ }
+ p.To.Type = obj.TYPE_REG
+ p.To.Reg = v.Reg()
+ case ssa.OpMIPS64MOVBload,
+ ssa.OpMIPS64MOVBUload,
+ ssa.OpMIPS64MOVHload,
+ ssa.OpMIPS64MOVHUload,
+ ssa.OpMIPS64MOVWload,
+ ssa.OpMIPS64MOVWUload,
+ ssa.OpMIPS64MOVVload,
+ ssa.OpMIPS64MOVFload,
+ ssa.OpMIPS64MOVDload:
+ p := gc.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.OpMIPS64MOVBstore,
+ ssa.OpMIPS64MOVHstore,
+ ssa.OpMIPS64MOVWstore,
+ ssa.OpMIPS64MOVVstore,
+ ssa.OpMIPS64MOVFstore,
+ ssa.OpMIPS64MOVDstore:
+ p := gc.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.OpMIPS64MOVBstorezero,
+ ssa.OpMIPS64MOVHstorezero,
+ ssa.OpMIPS64MOVWstorezero,
+ ssa.OpMIPS64MOVVstorezero:
+ p := gc.Prog(v.Op.Asm())
+ 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.AddAux(&p.To, v)
+ case ssa.OpMIPS64MOVBreg,
+ ssa.OpMIPS64MOVBUreg,
+ ssa.OpMIPS64MOVHreg,
+ ssa.OpMIPS64MOVHUreg,
+ ssa.OpMIPS64MOVWreg,
+ ssa.OpMIPS64MOVWUreg:
+ a := v.Args[0]
+ for a.Op == ssa.OpCopy || a.Op == ssa.OpMIPS64MOVVreg {
+ a = a.Args[0]
+ }
+ if a.Op == ssa.OpLoadReg {
+ t := a.Type
+ switch {
+ case v.Op == ssa.OpMIPS64MOVBreg && t.Size() == 1 && t.IsSigned(),
+ v.Op == ssa.OpMIPS64MOVBUreg && t.Size() == 1 && !t.IsSigned(),
+ v.Op == ssa.OpMIPS64MOVHreg && t.Size() == 2 && t.IsSigned(),
+ v.Op == ssa.OpMIPS64MOVHUreg && t.Size() == 2 && !t.IsSigned(),
+ v.Op == ssa.OpMIPS64MOVWreg && t.Size() == 4 && t.IsSigned(),
+ v.Op == ssa.OpMIPS64MOVWUreg && t.Size() == 4 && !t.IsSigned():
+ // arg is a proper-typed load, already zero/sign-extended, don't extend again
+ if v.Reg() == v.Args[0].Reg() {
+ return
+ }
+ p := gc.Prog(mips.AMOVV)
+ p.From.Type = obj.TYPE_REG
+ p.From.Reg = v.Args[0].Reg()
+ p.To.Type = obj.TYPE_REG
+ p.To.Reg = v.Reg()
+ return
+ default:
+ }
+ }
+ fallthrough
+ case ssa.OpMIPS64MOVWF,
+ ssa.OpMIPS64MOVWD,
+ ssa.OpMIPS64TRUNCFW,
+ ssa.OpMIPS64TRUNCDW,
+ ssa.OpMIPS64MOVVF,
+ ssa.OpMIPS64MOVVD,
+ ssa.OpMIPS64TRUNCFV,
+ ssa.OpMIPS64TRUNCDV,
+ ssa.OpMIPS64MOVFD,
+ ssa.OpMIPS64MOVDF,
+ ssa.OpMIPS64NEGF,
+ ssa.OpMIPS64NEGD:
+ p := gc.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.From.Type = obj.TYPE_REG
+ p.From.Reg = v.Args[0].Reg()
+ p.Reg = mips.REGZERO
+ p.To.Type = obj.TYPE_REG
+ p.To.Reg = v.Reg()
+ case ssa.OpMIPS64DUFFZERO:
+ // runtime.duffzero expects start address - 8 in R1
+ p := gc.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.To.Type = obj.TYPE_MEM
+ p.To.Name = obj.NAME_EXTERN
+ p.To.Sym = gc.Linksym(gc.Pkglookup("duffzero", gc.Runtimepkg))
+ p.To.Offset = v.AuxInt
+ case ssa.OpMIPS64LoweredZero:
+ // SUBV $8, R1
+ // MOVV R0, 8(R1)
+ // ADDV $8, R1
+ // BNE Rarg1, R1, -2(PC)
+ // arg1 is the address of the last element to zero
+ var sz int64
+ var mov obj.As
+ switch {
+ case v.AuxInt%8 == 0:
+ sz = 8
+ mov = mips.AMOVV
+ case v.AuxInt%4 == 0:
+ sz = 4
+ mov = mips.AMOVW
+ case v.AuxInt%2 == 0:
+ sz = 2
+ mov = mips.AMOVH
+ default:
+ sz = 1
+ mov = mips.AMOVB
+ }
+ p := gc.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.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.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.From.Type = obj.TYPE_REG
+ p4.From.Reg = v.Args[1].Reg()
+ p4.Reg = mips.REG_R1
+ p4.To.Type = obj.TYPE_BRANCH
+ gc.Patch(p4, p2)
+ case ssa.OpMIPS64LoweredMove:
+ // SUBV $8, R1
+ // MOVV 8(R1), Rtmp
+ // MOVV Rtmp, (R2)
+ // ADDV $8, R1
+ // ADDV $8, R2
+ // BNE Rarg2, R1, -4(PC)
+ // arg2 is the address of the last element of src
+ var sz int64
+ var mov obj.As
+ switch {
+ case v.AuxInt%8 == 0:
+ sz = 8
+ mov = mips.AMOVV
+ case v.AuxInt%4 == 0:
+ sz = 4
+ mov = mips.AMOVW
+ case v.AuxInt%2 == 0:
+ sz = 2
+ mov = mips.AMOVH
+ default:
+ sz = 1
+ mov = mips.AMOVB
+ }
+ p := gc.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.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.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.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.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.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.OpMIPS64LoweredNilCheck:
+ // Issue a load which will fault if arg is nil.
+ p := gc.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")
+ }
+ 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
+ // BFPF 2(PC)
+ // MOVV $1, r
+ branch := mips.ABFPF
+ if v.Op == ssa.OpMIPS64FPFlagFalse {
+ branch = mips.ABFPT
+ }
+ p := gc.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.To.Type = obj.TYPE_BRANCH
+ p3 := gc.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
+ gc.Patch(p2, p4)
+ case ssa.OpSelect0, ssa.OpSelect1:
+ // nothing to do
+ case ssa.OpMIPS64LoweredGetClosurePtr:
+ // Closure pointer is R22 (mips.REGCTXT).
+ gc.CheckLoweredGetClosurePtr(v)
+ default:
+ v.Fatalf("genValue not implemented: %s", v.LongString())
+ }
+}
+
+var blockJump = map[ssa.BlockKind]struct {
+ asm, invasm obj.As
+}{
+ ssa.BlockMIPS64EQ: {mips.ABEQ, mips.ABNE},
+ ssa.BlockMIPS64NE: {mips.ABNE, mips.ABEQ},
+ ssa.BlockMIPS64LTZ: {mips.ABLTZ, mips.ABGEZ},
+ ssa.BlockMIPS64GEZ: {mips.ABGEZ, mips.ABLTZ},
+ ssa.BlockMIPS64LEZ: {mips.ABLEZ, mips.ABGTZ},
+ ssa.BlockMIPS64GTZ: {mips.ABGTZ, mips.ABLEZ},
+ ssa.BlockMIPS64FPT: {mips.ABFPT, mips.ABFPF},
+ ssa.BlockMIPS64FPF: {mips.ABFPF, mips.ABFPT},
+}
+
+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.To.Type = obj.TYPE_BRANCH
+ s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()})
+ }
+ case ssa.BlockDefer:
+ // defer returns in R1:
+ // 0 if we should continue executing
+ // 1 if we should jump to deferreturn call
+ p := gc.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.To.Type = obj.TYPE_BRANCH
+ s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()})
+ }
+ case ssa.BlockExit:
+ gc.Prog(obj.AUNDEF) // tell plive.go that we never reach here
+ case ssa.BlockRet:
+ gc.Prog(obj.ARET)
+ case ssa.BlockRetJmp:
+ p := gc.Prog(obj.ARET)
+ p.To.Type = obj.TYPE_MEM
+ p.To.Name = obj.NAME_EXTERN
+ p.To.Sym = gc.Linksym(b.Aux.(*gc.Sym))
+ case ssa.BlockMIPS64EQ, ssa.BlockMIPS64NE,
+ ssa.BlockMIPS64LTZ, ssa.BlockMIPS64GEZ,
+ ssa.BlockMIPS64LEZ, ssa.BlockMIPS64GTZ,
+ ssa.BlockMIPS64FPT, ssa.BlockMIPS64FPF:
+ jmp := blockJump[b.Kind]
+ var p *obj.Prog
+ switch next {
+ case b.Succs[0].Block():
+ p = gc.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.To.Type = obj.TYPE_BRANCH
+ s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()})
+ default:
+ p = gc.Prog(jmp.asm)
+ p.To.Type = obj.TYPE_BRANCH
+ s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()})
+ q := gc.Prog(obj.AJMP)
+ q.To.Type = obj.TYPE_BRANCH
+ s.Branches = append(s.Branches, gc.Branch{P: q, B: b.Succs[1].Block()})
+ }
+ if !b.Control.Type.IsFlags() {
+ p.From.Type = obj.TYPE_REG
+ p.From.Reg = b.Control.Reg()
+ }
+ default:
+ b.Fatalf("branch not implemented: %s. Control: %s", b.LongString(), b.Control.LongString())
+ }
+}
diff --git a/src/cmd/compile/internal/ppc64/cgen.go b/src/cmd/compile/internal/ppc64/cgen.go
deleted file mode 100644
index f4cc9c4..0000000
--- a/src/cmd/compile/internal/ppc64/cgen.go
+++ /dev/null
@@ -1,143 +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 ppc64
-
-import (
- "cmd/compile/internal/gc"
- "cmd/internal/obj"
- "cmd/internal/obj/ppc64"
-)
-
-func blockcopy(n, res *gc.Node, osrc, odst, w int64) {
- // determine alignment.
- // want to avoid unaligned access, so have to use
- // smaller operations for less aligned types.
- // for example moving [4]byte must use 4 MOVB not 1 MOVW.
- align := int(n.Type.Align)
-
- var op obj.As
- switch align {
- default:
- gc.Fatalf("sgen: invalid alignment %d for %v", align, n.Type)
-
- case 1:
- op = ppc64.AMOVBU
-
- case 2:
- op = ppc64.AMOVHU
-
- case 4:
- op = ppc64.AMOVWZU // there is no lwau, only lwaux
-
- case 8:
- op = ppc64.AMOVDU
- }
-
- if w%int64(align) != 0 {
- gc.Fatalf("sgen: unaligned size %d (align=%d) for %v", w, align, n.Type)
- }
- c := int32(w / int64(align))
-
- // if we are copying forward on the stack and
- // the src and dst overlap, then reverse direction
- dir := align
-
- if osrc < odst && odst < osrc+w {
- dir = -dir
- }
-
- var dst gc.Node
- var src gc.Node
- if n.Ullman >= res.Ullman {
- gc.Agenr(n, &dst, res) // temporarily use dst
- gc.Regalloc(&src, gc.Types[gc.Tptr], nil)
- gins(ppc64.AMOVD, &dst, &src)
- if res.Op == gc.ONAME {
- gc.Gvardef(res)
- }
- gc.Agen(res, &dst)
- } else {
- if res.Op == gc.ONAME {
- gc.Gvardef(res)
- }
- gc.Agenr(res, &dst, res)
- gc.Agenr(n, &src, nil)
- }
-
- var tmp gc.Node
- gc.Regalloc(&tmp, gc.Types[gc.Tptr], nil)
-
- // set up end marker
- var nend gc.Node
-
- // move src and dest to the end of block if necessary
- if dir < 0 {
- if c >= 4 {
- gc.Regalloc(&nend, gc.Types[gc.Tptr], nil)
- gins(ppc64.AMOVD, &src, &nend)
- }
-
- p := gins(ppc64.AADD, nil, &src)
- p.From.Type = obj.TYPE_CONST
- p.From.Offset = w
-
- p = gins(ppc64.AADD, nil, &dst)
- p.From.Type = obj.TYPE_CONST
- p.From.Offset = w
- } else {
- p := gins(ppc64.AADD, nil, &src)
- p.From.Type = obj.TYPE_CONST
- p.From.Offset = int64(-dir)
-
- p = gins(ppc64.AADD, nil, &dst)
- p.From.Type = obj.TYPE_CONST
- p.From.Offset = int64(-dir)
-
- if c >= 4 {
- gc.Regalloc(&nend, gc.Types[gc.Tptr], nil)
- p := gins(ppc64.AMOVD, &src, &nend)
- p.From.Type = obj.TYPE_ADDR
- p.From.Offset = w
- }
- }
-
- // move
- // TODO: enable duffcopy for larger copies.
- if c >= 4 {
- p := gins(op, &src, &tmp)
- p.From.Type = obj.TYPE_MEM
- p.From.Offset = int64(dir)
- ploop := p
-
- p = gins(op, &tmp, &dst)
- p.To.Type = obj.TYPE_MEM
- p.To.Offset = int64(dir)
-
- p = gins(ppc64.ACMP, &src, &nend)
-
- gc.Patch(gc.Gbranch(ppc64.ABNE, nil, 0), ploop)
- gc.Regfree(&nend)
- } else {
- // TODO(austin): Instead of generating ADD $-8,R8; ADD
- // $-8,R7; n*(MOVDU 8(R8),R9; MOVDU R9,8(R7);) just
- // generate the offsets directly and eliminate the
- // ADDs. That will produce shorter, more
- // pipeline-able code.
- var p *obj.Prog
- for ; c > 0; c-- {
- p = gins(op, &src, &tmp)
- p.From.Type = obj.TYPE_MEM
- p.From.Offset = int64(dir)
-
- p = gins(op, &tmp, &dst)
- p.To.Type = obj.TYPE_MEM
- p.To.Offset = int64(dir)
- }
- }
-
- gc.Regfree(&dst)
- gc.Regfree(&src)
- gc.Regfree(&tmp)
-}
diff --git a/src/cmd/compile/internal/ppc64/galign.go b/src/cmd/compile/internal/ppc64/galign.go
index a83dff9..186aa29 100644
--- a/src/cmd/compile/internal/ppc64/galign.go
+++ b/src/cmd/compile/internal/ppc64/galign.go
@@ -10,65 +10,21 @@ import (
"cmd/internal/obj/ppc64"
)
-func betypeinit() {
- if gc.Ctxt.Flag_shared {
- gc.Thearch.ReservedRegs = append(gc.Thearch.ReservedRegs, ppc64.REG_R2)
- gc.Thearch.ReservedRegs = append(gc.Thearch.ReservedRegs, ppc64.REG_R12)
- }
-}
-
-func Main() {
+func Init() {
gc.Thearch.LinkArch = &ppc64.Linkppc64
- if obj.Getgoarch() == "ppc64le" {
+ if obj.GOARCH == "ppc64le" {
gc.Thearch.LinkArch = &ppc64.Linkppc64le
}
gc.Thearch.REGSP = ppc64.REGSP
- gc.Thearch.REGCTXT = ppc64.REGCTXT
- gc.Thearch.REGCALLX = ppc64.REG_R3
- gc.Thearch.REGCALLX2 = ppc64.REG_R4
- gc.Thearch.REGRETURN = ppc64.REG_R3
- gc.Thearch.REGMIN = ppc64.REG_R0
- gc.Thearch.REGMAX = ppc64.REG_R31
- gc.Thearch.FREGMIN = ppc64.REG_F0
- gc.Thearch.FREGMAX = ppc64.REG_F31
gc.Thearch.MAXWIDTH = 1 << 50
- gc.Thearch.ReservedRegs = resvd
- gc.Thearch.Betypeinit = betypeinit
- gc.Thearch.Cgen_hmul = cgen_hmul
- gc.Thearch.Cgen_shift = cgen_shift
- gc.Thearch.Clearfat = clearfat
gc.Thearch.Defframe = defframe
- gc.Thearch.Dodiv = dodiv
- gc.Thearch.Excise = excise
- gc.Thearch.Expandchecks = expandchecks
- gc.Thearch.Getg = getg
- gc.Thearch.Gins = gins
- gc.Thearch.Ginscmp = ginscmp
- gc.Thearch.Ginscon = ginscon
- gc.Thearch.Ginsnop = ginsnop
- gc.Thearch.Gmove = gmove
- gc.Thearch.Peep = peep
gc.Thearch.Proginfo = proginfo
- gc.Thearch.Regtyp = regtyp
- gc.Thearch.Sameaddr = sameaddr
- gc.Thearch.Smallindir = smallindir
- gc.Thearch.Stackaddr = stackaddr
- gc.Thearch.Blockcopy = blockcopy
- gc.Thearch.Sudoaddable = sudoaddable
- gc.Thearch.Sudoclean = sudoclean
- gc.Thearch.Excludedregs = excludedregs
- gc.Thearch.RtoB = RtoB
- gc.Thearch.FtoB = RtoB
- gc.Thearch.BtoR = BtoR
- gc.Thearch.BtoF = BtoF
- gc.Thearch.Optoas = optoas
- gc.Thearch.Doregbits = doregbits
- gc.Thearch.Regnames = regnames
+
+ gc.Thearch.SSAMarkMoves = ssaMarkMoves
+ gc.Thearch.SSAGenValue = ssaGenValue
+ gc.Thearch.SSAGenBlock = ssaGenBlock
initvariants()
initproginfo()
-
- gc.Main()
- gc.Exit(0)
}
diff --git a/src/cmd/compile/internal/ppc64/ggen.go b/src/cmd/compile/internal/ppc64/ggen.go
index a89ed8f..b3ce968 100644
--- a/src/cmd/compile/internal/ppc64/ggen.go
+++ b/src/cmd/compile/internal/ppc64/ggen.go
@@ -8,7 +8,6 @@ import (
"cmd/compile/internal/gc"
"cmd/internal/obj"
"cmd/internal/obj/ppc64"
- "fmt"
)
func defframe(ptxt *obj.Prog) {
@@ -36,7 +35,7 @@ func defframe(ptxt *obj.Prog) {
gc.Fatalf("needzero class %d", n.Class)
}
if n.Type.Width%int64(gc.Widthptr) != 0 || n.Xoffset%int64(gc.Widthptr) != 0 || n.Type.Width == 0 {
- gc.Fatalf("var %v has size %d offset %d", gc.Nconv(n, gc.FmtLong), int(n.Type.Width), int(n.Xoffset))
+ 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) {
@@ -66,488 +65,35 @@ func zerorange(p *obj.Prog, frame int64, lo int64, hi int64) *obj.Prog {
}
if cnt < int64(4*gc.Widthptr) {
for i := int64(0); i < cnt; i += int64(gc.Widthptr) {
- p = appendpp(p, ppc64.AMOVD, obj.TYPE_REG, ppc64.REGZERO, 0, obj.TYPE_MEM, ppc64.REGSP, gc.Ctxt.FixedFrameSize()+frame+lo+i)
+ p = gc.Appendpp(p, ppc64.AMOVD, obj.TYPE_REG, ppc64.REGZERO, 0, obj.TYPE_MEM, ppc64.REGSP, gc.Ctxt.FixedFrameSize()+frame+lo+i)
}
} else if cnt <= int64(128*gc.Widthptr) {
- p = appendpp(p, ppc64.AADD, obj.TYPE_CONST, 0, gc.Ctxt.FixedFrameSize()+frame+lo-8, obj.TYPE_REG, ppc64.REGRT1, 0)
+ p = gc.Appendpp(p, ppc64.AADD, obj.TYPE_CONST, 0, gc.Ctxt.FixedFrameSize()+frame+lo-8, obj.TYPE_REG, ppc64.REGRT1, 0)
p.Reg = ppc64.REGSP
- p = appendpp(p, obj.ADUFFZERO, obj.TYPE_NONE, 0, 0, obj.TYPE_MEM, 0, 0)
- f := gc.Sysfunc("duffzero")
- gc.Naddr(&p.To, f)
- gc.Afunclit(&p.To, f)
+ p = gc.Appendpp(p, obj.ADUFFZERO, obj.TYPE_NONE, 0, 0, obj.TYPE_MEM, 0, 0)
+ gc.Naddr(&p.To, gc.Sysfunc("duffzero"))
p.To.Offset = 4 * (128 - cnt/int64(gc.Widthptr))
} else {
- p = appendpp(p, ppc64.AMOVD, obj.TYPE_CONST, 0, gc.Ctxt.FixedFrameSize()+frame+lo-8, obj.TYPE_REG, ppc64.REGTMP, 0)
- p = appendpp(p, ppc64.AADD, obj.TYPE_REG, ppc64.REGTMP, 0, obj.TYPE_REG, ppc64.REGRT1, 0)
+ p = 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.Reg = ppc64.REGSP
- p = appendpp(p, ppc64.AMOVD, obj.TYPE_CONST, 0, cnt, obj.TYPE_REG, ppc64.REGTMP, 0)
- p = appendpp(p, ppc64.AADD, obj.TYPE_REG, ppc64.REGTMP, 0, obj.TYPE_REG, ppc64.REGRT2, 0)
+ p = 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.Reg = ppc64.REGRT1
- p = appendpp(p, ppc64.AMOVDU, obj.TYPE_REG, ppc64.REGZERO, 0, obj.TYPE_MEM, ppc64.REGRT1, int64(gc.Widthptr))
+ p = gc.Appendpp(p, ppc64.AMOVDU, obj.TYPE_REG, ppc64.REGZERO, 0, obj.TYPE_MEM, ppc64.REGRT1, int64(gc.Widthptr))
p1 := p
- p = appendpp(p, ppc64.ACMP, obj.TYPE_REG, ppc64.REGRT1, 0, obj.TYPE_REG, ppc64.REGRT2, 0)
- p = appendpp(p, ppc64.ABNE, obj.TYPE_NONE, 0, 0, obj.TYPE_BRANCH, 0, 0)
+ 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)
gc.Patch(p, p1)
}
return p
}
-func appendpp(p *obj.Prog, as obj.As, ftype obj.AddrType, freg int, foffset int64, ttype obj.AddrType, treg int, toffset int64) *obj.Prog {
- q := gc.Ctxt.NewProg()
- gc.Clearp(q)
- q.As = as
- q.Lineno = p.Lineno
- q.From.Type = ftype
- q.From.Reg = int16(freg)
- q.From.Offset = foffset
- q.To.Type = ttype
- q.To.Reg = int16(treg)
- q.To.Offset = toffset
- q.Link = p.Link
- p.Link = q
- return q
-}
-
func ginsnop() {
- var reg gc.Node
- gc.Nodreg(®, gc.Types[gc.TINT], ppc64.REG_R0)
- gins(ppc64.AOR, ®, ®)
-}
-
-var panicdiv *gc.Node
-
-/*
- * generate division.
- * generates one of:
- * res = nl / nr
- * res = nl % nr
- * according to op.
- */
-func dodiv(op gc.Op, nl *gc.Node, nr *gc.Node, res *gc.Node) {
- // Have to be careful about handling
- // most negative int divided by -1 correctly.
- // The hardware will generate undefined result.
- // Also need to explicitly trap on division on zero,
- // the hardware will silently generate undefined result.
- // DIVW will leave unpredictable result in higher 32-bit,
- // so always use DIVD/DIVDU.
- t := nl.Type
-
- t0 := t
- check := false
- if t.IsSigned() {
- check = true
- if gc.Isconst(nl, gc.CTINT) && nl.Int64() != -(1<<uint64(t.Width*8-1)) {
- check = false
- } else if gc.Isconst(nr, gc.CTINT) && nr.Int64() != -1 {
- check = false
- }
- }
-
- if t.Width < 8 {
- if t.IsSigned() {
- t = gc.Types[gc.TINT64]
- } else {
- t = gc.Types[gc.TUINT64]
- }
- check = false
- }
-
- a := optoas(gc.ODIV, t)
-
- var tl gc.Node
- gc.Regalloc(&tl, t0, nil)
- var tr gc.Node
- gc.Regalloc(&tr, t0, nil)
- if nl.Ullman >= nr.Ullman {
- gc.Cgen(nl, &tl)
- gc.Cgen(nr, &tr)
- } else {
- gc.Cgen(nr, &tr)
- gc.Cgen(nl, &tl)
- }
-
- if t != t0 {
- // Convert
- tl2 := tl
-
- tr2 := tr
- tl.Type = t
- tr.Type = t
- gmove(&tl2, &tl)
- gmove(&tr2, &tr)
- }
-
- // Handle divide-by-zero panic.
- p1 := gins(optoas(gc.OCMP, t), &tr, nil)
-
- p1.To.Type = obj.TYPE_REG
- p1.To.Reg = ppc64.REGZERO
- p1 = gc.Gbranch(optoas(gc.ONE, t), nil, +1)
- if panicdiv == nil {
- panicdiv = gc.Sysfunc("panicdivide")
- }
- gc.Ginscall(panicdiv, -1)
- gc.Patch(p1, gc.Pc)
-
- var p2 *obj.Prog
- if check {
- var nm1 gc.Node
- gc.Nodconst(&nm1, t, -1)
- gins(optoas(gc.OCMP, t), &tr, &nm1)
- p1 := gc.Gbranch(optoas(gc.ONE, t), nil, +1)
- if op == gc.ODIV {
- // a / (-1) is -a.
- gins(optoas(gc.OMINUS, t), nil, &tl)
-
- gmove(&tl, res)
- } else {
- // a % (-1) is 0.
- var nz gc.Node
- gc.Nodconst(&nz, t, 0)
-
- gmove(&nz, res)
- }
-
- p2 = gc.Gbranch(obj.AJMP, nil, 0)
- gc.Patch(p1, gc.Pc)
- }
-
- p1 = gins(a, &tr, &tl)
- if op == gc.ODIV {
- gc.Regfree(&tr)
- gmove(&tl, res)
- } else {
- // A%B = A-(A/B*B)
- var tm gc.Node
- gc.Regalloc(&tm, t, nil)
-
- // patch div to use the 3 register form
- // TODO(minux): add gins3?
- p1.Reg = p1.To.Reg
-
- p1.To.Reg = tm.Reg
- gins(optoas(gc.OMUL, t), &tr, &tm)
- gc.Regfree(&tr)
- gins(optoas(gc.OSUB, t), &tm, &tl)
- gc.Regfree(&tm)
- gmove(&tl, res)
- }
-
- gc.Regfree(&tl)
- if check {
- gc.Patch(p2, gc.Pc)
- }
-}
-
-/*
- * generate high multiply:
- * res = (nl*nr) >> width
- */
-func cgen_hmul(nl *gc.Node, nr *gc.Node, res *gc.Node) {
- // largest ullman on left.
- if nl.Ullman < nr.Ullman {
- nl, nr = nr, nl
- }
-
- t := nl.Type
- w := t.Width * 8
- var n1 gc.Node
- gc.Cgenr(nl, &n1, res)
- var n2 gc.Node
- gc.Cgenr(nr, &n2, nil)
- switch gc.Simtype[t.Etype] {
- case gc.TINT8,
- gc.TINT16,
- gc.TINT32:
- gins(optoas(gc.OMUL, t), &n2, &n1)
- p := gins(ppc64.ASRAD, nil, &n1)
- p.From.Type = obj.TYPE_CONST
- p.From.Offset = w
-
- case gc.TUINT8,
- gc.TUINT16,
- gc.TUINT32:
- gins(optoas(gc.OMUL, t), &n2, &n1)
- p := gins(ppc64.ASRD, nil, &n1)
- p.From.Type = obj.TYPE_CONST
- p.From.Offset = w
-
- case gc.TINT64,
- gc.TUINT64:
- if t.IsSigned() {
- gins(ppc64.AMULHD, &n2, &n1)
- } else {
- gins(ppc64.AMULHDU, &n2, &n1)
- }
-
- default:
- gc.Fatalf("cgen_hmul %v", t)
- }
-
- gc.Cgen(&n1, res)
- gc.Regfree(&n1)
- gc.Regfree(&n2)
-}
-
-/*
- * generate shift according to op, one of:
- * res = nl << nr
- * res = nl >> nr
- */
-func cgen_shift(op gc.Op, bounded bool, nl *gc.Node, nr *gc.Node, res *gc.Node) {
- a := optoas(op, nl.Type)
-
- if nr.Op == gc.OLITERAL {
- var n1 gc.Node
- gc.Regalloc(&n1, nl.Type, res)
- gc.Cgen(nl, &n1)
- sc := uint64(nr.Int64())
- if sc >= uint64(nl.Type.Width*8) {
- // large shift gets 2 shifts by width-1
- var n3 gc.Node
- gc.Nodconst(&n3, gc.Types[gc.TUINT32], nl.Type.Width*8-1)
-
- gins(a, &n3, &n1)
- gins(a, &n3, &n1)
- } else {
- gins(a, nr, &n1)
- }
- gmove(&n1, res)
- gc.Regfree(&n1)
- return
- }
-
- if nl.Ullman >= gc.UINF {
- var n4 gc.Node
- gc.Tempname(&n4, nl.Type)
- gc.Cgen(nl, &n4)
- nl = &n4
- }
-
- if nr.Ullman >= gc.UINF {
- var n5 gc.Node
- gc.Tempname(&n5, nr.Type)
- gc.Cgen(nr, &n5)
- nr = &n5
- }
-
- // Allow either uint32 or uint64 as shift type,
- // to avoid unnecessary conversion from uint32 to uint64
- // just to do the comparison.
- tcount := gc.Types[gc.Simtype[nr.Type.Etype]]
-
- if tcount.Etype < gc.TUINT32 {
- tcount = gc.Types[gc.TUINT32]
- }
-
- var n1 gc.Node
- gc.Regalloc(&n1, nr.Type, nil) // to hold the shift type in CX
- var n3 gc.Node
- gc.Regalloc(&n3, tcount, &n1) // to clear high bits of CX
-
- var n2 gc.Node
- gc.Regalloc(&n2, nl.Type, res)
-
- if nl.Ullman >= nr.Ullman {
- gc.Cgen(nl, &n2)
- gc.Cgen(nr, &n1)
- gmove(&n1, &n3)
- } else {
- gc.Cgen(nr, &n1)
- gmove(&n1, &n3)
- gc.Cgen(nl, &n2)
- }
-
- gc.Regfree(&n3)
-
- // test and fix up large shifts
- if !bounded {
- gc.Nodconst(&n3, tcount, nl.Type.Width*8)
- gins(optoas(gc.OCMP, tcount), &n1, &n3)
- p1 := gc.Gbranch(optoas(gc.OLT, tcount), nil, +1)
- if op == gc.ORSH && nl.Type.IsSigned() {
- gc.Nodconst(&n3, gc.Types[gc.TUINT32], nl.Type.Width*8-1)
- gins(a, &n3, &n2)
- } else {
- gc.Nodconst(&n3, nl.Type, 0)
- gmove(&n3, &n2)
- }
-
- gc.Patch(p1, gc.Pc)
- }
-
- gins(a, &n1, &n2)
-
- gmove(&n2, res)
-
- gc.Regfree(&n1)
- gc.Regfree(&n2)
-}
-
-func clearfat(nl *gc.Node) {
- /* clear a fat object */
- if gc.Debug['g'] != 0 {
- fmt.Printf("clearfat %v (%v, size: %d)\n", nl, nl.Type, nl.Type.Width)
- }
-
- w := uint64(nl.Type.Width)
-
- // Avoid taking the address for simple enough types.
- if gc.Componentgen(nil, nl) {
- return
- }
-
- c := w % 8 // bytes
- q := w / 8 // dwords
-
- if gc.Reginuse(ppc64.REGRT1) {
- gc.Fatalf("%v in use during clearfat", obj.Rconv(ppc64.REGRT1))
- }
-
- var r0 gc.Node
- gc.Nodreg(&r0, gc.Types[gc.TUINT64], ppc64.REGZERO)
- var dst gc.Node
- gc.Nodreg(&dst, gc.Types[gc.Tptr], ppc64.REGRT1)
- gc.Regrealloc(&dst)
- gc.Agen(nl, &dst)
-
- var boff uint64
- if q > 128 {
- p := gins(ppc64.ASUB, nil, &dst)
- p.From.Type = obj.TYPE_CONST
- p.From.Offset = 8
-
- var end gc.Node
- gc.Regalloc(&end, gc.Types[gc.Tptr], nil)
- p = gins(ppc64.AMOVD, &dst, &end)
- p.From.Type = obj.TYPE_ADDR
- p.From.Offset = int64(q * 8)
-
- p = gins(ppc64.AMOVDU, &r0, &dst)
- p.To.Type = obj.TYPE_MEM
- p.To.Offset = 8
- pl := p
-
- p = gins(ppc64.ACMP, &dst, &end)
- gc.Patch(gc.Gbranch(ppc64.ABNE, nil, 0), pl)
-
- gc.Regfree(&end)
-
- // The loop leaves R3 on the last zeroed dword
- boff = 8
- } else if q >= 4 {
- p := gins(ppc64.ASUB, nil, &dst)
- p.From.Type = obj.TYPE_CONST
- p.From.Offset = 8
- f := gc.Sysfunc("duffzero")
- p = gins(obj.ADUFFZERO, nil, f)
- gc.Afunclit(&p.To, f)
-
- // 4 and 128 = magic constants: see ../../runtime/asm_ppc64x.s
- p.To.Offset = int64(4 * (128 - q))
-
- // duffzero leaves R3 on the last zeroed dword
- boff = 8
- } else {
- var p *obj.Prog
- for t := uint64(0); t < q; t++ {
- p = gins(ppc64.AMOVD, &r0, &dst)
- p.To.Type = obj.TYPE_MEM
- p.To.Offset = int64(8 * t)
- }
-
- boff = 8 * q
- }
-
- var p *obj.Prog
- for t := uint64(0); t < c; t++ {
- p = gins(ppc64.AMOVB, &r0, &dst)
- p.To.Type = obj.TYPE_MEM
- p.To.Offset = int64(t + boff)
- }
-
- gc.Regfree(&dst)
-}
-
-// Called after regopt and peep have run.
-// Expand CHECKNIL pseudo-op into actual nil pointer check.
-func expandchecks(firstp *obj.Prog) {
- var p1 *obj.Prog
- var p2 *obj.Prog
-
- for p := firstp; p != nil; p = p.Link {
- if gc.Debug_checknil != 0 && gc.Ctxt.Debugvlog != 0 {
- fmt.Printf("expandchecks: %v\n", p)
- }
- if p.As != obj.ACHECKNIL {
- continue
- }
- if gc.Debug_checknil != 0 && p.Lineno > 1 { // p->lineno==1 in generated wrappers
- gc.Warnl(p.Lineno, "generated nil check")
- }
- if p.From.Type != obj.TYPE_REG {
- gc.Fatalf("invalid nil check %v\n", p)
- }
-
- /*
- // check is
- // TD $4, R0, arg (R0 is always zero)
- // eqv. to:
- // tdeq r0, arg
- // NOTE: this needs special runtime support to make SIGTRAP recoverable.
- reg = p->from.reg;
- p->as = ATD;
- p->from = p->to = p->from3 = zprog.from;
- p->from.type = TYPE_CONST;
- p->from.offset = 4;
- p->from.reg = 0;
- p->reg = REGZERO;
- p->to.type = TYPE_REG;
- p->to.reg = reg;
- */
- // check is
- // CMP arg, R0
- // BNE 2(PC) [likely]
- // MOVD R0, 0(R0)
- p1 = gc.Ctxt.NewProg()
-
- p2 = gc.Ctxt.NewProg()
- gc.Clearp(p1)
- gc.Clearp(p2)
- p1.Link = p2
- p2.Link = p.Link
- p.Link = p1
- p1.Lineno = p.Lineno
- p2.Lineno = p.Lineno
- p1.Pc = 9999
- p2.Pc = 9999
- p.As = ppc64.ACMP
- p.To.Type = obj.TYPE_REG
- p.To.Reg = ppc64.REGZERO
- p1.As = ppc64.ABNE
-
- //p1->from.type = TYPE_CONST;
- //p1->from.offset = 1; // likely
- p1.To.Type = obj.TYPE_BRANCH
-
- p1.To.Val = p2.Link
-
- // crash by write to memory address 0.
- p2.As = ppc64.AMOVD
-
- p2.From.Type = obj.TYPE_REG
- p2.From.Reg = ppc64.REGZERO
- p2.To.Type = obj.TYPE_MEM
- p2.To.Reg = ppc64.REGZERO
- p2.To.Offset = 0
- }
-}
-
-// res = runtime.getg()
-func getg(res *gc.Node) {
- var n1 gc.Node
- gc.Nodreg(&n1, res.Type, ppc64.REGG)
- gmove(&n1, res)
+ p := gc.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
}
diff --git a/src/cmd/compile/internal/ppc64/gsubr.go b/src/cmd/compile/internal/ppc64/gsubr.go
deleted file mode 100644
index f875999..0000000
--- a/src/cmd/compile/internal/ppc64/gsubr.go
+++ /dev/null
@@ -1,1076 +0,0 @@
-// Derived from Inferno utils/6c/txt.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6c/txt.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth at terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth at terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// Portions Copyright © 2009 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-package ppc64
-
-import (
- "cmd/compile/internal/big"
- "cmd/compile/internal/gc"
- "cmd/internal/obj"
- "cmd/internal/obj/ppc64"
- "fmt"
-)
-
-var resvd = []int{
- ppc64.REGZERO,
- ppc64.REGSP, // reserved for SP
- // We need to preserve the C ABI TLS pointer because sigtramp
- // may happen during C code and needs to access the g. C
- // clobbers REGG, so if Go were to clobber REGTLS, sigtramp
- // won't know which convention to use. By preserving REGTLS,
- // we can just retrieve g from TLS when we aren't sure.
- ppc64.REGTLS,
-
- // TODO(austin): Consolidate REGTLS and REGG?
- ppc64.REGG,
- ppc64.REGTMP, // REGTMP
- ppc64.FREGCVI,
- ppc64.FREGZERO,
- ppc64.FREGHALF,
- ppc64.FREGONE,
- ppc64.FREGTWO,
-}
-
-/*
- * generate
- * as $c, n
- */
-func ginscon(as obj.As, c int64, n2 *gc.Node) {
- var n1 gc.Node
-
- gc.Nodconst(&n1, gc.Types[gc.TINT64], c)
-
- if as != ppc64.AMOVD && (c < -ppc64.BIG || c > ppc64.BIG) || n2.Op != gc.OREGISTER || as == ppc64.AMULLD {
- // cannot have more than 16-bit of immediate in ADD, etc.
- // instead, MOV into register first.
- var ntmp gc.Node
- gc.Regalloc(&ntmp, gc.Types[gc.TINT64], nil)
-
- rawgins(ppc64.AMOVD, &n1, &ntmp)
- rawgins(as, &ntmp, n2)
- gc.Regfree(&ntmp)
- return
- }
-
- rawgins(as, &n1, n2)
-}
-
-/*
- * generate
- * as n, $c (CMP/CMPU)
- */
-func ginscon2(as obj.As, n2 *gc.Node, c int64) {
- var n1 gc.Node
-
- gc.Nodconst(&n1, gc.Types[gc.TINT64], c)
-
- switch as {
- default:
- gc.Fatalf("ginscon2")
-
- case ppc64.ACMP:
- if -ppc64.BIG <= c && c <= ppc64.BIG {
- rawgins(as, n2, &n1)
- return
- }
-
- case ppc64.ACMPU:
- if 0 <= c && c <= 2*ppc64.BIG {
- rawgins(as, n2, &n1)
- return
- }
- }
-
- // MOV n1 into register first
- var ntmp gc.Node
- gc.Regalloc(&ntmp, gc.Types[gc.TINT64], nil)
-
- rawgins(ppc64.AMOVD, &n1, &ntmp)
- rawgins(as, n2, &ntmp)
- gc.Regfree(&ntmp)
-}
-
-func ginscmp(op gc.Op, t *gc.Type, n1, n2 *gc.Node, likely int) *obj.Prog {
- if t.IsInteger() && n1.Op == gc.OLITERAL && n2.Op != gc.OLITERAL {
- // Reverse comparison to place constant last.
- op = gc.Brrev(op)
- n1, n2 = n2, n1
- }
-
- var r1, r2, g1, g2 gc.Node
- gc.Regalloc(&r1, t, n1)
- gc.Regalloc(&g1, n1.Type, &r1)
- gc.Cgen(n1, &g1)
- gmove(&g1, &r1)
- if t.IsInteger() && gc.Isconst(n2, gc.CTINT) {
- ginscon2(optoas(gc.OCMP, t), &r1, n2.Int64())
- } else {
- gc.Regalloc(&r2, t, n2)
- gc.Regalloc(&g2, n1.Type, &r2)
- gc.Cgen(n2, &g2)
- gmove(&g2, &r2)
- rawgins(optoas(gc.OCMP, t), &r1, &r2)
- gc.Regfree(&g2)
- gc.Regfree(&r2)
- }
- gc.Regfree(&g1)
- gc.Regfree(&r1)
- return gc.Gbranch(optoas(op, t), nil, likely)
-}
-
-// set up nodes representing 2^63
-var (
- bigi gc.Node
- bigf gc.Node
- bignodes_did bool
-)
-
-func bignodes() {
- if bignodes_did {
- return
- }
- bignodes_did = true
-
- var i big.Int
- i.SetInt64(1)
- i.Lsh(&i, 63)
-
- gc.Nodconst(&bigi, gc.Types[gc.TUINT64], 0)
- bigi.SetBigInt(&i)
-
- bigi.Convconst(&bigf, gc.Types[gc.TFLOAT64])
-}
-
-/*
- * generate move:
- * t = f
- * hard part is conversions.
- */
-func gmove(f *gc.Node, t *gc.Node) {
- if gc.Debug['M'] != 0 {
- fmt.Printf("gmove %v -> %v\n", gc.Nconv(f, gc.FmtLong), gc.Nconv(t, gc.FmtLong))
- }
-
- ft := int(gc.Simsimtype(f.Type))
- tt := int(gc.Simsimtype(t.Type))
- cvt := t.Type
-
- if gc.Iscomplex[ft] || gc.Iscomplex[tt] {
- gc.Complexmove(f, t)
- return
- }
-
- // cannot have two memory operands
- var r2 gc.Node
- var r1 gc.Node
- var a obj.As
- if gc.Ismem(f) && gc.Ismem(t) {
- goto hard
- }
-
- // convert constant to desired type
- if f.Op == gc.OLITERAL {
- var con gc.Node
- switch tt {
- default:
- f.Convconst(&con, t.Type)
-
- case gc.TINT32,
- gc.TINT16,
- gc.TINT8:
- var con gc.Node
- f.Convconst(&con, gc.Types[gc.TINT64])
- var r1 gc.Node
- gc.Regalloc(&r1, con.Type, t)
- gins(ppc64.AMOVD, &con, &r1)
- gmove(&r1, t)
- gc.Regfree(&r1)
- return
-
- case gc.TUINT32,
- gc.TUINT16,
- gc.TUINT8:
- var con gc.Node
- f.Convconst(&con, gc.Types[gc.TUINT64])
- var r1 gc.Node
- gc.Regalloc(&r1, con.Type, t)
- gins(ppc64.AMOVD, &con, &r1)
- gmove(&r1, t)
- gc.Regfree(&r1)
- return
- }
-
- f = &con
- ft = tt // so big switch will choose a simple mov
-
- // constants can't move directly to memory.
- if gc.Ismem(t) {
- goto hard
- }
- }
-
- // float constants come from memory.
- //if(isfloat[tt])
- // goto hard;
-
- // 64-bit immediates are also from memory.
- //if(isint[tt])
- // goto hard;
- //// 64-bit immediates are really 32-bit sign-extended
- //// unless moving into a register.
- //if(isint[tt]) {
- // if(mpcmpfixfix(con.val.u.xval, minintval[TINT32]) < 0)
- // goto hard;
- // if(mpcmpfixfix(con.val.u.xval, maxintval[TINT32]) > 0)
- // goto hard;
- //}
-
- // value -> value copy, only one memory operand.
- // figure out the instruction to use.
- // break out of switch for one-instruction gins.
- // goto rdst for "destination must be register".
- // goto hard for "convert to cvt type first".
- // otherwise handle and return.
-
- switch uint32(ft)<<16 | uint32(tt) {
- default:
- gc.Fatalf("gmove %v -> %v", gc.Tconv(f.Type, gc.FmtLong), gc.Tconv(t.Type, gc.FmtLong))
-
- /*
- * integer copy and truncate
- */
- case gc.TINT8<<16 | gc.TINT8, // same size
- gc.TUINT8<<16 | gc.TINT8,
- gc.TINT16<<16 | gc.TINT8,
- // truncate
- gc.TUINT16<<16 | gc.TINT8,
- gc.TINT32<<16 | gc.TINT8,
- gc.TUINT32<<16 | gc.TINT8,
- gc.TINT64<<16 | gc.TINT8,
- gc.TUINT64<<16 | gc.TINT8:
- a = ppc64.AMOVB
-
- case gc.TINT8<<16 | gc.TUINT8, // same size
- gc.TUINT8<<16 | gc.TUINT8,
- gc.TINT16<<16 | gc.TUINT8,
- // truncate
- gc.TUINT16<<16 | gc.TUINT8,
- gc.TINT32<<16 | gc.TUINT8,
- gc.TUINT32<<16 | gc.TUINT8,
- gc.TINT64<<16 | gc.TUINT8,
- gc.TUINT64<<16 | gc.TUINT8:
- a = ppc64.AMOVBZ
-
- case gc.TINT16<<16 | gc.TINT16, // same size
- gc.TUINT16<<16 | gc.TINT16,
- gc.TINT32<<16 | gc.TINT16,
- // truncate
- gc.TUINT32<<16 | gc.TINT16,
- gc.TINT64<<16 | gc.TINT16,
- gc.TUINT64<<16 | gc.TINT16:
- a = ppc64.AMOVH
-
- case gc.TINT16<<16 | gc.TUINT16, // same size
- gc.TUINT16<<16 | gc.TUINT16,
- gc.TINT32<<16 | gc.TUINT16,
- // truncate
- gc.TUINT32<<16 | gc.TUINT16,
- gc.TINT64<<16 | gc.TUINT16,
- gc.TUINT64<<16 | gc.TUINT16:
- a = ppc64.AMOVHZ
-
- case gc.TINT32<<16 | gc.TINT32, // same size
- gc.TUINT32<<16 | gc.TINT32,
- gc.TINT64<<16 | gc.TINT32,
- // truncate
- gc.TUINT64<<16 | gc.TINT32:
- a = ppc64.AMOVW
-
- case gc.TINT32<<16 | gc.TUINT32, // same size
- gc.TUINT32<<16 | gc.TUINT32,
- gc.TINT64<<16 | gc.TUINT32,
- gc.TUINT64<<16 | gc.TUINT32:
- a = ppc64.AMOVWZ
-
- case gc.TINT64<<16 | gc.TINT64, // same size
- gc.TINT64<<16 | gc.TUINT64,
- gc.TUINT64<<16 | gc.TINT64,
- gc.TUINT64<<16 | gc.TUINT64:
- a = ppc64.AMOVD
-
- /*
- * integer up-conversions
- */
- case gc.TINT8<<16 | gc.TINT16, // sign extend int8
- gc.TINT8<<16 | gc.TUINT16,
- gc.TINT8<<16 | gc.TINT32,
- gc.TINT8<<16 | gc.TUINT32,
- gc.TINT8<<16 | gc.TINT64,
- gc.TINT8<<16 | gc.TUINT64:
- a = ppc64.AMOVB
-
- goto rdst
-
- case gc.TUINT8<<16 | gc.TINT16, // zero extend uint8
- gc.TUINT8<<16 | gc.TUINT16,
- gc.TUINT8<<16 | gc.TINT32,
- gc.TUINT8<<16 | gc.TUINT32,
- gc.TUINT8<<16 | gc.TINT64,
- gc.TUINT8<<16 | gc.TUINT64:
- a = ppc64.AMOVBZ
-
- goto rdst
-
- case gc.TINT16<<16 | gc.TINT32, // sign extend int16
- gc.TINT16<<16 | gc.TUINT32,
- gc.TINT16<<16 | gc.TINT64,
- gc.TINT16<<16 | gc.TUINT64:
- a = ppc64.AMOVH
-
- goto rdst
-
- case gc.TUINT16<<16 | gc.TINT32, // zero extend uint16
- gc.TUINT16<<16 | gc.TUINT32,
- gc.TUINT16<<16 | gc.TINT64,
- gc.TUINT16<<16 | gc.TUINT64:
- a = ppc64.AMOVHZ
-
- goto rdst
-
- case gc.TINT32<<16 | gc.TINT64, // sign extend int32
- gc.TINT32<<16 | gc.TUINT64:
- a = ppc64.AMOVW
-
- goto rdst
-
- case gc.TUINT32<<16 | gc.TINT64, // zero extend uint32
- gc.TUINT32<<16 | gc.TUINT64:
- a = ppc64.AMOVWZ
-
- goto rdst
-
- //warn("gmove: convert float to int not implemented: %N -> %N\n", f, t);
- //return;
- // algorithm is:
- // if small enough, use native float64 -> int64 conversion.
- // otherwise, subtract 2^63, convert, and add it back.
- /*
- * float to integer
- */
- case gc.TFLOAT32<<16 | gc.TINT32,
- gc.TFLOAT64<<16 | gc.TINT32,
- gc.TFLOAT32<<16 | gc.TINT64,
- gc.TFLOAT64<<16 | gc.TINT64,
- gc.TFLOAT32<<16 | gc.TINT16,
- gc.TFLOAT32<<16 | gc.TINT8,
- gc.TFLOAT32<<16 | gc.TUINT16,
- gc.TFLOAT32<<16 | gc.TUINT8,
- gc.TFLOAT64<<16 | gc.TINT16,
- gc.TFLOAT64<<16 | gc.TINT8,
- gc.TFLOAT64<<16 | gc.TUINT16,
- gc.TFLOAT64<<16 | gc.TUINT8,
- gc.TFLOAT32<<16 | gc.TUINT32,
- gc.TFLOAT64<<16 | gc.TUINT32,
- gc.TFLOAT32<<16 | gc.TUINT64,
- gc.TFLOAT64<<16 | gc.TUINT64:
- bignodes()
-
- var r1 gc.Node
- gc.Regalloc(&r1, gc.Types[ft], f)
- gmove(f, &r1)
- if tt == gc.TUINT64 {
- gc.Regalloc(&r2, gc.Types[gc.TFLOAT64], nil)
- gmove(&bigf, &r2)
- gins(ppc64.AFCMPU, &r1, &r2)
- p1 := gc.Gbranch(optoas(gc.OLT, gc.Types[gc.TFLOAT64]), nil, +1)
- gins(ppc64.AFSUB, &r2, &r1)
- gc.Patch(p1, gc.Pc)
- gc.Regfree(&r2)
- }
-
- gc.Regalloc(&r2, gc.Types[gc.TFLOAT64], nil)
- var r3 gc.Node
- gc.Regalloc(&r3, gc.Types[gc.TINT64], t)
- gins(ppc64.AFCTIDZ, &r1, &r2)
- p1 := gins(ppc64.AFMOVD, &r2, nil)
- p1.To.Type = obj.TYPE_MEM
- p1.To.Reg = ppc64.REGSP
- p1.To.Offset = -8
- p1 = gins(ppc64.AMOVD, nil, &r3)
- p1.From.Type = obj.TYPE_MEM
- p1.From.Reg = ppc64.REGSP
- p1.From.Offset = -8
- gc.Regfree(&r2)
- gc.Regfree(&r1)
- if tt == gc.TUINT64 {
- p1 := gc.Gbranch(optoas(gc.OLT, gc.Types[gc.TFLOAT64]), nil, +1) // use CR0 here again
- gc.Nodreg(&r1, gc.Types[gc.TINT64], ppc64.REGTMP)
- gins(ppc64.AMOVD, &bigi, &r1)
- gins(ppc64.AADD, &r1, &r3)
- gc.Patch(p1, gc.Pc)
- }
-
- gmove(&r3, t)
- gc.Regfree(&r3)
- return
-
- /*
- * integer to float
- */
- case gc.TINT32<<16 | gc.TFLOAT32,
- gc.TINT32<<16 | gc.TFLOAT64,
- gc.TINT64<<16 | gc.TFLOAT32,
- gc.TINT64<<16 | gc.TFLOAT64,
- gc.TINT16<<16 | gc.TFLOAT32,
- gc.TINT16<<16 | gc.TFLOAT64,
- gc.TINT8<<16 | gc.TFLOAT32,
- gc.TINT8<<16 | gc.TFLOAT64,
- gc.TUINT16<<16 | gc.TFLOAT32,
- gc.TUINT16<<16 | gc.TFLOAT64,
- gc.TUINT8<<16 | gc.TFLOAT32,
- gc.TUINT8<<16 | gc.TFLOAT64,
- gc.TUINT32<<16 | gc.TFLOAT32,
- gc.TUINT32<<16 | gc.TFLOAT64,
- gc.TUINT64<<16 | gc.TFLOAT32,
- gc.TUINT64<<16 | gc.TFLOAT64:
- bignodes()
-
- // The algorithm is:
- // if small enough, use native int64 -> float64 conversion,
- // otherwise halve (x -> (x>>1)|(x&1)), convert, and double.
- // Note: could use FCFIDU instead if target supports it.
- var r1 gc.Node
- gc.Regalloc(&r1, gc.Types[gc.TINT64], nil)
- gmove(f, &r1)
- if ft == gc.TUINT64 {
- gc.Nodreg(&r2, gc.Types[gc.TUINT64], ppc64.REGTMP)
- gmove(&bigi, &r2)
- gins(ppc64.ACMPU, &r1, &r2)
- p1 := gc.Gbranch(optoas(gc.OLT, gc.Types[gc.TUINT64]), nil, +1)
- var r3 gc.Node
- gc.Regalloc(&r3, gc.Types[gc.TUINT64], nil)
- p2 := gins(ppc64.AANDCC, nil, &r3) // andi.
- p2.Reg = r1.Reg
- p2.From.Type = obj.TYPE_CONST
- p2.From.Offset = 1
- p3 := gins(ppc64.ASRD, nil, &r1)
- p3.From.Type = obj.TYPE_CONST
- p3.From.Offset = 1
- gins(ppc64.AOR, &r3, &r1)
- gc.Regfree(&r3)
- gc.Patch(p1, gc.Pc)
- }
- gc.Regalloc(&r2, gc.Types[gc.TFLOAT64], t)
- p1 := gins(ppc64.AMOVD, &r1, nil)
- p1.To.Type = obj.TYPE_MEM
- p1.To.Reg = ppc64.REGSP
- p1.To.Offset = -8
- p1 = gins(ppc64.AFMOVD, nil, &r2)
- p1.From.Type = obj.TYPE_MEM
- p1.From.Reg = ppc64.REGSP
- p1.From.Offset = -8
- gins(ppc64.AFCFID, &r2, &r2)
- gc.Regfree(&r1)
- if ft == gc.TUINT64 {
- p1 := gc.Gbranch(optoas(gc.OLT, gc.Types[gc.TUINT64]), nil, +1) // use CR0 here again
- gc.Nodreg(&r1, gc.Types[gc.TFLOAT64], ppc64.FREGTWO)
- gins(ppc64.AFMUL, &r1, &r2)
- gc.Patch(p1, gc.Pc)
- }
- gmove(&r2, t)
- gc.Regfree(&r2)
- return
-
- /*
- * float to float
- */
- case gc.TFLOAT32<<16 | gc.TFLOAT32:
- a = ppc64.AFMOVS
-
- case gc.TFLOAT64<<16 | gc.TFLOAT64:
- a = ppc64.AFMOVD
-
- case gc.TFLOAT32<<16 | gc.TFLOAT64:
- a = ppc64.AFMOVS
- goto rdst
-
- case gc.TFLOAT64<<16 | gc.TFLOAT32:
- a = ppc64.AFRSP
- goto rdst
- }
-
- gins(a, f, t)
- return
-
- // requires register destination
-rdst:
- {
- gc.Regalloc(&r1, t.Type, t)
-
- gins(a, f, &r1)
- gmove(&r1, t)
- gc.Regfree(&r1)
- return
- }
-
- // requires register intermediate
-hard:
- gc.Regalloc(&r1, cvt, t)
-
- gmove(f, &r1)
- gmove(&r1, t)
- gc.Regfree(&r1)
- return
-}
-
-// gins is called by the front end.
-// It synthesizes some multiple-instruction sequences
-// so the front end can stay simpler.
-func gins(as obj.As, f, t *gc.Node) *obj.Prog {
- if as >= obj.A_ARCHSPECIFIC {
- if x, ok := f.IntLiteral(); ok {
- ginscon(as, x, t)
- return nil // caller must not use
- }
- }
- if as == ppc64.ACMP || as == ppc64.ACMPU {
- if x, ok := t.IntLiteral(); ok {
- ginscon2(as, f, x)
- return nil // caller must not use
- }
- }
- return rawgins(as, f, t)
-}
-
-/*
- * generate one instruction:
- * as f, t
- */
-func rawgins(as obj.As, f *gc.Node, t *gc.Node) *obj.Prog {
- // TODO(austin): Add self-move test like in 6g (but be careful
- // of truncation moves)
-
- p := gc.Prog(as)
- gc.Naddr(&p.From, f)
- gc.Naddr(&p.To, t)
-
- switch as {
- case obj.ACALL:
- if p.To.Type == obj.TYPE_REG && p.To.Reg != ppc64.REG_CTR {
- // Allow front end to emit CALL REG, and rewrite into MOV REG, CTR; CALL CTR.
- if gc.Ctxt.Flag_shared {
- // Make sure function pointer is in R12 as well when
- // compiling Go into PIC.
- // TODO(mwhudson): it would obviously be better to
- // change the register allocation to put the value in
- // R12 already, but I don't know how to do that.
- q := gc.Prog(as)
- q.As = ppc64.AMOVD
- q.From = p.To
- q.To.Type = obj.TYPE_REG
- q.To.Reg = ppc64.REG_R12
- }
- pp := gc.Prog(as)
- pp.From = p.From
- pp.To.Type = obj.TYPE_REG
- pp.To.Reg = ppc64.REG_CTR
-
- p.As = ppc64.AMOVD
- p.From = p.To
- p.To.Type = obj.TYPE_REG
- p.To.Reg = ppc64.REG_CTR
-
- if gc.Ctxt.Flag_shared {
- // When compiling Go into PIC, the function we just
- // called via pointer might have been implemented in
- // a separate module and so overwritten the TOC
- // pointer in R2; reload it.
- q := gc.Prog(ppc64.AMOVD)
- q.From.Type = obj.TYPE_MEM
- q.From.Offset = 24
- q.From.Reg = ppc64.REGSP
- q.To.Type = obj.TYPE_REG
- q.To.Reg = ppc64.REG_R2
- }
-
- if gc.Debug['g'] != 0 {
- fmt.Printf("%v\n", p)
- fmt.Printf("%v\n", pp)
- }
-
- return pp
- }
-
- // Bad things the front end has done to us. Crash to find call stack.
- case ppc64.AAND, ppc64.AMULLD:
- if p.From.Type == obj.TYPE_CONST {
- gc.Debug['h'] = 1
- gc.Fatalf("bad inst: %v", p)
- }
- case ppc64.ACMP, ppc64.ACMPU:
- if p.From.Type == obj.TYPE_MEM || p.To.Type == obj.TYPE_MEM {
- gc.Debug['h'] = 1
- gc.Fatalf("bad inst: %v", p)
- }
- }
-
- if gc.Debug['g'] != 0 {
- fmt.Printf("%v\n", p)
- }
-
- w := int32(0)
- switch as {
- case ppc64.AMOVB,
- ppc64.AMOVBU,
- ppc64.AMOVBZ,
- ppc64.AMOVBZU:
- w = 1
-
- case ppc64.AMOVH,
- ppc64.AMOVHU,
- ppc64.AMOVHZ,
- ppc64.AMOVHZU:
- w = 2
-
- case ppc64.AMOVW,
- ppc64.AMOVWU,
- ppc64.AMOVWZ,
- ppc64.AMOVWZU:
- w = 4
-
- case ppc64.AMOVD,
- ppc64.AMOVDU:
- if p.From.Type == obj.TYPE_CONST || p.From.Type == obj.TYPE_ADDR {
- break
- }
- w = 8
- }
-
- if w != 0 && ((f != nil && p.From.Width < int64(w)) || (t != nil && p.To.Type != obj.TYPE_REG && p.To.Width > int64(w))) {
- gc.Dump("f", f)
- gc.Dump("t", t)
- gc.Fatalf("bad width: %v (%d, %d)\n", p, p.From.Width, p.To.Width)
- }
-
- return p
-}
-
-/*
- * return Axxx for Oxxx on type t.
- */
-func optoas(op gc.Op, t *gc.Type) obj.As {
- if t == nil {
- gc.Fatalf("optoas: t is nil")
- }
-
- // avoid constant conversions in switches below
- const (
- OMINUS_ = uint32(gc.OMINUS) << 16
- OLSH_ = uint32(gc.OLSH) << 16
- ORSH_ = uint32(gc.ORSH) << 16
- OADD_ = uint32(gc.OADD) << 16
- OSUB_ = uint32(gc.OSUB) << 16
- OMUL_ = uint32(gc.OMUL) << 16
- ODIV_ = uint32(gc.ODIV) << 16
- OOR_ = uint32(gc.OOR) << 16
- OAND_ = uint32(gc.OAND) << 16
- OXOR_ = uint32(gc.OXOR) << 16
- OEQ_ = uint32(gc.OEQ) << 16
- ONE_ = uint32(gc.ONE) << 16
- OLT_ = uint32(gc.OLT) << 16
- OLE_ = uint32(gc.OLE) << 16
- OGE_ = uint32(gc.OGE) << 16
- OGT_ = uint32(gc.OGT) << 16
- OCMP_ = uint32(gc.OCMP) << 16
- OAS_ = uint32(gc.OAS) << 16
- OHMUL_ = uint32(gc.OHMUL) << 16
- OSQRT_ = uint32(gc.OSQRT) << 16
- )
-
- a := obj.AXXX
- switch uint32(op)<<16 | uint32(gc.Simtype[t.Etype]) {
- default:
- gc.Fatalf("optoas: no entry for op=%v type=%v", op, t)
-
- case OEQ_ | gc.TBOOL,
- OEQ_ | gc.TINT8,
- OEQ_ | gc.TUINT8,
- OEQ_ | gc.TINT16,
- OEQ_ | gc.TUINT16,
- OEQ_ | gc.TINT32,
- OEQ_ | gc.TUINT32,
- OEQ_ | gc.TINT64,
- OEQ_ | gc.TUINT64,
- OEQ_ | gc.TPTR32,
- OEQ_ | gc.TPTR64,
- OEQ_ | gc.TFLOAT32,
- OEQ_ | gc.TFLOAT64:
- a = ppc64.ABEQ
-
- case ONE_ | gc.TBOOL,
- ONE_ | gc.TINT8,
- ONE_ | gc.TUINT8,
- ONE_ | gc.TINT16,
- ONE_ | gc.TUINT16,
- ONE_ | gc.TINT32,
- ONE_ | gc.TUINT32,
- ONE_ | gc.TINT64,
- ONE_ | gc.TUINT64,
- ONE_ | gc.TPTR32,
- ONE_ | gc.TPTR64,
- ONE_ | gc.TFLOAT32,
- ONE_ | gc.TFLOAT64:
- a = ppc64.ABNE
-
- case OLT_ | gc.TINT8, // ACMP
- OLT_ | gc.TINT16,
- OLT_ | gc.TINT32,
- OLT_ | gc.TINT64,
- OLT_ | gc.TUINT8,
- // ACMPU
- OLT_ | gc.TUINT16,
- OLT_ | gc.TUINT32,
- OLT_ | gc.TUINT64,
- OLT_ | gc.TFLOAT32,
- // AFCMPU
- OLT_ | gc.TFLOAT64:
- a = ppc64.ABLT
-
- case OLE_ | gc.TINT8, // ACMP
- OLE_ | gc.TINT16,
- OLE_ | gc.TINT32,
- OLE_ | gc.TINT64,
- OLE_ | gc.TUINT8,
- // ACMPU
- OLE_ | gc.TUINT16,
- OLE_ | gc.TUINT32,
- OLE_ | gc.TUINT64:
- // No OLE for floats, because it mishandles NaN.
- // Front end must reverse comparison or use OLT and OEQ together.
- a = ppc64.ABLE
-
- case OGT_ | gc.TINT8,
- OGT_ | gc.TINT16,
- OGT_ | gc.TINT32,
- OGT_ | gc.TINT64,
- OGT_ | gc.TUINT8,
- OGT_ | gc.TUINT16,
- OGT_ | gc.TUINT32,
- OGT_ | gc.TUINT64,
- OGT_ | gc.TFLOAT32,
- OGT_ | gc.TFLOAT64:
- a = ppc64.ABGT
-
- case OGE_ | gc.TINT8,
- OGE_ | gc.TINT16,
- OGE_ | gc.TINT32,
- OGE_ | gc.TINT64,
- OGE_ | gc.TUINT8,
- OGE_ | gc.TUINT16,
- OGE_ | gc.TUINT32,
- OGE_ | gc.TUINT64:
- // No OGE for floats, because it mishandles NaN.
- // Front end must reverse comparison or use OLT and OEQ together.
- a = ppc64.ABGE
-
- case OCMP_ | gc.TBOOL,
- OCMP_ | gc.TINT8,
- OCMP_ | gc.TINT16,
- OCMP_ | gc.TINT32,
- OCMP_ | gc.TPTR32,
- OCMP_ | gc.TINT64:
- a = ppc64.ACMP
-
- case OCMP_ | gc.TUINT8,
- OCMP_ | gc.TUINT16,
- OCMP_ | gc.TUINT32,
- OCMP_ | gc.TUINT64,
- OCMP_ | gc.TPTR64:
- a = ppc64.ACMPU
-
- case OCMP_ | gc.TFLOAT32,
- OCMP_ | gc.TFLOAT64:
- a = ppc64.AFCMPU
-
- case OAS_ | gc.TBOOL,
- OAS_ | gc.TINT8:
- a = ppc64.AMOVB
-
- case OAS_ | gc.TUINT8:
- a = ppc64.AMOVBZ
-
- case OAS_ | gc.TINT16:
- a = ppc64.AMOVH
-
- case OAS_ | gc.TUINT16:
- a = ppc64.AMOVHZ
-
- case OAS_ | gc.TINT32:
- a = ppc64.AMOVW
-
- case OAS_ | gc.TUINT32,
- OAS_ | gc.TPTR32:
- a = ppc64.AMOVWZ
-
- case OAS_ | gc.TINT64,
- OAS_ | gc.TUINT64,
- OAS_ | gc.TPTR64:
- a = ppc64.AMOVD
-
- case OAS_ | gc.TFLOAT32:
- a = ppc64.AFMOVS
-
- case OAS_ | gc.TFLOAT64:
- a = ppc64.AFMOVD
-
- case OADD_ | gc.TINT8,
- OADD_ | gc.TUINT8,
- OADD_ | gc.TINT16,
- OADD_ | gc.TUINT16,
- OADD_ | gc.TINT32,
- OADD_ | gc.TUINT32,
- OADD_ | gc.TPTR32,
- OADD_ | gc.TINT64,
- OADD_ | gc.TUINT64,
- OADD_ | gc.TPTR64:
- a = ppc64.AADD
-
- case OADD_ | gc.TFLOAT32:
- a = ppc64.AFADDS
-
- case OADD_ | gc.TFLOAT64:
- a = ppc64.AFADD
-
- case OSUB_ | gc.TINT8,
- OSUB_ | gc.TUINT8,
- OSUB_ | gc.TINT16,
- OSUB_ | gc.TUINT16,
- OSUB_ | gc.TINT32,
- OSUB_ | gc.TUINT32,
- OSUB_ | gc.TPTR32,
- OSUB_ | gc.TINT64,
- OSUB_ | gc.TUINT64,
- OSUB_ | gc.TPTR64:
- a = ppc64.ASUB
-
- case OSUB_ | gc.TFLOAT32:
- a = ppc64.AFSUBS
-
- case OSUB_ | gc.TFLOAT64:
- a = ppc64.AFSUB
-
- case OMINUS_ | gc.TINT8,
- OMINUS_ | gc.TUINT8,
- OMINUS_ | gc.TINT16,
- OMINUS_ | gc.TUINT16,
- OMINUS_ | gc.TINT32,
- OMINUS_ | gc.TUINT32,
- OMINUS_ | gc.TPTR32,
- OMINUS_ | gc.TINT64,
- OMINUS_ | gc.TUINT64,
- OMINUS_ | gc.TPTR64:
- a = ppc64.ANEG
-
- case OAND_ | gc.TINT8,
- OAND_ | gc.TUINT8,
- OAND_ | gc.TINT16,
- OAND_ | gc.TUINT16,
- OAND_ | gc.TINT32,
- OAND_ | gc.TUINT32,
- OAND_ | gc.TPTR32,
- OAND_ | gc.TINT64,
- OAND_ | gc.TUINT64,
- OAND_ | gc.TPTR64:
- a = ppc64.AAND
-
- case OOR_ | gc.TINT8,
- OOR_ | gc.TUINT8,
- OOR_ | gc.TINT16,
- OOR_ | gc.TUINT16,
- OOR_ | gc.TINT32,
- OOR_ | gc.TUINT32,
- OOR_ | gc.TPTR32,
- OOR_ | gc.TINT64,
- OOR_ | gc.TUINT64,
- OOR_ | gc.TPTR64:
- a = ppc64.AOR
-
- case OXOR_ | gc.TINT8,
- OXOR_ | gc.TUINT8,
- OXOR_ | gc.TINT16,
- OXOR_ | gc.TUINT16,
- OXOR_ | gc.TINT32,
- OXOR_ | gc.TUINT32,
- OXOR_ | gc.TPTR32,
- OXOR_ | gc.TINT64,
- OXOR_ | gc.TUINT64,
- OXOR_ | gc.TPTR64:
- a = ppc64.AXOR
-
- // TODO(minux): handle rotates
- //case CASE(OLROT, TINT8):
- //case CASE(OLROT, TUINT8):
- //case CASE(OLROT, TINT16):
- //case CASE(OLROT, TUINT16):
- //case CASE(OLROT, TINT32):
- //case CASE(OLROT, TUINT32):
- //case CASE(OLROT, TPTR32):
- //case CASE(OLROT, TINT64):
- //case CASE(OLROT, TUINT64):
- //case CASE(OLROT, TPTR64):
- // a = 0//???; RLDC?
- // break;
-
- case OLSH_ | gc.TINT8,
- OLSH_ | gc.TUINT8,
- OLSH_ | gc.TINT16,
- OLSH_ | gc.TUINT16,
- OLSH_ | gc.TINT32,
- OLSH_ | gc.TUINT32,
- OLSH_ | gc.TPTR32,
- OLSH_ | gc.TINT64,
- OLSH_ | gc.TUINT64,
- OLSH_ | gc.TPTR64:
- a = ppc64.ASLD
-
- case ORSH_ | gc.TUINT8,
- ORSH_ | gc.TUINT16,
- ORSH_ | gc.TUINT32,
- ORSH_ | gc.TPTR32,
- ORSH_ | gc.TUINT64,
- ORSH_ | gc.TPTR64:
- a = ppc64.ASRD
-
- case ORSH_ | gc.TINT8,
- ORSH_ | gc.TINT16,
- ORSH_ | gc.TINT32,
- ORSH_ | gc.TINT64:
- a = ppc64.ASRAD
-
- // TODO(minux): handle rotates
- //case CASE(ORROTC, TINT8):
- //case CASE(ORROTC, TUINT8):
- //case CASE(ORROTC, TINT16):
- //case CASE(ORROTC, TUINT16):
- //case CASE(ORROTC, TINT32):
- //case CASE(ORROTC, TUINT32):
- //case CASE(ORROTC, TINT64):
- //case CASE(ORROTC, TUINT64):
- // a = 0//??? RLDC??
- // break;
-
- case OHMUL_ | gc.TINT64:
- a = ppc64.AMULHD
-
- case OHMUL_ | gc.TUINT64,
- OHMUL_ | gc.TPTR64:
- a = ppc64.AMULHDU
-
- case OMUL_ | gc.TINT8,
- OMUL_ | gc.TINT16,
- OMUL_ | gc.TINT32,
- OMUL_ | gc.TINT64:
- a = ppc64.AMULLD
-
- case OMUL_ | gc.TUINT8,
- OMUL_ | gc.TUINT16,
- OMUL_ | gc.TUINT32,
- OMUL_ | gc.TPTR32,
- // don't use word multiply, the high 32-bit are undefined.
- OMUL_ | gc.TUINT64,
- OMUL_ | gc.TPTR64:
- // for 64-bit multiplies, signedness doesn't matter.
- a = ppc64.AMULLD
-
- case OMUL_ | gc.TFLOAT32:
- a = ppc64.AFMULS
-
- case OMUL_ | gc.TFLOAT64:
- a = ppc64.AFMUL
-
- case ODIV_ | gc.TINT8,
- ODIV_ | gc.TINT16,
- ODIV_ | gc.TINT32,
- ODIV_ | gc.TINT64:
- a = ppc64.ADIVD
-
- case ODIV_ | gc.TUINT8,
- ODIV_ | gc.TUINT16,
- ODIV_ | gc.TUINT32,
- ODIV_ | gc.TPTR32,
- ODIV_ | gc.TUINT64,
- ODIV_ | gc.TPTR64:
- a = ppc64.ADIVDU
-
- case ODIV_ | gc.TFLOAT32:
- a = ppc64.AFDIVS
-
- case ODIV_ | gc.TFLOAT64:
- a = ppc64.AFDIV
-
- case OSQRT_ | gc.TFLOAT64:
- a = ppc64.AFSQRT
- }
-
- return a
-}
-
-const (
- ODynam = 1 << 0
- OAddable = 1 << 1
-)
-
-func xgen(n *gc.Node, a *gc.Node, o int) bool {
- // TODO(minux)
-
- return -1 != 0 /*TypeKind(100016)*/
-}
-
-func sudoclean() {
- return
-}
-
-/*
- * generate code to compute address of n,
- * a reference to a (perhaps nested) field inside
- * an array or struct.
- * return 0 on failure, 1 on success.
- * on success, leaves usable address in a.
- *
- * caller is responsible for calling sudoclean
- * after successful sudoaddable,
- * to release the register used for a.
- */
-func sudoaddable(as obj.As, n *gc.Node, a *obj.Addr) bool {
- // TODO(minux)
-
- *a = obj.Addr{}
- return false
-}
diff --git a/src/cmd/compile/internal/ppc64/peep.go b/src/cmd/compile/internal/ppc64/peep.go
deleted file mode 100644
index 6efe0b7..0000000
--- a/src/cmd/compile/internal/ppc64/peep.go
+++ /dev/null
@@ -1,1032 +0,0 @@
-// Derived from Inferno utils/6c/peep.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6c/peep.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth at terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth at terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// Portions Copyright © 2009 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-package ppc64
-
-import (
- "cmd/compile/internal/gc"
- "cmd/internal/obj"
- "cmd/internal/obj/ppc64"
- "fmt"
-)
-
-var gactive uint32
-
-func peep(firstp *obj.Prog) {
- g := gc.Flowstart(firstp, nil)
- if g == nil {
- return
- }
- gactive = 0
-
- var p *obj.Prog
- var r *gc.Flow
- var t obj.As
-loop1:
- if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
- gc.Dumpit("loop1", g.Start, 0)
- }
-
- t = 0
- for r = g.Start; r != nil; r = r.Link {
- p = r.Prog
-
- // TODO(austin) Handle smaller moves. arm and amd64
- // distinguish between moves that moves that *must*
- // sign/zero extend and moves that don't care so they
- // can eliminate moves that don't care without
- // breaking moves that do care. This might let us
- // simplify or remove the next peep loop, too.
- if p.As == ppc64.AMOVD || p.As == ppc64.AFMOVD {
- if regtyp(&p.To) {
- // Try to eliminate reg->reg moves
- if regtyp(&p.From) {
- if p.From.Type == p.To.Type {
- if copyprop(r) {
- excise(r)
- t++
- } else if subprop(r) && copyprop(r) {
- excise(r)
- t++
- }
- }
- }
-
- // Convert uses to $0 to uses of R0 and
- // propagate R0
- if regzer(&p.From) {
- if p.To.Type == obj.TYPE_REG {
- p.From.Type = obj.TYPE_REG
- p.From.Reg = ppc64.REGZERO
- if copyprop(r) {
- excise(r)
- t++
- } else if subprop(r) && copyprop(r) {
- excise(r)
- t++
- }
- }
- }
- }
- }
- }
-
- if t != 0 {
- goto loop1
- }
-
- /*
- * look for MOVB x,R; MOVB R,R (for small MOVs not handled above)
- */
- var p1 *obj.Prog
- var r1 *gc.Flow
- for r := g.Start; r != nil; r = r.Link {
- p = r.Prog
- switch p.As {
- default:
- continue
-
- case ppc64.AMOVH,
- ppc64.AMOVHZ,
- ppc64.AMOVB,
- ppc64.AMOVBZ,
- ppc64.AMOVW,
- ppc64.AMOVWZ:
- if p.To.Type != obj.TYPE_REG {
- continue
- }
- }
-
- r1 = r.Link
- if r1 == nil {
- continue
- }
- p1 = r1.Prog
- if p1.As != p.As {
- continue
- }
- if p1.From.Type != obj.TYPE_REG || p1.From.Reg != p.To.Reg {
- continue
- }
- if p1.To.Type != obj.TYPE_REG || p1.To.Reg != p.To.Reg {
- continue
- }
- excise(r1)
- }
-
- if gc.Debug['D'] > 1 {
- goto ret /* allow following code improvement to be suppressed */
- }
-
- /*
- * look for OP x,y,R; CMP R, $0 -> OPCC x,y,R
- * when OP can set condition codes correctly
- */
- for r := g.Start; r != nil; r = r.Link {
- p = r.Prog
- switch p.As {
- case ppc64.ACMP,
- ppc64.ACMPW: /* always safe? */
- if !regzer(&p.To) {
- continue
- }
- r1 = r.S1
- if r1 == nil {
- continue
- }
- switch r1.Prog.As {
- default:
- continue
-
- /* the conditions can be complex and these are currently little used */
- case ppc64.ABCL,
- ppc64.ABC:
- continue
-
- case ppc64.ABEQ,
- ppc64.ABGE,
- ppc64.ABGT,
- ppc64.ABLE,
- ppc64.ABLT,
- ppc64.ABNE,
- ppc64.ABVC,
- ppc64.ABVS:
- break
- }
-
- r1 = r
- for {
- r1 = gc.Uniqp(r1)
- if r1 == nil || r1.Prog.As != obj.ANOP {
- break
- }
- }
-
- if r1 == nil {
- continue
- }
- p1 = r1.Prog
- if p1.To.Type != obj.TYPE_REG || p1.To.Reg != p.From.Reg {
- continue
- }
- switch p1.As {
- /* irregular instructions */
- case ppc64.ASUB,
- ppc64.AADD,
- ppc64.AXOR,
- ppc64.AOR:
- if p1.From.Type == obj.TYPE_CONST || p1.From.Type == obj.TYPE_ADDR {
- continue
- }
- }
-
- switch p1.As {
- default:
- continue
-
- case ppc64.AMOVW,
- ppc64.AMOVD:
- if p1.From.Type != obj.TYPE_REG {
- continue
- }
- continue
-
- case ppc64.AANDCC,
- ppc64.AANDNCC,
- ppc64.AORCC,
- ppc64.AORNCC,
- ppc64.AXORCC,
- ppc64.ASUBCC,
- ppc64.ASUBECC,
- ppc64.ASUBMECC,
- ppc64.ASUBZECC,
- ppc64.AADDCC,
- ppc64.AADDCCC,
- ppc64.AADDECC,
- ppc64.AADDMECC,
- ppc64.AADDZECC,
- ppc64.ARLWMICC,
- ppc64.ARLWNMCC,
- /* don't deal with floating point instructions for now */
- /*
- case AFABS:
- case AFADD:
- case AFADDS:
- case AFCTIW:
- case AFCTIWZ:
- case AFDIV:
- case AFDIVS:
- case AFMADD:
- case AFMADDS:
- case AFMOVD:
- case AFMSUB:
- case AFMSUBS:
- case AFMUL:
- case AFMULS:
- case AFNABS:
- case AFNEG:
- case AFNMADD:
- case AFNMADDS:
- case AFNMSUB:
- case AFNMSUBS:
- case AFRSP:
- case AFSUB:
- case AFSUBS:
- case ACNTLZW:
- case AMTFSB0:
- case AMTFSB1:
- */
- ppc64.AADD,
- ppc64.AADDV,
- ppc64.AADDC,
- ppc64.AADDCV,
- ppc64.AADDME,
- ppc64.AADDMEV,
- ppc64.AADDE,
- ppc64.AADDEV,
- ppc64.AADDZE,
- ppc64.AADDZEV,
- ppc64.AAND,
- ppc64.AANDN,
- ppc64.ADIVW,
- ppc64.ADIVWV,
- ppc64.ADIVWU,
- ppc64.ADIVWUV,
- ppc64.ADIVD,
- ppc64.ADIVDV,
- ppc64.ADIVDU,
- ppc64.ADIVDUV,
- ppc64.AEQV,
- ppc64.AEXTSB,
- ppc64.AEXTSH,
- ppc64.AEXTSW,
- ppc64.AMULHW,
- ppc64.AMULHWU,
- ppc64.AMULLW,
- ppc64.AMULLWV,
- ppc64.AMULHD,
- ppc64.AMULHDU,
- ppc64.AMULLD,
- ppc64.AMULLDV,
- ppc64.ANAND,
- ppc64.ANEG,
- ppc64.ANEGV,
- ppc64.ANOR,
- ppc64.AOR,
- ppc64.AORN,
- ppc64.AREM,
- ppc64.AREMV,
- ppc64.AREMU,
- ppc64.AREMUV,
- ppc64.AREMD,
- ppc64.AREMDV,
- ppc64.AREMDU,
- ppc64.AREMDUV,
- ppc64.ARLWMI,
- ppc64.ARLWNM,
- ppc64.ASLW,
- ppc64.ASRAW,
- ppc64.ASRW,
- ppc64.ASLD,
- ppc64.ASRAD,
- ppc64.ASRD,
- ppc64.ASUB,
- ppc64.ASUBV,
- ppc64.ASUBC,
- ppc64.ASUBCV,
- ppc64.ASUBME,
- ppc64.ASUBMEV,
- ppc64.ASUBE,
- ppc64.ASUBEV,
- ppc64.ASUBZE,
- ppc64.ASUBZEV,
- ppc64.AXOR:
- t = variant2as(p1.As, as2variant(p1.As)|V_CC)
- }
-
- if gc.Debug['D'] != 0 {
- fmt.Printf("cmp %v; %v -> ", p1, p)
- }
- p1.As = t
- if gc.Debug['D'] != 0 {
- fmt.Printf("%v\n", p1)
- }
- excise(r)
- continue
- }
- }
-
-ret:
- gc.Flowend(g)
-}
-
-func excise(r *gc.Flow) {
- p := r.Prog
- if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
- fmt.Printf("%v ===delete===\n", p)
- }
- obj.Nopout(p)
- gc.Ostats.Ndelmov++
-}
-
-// regzer returns true if a's value is 0 (a is R0 or $0)
-func regzer(a *obj.Addr) bool {
- if a.Type == obj.TYPE_CONST || a.Type == obj.TYPE_ADDR {
- if a.Sym == nil && a.Reg == 0 {
- if a.Offset == 0 {
- return true
- }
- }
- }
- return a.Type == obj.TYPE_REG && a.Reg == ppc64.REGZERO
-}
-
-func regtyp(a *obj.Addr) bool {
- // TODO(rsc): Floating point register exclusions?
- return a.Type == obj.TYPE_REG && ppc64.REG_R0 <= a.Reg && a.Reg <= ppc64.REG_F31 && a.Reg != ppc64.REGZERO
-}
-
-/*
- * the idea is to substitute
- * one register for another
- * from one MOV to another
- * MOV a, R1
- * ADD b, R1 / no use of R2
- * MOV R1, R2
- * would be converted to
- * MOV a, R2
- * ADD b, R2
- * MOV R2, R1
- * hopefully, then the former or latter MOV
- * will be eliminated by copy propagation.
- *
- * r0 (the argument, not the register) is the MOV at the end of the
- * above sequences. This returns 1 if it modified any instructions.
- */
-func subprop(r0 *gc.Flow) bool {
- p := r0.Prog
- v1 := &p.From
- if !regtyp(v1) {
- return false
- }
- v2 := &p.To
- if !regtyp(v2) {
- return false
- }
- for r := gc.Uniqp(r0); r != nil; r = gc.Uniqp(r) {
- if gc.Uniqs(r) == nil {
- break
- }
- p = r.Prog
- if p.As == obj.AVARDEF || p.As == obj.AVARKILL {
- continue
- }
- if p.Info.Flags&gc.Call != 0 {
- return false
- }
-
- if p.Info.Flags&(gc.RightRead|gc.RightWrite) == gc.RightWrite {
- if p.To.Type == v1.Type {
- if p.To.Reg == v1.Reg {
- copysub(&p.To, v1, v2, true)
- if gc.Debug['P'] != 0 {
- fmt.Printf("gotit: %v->%v\n%v", gc.Ctxt.Dconv(v1), gc.Ctxt.Dconv(v2), r.Prog)
- if p.From.Type == v2.Type {
- fmt.Printf(" excise")
- }
- fmt.Printf("\n")
- }
-
- for r = gc.Uniqs(r); r != r0; r = gc.Uniqs(r) {
- p = r.Prog
- copysub(&p.From, v1, v2, true)
- copysub1(p, v1, v2, true)
- copysub(&p.To, v1, v2, true)
- if gc.Debug['P'] != 0 {
- fmt.Printf("%v\n", r.Prog)
- }
- }
-
- v1.Reg, v2.Reg = v2.Reg, v1.Reg
- if gc.Debug['P'] != 0 {
- fmt.Printf("%v last\n", r.Prog)
- }
- return true
- }
- }
- }
-
- if copyau(&p.From, v2) || copyau1(p, v2) || copyau(&p.To, v2) {
- break
- }
- if copysub(&p.From, v1, v2, false) || copysub1(p, v1, v2, false) || copysub(&p.To, v1, v2, false) {
- break
- }
- }
-
- return false
-}
-
-/*
- * The idea is to remove redundant copies.
- * v1->v2 F=0
- * (use v2 s/v2/v1/)*
- * set v1 F=1
- * use v2 return fail (v1->v2 move must remain)
- * -----------------
- * v1->v2 F=0
- * (use v2 s/v2/v1/)*
- * set v1 F=1
- * set v2 return success (caller can remove v1->v2 move)
- */
-func copyprop(r0 *gc.Flow) bool {
- p := r0.Prog
- v1 := &p.From
- v2 := &p.To
- if copyas(v1, v2) {
- if gc.Debug['P'] != 0 {
- fmt.Printf("eliminating self-move: %v\n", r0.Prog)
- }
- return true
- }
-
- gactive++
- if gc.Debug['P'] != 0 {
- fmt.Printf("trying to eliminate %v->%v move from:\n%v\n", gc.Ctxt.Dconv(v1), gc.Ctxt.Dconv(v2), r0.Prog)
- }
- return copy1(v1, v2, r0.S1, false)
-}
-
-// copy1 replaces uses of v2 with v1 starting at r and returns 1 if
-// all uses were rewritten.
-func copy1(v1 *obj.Addr, v2 *obj.Addr, r *gc.Flow, f bool) bool {
- if uint32(r.Active) == gactive {
- if gc.Debug['P'] != 0 {
- fmt.Printf("act set; return 1\n")
- }
- return true
- }
-
- r.Active = int32(gactive)
- if gc.Debug['P'] != 0 {
- fmt.Printf("copy1 replace %v with %v f=%v\n", gc.Ctxt.Dconv(v2), gc.Ctxt.Dconv(v1), f)
- }
- for ; r != nil; r = r.S1 {
- p := r.Prog
- if gc.Debug['P'] != 0 {
- fmt.Printf("%v", p)
- }
- if !f && gc.Uniqp(r) == nil {
- // Multiple predecessors; conservatively
- // assume v1 was set on other path
- f = true
-
- if gc.Debug['P'] != 0 {
- fmt.Printf("; merge; f=%v", f)
- }
- }
-
- switch t := copyu(p, v2, nil); t {
- case 2: /* rar, can't split */
- if gc.Debug['P'] != 0 {
- fmt.Printf("; %v rar; return 0\n", gc.Ctxt.Dconv(v2))
- }
- return false
-
- case 3: /* set */
- if gc.Debug['P'] != 0 {
- fmt.Printf("; %v set; return 1\n", gc.Ctxt.Dconv(v2))
- }
- return true
-
- case 1, /* used, substitute */
- 4: /* use and set */
- if f {
- if gc.Debug['P'] == 0 {
- return false
- }
- if t == 4 {
- fmt.Printf("; %v used+set and f=%v; return 0\n", gc.Ctxt.Dconv(v2), f)
- } else {
- fmt.Printf("; %v used and f=%v; return 0\n", gc.Ctxt.Dconv(v2), f)
- }
- return false
- }
-
- if copyu(p, v2, v1) != 0 {
- if gc.Debug['P'] != 0 {
- fmt.Printf("; sub fail; return 0\n")
- }
- return false
- }
-
- if gc.Debug['P'] != 0 {
- fmt.Printf("; sub %v->%v\n => %v", gc.Ctxt.Dconv(v2), gc.Ctxt.Dconv(v1), p)
- }
- if t == 4 {
- if gc.Debug['P'] != 0 {
- fmt.Printf("; %v used+set; return 1\n", gc.Ctxt.Dconv(v2))
- }
- return true
- }
- }
-
- if !f {
- t := copyu(p, v1, nil)
- if t == 2 || t == 3 || t == 4 {
- f = true
- if gc.Debug['P'] != 0 {
- fmt.Printf("; %v set and !f; f=%v", gc.Ctxt.Dconv(v1), f)
- }
- }
- }
-
- if gc.Debug['P'] != 0 {
- fmt.Printf("\n")
- }
- if r.S2 != nil {
- if !copy1(v1, v2, r.S2, f) {
- return false
- }
- }
- }
-
- return true
-}
-
-// If s==nil, copyu returns the set/use of v in p; otherwise, it
-// modifies p to replace reads of v with reads of s and returns 0 for
-// success or non-zero for failure.
-//
-// If s==nil, copy returns one of the following values:
-// 1 if v only used
-// 2 if v is set and used in one address (read-alter-rewrite;
-// can't substitute)
-// 3 if v is only set
-// 4 if v is set in one address and used in another (so addresses
-// can be rewritten independently)
-// 0 otherwise (not touched)
-func copyu(p *obj.Prog, v *obj.Addr, s *obj.Addr) int {
- if p.From3Type() != obj.TYPE_NONE {
- // 9g never generates a from3
- fmt.Printf("copyu: from3 (%v) not implemented\n", gc.Ctxt.Dconv(p.From3))
- }
-
- switch p.As {
- default:
- fmt.Printf("copyu: can't find %v\n", obj.Aconv(p.As))
- return 2
-
- case obj.ANOP, /* read p->from, write p->to */
- ppc64.AMOVH,
- ppc64.AMOVHZ,
- ppc64.AMOVB,
- ppc64.AMOVBZ,
- ppc64.AMOVW,
- ppc64.AMOVWZ,
- ppc64.AMOVD,
- ppc64.ANEG,
- ppc64.ANEGCC,
- ppc64.AADDME,
- ppc64.AADDMECC,
- ppc64.AADDZE,
- ppc64.AADDZECC,
- ppc64.ASUBME,
- ppc64.ASUBMECC,
- ppc64.ASUBZE,
- ppc64.ASUBZECC,
- ppc64.AFCTIW,
- ppc64.AFCTIWZ,
- ppc64.AFCTID,
- ppc64.AFCTIDZ,
- ppc64.AFCFID,
- ppc64.AFCFIDCC,
- ppc64.AFCFIDU,
- ppc64.AFCFIDUCC,
- ppc64.AFMOVS,
- ppc64.AFMOVD,
- ppc64.AFRSP,
- ppc64.AFNEG,
- ppc64.AFNEGCC,
- ppc64.AFSQRT:
- if s != nil {
- if copysub(&p.From, v, s, true) {
- return 1
- }
-
- // Update only indirect uses of v in p->to
- if !copyas(&p.To, v) {
- if copysub(&p.To, v, s, true) {
- return 1
- }
- }
- return 0
- }
-
- if copyas(&p.To, v) {
- // Fix up implicit from
- if p.From.Type == obj.TYPE_NONE {
- p.From = p.To
- }
- if copyau(&p.From, v) {
- return 4
- }
- return 3
- }
-
- if copyau(&p.From, v) {
- return 1
- }
- if copyau(&p.To, v) {
- // p->to only indirectly uses v
- return 1
- }
-
- return 0
-
- case ppc64.AMOVBU, /* rar p->from, write p->to or read p->from, rar p->to */
- ppc64.AMOVBZU,
- ppc64.AMOVHU,
- ppc64.AMOVHZU,
- ppc64.AMOVWZU,
- ppc64.AMOVDU:
- if p.From.Type == obj.TYPE_MEM {
- if copyas(&p.From, v) {
- // No s!=nil check; need to fail
- // anyway in that case
- return 2
- }
-
- if s != nil {
- if copysub(&p.To, v, s, true) {
- return 1
- }
- return 0
- }
-
- if copyas(&p.To, v) {
- return 3
- }
- } else if p.To.Type == obj.TYPE_MEM {
- if copyas(&p.To, v) {
- return 2
- }
- if s != nil {
- if copysub(&p.From, v, s, true) {
- return 1
- }
- return 0
- }
-
- if copyau(&p.From, v) {
- return 1
- }
- } else {
- fmt.Printf("copyu: bad %v\n", p)
- }
-
- return 0
-
- case ppc64.ARLWMI, /* read p->from, read p->reg, rar p->to */
- ppc64.ARLWMICC:
- if copyas(&p.To, v) {
- return 2
- }
- fallthrough
-
- /* fall through */
- case ppc64.AADD,
- /* read p->from, read p->reg, write p->to */
- ppc64.AADDC,
- ppc64.AADDE,
- ppc64.ASUB,
- ppc64.ASLW,
- ppc64.ASRW,
- ppc64.ASRAW,
- ppc64.ASLD,
- ppc64.ASRD,
- ppc64.ASRAD,
- ppc64.AOR,
- ppc64.AORCC,
- ppc64.AORN,
- ppc64.AORNCC,
- ppc64.AAND,
- ppc64.AANDCC,
- ppc64.AANDN,
- ppc64.AANDNCC,
- ppc64.ANAND,
- ppc64.ANANDCC,
- ppc64.ANOR,
- ppc64.ANORCC,
- ppc64.AXOR,
- ppc64.AMULHW,
- ppc64.AMULHWU,
- ppc64.AMULLW,
- ppc64.AMULLD,
- ppc64.ADIVW,
- ppc64.ADIVD,
- ppc64.ADIVWU,
- ppc64.ADIVDU,
- ppc64.AREM,
- ppc64.AREMU,
- ppc64.AREMD,
- ppc64.AREMDU,
- ppc64.ARLWNM,
- ppc64.ARLWNMCC,
- ppc64.AFADDS,
- ppc64.AFADD,
- ppc64.AFSUBS,
- ppc64.AFSUB,
- ppc64.AFMULS,
- ppc64.AFMUL,
- ppc64.AFDIVS,
- ppc64.AFDIV:
- if s != nil {
- if copysub(&p.From, v, s, true) {
- return 1
- }
- if copysub1(p, v, s, true) {
- return 1
- }
-
- // Update only indirect uses of v in p->to
- if !copyas(&p.To, v) {
- if copysub(&p.To, v, s, true) {
- return 1
- }
- }
- return 0
- }
-
- if copyas(&p.To, v) {
- if p.Reg == 0 {
- // Fix up implicit reg (e.g., ADD
- // R3,R4 -> ADD R3,R4,R4) so we can
- // update reg and to separately.
- p.Reg = p.To.Reg
- }
-
- if copyau(&p.From, v) {
- return 4
- }
- if copyau1(p, v) {
- return 4
- }
- return 3
- }
-
- if copyau(&p.From, v) {
- return 1
- }
- if copyau1(p, v) {
- return 1
- }
- if copyau(&p.To, v) {
- return 1
- }
- return 0
-
- case ppc64.ABEQ,
- ppc64.ABGT,
- ppc64.ABGE,
- ppc64.ABLT,
- ppc64.ABLE,
- ppc64.ABNE,
- ppc64.ABVC,
- ppc64.ABVS:
- return 0
-
- case obj.ACHECKNIL, /* read p->from */
- ppc64.ACMP, /* read p->from, read p->to */
- ppc64.ACMPU,
- ppc64.ACMPW,
- ppc64.ACMPWU,
- ppc64.AFCMPO,
- ppc64.AFCMPU:
- if s != nil {
- if copysub(&p.From, v, s, true) {
- return 1
- }
- if copysub(&p.To, v, s, true) {
- return 1
- }
- return 0
- }
-
- if copyau(&p.From, v) {
- return 1
- }
- if copyau(&p.To, v) {
- return 1
- }
- return 0
-
- // 9g never generates a branch to a GPR (this isn't
- // even a normal instruction; liblink turns it in to a
- // mov and a branch).
- case ppc64.ABR: /* read p->to */
- if s != nil {
- if copysub(&p.To, v, s, true) {
- return 1
- }
- return 0
- }
-
- if copyau(&p.To, v) {
- return 1
- }
- return 0
-
- case obj.ARET: /* funny */
- if s != nil {
- return 0
- }
-
- // All registers die at this point, so claim
- // everything is set (and not used).
- return 3
-
- case ppc64.ABL: /* funny */
- if v.Type == obj.TYPE_REG {
- // TODO(rsc): REG_R0 and REG_F0 used to be
- // (when register numbers started at 0) exregoffset and exfregoffset,
- // which are unset entirely.
- // It's strange that this handles R0 and F0 differently from the other
- // registers. Possible failure to optimize?
- if ppc64.REG_R0 < v.Reg && v.Reg <= ppc64.REGEXT {
- return 2
- }
- if v.Reg == ppc64.REGARG {
- return 2
- }
- if ppc64.REG_F0 < v.Reg && v.Reg <= ppc64.FREGEXT {
- return 2
- }
- }
-
- if p.From.Type == obj.TYPE_REG && v.Type == obj.TYPE_REG && p.From.Reg == v.Reg {
- return 2
- }
-
- if s != nil {
- if copysub(&p.To, v, s, true) {
- return 1
- }
- return 0
- }
- if copyau(&p.To, v) {
- return 4
- }
- return 3
-
- // R0 is zero, used by DUFFZERO, cannot be substituted.
- // R3 is ptr to memory, used and set, cannot be substituted.
- case obj.ADUFFZERO:
- if v.Type == obj.TYPE_REG {
- if v.Reg == 0 {
- return 1
- }
- if v.Reg == 3 {
- return 2
- }
- }
-
- return 0
-
- // R3, R4 are ptr to src, dst, used and set, cannot be substituted.
- // R5 is scratch, set by DUFFCOPY, cannot be substituted.
- case obj.ADUFFCOPY:
- if v.Type == obj.TYPE_REG {
- if v.Reg == 3 || v.Reg == 4 {
- return 2
- }
- if v.Reg == 5 {
- return 3
- }
- }
-
- return 0
-
- case obj.ATEXT: /* funny */
- if v.Type == obj.TYPE_REG {
- if v.Reg == ppc64.REGARG {
- return 3
- }
- }
- return 0
-
- case obj.APCDATA,
- obj.AFUNCDATA,
- obj.AVARDEF,
- obj.AVARKILL,
- obj.AVARLIVE,
- obj.AUSEFIELD:
- return 0
- }
-}
-
-// copyas returns true if a and v address the same register.
-//
-// If a is the from operand, this means this operation reads the
-// register in v. If a is the to operand, this means this operation
-// writes the register in v.
-func copyas(a *obj.Addr, v *obj.Addr) bool {
- return regtyp(v) && a.Type == v.Type && a.Reg == v.Reg
-}
-
-// copyau returns true if a either directly or indirectly addresses the
-// same register as v.
-//
-// If a is the from operand, this means this operation reads the
-// register in v. If a is the to operand, this means the operation
-// either reads or writes the register in v (if !copyas(a, v), then
-// the operation reads the register in v).
-func copyau(a *obj.Addr, v *obj.Addr) bool {
- if copyas(a, v) {
- return true
- }
- if v.Type == obj.TYPE_REG {
- if a.Type == obj.TYPE_MEM || (a.Type == obj.TYPE_ADDR && a.Reg != 0) {
- if v.Reg == a.Reg {
- return true
- }
- }
- }
- return false
-}
-
-// copyau1 returns true if p->reg references the same register as v and v
-// is a direct reference.
-func copyau1(p *obj.Prog, v *obj.Addr) bool {
- return regtyp(v) && v.Reg != 0 && p.Reg == v.Reg
-}
-
-// copysub replaces v with s in a if f==true or indicates it if could if f==false.
-// Returns true on failure to substitute (it always succeeds on ppc64).
-// TODO(dfc) remove unused return value and callers where f=false.
-func copysub(a *obj.Addr, v *obj.Addr, s *obj.Addr, f bool) bool {
- if f && copyau(a, v) {
- a.Reg = s.Reg
- }
- return false
-}
-
-// copysub1 replaces v with s in p1->reg if f==true or indicates if it could if f==false.
-// Returns true on failure to substitute (it always succeeds on ppc64).
-// TODO(dfc) remove unused return value and callers where f=false.
-func copysub1(p1 *obj.Prog, v *obj.Addr, s *obj.Addr, f bool) bool {
- if f && copyau1(p1, v) {
- p1.Reg = s.Reg
- }
- return false
-}
-
-func sameaddr(a *obj.Addr, v *obj.Addr) bool {
- if a.Type != v.Type {
- return false
- }
- if regtyp(v) && a.Reg == v.Reg {
- return true
- }
- if v.Type == obj.NAME_AUTO || v.Type == obj.NAME_PARAM {
- if v.Offset == a.Offset {
- return true
- }
- }
- return false
-}
-
-func smallindir(a *obj.Addr, reg *obj.Addr) bool {
- return reg.Type == obj.TYPE_REG && a.Type == obj.TYPE_MEM && a.Reg == reg.Reg && 0 <= a.Offset && a.Offset < 4096
-}
-
-func stackaddr(a *obj.Addr) bool {
- return a.Type == obj.TYPE_REG && a.Reg == ppc64.REGSP
-}
diff --git a/src/cmd/compile/internal/ppc64/prog.go b/src/cmd/compile/internal/ppc64/prog.go
index e2d81ae..59cbaa1 100644
--- a/src/cmd/compile/internal/ppc64/prog.go
+++ b/src/cmd/compile/internal/ppc64/prog.go
@@ -24,14 +24,13 @@ const (
// size variants of an operation even if we just use a subset.
//
// The table is formatted for 8-space tabs.
-var progtable = [ppc64.ALAST & obj.AMask]obj.ProgInfo{
+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.ACHECKNIL: {Flags: gc.LeftRead},
obj.AVARDEF: {Flags: gc.Pseudo | gc.RightWrite},
obj.AVARKILL: {Flags: gc.Pseudo | gc.RightWrite},
obj.AVARLIVE: {Flags: gc.Pseudo | gc.LeftRead},
@@ -42,22 +41,36 @@ var progtable = [ppc64.ALAST & obj.AMask]obj.ProgInfo{
// 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.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
- ppc64.AMULHDU & 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.
@@ -70,11 +83,13 @@ var progtable = [ppc64.ALAST & obj.AMask]obj.ProgInfo{
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},
@@ -85,17 +100,23 @@ var progtable = [ppc64.ALAST & obj.AMask]obj.ProgInfo{
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},
@@ -127,9 +148,8 @@ func initproginfo() {
}
}
-func proginfo(p *obj.Prog) {
- info := &p.Info
- *info = progtable[p.As&obj.AMask]
+func proginfo(p *obj.Prog) gc.ProgInfo {
+ info := progtable[p.As&obj.AMask]
if info.Flags == 0 {
gc.Fatalf("proginfo: unknown instruction %v", p)
}
@@ -139,36 +159,12 @@ func proginfo(p *obj.Prog) {
info.Flags |= gc.RightRead /*CanRegRead |*/
}
- if (p.From.Type == obj.TYPE_MEM || p.From.Type == obj.TYPE_ADDR) && p.From.Reg != 0 {
- info.Regindex |= RtoB(int(p.From.Reg))
- if info.Flags&gc.PostInc != 0 {
- info.Regset |= RtoB(int(p.From.Reg))
- }
- }
-
- if (p.To.Type == obj.TYPE_MEM || p.To.Type == obj.TYPE_ADDR) && p.To.Reg != 0 {
- info.Regindex |= RtoB(int(p.To.Reg))
- if info.Flags&gc.PostInc != 0 {
- info.Regset |= RtoB(int(p.To.Reg))
- }
- }
-
if p.From.Type == obj.TYPE_ADDR && p.From.Sym != nil && (info.Flags&gc.LeftRead != 0) {
info.Flags &^= gc.LeftRead
info.Flags |= gc.LeftAddr
}
- if p.As == obj.ADUFFZERO {
- info.Reguse |= 1<<0 | RtoB(ppc64.REG_R3)
- info.Regset |= RtoB(ppc64.REG_R3)
- }
-
- if p.As == obj.ADUFFCOPY {
- // TODO(austin) Revisit when duffcopy is implemented
- info.Reguse |= RtoB(ppc64.REG_R3) | RtoB(ppc64.REG_R4) | RtoB(ppc64.REG_R5)
-
- info.Regset |= RtoB(ppc64.REG_R3) | RtoB(ppc64.REG_R4)
- }
+ return info
}
// Instruction variants table, populated by initvariants via Main.
@@ -297,7 +293,7 @@ func as2variant(as obj.As) int {
return i
}
}
- gc.Fatalf("as2variant: instruction %v is not a variant of itself", obj.Aconv(as&obj.AMask))
+ gc.Fatalf("as2variant: instruction %v is not a variant of itself", as&obj.AMask)
return 0
}
diff --git a/src/cmd/compile/internal/ppc64/reg.go b/src/cmd/compile/internal/ppc64/reg.go
deleted file mode 100644
index 215c9b5..0000000
--- a/src/cmd/compile/internal/ppc64/reg.go
+++ /dev/null
@@ -1,168 +0,0 @@
-// Derived from Inferno utils/6c/reg.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6c/reg.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth at terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth at terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// Portions Copyright © 2009 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-package ppc64
-
-import "cmd/internal/obj/ppc64"
-import "cmd/compile/internal/gc"
-
-const (
- NREGVAR = 64 /* 32 general + 32 floating */
-)
-
-var regname = []string{
- ".R0",
- ".R1",
- ".R2",
- ".R3",
- ".R4",
- ".R5",
- ".R6",
- ".R7",
- ".R8",
- ".R9",
- ".R10",
- ".R11",
- ".R12",
- ".R13",
- ".R14",
- ".R15",
- ".R16",
- ".R17",
- ".R18",
- ".R19",
- ".R20",
- ".R21",
- ".R22",
- ".R23",
- ".R24",
- ".R25",
- ".R26",
- ".R27",
- ".R28",
- ".R29",
- ".R30",
- ".R31",
- ".F0",
- ".F1",
- ".F2",
- ".F3",
- ".F4",
- ".F5",
- ".F6",
- ".F7",
- ".F8",
- ".F9",
- ".F10",
- ".F11",
- ".F12",
- ".F13",
- ".F14",
- ".F15",
- ".F16",
- ".F17",
- ".F18",
- ".F19",
- ".F20",
- ".F21",
- ".F22",
- ".F23",
- ".F24",
- ".F25",
- ".F26",
- ".F27",
- ".F28",
- ".F29",
- ".F30",
- ".F31",
-}
-
-func regnames(n *int) []string {
- *n = NREGVAR
- return regname
-}
-
-func excludedregs() uint64 {
- // Exclude registers with fixed functions
- regbits := 1<<0 | RtoB(ppc64.REGSP) | RtoB(ppc64.REGG) | RtoB(ppc64.REGTLS) | RtoB(ppc64.REGTMP)
-
- if gc.Ctxt.Flag_shared {
- // When compiling Go into PIC, R2 is reserved to be the TOC pointer
- // and R12 so that calls via function pointer can stomp on it.
- regbits |= RtoB(ppc64.REG_R2)
- regbits |= RtoB(ppc64.REG_R12)
- }
- // Also exclude floating point registers with fixed constants
- regbits |= RtoB(ppc64.REG_F27) | RtoB(ppc64.REG_F28) | RtoB(ppc64.REG_F29) | RtoB(ppc64.REG_F30) | RtoB(ppc64.REG_F31)
-
- return regbits
-}
-
-func doregbits(r int) uint64 {
- return 0
-}
-
-/*
- * track register variables including external registers:
- * bit reg
- * 0 R0
- * 1 R1
- * ... ...
- * 31 R31
- * 32+0 F0
- * 32+1 F1
- * ... ...
- * 32+31 F31
- */
-func RtoB(r int) uint64 {
- if r > ppc64.REG_R0 && r <= ppc64.REG_R31 {
- return 1 << uint(r-ppc64.REG_R0)
- }
- if r >= ppc64.REG_F0 && r <= ppc64.REG_F31 {
- return 1 << uint(32+r-ppc64.REG_F0)
- }
- return 0
-}
-
-func BtoR(b uint64) int {
- b &= 0xffffffff
- if b == 0 {
- return 0
- }
- return gc.Bitno(b) + ppc64.REG_R0
-}
-
-func BtoF(b uint64) int {
- b >>= 32
- if b == 0 {
- return 0
- }
- return gc.Bitno(b) + ppc64.REG_F0
-}
diff --git a/src/cmd/compile/internal/ppc64/ssa.go b/src/cmd/compile/internal/ppc64/ssa.go
new file mode 100644
index 0000000..8387692
--- /dev/null
+++ b/src/cmd/compile/internal/ppc64/ssa.go
@@ -0,0 +1,938 @@
+// Copyright 2016 The Go Authors. 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/compile/internal/ssa"
+ "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
+ valueIfCond int // if cond is true, the value to return (0 or 1)
+}
+
+// Input registers to ISEL used for comparison. Index 0 is zero, 1 is (will be) 1
+var iselRegs = [2]int16{ppc64.REG_R0, ppc64.REGTMP}
+
+var iselOps = map[ssa.Op]iselOp{
+ ssa.OpPPC64Equal: iselOp{cond: ppc64.C_COND_EQ, valueIfCond: 1},
+ ssa.OpPPC64NotEqual: iselOp{cond: ppc64.C_COND_EQ, valueIfCond: 0},
+ ssa.OpPPC64LessThan: iselOp{cond: ppc64.C_COND_LT, valueIfCond: 1},
+ ssa.OpPPC64GreaterEqual: iselOp{cond: ppc64.C_COND_LT, valueIfCond: 0},
+ ssa.OpPPC64GreaterThan: iselOp{cond: ppc64.C_COND_GT, valueIfCond: 1},
+ ssa.OpPPC64LessEqual: iselOp{cond: ppc64.C_COND_GT, valueIfCond: 0},
+ ssa.OpPPC64FLessThan: iselOp{cond: ppc64.C_COND_LT, valueIfCond: 1},
+ ssa.OpPPC64FGreaterThan: iselOp{cond: ppc64.C_COND_GT, valueIfCond: 1},
+ ssa.OpPPC64FLessEqual: iselOp{cond: ppc64.C_COND_LT, valueIfCond: 1}, // 2 comparisons, 2nd is EQ
+ ssa.OpPPC64FGreaterEqual: iselOp{cond: ppc64.C_COND_GT, valueIfCond: 1}, // 2 comparisons, 2nd is EQ
+}
+
+// markMoves marks any MOVXconst ops that need to avoid clobbering flags.
+func ssaMarkMoves(s *gc.SSAGenState, b *ssa.Block) {
+ // flive := b.FlagsLiveAtEnd
+ // if b.Control != nil && b.Control.Type.IsFlags() {
+ // flive = true
+ // }
+ // for i := len(b.Values) - 1; i >= 0; i-- {
+ // v := b.Values[i]
+ // if flive && (v.Op == v.Op == ssa.OpPPC64MOVDconst) {
+ // // The "mark" is any non-nil Aux value.
+ // v.Aux = v
+ // }
+ // if v.Type.IsFlags() {
+ // flive = false
+ // }
+ // for _, a := range v.Args {
+ // if a.Type.IsFlags() {
+ // flive = true
+ // }
+ // }
+ // }
+}
+
+// loadByType returns the load instruction of the given type.
+func loadByType(t ssa.Type) obj.As {
+ if t.IsFloat() {
+ switch t.Size() {
+ case 4:
+ return ppc64.AFMOVS
+ case 8:
+ return ppc64.AFMOVD
+ }
+ } else {
+ switch t.Size() {
+ case 1:
+ if t.IsSigned() {
+ return ppc64.AMOVB
+ } else {
+ return ppc64.AMOVBZ
+ }
+ case 2:
+ if t.IsSigned() {
+ return ppc64.AMOVH
+ } else {
+ return ppc64.AMOVHZ
+ }
+ case 4:
+ if t.IsSigned() {
+ return ppc64.AMOVW
+ } else {
+ return ppc64.AMOVWZ
+ }
+ case 8:
+ return ppc64.AMOVD
+ }
+ }
+ panic("bad load type")
+}
+
+// storeByType returns the store instruction of the given type.
+func storeByType(t ssa.Type) obj.As {
+ if t.IsFloat() {
+ switch t.Size() {
+ case 4:
+ return ppc64.AFMOVS
+ case 8:
+ return ppc64.AFMOVD
+ }
+ } else {
+ switch t.Size() {
+ case 1:
+ return ppc64.AMOVB
+ case 2:
+ return ppc64.AMOVH
+ case 4:
+ return ppc64.AMOVW
+ case 8:
+ return ppc64.AMOVD
+ }
+ }
+ panic("bad store type")
+}
+
+func ssaGenISEL(v *ssa.Value, cr int64, r1, r2 int16) {
+ r := v.Reg()
+ p := gc.Prog(ppc64.AISEL)
+ p.To.Type = obj.TYPE_REG
+ p.To.Reg = r
+ p.Reg = r1
+ p.From3 = &obj.Addr{Type: obj.TYPE_REG, Reg: r2}
+ p.From.Type = obj.TYPE_CONST
+ p.From.Offset = cr
+}
+
+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() {
+ return
+ }
+ x := v.Args[0].Reg()
+ y := v.Reg()
+ if x != y {
+ rt := obj.TYPE_REG
+ op := ppc64.AMOVD
+
+ if t.IsFloat() {
+ op = ppc64.AFMOVD
+ }
+ p := gc.Prog(op)
+ p.From.Type = rt
+ p.From.Reg = x
+ p.To.Type = rt
+ p.To.Reg = y
+ }
+
+ case ssa.OpPPC64Xf2i64:
+ {
+ x := v.Args[0].Reg()
+ y := v.Reg()
+ p := gc.Prog(ppc64.AFMOVD)
+ 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.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.OpPPC64LoweredGetClosurePtr:
+ // Closure pointer is R11 (already)
+ gc.CheckLoweredGetClosurePtr(v)
+
+ case ssa.OpLoadReg:
+ loadOp := loadByType(v.Type)
+ p := gc.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.From.Type = obj.TYPE_REG
+ p.From.Reg = v.Args[0].Reg()
+ gc.AddrAuto(&p.To, v)
+
+ case ssa.OpPPC64DIVD:
+ // For now,
+ //
+ // cmp arg1, -1
+ // be ahead
+ // v = arg0 / arg1
+ // b over
+ // ahead: v = - arg0
+ // over: nop
+ r := v.Reg()
+ r0 := v.Args[0].Reg()
+ r1 := v.Args[1].Reg()
+
+ p := gc.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.To.Type = obj.TYPE_BRANCH
+
+ p = gc.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.To.Type = obj.TYPE_BRANCH
+
+ p = gc.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)
+ gc.Patch(pbover, p)
+
+ case ssa.OpPPC64DIVW:
+ // word-width version of above
+ r := v.Reg()
+ r0 := v.Args[0].Reg()
+ r1 := v.Args[1].Reg()
+
+ p := gc.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.To.Type = obj.TYPE_BRANCH
+
+ p = gc.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.To.Type = obj.TYPE_BRANCH
+
+ p = gc.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)
+ gc.Patch(pbover, p)
+
+ case ssa.OpPPC64ADD, ssa.OpPPC64FADD, ssa.OpPPC64FADDS, ssa.OpPPC64SUB, ssa.OpPPC64FSUB, ssa.OpPPC64FSUBS,
+ ssa.OpPPC64MULLD, ssa.OpPPC64MULLW, ssa.OpPPC64DIVDU, ssa.OpPPC64DIVWU,
+ 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:
+ r := v.Reg()
+ r1 := v.Args[0].Reg()
+ r2 := v.Args[1].Reg()
+ p := gc.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.OpPPC64MaskIfNotCarry:
+ r := v.Reg()
+ p := gc.Prog(v.Op.Asm())
+ p.From.Type = obj.TYPE_REG
+ p.From.Reg = ppc64.REGZERO
+ p.To.Type = obj.TYPE_REG
+ p.To.Reg = r
+
+ case ssa.OpPPC64ADDconstForCarry:
+ r1 := v.Args[0].Reg()
+ p := gc.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:
+ r := v.Reg()
+ p := gc.Prog(v.Op.Asm())
+ p.To.Type = obj.TYPE_REG
+ p.To.Reg = r
+ p.From.Type = obj.TYPE_REG
+ p.From.Reg = v.Args[0].Reg()
+
+ 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.Reg = v.Args[0].Reg()
+
+ if v.Aux != nil {
+ p.From.Type = obj.TYPE_CONST
+ p.From.Offset = gc.AuxOffset(v)
+ } else {
+ p.From.Type = obj.TYPE_CONST
+ p.From.Offset = v.AuxInt
+ }
+
+ p.To.Type = obj.TYPE_REG
+ p.To.Reg = v.Reg()
+
+ case ssa.OpPPC64ANDCCconst:
+ p := gc.Prog(v.Op.Asm())
+ p.Reg = v.Args[0].Reg()
+
+ if v.Aux != nil {
+ p.From.Type = obj.TYPE_CONST
+ p.From.Offset = gc.AuxOffset(v)
+ } else {
+ p.From.Type = obj.TYPE_CONST
+ p.From.Offset = v.AuxInt
+ }
+
+ p.To.Type = obj.TYPE_REG
+ p.To.Reg = ppc64.REGTMP // discard result
+
+ case ssa.OpPPC64MOVDaddr:
+ p := gc.Prog(ppc64.AMOVD)
+ p.From.Type = obj.TYPE_ADDR
+ p.To.Type = obj.TYPE_REG
+ p.To.Reg = v.Reg()
+
+ var wantreg string
+ // Suspect comment, copied from ARM code
+ // MOVD $sym+off(base), R
+ // the assembler expands it as the following:
+ // - base is SP: add constant offset to SP
+ // when constant is large, tmp register (R11) may be used
+ // - base is SB: load external address from constant pool (use relocation)
+ switch v.Aux.(type) {
+ default:
+ v.Fatalf("aux is of unknown type %T", v.Aux)
+ case *ssa.ExternSymbol:
+ wantreg = "SB"
+ gc.AddAux(&p.From, v)
+ case *ssa.ArgSymbol, *ssa.AutoSymbol:
+ wantreg = "SP"
+ gc.AddAux(&p.From, v)
+ case nil:
+ // No sym, just MOVD $off(SP), R
+ wantreg = "SP"
+ p.From.Reg = ppc64.REGSP
+ p.From.Offset = v.AuxInt
+ }
+ if reg := v.Args[0].RegName(); reg != wantreg {
+ v.Fatalf("bad reg %s for symbol type %T, want %s", reg, v.Aux, wantreg)
+ }
+
+ case ssa.OpPPC64MOVDconst:
+ p := gc.Prog(v.Op.Asm())
+ p.From.Type = obj.TYPE_CONST
+ p.From.Offset = v.AuxInt
+ p.To.Type = obj.TYPE_REG
+ p.To.Reg = v.Reg()
+
+ case ssa.OpPPC64FMOVDconst, ssa.OpPPC64FMOVSconst:
+ p := gc.Prog(v.Op.Asm())
+ p.From.Type = obj.TYPE_FCONST
+ p.From.Val = math.Float64frombits(uint64(v.AuxInt))
+ p.To.Type = obj.TYPE_REG
+ p.To.Reg = v.Reg()
+
+ case ssa.OpPPC64FCMPU, ssa.OpPPC64CMP, ssa.OpPPC64CMPW, ssa.OpPPC64CMPU, ssa.OpPPC64CMPWU:
+ p := gc.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.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.OpPPC64MOVBreg, ssa.OpPPC64MOVBZreg, ssa.OpPPC64MOVHreg, ssa.OpPPC64MOVHZreg, ssa.OpPPC64MOVWreg, ssa.OpPPC64MOVWZreg:
+ // Shift in register to required size
+ p := gc.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.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.OpPPC64FMOVDload, ssa.OpPPC64FMOVSload:
+ p := gc.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.OpPPC64MOVDstorezero, ssa.OpPPC64MOVWstorezero, ssa.OpPPC64MOVHstorezero, ssa.OpPPC64MOVBstorezero:
+ p := gc.Prog(v.Op.Asm())
+ p.From.Type = obj.TYPE_REG
+ p.From.Reg = ppc64.REGZERO
+ p.To.Type = obj.TYPE_MEM
+ p.To.Reg = v.Args[0].Reg()
+ gc.AddAux(&p.To, v)
+
+ case ssa.OpPPC64MOVDstore, ssa.OpPPC64MOVWstore, ssa.OpPPC64MOVHstore, ssa.OpPPC64MOVBstore:
+ p := gc.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.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.OpPPC64Equal,
+ ssa.OpPPC64NotEqual,
+ ssa.OpPPC64LessThan,
+ ssa.OpPPC64FLessThan,
+ ssa.OpPPC64LessEqual,
+ ssa.OpPPC64GreaterThan,
+ ssa.OpPPC64FGreaterThan,
+ ssa.OpPPC64GreaterEqual:
+
+ // On Power7 or later, can use isel instruction:
+ // for a < b, a > b, a = b:
+ // rtmp := 1
+ // isel rt,rtmp,r0,cond // rt is target in ppc asm
+
+ // for a >= b, a <= b, a != b:
+ // 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.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])
+
+ 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.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())
+
+ 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()
+
+ 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
+
+ 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
+
+ p3 := gc.Prog(ppc64.ABLT)
+ p3.To.Type = obj.TYPE_BRANCH
+ gc.Patch(p3, p)
+
+ 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
+ }
+
+ 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()
+
+ 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
+
+ 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
+
+ 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
+
+ p4 := gc.Prog(ppc64.ABLT)
+ p4.To.Type = obj.TYPE_BRANCH
+ gc.Patch(p4, p)
+
+ 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)
+ 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()
+ }
+ }
+ 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.OpPPC64CALLclosure, ssa.OpPPC64CALLinter:
+ p := gc.Prog(ppc64.AMOVD)
+ p.From.Type = obj.TYPE_REG
+ p.From.Reg = v.Args[0].Reg()
+ p.To.Type = obj.TYPE_REG
+ p.To.Reg = ppc64.REG_CTR
+
+ if gc.Ctxt.Flag_shared && p.From.Reg != ppc64.REG_R12 {
+ // Make sure function pointer is in R12 as well when
+ // compiling Go into PIC.
+ // TODO(mwhudson): it would obviously be better to
+ // 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.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.To.Reg = ppc64.REG_CTR
+
+ if gc.Ctxt.Flag_shared {
+ // When compiling Go into PIC, the function we just
+ // called via pointer might have been implemented in
+ // a separate module and so overwritten the TOC
+ // pointer in R2; reload it.
+ q := gc.Prog(ppc64.AMOVD)
+ q.From.Type = obj.TYPE_MEM
+ q.From.Offset = 24
+ q.From.Reg = ppc64.REGSP
+ q.To.Type = obj.TYPE_REG
+ 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.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")
+ }
+
+ 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())
+
+ default:
+ v.Fatalf("genValue not implemented: %s", v.LongString())
+ }
+}
+
+var blockJump = [...]struct {
+ asm, invasm obj.As
+ asmeq, invasmun bool
+}{
+ ssa.BlockPPC64EQ: {ppc64.ABEQ, ppc64.ABNE, false, false},
+ ssa.BlockPPC64NE: {ppc64.ABNE, ppc64.ABEQ, false, false},
+
+ ssa.BlockPPC64LT: {ppc64.ABLT, ppc64.ABGE, false, false},
+ ssa.BlockPPC64GE: {ppc64.ABGE, ppc64.ABLT, false, false},
+ ssa.BlockPPC64LE: {ppc64.ABLE, ppc64.ABGT, false, false},
+ ssa.BlockPPC64GT: {ppc64.ABGT, ppc64.ABLE, false, false},
+
+ // TODO: need to work FP comparisons into block jumps
+ ssa.BlockPPC64FLT: {ppc64.ABLT, ppc64.ABGE, false, false},
+ ssa.BlockPPC64FGE: {ppc64.ABGT, ppc64.ABLT, true, true}, // GE = GT or EQ; !GE = LT or UN
+ ssa.BlockPPC64FLE: {ppc64.ABLT, ppc64.ABGT, true, true}, // LE = LT or EQ; !LE = GT or UN
+ ssa.BlockPPC64FGT: {ppc64.ABGT, ppc64.ABLE, false, false},
+}
+
+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.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.To.Type = obj.TYPE_BRANCH
+ s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[1].Block()})
+ if b.Succs[0].Block() != next {
+ p := gc.Prog(obj.AJMP)
+ p.To.Type = obj.TYPE_BRANCH
+ s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()})
+ }
+
+ case ssa.BlockPlain:
+ if b.Succs[0].Block() != next {
+ p := gc.Prog(obj.AJMP)
+ p.To.Type = obj.TYPE_BRANCH
+ s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()})
+ }
+ case ssa.BlockExit:
+ gc.Prog(obj.AUNDEF) // tell plive.go that we never reach here
+ case ssa.BlockRet:
+ gc.Prog(obj.ARET)
+ case ssa.BlockRetJmp:
+ p := gc.Prog(obj.AJMP)
+ p.To.Type = obj.TYPE_MEM
+ p.To.Name = obj.NAME_EXTERN
+ p.To.Sym = gc.Linksym(b.Aux.(*gc.Sym))
+
+ case ssa.BlockPPC64EQ, ssa.BlockPPC64NE,
+ ssa.BlockPPC64LT, ssa.BlockPPC64GE,
+ ssa.BlockPPC64LE, ssa.BlockPPC64GT,
+ 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.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.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.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.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.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.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.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/cgen.go b/src/cmd/compile/internal/s390x/cgen.go
deleted file mode 100644
index 28bb34e..0000000
--- a/src/cmd/compile/internal/s390x/cgen.go
+++ /dev/null
@@ -1,178 +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"
-)
-
-type direction int
-
-const (
- _FORWARDS direction = iota
- _BACKWARDS
-)
-
-// blockcopy copies w bytes from &n to &res
-func blockcopy(n, res *gc.Node, osrc, odst, w int64) {
- var dst gc.Node
- var src gc.Node
- if n.Ullman >= res.Ullman {
- gc.Agenr(n, &dst, res) // temporarily use dst
- gc.Regalloc(&src, gc.Types[gc.Tptr], nil)
- gins(s390x.AMOVD, &dst, &src)
- if res.Op == gc.ONAME {
- gc.Gvardef(res)
- }
- gc.Agen(res, &dst)
- } else {
- if res.Op == gc.ONAME {
- gc.Gvardef(res)
- }
- gc.Agenr(res, &dst, res)
- gc.Agenr(n, &src, nil)
- }
- defer gc.Regfree(&src)
- defer gc.Regfree(&dst)
-
- var tmp gc.Node
- gc.Regalloc(&tmp, gc.Types[gc.Tptr], nil)
- defer gc.Regfree(&tmp)
-
- offset := int64(0)
- dir := _FORWARDS
- if osrc < odst && odst < osrc+w {
- // Reverse. Can't use MVC, fall back onto basic moves.
- dir = _BACKWARDS
- const copiesPerIter = 2
- if w >= 8*copiesPerIter {
- cnt := w - (w % (8 * copiesPerIter))
- ginscon(s390x.AADD, w, &src)
- ginscon(s390x.AADD, w, &dst)
-
- var end gc.Node
- gc.Regalloc(&end, gc.Types[gc.Tptr], nil)
- p := gins(s390x.ASUB, nil, &end)
- p.From.Type = obj.TYPE_CONST
- p.From.Offset = cnt
- p.Reg = src.Reg
-
- var label *obj.Prog
- for i := 0; i < copiesPerIter; i++ {
- offset := int64(-8 * (i + 1))
- p := gins(s390x.AMOVD, &src, &tmp)
- p.From.Type = obj.TYPE_MEM
- p.From.Offset = offset
- if i == 0 {
- label = p
- }
- p = gins(s390x.AMOVD, &tmp, &dst)
- p.To.Type = obj.TYPE_MEM
- p.To.Offset = offset
- }
-
- ginscon(s390x.ASUB, 8*copiesPerIter, &src)
- ginscon(s390x.ASUB, 8*copiesPerIter, &dst)
- gins(s390x.ACMP, &src, &end)
- gc.Patch(gc.Gbranch(s390x.ABNE, nil, 0), label)
- gc.Regfree(&end)
-
- w -= cnt
- } else {
- offset = w
- }
- }
-
- if dir == _FORWARDS && w > 1024 {
- // Loop over MVCs
- cnt := w - (w % 256)
-
- var end gc.Node
- gc.Regalloc(&end, gc.Types[gc.Tptr], nil)
- add := gins(s390x.AADD, nil, &end)
- add.From.Type = obj.TYPE_CONST
- add.From.Offset = cnt
- add.Reg = src.Reg
-
- mvc := gins(s390x.AMVC, &src, &dst)
- mvc.From.Type = obj.TYPE_MEM
- mvc.From.Offset = 0
- mvc.To.Type = obj.TYPE_MEM
- mvc.To.Offset = 0
- mvc.From3 = new(obj.Addr)
- mvc.From3.Type = obj.TYPE_CONST
- mvc.From3.Offset = 256
-
- ginscon(s390x.AADD, 256, &src)
- ginscon(s390x.AADD, 256, &dst)
- gins(s390x.ACMP, &src, &end)
- gc.Patch(gc.Gbranch(s390x.ABNE, nil, 0), mvc)
- gc.Regfree(&end)
-
- w -= cnt
- }
-
- for w > 0 {
- cnt := w
- // If in reverse we can only do 8, 4, 2 or 1 bytes at a time.
- if dir == _BACKWARDS {
- switch {
- case cnt >= 8:
- cnt = 8
- case cnt >= 4:
- cnt = 4
- case cnt >= 2:
- cnt = 2
- }
- } else if cnt > 256 {
- cnt = 256
- }
-
- switch cnt {
- case 8, 4, 2, 1:
- op := s390x.AMOVB
- switch cnt {
- case 8:
- op = s390x.AMOVD
- case 4:
- op = s390x.AMOVW
- case 2:
- op = s390x.AMOVH
- }
- load := gins(op, &src, &tmp)
- load.From.Type = obj.TYPE_MEM
- load.From.Offset = offset
-
- store := gins(op, &tmp, &dst)
- store.To.Type = obj.TYPE_MEM
- store.To.Offset = offset
-
- if dir == _BACKWARDS {
- load.From.Offset -= cnt
- store.To.Offset -= cnt
- }
-
- default:
- p := gins(s390x.AMVC, &src, &dst)
- p.From.Type = obj.TYPE_MEM
- p.From.Offset = offset
- p.To.Type = obj.TYPE_MEM
- p.To.Offset = offset
- p.From3 = new(obj.Addr)
- p.From3.Type = obj.TYPE_CONST
- p.From3.Offset = cnt
- }
-
- switch dir {
- case _FORWARDS:
- offset += cnt
- case _BACKWARDS:
- offset -= cnt
- }
- w -= cnt
- }
-}
diff --git a/src/cmd/compile/internal/s390x/galign.go b/src/cmd/compile/internal/s390x/galign.go
index d0d621e..91b9ed0 100644
--- a/src/cmd/compile/internal/s390x/galign.go
+++ b/src/cmd/compile/internal/s390x/galign.go
@@ -9,58 +9,15 @@ import (
"cmd/internal/obj/s390x"
)
-func betypeinit() {
- gc.Widthptr = 8
- gc.Widthint = 8
- gc.Widthreg = 8
-}
-
-func Main() {
+func Init() {
gc.Thearch.LinkArch = &s390x.Links390x
gc.Thearch.REGSP = s390x.REGSP
- gc.Thearch.REGCTXT = s390x.REGCTXT
- gc.Thearch.REGCALLX = s390x.REG_R3
- gc.Thearch.REGCALLX2 = s390x.REG_R4
- gc.Thearch.REGRETURN = s390x.REG_R3
- gc.Thearch.REGMIN = s390x.REG_R0
- gc.Thearch.REGMAX = s390x.REG_R15
- gc.Thearch.FREGMIN = s390x.REG_F0
- gc.Thearch.FREGMAX = s390x.REG_F15
gc.Thearch.MAXWIDTH = 1 << 50
- gc.Thearch.ReservedRegs = resvd
- gc.Thearch.Betypeinit = betypeinit
- gc.Thearch.Cgen_hmul = cgen_hmul
- gc.Thearch.Cgen_shift = cgen_shift
- gc.Thearch.Clearfat = clearfat
gc.Thearch.Defframe = defframe
- gc.Thearch.Dodiv = dodiv
- gc.Thearch.Excise = excise
- gc.Thearch.Expandchecks = expandchecks
- gc.Thearch.Getg = getg
- gc.Thearch.Gins = gins
- gc.Thearch.Ginscmp = ginscmp
- gc.Thearch.Ginscon = ginscon
- gc.Thearch.Ginsnop = ginsnop
- gc.Thearch.Gmove = gmove
- gc.Thearch.Peep = peep
gc.Thearch.Proginfo = proginfo
- gc.Thearch.Regtyp = isReg
- gc.Thearch.Sameaddr = sameaddr
- gc.Thearch.Smallindir = smallindir
- gc.Thearch.Stackaddr = stackaddr
- gc.Thearch.Blockcopy = blockcopy
- gc.Thearch.Sudoaddable = sudoaddable
- gc.Thearch.Sudoclean = sudoclean
- gc.Thearch.Excludedregs = excludedregs
- gc.Thearch.RtoB = RtoB
- gc.Thearch.FtoB = RtoB
- gc.Thearch.BtoR = BtoR
- gc.Thearch.BtoF = BtoF
- gc.Thearch.Optoas = optoas
- gc.Thearch.Doregbits = doregbits
- gc.Thearch.Regnames = regnames
- gc.Main()
- gc.Exit(0)
+ gc.Thearch.SSAMarkMoves = ssaMarkMoves
+ gc.Thearch.SSAGenValue = ssaGenValue
+ gc.Thearch.SSAGenBlock = ssaGenBlock
}
diff --git a/src/cmd/compile/internal/s390x/ggen.go b/src/cmd/compile/internal/s390x/ggen.go
index 39885ba..15c6554 100644
--- a/src/cmd/compile/internal/s390x/ggen.go
+++ b/src/cmd/compile/internal/s390x/ggen.go
@@ -8,7 +8,6 @@ import (
"cmd/compile/internal/gc"
"cmd/internal/obj"
"cmd/internal/obj/s390x"
- "fmt"
)
// clearLoopCutOff is the (somewhat arbitrary) value above which it is better
@@ -42,7 +41,7 @@ func defframe(ptxt *obj.Prog) {
gc.Fatalf("needzero class %d", n.Class)
}
if n.Type.Width%int64(gc.Widthptr) != 0 || n.Xoffset%int64(gc.Widthptr) != 0 || n.Type.Width == 0 {
- gc.Fatalf("var %v has size %d offset %d", gc.Nconv(n, gc.FmtLong), int(n.Type.Width), int(n.Xoffset))
+ 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) {
@@ -81,7 +80,7 @@ func zerorange(p *obj.Prog, frame int64, lo int64, hi int64) *obj.Prog {
// need to create a copy of the stack pointer that we can adjust.
// We also need to do this if we are going to loop.
if offset < 0 || offset > 4096-clearLoopCutoff || cnt > clearLoopCutoff {
- p = appendpp(p, s390x.AADD, obj.TYPE_CONST, 0, offset, obj.TYPE_REG, s390x.REGRT1, 0)
+ p = gc.Appendpp(p, s390x.AADD, obj.TYPE_CONST, 0, offset, obj.TYPE_REG, s390x.REGRT1, 0)
p.Reg = int16(s390x.REGSP)
reg = s390x.REGRT1
offset = 0
@@ -91,16 +90,16 @@ func zerorange(p *obj.Prog, frame int64, lo int64, hi int64) *obj.Prog {
if cnt > clearLoopCutoff {
n := cnt - (cnt % 256)
end := int16(s390x.REGRT2)
- p = appendpp(p, s390x.AADD, obj.TYPE_CONST, 0, offset+n, obj.TYPE_REG, end, 0)
+ p = gc.Appendpp(p, s390x.AADD, obj.TYPE_CONST, 0, offset+n, obj.TYPE_REG, end, 0)
p.Reg = reg
- p = appendpp(p, s390x.AXC, obj.TYPE_MEM, reg, offset, obj.TYPE_MEM, reg, offset)
+ p = 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
pl := p
- p = appendpp(p, s390x.AADD, obj.TYPE_CONST, 0, 256, obj.TYPE_REG, reg, 0)
- p = appendpp(p, s390x.ACMP, obj.TYPE_REG, reg, 0, obj.TYPE_REG, end, 0)
- p = appendpp(p, s390x.ABNE, obj.TYPE_NONE, 0, 0, obj.TYPE_BRANCH, 0, 0)
+ 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)
gc.Patch(p, pl)
cnt -= n
@@ -127,11 +126,11 @@ func zerorange(p *obj.Prog, frame int64, lo int64, hi int64) *obj.Prog {
case 2:
ins = s390x.AMOVH
}
- p = appendpp(p, ins, obj.TYPE_CONST, 0, 0, obj.TYPE_MEM, reg, offset)
+ p = gc.Appendpp(p, ins, obj.TYPE_CONST, 0, 0, obj.TYPE_MEM, reg, offset)
// Handle clears that would require multiple move instructions with XC.
default:
- p = appendpp(p, s390x.AXC, obj.TYPE_MEM, reg, offset, obj.TYPE_MEM, reg, offset)
+ p = 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
@@ -144,434 +143,10 @@ func zerorange(p *obj.Prog, frame int64, lo int64, hi int64) *obj.Prog {
return p
}
-func appendpp(p *obj.Prog, as obj.As, ftype obj.AddrType, freg int16, foffset int64, ttype obj.AddrType, treg int16, toffset int64) *obj.Prog {
- q := gc.Ctxt.NewProg()
- gc.Clearp(q)
- q.As = as
- q.Lineno = p.Lineno
- q.From.Type = ftype
- q.From.Reg = freg
- q.From.Offset = foffset
- q.To.Type = ttype
- q.To.Reg = treg
- q.To.Offset = toffset
- q.Link = p.Link
- p.Link = q
- return q
-}
-
func ginsnop() {
- var reg gc.Node
- gc.Nodreg(®, gc.Types[gc.TINT], s390x.REG_R0)
- gins(s390x.AOR, ®, ®)
-}
-
-var panicdiv *gc.Node
-
-/*
- * generate division.
- * generates one of:
- * res = nl / nr
- * res = nl % nr
- * according to op.
- */
-func dodiv(op gc.Op, nl *gc.Node, nr *gc.Node, res *gc.Node) {
- // Have to be careful about handling
- // most negative int divided by -1 correctly.
- // The hardware will generate undefined result.
- // Also need to explicitly trap on division on zero,
- // the hardware will silently generate undefined result.
- // DIVW will leave unpredicable result in higher 32-bit,
- // so always use DIVD/DIVDU.
- t := nl.Type
-
- t0 := t
- check := 0
- if t.IsSigned() {
- check = 1
- if gc.Isconst(nl, gc.CTINT) && nl.Int64() != -(1<<uint64(t.Width*8-1)) {
- check = 0
- } else if gc.Isconst(nr, gc.CTINT) && nr.Int64() != -1 {
- check = 0
- }
- }
-
- if t.Width < 8 {
- if t.IsSigned() {
- t = gc.Types[gc.TINT64]
- } else {
- t = gc.Types[gc.TUINT64]
- }
- check = 0
- }
-
- a := optoas(gc.ODIV, t)
-
- var tl gc.Node
- gc.Regalloc(&tl, t0, nil)
- var tr gc.Node
- gc.Regalloc(&tr, t0, nil)
- if nl.Ullman >= nr.Ullman {
- gc.Cgen(nl, &tl)
- gc.Cgen(nr, &tr)
- } else {
- gc.Cgen(nr, &tr)
- gc.Cgen(nl, &tl)
- }
-
- if t != t0 {
- // Convert
- tl2 := tl
-
- tr2 := tr
- tl.Type = t
- tr.Type = t
- gmove(&tl2, &tl)
- gmove(&tr2, &tr)
- }
-
- // Handle divide-by-zero panic.
- p1 := gins(optoas(gc.OCMP, t), &tr, nil)
-
- p1.To.Type = obj.TYPE_REG
- p1.To.Reg = s390x.REGZERO
- p1 = gc.Gbranch(optoas(gc.ONE, t), nil, +1)
- if panicdiv == nil {
- panicdiv = gc.Sysfunc("panicdivide")
- }
- gc.Ginscall(panicdiv, -1)
- gc.Patch(p1, gc.Pc)
-
- var p2 *obj.Prog
- if check != 0 {
- var nm1 gc.Node
- gc.Nodconst(&nm1, t, -1)
- gins(optoas(gc.OCMP, t), &tr, &nm1)
- p1 := gc.Gbranch(optoas(gc.ONE, t), nil, +1)
- if op == gc.ODIV {
- // a / (-1) is -a.
- gins(optoas(gc.OMINUS, t), nil, &tl)
-
- gmove(&tl, res)
- } else {
- // a % (-1) is 0.
- var nz gc.Node
- gc.Nodconst(&nz, t, 0)
-
- gmove(&nz, res)
- }
-
- p2 = gc.Gbranch(obj.AJMP, nil, 0)
- gc.Patch(p1, gc.Pc)
- }
-
- p1 = gins(a, &tr, &tl)
- if op == gc.ODIV {
- gc.Regfree(&tr)
- gmove(&tl, res)
- } else {
- // A%B = A-(A/B*B)
- var tm gc.Node
- gc.Regalloc(&tm, t, nil)
-
- // patch div to use the 3 register form
- // TODO(minux): add gins3?
- p1.Reg = p1.To.Reg
-
- p1.To.Reg = tm.Reg
- gins(optoas(gc.OMUL, t), &tr, &tm)
- gc.Regfree(&tr)
- gins(optoas(gc.OSUB, t), &tm, &tl)
- gc.Regfree(&tm)
- gmove(&tl, res)
- }
-
- gc.Regfree(&tl)
- if check != 0 {
- gc.Patch(p2, gc.Pc)
- }
-}
-
-/*
- * generate high multiply:
- * res = (nl*nr) >> width
- */
-func cgen_hmul(nl *gc.Node, nr *gc.Node, res *gc.Node) {
- // largest ullman on left.
- if nl.Ullman < nr.Ullman {
- nl, nr = nr, nl
- }
-
- t := nl.Type
- w := int(t.Width) * 8
- var n1 gc.Node
- gc.Cgenr(nl, &n1, res)
- var n2 gc.Node
- gc.Cgenr(nr, &n2, nil)
- switch gc.Simtype[t.Etype] {
- case gc.TINT8,
- gc.TINT16,
- gc.TINT32:
- gins(optoas(gc.OMUL, t), &n2, &n1)
- p := gins(s390x.ASRAD, nil, &n1)
- p.From.Type = obj.TYPE_CONST
- p.From.Offset = int64(w)
-
- case gc.TUINT8,
- gc.TUINT16,
- gc.TUINT32:
- gins(optoas(gc.OMUL, t), &n2, &n1)
- p := gins(s390x.ASRD, nil, &n1)
- p.From.Type = obj.TYPE_CONST
- p.From.Offset = int64(w)
-
- case gc.TINT64:
- gins(s390x.AMULHD, &n2, &n1)
-
- case gc.TUINT64:
- gins(s390x.AMULHDU, &n2, &n1)
-
- default:
- gc.Fatalf("cgen_hmul %v", t)
- }
-
- gc.Cgen(&n1, res)
- gc.Regfree(&n1)
- gc.Regfree(&n2)
-}
-
-/*
- * generate shift according to op, one of:
- * res = nl << nr
- * res = nl >> nr
- */
-func cgen_shift(op gc.Op, bounded bool, nl *gc.Node, nr *gc.Node, res *gc.Node) {
- a := optoas(op, nl.Type)
-
- if nr.Op == gc.OLITERAL {
- var n1 gc.Node
- gc.Regalloc(&n1, nl.Type, res)
- gc.Cgen(nl, &n1)
- sc := uint64(nr.Int64())
- if sc >= uint64(nl.Type.Width*8) {
- // large shift gets 2 shifts by width-1
- var n3 gc.Node
- gc.Nodconst(&n3, gc.Types[gc.TUINT32], nl.Type.Width*8-1)
-
- gins(a, &n3, &n1)
- gins(a, &n3, &n1)
- } else {
- gins(a, nr, &n1)
- }
- gmove(&n1, res)
- gc.Regfree(&n1)
- return
- }
-
- if nl.Ullman >= gc.UINF {
- var n4 gc.Node
- gc.Tempname(&n4, nl.Type)
- gc.Cgen(nl, &n4)
- nl = &n4
- }
-
- if nr.Ullman >= gc.UINF {
- var n5 gc.Node
- gc.Tempname(&n5, nr.Type)
- gc.Cgen(nr, &n5)
- nr = &n5
- }
-
- // Allow either uint32 or uint64 as shift type,
- // to avoid unnecessary conversion from uint32 to uint64
- // just to do the comparison.
- tcount := gc.Types[gc.Simtype[nr.Type.Etype]]
-
- if tcount.Etype < gc.TUINT32 {
- tcount = gc.Types[gc.TUINT32]
- }
-
- var n1 gc.Node
- gc.Regalloc(&n1, nr.Type, nil) // to hold the shift type in CX
- var n3 gc.Node
- gc.Regalloc(&n3, tcount, &n1) // to clear high bits of CX
-
- var n2 gc.Node
- gc.Regalloc(&n2, nl.Type, res)
-
- if nl.Ullman >= nr.Ullman {
- gc.Cgen(nl, &n2)
- gc.Cgen(nr, &n1)
- gmove(&n1, &n3)
- } else {
- gc.Cgen(nr, &n1)
- gmove(&n1, &n3)
- gc.Cgen(nl, &n2)
- }
-
- gc.Regfree(&n3)
-
- // test and fix up large shifts
- if !bounded {
- gc.Nodconst(&n3, tcount, nl.Type.Width*8)
- gins(optoas(gc.OCMP, tcount), &n1, &n3)
- p1 := gc.Gbranch(optoas(gc.OLT, tcount), nil, 1)
- if op == gc.ORSH && nl.Type.IsSigned() {
- gc.Nodconst(&n3, gc.Types[gc.TUINT32], nl.Type.Width*8-1)
- gins(a, &n3, &n2)
- } else {
- gc.Nodconst(&n3, nl.Type, 0)
- gmove(&n3, &n2)
- }
-
- gc.Patch(p1, gc.Pc)
- }
-
- gins(a, &n1, &n2)
-
- gmove(&n2, res)
-
- gc.Regfree(&n1)
- gc.Regfree(&n2)
-}
-
-// clearfat clears (i.e. replaces with zeros) the value pointed to by nl.
-func clearfat(nl *gc.Node) {
- if gc.Debug['g'] != 0 {
- fmt.Printf("clearfat %v (%v, size: %d)\n", nl, nl.Type, nl.Type.Width)
- }
-
- // Avoid taking the address for simple enough types.
- if gc.Componentgen(nil, nl) {
- return
- }
-
- var dst gc.Node
- gc.Regalloc(&dst, gc.Types[gc.Tptr], nil)
- gc.Agen(nl, &dst)
-
- var boff int64
- w := nl.Type.Width
- if w > clearLoopCutoff {
- // Generate a loop clearing 256 bytes per iteration using XCs.
- var end gc.Node
- gc.Regalloc(&end, gc.Types[gc.Tptr], nil)
- p := gins(s390x.AMOVD, &dst, &end)
- p.From.Type = obj.TYPE_ADDR
- p.From.Offset = w - (w % 256)
-
- p = gins(s390x.AXC, &dst, &dst)
- p.From.Type = obj.TYPE_MEM
- p.From.Offset = 0
- p.To.Type = obj.TYPE_MEM
- p.To.Offset = 0
- p.From3 = new(obj.Addr)
- p.From3.Offset = 256
- p.From3.Type = obj.TYPE_CONST
- pl := p
-
- ginscon(s390x.AADD, 256, &dst)
- gins(s390x.ACMP, &dst, &end)
- gc.Patch(gc.Gbranch(s390x.ABNE, nil, 0), pl)
- gc.Regfree(&end)
- w = w % 256
- }
-
- // Generate instructions to clear the remaining memory.
- for w > 0 {
- n := w
-
- // Can clear at most 256 bytes per instruction.
- if n > 256 {
- n = 256
- }
-
- switch n {
- // Handle very small clears using moves.
- case 8, 4, 2, 1:
- ins := s390x.AMOVB
- switch n {
- case 8:
- ins = s390x.AMOVD
- case 4:
- ins = s390x.AMOVW
- case 2:
- ins = s390x.AMOVH
- }
- p := gins(ins, nil, &dst)
- p.From.Type = obj.TYPE_CONST
- p.From.Offset = 0
- p.To.Type = obj.TYPE_MEM
- p.To.Offset = boff
-
- // Handle clears that would require multiple moves with a XC.
- default:
- p := gins(s390x.AXC, &dst, &dst)
- p.From.Type = obj.TYPE_MEM
- p.From.Offset = boff
- p.To.Type = obj.TYPE_MEM
- p.To.Offset = boff
- p.From3 = new(obj.Addr)
- p.From3.Offset = n
- p.From3.Type = obj.TYPE_CONST
- }
-
- boff += n
- w -= n
- }
-
- gc.Regfree(&dst)
-}
-
-// Called after regopt and peep have run.
-// Expand CHECKNIL pseudo-op into actual nil pointer check.
-func expandchecks(firstp *obj.Prog) {
- for p := firstp; p != nil; p = p.Link {
- if gc.Debug_checknil != 0 && gc.Ctxt.Debugvlog != 0 {
- fmt.Printf("expandchecks: %v\n", p)
- }
- if p.As != obj.ACHECKNIL {
- continue
- }
- if gc.Debug_checknil != 0 && p.Lineno > 1 { // p->lineno==1 in generated wrappers
- gc.Warnl(p.Lineno, "generated nil check")
- }
- if p.From.Type != obj.TYPE_REG {
- gc.Fatalf("invalid nil check %v\n", p)
- }
-
- // check is
- // CMPBNE arg, $0, 2(PC) [likely]
- // MOVD R0, 0(R0)
- p1 := gc.Ctxt.NewProg()
-
- gc.Clearp(p1)
- p1.Link = p.Link
- p.Link = p1
- p1.Lineno = p.Lineno
- p1.Pc = 9999
- p.As = s390x.ACMPBNE
- p.From3 = new(obj.Addr)
- p.From3.Type = obj.TYPE_CONST
- p.From3.Offset = 0
-
- p.To.Type = obj.TYPE_BRANCH
- p.To.Val = p1.Link
-
- // crash by write to memory address 0.
- p1.As = s390x.AMOVD
-
- p1.From.Type = obj.TYPE_REG
- p1.From.Reg = s390x.REGZERO
- p1.To.Type = obj.TYPE_MEM
- p1.To.Reg = s390x.REGZERO
- p1.To.Offset = 0
- }
-}
-
-// res = runtime.getg()
-func getg(res *gc.Node) {
- var n1 gc.Node
- gc.Nodreg(&n1, res.Type, s390x.REGG)
- gmove(&n1, res)
+ p := gc.Prog(s390x.AOR)
+ p.From.Type = obj.TYPE_REG
+ p.From.Reg = int16(s390x.REG_R0)
+ p.To.Type = obj.TYPE_REG
+ p.To.Reg = int16(s390x.REG_R0)
}
diff --git a/src/cmd/compile/internal/s390x/gsubr.go b/src/cmd/compile/internal/s390x/gsubr.go
deleted file mode 100644
index 7760812..0000000
--- a/src/cmd/compile/internal/s390x/gsubr.go
+++ /dev/null
@@ -1,1110 +0,0 @@
-// Derived from Inferno utils/6c/txt.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6c/txt.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth at terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth at terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// Portions Copyright © 2009 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-package s390x
-
-import (
- "cmd/compile/internal/gc"
- "cmd/internal/obj"
- "cmd/internal/obj/s390x"
- "fmt"
-)
-
-var resvd = []int{
- s390x.REGZERO, // R0
- s390x.REGTMP, // R10
- s390x.REGTMP2, // R11
- s390x.REGCTXT, // R12
- s390x.REGG, // R13
- s390x.REG_LR, // R14
- s390x.REGSP, // R15
-}
-
-// generate
-// as $c, n
-func ginscon(as obj.As, c int64, n2 *gc.Node) {
- var n1 gc.Node
-
- gc.Nodconst(&n1, gc.Types[gc.TINT64], c)
-
- if as != s390x.AMOVD && (c < -s390x.BIG || c > s390x.BIG) || n2.Op != gc.OREGISTER {
- // cannot have more than 16-bit of immediate in ADD, etc.
- // instead, MOV into register first.
- var ntmp gc.Node
- gc.Regalloc(&ntmp, gc.Types[gc.TINT64], nil)
-
- rawgins(s390x.AMOVD, &n1, &ntmp)
- rawgins(as, &ntmp, n2)
- gc.Regfree(&ntmp)
- return
- }
-
- rawgins(as, &n1, n2)
-}
-
-// generate
-// as n, $c (CMP/CMPU)
-func ginscon2(as obj.As, n2 *gc.Node, c int64) {
- var n1 gc.Node
-
- gc.Nodconst(&n1, gc.Types[gc.TINT64], c)
-
- switch as {
- default:
- gc.Fatalf("ginscon2")
-
- case s390x.ACMP:
- if -s390x.BIG <= c && c <= s390x.BIG {
- rawgins(as, n2, &n1)
- return
- }
-
- case s390x.ACMPU:
- if 0 <= c && c <= 2*s390x.BIG {
- rawgins(as, n2, &n1)
- return
- }
- }
-
- // MOV n1 into register first
- var ntmp gc.Node
- gc.Regalloc(&ntmp, gc.Types[gc.TINT64], nil)
-
- rawgins(s390x.AMOVD, &n1, &ntmp)
- rawgins(as, n2, &ntmp)
- gc.Regfree(&ntmp)
-}
-
-func ginscmp(op gc.Op, t *gc.Type, n1, n2 *gc.Node, likely int) *obj.Prog {
- if t.IsInteger() && n1.Op == gc.OLITERAL && n2.Op != gc.OLITERAL {
- // Reverse comparison to place constant last.
- op = gc.Brrev(op)
- n1, n2 = n2, n1
- }
-
- var r1, r2, g1, g2 gc.Node
- gc.Regalloc(&r1, t, n1)
- gc.Regalloc(&g1, n1.Type, &r1)
- gc.Cgen(n1, &g1)
- gmove(&g1, &r1)
- if t.IsInteger() && gc.Isconst(n2, gc.CTINT) {
- ginscon2(optoas(gc.OCMP, t), &r1, n2.Int64())
- } else {
- gc.Regalloc(&r2, t, n2)
- gc.Regalloc(&g2, n1.Type, &r2)
- gc.Cgen(n2, &g2)
- gmove(&g2, &r2)
- rawgins(optoas(gc.OCMP, t), &r1, &r2)
- gc.Regfree(&g2)
- gc.Regfree(&r2)
- }
- gc.Regfree(&g1)
- gc.Regfree(&r1)
- return gc.Gbranch(optoas(op, t), nil, likely)
-}
-
-// gmvc tries to move f to t using a mvc instruction.
-// If successful it returns true, otherwise it returns false.
-func gmvc(f, t *gc.Node) bool {
- ft := int(gc.Simsimtype(f.Type))
- tt := int(gc.Simsimtype(t.Type))
-
- if ft != tt {
- return false
- }
-
- if f.Op != gc.OINDREG || t.Op != gc.OINDREG {
- return false
- }
-
- if f.Xoffset < 0 || f.Xoffset >= 4096-8 {
- return false
- }
-
- if t.Xoffset < 0 || t.Xoffset >= 4096-8 {
- return false
- }
-
- var len int64
- switch ft {
- case gc.TUINT8, gc.TINT8, gc.TBOOL:
- len = 1
- case gc.TUINT16, gc.TINT16:
- len = 2
- case gc.TUINT32, gc.TINT32, gc.TFLOAT32:
- len = 4
- case gc.TUINT64, gc.TINT64, gc.TFLOAT64, gc.TPTR64:
- len = 8
- case gc.TUNSAFEPTR:
- len = int64(gc.Widthptr)
- default:
- return false
- }
-
- p := gc.Prog(s390x.AMVC)
- gc.Naddr(&p.From, f)
- gc.Naddr(&p.To, t)
- p.From3 = new(obj.Addr)
- p.From3.Offset = len
- p.From3.Type = obj.TYPE_CONST
- return true
-}
-
-// generate move:
-// t = f
-// hard part is conversions.
-func gmove(f *gc.Node, t *gc.Node) {
- if gc.Debug['M'] != 0 {
- fmt.Printf("gmove %v -> %v\n", gc.Nconv(f, gc.FmtLong), gc.Nconv(t, gc.FmtLong))
- }
-
- ft := int(gc.Simsimtype(f.Type))
- tt := int(gc.Simsimtype(t.Type))
- cvt := t.Type
-
- if gc.Iscomplex[ft] || gc.Iscomplex[tt] {
- gc.Complexmove(f, t)
- return
- }
-
- var a obj.As
-
- // cannot have two memory operands
- if gc.Ismem(f) && gc.Ismem(t) {
- if gmvc(f, t) {
- return
- }
- goto hard
- }
-
- // convert constant to desired type
- if f.Op == gc.OLITERAL {
- var con gc.Node
- f.Convconst(&con, t.Type)
- f = &con
- ft = tt // so big switch will choose a simple mov
-
- // some constants can't move directly to memory.
- if gc.Ismem(t) {
- // float constants come from memory.
- if t.Type.IsFloat() {
- goto hard
- }
-
- // all immediates are 16-bit sign-extended
- // unless moving into a register.
- if t.Type.IsInteger() {
- if i := con.Int64(); int64(int16(i)) != i {
- goto hard
- }
- }
-
- // immediate moves to memory have a 12-bit unsigned displacement
- if t.Xoffset < 0 || t.Xoffset >= 4096-8 {
- goto hard
- }
- }
- }
-
- // a float-to-int or int-to-float conversion requires the source operand in a register
- if gc.Ismem(f) && ((f.Type.IsFloat() && t.Type.IsInteger()) || (f.Type.IsInteger() && t.Type.IsFloat())) {
- cvt = f.Type
- goto hard
- }
-
- // a float32-to-float64 or float64-to-float32 conversion requires the source operand in a register
- if gc.Ismem(f) && f.Type.IsFloat() && t.Type.IsFloat() && (ft != tt) {
- cvt = f.Type
- goto hard
- }
-
- // value -> value copy, only one memory operand.
- // figure out the instruction to use.
- // break out of switch for one-instruction gins.
- // goto rdst for "destination must be register".
- // goto hard for "convert to cvt type first".
- // otherwise handle and return.
- switch uint32(ft)<<16 | uint32(tt) {
- default:
- gc.Fatalf("gmove %v -> %v", gc.Tconv(f.Type, gc.FmtLong), gc.Tconv(t.Type, gc.FmtLong))
-
- // integer copy and truncate
- case gc.TINT8<<16 | gc.TINT8,
- gc.TUINT8<<16 | gc.TINT8,
- gc.TINT16<<16 | gc.TINT8,
- gc.TUINT16<<16 | gc.TINT8,
- gc.TINT32<<16 | gc.TINT8,
- gc.TUINT32<<16 | gc.TINT8,
- gc.TINT64<<16 | gc.TINT8,
- gc.TUINT64<<16 | gc.TINT8:
- a = s390x.AMOVB
-
- case gc.TINT8<<16 | gc.TUINT8,
- gc.TUINT8<<16 | gc.TUINT8,
- gc.TINT16<<16 | gc.TUINT8,
- gc.TUINT16<<16 | gc.TUINT8,
- gc.TINT32<<16 | gc.TUINT8,
- gc.TUINT32<<16 | gc.TUINT8,
- gc.TINT64<<16 | gc.TUINT8,
- gc.TUINT64<<16 | gc.TUINT8:
- a = s390x.AMOVBZ
-
- case gc.TINT16<<16 | gc.TINT16,
- gc.TUINT16<<16 | gc.TINT16,
- gc.TINT32<<16 | gc.TINT16,
- gc.TUINT32<<16 | gc.TINT16,
- gc.TINT64<<16 | gc.TINT16,
- gc.TUINT64<<16 | gc.TINT16:
- a = s390x.AMOVH
-
- case gc.TINT16<<16 | gc.TUINT16,
- gc.TUINT16<<16 | gc.TUINT16,
- gc.TINT32<<16 | gc.TUINT16,
- gc.TUINT32<<16 | gc.TUINT16,
- gc.TINT64<<16 | gc.TUINT16,
- gc.TUINT64<<16 | gc.TUINT16:
- a = s390x.AMOVHZ
-
- case gc.TINT32<<16 | gc.TINT32,
- gc.TUINT32<<16 | gc.TINT32,
- gc.TINT64<<16 | gc.TINT32,
- gc.TUINT64<<16 | gc.TINT32:
- a = s390x.AMOVW
-
- case gc.TINT32<<16 | gc.TUINT32,
- gc.TUINT32<<16 | gc.TUINT32,
- gc.TINT64<<16 | gc.TUINT32,
- gc.TUINT64<<16 | gc.TUINT32:
- a = s390x.AMOVWZ
-
- case gc.TINT64<<16 | gc.TINT64,
- gc.TINT64<<16 | gc.TUINT64,
- gc.TUINT64<<16 | gc.TINT64,
- gc.TUINT64<<16 | gc.TUINT64:
- a = s390x.AMOVD
-
- // sign extend int8
- case gc.TINT8<<16 | gc.TINT16,
- gc.TINT8<<16 | gc.TUINT16,
- gc.TINT8<<16 | gc.TINT32,
- gc.TINT8<<16 | gc.TUINT32,
- gc.TINT8<<16 | gc.TINT64,
- gc.TINT8<<16 | gc.TUINT64:
- a = s390x.AMOVB
- goto rdst
-
- // sign extend uint8
- case gc.TUINT8<<16 | gc.TINT16,
- gc.TUINT8<<16 | gc.TUINT16,
- gc.TUINT8<<16 | gc.TINT32,
- gc.TUINT8<<16 | gc.TUINT32,
- gc.TUINT8<<16 | gc.TINT64,
- gc.TUINT8<<16 | gc.TUINT64:
- a = s390x.AMOVBZ
- goto rdst
-
- // sign extend int16
- case gc.TINT16<<16 | gc.TINT32,
- gc.TINT16<<16 | gc.TUINT32,
- gc.TINT16<<16 | gc.TINT64,
- gc.TINT16<<16 | gc.TUINT64:
- a = s390x.AMOVH
- goto rdst
-
- // zero extend uint16
- case gc.TUINT16<<16 | gc.TINT32,
- gc.TUINT16<<16 | gc.TUINT32,
- gc.TUINT16<<16 | gc.TINT64,
- gc.TUINT16<<16 | gc.TUINT64:
- a = s390x.AMOVHZ
- goto rdst
-
- // sign extend int32
- case gc.TINT32<<16 | gc.TINT64,
- gc.TINT32<<16 | gc.TUINT64:
- a = s390x.AMOVW
- goto rdst
-
- // zero extend uint32
- case gc.TUINT32<<16 | gc.TINT64,
- gc.TUINT32<<16 | gc.TUINT64:
- a = s390x.AMOVWZ
- goto rdst
-
- // float to integer
- case gc.TFLOAT32<<16 | gc.TUINT8,
- gc.TFLOAT32<<16 | gc.TUINT16:
- cvt = gc.Types[gc.TUINT32]
- goto hard
-
- case gc.TFLOAT32<<16 | gc.TUINT32:
- a = s390x.ACLFEBR
- goto rdst
-
- case gc.TFLOAT32<<16 | gc.TUINT64:
- a = s390x.ACLGEBR
- goto rdst
-
- case gc.TFLOAT64<<16 | gc.TUINT8,
- gc.TFLOAT64<<16 | gc.TUINT16:
- cvt = gc.Types[gc.TUINT32]
- goto hard
-
- case gc.TFLOAT64<<16 | gc.TUINT32:
- a = s390x.ACLFDBR
- goto rdst
-
- case gc.TFLOAT64<<16 | gc.TUINT64:
- a = s390x.ACLGDBR
- goto rdst
-
- case gc.TFLOAT32<<16 | gc.TINT8,
- gc.TFLOAT32<<16 | gc.TINT16:
- cvt = gc.Types[gc.TINT32]
- goto hard
-
- case gc.TFLOAT32<<16 | gc.TINT32:
- a = s390x.ACFEBRA
- goto rdst
-
- case gc.TFLOAT32<<16 | gc.TINT64:
- a = s390x.ACGEBRA
- goto rdst
-
- case gc.TFLOAT64<<16 | gc.TINT8,
- gc.TFLOAT64<<16 | gc.TINT16:
- cvt = gc.Types[gc.TINT32]
- goto hard
-
- case gc.TFLOAT64<<16 | gc.TINT32:
- a = s390x.ACFDBRA
- goto rdst
-
- case gc.TFLOAT64<<16 | gc.TINT64:
- a = s390x.ACGDBRA
- goto rdst
-
- // integer to float
- case gc.TUINT8<<16 | gc.TFLOAT32,
- gc.TUINT16<<16 | gc.TFLOAT32:
- cvt = gc.Types[gc.TUINT32]
- goto hard
-
- case gc.TUINT32<<16 | gc.TFLOAT32:
- a = s390x.ACELFBR
- goto rdst
-
- case gc.TUINT64<<16 | gc.TFLOAT32:
- a = s390x.ACELGBR
- goto rdst
-
- case gc.TUINT8<<16 | gc.TFLOAT64,
- gc.TUINT16<<16 | gc.TFLOAT64:
- cvt = gc.Types[gc.TUINT32]
- goto hard
-
- case gc.TUINT32<<16 | gc.TFLOAT64:
- a = s390x.ACDLFBR
- goto rdst
-
- case gc.TUINT64<<16 | gc.TFLOAT64:
- a = s390x.ACDLGBR
- goto rdst
-
- case gc.TINT8<<16 | gc.TFLOAT32,
- gc.TINT16<<16 | gc.TFLOAT32:
- cvt = gc.Types[gc.TINT32]
- goto hard
-
- case gc.TINT32<<16 | gc.TFLOAT32:
- a = s390x.ACEFBRA
- goto rdst
-
- case gc.TINT64<<16 | gc.TFLOAT32:
- a = s390x.ACEGBRA
- goto rdst
-
- case gc.TINT8<<16 | gc.TFLOAT64,
- gc.TINT16<<16 | gc.TFLOAT64:
- cvt = gc.Types[gc.TINT32]
- goto hard
-
- case gc.TINT32<<16 | gc.TFLOAT64:
- a = s390x.ACDFBRA
- goto rdst
-
- case gc.TINT64<<16 | gc.TFLOAT64:
- a = s390x.ACDGBRA
- goto rdst
-
- // float to float
- case gc.TFLOAT32<<16 | gc.TFLOAT32:
- a = s390x.AFMOVS
-
- case gc.TFLOAT64<<16 | gc.TFLOAT64:
- a = s390x.AFMOVD
-
- case gc.TFLOAT32<<16 | gc.TFLOAT64:
- a = s390x.ALDEBR
- goto rdst
-
- case gc.TFLOAT64<<16 | gc.TFLOAT32:
- a = s390x.ALEDBR
- goto rdst
- }
-
- gins(a, f, t)
- return
-
- // requires register destination
-rdst:
- if t != nil && t.Op == gc.OREGISTER {
- gins(a, f, t)
- return
- } else {
- var r1 gc.Node
- gc.Regalloc(&r1, t.Type, t)
-
- gins(a, f, &r1)
- gmove(&r1, t)
- gc.Regfree(&r1)
- return
- }
-
- // requires register intermediate
-hard:
- var r1 gc.Node
- gc.Regalloc(&r1, cvt, t)
-
- gmove(f, &r1)
- gmove(&r1, t)
- gc.Regfree(&r1)
- return
-}
-
-func intLiteral(n *gc.Node) (x int64, ok bool) {
- switch {
- case n == nil:
- return
- case gc.Isconst(n, gc.CTINT):
- return n.Int64(), true
- case gc.Isconst(n, gc.CTBOOL):
- return int64(obj.Bool2int(n.Bool())), true
- }
- return
-}
-
-// gins is called by the front end.
-// It synthesizes some multiple-instruction sequences
-// so the front end can stay simpler.
-func gins(as obj.As, f, t *gc.Node) *obj.Prog {
- if t != nil {
- if as >= obj.A_ARCHSPECIFIC {
- if x, ok := intLiteral(f); ok {
- ginscon(as, x, t)
- return nil // caller must not use
- }
- }
- if as == s390x.ACMP || as == s390x.ACMPU {
- if x, ok := intLiteral(t); ok {
- ginscon2(as, f, x)
- return nil // caller must not use
- }
- }
- }
- return rawgins(as, f, t)
-}
-
-// generate one instruction:
-// as f, t
-func rawgins(as obj.As, f *gc.Node, t *gc.Node) *obj.Prog {
- // self move check
- // TODO(mundaym): use sized math and extend to MOVB, MOVWZ etc.
- switch as {
- case s390x.AMOVD, s390x.AFMOVS, s390x.AFMOVD:
- if f != nil && t != nil &&
- f.Op == gc.OREGISTER && t.Op == gc.OREGISTER &&
- f.Reg == t.Reg {
- return nil
- }
- }
-
- p := gc.Prog(as)
- gc.Naddr(&p.From, f)
- gc.Naddr(&p.To, t)
-
- switch as {
- // Bad things the front end has done to us. Crash to find call stack.
- case s390x.ACMP, s390x.ACMPU:
- if p.From.Type == obj.TYPE_MEM || p.To.Type == obj.TYPE_MEM {
- gc.Debug['h'] = 1
- gc.Fatalf("bad inst: %v", p)
- }
- }
-
- if gc.Debug['g'] != 0 {
- fmt.Printf("%v\n", p)
- }
-
- w := int32(0)
- switch as {
- case s390x.AMOVB, s390x.AMOVBZ:
- w = 1
-
- case s390x.AMOVH, s390x.AMOVHZ:
- w = 2
-
- case s390x.AMOVW, s390x.AMOVWZ:
- w = 4
-
- case s390x.AMOVD:
- if p.From.Type == obj.TYPE_CONST || p.From.Type == obj.TYPE_ADDR {
- break
- }
- w = 8
- }
-
- if w != 0 && ((f != nil && p.From.Width < int64(w)) || (t != nil && p.To.Type != obj.TYPE_REG && p.To.Width > int64(w))) {
- gc.Dump("f", f)
- gc.Dump("t", t)
- gc.Fatalf("bad width: %v (%d, %d)\n", p, p.From.Width, p.To.Width)
- }
-
- return p
-}
-
-// optoas returns the Axxx equivalent of Oxxx for type t
-func optoas(op gc.Op, t *gc.Type) obj.As {
- if t == nil {
- gc.Fatalf("optoas: t is nil")
- }
-
- // avoid constant conversions in switches below
- const (
- OMINUS_ = uint32(gc.OMINUS) << 16
- OLSH_ = uint32(gc.OLSH) << 16
- ORSH_ = uint32(gc.ORSH) << 16
- OADD_ = uint32(gc.OADD) << 16
- OSUB_ = uint32(gc.OSUB) << 16
- OMUL_ = uint32(gc.OMUL) << 16
- ODIV_ = uint32(gc.ODIV) << 16
- OOR_ = uint32(gc.OOR) << 16
- OAND_ = uint32(gc.OAND) << 16
- OXOR_ = uint32(gc.OXOR) << 16
- OEQ_ = uint32(gc.OEQ) << 16
- ONE_ = uint32(gc.ONE) << 16
- OLT_ = uint32(gc.OLT) << 16
- OLE_ = uint32(gc.OLE) << 16
- OGE_ = uint32(gc.OGE) << 16
- OGT_ = uint32(gc.OGT) << 16
- OCMP_ = uint32(gc.OCMP) << 16
- OAS_ = uint32(gc.OAS) << 16
- OHMUL_ = uint32(gc.OHMUL) << 16
- OSQRT_ = uint32(gc.OSQRT) << 16
- OLROT_ = uint32(gc.OLROT) << 16
- )
-
- a := obj.AXXX
- switch uint32(op)<<16 | uint32(gc.Simtype[t.Etype]) {
- default:
- gc.Fatalf("optoas: no entry for op=%v type=%v", op, t)
-
- case OEQ_ | gc.TBOOL,
- OEQ_ | gc.TINT8,
- OEQ_ | gc.TUINT8,
- OEQ_ | gc.TINT16,
- OEQ_ | gc.TUINT16,
- OEQ_ | gc.TINT32,
- OEQ_ | gc.TUINT32,
- OEQ_ | gc.TINT64,
- OEQ_ | gc.TUINT64,
- OEQ_ | gc.TPTR32,
- OEQ_ | gc.TPTR64,
- OEQ_ | gc.TFLOAT32,
- OEQ_ | gc.TFLOAT64:
- a = s390x.ABEQ
-
- case ONE_ | gc.TBOOL,
- ONE_ | gc.TINT8,
- ONE_ | gc.TUINT8,
- ONE_ | gc.TINT16,
- ONE_ | gc.TUINT16,
- ONE_ | gc.TINT32,
- ONE_ | gc.TUINT32,
- ONE_ | gc.TINT64,
- ONE_ | gc.TUINT64,
- ONE_ | gc.TPTR32,
- ONE_ | gc.TPTR64,
- ONE_ | gc.TFLOAT32,
- ONE_ | gc.TFLOAT64:
- a = s390x.ABNE
-
- case OLT_ | gc.TINT8, // ACMP
- OLT_ | gc.TINT16,
- OLT_ | gc.TINT32,
- OLT_ | gc.TINT64,
- OLT_ | gc.TUINT8,
- // ACMPU
- OLT_ | gc.TUINT16,
- OLT_ | gc.TUINT32,
- OLT_ | gc.TUINT64,
- OLT_ | gc.TFLOAT32,
- // AFCMPU
- OLT_ | gc.TFLOAT64:
- a = s390x.ABLT
-
- case OLE_ | gc.TINT8, // ACMP
- OLE_ | gc.TINT16,
- OLE_ | gc.TINT32,
- OLE_ | gc.TINT64,
- OLE_ | gc.TUINT8,
- // ACMPU
- OLE_ | gc.TUINT16,
- OLE_ | gc.TUINT32,
- OLE_ | gc.TUINT64,
- OLE_ | gc.TFLOAT32,
- OLE_ | gc.TFLOAT64:
- a = s390x.ABLE
-
- case OGT_ | gc.TINT8,
- OGT_ | gc.TINT16,
- OGT_ | gc.TINT32,
- OGT_ | gc.TINT64,
- OGT_ | gc.TUINT8,
- OGT_ | gc.TUINT16,
- OGT_ | gc.TUINT32,
- OGT_ | gc.TUINT64,
- OGT_ | gc.TFLOAT32,
- OGT_ | gc.TFLOAT64:
- a = s390x.ABGT
-
- case OGE_ | gc.TINT8,
- OGE_ | gc.TINT16,
- OGE_ | gc.TINT32,
- OGE_ | gc.TINT64,
- OGE_ | gc.TUINT8,
- OGE_ | gc.TUINT16,
- OGE_ | gc.TUINT32,
- OGE_ | gc.TUINT64,
- OGE_ | gc.TFLOAT32,
- OGE_ | gc.TFLOAT64:
- a = s390x.ABGE
-
- case OCMP_ | gc.TBOOL,
- OCMP_ | gc.TINT8,
- OCMP_ | gc.TINT16,
- OCMP_ | gc.TINT32,
- OCMP_ | gc.TPTR32,
- OCMP_ | gc.TINT64:
- a = s390x.ACMP
-
- case OCMP_ | gc.TUINT8,
- OCMP_ | gc.TUINT16,
- OCMP_ | gc.TUINT32,
- OCMP_ | gc.TUINT64,
- OCMP_ | gc.TPTR64:
- a = s390x.ACMPU
-
- case OCMP_ | gc.TFLOAT32:
- a = s390x.ACEBR
-
- case OCMP_ | gc.TFLOAT64:
- a = s390x.AFCMPU
-
- case OAS_ | gc.TBOOL,
- OAS_ | gc.TINT8:
- a = s390x.AMOVB
-
- case OAS_ | gc.TUINT8:
- a = s390x.AMOVBZ
-
- case OAS_ | gc.TINT16:
- a = s390x.AMOVH
-
- case OAS_ | gc.TUINT16:
- a = s390x.AMOVHZ
-
- case OAS_ | gc.TINT32:
- a = s390x.AMOVW
-
- case OAS_ | gc.TUINT32,
- OAS_ | gc.TPTR32:
- a = s390x.AMOVWZ
-
- case OAS_ | gc.TINT64,
- OAS_ | gc.TUINT64,
- OAS_ | gc.TPTR64:
- a = s390x.AMOVD
-
- case OAS_ | gc.TFLOAT32:
- a = s390x.AFMOVS
-
- case OAS_ | gc.TFLOAT64:
- a = s390x.AFMOVD
-
- case OADD_ | gc.TINT8,
- OADD_ | gc.TUINT8,
- OADD_ | gc.TINT16,
- OADD_ | gc.TUINT16,
- OADD_ | gc.TINT32,
- OADD_ | gc.TUINT32,
- OADD_ | gc.TPTR32,
- OADD_ | gc.TINT64,
- OADD_ | gc.TUINT64,
- OADD_ | gc.TPTR64:
- a = s390x.AADD
-
- case OADD_ | gc.TFLOAT32:
- a = s390x.AFADDS
-
- case OADD_ | gc.TFLOAT64:
- a = s390x.AFADD
-
- case OSUB_ | gc.TINT8,
- OSUB_ | gc.TUINT8,
- OSUB_ | gc.TINT16,
- OSUB_ | gc.TUINT16,
- OSUB_ | gc.TINT32,
- OSUB_ | gc.TUINT32,
- OSUB_ | gc.TPTR32,
- OSUB_ | gc.TINT64,
- OSUB_ | gc.TUINT64,
- OSUB_ | gc.TPTR64:
- a = s390x.ASUB
-
- case OSUB_ | gc.TFLOAT32:
- a = s390x.AFSUBS
-
- case OSUB_ | gc.TFLOAT64:
- a = s390x.AFSUB
-
- case OMINUS_ | gc.TINT8,
- OMINUS_ | gc.TUINT8,
- OMINUS_ | gc.TINT16,
- OMINUS_ | gc.TUINT16,
- OMINUS_ | gc.TINT32,
- OMINUS_ | gc.TUINT32,
- OMINUS_ | gc.TPTR32,
- OMINUS_ | gc.TINT64,
- OMINUS_ | gc.TUINT64,
- OMINUS_ | gc.TPTR64:
- a = s390x.ANEG
-
- case OAND_ | gc.TINT8,
- OAND_ | gc.TUINT8,
- OAND_ | gc.TINT16,
- OAND_ | gc.TUINT16,
- OAND_ | gc.TINT32,
- OAND_ | gc.TUINT32,
- OAND_ | gc.TPTR32,
- OAND_ | gc.TINT64,
- OAND_ | gc.TUINT64,
- OAND_ | gc.TPTR64:
- a = s390x.AAND
-
- case OOR_ | gc.TINT8,
- OOR_ | gc.TUINT8,
- OOR_ | gc.TINT16,
- OOR_ | gc.TUINT16,
- OOR_ | gc.TINT32,
- OOR_ | gc.TUINT32,
- OOR_ | gc.TPTR32,
- OOR_ | gc.TINT64,
- OOR_ | gc.TUINT64,
- OOR_ | gc.TPTR64:
- a = s390x.AOR
-
- case OXOR_ | gc.TINT8,
- OXOR_ | gc.TUINT8,
- OXOR_ | gc.TINT16,
- OXOR_ | gc.TUINT16,
- OXOR_ | gc.TINT32,
- OXOR_ | gc.TUINT32,
- OXOR_ | gc.TPTR32,
- OXOR_ | gc.TINT64,
- OXOR_ | gc.TUINT64,
- OXOR_ | gc.TPTR64:
- a = s390x.AXOR
-
- case OLSH_ | gc.TINT8,
- OLSH_ | gc.TUINT8,
- OLSH_ | gc.TINT16,
- OLSH_ | gc.TUINT16,
- OLSH_ | gc.TINT32,
- OLSH_ | gc.TUINT32,
- OLSH_ | gc.TPTR32,
- OLSH_ | gc.TINT64,
- OLSH_ | gc.TUINT64,
- OLSH_ | gc.TPTR64:
- a = s390x.ASLD
-
- case ORSH_ | gc.TUINT8,
- ORSH_ | gc.TUINT16,
- ORSH_ | gc.TUINT32,
- ORSH_ | gc.TPTR32,
- ORSH_ | gc.TUINT64,
- ORSH_ | gc.TPTR64:
- a = s390x.ASRD
-
- case ORSH_ | gc.TINT8,
- ORSH_ | gc.TINT16,
- ORSH_ | gc.TINT32,
- ORSH_ | gc.TINT64:
- a = s390x.ASRAD
-
- case OHMUL_ | gc.TINT64:
- a = s390x.AMULHD
-
- case OHMUL_ | gc.TUINT64,
- OHMUL_ | gc.TPTR64:
- a = s390x.AMULHDU
-
- case OMUL_ | gc.TINT8,
- OMUL_ | gc.TINT16,
- OMUL_ | gc.TINT32,
- OMUL_ | gc.TINT64:
- a = s390x.AMULLD
-
- case OMUL_ | gc.TUINT8,
- OMUL_ | gc.TUINT16,
- OMUL_ | gc.TUINT32,
- OMUL_ | gc.TPTR32,
- // don't use word multiply, the high 32-bit are undefined.
- OMUL_ | gc.TUINT64,
- OMUL_ | gc.TPTR64:
- // for 64-bit multiplies, signedness doesn't matter.
- a = s390x.AMULLD
-
- case OMUL_ | gc.TFLOAT32:
- a = s390x.AFMULS
-
- case OMUL_ | gc.TFLOAT64:
- a = s390x.AFMUL
-
- case ODIV_ | gc.TINT8,
- ODIV_ | gc.TINT16,
- ODIV_ | gc.TINT32,
- ODIV_ | gc.TINT64:
- a = s390x.ADIVD
-
- case ODIV_ | gc.TUINT8,
- ODIV_ | gc.TUINT16,
- ODIV_ | gc.TUINT32,
- ODIV_ | gc.TPTR32,
- ODIV_ | gc.TUINT64,
- ODIV_ | gc.TPTR64:
- a = s390x.ADIVDU
-
- case ODIV_ | gc.TFLOAT32:
- a = s390x.AFDIVS
-
- case ODIV_ | gc.TFLOAT64:
- a = s390x.AFDIV
-
- case OSQRT_ | gc.TFLOAT64:
- a = s390x.AFSQRT
-
- case OLROT_ | gc.TUINT32,
- OLROT_ | gc.TPTR32,
- OLROT_ | gc.TINT32:
- a = s390x.ARLL
-
- case OLROT_ | gc.TUINT64,
- OLROT_ | gc.TPTR64,
- OLROT_ | gc.TINT64:
- a = s390x.ARLLG
- }
-
- return a
-}
-
-const (
- ODynam = 1 << 0
- OAddable = 1 << 1
-)
-
-var clean [20]gc.Node
-
-var cleani int = 0
-
-func sudoclean() {
- if clean[cleani-1].Op != gc.OEMPTY {
- gc.Regfree(&clean[cleani-1])
- }
- if clean[cleani-2].Op != gc.OEMPTY {
- gc.Regfree(&clean[cleani-2])
- }
- cleani -= 2
-}
-
-/*
- * generate code to compute address of n,
- * a reference to a (perhaps nested) field inside
- * an array or struct.
- * return 0 on failure, 1 on success.
- * on success, leaves usable address in a.
- *
- * caller is responsible for calling sudoclean
- * after successful sudoaddable,
- * to release the register used for a.
- */
-func sudoaddable(as obj.As, n *gc.Node, a *obj.Addr) bool {
- if n.Type == nil {
- return false
- }
-
- *a = obj.Addr{}
-
- switch n.Op {
- case gc.OLITERAL:
- if !gc.Isconst(n, gc.CTINT) {
- return false
- }
- v := n.Int64()
- switch as {
- default:
- return false
-
- // operations that can cope with a 32-bit immediate
- // TODO(mundaym): logical operations can work on high bits
- case s390x.AADD,
- s390x.AADDC,
- s390x.ASUB,
- s390x.AMULLW,
- s390x.AAND,
- s390x.AOR,
- s390x.AXOR,
- s390x.ASLD,
- s390x.ASLW,
- s390x.ASRAW,
- s390x.ASRAD,
- s390x.ASRW,
- s390x.ASRD,
- s390x.AMOVB,
- s390x.AMOVBZ,
- s390x.AMOVH,
- s390x.AMOVHZ,
- s390x.AMOVW,
- s390x.AMOVWZ,
- s390x.AMOVD:
- if int64(int32(v)) != v {
- return false
- }
-
- // for comparisons avoid immediates unless they can
- // fit into a int8/uint8
- // this favours combined compare and branch instructions
- case s390x.ACMP:
- if int64(int8(v)) != v {
- return false
- }
- case s390x.ACMPU:
- if int64(uint8(v)) != v {
- return false
- }
- }
-
- cleani += 2
- reg := &clean[cleani-1]
- reg1 := &clean[cleani-2]
- reg.Op = gc.OEMPTY
- reg1.Op = gc.OEMPTY
- gc.Naddr(a, n)
- return true
-
- case gc.ODOT,
- gc.ODOTPTR:
- cleani += 2
- reg := &clean[cleani-1]
- reg1 := &clean[cleani-2]
- reg.Op = gc.OEMPTY
- reg1.Op = gc.OEMPTY
- var nn *gc.Node
- var oary [10]int64
- o := gc.Dotoffset(n, oary[:], &nn)
- if nn == nil {
- sudoclean()
- return false
- }
-
- if nn.Addable && o == 1 && oary[0] >= 0 {
- // directly addressable set of DOTs
- n1 := *nn
-
- n1.Type = n.Type
- n1.Xoffset += oary[0]
- // check that the offset fits into a 12-bit displacement
- if n1.Xoffset < 0 || n1.Xoffset >= (1<<12)-8 {
- sudoclean()
- return false
- }
- gc.Naddr(a, &n1)
- return true
- }
-
- gc.Regalloc(reg, gc.Types[gc.Tptr], nil)
- n1 := *reg
- n1.Op = gc.OINDREG
- if oary[0] >= 0 {
- gc.Agen(nn, reg)
- n1.Xoffset = oary[0]
- } else {
- gc.Cgen(nn, reg)
- gc.Cgen_checknil(reg)
- n1.Xoffset = -(oary[0] + 1)
- }
-
- for i := 1; i < o; i++ {
- if oary[i] >= 0 {
- gc.Fatalf("can't happen")
- }
- gins(s390x.AMOVD, &n1, reg)
- gc.Cgen_checknil(reg)
- n1.Xoffset = -(oary[i] + 1)
- }
-
- a.Type = obj.TYPE_NONE
- a.Index = 0
- // check that the offset fits into a 12-bit displacement
- if n1.Xoffset < 0 || n1.Xoffset >= (1<<12)-8 {
- tmp := n1
- tmp.Op = gc.OREGISTER
- tmp.Type = gc.Types[gc.Tptr]
- tmp.Xoffset = 0
- gc.Cgen_checknil(&tmp)
- ginscon(s390x.AADD, n1.Xoffset, &tmp)
- n1.Xoffset = 0
- }
- gc.Naddr(a, &n1)
- return true
- }
-
- return false
-}
diff --git a/src/cmd/compile/internal/s390x/peep.go b/src/cmd/compile/internal/s390x/peep.go
deleted file mode 100644
index cd6a8c5..0000000
--- a/src/cmd/compile/internal/s390x/peep.go
+++ /dev/null
@@ -1,1664 +0,0 @@
-// Derived from Inferno utils/6c/peep.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6c/peep.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth at terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth at terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// Portions Copyright © 2009 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-package s390x
-
-import (
- "cmd/compile/internal/gc"
- "cmd/internal/obj"
- "cmd/internal/obj/s390x"
- "fmt"
-)
-
-type usage int
-
-const (
- _None usage = iota // no usage found
- _Read // only read from
- _ReadWriteSame // both read from and written to in a single operand
- _Write // only written to
- _ReadWriteDiff // both read from and written to in different operands
-)
-
-var gactive uint32
-
-func peep(firstp *obj.Prog) {
- g := gc.Flowstart(firstp, nil)
- if g == nil {
- return
- }
- gactive = 0
-
- run := func(name string, pass func(r *gc.Flow) int) int {
- n := pass(g.Start)
- if gc.Debug['P'] != 0 {
- fmt.Println(name, ":", n)
- }
- if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
- gc.Dumpit(name, g.Start, 0)
- }
- return n
- }
-
- for {
- n := 0
- n += run("constant propagation", constantPropagation)
- n += run("copy propagation", copyPropagation)
- n += run("cast propagation", castPropagation)
- n += run("remove load-hit-stores", removeLoadHitStores)
- n += run("dead code elimination", deadCodeElimination)
- if n == 0 {
- break
- }
- }
- run("fuse op moves", fuseOpMoves)
- run("fuse clears", fuseClear)
- run("load pipelining", loadPipelining)
- run("fuse compare branch", fuseCompareBranch)
- run("simplify ops", simplifyOps)
- run("dead code elimination", deadCodeElimination)
-
- // TODO(mundaym): load/store multiple aren't currently handled by copyu
- // so this pass must be last.
- run("fuse multiple", fuseMultiple)
-
- gc.Flowend(g)
-}
-
-func pushback(r0 *gc.Flow) {
- var r *gc.Flow
-
- var b *gc.Flow
- p0 := r0.Prog
- for r = gc.Uniqp(r0); r != nil && gc.Uniqs(r) != nil; r = gc.Uniqp(r) {
- p := r.Prog
- if p.As != obj.ANOP {
- if !(isReg(&p.From) || isConst(&p.From)) || !isReg(&p.To) {
- break
- }
- if copyu(p, &p0.To, nil) != _None || copyu(p0, &p.To, nil) != _None {
- break
- }
- }
-
- if p.As == obj.ACALL {
- break
- }
- b = r
- }
-
- if b == nil {
- if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
- fmt.Printf("no pushback: %v\n", r0.Prog)
- if r != nil {
- fmt.Printf("\t%v [%v]\n", r.Prog, gc.Uniqs(r) != nil)
- }
- }
-
- return
- }
-
- if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
- fmt.Printf("pushback\n")
- for r := b; ; r = r.Link {
- fmt.Printf("\t%v\n", r.Prog)
- if r == r0 {
- break
- }
- }
- }
-
- t := *r0.Prog
- for r = gc.Uniqp(r0); ; r = gc.Uniqp(r) {
- p0 = r.Link.Prog
- p := r.Prog
- p0.As = p.As
- p0.Lineno = p.Lineno
- p0.From = p.From
- p0.To = p.To
- p0.From3 = p.From3
- p0.Reg = p.Reg
- p0.RegTo2 = p.RegTo2
- if r == b {
- break
- }
- }
-
- p0 = r.Prog
- p0.As = t.As
- p0.Lineno = t.Lineno
- p0.From = t.From
- p0.To = t.To
- p0.From3 = t.From3
- p0.Reg = t.Reg
- p0.RegTo2 = t.RegTo2
-
- if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
- fmt.Printf("\tafter\n")
- for r := b; ; r = r.Link {
- fmt.Printf("\t%v\n", r.Prog)
- if r == r0 {
- break
- }
- }
- }
-}
-
-// excise replaces the given instruction with a NOP and clears
-// its operands.
-func excise(r *gc.Flow) {
- p := r.Prog
- if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
- fmt.Printf("%v ===delete===\n", p)
- }
- obj.Nopout(p)
- gc.Ostats.Ndelmov++
-}
-
-// isZero returns true if a is either the constant 0 or the register
-// REGZERO.
-func isZero(a *obj.Addr) bool {
- if a.Type == obj.TYPE_CONST && a.Offset == 0 {
- return true
- }
- if a.Type == obj.TYPE_REG && a.Reg == s390x.REGZERO {
- return true
- }
- return false
-}
-
-// isReg returns true if a is a general purpose or floating point
-// register (GPR or FPR).
-//
-// TODO(mundaym): currently this excludes REGZER0, but not other
-// special registers.
-func isReg(a *obj.Addr) bool {
- return a.Type == obj.TYPE_REG &&
- s390x.REG_R0 <= a.Reg &&
- a.Reg <= s390x.REG_F15 &&
- a.Reg != s390x.REGZERO
-}
-
-// isGPR returns true if a is a general purpose register (GPR).
-// REGZERO is treated as a GPR.
-func isGPR(a *obj.Addr) bool {
- return a.Type == obj.TYPE_REG &&
- s390x.REG_R0 <= a.Reg &&
- a.Reg <= s390x.REG_R15
-}
-
-// isFPR returns true if a is a floating point register (FPR).
-func isFPR(a *obj.Addr) bool {
- return a.Type == obj.TYPE_REG &&
- s390x.REG_F0 <= a.Reg &&
- a.Reg <= s390x.REG_F15
-}
-
-// isConst returns true if a refers to a constant (integer or
-// floating point, not string currently).
-func isConst(a *obj.Addr) bool {
- return a.Type == obj.TYPE_CONST || a.Type == obj.TYPE_FCONST
-}
-
-// isBDMem returns true if a refers to a memory location addressable by a
-// base register (B) and a displacement (D), such as:
-// x+8(R1)
-// and
-// 0(R10)
-// It returns false if the address contains an index register (X) such as:
-// 16(R1)(R2*1)
-// or if a relocation is required.
-func isBDMem(a *obj.Addr) bool {
- return a.Type == obj.TYPE_MEM &&
- a.Index == 0 &&
- (a.Name == obj.NAME_NONE || a.Name == obj.NAME_AUTO || a.Name == obj.NAME_PARAM)
-}
-
-// the idea is to substitute
-// one register for another
-// from one MOV to another
-// MOV a, R1
-// ADD b, R1 / no use of R2
-// MOV R1, R2
-// would be converted to
-// MOV a, R2
-// ADD b, R2
-// MOV R2, R1
-// hopefully, then the former or latter MOV
-// will be eliminated by copy propagation.
-//
-// r0 (the argument, not the register) is the MOV at the end of the
-// above sequences. subprop returns true if it modified any instructions.
-func subprop(r0 *gc.Flow) bool {
- p := r0.Prog
- v1 := &p.From
- if !isReg(v1) {
- return false
- }
- v2 := &p.To
- if !isReg(v2) {
- return false
- }
- cast := false
- switch p.As {
- case s390x.AMOVW, s390x.AMOVWZ,
- s390x.AMOVH, s390x.AMOVHZ,
- s390x.AMOVB, s390x.AMOVBZ:
- cast = true
- }
- for r := gc.Uniqp(r0); r != nil; r = gc.Uniqp(r) {
- if gc.Uniqs(r) == nil {
- break
- }
- p = r.Prog
- switch copyu(p, v1, nil) {
- case _Write, _ReadWriteDiff:
- if p.As == obj.ACALL {
- return false
- }
- if (!cast || p.As == r0.Prog.As) && p.To.Type == v1.Type && p.To.Reg == v1.Reg {
- copysub(&p.To, v1, v2)
- for r = gc.Uniqs(r); r != r0; r = gc.Uniqs(r) {
- p = r.Prog
- copysub(&p.From, v1, v2)
- copysub1(p, v1, v2)
- copysub(&p.To, v1, v2)
- }
- v1.Reg, v2.Reg = v2.Reg, v1.Reg
- return true
- }
- if cast {
- return false
- }
- case _ReadWriteSame:
- if cast {
- return false
- }
- }
- if copyu(p, v2, nil) != _None {
- return false
- }
- }
- return false
-}
-
-// The idea is to remove redundant copies.
-// v1->v2 F=0
-// (use v2 s/v2/v1/)*
-// set v1 F=1
-// use v2 return fail (v1->v2 move must remain)
-// -----------------
-// v1->v2 F=0
-// (use v2 s/v2/v1/)*
-// set v1 F=1
-// set v2 return success (caller can remove v1->v2 move)
-func copyprop(r *gc.Flow) bool {
- p := r.Prog
-
- canSub := false
- switch p.As {
- case s390x.AFMOVS, s390x.AFMOVD, s390x.AMOVD:
- canSub = true
- default:
- for rr := gc.Uniqp(r); rr != nil; rr = gc.Uniqp(rr) {
- if gc.Uniqs(rr) == nil {
- break
- }
- switch copyu(rr.Prog, &p.From, nil) {
- case _Read, _None:
- continue
- }
- // write
- if rr.Prog.As == p.As {
- canSub = true
- }
- break
- }
- }
- if !canSub {
- return false
- }
- if copyas(&p.From, &p.To) {
- return true
- }
-
- gactive++
- return copy1(&p.From, &p.To, r.S1, 0)
-}
-
-// copy1 replaces uses of v2 with v1 starting at r and returns true if
-// all uses were rewritten.
-func copy1(v1 *obj.Addr, v2 *obj.Addr, r *gc.Flow, f int) bool {
- if uint32(r.Active) == gactive {
- return true
- }
- r.Active = int32(gactive)
- for ; r != nil; r = r.S1 {
- p := r.Prog
- if f == 0 && gc.Uniqp(r) == nil {
- // Multiple predecessors; conservatively
- // assume v1 was set on other path
- f = 1
- }
- t := copyu(p, v2, nil)
- switch t {
- case _ReadWriteSame:
- return false
- case _Write:
- return true
- case _Read, _ReadWriteDiff:
- if f != 0 {
- return false
- }
- if copyu(p, v2, v1) != 0 {
- return false
- }
- if t == _ReadWriteDiff {
- return true
- }
- }
- if f == 0 {
- switch copyu(p, v1, nil) {
- case _ReadWriteSame, _ReadWriteDiff, _Write:
- f = 1
- }
- }
- if r.S2 != nil {
- if !copy1(v1, v2, r.S2, f) {
- return false
- }
- }
- }
- return true
-}
-
-// If s==nil, copyu returns the set/use of v in p; otherwise, it
-// modifies p to replace reads of v with reads of s and returns 0 for
-// success or non-zero for failure.
-//
-// If s==nil, copy returns one of the following values:
-// _Read if v only used
-// _ReadWriteSame if v is set and used in one address (read-alter-rewrite;
-// can't substitute)
-// _Write if v is only set
-// _ReadWriteDiff if v is set in one address and used in another (so addresses
-// can be rewritten independently)
-// _None otherwise (not touched)
-func copyu(p *obj.Prog, v *obj.Addr, s *obj.Addr) usage {
- if p.From3Type() != obj.TYPE_NONE && p.From3Type() != obj.TYPE_CONST {
- // Currently we never generate a From3 with anything other than a constant in it.
- fmt.Printf("copyu: From3 (%v) not implemented\n", gc.Ctxt.Dconv(p.From3))
- }
-
- switch p.As {
- default:
- fmt.Printf("copyu: can't find %v\n", obj.Aconv(p.As))
- return _ReadWriteSame
-
- case // read p.From, write p.To
- s390x.AMOVH,
- s390x.AMOVHZ,
- s390x.AMOVB,
- s390x.AMOVBZ,
- s390x.AMOVW,
- s390x.AMOVWZ,
- s390x.AMOVD,
- s390x.ANEG,
- s390x.AADDME,
- s390x.AADDZE,
- s390x.ASUBME,
- s390x.ASUBZE,
- s390x.AFMOVS,
- s390x.AFMOVD,
- s390x.ALEDBR,
- s390x.AFNEG,
- s390x.ALDEBR,
- s390x.ACLFEBR,
- s390x.ACLGEBR,
- s390x.ACLFDBR,
- s390x.ACLGDBR,
- s390x.ACFEBRA,
- s390x.ACGEBRA,
- s390x.ACFDBRA,
- s390x.ACGDBRA,
- s390x.ACELFBR,
- s390x.ACELGBR,
- s390x.ACDLFBR,
- s390x.ACDLGBR,
- s390x.ACEFBRA,
- s390x.ACEGBRA,
- s390x.ACDFBRA,
- s390x.ACDGBRA,
- s390x.AFSQRT:
-
- if s != nil {
- copysub(&p.From, v, s)
-
- // Update only indirect uses of v in p.To
- if !copyas(&p.To, v) {
- copysub(&p.To, v, s)
- }
- return _None
- }
-
- if copyas(&p.To, v) {
- // Fix up implicit from
- if p.From.Type == obj.TYPE_NONE {
- p.From = p.To
- }
- if copyau(&p.From, v) {
- return _ReadWriteDiff
- }
- return _Write
- }
-
- if copyau(&p.From, v) {
- return _Read
- }
- if copyau(&p.To, v) {
- // p.To only indirectly uses v
- return _Read
- }
-
- return _None
-
- // read p.From, read p.Reg, write p.To
- case s390x.AADD,
- s390x.AADDC,
- s390x.AADDE,
- s390x.ASUB,
- s390x.ASLW,
- s390x.ASRW,
- s390x.ASRAW,
- s390x.ASLD,
- s390x.ASRD,
- s390x.ASRAD,
- s390x.ARLL,
- s390x.ARLLG,
- s390x.AOR,
- s390x.AORN,
- s390x.AAND,
- s390x.AANDN,
- s390x.ANAND,
- s390x.ANOR,
- s390x.AXOR,
- s390x.AMULLW,
- s390x.AMULLD,
- s390x.AMULHD,
- s390x.AMULHDU,
- s390x.ADIVW,
- s390x.ADIVD,
- s390x.ADIVWU,
- s390x.ADIVDU,
- s390x.AFADDS,
- s390x.AFADD,
- s390x.AFSUBS,
- s390x.AFSUB,
- s390x.AFMULS,
- s390x.AFMUL,
- s390x.AFDIVS,
- s390x.AFDIV:
- if s != nil {
- copysub(&p.From, v, s)
- copysub1(p, v, s)
-
- // Update only indirect uses of v in p.To
- if !copyas(&p.To, v) {
- copysub(&p.To, v, s)
- }
- }
-
- if copyas(&p.To, v) {
- if p.Reg == 0 {
- p.Reg = p.To.Reg
- }
- if copyau(&p.From, v) || copyau1(p, v) {
- return _ReadWriteDiff
- }
- return _Write
- }
-
- if copyau(&p.From, v) {
- return _Read
- }
- if copyau1(p, v) {
- return _Read
- }
- if copyau(&p.To, v) {
- return _Read
- }
- return _None
-
- case s390x.ABEQ,
- s390x.ABGT,
- s390x.ABGE,
- s390x.ABLT,
- s390x.ABLE,
- s390x.ABNE,
- s390x.ABVC,
- s390x.ABVS:
- return _None
-
- case obj.ACHECKNIL, // read p.From
- s390x.ACMP, // read p.From, read p.To
- s390x.ACMPU,
- s390x.ACMPW,
- s390x.ACMPWU,
- s390x.AFCMPO,
- s390x.AFCMPU,
- s390x.ACEBR,
- s390x.AMVC,
- s390x.ACLC,
- s390x.AXC,
- s390x.AOC,
- s390x.ANC:
- if s != nil {
- copysub(&p.From, v, s)
- copysub(&p.To, v, s)
- return _None
- }
-
- if copyau(&p.From, v) {
- return _Read
- }
- if copyau(&p.To, v) {
- return _Read
- }
- return _None
-
- case s390x.ACMPBNE, s390x.ACMPBEQ,
- s390x.ACMPBLT, s390x.ACMPBLE,
- s390x.ACMPBGT, s390x.ACMPBGE,
- s390x.ACMPUBNE, s390x.ACMPUBEQ,
- s390x.ACMPUBLT, s390x.ACMPUBLE,
- s390x.ACMPUBGT, s390x.ACMPUBGE:
- if s != nil {
- copysub(&p.From, v, s)
- copysub1(p, v, s)
- return _None
- }
- if copyau(&p.From, v) {
- return _Read
- }
- if copyau1(p, v) {
- return _Read
- }
- return _None
-
- case s390x.ACLEAR:
- if s != nil {
- copysub(&p.To, v, s)
- return _None
- }
- if copyau(&p.To, v) {
- return _Read
- }
- return _None
-
- // go never generates a branch to a GPR
- // read p.To
- case s390x.ABR:
- if s != nil {
- copysub(&p.To, v, s)
- return _None
- }
-
- if copyau(&p.To, v) {
- return _Read
- }
- return _None
-
- case obj.ARET, obj.AUNDEF:
- if s != nil {
- return _None
- }
-
- // All registers die at this point, so claim
- // everything is set (and not used).
- return _Write
-
- case s390x.ABL:
- if v.Type == obj.TYPE_REG {
- if s390x.REGARG != -1 && v.Reg == s390x.REGARG {
- return _ReadWriteSame
- }
- if p.From.Type == obj.TYPE_REG && p.From.Reg == v.Reg {
- return _ReadWriteSame
- }
- if v.Reg == s390x.REGZERO {
- // Deliberately inserted nops set R0.
- return _ReadWriteSame
- }
- if v.Reg == s390x.REGCTXT {
- // Context register for closures.
- // TODO(mundaym): not sure if we need to exclude this.
- return _ReadWriteSame
- }
- }
- if s != nil {
- copysub(&p.To, v, s)
- return _None
- }
- if copyau(&p.To, v) {
- return _ReadWriteDiff
- }
- return _Write
-
- case obj.ATEXT:
- if v.Type == obj.TYPE_REG {
- if v.Reg == s390x.REGARG {
- return _Write
- }
- }
- return _None
-
- case obj.APCDATA,
- obj.AFUNCDATA,
- obj.AVARDEF,
- obj.AVARKILL,
- obj.AVARLIVE,
- obj.AUSEFIELD,
- obj.ANOP:
- return _None
- }
-}
-
-// copyas returns 1 if a and v address the same register.
-//
-// If a is the from operand, this means this operation reads the
-// register in v. If a is the to operand, this means this operation
-// writes the register in v.
-func copyas(a *obj.Addr, v *obj.Addr) bool {
- if isReg(v) {
- if a.Type == v.Type {
- if a.Reg == v.Reg {
- return true
- }
- }
- }
- return false
-}
-
-// copyau returns 1 if a either directly or indirectly addresses the
-// same register as v.
-//
-// If a is the from operand, this means this operation reads the
-// register in v. If a is the to operand, this means the operation
-// either reads or writes the register in v (if !copyas(a, v), then
-// the operation reads the register in v).
-func copyau(a *obj.Addr, v *obj.Addr) bool {
- if copyas(a, v) {
- return true
- }
- if v.Type == obj.TYPE_REG {
- if a.Type == obj.TYPE_MEM || (a.Type == obj.TYPE_ADDR && a.Reg != 0) {
- if v.Reg == a.Reg {
- return true
- }
- }
- }
- return false
-}
-
-// copyau1 returns 1 if p.Reg references the same register as v and v
-// is a direct reference.
-func copyau1(p *obj.Prog, v *obj.Addr) bool {
- if isReg(v) && v.Reg != 0 {
- if p.Reg == v.Reg {
- return true
- }
- }
- return false
-}
-
-// copysub replaces v.Reg with s.Reg if a.Reg and v.Reg are direct
-// references to the same register.
-func copysub(a, v, s *obj.Addr) {
- if copyau(a, v) {
- a.Reg = s.Reg
- }
-}
-
-// copysub1 replaces p.Reg with s.Reg if p.Reg and v.Reg are direct
-// references to the same register.
-func copysub1(p *obj.Prog, v, s *obj.Addr) {
- if copyau1(p, v) {
- p.Reg = s.Reg
- }
-}
-
-func sameaddr(a *obj.Addr, v *obj.Addr) bool {
- if a.Type != v.Type {
- return false
- }
- if isReg(v) && a.Reg == v.Reg {
- return true
- }
- if v.Type == obj.NAME_AUTO || v.Type == obj.NAME_PARAM {
- // TODO(mundaym): is the offset enough here? Node?
- if v.Offset == a.Offset {
- return true
- }
- }
- return false
-}
-
-func smallindir(a *obj.Addr, reg *obj.Addr) bool {
- return reg.Type == obj.TYPE_REG &&
- a.Type == obj.TYPE_MEM &&
- a.Reg == reg.Reg &&
- 0 <= a.Offset && a.Offset < 4096
-}
-
-func stackaddr(a *obj.Addr) bool {
- // TODO(mundaym): the name implies this should check
- // for TYPE_ADDR with a base register REGSP.
- return a.Type == obj.TYPE_REG && a.Reg == s390x.REGSP
-}
-
-// isMove returns true if p is a move. Moves may imply
-// sign/zero extension.
-func isMove(p *obj.Prog) bool {
- switch p.As {
- case s390x.AMOVD,
- s390x.AMOVW, s390x.AMOVWZ,
- s390x.AMOVH, s390x.AMOVHZ,
- s390x.AMOVB, s390x.AMOVBZ,
- s390x.AFMOVD, s390x.AFMOVS:
- return true
- }
- return false
-}
-
-// isLoad returns true if p is a move from memory to a register.
-func isLoad(p *obj.Prog) bool {
- if !isMove(p) {
- return false
- }
- if !(isGPR(&p.To) || isFPR(&p.To)) {
- return false
- }
- if p.From.Type != obj.TYPE_MEM {
- return false
- }
- return true
-}
-
-// isStore returns true if p is a move from a register to memory.
-func isStore(p *obj.Prog) bool {
- if !isMove(p) {
- return false
- }
- if !(isGPR(&p.From) || isFPR(&p.From) || isConst(&p.From)) {
- return false
- }
- if p.To.Type != obj.TYPE_MEM {
- return false
- }
- return true
-}
-
-// sameStackMem returns true if a and b are both memory operands
-// and address the same location which must reside on the stack.
-func sameStackMem(a, b *obj.Addr) bool {
- if a.Type != obj.TYPE_MEM ||
- b.Type != obj.TYPE_MEM ||
- a.Name != b.Name ||
- a.Sym != b.Sym ||
- a.Node != b.Node ||
- a.Reg != b.Reg ||
- a.Index != b.Index ||
- a.Offset != b.Offset {
- return false
- }
- switch a.Name {
- case obj.NAME_NONE:
- return a.Reg == s390x.REGSP
- case obj.NAME_PARAM, obj.NAME_AUTO:
- // params and autos are always on the stack
- return true
- }
- return false
-}
-
-// removeLoadHitStores trys to remove loads that take place
-// immediately after a store to the same location. Returns
-// true if load-hit-stores were removed.
-//
-// For example:
-// MOVD R1, 0(R15)
-// MOVD 0(R15), R2
-// Would become:
-// MOVD R1, 0(R15)
-// MOVD R1, R2
-func removeLoadHitStores(r *gc.Flow) int {
- n := 0
- for ; r != nil; r = r.Link {
- p := r.Prog
- if !isStore(p) {
- continue
- }
- for rr := gc.Uniqs(r); rr != nil; rr = gc.Uniqs(rr) {
- pp := rr.Prog
- if gc.Uniqp(rr) == nil {
- break
- }
- if pp.As == obj.ANOP {
- continue
- }
- if isLoad(pp) && sameStackMem(&p.To, &pp.From) {
- if size(p.As) >= size(pp.As) && isGPR(&p.From) == isGPR(&pp.To) {
- pp.From = p.From
- }
- }
- if !isMove(pp) || isStore(pp) {
- break
- }
- if copyau(&p.From, &pp.To) {
- break
- }
- }
- }
- return n
-}
-
-// size returns the width of the given move.
-func size(as obj.As) int {
- switch as {
- case s390x.AMOVD, s390x.AFMOVD:
- return 8
- case s390x.AMOVW, s390x.AMOVWZ, s390x.AFMOVS:
- return 4
- case s390x.AMOVH, s390x.AMOVHZ:
- return 2
- case s390x.AMOVB, s390x.AMOVBZ:
- return 1
- }
- return -1
-}
-
-// castPropagation tries to eliminate unecessary casts.
-//
-// For example:
-// MOVHZ R1, R2 // uint16
-// MOVB R2, 0(R15) // int8
-// Can be simplified to:
-// MOVB R1, 0(R15)
-func castPropagation(r *gc.Flow) int {
- n := 0
- for ; r != nil; r = r.Link {
- p := r.Prog
- if !isMove(p) || !isGPR(&p.To) {
- continue
- }
-
- // r is a move with a destination register
- var move *gc.Flow
- for rr := gc.Uniqs(r); rr != nil; rr = gc.Uniqs(rr) {
- if gc.Uniqp(rr) == nil {
- // branch target: leave alone
- break
- }
- pp := rr.Prog
- if isMove(pp) && copyas(&pp.From, &p.To) {
- if pp.To.Type == obj.TYPE_MEM {
- if p.From.Type == obj.TYPE_MEM ||
- p.From.Type == obj.TYPE_ADDR {
- break
- }
- if p.From.Type == obj.TYPE_CONST &&
- int64(int16(p.From.Offset)) != p.From.Offset {
- break
- }
- }
- move = rr
- break
- }
- if pp.As == obj.ANOP {
- continue
- }
- break
- }
- if move == nil {
- continue
- }
-
- // we have a move that reads from our destination reg, check if any future
- // instructions also read from the reg
- mp := move.Prog
- if !copyas(&mp.From, &mp.To) {
- safe := false
- for rr := gc.Uniqs(move); rr != nil; rr = gc.Uniqs(rr) {
- if gc.Uniqp(rr) == nil {
- break
- }
- switch copyu(rr.Prog, &p.To, nil) {
- case _None:
- continue
- case _Write:
- safe = true
- }
- break
- }
- if !safe {
- continue
- }
- }
-
- // at this point we have something like:
- // MOV* const/mem/reg, reg
- // MOV* reg, reg/mem
- // now check if this is a cast that cannot be forward propagated
- execute := false
- if p.As == mp.As || isZero(&p.From) || size(p.As) == size(mp.As) {
- execute = true
- } else if isGPR(&p.From) && size(p.As) >= size(mp.As) {
- execute = true
- }
-
- if execute {
- mp.From = p.From
- excise(r)
- n++
- }
- }
- return n
-}
-
-// fuseClear merges memory clear operations.
-//
-// Looks for this pattern (sequence of clears):
-// MOVD R0, n(R15)
-// MOVD R0, n+8(R15)
-// MOVD R0, n+16(R15)
-// Replaces with:
-// CLEAR $24, n(R15)
-func fuseClear(r *gc.Flow) int {
- n := 0
- var align int64
- var clear *obj.Prog
- for ; r != nil; r = r.Link {
- // If there is a branch into the instruction stream then
- // we can't fuse into previous instructions.
- if gc.Uniqp(r) == nil {
- clear = nil
- }
-
- p := r.Prog
- if p.As == obj.ANOP {
- continue
- }
- if p.As == s390x.AXC {
- if p.From.Reg == p.To.Reg && p.From.Offset == p.To.Offset {
- // TODO(mundaym): merge clears?
- p.As = s390x.ACLEAR
- p.From.Offset = p.From3.Offset
- p.From3 = nil
- p.From.Type = obj.TYPE_CONST
- p.From.Reg = 0
- clear = p
- } else {
- clear = nil
- }
- continue
- }
-
- // Is our source a constant zero?
- if !isZero(&p.From) {
- clear = nil
- continue
- }
-
- // Are we moving to memory?
- if p.To.Type != obj.TYPE_MEM ||
- p.To.Index != 0 ||
- p.To.Offset >= 4096 ||
- !(p.To.Name == obj.NAME_NONE || p.To.Name == obj.NAME_AUTO || p.To.Name == obj.NAME_PARAM) {
- clear = nil
- continue
- }
-
- size := int64(0)
- switch p.As {
- default:
- clear = nil
- continue
- case s390x.AMOVB, s390x.AMOVBZ:
- size = 1
- case s390x.AMOVH, s390x.AMOVHZ:
- size = 2
- case s390x.AMOVW, s390x.AMOVWZ:
- size = 4
- case s390x.AMOVD:
- size = 8
- }
-
- // doubleword aligned clears should be kept doubleword
- // aligned
- if (size == 8 && align != 8) || (size != 8 && align == 8) {
- clear = nil
- }
-
- if clear != nil &&
- clear.To.Reg == p.To.Reg &&
- clear.To.Name == p.To.Name &&
- clear.To.Node == p.To.Node &&
- clear.To.Sym == p.To.Sym {
-
- min := clear.To.Offset
- max := clear.To.Offset + clear.From.Offset
-
- // previous clear is already clearing this region
- if min <= p.To.Offset && max >= p.To.Offset+size {
- excise(r)
- n++
- continue
- }
-
- // merge forwards
- if max == p.To.Offset {
- clear.From.Offset += size
- excise(r)
- n++
- continue
- }
-
- // merge backwards
- if min-size == p.To.Offset {
- clear.From.Offset += size
- clear.To.Offset -= size
- excise(r)
- n++
- continue
- }
- }
-
- // transform into clear
- p.From.Type = obj.TYPE_CONST
- p.From.Offset = size
- p.From.Reg = 0
- p.As = s390x.ACLEAR
- clear = p
- align = size
- }
- return n
-}
-
-// fuseMultiple merges memory loads and stores into load multiple and
-// store multiple operations.
-//
-// Looks for this pattern (sequence of loads or stores):
-// MOVD R1, 0(R15)
-// MOVD R2, 8(R15)
-// MOVD R3, 16(R15)
-// Replaces with:
-// STMG R1, R3, 0(R15)
-func fuseMultiple(r *gc.Flow) int {
- n := 0
- var fused *obj.Prog
- for ; r != nil; r = r.Link {
- // If there is a branch into the instruction stream then
- // we can't fuse into previous instructions.
- if gc.Uniqp(r) == nil {
- fused = nil
- }
-
- p := r.Prog
-
- isStore := isGPR(&p.From) && isBDMem(&p.To)
- isLoad := isGPR(&p.To) && isBDMem(&p.From)
-
- // are we a candidate?
- size := int64(0)
- switch p.As {
- default:
- fused = nil
- continue
- case obj.ANOP:
- // skip over nops
- continue
- case s390x.AMOVW, s390x.AMOVWZ:
- size = 4
- // TODO(mundaym): 32-bit load multiple is currently not supported
- // as it requires sign/zero extension.
- if !isStore {
- fused = nil
- continue
- }
- case s390x.AMOVD:
- size = 8
- if !isLoad && !isStore {
- fused = nil
- continue
- }
- }
-
- // If we merge two loads/stores with different source/destination Nodes
- // then we will lose a reference the second Node which means that the
- // compiler might mark the Node as unused and free its slot on the stack.
- // TODO(mundaym): allow this by adding a dummy reference to the Node.
- if fused == nil ||
- fused.From.Node != p.From.Node ||
- fused.From.Type != p.From.Type ||
- fused.To.Node != p.To.Node ||
- fused.To.Type != p.To.Type {
- fused = p
- continue
- }
-
- // check two addresses
- ca := func(a, b *obj.Addr, offset int64) bool {
- return a.Reg == b.Reg && a.Offset+offset == b.Offset &&
- a.Sym == b.Sym && a.Name == b.Name
- }
-
- switch fused.As {
- default:
- fused = p
- case s390x.AMOVW, s390x.AMOVWZ:
- if size == 4 && fused.From.Reg+1 == p.From.Reg && ca(&fused.To, &p.To, 4) {
- fused.As = s390x.ASTMY
- fused.Reg = p.From.Reg
- excise(r)
- n++
- } else {
- fused = p
- }
- case s390x.AMOVD:
- if size == 8 && fused.From.Reg+1 == p.From.Reg && ca(&fused.To, &p.To, 8) {
- fused.As = s390x.ASTMG
- fused.Reg = p.From.Reg
- excise(r)
- n++
- } else if size == 8 && fused.To.Reg+1 == p.To.Reg && ca(&fused.From, &p.From, 8) {
- fused.As = s390x.ALMG
- fused.Reg = fused.To.Reg
- fused.To.Reg = p.To.Reg
- excise(r)
- n++
- } else {
- fused = p
- }
- case s390x.ASTMG, s390x.ASTMY:
- if (fused.As == s390x.ASTMY && size != 4) ||
- (fused.As == s390x.ASTMG && size != 8) {
- fused = p
- continue
- }
- offset := size * int64(fused.Reg-fused.From.Reg+1)
- if fused.Reg+1 == p.From.Reg && ca(&fused.To, &p.To, offset) {
- fused.Reg = p.From.Reg
- excise(r)
- n++
- } else {
- fused = p
- }
- case s390x.ALMG:
- offset := 8 * int64(fused.To.Reg-fused.Reg+1)
- if size == 8 && fused.To.Reg+1 == p.To.Reg && ca(&fused.From, &p.From, offset) {
- fused.To.Reg = p.To.Reg
- excise(r)
- n++
- } else {
- fused = p
- }
- }
- }
- return n
-}
-
-// simplifyOps looks for side-effect free ops that can be removed or
-// replaced with moves.
-//
-// For example:
-// XOR $0, R1 => NOP
-// ADD $0, R1, R2 => MOVD R1, R2
-func simplifyOps(r *gc.Flow) int {
- n := 0
- for ; r != nil; r = r.Link {
- p := r.Prog
-
- // if the target is R0 then this is a required NOP
- if isGPR(&p.To) && p.To.Reg == s390x.REGZERO {
- continue
- }
-
- switch p.As {
- case s390x.AADD, s390x.ASUB,
- s390x.AOR, s390x.AXOR,
- s390x.ASLW, s390x.ASRW, s390x.ASRAW,
- s390x.ASLD, s390x.ASRD, s390x.ASRAD,
- s390x.ARLL, s390x.ARLLG:
- if isZero(&p.From) && isGPR(&p.To) {
- if p.Reg == 0 || p.Reg == p.To.Reg {
- excise(r)
- n++
- } else {
- p.As = s390x.AMOVD
- p.From.Type = obj.TYPE_REG
- p.From.Reg = p.Reg
- p.Reg = 0
- }
- }
- case s390x.AMULLW, s390x.AAND:
- if isZero(&p.From) && isGPR(&p.To) {
- p.As = s390x.AMOVD
- p.From.Type = obj.TYPE_REG
- p.From.Reg = s390x.REGZERO
- p.Reg = 0
- }
- }
- }
- return n
-}
-
-// fuseOpMoves looks for moves following 2-operand operations and trys to merge them into
-// a 3-operand operation.
-//
-// For example:
-// ADD R1, R2
-// MOVD R2, R3
-// might become
-// ADD R1, R2, R3
-func fuseOpMoves(r *gc.Flow) int {
- n := 0
- for ; r != nil; r = r.Link {
- p := r.Prog
- switch p.As {
- case s390x.AADD:
- case s390x.ASUB:
- if isConst(&p.From) && int64(int16(p.From.Offset)) != p.From.Offset {
- continue
- }
- case s390x.ASLW,
- s390x.ASRW,
- s390x.ASRAW,
- s390x.ASLD,
- s390x.ASRD,
- s390x.ASRAD,
- s390x.ARLL,
- s390x.ARLLG:
- // ok - p.From will be a reg or a constant
- case s390x.AOR,
- s390x.AORN,
- s390x.AAND,
- s390x.AANDN,
- s390x.ANAND,
- s390x.ANOR,
- s390x.AXOR,
- s390x.AMULLW,
- s390x.AMULLD:
- if isConst(&p.From) {
- // these instructions can either use 3 register form
- // or have an immediate but not both
- continue
- }
- default:
- continue
- }
-
- if p.Reg != 0 && p.Reg != p.To.Reg {
- continue
- }
-
- var move *gc.Flow
- rr := gc.Uniqs(r)
- for {
- if rr == nil || gc.Uniqp(rr) == nil || rr == r {
- break
- }
- pp := rr.Prog
- switch copyu(pp, &p.To, nil) {
- case _None:
- rr = gc.Uniqs(rr)
- continue
- case _Read:
- if move == nil && pp.As == s390x.AMOVD && isGPR(&pp.From) && isGPR(&pp.To) {
- move = rr
- rr = gc.Uniqs(rr)
- continue
- }
- case _Write:
- if move == nil {
- // dead code
- excise(r)
- n++
- } else {
- for prev := gc.Uniqp(move); prev != r; prev = gc.Uniqp(prev) {
- if copyu(prev.Prog, &move.Prog.To, nil) != 0 {
- move = nil
- break
- }
- }
- if move == nil {
- break
- }
- p.Reg, p.To.Reg = p.To.Reg, move.Prog.To.Reg
- excise(move)
- n++
-
- // clean up
- if p.From.Reg == p.To.Reg && isCommutative(p.As) {
- p.From.Reg, p.Reg = p.Reg, 0
- }
- if p.To.Reg == p.Reg {
- p.Reg = 0
- }
- // we could try again if p has become a 2-operand op
- // but in testing nothing extra was extracted
- }
- }
- break
- }
- }
- return n
-}
-
-// isCommutative returns true if the order of input operands
-// does not affect the result. For example:
-// x + y == y + x so ADD is commutative
-// x ^ y == y ^ x so XOR is commutative
-func isCommutative(as obj.As) bool {
- switch as {
- case s390x.AADD,
- s390x.AOR,
- s390x.AAND,
- s390x.AXOR,
- s390x.AMULLW,
- s390x.AMULLD:
- return true
- }
- return false
-}
-
-// applyCast applies the cast implied by the given move
-// instruction to v and returns the result.
-func applyCast(cast obj.As, v int64) int64 {
- switch cast {
- case s390x.AMOVWZ:
- return int64(uint32(v))
- case s390x.AMOVHZ:
- return int64(uint16(v))
- case s390x.AMOVBZ:
- return int64(uint8(v))
- case s390x.AMOVW:
- return int64(int32(v))
- case s390x.AMOVH:
- return int64(int16(v))
- case s390x.AMOVB:
- return int64(int8(v))
- }
- return v
-}
-
-// constantPropagation removes redundant constant copies.
-func constantPropagation(r *gc.Flow) int {
- n := 0
- // find MOV $con,R followed by
- // another MOV $con,R without
- // setting R in the interim
- for ; r != nil; r = r.Link {
- p := r.Prog
- if isMove(p) {
- if !isReg(&p.To) {
- continue
- }
- if !isConst(&p.From) {
- continue
- }
- } else {
- continue
- }
-
- rr := r
- for {
- rr = gc.Uniqs(rr)
- if rr == nil || rr == r {
- break
- }
- if gc.Uniqp(rr) == nil {
- break
- }
-
- pp := rr.Prog
- t := copyu(pp, &p.To, nil)
- switch t {
- case _None:
- continue
- case _Read:
- if !isGPR(&pp.From) || !isMove(pp) {
- continue
- }
- if p.From.Type == obj.TYPE_CONST {
- v := applyCast(p.As, p.From.Offset)
- if isGPR(&pp.To) {
- if int64(int32(v)) == v || ((v>>32)<<32) == v {
- pp.From.Reg = 0
- pp.From.Offset = v
- pp.From.Type = obj.TYPE_CONST
- n++
- }
- } else if int64(int16(v)) == v {
- pp.From.Reg = 0
- pp.From.Offset = v
- pp.From.Type = obj.TYPE_CONST
- n++
- }
- }
- continue
- case _Write:
- if p.As != pp.As || p.From.Type != pp.From.Type {
- break
- }
- if p.From.Type == obj.TYPE_CONST && p.From.Offset == pp.From.Offset {
- excise(rr)
- n++
- continue
- } else if p.From.Type == obj.TYPE_FCONST {
- if p.From.Val.(float64) == pp.From.Val.(float64) {
- excise(rr)
- n++
- continue
- }
- }
- }
- break
- }
- }
- return n
-}
-
-// copyPropagation tries to eliminate register-to-register moves.
-func copyPropagation(r *gc.Flow) int {
- n := 0
- for ; r != nil; r = r.Link {
- p := r.Prog
- if isMove(p) && isReg(&p.To) {
- // Convert uses to $0 to uses of R0 and
- // propagate R0
- if isGPR(&p.To) && isZero(&p.From) {
- p.From.Type = obj.TYPE_REG
- p.From.Reg = s390x.REGZERO
- }
-
- // Try to eliminate reg->reg moves
- if isGPR(&p.From) || isFPR(&p.From) {
- if copyprop(r) || (subprop(r) && copyprop(r)) {
- excise(r)
- n++
- }
- }
- }
- }
- return n
-}
-
-// loadPipelining pushes any load from memory as early as possible.
-func loadPipelining(r *gc.Flow) int {
- for ; r != nil; r = r.Link {
- p := r.Prog
- if isLoad(p) {
- pushback(r)
- }
- }
- return 0
-}
-
-// fuseCompareBranch finds comparisons followed by a branch and converts
-// them into a compare-and-branch instruction (which avoid setting the
-// condition code).
-func fuseCompareBranch(r *gc.Flow) int {
- n := 0
- for ; r != nil; r = r.Link {
- p := r.Prog
- r1 := gc.Uniqs(r)
- if r1 == nil {
- continue
- }
- p1 := r1.Prog
-
- var ins obj.As
- switch p.As {
- case s390x.ACMP:
- switch p1.As {
- case s390x.ABCL, s390x.ABC:
- continue
- case s390x.ABEQ:
- ins = s390x.ACMPBEQ
- case s390x.ABGE:
- ins = s390x.ACMPBGE
- case s390x.ABGT:
- ins = s390x.ACMPBGT
- case s390x.ABLE:
- ins = s390x.ACMPBLE
- case s390x.ABLT:
- ins = s390x.ACMPBLT
- case s390x.ABNE:
- ins = s390x.ACMPBNE
- default:
- continue
- }
-
- case s390x.ACMPU:
- switch p1.As {
- case s390x.ABCL, s390x.ABC:
- continue
- case s390x.ABEQ:
- ins = s390x.ACMPUBEQ
- case s390x.ABGE:
- ins = s390x.ACMPUBGE
- case s390x.ABGT:
- ins = s390x.ACMPUBGT
- case s390x.ABLE:
- ins = s390x.ACMPUBLE
- case s390x.ABLT:
- ins = s390x.ACMPUBLT
- case s390x.ABNE:
- ins = s390x.ACMPUBNE
- default:
- continue
- }
-
- case s390x.ACMPW, s390x.ACMPWU:
- continue
-
- default:
- continue
- }
-
- if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
- fmt.Printf("cnb %v; %v ", p, p1)
- }
-
- if p1.To.Sym != nil {
- continue
- }
-
- if p.To.Type == obj.TYPE_REG {
- p1.As = ins
- p1.From = p.From
- p1.Reg = p.To.Reg
- p1.From3 = nil
- } else if p.To.Type == obj.TYPE_CONST {
- switch p.As {
- case s390x.ACMP, s390x.ACMPW:
- if (p.To.Offset < -(1 << 7)) || (p.To.Offset >= ((1 << 7) - 1)) {
- continue
- }
- case s390x.ACMPU, s390x.ACMPWU:
- if p.To.Offset >= (1 << 8) {
- continue
- }
- default:
- }
- p1.As = ins
- p1.From = p.From
- p1.Reg = 0
- p1.From3 = new(obj.Addr)
- *(p1.From3) = p.To
- } else {
- continue
- }
-
- if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
- fmt.Printf("%v\n", p1)
- }
- excise(r)
- n++
- }
- return n
-}
-
-// deadCodeElimination removes writes to registers which are written
-// to again before they are next read.
-func deadCodeElimination(r *gc.Flow) int {
- n := 0
- for ; r != nil; r = r.Link {
- p := r.Prog
- // Currently there are no instructions which write to multiple
- // registers in copyu. This check will need to change if there
- // ever are.
- if !(isGPR(&p.To) || isFPR(&p.To)) || copyu(p, &p.To, nil) != _Write {
- continue
- }
- for rr := gc.Uniqs(r); rr != nil; rr = gc.Uniqs(rr) {
- t := copyu(rr.Prog, &p.To, nil)
- if t == _None {
- continue
- }
- if t == _Write {
- excise(r)
- n++
- }
- break
- }
- }
- return n
-}
diff --git a/src/cmd/compile/internal/s390x/prog.go b/src/cmd/compile/internal/s390x/prog.go
index 306adf8..f356617 100644
--- a/src/cmd/compile/internal/s390x/prog.go
+++ b/src/cmd/compile/internal/s390x/prog.go
@@ -17,14 +17,13 @@ import (
// Instructions not generated need not be listed.
// As an exception to that rule, we typically write down all the
// size variants of an operation even if we just use a subset.
-var progtable = [s390x.ALAST & obj.AMask]obj.ProgInfo{
+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.ACHECKNIL & obj.AMask: {Flags: gc.LeftRead},
obj.AVARDEF & obj.AMask: {Flags: gc.Pseudo | gc.RightWrite},
obj.AVARKILL & obj.AMask: {Flags: gc.Pseudo | gc.RightWrite},
obj.AVARLIVE & obj.AMask: {Flags: gc.Pseudo | gc.LeftRead},
@@ -36,23 +35,42 @@ var progtable = [s390x.ALAST & obj.AMask]obj.ProgInfo{
// 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.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
- s390x.AMULHDU & 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},
@@ -68,6 +86,8 @@ var progtable = [s390x.ALAST & obj.AMask]obj.ProgInfo{
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},
@@ -88,15 +108,24 @@ var progtable = [s390x.ALAST & obj.AMask]obj.ProgInfo{
s390x.ACLGDBR & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Conv},
// Moves
- s390x.AMOVB & obj.AMask: {Flags: gc.SizeB | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv},
- s390x.AMOVBZ & obj.AMask: {Flags: gc.SizeB | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv},
- s390x.AMOVH & obj.AMask: {Flags: gc.SizeW | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv},
- s390x.AMOVHZ & obj.AMask: {Flags: gc.SizeW | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv},
- s390x.AMOVW & obj.AMask: {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv},
- s390x.AMOVWZ & obj.AMask: {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv},
- s390x.AMOVD & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Move},
- s390x.AFMOVS & obj.AMask: {Flags: gc.SizeF | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv},
- s390x.AFMOVD & obj.AMask: {Flags: gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Move},
+ 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},
@@ -114,6 +143,8 @@ var progtable = [s390x.ALAST & obj.AMask]obj.ProgInfo{
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},
@@ -127,6 +158,12 @@ var progtable = [s390x.ALAST & obj.AMask]obj.ProgInfo{
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},
@@ -139,9 +176,8 @@ var progtable = [s390x.ALAST & obj.AMask]obj.ProgInfo{
obj.ARET & obj.AMask: {Flags: gc.Break},
}
-func proginfo(p *obj.Prog) {
- info := &p.Info
- *info = progtable[p.As&obj.AMask]
+func proginfo(p *obj.Prog) gc.ProgInfo {
+ info := progtable[p.As&obj.AMask]
if info.Flags == 0 {
gc.Fatalf("proginfo: unknown instruction %v", p)
}
@@ -151,29 +187,10 @@ func proginfo(p *obj.Prog) {
info.Flags |= gc.RightRead /*CanRegRead |*/
}
- if (p.From.Type == obj.TYPE_MEM || p.From.Type == obj.TYPE_ADDR) && p.From.Reg != 0 {
- info.Regindex |= RtoB(int(p.From.Reg))
- }
-
- if (p.To.Type == obj.TYPE_MEM || p.To.Type == obj.TYPE_ADDR) && p.To.Reg != 0 {
- info.Regindex |= RtoB(int(p.To.Reg))
- }
-
if p.From.Type == obj.TYPE_ADDR && p.From.Sym != nil && (info.Flags&gc.LeftRead != 0) {
info.Flags &^= gc.LeftRead
info.Flags |= gc.LeftAddr
}
- switch p.As {
- // load multiple sets a range of registers
- case s390x.ALMG, s390x.ALMY:
- for r := p.Reg; r <= p.To.Reg; r++ {
- info.Regset |= RtoB(int(r))
- }
- // store multiple reads a range of registers
- case s390x.ASTMG, s390x.ASTMY:
- for r := p.From.Reg; r <= p.Reg; r++ {
- info.Reguse |= RtoB(int(r))
- }
- }
+ return info
}
diff --git a/src/cmd/compile/internal/s390x/reg.go b/src/cmd/compile/internal/s390x/reg.go
deleted file mode 100644
index 4cb8a9d..0000000
--- a/src/cmd/compile/internal/s390x/reg.go
+++ /dev/null
@@ -1,130 +0,0 @@
-// Derived from Inferno utils/6c/reg.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6c/reg.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth at terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth at terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// Portions Copyright © 2009 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-package s390x
-
-import "cmd/internal/obj/s390x"
-import "cmd/compile/internal/gc"
-
-const (
- NREGVAR = 32 /* 16 general + 16 floating */
-)
-
-var regname = []string{
- ".R0",
- ".R1",
- ".R2",
- ".R3",
- ".R4",
- ".R5",
- ".R6",
- ".R7",
- ".R8",
- ".R9",
- ".R10",
- ".R11",
- ".R12",
- ".R13",
- ".R14",
- ".R15",
- ".F0",
- ".F1",
- ".F2",
- ".F3",
- ".F4",
- ".F5",
- ".F6",
- ".F7",
- ".F8",
- ".F9",
- ".F10",
- ".F11",
- ".F12",
- ".F13",
- ".F14",
- ".F15",
-}
-
-func regnames(n *int) []string {
- *n = NREGVAR
- return regname
-}
-
-func excludedregs() uint64 {
- // Exclude registers with fixed functions
- return RtoB(s390x.REG_R0) |
- RtoB(s390x.REGSP) |
- RtoB(s390x.REGG) |
- RtoB(s390x.REGTMP) |
- RtoB(s390x.REGTMP2) |
- RtoB(s390x.REG_LR)
-}
-
-func doregbits(r int) uint64 {
- return 0
-}
-
-/*
- * track register variables including external registers:
- * bit reg
- * 0 R0
- * ... ...
- * 15 R15
- * 16+0 F0
- * 16+1 F1
- * ... ...
- * 16+15 F15
- */
-func RtoB(r int) uint64 {
- if r >= s390x.REG_R0 && r <= s390x.REG_R15 {
- return 1 << uint(r-s390x.REG_R0)
- }
- if r >= s390x.REG_F0 && r <= s390x.REG_F15 {
- return 1 << uint(16+r-s390x.REG_F0)
- }
- return 0
-}
-
-func BtoR(b uint64) int {
- b &= 0xffff
- if b == 0 {
- return 0
- }
- return gc.Bitno(b) + s390x.REG_R0
-}
-
-func BtoF(b uint64) int {
- b >>= 16
- b &= 0xffff
- if b == 0 {
- return 0
- }
- return gc.Bitno(b) + s390x.REG_F0
-}
diff --git a/src/cmd/compile/internal/s390x/ssa.go b/src/cmd/compile/internal/s390x/ssa.go
new file mode 100644
index 0000000..e2d3c28
--- /dev/null
+++ b/src/cmd/compile/internal/s390x/ssa.go
@@ -0,0 +1,862 @@
+// Copyright 2016 The Go Authors. 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 (
+ "math"
+
+ "cmd/compile/internal/gc"
+ "cmd/compile/internal/ssa"
+ "cmd/internal/obj"
+ "cmd/internal/obj/s390x"
+)
+
+// markMoves marks any MOVXconst ops that need to avoid clobbering flags.
+func ssaMarkMoves(s *gc.SSAGenState, b *ssa.Block) {
+ flive := b.FlagsLiveAtEnd
+ if b.Control != nil && b.Control.Type.IsFlags() {
+ flive = true
+ }
+ for i := len(b.Values) - 1; i >= 0; i-- {
+ v := b.Values[i]
+ if flive && v.Op == ssa.OpS390XMOVDconst {
+ // The "mark" is any non-nil Aux value.
+ v.Aux = v
+ }
+ if v.Type.IsFlags() {
+ flive = false
+ }
+ for _, a := range v.Args {
+ if a.Type.IsFlags() {
+ flive = true
+ }
+ }
+ }
+}
+
+// loadByType returns the load instruction of the given type.
+func loadByType(t ssa.Type) obj.As {
+ if t.IsFloat() {
+ switch t.Size() {
+ case 4:
+ return s390x.AFMOVS
+ case 8:
+ return s390x.AFMOVD
+ }
+ } else {
+ switch t.Size() {
+ case 1:
+ if t.IsSigned() {
+ return s390x.AMOVB
+ } else {
+ return s390x.AMOVBZ
+ }
+ case 2:
+ if t.IsSigned() {
+ return s390x.AMOVH
+ } else {
+ return s390x.AMOVHZ
+ }
+ case 4:
+ if t.IsSigned() {
+ return s390x.AMOVW
+ } else {
+ return s390x.AMOVWZ
+ }
+ case 8:
+ return s390x.AMOVD
+ }
+ }
+ panic("bad load type")
+}
+
+// storeByType returns the store instruction of the given type.
+func storeByType(t ssa.Type) obj.As {
+ width := t.Size()
+ if t.IsFloat() {
+ switch width {
+ case 4:
+ return s390x.AFMOVS
+ case 8:
+ return s390x.AFMOVD
+ }
+ } else {
+ switch width {
+ case 1:
+ return s390x.AMOVB
+ case 2:
+ return s390x.AMOVH
+ case 4:
+ return s390x.AMOVW
+ case 8:
+ return s390x.AMOVD
+ }
+ }
+ panic("bad store type")
+}
+
+// moveByType returns the reg->reg move instruction of the given type.
+func moveByType(t ssa.Type) obj.As {
+ if t.IsFloat() {
+ return s390x.AFMOVD
+ } else {
+ switch t.Size() {
+ case 1:
+ if t.IsSigned() {
+ return s390x.AMOVB
+ } else {
+ return s390x.AMOVBZ
+ }
+ case 2:
+ if t.IsSigned() {
+ return s390x.AMOVH
+ } else {
+ return s390x.AMOVHZ
+ }
+ case 4:
+ if t.IsSigned() {
+ return s390x.AMOVW
+ } else {
+ return s390x.AMOVWZ
+ }
+ case 8:
+ return s390x.AMOVD
+ }
+ }
+ panic("bad load type")
+}
+
+// opregreg emits instructions for
+// dest := dest(To) op src(From)
+// and also returns the created obj.Prog so it
+// may be further adjusted (offset, scale, etc).
+func opregreg(op obj.As, dest, src int16) *obj.Prog {
+ p := gc.Prog(op)
+ p.From.Type = obj.TYPE_REG
+ p.To.Type = obj.TYPE_REG
+ p.To.Reg = dest
+ p.From.Reg = src
+ return p
+}
+
+// opregregimm emits instructions for
+// 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)
+ p.From.Type = obj.TYPE_CONST
+ p.From.Offset = off
+ p.Reg = src
+ p.To.Reg = dest
+ p.To.Type = obj.TYPE_REG
+ return p
+}
+
+func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
+ s.SetLineno(v.Line)
+ switch v.Op {
+ case ssa.OpS390XSLD, ssa.OpS390XSLW,
+ ssa.OpS390XSRD, ssa.OpS390XSRW,
+ ssa.OpS390XSRAD, ssa.OpS390XSRAW:
+ r := v.Reg()
+ r1 := v.Args[0].Reg()
+ r2 := v.Args[1].Reg()
+ if r2 == s390x.REG_R0 {
+ v.Fatalf("cannot use R0 as shift value %s", v.LongString())
+ }
+ p := opregreg(v.Op.Asm(), r, r2)
+ if r != r1 {
+ p.Reg = r1
+ }
+ case ssa.OpS390XADD, ssa.OpS390XADDW,
+ ssa.OpS390XSUB, ssa.OpS390XSUBW,
+ ssa.OpS390XAND, ssa.OpS390XANDW,
+ ssa.OpS390XOR, ssa.OpS390XORW,
+ ssa.OpS390XXOR, ssa.OpS390XXORW:
+ r := v.Reg()
+ r1 := v.Args[0].Reg()
+ r2 := v.Args[1].Reg()
+ p := opregreg(v.Op.Asm(), r, r2)
+ if r != r1 {
+ p.Reg = r1
+ }
+ // 2-address opcode arithmetic
+ case ssa.OpS390XMULLD, ssa.OpS390XMULLW,
+ ssa.OpS390XMULHD, ssa.OpS390XMULHDU,
+ ssa.OpS390XFADDS, ssa.OpS390XFADD, ssa.OpS390XFSUBS, ssa.OpS390XFSUB,
+ ssa.OpS390XFMULS, ssa.OpS390XFMUL, ssa.OpS390XFDIVS, ssa.OpS390XFDIV:
+ r := v.Reg()
+ 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())
+ case ssa.OpS390XDIVD, ssa.OpS390XDIVW,
+ ssa.OpS390XDIVDU, ssa.OpS390XDIVWU,
+ ssa.OpS390XMODD, ssa.OpS390XMODW,
+ ssa.OpS390XMODDU, ssa.OpS390XMODWU:
+
+ // TODO(mundaym): use the temp registers every time like x86 does with AX?
+ dividend := v.Args[0].Reg()
+ divisor := v.Args[1].Reg()
+
+ // CPU faults upon signed overflow, which occurs when most
+ // negative int is divided by -1.
+ var j *obj.Prog
+ if v.Op == ssa.OpS390XDIVD || v.Op == ssa.OpS390XDIVW ||
+ v.Op == ssa.OpS390XMODD || v.Op == ssa.OpS390XMODW {
+
+ var c *obj.Prog
+ c = gc.Prog(s390x.ACMP)
+ j = gc.Prog(s390x.ABEQ)
+
+ c.From.Type = obj.TYPE_REG
+ c.From.Reg = divisor
+ c.To.Type = obj.TYPE_CONST
+ c.To.Offset = -1
+
+ j.To.Type = obj.TYPE_BRANCH
+
+ }
+
+ p := gc.Prog(v.Op.Asm())
+ p.From.Type = obj.TYPE_REG
+ p.From.Reg = divisor
+ p.Reg = 0
+ p.To.Type = obj.TYPE_REG
+ p.To.Reg = dividend
+
+ // signed division, rest of the check for -1 case
+ if j != nil {
+ j2 := gc.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.To.Type = obj.TYPE_REG
+ n.To.Reg = dividend
+ } else {
+ // n % -1 == 0
+ n = gc.Prog(s390x.AXOR)
+ n.From.Type = obj.TYPE_REG
+ n.From.Reg = dividend
+ n.To.Type = obj.TYPE_REG
+ n.To.Reg = dividend
+ }
+
+ j.To.Val = n
+ j2.To.Val = s.Pc()
+ }
+ case ssa.OpS390XADDconst, ssa.OpS390XADDWconst:
+ opregregimm(v.Op.Asm(), v.Reg(), v.Args[0].Reg(), v.AuxInt)
+ case ssa.OpS390XMULLDconst, ssa.OpS390XMULLWconst,
+ ssa.OpS390XSUBconst, ssa.OpS390XSUBWconst,
+ ssa.OpS390XANDconst, ssa.OpS390XANDWconst,
+ ssa.OpS390XORconst, ssa.OpS390XORWconst,
+ ssa.OpS390XXORconst, ssa.OpS390XXORWconst:
+ r := v.Reg()
+ 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.From.Type = obj.TYPE_CONST
+ p.From.Offset = v.AuxInt
+ p.To.Type = obj.TYPE_REG
+ p.To.Reg = r
+ case ssa.OpS390XSLDconst, ssa.OpS390XSLWconst,
+ ssa.OpS390XSRDconst, ssa.OpS390XSRWconst,
+ ssa.OpS390XSRADconst, ssa.OpS390XSRAWconst,
+ ssa.OpS390XRLLGconst, ssa.OpS390XRLLconst:
+ p := gc.Prog(v.Op.Asm())
+ p.From.Type = obj.TYPE_CONST
+ p.From.Offset = v.AuxInt
+ r := v.Reg()
+ r1 := v.Args[0].Reg()
+ if r != r1 {
+ p.Reg = r1
+ }
+ p.To.Type = obj.TYPE_REG
+ p.To.Reg = r
+ case ssa.OpS390XSUBEcarrymask, ssa.OpS390XSUBEWcarrymask:
+ r := v.Reg()
+ p := gc.Prog(v.Op.Asm())
+ p.From.Type = obj.TYPE_REG
+ p.From.Reg = r
+ p.To.Type = obj.TYPE_REG
+ p.To.Reg = r
+ case ssa.OpS390XMOVDaddridx:
+ r := v.Args[0].Reg()
+ i := v.Args[1].Reg()
+ p := gc.Prog(s390x.AMOVD)
+ p.From.Scale = 1
+ if i == s390x.REGSP {
+ r, i = i, r
+ }
+ p.From.Type = obj.TYPE_ADDR
+ p.From.Reg = r
+ p.From.Index = i
+ gc.AddAux(&p.From, v)
+ p.To.Type = obj.TYPE_REG
+ p.To.Reg = v.Reg()
+ case ssa.OpS390XMOVDaddr:
+ p := gc.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())
+ case ssa.OpS390XFCMPS, ssa.OpS390XFCMP:
+ opregreg(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.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.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.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.OpS390XADDWload, ssa.OpS390XADDload,
+ ssa.OpS390XMULLWload, ssa.OpS390XMULLDload,
+ ssa.OpS390XSUBWload, ssa.OpS390XSUBload,
+ ssa.OpS390XANDWload, ssa.OpS390XANDload,
+ ssa.OpS390XORWload, ssa.OpS390XORload,
+ ssa.OpS390XXORWload, ssa.OpS390XXORload:
+ r := v.Reg()
+ 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.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 = r
+ case ssa.OpS390XMOVDload,
+ ssa.OpS390XMOVWZload, ssa.OpS390XMOVHZload, ssa.OpS390XMOVBZload,
+ ssa.OpS390XMOVDBRload, ssa.OpS390XMOVWBRload, ssa.OpS390XMOVHBRload,
+ ssa.OpS390XMOVBload, ssa.OpS390XMOVHload, ssa.OpS390XMOVWload,
+ ssa.OpS390XFMOVSload, ssa.OpS390XFMOVDload:
+ p := gc.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.OpS390XMOVBZloadidx, ssa.OpS390XMOVHZloadidx, ssa.OpS390XMOVWZloadidx, ssa.OpS390XMOVDloadidx,
+ ssa.OpS390XMOVHBRloadidx, ssa.OpS390XMOVWBRloadidx, ssa.OpS390XMOVDBRloadidx,
+ ssa.OpS390XFMOVSloadidx, ssa.OpS390XFMOVDloadidx:
+ r := v.Args[0].Reg()
+ i := v.Args[1].Reg()
+ if i == s390x.REGSP {
+ r, i = i, r
+ }
+ p := gc.Prog(v.Op.Asm())
+ p.From.Type = obj.TYPE_MEM
+ p.From.Reg = r
+ p.From.Scale = 1
+ p.From.Index = i
+ gc.AddAux(&p.From, v)
+ p.To.Type = obj.TYPE_REG
+ p.To.Reg = v.Reg()
+ 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.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.OpS390XMOVBstoreidx, ssa.OpS390XMOVHstoreidx, ssa.OpS390XMOVWstoreidx, ssa.OpS390XMOVDstoreidx,
+ ssa.OpS390XMOVHBRstoreidx, ssa.OpS390XMOVWBRstoreidx, ssa.OpS390XMOVDBRstoreidx,
+ ssa.OpS390XFMOVSstoreidx, ssa.OpS390XFMOVDstoreidx:
+ r := v.Args[0].Reg()
+ i := v.Args[1].Reg()
+ if i == s390x.REGSP {
+ r, i = i, r
+ }
+ p := gc.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 = r
+ p.To.Scale = 1
+ 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.From.Type = obj.TYPE_CONST
+ sc := v.AuxValAndOff()
+ p.From.Offset = sc.Val()
+ p.To.Type = obj.TYPE_MEM
+ p.To.Reg = v.Args[0].Reg()
+ gc.AddAux2(&p.To, v, sc.Off())
+ case ssa.OpS390XMOVBreg, ssa.OpS390XMOVHreg, ssa.OpS390XMOVWreg,
+ ssa.OpS390XMOVBZreg, ssa.OpS390XMOVHZreg, ssa.OpS390XMOVWZreg,
+ ssa.OpS390XCEFBRA, ssa.OpS390XCDFBRA, ssa.OpS390XCEGBRA, ssa.OpS390XCDGBRA,
+ 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())
+ case ssa.OpS390XCLEAR:
+ p := gc.Prog(v.Op.Asm())
+ p.From.Type = obj.TYPE_CONST
+ sc := v.AuxValAndOff()
+ p.From.Offset = sc.Val()
+ p.To.Type = obj.TYPE_MEM
+ p.To.Reg = v.Args[0].Reg()
+ gc.AddAux2(&p.To, v, sc.Off())
+ case ssa.OpCopy, ssa.OpS390XMOVDconvert:
+ if v.Type.IsMemory() {
+ return
+ }
+ x := v.Args[0].Reg()
+ y := v.Reg()
+ if x != y {
+ opregreg(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))
+ gc.AddrAuto(&p.From, v.Args[0])
+ p.To.Type = obj.TYPE_REG
+ p.To.Reg = v.Reg()
+ case ssa.OpStoreReg:
+ if v.Type.IsFlags() {
+ v.Fatalf("store flags not implemented: %v", v.LongString())
+ return
+ }
+ p := gc.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.OpS390XLoweredGetG:
+ r := v.Reg()
+ p := gc.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.OpS390XFLOGR, ssa.OpS390XNEG, ssa.OpS390XNEGW,
+ ssa.OpS390XMOVWBR, ssa.OpS390XMOVDBR:
+ p := gc.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.OpS390XNOT, ssa.OpS390XNOTW:
+ v.Fatalf("NOT/NOTW generated %s", v.LongString())
+ case ssa.OpS390XMOVDEQ, ssa.OpS390XMOVDNE,
+ ssa.OpS390XMOVDLT, ssa.OpS390XMOVDLE,
+ ssa.OpS390XMOVDGT, ssa.OpS390XMOVDGE,
+ ssa.OpS390XMOVDGTnoinv, ssa.OpS390XMOVDGEnoinv:
+ r := v.Reg()
+ 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.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.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:
+ v.Fatalf("Flag* ops should never make it to codegen %v", v.LongString())
+ case ssa.OpS390XAddTupleFirst32, ssa.OpS390XAddTupleFirst64:
+ 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.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")
+ }
+ 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.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++ {
+ if v.Args[i].Reg() != v.Args[i-1].Reg()+1 {
+ v.Fatalf("invalid store multiple %s", v.LongString())
+ }
+ }
+ p := gc.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()
+ p.To.Type = obj.TYPE_MEM
+ p.To.Reg = v.Args[0].Reg()
+ gc.AddAux(&p.To, v)
+ case ssa.OpS390XLoweredMove:
+ // Inputs must be valid pointers to memory,
+ // so adjust arg0 and arg1 as part of the expansion.
+ // arg2 should be src+size,
+ //
+ // mvc: MVC $256, 0(R2), 0(R1)
+ // MOVD $256(R1), R1
+ // MOVD $256(R2), R2
+ // CMP R2, Rarg2
+ // 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.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.From.Type = obj.TYPE_ADDR
+ movd.From.Reg = v.Args[i].Reg()
+ movd.From.Offset = 256
+ movd.To.Type = obj.TYPE_REG
+ movd.To.Reg = v.Args[i].Reg()
+ }
+
+ cmpu := gc.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.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.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,
+ // so adjust arg0 as part of the expansion.
+ // arg1 should be src+size,
+ //
+ // clear: CLEAR $256, 0(R1)
+ // MOVD $256(R1), R1
+ // CMP R1, Rarg1
+ // 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.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.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.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.To.Type = obj.TYPE_BRANCH
+ gc.Patch(bne, clear)
+
+ if v.AuxInt > 0 {
+ clear := gc.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.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.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.Reg = v.Reg0()
+ 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.OpS390XLoweredAtomicCas32, ssa.OpS390XLoweredAtomicCas64:
+ // Convert the flags output of CS{,G} into a bool.
+ // CS{,G} arg1, arg2, arg0
+ // MOVD $0, ret
+ // BNE 2(PC)
+ // MOVD $1, ret
+ // NOP (so the BNE has somewhere to land)
+
+ // CS{,G} arg1, arg2, arg0
+ cs := gc.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
+ cs.To.Type = obj.TYPE_MEM
+ cs.To.Reg = v.Args[0].Reg()
+ gc.AddAux(&cs.To, v)
+
+ // MOVD $0, ret
+ movd := gc.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.To.Type = obj.TYPE_BRANCH
+
+ // MOVD $1, ret
+ movd = gc.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)
+ gc.Patch(bne, nop)
+ case ssa.OpS390XLoweredAtomicExchange32, ssa.OpS390XLoweredAtomicExchange64:
+ // Loop until the CS{,G} succeeds.
+ // MOV{WZ,D} arg0, ret
+ // cs: CS{,G} ret, arg1, arg0
+ // BNE cs
+
+ // MOV{WZ,D} arg0, ret
+ load := gc.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
+ load.To.Reg = v.Reg0()
+ gc.AddAux(&load.From, v)
+
+ // CS{,G} ret, arg1, arg0
+ cs := gc.Prog(v.Op.Asm())
+ cs.From.Type = obj.TYPE_REG
+ cs.From.Reg = v.Reg0() // old
+ cs.Reg = v.Args[1].Reg() // new
+ cs.To.Type = obj.TYPE_MEM
+ cs.To.Reg = v.Args[0].Reg()
+ gc.AddAux(&cs.To, v)
+
+ // BNE cs
+ bne := gc.Prog(s390x.ABNE)
+ bne.To.Type = obj.TYPE_BRANCH
+ gc.Patch(bne, cs)
+ default:
+ v.Fatalf("genValue not implemented: %s", v.LongString())
+ }
+}
+
+var blockJump = [...]struct {
+ asm, invasm obj.As
+}{
+ ssa.BlockS390XEQ: {s390x.ABEQ, s390x.ABNE},
+ ssa.BlockS390XNE: {s390x.ABNE, s390x.ABEQ},
+ ssa.BlockS390XLT: {s390x.ABLT, s390x.ABGE},
+ ssa.BlockS390XGE: {s390x.ABGE, s390x.ABLT},
+ ssa.BlockS390XLE: {s390x.ABLE, s390x.ABGT},
+ ssa.BlockS390XGT: {s390x.ABGT, s390x.ABLE},
+ ssa.BlockS390XGTF: {s390x.ABGT, s390x.ABLEU},
+ ssa.BlockS390XGEF: {s390x.ABGE, s390x.ABLTU},
+}
+
+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.To.Type = obj.TYPE_BRANCH
+ s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()})
+ }
+ case ssa.BlockDefer:
+ // defer returns in R3:
+ // 0 if we should continue executing
+ // 1 if we should jump to deferreturn call
+ p := gc.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.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.To.Type = obj.TYPE_BRANCH
+ s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()})
+ }
+ case ssa.BlockExit:
+ gc.Prog(obj.AUNDEF) // tell plive.go that we never reach here
+ case ssa.BlockRet:
+ gc.Prog(obj.ARET)
+ case ssa.BlockRetJmp:
+ p := gc.Prog(s390x.ABR)
+ p.To.Type = obj.TYPE_MEM
+ p.To.Name = obj.NAME_EXTERN
+ p.To.Sym = gc.Linksym(b.Aux.(*gc.Sym))
+ 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.To.Type = obj.TYPE_BRANCH
+ s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[1].Block()})
+ case b.Succs[1].Block():
+ p = gc.Prog(jmp.asm)
+ p.To.Type = obj.TYPE_BRANCH
+ s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()})
+ default:
+ p = gc.Prog(jmp.asm)
+ p.To.Type = obj.TYPE_BRANCH
+ s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()})
+ q := gc.Prog(s390x.ABR)
+ q.To.Type = obj.TYPE_BRANCH
+ s.Branches = append(s.Branches, gc.Branch{P: q, B: b.Succs[1].Block()})
+ }
+ default:
+ b.Fatalf("branch not implemented: %s. Control: %s", b.LongString(), b.Control.LongString())
+ }
+}
diff --git a/src/cmd/compile/internal/ssa/block.go b/src/cmd/compile/internal/ssa/block.go
index 77f8306..e1c2f6d 100644
--- a/src/cmd/compile/internal/ssa/block.go
+++ b/src/cmd/compile/internal/ssa/block.go
@@ -89,13 +89,16 @@ type Edge struct {
func (e Edge) Block() *Block {
return e.b
}
+func (e Edge) Index() int {
+ return e.i
+}
// kind control successors
// ------------------------------------------
// Exit return mem []
// Plain nil [next]
// If a boolean Value [then, else]
-// Call mem [nopanic, panic] (control opcode should be OpCall or OpStaticCall)
+// Defer mem [nopanic, panic] (control opcode should be OpDeferCall)
type BlockKind int8
// short form print
@@ -144,6 +147,7 @@ func (b *Block) AddEdgeTo(c *Block) {
j := len(c.Preds)
b.Succs = append(b.Succs, Edge{c, j})
c.Preds = append(c.Preds, Edge{b, i})
+ b.Func.invalidateCFG()
}
// removePred removes the ith input edge from b.
@@ -159,6 +163,7 @@ func (b *Block) removePred(i int) {
}
b.Preds[n] = Edge{}
b.Preds = b.Preds[:n]
+ b.Func.invalidateCFG()
}
// removeSucc removes the ith output edge from b.
@@ -174,6 +179,7 @@ func (b *Block) removeSucc(i int) {
}
b.Succs[n] = Edge{}
b.Succs = b.Succs[:n]
+ b.Func.invalidateCFG()
}
func (b *Block) swapSuccessors() {
@@ -189,10 +195,9 @@ func (b *Block) swapSuccessors() {
b.Likely *= -1
}
-func (b *Block) Logf(msg string, args ...interface{}) { b.Func.Logf(msg, args...) }
-func (b *Block) Log() bool { return b.Func.Log() }
-func (b *Block) Fatalf(msg string, args ...interface{}) { b.Func.Fatalf(msg, args...) }
-func (b *Block) Unimplementedf(msg string, args ...interface{}) { b.Func.Unimplementedf(msg, args...) }
+func (b *Block) Logf(msg string, args ...interface{}) { b.Func.Logf(msg, args...) }
+func (b *Block) Log() bool { return b.Func.Log() }
+func (b *Block) Fatalf(msg string, args ...interface{}) { b.Func.Fatalf(msg, args...) }
type BranchPrediction int8
diff --git a/src/cmd/compile/internal/ssa/check.go b/src/cmd/compile/internal/ssa/check.go
index bfedd47..d78e915 100644
--- a/src/cmd/compile/internal/ssa/check.go
+++ b/src/cmd/compile/internal/ssa/check.go
@@ -80,16 +80,6 @@ func checkFunc(f *Func) {
if !b.Control.Type.IsBoolean() {
f.Fatalf("if block %s has non-bool control value %s", b, b.Control.LongString())
}
- case BlockCall:
- if len(b.Succs) != 1 {
- f.Fatalf("call block %s len(Succs)==%d, want 1", b, len(b.Succs))
- }
- if b.Control == nil {
- f.Fatalf("call block %s has no control value", b)
- }
- if !b.Control.Type.IsMemory() {
- f.Fatalf("call block %s has non-memory control value %s", b, b.Control.LongString())
- }
case BlockDefer:
if len(b.Succs) != 2 {
f.Fatalf("defer block %s len(Succs)==%d, want 2", b, len(b.Succs))
@@ -100,16 +90,6 @@ func checkFunc(f *Func) {
if !b.Control.Type.IsMemory() {
f.Fatalf("defer block %s has non-memory control value %s", b, b.Control.LongString())
}
- case BlockCheck:
- if len(b.Succs) != 1 {
- f.Fatalf("check block %s len(Succs)==%d, want 1", b, len(b.Succs))
- }
- if b.Control == nil {
- f.Fatalf("check block %s has no control value", b)
- }
- if !b.Control.Type.IsVoid() {
- f.Fatalf("check block %s has non-void control value %s", b, b.Control.LongString())
- }
case BlockFirst:
if len(b.Succs) != 2 {
f.Fatalf("plain/dead block %s len(Succs)==%d, want 2", b, len(b.Succs))
@@ -165,9 +145,11 @@ 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:
canHaveAux = true
- case auxSymOff, auxSymValAndOff:
+ case auxSymOff, auxSymValAndOff, auxSymSizeAndAlign:
canHaveAuxInt = true
canHaveAux = true
case auxSymInt32:
@@ -273,8 +255,7 @@ func checkFunc(f *Func) {
if f.RegAlloc == nil {
// Note: regalloc introduces non-dominating args.
// See TODO in regalloc.go.
- idom := dominators(f)
- sdom := newSparseTree(f, idom)
+ sdom := f.sdom()
for _, b := range f.Blocks {
for _, v := range b.Values {
for i, arg := range v.Args {
diff --git a/src/cmd/compile/internal/ssa/compile.go b/src/cmd/compile/internal/ssa/compile.go
index d8b0b0a..b9ec7eb 100644
--- a/src/cmd/compile/internal/ssa/compile.go
+++ b/src/cmd/compile/internal/ssa/compile.go
@@ -7,6 +7,7 @@ package ssa
import (
"fmt"
"log"
+ "os"
"regexp"
"runtime"
"strings"
@@ -41,6 +42,9 @@ func Compile(f *Func) {
// Run all the passes
printFunc(f)
f.Config.HTML.WriteFunc("start", f)
+ if BuildDump != "" && BuildDump == f.Name {
+ f.dumpFile("build")
+ }
if checkEnabled {
checkFunc(f)
}
@@ -96,6 +100,10 @@ func Compile(f *Func) {
f.LogStat("TIME(ns):BYTES:ALLOCS", time, nBytes, nAllocs)
}
}
+ if p.dump != nil && p.dump[f.Name] {
+ // Dump function to appropriately named file
+ f.dumpFile(phaseName)
+ }
if checkEnabled {
checkFunc(f)
}
@@ -105,16 +113,48 @@ func Compile(f *Func) {
phaseName = ""
}
+// TODO: should be a config field
+var dumpFileSeq int
+
+// dumpFile creates a file from the phase name and function name
+// Dumping is done to files to avoid buffering huge strings before
+// output.
+func (f *Func) dumpFile(phaseName string) {
+ dumpFileSeq++
+ fname := fmt.Sprintf("%s__%s_%d.dump", phaseName, f.Name, dumpFileSeq)
+ fname = strings.Replace(fname, " ", "_", -1)
+ fname = strings.Replace(fname, "/", "_", -1)
+ fname = strings.Replace(fname, ":", "_", -1)
+
+ fi, err := os.Create(fname)
+ if err != nil {
+ f.Config.Warnl(0, "Unable to create after-phase dump file %s", fname)
+ return
+ }
+
+ p := stringFuncPrinter{w: fi}
+ fprintFunc(p, f)
+ fi.Close()
+}
+
type pass struct {
name string
fn func(*Func)
required bool
disabled bool
- time bool // report time to run pass
- mem bool // report mem stats to run pass
- stats int // pass reports own "stats" (e.g., branches removed)
- debug int // pass performs some debugging. =1 should be in error-testing-friendly Warnl format.
- test int // pass-specific ad-hoc option, perhaps useful in development
+ time bool // report time to run pass
+ mem bool // report mem stats to run pass
+ stats int // pass reports own "stats" (e.g., branches removed)
+ debug int // pass performs some debugging. =1 should be in error-testing-friendly Warnl format.
+ test int // pass-specific ad-hoc option, perhaps useful in development
+ dump map[string]bool // dump if function name matches
+}
+
+func (p *pass) addDump(s string) {
+ if p.dump == nil {
+ p.dump = make(map[string]bool)
+ }
+ p.dump[s] = true
}
// Run consistency checker between each phase
@@ -127,6 +167,7 @@ var IntrinsicsDisable bool
var BuildDebug int
var BuildTest int
var BuildStats int
+var BuildDump string // name of function to dump after initial build of ssa
// PhaseOption sets the specified flag in the specified ssa phase,
// returning empty string if this was successful or a string explaining
@@ -146,7 +187,35 @@ var BuildStats int
//
// BOOT_GO_GCFLAGS=-d='ssa/~^.*scc$/off' GO_GCFLAGS='-d=ssa/~^.*scc$/off' ./make.bash
//
-func PhaseOption(phase, flag string, val int) string {
+func PhaseOption(phase, flag string, val int, valString string) string {
+ if phase == "help" {
+ lastcr := 0
+ phasenames := "check, all, build, intrinsics"
+ for _, p := range passes {
+ pn := strings.Replace(p.name, " ", "_", -1)
+ if len(pn)+len(phasenames)-lastcr > 70 {
+ phasenames += "\n"
+ lastcr = len(phasenames)
+ phasenames += pn
+ } else {
+ phasenames += ", " + pn
+ }
+ }
+ return "" +
+ `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
+<value> defaults to 1
+<function_name> is required for "dump", specifies name of function to dump after <phase>
+Except for dump, output is directed to standard out; dump appears in a file.
+Phase "all" supports flags "time", "mem", and "dump".
+Phases "intrinsics" supports flags "on", "off", and "debug".
+Interpretation of the "debug" value depends on the phase.
+Dump files are named <phase>__<function_name>_<seq>.dump.
+`
+ }
+
if phase == "check" && flag == "on" {
checkEnabled = val != 0
return ""
@@ -157,9 +226,18 @@ func PhaseOption(phase, flag string, val int) string {
}
alltime := false
+ allmem := false
+ alldump := false
if phase == "all" {
if flag == "time" {
alltime = val != 0
+ } else if flag == "mem" {
+ allmem = val != 0
+ } else if flag == "dump" {
+ alldump = val != 0
+ if alldump {
+ BuildDump = valString
+ }
} else {
return fmt.Sprintf("Did not find a flag matching %s in -d=ssa/%s debug option", flag, phase)
}
@@ -186,6 +264,8 @@ func PhaseOption(phase, flag string, val int) string {
BuildTest = val
case "stats":
BuildStats = val
+ case "dump":
+ BuildDump = valString
default:
return fmt.Sprintf("Did not find a flag matching %s in -d=ssa/%s debug option", flag, phase)
}
@@ -205,6 +285,10 @@ func PhaseOption(phase, flag string, val int) string {
for i, p := range passes {
if phase == "all" {
p.time = alltime
+ p.mem = allmem
+ if alldump {
+ p.addDump(valString)
+ }
passes[i] = p
matchedOne = true
} else if p.name == phase || p.name == underphase || re != nil && re.MatchString(p.name) {
@@ -223,6 +307,8 @@ func PhaseOption(phase, flag string, val int) string {
p.stats = val
case "test":
p.test = val
+ case "dump":
+ p.addDump(valString)
default:
return fmt.Sprintf("Did not find a flag matching %s in -d=ssa/%s debug option", flag, phase)
}
@@ -250,7 +336,6 @@ var passes = [...]pass{
{name: "opt", fn: opt, required: true}, // TODO: split required rules and optimizing rules
{name: "zero arg cse", fn: zcse, required: true}, // required to merge OpSB values
{name: "opt deadcode", fn: deadcode, required: true}, // remove any blocks orphaned during opt
- {name: "generic domtree", fn: domTree},
{name: "generic cse", fn: cse},
{name: "phiopt", fn: phiopt},
{name: "nilcheckelim", fn: nilcheckelim},
@@ -261,6 +346,7 @@ 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: "tighten", fn: tighten}, // move values closer to their uses
@@ -274,11 +360,13 @@ var passes = [...]pass{
{name: "late deadcode", fn: deadcode},
{name: "critical", fn: critical, required: true}, // remove critical edges
{name: "likelyadjust", fn: likelyadjust},
- {name: "layout", fn: layout, required: true}, // schedule blocks
- {name: "schedule", fn: schedule, required: true}, // schedule values
+ {name: "layout", fn: layout, required: true}, // schedule blocks
+ {name: "schedule", fn: schedule, required: true}, // schedule values
+ {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: "trim", fn: trim}, // remove empty blocks
+ {name: "stackframe", fn: stackframe, required: true},
+ {name: "trim", fn: trim}, // remove empty blocks
}
// Double-check phase ordering constraints.
@@ -307,12 +395,6 @@ var passOrder = [...]constraint{
{"opt", "nilcheckelim"},
// tighten should happen before lowering to avoid splitting naturally paired instructions such as CMP/SET
{"tighten", "lower"},
- // cse, phiopt, nilcheckelim, prove and loopbce share idom.
- {"generic domtree", "generic cse"},
- {"generic domtree", "phiopt"},
- {"generic domtree", "nilcheckelim"},
- {"generic domtree", "prove"},
- {"generic domtree", "loopbce"},
// tighten will be most effective when as many values have been removed as possible
{"generic deadcode", "tighten"},
{"generic cse", "tighten"},
@@ -329,10 +411,14 @@ var passOrder = [...]constraint{
// checkLower must run after lowering & subsequent dead code elim
{"lower", "checkLower"},
{"lowered deadcode", "checkLower"},
+ // late nilcheck needs instructions to be scheduled.
+ {"schedule", "late nilcheck"},
// flagalloc needs instructions to be scheduled.
{"schedule", "flagalloc"},
// regalloc needs flags to be allocated first.
{"flagalloc", "regalloc"},
+ // stackframe needs to know about spilled registers.
+ {"regalloc", "stackframe"},
// trim needs regalloc to be done first.
{"regalloc", "trim"},
}
diff --git a/src/cmd/compile/internal/ssa/config.go b/src/cmd/compile/internal/ssa/config.go
index e8ab178..919386e 100644
--- a/src/cmd/compile/internal/ssa/config.go
+++ b/src/cmd/compile/internal/ssa/config.go
@@ -17,14 +17,27 @@ type Config struct {
arch string // "amd64", etc.
IntSize int64 // 4 or 8
PtrSize int64 // 4 or 8
- lowerBlock func(*Block) bool // lowering function
+ 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
@@ -77,15 +90,12 @@ type Logger interface {
// Fatal reports a compiler error and exits.
Fatalf(line int32, msg string, args ...interface{})
- // Unimplemented reports that the function cannot be compiled.
- // It will be removed once SSA work is complete.
- Unimplementedf(line int32, msg string, args ...interface{})
-
// Warnl writes compiler messages in the form expected by "errorcheck" tests
Warnl(line int32, fmt_ string, args ...interface{})
- // Fowards the Debug_checknil flag from gc
+ // Fowards the Debug flags from gc
Debug_checknil() bool
+ Debug_wb() bool
}
type Frontend interface {
@@ -106,9 +116,18 @@ type Frontend interface {
SplitSlice(LocalSlot) (LocalSlot, LocalSlot, LocalSlot)
SplitComplex(LocalSlot) (LocalSlot, LocalSlot)
SplitStruct(LocalSlot, int) LocalSlot
+ 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
+
+ // 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
}
// interface used to hold *gc.Node. We'd use *gc.Node directly but
@@ -125,32 +144,150 @@ func NewConfig(arch string, fe Frontend, ctxt *obj.Link, optimize bool) *Config
case "amd64":
c.IntSize = 8
c.PtrSize = 8
+ c.RegSize = 8
c.lowerBlock = rewriteBlockAMD64
c.lowerValue = rewriteValueAMD64
c.registers = registersAMD64[:]
- case "386":
+ c.gpRegMask = gpRegMaskAMD64
+ c.fpRegMask = fpRegMaskAMD64
+ c.FPReg = framepointerRegAMD64
+ c.LinkReg = linkRegAMD64
+ c.hasGReg = false
+ case "amd64p32":
c.IntSize = 4
c.PtrSize = 4
+ c.RegSize = 8
c.lowerBlock = rewriteBlockAMD64
- c.lowerValue = rewriteValueAMD64 // TODO(khr): full 32-bit support
+ c.lowerValue = rewriteValueAMD64
+ c.registers = registersAMD64[:]
+ c.gpRegMask = gpRegMaskAMD64
+ c.fpRegMask = fpRegMaskAMD64
+ c.FPReg = framepointerRegAMD64
+ c.LinkReg = linkRegAMD64
+ c.hasGReg = false
+ c.noDuffDevice = true
+ case "386":
+ c.IntSize = 4
+ c.PtrSize = 4
+ c.RegSize = 4
+ c.lowerBlock = rewriteBlock386
+ c.lowerValue = rewriteValue386
+ c.registers = registers386[:]
+ c.gpRegMask = gpRegMask386
+ c.fpRegMask = fpRegMask386
+ c.FPReg = framepointerReg386
+ c.LinkReg = linkReg386
+ c.hasGReg = false
case "arm":
c.IntSize = 4
c.PtrSize = 4
+ c.RegSize = 4
c.lowerBlock = rewriteBlockARM
c.lowerValue = rewriteValueARM
c.registers = registersARM[:]
+ c.gpRegMask = gpRegMaskARM
+ c.fpRegMask = fpRegMaskARM
+ c.FPReg = framepointerRegARM
+ c.LinkReg = linkRegARM
+ c.hasGReg = true
+ case "arm64":
+ c.IntSize = 8
+ c.PtrSize = 8
+ c.RegSize = 8
+ c.lowerBlock = rewriteBlockARM64
+ c.lowerValue = rewriteValueARM64
+ c.registers = registersARM64[:]
+ c.gpRegMask = gpRegMaskARM64
+ c.fpRegMask = fpRegMaskARM64
+ c.FPReg = framepointerRegARM64
+ c.LinkReg = linkRegARM64
+ c.hasGReg = true
+ c.noDuffDevice = obj.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
+ c.lowerValue = rewriteValuePPC64
+ c.registers = registersPPC64[:]
+ c.gpRegMask = gpRegMaskPPC64
+ c.fpRegMask = fpRegMaskPPC64
+ 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
+ c.lowerValue = rewriteValueMIPS64
+ c.registers = registersMIPS64[:]
+ c.gpRegMask = gpRegMaskMIPS64
+ c.fpRegMask = fpRegMaskMIPS64
+ c.specialRegMask = specialRegMaskMIPS64
+ c.FPReg = framepointerRegMIPS64
+ c.LinkReg = linkRegMIPS64
+ c.hasGReg = true
+ case "s390x":
+ c.IntSize = 8
+ c.PtrSize = 8
+ c.RegSize = 8
+ c.lowerBlock = rewriteBlockS390X
+ c.lowerValue = rewriteValueS390X
+ c.registers = registersS390X[:]
+ c.gpRegMask = gpRegMaskS390X
+ c.fpRegMask = fpRegMaskS390X
+ c.FPReg = framepointerRegS390X
+ c.LinkReg = linkRegS390X
+ c.hasGReg = true
+ c.noDuffDevice = true
+ c.BigEndian = true
+ case "mips":
+ c.BigEndian = true
+ fallthrough
+ case "mipsle":
+ c.IntSize = 4
+ c.PtrSize = 4
+ c.RegSize = 4
+ c.lowerBlock = rewriteBlockMIPS
+ c.lowerValue = rewriteValueMIPS
+ c.registers = registersMIPS[:]
+ c.gpRegMask = gpRegMaskMIPS
+ c.fpRegMask = fpRegMaskMIPS
+ c.specialRegMask = specialRegMaskMIPS
+ c.FPReg = framepointerRegMIPS
+ c.LinkReg = linkRegMIPS
+ c.hasGReg = true
+ c.noDuffDevice = true
default:
- fe.Unimplementedf(0, "arch %s not implemented", arch)
+ fe.Fatalf(0, "arch %s not implemented", arch)
}
c.ctxt = ctxt
c.optimize = optimize
+ c.nacl = obj.GOOS == "nacl"
- // Don't use Duff's device on Plan 9, because floating
+ // Don't use Duff's device on Plan 9 AMD64, because floating
// point operations are not allowed in note handler.
- if obj.Getgoos() == "plan9" {
+ if obj.GOOS == "plan9" && arch == "amd64" {
c.noDuffDevice = true
}
+ if c.nacl {
+ c.noDuffDevice = true // Don't use Duff's device on NaCl
+
+ // runtime call clobber R12 on nacl
+ opcodeTable[OpARMUDIVrtcall].reg.clobbers |= 1 << 12 // R12
+ }
+
// Assign IDs to preallocated values/blocks.
for i := range c.values {
c.values[i].ID = ID(i)
@@ -180,8 +317,14 @@ func NewConfig(arch string, fe Frontend, ctxt *obj.Link, optimize bool) *Config
return c
}
+func (c *Config) Set387(b bool) {
+ c.NeedsFpScratch = b
+ 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.
@@ -198,11 +341,9 @@ func (c *Config) NewFunc() *Func {
func (c *Config) Logf(msg string, args ...interface{}) { c.fe.Logf(msg, args...) }
func (c *Config) Log() bool { return c.fe.Log() }
func (c *Config) Fatalf(line int32, msg string, args ...interface{}) { c.fe.Fatalf(line, msg, args...) }
-func (c *Config) Unimplementedf(line int32, msg string, args ...interface{}) {
- c.fe.Unimplementedf(line, msg, args...)
-}
-func (c *Config) Warnl(line int32, msg string, args ...interface{}) { c.fe.Warnl(line, msg, args...) }
-func (c *Config) Debug_checknil() bool { return c.fe.Debug_checknil() }
+func (c *Config) 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]
diff --git a/src/cmd/compile/internal/ssa/cse.go b/src/cmd/compile/internal/ssa/cse.go
index ad4e416..4e07c89 100644
--- a/src/cmd/compile/internal/ssa/cse.go
+++ b/src/cmd/compile/internal/ssa/cse.go
@@ -9,10 +9,6 @@ import (
"sort"
)
-const (
- cmpDepth = 4
-)
-
// cse does common-subexpression elimination on the Function.
// Values are just relinked, nothing is deleted. A subsequent deadcode
// pass is required to actually remove duplicate expressions.
@@ -60,7 +56,8 @@ func cse(f *Func) {
valueEqClass[v.ID] = -v.ID
}
}
- for i, e := range partition {
+ var pNum ID = 1
+ for _, e := range partition {
if f.pass.debug > 1 && len(e) > 500 {
fmt.Printf("CSE.large partition (%d): ", len(e))
for j := 0; j < 3; j++ {
@@ -70,20 +67,23 @@ func cse(f *Func) {
}
for _, v := range e {
- valueEqClass[v.ID] = ID(i)
+ valueEqClass[v.ID] = pNum
}
if f.pass.debug > 2 && len(e) > 1 {
- fmt.Printf("CSE.partition #%d:", i)
+ fmt.Printf("CSE.partition #%d:", pNum)
for _, v := range e {
fmt.Printf(" %s", v.String())
}
fmt.Printf("\n")
}
+ pNum++
}
- // Find an equivalence class where some members of the class have
- // non-equivalent arguments. Split the equivalence class appropriately.
- // Repeat until we can't find any more splits.
+ // Split equivalence classes at points where they have
+ // non-equivalent arguments. Repeat until we can't find any
+ // more splits.
+ var splitPoints []int
+ byArgClass := new(partitionByArgClass) // reuseable partitionByArgClass to reduce allocations
for {
changed := false
@@ -91,39 +91,53 @@ func cse(f *Func) {
// we process new additions as they arrive, avoiding O(n^2) behavior.
for i := 0; i < len(partition); i++ {
e := partition[i]
- v := e[0]
- // all values in this equiv class that are not equivalent to v get moved
- // into another equiv class.
- // To avoid allocating while building that equivalence class,
- // move the values equivalent to v to the beginning of e
- // and other values to the end of e.
- allvals := e
- eqloop:
- for j := 1; j < len(e); {
- w := e[j]
- equivalent := true
- for i := 0; i < len(v.Args); i++ {
- if valueEqClass[v.Args[i].ID] != valueEqClass[w.Args[i].ID] {
- equivalent = false
+
+ // Sort by eq class of arguments.
+ byArgClass.a = e
+ byArgClass.eqClass = valueEqClass
+ sort.Sort(byArgClass)
+
+ // Find split points.
+ splitPoints = append(splitPoints[:0], 0)
+ for j := 1; j < len(e); j++ {
+ v, w := e[j-1], e[j]
+ eqArgs := true
+ for k, a := range v.Args {
+ b := w.Args[k]
+ if valueEqClass[a.ID] != valueEqClass[b.ID] {
+ eqArgs = false
break
}
}
- if !equivalent || v.Type.Compare(w.Type) != CMPeq {
- // w is not equivalent to v.
- // move it to the end and shrink e.
- e[j], e[len(e)-1] = e[len(e)-1], e[j]
- e = e[:len(e)-1]
- valueEqClass[w.ID] = ID(len(partition))
- changed = true
- continue eqloop
+ if !eqArgs {
+ splitPoints = append(splitPoints, j)
}
- // v and w are equivalent. Keep w in e.
- j++
}
- partition[i] = e
- if len(e) < len(allvals) {
- partition = append(partition, allvals[len(e):])
+ if len(splitPoints) == 1 {
+ continue // no splits, leave equivalence class alone.
+ }
+
+ // Move another equivalence class down in place of e.
+ partition[i] = partition[len(partition)-1]
+ partition = partition[:len(partition)-1]
+ i--
+
+ // Add new equivalence classes for the parts of e we found.
+ splitPoints = append(splitPoints, len(e))
+ for j := 0; j < len(splitPoints)-1; j++ {
+ f := e[splitPoints[j]:splitPoints[j+1]]
+ if len(f) == 1 {
+ // Don't add singletons.
+ valueEqClass[f[0].ID] = -f[0].ID
+ continue
+ }
+ for _, v := range f {
+ valueEqClass[v.ID] = pNum
+ }
+ pNum++
+ partition = append(partition, f)
}
+ changed = true
}
if !changed {
@@ -131,13 +145,16 @@ func cse(f *Func) {
}
}
- // Dominator tree (f.sdom) is computed by the generic domtree pass.
+ sdom := f.sdom()
// Compute substitutions we would like to do. We substitute v for w
// if v and w are in the same equivalence class and v dominates w.
rewrite := make([]*Value, f.NumValues())
+ byDom := new(partitionByDom) // reusable partitionByDom to reduce allocs
for _, e := range partition {
- sort.Sort(partitionByDom{e, f.sdom})
+ byDom.a = e
+ byDom.sdom = sdom
+ sort.Sort(byDom)
for i := 0; i < len(e)-1; i++ {
// e is sorted by domorder, so a maximal dominant element is first in the slice
v := e[i]
@@ -152,7 +169,7 @@ func cse(f *Func) {
if w == nil {
continue
}
- if f.sdom.isAncestorEq(v.Block, w.Block) {
+ if sdom.isAncestorEq(v.Block, w.Block) {
rewrite[w.ID] = v
e[j] = nil
} else {
@@ -163,6 +180,43 @@ func cse(f *Func) {
}
}
+ // if we rewrite a tuple generator to a new one in a different block,
+ // copy its selectors to the new generator's block, so tuple generator
+ // and selectors stay together.
+ // be careful not to copy same selectors more than once (issue 16741).
+ copiedSelects := make(map[ID][]*Value)
+ for _, b := range f.Blocks {
+ out:
+ for _, v := range b.Values {
+ // New values are created when selectors are copied to
+ // a new block. We can safely ignore those new values,
+ // since they have already been copied (issue 17918).
+ if int(v.ID) >= len(rewrite) || rewrite[v.ID] != nil {
+ continue
+ }
+ if v.Op != OpSelect0 && v.Op != OpSelect1 {
+ continue
+ }
+ if !v.Args[0].Type.IsTuple() {
+ f.Fatalf("arg of tuple selector %s is not a tuple: %s", v.String(), v.Args[0].LongString())
+ }
+ t := rewrite[v.Args[0].ID]
+ if t != nil && t.Block != b {
+ // v.Args[0] is tuple generator, CSE'd into a different block as t, v is left behind
+ for _, c := range copiedSelects[t.ID] {
+ if v.Op == c.Op {
+ // an equivalent selector is already copied
+ rewrite[v.ID] = c
+ continue out
+ }
+ }
+ c := v.copyInto(t.Block)
+ rewrite[v.ID] = c
+ copiedSelects[t.ID] = append(copiedSelects[t.ID], c)
+ }
+ }
+ }
+
rewrites := int64(0)
// Apply substitutions
@@ -219,7 +273,7 @@ func partitionValues(a []*Value, auxIDs auxmap) []eqclass {
j := 1
for ; j < len(a); j++ {
w := a[j]
- if cmpVal(v, w, auxIDs, cmpDepth) != CMPeq {
+ if cmpVal(v, w, auxIDs) != CMPeq {
break
}
}
@@ -240,7 +294,7 @@ func lt2Cmp(isLt bool) Cmp {
type auxmap map[interface{}]int32
-func cmpVal(v, w *Value, auxIDs auxmap, depth int) Cmp {
+func cmpVal(v, w *Value, auxIDs auxmap) Cmp {
// Try to order these comparison by cost (cheaper first)
if v.Op != w.Op {
return lt2Cmp(v.Op < w.Op)
@@ -274,18 +328,6 @@ func cmpVal(v, w *Value, auxIDs auxmap, depth int) Cmp {
return lt2Cmp(auxIDs[v.Aux] < auxIDs[w.Aux])
}
- if depth > 0 {
- for i := range v.Args {
- if v.Args[i] == w.Args[i] {
- // skip comparing equal args
- continue
- }
- if ac := cmpVal(v.Args[i], w.Args[i], auxIDs, depth-1); ac != CMPeq {
- return ac
- }
- }
- }
-
return CMPeq
}
@@ -300,7 +342,7 @@ func (sv sortvalues) Swap(i, j int) { sv.a[i], sv.a[j] = sv.a[j], sv.a[i] }
func (sv sortvalues) Less(i, j int) bool {
v := sv.a[i]
w := sv.a[j]
- if cmp := cmpVal(v, w, sv.auxIDs, cmpDepth); cmp != CMPeq {
+ if cmp := cmpVal(v, w, sv.auxIDs); cmp != CMPeq {
return cmp == CMPlt
}
@@ -320,3 +362,25 @@ func (sv partitionByDom) Less(i, j int) bool {
w := sv.a[j]
return sv.sdom.domorder(v.Block) < sv.sdom.domorder(w.Block)
}
+
+type partitionByArgClass struct {
+ a []*Value // array of values
+ eqClass []ID // equivalence class IDs of values
+}
+
+func (sv partitionByArgClass) Len() int { return len(sv.a) }
+func (sv partitionByArgClass) Swap(i, j int) { sv.a[i], sv.a[j] = sv.a[j], sv.a[i] }
+func (sv partitionByArgClass) Less(i, j int) bool {
+ v := sv.a[i]
+ w := sv.a[j]
+ for i, a := range v.Args {
+ b := w.Args[i]
+ if sv.eqClass[a.ID] < sv.eqClass[b.ID] {
+ return true
+ }
+ if sv.eqClass[a.ID] > sv.eqClass[b.ID] {
+ return false
+ }
+ }
+ return false
+}
diff --git a/src/cmd/compile/internal/ssa/cse_test.go b/src/cmd/compile/internal/ssa/cse_test.go
index d5be2b5..905939f 100644
--- a/src/cmd/compile/internal/ssa/cse_test.go
+++ b/src/cmd/compile/internal/ssa/cse_test.go
@@ -44,7 +44,6 @@ func TestCSEAuxPartitionBug(t *testing.T) {
Exit("rstore")))
CheckFunc(fun.f)
- domTree(fun.f)
cse(fun.f)
deadcode(fun.f)
CheckFunc(fun.f)
diff --git a/src/cmd/compile/internal/ssa/deadcode.go b/src/cmd/compile/internal/ssa/deadcode.go
index 5ccf390..d75d2d5 100644
--- a/src/cmd/compile/internal/ssa/deadcode.go
+++ b/src/cmd/compile/internal/ssa/deadcode.go
@@ -54,6 +54,7 @@ func liveValues(f *Func, reachable []bool) []bool {
var q []*Value // stack-like worklist of unscanned values
// Starting set: all control values of reachable blocks are live.
+ // Calls are live (because callee can observe the memory state).
for _, b := range f.Blocks {
if !reachable[b.ID] {
continue
@@ -62,6 +63,17 @@ func liveValues(f *Func, reachable []bool) []bool {
live[v.ID] = true
q = append(q, v)
}
+ for _, v := range b.Values {
+ if opcodeTable[v.Op].call && !live[v.ID] {
+ live[v.ID] = true
+ q = append(q, v)
+ }
+ if v.Type.IsVoid() && !live[v.ID] {
+ // The only Void ops are nil checks. We must keep these.
+ live[v.ID] = true
+ q = append(q, v)
+ }
+ }
}
// Compute transitive closure of live values.
diff --git a/src/cmd/compile/internal/ssa/deadstore.go b/src/cmd/compile/internal/ssa/deadstore.go
index 59ac1b9..89ab17a 100644
--- a/src/cmd/compile/internal/ssa/deadstore.go
+++ b/src/cmd/compile/internal/ssa/deadstore.go
@@ -29,6 +29,10 @@ 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)
@@ -80,7 +84,12 @@ func dse(f *Func) {
shadowed.clear()
}
if v.Op == OpStore || v.Op == OpZero {
- sz := v.AuxInt
+ var sz int64
+ if v.Op == OpStore {
+ sz = v.AuxInt
+ } else { // OpZero
+ sz = SizeAndAlign(v.AuxInt).Size()
+ }
if shadowedSize := int64(shadowed.get(v.Args[0].ID)); shadowedSize != -1 && shadowedSize >= sz {
// Modify store into a copy
if v.Op == OpStore {
@@ -102,7 +111,7 @@ func dse(f *Func) {
if sz > 0x7fffffff { // work around sparseMap's int32 value type
sz = 0x7fffffff
}
- shadowed.set(v.Args[0].ID, int32(sz))
+ shadowed.set(v.Args[0].ID, int32(sz), 0)
}
}
// walk to previous store
diff --git a/src/cmd/compile/internal/ssa/decompose.go b/src/cmd/compile/internal/ssa/decompose.go
index 53116ba..b2ee2f0 100644
--- a/src/cmd/compile/internal/ssa/decompose.go
+++ b/src/cmd/compile/internal/ssa/decompose.go
@@ -25,6 +25,22 @@ 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
+ if t.IsSigned() {
+ elemType = f.Config.fe.TypeInt32()
+ } else {
+ elemType = f.Config.fe.TypeUInt32()
+ }
+ hiName, loName := f.Config.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)
+ 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
if t.Size() == 16 {
@@ -78,8 +94,10 @@ func decomposeBuiltIn(f *Func) {
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:
- f.Unimplementedf("undecomposed named type %s %s", name, t)
+ f.Fatalf("undecomposed named type %v %v", name, t)
default:
newNames = append(newNames, name)
}
@@ -88,8 +106,13 @@ func decomposeBuiltIn(f *Func) {
}
func decomposeBuiltInPhi(v *Value) {
- // TODO: decompose 64-bit ops on 32-bit archs?
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
+ }
+ decomposeInt64Phi(v)
case v.Type.IsComplex():
decomposeComplexPhi(v)
case v.Type.IsString():
@@ -98,8 +121,10 @@ func decomposeBuiltInPhi(v *Value) {
decomposeSlicePhi(v)
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:
- v.Unimplementedf("undecomposed type %s", v.Type)
+ v.Fatalf("undecomposed type %s", v.Type)
}
}
@@ -138,6 +163,26 @@ func decomposeSlicePhi(v *Value) {
v.AddArg(cap)
}
+func decomposeInt64Phi(v *Value) {
+ fe := v.Block.Func.Config.fe
+ var partType Type
+ if v.Type.IsSigned() {
+ partType = fe.TypeInt32()
+ } else {
+ partType = fe.TypeUInt32()
+ }
+
+ hi := v.Block.NewValue0(v.Line, OpPhi, partType)
+ lo := v.Block.NewValue0(v.Line, OpPhi, fe.TypeUInt32())
+ 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))
+ }
+ v.reset(OpInt64Make)
+ v.AddArg(hi)
+ v.AddArg(lo)
+}
+
func decomposeComplexPhi(v *Value) {
fe := v.Block.Func.Config.fe
var partType Type
@@ -208,6 +253,21 @@ func decomposeUser(f *Func) {
}
delete(f.NamedValues, name)
newNames = append(newNames, fnames...)
+ case t.IsArray():
+ if t.NumElem() == 0 {
+ // TODO(khr): Not sure what to do here. Probably nothing.
+ // Names for empty arrays aren't important.
+ break
+ }
+ if t.NumElem() != 1 {
+ f.Fatalf("array not of size 1")
+ }
+ elemName := f.Config.fe.SplitArray(name)
+ for _, v := range f.NamedValues[name] {
+ e := v.Block.NewValue1I(v.Line, OpArraySelect, t.ElemType(), 0, v)
+ f.NamedValues[elemName] = append(f.NamedValues[elemName], e)
+ }
+
default:
f.Names[i] = name
i++
@@ -221,10 +281,13 @@ func decomposeUserPhi(v *Value) {
switch {
case v.Type.IsStruct():
decomposeStructPhi(v)
+ case v.Type.IsArray():
+ decomposeArrayPhi(v)
}
- // TODO: Arrays of length 1?
}
+// decomposeStructPhi replaces phi-of-struct with structmake(phi-for-each-field),
+// and then recursively decomposes the phis for each field.
func decomposeStructPhi(v *Value) {
t := v.Type
n := t.NumFields()
@@ -242,10 +305,30 @@ func decomposeStructPhi(v *Value) {
// Recursively decompose phis for each field.
for _, f := range fields[:n] {
- if f.Type.IsStruct() {
- decomposeStructPhi(f)
- }
+ decomposeUserPhi(f)
+ }
+}
+
+// decomposeArrayPhi replaces phi-of-array with arraymake(phi-of-array-element),
+// and then recursively decomposes the element phi.
+func decomposeArrayPhi(v *Value) {
+ t := v.Type
+ if t.NumElem() == 0 {
+ v.reset(OpArrayMake0)
+ return
+ }
+ if t.NumElem() != 1 {
+ v.Fatalf("SSAable array must have no more than 1 element")
}
+ elem := v.Block.NewValue0(v.Line, OpPhi, t.ElemType())
+ for _, a := range v.Args {
+ elem.AddArg(a.Block.NewValue1I(v.Line, OpArraySelect, t.ElemType(), 0, a))
+ }
+ v.reset(OpArrayMake1)
+ v.AddArg(elem)
+
+ // Recursively decompose elem phi.
+ decomposeUserPhi(elem)
}
// MaxStruct is the maximum number of fields a struct
diff --git a/src/cmd/compile/internal/ssa/dom.go b/src/cmd/compile/internal/ssa/dom.go
index 0c532c8..4790e33 100644
--- a/src/cmd/compile/internal/ssa/dom.go
+++ b/src/cmd/compile/internal/ssa/dom.go
@@ -247,7 +247,7 @@ func dominatorsSimple(f *Func) []*Block {
idom := make([]*Block, f.NumBlocks())
// Compute postorder walk
- post := postorder(f)
+ post := f.postorder()
// Make map from block id to order index (for intersect call)
postnum := make([]int, f.NumBlocks())
@@ -306,9 +306,3 @@ func intersect(b, c *Block, postnum []int, idom []*Block) *Block {
}
return b
}
-
-// build immediate dominators.
-func domTree(f *Func) {
- f.idom = dominators(f)
- f.sdom = newSparseTree(f, f.idom)
-}
diff --git a/src/cmd/compile/internal/ssa/export_test.go b/src/cmd/compile/internal/ssa/export_test.go
index 27892a8..010c4d7 100644
--- a/src/cmd/compile/internal/ssa/export_test.go
+++ b/src/cmd/compile/internal/ssa/export_test.go
@@ -49,22 +49,34 @@ func (d DummyFrontend) SplitComplex(s LocalSlot) (LocalSlot, LocalSlot) {
}
return LocalSlot{s.N, d.TypeFloat32(), s.Off}, LocalSlot{s.N, d.TypeFloat32(), 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, d.TypeUInt32(), s.Off + 4}, LocalSlot{s.N, d.TypeUInt32(), 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)}
}
+func (d DummyFrontend) SplitArray(s LocalSlot) LocalSlot {
+ return LocalSlot{s.N, s.Type.ElemType(), s.Off}
+}
func (DummyFrontend) Line(line int32) string {
return "unknown.go:0"
}
+func (DummyFrontend) AllocFrame(f *Func) {
+}
+func (DummyFrontend) Syslook(s string) interface{} {
+ return nil
+}
func (d DummyFrontend) Logf(msg string, args ...interface{}) { d.t.Logf(msg, args...) }
func (d DummyFrontend) Log() bool { return true }
func (d DummyFrontend) Fatalf(line int32, msg string, args ...interface{}) { d.t.Fatalf(msg, args...) }
-func (d DummyFrontend) Unimplementedf(line int32, msg string, args ...interface{}) {
- d.t.Fatalf(msg, args...)
-}
-func (d DummyFrontend) Warnl(line int32, msg string, args ...interface{}) { d.t.Logf(msg, args...) }
-func (d DummyFrontend) Debug_checknil() bool { return false }
+func (d DummyFrontend) Warnl(line int32, 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 }
diff --git a/src/cmd/compile/internal/ssa/flagalloc.go b/src/cmd/compile/internal/ssa/flagalloc.go
index f6c457d..24b6a0e 100644
--- a/src/cmd/compile/internal/ssa/flagalloc.go
+++ b/src/cmd/compile/internal/ssa/flagalloc.go
@@ -4,8 +4,6 @@
package ssa
-const flagRegMask = regMask(1) << 33 // TODO: arch-specific
-
// flagalloc allocates the flag register among all the flag-generating
// instructions. Flag values are recomputed if they need to be
// spilled/restored.
@@ -13,14 +11,10 @@ func flagalloc(f *Func) {
// Compute the in-register flag value we want at the end of
// each block. This is basically a best-effort live variable
// analysis, so it can be much simpler than a full analysis.
- // TODO: do we really need to keep flag values live across blocks?
- // Could we force the flags register to be unused at basic block
- // boundaries? Then we wouldn't need this computation.
end := make([]*Value, f.NumBlocks())
+ po := f.postorder()
for n := 0; n < 2; n++ {
- // Walk blocks backwards. Poor-man's postorder traversal.
- for i := len(f.Blocks) - 1; i >= 0; i-- {
- b := f.Blocks[i]
+ for _, b := range po {
// Walk values backwards to figure out what flag
// value we want in the flag register at the start
// of the block.
@@ -33,7 +27,7 @@ func flagalloc(f *Func) {
if v == flag {
flag = nil
}
- if opcodeTable[v.Op].reg.clobbers&flagRegMask != 0 {
+ if v.clobbersFlags() {
flag = nil
}
for _, a := range v.Args {
@@ -97,7 +91,7 @@ func flagalloc(f *Func) {
continue
}
// Recalculate a
- c := a.copyInto(b)
+ c := copyFlags(a, b)
// Update v.
v.SetArg(i, c)
// Remember the most-recently computed flag value.
@@ -105,7 +99,7 @@ func flagalloc(f *Func) {
}
// Issue v.
b.Values = append(b.Values, v)
- if opcodeTable[v.Op].reg.clobbers&flagRegMask != 0 {
+ if v.clobbersFlags() {
flag = nil
}
if v.Type.IsFlags() {
@@ -121,7 +115,7 @@ func flagalloc(f *Func) {
if v := end[b.ID]; v != nil && v != flag {
// Need to reissue flag generator for use by
// subsequent blocks.
- _ = v.copyInto(b)
+ copyFlags(v, b)
// Note: this flag generator is not properly linked up
// with the flag users. This breaks the SSA representation.
// We could fix up the users with another pass, but for now
@@ -135,3 +129,32 @@ func flagalloc(f *Func) {
b.FlagsLiveAtEnd = end[b.ID] != nil
}
}
+
+func (v *Value) clobbersFlags() bool {
+ if opcodeTable[v.Op].clobberFlags {
+ return true
+ }
+ if v.Type.IsTuple() && (v.Type.FieldType(0).IsFlags() || v.Type.FieldType(1).IsFlags()) {
+ // This case handles the possibility where a flag value is generated but never used.
+ // In that case, there's no corresponding Select to overwrite the flags value,
+ // so we must consider flags clobbered by the tuple-generating instruction.
+ return true
+ }
+ return false
+}
+
+// copyFlags copies v (flag generator) into b, returns the copy.
+// If v's arg is also flags, copy recursively.
+func copyFlags(v *Value, b *Block) *Value {
+ flagsArgs := make(map[int]*Value)
+ for i, a := range v.Args {
+ if a.Type.IsFlags() || a.Type.IsTuple() {
+ flagsArgs[i] = copyFlags(a, b)
+ }
+ }
+ c := v.copyInto(b)
+ for i, a := range flagsArgs {
+ c.SetArg(i, a)
+ }
+ return c
+}
diff --git a/src/cmd/compile/internal/ssa/func.go b/src/cmd/compile/internal/ssa/func.go
index 1d60bb6..7b2097b 100644
--- a/src/cmd/compile/internal/ssa/func.go
+++ b/src/cmd/compile/internal/ssa/func.go
@@ -7,6 +7,7 @@ package ssa
import (
"fmt"
"math"
+ "strings"
)
// A Func represents a Go func declaration (or function literal) and
@@ -36,8 +37,10 @@ type Func struct {
freeValues *Value // free Values linked by argstorage[0]. All other fields except ID are 0/nil.
freeBlocks *Block // free Blocks linked by succstorage[0].b. All other fields except ID are 0/nil.
- idom []*Block // precomputed immediate dominators
- sdom SparseTree // precomputed dominator tree
+ cachedPostorder []*Block // cached postorder traversal
+ cachedIdom []*Block // cached immediate dominators
+ cachedSdom SparseTree // cached dominator tree
+ cachedLoopnest *loopnest // cached loop nest information
constants map[int64][]*Value // constants cache, keyed by constant value; users must check value's Op and Type
}
@@ -111,7 +114,7 @@ func (f *Func) LogStat(key string, args ...interface{}) {
}
n := "missing_pass"
if f.pass != nil {
- n = f.pass.name
+ 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)
}
@@ -166,6 +169,7 @@ func (f *Func) NewBlock(kind BlockKind) *Block {
b.Succs = b.succstorage[:0]
b.Values = b.valstorage[:0]
f.Blocks = append(f.Blocks, b)
+ f.invalidateCFG()
return b
}
@@ -315,6 +319,18 @@ func (b *Block) NewValue3I(line int32, op Op, t Type, auxint int64, arg0, arg1,
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)
+ v.AuxInt = 0
+ v.Args = []*Value{arg0, arg1, arg2, arg3}
+ arg0.Uses++
+ arg1.Uses++
+ arg2.Uses++
+ arg3.Uses++
+ return v
+}
+
// constVal returns a constant value for c.
func (f *Func) constVal(line int32, op Op, t Type, c int64, setAux bool) *Value {
if f.constants == nil {
@@ -395,11 +411,11 @@ func (f *Func) ConstEmptyString(line int32, t Type) *Value {
func (f *Func) Logf(msg string, args ...interface{}) { f.Config.Logf(msg, args...) }
func (f *Func) Log() bool { return f.Config.Log() }
func (f *Func) Fatalf(msg string, args ...interface{}) { f.Config.Fatalf(f.Entry.Line, msg, args...) }
-func (f *Func) Unimplementedf(msg string, args ...interface{}) {
- f.Config.Unimplementedf(f.Entry.Line, msg, args...)
-}
func (f *Func) Free() {
+ // Clear cached CFG info.
+ f.invalidateCFG()
+
// Clear values.
n := f.vid.num()
if n > len(f.Config.values) {
@@ -427,3 +443,45 @@ func (f *Func) Free() {
f.Config.curFunc = nil
*f = Func{} // just in case
}
+
+// postorder returns the reachable blocks in f in a postorder traversal.
+func (f *Func) postorder() []*Block {
+ if f.cachedPostorder == nil {
+ f.cachedPostorder = postorder(f)
+ }
+ return f.cachedPostorder
+}
+
+// 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 {
+ if f.cachedIdom == nil {
+ f.cachedIdom = dominators(f)
+ }
+ return f.cachedIdom
+}
+
+// sdom returns a sparse tree representing the dominator relationships
+// among the blocks of f.
+func (f *Func) sdom() SparseTree {
+ if f.cachedSdom == nil {
+ f.cachedSdom = newSparseTree(f, f.Idom())
+ }
+ return f.cachedSdom
+}
+
+// loopnest returns the loop nest information for f.
+func (f *Func) loopnest() *loopnest {
+ if f.cachedLoopnest == nil {
+ f.cachedLoopnest = loopnestfor(f)
+ }
+ return f.cachedLoopnest
+}
+
+// invalidateCFG tells f that its CFG has changed.
+func (f *Func) invalidateCFG() {
+ f.cachedPostorder = nil
+ f.cachedIdom = nil
+ f.cachedSdom = nil
+ f.cachedLoopnest = nil
+}
diff --git a/src/cmd/compile/internal/ssa/fuse.go b/src/cmd/compile/internal/ssa/fuse.go
index afb8bb2..d5940da 100644
--- a/src/cmd/compile/internal/ssa/fuse.go
+++ b/src/cmd/compile/internal/ssa/fuse.go
@@ -135,9 +135,11 @@ func fuseBlockPlain(b *Block) bool {
p := e.b
p.Succs[e.i] = Edge{c, i}
}
- if f := b.Func; f.Entry == b {
+ f := b.Func
+ if f.Entry == b {
f.Entry = c
}
+ f.invalidateCFG()
// trash b, just in case
b.Kind = BlockInvalid
diff --git a/src/cmd/compile/internal/ssa/gen/386.rules b/src/cmd/compile/internal/ssa/gen/386.rules
new file mode 100644
index 0000000..a3f2ecb
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/gen/386.rules
@@ -0,0 +1,1252 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Lowering arithmetic
+(AddPtr x y) -> (ADDL x y)
+(Add32 x y) -> (ADDL x y)
+(Add16 x y) -> (ADDL x y)
+(Add8 x y) -> (ADDL x y)
+(Add32F x y) -> (ADDSS x y)
+(Add64F x y) -> (ADDSD x y)
+
+(Add32carry x y) -> (ADDLcarry x y)
+(Add32withcarry x y c) -> (ADCL x y c)
+
+(SubPtr x y) -> (SUBL x y)
+(Sub32 x y) -> (SUBL x y)
+(Sub16 x y) -> (SUBL x y)
+(Sub8 x y) -> (SUBL x y)
+(Sub32F x y) -> (SUBSS x y)
+(Sub64F x y) -> (SUBSD x y)
+
+(Sub32carry x y) -> (SUBLcarry x y)
+(Sub32withcarry x y c) -> (SBBL x y c)
+
+(Mul32 x y) -> (MULL x y)
+(Mul16 x y) -> (MULL x y)
+(Mul8 x y) -> (MULL x y)
+(Mul32F x y) -> (MULSS x y)
+(Mul64F x y) -> (MULSD x y)
+
+(Mul32uhilo x y) -> (MULLQU x y)
+
+(Div32F x y) -> (DIVSS x y)
+(Div64F x y) -> (DIVSD x y)
+
+(Div32 x y) -> (DIVL x y)
+(Div32u x y) -> (DIVLU x y)
+(Div16 x y) -> (DIVW x y)
+(Div16u x y) -> (DIVWU x y)
+(Div8 x y) -> (DIVW (SignExt8to16 x) (SignExt8to16 y))
+(Div8u x y) -> (DIVWU (ZeroExt8to16 x) (ZeroExt8to16 y))
+
+(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)
+(Mod16 x y) -> (MODW x y)
+(Mod16u x y) -> (MODWU x y)
+(Mod8 x y) -> (MODW (SignExt8to16 x) (SignExt8to16 y))
+(Mod8u x y) -> (MODWU (ZeroExt8to16 x) (ZeroExt8to16 y))
+
+(And32 x y) -> (ANDL x y)
+(And16 x y) -> (ANDL x y)
+(And8 x y) -> (ANDL x y)
+
+(Or32 x y) -> (ORL x y)
+(Or16 x y) -> (ORL x y)
+(Or8 x y) -> (ORL x y)
+
+(Xor32 x y) -> (XORL x y)
+(Xor16 x y) -> (XORL x y)
+(Xor8 x y) -> (XORL x y)
+
+(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 -> (FCHS x)
+(Neg64F x) && config.use387 -> (FCHS x)
+
+(Com32 x) -> (NOTL x)
+(Com16 x) -> (NOTL x)
+(Com8 x) -> (NOTL x)
+
+// Lowering boolean ops
+(AndB x y) -> (ANDL x y)
+(OrB x y) -> (ORL x y)
+(Not x) -> (XORLconst [1] x)
+
+// Lowering pointer arithmetic
+(OffPtr [off] ptr) -> (ADDLconst [off] ptr)
+
+(Bswap32 x) -> (BSWAPL x)
+
+(Sqrt x) -> (SQRTSD x)
+
+// Lowering extension
+(SignExt8to16 x) -> (MOVBLSX x)
+(SignExt8to32 x) -> (MOVBLSX x)
+(SignExt16to32 x) -> (MOVWLSX x)
+
+(ZeroExt8to16 x) -> (MOVBLZX x)
+(ZeroExt8to32 x) -> (MOVBLZX x)
+(ZeroExt16to32 x) -> (MOVWLZX x)
+
+(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]))
+
+// Lowering truncation
+// Because we ignore high parts of registers, truncates are just copies.
+(Trunc16to8 x) -> x
+(Trunc32to8 x) -> x
+(Trunc32to16 x) -> x
+
+// Lowering float <-> int
+(Cvt32to32F x) -> (CVTSL2SS x)
+(Cvt32to64F x) -> (CVTSL2SD x)
+
+(Cvt32Fto32 x) -> (CVTTSS2SL x)
+(Cvt64Fto32 x) -> (CVTTSD2SL x)
+
+(Cvt32Fto64F x) -> (CVTSS2SD x)
+(Cvt64Fto32F x) -> (CVTSD2SS x)
+
+// Lowering shifts
+// Unsigned shifts need to return 0 if shift amount is >= width of shifted value.
+// result = (arg << shift) & (shift >= argbits ? 0 : 0xffffffffffffffff)
+(Lsh32x32 <t> x y) -> (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPLconst y [32])))
+(Lsh32x16 <t> x y) -> (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPWconst y [32])))
+(Lsh32x8 <t> x y) -> (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPBconst y [32])))
+
+(Lsh16x32 <t> x y) -> (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPLconst y [32])))
+(Lsh16x16 <t> x y) -> (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPWconst y [32])))
+(Lsh16x8 <t> x y) -> (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPBconst y [32])))
+
+(Lsh8x32 <t> x y) -> (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPLconst y [32])))
+(Lsh8x16 <t> x y) -> (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPWconst y [32])))
+(Lsh8x8 <t> x y) -> (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPBconst y [32])))
+
+(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])))
+
+(Rsh16Ux32 <t> x y) -> (ANDL (SHRW <t> x y) (SBBLcarrymask <t> (CMPLconst y [16])))
+(Rsh16Ux16 <t> x y) -> (ANDL (SHRW <t> x y) (SBBLcarrymask <t> (CMPWconst y [16])))
+(Rsh16Ux8 <t> x y) -> (ANDL (SHRW <t> x y) (SBBLcarrymask <t> (CMPBconst y [16])))
+
+(Rsh8Ux32 <t> x y) -> (ANDL (SHRB <t> x y) (SBBLcarrymask <t> (CMPLconst y [8])))
+(Rsh8Ux16 <t> x y) -> (ANDL (SHRB <t> x y) (SBBLcarrymask <t> (CMPWconst y [8])))
+(Rsh8Ux8 <t> x y) -> (ANDL (SHRB <t> x y) (SBBLcarrymask <t> (CMPBconst y [8])))
+
+// Signed right shift needs to return 0/-1 if shift amount is >= width of shifted value.
+// We implement this by setting the shift value to -1 (all ones) if the shift value is >= width.
+
+(Rsh32x32 <t> x y) -> (SARL <t> x (ORL <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPLconst y [32])))))
+(Rsh32x16 <t> x y) -> (SARL <t> x (ORL <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPWconst y [32])))))
+(Rsh32x8 <t> x y) -> (SARL <t> x (ORL <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPBconst y [32])))))
+
+(Rsh16x32 <t> x y) -> (SARW <t> x (ORL <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPLconst y [16])))))
+(Rsh16x16 <t> x y) -> (SARW <t> x (ORL <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPWconst y [16])))))
+(Rsh16x8 <t> x y) -> (SARW <t> x (ORL <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPBconst y [16])))))
+
+(Rsh8x32 <t> x y) -> (SARB <t> x (ORL <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPLconst y [8])))))
+(Rsh8x16 <t> x y) -> (SARB <t> x (ORL <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPWconst y [8])))))
+(Rsh8x8 <t> x y) -> (SARB <t> x (ORL <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPBconst y [8])))))
+
+// constant shifts
+// generic opt rewrites all constant shifts to shift by Const64
+(Lsh32x64 x (Const64 [c])) && uint64(c) < 32 -> (SHLLconst x [c])
+(Rsh32x64 x (Const64 [c])) && uint64(c) < 32 -> (SARLconst x [c])
+(Rsh32Ux64 x (Const64 [c])) && uint64(c) < 32 -> (SHRLconst x [c])
+(Lsh16x64 x (Const64 [c])) && uint64(c) < 16 -> (SHLLconst x [c])
+(Rsh16x64 x (Const64 [c])) && uint64(c) < 16 -> (SARWconst x [c])
+(Rsh16Ux64 x (Const64 [c])) && uint64(c) < 16 -> (SHRWconst x [c])
+(Lsh8x64 x (Const64 [c])) && uint64(c) < 8 -> (SHLLconst x [c])
+(Rsh8x64 x (Const64 [c])) && uint64(c) < 8 -> (SARBconst x [c])
+(Rsh8Ux64 x (Const64 [c])) && uint64(c) < 8 -> (SHRBconst x [c])
+
+// large constant shifts
+(Lsh32x64 _ (Const64 [c])) && uint64(c) >= 32 -> (Const32 [0])
+(Rsh32Ux64 _ (Const64 [c])) && uint64(c) >= 32 -> (Const32 [0])
+(Lsh16x64 _ (Const64 [c])) && uint64(c) >= 16 -> (Const16 [0])
+(Rsh16Ux64 _ (Const64 [c])) && uint64(c) >= 16 -> (Const16 [0])
+(Lsh8x64 _ (Const64 [c])) && uint64(c) >= 8 -> (Const8 [0])
+(Rsh8Ux64 _ (Const64 [c])) && uint64(c) >= 8 -> (Const8 [0])
+
+// large constant signed right shift, we leave the sign bit
+(Rsh32x64 x (Const64 [c])) && uint64(c) >= 32 -> (SARLconst x [31])
+(Rsh16x64 x (Const64 [c])) && uint64(c) >= 16 -> (SARWconst x [15])
+(Rsh8x64 x (Const64 [c])) && uint64(c) >= 8 -> (SARBconst x [7])
+
+// Lowering comparisons
+(Less32 x y) -> (SETL (CMPL x y))
+(Less16 x y) -> (SETL (CMPW x y))
+(Less8 x y) -> (SETL (CMPB x y))
+(Less32U x y) -> (SETB (CMPL x y))
+(Less16U x y) -> (SETB (CMPW x y))
+(Less8U x y) -> (SETB (CMPB x y))
+// Use SETGF with reversed operands to dodge NaN case
+(Less64F x y) -> (SETGF (UCOMISD y x))
+(Less32F x y) -> (SETGF (UCOMISS y x))
+
+(Leq32 x y) -> (SETLE (CMPL x y))
+(Leq16 x y) -> (SETLE (CMPW x y))
+(Leq8 x y) -> (SETLE (CMPB x y))
+(Leq32U x y) -> (SETBE (CMPL x y))
+(Leq16U x y) -> (SETBE (CMPW x y))
+(Leq8U x y) -> (SETBE (CMPB x y))
+// Use SETGEF with reversed operands to dodge NaN case
+(Leq64F x y) -> (SETGEF (UCOMISD y x))
+(Leq32F x y) -> (SETGEF (UCOMISS y x))
+
+(Greater32 x y) -> (SETG (CMPL x y))
+(Greater16 x y) -> (SETG (CMPW x y))
+(Greater8 x y) -> (SETG (CMPB x y))
+(Greater32U x y) -> (SETA (CMPL x y))
+(Greater16U x y) -> (SETA (CMPW x y))
+(Greater8U x y) -> (SETA (CMPB x y))
+// Note Go assembler gets UCOMISx operand order wrong, but it is right here
+// Bug is accommodated at generation of assembly language.
+(Greater64F x y) -> (SETGF (UCOMISD x y))
+(Greater32F x y) -> (SETGF (UCOMISS x y))
+
+(Geq32 x y) -> (SETGE (CMPL x y))
+(Geq16 x y) -> (SETGE (CMPW x y))
+(Geq8 x y) -> (SETGE (CMPB x y))
+(Geq32U x y) -> (SETAE (CMPL x y))
+(Geq16U x y) -> (SETAE (CMPW x y))
+(Geq8U x y) -> (SETAE (CMPB x y))
+// Note Go assembler gets UCOMISx operand order wrong, but it is right here
+// Bug is accommodated at generation of assembly language.
+(Geq64F x y) -> (SETGEF (UCOMISD x y))
+(Geq32F x y) -> (SETGEF (UCOMISS x y))
+
+(Eq32 x y) -> (SETEQ (CMPL x y))
+(Eq16 x y) -> (SETEQ (CMPW x y))
+(Eq8 x y) -> (SETEQ (CMPB x y))
+(EqB x y) -> (SETEQ (CMPB x y))
+(EqPtr x y) -> (SETEQ (CMPL x y))
+(Eq64F x y) -> (SETEQF (UCOMISD x y))
+(Eq32F x y) -> (SETEQF (UCOMISS x y))
+
+(Neq32 x y) -> (SETNE (CMPL x y))
+(Neq16 x y) -> (SETNE (CMPW x y))
+(Neq8 x y) -> (SETNE (CMPB x y))
+(NeqB x y) -> (SETNE (CMPB x y))
+(NeqPtr x y) -> (SETNE (CMPL x y))
+(Neq64F x y) -> (SETNEF (UCOMISD x y))
+(Neq32F x y) -> (SETNEF (UCOMISS x y))
+
+// Lowering loads
+(Load <t> ptr mem) && (is32BitInt(t) || isPtr(t)) -> (MOVLload ptr mem)
+(Load <t> ptr mem) && is16BitInt(t) -> (MOVWload ptr mem)
+(Load <t> ptr mem) && (t.IsBoolean() || is8BitInt(t)) -> (MOVBload ptr mem)
+(Load <t> ptr mem) && is32BitFloat(t) -> (MOVSSload ptr mem)
+(Load <t> ptr mem) && is64BitFloat(t) -> (MOVSDload ptr mem)
+
+// Lowering stores
+// These more-specific FP versions of Store pattern should come first.
+(Store [8] ptr val mem) && is64BitFloat(val.Type) -> (MOVSDstore ptr val mem)
+(Store [4] ptr val mem) && is32BitFloat(val.Type) -> (MOVSSstore ptr val mem)
+
+(Store [4] ptr val mem) -> (MOVLstore ptr val mem)
+(Store [2] ptr val mem) -> (MOVWstore ptr val mem)
+(Store [1] ptr val mem) -> (MOVBstore ptr val mem)
+
+// Lowering moves
+(Move [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 ->
+ (MOVBstore [2] dst (MOVBload [2] src mem)
+ (MOVWstore dst (MOVWload src mem) mem))
+(Move [s] dst src mem) && SizeAndAlign(s).Size() == 5 ->
+ (MOVBstore [4] dst (MOVBload [4] src mem)
+ (MOVLstore dst (MOVLload src mem) mem))
+(Move [s] dst src mem) && SizeAndAlign(s).Size() == 6 ->
+ (MOVWstore [4] dst (MOVWload [4] src mem)
+ (MOVLstore dst (MOVLload src mem) mem))
+(Move [s] dst src mem) && SizeAndAlign(s).Size() == 7 ->
+ (MOVLstore [3] dst (MOVLload [3] src mem)
+ (MOVLstore dst (MOVLload src mem) mem))
+(Move [s] dst src mem) && SizeAndAlign(s).Size() == 8 ->
+ (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])
+ (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
+ && !config.noDuffDevice ->
+ (DUFFCOPY [10*(128-SizeAndAlign(s).Size()/4)] dst src mem)
+// 10 and 128 are magic constants. 10 is the number of bytes to encode:
+// MOVL (SI), CX
+// ADDL $4, SI
+// MOVL CX, (DI)
+// ADDL $4, DI
+// 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)
+
+// 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() == 3 ->
+ (MOVBstoreconst [makeValAndOff(0,2)] destptr
+ (MOVWstoreconst [0] destptr mem))
+(Zero [s] destptr mem) && SizeAndAlign(s).Size() == 5 ->
+ (MOVBstoreconst [makeValAndOff(0,4)] destptr
+ (MOVLstoreconst [0] destptr mem))
+(Zero [s] destptr mem) && SizeAndAlign(s).Size() == 6 ->
+ (MOVWstoreconst [makeValAndOff(0,4)] destptr
+ (MOVLstoreconst [0] destptr mem))
+(Zero [s] destptr mem) && SizeAndAlign(s).Size() == 7 ->
+ (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])
+ (MOVLstoreconst [0] destptr mem))
+
+// Zero small numbers of words directly.
+(Zero [s] destptr mem) && SizeAndAlign(s).Size() == 8 ->
+ (MOVLstoreconst [makeValAndOff(0,4)] destptr
+ (MOVLstoreconst [0] destptr mem))
+(Zero [s] destptr mem) && SizeAndAlign(s).Size() == 12 ->
+ (MOVLstoreconst [makeValAndOff(0,8)] destptr
+ (MOVLstoreconst [makeValAndOff(0,4)] destptr
+ (MOVLstoreconst [0] destptr mem)))
+(Zero [s] destptr mem) && SizeAndAlign(s).Size() == 16 ->
+ (MOVLstoreconst [makeValAndOff(0,12)] destptr
+ (MOVLstoreconst [makeValAndOff(0,8)] destptr
+ (MOVLstoreconst [makeValAndOff(0,4)] destptr
+ (MOVLstoreconst [0] destptr mem))))
+
+// Medium zeroing uses a duff device.
+(Zero [s] destptr mem)
+ && SizeAndAlign(s).Size() > 16
+ && SizeAndAlign(s).Size() <= 4*128
+ && SizeAndAlign(s).Size()%4 == 0
+ && !config.noDuffDevice ->
+ (DUFFZERO [1*(128-SizeAndAlign(s).Size()/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)
+
+// Lowering constants
+(Const8 [val]) -> (MOVLconst [val])
+(Const16 [val]) -> (MOVLconst [val])
+(Const32 [val]) -> (MOVLconst [val])
+(Const32F [val]) -> (MOVSSconst [val])
+(Const64F [val]) -> (MOVSDconst [val])
+(ConstNil) -> (MOVLconst [0])
+(ConstBool [b]) -> (MOVLconst [b])
+
+// Lowering calls
+(StaticCall [argwid] {target} mem) -> (CALLstatic [argwid] {target} mem)
+(ClosureCall [argwid] entry closure mem) -> (CALLclosure [argwid] entry closure mem)
+(DeferCall [argwid] mem) -> (CALLdefer [argwid] mem)
+(GoCall [argwid] mem) -> (CALLgo [argwid] mem)
+(InterCall [argwid] entry mem) -> (CALLinter [argwid] entry mem)
+
+// Miscellaneous
+(Convert <t> x mem) -> (MOVLconvert <t> x mem)
+(IsNonNil p) -> (SETNE (TESTL p p))
+(IsInBounds idx len) -> (SETB (CMPL idx len))
+(IsSliceInBounds idx len) -> (SETBE (CMPL idx len))
+(NilCheck ptr mem) -> (LoweredNilCheck ptr mem)
+(GetG mem) -> (LoweredGetG mem)
+(GetClosurePtr) -> (LoweredGetClosurePtr)
+(Addr {sym} base) -> (LEAL {sym} base)
+
+// block rewrites
+(If (SETL cmp) yes no) -> (LT cmp yes no)
+(If (SETLE cmp) yes no) -> (LE cmp yes no)
+(If (SETG cmp) yes no) -> (GT cmp yes no)
+(If (SETGE cmp) yes no) -> (GE cmp yes no)
+(If (SETEQ cmp) yes no) -> (EQ cmp yes no)
+(If (SETNE cmp) yes no) -> (NE cmp yes no)
+(If (SETB cmp) yes no) -> (ULT cmp yes no)
+(If (SETBE cmp) yes no) -> (ULE cmp yes no)
+(If (SETA cmp) yes no) -> (UGT cmp yes no)
+(If (SETAE cmp) yes no) -> (UGE cmp yes no)
+
+// Special case for floating point - LF/LEF not generated
+(If (SETGF cmp) yes no) -> (UGT cmp yes no)
+(If (SETGEF cmp) yes no) -> (UGE cmp yes no)
+(If (SETEQF cmp) yes no) -> (EQF cmp yes no)
+(If (SETNEF cmp) yes no) -> (NEF cmp yes no)
+
+(If cond yes no) -> (NE (TESTB cond cond) yes no)
+
+// ***************************
+// Above: lowering rules
+// Below: optimizations
+// ***************************
+// TODO: Should the optimizations be a separate pass?
+
+// Fold boolean tests into blocks
+(NE (TESTB (SETL cmp) (SETL cmp)) yes no) -> (LT cmp yes no)
+(NE (TESTB (SETLE cmp) (SETLE cmp)) yes no) -> (LE cmp yes no)
+(NE (TESTB (SETG cmp) (SETG cmp)) yes no) -> (GT cmp yes no)
+(NE (TESTB (SETGE cmp) (SETGE cmp)) yes no) -> (GE cmp yes no)
+(NE (TESTB (SETEQ cmp) (SETEQ cmp)) yes no) -> (EQ cmp yes no)
+(NE (TESTB (SETNE cmp) (SETNE cmp)) yes no) -> (NE cmp yes no)
+(NE (TESTB (SETB cmp) (SETB cmp)) yes no) -> (ULT cmp yes no)
+(NE (TESTB (SETBE cmp) (SETBE cmp)) yes no) -> (ULE cmp yes no)
+(NE (TESTB (SETA cmp) (SETA cmp)) yes no) -> (UGT cmp yes no)
+(NE (TESTB (SETAE cmp) (SETAE cmp)) yes no) -> (UGE cmp yes no)
+
+// Special case for floating point - LF/LEF not generated
+(NE (TESTB (SETGF cmp) (SETGF cmp)) yes no) -> (UGT cmp yes no)
+(NE (TESTB (SETGEF cmp) (SETGEF cmp)) yes no) -> (UGE cmp yes no)
+(NE (TESTB (SETEQF cmp) (SETEQF cmp)) yes no) -> (EQF cmp yes no)
+(NE (TESTB (SETNEF cmp) (SETNEF cmp)) yes no) -> (NEF cmp yes no)
+
+// 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)
+
+(SUBL x (MOVLconst [c])) -> (SUBLconst x [c])
+(SUBL (MOVLconst [c]) x) -> (NEGL (SUBLconst <v.Type> x [c]))
+(SUBLcarry x (MOVLconst [c])) -> (SUBLconstcarry [c] x)
+(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)
+
+(XORLconst [c] (XORLconst [d] x)) -> (XORLconst [c ^ d] x)
+
+(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])) -> (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)
+
+(SARL x (ANDLconst [31] y)) -> (SARL x y)
+
+(SHLL x (ANDLconst [31] y)) -> (SHLL x y)
+
+(SHRL x (ANDLconst [31] y)) -> (SHRL x y)
+
+(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)
+
+(ROLLconst [0] x) -> x
+(ROLWconst [0] x) -> x
+(ROLBconst [0] x) -> 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
+// for the small shifts. I don't think we'll ever generate a weird shift (e.g.
+// (SHRW x (MOVLconst [24])), but just in case.
+
+(CMPL x (MOVLconst [c])) -> (CMPLconst x [c])
+(CMPL (MOVLconst [c]) x) -> (InvertFlags (CMPLconst x [c]))
+(CMPW x (MOVLconst [c])) -> (CMPWconst x [int64(int16(c))])
+(CMPW (MOVLconst [c]) x) -> (InvertFlags (CMPWconst x [int64(int16(c))]))
+(CMPB x (MOVLconst [c])) -> (CMPBconst x [int64(int8(c))])
+(CMPB (MOVLconst [c]) x) -> (InvertFlags (CMPBconst x [int64(int8(c))]))
+
+// strength reduction
+// Assumes that the following costs from https://gmplib.org/~tege/x86-timing.pdf:
+// 1 - addq, shlq, leaq, negq
+// 3 - imulq
+// This limits the rewrites to two instructions.
+// TODO: 27, 81
+(MULLconst [-1] x) -> (NEGL x)
+(MULLconst [0] _) -> (MOVLconst [0])
+(MULLconst [1] x) -> x
+(MULLconst [3] x) -> (LEAL2 x x)
+(MULLconst [5] x) -> (LEAL4 x x)
+(MULLconst [7] x) -> (LEAL8 (NEGL <v.Type> x) x)
+(MULLconst [9] x) -> (LEAL8 x x)
+(MULLconst [11] x) -> (LEAL2 x (LEAL4 <v.Type> x x))
+(MULLconst [13] x) -> (LEAL4 x (LEAL2 <v.Type> x x))
+(MULLconst [21] x) -> (LEAL4 x (LEAL4 <v.Type> x x))
+(MULLconst [25] x) -> (LEAL8 x (LEAL2 <v.Type> x x))
+(MULLconst [37] x) -> (LEAL4 x (LEAL8 <v.Type> x x))
+(MULLconst [41] x) -> (LEAL8 x (LEAL4 <v.Type> x x))
+(MULLconst [73] x) -> (LEAL8 x (LEAL8 <v.Type> x x))
+
+(MULLconst [c] x) && isPowerOfTwo(c) -> (SHLLconst [log2(c)] x)
+(MULLconst [c] x) && isPowerOfTwo(c+1) && c >= 15 -> (SUBL (SHLLconst <v.Type> [log2(c+1)] x) x)
+(MULLconst [c] x) && isPowerOfTwo(c-1) && c >= 17 -> (LEAL1 (SHLLconst <v.Type> [log2(c-1)] x) x)
+(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))
+
+// combine add/shift into LEAL
+(ADDL x (SHLLconst [3] y)) -> (LEAL8 x y)
+(ADDL x (SHLLconst [2] y)) -> (LEAL4 x y)
+(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)
+(ADDLconst [c] (LEAL2 [d] {s} x y)) && is32Bit(c+d) -> (LEAL2 [c+d] {s} x y)
+(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)
+(LEAL4 [c] {s} x (ADDLconst [d] y)) && is32Bit(c+4*d) && y.Op != OpSB -> (LEAL4 [c+4*d] {s} x y)
+(LEAL8 [c] {s} (ADDLconst [d] x) y) && is32Bit(c+d) && x.Op != OpSB -> (LEAL8 [c+d] {s} x y)
+(LEAL8 [c] {s} x (ADDLconst [d] y)) && is32Bit(c+8*d) && y.Op != OpSB -> (LEAL8 [c+8*d] {s} x y)
+
+// 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)
+
+// reverse ordering of compare instruction
+(SETL (InvertFlags x)) -> (SETG x)
+(SETG (InvertFlags x)) -> (SETL x)
+(SETB (InvertFlags x)) -> (SETA x)
+(SETA (InvertFlags x)) -> (SETB x)
+(SETLE (InvertFlags x)) -> (SETGE x)
+(SETGE (InvertFlags x)) -> (SETLE x)
+(SETBE (InvertFlags x)) -> (SETAE x)
+(SETAE (InvertFlags x)) -> (SETBE x)
+(SETEQ (InvertFlags x)) -> (SETEQ x)
+(SETNE (InvertFlags x)) -> (SETNE x)
+
+// sign extended loads
+// Note: The combined instruction must end up in the same block
+// as the original load. If not, we end up making a value with
+// memory type live in two different blocks, which can lead to
+// multiple memory values alive simultaneously.
+// Make sure we don't combine these ops if the load has another use.
+// This prevents a single load from being split into multiple loads
+// which then might return different values. See test/atomicload.go.
+(MOVBLSX x:(MOVBload [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVBLSXload <v.Type> [off] {sym} ptr mem)
+(MOVBLZX x:(MOVBload [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVBload <v.Type> [off] {sym} ptr mem)
+(MOVWLSX x:(MOVWload [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVWLSXload <v.Type> [off] {sym} ptr mem)
+(MOVWLZX x:(MOVWload [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVWload <v.Type> [off] {sym} ptr mem)
+
+(MOVBLZX x:(MOVBloadidx1 [off] {sym} ptr idx mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVBloadidx1 <v.Type> [off] {sym} ptr idx mem)
+(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
+(MOVLload [off] {sym} ptr (MOVLstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> x
+
+// Fold extensions and ANDs together.
+(MOVBLZX (ANDLconst [c] x)) -> (ANDLconst [c & 0xff] x)
+(MOVWLZX (ANDLconst [c] x)) -> (ANDLconst [c & 0xffff] x)
+(MOVBLSX (ANDLconst [c] x)) && c & 0x80 == 0 -> (ANDLconst [c & 0x7f] x)
+(MOVWLSX (ANDLconst [c] x)) && c & 0x8000 == 0 -> (ANDLconst [c & 0x7fff] x)
+
+// Don't extend before storing
+(MOVWstore [off] {sym} ptr (MOVWLSX x) mem) -> (MOVWstore [off] {sym} ptr x mem)
+(MOVBstore [off] {sym} ptr (MOVBLSX x) mem) -> (MOVBstore [off] {sym} ptr x mem)
+(MOVWstore [off] {sym} ptr (MOVWLZX x) mem) -> (MOVWstore [off] {sym} ptr x mem)
+(MOVBstore [off] {sym} ptr (MOVBLZX x) mem) -> (MOVBstore [off] {sym} ptr x mem)
+
+// fold constants into memory operations
+// Note that this is not always a good idea because if not all the uses of
+// the ADDQconst get eliminated, we still have to compute the ADDQconst and we now
+// have potentially two live values (ptr and (ADDQconst [off] ptr)) instead of one.
+// Nevertheless, let's do it!
+(MOVLload [off1] {sym} (ADDLconst [off2] ptr) mem) && is32Bit(off1+off2) -> (MOVLload [off1+off2] {sym} ptr mem)
+(MOVWload [off1] {sym} (ADDLconst [off2] ptr) mem) && is32Bit(off1+off2) -> (MOVWload [off1+off2] {sym} ptr mem)
+(MOVBload [off1] {sym} (ADDLconst [off2] ptr) mem) && is32Bit(off1+off2) -> (MOVBload [off1+off2] {sym} ptr mem)
+(MOVSSload [off1] {sym} (ADDLconst [off2] ptr) mem) && is32Bit(off1+off2) -> (MOVSSload [off1+off2] {sym} ptr mem)
+(MOVSDload [off1] {sym} (ADDLconst [off2] ptr) mem) && is32Bit(off1+off2) -> (MOVSDload [off1+off2] {sym} ptr mem)
+
+(MOVLstore [off1] {sym} (ADDLconst [off2] ptr) val mem) && is32Bit(off1+off2) -> (MOVLstore [off1+off2] {sym} ptr val mem)
+(MOVWstore [off1] {sym} (ADDLconst [off2] ptr) val mem) && is32Bit(off1+off2) -> (MOVWstore [off1+off2] {sym} ptr val mem)
+(MOVBstore [off1] {sym} (ADDLconst [off2] ptr) val mem) && is32Bit(off1+off2) -> (MOVBstore [off1+off2] {sym} ptr val mem)
+(MOVSSstore [off1] {sym} (ADDLconst [off2] ptr) val mem) && is32Bit(off1+off2) -> (MOVSSstore [off1+off2] {sym} ptr val mem)
+(MOVSDstore [off1] {sym} (ADDLconst [off2] ptr) val mem) && is32Bit(off1+off2) -> (MOVSDstore [off1+off2] {sym} ptr val mem)
+
+// Fold constants into stores.
+(MOVLstore [off] {sym} ptr (MOVLconst [c]) mem) && validOff(off) ->
+ (MOVLstoreconst [makeValAndOff(int64(int32(c)),off)] {sym} ptr mem)
+(MOVWstore [off] {sym} ptr (MOVLconst [c]) mem) && validOff(off) ->
+ (MOVWstoreconst [makeValAndOff(int64(int16(c)),off)] {sym} ptr mem)
+(MOVBstore [off] {sym} ptr (MOVLconst [c]) mem) && validOff(off) ->
+ (MOVBstoreconst [makeValAndOff(int64(int8(c)),off)] {sym} ptr mem)
+
+// Fold address offsets into constant stores.
+(MOVLstoreconst [sc] {s} (ADDLconst [off] ptr) mem) && ValAndOff(sc).canAdd(off) ->
+ (MOVLstoreconst [ValAndOff(sc).add(off)] {s} ptr mem)
+(MOVWstoreconst [sc] {s} (ADDLconst [off] ptr) mem) && ValAndOff(sc).canAdd(off) ->
+ (MOVWstoreconst [ValAndOff(sc).add(off)] {s} ptr mem)
+(MOVBstoreconst [sc] {s} (ADDLconst [off] ptr) mem) && ValAndOff(sc).canAdd(off) ->
+ (MOVBstoreconst [ValAndOff(sc).add(off)] {s} ptr mem)
+
+// We need to fold LEAQ into the MOVx ops so that the live variable analysis knows
+// what variables are being read/written by the ops.
+// Note: we turn off this merging for operations on globals when building
+// position-independent code (when Flag_shared is set).
+// PIC needs a spare register to load the PC into. Having the LEAL be
+// a separate instruction gives us that register. Having the LEAL be
+// a separate instruction also allows it to be CSEd (which is good because
+// it compiles to a thunk call).
+(MOVLload [off1] {sym1} (LEAL [off2] {sym2} base) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+ && (base.Op != OpSB || !config.ctxt.Flag_shared) ->
+ (MOVLload [off1+off2] {mergeSym(sym1,sym2)} base mem)
+(MOVWload [off1] {sym1} (LEAL [off2] {sym2} base) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+ && (base.Op != OpSB || !config.ctxt.Flag_shared) ->
+ (MOVWload [off1+off2] {mergeSym(sym1,sym2)} base mem)
+(MOVBload [off1] {sym1} (LEAL [off2] {sym2} base) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+ && (base.Op != OpSB || !config.ctxt.Flag_shared) ->
+ (MOVBload [off1+off2] {mergeSym(sym1,sym2)} base mem)
+(MOVSSload [off1] {sym1} (LEAL [off2] {sym2} base) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+ && (base.Op != OpSB || !config.ctxt.Flag_shared) ->
+ (MOVSSload [off1+off2] {mergeSym(sym1,sym2)} base mem)
+(MOVSDload [off1] {sym1} (LEAL [off2] {sym2} base) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+ && (base.Op != OpSB || !config.ctxt.Flag_shared) ->
+ (MOVSDload [off1+off2] {mergeSym(sym1,sym2)} base mem)
+
+(MOVBLSXload [off1] {sym1} (LEAL [off2] {sym2} base) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+ && (base.Op != OpSB || !config.ctxt.Flag_shared) ->
+ (MOVBLSXload [off1+off2] {mergeSym(sym1,sym2)} base mem)
+(MOVWLSXload [off1] {sym1} (LEAL [off2] {sym2} base) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+ && (base.Op != OpSB || !config.ctxt.Flag_shared) ->
+ (MOVWLSXload [off1+off2] {mergeSym(sym1,sym2)} base mem)
+
+(MOVLstore [off1] {sym1} (LEAL [off2] {sym2} base) val mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+ && (base.Op != OpSB || !config.ctxt.Flag_shared) ->
+ (MOVLstore [off1+off2] {mergeSym(sym1,sym2)} base val mem)
+(MOVWstore [off1] {sym1} (LEAL [off2] {sym2} base) val mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+ && (base.Op != OpSB || !config.ctxt.Flag_shared) ->
+ (MOVWstore [off1+off2] {mergeSym(sym1,sym2)} base val mem)
+(MOVBstore [off1] {sym1} (LEAL [off2] {sym2} base) val mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+ && (base.Op != OpSB || !config.ctxt.Flag_shared) ->
+ (MOVBstore [off1+off2] {mergeSym(sym1,sym2)} base val mem)
+(MOVSSstore [off1] {sym1} (LEAL [off2] {sym2} base) val mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+ && (base.Op != OpSB || !config.ctxt.Flag_shared) ->
+ (MOVSSstore [off1+off2] {mergeSym(sym1,sym2)} base val mem)
+(MOVSDstore [off1] {sym1} (LEAL [off2] {sym2} base) val mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+ && (base.Op != OpSB || !config.ctxt.Flag_shared) ->
+ (MOVSDstore [off1+off2] {mergeSym(sym1,sym2)} base val mem)
+
+(MOVLstoreconst [sc] {sym1} (LEAL [off] {sym2} ptr) mem) && canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd(off)
+ && (ptr.Op != OpSB || !config.ctxt.Flag_shared) ->
+ (MOVLstoreconst [ValAndOff(sc).add(off)] {mergeSym(sym1, sym2)} ptr mem)
+(MOVWstoreconst [sc] {sym1} (LEAL [off] {sym2} ptr) mem) && canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd(off)
+ && (ptr.Op != OpSB || !config.ctxt.Flag_shared) ->
+ (MOVWstoreconst [ValAndOff(sc).add(off)] {mergeSym(sym1, sym2)} ptr mem)
+(MOVBstoreconst [sc] {sym1} (LEAL [off] {sym2} ptr) mem) && canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd(off)
+ && (ptr.Op != OpSB || !config.ctxt.Flag_shared) ->
+ (MOVBstoreconst [ValAndOff(sc).add(off)] {mergeSym(sym1, sym2)} ptr mem)
+
+// generating indexed loads and stores
+(MOVBload [off1] {sym1} (LEAL1 [off2] {sym2} ptr idx) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
+ (MOVBloadidx1 [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem)
+(MOVWload [off1] {sym1} (LEAL1 [off2] {sym2} ptr idx) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
+ (MOVWloadidx1 [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem)
+(MOVWload [off1] {sym1} (LEAL2 [off2] {sym2} ptr idx) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
+ (MOVWloadidx2 [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem)
+(MOVLload [off1] {sym1} (LEAL1 [off2] {sym2} ptr idx) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
+ (MOVLloadidx1 [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem)
+(MOVLload [off1] {sym1} (LEAL4 [off2] {sym2} ptr idx) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
+ (MOVLloadidx4 [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem)
+(MOVSSload [off1] {sym1} (LEAL1 [off2] {sym2} ptr idx) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
+ (MOVSSloadidx1 [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem)
+(MOVSSload [off1] {sym1} (LEAL4 [off2] {sym2} ptr idx) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
+ (MOVSSloadidx4 [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem)
+(MOVSDload [off1] {sym1} (LEAL1 [off2] {sym2} ptr idx) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
+ (MOVSDloadidx1 [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem)
+(MOVSDload [off1] {sym1} (LEAL8 [off2] {sym2} ptr idx) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
+ (MOVSDloadidx8 [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem)
+
+(MOVBstore [off1] {sym1} (LEAL1 [off2] {sym2} ptr idx) val mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
+ (MOVBstoreidx1 [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem)
+(MOVWstore [off1] {sym1} (LEAL1 [off2] {sym2} ptr idx) val mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
+ (MOVWstoreidx1 [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem)
+(MOVWstore [off1] {sym1} (LEAL2 [off2] {sym2} ptr idx) val mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
+ (MOVWstoreidx2 [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem)
+(MOVLstore [off1] {sym1} (LEAL1 [off2] {sym2} ptr idx) val mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
+ (MOVLstoreidx1 [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem)
+(MOVLstore [off1] {sym1} (LEAL4 [off2] {sym2} ptr idx) val mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
+ (MOVLstoreidx4 [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem)
+(MOVSSstore [off1] {sym1} (LEAL1 [off2] {sym2} ptr idx) val mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
+ (MOVSSstoreidx1 [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem)
+(MOVSSstore [off1] {sym1} (LEAL4 [off2] {sym2} ptr idx) val mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
+ (MOVSSstoreidx4 [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem)
+(MOVSDstore [off1] {sym1} (LEAL1 [off2] {sym2} ptr idx) val mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
+ (MOVSDstoreidx1 [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem)
+(MOVSDstore [off1] {sym1} (LEAL8 [off2] {sym2} ptr idx) val mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
+ (MOVSDstoreidx8 [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem)
+
+(MOVBload [off] {sym} (ADDL ptr idx) mem) && ptr.Op != OpSB -> (MOVBloadidx1 [off] {sym} ptr idx mem)
+(MOVWload [off] {sym} (ADDL ptr idx) mem) && ptr.Op != OpSB -> (MOVWloadidx1 [off] {sym} ptr idx mem)
+(MOVLload [off] {sym} (ADDL ptr idx) mem) && ptr.Op != OpSB -> (MOVLloadidx1 [off] {sym} ptr idx mem)
+(MOVSSload [off] {sym} (ADDL ptr idx) mem) && ptr.Op != OpSB -> (MOVSSloadidx1 [off] {sym} ptr idx mem)
+(MOVSDload [off] {sym} (ADDL ptr idx) mem) && ptr.Op != OpSB -> (MOVSDloadidx1 [off] {sym} ptr idx mem)
+(MOVBstore [off] {sym} (ADDL ptr idx) val mem) && ptr.Op != OpSB -> (MOVBstoreidx1 [off] {sym} ptr idx val mem)
+(MOVWstore [off] {sym} (ADDL ptr idx) val mem) && ptr.Op != OpSB -> (MOVWstoreidx1 [off] {sym} ptr idx val mem)
+(MOVLstore [off] {sym} (ADDL ptr idx) val mem) && ptr.Op != OpSB -> (MOVLstoreidx1 [off] {sym} ptr idx val mem)
+(MOVSSstore [off] {sym} (ADDL ptr idx) val mem) && ptr.Op != OpSB -> (MOVSSstoreidx1 [off] {sym} ptr idx val mem)
+(MOVSDstore [off] {sym} (ADDL ptr idx) val mem) && ptr.Op != OpSB -> (MOVSDstoreidx1 [off] {sym} ptr idx val mem)
+
+(MOVBstoreconst [x] {sym1} (LEAL1 [off] {sym2} ptr idx) mem) && canMergeSym(sym1, sym2) ->
+ (MOVBstoreconstidx1 [ValAndOff(x).add(off)] {mergeSym(sym1,sym2)} ptr idx mem)
+(MOVWstoreconst [x] {sym1} (LEAL1 [off] {sym2} ptr idx) mem) && canMergeSym(sym1, sym2) ->
+ (MOVWstoreconstidx1 [ValAndOff(x).add(off)] {mergeSym(sym1,sym2)} ptr idx mem)
+(MOVWstoreconst [x] {sym1} (LEAL2 [off] {sym2} ptr idx) mem) && canMergeSym(sym1, sym2) ->
+ (MOVWstoreconstidx2 [ValAndOff(x).add(off)] {mergeSym(sym1,sym2)} ptr idx mem)
+(MOVLstoreconst [x] {sym1} (LEAL1 [off] {sym2} ptr idx) mem) && canMergeSym(sym1, sym2) ->
+ (MOVLstoreconstidx1 [ValAndOff(x).add(off)] {mergeSym(sym1,sym2)} ptr idx mem)
+(MOVLstoreconst [x] {sym1} (LEAL4 [off] {sym2} ptr idx) mem) && canMergeSym(sym1, sym2) ->
+ (MOVLstoreconstidx4 [ValAndOff(x).add(off)] {mergeSym(sym1,sym2)} ptr idx mem)
+
+(MOVBstoreconst [x] {sym} (ADDL ptr idx) mem) -> (MOVBstoreconstidx1 [x] {sym} ptr idx mem)
+(MOVWstoreconst [x] {sym} (ADDL ptr idx) mem) -> (MOVWstoreconstidx1 [x] {sym} ptr idx mem)
+(MOVLstoreconst [x] {sym} (ADDL ptr idx) mem) -> (MOVLstoreconstidx1 [x] {sym} ptr idx mem)
+
+// combine SHLL into indexed loads and stores
+(MOVWloadidx1 [c] {sym} ptr (SHLLconst [1] idx) mem) -> (MOVWloadidx2 [c] {sym} ptr idx mem)
+(MOVLloadidx1 [c] {sym} ptr (SHLLconst [2] idx) mem) -> (MOVLloadidx4 [c] {sym} ptr idx mem)
+(MOVWstoreidx1 [c] {sym} ptr (SHLLconst [1] idx) val mem) -> (MOVWstoreidx2 [c] {sym} ptr idx val mem)
+(MOVLstoreidx1 [c] {sym} ptr (SHLLconst [2] idx) val mem) -> (MOVLstoreidx4 [c] {sym} ptr idx val mem)
+(MOVWstoreconstidx1 [c] {sym} ptr (SHLLconst [1] idx) mem) -> (MOVWstoreconstidx2 [c] {sym} ptr idx mem)
+(MOVLstoreconstidx1 [c] {sym} ptr (SHLLconst [2] idx) mem) -> (MOVLstoreconstidx4 [c] {sym} ptr idx mem)
+
+// combine ADDL into indexed loads and stores
+(MOVBloadidx1 [c] {sym} (ADDLconst [d] ptr) idx mem) -> (MOVBloadidx1 [c+d] {sym} ptr idx mem)
+(MOVWloadidx1 [c] {sym} (ADDLconst [d] ptr) idx mem) -> (MOVWloadidx1 [c+d] {sym} ptr idx mem)
+(MOVWloadidx2 [c] {sym} (ADDLconst [d] ptr) idx mem) -> (MOVWloadidx2 [c+d] {sym} ptr idx mem)
+(MOVLloadidx1 [c] {sym} (ADDLconst [d] ptr) idx mem) -> (MOVLloadidx1 [c+d] {sym} ptr idx mem)
+(MOVLloadidx4 [c] {sym} (ADDLconst [d] ptr) idx mem) -> (MOVLloadidx4 [c+d] {sym} ptr idx mem)
+(MOVSSloadidx1 [c] {sym} (ADDLconst [d] ptr) idx mem) -> (MOVSSloadidx1 [c+d] {sym} ptr idx mem)
+(MOVSSloadidx4 [c] {sym} (ADDLconst [d] ptr) idx mem) -> (MOVSSloadidx4 [c+d] {sym} ptr idx mem)
+(MOVSDloadidx1 [c] {sym} (ADDLconst [d] ptr) idx mem) -> (MOVSDloadidx1 [c+d] {sym} ptr idx mem)
+(MOVSDloadidx8 [c] {sym} (ADDLconst [d] ptr) idx mem) -> (MOVSDloadidx8 [c+d] {sym} ptr idx mem)
+
+(MOVBstoreidx1 [c] {sym} (ADDLconst [d] ptr) idx val mem) -> (MOVBstoreidx1 [c+d] {sym} ptr idx val mem)
+(MOVWstoreidx1 [c] {sym} (ADDLconst [d] ptr) idx val mem) -> (MOVWstoreidx1 [c+d] {sym} ptr idx val mem)
+(MOVWstoreidx2 [c] {sym} (ADDLconst [d] ptr) idx val mem) -> (MOVWstoreidx2 [c+d] {sym} ptr idx val mem)
+(MOVLstoreidx1 [c] {sym} (ADDLconst [d] ptr) idx val mem) -> (MOVLstoreidx1 [c+d] {sym} ptr idx val mem)
+(MOVLstoreidx4 [c] {sym} (ADDLconst [d] ptr) idx val mem) -> (MOVLstoreidx4 [c+d] {sym} ptr idx val mem)
+(MOVSSstoreidx1 [c] {sym} (ADDLconst [d] ptr) idx val mem) -> (MOVSSstoreidx1 [c+d] {sym} ptr idx val mem)
+(MOVSSstoreidx4 [c] {sym} (ADDLconst [d] ptr) idx val mem) -> (MOVSSstoreidx4 [c+d] {sym} ptr idx val mem)
+(MOVSDstoreidx1 [c] {sym} (ADDLconst [d] ptr) idx val mem) -> (MOVSDstoreidx1 [c+d] {sym} ptr idx val mem)
+(MOVSDstoreidx8 [c] {sym} (ADDLconst [d] ptr) idx val mem) -> (MOVSDstoreidx8 [c+d] {sym} ptr idx val mem)
+
+(MOVBloadidx1 [c] {sym} ptr (ADDLconst [d] idx) mem) -> (MOVBloadidx1 [c+d] {sym} ptr idx mem)
+(MOVWloadidx1 [c] {sym} ptr (ADDLconst [d] idx) mem) -> (MOVWloadidx1 [c+d] {sym} ptr idx mem)
+(MOVWloadidx2 [c] {sym} ptr (ADDLconst [d] idx) mem) -> (MOVWloadidx2 [c+2*d] {sym} ptr idx mem)
+(MOVLloadidx1 [c] {sym} ptr (ADDLconst [d] idx) mem) -> (MOVLloadidx1 [c+d] {sym} ptr idx mem)
+(MOVLloadidx4 [c] {sym} ptr (ADDLconst [d] idx) mem) -> (MOVLloadidx4 [c+4*d] {sym} ptr idx mem)
+(MOVSSloadidx1 [c] {sym} ptr (ADDLconst [d] idx) mem) -> (MOVSSloadidx1 [c+d] {sym} ptr idx mem)
+(MOVSSloadidx4 [c] {sym} ptr (ADDLconst [d] idx) mem) -> (MOVSSloadidx4 [c+4*d] {sym} ptr idx mem)
+(MOVSDloadidx1 [c] {sym} ptr (ADDLconst [d] idx) mem) -> (MOVSDloadidx1 [c+d] {sym} ptr idx mem)
+(MOVSDloadidx8 [c] {sym} ptr (ADDLconst [d] idx) mem) -> (MOVSDloadidx8 [c+8*d] {sym} ptr idx mem)
+
+(MOVBstoreidx1 [c] {sym} ptr (ADDLconst [d] idx) val mem) -> (MOVBstoreidx1 [c+d] {sym} ptr idx val mem)
+(MOVWstoreidx1 [c] {sym} ptr (ADDLconst [d] idx) val mem) -> (MOVWstoreidx1 [c+d] {sym} ptr idx val mem)
+(MOVWstoreidx2 [c] {sym} ptr (ADDLconst [d] idx) val mem) -> (MOVWstoreidx2 [c+2*d] {sym} ptr idx val mem)
+(MOVLstoreidx1 [c] {sym} ptr (ADDLconst [d] idx) val mem) -> (MOVLstoreidx1 [c+d] {sym} ptr idx val mem)
+(MOVLstoreidx4 [c] {sym} ptr (ADDLconst [d] idx) val mem) -> (MOVLstoreidx4 [c+4*d] {sym} ptr idx val mem)
+(MOVSSstoreidx1 [c] {sym} ptr (ADDLconst [d] idx) val mem) -> (MOVSSstoreidx1 [c+d] {sym} ptr idx val mem)
+(MOVSSstoreidx4 [c] {sym} ptr (ADDLconst [d] idx) val mem) -> (MOVSSstoreidx4 [c+4*d] {sym} ptr idx val mem)
+(MOVSDstoreidx1 [c] {sym} ptr (ADDLconst [d] idx) val mem) -> (MOVSDstoreidx1 [c+d] {sym} ptr idx val mem)
+(MOVSDstoreidx8 [c] {sym} ptr (ADDLconst [d] idx) val mem) -> (MOVSDstoreidx8 [c+8*d] {sym} ptr idx val mem)
+
+(MOVBstoreconstidx1 [x] {sym} (ADDLconst [c] ptr) idx mem) ->
+ (MOVBstoreconstidx1 [ValAndOff(x).add(c)] {sym} ptr idx mem)
+(MOVWstoreconstidx1 [x] {sym} (ADDLconst [c] ptr) idx mem) ->
+ (MOVWstoreconstidx1 [ValAndOff(x).add(c)] {sym} ptr idx mem)
+(MOVWstoreconstidx2 [x] {sym} (ADDLconst [c] ptr) idx mem) ->
+ (MOVWstoreconstidx2 [ValAndOff(x).add(c)] {sym} ptr idx mem)
+(MOVLstoreconstidx1 [x] {sym} (ADDLconst [c] ptr) idx mem) ->
+ (MOVLstoreconstidx1 [ValAndOff(x).add(c)] {sym} ptr idx mem)
+(MOVLstoreconstidx4 [x] {sym} (ADDLconst [c] ptr) idx mem) ->
+ (MOVLstoreconstidx4 [ValAndOff(x).add(c)] {sym} ptr idx mem)
+
+(MOVBstoreconstidx1 [x] {sym} ptr (ADDLconst [c] idx) mem) ->
+ (MOVBstoreconstidx1 [ValAndOff(x).add(c)] {sym} ptr idx mem)
+(MOVWstoreconstidx1 [x] {sym} ptr (ADDLconst [c] idx) mem) ->
+ (MOVWstoreconstidx1 [ValAndOff(x).add(c)] {sym} ptr idx mem)
+(MOVWstoreconstidx2 [x] {sym} ptr (ADDLconst [c] idx) mem) ->
+ (MOVWstoreconstidx2 [ValAndOff(x).add(2*c)] {sym} ptr idx mem)
+(MOVLstoreconstidx1 [x] {sym} ptr (ADDLconst [c] idx) mem) ->
+ (MOVLstoreconstidx1 [ValAndOff(x).add(c)] {sym} ptr idx mem)
+(MOVLstoreconstidx4 [x] {sym} ptr (ADDLconst [c] idx) mem) ->
+ (MOVLstoreconstidx4 [ValAndOff(x).add(4*c)] {sym} ptr idx mem)
+
+// fold LEALs together
+(LEAL [off1] {sym1} (LEAL [off2] {sym2} x)) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
+ (LEAL [off1+off2] {mergeSym(sym1,sym2)} x)
+
+// 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) ->
+ (LEAL1 [off1+off2] {mergeSym(sym1,sym2)} x y)
+
+// LEAL into LEAL[248]
+(LEAL2 [off1] {sym1} (LEAL [off2] {sym2} x) y) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) && x.Op != OpSB ->
+ (LEAL2 [off1+off2] {mergeSym(sym1,sym2)} x y)
+(LEAL4 [off1] {sym1} (LEAL [off2] {sym2} x) y) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) && x.Op != OpSB ->
+ (LEAL4 [off1+off2] {mergeSym(sym1,sym2)} x y)
+(LEAL8 [off1] {sym1} (LEAL [off2] {sym2} x) y) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) && x.Op != OpSB ->
+ (LEAL8 [off1+off2] {mergeSym(sym1,sym2)} x y)
+
+// LEAL[248] into LEAL
+(LEAL [off1] {sym1} (LEAL2 [off2] {sym2} x y)) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
+ (LEAL2 [off1+off2] {mergeSym(sym1,sym2)} x y)
+(LEAL [off1] {sym1} (LEAL4 [off2] {sym2} x y)) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
+ (LEAL4 [off1+off2] {mergeSym(sym1,sym2)} x y)
+(LEAL [off1] {sym1} (LEAL8 [off2] {sym2} x y)) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
+ (LEAL8 [off1+off2] {mergeSym(sym1,sym2)} x y)
+
+// Absorb InvertFlags into branches.
+(LT (InvertFlags cmp) yes no) -> (GT cmp yes no)
+(GT (InvertFlags cmp) yes no) -> (LT cmp yes no)
+(LE (InvertFlags cmp) yes no) -> (GE cmp yes no)
+(GE (InvertFlags cmp) yes no) -> (LE cmp yes no)
+(ULT (InvertFlags cmp) yes no) -> (UGT cmp yes no)
+(UGT (InvertFlags cmp) yes no) -> (ULT cmp yes no)
+(ULE (InvertFlags cmp) yes no) -> (UGE cmp yes no)
+(UGE (InvertFlags cmp) yes no) -> (ULE cmp yes no)
+(EQ (InvertFlags cmp) yes no) -> (EQ cmp yes no)
+(NE (InvertFlags cmp) yes no) -> (NE cmp yes no)
+
+// Constant comparisons.
+(CMPLconst (MOVLconst [x]) [y]) && int32(x)==int32(y) -> (FlagEQ)
+(CMPLconst (MOVLconst [x]) [y]) && int32(x)<int32(y) && uint32(x)<uint32(y) -> (FlagLT_ULT)
+(CMPLconst (MOVLconst [x]) [y]) && int32(x)<int32(y) && uint32(x)>uint32(y) -> (FlagLT_UGT)
+(CMPLconst (MOVLconst [x]) [y]) && int32(x)>int32(y) && uint32(x)<uint32(y) -> (FlagGT_ULT)
+(CMPLconst (MOVLconst [x]) [y]) && int32(x)>int32(y) && uint32(x)>uint32(y) -> (FlagGT_UGT)
+(CMPWconst (MOVLconst [x]) [y]) && int16(x)==int16(y) -> (FlagEQ)
+(CMPWconst (MOVLconst [x]) [y]) && int16(x)<int16(y) && uint16(x)<uint16(y) -> (FlagLT_ULT)
+(CMPWconst (MOVLconst [x]) [y]) && int16(x)<int16(y) && uint16(x)>uint16(y) -> (FlagLT_UGT)
+(CMPWconst (MOVLconst [x]) [y]) && int16(x)>int16(y) && uint16(x)<uint16(y) -> (FlagGT_ULT)
+(CMPWconst (MOVLconst [x]) [y]) && int16(x)>int16(y) && uint16(x)>uint16(y) -> (FlagGT_UGT)
+(CMPBconst (MOVLconst [x]) [y]) && int8(x)==int8(y) -> (FlagEQ)
+(CMPBconst (MOVLconst [x]) [y]) && int8(x)<int8(y) && uint8(x)<uint8(y) -> (FlagLT_ULT)
+(CMPBconst (MOVLconst [x]) [y]) && int8(x)<int8(y) && uint8(x)>uint8(y) -> (FlagLT_UGT)
+(CMPBconst (MOVLconst [x]) [y]) && int8(x)>int8(y) && uint8(x)<uint8(y) -> (FlagGT_ULT)
+(CMPBconst (MOVLconst [x]) [y]) && int8(x)>int8(y) && uint8(x)>uint8(y) -> (FlagGT_UGT)
+
+// Other known comparisons.
+(CMPLconst (SHRLconst _ [c]) [n]) && 0 <= n && 0 < c && c <= 32 && (1<<uint64(32-c)) <= uint64(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.
+(SBBLcarrymask (FlagEQ)) -> (MOVLconst [0])
+(SBBLcarrymask (FlagLT_ULT)) -> (MOVLconst [-1])
+(SBBLcarrymask (FlagLT_UGT)) -> (MOVLconst [0])
+(SBBLcarrymask (FlagGT_ULT)) -> (MOVLconst [-1])
+(SBBLcarrymask (FlagGT_UGT)) -> (MOVLconst [0])
+
+// Absorb flag constants into branches.
+(EQ (FlagEQ) yes no) -> (First nil yes no)
+(EQ (FlagLT_ULT) yes no) -> (First nil no yes)
+(EQ (FlagLT_UGT) yes no) -> (First nil no yes)
+(EQ (FlagGT_ULT) yes no) -> (First nil no yes)
+(EQ (FlagGT_UGT) yes no) -> (First nil no yes)
+
+(NE (FlagEQ) yes no) -> (First nil no yes)
+(NE (FlagLT_ULT) yes no) -> (First nil yes no)
+(NE (FlagLT_UGT) yes no) -> (First nil yes no)
+(NE (FlagGT_ULT) yes no) -> (First nil yes no)
+(NE (FlagGT_UGT) yes no) -> (First nil yes no)
+
+(LT (FlagEQ) yes no) -> (First nil no yes)
+(LT (FlagLT_ULT) yes no) -> (First nil yes no)
+(LT (FlagLT_UGT) yes no) -> (First nil yes no)
+(LT (FlagGT_ULT) yes no) -> (First nil no yes)
+(LT (FlagGT_UGT) yes no) -> (First nil no yes)
+
+(LE (FlagEQ) yes no) -> (First nil yes no)
+(LE (FlagLT_ULT) yes no) -> (First nil yes no)
+(LE (FlagLT_UGT) yes no) -> (First nil yes no)
+(LE (FlagGT_ULT) yes no) -> (First nil no yes)
+(LE (FlagGT_UGT) yes no) -> (First nil no yes)
+
+(GT (FlagEQ) yes no) -> (First nil no yes)
+(GT (FlagLT_ULT) yes no) -> (First nil no yes)
+(GT (FlagLT_UGT) yes no) -> (First nil no yes)
+(GT (FlagGT_ULT) yes no) -> (First nil yes no)
+(GT (FlagGT_UGT) yes no) -> (First nil yes no)
+
+(GE (FlagEQ) yes no) -> (First nil yes no)
+(GE (FlagLT_ULT) yes no) -> (First nil no yes)
+(GE (FlagLT_UGT) yes no) -> (First nil no yes)
+(GE (FlagGT_ULT) yes no) -> (First nil yes no)
+(GE (FlagGT_UGT) yes no) -> (First nil yes no)
+
+(ULT (FlagEQ) yes no) -> (First nil no yes)
+(ULT (FlagLT_ULT) yes no) -> (First nil yes no)
+(ULT (FlagLT_UGT) yes no) -> (First nil no yes)
+(ULT (FlagGT_ULT) yes no) -> (First nil yes no)
+(ULT (FlagGT_UGT) yes no) -> (First nil no yes)
+
+(ULE (FlagEQ) yes no) -> (First nil yes no)
+(ULE (FlagLT_ULT) yes no) -> (First nil yes no)
+(ULE (FlagLT_UGT) yes no) -> (First nil no yes)
+(ULE (FlagGT_ULT) yes no) -> (First nil yes no)
+(ULE (FlagGT_UGT) yes no) -> (First nil no yes)
+
+(UGT (FlagEQ) yes no) -> (First nil no yes)
+(UGT (FlagLT_ULT) yes no) -> (First nil no yes)
+(UGT (FlagLT_UGT) yes no) -> (First nil yes no)
+(UGT (FlagGT_ULT) yes no) -> (First nil no yes)
+(UGT (FlagGT_UGT) yes no) -> (First nil yes no)
+
+(UGE (FlagEQ) yes no) -> (First nil yes no)
+(UGE (FlagLT_ULT) yes no) -> (First nil no yes)
+(UGE (FlagLT_UGT) yes no) -> (First nil yes no)
+(UGE (FlagGT_ULT) yes no) -> (First nil no yes)
+(UGE (FlagGT_UGT) yes no) -> (First nil yes no)
+
+// Absorb flag constants into SETxx ops.
+(SETEQ (FlagEQ)) -> (MOVLconst [1])
+(SETEQ (FlagLT_ULT)) -> (MOVLconst [0])
+(SETEQ (FlagLT_UGT)) -> (MOVLconst [0])
+(SETEQ (FlagGT_ULT)) -> (MOVLconst [0])
+(SETEQ (FlagGT_UGT)) -> (MOVLconst [0])
+
+(SETNE (FlagEQ)) -> (MOVLconst [0])
+(SETNE (FlagLT_ULT)) -> (MOVLconst [1])
+(SETNE (FlagLT_UGT)) -> (MOVLconst [1])
+(SETNE (FlagGT_ULT)) -> (MOVLconst [1])
+(SETNE (FlagGT_UGT)) -> (MOVLconst [1])
+
+(SETL (FlagEQ)) -> (MOVLconst [0])
+(SETL (FlagLT_ULT)) -> (MOVLconst [1])
+(SETL (FlagLT_UGT)) -> (MOVLconst [1])
+(SETL (FlagGT_ULT)) -> (MOVLconst [0])
+(SETL (FlagGT_UGT)) -> (MOVLconst [0])
+
+(SETLE (FlagEQ)) -> (MOVLconst [1])
+(SETLE (FlagLT_ULT)) -> (MOVLconst [1])
+(SETLE (FlagLT_UGT)) -> (MOVLconst [1])
+(SETLE (FlagGT_ULT)) -> (MOVLconst [0])
+(SETLE (FlagGT_UGT)) -> (MOVLconst [0])
+
+(SETG (FlagEQ)) -> (MOVLconst [0])
+(SETG (FlagLT_ULT)) -> (MOVLconst [0])
+(SETG (FlagLT_UGT)) -> (MOVLconst [0])
+(SETG (FlagGT_ULT)) -> (MOVLconst [1])
+(SETG (FlagGT_UGT)) -> (MOVLconst [1])
+
+(SETGE (FlagEQ)) -> (MOVLconst [1])
+(SETGE (FlagLT_ULT)) -> (MOVLconst [0])
+(SETGE (FlagLT_UGT)) -> (MOVLconst [0])
+(SETGE (FlagGT_ULT)) -> (MOVLconst [1])
+(SETGE (FlagGT_UGT)) -> (MOVLconst [1])
+
+(SETB (FlagEQ)) -> (MOVLconst [0])
+(SETB (FlagLT_ULT)) -> (MOVLconst [1])
+(SETB (FlagLT_UGT)) -> (MOVLconst [0])
+(SETB (FlagGT_ULT)) -> (MOVLconst [1])
+(SETB (FlagGT_UGT)) -> (MOVLconst [0])
+
+(SETBE (FlagEQ)) -> (MOVLconst [1])
+(SETBE (FlagLT_ULT)) -> (MOVLconst [1])
+(SETBE (FlagLT_UGT)) -> (MOVLconst [0])
+(SETBE (FlagGT_ULT)) -> (MOVLconst [1])
+(SETBE (FlagGT_UGT)) -> (MOVLconst [0])
+
+(SETA (FlagEQ)) -> (MOVLconst [0])
+(SETA (FlagLT_ULT)) -> (MOVLconst [0])
+(SETA (FlagLT_UGT)) -> (MOVLconst [1])
+(SETA (FlagGT_ULT)) -> (MOVLconst [0])
+(SETA (FlagGT_UGT)) -> (MOVLconst [1])
+
+(SETAE (FlagEQ)) -> (MOVLconst [1])
+(SETAE (FlagLT_ULT)) -> (MOVLconst [0])
+(SETAE (FlagLT_UGT)) -> (MOVLconst [1])
+(SETAE (FlagGT_ULT)) -> (MOVLconst [0])
+(SETAE (FlagGT_UGT)) -> (MOVLconst [1])
+
+// Remove redundant *const ops
+(ADDLconst [c] x) && int32(c)==0 -> x
+(SUBLconst [c] x) && int32(c) == 0 -> x
+(ANDLconst [c] _) && int32(c)==0 -> (MOVLconst [0])
+(ANDLconst [c] x) && int32(c)==-1 -> x
+(ORLconst [c] x) && int32(c)==0 -> x
+(ORLconst [c] _) && int32(c)==-1 -> (MOVLconst [-1])
+(XORLconst [c] x) && int32(c)==0 -> x
+// TODO: since we got rid of the W/B versions, we might miss
+// things like (ANDLconst [0x100] x) which were formerly
+// (ANDBconst [0] x). Probably doesn't happen very often.
+// If we cared, we might do:
+// (ANDLconst <t> [c] x) && t.Size()==1 && int8(x)==0 -> (MOVLconst [0])
+
+// Convert constant subtracts to constant adds
+(SUBLconst [c] x) -> (ADDLconst [int64(int32(-c))] x)
+
+// generic constant folding
+// TODO: more of this
+(ADDLconst [c] (MOVLconst [d])) -> (MOVLconst [int64(int32(c+d))])
+(ADDLconst [c] (ADDLconst [d] x)) -> (ADDLconst [int64(int32(c+d))] x)
+(SARLconst [c] (MOVLconst [d])) -> (MOVLconst [d>>uint64(c)])
+(SARWconst [c] (MOVLconst [d])) -> (MOVLconst [d>>uint64(c)])
+(SARBconst [c] (MOVLconst [d])) -> (MOVLconst [d>>uint64(c)])
+(NEGL (MOVLconst [c])) -> (MOVLconst [int64(int32(-c))])
+(MULLconst [c] (MOVLconst [d])) -> (MOVLconst [int64(int32(c*d))])
+(ANDLconst [c] (MOVLconst [d])) -> (MOVLconst [c&d])
+(ORLconst [c] (MOVLconst [d])) -> (MOVLconst [c|d])
+(XORLconst [c] (MOVLconst [d])) -> (MOVLconst [c^d])
+(NOTL (MOVLconst [c])) -> (MOVLconst [^c])
+
+// generic simplifications
+// TODO: more of this
+(ADDL x (NEGL y)) -> (SUBL x y)
+(SUBL x x) -> (MOVLconst [0])
+(ANDL x x) -> x
+(ORL x x) -> x
+(XORL x x) -> (MOVLconst [0])
+
+// checking AND against 0.
+(CMPLconst (ANDL x y) [0]) -> (TESTL x y)
+(CMPWconst (ANDL x y) [0]) -> (TESTW x y)
+(CMPBconst (ANDL x y) [0]) -> (TESTB x y)
+(CMPLconst (ANDLconst [c] x) [0]) -> (TESTLconst [c] x)
+(CMPWconst (ANDLconst [c] x) [0]) -> (TESTWconst [int64(int16(c))] x)
+(CMPBconst (ANDLconst [c] x) [0]) -> (TESTBconst [int64(int8(c))] x)
+
+// TEST %reg,%reg is shorter than CMP
+(CMPLconst x [0]) -> (TESTL x x)
+(CMPWconst x [0]) -> (TESTW x x)
+(CMPBconst x [0]) -> (TESTB x x)
+
+// Combining byte loads into larger (unaligned) loads.
+// There are many ways these combinations could occur. This is
+// designed to match the way encoding/binary.LittleEndian does it.
+(ORL x0:(MOVBload [i] {s} p mem)
+ s0:(SHLLconst [8] x1:(MOVBload [i+1] {s} p mem)))
+ && x0.Uses == 1
+ && x1.Uses == 1
+ && s0.Uses == 1
+ && mergePoint(b,x0,x1) != nil
+ && clobber(x0)
+ && clobber(x1)
+ && clobber(s0)
+ -> @mergePoint(b,x0,x1) (MOVWload [i] {s} p mem)
+
+(ORL o0:(ORL
+ 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.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)
+ -> @mergePoint(b,x0,x1,x2) (MOVLload [i] {s} p mem)
+
+(ORL x0:(MOVBloadidx1 [i] {s} p idx mem)
+ s0:(SHLLconst [8] x1:(MOVBloadidx1 [i+1] {s} p idx mem)))
+ && x0.Uses == 1
+ && x1.Uses == 1
+ && s0.Uses == 1
+ && mergePoint(b,x0,x1) != nil
+ && clobber(x0)
+ && clobber(x1)
+ && clobber(s0)
+ -> @mergePoint(b,x0,x1) (MOVWloadidx1 <v.Type> [i] {s} p idx mem)
+
+(ORL o0:(ORL
+ 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.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)
+ -> @mergePoint(b,x0,x1,x2) (MOVLloadidx1 <v.Type> [i] {s} p idx mem)
+
+// Combine constant stores into larger (unaligned) stores.
+(MOVBstoreconst [c] {s} p x:(MOVBstoreconst [a] {s} p mem))
+ && x.Uses == 1
+ && ValAndOff(a).Off() + 1 == ValAndOff(c).Off()
+ && clobber(x)
+ -> (MOVWstoreconst [makeValAndOff(ValAndOff(a).Val()&0xff | ValAndOff(c).Val()<<8, ValAndOff(a).Off())] {s} p mem)
+(MOVWstoreconst [c] {s} p x:(MOVWstoreconst [a] {s} p mem))
+ && x.Uses == 1
+ && ValAndOff(a).Off() + 2 == ValAndOff(c).Off()
+ && clobber(x)
+ -> (MOVLstoreconst [makeValAndOff(ValAndOff(a).Val()&0xffff | ValAndOff(c).Val()<<16, ValAndOff(a).Off())] {s} p mem)
+
+(MOVBstoreconstidx1 [c] {s} p i x:(MOVBstoreconstidx1 [a] {s} p i mem))
+ && x.Uses == 1
+ && ValAndOff(a).Off() + 1 == ValAndOff(c).Off()
+ && clobber(x)
+ -> (MOVWstoreconstidx1 [makeValAndOff(ValAndOff(a).Val()&0xff | ValAndOff(c).Val()<<8, ValAndOff(a).Off())] {s} p i mem)
+(MOVWstoreconstidx1 [c] {s} p i x:(MOVWstoreconstidx1 [a] {s} p i mem))
+ && x.Uses == 1
+ && ValAndOff(a).Off() + 2 == ValAndOff(c).Off()
+ && clobber(x)
+ -> (MOVLstoreconstidx1 [makeValAndOff(ValAndOff(a).Val()&0xffff | ValAndOff(c).Val()<<16, ValAndOff(a).Off())] {s} p i mem)
+
+(MOVWstoreconstidx2 [c] {s} p i x:(MOVWstoreconstidx2 [a] {s} p i mem))
+ && x.Uses == 1
+ && ValAndOff(a).Off() + 2 == ValAndOff(c).Off()
+ && clobber(x)
+ -> (MOVLstoreconstidx1 [makeValAndOff(ValAndOff(a).Val()&0xffff | ValAndOff(c).Val()<<16, ValAndOff(a).Off())] {s} p (SHLLconst <i.Type> [1] i) mem)
+
+// Combine stores into larger (unaligned) stores.
+(MOVBstore [i] {s} p (SHRLconst [8] w) x:(MOVBstore [i-1] {s} p w mem))
+ && x.Uses == 1
+ && clobber(x)
+ -> (MOVWstore [i-1] {s} p w mem)
+(MOVBstore [i] {s} p (SHRLconst [j] w) x:(MOVBstore [i-1] {s} p w0:(SHRLconst [j-8] w) mem))
+ && x.Uses == 1
+ && clobber(x)
+ -> (MOVWstore [i-1] {s} p w0 mem)
+(MOVWstore [i] {s} p (SHRLconst [16] w) x:(MOVWstore [i-2] {s} p w mem))
+ && x.Uses == 1
+ && clobber(x)
+ -> (MOVLstore [i-2] {s} p w mem)
+(MOVWstore [i] {s} p (SHRLconst [j] w) x:(MOVWstore [i-2] {s} p w0:(SHRLconst [j-16] w) mem))
+ && x.Uses == 1
+ && clobber(x)
+ -> (MOVLstore [i-2] {s} p w0 mem)
+
+(MOVBstoreidx1 [i] {s} p idx (SHRLconst [8] w) x:(MOVBstoreidx1 [i-1] {s} p idx w mem))
+ && x.Uses == 1
+ && clobber(x)
+ -> (MOVWstoreidx1 [i-1] {s} p idx w mem)
+(MOVBstoreidx1 [i] {s} p idx (SHRLconst [j] w) x:(MOVBstoreidx1 [i-1] {s} p idx w0:(SHRLconst [j-8] w) mem))
+ && x.Uses == 1
+ && clobber(x)
+ -> (MOVWstoreidx1 [i-1] {s} p idx w0 mem)
+(MOVWstoreidx1 [i] {s} p idx (SHRLconst [16] w) x:(MOVWstoreidx1 [i-2] {s} p idx w mem))
+ && x.Uses == 1
+ && clobber(x)
+ -> (MOVLstoreidx1 [i-2] {s} p idx w mem)
+(MOVWstoreidx1 [i] {s} p idx (SHRLconst [j] w) x:(MOVWstoreidx1 [i-2] {s} p idx w0:(SHRLconst [j-16] w) mem))
+ && x.Uses == 1
+ && clobber(x)
+ -> (MOVLstoreidx1 [i-2] {s} p idx w0 mem)
+
+(MOVWstoreidx2 [i] {s} p idx (SHRLconst [16] w) x:(MOVWstoreidx2 [i-2] {s} p idx w mem))
+ && x.Uses == 1
+ && clobber(x)
+ -> (MOVLstoreidx1 [i-2] {s} p (SHLLconst <idx.Type> [1] idx) w mem)
+(MOVWstoreidx2 [i] {s} p idx (SHRLconst [j] w) x:(MOVWstoreidx2 [i-2] {s} p idx w0:(SHRLconst [j-16] w) mem))
+ && x.Uses == 1
+ && clobber(x)
+ -> (MOVLstoreidx1 [i-2] {s} p (SHLLconst <idx.Type> [1] idx) w0 mem)
+
+// For PIC, break floating-point constant loading into two instructions so we have
+// a register to use for holding the address of the constant pool entry.
+(MOVSSconst [c]) && config.ctxt.Flag_shared -> (MOVSSconst2 (MOVSSconst1 [c]))
+(MOVSDconst [c]) && config.ctxt.Flag_shared -> (MOVSDconst2 (MOVSDconst1 [c]))
diff --git a/src/cmd/compile/internal/ssa/gen/386Ops.go b/src/cmd/compile/internal/ssa/gen/386Ops.go
new file mode 100644
index 0000000..d09f497
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/gen/386Ops.go
@@ -0,0 +1,506 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build ignore
+
+package main
+
+import "strings"
+
+// Notes:
+// - Integer types live in the low portion of registers. Upper portions are junk.
+// - Boolean types use the low-order byte of a register. 0=false, 1=true.
+// Upper bytes are junk.
+// - Floating-point types live in the low natural slot of an sse2 register.
+// Unused portions are junk.
+// - We do not use AH,BH,CH,DH registers.
+// - When doing sub-register operations, we try to write the whole
+// destination register to avoid a partial-register write.
+// - Unused portions of AuxInt (or the Val portion of ValAndOff) are
+// filled by sign-extending the used portion. Users of AuxInt which interpret
+// AuxInt as unsigned (e.g. shifts) must be careful.
+
+// Suffixes encode the bit width of various instructions.
+// L (long word) = 32 bit
+// W (word) = 16 bit
+// B (byte) = 8 bit
+
+// copied from ../../x86/reg.go
+var regNames386 = []string{
+ "AX",
+ "CX",
+ "DX",
+ "BX",
+ "SP",
+ "BP",
+ "SI",
+ "DI",
+ "X0",
+ "X1",
+ "X2",
+ "X3",
+ "X4",
+ "X5",
+ "X6",
+ "X7",
+
+ // pseudo-registers
+ "SB",
+}
+
+// Notes on 387 support.
+// - The 387 has a weird stack-register setup for floating-point registers.
+// We use these registers when SSE registers are not available (when GO386=387).
+// - We use the same register names (X0-X7) but they refer to the 387
+// floating-point registers. That way, most of the SSA backend is unchanged.
+// - The instruction generation pass maintains an SSE->387 register mapping.
+// This mapping is updated whenever the FP stack is pushed or popped so that
+// we can always find a given SSE register even when the TOS pointer has changed.
+// - To facilitate the mapping from SSE to 387, we enforce that
+// every basic block starts and ends with an empty floating-point stack.
+
+func init() {
+ // Make map from reg names to reg integers.
+ if len(regNames386) > 64 {
+ panic("too many registers")
+ }
+ num := map[string]int{}
+ for i, name := range regNames386 {
+ num[name] = i
+ }
+ buildReg := func(s string) regMask {
+ m := regMask(0)
+ for _, r := range strings.Split(s, " ") {
+ if n, ok := num[r]; ok {
+ m |= regMask(1) << uint(n)
+ continue
+ }
+ panic("register " + r + " not found")
+ }
+ return m
+ }
+
+ // Common individual register masks
+ var (
+ ax = buildReg("AX")
+ cx = buildReg("CX")
+ dx = buildReg("DX")
+ gp = buildReg("AX CX DX BX BP SI DI")
+ fp = buildReg("X0 X1 X2 X3 X4 X5 X6 X7")
+ gpsp = gp | buildReg("SP")
+ gpspsb = gpsp | buildReg("SB")
+ callerSave = gp | fp
+ )
+ // Common slices of register masks
+ var (
+ gponly = []regMask{gp}
+ fponly = []regMask{fp}
+ )
+
+ // Common regInfo
+ var (
+ gp01 = regInfo{inputs: nil, outputs: gponly}
+ gp11 = regInfo{inputs: []regMask{gp}, outputs: gponly}
+ gp11sp = regInfo{inputs: []regMask{gpsp}, outputs: gponly}
+ gp11sb = regInfo{inputs: []regMask{gpspsb}, outputs: gponly}
+ gp21 = regInfo{inputs: []regMask{gp, gp}, outputs: gponly}
+ gp11carry = regInfo{inputs: []regMask{gp}, outputs: []regMask{gp, 0}}
+ gp21carry = regInfo{inputs: []regMask{gp, gp}, outputs: []regMask{gp, 0}}
+ gp1carry1 = regInfo{inputs: []regMask{gp}, outputs: gponly}
+ gp2carry1 = regInfo{inputs: []regMask{gp, gp}, outputs: gponly}
+ gp21sp = regInfo{inputs: []regMask{gpsp, gp}, outputs: gponly}
+ gp21sb = regInfo{inputs: []regMask{gpspsb, gpsp}, outputs: gponly}
+ gp21shift = regInfo{inputs: []regMask{gp, cx}, outputs: []regMask{gp}}
+ gp11div = regInfo{inputs: []regMask{ax, gpsp &^ dx}, outputs: []regMask{ax}, clobbers: dx}
+ gp21hmul = regInfo{inputs: []regMask{ax, gpsp}, outputs: []regMask{dx}, clobbers: ax}
+ gp11mod = regInfo{inputs: []regMask{ax, gpsp &^ dx}, outputs: []regMask{dx}, clobbers: ax}
+ gp21mul = regInfo{inputs: []regMask{ax, gpsp}, outputs: []regMask{dx, ax}}
+
+ gp2flags = regInfo{inputs: []regMask{gpsp, gpsp}}
+ gp1flags = regInfo{inputs: []regMask{gpsp}}
+ flagsgp = regInfo{inputs: nil, outputs: gponly}
+
+ readflags = regInfo{inputs: nil, outputs: gponly}
+ flagsgpax = regInfo{inputs: nil, clobbers: ax, outputs: []regMask{gp &^ ax}}
+
+ gpload = regInfo{inputs: []regMask{gpspsb, 0}, outputs: gponly}
+ gploadidx = regInfo{inputs: []regMask{gpspsb, gpsp, 0}, outputs: gponly}
+
+ gpstore = regInfo{inputs: []regMask{gpspsb, gpsp, 0}}
+ gpstoreconst = regInfo{inputs: []regMask{gpspsb, 0}}
+ gpstoreidx = regInfo{inputs: []regMask{gpspsb, gpsp, gpsp, 0}}
+ gpstoreconstidx = regInfo{inputs: []regMask{gpspsb, gpsp, 0}}
+
+ fp01 = regInfo{inputs: nil, outputs: fponly}
+ fp21 = regInfo{inputs: []regMask{fp, fp}, outputs: fponly}
+ fpgp = regInfo{inputs: fponly, outputs: gponly}
+ gpfp = regInfo{inputs: gponly, outputs: fponly}
+ fp11 = regInfo{inputs: fponly, outputs: fponly}
+ fp2flags = regInfo{inputs: []regMask{fp, fp}}
+
+ fpload = regInfo{inputs: []regMask{gpspsb, 0}, outputs: fponly}
+ fploadidx = regInfo{inputs: []regMask{gpspsb, gpsp, 0}, outputs: fponly}
+
+ fpstore = regInfo{inputs: []regMask{gpspsb, fp, 0}}
+ fpstoreidx = regInfo{inputs: []regMask{gpspsb, gpsp, fp, 0}}
+ )
+
+ var _386ops = []opData{
+ // fp ops
+ {name: "ADDSS", argLength: 2, reg: fp21, asm: "ADDSS", commutative: true, resultInArg0: true, usesScratch: true}, // fp32 add
+ {name: "ADDSD", argLength: 2, reg: fp21, asm: "ADDSD", commutative: true, resultInArg0: true}, // fp64 add
+ {name: "SUBSS", argLength: 2, reg: fp21, asm: "SUBSS", resultInArg0: true, usesScratch: true}, // fp32 sub
+ {name: "SUBSD", argLength: 2, reg: fp21, asm: "SUBSD", resultInArg0: true}, // fp64 sub
+ {name: "MULSS", argLength: 2, reg: fp21, asm: "MULSS", commutative: true, resultInArg0: true, usesScratch: true}, // fp32 mul
+ {name: "MULSD", argLength: 2, reg: fp21, asm: "MULSD", commutative: true, resultInArg0: true}, // fp64 mul
+ {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
+
+ // binary ops
+ {name: "ADDL", argLength: 2, reg: gp21sp, asm: "ADDL", commutative: true, clobberFlags: true}, // arg0 + arg1
+ {name: "ADDLconst", argLength: 1, reg: gp11sp, asm: "ADDL", aux: "Int32", typ: "UInt32", clobberFlags: true}, // arg0 + auxint
+
+ {name: "ADDLcarry", argLength: 2, reg: gp21carry, asm: "ADDL", commutative: true, resultInArg0: true}, // arg0 + arg1, generates <carry,result> pair
+ {name: "ADDLconstcarry", argLength: 1, reg: gp11carry, asm: "ADDL", aux: "Int32", resultInArg0: true}, // arg0 + auxint, generates <carry,result> pair
+ {name: "ADCL", argLength: 3, reg: gp2carry1, asm: "ADCL", commutative: true, resultInArg0: true, clobberFlags: true}, // arg0+arg1+carry(arg2), where arg2 is flags
+ {name: "ADCLconst", argLength: 2, reg: gp1carry1, asm: "ADCL", aux: "Int32", resultInArg0: true, clobberFlags: true}, // arg0+auxint+carry(arg1), where arg1 is flags
+
+ {name: "SUBL", argLength: 2, reg: gp21, asm: "SUBL", resultInArg0: true, clobberFlags: true}, // arg0 - arg1
+ {name: "SUBLconst", argLength: 1, reg: gp11, asm: "SUBL", aux: "Int32", resultInArg0: true, clobberFlags: true}, // arg0 - auxint
+
+ {name: "SUBLcarry", argLength: 2, reg: gp21carry, asm: "SUBL", resultInArg0: true}, // arg0-arg1, generates <borrow,result> pair
+ {name: "SUBLconstcarry", argLength: 1, reg: gp11carry, asm: "SUBL", aux: "Int32", resultInArg0: true}, // arg0-auxint, generates <borrow,result> pair
+ {name: "SBBL", argLength: 3, reg: gp2carry1, asm: "SBBL", resultInArg0: true, clobberFlags: true}, // arg0-arg1-borrow(arg2), where arg2 is flags
+ {name: "SBBLconst", argLength: 2, reg: gp1carry1, asm: "SBBL", aux: "Int32", resultInArg0: true, clobberFlags: true}, // arg0-auxint-borrow(arg1), where arg1 is flags
+
+ {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: "MULLQU", argLength: 2, reg: gp21mul, asm: "MULL", clobberFlags: true}, // arg0 * arg1, high 32 in result[0], low 32 in result[1]
+
+ {name: "DIVL", argLength: 2, reg: gp11div, asm: "IDIVL", clobberFlags: true}, // arg0 / arg1
+ {name: "DIVW", argLength: 2, reg: gp11div, asm: "IDIVW", clobberFlags: true}, // arg0 / arg1
+ {name: "DIVLU", argLength: 2, reg: gp11div, asm: "DIVL", clobberFlags: true}, // arg0 / arg1
+ {name: "DIVWU", argLength: 2, reg: gp11div, asm: "DIVW", clobberFlags: true}, // arg0 / arg1
+
+ {name: "MODL", argLength: 2, reg: gp11mod, asm: "IDIVL", clobberFlags: true}, // arg0 % arg1
+ {name: "MODW", argLength: 2, reg: gp11mod, asm: "IDIVW", clobberFlags: true}, // arg0 % arg1
+ {name: "MODLU", argLength: 2, reg: gp11mod, asm: "DIVL", clobberFlags: true}, // arg0 % arg1
+ {name: "MODWU", argLength: 2, reg: gp11mod, asm: "DIVW", clobberFlags: true}, // arg0 % arg1
+
+ {name: "ANDL", argLength: 2, reg: gp21, asm: "ANDL", commutative: true, resultInArg0: true, clobberFlags: true}, // arg0 & arg1
+ {name: "ANDLconst", argLength: 1, reg: gp11, asm: "ANDL", aux: "Int32", resultInArg0: true, clobberFlags: true}, // arg0 & auxint
+
+ {name: "ORL", argLength: 2, reg: gp21, asm: "ORL", commutative: true, resultInArg0: true, clobberFlags: true}, // arg0 | arg1
+ {name: "ORLconst", argLength: 1, reg: gp11, asm: "ORL", aux: "Int32", resultInArg0: true, clobberFlags: true}, // arg0 | auxint
+
+ {name: "XORL", argLength: 2, reg: gp21, asm: "XORL", commutative: true, resultInArg0: true, clobberFlags: true}, // arg0 ^ arg1
+ {name: "XORLconst", argLength: 1, reg: gp11, asm: "XORL", aux: "Int32", resultInArg0: true, clobberFlags: true}, // arg0 ^ auxint
+
+ {name: "CMPL", argLength: 2, reg: gp2flags, asm: "CMPL", typ: "Flags"}, // arg0 compare to arg1
+ {name: "CMPW", argLength: 2, reg: gp2flags, asm: "CMPW", typ: "Flags"}, // arg0 compare to arg1
+ {name: "CMPB", argLength: 2, reg: gp2flags, asm: "CMPB", typ: "Flags"}, // arg0 compare to arg1
+ {name: "CMPLconst", argLength: 1, reg: gp1flags, asm: "CMPL", typ: "Flags", aux: "Int32"}, // arg0 compare to auxint
+ {name: "CMPWconst", argLength: 1, reg: gp1flags, asm: "CMPW", typ: "Flags", aux: "Int16"}, // arg0 compare to auxint
+ {name: "CMPBconst", argLength: 1, reg: gp1flags, asm: "CMPB", typ: "Flags", aux: "Int8"}, // arg0 compare to auxint
+
+ {name: "UCOMISS", argLength: 2, reg: fp2flags, asm: "UCOMISS", typ: "Flags", 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: "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: "SHLL", argLength: 2, reg: gp21shift, asm: "SHLL", resultInArg0: true, clobberFlags: true}, // arg0 << arg1, shift amount is mod 32
+ {name: "SHLLconst", argLength: 1, reg: gp11, asm: "SHLL", aux: "Int32", 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: "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: "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: "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: "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
+
+ // unary ops
+ {name: "NEGL", argLength: 1, reg: gp11, asm: "NEGL", resultInArg0: true, clobberFlags: true}, // -arg0
+
+ {name: "NOTL", argLength: 1, reg: gp11, asm: "NOTL", resultInArg0: true, clobberFlags: true}, // ^arg0
+
+ {name: "BSFL", argLength: 1, reg: gp11, asm: "BSFL", clobberFlags: true}, // arg0 # of low-order zeroes ; undef if zero
+ {name: "BSFW", argLength: 1, reg: gp11, asm: "BSFW", clobberFlags: true}, // arg0 # of low-order zeroes ; undef if zero
+
+ {name: "BSRL", argLength: 1, reg: gp11, asm: "BSRL", clobberFlags: true}, // arg0 # of high-order zeroes ; undef if zero
+ {name: "BSRW", argLength: 1, reg: gp11, asm: "BSRW", clobberFlags: true}, // arg0 # of high-order zeroes ; undef if zero
+
+ {name: "BSWAPL", argLength: 1, reg: gp11, asm: "BSWAPL", resultInArg0: true, clobberFlags: true}, // arg0 swap bytes
+
+ {name: "SQRTSD", argLength: 1, reg: fp11, asm: "SQRTSD"}, // sqrt(arg0)
+
+ {name: "SBBLcarrymask", argLength: 1, reg: flagsgp, asm: "SBBL"}, // (int32)(-1) if carry is set, 0 if carry is clear.
+ // Note: SBBW and SBBB are subsumed by SBBL
+
+ {name: "SETEQ", argLength: 1, reg: readflags, asm: "SETEQ"}, // extract == condition from arg0
+ {name: "SETNE", argLength: 1, reg: readflags, asm: "SETNE"}, // extract != condition from arg0
+ {name: "SETL", argLength: 1, reg: readflags, asm: "SETLT"}, // extract signed < condition from arg0
+ {name: "SETLE", argLength: 1, reg: readflags, asm: "SETLE"}, // extract signed <= condition from arg0
+ {name: "SETG", argLength: 1, reg: readflags, asm: "SETGT"}, // extract signed > condition from arg0
+ {name: "SETGE", argLength: 1, reg: readflags, asm: "SETGE"}, // extract signed >= condition from arg0
+ {name: "SETB", argLength: 1, reg: readflags, asm: "SETCS"}, // extract unsigned < condition from arg0
+ {name: "SETBE", argLength: 1, reg: readflags, asm: "SETLS"}, // extract unsigned <= condition from arg0
+ {name: "SETA", argLength: 1, reg: readflags, asm: "SETHI"}, // extract unsigned > condition from arg0
+ {name: "SETAE", argLength: 1, reg: readflags, asm: "SETCC"}, // extract unsigned >= condition from arg0
+ // Need different opcodes for floating point conditions because
+ // any comparison involving a NaN is always FALSE and thus
+ // the patterns for inverting conditions cannot be used.
+ {name: "SETEQF", argLength: 1, reg: flagsgpax, asm: "SETEQ", clobberFlags: true}, // extract == condition from arg0
+ {name: "SETNEF", argLength: 1, reg: flagsgpax, asm: "SETNE", clobberFlags: true}, // extract != condition from arg0
+ {name: "SETORD", argLength: 1, reg: flagsgp, asm: "SETPC"}, // extract "ordered" (No Nan present) condition from arg0
+ {name: "SETNAN", argLength: 1, reg: flagsgp, asm: "SETPS"}, // extract "unordered" (Nan present) condition from arg0
+
+ {name: "SETGF", argLength: 1, reg: flagsgp, asm: "SETHI"}, // extract floating > condition from arg0
+ {name: "SETGEF", argLength: 1, reg: flagsgp, asm: "SETCC"}, // extract floating >= condition from arg0
+
+ {name: "MOVBLSX", argLength: 1, reg: gp11, asm: "MOVBLSX"}, // sign extend arg0 from int8 to int32
+ {name: "MOVBLZX", argLength: 1, reg: gp11, asm: "MOVBLZX"}, // zero extend arg0 from int8 to int32
+ {name: "MOVWLSX", argLength: 1, reg: gp11, asm: "MOVWLSX"}, // sign extend arg0 from int16 to int32
+ {name: "MOVWLZX", argLength: 1, reg: gp11, asm: "MOVWLZX"}, // zero extend arg0 from int16 to int32
+
+ {name: "MOVLconst", reg: gp01, asm: "MOVL", typ: "UInt32", aux: "Int32", rematerializeable: true}, // 32 low bits of auxint
+
+ {name: "CVTTSD2SL", argLength: 1, reg: fpgp, asm: "CVTTSD2SL", usesScratch: true}, // convert float64 to int32
+ {name: "CVTTSS2SL", argLength: 1, reg: fpgp, asm: "CVTTSS2SL", usesScratch: true}, // convert float32 to int32
+ {name: "CVTSL2SS", argLength: 1, reg: gpfp, asm: "CVTSL2SS", usesScratch: true}, // convert int32 to float32
+ {name: "CVTSL2SD", argLength: 1, reg: gpfp, asm: "CVTSL2SD", usesScratch: true}, // convert int32 to float64
+ {name: "CVTSD2SS", argLength: 1, reg: fp11, asm: "CVTSD2SS", usesScratch: true}, // convert float64 to float32
+ {name: "CVTSS2SD", argLength: 1, reg: fp11, asm: "CVTSS2SD"}, // convert float32 to float64
+
+ {name: "PXOR", argLength: 2, reg: fp21, asm: "PXOR", commutative: true, resultInArg0: true}, // exclusive or, applied to X regs for float negation.
+
+ {name: "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
+ // 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
+
+ // 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
+ // 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
+ // 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: "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 ...
+
+ // arg0 = pointer to start of memory to zero
+ // arg1 = value to store (will always be zero)
+ // arg2 = mem
+ // auxint = offset into duffzero code to start executing
+ // returns mem
+ {
+ name: "DUFFZERO",
+ aux: "Int64",
+ argLength: 3,
+ reg: regInfo{
+ inputs: []regMask{buildReg("DI"), buildReg("AX")},
+ clobbers: buildReg("DI CX"),
+ // Note: CX is only clobbered when dynamic linking.
+ },
+ },
+
+ // arg0 = address of memory to zero
+ // arg1 = # of 4-byte words to zero
+ // arg2 = value to store (will always be zero)
+ // arg3 = mem
+ // returns mem
+ {
+ name: "REPSTOSL",
+ argLength: 4,
+ reg: regInfo{
+ inputs: []regMask{buildReg("DI"), buildReg("CX"), buildReg("AX")},
+ clobbers: buildReg("DI CX"),
+ },
+ },
+
+ {name: "CALLstatic", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "SymOff", 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("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
+ // arg1 = source pointer
+ // arg2 = mem
+ // auxint = offset from duffcopy symbol to call
+ // returns memory
+ {
+ name: "DUFFCOPY",
+ aux: "Int64",
+ argLength: 3,
+ reg: regInfo{
+ inputs: []regMask{buildReg("DI"), buildReg("SI")},
+ clobbers: buildReg("DI SI CX"), // uses CX as a temporary
+ },
+ clobberFlags: true,
+ },
+
+ // arg0 = destination pointer
+ // arg1 = source pointer
+ // arg2 = # of 8-byte words to copy
+ // arg3 = mem
+ // returns memory
+ {
+ name: "REPMOVSL",
+ argLength: 4,
+ reg: regInfo{
+ inputs: []regMask{buildReg("DI"), buildReg("SI"), buildReg("CX")},
+ clobbers: buildReg("DI SI CX"),
+ },
+ },
+
+ // (InvertFlags (CMPL a b)) == (CMPL b a)
+ // So if we want (SETL (CMPL a b)) but we can't do that because a is a constant,
+ // then we do (SETL (InvertFlags (CMPL b a))) instead.
+ // Rewrites will convert this to (SETG (CMPL b a)).
+ // InvertFlags is a pseudo-op which can't appear in assembly output.
+ {name: "InvertFlags", argLength: 1}, // reverse direction of arg0
+
+ // Pseudo-ops
+ {name: "LoweredGetG", argLength: 1, reg: gp01}, // arg0=mem
+ // Scheduler ensures LoweredGetClosurePtr occurs only in entry block,
+ // and sorts it to the very beginning of the block to prevent other
+ // use of DX (the closure pointer)
+ {name: "LoweredGetClosurePtr", reg: regInfo{outputs: []regMask{buildReg("DX")}}},
+ //arg0=ptr,arg1=mem, returns void. Faults if ptr is nil.
+ {name: "LoweredNilCheck", argLength: 2, reg: regInfo{inputs: []regMask{gpsp}}, clobberFlags: true, nilCheck: true, faultOnNilArg0: true},
+
+ // MOVLconvert converts between pointers and integers.
+ // We have a special op for this so as to not confuse GC
+ // (particularly stack maps). It takes a memory arg so it
+ // gets correctly ordered with respect to GC safepoints.
+ // arg0=ptr/int arg1=mem, output=int/ptr
+ {name: "MOVLconvert", argLength: 2, reg: gp11, asm: "MOVL"},
+
+ // Constant flag values. For any comparison, there are 5 possible
+ // outcomes: the three from the signed total order (<,==,>) and the
+ // three from the unsigned total order. The == cases overlap.
+ // Note: there's a sixth "unordered" outcome for floating-point
+ // comparisons, but we don't use such a beast yet.
+ // These ops are for temporary use by rewrite rules. They
+ // cannot appear in the generated assembly.
+ {name: "FlagEQ"}, // equal
+ {name: "FlagLT_ULT"}, // signed < and unsigned <
+ {name: "FlagLT_UGT"}, // signed < and unsigned >
+ {name: "FlagGT_UGT"}, // signed > and unsigned <
+ {name: "FlagGT_ULT"}, // signed > and unsigned >
+
+ // Special op for -x on 387
+ {name: "FCHS", argLength: 1, reg: fp11},
+
+ // Special ops for PIC floating-point constants.
+ // MOVSXconst1 loads the address of the constant-pool entry into a register.
+ // MOVSXconst2 loads the constant from that address.
+ // MOVSXconst1 returns a pointer, but we type it as uint32 because it can never point to the Go heap.
+ {name: "MOVSSconst1", reg: gp01, typ: "UInt32", aux: "Float32"},
+ {name: "MOVSDconst1", reg: gp01, typ: "UInt32", aux: "Float64"},
+ {name: "MOVSSconst2", argLength: 1, reg: gpfp, asm: "MOVSS"},
+ {name: "MOVSDconst2", argLength: 1, reg: gpfp, asm: "MOVSD"},
+ }
+
+ var _386blocks = []blockData{
+ {name: "EQ"},
+ {name: "NE"},
+ {name: "LT"},
+ {name: "LE"},
+ {name: "GT"},
+ {name: "GE"},
+ {name: "ULT"},
+ {name: "ULE"},
+ {name: "UGT"},
+ {name: "UGE"},
+ {name: "EQF"},
+ {name: "NEF"},
+ {name: "ORD"}, // FP, ordered comparison (parity zero)
+ {name: "NAN"}, // FP, unordered comparison (parity one)
+ }
+
+ archs = append(archs, arch{
+ name: "386",
+ pkg: "cmd/internal/obj/x86",
+ genfile: "../../x86/ssa.go",
+ ops: _386ops,
+ blocks: _386blocks,
+ regnames: regNames386,
+ gpregmask: gp,
+ fpregmask: fp,
+ framepointerreg: int8(num["BP"]),
+ linkreg: -1, // not used
+ })
+}
diff --git a/src/cmd/compile/internal/ssa/gen/AMD64.rules b/src/cmd/compile/internal/ssa/gen/AMD64.rules
index d27eff0..5b4649c 100644
--- a/src/cmd/compile/internal/ssa/gen/AMD64.rules
+++ b/src/cmd/compile/internal/ssa/gen/AMD64.rules
@@ -4,7 +4,8 @@
// Lowering arithmetic
(Add64 x y) -> (ADDQ x y)
-(AddPtr x y) -> (ADDQ x y)
+(AddPtr x y) && config.PtrSize == 8 -> (ADDQ x y)
+(AddPtr x y) && config.PtrSize == 4 -> (ADDL x y)
(Add32 x y) -> (ADDL x y)
(Add16 x y) -> (ADDL x y)
(Add8 x y) -> (ADDL x y)
@@ -12,7 +13,8 @@
(Add64F x y) -> (ADDSD x y)
(Sub64 x y) -> (SUBQ x y)
-(SubPtr x y) -> (SUBQ x y)
+(SubPtr x y) && config.PtrSize == 8 -> (SUBQ x y)
+(SubPtr x y) && config.PtrSize == 4 -> (SUBL x y)
(Sub32 x y) -> (SUBL x y)
(Sub16 x y) -> (SUBL x y)
(Sub8 x y) -> (SUBL x y)
@@ -29,14 +31,14 @@
(Div32F x y) -> (DIVSS x y)
(Div64F x y) -> (DIVSD x y)
-(Div64 x y) -> (DIVQ x y)
-(Div64u x y) -> (DIVQU x y)
-(Div32 x y) -> (DIVL x y)
-(Div32u x y) -> (DIVLU x y)
-(Div16 x y) -> (DIVW x y)
-(Div16u x y) -> (DIVWU x y)
-(Div8 x y) -> (DIVW (SignExt8to16 x) (SignExt8to16 y))
-(Div8u x y) -> (DIVWU (ZeroExt8to16 x) (ZeroExt8to16 y))
+(Div64 x y) -> (Select0 (DIVQ x y))
+(Div64u x y) -> (Select0 (DIVQU x y))
+(Div32 x y) -> (Select0 (DIVL x y))
+(Div32u x y) -> (Select0 (DIVLU x y))
+(Div16 x y) -> (Select0 (DIVW x y))
+(Div16u x y) -> (Select0 (DIVWU x y))
+(Div8 x y) -> (Select0 (DIVW (SignExt8to16 x) (SignExt8to16 y)))
+(Div8u x y) -> (Select0 (DIVWU (ZeroExt8to16 x) (ZeroExt8to16 y)))
(Hmul64 x y) -> (HMULQ x y)
(Hmul64u x y) -> (HMULQU x y)
@@ -47,16 +49,19 @@
(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)
+
(Avg64u x y) -> (AVGQU x y)
-(Mod64 x y) -> (MODQ x y)
-(Mod64u x y) -> (MODQU x y)
-(Mod32 x y) -> (MODL x y)
-(Mod32u x y) -> (MODLU x y)
-(Mod16 x y) -> (MODW x y)
-(Mod16u x y) -> (MODWU x y)
-(Mod8 x y) -> (MODW (SignExt8to16 x) (SignExt8to16 y))
-(Mod8u x y) -> (MODWU (ZeroExt8to16 x) (ZeroExt8to16 y))
+(Mod64 x y) -> (Select1 (DIVQ x y))
+(Mod64u x y) -> (Select1 (DIVQU x y))
+(Mod32 x y) -> (Select1 (DIVL x y))
+(Mod32u x y) -> (Select1 (DIVLU x y))
+(Mod16 x y) -> (Select1 (DIVW x y))
+(Mod16u x y) -> (Select1 (DIVWU x y))
+(Mod8 x y) -> (Select1 (DIVW (SignExt8to16 x) (SignExt8to16 y)))
+(Mod8u x y) -> (Select1 (DIVWU (ZeroExt8to16 x) (ZeroExt8to16 y)))
(And64 x y) -> (ANDQ x y)
(And32 x y) -> (ANDL x y)
@@ -91,14 +96,13 @@
(Not x) -> (XORLconst [1] x)
// Lowering pointer arithmetic
-(OffPtr [off] ptr) && is32Bit(off) -> (ADDQconst [off] ptr)
-(OffPtr [off] ptr) -> (ADDQ (MOVQconst [off]) ptr)
+(OffPtr [off] ptr) && config.PtrSize == 8 && is32Bit(off) -> (ADDQconst [off] ptr)
+(OffPtr [off] ptr) && config.PtrSize == 8 -> (ADDQ (MOVQconst [off]) ptr)
+(OffPtr [off] ptr) && config.PtrSize == 4 -> (ADDLconst [off] ptr)
// Lowering other arithmetic
-// TODO: CMPQconst 0 below is redundant because BSF sets Z but how to remove?
-(Ctz64 <t> x) -> (CMOVQEQconst (BSFQ <t> x) (CMPQconst x [0]) [64])
-(Ctz32 <t> x) -> (CMOVLEQconst (BSFL <t> x) (CMPLconst x [0]) [32])
-(Ctz16 <t> x) -> (CMOVWEQconst (BSFW <t> x) (CMPWconst x [0]) [16])
+(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)))
(Bswap64 x) -> (BSWAPQ x)
(Bswap32 x) -> (BSWAPL x)
@@ -121,6 +125,8 @@
(ZeroExt16to64 x) -> (MOVWQZX x)
(ZeroExt32to64 x) -> (MOVLQZX x)
+(Slicemask <t> x) -> (XORQconst [-1] (SARQconst <t> (SUBQconst <t> x [1]) [63]))
+
// Lowering truncation
// Because we ignore high parts of registers, truncates are just copies.
(Trunc16to8 x) -> x
@@ -270,7 +276,8 @@
(Eq16 x y) -> (SETEQ (CMPW x y))
(Eq8 x y) -> (SETEQ (CMPB x y))
(EqB x y) -> (SETEQ (CMPB x y))
-(EqPtr x y) -> (SETEQ (CMPQ x y))
+(EqPtr x y) && config.PtrSize == 8 -> (SETEQ (CMPQ x y))
+(EqPtr x y) && config.PtrSize == 4 -> (SETEQ (CMPL x y))
(Eq64F x y) -> (SETEQF (UCOMISD x y))
(Eq32F x y) -> (SETEQF (UCOMISS x y))
@@ -279,13 +286,16 @@
(Neq16 x y) -> (SETNE (CMPW x y))
(Neq8 x y) -> (SETNE (CMPB x y))
(NeqB x y) -> (SETNE (CMPB x y))
-(NeqPtr x y) -> (SETNE (CMPQ x y))
+(NeqPtr x y) && config.PtrSize == 8 -> (SETNE (CMPQ x y))
+(NeqPtr x y) && config.PtrSize == 4 -> (SETNE (CMPL x y))
(Neq64F x y) -> (SETNEF (UCOMISD x y))
(Neq32F x y) -> (SETNEF (UCOMISS x y))
+(Int64Hi x) -> (SHRQconst [32] x) // needed for amd64p32
+
// Lowering loads
-(Load <t> ptr mem) && (is64BitInt(t) || isPtr(t)) -> (MOVQload ptr mem)
-(Load <t> ptr mem) && is32BitInt(t) -> (MOVLload ptr mem)
+(Load <t> ptr mem) && (is64BitInt(t) || isPtr(t) && config.PtrSize == 8) -> (MOVQload ptr mem)
+(Load <t> ptr mem) && (is32BitInt(t) || isPtr(t) && config.PtrSize == 4) -> (MOVLload ptr mem)
(Load <t> ptr mem) && is16BitInt(t) -> (MOVWload ptr mem)
(Load <t> ptr mem) && (t.IsBoolean() || is8BitInt(t)) -> (MOVBload ptr mem)
(Load <t> ptr mem) && is32BitFloat(t) -> (MOVSSload ptr mem)
@@ -302,39 +312,47 @@
(Store [1] ptr val mem) -> (MOVBstore ptr val mem)
// Lowering moves
-(Move [0] _ _ mem) -> mem
-(Move [1] dst src mem) -> (MOVBstore dst (MOVBload src mem) mem)
-(Move [2] dst src mem) -> (MOVWstore dst (MOVWload src mem) mem)
-(Move [4] dst src mem) -> (MOVLstore dst (MOVLload src mem) mem)
-(Move [8] dst src mem) -> (MOVQstore dst (MOVQload src mem) mem)
-(Move [16] dst src mem) -> (MOVOstore dst (MOVOload src mem) mem)
-(Move [3] dst src mem) ->
+(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 ->
(MOVBstore [2] dst (MOVBload [2] src mem)
(MOVWstore dst (MOVWload src mem) mem))
-(Move [5] dst src mem) ->
+(Move [s] dst src mem) && SizeAndAlign(s).Size() == 5 ->
(MOVBstore [4] dst (MOVBload [4] src mem)
(MOVLstore dst (MOVLload src mem) mem))
-(Move [6] dst src mem) ->
+(Move [s] dst src mem) && SizeAndAlign(s).Size() == 6 ->
(MOVWstore [4] dst (MOVWload [4] src mem)
(MOVLstore dst (MOVLload src mem) mem))
-(Move [7] dst src mem) ->
+(Move [s] dst src mem) && SizeAndAlign(s).Size() == 7 ->
(MOVLstore [3] dst (MOVLload [3] src mem)
(MOVLstore dst (MOVLload src mem) mem))
-(Move [size] dst src mem) && size > 8 && size < 16 ->
- (MOVQstore [size-8] dst (MOVQload [size-8] src mem)
+(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)
(MOVQstore dst (MOVQload src mem) mem))
// Adjust moves to be a multiple of 16 bytes.
-(Move [size] dst src mem) && size > 16 && size%16 != 0 && size%16 <= 8 ->
- (Move [size-size%16] (ADDQconst <dst.Type> dst [size%16]) (ADDQconst <src.Type> src [size%16])
+(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])
(MOVQstore dst (MOVQload src mem) mem))
-(Move [size] dst src mem) && size > 16 && size%16 != 0 && size%16 > 8 ->
- (Move [size-size%16] (ADDQconst <dst.Type> dst [size%16]) (ADDQconst <src.Type> src [size%16])
+(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])
(MOVOstore dst (MOVOload src mem) mem))
// Medium copying uses a duff device.
-(Move [size] dst src mem) && size >= 32 && size <= 16*64 && size%16 == 0 && !config.noDuffDevice ->
- (DUFFCOPY [14*(64-size/16)] dst src mem)
+(Move [s] dst src mem)
+ && SizeAndAlign(s).Size() >= 32 && SizeAndAlign(s).Size() <= 16*64 && SizeAndAlign(s).Size()%16 == 0
+ && !config.noDuffDevice ->
+ (DUFFCOPY [14*(64-SizeAndAlign(s).Size()/16)] dst src mem)
// 14 and 64 are magic constants. 14 is the number of bytes to encode:
// MOVUPS (SI), X0
// ADDQ $16, SI
@@ -343,57 +361,62 @@
// and 64 is the number of such blocks. See src/runtime/duff_amd64.s:duffcopy.
// Large copying uses REP MOVSQ.
-(Move [size] dst src mem) && (size > 16*64 || config.noDuffDevice) && size%8 == 0 ->
- (REPMOVSQ dst src (MOVQconst [size/8]) mem)
+(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)
// Lowering Zero instructions
-(Zero [0] _ mem) -> mem
-(Zero [1] destptr mem) -> (MOVBstoreconst [0] destptr mem)
-(Zero [2] destptr mem) -> (MOVWstoreconst [0] destptr mem)
-(Zero [4] destptr mem) -> (MOVLstoreconst [0] destptr mem)
-(Zero [8] destptr mem) -> (MOVQstoreconst [0] destptr mem)
+(Zero [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 [3] destptr mem) ->
+(Zero [s] destptr mem) && SizeAndAlign(s).Size() == 3 ->
(MOVBstoreconst [makeValAndOff(0,2)] destptr
(MOVWstoreconst [0] destptr mem))
-(Zero [5] destptr mem) ->
+(Zero [s] destptr mem) && SizeAndAlign(s).Size() == 5 ->
(MOVBstoreconst [makeValAndOff(0,4)] destptr
(MOVLstoreconst [0] destptr mem))
-(Zero [6] destptr mem) ->
+(Zero [s] destptr mem) && SizeAndAlign(s).Size() == 6 ->
(MOVWstoreconst [makeValAndOff(0,4)] destptr
(MOVLstoreconst [0] destptr mem))
-(Zero [7] destptr mem) ->
+(Zero [s] destptr mem) && SizeAndAlign(s).Size() == 7 ->
(MOVLstoreconst [makeValAndOff(0,3)] destptr
(MOVLstoreconst [0] destptr mem))
// Strip off any fractional word zeroing.
-(Zero [size] destptr mem) && size%8 != 0 && size > 8 ->
- (Zero [size-size%8] (ADDQconst destptr [size%8])
+(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])
(MOVQstoreconst [0] destptr mem))
// Zero small numbers of words directly.
-(Zero [16] destptr mem) ->
+(Zero [s] destptr mem) && SizeAndAlign(s).Size() == 16 ->
(MOVQstoreconst [makeValAndOff(0,8)] destptr
(MOVQstoreconst [0] destptr mem))
-(Zero [24] destptr mem) ->
+(Zero [s] destptr mem) && SizeAndAlign(s).Size() == 24 ->
(MOVQstoreconst [makeValAndOff(0,16)] destptr
(MOVQstoreconst [makeValAndOff(0,8)] destptr
(MOVQstoreconst [0] destptr mem)))
-(Zero [32] destptr mem) ->
+(Zero [s] destptr mem) && SizeAndAlign(s).Size() == 32 ->
(MOVQstoreconst [makeValAndOff(0,24)] destptr
(MOVQstoreconst [makeValAndOff(0,16)] destptr
(MOVQstoreconst [makeValAndOff(0,8)] destptr
(MOVQstoreconst [0] destptr mem))))
// Medium zeroing uses a duff device.
-(Zero [size] destptr mem) && size <= 1024 && size%8 == 0 && size%16 != 0 && !config.noDuffDevice ->
- (Zero [size-8] (ADDQconst [8] destptr) (MOVQstore destptr (MOVQconst [0]) mem))
-(Zero [size] destptr mem) && size <= 1024 && size%16 == 0 && !config.noDuffDevice ->
- (DUFFZERO [size] destptr (MOVOconst [0]) mem)
+(Zero [s] destptr mem)
+ && SizeAndAlign(s).Size() <= 1024 && SizeAndAlign(s).Size()%8 == 0 && SizeAndAlign(s).Size()%16 != 0
+ && !config.noDuffDevice ->
+ (Zero [SizeAndAlign(s).Size()-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)
// Large zeroing uses REP STOSQ.
-(Zero [size] destptr mem) && (size > 1024 || (config.noDuffDevice && size > 32)) && size%8 == 0 ->
- (REPSTOSQ destptr (MOVQconst [size/8]) (MOVQconst [0]) mem)
+(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)
// Lowering constants
(Const8 [val]) -> (MOVLconst [val])
@@ -402,7 +425,8 @@
(Const64 [val]) -> (MOVQconst [val])
(Const32F [val]) -> (MOVSSconst [val])
(Const64F [val]) -> (MOVSDconst [val])
-(ConstNil) -> (MOVQconst [0])
+(ConstNil) && config.PtrSize == 8 -> (MOVQconst [0])
+(ConstNil) && config.PtrSize == 4 -> (MOVLconst [0])
(ConstBool [b]) -> (MOVLconst [b])
// Lowering calls
@@ -413,15 +437,17 @@
(InterCall [argwid] entry mem) -> (CALLinter [argwid] entry mem)
// Miscellaneous
-(Convert <t> x mem) -> (MOVQconvert <t> x mem)
-(IsNonNil p) -> (SETNE (TESTQ p p))
+(Convert <t> x mem) && config.PtrSize == 8 -> (MOVQconvert <t> x mem)
+(Convert <t> x mem) && config.PtrSize == 4 -> (MOVLconvert <t> x mem)
+(IsNonNil p) && config.PtrSize == 8 -> (SETNE (TESTQ p p))
+(IsNonNil p) && config.PtrSize == 4 -> (SETNE (TESTL p p))
(IsInBounds idx len) -> (SETB (CMPQ idx len))
(IsSliceInBounds idx len) -> (SETBE (CMPQ idx len))
(NilCheck ptr mem) -> (LoweredNilCheck ptr mem)
(GetG mem) -> (LoweredGetG mem)
(GetClosurePtr) -> (LoweredGetClosurePtr)
-(Addr {sym} base) -> (LEAQ {sym} base)
-(ITab (Load ptr mem)) -> (MOVQload ptr mem)
+(Addr {sym} base) && config.PtrSize == 8 -> (LEAQ {sym} base)
+(Addr {sym} base) && config.PtrSize == 4 -> (LEAL {sym} base)
// block rewrites
(If (SETL cmp) yes no) -> (LT cmp yes no)
@@ -443,6 +469,39 @@
(If cond yes no) -> (NE (TESTB cond cond) yes no)
+// Atomic loads. Other than preserving their ordering with respect to other loads, nothing special here.
+(AtomicLoad32 ptr mem) -> (MOVLatomicload ptr mem)
+(AtomicLoad64 ptr mem) -> (MOVQatomicload ptr mem)
+(AtomicLoadPtr ptr mem) && config.PtrSize == 8 -> (MOVQatomicload ptr mem)
+(AtomicLoadPtr ptr mem) && config.PtrSize == 4 -> (MOVLatomicload ptr mem)
+
+// 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))
+
+// 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)
+
+// Atomic compare and swap.
+(AtomicCompareAndSwap32 ptr old new_ mem) -> (CMPXCHGLlock ptr old new_ mem)
+(AtomicCompareAndSwap64 ptr old new_ mem) -> (CMPXCHGQlock ptr old new_ mem)
+
+// Atomic memory updates.
+(AtomicAnd8 ptr val mem) -> (ANDBlock ptr val mem)
+(AtomicOr8 ptr val mem) -> (ORBlock ptr val mem)
+
// ***************************
// Above: lowering rules
// Below: optimizations
@@ -495,6 +554,12 @@
(ANDLconst [c] (ANDLconst [d] x)) -> (ANDLconst [c & d] x)
(ANDQconst [c] (ANDQconst [d] x)) -> (ANDQconst [c & d] x)
+(XORLconst [c] (XORLconst [d] x)) -> (XORLconst [c ^ d] x)
+(XORQconst [c] (XORQconst [d] x)) -> (XORQconst [c ^ d] x)
+
+(MULLconst [c] (MULLconst [d] x)) -> (MULLconst [int64(int32(c * d))] x)
+(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)
@@ -544,6 +609,16 @@
(SHRL x (ANDLconst [31] y)) -> (SHRL x y)
(SHRQ x (ANDQconst [63] y)) -> (SHRQ x y)
+(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
+
// Note: the word and byte shifts keep the low 5 bits (not the low 4 or 3 bits)
// because the x86 instructions are defined to use all 5 bits of the shift even
// for the small shifts. I don't think we'll ever generate a weird shift (e.g.
@@ -558,7 +633,9 @@
(CMPB x (MOVLconst [c])) -> (CMPBconst x [int64(int8(c))])
(CMPB (MOVLconst [c]) x) -> (InvertFlags (CMPBconst x [int64(int8(c))]))
-// Using MOVBQZX instead of ANDQ is cheaper.
+// Using MOVZX instead of AND is cheaper.
+(ANDLconst [0xFF] x) -> (MOVBQZX x)
+(ANDLconst [0xFFFF] x) -> (MOVWQZX x)
(ANDQconst [0xFF] x) -> (MOVBQZX x)
(ANDQconst [0xFFFF] x) -> (MOVWQZX x)
(ANDQconst [0xFFFFFFFF] x) -> (MOVLQZX x)
@@ -661,11 +738,23 @@
// This prevents a single load from being split into multiple loads
// which then might return different values. See test/atomicload.go.
(MOVBQSX x:(MOVBload [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVBQSXload <v.Type> [off] {sym} ptr mem)
+(MOVBQSX x:(MOVWload [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVBQSXload <v.Type> [off] {sym} ptr mem)
+(MOVBQSX x:(MOVLload [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVBQSXload <v.Type> [off] {sym} ptr mem)
+(MOVBQSX x:(MOVQload [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVBQSXload <v.Type> [off] {sym} ptr mem)
(MOVBQZX x:(MOVBload [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVBload <v.Type> [off] {sym} ptr mem)
+(MOVBQZX x:(MOVWload [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVBload <v.Type> [off] {sym} ptr mem)
+(MOVBQZX x:(MOVLload [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVBload <v.Type> [off] {sym} ptr mem)
+(MOVBQZX x:(MOVQload [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVBload <v.Type> [off] {sym} ptr mem)
(MOVWQSX x:(MOVWload [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVWQSXload <v.Type> [off] {sym} ptr mem)
+(MOVWQSX x:(MOVLload [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVWQSXload <v.Type> [off] {sym} ptr mem)
+(MOVWQSX x:(MOVQload [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVWQSXload <v.Type> [off] {sym} ptr mem)
(MOVWQZX x:(MOVWload [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVWload <v.Type> [off] {sym} ptr mem)
+(MOVWQZX x:(MOVLload [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVWload <v.Type> [off] {sym} ptr mem)
+(MOVWQZX x:(MOVQload [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVWload <v.Type> [off] {sym} ptr mem)
(MOVLQSX x:(MOVLload [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVLQSXload <v.Type> [off] {sym} ptr mem)
+(MOVLQSX x:(MOVQload [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVLQSXload <v.Type> [off] {sym} ptr mem)
(MOVLQZX x:(MOVLload [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVLload <v.Type> [off] {sym} ptr mem)
+(MOVLQZX x:(MOVQload [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVLload <v.Type> [off] {sym} ptr mem)
(MOVBQZX x:(MOVBloadidx1 [off] {sym} ptr idx mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVBloadidx1 <v.Type> [off] {sym} ptr idx mem)
(MOVWQZX x:(MOVWloadidx1 [off] {sym} ptr idx mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVWloadidx1 <v.Type> [off] {sym} ptr idx mem)
@@ -868,9 +957,13 @@
(MOVWloadidx1 [c] {sym} ptr (SHLQconst [1] idx) mem) -> (MOVWloadidx2 [c] {sym} ptr idx mem)
(MOVLloadidx1 [c] {sym} ptr (SHLQconst [2] idx) mem) -> (MOVLloadidx4 [c] {sym} ptr idx mem)
(MOVQloadidx1 [c] {sym} ptr (SHLQconst [3] idx) mem) -> (MOVQloadidx8 [c] {sym} ptr idx mem)
+(MOVSSloadidx1 [c] {sym} ptr (SHLQconst [2] idx) mem) -> (MOVSSloadidx4 [c] {sym} ptr idx mem)
+(MOVSDloadidx1 [c] {sym} ptr (SHLQconst [3] idx) mem) -> (MOVSDloadidx8 [c] {sym} ptr idx mem)
(MOVWstoreidx1 [c] {sym} ptr (SHLQconst [1] idx) val mem) -> (MOVWstoreidx2 [c] {sym} ptr idx val mem)
(MOVLstoreidx1 [c] {sym} ptr (SHLQconst [2] idx) val mem) -> (MOVLstoreidx4 [c] {sym} ptr idx val mem)
(MOVQstoreidx1 [c] {sym} ptr (SHLQconst [3] idx) val mem) -> (MOVQstoreidx8 [c] {sym} ptr idx val mem)
+(MOVSSstoreidx1 [c] {sym} ptr (SHLQconst [2] idx) val mem) -> (MOVSSstoreidx4 [c] {sym} ptr idx val mem)
+(MOVSDstoreidx1 [c] {sym} ptr (SHLQconst [3] idx) val mem) -> (MOVSDstoreidx8 [c] {sym} ptr idx val mem)
(MOVWstoreconstidx1 [c] {sym} ptr (SHLQconst [1] idx) mem) -> (MOVWstoreconstidx2 [c] {sym} ptr idx mem)
(MOVLstoreconstidx1 [c] {sym} ptr (SHLQconst [2] idx) mem) -> (MOVLstoreconstidx4 [c] {sym} ptr idx mem)
(MOVQstoreconstidx1 [c] {sym} ptr (SHLQconst [3] idx) mem) -> (MOVQstoreconstidx8 [c] {sym} ptr idx mem)
@@ -1243,31 +1336,6 @@
(CMPWconst x [0]) -> (TESTW x x)
(CMPBconst x [0]) -> (TESTB x x)
-// Optimizing conditional moves
-(CMOVQEQconst x (InvertFlags y) [c]) -> (CMOVQNEconst x y [c])
-(CMOVLEQconst x (InvertFlags y) [c]) -> (CMOVLNEconst x y [c])
-(CMOVWEQconst x (InvertFlags y) [c]) -> (CMOVWNEconst x y [c])
-
-(CMOVQEQconst _ (FlagEQ) [c]) -> (Const64 [c])
-(CMOVLEQconst _ (FlagEQ) [c]) -> (Const32 [c])
-(CMOVWEQconst _ (FlagEQ) [c]) -> (Const16 [c])
-
-(CMOVQEQconst x (FlagLT_ULT)) -> x
-(CMOVLEQconst x (FlagLT_ULT)) -> x
-(CMOVWEQconst x (FlagLT_ULT)) -> x
-
-(CMOVQEQconst x (FlagLT_UGT)) -> x
-(CMOVLEQconst x (FlagLT_UGT)) -> x
-(CMOVWEQconst x (FlagLT_UGT)) -> x
-
-(CMOVQEQconst x (FlagGT_ULT)) -> x
-(CMOVLEQconst x (FlagGT_ULT)) -> x
-(CMOVWEQconst x (FlagGT_ULT)) -> x
-
-(CMOVQEQconst x (FlagGT_UGT)) -> x
-(CMOVLEQconst x (FlagGT_UGT)) -> x
-(CMOVWEQconst x (FlagGT_UGT)) -> x
-
// Combining byte loads into larger (unaligned) loads.
// There are many ways these combinations could occur. This is
// designed to match the way encoding/binary.LittleEndian does it.
@@ -1282,31 +1350,24 @@
&& clobber(s0)
-> @mergePoint(b,x0,x1) (MOVWload [i] {s} p mem)
-(ORL o0:(ORL o1:(ORL
- x0:(MOVBload [i] {s} p mem)
- s0:(SHLLconst [8] x1:(MOVBload [i+1] {s} p mem)))
- s1:(SHLLconst [16] x2:(MOVBload [i+2] {s} p mem)))
- s2:(SHLLconst [24] x3:(MOVBload [i+3] {s} p mem)))
+(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.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
+ && mergePoint(b,x0,x1,x2) != nil
&& clobber(x0)
&& clobber(x1)
&& clobber(x2)
- && clobber(x3)
&& clobber(s0)
&& clobber(s1)
- && clobber(s2)
&& clobber(o0)
- && clobber(o1)
- -> @mergePoint(b,x0,x1,x2,x3) (MOVLload [i] {s} p mem)
+ -> @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)
@@ -1373,31 +1434,24 @@
&& clobber(s0)
-> @mergePoint(b,x0,x1) (MOVWloadidx1 <v.Type> [i] {s} p idx mem)
-(ORL o0:(ORL o1:(ORL
- x0:(MOVBloadidx1 [i] {s} p idx mem)
- s0:(SHLLconst [8] x1:(MOVBloadidx1 [i+1] {s} p idx mem)))
- s1:(SHLLconst [16] x2:(MOVBloadidx1 [i+2] {s} p idx mem)))
- s2:(SHLLconst [24] x3:(MOVBloadidx1 [i+3] {s} p idx mem)))
+(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.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
+ && mergePoint(b,x0,x1,x2) != nil
&& clobber(x0)
&& clobber(x1)
&& clobber(x2)
- && clobber(x3)
&& clobber(s0)
&& clobber(s1)
- && clobber(s2)
&& clobber(o0)
- && clobber(o1)
- -> @mergePoint(b,x0,x1,x2,x3) (MOVLloadidx1 <v.Type> [i] {s} p idx mem)
+ -> @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)
@@ -1453,6 +1507,204 @@
&& 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)))
+ && x0.Uses == 1
+ && x1.Uses == 1
+ && x2.Uses == 1
+ && x3.Uses == 1
+ && s0.Uses == 1
+ && s1.Uses == 1
+ && s2.Uses == 1
+ && o0.Uses == 1
+ && o1.Uses == 1
+ && mergePoint(b,x0,x1,x2,x3) != nil
+ && clobber(x0)
+ && clobber(x1)
+ && clobber(x2)
+ && clobber(x3)
+ && clobber(s0)
+ && clobber(s1)
+ && clobber(s2)
+ && clobber(o0)
+ && clobber(o1)
+ -> @mergePoint(b,x0,x1,x2,x3) (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)))
+ && x0.Uses == 1
+ && x1.Uses == 1
+ && x2.Uses == 1
+ && x3.Uses == 1
+ && s0.Uses == 1
+ && s1.Uses == 1
+ && s2.Uses == 1
+ && o0.Uses == 1
+ && o1.Uses == 1
+ && mergePoint(b,x0,x1,x2,x3) != nil
+ && clobber(x0)
+ && clobber(x1)
+ && clobber(x2)
+ && clobber(x3)
+ && clobber(s0)
+ && clobber(s1)
+ && clobber(s2)
+ && clobber(o0)
+ && clobber(o1)
+ -> @mergePoint(b,x0,x1,x2,x3) (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)))
+ && x0.Uses == 1
+ && x1.Uses == 1
+ && x2.Uses == 1
+ && x3.Uses == 1
+ && x4.Uses == 1
+ && x5.Uses == 1
+ && x6.Uses == 1
+ && x7.Uses == 1
+ && s0.Uses == 1
+ && s1.Uses == 1
+ && s2.Uses == 1
+ && s3.Uses == 1
+ && s4.Uses == 1
+ && s5.Uses == 1
+ && s6.Uses == 1
+ && o0.Uses == 1
+ && o1.Uses == 1
+ && o2.Uses == 1
+ && o3.Uses == 1
+ && o4.Uses == 1
+ && o5.Uses == 1
+ && mergePoint(b,x0,x1,x2,x3,x4,x5,x6,x7) != nil
+ && clobber(x0)
+ && clobber(x1)
+ && clobber(x2)
+ && clobber(x3)
+ && clobber(x4)
+ && clobber(x5)
+ && clobber(x6)
+ && clobber(x7)
+ && clobber(s0)
+ && clobber(s1)
+ && clobber(s2)
+ && clobber(s3)
+ && clobber(s4)
+ && clobber(s5)
+ && clobber(s6)
+ && clobber(o0)
+ && clobber(o1)
+ && clobber(o2)
+ && clobber(o3)
+ && clobber(o4)
+ && clobber(o5)
+ -> @mergePoint(b,x0,x1,x2,x3,x4,x5,x6,x7) (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)))
+ && x0.Uses == 1
+ && x1.Uses == 1
+ && x2.Uses == 1
+ && x3.Uses == 1
+ && x4.Uses == 1
+ && x5.Uses == 1
+ && x6.Uses == 1
+ && x7.Uses == 1
+ && s0.Uses == 1
+ && s1.Uses == 1
+ && s2.Uses == 1
+ && s3.Uses == 1
+ && s4.Uses == 1
+ && s5.Uses == 1
+ && s6.Uses == 1
+ && o0.Uses == 1
+ && o1.Uses == 1
+ && o2.Uses == 1
+ && o3.Uses == 1
+ && o4.Uses == 1
+ && o5.Uses == 1
+ && mergePoint(b,x0,x1,x2,x3,x4,x5,x6,x7) != nil
+ && clobber(x0)
+ && clobber(x1)
+ && clobber(x2)
+ && clobber(x3)
+ && clobber(x4)
+ && clobber(x5)
+ && clobber(x6)
+ && clobber(x7)
+ && clobber(s0)
+ && clobber(s1)
+ && clobber(s2)
+ && clobber(s3)
+ && clobber(s4)
+ && clobber(s5)
+ && clobber(s6)
+ && clobber(o0)
+ && clobber(o1)
+ && clobber(o2)
+ && clobber(o3)
+ && clobber(o4)
+ && clobber(o5)
+ -> @mergePoint(b,x0,x1,x2,x3,x4,x5,x6,x7) (BSWAPQ <v.Type> (MOVQloadidx1 <v.Type> [i-7] {s} p idx mem))
+
+// Combine stores + shifts into bswap and larger (unaligned) stores
+(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))))
+ && x0.Uses == 1
+ && x1.Uses == 1
+ && x2.Uses == 1
+ && clobber(x0)
+ && clobber(x1)
+ && clobber(x2)
+ -> (MOVLstore [i-3] {s} p (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)
+ 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))))))))
+ && 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)
+ -> (MOVQstore [i-7] {s} p (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
@@ -1564,3 +1816,87 @@
&& x.Uses == 1
&& clobber(x)
-> (MOVQstoreidx1 [i-4] {s} p (SHLQconst <idx.Type> [2] idx) w0 mem)
+
+// amd64p32 rules
+// same as the rules above, but with 32 instead of 64 bit pointer arithmetic.
+// LEAQ,ADDQ -> LEAL,ADDL
+(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)
+
+(MOVQload [off1] {sym1} (LEAL [off2] {sym2} base) mem) && canMergeSym(sym1, sym2) ->
+ (MOVQload [off1+off2] {mergeSym(sym1,sym2)} base mem)
+(MOVLload [off1] {sym1} (LEAL [off2] {sym2} base) mem) && canMergeSym(sym1, sym2) ->
+ (MOVLload [off1+off2] {mergeSym(sym1,sym2)} base mem)
+(MOVWload [off1] {sym1} (LEAL [off2] {sym2} base) mem) && canMergeSym(sym1, sym2) ->
+ (MOVWload [off1+off2] {mergeSym(sym1,sym2)} base mem)
+(MOVBload [off1] {sym1} (LEAL [off2] {sym2} base) mem) && canMergeSym(sym1, sym2) ->
+ (MOVBload [off1+off2] {mergeSym(sym1,sym2)} base mem)
+
+(MOVQstore [off1] {sym1} (LEAL [off2] {sym2} base) val mem) && canMergeSym(sym1, sym2) ->
+ (MOVQstore [off1+off2] {mergeSym(sym1,sym2)} base val mem)
+(MOVLstore [off1] {sym1} (LEAL [off2] {sym2} base) val mem) && canMergeSym(sym1, sym2) ->
+ (MOVLstore [off1+off2] {mergeSym(sym1,sym2)} base val mem)
+(MOVWstore [off1] {sym1} (LEAL [off2] {sym2} base) val mem) && canMergeSym(sym1, sym2) ->
+ (MOVWstore [off1+off2] {mergeSym(sym1,sym2)} base val mem)
+(MOVBstore [off1] {sym1} (LEAL [off2] {sym2} base) val mem) && canMergeSym(sym1, sym2) ->
+ (MOVBstore [off1+off2] {mergeSym(sym1,sym2)} base val mem)
+
+(MOVQstoreconst [sc] {sym1} (LEAL [off] {sym2} ptr) mem) && canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd(off) ->
+ (MOVQstoreconst [ValAndOff(sc).add(off)] {mergeSym(sym1, sym2)} ptr mem)
+(MOVLstoreconst [sc] {sym1} (LEAL [off] {sym2} ptr) mem) && canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd(off) ->
+ (MOVLstoreconst [ValAndOff(sc).add(off)] {mergeSym(sym1, sym2)} ptr mem)
+(MOVWstoreconst [sc] {sym1} (LEAL [off] {sym2} ptr) mem) && canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd(off) ->
+ (MOVWstoreconst [ValAndOff(sc).add(off)] {mergeSym(sym1, sym2)} ptr mem)
+(MOVBstoreconst [sc] {sym1} (LEAL [off] {sym2} ptr) mem) && canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd(off) ->
+ (MOVBstoreconst [ValAndOff(sc).add(off)] {mergeSym(sym1, sym2)} ptr mem)
+
+(MOVQload [off1] {sym} (ADDLconst [off2] ptr) mem) && is32Bit(off1+off2) -> (MOVQload [off1+off2] {sym} ptr mem)
+(MOVLload [off1] {sym} (ADDLconst [off2] ptr) mem) && is32Bit(off1+off2) -> (MOVLload [off1+off2] {sym} ptr mem)
+(MOVWload [off1] {sym} (ADDLconst [off2] ptr) mem) && is32Bit(off1+off2) -> (MOVWload [off1+off2] {sym} ptr mem)
+(MOVBload [off1] {sym} (ADDLconst [off2] ptr) mem) && is32Bit(off1+off2) -> (MOVBload [off1+off2] {sym} ptr mem)
+(MOVQstore [off1] {sym} (ADDLconst [off2] ptr) val mem) && is32Bit(off1+off2) -> (MOVQstore [off1+off2] {sym} ptr val mem)
+(MOVLstore [off1] {sym} (ADDLconst [off2] ptr) val mem) && is32Bit(off1+off2) -> (MOVLstore [off1+off2] {sym} ptr val mem)
+(MOVWstore [off1] {sym} (ADDLconst [off2] ptr) val mem) && is32Bit(off1+off2) -> (MOVWstore [off1+off2] {sym} ptr val mem)
+(MOVBstore [off1] {sym} (ADDLconst [off2] ptr) val mem) && is32Bit(off1+off2) -> (MOVBstore [off1+off2] {sym} ptr val mem)
+(MOVQstoreconst [sc] {s} (ADDLconst [off] ptr) mem) && ValAndOff(sc).canAdd(off) ->
+ (MOVQstoreconst [ValAndOff(sc).add(off)] {s} ptr mem)
+(MOVLstoreconst [sc] {s} (ADDLconst [off] ptr) mem) && ValAndOff(sc).canAdd(off) ->
+ (MOVLstoreconst [ValAndOff(sc).add(off)] {s} ptr mem)
+(MOVWstoreconst [sc] {s} (ADDLconst [off] ptr) mem) && ValAndOff(sc).canAdd(off) ->
+ (MOVWstoreconst [ValAndOff(sc).add(off)] {s} ptr mem)
+(MOVBstoreconst [sc] {s} (ADDLconst [off] ptr) mem) && ValAndOff(sc).canAdd(off) ->
+ (MOVBstoreconst [ValAndOff(sc).add(off)] {s} 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)
+(MOVLatomicload [off1] {sym} (ADDQconst [off2] ptr) mem) && is32Bit(off1+off2) ->
+ (MOVLatomicload [off1+off2] {sym} ptr mem)
+(MOVQatomicload [off1] {sym1} (LEAQ [off2] {sym2} ptr) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
+ (MOVQatomicload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
+(MOVLatomicload [off1] {sym1} (LEAQ [off2] {sym2} ptr) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
+ (MOVLatomicload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
+
+// Merge ADDQconst and LEAQ into atomic stores.
+(XCHGQ [off1] {sym} val (ADDQconst [off2] ptr) mem) && is32Bit(off1+off2) ->
+ (XCHGQ [off1+off2] {sym} val ptr mem)
+(XCHGQ [off1] {sym1} val (LEAQ [off2] {sym2} ptr) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) && ptr.Op != OpSB ->
+ (XCHGQ [off1+off2] {mergeSym(sym1,sym2)} val ptr mem)
+(XCHGL [off1] {sym} val (ADDQconst [off2] ptr) mem) && is32Bit(off1+off2) ->
+ (XCHGL [off1+off2] {sym} val ptr mem)
+(XCHGL [off1] {sym1} val (LEAQ [off2] {sym2} ptr) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) && ptr.Op != OpSB ->
+ (XCHGL [off1+off2] {mergeSym(sym1,sym2)} val ptr mem)
+
+// Merge ADDQconst into atomic adds.
+// TODO: merging LEAQ doesn't work, assembler doesn't like the resulting instructions.
+(XADDQlock [off1] {sym} val (ADDQconst [off2] ptr) mem) && is32Bit(off1+off2) ->
+ (XADDQlock [off1+off2] {sym} val ptr mem)
+(XADDLlock [off1] {sym} val (ADDQconst [off2] ptr) mem) && is32Bit(off1+off2) ->
+ (XADDLlock [off1+off2] {sym} val ptr mem)
+
+// Merge ADDQconst into atomic compare and swaps.
+// TODO: merging LEAQ doesn't work, assembler doesn't like the resulting instructions.
+(CMPXCHGQlock [off1] {sym} (ADDQconst [off2] ptr) old new_ mem) && is32Bit(off1+off2) ->
+ (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)
diff --git a/src/cmd/compile/internal/ssa/gen/AMD64Ops.go b/src/cmd/compile/internal/ssa/gen/AMD64Ops.go
index 43cc0eb..5a293d1 100644
--- a/src/cmd/compile/internal/ssa/gen/AMD64Ops.go
+++ b/src/cmd/compile/internal/ssa/gen/AMD64Ops.go
@@ -64,7 +64,6 @@ var regNamesAMD64 = []string{
// pseudo-registers
"SB",
- "FLAGS",
}
func init() {
@@ -93,48 +92,39 @@ func init() {
ax = buildReg("AX")
cx = buildReg("CX")
dx = buildReg("DX")
- x15 = buildReg("X15")
gp = buildReg("AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15")
fp = buildReg("X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15")
gpsp = gp | buildReg("SP")
gpspsb = gpsp | buildReg("SB")
- flags = buildReg("FLAGS")
- callerSave = gp | fp | flags
+ callerSave = gp | fp
)
// Common slices of register masks
var (
- gponly = []regMask{gp}
- fponly = []regMask{fp}
- flagsonly = []regMask{flags}
+ gponly = []regMask{gp}
+ fponly = []regMask{fp}
)
// Common regInfo
var (
- gp01 = regInfo{inputs: []regMask{}, outputs: gponly}
- gp11 = regInfo{inputs: []regMask{gp}, outputs: gponly, clobbers: flags}
- gp11sp = regInfo{inputs: []regMask{gpsp}, outputs: gponly, clobbers: flags}
- gp11nf = regInfo{inputs: []regMask{gpsp}, outputs: gponly} // nf: no flags clobbered
+ gp01 = regInfo{inputs: nil, outputs: gponly}
+ gp11 = regInfo{inputs: []regMask{gp}, outputs: gponly}
+ gp11sp = regInfo{inputs: []regMask{gpsp}, outputs: gponly}
gp11sb = regInfo{inputs: []regMask{gpspsb}, outputs: gponly}
- gp21 = regInfo{inputs: []regMask{gp, gp}, outputs: gponly, clobbers: flags}
- gp21sp = regInfo{inputs: []regMask{gpsp, gp}, outputs: gponly, clobbers: flags}
+ gp21 = regInfo{inputs: []regMask{gp, gp}, outputs: gponly}
+ gp21sp = regInfo{inputs: []regMask{gpsp, gp}, outputs: gponly}
gp21sb = regInfo{inputs: []regMask{gpspsb, gpsp}, outputs: gponly}
- gp21shift = regInfo{inputs: []regMask{gp, cx}, outputs: []regMask{gp}, clobbers: flags}
- gp11div = regInfo{inputs: []regMask{ax, gpsp &^ dx}, outputs: []regMask{ax},
- clobbers: dx | flags}
- gp11hmul = regInfo{inputs: []regMask{ax, gpsp}, outputs: []regMask{dx},
- clobbers: ax | flags}
- gp11mod = regInfo{inputs: []regMask{ax, gpsp &^ dx}, outputs: []regMask{dx},
- clobbers: ax | flags}
+ gp21shift = regInfo{inputs: []regMask{gp, cx}, outputs: []regMask{gp}}
+ gp11div = regInfo{inputs: []regMask{ax, gpsp &^ dx}, outputs: []regMask{ax, dx}}
+ gp21hmul = regInfo{inputs: []regMask{ax, gpsp}, outputs: []regMask{dx}, clobbers: ax}
- gp2flags = regInfo{inputs: []regMask{gpsp, gpsp}, outputs: flagsonly}
- gp1flags = regInfo{inputs: []regMask{gpsp}, outputs: flagsonly}
- flagsgp = regInfo{inputs: flagsonly, outputs: gponly}
+ gp2flags = regInfo{inputs: []regMask{gpsp, gpsp}}
+ gp1flags = regInfo{inputs: []regMask{gpsp}}
+ flagsgp = regInfo{inputs: nil, outputs: gponly}
- // for CMOVconst -- uses AX to hold constant temporary.
- gp1flagsgp = regInfo{inputs: []regMask{gp &^ ax, flags}, clobbers: ax | flags, outputs: []regMask{gp &^ ax}}
+ gp11flags = regInfo{inputs: []regMask{gp}, outputs: []regMask{gp, 0}}
- readflags = regInfo{inputs: flagsonly, outputs: gponly}
- flagsgpax = regInfo{inputs: flagsonly, clobbers: ax | flags, outputs: []regMask{gp &^ ax}}
+ readflags = regInfo{inputs: nil, outputs: gponly}
+ flagsgpax = regInfo{inputs: nil, clobbers: ax, outputs: []regMask{gp &^ ax}}
gpload = regInfo{inputs: []regMask{gpspsb, 0}, outputs: gponly}
gploadidx = regInfo{inputs: []regMask{gpspsb, gpsp, 0}, outputs: gponly}
@@ -143,15 +133,15 @@ func init() {
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}}
+ cmpxchg = regInfo{inputs: []regMask{gp, ax, gp, 0}, outputs: []regMask{gp, 0}, clobbers: ax}
- fp01 = regInfo{inputs: []regMask{}, outputs: fponly}
- fp21 = regInfo{inputs: []regMask{fp, fp}, outputs: fponly}
- fp21x15 = regInfo{inputs: []regMask{fp &^ x15, fp &^ x15},
- clobbers: x15, outputs: []regMask{fp &^ x15}}
+ fp01 = regInfo{inputs: nil, outputs: fponly}
+ fp21 = regInfo{inputs: []regMask{fp, fp}, outputs: fponly}
fpgp = regInfo{inputs: fponly, outputs: gponly}
gpfp = regInfo{inputs: gponly, outputs: fponly}
fp11 = regInfo{inputs: fponly, outputs: fponly}
- fp2flags = regInfo{inputs: []regMask{fp, fp}, outputs: flagsonly}
+ fp2flags = regInfo{inputs: []regMask{fp, fp}}
fpload = regInfo{inputs: []regMask{gpspsb, 0}, outputs: fponly}
fploadidx = regInfo{inputs: []regMask{gpspsb, gpsp, 0}, outputs: fponly}
@@ -164,84 +154,80 @@ func init() {
// fp ops
{name: "ADDSS", argLength: 2, reg: fp21, asm: "ADDSS", commutative: true, resultInArg0: true}, // fp32 add
{name: "ADDSD", argLength: 2, reg: fp21, asm: "ADDSD", commutative: true, resultInArg0: true}, // fp64 add
- {name: "SUBSS", argLength: 2, reg: fp21x15, asm: "SUBSS", resultInArg0: true}, // fp32 sub
- {name: "SUBSD", argLength: 2, reg: fp21x15, asm: "SUBSD", resultInArg0: true}, // fp64 sub
+ {name: "SUBSS", argLength: 2, reg: fp21, asm: "SUBSS", resultInArg0: true}, // fp32 sub
+ {name: "SUBSD", argLength: 2, reg: fp21, asm: "SUBSD", resultInArg0: true}, // fp64 sub
{name: "MULSS", argLength: 2, reg: fp21, asm: "MULSS", commutative: true, resultInArg0: true}, // fp32 mul
{name: "MULSD", argLength: 2, reg: fp21, asm: "MULSD", commutative: true, resultInArg0: true}, // fp64 mul
- {name: "DIVSS", argLength: 2, reg: fp21x15, asm: "DIVSS", resultInArg0: true}, // fp32 div
- {name: "DIVSD", argLength: 2, reg: fp21x15, asm: "DIVSD", resultInArg0: true}, // fp64 div
-
- {name: "MOVSSload", argLength: 2, reg: fpload, asm: "MOVSS", aux: "SymOff"}, // fp32 load
- {name: "MOVSDload", argLength: 2, reg: fpload, asm: "MOVSD", aux: "SymOff"}, // fp64 load
- {name: "MOVSSconst", reg: fp01, asm: "MOVSS", aux: "Float32", rematerializeable: true}, // fp32 constant
- {name: "MOVSDconst", reg: fp01, asm: "MOVSD", aux: "Float64", rematerializeable: true}, // fp64 constant
- {name: "MOVSSloadidx1", argLength: 3, reg: fploadidx, asm: "MOVSS", aux: "SymOff"}, // fp32 load indexed by i
- {name: "MOVSSloadidx4", argLength: 3, reg: fploadidx, asm: "MOVSS", aux: "SymOff"}, // fp32 load indexed by 4*i
- {name: "MOVSDloadidx1", argLength: 3, reg: fploadidx, asm: "MOVSD", aux: "SymOff"}, // fp64 load indexed by i
- {name: "MOVSDloadidx8", argLength: 3, reg: fploadidx, asm: "MOVSD", aux: "SymOff"}, // fp64 load indexed by 8*i
-
- {name: "MOVSSstore", argLength: 3, reg: fpstore, asm: "MOVSS", aux: "SymOff"}, // fp32 store
- {name: "MOVSDstore", argLength: 3, reg: fpstore, asm: "MOVSD", aux: "SymOff"}, // fp64 store
- {name: "MOVSSstoreidx1", argLength: 4, reg: fpstoreidx, asm: "MOVSS", aux: "SymOff"}, // fp32 indexed by i store
- {name: "MOVSSstoreidx4", argLength: 4, reg: fpstoreidx, asm: "MOVSS", aux: "SymOff"}, // fp32 indexed by 4i store
- {name: "MOVSDstoreidx1", argLength: 4, reg: fpstoreidx, asm: "MOVSD", aux: "SymOff"}, // fp64 indexed by i store
- {name: "MOVSDstoreidx8", argLength: 4, reg: fpstoreidx, asm: "MOVSD", aux: "SymOff"}, // fp64 indexed by 8i store
+ {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
// binary ops
- {name: "ADDQ", argLength: 2, reg: gp21sp, asm: "ADDQ", commutative: true}, // arg0 + arg1
- {name: "ADDL", argLength: 2, reg: gp21sp, asm: "ADDL", commutative: true}, // arg0 + arg1
- {name: "ADDQconst", argLength: 1, reg: gp11sp, asm: "ADDQ", aux: "Int64", typ: "UInt64"}, // arg0 + auxint
- {name: "ADDLconst", argLength: 1, reg: gp11sp, asm: "ADDL", aux: "Int32"}, // arg0 + auxint
-
- {name: "SUBQ", argLength: 2, reg: gp21, asm: "SUBQ", resultInArg0: true}, // arg0 - arg1
- {name: "SUBL", argLength: 2, reg: gp21, asm: "SUBL", resultInArg0: true}, // arg0 - arg1
- {name: "SUBQconst", argLength: 1, reg: gp11, asm: "SUBQ", aux: "Int64", resultInArg0: true}, // arg0 - auxint
- {name: "SUBLconst", argLength: 1, reg: gp11, asm: "SUBL", aux: "Int32", resultInArg0: true}, // arg0 - auxint
-
- {name: "MULQ", argLength: 2, reg: gp21, asm: "IMULQ", commutative: true, resultInArg0: true}, // arg0 * arg1
- {name: "MULL", argLength: 2, reg: gp21, asm: "IMULL", commutative: true, resultInArg0: true}, // arg0 * arg1
- {name: "MULQconst", argLength: 1, reg: gp11, asm: "IMULQ", aux: "Int64", resultInArg0: true}, // arg0 * auxint
- {name: "MULLconst", argLength: 1, reg: gp11, asm: "IMULL", aux: "Int32", resultInArg0: true}, // arg0 * auxint
-
- {name: "HMULQ", argLength: 2, reg: gp11hmul, asm: "IMULQ"}, // (arg0 * arg1) >> width
- {name: "HMULL", argLength: 2, reg: gp11hmul, asm: "IMULL"}, // (arg0 * arg1) >> width
- {name: "HMULW", argLength: 2, reg: gp11hmul, asm: "IMULW"}, // (arg0 * arg1) >> width
- {name: "HMULB", argLength: 2, reg: gp11hmul, asm: "IMULB"}, // (arg0 * arg1) >> width
- {name: "HMULQU", argLength: 2, reg: gp11hmul, asm: "MULQ"}, // (arg0 * arg1) >> width
- {name: "HMULLU", argLength: 2, reg: gp11hmul, asm: "MULL"}, // (arg0 * arg1) >> width
- {name: "HMULWU", argLength: 2, reg: gp11hmul, asm: "MULW"}, // (arg0 * arg1) >> width
- {name: "HMULBU", argLength: 2, reg: gp11hmul, asm: "MULB"}, // (arg0 * arg1) >> width
-
- {name: "AVGQU", argLength: 2, reg: gp21, commutative: true, resultInArg0: true}, // (arg0 + arg1) / 2 as unsigned, all 64 result bits
-
- {name: "DIVQ", argLength: 2, reg: gp11div, asm: "IDIVQ"}, // arg0 / arg1
- {name: "DIVL", argLength: 2, reg: gp11div, asm: "IDIVL"}, // arg0 / arg1
- {name: "DIVW", argLength: 2, reg: gp11div, asm: "IDIVW"}, // arg0 / arg1
- {name: "DIVQU", argLength: 2, reg: gp11div, asm: "DIVQ"}, // arg0 / arg1
- {name: "DIVLU", argLength: 2, reg: gp11div, asm: "DIVL"}, // arg0 / arg1
- {name: "DIVWU", argLength: 2, reg: gp11div, asm: "DIVW"}, // arg0 / arg1
-
- {name: "MODQ", argLength: 2, reg: gp11mod, asm: "IDIVQ"}, // arg0 % arg1
- {name: "MODL", argLength: 2, reg: gp11mod, asm: "IDIVL"}, // arg0 % arg1
- {name: "MODW", argLength: 2, reg: gp11mod, asm: "IDIVW"}, // arg0 % arg1
- {name: "MODQU", argLength: 2, reg: gp11mod, asm: "DIVQ"}, // arg0 % arg1
- {name: "MODLU", argLength: 2, reg: gp11mod, asm: "DIVL"}, // arg0 % arg1
- {name: "MODWU", argLength: 2, reg: gp11mod, asm: "DIVW"}, // arg0 % arg1
-
- {name: "ANDQ", argLength: 2, reg: gp21, asm: "ANDQ", commutative: true, resultInArg0: true}, // arg0 & arg1
- {name: "ANDL", argLength: 2, reg: gp21, asm: "ANDL", commutative: true, resultInArg0: true}, // arg0 & arg1
- {name: "ANDQconst", argLength: 1, reg: gp11, asm: "ANDQ", aux: "Int64", resultInArg0: true}, // arg0 & auxint
- {name: "ANDLconst", argLength: 1, reg: gp11, asm: "ANDL", aux: "Int32", resultInArg0: true}, // arg0 & auxint
-
- {name: "ORQ", argLength: 2, reg: gp21, asm: "ORQ", commutative: true, resultInArg0: true}, // arg0 | arg1
- {name: "ORL", argLength: 2, reg: gp21, asm: "ORL", commutative: true, resultInArg0: true}, // arg0 | arg1
- {name: "ORQconst", argLength: 1, reg: gp11, asm: "ORQ", aux: "Int64", resultInArg0: true}, // arg0 | auxint
- {name: "ORLconst", argLength: 1, reg: gp11, asm: "ORL", aux: "Int32", resultInArg0: true}, // arg0 | auxint
-
- {name: "XORQ", argLength: 2, reg: gp21, asm: "XORQ", commutative: true, resultInArg0: true}, // arg0 ^ arg1
- {name: "XORL", argLength: 2, reg: gp21, asm: "XORL", commutative: true, resultInArg0: true}, // arg0 ^ arg1
- {name: "XORQconst", argLength: 1, reg: gp11, asm: "XORQ", aux: "Int64", resultInArg0: true}, // arg0 ^ auxint
- {name: "XORLconst", argLength: 1, reg: gp11, asm: "XORL", aux: "Int32", resultInArg0: true}, // arg0 ^ auxint
+ {name: "ADDQ", argLength: 2, reg: gp21sp, asm: "ADDQ", commutative: true, clobberFlags: true}, // arg0 + arg1
+ {name: "ADDL", argLength: 2, reg: gp21sp, asm: "ADDL", commutative: true, clobberFlags: true}, // arg0 + arg1
+ {name: "ADDQconst", argLength: 1, reg: gp11sp, asm: "ADDQ", aux: "Int64", typ: "UInt64", clobberFlags: true}, // arg0 + auxint
+ {name: "ADDLconst", argLength: 1, reg: gp11sp, asm: "ADDL", aux: "Int32", clobberFlags: true}, // arg0 + auxint
+
+ {name: "SUBQ", argLength: 2, reg: gp21, asm: "SUBQ", resultInArg0: true, clobberFlags: true}, // arg0 - arg1
+ {name: "SUBL", argLength: 2, reg: gp21, asm: "SUBL", resultInArg0: true, clobberFlags: true}, // arg0 - arg1
+ {name: "SUBQconst", argLength: 1, reg: gp11, asm: "SUBQ", aux: "Int64", resultInArg0: true, clobberFlags: true}, // arg0 - auxint
+ {name: "SUBLconst", argLength: 1, reg: gp11, asm: "SUBL", aux: "Int32", resultInArg0: true, clobberFlags: true}, // arg0 - auxint
+
+ {name: "MULQ", argLength: 2, reg: gp21, asm: "IMULQ", commutative: true, resultInArg0: true, clobberFlags: true}, // arg0 * arg1
+ {name: "MULL", argLength: 2, reg: gp21, asm: "IMULL", commutative: true, resultInArg0: true, clobberFlags: true}, // arg0 * arg1
+ {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: "AVGQU", argLength: 2, reg: gp21, commutative: true, resultInArg0: true, clobberFlags: true}, // (arg0 + arg1) / 2 as unsigned, all 64 result bits
+
+ {name: "DIVQ", argLength: 2, reg: gp11div, typ: "(Int64,Int64)", asm: "IDIVQ", clobberFlags: true}, // [arg0 / arg1, arg0 % arg1]
+ {name: "DIVL", argLength: 2, reg: gp11div, typ: "(Int32,Int32)", asm: "IDIVL", clobberFlags: true}, // [arg0 / arg1, arg0 % arg1]
+ {name: "DIVW", argLength: 2, reg: gp11div, typ: "(Int16,Int16)", asm: "IDIVW", clobberFlags: true}, // [arg0 / arg1, arg0 % arg1]
+ {name: "DIVQU", argLength: 2, reg: gp11div, typ: "(UInt64,UInt64)", asm: "DIVQ", clobberFlags: true}, // [arg0 / arg1, arg0 % arg1]
+ {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: "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
+ {name: "ANDQconst", argLength: 1, reg: gp11, asm: "ANDQ", aux: "Int64", resultInArg0: true, clobberFlags: true}, // arg0 & auxint
+ {name: "ANDLconst", argLength: 1, reg: gp11, asm: "ANDL", aux: "Int32", resultInArg0: true, clobberFlags: true}, // arg0 & auxint
+
+ {name: "ORQ", argLength: 2, reg: gp21, asm: "ORQ", commutative: true, resultInArg0: true, clobberFlags: true}, // arg0 | arg1
+ {name: "ORL", argLength: 2, reg: gp21, asm: "ORL", commutative: true, resultInArg0: true, clobberFlags: true}, // arg0 | arg1
+ {name: "ORQconst", argLength: 1, reg: gp11, asm: "ORQ", aux: "Int64", resultInArg0: true, clobberFlags: true}, // arg0 | auxint
+ {name: "ORLconst", argLength: 1, reg: gp11, asm: "ORL", aux: "Int32", resultInArg0: true, clobberFlags: true}, // arg0 | auxint
+
+ {name: "XORQ", argLength: 2, reg: gp21, asm: "XORQ", commutative: true, resultInArg0: true, clobberFlags: true}, // arg0 ^ arg1
+ {name: "XORL", argLength: 2, reg: gp21, asm: "XORL", commutative: true, resultInArg0: true, clobberFlags: true}, // arg0 ^ arg1
+ {name: "XORQconst", argLength: 1, reg: gp11, asm: "XORQ", aux: "Int64", resultInArg0: true, clobberFlags: true}, // arg0 ^ auxint
+ {name: "XORLconst", argLength: 1, reg: gp11, asm: "XORL", aux: "Int32", resultInArg0: true, clobberFlags: true}, // arg0 ^ auxint
{name: "CMPQ", argLength: 2, reg: gp2flags, asm: "CMPQ", typ: "Flags"}, // arg0 compare to arg1
{name: "CMPL", argLength: 2, reg: gp2flags, asm: "CMPL", typ: "Flags"}, // arg0 compare to arg1
@@ -264,60 +250,55 @@ func init() {
{name: "TESTWconst", argLength: 1, reg: gp1flags, asm: "TESTW", typ: "Flags", aux: "Int16"}, // (arg0 & auxint) compare to 0
{name: "TESTBconst", argLength: 1, reg: gp1flags, asm: "TESTB", typ: "Flags", aux: "Int8"}, // (arg0 & auxint) compare to 0
- {name: "SHLQ", argLength: 2, reg: gp21shift, asm: "SHLQ", resultInArg0: true}, // arg0 << arg1, shift amount is mod 64
- {name: "SHLL", argLength: 2, reg: gp21shift, asm: "SHLL", resultInArg0: true}, // arg0 << arg1, shift amount is mod 32
- {name: "SHLQconst", argLength: 1, reg: gp11, asm: "SHLQ", aux: "Int64", resultInArg0: true}, // arg0 << auxint, shift amount 0-63
- {name: "SHLLconst", argLength: 1, reg: gp11, asm: "SHLL", aux: "Int32", resultInArg0: true}, // arg0 << auxint, shift amount 0-31
+ {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
// Note: x86 is weird, the 16 and 8 byte shifts still use all 5 bits of shift amount!
- {name: "SHRQ", argLength: 2, reg: gp21shift, asm: "SHRQ", resultInArg0: true}, // unsigned arg0 >> arg1, shift amount is mod 64
- {name: "SHRL", argLength: 2, reg: gp21shift, asm: "SHRL", resultInArg0: true}, // unsigned arg0 >> arg1, shift amount is mod 32
- {name: "SHRW", argLength: 2, reg: gp21shift, asm: "SHRW", resultInArg0: true}, // unsigned arg0 >> arg1, shift amount is mod 32
- {name: "SHRB", argLength: 2, reg: gp21shift, asm: "SHRB", resultInArg0: true}, // unsigned arg0 >> arg1, shift amount is mod 32
- {name: "SHRQconst", argLength: 1, reg: gp11, asm: "SHRQ", aux: "Int64", resultInArg0: true}, // unsigned arg0 >> auxint, shift amount 0-63
- {name: "SHRLconst", argLength: 1, reg: gp11, asm: "SHRL", aux: "Int32", resultInArg0: true}, // unsigned arg0 >> auxint, shift amount 0-31
- {name: "SHRWconst", argLength: 1, reg: gp11, asm: "SHRW", aux: "Int16", resultInArg0: true}, // unsigned arg0 >> auxint, shift amount 0-31
- {name: "SHRBconst", argLength: 1, reg: gp11, asm: "SHRB", aux: "Int8", resultInArg0: true}, // unsigned arg0 >> auxint, shift amount 0-31
-
- {name: "SARQ", argLength: 2, reg: gp21shift, asm: "SARQ", resultInArg0: true}, // signed arg0 >> arg1, shift amount is mod 64
- {name: "SARL", argLength: 2, reg: gp21shift, asm: "SARL", resultInArg0: true}, // signed arg0 >> arg1, shift amount is mod 32
- {name: "SARW", argLength: 2, reg: gp21shift, asm: "SARW", resultInArg0: true}, // signed arg0 >> arg1, shift amount is mod 32
- {name: "SARB", argLength: 2, reg: gp21shift, asm: "SARB", resultInArg0: true}, // signed arg0 >> arg1, shift amount is mod 32
- {name: "SARQconst", argLength: 1, reg: gp11, asm: "SARQ", aux: "Int64", resultInArg0: true}, // signed arg0 >> auxint, shift amount 0-63
- {name: "SARLconst", argLength: 1, reg: gp11, asm: "SARL", aux: "Int32", resultInArg0: true}, // signed arg0 >> auxint, shift amount 0-31
- {name: "SARWconst", argLength: 1, reg: gp11, asm: "SARW", aux: "Int16", resultInArg0: true}, // signed arg0 >> auxint, shift amount 0-31
- {name: "SARBconst", argLength: 1, reg: gp11, asm: "SARB", aux: "Int8", resultInArg0: true}, // signed arg0 >> auxint, shift amount 0-31
-
- {name: "ROLQconst", argLength: 1, reg: gp11, asm: "ROLQ", aux: "Int64", resultInArg0: true}, // arg0 rotate left auxint, rotate amount 0-63
- {name: "ROLLconst", argLength: 1, reg: gp11, asm: "ROLL", aux: "Int32", resultInArg0: true}, // arg0 rotate left auxint, rotate amount 0-31
- {name: "ROLWconst", argLength: 1, reg: gp11, asm: "ROLW", aux: "Int16", resultInArg0: true}, // arg0 rotate left auxint, rotate amount 0-15
- {name: "ROLBconst", argLength: 1, reg: gp11, asm: "ROLB", aux: "Int8", resultInArg0: true}, // arg0 rotate left auxint, rotate amount 0-7
+ {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
// unary ops
- {name: "NEGQ", argLength: 1, reg: gp11, asm: "NEGQ", resultInArg0: true}, // -arg0
- {name: "NEGL", argLength: 1, reg: gp11, asm: "NEGL", resultInArg0: true}, // -arg0
+ {name: "NEGQ", argLength: 1, reg: gp11, asm: "NEGQ", resultInArg0: true, clobberFlags: true}, // -arg0
+ {name: "NEGL", argLength: 1, reg: gp11, asm: "NEGL", resultInArg0: true, clobberFlags: true}, // -arg0
- {name: "NOTQ", argLength: 1, reg: gp11, asm: "NOTQ", resultInArg0: true}, // ^arg0
- {name: "NOTL", argLength: 1, reg: gp11, asm: "NOTL", resultInArg0: true}, // ^arg0
+ {name: "NOTQ", argLength: 1, reg: gp11, asm: "NOTQ", resultInArg0: true, clobberFlags: true}, // ^arg0
+ {name: "NOTL", argLength: 1, reg: gp11, asm: "NOTL", resultInArg0: true, clobberFlags: true}, // ^arg0
- {name: "BSFQ", argLength: 1, reg: gp11, asm: "BSFQ"}, // arg0 # of low-order zeroes ; undef if zero
- {name: "BSFL", argLength: 1, reg: gp11, asm: "BSFL"}, // arg0 # of low-order zeroes ; undef if zero
- {name: "BSFW", argLength: 1, reg: gp11, asm: "BSFW"}, // arg0 # of low-order zeroes ; undef if zero
-
- {name: "BSRQ", argLength: 1, reg: gp11, asm: "BSRQ"}, // arg0 # of high-order zeroes ; undef if zero
- {name: "BSRL", argLength: 1, reg: gp11, asm: "BSRL"}, // arg0 # of high-order zeroes ; undef if zero
- {name: "BSRW", argLength: 1, reg: gp11, asm: "BSRW"}, // arg0 # of high-order zeroes ; undef if zero
+ // BSF{L,Q} returns a tuple [result, flags]
+ // result is undefined if the input is zero.
+ // 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
// Note ASM for ops moves whole register
- {name: "CMOVQEQconst", argLength: 2, reg: gp1flagsgp, asm: "CMOVQEQ", typ: "UInt64", aux: "Int64", resultInArg0: true}, // replace arg0 w/ constant if Z set
- {name: "CMOVLEQconst", argLength: 2, reg: gp1flagsgp, asm: "CMOVLEQ", typ: "UInt32", aux: "Int32", resultInArg0: true}, // replace arg0 w/ constant if Z set
- {name: "CMOVWEQconst", argLength: 2, reg: gp1flagsgp, asm: "CMOVLEQ", typ: "UInt16", aux: "Int16", resultInArg0: true}, // replace arg0 w/ constant if Z set
- {name: "CMOVQNEconst", argLength: 2, reg: gp1flagsgp, asm: "CMOVQNE", typ: "UInt64", aux: "Int64", resultInArg0: true}, // replace arg0 w/ constant if Z not set
- {name: "CMOVLNEconst", argLength: 2, reg: gp1flagsgp, asm: "CMOVLNE", typ: "UInt32", aux: "Int32", resultInArg0: true}, // replace arg0 w/ constant if Z not set
- {name: "CMOVWNEconst", argLength: 2, reg: gp1flagsgp, asm: "CMOVLNE", typ: "UInt16", aux: "Int16", resultInArg0: true}, // replace arg0 w/ constant if Z not set
+ //
+ {name: "CMOVQEQ", argLength: 3, reg: gp21, asm: "CMOVQEQ", resultInArg0: true}, // if arg2 encodes "equal" return arg1 else arg0
+ {name: "CMOVLEQ", argLength: 3, reg: gp21, asm: "CMOVLEQ", resultInArg0: true}, // if arg2 encodes "equal" return arg1 else arg0
- {name: "BSWAPQ", argLength: 1, reg: gp11, asm: "BSWAPQ", resultInArg0: true}, // arg0 swap bytes
- {name: "BSWAPL", argLength: 1, reg: gp11, asm: "BSWAPL", resultInArg0: true}, // arg0 swap bytes
+ {name: "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
{name: "SQRTSD", argLength: 1, reg: fp11, asm: "SQRTSD"}, // sqrt(arg0)
@@ -338,20 +319,20 @@ func init() {
// Need different opcodes for floating point conditions because
// any comparison involving a NaN is always FALSE and thus
// the patterns for inverting conditions cannot be used.
- {name: "SETEQF", argLength: 1, reg: flagsgpax, asm: "SETEQ"}, // extract == condition from arg0
- {name: "SETNEF", argLength: 1, reg: flagsgpax, asm: "SETNE"}, // extract != condition from arg0
- {name: "SETORD", argLength: 1, reg: flagsgp, asm: "SETPC"}, // extract "ordered" (No Nan present) condition from arg0
- {name: "SETNAN", argLength: 1, reg: flagsgp, asm: "SETPS"}, // extract "unordered" (Nan present) condition from arg0
+ {name: "SETEQF", argLength: 1, reg: flagsgpax, asm: "SETEQ", clobberFlags: true}, // extract == condition from arg0
+ {name: "SETNEF", argLength: 1, reg: flagsgpax, asm: "SETNE", clobberFlags: true}, // extract != condition from arg0
+ {name: "SETORD", argLength: 1, reg: flagsgp, asm: "SETPC"}, // extract "ordered" (No Nan present) condition from arg0
+ {name: "SETNAN", argLength: 1, reg: flagsgp, asm: "SETPS"}, // extract "unordered" (Nan present) condition from arg0
{name: "SETGF", argLength: 1, reg: flagsgp, asm: "SETHI"}, // extract floating > condition from arg0
{name: "SETGEF", argLength: 1, reg: flagsgp, asm: "SETCC"}, // extract floating >= condition from arg0
- {name: "MOVBQSX", argLength: 1, reg: gp11nf, asm: "MOVBQSX"}, // sign extend arg0 from int8 to int64
- {name: "MOVBQZX", argLength: 1, reg: gp11nf, asm: "MOVBQZX"}, // zero extend arg0 from int8 to int64
- {name: "MOVWQSX", argLength: 1, reg: gp11nf, asm: "MOVWQSX"}, // sign extend arg0 from int16 to int64
- {name: "MOVWQZX", argLength: 1, reg: gp11nf, asm: "MOVWQZX"}, // zero extend arg0 from int16 to int64
- {name: "MOVLQSX", argLength: 1, reg: gp11nf, asm: "MOVLQSX"}, // sign extend arg0 from int32 to int64
- {name: "MOVLQZX", argLength: 1, reg: gp11nf, asm: "MOVLQZX"}, // zero extend arg0 from int32 to int64
+ {name: "MOVBQSX", argLength: 1, reg: gp11, asm: "MOVBQSX"}, // sign extend arg0 from int8 to int64
+ {name: "MOVBQZX", argLength: 1, reg: gp11, asm: "MOVBLZX"}, // zero extend arg0 from int8 to int64
+ {name: "MOVWQSX", argLength: 1, reg: gp11, asm: "MOVWQSX"}, // sign extend arg0 from int16 to int64
+ {name: "MOVWQZX", argLength: 1, reg: gp11, asm: "MOVWLZX"}, // zero extend arg0 from int16 to int64
+ {name: "MOVLQSX", argLength: 1, reg: gp11, asm: "MOVLQSX"}, // sign extend arg0 from int32 to int64
+ {name: "MOVLQZX", argLength: 1, reg: gp11, asm: "MOVL"}, // zero extend arg0 from int32 to int64
{name: "MOVLconst", reg: gp01, asm: "MOVL", typ: "UInt32", aux: "Int32", rematerializeable: true}, // 32 low bits of auxint
{name: "MOVQconst", reg: gp01, asm: "MOVQ", typ: "UInt64", aux: "Int64", rematerializeable: true}, // auxint
@@ -369,27 +350,29 @@ 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, 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}, // arg0 + auxint + offset encoded in aux
+ {name: "LEAQ1", argLength: 2, reg: gp21sb, aux: "SymOff"}, // arg0 + arg1 + auxint + aux
+ {name: "LEAQ2", argLength: 2, reg: gp21sb, aux: "SymOff"}, // arg0 + 2*arg1 + auxint + aux
+ {name: "LEAQ4", argLength: 2, reg: gp21sb, aux: "SymOff"}, // arg0 + 4*arg1 + auxint + aux
+ {name: "LEAQ8", argLength: 2, reg: gp21sb, aux: "SymOff"}, // arg0 + 8*arg1 + auxint + aux
// Note: LEAQ{1,2,4,8} must not have OpSB as either argument.
+ {name: "LEAL", argLength: 1, reg: gp11sb, asm: "LEAL", aux: "SymOff", rematerializeable: true}, // 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"}, // load byte from arg0+auxint+aux. arg1=mem. Zero extend.
- {name: "MOVBQSXload", argLength: 2, reg: gpload, asm: "MOVBQSX", aux: "SymOff"}, // ditto, sign extend to int64
- {name: "MOVWload", argLength: 2, reg: gpload, asm: "MOVWLZX", aux: "SymOff", typ: "UInt16"}, // load 2 bytes from arg0+auxint+aux. arg1=mem. Zero extend.
- {name: "MOVWQSXload", argLength: 2, reg: gpload, asm: "MOVWQSX", aux: "SymOff"}, // ditto, sign extend to int64
- {name: "MOVLload", argLength: 2, reg: gpload, asm: "MOVL", aux: "SymOff", typ: "UInt32"}, // load 4 bytes from arg0+auxint+aux. arg1=mem. Zero extend.
- {name: "MOVLQSXload", argLength: 2, reg: gpload, asm: "MOVLQSX", aux: "SymOff"}, // ditto, sign extend to int64
- {name: "MOVQload", argLength: 2, reg: gpload, asm: "MOVQ", aux: "SymOff", typ: "UInt64"}, // load 8 bytes from arg0+auxint+aux. arg1=mem
- {name: "MOVBstore", argLength: 3, reg: gpstore, asm: "MOVB", aux: "SymOff", typ: "Mem"}, // store byte in arg1 to arg0+auxint+aux. arg2=mem
- {name: "MOVWstore", argLength: 3, reg: gpstore, asm: "MOVW", aux: "SymOff", typ: "Mem"}, // store 2 bytes in arg1 to arg0+auxint+aux. arg2=mem
- {name: "MOVLstore", argLength: 3, reg: gpstore, asm: "MOVL", aux: "SymOff", typ: "Mem"}, // store 4 bytes in arg1 to arg0+auxint+aux. arg2=mem
- {name: "MOVQstore", argLength: 3, reg: gpstore, asm: "MOVQ", aux: "SymOff", typ: "Mem"}, // store 8 bytes in arg1 to arg0+auxint+aux. arg2=mem
- {name: "MOVOload", argLength: 2, reg: fpload, asm: "MOVUPS", aux: "SymOff", typ: "Int128"}, // load 16 bytes from arg0+auxint+aux. arg1=mem
- {name: "MOVOstore", argLength: 3, reg: fpstore, asm: "MOVUPS", aux: "SymOff", typ: "Mem"}, // store 16 bytes in arg1 to arg0+auxint+aux. arg2=mem
+ {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
// indexed loads/stores
{name: "MOVBloadidx1", argLength: 3, reg: gploadidx, asm: "MOVBLZX", aux: "SymOff"}, // load a byte from arg0+arg1+auxint+aux. arg2=mem
@@ -412,10 +395,10 @@ func init() {
// For storeconst ops, the AuxInt field encodes both
// the value to store and an address offset of the store.
// Cast AuxInt to a ValAndOff to extract Val and Off fields.
- {name: "MOVBstoreconst", argLength: 2, reg: gpstoreconst, asm: "MOVB", aux: "SymValAndOff", typ: "Mem"}, // store low byte of ValAndOff(AuxInt).Val() to arg0+ValAndOff(AuxInt).Off()+aux. arg1=mem
- {name: "MOVWstoreconst", argLength: 2, reg: gpstoreconst, asm: "MOVW", aux: "SymValAndOff", typ: "Mem"}, // store low 2 bytes of ...
- {name: "MOVLstoreconst", argLength: 2, reg: gpstoreconst, asm: "MOVL", aux: "SymValAndOff", typ: "Mem"}, // store low 4 bytes of ...
- {name: "MOVQstoreconst", argLength: 2, reg: gpstoreconst, asm: "MOVQ", aux: "SymValAndOff", typ: "Mem"}, // store 8 bytes of ...
+ {name: "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 ...
@@ -436,8 +419,9 @@ func init() {
argLength: 3,
reg: regInfo{
inputs: []regMask{buildReg("DI"), buildReg("X0")},
- clobbers: buildReg("DI FLAGS"),
+ clobbers: buildReg("DI"),
},
+ clobberFlags: true,
},
{name: "MOVOconst", reg: regInfo{nil, 0, []regMask{fp}}, typ: "Int128", aux: "Int128", rematerializeable: true},
@@ -455,11 +439,11 @@ func init() {
},
},
- {name: "CALLstatic", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "SymOff"}, // call static function aux.(*gc.Sym). arg0=mem, auxint=argsize, returns mem
- {name: "CALLclosure", argLength: 3, reg: regInfo{[]regMask{gpsp, buildReg("DX"), 0}, callerSave, nil}, aux: "Int64"}, // call function via closure. arg0=codeptr, arg1=closure, arg2=mem, auxint=argsize, returns mem
- {name: "CALLdefer", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "Int64"}, // call deferproc. arg0=mem, auxint=argsize, returns mem
- {name: "CALLgo", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "Int64"}, // call newproc. arg0=mem, auxint=argsize, returns mem
- {name: "CALLinter", argLength: 2, reg: regInfo{inputs: []regMask{gp}, clobbers: callerSave}, aux: "Int64"}, // call fn by pointer. arg0=codeptr, arg1=mem, auxint=argsize, returns mem
+ {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("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
// arg1 = source pointer
@@ -472,8 +456,9 @@ func init() {
argLength: 3,
reg: regInfo{
inputs: []regMask{buildReg("DI"), buildReg("SI")},
- clobbers: buildReg("DI SI X0 FLAGS"), // uses X0 as a temporary
+ clobbers: buildReg("DI SI X0"), // uses X0 as a temporary
},
+ clobberFlags: true,
},
// arg0 = destination pointer
@@ -504,14 +489,15 @@ func init() {
// use of DX (the closure pointer)
{name: "LoweredGetClosurePtr", reg: regInfo{outputs: []regMask{buildReg("DX")}}},
//arg0=ptr,arg1=mem, returns void. Faults if ptr is nil.
- {name: "LoweredNilCheck", argLength: 2, reg: regInfo{inputs: []regMask{gpsp}, clobbers: flags}},
+ {name: "LoweredNilCheck", argLength: 2, reg: regInfo{inputs: []regMask{gpsp}}, clobberFlags: true, nilCheck: true, faultOnNilArg0: true},
// MOVQconvert converts between pointers and integers.
// We have a special op for this so as to not confuse GC
// (particularly stack maps). It takes a memory arg so it
// gets correctly ordered with respect to GC safepoints.
// arg0=ptr/int arg1=mem, output=int/ptr
- {name: "MOVQconvert", argLength: 2, reg: gp11nf, asm: "MOVQ"},
+ {name: "MOVQconvert", argLength: 2, reg: gp11, asm: "MOVQ"},
+ {name: "MOVLconvert", argLength: 2, reg: gp11, asm: "MOVL"}, // amd64p32 equivalent
// Constant flag values. For any comparison, there are 5 possible
// outcomes: the three from the signed total order (<,==,>) and the
@@ -525,6 +511,54 @@ func init() {
{name: "FlagLT_UGT"}, // signed < and unsigned >
{name: "FlagGT_UGT"}, // signed > and unsigned <
{name: "FlagGT_ULT"}, // signed > and unsigned >
+
+ // 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},
+
+ // 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},
+ {name: "XCHGQ", argLength: 3, reg: gpstorexchg, asm: "XCHGQ", aux: "SymOff", resultInArg0: true, faultOnNilArg1: true},
+
+ // 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},
+ {name: "XADDQlock", argLength: 3, reg: gpstorexchg, asm: "XADDQ", typ: "(UInt64,Mem)", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: 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>.
+
+ // Compare and swap.
+ // arg0 = pointer, arg1 = old value, arg2 = new value, arg3 = memory.
+ // if *(arg0+auxint+aux) == arg1 {
+ // *(arg0+auxint+aux) = arg2
+ // return (true, memory)
+ // } else {
+ // return (false, memory)
+ // }
+ // Note that these instructions also return the old value in AX, but we ignore it.
+ // TODO: have these return flags instead of bool. The current system generates:
+ // CMPXCHGQ ...
+ // SETEQ AX
+ // CMPB AX, $0
+ // JNE ...
+ // instead of just
+ // CMPXCHGQ ...
+ // 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},
+ {name: "CMPXCHGQlock", argLength: 4, reg: cmpxchg, asm: "CMPXCHGQ", aux: "SymOff", clobberFlags: true, faultOnNilArg0: true},
+
+ // Atomic memory updates.
+ {name: "ANDBlock", argLength: 3, reg: gpstore, asm: "ANDB", aux: "SymOff", clobberFlags: true, faultOnNilArg0: true}, // *(arg0+auxint+aux) &= arg1
+ {name: "ORBlock", argLength: 3, reg: gpstore, asm: "ORB", aux: "SymOff", clobberFlags: true, faultOnNilArg0: true}, // *(arg0+auxint+aux) |= arg1
}
var AMD64blocks = []blockData{
@@ -545,11 +579,15 @@ func init() {
}
archs = append(archs, arch{
- name: "AMD64",
- pkg: "cmd/internal/obj/x86",
- genfile: "../../amd64/ssa.go",
- ops: AMD64ops,
- blocks: AMD64blocks,
- regnames: regNamesAMD64,
+ name: "AMD64",
+ pkg: "cmd/internal/obj/x86",
+ genfile: "../../amd64/ssa.go",
+ ops: AMD64ops,
+ blocks: AMD64blocks,
+ regnames: regNamesAMD64,
+ gpregmask: gp,
+ fpregmask: fp,
+ framepointerreg: int8(num["BP"]),
+ linkreg: -1, // not used
})
}
diff --git a/src/cmd/compile/internal/ssa/gen/ARM.rules b/src/cmd/compile/internal/ssa/gen/ARM.rules
index 273500f..bea9d6c 100644
--- a/src/cmd/compile/internal/ssa/gen/ARM.rules
+++ b/src/cmd/compile/internal/ssa/gen/ARM.rules
@@ -2,31 +2,1244 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+(AddPtr x y) -> (ADD x y)
(Add32 x y) -> (ADD x y)
+(Add16 x y) -> (ADD x y)
+(Add8 x y) -> (ADD x y)
+(Add32F x y) -> (ADDF x y)
+(Add64F x y) -> (ADDD x y)
+(Add32carry x y) -> (ADDS x y)
+(Add32withcarry x y c) -> (ADC x y c)
+
+(SubPtr x y) -> (SUB x y)
+(Sub32 x y) -> (SUB x y)
+(Sub16 x y) -> (SUB x y)
+(Sub8 x y) -> (SUB x y)
+(Sub32F x y) -> (SUBF x y)
+(Sub64F x y) -> (SUBD x y)
+
+(Sub32carry x y) -> (SUBS x y)
+(Sub32withcarry x y c) -> (SBC x y c)
+
+(Mul32 x y) -> (MUL x y)
+(Mul16 x y) -> (MUL x y)
+(Mul8 x y) -> (MUL x y)
+(Mul32F x y) -> (MULF x y)
+(Mul64F x y) -> (MULD x y)
+
+(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))
+(Div16 x y) -> (Div32 (SignExt16to32 x) (SignExt16to32 y))
+(Div16u x y) -> (Div32u (ZeroExt16to32 x) (ZeroExt16to32 y))
+(Div8 x y) -> (Div32 (SignExt8to32 x) (SignExt8to32 y))
+(Div8u x y) -> (Div32u (ZeroExt8to32 x) (ZeroExt8to32 y))
+(Div32F x y) -> (DIVF x y)
+(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
+ (Signmask x)) (Signmask x))
+(Mod32u x y) -> (Select1 <config.fe.TypeUInt32()> (UDIVrtcall 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))
+
+(And32 x y) -> (AND x y)
+(And16 x y) -> (AND x y)
+(And8 x y) -> (AND x y)
+
+(Or32 x y) -> (OR x y)
+(Or16 x y) -> (OR x y)
+(Or8 x y) -> (OR x y)
+
+(Xor32 x y) -> (XOR x y)
+(Xor16 x y) -> (XOR x y)
+(Xor8 x y) -> (XOR x y)
+
+// unary ops
+(Neg32 x) -> (RSBconst [0] x)
+(Neg16 x) -> (RSBconst [0] x)
+(Neg8 x) -> (RSBconst [0] x)
+(Neg32F x) -> (NEGF x)
+(Neg64F x) -> (NEGD x)
+
+(Com32 x) -> (MVN x)
+(Com16 x) -> (MVN x)
+(Com8 x) -> (MVN x)
+
+(Sqrt x) -> (SQRTD x)
+
+// count trailing zero
+// 32 - CLZ(x&-x - 1)
+(Ctz32 <t> x) -> (RSBconst [32] (CLZ <t> (SUBconst <t> (AND <t> x (RSBconst <t> [0] x)) [1])))
+
+// byte swap
+// 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)
+// t3 = t2 &^ 0xff0000 -- (a^c, 0, a^c, b^d)
+// t4 = t3 >> 8 -- (0, a^c, 0, a^c)
+// 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) ->
+ (XOR <t>
+ (SRLconst <t> (BICconst <t> (XOR <t> x (SRRconst <t> [16] x)) [0xff0000]) [8])
+ (SRRconst <t> x [8]))
+
+// 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))
+(NeqB x y) -> (XOR x y)
+(Not x) -> (XORconst [1] x)
+
+// shifts
+// hardware instruction uses only the low byte of the shift
+// we compare to 256 to ensure Go semantics for large shifts
+(Lsh32x32 x y) -> (CMOVWHSconst (SLL <x.Type> x y) (CMPconst [256] y) [0])
+(Lsh32x16 x y) -> (CMOVWHSconst (SLL <x.Type> x (ZeroExt16to32 y)) (CMPconst [256] (ZeroExt16to32 y)) [0])
+(Lsh32x8 x y) -> (SLL x (ZeroExt8to32 y))
+
+(Lsh16x32 x y) -> (CMOVWHSconst (SLL <x.Type> x y) (CMPconst [256] y) [0])
+(Lsh16x16 x y) -> (CMOVWHSconst (SLL <x.Type> x (ZeroExt16to32 y)) (CMPconst [256] (ZeroExt16to32 y)) [0])
+(Lsh16x8 x y) -> (SLL x (ZeroExt8to32 y))
+
+(Lsh8x32 x y) -> (CMOVWHSconst (SLL <x.Type> x y) (CMPconst [256] y) [0])
+(Lsh8x16 x y) -> (CMOVWHSconst (SLL <x.Type> x (ZeroExt16to32 y)) (CMPconst [256] (ZeroExt16to32 y)) [0])
+(Lsh8x8 x y) -> (SLL x (ZeroExt8to32 y))
+
+(Rsh32Ux32 x y) -> (CMOVWHSconst (SRL <x.Type> x y) (CMPconst [256] y) [0])
+(Rsh32Ux16 x y) -> (CMOVWHSconst (SRL <x.Type> x (ZeroExt16to32 y)) (CMPconst [256] (ZeroExt16to32 y)) [0])
+(Rsh32Ux8 x y) -> (SRL x (ZeroExt8to32 y))
+
+(Rsh16Ux32 x y) -> (CMOVWHSconst (SRL <x.Type> (ZeroExt16to32 x) y) (CMPconst [256] y) [0])
+(Rsh16Ux16 x y) -> (CMOVWHSconst (SRL <x.Type> (ZeroExt16to32 x) (ZeroExt16to32 y)) (CMPconst [256] (ZeroExt16to32 y)) [0])
+(Rsh16Ux8 x y) -> (SRL (ZeroExt16to32 x) (ZeroExt8to32 y))
+
+(Rsh8Ux32 x y) -> (CMOVWHSconst (SRL <x.Type> (ZeroExt8to32 x) y) (CMPconst [256] y) [0])
+(Rsh8Ux16 x y) -> (CMOVWHSconst (SRL <x.Type> (ZeroExt8to32 x) (ZeroExt16to32 y)) (CMPconst [256] (ZeroExt16to32 y)) [0])
+(Rsh8Ux8 x y) -> (SRL (ZeroExt8to32 x) (ZeroExt8to32 y))
+
+(Rsh32x32 x y) -> (SRAcond x y (CMPconst [256] y))
+(Rsh32x16 x y) -> (SRAcond x (ZeroExt16to32 y) (CMPconst [256] (ZeroExt16to32 y)))
+(Rsh32x8 x y) -> (SRA x (ZeroExt8to32 y))
+
+(Rsh16x32 x y) -> (SRAcond (SignExt16to32 x) y (CMPconst [256] y))
+(Rsh16x16 x y) -> (SRAcond (SignExt16to32 x) (ZeroExt16to32 y) (CMPconst [256] (ZeroExt16to32 y)))
+(Rsh16x8 x y) -> (SRA (SignExt16to32 x) (ZeroExt8to32 y))
+
+(Rsh8x32 x y) -> (SRAcond (SignExt8to32 x) y (CMPconst [256] y))
+(Rsh8x16 x y) -> (SRAcond (SignExt8to32 x) (ZeroExt16to32 y) (CMPconst [256] (ZeroExt16to32 y)))
+(Rsh8x8 x y) -> (SRA (SignExt8to32 x) (ZeroExt8to32 y))
+
+// constant shifts
+// generic opt rewrites all constant shifts to shift by Const64
+(Lsh32x64 x (Const64 [c])) && uint64(c) < 32 -> (SLLconst x [c])
+(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])
+(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])
+
+// large constant shifts
+(Lsh32x64 _ (Const64 [c])) && uint64(c) >= 32 -> (Const32 [0])
+(Rsh32Ux64 _ (Const64 [c])) && uint64(c) >= 32 -> (Const32 [0])
+(Lsh16x64 _ (Const64 [c])) && uint64(c) >= 16 -> (Const16 [0])
+(Rsh16Ux64 _ (Const64 [c])) && uint64(c) >= 16 -> (Const16 [0])
+(Lsh8x64 _ (Const64 [c])) && uint64(c) >= 8 -> (Const8 [0])
+(Rsh8Ux64 _ (Const64 [c])) && uint64(c) >= 8 -> (Const8 [0])
+
+// 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> x [16-c&15]))
+(Lrot8 <t> x [c]) -> (OR (SLLconst <t> x [c&7]) (SRLconst <t> x [8-c&7]))
+
+// constants
+(Const8 [val]) -> (MOVWconst [val])
+(Const16 [val]) -> (MOVWconst [val])
(Const32 [val]) -> (MOVWconst [val])
+(Const32F [val]) -> (MOVFconst [val])
+(Const64F [val]) -> (MOVDconst [val])
+(ConstNil) -> (MOVWconst [0])
+(ConstBool [b]) -> (MOVWconst [b])
+
+// truncations
+// Because we ignore high parts of registers, truncates are just copies.
+(Trunc16to8 x) -> x
+(Trunc32to8 x) -> x
+(Trunc32to16 x) -> x
+
+// Zero-/Sign-extensions
+(ZeroExt8to16 x) -> (MOVBUreg x)
+(ZeroExt8to32 x) -> (MOVBUreg x)
+(ZeroExt16to32 x) -> (MOVHUreg x)
+(SignExt8to16 x) -> (MOVBreg x)
+(SignExt8to32 x) -> (MOVBreg x)
+(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]))
+
+// float <-> int conversion
+(Cvt32to32F x) -> (MOVWF x)
+(Cvt32to64F x) -> (MOVWD x)
+(Cvt32Uto32F x) -> (MOVWUF x)
+(Cvt32Uto64F x) -> (MOVWUD x)
+(Cvt32Fto32 x) -> (MOVFW x)
+(Cvt64Fto32 x) -> (MOVDW x)
+(Cvt32Fto32U x) -> (MOVFWU x)
+(Cvt64Fto32U x) -> (MOVDWU x)
+(Cvt32Fto64F x) -> (MOVFD x)
+(Cvt64Fto32F x) -> (MOVDF x)
+
+// comparisons
+(Eq8 x y) -> (Equal (CMP (ZeroExt8to32 x) (ZeroExt8to32 y)))
+(Eq16 x y) -> (Equal (CMP (ZeroExt16to32 x) (ZeroExt16to32 y)))
+(Eq32 x y) -> (Equal (CMP x y))
+(EqPtr x y) -> (Equal (CMP x y))
+(Eq32F x y) -> (Equal (CMPF x y))
+(Eq64F x y) -> (Equal (CMPD x y))
+
+(Neq8 x y) -> (NotEqual (CMP (ZeroExt8to32 x) (ZeroExt8to32 y)))
+(Neq16 x y) -> (NotEqual (CMP (ZeroExt16to32 x) (ZeroExt16to32 y)))
+(Neq32 x y) -> (NotEqual (CMP x y))
+(NeqPtr x y) -> (NotEqual (CMP x y))
+(Neq32F x y) -> (NotEqual (CMPF x y))
+(Neq64F x y) -> (NotEqual (CMPD x y))
+
+(Less8 x y) -> (LessThan (CMP (SignExt8to32 x) (SignExt8to32 y)))
+(Less16 x y) -> (LessThan (CMP (SignExt16to32 x) (SignExt16to32 y)))
(Less32 x y) -> (LessThan (CMP x y))
+(Less32F x y) -> (GreaterThan (CMPF y x)) // reverse operands to work around NaN
+(Less64F x y) -> (GreaterThan (CMPD y x)) // reverse operands to work around NaN
+
+(Less8U x y) -> (LessThanU (CMP (ZeroExt8to32 x) (ZeroExt8to32 y)))
+(Less16U x y) -> (LessThanU (CMP (ZeroExt16to32 x) (ZeroExt16to32 y)))
+(Less32U x y) -> (LessThanU (CMP x y))
+
+(Leq8 x y) -> (LessEqual (CMP (SignExt8to32 x) (SignExt8to32 y)))
+(Leq16 x y) -> (LessEqual (CMP (SignExt16to32 x) (SignExt16to32 y)))
+(Leq32 x y) -> (LessEqual (CMP x y))
+(Leq32F x y) -> (GreaterEqual (CMPF y x)) // reverse operands to work around NaN
+(Leq64F x y) -> (GreaterEqual (CMPD y x)) // reverse operands to work around NaN
+
+(Leq8U x y) -> (LessEqualU (CMP (ZeroExt8to32 x) (ZeroExt8to32 y)))
+(Leq16U x y) -> (LessEqualU (CMP (ZeroExt16to32 x) (ZeroExt16to32 y)))
+(Leq32U x y) -> (LessEqualU (CMP x y))
+
+(Greater8 x y) -> (GreaterThan (CMP (SignExt8to32 x) (SignExt8to32 y)))
+(Greater16 x y) -> (GreaterThan (CMP (SignExt16to32 x) (SignExt16to32 y)))
+(Greater32 x y) -> (GreaterThan (CMP x y))
+(Greater32F x y) -> (GreaterThan (CMPF x y))
+(Greater64F x y) -> (GreaterThan (CMPD x y))
+
+(Greater8U x y) -> (GreaterThanU (CMP (ZeroExt8to32 x) (ZeroExt8to32 y)))
+(Greater16U x y) -> (GreaterThanU (CMP (ZeroExt16to32 x) (ZeroExt16to32 y)))
+(Greater32U x y) -> (GreaterThanU (CMP x y))
+
+(Geq8 x y) -> (GreaterEqual (CMP (SignExt8to32 x) (SignExt8to32 y)))
+(Geq16 x y) -> (GreaterEqual (CMP (SignExt16to32 x) (SignExt16to32 y)))
+(Geq32 x y) -> (GreaterEqual (CMP x y))
+(Geq32F x y) -> (GreaterEqual (CMPF x y))
+(Geq64F x y) -> (GreaterEqual (CMPD x y))
+
+(Geq8U x y) -> (GreaterEqualU (CMP (ZeroExt8to32 x) (ZeroExt8to32 y)))
+(Geq16U x y) -> (GreaterEqualU (CMP (ZeroExt16to32 x) (ZeroExt16to32 y)))
+(Geq32U x y) -> (GreaterEqualU (CMP x y))
+
+(OffPtr [off] ptr:(SP)) -> (MOVWaddr [off] ptr)
+(OffPtr [off] ptr) -> (ADDconst [off] ptr)
+
+(Addr {sym} base) -> (MOVWaddr {sym} base)
+
+// loads
+(Load <t> ptr mem) && t.IsBoolean() -> (MOVBUload ptr mem)
+(Load <t> ptr mem) && (is8BitInt(t) && isSigned(t)) -> (MOVBload ptr mem)
+(Load <t> ptr mem) && (is8BitInt(t) && !isSigned(t)) -> (MOVBUload ptr mem)
+(Load <t> ptr mem) && (is16BitInt(t) && isSigned(t)) -> (MOVHload ptr mem)
+(Load <t> ptr mem) && (is16BitInt(t) && !isSigned(t)) -> (MOVHUload ptr mem)
+(Load <t> ptr mem) && (is32BitInt(t) || isPtr(t)) -> (MOVWload ptr mem)
+(Load <t> ptr mem) && is32BitFloat(t) -> (MOVFload ptr mem)
+(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)
-(OffPtr [off] ptr) -> (ADD (MOVWconst <config.Frontend().TypeInt32()> [off]) ptr)
+// 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 ->
+ (MOVHstore ptr (MOVWconst [0]) mem)
+(Zero [s] ptr mem) && SizeAndAlign(s).Size() == 2 ->
+ (MOVBstore [1] ptr (MOVWconst [0])
+ (MOVBstore [0] ptr (MOVWconst [0]) mem))
+(Zero [s] ptr mem) && SizeAndAlign(s).Size() == 4 && SizeAndAlign(s).Align()%4 == 0 ->
+ (MOVWstore ptr (MOVWconst [0]) mem)
+(Zero [s] ptr mem) && SizeAndAlign(s).Size() == 4 && SizeAndAlign(s).Align()%2 == 0 ->
+ (MOVHstore [2] ptr (MOVWconst [0])
+ (MOVHstore [0] ptr (MOVWconst [0]) mem))
+(Zero [s] ptr mem) && SizeAndAlign(s).Size() == 4 ->
+ (MOVBstore [3] ptr (MOVWconst [0])
+ (MOVBstore [2] ptr (MOVWconst [0])
+ (MOVBstore [1] ptr (MOVWconst [0])
+ (MOVBstore [0] ptr (MOVWconst [0]) mem))))
-(Addr {sym} base) -> (ADDconst {sym} base)
+(Zero [s] ptr mem) && SizeAndAlign(s).Size() == 3 ->
+ (MOVBstore [2] ptr (MOVWconst [0])
+ (MOVBstore [1] ptr (MOVWconst [0])
+ (MOVBstore [0] ptr (MOVWconst [0]) mem)))
-(Load <t> ptr mem) && is32BitInt(t) -> (MOVWload ptr mem)
-(Store [4] ptr val mem) -> (MOVWstore ptr val 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)
+// Large zeroing uses a loop
+(Zero [s] ptr mem)
+ && (SizeAndAlign(s).Size() > 512 || config.noDuffDevice) || SizeAndAlign(s).Align()%4 != 0 ->
+ (LoweredZero [SizeAndAlign(s).Align()]
+ ptr
+ (ADDconst <ptr.Type> ptr [SizeAndAlign(s).Size()-moveSize(SizeAndAlign(s).Align(), 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 ->
+ (MOVHstore dst (MOVHUload src mem) mem)
+(Move [s] dst src mem) && SizeAndAlign(s).Size() == 2 ->
+ (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 ->
+ (MOVWstore dst (MOVWload src mem) mem)
+(Move [s] dst src mem) && SizeAndAlign(s).Size() == 4 && SizeAndAlign(s).Align()%2 == 0 ->
+ (MOVHstore [2] dst (MOVHUload [2] src mem)
+ (MOVHstore dst (MOVHUload src mem) mem))
+(Move [s] dst src mem) && SizeAndAlign(s).Size() == 4 ->
+ (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 ->
+ (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)
+
+// 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()]
+ dst
+ src
+ (ADDconst <src.Type> src [SizeAndAlign(s).Size()-moveSize(SizeAndAlign(s).Align(), 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
+(NilCheck ptr mem) -> (LoweredNilCheck ptr mem)
+(IsNonNil ptr) -> (NotEqual (CMPconst [0] ptr))
+(IsInBounds idx len) -> (LessThanU (CMP idx len))
+(IsSliceInBounds idx len) -> (LessEqualU (CMP idx len))
-// Absorb LessThan into blocks.
+// pseudo-ops
+(GetClosurePtr) -> (LoweredGetClosurePtr)
+(Convert x mem) -> (MOVWconvert x mem)
+
+// Absorb pseudo-ops into blocks.
+(If (Equal cc) yes no) -> (EQ cc yes no)
+(If (NotEqual cc) yes no) -> (NE cc yes no)
(If (LessThan cc) yes no) -> (LT cc yes no)
+(If (LessThanU cc) yes no) -> (ULT cc yes no)
+(If (LessEqual cc) yes no) -> (LE cc yes no)
+(If (LessEqualU cc) yes no) -> (ULE cc yes no)
+(If (GreaterThan cc) yes no) -> (GT cc yes no)
+(If (GreaterThanU cc) yes no) -> (UGT cc yes no)
+(If (GreaterEqual cc) yes no) -> (GE cc yes no)
+(If (GreaterEqualU cc) yes no) -> (UGE cc yes no)
+(If cond yes no) -> (NE (CMPconst [0] cond) yes no)
+// Absorb boolean tests into block
+(NE (CMPconst [0] (Equal cc)) yes no) -> (EQ cc yes no)
+(NE (CMPconst [0] (NotEqual cc)) yes no) -> (NE cc yes no)
+(NE (CMPconst [0] (LessThan cc)) yes no) -> (LT cc yes no)
+(NE (CMPconst [0] (LessThanU cc)) yes no) -> (ULT cc yes no)
+(NE (CMPconst [0] (LessEqual cc)) yes no) -> (LE cc yes no)
+(NE (CMPconst [0] (LessEqualU cc)) yes no) -> (ULE cc yes no)
+(NE (CMPconst [0] (GreaterThan cc)) yes no) -> (GT cc yes no)
+(NE (CMPconst [0] (GreaterThanU cc)) yes no) -> (UGT cc yes no)
+(NE (CMPconst [0] (GreaterEqual cc)) yes no) -> (GE cc yes no)
+(NE (CMPconst [0] (GreaterEqualU cc)) yes no) -> (UGE cc yes no)
// Optimizations
+// fold offset into address
+(ADDconst [off1] (MOVWaddr [off2] {sym} ptr)) -> (MOVWaddr [off1+off2] {sym} ptr)
+
+// fold address into load/store
+(MOVBload [off1] {sym} (ADDconst [off2] ptr) mem) -> (MOVBload [off1+off2] {sym} ptr mem)
+(MOVBUload [off1] {sym} (ADDconst [off2] ptr) mem) -> (MOVBUload [off1+off2] {sym} ptr mem)
+(MOVHload [off1] {sym} (ADDconst [off2] ptr) mem) -> (MOVHload [off1+off2] {sym} ptr mem)
+(MOVHUload [off1] {sym} (ADDconst [off2] ptr) mem) -> (MOVHUload [off1+off2] {sym} ptr mem)
+(MOVWload [off1] {sym} (ADDconst [off2] ptr) mem) -> (MOVWload [off1+off2] {sym} ptr mem)
+(MOVFload [off1] {sym} (ADDconst [off2] ptr) mem) -> (MOVFload [off1+off2] {sym} ptr mem)
+(MOVDload [off1] {sym} (ADDconst [off2] ptr) mem) -> (MOVDload [off1+off2] {sym} ptr mem)
+
+(MOVBstore [off1] {sym} (ADDconst [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)
+(MOVWstore [off1] {sym} (ADDconst [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)
+(MOVDstore [off1] {sym} (ADDconst [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)
+(MOVBUload [off1] {sym1} (MOVWaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) ->
+ (MOVBUload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
+(MOVHload [off1] {sym1} (MOVWaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) ->
+ (MOVHload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
+(MOVHUload [off1] {sym1} (MOVWaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) ->
+ (MOVHUload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
+(MOVWload [off1] {sym1} (MOVWaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) ->
+ (MOVWload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
+(MOVFload [off1] {sym1} (MOVWaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) ->
+ (MOVFload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
+(MOVDload [off1] {sym1} (MOVWaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) ->
+ (MOVDload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
+
+(MOVBstore [off1] {sym1} (MOVWaddr [off2] {sym2} ptr) val mem) && canMergeSym(sym1,sym2) ->
+ (MOVBstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
+(MOVHstore [off1] {sym1} (MOVWaddr [off2] {sym2} ptr) val mem) && canMergeSym(sym1,sym2) ->
+ (MOVHstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
+(MOVWstore [off1] {sym1} (MOVWaddr [off2] {sym2} ptr) val mem) && canMergeSym(sym1,sym2) ->
+ (MOVWstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
+(MOVFstore [off1] {sym1} (MOVWaddr [off2] {sym2} ptr) val mem) && canMergeSym(sym1,sym2) ->
+ (MOVFstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
+(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
+(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
+
+(MOVWloadidx ptr idx (MOVWstoreidx ptr2 idx x _)) && isSamePtr(ptr, ptr2) -> x
+(MOVWloadshiftLL ptr idx [c] (MOVWstoreshiftLL ptr2 idx [d] x _)) && c==d && isSamePtr(ptr, ptr2) -> x
+(MOVWloadshiftRL ptr idx [c] (MOVWstoreshiftRL ptr2 idx [d] x _)) && c==d && isSamePtr(ptr, ptr2) -> x
+(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)
-(MOVWload [off1] {sym1} (ADDconst [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) ->
- (MOVWload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
-(MOVWstore [off1] {sym1} (ADDconst [off2] {sym2} ptr) val mem) && canMergeSym(sym1,sym2) ->
- (MOVWstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
+(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)
+(ADC x (MOVWconst [c]) flags) -> (ADCconst [c] x flags)
+(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)
+(XOR x (MOVWconst [c])) -> (XORconst [c] x)
+(BIC x (MOVWconst [c])) -> (BICconst [c] x)
+
+(SLL x (MOVWconst [c])) -> (SLLconst x [c&31]) // Note: I don't think we ever generate bad constant shifts (i.e. c>=32)
+(SRL x (MOVWconst [c])) -> (SRLconst x [c&31])
+(SRA x (MOVWconst [c])) -> (SRAconst x [c&31])
+
+(CMP x (MOVWconst [c])) -> (CMPconst [c] x)
+(CMP (MOVWconst [c]) x) -> (InvertFlags (CMPconst [c] x))
+
+// don't extend after proper load
+// MOVWreg instruction is not emitted if src and dst registers are same, but it ensures the type.
+(MOVBreg x:(MOVBload _ _)) -> (MOVWreg x)
+(MOVBUreg x:(MOVBUload _ _)) -> (MOVWreg x)
+(MOVHreg x:(MOVBload _ _)) -> (MOVWreg x)
+(MOVHreg x:(MOVBUload _ _)) -> (MOVWreg x)
+(MOVHreg x:(MOVHload _ _)) -> (MOVWreg x)
+(MOVHUreg x:(MOVBUload _ _)) -> (MOVWreg x)
+(MOVHUreg x:(MOVHUload _ _)) -> (MOVWreg x)
+
+// fold extensions and ANDs together
+(MOVBUreg (ANDconst [c] x)) -> (ANDconst [c&0xff] x)
+(MOVHUreg (ANDconst [c] x)) -> (ANDconst [c&0xffff] x)
+(MOVBreg (ANDconst [c] x)) && c & 0x80 == 0 -> (ANDconst [c&0x7f] x)
+(MOVHreg (ANDconst [c] x)) && c & 0x8000 == 0 -> (ANDconst [c&0x7fff] x)
+
+// fold double extensions
+(MOVBreg x:(MOVBreg _)) -> (MOVWreg x)
+(MOVBUreg x:(MOVBUreg _)) -> (MOVWreg x)
+(MOVHreg x:(MOVBreg _)) -> (MOVWreg x)
+(MOVHreg x:(MOVBUreg _)) -> (MOVWreg x)
+(MOVHreg x:(MOVHreg _)) -> (MOVWreg x)
+(MOVHUreg x:(MOVBUreg _)) -> (MOVWreg x)
+(MOVHUreg x:(MOVHUreg _)) -> (MOVWreg x)
+
+// don't extend before store
+(MOVBstore [off] {sym} ptr (MOVBreg x) mem) -> (MOVBstore [off] {sym} ptr x mem)
+(MOVBstore [off] {sym} ptr (MOVBUreg x) mem) -> (MOVBstore [off] {sym} ptr x mem)
+(MOVBstore [off] {sym} ptr (MOVHreg x) mem) -> (MOVBstore [off] {sym} ptr x mem)
+(MOVBstore [off] {sym} ptr (MOVHUreg x) mem) -> (MOVBstore [off] {sym} ptr x mem)
+(MOVHstore [off] {sym} ptr (MOVHreg x) mem) -> (MOVHstore [off] {sym} ptr x mem)
+(MOVHstore [off] {sym} ptr (MOVHUreg x) mem) -> (MOVHstore [off] {sym} ptr x mem)
+
+// if a register move has only 1 use, just use the same register without emitting instruction
+// MOVWnop doesn't emit instruction, only for ensuring the type.
+(MOVWreg x) && x.Uses == 1 -> (MOVWnop x)
+
+// mul by constant
+(MUL x (MOVWconst [c])) && int32(c) == -1 -> (RSBconst [0] x)
+(MUL _ (MOVWconst [0])) -> (MOVWconst [0])
+(MUL x (MOVWconst [1])) -> x
+(MUL x (MOVWconst [c])) && isPowerOfTwo(c) -> (SLLconst [log2(c)] x)
+(MUL x (MOVWconst [c])) && isPowerOfTwo(c-1) && int32(c) >= 3 -> (ADDshiftLL x x [log2(c-1)])
+(MUL x (MOVWconst [c])) && isPowerOfTwo(c+1) && int32(c) >= 7 -> (RSBshiftLL x x [log2(c+1)])
+(MUL x (MOVWconst [c])) && c%3 == 0 && isPowerOfTwo(c/3) && is32Bit(c) -> (SLLconst [log2(c/3)] (ADDshiftLL <x.Type> x x [1]))
+(MUL x (MOVWconst [c])) && c%5 == 0 && isPowerOfTwo(c/5) && is32Bit(c) -> (SLLconst [log2(c/5)] (ADDshiftLL <x.Type> x x [2]))
+(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)
+(MULA x (MOVWconst [c]) a) && isPowerOfTwo(c) -> (ADD (SLLconst <x.Type> [log2(c)] x) a)
+(MULA x (MOVWconst [c]) a) && isPowerOfTwo(c-1) && int32(c) >= 3 -> (ADD (ADDshiftLL <x.Type> x x [log2(c-1)]) a)
+(MULA x (MOVWconst [c]) a) && isPowerOfTwo(c+1) && int32(c) >= 7 -> (ADD (RSBshiftLL <x.Type> x x [log2(c+1)]) a)
+(MULA x (MOVWconst [c]) a) && c%3 == 0 && isPowerOfTwo(c/3) && is32Bit(c) -> (ADD (SLLconst <x.Type> [log2(c/3)] (ADDshiftLL <x.Type> x x [1])) a)
+(MULA x (MOVWconst [c]) a) && c%5 == 0 && isPowerOfTwo(c/5) && is32Bit(c) -> (ADD (SLLconst <x.Type> [log2(c/5)] (ADDshiftLL <x.Type> x x [2])) a)
+(MULA x (MOVWconst [c]) a) && c%7 == 0 && isPowerOfTwo(c/7) && is32Bit(c) -> (ADD (SLLconst <x.Type> [log2(c/7)] (RSBshiftLL <x.Type> x x [3])) a)
+(MULA x (MOVWconst [c]) a) && c%9 == 0 && isPowerOfTwo(c/9) && is32Bit(c) -> (ADD (SLLconst <x.Type> [log2(c/9)] (ADDshiftLL <x.Type> x x [3])) a)
+
+(MULA (MOVWconst [c]) x a) && int32(c) == -1 -> (SUB a x)
+(MULA (MOVWconst [0]) _ a) -> a
+(MULA (MOVWconst [1]) x a) -> (ADD x a)
+(MULA (MOVWconst [c]) x a) && isPowerOfTwo(c) -> (ADD (SLLconst <x.Type> [log2(c)] x) a)
+(MULA (MOVWconst [c]) x a) && isPowerOfTwo(c-1) && int32(c) >= 3 -> (ADD (ADDshiftLL <x.Type> x x [log2(c-1)]) a)
+(MULA (MOVWconst [c]) x a) && isPowerOfTwo(c+1) && int32(c) >= 7 -> (ADD (RSBshiftLL <x.Type> x x [log2(c+1)]) a)
+(MULA (MOVWconst [c]) x a) && c%3 == 0 && isPowerOfTwo(c/3) && is32Bit(c) -> (ADD (SLLconst <x.Type> [log2(c/3)] (ADDshiftLL <x.Type> x x [1])) a)
+(MULA (MOVWconst [c]) x a) && c%5 == 0 && isPowerOfTwo(c/5) && is32Bit(c) -> (ADD (SLLconst <x.Type> [log2(c/5)] (ADDshiftLL <x.Type> x x [2])) a)
+(MULA (MOVWconst [c]) x a) && c%7 == 0 && isPowerOfTwo(c/7) && is32Bit(c) -> (ADD (SLLconst <x.Type> [log2(c/7)] (RSBshiftLL <x.Type> x x [3])) a)
+(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)
+
+// constant comparisons
+(CMPconst (MOVWconst [x]) [y]) && int32(x)==int32(y) -> (FlagEQ)
+(CMPconst (MOVWconst [x]) [y]) && int32(x)<int32(y) && uint32(x)<uint32(y) -> (FlagLT_ULT)
+(CMPconst (MOVWconst [x]) [y]) && int32(x)<int32(y) && uint32(x)>uint32(y) -> (FlagLT_UGT)
+(CMPconst (MOVWconst [x]) [y]) && int32(x)>int32(y) && uint32(x)<uint32(y) -> (FlagGT_ULT)
+(CMPconst (MOVWconst [x]) [y]) && int32(x)>int32(y) && uint32(x)>uint32(y) -> (FlagGT_UGT)
+
+// other known comparisons
+(CMPconst (MOVBUreg _) [c]) && 0xff < c -> (FlagLT_ULT)
+(CMPconst (MOVHUreg _) [c]) && 0xffff < c -> (FlagLT_ULT)
+(CMPconst (ANDconst _ [m]) [n]) && 0 <= int32(m) && int32(m) < int32(n) -> (FlagLT_ULT)
+(CMPconst (SRLconst _ [c]) [n]) && 0 <= n && 0 < c && c <= 32 && (1<<uint32(32-c)) <= uint32(n) -> (FlagLT_ULT)
+
+// absorb flag constants into branches
+(EQ (FlagEQ) yes no) -> (First nil yes no)
+(EQ (FlagLT_ULT) yes no) -> (First nil no yes)
+(EQ (FlagLT_UGT) yes no) -> (First nil no yes)
+(EQ (FlagGT_ULT) yes no) -> (First nil no yes)
+(EQ (FlagGT_UGT) yes no) -> (First nil no yes)
+
+(NE (FlagEQ) yes no) -> (First nil no yes)
+(NE (FlagLT_ULT) yes no) -> (First nil yes no)
+(NE (FlagLT_UGT) yes no) -> (First nil yes no)
+(NE (FlagGT_ULT) yes no) -> (First nil yes no)
+(NE (FlagGT_UGT) yes no) -> (First nil yes no)
+
+(LT (FlagEQ) yes no) -> (First nil no yes)
+(LT (FlagLT_ULT) yes no) -> (First nil yes no)
+(LT (FlagLT_UGT) yes no) -> (First nil yes no)
+(LT (FlagGT_ULT) yes no) -> (First nil no yes)
+(LT (FlagGT_UGT) yes no) -> (First nil no yes)
+
+(LE (FlagEQ) yes no) -> (First nil yes no)
+(LE (FlagLT_ULT) yes no) -> (First nil yes no)
+(LE (FlagLT_UGT) yes no) -> (First nil yes no)
+(LE (FlagGT_ULT) yes no) -> (First nil no yes)
+(LE (FlagGT_UGT) yes no) -> (First nil no yes)
+
+(GT (FlagEQ) yes no) -> (First nil no yes)
+(GT (FlagLT_ULT) yes no) -> (First nil no yes)
+(GT (FlagLT_UGT) yes no) -> (First nil no yes)
+(GT (FlagGT_ULT) yes no) -> (First nil yes no)
+(GT (FlagGT_UGT) yes no) -> (First nil yes no)
+
+(GE (FlagEQ) yes no) -> (First nil yes no)
+(GE (FlagLT_ULT) yes no) -> (First nil no yes)
+(GE (FlagLT_UGT) yes no) -> (First nil no yes)
+(GE (FlagGT_ULT) yes no) -> (First nil yes no)
+(GE (FlagGT_UGT) yes no) -> (First nil yes no)
+
+(ULT (FlagEQ) yes no) -> (First nil no yes)
+(ULT (FlagLT_ULT) yes no) -> (First nil yes no)
+(ULT (FlagLT_UGT) yes no) -> (First nil no yes)
+(ULT (FlagGT_ULT) yes no) -> (First nil yes no)
+(ULT (FlagGT_UGT) yes no) -> (First nil no yes)
+
+(ULE (FlagEQ) yes no) -> (First nil yes no)
+(ULE (FlagLT_ULT) yes no) -> (First nil yes no)
+(ULE (FlagLT_UGT) yes no) -> (First nil no yes)
+(ULE (FlagGT_ULT) yes no) -> (First nil yes no)
+(ULE (FlagGT_UGT) yes no) -> (First nil no yes)
+
+(UGT (FlagEQ) yes no) -> (First nil no yes)
+(UGT (FlagLT_ULT) yes no) -> (First nil no yes)
+(UGT (FlagLT_UGT) yes no) -> (First nil yes no)
+(UGT (FlagGT_ULT) yes no) -> (First nil no yes)
+(UGT (FlagGT_UGT) yes no) -> (First nil yes no)
+
+(UGE (FlagEQ) yes no) -> (First nil yes no)
+(UGE (FlagLT_ULT) yes no) -> (First nil no yes)
+(UGE (FlagLT_UGT) yes no) -> (First nil yes no)
+(UGE (FlagGT_ULT) yes no) -> (First nil no yes)
+(UGE (FlagGT_UGT) yes no) -> (First nil yes no)
+
+// absorb InvertFlags into branches
+(LT (InvertFlags cmp) yes no) -> (GT cmp yes no)
+(GT (InvertFlags cmp) yes no) -> (LT cmp yes no)
+(LE (InvertFlags cmp) yes no) -> (GE cmp yes no)
+(GE (InvertFlags cmp) yes no) -> (LE cmp yes no)
+(ULT (InvertFlags cmp) yes no) -> (UGT cmp yes no)
+(UGT (InvertFlags cmp) yes no) -> (ULT cmp yes no)
+(ULE (InvertFlags cmp) yes no) -> (UGE cmp yes no)
+(UGE (InvertFlags cmp) yes no) -> (ULE cmp yes no)
+(EQ (InvertFlags cmp) yes no) -> (EQ cmp yes no)
+(NE (InvertFlags cmp) yes no) -> (NE cmp yes no)
+
+// absorb flag constants into boolean values
+(Equal (FlagEQ)) -> (MOVWconst [1])
+(Equal (FlagLT_ULT)) -> (MOVWconst [0])
+(Equal (FlagLT_UGT)) -> (MOVWconst [0])
+(Equal (FlagGT_ULT)) -> (MOVWconst [0])
+(Equal (FlagGT_UGT)) -> (MOVWconst [0])
+
+(NotEqual (FlagEQ)) -> (MOVWconst [0])
+(NotEqual (FlagLT_ULT)) -> (MOVWconst [1])
+(NotEqual (FlagLT_UGT)) -> (MOVWconst [1])
+(NotEqual (FlagGT_ULT)) -> (MOVWconst [1])
+(NotEqual (FlagGT_UGT)) -> (MOVWconst [1])
+
+(LessThan (FlagEQ)) -> (MOVWconst [0])
+(LessThan (FlagLT_ULT)) -> (MOVWconst [1])
+(LessThan (FlagLT_UGT)) -> (MOVWconst [1])
+(LessThan (FlagGT_ULT)) -> (MOVWconst [0])
+(LessThan (FlagGT_UGT)) -> (MOVWconst [0])
+
+(LessThanU (FlagEQ)) -> (MOVWconst [0])
+(LessThanU (FlagLT_ULT)) -> (MOVWconst [1])
+(LessThanU (FlagLT_UGT)) -> (MOVWconst [0])
+(LessThanU (FlagGT_ULT)) -> (MOVWconst [1])
+(LessThanU (FlagGT_UGT)) -> (MOVWconst [0])
+
+(LessEqual (FlagEQ)) -> (MOVWconst [1])
+(LessEqual (FlagLT_ULT)) -> (MOVWconst [1])
+(LessEqual (FlagLT_UGT)) -> (MOVWconst [1])
+(LessEqual (FlagGT_ULT)) -> (MOVWconst [0])
+(LessEqual (FlagGT_UGT)) -> (MOVWconst [0])
+
+(LessEqualU (FlagEQ)) -> (MOVWconst [1])
+(LessEqualU (FlagLT_ULT)) -> (MOVWconst [1])
+(LessEqualU (FlagLT_UGT)) -> (MOVWconst [0])
+(LessEqualU (FlagGT_ULT)) -> (MOVWconst [1])
+(LessEqualU (FlagGT_UGT)) -> (MOVWconst [0])
+
+(GreaterThan (FlagEQ)) -> (MOVWconst [0])
+(GreaterThan (FlagLT_ULT)) -> (MOVWconst [0])
+(GreaterThan (FlagLT_UGT)) -> (MOVWconst [0])
+(GreaterThan (FlagGT_ULT)) -> (MOVWconst [1])
+(GreaterThan (FlagGT_UGT)) -> (MOVWconst [1])
+
+(GreaterThanU (FlagEQ)) -> (MOVWconst [0])
+(GreaterThanU (FlagLT_ULT)) -> (MOVWconst [0])
+(GreaterThanU (FlagLT_UGT)) -> (MOVWconst [1])
+(GreaterThanU (FlagGT_ULT)) -> (MOVWconst [0])
+(GreaterThanU (FlagGT_UGT)) -> (MOVWconst [1])
+
+(GreaterEqual (FlagEQ)) -> (MOVWconst [1])
+(GreaterEqual (FlagLT_ULT)) -> (MOVWconst [0])
+(GreaterEqual (FlagLT_UGT)) -> (MOVWconst [0])
+(GreaterEqual (FlagGT_ULT)) -> (MOVWconst [1])
+(GreaterEqual (FlagGT_UGT)) -> (MOVWconst [1])
+
+(GreaterEqualU (FlagEQ)) -> (MOVWconst [1])
+(GreaterEqualU (FlagLT_ULT)) -> (MOVWconst [0])
+(GreaterEqualU (FlagLT_UGT)) -> (MOVWconst [1])
+(GreaterEqualU (FlagGT_ULT)) -> (MOVWconst [0])
+(GreaterEqualU (FlagGT_UGT)) -> (MOVWconst [1])
+
+// absorb InvertFlags into boolean values
+(Equal (InvertFlags x)) -> (Equal x)
+(NotEqual (InvertFlags x)) -> (NotEqual x)
+(LessThan (InvertFlags x)) -> (GreaterThan x)
+(LessThanU (InvertFlags x)) -> (GreaterThanU x)
+(GreaterThan (InvertFlags x)) -> (LessThan x)
+(GreaterThanU (InvertFlags x)) -> (LessThanU x)
+(LessEqual (InvertFlags x)) -> (GreaterEqual x)
+(LessEqualU (InvertFlags x)) -> (GreaterEqualU x)
+(GreaterEqual (InvertFlags x)) -> (LessEqual x)
+(GreaterEqualU (InvertFlags x)) -> (LessEqualU x)
+
+// absorb flag constants into conditional instructions
+(CMOVWLSconst _ (FlagEQ) [c]) -> (MOVWconst [c])
+(CMOVWLSconst _ (FlagLT_ULT) [c]) -> (MOVWconst [c])
+(CMOVWLSconst x (FlagLT_UGT)) -> x
+(CMOVWLSconst _ (FlagGT_ULT) [c]) -> (MOVWconst [c])
+(CMOVWLSconst x (FlagGT_UGT)) -> x
+
+(CMOVWHSconst _ (FlagEQ) [c]) -> (MOVWconst [c])
+(CMOVWHSconst x (FlagLT_ULT)) -> x
+(CMOVWHSconst _ (FlagLT_UGT) [c]) -> (MOVWconst [c])
+(CMOVWHSconst x (FlagGT_ULT)) -> x
+(CMOVWHSconst _ (FlagGT_UGT) [c]) -> (MOVWconst [c])
+
+(CMOVWLSconst x (InvertFlags flags) [c]) -> (CMOVWHSconst x flags [c])
+(CMOVWHSconst x (InvertFlags flags) [c]) -> (CMOVWLSconst x flags [c])
+
+(SRAcond x _ (FlagEQ)) -> (SRAconst x [31])
+(SRAcond x y (FlagLT_ULT)) -> (SRA x y)
+(SRAcond x _ (FlagLT_UGT)) -> (SRAconst x [31])
+(SRAcond x y (FlagGT_ULT)) -> (SRA x y)
+(SRAcond x _ (FlagGT_UGT)) -> (SRAconst x [31])
+
+// remove redundant *const ops
+(ADDconst [0] x) -> x
+(SUBconst [0] x) -> x
+(ANDconst [0] _) -> (MOVWconst [0])
+(ANDconst [c] x) && int32(c)==-1 -> x
+(ORconst [0] x) -> x
+(ORconst [c] _) && int32(c)==-1 -> (MOVWconst [-1])
+(XORconst [0] x) -> x
+(BICconst [0] x) -> x
+(BICconst [c] _) && int32(c)==-1 -> (MOVWconst [0])
+
+// generic constant folding
+(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)
+(ADDconst [c] (RSBconst [d] x)) -> (RSBconst [int64(int32(c+d))] x)
+(ADCconst [c] (ADDconst [d] x) flags) -> (ADCconst [int64(int32(c+d))] x flags)
+(ADCconst [c] (SUBconst [d] x) flags) -> (ADCconst [int64(int32(c-d))] x flags)
+(SUBconst [c] (MOVWconst [d])) -> (MOVWconst [int64(int32(d-c))])
+(SUBconst [c] (SUBconst [d] x)) -> (ADDconst [int64(int32(-c-d))] x)
+(SUBconst [c] (ADDconst [d] x)) -> (ADDconst [int64(int32(-c+d))] x)
+(SUBconst [c] (RSBconst [d] x)) -> (RSBconst [int64(int32(-c+d))] x)
+(SBCconst [c] (ADDconst [d] x) flags) -> (SBCconst [int64(int32(c-d))] x flags)
+(SBCconst [c] (SUBconst [d] x) flags) -> (SBCconst [int64(int32(c+d))] x flags)
+(RSBconst [c] (MOVWconst [d])) -> (MOVWconst [int64(int32(c-d))])
+(RSBconst [c] (RSBconst [d] x)) -> (ADDconst [int64(int32(c-d))] x)
+(RSBconst [c] (ADDconst [d] x)) -> (RSBconst [int64(int32(c-d))] x)
+(RSBconst [c] (SUBconst [d] x)) -> (RSBconst [int64(int32(c+d))] x)
+(RSCconst [c] (ADDconst [d] x) flags) -> (RSCconst [int64(int32(c-d))] x flags)
+(RSCconst [c] (SUBconst [d] x) flags) -> (RSCconst [int64(int32(c+d))] x flags)
+(SLLconst [c] (MOVWconst [d])) -> (MOVWconst [int64(uint32(d)<<uint64(c))])
+(SRLconst [c] (MOVWconst [d])) -> (MOVWconst [int64(uint32(d)>>uint64(c))])
+(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))])
+(ANDconst [c] (MOVWconst [d])) -> (MOVWconst [c&d])
+(ANDconst [c] (ANDconst [d] x)) -> (ANDconst [c&d] x)
+(ORconst [c] (MOVWconst [d])) -> (MOVWconst [c|d])
+(ORconst [c] (ORconst [d] x)) -> (ORconst [c|d] x)
+(XORconst [c] (MOVWconst [d])) -> (MOVWconst [c^d])
+(XORconst [c] (XORconst [d] x)) -> (XORconst [c^d] x)
+(BICconst [c] (MOVWconst [d])) -> (MOVWconst [d&^c])
+(MVN (MOVWconst [c])) -> (MOVWconst [^c])
+(MOVBreg (MOVWconst [c])) -> (MOVWconst [int64(int8(c))])
+(MOVBUreg (MOVWconst [c])) -> (MOVWconst [int64(uint8(c))])
+(MOVHreg (MOVWconst [c])) -> (MOVWconst [int64(int16(c))])
+(MOVHUreg (MOVWconst [c])) -> (MOVWconst [int64(uint16(c))])
+(MOVWreg (MOVWconst [c])) -> (MOVWconst [c])
+
+// 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)
+(ADC (SRLconst [c] y) x flags) -> (ADCshiftRL x y [c] flags)
+(ADC x (SRAconst [c] y) flags) -> (ADCshiftRA x y [c] flags)
+(ADC (SRAconst [c] y) x flags) -> (ADCshiftRA x y [c] flags)
+(ADC x (SLL y z) flags) -> (ADCshiftLLreg x y z flags)
+(ADC (SLL y z) x flags) -> (ADCshiftLLreg x y z flags)
+(ADC x (SRL y z) flags) -> (ADCshiftRLreg x y z flags)
+(ADC (SRL y z) x flags) -> (ADCshiftRLreg x y z flags)
+(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])
+(SUB (SRLconst [c] y) x) -> (RSBshiftRL x y [c])
+(SUB x (SRAconst [c] y)) -> (SUBshiftRA x y [c])
+(SUB (SRAconst [c] y) x) -> (RSBshiftRA x y [c])
+(SUB x (SLL y z)) -> (SUBshiftLLreg x y z)
+(SUB (SLL y z) x) -> (RSBshiftLLreg x y z)
+(SUB x (SRL y z)) -> (SUBshiftRLreg x y z)
+(SUB (SRL y z) x) -> (RSBshiftRLreg x y z)
+(SUB x (SRA y z)) -> (SUBshiftRAreg x y z)
+(SUB (SRA y z) x) -> (RSBshiftRAreg x y z)
+(SBC x (SLLconst [c] y) flags) -> (SBCshiftLL x y [c] flags)
+(SBC (SLLconst [c] y) x flags) -> (RSCshiftLL x y [c] flags)
+(SBC x (SRLconst [c] y) flags) -> (SBCshiftRL x y [c] flags)
+(SBC (SRLconst [c] y) x flags) -> (RSCshiftRL x y [c] flags)
+(SBC x (SRAconst [c] y) flags) -> (SBCshiftRA x y [c] flags)
+(SBC (SRAconst [c] y) x flags) -> (RSCshiftRA x y [c] flags)
+(SBC x (SLL y z) flags) -> (SBCshiftLLreg x y z flags)
+(SBC (SLL y z) x flags) -> (RSCshiftLLreg x y z flags)
+(SBC x (SRL y z) flags) -> (SBCshiftRLreg x y z flags)
+(SBC (SRL y z) x flags) -> (RSCshiftRLreg x y z flags)
+(SBC x (SRA y z) flags) -> (SBCshiftRAreg x y z flags)
+(SBC (SRA y z) x flags) -> (RSCshiftRAreg x y z flags)
+(SUBS x (SLLconst [c] y)) -> (SUBSshiftLL x y [c])
+(SUBS (SLLconst [c] y) x) -> (RSBSshiftLL x y [c])
+(SUBS x (SRLconst [c] y)) -> (SUBSshiftRL x y [c])
+(SUBS (SRLconst [c] y) x) -> (RSBSshiftRL x y [c])
+(SUBS x (SRAconst [c] y)) -> (SUBSshiftRA x y [c])
+(SUBS (SRAconst [c] y) x) -> (RSBSshiftRA x y [c])
+(SUBS x (SLL y z)) -> (SUBSshiftLLreg x y z)
+(SUBS (SLL y z) x) -> (RSBSshiftLLreg x y z)
+(SUBS x (SRL y z)) -> (SUBSshiftRLreg x y z)
+(SUBS (SRL y z) x) -> (RSBSshiftRLreg x y z)
+(SUBS x (SRA y z)) -> (SUBSshiftRAreg x y z)
+(SUBS (SRA y z) x) -> (RSBSshiftRAreg x y z)
+(RSB x (SLLconst [c] y)) -> (RSBshiftLL x y [c])
+(RSB (SLLconst [c] y) x) -> (SUBshiftLL x y [c])
+(RSB x (SRLconst [c] y)) -> (RSBshiftRL x y [c])
+(RSB (SRLconst [c] y) x) -> (SUBshiftRL x y [c])
+(RSB x (SRAconst [c] y)) -> (RSBshiftRA x y [c])
+(RSB (SRAconst [c] y) x) -> (SUBshiftRA x y [c])
+(RSB x (SLL y z)) -> (RSBshiftLLreg x y z)
+(RSB (SLL y z) x) -> (SUBshiftLLreg x y z)
+(RSB x (SRL y z)) -> (RSBshiftRLreg x y z)
+(RSB (SRL y z) x) -> (SUBshiftRLreg x y z)
+(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])
+(BIC x (SLL y z)) -> (BICshiftLLreg x y z)
+(BIC x (SRL y z)) -> (BICshiftRLreg x y z)
+(BIC x (SRA y z)) -> (BICshiftRAreg x y z)
+(MVN (SLLconst [c] x)) -> (MVNshiftLL x [c])
+(MVN (SRLconst [c] x)) -> (MVNshiftRL x [c])
+(MVN (SRAconst [c] x)) -> (MVNshiftRA x [c])
+(MVN (SLL x y)) -> (MVNshiftLLreg x y)
+(MVN (SRL x y)) -> (MVNshiftRLreg x y)
+(MVN (SRA x y)) -> (MVNshiftRAreg x y)
+
+(CMP x (SLLconst [c] y)) -> (CMPshiftLL x y [c])
+(CMP (SLLconst [c] y) x) -> (InvertFlags (CMPshiftLL x y [c]))
+(CMP x (SRLconst [c] y)) -> (CMPshiftRL x y [c])
+(CMP (SRLconst [c] y) x) -> (InvertFlags (CMPshiftRL x y [c]))
+(CMP x (SRAconst [c] y)) -> (CMPshiftRA x y [c])
+(CMP (SRAconst [c] y) x) -> (InvertFlags (CMPshiftRA x y [c]))
+(CMP x (SLL y z)) -> (CMPshiftLLreg x y z)
+(CMP (SLL y z) x) -> (InvertFlags (CMPshiftLLreg x y z))
+(CMP x (SRL y z)) -> (CMPshiftRLreg x y z)
+(CMP (SRL y z) x) -> (InvertFlags (CMPshiftRLreg x y z))
+(CMP x (SRA y z)) -> (CMPshiftRAreg x y z)
+(CMP (SRA y z) x) -> (InvertFlags (CMPshiftRAreg x y z))
+
+// prefer *const ops to *shift ops
+(ADDshiftLL (MOVWconst [c]) x [d]) -> (ADDconst [c] (SLLconst <x.Type> x [d]))
+(ADDshiftRL (MOVWconst [c]) x [d]) -> (ADDconst [c] (SRLconst <x.Type> x [d]))
+(ADDshiftRA (MOVWconst [c]) x [d]) -> (ADDconst [c] (SRAconst <x.Type> x [d]))
+(ADCshiftLL (MOVWconst [c]) x [d] flags) -> (ADCconst [c] (SLLconst <x.Type> x [d]) flags)
+(ADCshiftRL (MOVWconst [c]) x [d] flags) -> (ADCconst [c] (SRLconst <x.Type> x [d]) flags)
+(ADCshiftRA (MOVWconst [c]) x [d] flags) -> (ADCconst [c] (SRAconst <x.Type> x [d]) flags)
+(ADDSshiftLL (MOVWconst [c]) x [d]) -> (ADDSconst [c] (SLLconst <x.Type> x [d]))
+(ADDSshiftRL (MOVWconst [c]) x [d]) -> (ADDSconst [c] (SRLconst <x.Type> x [d]))
+(ADDSshiftRA (MOVWconst [c]) x [d]) -> (ADDSconst [c] (SRAconst <x.Type> x [d]))
+(SUBshiftLL (MOVWconst [c]) x [d]) -> (RSBconst [c] (SLLconst <x.Type> x [d]))
+(SUBshiftRL (MOVWconst [c]) x [d]) -> (RSBconst [c] (SRLconst <x.Type> x [d]))
+(SUBshiftRA (MOVWconst [c]) x [d]) -> (RSBconst [c] (SRAconst <x.Type> x [d]))
+(SBCshiftLL (MOVWconst [c]) x [d] flags) -> (RSCconst [c] (SLLconst <x.Type> x [d]) flags)
+(SBCshiftRL (MOVWconst [c]) x [d] flags) -> (RSCconst [c] (SRLconst <x.Type> x [d]) flags)
+(SBCshiftRA (MOVWconst [c]) x [d] flags) -> (RSCconst [c] (SRAconst <x.Type> x [d]) flags)
+(SUBSshiftLL (MOVWconst [c]) x [d]) -> (RSBSconst [c] (SLLconst <x.Type> x [d]))
+(SUBSshiftRL (MOVWconst [c]) x [d]) -> (RSBSconst [c] (SRLconst <x.Type> x [d]))
+(SUBSshiftRA (MOVWconst [c]) x [d]) -> (RSBSconst [c] (SRAconst <x.Type> x [d]))
+(RSBshiftLL (MOVWconst [c]) x [d]) -> (SUBconst [c] (SLLconst <x.Type> x [d]))
+(RSBshiftRL (MOVWconst [c]) x [d]) -> (SUBconst [c] (SRLconst <x.Type> x [d]))
+(RSBshiftRA (MOVWconst [c]) x [d]) -> (SUBconst [c] (SRAconst <x.Type> x [d]))
+(RSCshiftLL (MOVWconst [c]) x [d] flags) -> (SBCconst [c] (SLLconst <x.Type> x [d]) flags)
+(RSCshiftRL (MOVWconst [c]) x [d] flags) -> (SBCconst [c] (SRLconst <x.Type> x [d]) flags)
+(RSCshiftRA (MOVWconst [c]) x [d] flags) -> (SBCconst [c] (SRAconst <x.Type> x [d]) flags)
+(RSBSshiftLL (MOVWconst [c]) x [d]) -> (SUBSconst [c] (SLLconst <x.Type> x [d]))
+(RSBSshiftRL (MOVWconst [c]) x [d]) -> (SUBSconst [c] (SRLconst <x.Type> x [d]))
+(RSBSshiftRA (MOVWconst [c]) x [d]) -> (SUBSconst [c] (SRAconst <x.Type> x [d]))
+(ANDshiftLL (MOVWconst [c]) x [d]) -> (ANDconst [c] (SLLconst <x.Type> x [d]))
+(ANDshiftRL (MOVWconst [c]) x [d]) -> (ANDconst [c] (SRLconst <x.Type> x [d]))
+(ANDshiftRA (MOVWconst [c]) x [d]) -> (ANDconst [c] (SRAconst <x.Type> x [d]))
+(ORshiftLL (MOVWconst [c]) x [d]) -> (ORconst [c] (SLLconst <x.Type> x [d]))
+(ORshiftRL (MOVWconst [c]) x [d]) -> (ORconst [c] (SRLconst <x.Type> x [d]))
+(ORshiftRA (MOVWconst [c]) x [d]) -> (ORconst [c] (SRAconst <x.Type> x [d]))
+(XORshiftLL (MOVWconst [c]) x [d]) -> (XORconst [c] (SLLconst <x.Type> x [d]))
+(XORshiftRL (MOVWconst [c]) x [d]) -> (XORconst [c] (SRLconst <x.Type> x [d]))
+(XORshiftRA (MOVWconst [c]) x [d]) -> (XORconst [c] (SRAconst <x.Type> x [d]))
+(XORshiftRR (MOVWconst [c]) x [d]) -> (XORconst [c] (SRRconst <x.Type> x [d]))
+(CMPshiftLL (MOVWconst [c]) x [d]) -> (InvertFlags (CMPconst [c] (SLLconst <x.Type> x [d])))
+(CMPshiftRL (MOVWconst [c]) x [d]) -> (InvertFlags (CMPconst [c] (SRLconst <x.Type> x [d])))
+(CMPshiftRA (MOVWconst [c]) x [d]) -> (InvertFlags (CMPconst [c] (SRAconst <x.Type> x [d])))
+
+(ADDshiftLLreg (MOVWconst [c]) x y) -> (ADDconst [c] (SLL <x.Type> x y))
+(ADDshiftRLreg (MOVWconst [c]) x y) -> (ADDconst [c] (SRL <x.Type> x y))
+(ADDshiftRAreg (MOVWconst [c]) x y) -> (ADDconst [c] (SRA <x.Type> x y))
+(ADCshiftLLreg (MOVWconst [c]) x y flags) -> (ADCconst [c] (SLL <x.Type> x y) flags)
+(ADCshiftRLreg (MOVWconst [c]) x y flags) -> (ADCconst [c] (SRL <x.Type> x y) flags)
+(ADCshiftRAreg (MOVWconst [c]) x y flags) -> (ADCconst [c] (SRA <x.Type> x y) flags)
+(ADDSshiftLLreg (MOVWconst [c]) x y) -> (ADDSconst [c] (SLL <x.Type> x y))
+(ADDSshiftRLreg (MOVWconst [c]) x y) -> (ADDSconst [c] (SRL <x.Type> x y))
+(ADDSshiftRAreg (MOVWconst [c]) x y) -> (ADDSconst [c] (SRA <x.Type> x y))
+(SUBshiftLLreg (MOVWconst [c]) x y) -> (RSBconst [c] (SLL <x.Type> x y))
+(SUBshiftRLreg (MOVWconst [c]) x y) -> (RSBconst [c] (SRL <x.Type> x y))
+(SUBshiftRAreg (MOVWconst [c]) x y) -> (RSBconst [c] (SRA <x.Type> x y))
+(SBCshiftLLreg (MOVWconst [c]) x y flags) -> (RSCconst [c] (SLL <x.Type> x y) flags)
+(SBCshiftRLreg (MOVWconst [c]) x y flags) -> (RSCconst [c] (SRL <x.Type> x y) flags)
+(SBCshiftRAreg (MOVWconst [c]) x y flags) -> (RSCconst [c] (SRA <x.Type> x y) flags)
+(SUBSshiftLLreg (MOVWconst [c]) x y) -> (RSBSconst [c] (SLL <x.Type> x y))
+(SUBSshiftRLreg (MOVWconst [c]) x y) -> (RSBSconst [c] (SRL <x.Type> x y))
+(SUBSshiftRAreg (MOVWconst [c]) x y) -> (RSBSconst [c] (SRA <x.Type> x y))
+(RSBshiftLLreg (MOVWconst [c]) x y) -> (SUBconst [c] (SLL <x.Type> x y))
+(RSBshiftRLreg (MOVWconst [c]) x y) -> (SUBconst [c] (SRL <x.Type> x y))
+(RSBshiftRAreg (MOVWconst [c]) x y) -> (SUBconst [c] (SRA <x.Type> x y))
+(RSCshiftLLreg (MOVWconst [c]) x y flags) -> (SBCconst [c] (SLL <x.Type> x y) flags)
+(RSCshiftRLreg (MOVWconst [c]) x y flags) -> (SBCconst [c] (SRL <x.Type> x y) flags)
+(RSCshiftRAreg (MOVWconst [c]) x y flags) -> (SBCconst [c] (SRA <x.Type> x y) flags)
+(RSBSshiftLLreg (MOVWconst [c]) x y) -> (SUBSconst [c] (SLL <x.Type> x y))
+(RSBSshiftRLreg (MOVWconst [c]) x y) -> (SUBSconst [c] (SRL <x.Type> x y))
+(RSBSshiftRAreg (MOVWconst [c]) x y) -> (SUBSconst [c] (SRA <x.Type> x y))
+(ANDshiftLLreg (MOVWconst [c]) x y) -> (ANDconst [c] (SLL <x.Type> x y))
+(ANDshiftRLreg (MOVWconst [c]) x y) -> (ANDconst [c] (SRL <x.Type> x y))
+(ANDshiftRAreg (MOVWconst [c]) x y) -> (ANDconst [c] (SRA <x.Type> x y))
+(ORshiftLLreg (MOVWconst [c]) x y) -> (ORconst [c] (SLL <x.Type> x y))
+(ORshiftRLreg (MOVWconst [c]) x y) -> (ORconst [c] (SRL <x.Type> x y))
+(ORshiftRAreg (MOVWconst [c]) x y) -> (ORconst [c] (SRA <x.Type> x y))
+(XORshiftLLreg (MOVWconst [c]) x y) -> (XORconst [c] (SLL <x.Type> x y))
+(XORshiftRLreg (MOVWconst [c]) x y) -> (XORconst [c] (SRL <x.Type> x y))
+(XORshiftRAreg (MOVWconst [c]) x y) -> (XORconst [c] (SRA <x.Type> x y))
+(CMPshiftLLreg (MOVWconst [c]) x y) -> (InvertFlags (CMPconst [c] (SLL <x.Type> x y)))
+(CMPshiftRLreg (MOVWconst [c]) x y) -> (InvertFlags (CMPconst [c] (SRL <x.Type> x y)))
+(CMPshiftRAreg (MOVWconst [c]) x y) -> (InvertFlags (CMPconst [c] (SRA <x.Type> x y)))
+
+// constant folding in *shift ops
+(ADDshiftLL x (MOVWconst [c]) [d]) -> (ADDconst x [int64(uint32(c)<<uint64(d))])
+(ADDshiftRL x (MOVWconst [c]) [d]) -> (ADDconst x [int64(uint32(c)>>uint64(d))])
+(ADDshiftRA x (MOVWconst [c]) [d]) -> (ADDconst x [int64(int32(c)>>uint64(d))])
+(ADCshiftLL x (MOVWconst [c]) [d] flags) -> (ADCconst x [int64(uint32(c)<<uint64(d))] flags)
+(ADCshiftRL x (MOVWconst [c]) [d] flags) -> (ADCconst x [int64(uint32(c)>>uint64(d))] flags)
+(ADCshiftRA x (MOVWconst [c]) [d] flags) -> (ADCconst x [int64(int32(c)>>uint64(d))] flags)
+(ADDSshiftLL x (MOVWconst [c]) [d]) -> (ADDSconst x [int64(uint32(c)<<uint64(d))])
+(ADDSshiftRL x (MOVWconst [c]) [d]) -> (ADDSconst x [int64(uint32(c)>>uint64(d))])
+(ADDSshiftRA x (MOVWconst [c]) [d]) -> (ADDSconst x [int64(int32(c)>>uint64(d))])
+(SUBshiftLL x (MOVWconst [c]) [d]) -> (SUBconst x [int64(uint32(c)<<uint64(d))])
+(SUBshiftRL x (MOVWconst [c]) [d]) -> (SUBconst x [int64(uint32(c)>>uint64(d))])
+(SUBshiftRA x (MOVWconst [c]) [d]) -> (SUBconst x [int64(int32(c)>>uint64(d))])
+(SBCshiftLL x (MOVWconst [c]) [d] flags) -> (SBCconst x [int64(uint32(c)<<uint64(d))] flags)
+(SBCshiftRL x (MOVWconst [c]) [d] flags) -> (SBCconst x [int64(uint32(c)>>uint64(d))] flags)
+(SBCshiftRA x (MOVWconst [c]) [d] flags) -> (SBCconst x [int64(int32(c)>>uint64(d))] flags)
+(SUBSshiftLL x (MOVWconst [c]) [d]) -> (SUBSconst x [int64(uint32(c)<<uint64(d))])
+(SUBSshiftRL x (MOVWconst [c]) [d]) -> (SUBSconst x [int64(uint32(c)>>uint64(d))])
+(SUBSshiftRA x (MOVWconst [c]) [d]) -> (SUBSconst x [int64(int32(c)>>uint64(d))])
+(RSBshiftLL x (MOVWconst [c]) [d]) -> (RSBconst x [int64(uint32(c)<<uint64(d))])
+(RSBshiftRL x (MOVWconst [c]) [d]) -> (RSBconst x [int64(uint32(c)>>uint64(d))])
+(RSBshiftRA x (MOVWconst [c]) [d]) -> (RSBconst x [int64(int32(c)>>uint64(d))])
+(RSCshiftLL x (MOVWconst [c]) [d] flags) -> (RSCconst x [int64(uint32(c)<<uint64(d))] flags)
+(RSCshiftRL x (MOVWconst [c]) [d] flags) -> (RSCconst x [int64(uint32(c)>>uint64(d))] flags)
+(RSCshiftRA x (MOVWconst [c]) [d] flags) -> (RSCconst x [int64(int32(c)>>uint64(d))] flags)
+(RSBSshiftLL x (MOVWconst [c]) [d]) -> (RSBSconst x [int64(uint32(c)<<uint64(d))])
+(RSBSshiftRL x (MOVWconst [c]) [d]) -> (RSBSconst x [int64(uint32(c)>>uint64(d))])
+(RSBSshiftRA x (MOVWconst [c]) [d]) -> (RSBSconst x [int64(int32(c)>>uint64(d))])
+(ANDshiftLL x (MOVWconst [c]) [d]) -> (ANDconst x [int64(uint32(c)<<uint64(d))])
+(ANDshiftRL x (MOVWconst [c]) [d]) -> (ANDconst x [int64(uint32(c)>>uint64(d))])
+(ANDshiftRA x (MOVWconst [c]) [d]) -> (ANDconst x [int64(int32(c)>>uint64(d))])
+(ORshiftLL x (MOVWconst [c]) [d]) -> (ORconst x [int64(uint32(c)<<uint64(d))])
+(ORshiftRL x (MOVWconst [c]) [d]) -> (ORconst x [int64(uint32(c)>>uint64(d))])
+(ORshiftRA x (MOVWconst [c]) [d]) -> (ORconst x [int64(int32(c)>>uint64(d))])
+(XORshiftLL x (MOVWconst [c]) [d]) -> (XORconst x [int64(uint32(c)<<uint64(d))])
+(XORshiftRL x (MOVWconst [c]) [d]) -> (XORconst x [int64(uint32(c)>>uint64(d))])
+(XORshiftRA x (MOVWconst [c]) [d]) -> (XORconst x [int64(int32(c)>>uint64(d))])
+(XORshiftRR x (MOVWconst [c]) [d]) -> (XORconst x [int64(uint32(c)>>uint64(d)|uint32(c)<<uint64(32-d))])
+(BICshiftLL x (MOVWconst [c]) [d]) -> (BICconst x [int64(uint32(c)<<uint64(d))])
+(BICshiftRL x (MOVWconst [c]) [d]) -> (BICconst x [int64(uint32(c)>>uint64(d))])
+(BICshiftRA x (MOVWconst [c]) [d]) -> (BICconst x [int64(int32(c)>>uint64(d))])
+(MVNshiftLL (MOVWconst [c]) [d]) -> (MOVWconst [^int64(uint32(c)<<uint64(d))])
+(MVNshiftRL (MOVWconst [c]) [d]) -> (MOVWconst [^int64(uint32(c)>>uint64(d))])
+(MVNshiftRA (MOVWconst [c]) [d]) -> (MOVWconst [^int64(int32(c)>>uint64(d))])
+(CMPshiftLL x (MOVWconst [c]) [d]) -> (CMPconst x [int64(uint32(c)<<uint64(d))])
+(CMPshiftRL x (MOVWconst [c]) [d]) -> (CMPconst x [int64(uint32(c)>>uint64(d))])
+(CMPshiftRA x (MOVWconst [c]) [d]) -> (CMPconst x [int64(int32(c)>>uint64(d))])
+
+(ADDshiftLLreg x y (MOVWconst [c])) -> (ADDshiftLL x y [c])
+(ADDshiftRLreg x y (MOVWconst [c])) -> (ADDshiftRL x y [c])
+(ADDshiftRAreg x y (MOVWconst [c])) -> (ADDshiftRA x y [c])
+(ADCshiftLLreg x y (MOVWconst [c]) flags) -> (ADCshiftLL x y [c] flags)
+(ADCshiftRLreg x y (MOVWconst [c]) flags) -> (ADCshiftRL x y [c] flags)
+(ADCshiftRAreg x y (MOVWconst [c]) flags) -> (ADCshiftRA x y [c] flags)
+(ADDSshiftLLreg x y (MOVWconst [c])) -> (ADDSshiftLL x y [c])
+(ADDSshiftRLreg x y (MOVWconst [c])) -> (ADDSshiftRL x y [c])
+(ADDSshiftRAreg x y (MOVWconst [c])) -> (ADDSshiftRA x y [c])
+(SUBshiftLLreg x y (MOVWconst [c])) -> (SUBshiftLL x y [c])
+(SUBshiftRLreg x y (MOVWconst [c])) -> (SUBshiftRL x y [c])
+(SUBshiftRAreg x y (MOVWconst [c])) -> (SUBshiftRA x y [c])
+(SBCshiftLLreg x y (MOVWconst [c]) flags) -> (SBCshiftLL x y [c] flags)
+(SBCshiftRLreg x y (MOVWconst [c]) flags) -> (SBCshiftRL x y [c] flags)
+(SBCshiftRAreg x y (MOVWconst [c]) flags) -> (SBCshiftRA x y [c] flags)
+(SUBSshiftLLreg x y (MOVWconst [c])) -> (SUBSshiftLL x y [c])
+(SUBSshiftRLreg x y (MOVWconst [c])) -> (SUBSshiftRL x y [c])
+(SUBSshiftRAreg x y (MOVWconst [c])) -> (SUBSshiftRA x y [c])
+(RSBshiftLLreg x y (MOVWconst [c])) -> (RSBshiftLL x y [c])
+(RSBshiftRLreg x y (MOVWconst [c])) -> (RSBshiftRL x y [c])
+(RSBshiftRAreg x y (MOVWconst [c])) -> (RSBshiftRA x y [c])
+(RSCshiftLLreg x y (MOVWconst [c]) flags) -> (RSCshiftLL x y [c] flags)
+(RSCshiftRLreg x y (MOVWconst [c]) flags) -> (RSCshiftRL x y [c] flags)
+(RSCshiftRAreg x y (MOVWconst [c]) flags) -> (RSCshiftRA x y [c] flags)
+(RSBSshiftLLreg x y (MOVWconst [c])) -> (RSBSshiftLL x y [c])
+(RSBSshiftRLreg x y (MOVWconst [c])) -> (RSBSshiftRL x y [c])
+(RSBSshiftRAreg x y (MOVWconst [c])) -> (RSBSshiftRA x y [c])
+(ANDshiftLLreg x y (MOVWconst [c])) -> (ANDshiftLL x y [c])
+(ANDshiftRLreg x y (MOVWconst [c])) -> (ANDshiftRL x y [c])
+(ANDshiftRAreg x y (MOVWconst [c])) -> (ANDshiftRA x y [c])
+(ORshiftLLreg x y (MOVWconst [c])) -> (ORshiftLL x y [c])
+(ORshiftRLreg x y (MOVWconst [c])) -> (ORshiftRL x y [c])
+(ORshiftRAreg x y (MOVWconst [c])) -> (ORshiftRA x y [c])
+(XORshiftLLreg x y (MOVWconst [c])) -> (XORshiftLL x y [c])
+(XORshiftRLreg x y (MOVWconst [c])) -> (XORshiftRL x y [c])
+(XORshiftRAreg x y (MOVWconst [c])) -> (XORshiftRA x y [c])
+(BICshiftLLreg x y (MOVWconst [c])) -> (BICshiftLL x y [c])
+(BICshiftRLreg x y (MOVWconst [c])) -> (BICshiftRL x y [c])
+(BICshiftRAreg x y (MOVWconst [c])) -> (BICshiftRA x y [c])
+(MVNshiftLLreg x (MOVWconst [c])) -> (MVNshiftLL x [c])
+(MVNshiftRLreg x (MOVWconst [c])) -> (MVNshiftRL x [c])
+(MVNshiftRAreg x (MOVWconst [c])) -> (MVNshiftRA x [c])
+(CMPshiftLLreg x y (MOVWconst [c])) -> (CMPshiftLL x y [c])
+(CMPshiftRLreg x y (MOVWconst [c])) -> (CMPshiftRL x y [c])
+(CMPshiftRAreg x y (MOVWconst [c])) -> (CMPshiftRA x y [c])
+
+// 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)
+(MOVWload [0] {sym} (ADDshiftLL ptr idx [c]) mem) && sym == nil && !config.nacl -> (MOVWloadshiftLL ptr idx [c] mem)
+(MOVWload [0] {sym} (ADDshiftRL ptr idx [c]) mem) && sym == nil && !config.nacl -> (MOVWloadshiftRL ptr idx [c] mem)
+(MOVWload [0] {sym} (ADDshiftRA ptr idx [c]) mem) && sym == nil && !config.nacl -> (MOVWloadshiftRA ptr idx [c] mem)
+(MOVWstore [0] {sym} (ADDshiftLL ptr idx [c]) val mem) && sym == nil && !config.nacl -> (MOVWstoreshiftLL ptr idx [c] val mem)
+(MOVWstore [0] {sym} (ADDshiftRL ptr idx [c]) val mem) && sym == nil && !config.nacl -> (MOVWstoreshiftRL ptr idx [c] val mem)
+(MOVWstore [0] {sym} (ADDshiftRA ptr idx [c]) val mem) && sym == nil && !config.nacl -> (MOVWstoreshiftRA ptr idx [c] val mem)
+
+// constant folding in indexed loads and stores
+(MOVWloadidx ptr (MOVWconst [c]) mem) -> (MOVWload [c] ptr mem)
+(MOVWloadidx (MOVWconst [c]) ptr mem) -> (MOVWload [c] ptr mem)
+
+(MOVWstoreidx ptr (MOVWconst [c]) val mem) -> (MOVWstore [c] ptr val mem)
+(MOVWstoreidx (MOVWconst [c]) ptr val mem) -> (MOVWstore [c] ptr val mem)
+
+(MOVWloadidx ptr (SLLconst idx [c]) mem) -> (MOVWloadshiftLL ptr idx [c] mem)
+(MOVWloadidx (SLLconst idx [c]) ptr mem) -> (MOVWloadshiftLL ptr idx [c] mem)
+(MOVWloadidx ptr (SRLconst idx [c]) mem) -> (MOVWloadshiftRL ptr idx [c] mem)
+(MOVWloadidx (SRLconst idx [c]) ptr mem) -> (MOVWloadshiftRL ptr idx [c] mem)
+(MOVWloadidx ptr (SRAconst idx [c]) mem) -> (MOVWloadshiftRA ptr idx [c] mem)
+(MOVWloadidx (SRAconst idx [c]) ptr mem) -> (MOVWloadshiftRA ptr idx [c] mem)
+
+(MOVWstoreidx ptr (SLLconst idx [c]) val mem) -> (MOVWstoreshiftLL ptr idx [c] val mem)
+(MOVWstoreidx (SLLconst idx [c]) ptr val mem) -> (MOVWstoreshiftLL ptr idx [c] val mem)
+(MOVWstoreidx ptr (SRLconst idx [c]) val mem) -> (MOVWstoreshiftRL ptr idx [c] val mem)
+(MOVWstoreidx (SRLconst idx [c]) ptr val mem) -> (MOVWstoreshiftRL ptr idx [c] val mem)
+(MOVWstoreidx ptr (SRAconst idx [c]) val mem) -> (MOVWstoreshiftRA ptr idx [c] val mem)
+(MOVWstoreidx (SRAconst idx [c]) ptr val mem) -> (MOVWstoreshiftRA ptr idx [c] val mem)
+
+(MOVWloadshiftLL ptr (MOVWconst [c]) [d] mem) -> (MOVWload [int64(uint32(c)<<uint64(d))] ptr mem)
+(MOVWloadshiftRL ptr (MOVWconst [c]) [d] mem) -> (MOVWload [int64(uint32(c)>>uint64(d))] ptr mem)
+(MOVWloadshiftRA ptr (MOVWconst [c]) [d] mem) -> (MOVWload [int64(int32(c)>>uint64(d))] ptr mem)
+
+(MOVWstoreshiftLL ptr (MOVWconst [c]) [d] val mem) -> (MOVWstore [int64(uint32(c)<<uint64(d))] ptr val mem)
+(MOVWstoreshiftRL ptr (MOVWconst [c]) [d] val mem) -> (MOVWstore [int64(uint32(c)>>uint64(d))] ptr val mem)
+(MOVWstoreshiftRA ptr (MOVWconst [c]) [d] val mem) -> (MOVWstore [int64(int32(c)>>uint64(d))] ptr val mem)
+
+// generic simplifications
+(ADD x (RSBconst [0] y)) -> (SUB x y)
+(ADD (RSBconst [0] y) x) -> (SUB x y)
+(SUB x x) -> (MOVWconst [0])
+(RSB x x) -> (MOVWconst [0])
+(AND x x) -> x
+(OR x x) -> x
+(XOR x x) -> (MOVWconst [0])
+(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])
+(SUBshiftRL x (SRLconst x [c]) [d]) && c==d -> (MOVWconst [0])
+(SUBshiftRA x (SRAconst x [c]) [d]) && c==d -> (MOVWconst [0])
+(RSBshiftLL x (SLLconst x [c]) [d]) && c==d -> (MOVWconst [0])
+(RSBshiftRL x (SRLconst x [c]) [d]) && c==d -> (MOVWconst [0])
+(RSBshiftRA x (SRAconst x [c]) [d]) && c==d -> (MOVWconst [0])
+(ANDshiftLL x y:(SLLconst x [c]) [d]) && c==d -> y
+(ANDshiftRL x y:(SRLconst x [c]) [d]) && c==d -> y
+(ANDshiftRA x y:(SRAconst x [c]) [d]) && c==d -> y
+(ORshiftLL x y:(SLLconst x [c]) [d]) && c==d -> y
+(ORshiftRL x y:(SRLconst x [c]) [d]) && c==d -> y
+(ORshiftRA x y:(SRAconst x [c]) [d]) && c==d -> y
+(XORshiftLL x (SLLconst x [c]) [d]) && c==d -> (MOVWconst [0])
+(XORshiftRL x (SRLconst x [c]) [d]) && c==d -> (MOVWconst [0])
+(XORshiftRA x (SRAconst x [c]) [d]) && c==d -> (MOVWconst [0])
+(BICshiftLL x (SLLconst x [c]) [d]) && c==d -> (MOVWconst [0])
+(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)
+(CMPD x (MOVDconst [0])) -> (CMPD0 x)
diff --git a/src/cmd/compile/internal/ssa/gen/ARM64.rules b/src/cmd/compile/internal/ssa/gen/ARM64.rules
new file mode 100644
index 0000000..c36b6f7
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/gen/ARM64.rules
@@ -0,0 +1,1302 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+(AddPtr x y) -> (ADD x y)
+(Add64 x y) -> (ADD x y)
+(Add32 x y) -> (ADD x y)
+(Add16 x y) -> (ADD x y)
+(Add8 x y) -> (ADD x y)
+(Add32F x y) -> (FADDS x y)
+(Add64F x y) -> (FADDD x y)
+
+(SubPtr x y) -> (SUB x y)
+(Sub64 x y) -> (SUB x y)
+(Sub32 x y) -> (SUB x y)
+(Sub16 x y) -> (SUB x y)
+(Sub8 x y) -> (SUB x y)
+(Sub32F x y) -> (FSUBS x y)
+(Sub64F x y) -> (FSUBD x y)
+
+(Mul64 x y) -> (MUL x y)
+(Mul32 x y) -> (MULW x y)
+(Mul16 x y) -> (MULW x y)
+(Mul8 x y) -> (MULW x y)
+(Mul32F x y) -> (FMULS x y)
+(Mul64F x y) -> (FMULD x y)
+
+(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])
+
+(Div64 x y) -> (DIV x y)
+(Div64u x y) -> (UDIV x y)
+(Div32 x y) -> (DIVW x y)
+(Div32u x y) -> (UDIVW x y)
+(Div16 x y) -> (DIVW (SignExt16to32 x) (SignExt16to32 y))
+(Div16u x y) -> (UDIVW (ZeroExt16to32 x) (ZeroExt16to32 y))
+(Div8 x y) -> (DIVW (SignExt8to32 x) (SignExt8to32 y))
+(Div8u x y) -> (UDIVW (ZeroExt8to32 x) (ZeroExt8to32 y))
+(Div32F x y) -> (FDIVS x y)
+(Div64F x y) -> (FDIVD x y)
+
+(Mod64 x y) -> (MOD x y)
+(Mod64u x y) -> (UMOD x y)
+(Mod32 x y) -> (MODW x y)
+(Mod32u x y) -> (UMODW x y)
+(Mod16 x y) -> (MODW (SignExt16to32 x) (SignExt16to32 y))
+(Mod16u x y) -> (UMODW (ZeroExt16to32 x) (ZeroExt16to32 y))
+(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])))
+
+(And64 x y) -> (AND x y)
+(And32 x y) -> (AND x y)
+(And16 x y) -> (AND x y)
+(And8 x y) -> (AND x y)
+
+(Or64 x y) -> (OR x y)
+(Or32 x y) -> (OR x y)
+(Or16 x y) -> (OR x y)
+(Or8 x y) -> (OR x y)
+
+(Xor64 x y) -> (XOR x y)
+(Xor32 x y) -> (XOR x y)
+(Xor16 x y) -> (XOR x y)
+(Xor8 x y) -> (XOR x y)
+
+// unary ops
+(Neg64 x) -> (NEG x)
+(Neg32 x) -> (NEG x)
+(Neg16 x) -> (NEG x)
+(Neg8 x) -> (NEG x)
+(Neg32F x) -> (FNEGS x)
+(Neg64F x) -> (FNEGD x)
+
+(Com64 x) -> (MVN x)
+(Com32 x) -> (MVN x)
+(Com16 x) -> (MVN x)
+(Com8 x) -> (MVN x)
+
+(Sqrt x) -> (FSQRTD x)
+
+(Ctz64 <t> x) -> (CLZ (RBIT <t> x))
+(Ctz32 <t> x) -> (CLZW (RBITW <t> x))
+
+(Bswap64 x) -> (REV x)
+(Bswap32 x) -> (REVW 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))
+(NeqB x y) -> (XOR x y)
+(Not x) -> (XOR (MOVDconst [1]) x)
+
+// constant shifts
+(Lsh64x64 x (MOVDconst [c])) && uint64(c) < 64 -> (SLLconst x [c])
+(Rsh64x64 x (MOVDconst [c])) && uint64(c) < 64 -> (SRAconst x [c])
+(Rsh64Ux64 x (MOVDconst [c])) && uint64(c) < 64 -> (SRLconst x [c])
+(Lsh32x64 x (MOVDconst [c])) && uint64(c) < 32 -> (SLLconst x [c])
+(Rsh32x64 x (MOVDconst [c])) && uint64(c) < 32 -> (SRAconst (SignExt32to64 x) [c])
+(Rsh32Ux64 x (MOVDconst [c])) && uint64(c) < 32 -> (SRLconst (ZeroExt32to64 x) [c])
+(Lsh16x64 x (MOVDconst [c])) && uint64(c) < 16 -> (SLLconst x [c])
+(Rsh16x64 x (MOVDconst [c])) && uint64(c) < 16 -> (SRAconst (SignExt16to64 x) [c])
+(Rsh16Ux64 x (MOVDconst [c])) && uint64(c) < 16 -> (SRLconst (ZeroExt16to64 x) [c])
+(Lsh8x64 x (MOVDconst [c])) && uint64(c) < 8 -> (SLLconst x [c])
+(Rsh8x64 x (MOVDconst [c])) && uint64(c) < 8 -> (SRAconst (SignExt8to64 x) [c])
+(Rsh8Ux64 x (MOVDconst [c])) && uint64(c) < 8 -> (SRLconst (ZeroExt8to64 x) [c])
+
+// large constant shifts
+(Lsh64x64 _ (MOVDconst [c])) && uint64(c) >= 64 -> (MOVDconst [0])
+(Rsh64Ux64 _ (MOVDconst [c])) && uint64(c) >= 64 -> (MOVDconst [0])
+(Lsh32x64 _ (MOVDconst [c])) && uint64(c) >= 32 -> (MOVDconst [0])
+(Rsh32Ux64 _ (MOVDconst [c])) && uint64(c) >= 32 -> (MOVDconst [0])
+(Lsh16x64 _ (MOVDconst [c])) && uint64(c) >= 16 -> (MOVDconst [0])
+(Rsh16Ux64 _ (MOVDconst [c])) && uint64(c) >= 16 -> (MOVDconst [0])
+(Lsh8x64 _ (MOVDconst [c])) && uint64(c) >= 8 -> (MOVDconst [0])
+(Rsh8Ux64 _ (MOVDconst [c])) && uint64(c) >= 8 -> (MOVDconst [0])
+
+// large constant signed right shift, we leave the sign bit
+(Rsh64x64 x (MOVDconst [c])) && uint64(c) >= 64 -> (SRAconst x [63])
+(Rsh32x64 x (MOVDconst [c])) && uint64(c) >= 32 -> (SRAconst (SignExt32to64 x) [63])
+(Rsh16x64 x (MOVDconst [c])) && uint64(c) >= 16 -> (SRAconst (SignExt16to64 x) [63])
+(Rsh8x64 x (MOVDconst [c])) && uint64(c) >= 8 -> (SRAconst (SignExt8to64 x) [63])
+
+// 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) -> (CSELULT (SLL <t> x y) (Const64 <t> [0]) (CMPconst [64] y))
+(Lsh64x32 <t> x y) -> (CSELULT (SLL <t> x (ZeroExt32to64 y)) (Const64 <t> [0]) (CMPconst [64] (ZeroExt32to64 y)))
+(Lsh64x16 <t> x y) -> (CSELULT (SLL <t> x (ZeroExt16to64 y)) (Const64 <t> [0]) (CMPconst [64] (ZeroExt16to64 y)))
+(Lsh64x8 <t> x y) -> (CSELULT (SLL <t> x (ZeroExt8to64 y)) (Const64 <t> [0]) (CMPconst [64] (ZeroExt8to64 y)))
+
+(Lsh32x64 <t> x y) -> (CSELULT (SLL <t> x y) (Const64 <t> [0]) (CMPconst [64] y))
+(Lsh32x32 <t> x y) -> (CSELULT (SLL <t> x (ZeroExt32to64 y)) (Const64 <t> [0]) (CMPconst [64] (ZeroExt32to64 y)))
+(Lsh32x16 <t> x y) -> (CSELULT (SLL <t> x (ZeroExt16to64 y)) (Const64 <t> [0]) (CMPconst [64] (ZeroExt16to64 y)))
+(Lsh32x8 <t> x y) -> (CSELULT (SLL <t> x (ZeroExt8to64 y)) (Const64 <t> [0]) (CMPconst [64] (ZeroExt8to64 y)))
+
+(Lsh16x64 <t> x y) -> (CSELULT (SLL <t> x y) (Const64 <t> [0]) (CMPconst [64] y))
+(Lsh16x32 <t> x y) -> (CSELULT (SLL <t> x (ZeroExt32to64 y)) (Const64 <t> [0]) (CMPconst [64] (ZeroExt32to64 y)))
+(Lsh16x16 <t> x y) -> (CSELULT (SLL <t> x (ZeroExt16to64 y)) (Const64 <t> [0]) (CMPconst [64] (ZeroExt16to64 y)))
+(Lsh16x8 <t> x y) -> (CSELULT (SLL <t> x (ZeroExt8to64 y)) (Const64 <t> [0]) (CMPconst [64] (ZeroExt8to64 y)))
+
+(Lsh8x64 <t> x y) -> (CSELULT (SLL <t> x y) (Const64 <t> [0]) (CMPconst [64] y))
+(Lsh8x32 <t> x y) -> (CSELULT (SLL <t> x (ZeroExt32to64 y)) (Const64 <t> [0]) (CMPconst [64] (ZeroExt32to64 y)))
+(Lsh8x16 <t> x y) -> (CSELULT (SLL <t> x (ZeroExt16to64 y)) (Const64 <t> [0]) (CMPconst [64] (ZeroExt16to64 y)))
+(Lsh8x8 <t> x y) -> (CSELULT (SLL <t> x (ZeroExt8to64 y)) (Const64 <t> [0]) (CMPconst [64] (ZeroExt8to64 y)))
+
+(Rsh64Ux64 <t> x y) -> (CSELULT (SRL <t> x y) (Const64 <t> [0]) (CMPconst [64] y))
+(Rsh64Ux32 <t> x y) -> (CSELULT (SRL <t> x (ZeroExt32to64 y)) (Const64 <t> [0]) (CMPconst [64] (ZeroExt32to64 y)))
+(Rsh64Ux16 <t> x y) -> (CSELULT (SRL <t> x (ZeroExt16to64 y)) (Const64 <t> [0]) (CMPconst [64] (ZeroExt16to64 y)))
+(Rsh64Ux8 <t> x y) -> (CSELULT (SRL <t> x (ZeroExt8to64 y)) (Const64 <t> [0]) (CMPconst [64] (ZeroExt8to64 y)))
+
+(Rsh32Ux64 <t> x y) -> (CSELULT (SRL <t> (ZeroExt32to64 x) y) (Const64 <t> [0]) (CMPconst [64] y))
+(Rsh32Ux32 <t> x y) -> (CSELULT (SRL <t> (ZeroExt32to64 x) (ZeroExt32to64 y)) (Const64 <t> [0]) (CMPconst [64] (ZeroExt32to64 y)))
+(Rsh32Ux16 <t> x y) -> (CSELULT (SRL <t> (ZeroExt32to64 x) (ZeroExt16to64 y)) (Const64 <t> [0]) (CMPconst [64] (ZeroExt16to64 y)))
+(Rsh32Ux8 <t> x y) -> (CSELULT (SRL <t> (ZeroExt32to64 x) (ZeroExt8to64 y)) (Const64 <t> [0]) (CMPconst [64] (ZeroExt8to64 y)))
+
+(Rsh16Ux64 <t> x y) -> (CSELULT (SRL <t> (ZeroExt16to64 x) y) (Const64 <t> [0]) (CMPconst [64] y))
+(Rsh16Ux32 <t> x y) -> (CSELULT (SRL <t> (ZeroExt16to64 x) (ZeroExt32to64 y)) (Const64 <t> [0]) (CMPconst [64] (ZeroExt32to64 y)))
+(Rsh16Ux16 <t> x y) -> (CSELULT (SRL <t> (ZeroExt16to64 x) (ZeroExt16to64 y)) (Const64 <t> [0]) (CMPconst [64] (ZeroExt16to64 y)))
+(Rsh16Ux8 <t> x y) -> (CSELULT (SRL <t> (ZeroExt16to64 x) (ZeroExt8to64 y)) (Const64 <t> [0]) (CMPconst [64] (ZeroExt8to64 y)))
+
+(Rsh8Ux64 <t> x y) -> (CSELULT (SRL <t> (ZeroExt8to64 x) y) (Const64 <t> [0]) (CMPconst [64] y))
+(Rsh8Ux32 <t> x y) -> (CSELULT (SRL <t> (ZeroExt8to64 x) (ZeroExt32to64 y)) (Const64 <t> [0]) (CMPconst [64] (ZeroExt32to64 y)))
+(Rsh8Ux16 <t> x y) -> (CSELULT (SRL <t> (ZeroExt8to64 x) (ZeroExt16to64 y)) (Const64 <t> [0]) (CMPconst [64] (ZeroExt16to64 y)))
+(Rsh8Ux8 <t> x y) -> (CSELULT (SRL <t> (ZeroExt8to64 x) (ZeroExt8to64 y)) (Const64 <t> [0]) (CMPconst [64] (ZeroExt8to64 y)))
+
+(Rsh64x64 x y) -> (SRA x (CSELULT <y.Type> y (Const64 <y.Type> [63]) (CMPconst [64] y)))
+(Rsh64x32 x y) -> (SRA x (CSELULT <y.Type> (ZeroExt32to64 y) (Const64 <y.Type> [63]) (CMPconst [64] (ZeroExt32to64 y))))
+(Rsh64x16 x y) -> (SRA x (CSELULT <y.Type> (ZeroExt16to64 y) (Const64 <y.Type> [63]) (CMPconst [64] (ZeroExt16to64 y))))
+(Rsh64x8 x y) -> (SRA x (CSELULT <y.Type> (ZeroExt8to64 y) (Const64 <y.Type> [63]) (CMPconst [64] (ZeroExt8to64 y))))
+
+(Rsh32x64 x y) -> (SRA (SignExt32to64 x) (CSELULT <y.Type> y (Const64 <y.Type> [63]) (CMPconst [64] y)))
+(Rsh32x32 x y) -> (SRA (SignExt32to64 x) (CSELULT <y.Type> (ZeroExt32to64 y) (Const64 <y.Type> [63]) (CMPconst [64] (ZeroExt32to64 y))))
+(Rsh32x16 x y) -> (SRA (SignExt32to64 x) (CSELULT <y.Type> (ZeroExt16to64 y) (Const64 <y.Type> [63]) (CMPconst [64] (ZeroExt16to64 y))))
+(Rsh32x8 x y) -> (SRA (SignExt32to64 x) (CSELULT <y.Type> (ZeroExt8to64 y) (Const64 <y.Type> [63]) (CMPconst [64] (ZeroExt8to64 y))))
+
+(Rsh16x64 x y) -> (SRA (SignExt16to64 x) (CSELULT <y.Type> y (Const64 <y.Type> [63]) (CMPconst [64] y)))
+(Rsh16x32 x y) -> (SRA (SignExt16to64 x) (CSELULT <y.Type> (ZeroExt32to64 y) (Const64 <y.Type> [63]) (CMPconst [64] (ZeroExt32to64 y))))
+(Rsh16x16 x y) -> (SRA (SignExt16to64 x) (CSELULT <y.Type> (ZeroExt16to64 y) (Const64 <y.Type> [63]) (CMPconst [64] (ZeroExt16to64 y))))
+(Rsh16x8 x y) -> (SRA (SignExt16to64 x) (CSELULT <y.Type> (ZeroExt8to64 y) (Const64 <y.Type> [63]) (CMPconst [64] (ZeroExt8to64 y))))
+
+(Rsh8x64 x y) -> (SRA (SignExt8to64 x) (CSELULT <y.Type> y (Const64 <y.Type> [63]) (CMPconst [64] y)))
+(Rsh8x32 x y) -> (SRA (SignExt8to64 x) (CSELULT <y.Type> (ZeroExt32to64 y) (Const64 <y.Type> [63]) (CMPconst [64] (ZeroExt32to64 y))))
+(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])
+(Const16 [val]) -> (MOVDconst [val])
+(Const8 [val]) -> (MOVDconst [val])
+(Const32F [val]) -> (FMOVSconst [val])
+(Const64F [val]) -> (FMOVDconst [val])
+(ConstNil) -> (MOVDconst [0])
+(ConstBool [b]) -> (MOVDconst [b])
+
+(Slicemask <t> x) -> (MVN (SRAconst <t> (SUBconst <t> x [1]) [63]))
+
+// truncations
+// Because we ignore high parts of registers, truncates are just copies.
+(Trunc16to8 x) -> x
+(Trunc32to8 x) -> x
+(Trunc32to16 x) -> x
+(Trunc64to8 x) -> x
+(Trunc64to16 x) -> x
+(Trunc64to32 x) -> x
+
+// Zero-/Sign-extensions
+(ZeroExt8to16 x) -> (MOVBUreg x)
+(ZeroExt8to32 x) -> (MOVBUreg x)
+(ZeroExt16to32 x) -> (MOVHUreg x)
+(ZeroExt8to64 x) -> (MOVBUreg x)
+(ZeroExt16to64 x) -> (MOVHUreg x)
+(ZeroExt32to64 x) -> (MOVWUreg x)
+
+(SignExt8to16 x) -> (MOVBreg x)
+(SignExt8to32 x) -> (MOVBreg x)
+(SignExt16to32 x) -> (MOVHreg x)
+(SignExt8to64 x) -> (MOVBreg x)
+(SignExt16to64 x) -> (MOVHreg x)
+(SignExt32to64 x) -> (MOVWreg x)
+
+// float <-> int conversion
+(Cvt32to32F x) -> (SCVTFWS x)
+(Cvt32to64F x) -> (SCVTFWD x)
+(Cvt64to32F x) -> (SCVTFS x)
+(Cvt64to64F x) -> (SCVTFD x)
+(Cvt32Uto32F x) -> (UCVTFWS x)
+(Cvt32Uto64F x) -> (UCVTFWD x)
+(Cvt64Uto32F x) -> (UCVTFS x)
+(Cvt64Uto64F x) -> (UCVTFD x)
+(Cvt32Fto32 x) -> (FCVTZSSW x)
+(Cvt64Fto32 x) -> (FCVTZSDW x)
+(Cvt32Fto64 x) -> (FCVTZSS x)
+(Cvt64Fto64 x) -> (FCVTZSD x)
+(Cvt32Fto32U x) -> (FCVTZUSW x)
+(Cvt64Fto32U x) -> (FCVTZUDW x)
+(Cvt32Fto64U x) -> (FCVTZUS x)
+(Cvt64Fto64U x) -> (FCVTZUD x)
+(Cvt32Fto64F x) -> (FCVTSD x)
+(Cvt64Fto32F x) -> (FCVTDS x)
+
+// comparisons
+(Eq8 x y) -> (Equal (CMPW (ZeroExt8to32 x) (ZeroExt8to32 y)))
+(Eq16 x y) -> (Equal (CMPW (ZeroExt16to32 x) (ZeroExt16to32 y)))
+(Eq32 x y) -> (Equal (CMPW x y))
+(Eq64 x y) -> (Equal (CMP x y))
+(EqPtr x y) -> (Equal (CMP x y))
+(Eq32F x y) -> (Equal (FCMPS x y))
+(Eq64F x y) -> (Equal (FCMPD x y))
+
+(Neq8 x y) -> (NotEqual (CMPW (ZeroExt8to32 x) (ZeroExt8to32 y)))
+(Neq16 x y) -> (NotEqual (CMPW (ZeroExt16to32 x) (ZeroExt16to32 y)))
+(Neq32 x y) -> (NotEqual (CMPW x y))
+(Neq64 x y) -> (NotEqual (CMP x y))
+(NeqPtr x y) -> (NotEqual (CMP x y))
+(Neq32F x y) -> (NotEqual (FCMPS x y))
+(Neq64F x y) -> (NotEqual (FCMPD x y))
+
+(Less8 x y) -> (LessThan (CMPW (SignExt8to32 x) (SignExt8to32 y)))
+(Less16 x y) -> (LessThan (CMPW (SignExt16to32 x) (SignExt16to32 y)))
+(Less32 x y) -> (LessThan (CMPW x y))
+(Less64 x y) -> (LessThan (CMP x y))
+(Less32F x y) -> (GreaterThan (FCMPS y x)) // reverse operands to work around NaN
+(Less64F x y) -> (GreaterThan (FCMPD y x)) // reverse operands to work around NaN
+
+(Less8U x y) -> (LessThanU (CMPW (ZeroExt8to32 x) (ZeroExt8to32 y)))
+(Less16U x y) -> (LessThanU (CMPW (ZeroExt16to32 x) (ZeroExt16to32 y)))
+(Less32U x y) -> (LessThanU (CMPW x y))
+(Less64U x y) -> (LessThanU (CMP x y))
+
+(Leq8 x y) -> (LessEqual (CMPW (SignExt8to32 x) (SignExt8to32 y)))
+(Leq16 x y) -> (LessEqual (CMPW (SignExt16to32 x) (SignExt16to32 y)))
+(Leq32 x y) -> (LessEqual (CMPW x y))
+(Leq64 x y) -> (LessEqual (CMP x y))
+(Leq32F x y) -> (GreaterEqual (FCMPS y x)) // reverse operands to work around NaN
+(Leq64F x y) -> (GreaterEqual (FCMPD y x)) // reverse operands to work around NaN
+
+(Leq8U x y) -> (LessEqualU (CMPW (ZeroExt8to32 x) (ZeroExt8to32 y)))
+(Leq16U x y) -> (LessEqualU (CMPW (ZeroExt16to32 x) (ZeroExt16to32 y)))
+(Leq32U x y) -> (LessEqualU (CMPW x y))
+(Leq64U x y) -> (LessEqualU (CMP x y))
+
+(Greater8 x y) -> (GreaterThan (CMPW (SignExt8to32 x) (SignExt8to32 y)))
+(Greater16 x y) -> (GreaterThan (CMPW (SignExt16to32 x) (SignExt16to32 y)))
+(Greater32 x y) -> (GreaterThan (CMPW x y))
+(Greater64 x y) -> (GreaterThan (CMP x y))
+(Greater32F x y) -> (GreaterThan (FCMPS x y))
+(Greater64F x y) -> (GreaterThan (FCMPD x y))
+
+(Greater8U x y) -> (GreaterThanU (CMPW (ZeroExt8to32 x) (ZeroExt8to32 y)))
+(Greater16U x y) -> (GreaterThanU (CMPW (ZeroExt16to32 x) (ZeroExt16to32 y)))
+(Greater32U x y) -> (GreaterThanU (CMPW x y))
+(Greater64U x y) -> (GreaterThanU (CMP x y))
+
+(Geq8 x y) -> (GreaterEqual (CMPW (SignExt8to32 x) (SignExt8to32 y)))
+(Geq16 x y) -> (GreaterEqual (CMPW (SignExt16to32 x) (SignExt16to32 y)))
+(Geq32 x y) -> (GreaterEqual (CMPW x y))
+(Geq64 x y) -> (GreaterEqual (CMP x y))
+(Geq32F x y) -> (GreaterEqual (FCMPS x y))
+(Geq64F x y) -> (GreaterEqual (FCMPD x y))
+
+(Geq8U x y) -> (GreaterEqualU (CMPW (ZeroExt8to32 x) (ZeroExt8to32 y)))
+(Geq16U x y) -> (GreaterEqualU (CMPW (ZeroExt16to32 x) (ZeroExt16to32 y)))
+(Geq32U x y) -> (GreaterEqualU (CMPW x y))
+(Geq64U x y) -> (GreaterEqualU (CMP x y))
+
+(OffPtr [off] ptr:(SP)) -> (MOVDaddr [off] ptr)
+(OffPtr [off] ptr) -> (ADDconst [off] ptr)
+
+(Addr {sym} base) -> (MOVDaddr {sym} base)
+
+// loads
+(Load <t> ptr mem) && t.IsBoolean() -> (MOVBUload ptr mem)
+(Load <t> ptr mem) && (is8BitInt(t) && isSigned(t)) -> (MOVBload ptr mem)
+(Load <t> ptr mem) && (is8BitInt(t) && !isSigned(t)) -> (MOVBUload ptr mem)
+(Load <t> ptr mem) && (is16BitInt(t) && isSigned(t)) -> (MOVHload ptr mem)
+(Load <t> ptr mem) && (is16BitInt(t) && !isSigned(t)) -> (MOVHUload ptr mem)
+(Load <t> ptr mem) && (is32BitInt(t) && isSigned(t)) -> (MOVWload ptr mem)
+(Load <t> ptr mem) && (is32BitInt(t) && !isSigned(t)) -> (MOVWUload ptr mem)
+(Load <t> ptr mem) && (is64BitInt(t) || isPtr(t)) -> (MOVDload ptr mem)
+(Load <t> ptr mem) && is32BitFloat(t) -> (FMOVSload ptr mem)
+(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)
+
+// 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 [s] ptr mem) && SizeAndAlign(s).Size() == 3 ->
+ (MOVBstore [2] ptr (MOVDconst [0])
+ (MOVHstore ptr (MOVDconst [0]) mem))
+(Zero [s] ptr mem) && SizeAndAlign(s).Size() == 5 ->
+ (MOVBstore [4] ptr (MOVDconst [0])
+ (MOVWstore ptr (MOVDconst [0]) mem))
+(Zero [s] ptr mem) && SizeAndAlign(s).Size() == 6 ->
+ (MOVHstore [4] ptr (MOVDconst [0])
+ (MOVWstore ptr (MOVDconst [0]) mem))
+(Zero [s] ptr mem) && SizeAndAlign(s).Size() == 7 ->
+ (MOVBstore [6] ptr (MOVDconst [0])
+ (MOVHstore [4] ptr (MOVDconst [0])
+ (MOVWstore ptr (MOVDconst [0]) mem)))
+(Zero [s] ptr mem) && SizeAndAlign(s).Size() == 12 ->
+ (MOVWstore [8] ptr (MOVDconst [0])
+ (MOVDstore ptr (MOVDconst [0]) mem))
+(Zero [s] ptr mem) && SizeAndAlign(s).Size() == 16 ->
+ (MOVDstore [8] ptr (MOVDconst [0])
+ (MOVDstore ptr (MOVDconst [0]) mem))
+(Zero [s] ptr mem) && SizeAndAlign(s).Size() == 24 ->
+ (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))
+
+// 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
+ && !config.noDuffDevice ->
+ (DUFFZERO [4 * (128 - int64(SizeAndAlign(s).Size()/8))] ptr mem)
+
+// large zeroing uses a loop
+(Zero [s] ptr mem)
+ && SizeAndAlign(s).Size()%8 == 0 && (SizeAndAlign(s).Size() > 8*128 || config.noDuffDevice) ->
+ (LoweredZero
+ ptr
+ (ADDconst <ptr.Type> [SizeAndAlign(s).Size()-moveSize(SizeAndAlign(s).Align(), config)] 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 [s] dst src mem) && SizeAndAlign(s).Size() == 3 ->
+ (MOVBstore [2] dst (MOVBUload [2] src mem)
+ (MOVHstore dst (MOVHUload src mem) mem))
+(Move [s] dst src mem) && SizeAndAlign(s).Size() == 5 ->
+ (MOVBstore [4] dst (MOVBUload [4] src mem)
+ (MOVWstore dst (MOVWUload src mem) mem))
+(Move [s] dst src mem) && SizeAndAlign(s).Size() == 6 ->
+ (MOVHstore [4] dst (MOVHUload [4] src mem)
+ (MOVWstore dst (MOVWUload src mem) mem))
+(Move [s] dst src mem) && SizeAndAlign(s).Size() == 7 ->
+ (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 ->
+ (MOVWstore [8] dst (MOVWUload [8] src mem)
+ (MOVDstore dst (MOVDload src mem) mem))
+(Move [s] dst src mem) && SizeAndAlign(s).Size() == 16 ->
+ (MOVDstore [8] dst (MOVDload [8] src mem)
+ (MOVDstore dst (MOVDload src mem) mem))
+(Move [s] dst src mem) && SizeAndAlign(s).Size() == 24 ->
+ (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))
+
+// 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
+ && !config.noDuffDevice ->
+ (DUFFCOPY [8 * (128 - int64(SizeAndAlign(s).Size()/8))] dst src mem)
+
+// large move uses a loop
+(Move [s] dst src mem)
+ && SizeAndAlign(s).Size() > 24 && SizeAndAlign(s).Size()%8 == 0 ->
+ (LoweredMove
+ dst
+ src
+ (ADDconst <src.Type> src [SizeAndAlign(s).Size()-moveSize(SizeAndAlign(s).Align(), 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
+(NilCheck ptr mem) -> (LoweredNilCheck ptr mem)
+(IsNonNil ptr) -> (NotEqual (CMPconst [0] ptr))
+(IsInBounds idx len) -> (LessThanU (CMP idx len))
+(IsSliceInBounds idx len) -> (LessEqualU (CMP idx len))
+
+// pseudo-ops
+(GetClosurePtr) -> (LoweredGetClosurePtr)
+(Convert x mem) -> (MOVDconvert x mem)
+
+// Absorb pseudo-ops into blocks.
+(If (Equal cc) yes no) -> (EQ cc yes no)
+(If (NotEqual cc) yes no) -> (NE cc yes no)
+(If (LessThan cc) yes no) -> (LT cc yes no)
+(If (LessThanU cc) yes no) -> (ULT cc yes no)
+(If (LessEqual cc) yes no) -> (LE cc yes no)
+(If (LessEqualU cc) yes no) -> (ULE cc yes no)
+(If (GreaterThan cc) yes no) -> (GT cc yes no)
+(If (GreaterThanU cc) yes no) -> (UGT cc yes no)
+(If (GreaterEqual cc) yes no) -> (GE cc yes no)
+(If (GreaterEqualU cc) yes no) -> (UGE cc yes no)
+
+(If cond yes no) -> (NZ cond yes no)
+
+// atomic intrinsics
+// Note: these ops do not accept offset.
+(AtomicLoad32 ptr mem) -> (LDARW ptr mem)
+(AtomicLoad64 ptr mem) -> (LDAR ptr mem)
+(AtomicLoadPtr ptr mem) -> (LDAR ptr mem)
+
+(AtomicStore32 ptr val mem) -> (STLRW ptr val mem)
+(AtomicStore64 ptr val mem) -> (STLR 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)
+
+// Optimizations
+
+// Absorb boolean tests into block
+(NZ (Equal cc) yes no) -> (EQ cc yes no)
+(NZ (NotEqual cc) yes no) -> (NE cc yes no)
+(NZ (LessThan cc) yes no) -> (LT cc yes no)
+(NZ (LessThanU cc) yes no) -> (ULT cc yes no)
+(NZ (LessEqual cc) yes no) -> (LE cc yes no)
+(NZ (LessEqualU cc) yes no) -> (ULE cc yes no)
+(NZ (GreaterThan cc) yes no) -> (GT cc yes no)
+(NZ (GreaterThanU cc) yes no) -> (UGT cc yes no)
+(NZ (GreaterEqual cc) yes no) -> (GE cc yes no)
+(NZ (GreaterEqualU cc) yes no) -> (UGE cc yes no)
+
+(EQ (CMPconst [0] x) yes no) -> (Z x yes no)
+(NE (CMPconst [0] x) yes no) -> (NZ x yes no)
+(EQ (CMPWconst [0] x) yes no) -> (ZW x yes no)
+(NE (CMPWconst [0] x) yes no) -> (NZW x yes no)
+
+// fold offset into address
+(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) -> (MOVBload [off1+off2] {sym} ptr mem)
+(MOVBUload [off1] {sym} (ADDconst [off2] ptr) mem) -> (MOVBUload [off1+off2] {sym} ptr mem)
+(MOVHload [off1] {sym} (ADDconst [off2] ptr) mem)
+ && (off1+off2)%2==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym) ->
+ (MOVHload [off1+off2] {sym} ptr mem)
+(MOVHUload [off1] {sym} (ADDconst [off2] ptr) mem)
+ && (off1+off2)%2==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym) ->
+ (MOVHUload [off1+off2] {sym} ptr mem)
+(MOVWload [off1] {sym} (ADDconst [off2] ptr) mem)
+ && (off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym) ->
+ (MOVWload [off1+off2] {sym} ptr mem)
+(MOVWUload [off1] {sym} (ADDconst [off2] ptr) mem)
+ && (off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym) ->
+ (MOVWUload [off1+off2] {sym} ptr mem)
+(MOVDload [off1] {sym} (ADDconst [off2] ptr) mem)
+ && (off1+off2)%8==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym) ->
+ (MOVDload [off1+off2] {sym} ptr mem)
+(FMOVSload [off1] {sym} (ADDconst [off2] ptr) mem)
+ && (off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym) ->
+ (FMOVSload [off1+off2] {sym} ptr mem)
+(FMOVDload [off1] {sym} (ADDconst [off2] ptr) mem)
+ && (off1+off2)%8==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym) ->
+ (FMOVDload [off1+off2] {sym} ptr mem)
+
+(MOVBstore [off1] {sym} (ADDconst [off2] ptr) val mem) -> (MOVBstore [off1+off2] {sym} ptr val mem)
+(MOVHstore [off1] {sym} (ADDconst [off2] ptr) val mem)
+ && (off1+off2)%2==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym) ->
+ (MOVHstore [off1+off2] {sym} ptr val mem)
+(MOVWstore [off1] {sym} (ADDconst [off2] ptr) val mem)
+ && (off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym) ->
+ (MOVWstore [off1+off2] {sym} ptr val mem)
+(MOVDstore [off1] {sym} (ADDconst [off2] ptr) val mem)
+ && (off1+off2)%8==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym) ->
+ (MOVDstore [off1+off2] {sym} ptr val mem)
+(FMOVSstore [off1] {sym} (ADDconst [off2] ptr) val mem)
+ && (off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym) ->
+ (FMOVSstore [off1+off2] {sym} ptr val mem)
+(FMOVDstore [off1] {sym} (ADDconst [off2] ptr) val mem)
+ && (off1+off2)%8==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym) ->
+ (FMOVDstore [off1+off2] {sym} ptr val mem)
+(MOVBstorezero [off1] {sym} (ADDconst [off2] ptr) mem) -> (MOVBstorezero [off1+off2] {sym} ptr mem)
+(MOVHstorezero [off1] {sym} (ADDconst [off2] ptr) mem)
+ && (off1+off2)%2==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym) ->
+ (MOVHstorezero [off1+off2] {sym} ptr mem)
+(MOVWstorezero [off1] {sym} (ADDconst [off2] ptr) mem)
+ && (off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym) ->
+ (MOVWstorezero [off1+off2] {sym} ptr mem)
+(MOVDstorezero [off1] {sym} (ADDconst [off2] ptr) mem)
+ && (off1+off2)%2==8 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym) ->
+ (MOVDstorezero [off1+off2] {sym} ptr mem)
+
+(MOVBload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) ->
+ (MOVBload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
+(MOVBUload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) ->
+ (MOVBUload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
+(MOVHload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2)
+ && ((off1+off2)%2==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym1) && !isAuto(sym1)) ->
+ (MOVHload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
+(MOVHUload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2)
+ && ((off1+off2)%2==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym1) && !isAuto(sym1)) ->
+ (MOVHUload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
+(MOVWload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2)
+ && ((off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym1) && !isAuto(sym1)) ->
+ (MOVWload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
+(MOVWUload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2)
+ && ((off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym1) && !isAuto(sym1)) ->
+ (MOVWUload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
+(MOVDload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2)
+ && ((off1+off2)%8==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym1) && !isAuto(sym1)) ->
+ (MOVDload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
+(FMOVSload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2)
+ && ((off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym1) && !isAuto(sym1)) ->
+ (FMOVSload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
+(FMOVDload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2)
+ && ((off1+off2)%8==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym1) && !isAuto(sym1)) ->
+ (FMOVDload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
+
+(MOVBstore [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) val mem) && canMergeSym(sym1,sym2) ->
+ (MOVBstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
+(MOVHstore [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) val mem) && canMergeSym(sym1,sym2)
+ && ((off1+off2)%2==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym1) && !isAuto(sym1)) ->
+ (MOVHstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
+(MOVWstore [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) val mem) && canMergeSym(sym1,sym2)
+ && ((off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym1) && !isAuto(sym1)) ->
+ (MOVWstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
+(MOVDstore [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) val mem) && canMergeSym(sym1,sym2)
+ && ((off1+off2)%8==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym1) && !isAuto(sym1)) ->
+ (MOVDstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
+(FMOVSstore [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) val mem) && canMergeSym(sym1,sym2)
+ && ((off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym1) && !isAuto(sym1)) ->
+ (FMOVSstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
+(FMOVDstore [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) val mem) && canMergeSym(sym1,sym2)
+ && ((off1+off2)%8==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym1) && !isAuto(sym1)) ->
+ (FMOVDstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
+(MOVBstorezero [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) ->
+ (MOVBstorezero [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
+(MOVHstorezero [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2)
+ && ((off1+off2)%2==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym1) && !isAuto(sym1)) ->
+ (MOVHstorezero [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
+(MOVWstorezero [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2)
+ && ((off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym1) && !isAuto(sym1)) ->
+ (MOVWstorezero [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
+(MOVDstorezero [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2)
+ && ((off1+off2)%8==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym1) && !isAuto(sym1)) ->
+ (MOVDstorezero [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
+
+// store zero
+(MOVBstore [off] {sym} ptr (MOVDconst [0]) mem) -> (MOVBstorezero [off] {sym} ptr mem)
+(MOVHstore [off] {sym} ptr (MOVDconst [0]) mem) -> (MOVHstorezero [off] {sym} ptr mem)
+(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
+// 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
+//(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
+
+(MOVBload [off] {sym} ptr (MOVBstorezero [off2] {sym2} ptr2 _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVDconst [0])
+(MOVBUload [off] {sym} ptr (MOVBstorezero [off2] {sym2} ptr2 _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVDconst [0])
+(MOVHload [off] {sym} ptr (MOVHstorezero [off2] {sym2} ptr2 _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVDconst [0])
+(MOVHUload [off] {sym} ptr (MOVHstorezero [off2] {sym2} ptr2 _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVDconst [0])
+(MOVWload [off] {sym} ptr (MOVWstorezero [off2] {sym2} ptr2 _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVDconst [0])
+(MOVWUload [off] {sym} ptr (MOVWstorezero [off2] {sym2} ptr2 _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVDconst [0])
+(MOVDload [off] {sym} ptr (MOVDstorezero [off2] {sym2} ptr2 _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVDconst [0])
+
+// don't extend after proper load
+(MOVBreg x:(MOVBload _ _)) -> (MOVDreg x)
+(MOVBUreg x:(MOVBUload _ _)) -> (MOVDreg x)
+(MOVHreg x:(MOVBload _ _)) -> (MOVDreg x)
+(MOVHreg x:(MOVBUload _ _)) -> (MOVDreg x)
+(MOVHreg x:(MOVHload _ _)) -> (MOVDreg x)
+(MOVHUreg x:(MOVBUload _ _)) -> (MOVDreg x)
+(MOVHUreg x:(MOVHUload _ _)) -> (MOVDreg x)
+(MOVWreg x:(MOVBload _ _)) -> (MOVDreg x)
+(MOVWreg x:(MOVBUload _ _)) -> (MOVDreg x)
+(MOVWreg x:(MOVHload _ _)) -> (MOVDreg x)
+(MOVWreg x:(MOVHUload _ _)) -> (MOVDreg x)
+(MOVWreg x:(MOVWload _ _)) -> (MOVDreg x)
+(MOVWUreg x:(MOVBUload _ _)) -> (MOVDreg x)
+(MOVWUreg x:(MOVHUload _ _)) -> (MOVDreg x)
+(MOVWUreg x:(MOVWUload _ _)) -> (MOVDreg x)
+
+// fold double extensions
+(MOVBreg x:(MOVBreg _)) -> (MOVDreg x)
+(MOVBUreg x:(MOVBUreg _)) -> (MOVDreg x)
+(MOVHreg x:(MOVBreg _)) -> (MOVDreg x)
+(MOVHreg x:(MOVBUreg _)) -> (MOVDreg x)
+(MOVHreg x:(MOVHreg _)) -> (MOVDreg x)
+(MOVHUreg x:(MOVBUreg _)) -> (MOVDreg x)
+(MOVHUreg x:(MOVHUreg _)) -> (MOVDreg x)
+(MOVWreg x:(MOVBreg _)) -> (MOVDreg x)
+(MOVWreg x:(MOVBUreg _)) -> (MOVDreg x)
+(MOVWreg x:(MOVHreg _)) -> (MOVDreg x)
+(MOVWreg x:(MOVHreg _)) -> (MOVDreg x)
+(MOVWreg x:(MOVWreg _)) -> (MOVDreg x)
+(MOVWUreg x:(MOVBUreg _)) -> (MOVDreg x)
+(MOVWUreg x:(MOVHUreg _)) -> (MOVDreg x)
+(MOVWUreg x:(MOVWUreg _)) -> (MOVDreg x)
+
+// don't extend before store
+(MOVBstore [off] {sym} ptr (MOVBreg x) mem) -> (MOVBstore [off] {sym} ptr x mem)
+(MOVBstore [off] {sym} ptr (MOVBUreg x) mem) -> (MOVBstore [off] {sym} ptr x mem)
+(MOVBstore [off] {sym} ptr (MOVHreg x) mem) -> (MOVBstore [off] {sym} ptr x mem)
+(MOVBstore [off] {sym} ptr (MOVHUreg x) mem) -> (MOVBstore [off] {sym} ptr x mem)
+(MOVBstore [off] {sym} ptr (MOVWreg x) mem) -> (MOVBstore [off] {sym} ptr x mem)
+(MOVBstore [off] {sym} ptr (MOVWUreg x) mem) -> (MOVBstore [off] {sym} ptr x mem)
+(MOVHstore [off] {sym} ptr (MOVHreg x) mem) -> (MOVHstore [off] {sym} ptr x mem)
+(MOVHstore [off] {sym} ptr (MOVHUreg x) mem) -> (MOVHstore [off] {sym} ptr x mem)
+(MOVHstore [off] {sym} ptr (MOVWreg x) mem) -> (MOVHstore [off] {sym} ptr x mem)
+(MOVHstore [off] {sym} ptr (MOVWUreg x) mem) -> (MOVHstore [off] {sym} ptr x mem)
+(MOVWstore [off] {sym} ptr (MOVWreg x) mem) -> (MOVWstore [off] {sym} ptr x mem)
+(MOVWstore [off] {sym} ptr (MOVWUreg x) mem) -> (MOVWstore [off] {sym} ptr x mem)
+
+// if a register move has only 1 use, just use the same register without emitting instruction
+// MOVDnop doesn't emit instruction, only for ensuring the type.
+(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)
+
+(SLL x (MOVDconst [c])) -> (SLLconst x [c&63]) // Note: I don't think we ever generate bad constant shifts (i.e. c>=64)
+(SRL x (MOVDconst [c])) -> (SRLconst x [c&63])
+(SRA x (MOVDconst [c])) -> (SRAconst x [c&63])
+
+(CMP x (MOVDconst [c])) -> (CMPconst [c] x)
+(CMP (MOVDconst [c]) x) -> (InvertFlags (CMPconst [c] x))
+(CMPW x (MOVDconst [c])) -> (CMPWconst [int64(int32(c))] x)
+(CMPW (MOVDconst [c]) x) -> (InvertFlags (CMPWconst [int64(int32(c))] x))
+
+// mul by constant
+(MUL x (MOVDconst [-1])) -> (NEG x)
+(MUL _ (MOVDconst [0])) -> (MOVDconst [0])
+(MUL x (MOVDconst [1])) -> x
+(MUL x (MOVDconst [c])) && isPowerOfTwo(c) -> (SLLconst [log2(c)] x)
+(MUL x (MOVDconst [c])) && isPowerOfTwo(c-1) && c >= 3 -> (ADDshiftLL x x [log2(c-1)])
+(MUL x (MOVDconst [c])) && isPowerOfTwo(c+1) && c >= 7 -> (ADDshiftLL (NEG <x.Type> x) x [log2(c+1)])
+(MUL x (MOVDconst [c])) && c%3 == 0 && isPowerOfTwo(c/3) -> (SLLconst [log2(c/3)] (ADDshiftLL <x.Type> x x [1]))
+(MUL x (MOVDconst [c])) && c%5 == 0 && isPowerOfTwo(c/5) -> (SLLconst [log2(c/5)] (ADDshiftLL <x.Type> x x [2]))
+(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
+(MULW x (MOVDconst [c])) && isPowerOfTwo(c) -> (SLLconst [log2(c)] x)
+(MULW x (MOVDconst [c])) && isPowerOfTwo(c-1) && int32(c) >= 3 -> (ADDshiftLL x x [log2(c-1)])
+(MULW x (MOVDconst [c])) && isPowerOfTwo(c+1) && int32(c) >= 7 -> (ADDshiftLL (NEG <x.Type> x) x [log2(c+1)])
+(MULW x (MOVDconst [c])) && c%3 == 0 && isPowerOfTwo(c/3) && is32Bit(c) -> (SLLconst [log2(c/3)] (ADDshiftLL <x.Type> x x [1]))
+(MULW x (MOVDconst [c])) && c%5 == 0 && isPowerOfTwo(c/5) && is32Bit(c) -> (SLLconst [log2(c/5)] (ADDshiftLL <x.Type> x x [2]))
+(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)
+(UDIVW x (MOVDconst [c])) && uint32(c)==1 -> x
+(UDIVW x (MOVDconst [c])) && isPowerOfTwo(c) && is32Bit(c) -> (SRLconst [log2(c)] x)
+(UMOD _ (MOVDconst [1])) -> (MOVDconst [0])
+(UMOD x (MOVDconst [c])) && isPowerOfTwo(c) -> (ANDconst [c-1] x)
+(UMODW _ (MOVDconst [c])) && uint32(c)==1 -> (MOVDconst [0])
+(UMODW x (MOVDconst [c])) && isPowerOfTwo(c) && is32Bit(c) -> (ANDconst [c-1] x)
+
+// 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
+(XOR x x) -> (MOVDconst [0])
+(BIC x x) -> (MOVDconst [0])
+(AND x (MVN y)) -> (BIC x y)
+(CSELULT x (MOVDconst [0]) flag) -> (CSELULT0 x flag)
+
+// remove redundant *const ops
+(ADDconst [0] x) -> x
+(SUBconst [0] x) -> x
+(ANDconst [0] _) -> (MOVDconst [0])
+(ANDconst [-1] x) -> x
+(ORconst [0] x) -> x
+(ORconst [-1] _) -> (MOVDconst [-1])
+(XORconst [0] x) -> x
+(XORconst [-1] x) -> (MVN x)
+(BICconst [0] x) -> x
+(BICconst [-1] _) -> (MOVDconst [0])
+
+// generic constant folding
+(ADDconst [c] (MOVDconst [d])) -> (MOVDconst [c+d])
+(ADDconst [c] (ADDconst [d] x)) -> (ADDconst [c+d] x)
+(ADDconst [c] (SUBconst [d] x)) -> (ADDconst [c-d] x)
+(SUBconst [c] (MOVDconst [d])) -> (MOVDconst [d-c])
+(SUBconst [c] (SUBconst [d] x)) -> (ADDconst [-c-d] x)
+(SUBconst [c] (ADDconst [d] x)) -> (ADDconst [-c+d] x)
+(SLLconst [c] (MOVDconst [d])) -> (MOVDconst [int64(d)<<uint64(c)])
+(SRLconst [c] (MOVDconst [d])) -> (MOVDconst [int64(uint64(d)>>uint64(c))])
+(SRAconst [c] (MOVDconst [d])) -> (MOVDconst [int64(d)>>uint64(c)])
+(MUL (MOVDconst [c]) (MOVDconst [d])) -> (MOVDconst [c*d])
+(MULW (MOVDconst [c]) (MOVDconst [d])) -> (MOVDconst [int64(int32(c)*int32(d))])
+(DIV (MOVDconst [c]) (MOVDconst [d])) -> (MOVDconst [int64(c)/int64(d)])
+(UDIV (MOVDconst [c]) (MOVDconst [d])) -> (MOVDconst [int64(uint64(c)/uint64(d))])
+(DIVW (MOVDconst [c]) (MOVDconst [d])) -> (MOVDconst [int64(int32(c)/int32(d))])
+(UDIVW (MOVDconst [c]) (MOVDconst [d])) -> (MOVDconst [int64(uint32(c)/uint32(d))])
+(MOD (MOVDconst [c]) (MOVDconst [d])) -> (MOVDconst [int64(c)%int64(d)])
+(UMOD (MOVDconst [c]) (MOVDconst [d])) -> (MOVDconst [int64(uint64(c)%uint64(d))])
+(MODW (MOVDconst [c]) (MOVDconst [d])) -> (MOVDconst [int64(int32(c)%int32(d))])
+(UMODW (MOVDconst [c]) (MOVDconst [d])) -> (MOVDconst [int64(uint32(c)%uint32(d))])
+(ANDconst [c] (MOVDconst [d])) -> (MOVDconst [c&d])
+(ANDconst [c] (ANDconst [d] x)) -> (ANDconst [c&d] x)
+(ORconst [c] (MOVDconst [d])) -> (MOVDconst [c|d])
+(ORconst [c] (ORconst [d] x)) -> (ORconst [c|d] x)
+(XORconst [c] (MOVDconst [d])) -> (MOVDconst [c^d])
+(XORconst [c] (XORconst [d] x)) -> (XORconst [c^d] x)
+(BICconst [c] (MOVDconst [d])) -> (MOVDconst [d&^c])
+(MVN (MOVDconst [c])) -> (MOVDconst [^c])
+(NEG (MOVDconst [c])) -> (MOVDconst [-c])
+(MOVBreg (MOVDconst [c])) -> (MOVDconst [int64(int8(c))])
+(MOVBUreg (MOVDconst [c])) -> (MOVDconst [int64(uint8(c))])
+(MOVHreg (MOVDconst [c])) -> (MOVDconst [int64(int16(c))])
+(MOVHUreg (MOVDconst [c])) -> (MOVDconst [int64(uint16(c))])
+(MOVWreg (MOVDconst [c])) -> (MOVDconst [int64(int32(c))])
+(MOVWUreg (MOVDconst [c])) -> (MOVDconst [int64(uint32(c))])
+(MOVDreg (MOVDconst [c])) -> (MOVDconst [c])
+
+// constant comparisons
+(CMPconst (MOVDconst [x]) [y]) && x==y -> (FlagEQ)
+(CMPconst (MOVDconst [x]) [y]) && int64(x)<int64(y) && uint64(x)<uint64(y) -> (FlagLT_ULT)
+(CMPconst (MOVDconst [x]) [y]) && int64(x)<int64(y) && uint64(x)>uint64(y) -> (FlagLT_UGT)
+(CMPconst (MOVDconst [x]) [y]) && int64(x)>int64(y) && uint64(x)<uint64(y) -> (FlagGT_ULT)
+(CMPconst (MOVDconst [x]) [y]) && int64(x)>int64(y) && uint64(x)>uint64(y) -> (FlagGT_UGT)
+(CMPWconst (MOVDconst [x]) [y]) && int32(x)==int32(y) -> (FlagEQ)
+(CMPWconst (MOVDconst [x]) [y]) && int32(x)<int32(y) && uint32(x)<uint32(y) -> (FlagLT_ULT)
+(CMPWconst (MOVDconst [x]) [y]) && int32(x)<int32(y) && uint32(x)>uint32(y) -> (FlagLT_UGT)
+(CMPWconst (MOVDconst [x]) [y]) && int32(x)>int32(y) && uint32(x)<uint32(y) -> (FlagGT_ULT)
+(CMPWconst (MOVDconst [x]) [y]) && int32(x)>int32(y) && uint32(x)>uint32(y) -> (FlagGT_UGT)
+
+// other known comparisons
+(CMPconst (MOVBUreg _) [c]) && 0xff < c -> (FlagLT_ULT)
+(CMPconst (MOVHUreg _) [c]) && 0xffff < c -> (FlagLT_ULT)
+(CMPconst (MOVWUreg _) [c]) && 0xffffffff < c -> (FlagLT_ULT)
+(CMPconst (ANDconst _ [m]) [n]) && 0 <= m && m < n -> (FlagLT_ULT)
+(CMPconst (SRLconst _ [c]) [n]) && 0 <= n && 0 < c && c <= 63 && (1<<uint64(64-c)) <= uint64(n) -> (FlagLT_ULT)
+(CMPWconst (MOVBUreg _) [c]) && 0xff < int32(c) -> (FlagLT_ULT)
+(CMPWconst (MOVHUreg _) [c]) && 0xffff < int32(c) -> (FlagLT_ULT)
+
+// absorb flag constants into branches
+(EQ (FlagEQ) yes no) -> (First nil yes no)
+(EQ (FlagLT_ULT) yes no) -> (First nil no yes)
+(EQ (FlagLT_UGT) yes no) -> (First nil no yes)
+(EQ (FlagGT_ULT) yes no) -> (First nil no yes)
+(EQ (FlagGT_UGT) yes no) -> (First nil no yes)
+
+(NE (FlagEQ) yes no) -> (First nil no yes)
+(NE (FlagLT_ULT) yes no) -> (First nil yes no)
+(NE (FlagLT_UGT) yes no) -> (First nil yes no)
+(NE (FlagGT_ULT) yes no) -> (First nil yes no)
+(NE (FlagGT_UGT) yes no) -> (First nil yes no)
+
+(LT (FlagEQ) yes no) -> (First nil no yes)
+(LT (FlagLT_ULT) yes no) -> (First nil yes no)
+(LT (FlagLT_UGT) yes no) -> (First nil yes no)
+(LT (FlagGT_ULT) yes no) -> (First nil no yes)
+(LT (FlagGT_UGT) yes no) -> (First nil no yes)
+
+(LE (FlagEQ) yes no) -> (First nil yes no)
+(LE (FlagLT_ULT) yes no) -> (First nil yes no)
+(LE (FlagLT_UGT) yes no) -> (First nil yes no)
+(LE (FlagGT_ULT) yes no) -> (First nil no yes)
+(LE (FlagGT_UGT) yes no) -> (First nil no yes)
+
+(GT (FlagEQ) yes no) -> (First nil no yes)
+(GT (FlagLT_ULT) yes no) -> (First nil no yes)
+(GT (FlagLT_UGT) yes no) -> (First nil no yes)
+(GT (FlagGT_ULT) yes no) -> (First nil yes no)
+(GT (FlagGT_UGT) yes no) -> (First nil yes no)
+
+(GE (FlagEQ) yes no) -> (First nil yes no)
+(GE (FlagLT_ULT) yes no) -> (First nil no yes)
+(GE (FlagLT_UGT) yes no) -> (First nil no yes)
+(GE (FlagGT_ULT) yes no) -> (First nil yes no)
+(GE (FlagGT_UGT) yes no) -> (First nil yes no)
+
+(ULT (FlagEQ) yes no) -> (First nil no yes)
+(ULT (FlagLT_ULT) yes no) -> (First nil yes no)
+(ULT (FlagLT_UGT) yes no) -> (First nil no yes)
+(ULT (FlagGT_ULT) yes no) -> (First nil yes no)
+(ULT (FlagGT_UGT) yes no) -> (First nil no yes)
+
+(ULE (FlagEQ) yes no) -> (First nil yes no)
+(ULE (FlagLT_ULT) yes no) -> (First nil yes no)
+(ULE (FlagLT_UGT) yes no) -> (First nil no yes)
+(ULE (FlagGT_ULT) yes no) -> (First nil yes no)
+(ULE (FlagGT_UGT) yes no) -> (First nil no yes)
+
+(UGT (FlagEQ) yes no) -> (First nil no yes)
+(UGT (FlagLT_ULT) yes no) -> (First nil no yes)
+(UGT (FlagLT_UGT) yes no) -> (First nil yes no)
+(UGT (FlagGT_ULT) yes no) -> (First nil no yes)
+(UGT (FlagGT_UGT) yes no) -> (First nil yes no)
+
+(UGE (FlagEQ) yes no) -> (First nil yes no)
+(UGE (FlagLT_ULT) yes no) -> (First nil no yes)
+(UGE (FlagLT_UGT) yes no) -> (First nil yes no)
+(UGE (FlagGT_ULT) yes no) -> (First nil no yes)
+(UGE (FlagGT_UGT) yes no) -> (First nil yes no)
+
+(Z (MOVDconst [0]) yes no) -> (First nil yes no)
+(Z (MOVDconst [c]) yes no) && c != 0 -> (First nil no yes)
+(NZ (MOVDconst [0]) yes no) -> (First nil no yes)
+(NZ (MOVDconst [c]) yes no) && c != 0 -> (First nil yes no)
+(ZW (MOVDconst [c]) yes no) && int32(c) == 0 -> (First nil yes no)
+(ZW (MOVDconst [c]) yes no) && int32(c) != 0 -> (First nil no yes)
+(NZW (MOVDconst [c]) yes no) && int32(c) == 0 -> (First nil no yes)
+(NZW (MOVDconst [c]) yes no) && int32(c) != 0 -> (First nil yes no)
+
+// absorb InvertFlags into branches
+(LT (InvertFlags cmp) yes no) -> (GT cmp yes no)
+(GT (InvertFlags cmp) yes no) -> (LT cmp yes no)
+(LE (InvertFlags cmp) yes no) -> (GE cmp yes no)
+(GE (InvertFlags cmp) yes no) -> (LE cmp yes no)
+(ULT (InvertFlags cmp) yes no) -> (UGT cmp yes no)
+(UGT (InvertFlags cmp) yes no) -> (ULT cmp yes no)
+(ULE (InvertFlags cmp) yes no) -> (UGE cmp yes no)
+(UGE (InvertFlags cmp) yes no) -> (ULE cmp yes no)
+(EQ (InvertFlags cmp) yes no) -> (EQ cmp yes no)
+(NE (InvertFlags cmp) yes no) -> (NE cmp yes no)
+
+// absorb flag constants into boolean values
+(Equal (FlagEQ)) -> (MOVDconst [1])
+(Equal (FlagLT_ULT)) -> (MOVDconst [0])
+(Equal (FlagLT_UGT)) -> (MOVDconst [0])
+(Equal (FlagGT_ULT)) -> (MOVDconst [0])
+(Equal (FlagGT_UGT)) -> (MOVDconst [0])
+
+(NotEqual (FlagEQ)) -> (MOVDconst [0])
+(NotEqual (FlagLT_ULT)) -> (MOVDconst [1])
+(NotEqual (FlagLT_UGT)) -> (MOVDconst [1])
+(NotEqual (FlagGT_ULT)) -> (MOVDconst [1])
+(NotEqual (FlagGT_UGT)) -> (MOVDconst [1])
+
+(LessThan (FlagEQ)) -> (MOVDconst [0])
+(LessThan (FlagLT_ULT)) -> (MOVDconst [1])
+(LessThan (FlagLT_UGT)) -> (MOVDconst [1])
+(LessThan (FlagGT_ULT)) -> (MOVDconst [0])
+(LessThan (FlagGT_UGT)) -> (MOVDconst [0])
+
+(LessThanU (FlagEQ)) -> (MOVDconst [0])
+(LessThanU (FlagLT_ULT)) -> (MOVDconst [1])
+(LessThanU (FlagLT_UGT)) -> (MOVDconst [0])
+(LessThanU (FlagGT_ULT)) -> (MOVDconst [1])
+(LessThanU (FlagGT_UGT)) -> (MOVDconst [0])
+
+(LessEqual (FlagEQ)) -> (MOVDconst [1])
+(LessEqual (FlagLT_ULT)) -> (MOVDconst [1])
+(LessEqual (FlagLT_UGT)) -> (MOVDconst [1])
+(LessEqual (FlagGT_ULT)) -> (MOVDconst [0])
+(LessEqual (FlagGT_UGT)) -> (MOVDconst [0])
+
+(LessEqualU (FlagEQ)) -> (MOVDconst [1])
+(LessEqualU (FlagLT_ULT)) -> (MOVDconst [1])
+(LessEqualU (FlagLT_UGT)) -> (MOVDconst [0])
+(LessEqualU (FlagGT_ULT)) -> (MOVDconst [1])
+(LessEqualU (FlagGT_UGT)) -> (MOVDconst [0])
+
+(GreaterThan (FlagEQ)) -> (MOVDconst [0])
+(GreaterThan (FlagLT_ULT)) -> (MOVDconst [0])
+(GreaterThan (FlagLT_UGT)) -> (MOVDconst [0])
+(GreaterThan (FlagGT_ULT)) -> (MOVDconst [1])
+(GreaterThan (FlagGT_UGT)) -> (MOVDconst [1])
+
+(GreaterThanU (FlagEQ)) -> (MOVDconst [0])
+(GreaterThanU (FlagLT_ULT)) -> (MOVDconst [0])
+(GreaterThanU (FlagLT_UGT)) -> (MOVDconst [1])
+(GreaterThanU (FlagGT_ULT)) -> (MOVDconst [0])
+(GreaterThanU (FlagGT_UGT)) -> (MOVDconst [1])
+
+(GreaterEqual (FlagEQ)) -> (MOVDconst [1])
+(GreaterEqual (FlagLT_ULT)) -> (MOVDconst [0])
+(GreaterEqual (FlagLT_UGT)) -> (MOVDconst [0])
+(GreaterEqual (FlagGT_ULT)) -> (MOVDconst [1])
+(GreaterEqual (FlagGT_UGT)) -> (MOVDconst [1])
+
+(GreaterEqualU (FlagEQ)) -> (MOVDconst [1])
+(GreaterEqualU (FlagLT_ULT)) -> (MOVDconst [0])
+(GreaterEqualU (FlagLT_UGT)) -> (MOVDconst [1])
+(GreaterEqualU (FlagGT_ULT)) -> (MOVDconst [0])
+(GreaterEqualU (FlagGT_UGT)) -> (MOVDconst [1])
+
+// absorb InvertFlags into boolean values
+(Equal (InvertFlags x)) -> (Equal x)
+(NotEqual (InvertFlags x)) -> (NotEqual x)
+(LessThan (InvertFlags x)) -> (GreaterThan x)
+(LessThanU (InvertFlags x)) -> (GreaterThanU x)
+(GreaterThan (InvertFlags x)) -> (LessThan x)
+(GreaterThanU (InvertFlags x)) -> (LessThanU x)
+(LessEqual (InvertFlags x)) -> (GreaterEqual x)
+(LessEqualU (InvertFlags x)) -> (GreaterEqualU x)
+(GreaterEqual (InvertFlags x)) -> (LessEqual x)
+(GreaterEqualU (InvertFlags x)) -> (LessEqualU x)
+
+// absorb flag constants into conditional instructions
+(CSELULT _ y (FlagEQ)) -> y
+(CSELULT x _ (FlagLT_ULT)) -> x
+(CSELULT _ y (FlagLT_UGT)) -> y
+(CSELULT x _ (FlagGT_ULT)) -> x
+(CSELULT _ y (FlagGT_UGT)) -> y
+(CSELULT0 _ (FlagEQ)) -> (MOVDconst [0])
+(CSELULT0 x (FlagLT_ULT)) -> x
+(CSELULT0 _ (FlagLT_UGT)) -> (MOVDconst [0])
+(CSELULT0 x (FlagGT_ULT)) -> x
+(CSELULT0 _ (FlagGT_UGT)) -> (MOVDconst [0])
+
+// 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 (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])
+(CMP x (SLLconst [c] y)) -> (CMPshiftLL x y [c])
+(CMP (SLLconst [c] y) x) -> (InvertFlags (CMPshiftLL x y [c]))
+(CMP x (SRLconst [c] y)) -> (CMPshiftRL x y [c])
+(CMP (SRLconst [c] y) x) -> (InvertFlags (CMPshiftRL x y [c]))
+(CMP x (SRAconst [c] y)) -> (CMPshiftRA x y [c])
+(CMP (SRAconst [c] y) x) -> (InvertFlags (CMPshiftRA x y [c]))
+
+// prefer *const ops to *shift ops
+(ADDshiftLL (MOVDconst [c]) x [d]) -> (ADDconst [c] (SLLconst <x.Type> x [d]))
+(ADDshiftRL (MOVDconst [c]) x [d]) -> (ADDconst [c] (SRLconst <x.Type> x [d]))
+(ADDshiftRA (MOVDconst [c]) x [d]) -> (ADDconst [c] (SRAconst <x.Type> x [d]))
+(ANDshiftLL (MOVDconst [c]) x [d]) -> (ANDconst [c] (SLLconst <x.Type> x [d]))
+(ANDshiftRL (MOVDconst [c]) x [d]) -> (ANDconst [c] (SRLconst <x.Type> x [d]))
+(ANDshiftRA (MOVDconst [c]) x [d]) -> (ANDconst [c] (SRAconst <x.Type> x [d]))
+(ORshiftLL (MOVDconst [c]) x [d]) -> (ORconst [c] (SLLconst <x.Type> x [d]))
+(ORshiftRL (MOVDconst [c]) x [d]) -> (ORconst [c] (SRLconst <x.Type> x [d]))
+(ORshiftRA (MOVDconst [c]) x [d]) -> (ORconst [c] (SRAconst <x.Type> x [d]))
+(XORshiftLL (MOVDconst [c]) x [d]) -> (XORconst [c] (SLLconst <x.Type> x [d]))
+(XORshiftRL (MOVDconst [c]) x [d]) -> (XORconst [c] (SRLconst <x.Type> x [d]))
+(XORshiftRA (MOVDconst [c]) x [d]) -> (XORconst [c] (SRAconst <x.Type> x [d]))
+(CMPshiftLL (MOVDconst [c]) x [d]) -> (InvertFlags (CMPconst [c] (SLLconst <x.Type> x [d])))
+(CMPshiftRL (MOVDconst [c]) x [d]) -> (InvertFlags (CMPconst [c] (SRLconst <x.Type> x [d])))
+(CMPshiftRA (MOVDconst [c]) x [d]) -> (InvertFlags (CMPconst [c] (SRAconst <x.Type> x [d])))
+
+// constant folding in *shift ops
+(ADDshiftLL x (MOVDconst [c]) [d]) -> (ADDconst x [int64(uint64(c)<<uint64(d))])
+(ADDshiftRL x (MOVDconst [c]) [d]) -> (ADDconst x [int64(uint64(c)>>uint64(d))])
+(ADDshiftRA x (MOVDconst [c]) [d]) -> (ADDconst x [int64(int64(c)>>uint64(d))])
+(SUBshiftLL x (MOVDconst [c]) [d]) -> (SUBconst x [int64(uint64(c)<<uint64(d))])
+(SUBshiftRL x (MOVDconst [c]) [d]) -> (SUBconst x [int64(uint64(c)>>uint64(d))])
+(SUBshiftRA x (MOVDconst [c]) [d]) -> (SUBconst x [int64(int64(c)>>uint64(d))])
+(ANDshiftLL x (MOVDconst [c]) [d]) -> (ANDconst x [int64(uint64(c)<<uint64(d))])
+(ANDshiftRL x (MOVDconst [c]) [d]) -> (ANDconst x [int64(uint64(c)>>uint64(d))])
+(ANDshiftRA x (MOVDconst [c]) [d]) -> (ANDconst x [int64(int64(c)>>uint64(d))])
+(ORshiftLL x (MOVDconst [c]) [d]) -> (ORconst x [int64(uint64(c)<<uint64(d))])
+(ORshiftRL x (MOVDconst [c]) [d]) -> (ORconst x [int64(uint64(c)>>uint64(d))])
+(ORshiftRA x (MOVDconst [c]) [d]) -> (ORconst x [int64(int64(c)>>uint64(d))])
+(XORshiftLL x (MOVDconst [c]) [d]) -> (XORconst x [int64(uint64(c)<<uint64(d))])
+(XORshiftRL x (MOVDconst [c]) [d]) -> (XORconst x [int64(uint64(c)>>uint64(d))])
+(XORshiftRA x (MOVDconst [c]) [d]) -> (XORconst x [int64(int64(c)>>uint64(d))])
+(BICshiftLL x (MOVDconst [c]) [d]) -> (BICconst x [int64(uint64(c)<<uint64(d))])
+(BICshiftRL x (MOVDconst [c]) [d]) -> (BICconst x [int64(uint64(c)>>uint64(d))])
+(BICshiftRA x (MOVDconst [c]) [d]) -> (BICconst x [int64(int64(c)>>uint64(d))])
+(CMPshiftLL x (MOVDconst [c]) [d]) -> (CMPconst x [int64(uint64(c)<<uint64(d))])
+(CMPshiftRL x (MOVDconst [c]) [d]) -> (CMPconst x [int64(uint64(c)>>uint64(d))])
+(CMPshiftRA x (MOVDconst [c]) [d]) -> (CMPconst x [int64(int64(c)>>uint64(d))])
+
+// simplification with *shift ops
+(SUBshiftLL x (SLLconst x [c]) [d]) && c==d -> (MOVDconst [0])
+(SUBshiftRL x (SRLconst x [c]) [d]) && c==d -> (MOVDconst [0])
+(SUBshiftRA x (SRAconst x [c]) [d]) && c==d -> (MOVDconst [0])
+(ANDshiftLL x y:(SLLconst x [c]) [d]) && c==d -> y
+(ANDshiftRL x y:(SRLconst x [c]) [d]) && c==d -> y
+(ANDshiftRA x y:(SRAconst x [c]) [d]) && c==d -> y
+(ORshiftLL x y:(SLLconst x [c]) [d]) && c==d -> y
+(ORshiftRL x y:(SRLconst x [c]) [d]) && c==d -> y
+(ORshiftRA x y:(SRAconst x [c]) [d]) && c==d -> y
+(XORshiftLL x (SLLconst x [c]) [d]) && c==d -> (MOVDconst [0])
+(XORshiftRL x (SRLconst x [c]) [d]) && c==d -> (MOVDconst [0])
+(XORshiftRA x (SRAconst x [c]) [d]) && c==d -> (MOVDconst [0])
+(BICshiftLL x (SLLconst x [c]) [d]) && c==d -> (MOVDconst [0])
+(BICshiftRL x (SRLconst x [c]) [d]) && c==d -> (MOVDconst [0])
+(BICshiftRA x (SRAconst x [c]) [d]) && c==d -> (MOVDconst [0])
+
+// 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)))
+ && 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)
+
+// 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.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)
+ -> @mergePoint(b,x0,x1,x2) (MOVWUload <t> {s} (OffPtr <p.Type> [i] 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.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)
+ -> @mergePoint(b,x0,x1,x2,x3,x4) (MOVDload <t> {s} (OffPtr <p.Type> [i] 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)))
+ && 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)
+ -> @mergePoint(b,x0,x1,x2,x3) (MOVWUload <t> {s} (OffPtr <p.Type> [i-3] 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)))
+ && 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)
+ && clobber(x4) && clobber(x5) && clobber(x6) && clobber(x7)
+ && clobber(y0) && clobber(y1) && clobber(y2) && clobber(y3)
+ && 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))
+
+// 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))
+ && 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))
+
+// 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)))
+ && 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)
+ -> @mergePoint(b,x0,x1,x2) (REVW <t> (MOVWUload <t> {s} (OffPtr <p.Type> [i-2] 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)))
+ && 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)
+ -> @mergePoint(b,x0,x1,x2,x3,x4) (REV <t> (MOVDload <t> {s} (OffPtr <p.Type> [i-4] 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)))
+ && 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)
+ -> @mergePoint(b,x0,x1,x2,x3) (REVW <t> (MOVWUload <t> {s} (OffPtr <p.Type> [i] 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)))
+ && 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)
+ && clobber(x4) && clobber(x5) && clobber(x6) && clobber(x7)
+ && clobber(y0) && clobber(y1) && clobber(y2) && clobber(y3)
+ && 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))
diff --git a/src/cmd/compile/internal/ssa/gen/ARM64Ops.go b/src/cmd/compile/internal/ssa/gen/ARM64Ops.go
new file mode 100644
index 0000000..dce61e3
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/gen/ARM64Ops.go
@@ -0,0 +1,535 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build ignore
+
+package main
+
+import "strings"
+
+// Notes:
+// - Integer types live in the low portion of registers. Upper portions are junk.
+// - Boolean types use the low-order byte of a register. 0=false, 1=true.
+// Upper bytes are junk.
+// - *const instructions may use a constant larger than the instuction can encode.
+// In this case the assembler expands to multiple instructions and uses tmp
+// register (R27).
+
+// Suffixes encode the bit width of various instructions.
+// D (double word) = 64 bit
+// W (word) = 32 bit
+// H (half word) = 16 bit
+// HU = 16 bit unsigned
+// B (byte) = 8 bit
+// BU = 8 bit unsigned
+// S (single) = 32 bit float
+// D (double) = 64 bit float
+
+// Note: registers not used in regalloc are not included in this list,
+// so that regmask stays within int64
+// Be careful when hand coding regmasks.
+var regNamesARM64 = []string{
+ "R0",
+ "R1",
+ "R2",
+ "R3",
+ "R4",
+ "R5",
+ "R6",
+ "R7",
+ "R8",
+ "R9",
+ "R10",
+ "R11",
+ "R12",
+ "R13",
+ "R14",
+ "R15",
+ "R16",
+ "R17",
+ "R18", // platform register, not used
+ "R19",
+ "R20",
+ "R21",
+ "R22",
+ "R23",
+ "R24",
+ "R25",
+ "R26",
+ // R27 = REGTMP not used in regalloc
+ "g", // aka R28
+ "R29", // frame pointer, not used
+ "R30", // aka REGLINK
+ "SP", // aka 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",
+
+ // pseudo-registers
+ "SB",
+}
+
+func init() {
+ // Make map from reg names to reg integers.
+ if len(regNamesARM64) > 64 {
+ panic("too many registers")
+ }
+ num := map[string]int{}
+ for i, name := range regNamesARM64 {
+ num[name] = i
+ }
+ buildReg := func(s string) regMask {
+ m := regMask(0)
+ for _, r := range strings.Split(s, " ") {
+ if n, ok := num[r]; ok {
+ m |= regMask(1) << uint(n)
+ continue
+ }
+ panic("register " + r + " not found")
+ }
+ return m
+ }
+
+ // Common individual register masks
+ var (
+ gp = buildReg("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 R30")
+ gpg = gp | buildReg("g")
+ gpsp = gp | buildReg("SP")
+ gpspg = gpg | buildReg("SP")
+ gpspsbg = gpspg | buildReg("SB")
+ fp = buildReg("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")
+ callerSave = gp | fp | buildReg("g") // runtime.setg (and anything calling it) may clobber g
+ )
+ // Common regInfo
+ var (
+ gp01 = regInfo{inputs: nil, outputs: []regMask{gp}}
+ gp11 = regInfo{inputs: []regMask{gpg}, outputs: []regMask{gp}}
+ gp11sp = regInfo{inputs: []regMask{gpspg}, outputs: []regMask{gp}}
+ gp1flags = regInfo{inputs: []regMask{gpg}}
+ gp1flags1 = regInfo{inputs: []regMask{gpg}, outputs: []regMask{gp}}
+ gp21 = regInfo{inputs: []regMask{gpg, gpg}, outputs: []regMask{gp}}
+ gp2flags = regInfo{inputs: []regMask{gpg, gpg}}
+ gp2flags1 = regInfo{inputs: []regMask{gp, gp}, outputs: []regMask{gp}}
+ gpload = regInfo{inputs: []regMask{gpspsbg}, outputs: []regMask{gp}}
+ gpstore = regInfo{inputs: []regMask{gpspsbg, gpg}}
+ gpstore0 = regInfo{inputs: []regMask{gpspsbg}}
+ gpxchg = regInfo{inputs: []regMask{gpspsbg, gpg}, outputs: []regMask{gp}}
+ gpcas = regInfo{inputs: []regMask{gpspsbg, gpg, gpg}, 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}}
+ fp2flags = regInfo{inputs: []regMask{fp, fp}}
+ fpload = regInfo{inputs: []regMask{gpspsbg}, outputs: []regMask{fp}}
+ fpstore = regInfo{inputs: []regMask{gpspsbg, fp}}
+ readflags = regInfo{inputs: nil, outputs: []regMask{gp}}
+ )
+ ops := []opData{
+ // binary ops
+ {name: "ADD", argLength: 2, reg: gp21, asm: "ADD", commutative: true}, // arg0 + arg1
+ {name: "ADDconst", argLength: 1, reg: gp11sp, asm: "ADD", aux: "Int64"}, // arg0 + auxInt
+ {name: "SUB", argLength: 2, reg: gp21, asm: "SUB"}, // arg0 - arg1
+ {name: "SUBconst", argLength: 1, reg: gp11, asm: "SUB", aux: "Int64"}, // arg0 - auxInt
+ {name: "MUL", argLength: 2, reg: gp21, asm: "MUL", commutative: true}, // arg0 * arg1
+ {name: "MULW", argLength: 2, reg: gp21, asm: "MULW", commutative: true}, // arg0 * arg1, 32-bit
+ {name: "MULH", argLength: 2, reg: gp21, asm: "SMULH", commutative: true}, // (arg0 * arg1) >> 64, signed
+ {name: "UMULH", argLength: 2, reg: gp21, asm: "UMULH", commutative: true}, // (arg0 * arg1) >> 64, unsigned
+ {name: "MULL", argLength: 2, reg: gp21, asm: "SMULL", commutative: true}, // arg0 * arg1, signed, 32-bit mult results in 64-bit
+ {name: "UMULL", argLength: 2, reg: gp21, asm: "UMULL", commutative: true}, // arg0 * arg1, unsigned, 32-bit mult results in 64-bit
+ {name: "DIV", argLength: 2, reg: gp21, asm: "SDIV"}, // arg0 / arg1, signed
+ {name: "UDIV", argLength: 2, reg: gp21, asm: "UDIV"}, // arg0 / arg1, unsighed
+ {name: "DIVW", argLength: 2, reg: gp21, asm: "SDIVW"}, // arg0 / arg1, signed, 32 bit
+ {name: "UDIVW", argLength: 2, reg: gp21, asm: "UDIVW"}, // arg0 / arg1, unsighed, 32 bit
+ {name: "MOD", argLength: 2, reg: gp21, asm: "REM"}, // arg0 % arg1, signed
+ {name: "UMOD", argLength: 2, reg: gp21, asm: "UREM"}, // arg0 % arg1, unsigned
+ {name: "MODW", argLength: 2, reg: gp21, asm: "REMW"}, // arg0 % arg1, signed, 32 bit
+ {name: "UMODW", argLength: 2, reg: gp21, asm: "UREMW"}, // arg0 % arg1, unsigned, 32 bit
+
+ {name: "FADDS", argLength: 2, reg: fp21, asm: "FADDS", commutative: true}, // arg0 + arg1
+ {name: "FADDD", argLength: 2, reg: fp21, asm: "FADDD", commutative: true}, // arg0 + arg1
+ {name: "FSUBS", argLength: 2, reg: fp21, asm: "FSUBS"}, // arg0 - arg1
+ {name: "FSUBD", argLength: 2, reg: fp21, asm: "FSUBD"}, // arg0 - arg1
+ {name: "FMULS", argLength: 2, reg: fp21, asm: "FMULS", commutative: true}, // arg0 * arg1
+ {name: "FMULD", argLength: 2, reg: fp21, asm: "FMULD", commutative: true}, // arg0 * arg1
+ {name: "FDIVS", argLength: 2, reg: fp21, asm: "FDIVS"}, // arg0 / arg1
+ {name: "FDIVD", argLength: 2, reg: fp21, asm: "FDIVD"}, // arg0 / arg1
+
+ {name: "AND", argLength: 2, reg: gp21, asm: "AND", commutative: true}, // arg0 & arg1
+ {name: "ANDconst", argLength: 1, reg: gp11, asm: "AND", aux: "Int64"}, // arg0 & auxInt
+ {name: "OR", argLength: 2, reg: gp21, asm: "ORR", commutative: true}, // arg0 | arg1
+ {name: "ORconst", argLength: 1, reg: gp11, asm: "ORR", aux: "Int64"}, // arg0 | auxInt
+ {name: "XOR", argLength: 2, reg: gp21, asm: "EOR", commutative: true}, // arg0 ^ arg1
+ {name: "XORconst", argLength: 1, reg: gp11, asm: "EOR", aux: "Int64"}, // arg0 ^ auxInt
+ {name: "BIC", argLength: 2, reg: gp21, asm: "BIC"}, // arg0 &^ arg1
+ {name: "BICconst", argLength: 1, reg: gp11, asm: "BIC", aux: "Int64"}, // arg0 &^ auxInt
+
+ // unary ops
+ {name: "MVN", argLength: 1, reg: gp11, asm: "MVN"}, // ^arg0
+ {name: "NEG", argLength: 1, reg: gp11, asm: "NEG"}, // -arg0
+ {name: "FNEGS", argLength: 1, reg: fp11, asm: "FNEGS"}, // -arg0, float32
+ {name: "FNEGD", argLength: 1, reg: fp11, asm: "FNEGD"}, // -arg0, float64
+ {name: "FSQRTD", argLength: 1, reg: fp11, asm: "FSQRTD"}, // sqrt(arg0), float64
+ {name: "REV", argLength: 1, reg: gp11, asm: "REV"}, // byte reverse, 64-bit
+ {name: "REVW", argLength: 1, reg: gp11, asm: "REVW"}, // byte reverse, 32-bit
+ {name: "REV16W", argLength: 1, reg: gp11, asm: "REV16W"}, // byte reverse in each 16-bit halfword, 32-bit
+ {name: "RBIT", argLength: 1, reg: gp11, asm: "RBIT"}, // bit reverse, 64-bit
+ {name: "RBITW", argLength: 1, reg: gp11, asm: "RBITW"}, // bit reverse, 32-bit
+ {name: "CLZ", argLength: 1, reg: gp11, asm: "CLZ"}, // count leading zero, 64-bit
+ {name: "CLZW", argLength: 1, reg: gp11, asm: "CLZW"}, // count leading zero, 32-bit
+
+ // shifts
+ {name: "SLL", argLength: 2, reg: gp21, asm: "LSL"}, // arg0 << arg1, shift amount is mod 64
+ {name: "SLLconst", argLength: 1, reg: gp11, asm: "LSL", aux: "Int64"}, // arg0 << auxInt
+ {name: "SRL", argLength: 2, reg: gp21, asm: "LSR"}, // arg0 >> arg1, unsigned, shift amount is mod 64
+ {name: "SRLconst", argLength: 1, reg: gp11, asm: "LSR", aux: "Int64"}, // arg0 >> auxInt, unsigned
+ {name: "SRA", argLength: 2, reg: gp21, asm: "ASR"}, // arg0 >> arg1, signed, shift amount is mod 64
+ {name: "SRAconst", argLength: 1, reg: gp11, asm: "ASR", aux: "Int64"}, // arg0 >> auxInt, signed
+ {name: "RORconst", argLength: 1, reg: gp11, asm: "ROR", aux: "Int64"}, // arg0 right rotate by auxInt bits
+ {name: "RORWconst", argLength: 1, reg: gp11, asm: "RORW", aux: "Int64"}, // uint32(arg0) right rotate by auxInt bits
+
+ // comparisons
+ {name: "CMP", argLength: 2, reg: gp2flags, asm: "CMP", typ: "Flags"}, // arg0 compare to arg1
+ {name: "CMPconst", argLength: 1, reg: gp1flags, asm: "CMP", aux: "Int64", typ: "Flags"}, // arg0 compare to auxInt
+ {name: "CMPW", argLength: 2, reg: gp2flags, asm: "CMPW", typ: "Flags"}, // arg0 compare to arg1, 32 bit
+ {name: "CMPWconst", argLength: 1, reg: gp1flags, asm: "CMPW", aux: "Int32", typ: "Flags"}, // arg0 compare to auxInt, 32 bit
+ {name: "CMN", argLength: 2, reg: gp2flags, asm: "CMN", typ: "Flags"}, // arg0 compare to -arg1
+ {name: "CMNconst", argLength: 1, reg: gp1flags, asm: "CMN", aux: "Int64", typ: "Flags"}, // arg0 compare to -auxInt
+ {name: "CMNW", argLength: 2, reg: gp2flags, asm: "CMNW", typ: "Flags"}, // arg0 compare to -arg1, 32 bit
+ {name: "CMNWconst", argLength: 1, reg: gp1flags, asm: "CMNW", aux: "Int32", typ: "Flags"}, // arg0 compare to -auxInt, 32 bit
+ {name: "FCMPS", argLength: 2, reg: fp2flags, asm: "FCMPS", typ: "Flags"}, // arg0 compare to arg1, float32
+ {name: "FCMPD", argLength: 2, reg: fp2flags, asm: "FCMPD", typ: "Flags"}, // arg0 compare to arg1, float64
+
+ // shifted ops
+ {name: "ADDshiftLL", argLength: 2, reg: gp21, asm: "ADD", aux: "Int64"}, // arg0 + arg1<<auxInt
+ {name: "ADDshiftRL", argLength: 2, reg: gp21, asm: "ADD", aux: "Int64"}, // arg0 + arg1>>auxInt, unsigned shift
+ {name: "ADDshiftRA", argLength: 2, reg: gp21, asm: "ADD", aux: "Int64"}, // arg0 + arg1>>auxInt, signed shift
+ {name: "SUBshiftLL", argLength: 2, reg: gp21, asm: "SUB", aux: "Int64"}, // arg0 - arg1<<auxInt
+ {name: "SUBshiftRL", argLength: 2, reg: gp21, asm: "SUB", aux: "Int64"}, // arg0 - arg1>>auxInt, unsigned shift
+ {name: "SUBshiftRA", argLength: 2, reg: gp21, asm: "SUB", aux: "Int64"}, // arg0 - arg1>>auxInt, signed shift
+ {name: "ANDshiftLL", argLength: 2, reg: gp21, asm: "AND", aux: "Int64"}, // arg0 & (arg1<<auxInt)
+ {name: "ANDshiftRL", argLength: 2, reg: gp21, asm: "AND", aux: "Int64"}, // arg0 & (arg1>>auxInt), unsigned shift
+ {name: "ANDshiftRA", argLength: 2, reg: gp21, asm: "AND", aux: "Int64"}, // arg0 & (arg1>>auxInt), signed shift
+ {name: "ORshiftLL", argLength: 2, reg: gp21, asm: "ORR", aux: "Int64"}, // arg0 | arg1<<auxInt
+ {name: "ORshiftRL", argLength: 2, reg: gp21, asm: "ORR", aux: "Int64"}, // arg0 | arg1>>auxInt, unsigned shift
+ {name: "ORshiftRA", argLength: 2, reg: gp21, asm: "ORR", aux: "Int64"}, // arg0 | arg1>>auxInt, signed shift
+ {name: "XORshiftLL", argLength: 2, reg: gp21, asm: "EOR", aux: "Int64"}, // arg0 ^ arg1<<auxInt
+ {name: "XORshiftRL", argLength: 2, reg: gp21, asm: "EOR", aux: "Int64"}, // arg0 ^ arg1>>auxInt, unsigned shift
+ {name: "XORshiftRA", argLength: 2, reg: gp21, asm: "EOR", aux: "Int64"}, // arg0 ^ arg1>>auxInt, signed shift
+ {name: "BICshiftLL", argLength: 2, reg: gp21, asm: "BIC", aux: "Int64"}, // arg0 &^ (arg1<<auxInt)
+ {name: "BICshiftRL", argLength: 2, reg: gp21, asm: "BIC", aux: "Int64"}, // arg0 &^ (arg1>>auxInt), unsigned shift
+ {name: "BICshiftRA", argLength: 2, reg: gp21, asm: "BIC", aux: "Int64"}, // arg0 &^ (arg1>>auxInt), signed shift
+ {name: "CMPshiftLL", argLength: 2, reg: gp2flags, asm: "CMP", aux: "Int64", typ: "Flags"}, // arg0 compare to arg1<<auxInt
+ {name: "CMPshiftRL", argLength: 2, reg: gp2flags, asm: "CMP", aux: "Int64", typ: "Flags"}, // arg0 compare to arg1>>auxInt, unsigned shift
+ {name: "CMPshiftRA", argLength: 2, reg: gp2flags, asm: "CMP", aux: "Int64", typ: "Flags"}, // arg0 compare to arg1>>auxInt, signed shift
+
+ // moves
+ {name: "MOVDconst", argLength: 0, reg: gp01, aux: "Int64", asm: "MOVD", typ: "UInt64", rematerializeable: true}, // 32 low bits of auxint
+ {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.
+
+ // conversions
+ {name: "MOVBreg", argLength: 1, reg: gp11, asm: "MOVB"}, // move from arg0, sign-extended from byte
+ {name: "MOVBUreg", argLength: 1, reg: gp11, asm: "MOVBU"}, // move from arg0, unsign-extended from byte
+ {name: "MOVHreg", argLength: 1, reg: gp11, asm: "MOVH"}, // move from arg0, sign-extended from half
+ {name: "MOVHUreg", argLength: 1, reg: gp11, asm: "MOVHU"}, // move from arg0, unsign-extended from half
+ {name: "MOVWreg", argLength: 1, reg: gp11, asm: "MOVW"}, // move from arg0, sign-extended from word
+ {name: "MOVWUreg", argLength: 1, reg: gp11, asm: "MOVWU"}, // move from arg0, unsign-extended from word
+ {name: "MOVDreg", argLength: 1, reg: gp11, asm: "MOVD"}, // move from arg0
+
+ {name: "MOVDnop", argLength: 1, reg: regInfo{inputs: []regMask{gp}, outputs: []regMask{gp}}, resultInArg0: true}, // nop, return arg0 in same register
+
+ {name: "SCVTFWS", argLength: 1, reg: gpfp, asm: "SCVTFWS"}, // int32 -> float32
+ {name: "SCVTFWD", argLength: 1, reg: gpfp, asm: "SCVTFWD"}, // int32 -> float64
+ {name: "UCVTFWS", argLength: 1, reg: gpfp, asm: "UCVTFWS"}, // uint32 -> float32
+ {name: "UCVTFWD", argLength: 1, reg: gpfp, asm: "UCVTFWD"}, // uint32 -> float64
+ {name: "SCVTFS", argLength: 1, reg: gpfp, asm: "SCVTFS"}, // int64 -> float32
+ {name: "SCVTFD", argLength: 1, reg: gpfp, asm: "SCVTFD"}, // int64 -> float64
+ {name: "UCVTFS", argLength: 1, reg: gpfp, asm: "UCVTFS"}, // uint64 -> float32
+ {name: "UCVTFD", argLength: 1, reg: gpfp, asm: "UCVTFD"}, // uint64 -> float64
+ {name: "FCVTZSSW", argLength: 1, reg: fpgp, asm: "FCVTZSSW"}, // float32 -> int32
+ {name: "FCVTZSDW", argLength: 1, reg: fpgp, asm: "FCVTZSDW"}, // float64 -> int32
+ {name: "FCVTZUSW", argLength: 1, reg: fpgp, asm: "FCVTZUSW"}, // float32 -> uint32
+ {name: "FCVTZUDW", argLength: 1, reg: fpgp, asm: "FCVTZUDW"}, // float64 -> uint32
+ {name: "FCVTZSS", argLength: 1, reg: fpgp, asm: "FCVTZSS"}, // float32 -> int64
+ {name: "FCVTZSD", argLength: 1, reg: fpgp, asm: "FCVTZSD"}, // float64 -> int64
+ {name: "FCVTZUS", argLength: 1, reg: fpgp, asm: "FCVTZUS"}, // float32 -> uint64
+ {name: "FCVTZUD", argLength: 1, reg: fpgp, asm: "FCVTZUD"}, // float64 -> uint64
+ {name: "FCVTSD", argLength: 1, reg: fp11, asm: "FCVTSD"}, // float32 -> float64
+ {name: "FCVTDS", argLength: 1, reg: fp11, asm: "FCVTDS"}, // float64 -> float32
+
+ // conditional instructions
+ {name: "CSELULT", argLength: 3, reg: gp2flags1, asm: "CSEL"}, // returns arg0 if flags indicates unsigned LT, arg1 otherwise, arg2=flags
+ {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: "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
+ {name: "LoweredNilCheck", argLength: 2, reg: regInfo{inputs: []regMask{gpg}}, nilCheck: true, faultOnNilArg0: true}, // panic if arg0 is nil. arg1=mem.
+
+ {name: "Equal", argLength: 1, reg: readflags}, // bool, true flags encode x==y false otherwise.
+ {name: "NotEqual", argLength: 1, reg: readflags}, // bool, true flags encode x!=y false otherwise.
+ {name: "LessThan", argLength: 1, reg: readflags}, // bool, true flags encode signed x<y false otherwise.
+ {name: "LessEqual", argLength: 1, reg: readflags}, // bool, true flags encode signed x<=y false otherwise.
+ {name: "GreaterThan", argLength: 1, reg: readflags}, // bool, true flags encode signed x>y false otherwise.
+ {name: "GreaterEqual", argLength: 1, reg: readflags}, // bool, true flags encode signed x>=y false otherwise.
+ {name: "LessThanU", argLength: 1, reg: readflags}, // bool, true flags encode unsigned x<y false otherwise.
+ {name: "LessEqualU", argLength: 1, reg: readflags}, // bool, true flags encode unsigned x<=y false otherwise.
+ {name: "GreaterThanU", argLength: 1, reg: readflags}, // bool, true flags encode unsigned x>y false otherwise.
+ {name: "GreaterEqualU", argLength: 1, reg: readflags}, // bool, true flags encode unsigned x>=y false otherwise.
+
+ // duffzero
+ // arg0 = address of memory to zero
+ // arg1 = mem
+ // auxint = offset into duffzero code to start executing
+ // returns mem
+ // R16 aka arm64.REGRT1 changed as side effect
+ {
+ name: "DUFFZERO",
+ aux: "Int64",
+ argLength: 2,
+ reg: regInfo{
+ inputs: []regMask{gp},
+ clobbers: buildReg("R16 R30"),
+ },
+ faultOnNilArg0: true,
+ },
+
+ // large zeroing
+ // arg0 = address of memory to zero (in R16 aka arm64.REGRT1, changed as side effect)
+ // arg1 = address of the last element to zero
+ // arg2 = mem
+ // returns mem
+ // MOVD.P ZR, 8(R16)
+ // CMP Rarg1, R16
+ // BLE -2(PC)
+ // Note: the-end-of-the-memory may be not a valid pointer. it's a problem if it is spilled.
+ // the-end-of-the-memory - 8 is with the area to zero, ok to spill.
+ {
+ name: "LoweredZero",
+ argLength: 3,
+ reg: regInfo{
+ inputs: []regMask{buildReg("R16"), gp},
+ clobbers: buildReg("R16"),
+ },
+ clobberFlags: true,
+ faultOnNilArg0: true,
+ },
+
+ // duffcopy
+ // arg0 = address of dst memory (in R17 aka arm64.REGRT2, changed as side effect)
+ // arg1 = address of src memory (in R16 aka arm64.REGRT1, changed as side effect)
+ // arg2 = mem
+ // auxint = offset into duffcopy code to start executing
+ // returns mem
+ // R16, R17 changed as side effect
+ {
+ name: "DUFFCOPY",
+ aux: "Int64",
+ argLength: 3,
+ reg: regInfo{
+ inputs: []regMask{buildReg("R17"), buildReg("R16")},
+ clobbers: buildReg("R16 R17 R30"),
+ },
+ faultOnNilArg0: true,
+ faultOnNilArg1: true,
+ },
+
+ // large move
+ // arg0 = address of dst memory (in R17 aka arm64.REGRT2, changed as side effect)
+ // arg1 = address of src memory (in R16 aka arm64.REGRT1, changed as side effect)
+ // arg2 = address of the last element of src
+ // arg3 = mem
+ // returns mem
+ // MOVD.P 8(R16), Rtmp
+ // MOVD.P Rtmp, 8(R17)
+ // CMP Rarg2, R16
+ // BLE -3(PC)
+ // Note: the-end-of-src may be not a valid pointer. it's a problem if it is spilled.
+ // the-end-of-src - 8 is within the area to copy, ok to spill.
+ {
+ name: "LoweredMove",
+ argLength: 4,
+ reg: regInfo{
+ inputs: []regMask{buildReg("R17"), buildReg("R16"), gp},
+ clobbers: buildReg("R16 R17"),
+ },
+ clobberFlags: true,
+ faultOnNilArg0: true,
+ faultOnNilArg1: true,
+ },
+
+ // Scheduler ensures LoweredGetClosurePtr occurs only in entry block,
+ // and sorts it to the very beginning of the block to prevent other
+ // use of R26 (arm64.REGCTXT, the closure pointer)
+ {name: "LoweredGetClosurePtr", reg: regInfo{outputs: []regMask{buildReg("R26")}}},
+
+ // MOVDconvert converts between pointers and integers.
+ // We have a special op for this so as to not confuse GC
+ // (particularly stack maps). It takes a memory arg so it
+ // gets correctly ordered with respect to GC safepoints.
+ // arg0=ptr/int arg1=mem, output=int/ptr
+ {name: "MOVDconvert", argLength: 2, reg: gp11, asm: "MOVD"},
+
+ // Constant flag values. For any comparison, there are 5 possible
+ // outcomes: the three from the signed total order (<,==,>) and the
+ // three from the unsigned total order. The == cases overlap.
+ // Note: there's a sixth "unordered" outcome for floating-point
+ // comparisons, but we don't use such a beast yet.
+ // These ops are for temporary use by rewrite rules. They
+ // cannot appear in the generated assembly.
+ {name: "FlagEQ"}, // equal
+ {name: "FlagLT_ULT"}, // signed < and unsigned <
+ {name: "FlagLT_UGT"}, // signed < and unsigned >
+ {name: "FlagGT_UGT"}, // signed > and unsigned <
+ {name: "FlagGT_ULT"}, // signed > and unsigned >
+
+ // (InvertFlags (CMP a b)) == (CMP b a)
+ // InvertFlags is a pseudo-op which can't appear in assembly output.
+ {name: "InvertFlags", argLength: 1}, // reverse direction of arg0
+
+ // atomic loads.
+ // load from arg0. arg1=mem. auxint must be zero.
+ // returns <value,memory> so they can be properly ordered with other loads.
+ {name: "LDAR", argLength: 2, reg: gpload, asm: "LDAR", faultOnNilArg0: true},
+ {name: "LDARW", argLength: 2, reg: gpload, asm: "LDARW", faultOnNilArg0: true},
+
+ // atomic stores.
+ // store arg1 to arg0. arg2=mem. returns memory. auxint must be zero.
+ {name: "STLR", argLength: 3, reg: gpstore, asm: "STLR", faultOnNilArg0: true},
+ {name: "STLRW", argLength: 3, reg: gpstore, asm: "STLRW", faultOnNilArg0: true},
+
+ // atomic exchange.
+ // store arg1 to arg0. arg2=mem. returns <old content of *arg0, memory>. auxint must be zero.
+ // LDAXR (Rarg0), Rout
+ // STLXR Rarg1, (Rarg0), Rtmp
+ // CBNZ Rtmp, -2(PC)
+ {name: "LoweredAtomicExchange64", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true},
+ {name: "LoweredAtomicExchange32", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true},
+
+ // atomic add.
+ // *arg0 += arg1. arg2=mem. returns <new content of *arg0, memory>. auxint must be zero.
+ // LDAXR (Rarg0), Rout
+ // ADD Rarg1, Rout
+ // STLXR Rout, (Rarg0), Rtmp
+ // CBNZ Rtmp, -3(PC)
+ {name: "LoweredAtomicAdd64", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true},
+ {name: "LoweredAtomicAdd32", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: 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)
+ // }
+ // LDAXR (Rarg0), Rtmp
+ // CMP Rarg1, Rtmp
+ // BNE 3(PC)
+ // STLXR Rarg2, (Rarg0), Rtmp
+ // CBNZ Rtmp, -4(PC)
+ // CSET EQ, Rout
+ {name: "LoweredAtomicCas64", argLength: 4, reg: gpcas, resultNotInArgs: true, clobberFlags: true, faultOnNilArg0: true},
+ {name: "LoweredAtomicCas32", argLength: 4, reg: gpcas, resultNotInArgs: true, clobberFlags: true, faultOnNilArg0: true},
+
+ // atomic and/or.
+ // *arg0 &= (|=) arg1. arg2=mem. returns memory. auxint must be zero.
+ // LDAXRB (Rarg0), Rtmp
+ // AND/OR Rarg1, Rtmp
+ // STLXRB Rtmp, (Rarg0), Rtmp
+ // CBNZ Rtmp, -3(PC)
+ {name: "LoweredAtomicAnd8", argLength: 3, reg: gpstore, asm: "AND", faultOnNilArg0: true},
+ {name: "LoweredAtomicOr8", argLength: 3, reg: gpstore, asm: "ORR", faultOnNilArg0: true},
+ }
+
+ blocks := []blockData{
+ {name: "EQ"},
+ {name: "NE"},
+ {name: "LT"},
+ {name: "LE"},
+ {name: "GT"},
+ {name: "GE"},
+ {name: "ULT"},
+ {name: "ULE"},
+ {name: "UGT"},
+ {name: "UGE"},
+ {name: "Z"}, // Control == 0 (take a register instead of flags)
+ {name: "NZ"}, // Control != 0
+ {name: "ZW"}, // Control == 0, 32-bit
+ {name: "NZW"}, // Control != 0, 32-bit
+ }
+
+ archs = append(archs, arch{
+ name: "ARM64",
+ pkg: "cmd/internal/obj/arm64",
+ genfile: "../../arm64/ssa.go",
+ ops: ops,
+ blocks: blocks,
+ regnames: regNamesARM64,
+ gpregmask: gp,
+ fpregmask: fp,
+ framepointerreg: -1, // not used
+ linkreg: int8(num["R30"]),
+ })
+}
diff --git a/src/cmd/compile/internal/ssa/gen/ARMOps.go b/src/cmd/compile/internal/ssa/gen/ARMOps.go
index 23e8f63..5bf3c00 100644
--- a/src/cmd/compile/internal/ssa/gen/ARMOps.go
+++ b/src/cmd/compile/internal/ssa/gen/ARMOps.go
@@ -6,32 +6,501 @@
package main
+import "strings"
+
+// Notes:
+// - Integer types live in the low portion of registers. Upper portions are junk.
+// - Boolean types use the low-order byte of a register. 0=false, 1=true.
+// Upper bytes are junk.
+// - *const instructions may use a constant larger than the instuction can encode.
+// In this case the assembler expands to multiple instructions and uses tmp
+// register (R11).
+
+// Suffixes encode the bit width of various instructions.
+// W (word) = 32 bit
+// H (half word) = 16 bit
+// HU = 16 bit unsigned
+// B (byte) = 8 bit
+// BU = 8 bit unsigned
+// F (float) = 32 bit float
+// D (double) = 64 bit float
+
+var regNamesARM = []string{
+ "R0",
+ "R1",
+ "R2",
+ "R3",
+ "R4",
+ "R5",
+ "R6",
+ "R7",
+ "R8",
+ "R9",
+ "g", // aka R10
+ "R11", // tmp
+ "R12",
+ "SP", // aka R13
+ "R14", // link
+ "R15", // pc
+
+ "F0",
+ "F1",
+ "F2",
+ "F3",
+ "F4",
+ "F5",
+ "F6",
+ "F7",
+ "F8",
+ "F9",
+ "F10",
+ "F11",
+ "F12",
+ "F13",
+ "F14",
+ "F15", // tmp
+
+ // pseudo-registers
+ "SB",
+}
+
func init() {
+ // Make map from reg names to reg integers.
+ if len(regNamesARM) > 64 {
+ panic("too many registers")
+ }
+ num := map[string]int{}
+ for i, name := range regNamesARM {
+ num[name] = i
+ }
+ buildReg := func(s string) regMask {
+ m := regMask(0)
+ for _, r := range strings.Split(s, " ") {
+ if n, ok := num[r]; ok {
+ m |= regMask(1) << uint(n)
+ continue
+ }
+ panic("register " + r + " not found")
+ }
+ return m
+ }
+
+ // Common individual register masks
+ var (
+ gp = buildReg("R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14")
+ gpg = gp | buildReg("g")
+ gpsp = gp | buildReg("SP")
+ gpspg = gpg | buildReg("SP")
+ gpspsbg = gpspg | buildReg("SB")
+ fp = buildReg("F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15")
+ callerSave = gp | fp | buildReg("g") // runtime.setg (and anything calling it) may clobber g
+ )
+ // Common regInfo
var (
- gp01 = regInfo{inputs: []regMask{}, outputs: []regMask{31}}
- gp11 = regInfo{inputs: []regMask{31}, outputs: []regMask{31}}
- gp21 = regInfo{inputs: []regMask{31, 31}, outputs: []regMask{31}}
- gp2flags = regInfo{inputs: []regMask{31, 31}, outputs: []regMask{32}}
- gpload = regInfo{inputs: []regMask{31}, outputs: []regMask{31}}
- gpstore = regInfo{inputs: []regMask{31, 31}, outputs: []regMask{}}
- flagsgp = regInfo{inputs: []regMask{32}, outputs: []regMask{31}}
- callerSave = regMask(15)
+ gp01 = regInfo{inputs: nil, outputs: []regMask{gp}}
+ gp11 = regInfo{inputs: []regMask{gpg}, outputs: []regMask{gp}}
+ gp11carry = regInfo{inputs: []regMask{gpg}, outputs: []regMask{gp, 0}}
+ gp11sp = regInfo{inputs: []regMask{gpspg}, outputs: []regMask{gp}}
+ gp1flags = regInfo{inputs: []regMask{gpg}}
+ gp1flags1 = regInfo{inputs: []regMask{gp}, outputs: []regMask{gp}}
+ gp21 = regInfo{inputs: []regMask{gpg, gpg}, outputs: []regMask{gp}}
+ gp21carry = regInfo{inputs: []regMask{gpg, gpg}, outputs: []regMask{gp, 0}}
+ gp2flags = regInfo{inputs: []regMask{gpg, gpg}}
+ gp2flags1 = regInfo{inputs: []regMask{gp, gp}, outputs: []regMask{gp}}
+ gp22 = regInfo{inputs: []regMask{gpg, gpg}, outputs: []regMask{gp, gp}}
+ gp31 = regInfo{inputs: []regMask{gp, gp, gp}, outputs: []regMask{gp}}
+ gp31carry = regInfo{inputs: []regMask{gp, gp, gp}, outputs: []regMask{gp, 0}}
+ gp3flags = regInfo{inputs: []regMask{gp, gp, gp}}
+ gp3flags1 = regInfo{inputs: []regMask{gp, gp, gp}, outputs: []regMask{gp}}
+ gpload = regInfo{inputs: []regMask{gpspsbg}, outputs: []regMask{gp}}
+ gpstore = regInfo{inputs: []regMask{gpspsbg, gpg}}
+ gp2load = regInfo{inputs: []regMask{gpspsbg, gpg}, outputs: []regMask{gp}}
+ gp2store = regInfo{inputs: []regMask{gpspsbg, gpg, gpg}}
+ fp01 = regInfo{inputs: nil, outputs: []regMask{fp}}
+ fp11 = regInfo{inputs: []regMask{fp}, outputs: []regMask{fp}}
+ fp1flags = regInfo{inputs: []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}}
+ fp2flags = regInfo{inputs: []regMask{fp, fp}}
+ fpload = regInfo{inputs: []regMask{gpspsbg}, outputs: []regMask{fp}}
+ fpstore = regInfo{inputs: []regMask{gpspsbg, fp}}
+ readflags = regInfo{inputs: nil, outputs: []regMask{gp}}
)
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)
+ // binary ops
+ {name: "ADD", argLength: 2, reg: gp21, asm: "ADD", commutative: true}, // arg0 + arg1
+ {name: "ADDconst", argLength: 1, reg: gp11sp, asm: "ADD", aux: "Int32"}, // arg0 + auxInt
+ {name: "SUB", argLength: 2, reg: gp21, asm: "SUB"}, // arg0 - arg1
+ {name: "SUBconst", argLength: 1, reg: gp11, asm: "SUB", aux: "Int32"}, // arg0 - auxInt
+ {name: "RSB", argLength: 2, reg: gp21, asm: "RSB"}, // arg1 - arg0
+ {name: "RSBconst", argLength: 1, reg: gp11, asm: "RSB", aux: "Int32"}, // auxInt - arg0
+ {name: "MUL", argLength: 2, reg: gp21, asm: "MUL", commutative: true}, // arg0 * arg1
+ {name: "HMUL", argLength: 2, reg: gp21, asm: "MULL", commutative: true}, // (arg0 * arg1) >> 32, signed
+ {name: "HMULU", argLength: 2, reg: gp21, asm: "MULLU", commutative: true}, // (arg0 * arg1) >> 32, unsigned
+
+ // udiv runtime call for soft division
+ // output0 = arg0/arg1, output1 = arg0%arg1
+ // see ../../../../../runtime/vlop_arm.s
+ {
+ name: "UDIVrtcall",
+ argLength: 2,
+ reg: regInfo{
+ inputs: []regMask{buildReg("R1"), buildReg("R0")},
+ outputs: []regMask{buildReg("R0"), buildReg("R1")},
+ clobbers: buildReg("R2 R3 R14"), // also clobbers R12 on NaCl (modified in ../config.go)
+ },
+ clobberFlags: true,
+ typ: "(UInt32,UInt32)",
+ },
+
+ {name: "ADDS", argLength: 2, reg: gp21carry, asm: "ADD", commutative: true}, // arg0 + arg1, set carry flag
+ {name: "ADDSconst", argLength: 1, reg: gp11carry, asm: "ADD", aux: "Int32"}, // arg0 + auxInt, set carry flag
+ {name: "ADC", argLength: 3, reg: gp2flags1, asm: "ADC", commutative: true}, // arg0 + arg1 + carry, arg2=flags
+ {name: "ADCconst", argLength: 2, reg: gp1flags1, asm: "ADC", aux: "Int32"}, // arg0 + auxInt + carry, arg1=flags
+ {name: "SUBS", argLength: 2, reg: gp21carry, asm: "SUB"}, // arg0 - arg1, set carry flag
+ {name: "SUBSconst", argLength: 1, reg: gp11carry, asm: "SUB", aux: "Int32"}, // arg0 - auxInt, set carry flag
+ {name: "RSBSconst", argLength: 1, reg: gp11carry, asm: "RSB", aux: "Int32"}, // auxInt - arg0, set carry flag
+ {name: "SBC", argLength: 3, reg: gp2flags1, asm: "SBC"}, // arg0 - arg1 - carry, arg2=flags
+ {name: "SBCconst", argLength: 2, reg: gp1flags1, asm: "SBC", aux: "Int32"}, // arg0 - auxInt - carry, arg1=flags
+ {name: "RSCconst", argLength: 2, reg: gp1flags1, asm: "RSC", aux: "Int32"}, // auxInt - arg0 - carry, arg1=flags
+
+ {name: "MULLU", argLength: 2, reg: gp22, asm: "MULLU", commutative: true}, // arg0 * arg1, high 32 bits in out0, low 32 bits in out1
+ {name: "MULA", argLength: 3, reg: gp31, asm: "MULA"}, // arg0 * arg1 + arg2
+
+ {name: "ADDF", argLength: 2, reg: fp21, asm: "ADDF", commutative: true}, // arg0 + arg1
+ {name: "ADDD", argLength: 2, reg: fp21, asm: "ADDD", commutative: true}, // arg0 + arg1
+ {name: "SUBF", argLength: 2, reg: fp21, asm: "SUBF"}, // arg0 - arg1
+ {name: "SUBD", argLength: 2, reg: fp21, asm: "SUBD"}, // arg0 - arg1
+ {name: "MULF", argLength: 2, reg: fp21, asm: "MULF", commutative: true}, // arg0 * arg1
+ {name: "MULD", argLength: 2, reg: fp21, asm: "MULD", commutative: true}, // arg0 * arg1
+ {name: "DIVF", argLength: 2, reg: fp21, asm: "DIVF"}, // arg0 / arg1
+ {name: "DIVD", argLength: 2, reg: fp21, asm: "DIVD"}, // arg0 / arg1
+
+ {name: "AND", argLength: 2, reg: gp21, asm: "AND", commutative: true}, // arg0 & arg1
+ {name: "ANDconst", argLength: 1, reg: gp11, asm: "AND", aux: "Int32"}, // arg0 & auxInt
+ {name: "OR", argLength: 2, reg: gp21, asm: "ORR", commutative: true}, // arg0 | arg1
+ {name: "ORconst", argLength: 1, reg: gp11, asm: "ORR", aux: "Int32"}, // arg0 | auxInt
+ {name: "XOR", argLength: 2, reg: gp21, asm: "EOR", commutative: true}, // arg0 ^ arg1
+ {name: "XORconst", argLength: 1, reg: gp11, asm: "EOR", aux: "Int32"}, // arg0 ^ auxInt
+ {name: "BIC", argLength: 2, reg: gp21, asm: "BIC"}, // arg0 &^ arg1
+ {name: "BICconst", argLength: 1, reg: gp11, asm: "BIC", aux: "Int32"}, // arg0 &^ auxInt
+
+ // unary ops
+ {name: "MVN", argLength: 1, reg: gp11, asm: "MVN"}, // ^arg0
+
+ {name: "NEGF", argLength: 1, reg: fp11, asm: "NEGF"}, // -arg0, float32
+ {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
+
+ // shifts
+ {name: "SLL", argLength: 2, reg: gp21, asm: "SLL"}, // arg0 << arg1, shift amount is mod 256
+ {name: "SLLconst", argLength: 1, reg: gp11, asm: "SLL", aux: "Int32"}, // arg0 << auxInt
+ {name: "SRL", argLength: 2, reg: gp21, asm: "SRL"}, // arg0 >> arg1, unsigned, shift amount is mod 256
+ {name: "SRLconst", argLength: 1, reg: gp11, asm: "SRL", aux: "Int32"}, // arg0 >> auxInt, unsigned
+ {name: "SRA", argLength: 2, reg: gp21, asm: "SRA"}, // arg0 >> arg1, signed, shift amount is mod 256
+ {name: "SRAconst", argLength: 1, reg: gp11, asm: "SRA", aux: "Int32"}, // arg0 >> auxInt, signed
+ {name: "SRRconst", argLength: 1, reg: gp11, aux: "Int32"}, // arg0 right rotate by auxInt bits
+
+ {name: "ADDshiftLL", argLength: 2, reg: gp21, asm: "ADD", aux: "Int32"}, // arg0 + arg1<<auxInt
+ {name: "ADDshiftRL", argLength: 2, reg: gp21, asm: "ADD", aux: "Int32"}, // arg0 + arg1>>auxInt, unsigned shift
+ {name: "ADDshiftRA", argLength: 2, reg: gp21, asm: "ADD", aux: "Int32"}, // arg0 + arg1>>auxInt, signed shift
+ {name: "SUBshiftLL", argLength: 2, reg: gp21, asm: "SUB", aux: "Int32"}, // arg0 - arg1<<auxInt
+ {name: "SUBshiftRL", argLength: 2, reg: gp21, asm: "SUB", aux: "Int32"}, // arg0 - arg1>>auxInt, unsigned shift
+ {name: "SUBshiftRA", argLength: 2, reg: gp21, asm: "SUB", aux: "Int32"}, // arg0 - arg1>>auxInt, signed shift
+ {name: "RSBshiftLL", argLength: 2, reg: gp21, asm: "RSB", aux: "Int32"}, // arg1<<auxInt - arg0
+ {name: "RSBshiftRL", argLength: 2, reg: gp21, asm: "RSB", aux: "Int32"}, // arg1>>auxInt - arg0, unsigned shift
+ {name: "RSBshiftRA", argLength: 2, reg: gp21, asm: "RSB", aux: "Int32"}, // arg1>>auxInt - arg0, signed shift
+ {name: "ANDshiftLL", argLength: 2, reg: gp21, asm: "AND", aux: "Int32"}, // arg0 & (arg1<<auxInt)
+ {name: "ANDshiftRL", argLength: 2, reg: gp21, asm: "AND", aux: "Int32"}, // arg0 & (arg1>>auxInt), unsigned shift
+ {name: "ANDshiftRA", argLength: 2, reg: gp21, asm: "AND", aux: "Int32"}, // arg0 & (arg1>>auxInt), signed shift
+ {name: "ORshiftLL", argLength: 2, reg: gp21, asm: "ORR", aux: "Int32"}, // arg0 | arg1<<auxInt
+ {name: "ORshiftRL", argLength: 2, reg: gp21, asm: "ORR", aux: "Int32"}, // arg0 | arg1>>auxInt, unsigned shift
+ {name: "ORshiftRA", argLength: 2, reg: gp21, asm: "ORR", aux: "Int32"}, // arg0 | arg1>>auxInt, signed shift
+ {name: "XORshiftLL", argLength: 2, reg: gp21, asm: "EOR", aux: "Int32"}, // arg0 ^ arg1<<auxInt
+ {name: "XORshiftRL", argLength: 2, reg: gp21, asm: "EOR", aux: "Int32"}, // arg0 ^ arg1>>auxInt, unsigned shift
+ {name: "XORshiftRA", argLength: 2, reg: gp21, asm: "EOR", aux: "Int32"}, // arg0 ^ arg1>>auxInt, signed shift
+ {name: "XORshiftRR", argLength: 2, reg: gp21, asm: "EOR", aux: "Int32"}, // arg0 ^ (arg1 right rotate by auxInt)
+ {name: "BICshiftLL", argLength: 2, reg: gp21, asm: "BIC", aux: "Int32"}, // arg0 &^ (arg1<<auxInt)
+ {name: "BICshiftRL", argLength: 2, reg: gp21, asm: "BIC", aux: "Int32"}, // arg0 &^ (arg1>>auxInt), unsigned shift
+ {name: "BICshiftRA", argLength: 2, reg: gp21, asm: "BIC", aux: "Int32"}, // arg0 &^ (arg1>>auxInt), signed shift
+ {name: "MVNshiftLL", argLength: 1, reg: gp11, asm: "MVN", aux: "Int32"}, // ^(arg0<<auxInt)
+ {name: "MVNshiftRL", argLength: 1, reg: gp11, asm: "MVN", aux: "Int32"}, // ^(arg0>>auxInt), unsigned shift
+ {name: "MVNshiftRA", argLength: 1, reg: gp11, asm: "MVN", aux: "Int32"}, // ^(arg0>>auxInt), signed shift
+
+ {name: "ADCshiftLL", argLength: 3, reg: gp2flags1, asm: "ADC", aux: "Int32"}, // arg0 + arg1<<auxInt + carry, arg2=flags
+ {name: "ADCshiftRL", argLength: 3, reg: gp2flags1, asm: "ADC", aux: "Int32"}, // arg0 + arg1>>auxInt + carry, unsigned shift, arg2=flags
+ {name: "ADCshiftRA", argLength: 3, reg: gp2flags1, asm: "ADC", aux: "Int32"}, // arg0 + arg1>>auxInt + carry, signed shift, arg2=flags
+ {name: "SBCshiftLL", argLength: 3, reg: gp2flags1, asm: "SBC", aux: "Int32"}, // arg0 - arg1<<auxInt - carry, arg2=flags
+ {name: "SBCshiftRL", argLength: 3, reg: gp2flags1, asm: "SBC", aux: "Int32"}, // arg0 - arg1>>auxInt - carry, unsigned shift, arg2=flags
+ {name: "SBCshiftRA", argLength: 3, reg: gp2flags1, asm: "SBC", aux: "Int32"}, // arg0 - arg1>>auxInt - carry, signed shift, arg2=flags
+ {name: "RSCshiftLL", argLength: 3, reg: gp2flags1, asm: "RSC", aux: "Int32"}, // arg1<<auxInt - arg0 - carry, arg2=flags
+ {name: "RSCshiftRL", argLength: 3, reg: gp2flags1, asm: "RSC", aux: "Int32"}, // arg1>>auxInt - arg0 - carry, unsigned shift, arg2=flags
+ {name: "RSCshiftRA", argLength: 3, reg: gp2flags1, asm: "RSC", aux: "Int32"}, // arg1>>auxInt - arg0 - carry, signed shift, arg2=flags
+
+ {name: "ADDSshiftLL", argLength: 2, reg: gp21carry, asm: "ADD", aux: "Int32"}, // arg0 + arg1<<auxInt, set carry flag
+ {name: "ADDSshiftRL", argLength: 2, reg: gp21carry, asm: "ADD", aux: "Int32"}, // arg0 + arg1>>auxInt, unsigned shift, set carry flag
+ {name: "ADDSshiftRA", argLength: 2, reg: gp21carry, asm: "ADD", aux: "Int32"}, // arg0 + arg1>>auxInt, signed shift, set carry flag
+ {name: "SUBSshiftLL", argLength: 2, reg: gp21carry, asm: "SUB", aux: "Int32"}, // arg0 - arg1<<auxInt, set carry flag
+ {name: "SUBSshiftRL", argLength: 2, reg: gp21carry, asm: "SUB", aux: "Int32"}, // arg0 - arg1>>auxInt, unsigned shift, set carry flag
+ {name: "SUBSshiftRA", argLength: 2, reg: gp21carry, asm: "SUB", aux: "Int32"}, // arg0 - arg1>>auxInt, signed shift, set carry flag
+ {name: "RSBSshiftLL", argLength: 2, reg: gp21carry, asm: "RSB", aux: "Int32"}, // arg1<<auxInt - arg0, set carry flag
+ {name: "RSBSshiftRL", argLength: 2, reg: gp21carry, asm: "RSB", aux: "Int32"}, // arg1>>auxInt - arg0, unsigned shift, set carry flag
+ {name: "RSBSshiftRA", argLength: 2, reg: gp21carry, asm: "RSB", aux: "Int32"}, // arg1>>auxInt - arg0, signed shift, set carry flag
- {name: "MOVWconst", argLength: 0, reg: gp01, aux: "Int32", asm: "MOVW", rematerializeable: true}, // 32 low bits of auxint
+ {name: "ADDshiftLLreg", argLength: 3, reg: gp31, asm: "ADD"}, // arg0 + arg1<<arg2
+ {name: "ADDshiftRLreg", argLength: 3, reg: gp31, asm: "ADD"}, // arg0 + arg1>>arg2, unsigned shift
+ {name: "ADDshiftRAreg", argLength: 3, reg: gp31, asm: "ADD"}, // arg0 + arg1>>arg2, signed shift
+ {name: "SUBshiftLLreg", argLength: 3, reg: gp31, asm: "SUB"}, // arg0 - arg1<<arg2
+ {name: "SUBshiftRLreg", argLength: 3, reg: gp31, asm: "SUB"}, // arg0 - arg1>>arg2, unsigned shift
+ {name: "SUBshiftRAreg", argLength: 3, reg: gp31, asm: "SUB"}, // arg0 - arg1>>arg2, signed shift
+ {name: "RSBshiftLLreg", argLength: 3, reg: gp31, asm: "RSB"}, // arg1<<arg2 - arg0
+ {name: "RSBshiftRLreg", argLength: 3, reg: gp31, asm: "RSB"}, // arg1>>arg2 - arg0, unsigned shift
+ {name: "RSBshiftRAreg", argLength: 3, reg: gp31, asm: "RSB"}, // arg1>>arg2 - arg0, signed shift
+ {name: "ANDshiftLLreg", argLength: 3, reg: gp31, asm: "AND"}, // arg0 & (arg1<<arg2)
+ {name: "ANDshiftRLreg", argLength: 3, reg: gp31, asm: "AND"}, // arg0 & (arg1>>arg2), unsigned shift
+ {name: "ANDshiftRAreg", argLength: 3, reg: gp31, asm: "AND"}, // arg0 & (arg1>>arg2), signed shift
+ {name: "ORshiftLLreg", argLength: 3, reg: gp31, asm: "ORR"}, // arg0 | arg1<<arg2
+ {name: "ORshiftRLreg", argLength: 3, reg: gp31, asm: "ORR"}, // arg0 | arg1>>arg2, unsigned shift
+ {name: "ORshiftRAreg", argLength: 3, reg: gp31, asm: "ORR"}, // arg0 | arg1>>arg2, signed shift
+ {name: "XORshiftLLreg", argLength: 3, reg: gp31, asm: "EOR"}, // arg0 ^ arg1<<arg2
+ {name: "XORshiftRLreg", argLength: 3, reg: gp31, asm: "EOR"}, // arg0 ^ arg1>>arg2, unsigned shift
+ {name: "XORshiftRAreg", argLength: 3, reg: gp31, asm: "EOR"}, // arg0 ^ arg1>>arg2, signed shift
+ {name: "BICshiftLLreg", argLength: 3, reg: gp31, asm: "BIC"}, // arg0 &^ (arg1<<arg2)
+ {name: "BICshiftRLreg", argLength: 3, reg: gp31, asm: "BIC"}, // arg0 &^ (arg1>>arg2), unsigned shift
+ {name: "BICshiftRAreg", argLength: 3, reg: gp31, asm: "BIC"}, // arg0 &^ (arg1>>arg2), signed shift
+ {name: "MVNshiftLLreg", argLength: 2, reg: gp21, asm: "MVN"}, // ^(arg0<<arg1)
+ {name: "MVNshiftRLreg", argLength: 2, reg: gp21, asm: "MVN"}, // ^(arg0>>arg1), unsigned shift
+ {name: "MVNshiftRAreg", argLength: 2, reg: gp21, asm: "MVN"}, // ^(arg0>>arg1), signed shift
- {name: "CMP", argLength: 2, reg: gp2flags, asm: "CMP", typ: "Flags"}, // arg0 compare to arg1
+ {name: "ADCshiftLLreg", argLength: 4, reg: gp3flags1, asm: "ADC"}, // arg0 + arg1<<arg2 + carry, arg3=flags
+ {name: "ADCshiftRLreg", argLength: 4, reg: gp3flags1, asm: "ADC"}, // arg0 + arg1>>arg2 + carry, unsigned shift, arg3=flags
+ {name: "ADCshiftRAreg", argLength: 4, reg: gp3flags1, asm: "ADC"}, // arg0 + arg1>>arg2 + carry, signed shift, arg3=flags
+ {name: "SBCshiftLLreg", argLength: 4, reg: gp3flags1, asm: "SBC"}, // arg0 - arg1<<arg2 - carry, arg3=flags
+ {name: "SBCshiftRLreg", argLength: 4, reg: gp3flags1, asm: "SBC"}, // arg0 - arg1>>arg2 - carry, unsigned shift, arg3=flags
+ {name: "SBCshiftRAreg", argLength: 4, reg: gp3flags1, asm: "SBC"}, // arg0 - arg1>>arg2 - carry, signed shift, arg3=flags
+ {name: "RSCshiftLLreg", argLength: 4, reg: gp3flags1, asm: "RSC"}, // arg1<<arg2 - arg0 - carry, arg3=flags
+ {name: "RSCshiftRLreg", argLength: 4, reg: gp3flags1, asm: "RSC"}, // arg1>>arg2 - arg0 - carry, unsigned shift, arg3=flags
+ {name: "RSCshiftRAreg", argLength: 4, reg: gp3flags1, asm: "RSC"}, // arg1>>arg2 - arg0 - carry, signed shift, arg3=flags
- {name: "MOVWload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVW"}, // load from arg0 + auxInt + aux. arg1=mem.
- {name: "MOVWstore", argLength: 3, reg: gpstore, aux: "SymOff", asm: "MOVW"}, // store 4 bytes of arg1 to arg0 + auxInt + aux. arg2=mem.
+ {name: "ADDSshiftLLreg", argLength: 3, reg: gp31carry, asm: "ADD"}, // arg0 + arg1<<arg2, set carry flag
+ {name: "ADDSshiftRLreg", argLength: 3, reg: gp31carry, asm: "ADD"}, // arg0 + arg1>>arg2, unsigned shift, set carry flag
+ {name: "ADDSshiftRAreg", argLength: 3, reg: gp31carry, asm: "ADD"}, // arg0 + arg1>>arg2, signed shift, set carry flag
+ {name: "SUBSshiftLLreg", argLength: 3, reg: gp31carry, asm: "SUB"}, // arg0 - arg1<<arg2, set carry flag
+ {name: "SUBSshiftRLreg", argLength: 3, reg: gp31carry, asm: "SUB"}, // arg0 - arg1>>arg2, unsigned shift, set carry flag
+ {name: "SUBSshiftRAreg", argLength: 3, reg: gp31carry, asm: "SUB"}, // arg0 - arg1>>arg2, signed shift, set carry flag
+ {name: "RSBSshiftLLreg", argLength: 3, reg: gp31carry, asm: "RSB"}, // arg1<<arg2 - arg0, set carry flag
+ {name: "RSBSshiftRLreg", argLength: 3, reg: gp31carry, asm: "RSB"}, // arg1>>arg2 - arg0, unsigned shift, set carry flag
+ {name: "RSBSshiftRAreg", argLength: 3, reg: gp31carry, asm: "RSB"}, // arg1>>arg2 - arg0, signed shift, set carry flag
- {name: "CALLstatic", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "SymOff"}, // call static function aux.(*gc.Sym). arg0=mem, auxint=argsize, returns mem
+ // comparisons
+ {name: "CMP", argLength: 2, reg: gp2flags, asm: "CMP", typ: "Flags"}, // arg0 compare to arg1
+ {name: "CMPconst", argLength: 1, reg: gp1flags, asm: "CMP", aux: "Int32", typ: "Flags"}, // arg0 compare to auxInt
+ {name: "CMN", argLength: 2, reg: gp2flags, asm: "CMN", typ: "Flags"}, // arg0 compare to -arg1
+ {name: "CMNconst", argLength: 1, reg: gp1flags, asm: "CMN", aux: "Int32", typ: "Flags"}, // arg0 compare to -auxInt
+ {name: "TST", argLength: 2, reg: gp2flags, asm: "TST", typ: "Flags", commutative: true}, // arg0 & arg1 compare to 0
+ {name: "TSTconst", argLength: 1, reg: gp1flags, asm: "TST", aux: "Int32", typ: "Flags"}, // arg0 & auxInt compare to 0
+ {name: "TEQ", argLength: 2, reg: gp2flags, asm: "TEQ", typ: "Flags", commutative: true}, // arg0 ^ arg1 compare to 0
+ {name: "TEQconst", argLength: 1, reg: gp1flags, asm: "TEQ", aux: "Int32", typ: "Flags"}, // arg0 ^ auxInt compare to 0
+ {name: "CMPF", argLength: 2, reg: fp2flags, asm: "CMPF", typ: "Flags"}, // arg0 compare to arg1, float32
+ {name: "CMPD", argLength: 2, reg: fp2flags, asm: "CMPD", typ: "Flags"}, // arg0 compare to arg1, float64
+
+ {name: "CMPshiftLL", argLength: 2, reg: gp2flags, asm: "CMP", aux: "Int32", typ: "Flags"}, // arg0 compare to arg1<<auxInt
+ {name: "CMPshiftRL", argLength: 2, reg: gp2flags, asm: "CMP", aux: "Int32", typ: "Flags"}, // arg0 compare to arg1>>auxInt, unsigned shift
+ {name: "CMPshiftRA", argLength: 2, reg: gp2flags, asm: "CMP", aux: "Int32", typ: "Flags"}, // arg0 compare to arg1>>auxInt, signed shift
+
+ {name: "CMPshiftLLreg", argLength: 3, reg: gp3flags, asm: "CMP", typ: "Flags"}, // arg0 compare to arg1<<arg2
+ {name: "CMPshiftRLreg", argLength: 3, reg: gp3flags, asm: "CMP", typ: "Flags"}, // arg0 compare to arg1>>arg2, unsigned shift
+ {name: "CMPshiftRAreg", argLength: 3, reg: gp3flags, asm: "CMP", typ: "Flags"}, // arg0 compare to arg1>>arg2, signed shift
+
+ {name: "CMPF0", argLength: 1, reg: fp1flags, asm: "CMPF", typ: "Flags"}, // arg0 compare to 0, float32
+ {name: "CMPD0", argLength: 1, reg: fp1flags, asm: "CMPD", typ: "Flags"}, // arg0 compare to 0, float64
+
+ // moves
+ {name: "MOVWconst", argLength: 0, reg: gp01, aux: "Int32", asm: "MOVW", typ: "UInt32", rematerializeable: true}, // 32 low bits of auxint
+ {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: "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: "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
+ {name: "MOVWloadshiftRL", argLength: 3, reg: gp2load, asm: "MOVW", aux: "Int32"}, // load from arg0 + arg1>>auxInt, unsigned shift. arg2=mem
+ {name: "MOVWloadshiftRA", argLength: 3, reg: gp2load, asm: "MOVW", aux: "Int32"}, // load from arg0 + arg1>>auxInt, signed shift. arg2=mem
+
+ {name: "MOVWstoreidx", argLength: 4, reg: gp2store, asm: "MOVW"}, // store arg2 to arg0 + arg1. arg3=mem
+ {name: "MOVWstoreshiftLL", argLength: 4, reg: gp2store, asm: "MOVW", aux: "Int32"}, // store arg2 to arg0 + arg1<<auxInt. arg3=mem
+ {name: "MOVWstoreshiftRL", argLength: 4, reg: gp2store, asm: "MOVW", aux: "Int32"}, // store arg2 to arg0 + arg1>>auxInt, unsigned shift. arg3=mem
+ {name: "MOVWstoreshiftRA", argLength: 4, reg: gp2store, asm: "MOVW", aux: "Int32"}, // store arg2 to arg0 + arg1>>auxInt, signed shift. arg3=mem
+
+ {name: "MOVBreg", argLength: 1, reg: gp11, asm: "MOVBS"}, // move from arg0, sign-extended from byte
+ {name: "MOVBUreg", argLength: 1, reg: gp11, asm: "MOVBU"}, // move from arg0, unsign-extended from byte
+ {name: "MOVHreg", argLength: 1, reg: gp11, asm: "MOVHS"}, // move from arg0, sign-extended from half
+ {name: "MOVHUreg", argLength: 1, reg: gp11, asm: "MOVHU"}, // move from arg0, unsign-extended from half
+ {name: "MOVWreg", argLength: 1, reg: gp11, asm: "MOVW"}, // move from arg0
+
+ {name: "MOVWnop", argLength: 1, reg: regInfo{inputs: []regMask{gp}, outputs: []regMask{gp}}, resultInArg0: true}, // nop, return arg0 in same register
+
+ {name: "MOVWF", argLength: 1, reg: gpfp, asm: "MOVWF"}, // int32 -> float32
+ {name: "MOVWD", argLength: 1, reg: gpfp, asm: "MOVWD"}, // int32 -> float64
+ {name: "MOVWUF", argLength: 1, reg: gpfp, asm: "MOVWF"}, // uint32 -> float32, set U bit in the instruction
+ {name: "MOVWUD", argLength: 1, reg: gpfp, asm: "MOVWD"}, // uint32 -> float64, set U bit in the instruction
+ {name: "MOVFW", argLength: 1, reg: fpgp, asm: "MOVFW"}, // float32 -> int32
+ {name: "MOVDW", argLength: 1, reg: fpgp, asm: "MOVDW"}, // float64 -> int32
+ {name: "MOVFWU", argLength: 1, reg: fpgp, asm: "MOVFW"}, // float32 -> uint32, set U bit in the instruction
+ {name: "MOVDWU", argLength: 1, reg: fpgp, asm: "MOVDW"}, // float64 -> uint32, set U bit in the instruction
+ {name: "MOVFD", argLength: 1, reg: fp11, asm: "MOVFD"}, // float32 -> float64
+ {name: "MOVDF", argLength: 1, reg: fp11, asm: "MOVDF"}, // float64 -> float32
+
+ // conditional instructions, for lowering shifts
+ {name: "CMOVWHSconst", argLength: 2, reg: gp1flags1, asm: "MOVW", aux: "Int32", resultInArg0: true}, // replace arg0 w/ const if flags indicates HS, arg1=flags
+ {name: "CMOVWLSconst", argLength: 2, reg: gp1flags1, asm: "MOVW", aux: "Int32", resultInArg0: true}, // replace arg0 w/ const if flags indicates LS, arg1=flags
+ {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: "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
- {name: "LessThan", argLength: 1, reg: flagsgp}, // bool, 1 flags encode x<y 0 otherwise.
+ {name: "LoweredNilCheck", argLength: 2, reg: regInfo{inputs: []regMask{gpg}}, nilCheck: true, faultOnNilArg0: true}, // panic if arg0 is nil. arg1=mem.
+
+ {name: "Equal", argLength: 1, reg: readflags}, // bool, true flags encode x==y false otherwise.
+ {name: "NotEqual", argLength: 1, reg: readflags}, // bool, true flags encode x!=y false otherwise.
+ {name: "LessThan", argLength: 1, reg: readflags}, // bool, true flags encode signed x<y false otherwise.
+ {name: "LessEqual", argLength: 1, reg: readflags}, // bool, true flags encode signed x<=y false otherwise.
+ {name: "GreaterThan", argLength: 1, reg: readflags}, // bool, true flags encode signed x>y false otherwise.
+ {name: "GreaterEqual", argLength: 1, reg: readflags}, // bool, true flags encode signed x>=y false otherwise.
+ {name: "LessThanU", argLength: 1, reg: readflags}, // bool, true flags encode unsigned x<y false otherwise.
+ {name: "LessEqualU", argLength: 1, reg: readflags}, // bool, true flags encode unsigned x<=y false otherwise.
+ {name: "GreaterThanU", argLength: 1, reg: readflags}, // bool, true flags encode unsigned x>y false otherwise.
+ {name: "GreaterEqualU", argLength: 1, reg: readflags}, // bool, true flags encode unsigned x>=y false otherwise.
+
+ // duffzero (must be 4-byte aligned)
+ // arg0 = address of memory to zero (in R1, changed as side effect)
+ // arg1 = value to store (always zero)
+ // arg2 = mem
+ // auxint = offset into duffzero code to start executing
+ // returns mem
+ {
+ name: "DUFFZERO",
+ aux: "Int64",
+ argLength: 3,
+ reg: regInfo{
+ inputs: []regMask{buildReg("R1"), buildReg("R0")},
+ clobbers: buildReg("R1 R14"),
+ },
+ faultOnNilArg0: true,
+ },
+
+ // duffcopy (must be 4-byte aligned)
+ // arg0 = address of dst memory (in R2, changed as side effect)
+ // arg1 = address of src memory (in R1, changed as side effect)
+ // arg2 = mem
+ // auxint = offset into duffcopy code to start executing
+ // returns mem
+ {
+ name: "DUFFCOPY",
+ aux: "Int64",
+ argLength: 3,
+ reg: regInfo{
+ inputs: []regMask{buildReg("R2"), buildReg("R1")},
+ clobbers: buildReg("R0 R1 R2 R14"),
+ },
+ faultOnNilArg0: true,
+ faultOnNilArg1: true,
+ },
+
+ // large or unaligned zeroing
+ // arg0 = address of memory to zero (in R1, changed as side effect)
+ // arg1 = address of the last element to zero
+ // arg2 = value to store (always zero)
+ // arg3 = mem
+ // returns mem
+ // MOVW.P Rarg2, 4(R1)
+ // CMP R1, Rarg1
+ // BLE -2(PC)
+ {
+ name: "LoweredZero",
+ aux: "Int64",
+ argLength: 4,
+ reg: regInfo{
+ inputs: []regMask{buildReg("R1"), gp, gp},
+ clobbers: buildReg("R1"),
+ },
+ clobberFlags: true,
+ faultOnNilArg0: true,
+ },
+
+ // large or unaligned move
+ // arg0 = address of dst memory (in R2, changed as side effect)
+ // arg1 = address of src memory (in R1, changed as side effect)
+ // arg2 = address of the last element of src
+ // arg3 = mem
+ // returns mem
+ // MOVW.P 4(R1), Rtmp
+ // MOVW.P Rtmp, 4(R2)
+ // CMP R1, Rarg2
+ // BLE -3(PC)
+ {
+ name: "LoweredMove",
+ aux: "Int64",
+ argLength: 4,
+ reg: regInfo{
+ inputs: []regMask{buildReg("R2"), buildReg("R1"), gp},
+ clobbers: buildReg("R1 R2"),
+ },
+ clobberFlags: true,
+ faultOnNilArg0: true,
+ faultOnNilArg1: true,
+ },
+
+ // Scheduler ensures LoweredGetClosurePtr occurs only in entry block,
+ // and sorts it to the very beginning of the block to prevent other
+ // use of R7 (arm.REGCTXT, the closure pointer)
+ {name: "LoweredGetClosurePtr", reg: regInfo{outputs: []regMask{buildReg("R7")}}},
+
+ // MOVWconvert converts between pointers and integers.
+ // We have a special op for this so as to not confuse GC
+ // (particularly stack maps). It takes a memory arg so it
+ // gets correctly ordered with respect to GC safepoints.
+ // arg0=ptr/int arg1=mem, output=int/ptr
+ {name: "MOVWconvert", argLength: 2, reg: gp11, asm: "MOVW"},
+
+ // Constant flag values. For any comparison, there are 5 possible
+ // outcomes: the three from the signed total order (<,==,>) and the
+ // three from the unsigned total order. The == cases overlap.
+ // Note: there's a sixth "unordered" outcome for floating-point
+ // comparisons, but we don't use such a beast yet.
+ // These ops are for temporary use by rewrite rules. They
+ // cannot appear in the generated assembly.
+ {name: "FlagEQ"}, // equal
+ {name: "FlagLT_ULT"}, // signed < and unsigned <
+ {name: "FlagLT_UGT"}, // signed < and unsigned >
+ {name: "FlagGT_UGT"}, // signed > and unsigned <
+ {name: "FlagGT_ULT"}, // signed > and unsigned >
+
+ // (InvertFlags (CMP a b)) == (CMP b a)
+ // InvertFlags is a pseudo-op which can't appear in assembly output.
+ {name: "InvertFlags", argLength: 1}, // reverse direction of arg0
}
blocks := []blockData{
@@ -47,22 +516,16 @@ func init() {
{name: "UGE"},
}
- regNames := []string{
- "R0",
- "R1",
- "R2",
- "R3",
- "SP",
- "FLAGS",
- "SB",
- }
-
archs = append(archs, arch{
- name: "ARM",
- pkg: "cmd/internal/obj/arm",
- genfile: "../../arm/ssa.go",
- ops: ops,
- blocks: blocks,
- regnames: regNames,
+ name: "ARM",
+ pkg: "cmd/internal/obj/arm",
+ genfile: "../../arm/ssa.go",
+ ops: ops,
+ blocks: blocks,
+ regnames: regNamesARM,
+ gpregmask: gp,
+ fpregmask: fp,
+ framepointerreg: -1, // not used
+ linkreg: int8(num["R14"]),
})
}
diff --git a/src/cmd/compile/internal/ssa/gen/MIPS.rules b/src/cmd/compile/internal/ssa/gen/MIPS.rules
new file mode 100644
index 0000000..008f1b1
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/gen/MIPS.rules
@@ -0,0 +1,739 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+(AddPtr x y) -> (ADD x y)
+(Add32 x y) -> (ADD x y)
+(Add16 x y) -> (ADD x y)
+(Add8 x y) -> (ADD x y)
+(Add32F x y) -> (ADDF x y)
+(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))
+(Add32withcarry <t> x y c) -> (ADD c (ADD <t> x y))
+
+(SubPtr x y) -> (SUB x y)
+(Sub32 x y) -> (SUB x y)
+(Sub16 x y) -> (SUB x y)
+(Sub8 x y) -> (SUB x y)
+(Sub32F x y) -> (SUBF x y)
+(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)
+(Sub32withcarry <t> x y c) -> (SUB (SUB <t> x y) c)
+
+(Mul32 x y) -> (MUL x y)
+(Mul16 x y) -> (MUL x y)
+(Mul8 x y) -> (MUL x y)
+(Mul32F x y) -> (MULF x y)
+(Mul64F x y) -> (MULD x y)
+
+(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)
+
+(Div32 x y) -> (Select1 (DIV x y))
+(Div32u x y) -> (Select1 (DIVU x y))
+(Div16 x y) -> (Select1 (DIV (SignExt16to32 x) (SignExt16to32 y)))
+(Div16u x y) -> (Select1 (DIVU (ZeroExt16to32 x) (ZeroExt16to32 y)))
+(Div8 x y) -> (Select1 (DIV (SignExt8to32 x) (SignExt8to32 y)))
+(Div8u x y) -> (Select1 (DIVU (ZeroExt8to32 x) (ZeroExt8to32 y)))
+(Div32F x y) -> (DIVF x y)
+(Div64F x y) -> (DIVD x y)
+
+(Mod32 x y) -> (Select0 (DIV x y))
+(Mod32u x y) -> (Select0 (DIVU x y))
+(Mod16 x y) -> (Select0 (DIV (SignExt16to32 x) (SignExt16to32 y)))
+(Mod16u x y) -> (Select0 (DIVU (ZeroExt16to32 x) (ZeroExt16to32 y)))
+(Mod8 x y) -> (Select0 (DIV (SignExt8to32 x) (SignExt8to32 y)))
+(Mod8u x y) -> (Select0 (DIVU (ZeroExt8to32 x) (ZeroExt8to32 y)))
+
+(And32 x y) -> (AND x y)
+(And16 x y) -> (AND x y)
+(And8 x y) -> (AND x y)
+
+(Or32 x y) -> (OR x y)
+(Or16 x y) -> (OR x y)
+(Or8 x y) -> (OR x y)
+
+(Xor32 x y) -> (XOR x y)
+(Xor16 x y) -> (XOR x y)
+(Xor8 x y) -> (XOR x y)
+
+// constant shifts
+// generic opt rewrites all constant shifts to shift by Const64
+(Lsh32x64 x (Const64 [c])) && uint32(c) < 32 -> (SLLconst x [c])
+(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])
+(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])
+
+// large constant shifts
+(Lsh32x64 _ (Const64 [c])) && uint32(c) >= 32 -> (MOVWconst [0])
+(Rsh32Ux64 _ (Const64 [c])) && uint32(c) >= 32 -> (MOVWconst [0])
+(Lsh16x64 _ (Const64 [c])) && uint32(c) >= 16 -> (MOVWconst [0])
+(Rsh16Ux64 _ (Const64 [c])) && uint32(c) >= 16 -> (MOVWconst [0])
+(Lsh8x64 _ (Const64 [c])) && uint32(c) >= 8 -> (MOVWconst [0])
+(Rsh8Ux64 _ (Const64 [c])) && uint32(c) >= 8 -> (MOVWconst [0])
+
+// 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])
+
+// shifts
+// hardware instruction uses only the low 5 bits of the shift
+// we compare to 32 to ensure Go semantics for large shifts
+(Lsh32x32 <t> x y) -> (CMOVZ (SLL <t> x y) (MOVWconst [0]) (SGTUconst [32] y))
+(Lsh32x16 <t> x y) -> (CMOVZ (SLL <t> x (ZeroExt16to32 y) ) (MOVWconst [0]) (SGTUconst [32] (ZeroExt16to32 y)))
+(Lsh32x8 <t> x y) -> (CMOVZ (SLL <t> x (ZeroExt8to32 y) ) (MOVWconst [0]) (SGTUconst [32] (ZeroExt8to32 y)))
+
+(Lsh16x32 <t> x y) -> (CMOVZ (SLL <t> x y) (MOVWconst [0]) (SGTUconst [32] y))
+(Lsh16x16 <t> x y) -> (CMOVZ (SLL <t> x (ZeroExt16to32 y) ) (MOVWconst [0]) (SGTUconst [32] (ZeroExt16to32 y)))
+(Lsh16x8 <t> x y) -> (CMOVZ (SLL <t> x (ZeroExt8to32 y) ) (MOVWconst [0]) (SGTUconst [32] (ZeroExt8to32 y)))
+
+(Lsh8x32 <t> x y) -> (CMOVZ (SLL <t> x y) (MOVWconst [0]) (SGTUconst [32] y))
+(Lsh8x16 <t> x y) -> (CMOVZ (SLL <t> x (ZeroExt16to32 y) ) (MOVWconst [0]) (SGTUconst [32] (ZeroExt16to32 y)))
+(Lsh8x8 <t> x y) -> (CMOVZ (SLL <t> x (ZeroExt8to32 y) ) (MOVWconst [0]) (SGTUconst [32] (ZeroExt8to32 y)))
+
+(Rsh32Ux32 <t> x y) -> (CMOVZ (SRL <t> x y) (MOVWconst [0]) (SGTUconst [32] y))
+(Rsh32Ux16 <t> x y) -> (CMOVZ (SRL <t> x (ZeroExt16to32 y) ) (MOVWconst [0]) (SGTUconst [32] (ZeroExt16to32 y)))
+(Rsh32Ux8 <t> x y) -> (CMOVZ (SRL <t> x (ZeroExt8to32 y) ) (MOVWconst [0]) (SGTUconst [32] (ZeroExt8to32 y)))
+
+(Rsh16Ux32 <t> x y) -> (CMOVZ (SRL <t> (ZeroExt16to32 x) y) (MOVWconst [0]) (SGTUconst [32] y))
+(Rsh16Ux16 <t> x y) -> (CMOVZ (SRL <t> (ZeroExt16to32 x) (ZeroExt16to32 y) ) (MOVWconst [0]) (SGTUconst [32] (ZeroExt16to32 y)))
+(Rsh16Ux8 <t> x y) -> (CMOVZ (SRL <t> (ZeroExt16to32 x) (ZeroExt8to32 y) ) (MOVWconst [0]) (SGTUconst [32] (ZeroExt8to32 y)))
+
+(Rsh8Ux32 <t> x y) -> (CMOVZ (SRL <t> (ZeroExt8to32 x) y) (MOVWconst [0]) (SGTUconst [32] y))
+(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))))
+
+(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))))
+
+(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))))
+
+// unary ops
+(Neg32 x) -> (NEG x)
+(Neg16 x) -> (NEG x)
+(Neg8 x) -> (NEG x)
+(Neg32F x) -> (NEGF x)
+(Neg64F x) -> (NEGD x)
+
+(Com32 x) -> (NORconst [0] x)
+(Com16 x) -> (NORconst [0] x)
+(Com8 x) -> (NORconst [0] x)
+
+(Sqrt x) -> (SQRTD x)
+
+// count trailing zero
+// 32 - CLZ(x&-x - 1)
+(Ctz32 <t> x) -> (SUB (MOVWconst [32]) (CLZ <t> (SUBconst <t> [1] (AND <t> x (NEG <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))
+(NeqB x y) -> (XOR x y)
+(Not x) -> (XORconst [1] x)
+
+// constants
+(Const32 [val]) -> (MOVWconst [val])
+(Const16 [val]) -> (MOVWconst [val])
+(Const8 [val]) -> (MOVWconst [val])
+(Const32F [val]) -> (MOVFconst [val])
+(Const64F [val]) -> (MOVDconst [val])
+(ConstNil) -> (MOVWconst [0])
+(ConstBool [b]) -> (MOVWconst [b])
+
+// truncations
+// Because we ignore high parts of registers, truncates are just copies.
+(Trunc16to8 x) -> x
+(Trunc32to8 x) -> x
+(Trunc32to16 x) -> x
+
+// Zero-/Sign-extensions
+(ZeroExt8to16 x) -> (MOVBUreg x)
+(ZeroExt8to32 x) -> (MOVBUreg x)
+(ZeroExt16to32 x) -> (MOVHUreg x)
+
+(SignExt8to16 x) -> (MOVBreg x)
+(SignExt8to32 x) -> (MOVBreg x)
+(SignExt16to32 x) -> (MOVHreg x)
+
+(Signmask x) -> (SRAconst x [31])
+(Zeromask x) -> (NEG (SGTU x (MOVWconst [0])))
+(Slicemask x) -> (NEG (SGT x (MOVWconst [0])))
+
+// float <-> int conversion
+(Cvt32to32F x) -> (MOVWF x)
+(Cvt32to64F x) -> (MOVWD x)
+(Cvt32Fto32 x) -> (TRUNCFW x)
+(Cvt64Fto32 x) -> (TRUNCDW x)
+(Cvt32Fto64F x) -> (MOVFD x)
+(Cvt64Fto32F x) -> (MOVDF x)
+
+// comparisons
+(Eq8 x y) -> (SGTUconst [1] (XOR (ZeroExt8to32 x) (ZeroExt8to32 y)))
+(Eq16 x y) -> (SGTUconst [1] (XOR (ZeroExt16to32 x) (ZeroExt16to32 y)))
+(Eq32 x y) -> (SGTUconst [1] (XOR x y))
+(EqPtr x y) -> (SGTUconst [1] (XOR x y))
+(Eq32F x y) -> (FPFlagTrue (CMPEQF x y))
+(Eq64F x y) -> (FPFlagTrue (CMPEQD x y))
+
+(Neq8 x y) -> (SGTU (XOR (ZeroExt8to32 x) (ZeroExt8to32 y)) (MOVWconst [0]))
+(Neq16 x y) -> (SGTU (XOR (ZeroExt16to32 x) (ZeroExt16to32 y)) (MOVWconst [0]))
+(Neq32 x y) -> (SGTU (XOR x y) (MOVWconst [0]))
+(NeqPtr x y) -> (SGTU (XOR x y) (MOVWconst [0]))
+(Neq32F x y) -> (FPFlagFalse (CMPEQF x y))
+(Neq64F x y) -> (FPFlagFalse (CMPEQD x y))
+
+(Less8 x y) -> (SGT (SignExt8to32 y) (SignExt8to32 x))
+(Less16 x y) -> (SGT (SignExt16to32 y) (SignExt16to32 x))
+(Less32 x y) -> (SGT y x)
+(Less32F x y) -> (FPFlagTrue (CMPGTF y x)) // reverse operands to work around NaN
+(Less64F x y) -> (FPFlagTrue (CMPGTD y x)) // reverse operands to work around NaN
+
+(Less8U x y) -> (SGTU (ZeroExt8to32 y) (ZeroExt8to32 x))
+(Less16U x y) -> (SGTU (ZeroExt16to32 y) (ZeroExt16to32 x))
+(Less32U x y) -> (SGTU y x)
+
+(Leq8 x y) -> (XORconst [1] (SGT (SignExt8to32 x) (SignExt8to32 y)))
+(Leq16 x y) -> (XORconst [1] (SGT (SignExt16to32 x) (SignExt16to32 y)))
+(Leq32 x y) -> (XORconst [1] (SGT x y))
+(Leq32F x y) -> (FPFlagTrue (CMPGEF y x)) // reverse operands to work around NaN
+(Leq64F x y) -> (FPFlagTrue (CMPGED y x)) // reverse operands to work around NaN
+
+(Leq8U x y) -> (XORconst [1] (SGTU (ZeroExt8to32 x) (ZeroExt8to32 y)))
+(Leq16U x y) -> (XORconst [1] (SGTU (ZeroExt16to32 x) (ZeroExt16to32 y)))
+(Leq32U x y) -> (XORconst [1] (SGTU x y))
+
+(Greater8 x y) -> (SGT (SignExt8to32 x) (SignExt8to32 y))
+(Greater16 x y) -> (SGT (SignExt16to32 x) (SignExt16to32 y))
+(Greater32 x y) -> (SGT x y)
+(Greater32F x y) -> (FPFlagTrue (CMPGTF x y))
+(Greater64F x y) -> (FPFlagTrue (CMPGTD x y))
+
+(Greater8U x y) -> (SGTU (ZeroExt8to32 x) (ZeroExt8to32 y))
+(Greater16U x y) -> (SGTU (ZeroExt16to32 x) (ZeroExt16to32 y))
+(Greater32U x y) -> (SGTU x y)
+
+(Geq8 x y) -> (XORconst [1] (SGT (SignExt8to32 y) (SignExt8to32 x)))
+(Geq16 x y) -> (XORconst [1] (SGT (SignExt16to32 y) (SignExt16to32 x)))
+(Geq32 x y) -> (XORconst [1] (SGT y x))
+(Geq32F x y) -> (FPFlagTrue (CMPGEF x y))
+(Geq64F x y) -> (FPFlagTrue (CMPGED x y))
+
+(Geq8U x y) -> (XORconst [1] (SGTU (ZeroExt8to32 y) (ZeroExt8to32 x)))
+(Geq16U x y) -> (XORconst [1] (SGTU (ZeroExt16to32 y) (ZeroExt16to32 x)))
+(Geq32U x y) -> (XORconst [1] (SGTU y x))
+
+(OffPtr [off] ptr:(SP)) -> (MOVWaddr [off] ptr)
+(OffPtr [off] ptr) -> (ADDconst [off] ptr)
+
+(Addr {sym} base) -> (MOVWaddr {sym} base)
+
+// loads
+(Load <t> ptr mem) && t.IsBoolean() -> (MOVBUload ptr mem)
+(Load <t> ptr mem) && (is8BitInt(t) && isSigned(t)) -> (MOVBload ptr mem)
+(Load <t> ptr mem) && (is8BitInt(t) && !isSigned(t)) -> (MOVBUload ptr mem)
+(Load <t> ptr mem) && (is16BitInt(t) && isSigned(t)) -> (MOVHload ptr mem)
+(Load <t> ptr mem) && (is16BitInt(t) && !isSigned(t)) -> (MOVHUload ptr mem)
+(Load <t> ptr mem) && (is32BitInt(t) || isPtr(t)) -> (MOVWload ptr mem)
+(Load <t> ptr mem) && is32BitFloat(t) -> (MOVFload ptr mem)
+(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)
+
+// 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 ->
+ (MOVHstore ptr (MOVWconst [0]) mem)
+(Zero [s] ptr mem) && SizeAndAlign(s).Size() == 2 ->
+ (MOVBstore [1] ptr (MOVWconst [0])
+ (MOVBstore [0] ptr (MOVWconst [0]) mem))
+(Zero [s] ptr mem) && SizeAndAlign(s).Size() == 4 && SizeAndAlign(s).Align()%4 == 0 ->
+ (MOVWstore ptr (MOVWconst [0]) mem)
+(Zero [s] ptr mem) && SizeAndAlign(s).Size() == 4 && SizeAndAlign(s).Align()%2 == 0 ->
+ (MOVHstore [2] ptr (MOVWconst [0])
+ (MOVHstore [0] ptr (MOVWconst [0]) mem))
+(Zero [s] ptr mem) && SizeAndAlign(s).Size() == 4 ->
+ (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 ->
+ (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 ->
+ (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 ->
+ (MOVWstore [4] ptr (MOVWconst [0])
+ (MOVWstore [0] ptr (MOVWconst [0]) mem))
+(Zero [s] ptr mem) && SizeAndAlign(s).Size() == 12 && SizeAndAlign(s).Align()%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 ->
+ (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()]
+ ptr
+ (ADDconst <ptr.Type> ptr [SizeAndAlign(s).Size()-moveSize(SizeAndAlign(s).Align(), 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 ->
+ (MOVHstore dst (MOVHUload src mem) mem)
+(Move [s] dst src mem) && SizeAndAlign(s).Size() == 2 ->
+ (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 ->
+ (MOVWstore dst (MOVWload src mem) mem)
+(Move [s] dst src mem) && SizeAndAlign(s).Size() == 4 && SizeAndAlign(s).Align()%2 == 0 ->
+ (MOVHstore [2] dst (MOVHUload [2] src mem)
+ (MOVHstore dst (MOVHUload src mem) mem))
+(Move [s] dst src mem) && SizeAndAlign(s).Size() == 4 ->
+ (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 ->
+ (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 ->
+ (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 ->
+ (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 ->
+ (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 ->
+ (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 ->
+ (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))))
+
+
+// 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()]
+ dst
+ src
+ (ADDconst <src.Type> src [SizeAndAlign(s).Size()-moveSize(SizeAndAlign(s).Align(), 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
+(AtomicLoad32 ptr mem) -> (LoweredAtomicLoad ptr mem)
+(AtomicLoadPtr ptr mem) -> (LoweredAtomicLoad ptr mem)
+
+(AtomicStore32 ptr val mem) -> (LoweredAtomicStore ptr val mem)
+(AtomicStorePtrNoWB ptr val mem) -> (LoweredAtomicStore ptr val mem)
+
+(AtomicExchange32 ptr val mem) -> (LoweredAtomicExchange ptr val mem)
+(AtomicAdd32 ptr val mem) -> (LoweredAtomicAdd ptr val mem)
+
+(AtomicCompareAndSwap32 ptr old new_ mem) -> (LoweredAtomicCas ptr old new_ mem)
+
+// 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)
+
+// 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]
+ (XORconst <config.fe.TypeUInt32()> [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)
+
+// 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)
+
+
+// checks
+(NilCheck ptr mem) -> (LoweredNilCheck ptr mem)
+(IsNonNil ptr) -> (SGTU ptr (MOVWconst [0]))
+(IsInBounds idx len) -> (SGTU len idx)
+(IsSliceInBounds idx len) -> (XORconst [1] (SGTU idx len))
+
+// pseudo-ops
+(GetClosurePtr) -> (LoweredGetClosurePtr)
+(Convert x mem) -> (MOVWconvert x mem)
+
+(If cond yes no) -> (NE cond yes no)
+
+
+// Optimizations
+
+// Absorb boolean tests into block
+(NE (FPFlagTrue cmp) yes no) -> (FPT cmp yes no)
+(NE (FPFlagFalse cmp) yes no) -> (FPF cmp yes no)
+(EQ (FPFlagTrue cmp) yes no) -> (FPF cmp yes no)
+(EQ (FPFlagFalse cmp) yes no) -> (FPT cmp yes no)
+(NE (XORconst [1] cmp:(SGT _ _)) yes no) -> (EQ cmp yes no)
+(NE (XORconst [1] cmp:(SGTU _ _)) yes no) -> (EQ cmp yes no)
+(NE (XORconst [1] cmp:(SGTconst _)) yes no) -> (EQ cmp yes no)
+(NE (XORconst [1] cmp:(SGTUconst _)) yes no) -> (EQ cmp yes no)
+(NE (XORconst [1] cmp:(SGTzero _)) yes no) -> (EQ cmp yes no)
+(NE (XORconst [1] cmp:(SGTUzero _)) yes no) -> (EQ cmp yes no)
+(EQ (XORconst [1] cmp:(SGT _ _)) yes no) -> (NE cmp yes no)
+(EQ (XORconst [1] cmp:(SGTU _ _)) yes no) -> (NE cmp yes no)
+(EQ (XORconst [1] cmp:(SGTconst _)) yes no) -> (NE cmp yes no)
+(EQ (XORconst [1] cmp:(SGTUconst _)) yes no) -> (NE cmp yes no)
+(EQ (XORconst [1] cmp:(SGTzero _)) yes no) -> (NE cmp yes no)
+(EQ (XORconst [1] cmp:(SGTUzero _)) yes no) -> (NE cmp yes no)
+(NE (SGTUconst [1] x) yes no) -> (EQ x yes no)
+(EQ (SGTUconst [1] x) yes no) -> (NE x yes no)
+(NE (SGTUzero x) yes no) -> (NE x yes no)
+(EQ (SGTUzero x) yes no) -> (EQ x yes no)
+(NE (SGTconst [0] x) yes no) -> (LTZ x yes no)
+(EQ (SGTconst [0] x) yes no) -> (GEZ x yes no)
+(NE (SGTzero x) yes no) -> (GTZ x yes no)
+(EQ (SGTzero x) yes no) -> (LEZ x yes no)
+
+// fold offset into address
+(ADDconst [off1] (MOVWaddr [off2] {sym} ptr)) -> (MOVWaddr [off1+off2] {sym} ptr)
+
+// fold address into load/store
+(MOVBload [off1] {sym} x:(ADDconst [off2] ptr) mem) && (is16Bit(off1+off2) || x.Uses == 1) -> (MOVBload [off1+off2] {sym} ptr mem)
+(MOVBUload [off1] {sym} x:(ADDconst [off2] ptr) mem) && (is16Bit(off1+off2) || x.Uses == 1) -> (MOVBUload [off1+off2] {sym} ptr mem)
+(MOVHload [off1] {sym} x:(ADDconst [off2] ptr) mem) && (is16Bit(off1+off2) || x.Uses == 1) -> (MOVHload [off1+off2] {sym} ptr mem)
+(MOVHUload [off1] {sym} x:(ADDconst [off2] ptr) mem) && (is16Bit(off1+off2) || x.Uses == 1) -> (MOVHUload [off1+off2] {sym} ptr mem)
+(MOVWload [off1] {sym} x:(ADDconst [off2] ptr) mem) && (is16Bit(off1+off2) || x.Uses == 1) -> (MOVWload [off1+off2] {sym} ptr mem)
+(MOVFload [off1] {sym} x:(ADDconst [off2] ptr) mem) && (is16Bit(off1+off2) || x.Uses == 1) -> (MOVFload [off1+off2] {sym} ptr mem)
+(MOVDload [off1] {sym} x:(ADDconst [off2] ptr) mem) && (is16Bit(off1+off2) || x.Uses == 1) -> (MOVDload [off1+off2] {sym} ptr mem)
+
+(MOVBstore [off1] {sym} x:(ADDconst [off2] ptr) val mem) && (is16Bit(off1+off2) || x.Uses == 1) -> (MOVBstore [off1+off2] {sym} ptr val mem)
+(MOVHstore [off1] {sym} x:(ADDconst [off2] ptr) val mem) && (is16Bit(off1+off2) || x.Uses == 1) -> (MOVHstore [off1+off2] {sym} ptr val mem)
+(MOVWstore [off1] {sym} x:(ADDconst [off2] ptr) val mem) && (is16Bit(off1+off2) || x.Uses == 1) -> (MOVWstore [off1+off2] {sym} ptr val mem)
+(MOVFstore [off1] {sym} x:(ADDconst [off2] ptr) val mem) && (is16Bit(off1+off2) || x.Uses == 1) -> (MOVFstore [off1+off2] {sym} ptr val mem)
+(MOVDstore [off1] {sym} x:(ADDconst [off2] ptr) val mem) && (is16Bit(off1+off2) || x.Uses == 1) -> (MOVDstore [off1+off2] {sym} ptr val mem)
+
+(MOVBstorezero [off1] {sym} x:(ADDconst [off2] ptr) mem) && (is16Bit(off1+off2) || x.Uses == 1) -> (MOVBstorezero [off1+off2] {sym} ptr mem)
+(MOVHstorezero [off1] {sym} x:(ADDconst [off2] ptr) mem) && (is16Bit(off1+off2) || x.Uses == 1) -> (MOVHstorezero [off1+off2] {sym} ptr mem)
+(MOVWstorezero [off1] {sym} x:(ADDconst [off2] ptr) mem) && (is16Bit(off1+off2) || x.Uses == 1) -> (MOVWstorezero [off1+off2] {sym} ptr mem)
+
+(MOVBload [off1] {sym1} (MOVWaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) ->
+ (MOVBload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
+(MOVBUload [off1] {sym1} (MOVWaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) ->
+ (MOVBUload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
+(MOVHload [off1] {sym1} (MOVWaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) ->
+ (MOVHload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
+(MOVHUload [off1] {sym1} (MOVWaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) ->
+ (MOVHUload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
+(MOVWload [off1] {sym1} (MOVWaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) ->
+ (MOVWload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
+(MOVFload [off1] {sym1} (MOVWaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) ->
+ (MOVFload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
+(MOVDload [off1] {sym1} (MOVWaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) ->
+ (MOVDload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
+
+(MOVBstore [off1] {sym1} (MOVWaddr [off2] {sym2} ptr) val mem) && canMergeSym(sym1,sym2) ->
+ (MOVBstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
+(MOVHstore [off1] {sym1} (MOVWaddr [off2] {sym2} ptr) val mem) && canMergeSym(sym1,sym2) ->
+ (MOVHstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
+(MOVWstore [off1] {sym1} (MOVWaddr [off2] {sym2} ptr) val mem) && canMergeSym(sym1,sym2) ->
+ (MOVWstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
+(MOVFstore [off1] {sym1} (MOVWaddr [off2] {sym2} ptr) val mem) && canMergeSym(sym1,sym2) ->
+ (MOVFstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
+(MOVDstore [off1] {sym1} (MOVWaddr [off2] {sym2} ptr) val mem) && canMergeSym(sym1,sym2) ->
+ (MOVDstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
+(MOVBstorezero [off1] {sym1} (MOVWaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) ->
+ (MOVBstorezero [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
+(MOVHstorezero [off1] {sym1} (MOVWaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) ->
+ (MOVHstorezero [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
+(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
+(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
+
+// store zero
+(MOVBstore [off] {sym} ptr (MOVWconst [0]) mem) -> (MOVBstorezero [off] {sym} ptr mem)
+(MOVHstore [off] {sym} ptr (MOVWconst [0]) mem) -> (MOVHstorezero [off] {sym} ptr mem)
+(MOVWstore [off] {sym} ptr (MOVWconst [0]) mem) -> (MOVWstorezero [off] {sym} ptr mem)
+
+// don't extend after proper load
+(MOVBreg x:(MOVBload _ _)) -> (MOVWreg x)
+(MOVBUreg x:(MOVBUload _ _)) -> (MOVWreg x)
+(MOVHreg x:(MOVBload _ _)) -> (MOVWreg x)
+(MOVHreg x:(MOVBUload _ _)) -> (MOVWreg x)
+(MOVHreg x:(MOVHload _ _)) -> (MOVWreg x)
+(MOVHUreg x:(MOVBUload _ _)) -> (MOVWreg x)
+(MOVHUreg x:(MOVHUload _ _)) -> (MOVWreg x)
+
+// fold double extensions
+(MOVBreg x:(MOVBreg _)) -> (MOVWreg x)
+(MOVBUreg x:(MOVBUreg _)) -> (MOVWreg x)
+(MOVHreg x:(MOVBreg _)) -> (MOVWreg x)
+(MOVHreg x:(MOVBUreg _)) -> (MOVWreg x)
+(MOVHreg x:(MOVHreg _)) -> (MOVWreg x)
+(MOVHUreg x:(MOVBUreg _)) -> (MOVWreg x)
+(MOVHUreg x:(MOVHUreg _)) -> (MOVWreg x)
+
+// sign extended loads
+// Note: The combined instruction must end up in the same block
+// as the original load. If not, we end up making a value with
+// memory type live in two different blocks, which can lead to
+// multiple memory values alive simultaneously.
+// Make sure we don't combine these ops if the load has another use.
+// This prevents a single load from being split into multiple loads
+// which then might return different values. See test/atomicload.go.
+(MOVBreg <t> x:(MOVBUload [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVBload <t> [off] {sym} ptr mem)
+(MOVBUreg <t> x:(MOVBload [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVBUload <t> [off] {sym} ptr mem)
+(MOVHreg <t> x:(MOVHUload [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVHload <t> [off] {sym} ptr mem)
+(MOVHUreg <t> x:(MOVHload [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVHUload <t> [off] {sym} ptr mem)
+
+// fold extensions and ANDs together
+(MOVBUreg (ANDconst [c] x)) -> (ANDconst [c&0xff] x)
+(MOVHUreg (ANDconst [c] x)) -> (ANDconst [c&0xffff] x)
+(MOVBreg (ANDconst [c] x)) && c & 0x80 == 0 -> (ANDconst [c&0x7f] x)
+(MOVHreg (ANDconst [c] x)) && c & 0x8000 == 0 -> (ANDconst [c&0x7fff] x)
+
+// don't extend before store
+(MOVBstore [off] {sym} ptr (MOVBreg x) mem) -> (MOVBstore [off] {sym} ptr x mem)
+(MOVBstore [off] {sym} ptr (MOVBUreg x) mem) -> (MOVBstore [off] {sym} ptr x mem)
+(MOVBstore [off] {sym} ptr (MOVHreg x) mem) -> (MOVBstore [off] {sym} ptr x mem)
+(MOVBstore [off] {sym} ptr (MOVHUreg x) mem) -> (MOVBstore [off] {sym} ptr x mem)
+(MOVBstore [off] {sym} ptr (MOVWreg x) mem) -> (MOVBstore [off] {sym} ptr x mem)
+(MOVHstore [off] {sym} ptr (MOVHreg x) mem) -> (MOVHstore [off] {sym} ptr x mem)
+(MOVHstore [off] {sym} ptr (MOVHUreg x) mem) -> (MOVHstore [off] {sym} ptr x mem)
+(MOVHstore [off] {sym} ptr (MOVWreg x) mem) -> (MOVHstore [off] {sym} ptr x mem)
+(MOVWstore [off] {sym} ptr (MOVWreg x) mem) -> (MOVWstore [off] {sym} ptr x mem)
+
+// if a register move has only 1 use, just use the same register without emitting instruction
+// MOVWnop doesn't emit instruction, only for ensuring the type.
+(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])
+(SRL _ (MOVWconst [c])) && uint32(c)>=32 -> (MOVWconst [0])
+(SRA x (MOVWconst [c])) && uint32(c)>=32 -> (SRAconst x [31])
+(SLL x (MOVWconst [c])) -> (SLLconst x [c])
+(SRL x (MOVWconst [c])) -> (SRLconst x [c])
+(SRA x (MOVWconst [c])) -> (SRAconst x [c])
+
+(SGT (MOVWconst [c]) x) -> (SGTconst [c] x)
+(SGTU (MOVWconst [c]) x) -> (SGTUconst [c] x)
+(SGT x (MOVWconst [0])) -> (SGTzero x)
+(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
+(Select0 (MULTU (MOVWconst [1]) _ )) -> (MOVWconst [0])
+(Select1 (MULTU (MOVWconst [-1]) x )) -> (NEG <x.Type> x)
+(Select0 (MULTU (MOVWconst [-1]) x )) -> (CMOVZ (ADDconst <x.Type> [-1] x) (MOVWconst [0]) x)
+(Select1 (MULTU (MOVWconst [c]) x )) && isPowerOfTwo(int64(uint32(c))) -> (SLLconst [log2(int64(uint32(c)))] x)
+(Select0 (MULTU (MOVWconst [c]) x )) && isPowerOfTwo(int64(uint32(c))) -> (SRLconst [32-log2(int64(uint32(c)))] x)
+
+(MUL (MOVWconst [0]) _ ) -> (MOVWconst [0])
+(MUL (MOVWconst [1]) x ) -> x
+(MUL (MOVWconst [-1]) x ) -> (NEG x)
+(MUL (MOVWconst [c]) x ) && isPowerOfTwo(int64(uint32(c))) -> (SLLconst [log2(int64(uint32(c)))] x)
+
+// 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
+(OR x x) -> x
+(XOR x x) -> (MOVWconst [0])
+
+// miscellaneous patterns generated by dec64
+(AND (SGTUconst [1] x) (SGTUconst [1] y)) -> (SGTUconst [1] (OR <x.Type> x y))
+(OR (SGTUzero x) (SGTUzero y)) -> (SGTUzero (OR <x.Type> x y))
+
+// remove redundant *const ops
+(ADDconst [0] x) -> x
+(SUBconst [0] x) -> x
+(ANDconst [0] _) -> (MOVWconst [0])
+(ANDconst [-1] x) -> x
+(ORconst [0] x) -> x
+(ORconst [-1] _) -> (MOVWconst [-1])
+(XORconst [0] x) -> x
+(XORconst [-1] x) -> (NORconst [0] x)
+
+// generic constant folding
+(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)
+(SUBconst [c] (MOVWconst [d])) -> (MOVWconst [int64(int32(d-c))])
+(SUBconst [c] (SUBconst [d] x)) -> (ADDconst [int64(int32(-c-d))] x)
+(SUBconst [c] (ADDconst [d] x)) -> (ADDconst [int64(int32(-c+d))] x)
+(SLLconst [c] (MOVWconst [d])) -> (MOVWconst [int64(int32(uint32(d)<<uint32(c)))])
+(SRLconst [c] (MOVWconst [d])) -> (MOVWconst [int64(uint32(d)>>uint32(c))])
+(SRAconst [c] (MOVWconst [d])) -> (MOVWconst [int64(int32(d)>>uint32(c))])
+(MUL (MOVWconst [c]) (MOVWconst [d])) -> (MOVWconst [int64(int32(c)*int32(d))])
+(Select1 (MULTU (MOVWconst [c]) (MOVWconst [d]))) -> (MOVWconst [int64(int32(uint32(c)*uint32(d)))])
+(Select0 (MULTU (MOVWconst [c]) (MOVWconst [d]))) -> (MOVWconst [(c*d)>>32])
+(Select1 (DIV (MOVWconst [c]) (MOVWconst [d]))) -> (MOVWconst [int64(int32(c)/int32(d))])
+(Select1 (DIVU (MOVWconst [c]) (MOVWconst [d]))) -> (MOVWconst [int64(int32(uint32(c)/uint32(d)))])
+(Select0 (DIV (MOVWconst [c]) (MOVWconst [d]))) -> (MOVWconst [int64(int32(c)%int32(d))])
+(Select0 (DIVU (MOVWconst [c]) (MOVWconst [d]))) -> (MOVWconst [int64(int32(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])
+(ORconst [c] (ORconst [d] x)) -> (ORconst [c|d] x)
+(XORconst [c] (MOVWconst [d])) -> (MOVWconst [c^d])
+(XORconst [c] (XORconst [d] x)) -> (XORconst [c^d] x)
+(NORconst [c] (MOVWconst [d])) -> (MOVWconst [^(c|d)])
+(NEG (MOVWconst [c])) -> (MOVWconst [int64(int32(-c))])
+(MOVBreg (MOVWconst [c])) -> (MOVWconst [int64(int8(c))])
+(MOVBUreg (MOVWconst [c])) -> (MOVWconst [int64(uint8(c))])
+(MOVHreg (MOVWconst [c])) -> (MOVWconst [int64(int16(c))])
+(MOVHUreg (MOVWconst [c])) -> (MOVWconst [int64(uint16(c))])
+(MOVWreg (MOVWconst [c])) -> (MOVWconst [c])
+
+// constant comparisons
+(SGTconst [c] (MOVWconst [d])) && int32(c) > int32(d) -> (MOVWconst [1])
+(SGTconst [c] (MOVWconst [d])) && int32(c) <= int32(d) -> (MOVWconst [0])
+(SGTUconst [c] (MOVWconst [d])) && uint32(c)>uint32(d) -> (MOVWconst [1])
+(SGTUconst [c] (MOVWconst [d])) && uint32(c)<=uint32(d) -> (MOVWconst [0])
+(SGTzero (MOVWconst [d])) && int32(d) > 0 -> (MOVWconst [1])
+(SGTzero (MOVWconst [d])) && int32(d) <= 0 -> (MOVWconst [0])
+(SGTUzero (MOVWconst [d])) && uint32(d) != 0 -> (MOVWconst [1])
+(SGTUzero (MOVWconst [d])) && uint32(d) == 0 -> (MOVWconst [0])
+
+// other known comparisons
+(SGTconst [c] (MOVBreg _)) && 0x7f < int32(c) -> (MOVWconst [1])
+(SGTconst [c] (MOVBreg _)) && int32(c) <= -0x80 -> (MOVWconst [0])
+(SGTconst [c] (MOVBUreg _)) && 0xff < int32(c) -> (MOVWconst [1])
+(SGTconst [c] (MOVBUreg _)) && int32(c) < 0 -> (MOVWconst [0])
+(SGTUconst [c] (MOVBUreg _)) && 0xff < uint32(c) -> (MOVWconst [1])
+(SGTconst [c] (MOVHreg _)) && 0x7fff < int32(c) -> (MOVWconst [1])
+(SGTconst [c] (MOVHreg _)) && int32(c) <= -0x8000 -> (MOVWconst [0])
+(SGTconst [c] (MOVHUreg _)) && 0xffff < int32(c) -> (MOVWconst [1])
+(SGTconst [c] (MOVHUreg _)) && int32(c) < 0 -> (MOVWconst [0])
+(SGTUconst [c] (MOVHUreg _)) && 0xffff < uint32(c) -> (MOVWconst [1])
+(SGTconst [c] (ANDconst [m] _)) && 0 <= int32(m) && int32(m) < int32(c) -> (MOVWconst [1])
+(SGTUconst [c] (ANDconst [m] _)) && uint32(m) < uint32(c) -> (MOVWconst [1])
+(SGTconst [c] (SRLconst _ [d])) && 0 <= int32(c) && uint32(d) <= 31 && 1<<(32-uint32(d)) <= int32(c) -> (MOVWconst [1])
+(SGTUconst [c] (SRLconst _ [d])) && uint32(d) <= 31 && 1<<(32-uint32(d)) <= uint32(c) -> (MOVWconst [1])
+
+// absorb constants into branches
+(EQ (MOVWconst [0]) yes no) -> (First nil yes no)
+(EQ (MOVWconst [c]) yes no) && c != 0 -> (First nil no yes)
+(NE (MOVWconst [0]) yes no) -> (First nil no yes)
+(NE (MOVWconst [c]) yes no) && c != 0 -> (First nil yes no)
+(LTZ (MOVWconst [c]) yes no) && int32(c) < 0 -> (First nil yes no)
+(LTZ (MOVWconst [c]) yes no) && int32(c) >= 0 -> (First nil no yes)
+(LEZ (MOVWconst [c]) yes no) && int32(c) <= 0 -> (First nil yes no)
+(LEZ (MOVWconst [c]) yes no) && int32(c) > 0 -> (First nil no yes)
+(GTZ (MOVWconst [c]) yes no) && int32(c) > 0 -> (First nil yes no)
+(GTZ (MOVWconst [c]) yes no) && int32(c) <= 0 -> (First nil no yes)
+(GEZ (MOVWconst [c]) yes no) && int32(c) >= 0 -> (First nil yes no)
+(GEZ (MOVWconst [c]) yes no) && int32(c) < 0 -> (First nil no yes)
+
+// conditional move
+(CMOVZ _ b (MOVWconst [0])) -> b
+(CMOVZ a _ (MOVWconst [c])) && c!=0-> a
+(CMOVZzero _ (MOVWconst [0])) -> (MOVWconst [0])
+(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)
+
diff --git a/src/cmd/compile/internal/ssa/gen/MIPS64.rules b/src/cmd/compile/internal/ssa/gen/MIPS64.rules
new file mode 100644
index 0000000..7a496be
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/gen/MIPS64.rules
@@ -0,0 +1,708 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+(AddPtr x y) -> (ADDV x y)
+(Add64 x y) -> (ADDV x y)
+(Add32 x y) -> (ADDV x y)
+(Add16 x y) -> (ADDV x y)
+(Add8 x y) -> (ADDV x y)
+(Add32F x y) -> (ADDF x y)
+(Add64F x y) -> (ADDD x y)
+
+(SubPtr x y) -> (SUBV x y)
+(Sub64 x y) -> (SUBV x y)
+(Sub32 x y) -> (SUBV x y)
+(Sub16 x y) -> (SUBV x y)
+(Sub8 x y) -> (SUBV x y)
+(Sub32F x y) -> (SUBF x y)
+(Sub64F x y) -> (SUBD x y)
+
+(Mul64 x y) -> (Select1 (MULVU x y))
+(Mul32 x y) -> (Select1 (MULVU x y))
+(Mul16 x y) -> (Select1 (MULVU x y))
+(Mul8 x y) -> (Select1 (MULVU x y))
+(Mul32F x y) -> (MULF x y)
+(Mul64F x y) -> (MULD x y)
+
+(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])
+
+(Div64 x y) -> (Select1 (DIVV x y))
+(Div64u x y) -> (Select1 (DIVVU x y))
+(Div32 x y) -> (Select1 (DIVV (SignExt32to64 x) (SignExt32to64 y)))
+(Div32u x y) -> (Select1 (DIVVU (ZeroExt32to64 x) (ZeroExt32to64 y)))
+(Div16 x y) -> (Select1 (DIVV (SignExt16to64 x) (SignExt16to64 y)))
+(Div16u x y) -> (Select1 (DIVVU (ZeroExt16to64 x) (ZeroExt16to64 y)))
+(Div8 x y) -> (Select1 (DIVV (SignExt8to64 x) (SignExt8to64 y)))
+(Div8u x y) -> (Select1 (DIVVU (ZeroExt8to64 x) (ZeroExt8to64 y)))
+(Div32F x y) -> (DIVF x y)
+(Div64F x y) -> (DIVD x y)
+
+(Mod64 x y) -> (Select0 (DIVV x y))
+(Mod64u x y) -> (Select0 (DIVVU x y))
+(Mod32 x y) -> (Select0 (DIVV (SignExt32to64 x) (SignExt32to64 y)))
+(Mod32u x y) -> (Select0 (DIVVU (ZeroExt32to64 x) (ZeroExt32to64 y)))
+(Mod16 x y) -> (Select0 (DIVV (SignExt16to64 x) (SignExt16to64 y)))
+(Mod16u x y) -> (Select0 (DIVVU (ZeroExt16to64 x) (ZeroExt16to64 y)))
+(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])))
+
+(And64 x y) -> (AND x y)
+(And32 x y) -> (AND x y)
+(And16 x y) -> (AND x y)
+(And8 x y) -> (AND x y)
+
+(Or64 x y) -> (OR x y)
+(Or32 x y) -> (OR x y)
+(Or16 x y) -> (OR x y)
+(Or8 x y) -> (OR x y)
+
+(Xor64 x y) -> (XOR x y)
+(Xor32 x y) -> (XOR x y)
+(Xor16 x y) -> (XOR x y)
+(Xor8 x y) -> (XOR x y)
+
+// 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)))
+
+// unary ops
+(Neg64 x) -> (NEGV x)
+(Neg32 x) -> (NEGV x)
+(Neg16 x) -> (NEGV x)
+(Neg8 x) -> (NEGV x)
+(Neg32F x) -> (NEGF x)
+(Neg64F x) -> (NEGD x)
+
+(Com64 x) -> (NOR (MOVVconst [0]) x)
+(Com32 x) -> (NOR (MOVVconst [0]) x)
+(Com16 x) -> (NOR (MOVVconst [0]) x)
+(Com8 x) -> (NOR (MOVVconst [0]) 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 (MOVVconst [1]) (XOR <config.fe.TypeBool()> x y))
+(NeqB x y) -> (XOR x y)
+(Not x) -> (XORconst [1] x)
+
+// constants
+(Const64 [val]) -> (MOVVconst [val])
+(Const32 [val]) -> (MOVVconst [val])
+(Const16 [val]) -> (MOVVconst [val])
+(Const8 [val]) -> (MOVVconst [val])
+(Const32F [val]) -> (MOVFconst [val])
+(Const64F [val]) -> (MOVDconst [val])
+(ConstNil) -> (MOVVconst [0])
+(ConstBool [b]) -> (MOVVconst [b])
+
+(Slicemask <t> x) -> (NORconst [0] (SRAVconst <t> (SUBVconst <t> x [1]) [63]))
+
+// truncations
+// Because we ignore high parts of registers, truncates are just copies.
+(Trunc16to8 x) -> x
+(Trunc32to8 x) -> x
+(Trunc32to16 x) -> x
+(Trunc64to8 x) -> x
+(Trunc64to16 x) -> x
+(Trunc64to32 x) -> x
+
+// Zero-/Sign-extensions
+(ZeroExt8to16 x) -> (MOVBUreg x)
+(ZeroExt8to32 x) -> (MOVBUreg x)
+(ZeroExt16to32 x) -> (MOVHUreg x)
+(ZeroExt8to64 x) -> (MOVBUreg x)
+(ZeroExt16to64 x) -> (MOVHUreg x)
+(ZeroExt32to64 x) -> (MOVWUreg x)
+
+(SignExt8to16 x) -> (MOVBreg x)
+(SignExt8to32 x) -> (MOVBreg x)
+(SignExt16to32 x) -> (MOVHreg x)
+(SignExt8to64 x) -> (MOVBreg x)
+(SignExt16to64 x) -> (MOVHreg x)
+(SignExt32to64 x) -> (MOVWreg x)
+
+// float <-> int conversion
+(Cvt32to32F x) -> (MOVWF x)
+(Cvt32to64F x) -> (MOVWD x)
+(Cvt64to32F x) -> (MOVVF x)
+(Cvt64to64F x) -> (MOVVD x)
+(Cvt32Fto32 x) -> (TRUNCFW x)
+(Cvt64Fto32 x) -> (TRUNCDW x)
+(Cvt32Fto64 x) -> (TRUNCFV x)
+(Cvt64Fto64 x) -> (TRUNCDV x)
+(Cvt32Fto64F x) -> (MOVFD x)
+(Cvt64Fto32F x) -> (MOVDF x)
+
+// comparisons
+(Eq8 x y) -> (SGTU (MOVVconst [1]) (XOR (ZeroExt8to64 x) (ZeroExt8to64 y)))
+(Eq16 x y) -> (SGTU (MOVVconst [1]) (XOR (ZeroExt16to64 x) (ZeroExt16to64 y)))
+(Eq32 x y) -> (SGTU (MOVVconst [1]) (XOR (ZeroExt32to64 x) (ZeroExt32to64 y)))
+(Eq64 x y) -> (SGTU (MOVVconst [1]) (XOR x y))
+(EqPtr x y) -> (SGTU (MOVVconst [1]) (XOR x y))
+(Eq32F x y) -> (FPFlagTrue (CMPEQF x y))
+(Eq64F x y) -> (FPFlagTrue (CMPEQD x y))
+
+(Neq8 x y) -> (SGTU (XOR (ZeroExt8to64 x) (ZeroExt8to64 y)) (MOVVconst [0]))
+(Neq16 x y) -> (SGTU (XOR (ZeroExt16to32 x) (ZeroExt16to64 y)) (MOVVconst [0]))
+(Neq32 x y) -> (SGTU (XOR (ZeroExt32to64 x) (ZeroExt32to64 y)) (MOVVconst [0]))
+(Neq64 x y) -> (SGTU (XOR x y) (MOVVconst [0]))
+(NeqPtr x y) -> (SGTU (XOR x y) (MOVVconst [0]))
+(Neq32F x y) -> (FPFlagFalse (CMPEQF x y))
+(Neq64F x y) -> (FPFlagFalse (CMPEQD x y))
+
+(Less8 x y) -> (SGT (SignExt8to64 y) (SignExt8to64 x))
+(Less16 x y) -> (SGT (SignExt16to64 y) (SignExt16to64 x))
+(Less32 x y) -> (SGT (SignExt32to64 y) (SignExt32to64 x))
+(Less64 x y) -> (SGT y x)
+(Less32F x y) -> (FPFlagTrue (CMPGTF y x)) // reverse operands to work around NaN
+(Less64F x y) -> (FPFlagTrue (CMPGTD y x)) // reverse operands to work around NaN
+
+(Less8U x y) -> (SGTU (ZeroExt8to64 y) (ZeroExt8to64 x))
+(Less16U x y) -> (SGTU (ZeroExt16to64 y) (ZeroExt16to64 x))
+(Less32U x y) -> (SGTU (ZeroExt32to64 y) (ZeroExt32to64 x))
+(Less64U x y) -> (SGTU y x)
+
+(Leq8 x y) -> (XOR (MOVVconst [1]) (SGT (SignExt8to64 x) (SignExt8to64 y)))
+(Leq16 x y) -> (XOR (MOVVconst [1]) (SGT (SignExt16to64 x) (SignExt16to64 y)))
+(Leq32 x y) -> (XOR (MOVVconst [1]) (SGT (SignExt32to64 x) (SignExt32to64 y)))
+(Leq64 x y) -> (XOR (MOVVconst [1]) (SGT x y))
+(Leq32F x y) -> (FPFlagTrue (CMPGEF y x)) // reverse operands to work around NaN
+(Leq64F x y) -> (FPFlagTrue (CMPGED y x)) // reverse operands to work around NaN
+
+(Leq8U x y) -> (XOR (MOVVconst [1]) (SGTU (ZeroExt8to64 x) (ZeroExt8to64 y)))
+(Leq16U x y) -> (XOR (MOVVconst [1]) (SGTU (ZeroExt16to64 x) (ZeroExt16to64 y)))
+(Leq32U x y) -> (XOR (MOVVconst [1]) (SGTU (ZeroExt32to64 x) (ZeroExt32to64 y)))
+(Leq64U x y) -> (XOR (MOVVconst [1]) (SGTU x y))
+
+(Greater8 x y) -> (SGT (SignExt8to64 x) (SignExt8to64 y))
+(Greater16 x y) -> (SGT (SignExt16to64 x) (SignExt16to64 y))
+(Greater32 x y) -> (SGT (SignExt32to64 x) (SignExt32to64 y))
+(Greater64 x y) -> (SGT x y)
+(Greater32F x y) -> (FPFlagTrue (CMPGTF x y))
+(Greater64F x y) -> (FPFlagTrue (CMPGTD x y))
+
+(Greater8U x y) -> (SGTU (ZeroExt8to64 x) (ZeroExt8to64 y))
+(Greater16U x y) -> (SGTU (ZeroExt16to64 x) (ZeroExt16to64 y))
+(Greater32U x y) -> (SGTU (ZeroExt32to64 x) (ZeroExt32to64 y))
+(Greater64U x y) -> (SGTU x y)
+
+(Geq8 x y) -> (XOR (MOVVconst [1]) (SGT (SignExt8to64 y) (SignExt8to64 x)))
+(Geq16 x y) -> (XOR (MOVVconst [1]) (SGT (SignExt16to64 y) (SignExt16to64 x)))
+(Geq32 x y) -> (XOR (MOVVconst [1]) (SGT (SignExt32to64 y) (SignExt32to64 x)))
+(Geq64 x y) -> (XOR (MOVVconst [1]) (SGT y x))
+(Geq32F x y) -> (FPFlagTrue (CMPGEF x y))
+(Geq64F x y) -> (FPFlagTrue (CMPGED x y))
+
+(Geq8U x y) -> (XOR (MOVVconst [1]) (SGTU (ZeroExt8to64 y) (ZeroExt8to64 x)))
+(Geq16U x y) -> (XOR (MOVVconst [1]) (SGTU (ZeroExt16to64 y) (ZeroExt16to64 x)))
+(Geq32U x y) -> (XOR (MOVVconst [1]) (SGTU (ZeroExt32to64 y) (ZeroExt32to64 x)))
+(Geq64U x y) -> (XOR (MOVVconst [1]) (SGTU y x))
+
+(OffPtr [off] ptr:(SP)) -> (MOVVaddr [off] ptr)
+(OffPtr [off] ptr) -> (ADDVconst [off] ptr)
+
+(Addr {sym} base) -> (MOVVaddr {sym} base)
+
+// loads
+(Load <t> ptr mem) && t.IsBoolean() -> (MOVBUload ptr mem)
+(Load <t> ptr mem) && (is8BitInt(t) && isSigned(t)) -> (MOVBload ptr mem)
+(Load <t> ptr mem) && (is8BitInt(t) && !isSigned(t)) -> (MOVBUload ptr mem)
+(Load <t> ptr mem) && (is16BitInt(t) && isSigned(t)) -> (MOVHload ptr mem)
+(Load <t> ptr mem) && (is16BitInt(t) && !isSigned(t)) -> (MOVHUload ptr mem)
+(Load <t> ptr mem) && (is32BitInt(t) && isSigned(t)) -> (MOVWload ptr mem)
+(Load <t> ptr mem) && (is32BitInt(t) && !isSigned(t)) -> (MOVWUload ptr mem)
+(Load <t> ptr mem) && (is64BitInt(t) || isPtr(t)) -> (MOVVload ptr mem)
+(Load <t> ptr mem) && is32BitFloat(t) -> (MOVFload ptr mem)
+(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)
+
+// 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 ->
+ (MOVHstore ptr (MOVVconst [0]) mem)
+(Zero [s] ptr mem) && SizeAndAlign(s).Size() == 2 ->
+ (MOVBstore [1] ptr (MOVVconst [0])
+ (MOVBstore [0] ptr (MOVVconst [0]) mem))
+(Zero [s] ptr mem) && SizeAndAlign(s).Size() == 4 && SizeAndAlign(s).Align()%4 == 0 ->
+ (MOVWstore ptr (MOVVconst [0]) mem)
+(Zero [s] ptr mem) && SizeAndAlign(s).Size() == 4 && SizeAndAlign(s).Align()%2 == 0 ->
+ (MOVHstore [2] ptr (MOVVconst [0])
+ (MOVHstore [0] ptr (MOVVconst [0]) mem))
+(Zero [s] ptr mem) && SizeAndAlign(s).Size() == 4 ->
+ (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 ->
+ (MOVVstore ptr (MOVVconst [0]) mem)
+(Zero [s] ptr mem) && SizeAndAlign(s).Size() == 8 && SizeAndAlign(s).Align()%4 == 0 ->
+ (MOVWstore [4] ptr (MOVVconst [0])
+ (MOVWstore [0] ptr (MOVVconst [0]) mem))
+(Zero [s] ptr mem) && SizeAndAlign(s).Size() == 4 ->
+ (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 ->
+ (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 ->
+ (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 ->
+ (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 ->
+ (MOVVstore [8] ptr (MOVVconst [0])
+ (MOVVstore [0] ptr (MOVVconst [0]) mem))
+(Zero [s] ptr mem) && SizeAndAlign(s).Size() == 24 && SizeAndAlign(s).Align()%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)
+
+// 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()]
+ ptr
+ (ADDVconst <ptr.Type> ptr [SizeAndAlign(s).Size()-moveSize(SizeAndAlign(s).Align(), 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 ->
+ (MOVHstore dst (MOVHload src mem) mem)
+(Move [s] dst src mem) && SizeAndAlign(s).Size() == 2 ->
+ (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 ->
+ (MOVWstore dst (MOVWload src mem) mem)
+(Move [s] dst src mem) && SizeAndAlign(s).Size() == 4 && SizeAndAlign(s).Align()%2 == 0 ->
+ (MOVHstore [2] dst (MOVHload [2] src mem)
+ (MOVHstore dst (MOVHload src mem) mem))
+(Move [s] dst src mem) && SizeAndAlign(s).Size() == 4 ->
+ (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 ->
+ (MOVVstore dst (MOVVload src mem) mem)
+(Move [s] dst src mem) && SizeAndAlign(s).Size() == 8 && SizeAndAlign(s).Align()%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 ->
+ (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 ->
+ (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 ->
+ (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 ->
+ (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 ->
+ (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 ->
+ (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()]
+ dst
+ src
+ (ADDVconst <src.Type> src [SizeAndAlign(s).Size()-moveSize(SizeAndAlign(s).Align(), 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
+(NilCheck ptr mem) -> (LoweredNilCheck ptr mem)
+(IsNonNil ptr) -> (SGTU ptr (MOVVconst [0]))
+(IsInBounds idx len) -> (SGTU len idx)
+(IsSliceInBounds idx len) -> (XOR (MOVVconst [1]) (SGTU idx len))
+
+// pseudo-ops
+(GetClosurePtr) -> (LoweredGetClosurePtr)
+(Convert x mem) -> (MOVVconvert x mem)
+
+(If cond yes no) -> (NE cond yes no)
+
+// Optimizations
+
+// Absorb boolean tests into block
+(NE (FPFlagTrue cmp) yes no) -> (FPT cmp yes no)
+(NE (FPFlagFalse cmp) yes no) -> (FPF cmp yes no)
+(EQ (FPFlagTrue cmp) yes no) -> (FPF cmp yes no)
+(EQ (FPFlagFalse cmp) yes no) -> (FPT cmp yes no)
+(NE (XORconst [1] cmp:(SGT _ _)) yes no) -> (EQ cmp yes no)
+(NE (XORconst [1] cmp:(SGTU _ _)) yes no) -> (EQ cmp yes no)
+(NE (XORconst [1] cmp:(SGTconst _)) yes no) -> (EQ cmp yes no)
+(NE (XORconst [1] cmp:(SGTUconst _)) yes no) -> (EQ cmp yes no)
+(EQ (XORconst [1] cmp:(SGT _ _)) yes no) -> (NE cmp yes no)
+(EQ (XORconst [1] cmp:(SGTU _ _)) yes no) -> (NE cmp yes no)
+(EQ (XORconst [1] cmp:(SGTconst _)) yes no) -> (NE cmp yes no)
+(EQ (XORconst [1] cmp:(SGTUconst _)) yes no) -> (NE cmp yes no)
+(NE (SGTUconst [1] x) yes no) -> (EQ x yes no)
+(EQ (SGTUconst [1] x) yes no) -> (NE x yes no)
+(NE (SGTU x (MOVVconst [0])) yes no) -> (NE x yes no)
+(EQ (SGTU x (MOVVconst [0])) yes no) -> (EQ x yes no)
+(NE (SGTconst [0] x) yes no) -> (LTZ x yes no)
+(EQ (SGTconst [0] x) yes no) -> (GEZ x yes no)
+(NE (SGT x (MOVVconst [0])) yes no) -> (GTZ x yes no)
+(EQ (SGT x (MOVVconst [0])) yes no) -> (LEZ x yes no)
+
+// fold offset into address
+(ADDVconst [off1] (MOVVaddr [off2] {sym} ptr)) -> (MOVVaddr [off1+off2] {sym} ptr)
+
+// fold address into load/store
+(MOVBload [off1] {sym} (ADDVconst [off2] ptr) mem) && is32Bit(off1+off2) -> (MOVBload [off1+off2] {sym} ptr mem)
+(MOVBUload [off1] {sym} (ADDVconst [off2] ptr) mem) && is32Bit(off1+off2) -> (MOVBUload [off1+off2] {sym} ptr mem)
+(MOVHload [off1] {sym} (ADDVconst [off2] ptr) mem) && is32Bit(off1+off2) -> (MOVHload [off1+off2] {sym} ptr mem)
+(MOVHUload [off1] {sym} (ADDVconst [off2] ptr) mem) && is32Bit(off1+off2) -> (MOVHUload [off1+off2] {sym} ptr mem)
+(MOVWload [off1] {sym} (ADDVconst [off2] ptr) mem) && is32Bit(off1+off2) -> (MOVWload [off1+off2] {sym} ptr mem)
+(MOVWUload [off1] {sym} (ADDVconst [off2] ptr) mem) && is32Bit(off1+off2) -> (MOVWUload [off1+off2] {sym} ptr mem)
+(MOVVload [off1] {sym} (ADDVconst [off2] ptr) mem) && is32Bit(off1+off2) -> (MOVVload [off1+off2] {sym} ptr mem)
+(MOVFload [off1] {sym} (ADDVconst [off2] ptr) mem) && is32Bit(off1+off2) -> (MOVFload [off1+off2] {sym} ptr mem)
+(MOVDload [off1] {sym} (ADDVconst [off2] ptr) mem) && is32Bit(off1+off2) -> (MOVDload [off1+off2] {sym} ptr mem)
+
+(MOVBstore [off1] {sym} (ADDVconst [off2] ptr) val mem) && is32Bit(off1+off2) -> (MOVBstore [off1+off2] {sym} ptr val mem)
+(MOVHstore [off1] {sym} (ADDVconst [off2] ptr) val mem) && is32Bit(off1+off2) -> (MOVHstore [off1+off2] {sym} ptr val mem)
+(MOVWstore [off1] {sym} (ADDVconst [off2] ptr) val mem) && is32Bit(off1+off2) -> (MOVWstore [off1+off2] {sym} ptr val mem)
+(MOVVstore [off1] {sym} (ADDVconst [off2] ptr) val mem) && is32Bit(off1+off2) -> (MOVVstore [off1+off2] {sym} ptr val mem)
+(MOVFstore [off1] {sym} (ADDVconst [off2] ptr) val mem) && is32Bit(off1+off2) -> (MOVFstore [off1+off2] {sym} ptr val mem)
+(MOVDstore [off1] {sym} (ADDVconst [off2] ptr) val mem) && is32Bit(off1+off2) -> (MOVDstore [off1+off2] {sym} ptr val mem)
+(MOVBstorezero [off1] {sym} (ADDVconst [off2] ptr) mem) && is32Bit(off1+off2) -> (MOVBstorezero [off1+off2] {sym} ptr mem)
+(MOVHstorezero [off1] {sym} (ADDVconst [off2] ptr) mem) && is32Bit(off1+off2) -> (MOVHstorezero [off1+off2] {sym} ptr mem)
+(MOVWstorezero [off1] {sym} (ADDVconst [off2] ptr) mem) && is32Bit(off1+off2) -> (MOVWstorezero [off1+off2] {sym} ptr mem)
+(MOVVstorezero [off1] {sym} (ADDVconst [off2] ptr) mem) && is32Bit(off1+off2) -> (MOVVstorezero [off1+off2] {sym} ptr mem)
+
+(MOVBload [off1] {sym1} (MOVVaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) && is32Bit(off1+off2) ->
+ (MOVBload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
+(MOVBUload [off1] {sym1} (MOVVaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) && is32Bit(off1+off2) ->
+ (MOVBUload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
+(MOVHload [off1] {sym1} (MOVVaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) && is32Bit(off1+off2) ->
+ (MOVHload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
+(MOVHUload [off1] {sym1} (MOVVaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) && is32Bit(off1+off2) ->
+ (MOVHUload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
+(MOVWload [off1] {sym1} (MOVVaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) && is32Bit(off1+off2) ->
+ (MOVWload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
+(MOVWUload [off1] {sym1} (MOVVaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) && is32Bit(off1+off2) ->
+ (MOVWUload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
+(MOVVload [off1] {sym1} (MOVVaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) && is32Bit(off1+off2) ->
+ (MOVVload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
+(MOVFload [off1] {sym1} (MOVVaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) && is32Bit(off1+off2) ->
+ (MOVFload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
+(MOVDload [off1] {sym1} (MOVVaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) && is32Bit(off1+off2) ->
+ (MOVDload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
+
+(MOVBstore [off1] {sym1} (MOVVaddr [off2] {sym2} ptr) val mem) && canMergeSym(sym1,sym2) && is32Bit(off1+off2) ->
+ (MOVBstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
+(MOVHstore [off1] {sym1} (MOVVaddr [off2] {sym2} ptr) val mem) && canMergeSym(sym1,sym2) && is32Bit(off1+off2) ->
+ (MOVHstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
+(MOVWstore [off1] {sym1} (MOVVaddr [off2] {sym2} ptr) val mem) && canMergeSym(sym1,sym2) && is32Bit(off1+off2) ->
+ (MOVWstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
+(MOVVstore [off1] {sym1} (MOVVaddr [off2] {sym2} ptr) val mem) && canMergeSym(sym1,sym2) && is32Bit(off1+off2) ->
+ (MOVVstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
+(MOVFstore [off1] {sym1} (MOVVaddr [off2] {sym2} ptr) val mem) && canMergeSym(sym1,sym2) && is32Bit(off1+off2) ->
+ (MOVFstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
+(MOVDstore [off1] {sym1} (MOVVaddr [off2] {sym2} ptr) val mem) && canMergeSym(sym1,sym2) && is32Bit(off1+off2) ->
+ (MOVDstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
+(MOVBstorezero [off1] {sym1} (MOVVaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) && is32Bit(off1+off2) ->
+ (MOVBstorezero [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
+(MOVHstorezero [off1] {sym1} (MOVVaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) && is32Bit(off1+off2) ->
+ (MOVHstorezero [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
+(MOVWstorezero [off1] {sym1} (MOVVaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) && is32Bit(off1+off2) ->
+ (MOVWstorezero [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
+(MOVVstorezero [off1] {sym1} (MOVVaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) && is32Bit(off1+off2) ->
+ (MOVVstorezero [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
+
+// store zero
+(MOVBstore [off] {sym} ptr (MOVVconst [0]) mem) -> (MOVBstorezero [off] {sym} ptr mem)
+(MOVHstore [off] {sym} ptr (MOVVconst [0]) mem) -> (MOVHstorezero [off] {sym} ptr mem)
+(MOVWstore [off] {sym} ptr (MOVVconst [0]) mem) -> (MOVWstorezero [off] {sym} ptr mem)
+(MOVVstore [off] {sym} ptr (MOVVconst [0]) mem) -> (MOVVstorezero [off] {sym} ptr mem)
+
+// don't extend after proper load
+(MOVBreg x:(MOVBload _ _)) -> (MOVVreg x)
+(MOVBUreg x:(MOVBUload _ _)) -> (MOVVreg x)
+(MOVHreg x:(MOVBload _ _)) -> (MOVVreg x)
+(MOVHreg x:(MOVBUload _ _)) -> (MOVVreg x)
+(MOVHreg x:(MOVHload _ _)) -> (MOVVreg x)
+(MOVHUreg x:(MOVBUload _ _)) -> (MOVVreg x)
+(MOVHUreg x:(MOVHUload _ _)) -> (MOVVreg x)
+(MOVWreg x:(MOVBload _ _)) -> (MOVVreg x)
+(MOVWreg x:(MOVBUload _ _)) -> (MOVVreg x)
+(MOVWreg x:(MOVHload _ _)) -> (MOVVreg x)
+(MOVWreg x:(MOVHUload _ _)) -> (MOVVreg x)
+(MOVWreg x:(MOVWload _ _)) -> (MOVVreg x)
+(MOVWUreg x:(MOVBUload _ _)) -> (MOVVreg x)
+(MOVWUreg x:(MOVHUload _ _)) -> (MOVVreg x)
+(MOVWUreg x:(MOVWUload _ _)) -> (MOVVreg x)
+
+// fold double extensions
+(MOVBreg x:(MOVBreg _)) -> (MOVVreg x)
+(MOVBUreg x:(MOVBUreg _)) -> (MOVVreg x)
+(MOVHreg x:(MOVBreg _)) -> (MOVVreg x)
+(MOVHreg x:(MOVBUreg _)) -> (MOVVreg x)
+(MOVHreg x:(MOVHreg _)) -> (MOVVreg x)
+(MOVHUreg x:(MOVBUreg _)) -> (MOVVreg x)
+(MOVHUreg x:(MOVHUreg _)) -> (MOVVreg x)
+(MOVWreg x:(MOVBreg _)) -> (MOVVreg x)
+(MOVWreg x:(MOVBUreg _)) -> (MOVVreg x)
+(MOVWreg x:(MOVHreg _)) -> (MOVVreg x)
+(MOVWreg x:(MOVHreg _)) -> (MOVVreg x)
+(MOVWreg x:(MOVWreg _)) -> (MOVVreg x)
+(MOVWUreg x:(MOVBUreg _)) -> (MOVVreg x)
+(MOVWUreg x:(MOVHUreg _)) -> (MOVVreg x)
+(MOVWUreg x:(MOVWUreg _)) -> (MOVVreg x)
+
+// don't extend before store
+(MOVBstore [off] {sym} ptr (MOVBreg x) mem) -> (MOVBstore [off] {sym} ptr x mem)
+(MOVBstore [off] {sym} ptr (MOVBUreg x) mem) -> (MOVBstore [off] {sym} ptr x mem)
+(MOVBstore [off] {sym} ptr (MOVHreg x) mem) -> (MOVBstore [off] {sym} ptr x mem)
+(MOVBstore [off] {sym} ptr (MOVHUreg x) mem) -> (MOVBstore [off] {sym} ptr x mem)
+(MOVBstore [off] {sym} ptr (MOVWreg x) mem) -> (MOVBstore [off] {sym} ptr x mem)
+(MOVBstore [off] {sym} ptr (MOVWUreg x) mem) -> (MOVBstore [off] {sym} ptr x mem)
+(MOVHstore [off] {sym} ptr (MOVHreg x) mem) -> (MOVHstore [off] {sym} ptr x mem)
+(MOVHstore [off] {sym} ptr (MOVHUreg x) mem) -> (MOVHstore [off] {sym} ptr x mem)
+(MOVHstore [off] {sym} ptr (MOVWreg x) mem) -> (MOVHstore [off] {sym} ptr x mem)
+(MOVHstore [off] {sym} ptr (MOVWUreg x) mem) -> (MOVHstore [off] {sym} ptr x mem)
+(MOVWstore [off] {sym} ptr (MOVWreg x) mem) -> (MOVWstore [off] {sym} ptr x mem)
+(MOVWstore [off] {sym} ptr (MOVWUreg x) mem) -> (MOVWstore [off] {sym} ptr x mem)
+
+// if a register move has only 1 use, just use the same register without emitting instruction
+// MOVVnop doesn't emit instruction, only for ensuring the type.
+(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])
+(SRLV _ (MOVVconst [c])) && uint64(c)>=64 -> (MOVVconst [0])
+(SRAV x (MOVVconst [c])) && uint64(c)>=64 -> (SRAVconst x [63])
+(SLLV x (MOVVconst [c])) -> (SLLVconst x [c])
+(SRLV x (MOVVconst [c])) -> (SRLVconst x [c])
+(SRAV x (MOVVconst [c])) -> (SRAVconst x [c])
+
+(SGT (MOVVconst [c]) x) && is32Bit(c) -> (SGTconst [c] x)
+(SGTU (MOVVconst [c]) x) && is32Bit(c) -> (SGTUconst [c] x)
+
+// mul by constant
+(Select1 (MULVU x (MOVVconst [-1]))) -> (NEGV x)
+(Select1 (MULVU _ (MOVVconst [0]))) -> (MOVVconst [0])
+(Select1 (MULVU x (MOVVconst [1]))) -> x
+(Select1 (MULVU x (MOVVconst [c]))) && isPowerOfTwo(c) -> (SLLVconst [log2(c)] x)
+
+(Select1 (MULVU (MOVVconst [-1]) x)) -> (NEGV x)
+(Select1 (MULVU (MOVVconst [0]) _)) -> (MOVVconst [0])
+(Select1 (MULVU (MOVVconst [1]) x)) -> x
+(Select1 (MULVU (MOVVconst [c]) x)) && isPowerOfTwo(c) -> (SLLVconst [log2(c)] x)
+
+// div by constant
+(Select1 (DIVVU x (MOVVconst [1]))) -> x
+(Select1 (DIVVU x (MOVVconst [c]))) && isPowerOfTwo(c) -> (SRLVconst [log2(c)] x)
+(Select0 (DIVVU _ (MOVVconst [1]))) -> (MOVVconst [0]) // mod
+(Select0 (DIVVU x (MOVVconst [c]))) && isPowerOfTwo(c) -> (ANDconst [c-1] x) // mod
+
+// 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
+(OR x x) -> x
+(XOR x x) -> (MOVVconst [0])
+
+// remove redundant *const ops
+(ADDVconst [0] x) -> x
+(SUBVconst [0] x) -> x
+(ANDconst [0] _) -> (MOVVconst [0])
+(ANDconst [-1] x) -> x
+(ORconst [0] x) -> x
+(ORconst [-1] _) -> (MOVVconst [-1])
+(XORconst [0] x) -> x
+(XORconst [-1] x) -> (NORconst [0] x)
+
+// generic constant folding
+(ADDVconst [c] (MOVVconst [d])) -> (MOVVconst [c+d])
+(ADDVconst [c] (ADDVconst [d] x)) && is32Bit(c+d) -> (ADDVconst [c+d] x)
+(ADDVconst [c] (SUBVconst [d] x)) && is32Bit(c-d) -> (ADDVconst [c-d] x)
+(SUBVconst [c] (MOVVconst [d])) -> (MOVVconst [d-c])
+(SUBVconst [c] (SUBVconst [d] x)) && is32Bit(-c-d) -> (ADDVconst [-c-d] x)
+(SUBVconst [c] (ADDVconst [d] x)) && is32Bit(-c+d) -> (ADDVconst [-c+d] x)
+(SLLVconst [c] (MOVVconst [d])) -> (MOVVconst [int64(d)<<uint64(c)])
+(SRLVconst [c] (MOVVconst [d])) -> (MOVVconst [int64(uint64(d)>>uint64(c))])
+(SRAVconst [c] (MOVVconst [d])) -> (MOVVconst [int64(d)>>uint64(c)])
+(Select1 (MULVU (MOVVconst [c]) (MOVVconst [d]))) -> (MOVVconst [c*d])
+(Select1 (DIVV (MOVVconst [c]) (MOVVconst [d]))) -> (MOVVconst [int64(c)/int64(d)])
+(Select1 (DIVVU (MOVVconst [c]) (MOVVconst [d]))) -> (MOVVconst [int64(uint64(c)/uint64(d))])
+(Select0 (DIVV (MOVVconst [c]) (MOVVconst [d]))) -> (MOVVconst [int64(c)%int64(d)]) // mod
+(Select0 (DIVVU (MOVVconst [c]) (MOVVconst [d]))) -> (MOVVconst [int64(uint64(c)%uint64(d))]) // mod
+(ANDconst [c] (MOVVconst [d])) -> (MOVVconst [c&d])
+(ANDconst [c] (ANDconst [d] x)) -> (ANDconst [c&d] x)
+(ORconst [c] (MOVVconst [d])) -> (MOVVconst [c|d])
+(ORconst [c] (ORconst [d] x)) && is32Bit(c|d) -> (ORconst [c|d] x)
+(XORconst [c] (MOVVconst [d])) -> (MOVVconst [c^d])
+(XORconst [c] (XORconst [d] x)) && is32Bit(c^d) -> (XORconst [c^d] x)
+(NORconst [c] (MOVVconst [d])) -> (MOVVconst [^(c|d)])
+(NEGV (MOVVconst [c])) -> (MOVVconst [-c])
+(MOVBreg (MOVVconst [c])) -> (MOVVconst [int64(int8(c))])
+(MOVBUreg (MOVVconst [c])) -> (MOVVconst [int64(uint8(c))])
+(MOVHreg (MOVVconst [c])) -> (MOVVconst [int64(int16(c))])
+(MOVHUreg (MOVVconst [c])) -> (MOVVconst [int64(uint16(c))])
+(MOVWreg (MOVVconst [c])) -> (MOVVconst [int64(int32(c))])
+(MOVWUreg (MOVVconst [c])) -> (MOVVconst [int64(uint32(c))])
+(MOVVreg (MOVVconst [c])) -> (MOVVconst [c])
+
+// constant comparisons
+(SGTconst [c] (MOVVconst [d])) && int64(c)>int64(d) -> (MOVVconst [1])
+(SGTconst [c] (MOVVconst [d])) && int64(c)<=int64(d) -> (MOVVconst [0])
+(SGTUconst [c] (MOVVconst [d])) && uint64(c)>uint64(d) -> (MOVVconst [1])
+(SGTUconst [c] (MOVVconst [d])) && uint64(c)<=uint64(d) -> (MOVVconst [0])
+
+// other known comparisons
+(SGTconst [c] (MOVBreg _)) && 0x7f < int64(c) -> (MOVVconst [1])
+(SGTconst [c] (MOVBreg _)) && int64(c) <= -0x80 -> (MOVVconst [0])
+(SGTconst [c] (MOVBUreg _)) && 0xff < int64(c) -> (MOVVconst [1])
+(SGTconst [c] (MOVBUreg _)) && int64(c) < 0 -> (MOVVconst [0])
+(SGTUconst [c] (MOVBUreg _)) && 0xff < uint64(c) -> (MOVVconst [1])
+(SGTconst [c] (MOVHreg _)) && 0x7fff < int64(c) -> (MOVVconst [1])
+(SGTconst [c] (MOVHreg _)) && int64(c) <= -0x8000 -> (MOVVconst [0])
+(SGTconst [c] (MOVHUreg _)) && 0xffff < int64(c) -> (MOVVconst [1])
+(SGTconst [c] (MOVHUreg _)) && int64(c) < 0 -> (MOVVconst [0])
+(SGTUconst [c] (MOVHUreg _)) && 0xffff < uint64(c) -> (MOVVconst [1])
+(SGTconst [c] (MOVWUreg _)) && int64(c) < 0 -> (MOVVconst [0])
+(SGTconst [c] (ANDconst [m] _)) && 0 <= m && m < c -> (MOVVconst [1])
+(SGTUconst [c] (ANDconst [m] _)) && uint64(m) < uint64(c) -> (MOVVconst [1])
+(SGTconst [c] (SRLVconst _ [d])) && 0 <= c && 0 < d && d <= 63 && 1<<uint64(64-d) <= c -> (MOVVconst [1])
+(SGTUconst [c] (SRLVconst _ [d])) && 0 < d && d <= 63 && 1<<uint64(64-d) <= uint64(c) -> (MOVVconst [1])
+
+// absorb constants into branches
+(EQ (MOVVconst [0]) yes no) -> (First nil yes no)
+(EQ (MOVVconst [c]) yes no) && c != 0 -> (First nil no yes)
+(NE (MOVVconst [0]) yes no) -> (First nil no yes)
+(NE (MOVVconst [c]) yes no) && c != 0 -> (First nil yes no)
+(LTZ (MOVVconst [c]) yes no) && c < 0 -> (First nil yes no)
+(LTZ (MOVVconst [c]) yes no) && c >= 0 -> (First nil no yes)
+(LEZ (MOVVconst [c]) yes no) && c <= 0 -> (First nil yes no)
+(LEZ (MOVVconst [c]) yes no) && c > 0 -> (First nil no yes)
+(GTZ (MOVVconst [c]) yes no) && c > 0 -> (First nil yes no)
+(GTZ (MOVVconst [c]) yes no) && c <= 0 -> (First nil no yes)
+(GEZ (MOVVconst [c]) yes no) && c >= 0 -> (First nil yes no)
+(GEZ (MOVVconst [c]) yes no) && c < 0 -> (First nil no yes)
diff --git a/src/cmd/compile/internal/ssa/gen/MIPS64Ops.go b/src/cmd/compile/internal/ssa/gen/MIPS64Ops.go
new file mode 100644
index 0000000..d7d7fec
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/gen/MIPS64Ops.go
@@ -0,0 +1,381 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build ignore
+
+package main
+
+import "strings"
+
+// Notes:
+// - Integer types live in the low portion of registers. Upper portions are junk.
+// - Boolean types use the low-order byte of a register. 0=false, 1=true.
+// Upper bytes are junk.
+// - *const instructions may use a constant larger than the instuction can encode.
+// In this case the assembler expands to multiple instructions and uses tmp
+// register (R23).
+
+// Suffixes encode the bit width of various instructions.
+// V (vlong) = 64 bit
+// WU (word) = 32 bit unsigned
+// W (word) = 32 bit
+// H (half word) = 16 bit
+// HU = 16 bit unsigned
+// B (byte) = 8 bit
+// BU = 8 bit unsigned
+// F (float) = 32 bit float
+// D (double) = 64 bit float
+
+// Note: registers not used in regalloc are not included in this list,
+// so that regmask stays within int64
+// Be careful when hand coding regmasks.
+var regNamesMIPS64 = []string{
+ "R0", // constant 0
+ "R1",
+ "R2",
+ "R3",
+ "R4",
+ "R5",
+ "R6",
+ "R7",
+ "R8",
+ "R9",
+ "R10",
+ "R11",
+ "R12",
+ "R13",
+ "R14",
+ "R15",
+ "R16",
+ "R17",
+ "R18",
+ "R19",
+ "R20",
+ "R21",
+ "R22",
+ // R23 = REGTMP not used in regalloc
+ "R24",
+ "R25",
+ // R26 reserved by kernel
+ // R27 reserved by kernel
+ // R28 = REGSB not used in regalloc
+ "SP", // aka R29
+ "g", // aka R30
+ "R31", // aka REGLINK
+
+ "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", // high bits of multiplication
+ "LO", // low bits of multiplication
+
+ // pseudo-registers
+ "SB",
+}
+
+func init() {
+ // Make map from reg names to reg integers.
+ if len(regNamesMIPS64) > 64 {
+ panic("too many registers")
+ }
+ num := map[string]int{}
+ for i, name := range regNamesMIPS64 {
+ num[name] = i
+ }
+ buildReg := func(s string) regMask {
+ m := regMask(0)
+ for _, r := range strings.Split(s, " ") {
+ if n, ok := num[r]; ok {
+ m |= regMask(1) << uint(n)
+ continue
+ }
+ panic("register " + r + " not found")
+ }
+ return m
+ }
+
+ // Common individual register masks
+ var (
+ gp = buildReg("R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R22 R24 R25 R31")
+ gpg = gp | buildReg("g")
+ gpsp = gp | buildReg("SP")
+ gpspg = gpg | buildReg("SP")
+ gpspsbg = gpspg | buildReg("SB")
+ fp = buildReg("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")
+ lo = buildReg("LO")
+ hi = buildReg("HI")
+ callerSave = gp | fp | lo | hi | buildReg("g") // runtime.setg (and anything calling it) may clobber g
+ )
+ // Common regInfo
+ var (
+ gp01 = regInfo{inputs: nil, outputs: []regMask{gp}}
+ gp11 = regInfo{inputs: []regMask{gpg}, outputs: []regMask{gp}}
+ gp11sp = regInfo{inputs: []regMask{gpspg}, outputs: []regMask{gp}}
+ gp21 = regInfo{inputs: []regMask{gpg, gpg}, outputs: []regMask{gp}}
+ gp2hilo = regInfo{inputs: []regMask{gpg, gpg}, outputs: []regMask{hi, lo}}
+ gpload = regInfo{inputs: []regMask{gpspsbg}, outputs: []regMask{gp}}
+ gpstore = regInfo{inputs: []regMask{gpspsbg, gpg}}
+ gpstore0 = regInfo{inputs: []regMask{gpspsbg}}
+ fp01 = regInfo{inputs: nil, outputs: []regMask{fp}}
+ fp11 = regInfo{inputs: []regMask{fp}, outputs: []regMask{fp}}
+ //fp1flags = regInfo{inputs: []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}}
+ fp2flags = regInfo{inputs: []regMask{fp, fp}}
+ fpload = regInfo{inputs: []regMask{gpspsbg}, outputs: []regMask{fp}}
+ fpstore = regInfo{inputs: []regMask{gpspsbg, fp}}
+ readflags = regInfo{inputs: nil, outputs: []regMask{gp}}
+ )
+ ops := []opData{
+ // binary ops
+ {name: "ADDV", argLength: 2, reg: gp21, asm: "ADDVU", commutative: true}, // arg0 + arg1
+ {name: "ADDVconst", argLength: 1, reg: gp11sp, asm: "ADDVU", aux: "Int64"}, // arg0 + auxInt
+ {name: "SUBV", argLength: 2, reg: gp21, asm: "SUBVU"}, // arg0 - arg1
+ {name: "SUBVconst", argLength: 1, reg: gp11, asm: "SUBVU", aux: "Int64"}, // arg0 - auxInt
+ {name: "MULV", argLength: 2, reg: gp2hilo, asm: "MULV", commutative: true, typ: "(Int64,Int64)"}, // arg0 * arg1, signed, results hi,lo
+ {name: "MULVU", argLength: 2, reg: gp2hilo, asm: "MULVU", commutative: true, typ: "(UInt64,UInt64)"}, // arg0 * arg1, unsigned, results hi,lo
+ {name: "DIVV", argLength: 2, reg: gp2hilo, asm: "DIVV", typ: "(Int64,Int64)"}, // arg0 / arg1, signed, results hi=arg0%arg1,lo=arg0/arg1
+ {name: "DIVVU", argLength: 2, reg: gp2hilo, asm: "DIVVU", typ: "(UInt64,UInt64)"}, // arg0 / arg1, signed, results hi=arg0%arg1,lo=arg0/arg1
+
+ {name: "ADDF", argLength: 2, reg: fp21, asm: "ADDF", commutative: true}, // arg0 + arg1
+ {name: "ADDD", argLength: 2, reg: fp21, asm: "ADDD", commutative: true}, // arg0 + arg1
+ {name: "SUBF", argLength: 2, reg: fp21, asm: "SUBF"}, // arg0 - arg1
+ {name: "SUBD", argLength: 2, reg: fp21, asm: "SUBD"}, // arg0 - arg1
+ {name: "MULF", argLength: 2, reg: fp21, asm: "MULF", commutative: true}, // arg0 * arg1
+ {name: "MULD", argLength: 2, reg: fp21, asm: "MULD", commutative: true}, // arg0 * arg1
+ {name: "DIVF", argLength: 2, reg: fp21, asm: "DIVF"}, // arg0 / arg1
+ {name: "DIVD", argLength: 2, reg: fp21, asm: "DIVD"}, // arg0 / arg1
+
+ {name: "AND", argLength: 2, reg: gp21, asm: "AND", commutative: true}, // arg0 & arg1
+ {name: "ANDconst", argLength: 1, reg: gp11, asm: "AND", aux: "Int64"}, // arg0 & auxInt
+ {name: "OR", argLength: 2, reg: gp21, asm: "OR", commutative: true}, // arg0 | arg1
+ {name: "ORconst", argLength: 1, reg: gp11, asm: "OR", aux: "Int64"}, // arg0 | auxInt
+ {name: "XOR", argLength: 2, reg: gp21, asm: "XOR", commutative: true, typ: "UInt64"}, // arg0 ^ arg1
+ {name: "XORconst", argLength: 1, reg: gp11, asm: "XOR", aux: "Int64", typ: "UInt64"}, // arg0 ^ auxInt
+ {name: "NOR", argLength: 2, reg: gp21, asm: "NOR", commutative: true}, // ^(arg0 | arg1)
+ {name: "NORconst", argLength: 1, reg: gp11, asm: "NOR", aux: "Int64"}, // ^(arg0 | auxInt)
+
+ {name: "NEGV", argLength: 1, reg: gp11}, // -arg0
+ {name: "NEGF", argLength: 1, reg: fp11, asm: "NEGF"}, // -arg0, float32
+ {name: "NEGD", argLength: 1, reg: fp11, asm: "NEGD"}, // -arg0, float64
+
+ // shifts
+ {name: "SLLV", argLength: 2, reg: gp21, asm: "SLLV"}, // arg0 << arg1, shift amount is mod 64
+ {name: "SLLVconst", argLength: 1, reg: gp11, asm: "SLLV", aux: "Int64"}, // arg0 << auxInt
+ {name: "SRLV", argLength: 2, reg: gp21, asm: "SRLV"}, // arg0 >> arg1, unsigned, shift amount is mod 64
+ {name: "SRLVconst", argLength: 1, reg: gp11, asm: "SRLV", aux: "Int64"}, // arg0 >> auxInt, unsigned
+ {name: "SRAV", argLength: 2, reg: gp21, asm: "SRAV"}, // arg0 >> arg1, signed, shift amount is mod 64
+ {name: "SRAVconst", argLength: 1, reg: gp11, asm: "SRAV", aux: "Int64"}, // arg0 >> auxInt, signed
+
+ // comparisons
+ {name: "SGT", argLength: 2, reg: gp21, asm: "SGT", typ: "Bool"}, // 1 if arg0 > arg1 (signed), 0 otherwise
+ {name: "SGTconst", argLength: 1, reg: gp11, asm: "SGT", aux: "Int64", typ: "Bool"}, // 1 if auxInt > arg0 (signed), 0 otherwise
+ {name: "SGTU", argLength: 2, reg: gp21, asm: "SGTU", typ: "Bool"}, // 1 if arg0 > arg1 (unsigned), 0 otherwise
+ {name: "SGTUconst", argLength: 1, reg: gp11, asm: "SGTU", aux: "Int64", typ: "Bool"}, // 1 if auxInt > arg0 (unsigned), 0 otherwise
+
+ {name: "CMPEQF", argLength: 2, reg: fp2flags, asm: "CMPEQF", typ: "Flags"}, // flags=true if arg0 = arg1, float32
+ {name: "CMPEQD", argLength: 2, reg: fp2flags, asm: "CMPEQD", typ: "Flags"}, // flags=true if arg0 = arg1, float64
+ {name: "CMPGEF", argLength: 2, reg: fp2flags, asm: "CMPGEF", typ: "Flags"}, // flags=true if arg0 >= arg1, float32
+ {name: "CMPGED", argLength: 2, reg: fp2flags, asm: "CMPGED", typ: "Flags"}, // flags=true if arg0 >= arg1, float64
+ {name: "CMPGTF", argLength: 2, reg: fp2flags, asm: "CMPGTF", typ: "Flags"}, // flags=true if arg0 > arg1, float32
+ {name: "CMPGTD", argLength: 2, reg: fp2flags, asm: "CMPGTD", typ: "Flags"}, // flags=true if arg0 > arg1, float64
+
+ // moves
+ {name: "MOVVconst", argLength: 0, reg: gp01, aux: "Int64", asm: "MOVV", typ: "UInt64", rematerializeable: true}, // auxint
+ {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.
+
+ // conversions
+ {name: "MOVBreg", argLength: 1, reg: gp11, asm: "MOVB"}, // move from arg0, sign-extended from byte
+ {name: "MOVBUreg", argLength: 1, reg: gp11, asm: "MOVBU"}, // move from arg0, unsign-extended from byte
+ {name: "MOVHreg", argLength: 1, reg: gp11, asm: "MOVH"}, // move from arg0, sign-extended from half
+ {name: "MOVHUreg", argLength: 1, reg: gp11, asm: "MOVHU"}, // move from arg0, unsign-extended from half
+ {name: "MOVWreg", argLength: 1, reg: gp11, asm: "MOVW"}, // move from arg0, sign-extended from word
+ {name: "MOVWUreg", argLength: 1, reg: gp11, asm: "MOVWU"}, // move from arg0, unsign-extended from word
+ {name: "MOVVreg", argLength: 1, reg: gp11, asm: "MOVV"}, // move from arg0
+
+ {name: "MOVVnop", argLength: 1, reg: regInfo{inputs: []regMask{gp}, outputs: []regMask{gp}}, resultInArg0: true}, // nop, return arg0 in same register
+
+ {name: "MOVWF", argLength: 1, reg: fp11, asm: "MOVWF"}, // int32 -> float32
+ {name: "MOVWD", argLength: 1, reg: fp11, asm: "MOVWD"}, // int32 -> float64
+ {name: "MOVVF", argLength: 1, reg: fp11, asm: "MOVVF"}, // int64 -> float32
+ {name: "MOVVD", argLength: 1, reg: fp11, asm: "MOVVD"}, // int64 -> float64
+ {name: "TRUNCFW", argLength: 1, reg: fp11, asm: "TRUNCFW"}, // float32 -> int32
+ {name: "TRUNCDW", argLength: 1, reg: fp11, asm: "TRUNCDW"}, // float64 -> int32
+ {name: "TRUNCFV", argLength: 1, reg: fp11, asm: "TRUNCFV"}, // float32 -> int64
+ {name: "TRUNCDV", argLength: 1, reg: fp11, asm: "TRUNCDV"}, // float64 -> int64
+ {name: "MOVFD", argLength: 1, reg: fp11, asm: "MOVFD"}, // float32 -> float64
+ {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: "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
+ // arg0 = address of memory to zero
+ // arg1 = mem
+ // auxint = offset into duffzero code to start executing
+ // returns mem
+ // R1 aka mips.REGRT1 changed as side effect
+ {
+ name: "DUFFZERO",
+ aux: "Int64",
+ argLength: 2,
+ reg: regInfo{
+ inputs: []regMask{gp},
+ clobbers: buildReg("R1 R31"),
+ },
+ faultOnNilArg0: true,
+ },
+
+ // large or unaligned zeroing
+ // arg0 = address of memory to zero (in R1, changed as side effect)
+ // arg1 = address of the last element to zero
+ // arg2 = mem
+ // auxint = alignment
+ // returns mem
+ // SUBV $8, R1
+ // MOVV R0, 8(R1)
+ // ADDV $8, R1
+ // BNE Rarg1, R1, -2(PC)
+ {
+ name: "LoweredZero",
+ aux: "Int64",
+ argLength: 3,
+ reg: regInfo{
+ inputs: []regMask{buildReg("R1"), gp},
+ clobbers: buildReg("R1"),
+ },
+ clobberFlags: true,
+ faultOnNilArg0: true,
+ },
+
+ // large or unaligned move
+ // arg0 = address of dst memory (in R2, changed as side effect)
+ // arg1 = address of src memory (in R1, changed as side effect)
+ // arg2 = address of the last element of src
+ // arg3 = mem
+ // auxint = alignment
+ // returns mem
+ // SUBV $8, R1
+ // MOVV 8(R1), Rtmp
+ // MOVV Rtmp, (R2)
+ // ADDV $8, R1
+ // ADDV $8, R2
+ // BNE Rarg2, R1, -4(PC)
+ {
+ name: "LoweredMove",
+ aux: "Int64",
+ argLength: 4,
+ reg: regInfo{
+ inputs: []regMask{buildReg("R2"), buildReg("R1"), gp},
+ clobbers: buildReg("R1 R2"),
+ },
+ clobberFlags: true,
+ faultOnNilArg0: true,
+ faultOnNilArg1: true,
+ },
+
+ // pseudo-ops
+ {name: "LoweredNilCheck", argLength: 2, reg: regInfo{inputs: []regMask{gpg}}, nilCheck: true, faultOnNilArg0: true}, // panic if arg0 is nil. arg1=mem.
+
+ {name: "FPFlagTrue", argLength: 1, reg: readflags}, // bool, true if FP flag is true
+ {name: "FPFlagFalse", argLength: 1, reg: readflags}, // bool, true if FP flag is false
+
+ // Scheduler ensures LoweredGetClosurePtr occurs only in entry block,
+ // and sorts it to the very beginning of the block to prevent other
+ // use of R22 (mips.REGCTXT, the closure pointer)
+ {name: "LoweredGetClosurePtr", reg: regInfo{outputs: []regMask{buildReg("R22")}}},
+
+ // MOVDconvert converts between pointers and integers.
+ // We have a special op for this so as to not confuse GC
+ // (particularly stack maps). It takes a memory arg so it
+ // gets correctly ordered with respect to GC safepoints.
+ // arg0=ptr/int arg1=mem, output=int/ptr
+ {name: "MOVVconvert", argLength: 2, reg: gp11, asm: "MOVV"},
+ }
+
+ blocks := []blockData{
+ {name: "EQ"},
+ {name: "NE"},
+ {name: "LTZ"}, // < 0
+ {name: "LEZ"}, // <= 0
+ {name: "GTZ"}, // > 0
+ {name: "GEZ"}, // >= 0
+ {name: "FPT"}, // FP flag is true
+ {name: "FPF"}, // FP flag is false
+ }
+
+ archs = append(archs, arch{
+ name: "MIPS64",
+ pkg: "cmd/internal/obj/mips",
+ genfile: "../../mips64/ssa.go",
+ ops: ops,
+ blocks: blocks,
+ regnames: regNamesMIPS64,
+ gpregmask: gp,
+ fpregmask: fp,
+ specialregmask: hi | lo,
+ framepointerreg: -1, // not used
+ linkreg: int8(num["R31"]),
+ })
+}
diff --git a/src/cmd/compile/internal/ssa/gen/MIPSOps.go b/src/cmd/compile/internal/ssa/gen/MIPSOps.go
new file mode 100644
index 0000000..c803c49
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/gen/MIPSOps.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.
+
+// +build ignore
+
+package main
+
+import "strings"
+
+// Notes:
+// - Integer types live in the low portion of registers. Upper portions are junk.
+// - Boolean types use the low-order byte of a register. 0=false, 1=true.
+// Upper bytes are junk.
+// - Unused portions of AuxInt are filled by sign-extending the used portion.
+// - *const instructions may use a constant larger than the instuction can encode.
+// In this case the assembler expands to multiple instructions and uses tmp
+// register (R23).
+
+// Suffixes encode the bit width of various instructions.
+// W (word) = 32 bit
+// H (half word) = 16 bit
+// HU = 16 bit unsigned
+// B (byte) = 8 bit
+// BU = 8 bit unsigned
+// F (float) = 32 bit float
+// D (double) = 64 bit float
+
+// Note: registers not used in regalloc are not included in this list,
+// so that regmask stays within int64
+// Be careful when hand coding regmasks.
+var regNamesMIPS = []string{
+ "R0", // constant 0
+ "R1",
+ "R2",
+ "R3",
+ "R4",
+ "R5",
+ "R6",
+ "R7",
+ "R8",
+ "R9",
+ "R10",
+ "R11",
+ "R12",
+ "R13",
+ "R14",
+ "R15",
+ "R16",
+ "R17",
+ "R18",
+ "R19",
+ "R20",
+ "R21",
+ "R22",
+ //REGTMP
+ "R24",
+ "R25",
+ // R26 reserved by kernel
+ // R27 reserved by kernel
+ "R28",
+ "SP", // aka R29
+ "g", // aka R30
+ "R31", // REGLINK
+
+ // odd FP registers contain high parts of 64-bit FP values
+ "F0",
+ "F2",
+ "F4",
+ "F6",
+ "F8",
+ "F10",
+ "F12",
+ "F14",
+ "F16",
+ "F18",
+ "F20",
+ "F22",
+ "F24",
+ "F26",
+ "F28",
+ "F30",
+
+ "HI", // high bits of multiplication
+ "LO", // low bits of multiplication
+
+ // pseudo-registers
+ "SB",
+}
+
+func init() {
+ // Make map from reg names to reg integers.
+ if len(regNamesMIPS) > 64 {
+ panic("too many registers")
+ }
+ num := map[string]int{}
+ for i, name := range regNamesMIPS {
+ num[name] = i
+ }
+ buildReg := func(s string) regMask {
+ m := regMask(0)
+ for _, r := range strings.Split(s, " ") {
+ if n, ok := num[r]; ok {
+ m |= regMask(1) << uint(n)
+ continue
+ }
+ panic("register " + r + " not found")
+ }
+ return m
+ }
+
+ // Common individual register masks
+ var (
+ gp = buildReg("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 R31")
+ gpg = gp | buildReg("g")
+ gpsp = gp | buildReg("SP")
+ gpspg = gpg | buildReg("SP")
+ gpspsbg = gpspg | buildReg("SB")
+ fp = buildReg("F0 F2 F4 F6 F8 F10 F12 F14 F16 F18 F20 F22 F24 F26 F28 F30")
+ lo = buildReg("LO")
+ hi = buildReg("HI")
+ callerSave = gp | fp | lo | hi | buildReg("g") // runtime.setg (and anything calling it) may clobber g
+ )
+ // Common regInfo
+ var (
+ gp01 = regInfo{inputs: nil, outputs: []regMask{gp}}
+ gp11 = regInfo{inputs: []regMask{gpg}, outputs: []regMask{gp}}
+ gp11sp = regInfo{inputs: []regMask{gpspg}, outputs: []regMask{gp}}
+ gp21 = regInfo{inputs: []regMask{gpg, gpg}, outputs: []regMask{gp}}
+ gp31 = regInfo{inputs: []regMask{gp, gp, gp}, outputs: []regMask{gp}}
+ gp2hilo = regInfo{inputs: []regMask{gpg, gpg}, outputs: []regMask{hi, lo}}
+ gpload = regInfo{inputs: []regMask{gpspsbg}, outputs: []regMask{gp}}
+ gpstore = regInfo{inputs: []regMask{gpspsbg, gpg}}
+ gpxchg = regInfo{inputs: []regMask{gpspsbg, gpg}, outputs: []regMask{gp}}
+ gpcas = regInfo{inputs: []regMask{gpspsbg, gpg, gpg}, outputs: []regMask{gp}}
+ gpstore0 = regInfo{inputs: []regMask{gpspsbg}}
+ fp01 = regInfo{inputs: nil, outputs: []regMask{fp}}
+ fp11 = regInfo{inputs: []regMask{fp}, outputs: []regMask{fp}}
+ fp21 = regInfo{inputs: []regMask{fp, fp}, outputs: []regMask{fp}}
+ fp2flags = regInfo{inputs: []regMask{fp, fp}}
+ fpload = regInfo{inputs: []regMask{gpspsbg}, outputs: []regMask{fp}}
+ fpstore = regInfo{inputs: []regMask{gpspsbg, fp}}
+ readflags = regInfo{inputs: nil, outputs: []regMask{gp}}
+ )
+ ops := []opData{
+ {name: "ADD", argLength: 2, reg: gp21, asm: "ADDU", commutative: true}, // arg0 + arg1
+ {name: "ADDconst", argLength: 1, reg: gp11sp, asm: "ADDU", aux: "Int32"}, // arg0 + auxInt
+ {name: "SUB", argLength: 2, reg: gp21, asm: "SUBU"}, // arg0 - arg1
+ {name: "SUBconst", argLength: 1, reg: gp11, asm: "SUBU", aux: "Int32"}, // arg0 - auxInt
+ {name: "MUL", argLength: 2, reg: regInfo{inputs: []regMask{gpg, gpg}, outputs: []regMask{gp}, clobbers: hi | lo}, asm: "MUL", commutative: true}, // arg0 * arg1
+ {name: "MULT", argLength: 2, reg: gp2hilo, asm: "MUL", commutative: true, typ: "(Int32,Int32)"}, // arg0 * arg1, signed, results hi,lo
+ {name: "MULTU", argLength: 2, reg: gp2hilo, asm: "MULU", commutative: true, typ: "(UInt32,UInt32)"}, // arg0 * arg1, unsigned, results hi,lo
+ {name: "DIV", argLength: 2, reg: gp2hilo, asm: "DIV", typ: "(Int32,Int32)"}, // arg0 / arg1, signed, results hi=arg0%arg1,lo=arg0/arg1
+ {name: "DIVU", argLength: 2, reg: gp2hilo, asm: "DIVU", typ: "(UInt32,UInt32)"}, // arg0 / arg1, signed, results hi=arg0%arg1,lo=arg0/arg1
+
+ {name: "ADDF", argLength: 2, reg: fp21, asm: "ADDF", commutative: true}, // arg0 + arg1
+ {name: "ADDD", argLength: 2, reg: fp21, asm: "ADDD", commutative: true}, // arg0 + arg1
+ {name: "SUBF", argLength: 2, reg: fp21, asm: "SUBF"}, // arg0 - arg1
+ {name: "SUBD", argLength: 2, reg: fp21, asm: "SUBD"}, // arg0 - arg1
+ {name: "MULF", argLength: 2, reg: fp21, asm: "MULF", commutative: true}, // arg0 * arg1
+ {name: "MULD", argLength: 2, reg: fp21, asm: "MULD", commutative: true}, // arg0 * arg1
+ {name: "DIVF", argLength: 2, reg: fp21, asm: "DIVF"}, // arg0 / arg1
+ {name: "DIVD", argLength: 2, reg: fp21, asm: "DIVD"}, // arg0 / arg1
+
+ {name: "AND", argLength: 2, reg: gp21, asm: "AND", commutative: true}, // arg0 & arg1
+ {name: "ANDconst", argLength: 1, reg: gp11, asm: "AND", aux: "Int32"}, // arg0 & auxInt
+ {name: "OR", argLength: 2, reg: gp21, asm: "OR", commutative: true}, // arg0 | arg1
+ {name: "ORconst", argLength: 1, reg: gp11, asm: "OR", aux: "Int32"}, // arg0 | auxInt
+ {name: "XOR", argLength: 2, reg: gp21, asm: "XOR", commutative: true, typ: "UInt32"}, // arg0 ^ arg1
+ {name: "XORconst", argLength: 1, reg: gp11, asm: "XOR", aux: "Int32", typ: "UInt32"}, // arg0 ^ auxInt
+ {name: "NOR", argLength: 2, reg: gp21, asm: "NOR", commutative: true}, // ^(arg0 | arg1)
+ {name: "NORconst", argLength: 1, reg: gp11, asm: "NOR", aux: "Int32"}, // ^(arg0 | auxInt)
+
+ {name: "NEG", argLength: 1, reg: gp11}, // -arg0
+ {name: "NEGF", argLength: 1, reg: fp11, asm: "NEGF"}, // -arg0, float32
+ {name: "NEGD", argLength: 1, reg: fp11, asm: "NEGD"}, // -arg0, float64
+ {name: "SQRTD", argLength: 1, reg: fp11, asm: "SQRTD"}, // sqrt(arg0), float64
+
+ // shifts
+ {name: "SLL", argLength: 2, reg: gp21, asm: "SLL"}, // arg0 << arg1, shift amount is mod 32
+ {name: "SLLconst", argLength: 1, reg: gp11, asm: "SLL", aux: "Int32"}, // arg0 << auxInt
+ {name: "SRL", argLength: 2, reg: gp21, asm: "SRL"}, // arg0 >> arg1, unsigned, shift amount is mod 32
+ {name: "SRLconst", argLength: 1, reg: gp11, asm: "SRL", aux: "Int32"}, // arg0 >> auxInt, unsigned
+ {name: "SRA", argLength: 2, reg: gp21, asm: "SRA"}, // arg0 >> arg1, signed, shift amount is mod 32
+ {name: "SRAconst", argLength: 1, reg: gp11, asm: "SRA", aux: "Int32"}, // arg0 >> auxInt, signed
+
+ {name: "CLZ", argLength: 1, reg: gp11, asm: "CLZ"},
+
+ // comparisons
+ {name: "SGT", argLength: 2, reg: gp21, asm: "SGT", typ: "Bool"}, // 1 if arg0 > arg1 (signed), 0 otherwise
+ {name: "SGTconst", argLength: 1, reg: gp11, asm: "SGT", aux: "Int32", typ: "Bool"}, // 1 if auxInt > arg0 (signed), 0 otherwise
+ {name: "SGTzero", argLength: 1, reg: gp11, asm: "SGT", typ: "Bool"}, // 1 if arg0 > 0 (signed), 0 otherwise
+ {name: "SGTU", argLength: 2, reg: gp21, asm: "SGTU", typ: "Bool"}, // 1 if arg0 > arg1 (unsigned), 0 otherwise
+ {name: "SGTUconst", argLength: 1, reg: gp11, asm: "SGTU", aux: "Int32", typ: "Bool"}, // 1 if auxInt > arg0 (unsigned), 0 otherwise
+ {name: "SGTUzero", argLength: 1, reg: gp11, asm: "SGTU", typ: "Bool"}, // 1 if arg0 > 0 (unsigned), 0 otherwise
+
+ {name: "CMPEQF", argLength: 2, reg: fp2flags, asm: "CMPEQF", typ: "Flags"}, // flags=true if arg0 = arg1, float32
+ {name: "CMPEQD", argLength: 2, reg: fp2flags, asm: "CMPEQD", typ: "Flags"}, // flags=true if arg0 = arg1, float64
+ {name: "CMPGEF", argLength: 2, reg: fp2flags, asm: "CMPGEF", typ: "Flags"}, // flags=true if arg0 >= arg1, float32
+ {name: "CMPGED", argLength: 2, reg: fp2flags, asm: "CMPGED", typ: "Flags"}, // flags=true if arg0 >= arg1, float64
+ {name: "CMPGTF", argLength: 2, reg: fp2flags, asm: "CMPGTF", typ: "Flags"}, // flags=true if arg0 > arg1, float32
+ {name: "CMPGTD", argLength: 2, reg: fp2flags, asm: "CMPGTD", typ: "Flags"}, // flags=true if arg0 > arg1, float64
+
+ // moves
+ {name: "MOVWconst", argLength: 0, reg: gp01, aux: "Int32", asm: "MOVW", typ: "UInt32", rematerializeable: true}, // auxint
+ {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.
+
+ // conversions
+ {name: "MOVBreg", argLength: 1, reg: gp11, asm: "MOVB"}, // move from arg0, sign-extended from byte
+ {name: "MOVBUreg", argLength: 1, reg: gp11, asm: "MOVBU"}, // move from arg0, unsign-extended from byte
+ {name: "MOVHreg", argLength: 1, reg: gp11, asm: "MOVH"}, // move from arg0, sign-extended from half
+ {name: "MOVHUreg", argLength: 1, reg: gp11, asm: "MOVHU"}, // move from arg0, unsign-extended from half
+ {name: "MOVWreg", argLength: 1, reg: gp11, asm: "MOVW"}, // move from arg0
+
+ {name: "MOVWnop", argLength: 1, reg: regInfo{inputs: []regMask{gp}, outputs: []regMask{gp}}, resultInArg0: true}, // nop, return arg0 in same register
+
+ // conditional move on zero (returns arg1 if arg2 is 0, otherwise arg0)
+ // order of parameters is reversed so we can use resultInArg0 (OpCMOVZ result arg1 arg2-> CMOVZ arg2reg, arg1reg, resultReg)
+ {name: "CMOVZ", argLength: 3, reg: gp31, asm: "CMOVZ", resultInArg0: true},
+ {name: "CMOVZzero", argLength: 2, reg: regInfo{inputs: []regMask{gp, gpg}, outputs: []regMask{gp}}, asm: "CMOVZ", resultInArg0: true},
+
+ {name: "MOVWF", argLength: 1, reg: fp11, asm: "MOVWF"}, // int32 -> float32
+ {name: "MOVWD", argLength: 1, reg: fp11, asm: "MOVWD"}, // int32 -> float64
+ {name: "TRUNCFW", argLength: 1, reg: fp11, asm: "TRUNCFW"}, // float32 -> int32
+ {name: "TRUNCDW", argLength: 1, reg: fp11, asm: "TRUNCDW"}, // float64 -> int32
+ {name: "MOVFD", argLength: 1, reg: fp11, asm: "MOVFD"}, // float32 -> float64
+ {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
+
+ // atomic ops
+
+ // load from arg0. arg1=mem.
+ // returns <value,memory> so they can be properly ordered with other loads.
+ // SYNC
+ // MOVW (Rarg0), Rout
+ // SYNC
+ {name: "LoweredAtomicLoad", argLength: 2, reg: gpload, faultOnNilArg0: true},
+
+ // store arg1 to arg0. arg2=mem. returns memory.
+ // SYNC
+ // MOVW Rarg1, (Rarg0)
+ // SYNC
+ {name: "LoweredAtomicStore", argLength: 3, reg: gpstore, faultOnNilArg0: true},
+ {name: "LoweredAtomicStorezero", argLength: 2, reg: gpstore0, faultOnNilArg0: true},
+
+ // atomic exchange.
+ // store arg1 to arg0. arg2=mem. returns <old content of *arg0, memory>.
+ // SYNC
+ // LL (Rarg0), Rout
+ // MOVW Rarg1, Rtmp
+ // SC Rtmp, (Rarg0)
+ // BEQ Rtmp, -3(PC)
+ // SYNC
+ {name: "LoweredAtomicExchange", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true},
+
+ // atomic add.
+ // *arg0 += arg1. arg2=mem. returns <new content of *arg0, memory>.
+ // SYNC
+ // LL (Rarg0), Rout
+ // ADDU Rarg1, Rout, Rtmp
+ // SC Rtmp, (Rarg0)
+ // BEQ Rtmp, -3(PC)
+ // SYNC
+ // ADDU Rarg1, Rout
+ {name: "LoweredAtomicAdd", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true},
+ {name: "LoweredAtomicAddconst", argLength: 2, reg: regInfo{inputs: []regMask{gpspsbg}, outputs: []regMask{gp}}, aux: "Int32", resultNotInArgs: true, faultOnNilArg0: true},
+
+ // atomic compare and swap.
+ // arg0 = pointer, arg1 = old value, arg2 = new value, arg3 = memory.
+ // if *arg0 == arg1 {
+ // *arg0 = arg2
+ // return (true, memory)
+ // } else {
+ // return (false, memory)
+ // }
+ // SYNC
+ // MOVW $0, Rout
+ // LL (Rarg0), Rtmp
+ // BNE Rtmp, Rarg1, 4(PC)
+ // MOVW Rarg2, Rout
+ // SC Rout, (Rarg0)
+ // BEQ Rout, -4(PC)
+ // SYNC
+ {name: "LoweredAtomicCas", argLength: 4, reg: gpcas, resultNotInArgs: true, faultOnNilArg0: true},
+
+ // atomic and/or.
+ // *arg0 &= (|=) arg1. arg2=mem. returns memory.
+ // SYNC
+ // LL (Rarg0), Rtmp
+ // AND Rarg1, Rtmp
+ // SC Rtmp, (Rarg0)
+ // BEQ Rtmp, -3(PC)
+ // SYNC
+ {name: "LoweredAtomicAnd", argLength: 3, reg: gpstore, asm: "AND", faultOnNilArg0: true},
+ {name: "LoweredAtomicOr", argLength: 3, reg: gpstore, asm: "OR", faultOnNilArg0: true},
+
+ // large or unaligned zeroing
+ // arg0 = address of memory to zero (in R1, changed as side effect)
+ // arg1 = address of the last element to zero
+ // arg2 = mem
+ // auxint = alignment
+ // returns mem
+ // SUBU $4, R1
+ // MOVW R0, 4(R1)
+ // ADDU $4, R1
+ // BNE Rarg1, R1, -2(PC)
+ {
+ name: "LoweredZero",
+ aux: "Int32",
+ argLength: 3,
+ reg: regInfo{
+ inputs: []regMask{buildReg("R1"), gp},
+ clobbers: buildReg("R1"),
+ },
+ faultOnNilArg0: true,
+ },
+
+ // large or unaligned move
+ // arg0 = address of dst memory (in R2, changed as side effect)
+ // arg1 = address of src memory (in R1, changed as side effect)
+ // arg2 = address of the last element of src
+ // arg3 = mem
+ // auxint = alignment
+ // returns mem
+ // SUBU $4, R1
+ // MOVW 4(R1), Rtmp
+ // MOVW Rtmp, (R2)
+ // ADDU $4, R1
+ // ADDU $4, R2
+ // BNE Rarg2, R1, -4(PC)
+ {
+ name: "LoweredMove",
+ aux: "Int32",
+ argLength: 4,
+ reg: regInfo{
+ inputs: []regMask{buildReg("R2"), buildReg("R1"), gp},
+ clobbers: buildReg("R1 R2"),
+ },
+ faultOnNilArg0: true,
+ faultOnNilArg1: true,
+ },
+
+ // pseudo-ops
+ {name: "LoweredNilCheck", argLength: 2, reg: regInfo{inputs: []regMask{gpg}}, nilCheck: true, faultOnNilArg0: true}, // panic if arg0 is nil. arg1=mem.
+
+ {name: "FPFlagTrue", argLength: 1, reg: readflags}, // bool, true if FP flag is true
+ {name: "FPFlagFalse", argLength: 1, reg: readflags}, // bool, true if FP flag is false
+
+ // Scheduler ensures LoweredGetClosurePtr occurs only in entry block,
+ // and sorts it to the very beginning of the block to prevent other
+ // use of R22 (mips.REGCTXT, the closure pointer)
+ {name: "LoweredGetClosurePtr", reg: regInfo{outputs: []regMask{buildReg("R22")}}},
+
+ // MOVWconvert converts between pointers and integers.
+ // We have a special op for this so as to not confuse GC
+ // (particularly stack maps). It takes a memory arg so it
+ // gets correctly ordered with respect to GC safepoints.
+ // arg0=ptr/int arg1=mem, output=int/ptr
+ {name: "MOVWconvert", argLength: 2, reg: gp11, asm: "MOVW"},
+ }
+
+ blocks := []blockData{
+ {name: "EQ"},
+ {name: "NE"},
+ {name: "LTZ"}, // < 0
+ {name: "LEZ"}, // <= 0
+ {name: "GTZ"}, // > 0
+ {name: "GEZ"}, // >= 0
+ {name: "FPT"}, // FP flag is true
+ {name: "FPF"}, // FP flag is false
+ }
+
+ archs = append(archs, arch{
+ name: "MIPS",
+ pkg: "cmd/internal/obj/mips",
+ genfile: "../../mips/ssa.go",
+ ops: ops,
+ blocks: blocks,
+ regnames: regNamesMIPS,
+ gpregmask: gp,
+ fpregmask: fp,
+ specialregmask: hi | lo,
+ framepointerreg: -1, // not used
+ linkreg: int8(num["R31"]),
+ })
+}
diff --git a/src/cmd/compile/internal/ssa/gen/PPC64.rules b/src/cmd/compile/internal/ssa/gen/PPC64.rules
new file mode 100644
index 0000000..0e0f1f9
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/gen/PPC64.rules
@@ -0,0 +1,832 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Lowering arithmetic
+(Add64 x y) -> (ADD x y)
+(AddPtr x y) -> (ADD x y)
+(Add32 x y) -> (ADD x y)
+(Add16 x y) -> (ADD x y)
+(Add8 x y) -> (ADD x y)
+(Add64F x y) -> (FADD x y)
+(Add32F x y) -> (FADDS x y)
+
+(Sub64 x y) -> (SUB x y)
+(SubPtr x y) -> (SUB x y)
+(Sub32 x y) -> (SUB x y)
+(Sub16 x y) -> (SUB x y)
+(Sub8 x y) -> (SUB x y)
+(Sub32F x y) -> (FSUBS x y)
+(Sub64F x y) -> (FSUB 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))
+(Mod64 x y) -> (SUB x (MULLD y (DIVD x y)))
+(Mod64u x y) -> (SUB x (MULLD y (DIVDU x y)))
+(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]))
+
+(Mul64 x y) -> (MULLD x y)
+(Mul32 x y) -> (MULLW x y)
+(Mul16 x y) -> (MULLW x y)
+(Mul8 x y) -> (MULLW x y)
+
+(Div64 x y) -> (DIVD x y)
+(Div64u x y) -> (DIVDU x y)
+(Div32 x y) -> (DIVW x y)
+(Div32u x y) -> (DIVWU x y)
+(Div16 x y) -> (DIVW (SignExt16to32 x) (SignExt16to32 y))
+(Div16u x y) -> (DIVWU (ZeroExt16to32 x) (ZeroExt16to32 y))
+(Div8 x y) -> (DIVW (SignExt8to32 x) (SignExt8to32 y))
+(Div8u x y) -> (DIVWU (ZeroExt8to32 x) (ZeroExt8to32 y))
+
+(Hmul64 x y) -> (MULHD x y)
+(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)
+
+(Div32F x y) -> (FDIVS x y)
+(Div64F x y) -> (FDIV x y)
+
+// Lowering float <-> int
+(Cvt32to32F x) -> (FRSP (FCFID (Xi2f64 (SignExt32to64 x))))
+(Cvt32to64F x) -> (FCFID (Xi2f64 (SignExt32to64 x)))
+(Cvt64to32F x) -> (FRSP (FCFID (Xi2f64 x)))
+(Cvt64to64F x) -> (FCFID (Xi2f64 x))
+
+(Cvt32Fto32 x) -> (Xf2i64 (FCTIWZ x))
+(Cvt32Fto64 x) -> (Xf2i64 (FCTIDZ x))
+(Cvt64Fto32 x) -> (Xf2i64 (FCTIWZ x))
+(Cvt64Fto64 x) -> (Xf2i64 (FCTIDZ x))
+
+(Cvt32Fto64F x) -> x // Note x will have the wrong type for patterns dependent on Float32/Float64
+(Cvt64Fto32F x) -> (FRSP x)
+
+(Sqrt x) -> (FSQRT x)
+
+// Lowering constants
+(Const8 [val]) -> (MOVDconst [val])
+(Const16 [val]) -> (MOVDconst [val])
+(Const32 [val]) -> (MOVDconst [val])
+(Const64 [val]) -> (MOVDconst [val])
+(Const32F [val]) -> (FMOVSconst [val])
+(Const64F [val]) -> (FMOVDconst [val])
+(ConstNil) -> (MOVDconst [0])
+(ConstBool [b]) -> (MOVDconst [b])
+
+(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])
+(Lsh32x64 x (Const64 [c])) && uint64(c) < 32 -> (SLWconst x [c])
+(Rsh32x64 x (Const64 [c])) && uint64(c) < 32 -> (SRAWconst x [c])
+(Rsh32Ux64 x (Const64 [c])) && uint64(c) < 32 -> (SRWconst x [c])
+(Lsh16x64 x (Const64 [c])) && uint64(c) < 16 -> (SLWconst x [c])
+(Rsh16x64 x (Const64 [c])) && uint64(c) < 16 -> (SRAWconst (SignExt16to32 x) [c])
+(Rsh16Ux64 x (Const64 [c])) && uint64(c) < 16 -> (SRWconst (ZeroExt16to32 x) [c])
+(Lsh8x64 x (Const64 [c])) && uint64(c) < 8 -> (SLWconst x [c])
+(Rsh8x64 x (Const64 [c])) && uint64(c) < 8 -> (SRAWconst (SignExt8to32 x) [c])
+(Rsh8Ux64 x (Const64 [c])) && uint64(c) < 8 -> (SRWconst (ZeroExt8to32 x) [c])
+
+(Lsh64x32 x (Const64 [c])) && uint32(c) < 64 -> (SLDconst x [c])
+(Rsh64x32 x (Const64 [c])) && uint32(c) < 64 -> (SRADconst x [c])
+(Rsh64Ux32 x (Const64 [c])) && uint32(c) < 64 -> (SRDconst x [c])
+(Lsh32x32 x (Const64 [c])) && uint32(c) < 32 -> (SLWconst x [c])
+(Rsh32x32 x (Const64 [c])) && uint32(c) < 32 -> (SRAWconst x [c])
+(Rsh32Ux32 x (Const64 [c])) && uint32(c) < 32 -> (SRWconst x [c])
+(Lsh16x32 x (Const64 [c])) && uint32(c) < 16 -> (SLWconst x [c])
+(Rsh16x32 x (Const64 [c])) && uint32(c) < 16 -> (SRAWconst (SignExt16to32 x) [c])
+(Rsh16Ux32 x (Const64 [c])) && uint32(c) < 16 -> (SRWconst (ZeroExt16to32 x) [c])
+(Lsh8x32 x (Const64 [c])) && uint32(c) < 8 -> (SLWconst x [c])
+(Rsh8x32 x (Const64 [c])) && uint32(c) < 8 -> (SRAWconst (SignExt8to32 x) [c])
+(Rsh8Ux32 x (Const64 [c])) && uint32(c) < 8 -> (SRWconst (ZeroExt8to32 x) [c])
+
+// large constant shifts
+(Lsh64x64 _ (Const64 [c])) && uint64(c) >= 64 -> (MOVDconst [0])
+(Rsh64Ux64 _ (Const64 [c])) && uint64(c) >= 64 -> (MOVDconst [0])
+(Lsh32x64 _ (Const64 [c])) && uint64(c) >= 32 -> (MOVDconst [0])
+(Rsh32Ux64 _ (Const64 [c])) && uint64(c) >= 32 -> (MOVDconst [0])
+(Lsh16x64 _ (Const64 [c])) && uint64(c) >= 16 -> (MOVDconst [0])
+(Rsh16Ux64 _ (Const64 [c])) && uint64(c) >= 16 -> (MOVDconst [0])
+(Lsh8x64 _ (Const64 [c])) && uint64(c) >= 8 -> (MOVDconst [0])
+(Rsh8Ux64 _ (Const64 [c])) && uint64(c) >= 8 -> (MOVDconst [0])
+
+// large constant signed right shift, we leave the sign bit
+(Rsh64x64 x (Const64 [c])) && uint64(c) >= 64 -> (SRADconst x [63])
+(Rsh32x64 x (Const64 [c])) && uint64(c) >= 32 -> (SRAWconst x [63])
+(Rsh16x64 x (Const64 [c])) && uint64(c) >= 16 -> (SRAWconst (SignExt16to32 x) [63])
+(Rsh8x64 x (Const64 [c])) && uint64(c) >= 8 -> (SRAWconst (SignExt8to32 x) [63])
+
+// constant shifts
+(Lsh64x64 x (MOVDconst [c])) && uint64(c) < 64 -> (SLDconst x [c])
+(Rsh64x64 x (MOVDconst [c])) && uint64(c) < 64 -> (SRADconst x [c])
+(Rsh64Ux64 x (MOVDconst [c])) && uint64(c) < 64 -> (SRDconst x [c])
+(Lsh32x64 x (MOVDconst [c])) && uint64(c) < 32 -> (SLWconst x [c])
+(Rsh32x64 x (MOVDconst [c])) && uint64(c) < 32 -> (SRAWconst x [c])
+(Rsh32Ux64 x (MOVDconst [c])) && uint64(c) < 32 -> (SRWconst x [c])
+(Lsh16x64 x (MOVDconst [c])) && uint64(c) < 16 -> (SLWconst x [c])
+(Rsh16x64 x (MOVDconst [c])) && uint64(c) < 16 -> (SRAWconst (SignExt16to32 x) [c])
+(Rsh16Ux64 x (MOVDconst [c])) && uint64(c) < 16 -> (SRWconst (ZeroExt16to32 x) [c])
+(Lsh8x64 x (MOVDconst [c])) && uint64(c) < 8 -> (SLWconst x [c])
+(Rsh8x64 x (MOVDconst [c])) && uint64(c) < 8 -> (SRAWconst (SignExt8to32 x) [c])
+(Rsh8Ux64 x (MOVDconst [c])) && uint64(c) < 8 -> (SRWconst (ZeroExt8to32 x) [c])
+
+(Lsh64x32 x (MOVDconst [c])) && uint32(c) < 64 -> (SLDconst x [c])
+(Rsh64x32 x (MOVDconst [c])) && uint32(c) < 64 -> (SRADconst x [c])
+(Rsh64Ux32 x (MOVDconst [c])) && uint32(c) < 64 -> (SRDconst x [c])
+(Lsh32x32 x (MOVDconst [c])) && uint32(c) < 32 -> (SLWconst x [c])
+(Rsh32x32 x (MOVDconst [c])) && uint32(c) < 32 -> (SRAWconst x [c])
+(Rsh32Ux32 x (MOVDconst [c])) && uint32(c) < 32 -> (SRWconst x [c])
+(Lsh16x32 x (MOVDconst [c])) && uint32(c) < 16 -> (SLWconst x [c])
+(Rsh16x32 x (MOVDconst [c])) && uint32(c) < 16 -> (SRAWconst (SignExt16to32 x) [c])
+(Rsh16Ux32 x (MOVDconst [c])) && uint32(c) < 16 -> (SRWconst (ZeroExt16to32 x) [c])
+(Lsh8x32 x (MOVDconst [c])) && uint32(c) < 8 -> (SLWconst x [c])
+(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))))
+
+(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))))
+
+(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))))
+
+(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))))
+
+
+(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)))))
+
+(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)))))
+
+(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)))))
+
+(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)))))
+
+
+(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)))))
+
+(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)))))
+
+(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)))))
+
+(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)))))
+
+
+(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)))))
+
+(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)))))
+
+(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)))))
+
+(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)))))
+
+// Cleaning up shift ops when input is masked
+(MaskIfNotCarry (ADDconstForCarry [c] (ANDconst [d] _))) && c < 0 && d > 0 && c + d < 0 -> (MOVDconst [-1])
+(ORN x (MOVDconst [-1])) -> x
+
+// Potentially useful optimizing rewrites.
+// (ADDconstForCarry [k] c), k < 0 && (c < 0 || k+c >= 0) -> CarrySet
+// (ADDconstForCarry [k] c), K < 0 && (c >= 0 && k+c < 0) -> CarryClear
+// (MaskIfNotCarry CarrySet) -> 0
+// (MaskIfNotCarry CarrySet) -> -1
+
+(Addr {sym} base) -> (MOVDaddr {sym} base)
+// (Addr {sym} base) -> (ADDconst {sym} base)
+(OffPtr [off] ptr) -> (ADD (MOVDconst <config.Frontend().TypeInt64()> [off]) ptr)
+
+(And64 x y) -> (AND x y)
+(And32 x y) -> (AND x y)
+(And16 x y) -> (AND x y)
+(And8 x y) -> (AND x y)
+
+(Or64 x y) -> (OR x y)
+(Or32 x y) -> (OR x y)
+(Or16 x y) -> (OR x y)
+(Or8 x y) -> (OR x y)
+
+(Xor64 x y) -> (XOR x y)
+(Xor32 x y) -> (XOR x y)
+(Xor16 x y) -> (XOR x y)
+(Xor8 x y) -> (XOR x y)
+
+(Neg64F x) -> (FNEG x)
+(Neg32F x) -> (FNEG x)
+(Neg64 x) -> (NEG x)
+(Neg32 x) -> (NEG x)
+(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)
+
+// Lowering boolean ops
+(AndB x y) -> (AND x y)
+(OrB x y) -> (OR x y)
+(Not x) -> (XORconst [1] x)
+
+// Use ANDN for AND x NOT y
+(AND x (XORconst [-1] y)) -> (ANDN x y)
+
+// Lowering comparisons
+(EqB x y) -> (ANDconst [1] (EQV x y))
+// Sign extension dependence on operand sign sets up for sign/zero-extension elision later
+(Eq8 x y) && isSigned(x.Type) && isSigned(y.Type) -> (Equal (CMPW (SignExt8to32 x) (SignExt8to32 y)))
+(Eq16 x y) && isSigned(x.Type) && isSigned(y.Type) -> (Equal (CMPW (SignExt16to32 x) (SignExt16to32 y)))
+(Eq8 x y) -> (Equal (CMPW (ZeroExt8to32 x) (ZeroExt8to32 y)))
+(Eq16 x y) -> (Equal (CMPW (ZeroExt16to32 x) (ZeroExt16to32 y)))
+(Eq32 x y) -> (Equal (CMPW x y))
+(Eq64 x y) -> (Equal (CMP x y))
+(Eq32F x y) -> (Equal (FCMPU x y))
+(Eq64F x y) -> (Equal (FCMPU x y))
+(EqPtr x y) -> (Equal (CMP x y))
+
+(NeqB x y) -> (XOR x y)
+// Like Eq8 and Eq16, prefer sign extension likely to enable later elision.
+(Neq8 x y) && isSigned(x.Type) && isSigned(y.Type) -> (NotEqual (CMPW (SignExt8to32 x) (SignExt8to32 y)))
+(Neq16 x y) && isSigned(x.Type) && isSigned(y.Type) -> (NotEqual (CMPW (SignExt16to32 x) (SignExt16to32 y)))
+(Neq8 x y) -> (NotEqual (CMPW (ZeroExt8to32 x) (ZeroExt8to32 y)))
+(Neq16 x y) -> (NotEqual (CMPW (ZeroExt16to32 x) (ZeroExt16to32 y)))
+(Neq32 x y) -> (NotEqual (CMPW x y))
+(Neq64 x y) -> (NotEqual (CMP x y))
+(Neq32F x y) -> (NotEqual (FCMPU x y))
+(Neq64F x y) -> (NotEqual (FCMPU x y))
+(NeqPtr x y) -> (NotEqual (CMP x y))
+
+(Less8 x y) -> (LessThan (CMPW (SignExt8to32 x) (SignExt8to32 y)))
+(Less16 x y) -> (LessThan (CMPW (SignExt16to32 x) (SignExt16to32 y)))
+(Less32 x y) -> (LessThan (CMPW x y))
+(Less64 x y) -> (LessThan (CMP x y))
+(Less32F x y) -> (FLessThan (FCMPU x y))
+(Less64F x y) -> (FLessThan (FCMPU x y))
+
+(Less8U x y) -> (LessThan (CMPWU (ZeroExt8to32 x) (ZeroExt8to32 y)))
+(Less16U x y) -> (LessThan (CMPWU (ZeroExt16to32 x) (ZeroExt16to32 y)))
+(Less32U x y) -> (LessThan (CMPWU x y))
+(Less64U x y) -> (LessThan (CMPU x y))
+
+(Leq8 x y) -> (LessEqual (CMPW (SignExt8to32 x) (SignExt8to32 y)))
+(Leq16 x y) -> (LessEqual (CMPW (SignExt16to32 x) (SignExt16to32 y)))
+(Leq32 x y) -> (LessEqual (CMPW x y))
+(Leq64 x y) -> (LessEqual (CMP x y))
+(Leq32F x y) -> (FLessEqual (FCMPU x y))
+(Leq64F x y) -> (FLessEqual (FCMPU x y))
+
+(Leq8U x y) -> (LessEqual (CMPWU (ZeroExt8to32 x) (ZeroExt8to32 y)))
+(Leq16U x y) -> (LessEqual (CMPWU (ZeroExt16to32 x) (ZeroExt16to32 y)))
+(Leq32U x y) -> (LessEqual (CMPWU x y))
+(Leq64U x y) -> (LessEqual (CMPU x y))
+
+(Greater8 x y) -> (GreaterThan (CMPW (SignExt8to32 x) (SignExt8to32 y)))
+(Greater16 x y) -> (GreaterThan (CMPW (SignExt16to32 x) (SignExt16to32 y)))
+(Greater32 x y) -> (GreaterThan (CMPW x y))
+(Greater64 x y) -> (GreaterThan (CMP x y))
+(Greater32F x y) -> (FGreaterThan (FCMPU x y))
+(Greater64F x y) -> (FGreaterThan (FCMPU x y))
+
+(Greater8U x y) -> (GreaterThan (CMPWU (ZeroExt8to32 x) (ZeroExt8to32 y)))
+(Greater16U x y) -> (GreaterThan (CMPWU (ZeroExt16to32 x) (ZeroExt16to32 y)))
+(Greater32U x y) -> (GreaterThan (CMPWU x y))
+(Greater64U x y) -> (GreaterThan (CMPU x y))
+
+(Geq8 x y) -> (GreaterEqual (CMPW (SignExt8to32 x) (SignExt8to32 y)))
+(Geq16 x y) -> (GreaterEqual (CMPW (SignExt16to32 x) (SignExt16to32 y)))
+(Geq32 x y) -> (GreaterEqual (CMPW x y))
+(Geq64 x y) -> (GreaterEqual (CMP x y))
+(Geq32F x y) -> (FGreaterEqual (FCMPU x y))
+(Geq64F x y) -> (FGreaterEqual (FCMPU x y))
+
+(Geq8U x y) -> (GreaterEqual (CMPU (ZeroExt8to32 x) (ZeroExt8to32 y)))
+(Geq16U x y) -> (GreaterEqual (CMPU (ZeroExt16to32 x) (ZeroExt16to32 y)))
+(Geq32U x y) -> (GreaterEqual (CMPU x y))
+(Geq64U x y) -> (GreaterEqual (CMPU x y))
+
+// Absorb pseudo-ops into blocks.
+(If (Equal cc) yes no) -> (EQ cc yes no)
+(If (NotEqual cc) yes no) -> (NE cc yes no)
+(If (LessThan cc) yes no) -> (LT cc yes no)
+(If (LessEqual cc) yes no) -> (LE cc yes no)
+(If (GreaterThan cc) yes no) -> (GT cc yes no)
+(If (GreaterEqual cc) yes no) -> (GE cc yes no)
+(If (FLessThan cc) yes no) -> (FLT cc yes no)
+(If (FLessEqual cc) yes no) -> (FLE cc yes no)
+(If (FGreaterThan cc) yes no) -> (FGT cc yes no)
+(If (FGreaterEqual cc) yes no) -> (FGE cc yes no)
+
+(If cond yes no) -> (NE (CMPWconst [0] cond) yes no)
+
+// Absorb boolean tests into block
+(NE (CMPWconst [0] (Equal cc)) yes no) -> (EQ cc yes no)
+(NE (CMPWconst [0] (NotEqual cc)) yes no) -> (NE cc yes no)
+(NE (CMPWconst [0] (LessThan cc)) yes no) -> (LT cc yes no)
+(NE (CMPWconst [0] (LessEqual cc)) yes no) -> (LE cc yes no)
+(NE (CMPWconst [0] (GreaterThan cc)) yes no) -> (GT cc yes no)
+(NE (CMPWconst [0] (GreaterEqual cc)) yes no) -> (GE cc yes no)
+(NE (CMPWconst [0] (FLessThan cc)) yes no) -> (FLT cc yes no)
+(NE (CMPWconst [0] (FLessEqual cc)) yes no) -> (FLE cc yes no)
+(NE (CMPWconst [0] (FGreaterThan cc)) yes no) -> (FGT cc yes no)
+(NE (CMPWconst [0] (FGreaterEqual cc)) yes no) -> (FGE cc yes no)
+
+// Elide compares of bit tests // TODO need to make both CC and result of ANDCC available.
+(EQ (CMPconst [0] (ANDconst [c] x)) yes no) -> (EQ (ANDCCconst [c] x) yes no)
+(NE (CMPconst [0] (ANDconst [c] x)) yes no) -> (NE (ANDCCconst [c] x) yes no)
+(EQ (CMPWconst [0] (ANDconst [c] x)) yes no) -> (EQ (ANDCCconst [c] x) yes no)
+(NE (CMPWconst [0] (ANDconst [c] x)) yes no) -> (NE (ANDCCconst [c] x) yes no)
+
+// absorb flag constants into branches
+(EQ (FlagEQ) yes no) -> (First nil yes no)
+(EQ (FlagLT) yes no) -> (First nil no yes)
+(EQ (FlagGT) yes no) -> (First nil no yes)
+
+(NE (FlagEQ) yes no) -> (First nil no yes)
+(NE (FlagLT) yes no) -> (First nil yes no)
+(NE (FlagGT) yes no) -> (First nil yes no)
+
+(LT (FlagEQ) yes no) -> (First nil no yes)
+(LT (FlagLT) yes no) -> (First nil yes no)
+(LT (FlagGT) yes no) -> (First nil no yes)
+
+(LE (FlagEQ) yes no) -> (First nil yes no)
+(LE (FlagLT) yes no) -> (First nil yes no)
+(LE (FlagGT) yes no) -> (First nil no yes)
+
+(GT (FlagEQ) yes no) -> (First nil no yes)
+(GT (FlagLT) yes no) -> (First nil no yes)
+(GT (FlagGT) yes no) -> (First nil yes no)
+
+(GE (FlagEQ) yes no) -> (First nil yes no)
+(GE (FlagLT) yes no) -> (First nil no yes)
+(GE (FlagGT) yes no) -> (First nil yes no)
+
+// absorb InvertFlags into branches
+(LT (InvertFlags cmp) yes no) -> (GT cmp yes no)
+(GT (InvertFlags cmp) yes no) -> (LT cmp yes no)
+(LE (InvertFlags cmp) yes no) -> (GE cmp yes no)
+(GE (InvertFlags cmp) yes no) -> (LE cmp yes no)
+(EQ (InvertFlags cmp) yes no) -> (EQ cmp yes no)
+(NE (InvertFlags cmp) yes no) -> (NE cmp yes no)
+
+// constant comparisons
+(CMPWconst (MOVDconst [x]) [y]) && int32(x)==int32(y) -> (FlagEQ)
+(CMPWconst (MOVDconst [x]) [y]) && int32(x)<int32(y) -> (FlagLT)
+(CMPWconst (MOVDconst [x]) [y]) && int32(x)>int32(y) -> (FlagGT)
+
+(CMPconst (MOVDconst [x]) [y]) && int64(x)==int64(y) -> (FlagEQ)
+(CMPconst (MOVDconst [x]) [y]) && int64(x)<int64(y) -> (FlagLT)
+(CMPconst (MOVDconst [x]) [y]) && int64(x)>int64(y) -> (FlagGT)
+
+(CMPWUconst (MOVDconst [x]) [y]) && int32(x)==int32(y) -> (FlagEQ)
+(CMPWUconst (MOVDconst [x]) [y]) && uint32(x)<uint32(y) -> (FlagLT)
+(CMPWUconst (MOVDconst [x]) [y]) && uint32(x)>uint32(y) -> (FlagGT)
+
+(CMPUconst (MOVDconst [x]) [y]) && int64(x)==int64(y) -> (FlagEQ)
+(CMPUconst (MOVDconst [x]) [y]) && uint64(x)<uint64(y) -> (FlagLT)
+(CMPUconst (MOVDconst [x]) [y]) && uint64(x)>uint64(y) -> (FlagGT)
+
+// other known comparisons
+//(CMPconst (MOVBUreg _) [c]) && 0xff < c -> (FlagLT)
+//(CMPconst (MOVHUreg _) [c]) && 0xffff < c -> (FlagLT)
+//(CMPconst (ANDconst _ [m]) [n]) && 0 <= int32(m) && int32(m) < int32(n) -> (FlagLT)
+//(CMPconst (SRLconst _ [c]) [n]) && 0 <= n && 0 < c && c <= 32 && (1<<uint32(32-c)) <= uint32(n) -> (FlagLT)
+
+// absorb flag constants into boolean values
+(Equal (FlagEQ)) -> (MOVDconst [1])
+(Equal (FlagLT)) -> (MOVDconst [0])
+(Equal (FlagGT)) -> (MOVDconst [0])
+
+(NotEqual (FlagEQ)) -> (MOVDconst [0])
+(NotEqual (FlagLT)) -> (MOVDconst [1])
+(NotEqual (FlagGT)) -> (MOVDconst [1])
+
+(LessThan (FlagEQ)) -> (MOVDconst [0])
+(LessThan (FlagLT)) -> (MOVDconst [1])
+(LessThan (FlagGT)) -> (MOVDconst [0])
+
+(LessEqual (FlagEQ)) -> (MOVDconst [1])
+(LessEqual (FlagLT)) -> (MOVDconst [1])
+(LessEqual (FlagGT)) -> (MOVDconst [0])
+
+(GreaterThan (FlagEQ)) -> (MOVDconst [0])
+(GreaterThan (FlagLT)) -> (MOVDconst [0])
+(GreaterThan (FlagGT)) -> (MOVDconst [1])
+
+(GreaterEqual (FlagEQ)) -> (MOVDconst [1])
+(GreaterEqual (FlagLT)) -> (MOVDconst [0])
+(GreaterEqual (FlagGT)) -> (MOVDconst [1])
+
+// absorb InvertFlags into boolean values
+(Equal (InvertFlags x)) -> (Equal x)
+(NotEqual (InvertFlags x)) -> (NotEqual x)
+(LessThan (InvertFlags x)) -> (GreaterThan x)
+(GreaterThan (InvertFlags x)) -> (LessThan x)
+(LessEqual (InvertFlags x)) -> (GreaterEqual x)
+(GreaterEqual (InvertFlags x)) -> (LessEqual x)
+
+// Lowering loads
+(Load <t> ptr mem) && (is64BitInt(t) || isPtr(t)) -> (MOVDload ptr mem)
+(Load <t> ptr mem) && is32BitInt(t) && isSigned(t) -> (MOVWload ptr mem)
+(Load <t> ptr mem) && is32BitInt(t) && !isSigned(t) -> (MOVWZload ptr mem)
+(Load <t> ptr mem) && is16BitInt(t) && isSigned(t) -> (MOVHload ptr mem)
+(Load <t> ptr mem) && is16BitInt(t) && !isSigned(t) -> (MOVHZload ptr mem)
+(Load <t> ptr mem) && t.IsBoolean() -> (MOVBZload ptr mem)
+(Load <t> ptr mem) && is8BitInt(t) && isSigned(t) -> (MOVBreg (MOVBZload ptr mem)) // PPC has no signed-byte load.
+(Load <t> ptr mem) && is8BitInt(t) && !isSigned(t) -> (MOVBZload ptr mem)
+
+(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 ->
+ (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 ->
+ (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
+ (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)))
+
+// Zero small numbers of words directly.
+(Zero [s] destptr mem) && SizeAndAlign(s).Size() == 16 && SizeAndAlign(s).Align()%8 == 0 ->
+ (MOVDstorezero [8] destptr
+ (MOVDstorezero [0] destptr mem))
+(Zero [s] destptr mem) && SizeAndAlign(s).Size() == 24 && SizeAndAlign(s).Align()%8 == 0 ->
+ (MOVDstorezero [16] destptr
+ (MOVDstorezero [8] destptr
+ (MOVDstorezero [0] destptr mem)))
+(Zero [s] destptr mem) && SizeAndAlign(s).Size() == 32 && SizeAndAlign(s).Align()%8 == 0 ->
+ (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)
+
+// 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 ->
+ (MOVDstore dst (MOVDload src mem) mem)
+(Move [s] dst src mem) && SizeAndAlign(s).Size() == 8 && SizeAndAlign(s).Align()%4 == 0 ->
+ (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)
+
+// 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
+(Convert <t> x mem) -> (MOVDconvert <t> x mem)
+(GetClosurePtr) -> (LoweredGetClosurePtr)
+(IsNonNil ptr) -> (NotEqual (CMPconst [0] ptr))
+(IsInBounds idx len) -> (LessThan (CMPU idx len))
+(IsSliceInBounds idx len) -> (LessEqual (CMPU idx len))
+(NilCheck ptr mem) -> (LoweredNilCheck ptr mem)
+
+// Optimizations
+// Note that PPC "logical" immediates come in 0:15 and 16:31 unsigned immediate forms,
+// so ORconst, XORconst easily expand into a pair.
+
+// Include very-large constants in the const-const case.
+(AND (MOVDconst [c]) (MOVDconst [d])) -> (MOVDconst [c&d])
+(OR (MOVDconst [c]) (MOVDconst [d])) -> (MOVDconst [c|d])
+(XOR (MOVDconst [c]) (MOVDconst [d])) -> (MOVDconst [c^d])
+
+// Discover consts
+(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)
+(ORconst [c] (ORconst [d] x)) -> (ORconst [c|d] x)
+(XORconst [c] (XORconst [d] x)) -> (XORconst [c^d] x)
+(ANDconst [-1] x) -> x
+(ANDconst [0] _) -> (MOVDconst [0])
+(XORconst [0] x) -> x
+(ORconst [-1] _) -> (MOVDconst [-1])
+(ORconst [0] x) -> x
+
+// zero-extend of small and -> small and
+(MOVBZreg y:(ANDconst [c] _)) && uint64(c) <= 0xFF -> y
+(MOVHZreg y:(ANDconst [c] _)) && uint64(c) <= 0xFFFF -> y
+(MOVWZreg y:(ANDconst [c] _)) && uint64(c) <= 0xFFFFFFFF -> y
+(MOVWZreg y:(AND (MOVDconst [c]) _)) && uint64(c) <= 0xFFFFFFFF -> y
+
+// sign extend of small-positive and -> small-positive-and
+(MOVBreg y:(ANDconst [c] _)) && uint64(c) <= 0x7F -> y
+(MOVHreg y:(ANDconst [c] _)) && uint64(c) <= 0x7FFF -> y
+(MOVWreg y:(ANDconst [c] _)) && uint64(c) <= 0xFFFF -> y // 0xFFFF is largest immediate constant, when regarded as 32-bit is > 0
+(MOVWreg y:(AND (MOVDconst [c]) _)) && uint64(c) <= 0x7FFFFFFF -> y
+
+// small and of zero-extend -> either zero-extend or small and
+ // degenerate-and
+(ANDconst [c] y:(MOVBZreg _)) && c&0xFF == 0xFF -> y
+(ANDconst [c] y:(MOVHZreg _)) && c&0xFFFF == 0xFFFF -> y
+(ANDconst [c] y:(MOVWZreg _)) && c&0xFFFFFFFF == 0xFFFFFFFF -> y
+ // normal case
+(ANDconst [c] (MOVBZreg x)) -> (ANDconst [c&0xFF] x)
+(ANDconst [c] (MOVHZreg x)) -> (ANDconst [c&0xFFFF] x)
+(ANDconst [c] (MOVWZreg x)) -> (ANDconst [c&0xFFFFFFFF] x)
+
+// Various redundant zero/sign extension combinations.
+(MOVBZreg y:(MOVBZreg _)) -> y // repeat
+(MOVBreg y:(MOVBreg _)) -> y // repeat
+(MOVBreg (MOVBZreg x)) -> (MOVBreg x)
+(MOVBZreg (MOVBreg x)) -> (MOVBZreg x)
+
+// H - there are more combinations than these
+
+(MOVHZreg y:(MOVHZreg _)) -> y // repeat
+(MOVHZreg y:(MOVBZreg _)) -> y // wide of narrow
+
+(MOVHreg y:(MOVHreg _)) -> y // repeat
+(MOVHreg y:(MOVBreg _)) -> y // wide of narrow
+
+(MOVHreg y:(MOVHZreg x)) -> (MOVHreg x)
+(MOVHZreg y:(MOVHreg x)) -> (MOVHZreg x)
+
+// W - there are more combinations than these
+
+(MOVWZreg y:(MOVWZreg _)) -> y // repeat
+(MOVWZreg y:(MOVHZreg _)) -> y // wide of narrow
+(MOVWZreg y:(MOVBZreg _)) -> y // wide of narrow
+
+(MOVWreg y:(MOVWreg _)) -> y // repeat
+(MOVWreg y:(MOVHreg _)) -> y // wide of narrow
+(MOVWreg y:(MOVBreg _)) -> y // wide of narrow
+
+(MOVWreg y:(MOVWZreg x)) -> (MOVWreg x)
+(MOVWZreg y:(MOVWreg x)) -> (MOVWZreg x)
+
+// 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
+(SUB x (MOVDconst [c])) && is32Bit(-c) -> (ADDconst [-c] x)
+// TODO deal with subtract-from-const
+
+(ADDconst [c] (MOVDaddr [d] {sym} x)) -> (MOVDaddr [c+d] {sym} x)
+
+// Fold offsets for stores.
+(MOVDstore [off1] {sym} (ADDconst [off2] x) val mem) && is16Bit(off1+off2) -> (MOVDstore [off1+off2] {sym} x val mem)
+(MOVWstore [off1] {sym} (ADDconst [off2] x) val mem) && is16Bit(off1+off2) -> (MOVWstore [off1+off2] {sym} x val mem)
+(MOVHstore [off1] {sym} (ADDconst [off2] x) val mem) && is16Bit(off1+off2) -> (MOVHstore [off1+off2] {sym} x val mem)
+(MOVBstore [off1] {sym} (ADDconst [off2] x) val mem) && is16Bit(off1+off2) -> (MOVBstore [off1+off2] {sym} x val mem)
+
+(FMOVSstore [off1] {sym} (ADDconst [off2] ptr) val mem) && is16Bit(off1+off2) -> (FMOVSstore [off1+off2] {sym} ptr val mem)
+(FMOVDstore [off1] {sym} (ADDconst [off2] ptr) val mem) && is16Bit(off1+off2) -> (FMOVDstore [off1+off2] {sym} ptr val mem)
+
+(MOVBstore [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) val mem) && canMergeSym(sym1,sym2) ->
+ (MOVBstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
+(MOVHstore [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) val mem) && canMergeSym(sym1,sym2) ->
+ (MOVHstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
+(MOVWstore [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) val mem) && canMergeSym(sym1,sym2) ->
+ (MOVWstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
+(MOVDstore [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) val mem) && canMergeSym(sym1,sym2) ->
+ (MOVDstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
+
+(FMOVSstore [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) val mem) && canMergeSym(sym1,sym2) ->
+ (FMOVSstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
+(FMOVDstore [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) val mem) && canMergeSym(sym1,sym2) ->
+ (FMOVDstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
+
+(MOVBZload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) ->
+ (MOVBZload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
+(MOVHload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) ->
+ (MOVHload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
+(MOVHZload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) ->
+ (MOVHZload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
+(MOVWload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) ->
+ (MOVWload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
+(MOVWZload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) ->
+ (MOVWZload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
+(MOVDload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) ->
+ (MOVDload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
+(FMOVSload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) ->
+ (FMOVSload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
+(FMOVDload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) ->
+ (FMOVDload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
+
+// Fold offsets for loads.
+(FMOVSload [off1] {sym} (ADDconst [off2] ptr) mem) && is16Bit(off1+off2) -> (FMOVSload [off1+off2] {sym} ptr mem)
+(FMOVDload [off1] {sym} (ADDconst [off2] ptr) mem) && is16Bit(off1+off2) -> (FMOVDload [off1+off2] {sym} ptr mem)
+
+(MOVDload [off1] {sym} (ADDconst [off2] x) mem) && is16Bit(off1+off2) -> (MOVDload [off1+off2] {sym} x mem)
+(MOVWload [off1] {sym} (ADDconst [off2] x) mem) && is16Bit(off1+off2) -> (MOVWload [off1+off2] {sym} x mem)
+(MOVWZload [off1] {sym} (ADDconst [off2] x) mem) && is16Bit(off1+off2) -> (MOVWZload [off1+off2] {sym} x mem)
+(MOVHload [off1] {sym} (ADDconst [off2] x) mem) && is16Bit(off1+off2) -> (MOVHload [off1+off2] {sym} x mem)
+(MOVHZload [off1] {sym} (ADDconst [off2] x) mem) && is16Bit(off1+off2) -> (MOVHZload [off1+off2] {sym} x mem)
+(MOVBZload [off1] {sym} (ADDconst [off2] x) mem) && is16Bit(off1+off2) -> (MOVBZload [off1+off2] {sym} x mem)
+
+// Store of zero -> storezero
+(MOVDstore [off] {sym} ptr (MOVDconst [c]) mem) && c == 0 -> (MOVDstorezero [off] {sym} ptr mem)
+(MOVWstore [off] {sym} ptr (MOVDconst [c]) mem) && c == 0 -> (MOVWstorezero [off] {sym} ptr mem)
+(MOVHstore [off] {sym} ptr (MOVDconst [c]) mem) && c == 0 -> (MOVHstorezero [off] {sym} ptr mem)
+(MOVBstore [off] {sym} ptr (MOVDconst [c]) mem) && c == 0 -> (MOVBstorezero [off] {sym} ptr mem)
+
+// Fold offsets for storezero
+(MOVDstorezero [off1] {sym} (ADDconst [off2] x) mem) && is16Bit(off1+off2) ->
+ (MOVDstorezero [off1+off2] {sym} x mem)
+(MOVWstorezero [off1] {sym} (ADDconst [off2] x) mem) && is16Bit(off1+off2) ->
+ (MOVWstorezero [off1+off2] {sym} x mem)
+(MOVHstorezero [off1] {sym} (ADDconst [off2] x) mem) && is16Bit(off1+off2) ->
+ (MOVHstorezero [off1+off2] {sym} x mem)
+(MOVBstorezero [off1] {sym} (ADDconst [off2] x) mem) && is16Bit(off1+off2) ->
+ (MOVBstorezero [off1+off2] {sym} x mem)
+
+// Fold symbols into storezero
+(MOVDstorezero [off1] {sym1} (MOVDaddr [off2] {sym2} x) mem) && canMergeSym(sym1,sym2) ->
+ (MOVDstorezero [off1+off2] {mergeSym(sym1,sym2)} x mem)
+(MOVWstorezero [off1] {sym1} (MOVDaddr [off2] {sym2} x) mem) && canMergeSym(sym1,sym2) ->
+ (MOVWstorezero [off1+off2] {mergeSym(sym1,sym2)} x mem)
+(MOVHstorezero [off1] {sym1} (MOVDaddr [off2] {sym2} x) mem) && canMergeSym(sym1,sym2) ->
+ (MOVHstorezero [off1+off2] {mergeSym(sym1,sym2)} x mem)
+(MOVBstorezero [off1] {sym1} (MOVDaddr [off2] {sym2} x) mem) && canMergeSym(sym1,sym2) ->
+ (MOVBstorezero [off1+off2] {mergeSym(sym1,sym2)} x 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)
+(SignExt8to32 x) -> (MOVBreg x)
+(SignExt8to64 x) -> (MOVBreg x)
+(SignExt16to32 x) -> (MOVHreg x)
+(SignExt16to64 x) -> (MOVHreg x)
+(SignExt32to64 x) -> (MOVWreg x)
+
+(ZeroExt8to16 x) -> (MOVBZreg x)
+(ZeroExt8to32 x) -> (MOVBZreg x)
+(ZeroExt8to64 x) -> (MOVBZreg x)
+(ZeroExt16to32 x) -> (MOVHZreg x)
+(ZeroExt16to64 x) -> (MOVHZreg x)
+(ZeroExt32to64 x) -> (MOVWZreg x)
+
+(Trunc16to8 x) -> (MOVBreg x)
+(Trunc32to8 x) -> (MOVBreg x)
+(Trunc32to16 x) -> (MOVHreg x)
+(Trunc64to8 x) -> (MOVBreg x)
+(Trunc64to16 x) -> (MOVHreg x)
+(Trunc64to32 x) -> (MOVWreg x)
+
+(Slicemask <t> x) -> (XORconst [-1] (SRADconst <t> (ADDconst <t> x [-1]) [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)
+(MOVBZreg x:(MOVBZload _ _)) -> x
+(MOVHZreg x:(MOVHZload _ _)) -> x
+(MOVHreg x:(MOVHload _ _)) -> x
+
+(MOVBZreg (MOVDconst [c])) -> (MOVDconst [int64(uint8(c))])
+(MOVBreg (MOVDconst [c])) -> (MOVDconst [int64(int8(c))])
+(MOVHZreg (MOVDconst [c])) -> (MOVDconst [int64(uint16(c))])
+(MOVHreg (MOVDconst [c])) -> (MOVDconst [int64(int16(c))])
+
+// Lose widening ops fed to to stores
+(MOVBstore [off] {sym} ptr (MOVBreg x) mem) -> (MOVBstore [off] {sym} ptr x mem)
+(MOVBstore [off] {sym} ptr (MOVBZreg x) mem) -> (MOVBstore [off] {sym} ptr x mem)
+(MOVHstore [off] {sym} ptr (MOVHreg x) mem) -> (MOVHstore [off] {sym} ptr x mem)
+(MOVHstore [off] {sym} ptr (MOVHZreg x) mem) -> (MOVHstore [off] {sym} ptr x mem)
+(MOVWstore [off] {sym} ptr (MOVWreg x) mem) -> (MOVWstore [off] {sym} ptr x mem)
+(MOVWstore [off] {sym} ptr (MOVWZreg x) mem) -> (MOVWstore [off] {sym} ptr x mem)
+
+// Lose W-widening ops fed to compare-W
+(CMPW x (MOVWreg y)) -> (CMPW x y)
+(CMPW (MOVWreg x) y) -> (CMPW x y)
+(CMPWU x (MOVWZreg y)) -> (CMPWU x y)
+(CMPWU (MOVWZreg x) y) -> (CMPWU x y)
+
+(CMP x (MOVDconst [c])) && is16Bit(c) -> (CMPconst x [c])
+(CMP (MOVDconst [c]) y) && is16Bit(c) -> (InvertFlags (CMPconst y [c]))
+(CMPW x (MOVDconst [c])) && is16Bit(c) -> (CMPWconst x [c])
+(CMPW (MOVDconst [c]) y) && is16Bit(c) -> (InvertFlags (CMPWconst y [c]))
+
+(CMPU x (MOVDconst [c])) && isU16Bit(c) -> (CMPUconst x [c])
+(CMPU (MOVDconst [c]) y) && isU16Bit(c) -> (InvertFlags (CMPUconst y [c]))
+(CMPWU x (MOVDconst [c])) && isU16Bit(c) -> (CMPWUconst x [c])
+(CMPWU (MOVDconst [c]) y) && isU16Bit(c) -> (InvertFlags (CMPWUconst y [c]))
+
+// 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)
diff --git a/src/cmd/compile/internal/ssa/gen/PPC64Ops.go b/src/cmd/compile/internal/ssa/gen/PPC64Ops.go
new file mode 100644
index 0000000..d7a1363
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/gen/PPC64Ops.go
@@ -0,0 +1,398 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build ignore
+
+package main
+
+import "strings"
+
+// Notes:
+// - Less-than-64-bit integer types live in the low portion of registers.
+// For now, the upper portion is junk; sign/zero-extension might be optimized in the future, but not yet.
+// - Boolean types are zero or 1; stored in a byte, but loaded with AMOVBZ so the upper bytes of a register are zero.
+// - *const instructions may use a constant larger than the instuction can encode.
+// In this case the assembler expands to multiple instructions and uses tmp
+// register (R31).
+
+var regNamesPPC64 = []string{
+ "R0", // REGZERO, not used, but simplifies counting in regalloc
+ "SP", // REGSP
+ "SB", // REGSB
+ "R3",
+ "R4",
+ "R5",
+ "R6",
+ "R7",
+ "R8",
+ "R9",
+ "R10",
+ "R11", // REGCTXT for closures
+ "R12",
+ "R13", // REGTLS
+ "R14",
+ "R15",
+ "R16",
+ "R17",
+ "R18",
+ "R19",
+ "R20",
+ "R21",
+ "R22",
+ "R23",
+ "R24",
+ "R25",
+ "R26",
+ "R27",
+ "R28",
+ "R29",
+ "g", // REGG. Using name "g" and setting Config.hasGReg makes it "just happen".
+ "R31", // REGTMP
+
+ "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",
+
+ // "CR0",
+ // "CR1",
+ // "CR2",
+ // "CR3",
+ // "CR4",
+ // "CR5",
+ // "CR6",
+ // "CR7",
+
+ // "CR",
+ // "XER",
+ // "LR",
+ // "CTR",
+}
+
+func init() {
+ // Make map from reg names to reg integers.
+ if len(regNamesPPC64) > 64 {
+ panic("too many registers")
+ }
+ num := map[string]int{}
+ for i, name := range regNamesPPC64 {
+ num[name] = i
+ }
+ buildReg := func(s string) regMask {
+ m := regMask(0)
+ for _, r := range strings.Split(s, " ") {
+ if n, ok := num[r]; ok {
+ m |= regMask(1) << uint(n)
+ continue
+ }
+ panic("register " + r + " not found")
+ }
+ return m
+ }
+
+ var (
+ gp = buildReg("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")
+ fp = buildReg("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")
+ sp = buildReg("SP")
+ sb = buildReg("SB")
+ gr = buildReg("g")
+ // cr = buildReg("CR")
+ // ctr = buildReg("CTR")
+ // lr = buildReg("LR")
+ tmp = buildReg("R31")
+ ctxt = buildReg("R11")
+ // tls = buildReg("R13")
+ gp01 = regInfo{inputs: nil, outputs: []regMask{gp}}
+ gp11 = regInfo{inputs: []regMask{gp | sp | sb}, outputs: []regMask{gp}}
+ gp21 = regInfo{inputs: []regMask{gp | sp | sb, gp | sp | sb}, outputs: []regMask{gp}}
+ gp1cr = regInfo{inputs: []regMask{gp | sp | sb}}
+ gp2cr = regInfo{inputs: []regMask{gp | sp | sb, gp | sp | sb}}
+ crgp = regInfo{inputs: nil, outputs: []regMask{gp}}
+ 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
+ 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}}
+ 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: "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)
+
+ {name: "MULHD", argLength: 2, reg: gp21, asm: "MULHD", commutative: true}, // (arg0 * arg1) >> 64, signed
+ {name: "MULHW", argLength: 2, reg: gp21, asm: "MULHW", commutative: true}, // (arg0 * arg1) >> 32, signed
+ {name: "MULHDU", argLength: 2, reg: gp21, asm: "MULHDU", commutative: true}, // (arg0 * arg1) >> 64, unsigned
+ {name: "MULHWU", argLength: 2, reg: gp21, asm: "MULHWU", commutative: true}, // (arg0 * arg1) >> 32, unsigned
+
+ {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: "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)
+ {name: "SRW", argLength: 2, reg: gp21, asm: "SRW"}, // arg0 >> arg1, 32 bits (0 if arg1 & 32 != 0)
+ {name: "SLD", argLength: 2, reg: gp21, asm: "SLD"}, // arg0 << arg1, 64 bits (0 if arg1 & 64 != 0)
+ {name: "SLW", argLength: 2, reg: gp21, asm: "SLW"}, // arg0 << arg1, 32 bits (0 if arg1 & 32 != 0)
+
+ {name: "ADDconstForCarry", argLength: 1, reg: regInfo{inputs: []regMask{gp | sp | sb}, clobbers: tmp}, aux: "Int16", asm: "ADDC", typ: "Flags"}, // _, carry := arg0 + aux
+ {name: "MaskIfNotCarry", argLength: 1, reg: crgp, asm: "ADDME", typ: "Int64"}, // carry - 1 (if carry then 0 else -1)
+
+ {name: "SRADconst", argLength: 1, reg: gp11, asm: "SRAD", aux: "Int64"}, // arg0 >>a aux, 64 bits
+ {name: "SRAWconst", argLength: 1, reg: gp11, asm: "SRAW", aux: "Int64"}, // arg0 >>a aux, 32 bits
+ {name: "SRDconst", argLength: 1, reg: gp11, asm: "SRD", aux: "Int64"}, // arg0 >> aux, 64 bits
+ {name: "SRWconst", argLength: 1, reg: gp11, asm: "SRW", aux: "Int64"}, // arg0 >> aux, 32 bits
+ {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: "FDIV", argLength: 2, reg: fp21, asm: "FDIV"}, // arg0/arg1
+ {name: "FDIVS", argLength: 2, reg: fp21, asm: "FDIVS"}, // arg0/arg1
+
+ {name: "DIVD", argLength: 2, reg: gp21, asm: "DIVD", typ: "Int64"}, // arg0/arg1 (signed 64-bit)
+ {name: "DIVW", argLength: 2, reg: gp21, asm: "DIVW", typ: "Int32"}, // arg0/arg1 (signed 32-bit)
+ {name: "DIVDU", argLength: 2, reg: gp21, asm: "DIVDU", typ: "Int64"}, // arg0/arg1 (unsigned 64-bit)
+ {name: "DIVWU", argLength: 2, reg: gp21, asm: "DIVWU", typ: "Int32"}, // arg0/arg1 (unsigned 32-bit)
+
+ // MOD is implemented as rem := arg0 - (arg0/arg1) * arg1
+
+ // Conversions are all float-to-float register operations. "Integer" refers to encoding in the FP register.
+ {name: "FCTIDZ", argLength: 1, reg: fp11, asm: "FCTIDZ", typ: "Float64"}, // convert float to 64-bit int round towards zero
+ {name: "FCTIWZ", argLength: 1, reg: fp11, asm: "FCTIWZ", typ: "Float64"}, // convert float to 32-bit int round towards zero
+ {name: "FCFID", argLength: 1, reg: fp11, asm: "FCFID", typ: "Float64"}, // convert 64-bit integer to float
+ {name: "FRSP", argLength: 1, reg: fp11, asm: "FRSP", typ: "Float64"}, // round float to 32-bit value
+
+ // Movement between float and integer registers with no change in bits; accomplished with stores+loads on PPC.
+ // Because the 32-bit load-literal-bits instructions have impoverished addressability, always widen the
+ // data instead and use FMOVDload and FMOVDstore instead (this will also dodge endianess issues).
+ // 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: "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: "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)
+ {name: "FNEG", argLength: 1, reg: fp11, asm: "FNEG"}, // -arg0 (floating point)
+ {name: "FSQRT", argLength: 1, reg: fp11, asm: "FSQRT"}, // sqrt(arg0) (floating point)
+ {name: "FSQRTS", argLength: 1, reg: fp11, asm: "FSQRTS"}, // sqrt(arg0) (floating point, single precision)
+
+ {name: "ORconst", argLength: 1, reg: gp11, asm: "OR", aux: "Int64"}, // arg0|aux
+ {name: "XORconst", argLength: 1, reg: gp11, asm: "XOR", aux: "Int64"}, // arg0^aux
+ {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: "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}, //
+ {name: "FMOVSconst", argLength: 0, reg: fp01, aux: "Float32", asm: "FMOVS", rematerializeable: true}, //
+ {name: "FCMPU", argLength: 2, reg: fp2cr, asm: "FCMPU", typ: "Flags"},
+
+ {name: "CMP", argLength: 2, reg: gp2cr, asm: "CMP", typ: "Flags"}, // arg0 compare to arg1
+ {name: "CMPU", argLength: 2, reg: gp2cr, asm: "CMPU", typ: "Flags"}, // arg0 compare to arg1
+ {name: "CMPW", argLength: 2, reg: gp2cr, asm: "CMPW", typ: "Flags"}, // arg0 compare to arg1
+ {name: "CMPWU", argLength: 2, reg: gp2cr, asm: "CMPWU", typ: "Flags"}, // arg0 compare to arg1
+ {name: "CMPconst", argLength: 1, reg: gp1cr, asm: "CMP", aux: "Int64", typ: "Flags"},
+ {name: "CMPUconst", argLength: 1, reg: gp1cr, asm: "CMPU", aux: "Int64", typ: "Flags"},
+ {name: "CMPWconst", argLength: 1, reg: gp1cr, asm: "CMPW", aux: "Int32", typ: "Flags"},
+ {name: "CMPWUconst", argLength: 1, reg: gp1cr, asm: "CMPWU", aux: "Int32", typ: "Flags"},
+
+ // pseudo-ops
+ {name: "Equal", argLength: 1, reg: crgp}, // bool, true flags encode x==y false otherwise.
+ {name: "NotEqual", argLength: 1, reg: crgp}, // bool, true flags encode x!=y false otherwise.
+ {name: "LessThan", argLength: 1, reg: crgp}, // bool, true flags encode x<y false otherwise.
+ {name: "FLessThan", argLength: 1, reg: crgp}, // bool, true flags encode x<y false otherwise.
+ {name: "LessEqual", argLength: 1, reg: crgp}, // bool, true flags encode x<=y false otherwise.
+ {name: "FLessEqual", argLength: 1, reg: crgp}, // bool, true flags encode x<=y false otherwise; PPC <= === !> which is wrong for NaN
+ {name: "GreaterThan", argLength: 1, reg: crgp}, // bool, true flags encode x>y false otherwise.
+ {name: "FGreaterThan", argLength: 1, reg: crgp}, // bool, true flags encode x>y false otherwise.
+ {name: "GreaterEqual", argLength: 1, reg: crgp}, // bool, true flags encode x>=y false otherwise.
+ {name: "FGreaterEqual", argLength: 1, reg: crgp}, // bool, true flags encode x>=y false otherwise.; PPC >= === !< which is wrong for NaN
+
+ // Scheduler ensures LoweredGetClosurePtr occurs only in entry block,
+ // and sorts it to the very beginning of the block to prevent other
+ // use of the closure pointer.
+ {name: "LoweredGetClosurePtr", reg: regInfo{outputs: []regMask{ctxt}}},
+
+ //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},
+
+ // 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: "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)
+ {
+ name: "LoweredZero",
+ aux: "Int64",
+ argLength: 3,
+ reg: regInfo{
+ inputs: []regMask{buildReg("R3"), gp},
+ clobbers: buildReg("R3"),
+ },
+ clobberFlags: true,
+ typ: "Mem",
+ faultOnNilArg0: true,
+ },
+
+ // 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,
+ reg: regInfo{
+ inputs: []regMask{buildReg("R3"), buildReg("R4"), gp},
+ clobbers: buildReg("R3 R4"),
+ },
+ clobberFlags: true,
+ typ: "Mem",
+ faultOnNilArg0: true,
+ faultOnNilArg1: 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.
+ // Rewrites will convert this to (GreaterThan (CMP b a)).
+ // InvertFlags is a pseudo-op which can't appear in assembly output.
+ {name: "InvertFlags", argLength: 1}, // reverse direction of arg0
+
+ // Constant flag values. For any comparison, there are 3 possible
+ // outcomes: either the three from the signed total order (<,==,>)
+ // or the three from the unsigned total order, depending on which
+ // comparison operation was used (CMP or CMPU -- PPC is different from
+ // the other architectures, which have a single comparison producing
+ // both signed and unsigned comparison results.)
+
+ // These ops are for temporary use by rewrite rules. They
+ // cannot appear in the generated assembly.
+ {name: "FlagEQ"}, // equal
+ {name: "FlagLT"}, // signed < or unsigned <
+ {name: "FlagGT"}, // signed > or unsigned >
+
+ }
+
+ blocks := []blockData{
+ {name: "EQ"},
+ {name: "NE"},
+ {name: "LT"},
+ {name: "LE"},
+ {name: "GT"},
+ {name: "GE"},
+ {name: "FLT"},
+ {name: "FLE"},
+ {name: "FGT"},
+ {name: "FGE"},
+ }
+
+ archs = append(archs, arch{
+ name: "PPC64",
+ pkg: "cmd/internal/obj/ppc64",
+ genfile: "../../ppc64/ssa.go",
+ ops: ops,
+ blocks: blocks,
+ regnames: regNamesPPC64,
+ gpregmask: gp,
+ fpregmask: fp,
+ framepointerreg: int8(num["SP"]),
+ linkreg: -1, // not used
+ })
+}
diff --git a/src/cmd/compile/internal/ssa/gen/S390X.rules b/src/cmd/compile/internal/ssa/gen/S390X.rules
new file mode 100644
index 0000000..3e0533a
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/gen/S390X.rules
@@ -0,0 +1,1649 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Lowering arithmetic
+(Add64 x y) -> (ADD x y)
+(AddPtr x y) -> (ADD x y)
+(Add32 x y) -> (ADDW x y)
+(Add16 x y) -> (ADDW x y)
+(Add8 x y) -> (ADDW x y)
+(Add32F x y) -> (FADDS x y)
+(Add64F x y) -> (FADD x y)
+
+(Sub64 x y) -> (SUB x y)
+(SubPtr x y) -> (SUB x y)
+(Sub32 x y) -> (SUBW x y)
+(Sub16 x y) -> (SUBW x y)
+(Sub8 x y) -> (SUBW x y)
+(Sub32F x y) -> (FSUBS x y)
+(Sub64F x y) -> (FSUB x y)
+
+(Mul64 x y) -> (MULLD x y)
+(Mul32 x y) -> (MULLW x y)
+(Mul16 x y) -> (MULLW x y)
+(Mul8 x y) -> (MULLW x y)
+(Mul32F x y) -> (FMULS x y)
+(Mul64F x y) -> (FMUL x y)
+
+(Div32F x y) -> (FDIVS x y)
+(Div64F x y) -> (FDIV x y)
+
+(Div64 x y) -> (DIVD x y)
+(Div64u x y) -> (DIVDU x y)
+// DIVW/DIVWU has a 64-bit dividend and a 32-bit divisor,
+// so a sign/zero extension of the dividend is required.
+(Div32 x y) -> (DIVW (MOVWreg x) y)
+(Div32u x y) -> (DIVWU (MOVWZreg x) y)
+(Div16 x y) -> (DIVW (MOVHreg x) (MOVHreg y))
+(Div16u x y) -> (DIVWU (MOVHZreg x) (MOVHZreg y))
+(Div8 x y) -> (DIVW (MOVBreg x) (MOVBreg y))
+(Div8u x y) -> (DIVWU (MOVBZreg x) (MOVBZreg y))
+
+(Hmul64 x y) -> (MULHD x y)
+(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)
+// MODW/MODWU has a 64-bit dividend and a 32-bit divisor,
+// so a sign/zero extension of the dividend is required.
+(Mod32 x y) -> (MODW (MOVWreg x) y)
+(Mod32u x y) -> (MODWU (MOVWZreg x) y)
+(Mod16 x y) -> (MODW (MOVHreg x) (MOVHreg y))
+(Mod16u x y) -> (MODWU (MOVHZreg x) (MOVHZreg y))
+(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]))
+
+(And64 x y) -> (AND x y)
+(And32 x y) -> (ANDW x y)
+(And16 x y) -> (ANDW x y)
+(And8 x y) -> (ANDW x y)
+
+(Or64 x y) -> (OR x y)
+(Or32 x y) -> (ORW x y)
+(Or16 x y) -> (ORW x y)
+(Or8 x y) -> (ORW x y)
+
+(Xor64 x y) -> (XOR x y)
+(Xor32 x y) -> (XORW x y)
+(Xor16 x y) -> (XORW x y)
+(Xor8 x y) -> (XORW x y)
+
+(Neg64 x) -> (NEG x)
+(Neg32 x) -> (NEGW x)
+(Neg16 x) -> (NEGW (MOVHreg x))
+(Neg8 x) -> (NEGW (MOVBreg x))
+(Neg32F x) -> (FNEGS x)
+(Neg64F x) -> (FNEG x)
+
+(Com64 x) -> (NOT x)
+(Com32 x) -> (NOTW x)
+(Com16 x) -> (NOTW x)
+(Com8 x) -> (NOTW x)
+(NOT x) && true -> (XOR (MOVDconst [-1]) x)
+(NOTW x) && true -> (XORWconst [-1] x)
+
+// Lowering boolean ops
+(AndB x y) -> (ANDW x y)
+(OrB x y) -> (ORW x y)
+(Not x) -> (XORWconst [1] x)
+
+// Lowering pointer arithmetic
+(OffPtr [off] ptr:(SP)) -> (MOVDaddr [off] ptr)
+(OffPtr [off] ptr) && is32Bit(off) -> (ADDconst [off] ptr)
+(OffPtr [off] ptr) -> (ADD (MOVDconst [off]) ptr)
+
+// Ctz(x) = 64 - findLeftmostOne((x-1)&^x)
+(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)))))
+
+(Bswap64 x) -> (MOVDBR x)
+(Bswap32 x) -> (MOVWBR x)
+
+(Sqrt x) -> (FSQRT x)
+
+// Atomic loads.
+(AtomicLoad32 ptr mem) -> (MOVWZatomicload ptr mem)
+(AtomicLoad64 ptr mem) -> (MOVDatomicload ptr mem)
+(AtomicLoadPtr ptr mem) -> (MOVDatomicload ptr mem)
+
+// Atomic stores.
+(AtomicStore32 ptr val mem) -> (MOVWatomicstore ptr val mem)
+(AtomicStore64 ptr val mem) -> (MOVDatomicstore ptr val mem)
+(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)
+
+// Atomic exchanges.
+(AtomicExchange32 ptr val mem) -> (LoweredAtomicExchange32 ptr val mem)
+(AtomicExchange64 ptr val mem) -> (LoweredAtomicExchange64 ptr val mem)
+
+// Atomic compare and swap.
+(AtomicCompareAndSwap32 ptr old new_ mem) -> (LoweredAtomicCas32 ptr old new_ mem)
+(AtomicCompareAndSwap64 ptr old new_ mem) -> (LoweredAtomicCas64 ptr old new_ 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)
+(SignExt8to32 x) -> (MOVBreg x)
+(SignExt8to64 x) -> (MOVBreg x)
+(SignExt16to32 x) -> (MOVHreg x)
+(SignExt16to64 x) -> (MOVHreg x)
+(SignExt32to64 x) -> (MOVWreg x)
+
+(ZeroExt8to16 x) -> (MOVBZreg x)
+(ZeroExt8to32 x) -> (MOVBZreg x)
+(ZeroExt8to64 x) -> (MOVBZreg x)
+(ZeroExt16to32 x) -> (MOVHZreg x)
+(ZeroExt16to64 x) -> (MOVHZreg x)
+(ZeroExt32to64 x) -> (MOVWZreg x)
+
+(Slicemask <t> x) -> (XOR (MOVDconst [-1]) (SRADconst <t> (SUBconst <t> x [1]) [63]))
+
+// Lowering truncation
+// Because we ignore high parts of registers, truncates are just copies.
+(Trunc16to8 x) -> x
+(Trunc32to8 x) -> x
+(Trunc32to16 x) -> x
+(Trunc64to8 x) -> x
+(Trunc64to16 x) -> x
+(Trunc64to32 x) -> x
+
+// Lowering float <-> int
+(Cvt32to32F x) -> (CEFBRA x)
+(Cvt32to64F x) -> (CDFBRA x)
+(Cvt64to32F x) -> (CEGBRA x)
+(Cvt64to64F x) -> (CDGBRA x)
+
+(Cvt32Fto32 x) -> (CFEBRA x)
+(Cvt32Fto64 x) -> (CGEBRA x)
+(Cvt64Fto32 x) -> (CFDBRA x)
+(Cvt64Fto64 x) -> (CGDBRA x)
+
+(Cvt32Fto64F x) -> (LDEBR x)
+(Cvt64Fto32F x) -> (LEDBR x)
+
+// Lowering shifts
+// Unsigned shifts need to return 0 if shift amount is >= width of shifted value.
+// result = (arg << shift) & (shift >= argbits ? 0 : 0xffffffffffffffff)
+(Lsh64x64 <t> x y) -> (AND (SLD <t> x y) (SUBEcarrymask <t> (CMPUconst y [63])))
+(Lsh64x32 <t> x y) -> (AND (SLD <t> x y) (SUBEcarrymask <t> (CMPWUconst y [63])))
+(Lsh64x16 <t> x y) -> (AND (SLD <t> x y) (SUBEcarrymask <t> (CMPWUconst (MOVHZreg y) [63])))
+(Lsh64x8 <t> x y) -> (AND (SLD <t> x y) (SUBEcarrymask <t> (CMPWUconst (MOVBZreg y) [63])))
+
+(Lsh32x64 <t> x y) -> (ANDW (SLW <t> x y) (SUBEWcarrymask <t> (CMPUconst y [31])))
+(Lsh32x32 <t> x y) -> (ANDW (SLW <t> x y) (SUBEWcarrymask <t> (CMPWUconst y [31])))
+(Lsh32x16 <t> x y) -> (ANDW (SLW <t> x y) (SUBEWcarrymask <t> (CMPWUconst (MOVHZreg y) [31])))
+(Lsh32x8 <t> x y) -> (ANDW (SLW <t> x y) (SUBEWcarrymask <t> (CMPWUconst (MOVBZreg y) [31])))
+
+(Lsh16x64 <t> x y) -> (ANDW (SLW <t> x y) (SUBEWcarrymask <t> (CMPUconst y [31])))
+(Lsh16x32 <t> x y) -> (ANDW (SLW <t> x y) (SUBEWcarrymask <t> (CMPWUconst y [31])))
+(Lsh16x16 <t> x y) -> (ANDW (SLW <t> x y) (SUBEWcarrymask <t> (CMPWUconst (MOVHZreg y) [31])))
+(Lsh16x8 <t> x y) -> (ANDW (SLW <t> x y) (SUBEWcarrymask <t> (CMPWUconst (MOVBZreg y) [31])))
+
+(Lsh8x64 <t> x y) -> (ANDW (SLW <t> x y) (SUBEWcarrymask <t> (CMPUconst y [31])))
+(Lsh8x32 <t> x y) -> (ANDW (SLW <t> x y) (SUBEWcarrymask <t> (CMPWUconst y [31])))
+(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])))
+(Rsh64Ux8 <t> x y) -> (AND (SRD <t> x y) (SUBEcarrymask <t> (CMPWUconst (MOVBZreg y) [63])))
+
+(Rsh32Ux64 <t> x y) -> (ANDW (SRW <t> x y) (SUBEWcarrymask <t> (CMPUconst y [31])))
+(Rsh32Ux32 <t> x y) -> (ANDW (SRW <t> x y) (SUBEWcarrymask <t> (CMPWUconst y [31])))
+(Rsh32Ux16 <t> x y) -> (ANDW (SRW <t> x y) (SUBEWcarrymask <t> (CMPWUconst (MOVHZreg y) [31])))
+(Rsh32Ux8 <t> x y) -> (ANDW (SRW <t> x y) (SUBEWcarrymask <t> (CMPWUconst (MOVBZreg y) [31])))
+
+(Rsh16Ux64 <t> x y) -> (ANDW (SRW <t> (MOVHZreg x) y) (SUBEWcarrymask <t> (CMPUconst y [15])))
+(Rsh16Ux32 <t> x y) -> (ANDW (SRW <t> (MOVHZreg x) y) (SUBEWcarrymask <t> (CMPWUconst y [15])))
+(Rsh16Ux16 <t> x y) -> (ANDW (SRW <t> (MOVHZreg x) y) (SUBEWcarrymask <t> (CMPWUconst (MOVHZreg y) [15])))
+(Rsh16Ux8 <t> x y) -> (ANDW (SRW <t> (MOVHZreg x) y) (SUBEWcarrymask <t> (CMPWUconst (MOVBZreg y) [15])))
+
+(Rsh8Ux64 <t> x y) -> (ANDW (SRW <t> (MOVBZreg x) y) (SUBEWcarrymask <t> (CMPUconst y [7])))
+(Rsh8Ux32 <t> x y) -> (ANDW (SRW <t> (MOVBZreg x) y) (SUBEWcarrymask <t> (CMPWUconst y [7])))
+(Rsh8Ux16 <t> x y) -> (ANDW (SRW <t> (MOVBZreg x) y) (SUBEWcarrymask <t> (CMPWUconst (MOVHZreg y) [7])))
+(Rsh8Ux8 <t> x y) -> (ANDW (SRW <t> (MOVBZreg x) y) (SUBEWcarrymask <t> (CMPWUconst (MOVBZreg y) [7])))
+
+// Signed right shift needs to return 0/-1 if shift amount is >= width of shifted value.
+// We implement this by setting the shift value to -1 (all ones) if the shift value is >= width.
+(Rsh64x64 <t> x y) -> (SRAD <t> x (OR <y.Type> y (NOT <y.Type> (SUBEcarrymask <y.Type> (CMPUconst y [63])))))
+(Rsh64x32 <t> x y) -> (SRAD <t> x (ORW <y.Type> y (NOTW <y.Type> (SUBEWcarrymask <y.Type> (CMPWUconst y [63])))))
+(Rsh64x16 <t> x y) -> (SRAD <t> x (ORW <y.Type> y (NOTW <y.Type> (SUBEWcarrymask <y.Type> (CMPWUconst (MOVHZreg y) [63])))))
+(Rsh64x8 <t> x y) -> (SRAD <t> x (ORW <y.Type> y (NOTW <y.Type> (SUBEWcarrymask <y.Type> (CMPWUconst (MOVBZreg y) [63])))))
+
+(Rsh32x64 <t> x y) -> (SRAW <t> x (OR <y.Type> y (NOT <y.Type> (SUBEcarrymask <y.Type> (CMPUconst y [31])))))
+(Rsh32x32 <t> x y) -> (SRAW <t> x (ORW <y.Type> y (NOTW <y.Type> (SUBEWcarrymask <y.Type> (CMPWUconst y [31])))))
+(Rsh32x16 <t> x y) -> (SRAW <t> x (ORW <y.Type> y (NOTW <y.Type> (SUBEWcarrymask <y.Type> (CMPWUconst (MOVHZreg y) [31])))))
+(Rsh32x8 <t> x y) -> (SRAW <t> x (ORW <y.Type> y (NOTW <y.Type> (SUBEWcarrymask <y.Type> (CMPWUconst (MOVBZreg y) [31])))))
+
+(Rsh16x64 <t> x y) -> (SRAW <t> (MOVHreg x) (OR <y.Type> y (NOT <y.Type> (SUBEcarrymask <y.Type> (CMPUconst y [15])))))
+(Rsh16x32 <t> x y) -> (SRAW <t> (MOVHreg x) (ORW <y.Type> y (NOTW <y.Type> (SUBEWcarrymask <y.Type> (CMPWUconst y [15])))))
+(Rsh16x16 <t> x y) -> (SRAW <t> (MOVHreg x) (ORW <y.Type> y (NOTW <y.Type> (SUBEWcarrymask <y.Type> (CMPWUconst (MOVHZreg y) [15])))))
+(Rsh16x8 <t> x y) -> (SRAW <t> (MOVHreg x) (ORW <y.Type> y (NOTW <y.Type> (SUBEWcarrymask <y.Type> (CMPWUconst (MOVBZreg y) [15])))))
+
+(Rsh8x64 <t> x y) -> (SRAW <t> (MOVBreg x) (OR <y.Type> y (NOT <y.Type> (SUBEcarrymask <y.Type> (CMPUconst y [7])))))
+(Rsh8x32 <t> x y) -> (SRAW <t> (MOVBreg x) (ORW <y.Type> y (NOTW <y.Type> (SUBEWcarrymask <y.Type> (CMPWUconst y [7])))))
+(Rsh8x16 <t> x y) -> (SRAW <t> (MOVBreg x) (ORW <y.Type> y (NOTW <y.Type> (SUBEWcarrymask <y.Type> (CMPWUconst (MOVHZreg y) [7])))))
+(Rsh8x8 <t> x y) -> (SRAW <t> (MOVBreg x) (ORW <y.Type> y (NOTW <y.Type> (SUBEWcarrymask <y.Type> (CMPWUconst (MOVBZreg y) [7])))))
+
+// Lowering comparisons
+(Less64 x y) -> (MOVDLT (MOVDconst [0]) (MOVDconst [1]) (CMP x y))
+(Less32 x y) -> (MOVDLT (MOVDconst [0]) (MOVDconst [1]) (CMPW x y))
+(Less16 x y) -> (MOVDLT (MOVDconst [0]) (MOVDconst [1]) (CMP (MOVHreg x) (MOVHreg y)))
+(Less8 x y) -> (MOVDLT (MOVDconst [0]) (MOVDconst [1]) (CMP (MOVBreg x) (MOVBreg y)))
+(Less64U x y) -> (MOVDLT (MOVDconst [0]) (MOVDconst [1]) (CMPU x y))
+(Less32U x y) -> (MOVDLT (MOVDconst [0]) (MOVDconst [1]) (CMPWU x y))
+(Less16U x y) -> (MOVDLT (MOVDconst [0]) (MOVDconst [1]) (CMPU (MOVHZreg x) (MOVHZreg y)))
+(Less8U x y) -> (MOVDLT (MOVDconst [0]) (MOVDconst [1]) (CMPU (MOVBZreg x) (MOVBZreg y)))
+// Use SETG with reversed operands to dodge NaN case.
+(Less64F x y) -> (MOVDGTnoinv (MOVDconst [0]) (MOVDconst [1]) (FCMP y x))
+(Less32F x y) -> (MOVDGTnoinv (MOVDconst [0]) (MOVDconst [1]) (FCMPS y x))
+
+(Leq64 x y) -> (MOVDLE (MOVDconst [0]) (MOVDconst [1]) (CMP x y))
+(Leq32 x y) -> (MOVDLE (MOVDconst [0]) (MOVDconst [1]) (CMPW x y))
+(Leq16 x y) -> (MOVDLE (MOVDconst [0]) (MOVDconst [1]) (CMP (MOVHreg x) (MOVHreg y)))
+(Leq8 x y) -> (MOVDLE (MOVDconst [0]) (MOVDconst [1]) (CMP (MOVBreg x) (MOVBreg y)))
+(Leq64U x y) -> (MOVDLE (MOVDconst [0]) (MOVDconst [1]) (CMPU x y))
+(Leq32U x y) -> (MOVDLE (MOVDconst [0]) (MOVDconst [1]) (CMPWU x y))
+(Leq16U x y) -> (MOVDLE (MOVDconst [0]) (MOVDconst [1]) (CMPU (MOVHZreg x) (MOVHZreg y)))
+(Leq8U x y) -> (MOVDLE (MOVDconst [0]) (MOVDconst [1]) (CMPU (MOVBZreg x) (MOVBZreg y)))
+// Use SETGE with reversed operands to dodge NaN case.
+(Leq64F x y) -> (MOVDGEnoinv (MOVDconst [0]) (MOVDconst [1]) (FCMP y x))
+(Leq32F x y) -> (MOVDGEnoinv (MOVDconst [0]) (MOVDconst [1]) (FCMPS y x))
+
+(Greater64 x y) -> (MOVDGT (MOVDconst [0]) (MOVDconst [1]) (CMP x y))
+(Greater32 x y) -> (MOVDGT (MOVDconst [0]) (MOVDconst [1]) (CMPW x y))
+(Greater16 x y) -> (MOVDGT (MOVDconst [0]) (MOVDconst [1]) (CMP (MOVHreg x) (MOVHreg y)))
+(Greater8 x y) -> (MOVDGT (MOVDconst [0]) (MOVDconst [1]) (CMP (MOVBreg x) (MOVBreg y)))
+(Greater64U x y) -> (MOVDGT (MOVDconst [0]) (MOVDconst [1]) (CMPU x y))
+(Greater32U x y) -> (MOVDGT (MOVDconst [0]) (MOVDconst [1]) (CMPWU x y))
+(Greater16U x y) -> (MOVDGT (MOVDconst [0]) (MOVDconst [1]) (CMPU (MOVHZreg x) (MOVHZreg y)))
+(Greater8U x y) -> (MOVDGT (MOVDconst [0]) (MOVDconst [1]) (CMPU (MOVBZreg x) (MOVBZreg y)))
+(Greater64F x y) -> (MOVDGTnoinv (MOVDconst [0]) (MOVDconst [1]) (FCMP x y))
+(Greater32F x y) -> (MOVDGTnoinv (MOVDconst [0]) (MOVDconst [1]) (FCMPS x y))
+
+(Geq64 x y) -> (MOVDGE (MOVDconst [0]) (MOVDconst [1]) (CMP x y))
+(Geq32 x y) -> (MOVDGE (MOVDconst [0]) (MOVDconst [1]) (CMPW x y))
+(Geq16 x y) -> (MOVDGE (MOVDconst [0]) (MOVDconst [1]) (CMP (MOVHreg x) (MOVHreg y)))
+(Geq8 x y) -> (MOVDGE (MOVDconst [0]) (MOVDconst [1]) (CMP (MOVBreg x) (MOVBreg y)))
+(Geq64U x y) -> (MOVDGE (MOVDconst [0]) (MOVDconst [1]) (CMPU x y))
+(Geq32U x y) -> (MOVDGE (MOVDconst [0]) (MOVDconst [1]) (CMPWU x y))
+(Geq16U x y) -> (MOVDGE (MOVDconst [0]) (MOVDconst [1]) (CMPU (MOVHZreg x) (MOVHZreg y)))
+(Geq8U x y) -> (MOVDGE (MOVDconst [0]) (MOVDconst [1]) (CMPU (MOVBZreg x) (MOVBZreg y)))
+(Geq64F x y) -> (MOVDGEnoinv (MOVDconst [0]) (MOVDconst [1]) (FCMP x y))
+(Geq32F x y) -> (MOVDGEnoinv (MOVDconst [0]) (MOVDconst [1]) (FCMPS x y))
+
+(Eq64 x y) -> (MOVDEQ (MOVDconst [0]) (MOVDconst [1]) (CMP x y))
+(Eq32 x y) -> (MOVDEQ (MOVDconst [0]) (MOVDconst [1]) (CMPW x y))
+(Eq16 x y) -> (MOVDEQ (MOVDconst [0]) (MOVDconst [1]) (CMP (MOVHreg x) (MOVHreg y)))
+(Eq8 x y) -> (MOVDEQ (MOVDconst [0]) (MOVDconst [1]) (CMP (MOVBreg x) (MOVBreg y)))
+(EqB x y) -> (MOVDEQ (MOVDconst [0]) (MOVDconst [1]) (CMP (MOVBreg x) (MOVBreg y)))
+(EqPtr x y) -> (MOVDEQ (MOVDconst [0]) (MOVDconst [1]) (CMP x y))
+(Eq64F x y) -> (MOVDEQ (MOVDconst [0]) (MOVDconst [1]) (FCMP x y))
+(Eq32F x y) -> (MOVDEQ (MOVDconst [0]) (MOVDconst [1]) (FCMPS x y))
+
+(Neq64 x y) -> (MOVDNE (MOVDconst [0]) (MOVDconst [1]) (CMP x y))
+(Neq32 x y) -> (MOVDNE (MOVDconst [0]) (MOVDconst [1]) (CMPW x y))
+(Neq16 x y) -> (MOVDNE (MOVDconst [0]) (MOVDconst [1]) (CMP (MOVHreg x) (MOVHreg y)))
+(Neq8 x y) -> (MOVDNE (MOVDconst [0]) (MOVDconst [1]) (CMP (MOVBreg x) (MOVBreg y)))
+(NeqB x y) -> (MOVDNE (MOVDconst [0]) (MOVDconst [1]) (CMP (MOVBreg x) (MOVBreg y)))
+(NeqPtr x y) -> (MOVDNE (MOVDconst [0]) (MOVDconst [1]) (CMP x y))
+(Neq64F x y) -> (MOVDNE (MOVDconst [0]) (MOVDconst [1]) (FCMP x y))
+(Neq32F x y) -> (MOVDNE (MOVDconst [0]) (MOVDconst [1]) (FCMPS x y))
+
+// Lowering loads
+(Load <t> ptr mem) && (is64BitInt(t) || isPtr(t)) -> (MOVDload ptr mem)
+(Load <t> ptr mem) && is32BitInt(t) -> (MOVWZload ptr mem)
+(Load <t> ptr mem) && is16BitInt(t) -> (MOVHZload ptr mem)
+(Load <t> ptr mem) && (t.IsBoolean() || is8BitInt(t)) -> (MOVBZload ptr mem)
+(Load <t> ptr mem) && is32BitFloat(t) -> (FMOVSload ptr mem)
+(Load <t> ptr mem) && is64BitFloat(t) -> (FMOVDload ptr mem)
+
+// 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 [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)
+
+// 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 ->
+ (MOVDstore [8] dst (MOVDload [8] src mem)
+ (MOVDstore dst (MOVDload src mem) mem))
+(Move [s] dst src mem) && SizeAndAlign(s).Size() == 24 ->
+ (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 ->
+ (MOVBstore [2] dst (MOVBZload [2] src mem)
+ (MOVHstore dst (MOVHZload src mem) mem))
+(Move [s] dst src mem) && SizeAndAlign(s).Size() == 5 ->
+ (MOVBstore [4] dst (MOVBZload [4] src mem)
+ (MOVWstore dst (MOVWZload src mem) mem))
+(Move [s] dst src mem) && SizeAndAlign(s).Size() == 6 ->
+ (MOVHstore [4] dst (MOVHZload [4] src mem)
+ (MOVWstore dst (MOVWZload src mem) mem))
+(Move [s] dst src mem) && SizeAndAlign(s).Size() == 7 ->
+ (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 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)
+
+// 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 ->
+ (MOVBstoreconst [makeValAndOff(0,2)] destptr
+ (MOVHstoreconst [0] destptr mem))
+(Zero [s] destptr mem) && SizeAndAlign(s).Size() == 5 ->
+ (MOVBstoreconst [makeValAndOff(0,4)] destptr
+ (MOVWstoreconst [0] destptr mem))
+(Zero [s] destptr mem) && SizeAndAlign(s).Size() == 6 ->
+ (MOVHstoreconst [makeValAndOff(0,4)] destptr
+ (MOVWstoreconst [0] destptr mem))
+(Zero [s] destptr mem) && SizeAndAlign(s).Size() == 7 ->
+ (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)
+
+// 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)
+
+// Lowering constants
+(Const8 [val]) -> (MOVDconst [val])
+(Const16 [val]) -> (MOVDconst [val])
+(Const32 [val]) -> (MOVDconst [val])
+(Const64 [val]) -> (MOVDconst [val])
+(Const32F [val]) -> (FMOVSconst [val])
+(Const64F [val]) -> (FMOVDconst [val])
+(ConstNil) -> (MOVDconst [0])
+(ConstBool [b]) -> (MOVDconst [b])
+
+// Lowering calls
+(StaticCall [argwid] {target} mem) -> (CALLstatic [argwid] {target} mem)
+(ClosureCall [argwid] entry closure mem) -> (CALLclosure [argwid] entry closure mem)
+(DeferCall [argwid] mem) -> (CALLdefer [argwid] mem)
+(GoCall [argwid] mem) -> (CALLgo [argwid] mem)
+(InterCall [argwid] entry mem) -> (CALLinter [argwid] entry mem)
+
+// Miscellaneous
+(Convert <t> x mem) -> (MOVDconvert <t> x mem)
+(IsNonNil p) -> (MOVDNE (MOVDconst [0]) (MOVDconst [1]) (CMPconst p [0]))
+(IsInBounds idx len) -> (MOVDLT (MOVDconst [0]) (MOVDconst [1]) (CMPU idx len))
+(IsSliceInBounds idx len) -> (MOVDLE (MOVDconst [0]) (MOVDconst [1]) (CMPU idx len))
+(NilCheck ptr mem) -> (LoweredNilCheck ptr mem)
+(GetG mem) -> (LoweredGetG mem)
+(GetClosurePtr) -> (LoweredGetClosurePtr)
+(Addr {sym} base) -> (MOVDaddr {sym} base)
+(ITab (Load ptr mem)) -> (MOVDload ptr mem)
+
+// block rewrites
+(If (MOVDLT (MOVDconst [0]) (MOVDconst [1]) cmp) yes no) -> (LT cmp yes no)
+(If (MOVDLE (MOVDconst [0]) (MOVDconst [1]) cmp) yes no) -> (LE cmp yes no)
+(If (MOVDGT (MOVDconst [0]) (MOVDconst [1]) cmp) yes no) -> (GT cmp yes no)
+(If (MOVDGE (MOVDconst [0]) (MOVDconst [1]) cmp) yes no) -> (GE cmp yes no)
+(If (MOVDEQ (MOVDconst [0]) (MOVDconst [1]) cmp) yes no) -> (EQ cmp yes no)
+(If (MOVDNE (MOVDconst [0]) (MOVDconst [1]) cmp) yes no) -> (NE cmp yes no)
+
+// Special case for floating point - LF/LEF not generated.
+(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 cond)) yes no)
+
+// ***************************
+// Above: lowering rules
+// Below: optimizations
+// ***************************
+// TODO: Should the optimizations be a separate pass?
+
+// 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 -> x
+(MOVBZreg x:(MOVDLE (MOVDconst [c]) (MOVDconst [d]) _)) && int64(uint8(c)) == c && int64(uint8(d)) == d -> x
+(MOVBZreg x:(MOVDGT (MOVDconst [c]) (MOVDconst [d]) _)) && int64(uint8(c)) == c && int64(uint8(d)) == d -> x
+(MOVBZreg x:(MOVDGE (MOVDconst [c]) (MOVDconst [d]) _)) && int64(uint8(c)) == c && int64(uint8(d)) == d -> x
+(MOVBZreg x:(MOVDEQ (MOVDconst [c]) (MOVDconst [d]) _)) && int64(uint8(c)) == c && int64(uint8(d)) == d -> x
+(MOVBZreg x:(MOVDNE (MOVDconst [c]) (MOVDconst [d]) _)) && int64(uint8(c)) == c && int64(uint8(d)) == d -> x
+(MOVBZreg x:(MOVDGTnoinv (MOVDconst [c]) (MOVDconst [d]) _)) && int64(uint8(c)) == c && int64(uint8(d)) == d -> x
+(MOVBZreg x:(MOVDGEnoinv (MOVDconst [c]) (MOVDconst [d]) _)) && int64(uint8(c)) == c && int64(uint8(d)) == d -> x
+
+// Fold boolean tests into blocks.
+(NE (CMPWconst [0] (MOVDLT (MOVDconst [0]) (MOVDconst [1]) cmp)) yes no) -> (LT cmp yes no)
+(NE (CMPWconst [0] (MOVDLE (MOVDconst [0]) (MOVDconst [1]) cmp)) yes no) -> (LE cmp yes no)
+(NE (CMPWconst [0] (MOVDGT (MOVDconst [0]) (MOVDconst [1]) cmp)) yes no) -> (GT cmp yes no)
+(NE (CMPWconst [0] (MOVDGE (MOVDconst [0]) (MOVDconst [1]) cmp)) yes no) -> (GE cmp yes no)
+(NE (CMPWconst [0] (MOVDEQ (MOVDconst [0]) (MOVDconst [1]) cmp)) yes no) -> (EQ cmp yes no)
+(NE (CMPWconst [0] (MOVDNE (MOVDconst [0]) (MOVDconst [1]) cmp)) yes no) -> (NE cmp yes no)
+(NE (CMPWconst [0] (MOVDGTnoinv (MOVDconst [0]) (MOVDconst [1]) cmp)) yes no) -> (GTF cmp yes no)
+(NE (CMPWconst [0] (MOVDGEnoinv (MOVDconst [0]) (MOVDconst [1]) cmp)) yes no) -> (GEF cmp yes no)
+
+// 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]))
+(SUBW x (MOVDconst [c])) -> (SUBWconst x [c])
+(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)
+(SRD x (MOVDconst [c])) -> (SRDconst [c&63] x)
+(SRW x (MOVDconst [c])) -> (SRWconst [c&63] x)
+(SRAD x (MOVDconst [c])) -> (SRADconst [c&63] x)
+(SRAW x (MOVDconst [c])) -> (SRAWconst [c&63] x)
+
+(SRAW x (ANDWconst [63] y)) -> (SRAW x y)
+(SRAD x (ANDconst [63] y)) -> (SRAD x y)
+(SLW x (ANDWconst [63] y)) -> (SLW x y)
+(SLD x (ANDconst [63] y)) -> (SLD x y)
+(SRW x (ANDWconst [63] y)) -> (SRW x y)
+(SRD x (ANDconst [63] y)) -> (SRD x y)
+
+(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])
+(CMPW (MOVDconst [c]) x) -> (InvertFlags (CMPWconst x [c]))
+(CMPU x (MOVDconst [c])) && is32Bit(c) -> (CMPUconst x [int64(uint32(c))])
+(CMPU (MOVDconst [c]) x) && is32Bit(c) -> (InvertFlags (CMPUconst x [int64(uint32(c))]))
+(CMPWU x (MOVDconst [c])) -> (CMPWUconst x [int64(uint32(c))])
+(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)
+
+// strength reduction
+(MULLDconst [-1] x) -> (NEG x)
+(MULLDconst [0] _) -> (MOVDconst [0])
+(MULLDconst [1] x) -> x
+(MULLDconst [c] x) && isPowerOfTwo(c) -> (SLDconst [log2(c)] x)
+(MULLDconst [c] x) && isPowerOfTwo(c+1) && c >= 15 -> (SUB (SLDconst <v.Type> [log2(c+1)] x) x)
+(MULLDconst [c] x) && isPowerOfTwo(c-1) && c >= 17 -> (ADD (SLDconst <v.Type> [log2(c-1)] x) x)
+
+(MULLWconst [-1] x) -> (NEGW x)
+(MULLWconst [0] _) -> (MOVDconst [0])
+(MULLWconst [1] x) -> x
+(MULLWconst [c] x) && isPowerOfTwo(c) -> (SLWconst [log2(c)] x)
+(MULLWconst [c] x) && isPowerOfTwo(c+1) && c >= 15 -> (SUBW (SLWconst <v.Type> [log2(c+1)] x) x)
+(MULLWconst [c] x) && isPowerOfTwo(c-1) && c >= 17 -> (ADDW (SLWconst <v.Type> [log2(c-1)] x) x)
+
+// 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)
+
+// fold ADDconst into MOVDaddrx
+(ADDconst [c] (MOVDaddridx [d] {s} x y)) && is20Bit(c+d) -> (MOVDaddridx [c+d] {s} x y)
+(MOVDaddridx [c] {s} (ADDconst [d] x) y) && is20Bit(c+d) && x.Op != OpSB -> (MOVDaddridx [c+d] {s} x y)
+(MOVDaddridx [c] {s} x (ADDconst [d] y)) && is20Bit(c+d) && y.Op != OpSB -> (MOVDaddridx [c+d] {s} x y)
+
+// reverse ordering of compare instruction
+(MOVDLT x y (InvertFlags cmp)) -> (MOVDGT x y cmp)
+(MOVDGT x y (InvertFlags cmp)) -> (MOVDLT x y cmp)
+(MOVDLE x y (InvertFlags cmp)) -> (MOVDGE x y cmp)
+(MOVDGE x y (InvertFlags cmp)) -> (MOVDLE x y cmp)
+(MOVDEQ x y (InvertFlags cmp)) -> (MOVDEQ x y cmp)
+(MOVDNE x y (InvertFlags cmp)) -> (MOVDNE x y cmp)
+
+// don't extend after proper load
+(MOVBreg x:(MOVBload _ _)) -> x
+(MOVBZreg x:(MOVBZload _ _)) -> x
+(MOVHreg x:(MOVBload _ _)) -> x
+(MOVHreg x:(MOVBZload _ _)) -> x
+(MOVHreg x:(MOVHload _ _)) -> x
+(MOVHZreg x:(MOVBZload _ _)) -> x
+(MOVHZreg x:(MOVHZload _ _)) -> x
+(MOVWreg x:(MOVBload _ _)) -> x
+(MOVWreg x:(MOVBZload _ _)) -> x
+(MOVWreg x:(MOVHload _ _)) -> x
+(MOVWreg x:(MOVHZload _ _)) -> x
+(MOVWreg x:(MOVWload _ _)) -> x
+(MOVWZreg x:(MOVBZload _ _)) -> x
+(MOVWZreg x:(MOVHZload _ _)) -> x
+(MOVWZreg x:(MOVWZload _ _)) -> x
+
+// don't extend if argument is already extended
+(MOVBreg x:(Arg <t>)) && is8BitInt(t) && isSigned(t) -> x
+(MOVBZreg x:(Arg <t>)) && is8BitInt(t) && !isSigned(t) -> x
+(MOVHreg x:(Arg <t>)) && (is8BitInt(t) || is16BitInt(t)) && isSigned(t) -> x
+(MOVHZreg x:(Arg <t>)) && (is8BitInt(t) || is16BitInt(t)) && !isSigned(t) -> x
+(MOVWreg x:(Arg <t>)) && (is8BitInt(t) || is16BitInt(t) || is32BitInt(t)) && isSigned(t) -> x
+(MOVWZreg x:(Arg <t>)) && (is8BitInt(t) || is16BitInt(t) || is32BitInt(t)) && !isSigned(t) -> x
+
+// fold double extensions
+(MOVBreg x:(MOVBreg _)) -> x
+(MOVBZreg x:(MOVBZreg _)) -> x
+(MOVHreg x:(MOVBreg _)) -> x
+(MOVHreg x:(MOVBZreg _)) -> x
+(MOVHreg x:(MOVHreg _)) -> x
+(MOVHZreg x:(MOVBZreg _)) -> x
+(MOVHZreg x:(MOVHZreg _)) -> x
+(MOVWreg x:(MOVBreg _)) -> x
+(MOVWreg x:(MOVBZreg _)) -> x
+(MOVWreg x:(MOVHreg _)) -> x
+(MOVWreg x:(MOVHreg _)) -> x
+(MOVWreg x:(MOVWreg _)) -> x
+(MOVWZreg x:(MOVBZreg _)) -> x
+(MOVWZreg x:(MOVHZreg _)) -> x
+(MOVWZreg x:(MOVWZreg _)) -> x
+
+// fold extensions into constants
+(MOVBreg (MOVDconst [c])) -> (MOVDconst [int64(int8(c))])
+(MOVBZreg (MOVDconst [c])) -> (MOVDconst [int64(uint8(c))])
+(MOVHreg (MOVDconst [c])) -> (MOVDconst [int64(int16(c))])
+(MOVHZreg (MOVDconst [c])) -> (MOVDconst [int64(uint16(c))])
+(MOVWreg (MOVDconst [c])) -> (MOVDconst [int64(int32(c))])
+(MOVWZreg (MOVDconst [c])) -> (MOVDconst [int64(uint32(c))])
+
+// sign extended loads
+// Note: The combined instruction must end up in the same block
+// as the original load. If not, we end up making a value with
+// memory type live in two different blocks, which can lead to
+// multiple memory values alive simultaneously.
+// Make sure we don't combine these ops if the load has another use.
+// This prevents a single load from being split into multiple loads
+// which then might return different values. See test/atomicload.go.
+(MOVBreg x:(MOVBZload [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVBload <v.Type> [off] {sym} ptr mem)
+(MOVBZreg x:(MOVBZload [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVBZload <v.Type> [off] {sym} ptr mem)
+(MOVHreg x:(MOVHZload [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVHload <v.Type> [off] {sym} ptr mem)
+(MOVHZreg x:(MOVHZload [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVHZload <v.Type> [off] {sym} ptr mem)
+(MOVWreg x:(MOVWZload [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVWload <v.Type> [off] {sym} ptr mem)
+(MOVWZreg x:(MOVWZload [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVWZload <v.Type> [off] {sym} ptr mem)
+
+(MOVBZreg x:(MOVBZloadidx [off] {sym} ptr idx mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVBZloadidx <v.Type> [off] {sym} ptr idx mem)
+(MOVHZreg x:(MOVHZloadidx [off] {sym} ptr idx mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVHZloadidx <v.Type> [off] {sym} ptr idx mem)
+(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) -> x
+(MOVHZload [off] {sym} ptr (MOVHstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> x
+(MOVWZload [off] {sym} ptr (MOVWstore [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
+
+// Don't extend before storing
+(MOVWstore [off] {sym} ptr (MOVWreg x) mem) -> (MOVWstore [off] {sym} ptr x mem)
+(MOVHstore [off] {sym} ptr (MOVHreg x) mem) -> (MOVHstore [off] {sym} ptr x mem)
+(MOVBstore [off] {sym} ptr (MOVBreg x) mem) -> (MOVBstore [off] {sym} ptr x mem)
+(MOVWstore [off] {sym} ptr (MOVWZreg x) mem) -> (MOVWstore [off] {sym} ptr x mem)
+(MOVHstore [off] {sym} ptr (MOVHZreg x) mem) -> (MOVHstore [off] {sym} ptr x mem)
+(MOVBstore [off] {sym} ptr (MOVBZreg x) mem) -> (MOVBstore [off] {sym} ptr x mem)
+
+// Fold constants into memory operations.
+// Note that this is not always a good idea because if not all the uses of
+// the ADDconst get eliminated, we still have to compute the ADDconst and we now
+// have potentially two live values (ptr and (ADDconst [off] ptr)) instead of one.
+// Nevertheless, let's do it!
+(MOVDload [off1] {sym} (ADDconst [off2] ptr) mem) && is20Bit(off1+off2) -> (MOVDload [off1+off2] {sym} ptr mem)
+(MOVWload [off1] {sym} (ADDconst [off2] ptr) mem) && is20Bit(off1+off2) -> (MOVWload [off1+off2] {sym} ptr mem)
+(MOVHload [off1] {sym} (ADDconst [off2] ptr) mem) && is20Bit(off1+off2) -> (MOVHload [off1+off2] {sym} ptr mem)
+(MOVBload [off1] {sym} (ADDconst [off2] ptr) mem) && is20Bit(off1+off2) -> (MOVBload [off1+off2] {sym} ptr mem)
+(MOVWZload [off1] {sym} (ADDconst [off2] ptr) mem) && is20Bit(off1+off2) -> (MOVWZload [off1+off2] {sym} ptr mem)
+(MOVHZload [off1] {sym} (ADDconst [off2] ptr) mem) && is20Bit(off1+off2) -> (MOVHZload [off1+off2] {sym} ptr mem)
+(MOVBZload [off1] {sym} (ADDconst [off2] ptr) mem) && is20Bit(off1+off2) -> (MOVBZload [off1+off2] {sym} ptr mem)
+(FMOVSload [off1] {sym} (ADDconst [off2] ptr) mem) && is20Bit(off1+off2) -> (FMOVSload [off1+off2] {sym} ptr mem)
+(FMOVDload [off1] {sym} (ADDconst [off2] ptr) mem) && is20Bit(off1+off2) -> (FMOVDload [off1+off2] {sym} ptr mem)
+
+(MOVDstore [off1] {sym} (ADDconst [off2] ptr) val mem) && is20Bit(off1+off2) -> (MOVDstore [off1+off2] {sym} ptr val mem)
+(MOVWstore [off1] {sym} (ADDconst [off2] ptr) val mem) && is20Bit(off1+off2) -> (MOVWstore [off1+off2] {sym} ptr val mem)
+(MOVHstore [off1] {sym} (ADDconst [off2] ptr) val mem) && is20Bit(off1+off2) -> (MOVHstore [off1+off2] {sym} ptr val mem)
+(MOVBstore [off1] {sym} (ADDconst [off2] ptr) val mem) && is20Bit(off1+off2) -> (MOVBstore [off1+off2] {sym} ptr val mem)
+(FMOVSstore [off1] {sym} (ADDconst [off2] ptr) val mem) && is20Bit(off1+off2) -> (FMOVSstore [off1+off2] {sym} ptr val mem)
+(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 ->
+ (MOVDstoreconst [makeValAndOff(c,off)] {sym} ptr mem)
+(MOVWstore [off] {sym} ptr (MOVDconst [c]) mem) && validOff(off) && int64(int16(c)) == c && ptr.Op != OpSB ->
+ (MOVWstoreconst [makeValAndOff(int64(int32(c)),off)] {sym} ptr mem)
+(MOVHstore [off] {sym} ptr (MOVDconst [c]) mem) && validOff(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 ->
+ (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 [ValAndOff(sc).add(off)] {s} ptr mem)
+(MOVWstoreconst [sc] {s} (ADDconst [off] ptr) mem) && ValAndOff(sc).canAdd(off) ->
+ (MOVWstoreconst [ValAndOff(sc).add(off)] {s} ptr mem)
+(MOVHstoreconst [sc] {s} (ADDconst [off] ptr) mem) && ValAndOff(sc).canAdd(off) ->
+ (MOVHstoreconst [ValAndOff(sc).add(off)] {s} ptr mem)
+(MOVBstoreconst [sc] {s} (ADDconst [off] ptr) mem) && ValAndOff(sc).canAdd(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
+// what variables are being read/written by the ops.
+(MOVDload [off1] {sym1} (MOVDaddr [off2] {sym2} base) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
+ (MOVDload [off1+off2] {mergeSym(sym1,sym2)} base mem)
+(MOVWZload [off1] {sym1} (MOVDaddr [off2] {sym2} base) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
+ (MOVWZload [off1+off2] {mergeSym(sym1,sym2)} base mem)
+(MOVHZload [off1] {sym1} (MOVDaddr [off2] {sym2} base) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
+ (MOVHZload [off1+off2] {mergeSym(sym1,sym2)} base mem)
+(MOVBZload [off1] {sym1} (MOVDaddr [off2] {sym2} base) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
+ (MOVBZload [off1+off2] {mergeSym(sym1,sym2)} base mem)
+(FMOVSload [off1] {sym1} (MOVDaddr [off2] {sym2} base) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
+ (FMOVSload [off1+off2] {mergeSym(sym1,sym2)} base mem)
+(FMOVDload [off1] {sym1} (MOVDaddr [off2] {sym2} base) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
+ (FMOVDload [off1+off2] {mergeSym(sym1,sym2)} base mem)
+
+(MOVBload [off1] {sym1} (MOVDaddr [off2] {sym2} base) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
+ (MOVBload [off1+off2] {mergeSym(sym1,sym2)} base mem)
+(MOVHload [off1] {sym1} (MOVDaddr [off2] {sym2} base) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
+ (MOVHload [off1+off2] {mergeSym(sym1,sym2)} base mem)
+(MOVWload [off1] {sym1} (MOVDaddr [off2] {sym2} base) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
+ (MOVWload [off1+off2] {mergeSym(sym1,sym2)} base mem)
+
+(MOVDstore [off1] {sym1} (MOVDaddr [off2] {sym2} base) val mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
+ (MOVDstore [off1+off2] {mergeSym(sym1,sym2)} base val mem)
+(MOVWstore [off1] {sym1} (MOVDaddr [off2] {sym2} base) val mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
+ (MOVWstore [off1+off2] {mergeSym(sym1,sym2)} base val mem)
+(MOVHstore [off1] {sym1} (MOVDaddr [off2] {sym2} base) val mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
+ (MOVHstore [off1+off2] {mergeSym(sym1,sym2)} base val mem)
+(MOVBstore [off1] {sym1} (MOVDaddr [off2] {sym2} base) val mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
+ (MOVBstore [off1+off2] {mergeSym(sym1,sym2)} base val mem)
+(FMOVSstore [off1] {sym1} (MOVDaddr [off2] {sym2} base) val mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
+ (FMOVSstore [off1+off2] {mergeSym(sym1,sym2)} base val mem)
+(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) ->
+ (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 [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 [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 [ValAndOff(sc).add(off)] {mergeSym(sym1, sym2)} ptr mem)
+
+// generating indexed loads and stores
+(MOVBZload [off1] {sym1} (MOVDaddridx [off2] {sym2} ptr idx) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
+ (MOVBZloadidx [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem)
+(MOVHZload [off1] {sym1} (MOVDaddridx [off2] {sym2} ptr idx) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
+ (MOVHZloadidx [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem)
+(MOVWZload [off1] {sym1} (MOVDaddridx [off2] {sym2} ptr idx) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
+ (MOVWZloadidx [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem)
+(MOVDload [off1] {sym1} (MOVDaddridx [off2] {sym2} ptr idx) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
+ (MOVDloadidx [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem)
+(FMOVSload [off1] {sym1} (MOVDaddridx [off2] {sym2} ptr idx) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
+ (FMOVSloadidx [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem)
+(FMOVDload [off1] {sym1} (MOVDaddridx [off2] {sym2} ptr idx) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
+ (FMOVDloadidx [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem)
+
+(MOVBstore [off1] {sym1} (MOVDaddridx [off2] {sym2} ptr idx) val mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
+ (MOVBstoreidx [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem)
+(MOVHstore [off1] {sym1} (MOVDaddridx [off2] {sym2} ptr idx) val mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
+ (MOVHstoreidx [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem)
+(MOVWstore [off1] {sym1} (MOVDaddridx [off2] {sym2} ptr idx) val mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
+ (MOVWstoreidx [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem)
+(MOVDstore [off1] {sym1} (MOVDaddridx [off2] {sym2} ptr idx) val mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
+ (MOVDstoreidx [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem)
+(FMOVSstore [off1] {sym1} (MOVDaddridx [off2] {sym2} ptr idx) val mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
+ (FMOVSstoreidx [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem)
+(FMOVDstore [off1] {sym1} (MOVDaddridx [off2] {sym2} ptr idx) val mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) ->
+ (FMOVDstoreidx [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem)
+
+(MOVBZload [off] {sym} (ADD ptr idx) mem) && ptr.Op != OpSB -> (MOVBZloadidx [off] {sym} ptr idx mem)
+(MOVHZload [off] {sym} (ADD ptr idx) mem) && ptr.Op != OpSB -> (MOVHZloadidx [off] {sym} ptr idx mem)
+(MOVWZload [off] {sym} (ADD ptr idx) mem) && ptr.Op != OpSB -> (MOVWZloadidx [off] {sym} ptr idx mem)
+(MOVDload [off] {sym} (ADD ptr idx) mem) && ptr.Op != OpSB -> (MOVDloadidx [off] {sym} ptr idx mem)
+(FMOVSload [off] {sym} (ADD ptr idx) mem) && ptr.Op != OpSB -> (FMOVSloadidx [off] {sym} ptr idx mem)
+(FMOVDload [off] {sym} (ADD ptr idx) mem) && ptr.Op != OpSB -> (FMOVDloadidx [off] {sym} ptr idx mem)
+(MOVBstore [off] {sym} (ADD ptr idx) val mem) && ptr.Op != OpSB -> (MOVBstoreidx [off] {sym} ptr idx val mem)
+(MOVHstore [off] {sym} (ADD ptr idx) val mem) && ptr.Op != OpSB -> (MOVHstoreidx [off] {sym} ptr idx val mem)
+(MOVWstore [off] {sym} (ADD ptr idx) val mem) && ptr.Op != OpSB -> (MOVWstoreidx [off] {sym} ptr idx val mem)
+(MOVDstore [off] {sym} (ADD ptr idx) val mem) && ptr.Op != OpSB -> (MOVDstoreidx [off] {sym} ptr idx val mem)
+(FMOVSstore [off] {sym} (ADD ptr idx) val mem) && ptr.Op != OpSB -> (FMOVSstoreidx [off] {sym} ptr idx val mem)
+(FMOVDstore [off] {sym} (ADD ptr idx) val mem) && ptr.Op != OpSB -> (FMOVDstoreidx [off] {sym} ptr idx val mem)
+
+// combine ADD into indexed loads and stores
+(MOVBZloadidx [c] {sym} (ADDconst [d] ptr) idx mem) -> (MOVBZloadidx [c+d] {sym} ptr idx mem)
+(MOVHZloadidx [c] {sym} (ADDconst [d] ptr) idx mem) -> (MOVHZloadidx [c+d] {sym} ptr idx mem)
+(MOVWZloadidx [c] {sym} (ADDconst [d] ptr) idx mem) -> (MOVWZloadidx [c+d] {sym} ptr idx mem)
+(MOVDloadidx [c] {sym} (ADDconst [d] ptr) idx mem) -> (MOVDloadidx [c+d] {sym} ptr idx mem)
+(FMOVSloadidx [c] {sym} (ADDconst [d] ptr) idx mem) -> (FMOVSloadidx [c+d] {sym} ptr idx mem)
+(FMOVDloadidx [c] {sym} (ADDconst [d] ptr) idx mem) -> (FMOVDloadidx [c+d] {sym} ptr idx mem)
+
+(MOVBstoreidx [c] {sym} (ADDconst [d] ptr) idx val mem) -> (MOVBstoreidx [c+d] {sym} ptr idx val mem)
+(MOVHstoreidx [c] {sym} (ADDconst [d] ptr) idx val mem) -> (MOVHstoreidx [c+d] {sym} ptr idx val mem)
+(MOVWstoreidx [c] {sym} (ADDconst [d] ptr) idx val mem) -> (MOVWstoreidx [c+d] {sym} ptr idx val mem)
+(MOVDstoreidx [c] {sym} (ADDconst [d] ptr) idx val mem) -> (MOVDstoreidx [c+d] {sym} ptr idx val mem)
+(FMOVSstoreidx [c] {sym} (ADDconst [d] ptr) idx val mem) -> (FMOVSstoreidx [c+d] {sym} ptr idx val mem)
+(FMOVDstoreidx [c] {sym} (ADDconst [d] ptr) idx val mem) -> (FMOVDstoreidx [c+d] {sym} ptr idx val mem)
+
+(MOVBZloadidx [c] {sym} ptr (ADDconst [d] idx) mem) -> (MOVBZloadidx [c+d] {sym} ptr idx mem)
+(MOVHZloadidx [c] {sym} ptr (ADDconst [d] idx) mem) -> (MOVHZloadidx [c+d] {sym} ptr idx mem)
+(MOVWZloadidx [c] {sym} ptr (ADDconst [d] idx) mem) -> (MOVWZloadidx [c+d] {sym} ptr idx mem)
+(MOVDloadidx [c] {sym} ptr (ADDconst [d] idx) mem) -> (MOVDloadidx [c+d] {sym} ptr idx mem)
+(FMOVSloadidx [c] {sym} ptr (ADDconst [d] idx) mem) -> (FMOVSloadidx [c+d] {sym} ptr idx mem)
+(FMOVDloadidx [c] {sym} ptr (ADDconst [d] idx) mem) -> (FMOVDloadidx [c+d] {sym} ptr idx mem)
+
+(MOVBstoreidx [c] {sym} ptr (ADDconst [d] idx) val mem) -> (MOVBstoreidx [c+d] {sym} ptr idx val mem)
+(MOVHstoreidx [c] {sym} ptr (ADDconst [d] idx) val mem) -> (MOVHstoreidx [c+d] {sym} ptr idx val mem)
+(MOVWstoreidx [c] {sym} ptr (ADDconst [d] idx) val mem) -> (MOVWstoreidx [c+d] {sym} ptr idx val mem)
+(MOVDstoreidx [c] {sym} ptr (ADDconst [d] idx) val mem) -> (MOVDstoreidx [c+d] {sym} ptr idx val mem)
+(FMOVSstoreidx [c] {sym} ptr (ADDconst [d] idx) val mem) -> (FMOVSstoreidx [c+d] {sym} ptr idx val mem)
+(FMOVDstoreidx [c] {sym} ptr (ADDconst [d] idx) val mem) -> (FMOVDstoreidx [c+d] {sym} ptr idx val mem)
+
+// MOVDaddr into MOVDaddridx
+(MOVDaddridx [off1] {sym1} (MOVDaddr [off2] {sym2} x) y) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) && x.Op != OpSB ->
+ (MOVDaddridx [off1+off2] {mergeSym(sym1,sym2)} x y)
+(MOVDaddridx [off1] {sym1} x (MOVDaddr [off2] {sym2} y)) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) && y.Op != OpSB ->
+ (MOVDaddridx [off1+off2] {mergeSym(sym1,sym2)} x y)
+
+// Absorb InvertFlags into branches.
+(LT (InvertFlags cmp) yes no) -> (GT cmp yes no)
+(GT (InvertFlags cmp) yes no) -> (LT cmp yes no)
+(LE (InvertFlags cmp) yes no) -> (GE cmp yes no)
+(GE (InvertFlags cmp) yes no) -> (LE cmp yes no)
+(EQ (InvertFlags cmp) yes no) -> (EQ cmp yes no)
+(NE (InvertFlags cmp) yes no) -> (NE cmp yes no)
+
+// Constant comparisons.
+(CMPconst (MOVDconst [x]) [y]) && x==y -> (FlagEQ)
+(CMPconst (MOVDconst [x]) [y]) && x<y -> (FlagLT)
+(CMPconst (MOVDconst [x]) [y]) && x>y -> (FlagGT)
+(CMPUconst (MOVDconst [x]) [y]) && uint64(x)==uint64(y) -> (FlagEQ)
+(CMPUconst (MOVDconst [x]) [y]) && uint64(x)<uint64(y) -> (FlagLT)
+(CMPUconst (MOVDconst [x]) [y]) && uint64(x)>uint64(y) -> (FlagGT)
+
+(CMPWconst (MOVDconst [x]) [y]) && int32(x)==int32(y) -> (FlagEQ)
+(CMPWconst (MOVDconst [x]) [y]) && int32(x)<int32(y) -> (FlagLT)
+(CMPWconst (MOVDconst [x]) [y]) && int32(x)>int32(y) -> (FlagGT)
+(CMPWUconst (MOVDconst [x]) [y]) && uint32(x)==uint32(y) -> (FlagEQ)
+(CMPWUconst (MOVDconst [x]) [y]) && uint32(x)<uint32(y) -> (FlagLT)
+(CMPWUconst (MOVDconst [x]) [y]) && uint32(x)>uint32(y) -> (FlagGT)
+
+// Other known comparisons.
+(CMPconst (MOVBZreg _) [c]) && 0xFF < c -> (FlagLT)
+(CMPconst (MOVHZreg _) [c]) && 0xFFFF < c -> (FlagLT)
+(CMPconst (MOVWZreg _) [c]) && 0xFFFFFFFF < c -> (FlagLT)
+(CMPWconst (SRWconst _ [c]) [n]) && 0 <= n && 0 < c && c <= 32 && (1<<uint64(32-c)) <= uint64(n) -> (FlagLT)
+(CMPconst (SRDconst _ [c]) [n]) && 0 <= n && 0 < c && c <= 64 && (1<<uint64(64-c)) <= uint64(n) -> (FlagLT)
+(CMPconst (ANDconst _ [m]) [n]) && 0 <= m && m < n -> (FlagLT)
+(CMPWconst (ANDWconst _ [m]) [n]) && 0 <= int32(m) && int32(m) < int32(n) -> (FlagLT)
+
+// Absorb flag constants into SBB ops.
+(SUBEcarrymask (FlagEQ)) -> (MOVDconst [-1])
+(SUBEcarrymask (FlagLT)) -> (MOVDconst [-1])
+(SUBEcarrymask (FlagGT)) -> (MOVDconst [0])
+(SUBEWcarrymask (FlagEQ)) -> (MOVDconst [-1])
+(SUBEWcarrymask (FlagLT)) -> (MOVDconst [-1])
+(SUBEWcarrymask (FlagGT)) -> (MOVDconst [0])
+
+// Absorb flag constants into branches.
+(EQ (FlagEQ) yes no) -> (First nil yes no)
+(EQ (FlagLT) yes no) -> (First nil no yes)
+(EQ (FlagGT) yes no) -> (First nil no yes)
+
+(NE (FlagEQ) yes no) -> (First nil no yes)
+(NE (FlagLT) yes no) -> (First nil yes no)
+(NE (FlagGT) yes no) -> (First nil yes no)
+
+(LT (FlagEQ) yes no) -> (First nil no yes)
+(LT (FlagLT) yes no) -> (First nil yes no)
+(LT (FlagGT) yes no) -> (First nil no yes)
+
+(LE (FlagEQ) yes no) -> (First nil yes no)
+(LE (FlagLT) yes no) -> (First nil yes no)
+(LE (FlagGT) yes no) -> (First nil no yes)
+
+(GT (FlagEQ) yes no) -> (First nil no yes)
+(GT (FlagLT) yes no) -> (First nil no yes)
+(GT (FlagGT) yes no) -> (First nil yes no)
+
+(GE (FlagEQ) yes no) -> (First nil yes no)
+(GE (FlagLT) yes no) -> (First nil no yes)
+(GE (FlagGT) yes no) -> (First nil yes no)
+
+// Absorb flag constants into SETxx ops.
+(MOVDEQ _ x (FlagEQ)) -> x
+(MOVDEQ y _ (FlagLT)) -> y
+(MOVDEQ y _ (FlagGT)) -> y
+
+(MOVDNE _ y (FlagEQ)) -> y
+(MOVDNE x _ (FlagLT)) -> x
+(MOVDNE x _ (FlagGT)) -> x
+
+(MOVDLT y _ (FlagEQ)) -> y
+(MOVDLT _ x (FlagLT)) -> x
+(MOVDLT y _ (FlagGT)) -> y
+
+(MOVDLE _ x (FlagEQ)) -> x
+(MOVDLE _ x (FlagLT)) -> x
+(MOVDLE y _ (FlagGT)) -> y
+
+(MOVDGT y _ (FlagEQ)) -> y
+(MOVDGT y _ (FlagLT)) -> y
+(MOVDGT _ x (FlagGT)) -> x
+
+(MOVDGE _ x (FlagEQ)) -> x
+(MOVDGE y _ (FlagLT)) -> y
+(MOVDGE _ x (FlagGT)) -> x
+
+// Remove redundant *const ops
+(ADDconst [0] x) -> x
+(ADDWconst [c] x) && int32(c)==0 -> x
+(SUBconst [0] x) -> x
+(SUBWconst [c] x) && int32(c) == 0 -> x
+(ANDconst [0] _) -> (MOVDconst [0])
+(ANDWconst [c] _) && int32(c)==0 -> (MOVDconst [0])
+(ANDconst [-1] x) -> x
+(ANDWconst [c] x) && int32(c)==-1 -> x
+(ORconst [0] x) -> x
+(ORWconst [c] x) && int32(c)==0 -> x
+(ORconst [-1] _) -> (MOVDconst [-1])
+(ORWconst [c] _) && int32(c)==-1 -> (MOVDconst [-1])
+(XORconst [0] x) -> x
+(XORWconst [c] x) && int32(c)==0 -> x
+
+// Convert constant subtracts to constant adds.
+(SUBconst [c] x) && c != -(1<<31) -> (ADDconst [-c] x)
+(SUBWconst [c] x) -> (ADDWconst [int64(int32(-c))] x)
+
+// generic constant folding
+// TODO: more of this
+(ADDconst [c] (MOVDconst [d])) -> (MOVDconst [c+d])
+(ADDWconst [c] (MOVDconst [d])) -> (MOVDconst [int64(int32(c+d))])
+(ADDconst [c] (ADDconst [d] x)) && is32Bit(c+d) -> (ADDconst [c+d] x)
+(ADDWconst [c] (ADDWconst [d] x)) -> (ADDWconst [int64(int32(c+d))] x)
+(SUBconst (MOVDconst [d]) [c]) -> (MOVDconst [d-c])
+(SUBconst (SUBconst x [d]) [c]) && is32Bit(-c-d) -> (ADDconst [-c-d] x)
+(SRADconst [c] (MOVDconst [d])) -> (MOVDconst [d>>uint64(c)])
+(SRAWconst [c] (MOVDconst [d])) -> (MOVDconst [d>>uint64(c)])
+(NEG (MOVDconst [c])) -> (MOVDconst [-c])
+(NEGW (MOVDconst [c])) -> (MOVDconst [int64(int32(-c))])
+(MULLDconst [c] (MOVDconst [d])) -> (MOVDconst [c*d])
+(MULLWconst [c] (MOVDconst [d])) -> (MOVDconst [int64(int32(c*d))])
+(AND (MOVDconst [c]) (MOVDconst [d])) -> (MOVDconst [c&d])
+(ANDconst [c] (MOVDconst [d])) -> (MOVDconst [c&d])
+(ANDWconst [c] (MOVDconst [d])) -> (MOVDconst [c&d])
+(OR (MOVDconst [c]) (MOVDconst [d])) -> (MOVDconst [c|d])
+(ORconst [c] (MOVDconst [d])) -> (MOVDconst [c|d])
+(ORWconst [c] (MOVDconst [d])) -> (MOVDconst [c|d])
+(XOR (MOVDconst [c]) (MOVDconst [d])) -> (MOVDconst [c^d])
+(XORconst [c] (MOVDconst [d])) -> (MOVDconst [c^d])
+(XORWconst [c] (MOVDconst [d])) -> (MOVDconst [c^d])
+
+// generic simplifications
+// TODO: more of this
+(ADD x (NEG y)) -> (SUB x y)
+(ADDW x (NEGW y)) -> (SUBW x y)
+(SUB x x) -> (MOVDconst [0])
+(SUBW x x) -> (MOVDconst [0])
+(AND x x) -> x
+(ANDW x x) -> x
+(OR x x) -> x
+(ORW x x) -> x
+(XOR x x) -> (MOVDconst [0])
+(XORW x x) -> (MOVDconst [0])
+
+// 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)
+ -> (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)
+ -> (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)
+ -> (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)
+ -> (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)
+ -> (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)
+ -> (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)
+ -> (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)
+ -> (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)
+ -> (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)
+ -> (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)
+ -> (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)
+ -> (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)
+ -> (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)
+ -> (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)
+ -> (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)
+ -> (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)
+ -> (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)
+ -> (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)
+ -> (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)
+ -> (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)
+ -> (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)
+ -> (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)
+ -> (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)
+ -> (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)
+ -> (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)
+ -> (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)
+ -> (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)
+ -> (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)
+ -> (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)
+ -> (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)
+ -> (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)
+ -> (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)
+ -> (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
+(MOVBstoreconst [c] {s} p x:(MOVBstoreconst [a] {s} p mem))
+ && p.Op != OpSB
+ && x.Uses == 1
+ && ValAndOff(a).Off() + 1 == ValAndOff(c).Off()
+ && clobber(x)
+ -> (MOVHstoreconst [makeValAndOff(ValAndOff(c).Val()&0xff | ValAndOff(a).Val()<<8, ValAndOff(a).Off())] {s} p mem)
+(MOVHstoreconst [c] {s} p x:(MOVHstoreconst [a] {s} p mem))
+ && p.Op != OpSB
+ && 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)
+(MOVWstoreconst [c] {s} p x:(MOVWstoreconst [a] {s} p mem))
+ && p.Op != OpSB
+ && x.Uses == 1
+ && ValAndOff(a).Off() + 4 == ValAndOff(c).Off()
+ && clobber(x)
+ -> (MOVDstore [ValAndOff(a).Off()] {s} p (MOVDconst [ValAndOff(c).Val()&0xffffffff | ValAndOff(a).Val()<<32]) mem)
+
+// Combine stores into larger (unaligned) stores.
+// It doesn't work on global data (based on SB) because stores with relative addressing
+// require that the memory operand be aligned.
+(MOVBstore [i] {s} p w x:(MOVBstore [i-1] {s} p (SRDconst [8] w) mem))
+ && p.Op != OpSB
+ && x.Uses == 1
+ && clobber(x)
+ -> (MOVHstore [i-1] {s} p w mem)
+(MOVBstore [i] {s} p w0:(SRDconst [j] w) x:(MOVBstore [i-1] {s} p (SRDconst [j+8] w) mem))
+ && p.Op != OpSB
+ && x.Uses == 1
+ && clobber(x)
+ -> (MOVHstore [i-1] {s} p w0 mem)
+(MOVBstore [i] {s} p w x:(MOVBstore [i-1] {s} p (SRWconst [8] w) mem))
+ && p.Op != OpSB
+ && x.Uses == 1
+ && clobber(x)
+ -> (MOVHstore [i-1] {s} p w mem)
+(MOVBstore [i] {s} p w0:(SRWconst [j] w) x:(MOVBstore [i-1] {s} p (SRWconst [j+8] w) mem))
+ && p.Op != OpSB
+ && x.Uses == 1
+ && clobber(x)
+ -> (MOVHstore [i-1] {s} p w0 mem)
+(MOVHstore [i] {s} p w x:(MOVHstore [i-2] {s} p (SRDconst [16] w) mem))
+ && p.Op != OpSB
+ && x.Uses == 1
+ && clobber(x)
+ -> (MOVWstore [i-2] {s} p w mem)
+(MOVHstore [i] {s} p w0:(SRDconst [j] w) x:(MOVHstore [i-2] {s} p (SRDconst [j+16] w) mem))
+ && p.Op != OpSB
+ && x.Uses == 1
+ && clobber(x)
+ -> (MOVWstore [i-2] {s} p w0 mem)
+(MOVHstore [i] {s} p w x:(MOVHstore [i-2] {s} p (SRWconst [16] w) mem))
+ && p.Op != OpSB
+ && x.Uses == 1
+ && clobber(x)
+ -> (MOVWstore [i-2] {s} p w mem)
+(MOVHstore [i] {s} p w0:(SRWconst [j] w) x:(MOVHstore [i-2] {s} p (SRWconst [j+16] w) mem))
+ && p.Op != OpSB
+ && x.Uses == 1
+ && clobber(x)
+ -> (MOVWstore [i-2] {s} p w0 mem)
+(MOVWstore [i] {s} p (SRDconst [32] w) x:(MOVWstore [i-4] {s} p w mem))
+ && p.Op != OpSB
+ && x.Uses == 1
+ && clobber(x)
+ -> (MOVDstore [i-4] {s} p w mem)
+(MOVWstore [i] {s} p w0:(SRDconst [j] w) x:(MOVWstore [i-4] {s} p (SRDconst [j+32] w) mem))
+ && p.Op != OpSB
+ && x.Uses == 1
+ && clobber(x)
+ -> (MOVDstore [i-4] {s} p w0 mem)
+
+(MOVBstoreidx [i] {s} p idx w x:(MOVBstoreidx [i-1] {s} p idx (SRDconst [8] w) mem))
+ && x.Uses == 1
+ && clobber(x)
+ -> (MOVHstoreidx [i-1] {s} p idx w mem)
+(MOVBstoreidx [i] {s} p idx w0:(SRDconst [j] w) x:(MOVBstoreidx [i-1] {s} p idx (SRDconst [j+8] w) mem))
+ && x.Uses == 1
+ && clobber(x)
+ -> (MOVHstoreidx [i-1] {s} p idx w0 mem)
+(MOVBstoreidx [i] {s} p idx w x:(MOVBstoreidx [i-1] {s} p idx (SRWconst [8] w) mem))
+ && x.Uses == 1
+ && clobber(x)
+ -> (MOVHstoreidx [i-1] {s} p idx w mem)
+(MOVBstoreidx [i] {s} p idx w0:(SRWconst [j] w) x:(MOVBstoreidx [i-1] {s} p idx (SRWconst [j+8] w) mem))
+ && x.Uses == 1
+ && clobber(x)
+ -> (MOVHstoreidx [i-1] {s} p idx w0 mem)
+(MOVHstoreidx [i] {s} p idx w x:(MOVHstoreidx [i-2] {s} p idx (SRDconst [16] w) mem))
+ && x.Uses == 1
+ && clobber(x)
+ -> (MOVWstoreidx [i-2] {s} p idx w mem)
+(MOVHstoreidx [i] {s} p idx w0:(SRDconst [j] w) x:(MOVHstoreidx [i-2] {s} p idx (SRDconst [j+16] w) mem))
+ && x.Uses == 1
+ && clobber(x)
+ -> (MOVWstoreidx [i-2] {s} p idx w0 mem)
+(MOVHstoreidx [i] {s} p idx w x:(MOVHstoreidx [i-2] {s} p idx (SRWconst [16] w) mem))
+ && x.Uses == 1
+ && clobber(x)
+ -> (MOVWstoreidx [i-2] {s} p idx w mem)
+(MOVHstoreidx [i] {s} p idx w0:(SRWconst [j] w) x:(MOVHstoreidx [i-2] {s} p idx (SRWconst [j+16] w) mem))
+ && x.Uses == 1
+ && clobber(x)
+ -> (MOVWstoreidx [i-2] {s} p idx w0 mem)
+(MOVWstoreidx [i] {s} p idx w x:(MOVWstoreidx [i-4] {s} p idx (SRDconst [32] w) mem))
+ && x.Uses == 1
+ && clobber(x)
+ -> (MOVDstoreidx [i-4] {s} p idx w mem)
+(MOVWstoreidx [i] {s} p idx w0:(SRDconst [j] w) x:(MOVWstoreidx [i-4] {s} p idx (SRDconst [j+32] w) mem))
+ && x.Uses == 1
+ && clobber(x)
+ -> (MOVDstoreidx [i-4] {s} p idx w0 mem)
+
+// Combine stores into larger (unaligned) stores with the bytes reversed (little endian).
+// Store-with-bytes-reversed instructions do not support relative memory addresses,
+// so these stores can't operate on global data (SB).
+(MOVBstore [i] {s} p (SRDconst [8] w) x:(MOVBstore [i-1] {s} p w mem))
+ && p.Op != OpSB
+ && x.Uses == 1
+ && clobber(x)
+ -> (MOVHBRstore [i-1] {s} p w mem)
+(MOVBstore [i] {s} p (SRDconst [j] w) x:(MOVBstore [i-1] {s} p w0:(SRDconst [j-8] w) mem))
+ && p.Op != OpSB
+ && x.Uses == 1
+ && clobber(x)
+ -> (MOVHBRstore [i-1] {s} p w0 mem)
+(MOVBstore [i] {s} p (SRWconst [8] w) x:(MOVBstore [i-1] {s} p w mem))
+ && p.Op != OpSB
+ && x.Uses == 1
+ && clobber(x)
+ -> (MOVHBRstore [i-1] {s} p w mem)
+(MOVBstore [i] {s} p (SRWconst [j] w) x:(MOVBstore [i-1] {s} p w0:(SRWconst [j-8] w) mem))
+ && p.Op != OpSB
+ && x.Uses == 1
+ && clobber(x)
+ -> (MOVHBRstore [i-1] {s} p w0 mem)
+(MOVHBRstore [i] {s} p (SRDconst [16] w) x:(MOVHBRstore [i-2] {s} p w mem))
+ && x.Uses == 1
+ && clobber(x)
+ -> (MOVWBRstore [i-2] {s} p w mem)
+(MOVHBRstore [i] {s} p (SRDconst [j] w) x:(MOVHBRstore [i-2] {s} p w0:(SRDconst [j-16] w) mem))
+ && x.Uses == 1
+ && clobber(x)
+ -> (MOVWBRstore [i-2] {s} p w0 mem)
+(MOVHBRstore [i] {s} p (SRWconst [16] w) x:(MOVHBRstore [i-2] {s} p w mem))
+ && x.Uses == 1
+ && clobber(x)
+ -> (MOVWBRstore [i-2] {s} p w mem)
+(MOVHBRstore [i] {s} p (SRWconst [j] w) x:(MOVHBRstore [i-2] {s} p w0:(SRWconst [j-16] w) mem))
+ && x.Uses == 1
+ && clobber(x)
+ -> (MOVWBRstore [i-2] {s} p w0 mem)
+(MOVWBRstore [i] {s} p (SRDconst [32] w) x:(MOVWBRstore [i-4] {s} p w mem))
+ && x.Uses == 1
+ && clobber(x)
+ -> (MOVDBRstore [i-4] {s} p w mem)
+(MOVWBRstore [i] {s} p (SRDconst [j] w) x:(MOVWBRstore [i-4] {s} p w0:(SRDconst [j-32] w) mem))
+ && x.Uses == 1
+ && clobber(x)
+ -> (MOVDBRstore [i-4] {s} p w0 mem)
+
+(MOVBstoreidx [i] {s} p idx (SRDconst [8] w) x:(MOVBstoreidx [i-1] {s} p idx w mem))
+ && x.Uses == 1
+ && clobber(x)
+ -> (MOVHBRstoreidx [i-1] {s} p idx w mem)
+(MOVBstoreidx [i] {s} p idx (SRDconst [j] w) x:(MOVBstoreidx [i-1] {s} p idx w0:(SRDconst [j-8] w) mem))
+ && x.Uses == 1
+ && clobber(x)
+ -> (MOVHBRstoreidx [i-1] {s} p idx w0 mem)
+(MOVBstoreidx [i] {s} p idx (SRWconst [8] w) x:(MOVBstoreidx [i-1] {s} p idx w mem))
+ && x.Uses == 1
+ && clobber(x)
+ -> (MOVHBRstoreidx [i-1] {s} p idx w mem)
+(MOVBstoreidx [i] {s} p idx (SRWconst [j] w) x:(MOVBstoreidx [i-1] {s} p idx w0:(SRWconst [j-8] w) mem))
+ && x.Uses == 1
+ && clobber(x)
+ -> (MOVHBRstoreidx [i-1] {s} p idx w0 mem)
+(MOVHBRstoreidx [i] {s} p idx (SRDconst [16] w) x:(MOVHBRstoreidx [i-2] {s} p idx w mem))
+ && x.Uses == 1
+ && clobber(x)
+ -> (MOVWBRstoreidx [i-2] {s} p idx w mem)
+(MOVHBRstoreidx [i] {s} p idx (SRDconst [j] w) x:(MOVHBRstoreidx [i-2] {s} p idx w0:(SRDconst [j-16] w) mem))
+ && x.Uses == 1
+ && clobber(x)
+ -> (MOVWBRstoreidx [i-2] {s} p idx w0 mem)
+(MOVHBRstoreidx [i] {s} p idx (SRWconst [16] w) x:(MOVHBRstoreidx [i-2] {s} p idx w mem))
+ && x.Uses == 1
+ && clobber(x)
+ -> (MOVWBRstoreidx [i-2] {s} p idx w mem)
+(MOVHBRstoreidx [i] {s} p idx (SRWconst [j] w) x:(MOVHBRstoreidx [i-2] {s} p idx w0:(SRWconst [j-16] w) mem))
+ && x.Uses == 1
+ && clobber(x)
+ -> (MOVWBRstoreidx [i-2] {s} p idx w0 mem)
+(MOVWBRstoreidx [i] {s} p idx (SRDconst [32] w) x:(MOVWBRstoreidx [i-4] {s} p idx w mem))
+ && x.Uses == 1
+ && clobber(x)
+ -> (MOVDBRstoreidx [i-4] {s} p idx w mem)
+(MOVWBRstoreidx [i] {s} p idx (SRDconst [j] w) x:(MOVWBRstoreidx [i-4] {s} p idx w0:(SRDconst [j-32] w) mem))
+ && x.Uses == 1
+ && clobber(x)
+ -> (MOVDBRstoreidx [i-4] {s} p idx w0 mem)
+
+// Combining byte loads into larger (unaligned) loads.
+
+// Little 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)))
+ && p.Op != OpSB
+ && x0.Uses == 1
+ && x1.Uses == 1
+ && s0.Uses == 1
+ && mergePoint(b,x0,x1) != nil
+ && clobber(x0)
+ && clobber(x1)
+ && clobber(s0)
+ -> @mergePoint(b,x0,x1) (MOVHZreg (MOVHBRload [i] {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)))
+ && 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)
+ -> @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
+ && x0.Uses == 1
+ && x1.Uses == 1
+ && x2.Uses == 1
+ && x3.Uses == 1
+ && x4.Uses == 1
+ && x5.Uses == 1
+ && x6.Uses == 1
+ && x7.Uses == 1
+ && s0.Uses == 1
+ && s1.Uses == 1
+ && s2.Uses == 1
+ && s3.Uses == 1
+ && s4.Uses == 1
+ && s5.Uses == 1
+ && s6.Uses == 1
+ && o0.Uses == 1
+ && o1.Uses == 1
+ && o2.Uses == 1
+ && o3.Uses == 1
+ && o4.Uses == 1
+ && o5.Uses == 1
+ && mergePoint(b,x0,x1,x2,x3,x4,x5,x6,x7) != nil
+ && clobber(x0)
+ && clobber(x1)
+ && clobber(x2)
+ && clobber(x3)
+ && clobber(x4)
+ && clobber(x5)
+ && clobber(x6)
+ && clobber(x7)
+ && clobber(s0)
+ && clobber(s1)
+ && clobber(s2)
+ && clobber(s3)
+ && clobber(s4)
+ && clobber(s5)
+ && clobber(s6)
+ && clobber(o0)
+ && clobber(o1)
+ && clobber(o2)
+ && clobber(o3)
+ && clobber(o4)
+ && clobber(o5)
+ -> @mergePoint(b,x0,x1,x2,x3,x4,x5,x6,x7) (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)))
+ && x0.Uses == 1
+ && x1.Uses == 1
+ && s0.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))
+
+// 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
+ && 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)
+ -> @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)))
+ && x0.Uses == 1
+ && x1.Uses == 1
+ && x2.Uses == 1
+ && x3.Uses == 1
+ && x4.Uses == 1
+ && x5.Uses == 1
+ && x6.Uses == 1
+ && x7.Uses == 1
+ && s0.Uses == 1
+ && s1.Uses == 1
+ && s2.Uses == 1
+ && s3.Uses == 1
+ && s4.Uses == 1
+ && s5.Uses == 1
+ && s6.Uses == 1
+ && o0.Uses == 1
+ && o1.Uses == 1
+ && o2.Uses == 1
+ && o3.Uses == 1
+ && o4.Uses == 1
+ && o5.Uses == 1
+ && mergePoint(b,x0,x1,x2,x3,x4,x5,x6,x7) != nil
+ && clobber(x0)
+ && clobber(x1)
+ && clobber(x2)
+ && clobber(x3)
+ && clobber(x4)
+ && clobber(x5)
+ && clobber(x6)
+ && clobber(x7)
+ && clobber(s0)
+ && clobber(s1)
+ && clobber(s2)
+ && clobber(s3)
+ && clobber(s4)
+ && clobber(s5)
+ && clobber(s6)
+ && clobber(o0)
+ && clobber(o1)
+ && clobber(o2)
+ && clobber(o3)
+ && clobber(o4)
+ && clobber(o5)
+ -> @mergePoint(b,x0,x1,x2,x3,x4,x5,x6,x7) (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
+ && x0.Uses == 1
+ && x1.Uses == 1
+ && s0.Uses == 1
+ && mergePoint(b,x0,x1) != nil
+ && clobber(x0)
+ && clobber(x1)
+ && clobber(s0)
+ -> @mergePoint(b,x0,x1) (MOVHZload [i-1] {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)))
+ && 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)
+ -> @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)))
+ && 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)
+ && 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)))
+ && x0.Uses == 1
+ && x1.Uses == 1
+ && s0.Uses == 1
+ && mergePoint(b,x0,x1) != nil
+ && clobber(x0)
+ && clobber(x1)
+ && clobber(s0)
+ -> @mergePoint(b,x0,x1) (MOVHZloadidx <v.Type> [i-1] {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)))
+ && 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)
+ -> @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)))
+ && x0.Uses == 1
+ && x1.Uses == 1
+ && x2.Uses == 1
+ && x3.Uses == 1
+ && x4.Uses == 1
+ && x5.Uses == 1
+ && x6.Uses == 1
+ && x7.Uses == 1
+ && s0.Uses == 1
+ && s1.Uses == 1
+ && s2.Uses == 1
+ && s3.Uses == 1
+ && s4.Uses == 1
+ && s5.Uses == 1
+ && s6.Uses == 1
+ && o0.Uses == 1
+ && o1.Uses == 1
+ && o2.Uses == 1
+ && o3.Uses == 1
+ && o4.Uses == 1
+ && o5.Uses == 1
+ && mergePoint(b,x0,x1,x2,x3,x4,x5,x6,x7) != nil
+ && clobber(x0)
+ && clobber(x1)
+ && clobber(x2)
+ && clobber(x3)
+ && clobber(x4)
+ && clobber(x5)
+ && clobber(x6)
+ && clobber(x7)
+ && clobber(s0)
+ && clobber(s1)
+ && clobber(s2)
+ && clobber(s3)
+ && clobber(s4)
+ && clobber(s5)
+ && clobber(s6)
+ && clobber(o0)
+ && clobber(o1)
+ && clobber(o2)
+ && clobber(o3)
+ && clobber(o4)
+ && clobber(o5)
+ -> @mergePoint(b,x0,x1,x2,x3,x4,x5,x6,x7) (MOVDloadidx <v.Type> [i-7] {s} p idx mem)
+
+// Combine stores into store multiples.
+// 32-bit
+(MOVWstore [i] {s} p w1 x:(MOVWstore [i-4] {s} p w0 mem))
+ && p.Op != OpSB
+ && x.Uses == 1
+ && is20Bit(i-4)
+ && clobber(x)
+ -> (STM2 [i-4] {s} p w0 w1 mem)
+(MOVWstore [i] {s} p w2 x:(STM2 [i-8] {s} p w0 w1 mem))
+ && x.Uses == 1
+ && is20Bit(i-8)
+ && clobber(x)
+ -> (STM3 [i-8] {s} p w0 w1 w2 mem)
+(MOVWstore [i] {s} p w3 x:(STM3 [i-12] {s} p w0 w1 w2 mem))
+ && x.Uses == 1
+ && is20Bit(i-12)
+ && clobber(x)
+ -> (STM4 [i-12] {s} p w0 w1 w2 w3 mem)
+(STM2 [i] {s} p w2 w3 x:(STM2 [i-8] {s} p w0 w1 mem))
+ && x.Uses == 1
+ && is20Bit(i-8)
+ && clobber(x)
+ -> (STM4 [i-8] {s} p w0 w1 w2 w3 mem)
+// 64-bit
+(MOVDstore [i] {s} p w1 x:(MOVDstore [i-8] {s} p w0 mem))
+ && p.Op != OpSB
+ && x.Uses == 1
+ && is20Bit(i-8)
+ && clobber(x)
+ -> (STMG2 [i-8] {s} p w0 w1 mem)
+(MOVDstore [i] {s} p w2 x:(STMG2 [i-16] {s} p w0 w1 mem))
+ && x.Uses == 1
+ && is20Bit(i-16)
+ && clobber(x)
+ -> (STMG3 [i-16] {s} p w0 w1 w2 mem)
+(MOVDstore [i] {s} p w3 x:(STMG3 [i-24] {s} p w0 w1 w2 mem))
+ && x.Uses == 1
+ && is20Bit(i-24)
+ && clobber(x)
+ -> (STMG4 [i-24] {s} p w0 w1 w2 w3 mem)
+(STMG2 [i] {s} p w2 w3 x:(STMG2 [i-16] {s} p w0 w1 mem))
+ && x.Uses == 1
+ && is20Bit(i-16)
+ && clobber(x)
+ -> (STMG4 [i-16] {s} p w0 w1 w2 w3 mem)
+
+// Convert 32-bit store multiples into 64-bit stores.
+(STM2 [i] {s} p (SRDconst [32] x) x mem) -> (MOVDstore [i] {s} p x mem)
diff --git a/src/cmd/compile/internal/ssa/gen/S390XOps.go b/src/cmd/compile/internal/ssa/gen/S390XOps.go
new file mode 100644
index 0000000..7a25c26
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/gen/S390XOps.go
@@ -0,0 +1,623 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build ignore
+
+package main
+
+import "strings"
+
+// Notes:
+// - Integer types live in the low portion of registers. Upper portions are junk.
+// - Boolean types use the low-order byte of a register. 0=false, 1=true.
+// Upper bytes are junk.
+// - When doing sub-register operations, we try to write the whole
+// destination register to avoid a partial-register write.
+// - Unused portions of AuxInt (or the Val portion of ValAndOff) are
+// filled by sign-extending the used portion. Users of AuxInt which interpret
+// AuxInt as unsigned (e.g. shifts) must be careful.
+
+// Suffixes encode the bit width of various instructions.
+// D (double word) = 64 bit (frequently omitted)
+// W (word) = 32 bit
+// H (half word) = 16 bit
+// B (byte) = 8 bit
+
+// copied from ../../s390x/reg.go
+var regNamesS390X = []string{
+ "R0",
+ "R1",
+ "R2",
+ "R3",
+ "R4",
+ "R5",
+ "R6",
+ "R7",
+ "R8",
+ "R9",
+ "R10",
+ "R11",
+ "R12",
+ "g", // R13
+ "R14",
+ "SP", // R15
+ "F0",
+ "F1",
+ "F2",
+ "F3",
+ "F4",
+ "F5",
+ "F6",
+ "F7",
+ "F8",
+ "F9",
+ "F10",
+ "F11",
+ "F12",
+ "F13",
+ "F14",
+ "F15",
+
+ //pseudo-registers
+ "SB",
+}
+
+func init() {
+ // Make map from reg names to reg integers.
+ if len(regNamesS390X) > 64 {
+ panic("too many registers")
+ }
+ num := map[string]int{}
+ for i, name := range regNamesS390X {
+ num[name] = i
+ }
+ buildReg := func(s string) regMask {
+ m := regMask(0)
+ for _, r := range strings.Split(s, " ") {
+ if n, ok := num[r]; ok {
+ m |= regMask(1) << uint(n)
+ continue
+ }
+ panic("register " + r + " not found")
+ }
+ return m
+ }
+
+ // Common individual register masks
+ var (
+ sp = buildReg("SP")
+ sb = buildReg("SB")
+ r0 = buildReg("R0")
+
+ // R10 and R11 are reserved by the assembler.
+ gp = buildReg("R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14")
+ gpsp = gp | sp
+
+ // R0 is considered to contain the value 0 in address calculations.
+ ptr = gp &^ r0
+ ptrsp = ptr | sp
+ ptrspsb = ptrsp | sb
+
+ fp = buildReg("F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15")
+ callerSave = gp | fp
+ )
+ // Common slices of register masks
+ var (
+ gponly = []regMask{gp}
+ fponly = []regMask{fp}
+ )
+
+ // Common regInfo
+ var (
+ gp01 = regInfo{inputs: []regMask{}, outputs: gponly}
+ gp11 = regInfo{inputs: []regMask{gp}, outputs: gponly}
+ gp11sp = regInfo{inputs: []regMask{gpsp}, outputs: gponly}
+ gp21 = regInfo{inputs: []regMask{gp, gp}, outputs: gponly}
+ gp21sp = regInfo{inputs: []regMask{gpsp, gp}, outputs: gponly}
+
+ // R0 evaluates to 0 when used as the number of bits to shift
+ // so we need to exclude it from that operand.
+ sh21 = regInfo{inputs: []regMask{gp, ptr}, outputs: gponly}
+
+ addr = regInfo{inputs: []regMask{sp | sb}, outputs: gponly}
+ addridx = regInfo{inputs: []regMask{sp | sb, ptrsp}, outputs: gponly}
+
+ gp2flags = regInfo{inputs: []regMask{gpsp, gpsp}}
+ gp1flags = regInfo{inputs: []regMask{gpsp}}
+ flagsgp = regInfo{outputs: gponly}
+ gp2flags1 = regInfo{inputs: []regMask{gp, gp}, outputs: gponly}
+
+ gpload = regInfo{inputs: []regMask{ptrspsb, 0}, outputs: gponly}
+ gploadidx = regInfo{inputs: []regMask{ptrspsb, ptrsp, 0}, outputs: gponly}
+ gpopload = regInfo{inputs: []regMask{gp, ptrsp, 0}, outputs: gponly}
+ gpstore = regInfo{inputs: []regMask{ptrspsb, gpsp, 0}}
+ gpstoreconst = regInfo{inputs: []regMask{ptrspsb, 0}}
+ gpstoreidx = regInfo{inputs: []regMask{ptrsp, ptrsp, gpsp, 0}}
+ gpstorebr = regInfo{inputs: []regMask{ptrsp, gpsp, 0}}
+ gpstorelaa = regInfo{inputs: []regMask{ptrspsb, gpsp, 0}, outputs: gponly}
+
+ gpmvc = regInfo{inputs: []regMask{ptrsp, ptrsp, 0}}
+
+ fp01 = regInfo{inputs: []regMask{}, outputs: fponly}
+ fp21 = regInfo{inputs: []regMask{fp, fp}, outputs: fponly}
+ fp21clobber = regInfo{inputs: []regMask{fp, fp}, outputs: fponly}
+ fpgp = regInfo{inputs: fponly, outputs: gponly}
+ gpfp = regInfo{inputs: gponly, outputs: fponly}
+ fp11 = regInfo{inputs: fponly, outputs: fponly}
+ fp11clobber = regInfo{inputs: fponly, outputs: fponly}
+ fp2flags = regInfo{inputs: []regMask{fp, fp}}
+
+ fpload = regInfo{inputs: []regMask{ptrspsb, 0}, outputs: fponly}
+ fploadidx = regInfo{inputs: []regMask{ptrsp, ptrsp, 0}, outputs: fponly}
+
+ fpstore = regInfo{inputs: []regMask{ptrspsb, fp, 0}}
+ fpstoreidx = regInfo{inputs: []regMask{ptrsp, ptrsp, fp, 0}}
+
+ // LoweredAtomicCas may overwrite arg1, so force it to R0 for now.
+ cas = regInfo{inputs: []regMask{ptrsp, r0, gpsp, 0}, outputs: []regMask{gp, 0}, clobbers: r0}
+
+ // LoweredAtomicExchange overwrites the output before executing
+ // CS{,G}, so the output register must not be the same as the
+ // input register. For now we just force the output register to
+ // R0.
+ exchange = regInfo{inputs: []regMask{ptrsp, gpsp &^ r0, 0}, outputs: []regMask{r0, 0}}
+ )
+
+ 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
+
+ // 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: "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
+ {name: "DIVDU", argLength: 2, reg: gp21, asm: "DIVDU", resultInArg0: true, clobberFlags: true}, // arg0 / arg1
+ {name: "DIVWU", argLength: 2, reg: gp21, asm: "DIVWU", resultInArg0: true, clobberFlags: true}, // arg0 / arg1
+
+ {name: "MODD", argLength: 2, reg: gp21, asm: "MODD", resultInArg0: true, clobberFlags: true}, // arg0 % arg1
+ {name: "MODW", argLength: 2, reg: gp21, asm: "MODW", resultInArg0: true, clobberFlags: true}, // arg0 % arg1
+
+ {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: "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
+
+ {name: "CMPU", argLength: 2, reg: gp2flags, asm: "CMPU", typ: "Flags"}, // arg0 compare to arg1
+ {name: "CMPWU", argLength: 2, reg: gp2flags, asm: "CMPWU", typ: "Flags"}, // arg0 compare to arg1
+
+ {name: "CMPconst", argLength: 1, reg: gp1flags, asm: "CMP", typ: "Flags", aux: "Int64"}, // arg0 compare to auxint
+ {name: "CMPWconst", argLength: 1, reg: gp1flags, asm: "CMPW", typ: "Flags", aux: "Int32"}, // arg0 compare to auxint
+ {name: "CMPUconst", argLength: 1, reg: gp1flags, asm: "CMPU", typ: "Flags", aux: "Int64"}, // arg0 compare to auxint
+ {name: "CMPWUconst", argLength: 1, reg: gp1flags, asm: "CMPWU", typ: "Flags", aux: "Int32"}, // arg0 compare to auxint
+
+ {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: "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
+
+ // 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: "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
+
+ // unary ops
+ {name: "NEG", argLength: 1, reg: gp11, asm: "NEG", clobberFlags: true}, // -arg0
+ {name: "NEGW", argLength: 1, reg: gp11, asm: "NEGW", clobberFlags: true}, // -arg0
+
+ {name: "NOT", argLength: 1, reg: gp11, resultInArg0: true, clobberFlags: true}, // ^arg0
+ {name: "NOTW", argLength: 1, reg: gp11, resultInArg0: true, clobberFlags: true}, // ^arg0
+
+ {name: "FSQRT", argLength: 1, reg: fp11, asm: "FSQRT"}, // sqrt(arg0)
+
+ {name: "SUBEcarrymask", argLength: 1, reg: flagsgp, asm: "SUBE"}, // (int64)(-1) if carry is set, 0 if carry is clear.
+ {name: "SUBEWcarrymask", argLength: 1, reg: flagsgp, asm: "SUBE"}, // (int32)(-1) if carry is set, 0 if carry is clear.
+ // Note: 32-bits subtraction is not implemented in S390X. Temporarily use SUBE (64-bits).
+
+ {name: "MOVDEQ", argLength: 3, reg: gp2flags1, resultInArg0: true, asm: "MOVDEQ"}, // extract == condition from arg0
+ {name: "MOVDNE", argLength: 3, reg: gp2flags1, resultInArg0: true, asm: "MOVDNE"}, // extract != condition from arg0
+ {name: "MOVDLT", argLength: 3, reg: gp2flags1, resultInArg0: true, asm: "MOVDLT"}, // extract signed < condition from arg0
+ {name: "MOVDLE", argLength: 3, reg: gp2flags1, resultInArg0: true, asm: "MOVDLE"}, // extract signed <= condition from arg0
+ {name: "MOVDGT", argLength: 3, reg: gp2flags1, resultInArg0: true, asm: "MOVDGT"}, // extract signed > condition from arg0
+ {name: "MOVDGE", argLength: 3, reg: gp2flags1, resultInArg0: true, asm: "MOVDGE"}, // extract signed >= condition from arg0
+
+ // Different rules for floating point conditions because
+ // any comparison involving a NaN is always false and thus
+ // the patterns for inverting conditions cannot be used.
+ {name: "MOVDGTnoinv", argLength: 3, reg: gp2flags1, resultInArg0: true, asm: "MOVDGT"}, // extract floating > condition from arg0
+ {name: "MOVDGEnoinv", argLength: 3, reg: gp2flags1, resultInArg0: true, asm: "MOVDGE"}, // extract floating >= condition from arg0
+
+ {name: "MOVBreg", argLength: 1, reg: gp11sp, asm: "MOVB", typ: "Int64"}, // sign extend arg0 from int8 to int64
+ {name: "MOVBZreg", argLength: 1, reg: gp11sp, asm: "MOVBZ", typ: "UInt64"}, // zero extend arg0 from int8 to int64
+ {name: "MOVHreg", argLength: 1, reg: gp11sp, asm: "MOVH", typ: "Int64"}, // sign extend arg0 from int16 to int64
+ {name: "MOVHZreg", argLength: 1, reg: gp11sp, asm: "MOVHZ", typ: "UInt64"}, // zero extend arg0 from int16 to int64
+ {name: "MOVWreg", argLength: 1, reg: gp11sp, asm: "MOVW", typ: "Int64"}, // sign extend arg0 from int32 to int64
+ {name: "MOVWZreg", argLength: 1, reg: gp11sp, asm: "MOVWZ", typ: "UInt64"}, // zero extend arg0 from int32 to int64
+
+ {name: "MOVDconst", reg: gp01, asm: "MOVD", typ: "UInt64", aux: "Int64", rematerializeable: true}, // auxint
+
+ {name: "CFDBRA", argLength: 1, reg: fpgp, asm: "CFDBRA"}, // convert float64 to int32
+ {name: "CGDBRA", argLength: 1, reg: fpgp, asm: "CGDBRA"}, // convert float64 to int64
+ {name: "CFEBRA", argLength: 1, reg: fpgp, asm: "CFEBRA"}, // convert float32 to int32
+ {name: "CGEBRA", argLength: 1, reg: fpgp, asm: "CGEBRA"}, // convert float32 to int64
+ {name: "CEFBRA", argLength: 1, reg: gpfp, asm: "CEFBRA"}, // convert int32 to float32
+ {name: "CDFBRA", argLength: 1, reg: gpfp, asm: "CDFBRA"}, // convert int32 to float64
+ {name: "CEGBRA", argLength: 1, reg: gpfp, asm: "CEGBRA"}, // convert int64 to float32
+ {name: "CDGBRA", argLength: 1, reg: gpfp, asm: "CDGBRA"}, // convert int64 to float64
+ {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
+
+ // 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: "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: "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: "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
+
+ // 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.
+
+ // 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: "CLEAR", argLength: 2, reg: regInfo{inputs: []regMask{ptr, 0}}, asm: "CLEAR", aux: "SymValAndOff", typ: "Mem", clobberFlags: true, 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: "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)
+ // InvertFlags is a pseudo-op which can't appear in assembly output.
+ {name: "InvertFlags", argLength: 1}, // reverse direction of arg0
+
+ // Pseudo-ops
+ {name: "LoweredGetG", argLength: 1, reg: gp01}, // arg0=mem
+ // Scheduler ensures LoweredGetClosurePtr occurs only in entry block,
+ // and sorts it to the very beginning of the block to prevent other
+ // use of R12 (the closure pointer)
+ {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},
+
+ // MOVDconvert converts between pointers and integers.
+ // We have a special op for this so as to not confuse GC
+ // (particularly stack maps). It takes a memory arg so it
+ // gets correctly ordered with respect to GC safepoints.
+ // arg0=ptr/int arg1=mem, output=int/ptr
+ {name: "MOVDconvert", argLength: 2, reg: gp11sp, asm: "MOVD"},
+
+ // Constant flag values. For any comparison, there are 5 possible
+ // outcomes: the three from the signed total order (<,==,>) and the
+ // three from the unsigned total order. The == cases overlap.
+ // Note: there's a sixth "unordered" outcome for floating-point
+ // comparisons, but we don't use such a beast yet.
+ // These ops are for temporary use by rewrite rules. They
+ // cannot appear in the generated assembly.
+ {name: "FlagEQ"}, // equal
+ {name: "FlagLT"}, // <
+ {name: "FlagGT"}, // >
+
+ // 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},
+
+ // 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},
+ {name: "MOVDatomicstore", argLength: 3, reg: gpstore, asm: "MOVD", aux: "SymOff", typ: "Mem", clobberFlags: true, faultOnNilArg0: true},
+
+ // 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},
+ {name: "LAAG", argLength: 3, reg: gpstorelaa, asm: "LAAG", typ: "(UInt64,Mem)", aux: "SymOff", faultOnNilArg0: 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>.
+
+ // Compare and swap.
+ // arg0 = pointer, arg1 = old value, arg2 = new value, arg3 = memory.
+ // if *(arg0+auxint+aux) == arg1 {
+ // *(arg0+auxint+aux) = arg2
+ // return (true, memory)
+ // } else {
+ // return (false, memory)
+ // }
+ // Note that these instructions also return the old value in arg1, but we ignore it.
+ // TODO: have these return flags instead of bool. The current system generates:
+ // CS ...
+ // MOVD $0, ret
+ // BNE 2(PC)
+ // MOVD $1, ret
+ // CMPW ret, $0
+ // BNE ...
+ // instead of just
+ // CS ...
+ // 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},
+ {name: "LoweredAtomicCas64", argLength: 4, reg: cas, asm: "CSG", aux: "SymOff", clobberFlags: true, faultOnNilArg0: true},
+
+ // 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},
+ {name: "LoweredAtomicExchange64", argLength: 3, reg: exchange, asm: "CSG", aux: "SymOff", clobberFlags: true, faultOnNilArg0: true},
+
+ // find leftmost one
+ {
+ name: "FLOGR",
+ argLength: 1,
+ reg: regInfo{inputs: gponly, outputs: []regMask{buildReg("R0")}, clobbers: buildReg("R1")},
+ asm: "FLOGR",
+ typ: "UInt64",
+ clobberFlags: true,
+ },
+
+ // store multiple
+ {
+ name: "STMG2",
+ argLength: 4,
+ reg: regInfo{inputs: []regMask{ptrsp, buildReg("R1"), buildReg("R2"), 0}},
+ aux: "SymOff",
+ typ: "Mem",
+ asm: "STMG",
+ faultOnNilArg0: true,
+ },
+ {
+ name: "STMG3",
+ argLength: 5,
+ reg: regInfo{inputs: []regMask{ptrsp, buildReg("R1"), buildReg("R2"), buildReg("R3"), 0}},
+ aux: "SymOff",
+ typ: "Mem",
+ asm: "STMG",
+ faultOnNilArg0: true,
+ },
+ {
+ name: "STMG4",
+ argLength: 6,
+ reg: regInfo{inputs: []regMask{
+ ptrsp,
+ buildReg("R1"),
+ buildReg("R2"),
+ buildReg("R3"),
+ buildReg("R4"),
+ 0,
+ }},
+ aux: "SymOff",
+ typ: "Mem",
+ asm: "STMG",
+ faultOnNilArg0: true,
+ },
+ {
+ name: "STM2",
+ argLength: 4,
+ reg: regInfo{inputs: []regMask{ptrsp, buildReg("R1"), buildReg("R2"), 0}},
+ aux: "SymOff",
+ typ: "Mem",
+ asm: "STMY",
+ faultOnNilArg0: true,
+ },
+ {
+ name: "STM3",
+ argLength: 5,
+ reg: regInfo{inputs: []regMask{ptrsp, buildReg("R1"), buildReg("R2"), buildReg("R3"), 0}},
+ aux: "SymOff",
+ typ: "Mem",
+ asm: "STMY",
+ faultOnNilArg0: true,
+ },
+ {
+ name: "STM4",
+ argLength: 6,
+ reg: regInfo{inputs: []regMask{
+ ptrsp,
+ buildReg("R1"),
+ buildReg("R2"),
+ buildReg("R3"),
+ buildReg("R4"),
+ 0,
+ }},
+ aux: "SymOff",
+ typ: "Mem",
+ asm: "STMY",
+ faultOnNilArg0: true,
+ },
+
+ // large move
+ // auxint = remaining bytes after loop (rem)
+ // arg0 = address of dst memory (in R1, changed as a side effect)
+ // arg1 = address of src memory (in R2, changed as a side effect)
+ // arg2 = pointer to last address to move in loop + 256
+ // arg3 = mem
+ // returns mem
+ //
+ // mvc: MVC $256, 0(R2), 0(R1)
+ // MOVD $256(R1), R1
+ // MOVD $256(R2), R2
+ // CMP R2, Rarg2
+ // BNE mvc
+ // MVC $rem, 0(R2), 0(R1) // if rem > 0
+ {
+ name: "LoweredMove",
+ aux: "Int64",
+ argLength: 4,
+ reg: regInfo{
+ inputs: []regMask{buildReg("R1"), buildReg("R2"), gpsp},
+ clobbers: buildReg("R1 R2"),
+ },
+ clobberFlags: true,
+ typ: "Mem",
+ },
+
+ // large clear
+ // auxint = remaining bytes after loop (rem)
+ // arg0 = address of dst memory (in R1, changed as a side effect)
+ // arg1 = pointer to last address to zero in loop + 256
+ // arg2 = mem
+ // returns mem
+ //
+ // clear: CLEAR $256, 0(R1)
+ // MOVD $256(R1), R1
+ // CMP R1, Rarg2
+ // BNE clear
+ // CLEAR $rem, 0(R1) // if rem > 0
+ {
+ name: "LoweredZero",
+ aux: "Int64",
+ argLength: 3,
+ reg: regInfo{
+ inputs: []regMask{buildReg("R1"), gpsp},
+ clobbers: buildReg("R1"),
+ },
+ clobberFlags: true,
+ typ: "Mem",
+ },
+ }
+
+ var S390Xblocks = []blockData{
+ {name: "EQ"},
+ {name: "NE"},
+ {name: "LT"},
+ {name: "LE"},
+ {name: "GT"},
+ {name: "GE"},
+ {name: "GTF"}, // FP comparison
+ {name: "GEF"}, // FP comparison
+ }
+
+ archs = append(archs, arch{
+ name: "S390X",
+ pkg: "cmd/internal/obj/s390x",
+ genfile: "../../s390x/ssa.go",
+ ops: S390Xops,
+ blocks: S390Xblocks,
+ regnames: regNamesS390X,
+ gpregmask: gp,
+ fpregmask: fp,
+ framepointerreg: -1, // not used
+ linkreg: int8(num["R14"]),
+ })
+}
diff --git a/src/cmd/compile/internal/ssa/gen/dec64.rules b/src/cmd/compile/internal/ssa/gen/dec64.rules
new file mode 100644
index 0000000..961ffc7
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/gen/dec64.rules
@@ -0,0 +1,447 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file contains rules to decompose [u]int64 types on 32-bit
+// architectures. These rules work together with the decomposeBuiltIn
+// pass which handles phis of these types.
+
+(Int64Hi (Int64Make hi _)) -> hi
+(Int64Lo (Int64Make _ lo)) -> lo
+
+
+(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 <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 <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 <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))
+
+(Store [8] dst (Int64Make hi lo) mem) && !config.BigEndian ->
+ (Store [4]
+ (OffPtr <hi.Type.PtrTo()> [4] dst)
+ hi
+ (Store [4] dst lo mem))
+
+(Store [8] dst (Int64Make hi lo) mem) && config.BigEndian ->
+ (Store [4]
+ (OffPtr <lo.Type.PtrTo()> [4] dst)
+ lo
+ (Store [4] 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 {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 {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 {n} [off]) && is64BitInt(v.Type) && config.BigEndian && !v.Type.IsSigned() ->
+ (Int64Make
+ (Arg <config.fe.TypeUInt32()> {n} [off])
+ (Arg <config.fe.TypeUInt32()> {n} [off+4]))
+
+(Add64 x y) ->
+ (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))))
+
+(Sub64 x y) ->
+ (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))))
+
+(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))))
+
+(And64 x y) ->
+ (Int64Make
+ (And32 <config.fe.TypeUInt32()> (Int64Hi x) (Int64Hi y))
+ (And32 <config.fe.TypeUInt32()> (Int64Lo x) (Int64Lo y)))
+
+(Or64 x y) ->
+ (Int64Make
+ (Or32 <config.fe.TypeUInt32()> (Int64Hi x) (Int64Hi y))
+ (Or32 <config.fe.TypeUInt32()> (Int64Lo x) (Int64Lo y)))
+
+(Xor64 x y) ->
+ (Int64Make
+ (Xor32 <config.fe.TypeUInt32()> (Int64Hi x) (Int64Hi y))
+ (Xor32 <config.fe.TypeUInt32()> (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)))
+
+(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)))))
+
+(Bswap64 x) ->
+ (Int64Make
+ (Bswap32 <config.fe.TypeUInt32()> (Int64Lo x))
+ (Bswap32 <config.fe.TypeUInt32()> (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)
+(ZeroExt16to64 x) -> (ZeroExt32to64 (ZeroExt16to32 x))
+(ZeroExt8to64 x) -> (ZeroExt32to64 (ZeroExt8to32 x))
+
+(Trunc64to32 (Int64Make _ lo)) -> lo
+(Trunc64to16 (Int64Make _ lo)) -> (Trunc32to16 lo)
+(Trunc64to8 (Int64Make _ lo)) -> (Trunc32to8 lo)
+
+(Lsh32x64 _ (Int64Make (Const32 [c]) _)) && c != 0 -> (Const32 [0])
+(Rsh32x64 x (Int64Make (Const32 [c]) _)) && c != 0 -> (Signmask x)
+(Rsh32Ux64 _ (Int64Make (Const32 [c]) _)) && c != 0 -> (Const32 [0])
+(Lsh16x64 _ (Int64Make (Const32 [c]) _)) && c != 0 -> (Const32 [0])
+(Rsh16x64 x (Int64Make (Const32 [c]) _)) && c != 0 -> (Signmask (SignExt16to32 x))
+(Rsh16Ux64 _ (Int64Make (Const32 [c]) _)) && c != 0 -> (Const32 [0])
+(Lsh8x64 _ (Int64Make (Const32 [c]) _)) && c != 0 -> (Const32 [0])
+(Rsh8x64 x (Int64Make (Const32 [c]) _)) && c != 0 -> (Signmask (SignExt8to32 x))
+(Rsh8Ux64 _ (Int64Make (Const32 [c]) _)) && c != 0 -> (Const32 [0])
+
+(Lsh32x64 x (Int64Make (Const32 [0]) lo)) -> (Lsh32x32 x lo)
+(Rsh32x64 x (Int64Make (Const32 [0]) lo)) -> (Rsh32x32 x lo)
+(Rsh32Ux64 x (Int64Make (Const32 [0]) lo)) -> (Rsh32Ux32 x lo)
+(Lsh16x64 x (Int64Make (Const32 [0]) lo)) -> (Lsh16x32 x lo)
+(Rsh16x64 x (Int64Make (Const32 [0]) lo)) -> (Rsh16x32 x lo)
+(Rsh16Ux64 x (Int64Make (Const32 [0]) lo)) -> (Rsh16Ux32 x lo)
+(Lsh8x64 x (Int64Make (Const32 [0]) lo)) -> (Lsh8x32 x lo)
+(Rsh8x64 x (Int64Make (Const32 [0]) lo)) -> (Rsh8x32 x lo)
+(Rsh8Ux64 x (Int64Make (Const32 [0]) lo)) -> (Rsh8Ux32 x lo)
+
+(Lsh64x64 _ (Int64Make (Const32 [c]) _)) && c != 0 -> (Const64 [0])
+(Rsh64x64 x (Int64Make (Const32 [c]) _)) && c != 0 -> (Int64Make (Signmask (Int64Hi x)) (Signmask (Int64Hi x)))
+(Rsh64Ux64 _ (Int64Make (Const32 [c]) _)) && c != 0 -> (Const64 [0])
+
+(Lsh64x64 x (Int64Make (Const32 [0]) lo)) -> (Lsh64x32 x lo)
+(Rsh64x64 x (Int64Make (Const32 [0]) lo)) -> (Rsh64x32 x lo)
+(Rsh64Ux64 x (Int64Make (Const32 [0]) lo)) -> (Rsh64Ux32 x lo)
+
+// 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))
+(Rsh64x64 x (Int64Make hi lo)) && hi.Op != OpConst32 ->
+ (Rsh64x32 x (Or32 <config.fe.TypeUInt32()> (Zeromask hi) lo))
+(Rsh64Ux64 x (Int64Make hi lo)) && hi.Op != OpConst32 ->
+ (Rsh64Ux32 x (Or32 <config.fe.TypeUInt32()> (Zeromask hi) lo))
+(Lsh32x64 x (Int64Make hi lo)) && hi.Op != OpConst32 ->
+ (Lsh32x32 x (Or32 <config.fe.TypeUInt32()> (Zeromask hi) lo))
+(Rsh32x64 x (Int64Make hi lo)) && hi.Op != OpConst32 ->
+ (Rsh32x32 x (Or32 <config.fe.TypeUInt32()> (Zeromask hi) lo))
+(Rsh32Ux64 x (Int64Make hi lo)) && hi.Op != OpConst32 ->
+ (Rsh32Ux32 x (Or32 <config.fe.TypeUInt32()> (Zeromask hi) lo))
+(Lsh16x64 x (Int64Make hi lo)) && hi.Op != OpConst32 ->
+ (Lsh16x32 x (Or32 <config.fe.TypeUInt32()> (Zeromask hi) lo))
+(Rsh16x64 x (Int64Make hi lo)) && hi.Op != OpConst32 ->
+ (Rsh16x32 x (Or32 <config.fe.TypeUInt32()> (Zeromask hi) lo))
+(Rsh16Ux64 x (Int64Make hi lo)) && hi.Op != OpConst32 ->
+ (Rsh16Ux32 x (Or32 <config.fe.TypeUInt32()> (Zeromask hi) lo))
+(Lsh8x64 x (Int64Make hi lo)) && hi.Op != OpConst32 ->
+ (Lsh8x32 x (Or32 <config.fe.TypeUInt32()> (Zeromask hi) lo))
+(Rsh8x64 x (Int64Make hi lo)) && hi.Op != OpConst32 ->
+ (Rsh8x32 x (Or32 <config.fe.TypeUInt32()> (Zeromask hi) lo))
+(Rsh8Ux64 x (Int64Make hi lo)) && hi.Op != OpConst32 ->
+ (Rsh8Ux32 x (Or32 <config.fe.TypeUInt32()> (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()>
+ 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))
+(Lsh64x16 (Int64Make hi lo) s) ->
+ (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))
+(Lsh64x8 (Int64Make hi lo) s) ->
+ (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))
+
+// 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()>
+ 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])))))
+(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()>
+ 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])))))
+(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()>
+ 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])))))
+
+// 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()>
+ 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
+ (Rsh32Ux32 <config.fe.TypeUInt32()> s (Const32 <config.fe.TypeUInt32()> [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()>
+ 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
+ (ZeroExt16to32
+ (Rsh16Ux32 <config.fe.TypeUInt16()> s (Const32 <config.fe.TypeUInt32()> [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()>
+ 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
+ (Rsh8Ux32 <config.fe.TypeUInt8()> s (Const32 <config.fe.TypeUInt32()> [5])))))))
+
+// 64xConst32 shifts
+// we probably do not need them -- lateopt may take care of them just fine
+//(Lsh64x32 _ (Const32 [c])) && uint32(c) >= 64 -> (Const64 [0])
+//(Rsh64x32 x (Const32 [c])) && uint32(c) >= 64 -> (Int64Make (Signmask (Int64Hi x)) (Signmask (Int64Hi x)))
+//(Rsh64Ux32 _ (Const32 [c])) && uint32(c) >= 64 -> (Const64 [0])
+//
+//(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]))
+//(Rsh64x32 x (Const32 [c])) && c < 64 && c > 32 ->
+// (Int64Make
+// (Signmask (Int64Hi x))
+// (Rsh32x32 <config.fe.TypeInt32()> (Int64Hi x) (Const32 <config.fe.TypeUInt32()> [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])))
+//
+//(Lsh64x32 x (Const32 [32])) -> (Int64Make (Int64Lo x) (Const32 <config.fe.TypeUInt32()> [0]))
+//(Rsh64x32 x (Const32 [32])) -> (Int64Make (Signmask (Int64Hi x)) (Int64Hi x))
+//(Rsh64Ux32 x (Const32 [32])) -> (Int64Make (Const32 <config.fe.TypeUInt32()> [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])))
+//(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]))))
+//(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]))))
+//
+//(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))]))
+(Const64 <t> [c]) && !t.IsSigned() ->
+ (Int64Make (Const32 <config.fe.TypeUInt32()> [c>>32]) (Const32 <config.fe.TypeUInt32()> [int64(int32(c))]))
+
+(Eq64 x y) ->
+ (AndB
+ (Eq32 (Int64Hi x) (Int64Hi y))
+ (Eq32 (Int64Lo x) (Int64Lo y)))
+
+(Neq64 x y) ->
+ (OrB
+ (Neq32 (Int64Hi x) (Int64Hi y))
+ (Neq32 (Int64Lo x) (Int64Lo y)))
+
+(Less64U x y) ->
+ (OrB
+ (Less32U (Int64Hi x) (Int64Hi y))
+ (AndB
+ (Eq32 (Int64Hi x) (Int64Hi y))
+ (Less32U (Int64Lo x) (Int64Lo y))))
+
+(Leq64U x y) ->
+ (OrB
+ (Less32U (Int64Hi x) (Int64Hi y))
+ (AndB
+ (Eq32 (Int64Hi x) (Int64Hi y))
+ (Leq32U (Int64Lo x) (Int64Lo y))))
+
+(Greater64U x y) ->
+ (OrB
+ (Greater32U (Int64Hi x) (Int64Hi y))
+ (AndB
+ (Eq32 (Int64Hi x) (Int64Hi y))
+ (Greater32U (Int64Lo x) (Int64Lo y))))
+
+(Geq64U x y) ->
+ (OrB
+ (Greater32U (Int64Hi x) (Int64Hi y))
+ (AndB
+ (Eq32 (Int64Hi x) (Int64Hi y))
+ (Geq32U (Int64Lo x) (Int64Lo y))))
+
+(Less64 x y) ->
+ (OrB
+ (Less32 (Int64Hi x) (Int64Hi y))
+ (AndB
+ (Eq32 (Int64Hi x) (Int64Hi y))
+ (Less32U (Int64Lo x) (Int64Lo y))))
+
+(Leq64 x y) ->
+ (OrB
+ (Less32 (Int64Hi x) (Int64Hi y))
+ (AndB
+ (Eq32 (Int64Hi x) (Int64Hi y))
+ (Leq32U (Int64Lo x) (Int64Lo y))))
+
+(Greater64 x y) ->
+ (OrB
+ (Greater32 (Int64Hi x) (Int64Hi y))
+ (AndB
+ (Eq32 (Int64Hi x) (Int64Hi y))
+ (Greater32U (Int64Lo x) (Int64Lo y))))
+
+(Geq64 x y) ->
+ (OrB
+ (Greater32 (Int64Hi x) (Int64Hi y))
+ (AndB
+ (Eq32 (Int64Hi x) (Int64Hi y))
+ (Geq32U (Int64Lo x) (Int64Lo y))))
diff --git a/src/cmd/compile/internal/ssa/gen/dec64Ops.go b/src/cmd/compile/internal/ssa/gen/dec64Ops.go
new file mode 100644
index 0000000..8c5883b
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/gen/dec64Ops.go
@@ -0,0 +1,20 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build ignore
+
+package main
+
+var dec64Ops = []opData{}
+
+var dec64Blocks = []blockData{}
+
+func init() {
+ archs = append(archs, arch{
+ name: "dec64",
+ ops: dec64Ops,
+ blocks: dec64Blocks,
+ generic: true,
+ })
+}
diff --git a/src/cmd/compile/internal/ssa/gen/generic.rules b/src/cmd/compile/internal/ssa/gen/generic.rules
index f5d1c98..0137b10 100644
--- a/src/cmd/compile/internal/ssa/gen/generic.rules
+++ b/src/cmd/compile/internal/ssa/gen/generic.rules
@@ -2,6 +2,19 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// Simplifications that apply to all backend architectures. As an example, this
+// Go source code
+//
+// y := 0 * x
+//
+// can be translated into y := 0 without losing any information, which saves a
+// pointless multiplication instruction. Other .rules files in this directory
+// (for example AMD64.rules) contain rules specific to the architecture in the
+// filename. The rules here apply to every architecture.
+//
+// The code for parsing this file lives in rulegen.go; this file generates
+// ssa/rewritegeneric.go.
+
// values are specified using the following format:
// (op <type> [auxint] {aux} arg0 arg1 ...)
// the type, aux, and auxint fields are optional
@@ -34,6 +47,27 @@
(Cvt64Fto32F (Const64F [c])) -> (Const32F [f2i(float64(i2f32(c)))])
(Cvt32Fto64F (Const32F [c])) -> (Const64F [c]) // c is already a 64 bit float
+(Trunc16to8 (ZeroExt8to16 x)) -> x
+(Trunc32to8 (ZeroExt8to32 x)) -> x
+(Trunc32to16 (ZeroExt8to32 x)) -> (ZeroExt8to16 x)
+(Trunc32to16 (ZeroExt16to32 x)) -> x
+(Trunc64to8 (ZeroExt8to64 x)) -> x
+(Trunc64to16 (ZeroExt8to64 x)) -> (ZeroExt8to16 x)
+(Trunc64to16 (ZeroExt16to64 x)) -> x
+(Trunc64to32 (ZeroExt8to64 x)) -> (ZeroExt8to32 x)
+(Trunc64to32 (ZeroExt16to64 x)) -> (ZeroExt16to32 x)
+(Trunc64to32 (ZeroExt32to64 x)) -> x
+(Trunc16to8 (SignExt8to16 x)) -> x
+(Trunc32to8 (SignExt8to32 x)) -> x
+(Trunc32to16 (SignExt8to32 x)) -> (SignExt8to16 x)
+(Trunc32to16 (SignExt16to32 x)) -> x
+(Trunc64to8 (SignExt8to64 x)) -> x
+(Trunc64to16 (SignExt8to64 x)) -> (SignExt8to16 x)
+(Trunc64to16 (SignExt16to64 x)) -> x
+(Trunc64to32 (SignExt8to64 x)) -> (SignExt8to32 x)
+(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])
@@ -46,7 +80,7 @@
(Add16 (Const16 [c]) (Const16 [d])) -> (Const16 [int64(int16(c+d))])
(Add32 (Const32 [c]) (Const32 [d])) -> (Const32 [int64(int32(c+d))])
(Add64 (Const64 [c]) (Const64 [d])) -> (Const64 [c+d])
-(Add32F (Const32F [c]) (Const32F [d])) ->
+(Add32F (Const32F [c]) (Const32F [d])) ->
(Const32F [f2i(float64(i2f32(c) + i2f32(d)))]) // ensure we combine the operands with 32 bit precision
(Add64F (Const64F [c]) (Const64F [d])) -> (Const64F [f2i(i2f(c) + i2f(d))])
(AddPtr <t> x (Const64 [c])) -> (OffPtr <t> x [c])
@@ -55,7 +89,7 @@
(Sub16 (Const16 [c]) (Const16 [d])) -> (Const16 [int64(int16(c-d))])
(Sub32 (Const32 [c]) (Const32 [d])) -> (Const32 [int64(int32(c-d))])
(Sub64 (Const64 [c]) (Const64 [d])) -> (Const64 [c-d])
-(Sub32F (Const32F [c]) (Const32F [d])) ->
+(Sub32F (Const32F [c]) (Const32F [d])) ->
(Const32F [f2i(float64(i2f32(c) - i2f32(d)))])
(Sub64F (Const64F [c]) (Const64F [d])) -> (Const64F [f2i(i2f(c) - i2f(d))])
@@ -63,10 +97,16 @@
(Mul16 (Const16 [c]) (Const16 [d])) -> (Const16 [int64(int16(c*d))])
(Mul32 (Const32 [c]) (Const32 [d])) -> (Const32 [int64(int32(c*d))])
(Mul64 (Const64 [c]) (Const64 [d])) -> (Const64 [c*d])
-(Mul32F (Const32F [c]) (Const32F [d])) ->
+(Mul32F (Const32F [c]) (Const32F [d])) ->
(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.
+(Mul8 (Const8 [-1]) x) -> (Neg8 x)
+(Mul16 (Const16 [-1]) x) -> (Neg16 x)
+(Mul32 (Const32 [-1]) x) -> (Neg32 x)
+(Mul64 (Const64 [-1]) x) -> (Neg64 x)
+
(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))])
@@ -181,6 +221,59 @@
(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)
+(Not (Eq16 x y)) -> (Neq16 x y)
+(Not (Eq8 x y)) -> (Neq8 x y)
+(Not (EqB x y)) -> (NeqB x y)
+
+(Not (Neq64 x y)) -> (Eq64 x y)
+(Not (Neq32 x y)) -> (Eq32 x y)
+(Not (Neq16 x y)) -> (Eq16 x y)
+(Not (Neq8 x y)) -> (Eq8 x y)
+(Not (NeqB x y)) -> (EqB x y)
+
+(Not (Greater64 x y)) -> (Leq64 x y)
+(Not (Greater32 x y)) -> (Leq32 x y)
+(Not (Greater16 x y)) -> (Leq16 x y)
+(Not (Greater8 x y)) -> (Leq8 x y)
+
+(Not (Greater64U x y)) -> (Leq64U x y)
+(Not (Greater32U x y)) -> (Leq32U x y)
+(Not (Greater16U x y)) -> (Leq16U x y)
+(Not (Greater8U x y)) -> (Leq8U x y)
+
+(Not (Geq64 x y)) -> (Less64 x y)
+(Not (Geq32 x y)) -> (Less32 x y)
+(Not (Geq16 x y)) -> (Less16 x y)
+(Not (Geq8 x y)) -> (Less8 x y)
+
+(Not (Geq64U x y)) -> (Less64U x y)
+(Not (Geq32U x y)) -> (Less32U x y)
+(Not (Geq16U x y)) -> (Less16U x y)
+(Not (Geq8U x y)) -> (Less8U x y)
+
+(Not (Less64 x y)) -> (Geq64 x y)
+(Not (Less32 x y)) -> (Geq32 x y)
+(Not (Less16 x y)) -> (Geq16 x y)
+(Not (Less8 x y)) -> (Geq8 x y)
+
+(Not (Less64U x y)) -> (Geq64U x y)
+(Not (Less32U x y)) -> (Geq32U x y)
+(Not (Less16U x y)) -> (Geq16U x y)
+(Not (Less8U x y)) -> (Geq8U x y)
+
+(Not (Leq64 x y)) -> (Greater64 x y)
+(Not (Leq32 x y)) -> (Greater32 x y)
+(Not (Leq16 x y)) -> (Greater16 x y)
+(Not (Leq8 x y)) -> (Greater8 x y)
+
+(Not (Leq64U x y)) -> (Greater64U x y)
+(Not (Leq32U x y)) -> (Greater32U x y)
+(Not (Leq16U x y)) -> (Greater16U x y)
+(Not (Leq8U x y)) -> (Greater8U x y)
+
// Distribute multiplication c * (d+x) -> c*d + c*x. Useful for:
// a[i].b = ...; a[i+1].b = ...
(Mul64 (Const64 <t> [c]) (Add64 <t> (Const64 <t> [d]) x)) ->
@@ -509,6 +602,25 @@
(Trunc32to16 (And32 (Const32 [y]) x)) && y&0xFFFF == 0xFFFF -> (Trunc32to16 x)
(Trunc16to8 (And16 (Const16 [y]) x)) && y&0xFF == 0xFF -> (Trunc16to8 x)
+(ZeroExt8to64 (Trunc64to8 x:(Rsh64Ux64 _ (Const64 [s])))) && s >= 56 -> x
+(ZeroExt16to64 (Trunc64to16 x:(Rsh64Ux64 _ (Const64 [s])))) && s >= 48 -> x
+(ZeroExt32to64 (Trunc64to32 x:(Rsh64Ux64 _ (Const64 [s])))) && s >= 32 -> x
+(ZeroExt8to32 (Trunc32to8 x:(Rsh32Ux64 _ (Const64 [s])))) && s >= 24 -> x
+(ZeroExt16to32 (Trunc32to16 x:(Rsh32Ux64 _ (Const64 [s])))) && s >= 16 -> x
+(ZeroExt8to16 (Trunc16to8 x:(Rsh16Ux64 _ (Const64 [s])))) && s >= 8 -> x
+
+(SignExt8to64 (Trunc64to8 x:(Rsh64x64 _ (Const64 [s])))) && s >= 56 -> x
+(SignExt16to64 (Trunc64to16 x:(Rsh64x64 _ (Const64 [s])))) && s >= 48 -> x
+(SignExt32to64 (Trunc64to32 x:(Rsh64x64 _ (Const64 [s])))) && s >= 32 -> x
+(SignExt8to32 (Trunc32to8 x:(Rsh32x64 _ (Const64 [s])))) && s >= 24 -> x
+(SignExt16to32 (Trunc32to16 x:(Rsh32x64 _ (Const64 [s])))) && s >= 16 -> x
+(SignExt8to16 (Trunc16to8 x:(Rsh16x64 _ (Const64 [s])))) && s >= 8 -> x
+
+(Slicemask (Const32 [x])) && x > 0 -> (Const32 [-1])
+(Slicemask (Const32 [0])) -> (Const32 [0])
+(Slicemask (Const64 [x])) && x > 0 -> (Const64 [-1])
+(Slicemask (Const64 [0])) -> (Const64 [0])
+
// Rewrite AND of consts as shifts if possible, slightly faster for 64 bit operands
// leading zeros can be shifted left, then right
(And64 <t> (Const64 [y]) x) && nlz(y) + nto(y) == 64 && nto(y) >= 32
@@ -556,7 +668,6 @@
// indexing operations
// Note: bounds check has already been done
-(ArrayIndex <t> [0] x:(Load ptr mem)) -> @x.Block (Load <t> ptr mem)
(PtrIndex <t> ptr idx) && config.PtrSize == 4 -> (AddPtr ptr (Mul32 <config.fe.TypeInt()> idx (Const32 <config.fe.TypeInt()> [t.ElemType().Size()])))
(PtrIndex <t> ptr idx) && config.PtrSize == 8 -> (AddPtr ptr (Mul64 <config.fe.TypeInt()> idx (Const64 <config.fe.TypeInt()> [t.ElemType().Size()])))
@@ -624,9 +735,33 @@
f1
(Store [t.FieldType(0).Size()] 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 [size] dst src mem)
-(Store [size] dst (Load <t> src mem) (VarDef {x} mem)) && !config.fe.CanSSA(t) -> (Move [size] dst src (VarDef {x} mem))
+(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))
+
+// array ops
+(ArraySelect (ArrayMake1 x)) -> x
+
+(Load <t> _ _) && t.IsArray() && t.NumElem() == 0 ->
+ (ArrayMake0)
+
+(Load <t> ptr mem) && t.IsArray() && t.NumElem() == 1 && config.fe.CanSSA(t) ->
+ (ArrayMake1 (Load <t.ElemType()> ptr mem))
+
+(Store _ (ArrayMake0) mem) -> mem
+(Store [size] dst (ArrayMake1 e) mem) -> (Store [size] dst e mem)
+
+(ArraySelect [0] (Load ptr mem)) -> (Load ptr mem)
+
+// Putting [1]{*byte} and similar into direct interfaces.
+(IMake typ (ArrayMake1 val)) -> (IMake typ val)
+(ArraySelect [0] x:(IData _)) -> x
// string ops
// Decomposing StringMake and lowering of StringPtr and StringLen
@@ -654,6 +789,8 @@
// a more comprehensive set.
(SliceLen (SliceMake _ (Const64 <t> [c]) _)) -> (Const64 <t> [c])
(SliceCap (SliceMake _ _ (Const64 <t> [c]))) -> (Const64 <t> [c])
+(SliceLen (SliceMake _ (Const32 <t> [c]) _)) -> (Const32 <t> [c])
+(SliceCap (SliceMake _ _ (Const32 <t> [c]))) -> (Const32 <t> [c])
(SlicePtr (SliceMake (SlicePtr x) _ _)) -> (SlicePtr x)
(SliceLen (SliceMake _ (SliceLen x) _)) -> (SliceLen x)
(SliceCap (SliceMake _ _ (SliceCap x))) -> (SliceCap x)
@@ -675,7 +812,7 @@
(ConstNil <config.fe.TypeBytePtr()>)
(ConstNil <config.fe.TypeBytePtr()>))
-(Check (NilCheck (GetG _) _) next) -> (Plain nil next)
+(NilCheck (GetG mem) mem) -> mem
(If (Not cond) yes no) -> (If cond no yes)
(If (ConstBool [c]) yes no) && c == 1 -> (First nil yes no)
@@ -734,6 +871,11 @@
(Arg <t.FieldType(2)> {n} [off+t.FieldOff(2)])
(Arg <t.FieldType(3)> {n} [off+t.FieldOff(3)]))
+(Arg <t>) && t.IsArray() && t.NumElem() == 0 ->
+ (ArrayMake0)
+(Arg <t> {n} [off]) && t.IsArray() && t.NumElem() == 1 && config.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?
@@ -832,3 +974,46 @@
-> (Sub64 x (Mul64 <t> (Div64 <t> x (Const64 <t> [c])) (Const64 <t> [c])))
(Mod64u <t> x (Const64 [c])) && x.Op != OpConst64 && umagic64ok(c)
-> (Sub64 x (Mul64 <t> (Div64u <t> x (Const64 <t> [c])) (Const64 <t> [c])))
+
+// 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)
+
+(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
+ && isSameSym(mem.Aux, "runtime.newobject")
+ && c == config.ctxt.FixedFrameSize() + config.PtrSize // offset of return value
+ -> mem
+// nil checks just need to rewrite to something useless.
+// they will be deadcode eliminated soon afterwards.
+(NilCheck (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")
+ -> (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")
+ -> (Invalid)
diff --git a/src/cmd/compile/internal/ssa/gen/genericOps.go b/src/cmd/compile/internal/ssa/gen/genericOps.go
index 8388ea8..fe93e52 100644
--- a/src/cmd/compile/internal/ssa/gen/genericOps.go
+++ b/src/cmd/compile/internal/ssa/gen/genericOps.go
@@ -58,6 +58,9 @@ var genericOps = []opData{
{name: "Hmul64", argLength: 2},
{name: "Hmul64u", argLength: 2},
+ {name: "Mul32uhilo", argLength: 2, typ: "(UInt32,UInt32)"}, // arg0 * arg1, returns (hi, lo)
+ {name: "Mul64uhilo", argLength: 2, typ: "(UInt64,UInt64)"}, // 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.
@@ -69,6 +72,7 @@ var genericOps = []opData{
{name: "Div32u", argLength: 2},
{name: "Div64", argLength: 2},
{name: "Div64u", argLength: 2},
+ {name: "Div128u", argLength: 3}, // arg0:arg1 / arg2 (128-bit divided by 64-bit), returns (q, r)
{name: "Mod8", argLength: 2}, // arg0 % arg1, signed
{name: "Mod8u", argLength: 2}, // arg0 % arg1, unsigned
@@ -173,76 +177,76 @@ var genericOps = []opData{
{name: "Lrot64", argLength: 1, aux: "Int64"},
// 2-input comparisons
- {name: "Eq8", argLength: 2, commutative: true}, // arg0 == arg1
- {name: "Eq16", argLength: 2, commutative: true},
- {name: "Eq32", argLength: 2, commutative: true},
- {name: "Eq64", argLength: 2, commutative: true},
- {name: "EqPtr", argLength: 2, commutative: true},
- {name: "EqInter", argLength: 2}, // arg0 or arg1 is nil; other cases handled by frontend
- {name: "EqSlice", argLength: 2}, // arg0 or arg1 is nil; other cases handled by frontend
- {name: "Eq32F", argLength: 2},
- {name: "Eq64F", argLength: 2},
-
- {name: "Neq8", argLength: 2, commutative: true}, // arg0 != arg1
- {name: "Neq16", argLength: 2, commutative: true},
- {name: "Neq32", argLength: 2, commutative: true},
- {name: "Neq64", argLength: 2, commutative: true},
- {name: "NeqPtr", argLength: 2, commutative: true},
- {name: "NeqInter", argLength: 2}, // arg0 or arg1 is nil; other cases handled by frontend
- {name: "NeqSlice", argLength: 2}, // arg0 or arg1 is nil; other cases handled by frontend
- {name: "Neq32F", argLength: 2},
+ {name: "Eq8", argLength: 2, commutative: true, typ: "Bool"}, // arg0 == arg1
+ {name: "Eq16", argLength: 2, commutative: true, typ: "Bool"},
+ {name: "Eq32", argLength: 2, commutative: true, typ: "Bool"},
+ {name: "Eq64", argLength: 2, commutative: true, typ: "Bool"},
+ {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: "Neq8", argLength: 2, commutative: true, typ: "Bool"}, // arg0 != arg1
+ {name: "Neq16", argLength: 2, commutative: true, typ: "Bool"},
+ {name: "Neq32", argLength: 2, commutative: true, typ: "Bool"},
+ {name: "Neq64", argLength: 2, commutative: true, typ: "Bool"},
+ {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: "Less8", argLength: 2}, // arg0 < arg1, signed
- {name: "Less8U", argLength: 2}, // arg0 < arg1, unsigned
- {name: "Less16", argLength: 2},
- {name: "Less16U", argLength: 2},
- {name: "Less32", argLength: 2},
- {name: "Less32U", argLength: 2},
- {name: "Less64", argLength: 2},
- {name: "Less64U", argLength: 2},
- {name: "Less32F", argLength: 2},
- {name: "Less64F", argLength: 2},
-
- {name: "Leq8", argLength: 2}, // arg0 <= arg1, signed
- {name: "Leq8U", argLength: 2}, // arg0 <= arg1, unsigned
- {name: "Leq16", argLength: 2},
- {name: "Leq16U", argLength: 2},
- {name: "Leq32", argLength: 2},
- {name: "Leq32U", argLength: 2},
- {name: "Leq64", argLength: 2},
- {name: "Leq64U", argLength: 2},
- {name: "Leq32F", argLength: 2},
- {name: "Leq64F", argLength: 2},
-
- {name: "Greater8", argLength: 2}, // arg0 > arg1, signed
- {name: "Greater8U", argLength: 2}, // arg0 > arg1, unsigned
- {name: "Greater16", argLength: 2},
- {name: "Greater16U", argLength: 2},
- {name: "Greater32", argLength: 2},
- {name: "Greater32U", argLength: 2},
- {name: "Greater64", argLength: 2},
- {name: "Greater64U", argLength: 2},
- {name: "Greater32F", argLength: 2},
- {name: "Greater64F", argLength: 2},
-
- {name: "Geq8", argLength: 2}, // arg0 <= arg1, signed
- {name: "Geq8U", argLength: 2}, // arg0 <= arg1, unsigned
- {name: "Geq16", argLength: 2},
- {name: "Geq16U", argLength: 2},
- {name: "Geq32", argLength: 2},
- {name: "Geq32U", argLength: 2},
- {name: "Geq64", argLength: 2},
- {name: "Geq64U", argLength: 2},
- {name: "Geq32F", argLength: 2},
- {name: "Geq64F", argLength: 2},
+ {name: "Less8", argLength: 2, typ: "Bool"}, // arg0 < arg1, signed
+ {name: "Less8U", argLength: 2, typ: "Bool"}, // arg0 < arg1, unsigned
+ {name: "Less16", argLength: 2, typ: "Bool"},
+ {name: "Less16U", argLength: 2, typ: "Bool"},
+ {name: "Less32", argLength: 2, typ: "Bool"},
+ {name: "Less32U", argLength: 2, typ: "Bool"},
+ {name: "Less64", argLength: 2, typ: "Bool"},
+ {name: "Less64U", argLength: 2, typ: "Bool"},
+ {name: "Less32F", argLength: 2, typ: "Bool"},
+ {name: "Less64F", argLength: 2, typ: "Bool"},
+
+ {name: "Leq8", argLength: 2, typ: "Bool"}, // arg0 <= arg1, signed
+ {name: "Leq8U", argLength: 2, typ: "Bool"}, // arg0 <= arg1, unsigned
+ {name: "Leq16", argLength: 2, typ: "Bool"},
+ {name: "Leq16U", argLength: 2, typ: "Bool"},
+ {name: "Leq32", argLength: 2, typ: "Bool"},
+ {name: "Leq32U", argLength: 2, typ: "Bool"},
+ {name: "Leq64", argLength: 2, typ: "Bool"},
+ {name: "Leq64U", argLength: 2, typ: "Bool"},
+ {name: "Leq32F", argLength: 2, typ: "Bool"},
+ {name: "Leq64F", argLength: 2, typ: "Bool"},
+
+ {name: "Greater8", argLength: 2, typ: "Bool"}, // arg0 > arg1, signed
+ {name: "Greater8U", argLength: 2, typ: "Bool"}, // arg0 > arg1, unsigned
+ {name: "Greater16", argLength: 2, typ: "Bool"},
+ {name: "Greater16U", argLength: 2, typ: "Bool"},
+ {name: "Greater32", argLength: 2, typ: "Bool"},
+ {name: "Greater32U", argLength: 2, typ: "Bool"},
+ {name: "Greater64", argLength: 2, typ: "Bool"},
+ {name: "Greater64U", argLength: 2, typ: "Bool"},
+ {name: "Greater32F", argLength: 2, typ: "Bool"},
+ {name: "Greater64F", argLength: 2, typ: "Bool"},
+
+ {name: "Geq8", argLength: 2, typ: "Bool"}, // arg0 <= arg1, signed
+ {name: "Geq8U", argLength: 2, typ: "Bool"}, // arg0 <= arg1, unsigned
+ {name: "Geq16", argLength: 2, typ: "Bool"},
+ {name: "Geq16U", argLength: 2, typ: "Bool"},
+ {name: "Geq32", argLength: 2, typ: "Bool"},
+ {name: "Geq32U", argLength: 2, typ: "Bool"},
+ {name: "Geq64", argLength: 2, typ: "Bool"},
+ {name: "Geq64U", argLength: 2, typ: "Bool"},
+ {name: "Geq32F", argLength: 2, typ: "Bool"},
+ {name: "Geq64F", argLength: 2, typ: "Bool"},
// boolean ops
- {name: "AndB", argLength: 2}, // arg0 && arg1 (not shortcircuited)
- {name: "OrB", argLength: 2}, // arg0 || arg1 (not shortcircuited)
- {name: "EqB", argLength: 2}, // arg0 == arg1
- {name: "NeqB", argLength: 2}, // arg0 != arg1
- {name: "Not", argLength: 1}, // !arg0, boolean
+ {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
// 1-input ops
{name: "Neg8", argLength: 1}, // -arg0
@@ -257,14 +261,9 @@ var genericOps = []opData{
{name: "Com32", argLength: 1},
{name: "Com64", argLength: 1},
- {name: "Ctz16", argLength: 1}, // Count trailing (low order) zeroes (returns 0-16)
- {name: "Ctz32", argLength: 1}, // Count trailing zeroes (returns 0-32)
+ {name: "Ctz32", argLength: 1}, // Count trailing (low order) zeroes (returns 0-32)
{name: "Ctz64", argLength: 1}, // Count trailing zeroes (returns 0-64)
- {name: "Clz16", argLength: 1}, // Count leading (high order) zeroes (returns 0-16)
- {name: "Clz32", argLength: 1}, // Count leading zeroes (returns 0-32)
- {name: "Clz64", argLength: 1}, // Count leading zeroes (returns 0-64)
-
{name: "Bswap32", argLength: 1}, // Swap bytes
{name: "Bswap64", argLength: 1}, // Swap bytes
@@ -308,35 +307,43 @@ var genericOps = []opData{
{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, aux: "Int64"}, // arg0=destptr, arg1=srcptr, arg2=mem, auxint=size. Returns memory.
- {name: "Zero", argLength: 2, aux: "Int64"}, // arg0=destptr, arg1=mem, auxint=size. Returns memory.
+ {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.
+
+ // 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.
// Function calls. Arguments to the call have already been written to the stack.
// Return values appear on the stack. The method receiver, if any, is treated
// as a phantom first argument.
- {name: "ClosureCall", argLength: 3, aux: "Int64"}, // arg0=code pointer, arg1=context ptr, arg2=memory. auxint=arg size. Returns memory.
- {name: "StaticCall", argLength: 1, aux: "SymOff"}, // call function aux.(*gc.Sym), arg0=memory. auxint=arg size. Returns memory.
- {name: "DeferCall", argLength: 1, aux: "Int64"}, // defer call. arg0=memory, auxint=arg size. Returns memory.
- {name: "GoCall", argLength: 1, aux: "Int64"}, // go call. arg0=memory, auxint=arg size. Returns memory.
- {name: "InterCall", argLength: 2, aux: "Int64"}, // interface call. arg0=code pointer, arg1=memory, auxint=arg size. Returns memory.
+ {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.
// Conversions: signed extensions, zero (unsigned) extensions, truncations
{name: "SignExt8to16", argLength: 1, typ: "Int16"},
- {name: "SignExt8to32", argLength: 1},
- {name: "SignExt8to64", argLength: 1},
- {name: "SignExt16to32", argLength: 1},
- {name: "SignExt16to64", argLength: 1},
- {name: "SignExt32to64", argLength: 1},
+ {name: "SignExt8to32", argLength: 1, typ: "Int32"},
+ {name: "SignExt8to64", argLength: 1, typ: "Int64"},
+ {name: "SignExt16to32", argLength: 1, typ: "Int32"},
+ {name: "SignExt16to64", argLength: 1, typ: "Int64"},
+ {name: "SignExt32to64", argLength: 1, typ: "Int64"},
{name: "ZeroExt8to16", argLength: 1, typ: "UInt16"},
- {name: "ZeroExt8to32", argLength: 1},
- {name: "ZeroExt8to64", argLength: 1},
- {name: "ZeroExt16to32", argLength: 1},
- {name: "ZeroExt16to64", argLength: 1},
- {name: "ZeroExt32to64", argLength: 1},
+ {name: "ZeroExt8to32", argLength: 1, typ: "UInt32"},
+ {name: "ZeroExt8to64", argLength: 1, typ: "UInt64"},
+ {name: "ZeroExt16to32", argLength: 1, typ: "UInt32"},
+ {name: "ZeroExt16to64", argLength: 1, typ: "UInt64"},
+ {name: "ZeroExt32to64", argLength: 1, typ: "UInt64"},
{name: "Trunc16to8", argLength: 1},
{name: "Trunc32to8", argLength: 1},
{name: "Trunc32to16", argLength: 1},
@@ -359,16 +366,15 @@ var genericOps = []opData{
{name: "IsNonNil", argLength: 1, typ: "Bool"}, // arg0 != nil
{name: "IsInBounds", argLength: 2, typ: "Bool"}, // 0 <= arg0 < arg1. arg1 is guaranteed >= 0.
{name: "IsSliceInBounds", argLength: 2, typ: "Bool"}, // 0 <= arg0 <= arg1. arg1 is guaranteed >= 0.
- {name: "NilCheck", argLength: 2, typ: "Void"}, // arg0=ptr, arg1=mem. Panics if arg0 is nil, returns void.
+ {name: "NilCheck", argLength: 2, typ: "Void"}, // arg0=ptr, arg1=mem. Panics if arg0 is nil. Returns void.
// Pseudo-ops
{name: "GetG", argLength: 1}, // runtime.getg() (read g pointer). arg0=mem
{name: "GetClosurePtr"}, // get closure pointer from dedicated register
// Indexing operations
- {name: "ArrayIndex", aux: "Int64", argLength: 1}, // arg0=array, auxint=index. Returns a[i]
- {name: "PtrIndex", argLength: 2}, // arg0=ptr, arg1=index. Computes ptr+sizeof(*v.type)*index, where index is extended to ptrwidth type
- {name: "OffPtr", argLength: 1, aux: "Int64"}, // arg0 + auxint (arg0 and result are pointers)
+ {name: "PtrIndex", argLength: 2}, // arg0=ptr, arg1=index. Computes ptr+sizeof(*v.type)*index, where index is extended to ptrwidth type
+ {name: "OffPtr", argLength: 1, aux: "Int64"}, // arg0 + auxint (arg0 and result are pointers)
// Slices
{name: "SliceMake", argLength: 3}, // arg0=ptr, arg1=len, arg2=cap
@@ -399,6 +405,11 @@ var genericOps = []opData{
{name: "StructMake4", argLength: 4}, // arg0..3=field0..3. Returns struct.
{name: "StructSelect", argLength: 1, aux: "Int64"}, // arg0=struct, auxint=field index. Returns the auxint'th field.
+ // Arrays
+ {name: "ArrayMake0"}, // Returns array with 0 elements
+ {name: "ArrayMake1", argLength: 1}, // Returns array with 1 element
+ {name: "ArraySelect", argLength: 1, aux: "Int64"}, // arg0=array, auxint=index. Returns a[i].
+
// Spill&restore ops for the register allocator. These are
// semantically identical to OpCopy; they do not take/return
// stores like regular memory ops do. We can get away without memory
@@ -416,6 +427,53 @@ var genericOps = []opData{
{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
+
+ // Ops for breaking 64-bit operations on 32-bit architectures
+ {name: "Int64Make", argLength: 2, typ: "UInt64"}, // arg0=hi, arg1=lo
+ {name: "Int64Hi", argLength: 1, typ: "UInt32"}, // high 32-bit of arg0
+ {name: "Int64Lo", argLength: 1, typ: "UInt32"}, // low 32-bit of arg0
+
+ {name: "Add32carry", argLength: 2, commutative: true, typ: "(UInt32,Flags)"}, // arg0 + arg1, returns (value, carry)
+ {name: "Add32withcarry", argLength: 3, commutative: true}, // arg0 + arg1 + arg2, arg2=carry (0 or 1)
+
+ {name: "Sub32carry", argLength: 2, typ: "(UInt32,Flags)"}, // arg0 - arg1, returns (value, carry)
+ {name: "Sub32withcarry", argLength: 3}, // arg0 - arg1 - arg2, arg2=carry (0 or 1)
+
+ {name: "Signmask", argLength: 1, typ: "Int32"}, // 0 if arg0 >= 0, -1 if arg0 < 0
+ {name: "Zeromask", argLength: 1, typ: "UInt32"}, // 0 if arg0 == 0, 0xffffffff if arg0 != 0
+ {name: "Slicemask", argLength: 1}, // 0 if arg0 == 0, -1 if arg0 > 0, undef if arg0<0. Type is native int size.
+
+ {name: "Cvt32Uto32F", argLength: 1}, // uint32 -> float32, only used on 32-bit arch
+ {name: "Cvt32Uto64F", argLength: 1}, // uint32 -> float64, only used on 32-bit arch
+ {name: "Cvt32Fto32U", argLength: 1}, // float32 -> uint32, only used on 32-bit arch
+ {name: "Cvt64Fto32U", argLength: 1}, // float64 -> uint32, only used on 32-bit arch
+ {name: "Cvt64Uto32F", argLength: 1}, // uint64 -> float32, only used on archs that has the instruction
+ {name: "Cvt64Uto64F", argLength: 1}, // uint64 -> float64, only used on archs that has the instruction
+ {name: "Cvt32Fto64U", argLength: 1}, // float32 -> uint64, only used on archs that has the instruction
+ {name: "Cvt64Fto64U", argLength: 1}, // float64 -> uint64, only used on archs that has the instruction
+
+ // pseudo-ops for breaking Tuple
+ {name: "Select0", argLength: 1}, // the first component of a tuple
+ {name: "Select1", argLength: 1}, // the second component of a tuple
+
+ // Atomic operations used for semantically inlining runtime/internal/atomic.
+ // Atomic loads return a new memory so that the loads are properly ordered
+ // with respect to other loads and stores.
+ // TODO: use for sync/atomic at some point.
+ {name: "AtomicLoad32", argLength: 2, typ: "(UInt32,Mem)"}, // Load from arg0. arg1=memory. Returns loaded value and new memory.
+ {name: "AtomicLoad64", argLength: 2, typ: "(UInt64,Mem)"}, // Load from arg0. arg1=memory. Returns loaded value and new memory.
+ {name: "AtomicLoadPtr", argLength: 2, typ: "(BytePtr,Mem)"}, // Load from arg0. arg1=memory. Returns loaded value and new memory.
+ {name: "AtomicStore32", argLength: 3, typ: "Mem"}, // Store arg1 to *arg0. arg2=memory. Returns memory.
+ {name: "AtomicStore64", argLength: 3, typ: "Mem"}, // Store arg1 to *arg0. arg2=memory. Returns memory.
+ {name: "AtomicStorePtrNoWB", argLength: 3, typ: "Mem"}, // Store arg1 to *arg0. arg2=memory. Returns memory.
+ {name: "AtomicExchange32", argLength: 3, typ: "(UInt32,Mem)"}, // Store arg1 to *arg0. arg2=memory. Returns old contents of *arg0 and new memory.
+ {name: "AtomicExchange64", argLength: 3, typ: "(UInt64,Mem)"}, // Store arg1 to *arg0. arg2=memory. Returns old contents of *arg0 and new memory.
+ {name: "AtomicAdd32", argLength: 3, typ: "(UInt32,Mem)"}, // Do *arg0 += arg1. arg2=memory. Returns sum and new memory.
+ {name: "AtomicAdd64", argLength: 3, typ: "(UInt64,Mem)"}, // Do *arg0 += arg1. arg2=memory. Returns sum and new memory.
+ {name: "AtomicCompareAndSwap32", argLength: 4, typ: "(Bool,Mem)"}, // if *arg0==arg1, then set *arg0=arg2. Returns true iff store happens and new memory.
+ {name: "AtomicCompareAndSwap64", argLength: 4, typ: "(Bool,Mem)"}, // if *arg0==arg1, then set *arg0=arg2. Returns true iff store happens and new memory.
+ {name: "AtomicAnd8", argLength: 3, typ: "Mem"}, // *arg0 &= arg1. arg2=memory. Returns memory.
+ {name: "AtomicOr8", argLength: 3, typ: "Mem"}, // *arg0 |= arg1. arg2=memory. Returns memory.
}
// kind control successors implicit exit
@@ -432,9 +490,7 @@ var genericOps = []opData{
var genericBlocks = []blockData{
{name: "Plain"}, // a single successor
{name: "If"}, // 2 successors, if control goto Succs[0] else goto Succs[1]
- {name: "Call"}, // 1 successor, control is call op (of memory type)
{name: "Defer"}, // 2 successors, Succs[0]=defer queued, Succs[1]=defer recovered. control is call op (of memory type)
- {name: "Check"}, // 1 successor, control is nilcheck op (of void type)
{name: "Ret"}, // no successors, control value is memory result
{name: "RetJmp"}, // no successors, jumps to b.Aux.(*gc.Sym)
{name: "Exit"}, // no successors, control value generates a panic
diff --git a/src/cmd/compile/internal/ssa/gen/main.go b/src/cmd/compile/internal/ssa/gen/main.go
index 2aec4a3..41199f7 100644
--- a/src/cmd/compile/internal/ssa/gen/main.go
+++ b/src/cmd/compile/internal/ssa/gen/main.go
@@ -21,13 +21,18 @@ import (
)
type arch struct {
- name string
- pkg string // obj package to import for this arch.
- genfile string // source file containing opcode code generation.
- ops []opData
- blocks []blockData
- regnames []string
- generic bool
+ name string
+ pkg string // obj package to import for this arch.
+ genfile string // source file containing opcode code generation.
+ ops []opData
+ blocks []blockData
+ regnames []string
+ gpregmask regMask
+ fpregmask regMask
+ specialregmask regMask
+ framepointerreg int8
+ linkreg int8
+ generic bool
}
type opData struct {
@@ -38,8 +43,15 @@ type opData struct {
aux string
rematerializeable bool
argLength int32 // number of arguments, if -1, then this operation has a variable number of arguments
- commutative bool // this operation is commutative (e.g. addition)
- resultInArg0 bool // v and v.Args[0] must be allocated to the same register
+ 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
}
type blockData struct {
@@ -73,6 +85,7 @@ var archs []arch
func main() {
flag.Parse()
+ sort.Sort(ArchsByName(archs))
genOp()
genLower()
}
@@ -118,10 +131,13 @@ func genOp() {
// generate Op* declarations
fmt.Fprintln(w, "const (")
- fmt.Fprintln(w, "OpInvalid Op = iota")
+ fmt.Fprintln(w, "OpInvalid Op = iota") // make sure OpInvalid is 0.
for _, a := range archs {
fmt.Fprintln(w)
for _, v := range a.ops {
+ if v.name == "Invalid" {
+ continue
+ }
fmt.Fprintf(w, "Op%s%s\n", a.Name(), v.name)
}
}
@@ -135,6 +151,9 @@ func genOp() {
pkg := path.Base(a.pkg)
for _, v := range a.ops {
+ if v.name == "Invalid" {
+ continue
+ }
fmt.Fprintln(w, "{")
fmt.Fprintf(w, "name:\"%s\",\n", v.name)
@@ -156,12 +175,39 @@ func genOp() {
if v.resultInArg0 {
fmt.Fprintln(w, "resultInArg0: true,")
if v.reg.inputs[0] != v.reg.outputs[0] {
- log.Fatalf("input[0] and output registers must be equal for %s", v.name)
+ log.Fatalf("input[0] and output[0] must use the same registers for %s", v.name)
}
if v.commutative && v.reg.inputs[1] != v.reg.outputs[0] {
- log.Fatalf("input[1] and output registers must be equal for %s", v.name)
+ log.Fatalf("input[1] and output[0] must use the same registers for %s", v.name)
+ }
+ }
+ if v.resultNotInArgs {
+ fmt.Fprintln(w, "resultNotInArgs: true,")
+ }
+ if v.clobberFlags {
+ fmt.Fprintln(w, "clobberFlags: true,")
+ }
+ if v.call {
+ fmt.Fprintln(w, "call: true,")
+ }
+ if v.nilCheck {
+ fmt.Fprintln(w, "nilCheck: true,")
+ }
+ if v.faultOnNilArg0 {
+ fmt.Fprintln(w, "faultOnNilArg0: true,")
+ if v.aux != "SymOff" && v.aux != "SymValAndOff" && v.aux != "Int64" && v.aux != "Int32" && v.aux != "" {
+ log.Fatalf("faultOnNilArg0 with aux %s not allowed", v.aux)
+ }
+ }
+ if v.faultOnNilArg1 {
+ fmt.Fprintln(w, "faultOnNilArg1: true,")
+ if v.aux != "SymOff" && v.aux != "SymValAndOff" && v.aux != "Int64" && v.aux != "Int32" && v.aux != "" {
+ log.Fatalf("faultOnNilArg1 with aux %s not allowed", v.aux)
}
}
+ if v.usesScratch {
+ fmt.Fprintln(w, "usesScratch: true,")
+ }
if a.name == "generic" {
fmt.Fprintln(w, "generic:true,")
fmt.Fprintln(w, "},") // close op
@@ -191,14 +237,22 @@ func genOp() {
}
fmt.Fprintln(w, "},")
}
+
if v.reg.clobbers > 0 {
fmt.Fprintf(w, "clobbers: %d,%s\n", v.reg.clobbers, a.regMaskComment(v.reg.clobbers))
}
+
// reg outputs
- if len(v.reg.outputs) > 0 {
- fmt.Fprintln(w, "outputs: []regMask{")
- for _, r := range v.reg.outputs {
- fmt.Fprintf(w, "%d,%s\n", r, a.regMaskComment(r))
+ s = s[:0]
+ for i, r := range v.reg.outputs {
+ s = append(s, intPair{countRegs(r), i})
+ }
+ if len(s) > 0 {
+ sort.Sort(byKey(s))
+ fmt.Fprintln(w, "outputs: []outputInfo{")
+ for _, p := range s {
+ r := v.reg.outputs[p.val]
+ fmt.Fprintf(w, "{%d,%d},%s\n", p.val, r, a.regMaskComment(r))
}
fmt.Fprintln(w, "},")
}
@@ -213,6 +267,8 @@ func genOp() {
// generate op string method
fmt.Fprintln(w, "func (o Op) String() string {return opcodeTable[o].name }")
+ fmt.Fprintln(w, "func (o Op) UsesScratch() bool { return opcodeTable[o].usesScratch }")
+
// generate registers
for _, a := range archs {
if a.generic {
@@ -220,9 +276,27 @@ func genOp() {
}
fmt.Fprintf(w, "var registers%s = [...]Register {\n", a.name)
for i, r := range a.regnames {
- fmt.Fprintf(w, " {%d, \"%s\"},\n", i, r)
+ pkg := a.pkg[len("cmd/internal/obj/"):]
+ var objname string // name in cmd/internal/obj/$ARCH
+ switch r {
+ case "SB":
+ // SB isn't a real register. cmd/internal/obj expects 0 in this case.
+ objname = "0"
+ case "SP":
+ objname = pkg + ".REGSP"
+ case "g":
+ objname = pkg + ".REGG"
+ default:
+ objname = pkg + ".REG_" + r
+ }
+ fmt.Fprintf(w, " {%d, %s, \"%s\"},\n", i, objname, r)
}
fmt.Fprintln(w, "}")
+ fmt.Fprintf(w, "var gpRegMask%s = regMask(%d)\n", a.name, a.gpregmask)
+ fmt.Fprintf(w, "var fpRegMask%s = regMask(%d)\n", a.name, a.fpregmask)
+ fmt.Fprintf(w, "var specialRegMask%s = regMask(%d)\n", a.name, a.specialregmask)
+ fmt.Fprintf(w, "var framepointerReg%s = int8(%d)\n", a.name, a.framepointerreg)
+ fmt.Fprintf(w, "var linkReg%s = int8(%d)\n", a.name, a.linkreg)
}
// gofmt result
@@ -298,3 +372,9 @@ type byKey []intPair
func (a byKey) Len() int { return len(a) }
func (a byKey) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a byKey) Less(i, j int) bool { return a[i].key < a[j].key }
+
+type ArchsByName []arch
+
+func (x ArchsByName) Len() int { return len(x) }
+func (x ArchsByName) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
+func (x ArchsByName) Less(i, j int) bool { return x[i].name < x[j].name }
diff --git a/src/cmd/compile/internal/ssa/gen/rulegen.go b/src/cmd/compile/internal/ssa/gen/rulegen.go
index 0fc5749..f255f6b 100644
--- a/src/cmd/compile/internal/ssa/gen/rulegen.go
+++ b/src/cmd/compile/internal/ssa/gen/rulegen.go
@@ -117,15 +117,17 @@ func genRules(arch arch) {
if unbalanced(rule) {
continue
}
- op := strings.Split(rule, " ")[0][1:]
- if op[len(op)-1] == ')' {
- op = op[:len(op)-1] // rule has only opcode, e.g. (ConstNil) -> ...
- }
+
loc := fmt.Sprintf("%s.rules:%d", arch.name, ruleLineno)
- if isBlock(op, arch) {
- blockrules[op] = append(blockrules[op], Rule{rule: rule, loc: loc})
+ r := Rule{rule: rule, loc: loc}
+ if rawop := strings.Split(rule, " ")[0][1:]; isBlock(rawop, arch) {
+ blockrules[rawop] = append(blockrules[rawop], r)
} else {
- oprules[op] = append(oprules[op], Rule{rule: rule, loc: loc})
+ // 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
@@ -157,8 +159,8 @@ func genRules(arch arch) {
fmt.Fprintf(w, "func rewriteValue%s(v *Value, config *Config) bool {\n", arch.name)
fmt.Fprintf(w, "switch v.Op {\n")
for _, op := range ops {
- fmt.Fprintf(w, "case %s:\n", opName(op, arch))
- fmt.Fprintf(w, "return rewriteValue%s_%s(v, config)\n", arch.name, opName(op, arch))
+ fmt.Fprintf(w, "case %s:\n", op)
+ fmt.Fprintf(w, "return rewriteValue%s_%s(v, config)\n", arch.name, op)
}
fmt.Fprintf(w, "}\n")
fmt.Fprintf(w, "return false\n")
@@ -167,7 +169,7 @@ 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, opName(op, arch))
+ 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
@@ -207,7 +209,7 @@ func genRules(arch arch) {
// Generate block rewrite function. There are only a few block types
// so we can make this one function with a switch.
- fmt.Fprintf(w, "func rewriteBlock%s(b *Block) bool {\n", arch.name)
+ fmt.Fprintf(w, "func rewriteBlock%s(b *Block, config *Config) bool {\n", arch.name)
fmt.Fprintf(w, "switch b.Kind {\n")
ops = nil
for op := range blockrules {
@@ -232,6 +234,7 @@ func genRules(arch arch) {
if strings.Contains(s[1], "(") {
genMatch0(w, arch, s[1], "v", map[string]struct{}{}, false, rule.loc)
} else {
+ fmt.Fprintf(w, "_ = v\n") // in case we don't use v
fmt.Fprintf(w, "%s := b.Control\n", s[1])
}
}
@@ -334,141 +337,108 @@ func genMatch0(w io.Writer, arch arch, match, v string, m map[string]struct{}, t
}
canFail := false
- // split body up into regions. Split by spaces/tabs, except those
- // contained in () or {}.
- s := split(match[1 : len(match)-1]) // remove parens, then split
-
- // Find op record
- var op opData
- for _, x := range genericOps {
- if x.name == s[0] {
- op = x
- break
- }
- }
- for _, x := range arch.ops {
- if x.name == s[0] {
- op = x
- break
- }
- }
- if op.name == "" {
- log.Fatalf("%s: unknown op %s", loc, s[0])
- }
+ op, oparch, typ, auxint, aux, args := parseValue(match, arch, loc)
// check op
if !top {
- fmt.Fprintf(w, "if %s.Op != %s {\nbreak\n}\n", v, opName(s[0], arch))
+ fmt.Fprintf(w, "if %s.Op != Op%s%s {\nbreak\n}\n", v, oparch, op.name)
canFail = true
}
- // check type/aux/args
- argnum := 0
- for _, a := range s[1:] {
- if a[0] == '<' {
- // type restriction
- t := a[1 : len(a)-1] // remove <>
- if !isVariable(t) {
- // code. We must match the results of this code.
- fmt.Fprintf(w, "if %s.Type != %s {\nbreak\n}\n", v, t)
+ if typ != "" {
+ if !isVariable(typ) {
+ // code. We must match the results of this code.
+ fmt.Fprintf(w, "if %s.Type != %s {\nbreak\n}\n", v, typ)
+ canFail = true
+ } else {
+ // variable
+ if _, ok := m[typ]; ok {
+ // must match previous variable
+ fmt.Fprintf(w, "if %s.Type != %s {\nbreak\n}\n", v, typ)
canFail = true
} else {
- // variable
- if _, ok := m[t]; ok {
- // must match previous variable
- fmt.Fprintf(w, "if %s.Type != %s {\nbreak\n}\n", v, t)
- canFail = true
- } else {
- m[t] = struct{}{}
- fmt.Fprintf(w, "%s := %s.Type\n", t, v)
- }
+ m[typ] = struct{}{}
+ fmt.Fprintf(w, "%s := %s.Type\n", typ, v)
}
- } else if a[0] == '[' {
- // auxint restriction
- switch op.aux {
- case "Bool", "Int8", "Int16", "Int32", "Int64", "Int128", "Float32", "Float64", "SymOff", "SymValAndOff", "SymInt32":
- default:
- log.Fatalf("%s: op %s %s can't have auxint", loc, op.name, op.aux)
- }
- x := a[1 : len(a)-1] // remove []
- if !isVariable(x) {
- // code
- fmt.Fprintf(w, "if %s.AuxInt != %s {\nbreak\n}\n", v, x)
+ }
+ }
+
+ if auxint != "" {
+ if !isVariable(auxint) {
+ // code
+ fmt.Fprintf(w, "if %s.AuxInt != %s {\nbreak\n}\n", v, auxint)
+ canFail = true
+ } else {
+ // variable
+ if _, ok := m[auxint]; ok {
+ fmt.Fprintf(w, "if %s.AuxInt != %s {\nbreak\n}\n", v, auxint)
canFail = true
} else {
- // variable
- if _, ok := m[x]; ok {
- fmt.Fprintf(w, "if %s.AuxInt != %s {\nbreak\n}\n", v, x)
- canFail = true
- } else {
- m[x] = struct{}{}
- fmt.Fprintf(w, "%s := %s.AuxInt\n", x, v)
- }
- }
- } else if a[0] == '{' {
- // aux restriction
- switch op.aux {
- case "String", "Sym", "SymOff", "SymValAndOff", "SymInt32":
- default:
- log.Fatalf("%s: op %s %s can't have aux", loc, op.name, op.aux)
+ m[auxint] = struct{}{}
+ fmt.Fprintf(w, "%s := %s.AuxInt\n", auxint, v)
}
- x := a[1 : len(a)-1] // remove {}
- if !isVariable(x) {
- // code
- fmt.Fprintf(w, "if %s.Aux != %s {\nbreak\n}\n", v, x)
+ }
+ }
+
+ if aux != "" {
+
+ if !isVariable(aux) {
+ // code
+ fmt.Fprintf(w, "if %s.Aux != %s {\nbreak\n}\n", v, aux)
+ canFail = true
+ } else {
+ // variable
+ if _, ok := m[aux]; ok {
+ fmt.Fprintf(w, "if %s.Aux != %s {\nbreak\n}\n", v, aux)
canFail = true
} else {
- // variable
- if _, ok := m[x]; ok {
- fmt.Fprintf(w, "if %s.Aux != %s {\nbreak\n}\n", v, x)
- canFail = true
- } else {
- m[x] = struct{}{}
- fmt.Fprintf(w, "%s := %s.Aux\n", x, v)
- }
+ m[aux] = struct{}{}
+ fmt.Fprintf(w, "%s := %s.Aux\n", aux, v)
}
- } else if a == "_" {
- argnum++
- } else if !strings.Contains(a, "(") {
+ }
+ }
+
+ for i, arg := range args {
+ if arg == "_" {
+ continue
+ }
+ if !strings.Contains(arg, "(") {
// leaf variable
- if _, ok := m[a]; ok {
+ if _, ok := m[arg]; ok {
// variable already has a definition. Check whether
// the old definition and the new definition match.
// For example, (add x x). Equality is just pointer equality
// on Values (so cse is important to do before lowering).
- fmt.Fprintf(w, "if %s != %s.Args[%d] {\nbreak\n}\n", a, v, argnum)
+ fmt.Fprintf(w, "if %s != %s.Args[%d] {\nbreak\n}\n", arg, v, i)
canFail = true
} else {
// remember that this variable references the given value
- m[a] = struct{}{}
- fmt.Fprintf(w, "%s := %s.Args[%d]\n", a, v, argnum)
+ m[arg] = struct{}{}
+ fmt.Fprintf(w, "%s := %s.Args[%d]\n", arg, v, i)
}
- argnum++
+ continue
+ }
+ // compound sexpr
+ var argname string
+ colon := strings.Index(arg, ":")
+ openparen := strings.Index(arg, "(")
+ if colon >= 0 && openparen >= 0 && colon < openparen {
+ // rule-specified name
+ argname = arg[:colon]
+ arg = arg[colon+1:]
} else {
- // compound sexpr
- var argname string
- colon := strings.Index(a, ":")
- openparen := strings.Index(a, "(")
- if colon >= 0 && openparen >= 0 && colon < openparen {
- // rule-specified name
- argname = a[:colon]
- a = a[colon+1:]
- } else {
- // autogenerated name
- argname = fmt.Sprintf("%s_%d", v, argnum)
- }
- fmt.Fprintf(w, "%s := %s.Args[%d]\n", argname, v, argnum)
- if genMatch0(w, arch, a, argname, m, false, loc) {
- canFail = true
- }
- argnum++
+ // autogenerated name
+ argname = fmt.Sprintf("%s_%d", v, i)
+ }
+ fmt.Fprintf(w, "%s := %s.Args[%d]\n", argname, v, i)
+ if genMatch0(w, arch, arg, argname, m, false, loc) {
+ canFail = true
}
}
+
if op.argLength == -1 {
- fmt.Fprintf(w, "if len(%s.Args) != %d {\nbreak\n}\n", v, argnum)
+ fmt.Fprintf(w, "if len(%s.Args) != %d {\nbreak\n}\n", v, len(args))
canFail = true
- } else if int(op.argLength) != argnum {
- log.Fatalf("%s: op %s should have %d args, has %d", loc, op.name, op.argLength, argnum)
}
return canFail
}
@@ -500,105 +470,44 @@ func genResult0(w io.Writer, arch arch, result string, alloc *int, top, move boo
return result
}
- s := split(result[1 : len(result)-1]) // remove parens, then split
-
- // Find op record
- var op opData
- for _, x := range genericOps {
- if x.name == s[0] {
- op = x
- break
- }
- }
- for _, x := range arch.ops {
- if x.name == s[0] {
- op = x
- break
- }
- }
- if op.name == "" {
- log.Fatalf("%s: unknown op %s", loc, s[0])
- }
+ op, oparch, typ, auxint, aux, args := parseValue(result, arch, loc)
// Find the type of the variable.
- var opType string
- var typeOverride bool
- for _, a := range s[1:] {
- if a[0] == '<' {
- // type restriction
- opType = a[1 : len(a)-1] // remove <>
- typeOverride = true
- break
- }
- }
- if opType == "" {
- // find default type, if any
- for _, op := range arch.ops {
- if op.name == s[0] && op.typ != "" {
- opType = typeName(op.typ)
- break
- }
- }
- }
- if opType == "" {
- for _, op := range genericOps {
- if op.name == s[0] && op.typ != "" {
- opType = typeName(op.typ)
- break
- }
- }
+ typeOverride := typ != ""
+ if typ == "" && op.typ != "" {
+ typ = typeName(op.typ)
}
+
var v string
if top && !move {
v = "v"
- fmt.Fprintf(w, "v.reset(%s)\n", opName(s[0], arch))
+ fmt.Fprintf(w, "v.reset(Op%s%s)\n", oparch, op.name)
if typeOverride {
- fmt.Fprintf(w, "v.Type = %s\n", opType)
+ fmt.Fprintf(w, "v.Type = %s\n", typ)
}
} else {
- if opType == "" {
- log.Fatalf("sub-expression %s (op=%s) must have a type", result, s[0])
+ if typ == "" {
+ log.Fatalf("sub-expression %s (op=Op%s%s) must have a type", result, oparch, op.name)
}
v = fmt.Sprintf("v%d", *alloc)
*alloc++
- fmt.Fprintf(w, "%s := b.NewValue0(v.Line, %s, %s)\n", v, opName(s[0], arch), opType)
+ fmt.Fprintf(w, "%s := b.NewValue0(v.Line, 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")
fmt.Fprintf(w, "v.AddArg(%s)\n", v)
}
}
- argnum := 0
- for _, a := range s[1:] {
- if a[0] == '<' {
- // type restriction, handled above
- } else if a[0] == '[' {
- // auxint restriction
- switch op.aux {
- case "Bool", "Int8", "Int16", "Int32", "Int64", "Int128", "Float32", "Float64", "SymOff", "SymValAndOff", "SymInt32":
- default:
- log.Fatalf("%s: op %s %s can't have auxint", loc, op.name, op.aux)
- }
- x := a[1 : len(a)-1] // remove []
- fmt.Fprintf(w, "%s.AuxInt = %s\n", v, x)
- } else if a[0] == '{' {
- // aux restriction
- switch op.aux {
- case "String", "Sym", "SymOff", "SymValAndOff", "SymInt32":
- default:
- log.Fatalf("%s: op %s %s can't have aux", loc, op.name, op.aux)
- }
- x := a[1 : len(a)-1] // remove {}
- fmt.Fprintf(w, "%s.Aux = %s\n", v, x)
- } else {
- // regular argument (sexpr or variable)
- x := genResult0(w, arch, a, alloc, false, move, loc)
- fmt.Fprintf(w, "%s.AddArg(%s)\n", v, x)
- argnum++
- }
+
+ if auxint != "" {
+ fmt.Fprintf(w, "%s.AuxInt = %s\n", v, auxint)
}
- if op.argLength != -1 && int(op.argLength) != argnum {
- log.Fatalf("%s: op %s should have %d args, has %d", loc, op.name, op.argLength, argnum)
+ if aux != "" {
+ fmt.Fprintf(w, "%s.Aux = %s\n", v, aux)
+ }
+ for _, arg := range args {
+ x := genResult0(w, arch, arg, alloc, false, move, loc)
+ fmt.Fprintf(w, "%s.AddArg(%s)\n", v, x)
}
return v
@@ -666,16 +575,102 @@ func isBlock(name string, arch arch) bool {
return false
}
-// opName converts from an op name specified in a rule file to an Op enum.
-// if the name matches a generic op, returns "Op" plus the specified name.
-// Otherwise, returns "Op" plus arch name plus op name.
-func opName(name string, arch arch) string {
- for _, op := range genericOps {
- if op.name == name {
- return "Op" + name
+// parseValue parses a parenthesized value from a rule.
+// The value can be from the match or the result side.
+// It returns the op and unparsed strings for typ, auxint, and aux restrictions and for all args.
+// oparch is the architecture that op is located in, or "" for generic.
+func parseValue(val string, arch arch, loc string) (op opData, oparch string, typ string, auxint string, aux string, args []string) {
+ val = val[1 : len(val)-1] // remove ()
+
+ // Split val up into regions.
+ // Split by spaces/tabs, except those contained in (), {}, [], or <>.
+ s := split(val)
+
+ // Extract restrictions and args.
+ for _, a := range s[1:] {
+ switch a[0] {
+ case '<':
+ typ = a[1 : len(a)-1] // remove <>
+ case '[':
+ auxint = a[1 : len(a)-1] // remove []
+ case '{':
+ aux = a[1 : len(a)-1] // remove {}
+ default:
+ args = append(args, a)
+ }
+ }
+
+ // Resolve the op.
+
+ // match reports whether x is a good op to select.
+ // If strict is true, rule generation might succeed.
+ // If strict is false, rule generation has failed,
+ // but we're trying to generate a useful error.
+ // Doing strict=true then strict=false allows
+ // precise op matching while retaining good error messages.
+ match := func(x opData, strict bool, archname string) bool {
+ if x.name != s[0] {
+ return false
+ }
+ if x.argLength != -1 && int(x.argLength) != len(args) {
+ if strict {
+ return false
+ } else {
+ log.Printf("%s: op %s (%s) should have %d args, has %d", loc, s[0], archname, x.argLength, len(args))
+ }
+ }
+ return true
+ }
+
+ for _, x := range genericOps {
+ if match(x, true, "generic") {
+ op = x
+ break
+ }
+ }
+ if arch.name != "generic" {
+ for _, x := range arch.ops {
+ if match(x, true, arch.name) {
+ if op.name != "" {
+ log.Fatalf("%s: matches for op %s found in both generic and %s", loc, op.name, arch.name)
+ }
+ op = x
+ oparch = arch.name
+ break
+ }
}
}
- return "Op" + arch.name + name
+
+ if op.name == "" {
+ // Failed to find the op.
+ // Run through everything again with strict=false
+ // to generate useful diagnosic messages before failing.
+ for _, x := range genericOps {
+ match(x, false, "generic")
+ }
+ for _, x := range arch.ops {
+ match(x, false, arch.name)
+ }
+ log.Fatalf("%s: unknown op %s", loc, s)
+ }
+
+ // Sanity check aux, auxint.
+ if auxint != "" {
+ switch op.aux {
+ case "Bool", "Int8", "Int16", "Int32", "Int64", "Int128", "Float32", "Float64", "SymOff", "SymValAndOff", "SymInt32", "SizeAndAlign":
+ 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":
+ default:
+ log.Fatalf("%s: op %s %s can't have aux", loc, op.name, op.aux)
+ }
+ }
+
+ return
}
func blockName(name string, arch arch) string {
@@ -689,6 +684,13 @@ func blockName(name string, arch arch) string {
// typeName returns the string to use to generate a type.
func typeName(typ string) string {
+ if typ[0] == '(' {
+ ts := strings.Split(typ[1:len(typ)-1], ",")
+ if len(ts) != 2 {
+ panic("Tuple expect 2 arguments")
+ }
+ return "MakeTuple(" + typeName(ts[0]) + ", " + typeName(ts[1]) + ")"
+ }
switch typ {
case "Flags", "Mem", "Void", "Int128":
return "Type" + typ
diff --git a/src/cmd/compile/internal/ssa/html.go b/src/cmd/compile/internal/ssa/html.go
index 7432a07..316fd2a 100644
--- a/src/cmd/compile/internal/ssa/html.go
+++ b/src/cmd/compile/internal/ssa/html.go
@@ -274,9 +274,10 @@ function toggle_visibility(id) {
<div id="help">
<p>
-Click on a value or block to toggle highlighting of that value/block and its uses.
-Values and blocks are highlighted by ID, which may vary across passes.
-(TODO: Fix this.)
+Click on a value or block to toggle highlighting of that value/block
+and its uses. (Values and blocks are highlighted by ID, and IDs of
+dead items may be reused, so not all highlights necessarily correspond
+to the clicked item.)
</p>
<p>
@@ -341,7 +342,8 @@ func (v *Value) HTML() string {
// TODO: Using the value ID as the class ignores the fact
// that value IDs get recycled and that some values
// are transmuted into other values.
- return fmt.Sprintf("<span class=\"%[1]s ssa-value\">%[1]s</span>", v.String())
+ s := v.String()
+ return fmt.Sprintf("<span class=\"%s ssa-value\">%s</span>", s, s)
}
func (v *Value) LongHTML() string {
@@ -359,7 +361,7 @@ func (v *Value) LongHTML() string {
}
r := v.Block.Func.RegAlloc
if int(v.ID) < len(r) && r[v.ID] != nil {
- s += " : " + r[v.ID].Name()
+ s += " : " + html.EscapeString(r[v.ID].Name())
}
s += "</span>"
return s
@@ -369,7 +371,8 @@ func (b *Block) HTML() string {
// TODO: Using the value ID as the class ignores the fact
// that value IDs get recycled and that some values
// are transmuted into other values.
- return fmt.Sprintf("<span class=\"%[1]s ssa-block\">%[1]s</span>", html.EscapeString(b.String()))
+ s := html.EscapeString(b.String())
+ return fmt.Sprintf("<span class=\"%s ssa-block\">%s</span>", s, s)
}
func (b *Block) LongHTML() string {
diff --git a/src/cmd/compile/internal/ssa/lca.go b/src/cmd/compile/internal/ssa/lca.go
new file mode 100644
index 0000000..b9731fa
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/lca.go
@@ -0,0 +1,123 @@
+// Copyright 2016 The Go Authors. 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
+
+// Code to compute lowest common ancestors in the dominator tree.
+// https://en.wikipedia.org/wiki/Lowest_common_ancestor
+// https://en.wikipedia.org/wiki/Range_minimum_query#Solution_using_constant_time_and_linearithmic_space
+
+// lcaRange is a data structure that can compute lowest common ancestor queries
+// in O(n lg n) precomputed space and O(1) time per query.
+type lcaRange struct {
+ // Additional information about each block (indexed by block ID).
+ blocks []lcaRangeBlock
+
+ // Data structure for range minimum queries.
+ // rangeMin[k][i] contains the ID of the minimum depth block
+ // in the Euler tour from positions i to i+1<<k-1, inclusive.
+ rangeMin [][]ID
+}
+
+type lcaRangeBlock struct {
+ b *Block
+ parent ID // parent in dominator tree. 0 = no parent (entry or unreachable)
+ firstChild ID // first child in dominator tree
+ sibling ID // next child of parent
+ pos int32 // an index in the Euler tour where this block appears (any one of its occurrences)
+ depth int32 // depth in dominator tree (root=0, its children=1, etc.)
+}
+
+func makeLCArange(f *Func) *lcaRange {
+ dom := f.Idom()
+
+ // Build tree
+ blocks := make([]lcaRangeBlock, f.NumBlocks())
+ for _, b := range f.Blocks {
+ blocks[b.ID].b = b
+ if dom[b.ID] == nil {
+ continue // entry or unreachable
+ }
+ parent := dom[b.ID].ID
+ blocks[b.ID].parent = parent
+ blocks[b.ID].sibling = blocks[parent].firstChild
+ blocks[parent].firstChild = b.ID
+ }
+
+ // Compute euler tour ordering.
+ // Each reachable block will appear #children+1 times in the tour.
+ tour := make([]ID, 0, f.NumBlocks()*2-1)
+ type queueEntry struct {
+ bid ID // block to work on
+ cid ID // child we're already working on (0 = haven't started yet)
+ }
+ q := []queueEntry{{f.Entry.ID, 0}}
+ for len(q) > 0 {
+ n := len(q) - 1
+ bid := q[n].bid
+ cid := q[n].cid
+ q = q[:n]
+
+ // Add block to tour.
+ blocks[bid].pos = int32(len(tour))
+ tour = append(tour, bid)
+
+ // Proceed down next child edge (if any).
+ if cid == 0 {
+ // This is our first visit to b. Set its depth.
+ blocks[bid].depth = blocks[blocks[bid].parent].depth + 1
+ // Then explore its first child.
+ cid = blocks[bid].firstChild
+ } else {
+ // We've seen b before. Explore the next child.
+ cid = blocks[cid].sibling
+ }
+ if cid != 0 {
+ q = append(q, queueEntry{bid, cid}, queueEntry{cid, 0})
+ }
+ }
+
+ // Compute fast range-minimum query data structure
+ var rangeMin [][]ID
+ rangeMin = append(rangeMin, tour) // 1-size windows are just the tour itself.
+ for logS, s := 1, 2; s < len(tour); logS, s = logS+1, s*2 {
+ r := make([]ID, len(tour)-s+1)
+ for i := 0; i < len(tour)-s+1; i++ {
+ bid := rangeMin[logS-1][i]
+ bid2 := rangeMin[logS-1][i+s/2]
+ if blocks[bid2].depth < blocks[bid].depth {
+ bid = bid2
+ }
+ r[i] = bid
+ }
+ rangeMin = append(rangeMin, r)
+ }
+
+ return &lcaRange{blocks: blocks, rangeMin: rangeMin}
+}
+
+// find returns the lowest common ancestor of a and b.
+func (lca *lcaRange) find(a, b *Block) *Block {
+ if a == b {
+ return a
+ }
+ // Find the positions of a and bin the Euler tour.
+ p1 := lca.blocks[a.ID].pos
+ p2 := lca.blocks[b.ID].pos
+ if p1 > p2 {
+ p1, p2 = p2, p1
+ }
+
+ // The lowest common ancestor is the minimum depth block
+ // on the tour from p1 to p2. We've precomputed minimum
+ // depth blocks for powers-of-two subsequences of the tour.
+ // Combine the right two precomputed values to get the answer.
+ logS := uint(log2(int64(p2 - p1)))
+ bid1 := lca.rangeMin[logS][p1]
+ bid2 := lca.rangeMin[logS][p2-1<<logS+1]
+ if lca.blocks[bid1].depth < lca.blocks[bid2].depth {
+ return lca.blocks[bid1].b
+ }
+ return lca.blocks[bid2].b
+}
diff --git a/src/cmd/compile/internal/ssa/lca_test.go b/src/cmd/compile/internal/ssa/lca_test.go
new file mode 100644
index 0000000..beb33e0
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/lca_test.go
@@ -0,0 +1,103 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ssa
+
+import "testing"
+
+type lca interface {
+ find(a, b *Block) *Block
+}
+
+func lcaEqual(f *Func, lca1, lca2 lca) bool {
+ for _, b := range f.Blocks {
+ for _, c := range f.Blocks {
+ if lca1.find(b, c) != lca2.find(b, c) {
+ return false
+ }
+ }
+ }
+ return true
+}
+
+func testLCAgen(t *testing.T, bg blockGen, size int) {
+ c := NewConfig("amd64", DummyFrontend{t}, nil, true)
+ fun := Fun(c, "entry", bg(size)...)
+ CheckFunc(fun.f)
+ if size == 4 {
+ t.Logf(fun.f.String())
+ }
+ lca1 := makeLCArange(fun.f)
+ lca2 := makeLCAeasy(fun.f)
+ for _, b := range fun.f.Blocks {
+ for _, c := range fun.f.Blocks {
+ l1 := lca1.find(b, c)
+ l2 := lca2.find(b, c)
+ if l1 != l2 {
+ t.Errorf("lca(%s,%s)=%s, want %s", b, c, l1, l2)
+ }
+ }
+ }
+}
+
+func TestLCALinear(t *testing.T) {
+ testLCAgen(t, genLinear, 10)
+ testLCAgen(t, genLinear, 100)
+}
+
+func TestLCAFwdBack(t *testing.T) {
+ testLCAgen(t, genFwdBack, 10)
+ testLCAgen(t, genFwdBack, 100)
+}
+
+func TestLCAManyPred(t *testing.T) {
+ testLCAgen(t, genManyPred, 10)
+ testLCAgen(t, genManyPred, 100)
+}
+
+func TestLCAMaxPred(t *testing.T) {
+ testLCAgen(t, genMaxPred, 10)
+ testLCAgen(t, genMaxPred, 100)
+}
+
+func TestLCAMaxPredValue(t *testing.T) {
+ testLCAgen(t, genMaxPredValue, 10)
+ testLCAgen(t, genMaxPredValue, 100)
+}
+
+// Simple implementation of LCA to compare against.
+type lcaEasy struct {
+ parent []*Block
+}
+
+func makeLCAeasy(f *Func) *lcaEasy {
+ return &lcaEasy{parent: dominators(f)}
+}
+
+func (lca *lcaEasy) find(a, b *Block) *Block {
+ da := lca.depth(a)
+ db := lca.depth(b)
+ for da > db {
+ da--
+ a = lca.parent[a.ID]
+ }
+ for da < db {
+ db--
+ b = lca.parent[b.ID]
+ }
+ for a != b {
+ a = lca.parent[a.ID]
+ b = lca.parent[b.ID]
+ }
+ return a
+}
+
+func (lca *lcaEasy) depth(b *Block) int {
+ n := 0
+ for b != nil {
+ b = lca.parent[b.ID]
+ n++
+ }
+ return n
+}
diff --git a/src/cmd/compile/internal/ssa/likelyadjust.go b/src/cmd/compile/internal/ssa/likelyadjust.go
index cb2d82f..38a5e81 100644
--- a/src/cmd/compile/internal/ssa/likelyadjust.go
+++ b/src/cmd/compile/internal/ssa/likelyadjust.go
@@ -28,7 +28,7 @@ type loop struct {
isInner bool // True if never discovered to contain a loop
// register allocation uses this.
- containsCall bool // if any block in this loop or any loop it contains is a BlockCall or BlockDefer
+ containsCall bool // if any block in this loop or any loop it contains has a call
}
// outerinner records that outer contains inner
@@ -50,8 +50,15 @@ func (l *loop) setContainsCall() {
}
func (l *loop) checkContainsCall(bb *Block) {
- if bb.Kind == BlockCall || bb.Kind == BlockDefer {
+ if bb.Kind == BlockDefer {
l.setContainsCall()
+ return
+ }
+ for _, v := range bb.Values {
+ if opcodeTable[v.Op].call {
+ l.setContainsCall()
+ return
+ }
}
}
@@ -113,8 +120,8 @@ func likelyadjust(f *Func) {
certain := make([]int8, f.NumBlocks()) // In the long run, all outcomes are at least this bad. Mainly for Exit
local := make([]int8, f.NumBlocks()) // for our immediate predecessors.
- nest := loopnestfor(f)
- po := nest.po
+ po := f.postorder()
+ nest := f.loopnest()
b2l := nest.b2l
for _, b := range po {
@@ -132,7 +139,7 @@ func likelyadjust(f *Func) {
// Calls. TODO not all calls are equal, names give useful clues.
// Any name-based heuristics are only relative to other calls,
// and less influential than inferences from loop structure.
- case BlockCall, BlockDefer:
+ case BlockDefer:
local[b.ID] = blCALL
certain[b.ID] = max8(blCALL, certain[b.Succs[0].b.ID])
@@ -210,6 +217,13 @@ func likelyadjust(f *Func) {
}
}
}
+ // Look for calls in the block. If there is one, make this block unlikely.
+ for _, v := range b.Values {
+ if opcodeTable[v.Op].call {
+ local[b.ID] = blCALL
+ certain[b.ID] = max8(blCALL, certain[b.Succs[0].b.ID])
+ }
+ }
}
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])
@@ -246,9 +260,8 @@ func (l *loop) nearestOuterLoop(sdom SparseTree, b *Block) *loop {
}
func loopnestfor(f *Func) *loopnest {
- po := postorder(f)
- dom := dominators(f)
- sdom := newSparseTree(f, dom)
+ po := f.postorder()
+ sdom := f.sdom()
b2l := make([]*loop, f.NumBlocks())
loops := make([]*loop, 0)
diff --git a/src/cmd/compile/internal/ssa/location.go b/src/cmd/compile/internal/ssa/location.go
index 85f5255..f9eaedf 100644
--- a/src/cmd/compile/internal/ssa/location.go
+++ b/src/cmd/compile/internal/ssa/location.go
@@ -14,8 +14,9 @@ type Location interface {
// A Register is a machine register, like %rax.
// They are numbered densely from 0 (for each architecture).
type Register struct {
- Num int32
- name string
+ num int32
+ objNum int16 // register number from cmd/internal/obj/$ARCH
+ name string
}
func (r *Register) Name() string {
@@ -32,7 +33,20 @@ type LocalSlot struct {
func (s LocalSlot) Name() string {
if s.Off == 0 {
- return fmt.Sprintf("%s[%s]", s.N, s.Type)
+ return fmt.Sprintf("%v[%v]", s.N, s.Type)
}
- return fmt.Sprintf("%s+%d[%s]", s.N, s.Off, s.Type)
+ return fmt.Sprintf("%v+%d[%v]", s.N, s.Off, s.Type)
+}
+
+type LocPair [2]Location
+
+func (t LocPair) Name() string {
+ n0, n1 := "nil", "nil"
+ if t[0] != nil {
+ n0 = t[0].Name()
+ }
+ if t[1] != nil {
+ n1 = t[1].Name()
+ }
+ return fmt.Sprintf("<%s,%s>", n0, n1)
}
diff --git a/src/cmd/compile/internal/ssa/loopbce.go b/src/cmd/compile/internal/ssa/loopbce.go
index e94781b..14d8834 100644
--- a/src/cmd/compile/internal/ssa/loopbce.go
+++ b/src/cmd/compile/internal/ssa/loopbce.go
@@ -33,6 +33,7 @@ type indVar struct {
// TODO: handle 32 bit operations
func findIndVar(f *Func) []indVar {
var iv []indVar
+ sdom := f.sdom()
nextb:
for _, b := range f.Blocks {
@@ -110,7 +111,7 @@ nextb:
// Second condition: b.Succs[entry] dominates nxt so that
// nxt is computed when inc < max, meaning nxt <= max.
- if !f.sdom.isAncestorEq(b.Succs[entry].b, nxt.Block) {
+ if !sdom.isAncestorEq(b.Succs[entry].b, nxt.Block) {
// inc+ind can only be reached through the branch that enters the loop.
continue
}
@@ -172,6 +173,7 @@ func loopbce(f *Func) {
// removesBoundsChecks remove IsInBounds and IsSliceInBounds based on the induction variables.
func removeBoundsChecks(f *Func, m map[*Value]indVar) {
+ sdom := f.sdom()
for _, b := range f.Blocks {
if b.Kind != BlockIf {
continue
@@ -200,7 +202,7 @@ func removeBoundsChecks(f *Func, m map[*Value]indVar) {
goto skip1
}
- if iv, has := m[ind]; has && f.sdom.isAncestorEq(iv.entry, b) && isNonNegative(iv.min) {
+ 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)
@@ -227,7 +229,7 @@ func removeBoundsChecks(f *Func, m map[*Value]indVar) {
goto skip2
}
- if iv, has := m[ind]; has && f.sdom.isAncestorEq(iv.entry, b) && isNonNegative(iv.min) {
+ 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)
@@ -248,7 +250,7 @@ func removeBoundsChecks(f *Func, m map[*Value]indVar) {
}
// ind + add >= 0 <-> min + add >= 0 <-> min >= -add
- if iv, has := m[ind]; has && f.sdom.isAncestorEq(iv.entry, b) && isGreaterOrEqualThan(iv.min, -add) {
+ if iv, has := m[ind]; has && sdom.isAncestorEq(iv.entry, b) && isGreaterOrEqualThan(iv.min, -add) {
if !v.Args[1].isGenericIntConst() || !iv.max.isGenericIntConst() {
goto skip3
}
diff --git a/src/cmd/compile/internal/ssa/lower.go b/src/cmd/compile/internal/ssa/lower.go
index e271ed4..e7c2629 100644
--- a/src/cmd/compile/internal/ssa/lower.go
+++ b/src/cmd/compile/internal/ssa/lower.go
@@ -21,14 +21,19 @@ func checkLower(f *Func) {
continue // lowered
}
switch v.Op {
- case OpSP, OpSB, OpInitMem, OpArg, OpPhi, OpVarDef, OpVarKill, OpVarLive, OpKeepAlive:
+ case OpSP, OpSB, OpInitMem, OpArg, OpPhi, OpVarDef, OpVarKill, OpVarLive, OpKeepAlive, OpSelect0, OpSelect1:
continue // ok not to lower
+ case OpGetG:
+ if f.Config.hasGReg {
+ // has hardware g register, regalloc takes care of it
+ continue // ok not to lower
+ }
}
- s := "not lowered: " + v.Op.String() + " " + v.Type.SimpleString()
+ s := "not lowered: " + v.String() + ", " + v.Op.String() + " " + v.Type.SimpleString()
for _, a := range v.Args {
s += " " + a.Type.SimpleString()
}
- f.Unimplementedf("%s", s)
+ f.Fatalf("%s", s)
}
}
}
diff --git a/src/cmd/compile/internal/ssa/nilcheck.go b/src/cmd/compile/internal/ssa/nilcheck.go
index 00cb75e..eb2d297 100644
--- a/src/cmd/compile/internal/ssa/nilcheck.go
+++ b/src/cmd/compile/internal/ssa/nilcheck.go
@@ -5,19 +5,12 @@
package ssa
// nilcheckelim eliminates unnecessary nil checks.
+// runs on machine-independent code.
func nilcheckelim(f *Func) {
// A nil check is redundant if the same nil check was successful in a
// dominating block. The efficacy of this pass depends heavily on the
// efficacy of the cse pass.
- idom := f.idom
- domTree := make([][]*Block, f.NumBlocks())
-
- // Create a block ID -> [dominees] mapping
- for _, b := range f.Blocks {
- if dom := idom[b.ID]; dom != nil {
- domTree[dom.ID] = append(domTree[dom.ID], b)
- }
- }
+ sdom := f.sdom()
// TODO: Eliminate more nil checks.
// We can recursively remove any chain of fixed offset calculations,
@@ -26,14 +19,13 @@ func nilcheckelim(f *Func) {
type walkState int
const (
- Work walkState = iota // clear nil check if we should and traverse to dominees regardless
- RecPtr // record the pointer as being nil checked
- ClearPtr
+ Work walkState = iota // process nil checks and traverse to dominees
+ ClearPtr // forget the fact that ptr is nil
)
type bp struct {
- block *Block // block, or nil in RecPtr/ClearPtr state
- ptr *Value // if non-nil, ptr that is to be set/cleared in RecPtr/ClearPtr state
+ block *Block // block, or nil in ClearPtr state
+ ptr *Value // if non-nil, ptr that is to be cleared in ClearPtr state
op walkState
}
@@ -76,54 +68,62 @@ func nilcheckelim(f *Func) {
switch node.op {
case Work:
- checked := checkedptr(node.block) // ptr being checked for nil/non-nil
- nonnil := nonnilptr(node.block) // ptr that is non-nil due to this blocks pred
-
- if checked != nil {
- // already have a nilcheck in the dominator path, or this block is a success
- // block for the same value it is checking
- if nonNilValues[checked.ID] || checked == nonnil {
- // Eliminate the nil check.
- // The deadcode pass will remove vestigial values,
- // and the fuse pass will join this block with its successor.
-
- // Logging in the style of the former compiler -- and omit line 1,
- // which is usually in generated code.
- if f.Config.Debug_checknil() && node.block.Control.Line > 1 {
- f.Config.Warnl(node.block.Control.Line, "removed nil check")
+ b := node.block
+
+ // First, see if we're dominated by an explicit nil check.
+ if len(b.Preds) == 1 {
+ p := b.Preds[0].b
+ if p.Kind == BlockIf && p.Control.Op == OpIsNonNil && p.Succs[0].b == b {
+ ptr := p.Control.Args[0]
+ if !nonNilValues[ptr.ID] {
+ nonNilValues[ptr.ID] = true
+ work = append(work, bp{op: ClearPtr, ptr: ptr})
}
+ }
+ }
- switch node.block.Kind {
- case BlockIf:
- node.block.Kind = BlockFirst
- node.block.SetControl(nil)
- case BlockCheck:
- node.block.Kind = BlockPlain
- node.block.SetControl(nil)
- default:
- f.Fatalf("bad block kind in nilcheck %s", node.block.Kind)
+ // Next, process values in the block.
+ i := 0
+ for _, v := range b.Values {
+ b.Values[i] = v
+ i++
+ switch v.Op {
+ case OpIsNonNil:
+ ptr := v.Args[0]
+ if nonNilValues[ptr.ID] {
+ // This is a redundant explicit nil check.
+ v.reset(OpConstBool)
+ v.AuxInt = 1 // true
}
+ case OpNilCheck:
+ ptr := v.Args[0]
+ if nonNilValues[ptr.ID] {
+ // 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")
+ }
+ v.reset(OpUnknown)
+ 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})
}
}
-
- if nonnil != nil && !nonNilValues[nonnil.ID] {
- // this is a new nilcheck so add a ClearPtr node to clear the
- // ptr from the map of nil checks once we traverse
- // back up the tree
- work = append(work, bp{op: ClearPtr, ptr: nonnil})
+ for j := i; j < len(b.Values); j++ {
+ b.Values[j] = nil
}
+ b.Values = b.Values[:i]
- // add all dominated blocks to the work list
- for _, w := range domTree[node.block.ID] {
- work = append(work, bp{block: w})
+ // 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})
}
- if nonnil != nil && !nonNilValues[nonnil.ID] {
- work = append(work, bp{op: RecPtr, ptr: nonnil})
- }
- case RecPtr:
- nonNilValues[node.ptr.ID] = true
- continue
case ClearPtr:
nonNilValues[node.ptr.ID] = false
continue
@@ -131,31 +131,88 @@ func nilcheckelim(f *Func) {
}
}
-// checkedptr returns the Value, if any,
-// that is used in a nil check in b's Control op.
-func checkedptr(b *Block) *Value {
- if b.Kind == BlockCheck {
- return b.Control.Args[0]
- }
- if b.Kind == BlockIf && b.Control.Op == OpIsNonNil {
- return b.Control.Args[0]
- }
- return nil
-}
+// All platforms are guaranteed to fault if we load/store to anything smaller than this address.
+const minZeroPage = 4096
-// nonnilptr returns the Value, if any,
-// that is non-nil due to b being the successor block
-// of an OpIsNonNil or OpNilCheck block for the value and having a single
-// predecessor.
-func nonnilptr(b *Block) *Value {
- if len(b.Preds) == 1 {
- bp := b.Preds[0].b
- if bp.Kind == BlockCheck {
- return bp.Control.Args[0]
+// nilcheckelim2 eliminates unnecessary nil checks.
+// Runs after lowering and scheduling.
+func nilcheckelim2(f *Func) {
+ unnecessary := f.newSparseSet(f.NumValues())
+ defer f.retSparseSet(unnecessary)
+ for _, b := range f.Blocks {
+ // Walk the block backwards. Find instructions that will fault if their
+ // input pointer is nil. Remove nil checks on those pointers, as the
+ // faulting instruction effectively does the nil check for free.
+ unnecessary.clear()
+ 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")
+ }
+ v.reset(OpUnknown)
+ continue
+ }
+ if v.Type.IsMemory() || v.Type.IsTuple() && v.Type.FieldType(1).IsMemory() {
+ if v.Op == OpVarDef || v.Op == OpVarKill || v.Op == OpVarLive {
+ // These ops don't really change memory.
+ continue
+ }
+ // This op changes memory. Any faulting instruction after v that
+ // we've recorded in the unnecessary map is now obsolete.
+ unnecessary.clear()
+ }
+
+ // Find any pointers that this op is guaranteed to fault on if nil.
+ var ptrstore [2]*Value
+ ptrs := ptrstore[:0]
+ if opcodeTable[v.Op].faultOnNilArg0 {
+ ptrs = append(ptrs, v.Args[0])
+ }
+ if opcodeTable[v.Op].faultOnNilArg1 {
+ ptrs = append(ptrs, v.Args[1])
+ }
+ for _, ptr := range ptrs {
+ // Check to make sure the offset is small.
+ switch opcodeTable[v.Op].auxType {
+ case auxSymOff:
+ if v.Aux != nil || v.AuxInt < 0 || v.AuxInt >= minZeroPage {
+ continue
+ }
+ case auxSymValAndOff:
+ off := ValAndOff(v.AuxInt).Off()
+ if v.Aux != nil || off < 0 || off >= minZeroPage {
+ continue
+ }
+ case auxInt32:
+ // Mips uses this auxType for atomic add constant. It does not affect the effective address.
+ case auxInt64:
+ // ARM uses this auxType for duffcopy/duffzero/alignment info.
+ // It does not affect the effective address.
+ case auxNone:
+ // offset is zero.
+ default:
+ v.Fatalf("can't handle aux %s (type %d) yet\n", v.auxString(), int(opcodeTable[v.Op].auxType))
+ }
+ // This instruction is guaranteed to fault if ptr is nil.
+ // Any previous nil check op is unnecessary.
+ unnecessary.add(ptr.ID)
+ }
}
- if bp.Kind == BlockIf && bp.Control.Op == OpIsNonNil && bp.Succs[0].b == b {
- return bp.Control.Args[0]
+ // Remove values we've clobbered with OpUnknown.
+ i := 0
+ for _, v := range b.Values {
+ if v.Op != OpUnknown {
+ b.Values[i] = v
+ i++
+ }
+ }
+ for j := i; j < len(b.Values); j++ {
+ b.Values[j] = nil
}
+ b.Values = b.Values[:i]
+
+ // TODO: if b.Kind == BlockPlain, start the analysis in the subsequent block to find
+ // more unnecessary nil checks. Would fix test/nilptr3_ssa.go:157.
}
- return nil
}
diff --git a/src/cmd/compile/internal/ssa/nilcheck_test.go b/src/cmd/compile/internal/ssa/nilcheck_test.go
index af6cbe8..f12c68c 100644
--- a/src/cmd/compile/internal/ssa/nilcheck_test.go
+++ b/src/cmd/compile/internal/ssa/nilcheck_test.go
@@ -49,7 +49,6 @@ func benchmarkNilCheckDeep(b *testing.B, depth int) {
b.ReportAllocs()
for i := 0; i < b.N; i++ {
- domTree(fun.f)
nilcheckelim(fun.f)
}
}
@@ -84,7 +83,6 @@ func TestNilcheckSimple(t *testing.T) {
Exit("mem")))
CheckFunc(fun.f)
- domTree(fun.f)
nilcheckelim(fun.f)
// clean up the removed nil check
@@ -122,7 +120,6 @@ func TestNilcheckDomOrder(t *testing.T) {
Goto("exit")))
CheckFunc(fun.f)
- domTree(fun.f)
nilcheckelim(fun.f)
// clean up the removed nil check
@@ -156,7 +153,6 @@ func TestNilcheckAddr(t *testing.T) {
Exit("mem")))
CheckFunc(fun.f)
- domTree(fun.f)
nilcheckelim(fun.f)
// clean up the removed nil check
@@ -191,7 +187,6 @@ func TestNilcheckAddPtr(t *testing.T) {
Exit("mem")))
CheckFunc(fun.f)
- domTree(fun.f)
nilcheckelim(fun.f)
// clean up the removed nil check
@@ -236,7 +231,6 @@ func TestNilcheckPhi(t *testing.T) {
Exit("mem")))
CheckFunc(fun.f)
- domTree(fun.f)
nilcheckelim(fun.f)
// clean up the removed nil check
@@ -278,7 +272,6 @@ func TestNilcheckKeepRemove(t *testing.T) {
Exit("mem")))
CheckFunc(fun.f)
- domTree(fun.f)
nilcheckelim(fun.f)
// clean up the removed nil check
@@ -326,7 +319,6 @@ func TestNilcheckInFalseBranch(t *testing.T) {
Exit("mem")))
CheckFunc(fun.f)
- domTree(fun.f)
nilcheckelim(fun.f)
// clean up the removed nil check
@@ -378,7 +370,6 @@ func TestNilcheckUser(t *testing.T) {
CheckFunc(fun.f)
// we need the opt here to rewrite the user nilcheck
opt(fun.f)
- domTree(fun.f)
nilcheckelim(fun.f)
// clean up the removed nil check
@@ -423,7 +414,6 @@ func TestNilcheckBug(t *testing.T) {
CheckFunc(fun.f)
// we need the opt here to rewrite the user nilcheck
opt(fun.f)
- domTree(fun.f)
nilcheckelim(fun.f)
// clean up the removed nil check
diff --git a/src/cmd/compile/internal/ssa/op.go b/src/cmd/compile/internal/ssa/op.go
index cadbc7c..315d720 100644
--- a/src/cmd/compile/internal/ssa/op.go
+++ b/src/cmd/compile/internal/ssa/op.go
@@ -26,7 +26,14 @@ type opInfo struct {
generic bool // this is a generic (arch-independent) opcode
rematerializeable bool // this op is rematerializeable
commutative bool // this operation is commutative (e.g. addition)
- resultInArg0 bool // v and v.Args[0] must be allocated to the same register
+ 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
}
type inputInfo struct {
@@ -34,28 +41,35 @@ type inputInfo struct {
regs regMask // allowed input registers
}
+type outputInfo struct {
+ idx int // index in output tuple
+ regs regMask // allowed output registers
+}
+
type regInfo struct {
inputs []inputInfo // ordered in register allocation order
clobbers regMask
- outputs []regMask // NOTE: values can only have 1 output for now.
+ outputs []outputInfo // ordered in register allocation order
}
type auxType int8
const (
- auxNone auxType = iota
- auxBool // auxInt is 0/1 for false/true
- auxInt8 // auxInt is an 8-bit integer
- auxInt16 // auxInt is a 16-bit integer
- auxInt32 // auxInt is a 32-bit integer
- auxInt64 // auxInt is a 64-bit integer
- auxInt128 // auxInt represents a 128-bit integer. Always 0.
- auxFloat32 // auxInt is a float32 (encoded with math.Float64bits)
- auxFloat64 // auxInt is a float64 (encoded with math.Float64bits)
- auxString // aux is a string
- auxSym // aux is a symbol
- auxSymOff // aux is a symbol, auxInt is an offset
- auxSymValAndOff // aux is a symbol, auxInt is a ValAndOff
+ 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
auxSymInt32 // aux is a symbol, auxInt is a 32-bit integer
)
@@ -124,3 +138,31 @@ 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 383f1ae..a63c5b9 100644
--- a/src/cmd/compile/internal/ssa/opGen.go
+++ b/src/cmd/compile/internal/ssa/opGen.go
@@ -6,12 +6,31 @@ package ssa
import (
"cmd/internal/obj"
"cmd/internal/obj/arm"
+ "cmd/internal/obj/arm64"
+ "cmd/internal/obj/mips"
+ "cmd/internal/obj/ppc64"
+ "cmd/internal/obj/s390x"
"cmd/internal/obj/x86"
)
const (
BlockInvalid BlockKind = iota
+ Block386EQ
+ Block386NE
+ Block386LT
+ Block386LE
+ Block386GT
+ Block386GE
+ Block386ULT
+ Block386ULE
+ Block386UGT
+ Block386UGE
+ Block386EQF
+ Block386NEF
+ Block386ORD
+ Block386NAN
+
BlockAMD64EQ
BlockAMD64NE
BlockAMD64LT
@@ -38,11 +57,62 @@ const (
BlockARMUGT
BlockARMUGE
+ BlockARM64EQ
+ BlockARM64NE
+ BlockARM64LT
+ BlockARM64LE
+ BlockARM64GT
+ BlockARM64GE
+ BlockARM64ULT
+ BlockARM64ULE
+ BlockARM64UGT
+ BlockARM64UGE
+ BlockARM64Z
+ BlockARM64NZ
+ BlockARM64ZW
+ BlockARM64NZW
+
+ BlockMIPSEQ
+ BlockMIPSNE
+ BlockMIPSLTZ
+ BlockMIPSLEZ
+ BlockMIPSGTZ
+ BlockMIPSGEZ
+ BlockMIPSFPT
+ BlockMIPSFPF
+
+ BlockMIPS64EQ
+ BlockMIPS64NE
+ BlockMIPS64LTZ
+ BlockMIPS64LEZ
+ BlockMIPS64GTZ
+ BlockMIPS64GEZ
+ BlockMIPS64FPT
+ BlockMIPS64FPF
+
+ BlockPPC64EQ
+ BlockPPC64NE
+ BlockPPC64LT
+ BlockPPC64LE
+ BlockPPC64GT
+ BlockPPC64GE
+ BlockPPC64FLT
+ BlockPPC64FLE
+ BlockPPC64FGT
+ BlockPPC64FGE
+
+ BlockS390XEQ
+ BlockS390XNE
+ BlockS390XLT
+ BlockS390XLE
+ BlockS390XGT
+ BlockS390XGE
+ BlockS390XGTF
+ BlockS390XGEF
+
BlockPlain
BlockIf
- BlockCall
BlockDefer
- BlockCheck
BlockRet
BlockRetJmp
BlockExit
@@ -52,6 +122,21 @@ const (
var blockString = [...]string{
BlockInvalid: "BlockInvalid",
+ Block386EQ: "EQ",
+ Block386NE: "NE",
+ Block386LT: "LT",
+ Block386LE: "LE",
+ Block386GT: "GT",
+ Block386GE: "GE",
+ Block386ULT: "ULT",
+ Block386ULE: "ULE",
+ Block386UGT: "UGT",
+ Block386UGE: "UGE",
+ Block386EQF: "EQF",
+ Block386NEF: "NEF",
+ Block386ORD: "ORD",
+ Block386NAN: "NAN",
+
BlockAMD64EQ: "EQ",
BlockAMD64NE: "NE",
BlockAMD64LT: "LT",
@@ -78,11 +163,62 @@ var blockString = [...]string{
BlockARMUGT: "UGT",
BlockARMUGE: "UGE",
+ BlockARM64EQ: "EQ",
+ BlockARM64NE: "NE",
+ BlockARM64LT: "LT",
+ BlockARM64LE: "LE",
+ BlockARM64GT: "GT",
+ BlockARM64GE: "GE",
+ BlockARM64ULT: "ULT",
+ BlockARM64ULE: "ULE",
+ BlockARM64UGT: "UGT",
+ BlockARM64UGE: "UGE",
+ BlockARM64Z: "Z",
+ BlockARM64NZ: "NZ",
+ BlockARM64ZW: "ZW",
+ BlockARM64NZW: "NZW",
+
+ BlockMIPSEQ: "EQ",
+ BlockMIPSNE: "NE",
+ BlockMIPSLTZ: "LTZ",
+ BlockMIPSLEZ: "LEZ",
+ BlockMIPSGTZ: "GTZ",
+ BlockMIPSGEZ: "GEZ",
+ BlockMIPSFPT: "FPT",
+ BlockMIPSFPF: "FPF",
+
+ BlockMIPS64EQ: "EQ",
+ BlockMIPS64NE: "NE",
+ BlockMIPS64LTZ: "LTZ",
+ BlockMIPS64LEZ: "LEZ",
+ BlockMIPS64GTZ: "GTZ",
+ BlockMIPS64GEZ: "GEZ",
+ BlockMIPS64FPT: "FPT",
+ BlockMIPS64FPF: "FPF",
+
+ BlockPPC64EQ: "EQ",
+ BlockPPC64NE: "NE",
+ BlockPPC64LT: "LT",
+ BlockPPC64LE: "LE",
+ BlockPPC64GT: "GT",
+ BlockPPC64GE: "GE",
+ BlockPPC64FLT: "FLT",
+ BlockPPC64FLE: "FLE",
+ BlockPPC64FGT: "FGT",
+ BlockPPC64FGE: "FGE",
+
+ BlockS390XEQ: "EQ",
+ BlockS390XNE: "NE",
+ BlockS390XLT: "LT",
+ BlockS390XLE: "LE",
+ BlockS390XGT: "GT",
+ BlockS390XGE: "GE",
+ BlockS390XGTF: "GTF",
+ BlockS390XGEF: "GEF",
+
BlockPlain: "Plain",
BlockIf: "If",
- BlockCall: "Call",
BlockDefer: "Defer",
- BlockCheck: "Check",
BlockRet: "Ret",
BlockRetJmp: "RetJmp",
BlockExit: "Exit",
@@ -94,6 +230,187 @@ func (k BlockKind) String() string { return blockString[k] }
const (
OpInvalid Op = iota
+ Op386ADDSS
+ Op386ADDSD
+ Op386SUBSS
+ Op386SUBSD
+ Op386MULSS
+ Op386MULSD
+ Op386DIVSS
+ Op386DIVSD
+ Op386MOVSSload
+ Op386MOVSDload
+ Op386MOVSSconst
+ Op386MOVSDconst
+ Op386MOVSSloadidx1
+ Op386MOVSSloadidx4
+ Op386MOVSDloadidx1
+ Op386MOVSDloadidx8
+ Op386MOVSSstore
+ Op386MOVSDstore
+ Op386MOVSSstoreidx1
+ Op386MOVSSstoreidx4
+ Op386MOVSDstoreidx1
+ Op386MOVSDstoreidx8
+ Op386ADDL
+ Op386ADDLconst
+ Op386ADDLcarry
+ Op386ADDLconstcarry
+ Op386ADCL
+ Op386ADCLconst
+ Op386SUBL
+ Op386SUBLconst
+ Op386SUBLcarry
+ Op386SUBLconstcarry
+ Op386SBBL
+ Op386SBBLconst
+ Op386MULL
+ Op386MULLconst
+ Op386HMULL
+ Op386HMULLU
+ Op386HMULW
+ Op386HMULB
+ Op386HMULWU
+ Op386HMULBU
+ Op386MULLQU
+ Op386DIVL
+ Op386DIVW
+ Op386DIVLU
+ Op386DIVWU
+ Op386MODL
+ Op386MODW
+ Op386MODLU
+ Op386MODWU
+ Op386ANDL
+ Op386ANDLconst
+ Op386ORL
+ Op386ORLconst
+ Op386XORL
+ Op386XORLconst
+ Op386CMPL
+ Op386CMPW
+ Op386CMPB
+ Op386CMPLconst
+ Op386CMPWconst
+ Op386CMPBconst
+ Op386UCOMISS
+ Op386UCOMISD
+ Op386TESTL
+ Op386TESTW
+ Op386TESTB
+ Op386TESTLconst
+ Op386TESTWconst
+ Op386TESTBconst
+ Op386SHLL
+ Op386SHLLconst
+ Op386SHRL
+ Op386SHRW
+ Op386SHRB
+ Op386SHRLconst
+ Op386SHRWconst
+ Op386SHRBconst
+ Op386SARL
+ Op386SARW
+ Op386SARB
+ Op386SARLconst
+ Op386SARWconst
+ Op386SARBconst
+ Op386ROLLconst
+ Op386ROLWconst
+ Op386ROLBconst
+ Op386NEGL
+ Op386NOTL
+ Op386BSFL
+ Op386BSFW
+ Op386BSRL
+ Op386BSRW
+ Op386BSWAPL
+ Op386SQRTSD
+ Op386SBBLcarrymask
+ Op386SETEQ
+ Op386SETNE
+ Op386SETL
+ Op386SETLE
+ Op386SETG
+ Op386SETGE
+ Op386SETB
+ Op386SETBE
+ Op386SETA
+ Op386SETAE
+ Op386SETEQF
+ Op386SETNEF
+ Op386SETORD
+ Op386SETNAN
+ Op386SETGF
+ Op386SETGEF
+ Op386MOVBLSX
+ Op386MOVBLZX
+ Op386MOVWLSX
+ Op386MOVWLZX
+ Op386MOVLconst
+ Op386CVTTSD2SL
+ Op386CVTTSS2SL
+ Op386CVTSL2SS
+ Op386CVTSL2SD
+ Op386CVTSD2SS
+ Op386CVTSS2SD
+ Op386PXOR
+ Op386LEAL
+ Op386LEAL1
+ Op386LEAL2
+ Op386LEAL4
+ Op386LEAL8
+ Op386MOVBload
+ Op386MOVBLSXload
+ Op386MOVWload
+ Op386MOVWLSXload
+ Op386MOVLload
+ Op386MOVBstore
+ Op386MOVWstore
+ Op386MOVLstore
+ Op386MOVBloadidx1
+ Op386MOVWloadidx1
+ Op386MOVWloadidx2
+ Op386MOVLloadidx1
+ Op386MOVLloadidx4
+ Op386MOVBstoreidx1
+ Op386MOVWstoreidx1
+ Op386MOVWstoreidx2
+ Op386MOVLstoreidx1
+ Op386MOVLstoreidx4
+ Op386MOVBstoreconst
+ Op386MOVWstoreconst
+ Op386MOVLstoreconst
+ Op386MOVBstoreconstidx1
+ Op386MOVWstoreconstidx1
+ Op386MOVWstoreconstidx2
+ Op386MOVLstoreconstidx1
+ Op386MOVLstoreconstidx4
+ Op386DUFFZERO
+ Op386REPSTOSL
+ Op386CALLstatic
+ Op386CALLclosure
+ Op386CALLdefer
+ Op386CALLgo
+ Op386CALLinter
+ Op386DUFFCOPY
+ Op386REPMOVSL
+ Op386InvertFlags
+ Op386LoweredGetG
+ Op386LoweredGetClosurePtr
+ Op386LoweredNilCheck
+ Op386MOVLconvert
+ Op386FlagEQ
+ Op386FlagLT_ULT
+ Op386FlagLT_UGT
+ Op386FlagGT_UGT
+ Op386FlagGT_ULT
+ Op386FCHS
+ Op386MOVSSconst1
+ Op386MOVSDconst1
+ Op386MOVSSconst2
+ Op386MOVSDconst2
+
OpAMD64ADDSS
OpAMD64ADDSD
OpAMD64SUBSS
@@ -143,12 +460,8 @@ const (
OpAMD64DIVQU
OpAMD64DIVLU
OpAMD64DIVWU
- OpAMD64MODQ
- OpAMD64MODL
- OpAMD64MODW
- OpAMD64MODQU
- OpAMD64MODLU
- OpAMD64MODWU
+ OpAMD64MULQU2
+ OpAMD64DIVQU2
OpAMD64ANDQ
OpAMD64ANDL
OpAMD64ANDQconst
@@ -209,16 +522,8 @@ const (
OpAMD64NOTL
OpAMD64BSFQ
OpAMD64BSFL
- OpAMD64BSFW
- OpAMD64BSRQ
- OpAMD64BSRL
- OpAMD64BSRW
- OpAMD64CMOVQEQconst
- OpAMD64CMOVLEQconst
- OpAMD64CMOVWEQconst
- OpAMD64CMOVQNEconst
- OpAMD64CMOVLNEconst
- OpAMD64CMOVWNEconst
+ OpAMD64CMOVQEQ
+ OpAMD64CMOVLEQ
OpAMD64BSWAPQ
OpAMD64BSWAPL
OpAMD64SQRTSD
@@ -264,6 +569,7 @@ const (
OpAMD64LEAQ2
OpAMD64LEAQ4
OpAMD64LEAQ8
+ OpAMD64LEAL
OpAMD64MOVBload
OpAMD64MOVBQSXload
OpAMD64MOVWload
@@ -317,20 +623,942 @@ const (
OpAMD64LoweredGetClosurePtr
OpAMD64LoweredNilCheck
OpAMD64MOVQconvert
+ OpAMD64MOVLconvert
OpAMD64FlagEQ
OpAMD64FlagLT_ULT
OpAMD64FlagLT_UGT
OpAMD64FlagGT_UGT
OpAMD64FlagGT_ULT
+ OpAMD64MOVLatomicload
+ OpAMD64MOVQatomicload
+ OpAMD64XCHGL
+ OpAMD64XCHGQ
+ OpAMD64XADDLlock
+ OpAMD64XADDQlock
+ OpAMD64AddTupleFirst32
+ OpAMD64AddTupleFirst64
+ OpAMD64CMPXCHGLlock
+ OpAMD64CMPXCHGQlock
+ OpAMD64ANDBlock
+ OpAMD64ORBlock
OpARMADD
OpARMADDconst
- OpARMMOVWconst
+ OpARMSUB
+ OpARMSUBconst
+ OpARMRSB
+ OpARMRSBconst
+ OpARMMUL
+ OpARMHMUL
+ OpARMHMULU
+ OpARMUDIVrtcall
+ OpARMADDS
+ OpARMADDSconst
+ OpARMADC
+ OpARMADCconst
+ OpARMSUBS
+ OpARMSUBSconst
+ OpARMRSBSconst
+ OpARMSBC
+ OpARMSBCconst
+ OpARMRSCconst
+ OpARMMULLU
+ OpARMMULA
+ OpARMADDF
+ OpARMADDD
+ OpARMSUBF
+ OpARMSUBD
+ OpARMMULF
+ OpARMMULD
+ OpARMDIVF
+ OpARMDIVD
+ OpARMAND
+ OpARMANDconst
+ OpARMOR
+ OpARMORconst
+ OpARMXOR
+ OpARMXORconst
+ OpARMBIC
+ OpARMBICconst
+ OpARMMVN
+ OpARMNEGF
+ OpARMNEGD
+ OpARMSQRTD
+ OpARMCLZ
+ OpARMSLL
+ OpARMSLLconst
+ OpARMSRL
+ OpARMSRLconst
+ OpARMSRA
+ OpARMSRAconst
+ OpARMSRRconst
+ OpARMADDshiftLL
+ OpARMADDshiftRL
+ OpARMADDshiftRA
+ OpARMSUBshiftLL
+ OpARMSUBshiftRL
+ OpARMSUBshiftRA
+ OpARMRSBshiftLL
+ OpARMRSBshiftRL
+ OpARMRSBshiftRA
+ OpARMANDshiftLL
+ OpARMANDshiftRL
+ OpARMANDshiftRA
+ OpARMORshiftLL
+ OpARMORshiftRL
+ OpARMORshiftRA
+ OpARMXORshiftLL
+ OpARMXORshiftRL
+ OpARMXORshiftRA
+ OpARMXORshiftRR
+ OpARMBICshiftLL
+ OpARMBICshiftRL
+ OpARMBICshiftRA
+ OpARMMVNshiftLL
+ OpARMMVNshiftRL
+ OpARMMVNshiftRA
+ OpARMADCshiftLL
+ OpARMADCshiftRL
+ OpARMADCshiftRA
+ OpARMSBCshiftLL
+ OpARMSBCshiftRL
+ OpARMSBCshiftRA
+ OpARMRSCshiftLL
+ OpARMRSCshiftRL
+ OpARMRSCshiftRA
+ OpARMADDSshiftLL
+ OpARMADDSshiftRL
+ OpARMADDSshiftRA
+ OpARMSUBSshiftLL
+ OpARMSUBSshiftRL
+ OpARMSUBSshiftRA
+ OpARMRSBSshiftLL
+ OpARMRSBSshiftRL
+ OpARMRSBSshiftRA
+ OpARMADDshiftLLreg
+ OpARMADDshiftRLreg
+ OpARMADDshiftRAreg
+ OpARMSUBshiftLLreg
+ OpARMSUBshiftRLreg
+ OpARMSUBshiftRAreg
+ OpARMRSBshiftLLreg
+ OpARMRSBshiftRLreg
+ OpARMRSBshiftRAreg
+ OpARMANDshiftLLreg
+ OpARMANDshiftRLreg
+ OpARMANDshiftRAreg
+ OpARMORshiftLLreg
+ OpARMORshiftRLreg
+ OpARMORshiftRAreg
+ OpARMXORshiftLLreg
+ OpARMXORshiftRLreg
+ OpARMXORshiftRAreg
+ OpARMBICshiftLLreg
+ OpARMBICshiftRLreg
+ OpARMBICshiftRAreg
+ OpARMMVNshiftLLreg
+ OpARMMVNshiftRLreg
+ OpARMMVNshiftRAreg
+ OpARMADCshiftLLreg
+ OpARMADCshiftRLreg
+ OpARMADCshiftRAreg
+ OpARMSBCshiftLLreg
+ OpARMSBCshiftRLreg
+ OpARMSBCshiftRAreg
+ OpARMRSCshiftLLreg
+ OpARMRSCshiftRLreg
+ OpARMRSCshiftRAreg
+ OpARMADDSshiftLLreg
+ OpARMADDSshiftRLreg
+ OpARMADDSshiftRAreg
+ OpARMSUBSshiftLLreg
+ OpARMSUBSshiftRLreg
+ OpARMSUBSshiftRAreg
+ OpARMRSBSshiftLLreg
+ OpARMRSBSshiftRLreg
+ OpARMRSBSshiftRAreg
OpARMCMP
+ OpARMCMPconst
+ OpARMCMN
+ OpARMCMNconst
+ OpARMTST
+ OpARMTSTconst
+ OpARMTEQ
+ OpARMTEQconst
+ OpARMCMPF
+ OpARMCMPD
+ OpARMCMPshiftLL
+ OpARMCMPshiftRL
+ OpARMCMPshiftRA
+ OpARMCMPshiftLLreg
+ OpARMCMPshiftRLreg
+ OpARMCMPshiftRAreg
+ OpARMCMPF0
+ OpARMCMPD0
+ OpARMMOVWconst
+ OpARMMOVFconst
+ OpARMMOVDconst
+ OpARMMOVWaddr
+ OpARMMOVBload
+ OpARMMOVBUload
+ OpARMMOVHload
+ OpARMMOVHUload
OpARMMOVWload
+ OpARMMOVFload
+ OpARMMOVDload
+ OpARMMOVBstore
+ OpARMMOVHstore
OpARMMOVWstore
+ OpARMMOVFstore
+ OpARMMOVDstore
+ OpARMMOVWloadidx
+ OpARMMOVWloadshiftLL
+ OpARMMOVWloadshiftRL
+ OpARMMOVWloadshiftRA
+ OpARMMOVWstoreidx
+ OpARMMOVWstoreshiftLL
+ OpARMMOVWstoreshiftRL
+ OpARMMOVWstoreshiftRA
+ OpARMMOVBreg
+ OpARMMOVBUreg
+ OpARMMOVHreg
+ OpARMMOVHUreg
+ OpARMMOVWreg
+ OpARMMOVWnop
+ OpARMMOVWF
+ OpARMMOVWD
+ OpARMMOVWUF
+ OpARMMOVWUD
+ OpARMMOVFW
+ OpARMMOVDW
+ OpARMMOVFWU
+ OpARMMOVDWU
+ OpARMMOVFD
+ OpARMMOVDF
+ OpARMCMOVWHSconst
+ OpARMCMOVWLSconst
+ OpARMSRAcond
OpARMCALLstatic
+ OpARMCALLclosure
+ OpARMCALLdefer
+ OpARMCALLgo
+ OpARMCALLinter
+ OpARMLoweredNilCheck
+ OpARMEqual
+ OpARMNotEqual
OpARMLessThan
+ OpARMLessEqual
+ OpARMGreaterThan
+ OpARMGreaterEqual
+ OpARMLessThanU
+ OpARMLessEqualU
+ OpARMGreaterThanU
+ OpARMGreaterEqualU
+ OpARMDUFFZERO
+ OpARMDUFFCOPY
+ OpARMLoweredZero
+ OpARMLoweredMove
+ OpARMLoweredGetClosurePtr
+ OpARMMOVWconvert
+ OpARMFlagEQ
+ OpARMFlagLT_ULT
+ OpARMFlagLT_UGT
+ OpARMFlagGT_UGT
+ OpARMFlagGT_ULT
+ OpARMInvertFlags
+
+ OpARM64ADD
+ OpARM64ADDconst
+ OpARM64SUB
+ OpARM64SUBconst
+ OpARM64MUL
+ OpARM64MULW
+ OpARM64MULH
+ OpARM64UMULH
+ OpARM64MULL
+ OpARM64UMULL
+ OpARM64DIV
+ OpARM64UDIV
+ OpARM64DIVW
+ OpARM64UDIVW
+ OpARM64MOD
+ OpARM64UMOD
+ OpARM64MODW
+ OpARM64UMODW
+ OpARM64FADDS
+ OpARM64FADDD
+ OpARM64FSUBS
+ OpARM64FSUBD
+ OpARM64FMULS
+ OpARM64FMULD
+ OpARM64FDIVS
+ OpARM64FDIVD
+ OpARM64AND
+ OpARM64ANDconst
+ OpARM64OR
+ OpARM64ORconst
+ OpARM64XOR
+ OpARM64XORconst
+ OpARM64BIC
+ OpARM64BICconst
+ OpARM64MVN
+ OpARM64NEG
+ OpARM64FNEGS
+ OpARM64FNEGD
+ OpARM64FSQRTD
+ OpARM64REV
+ OpARM64REVW
+ OpARM64REV16W
+ OpARM64RBIT
+ OpARM64RBITW
+ OpARM64CLZ
+ OpARM64CLZW
+ OpARM64SLL
+ OpARM64SLLconst
+ OpARM64SRL
+ OpARM64SRLconst
+ OpARM64SRA
+ OpARM64SRAconst
+ OpARM64RORconst
+ OpARM64RORWconst
+ OpARM64CMP
+ OpARM64CMPconst
+ OpARM64CMPW
+ OpARM64CMPWconst
+ OpARM64CMN
+ OpARM64CMNconst
+ OpARM64CMNW
+ OpARM64CMNWconst
+ OpARM64FCMPS
+ OpARM64FCMPD
+ OpARM64ADDshiftLL
+ OpARM64ADDshiftRL
+ OpARM64ADDshiftRA
+ OpARM64SUBshiftLL
+ OpARM64SUBshiftRL
+ OpARM64SUBshiftRA
+ OpARM64ANDshiftLL
+ OpARM64ANDshiftRL
+ OpARM64ANDshiftRA
+ OpARM64ORshiftLL
+ OpARM64ORshiftRL
+ OpARM64ORshiftRA
+ OpARM64XORshiftLL
+ OpARM64XORshiftRL
+ OpARM64XORshiftRA
+ OpARM64BICshiftLL
+ OpARM64BICshiftRL
+ OpARM64BICshiftRA
+ OpARM64CMPshiftLL
+ OpARM64CMPshiftRL
+ OpARM64CMPshiftRA
+ OpARM64MOVDconst
+ OpARM64FMOVSconst
+ OpARM64FMOVDconst
+ OpARM64MOVDaddr
+ OpARM64MOVBload
+ OpARM64MOVBUload
+ OpARM64MOVHload
+ OpARM64MOVHUload
+ OpARM64MOVWload
+ OpARM64MOVWUload
+ OpARM64MOVDload
+ OpARM64FMOVSload
+ OpARM64FMOVDload
+ OpARM64MOVBstore
+ OpARM64MOVHstore
+ OpARM64MOVWstore
+ OpARM64MOVDstore
+ OpARM64FMOVSstore
+ OpARM64FMOVDstore
+ OpARM64MOVBstorezero
+ OpARM64MOVHstorezero
+ OpARM64MOVWstorezero
+ OpARM64MOVDstorezero
+ OpARM64MOVBreg
+ OpARM64MOVBUreg
+ OpARM64MOVHreg
+ OpARM64MOVHUreg
+ OpARM64MOVWreg
+ OpARM64MOVWUreg
+ OpARM64MOVDreg
+ OpARM64MOVDnop
+ OpARM64SCVTFWS
+ OpARM64SCVTFWD
+ OpARM64UCVTFWS
+ OpARM64UCVTFWD
+ OpARM64SCVTFS
+ OpARM64SCVTFD
+ OpARM64UCVTFS
+ OpARM64UCVTFD
+ OpARM64FCVTZSSW
+ OpARM64FCVTZSDW
+ OpARM64FCVTZUSW
+ OpARM64FCVTZUDW
+ OpARM64FCVTZSS
+ OpARM64FCVTZSD
+ OpARM64FCVTZUS
+ OpARM64FCVTZUD
+ OpARM64FCVTSD
+ OpARM64FCVTDS
+ OpARM64CSELULT
+ OpARM64CSELULT0
+ OpARM64CALLstatic
+ OpARM64CALLclosure
+ OpARM64CALLdefer
+ OpARM64CALLgo
+ OpARM64CALLinter
+ OpARM64LoweredNilCheck
+ OpARM64Equal
+ OpARM64NotEqual
+ OpARM64LessThan
+ OpARM64LessEqual
+ OpARM64GreaterThan
+ OpARM64GreaterEqual
+ OpARM64LessThanU
+ OpARM64LessEqualU
+ OpARM64GreaterThanU
+ OpARM64GreaterEqualU
+ OpARM64DUFFZERO
+ OpARM64LoweredZero
+ OpARM64DUFFCOPY
+ OpARM64LoweredMove
+ OpARM64LoweredGetClosurePtr
+ OpARM64MOVDconvert
+ OpARM64FlagEQ
+ OpARM64FlagLT_ULT
+ OpARM64FlagLT_UGT
+ OpARM64FlagGT_UGT
+ OpARM64FlagGT_ULT
+ OpARM64InvertFlags
+ OpARM64LDAR
+ OpARM64LDARW
+ OpARM64STLR
+ OpARM64STLRW
+ OpARM64LoweredAtomicExchange64
+ OpARM64LoweredAtomicExchange32
+ OpARM64LoweredAtomicAdd64
+ OpARM64LoweredAtomicAdd32
+ OpARM64LoweredAtomicCas64
+ OpARM64LoweredAtomicCas32
+ OpARM64LoweredAtomicAnd8
+ OpARM64LoweredAtomicOr8
+
+ OpMIPSADD
+ OpMIPSADDconst
+ OpMIPSSUB
+ OpMIPSSUBconst
+ OpMIPSMUL
+ OpMIPSMULT
+ OpMIPSMULTU
+ OpMIPSDIV
+ OpMIPSDIVU
+ OpMIPSADDF
+ OpMIPSADDD
+ OpMIPSSUBF
+ OpMIPSSUBD
+ OpMIPSMULF
+ OpMIPSMULD
+ OpMIPSDIVF
+ OpMIPSDIVD
+ OpMIPSAND
+ OpMIPSANDconst
+ OpMIPSOR
+ OpMIPSORconst
+ OpMIPSXOR
+ OpMIPSXORconst
+ OpMIPSNOR
+ OpMIPSNORconst
+ OpMIPSNEG
+ OpMIPSNEGF
+ OpMIPSNEGD
+ OpMIPSSQRTD
+ OpMIPSSLL
+ OpMIPSSLLconst
+ OpMIPSSRL
+ OpMIPSSRLconst
+ OpMIPSSRA
+ OpMIPSSRAconst
+ OpMIPSCLZ
+ OpMIPSSGT
+ OpMIPSSGTconst
+ OpMIPSSGTzero
+ OpMIPSSGTU
+ OpMIPSSGTUconst
+ OpMIPSSGTUzero
+ OpMIPSCMPEQF
+ OpMIPSCMPEQD
+ OpMIPSCMPGEF
+ OpMIPSCMPGED
+ OpMIPSCMPGTF
+ OpMIPSCMPGTD
+ OpMIPSMOVWconst
+ OpMIPSMOVFconst
+ OpMIPSMOVDconst
+ OpMIPSMOVWaddr
+ OpMIPSMOVBload
+ OpMIPSMOVBUload
+ OpMIPSMOVHload
+ OpMIPSMOVHUload
+ OpMIPSMOVWload
+ OpMIPSMOVFload
+ OpMIPSMOVDload
+ OpMIPSMOVBstore
+ OpMIPSMOVHstore
+ OpMIPSMOVWstore
+ OpMIPSMOVFstore
+ OpMIPSMOVDstore
+ OpMIPSMOVBstorezero
+ OpMIPSMOVHstorezero
+ OpMIPSMOVWstorezero
+ OpMIPSMOVBreg
+ OpMIPSMOVBUreg
+ OpMIPSMOVHreg
+ OpMIPSMOVHUreg
+ OpMIPSMOVWreg
+ OpMIPSMOVWnop
+ OpMIPSCMOVZ
+ OpMIPSCMOVZzero
+ OpMIPSMOVWF
+ OpMIPSMOVWD
+ OpMIPSTRUNCFW
+ OpMIPSTRUNCDW
+ OpMIPSMOVFD
+ OpMIPSMOVDF
+ OpMIPSCALLstatic
+ OpMIPSCALLclosure
+ OpMIPSCALLdefer
+ OpMIPSCALLgo
+ OpMIPSCALLinter
+ OpMIPSLoweredAtomicLoad
+ OpMIPSLoweredAtomicStore
+ OpMIPSLoweredAtomicStorezero
+ OpMIPSLoweredAtomicExchange
+ OpMIPSLoweredAtomicAdd
+ OpMIPSLoweredAtomicAddconst
+ OpMIPSLoweredAtomicCas
+ OpMIPSLoweredAtomicAnd
+ OpMIPSLoweredAtomicOr
+ OpMIPSLoweredZero
+ OpMIPSLoweredMove
+ OpMIPSLoweredNilCheck
+ OpMIPSFPFlagTrue
+ OpMIPSFPFlagFalse
+ OpMIPSLoweredGetClosurePtr
+ OpMIPSMOVWconvert
+
+ OpMIPS64ADDV
+ OpMIPS64ADDVconst
+ OpMIPS64SUBV
+ OpMIPS64SUBVconst
+ OpMIPS64MULV
+ OpMIPS64MULVU
+ OpMIPS64DIVV
+ OpMIPS64DIVVU
+ OpMIPS64ADDF
+ OpMIPS64ADDD
+ OpMIPS64SUBF
+ OpMIPS64SUBD
+ OpMIPS64MULF
+ OpMIPS64MULD
+ OpMIPS64DIVF
+ OpMIPS64DIVD
+ OpMIPS64AND
+ OpMIPS64ANDconst
+ OpMIPS64OR
+ OpMIPS64ORconst
+ OpMIPS64XOR
+ OpMIPS64XORconst
+ OpMIPS64NOR
+ OpMIPS64NORconst
+ OpMIPS64NEGV
+ OpMIPS64NEGF
+ OpMIPS64NEGD
+ OpMIPS64SLLV
+ OpMIPS64SLLVconst
+ OpMIPS64SRLV
+ OpMIPS64SRLVconst
+ OpMIPS64SRAV
+ OpMIPS64SRAVconst
+ OpMIPS64SGT
+ OpMIPS64SGTconst
+ OpMIPS64SGTU
+ OpMIPS64SGTUconst
+ OpMIPS64CMPEQF
+ OpMIPS64CMPEQD
+ OpMIPS64CMPGEF
+ OpMIPS64CMPGED
+ OpMIPS64CMPGTF
+ OpMIPS64CMPGTD
+ OpMIPS64MOVVconst
+ OpMIPS64MOVFconst
+ OpMIPS64MOVDconst
+ OpMIPS64MOVVaddr
+ OpMIPS64MOVBload
+ OpMIPS64MOVBUload
+ OpMIPS64MOVHload
+ OpMIPS64MOVHUload
+ OpMIPS64MOVWload
+ OpMIPS64MOVWUload
+ OpMIPS64MOVVload
+ OpMIPS64MOVFload
+ OpMIPS64MOVDload
+ OpMIPS64MOVBstore
+ OpMIPS64MOVHstore
+ OpMIPS64MOVWstore
+ OpMIPS64MOVVstore
+ OpMIPS64MOVFstore
+ OpMIPS64MOVDstore
+ OpMIPS64MOVBstorezero
+ OpMIPS64MOVHstorezero
+ OpMIPS64MOVWstorezero
+ OpMIPS64MOVVstorezero
+ OpMIPS64MOVBreg
+ OpMIPS64MOVBUreg
+ OpMIPS64MOVHreg
+ OpMIPS64MOVHUreg
+ OpMIPS64MOVWreg
+ OpMIPS64MOVWUreg
+ OpMIPS64MOVVreg
+ OpMIPS64MOVVnop
+ OpMIPS64MOVWF
+ OpMIPS64MOVWD
+ OpMIPS64MOVVF
+ OpMIPS64MOVVD
+ OpMIPS64TRUNCFW
+ OpMIPS64TRUNCDW
+ OpMIPS64TRUNCFV
+ OpMIPS64TRUNCDV
+ OpMIPS64MOVFD
+ OpMIPS64MOVDF
+ OpMIPS64CALLstatic
+ OpMIPS64CALLclosure
+ OpMIPS64CALLdefer
+ OpMIPS64CALLgo
+ OpMIPS64CALLinter
+ OpMIPS64DUFFZERO
+ OpMIPS64LoweredZero
+ OpMIPS64LoweredMove
+ OpMIPS64LoweredNilCheck
+ OpMIPS64FPFlagTrue
+ OpMIPS64FPFlagFalse
+ OpMIPS64LoweredGetClosurePtr
+ OpMIPS64MOVVconvert
+
+ OpPPC64ADD
+ OpPPC64ADDconst
+ OpPPC64FADD
+ OpPPC64FADDS
+ OpPPC64SUB
+ OpPPC64FSUB
+ OpPPC64FSUBS
+ OpPPC64MULLD
+ OpPPC64MULLW
+ OpPPC64MULHD
+ OpPPC64MULHW
+ OpPPC64MULHDU
+ OpPPC64MULHWU
+ OpPPC64FMUL
+ OpPPC64FMULS
+ OpPPC64SRAD
+ OpPPC64SRAW
+ OpPPC64SRD
+ OpPPC64SRW
+ OpPPC64SLD
+ OpPPC64SLW
+ OpPPC64ADDconstForCarry
+ OpPPC64MaskIfNotCarry
+ OpPPC64SRADconst
+ OpPPC64SRAWconst
+ OpPPC64SRDconst
+ OpPPC64SRWconst
+ OpPPC64SLDconst
+ OpPPC64SLWconst
+ OpPPC64FDIV
+ OpPPC64FDIVS
+ OpPPC64DIVD
+ OpPPC64DIVW
+ OpPPC64DIVDU
+ OpPPC64DIVWU
+ OpPPC64FCTIDZ
+ OpPPC64FCTIWZ
+ OpPPC64FCFID
+ OpPPC64FRSP
+ OpPPC64Xf2i64
+ OpPPC64Xi2f64
+ OpPPC64AND
+ OpPPC64ANDN
+ OpPPC64OR
+ OpPPC64ORN
+ OpPPC64XOR
+ OpPPC64EQV
+ OpPPC64NEG
+ OpPPC64FNEG
+ OpPPC64FSQRT
+ OpPPC64FSQRTS
+ OpPPC64ORconst
+ OpPPC64XORconst
+ OpPPC64ANDconst
+ OpPPC64ANDCCconst
+ OpPPC64MOVBreg
+ OpPPC64MOVBZreg
+ OpPPC64MOVHreg
+ OpPPC64MOVHZreg
+ OpPPC64MOVWreg
+ OpPPC64MOVWZreg
+ OpPPC64MOVBZload
+ OpPPC64MOVHload
+ OpPPC64MOVHZload
+ OpPPC64MOVWload
+ OpPPC64MOVWZload
+ OpPPC64MOVDload
+ OpPPC64FMOVDload
+ OpPPC64FMOVSload
+ OpPPC64MOVBstore
+ OpPPC64MOVHstore
+ OpPPC64MOVWstore
+ OpPPC64MOVDstore
+ OpPPC64FMOVDstore
+ OpPPC64FMOVSstore
+ OpPPC64MOVBstorezero
+ OpPPC64MOVHstorezero
+ OpPPC64MOVWstorezero
+ OpPPC64MOVDstorezero
+ OpPPC64MOVDaddr
+ OpPPC64MOVDconst
+ OpPPC64FMOVDconst
+ OpPPC64FMOVSconst
+ OpPPC64FCMPU
+ OpPPC64CMP
+ OpPPC64CMPU
+ OpPPC64CMPW
+ OpPPC64CMPWU
+ OpPPC64CMPconst
+ OpPPC64CMPUconst
+ OpPPC64CMPWconst
+ OpPPC64CMPWUconst
+ OpPPC64Equal
+ OpPPC64NotEqual
+ OpPPC64LessThan
+ OpPPC64FLessThan
+ OpPPC64LessEqual
+ OpPPC64FLessEqual
+ OpPPC64GreaterThan
+ OpPPC64FGreaterThan
+ OpPPC64GreaterEqual
+ OpPPC64FGreaterEqual
+ OpPPC64LoweredGetClosurePtr
+ OpPPC64LoweredNilCheck
+ OpPPC64MOVDconvert
+ OpPPC64CALLstatic
+ OpPPC64CALLclosure
+ OpPPC64CALLdefer
+ OpPPC64CALLgo
+ OpPPC64CALLinter
+ OpPPC64LoweredZero
+ OpPPC64LoweredMove
+ OpPPC64InvertFlags
+ OpPPC64FlagEQ
+ OpPPC64FlagLT
+ OpPPC64FlagGT
+
+ OpS390XFADDS
+ OpS390XFADD
+ OpS390XFSUBS
+ OpS390XFSUB
+ OpS390XFMULS
+ OpS390XFMUL
+ OpS390XFDIVS
+ OpS390XFDIV
+ OpS390XFNEGS
+ OpS390XFNEG
+ OpS390XFMOVSload
+ OpS390XFMOVDload
+ OpS390XFMOVSconst
+ OpS390XFMOVDconst
+ OpS390XFMOVSloadidx
+ OpS390XFMOVDloadidx
+ OpS390XFMOVSstore
+ OpS390XFMOVDstore
+ OpS390XFMOVSstoreidx
+ OpS390XFMOVDstoreidx
+ OpS390XADD
+ OpS390XADDW
+ OpS390XADDconst
+ OpS390XADDWconst
+ OpS390XADDload
+ OpS390XADDWload
+ OpS390XSUB
+ OpS390XSUBW
+ OpS390XSUBconst
+ OpS390XSUBWconst
+ OpS390XSUBload
+ OpS390XSUBWload
+ OpS390XMULLD
+ OpS390XMULLW
+ OpS390XMULLDconst
+ OpS390XMULLWconst
+ OpS390XMULLDload
+ OpS390XMULLWload
+ OpS390XMULHD
+ OpS390XMULHDU
+ OpS390XDIVD
+ OpS390XDIVW
+ OpS390XDIVDU
+ OpS390XDIVWU
+ OpS390XMODD
+ OpS390XMODW
+ OpS390XMODDU
+ OpS390XMODWU
+ OpS390XAND
+ OpS390XANDW
+ OpS390XANDconst
+ OpS390XANDWconst
+ OpS390XANDload
+ OpS390XANDWload
+ OpS390XOR
+ OpS390XORW
+ OpS390XORconst
+ OpS390XORWconst
+ OpS390XORload
+ OpS390XORWload
+ OpS390XXOR
+ OpS390XXORW
+ OpS390XXORconst
+ OpS390XXORWconst
+ OpS390XXORload
+ OpS390XXORWload
+ OpS390XCMP
+ OpS390XCMPW
+ OpS390XCMPU
+ OpS390XCMPWU
+ OpS390XCMPconst
+ OpS390XCMPWconst
+ OpS390XCMPUconst
+ OpS390XCMPWUconst
+ OpS390XFCMPS
+ OpS390XFCMP
+ OpS390XSLD
+ OpS390XSLW
+ OpS390XSLDconst
+ OpS390XSLWconst
+ OpS390XSRD
+ OpS390XSRW
+ OpS390XSRDconst
+ OpS390XSRWconst
+ OpS390XSRAD
+ OpS390XSRAW
+ OpS390XSRADconst
+ OpS390XSRAWconst
+ OpS390XRLLGconst
+ OpS390XRLLconst
+ OpS390XNEG
+ OpS390XNEGW
+ OpS390XNOT
+ OpS390XNOTW
+ OpS390XFSQRT
+ OpS390XSUBEcarrymask
+ OpS390XSUBEWcarrymask
+ OpS390XMOVDEQ
+ OpS390XMOVDNE
+ OpS390XMOVDLT
+ OpS390XMOVDLE
+ OpS390XMOVDGT
+ OpS390XMOVDGE
+ OpS390XMOVDGTnoinv
+ OpS390XMOVDGEnoinv
+ OpS390XMOVBreg
+ OpS390XMOVBZreg
+ OpS390XMOVHreg
+ OpS390XMOVHZreg
+ OpS390XMOVWreg
+ OpS390XMOVWZreg
+ OpS390XMOVDconst
+ OpS390XCFDBRA
+ OpS390XCGDBRA
+ OpS390XCFEBRA
+ OpS390XCGEBRA
+ OpS390XCEFBRA
+ OpS390XCDFBRA
+ OpS390XCEGBRA
+ OpS390XCDGBRA
+ OpS390XLEDBR
+ OpS390XLDEBR
+ OpS390XMOVDaddr
+ OpS390XMOVDaddridx
+ OpS390XMOVBZload
+ OpS390XMOVBload
+ OpS390XMOVHZload
+ OpS390XMOVHload
+ OpS390XMOVWZload
+ OpS390XMOVWload
+ OpS390XMOVDload
+ OpS390XMOVWBR
+ OpS390XMOVDBR
+ OpS390XMOVHBRload
+ OpS390XMOVWBRload
+ OpS390XMOVDBRload
+ OpS390XMOVBstore
+ OpS390XMOVHstore
+ OpS390XMOVWstore
+ OpS390XMOVDstore
+ OpS390XMOVHBRstore
+ OpS390XMOVWBRstore
+ OpS390XMOVDBRstore
+ OpS390XMVC
+ OpS390XMOVBZloadidx
+ OpS390XMOVHZloadidx
+ OpS390XMOVWZloadidx
+ OpS390XMOVDloadidx
+ OpS390XMOVHBRloadidx
+ OpS390XMOVWBRloadidx
+ OpS390XMOVDBRloadidx
+ OpS390XMOVBstoreidx
+ OpS390XMOVHstoreidx
+ OpS390XMOVWstoreidx
+ OpS390XMOVDstoreidx
+ OpS390XMOVHBRstoreidx
+ OpS390XMOVWBRstoreidx
+ OpS390XMOVDBRstoreidx
+ OpS390XMOVBstoreconst
+ OpS390XMOVHstoreconst
+ OpS390XMOVWstoreconst
+ OpS390XMOVDstoreconst
+ OpS390XCLEAR
+ OpS390XCALLstatic
+ OpS390XCALLclosure
+ OpS390XCALLdefer
+ OpS390XCALLgo
+ OpS390XCALLinter
+ OpS390XInvertFlags
+ OpS390XLoweredGetG
+ OpS390XLoweredGetClosurePtr
+ OpS390XLoweredNilCheck
+ OpS390XMOVDconvert
+ OpS390XFlagEQ
+ OpS390XFlagLT
+ OpS390XFlagGT
+ OpS390XMOVWZatomicload
+ OpS390XMOVDatomicload
+ OpS390XMOVWatomicstore
+ OpS390XMOVDatomicstore
+ OpS390XLAA
+ OpS390XLAAG
+ OpS390XAddTupleFirst32
+ OpS390XAddTupleFirst64
+ OpS390XLoweredAtomicCas32
+ OpS390XLoweredAtomicCas64
+ OpS390XLoweredAtomicExchange32
+ OpS390XLoweredAtomicExchange64
+ OpS390XFLOGR
+ OpS390XSTMG2
+ OpS390XSTMG3
+ OpS390XSTMG4
+ OpS390XSTM2
+ OpS390XSTM3
+ OpS390XSTM4
+ OpS390XLoweredMove
+ OpS390XLoweredZero
OpAdd8
OpAdd16
@@ -362,6 +1590,8 @@ const (
OpHmul32u
OpHmul64
OpHmul64u
+ OpMul32uhilo
+ OpMul64uhilo
OpAvg64u
OpDiv8
OpDiv8u
@@ -371,6 +1601,7 @@ const (
OpDiv32u
OpDiv64
OpDiv64u
+ OpDiv128u
OpMod8
OpMod8u
OpMod16
@@ -516,12 +1747,8 @@ const (
OpCom16
OpCom32
OpCom64
- OpCtz16
OpCtz32
OpCtz64
- OpClz16
- OpClz32
- OpClz64
OpBswap32
OpBswap64
OpSqrt
@@ -549,6 +1776,10 @@ const (
OpStore
OpMove
OpZero
+ OpStoreWB
+ OpMoveWB
+ OpMoveWBVolatile
+ OpZeroWB
OpClosureCall
OpStaticCall
OpDeferCall
@@ -588,7 +1819,6 @@ const (
OpNilCheck
OpGetG
OpGetClosurePtr
- OpArrayIndex
OpPtrIndex
OpOffPtr
OpSliceMake
@@ -610,6 +1840,9 @@ const (
OpStructMake3
OpStructMake4
OpStructSelect
+ OpArrayMake0
+ OpArrayMake1
+ OpArraySelect
OpStoreReg
OpLoadReg
OpFwdRef
@@ -618,6 +1851,40 @@ const (
OpVarKill
OpVarLive
OpKeepAlive
+ OpInt64Make
+ OpInt64Hi
+ OpInt64Lo
+ OpAdd32carry
+ OpAdd32withcarry
+ OpSub32carry
+ OpSub32withcarry
+ OpSignmask
+ OpZeromask
+ OpSlicemask
+ OpCvt32Uto32F
+ OpCvt32Uto64F
+ OpCvt32Fto32U
+ OpCvt64Fto32U
+ OpCvt64Uto32F
+ OpCvt64Uto64F
+ OpCvt32Fto64U
+ OpCvt64Fto64U
+ OpSelect0
+ OpSelect1
+ OpAtomicLoad32
+ OpAtomicLoad64
+ OpAtomicLoadPtr
+ OpAtomicStore32
+ OpAtomicStore64
+ OpAtomicStorePtrNoWB
+ OpAtomicExchange32
+ OpAtomicExchange64
+ OpAtomicAdd32
+ OpAtomicAdd64
+ OpAtomicCompareAndSwap32
+ OpAtomicCompareAndSwap64
+ OpAtomicAnd8
+ OpAtomicOr8
)
var opcodeTable = [...]opInfo{
@@ -628,14 +1895,15 @@ var opcodeTable = [...]opInfo{
argLen: 2,
commutative: true,
resultInArg0: true,
+ usesScratch: true,
asm: x86.AADDSS,
reg: regInfo{
inputs: []inputInfo{
- {0, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
- {1, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+ {0, 65280}, // X0 X1 X2 X3 X4 X5 X6 X7
+ {1, 65280}, // X0 X1 X2 X3 X4 X5 X6 X7
},
- outputs: []regMask{
- 4294901760, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+ outputs: []outputInfo{
+ {0, 65280}, // X0 X1 X2 X3 X4 X5 X6 X7
},
},
},
@@ -647,11 +1915,11 @@ var opcodeTable = [...]opInfo{
asm: x86.AADDSD,
reg: regInfo{
inputs: []inputInfo{
- {0, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
- {1, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+ {0, 65280}, // X0 X1 X2 X3 X4 X5 X6 X7
+ {1, 65280}, // X0 X1 X2 X3 X4 X5 X6 X7
},
- outputs: []regMask{
- 4294901760, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+ outputs: []outputInfo{
+ {0, 65280}, // X0 X1 X2 X3 X4 X5 X6 X7
},
},
},
@@ -659,15 +1927,15 @@ var opcodeTable = [...]opInfo{
name: "SUBSS",
argLen: 2,
resultInArg0: true,
+ usesScratch: true,
asm: x86.ASUBSS,
reg: regInfo{
inputs: []inputInfo{
- {0, 2147418112}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14
- {1, 2147418112}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14
+ {0, 65280}, // X0 X1 X2 X3 X4 X5 X6 X7
+ {1, 65280}, // X0 X1 X2 X3 X4 X5 X6 X7
},
- clobbers: 2147483648, // X15
- outputs: []regMask{
- 2147418112, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14
+ outputs: []outputInfo{
+ {0, 65280}, // X0 X1 X2 X3 X4 X5 X6 X7
},
},
},
@@ -678,12 +1946,11 @@ var opcodeTable = [...]opInfo{
asm: x86.ASUBSD,
reg: regInfo{
inputs: []inputInfo{
- {0, 2147418112}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14
- {1, 2147418112}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14
+ {0, 65280}, // X0 X1 X2 X3 X4 X5 X6 X7
+ {1, 65280}, // X0 X1 X2 X3 X4 X5 X6 X7
},
- clobbers: 2147483648, // X15
- outputs: []regMask{
- 2147418112, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14
+ outputs: []outputInfo{
+ {0, 65280}, // X0 X1 X2 X3 X4 X5 X6 X7
},
},
},
@@ -692,14 +1959,15 @@ var opcodeTable = [...]opInfo{
argLen: 2,
commutative: true,
resultInArg0: true,
+ usesScratch: true,
asm: x86.AMULSS,
reg: regInfo{
inputs: []inputInfo{
- {0, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
- {1, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+ {0, 65280}, // X0 X1 X2 X3 X4 X5 X6 X7
+ {1, 65280}, // X0 X1 X2 X3 X4 X5 X6 X7
},
- outputs: []regMask{
- 4294901760, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+ outputs: []outputInfo{
+ {0, 65280}, // X0 X1 X2 X3 X4 X5 X6 X7
},
},
},
@@ -711,11 +1979,11 @@ var opcodeTable = [...]opInfo{
asm: x86.AMULSD,
reg: regInfo{
inputs: []inputInfo{
- {0, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
- {1, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+ {0, 65280}, // X0 X1 X2 X3 X4 X5 X6 X7
+ {1, 65280}, // X0 X1 X2 X3 X4 X5 X6 X7
},
- outputs: []regMask{
- 4294901760, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+ outputs: []outputInfo{
+ {0, 65280}, // X0 X1 X2 X3 X4 X5 X6 X7
},
},
},
@@ -723,15 +1991,15 @@ var opcodeTable = [...]opInfo{
name: "DIVSS",
argLen: 2,
resultInArg0: true,
+ usesScratch: true,
asm: x86.ADIVSS,
reg: regInfo{
inputs: []inputInfo{
- {0, 2147418112}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14
- {1, 2147418112}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14
+ {0, 65280}, // X0 X1 X2 X3 X4 X5 X6 X7
+ {1, 65280}, // X0 X1 X2 X3 X4 X5 X6 X7
},
- clobbers: 2147483648, // X15
- outputs: []regMask{
- 2147418112, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14
+ outputs: []outputInfo{
+ {0, 65280}, // X0 X1 X2 X3 X4 X5 X6 X7
},
},
},
@@ -742,40 +2010,41 @@ var opcodeTable = [...]opInfo{
asm: x86.ADIVSD,
reg: regInfo{
inputs: []inputInfo{
- {0, 2147418112}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14
- {1, 2147418112}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14
+ {0, 65280}, // X0 X1 X2 X3 X4 X5 X6 X7
+ {1, 65280}, // X0 X1 X2 X3 X4 X5 X6 X7
},
- clobbers: 2147483648, // X15
- outputs: []regMask{
- 2147418112, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14
+ outputs: []outputInfo{
+ {0, 65280}, // X0 X1 X2 X3 X4 X5 X6 X7
},
},
},
{
- name: "MOVSSload",
- auxType: auxSymOff,
- argLen: 2,
- asm: x86.AMOVSS,
+ name: "MOVSSload",
+ auxType: auxSymOff,
+ argLen: 2,
+ faultOnNilArg0: true,
+ asm: x86.AMOVSS,
reg: regInfo{
inputs: []inputInfo{
- {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+ {0, 65791}, // AX CX DX BX SP BP SI DI SB
},
- outputs: []regMask{
- 4294901760, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+ outputs: []outputInfo{
+ {0, 65280}, // X0 X1 X2 X3 X4 X5 X6 X7
},
},
},
{
- name: "MOVSDload",
- auxType: auxSymOff,
- argLen: 2,
- asm: x86.AMOVSD,
+ name: "MOVSDload",
+ auxType: auxSymOff,
+ argLen: 2,
+ faultOnNilArg0: true,
+ asm: x86.AMOVSD,
reg: regInfo{
inputs: []inputInfo{
- {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+ {0, 65791}, // AX CX DX BX SP BP SI DI SB
},
- outputs: []regMask{
- 4294901760, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+ outputs: []outputInfo{
+ {0, 65280}, // X0 X1 X2 X3 X4 X5 X6 X7
},
},
},
@@ -786,8 +2055,8 @@ var opcodeTable = [...]opInfo{
rematerializeable: true,
asm: x86.AMOVSS,
reg: regInfo{
- outputs: []regMask{
- 4294901760, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+ outputs: []outputInfo{
+ {0, 65280}, // X0 X1 X2 X3 X4 X5 X6 X7
},
},
},
@@ -798,8 +2067,8 @@ var opcodeTable = [...]opInfo{
rematerializeable: true,
asm: x86.AMOVSD,
reg: regInfo{
- outputs: []regMask{
- 4294901760, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+ outputs: []outputInfo{
+ {0, 65280}, // X0 X1 X2 X3 X4 X5 X6 X7
},
},
},
@@ -810,11 +2079,11 @@ var opcodeTable = [...]opInfo{
asm: x86.AMOVSS,
reg: regInfo{
inputs: []inputInfo{
- {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+ {1, 255}, // AX CX DX BX SP BP SI DI
+ {0, 65791}, // AX CX DX BX SP BP SI DI SB
},
- outputs: []regMask{
- 4294901760, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+ outputs: []outputInfo{
+ {0, 65280}, // X0 X1 X2 X3 X4 X5 X6 X7
},
},
},
@@ -825,11 +2094,11 @@ var opcodeTable = [...]opInfo{
asm: x86.AMOVSS,
reg: regInfo{
inputs: []inputInfo{
- {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+ {1, 255}, // AX CX DX BX SP BP SI DI
+ {0, 65791}, // AX CX DX BX SP BP SI DI SB
},
- outputs: []regMask{
- 4294901760, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+ outputs: []outputInfo{
+ {0, 65280}, // X0 X1 X2 X3 X4 X5 X6 X7
},
},
},
@@ -840,11 +2109,11 @@ var opcodeTable = [...]opInfo{
asm: x86.AMOVSD,
reg: regInfo{
inputs: []inputInfo{
- {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+ {1, 255}, // AX CX DX BX SP BP SI DI
+ {0, 65791}, // AX CX DX BX SP BP SI DI SB
},
- outputs: []regMask{
- 4294901760, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+ outputs: []outputInfo{
+ {0, 65280}, // X0 X1 X2 X3 X4 X5 X6 X7
},
},
},
@@ -855,35 +2124,37 @@ var opcodeTable = [...]opInfo{
asm: x86.AMOVSD,
reg: regInfo{
inputs: []inputInfo{
- {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+ {1, 255}, // AX CX DX BX SP BP SI DI
+ {0, 65791}, // AX CX DX BX SP BP SI DI SB
},
- outputs: []regMask{
- 4294901760, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+ outputs: []outputInfo{
+ {0, 65280}, // X0 X1 X2 X3 X4 X5 X6 X7
},
},
},
{
- name: "MOVSSstore",
- auxType: auxSymOff,
- argLen: 3,
- asm: x86.AMOVSS,
+ name: "MOVSSstore",
+ auxType: auxSymOff,
+ argLen: 3,
+ faultOnNilArg0: true,
+ asm: x86.AMOVSS,
reg: regInfo{
inputs: []inputInfo{
- {1, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
- {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+ {1, 65280}, // X0 X1 X2 X3 X4 X5 X6 X7
+ {0, 65791}, // AX CX DX BX SP BP SI DI SB
},
},
},
{
- name: "MOVSDstore",
- auxType: auxSymOff,
- argLen: 3,
- asm: x86.AMOVSD,
+ name: "MOVSDstore",
+ auxType: auxSymOff,
+ argLen: 3,
+ faultOnNilArg0: true,
+ asm: x86.AMOVSD,
reg: regInfo{
inputs: []inputInfo{
- {1, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
- {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+ {1, 65280}, // X0 X1 X2 X3 X4 X5 X6 X7
+ {0, 65791}, // AX CX DX BX SP BP SI DI SB
},
},
},
@@ -894,9 +2165,9 @@ var opcodeTable = [...]opInfo{
asm: x86.AMOVSS,
reg: regInfo{
inputs: []inputInfo{
- {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- {2, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
- {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+ {1, 255}, // AX CX DX BX SP BP SI DI
+ {2, 65280}, // X0 X1 X2 X3 X4 X5 X6 X7
+ {0, 65791}, // AX CX DX BX SP BP SI DI SB
},
},
},
@@ -907,9 +2178,9 @@ var opcodeTable = [...]opInfo{
asm: x86.AMOVSS,
reg: regInfo{
inputs: []inputInfo{
- {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- {2, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
- {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+ {1, 255}, // AX CX DX BX SP BP SI DI
+ {2, 65280}, // X0 X1 X2 X3 X4 X5 X6 X7
+ {0, 65791}, // AX CX DX BX SP BP SI DI SB
},
},
},
@@ -920,9 +2191,9 @@ var opcodeTable = [...]opInfo{
asm: x86.AMOVSD,
reg: regInfo{
inputs: []inputInfo{
- {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- {2, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
- {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+ {1, 255}, // AX CX DX BX SP BP SI DI
+ {2, 65280}, // X0 X1 X2 X3 X4 X5 X6 X7
+ {0, 65791}, // AX CX DX BX SP BP SI DI SB
},
},
},
@@ -933,119 +2204,122 @@ var opcodeTable = [...]opInfo{
asm: x86.AMOVSD,
reg: regInfo{
inputs: []inputInfo{
- {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- {2, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
- {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+ {1, 255}, // AX CX DX BX SP BP SI DI
+ {2, 65280}, // X0 X1 X2 X3 X4 X5 X6 X7
+ {0, 65791}, // AX CX DX BX SP BP SI DI SB
},
},
},
{
- name: "ADDQ",
- argLen: 2,
- commutative: true,
- asm: x86.AADDQ,
+ name: "ADDL",
+ argLen: 2,
+ commutative: true,
+ clobberFlags: true,
+ asm: x86.AADDL,
reg: regInfo{
inputs: []inputInfo{
- {1, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {1, 239}, // AX CX DX BX BP SI DI
+ {0, 255}, // AX CX DX BX SP BP SI DI
},
- clobbers: 8589934592, // FLAGS
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ outputs: []outputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
},
},
},
{
- name: "ADDL",
- argLen: 2,
- commutative: true,
- asm: x86.AADDL,
+ name: "ADDLconst",
+ auxType: auxInt32,
+ argLen: 1,
+ clobberFlags: true,
+ asm: x86.AADDL,
reg: regInfo{
inputs: []inputInfo{
- {1, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 255}, // AX CX DX BX SP BP SI DI
},
- clobbers: 8589934592, // FLAGS
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ outputs: []outputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
},
},
},
{
- name: "ADDQconst",
- auxType: auxInt64,
- argLen: 1,
- asm: x86.AADDQ,
+ name: "ADDLcarry",
+ argLen: 2,
+ commutative: true,
+ resultInArg0: true,
+ asm: x86.AADDL,
reg: regInfo{
inputs: []inputInfo{
- {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 239}, // AX CX DX BX BP SI DI
+ {1, 239}, // AX CX DX BX BP SI DI
},
- clobbers: 8589934592, // FLAGS
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ outputs: []outputInfo{
+ {1, 0},
+ {0, 239}, // AX CX DX BX BP SI DI
},
},
},
{
- name: "ADDLconst",
- auxType: auxInt32,
- argLen: 1,
- asm: x86.AADDL,
+ name: "ADDLconstcarry",
+ auxType: auxInt32,
+ argLen: 1,
+ resultInArg0: true,
+ asm: x86.AADDL,
reg: regInfo{
inputs: []inputInfo{
- {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 239}, // AX CX DX BX BP SI DI
},
- clobbers: 8589934592, // FLAGS
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ outputs: []outputInfo{
+ {1, 0},
+ {0, 239}, // AX CX DX BX BP SI DI
},
},
},
{
- name: "SUBQ",
- argLen: 2,
+ name: "ADCL",
+ argLen: 3,
+ commutative: true,
resultInArg0: true,
- asm: x86.ASUBQ,
+ clobberFlags: true,
+ asm: x86.AADCL,
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, 239}, // AX CX DX BX BP SI DI
+ {1, 239}, // AX CX DX BX BP SI DI
},
- clobbers: 8589934592, // FLAGS
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ outputs: []outputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
},
},
},
{
- name: "SUBL",
+ name: "ADCLconst",
+ auxType: auxInt32,
argLen: 2,
resultInArg0: true,
- asm: x86.ASUBL,
+ clobberFlags: true,
+ asm: x86.AADCL,
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, 239}, // AX CX DX BX BP SI DI
},
- clobbers: 8589934592, // FLAGS
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ outputs: []outputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
},
},
},
{
- name: "SUBQconst",
- auxType: auxInt64,
- argLen: 1,
+ name: "SUBL",
+ argLen: 2,
resultInArg0: true,
- asm: x86.ASUBQ,
+ clobberFlags: true,
+ asm: x86.ASUBL,
reg: regInfo{
inputs: []inputInfo{
- {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 239}, // AX CX DX BX BP SI DI
+ {1, 239}, // AX CX DX BX BP SI DI
},
- clobbers: 8589934592, // FLAGS
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ outputs: []outputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
},
},
},
@@ -1054,2676 +2328,17049 @@ var opcodeTable = [...]opInfo{
auxType: auxInt32,
argLen: 1,
resultInArg0: true,
+ clobberFlags: true,
asm: x86.ASUBL,
reg: regInfo{
inputs: []inputInfo{
- {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 239}, // AX CX DX BX BP SI DI
},
- clobbers: 8589934592, // FLAGS
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ outputs: []outputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
},
},
},
{
- name: "MULQ",
+ name: "SUBLcarry",
argLen: 2,
- commutative: true,
resultInArg0: true,
- asm: x86.AIMULQ,
+ asm: x86.ASUBL,
reg: regInfo{
inputs: []inputInfo{
- {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- {1, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 239}, // AX CX DX BX BP SI DI
+ {1, 239}, // AX CX DX BX BP SI DI
},
- clobbers: 8589934592, // FLAGS
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ outputs: []outputInfo{
+ {1, 0},
+ {0, 239}, // AX CX DX BX BP SI DI
},
},
},
{
- name: "MULL",
- argLen: 2,
- commutative: true,
+ name: "SUBLconstcarry",
+ auxType: auxInt32,
+ argLen: 1,
resultInArg0: true,
- asm: x86.AIMULL,
+ asm: x86.ASUBL,
reg: regInfo{
inputs: []inputInfo{
- {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- {1, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 239}, // AX CX DX BX BP SI DI
},
- clobbers: 8589934592, // FLAGS
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ outputs: []outputInfo{
+ {1, 0},
+ {0, 239}, // AX CX DX BX BP SI DI
},
},
},
{
- name: "MULQconst",
- auxType: auxInt64,
- argLen: 1,
+ name: "SBBL",
+ argLen: 3,
resultInArg0: true,
- asm: x86.AIMULQ,
+ clobberFlags: true,
+ asm: x86.ASBBL,
reg: regInfo{
inputs: []inputInfo{
- {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 239}, // AX CX DX BX BP SI DI
+ {1, 239}, // AX CX DX BX BP SI DI
},
- clobbers: 8589934592, // FLAGS
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ outputs: []outputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
},
},
},
{
- name: "MULLconst",
+ name: "SBBLconst",
auxType: auxInt32,
- argLen: 1,
+ argLen: 2,
resultInArg0: true,
- asm: x86.AIMULL,
+ clobberFlags: true,
+ asm: x86.ASBBL,
reg: regInfo{
inputs: []inputInfo{
- {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 239}, // AX CX DX BX BP SI DI
},
- clobbers: 8589934592, // FLAGS
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ outputs: []outputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
},
},
},
{
- name: "HMULQ",
- argLen: 2,
- asm: x86.AIMULQ,
+ name: "MULL",
+ argLen: 2,
+ commutative: true,
+ resultInArg0: true,
+ clobberFlags: true,
+ asm: x86.AIMULL,
reg: regInfo{
inputs: []inputInfo{
- {0, 1}, // AX
- {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 239}, // AX CX DX BX BP SI DI
+ {1, 239}, // AX CX DX BX BP SI DI
},
- clobbers: 8589934593, // AX FLAGS
- outputs: []regMask{
- 4, // DX
+ outputs: []outputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
},
},
},
{
- name: "HMULL",
- argLen: 2,
- asm: x86.AIMULL,
+ name: "MULLconst",
+ auxType: auxInt32,
+ argLen: 1,
+ resultInArg0: true,
+ clobberFlags: true,
+ asm: x86.AIMULL,
reg: regInfo{
inputs: []inputInfo{
- {0, 1}, // AX
- {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 239}, // AX CX DX BX BP SI DI
},
- clobbers: 8589934593, // AX FLAGS
- outputs: []regMask{
- 4, // DX
+ outputs: []outputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
},
},
},
{
- name: "HMULW",
- argLen: 2,
- asm: x86.AIMULW,
+ name: "HMULL",
+ argLen: 2,
+ clobberFlags: true,
+ asm: x86.AIMULL,
reg: regInfo{
inputs: []inputInfo{
- {0, 1}, // AX
- {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 1}, // AX
+ {1, 255}, // AX CX DX BX SP BP SI DI
},
- clobbers: 8589934593, // AX FLAGS
- outputs: []regMask{
- 4, // DX
+ clobbers: 1, // AX
+ outputs: []outputInfo{
+ {0, 4}, // DX
},
},
},
{
- name: "HMULB",
- argLen: 2,
- asm: x86.AIMULB,
+ 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
+ {0, 1}, // AX
+ {1, 255}, // AX CX DX BX SP BP SI DI
},
- clobbers: 8589934593, // AX FLAGS
- outputs: []regMask{
- 4, // DX
+ clobbers: 1, // AX
+ outputs: []outputInfo{
+ {0, 4}, // DX
},
},
},
{
- name: "HMULQU",
- argLen: 2,
- asm: x86.AMULQ,
+ name: "HMULW",
+ argLen: 2,
+ clobberFlags: true,
+ asm: x86.AIMULW,
reg: regInfo{
inputs: []inputInfo{
- {0, 1}, // AX
- {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 1}, // AX
+ {1, 255}, // AX CX DX BX SP BP SI DI
},
- clobbers: 8589934593, // AX FLAGS
- outputs: []regMask{
- 4, // DX
+ clobbers: 1, // AX
+ outputs: []outputInfo{
+ {0, 4}, // DX
},
},
},
{
- name: "HMULLU",
- argLen: 2,
- asm: x86.AMULL,
+ name: "HMULB",
+ argLen: 2,
+ clobberFlags: true,
+ asm: x86.AIMULB,
reg: regInfo{
inputs: []inputInfo{
- {0, 1}, // AX
- {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 1}, // AX
+ {1, 255}, // AX CX DX BX SP BP SI DI
},
- clobbers: 8589934593, // AX FLAGS
- outputs: []regMask{
- 4, // DX
+ clobbers: 1, // AX
+ outputs: []outputInfo{
+ {0, 4}, // DX
},
},
},
{
- name: "HMULWU",
- argLen: 2,
- asm: x86.AMULW,
+ 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
+ {0, 1}, // AX
+ {1, 255}, // AX CX DX BX SP BP SI DI
},
- clobbers: 8589934593, // AX FLAGS
- outputs: []regMask{
- 4, // DX
+ clobbers: 1, // AX
+ outputs: []outputInfo{
+ {0, 4}, // DX
},
},
},
{
- name: "HMULBU",
- argLen: 2,
- asm: x86.AMULB,
+ 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
+ {0, 1}, // AX
+ {1, 255}, // AX CX DX BX SP BP SI DI
},
- clobbers: 8589934593, // AX FLAGS
- outputs: []regMask{
- 4, // DX
+ clobbers: 1, // AX
+ outputs: []outputInfo{
+ {0, 4}, // DX
},
},
},
{
- name: "AVGQU",
+ name: "MULLQU",
argLen: 2,
- commutative: true,
- resultInArg0: true,
+ clobberFlags: true,
+ asm: x86.AMULL,
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, 1}, // AX
+ {1, 255}, // AX CX DX BX SP BP SI DI
},
- clobbers: 8589934592, // FLAGS
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ outputs: []outputInfo{
+ {0, 4}, // DX
+ {1, 1}, // AX
},
},
},
{
- name: "DIVQ",
- argLen: 2,
- asm: x86.AIDIVQ,
+ name: "DIVL",
+ argLen: 2,
+ clobberFlags: true,
+ asm: x86.AIDIVL,
reg: regInfo{
inputs: []inputInfo{
- {0, 1}, // AX
- {1, 65531}, // AX CX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 1}, // AX
+ {1, 251}, // AX CX BX SP BP SI DI
},
- clobbers: 8589934596, // DX FLAGS
- outputs: []regMask{
- 1, // AX
+ clobbers: 4, // DX
+ outputs: []outputInfo{
+ {0, 1}, // AX
},
},
},
{
- name: "DIVL",
- argLen: 2,
- asm: x86.AIDIVL,
+ name: "DIVW",
+ argLen: 2,
+ clobberFlags: true,
+ asm: x86.AIDIVW,
reg: regInfo{
inputs: []inputInfo{
- {0, 1}, // AX
- {1, 65531}, // AX CX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 1}, // AX
+ {1, 251}, // AX CX BX SP BP SI DI
},
- clobbers: 8589934596, // DX FLAGS
- outputs: []regMask{
- 1, // AX
+ clobbers: 4, // DX
+ outputs: []outputInfo{
+ {0, 1}, // AX
},
},
},
{
- name: "DIVW",
- argLen: 2,
- asm: x86.AIDIVW,
+ name: "DIVLU",
+ argLen: 2,
+ clobberFlags: true,
+ asm: x86.ADIVL,
reg: regInfo{
inputs: []inputInfo{
- {0, 1}, // AX
- {1, 65531}, // AX CX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 1}, // AX
+ {1, 251}, // AX CX BX SP BP SI DI
},
- clobbers: 8589934596, // DX FLAGS
- outputs: []regMask{
- 1, // AX
+ clobbers: 4, // DX
+ outputs: []outputInfo{
+ {0, 1}, // AX
},
},
},
{
- name: "DIVQU",
- argLen: 2,
- asm: x86.ADIVQ,
+ name: "DIVWU",
+ argLen: 2,
+ clobberFlags: true,
+ asm: x86.ADIVW,
reg: regInfo{
inputs: []inputInfo{
- {0, 1}, // AX
- {1, 65531}, // AX CX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 1}, // AX
+ {1, 251}, // AX CX BX SP BP SI DI
},
- clobbers: 8589934596, // DX FLAGS
- outputs: []regMask{
- 1, // AX
+ clobbers: 4, // DX
+ outputs: []outputInfo{
+ {0, 1}, // AX
},
},
},
{
- name: "DIVLU",
- argLen: 2,
- asm: x86.ADIVL,
+ name: "MODL",
+ argLen: 2,
+ clobberFlags: true,
+ asm: x86.AIDIVL,
reg: regInfo{
inputs: []inputInfo{
- {0, 1}, // AX
- {1, 65531}, // AX CX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 1}, // AX
+ {1, 251}, // AX CX BX SP BP SI DI
},
- clobbers: 8589934596, // DX FLAGS
- outputs: []regMask{
- 1, // AX
+ clobbers: 1, // AX
+ outputs: []outputInfo{
+ {0, 4}, // DX
},
},
},
{
- name: "DIVWU",
- argLen: 2,
- asm: x86.ADIVW,
+ name: "MODW",
+ argLen: 2,
+ clobberFlags: true,
+ asm: x86.AIDIVW,
reg: regInfo{
inputs: []inputInfo{
- {0, 1}, // AX
- {1, 65531}, // AX CX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 1}, // AX
+ {1, 251}, // AX CX BX SP BP SI DI
},
- clobbers: 8589934596, // DX FLAGS
- outputs: []regMask{
- 1, // AX
+ clobbers: 1, // AX
+ outputs: []outputInfo{
+ {0, 4}, // DX
},
},
},
{
- name: "MODQ",
- argLen: 2,
- asm: x86.AIDIVQ,
+ name: "MODLU",
+ argLen: 2,
+ clobberFlags: true,
+ asm: x86.ADIVL,
reg: regInfo{
inputs: []inputInfo{
- {0, 1}, // AX
- {1, 65531}, // AX CX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 1}, // AX
+ {1, 251}, // AX CX BX SP BP SI DI
},
- clobbers: 8589934593, // AX FLAGS
- outputs: []regMask{
- 4, // DX
+ clobbers: 1, // AX
+ outputs: []outputInfo{
+ {0, 4}, // DX
},
},
},
{
- name: "MODL",
- argLen: 2,
- asm: x86.AIDIVL,
+ name: "MODWU",
+ argLen: 2,
+ clobberFlags: true,
+ asm: x86.ADIVW,
reg: regInfo{
inputs: []inputInfo{
- {0, 1}, // AX
- {1, 65531}, // AX CX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 1}, // AX
+ {1, 251}, // AX CX BX SP BP SI DI
},
- clobbers: 8589934593, // AX FLAGS
- outputs: []regMask{
- 4, // DX
+ clobbers: 1, // AX
+ outputs: []outputInfo{
+ {0, 4}, // DX
},
},
},
{
- name: "MODW",
- argLen: 2,
- asm: x86.AIDIVW,
+ name: "ANDL",
+ argLen: 2,
+ commutative: true,
+ resultInArg0: true,
+ clobberFlags: true,
+ asm: x86.AANDL,
reg: regInfo{
inputs: []inputInfo{
- {0, 1}, // AX
- {1, 65531}, // AX CX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 239}, // AX CX DX BX BP SI DI
+ {1, 239}, // AX CX DX BX BP SI DI
},
- clobbers: 8589934593, // AX FLAGS
- outputs: []regMask{
- 4, // DX
+ outputs: []outputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
},
},
},
{
- name: "MODQU",
- argLen: 2,
- asm: x86.ADIVQ,
+ name: "ANDLconst",
+ auxType: auxInt32,
+ argLen: 1,
+ resultInArg0: true,
+ clobberFlags: true,
+ asm: x86.AANDL,
reg: regInfo{
inputs: []inputInfo{
- {0, 1}, // AX
- {1, 65531}, // AX CX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 239}, // AX CX DX BX BP SI DI
},
- clobbers: 8589934593, // AX FLAGS
- outputs: []regMask{
- 4, // DX
+ outputs: []outputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
},
},
},
{
- name: "MODLU",
- argLen: 2,
- asm: x86.ADIVL,
+ name: "ORL",
+ argLen: 2,
+ commutative: true,
+ resultInArg0: true,
+ clobberFlags: true,
+ asm: x86.AORL,
reg: regInfo{
inputs: []inputInfo{
- {0, 1}, // AX
- {1, 65531}, // AX CX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 239}, // AX CX DX BX BP SI DI
+ {1, 239}, // AX CX DX BX BP SI DI
},
- clobbers: 8589934593, // AX FLAGS
- outputs: []regMask{
- 4, // DX
+ outputs: []outputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
},
},
},
{
- name: "MODWU",
- argLen: 2,
- asm: x86.ADIVW,
+ name: "ORLconst",
+ auxType: auxInt32,
+ argLen: 1,
+ resultInArg0: true,
+ clobberFlags: true,
+ asm: x86.AORL,
reg: regInfo{
inputs: []inputInfo{
- {0, 1}, // AX
- {1, 65531}, // AX CX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 239}, // AX CX DX BX BP SI DI
},
- clobbers: 8589934593, // AX FLAGS
- outputs: []regMask{
- 4, // DX
+ outputs: []outputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
},
},
},
{
- name: "ANDQ",
+ name: "XORL",
argLen: 2,
commutative: true,
resultInArg0: true,
- asm: x86.AANDQ,
+ clobberFlags: true,
+ asm: x86.AXORL,
reg: regInfo{
inputs: []inputInfo{
- {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- {1, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 239}, // AX CX DX BX BP SI DI
+ {1, 239}, // AX CX DX BX BP SI DI
},
- clobbers: 8589934592, // FLAGS
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ outputs: []outputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
},
},
},
{
- name: "ANDL",
- argLen: 2,
- commutative: true,
+ name: "XORLconst",
+ auxType: auxInt32,
+ argLen: 1,
resultInArg0: true,
- asm: x86.AANDL,
+ clobberFlags: true,
+ asm: x86.AXORL,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
+ },
+ outputs: []outputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
+ },
+ },
+ },
+ {
+ name: "CMPL",
+ argLen: 2,
+ asm: x86.ACMPL,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 255}, // AX CX DX BX SP BP SI DI
+ {1, 255}, // AX CX DX BX SP BP SI DI
+ },
+ },
+ },
+ {
+ name: "CMPW",
+ argLen: 2,
+ asm: x86.ACMPW,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 255}, // AX CX DX BX SP BP SI DI
+ {1, 255}, // AX CX DX BX SP BP SI DI
+ },
+ },
+ },
+ {
+ name: "CMPB",
+ argLen: 2,
+ asm: x86.ACMPB,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 255}, // AX CX DX BX SP BP SI DI
+ {1, 255}, // AX CX DX BX SP BP SI DI
+ },
+ },
+ },
+ {
+ name: "CMPLconst",
+ auxType: auxInt32,
+ argLen: 1,
+ asm: x86.ACMPL,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 255}, // AX CX DX BX SP BP SI DI
+ },
+ },
+ },
+ {
+ name: "CMPWconst",
+ auxType: auxInt16,
+ argLen: 1,
+ asm: x86.ACMPW,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 255}, // AX CX DX BX SP BP SI DI
+ },
+ },
+ },
+ {
+ name: "CMPBconst",
+ auxType: auxInt8,
+ argLen: 1,
+ asm: x86.ACMPB,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 255}, // AX CX DX BX SP BP SI DI
+ },
+ },
+ },
+ {
+ name: "UCOMISS",
+ argLen: 2,
+ usesScratch: true,
+ asm: x86.AUCOMISS,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 65280}, // X0 X1 X2 X3 X4 X5 X6 X7
+ {1, 65280}, // X0 X1 X2 X3 X4 X5 X6 X7
+ },
+ },
+ },
+ {
+ name: "UCOMISD",
+ argLen: 2,
+ usesScratch: true,
+ asm: x86.AUCOMISD,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 65280}, // X0 X1 X2 X3 X4 X5 X6 X7
+ {1, 65280}, // X0 X1 X2 X3 X4 X5 X6 X7
+ },
+ },
+ },
+ {
+ name: "TESTL",
+ argLen: 2,
+ asm: x86.ATESTL,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 255}, // AX CX DX BX SP BP SI DI
+ {1, 255}, // AX CX DX BX SP BP SI DI
+ },
+ },
+ },
+ {
+ name: "TESTW",
+ argLen: 2,
+ asm: x86.ATESTW,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 255}, // AX CX DX BX SP BP SI DI
+ {1, 255}, // AX CX DX BX SP BP SI DI
+ },
+ },
+ },
+ {
+ name: "TESTB",
+ argLen: 2,
+ asm: x86.ATESTB,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 255}, // AX CX DX BX SP BP SI DI
+ {1, 255}, // AX CX DX BX SP BP SI DI
+ },
+ },
+ },
+ {
+ name: "TESTLconst",
+ auxType: auxInt32,
+ argLen: 1,
+ asm: x86.ATESTL,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 255}, // AX CX DX BX SP BP SI DI
+ },
+ },
+ },
+ {
+ name: "TESTWconst",
+ auxType: auxInt16,
+ argLen: 1,
+ asm: x86.ATESTW,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 255}, // AX CX DX BX SP BP SI DI
+ },
+ },
+ },
+ {
+ name: "TESTBconst",
+ auxType: auxInt8,
+ argLen: 1,
+ asm: x86.ATESTB,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 255}, // AX CX DX BX SP BP SI DI
+ },
+ },
+ },
+ {
+ name: "SHLL",
+ argLen: 2,
+ resultInArg0: true,
+ clobberFlags: true,
+ asm: x86.ASHLL,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 2}, // CX
+ {0, 239}, // AX CX DX BX BP SI DI
+ },
+ outputs: []outputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
+ },
+ },
+ },
+ {
+ name: "SHLLconst",
+ auxType: auxInt32,
+ argLen: 1,
+ resultInArg0: true,
+ clobberFlags: true,
+ asm: x86.ASHLL,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
+ },
+ outputs: []outputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
+ },
+ },
+ },
+ {
+ name: "SHRL",
+ argLen: 2,
+ resultInArg0: true,
+ clobberFlags: true,
+ asm: x86.ASHRL,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 2}, // CX
+ {0, 239}, // AX CX DX BX BP SI DI
+ },
+ outputs: []outputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
+ },
+ },
+ },
+ {
+ name: "SHRW",
+ argLen: 2,
+ resultInArg0: true,
+ clobberFlags: true,
+ asm: x86.ASHRW,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 2}, // CX
+ {0, 239}, // AX CX DX BX BP SI DI
+ },
+ outputs: []outputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
+ },
+ },
+ },
+ {
+ name: "SHRB",
+ argLen: 2,
+ resultInArg0: true,
+ clobberFlags: true,
+ asm: x86.ASHRB,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 2}, // CX
+ {0, 239}, // AX CX DX BX BP SI DI
+ },
+ outputs: []outputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
+ },
+ },
+ },
+ {
+ name: "SHRLconst",
+ auxType: auxInt32,
+ argLen: 1,
+ resultInArg0: true,
+ clobberFlags: true,
+ asm: x86.ASHRL,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
+ },
+ outputs: []outputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
+ },
+ },
+ },
+ {
+ name: "SHRWconst",
+ auxType: auxInt16,
+ argLen: 1,
+ resultInArg0: true,
+ clobberFlags: true,
+ asm: x86.ASHRW,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
+ },
+ outputs: []outputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
+ },
+ },
+ },
+ {
+ name: "SHRBconst",
+ auxType: auxInt8,
+ argLen: 1,
+ resultInArg0: true,
+ clobberFlags: true,
+ asm: x86.ASHRB,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
+ },
+ outputs: []outputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
+ },
+ },
+ },
+ {
+ name: "SARL",
+ argLen: 2,
+ resultInArg0: true,
+ clobberFlags: true,
+ asm: x86.ASARL,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 2}, // CX
+ {0, 239}, // AX CX DX BX BP SI DI
+ },
+ outputs: []outputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
+ },
+ },
+ },
+ {
+ name: "SARW",
+ argLen: 2,
+ resultInArg0: true,
+ clobberFlags: true,
+ asm: x86.ASARW,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 2}, // CX
+ {0, 239}, // AX CX DX BX BP SI DI
+ },
+ outputs: []outputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
+ },
+ },
+ },
+ {
+ name: "SARB",
+ argLen: 2,
+ resultInArg0: true,
+ clobberFlags: true,
+ asm: x86.ASARB,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 2}, // CX
+ {0, 239}, // AX CX DX BX BP SI DI
+ },
+ outputs: []outputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
+ },
+ },
+ },
+ {
+ name: "SARLconst",
+ auxType: auxInt32,
+ argLen: 1,
+ resultInArg0: true,
+ clobberFlags: true,
+ asm: x86.ASARL,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
+ },
+ outputs: []outputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
+ },
+ },
+ },
+ {
+ name: "SARWconst",
+ auxType: auxInt16,
+ argLen: 1,
+ resultInArg0: true,
+ clobberFlags: true,
+ asm: x86.ASARW,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
+ },
+ outputs: []outputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
+ },
+ },
+ },
+ {
+ name: "SARBconst",
+ auxType: auxInt8,
+ argLen: 1,
+ resultInArg0: true,
+ clobberFlags: true,
+ asm: x86.ASARB,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
+ },
+ outputs: []outputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
+ },
+ },
+ },
+ {
+ name: "ROLLconst",
+ auxType: auxInt32,
+ argLen: 1,
+ resultInArg0: true,
+ clobberFlags: true,
+ asm: x86.AROLL,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
+ },
+ outputs: []outputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
+ },
+ },
+ },
+ {
+ name: "ROLWconst",
+ auxType: auxInt16,
+ argLen: 1,
+ resultInArg0: true,
+ clobberFlags: true,
+ asm: x86.AROLW,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
+ },
+ outputs: []outputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
+ },
+ },
+ },
+ {
+ name: "ROLBconst",
+ auxType: auxInt8,
+ argLen: 1,
+ resultInArg0: true,
+ clobberFlags: true,
+ asm: x86.AROLB,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
+ },
+ outputs: []outputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
+ },
+ },
+ },
+ {
+ name: "NEGL",
+ argLen: 1,
+ resultInArg0: true,
+ clobberFlags: true,
+ asm: x86.ANEGL,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
+ },
+ outputs: []outputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
+ },
+ },
+ },
+ {
+ name: "NOTL",
+ argLen: 1,
+ resultInArg0: true,
+ clobberFlags: true,
+ asm: x86.ANOTL,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
+ },
+ outputs: []outputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
+ },
+ },
+ },
+ {
+ name: "BSFL",
+ argLen: 1,
+ clobberFlags: true,
+ asm: x86.ABSFL,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
+ },
+ outputs: []outputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
+ },
+ },
+ },
+ {
+ name: "BSFW",
+ argLen: 1,
+ clobberFlags: true,
+ asm: x86.ABSFW,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
+ },
+ outputs: []outputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
+ },
+ },
+ },
+ {
+ name: "BSRL",
+ argLen: 1,
+ clobberFlags: true,
+ asm: x86.ABSRL,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
+ },
+ outputs: []outputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
+ },
+ },
+ },
+ {
+ name: "BSRW",
+ argLen: 1,
+ clobberFlags: true,
+ asm: x86.ABSRW,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
+ },
+ outputs: []outputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
+ },
+ },
+ },
+ {
+ name: "BSWAPL",
+ argLen: 1,
+ resultInArg0: true,
+ clobberFlags: true,
+ asm: x86.ABSWAPL,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
+ },
+ outputs: []outputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
+ },
+ },
+ },
+ {
+ name: "SQRTSD",
+ argLen: 1,
+ asm: x86.ASQRTSD,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 65280}, // X0 X1 X2 X3 X4 X5 X6 X7
+ },
+ outputs: []outputInfo{
+ {0, 65280}, // X0 X1 X2 X3 X4 X5 X6 X7
+ },
+ },
+ },
+ {
+ name: "SBBLcarrymask",
+ argLen: 1,
+ asm: x86.ASBBL,
+ reg: regInfo{
+ outputs: []outputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
+ },
+ },
+ },
+ {
+ name: "SETEQ",
+ argLen: 1,
+ asm: x86.ASETEQ,
+ reg: regInfo{
+ outputs: []outputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
+ },
+ },
+ },
+ {
+ name: "SETNE",
+ argLen: 1,
+ asm: x86.ASETNE,
+ reg: regInfo{
+ outputs: []outputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
+ },
+ },
+ },
+ {
+ name: "SETL",
+ argLen: 1,
+ asm: x86.ASETLT,
+ reg: regInfo{
+ outputs: []outputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
+ },
+ },
+ },
+ {
+ name: "SETLE",
+ argLen: 1,
+ asm: x86.ASETLE,
+ reg: regInfo{
+ outputs: []outputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
+ },
+ },
+ },
+ {
+ name: "SETG",
+ argLen: 1,
+ asm: x86.ASETGT,
+ reg: regInfo{
+ outputs: []outputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
+ },
+ },
+ },
+ {
+ name: "SETGE",
+ argLen: 1,
+ asm: x86.ASETGE,
+ reg: regInfo{
+ outputs: []outputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
+ },
+ },
+ },
+ {
+ name: "SETB",
+ argLen: 1,
+ asm: x86.ASETCS,
+ reg: regInfo{
+ outputs: []outputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
+ },
+ },
+ },
+ {
+ name: "SETBE",
+ argLen: 1,
+ asm: x86.ASETLS,
+ reg: regInfo{
+ outputs: []outputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
+ },
+ },
+ },
+ {
+ name: "SETA",
+ argLen: 1,
+ asm: x86.ASETHI,
+ reg: regInfo{
+ outputs: []outputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
+ },
+ },
+ },
+ {
+ name: "SETAE",
+ argLen: 1,
+ asm: x86.ASETCC,
+ reg: regInfo{
+ outputs: []outputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
+ },
+ },
+ },
+ {
+ name: "SETEQF",
+ argLen: 1,
+ clobberFlags: true,
+ asm: x86.ASETEQ,
+ reg: regInfo{
+ clobbers: 1, // AX
+ outputs: []outputInfo{
+ {0, 238}, // CX DX BX BP SI DI
+ },
+ },
+ },
+ {
+ name: "SETNEF",
+ argLen: 1,
+ clobberFlags: true,
+ asm: x86.ASETNE,
+ reg: regInfo{
+ clobbers: 1, // AX
+ outputs: []outputInfo{
+ {0, 238}, // CX DX BX BP SI DI
+ },
+ },
+ },
+ {
+ name: "SETORD",
+ argLen: 1,
+ asm: x86.ASETPC,
+ reg: regInfo{
+ outputs: []outputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
+ },
+ },
+ },
+ {
+ name: "SETNAN",
+ argLen: 1,
+ asm: x86.ASETPS,
+ reg: regInfo{
+ outputs: []outputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
+ },
+ },
+ },
+ {
+ name: "SETGF",
+ argLen: 1,
+ asm: x86.ASETHI,
+ reg: regInfo{
+ outputs: []outputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
+ },
+ },
+ },
+ {
+ name: "SETGEF",
+ argLen: 1,
+ asm: x86.ASETCC,
+ reg: regInfo{
+ outputs: []outputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
+ },
+ },
+ },
+ {
+ name: "MOVBLSX",
+ argLen: 1,
+ asm: x86.AMOVBLSX,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
+ },
+ outputs: []outputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
+ },
+ },
+ },
+ {
+ name: "MOVBLZX",
+ argLen: 1,
+ asm: x86.AMOVBLZX,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
+ },
+ outputs: []outputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
+ },
+ },
+ },
+ {
+ name: "MOVWLSX",
+ argLen: 1,
+ asm: x86.AMOVWLSX,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
+ },
+ outputs: []outputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
+ },
+ },
+ },
+ {
+ name: "MOVWLZX",
+ argLen: 1,
+ asm: x86.AMOVWLZX,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
+ },
+ outputs: []outputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
+ },
+ },
+ },
+ {
+ name: "MOVLconst",
+ auxType: auxInt32,
+ argLen: 0,
+ rematerializeable: true,
+ asm: x86.AMOVL,
+ reg: regInfo{
+ outputs: []outputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
+ },
+ },
+ },
+ {
+ name: "CVTTSD2SL",
+ argLen: 1,
+ usesScratch: true,
+ asm: x86.ACVTTSD2SL,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 65280}, // X0 X1 X2 X3 X4 X5 X6 X7
+ },
+ outputs: []outputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
+ },
+ },
+ },
+ {
+ name: "CVTTSS2SL",
+ argLen: 1,
+ usesScratch: true,
+ asm: x86.ACVTTSS2SL,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 65280}, // X0 X1 X2 X3 X4 X5 X6 X7
+ },
+ outputs: []outputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
+ },
+ },
+ },
+ {
+ name: "CVTSL2SS",
+ argLen: 1,
+ usesScratch: true,
+ asm: x86.ACVTSL2SS,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
+ },
+ outputs: []outputInfo{
+ {0, 65280}, // X0 X1 X2 X3 X4 X5 X6 X7
+ },
+ },
+ },
+ {
+ name: "CVTSL2SD",
+ argLen: 1,
+ usesScratch: true,
+ asm: x86.ACVTSL2SD,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
+ },
+ outputs: []outputInfo{
+ {0, 65280}, // X0 X1 X2 X3 X4 X5 X6 X7
+ },
+ },
+ },
+ {
+ name: "CVTSD2SS",
+ argLen: 1,
+ usesScratch: true,
+ asm: x86.ACVTSD2SS,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 65280}, // X0 X1 X2 X3 X4 X5 X6 X7
+ },
+ outputs: []outputInfo{
+ {0, 65280}, // X0 X1 X2 X3 X4 X5 X6 X7
+ },
+ },
+ },
+ {
+ name: "CVTSS2SD",
+ argLen: 1,
+ asm: x86.ACVTSS2SD,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 65280}, // X0 X1 X2 X3 X4 X5 X6 X7
+ },
+ outputs: []outputInfo{
+ {0, 65280}, // X0 X1 X2 X3 X4 X5 X6 X7
+ },
+ },
+ },
+ {
+ name: "PXOR",
+ argLen: 2,
+ commutative: true,
+ resultInArg0: true,
+ asm: x86.APXOR,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 65280}, // X0 X1 X2 X3 X4 X5 X6 X7
+ {1, 65280}, // X0 X1 X2 X3 X4 X5 X6 X7
+ },
+ outputs: []outputInfo{
+ {0, 65280}, // X0 X1 X2 X3 X4 X5 X6 X7
+ },
+ },
+ },
+ {
+ name: "LEAL",
+ auxType: auxSymOff,
+ argLen: 1,
+ rematerializeable: true,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 65791}, // AX CX DX BX SP BP SI DI SB
+ },
+ outputs: []outputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
+ },
+ },
+ },
+ {
+ name: "LEAL1",
+ auxType: auxSymOff,
+ argLen: 2,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 255}, // AX CX DX BX SP BP SI DI
+ {0, 65791}, // AX CX DX BX SP BP SI DI SB
+ },
+ outputs: []outputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
+ },
+ },
+ },
+ {
+ name: "LEAL2",
+ auxType: auxSymOff,
+ argLen: 2,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 255}, // AX CX DX BX SP BP SI DI
+ {0, 65791}, // AX CX DX BX SP BP SI DI SB
+ },
+ outputs: []outputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
+ },
+ },
+ },
+ {
+ name: "LEAL4",
+ auxType: auxSymOff,
+ argLen: 2,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 255}, // AX CX DX BX SP BP SI DI
+ {0, 65791}, // AX CX DX BX SP BP SI DI SB
+ },
+ outputs: []outputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
+ },
+ },
+ },
+ {
+ name: "LEAL8",
+ auxType: auxSymOff,
+ argLen: 2,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 255}, // AX CX DX BX SP BP SI DI
+ {0, 65791}, // AX CX DX BX SP BP SI DI SB
+ },
+ outputs: []outputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
+ },
+ },
+ },
+ {
+ name: "MOVBload",
+ auxType: auxSymOff,
+ argLen: 2,
+ faultOnNilArg0: true,
+ asm: x86.AMOVBLZX,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 65791}, // AX CX DX BX SP BP SI DI SB
+ },
+ outputs: []outputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
+ },
+ },
+ },
+ {
+ name: "MOVBLSXload",
+ auxType: auxSymOff,
+ argLen: 2,
+ faultOnNilArg0: true,
+ asm: x86.AMOVBLSX,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 65791}, // AX CX DX BX SP BP SI DI SB
+ },
+ outputs: []outputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
+ },
+ },
+ },
+ {
+ name: "MOVWload",
+ auxType: auxSymOff,
+ argLen: 2,
+ faultOnNilArg0: true,
+ asm: x86.AMOVWLZX,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 65791}, // AX CX DX BX SP BP SI DI SB
+ },
+ outputs: []outputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
+ },
+ },
+ },
+ {
+ name: "MOVWLSXload",
+ auxType: auxSymOff,
+ argLen: 2,
+ faultOnNilArg0: true,
+ asm: x86.AMOVWLSX,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 65791}, // AX CX DX BX SP BP SI DI SB
+ },
+ outputs: []outputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
+ },
+ },
+ },
+ {
+ name: "MOVLload",
+ auxType: auxSymOff,
+ argLen: 2,
+ faultOnNilArg0: true,
+ asm: x86.AMOVL,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 65791}, // AX CX DX BX SP BP SI DI SB
+ },
+ outputs: []outputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
+ },
+ },
+ },
+ {
+ name: "MOVBstore",
+ auxType: auxSymOff,
+ argLen: 3,
+ faultOnNilArg0: true,
+ asm: x86.AMOVB,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 255}, // AX CX DX BX SP BP SI DI
+ {0, 65791}, // AX CX DX BX SP BP SI DI SB
+ },
+ },
+ },
+ {
+ name: "MOVWstore",
+ auxType: auxSymOff,
+ argLen: 3,
+ faultOnNilArg0: true,
+ asm: x86.AMOVW,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 255}, // AX CX DX BX SP BP SI DI
+ {0, 65791}, // AX CX DX BX SP BP SI DI SB
+ },
+ },
+ },
+ {
+ name: "MOVLstore",
+ auxType: auxSymOff,
+ argLen: 3,
+ faultOnNilArg0: true,
+ asm: x86.AMOVL,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 255}, // AX CX DX BX SP BP SI DI
+ {0, 65791}, // AX CX DX BX SP BP SI DI SB
+ },
+ },
+ },
+ {
+ name: "MOVBloadidx1",
+ auxType: auxSymOff,
+ argLen: 3,
+ asm: x86.AMOVBLZX,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 255}, // AX CX DX BX SP BP SI DI
+ {0, 65791}, // AX CX DX BX SP BP SI DI SB
+ },
+ outputs: []outputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
+ },
+ },
+ },
+ {
+ name: "MOVWloadidx1",
+ auxType: auxSymOff,
+ argLen: 3,
+ asm: x86.AMOVWLZX,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 255}, // AX CX DX BX SP BP SI DI
+ {0, 65791}, // AX CX DX BX SP BP SI DI SB
+ },
+ outputs: []outputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
+ },
+ },
+ },
+ {
+ name: "MOVWloadidx2",
+ auxType: auxSymOff,
+ argLen: 3,
+ asm: x86.AMOVWLZX,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 255}, // AX CX DX BX SP BP SI DI
+ {0, 65791}, // AX CX DX BX SP BP SI DI SB
+ },
+ outputs: []outputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
+ },
+ },
+ },
+ {
+ name: "MOVLloadidx1",
+ auxType: auxSymOff,
+ argLen: 3,
+ asm: x86.AMOVL,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 255}, // AX CX DX BX SP BP SI DI
+ {0, 65791}, // AX CX DX BX SP BP SI DI SB
+ },
+ outputs: []outputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
+ },
+ },
+ },
+ {
+ name: "MOVLloadidx4",
+ auxType: auxSymOff,
+ argLen: 3,
+ asm: x86.AMOVL,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 255}, // AX CX DX BX SP BP SI DI
+ {0, 65791}, // AX CX DX BX SP BP SI DI SB
+ },
+ outputs: []outputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
+ },
+ },
+ },
+ {
+ name: "MOVBstoreidx1",
+ auxType: auxSymOff,
+ argLen: 4,
+ asm: x86.AMOVB,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 255}, // AX CX DX BX SP BP SI DI
+ {2, 255}, // AX CX DX BX SP BP SI DI
+ {0, 65791}, // AX CX DX BX SP BP SI DI SB
+ },
+ },
+ },
+ {
+ name: "MOVWstoreidx1",
+ auxType: auxSymOff,
+ argLen: 4,
+ asm: x86.AMOVW,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 255}, // AX CX DX BX SP BP SI DI
+ {2, 255}, // AX CX DX BX SP BP SI DI
+ {0, 65791}, // AX CX DX BX SP BP SI DI SB
+ },
+ },
+ },
+ {
+ name: "MOVWstoreidx2",
+ auxType: auxSymOff,
+ argLen: 4,
+ asm: x86.AMOVW,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 255}, // AX CX DX BX SP BP SI DI
+ {2, 255}, // AX CX DX BX SP BP SI DI
+ {0, 65791}, // AX CX DX BX SP BP SI DI SB
+ },
+ },
+ },
+ {
+ name: "MOVLstoreidx1",
+ auxType: auxSymOff,
+ argLen: 4,
+ asm: x86.AMOVL,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 255}, // AX CX DX BX SP BP SI DI
+ {2, 255}, // AX CX DX BX SP BP SI DI
+ {0, 65791}, // AX CX DX BX SP BP SI DI SB
+ },
+ },
+ },
+ {
+ name: "MOVLstoreidx4",
+ auxType: auxSymOff,
+ argLen: 4,
+ asm: x86.AMOVL,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 255}, // AX CX DX BX SP BP SI DI
+ {2, 255}, // AX CX DX BX SP BP SI DI
+ {0, 65791}, // AX CX DX BX SP BP SI DI SB
+ },
+ },
+ },
+ {
+ name: "MOVBstoreconst",
+ auxType: auxSymValAndOff,
+ argLen: 2,
+ faultOnNilArg0: true,
+ asm: x86.AMOVB,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 65791}, // AX CX DX BX SP BP SI DI SB
+ },
+ },
+ },
+ {
+ name: "MOVWstoreconst",
+ auxType: auxSymValAndOff,
+ argLen: 2,
+ faultOnNilArg0: true,
+ asm: x86.AMOVW,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 65791}, // AX CX DX BX SP BP SI DI SB
+ },
+ },
+ },
+ {
+ name: "MOVLstoreconst",
+ auxType: auxSymValAndOff,
+ argLen: 2,
+ faultOnNilArg0: true,
+ asm: x86.AMOVL,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 65791}, // AX CX DX BX SP BP SI DI SB
+ },
+ },
+ },
+ {
+ name: "MOVBstoreconstidx1",
+ auxType: auxSymValAndOff,
+ argLen: 3,
+ asm: x86.AMOVB,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 255}, // AX CX DX BX SP BP SI DI
+ {0, 65791}, // AX CX DX BX SP BP SI DI SB
+ },
+ },
+ },
+ {
+ name: "MOVWstoreconstidx1",
+ auxType: auxSymValAndOff,
+ argLen: 3,
+ asm: x86.AMOVW,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 255}, // AX CX DX BX SP BP SI DI
+ {0, 65791}, // AX CX DX BX SP BP SI DI SB
+ },
+ },
+ },
+ {
+ name: "MOVWstoreconstidx2",
+ auxType: auxSymValAndOff,
+ argLen: 3,
+ asm: x86.AMOVW,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 255}, // AX CX DX BX SP BP SI DI
+ {0, 65791}, // AX CX DX BX SP BP SI DI SB
+ },
+ },
+ },
+ {
+ name: "MOVLstoreconstidx1",
+ auxType: auxSymValAndOff,
+ argLen: 3,
+ asm: x86.AMOVL,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 255}, // AX CX DX BX SP BP SI DI
+ {0, 65791}, // AX CX DX BX SP BP SI DI SB
+ },
+ },
+ },
+ {
+ name: "MOVLstoreconstidx4",
+ auxType: auxSymValAndOff,
+ argLen: 3,
+ asm: x86.AMOVL,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 255}, // AX CX DX BX SP BP SI DI
+ {0, 65791}, // AX CX DX BX SP BP SI DI SB
+ },
+ },
+ },
+ {
+ name: "DUFFZERO",
+ auxType: auxInt64,
+ argLen: 3,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 128}, // DI
+ {1, 1}, // AX
+ },
+ clobbers: 130, // CX DI
+ },
+ },
+ {
+ name: "REPSTOSL",
+ argLen: 4,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 128}, // DI
+ {1, 2}, // CX
+ {2, 1}, // AX
+ },
+ clobbers: 130, // CX DI
+ },
+ },
+ {
+ name: "CALLstatic",
+ auxType: auxSymOff,
+ argLen: 1,
+ clobberFlags: true,
+ call: true,
+ reg: regInfo{
+ clobbers: 65519, // AX CX DX BX BP SI DI X0 X1 X2 X3 X4 X5 X6 X7
+ },
+ },
+ {
+ name: "CALLclosure",
+ auxType: auxInt64,
+ argLen: 3,
+ clobberFlags: true,
+ call: true,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 4}, // DX
+ {0, 255}, // AX CX DX BX SP BP SI DI
+ },
+ clobbers: 65519, // AX CX DX BX BP SI DI X0 X1 X2 X3 X4 X5 X6 X7
+ },
+ },
+ {
+ 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,
+ clobberFlags: true,
+ call: true,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
+ },
+ clobbers: 65519, // AX CX DX BX BP SI DI X0 X1 X2 X3 X4 X5 X6 X7
+ },
+ },
+ {
+ name: "DUFFCOPY",
+ auxType: auxInt64,
+ argLen: 3,
+ clobberFlags: true,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 128}, // DI
+ {1, 64}, // SI
+ },
+ clobbers: 194, // CX SI DI
+ },
+ },
+ {
+ name: "REPMOVSL",
+ argLen: 4,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 128}, // DI
+ {1, 64}, // SI
+ {2, 2}, // CX
+ },
+ clobbers: 194, // CX SI DI
+ },
+ },
+ {
+ name: "InvertFlags",
+ argLen: 1,
+ reg: regInfo{},
+ },
+ {
+ name: "LoweredGetG",
+ argLen: 1,
+ reg: regInfo{
+ outputs: []outputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
+ },
+ },
+ },
+ {
+ name: "LoweredGetClosurePtr",
+ argLen: 0,
+ reg: regInfo{
+ outputs: []outputInfo{
+ {0, 4}, // DX
+ },
+ },
+ },
+ {
+ name: "LoweredNilCheck",
+ argLen: 2,
+ clobberFlags: true,
+ nilCheck: true,
+ faultOnNilArg0: true,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 255}, // AX CX DX BX SP BP SI DI
+ },
+ },
+ },
+ {
+ name: "MOVLconvert",
+ argLen: 2,
+ asm: x86.AMOVL,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
+ },
+ outputs: []outputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
+ },
+ },
+ },
+ {
+ name: "FlagEQ",
+ argLen: 0,
+ reg: regInfo{},
+ },
+ {
+ name: "FlagLT_ULT",
+ argLen: 0,
+ reg: regInfo{},
+ },
+ {
+ name: "FlagLT_UGT",
+ argLen: 0,
+ reg: regInfo{},
+ },
+ {
+ name: "FlagGT_UGT",
+ argLen: 0,
+ reg: regInfo{},
+ },
+ {
+ name: "FlagGT_ULT",
+ argLen: 0,
+ reg: regInfo{},
+ },
+ {
+ name: "FCHS",
+ argLen: 1,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 65280}, // X0 X1 X2 X3 X4 X5 X6 X7
+ },
+ outputs: []outputInfo{
+ {0, 65280}, // X0 X1 X2 X3 X4 X5 X6 X7
+ },
+ },
+ },
+ {
+ name: "MOVSSconst1",
+ auxType: auxFloat32,
+ argLen: 0,
+ reg: regInfo{
+ outputs: []outputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
+ },
+ },
+ },
+ {
+ name: "MOVSDconst1",
+ auxType: auxFloat64,
+ argLen: 0,
+ reg: regInfo{
+ outputs: []outputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
+ },
+ },
+ },
+ {
+ name: "MOVSSconst2",
+ argLen: 1,
+ asm: x86.AMOVSS,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
+ },
+ outputs: []outputInfo{
+ {0, 65280}, // X0 X1 X2 X3 X4 X5 X6 X7
+ },
+ },
+ },
+ {
+ name: "MOVSDconst2",
+ argLen: 1,
+ asm: x86.AMOVSD,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 239}, // AX CX DX BX BP SI DI
+ },
+ outputs: []outputInfo{
+ {0, 65280}, // X0 X1 X2 X3 X4 X5 X6 X7
+ },
+ },
+ },
+
+ {
+ name: "ADDSS",
+ argLen: 2,
+ commutative: true,
+ resultInArg0: true,
+ asm: x86.AADDSS,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+ {1, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+ },
+ outputs: []outputInfo{
+ {0, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+ },
+ },
+ },
+ {
+ name: "ADDSD",
+ argLen: 2,
+ commutative: true,
+ resultInArg0: true,
+ asm: x86.AADDSD,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+ {1, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+ },
+ outputs: []outputInfo{
+ {0, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+ },
+ },
+ },
+ {
+ name: "SUBSS",
+ argLen: 2,
+ resultInArg0: true,
+ asm: x86.ASUBSS,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+ {1, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+ },
+ outputs: []outputInfo{
+ {0, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+ },
+ },
+ },
+ {
+ name: "SUBSD",
+ argLen: 2,
+ resultInArg0: true,
+ 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, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+ },
+ outputs: []outputInfo{
+ {0, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+ },
+ },
+ },
+ {
+ name: "MULSS",
+ argLen: 2,
+ commutative: true,
+ resultInArg0: true,
+ asm: x86.AMULSS,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+ {1, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+ },
+ outputs: []outputInfo{
+ {0, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+ },
+ },
+ },
+ {
+ name: "MULSD",
+ argLen: 2,
+ commutative: true,
+ resultInArg0: true,
+ asm: x86.AMULSD,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+ {1, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+ },
+ outputs: []outputInfo{
+ {0, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+ },
+ },
+ },
+ {
+ name: "DIVSS",
+ argLen: 2,
+ resultInArg0: true,
+ asm: x86.ADIVSS,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+ {1, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+ },
+ outputs: []outputInfo{
+ {0, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+ },
+ },
+ },
+ {
+ name: "DIVSD",
+ argLen: 2,
+ resultInArg0: true,
+ asm: x86.ADIVSD,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+ {1, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+ },
+ outputs: []outputInfo{
+ {0, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+ },
+ },
+ },
+ {
+ name: "MOVSSload",
+ auxType: auxSymOff,
+ argLen: 2,
+ faultOnNilArg0: true,
+ asm: x86.AMOVSS,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+ },
+ outputs: []outputInfo{
+ {0, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+ },
+ },
+ },
+ {
+ name: "MOVSDload",
+ auxType: auxSymOff,
+ argLen: 2,
+ faultOnNilArg0: true,
+ asm: x86.AMOVSD,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+ },
+ outputs: []outputInfo{
+ {0, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+ },
+ },
+ },
+ {
+ name: "MOVSSconst",
+ auxType: auxFloat32,
+ argLen: 0,
+ rematerializeable: true,
+ asm: x86.AMOVSS,
+ reg: regInfo{
+ outputs: []outputInfo{
+ {0, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+ },
+ },
+ },
+ {
+ name: "MOVSDconst",
+ auxType: auxFloat64,
+ argLen: 0,
+ rematerializeable: true,
+ asm: x86.AMOVSD,
+ reg: regInfo{
+ outputs: []outputInfo{
+ {0, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+ },
+ },
+ },
+ {
+ name: "MOVSSloadidx1",
+ auxType: auxSymOff,
+ argLen: 3,
+ asm: x86.AMOVSS,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+ },
+ outputs: []outputInfo{
+ {0, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+ },
+ },
+ },
+ {
+ name: "MOVSSloadidx4",
+ auxType: auxSymOff,
+ argLen: 3,
+ asm: x86.AMOVSS,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+ },
+ outputs: []outputInfo{
+ {0, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+ },
+ },
+ },
+ {
+ name: "MOVSDloadidx1",
+ auxType: auxSymOff,
+ argLen: 3,
+ asm: x86.AMOVSD,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+ },
+ outputs: []outputInfo{
+ {0, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+ },
+ },
+ },
+ {
+ name: "MOVSDloadidx8",
+ auxType: auxSymOff,
+ argLen: 3,
+ asm: x86.AMOVSD,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+ },
+ outputs: []outputInfo{
+ {0, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+ },
+ },
+ },
+ {
+ name: "MOVSSstore",
+ auxType: auxSymOff,
+ argLen: 3,
+ faultOnNilArg0: true,
+ asm: x86.AMOVSS,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+ {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+ },
+ },
+ },
+ {
+ name: "MOVSDstore",
+ auxType: auxSymOff,
+ argLen: 3,
+ faultOnNilArg0: true,
+ asm: x86.AMOVSD,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+ {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+ },
+ },
+ },
+ {
+ name: "MOVSSstoreidx1",
+ auxType: auxSymOff,
+ argLen: 4,
+ asm: x86.AMOVSS,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {2, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+ {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+ },
+ },
+ },
+ {
+ name: "MOVSSstoreidx4",
+ auxType: auxSymOff,
+ argLen: 4,
+ asm: x86.AMOVSS,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {2, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+ {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+ },
+ },
+ },
+ {
+ name: "MOVSDstoreidx1",
+ auxType: auxSymOff,
+ argLen: 4,
+ asm: x86.AMOVSD,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {2, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+ {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+ },
+ },
+ },
+ {
+ name: "MOVSDstoreidx8",
+ auxType: auxSymOff,
+ argLen: 4,
+ asm: x86.AMOVSD,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {2, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+ {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+ },
+ },
+ },
+ {
+ name: "ADDQ",
+ argLen: 2,
+ commutative: true,
+ clobberFlags: true,
+ asm: x86.AADDQ,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ outputs: []outputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "ADDL",
+ argLen: 2,
+ commutative: true,
+ clobberFlags: true,
+ asm: x86.AADDL,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ outputs: []outputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "ADDQconst",
+ auxType: auxInt64,
+ argLen: 1,
+ clobberFlags: true,
+ asm: x86.AADDQ,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ outputs: []outputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "ADDLconst",
+ auxType: auxInt32,
+ argLen: 1,
+ clobberFlags: true,
+ asm: x86.AADDL,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ outputs: []outputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "SUBQ",
+ argLen: 2,
+ resultInArg0: true,
+ clobberFlags: true,
+ asm: x86.ASUBQ,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {1, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ outputs: []outputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "SUBL",
+ argLen: 2,
+ resultInArg0: true,
+ clobberFlags: true,
+ asm: x86.ASUBL,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {1, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ outputs: []outputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "SUBQconst",
+ auxType: auxInt64,
+ argLen: 1,
+ resultInArg0: true,
+ clobberFlags: true,
+ asm: x86.ASUBQ,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ outputs: []outputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "SUBLconst",
+ auxType: auxInt32,
+ argLen: 1,
+ resultInArg0: true,
+ clobberFlags: true,
+ asm: x86.ASUBL,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ outputs: []outputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "MULQ",
+ argLen: 2,
+ commutative: true,
+ resultInArg0: true,
+ clobberFlags: true,
+ asm: x86.AIMULQ,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {1, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ outputs: []outputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "MULL",
+ argLen: 2,
+ commutative: true,
+ resultInArg0: true,
+ clobberFlags: true,
+ asm: x86.AIMULL,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {1, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ outputs: []outputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "MULQconst",
+ auxType: auxInt64,
+ argLen: 1,
+ resultInArg0: true,
+ clobberFlags: true,
+ asm: x86.AIMULQ,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ outputs: []outputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "MULLconst",
+ auxType: auxInt32,
+ argLen: 1,
+ resultInArg0: true,
+ clobberFlags: true,
+ asm: x86.AIMULL,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ outputs: []outputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "HMULQ",
+ argLen: 2,
+ clobberFlags: true,
+ asm: x86.AIMULQ,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 1}, // AX
+ {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ clobbers: 1, // AX
+ outputs: []outputInfo{
+ {0, 4}, // DX
+ },
+ },
+ },
+ {
+ name: "HMULL",
+ argLen: 2,
+ clobberFlags: true,
+ asm: x86.AIMULL,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 1}, // AX
+ {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ clobbers: 1, // AX
+ outputs: []outputInfo{
+ {0, 4}, // DX
+ },
+ },
+ },
+ {
+ name: "HMULW",
+ argLen: 2,
+ clobberFlags: true,
+ asm: x86.AIMULW,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 1}, // AX
+ {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ clobbers: 1, // AX
+ outputs: []outputInfo{
+ {0, 4}, // DX
+ },
+ },
+ },
+ {
+ name: "HMULB",
+ argLen: 2,
+ clobberFlags: true,
+ asm: x86.AIMULB,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 1}, // AX
+ {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ clobbers: 1, // AX
+ outputs: []outputInfo{
+ {0, 4}, // DX
+ },
+ },
+ },
+ {
+ name: "HMULQU",
+ argLen: 2,
+ 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
+ },
+ outputs: []outputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "DIVQ",
+ argLen: 2,
+ clobberFlags: true,
+ asm: x86.AIDIVQ,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 1}, // AX
+ {1, 65531}, // AX CX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ outputs: []outputInfo{
+ {0, 1}, // AX
+ {1, 4}, // DX
+ },
+ },
+ },
+ {
+ name: "DIVL",
+ argLen: 2,
+ clobberFlags: true,
+ asm: x86.AIDIVL,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 1}, // AX
+ {1, 65531}, // AX CX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ outputs: []outputInfo{
+ {0, 1}, // AX
+ {1, 4}, // DX
+ },
+ },
+ },
+ {
+ name: "DIVW",
+ argLen: 2,
+ clobberFlags: true,
+ asm: x86.AIDIVW,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 1}, // AX
+ {1, 65531}, // AX CX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ outputs: []outputInfo{
+ {0, 1}, // AX
+ {1, 4}, // DX
+ },
+ },
+ },
+ {
+ name: "DIVQU",
+ argLen: 2,
+ clobberFlags: true,
+ asm: x86.ADIVQ,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 1}, // AX
+ {1, 65531}, // AX CX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ outputs: []outputInfo{
+ {0, 1}, // AX
+ {1, 4}, // DX
+ },
+ },
+ },
+ {
+ name: "DIVLU",
+ argLen: 2,
+ clobberFlags: true,
+ asm: x86.ADIVL,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 1}, // AX
+ {1, 65531}, // AX CX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ outputs: []outputInfo{
+ {0, 1}, // AX
+ {1, 4}, // DX
+ },
+ },
+ },
+ {
+ name: "DIVWU",
+ argLen: 2,
+ clobberFlags: true,
+ asm: x86.ADIVW,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 1}, // AX
+ {1, 65531}, // AX CX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ outputs: []outputInfo{
+ {0, 1}, // AX
+ {1, 4}, // DX
+ },
+ },
+ },
+ {
+ name: "MULQU2",
+ argLen: 2,
+ 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
+ },
+ outputs: []outputInfo{
+ {0, 4}, // DX
+ {1, 1}, // AX
+ },
+ },
+ },
+ {
+ name: "DIVQU2",
+ argLen: 3,
+ clobberFlags: true,
+ asm: x86.ADIVQ,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 4}, // DX
+ {1, 1}, // AX
+ {2, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ outputs: []outputInfo{
+ {0, 1}, // AX
+ {1, 4}, // DX
+ },
+ },
+ },
+ {
+ name: "ANDQ",
+ argLen: 2,
+ commutative: true,
+ resultInArg0: true,
+ clobberFlags: true,
+ asm: x86.AANDQ,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {1, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ outputs: []outputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "ANDL",
+ argLen: 2,
+ commutative: true,
+ resultInArg0: true,
+ clobberFlags: true,
+ asm: x86.AANDL,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {1, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ outputs: []outputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "ANDQconst",
+ auxType: auxInt64,
+ argLen: 1,
+ resultInArg0: true,
+ clobberFlags: true,
+ asm: x86.AANDQ,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ outputs: []outputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "ANDLconst",
+ auxType: auxInt32,
+ argLen: 1,
+ resultInArg0: true,
+ clobberFlags: true,
+ asm: x86.AANDL,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ outputs: []outputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "ORQ",
+ argLen: 2,
+ commutative: true,
+ resultInArg0: true,
+ clobberFlags: true,
+ asm: x86.AORQ,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {1, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ outputs: []outputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "ORL",
+ argLen: 2,
+ commutative: true,
+ resultInArg0: true,
+ clobberFlags: true,
+ asm: x86.AORL,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {1, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ outputs: []outputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "ORQconst",
+ auxType: auxInt64,
+ argLen: 1,
+ resultInArg0: true,
+ clobberFlags: true,
+ asm: x86.AORQ,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ outputs: []outputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "ORLconst",
+ auxType: auxInt32,
+ argLen: 1,
+ resultInArg0: true,
+ clobberFlags: true,
+ asm: x86.AORL,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ outputs: []outputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "XORQ",
+ argLen: 2,
+ commutative: true,
+ resultInArg0: true,
+ clobberFlags: true,
+ asm: x86.AXORQ,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {1, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ outputs: []outputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "XORL",
+ argLen: 2,
+ commutative: true,
+ resultInArg0: true,
+ clobberFlags: true,
+ asm: x86.AXORL,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {1, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ outputs: []outputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "XORQconst",
+ auxType: auxInt64,
+ argLen: 1,
+ resultInArg0: true,
+ clobberFlags: true,
+ asm: x86.AXORQ,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ outputs: []outputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "XORLconst",
+ auxType: auxInt32,
+ argLen: 1,
+ resultInArg0: true,
+ clobberFlags: true,
+ asm: x86.AXORL,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ outputs: []outputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "CMPQ",
+ argLen: 2,
+ asm: x86.ACMPQ,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "CMPL",
+ argLen: 2,
+ asm: x86.ACMPL,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "CMPW",
+ argLen: 2,
+ asm: x86.ACMPW,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "CMPB",
+ argLen: 2,
+ asm: x86.ACMPB,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "CMPQconst",
+ auxType: auxInt64,
+ argLen: 1,
+ asm: x86.ACMPQ,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "CMPLconst",
+ auxType: auxInt32,
+ argLen: 1,
+ asm: x86.ACMPL,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "CMPWconst",
+ auxType: auxInt16,
+ argLen: 1,
+ asm: x86.ACMPW,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "CMPBconst",
+ auxType: auxInt8,
+ argLen: 1,
+ asm: x86.ACMPB,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "UCOMISS",
+ argLen: 2,
+ asm: x86.AUCOMISS,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+ {1, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+ },
+ },
+ },
+ {
+ name: "UCOMISD",
+ argLen: 2,
+ asm: x86.AUCOMISD,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+ {1, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+ },
+ },
+ },
+ {
+ name: "TESTQ",
+ argLen: 2,
+ asm: x86.ATESTQ,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "TESTL",
+ argLen: 2,
+ asm: x86.ATESTL,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "TESTW",
+ argLen: 2,
+ asm: x86.ATESTW,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "TESTB",
+ argLen: 2,
+ asm: x86.ATESTB,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "TESTQconst",
+ auxType: auxInt64,
+ argLen: 1,
+ asm: x86.ATESTQ,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "TESTLconst",
+ auxType: auxInt32,
+ argLen: 1,
+ asm: x86.ATESTL,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "TESTWconst",
+ auxType: auxInt16,
+ argLen: 1,
+ asm: x86.ATESTW,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "TESTBconst",
+ auxType: auxInt8,
+ argLen: 1,
+ asm: x86.ATESTB,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "SHLQ",
+ argLen: 2,
+ resultInArg0: true,
+ clobberFlags: true,
+ asm: x86.ASHLQ,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 2}, // CX
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ outputs: []outputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "SHLL",
+ argLen: 2,
+ resultInArg0: true,
+ clobberFlags: true,
+ asm: x86.ASHLL,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 2}, // CX
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ outputs: []outputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "SHLQconst",
+ auxType: auxInt64,
+ argLen: 1,
+ resultInArg0: true,
+ clobberFlags: true,
+ asm: x86.ASHLQ,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ outputs: []outputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "SHLLconst",
+ auxType: auxInt32,
+ argLen: 1,
+ resultInArg0: true,
+ clobberFlags: true,
+ asm: x86.ASHLL,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ outputs: []outputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "SHRQ",
+ argLen: 2,
+ resultInArg0: true,
+ clobberFlags: true,
+ asm: x86.ASHRQ,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 2}, // CX
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ outputs: []outputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "SHRL",
+ argLen: 2,
+ resultInArg0: true,
+ clobberFlags: true,
+ asm: x86.ASHRL,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 2}, // CX
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ outputs: []outputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "SHRW",
+ argLen: 2,
+ resultInArg0: true,
+ clobberFlags: true,
+ asm: x86.ASHRW,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 2}, // CX
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ outputs: []outputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "SHRB",
+ argLen: 2,
+ resultInArg0: true,
+ clobberFlags: true,
+ asm: x86.ASHRB,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 2}, // CX
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ outputs: []outputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "SHRQconst",
+ auxType: auxInt64,
+ argLen: 1,
+ resultInArg0: true,
+ clobberFlags: true,
+ asm: x86.ASHRQ,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ outputs: []outputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "SHRLconst",
+ auxType: auxInt32,
+ argLen: 1,
+ resultInArg0: true,
+ clobberFlags: true,
+ asm: x86.ASHRL,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ outputs: []outputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "SHRWconst",
+ auxType: auxInt16,
+ argLen: 1,
+ resultInArg0: true,
+ clobberFlags: true,
+ asm: x86.ASHRW,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ outputs: []outputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "SHRBconst",
+ auxType: auxInt8,
+ argLen: 1,
+ resultInArg0: true,
+ clobberFlags: true,
+ asm: x86.ASHRB,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ outputs: []outputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "SARQ",
+ argLen: 2,
+ resultInArg0: true,
+ clobberFlags: true,
+ asm: x86.ASARQ,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 2}, // CX
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ outputs: []outputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "SARL",
+ argLen: 2,
+ resultInArg0: true,
+ clobberFlags: true,
+ asm: x86.ASARL,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 2}, // CX
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ outputs: []outputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "SARW",
+ argLen: 2,
+ resultInArg0: true,
+ clobberFlags: true,
+ asm: x86.ASARW,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 2}, // CX
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ outputs: []outputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "SARB",
+ argLen: 2,
+ resultInArg0: true,
+ clobberFlags: true,
+ asm: x86.ASARB,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 2}, // CX
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ outputs: []outputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "SARQconst",
+ auxType: auxInt64,
+ argLen: 1,
+ resultInArg0: true,
+ clobberFlags: true,
+ asm: x86.ASARQ,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ outputs: []outputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "SARLconst",
+ auxType: auxInt32,
+ argLen: 1,
+ resultInArg0: true,
+ clobberFlags: true,
+ asm: x86.ASARL,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ outputs: []outputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "SARWconst",
+ auxType: auxInt16,
+ argLen: 1,
+ resultInArg0: true,
+ clobberFlags: true,
+ asm: x86.ASARW,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ outputs: []outputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "SARBconst",
+ auxType: auxInt8,
+ argLen: 1,
+ resultInArg0: true,
+ clobberFlags: true,
+ asm: x86.ASARB,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ outputs: []outputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "ROLQconst",
+ auxType: auxInt64,
+ argLen: 1,
+ resultInArg0: true,
+ clobberFlags: true,
+ asm: x86.AROLQ,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ outputs: []outputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "ROLLconst",
+ auxType: auxInt32,
+ argLen: 1,
+ resultInArg0: true,
+ clobberFlags: true,
+ asm: x86.AROLL,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ outputs: []outputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "ROLWconst",
+ auxType: auxInt16,
+ argLen: 1,
+ resultInArg0: true,
+ clobberFlags: true,
+ asm: x86.AROLW,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ outputs: []outputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "ROLBconst",
+ auxType: auxInt8,
+ argLen: 1,
+ resultInArg0: true,
+ clobberFlags: true,
+ asm: x86.AROLB,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ 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,
+ clobberFlags: true,
+ asm: x86.ANEGQ,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ outputs: []outputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "NEGL",
+ argLen: 1,
+ resultInArg0: true,
+ clobberFlags: true,
+ asm: x86.ANEGL,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ outputs: []outputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "NOTQ",
+ argLen: 1,
+ resultInArg0: true,
+ clobberFlags: true,
+ asm: x86.ANOTQ,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ outputs: []outputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "NOTL",
+ argLen: 1,
+ resultInArg0: true,
+ clobberFlags: true,
+ asm: x86.ANOTL,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ outputs: []outputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "BSFQ",
+ argLen: 1,
+ asm: x86.ABSFQ,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ outputs: []outputInfo{
+ {1, 0},
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "BSFL",
+ argLen: 1,
+ asm: x86.ABSFL,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ 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,
+ 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
+ },
+ outputs: []outputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "BSWAPL",
+ argLen: 1,
+ resultInArg0: true,
+ 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
+ },
+ outputs: []outputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "SQRTSD",
+ argLen: 1,
+ asm: x86.ASQRTSD,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+ },
+ outputs: []outputInfo{
+ {0, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+ },
+ },
+ },
+ {
+ name: "SBBQcarrymask",
+ argLen: 1,
+ asm: x86.ASBBQ,
+ reg: regInfo{
+ outputs: []outputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "SBBLcarrymask",
+ argLen: 1,
+ asm: x86.ASBBL,
+ reg: regInfo{
+ outputs: []outputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "SETEQ",
+ argLen: 1,
+ asm: x86.ASETEQ,
+ reg: regInfo{
+ outputs: []outputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "SETNE",
+ argLen: 1,
+ asm: x86.ASETNE,
+ reg: regInfo{
+ outputs: []outputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "SETL",
+ argLen: 1,
+ asm: x86.ASETLT,
+ reg: regInfo{
+ outputs: []outputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "SETLE",
+ argLen: 1,
+ asm: x86.ASETLE,
+ reg: regInfo{
+ outputs: []outputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "SETG",
+ argLen: 1,
+ asm: x86.ASETGT,
+ reg: regInfo{
+ outputs: []outputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "SETGE",
+ argLen: 1,
+ asm: x86.ASETGE,
+ reg: regInfo{
+ outputs: []outputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "SETB",
+ argLen: 1,
+ asm: x86.ASETCS,
+ reg: regInfo{
+ outputs: []outputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "SETBE",
+ argLen: 1,
+ asm: x86.ASETLS,
+ reg: regInfo{
+ outputs: []outputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "SETA",
+ argLen: 1,
+ asm: x86.ASETHI,
+ reg: regInfo{
+ outputs: []outputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "SETAE",
+ argLen: 1,
+ asm: x86.ASETCC,
+ reg: regInfo{
+ outputs: []outputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "SETEQF",
+ argLen: 1,
+ clobberFlags: true,
+ asm: x86.ASETEQ,
+ reg: regInfo{
+ clobbers: 1, // AX
+ outputs: []outputInfo{
+ {0, 65518}, // CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "SETNEF",
+ argLen: 1,
+ clobberFlags: true,
+ asm: x86.ASETNE,
+ reg: regInfo{
+ clobbers: 1, // AX
+ outputs: []outputInfo{
+ {0, 65518}, // CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "SETORD",
+ argLen: 1,
+ asm: x86.ASETPC,
+ reg: regInfo{
+ outputs: []outputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "SETNAN",
+ argLen: 1,
+ asm: x86.ASETPS,
+ reg: regInfo{
+ outputs: []outputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "SETGF",
+ argLen: 1,
+ asm: x86.ASETHI,
+ reg: regInfo{
+ outputs: []outputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "SETGEF",
+ argLen: 1,
+ asm: x86.ASETCC,
+ reg: regInfo{
+ outputs: []outputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "MOVBQSX",
+ argLen: 1,
+ asm: x86.AMOVBQSX,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 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: "MOVBQZX",
+ argLen: 1,
+ asm: x86.AMOVBLZX,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {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: "MOVWQSX",
+ argLen: 1,
+ asm: x86.AMOVWQSX,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {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: "MOVWQZX",
+ argLen: 1,
+ asm: x86.AMOVWLZX,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {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: "MOVLQSX",
+ argLen: 1,
+ asm: x86.AMOVLQSX,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {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: "MOVLQZX",
+ argLen: 1,
+ asm: x86.AMOVL,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {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: "MOVLconst",
+ auxType: auxInt32,
+ argLen: 0,
+ rematerializeable: true,
+ asm: x86.AMOVL,
+ reg: regInfo{
+ outputs: []outputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "MOVQconst",
+ auxType: auxInt64,
+ argLen: 0,
+ rematerializeable: true,
+ asm: x86.AMOVQ,
+ reg: regInfo{
+ outputs: []outputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "CVTTSD2SL",
+ argLen: 1,
+ asm: x86.ACVTTSD2SL,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+ },
+ outputs: []outputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "CVTTSD2SQ",
+ argLen: 1,
+ asm: x86.ACVTTSD2SQ,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+ },
+ outputs: []outputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "CVTTSS2SL",
+ argLen: 1,
+ asm: x86.ACVTTSS2SL,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+ },
+ outputs: []outputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "CVTTSS2SQ",
+ argLen: 1,
+ asm: x86.ACVTTSS2SQ,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+ },
+ outputs: []outputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "CVTSL2SS",
+ argLen: 1,
+ asm: x86.ACVTSL2SS,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ outputs: []outputInfo{
+ {0, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+ },
+ },
+ },
+ {
+ name: "CVTSL2SD",
+ argLen: 1,
+ asm: x86.ACVTSL2SD,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ outputs: []outputInfo{
+ {0, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+ },
+ },
+ },
+ {
+ name: "CVTSQ2SS",
+ argLen: 1,
+ asm: x86.ACVTSQ2SS,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ outputs: []outputInfo{
+ {0, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+ },
+ },
+ },
+ {
+ name: "CVTSQ2SD",
+ argLen: 1,
+ asm: x86.ACVTSQ2SD,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ outputs: []outputInfo{
+ {0, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+ },
+ },
+ },
+ {
+ name: "CVTSD2SS",
+ argLen: 1,
+ asm: x86.ACVTSD2SS,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+ },
+ outputs: []outputInfo{
+ {0, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+ },
+ },
+ },
+ {
+ name: "CVTSS2SD",
+ argLen: 1,
+ asm: x86.ACVTSS2SD,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+ },
+ outputs: []outputInfo{
+ {0, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+ },
+ },
+ },
+ {
+ name: "PXOR",
+ argLen: 2,
+ commutative: true,
+ resultInArg0: true,
+ asm: x86.APXOR,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+ {1, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+ },
+ outputs: []outputInfo{
+ {0, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+ },
+ },
+ },
+ {
+ name: "LEAQ",
+ auxType: auxSymOff,
+ argLen: 1,
+ rematerializeable: true,
+ asm: x86.ALEAQ,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 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: "LEAQ1",
+ auxType: auxSymOff,
+ argLen: 2,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+ },
+ outputs: []outputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "LEAQ2",
+ auxType: auxSymOff,
+ argLen: 2,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+ },
+ outputs: []outputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "LEAQ4",
+ auxType: auxSymOff,
+ argLen: 2,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+ },
+ outputs: []outputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "LEAQ8",
+ auxType: auxSymOff,
+ argLen: 2,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+ },
+ outputs: []outputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "LEAL",
+ auxType: auxSymOff,
+ argLen: 1,
+ rematerializeable: true,
+ asm: x86.ALEAL,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 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: "MOVBload",
+ auxType: auxSymOff,
+ argLen: 2,
+ faultOnNilArg0: true,
+ asm: x86.AMOVBLZX,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+ },
+ outputs: []outputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "MOVBQSXload",
+ auxType: auxSymOff,
+ argLen: 2,
+ faultOnNilArg0: true,
+ asm: x86.AMOVBQSX,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+ },
+ outputs: []outputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "MOVWload",
+ auxType: auxSymOff,
+ argLen: 2,
+ faultOnNilArg0: true,
+ asm: x86.AMOVWLZX,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+ },
+ outputs: []outputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "MOVWQSXload",
+ auxType: auxSymOff,
+ argLen: 2,
+ faultOnNilArg0: true,
+ asm: x86.AMOVWQSX,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+ },
+ outputs: []outputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "MOVLload",
+ auxType: auxSymOff,
+ argLen: 2,
+ faultOnNilArg0: true,
+ asm: x86.AMOVL,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+ },
+ outputs: []outputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "MOVLQSXload",
+ auxType: auxSymOff,
+ argLen: 2,
+ faultOnNilArg0: true,
+ asm: x86.AMOVLQSX,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+ },
+ outputs: []outputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "MOVQload",
+ auxType: auxSymOff,
+ argLen: 2,
+ faultOnNilArg0: true,
+ asm: x86.AMOVQ,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+ },
+ outputs: []outputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "MOVBstore",
+ auxType: auxSymOff,
+ argLen: 3,
+ faultOnNilArg0: true,
+ asm: x86.AMOVB,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+ },
+ },
+ },
+ {
+ name: "MOVWstore",
+ auxType: auxSymOff,
+ argLen: 3,
+ faultOnNilArg0: true,
+ asm: x86.AMOVW,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+ },
+ },
+ },
+ {
+ name: "MOVLstore",
+ auxType: auxSymOff,
+ argLen: 3,
+ faultOnNilArg0: true,
+ asm: x86.AMOVL,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+ },
+ },
+ },
+ {
+ name: "MOVQstore",
+ auxType: auxSymOff,
+ argLen: 3,
+ faultOnNilArg0: true,
+ asm: x86.AMOVQ,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+ },
+ },
+ },
+ {
+ name: "MOVOload",
+ auxType: auxSymOff,
+ argLen: 2,
+ faultOnNilArg0: true,
+ asm: x86.AMOVUPS,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+ },
+ outputs: []outputInfo{
+ {0, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+ },
+ },
+ },
+ {
+ name: "MOVOstore",
+ auxType: auxSymOff,
+ argLen: 3,
+ faultOnNilArg0: true,
+ asm: x86.AMOVUPS,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+ {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+ },
+ },
+ },
+ {
+ name: "MOVBloadidx1",
+ auxType: auxSymOff,
+ argLen: 3,
+ asm: x86.AMOVBLZX,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+ },
+ outputs: []outputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "MOVWloadidx1",
+ auxType: auxSymOff,
+ argLen: 3,
+ asm: x86.AMOVWLZX,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+ },
+ outputs: []outputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "MOVWloadidx2",
+ auxType: auxSymOff,
+ argLen: 3,
+ asm: x86.AMOVWLZX,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+ },
+ outputs: []outputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "MOVLloadidx1",
+ auxType: auxSymOff,
+ argLen: 3,
+ asm: x86.AMOVL,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+ },
+ outputs: []outputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "MOVLloadidx4",
+ auxType: auxSymOff,
+ argLen: 3,
+ asm: x86.AMOVL,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+ },
+ outputs: []outputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "MOVQloadidx1",
+ auxType: auxSymOff,
+ argLen: 3,
+ asm: x86.AMOVQ,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+ },
+ outputs: []outputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "MOVQloadidx8",
+ auxType: auxSymOff,
+ argLen: 3,
+ asm: x86.AMOVQ,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+ },
+ outputs: []outputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "MOVBstoreidx1",
+ auxType: auxSymOff,
+ argLen: 4,
+ asm: x86.AMOVB,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {2, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+ },
+ },
+ },
+ {
+ name: "MOVWstoreidx1",
+ auxType: auxSymOff,
+ argLen: 4,
+ asm: x86.AMOVW,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {2, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+ },
+ },
+ },
+ {
+ name: "MOVWstoreidx2",
+ auxType: auxSymOff,
+ argLen: 4,
+ asm: x86.AMOVW,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {2, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+ },
+ },
+ },
+ {
+ name: "MOVLstoreidx1",
+ auxType: auxSymOff,
+ argLen: 4,
+ asm: x86.AMOVL,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {2, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+ },
+ },
+ },
+ {
+ name: "MOVLstoreidx4",
+ auxType: auxSymOff,
+ argLen: 4,
+ asm: x86.AMOVL,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {2, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+ },
+ },
+ },
+ {
+ name: "MOVQstoreidx1",
+ auxType: auxSymOff,
+ argLen: 4,
+ asm: x86.AMOVQ,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {2, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+ },
+ },
+ },
+ {
+ name: "MOVQstoreidx8",
+ auxType: auxSymOff,
+ argLen: 4,
+ asm: x86.AMOVQ,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {2, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+ },
+ },
+ },
+ {
+ name: "MOVBstoreconst",
+ auxType: auxSymValAndOff,
+ argLen: 2,
+ faultOnNilArg0: true,
+ asm: x86.AMOVB,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+ },
+ },
+ },
+ {
+ name: "MOVWstoreconst",
+ auxType: auxSymValAndOff,
+ argLen: 2,
+ faultOnNilArg0: true,
+ asm: x86.AMOVW,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+ },
+ },
+ },
+ {
+ name: "MOVLstoreconst",
+ auxType: auxSymValAndOff,
+ argLen: 2,
+ faultOnNilArg0: true,
+ asm: x86.AMOVL,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+ },
+ },
+ },
+ {
+ name: "MOVQstoreconst",
+ auxType: auxSymValAndOff,
+ argLen: 2,
+ faultOnNilArg0: true,
+ asm: x86.AMOVQ,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+ },
+ },
+ },
+ {
+ name: "MOVBstoreconstidx1",
+ auxType: auxSymValAndOff,
+ argLen: 3,
+ asm: x86.AMOVB,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+ },
+ },
+ },
+ {
+ name: "MOVWstoreconstidx1",
+ auxType: auxSymValAndOff,
+ argLen: 3,
+ asm: x86.AMOVW,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+ },
+ },
+ },
+ {
+ name: "MOVWstoreconstidx2",
+ auxType: auxSymValAndOff,
+ argLen: 3,
+ asm: x86.AMOVW,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+ },
+ },
+ },
+ {
+ name: "MOVLstoreconstidx1",
+ auxType: auxSymValAndOff,
+ argLen: 3,
+ asm: x86.AMOVL,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+ },
+ },
+ },
+ {
+ name: "MOVLstoreconstidx4",
+ auxType: auxSymValAndOff,
+ argLen: 3,
+ asm: x86.AMOVL,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+ },
+ },
+ },
+ {
+ name: "MOVQstoreconstidx1",
+ auxType: auxSymValAndOff,
+ argLen: 3,
+ asm: x86.AMOVQ,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+ },
+ },
+ },
+ {
+ name: "MOVQstoreconstidx8",
+ auxType: auxSymValAndOff,
+ argLen: 3,
+ asm: x86.AMOVQ,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+ },
+ },
+ },
+ {
+ name: "DUFFZERO",
+ auxType: auxInt64,
+ argLen: 3,
+ clobberFlags: true,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 128}, // DI
+ {1, 65536}, // X0
+ },
+ clobbers: 128, // DI
+ },
+ },
+ {
+ name: "MOVOconst",
+ auxType: auxInt128,
+ argLen: 0,
+ rematerializeable: true,
+ reg: regInfo{
+ outputs: []outputInfo{
+ {0, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+ },
+ },
+ },
+ {
+ name: "REPSTOSQ",
+ argLen: 4,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 128}, // DI
+ {1, 2}, // CX
+ {2, 1}, // AX
+ },
+ clobbers: 130, // CX DI
+ },
+ },
+ {
+ name: "CALLstatic",
+ auxType: auxSymOff,
+ argLen: 1,
+ 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: "CALLclosure",
+ auxType: auxInt64,
+ argLen: 3,
+ clobberFlags: true,
+ call: true,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 4}, // DX
+ {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ clobbers: 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: "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,
+ clobberFlags: true,
+ call: true,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ 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: "DUFFCOPY",
+ auxType: auxInt64,
+ argLen: 3,
+ clobberFlags: true,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 128}, // DI
+ {1, 64}, // SI
+ },
+ clobbers: 65728, // SI DI X0
+ },
+ },
+ {
+ name: "REPMOVSQ",
+ argLen: 4,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 128}, // DI
+ {1, 64}, // SI
+ {2, 2}, // CX
+ },
+ clobbers: 194, // CX SI DI
+ },
+ },
+ {
+ name: "InvertFlags",
+ argLen: 1,
+ reg: regInfo{},
+ },
+ {
+ name: "LoweredGetG",
+ argLen: 1,
+ reg: regInfo{
+ outputs: []outputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "LoweredGetClosurePtr",
+ argLen: 0,
+ reg: regInfo{
+ outputs: []outputInfo{
+ {0, 4}, // DX
+ },
+ },
+ },
+ {
+ name: "LoweredNilCheck",
+ argLen: 2,
+ clobberFlags: true,
+ nilCheck: true,
+ faultOnNilArg0: true,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "MOVQconvert",
+ argLen: 2,
+ asm: x86.AMOVQ,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {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: "MOVLconvert",
+ argLen: 2,
+ asm: x86.AMOVL,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {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: "FlagEQ",
+ argLen: 0,
+ reg: regInfo{},
+ },
+ {
+ name: "FlagLT_ULT",
+ argLen: 0,
+ reg: regInfo{},
+ },
+ {
+ name: "FlagLT_UGT",
+ argLen: 0,
+ reg: regInfo{},
+ },
+ {
+ name: "FlagGT_UGT",
+ argLen: 0,
+ reg: regInfo{},
+ },
+ {
+ name: "FlagGT_ULT",
+ argLen: 0,
+ reg: regInfo{},
+ },
+ {
+ name: "MOVLatomicload",
+ auxType: auxSymOff,
+ argLen: 2,
+ faultOnNilArg0: true,
+ asm: x86.AMOVL,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+ },
+ outputs: []outputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "MOVQatomicload",
+ auxType: auxSymOff,
+ argLen: 2,
+ faultOnNilArg0: true,
+ asm: x86.AMOVQ,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+ },
+ outputs: []outputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "XCHGL",
+ auxType: auxSymOff,
+ argLen: 3,
+ resultInArg0: true,
+ faultOnNilArg1: true,
+ 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
+ },
+ outputs: []outputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "XCHGQ",
+ auxType: auxSymOff,
+ argLen: 3,
+ resultInArg0: true,
+ faultOnNilArg1: true,
+ 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
+ },
+ outputs: []outputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "XADDLlock",
+ auxType: auxSymOff,
+ argLen: 3,
+ resultInArg0: true,
+ clobberFlags: true,
+ faultOnNilArg1: true,
+ 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
+ },
+ outputs: []outputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "XADDQlock",
+ auxType: auxSymOff,
+ argLen: 3,
+ resultInArg0: true,
+ clobberFlags: true,
+ faultOnNilArg1: true,
+ 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
+ },
+ outputs: []outputInfo{
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "AddTupleFirst32",
+ argLen: 2,
+ reg: regInfo{},
+ },
+ {
+ name: "AddTupleFirst64",
+ argLen: 2,
+ reg: regInfo{},
+ },
+ {
+ name: "CMPXCHGLlock",
+ auxType: auxSymOff,
+ argLen: 4,
+ clobberFlags: true,
+ faultOnNilArg0: true,
+ asm: x86.ACMPXCHGL,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 1}, // AX
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {2, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ clobbers: 1, // AX
+ outputs: []outputInfo{
+ {1, 0},
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "CMPXCHGQlock",
+ auxType: auxSymOff,
+ argLen: 4,
+ clobberFlags: true,
+ faultOnNilArg0: true,
+ asm: x86.ACMPXCHGQ,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 1}, // AX
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {2, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ clobbers: 1, // AX
+ outputs: []outputInfo{
+ {1, 0},
+ {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ },
+ {
+ name: "ANDBlock",
+ auxType: auxSymOff,
+ argLen: 3,
+ clobberFlags: true,
+ faultOnNilArg0: true,
+ asm: x86.AANDB,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+ },
+ },
+ },
+ {
+ name: "ORBlock",
+ auxType: auxSymOff,
+ argLen: 3,
+ clobberFlags: true,
+ faultOnNilArg0: true,
+ asm: x86.AORB,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+ },
+ },
+ },
+
+ {
+ name: "ADD",
+ argLen: 2,
+ commutative: true,
+ asm: arm.AADD,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 22527}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 R14
+ {1, 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: "ADDconst",
+ auxType: auxInt32,
+ argLen: 1,
+ asm: arm.AADD,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 30719}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 SP R14
+ },
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ },
+ },
+ {
+ name: "SUB",
+ argLen: 2,
+ asm: arm.ASUB,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 22527}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 R14
+ {1, 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: "SUBconst",
+ auxType: auxInt32,
+ argLen: 1,
+ asm: arm.ASUB,
+ 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: "RSB",
+ argLen: 2,
+ asm: arm.ARSB,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 22527}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 R14
+ {1, 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: "RSBconst",
+ auxType: auxInt32,
+ argLen: 1,
+ asm: arm.ARSB,
+ 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: "MUL",
+ argLen: 2,
+ commutative: true,
+ asm: arm.AMUL,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 22527}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 R14
+ {1, 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: "HMUL",
+ argLen: 2,
+ commutative: true,
+ asm: arm.AMULL,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 22527}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 R14
+ {1, 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: "HMULU",
+ argLen: 2,
+ commutative: true,
+ asm: arm.AMULLU,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 22527}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 R14
+ {1, 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: "UDIVrtcall",
+ argLen: 2,
+ clobberFlags: true,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 2}, // R1
+ {1, 1}, // R0
+ },
+ clobbers: 16396, // R2 R3 R14
+ outputs: []outputInfo{
+ {0, 1}, // R0
+ {1, 2}, // R1
+ },
+ },
+ },
+ {
+ name: "ADDS",
+ argLen: 2,
+ commutative: true,
+ asm: arm.AADD,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 22527}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 R14
+ {1, 22527}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 R14
+ },
+ outputs: []outputInfo{
+ {1, 0},
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ },
+ },
+ {
+ name: "ADDSconst",
+ auxType: auxInt32,
+ argLen: 1,
+ asm: arm.AADD,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 22527}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 R14
+ },
+ outputs: []outputInfo{
+ {1, 0},
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ },
+ },
+ {
+ name: "ADC",
+ argLen: 3,
+ commutative: true,
+ asm: arm.AADC,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {1, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ },
+ },
+ {
+ name: "ADCconst",
+ auxType: auxInt32,
+ argLen: 2,
+ asm: arm.AADC,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ },
+ },
+ {
+ name: "SUBS",
+ argLen: 2,
+ asm: arm.ASUB,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 22527}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 R14
+ {1, 22527}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 R14
+ },
+ outputs: []outputInfo{
+ {1, 0},
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ },
+ },
+ {
+ name: "SUBSconst",
+ auxType: auxInt32,
+ argLen: 1,
+ asm: arm.ASUB,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 22527}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 R14
+ },
+ outputs: []outputInfo{
+ {1, 0},
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ },
+ },
+ {
+ name: "RSBSconst",
+ auxType: auxInt32,
+ argLen: 1,
+ asm: arm.ARSB,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 22527}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 R14
+ },
+ outputs: []outputInfo{
+ {1, 0},
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ },
+ },
+ {
+ name: "SBC",
+ argLen: 3,
+ asm: arm.ASBC,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {1, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ },
+ },
+ {
+ name: "SBCconst",
+ auxType: auxInt32,
+ argLen: 2,
+ asm: arm.ASBC,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ },
+ },
+ {
+ name: "RSCconst",
+ auxType: auxInt32,
+ argLen: 2,
+ asm: arm.ARSC,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ },
+ },
+ {
+ name: "MULLU",
+ argLen: 2,
+ commutative: true,
+ asm: arm.AMULLU,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 22527}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 R14
+ {1, 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
+ {1, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ },
+ },
+ {
+ name: "MULA",
+ argLen: 3,
+ asm: arm.AMULA,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {1, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {2, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ },
+ },
+ {
+ name: "ADDF",
+ argLen: 2,
+ commutative: true,
+ asm: arm.AADDF,
+ 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
+ },
+ outputs: []outputInfo{
+ {0, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
+ },
+ },
+ },
+ {
+ name: "ADDD",
+ argLen: 2,
+ commutative: true,
+ asm: arm.AADDD,
+ 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
+ },
+ outputs: []outputInfo{
+ {0, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
+ },
+ },
+ },
+ {
+ name: "SUBF",
+ argLen: 2,
+ asm: arm.ASUBF,
+ 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
+ },
+ outputs: []outputInfo{
+ {0, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
+ },
+ },
+ },
+ {
+ name: "SUBD",
+ argLen: 2,
+ asm: arm.ASUBD,
+ 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
+ },
+ outputs: []outputInfo{
+ {0, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
+ },
+ },
+ },
+ {
+ name: "MULF",
+ argLen: 2,
+ commutative: true,
+ asm: arm.AMULF,
+ 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
+ },
+ outputs: []outputInfo{
+ {0, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
+ },
+ },
+ },
+ {
+ name: "MULD",
+ argLen: 2,
+ commutative: true,
+ asm: arm.AMULD,
+ 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
+ },
+ outputs: []outputInfo{
+ {0, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
+ },
+ },
+ },
+ {
+ name: "DIVF",
+ argLen: 2,
+ asm: arm.ADIVF,
+ 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
+ },
+ outputs: []outputInfo{
+ {0, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
+ },
+ },
+ },
+ {
+ name: "DIVD",
+ argLen: 2,
+ asm: arm.ADIVD,
+ 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
+ },
+ outputs: []outputInfo{
+ {0, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
+ },
+ },
+ },
+ {
+ name: "AND",
+ argLen: 2,
+ commutative: true,
+ asm: arm.AAND,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 22527}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 R14
+ {1, 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: "ANDconst",
+ auxType: auxInt32,
+ argLen: 1,
+ asm: arm.AAND,
+ 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: "OR",
+ argLen: 2,
+ commutative: true,
+ asm: arm.AORR,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 22527}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 R14
+ {1, 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: "ORconst",
+ auxType: auxInt32,
+ argLen: 1,
+ asm: arm.AORR,
+ 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: "XOR",
+ argLen: 2,
+ commutative: true,
+ asm: arm.AEOR,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 22527}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 R14
+ {1, 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: "XORconst",
+ auxType: auxInt32,
+ argLen: 1,
+ asm: arm.AEOR,
+ 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: "BIC",
+ argLen: 2,
+ asm: arm.ABIC,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 22527}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 R14
+ {1, 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: "BICconst",
+ auxType: auxInt32,
+ argLen: 1,
+ asm: arm.ABIC,
+ 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: "MVN",
+ argLen: 1,
+ asm: arm.AMVN,
+ 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: "NEGF",
+ argLen: 1,
+ asm: arm.ANEGF,
+ 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: "NEGD",
+ argLen: 1,
+ asm: arm.ANEGD,
+ 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: "SQRTD",
+ argLen: 1,
+ asm: arm.ASQRTD,
+ 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: "CLZ",
+ argLen: 1,
+ asm: arm.ACLZ,
+ 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,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 22527}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 R14
+ {1, 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: "SLLconst",
+ auxType: auxInt32,
+ argLen: 1,
+ asm: arm.ASLL,
+ 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: "SRL",
+ argLen: 2,
+ asm: arm.ASRL,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 22527}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 R14
+ {1, 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: "SRLconst",
+ auxType: auxInt32,
+ argLen: 1,
+ asm: arm.ASRL,
+ 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: "SRA",
+ argLen: 2,
+ asm: arm.ASRA,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 22527}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 R14
+ {1, 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: "SRAconst",
+ auxType: auxInt32,
+ argLen: 1,
+ asm: arm.ASRA,
+ 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: "SRRconst",
+ auxType: auxInt32,
+ argLen: 1,
+ 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: "ADDshiftLL",
+ auxType: auxInt32,
+ argLen: 2,
+ asm: arm.AADD,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 22527}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 R14
+ {1, 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: "ADDshiftRL",
+ auxType: auxInt32,
+ argLen: 2,
+ asm: arm.AADD,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 22527}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 R14
+ {1, 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: "ADDshiftRA",
+ auxType: auxInt32,
+ argLen: 2,
+ asm: arm.AADD,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 22527}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 R14
+ {1, 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: "SUBshiftLL",
+ auxType: auxInt32,
+ argLen: 2,
+ asm: arm.ASUB,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 22527}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 R14
+ {1, 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: "SUBshiftRL",
+ auxType: auxInt32,
+ argLen: 2,
+ asm: arm.ASUB,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 22527}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 R14
+ {1, 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: "SUBshiftRA",
+ auxType: auxInt32,
+ argLen: 2,
+ asm: arm.ASUB,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 22527}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 R14
+ {1, 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: "RSBshiftLL",
+ auxType: auxInt32,
+ argLen: 2,
+ asm: arm.ARSB,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 22527}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 R14
+ {1, 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: "RSBshiftRL",
+ auxType: auxInt32,
+ argLen: 2,
+ asm: arm.ARSB,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 22527}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 R14
+ {1, 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: "RSBshiftRA",
+ auxType: auxInt32,
+ argLen: 2,
+ asm: arm.ARSB,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 22527}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 R14
+ {1, 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: "ANDshiftLL",
+ auxType: auxInt32,
+ argLen: 2,
+ asm: arm.AAND,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 22527}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 R14
+ {1, 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: "ANDshiftRL",
+ auxType: auxInt32,
+ argLen: 2,
+ asm: arm.AAND,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 22527}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 R14
+ {1, 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: "ANDshiftRA",
+ auxType: auxInt32,
+ argLen: 2,
+ asm: arm.AAND,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 22527}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 R14
+ {1, 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: "ORshiftLL",
+ auxType: auxInt32,
+ argLen: 2,
+ asm: arm.AORR,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 22527}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 R14
+ {1, 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: "ORshiftRL",
+ auxType: auxInt32,
+ argLen: 2,
+ asm: arm.AORR,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 22527}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 R14
+ {1, 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: "ORshiftRA",
+ auxType: auxInt32,
+ argLen: 2,
+ asm: arm.AORR,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 22527}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 R14
+ {1, 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: "XORshiftLL",
+ auxType: auxInt32,
+ argLen: 2,
+ asm: arm.AEOR,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 22527}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 R14
+ {1, 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: "XORshiftRL",
+ auxType: auxInt32,
+ argLen: 2,
+ asm: arm.AEOR,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 22527}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 R14
+ {1, 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: "XORshiftRA",
+ auxType: auxInt32,
+ argLen: 2,
+ asm: arm.AEOR,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 22527}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 R14
+ {1, 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: "XORshiftRR",
+ auxType: auxInt32,
+ argLen: 2,
+ asm: arm.AEOR,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 22527}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 R14
+ {1, 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: "BICshiftLL",
+ auxType: auxInt32,
+ argLen: 2,
+ asm: arm.ABIC,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 22527}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 R14
+ {1, 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: "BICshiftRL",
+ auxType: auxInt32,
+ argLen: 2,
+ asm: arm.ABIC,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 22527}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 R14
+ {1, 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: "BICshiftRA",
+ auxType: auxInt32,
+ argLen: 2,
+ asm: arm.ABIC,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 22527}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 R14
+ {1, 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: "MVNshiftLL",
+ auxType: auxInt32,
+ argLen: 1,
+ asm: arm.AMVN,
+ 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: "MVNshiftRL",
+ auxType: auxInt32,
+ argLen: 1,
+ asm: arm.AMVN,
+ 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: "MVNshiftRA",
+ auxType: auxInt32,
+ argLen: 1,
+ asm: arm.AMVN,
+ 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: "ADCshiftLL",
+ auxType: auxInt32,
+ argLen: 3,
+ asm: arm.AADC,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {1, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ },
+ },
+ {
+ name: "ADCshiftRL",
+ auxType: auxInt32,
+ argLen: 3,
+ asm: arm.AADC,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {1, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ },
+ },
+ {
+ name: "ADCshiftRA",
+ auxType: auxInt32,
+ argLen: 3,
+ asm: arm.AADC,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {1, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ },
+ },
+ {
+ name: "SBCshiftLL",
+ auxType: auxInt32,
+ argLen: 3,
+ asm: arm.ASBC,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {1, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ },
+ },
+ {
+ name: "SBCshiftRL",
+ auxType: auxInt32,
+ argLen: 3,
+ asm: arm.ASBC,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {1, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ },
+ },
+ {
+ name: "SBCshiftRA",
+ auxType: auxInt32,
+ argLen: 3,
+ asm: arm.ASBC,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {1, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ },
+ },
+ {
+ name: "RSCshiftLL",
+ auxType: auxInt32,
+ argLen: 3,
+ asm: arm.ARSC,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {1, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ },
+ },
+ {
+ name: "RSCshiftRL",
+ auxType: auxInt32,
+ argLen: 3,
+ asm: arm.ARSC,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {1, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ },
+ },
+ {
+ name: "RSCshiftRA",
+ auxType: auxInt32,
+ argLen: 3,
+ asm: arm.ARSC,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {1, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ },
+ },
+ {
+ name: "ADDSshiftLL",
+ auxType: auxInt32,
+ argLen: 2,
+ asm: arm.AADD,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 22527}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 R14
+ {1, 22527}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 R14
+ },
+ outputs: []outputInfo{
+ {1, 0},
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ },
+ },
+ {
+ name: "ADDSshiftRL",
+ auxType: auxInt32,
+ argLen: 2,
+ asm: arm.AADD,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 22527}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 R14
+ {1, 22527}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 R14
+ },
+ outputs: []outputInfo{
+ {1, 0},
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ },
+ },
+ {
+ name: "ADDSshiftRA",
+ auxType: auxInt32,
+ argLen: 2,
+ asm: arm.AADD,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 22527}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 R14
+ {1, 22527}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 R14
+ },
+ outputs: []outputInfo{
+ {1, 0},
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ },
+ },
+ {
+ name: "SUBSshiftLL",
+ auxType: auxInt32,
+ argLen: 2,
+ asm: arm.ASUB,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 22527}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 R14
+ {1, 22527}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 R14
+ },
+ outputs: []outputInfo{
+ {1, 0},
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ },
+ },
+ {
+ name: "SUBSshiftRL",
+ auxType: auxInt32,
+ argLen: 2,
+ asm: arm.ASUB,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 22527}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 R14
+ {1, 22527}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 R14
+ },
+ outputs: []outputInfo{
+ {1, 0},
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ },
+ },
+ {
+ name: "SUBSshiftRA",
+ auxType: auxInt32,
+ argLen: 2,
+ asm: arm.ASUB,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 22527}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 R14
+ {1, 22527}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 R14
+ },
+ outputs: []outputInfo{
+ {1, 0},
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ },
+ },
+ {
+ name: "RSBSshiftLL",
+ auxType: auxInt32,
+ argLen: 2,
+ asm: arm.ARSB,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 22527}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 R14
+ {1, 22527}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 R14
+ },
+ outputs: []outputInfo{
+ {1, 0},
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ },
+ },
+ {
+ name: "RSBSshiftRL",
+ auxType: auxInt32,
+ argLen: 2,
+ asm: arm.ARSB,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 22527}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 R14
+ {1, 22527}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 R14
+ },
+ outputs: []outputInfo{
+ {1, 0},
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ },
+ },
+ {
+ name: "RSBSshiftRA",
+ auxType: auxInt32,
+ argLen: 2,
+ asm: arm.ARSB,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 22527}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 R14
+ {1, 22527}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 R14
+ },
+ outputs: []outputInfo{
+ {1, 0},
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ },
+ },
+ {
+ name: "ADDshiftLLreg",
+ argLen: 3,
+ asm: arm.AADD,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {1, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {2, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ },
+ },
+ {
+ name: "ADDshiftRLreg",
+ argLen: 3,
+ asm: arm.AADD,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {1, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {2, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ },
+ },
+ {
+ name: "ADDshiftRAreg",
+ argLen: 3,
+ asm: arm.AADD,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {1, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {2, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ },
+ },
+ {
+ name: "SUBshiftLLreg",
+ argLen: 3,
+ asm: arm.ASUB,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {1, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {2, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ },
+ },
+ {
+ name: "SUBshiftRLreg",
+ argLen: 3,
+ asm: arm.ASUB,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {1, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {2, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ },
+ },
+ {
+ name: "SUBshiftRAreg",
+ argLen: 3,
+ asm: arm.ASUB,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {1, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {2, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ },
+ },
+ {
+ name: "RSBshiftLLreg",
+ argLen: 3,
+ asm: arm.ARSB,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {1, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {2, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ },
+ },
+ {
+ name: "RSBshiftRLreg",
+ argLen: 3,
+ asm: arm.ARSB,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {1, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {2, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ },
+ },
+ {
+ name: "RSBshiftRAreg",
+ argLen: 3,
+ asm: arm.ARSB,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {1, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {2, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ },
+ },
+ {
+ name: "ANDshiftLLreg",
+ argLen: 3,
+ asm: arm.AAND,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {1, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {2, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ },
+ },
+ {
+ name: "ANDshiftRLreg",
+ argLen: 3,
+ asm: arm.AAND,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {1, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {2, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ },
+ },
+ {
+ name: "ANDshiftRAreg",
+ argLen: 3,
+ asm: arm.AAND,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {1, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {2, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ },
+ },
+ {
+ name: "ORshiftLLreg",
+ argLen: 3,
+ asm: arm.AORR,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {1, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {2, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ },
+ },
+ {
+ name: "ORshiftRLreg",
+ argLen: 3,
+ asm: arm.AORR,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {1, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {2, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ },
+ },
+ {
+ name: "ORshiftRAreg",
+ argLen: 3,
+ asm: arm.AORR,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {1, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {2, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ },
+ },
+ {
+ name: "XORshiftLLreg",
+ argLen: 3,
+ asm: arm.AEOR,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {1, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {2, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ },
+ },
+ {
+ name: "XORshiftRLreg",
+ argLen: 3,
+ asm: arm.AEOR,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {1, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {2, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ },
+ },
+ {
+ name: "XORshiftRAreg",
+ argLen: 3,
+ asm: arm.AEOR,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {1, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {2, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ },
+ },
+ {
+ name: "BICshiftLLreg",
+ argLen: 3,
+ asm: arm.ABIC,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {1, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {2, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ },
+ },
+ {
+ name: "BICshiftRLreg",
+ argLen: 3,
+ asm: arm.ABIC,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {1, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {2, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ },
+ },
+ {
+ name: "BICshiftRAreg",
+ argLen: 3,
+ asm: arm.ABIC,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {1, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {2, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ },
+ },
+ {
+ name: "MVNshiftLLreg",
+ argLen: 2,
+ asm: arm.AMVN,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 22527}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 R14
+ {1, 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: "MVNshiftRLreg",
+ argLen: 2,
+ asm: arm.AMVN,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 22527}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 R14
+ {1, 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: "MVNshiftRAreg",
+ argLen: 2,
+ asm: arm.AMVN,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 22527}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 R14
+ {1, 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: "ADCshiftLLreg",
+ argLen: 4,
+ asm: arm.AADC,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {1, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {2, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ },
+ },
+ {
+ name: "ADCshiftRLreg",
+ argLen: 4,
+ asm: arm.AADC,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {1, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {2, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ },
+ },
+ {
+ name: "ADCshiftRAreg",
+ argLen: 4,
+ asm: arm.AADC,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {1, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {2, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ },
+ },
+ {
+ name: "SBCshiftLLreg",
+ argLen: 4,
+ asm: arm.ASBC,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {1, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {2, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ },
+ },
+ {
+ name: "SBCshiftRLreg",
+ argLen: 4,
+ asm: arm.ASBC,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {1, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {2, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ },
+ },
+ {
+ name: "SBCshiftRAreg",
+ argLen: 4,
+ asm: arm.ASBC,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {1, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {2, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ },
+ },
+ {
+ name: "RSCshiftLLreg",
+ argLen: 4,
+ asm: arm.ARSC,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {1, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {2, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ },
+ },
+ {
+ name: "RSCshiftRLreg",
+ argLen: 4,
+ asm: arm.ARSC,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {1, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {2, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ },
+ },
+ {
+ name: "RSCshiftRAreg",
+ argLen: 4,
+ asm: arm.ARSC,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {1, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {2, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ },
+ },
+ {
+ name: "ADDSshiftLLreg",
+ argLen: 3,
+ asm: arm.AADD,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {1, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {2, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ outputs: []outputInfo{
+ {1, 0},
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ },
+ },
+ {
+ name: "ADDSshiftRLreg",
+ argLen: 3,
+ asm: arm.AADD,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {1, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {2, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ outputs: []outputInfo{
+ {1, 0},
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ },
+ },
+ {
+ name: "ADDSshiftRAreg",
+ argLen: 3,
+ asm: arm.AADD,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {1, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {2, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ outputs: []outputInfo{
+ {1, 0},
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ },
+ },
+ {
+ name: "SUBSshiftLLreg",
+ argLen: 3,
+ asm: arm.ASUB,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {1, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {2, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ outputs: []outputInfo{
+ {1, 0},
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ },
+ },
+ {
+ name: "SUBSshiftRLreg",
+ argLen: 3,
+ asm: arm.ASUB,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {1, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {2, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ outputs: []outputInfo{
+ {1, 0},
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ },
+ },
+ {
+ name: "SUBSshiftRAreg",
+ argLen: 3,
+ asm: arm.ASUB,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {1, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {2, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ outputs: []outputInfo{
+ {1, 0},
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ },
+ },
+ {
+ name: "RSBSshiftLLreg",
+ argLen: 3,
+ asm: arm.ARSB,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {1, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {2, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ outputs: []outputInfo{
+ {1, 0},
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ },
+ },
+ {
+ name: "RSBSshiftRLreg",
+ argLen: 3,
+ asm: arm.ARSB,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {1, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {2, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ outputs: []outputInfo{
+ {1, 0},
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ },
+ },
+ {
+ name: "RSBSshiftRAreg",
+ argLen: 3,
+ asm: arm.ARSB,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {1, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {2, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ outputs: []outputInfo{
+ {1, 0},
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ },
+ },
+ {
+ name: "CMP",
+ argLen: 2,
+ asm: arm.ACMP,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 22527}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 R14
+ {1, 22527}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 R14
+ },
+ },
+ },
+ {
+ name: "CMPconst",
+ auxType: auxInt32,
+ argLen: 1,
+ asm: arm.ACMP,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 22527}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 R14
+ },
+ },
+ },
+ {
+ name: "CMN",
+ argLen: 2,
+ asm: arm.ACMN,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 22527}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 R14
+ {1, 22527}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 R14
+ },
+ },
+ },
+ {
+ name: "CMNconst",
+ auxType: auxInt32,
+ argLen: 1,
+ asm: arm.ACMN,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 22527}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 R14
+ },
+ },
+ },
+ {
+ name: "TST",
+ argLen: 2,
+ commutative: true,
+ asm: arm.ATST,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 22527}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 R14
+ {1, 22527}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 R14
+ },
+ },
+ },
+ {
+ name: "TSTconst",
+ auxType: auxInt32,
+ argLen: 1,
+ asm: arm.ATST,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 22527}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 R14
+ },
+ },
+ },
+ {
+ name: "TEQ",
+ argLen: 2,
+ commutative: true,
+ asm: arm.ATEQ,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 22527}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 R14
+ {1, 22527}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 R14
+ },
+ },
+ },
+ {
+ name: "TEQconst",
+ auxType: auxInt32,
+ argLen: 1,
+ asm: arm.ATEQ,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 22527}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 R14
+ },
+ },
+ },
+ {
+ name: "CMPF",
+ argLen: 2,
+ asm: arm.ACMPF,
+ 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
+ },
+ },
+ },
+ {
+ name: "CMPD",
+ argLen: 2,
+ asm: arm.ACMPD,
+ 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
+ },
+ },
+ },
+ {
+ name: "CMPshiftLL",
+ auxType: auxInt32,
+ argLen: 2,
+ asm: arm.ACMP,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 22527}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 R14
+ {1, 22527}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 R14
+ },
+ },
+ },
+ {
+ name: "CMPshiftRL",
+ auxType: auxInt32,
+ argLen: 2,
+ asm: arm.ACMP,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 22527}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 R14
+ {1, 22527}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 R14
+ },
+ },
+ },
+ {
+ name: "CMPshiftRA",
+ auxType: auxInt32,
+ argLen: 2,
+ asm: arm.ACMP,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 22527}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 R14
+ {1, 22527}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 R14
+ },
+ },
+ },
+ {
+ name: "CMPshiftLLreg",
+ argLen: 3,
+ asm: arm.ACMP,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {1, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {2, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ },
+ },
+ {
+ name: "CMPshiftRLreg",
+ argLen: 3,
+ asm: arm.ACMP,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {1, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {2, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ },
+ },
+ {
+ name: "CMPshiftRAreg",
+ argLen: 3,
+ asm: arm.ACMP,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {1, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {2, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ },
+ },
+ {
+ name: "CMPF0",
+ argLen: 1,
+ asm: arm.ACMPF,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
+ },
+ },
+ },
+ {
+ name: "CMPD0",
+ argLen: 1,
+ asm: arm.ACMPD,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
+ },
+ },
+ },
+ {
+ name: "MOVWconst",
+ auxType: auxInt32,
+ argLen: 0,
+ rematerializeable: true,
+ asm: arm.AMOVW,
+ reg: regInfo{
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ },
+ },
+ {
+ name: "MOVFconst",
+ auxType: auxFloat64,
+ argLen: 0,
+ rematerializeable: true,
+ asm: arm.AMOVF,
+ reg: regInfo{
+ outputs: []outputInfo{
+ {0, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
+ },
+ },
+ },
+ {
+ name: "MOVDconst",
+ auxType: auxFloat64,
+ argLen: 0,
+ rematerializeable: true,
+ asm: arm.AMOVD,
+ reg: regInfo{
+ outputs: []outputInfo{
+ {0, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
+ },
+ },
+ },
+ {
+ name: "MOVWaddr",
+ auxType: auxSymOff,
+ argLen: 1,
+ rematerializeable: true,
+ asm: arm.AMOVW,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 4294975488}, // SP SB
+ },
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ },
+ },
+ {
+ name: "MOVBload",
+ auxType: auxSymOff,
+ argLen: 2,
+ faultOnNilArg0: true,
+ asm: arm.AMOVB,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 4294998015}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 SP R14 SB
+ },
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ },
+ },
+ {
+ name: "MOVBUload",
+ auxType: auxSymOff,
+ argLen: 2,
+ faultOnNilArg0: true,
+ asm: arm.AMOVBU,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 4294998015}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 SP R14 SB
+ },
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ },
+ },
+ {
+ name: "MOVHload",
+ auxType: auxSymOff,
+ argLen: 2,
+ faultOnNilArg0: true,
+ asm: arm.AMOVH,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 4294998015}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 SP R14 SB
+ },
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ },
+ },
+ {
+ name: "MOVHUload",
+ auxType: auxSymOff,
+ argLen: 2,
+ faultOnNilArg0: true,
+ asm: arm.AMOVHU,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 4294998015}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 SP R14 SB
+ },
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ },
+ },
+ {
+ name: "MOVWload",
+ auxType: auxSymOff,
+ argLen: 2,
+ faultOnNilArg0: true,
+ asm: arm.AMOVW,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 4294998015}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 SP R14 SB
+ },
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ },
+ },
+ {
+ name: "MOVFload",
+ auxType: auxSymOff,
+ argLen: 2,
+ faultOnNilArg0: true,
+ asm: arm.AMOVF,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 4294998015}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 SP R14 SB
+ },
+ outputs: []outputInfo{
+ {0, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
+ },
+ },
+ },
+ {
+ name: "MOVDload",
+ auxType: auxSymOff,
+ argLen: 2,
+ faultOnNilArg0: true,
+ asm: arm.AMOVD,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 4294998015}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 SP R14 SB
+ },
+ outputs: []outputInfo{
+ {0, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
+ },
+ },
+ },
+ {
+ name: "MOVBstore",
+ auxType: auxSymOff,
+ argLen: 3,
+ faultOnNilArg0: true,
+ asm: arm.AMOVB,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 22527}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 R14
+ {0, 4294998015}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 SP R14 SB
+ },
+ },
+ },
+ {
+ name: "MOVHstore",
+ auxType: auxSymOff,
+ argLen: 3,
+ faultOnNilArg0: true,
+ asm: arm.AMOVH,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 22527}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 R14
+ {0, 4294998015}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 SP R14 SB
+ },
+ },
+ },
+ {
+ name: "MOVWstore",
+ auxType: auxSymOff,
+ argLen: 3,
+ faultOnNilArg0: true,
+ asm: arm.AMOVW,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 22527}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 R14
+ {0, 4294998015}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 SP R14 SB
+ },
+ },
+ },
+ {
+ name: "MOVFstore",
+ auxType: auxSymOff,
+ argLen: 3,
+ faultOnNilArg0: true,
+ asm: arm.AMOVF,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 4294998015}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 SP R14 SB
+ {1, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
+ },
+ },
+ },
+ {
+ name: "MOVDstore",
+ auxType: auxSymOff,
+ argLen: 3,
+ faultOnNilArg0: true,
+ asm: arm.AMOVD,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 4294998015}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 SP R14 SB
+ {1, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
+ },
+ },
+ },
+ {
+ name: "MOVWloadidx",
+ argLen: 3,
+ asm: arm.AMOVW,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 22527}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 R14
+ {0, 4294998015}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 SP R14 SB
+ },
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ },
+ },
+ {
+ name: "MOVWloadshiftLL",
+ auxType: auxInt32,
+ argLen: 3,
+ asm: arm.AMOVW,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 22527}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 R14
+ {0, 4294998015}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 SP R14 SB
+ },
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ },
+ },
+ {
+ name: "MOVWloadshiftRL",
+ auxType: auxInt32,
+ argLen: 3,
+ asm: arm.AMOVW,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 22527}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 R14
+ {0, 4294998015}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 SP R14 SB
+ },
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ },
+ },
+ {
+ name: "MOVWloadshiftRA",
+ auxType: auxInt32,
+ argLen: 3,
+ asm: arm.AMOVW,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 22527}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 R14
+ {0, 4294998015}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 SP R14 SB
+ },
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ },
+ },
+ {
+ name: "MOVWstoreidx",
+ argLen: 4,
+ asm: arm.AMOVW,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 22527}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 R14
+ {2, 22527}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 R14
+ {0, 4294998015}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 SP R14 SB
+ },
+ },
+ },
+ {
+ name: "MOVWstoreshiftLL",
+ auxType: auxInt32,
+ argLen: 4,
+ asm: arm.AMOVW,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 22527}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 R14
+ {2, 22527}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 R14
+ {0, 4294998015}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 SP R14 SB
+ },
+ },
+ },
+ {
+ name: "MOVWstoreshiftRL",
+ auxType: auxInt32,
+ argLen: 4,
+ asm: arm.AMOVW,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 22527}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 R14
+ {2, 22527}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 R14
+ {0, 4294998015}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 SP R14 SB
+ },
+ },
+ },
+ {
+ name: "MOVWstoreshiftRA",
+ auxType: auxInt32,
+ argLen: 4,
+ asm: arm.AMOVW,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 22527}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 R14
+ {2, 22527}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 R14
+ {0, 4294998015}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 SP R14 SB
+ },
+ },
+ },
+ {
+ name: "MOVBreg",
+ argLen: 1,
+ asm: arm.AMOVBS,
+ 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: "MOVBUreg",
+ argLen: 1,
+ asm: arm.AMOVBU,
+ 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: "MOVHreg",
+ argLen: 1,
+ asm: arm.AMOVHS,
+ 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: "MOVHUreg",
+ argLen: 1,
+ asm: arm.AMOVHU,
+ 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: "MOVWreg",
+ argLen: 1,
+ asm: arm.AMOVW,
+ 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: "MOVWnop",
+ argLen: 1,
+ resultInArg0: true,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ },
+ },
+ {
+ name: "MOVWF",
+ argLen: 1,
+ asm: arm.AMOVWF,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ outputs: []outputInfo{
+ {0, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
+ },
+ },
+ },
+ {
+ name: "MOVWD",
+ argLen: 1,
+ asm: arm.AMOVWD,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ outputs: []outputInfo{
+ {0, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
+ },
+ },
+ },
+ {
+ name: "MOVWUF",
+ argLen: 1,
+ asm: arm.AMOVWF,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ outputs: []outputInfo{
+ {0, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
+ },
+ },
+ },
+ {
+ name: "MOVWUD",
+ argLen: 1,
+ asm: arm.AMOVWD,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ outputs: []outputInfo{
+ {0, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
+ },
+ },
+ },
+ {
+ name: "MOVFW",
+ argLen: 1,
+ asm: arm.AMOVFW,
+ 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, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ },
+ },
+ {
+ name: "MOVDW",
+ argLen: 1,
+ asm: arm.AMOVDW,
+ 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, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ },
+ },
+ {
+ name: "MOVFWU",
+ argLen: 1,
+ asm: arm.AMOVFW,
+ 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, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ },
+ },
+ {
+ name: "MOVDWU",
+ argLen: 1,
+ asm: arm.AMOVDW,
+ 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, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ },
+ },
+ {
+ name: "MOVFD",
+ argLen: 1,
+ asm: arm.AMOVFD,
+ 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: "MOVDF",
+ argLen: 1,
+ asm: arm.AMOVDF,
+ 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: "CMOVWHSconst",
+ auxType: auxInt32,
+ argLen: 2,
+ resultInArg0: true,
+ asm: arm.AMOVW,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ },
+ },
+ {
+ name: "CMOVWLSconst",
+ auxType: auxInt32,
+ argLen: 2,
+ resultInArg0: true,
+ asm: arm.AMOVW,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ },
+ },
+ {
+ name: "SRAcond",
+ argLen: 3,
+ asm: arm.ASRA,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {1, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ },
+ },
+ {
+ name: "CALLstatic",
+ auxType: auxSymOff,
+ 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: "CALLclosure",
+ auxType: auxInt64,
+ argLen: 3,
+ clobberFlags: true,
+ call: true,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 128}, // R7
+ {0, 29695}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 SP R14
+ },
+ 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: "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,
+ clobberFlags: true,
+ call: true,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ 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: "LoweredNilCheck",
+ argLen: 2,
+ nilCheck: true,
+ faultOnNilArg0: true,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 22527}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 R14
+ },
+ },
+ },
+ {
+ name: "Equal",
+ argLen: 1,
+ reg: regInfo{
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ },
+ },
+ {
+ name: "NotEqual",
+ argLen: 1,
+ reg: regInfo{
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ },
+ },
+ {
+ name: "LessThan",
+ argLen: 1,
+ reg: regInfo{
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ },
+ },
+ {
+ name: "LessEqual",
+ argLen: 1,
+ reg: regInfo{
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ },
+ },
+ {
+ name: "GreaterThan",
+ argLen: 1,
+ reg: regInfo{
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ },
+ },
+ {
+ name: "GreaterEqual",
+ argLen: 1,
+ reg: regInfo{
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ },
+ },
+ {
+ name: "LessThanU",
+ argLen: 1,
+ reg: regInfo{
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ },
+ },
+ {
+ name: "LessEqualU",
+ argLen: 1,
+ reg: regInfo{
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ },
+ },
+ {
+ name: "GreaterThanU",
+ argLen: 1,
+ reg: regInfo{
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ },
+ },
+ {
+ name: "GreaterEqualU",
+ argLen: 1,
+ reg: regInfo{
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ },
+ },
+ {
+ name: "DUFFZERO",
+ auxType: auxInt64,
+ argLen: 3,
+ faultOnNilArg0: true,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 2}, // R1
+ {1, 1}, // R0
+ },
+ clobbers: 16386, // R1 R14
+ },
+ },
+ {
+ name: "DUFFCOPY",
+ auxType: auxInt64,
+ argLen: 3,
+ faultOnNilArg0: true,
+ faultOnNilArg1: true,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 4}, // R2
+ {1, 2}, // R1
+ },
+ clobbers: 16391, // R0 R1 R2 R14
+ },
+ },
+ {
+ name: "LoweredZero",
+ auxType: auxInt64,
+ argLen: 4,
+ clobberFlags: true,
+ faultOnNilArg0: true,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 2}, // R1
+ {1, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {2, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ clobbers: 2, // R1
+ },
+ },
+ {
+ name: "LoweredMove",
+ auxType: auxInt64,
+ argLen: 4,
+ clobberFlags: true,
+ faultOnNilArg0: true,
+ faultOnNilArg1: true,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 4}, // R2
+ {1, 2}, // R1
+ {2, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ clobbers: 6, // R1 R2
+ },
+ },
+ {
+ name: "LoweredGetClosurePtr",
+ argLen: 0,
+ reg: regInfo{
+ outputs: []outputInfo{
+ {0, 128}, // R7
+ },
+ },
+ },
+ {
+ name: "MOVWconvert",
+ argLen: 2,
+ asm: arm.AMOVW,
+ 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: "FlagEQ",
+ argLen: 0,
+ reg: regInfo{},
+ },
+ {
+ name: "FlagLT_ULT",
+ argLen: 0,
+ reg: regInfo{},
+ },
+ {
+ name: "FlagLT_UGT",
+ argLen: 0,
+ reg: regInfo{},
+ },
+ {
+ name: "FlagGT_UGT",
+ argLen: 0,
+ reg: regInfo{},
+ },
+ {
+ name: "FlagGT_ULT",
+ argLen: 0,
+ reg: regInfo{},
+ },
+ {
+ name: "InvertFlags",
+ argLen: 1,
+ reg: regInfo{},
+ },
+
+ {
+ name: "ADD",
+ argLen: 2,
+ commutative: true,
+ asm: arm64.AADD,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 805044223}, // 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
+ {1, 805044223}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ },
+ },
+ {
+ name: "ADDconst",
+ auxType: auxInt64,
+ argLen: 1,
+ asm: arm64.AADD,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 1878786047}, // 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 SP
+ },
+ outputs: []outputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ },
+ },
+ {
+ name: "SUB",
+ argLen: 2,
+ asm: arm64.ASUB,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 805044223}, // 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
+ {1, 805044223}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ },
+ },
+ {
+ name: "SUBconst",
+ auxType: auxInt64,
+ argLen: 1,
+ asm: arm64.ASUB,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 805044223}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ },
+ },
+ {
+ name: "MUL",
+ argLen: 2,
+ commutative: true,
+ asm: arm64.AMUL,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 805044223}, // 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
+ {1, 805044223}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ },
+ },
+ {
+ name: "MULW",
+ argLen: 2,
+ commutative: true,
+ asm: arm64.AMULW,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 805044223}, // 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
+ {1, 805044223}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ },
+ },
+ {
+ name: "MULH",
+ argLen: 2,
+ commutative: true,
+ asm: arm64.ASMULH,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 805044223}, // 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
+ {1, 805044223}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ },
+ },
+ {
+ name: "UMULH",
+ argLen: 2,
+ commutative: true,
+ asm: arm64.AUMULH,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 805044223}, // 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
+ {1, 805044223}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ },
+ },
+ {
+ name: "MULL",
+ argLen: 2,
+ commutative: true,
+ asm: arm64.ASMULL,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 805044223}, // 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
+ {1, 805044223}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ },
+ },
+ {
+ name: "UMULL",
+ argLen: 2,
+ commutative: true,
+ asm: arm64.AUMULL,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 805044223}, // 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
+ {1, 805044223}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ },
+ },
+ {
+ name: "DIV",
+ argLen: 2,
+ asm: arm64.ASDIV,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 805044223}, // 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
+ {1, 805044223}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ },
+ },
+ {
+ name: "UDIV",
+ argLen: 2,
+ asm: arm64.AUDIV,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 805044223}, // 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
+ {1, 805044223}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ },
+ },
+ {
+ name: "DIVW",
+ argLen: 2,
+ asm: arm64.ASDIVW,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 805044223}, // 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
+ {1, 805044223}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ },
+ },
+ {
+ name: "UDIVW",
+ argLen: 2,
+ asm: arm64.AUDIVW,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 805044223}, // 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
+ {1, 805044223}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ },
+ },
+ {
+ name: "MOD",
+ argLen: 2,
+ asm: arm64.AREM,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 805044223}, // 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
+ {1, 805044223}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ },
+ },
+ {
+ name: "UMOD",
+ argLen: 2,
+ asm: arm64.AUREM,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 805044223}, // 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
+ {1, 805044223}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ },
+ },
+ {
+ name: "MODW",
+ argLen: 2,
+ asm: arm64.AREMW,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 805044223}, // 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
+ {1, 805044223}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ },
+ },
+ {
+ name: "UMODW",
+ argLen: 2,
+ asm: arm64.AUREMW,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 805044223}, // 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
+ {1, 805044223}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ },
+ },
+ {
+ name: "FADDS",
+ argLen: 2,
+ commutative: true,
+ asm: arm64.AFADDS,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 9223372034707292160}, // 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
+ {1, 9223372034707292160}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 9223372034707292160}, // 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: "FADDD",
+ argLen: 2,
+ commutative: true,
+ asm: arm64.AFADDD,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 9223372034707292160}, // 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
+ {1, 9223372034707292160}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 9223372034707292160}, // 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: "FSUBS",
+ argLen: 2,
+ asm: arm64.AFSUBS,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 9223372034707292160}, // 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
+ {1, 9223372034707292160}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 9223372034707292160}, // 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: "FSUBD",
+ argLen: 2,
+ asm: arm64.AFSUBD,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 9223372034707292160}, // 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
+ {1, 9223372034707292160}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 9223372034707292160}, // 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: "FMULS",
+ argLen: 2,
+ commutative: true,
+ asm: arm64.AFMULS,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 9223372034707292160}, // 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
+ {1, 9223372034707292160}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 9223372034707292160}, // 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: "FMULD",
+ argLen: 2,
+ commutative: true,
+ asm: arm64.AFMULD,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 9223372034707292160}, // 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
+ {1, 9223372034707292160}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 9223372034707292160}, // 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: "FDIVS",
+ argLen: 2,
+ asm: arm64.AFDIVS,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 9223372034707292160}, // 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
+ {1, 9223372034707292160}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 9223372034707292160}, // 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: "FDIVD",
+ argLen: 2,
+ asm: arm64.AFDIVD,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 9223372034707292160}, // 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
+ {1, 9223372034707292160}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 9223372034707292160}, // 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: "AND",
+ argLen: 2,
+ commutative: true,
+ asm: arm64.AAND,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 805044223}, // 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
+ {1, 805044223}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ },
+ },
+ {
+ name: "ANDconst",
+ auxType: auxInt64,
+ argLen: 1,
+ asm: arm64.AAND,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 805044223}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ },
+ },
+ {
+ name: "OR",
+ argLen: 2,
+ commutative: true,
+ asm: arm64.AORR,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 805044223}, // 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
+ {1, 805044223}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ },
+ },
+ {
+ name: "ORconst",
+ auxType: auxInt64,
+ argLen: 1,
+ asm: arm64.AORR,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 805044223}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ },
+ },
+ {
+ name: "XOR",
+ argLen: 2,
+ commutative: true,
+ asm: arm64.AEOR,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 805044223}, // 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
+ {1, 805044223}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ },
+ },
+ {
+ name: "XORconst",
+ auxType: auxInt64,
+ argLen: 1,
+ asm: arm64.AEOR,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 805044223}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ },
+ },
+ {
+ name: "BIC",
+ argLen: 2,
+ asm: arm64.ABIC,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 805044223}, // 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
+ {1, 805044223}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ },
+ },
+ {
+ name: "BICconst",
+ auxType: auxInt64,
+ argLen: 1,
+ asm: arm64.ABIC,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 805044223}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ },
+ },
+ {
+ name: "MVN",
+ argLen: 1,
+ asm: arm64.AMVN,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 805044223}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ },
+ },
+ {
+ name: "NEG",
+ argLen: 1,
+ asm: arm64.ANEG,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 805044223}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ },
+ },
+ {
+ name: "FNEGS",
+ argLen: 1,
+ asm: arm64.AFNEGS,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 9223372034707292160}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 9223372034707292160}, // 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: "FNEGD",
+ argLen: 1,
+ asm: arm64.AFNEGD,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 9223372034707292160}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 9223372034707292160}, // 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: "FSQRTD",
+ argLen: 1,
+ asm: arm64.AFSQRTD,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 9223372034707292160}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 9223372034707292160}, // 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: "REV",
+ argLen: 1,
+ asm: arm64.AREV,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 805044223}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ },
+ },
+ {
+ name: "REVW",
+ argLen: 1,
+ asm: arm64.AREVW,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 805044223}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ },
+ },
+ {
+ name: "REV16W",
+ argLen: 1,
+ asm: arm64.AREV16W,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 805044223}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ },
+ },
+ {
+ name: "RBIT",
+ argLen: 1,
+ asm: arm64.ARBIT,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 805044223}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ },
+ },
+ {
+ name: "RBITW",
+ argLen: 1,
+ asm: arm64.ARBITW,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 805044223}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ },
+ },
+ {
+ name: "CLZ",
+ argLen: 1,
+ asm: arm64.ACLZ,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 805044223}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ },
+ },
+ {
+ name: "CLZW",
+ argLen: 1,
+ asm: arm64.ACLZW,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 805044223}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ },
+ },
+ {
+ name: "SLL",
+ argLen: 2,
+ asm: arm64.ALSL,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 805044223}, // 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
+ {1, 805044223}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ },
+ },
+ {
+ name: "SLLconst",
+ auxType: auxInt64,
+ argLen: 1,
+ asm: arm64.ALSL,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 805044223}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ },
+ },
+ {
+ name: "SRL",
+ argLen: 2,
+ asm: arm64.ALSR,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 805044223}, // 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
+ {1, 805044223}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ },
+ },
+ {
+ name: "SRLconst",
+ auxType: auxInt64,
+ argLen: 1,
+ asm: arm64.ALSR,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 805044223}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ },
+ },
+ {
+ name: "SRA",
+ argLen: 2,
+ asm: arm64.AASR,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 805044223}, // 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
+ {1, 805044223}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ },
+ },
+ {
+ name: "SRAconst",
+ auxType: auxInt64,
+ argLen: 1,
+ asm: arm64.AASR,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 805044223}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ },
+ },
+ {
+ name: "RORconst",
+ auxType: auxInt64,
+ argLen: 1,
+ asm: arm64.AROR,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 805044223}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ },
+ },
+ {
+ name: "RORWconst",
+ auxType: auxInt64,
+ argLen: 1,
+ asm: arm64.ARORW,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 805044223}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ },
+ },
+ {
+ name: "CMP",
+ argLen: 2,
+ asm: arm64.ACMP,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 805044223}, // 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
+ {1, 805044223}, // 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
+ },
+ },
+ },
+ {
+ name: "CMPconst",
+ auxType: auxInt64,
+ argLen: 1,
+ asm: arm64.ACMP,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 805044223}, // 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
+ },
+ },
+ },
+ {
+ name: "CMPW",
+ argLen: 2,
+ asm: arm64.ACMPW,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 805044223}, // 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
+ {1, 805044223}, // 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
+ },
+ },
+ },
+ {
+ name: "CMPWconst",
+ auxType: auxInt32,
+ argLen: 1,
+ asm: arm64.ACMPW,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 805044223}, // 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
+ },
+ },
+ },
+ {
+ name: "CMN",
+ argLen: 2,
+ asm: arm64.ACMN,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 805044223}, // 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
+ {1, 805044223}, // 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
+ },
+ },
+ },
+ {
+ name: "CMNconst",
+ auxType: auxInt64,
+ argLen: 1,
+ asm: arm64.ACMN,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 805044223}, // 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
+ },
+ },
+ },
+ {
+ name: "CMNW",
+ argLen: 2,
+ asm: arm64.ACMNW,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 805044223}, // 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
+ {1, 805044223}, // 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
+ },
+ },
+ },
+ {
+ name: "CMNWconst",
+ auxType: auxInt32,
+ argLen: 1,
+ asm: arm64.ACMNW,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 805044223}, // 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
+ },
+ },
+ },
+ {
+ name: "FCMPS",
+ argLen: 2,
+ asm: arm64.AFCMPS,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 9223372034707292160}, // 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
+ {1, 9223372034707292160}, // 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: "FCMPD",
+ argLen: 2,
+ asm: arm64.AFCMPD,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 9223372034707292160}, // 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
+ {1, 9223372034707292160}, // 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: "ADDshiftLL",
+ auxType: auxInt64,
+ argLen: 2,
+ asm: arm64.AADD,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 805044223}, // 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
+ {1, 805044223}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ },
+ },
+ {
+ name: "ADDshiftRL",
+ auxType: auxInt64,
+ argLen: 2,
+ asm: arm64.AADD,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 805044223}, // 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
+ {1, 805044223}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ },
+ },
+ {
+ name: "ADDshiftRA",
+ auxType: auxInt64,
+ argLen: 2,
+ asm: arm64.AADD,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 805044223}, // 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
+ {1, 805044223}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ },
+ },
+ {
+ name: "SUBshiftLL",
+ auxType: auxInt64,
+ argLen: 2,
+ asm: arm64.ASUB,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 805044223}, // 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
+ {1, 805044223}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ },
+ },
+ {
+ name: "SUBshiftRL",
+ auxType: auxInt64,
+ argLen: 2,
+ asm: arm64.ASUB,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 805044223}, // 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
+ {1, 805044223}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ },
+ },
+ {
+ name: "SUBshiftRA",
+ auxType: auxInt64,
+ argLen: 2,
+ asm: arm64.ASUB,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 805044223}, // 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
+ {1, 805044223}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ },
+ },
+ {
+ name: "ANDshiftLL",
+ auxType: auxInt64,
+ argLen: 2,
+ asm: arm64.AAND,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 805044223}, // 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
+ {1, 805044223}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ },
+ },
+ {
+ name: "ANDshiftRL",
+ auxType: auxInt64,
+ argLen: 2,
+ asm: arm64.AAND,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 805044223}, // 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
+ {1, 805044223}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ },
+ },
+ {
+ name: "ANDshiftRA",
+ auxType: auxInt64,
+ argLen: 2,
+ asm: arm64.AAND,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 805044223}, // 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
+ {1, 805044223}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ },
+ },
+ {
+ name: "ORshiftLL",
+ auxType: auxInt64,
+ argLen: 2,
+ asm: arm64.AORR,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 805044223}, // 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
+ {1, 805044223}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ },
+ },
+ {
+ name: "ORshiftRL",
+ auxType: auxInt64,
+ argLen: 2,
+ asm: arm64.AORR,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 805044223}, // 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
+ {1, 805044223}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ },
+ },
+ {
+ name: "ORshiftRA",
+ auxType: auxInt64,
+ argLen: 2,
+ asm: arm64.AORR,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 805044223}, // 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
+ {1, 805044223}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ },
+ },
+ {
+ name: "XORshiftLL",
+ auxType: auxInt64,
+ argLen: 2,
+ asm: arm64.AEOR,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 805044223}, // 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
+ {1, 805044223}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ },
+ },
+ {
+ name: "XORshiftRL",
+ auxType: auxInt64,
+ argLen: 2,
+ asm: arm64.AEOR,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 805044223}, // 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
+ {1, 805044223}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ },
+ },
+ {
+ name: "XORshiftRA",
+ auxType: auxInt64,
+ argLen: 2,
+ asm: arm64.AEOR,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 805044223}, // 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
+ {1, 805044223}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ },
+ },
+ {
+ name: "BICshiftLL",
+ auxType: auxInt64,
+ argLen: 2,
+ asm: arm64.ABIC,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 805044223}, // 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
+ {1, 805044223}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ },
+ },
+ {
+ name: "BICshiftRL",
+ auxType: auxInt64,
+ argLen: 2,
+ asm: arm64.ABIC,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 805044223}, // 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
+ {1, 805044223}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ },
+ },
+ {
+ name: "BICshiftRA",
+ auxType: auxInt64,
+ argLen: 2,
+ asm: arm64.ABIC,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 805044223}, // 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
+ {1, 805044223}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ },
+ },
+ {
+ name: "CMPshiftLL",
+ auxType: auxInt64,
+ argLen: 2,
+ asm: arm64.ACMP,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 805044223}, // 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
+ {1, 805044223}, // 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
+ },
+ },
+ },
+ {
+ name: "CMPshiftRL",
+ auxType: auxInt64,
+ argLen: 2,
+ asm: arm64.ACMP,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 805044223}, // 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
+ {1, 805044223}, // 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
+ },
+ },
+ },
+ {
+ name: "CMPshiftRA",
+ auxType: auxInt64,
+ argLen: 2,
+ asm: arm64.ACMP,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 805044223}, // 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
+ {1, 805044223}, // 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
+ },
+ },
+ },
+ {
+ name: "MOVDconst",
+ auxType: auxInt64,
+ argLen: 0,
+ rematerializeable: true,
+ asm: arm64.AMOVD,
+ reg: regInfo{
+ outputs: []outputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ },
+ },
+ {
+ name: "FMOVSconst",
+ auxType: auxFloat64,
+ argLen: 0,
+ rematerializeable: true,
+ asm: arm64.AFMOVS,
+ reg: regInfo{
+ outputs: []outputInfo{
+ {0, 9223372034707292160}, // 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: "FMOVDconst",
+ auxType: auxFloat64,
+ argLen: 0,
+ rematerializeable: true,
+ asm: arm64.AFMOVD,
+ reg: regInfo{
+ outputs: []outputInfo{
+ {0, 9223372034707292160}, // 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: "MOVDaddr",
+ auxType: auxSymOff,
+ argLen: 1,
+ rematerializeable: true,
+ asm: arm64.AMOVD,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 9223372037928517632}, // SP SB
+ },
+ outputs: []outputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ },
+ },
+ {
+ name: "MOVBload",
+ auxType: auxSymOff,
+ argLen: 2,
+ faultOnNilArg0: true,
+ asm: arm64.AMOVB,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 9223372038733561855}, // 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 SP SB
+ },
+ outputs: []outputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ },
+ },
+ {
+ name: "MOVBUload",
+ auxType: auxSymOff,
+ argLen: 2,
+ faultOnNilArg0: true,
+ asm: arm64.AMOVBU,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 9223372038733561855}, // 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 SP SB
+ },
+ outputs: []outputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ },
+ },
+ {
+ name: "MOVHload",
+ auxType: auxSymOff,
+ argLen: 2,
+ faultOnNilArg0: true,
+ asm: arm64.AMOVH,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 9223372038733561855}, // 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 SP SB
+ },
+ outputs: []outputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ },
+ },
+ {
+ name: "MOVHUload",
+ auxType: auxSymOff,
+ argLen: 2,
+ faultOnNilArg0: true,
+ asm: arm64.AMOVHU,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 9223372038733561855}, // 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 SP SB
+ },
+ outputs: []outputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ },
+ },
+ {
+ name: "MOVWload",
+ auxType: auxSymOff,
+ argLen: 2,
+ faultOnNilArg0: true,
+ asm: arm64.AMOVW,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 9223372038733561855}, // 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 SP SB
+ },
+ outputs: []outputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ },
+ },
+ {
+ name: "MOVWUload",
+ auxType: auxSymOff,
+ argLen: 2,
+ faultOnNilArg0: true,
+ asm: arm64.AMOVWU,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 9223372038733561855}, // 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 SP SB
+ },
+ outputs: []outputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ },
+ },
+ {
+ name: "MOVDload",
+ auxType: auxSymOff,
+ argLen: 2,
+ faultOnNilArg0: true,
+ asm: arm64.AMOVD,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 9223372038733561855}, // 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 SP SB
+ },
+ outputs: []outputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ },
+ },
+ {
+ name: "FMOVSload",
+ auxType: auxSymOff,
+ argLen: 2,
+ faultOnNilArg0: true,
+ asm: arm64.AFMOVS,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 9223372038733561855}, // 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 SP SB
+ },
+ outputs: []outputInfo{
+ {0, 9223372034707292160}, // 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: "FMOVDload",
+ auxType: auxSymOff,
+ argLen: 2,
+ faultOnNilArg0: true,
+ asm: arm64.AFMOVD,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 9223372038733561855}, // 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 SP SB
+ },
+ outputs: []outputInfo{
+ {0, 9223372034707292160}, // 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: "MOVBstore",
+ auxType: auxSymOff,
+ argLen: 3,
+ faultOnNilArg0: true,
+ asm: arm64.AMOVB,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 805044223}, // 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
+ {0, 9223372038733561855}, // 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 SP SB
+ },
+ },
+ },
+ {
+ name: "MOVHstore",
+ auxType: auxSymOff,
+ argLen: 3,
+ faultOnNilArg0: true,
+ asm: arm64.AMOVH,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 805044223}, // 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
+ {0, 9223372038733561855}, // 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 SP SB
+ },
+ },
+ },
+ {
+ name: "MOVWstore",
+ auxType: auxSymOff,
+ argLen: 3,
+ faultOnNilArg0: true,
+ asm: arm64.AMOVW,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 805044223}, // 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
+ {0, 9223372038733561855}, // 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 SP SB
+ },
+ },
+ },
+ {
+ name: "MOVDstore",
+ auxType: auxSymOff,
+ argLen: 3,
+ faultOnNilArg0: true,
+ asm: arm64.AMOVD,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 805044223}, // 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
+ {0, 9223372038733561855}, // 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 SP SB
+ },
+ },
+ },
+ {
+ name: "FMOVSstore",
+ auxType: auxSymOff,
+ argLen: 3,
+ faultOnNilArg0: true,
+ asm: arm64.AFMOVS,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 9223372038733561855}, // 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 SP SB
+ {1, 9223372034707292160}, // 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: "FMOVDstore",
+ auxType: auxSymOff,
+ argLen: 3,
+ faultOnNilArg0: true,
+ asm: arm64.AFMOVD,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 9223372038733561855}, // 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 SP SB
+ {1, 9223372034707292160}, // 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: "MOVBstorezero",
+ auxType: auxSymOff,
+ argLen: 2,
+ faultOnNilArg0: true,
+ asm: arm64.AMOVB,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 9223372038733561855}, // 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 SP SB
+ },
+ },
+ },
+ {
+ name: "MOVHstorezero",
+ auxType: auxSymOff,
+ argLen: 2,
+ faultOnNilArg0: true,
+ asm: arm64.AMOVH,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 9223372038733561855}, // 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 SP SB
+ },
+ },
+ },
+ {
+ name: "MOVWstorezero",
+ auxType: auxSymOff,
+ argLen: 2,
+ faultOnNilArg0: true,
+ asm: arm64.AMOVW,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 9223372038733561855}, // 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 SP SB
+ },
+ },
+ },
+ {
+ name: "MOVDstorezero",
+ auxType: auxSymOff,
+ argLen: 2,
+ faultOnNilArg0: true,
+ asm: arm64.AMOVD,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 9223372038733561855}, // 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 SP SB
+ },
+ },
+ },
+ {
+ name: "MOVBreg",
+ argLen: 1,
+ asm: arm64.AMOVB,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 805044223}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ },
+ },
+ {
+ name: "MOVBUreg",
+ argLen: 1,
+ asm: arm64.AMOVBU,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 805044223}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ },
+ },
+ {
+ name: "MOVHreg",
+ argLen: 1,
+ asm: arm64.AMOVH,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 805044223}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ },
+ },
+ {
+ name: "MOVHUreg",
+ argLen: 1,
+ asm: arm64.AMOVHU,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 805044223}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ },
+ },
+ {
+ name: "MOVWreg",
+ argLen: 1,
+ asm: arm64.AMOVW,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 805044223}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ },
+ },
+ {
+ name: "MOVWUreg",
+ argLen: 1,
+ asm: arm64.AMOVWU,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 805044223}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ },
+ },
+ {
+ name: "MOVDreg",
+ argLen: 1,
+ asm: arm64.AMOVD,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 805044223}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ },
+ },
+ {
+ name: "MOVDnop",
+ argLen: 1,
+ resultInArg0: true,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ outputs: []outputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ },
+ },
+ {
+ name: "SCVTFWS",
+ argLen: 1,
+ asm: arm64.ASCVTFWS,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ outputs: []outputInfo{
+ {0, 9223372034707292160}, // 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: "SCVTFWD",
+ argLen: 1,
+ asm: arm64.ASCVTFWD,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ outputs: []outputInfo{
+ {0, 9223372034707292160}, // 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: "UCVTFWS",
+ argLen: 1,
+ asm: arm64.AUCVTFWS,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ outputs: []outputInfo{
+ {0, 9223372034707292160}, // 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: "UCVTFWD",
+ argLen: 1,
+ asm: arm64.AUCVTFWD,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ outputs: []outputInfo{
+ {0, 9223372034707292160}, // 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: "SCVTFS",
+ argLen: 1,
+ asm: arm64.ASCVTFS,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ outputs: []outputInfo{
+ {0, 9223372034707292160}, // 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: "SCVTFD",
+ argLen: 1,
+ asm: arm64.ASCVTFD,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ outputs: []outputInfo{
+ {0, 9223372034707292160}, // 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: "UCVTFS",
+ argLen: 1,
+ asm: arm64.AUCVTFS,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ outputs: []outputInfo{
+ {0, 9223372034707292160}, // 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: "UCVTFD",
+ argLen: 1,
+ asm: arm64.AUCVTFD,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ outputs: []outputInfo{
+ {0, 9223372034707292160}, // 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: "FCVTZSSW",
+ argLen: 1,
+ asm: arm64.AFCVTZSSW,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 9223372034707292160}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ },
+ },
+ {
+ name: "FCVTZSDW",
+ argLen: 1,
+ asm: arm64.AFCVTZSDW,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 9223372034707292160}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ },
+ },
+ {
+ name: "FCVTZUSW",
+ argLen: 1,
+ asm: arm64.AFCVTZUSW,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 9223372034707292160}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ },
+ },
+ {
+ name: "FCVTZUDW",
+ argLen: 1,
+ asm: arm64.AFCVTZUDW,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 9223372034707292160}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ },
+ },
+ {
+ name: "FCVTZSS",
+ argLen: 1,
+ asm: arm64.AFCVTZSS,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 9223372034707292160}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ },
+ },
+ {
+ name: "FCVTZSD",
+ argLen: 1,
+ asm: arm64.AFCVTZSD,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 9223372034707292160}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ },
+ },
+ {
+ name: "FCVTZUS",
+ argLen: 1,
+ asm: arm64.AFCVTZUS,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 9223372034707292160}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ },
+ },
+ {
+ name: "FCVTZUD",
+ argLen: 1,
+ asm: arm64.AFCVTZUD,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 9223372034707292160}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ },
+ },
+ {
+ name: "FCVTSD",
+ argLen: 1,
+ asm: arm64.AFCVTSD,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 9223372034707292160}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 9223372034707292160}, // 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: "FCVTDS",
+ argLen: 1,
+ asm: arm64.AFCVTDS,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 9223372034707292160}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 9223372034707292160}, // 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: "CSELULT",
+ argLen: 3,
+ asm: arm64.ACSEL,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 670826495}, // 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 R30
+ {1, 670826495}, // 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 R30
+ },
+ outputs: []outputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ },
+ },
+ {
+ name: "CSELULT0",
+ argLen: 2,
+ asm: arm64.ACSEL,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 805044223}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ },
+ },
+ {
+ name: "CALLstatic",
+ auxType: auxSymOff,
+ 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: "CALLclosure",
+ auxType: auxInt64,
+ argLen: 3,
+ clobberFlags: true,
+ call: true,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 67108864}, // R26
+ {0, 1744568319}, // 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 R30 SP
+ },
+ 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: "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,
+ clobberFlags: true,
+ call: true,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ 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: "LoweredNilCheck",
+ argLen: 2,
+ nilCheck: true,
+ faultOnNilArg0: true,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 805044223}, // 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
+ },
+ },
+ },
+ {
+ name: "Equal",
+ argLen: 1,
+ reg: regInfo{
+ outputs: []outputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ },
+ },
+ {
+ name: "NotEqual",
+ argLen: 1,
+ reg: regInfo{
+ outputs: []outputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ },
+ },
+ {
+ name: "LessThan",
+ argLen: 1,
+ reg: regInfo{
+ outputs: []outputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ },
+ },
+ {
+ name: "LessEqual",
+ argLen: 1,
+ reg: regInfo{
+ outputs: []outputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ },
+ },
+ {
+ name: "GreaterThan",
+ argLen: 1,
+ reg: regInfo{
+ outputs: []outputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ },
+ },
+ {
+ name: "GreaterEqual",
+ argLen: 1,
+ reg: regInfo{
+ outputs: []outputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ },
+ },
+ {
+ name: "LessThanU",
+ argLen: 1,
+ reg: regInfo{
+ outputs: []outputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ },
+ },
+ {
+ name: "LessEqualU",
+ argLen: 1,
+ reg: regInfo{
+ outputs: []outputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ },
+ },
+ {
+ name: "GreaterThanU",
+ argLen: 1,
+ reg: regInfo{
+ outputs: []outputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ },
+ },
+ {
+ name: "GreaterEqualU",
+ argLen: 1,
+ reg: regInfo{
+ outputs: []outputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ },
+ },
+ {
+ name: "DUFFZERO",
+ auxType: auxInt64,
+ argLen: 2,
+ faultOnNilArg0: true,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ clobbers: 536936448, // R16 R30
+ },
+ },
+ {
+ name: "LoweredZero",
+ argLen: 3,
+ clobberFlags: true,
+ faultOnNilArg0: true,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 65536}, // R16
+ {1, 670826495}, // 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 R30
+ },
+ clobbers: 65536, // R16
+ },
+ },
+ {
+ name: "DUFFCOPY",
+ auxType: auxInt64,
+ argLen: 3,
+ faultOnNilArg0: true,
+ faultOnNilArg1: true,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 131072}, // R17
+ {1, 65536}, // R16
+ },
+ clobbers: 537067520, // R16 R17 R30
+ },
+ },
+ {
+ name: "LoweredMove",
+ argLen: 4,
+ clobberFlags: true,
+ faultOnNilArg0: true,
+ faultOnNilArg1: true,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 131072}, // R17
+ {1, 65536}, // R16
+ {2, 670826495}, // 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 R30
+ },
+ clobbers: 196608, // R16 R17
+ },
+ },
+ {
+ name: "LoweredGetClosurePtr",
+ argLen: 0,
+ reg: regInfo{
+ outputs: []outputInfo{
+ {0, 67108864}, // R26
+ },
+ },
+ },
+ {
+ name: "MOVDconvert",
+ argLen: 2,
+ asm: arm64.AMOVD,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 805044223}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ },
+ },
+ {
+ name: "FlagEQ",
+ argLen: 0,
+ reg: regInfo{},
+ },
+ {
+ name: "FlagLT_ULT",
+ argLen: 0,
+ reg: regInfo{},
+ },
+ {
+ name: "FlagLT_UGT",
+ argLen: 0,
+ reg: regInfo{},
+ },
+ {
+ name: "FlagGT_UGT",
+ argLen: 0,
+ reg: regInfo{},
+ },
+ {
+ name: "FlagGT_ULT",
+ argLen: 0,
+ reg: regInfo{},
+ },
+ {
+ name: "InvertFlags",
+ argLen: 1,
+ reg: regInfo{},
+ },
+ {
+ name: "LDAR",
+ argLen: 2,
+ faultOnNilArg0: true,
+ asm: arm64.ALDAR,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 9223372038733561855}, // 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 SP SB
+ },
+ outputs: []outputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ },
+ },
+ {
+ name: "LDARW",
+ argLen: 2,
+ faultOnNilArg0: true,
+ asm: arm64.ALDARW,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 9223372038733561855}, // 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 SP SB
+ },
+ outputs: []outputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ },
+ },
+ {
+ name: "STLR",
+ argLen: 3,
+ faultOnNilArg0: true,
+ asm: arm64.ASTLR,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 805044223}, // 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
+ {0, 9223372038733561855}, // 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 SP SB
+ },
+ },
+ },
+ {
+ name: "STLRW",
+ argLen: 3,
+ faultOnNilArg0: true,
+ asm: arm64.ASTLRW,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 805044223}, // 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
+ {0, 9223372038733561855}, // 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 SP SB
+ },
+ },
+ },
+ {
+ name: "LoweredAtomicExchange64",
+ argLen: 3,
+ resultNotInArgs: true,
+ faultOnNilArg0: true,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 805044223}, // 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
+ {0, 9223372038733561855}, // 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 SP SB
+ },
+ outputs: []outputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ },
+ },
+ {
+ name: "LoweredAtomicExchange32",
+ argLen: 3,
+ resultNotInArgs: true,
+ faultOnNilArg0: true,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 805044223}, // 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
+ {0, 9223372038733561855}, // 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 SP SB
+ },
+ outputs: []outputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ },
+ },
+ {
+ name: "LoweredAtomicAdd64",
+ argLen: 3,
+ resultNotInArgs: true,
+ faultOnNilArg0: true,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 805044223}, // 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
+ {0, 9223372038733561855}, // 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 SP SB
+ },
+ outputs: []outputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ },
+ },
+ {
+ name: "LoweredAtomicAdd32",
+ argLen: 3,
+ resultNotInArgs: true,
+ faultOnNilArg0: true,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 805044223}, // 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
+ {0, 9223372038733561855}, // 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 SP SB
+ },
+ outputs: []outputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ },
+ },
+ {
+ name: "LoweredAtomicCas64",
+ argLen: 4,
+ resultNotInArgs: true,
+ clobberFlags: true,
+ faultOnNilArg0: true,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 805044223}, // 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
+ {2, 805044223}, // 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
+ {0, 9223372038733561855}, // 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 SP SB
+ },
+ outputs: []outputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ },
+ },
+ {
+ name: "LoweredAtomicCas32",
+ argLen: 4,
+ resultNotInArgs: true,
+ clobberFlags: true,
+ faultOnNilArg0: true,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 805044223}, // 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
+ {2, 805044223}, // 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
+ {0, 9223372038733561855}, // 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 SP SB
+ },
+ outputs: []outputInfo{
+ {0, 670826495}, // 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 R30
+ },
+ },
+ },
+ {
+ name: "LoweredAtomicAnd8",
+ argLen: 3,
+ faultOnNilArg0: true,
+ asm: arm64.AAND,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 805044223}, // 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
+ {0, 9223372038733561855}, // 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 SP SB
+ },
+ },
+ },
+ {
+ name: "LoweredAtomicOr8",
+ argLen: 3,
+ faultOnNilArg0: true,
+ asm: arm64.AORR,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 805044223}, // 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
+ {0, 9223372038733561855}, // 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 SP SB
+ },
+ },
+ },
+
+ {
+ name: "ADD",
+ argLen: 2,
+ commutative: true,
+ asm: mips.AADDU,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 469762046}, // 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
+ {1, 469762046}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 335544318}, // 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 R31
+ },
+ },
+ },
+ {
+ name: "ADDconst",
+ auxType: auxInt32,
+ argLen: 1,
+ asm: mips.AADDU,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 536870910}, // 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 SP g R31
+ },
+ outputs: []outputInfo{
+ {0, 335544318}, // 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 R31
+ },
+ },
+ },
+ {
+ name: "SUB",
+ argLen: 2,
+ asm: mips.ASUBU,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 469762046}, // 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
+ {1, 469762046}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 335544318}, // 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 R31
+ },
+ },
+ },
+ {
+ name: "SUBconst",
+ auxType: auxInt32,
+ argLen: 1,
+ asm: mips.ASUBU,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 469762046}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 335544318}, // 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 R31
+ },
+ },
+ },
+ {
+ name: "MUL",
+ argLen: 2,
+ commutative: true,
+ asm: mips.AMUL,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 469762046}, // 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
+ {1, 469762046}, // 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
+ },
+ clobbers: 105553116266496, // HI LO
+ outputs: []outputInfo{
+ {0, 335544318}, // 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 R31
+ },
+ },
+ },
+ {
+ name: "MULT",
+ argLen: 2,
+ commutative: true,
+ asm: mips.AMUL,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 469762046}, // 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
+ {1, 469762046}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 35184372088832}, // HI
+ {1, 70368744177664}, // LO
+ },
+ },
+ },
+ {
+ name: "MULTU",
+ argLen: 2,
+ commutative: true,
+ asm: mips.AMULU,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 469762046}, // 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
+ {1, 469762046}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 35184372088832}, // HI
+ {1, 70368744177664}, // LO
+ },
+ },
+ },
+ {
+ name: "DIV",
+ argLen: 2,
+ asm: mips.ADIV,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 469762046}, // 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
+ {1, 469762046}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 35184372088832}, // HI
+ {1, 70368744177664}, // LO
+ },
+ },
+ },
+ {
+ name: "DIVU",
+ argLen: 2,
+ asm: mips.ADIVU,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 469762046}, // 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
+ {1, 469762046}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 35184372088832}, // HI
+ {1, 70368744177664}, // LO
+ },
+ },
+ },
+ {
+ name: "ADDF",
+ argLen: 2,
+ commutative: true,
+ asm: mips.AADDF,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 35183835217920}, // F0 F2 F4 F6 F8 F10 F12 F14 F16 F18 F20 F22 F24 F26 F28 F30
+ {1, 35183835217920}, // F0 F2 F4 F6 F8 F10 F12 F14 F16 F18 F20 F22 F24 F26 F28 F30
+ },
+ outputs: []outputInfo{
+ {0, 35183835217920}, // F0 F2 F4 F6 F8 F10 F12 F14 F16 F18 F20 F22 F24 F26 F28 F30
+ },
+ },
+ },
+ {
+ name: "ADDD",
+ argLen: 2,
+ commutative: true,
+ asm: mips.AADDD,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 35183835217920}, // F0 F2 F4 F6 F8 F10 F12 F14 F16 F18 F20 F22 F24 F26 F28 F30
+ {1, 35183835217920}, // F0 F2 F4 F6 F8 F10 F12 F14 F16 F18 F20 F22 F24 F26 F28 F30
+ },
+ outputs: []outputInfo{
+ {0, 35183835217920}, // F0 F2 F4 F6 F8 F10 F12 F14 F16 F18 F20 F22 F24 F26 F28 F30
+ },
+ },
+ },
+ {
+ name: "SUBF",
+ argLen: 2,
+ asm: mips.ASUBF,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 35183835217920}, // F0 F2 F4 F6 F8 F10 F12 F14 F16 F18 F20 F22 F24 F26 F28 F30
+ {1, 35183835217920}, // F0 F2 F4 F6 F8 F10 F12 F14 F16 F18 F20 F22 F24 F26 F28 F30
+ },
+ outputs: []outputInfo{
+ {0, 35183835217920}, // F0 F2 F4 F6 F8 F10 F12 F14 F16 F18 F20 F22 F24 F26 F28 F30
+ },
+ },
+ },
+ {
+ name: "SUBD",
+ argLen: 2,
+ asm: mips.ASUBD,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 35183835217920}, // F0 F2 F4 F6 F8 F10 F12 F14 F16 F18 F20 F22 F24 F26 F28 F30
+ {1, 35183835217920}, // F0 F2 F4 F6 F8 F10 F12 F14 F16 F18 F20 F22 F24 F26 F28 F30
+ },
+ outputs: []outputInfo{
+ {0, 35183835217920}, // F0 F2 F4 F6 F8 F10 F12 F14 F16 F18 F20 F22 F24 F26 F28 F30
+ },
+ },
+ },
+ {
+ name: "MULF",
+ argLen: 2,
+ commutative: true,
+ asm: mips.AMULF,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 35183835217920}, // F0 F2 F4 F6 F8 F10 F12 F14 F16 F18 F20 F22 F24 F26 F28 F30
+ {1, 35183835217920}, // F0 F2 F4 F6 F8 F10 F12 F14 F16 F18 F20 F22 F24 F26 F28 F30
+ },
+ outputs: []outputInfo{
+ {0, 35183835217920}, // F0 F2 F4 F6 F8 F10 F12 F14 F16 F18 F20 F22 F24 F26 F28 F30
+ },
+ },
+ },
+ {
+ name: "MULD",
+ argLen: 2,
+ commutative: true,
+ asm: mips.AMULD,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 35183835217920}, // F0 F2 F4 F6 F8 F10 F12 F14 F16 F18 F20 F22 F24 F26 F28 F30
+ {1, 35183835217920}, // F0 F2 F4 F6 F8 F10 F12 F14 F16 F18 F20 F22 F24 F26 F28 F30
+ },
+ outputs: []outputInfo{
+ {0, 35183835217920}, // F0 F2 F4 F6 F8 F10 F12 F14 F16 F18 F20 F22 F24 F26 F28 F30
+ },
+ },
+ },
+ {
+ name: "DIVF",
+ argLen: 2,
+ asm: mips.ADIVF,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 35183835217920}, // F0 F2 F4 F6 F8 F10 F12 F14 F16 F18 F20 F22 F24 F26 F28 F30
+ {1, 35183835217920}, // F0 F2 F4 F6 F8 F10 F12 F14 F16 F18 F20 F22 F24 F26 F28 F30
+ },
+ outputs: []outputInfo{
+ {0, 35183835217920}, // F0 F2 F4 F6 F8 F10 F12 F14 F16 F18 F20 F22 F24 F26 F28 F30
+ },
+ },
+ },
+ {
+ name: "DIVD",
+ argLen: 2,
+ asm: mips.ADIVD,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 35183835217920}, // F0 F2 F4 F6 F8 F10 F12 F14 F16 F18 F20 F22 F24 F26 F28 F30
+ {1, 35183835217920}, // F0 F2 F4 F6 F8 F10 F12 F14 F16 F18 F20 F22 F24 F26 F28 F30
+ },
+ outputs: []outputInfo{
+ {0, 35183835217920}, // F0 F2 F4 F6 F8 F10 F12 F14 F16 F18 F20 F22 F24 F26 F28 F30
+ },
+ },
+ },
+ {
+ name: "AND",
+ argLen: 2,
+ commutative: true,
+ asm: mips.AAND,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 469762046}, // 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
+ {1, 469762046}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 335544318}, // 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 R31
+ },
+ },
+ },
+ {
+ name: "ANDconst",
+ auxType: auxInt32,
+ argLen: 1,
+ asm: mips.AAND,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 469762046}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 335544318}, // 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 R31
+ },
+ },
+ },
+ {
+ name: "OR",
+ argLen: 2,
+ commutative: true,
+ asm: mips.AOR,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 469762046}, // 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
+ {1, 469762046}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 335544318}, // 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 R31
+ },
+ },
+ },
+ {
+ name: "ORconst",
+ auxType: auxInt32,
+ argLen: 1,
+ asm: mips.AOR,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 469762046}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 335544318}, // 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 R31
+ },
+ },
+ },
+ {
+ name: "XOR",
+ argLen: 2,
+ commutative: true,
+ asm: mips.AXOR,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 469762046}, // 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
+ {1, 469762046}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 335544318}, // 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 R31
+ },
+ },
+ },
+ {
+ name: "XORconst",
+ auxType: auxInt32,
+ argLen: 1,
+ asm: mips.AXOR,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 469762046}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 335544318}, // 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 R31
+ },
+ },
+ },
+ {
+ name: "NOR",
+ argLen: 2,
+ commutative: true,
+ asm: mips.ANOR,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 469762046}, // 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
+ {1, 469762046}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 335544318}, // 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 R31
+ },
+ },
+ },
+ {
+ name: "NORconst",
+ auxType: auxInt32,
+ argLen: 1,
+ asm: mips.ANOR,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 469762046}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 335544318}, // 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 R31
+ },
+ },
+ },
+ {
+ name: "NEG",
+ argLen: 1,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 469762046}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 335544318}, // 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 R31
+ },
+ },
+ },
+ {
+ name: "NEGF",
+ argLen: 1,
+ asm: mips.ANEGF,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 35183835217920}, // F0 F2 F4 F6 F8 F10 F12 F14 F16 F18 F20 F22 F24 F26 F28 F30
+ },
+ outputs: []outputInfo{
+ {0, 35183835217920}, // F0 F2 F4 F6 F8 F10 F12 F14 F16 F18 F20 F22 F24 F26 F28 F30
+ },
+ },
+ },
+ {
+ name: "NEGD",
+ argLen: 1,
+ asm: mips.ANEGD,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 35183835217920}, // F0 F2 F4 F6 F8 F10 F12 F14 F16 F18 F20 F22 F24 F26 F28 F30
+ },
+ outputs: []outputInfo{
+ {0, 35183835217920}, // F0 F2 F4 F6 F8 F10 F12 F14 F16 F18 F20 F22 F24 F26 F28 F30
+ },
+ },
+ },
+ {
+ name: "SQRTD",
+ argLen: 1,
+ asm: mips.ASQRTD,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 35183835217920}, // F0 F2 F4 F6 F8 F10 F12 F14 F16 F18 F20 F22 F24 F26 F28 F30
+ },
+ outputs: []outputInfo{
+ {0, 35183835217920}, // F0 F2 F4 F6 F8 F10 F12 F14 F16 F18 F20 F22 F24 F26 F28 F30
+ },
+ },
+ },
+ {
+ name: "SLL",
+ argLen: 2,
+ asm: mips.ASLL,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 469762046}, // 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
+ {1, 469762046}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 335544318}, // 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 R31
+ },
+ },
+ },
+ {
+ name: "SLLconst",
+ auxType: auxInt32,
+ argLen: 1,
+ asm: mips.ASLL,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 469762046}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 335544318}, // 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 R31
+ },
+ },
+ },
+ {
+ name: "SRL",
+ argLen: 2,
+ asm: mips.ASRL,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 469762046}, // 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
+ {1, 469762046}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 335544318}, // 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 R31
+ },
+ },
+ },
+ {
+ name: "SRLconst",
+ auxType: auxInt32,
+ argLen: 1,
+ asm: mips.ASRL,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 469762046}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 335544318}, // 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 R31
+ },
+ },
+ },
+ {
+ name: "SRA",
+ argLen: 2,
+ asm: mips.ASRA,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 469762046}, // 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
+ {1, 469762046}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 335544318}, // 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 R31
+ },
+ },
+ },
+ {
+ name: "SRAconst",
+ auxType: auxInt32,
+ argLen: 1,
+ asm: mips.ASRA,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 469762046}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 335544318}, // 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 R31
+ },
+ },
+ },
+ {
+ name: "CLZ",
+ argLen: 1,
+ asm: mips.ACLZ,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 469762046}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 335544318}, // 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 R31
+ },
+ },
+ },
+ {
+ name: "SGT",
+ argLen: 2,
+ asm: mips.ASGT,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 469762046}, // 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
+ {1, 469762046}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 335544318}, // 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 R31
+ },
+ },
+ },
+ {
+ name: "SGTconst",
+ auxType: auxInt32,
+ argLen: 1,
+ asm: mips.ASGT,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 469762046}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 335544318}, // 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 R31
+ },
+ },
+ },
+ {
+ name: "SGTzero",
+ argLen: 1,
+ asm: mips.ASGT,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 469762046}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 335544318}, // 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 R31
+ },
+ },
+ },
+ {
+ name: "SGTU",
+ argLen: 2,
+ asm: mips.ASGTU,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 469762046}, // 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
+ {1, 469762046}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 335544318}, // 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 R31
+ },
+ },
+ },
+ {
+ name: "SGTUconst",
+ auxType: auxInt32,
+ argLen: 1,
+ asm: mips.ASGTU,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 469762046}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 335544318}, // 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 R31
+ },
+ },
+ },
+ {
+ name: "SGTUzero",
+ argLen: 1,
+ asm: mips.ASGTU,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 469762046}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 335544318}, // 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 R31
+ },
+ },
+ },
+ {
+ name: "CMPEQF",
+ argLen: 2,
+ asm: mips.ACMPEQF,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 35183835217920}, // F0 F2 F4 F6 F8 F10 F12 F14 F16 F18 F20 F22 F24 F26 F28 F30
+ {1, 35183835217920}, // F0 F2 F4 F6 F8 F10 F12 F14 F16 F18 F20 F22 F24 F26 F28 F30
+ },
+ },
+ },
+ {
+ name: "CMPEQD",
+ argLen: 2,
+ asm: mips.ACMPEQD,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 35183835217920}, // F0 F2 F4 F6 F8 F10 F12 F14 F16 F18 F20 F22 F24 F26 F28 F30
+ {1, 35183835217920}, // F0 F2 F4 F6 F8 F10 F12 F14 F16 F18 F20 F22 F24 F26 F28 F30
+ },
+ },
+ },
+ {
+ name: "CMPGEF",
+ argLen: 2,
+ asm: mips.ACMPGEF,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 35183835217920}, // F0 F2 F4 F6 F8 F10 F12 F14 F16 F18 F20 F22 F24 F26 F28 F30
+ {1, 35183835217920}, // F0 F2 F4 F6 F8 F10 F12 F14 F16 F18 F20 F22 F24 F26 F28 F30
+ },
+ },
+ },
+ {
+ name: "CMPGED",
+ argLen: 2,
+ asm: mips.ACMPGED,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 35183835217920}, // F0 F2 F4 F6 F8 F10 F12 F14 F16 F18 F20 F22 F24 F26 F28 F30
+ {1, 35183835217920}, // F0 F2 F4 F6 F8 F10 F12 F14 F16 F18 F20 F22 F24 F26 F28 F30
+ },
+ },
+ },
+ {
+ name: "CMPGTF",
+ argLen: 2,
+ asm: mips.ACMPGTF,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 35183835217920}, // F0 F2 F4 F6 F8 F10 F12 F14 F16 F18 F20 F22 F24 F26 F28 F30
+ {1, 35183835217920}, // F0 F2 F4 F6 F8 F10 F12 F14 F16 F18 F20 F22 F24 F26 F28 F30
+ },
+ },
+ },
+ {
+ name: "CMPGTD",
+ argLen: 2,
+ asm: mips.ACMPGTD,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 35183835217920}, // F0 F2 F4 F6 F8 F10 F12 F14 F16 F18 F20 F22 F24 F26 F28 F30
+ {1, 35183835217920}, // F0 F2 F4 F6 F8 F10 F12 F14 F16 F18 F20 F22 F24 F26 F28 F30
+ },
+ },
+ },
+ {
+ name: "MOVWconst",
+ auxType: auxInt32,
+ argLen: 0,
+ rematerializeable: true,
+ asm: mips.AMOVW,
+ reg: regInfo{
+ outputs: []outputInfo{
+ {0, 335544318}, // 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 R31
+ },
+ },
+ },
+ {
+ name: "MOVFconst",
+ auxType: auxFloat32,
+ argLen: 0,
+ rematerializeable: true,
+ asm: mips.AMOVF,
+ reg: regInfo{
+ outputs: []outputInfo{
+ {0, 35183835217920}, // F0 F2 F4 F6 F8 F10 F12 F14 F16 F18 F20 F22 F24 F26 F28 F30
+ },
+ },
+ },
+ {
+ name: "MOVDconst",
+ auxType: auxFloat64,
+ argLen: 0,
+ rematerializeable: true,
+ asm: mips.AMOVD,
+ reg: regInfo{
+ outputs: []outputInfo{
+ {0, 35183835217920}, // F0 F2 F4 F6 F8 F10 F12 F14 F16 F18 F20 F22 F24 F26 F28 F30
+ },
+ },
+ },
+ {
+ name: "MOVWaddr",
+ auxType: auxSymOff,
+ argLen: 1,
+ rematerializeable: true,
+ asm: mips.AMOVW,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 140737555464192}, // SP SB
+ },
+ outputs: []outputInfo{
+ {0, 335544318}, // 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 R31
+ },
+ },
+ },
+ {
+ name: "MOVBload",
+ auxType: auxSymOff,
+ argLen: 2,
+ faultOnNilArg0: true,
+ asm: mips.AMOVB,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 140738025226238}, // 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 SP g R31 SB
+ },
+ outputs: []outputInfo{
+ {0, 335544318}, // 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 R31
+ },
+ },
+ },
+ {
+ name: "MOVBUload",
+ auxType: auxSymOff,
+ argLen: 2,
+ faultOnNilArg0: true,
+ asm: mips.AMOVBU,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 140738025226238}, // 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 SP g R31 SB
+ },
+ outputs: []outputInfo{
+ {0, 335544318}, // 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 R31
+ },
+ },
+ },
+ {
+ name: "MOVHload",
+ auxType: auxSymOff,
+ argLen: 2,
+ faultOnNilArg0: true,
+ asm: mips.AMOVH,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 140738025226238}, // 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 SP g R31 SB
+ },
+ outputs: []outputInfo{
+ {0, 335544318}, // 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 R31
+ },
+ },
+ },
+ {
+ name: "MOVHUload",
+ auxType: auxSymOff,
+ argLen: 2,
+ faultOnNilArg0: true,
+ asm: mips.AMOVHU,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 140738025226238}, // 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 SP g R31 SB
+ },
+ outputs: []outputInfo{
+ {0, 335544318}, // 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 R31
+ },
+ },
+ },
+ {
+ name: "MOVWload",
+ auxType: auxSymOff,
+ argLen: 2,
+ faultOnNilArg0: true,
+ asm: mips.AMOVW,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 140738025226238}, // 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 SP g R31 SB
+ },
+ outputs: []outputInfo{
+ {0, 335544318}, // 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 R31
+ },
+ },
+ },
+ {
+ name: "MOVFload",
+ auxType: auxSymOff,
+ argLen: 2,
+ faultOnNilArg0: true,
+ asm: mips.AMOVF,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 140738025226238}, // 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 SP g R31 SB
+ },
+ outputs: []outputInfo{
+ {0, 35183835217920}, // F0 F2 F4 F6 F8 F10 F12 F14 F16 F18 F20 F22 F24 F26 F28 F30
+ },
+ },
+ },
+ {
+ name: "MOVDload",
+ auxType: auxSymOff,
+ argLen: 2,
+ faultOnNilArg0: true,
+ asm: mips.AMOVD,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 140738025226238}, // 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 SP g R31 SB
+ },
+ outputs: []outputInfo{
+ {0, 35183835217920}, // F0 F2 F4 F6 F8 F10 F12 F14 F16 F18 F20 F22 F24 F26 F28 F30
+ },
+ },
+ },
+ {
+ name: "MOVBstore",
+ auxType: auxSymOff,
+ argLen: 3,
+ faultOnNilArg0: true,
+ asm: mips.AMOVB,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 469762046}, // 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
+ {0, 140738025226238}, // 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 SP g R31 SB
+ },
+ },
+ },
+ {
+ name: "MOVHstore",
+ auxType: auxSymOff,
+ argLen: 3,
+ faultOnNilArg0: true,
+ asm: mips.AMOVH,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 469762046}, // 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
+ {0, 140738025226238}, // 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 SP g R31 SB
+ },
+ },
+ },
+ {
+ name: "MOVWstore",
+ auxType: auxSymOff,
+ argLen: 3,
+ faultOnNilArg0: true,
+ asm: mips.AMOVW,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 469762046}, // 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
+ {0, 140738025226238}, // 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 SP g R31 SB
+ },
+ },
+ },
+ {
+ name: "MOVFstore",
+ auxType: auxSymOff,
+ argLen: 3,
+ faultOnNilArg0: true,
+ asm: mips.AMOVF,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 35183835217920}, // F0 F2 F4 F6 F8 F10 F12 F14 F16 F18 F20 F22 F24 F26 F28 F30
+ {0, 140738025226238}, // 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 SP g R31 SB
+ },
+ },
+ },
+ {
+ name: "MOVDstore",
+ auxType: auxSymOff,
+ argLen: 3,
+ faultOnNilArg0: true,
+ asm: mips.AMOVD,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 35183835217920}, // F0 F2 F4 F6 F8 F10 F12 F14 F16 F18 F20 F22 F24 F26 F28 F30
+ {0, 140738025226238}, // 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 SP g R31 SB
+ },
+ },
+ },
+ {
+ name: "MOVBstorezero",
+ auxType: auxSymOff,
+ argLen: 2,
+ faultOnNilArg0: true,
+ asm: mips.AMOVB,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 140738025226238}, // 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 SP g R31 SB
+ },
+ },
+ },
+ {
+ name: "MOVHstorezero",
+ auxType: auxSymOff,
+ argLen: 2,
+ faultOnNilArg0: true,
+ asm: mips.AMOVH,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 140738025226238}, // 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 SP g R31 SB
+ },
+ },
+ },
+ {
+ name: "MOVWstorezero",
+ auxType: auxSymOff,
+ argLen: 2,
+ faultOnNilArg0: true,
+ asm: mips.AMOVW,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 140738025226238}, // 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 SP g R31 SB
+ },
+ },
+ },
+ {
+ name: "MOVBreg",
+ argLen: 1,
+ asm: mips.AMOVB,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 469762046}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 335544318}, // 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 R31
+ },
+ },
+ },
+ {
+ name: "MOVBUreg",
+ argLen: 1,
+ asm: mips.AMOVBU,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 469762046}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 335544318}, // 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 R31
+ },
+ },
+ },
+ {
+ name: "MOVHreg",
+ argLen: 1,
+ asm: mips.AMOVH,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 469762046}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 335544318}, // 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 R31
+ },
+ },
+ },
+ {
+ name: "MOVHUreg",
+ argLen: 1,
+ asm: mips.AMOVHU,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 469762046}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 335544318}, // 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 R31
+ },
+ },
+ },
+ {
+ name: "MOVWreg",
+ argLen: 1,
+ asm: mips.AMOVW,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 469762046}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 335544318}, // 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 R31
+ },
+ },
+ },
+ {
+ name: "MOVWnop",
+ argLen: 1,
+ resultInArg0: true,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 335544318}, // 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 R31
+ },
+ outputs: []outputInfo{
+ {0, 335544318}, // 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 R31
+ },
+ },
+ },
+ {
+ name: "CMOVZ",
+ argLen: 3,
+ resultInArg0: true,
+ asm: mips.ACMOVZ,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 335544318}, // 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 R31
+ {1, 335544318}, // 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 R31
+ {2, 335544318}, // 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 R31
+ },
+ outputs: []outputInfo{
+ {0, 335544318}, // 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 R31
+ },
+ },
+ },
+ {
+ name: "CMOVZzero",
+ argLen: 2,
+ resultInArg0: true,
+ asm: mips.ACMOVZ,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 335544318}, // 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 R31
+ {1, 469762046}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 335544318}, // 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 R31
+ },
+ },
+ },
+ {
+ name: "MOVWF",
+ argLen: 1,
+ asm: mips.AMOVWF,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 35183835217920}, // F0 F2 F4 F6 F8 F10 F12 F14 F16 F18 F20 F22 F24 F26 F28 F30
+ },
+ outputs: []outputInfo{
+ {0, 35183835217920}, // F0 F2 F4 F6 F8 F10 F12 F14 F16 F18 F20 F22 F24 F26 F28 F30
+ },
+ },
+ },
+ {
+ name: "MOVWD",
+ argLen: 1,
+ asm: mips.AMOVWD,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 35183835217920}, // F0 F2 F4 F6 F8 F10 F12 F14 F16 F18 F20 F22 F24 F26 F28 F30
+ },
+ outputs: []outputInfo{
+ {0, 35183835217920}, // F0 F2 F4 F6 F8 F10 F12 F14 F16 F18 F20 F22 F24 F26 F28 F30
+ },
+ },
+ },
+ {
+ name: "TRUNCFW",
+ argLen: 1,
+ asm: mips.ATRUNCFW,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 35183835217920}, // F0 F2 F4 F6 F8 F10 F12 F14 F16 F18 F20 F22 F24 F26 F28 F30
+ },
+ outputs: []outputInfo{
+ {0, 35183835217920}, // F0 F2 F4 F6 F8 F10 F12 F14 F16 F18 F20 F22 F24 F26 F28 F30
+ },
+ },
+ },
+ {
+ name: "TRUNCDW",
+ argLen: 1,
+ asm: mips.ATRUNCDW,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 35183835217920}, // F0 F2 F4 F6 F8 F10 F12 F14 F16 F18 F20 F22 F24 F26 F28 F30
+ },
+ outputs: []outputInfo{
+ {0, 35183835217920}, // F0 F2 F4 F6 F8 F10 F12 F14 F16 F18 F20 F22 F24 F26 F28 F30
+ },
+ },
+ },
+ {
+ name: "MOVFD",
+ argLen: 1,
+ asm: mips.AMOVFD,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 35183835217920}, // F0 F2 F4 F6 F8 F10 F12 F14 F16 F18 F20 F22 F24 F26 F28 F30
+ },
+ outputs: []outputInfo{
+ {0, 35183835217920}, // F0 F2 F4 F6 F8 F10 F12 F14 F16 F18 F20 F22 F24 F26 F28 F30
+ },
+ },
+ },
+ {
+ name: "MOVDF",
+ argLen: 1,
+ asm: mips.AMOVDF,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 35183835217920}, // F0 F2 F4 F6 F8 F10 F12 F14 F16 F18 F20 F22 F24 F26 F28 F30
+ },
+ outputs: []outputInfo{
+ {0, 35183835217920}, // F0 F2 F4 F6 F8 F10 F12 F14 F16 F18 F20 F22 F24 F26 F28 F30
+ },
+ },
+ },
+ {
+ name: "CALLstatic",
+ auxType: auxSymOff,
+ 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: "CALLclosure",
+ auxType: auxInt32,
+ argLen: 3,
+ clobberFlags: true,
+ call: true,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 4194304}, // R22
+ {0, 402653182}, // 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 SP R31
+ },
+ 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: "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,
+ argLen: 2,
+ clobberFlags: true,
+ call: true,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 335544318}, // 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 R31
+ },
+ 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: "LoweredAtomicLoad",
+ argLen: 2,
+ faultOnNilArg0: true,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 140738025226238}, // 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 SP g R31 SB
+ },
+ outputs: []outputInfo{
+ {0, 335544318}, // 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 R31
+ },
+ },
+ },
+ {
+ name: "LoweredAtomicStore",
+ argLen: 3,
+ faultOnNilArg0: true,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 469762046}, // 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
+ {0, 140738025226238}, // 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 SP g R31 SB
+ },
+ },
+ },
+ {
+ name: "LoweredAtomicStorezero",
+ argLen: 2,
+ faultOnNilArg0: true,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 140738025226238}, // 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 SP g R31 SB
+ },
+ },
+ },
+ {
+ name: "LoweredAtomicExchange",
+ argLen: 3,
+ resultNotInArgs: true,
+ faultOnNilArg0: true,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 469762046}, // 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
+ {0, 140738025226238}, // 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 SP g R31 SB
+ },
+ outputs: []outputInfo{
+ {0, 335544318}, // 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 R31
+ },
+ },
+ },
+ {
+ name: "LoweredAtomicAdd",
+ argLen: 3,
+ resultNotInArgs: true,
+ faultOnNilArg0: true,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 469762046}, // 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
+ {0, 140738025226238}, // 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 SP g R31 SB
+ },
+ outputs: []outputInfo{
+ {0, 335544318}, // 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 R31
+ },
+ },
+ },
+ {
+ name: "LoweredAtomicAddconst",
+ auxType: auxInt32,
+ argLen: 2,
+ resultNotInArgs: true,
+ faultOnNilArg0: true,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 140738025226238}, // 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 SP g R31 SB
+ },
+ outputs: []outputInfo{
+ {0, 335544318}, // 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 R31
+ },
+ },
+ },
+ {
+ name: "LoweredAtomicCas",
+ argLen: 4,
+ resultNotInArgs: true,
+ faultOnNilArg0: true,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 469762046}, // 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
+ {2, 469762046}, // 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
+ {0, 140738025226238}, // 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 SP g R31 SB
+ },
+ outputs: []outputInfo{
+ {0, 335544318}, // 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 R31
+ },
+ },
+ },
+ {
+ name: "LoweredAtomicAnd",
+ argLen: 3,
+ faultOnNilArg0: true,
+ asm: mips.AAND,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 469762046}, // 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
+ {0, 140738025226238}, // 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 SP g R31 SB
+ },
+ },
+ },
+ {
+ name: "LoweredAtomicOr",
+ argLen: 3,
+ faultOnNilArg0: true,
+ asm: mips.AOR,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 469762046}, // 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
+ {0, 140738025226238}, // 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 SP g R31 SB
+ },
+ },
+ },
+ {
+ name: "LoweredZero",
+ auxType: auxInt32,
+ argLen: 3,
+ faultOnNilArg0: true,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 2}, // R1
+ {1, 335544318}, // 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 R31
+ },
+ clobbers: 2, // R1
+ },
+ },
+ {
+ name: "LoweredMove",
+ auxType: auxInt32,
+ argLen: 4,
+ faultOnNilArg0: true,
+ faultOnNilArg1: true,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 4}, // R2
+ {1, 2}, // R1
+ {2, 335544318}, // 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 R31
+ },
+ clobbers: 6, // R1 R2
+ },
+ },
+ {
+ name: "LoweredNilCheck",
+ argLen: 2,
+ nilCheck: true,
+ faultOnNilArg0: true,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 469762046}, // 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
+ },
+ },
+ },
+ {
+ name: "FPFlagTrue",
+ argLen: 1,
+ reg: regInfo{
+ outputs: []outputInfo{
+ {0, 335544318}, // 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 R31
+ },
+ },
+ },
+ {
+ name: "FPFlagFalse",
+ argLen: 1,
+ reg: regInfo{
+ outputs: []outputInfo{
+ {0, 335544318}, // 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 R31
+ },
+ },
+ },
+ {
+ name: "LoweredGetClosurePtr",
+ argLen: 0,
+ reg: regInfo{
+ outputs: []outputInfo{
+ {0, 4194304}, // R22
+ },
+ },
+ },
+ {
+ name: "MOVWconvert",
+ argLen: 2,
+ asm: mips.AMOVW,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 469762046}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 335544318}, // 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 R31
+ },
+ },
+ },
+
+ {
+ name: "ADDV",
+ argLen: 2,
+ commutative: true,
+ asm: mips.AADDVU,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 234881022}, // 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
+ {1, 234881022}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 167772158}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R22 R24 R25 R31
+ },
+ },
+ },
+ {
+ name: "ADDVconst",
+ auxType: auxInt64,
+ argLen: 1,
+ asm: mips.AADDVU,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 268435454}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R22 R24 R25 SP g R31
+ },
+ outputs: []outputInfo{
+ {0, 167772158}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R22 R24 R25 R31
+ },
+ },
+ },
+ {
+ name: "SUBV",
+ argLen: 2,
+ asm: mips.ASUBVU,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 234881022}, // 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
+ {1, 234881022}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 167772158}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R22 R24 R25 R31
+ },
+ },
+ },
+ {
+ name: "SUBVconst",
+ auxType: auxInt64,
+ argLen: 1,
+ asm: mips.ASUBVU,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 234881022}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 167772158}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R22 R24 R25 R31
+ },
+ },
+ },
+ {
+ name: "MULV",
+ argLen: 2,
+ commutative: true,
+ asm: mips.AMULV,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 234881022}, // 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
+ {1, 234881022}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 1152921504606846976}, // HI
+ {1, 2305843009213693952}, // LO
+ },
+ },
+ },
+ {
+ name: "MULVU",
+ argLen: 2,
+ commutative: true,
+ asm: mips.AMULVU,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 234881022}, // 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
+ {1, 234881022}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 1152921504606846976}, // HI
+ {1, 2305843009213693952}, // LO
+ },
+ },
+ },
+ {
+ name: "DIVV",
+ argLen: 2,
+ asm: mips.ADIVV,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 234881022}, // 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
+ {1, 234881022}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 1152921504606846976}, // HI
+ {1, 2305843009213693952}, // LO
+ },
+ },
+ },
+ {
+ name: "DIVVU",
+ argLen: 2,
+ asm: mips.ADIVVU,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 234881022}, // 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
+ {1, 234881022}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 1152921504606846976}, // HI
+ {1, 2305843009213693952}, // LO
+ },
+ },
+ },
+ {
+ name: "ADDF",
+ argLen: 2,
+ commutative: true,
+ asm: mips.AADDF,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 1152921504338411520}, // 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
+ {1, 1152921504338411520}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 1152921504338411520}, // 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: "ADDD",
+ argLen: 2,
+ commutative: true,
+ asm: mips.AADDD,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 1152921504338411520}, // 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
+ {1, 1152921504338411520}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 1152921504338411520}, // 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: "SUBF",
+ argLen: 2,
+ asm: mips.ASUBF,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 1152921504338411520}, // 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
+ {1, 1152921504338411520}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 1152921504338411520}, // 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: "SUBD",
+ argLen: 2,
+ asm: mips.ASUBD,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 1152921504338411520}, // 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
+ {1, 1152921504338411520}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 1152921504338411520}, // 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: "MULF",
+ argLen: 2,
+ commutative: true,
+ asm: mips.AMULF,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 1152921504338411520}, // 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
+ {1, 1152921504338411520}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 1152921504338411520}, // 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: "MULD",
+ argLen: 2,
+ commutative: true,
+ asm: mips.AMULD,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 1152921504338411520}, // 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
+ {1, 1152921504338411520}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 1152921504338411520}, // 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: "DIVF",
+ argLen: 2,
+ asm: mips.ADIVF,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 1152921504338411520}, // 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
+ {1, 1152921504338411520}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 1152921504338411520}, // 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: "DIVD",
+ argLen: 2,
+ asm: mips.ADIVD,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 1152921504338411520}, // 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
+ {1, 1152921504338411520}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 1152921504338411520}, // 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: "AND",
+ argLen: 2,
+ commutative: true,
+ asm: mips.AAND,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 234881022}, // 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
+ {1, 234881022}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 167772158}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R22 R24 R25 R31
+ },
+ },
+ },
+ {
+ name: "ANDconst",
+ auxType: auxInt64,
+ argLen: 1,
+ asm: mips.AAND,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 234881022}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 167772158}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R22 R24 R25 R31
+ },
+ },
+ },
+ {
+ name: "OR",
+ argLen: 2,
+ commutative: true,
+ asm: mips.AOR,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 234881022}, // 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
+ {1, 234881022}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 167772158}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R22 R24 R25 R31
+ },
+ },
+ },
+ {
+ name: "ORconst",
+ auxType: auxInt64,
+ argLen: 1,
+ asm: mips.AOR,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 234881022}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 167772158}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R22 R24 R25 R31
+ },
+ },
+ },
+ {
+ name: "XOR",
+ argLen: 2,
+ commutative: true,
+ asm: mips.AXOR,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 234881022}, // 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
+ {1, 234881022}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 167772158}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R22 R24 R25 R31
+ },
+ },
+ },
+ {
+ name: "XORconst",
+ auxType: auxInt64,
+ argLen: 1,
+ asm: mips.AXOR,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 234881022}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 167772158}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R22 R24 R25 R31
+ },
+ },
+ },
+ {
+ name: "NOR",
+ argLen: 2,
+ commutative: true,
+ asm: mips.ANOR,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 234881022}, // 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
+ {1, 234881022}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 167772158}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R22 R24 R25 R31
+ },
+ },
+ },
+ {
+ name: "NORconst",
+ auxType: auxInt64,
+ argLen: 1,
+ asm: mips.ANOR,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 234881022}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 167772158}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R22 R24 R25 R31
+ },
+ },
+ },
+ {
+ name: "NEGV",
+ argLen: 1,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 234881022}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 167772158}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R22 R24 R25 R31
+ },
+ },
+ },
+ {
+ name: "NEGF",
+ argLen: 1,
+ asm: mips.ANEGF,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 1152921504338411520}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 1152921504338411520}, // 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: "NEGD",
+ argLen: 1,
+ asm: mips.ANEGD,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 1152921504338411520}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 1152921504338411520}, // 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: "SLLV",
+ argLen: 2,
+ asm: mips.ASLLV,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 234881022}, // 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
+ {1, 234881022}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 167772158}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R22 R24 R25 R31
+ },
+ },
+ },
+ {
+ name: "SLLVconst",
+ auxType: auxInt64,
+ argLen: 1,
+ asm: mips.ASLLV,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 234881022}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 167772158}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R22 R24 R25 R31
+ },
+ },
+ },
+ {
+ name: "SRLV",
+ argLen: 2,
+ asm: mips.ASRLV,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 234881022}, // 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
+ {1, 234881022}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 167772158}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R22 R24 R25 R31
+ },
+ },
+ },
+ {
+ name: "SRLVconst",
+ auxType: auxInt64,
+ argLen: 1,
+ asm: mips.ASRLV,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 234881022}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 167772158}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R22 R24 R25 R31
+ },
+ },
+ },
+ {
+ name: "SRAV",
+ argLen: 2,
+ asm: mips.ASRAV,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 234881022}, // 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
+ {1, 234881022}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 167772158}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R22 R24 R25 R31
+ },
+ },
+ },
+ {
+ name: "SRAVconst",
+ auxType: auxInt64,
+ argLen: 1,
+ asm: mips.ASRAV,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 234881022}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 167772158}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R22 R24 R25 R31
+ },
+ },
+ },
+ {
+ name: "SGT",
+ argLen: 2,
+ asm: mips.ASGT,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 234881022}, // 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
+ {1, 234881022}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 167772158}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R22 R24 R25 R31
+ },
+ },
+ },
+ {
+ name: "SGTconst",
+ auxType: auxInt64,
+ argLen: 1,
+ asm: mips.ASGT,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 234881022}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 167772158}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R22 R24 R25 R31
+ },
+ },
+ },
+ {
+ name: "SGTU",
+ argLen: 2,
+ asm: mips.ASGTU,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 234881022}, // 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
+ {1, 234881022}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 167772158}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R22 R24 R25 R31
+ },
+ },
+ },
+ {
+ name: "SGTUconst",
+ auxType: auxInt64,
+ argLen: 1,
+ asm: mips.ASGTU,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 234881022}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 167772158}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R22 R24 R25 R31
+ },
+ },
+ },
+ {
+ name: "CMPEQF",
+ argLen: 2,
+ asm: mips.ACMPEQF,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 1152921504338411520}, // 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
+ {1, 1152921504338411520}, // 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: "CMPEQD",
+ argLen: 2,
+ asm: mips.ACMPEQD,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 1152921504338411520}, // 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
+ {1, 1152921504338411520}, // 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: "CMPGEF",
+ argLen: 2,
+ asm: mips.ACMPGEF,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 1152921504338411520}, // 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
+ {1, 1152921504338411520}, // 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: "CMPGED",
+ argLen: 2,
+ asm: mips.ACMPGED,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 1152921504338411520}, // 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
+ {1, 1152921504338411520}, // 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: "CMPGTF",
+ argLen: 2,
+ asm: mips.ACMPGTF,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 1152921504338411520}, // 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
+ {1, 1152921504338411520}, // 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: "CMPGTD",
+ argLen: 2,
+ asm: mips.ACMPGTD,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 1152921504338411520}, // 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
+ {1, 1152921504338411520}, // 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: "MOVVconst",
+ auxType: auxInt64,
+ argLen: 0,
+ rematerializeable: true,
+ asm: mips.AMOVV,
+ reg: regInfo{
+ outputs: []outputInfo{
+ {0, 167772158}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R22 R24 R25 R31
+ },
+ },
+ },
+ {
+ name: "MOVFconst",
+ auxType: auxFloat64,
+ argLen: 0,
+ rematerializeable: true,
+ asm: mips.AMOVF,
+ reg: regInfo{
+ outputs: []outputInfo{
+ {0, 1152921504338411520}, // 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: "MOVDconst",
+ auxType: auxFloat64,
+ argLen: 0,
+ rematerializeable: true,
+ asm: mips.AMOVD,
+ reg: regInfo{
+ outputs: []outputInfo{
+ {0, 1152921504338411520}, // 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: "MOVVaddr",
+ auxType: auxSymOff,
+ argLen: 1,
+ rematerializeable: true,
+ asm: mips.AMOVV,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 4611686018460942336}, // SP SB
+ },
+ outputs: []outputInfo{
+ {0, 167772158}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R22 R24 R25 R31
+ },
+ },
+ },
+ {
+ name: "MOVBload",
+ auxType: auxSymOff,
+ argLen: 2,
+ faultOnNilArg0: true,
+ asm: mips.AMOVB,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 4611686018695823358}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R22 R24 R25 SP g R31 SB
+ },
+ outputs: []outputInfo{
+ {0, 167772158}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R22 R24 R25 R31
+ },
+ },
+ },
+ {
+ name: "MOVBUload",
+ auxType: auxSymOff,
+ argLen: 2,
+ faultOnNilArg0: true,
+ asm: mips.AMOVBU,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 4611686018695823358}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R22 R24 R25 SP g R31 SB
+ },
+ outputs: []outputInfo{
+ {0, 167772158}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R22 R24 R25 R31
+ },
+ },
+ },
+ {
+ name: "MOVHload",
+ auxType: auxSymOff,
+ argLen: 2,
+ faultOnNilArg0: true,
+ asm: mips.AMOVH,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 4611686018695823358}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R22 R24 R25 SP g R31 SB
+ },
+ outputs: []outputInfo{
+ {0, 167772158}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R22 R24 R25 R31
+ },
+ },
+ },
+ {
+ name: "MOVHUload",
+ auxType: auxSymOff,
+ argLen: 2,
+ faultOnNilArg0: true,
+ asm: mips.AMOVHU,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 4611686018695823358}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R22 R24 R25 SP g R31 SB
+ },
+ outputs: []outputInfo{
+ {0, 167772158}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R22 R24 R25 R31
+ },
+ },
+ },
+ {
+ name: "MOVWload",
+ auxType: auxSymOff,
+ argLen: 2,
+ faultOnNilArg0: true,
+ asm: mips.AMOVW,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 4611686018695823358}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R22 R24 R25 SP g R31 SB
+ },
+ outputs: []outputInfo{
+ {0, 167772158}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R22 R24 R25 R31
+ },
+ },
+ },
+ {
+ name: "MOVWUload",
+ auxType: auxSymOff,
+ argLen: 2,
+ faultOnNilArg0: true,
+ asm: mips.AMOVWU,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 4611686018695823358}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R22 R24 R25 SP g R31 SB
+ },
+ outputs: []outputInfo{
+ {0, 167772158}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R22 R24 R25 R31
+ },
+ },
+ },
+ {
+ name: "MOVVload",
+ auxType: auxSymOff,
+ argLen: 2,
+ faultOnNilArg0: true,
+ asm: mips.AMOVV,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 4611686018695823358}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R22 R24 R25 SP g R31 SB
+ },
+ outputs: []outputInfo{
+ {0, 167772158}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R22 R24 R25 R31
+ },
+ },
+ },
+ {
+ name: "MOVFload",
+ auxType: auxSymOff,
+ argLen: 2,
+ faultOnNilArg0: true,
+ asm: mips.AMOVF,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 4611686018695823358}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R22 R24 R25 SP g R31 SB
+ },
+ outputs: []outputInfo{
+ {0, 1152921504338411520}, // 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: "MOVDload",
+ auxType: auxSymOff,
+ argLen: 2,
+ faultOnNilArg0: true,
+ asm: mips.AMOVD,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 4611686018695823358}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R22 R24 R25 SP g R31 SB
+ },
+ outputs: []outputInfo{
+ {0, 1152921504338411520}, // 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: "MOVBstore",
+ auxType: auxSymOff,
+ argLen: 3,
+ faultOnNilArg0: true,
+ asm: mips.AMOVB,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 234881022}, // 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
+ {0, 4611686018695823358}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R22 R24 R25 SP g R31 SB
+ },
+ },
+ },
+ {
+ name: "MOVHstore",
+ auxType: auxSymOff,
+ argLen: 3,
+ faultOnNilArg0: true,
+ asm: mips.AMOVH,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 234881022}, // 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
+ {0, 4611686018695823358}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R22 R24 R25 SP g R31 SB
+ },
+ },
+ },
+ {
+ name: "MOVWstore",
+ auxType: auxSymOff,
+ argLen: 3,
+ faultOnNilArg0: true,
+ asm: mips.AMOVW,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 234881022}, // 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
+ {0, 4611686018695823358}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R22 R24 R25 SP g R31 SB
+ },
+ },
+ },
+ {
+ name: "MOVVstore",
+ auxType: auxSymOff,
+ argLen: 3,
+ faultOnNilArg0: true,
+ asm: mips.AMOVV,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 234881022}, // 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
+ {0, 4611686018695823358}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R22 R24 R25 SP g R31 SB
+ },
+ },
+ },
+ {
+ name: "MOVFstore",
+ auxType: auxSymOff,
+ argLen: 3,
+ faultOnNilArg0: true,
+ asm: mips.AMOVF,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 4611686018695823358}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R22 R24 R25 SP g R31 SB
+ {1, 1152921504338411520}, // 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: "MOVDstore",
+ auxType: auxSymOff,
+ argLen: 3,
+ faultOnNilArg0: true,
+ asm: mips.AMOVD,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 4611686018695823358}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R22 R24 R25 SP g R31 SB
+ {1, 1152921504338411520}, // 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: "MOVBstorezero",
+ auxType: auxSymOff,
+ argLen: 2,
+ faultOnNilArg0: true,
+ asm: mips.AMOVB,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 4611686018695823358}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R22 R24 R25 SP g R31 SB
+ },
+ },
+ },
+ {
+ name: "MOVHstorezero",
+ auxType: auxSymOff,
+ argLen: 2,
+ faultOnNilArg0: true,
+ asm: mips.AMOVH,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 4611686018695823358}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R22 R24 R25 SP g R31 SB
+ },
+ },
+ },
+ {
+ name: "MOVWstorezero",
+ auxType: auxSymOff,
+ argLen: 2,
+ faultOnNilArg0: true,
+ asm: mips.AMOVW,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 4611686018695823358}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R22 R24 R25 SP g R31 SB
+ },
+ },
+ },
+ {
+ name: "MOVVstorezero",
+ auxType: auxSymOff,
+ argLen: 2,
+ faultOnNilArg0: true,
+ asm: mips.AMOVV,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 4611686018695823358}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R22 R24 R25 SP g R31 SB
+ },
+ },
+ },
+ {
+ name: "MOVBreg",
+ argLen: 1,
+ asm: mips.AMOVB,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 234881022}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 167772158}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R22 R24 R25 R31
+ },
+ },
+ },
+ {
+ name: "MOVBUreg",
+ argLen: 1,
+ asm: mips.AMOVBU,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 234881022}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 167772158}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R22 R24 R25 R31
+ },
+ },
+ },
+ {
+ name: "MOVHreg",
+ argLen: 1,
+ asm: mips.AMOVH,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 234881022}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 167772158}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R22 R24 R25 R31
+ },
+ },
+ },
+ {
+ name: "MOVHUreg",
+ argLen: 1,
+ asm: mips.AMOVHU,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 234881022}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 167772158}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R22 R24 R25 R31
+ },
+ },
+ },
+ {
+ name: "MOVWreg",
+ argLen: 1,
+ asm: mips.AMOVW,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 234881022}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 167772158}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R22 R24 R25 R31
+ },
+ },
+ },
+ {
+ name: "MOVWUreg",
+ argLen: 1,
+ asm: mips.AMOVWU,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 234881022}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 167772158}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R22 R24 R25 R31
+ },
+ },
+ },
+ {
+ name: "MOVVreg",
+ argLen: 1,
+ asm: mips.AMOVV,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 234881022}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 167772158}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R22 R24 R25 R31
+ },
+ },
+ },
+ {
+ name: "MOVVnop",
+ argLen: 1,
+ resultInArg0: true,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 167772158}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R22 R24 R25 R31
+ },
+ outputs: []outputInfo{
+ {0, 167772158}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R22 R24 R25 R31
+ },
+ },
+ },
+ {
+ name: "MOVWF",
+ argLen: 1,
+ asm: mips.AMOVWF,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 1152921504338411520}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 1152921504338411520}, // 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: "MOVWD",
+ argLen: 1,
+ asm: mips.AMOVWD,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 1152921504338411520}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 1152921504338411520}, // 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: "MOVVF",
+ argLen: 1,
+ asm: mips.AMOVVF,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 1152921504338411520}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 1152921504338411520}, // 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: "MOVVD",
+ argLen: 1,
+ asm: mips.AMOVVD,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 1152921504338411520}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 1152921504338411520}, // 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: "TRUNCFW",
+ argLen: 1,
+ asm: mips.ATRUNCFW,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 1152921504338411520}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 1152921504338411520}, // 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: "TRUNCDW",
+ argLen: 1,
+ asm: mips.ATRUNCDW,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 1152921504338411520}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 1152921504338411520}, // 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: "TRUNCFV",
+ argLen: 1,
+ asm: mips.ATRUNCFV,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 1152921504338411520}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 1152921504338411520}, // 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: "TRUNCDV",
+ argLen: 1,
+ asm: mips.ATRUNCDV,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 1152921504338411520}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 1152921504338411520}, // 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: "MOVFD",
+ argLen: 1,
+ asm: mips.AMOVFD,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 1152921504338411520}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 1152921504338411520}, // 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: "MOVDF",
+ argLen: 1,
+ asm: mips.AMOVDF,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 1152921504338411520}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 1152921504338411520}, // 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: "CALLstatic",
+ auxType: auxSymOff,
+ 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: "CALLclosure",
+ auxType: auxInt64,
+ argLen: 3,
+ clobberFlags: true,
+ call: true,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 4194304}, // R22
+ {0, 201326590}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R22 R24 R25 SP R31
+ },
+ 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: "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,
+ clobberFlags: true,
+ call: true,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 167772158}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R22 R24 R25 R31
+ },
+ 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: "DUFFZERO",
+ auxType: auxInt64,
+ argLen: 2,
+ faultOnNilArg0: true,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 167772158}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R22 R24 R25 R31
+ },
+ clobbers: 134217730, // R1 R31
+ },
+ },
+ {
+ name: "LoweredZero",
+ auxType: auxInt64,
+ argLen: 3,
+ clobberFlags: true,
+ faultOnNilArg0: true,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 2}, // R1
+ {1, 167772158}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R22 R24 R25 R31
+ },
+ clobbers: 2, // R1
+ },
+ },
+ {
+ name: "LoweredMove",
+ auxType: auxInt64,
+ argLen: 4,
+ clobberFlags: true,
+ faultOnNilArg0: true,
+ faultOnNilArg1: true,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 4}, // R2
+ {1, 2}, // R1
+ {2, 167772158}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R22 R24 R25 R31
+ },
+ clobbers: 6, // R1 R2
+ },
+ },
+ {
+ name: "LoweredNilCheck",
+ argLen: 2,
+ nilCheck: true,
+ faultOnNilArg0: true,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 234881022}, // 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
+ },
+ },
+ },
+ {
+ name: "FPFlagTrue",
+ argLen: 1,
+ reg: regInfo{
+ outputs: []outputInfo{
+ {0, 167772158}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R22 R24 R25 R31
+ },
+ },
+ },
+ {
+ name: "FPFlagFalse",
+ argLen: 1,
+ reg: regInfo{
+ outputs: []outputInfo{
+ {0, 167772158}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R22 R24 R25 R31
+ },
+ },
+ },
+ {
+ name: "LoweredGetClosurePtr",
+ argLen: 0,
+ reg: regInfo{
+ outputs: []outputInfo{
+ {0, 4194304}, // R22
+ },
+ },
+ },
+ {
+ name: "MOVVconvert",
+ argLen: 2,
+ asm: mips.AMOVV,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 234881022}, // 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
+ },
+ outputs: []outputInfo{
+ {0, 167772158}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R22 R24 R25 R31
+ },
+ },
+ },
+
+ {
+ name: "ADD",
+ argLen: 2,
+ commutative: true,
+ 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
+ {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: "ADDconst",
+ auxType: auxSymOff,
+ argLen: 1,
+ 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
+ },
+ 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: "FADD",
+ argLen: 2,
+ commutative: true,
+ asm: ppc64.AFADD,
+ 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
+ },
+ 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: "FADDS",
+ argLen: 2,
+ commutative: true,
+ asm: ppc64.AFADDS,
+ 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
+ },
+ 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: "SUB",
+ argLen: 2,
+ asm: ppc64.ASUB,
+ 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: "FSUB",
+ argLen: 2,
+ asm: ppc64.AFSUB,
+ 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
+ },
+ 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: "FSUBS",
+ argLen: 2,
+ asm: ppc64.AFSUBS,
+ 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
+ },
+ 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: "MULLD",
+ argLen: 2,
+ commutative: true,
+ asm: ppc64.AMULLD,
+ 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: "MULLW",
+ argLen: 2,
+ commutative: true,
+ asm: ppc64.AMULLW,
+ 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: "MULHD",
+ argLen: 2,
+ commutative: true,
+ asm: ppc64.AMULHD,
+ 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: "MULHW",
+ argLen: 2,
+ commutative: true,
+ asm: ppc64.AMULHW,
+ 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: "MULHDU",
+ argLen: 2,
+ commutative: true,
+ asm: ppc64.AMULHDU,
+ 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: "MULHWU",
+ argLen: 2,
+ commutative: true,
+ asm: ppc64.AMULHWU,
+ 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: "FMUL",
+ argLen: 2,
+ commutative: true,
+ asm: ppc64.AFMUL,
+ 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
+ },
+ 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: "FMULS",
+ argLen: 2,
+ commutative: true,
+ asm: ppc64.AFMULS,
+ 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
+ },
+ 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,
+ 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: "SRAW",
+ argLen: 2,
+ asm: ppc64.ASRAW,
+ 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: "SRD",
+ argLen: 2,
+ asm: ppc64.ASRD,
+ 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: "SRW",
+ argLen: 2,
+ asm: ppc64.ASRW,
+ 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: "SLD",
+ argLen: 2,
+ asm: ppc64.ASLD,
+ 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: "SLW",
+ argLen: 2,
+ asm: ppc64.ASLW,
+ 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: "ADDconstForCarry",
+ auxType: auxInt16,
+ argLen: 1,
+ asm: ppc64.AADDC,
+ 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: "MaskIfNotCarry",
+ argLen: 1,
+ asm: ppc64.AADDME,
+ reg: regInfo{
+ 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: "SRADconst",
+ auxType: auxInt64,
+ argLen: 1,
+ asm: ppc64.ASRAD,
+ 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: "SRAWconst",
+ auxType: auxInt64,
+ argLen: 1,
+ asm: ppc64.ASRAW,
+ 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: "SRDconst",
+ auxType: auxInt64,
+ argLen: 1,
+ asm: ppc64.ASRD,
+ 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: "SRWconst",
+ auxType: auxInt64,
+ argLen: 1,
+ asm: ppc64.ASRW,
+ 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: "SLDconst",
+ auxType: auxInt64,
+ argLen: 1,
+ asm: ppc64.ASLD,
+ 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: "SLWconst",
+ auxType: auxInt64,
+ argLen: 1,
+ asm: ppc64.ASLW,
+ 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,
+ 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
+ },
+ 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: "FDIVS",
+ argLen: 2,
+ asm: ppc64.AFDIVS,
+ 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
+ },
+ 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: "DIVD",
+ argLen: 2,
+ asm: ppc64.ADIVD,
+ 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: "DIVW",
+ argLen: 2,
+ asm: ppc64.ADIVW,
+ 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: "DIVDU",
+ argLen: 2,
+ asm: ppc64.ADIVDU,
+ 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: "DIVWU",
+ argLen: 2,
+ asm: ppc64.ADIVWU,
+ 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: "FCTIDZ",
+ argLen: 1,
+ asm: ppc64.AFCTIDZ,
+ 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: "FCTIWZ",
+ argLen: 1,
+ asm: ppc64.AFCTIWZ,
+ 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: "FCFID",
+ argLen: 1,
+ asm: ppc64.AFCFID,
+ 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: "FRSP",
+ argLen: 1,
+ asm: ppc64.AFRSP,
+ 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: "Xf2i64",
+ argLen: 1,
+ usesScratch: 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, 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: "Xi2f64",
+ argLen: 1,
+ usesScratch: 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
+ },
+ 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: "AND",
+ argLen: 2,
+ commutative: true,
+ asm: ppc64.AAND,
+ 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: "ANDN",
+ argLen: 2,
+ asm: ppc64.AANDN,
+ 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: "OR",
+ argLen: 2,
+ commutative: true,
+ asm: ppc64.AOR,
+ 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: "ORN",
+ argLen: 2,
+ asm: ppc64.AORN,
+ 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,
+ asm: ppc64.AXOR,
+ 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: "EQV",
+ argLen: 2,
+ commutative: true,
+ asm: ppc64.AEQV,
+ 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: "NEG",
+ argLen: 1,
+ asm: ppc64.ANEG,
+ 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: "FNEG",
+ argLen: 1,
+ asm: ppc64.AFNEG,
+ 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: "FSQRT",
+ argLen: 1,
+ asm: ppc64.AFSQRT,
+ 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: "FSQRTS",
+ argLen: 1,
+ asm: ppc64.AFSQRTS,
+ 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: "ORconst",
+ auxType: auxInt64,
+ argLen: 1,
+ asm: ppc64.AOR,
+ 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: "XORconst",
+ auxType: auxInt64,
+ argLen: 1,
+ asm: ppc64.AXOR,
+ 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: "ANDconst",
+ auxType: auxInt64,
+ argLen: 1,
+ clobberFlags: true,
+ asm: ppc64.AANDCC,
+ 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: "ANDCCconst",
+ auxType: auxInt64,
+ argLen: 1,
+ asm: ppc64.AANDCC,
+ 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
+ },
+ },
+ },
+ {
+ name: "MOVBreg",
+ argLen: 1,
+ asm: ppc64.AMOVB,
+ 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: "MOVBZreg",
+ argLen: 1,
+ asm: ppc64.AMOVBZ,
+ 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: "MOVHreg",
+ argLen: 1,
+ asm: ppc64.AMOVH,
+ 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: "MOVHZreg",
+ argLen: 1,
+ asm: ppc64.AMOVHZ,
+ 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: "MOVWreg",
+ argLen: 1,
+ asm: ppc64.AMOVW,
+ 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: "MOVWZreg",
+ argLen: 1,
+ asm: ppc64.AMOVWZ,
+ 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: "MOVBZload",
+ auxType: auxSymOff,
+ argLen: 2,
+ faultOnNilArg0: true,
+ asm: ppc64.AMOVBZ,
+ 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: "MOVHload",
+ auxType: auxSymOff,
+ argLen: 2,
+ faultOnNilArg0: true,
+ asm: ppc64.AMOVH,
+ 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: "MOVHZload",
+ auxType: auxSymOff,
+ argLen: 2,
+ faultOnNilArg0: true,
+ asm: ppc64.AMOVHZ,
+ 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: "MOVWload",
+ auxType: auxSymOff,
+ argLen: 2,
+ faultOnNilArg0: true,
+ asm: ppc64.AMOVW,
+ 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: "MOVWZload",
+ auxType: auxSymOff,
+ argLen: 2,
+ faultOnNilArg0: true,
+ asm: ppc64.AMOVWZ,
+ 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: "MOVDload",
+ auxType: auxSymOff,
+ argLen: 2,
+ faultOnNilArg0: true,
+ 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: "FMOVDload",
+ auxType: auxSymOff,
+ argLen: 2,
+ faultOnNilArg0: true,
+ asm: ppc64.AFMOVD,
+ 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, 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: "FMOVSload",
+ auxType: auxSymOff,
+ argLen: 2,
+ faultOnNilArg0: true,
+ asm: ppc64.AFMOVS,
+ 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, 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: "MOVBstore",
+ auxType: auxSymOff,
+ argLen: 3,
+ faultOnNilArg0: true,
+ asm: ppc64.AMOVB,
+ 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: "MOVHstore",
+ auxType: auxSymOff,
+ argLen: 3,
+ faultOnNilArg0: true,
+ asm: ppc64.AMOVH,
+ 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: "MOVWstore",
+ auxType: auxSymOff,
+ argLen: 3,
+ faultOnNilArg0: true,
+ asm: ppc64.AMOVW,
+ 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: "MOVDstore",
+ auxType: auxSymOff,
+ argLen: 3,
+ faultOnNilArg0: true,
+ 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
+ {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: "FMOVDstore",
+ auxType: auxSymOff,
+ argLen: 3,
+ faultOnNilArg0: true,
+ asm: ppc64.AFMOVD,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {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
+ {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
+ },
+ },
+ },
+ {
+ name: "FMOVSstore",
+ auxType: auxSymOff,
+ argLen: 3,
+ faultOnNilArg0: true,
+ asm: ppc64.AFMOVS,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {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
+ {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
+ },
+ },
+ },
+ {
+ name: "MOVBstorezero",
+ auxType: auxSymOff,
+ argLen: 2,
+ faultOnNilArg0: true,
+ asm: ppc64.AMOVB,
+ 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
+ },
+ },
+ },
+ {
+ name: "MOVHstorezero",
+ auxType: auxSymOff,
+ argLen: 2,
+ faultOnNilArg0: true,
+ asm: ppc64.AMOVH,
+ 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
+ },
+ },
+ },
+ {
+ name: "MOVWstorezero",
+ auxType: auxSymOff,
+ argLen: 2,
+ faultOnNilArg0: true,
+ asm: ppc64.AMOVW,
+ 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
+ },
+ },
+ },
+ {
+ name: "MOVDstorezero",
+ auxType: auxSymOff,
+ argLen: 2,
+ faultOnNilArg0: true,
+ 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
+ },
+ },
+ },
+ {
+ name: "MOVDaddr",
+ auxType: auxSymOff,
+ argLen: 1,
+ rematerializeable: true,
+ asm: ppc64.AMOVD,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 6}, // SP SB
+ },
+ 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: "MOVDconst",
+ auxType: auxInt64,
+ argLen: 0,
+ rematerializeable: true,
+ asm: ppc64.AMOVD,
+ reg: regInfo{
+ 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: "FMOVDconst",
+ auxType: auxFloat64,
+ argLen: 0,
+ rematerializeable: true,
+ asm: ppc64.AFMOVD,
+ reg: regInfo{
+ 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: "FMOVSconst",
+ auxType: auxFloat32,
+ argLen: 0,
+ rematerializeable: true,
+ asm: ppc64.AFMOVS,
+ reg: regInfo{
+ 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: "FCMPU",
+ argLen: 2,
+ asm: ppc64.AFCMPU,
+ 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
+ },
+ },
+ },
+ {
+ name: "CMP",
+ argLen: 2,
+ asm: ppc64.ACMP,
+ 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: "CMPU",
+ argLen: 2,
+ asm: ppc64.ACMPU,
+ 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: "CMPW",
+ argLen: 2,
+ asm: ppc64.ACMPW,
+ 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: "CMPWU",
+ argLen: 2,
+ asm: ppc64.ACMPWU,
+ 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: "CMPconst",
+ auxType: auxInt64,
+ argLen: 1,
+ asm: ppc64.ACMP,
+ 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
+ },
+ },
+ },
+ {
+ name: "CMPUconst",
+ auxType: auxInt64,
+ argLen: 1,
+ asm: ppc64.ACMPU,
+ 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
+ },
+ },
+ },
+ {
+ name: "CMPWconst",
+ auxType: auxInt32,
+ argLen: 1,
+ asm: ppc64.ACMPW,
+ 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
+ },
+ },
+ },
+ {
+ name: "CMPWUconst",
+ auxType: auxInt32,
+ argLen: 1,
+ asm: ppc64.ACMPWU,
+ 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
+ },
+ },
+ },
+ {
+ name: "Equal",
+ argLen: 1,
+ reg: regInfo{
+ 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: "NotEqual",
+ argLen: 1,
+ reg: regInfo{
+ 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: "LessThan",
+ argLen: 1,
+ reg: regInfo{
+ 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: "FLessThan",
+ argLen: 1,
+ reg: regInfo{
+ 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: "LessEqual",
+ argLen: 1,
+ reg: regInfo{
+ 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: "FLessEqual",
+ argLen: 1,
+ reg: regInfo{
+ 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: "GreaterThan",
+ argLen: 1,
+ reg: regInfo{
+ 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: "FGreaterThan",
+ argLen: 1,
+ reg: regInfo{
+ 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: "GreaterEqual",
+ argLen: 1,
+ reg: regInfo{
+ 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: "FGreaterEqual",
+ argLen: 1,
+ reg: regInfo{
+ 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: "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: "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,
+ 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: "CALLdefer",
+ auxType: auxInt64,
+ argLen: 1,
+ clobberFlags: true,
+ call: 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
+ },
+ },
+ {
+ name: "CALLgo",
+ auxType: auxInt64,
+ argLen: 1,
+ clobberFlags: true,
+ call: 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
+ },
+ },
+ {
+ 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: 3,
+ clobberFlags: true,
+ faultOnNilArg0: 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, 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
},
- clobbers: 8589934592, // FLAGS
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ clobbers: 8, // R3
+ },
+ },
+ {
+ name: "LoweredMove",
+ auxType: auxInt64,
+ argLen: 4,
+ clobberFlags: true,
+ faultOnNilArg0: true,
+ faultOnNilArg1: true,
+ 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
},
+ clobbers: 24, // R3 R4
},
},
{
- name: "ANDQconst",
- auxType: auxInt64,
- argLen: 1,
+ name: "InvertFlags",
+ argLen: 1,
+ reg: regInfo{},
+ },
+ {
+ name: "FlagEQ",
+ argLen: 0,
+ reg: regInfo{},
+ },
+ {
+ name: "FlagLT",
+ argLen: 0,
+ reg: regInfo{},
+ },
+ {
+ name: "FlagGT",
+ argLen: 0,
+ reg: regInfo{},
+ },
+
+ {
+ name: "FADDS",
+ argLen: 2,
+ commutative: true,
resultInArg0: true,
- asm: x86.AANDQ,
+ clobberFlags: true,
+ asm: s390x.AFADDS,
reg: regInfo{
inputs: []inputInfo{
- {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {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
},
- clobbers: 8589934592, // FLAGS
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ outputs: []outputInfo{
+ {0, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
},
},
},
{
- name: "ANDLconst",
- auxType: auxInt32,
- argLen: 1,
+ name: "FADD",
+ argLen: 2,
+ commutative: true,
resultInArg0: true,
- asm: x86.AANDL,
+ clobberFlags: true,
+ asm: s390x.AFADD,
reg: regInfo{
inputs: []inputInfo{
- {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {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
},
- clobbers: 8589934592, // FLAGS
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ outputs: []outputInfo{
+ {0, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
},
},
},
{
- name: "ORQ",
+ name: "FSUBS",
argLen: 2,
- commutative: true,
resultInArg0: true,
- asm: x86.AORQ,
+ clobberFlags: true,
+ asm: s390x.AFSUBS,
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, 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
},
- clobbers: 8589934592, // FLAGS
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ outputs: []outputInfo{
+ {0, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
},
},
},
{
- name: "ORL",
+ name: "FSUB",
argLen: 2,
- commutative: true,
resultInArg0: true,
- asm: x86.AORL,
+ clobberFlags: true,
+ asm: s390x.AFSUB,
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, 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
},
- clobbers: 8589934592, // FLAGS
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ outputs: []outputInfo{
+ {0, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
},
},
},
{
- name: "ORQconst",
- auxType: auxInt64,
- argLen: 1,
+ name: "FMULS",
+ argLen: 2,
+ commutative: true,
resultInArg0: true,
- asm: x86.AORQ,
+ asm: s390x.AFMULS,
reg: regInfo{
inputs: []inputInfo{
- {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {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
},
- clobbers: 8589934592, // FLAGS
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ outputs: []outputInfo{
+ {0, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
},
},
},
{
- name: "ORLconst",
- auxType: auxInt32,
- argLen: 1,
+ name: "FMUL",
+ argLen: 2,
+ commutative: true,
resultInArg0: true,
- asm: x86.AORL,
+ asm: s390x.AFMUL,
reg: regInfo{
inputs: []inputInfo{
- {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {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
},
- clobbers: 8589934592, // FLAGS
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ outputs: []outputInfo{
+ {0, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
},
},
},
{
- name: "XORQ",
+ name: "FDIVS",
argLen: 2,
- commutative: true,
resultInArg0: true,
- asm: x86.AXORQ,
+ asm: s390x.AFDIVS,
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, 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
},
- clobbers: 8589934592, // FLAGS
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ outputs: []outputInfo{
+ {0, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
},
},
},
{
- name: "XORL",
+ name: "FDIV",
argLen: 2,
- commutative: true,
resultInArg0: true,
- asm: x86.AXORL,
+ asm: s390x.AFDIV,
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, 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
},
- clobbers: 8589934592, // FLAGS
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ outputs: []outputInfo{
+ {0, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
},
},
},
{
- name: "XORQconst",
- auxType: auxInt64,
+ name: "FNEGS",
argLen: 1,
- resultInArg0: true,
- asm: x86.AXORQ,
+ clobberFlags: true,
+ asm: s390x.AFNEGS,
reg: regInfo{
inputs: []inputInfo{
- {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
},
- clobbers: 8589934592, // FLAGS
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ outputs: []outputInfo{
+ {0, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
},
},
},
{
- name: "XORLconst",
- auxType: auxInt32,
+ name: "FNEG",
argLen: 1,
- resultInArg0: true,
- asm: x86.AXORL,
+ clobberFlags: true,
+ asm: s390x.AFNEG,
reg: regInfo{
inputs: []inputInfo{
- {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
},
- clobbers: 8589934592, // FLAGS
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ outputs: []outputInfo{
+ {0, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
},
},
},
{
- name: "CMPQ",
- argLen: 2,
- asm: x86.ACMPQ,
+ name: "FMOVSload",
+ auxType: auxSymOff,
+ argLen: 2,
+ faultOnNilArg0: true,
+ asm: s390x.AFMOVS,
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
+ {0, 4295021566}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP SB
},
- outputs: []regMask{
- 8589934592, // FLAGS
+ outputs: []outputInfo{
+ {0, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
},
},
},
{
- name: "CMPL",
- argLen: 2,
- asm: x86.ACMPL,
+ name: "FMOVDload",
+ auxType: auxSymOff,
+ argLen: 2,
+ faultOnNilArg0: true,
+ asm: s390x.AFMOVD,
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
+ {0, 4295021566}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP SB
},
- outputs: []regMask{
- 8589934592, // FLAGS
+ outputs: []outputInfo{
+ {0, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
},
},
},
{
- name: "CMPW",
- argLen: 2,
- asm: x86.ACMPW,
+ name: "FMOVSconst",
+ auxType: auxFloat32,
+ argLen: 0,
+ rematerializeable: true,
+ asm: s390x.AFMOVS,
+ reg: regInfo{
+ outputs: []outputInfo{
+ {0, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
+ },
+ },
+ },
+ {
+ name: "FMOVDconst",
+ auxType: auxFloat64,
+ argLen: 0,
+ rematerializeable: true,
+ asm: s390x.AFMOVD,
+ reg: regInfo{
+ outputs: []outputInfo{
+ {0, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
+ },
+ },
+ },
+ {
+ name: "FMOVSloadidx",
+ auxType: auxSymOff,
+ argLen: 3,
+ asm: s390x.AFMOVS,
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
+ {0, 54270}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP
+ {1, 54270}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP
},
- outputs: []regMask{
- 8589934592, // FLAGS
+ outputs: []outputInfo{
+ {0, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
},
},
},
{
- name: "CMPB",
- argLen: 2,
- asm: x86.ACMPB,
+ name: "FMOVDloadidx",
+ auxType: auxSymOff,
+ argLen: 3,
+ asm: s390x.AFMOVD,
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
+ {0, 54270}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP
+ {1, 54270}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP
},
- outputs: []regMask{
- 8589934592, // FLAGS
+ outputs: []outputInfo{
+ {0, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
},
},
},
{
- name: "CMPQconst",
- auxType: auxInt64,
- argLen: 1,
- asm: x86.ACMPQ,
+ name: "FMOVSstore",
+ auxType: auxSymOff,
+ argLen: 3,
+ faultOnNilArg0: true,
+ asm: s390x.AFMOVS,
reg: regInfo{
inputs: []inputInfo{
- {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 4295021566}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP SB
+ {1, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
},
- outputs: []regMask{
- 8589934592, // FLAGS
+ },
+ },
+ {
+ name: "FMOVDstore",
+ auxType: auxSymOff,
+ argLen: 3,
+ faultOnNilArg0: true,
+ asm: s390x.AFMOVD,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 4295021566}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP SB
+ {1, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
},
},
},
{
- name: "CMPLconst",
- auxType: auxInt32,
- argLen: 1,
- asm: x86.ACMPL,
+ name: "FMOVSstoreidx",
+ auxType: auxSymOff,
+ argLen: 4,
+ asm: s390x.AFMOVS,
reg: regInfo{
inputs: []inputInfo{
- {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 54270}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP
+ {1, 54270}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP
+ {2, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
},
- outputs: []regMask{
- 8589934592, // FLAGS
+ },
+ },
+ {
+ name: "FMOVDstoreidx",
+ auxType: auxSymOff,
+ argLen: 4,
+ asm: s390x.AFMOVD,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 54270}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP
+ {1, 54270}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP
+ {2, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
},
},
},
{
- name: "CMPWconst",
- auxType: auxInt16,
- argLen: 1,
- asm: x86.ACMPW,
+ name: "ADD",
+ argLen: 2,
+ commutative: true,
+ clobberFlags: true,
+ asm: s390x.AADD,
reg: regInfo{
inputs: []inputInfo{
- {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {1, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {0, 54271}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP
},
- outputs: []regMask{
- 8589934592, // FLAGS
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
},
},
{
- name: "CMPBconst",
- auxType: auxInt8,
- argLen: 1,
- asm: x86.ACMPB,
+ name: "ADDW",
+ argLen: 2,
+ commutative: true,
+ clobberFlags: true,
+ asm: s390x.AADDW,
reg: regInfo{
inputs: []inputInfo{
- {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {1, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {0, 54271}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP
},
- outputs: []regMask{
- 8589934592, // FLAGS
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
},
},
{
- name: "UCOMISS",
- argLen: 2,
- asm: x86.AUCOMISS,
+ name: "ADDconst",
+ auxType: auxInt64,
+ argLen: 1,
+ clobberFlags: true,
+ asm: s390x.AADD,
reg: regInfo{
inputs: []inputInfo{
- {0, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
- {1, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+ {0, 54271}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP
},
- outputs: []regMask{
- 8589934592, // FLAGS
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
},
},
{
- name: "UCOMISD",
- argLen: 2,
- asm: x86.AUCOMISD,
+ name: "ADDWconst",
+ auxType: auxInt32,
+ argLen: 1,
+ clobberFlags: true,
+ asm: s390x.AADDW,
reg: regInfo{
inputs: []inputInfo{
- {0, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
- {1, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+ {0, 54271}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP
},
- outputs: []regMask{
- 8589934592, // FLAGS
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
},
},
{
- name: "TESTQ",
- argLen: 2,
- asm: x86.ATESTQ,
+ name: "ADDload",
+ auxType: auxSymOff,
+ argLen: 3,
+ resultInArg0: true,
+ clobberFlags: true,
+ faultOnNilArg1: true,
+ asm: s390x.AADD,
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
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {1, 54270}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP
},
- outputs: []regMask{
- 8589934592, // FLAGS
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
},
},
{
- name: "TESTL",
- argLen: 2,
- asm: x86.ATESTL,
+ name: "ADDWload",
+ auxType: auxSymOff,
+ argLen: 3,
+ resultInArg0: true,
+ clobberFlags: true,
+ faultOnNilArg1: true,
+ asm: s390x.AADDW,
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
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {1, 54270}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP
},
- outputs: []regMask{
- 8589934592, // FLAGS
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
},
},
{
- name: "TESTW",
- argLen: 2,
- asm: x86.ATESTW,
+ name: "SUB",
+ argLen: 2,
+ clobberFlags: true,
+ asm: s390x.ASUB,
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
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {1, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
- outputs: []regMask{
- 8589934592, // FLAGS
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
},
},
{
- name: "TESTB",
- argLen: 2,
- asm: x86.ATESTB,
+ name: "SUBW",
+ argLen: 2,
+ clobberFlags: true,
+ asm: s390x.ASUBW,
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
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {1, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
- outputs: []regMask{
- 8589934592, // FLAGS
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
},
},
{
- name: "TESTQconst",
- auxType: auxInt64,
- argLen: 1,
- asm: x86.ATESTQ,
+ name: "SUBconst",
+ auxType: auxInt64,
+ argLen: 1,
+ resultInArg0: true,
+ clobberFlags: true,
+ asm: s390x.ASUB,
reg: regInfo{
inputs: []inputInfo{
- {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
- outputs: []regMask{
- 8589934592, // FLAGS
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
},
},
{
- name: "TESTLconst",
- auxType: auxInt32,
- argLen: 1,
- asm: x86.ATESTL,
+ name: "SUBWconst",
+ auxType: auxInt32,
+ argLen: 1,
+ resultInArg0: true,
+ clobberFlags: true,
+ asm: s390x.ASUBW,
reg: regInfo{
inputs: []inputInfo{
- {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
- outputs: []regMask{
- 8589934592, // FLAGS
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
},
},
{
- name: "TESTWconst",
- auxType: auxInt16,
- argLen: 1,
- asm: x86.ATESTW,
+ name: "SUBload",
+ auxType: auxSymOff,
+ argLen: 3,
+ resultInArg0: true,
+ clobberFlags: true,
+ faultOnNilArg1: true,
+ asm: s390x.ASUB,
reg: regInfo{
inputs: []inputInfo{
- {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {1, 54270}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP
},
- outputs: []regMask{
- 8589934592, // FLAGS
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
},
},
{
- name: "TESTBconst",
- auxType: auxInt8,
- argLen: 1,
- asm: x86.ATESTB,
+ name: "SUBWload",
+ auxType: auxSymOff,
+ argLen: 3,
+ resultInArg0: true,
+ clobberFlags: true,
+ faultOnNilArg1: true,
+ asm: s390x.ASUBW,
reg: regInfo{
inputs: []inputInfo{
- {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {1, 54270}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP
},
- outputs: []regMask{
- 8589934592, // FLAGS
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
},
},
{
- name: "SHLQ",
+ name: "MULLD",
argLen: 2,
+ commutative: true,
resultInArg0: true,
- asm: x86.ASHLQ,
+ clobberFlags: true,
+ asm: s390x.AMULLD,
reg: regInfo{
inputs: []inputInfo{
- {1, 2}, // CX
- {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {1, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
- clobbers: 8589934592, // FLAGS
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
},
},
{
- name: "SHLL",
+ name: "MULLW",
argLen: 2,
+ commutative: true,
resultInArg0: true,
- asm: x86.ASHLL,
+ clobberFlags: true,
+ asm: s390x.AMULLW,
reg: regInfo{
inputs: []inputInfo{
- {1, 2}, // CX
- {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {1, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
- clobbers: 8589934592, // FLAGS
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
},
},
{
- name: "SHLQconst",
+ name: "MULLDconst",
auxType: auxInt64,
argLen: 1,
resultInArg0: true,
- asm: x86.ASHLQ,
+ clobberFlags: true,
+ asm: s390x.AMULLD,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ },
+ },
+ {
+ name: "MULLWconst",
+ auxType: auxInt32,
+ argLen: 1,
+ resultInArg0: true,
+ clobberFlags: true,
+ asm: s390x.AMULLW,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ },
+ },
+ {
+ name: "MULLDload",
+ auxType: auxSymOff,
+ argLen: 3,
+ resultInArg0: true,
+ clobberFlags: true,
+ faultOnNilArg1: true,
+ asm: s390x.AMULLD,
reg: regInfo{
inputs: []inputInfo{
- {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {1, 54270}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP
},
- clobbers: 8589934592, // FLAGS
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
},
},
{
- name: "SHLLconst",
- auxType: auxInt32,
- argLen: 1,
- resultInArg0: true,
- asm: x86.ASHLL,
+ name: "MULLWload",
+ auxType: auxSymOff,
+ argLen: 3,
+ resultInArg0: true,
+ clobberFlags: true,
+ faultOnNilArg1: true,
+ asm: s390x.AMULLW,
reg: regInfo{
inputs: []inputInfo{
- {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {1, 54270}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP
},
- clobbers: 8589934592, // FLAGS
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
},
},
{
- name: "SHRQ",
+ name: "MULHD",
argLen: 2,
resultInArg0: true,
- asm: x86.ASHRQ,
+ clobberFlags: true,
+ asm: s390x.AMULHD,
reg: regInfo{
inputs: []inputInfo{
- {1, 2}, // CX
- {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {1, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
- clobbers: 8589934592, // FLAGS
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
},
},
{
- name: "SHRL",
+ name: "MULHDU",
argLen: 2,
resultInArg0: true,
- asm: x86.ASHRL,
+ clobberFlags: true,
+ asm: s390x.AMULHDU,
reg: regInfo{
inputs: []inputInfo{
- {1, 2}, // CX
- {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {1, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
- clobbers: 8589934592, // FLAGS
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
},
},
{
- name: "SHRW",
+ name: "DIVD",
argLen: 2,
resultInArg0: true,
- asm: x86.ASHRW,
+ clobberFlags: true,
+ asm: s390x.ADIVD,
reg: regInfo{
inputs: []inputInfo{
- {1, 2}, // CX
- {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {1, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
- clobbers: 8589934592, // FLAGS
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
},
},
{
- name: "SHRB",
+ name: "DIVW",
argLen: 2,
resultInArg0: true,
- asm: x86.ASHRB,
+ clobberFlags: true,
+ asm: s390x.ADIVW,
reg: regInfo{
inputs: []inputInfo{
- {1, 2}, // CX
- {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {1, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
- clobbers: 8589934592, // FLAGS
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
},
},
{
- name: "SHRQconst",
- auxType: auxInt64,
- argLen: 1,
+ name: "DIVDU",
+ argLen: 2,
resultInArg0: true,
- asm: x86.ASHRQ,
+ clobberFlags: true,
+ asm: s390x.ADIVDU,
reg: regInfo{
inputs: []inputInfo{
- {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {1, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
- clobbers: 8589934592, // FLAGS
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
},
},
{
- name: "SHRLconst",
- auxType: auxInt32,
- argLen: 1,
+ name: "DIVWU",
+ argLen: 2,
resultInArg0: true,
- asm: x86.ASHRL,
+ clobberFlags: true,
+ asm: s390x.ADIVWU,
reg: regInfo{
inputs: []inputInfo{
- {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {1, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
- clobbers: 8589934592, // FLAGS
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
},
},
{
- name: "SHRWconst",
- auxType: auxInt16,
- argLen: 1,
+ name: "MODD",
+ argLen: 2,
resultInArg0: true,
- asm: x86.ASHRW,
+ clobberFlags: true,
+ asm: s390x.AMODD,
reg: regInfo{
inputs: []inputInfo{
- {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {1, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
- clobbers: 8589934592, // FLAGS
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
},
},
{
- name: "SHRBconst",
- auxType: auxInt8,
- argLen: 1,
+ name: "MODW",
+ argLen: 2,
resultInArg0: true,
- asm: x86.ASHRB,
+ clobberFlags: true,
+ asm: s390x.AMODW,
reg: regInfo{
inputs: []inputInfo{
- {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {1, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
- clobbers: 8589934592, // FLAGS
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
},
},
{
- name: "SARQ",
+ name: "MODDU",
argLen: 2,
resultInArg0: true,
- asm: x86.ASARQ,
+ clobberFlags: true,
+ asm: s390x.AMODDU,
reg: regInfo{
inputs: []inputInfo{
- {1, 2}, // CX
- {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {1, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
- clobbers: 8589934592, // FLAGS
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
},
},
{
- name: "SARL",
+ name: "MODWU",
argLen: 2,
resultInArg0: true,
- asm: x86.ASARL,
+ clobberFlags: true,
+ asm: s390x.AMODWU,
reg: regInfo{
inputs: []inputInfo{
- {1, 2}, // CX
- {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {1, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
- clobbers: 8589934592, // FLAGS
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
},
},
{
- name: "SARW",
+ name: "AND",
argLen: 2,
- resultInArg0: true,
- asm: x86.ASARW,
+ commutative: true,
+ clobberFlags: true,
+ asm: s390x.AAND,
reg: regInfo{
inputs: []inputInfo{
- {1, 2}, // CX
- {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {1, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
- clobbers: 8589934592, // FLAGS
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
},
},
{
- name: "SARB",
+ name: "ANDW",
argLen: 2,
- resultInArg0: true,
- asm: x86.ASARB,
+ commutative: true,
+ clobberFlags: true,
+ asm: s390x.AANDW,
reg: regInfo{
inputs: []inputInfo{
- {1, 2}, // CX
- {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {1, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
- clobbers: 8589934592, // FLAGS
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
},
},
{
- name: "SARQconst",
+ name: "ANDconst",
auxType: auxInt64,
argLen: 1,
resultInArg0: true,
- asm: x86.ASARQ,
+ clobberFlags: true,
+ asm: s390x.AAND,
reg: regInfo{
inputs: []inputInfo{
- {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
- clobbers: 8589934592, // FLAGS
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
},
},
{
- name: "SARLconst",
+ name: "ANDWconst",
auxType: auxInt32,
argLen: 1,
resultInArg0: true,
- asm: x86.ASARL,
+ clobberFlags: true,
+ asm: s390x.AANDW,
reg: regInfo{
inputs: []inputInfo{
- {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
- clobbers: 8589934592, // FLAGS
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
},
},
{
- name: "SARWconst",
- auxType: auxInt16,
- argLen: 1,
- resultInArg0: true,
- asm: x86.ASARW,
+ name: "ANDload",
+ auxType: auxSymOff,
+ argLen: 3,
+ resultInArg0: true,
+ clobberFlags: true,
+ faultOnNilArg1: true,
+ asm: s390x.AAND,
reg: regInfo{
inputs: []inputInfo{
- {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {1, 54270}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP
},
- clobbers: 8589934592, // FLAGS
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
},
},
{
- name: "SARBconst",
- auxType: auxInt8,
- argLen: 1,
- resultInArg0: true,
- asm: x86.ASARB,
+ name: "ANDWload",
+ auxType: auxSymOff,
+ argLen: 3,
+ resultInArg0: true,
+ clobberFlags: true,
+ faultOnNilArg1: true,
+ asm: s390x.AANDW,
reg: regInfo{
inputs: []inputInfo{
- {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {1, 54270}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP
},
- clobbers: 8589934592, // FLAGS
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
},
},
{
- name: "ROLQconst",
- auxType: auxInt64,
- argLen: 1,
- resultInArg0: true,
- asm: x86.AROLQ,
+ name: "OR",
+ argLen: 2,
+ commutative: true,
+ clobberFlags: true,
+ asm: s390x.AOR,
reg: regInfo{
inputs: []inputInfo{
- {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {1, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
- clobbers: 8589934592, // FLAGS
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
},
},
{
- name: "ROLLconst",
- auxType: auxInt32,
- argLen: 1,
- resultInArg0: true,
- asm: x86.AROLL,
+ name: "ORW",
+ argLen: 2,
+ commutative: true,
+ clobberFlags: true,
+ asm: s390x.AORW,
reg: regInfo{
inputs: []inputInfo{
- {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {1, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
- clobbers: 8589934592, // FLAGS
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
},
},
{
- name: "ROLWconst",
- auxType: auxInt16,
+ name: "ORconst",
+ auxType: auxInt64,
argLen: 1,
resultInArg0: true,
- asm: x86.AROLW,
+ clobberFlags: true,
+ asm: s390x.AOR,
reg: regInfo{
inputs: []inputInfo{
- {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
- clobbers: 8589934592, // FLAGS
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
},
},
{
- name: "ROLBconst",
- auxType: auxInt8,
+ name: "ORWconst",
+ auxType: auxInt32,
argLen: 1,
resultInArg0: true,
- asm: x86.AROLB,
+ clobberFlags: true,
+ asm: s390x.AORW,
reg: regInfo{
inputs: []inputInfo{
- {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
- clobbers: 8589934592, // FLAGS
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
},
},
{
- name: "NEGQ",
- argLen: 1,
- resultInArg0: true,
- asm: x86.ANEGQ,
+ name: "ORload",
+ auxType: auxSymOff,
+ argLen: 3,
+ resultInArg0: true,
+ clobberFlags: true,
+ faultOnNilArg1: true,
+ asm: s390x.AOR,
reg: regInfo{
inputs: []inputInfo{
- {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {1, 54270}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP
},
- clobbers: 8589934592, // FLAGS
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
},
},
{
- name: "NEGL",
- argLen: 1,
- resultInArg0: true,
- asm: x86.ANEGL,
+ name: "ORWload",
+ auxType: auxSymOff,
+ argLen: 3,
+ resultInArg0: true,
+ clobberFlags: true,
+ faultOnNilArg1: true,
+ asm: s390x.AORW,
reg: regInfo{
inputs: []inputInfo{
- {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {1, 54270}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP
},
- clobbers: 8589934592, // FLAGS
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
},
},
{
- name: "NOTQ",
- argLen: 1,
- resultInArg0: true,
- asm: x86.ANOTQ,
+ name: "XOR",
+ argLen: 2,
+ commutative: true,
+ clobberFlags: true,
+ asm: s390x.AXOR,
reg: regInfo{
inputs: []inputInfo{
- {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {1, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
- clobbers: 8589934592, // FLAGS
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
},
},
{
- name: "NOTL",
- argLen: 1,
- resultInArg0: true,
- asm: x86.ANOTL,
+ name: "XORW",
+ argLen: 2,
+ commutative: true,
+ clobberFlags: true,
+ asm: s390x.AXORW,
reg: regInfo{
inputs: []inputInfo{
- {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {1, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
- clobbers: 8589934592, // FLAGS
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
},
},
{
- name: "BSFQ",
- argLen: 1,
- asm: x86.ABSFQ,
+ name: "XORconst",
+ auxType: auxInt64,
+ argLen: 1,
+ resultInArg0: true,
+ clobberFlags: true,
+ asm: s390x.AXOR,
reg: regInfo{
inputs: []inputInfo{
- {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
- clobbers: 8589934592, // FLAGS
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
},
},
{
- name: "BSFL",
- argLen: 1,
- asm: x86.ABSFL,
+ name: "XORWconst",
+ auxType: auxInt32,
+ argLen: 1,
+ resultInArg0: true,
+ clobberFlags: true,
+ asm: s390x.AXORW,
reg: regInfo{
inputs: []inputInfo{
- {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
- clobbers: 8589934592, // FLAGS
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
},
},
{
- name: "BSFW",
- argLen: 1,
- asm: x86.ABSFW,
+ name: "XORload",
+ auxType: auxSymOff,
+ argLen: 3,
+ resultInArg0: true,
+ clobberFlags: true,
+ faultOnNilArg1: true,
+ asm: s390x.AXOR,
reg: regInfo{
inputs: []inputInfo{
- {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {1, 54270}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP
},
- clobbers: 8589934592, // FLAGS
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
},
},
{
- name: "BSRQ",
- argLen: 1,
- asm: x86.ABSRQ,
+ name: "XORWload",
+ auxType: auxSymOff,
+ argLen: 3,
+ resultInArg0: true,
+ clobberFlags: true,
+ faultOnNilArg1: true,
+ asm: s390x.AXORW,
reg: regInfo{
inputs: []inputInfo{
- {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {1, 54270}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP
},
- clobbers: 8589934592, // FLAGS
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
},
},
{
- name: "BSRL",
- argLen: 1,
- asm: x86.ABSRL,
+ name: "CMP",
+ argLen: 2,
+ asm: s390x.ACMP,
reg: regInfo{
inputs: []inputInfo{
- {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- },
- clobbers: 8589934592, // FLAGS
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 54271}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP
+ {1, 54271}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP
},
},
},
{
- name: "BSRW",
- argLen: 1,
- asm: x86.ABSRW,
+ name: "CMPW",
+ argLen: 2,
+ asm: s390x.ACMPW,
reg: regInfo{
inputs: []inputInfo{
- {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- },
- clobbers: 8589934592, // FLAGS
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 54271}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP
+ {1, 54271}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP
},
},
},
{
- name: "CMOVQEQconst",
- auxType: auxInt64,
- argLen: 2,
- resultInArg0: true,
- asm: x86.ACMOVQEQ,
+ name: "CMPU",
+ argLen: 2,
+ asm: s390x.ACMPU,
reg: regInfo{
inputs: []inputInfo{
- {1, 8589934592}, // FLAGS
- {0, 65518}, // CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- },
- clobbers: 8589934593, // AX FLAGS
- outputs: []regMask{
- 65518, // CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 54271}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP
+ {1, 54271}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP
},
},
},
{
- name: "CMOVLEQconst",
- auxType: auxInt32,
- argLen: 2,
- resultInArg0: true,
- asm: x86.ACMOVLEQ,
+ name: "CMPWU",
+ argLen: 2,
+ asm: s390x.ACMPWU,
reg: regInfo{
inputs: []inputInfo{
- {1, 8589934592}, // FLAGS
- {0, 65518}, // CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- },
- clobbers: 8589934593, // AX FLAGS
- outputs: []regMask{
- 65518, // CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 54271}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP
+ {1, 54271}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP
},
},
},
{
- name: "CMOVWEQconst",
- auxType: auxInt16,
- argLen: 2,
- resultInArg0: true,
- asm: x86.ACMOVLEQ,
+ name: "CMPconst",
+ auxType: auxInt64,
+ argLen: 1,
+ asm: s390x.ACMP,
reg: regInfo{
inputs: []inputInfo{
- {1, 8589934592}, // FLAGS
- {0, 65518}, // CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- },
- clobbers: 8589934593, // AX FLAGS
- outputs: []regMask{
- 65518, // CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 54271}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP
},
},
},
{
- name: "CMOVQNEconst",
- auxType: auxInt64,
- argLen: 2,
- resultInArg0: true,
- asm: x86.ACMOVQNE,
+ name: "CMPWconst",
+ auxType: auxInt32,
+ argLen: 1,
+ asm: s390x.ACMPW,
reg: regInfo{
inputs: []inputInfo{
- {1, 8589934592}, // FLAGS
- {0, 65518}, // CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- },
- clobbers: 8589934593, // AX FLAGS
- outputs: []regMask{
- 65518, // CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 54271}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP
},
},
},
{
- name: "CMOVLNEconst",
- auxType: auxInt32,
- argLen: 2,
- resultInArg0: true,
- asm: x86.ACMOVLNE,
+ name: "CMPUconst",
+ auxType: auxInt64,
+ argLen: 1,
+ asm: s390x.ACMPU,
reg: regInfo{
inputs: []inputInfo{
- {1, 8589934592}, // FLAGS
- {0, 65518}, // CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- },
- clobbers: 8589934593, // AX FLAGS
- outputs: []regMask{
- 65518, // CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 54271}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP
},
},
},
{
- name: "CMOVWNEconst",
- auxType: auxInt16,
- argLen: 2,
- resultInArg0: true,
- asm: x86.ACMOVLNE,
+ name: "CMPWUconst",
+ auxType: auxInt32,
+ argLen: 1,
+ asm: s390x.ACMPWU,
reg: regInfo{
inputs: []inputInfo{
- {1, 8589934592}, // FLAGS
- {0, 65518}, // CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- },
- clobbers: 8589934593, // AX FLAGS
- outputs: []regMask{
- 65518, // CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 54271}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP
},
},
},
{
- name: "BSWAPQ",
- argLen: 1,
- resultInArg0: true,
- asm: x86.ABSWAPQ,
+ name: "FCMPS",
+ argLen: 2,
+ asm: s390x.ACEBR,
reg: regInfo{
inputs: []inputInfo{
- {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {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
},
- clobbers: 8589934592, // FLAGS
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ },
+ },
+ {
+ name: "FCMP",
+ argLen: 2,
+ asm: s390x.AFCMPU,
+ 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
},
},
},
{
- name: "BSWAPL",
- argLen: 1,
- resultInArg0: true,
- asm: x86.ABSWAPL,
+ name: "SLD",
+ argLen: 2,
+ asm: s390x.ASLD,
reg: regInfo{
inputs: []inputInfo{
- {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {1, 21502}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
- clobbers: 8589934592, // FLAGS
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
},
},
{
- name: "SQRTSD",
- argLen: 1,
- asm: x86.ASQRTSD,
+ name: "SLW",
+ argLen: 2,
+ asm: s390x.ASLW,
reg: regInfo{
inputs: []inputInfo{
- {0, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+ {1, 21502}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
- outputs: []regMask{
- 4294901760, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
},
},
{
- name: "SBBQcarrymask",
- argLen: 1,
- asm: x86.ASBBQ,
+ name: "SLDconst",
+ auxType: auxInt64,
+ argLen: 1,
+ asm: s390x.ASLD,
reg: regInfo{
inputs: []inputInfo{
- {0, 8589934592}, // FLAGS
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
},
},
{
- name: "SBBLcarrymask",
- argLen: 1,
- asm: x86.ASBBL,
+ name: "SLWconst",
+ auxType: auxInt32,
+ argLen: 1,
+ asm: s390x.ASLW,
reg: regInfo{
inputs: []inputInfo{
- {0, 8589934592}, // FLAGS
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
},
},
{
- name: "SETEQ",
- argLen: 1,
- asm: x86.ASETEQ,
+ name: "SRD",
+ argLen: 2,
+ asm: s390x.ASRD,
reg: regInfo{
inputs: []inputInfo{
- {0, 8589934592}, // FLAGS
+ {1, 21502}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
},
},
{
- name: "SETNE",
- argLen: 1,
- asm: x86.ASETNE,
+ name: "SRW",
+ argLen: 2,
+ asm: s390x.ASRW,
reg: regInfo{
inputs: []inputInfo{
- {0, 8589934592}, // FLAGS
+ {1, 21502}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
},
},
{
- name: "SETL",
- argLen: 1,
- asm: x86.ASETLT,
+ name: "SRDconst",
+ auxType: auxInt64,
+ argLen: 1,
+ asm: s390x.ASRD,
reg: regInfo{
inputs: []inputInfo{
- {0, 8589934592}, // FLAGS
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
},
},
{
- name: "SETLE",
- argLen: 1,
- asm: x86.ASETLE,
+ name: "SRWconst",
+ auxType: auxInt32,
+ argLen: 1,
+ asm: s390x.ASRW,
reg: regInfo{
inputs: []inputInfo{
- {0, 8589934592}, // FLAGS
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
},
},
{
- name: "SETG",
- argLen: 1,
- asm: x86.ASETGT,
+ name: "SRAD",
+ argLen: 2,
+ clobberFlags: true,
+ asm: s390x.ASRAD,
reg: regInfo{
inputs: []inputInfo{
- {0, 8589934592}, // FLAGS
+ {1, 21502}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
},
},
{
- name: "SETGE",
- argLen: 1,
- asm: x86.ASETGE,
+ name: "SRAW",
+ argLen: 2,
+ clobberFlags: true,
+ asm: s390x.ASRAW,
reg: regInfo{
inputs: []inputInfo{
- {0, 8589934592}, // FLAGS
+ {1, 21502}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
},
},
{
- name: "SETB",
- argLen: 1,
- asm: x86.ASETCS,
+ name: "SRADconst",
+ auxType: auxInt64,
+ argLen: 1,
+ clobberFlags: true,
+ asm: s390x.ASRAD,
reg: regInfo{
inputs: []inputInfo{
- {0, 8589934592}, // FLAGS
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
},
},
{
- name: "SETBE",
- argLen: 1,
- asm: x86.ASETLS,
+ name: "SRAWconst",
+ auxType: auxInt32,
+ argLen: 1,
+ clobberFlags: true,
+ asm: s390x.ASRAW,
reg: regInfo{
inputs: []inputInfo{
- {0, 8589934592}, // FLAGS
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
},
},
{
- name: "SETA",
- argLen: 1,
- asm: x86.ASETHI,
+ name: "RLLGconst",
+ auxType: auxInt64,
+ argLen: 1,
+ asm: s390x.ARLLG,
reg: regInfo{
inputs: []inputInfo{
- {0, 8589934592}, // FLAGS
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
},
},
{
- name: "SETAE",
- argLen: 1,
- asm: x86.ASETCC,
+ name: "RLLconst",
+ auxType: auxInt32,
+ argLen: 1,
+ asm: s390x.ARLL,
reg: regInfo{
inputs: []inputInfo{
- {0, 8589934592}, // FLAGS
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
},
},
{
- name: "SETEQF",
- argLen: 1,
- asm: x86.ASETEQ,
+ name: "NEG",
+ argLen: 1,
+ clobberFlags: true,
+ asm: s390x.ANEG,
reg: regInfo{
inputs: []inputInfo{
- {0, 8589934592}, // FLAGS
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
- clobbers: 8589934593, // AX FLAGS
- outputs: []regMask{
- 65518, // CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
},
},
{
- name: "SETNEF",
- argLen: 1,
- asm: x86.ASETNE,
+ name: "NEGW",
+ argLen: 1,
+ clobberFlags: true,
+ asm: s390x.ANEGW,
reg: regInfo{
inputs: []inputInfo{
- {0, 8589934592}, // FLAGS
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
- clobbers: 8589934593, // AX FLAGS
- outputs: []regMask{
- 65518, // CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
},
},
{
- name: "SETORD",
- argLen: 1,
- asm: x86.ASETPC,
+ name: "NOT",
+ argLen: 1,
+ resultInArg0: true,
+ clobberFlags: true,
reg: regInfo{
inputs: []inputInfo{
- {0, 8589934592}, // FLAGS
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
},
},
{
- name: "SETNAN",
- argLen: 1,
- asm: x86.ASETPS,
+ name: "NOTW",
+ argLen: 1,
+ resultInArg0: true,
+ clobberFlags: true,
reg: regInfo{
inputs: []inputInfo{
- {0, 8589934592}, // FLAGS
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
},
},
{
- name: "SETGF",
+ name: "FSQRT",
argLen: 1,
- asm: x86.ASETHI,
+ asm: s390x.AFSQRT,
reg: regInfo{
inputs: []inputInfo{
- {0, 8589934592}, // FLAGS
+ {0, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
},
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ outputs: []outputInfo{
+ {0, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
},
},
},
{
- name: "SETGEF",
+ name: "SUBEcarrymask",
argLen: 1,
- asm: x86.ASETCC,
+ asm: s390x.ASUBE,
reg: regInfo{
- inputs: []inputInfo{
- {0, 8589934592}, // FLAGS
- },
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
},
},
{
- name: "MOVBQSX",
+ name: "SUBEWcarrymask",
argLen: 1,
- asm: x86.AMOVBQSX,
+ asm: s390x.ASUBE,
reg: regInfo{
- inputs: []inputInfo{
- {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- },
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
},
},
{
- name: "MOVBQZX",
- argLen: 1,
- asm: x86.AMOVBQZX,
+ name: "MOVDEQ",
+ argLen: 3,
+ resultInArg0: true,
+ asm: s390x.AMOVDEQ,
reg: regInfo{
inputs: []inputInfo{
- {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {1, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
},
},
{
- name: "MOVWQSX",
- argLen: 1,
- asm: x86.AMOVWQSX,
+ name: "MOVDNE",
+ argLen: 3,
+ resultInArg0: true,
+ asm: s390x.AMOVDNE,
reg: regInfo{
inputs: []inputInfo{
- {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {1, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
},
},
{
- name: "MOVWQZX",
- argLen: 1,
- asm: x86.AMOVWQZX,
+ name: "MOVDLT",
+ argLen: 3,
+ resultInArg0: true,
+ asm: s390x.AMOVDLT,
reg: regInfo{
inputs: []inputInfo{
- {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {1, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
},
},
{
- name: "MOVLQSX",
- argLen: 1,
- asm: x86.AMOVLQSX,
+ name: "MOVDLE",
+ argLen: 3,
+ resultInArg0: true,
+ asm: s390x.AMOVDLE,
reg: regInfo{
inputs: []inputInfo{
- {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {1, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
},
},
{
- name: "MOVLQZX",
- argLen: 1,
- asm: x86.AMOVLQZX,
+ name: "MOVDGT",
+ argLen: 3,
+ resultInArg0: true,
+ asm: s390x.AMOVDGT,
reg: regInfo{
inputs: []inputInfo{
- {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {1, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
},
},
{
- name: "MOVLconst",
- auxType: auxInt32,
- argLen: 0,
- rematerializeable: true,
- asm: x86.AMOVL,
+ name: "MOVDGE",
+ argLen: 3,
+ resultInArg0: true,
+ asm: s390x.AMOVDGE,
reg: regInfo{
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ inputs: []inputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {1, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
},
},
{
- name: "MOVQconst",
- auxType: auxInt64,
- argLen: 0,
- rematerializeable: true,
- asm: x86.AMOVQ,
+ name: "MOVDGTnoinv",
+ argLen: 3,
+ resultInArg0: true,
+ asm: s390x.AMOVDGT,
reg: regInfo{
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ inputs: []inputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {1, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
},
},
{
- name: "CVTTSD2SL",
- argLen: 1,
- asm: x86.ACVTTSD2SL,
+ name: "MOVDGEnoinv",
+ argLen: 3,
+ resultInArg0: true,
+ asm: s390x.AMOVDGE,
reg: regInfo{
inputs: []inputInfo{
- {0, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ {1, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
},
},
{
- name: "CVTTSD2SQ",
+ name: "MOVBreg",
argLen: 1,
- asm: x86.ACVTTSD2SQ,
+ asm: s390x.AMOVB,
reg: regInfo{
inputs: []inputInfo{
- {0, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+ {0, 54271}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP
},
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
},
},
{
- name: "CVTTSS2SL",
+ name: "MOVBZreg",
argLen: 1,
- asm: x86.ACVTTSS2SL,
+ asm: s390x.AMOVBZ,
reg: regInfo{
inputs: []inputInfo{
- {0, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+ {0, 54271}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP
},
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
},
},
{
- name: "CVTTSS2SQ",
+ name: "MOVHreg",
argLen: 1,
- asm: x86.ACVTTSS2SQ,
+ asm: s390x.AMOVH,
reg: regInfo{
inputs: []inputInfo{
- {0, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+ {0, 54271}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP
},
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
},
},
{
- name: "CVTSL2SS",
+ name: "MOVHZreg",
argLen: 1,
- asm: x86.ACVTSL2SS,
+ asm: s390x.AMOVHZ,
reg: regInfo{
inputs: []inputInfo{
- {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 54271}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP
},
- outputs: []regMask{
- 4294901760, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
},
},
{
- name: "CVTSL2SD",
+ name: "MOVWreg",
argLen: 1,
- asm: x86.ACVTSL2SD,
+ asm: s390x.AMOVW,
reg: regInfo{
inputs: []inputInfo{
- {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 54271}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP
},
- outputs: []regMask{
- 4294901760, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
},
},
{
- name: "CVTSQ2SS",
+ name: "MOVWZreg",
argLen: 1,
- asm: x86.ACVTSQ2SS,
+ asm: s390x.AMOVWZ,
reg: regInfo{
inputs: []inputInfo{
- {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 54271}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP
},
- outputs: []regMask{
- 4294901760, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
},
},
{
- name: "CVTSQ2SD",
- argLen: 1,
- asm: x86.ACVTSQ2SD,
+ name: "MOVDconst",
+ auxType: auxInt64,
+ argLen: 0,
+ rematerializeable: true,
+ asm: s390x.AMOVD,
reg: regInfo{
- inputs: []inputInfo{
- {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- },
- outputs: []regMask{
- 4294901760, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
},
},
{
- name: "CVTSD2SS",
+ name: "CFDBRA",
argLen: 1,
- asm: x86.ACVTSD2SS,
+ asm: s390x.ACFDBRA,
reg: regInfo{
inputs: []inputInfo{
- {0, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+ {0, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
},
- outputs: []regMask{
- 4294901760, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
},
},
{
- name: "CVTSS2SD",
+ name: "CGDBRA",
argLen: 1,
- asm: x86.ACVTSS2SD,
+ asm: s390x.ACGDBRA,
reg: regInfo{
inputs: []inputInfo{
- {0, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+ {0, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
},
- outputs: []regMask{
- 4294901760, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
},
},
{
- name: "PXOR",
- argLen: 2,
- commutative: true,
- resultInArg0: true,
- asm: x86.APXOR,
+ name: "CFEBRA",
+ argLen: 1,
+ asm: s390x.ACFEBRA,
reg: regInfo{
inputs: []inputInfo{
- {0, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
- {1, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+ {0, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
},
- outputs: []regMask{
- 4294901760, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
},
},
{
- name: "LEAQ",
- auxType: auxSymOff,
- argLen: 1,
- rematerializeable: true,
+ name: "CGEBRA",
+ argLen: 1,
+ asm: s390x.ACGEBRA,
reg: regInfo{
inputs: []inputInfo{
- {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+ {0, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
},
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
},
},
{
- name: "LEAQ1",
- auxType: auxSymOff,
- argLen: 2,
+ name: "CEFBRA",
+ argLen: 1,
+ asm: s390x.ACEFBRA,
reg: regInfo{
inputs: []inputInfo{
- {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ outputs: []outputInfo{
+ {0, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
},
},
},
{
- name: "LEAQ2",
- auxType: auxSymOff,
- argLen: 2,
+ name: "CDFBRA",
+ argLen: 1,
+ asm: s390x.ACDFBRA,
reg: regInfo{
inputs: []inputInfo{
- {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ outputs: []outputInfo{
+ {0, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
},
},
},
{
- name: "LEAQ4",
- auxType: auxSymOff,
- argLen: 2,
+ name: "CEGBRA",
+ argLen: 1,
+ asm: s390x.ACEGBRA,
reg: regInfo{
inputs: []inputInfo{
- {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ outputs: []outputInfo{
+ {0, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
},
},
},
{
- name: "LEAQ8",
- auxType: auxSymOff,
- argLen: 2,
+ name: "CDGBRA",
+ argLen: 1,
+ asm: s390x.ACDGBRA,
reg: regInfo{
inputs: []inputInfo{
- {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ outputs: []outputInfo{
+ {0, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
},
},
},
{
- name: "MOVBload",
- auxType: auxSymOff,
- argLen: 2,
- asm: x86.AMOVBLZX,
+ name: "LEDBR",
+ argLen: 1,
+ asm: s390x.ALEDBR,
reg: regInfo{
inputs: []inputInfo{
- {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+ {0, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
},
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ outputs: []outputInfo{
+ {0, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
},
},
},
{
- name: "MOVBQSXload",
- auxType: auxSymOff,
- argLen: 2,
- asm: x86.AMOVBQSX,
+ name: "LDEBR",
+ argLen: 1,
+ asm: s390x.ALDEBR,
reg: regInfo{
inputs: []inputInfo{
- {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+ {0, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
},
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ outputs: []outputInfo{
+ {0, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
},
},
},
{
- name: "MOVWload",
- auxType: auxSymOff,
- argLen: 2,
- asm: x86.AMOVWLZX,
+ name: "MOVDaddr",
+ auxType: auxSymOff,
+ argLen: 1,
+ rematerializeable: true,
+ clobberFlags: true,
reg: regInfo{
inputs: []inputInfo{
- {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+ {0, 4295000064}, // SP SB
},
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
},
},
{
- name: "MOVWQSXload",
- auxType: auxSymOff,
- argLen: 2,
- asm: x86.AMOVWQSX,
+ name: "MOVDaddridx",
+ auxType: auxSymOff,
+ argLen: 2,
+ clobberFlags: true,
reg: regInfo{
inputs: []inputInfo{
- {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+ {0, 4295000064}, // SP SB
+ {1, 54270}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP
},
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
},
},
{
- name: "MOVLload",
- auxType: auxSymOff,
- argLen: 2,
- asm: x86.AMOVL,
+ name: "MOVBZload",
+ auxType: auxSymOff,
+ argLen: 2,
+ clobberFlags: true,
+ faultOnNilArg0: true,
+ asm: s390x.AMOVBZ,
reg: regInfo{
inputs: []inputInfo{
- {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+ {0, 4295021566}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP SB
},
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
},
},
{
- name: "MOVLQSXload",
- auxType: auxSymOff,
- argLen: 2,
- asm: x86.AMOVLQSX,
+ name: "MOVBload",
+ auxType: auxSymOff,
+ argLen: 2,
+ clobberFlags: true,
+ faultOnNilArg0: true,
+ asm: s390x.AMOVB,
reg: regInfo{
inputs: []inputInfo{
- {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+ {0, 4295021566}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP SB
},
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
},
},
{
- name: "MOVQload",
- auxType: auxSymOff,
- argLen: 2,
- asm: x86.AMOVQ,
+ name: "MOVHZload",
+ auxType: auxSymOff,
+ argLen: 2,
+ clobberFlags: true,
+ faultOnNilArg0: true,
+ asm: s390x.AMOVHZ,
reg: regInfo{
inputs: []inputInfo{
- {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+ {0, 4295021566}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP SB
},
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
},
},
{
- name: "MOVBstore",
- auxType: auxSymOff,
- argLen: 3,
- asm: x86.AMOVB,
+ name: "MOVHload",
+ auxType: auxSymOff,
+ argLen: 2,
+ clobberFlags: true,
+ faultOnNilArg0: true,
+ asm: s390x.AMOVH,
reg: regInfo{
inputs: []inputInfo{
- {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+ {0, 4295021566}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP SB
+ },
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
},
},
{
- name: "MOVWstore",
- auxType: auxSymOff,
- argLen: 3,
- asm: x86.AMOVW,
+ name: "MOVWZload",
+ auxType: auxSymOff,
+ argLen: 2,
+ clobberFlags: true,
+ faultOnNilArg0: true,
+ asm: s390x.AMOVWZ,
reg: regInfo{
inputs: []inputInfo{
- {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+ {0, 4295021566}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP SB
+ },
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
},
},
{
- name: "MOVLstore",
- auxType: auxSymOff,
- argLen: 3,
- asm: x86.AMOVL,
+ name: "MOVWload",
+ auxType: auxSymOff,
+ argLen: 2,
+ clobberFlags: true,
+ faultOnNilArg0: true,
+ asm: s390x.AMOVW,
reg: regInfo{
inputs: []inputInfo{
- {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+ {0, 4295021566}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP SB
+ },
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
},
},
{
- name: "MOVQstore",
- auxType: auxSymOff,
- argLen: 3,
- asm: x86.AMOVQ,
+ name: "MOVDload",
+ auxType: auxSymOff,
+ argLen: 2,
+ clobberFlags: true,
+ faultOnNilArg0: true,
+ asm: s390x.AMOVD,
reg: regInfo{
inputs: []inputInfo{
- {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+ {0, 4295021566}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP SB
+ },
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
},
},
{
- name: "MOVOload",
- auxType: auxSymOff,
- argLen: 2,
- asm: x86.AMOVUPS,
+ name: "MOVWBR",
+ argLen: 1,
+ asm: s390x.AMOVWBR,
reg: regInfo{
inputs: []inputInfo{
- {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
- outputs: []regMask{
- 4294901760, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
},
},
{
- name: "MOVOstore",
- auxType: auxSymOff,
- argLen: 3,
- asm: x86.AMOVUPS,
+ name: "MOVDBR",
+ argLen: 1,
+ asm: s390x.AMOVDBR,
reg: regInfo{
inputs: []inputInfo{
- {1, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
- {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
},
},
{
- name: "MOVBloadidx1",
- auxType: auxSymOff,
- argLen: 3,
- asm: x86.AMOVBLZX,
+ name: "MOVHBRload",
+ auxType: auxSymOff,
+ argLen: 2,
+ clobberFlags: true,
+ faultOnNilArg0: true,
+ asm: s390x.AMOVHBR,
reg: regInfo{
inputs: []inputInfo{
- {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+ {0, 4295021566}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP SB
},
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
},
},
{
- name: "MOVWloadidx1",
- auxType: auxSymOff,
- argLen: 3,
- asm: x86.AMOVWLZX,
+ name: "MOVWBRload",
+ auxType: auxSymOff,
+ argLen: 2,
+ clobberFlags: true,
+ faultOnNilArg0: true,
+ asm: s390x.AMOVWBR,
reg: regInfo{
inputs: []inputInfo{
- {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+ {0, 4295021566}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP SB
},
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
},
},
{
- name: "MOVWloadidx2",
- auxType: auxSymOff,
- argLen: 3,
- asm: x86.AMOVWLZX,
+ name: "MOVDBRload",
+ auxType: auxSymOff,
+ argLen: 2,
+ clobberFlags: true,
+ faultOnNilArg0: true,
+ asm: s390x.AMOVDBR,
reg: regInfo{
inputs: []inputInfo{
- {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+ {0, 4295021566}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP SB
},
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
},
},
{
- name: "MOVLloadidx1",
- auxType: auxSymOff,
- argLen: 3,
- asm: x86.AMOVL,
+ name: "MOVBstore",
+ auxType: auxSymOff,
+ argLen: 3,
+ clobberFlags: true,
+ faultOnNilArg0: true,
+ asm: s390x.AMOVB,
reg: regInfo{
inputs: []inputInfo{
- {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
- },
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 4295021566}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP SB
+ {1, 54271}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP
},
},
},
{
- name: "MOVLloadidx4",
- auxType: auxSymOff,
- argLen: 3,
- asm: x86.AMOVL,
+ name: "MOVHstore",
+ auxType: auxSymOff,
+ argLen: 3,
+ clobberFlags: true,
+ faultOnNilArg0: true,
+ asm: s390x.AMOVH,
reg: regInfo{
inputs: []inputInfo{
- {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
- },
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 4295021566}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP SB
+ {1, 54271}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP
},
},
},
{
- name: "MOVQloadidx1",
- auxType: auxSymOff,
- argLen: 3,
- asm: x86.AMOVQ,
+ name: "MOVWstore",
+ auxType: auxSymOff,
+ argLen: 3,
+ clobberFlags: true,
+ faultOnNilArg0: true,
+ asm: s390x.AMOVW,
reg: regInfo{
inputs: []inputInfo{
- {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
- },
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 4295021566}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP SB
+ {1, 54271}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP
},
},
},
{
- name: "MOVQloadidx8",
- auxType: auxSymOff,
- argLen: 3,
- asm: x86.AMOVQ,
+ name: "MOVDstore",
+ auxType: auxSymOff,
+ argLen: 3,
+ clobberFlags: true,
+ faultOnNilArg0: true,
+ asm: s390x.AMOVD,
reg: regInfo{
inputs: []inputInfo{
- {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
- },
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 4295021566}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP SB
+ {1, 54271}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP
},
},
},
{
- name: "MOVBstoreidx1",
- auxType: auxSymOff,
- argLen: 4,
- asm: x86.AMOVB,
+ name: "MOVHBRstore",
+ auxType: auxSymOff,
+ argLen: 3,
+ clobberFlags: true,
+ faultOnNilArg0: true,
+ asm: s390x.AMOVHBR,
reg: regInfo{
inputs: []inputInfo{
- {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- {2, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+ {0, 54270}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP
+ {1, 54271}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP
},
},
},
{
- name: "MOVWstoreidx1",
- auxType: auxSymOff,
- argLen: 4,
- asm: x86.AMOVW,
+ name: "MOVWBRstore",
+ auxType: auxSymOff,
+ argLen: 3,
+ clobberFlags: true,
+ faultOnNilArg0: true,
+ asm: s390x.AMOVWBR,
reg: regInfo{
inputs: []inputInfo{
- {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- {2, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+ {0, 54270}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP
+ {1, 54271}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP
},
},
},
{
- name: "MOVWstoreidx2",
- auxType: auxSymOff,
- argLen: 4,
- asm: x86.AMOVW,
+ name: "MOVDBRstore",
+ auxType: auxSymOff,
+ argLen: 3,
+ clobberFlags: true,
+ faultOnNilArg0: true,
+ asm: s390x.AMOVDBR,
reg: regInfo{
inputs: []inputInfo{
- {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- {2, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+ {0, 54270}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP
+ {1, 54271}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP
},
},
},
{
- name: "MOVLstoreidx1",
- auxType: auxSymOff,
- argLen: 4,
- asm: x86.AMOVL,
+ name: "MVC",
+ auxType: auxSymValAndOff,
+ argLen: 3,
+ clobberFlags: true,
+ faultOnNilArg0: true,
+ faultOnNilArg1: true,
+ asm: s390x.AMVC,
reg: regInfo{
inputs: []inputInfo{
- {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- {2, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+ {0, 54270}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP
+ {1, 54270}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP
},
},
},
{
- name: "MOVLstoreidx4",
- auxType: auxSymOff,
- argLen: 4,
- asm: x86.AMOVL,
+ name: "MOVBZloadidx",
+ auxType: auxSymOff,
+ argLen: 3,
+ clobberFlags: true,
+ asm: s390x.AMOVBZ,
reg: regInfo{
inputs: []inputInfo{
- {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- {2, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+ {1, 54270}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP
+ {0, 4295021566}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP SB
+ },
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
},
},
{
- name: "MOVQstoreidx1",
- auxType: auxSymOff,
- argLen: 4,
- asm: x86.AMOVQ,
+ name: "MOVHZloadidx",
+ auxType: auxSymOff,
+ argLen: 3,
+ clobberFlags: true,
+ asm: s390x.AMOVHZ,
reg: regInfo{
inputs: []inputInfo{
- {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- {2, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+ {1, 54270}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP
+ {0, 4295021566}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP SB
+ },
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
},
},
{
- name: "MOVQstoreidx8",
- auxType: auxSymOff,
- argLen: 4,
- asm: x86.AMOVQ,
+ name: "MOVWZloadidx",
+ auxType: auxSymOff,
+ argLen: 3,
+ clobberFlags: true,
+ asm: s390x.AMOVWZ,
reg: regInfo{
inputs: []inputInfo{
- {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- {2, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+ {1, 54270}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP
+ {0, 4295021566}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP SB
+ },
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
},
},
{
- name: "MOVBstoreconst",
- auxType: auxSymValAndOff,
- argLen: 2,
- asm: x86.AMOVB,
+ name: "MOVDloadidx",
+ auxType: auxSymOff,
+ argLen: 3,
+ clobberFlags: true,
+ asm: s390x.AMOVD,
reg: regInfo{
inputs: []inputInfo{
- {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+ {1, 54270}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP
+ {0, 4295021566}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP SB
+ },
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
},
},
{
- name: "MOVWstoreconst",
- auxType: auxSymValAndOff,
- argLen: 2,
- asm: x86.AMOVW,
+ name: "MOVHBRloadidx",
+ auxType: auxSymOff,
+ argLen: 3,
+ clobberFlags: true,
+ asm: s390x.AMOVHBR,
reg: regInfo{
inputs: []inputInfo{
- {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+ {1, 54270}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP
+ {0, 4295021566}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP SB
+ },
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
},
},
{
- name: "MOVLstoreconst",
- auxType: auxSymValAndOff,
- argLen: 2,
- asm: x86.AMOVL,
+ name: "MOVWBRloadidx",
+ auxType: auxSymOff,
+ argLen: 3,
+ clobberFlags: true,
+ asm: s390x.AMOVWBR,
reg: regInfo{
inputs: []inputInfo{
- {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+ {1, 54270}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP
+ {0, 4295021566}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP SB
+ },
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
},
},
{
- name: "MOVQstoreconst",
- auxType: auxSymValAndOff,
- argLen: 2,
- asm: x86.AMOVQ,
+ name: "MOVDBRloadidx",
+ auxType: auxSymOff,
+ argLen: 3,
+ clobberFlags: true,
+ asm: s390x.AMOVDBR,
reg: regInfo{
inputs: []inputInfo{
- {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+ {1, 54270}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP
+ {0, 4295021566}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP SB
+ },
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
},
},
{
- name: "MOVBstoreconstidx1",
- auxType: auxSymValAndOff,
- argLen: 3,
- asm: x86.AMOVB,
+ name: "MOVBstoreidx",
+ auxType: auxSymOff,
+ argLen: 4,
+ clobberFlags: true,
+ asm: s390x.AMOVB,
reg: regInfo{
inputs: []inputInfo{
- {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+ {0, 54270}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP
+ {1, 54270}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP
+ {2, 54271}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP
},
},
},
{
- name: "MOVWstoreconstidx1",
- auxType: auxSymValAndOff,
- argLen: 3,
- asm: x86.AMOVW,
+ name: "MOVHstoreidx",
+ auxType: auxSymOff,
+ argLen: 4,
+ clobberFlags: true,
+ asm: s390x.AMOVH,
reg: regInfo{
inputs: []inputInfo{
- {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+ {0, 54270}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP
+ {1, 54270}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP
+ {2, 54271}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP
},
},
},
{
- name: "MOVWstoreconstidx2",
- auxType: auxSymValAndOff,
- argLen: 3,
- asm: x86.AMOVW,
+ name: "MOVWstoreidx",
+ auxType: auxSymOff,
+ argLen: 4,
+ clobberFlags: true,
+ asm: s390x.AMOVW,
reg: regInfo{
inputs: []inputInfo{
- {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+ {0, 54270}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP
+ {1, 54270}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP
+ {2, 54271}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP
},
},
},
{
- name: "MOVLstoreconstidx1",
- auxType: auxSymValAndOff,
- argLen: 3,
- asm: x86.AMOVL,
+ name: "MOVDstoreidx",
+ auxType: auxSymOff,
+ argLen: 4,
+ clobberFlags: true,
+ asm: s390x.AMOVD,
reg: regInfo{
inputs: []inputInfo{
- {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+ {0, 54270}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP
+ {1, 54270}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP
+ {2, 54271}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP
},
},
},
{
- name: "MOVLstoreconstidx4",
- auxType: auxSymValAndOff,
- argLen: 3,
- asm: x86.AMOVL,
+ name: "MOVHBRstoreidx",
+ auxType: auxSymOff,
+ argLen: 4,
+ clobberFlags: true,
+ asm: s390x.AMOVHBR,
reg: regInfo{
inputs: []inputInfo{
- {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+ {0, 54270}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP
+ {1, 54270}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP
+ {2, 54271}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP
},
},
},
{
- name: "MOVQstoreconstidx1",
- auxType: auxSymValAndOff,
- argLen: 3,
- asm: x86.AMOVQ,
+ name: "MOVWBRstoreidx",
+ auxType: auxSymOff,
+ argLen: 4,
+ clobberFlags: true,
+ asm: s390x.AMOVWBR,
reg: regInfo{
inputs: []inputInfo{
- {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+ {0, 54270}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP
+ {1, 54270}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP
+ {2, 54271}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP
},
},
},
{
- name: "MOVQstoreconstidx8",
- auxType: auxSymValAndOff,
- argLen: 3,
- asm: x86.AMOVQ,
+ name: "MOVDBRstoreidx",
+ auxType: auxSymOff,
+ argLen: 4,
+ clobberFlags: true,
+ asm: s390x.AMOVDBR,
reg: regInfo{
inputs: []inputInfo{
- {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB
+ {0, 54270}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP
+ {1, 54270}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP
+ {2, 54271}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP
},
},
},
{
- name: "DUFFZERO",
- auxType: auxInt64,
- argLen: 3,
+ name: "MOVBstoreconst",
+ auxType: auxSymValAndOff,
+ argLen: 2,
+ clobberFlags: true,
+ faultOnNilArg0: true,
+ asm: s390x.AMOVB,
reg: regInfo{
inputs: []inputInfo{
- {0, 128}, // DI
- {1, 65536}, // X0
+ {0, 4295021566}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP SB
},
- clobbers: 8589934720, // DI FLAGS
},
},
{
- name: "MOVOconst",
- auxType: auxInt128,
- argLen: 0,
- rematerializeable: true,
+ name: "MOVHstoreconst",
+ auxType: auxSymValAndOff,
+ argLen: 2,
+ clobberFlags: true,
+ faultOnNilArg0: true,
+ asm: s390x.AMOVH,
reg: regInfo{
- outputs: []regMask{
- 4294901760, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15
+ inputs: []inputInfo{
+ {0, 4295021566}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP SB
},
},
},
{
- name: "REPSTOSQ",
- argLen: 4,
+ name: "MOVWstoreconst",
+ auxType: auxSymValAndOff,
+ argLen: 2,
+ clobberFlags: true,
+ faultOnNilArg0: true,
+ asm: s390x.AMOVW,
reg: regInfo{
inputs: []inputInfo{
- {0, 128}, // DI
- {1, 2}, // CX
- {2, 1}, // AX
+ {0, 4295021566}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP SB
},
- clobbers: 130, // CX DI
},
},
{
- name: "CALLstatic",
- auxType: auxSymOff,
- argLen: 1,
+ name: "MOVDstoreconst",
+ auxType: auxSymValAndOff,
+ argLen: 2,
+ clobberFlags: true,
+ faultOnNilArg0: true,
+ asm: s390x.AMOVD,
reg: regInfo{
- clobbers: 12884901871, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 FLAGS
+ inputs: []inputInfo{
+ {0, 4295021566}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP SB
+ },
},
},
{
- name: "CALLclosure",
- auxType: auxInt64,
- argLen: 3,
+ name: "CLEAR",
+ auxType: auxSymValAndOff,
+ argLen: 2,
+ clobberFlags: true,
+ faultOnNilArg0: true,
+ asm: s390x.ACLEAR,
reg: regInfo{
inputs: []inputInfo{
- {1, 4}, // DX
- {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 21502}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
- clobbers: 12884901871, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 FLAGS
},
},
{
- name: "CALLdefer",
- auxType: auxInt64,
- argLen: 1,
+ name: "CALLstatic",
+ auxType: auxSymOff,
+ argLen: 1,
+ clobberFlags: true,
+ call: true,
reg: regInfo{
- clobbers: 12884901871, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 FLAGS
+ 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,
+ name: "CALLclosure",
+ auxType: auxInt64,
+ argLen: 3,
+ clobberFlags: true,
+ call: true,
reg: regInfo{
- clobbers: 12884901871, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 FLAGS
+ 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: "CALLinter",
- auxType: auxInt64,
- argLen: 2,
+ name: "CALLdefer",
+ auxType: auxInt64,
+ argLen: 1,
+ clobberFlags: true,
+ call: true,
reg: regInfo{
- inputs: []inputInfo{
- {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
- },
- clobbers: 12884901871, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 FLAGS
+ 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: "DUFFCOPY",
- auxType: auxInt64,
- argLen: 3,
+ name: "CALLgo",
+ auxType: auxInt64,
+ argLen: 1,
+ clobberFlags: true,
+ call: true,
reg: regInfo{
- inputs: []inputInfo{
- {0, 128}, // DI
- {1, 64}, // SI
- },
- clobbers: 8590000320, // SI DI X0 FLAGS
+ 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: "REPMOVSQ",
- argLen: 4,
+ name: "CALLinter",
+ auxType: auxInt64,
+ argLen: 2,
+ clobberFlags: true,
+ call: true,
reg: regInfo{
inputs: []inputInfo{
- {0, 128}, // DI
- {1, 64}, // SI
- {2, 2}, // CX
+ {0, 21502}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
- clobbers: 194, // CX SI DI
+ 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
},
},
{
@@ -3735,8 +19382,8 @@ var opcodeTable = [...]opInfo{
name: "LoweredGetG",
argLen: 1,
reg: regInfo{
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
},
},
@@ -3744,31 +19391,33 @@ var opcodeTable = [...]opInfo{
name: "LoweredGetClosurePtr",
argLen: 0,
reg: regInfo{
- outputs: []regMask{
- 4, // DX
+ outputs: []outputInfo{
+ {0, 4096}, // R12
},
},
},
{
- name: "LoweredNilCheck",
- argLen: 2,
+ name: "LoweredNilCheck",
+ argLen: 2,
+ clobberFlags: true,
+ nilCheck: true,
+ faultOnNilArg0: true,
reg: regInfo{
inputs: []inputInfo{
- {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 54270}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP
},
- clobbers: 8589934592, // FLAGS
},
},
{
- name: "MOVQconvert",
+ name: "MOVDconvert",
argLen: 2,
- asm: x86.AMOVQ,
+ asm: s390x.AMOVD,
reg: regInfo{
inputs: []inputInfo{
- {0, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 54271}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP
},
- outputs: []regMask{
- 65519, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
},
},
},
@@ -3778,125 +19427,321 @@ var opcodeTable = [...]opInfo{
reg: regInfo{},
},
{
- name: "FlagLT_ULT",
+ name: "FlagLT",
argLen: 0,
reg: regInfo{},
},
{
- name: "FlagLT_UGT",
+ name: "FlagGT",
argLen: 0,
reg: regInfo{},
},
{
- name: "FlagGT_UGT",
- argLen: 0,
+ name: "MOVWZatomicload",
+ auxType: auxSymOff,
+ argLen: 2,
+ faultOnNilArg0: true,
+ asm: s390x.AMOVWZ,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 4295021566}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP SB
+ },
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ },
+ },
+ {
+ name: "MOVDatomicload",
+ auxType: auxSymOff,
+ argLen: 2,
+ faultOnNilArg0: true,
+ asm: s390x.AMOVD,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 4295021566}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP SB
+ },
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ },
+ },
+ {
+ name: "MOVWatomicstore",
+ auxType: auxSymOff,
+ argLen: 3,
+ clobberFlags: true,
+ faultOnNilArg0: true,
+ asm: s390x.AMOVW,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 4295021566}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP SB
+ {1, 54271}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP
+ },
+ },
+ },
+ {
+ name: "MOVDatomicstore",
+ auxType: auxSymOff,
+ argLen: 3,
+ clobberFlags: true,
+ faultOnNilArg0: true,
+ asm: s390x.AMOVD,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 4295021566}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP SB
+ {1, 54271}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP
+ },
+ },
+ },
+ {
+ name: "LAA",
+ auxType: auxSymOff,
+ argLen: 3,
+ faultOnNilArg0: true,
+ asm: s390x.ALAA,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 4295021566}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP SB
+ {1, 54271}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP
+ },
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ },
+ },
+ {
+ name: "LAAG",
+ auxType: auxSymOff,
+ argLen: 3,
+ faultOnNilArg0: true,
+ asm: s390x.ALAAG,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 4295021566}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP SB
+ {1, 54271}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP
+ },
+ outputs: []outputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ },
+ },
+ {
+ name: "AddTupleFirst32",
+ argLen: 2,
reg: regInfo{},
},
{
- name: "FlagGT_ULT",
- argLen: 0,
+ name: "AddTupleFirst64",
+ argLen: 2,
reg: regInfo{},
},
-
{
- name: "ADD",
- argLen: 2,
- commutative: true,
- asm: arm.AADD,
+ name: "LoweredAtomicCas32",
+ auxType: auxSymOff,
+ argLen: 4,
+ clobberFlags: true,
+ faultOnNilArg0: true,
+ asm: s390x.ACS,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 1}, // R0
+ {0, 54270}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP
+ {2, 54271}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP
+ },
+ clobbers: 1, // R0
+ outputs: []outputInfo{
+ {1, 0},
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ },
+ },
+ {
+ name: "LoweredAtomicCas64",
+ auxType: auxSymOff,
+ argLen: 4,
+ clobberFlags: true,
+ faultOnNilArg0: true,
+ asm: s390x.ACSG,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 1}, // R0
+ {0, 54270}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP
+ {2, 54271}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP
+ },
+ clobbers: 1, // R0
+ outputs: []outputInfo{
+ {1, 0},
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ },
+ },
+ {
+ name: "LoweredAtomicExchange32",
+ auxType: auxSymOff,
+ argLen: 3,
+ clobberFlags: true,
+ faultOnNilArg0: true,
+ asm: s390x.ACS,
reg: regInfo{
inputs: []inputInfo{
- {0, 31}, // R0 R1 R2 R3 SP
- {1, 31}, // R0 R1 R2 R3 SP
+ {0, 54270}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP
+ {1, 54270}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP
},
- outputs: []regMask{
- 31, // R0 R1 R2 R3 SP
+ outputs: []outputInfo{
+ {1, 0},
+ {0, 1}, // R0
},
},
},
{
- name: "ADDconst",
- auxType: auxSymOff,
- argLen: 1,
- asm: arm.AADD,
+ name: "LoweredAtomicExchange64",
+ auxType: auxSymOff,
+ argLen: 3,
+ clobberFlags: true,
+ faultOnNilArg0: true,
+ asm: s390x.ACSG,
reg: regInfo{
inputs: []inputInfo{
- {0, 31}, // R0 R1 R2 R3 SP
+ {0, 54270}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP
+ {1, 54270}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP
},
- outputs: []regMask{
- 31, // R0 R1 R2 R3 SP
+ outputs: []outputInfo{
+ {1, 0},
+ {0, 1}, // R0
},
},
},
{
- name: "MOVWconst",
- auxType: auxInt32,
- argLen: 0,
- rematerializeable: true,
- asm: arm.AMOVW,
+ name: "FLOGR",
+ argLen: 1,
+ clobberFlags: true,
+ asm: s390x.AFLOGR,
reg: regInfo{
- outputs: []regMask{
- 31, // R0 R1 R2 R3 SP
+ inputs: []inputInfo{
+ {0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
+ },
+ clobbers: 2, // R1
+ outputs: []outputInfo{
+ {0, 1}, // R0
},
},
},
{
- name: "CMP",
- argLen: 2,
- asm: arm.ACMP,
+ name: "STMG2",
+ auxType: auxSymOff,
+ argLen: 4,
+ faultOnNilArg0: true,
+ asm: s390x.ASTMG,
reg: regInfo{
inputs: []inputInfo{
- {0, 31}, // R0 R1 R2 R3 SP
- {1, 31}, // R0 R1 R2 R3 SP
+ {1, 2}, // R1
+ {2, 4}, // R2
+ {0, 54270}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP
},
- outputs: []regMask{
- 32, // FLAGS
+ },
+ },
+ {
+ name: "STMG3",
+ auxType: auxSymOff,
+ argLen: 5,
+ faultOnNilArg0: true,
+ asm: s390x.ASTMG,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 2}, // R1
+ {2, 4}, // R2
+ {3, 8}, // R3
+ {0, 54270}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP
},
},
},
{
- name: "MOVWload",
- auxType: auxSymOff,
- argLen: 2,
- asm: arm.AMOVW,
+ name: "STMG4",
+ auxType: auxSymOff,
+ argLen: 6,
+ faultOnNilArg0: true,
+ asm: s390x.ASTMG,
reg: regInfo{
inputs: []inputInfo{
- {0, 31}, // R0 R1 R2 R3 SP
+ {1, 2}, // R1
+ {2, 4}, // R2
+ {3, 8}, // R3
+ {4, 16}, // R4
+ {0, 54270}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP
},
- outputs: []regMask{
- 31, // R0 R1 R2 R3 SP
+ },
+ },
+ {
+ name: "STM2",
+ auxType: auxSymOff,
+ argLen: 4,
+ faultOnNilArg0: true,
+ asm: s390x.ASTMY,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 2}, // R1
+ {2, 4}, // R2
+ {0, 54270}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP
},
},
},
{
- name: "MOVWstore",
- auxType: auxSymOff,
- argLen: 3,
- asm: arm.AMOVW,
+ name: "STM3",
+ auxType: auxSymOff,
+ argLen: 5,
+ faultOnNilArg0: true,
+ asm: s390x.ASTMY,
reg: regInfo{
inputs: []inputInfo{
- {0, 31}, // R0 R1 R2 R3 SP
- {1, 31}, // R0 R1 R2 R3 SP
+ {1, 2}, // R1
+ {2, 4}, // R2
+ {3, 8}, // R3
+ {0, 54270}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP
},
},
},
{
- name: "CALLstatic",
- auxType: auxSymOff,
- argLen: 1,
+ name: "STM4",
+ auxType: auxSymOff,
+ argLen: 6,
+ faultOnNilArg0: true,
+ asm: s390x.ASTMY,
reg: regInfo{
- clobbers: 15, // R0 R1 R2 R3
+ inputs: []inputInfo{
+ {1, 2}, // R1
+ {2, 4}, // R2
+ {3, 8}, // R3
+ {4, 16}, // R4
+ {0, 54270}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP
+ },
},
},
{
- name: "LessThan",
- argLen: 1,
+ name: "LoweredMove",
+ auxType: auxInt64,
+ argLen: 4,
+ clobberFlags: true,
reg: regInfo{
inputs: []inputInfo{
- {0, 32}, // FLAGS
+ {0, 2}, // R1
+ {1, 4}, // R2
+ {2, 54271}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP
},
- outputs: []regMask{
- 31, // R0 R1 R2 R3 SP
+ clobbers: 6, // R1 R2
+ },
+ },
+ {
+ name: "LoweredZero",
+ auxType: auxInt64,
+ argLen: 3,
+ clobberFlags: true,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {0, 2}, // R1
+ {1, 54271}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14 SP
},
+ clobbers: 2, // R1
},
},
@@ -4059,6 +19904,16 @@ var opcodeTable = [...]opInfo{
generic: true,
},
{
+ name: "Mul32uhilo",
+ argLen: 2,
+ generic: true,
+ },
+ {
+ name: "Mul64uhilo",
+ argLen: 2,
+ generic: true,
+ },
+ {
name: "Avg64u",
argLen: 2,
generic: true,
@@ -4104,6 +19959,11 @@ var opcodeTable = [...]opInfo{
generic: true,
},
{
+ name: "Div128u",
+ argLen: 3,
+ generic: true,
+ },
+ {
name: "Mod8",
argLen: 2,
generic: true,
@@ -4855,11 +20715,6 @@ var opcodeTable = [...]opInfo{
generic: true,
},
{
- name: "Ctz16",
- argLen: 1,
- generic: true,
- },
- {
name: "Ctz32",
argLen: 1,
generic: true,
@@ -4870,21 +20725,6 @@ var opcodeTable = [...]opInfo{
generic: true,
},
{
- name: "Clz16",
- argLen: 1,
- generic: true,
- },
- {
- name: "Clz32",
- argLen: 1,
- generic: true,
- },
- {
- name: "Clz64",
- argLen: 1,
- generic: true,
- },
- {
name: "Bswap32",
argLen: 1,
generic: true,
@@ -5023,13 +20863,37 @@ var opcodeTable = [...]opInfo{
},
{
name: "Move",
- auxType: auxInt64,
+ auxType: auxSizeAndAlign,
argLen: 3,
generic: true,
},
{
name: "Zero",
+ auxType: auxSizeAndAlign,
+ argLen: 2,
+ generic: true,
+ },
+ {
+ name: "StoreWB",
auxType: auxInt64,
+ argLen: 3,
+ generic: true,
+ },
+ {
+ name: "MoveWB",
+ auxType: auxSymSizeAndAlign,
+ argLen: 3,
+ generic: true,
+ },
+ {
+ name: "MoveWBVolatile",
+ auxType: auxSymSizeAndAlign,
+ argLen: 3,
+ generic: true,
+ },
+ {
+ name: "ZeroWB",
+ auxType: auxSymSizeAndAlign,
argLen: 2,
generic: true,
},
@@ -5037,30 +20901,35 @@ var opcodeTable = [...]opInfo{
name: "ClosureCall",
auxType: auxInt64,
argLen: 3,
+ call: true,
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: "InterCall",
auxType: auxInt64,
argLen: 2,
+ call: true,
generic: true,
},
{
@@ -5234,12 +21103,6 @@ var opcodeTable = [...]opInfo{
generic: true,
},
{
- name: "ArrayIndex",
- auxType: auxInt64,
- argLen: 1,
- generic: true,
- },
- {
name: "PtrIndex",
argLen: 2,
generic: true,
@@ -5347,6 +21210,22 @@ var opcodeTable = [...]opInfo{
generic: true,
},
{
+ name: "ArrayMake0",
+ argLen: 0,
+ generic: true,
+ },
+ {
+ name: "ArrayMake1",
+ argLen: 1,
+ generic: true,
+ },
+ {
+ name: "ArraySelect",
+ auxType: auxInt64,
+ argLen: 1,
+ generic: true,
+ },
+ {
name: "StoreReg",
argLen: 1,
generic: true,
@@ -5390,53 +21269,592 @@ var opcodeTable = [...]opInfo{
argLen: 2,
generic: true,
},
+ {
+ name: "Int64Make",
+ argLen: 2,
+ generic: true,
+ },
+ {
+ name: "Int64Hi",
+ argLen: 1,
+ generic: true,
+ },
+ {
+ name: "Int64Lo",
+ argLen: 1,
+ generic: true,
+ },
+ {
+ name: "Add32carry",
+ argLen: 2,
+ commutative: true,
+ generic: true,
+ },
+ {
+ name: "Add32withcarry",
+ argLen: 3,
+ commutative: true,
+ generic: true,
+ },
+ {
+ name: "Sub32carry",
+ argLen: 2,
+ generic: true,
+ },
+ {
+ name: "Sub32withcarry",
+ argLen: 3,
+ generic: true,
+ },
+ {
+ name: "Signmask",
+ argLen: 1,
+ generic: true,
+ },
+ {
+ name: "Zeromask",
+ argLen: 1,
+ generic: true,
+ },
+ {
+ name: "Slicemask",
+ argLen: 1,
+ generic: true,
+ },
+ {
+ name: "Cvt32Uto32F",
+ argLen: 1,
+ generic: true,
+ },
+ {
+ name: "Cvt32Uto64F",
+ argLen: 1,
+ generic: true,
+ },
+ {
+ name: "Cvt32Fto32U",
+ argLen: 1,
+ generic: true,
+ },
+ {
+ name: "Cvt64Fto32U",
+ argLen: 1,
+ generic: true,
+ },
+ {
+ name: "Cvt64Uto32F",
+ argLen: 1,
+ generic: true,
+ },
+ {
+ name: "Cvt64Uto64F",
+ argLen: 1,
+ generic: true,
+ },
+ {
+ name: "Cvt32Fto64U",
+ argLen: 1,
+ generic: true,
+ },
+ {
+ name: "Cvt64Fto64U",
+ argLen: 1,
+ generic: true,
+ },
+ {
+ name: "Select0",
+ argLen: 1,
+ generic: true,
+ },
+ {
+ name: "Select1",
+ argLen: 1,
+ generic: true,
+ },
+ {
+ name: "AtomicLoad32",
+ argLen: 2,
+ generic: true,
+ },
+ {
+ name: "AtomicLoad64",
+ argLen: 2,
+ generic: true,
+ },
+ {
+ name: "AtomicLoadPtr",
+ argLen: 2,
+ generic: true,
+ },
+ {
+ name: "AtomicStore32",
+ argLen: 3,
+ generic: true,
+ },
+ {
+ name: "AtomicStore64",
+ argLen: 3,
+ generic: true,
+ },
+ {
+ name: "AtomicStorePtrNoWB",
+ argLen: 3,
+ generic: true,
+ },
+ {
+ name: "AtomicExchange32",
+ argLen: 3,
+ generic: true,
+ },
+ {
+ name: "AtomicExchange64",
+ argLen: 3,
+ generic: true,
+ },
+ {
+ name: "AtomicAdd32",
+ argLen: 3,
+ generic: true,
+ },
+ {
+ name: "AtomicAdd64",
+ argLen: 3,
+ generic: true,
+ },
+ {
+ name: "AtomicCompareAndSwap32",
+ argLen: 4,
+ generic: true,
+ },
+ {
+ name: "AtomicCompareAndSwap64",
+ argLen: 4,
+ generic: true,
+ },
+ {
+ name: "AtomicAnd8",
+ argLen: 3,
+ generic: true,
+ },
+ {
+ name: "AtomicOr8",
+ argLen: 3,
+ generic: true,
+ },
}
-func (o Op) Asm() obj.As { return opcodeTable[o].asm }
-func (o Op) String() string { return opcodeTable[o].name }
+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 }
+var registers386 = [...]Register{
+ {0, x86.REG_AX, "AX"},
+ {1, x86.REG_CX, "CX"},
+ {2, x86.REG_DX, "DX"},
+ {3, x86.REG_BX, "BX"},
+ {4, x86.REGSP, "SP"},
+ {5, x86.REG_BP, "BP"},
+ {6, x86.REG_SI, "SI"},
+ {7, x86.REG_DI, "DI"},
+ {8, x86.REG_X0, "X0"},
+ {9, x86.REG_X1, "X1"},
+ {10, x86.REG_X2, "X2"},
+ {11, x86.REG_X3, "X3"},
+ {12, x86.REG_X4, "X4"},
+ {13, x86.REG_X5, "X5"},
+ {14, x86.REG_X6, "X6"},
+ {15, x86.REG_X7, "X7"},
+ {16, 0, "SB"},
+}
+var gpRegMask386 = regMask(239)
+var fpRegMask386 = regMask(65280)
+var specialRegMask386 = regMask(0)
+var framepointerReg386 = int8(5)
+var linkReg386 = int8(-1)
var registersAMD64 = [...]Register{
- {0, "AX"},
- {1, "CX"},
- {2, "DX"},
- {3, "BX"},
- {4, "SP"},
- {5, "BP"},
- {6, "SI"},
- {7, "DI"},
- {8, "R8"},
- {9, "R9"},
- {10, "R10"},
- {11, "R11"},
- {12, "R12"},
- {13, "R13"},
- {14, "R14"},
- {15, "R15"},
- {16, "X0"},
- {17, "X1"},
- {18, "X2"},
- {19, "X3"},
- {20, "X4"},
- {21, "X5"},
- {22, "X6"},
- {23, "X7"},
- {24, "X8"},
- {25, "X9"},
- {26, "X10"},
- {27, "X11"},
- {28, "X12"},
- {29, "X13"},
- {30, "X14"},
- {31, "X15"},
- {32, "SB"},
- {33, "FLAGS"},
+ {0, x86.REG_AX, "AX"},
+ {1, x86.REG_CX, "CX"},
+ {2, x86.REG_DX, "DX"},
+ {3, x86.REG_BX, "BX"},
+ {4, x86.REGSP, "SP"},
+ {5, x86.REG_BP, "BP"},
+ {6, x86.REG_SI, "SI"},
+ {7, x86.REG_DI, "DI"},
+ {8, x86.REG_R8, "R8"},
+ {9, x86.REG_R9, "R9"},
+ {10, x86.REG_R10, "R10"},
+ {11, x86.REG_R11, "R11"},
+ {12, x86.REG_R12, "R12"},
+ {13, x86.REG_R13, "R13"},
+ {14, x86.REG_R14, "R14"},
+ {15, x86.REG_R15, "R15"},
+ {16, x86.REG_X0, "X0"},
+ {17, x86.REG_X1, "X1"},
+ {18, x86.REG_X2, "X2"},
+ {19, x86.REG_X3, "X3"},
+ {20, x86.REG_X4, "X4"},
+ {21, x86.REG_X5, "X5"},
+ {22, x86.REG_X6, "X6"},
+ {23, x86.REG_X7, "X7"},
+ {24, x86.REG_X8, "X8"},
+ {25, x86.REG_X9, "X9"},
+ {26, x86.REG_X10, "X10"},
+ {27, x86.REG_X11, "X11"},
+ {28, x86.REG_X12, "X12"},
+ {29, x86.REG_X13, "X13"},
+ {30, x86.REG_X14, "X14"},
+ {31, x86.REG_X15, "X15"},
+ {32, 0, "SB"},
}
+var gpRegMaskAMD64 = regMask(65519)
+var fpRegMaskAMD64 = regMask(4294901760)
+var specialRegMaskAMD64 = regMask(0)
+var framepointerRegAMD64 = int8(5)
+var linkRegAMD64 = int8(-1)
var registersARM = [...]Register{
- {0, "R0"},
- {1, "R1"},
- {2, "R2"},
- {3, "R3"},
- {4, "SP"},
- {5, "FLAGS"},
- {6, "SB"},
+ {0, arm.REG_R0, "R0"},
+ {1, arm.REG_R1, "R1"},
+ {2, arm.REG_R2, "R2"},
+ {3, arm.REG_R3, "R3"},
+ {4, arm.REG_R4, "R4"},
+ {5, arm.REG_R5, "R5"},
+ {6, arm.REG_R6, "R6"},
+ {7, arm.REG_R7, "R7"},
+ {8, arm.REG_R8, "R8"},
+ {9, arm.REG_R9, "R9"},
+ {10, arm.REGG, "g"},
+ {11, arm.REG_R11, "R11"},
+ {12, arm.REG_R12, "R12"},
+ {13, arm.REGSP, "SP"},
+ {14, arm.REG_R14, "R14"},
+ {15, arm.REG_R15, "R15"},
+ {16, arm.REG_F0, "F0"},
+ {17, arm.REG_F1, "F1"},
+ {18, arm.REG_F2, "F2"},
+ {19, arm.REG_F3, "F3"},
+ {20, arm.REG_F4, "F4"},
+ {21, arm.REG_F5, "F5"},
+ {22, arm.REG_F6, "F6"},
+ {23, arm.REG_F7, "F7"},
+ {24, arm.REG_F8, "F8"},
+ {25, arm.REG_F9, "F9"},
+ {26, arm.REG_F10, "F10"},
+ {27, arm.REG_F11, "F11"},
+ {28, arm.REG_F12, "F12"},
+ {29, arm.REG_F13, "F13"},
+ {30, arm.REG_F14, "F14"},
+ {31, arm.REG_F15, "F15"},
+ {32, 0, "SB"},
+}
+var gpRegMaskARM = regMask(21503)
+var fpRegMaskARM = regMask(4294901760)
+var specialRegMaskARM = regMask(0)
+var framepointerRegARM = int8(-1)
+var linkRegARM = int8(14)
+var registersARM64 = [...]Register{
+ {0, arm64.REG_R0, "R0"},
+ {1, arm64.REG_R1, "R1"},
+ {2, arm64.REG_R2, "R2"},
+ {3, arm64.REG_R3, "R3"},
+ {4, arm64.REG_R4, "R4"},
+ {5, arm64.REG_R5, "R5"},
+ {6, arm64.REG_R6, "R6"},
+ {7, arm64.REG_R7, "R7"},
+ {8, arm64.REG_R8, "R8"},
+ {9, arm64.REG_R9, "R9"},
+ {10, arm64.REG_R10, "R10"},
+ {11, arm64.REG_R11, "R11"},
+ {12, arm64.REG_R12, "R12"},
+ {13, arm64.REG_R13, "R13"},
+ {14, arm64.REG_R14, "R14"},
+ {15, arm64.REG_R15, "R15"},
+ {16, arm64.REG_R16, "R16"},
+ {17, arm64.REG_R17, "R17"},
+ {18, arm64.REG_R18, "R18"},
+ {19, arm64.REG_R19, "R19"},
+ {20, arm64.REG_R20, "R20"},
+ {21, arm64.REG_R21, "R21"},
+ {22, arm64.REG_R22, "R22"},
+ {23, arm64.REG_R23, "R23"},
+ {24, arm64.REG_R24, "R24"},
+ {25, arm64.REG_R25, "R25"},
+ {26, arm64.REG_R26, "R26"},
+ {27, arm64.REGG, "g"},
+ {28, arm64.REG_R29, "R29"},
+ {29, arm64.REG_R30, "R30"},
+ {30, arm64.REGSP, "SP"},
+ {31, arm64.REG_F0, "F0"},
+ {32, arm64.REG_F1, "F1"},
+ {33, arm64.REG_F2, "F2"},
+ {34, arm64.REG_F3, "F3"},
+ {35, arm64.REG_F4, "F4"},
+ {36, arm64.REG_F5, "F5"},
+ {37, arm64.REG_F6, "F6"},
+ {38, arm64.REG_F7, "F7"},
+ {39, arm64.REG_F8, "F8"},
+ {40, arm64.REG_F9, "F9"},
+ {41, arm64.REG_F10, "F10"},
+ {42, arm64.REG_F11, "F11"},
+ {43, arm64.REG_F12, "F12"},
+ {44, arm64.REG_F13, "F13"},
+ {45, arm64.REG_F14, "F14"},
+ {46, arm64.REG_F15, "F15"},
+ {47, arm64.REG_F16, "F16"},
+ {48, arm64.REG_F17, "F17"},
+ {49, arm64.REG_F18, "F18"},
+ {50, arm64.REG_F19, "F19"},
+ {51, arm64.REG_F20, "F20"},
+ {52, arm64.REG_F21, "F21"},
+ {53, arm64.REG_F22, "F22"},
+ {54, arm64.REG_F23, "F23"},
+ {55, arm64.REG_F24, "F24"},
+ {56, arm64.REG_F25, "F25"},
+ {57, arm64.REG_F26, "F26"},
+ {58, arm64.REG_F27, "F27"},
+ {59, arm64.REG_F28, "F28"},
+ {60, arm64.REG_F29, "F29"},
+ {61, arm64.REG_F30, "F30"},
+ {62, arm64.REG_F31, "F31"},
+ {63, 0, "SB"},
+}
+var gpRegMaskARM64 = regMask(670826495)
+var fpRegMaskARM64 = regMask(9223372034707292160)
+var specialRegMaskARM64 = regMask(0)
+var framepointerRegARM64 = int8(-1)
+var linkRegARM64 = int8(29)
+var registersMIPS = [...]Register{
+ {0, mips.REG_R0, "R0"},
+ {1, mips.REG_R1, "R1"},
+ {2, mips.REG_R2, "R2"},
+ {3, mips.REG_R3, "R3"},
+ {4, mips.REG_R4, "R4"},
+ {5, mips.REG_R5, "R5"},
+ {6, mips.REG_R6, "R6"},
+ {7, mips.REG_R7, "R7"},
+ {8, mips.REG_R8, "R8"},
+ {9, mips.REG_R9, "R9"},
+ {10, mips.REG_R10, "R10"},
+ {11, mips.REG_R11, "R11"},
+ {12, mips.REG_R12, "R12"},
+ {13, mips.REG_R13, "R13"},
+ {14, mips.REG_R14, "R14"},
+ {15, mips.REG_R15, "R15"},
+ {16, mips.REG_R16, "R16"},
+ {17, mips.REG_R17, "R17"},
+ {18, mips.REG_R18, "R18"},
+ {19, mips.REG_R19, "R19"},
+ {20, mips.REG_R20, "R20"},
+ {21, mips.REG_R21, "R21"},
+ {22, mips.REG_R22, "R22"},
+ {23, mips.REG_R24, "R24"},
+ {24, mips.REG_R25, "R25"},
+ {25, mips.REG_R28, "R28"},
+ {26, mips.REGSP, "SP"},
+ {27, mips.REGG, "g"},
+ {28, mips.REG_R31, "R31"},
+ {29, mips.REG_F0, "F0"},
+ {30, mips.REG_F2, "F2"},
+ {31, mips.REG_F4, "F4"},
+ {32, mips.REG_F6, "F6"},
+ {33, mips.REG_F8, "F8"},
+ {34, mips.REG_F10, "F10"},
+ {35, mips.REG_F12, "F12"},
+ {36, mips.REG_F14, "F14"},
+ {37, mips.REG_F16, "F16"},
+ {38, mips.REG_F18, "F18"},
+ {39, mips.REG_F20, "F20"},
+ {40, mips.REG_F22, "F22"},
+ {41, mips.REG_F24, "F24"},
+ {42, mips.REG_F26, "F26"},
+ {43, mips.REG_F28, "F28"},
+ {44, mips.REG_F30, "F30"},
+ {45, mips.REG_HI, "HI"},
+ {46, mips.REG_LO, "LO"},
+ {47, 0, "SB"},
+}
+var gpRegMaskMIPS = regMask(335544318)
+var fpRegMaskMIPS = regMask(35183835217920)
+var specialRegMaskMIPS = regMask(105553116266496)
+var framepointerRegMIPS = int8(-1)
+var linkRegMIPS = int8(28)
+var registersMIPS64 = [...]Register{
+ {0, mips.REG_R0, "R0"},
+ {1, mips.REG_R1, "R1"},
+ {2, mips.REG_R2, "R2"},
+ {3, mips.REG_R3, "R3"},
+ {4, mips.REG_R4, "R4"},
+ {5, mips.REG_R5, "R5"},
+ {6, mips.REG_R6, "R6"},
+ {7, mips.REG_R7, "R7"},
+ {8, mips.REG_R8, "R8"},
+ {9, mips.REG_R9, "R9"},
+ {10, mips.REG_R10, "R10"},
+ {11, mips.REG_R11, "R11"},
+ {12, mips.REG_R12, "R12"},
+ {13, mips.REG_R13, "R13"},
+ {14, mips.REG_R14, "R14"},
+ {15, mips.REG_R15, "R15"},
+ {16, mips.REG_R16, "R16"},
+ {17, mips.REG_R17, "R17"},
+ {18, mips.REG_R18, "R18"},
+ {19, mips.REG_R19, "R19"},
+ {20, mips.REG_R20, "R20"},
+ {21, mips.REG_R21, "R21"},
+ {22, mips.REG_R22, "R22"},
+ {23, mips.REG_R24, "R24"},
+ {24, mips.REG_R25, "R25"},
+ {25, mips.REGSP, "SP"},
+ {26, mips.REGG, "g"},
+ {27, mips.REG_R31, "R31"},
+ {28, mips.REG_F0, "F0"},
+ {29, mips.REG_F1, "F1"},
+ {30, mips.REG_F2, "F2"},
+ {31, mips.REG_F3, "F3"},
+ {32, mips.REG_F4, "F4"},
+ {33, mips.REG_F5, "F5"},
+ {34, mips.REG_F6, "F6"},
+ {35, mips.REG_F7, "F7"},
+ {36, mips.REG_F8, "F8"},
+ {37, mips.REG_F9, "F9"},
+ {38, mips.REG_F10, "F10"},
+ {39, mips.REG_F11, "F11"},
+ {40, mips.REG_F12, "F12"},
+ {41, mips.REG_F13, "F13"},
+ {42, mips.REG_F14, "F14"},
+ {43, mips.REG_F15, "F15"},
+ {44, mips.REG_F16, "F16"},
+ {45, mips.REG_F17, "F17"},
+ {46, mips.REG_F18, "F18"},
+ {47, mips.REG_F19, "F19"},
+ {48, mips.REG_F20, "F20"},
+ {49, mips.REG_F21, "F21"},
+ {50, mips.REG_F22, "F22"},
+ {51, mips.REG_F23, "F23"},
+ {52, mips.REG_F24, "F24"},
+ {53, mips.REG_F25, "F25"},
+ {54, mips.REG_F26, "F26"},
+ {55, mips.REG_F27, "F27"},
+ {56, mips.REG_F28, "F28"},
+ {57, mips.REG_F29, "F29"},
+ {58, mips.REG_F30, "F30"},
+ {59, mips.REG_F31, "F31"},
+ {60, mips.REG_HI, "HI"},
+ {61, mips.REG_LO, "LO"},
+ {62, 0, "SB"},
+}
+var gpRegMaskMIPS64 = regMask(167772158)
+var fpRegMaskMIPS64 = regMask(1152921504338411520)
+var specialRegMaskMIPS64 = regMask(3458764513820540928)
+var framepointerRegMIPS64 = int8(-1)
+var linkRegMIPS64 = int8(27)
+var registersPPC64 = [...]Register{
+ {0, ppc64.REG_R0, "R0"},
+ {1, ppc64.REGSP, "SP"},
+ {2, 0, "SB"},
+ {3, ppc64.REG_R3, "R3"},
+ {4, ppc64.REG_R4, "R4"},
+ {5, ppc64.REG_R5, "R5"},
+ {6, ppc64.REG_R6, "R6"},
+ {7, ppc64.REG_R7, "R7"},
+ {8, ppc64.REG_R8, "R8"},
+ {9, ppc64.REG_R9, "R9"},
+ {10, ppc64.REG_R10, "R10"},
+ {11, ppc64.REG_R11, "R11"},
+ {12, ppc64.REG_R12, "R12"},
+ {13, ppc64.REG_R13, "R13"},
+ {14, ppc64.REG_R14, "R14"},
+ {15, ppc64.REG_R15, "R15"},
+ {16, ppc64.REG_R16, "R16"},
+ {17, ppc64.REG_R17, "R17"},
+ {18, ppc64.REG_R18, "R18"},
+ {19, ppc64.REG_R19, "R19"},
+ {20, ppc64.REG_R20, "R20"},
+ {21, ppc64.REG_R21, "R21"},
+ {22, ppc64.REG_R22, "R22"},
+ {23, ppc64.REG_R23, "R23"},
+ {24, ppc64.REG_R24, "R24"},
+ {25, ppc64.REG_R25, "R25"},
+ {26, ppc64.REG_R26, "R26"},
+ {27, ppc64.REG_R27, "R27"},
+ {28, ppc64.REG_R28, "R28"},
+ {29, ppc64.REG_R29, "R29"},
+ {30, ppc64.REGG, "g"},
+ {31, ppc64.REG_R31, "R31"},
+ {32, ppc64.REG_F0, "F0"},
+ {33, ppc64.REG_F1, "F1"},
+ {34, ppc64.REG_F2, "F2"},
+ {35, ppc64.REG_F3, "F3"},
+ {36, ppc64.REG_F4, "F4"},
+ {37, ppc64.REG_F5, "F5"},
+ {38, ppc64.REG_F6, "F6"},
+ {39, ppc64.REG_F7, "F7"},
+ {40, ppc64.REG_F8, "F8"},
+ {41, ppc64.REG_F9, "F9"},
+ {42, ppc64.REG_F10, "F10"},
+ {43, ppc64.REG_F11, "F11"},
+ {44, ppc64.REG_F12, "F12"},
+ {45, ppc64.REG_F13, "F13"},
+ {46, ppc64.REG_F14, "F14"},
+ {47, ppc64.REG_F15, "F15"},
+ {48, ppc64.REG_F16, "F16"},
+ {49, ppc64.REG_F17, "F17"},
+ {50, ppc64.REG_F18, "F18"},
+ {51, ppc64.REG_F19, "F19"},
+ {52, ppc64.REG_F20, "F20"},
+ {53, ppc64.REG_F21, "F21"},
+ {54, ppc64.REG_F22, "F22"},
+ {55, ppc64.REG_F23, "F23"},
+ {56, ppc64.REG_F24, "F24"},
+ {57, ppc64.REG_F25, "F25"},
+ {58, ppc64.REG_F26, "F26"},
+ {59, ppc64.REG_F27, "F27"},
+ {60, ppc64.REG_F28, "F28"},
+ {61, ppc64.REG_F29, "F29"},
+ {62, ppc64.REG_F30, "F30"},
+ {63, ppc64.REG_F31, "F31"},
+}
+var gpRegMaskPPC64 = regMask(1073733624)
+var fpRegMaskPPC64 = regMask(576460743713488896)
+var specialRegMaskPPC64 = regMask(0)
+var framepointerRegPPC64 = int8(1)
+var linkRegPPC64 = int8(-1)
+var registersS390X = [...]Register{
+ {0, s390x.REG_R0, "R0"},
+ {1, s390x.REG_R1, "R1"},
+ {2, s390x.REG_R2, "R2"},
+ {3, s390x.REG_R3, "R3"},
+ {4, s390x.REG_R4, "R4"},
+ {5, s390x.REG_R5, "R5"},
+ {6, s390x.REG_R6, "R6"},
+ {7, s390x.REG_R7, "R7"},
+ {8, s390x.REG_R8, "R8"},
+ {9, s390x.REG_R9, "R9"},
+ {10, s390x.REG_R10, "R10"},
+ {11, s390x.REG_R11, "R11"},
+ {12, s390x.REG_R12, "R12"},
+ {13, s390x.REGG, "g"},
+ {14, s390x.REG_R14, "R14"},
+ {15, s390x.REGSP, "SP"},
+ {16, s390x.REG_F0, "F0"},
+ {17, s390x.REG_F1, "F1"},
+ {18, s390x.REG_F2, "F2"},
+ {19, s390x.REG_F3, "F3"},
+ {20, s390x.REG_F4, "F4"},
+ {21, s390x.REG_F5, "F5"},
+ {22, s390x.REG_F6, "F6"},
+ {23, s390x.REG_F7, "F7"},
+ {24, s390x.REG_F8, "F8"},
+ {25, s390x.REG_F9, "F9"},
+ {26, s390x.REG_F10, "F10"},
+ {27, s390x.REG_F11, "F11"},
+ {28, s390x.REG_F12, "F12"},
+ {29, s390x.REG_F13, "F13"},
+ {30, s390x.REG_F14, "F14"},
+ {31, s390x.REG_F15, "F15"},
+ {32, 0, "SB"},
}
+var gpRegMaskS390X = regMask(21503)
+var fpRegMaskS390X = regMask(4294901760)
+var specialRegMaskS390X = regMask(0)
+var framepointerRegS390X = int8(-1)
+var linkRegS390X = int8(14)
diff --git a/src/cmd/compile/internal/ssa/opt.go b/src/cmd/compile/internal/ssa/opt.go
index caf8cca..f211488 100644
--- a/src/cmd/compile/internal/ssa/opt.go
+++ b/src/cmd/compile/internal/ssa/opt.go
@@ -11,4 +11,7 @@ func opt(f *Func) {
func dec(f *Func) {
applyRewrite(f, rewriteBlockdec, rewriteValuedec)
+ if f.Config.IntSize == 4 && f.Config.arch != "amd64p32" {
+ 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 87069ab..e4bb0b8 100644
--- a/src/cmd/compile/internal/ssa/passbm_test.go
+++ b/src/cmd/compile/internal/ssa/passbm_test.go
@@ -35,7 +35,6 @@ func benchFnPass(b *testing.B, fn passFunc, size int, bg blockGen) {
b.ReportAllocs()
c := NewConfig("amd64", DummyFrontend{b}, nil, true)
fun := Fun(c, "entry", bg(size)...)
- domTree(fun.f)
CheckFunc(fun.f)
b.ResetTimer()
for i := 0; i < b.N; i++ {
@@ -51,7 +50,6 @@ func benchFnBlock(b *testing.B, fn passFunc, bg blockGen) {
b.ReportAllocs()
c := NewConfig("amd64", DummyFrontend{b}, nil, true)
fun := Fun(c, "entry", bg(b.N)...)
- domTree(fun.f)
CheckFunc(fun.f)
b.ResetTimer()
for i := 0; i < passCount; i++ {
diff --git a/src/cmd/compile/internal/ssa/phiopt.go b/src/cmd/compile/internal/ssa/phiopt.go
index d6272b4..3e9f195 100644
--- a/src/cmd/compile/internal/ssa/phiopt.go
+++ b/src/cmd/compile/internal/ssa/phiopt.go
@@ -24,6 +24,7 @@ package ssa
//
// In this case we can replace x with a copy of b.
func phiopt(f *Func) {
+ sdom := f.sdom()
for _, b := range f.Blocks {
if len(b.Preds) != 2 || len(b.Values) == 0 {
// TODO: handle more than 2 predecessors, e.g. a || b || c.
@@ -57,7 +58,16 @@ func phiopt(f *Func) {
}
for _, v := range b.Values {
- if v.Op != OpPhi || !v.Type.IsBoolean() {
+ if v.Op != OpPhi {
+ continue
+ }
+
+ // Look for conversions from bool to 0/1.
+ if v.Type.IsInteger() {
+ phioptint(v, b0, reverse)
+ }
+
+ if !v.Type.IsBoolean() {
continue
}
@@ -83,7 +93,7 @@ func phiopt(f *Func) {
// value is always computed. This guarantees that the side effects
// of value are not seen if a is false.
if v.Args[reverse].Op == OpConstBool && v.Args[reverse].AuxInt == 1 {
- if tmp := v.Args[1-reverse]; f.sdom.isAncestorEq(tmp.Block, b) {
+ if tmp := v.Args[1-reverse]; sdom.isAncestorEq(tmp.Block, b) {
v.reset(OpOrB)
v.SetArgs2(b0.Control, tmp)
if f.pass.debug > 0 {
@@ -99,7 +109,7 @@ func phiopt(f *Func) {
// value is always computed. This guarantees that the side effects
// of value are not seen if a is false.
if v.Args[1-reverse].Op == OpConstBool && v.Args[1-reverse].AuxInt == 0 {
- if tmp := v.Args[reverse]; f.sdom.isAncestorEq(tmp.Block, b) {
+ if tmp := v.Args[reverse]; sdom.isAncestorEq(tmp.Block, b) {
v.reset(OpAndB)
v.SetArgs2(b0.Control, tmp)
if f.pass.debug > 0 {
@@ -110,5 +120,55 @@ func phiopt(f *Func) {
}
}
}
+}
+
+func phioptint(v *Value, b0 *Block, reverse int) {
+ a0 := v.Args[0]
+ a1 := v.Args[1]
+ if a0.Op != a1.Op {
+ return
+ }
+
+ switch a0.Op {
+ case OpConst8, OpConst16, OpConst32, OpConst64:
+ default:
+ return
+ }
+ negate := false
+ switch {
+ case a0.AuxInt == 0 && a1.AuxInt == 1:
+ negate = true
+ case a0.AuxInt == 1 && a1.AuxInt == 0:
+ default:
+ return
+ }
+
+ if reverse == 1 {
+ negate = !negate
+ }
+
+ switch v.Type.Size() {
+ case 1:
+ v.reset(OpCopy)
+ case 2:
+ v.reset(OpZeroExt8to16)
+ case 4:
+ v.reset(OpZeroExt8to32)
+ case 8:
+ v.reset(OpZeroExt8to64)
+ default:
+ v.Fatalf("bad int size %d", v.Type.Size())
+ }
+
+ a := b0.Control
+ if negate {
+ a = v.Block.NewValue1(v.Line, 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)
+ }
}
diff --git a/src/cmd/compile/internal/ssa/prove.go b/src/cmd/compile/internal/ssa/prove.go
index 4416fa2..1925a61 100644
--- a/src/cmd/compile/internal/ssa/prove.go
+++ b/src/cmd/compile/internal/ssa/prove.go
@@ -4,7 +4,10 @@
package ssa
-import "math"
+import (
+ "fmt"
+ "math"
+)
type branch int
@@ -74,6 +77,10 @@ type limit struct {
umin, umax uint64 // umin <= value <= umax, unsigned
}
+func (l limit) String() string {
+ return fmt.Sprintf("sm,SM,um,UM=%d,%d,%d,%d", l.min, l.max, l.umin, l.umax)
+}
+
var noLimit = limit{math.MinInt64, math.MaxInt64, 0, math.MaxUint64}
// a limitFact is a limit known for a particular value.
@@ -191,7 +198,7 @@ func (ft *factsTable) get(v, w *Value, d domain) relation {
// update updates the set of relations between v and w in domain d
// restricting it to r.
-func (ft *factsTable) update(v, w *Value, d domain, r relation) {
+func (ft *factsTable) update(parent *Block, v, w *Value, d domain, r relation) {
if lessByID(w, v) {
v, w = w, v
r = reverseBits[r]
@@ -293,6 +300,9 @@ func (ft *factsTable) update(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())
+ }
}
}
@@ -463,24 +473,26 @@ func prove(f *Func) {
})
ft := newFactsTable()
+ idom := f.Idom()
+ sdom := f.sdom()
// DFS on the dominator tree.
for len(work) > 0 {
node := work[len(work)-1]
work = work[:len(work)-1]
- parent := f.idom[node.block.ID]
- branch := getBranch(f.sdom, parent, node.block)
+ parent := idom[node.block.ID]
+ branch := getBranch(sdom, parent, node.block)
switch node.state {
case descend:
if branch != unknown {
ft.checkpoint()
c := parent.Control
- updateRestrictions(ft, boolean, nil, c, lt|gt, branch)
+ updateRestrictions(parent, ft, boolean, nil, c, lt|gt, branch)
if tr, has := domainRelationTable[parent.Control.Op]; has {
// When we branched from parent we learned a new set of
// restrictions. Update the factsTable accordingly.
- updateRestrictions(ft, tr.d, c.Args[0], c.Args[1], tr.r, branch)
+ updateRestrictions(parent, ft, tr.d, c.Args[0], c.Args[1], tr.r, branch)
}
}
@@ -488,7 +500,7 @@ func prove(f *Func) {
block: node.block,
state: simplify,
})
- for s := f.sdom.Child(node.block); s != nil; s = f.sdom.Sibling(s) {
+ for s := sdom.Child(node.block); s != nil; s = sdom.Sibling(s) {
work = append(work, bp{
block: s,
state: descend,
@@ -536,7 +548,7 @@ func getBranch(sdom SparseTree, p *Block, b *Block) branch {
// updateRestrictions updates restrictions from the immediate
// dominating block (p) using r. r is adjusted according to the branch taken.
-func updateRestrictions(ft *factsTable, t domain, v, w *Value, r relation, branch branch) {
+func updateRestrictions(parent *Block, ft *factsTable, t domain, v, w *Value, r relation, branch branch) {
if t == 0 || branch == unknown {
// Trivial case: nothing to do, or branch unknown.
// Shoult not happen, but just in case.
@@ -548,7 +560,7 @@ func updateRestrictions(ft *factsTable, t domain, v, w *Value, r relation, branc
}
for i := domain(1); i <= t; i <<= 1 {
if t&i != 0 {
- ft.update(v, w, i, r)
+ ft.update(parent, v, w, i, r)
}
}
}
@@ -556,6 +568,44 @@ func updateRestrictions(ft *factsTable, t domain, v, w *Value, r relation, branc
// simplifyBlock simplifies block known the restrictions in ft.
// Returns which branch must always be taken.
func simplifyBlock(ft *factsTable, b *Block) branch {
+ for _, v := range b.Values {
+ if v.Op != OpSlicemask {
+ continue
+ }
+ add := v.Args[0]
+ if add.Op != OpAdd64 && add.Op != OpAdd32 {
+ continue
+ }
+ // Note that the arg of slicemask was originally a sub, but
+ // was rewritten to an add by generic.rules (if the thing
+ // being subtracted was a constant).
+ x := add.Args[0]
+ y := add.Args[1]
+ if x.Op == OpConst64 || x.Op == OpConst32 {
+ x, y = y, x
+ }
+ if y.Op != OpConst64 && y.Op != OpConst32 {
+ continue
+ }
+ // slicemask(x + y)
+ // if x is larger than -y (y is negative), then slicemask is -1.
+ lim, ok := ft.limits[x.ID]
+ if !ok {
+ continue
+ }
+ if lim.umin > uint64(-y.AuxInt) {
+ if v.Args[0].Op == OpAdd64 {
+ v.reset(OpConst64)
+ } else {
+ v.reset(OpConst32)
+ }
+ if b.Func.pass.debug > 0 {
+ b.Func.Config.Warnl(v.Line, "Proved slicemask not needed")
+ }
+ v.AuxInt = -1
+ }
+ }
+
if b.Kind != BlockIf {
return unknown
}
@@ -564,13 +614,21 @@ func simplifyBlock(ft *factsTable, b *Block) branch {
m := ft.get(nil, b.Control, boolean)
if m == lt|gt {
if b.Func.pass.debug > 0 {
- b.Func.Config.Warnl(b.Line, "Proved boolean %s", b.Control.Op)
+ if b.Func.pass.debug > 1 {
+ b.Func.Config.Warnl(b.Line, "Proved boolean %s (%s)", b.Control.Op, b.Control)
+ } else {
+ b.Func.Config.Warnl(b.Line, "Proved boolean %s", b.Control.Op)
+ }
}
return positive
}
if m == eq {
if b.Func.pass.debug > 0 {
- b.Func.Config.Warnl(b.Line, "Disproved boolean %s", b.Control.Op)
+ if b.Func.pass.debug > 1 {
+ b.Func.Config.Warnl(b.Line, "Disproved boolean %s (%s)", b.Control.Op, b.Control)
+ } else {
+ b.Func.Config.Warnl(b.Line, "Disproved boolean %s", b.Control.Op)
+ }
}
return negative
}
@@ -597,13 +655,21 @@ func simplifyBlock(ft *factsTable, b *Block) branch {
m := ft.get(a0, a1, d)
if m != 0 && tr.r&m == m {
if b.Func.pass.debug > 0 {
- b.Func.Config.Warnl(b.Line, "Proved %s", c.Op)
+ if b.Func.pass.debug > 1 {
+ b.Func.Config.Warnl(b.Line, "Proved %s (%s)", c.Op, c)
+ } else {
+ b.Func.Config.Warnl(b.Line, "Proved %s", c.Op)
+ }
}
return positive
}
if m != 0 && ((lt|eq|gt)^tr.r)&m == m {
if b.Func.pass.debug > 0 {
- b.Func.Config.Warnl(b.Line, "Disproved %s", c.Op)
+ if b.Func.pass.debug > 1 {
+ b.Func.Config.Warnl(b.Line, "Disproved %s (%s)", c.Op, c)
+ } else {
+ b.Func.Config.Warnl(b.Line, "Disproved %s", c.Op)
+ }
}
return negative
}
@@ -618,7 +684,11 @@ func simplifyBlock(ft *factsTable, b *Block) branch {
m := ft.get(a0, a1, signed)
if m != 0 && tr.r&m == m {
if b.Func.pass.debug > 0 {
- b.Func.Config.Warnl(b.Line, "Proved non-negative bounds %s", c.Op)
+ if b.Func.pass.debug > 1 {
+ b.Func.Config.Warnl(b.Line, "Proved non-negative bounds %s (%s)", c.Op, c)
+ } else {
+ b.Func.Config.Warnl(b.Line, "Proved non-negative bounds %s", c.Op)
+ }
}
return positive
}
@@ -633,6 +703,9 @@ func isNonNegative(v *Value) bool {
case OpConst64:
return v.AuxInt >= 0
+ case OpConst32:
+ return int32(v.AuxInt) >= 0
+
case OpStringLen, OpSliceLen, OpSliceCap,
OpZeroExt8to64, OpZeroExt16to64, OpZeroExt32to64:
return true
diff --git a/src/cmd/compile/internal/ssa/regalloc.go b/src/cmd/compile/internal/ssa/regalloc.go
index 1eecd49..2b66982 100644
--- a/src/cmd/compile/internal/ssa/regalloc.go
+++ b/src/cmd/compile/internal/ssa/regalloc.go
@@ -106,6 +106,7 @@
package ssa
import (
+ "cmd/internal/obj"
"fmt"
"unsafe"
)
@@ -180,6 +181,7 @@ 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
}
@@ -206,6 +208,7 @@ type regAllocState struct {
numRegs register
SPReg register
SBReg register
+ GReg register
allocatable regMask
// for each block, its primary predecessor.
@@ -240,6 +243,9 @@ type regAllocState struct {
// mask of registers currently in use
used regMask
+ // mask of registers used in the current instruction
+ tmpused regMask
+
// current block we're working on
curBlock *Block
@@ -257,6 +263,10 @@ type regAllocState struct {
// spillLive[blockid] is the set of live spills at the end of each block
spillLive [][]ID
+ // a set of copies we generated to move things around, and
+ // whether it is used in shuffle. Unused copies will be deleted.
+ copies map[*Value]bool
+
loopnest *loopnest
}
@@ -276,8 +286,9 @@ type endReg struct {
}
type startReg struct {
- r register
- vid ID // pre-regalloc value needed in this register
+ r register
+ vid ID // pre-regalloc value needed in this register
+ line int32 // line number of use of this register
}
// freeReg frees up register r. Any current user of r is kicked out.
@@ -332,14 +343,14 @@ func (s *regAllocState) assignReg(r register, v *Value, c *Value) {
s.f.setHome(c, &s.registers[r])
}
-// allocReg chooses a register for v from the set of registers in mask.
+// allocReg chooses a register from the set of registers in mask.
// If there is no unused register, a Value will be kicked out of
// a register to make room.
-func (s *regAllocState) allocReg(v *Value, mask regMask) register {
+func (s *regAllocState) allocReg(mask regMask, v *Value) register {
mask &= s.allocatable
mask &^= s.nospill
if mask == 0 {
- s.f.Fatalf("no register available")
+ s.f.Fatalf("no register available for %s", v)
}
// Pick an unused register if one is available.
@@ -372,7 +383,22 @@ func (s *regAllocState) allocReg(v *Value, mask regMask) register {
}
}
if maxuse == -1 {
- s.f.Unimplementedf("couldn't find register to spill")
+ s.f.Fatalf("couldn't find register to spill")
+ }
+
+ // Try to move it around before kicking out, if there is a free register.
+ // We generate a Copy and record it. It will be deleted if never used.
+ v2 := s.regs[r].v
+ 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)
+ s.copies[c] = false
+ if s.f.pass.debug > regDebug {
+ fmt.Printf("copy %s to %s : %s\n", v2, c, s.registers[r2].Name())
+ }
+ s.setOrig(c, v2)
+ s.assignReg(r2, v2, c)
}
s.freeReg(r)
return r
@@ -400,7 +426,7 @@ func (s *regAllocState) allocValToReg(v *Value, mask regMask, nospill bool, line
}
// Allocate a register.
- r := s.allocReg(v, mask)
+ r := s.allocReg(mask, v)
// Allocate v to the new register.
var c *Value
@@ -435,43 +461,128 @@ func (s *regAllocState) allocValToReg(v *Value, mask regMask, nospill bool, line
return c
}
+// isLeaf reports whether f performs any calls.
+func isLeaf(f *Func) bool {
+ for _, b := range f.Blocks {
+ for _, v := range b.Values {
+ if opcodeTable[v.Op].call {
+ return false
+ }
+ }
+ }
+ return true
+}
+
func (s *regAllocState) init(f *Func) {
s.f = f
s.registers = f.Config.registers
- s.numRegs = register(len(s.registers))
- if s.numRegs > noRegister || s.numRegs > register(unsafe.Sizeof(regMask(0))*8) {
- panic("too many registers")
+ 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)
+ } else {
+ s.numRegs = register(nr)
}
+ // Locate SP, SB, and g registers.
+ s.SPReg = noRegister
+ s.SBReg = noRegister
+ s.GReg = noRegister
for r := register(0); r < s.numRegs; r++ {
- if s.registers[r].Name() == "SP" {
+ switch s.registers[r].Name() {
+ case "SP":
s.SPReg = r
- }
- if s.registers[r].Name() == "SB" {
+ case "SB":
s.SBReg = r
+ case "g":
+ s.GReg = r
+ }
+ }
+ // Make sure we found all required registers.
+ switch noRegister {
+ case s.SPReg:
+ s.f.Fatalf("no SP register found")
+ case s.SBReg:
+ s.f.Fatalf("no SB register found")
+ case s.GReg:
+ if f.Config.hasGReg {
+ s.f.Fatalf("no g register found")
}
}
// Figure out which registers we're allowed to use.
- s.allocatable = regMask(1)<<s.numRegs - 1
+ s.allocatable = s.f.Config.gpRegMask | s.f.Config.fpRegMask | s.f.Config.specialRegMask
s.allocatable &^= 1 << s.SPReg
s.allocatable &^= 1 << s.SBReg
- if s.f.Config.ctxt.Framepointer_enabled {
- s.allocatable &^= 1 << 5 // BP
+ if s.f.Config.hasGReg {
+ s.allocatable &^= 1 << s.GReg
+ }
+ if s.f.Config.ctxt.Framepointer_enabled && s.f.Config.FPReg >= 0 {
+ s.allocatable &^= 1 << uint(s.f.Config.FPReg)
+ }
+ if s.f.Config.ctxt.Flag_shared {
+ switch s.f.Config.arch {
+ case "ppc64le": // R2 already reserved.
+ s.allocatable &^= 1 << 12 // R12
+ }
+ }
+ if s.f.Config.LinkReg != -1 {
+ if isLeaf(f) {
+ // 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 {
+ // On ARMv5 we insert softfloat calls at each FP instruction.
+ // This clobbers LR almost everywhere. Disable allocating LR
+ // on ARMv5.
+ s.allocatable &^= 1 << uint(s.f.Config.LinkReg)
+ }
}
if s.f.Config.ctxt.Flag_dynlink {
- s.allocatable &^= 1 << 15 // R15
+ switch s.f.Config.arch {
+ case "amd64":
+ s.allocatable &^= 1 << 15 // R15
+ case "arm":
+ s.allocatable &^= 1 << 9 // R9
+ case "ppc64le": // R2 already reserved.
+ s.allocatable &^= 1 << 12 // R12
+ case "arm64":
+ // nothing to do?
+ case "386":
+ // nothing to do.
+ // Note that for Flag_shared (position independent code)
+ // we do need to be careful, but that carefulness is hidden
+ // in the rewrite rules so we always have a free register
+ // available for global load/stores. See gen/386.rules (search for Flag_shared).
+ case "s390x":
+ // nothing to do, R10 & R11 already reserved
+ default:
+ s.f.Config.fe.Fatalf(0, "arch %s not implemented", s.f.Config.arch)
+ }
+ }
+ if s.f.Config.nacl {
+ switch s.f.Config.arch {
+ case "arm":
+ s.allocatable &^= 1 << 9 // R9 is "thread pointer" on nacl/arm
+ case "amd64p32":
+ s.allocatable &^= 1 << 5 // BP - reserved for nacl
+ s.allocatable &^= 1 << 15 // R15 - reserved for nacl
+ }
+ }
+ if s.f.Config.use387 {
+ s.allocatable &^= 1 << 15 // X7 disallowed (one 387 register is used as scratch space during SSE->387 generation in ../x86/387.go)
}
s.regs = make([]regState, s.numRegs)
s.values = make([]valState, f.NumValues())
s.orig = make([]*Value, f.NumValues())
+ s.copies = make(map[*Value]bool)
for _, b := range f.Blocks {
for _, v := range b.Values {
- if !v.Type.IsMemory() && !v.Type.IsVoid() && !v.Type.IsFlags() {
+ if !v.Type.IsMemory() && !v.Type.IsVoid() && !v.Type.IsFlags() && !v.Type.IsTuple() {
s.values[v.ID].needReg = true
s.values[v.ID].rematerializeable = v.rematerializeable()
s.orig[v.ID] = v
}
+ // Note: needReg is false for values returning Tuple types.
+ // Instead, we mark the corresponding Selects as needReg.
}
}
s.computeLive()
@@ -506,7 +617,7 @@ func (s *regAllocState) init(f *Func) {
// 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) {
+func (s *regAllocState) addUse(id ID, dist int32, line int32) {
r := s.freeUseRecords
if r != nil {
s.freeUseRecords = r.next
@@ -514,6 +625,7 @@ func (s *regAllocState) addUse(id ID, dist int32) {
r = &use{}
}
r.dist = dist
+ r.line = line
r.next = s.values[id].uses
s.values[id].uses = r
if r.next != nil && dist > r.next.dist {
@@ -563,10 +675,13 @@ 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 {
var m regMask
+ if t.IsTuple() || t.IsFlags() {
+ return 0
+ }
if t.IsFloat() || t == TypeInt128 {
- m = 0xffff << 16 // X0-X15
+ m = s.f.Config.fpRegMask
} else {
- m = 0xffff << 0 // AX-R15
+ m = s.f.Config.gpRegMask
}
return m & s.allocatable
}
@@ -639,16 +754,12 @@ func (s *regAllocState) regalloc(f *Func) {
// Initialize liveSet and uses fields for this block.
// Walk backwards through the block doing liveness analysis.
liveSet.clear()
- d := int32(len(b.Values))
- if b.Kind == BlockCall || b.Kind == BlockDefer {
- d += unlikelyDistance
- }
for _, e := range s.live[b.ID] {
- s.addUse(e.ID, d+e.dist) // pseudo-uses from beyond end of block
+ s.addUse(e.ID, int32(len(b.Values))+e.dist, e.line) // pseudo-uses from beyond end of block
liveSet.add(e.ID)
}
if v := b.Control; v != nil && s.values[v.ID].needReg {
- s.addUse(v.ID, int32(len(b.Values))) // psuedo-use by control value
+ s.addUse(v.ID, int32(len(b.Values)), b.Line) // psuedo-use by control value
liveSet.add(v.ID)
}
for i := len(b.Values) - 1; i >= 0; i-- {
@@ -664,7 +775,7 @@ func (s *regAllocState) regalloc(f *Func) {
if !s.values[a.ID].needReg {
continue
}
- s.addUse(a.ID, int32(i))
+ s.addUse(a.ID, int32(i), v.Line)
liveSet.add(a.ID)
}
}
@@ -753,10 +864,11 @@ func (s *regAllocState) regalloc(f *Func) {
continue
}
a := v.Args[idx]
- m := s.values[a.ID].regs &^ phiUsed
+ // Some instructions target not-allocatable registers.
+ // They're not suitable for further (phi-function) allocation.
+ m := s.values[a.ID].regs &^ phiUsed & s.allocatable
if m != 0 {
r := pickReg(m)
- s.freeReg(r)
phiUsed |= regMask(1) << r
phiRegs = append(phiRegs, r)
} else {
@@ -765,7 +877,7 @@ func (s *regAllocState) regalloc(f *Func) {
}
// Second pass - deallocate any phi inputs which are now dead.
- for _, v := range phis {
+ for i, v := range phis {
if !s.values[v.ID].needReg {
continue
}
@@ -774,6 +886,31 @@ func (s *regAllocState) regalloc(f *Func) {
// Input is dead beyond the phi, deallocate
// anywhere else it might live.
s.freeRegs(s.values[a.ID].regs)
+ } else {
+ // Input is still live.
+ // Try to move it around before kicking out, if there is a free register.
+ // We generate a Copy in the predecessor block and record it. It will be
+ // deleted if never used.
+ r := phiRegs[i]
+ if r == noRegister {
+ continue
+ }
+ // Pick a free register. At this point some registers used in the predecessor
+ // block may have been deallocated. Those are the ones used for Phis. Exclude
+ // them (and they are not going to be helpful anyway).
+ 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)
+ s.copies[c] = false
+ if s.f.pass.debug > regDebug {
+ fmt.Printf("copy %s to %s : %s\n", a, c, s.registers[r2].Name())
+ }
+ s.setOrig(c, a)
+ s.assignReg(r2, a, c)
+ s.endRegs[p.ID] = append(s.endRegs[p.ID], endReg{r2, a, c})
+ }
+ s.freeReg(r)
}
}
@@ -786,6 +923,9 @@ func (s *regAllocState) regalloc(f *Func) {
if phiRegs[i] != noRegister {
continue
}
+ if s.f.Config.use387 && v.Type.IsFloat() {
+ continue // 387 can't handle floats in registers between blocks
+ }
m := s.compatRegs(v.Type) &^ phiUsed &^ s.used
if m != 0 {
r := pickReg(m)
@@ -833,7 +973,7 @@ func (s *regAllocState) regalloc(f *Func) {
// specially during merge edge processing.
continue
}
- regList = append(regList, startReg{r, v.ID})
+ regList = append(regList, startReg{r, v.ID, s.values[v.ID].uses.line})
}
s.startRegs[b.ID] = regList
@@ -878,7 +1018,7 @@ func (s *regAllocState) regalloc(f *Func) {
if !ok {
continue
}
- desired.add(v.Args[pidx].ID, register(rp.Num))
+ desired.add(v.Args[pidx].ID, register(rp.num))
}
}
// Walk values backwards computing desired register info.
@@ -915,6 +1055,7 @@ func (s *regAllocState) regalloc(f *Func) {
if s.f.pass.debug > regDebug {
fmt.Printf(" processing %s\n", v.LongString())
}
+ regspec := opcodeTable[v.Op].reg
if v.Op == OpPhi {
f.Fatalf("phi %s not at start of block", v)
}
@@ -930,6 +1071,28 @@ func (s *regAllocState) regalloc(f *Func) {
s.advanceUses(v)
continue
}
+ if v.Op == OpSelect0 || v.Op == OpSelect1 {
+ if s.values[v.ID].needReg {
+ var i = 0
+ if v.Op == OpSelect1 {
+ i = 1
+ }
+ s.assignReg(register(s.f.getHome(v.Args[0].ID).(LocPair)[i].(*Register).num), v, v)
+ }
+ b.Values = append(b.Values, v)
+ s.advanceUses(v)
+ goto issueSpill
+ }
+ if v.Op == OpGetG && s.f.Config.hasGReg {
+ // use hardware g register
+ if s.regs[s.GReg].v != nil {
+ s.freeReg(s.GReg) // kick out the old value
+ }
+ s.assignReg(s.GReg, v, v)
+ b.Values = append(b.Values, v)
+ s.advanceUses(v)
+ goto issueSpill
+ }
if v.Op == OpArg {
// Args are "pre-spilled" values. We don't allocate
// any register here. We just set up the spill pointer to
@@ -957,7 +1120,6 @@ func (s *regAllocState) regalloc(f *Func) {
b.Values = append(b.Values, v)
continue
}
- regspec := opcodeTable[v.Op].reg
if len(regspec.inputs) == 0 && len(regspec.outputs) == 0 {
// No register allocation required (or none specified yet)
s.freeRegs(regspec.clobbers)
@@ -1002,10 +1164,6 @@ func (s *regAllocState) regalloc(f *Func) {
args = append(args[:0], v.Args...)
for _, i := range regspec.inputs {
mask := i.regs
- if mask == flagRegMask {
- // TODO: remove flag input from regspec.inputs.
- continue
- }
if mask&s.values[args[i.idx].ID].regs == 0 {
// Need a new register for the input.
mask &= s.allocatable
@@ -1037,6 +1195,10 @@ func (s *regAllocState) regalloc(f *Func) {
// arg0 is dead. We can clobber its register.
goto ok
}
+ if s.values[v.Args[0].ID].rematerializeable {
+ // We can rematerialize the input, don't worry about clobbering it.
+ goto ok
+ }
if countRegs(s.values[v.Args[0].ID].regs) >= 2 {
// we have at least 2 copies of arg0. We can afford to clobber one.
goto ok
@@ -1046,6 +1208,10 @@ func (s *regAllocState) regalloc(f *Func) {
args[0], args[1] = args[1], args[0]
goto ok
}
+ if s.values[v.Args[1].ID].rematerializeable {
+ args[0], args[1] = args[1], args[0]
+ goto ok
+ }
if countRegs(s.values[v.Args[1].ID].regs) >= 2 {
args[0], args[1] = args[1], args[0]
goto ok
@@ -1080,7 +1246,8 @@ func (s *regAllocState) regalloc(f *Func) {
for _, r := range dinfo[idx].in[0] {
if r != noRegister && m>>r&1 != 0 {
m = regMask(1) << r
- s.allocValToReg(v.Args[0], m, true, v.Line)
+ c := s.allocValToReg(v.Args[0], m, true, v.Line)
+ s.copies[c] = false
// Note: no update to args[0] so the instruction will
// use the original copy.
goto ok
@@ -1090,7 +1257,8 @@ func (s *regAllocState) regalloc(f *Func) {
for _, r := range dinfo[idx].in[1] {
if r != noRegister && m>>r&1 != 0 {
m = regMask(1) << r
- s.allocValToReg(v.Args[1], m, true, v.Line)
+ c := s.allocValToReg(v.Args[1], m, true, v.Line)
+ s.copies[c] = false
args[0], args[1] = args[1], args[0]
goto ok
}
@@ -1101,65 +1269,102 @@ func (s *regAllocState) regalloc(f *Func) {
m &^= desired.avoid
}
// Save input 0 to a new register so we can clobber it.
- s.allocValToReg(v.Args[0], m, true, v.Line)
- ok:
+ c := s.allocValToReg(v.Args[0], m, true, v.Line)
+ s.copies[c] = false
}
+ ok:
// Now that all args are in regs, we're ready to issue the value itself.
// Before we pick a register for the output value, allow input registers
// to be deallocated. We do this here so that the output can use the
// same register as a dying input.
- s.nospill = 0
- s.advanceUses(v) // frees any registers holding args that are no longer live
+ if !opcodeTable[v.Op].resultNotInArgs {
+ s.tmpused = s.nospill
+ s.nospill = 0
+ s.advanceUses(v) // frees any registers holding args that are no longer live
+ }
// Dump any registers which will be clobbered
s.freeRegs(regspec.clobbers)
-
- // Pick register for output.
- if s.values[v.ID].needReg {
- mask := regspec.outputs[0] & s.allocatable
- if opcodeTable[v.Op].resultInArg0 {
- if !opcodeTable[v.Op].commutative {
- // Output must use the same register as input 0.
- r := register(s.f.getHome(args[0].ID).(*Register).Num)
- mask = regMask(1) << r
- } else {
- // Output must use the same register as input 0 or 1.
- r0 := register(s.f.getHome(args[0].ID).(*Register).Num)
- r1 := register(s.f.getHome(args[1].ID).(*Register).Num)
- // Check r0 and r1 for desired output register.
- found := false
- for _, r := range dinfo[idx].out {
- if (r == r0 || r == r1) && (mask&^s.used)>>r&1 != 0 {
- mask = regMask(1) << r
- found = true
- if r == r1 {
- args[0], args[1] = args[1], args[0]
+ s.tmpused |= regspec.clobbers
+
+ // Pick registers for outputs.
+ {
+ outRegs := [2]register{noRegister, noRegister}
+ var used regMask
+ for _, out := range regspec.outputs {
+ mask := out.regs & s.allocatable &^ used
+ if mask == 0 {
+ continue
+ }
+ if opcodeTable[v.Op].resultInArg0 && out.idx == 0 {
+ if !opcodeTable[v.Op].commutative {
+ // Output must use the same register as input 0.
+ r := register(s.f.getHome(args[0].ID).(*Register).num)
+ mask = regMask(1) << r
+ } else {
+ // Output must use the same register as input 0 or 1.
+ r0 := register(s.f.getHome(args[0].ID).(*Register).num)
+ r1 := register(s.f.getHome(args[1].ID).(*Register).num)
+ // Check r0 and r1 for desired output register.
+ found := false
+ for _, r := range dinfo[idx].out {
+ if (r == r0 || r == r1) && (mask&^s.used)>>r&1 != 0 {
+ mask = regMask(1) << r
+ found = true
+ if r == r1 {
+ args[0], args[1] = args[1], args[0]
+ }
+ break
}
- break
+ }
+ if !found {
+ // Neither are desired, pick r0.
+ mask = regMask(1) << r0
}
}
- if !found {
- // Neither are desired, pick r0.
- mask = regMask(1) << r0
+ }
+ for _, r := range dinfo[idx].out {
+ if r != noRegister && (mask&^s.used)>>r&1 != 0 {
+ // Desired register is allowed and unused.
+ mask = regMask(1) << r
+ break
}
}
- }
- for _, r := range dinfo[idx].out {
- if r != noRegister && (mask&^s.used)>>r&1 != 0 {
- // Desired register is allowed and unused.
- mask = regMask(1) << r
- break
+ // Avoid registers we're saving for other values.
+ if mask&^desired.avoid != 0 {
+ mask &^= desired.avoid
+ }
+ r := s.allocReg(mask, v)
+ outRegs[out.idx] = r
+ used |= regMask(1) << r
+ s.tmpused |= regMask(1) << r
+ }
+ // Record register choices
+ if v.Type.IsTuple() {
+ var outLocs LocPair
+ if r := outRegs[0]; r != noRegister {
+ outLocs[0] = &s.registers[r]
+ }
+ if r := outRegs[1]; r != noRegister {
+ outLocs[1] = &s.registers[r]
+ }
+ s.f.setHome(v, outLocs)
+ // Note that subsequent SelectX instructions will do the assignReg calls.
+ } else {
+ if r := outRegs[0]; r != noRegister {
+ s.assignReg(r, v, v)
}
}
- // Avoid registers we're saving for other values.
- if mask&^desired.avoid != 0 {
- mask &^= desired.avoid
- }
- r := s.allocReg(v, mask)
- s.assignReg(r, v, v)
}
+ // deallocate dead args, if we have not done so
+ if opcodeTable[v.Op].resultNotInArgs {
+ s.nospill = 0
+ s.advanceUses(v) // frees any registers holding args that are no longer live
+ }
+ s.tmpused = 0
+
// Issue the Value itself.
for i, a := range args {
v.SetArg(i, a) // use register version of arguments
@@ -1176,6 +1381,7 @@ func (s *regAllocState) regalloc(f *Func) {
// 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)
@@ -1194,9 +1400,14 @@ func (s *regAllocState) regalloc(f *Func) {
if s.f.pass.debug > regDebug {
fmt.Printf(" processing control %s\n", v.LongString())
}
- // TODO: regspec for block control values, instead of using
- // register set from the control op's output.
- s.allocValToReg(v, opcodeTable[v.Op].reg.outputs[0], false, b.Line)
+ // 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)
+ if b.Control != v {
+ v.Uses--
+ b.Control.Uses++
+ }
// Remove this use from the uses list.
vi := &s.values[v.ID]
u := vi.uses
@@ -1208,6 +1419,11 @@ func (s *regAllocState) regalloc(f *Func) {
s.freeUseRecords = u
}
+ // Spill any values that can't live across basic block boundaries.
+ if s.f.Config.use387 {
+ s.freeRegs(s.f.Config.fpRegMask)
+ }
+
// If we are approaching a merge point and we are the primary
// predecessor of it, find live values that we use soon after
// the merge point and promote them to registers now.
@@ -1230,7 +1446,13 @@ func (s *regAllocState) regalloc(f *Func) {
if vi.regs != 0 {
continue
}
+ if vi.rematerializeable {
+ continue
+ }
v := s.orig[vid]
+ if s.f.Config.use387 && v.Type.IsFloat() {
+ continue // 387 can't handle floats in registers between blocks
+ }
m := s.compatRegs(v.Type) &^ s.used
if m&^desired.avoid != 0 {
m &^= desired.avoid
@@ -1263,8 +1485,7 @@ func (s *regAllocState) regalloc(f *Func) {
}
s.endRegs[b.ID] = regList
- // Check. TODO: remove
- {
+ if checkEnabled {
liveSet.clear()
for _, x := range s.live[b.ID] {
liveSet.add(x.ID)
@@ -1387,7 +1608,7 @@ func (s *regAllocState) regalloc(f *Func) {
for i := range s.values {
vi := s.values[i]
if vi.spillUsed {
- if s.f.pass.debug > logSpills {
+ 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
@@ -1545,6 +1766,39 @@ sinking:
}
}
+ // 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.
+ for {
+ progress := false
+ for c, used := range s.copies {
+ if !used && c.Uses == 0 {
+ if s.f.pass.debug > regDebug {
+ fmt.Printf("delete copied value %s\n", c.LongString())
+ }
+ c.Args[0].Uses--
+ f.freeValue(c)
+ delete(s.copies, c)
+ progress = true
+ }
+ }
+ if !progress {
+ break
+ }
+ }
+
+ 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]
+ }
+
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")
@@ -1627,12 +1881,14 @@ 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
}
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
}
// setup initializes the edge state for shuffling.
@@ -1655,19 +1911,19 @@ 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)
+ e.set(&e.s.registers[x.r], x.v.ID, x.c, false, 0) // don't care the line number 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)
+ e.set(e.s.f.getHome(spillID), v.ID, spill, false, 0) // don't care the line number 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})
+ dsts = append(dsts, dstRecord{&e.s.registers[x.r], x.vid, nil, x.line})
}
// Phis need their args to end up in a specific location.
for _, v := range e.b.Values {
@@ -1678,7 +1934,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]})
+ dsts = append(dsts, dstRecord{loc, v.Args[idx].ID, &v.Args[idx], v.Line})
}
e.destinations = dsts
@@ -1703,7 +1959,7 @@ func (e *edgeState) process() {
for len(dsts) > 0 {
i := 0
for _, d := range dsts {
- if !e.processDest(d.loc, d.vid, d.splice) {
+ if !e.processDest(d.loc, d.vid, d.splice, d.line) {
// Failed - save for next iteration.
dsts[i] = d
i++
@@ -1741,7 +1997,8 @@ func (e *edgeState) process() {
// Copy any cycle location to a temp register. This duplicates
// one of the cycle entries, allowing the just duplicated value
// to be overwritten and the cycle to proceed.
- loc := dsts[0].loc
+ d := dsts[0]
+ loc := d.loc
vid := e.contents[loc].vid
c := e.contents[loc].c
r := e.findRegFor(c.Type)
@@ -1749,30 +2006,37 @@ 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(c.Line, OpCopy, c.Type, c)
+ c = e.p.NewValue1(d.line, OpCopy, c.Type, c)
} else {
e.s.lateSpillUse(vid)
- c = e.p.NewValue1(c.Line, OpLoadReg, c.Type, c)
+ c = e.p.NewValue1(d.line, OpLoadReg, c.Type, c)
}
- e.set(r, vid, c, false)
+ e.set(r, vid, c, false, d.line)
}
}
// processDest generates code to put value vid into location loc. Returns true
// if progress was made.
-func (e *edgeState) processDest(loc Location, vid ID, splice **Value) bool {
+func (e *edgeState) processDest(loc Location, vid ID, splice **Value, line int32) bool {
occupant := e.contents[loc]
if occupant.vid == vid {
// Value is already in the correct place.
- e.contents[loc] = contentRecord{vid, occupant.c, true}
+ e.contents[loc] = contentRecord{vid, occupant.c, true, line}
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
// deadcode elimination.
+ if _, ok := e.s.copies[occupant.c]; ok {
+ // The copy at occupant.c was used to avoid spill.
+ e.s.copies[occupant.c] = true
+ }
return true
}
@@ -1813,7 +2077,7 @@ func (e *edgeState) processDest(loc Location, vid ID, splice **Value) bool {
var x *Value
if c == nil {
if !e.s.values[vid].rematerializeable {
- e.s.f.Fatalf("can't find source for %s->%s: v%d\n", e.p, e.b, vid)
+ 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)
@@ -1823,25 +2087,25 @@ func (e *edgeState) processDest(loc Location, vid ID, splice **Value) bool {
e.erase(loc) // see pre-clobber comment below
r := e.findRegFor(v.Type)
x = v.copyInto(e.p)
- e.set(r, vid, x, false)
+ e.set(r, vid, x, false, line)
// Make sure we spill with the size of the slot, not the
// size of x (which might be wider due to our dropping
// of narrowing conversions).
- x = e.p.NewValue1(x.Line, OpStoreReg, loc.(LocalSlot).Type, x)
+ x = e.p.NewValue1(line, OpStoreReg, loc.(LocalSlot).Type, x)
}
} else {
// Emit move from src to dst.
_, srcReg := src.(*Register)
if srcReg {
if dstReg {
- x = e.p.NewValue1(c.Line, OpCopy, c.Type, c)
+ x = e.p.NewValue1(line, OpCopy, c.Type, c)
} else {
- x = e.p.NewValue1(c.Line, OpStoreReg, loc.(LocalSlot).Type, c)
+ x = e.p.NewValue1(line, OpStoreReg, loc.(LocalSlot).Type, c)
}
} else {
if dstReg {
e.s.lateSpillUse(vid)
- x = e.p.NewValue1(c.Line, OpLoadReg, c.Type, c)
+ x = e.p.NewValue1(line, OpLoadReg, c.Type, c)
} else {
// mem->mem. Use temp register.
@@ -1859,13 +2123,13 @@ func (e *edgeState) processDest(loc Location, vid ID, splice **Value) bool {
r := e.findRegFor(c.Type)
e.s.lateSpillUse(vid)
- t := e.p.NewValue1(c.Line, OpLoadReg, c.Type, c)
- e.set(r, vid, t, false)
- x = e.p.NewValue1(c.Line, OpStoreReg, loc.(LocalSlot).Type, t)
+ 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)
}
}
}
- e.set(loc, vid, x, true)
+ e.set(loc, vid, x, true, line)
if splice != nil {
(*splice).Uses--
*splice = x
@@ -1875,10 +2139,10 @@ func (e *edgeState) processDest(loc Location, vid ID, splice **Value) bool {
}
// 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) {
+func (e *edgeState) set(loc Location, vid ID, c *Value, final bool, line int32) {
e.s.f.setHome(c, loc)
e.erase(loc)
- e.contents[loc] = contentRecord{vid, c, final}
+ e.contents[loc] = contentRecord{vid, c, final, line}
a := e.cache[vid]
if len(a) == 0 {
e.cachedVals = append(e.cachedVals, vid)
@@ -1886,16 +2150,16 @@ func (e *edgeState) set(loc Location, vid ID, c *Value, final bool) {
a = append(a, c)
e.cache[vid] = a
if r, ok := loc.(*Register); ok {
- e.usedRegs |= regMask(1) << uint(r.Num)
+ e.usedRegs |= regMask(1) << uint(r.num)
if final {
- e.finalRegs |= regMask(1) << uint(r.Num)
+ e.finalRegs |= regMask(1) << uint(r.num)
}
if len(a) == 1 {
- e.uniqueRegs |= regMask(1) << uint(r.Num)
+ e.uniqueRegs |= regMask(1) << uint(r.num)
}
if len(a) == 2 {
if t, ok := e.s.f.getHome(a[0].ID).(*Register); ok {
- e.uniqueRegs &^= regMask(1) << uint(t.Num)
+ e.uniqueRegs &^= regMask(1) << uint(t.num)
}
}
}
@@ -1917,7 +2181,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})
+ e.extra = append(e.extra, dstRecord{loc, cr.vid, nil, cr.line})
}
// Remove c from the list of cached values.
@@ -1935,14 +2199,14 @@ func (e *edgeState) erase(loc Location) {
// Update register masks.
if r, ok := loc.(*Register); ok {
- e.usedRegs &^= regMask(1) << uint(r.Num)
+ e.usedRegs &^= regMask(1) << uint(r.num)
if cr.final {
- e.finalRegs &^= regMask(1) << uint(r.Num)
+ e.finalRegs &^= regMask(1) << uint(r.num)
}
}
if len(a) == 1 {
if r, ok := e.s.f.getHome(a[0].ID).(*Register); ok {
- e.uniqueRegs |= regMask(1) << uint(r.Num)
+ e.uniqueRegs |= regMask(1) << uint(r.num)
}
}
}
@@ -1985,9 +2249,9 @@ func (e *edgeState) findRegFor(typ Type) Location {
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 {
+ 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)
+ 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())
}
@@ -2010,6 +2274,8 @@ func (e *edgeState) findRegFor(typ Type) Location {
return nil
}
+// rematerializeable reports whether the register allocator should recompute
+// a value instead of spilling/restoring it.
func (v *Value) rematerializeable() bool {
if !opcodeTable[v.Op].rematerializeable {
return false
@@ -2026,6 +2292,7 @@ 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
}
// dblock contains information about desired & avoid registers at the end of a block.
@@ -2063,8 +2330,8 @@ func (s *regAllocState) computeLive() {
// Walk the dominator tree from end to beginning, just once, treating SCC
// components as single blocks, duplicated calculated liveness information
// out to all of them.
- s.loopnest = loopnestfor(f)
- po := s.loopnest.po
+ po := f.postorder()
+ s.loopnest = f.loopnest()
for {
changed := false
@@ -2073,19 +2340,13 @@ func (s *regAllocState) computeLive() {
// Add len(b.Values) to adjust from end-of-block distance
// to beginning-of-block distance.
live.clear()
- d := int32(len(b.Values))
- if b.Kind == BlockCall || b.Kind == BlockDefer {
- // Because we keep no values in registers across a call,
- // make every use past a call appear very far away.
- d += unlikelyDistance
- }
for _, e := range s.live[b.ID] {
- live.set(e.ID, e.dist+d)
+ live.set(e.ID, e.dist+int32(len(b.Values)), e.line)
}
// Mark control value as live
if b.Control != nil && s.values[b.Control.ID].needReg {
- live.set(b.Control.ID, int32(len(b.Values)))
+ live.set(b.Control.ID, int32(len(b.Values)), b.Line)
}
// Propagate backwards to the start of the block
@@ -2099,9 +2360,15 @@ func (s *regAllocState) computeLive() {
phis = append(phis, v)
continue
}
+ if opcodeTable[v.Op].call {
+ c := live.contents()
+ for i := range c {
+ c[i].val += unlikelyDistance
+ }
+ }
for _, a := range v.Args {
if s.values[a.ID].needReg {
- live.set(a.ID, int32(i))
+ live.set(a.ID, int32(i), v.Line)
}
}
}
@@ -2160,7 +2427,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)
+ t.set(e.ID, e.dist, e.line)
}
update := false
@@ -2169,7 +2436,7 @@ func (s *regAllocState) computeLive() {
d := e.val + delta
if !t.contains(e.key) || d < t.get(e.key) {
update = true
- t.set(e.key, d)
+ t.set(e.key, d, e.aux)
}
}
// Also add the correct arg from the saved phi values.
@@ -2179,7 +2446,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)
+ t.set(id, delta, v.Line)
}
}
@@ -2192,7 +2459,7 @@ func (s *regAllocState) computeLive() {
l = make([]liveInfo, 0, t.size())
}
for _, e := range t.contents() {
- l = append(l, liveInfo{e.key, e.val})
+ l = append(l, liveInfo{e.key, e.val, e.aux})
}
s.live[p.ID] = l
changed = true
diff --git a/src/cmd/compile/internal/ssa/rewrite.go b/src/cmd/compile/internal/ssa/rewrite.go
index 61d4234..1f9a90f 100644
--- a/src/cmd/compile/internal/ssa/rewrite.go
+++ b/src/cmd/compile/internal/ssa/rewrite.go
@@ -11,7 +11,7 @@ import (
"path/filepath"
)
-func applyRewrite(f *Func, rb func(*Block) bool, rv func(*Value, *Config) bool) {
+func applyRewrite(f *Func, rb func(*Block, *Config) bool, rv func(*Value, *Config) bool) {
// repeat rewrites until we find no more rewrites
var curb *Block
var curv *Value
@@ -34,7 +34,7 @@ func applyRewrite(f *Func, rb func(*Block) bool, rv func(*Value, *Config) bool)
}
}
curb = b
- if rb(b) {
+ if rb(b, config) {
change = true
}
curb = nil
@@ -149,6 +149,134 @@ func canMergeSym(x, y interface{}) bool {
return x == nil || y == nil
}
+// canMergeLoad reports whether the load can be merged into target without
+// invalidating the schedule.
+func canMergeLoad(target, load *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 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
+ // state that is a successor of load's memory arg.
+ //
+ // For example, it would be invalid to merge load into target in
+ // the following situation because newmem has killed oldmem
+ // before target is reached:
+ // load = read ... oldmem
+ // newmem = write ... oldmem
+ // arg0 = read ... newmem
+ // target = add arg0 load
+ //
+ // If the argument comes from a different block then we can exclude
+ // it immediately because it must dominate load (which is in the
+ // same block as target).
+ var args []*Value
+ for _, a := range target.Args {
+ if a != load && a.Block.ID == target.Block.ID {
+ args = append(args, a)
+ }
+ }
+
+ // memPreds contains memory states known to be predecessors of load's
+ // memory state. It is lazily initialized.
+ var memPreds map[*Value]bool
+search:
+ for i := 0; len(args) > 0; i++ {
+ const limit = 100
+ if i >= limit {
+ // Give up if we have done a lot of iterations.
+ return false
+ }
+ v := args[len(args)-1]
+ args = args[:len(args)-1]
+ if target.Block.ID != v.Block.ID {
+ // Since target and load are in the same block
+ // we can stop searching when we leave the block.
+ continue search
+ }
+ if v.Op == OpPhi {
+ // A Phi implies we have reached the top of the block.
+ continue search
+ }
+ if v.Type.IsTuple() && v.Type.FieldType(1).IsMemory() {
+ // We could handle this situation however it is likely
+ // to be very rare.
+ return false
+ }
+ if v.Type.IsMemory() {
+ if memPreds == nil {
+ // Initialise a map containing memory states
+ // known to be predecessors of load's memory
+ // state.
+ memPreds = make(map[*Value]bool)
+ m := mem
+ const limit = 50
+ for i := 0; i < limit; i++ {
+ if m.Op == OpPhi {
+ break
+ }
+ if m.Block.ID != target.Block.ID {
+ break
+ }
+ if !m.Type.IsMemory() {
+ break
+ }
+ memPreds[m] = true
+ if len(m.Args) == 0 {
+ break
+ }
+ m = m.Args[len(m.Args)-1]
+ }
+ }
+
+ // We can merge if v is a predecessor of mem.
+ //
+ // For example, we can merge load into target in the
+ // following scenario:
+ // x = read ... v
+ // mem = write ... v
+ // load = read ... mem
+ // target = add x load
+ if memPreds[v] {
+ continue search
+ }
+ return false
+ }
+ if len(v.Args) > 0 && v.Args[len(v.Args)-1] == mem {
+ // If v takes mem as an input then we know mem
+ // is valid at this point.
+ continue search
+ }
+ for _, a := range v.Args {
+ if target.Block.ID == a.Block.ID {
+ args = append(args, a)
+ }
+ }
+ }
+ return true
+}
+
+// isArg returns whether s is an arg symbol
+func isArg(s interface{}) bool {
+ _, ok := s.(*ArgSymbol)
+ return ok
+}
+
+// isAuto returns whether s is an auto symbol
+func isAuto(s interface{}) bool {
+ _, ok := s.(*AutoSymbol)
+ return ok
+}
+
+// isSameSym returns whether sym is the same as the given named symbol
+func isSameSym(sym interface{}, name string) bool {
+ s, ok := sym.(fmt.Stringer)
+ return ok && s.String() == name
+}
+
// nlz returns the number of leading zeros.
func nlz(x int64) int64 {
// log2(0) == 1, so nlz(0) == 64
@@ -171,6 +299,7 @@ func nto(x int64) int64 {
}
// log2 returns logarithm in base of uint64(n), with log2(0) = -1.
+// Rounds down.
func log2(n int64) (l int64) {
l = -1
x := uint64(n)
@@ -205,6 +334,26 @@ func is32Bit(n int64) bool {
return n == int64(int32(n))
}
+// is16Bit reports whether n can be represented as a signed 16 bit integer.
+func is16Bit(n int64) bool {
+ return n == int64(int16(n))
+}
+
+// isU16Bit reports whether n can be represented as an unsigned 16 bit integer.
+func isU16Bit(n int64) bool {
+ return n == int64(uint16(n))
+}
+
+// isU32Bit reports whether n can be represented as an unsigned 32 bit integer.
+func isU32Bit(n int64) bool {
+ return n == int64(uint32(n))
+}
+
+// is20Bit reports whether n can be represented as a signed 20 bit integer.
+func is20Bit(n int64) bool {
+ return -(1<<19) <= n && n < (1<<19)
+}
+
// b2i translates a boolean value to 0 or 1 for assigning to auxInt.
func b2i(b bool) int64 {
if b {
@@ -254,6 +403,19 @@ func isSamePtr(p1, p2 *Value) bool {
return false
}
+// 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:
+ return 8
+ case align%4 == 0:
+ return 4
+ case align%2 == 0:
+ return 2
+ }
+ return 1
+}
+
// mergePoint finds a block among a's blocks which dominates b and is itself
// dominated by all of a's blocks. Returns nil if it can't find one.
// Might return nil even if one does exist.
@@ -314,6 +476,24 @@ func clobber(v *Value) bool {
return true
}
+// noteRule is an easy way to track if a rule is matched when writing
+// new ones. Make the rule of interest also conditional on
+// noteRule("note to self: rule of interest matched")
+// and that message will print when the rule matches.
+func noteRule(s string) bool {
+ fmt.Println(s)
+ return true
+}
+
+// warnRule generates a compiler debug output with string s when
+// 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)
+ }
+ return true
+}
+
// logRule logs the use of the rule s. This will only be enabled if
// rewrite rules were generated with the -log option, see gen/rulegen.go.
func logRule(s string) {
diff --git a/src/cmd/compile/internal/ssa/rewrite386.go b/src/cmd/compile/internal/ssa/rewrite386.go
new file mode 100644
index 0000000..741886d
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/rewrite386.go
@@ -0,0 +1,14787 @@
+// autogenerated from gen/386.rules: do not edit!
+// generated with: cd gen; go run *.go
+
+package ssa
+
+import "math"
+
+var _ = math.MinInt8 // in case not otherwise used
+func rewriteValue386(v *Value, config *Config) bool {
+ switch v.Op {
+ case Op386ADCL:
+ return rewriteValue386_Op386ADCL(v, config)
+ case Op386ADDL:
+ return rewriteValue386_Op386ADDL(v, config)
+ case Op386ADDLcarry:
+ return rewriteValue386_Op386ADDLcarry(v, config)
+ case Op386ADDLconst:
+ return rewriteValue386_Op386ADDLconst(v, config)
+ case Op386ANDL:
+ return rewriteValue386_Op386ANDL(v, config)
+ case Op386ANDLconst:
+ return rewriteValue386_Op386ANDLconst(v, config)
+ case Op386CMPB:
+ return rewriteValue386_Op386CMPB(v, config)
+ case Op386CMPBconst:
+ return rewriteValue386_Op386CMPBconst(v, config)
+ case Op386CMPL:
+ return rewriteValue386_Op386CMPL(v, config)
+ case Op386CMPLconst:
+ return rewriteValue386_Op386CMPLconst(v, config)
+ case Op386CMPW:
+ return rewriteValue386_Op386CMPW(v, config)
+ case Op386CMPWconst:
+ return rewriteValue386_Op386CMPWconst(v, config)
+ case Op386LEAL:
+ return rewriteValue386_Op386LEAL(v, config)
+ case Op386LEAL1:
+ return rewriteValue386_Op386LEAL1(v, config)
+ case Op386LEAL2:
+ return rewriteValue386_Op386LEAL2(v, config)
+ case Op386LEAL4:
+ return rewriteValue386_Op386LEAL4(v, config)
+ case Op386LEAL8:
+ return rewriteValue386_Op386LEAL8(v, config)
+ case Op386MOVBLSX:
+ return rewriteValue386_Op386MOVBLSX(v, config)
+ case Op386MOVBLSXload:
+ return rewriteValue386_Op386MOVBLSXload(v, config)
+ case Op386MOVBLZX:
+ return rewriteValue386_Op386MOVBLZX(v, config)
+ case Op386MOVBload:
+ return rewriteValue386_Op386MOVBload(v, config)
+ case Op386MOVBloadidx1:
+ return rewriteValue386_Op386MOVBloadidx1(v, config)
+ case Op386MOVBstore:
+ return rewriteValue386_Op386MOVBstore(v, config)
+ case Op386MOVBstoreconst:
+ return rewriteValue386_Op386MOVBstoreconst(v, config)
+ case Op386MOVBstoreconstidx1:
+ return rewriteValue386_Op386MOVBstoreconstidx1(v, config)
+ case Op386MOVBstoreidx1:
+ return rewriteValue386_Op386MOVBstoreidx1(v, config)
+ case Op386MOVLload:
+ return rewriteValue386_Op386MOVLload(v, config)
+ case Op386MOVLloadidx1:
+ return rewriteValue386_Op386MOVLloadidx1(v, config)
+ case Op386MOVLloadidx4:
+ return rewriteValue386_Op386MOVLloadidx4(v, config)
+ case Op386MOVLstore:
+ return rewriteValue386_Op386MOVLstore(v, config)
+ case Op386MOVLstoreconst:
+ return rewriteValue386_Op386MOVLstoreconst(v, config)
+ case Op386MOVLstoreconstidx1:
+ return rewriteValue386_Op386MOVLstoreconstidx1(v, config)
+ case Op386MOVLstoreconstidx4:
+ return rewriteValue386_Op386MOVLstoreconstidx4(v, config)
+ case Op386MOVLstoreidx1:
+ return rewriteValue386_Op386MOVLstoreidx1(v, config)
+ case Op386MOVLstoreidx4:
+ return rewriteValue386_Op386MOVLstoreidx4(v, config)
+ case Op386MOVSDconst:
+ return rewriteValue386_Op386MOVSDconst(v, config)
+ case Op386MOVSDload:
+ return rewriteValue386_Op386MOVSDload(v, config)
+ case Op386MOVSDloadidx1:
+ return rewriteValue386_Op386MOVSDloadidx1(v, config)
+ case Op386MOVSDloadidx8:
+ return rewriteValue386_Op386MOVSDloadidx8(v, config)
+ case Op386MOVSDstore:
+ return rewriteValue386_Op386MOVSDstore(v, config)
+ case Op386MOVSDstoreidx1:
+ return rewriteValue386_Op386MOVSDstoreidx1(v, config)
+ case Op386MOVSDstoreidx8:
+ return rewriteValue386_Op386MOVSDstoreidx8(v, config)
+ case Op386MOVSSconst:
+ return rewriteValue386_Op386MOVSSconst(v, config)
+ case Op386MOVSSload:
+ return rewriteValue386_Op386MOVSSload(v, config)
+ case Op386MOVSSloadidx1:
+ return rewriteValue386_Op386MOVSSloadidx1(v, config)
+ case Op386MOVSSloadidx4:
+ return rewriteValue386_Op386MOVSSloadidx4(v, config)
+ case Op386MOVSSstore:
+ return rewriteValue386_Op386MOVSSstore(v, config)
+ case Op386MOVSSstoreidx1:
+ return rewriteValue386_Op386MOVSSstoreidx1(v, config)
+ case Op386MOVSSstoreidx4:
+ return rewriteValue386_Op386MOVSSstoreidx4(v, config)
+ case Op386MOVWLSX:
+ return rewriteValue386_Op386MOVWLSX(v, config)
+ case Op386MOVWLSXload:
+ return rewriteValue386_Op386MOVWLSXload(v, config)
+ case Op386MOVWLZX:
+ return rewriteValue386_Op386MOVWLZX(v, config)
+ case Op386MOVWload:
+ return rewriteValue386_Op386MOVWload(v, config)
+ case Op386MOVWloadidx1:
+ return rewriteValue386_Op386MOVWloadidx1(v, config)
+ case Op386MOVWloadidx2:
+ return rewriteValue386_Op386MOVWloadidx2(v, config)
+ case Op386MOVWstore:
+ return rewriteValue386_Op386MOVWstore(v, config)
+ case Op386MOVWstoreconst:
+ return rewriteValue386_Op386MOVWstoreconst(v, config)
+ case Op386MOVWstoreconstidx1:
+ return rewriteValue386_Op386MOVWstoreconstidx1(v, config)
+ case Op386MOVWstoreconstidx2:
+ return rewriteValue386_Op386MOVWstoreconstidx2(v, config)
+ case Op386MOVWstoreidx1:
+ return rewriteValue386_Op386MOVWstoreidx1(v, config)
+ case Op386MOVWstoreidx2:
+ return rewriteValue386_Op386MOVWstoreidx2(v, config)
+ case Op386MULL:
+ return rewriteValue386_Op386MULL(v, config)
+ case Op386MULLconst:
+ return rewriteValue386_Op386MULLconst(v, config)
+ case Op386NEGL:
+ return rewriteValue386_Op386NEGL(v, config)
+ case Op386NOTL:
+ return rewriteValue386_Op386NOTL(v, config)
+ case Op386ORL:
+ return rewriteValue386_Op386ORL(v, config)
+ case Op386ORLconst:
+ return rewriteValue386_Op386ORLconst(v, config)
+ case Op386ROLBconst:
+ return rewriteValue386_Op386ROLBconst(v, config)
+ case Op386ROLLconst:
+ return rewriteValue386_Op386ROLLconst(v, config)
+ case Op386ROLWconst:
+ return rewriteValue386_Op386ROLWconst(v, config)
+ case Op386SARB:
+ return rewriteValue386_Op386SARB(v, config)
+ case Op386SARBconst:
+ return rewriteValue386_Op386SARBconst(v, config)
+ case Op386SARL:
+ return rewriteValue386_Op386SARL(v, config)
+ case Op386SARLconst:
+ return rewriteValue386_Op386SARLconst(v, config)
+ case Op386SARW:
+ return rewriteValue386_Op386SARW(v, config)
+ case Op386SARWconst:
+ return rewriteValue386_Op386SARWconst(v, config)
+ case Op386SBBL:
+ return rewriteValue386_Op386SBBL(v, config)
+ case Op386SBBLcarrymask:
+ return rewriteValue386_Op386SBBLcarrymask(v, config)
+ case Op386SETA:
+ return rewriteValue386_Op386SETA(v, config)
+ case Op386SETAE:
+ return rewriteValue386_Op386SETAE(v, config)
+ case Op386SETB:
+ return rewriteValue386_Op386SETB(v, config)
+ case Op386SETBE:
+ return rewriteValue386_Op386SETBE(v, config)
+ case Op386SETEQ:
+ return rewriteValue386_Op386SETEQ(v, config)
+ case Op386SETG:
+ return rewriteValue386_Op386SETG(v, config)
+ case Op386SETGE:
+ return rewriteValue386_Op386SETGE(v, config)
+ case Op386SETL:
+ return rewriteValue386_Op386SETL(v, config)
+ case Op386SETLE:
+ return rewriteValue386_Op386SETLE(v, config)
+ case Op386SETNE:
+ return rewriteValue386_Op386SETNE(v, config)
+ case Op386SHLL:
+ return rewriteValue386_Op386SHLL(v, config)
+ case Op386SHRB:
+ return rewriteValue386_Op386SHRB(v, config)
+ case Op386SHRL:
+ return rewriteValue386_Op386SHRL(v, config)
+ case Op386SHRW:
+ return rewriteValue386_Op386SHRW(v, config)
+ case Op386SUBL:
+ return rewriteValue386_Op386SUBL(v, config)
+ case Op386SUBLcarry:
+ return rewriteValue386_Op386SUBLcarry(v, config)
+ case Op386SUBLconst:
+ return rewriteValue386_Op386SUBLconst(v, config)
+ case Op386XORL:
+ return rewriteValue386_Op386XORL(v, config)
+ case Op386XORLconst:
+ return rewriteValue386_Op386XORLconst(v, config)
+ case OpAdd16:
+ return rewriteValue386_OpAdd16(v, config)
+ case OpAdd32:
+ return rewriteValue386_OpAdd32(v, config)
+ case OpAdd32F:
+ return rewriteValue386_OpAdd32F(v, config)
+ case OpAdd32carry:
+ return rewriteValue386_OpAdd32carry(v, config)
+ case OpAdd32withcarry:
+ return rewriteValue386_OpAdd32withcarry(v, config)
+ case OpAdd64F:
+ return rewriteValue386_OpAdd64F(v, config)
+ case OpAdd8:
+ return rewriteValue386_OpAdd8(v, config)
+ case OpAddPtr:
+ return rewriteValue386_OpAddPtr(v, config)
+ case OpAddr:
+ return rewriteValue386_OpAddr(v, config)
+ case OpAnd16:
+ return rewriteValue386_OpAnd16(v, config)
+ case OpAnd32:
+ return rewriteValue386_OpAnd32(v, config)
+ case OpAnd8:
+ return rewriteValue386_OpAnd8(v, config)
+ case OpAndB:
+ return rewriteValue386_OpAndB(v, config)
+ case OpBswap32:
+ return rewriteValue386_OpBswap32(v, config)
+ case OpClosureCall:
+ return rewriteValue386_OpClosureCall(v, config)
+ case OpCom16:
+ return rewriteValue386_OpCom16(v, config)
+ case OpCom32:
+ return rewriteValue386_OpCom32(v, config)
+ case OpCom8:
+ return rewriteValue386_OpCom8(v, config)
+ case OpConst16:
+ return rewriteValue386_OpConst16(v, config)
+ case OpConst32:
+ return rewriteValue386_OpConst32(v, config)
+ case OpConst32F:
+ return rewriteValue386_OpConst32F(v, config)
+ case OpConst64F:
+ return rewriteValue386_OpConst64F(v, config)
+ case OpConst8:
+ return rewriteValue386_OpConst8(v, config)
+ case OpConstBool:
+ return rewriteValue386_OpConstBool(v, config)
+ case OpConstNil:
+ return rewriteValue386_OpConstNil(v, config)
+ case OpConvert:
+ return rewriteValue386_OpConvert(v, config)
+ case OpCvt32Fto32:
+ return rewriteValue386_OpCvt32Fto32(v, config)
+ case OpCvt32Fto64F:
+ return rewriteValue386_OpCvt32Fto64F(v, config)
+ case OpCvt32to32F:
+ return rewriteValue386_OpCvt32to32F(v, config)
+ case OpCvt32to64F:
+ return rewriteValue386_OpCvt32to64F(v, config)
+ case OpCvt64Fto32:
+ return rewriteValue386_OpCvt64Fto32(v, config)
+ case OpCvt64Fto32F:
+ return rewriteValue386_OpCvt64Fto32F(v, config)
+ case OpDeferCall:
+ return rewriteValue386_OpDeferCall(v, config)
+ case OpDiv16:
+ return rewriteValue386_OpDiv16(v, config)
+ case OpDiv16u:
+ return rewriteValue386_OpDiv16u(v, config)
+ case OpDiv32:
+ return rewriteValue386_OpDiv32(v, config)
+ case OpDiv32F:
+ return rewriteValue386_OpDiv32F(v, config)
+ case OpDiv32u:
+ return rewriteValue386_OpDiv32u(v, config)
+ case OpDiv64F:
+ return rewriteValue386_OpDiv64F(v, config)
+ case OpDiv8:
+ return rewriteValue386_OpDiv8(v, config)
+ case OpDiv8u:
+ return rewriteValue386_OpDiv8u(v, config)
+ case OpEq16:
+ return rewriteValue386_OpEq16(v, config)
+ case OpEq32:
+ return rewriteValue386_OpEq32(v, config)
+ case OpEq32F:
+ return rewriteValue386_OpEq32F(v, config)
+ case OpEq64F:
+ return rewriteValue386_OpEq64F(v, config)
+ case OpEq8:
+ return rewriteValue386_OpEq8(v, config)
+ case OpEqB:
+ return rewriteValue386_OpEqB(v, config)
+ case OpEqPtr:
+ return rewriteValue386_OpEqPtr(v, config)
+ case OpGeq16:
+ return rewriteValue386_OpGeq16(v, config)
+ case OpGeq16U:
+ return rewriteValue386_OpGeq16U(v, config)
+ case OpGeq32:
+ return rewriteValue386_OpGeq32(v, config)
+ case OpGeq32F:
+ return rewriteValue386_OpGeq32F(v, config)
+ case OpGeq32U:
+ return rewriteValue386_OpGeq32U(v, config)
+ case OpGeq64F:
+ return rewriteValue386_OpGeq64F(v, config)
+ case OpGeq8:
+ return rewriteValue386_OpGeq8(v, config)
+ case OpGeq8U:
+ return rewriteValue386_OpGeq8U(v, config)
+ case OpGetClosurePtr:
+ return rewriteValue386_OpGetClosurePtr(v, config)
+ case OpGetG:
+ return rewriteValue386_OpGetG(v, config)
+ case OpGoCall:
+ return rewriteValue386_OpGoCall(v, config)
+ case OpGreater16:
+ return rewriteValue386_OpGreater16(v, config)
+ case OpGreater16U:
+ return rewriteValue386_OpGreater16U(v, config)
+ case OpGreater32:
+ return rewriteValue386_OpGreater32(v, config)
+ case OpGreater32F:
+ return rewriteValue386_OpGreater32F(v, config)
+ case OpGreater32U:
+ return rewriteValue386_OpGreater32U(v, config)
+ case OpGreater64F:
+ return rewriteValue386_OpGreater64F(v, config)
+ case OpGreater8:
+ return rewriteValue386_OpGreater8(v, config)
+ case OpGreater8U:
+ return rewriteValue386_OpGreater8U(v, config)
+ case OpHmul16:
+ return rewriteValue386_OpHmul16(v, config)
+ case OpHmul16u:
+ return rewriteValue386_OpHmul16u(v, config)
+ case OpHmul32:
+ return rewriteValue386_OpHmul32(v, config)
+ case OpHmul32u:
+ return rewriteValue386_OpHmul32u(v, config)
+ case OpHmul8:
+ return rewriteValue386_OpHmul8(v, config)
+ case OpHmul8u:
+ return rewriteValue386_OpHmul8u(v, config)
+ case OpInterCall:
+ return rewriteValue386_OpInterCall(v, config)
+ case OpIsInBounds:
+ return rewriteValue386_OpIsInBounds(v, config)
+ case OpIsNonNil:
+ return rewriteValue386_OpIsNonNil(v, config)
+ case OpIsSliceInBounds:
+ return rewriteValue386_OpIsSliceInBounds(v, config)
+ case OpLeq16:
+ return rewriteValue386_OpLeq16(v, config)
+ case OpLeq16U:
+ return rewriteValue386_OpLeq16U(v, config)
+ case OpLeq32:
+ return rewriteValue386_OpLeq32(v, config)
+ case OpLeq32F:
+ return rewriteValue386_OpLeq32F(v, config)
+ case OpLeq32U:
+ return rewriteValue386_OpLeq32U(v, config)
+ case OpLeq64F:
+ return rewriteValue386_OpLeq64F(v, config)
+ case OpLeq8:
+ return rewriteValue386_OpLeq8(v, config)
+ case OpLeq8U:
+ return rewriteValue386_OpLeq8U(v, config)
+ case OpLess16:
+ return rewriteValue386_OpLess16(v, config)
+ case OpLess16U:
+ return rewriteValue386_OpLess16U(v, config)
+ case OpLess32:
+ return rewriteValue386_OpLess32(v, config)
+ case OpLess32F:
+ return rewriteValue386_OpLess32F(v, config)
+ case OpLess32U:
+ return rewriteValue386_OpLess32U(v, config)
+ case OpLess64F:
+ return rewriteValue386_OpLess64F(v, config)
+ case OpLess8:
+ return rewriteValue386_OpLess8(v, config)
+ case OpLess8U:
+ return rewriteValue386_OpLess8U(v, config)
+ 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)
+ case OpLsh16x16:
+ return rewriteValue386_OpLsh16x16(v, config)
+ case OpLsh16x32:
+ return rewriteValue386_OpLsh16x32(v, config)
+ case OpLsh16x64:
+ return rewriteValue386_OpLsh16x64(v, config)
+ case OpLsh16x8:
+ return rewriteValue386_OpLsh16x8(v, config)
+ case OpLsh32x16:
+ return rewriteValue386_OpLsh32x16(v, config)
+ case OpLsh32x32:
+ return rewriteValue386_OpLsh32x32(v, config)
+ case OpLsh32x64:
+ return rewriteValue386_OpLsh32x64(v, config)
+ case OpLsh32x8:
+ return rewriteValue386_OpLsh32x8(v, config)
+ case OpLsh8x16:
+ return rewriteValue386_OpLsh8x16(v, config)
+ case OpLsh8x32:
+ return rewriteValue386_OpLsh8x32(v, config)
+ case OpLsh8x64:
+ return rewriteValue386_OpLsh8x64(v, config)
+ case OpLsh8x8:
+ return rewriteValue386_OpLsh8x8(v, config)
+ case OpMod16:
+ return rewriteValue386_OpMod16(v, config)
+ case OpMod16u:
+ return rewriteValue386_OpMod16u(v, config)
+ case OpMod32:
+ return rewriteValue386_OpMod32(v, config)
+ case OpMod32u:
+ return rewriteValue386_OpMod32u(v, config)
+ case OpMod8:
+ return rewriteValue386_OpMod8(v, config)
+ case OpMod8u:
+ return rewriteValue386_OpMod8u(v, config)
+ case OpMove:
+ return rewriteValue386_OpMove(v, config)
+ case OpMul16:
+ return rewriteValue386_OpMul16(v, config)
+ case OpMul32:
+ return rewriteValue386_OpMul32(v, config)
+ case OpMul32F:
+ return rewriteValue386_OpMul32F(v, config)
+ case OpMul32uhilo:
+ return rewriteValue386_OpMul32uhilo(v, config)
+ case OpMul64F:
+ return rewriteValue386_OpMul64F(v, config)
+ case OpMul8:
+ return rewriteValue386_OpMul8(v, config)
+ case OpNeg16:
+ return rewriteValue386_OpNeg16(v, config)
+ case OpNeg32:
+ return rewriteValue386_OpNeg32(v, config)
+ case OpNeg32F:
+ return rewriteValue386_OpNeg32F(v, config)
+ case OpNeg64F:
+ return rewriteValue386_OpNeg64F(v, config)
+ case OpNeg8:
+ return rewriteValue386_OpNeg8(v, config)
+ case OpNeq16:
+ return rewriteValue386_OpNeq16(v, config)
+ case OpNeq32:
+ return rewriteValue386_OpNeq32(v, config)
+ case OpNeq32F:
+ return rewriteValue386_OpNeq32F(v, config)
+ case OpNeq64F:
+ return rewriteValue386_OpNeq64F(v, config)
+ case OpNeq8:
+ return rewriteValue386_OpNeq8(v, config)
+ case OpNeqB:
+ return rewriteValue386_OpNeqB(v, config)
+ case OpNeqPtr:
+ return rewriteValue386_OpNeqPtr(v, config)
+ case OpNilCheck:
+ return rewriteValue386_OpNilCheck(v, config)
+ case OpNot:
+ return rewriteValue386_OpNot(v, config)
+ case OpOffPtr:
+ return rewriteValue386_OpOffPtr(v, config)
+ case OpOr16:
+ return rewriteValue386_OpOr16(v, config)
+ case OpOr32:
+ return rewriteValue386_OpOr32(v, config)
+ case OpOr8:
+ return rewriteValue386_OpOr8(v, config)
+ case OpOrB:
+ return rewriteValue386_OpOrB(v, config)
+ case OpRsh16Ux16:
+ return rewriteValue386_OpRsh16Ux16(v, config)
+ case OpRsh16Ux32:
+ return rewriteValue386_OpRsh16Ux32(v, config)
+ case OpRsh16Ux64:
+ return rewriteValue386_OpRsh16Ux64(v, config)
+ case OpRsh16Ux8:
+ return rewriteValue386_OpRsh16Ux8(v, config)
+ case OpRsh16x16:
+ return rewriteValue386_OpRsh16x16(v, config)
+ case OpRsh16x32:
+ return rewriteValue386_OpRsh16x32(v, config)
+ case OpRsh16x64:
+ return rewriteValue386_OpRsh16x64(v, config)
+ case OpRsh16x8:
+ return rewriteValue386_OpRsh16x8(v, config)
+ case OpRsh32Ux16:
+ return rewriteValue386_OpRsh32Ux16(v, config)
+ case OpRsh32Ux32:
+ return rewriteValue386_OpRsh32Ux32(v, config)
+ case OpRsh32Ux64:
+ return rewriteValue386_OpRsh32Ux64(v, config)
+ case OpRsh32Ux8:
+ return rewriteValue386_OpRsh32Ux8(v, config)
+ case OpRsh32x16:
+ return rewriteValue386_OpRsh32x16(v, config)
+ case OpRsh32x32:
+ return rewriteValue386_OpRsh32x32(v, config)
+ case OpRsh32x64:
+ return rewriteValue386_OpRsh32x64(v, config)
+ case OpRsh32x8:
+ return rewriteValue386_OpRsh32x8(v, config)
+ case OpRsh8Ux16:
+ return rewriteValue386_OpRsh8Ux16(v, config)
+ case OpRsh8Ux32:
+ return rewriteValue386_OpRsh8Ux32(v, config)
+ case OpRsh8Ux64:
+ return rewriteValue386_OpRsh8Ux64(v, config)
+ case OpRsh8Ux8:
+ return rewriteValue386_OpRsh8Ux8(v, config)
+ case OpRsh8x16:
+ return rewriteValue386_OpRsh8x16(v, config)
+ case OpRsh8x32:
+ return rewriteValue386_OpRsh8x32(v, config)
+ case OpRsh8x64:
+ return rewriteValue386_OpRsh8x64(v, config)
+ case OpRsh8x8:
+ return rewriteValue386_OpRsh8x8(v, config)
+ case OpSignExt16to32:
+ return rewriteValue386_OpSignExt16to32(v, config)
+ case OpSignExt8to16:
+ return rewriteValue386_OpSignExt8to16(v, config)
+ case OpSignExt8to32:
+ return rewriteValue386_OpSignExt8to32(v, config)
+ case OpSignmask:
+ return rewriteValue386_OpSignmask(v, config)
+ case OpSlicemask:
+ return rewriteValue386_OpSlicemask(v, config)
+ case OpSqrt:
+ return rewriteValue386_OpSqrt(v, config)
+ case OpStaticCall:
+ return rewriteValue386_OpStaticCall(v, config)
+ case OpStore:
+ return rewriteValue386_OpStore(v, config)
+ case OpSub16:
+ return rewriteValue386_OpSub16(v, config)
+ case OpSub32:
+ return rewriteValue386_OpSub32(v, config)
+ case OpSub32F:
+ return rewriteValue386_OpSub32F(v, config)
+ case OpSub32carry:
+ return rewriteValue386_OpSub32carry(v, config)
+ case OpSub32withcarry:
+ return rewriteValue386_OpSub32withcarry(v, config)
+ case OpSub64F:
+ return rewriteValue386_OpSub64F(v, config)
+ case OpSub8:
+ return rewriteValue386_OpSub8(v, config)
+ case OpSubPtr:
+ return rewriteValue386_OpSubPtr(v, config)
+ case OpTrunc16to8:
+ return rewriteValue386_OpTrunc16to8(v, config)
+ case OpTrunc32to16:
+ return rewriteValue386_OpTrunc32to16(v, config)
+ case OpTrunc32to8:
+ return rewriteValue386_OpTrunc32to8(v, config)
+ case OpXor16:
+ return rewriteValue386_OpXor16(v, config)
+ case OpXor32:
+ return rewriteValue386_OpXor32(v, config)
+ case OpXor8:
+ return rewriteValue386_OpXor8(v, config)
+ case OpZero:
+ return rewriteValue386_OpZero(v, config)
+ case OpZeroExt16to32:
+ return rewriteValue386_OpZeroExt16to32(v, config)
+ case OpZeroExt8to16:
+ return rewriteValue386_OpZeroExt8to16(v, config)
+ case OpZeroExt8to32:
+ return rewriteValue386_OpZeroExt8to32(v, config)
+ case OpZeromask:
+ return rewriteValue386_OpZeromask(v, config)
+ }
+ return false
+}
+func rewriteValue386_Op386ADCL(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ADCL x (MOVLconst [c]) f)
+ // cond:
+ // result: (ADCLconst [c] x f)
+ for {
+ 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
+ }
+ // match: (ADCL (MOVLconst [c]) x f)
+ // cond:
+ // result: (ADCLconst [c] x f)
+ for {
+ 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
+ }
+ return false
+}
+func rewriteValue386_Op386ADDL(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ADDL x (MOVLconst [c]))
+ // cond:
+ // result: (ADDLconst [c] x)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != Op386MOVLconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(Op386ADDLconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (ADDL (MOVLconst [c]) x)
+ // cond:
+ // result: (ADDLconst [c] x)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != Op386MOVLconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ v.reset(Op386ADDLconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (ADDL x (SHLLconst [3] y))
+ // cond:
+ // result: (LEAL8 x y)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != Op386SHLLconst {
+ break
+ }
+ if v_1.AuxInt != 3 {
+ break
+ }
+ y := v_1.Args[0]
+ v.reset(Op386LEAL8)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (ADDL x (SHLLconst [2] y))
+ // cond:
+ // result: (LEAL4 x y)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != Op386SHLLconst {
+ break
+ }
+ if v_1.AuxInt != 2 {
+ break
+ }
+ y := v_1.Args[0]
+ v.reset(Op386LEAL4)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (ADDL x (SHLLconst [1] y))
+ // cond:
+ // result: (LEAL2 x y)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != Op386SHLLconst {
+ break
+ }
+ if v_1.AuxInt != 1 {
+ break
+ }
+ y := v_1.Args[0]
+ v.reset(Op386LEAL2)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (ADDL x (ADDL y y))
+ // cond:
+ // result: (LEAL2 x y)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != Op386ADDL {
+ break
+ }
+ y := v_1.Args[0]
+ if y != v_1.Args[1] {
+ break
+ }
+ v.reset(Op386LEAL2)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (ADDL x (ADDL x y))
+ // cond:
+ // result: (LEAL2 y x)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != Op386ADDL {
+ break
+ }
+ if x != v_1.Args[0] {
+ break
+ }
+ y := v_1.Args[1]
+ v.reset(Op386LEAL2)
+ v.AddArg(y)
+ v.AddArg(x)
+ return true
+ }
+ // match: (ADDL x (ADDL y x))
+ // cond:
+ // result: (LEAL2 y x)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != Op386ADDL {
+ break
+ }
+ y := v_1.Args[0]
+ if x != v_1.Args[1] {
+ break
+ }
+ v.reset(Op386LEAL2)
+ v.AddArg(y)
+ v.AddArg(x)
+ return true
+ }
+ // match: (ADDL (ADDLconst [c] x) y)
+ // cond:
+ // result: (LEAL1 [c] x y)
+ for {
+ 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 x (ADDLconst [c] y))
+ // cond:
+ // result: (LEAL1 [c] x y)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != Op386ADDLconst {
+ break
+ }
+ c := v_1.AuxInt
+ y := v_1.Args[0]
+ v.reset(Op386LEAL1)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (ADDL x (LEAL [c] {s} y))
+ // cond: x.Op != OpSB && y.Op != OpSB
+ // result: (LEAL1 [c] {s} x y)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != Op386LEAL {
+ break
+ }
+ c := v_1.AuxInt
+ s := v_1.Aux
+ y := v_1.Args[0]
+ if !(x.Op != OpSB && y.Op != OpSB) {
+ break
+ }
+ v.reset(Op386LEAL1)
+ v.AuxInt = c
+ v.Aux = s
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (ADDL (LEAL [c] {s} x) y)
+ // cond: x.Op != OpSB && y.Op != OpSB
+ // result: (LEAL1 [c] {s} x y)
+ for {
+ 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]
+ if !(x.Op != OpSB && y.Op != OpSB) {
+ break
+ }
+ v.reset(Op386LEAL1)
+ v.AuxInt = c
+ v.Aux = s
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (ADDL x (NEGL y))
+ // cond:
+ // result: (SUBL x y)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != Op386NEGL {
+ break
+ }
+ y := v_1.Args[0]
+ 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
+ // match: (ADDLcarry x (MOVLconst [c]))
+ // cond:
+ // result: (ADDLconstcarry [c] x)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != Op386MOVLconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(Op386ADDLconstcarry)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (ADDLcarry (MOVLconst [c]) x)
+ // cond:
+ // result: (ADDLconstcarry [c] x)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != Op386MOVLconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ v.reset(Op386ADDLconstcarry)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValue386_Op386ADDLconst(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ADDLconst [c] (ADDL x y))
+ // cond:
+ // result: (LEAL1 [c] x y)
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != Op386ADDL {
+ break
+ }
+ x := v_0.Args[0]
+ y := v_0.Args[1]
+ v.reset(Op386LEAL1)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (ADDLconst [c] (LEAL [d] {s} x))
+ // cond: is32Bit(c+d)
+ // result: (LEAL [c+d] {s} x)
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != Op386LEAL {
+ break
+ }
+ d := v_0.AuxInt
+ s := v_0.Aux
+ x := v_0.Args[0]
+ if !(is32Bit(c + d)) {
+ break
+ }
+ v.reset(Op386LEAL)
+ v.AuxInt = c + d
+ v.Aux = s
+ v.AddArg(x)
+ return true
+ }
+ // match: (ADDLconst [c] (LEAL1 [d] {s} x y))
+ // cond: is32Bit(c+d)
+ // result: (LEAL1 [c+d] {s} x y)
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != Op386LEAL1 {
+ break
+ }
+ d := v_0.AuxInt
+ s := v_0.Aux
+ x := v_0.Args[0]
+ y := v_0.Args[1]
+ if !(is32Bit(c + d)) {
+ break
+ }
+ v.reset(Op386LEAL1)
+ v.AuxInt = c + d
+ v.Aux = s
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (ADDLconst [c] (LEAL2 [d] {s} x y))
+ // cond: is32Bit(c+d)
+ // result: (LEAL2 [c+d] {s} x y)
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != Op386LEAL2 {
+ break
+ }
+ d := v_0.AuxInt
+ s := v_0.Aux
+ x := v_0.Args[0]
+ y := v_0.Args[1]
+ if !(is32Bit(c + d)) {
+ break
+ }
+ v.reset(Op386LEAL2)
+ v.AuxInt = c + d
+ v.Aux = s
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (ADDLconst [c] (LEAL4 [d] {s} x y))
+ // cond: is32Bit(c+d)
+ // result: (LEAL4 [c+d] {s} x y)
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != Op386LEAL4 {
+ break
+ }
+ d := v_0.AuxInt
+ s := v_0.Aux
+ x := v_0.Args[0]
+ y := v_0.Args[1]
+ if !(is32Bit(c + d)) {
+ break
+ }
+ v.reset(Op386LEAL4)
+ v.AuxInt = c + d
+ v.Aux = s
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (ADDLconst [c] (LEAL8 [d] {s} x y))
+ // cond: is32Bit(c+d)
+ // result: (LEAL8 [c+d] {s} x y)
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != Op386LEAL8 {
+ break
+ }
+ d := v_0.AuxInt
+ s := v_0.Aux
+ x := v_0.Args[0]
+ y := v_0.Args[1]
+ if !(is32Bit(c + d)) {
+ break
+ }
+ v.reset(Op386LEAL8)
+ v.AuxInt = c + d
+ v.Aux = s
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (ADDLconst [c] x)
+ // cond: int32(c)==0
+ // result: x
+ for {
+ c := v.AuxInt
+ x := v.Args[0]
+ if !(int32(c) == 0) {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ // match: (ADDLconst [c] (MOVLconst [d]))
+ // cond:
+ // result: (MOVLconst [int64(int32(c+d))])
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != Op386MOVLconst {
+ break
+ }
+ d := v_0.AuxInt
+ v.reset(Op386MOVLconst)
+ v.AuxInt = int64(int32(c + d))
+ return true
+ }
+ // match: (ADDLconst [c] (ADDLconst [d] x))
+ // cond:
+ // result: (ADDLconst [int64(int32(c+d))] x)
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != Op386ADDLconst {
+ break
+ }
+ d := v_0.AuxInt
+ x := v_0.Args[0]
+ v.reset(Op386ADDLconst)
+ v.AuxInt = int64(int32(c + d))
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValue386_Op386ANDL(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ANDL x (MOVLconst [c]))
+ // cond:
+ // result: (ANDLconst [c] x)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != Op386MOVLconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(Op386ANDLconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (ANDL (MOVLconst [c]) x)
+ // cond:
+ // result: (ANDLconst [c] x)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != Op386MOVLconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ v.reset(Op386ANDLconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (ANDL x x)
+ // cond:
+ // result: x
+ for {
+ x := v.Args[0]
+ if x != v.Args[1] {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValue386_Op386ANDLconst(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ANDLconst [c] (ANDLconst [d] x))
+ // cond:
+ // result: (ANDLconst [c & d] x)
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != Op386ANDLconst {
+ break
+ }
+ d := v_0.AuxInt
+ x := v_0.Args[0]
+ v.reset(Op386ANDLconst)
+ v.AuxInt = c & d
+ v.AddArg(x)
+ return true
+ }
+ // match: (ANDLconst [c] _)
+ // cond: int32(c)==0
+ // result: (MOVLconst [0])
+ for {
+ c := v.AuxInt
+ if !(int32(c) == 0) {
+ break
+ }
+ v.reset(Op386MOVLconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (ANDLconst [c] x)
+ // cond: int32(c)==-1
+ // result: x
+ for {
+ c := v.AuxInt
+ x := v.Args[0]
+ if !(int32(c) == -1) {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ // match: (ANDLconst [c] (MOVLconst [d]))
+ // cond:
+ // result: (MOVLconst [c&d])
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != Op386MOVLconst {
+ break
+ }
+ d := v_0.AuxInt
+ v.reset(Op386MOVLconst)
+ v.AuxInt = c & d
+ return true
+ }
+ return false
+}
+func rewriteValue386_Op386CMPB(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (CMPB x (MOVLconst [c]))
+ // cond:
+ // result: (CMPBconst x [int64(int8(c))])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != Op386MOVLconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(Op386CMPBconst)
+ v.AuxInt = int64(int8(c))
+ v.AddArg(x)
+ return true
+ }
+ // match: (CMPB (MOVLconst [c]) x)
+ // cond:
+ // result: (InvertFlags (CMPBconst x [int64(int8(c))]))
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != Op386MOVLconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ v.reset(Op386InvertFlags)
+ v0 := b.NewValue0(v.Line, Op386CMPBconst, TypeFlags)
+ v0.AuxInt = int64(int8(c))
+ v0.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+ return false
+}
+func rewriteValue386_Op386CMPBconst(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (CMPBconst (MOVLconst [x]) [y])
+ // cond: int8(x)==int8(y)
+ // result: (FlagEQ)
+ for {
+ y := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != Op386MOVLconst {
+ break
+ }
+ x := v_0.AuxInt
+ if !(int8(x) == int8(y)) {
+ break
+ }
+ v.reset(Op386FlagEQ)
+ return true
+ }
+ // match: (CMPBconst (MOVLconst [x]) [y])
+ // cond: int8(x)<int8(y) && uint8(x)<uint8(y)
+ // result: (FlagLT_ULT)
+ for {
+ y := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != Op386MOVLconst {
+ break
+ }
+ x := v_0.AuxInt
+ if !(int8(x) < int8(y) && uint8(x) < uint8(y)) {
+ break
+ }
+ v.reset(Op386FlagLT_ULT)
+ return true
+ }
+ // match: (CMPBconst (MOVLconst [x]) [y])
+ // cond: int8(x)<int8(y) && uint8(x)>uint8(y)
+ // result: (FlagLT_UGT)
+ for {
+ y := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != Op386MOVLconst {
+ break
+ }
+ x := v_0.AuxInt
+ if !(int8(x) < int8(y) && uint8(x) > uint8(y)) {
+ break
+ }
+ v.reset(Op386FlagLT_UGT)
+ return true
+ }
+ // match: (CMPBconst (MOVLconst [x]) [y])
+ // cond: int8(x)>int8(y) && uint8(x)<uint8(y)
+ // result: (FlagGT_ULT)
+ for {
+ y := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != Op386MOVLconst {
+ break
+ }
+ x := v_0.AuxInt
+ if !(int8(x) > int8(y) && uint8(x) < uint8(y)) {
+ break
+ }
+ v.reset(Op386FlagGT_ULT)
+ return true
+ }
+ // match: (CMPBconst (MOVLconst [x]) [y])
+ // cond: int8(x)>int8(y) && uint8(x)>uint8(y)
+ // result: (FlagGT_UGT)
+ for {
+ y := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != Op386MOVLconst {
+ break
+ }
+ x := v_0.AuxInt
+ if !(int8(x) > int8(y) && uint8(x) > uint8(y)) {
+ break
+ }
+ v.reset(Op386FlagGT_UGT)
+ return true
+ }
+ // match: (CMPBconst (ANDLconst _ [m]) [n])
+ // cond: 0 <= int8(m) && int8(m) < int8(n)
+ // result: (FlagLT_ULT)
+ for {
+ n := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != Op386ANDLconst {
+ break
+ }
+ m := v_0.AuxInt
+ if !(0 <= int8(m) && int8(m) < int8(n)) {
+ break
+ }
+ v.reset(Op386FlagLT_ULT)
+ return true
+ }
+ // match: (CMPBconst (ANDL x y) [0])
+ // cond:
+ // result: (TESTB x y)
+ for {
+ if v.AuxInt != 0 {
+ break
+ }
+ v_0 := v.Args[0]
+ if v_0.Op != Op386ANDL {
+ break
+ }
+ x := v_0.Args[0]
+ y := v_0.Args[1]
+ v.reset(Op386TESTB)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (CMPBconst (ANDLconst [c] x) [0])
+ // cond:
+ // result: (TESTBconst [int64(int8(c))] x)
+ for {
+ if v.AuxInt != 0 {
+ break
+ }
+ v_0 := v.Args[0]
+ if v_0.Op != Op386ANDLconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v_0.Args[0]
+ v.reset(Op386TESTBconst)
+ v.AuxInt = int64(int8(c))
+ v.AddArg(x)
+ return true
+ }
+ // match: (CMPBconst x [0])
+ // cond:
+ // result: (TESTB x x)
+ for {
+ if v.AuxInt != 0 {
+ break
+ }
+ x := v.Args[0]
+ v.reset(Op386TESTB)
+ v.AddArg(x)
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValue386_Op386CMPL(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (CMPL x (MOVLconst [c]))
+ // cond:
+ // result: (CMPLconst x [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != Op386MOVLconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(Op386CMPLconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (CMPL (MOVLconst [c]) x)
+ // cond:
+ // result: (InvertFlags (CMPLconst x [c]))
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != Op386MOVLconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ v.reset(Op386InvertFlags)
+ v0 := b.NewValue0(v.Line, Op386CMPLconst, TypeFlags)
+ v0.AuxInt = c
+ v0.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+ return false
+}
+func rewriteValue386_Op386CMPLconst(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (CMPLconst (MOVLconst [x]) [y])
+ // cond: int32(x)==int32(y)
+ // result: (FlagEQ)
+ for {
+ y := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != Op386MOVLconst {
+ break
+ }
+ x := v_0.AuxInt
+ if !(int32(x) == int32(y)) {
+ break
+ }
+ v.reset(Op386FlagEQ)
+ return true
+ }
+ // match: (CMPLconst (MOVLconst [x]) [y])
+ // cond: int32(x)<int32(y) && uint32(x)<uint32(y)
+ // result: (FlagLT_ULT)
+ for {
+ y := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != Op386MOVLconst {
+ break
+ }
+ x := v_0.AuxInt
+ if !(int32(x) < int32(y) && uint32(x) < uint32(y)) {
+ break
+ }
+ v.reset(Op386FlagLT_ULT)
+ return true
+ }
+ // match: (CMPLconst (MOVLconst [x]) [y])
+ // cond: int32(x)<int32(y) && uint32(x)>uint32(y)
+ // result: (FlagLT_UGT)
+ for {
+ y := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != Op386MOVLconst {
+ break
+ }
+ x := v_0.AuxInt
+ if !(int32(x) < int32(y) && uint32(x) > uint32(y)) {
+ break
+ }
+ v.reset(Op386FlagLT_UGT)
+ return true
+ }
+ // match: (CMPLconst (MOVLconst [x]) [y])
+ // cond: int32(x)>int32(y) && uint32(x)<uint32(y)
+ // result: (FlagGT_ULT)
+ for {
+ y := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != Op386MOVLconst {
+ break
+ }
+ x := v_0.AuxInt
+ if !(int32(x) > int32(y) && uint32(x) < uint32(y)) {
+ break
+ }
+ v.reset(Op386FlagGT_ULT)
+ return true
+ }
+ // match: (CMPLconst (MOVLconst [x]) [y])
+ // cond: int32(x)>int32(y) && uint32(x)>uint32(y)
+ // result: (FlagGT_UGT)
+ for {
+ y := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != Op386MOVLconst {
+ break
+ }
+ x := v_0.AuxInt
+ if !(int32(x) > int32(y) && uint32(x) > uint32(y)) {
+ break
+ }
+ v.reset(Op386FlagGT_UGT)
+ return true
+ }
+ // match: (CMPLconst (SHRLconst _ [c]) [n])
+ // cond: 0 <= n && 0 < c && c <= 32 && (1<<uint64(32-c)) <= uint64(n)
+ // result: (FlagLT_ULT)
+ for {
+ n := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != Op386SHRLconst {
+ break
+ }
+ c := v_0.AuxInt
+ if !(0 <= n && 0 < c && c <= 32 && (1<<uint64(32-c)) <= uint64(n)) {
+ break
+ }
+ v.reset(Op386FlagLT_ULT)
+ return true
+ }
+ // match: (CMPLconst (ANDLconst _ [m]) [n])
+ // cond: 0 <= int32(m) && int32(m) < int32(n)
+ // result: (FlagLT_ULT)
+ for {
+ n := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != Op386ANDLconst {
+ break
+ }
+ m := v_0.AuxInt
+ if !(0 <= int32(m) && int32(m) < int32(n)) {
+ break
+ }
+ v.reset(Op386FlagLT_ULT)
+ return true
+ }
+ // match: (CMPLconst (ANDL x y) [0])
+ // cond:
+ // result: (TESTL x y)
+ for {
+ if v.AuxInt != 0 {
+ break
+ }
+ v_0 := v.Args[0]
+ if v_0.Op != Op386ANDL {
+ break
+ }
+ x := v_0.Args[0]
+ y := v_0.Args[1]
+ v.reset(Op386TESTL)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (CMPLconst (ANDLconst [c] x) [0])
+ // cond:
+ // result: (TESTLconst [c] x)
+ for {
+ if v.AuxInt != 0 {
+ break
+ }
+ v_0 := v.Args[0]
+ if v_0.Op != Op386ANDLconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v_0.Args[0]
+ v.reset(Op386TESTLconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (CMPLconst x [0])
+ // cond:
+ // result: (TESTL x x)
+ for {
+ if v.AuxInt != 0 {
+ break
+ }
+ x := v.Args[0]
+ v.reset(Op386TESTL)
+ v.AddArg(x)
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValue386_Op386CMPW(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (CMPW x (MOVLconst [c]))
+ // cond:
+ // result: (CMPWconst x [int64(int16(c))])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != Op386MOVLconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(Op386CMPWconst)
+ v.AuxInt = int64(int16(c))
+ v.AddArg(x)
+ return true
+ }
+ // match: (CMPW (MOVLconst [c]) x)
+ // cond:
+ // result: (InvertFlags (CMPWconst x [int64(int16(c))]))
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != Op386MOVLconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ v.reset(Op386InvertFlags)
+ v0 := b.NewValue0(v.Line, Op386CMPWconst, TypeFlags)
+ v0.AuxInt = int64(int16(c))
+ v0.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+ return false
+}
+func rewriteValue386_Op386CMPWconst(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (CMPWconst (MOVLconst [x]) [y])
+ // cond: int16(x)==int16(y)
+ // result: (FlagEQ)
+ for {
+ y := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != Op386MOVLconst {
+ break
+ }
+ x := v_0.AuxInt
+ if !(int16(x) == int16(y)) {
+ break
+ }
+ v.reset(Op386FlagEQ)
+ return true
+ }
+ // match: (CMPWconst (MOVLconst [x]) [y])
+ // cond: int16(x)<int16(y) && uint16(x)<uint16(y)
+ // result: (FlagLT_ULT)
+ for {
+ y := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != Op386MOVLconst {
+ break
+ }
+ x := v_0.AuxInt
+ if !(int16(x) < int16(y) && uint16(x) < uint16(y)) {
+ break
+ }
+ v.reset(Op386FlagLT_ULT)
+ return true
+ }
+ // match: (CMPWconst (MOVLconst [x]) [y])
+ // cond: int16(x)<int16(y) && uint16(x)>uint16(y)
+ // result: (FlagLT_UGT)
+ for {
+ y := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != Op386MOVLconst {
+ break
+ }
+ x := v_0.AuxInt
+ if !(int16(x) < int16(y) && uint16(x) > uint16(y)) {
+ break
+ }
+ v.reset(Op386FlagLT_UGT)
+ return true
+ }
+ // match: (CMPWconst (MOVLconst [x]) [y])
+ // cond: int16(x)>int16(y) && uint16(x)<uint16(y)
+ // result: (FlagGT_ULT)
+ for {
+ y := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != Op386MOVLconst {
+ break
+ }
+ x := v_0.AuxInt
+ if !(int16(x) > int16(y) && uint16(x) < uint16(y)) {
+ break
+ }
+ v.reset(Op386FlagGT_ULT)
+ return true
+ }
+ // match: (CMPWconst (MOVLconst [x]) [y])
+ // cond: int16(x)>int16(y) && uint16(x)>uint16(y)
+ // result: (FlagGT_UGT)
+ for {
+ y := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != Op386MOVLconst {
+ break
+ }
+ x := v_0.AuxInt
+ if !(int16(x) > int16(y) && uint16(x) > uint16(y)) {
+ break
+ }
+ v.reset(Op386FlagGT_UGT)
+ return true
+ }
+ // match: (CMPWconst (ANDLconst _ [m]) [n])
+ // cond: 0 <= int16(m) && int16(m) < int16(n)
+ // result: (FlagLT_ULT)
+ for {
+ n := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != Op386ANDLconst {
+ break
+ }
+ m := v_0.AuxInt
+ if !(0 <= int16(m) && int16(m) < int16(n)) {
+ break
+ }
+ v.reset(Op386FlagLT_ULT)
+ return true
+ }
+ // match: (CMPWconst (ANDL x y) [0])
+ // cond:
+ // result: (TESTW x y)
+ for {
+ if v.AuxInt != 0 {
+ break
+ }
+ v_0 := v.Args[0]
+ if v_0.Op != Op386ANDL {
+ break
+ }
+ x := v_0.Args[0]
+ y := v_0.Args[1]
+ v.reset(Op386TESTW)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (CMPWconst (ANDLconst [c] x) [0])
+ // cond:
+ // result: (TESTWconst [int64(int16(c))] x)
+ for {
+ if v.AuxInt != 0 {
+ break
+ }
+ v_0 := v.Args[0]
+ if v_0.Op != Op386ANDLconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v_0.Args[0]
+ v.reset(Op386TESTWconst)
+ v.AuxInt = int64(int16(c))
+ v.AddArg(x)
+ return true
+ }
+ // match: (CMPWconst x [0])
+ // cond:
+ // result: (TESTW x x)
+ for {
+ if v.AuxInt != 0 {
+ break
+ }
+ x := v.Args[0]
+ v.reset(Op386TESTW)
+ v.AddArg(x)
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValue386_Op386LEAL(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (LEAL [c] {s} (ADDLconst [d] x))
+ // cond: is32Bit(c+d)
+ // result: (LEAL [c+d] {s} x)
+ for {
+ c := v.AuxInt
+ s := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != Op386ADDLconst {
+ break
+ }
+ d := v_0.AuxInt
+ x := v_0.Args[0]
+ if !(is32Bit(c + d)) {
+ break
+ }
+ v.reset(Op386LEAL)
+ v.AuxInt = c + d
+ v.Aux = s
+ v.AddArg(x)
+ return true
+ }
+ // match: (LEAL [c] {s} (ADDL x y))
+ // cond: x.Op != OpSB && y.Op != OpSB
+ // result: (LEAL1 [c] {s} x y)
+ for {
+ c := v.AuxInt
+ s := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != Op386ADDL {
+ break
+ }
+ x := v_0.Args[0]
+ y := v_0.Args[1]
+ if !(x.Op != OpSB && y.Op != OpSB) {
+ break
+ }
+ v.reset(Op386LEAL1)
+ v.AuxInt = c
+ v.Aux = s
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (LEAL [off1] {sym1} (LEAL [off2] {sym2} x))
+ // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+ // result: (LEAL [off1+off2] {mergeSym(sym1,sym2)} x)
+ for {
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != Op386LEAL {
+ break
+ }
+ off2 := v_0.AuxInt
+ sym2 := v_0.Aux
+ x := v_0.Args[0]
+ if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
+ break
+ }
+ v.reset(Op386LEAL)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(x)
+ return true
+ }
+ // match: (LEAL [off1] {sym1} (LEAL1 [off2] {sym2} x y))
+ // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+ // result: (LEAL1 [off1+off2] {mergeSym(sym1,sym2)} x y)
+ for {
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != Op386LEAL1 {
+ break
+ }
+ off2 := v_0.AuxInt
+ sym2 := v_0.Aux
+ x := v_0.Args[0]
+ y := v_0.Args[1]
+ if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
+ break
+ }
+ v.reset(Op386LEAL1)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (LEAL [off1] {sym1} (LEAL2 [off2] {sym2} x y))
+ // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+ // result: (LEAL2 [off1+off2] {mergeSym(sym1,sym2)} x y)
+ for {
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != Op386LEAL2 {
+ break
+ }
+ off2 := v_0.AuxInt
+ sym2 := v_0.Aux
+ x := v_0.Args[0]
+ y := v_0.Args[1]
+ if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
+ break
+ }
+ v.reset(Op386LEAL2)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (LEAL [off1] {sym1} (LEAL4 [off2] {sym2} x y))
+ // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+ // result: (LEAL4 [off1+off2] {mergeSym(sym1,sym2)} x y)
+ for {
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != Op386LEAL4 {
+ break
+ }
+ off2 := v_0.AuxInt
+ sym2 := v_0.Aux
+ x := v_0.Args[0]
+ y := v_0.Args[1]
+ if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
+ break
+ }
+ v.reset(Op386LEAL4)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (LEAL [off1] {sym1} (LEAL8 [off2] {sym2} x y))
+ // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+ // result: (LEAL8 [off1+off2] {mergeSym(sym1,sym2)} x y)
+ for {
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != Op386LEAL8 {
+ break
+ }
+ off2 := v_0.AuxInt
+ sym2 := v_0.Aux
+ x := v_0.Args[0]
+ y := v_0.Args[1]
+ if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
+ break
+ }
+ v.reset(Op386LEAL8)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ return false
+}
+func rewriteValue386_Op386LEAL1(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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_0 := v.Args[0]
+ if v_0.Op != Op386ADDLconst {
+ break
+ }
+ d := v_0.AuxInt
+ x := v_0.Args[0]
+ y := v.Args[1]
+ if !(is32Bit(c+d) && x.Op != OpSB) {
+ break
+ }
+ v.reset(Op386LEAL1)
+ v.AuxInt = c + d
+ v.Aux = s
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (LEAL1 [c] {s} x (ADDLconst [d] y))
+ // cond: is32Bit(c+d) && y.Op != OpSB
+ // result: (LEAL1 [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 != Op386ADDLconst {
+ break
+ }
+ d := v_1.AuxInt
+ y := v_1.Args[0]
+ if !(is32Bit(c+d) && y.Op != OpSB) {
+ break
+ }
+ v.reset(Op386LEAL1)
+ v.AuxInt = c + d
+ v.Aux = s
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (LEAL1 [c] {s} x (SHLLconst [1] y))
+ // cond:
+ // result: (LEAL2 [c] {s} x y)
+ for {
+ c := v.AuxInt
+ s := v.Aux
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != Op386SHLLconst {
+ break
+ }
+ if v_1.AuxInt != 1 {
+ break
+ }
+ y := v_1.Args[0]
+ v.reset(Op386LEAL2)
+ v.AuxInt = c
+ v.Aux = s
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (LEAL1 [c] {s} (SHLLconst [1] x) y)
+ // cond:
+ // result: (LEAL2 [c] {s} y x)
+ for {
+ c := v.AuxInt
+ s := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != Op386SHLLconst {
+ break
+ }
+ if v_0.AuxInt != 1 {
+ break
+ }
+ x := v_0.Args[0]
+ y := v.Args[1]
+ v.reset(Op386LEAL2)
+ v.AuxInt = c
+ v.Aux = s
+ v.AddArg(y)
+ v.AddArg(x)
+ return true
+ }
+ // match: (LEAL1 [c] {s} x (SHLLconst [2] y))
+ // cond:
+ // result: (LEAL4 [c] {s} x y)
+ for {
+ c := v.AuxInt
+ s := v.Aux
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != Op386SHLLconst {
+ break
+ }
+ if v_1.AuxInt != 2 {
+ break
+ }
+ y := v_1.Args[0]
+ v.reset(Op386LEAL4)
+ v.AuxInt = c
+ v.Aux = s
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (LEAL1 [c] {s} (SHLLconst [2] x) y)
+ // cond:
+ // result: (LEAL4 [c] {s} y x)
+ for {
+ c := v.AuxInt
+ s := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != Op386SHLLconst {
+ break
+ }
+ if v_0.AuxInt != 2 {
+ break
+ }
+ x := v_0.Args[0]
+ y := v.Args[1]
+ v.reset(Op386LEAL4)
+ v.AuxInt = c
+ v.Aux = s
+ v.AddArg(y)
+ v.AddArg(x)
+ return true
+ }
+ // match: (LEAL1 [c] {s} x (SHLLconst [3] y))
+ // cond:
+ // result: (LEAL8 [c] {s} x y)
+ for {
+ c := v.AuxInt
+ s := v.Aux
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != Op386SHLLconst {
+ break
+ }
+ if v_1.AuxInt != 3 {
+ break
+ }
+ y := v_1.Args[0]
+ v.reset(Op386LEAL8)
+ v.AuxInt = c
+ v.Aux = s
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (LEAL1 [c] {s} (SHLLconst [3] x) y)
+ // cond:
+ // result: (LEAL8 [c] {s} y x)
+ for {
+ c := v.AuxInt
+ s := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != Op386SHLLconst {
+ break
+ }
+ if v_0.AuxInt != 3 {
+ break
+ }
+ x := v_0.Args[0]
+ y := v.Args[1]
+ v.reset(Op386LEAL8)
+ v.AuxInt = c
+ v.Aux = s
+ v.AddArg(y)
+ v.AddArg(x)
+ return true
+ }
+ // match: (LEAL1 [off1] {sym1} (LEAL [off2] {sym2} x) y)
+ // 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
+ v_0 := v.Args[0]
+ if v_0.Op != Op386LEAL {
+ 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(Op386LEAL1)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (LEAL1 [off1] {sym1} x (LEAL [off2] {sym2} y))
+ // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2) && y.Op != OpSB
+ // result: (LEAL1 [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 != 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) {
+ break
+ }
+ v.reset(Op386LEAL1)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ return false
+}
+func rewriteValue386_Op386LEAL2(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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_0 := v.Args[0]
+ if v_0.Op != Op386ADDLconst {
+ break
+ }
+ d := v_0.AuxInt
+ x := v_0.Args[0]
+ y := v.Args[1]
+ if !(is32Bit(c+d) && x.Op != OpSB) {
+ break
+ }
+ v.reset(Op386LEAL2)
+ v.AuxInt = c + d
+ v.Aux = s
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (LEAL2 [c] {s} x (ADDLconst [d] y))
+ // cond: is32Bit(c+2*d) && y.Op != OpSB
+ // result: (LEAL2 [c+2*d] {s} x y)
+ for {
+ c := v.AuxInt
+ s := v.Aux
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != Op386ADDLconst {
+ break
+ }
+ d := v_1.AuxInt
+ y := v_1.Args[0]
+ if !(is32Bit(c+2*d) && y.Op != OpSB) {
+ break
+ }
+ v.reset(Op386LEAL2)
+ v.AuxInt = c + 2*d
+ v.Aux = s
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (LEAL2 [c] {s} x (SHLLconst [1] y))
+ // cond:
+ // result: (LEAL4 [c] {s} x y)
+ for {
+ c := v.AuxInt
+ s := v.Aux
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != Op386SHLLconst {
+ break
+ }
+ if v_1.AuxInt != 1 {
+ break
+ }
+ y := v_1.Args[0]
+ v.reset(Op386LEAL4)
+ v.AuxInt = c
+ v.Aux = s
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (LEAL2 [c] {s} x (SHLLconst [2] y))
+ // cond:
+ // result: (LEAL8 [c] {s} x y)
+ for {
+ c := v.AuxInt
+ s := v.Aux
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != Op386SHLLconst {
+ break
+ }
+ if v_1.AuxInt != 2 {
+ break
+ }
+ y := v_1.Args[0]
+ v.reset(Op386LEAL8)
+ v.AuxInt = c
+ v.Aux = s
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (LEAL2 [off1] {sym1} (LEAL [off2] {sym2} x) y)
+ // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2) && x.Op != OpSB
+ // result: (LEAL2 [off1+off2] {mergeSym(sym1,sym2)} x y)
+ for {
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != Op386LEAL {
+ 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(Op386LEAL2)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ return false
+}
+func rewriteValue386_Op386LEAL4(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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_0 := v.Args[0]
+ if v_0.Op != Op386ADDLconst {
+ break
+ }
+ d := v_0.AuxInt
+ x := v_0.Args[0]
+ y := v.Args[1]
+ if !(is32Bit(c+d) && x.Op != OpSB) {
+ break
+ }
+ v.reset(Op386LEAL4)
+ v.AuxInt = c + d
+ v.Aux = s
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (LEAL4 [c] {s} x (ADDLconst [d] y))
+ // cond: is32Bit(c+4*d) && y.Op != OpSB
+ // result: (LEAL4 [c+4*d] {s} x y)
+ for {
+ c := v.AuxInt
+ s := v.Aux
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != Op386ADDLconst {
+ break
+ }
+ d := v_1.AuxInt
+ y := v_1.Args[0]
+ if !(is32Bit(c+4*d) && y.Op != OpSB) {
+ break
+ }
+ v.reset(Op386LEAL4)
+ v.AuxInt = c + 4*d
+ v.Aux = s
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (LEAL4 [c] {s} x (SHLLconst [1] y))
+ // cond:
+ // result: (LEAL8 [c] {s} x y)
+ for {
+ c := v.AuxInt
+ s := v.Aux
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != Op386SHLLconst {
+ break
+ }
+ if v_1.AuxInt != 1 {
+ break
+ }
+ y := v_1.Args[0]
+ v.reset(Op386LEAL8)
+ v.AuxInt = c
+ v.Aux = s
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (LEAL4 [off1] {sym1} (LEAL [off2] {sym2} x) y)
+ // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2) && x.Op != OpSB
+ // result: (LEAL4 [off1+off2] {mergeSym(sym1,sym2)} x y)
+ for {
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != Op386LEAL {
+ 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(Op386LEAL4)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ return false
+}
+func rewriteValue386_Op386LEAL8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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_0 := v.Args[0]
+ if v_0.Op != Op386ADDLconst {
+ break
+ }
+ d := v_0.AuxInt
+ x := v_0.Args[0]
+ y := v.Args[1]
+ if !(is32Bit(c+d) && x.Op != OpSB) {
+ break
+ }
+ v.reset(Op386LEAL8)
+ v.AuxInt = c + d
+ v.Aux = s
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (LEAL8 [c] {s} x (ADDLconst [d] y))
+ // cond: is32Bit(c+8*d) && y.Op != OpSB
+ // result: (LEAL8 [c+8*d] {s} x y)
+ for {
+ c := v.AuxInt
+ s := v.Aux
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != Op386ADDLconst {
+ break
+ }
+ d := v_1.AuxInt
+ y := v_1.Args[0]
+ if !(is32Bit(c+8*d) && y.Op != OpSB) {
+ break
+ }
+ v.reset(Op386LEAL8)
+ v.AuxInt = c + 8*d
+ v.Aux = s
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (LEAL8 [off1] {sym1} (LEAL [off2] {sym2} x) y)
+ // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2) && x.Op != OpSB
+ // result: (LEAL8 [off1+off2] {mergeSym(sym1,sym2)} x y)
+ for {
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != Op386LEAL {
+ 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(Op386LEAL8)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ return false
+}
+func rewriteValue386_Op386MOVBLSX(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (MOVBLSX x:(MOVBload [off] {sym} ptr mem))
+ // cond: x.Uses == 1 && clobber(x)
+ // result: @x.Block (MOVBLSXload <v.Type> [off] {sym} ptr mem)
+ for {
+ x := v.Args[0]
+ if x.Op != Op386MOVBload {
+ 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, Op386MOVBLSXload, v.Type)
+ v.reset(OpCopy)
+ v.AddArg(v0)
+ v0.AuxInt = off
+ v0.Aux = sym
+ v0.AddArg(ptr)
+ v0.AddArg(mem)
+ return true
+ }
+ // match: (MOVBLSX (ANDLconst [c] x))
+ // cond: c & 0x80 == 0
+ // result: (ANDLconst [c & 0x7f] x)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != Op386ANDLconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v_0.Args[0]
+ if !(c&0x80 == 0) {
+ break
+ }
+ v.reset(Op386ANDLconst)
+ v.AuxInt = c & 0x7f
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValue386_Op386MOVBLSXload(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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_0 := v.Args[0]
+ if v_0.Op != Op386LEAL {
+ 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)) {
+ break
+ }
+ v.reset(Op386MOVBLSXload)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(base)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValue386_Op386MOVBLZX(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (MOVBLZX x:(MOVBload [off] {sym} ptr mem))
+ // cond: x.Uses == 1 && clobber(x)
+ // result: @x.Block (MOVBload <v.Type> [off] {sym} ptr mem)
+ for {
+ x := v.Args[0]
+ if x.Op != Op386MOVBload {
+ 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, Op386MOVBload, v.Type)
+ v.reset(OpCopy)
+ v.AddArg(v0)
+ v0.AuxInt = off
+ v0.Aux = sym
+ v0.AddArg(ptr)
+ v0.AddArg(mem)
+ return true
+ }
+ // match: (MOVBLZX x:(MOVBloadidx1 [off] {sym} ptr idx mem))
+ // cond: x.Uses == 1 && clobber(x)
+ // result: @x.Block (MOVBloadidx1 <v.Type> [off] {sym} ptr idx mem)
+ for {
+ x := v.Args[0]
+ if x.Op != Op386MOVBloadidx1 {
+ 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, Op386MOVBloadidx1, 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: (MOVBLZX (ANDLconst [c] x))
+ // cond:
+ // result: (ANDLconst [c & 0xff] x)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != Op386ANDLconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v_0.Args[0]
+ v.reset(Op386ANDLconst)
+ v.AuxInt = c & 0xff
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValue386_Op386MOVBload(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (MOVBload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _))
+ // cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
+ // result: x
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != Op386MOVBstore {
+ break
+ }
+ off2 := v_1.AuxInt
+ sym2 := v_1.Aux
+ ptr2 := v_1.Args[0]
+ x := v_1.Args[1]
+ if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVBload [off1] {sym} (ADDLconst [off2] ptr) mem)
+ // cond: is32Bit(off1+off2)
+ // result: (MOVBload [off1+off2] {sym} ptr mem)
+ for {
+ off1 := v.AuxInt
+ sym := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != Op386ADDLconst {
+ break
+ }
+ off2 := v_0.AuxInt
+ ptr := v_0.Args[0]
+ mem := v.Args[1]
+ if !(is32Bit(off1 + off2)) {
+ break
+ }
+ v.reset(Op386MOVBload)
+ v.AuxInt = off1 + off2
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // 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_0 := v.Args[0]
+ if v_0.Op != Op386LEAL {
+ 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)) {
+ break
+ }
+ v.reset(Op386MOVBload)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(base)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVBload [off1] {sym1} (LEAL1 [off2] {sym2} ptr idx) mem)
+ // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+ // result: (MOVBloadidx1 [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem)
+ for {
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != Op386LEAL1 {
+ 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(Op386MOVBloadidx1)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVBload [off] {sym} (ADDL ptr idx) mem)
+ // cond: ptr.Op != OpSB
+ // result: (MOVBloadidx1 [off] {sym} ptr idx mem)
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != Op386ADDL {
+ break
+ }
+ ptr := v_0.Args[0]
+ idx := v_0.Args[1]
+ mem := v.Args[1]
+ if !(ptr.Op != OpSB) {
+ break
+ }
+ v.reset(Op386MOVBloadidx1)
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValue386_Op386MOVBloadidx1(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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_0 := v.Args[0]
+ if v_0.Op != Op386ADDLconst {
+ break
+ }
+ d := v_0.AuxInt
+ ptr := v_0.Args[0]
+ idx := 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
+ }
+ // 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
+ 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(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 {
+ b := v.Block
+ _ = b
+ // match: (MOVBstore [off] {sym} ptr (MOVBLSX x) mem)
+ // cond:
+ // result: (MOVBstore [off] {sym} ptr x mem)
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != Op386MOVBLSX {
+ break
+ }
+ x := v_1.Args[0]
+ mem := v.Args[2]
+ v.reset(Op386MOVBstore)
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(x)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVBstore [off] {sym} ptr (MOVBLZX x) mem)
+ // cond:
+ // result: (MOVBstore [off] {sym} ptr x mem)
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != Op386MOVBLZX {
+ break
+ }
+ x := v_1.Args[0]
+ mem := v.Args[2]
+ v.reset(Op386MOVBstore)
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(x)
+ v.AddArg(mem)
+ return true
+ }
+ // 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_0 := v.Args[0]
+ if v_0.Op != Op386ADDLconst {
+ break
+ }
+ off2 := v_0.AuxInt
+ ptr := v_0.Args[0]
+ val := v.Args[1]
+ mem := v.Args[2]
+ if !(is32Bit(off1 + off2)) {
+ break
+ }
+ v.reset(Op386MOVBstore)
+ v.AuxInt = off1 + off2
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVBstore [off] {sym} ptr (MOVLconst [c]) mem)
+ // cond: validOff(off)
+ // result: (MOVBstoreconst [makeValAndOff(int64(int8(c)),off)] {sym} ptr mem)
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != Op386MOVLconst {
+ break
+ }
+ c := v_1.AuxInt
+ mem := v.Args[2]
+ if !(validOff(off)) {
+ break
+ }
+ v.reset(Op386MOVBstoreconst)
+ v.AuxInt = makeValAndOff(int64(int8(c)), off)
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // 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_0 := v.Args[0]
+ if v_0.Op != Op386LEAL {
+ 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) && (base.Op != OpSB || !config.ctxt.Flag_shared)) {
+ break
+ }
+ v.reset(Op386MOVBstore)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(base)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVBstore [off1] {sym1} (LEAL1 [off2] {sym2} ptr idx) val mem)
+ // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+ // result: (MOVBstoreidx1 [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem)
+ for {
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != Op386LEAL1 {
+ break
+ }
+ off2 := v_0.AuxInt
+ sym2 := v_0.Aux
+ ptr := v_0.Args[0]
+ idx := v_0.Args[1]
+ val := v.Args[1]
+ mem := v.Args[2]
+ if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
+ break
+ }
+ v.reset(Op386MOVBstoreidx1)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVBstore [off] {sym} (ADDL ptr idx) val mem)
+ // cond: ptr.Op != OpSB
+ // result: (MOVBstoreidx1 [off] {sym} ptr idx val mem)
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != Op386ADDL {
+ break
+ }
+ ptr := v_0.Args[0]
+ idx := v_0.Args[1]
+ val := v.Args[1]
+ mem := v.Args[2]
+ if !(ptr.Op != OpSB) {
+ break
+ }
+ v.reset(Op386MOVBstoreidx1)
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVBstore [i] {s} p (SHRLconst [8] w) x:(MOVBstore [i-1] {s} p w mem))
+ // cond: x.Uses == 1 && clobber(x)
+ // result: (MOVWstore [i-1] {s} p w mem)
+ for {
+ i := v.AuxInt
+ s := v.Aux
+ p := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != Op386SHRLconst {
+ break
+ }
+ if v_1.AuxInt != 8 {
+ break
+ }
+ w := v_1.Args[0]
+ x := v.Args[2]
+ if x.Op != Op386MOVBstore {
+ break
+ }
+ if x.AuxInt != i-1 {
+ break
+ }
+ if x.Aux != s {
+ break
+ }
+ if p != x.Args[0] {
+ break
+ }
+ if w != x.Args[1] {
+ break
+ }
+ mem := x.Args[2]
+ if !(x.Uses == 1 && clobber(x)) {
+ break
+ }
+ v.reset(Op386MOVWstore)
+ v.AuxInt = i - 1
+ v.Aux = s
+ v.AddArg(p)
+ v.AddArg(w)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVBstore [i] {s} p (SHRLconst [j] w) x:(MOVBstore [i-1] {s} p w0:(SHRLconst [j-8] w) mem))
+ // cond: x.Uses == 1 && clobber(x)
+ // result: (MOVWstore [i-1] {s} p w0 mem)
+ for {
+ i := v.AuxInt
+ s := v.Aux
+ p := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != Op386SHRLconst {
+ break
+ }
+ j := v_1.AuxInt
+ w := v_1.Args[0]
+ x := v.Args[2]
+ if x.Op != Op386MOVBstore {
+ break
+ }
+ if x.AuxInt != i-1 {
+ break
+ }
+ if x.Aux != s {
+ break
+ }
+ if p != x.Args[0] {
+ break
+ }
+ w0 := x.Args[1]
+ if w0.Op != Op386SHRLconst {
+ break
+ }
+ if w0.AuxInt != j-8 {
+ break
+ }
+ if w != w0.Args[0] {
+ break
+ }
+ mem := x.Args[2]
+ if !(x.Uses == 1 && clobber(x)) {
+ break
+ }
+ v.reset(Op386MOVWstore)
+ v.AuxInt = i - 1
+ v.Aux = s
+ v.AddArg(p)
+ v.AddArg(w0)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValue386_Op386MOVBstoreconst(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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_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(Op386MOVBstoreconst)
+ v.AuxInt = ValAndOff(sc).add(off)
+ v.Aux = s
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVBstoreconst [sc] {sym1} (LEAL [off] {sym2} ptr) mem)
+ // cond: canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd(off) && (ptr.Op != OpSB || !config.ctxt.Flag_shared)
+ // result: (MOVBstoreconst [ValAndOff(sc).add(off)] {mergeSym(sym1, sym2)} ptr mem)
+ for {
+ sc := v.AuxInt
+ sym1 := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != 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(Op386MOVBstoreconst)
+ v.AuxInt = ValAndOff(sc).add(off)
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVBstoreconst [x] {sym1} (LEAL1 [off] {sym2} ptr idx) mem)
+ // cond: canMergeSym(sym1, sym2)
+ // result: (MOVBstoreconstidx1 [ValAndOff(x).add(off)] {mergeSym(sym1,sym2)} ptr idx mem)
+ for {
+ x := v.AuxInt
+ sym1 := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != 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(Op386MOVBstoreconstidx1)
+ v.AuxInt = ValAndOff(x).add(off)
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVBstoreconst [x] {sym} (ADDL ptr idx) mem)
+ // cond:
+ // result: (MOVBstoreconstidx1 [x] {sym} ptr idx mem)
+ for {
+ x := v.AuxInt
+ sym := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != Op386ADDL {
+ break
+ }
+ ptr := v_0.Args[0]
+ idx := v_0.Args[1]
+ mem := v.Args[1]
+ v.reset(Op386MOVBstoreconstidx1)
+ v.AuxInt = x
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVBstoreconst [c] {s} p x:(MOVBstoreconst [a] {s} p mem))
+ // cond: x.Uses == 1 && ValAndOff(a).Off() + 1 == ValAndOff(c).Off() && clobber(x)
+ // result: (MOVWstoreconst [makeValAndOff(ValAndOff(a).Val()&0xff | ValAndOff(c).Val()<<8, ValAndOff(a).Off())] {s} p mem)
+ for {
+ c := v.AuxInt
+ s := v.Aux
+ p := v.Args[0]
+ x := v.Args[1]
+ if x.Op != Op386MOVBstoreconst {
+ break
+ }
+ a := x.AuxInt
+ if x.Aux != s {
+ break
+ }
+ if p != x.Args[0] {
+ break
+ }
+ mem := x.Args[1]
+ if !(x.Uses == 1 && ValAndOff(a).Off()+1 == ValAndOff(c).Off() && clobber(x)) {
+ break
+ }
+ v.reset(Op386MOVWstoreconst)
+ v.AuxInt = makeValAndOff(ValAndOff(a).Val()&0xff|ValAndOff(c).Val()<<8, ValAndOff(a).Off())
+ v.Aux = s
+ v.AddArg(p)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValue386_Op386MOVBstoreconstidx1(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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_0 := v.Args[0]
+ if v_0.Op != Op386ADDLconst {
+ break
+ }
+ c := v_0.AuxInt
+ ptr := v_0.Args[0]
+ idx := v.Args[1]
+ mem := v.Args[2]
+ v.reset(Op386MOVBstoreconstidx1)
+ v.AuxInt = ValAndOff(x).add(c)
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVBstoreconstidx1 [x] {sym} ptr (ADDLconst [c] idx) mem)
+ // cond:
+ // result: (MOVBstoreconstidx1 [ValAndOff(x).add(c)] {sym} ptr idx mem)
+ for {
+ x := v.AuxInt
+ sym := v.Aux
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != Op386ADDLconst {
+ break
+ }
+ c := v_1.AuxInt
+ idx := v_1.Args[0]
+ mem := v.Args[2]
+ v.reset(Op386MOVBstoreconstidx1)
+ v.AuxInt = ValAndOff(x).add(c)
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVBstoreconstidx1 [c] {s} p i x:(MOVBstoreconstidx1 [a] {s} p i mem))
+ // cond: x.Uses == 1 && ValAndOff(a).Off() + 1 == ValAndOff(c).Off() && clobber(x)
+ // result: (MOVWstoreconstidx1 [makeValAndOff(ValAndOff(a).Val()&0xff | ValAndOff(c).Val()<<8, ValAndOff(a).Off())] {s} p i mem)
+ for {
+ c := v.AuxInt
+ s := v.Aux
+ p := v.Args[0]
+ i := v.Args[1]
+ x := v.Args[2]
+ if x.Op != Op386MOVBstoreconstidx1 {
+ break
+ }
+ a := x.AuxInt
+ if x.Aux != s {
+ break
+ }
+ if p != x.Args[0] {
+ break
+ }
+ if i != x.Args[1] {
+ break
+ }
+ mem := x.Args[2]
+ if !(x.Uses == 1 && ValAndOff(a).Off()+1 == ValAndOff(c).Off() && clobber(x)) {
+ break
+ }
+ v.reset(Op386MOVWstoreconstidx1)
+ v.AuxInt = makeValAndOff(ValAndOff(a).Val()&0xff|ValAndOff(c).Val()<<8, ValAndOff(a).Off())
+ v.Aux = s
+ v.AddArg(p)
+ v.AddArg(i)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValue386_Op386MOVBstoreidx1(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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_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(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
+ 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(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
+ p := v.Args[0]
+ idx := v.Args[1]
+ v_2 := v.Args[2]
+ if v_2.Op != Op386SHRLconst {
+ break
+ }
+ if v_2.AuxInt != 8 {
+ break
+ }
+ 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
+ }
+ 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(Op386MOVWstoreidx1)
+ v.AuxInt = i - 1
+ v.Aux = s
+ v.AddArg(p)
+ v.AddArg(idx)
+ v.AddArg(w)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVBstoreidx1 [i] {s} p idx (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 {
+ 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 != Op386MOVBstoreidx1 {
+ break
+ }
+ if x.AuxInt != i-1 {
+ break
+ }
+ if x.Aux != s {
+ break
+ }
+ if p != x.Args[0] {
+ break
+ }
+ if idx != x.Args[1] {
+ break
+ }
+ w0 := x.Args[2]
+ if w0.Op != 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_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
+ 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)) {
+ 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 {
+ break
+ }
+ off2 := v_0.AuxInt
+ ptr := v_0.Args[0]
+ mem := v.Args[1]
+ if !(is32Bit(off1 + off2)) {
+ 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 {
+ 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)) {
+ 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 {
+ 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(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 {
+ 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(Op386MOVLloadidx4)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVLload [off] {sym} (ADDL 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 != Op386ADDL {
+ break
+ }
+ ptr := v_0.Args[0]
+ idx := v_0.Args[1]
+ mem := v.Args[1]
+ if !(ptr.Op != OpSB) {
+ 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 {
+ break
+ }
+ if v_1.AuxInt != 2 {
+ break
+ }
+ idx := v_1.Args[0]
+ mem := v.Args[2]
+ v.reset(Op386MOVLloadidx4)
+ v.AuxInt = c
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVLloadidx1 [c] {sym} (ADDLconst [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 != Op386ADDLconst {
+ 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)
+ v.AddArg(idx)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVLloadidx1 [c] {sym} ptr (ADDLconst [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 != Op386ADDLconst {
+ 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)
+ v.AddArg(idx)
+ 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)
+ for {
+ c := v.AuxInt
+ sym := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != Op386ADDLconst {
+ 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)
+ v.AddArg(idx)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVLloadidx4 [c] {sym} ptr (ADDLconst [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 != Op386ADDLconst {
+ 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)
+ v.AddArg(idx)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValue386_Op386MOVLstore(v *Value, config *Config) 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)
+ for {
+ off1 := v.AuxInt
+ sym := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != Op386ADDLconst {
+ break
+ }
+ off2 := v_0.AuxInt
+ ptr := v_0.Args[0]
+ val := v.Args[1]
+ mem := v.Args[2]
+ if !(is32Bit(off1 + off2)) {
+ break
+ }
+ v.reset(Op386MOVLstore)
+ 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 != Op386MOVLconst {
+ break
+ }
+ c := v_1.AuxInt
+ mem := v.Args[2]
+ if !(validOff(off)) {
+ break
+ }
+ v.reset(Op386MOVLstoreconst)
+ v.AuxInt = makeValAndOff(int64(int32(c)), off)
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // 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: (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 != Op386LEAL {
+ 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) && (base.Op != OpSB || !config.ctxt.Flag_shared)) {
+ break
+ }
+ v.reset(Op386MOVLstore)
+ 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)
+ // 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 != Op386LEAL1 {
+ break
+ }
+ off2 := v_0.AuxInt
+ sym2 := v_0.Aux
+ ptr := v_0.Args[0]
+ idx := v_0.Args[1]
+ val := v.Args[1]
+ mem := v.Args[2]
+ if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
+ break
+ }
+ v.reset(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: (MOVLstore [off1] {sym1} (LEAL4 [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 != Op386LEAL4 {
+ break
+ }
+ off2 := v_0.AuxInt
+ sym2 := v_0.Aux
+ ptr := v_0.Args[0]
+ idx := v_0.Args[1]
+ val := v.Args[1]
+ mem := v.Args[2]
+ if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
+ break
+ }
+ v.reset(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: (MOVLstore [off] {sym} (ADDL 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 != Op386ADDL {
+ break
+ }
+ ptr := v_0.Args[0]
+ idx := v_0.Args[1]
+ val := v.Args[1]
+ mem := v.Args[2]
+ if !(ptr.Op != OpSB) {
+ break
+ }
+ v.reset(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_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)
+ // cond:
+ // result: (MOVLstoreconstidx4 [c] {sym} ptr idx mem)
+ for {
+ c := v.AuxInt
+ sym := v.Aux
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != Op386SHLLconst {
+ break
+ }
+ if v_1.AuxInt != 2 {
+ break
+ }
+ idx := v_1.Args[0]
+ mem := v.Args[2]
+ v.reset(Op386MOVLstoreconstidx4)
+ v.AuxInt = c
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVLstoreconstidx1 [x] {sym} (ADDLconst [c] ptr) idx mem)
+ // cond:
+ // result: (MOVLstoreconstidx1 [ValAndOff(x).add(c)] {sym} ptr idx mem)
+ for {
+ x := v.AuxInt
+ sym := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != Op386ADDLconst {
+ break
+ }
+ c := 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.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVLstoreconstidx1 [x] {sym} ptr (ADDLconst [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 != Op386ADDLconst {
+ break
+ }
+ c := v_1.AuxInt
+ idx := v_1.Args[0]
+ mem := v.Args[2]
+ v.reset(Op386MOVLstoreconstidx1)
+ v.AuxInt = ValAndOff(x).add(c)
+ 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)
+ // cond:
+ // result: (MOVLstoreconstidx4 [ValAndOff(x).add(c)] {sym} ptr idx mem)
+ for {
+ x := v.AuxInt
+ sym := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != Op386ADDLconst {
+ break
+ }
+ c := v_0.AuxInt
+ ptr := v_0.Args[0]
+ idx := v.Args[1]
+ mem := v.Args[2]
+ 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
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != Op386ADDLconst {
+ break
+ }
+ 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(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)
+ // cond:
+ // result: (MOVLstoreidx4 [c] {sym} ptr idx val mem)
+ for {
+ c := v.AuxInt
+ sym := v.Aux
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != Op386SHLLconst {
+ break
+ }
+ if v_1.AuxInt != 2 {
+ break
+ }
+ 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: (MOVLstoreidx1 [c] {sym} (ADDLconst [d] ptr) idx val mem)
+ // cond:
+ // result: (MOVLstoreidx1 [c+d] {sym} ptr idx val mem)
+ for {
+ c := v.AuxInt
+ sym := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != 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(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
+ 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(Op386MOVLstoreidx1)
+ 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_Op386MOVLstoreidx4(v *Value, config *Config) 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)
+ for {
+ c := v.AuxInt
+ sym := v.Aux
+ 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(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 {
+ 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.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)
+ for {
+ off1 := v.AuxInt
+ sym := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != Op386ADDLconst {
+ break
+ }
+ off2 := v_0.AuxInt
+ ptr := v_0.Args[0]
+ mem := v.Args[1]
+ if !(is32Bit(off1 + off2)) {
+ break
+ }
+ v.reset(Op386MOVSDload)
+ v.AuxInt = off1 + off2
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVSDload [off1] {sym1} (LEAL [off2] {sym2} base) mem)
+ // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared)
+ // result: (MOVSDload [off1+off2] {mergeSym(sym1,sym2)} base mem)
+ for {
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != Op386LEAL {
+ 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)) {
+ break
+ }
+ v.reset(Op386MOVSDload)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(base)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVSDload [off1] {sym1} (LEAL1 [off2] {sym2} ptr idx) mem)
+ // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+ // result: (MOVSDloadidx1 [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem)
+ for {
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != Op386LEAL1 {
+ 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(Op386MOVSDloadidx1)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVSDload [off1] {sym1} (LEAL8 [off2] {sym2} ptr idx) mem)
+ // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+ // result: (MOVSDloadidx8 [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem)
+ for {
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != Op386LEAL8 {
+ 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(Op386MOVSDloadidx8)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVSDload [off] {sym} (ADDL ptr idx) mem)
+ // cond: ptr.Op != OpSB
+ // result: (MOVSDloadidx1 [off] {sym} ptr idx mem)
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != Op386ADDL {
+ break
+ }
+ ptr := v_0.Args[0]
+ idx := v_0.Args[1]
+ mem := v.Args[1]
+ if !(ptr.Op != OpSB) {
+ break
+ }
+ v.reset(Op386MOVSDloadidx1)
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValue386_Op386MOVSDloadidx1(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (MOVSDloadidx1 [c] {sym} (ADDLconst [d] ptr) idx mem)
+ // cond:
+ // result: (MOVSDloadidx1 [c+d] {sym} ptr idx mem)
+ for {
+ c := v.AuxInt
+ sym := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != Op386ADDLconst {
+ break
+ }
+ d := 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
+ 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)
+ for {
+ c := v.AuxInt
+ sym := v.Aux
+ 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(Op386MOVSDloadidx1)
+ v.AuxInt = c + d
+ v.Aux = sym
+ 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)
+ // 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 != Op386ADDLconst {
+ break
+ }
+ d := v_0.AuxInt
+ ptr := v_0.Args[0]
+ idx := v.Args[1]
+ mem := v.Args[2]
+ v.reset(Op386MOVSDloadidx8)
+ v.AuxInt = c + d
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVSDloadidx8 [c] {sym} ptr (ADDLconst [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 != Op386ADDLconst {
+ break
+ }
+ d := v_1.AuxInt
+ idx := v_1.Args[0]
+ mem := v.Args[2]
+ v.reset(Op386MOVSDloadidx8)
+ v.AuxInt = c + 8*d
+ 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)
+ for {
+ off1 := v.AuxInt
+ sym := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != Op386ADDLconst {
+ break
+ }
+ off2 := v_0.AuxInt
+ ptr := v_0.Args[0]
+ val := v.Args[1]
+ mem := v.Args[2]
+ if !(is32Bit(off1 + off2)) {
+ break
+ }
+ v.reset(Op386MOVSDstore)
+ v.AuxInt = off1 + off2
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(val)
+ 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)
+ for {
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != Op386LEAL {
+ 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) && (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.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)
+ for {
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != Op386LEAL1 {
+ break
+ }
+ off2 := v_0.AuxInt
+ sym2 := v_0.Aux
+ ptr := v_0.Args[0]
+ idx := v_0.Args[1]
+ val := v.Args[1]
+ mem := v.Args[2]
+ if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
+ break
+ }
+ v.reset(Op386MOVSDstoreidx1)
+ 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} (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)
+ for {
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != Op386LEAL8 {
+ break
+ }
+ off2 := v_0.AuxInt
+ sym2 := v_0.Aux
+ ptr := v_0.Args[0]
+ idx := v_0.Args[1]
+ val := v.Args[1]
+ mem := v.Args[2]
+ if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
+ break
+ }
+ v.reset(Op386MOVSDstoreidx8)
+ 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} (ADDL ptr idx) val mem)
+ // cond: ptr.Op != OpSB
+ // result: (MOVSDstoreidx1 [off] {sym} ptr idx val mem)
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != Op386ADDL {
+ break
+ }
+ ptr := v_0.Args[0]
+ idx := v_0.Args[1]
+ val := v.Args[1]
+ mem := v.Args[2]
+ if !(ptr.Op != OpSB) {
+ break
+ }
+ v.reset(Op386MOVSDstoreidx1)
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(val)
+ 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)
+ // cond:
+ // result: (MOVSDstoreidx1 [c+d] {sym} ptr idx val mem)
+ for {
+ c := v.AuxInt
+ sym := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != 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(Op386MOVSDstoreidx1)
+ 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 (ADDLconst [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 != Op386ADDLconst {
+ break
+ }
+ d := v_1.AuxInt
+ idx := v_1.Args[0]
+ val := v.Args[2]
+ mem := v.Args[3]
+ v.reset(Op386MOVSDstoreidx1)
+ 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_Op386MOVSDstoreidx8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (MOVSDstoreidx8 [c] {sym} (ADDLconst [d] ptr) idx val mem)
+ // cond:
+ // result: (MOVSDstoreidx8 [c+d] {sym} ptr idx val mem)
+ for {
+ c := v.AuxInt
+ sym := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != 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(Op386MOVSDstoreidx8)
+ 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 (ADDLconst [d] idx) val mem)
+ // cond:
+ // result: (MOVSDstoreidx8 [c+8*d] {sym} ptr idx val mem)
+ for {
+ c := v.AuxInt
+ sym := v.Aux
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != Op386ADDLconst {
+ break
+ }
+ d := v_1.AuxInt
+ idx := v_1.Args[0]
+ val := v.Args[2]
+ mem := v.Args[3]
+ v.reset(Op386MOVSDstoreidx8)
+ 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 rewriteValue386_Op386MOVSSconst(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (MOVSSconst [c])
+ // cond: config.ctxt.Flag_shared
+ // result: (MOVSSconst2 (MOVSSconst1 [c]))
+ for {
+ c := v.AuxInt
+ if !(config.ctxt.Flag_shared) {
+ break
+ }
+ v.reset(Op386MOVSSconst2)
+ v0 := b.NewValue0(v.Line, Op386MOVSSconst1, config.fe.TypeUInt32())
+ v0.AuxInt = c
+ v.AddArg(v0)
+ return true
+ }
+ return false
+}
+func rewriteValue386_Op386MOVSSload(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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_0 := v.Args[0]
+ if v_0.Op != Op386ADDLconst {
+ break
+ }
+ off2 := v_0.AuxInt
+ ptr := v_0.Args[0]
+ mem := v.Args[1]
+ if !(is32Bit(off1 + off2)) {
+ break
+ }
+ v.reset(Op386MOVSSload)
+ v.AuxInt = off1 + off2
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVSSload [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)
+ for {
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != Op386LEAL {
+ 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)) {
+ break
+ }
+ v.reset(Op386MOVSSload)
+ 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)
+ // 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 != Op386LEAL1 {
+ 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(Op386MOVSSloadidx1)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(mem)
+ return true
+ }
+ // 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 {
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != Op386LEAL4 {
+ 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(Op386MOVSSloadidx4)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVSSload [off] {sym} (ADDL 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 != Op386ADDL {
+ break
+ }
+ ptr := v_0.Args[0]
+ idx := v_0.Args[1]
+ mem := v.Args[1]
+ if !(ptr.Op != OpSB) {
+ break
+ }
+ v.reset(Op386MOVSSloadidx1)
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValue386_Op386MOVSSloadidx1(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (MOVSSloadidx1 [c] {sym} (ADDLconst [d] ptr) idx mem)
+ // cond:
+ // result: (MOVSSloadidx1 [c+d] {sym} ptr idx mem)
+ for {
+ c := v.AuxInt
+ sym := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != Op386ADDLconst {
+ break
+ }
+ 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
+ }
+ // match: (MOVSSloadidx1 [c] {sym} ptr (ADDLconst [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 != Op386ADDLconst {
+ break
+ }
+ 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(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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_0 := v.Args[0]
+ if v_0.Op != Op386ADDLconst {
+ break
+ }
+ 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
+ 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
+ }
+ return false
+}
+func rewriteValue386_Op386MOVSSstore(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (MOVSSstore [off1] {sym} (ADDLconst [off2] ptr) val mem)
+ // cond: is32Bit(off1+off2)
+ // result: (MOVSSstore [off1+off2] {sym} ptr val mem)
+ for {
+ off1 := v.AuxInt
+ sym := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != Op386ADDLconst {
+ break
+ }
+ off2 := v_0.AuxInt
+ ptr := v_0.Args[0]
+ val := v.Args[1]
+ mem := v.Args[2]
+ if !(is32Bit(off1 + off2)) {
+ break
+ }
+ v.reset(Op386MOVSSstore)
+ v.AuxInt = off1 + off2
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ // 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: (MOVSSstore [off1+off2] {mergeSym(sym1,sym2)} base val mem)
+ for {
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != Op386LEAL {
+ 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) && (base.Op != OpSB || !config.ctxt.Flag_shared)) {
+ break
+ }
+ v.reset(Op386MOVSSstore)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(base)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVSSstore [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)
+ for {
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != Op386LEAL1 {
+ break
+ }
+ off2 := v_0.AuxInt
+ sym2 := v_0.Aux
+ ptr := v_0.Args[0]
+ idx := v_0.Args[1]
+ val := v.Args[1]
+ mem := v.Args[2]
+ if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
+ break
+ }
+ v.reset(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: (MOVSSstore [off1] {sym1} (LEAL4 [off2] {sym2} ptr idx) val mem)
+ // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+ // result: (MOVSSstoreidx4 [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem)
+ for {
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != Op386LEAL4 {
+ break
+ }
+ off2 := v_0.AuxInt
+ sym2 := v_0.Aux
+ ptr := v_0.Args[0]
+ idx := v_0.Args[1]
+ val := v.Args[1]
+ mem := v.Args[2]
+ if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
+ break
+ }
+ v.reset(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: (MOVSSstore [off] {sym} (ADDL ptr idx) val mem)
+ // cond: ptr.Op != OpSB
+ // result: (MOVSSstoreidx1 [off] {sym} ptr idx val mem)
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != Op386ADDL {
+ break
+ }
+ ptr := v_0.Args[0]
+ idx := v_0.Args[1]
+ val := v.Args[1]
+ mem := v.Args[2]
+ if !(ptr.Op != OpSB) {
+ break
+ }
+ v.reset(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_Op386MOVSSstoreidx1(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (MOVSSstoreidx1 [c] {sym} (ADDLconst [d] ptr) idx val mem)
+ // cond:
+ // result: (MOVSSstoreidx1 [c+d] {sym} ptr idx val mem)
+ for {
+ c := v.AuxInt
+ sym := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != 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(Op386MOVSSstoreidx1)
+ v.AuxInt = c + d
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVSSstoreidx1 [c] {sym} ptr (ADDLconst [d] idx) val mem)
+ // cond:
+ // result: (MOVSSstoreidx1 [c+d] {sym} ptr idx val mem)
+ for {
+ c := v.AuxInt
+ sym := v.Aux
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != Op386ADDLconst {
+ break
+ }
+ d := v_1.AuxInt
+ idx := v_1.Args[0]
+ 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_Op386MOVSSstoreidx4(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (MOVSSstoreidx4 [c] {sym} (ADDLconst [d] ptr) idx val mem)
+ // cond:
+ // result: (MOVSSstoreidx4 [c+d] {sym} ptr idx val mem)
+ for {
+ c := v.AuxInt
+ sym := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != 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(Op386MOVSSstoreidx4)
+ 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 (ADDLconst [d] idx) val mem)
+ // cond:
+ // result: (MOVSSstoreidx4 [c+4*d] {sym} ptr idx val mem)
+ for {
+ c := v.AuxInt
+ sym := v.Aux
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != Op386ADDLconst {
+ break
+ }
+ d := v_1.AuxInt
+ idx := v_1.Args[0]
+ 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_Op386MOVWLSX(v *Value, config *Config) 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)
+ 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)) {
+ break
+ }
+ b = x.Block
+ v0 := b.NewValue0(v.Line, Op386MOVWLSXload, v.Type)
+ v.reset(OpCopy)
+ 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)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != Op386ANDLconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v_0.Args[0]
+ if !(c&0x8000 == 0) {
+ break
+ }
+ v.reset(Op386ANDLconst)
+ v.AuxInt = c & 0x7fff
+ v.AddArg(x)
+ 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)
+ // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared)
+ // result: (MOVWLSXload [off1+off2] {mergeSym(sym1,sym2)} base mem)
+ for {
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != Op386LEAL {
+ 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)) {
+ break
+ }
+ v.reset(Op386MOVWLSXload)
+ 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)
+ 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)) {
+ 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)
+ 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)
+ for {
+ x := v.Args[0]
+ if x.Op != Op386MOVWloadidx1 {
+ 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, 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: (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 {
+ x := v.Args[0]
+ if x.Op != Op386MOVWloadidx2 {
+ 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, 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: (MOVWLZX (ANDLconst [c] x))
+ // cond:
+ // result: (ANDLconst [c & 0xffff] x)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != Op386ANDLconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v_0.Args[0]
+ v.reset(Op386ANDLconst)
+ v.AuxInt = c & 0xffff
+ v.AddArg(x)
+ 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
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != Op386MOVWstore {
+ break
+ }
+ off2 := v_1.AuxInt
+ sym2 := v_1.Aux
+ ptr2 := v_1.Args[0]
+ x := v_1.Args[1]
+ if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVWload [off1] {sym} (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 != Op386ADDLconst {
+ break
+ }
+ off2 := v_0.AuxInt
+ ptr := v_0.Args[0]
+ mem := v.Args[1]
+ if !(is32Bit(off1 + off2)) {
+ break
+ }
+ v.reset(Op386MOVWload)
+ v.AuxInt = off1 + off2
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // 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 {
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != Op386LEAL {
+ 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)) {
+ break
+ }
+ v.reset(Op386MOVWload)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(base)
+ v.AddArg(mem)
+ return true
+ }
+ // 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 {
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != Op386LEAL1 {
+ 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(Op386MOVWloadidx1)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(mem)
+ return true
+ }
+ // 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 {
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != Op386LEAL2 {
+ 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(Op386MOVWloadidx2)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVWload [off] {sym} (ADDL ptr idx) mem)
+ // cond: ptr.Op != OpSB
+ // result: (MOVWloadidx1 [off] {sym} ptr idx mem)
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != Op386ADDL {
+ break
+ }
+ ptr := v_0.Args[0]
+ idx := v_0.Args[1]
+ mem := v.Args[1]
+ 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
+ }
+ 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)
+ // cond:
+ // result: (MOVWloadidx1 [c+d] {sym} ptr idx mem)
+ for {
+ c := v.AuxInt
+ sym := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != Op386ADDLconst {
+ break
+ }
+ d := v_0.AuxInt
+ ptr := v_0.Args[0]
+ idx := 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
+ }
+ // match: (MOVWloadidx1 [c] {sym} ptr (ADDLconst [d] idx) mem)
+ // cond:
+ // result: (MOVWloadidx1 [c+d] {sym} ptr idx mem)
+ for {
+ c := v.AuxInt
+ sym := v.Aux
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != Op386ADDLconst {
+ break
+ }
+ 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
+ }
+ return false
+}
+func rewriteValue386_Op386MOVWloadidx2(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (MOVWloadidx2 [c] {sym} (ADDLconst [d] ptr) idx mem)
+ // cond:
+ // result: (MOVWloadidx2 [c+d] {sym} ptr idx mem)
+ for {
+ c := v.AuxInt
+ sym := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != Op386ADDLconst {
+ break
+ }
+ d := v_0.AuxInt
+ ptr := v_0.Args[0]
+ idx := v.Args[1]
+ mem := v.Args[2]
+ v.reset(Op386MOVWloadidx2)
+ v.AuxInt = c + d
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVWloadidx2 [c] {sym} ptr (ADDLconst [d] idx) mem)
+ // cond:
+ // result: (MOVWloadidx2 [c+2*d] {sym} ptr idx mem)
+ for {
+ c := v.AuxInt
+ sym := v.Aux
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != Op386ADDLconst {
+ break
+ }
+ d := v_1.AuxInt
+ idx := v_1.Args[0]
+ mem := v.Args[2]
+ v.reset(Op386MOVWloadidx2)
+ v.AuxInt = c + 2*d
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValue386_Op386MOVWstore(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (MOVWstore [off] {sym} ptr (MOVWLSX 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 != Op386MOVWLSX {
+ 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 {
+ 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 [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_0 := v.Args[0]
+ if v_0.Op != Op386ADDLconst {
+ break
+ }
+ off2 := v_0.AuxInt
+ ptr := v_0.Args[0]
+ val := v.Args[1]
+ mem := v.Args[2]
+ if !(is32Bit(off1 + off2)) {
+ break
+ }
+ v.reset(Op386MOVWstore)
+ v.AuxInt = off1 + off2
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVWstore [off] {sym} ptr (MOVLconst [c]) mem)
+ // cond: validOff(off)
+ // result: (MOVWstoreconst [makeValAndOff(int64(int16(c)),off)] {sym} ptr mem)
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != Op386MOVLconst {
+ break
+ }
+ 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(mem)
+ return true
+ }
+ // 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 {
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != Op386LEAL {
+ 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) && (base.Op != OpSB || !config.ctxt.Flag_shared)) {
+ break
+ }
+ 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_0 := v.Args[0]
+ if v_0.Op != Op386LEAL1 {
+ break
+ }
+ off2 := v_0.AuxInt
+ sym2 := v_0.Aux
+ ptr := v_0.Args[0]
+ idx := v_0.Args[1]
+ val := v.Args[1]
+ mem := v.Args[2]
+ if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
+ break
+ }
+ v.reset(Op386MOVWstoreidx1)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVWstore [off1] {sym1} (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 {
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != Op386LEAL2 {
+ break
+ }
+ off2 := v_0.AuxInt
+ sym2 := v_0.Aux
+ ptr := v_0.Args[0]
+ idx := v_0.Args[1]
+ val := v.Args[1]
+ mem := v.Args[2]
+ if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
+ break
+ }
+ v.reset(Op386MOVWstoreidx2)
+ 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} (ADDL ptr idx) val mem)
+ // cond: ptr.Op != OpSB
+ // result: (MOVWstoreidx1 [off] {sym} ptr idx val mem)
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != Op386ADDL {
+ break
+ }
+ ptr := v_0.Args[0]
+ idx := v_0.Args[1]
+ val := v.Args[1]
+ mem := v.Args[2]
+ if !(ptr.Op != OpSB) {
+ break
+ }
+ v.reset(Op386MOVWstoreidx1)
+ 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 (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)
+ 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 {
+ 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)
+ 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)
+ for {
+ i := v.AuxInt
+ s := v.Aux
+ p := 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] {
+ 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(w0)
+ v.AddArg(mem)
+ 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)
+ 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(Op386MOVWstoreconst)
+ v.AuxInt = ValAndOff(sc).add(off)
+ v.Aux = s
+ 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)
+ 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(Op386MOVWstoreconst)
+ v.AuxInt = ValAndOff(sc).add(off)
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(ptr)
+ 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)
+ 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(Op386MOVWstoreconstidx1)
+ 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} (LEAL2 [off] {sym2} ptr idx) mem)
+ // cond: canMergeSym(sym1, sym2)
+ // result: (MOVWstoreconstidx2 [ValAndOff(x).add(off)] {mergeSym(sym1,sym2)} ptr idx mem)
+ for {
+ x := v.AuxInt
+ sym1 := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != Op386LEAL2 {
+ 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(Op386MOVWstoreconstidx2)
+ v.AuxInt = ValAndOff(x).add(off)
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVWstoreconst [x] {sym} (ADDL ptr idx) mem)
+ // cond:
+ // result: (MOVWstoreconstidx1 [x] {sym} ptr idx mem)
+ for {
+ x := v.AuxInt
+ sym := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != Op386ADDL {
+ break
+ }
+ 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: (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 != Op386MOVWstoreconst {
+ break
+ }
+ a := x.AuxInt
+ if x.Aux != s {
+ break
+ }
+ if p != x.Args[0] {
+ break
+ }
+ mem := x.Args[1]
+ if !(x.Uses == 1 && ValAndOff(a).Off()+2 == ValAndOff(c).Off() && clobber(x)) {
+ break
+ }
+ v.reset(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
+ }
+ return false
+}
+func rewriteValue386_Op386MOVWstoreconstidx1(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (MOVWstoreconstidx1 [c] {sym} ptr (SHLLconst [1] idx) mem)
+ // cond:
+ // result: (MOVWstoreconstidx2 [c] {sym} ptr idx mem)
+ for {
+ c := v.AuxInt
+ sym := v.Aux
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != Op386SHLLconst {
+ break
+ }
+ if v_1.AuxInt != 1 {
+ break
+ }
+ 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: (MOVWstoreconstidx1 [x] {sym} (ADDLconst [c] ptr) idx mem)
+ // cond:
+ // result: (MOVWstoreconstidx1 [ValAndOff(x).add(c)] {sym} ptr idx mem)
+ for {
+ x := v.AuxInt
+ sym := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != Op386ADDLconst {
+ break
+ }
+ 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: (MOVWstoreconstidx1 [x] {sym} ptr (ADDLconst [c] idx) mem)
+ // cond:
+ // result: (MOVWstoreconstidx1 [ValAndOff(x).add(c)] {sym} ptr idx mem)
+ for {
+ x := v.AuxInt
+ sym := v.Aux
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != Op386ADDLconst {
+ break
+ }
+ 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: (MOVWstoreconstidx1 [c] {s} p i x:(MOVWstoreconstidx1 [a] {s} p i mem))
+ // cond: x.Uses == 1 && ValAndOff(a).Off() + 2 == ValAndOff(c).Off() && clobber(x)
+ // result: (MOVLstoreconstidx1 [makeValAndOff(ValAndOff(a).Val()&0xffff | ValAndOff(c).Val()<<16, ValAndOff(a).Off())] {s} p i mem)
+ for {
+ c := v.AuxInt
+ s := v.Aux
+ p := v.Args[0]
+ i := v.Args[1]
+ x := v.Args[2]
+ if x.Op != Op386MOVWstoreconstidx1 {
+ 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)
+ v.AddArg(i)
+ 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)
+ // cond:
+ // result: (MOVWstoreconstidx2 [ValAndOff(x).add(c)] {sym} ptr idx mem)
+ for {
+ x := v.AuxInt
+ sym := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != Op386ADDLconst {
+ break
+ }
+ 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: (MOVWstoreconstidx2 [x] {sym} ptr (ADDLconst [c] idx) mem)
+ // cond:
+ // result: (MOVWstoreconstidx2 [ValAndOff(x).add(2*c)] {sym} ptr idx mem)
+ for {
+ x := v.AuxInt
+ sym := v.Aux
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != Op386ADDLconst {
+ break
+ }
+ 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: (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 {
+ b := v.Block
+ _ = b
+ // match: (MOVWstoreidx1 [c] {sym} ptr (SHLLconst [1] idx) val mem)
+ // cond:
+ // result: (MOVWstoreidx2 [c] {sym} ptr idx val mem)
+ for {
+ c := v.AuxInt
+ sym := v.Aux
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != Op386SHLLconst {
+ break
+ }
+ 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: (MOVWstoreidx1 [c] {sym} (ADDLconst [d] ptr) idx val mem)
+ // cond:
+ // result: (MOVWstoreidx1 [c+d] {sym} ptr idx val mem)
+ for {
+ c := v.AuxInt
+ sym := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != 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(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} ptr (ADDLconst [d] idx) val mem)
+ // cond:
+ // result: (MOVWstoreidx1 [c+d] {sym} ptr idx val mem)
+ for {
+ c := v.AuxInt
+ sym := v.Aux
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != Op386ADDLconst {
+ 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
+ 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)
+ 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 {
+ break
+ }
+ if x.AuxInt != i-2 {
+ break
+ }
+ if x.Aux != s {
+ break
+ }
+ if p != x.Args[0] {
+ break
+ }
+ if idx != x.Args[1] {
+ break
+ }
+ if w != x.Args[2] {
+ break
+ }
+ mem := x.Args[3]
+ if !(x.Uses == 1 && clobber(x)) {
+ break
+ }
+ v.reset(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} 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
+ 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] {
+ 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(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)
+ for {
+ c := v.AuxInt
+ sym := v.Aux
+ 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
+ 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
+ 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
+ }
+ 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.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))
+ // 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
+ 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
+ }
+ 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.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 {
+ b := v.Block
+ _ = b
+ // match: (MULL x (MOVLconst [c]))
+ // cond:
+ // result: (MULLconst [c] x)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != 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_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(v *Value, config *Config) 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.Line, 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.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 {
+ 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 {
+ 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)
+ 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.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 {
+ 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)
+ 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.Line, 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.Line, 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.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) {
+ 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) {
+ 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)
+ 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.Line, Op386SHLLconst, v.Type)
+ v0.AuxInt = log2(c - 4)
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v.AddArg(x)
+ return true
+ }
+ // 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.Line, 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.Line, 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.Line, 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.Line, 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(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (NEGL (MOVLconst [c]))
+ // cond:
+ // result: (MOVLconst [int64(int32(-c))])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != Op386MOVLconst {
+ break
+ }
+ c := v_0.AuxInt
+ v.reset(Op386MOVLconst)
+ v.AuxInt = int64(int32(-c))
+ return true
+ }
+ return false
+}
+func rewriteValue386_Op386NOTL(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (NOTL (MOVLconst [c]))
+ // cond:
+ // result: (MOVLconst [^c])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != Op386MOVLconst {
+ break
+ }
+ c := v_0.AuxInt
+ v.reset(Op386MOVLconst)
+ v.AuxInt = ^c
+ return true
+ }
+ return false
+}
+func rewriteValue386_Op386ORL(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ORL x (MOVLconst [c]))
+ // cond:
+ // result: (ORLconst [c] x)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != 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_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 x x)
+ // cond:
+ // result: x
+ for {
+ x := v.Args[0]
+ if x != v.Args[1] {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ // match: (ORL x0:(MOVBload [i] {s} p mem) s0:(SHLLconst [8] x1:(MOVBload [i+1] {s} p mem)))
+ // cond: x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && mergePoint(b,x0,x1) != nil && clobber(x0) && clobber(x1) && clobber(s0)
+ // result: @mergePoint(b,x0,x1) (MOVWload [i] {s} p mem)
+ for {
+ x0 := v.Args[0]
+ if x0.Op != Op386MOVBload {
+ break
+ }
+ i := x0.AuxInt
+ s := x0.Aux
+ 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
+ }
+ if x1.AuxInt != i+1 {
+ break
+ }
+ if x1.Aux != s {
+ break
+ }
+ if p != x1.Args[0] {
+ break
+ }
+ if mem != x1.Args[1] {
+ break
+ }
+ if !(x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0)) {
+ break
+ }
+ b = mergePoint(b, x0, x1)
+ v0 := b.NewValue0(v.Line, Op386MOVWload, 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 != Op386ORL {
+ break
+ }
+ x0 := o0.Args[0]
+ if x0.Op != Op386MOVWload {
+ break
+ }
+ i := x0.AuxInt
+ s := x0.Aux
+ 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
+ }
+ if x1.AuxInt != i+2 {
+ break
+ }
+ if x1.Aux != s {
+ break
+ }
+ 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
+ }
+ if x2.AuxInt != i+3 {
+ break
+ }
+ if x2.Aux != s {
+ break
+ }
+ if p != x2.Args[0] {
+ break
+ }
+ if mem != x2.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)) {
+ break
+ }
+ b = mergePoint(b, x0, x1, x2)
+ v0 := b.NewValue0(v.Line, Op386MOVLload, config.fe.TypeUInt32())
+ v.reset(OpCopy)
+ v.AddArg(v0)
+ v0.AuxInt = i
+ v0.Aux = s
+ v0.AddArg(p)
+ v0.AddArg(mem)
+ return true
+ }
+ // match: (ORL x0:(MOVBloadidx1 [i] {s} p idx mem) s0:(SHLLconst [8] x1:(MOVBloadidx1 [i+1] {s} p idx mem)))
+ // cond: x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && mergePoint(b,x0,x1) != nil && clobber(x0) && clobber(x1) && clobber(s0)
+ // result: @mergePoint(b,x0,x1) (MOVWloadidx1 <v.Type> [i] {s} p idx mem)
+ for {
+ x0 := v.Args[0]
+ if x0.Op != Op386MOVBloadidx1 {
+ 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 != Op386SHLLconst {
+ break
+ }
+ if s0.AuxInt != 8 {
+ break
+ }
+ x1 := s0.Args[0]
+ if x1.Op != Op386MOVBloadidx1 {
+ break
+ }
+ if x1.AuxInt != i+1 {
+ break
+ }
+ if x1.Aux != s {
+ break
+ }
+ if p != x1.Args[0] {
+ break
+ }
+ if idx != x1.Args[1] {
+ break
+ }
+ if mem != x1.Args[2] {
+ break
+ }
+ if !(x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0)) {
+ break
+ }
+ b = mergePoint(b, x0, x1)
+ v0 := b.NewValue0(v.Line, Op386MOVWloadidx1, v.Type)
+ v.reset(OpCopy)
+ v.AddArg(v0)
+ v0.AuxInt = i
+ v0.Aux = s
+ v0.AddArg(p)
+ v0.AddArg(idx)
+ v0.AddArg(mem)
+ return true
+ }
+ // match: (ORL o0:(ORL 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)
+ for {
+ o0 := v.Args[0]
+ if o0.Op != Op386ORL {
+ break
+ }
+ x0 := o0.Args[0]
+ if x0.Op != Op386MOVWloadidx1 {
+ 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 != Op386SHLLconst {
+ break
+ }
+ if s0.AuxInt != 16 {
+ break
+ }
+ x1 := s0.Args[0]
+ if x1.Op != Op386MOVBloadidx1 {
+ break
+ }
+ if x1.AuxInt != i+2 {
+ break
+ }
+ if x1.Aux != s {
+ break
+ }
+ if p != x1.Args[0] {
+ break
+ }
+ if idx != x1.Args[1] {
+ break
+ }
+ if mem != x1.Args[2] {
+ break
+ }
+ s1 := v.Args[1]
+ if s1.Op != Op386SHLLconst {
+ break
+ }
+ if s1.AuxInt != 24 {
+ break
+ }
+ x2 := s1.Args[0]
+ if x2.Op != Op386MOVBloadidx1 {
+ break
+ }
+ if x2.AuxInt != i+3 {
+ break
+ }
+ if x2.Aux != s {
+ break
+ }
+ if p != x2.Args[0] {
+ break
+ }
+ if idx != x2.Args[1] {
+ break
+ }
+ if mem != x2.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)) {
+ break
+ }
+ b = mergePoint(b, x0, x1, x2)
+ v0 := b.NewValue0(v.Line, Op386MOVLloadidx1, v.Type)
+ v.reset(OpCopy)
+ v.AddArg(v0)
+ v0.AuxInt = i
+ v0.Aux = s
+ v0.AddArg(p)
+ v0.AddArg(idx)
+ v0.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValue386_Op386ORLconst(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ORLconst [c] x)
+ // cond: int32(c)==0
+ // result: x
+ for {
+ c := v.AuxInt
+ x := v.Args[0]
+ if !(int32(c) == 0) {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ // match: (ORLconst [c] _)
+ // cond: int32(c)==-1
+ // result: (MOVLconst [-1])
+ for {
+ c := v.AuxInt
+ if !(int32(c) == -1) {
+ break
+ }
+ v.reset(Op386MOVLconst)
+ v.AuxInt = -1
+ return true
+ }
+ // match: (ORLconst [c] (MOVLconst [d]))
+ // cond:
+ // result: (MOVLconst [c|d])
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != Op386MOVLconst {
+ break
+ }
+ d := v_0.AuxInt
+ v.reset(Op386MOVLconst)
+ v.AuxInt = c | d
+ return true
+ }
+ return false
+}
+func rewriteValue386_Op386ROLBconst(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 != Op386ROLBconst {
+ break
+ }
+ d := v_0.AuxInt
+ x := v_0.Args[0]
+ v.reset(Op386ROLBconst)
+ v.AuxInt = (c + d) & 7
+ v.AddArg(x)
+ return true
+ }
+ // match: (ROLBconst [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
+ }
+ return false
+}
+func rewriteValue386_Op386ROLLconst(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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 != Op386ROLLconst {
+ break
+ }
+ d := v_0.AuxInt
+ x := v_0.Args[0]
+ v.reset(Op386ROLLconst)
+ v.AuxInt = (c + d) & 31
+ v.AddArg(x)
+ return true
+ }
+ // match: (ROLLconst [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
+ }
+ return false
+}
+func rewriteValue386_Op386ROLWconst(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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 != Op386ROLWconst {
+ break
+ }
+ d := v_0.AuxInt
+ x := v_0.Args[0]
+ v.reset(Op386ROLWconst)
+ v.AuxInt = (c + d) & 15
+ v.AddArg(x)
+ return true
+ }
+ // match: (ROLWconst [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
+ }
+ return false
+}
+func rewriteValue386_Op386SARB(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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 != Op386MOVLconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(Op386SARBconst)
+ 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 != Op386MOVLconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(Op386SARBconst)
+ v.AuxInt = c & 31
+ 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)])
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != Op386MOVLconst {
+ break
+ }
+ d := v_0.AuxInt
+ v.reset(Op386MOVLconst)
+ v.AuxInt = d >> uint64(c)
+ return true
+ }
+ 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
+ }
+ // 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
+ }
+ // 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 != Op386ANDLconst {
+ break
+ }
+ if v_1.AuxInt != 31 {
+ break
+ }
+ y := v_1.Args[0]
+ v.reset(Op386SARL)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ return false
+}
+func rewriteValue386_Op386SARLconst(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SARLconst [c] (MOVLconst [d]))
+ // cond:
+ // result: (MOVLconst [d>>uint64(c)])
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != Op386MOVLconst {
+ break
+ }
+ d := v_0.AuxInt
+ v.reset(Op386MOVLconst)
+ v.AuxInt = d >> uint64(c)
+ return true
+ }
+ return false
+}
+func rewriteValue386_Op386SARW(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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 != Op386MOVLconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(Op386SARWconst)
+ 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 != Op386MOVLconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(Op386SARWconst)
+ v.AuxInt = c & 31
+ 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)])
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != Op386MOVLconst {
+ break
+ }
+ d := v_0.AuxInt
+ v.reset(Op386MOVLconst)
+ v.AuxInt = d >> uint64(c)
+ return true
+ }
+ return false
+}
+func rewriteValue386_Op386SBBL(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SBBL x (MOVLconst [c]) f)
+ // cond:
+ // result: (SBBLconst [c] x f)
+ for {
+ 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(Op386SBBLconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(f)
+ return true
+ }
+ return false
+}
+func rewriteValue386_Op386SBBLcarrymask(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 != Op386FlagEQ {
+ break
+ }
+ v.reset(Op386MOVLconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (SBBLcarrymask (FlagLT_ULT))
+ // cond:
+ // result: (MOVLconst [-1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != Op386FlagLT_ULT {
+ break
+ }
+ v.reset(Op386MOVLconst)
+ v.AuxInt = -1
+ return true
+ }
+ // match: (SBBLcarrymask (FlagLT_UGT))
+ // cond:
+ // result: (MOVLconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != Op386FlagLT_UGT {
+ break
+ }
+ v.reset(Op386MOVLconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (SBBLcarrymask (FlagGT_ULT))
+ // cond:
+ // result: (MOVLconst [-1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != Op386FlagGT_ULT {
+ break
+ }
+ v.reset(Op386MOVLconst)
+ v.AuxInt = -1
+ return true
+ }
+ // match: (SBBLcarrymask (FlagGT_UGT))
+ // cond:
+ // result: (MOVLconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != Op386FlagGT_UGT {
+ break
+ }
+ v.reset(Op386MOVLconst)
+ v.AuxInt = 0
+ return true
+ }
+ return false
+}
+func rewriteValue386_Op386SETA(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 != Op386InvertFlags {
+ break
+ }
+ x := v_0.Args[0]
+ v.reset(Op386SETB)
+ v.AddArg(x)
+ return true
+ }
+ // match: (SETA (FlagEQ))
+ // cond:
+ // result: (MOVLconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != Op386FlagEQ {
+ break
+ }
+ v.reset(Op386MOVLconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (SETA (FlagLT_ULT))
+ // cond:
+ // result: (MOVLconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != Op386FlagLT_ULT {
+ break
+ }
+ v.reset(Op386MOVLconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (SETA (FlagLT_UGT))
+ // cond:
+ // result: (MOVLconst [1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != Op386FlagLT_UGT {
+ break
+ }
+ v.reset(Op386MOVLconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (SETA (FlagGT_ULT))
+ // cond:
+ // result: (MOVLconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != Op386FlagGT_ULT {
+ break
+ }
+ v.reset(Op386MOVLconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (SETA (FlagGT_UGT))
+ // cond:
+ // result: (MOVLconst [1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != Op386FlagGT_UGT {
+ break
+ }
+ v.reset(Op386MOVLconst)
+ v.AuxInt = 1
+ return true
+ }
+ return false
+}
+func rewriteValue386_Op386SETAE(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SETAE (InvertFlags x))
+ // cond:
+ // result: (SETBE x)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != Op386InvertFlags {
+ break
+ }
+ x := v_0.Args[0]
+ v.reset(Op386SETBE)
+ v.AddArg(x)
+ return true
+ }
+ // match: (SETAE (FlagEQ))
+ // cond:
+ // result: (MOVLconst [1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != Op386FlagEQ {
+ break
+ }
+ v.reset(Op386MOVLconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (SETAE (FlagLT_ULT))
+ // cond:
+ // result: (MOVLconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != Op386FlagLT_ULT {
+ break
+ }
+ v.reset(Op386MOVLconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (SETAE (FlagLT_UGT))
+ // cond:
+ // result: (MOVLconst [1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != Op386FlagLT_UGT {
+ break
+ }
+ v.reset(Op386MOVLconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (SETAE (FlagGT_ULT))
+ // cond:
+ // result: (MOVLconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != Op386FlagGT_ULT {
+ break
+ }
+ v.reset(Op386MOVLconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (SETAE (FlagGT_UGT))
+ // cond:
+ // result: (MOVLconst [1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != Op386FlagGT_UGT {
+ break
+ }
+ v.reset(Op386MOVLconst)
+ v.AuxInt = 1
+ return true
+ }
+ return false
+}
+func rewriteValue386_Op386SETB(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 != Op386InvertFlags {
+ break
+ }
+ x := v_0.Args[0]
+ v.reset(Op386SETA)
+ v.AddArg(x)
+ return true
+ }
+ // match: (SETB (FlagEQ))
+ // cond:
+ // result: (MOVLconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != Op386FlagEQ {
+ break
+ }
+ v.reset(Op386MOVLconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (SETB (FlagLT_ULT))
+ // cond:
+ // result: (MOVLconst [1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != Op386FlagLT_ULT {
+ break
+ }
+ v.reset(Op386MOVLconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (SETB (FlagLT_UGT))
+ // cond:
+ // result: (MOVLconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != Op386FlagLT_UGT {
+ break
+ }
+ v.reset(Op386MOVLconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (SETB (FlagGT_ULT))
+ // cond:
+ // result: (MOVLconst [1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != Op386FlagGT_ULT {
+ break
+ }
+ v.reset(Op386MOVLconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (SETB (FlagGT_UGT))
+ // cond:
+ // result: (MOVLconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != Op386FlagGT_UGT {
+ break
+ }
+ v.reset(Op386MOVLconst)
+ v.AuxInt = 0
+ return true
+ }
+ return false
+}
+func rewriteValue386_Op386SETBE(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 != Op386InvertFlags {
+ break
+ }
+ x := v_0.Args[0]
+ v.reset(Op386SETAE)
+ v.AddArg(x)
+ return true
+ }
+ // match: (SETBE (FlagEQ))
+ // cond:
+ // result: (MOVLconst [1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != Op386FlagEQ {
+ break
+ }
+ v.reset(Op386MOVLconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (SETBE (FlagLT_ULT))
+ // cond:
+ // result: (MOVLconst [1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != Op386FlagLT_ULT {
+ break
+ }
+ v.reset(Op386MOVLconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (SETBE (FlagLT_UGT))
+ // cond:
+ // result: (MOVLconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != Op386FlagLT_UGT {
+ break
+ }
+ v.reset(Op386MOVLconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (SETBE (FlagGT_ULT))
+ // cond:
+ // result: (MOVLconst [1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != Op386FlagGT_ULT {
+ break
+ }
+ v.reset(Op386MOVLconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (SETBE (FlagGT_UGT))
+ // cond:
+ // result: (MOVLconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != Op386FlagGT_UGT {
+ break
+ }
+ v.reset(Op386MOVLconst)
+ v.AuxInt = 0
+ return true
+ }
+ return false
+}
+func rewriteValue386_Op386SETEQ(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 != Op386InvertFlags {
+ break
+ }
+ x := v_0.Args[0]
+ v.reset(Op386SETEQ)
+ v.AddArg(x)
+ return true
+ }
+ // match: (SETEQ (FlagEQ))
+ // cond:
+ // result: (MOVLconst [1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != Op386FlagEQ {
+ break
+ }
+ v.reset(Op386MOVLconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (SETEQ (FlagLT_ULT))
+ // cond:
+ // result: (MOVLconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != Op386FlagLT_ULT {
+ break
+ }
+ v.reset(Op386MOVLconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (SETEQ (FlagLT_UGT))
+ // cond:
+ // result: (MOVLconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != Op386FlagLT_UGT {
+ break
+ }
+ v.reset(Op386MOVLconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (SETEQ (FlagGT_ULT))
+ // cond:
+ // result: (MOVLconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != Op386FlagGT_ULT {
+ break
+ }
+ v.reset(Op386MOVLconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (SETEQ (FlagGT_UGT))
+ // cond:
+ // result: (MOVLconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != Op386FlagGT_UGT {
+ break
+ }
+ v.reset(Op386MOVLconst)
+ v.AuxInt = 0
+ return true
+ }
+ return false
+}
+func rewriteValue386_Op386SETG(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 != Op386InvertFlags {
+ break
+ }
+ x := v_0.Args[0]
+ v.reset(Op386SETL)
+ v.AddArg(x)
+ return true
+ }
+ // match: (SETG (FlagEQ))
+ // cond:
+ // result: (MOVLconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != Op386FlagEQ {
+ break
+ }
+ v.reset(Op386MOVLconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (SETG (FlagLT_ULT))
+ // cond:
+ // result: (MOVLconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != Op386FlagLT_ULT {
+ break
+ }
+ v.reset(Op386MOVLconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (SETG (FlagLT_UGT))
+ // cond:
+ // result: (MOVLconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != Op386FlagLT_UGT {
+ break
+ }
+ v.reset(Op386MOVLconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (SETG (FlagGT_ULT))
+ // cond:
+ // result: (MOVLconst [1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != Op386FlagGT_ULT {
+ break
+ }
+ v.reset(Op386MOVLconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (SETG (FlagGT_UGT))
+ // cond:
+ // result: (MOVLconst [1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != Op386FlagGT_UGT {
+ break
+ }
+ v.reset(Op386MOVLconst)
+ v.AuxInt = 1
+ return true
+ }
+ return false
+}
+func rewriteValue386_Op386SETGE(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 != Op386InvertFlags {
+ break
+ }
+ x := v_0.Args[0]
+ v.reset(Op386SETLE)
+ v.AddArg(x)
+ return true
+ }
+ // match: (SETGE (FlagEQ))
+ // cond:
+ // result: (MOVLconst [1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != Op386FlagEQ {
+ break
+ }
+ v.reset(Op386MOVLconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (SETGE (FlagLT_ULT))
+ // cond:
+ // result: (MOVLconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != Op386FlagLT_ULT {
+ break
+ }
+ v.reset(Op386MOVLconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (SETGE (FlagLT_UGT))
+ // cond:
+ // result: (MOVLconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != Op386FlagLT_UGT {
+ break
+ }
+ v.reset(Op386MOVLconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (SETGE (FlagGT_ULT))
+ // cond:
+ // result: (MOVLconst [1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != Op386FlagGT_ULT {
+ break
+ }
+ v.reset(Op386MOVLconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (SETGE (FlagGT_UGT))
+ // cond:
+ // result: (MOVLconst [1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != Op386FlagGT_UGT {
+ break
+ }
+ v.reset(Op386MOVLconst)
+ v.AuxInt = 1
+ return true
+ }
+ return false
+}
+func rewriteValue386_Op386SETL(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 != Op386InvertFlags {
+ break
+ }
+ x := v_0.Args[0]
+ v.reset(Op386SETG)
+ v.AddArg(x)
+ return true
+ }
+ // match: (SETL (FlagEQ))
+ // cond:
+ // result: (MOVLconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != Op386FlagEQ {
+ break
+ }
+ v.reset(Op386MOVLconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (SETL (FlagLT_ULT))
+ // cond:
+ // result: (MOVLconst [1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != Op386FlagLT_ULT {
+ break
+ }
+ v.reset(Op386MOVLconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (SETL (FlagLT_UGT))
+ // cond:
+ // result: (MOVLconst [1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != Op386FlagLT_UGT {
+ break
+ }
+ v.reset(Op386MOVLconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (SETL (FlagGT_ULT))
+ // cond:
+ // result: (MOVLconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != Op386FlagGT_ULT {
+ break
+ }
+ v.reset(Op386MOVLconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (SETL (FlagGT_UGT))
+ // cond:
+ // result: (MOVLconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != Op386FlagGT_UGT {
+ break
+ }
+ v.reset(Op386MOVLconst)
+ v.AuxInt = 0
+ return true
+ }
+ return false
+}
+func rewriteValue386_Op386SETLE(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 != Op386InvertFlags {
+ break
+ }
+ x := v_0.Args[0]
+ v.reset(Op386SETGE)
+ v.AddArg(x)
+ return true
+ }
+ // match: (SETLE (FlagEQ))
+ // cond:
+ // result: (MOVLconst [1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != Op386FlagEQ {
+ break
+ }
+ v.reset(Op386MOVLconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (SETLE (FlagLT_ULT))
+ // cond:
+ // result: (MOVLconst [1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != Op386FlagLT_ULT {
+ break
+ }
+ v.reset(Op386MOVLconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (SETLE (FlagLT_UGT))
+ // cond:
+ // result: (MOVLconst [1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != Op386FlagLT_UGT {
+ break
+ }
+ v.reset(Op386MOVLconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (SETLE (FlagGT_ULT))
+ // cond:
+ // result: (MOVLconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != Op386FlagGT_ULT {
+ break
+ }
+ v.reset(Op386MOVLconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (SETLE (FlagGT_UGT))
+ // cond:
+ // result: (MOVLconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != Op386FlagGT_UGT {
+ break
+ }
+ v.reset(Op386MOVLconst)
+ v.AuxInt = 0
+ return true
+ }
+ return false
+}
+func rewriteValue386_Op386SETNE(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SETNE (InvertFlags x))
+ // cond:
+ // result: (SETNE x)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != Op386InvertFlags {
+ break
+ }
+ x := v_0.Args[0]
+ v.reset(Op386SETNE)
+ v.AddArg(x)
+ return true
+ }
+ // match: (SETNE (FlagEQ))
+ // cond:
+ // result: (MOVLconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != Op386FlagEQ {
+ break
+ }
+ v.reset(Op386MOVLconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (SETNE (FlagLT_ULT))
+ // cond:
+ // result: (MOVLconst [1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != Op386FlagLT_ULT {
+ break
+ }
+ v.reset(Op386MOVLconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (SETNE (FlagLT_UGT))
+ // cond:
+ // result: (MOVLconst [1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != Op386FlagLT_UGT {
+ break
+ }
+ v.reset(Op386MOVLconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (SETNE (FlagGT_ULT))
+ // cond:
+ // result: (MOVLconst [1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != Op386FlagGT_ULT {
+ break
+ }
+ v.reset(Op386MOVLconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (SETNE (FlagGT_UGT))
+ // cond:
+ // result: (MOVLconst [1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != Op386FlagGT_UGT {
+ break
+ }
+ v.reset(Op386MOVLconst)
+ v.AuxInt = 1
+ return true
+ }
+ 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
+ }
+ // 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
+ }
+ // 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 != Op386ANDLconst {
+ break
+ }
+ if v_1.AuxInt != 31 {
+ break
+ }
+ y := v_1.Args[0]
+ v.reset(Op386SHLL)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ return false
+}
+func rewriteValue386_Op386SHRB(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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 != Op386MOVLconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(Op386SHRBconst)
+ 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 != Op386MOVLconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(Op386SHRBconst)
+ v.AuxInt = c & 31
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValue386_Op386SHRL(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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 != Op386MOVLconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(Op386SHRLconst)
+ 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 != Op386MOVLconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(Op386SHRLconst)
+ 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 != Op386ANDLconst {
+ break
+ }
+ if v_1.AuxInt != 31 {
+ break
+ }
+ y := v_1.Args[0]
+ v.reset(Op386SHRL)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ return false
+}
+func rewriteValue386_Op386SHRW(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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 != Op386MOVLconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(Op386SHRWconst)
+ 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 != Op386MOVLconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(Op386SHRWconst)
+ v.AuxInt = c & 31
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValue386_Op386SUBL(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 != Op386MOVLconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(Op386SUBLconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (SUBL (MOVLconst [c]) x)
+ // cond:
+ // result: (NEGL (SUBLconst <v.Type> x [c]))
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != Op386MOVLconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ v.reset(Op386NEGL)
+ v0 := b.NewValue0(v.Line, Op386SUBLconst, 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] {
+ break
+ }
+ v.reset(Op386MOVLconst)
+ v.AuxInt = 0
+ return true
+ }
+ return false
+}
+func rewriteValue386_Op386SUBLcarry(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SUBLcarry x (MOVLconst [c]))
+ // cond:
+ // result: (SUBLconstcarry [c] x)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != Op386MOVLconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(Op386SUBLconstcarry)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValue386_Op386SUBLconst(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SUBLconst [c] x)
+ // cond: int32(c) == 0
+ // result: x
+ for {
+ c := v.AuxInt
+ x := v.Args[0]
+ if !(int32(c) == 0) {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ // match: (SUBLconst [c] x)
+ // cond:
+ // result: (ADDLconst [int64(int32(-c))] x)
+ for {
+ c := v.AuxInt
+ x := v.Args[0]
+ v.reset(Op386ADDLconst)
+ v.AuxInt = int64(int32(-c))
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValue386_Op386XORL(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (XORL x (MOVLconst [c]))
+ // cond:
+ // result: (XORLconst [c] x)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != 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_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 x x)
+ // cond:
+ // result: (MOVLconst [0])
+ for {
+ x := v.Args[0]
+ if x != v.Args[1] {
+ break
+ }
+ v.reset(Op386MOVLconst)
+ v.AuxInt = 0
+ return true
+ }
+ return false
+}
+func rewriteValue386_Op386XORLconst(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 != Op386XORLconst {
+ break
+ }
+ d := v_0.AuxInt
+ x := v_0.Args[0]
+ v.reset(Op386XORLconst)
+ 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 != Op386MOVLconst {
+ break
+ }
+ d := v_0.AuxInt
+ v.reset(Op386MOVLconst)
+ v.AuxInt = c ^ d
+ return true
+ }
+ return false
+}
+func rewriteValue386_OpAdd16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Add16 x y)
+ // cond:
+ // result: (ADDL x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(Op386ADDL)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValue386_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(Op386ADDL)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValue386_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(Op386ADDSS)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValue386_OpAdd32carry(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Add32carry x y)
+ // cond:
+ // result: (ADDLcarry x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(Op386ADDLcarry)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValue386_OpAdd32withcarry(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Add32withcarry x y c)
+ // cond:
+ // result: (ADCL x y c)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ c := v.Args[2]
+ v.reset(Op386ADCL)
+ v.AddArg(x)
+ v.AddArg(y)
+ v.AddArg(c)
+ return true
+ }
+}
+func rewriteValue386_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(Op386ADDSD)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValue386_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(Op386ADDL)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValue386_OpAddPtr(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (AddPtr x y)
+ // cond:
+ // result: (ADDL x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(Op386ADDL)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValue386_OpAddr(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Addr {sym} base)
+ // cond:
+ // result: (LEAL {sym} base)
+ for {
+ sym := v.Aux
+ base := v.Args[0]
+ v.reset(Op386LEAL)
+ v.Aux = sym
+ v.AddArg(base)
+ return true
+ }
+}
+func rewriteValue386_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(Op386ANDL)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValue386_OpAnd32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (And32 x y)
+ // cond:
+ // result: (ANDL x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(Op386ANDL)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValue386_OpAnd8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (And8 x y)
+ // cond:
+ // result: (ANDL x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(Op386ANDL)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValue386_OpAndB(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (AndB x y)
+ // cond:
+ // result: (ANDL x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(Op386ANDL)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValue386_OpBswap32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Bswap32 x)
+ // cond:
+ // result: (BSWAPL x)
+ for {
+ x := v.Args[0]
+ v.reset(Op386BSWAPL)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValue386_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(Op386CALLclosure)
+ v.AuxInt = argwid
+ v.AddArg(entry)
+ v.AddArg(closure)
+ v.AddArg(mem)
+ return true
+ }
+}
+func rewriteValue386_OpCom16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Com16 x)
+ // cond:
+ // result: (NOTL x)
+ for {
+ x := v.Args[0]
+ v.reset(Op386NOTL)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValue386_OpCom32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Com32 x)
+ // cond:
+ // result: (NOTL x)
+ for {
+ x := v.Args[0]
+ v.reset(Op386NOTL)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValue386_OpCom8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Com8 x)
+ // cond:
+ // result: (NOTL x)
+ for {
+ x := v.Args[0]
+ v.reset(Op386NOTL)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValue386_OpConst16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Const16 [val])
+ // cond:
+ // result: (MOVLconst [val])
+ for {
+ val := v.AuxInt
+ v.reset(Op386MOVLconst)
+ v.AuxInt = val
+ return true
+ }
+}
+func rewriteValue386_OpConst32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Const32 [val])
+ // cond:
+ // result: (MOVLconst [val])
+ for {
+ val := v.AuxInt
+ v.reset(Op386MOVLconst)
+ v.AuxInt = val
+ return true
+ }
+}
+func rewriteValue386_OpConst32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Const32F [val])
+ // cond:
+ // result: (MOVSSconst [val])
+ for {
+ val := v.AuxInt
+ v.reset(Op386MOVSSconst)
+ v.AuxInt = val
+ return true
+ }
+}
+func rewriteValue386_OpConst64F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Const64F [val])
+ // cond:
+ // result: (MOVSDconst [val])
+ for {
+ val := v.AuxInt
+ v.reset(Op386MOVSDconst)
+ v.AuxInt = val
+ return true
+ }
+}
+func rewriteValue386_OpConst8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Const8 [val])
+ // cond:
+ // result: (MOVLconst [val])
+ for {
+ val := v.AuxInt
+ v.reset(Op386MOVLconst)
+ v.AuxInt = val
+ return true
+ }
+}
+func rewriteValue386_OpConstBool(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ConstBool [b])
+ // cond:
+ // result: (MOVLconst [b])
+ for {
+ b := v.AuxInt
+ v.reset(Op386MOVLconst)
+ v.AuxInt = b
+ return true
+ }
+}
+func rewriteValue386_OpConstNil(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ConstNil)
+ // cond:
+ // result: (MOVLconst [0])
+ for {
+ v.reset(Op386MOVLconst)
+ v.AuxInt = 0
+ return true
+ }
+}
+func rewriteValue386_OpConvert(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Convert <t> x mem)
+ // cond:
+ // result: (MOVLconvert <t> x mem)
+ for {
+ t := v.Type
+ x := v.Args[0]
+ mem := v.Args[1]
+ v.reset(Op386MOVLconvert)
+ v.Type = t
+ v.AddArg(x)
+ v.AddArg(mem)
+ return true
+ }
+}
+func rewriteValue386_OpCvt32Fto32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Cvt32Fto32 x)
+ // cond:
+ // result: (CVTTSS2SL x)
+ for {
+ x := v.Args[0]
+ v.reset(Op386CVTTSS2SL)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValue386_OpCvt32Fto64F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Cvt32Fto64F x)
+ // cond:
+ // result: (CVTSS2SD x)
+ for {
+ x := v.Args[0]
+ v.reset(Op386CVTSS2SD)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValue386_OpCvt32to32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Cvt32to32F x)
+ // cond:
+ // result: (CVTSL2SS x)
+ for {
+ x := v.Args[0]
+ v.reset(Op386CVTSL2SS)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValue386_OpCvt32to64F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Cvt32to64F x)
+ // cond:
+ // result: (CVTSL2SD x)
+ for {
+ x := v.Args[0]
+ v.reset(Op386CVTSL2SD)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValue386_OpCvt64Fto32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Cvt64Fto32 x)
+ // cond:
+ // result: (CVTTSD2SL x)
+ for {
+ x := v.Args[0]
+ v.reset(Op386CVTTSD2SL)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValue386_OpCvt64Fto32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Cvt64Fto32F x)
+ // cond:
+ // result: (CVTSD2SS x)
+ for {
+ x := v.Args[0]
+ v.reset(Op386CVTSD2SS)
+ v.AddArg(x)
+ 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)
+ // cond:
+ // result: (DIVW x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(Op386DIVW)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValue386_OpDiv16u(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Div16u x y)
+ // cond:
+ // result: (DIVWU x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(Op386DIVWU)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValue386_OpDiv32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Div32 x y)
+ // cond:
+ // result: (DIVL x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(Op386DIVL)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValue386_OpDiv32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Div32F x y)
+ // cond:
+ // result: (DIVSS x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(Op386DIVSS)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValue386_OpDiv32u(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Div32u x y)
+ // cond:
+ // result: (DIVLU x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(Op386DIVLU)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValue386_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(Op386DIVSD)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValue386_OpDiv8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Div8 x y)
+ // cond:
+ // result: (DIVW (SignExt8to16 x) (SignExt8to16 y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(Op386DIVW)
+ v0 := b.NewValue0(v.Line, OpSignExt8to16, config.fe.TypeInt16())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpSignExt8to16, config.fe.TypeInt16())
+ v1.AddArg(y)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValue386_OpDiv8u(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Div8u x y)
+ // cond:
+ // result: (DIVWU (ZeroExt8to16 x) (ZeroExt8to16 y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(Op386DIVWU)
+ v0 := b.NewValue0(v.Line, OpZeroExt8to16, config.fe.TypeUInt16())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpZeroExt8to16, config.fe.TypeUInt16())
+ v1.AddArg(y)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValue386_OpEq16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Eq16 x y)
+ // cond:
+ // result: (SETEQ (CMPW x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(Op386SETEQ)
+ v0 := b.NewValue0(v.Line, Op386CMPW, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValue386_OpEq32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Eq32 x y)
+ // cond:
+ // result: (SETEQ (CMPL x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(Op386SETEQ)
+ v0 := b.NewValue0(v.Line, Op386CMPL, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValue386_OpEq32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Eq32F x y)
+ // cond:
+ // result: (SETEQF (UCOMISS x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(Op386SETEQF)
+ v0 := b.NewValue0(v.Line, Op386UCOMISS, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValue386_OpEq64F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Eq64F x y)
+ // cond:
+ // result: (SETEQF (UCOMISD x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(Op386SETEQF)
+ v0 := b.NewValue0(v.Line, Op386UCOMISD, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValue386_OpEq8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Eq8 x y)
+ // cond:
+ // result: (SETEQ (CMPB x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(Op386SETEQ)
+ v0 := b.NewValue0(v.Line, Op386CMPB, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValue386_OpEqB(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (EqB x y)
+ // cond:
+ // result: (SETEQ (CMPB x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(Op386SETEQ)
+ v0 := b.NewValue0(v.Line, Op386CMPB, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValue386_OpEqPtr(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (EqPtr x y)
+ // cond:
+ // result: (SETEQ (CMPL x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(Op386SETEQ)
+ v0 := b.NewValue0(v.Line, Op386CMPL, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValue386_OpGeq16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Geq16 x y)
+ // cond:
+ // result: (SETGE (CMPW x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(Op386SETGE)
+ v0 := b.NewValue0(v.Line, Op386CMPW, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValue386_OpGeq16U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Geq16U x y)
+ // cond:
+ // result: (SETAE (CMPW x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(Op386SETAE)
+ v0 := b.NewValue0(v.Line, Op386CMPW, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValue386_OpGeq32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Geq32 x y)
+ // cond:
+ // result: (SETGE (CMPL x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(Op386SETGE)
+ v0 := b.NewValue0(v.Line, Op386CMPL, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValue386_OpGeq32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Geq32F x y)
+ // cond:
+ // result: (SETGEF (UCOMISS x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(Op386SETGEF)
+ v0 := b.NewValue0(v.Line, Op386UCOMISS, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValue386_OpGeq32U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Geq32U x y)
+ // cond:
+ // result: (SETAE (CMPL x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(Op386SETAE)
+ v0 := b.NewValue0(v.Line, Op386CMPL, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValue386_OpGeq64F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Geq64F x y)
+ // cond:
+ // result: (SETGEF (UCOMISD x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(Op386SETGEF)
+ v0 := b.NewValue0(v.Line, Op386UCOMISD, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValue386_OpGeq8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Geq8 x y)
+ // cond:
+ // result: (SETGE (CMPB x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(Op386SETGE)
+ v0 := b.NewValue0(v.Line, Op386CMPB, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValue386_OpGeq8U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Geq8U x y)
+ // cond:
+ // result: (SETAE (CMPB x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(Op386SETAE)
+ v0 := b.NewValue0(v.Line, Op386CMPB, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValue386_OpGetClosurePtr(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (GetClosurePtr)
+ // cond:
+ // result: (LoweredGetClosurePtr)
+ for {
+ v.reset(Op386LoweredGetClosurePtr)
+ return true
+ }
+}
+func rewriteValue386_OpGetG(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (GetG mem)
+ // cond:
+ // result: (LoweredGetG mem)
+ for {
+ mem := v.Args[0]
+ v.reset(Op386LoweredGetG)
+ v.AddArg(mem)
+ return true
+ }
+}
+func rewriteValue386_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(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)
+ // cond:
+ // result: (SETG (CMPW x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(Op386SETG)
+ v0 := b.NewValue0(v.Line, Op386CMPW, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValue386_OpGreater16U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Greater16U x y)
+ // cond:
+ // result: (SETA (CMPW x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(Op386SETA)
+ v0 := b.NewValue0(v.Line, Op386CMPW, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValue386_OpGreater32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Greater32 x y)
+ // cond:
+ // result: (SETG (CMPL x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(Op386SETG)
+ v0 := b.NewValue0(v.Line, Op386CMPL, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValue386_OpGreater32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Greater32F x y)
+ // cond:
+ // result: (SETGF (UCOMISS x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(Op386SETGF)
+ v0 := b.NewValue0(v.Line, Op386UCOMISS, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValue386_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(Op386SETA)
+ v0 := b.NewValue0(v.Line, Op386CMPL, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValue386_OpGreater64F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Greater64F x y)
+ // cond:
+ // result: (SETGF (UCOMISD x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(Op386SETGF)
+ v0 := b.NewValue0(v.Line, Op386UCOMISD, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValue386_OpGreater8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Greater8 x y)
+ // cond:
+ // result: (SETG (CMPB x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(Op386SETG)
+ v0 := b.NewValue0(v.Line, Op386CMPB, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValue386_OpGreater8U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Greater8U x y)
+ // cond:
+ // result: (SETA (CMPB x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(Op386SETA)
+ v0 := b.NewValue0(v.Line, Op386CMPB, 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)
+ // cond:
+ // result: (HMULL x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(Op386HMULL)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValue386_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(Op386HMULLU)
+ v.AddArg(x)
+ v.AddArg(y)
+ 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
+ // 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(Op386CALLinter)
+ v.AuxInt = argwid
+ v.AddArg(entry)
+ v.AddArg(mem)
+ return true
+ }
+}
+func rewriteValue386_OpIsInBounds(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (IsInBounds idx len)
+ // cond:
+ // result: (SETB (CMPL idx len))
+ for {
+ idx := v.Args[0]
+ len := v.Args[1]
+ v.reset(Op386SETB)
+ v0 := b.NewValue0(v.Line, Op386CMPL, TypeFlags)
+ v0.AddArg(idx)
+ v0.AddArg(len)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValue386_OpIsNonNil(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (IsNonNil p)
+ // cond:
+ // result: (SETNE (TESTL p p))
+ for {
+ p := v.Args[0]
+ v.reset(Op386SETNE)
+ v0 := b.NewValue0(v.Line, Op386TESTL, TypeFlags)
+ v0.AddArg(p)
+ v0.AddArg(p)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValue386_OpIsSliceInBounds(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (IsSliceInBounds idx len)
+ // cond:
+ // result: (SETBE (CMPL idx len))
+ for {
+ idx := v.Args[0]
+ len := v.Args[1]
+ v.reset(Op386SETBE)
+ v0 := b.NewValue0(v.Line, Op386CMPL, TypeFlags)
+ v0.AddArg(idx)
+ v0.AddArg(len)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValue386_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(Op386SETLE)
+ v0 := b.NewValue0(v.Line, Op386CMPW, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValue386_OpLeq16U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Leq16U x y)
+ // cond:
+ // result: (SETBE (CMPW x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(Op386SETBE)
+ v0 := b.NewValue0(v.Line, Op386CMPW, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValue386_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(Op386SETLE)
+ v0 := b.NewValue0(v.Line, Op386CMPL, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValue386_OpLeq32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Leq32F x y)
+ // cond:
+ // result: (SETGEF (UCOMISS y x))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(Op386SETGEF)
+ v0 := b.NewValue0(v.Line, Op386UCOMISS, TypeFlags)
+ v0.AddArg(y)
+ v0.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValue386_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(Op386SETBE)
+ v0 := b.NewValue0(v.Line, Op386CMPL, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValue386_OpLeq64F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Leq64F x y)
+ // cond:
+ // result: (SETGEF (UCOMISD y x))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(Op386SETGEF)
+ v0 := b.NewValue0(v.Line, Op386UCOMISD, TypeFlags)
+ v0.AddArg(y)
+ v0.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValue386_OpLeq8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Leq8 x y)
+ // cond:
+ // result: (SETLE (CMPB x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(Op386SETLE)
+ v0 := b.NewValue0(v.Line, Op386CMPB, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValue386_OpLeq8U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Leq8U x y)
+ // cond:
+ // result: (SETBE (CMPB x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(Op386SETBE)
+ v0 := b.NewValue0(v.Line, Op386CMPB, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValue386_OpLess16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Less16 x y)
+ // cond:
+ // result: (SETL (CMPW x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(Op386SETL)
+ v0 := b.NewValue0(v.Line, Op386CMPW, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValue386_OpLess16U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Less16U x y)
+ // cond:
+ // result: (SETB (CMPW x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(Op386SETB)
+ v0 := b.NewValue0(v.Line, Op386CMPW, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValue386_OpLess32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Less32 x y)
+ // cond:
+ // result: (SETL (CMPL x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(Op386SETL)
+ v0 := b.NewValue0(v.Line, Op386CMPL, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValue386_OpLess32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Less32F x y)
+ // cond:
+ // result: (SETGF (UCOMISS y x))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(Op386SETGF)
+ v0 := b.NewValue0(v.Line, Op386UCOMISS, TypeFlags)
+ v0.AddArg(y)
+ v0.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValue386_OpLess32U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Less32U x y)
+ // cond:
+ // result: (SETB (CMPL x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(Op386SETB)
+ v0 := b.NewValue0(v.Line, Op386CMPL, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValue386_OpLess64F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Less64F x y)
+ // cond:
+ // result: (SETGF (UCOMISD y x))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(Op386SETGF)
+ v0 := b.NewValue0(v.Line, Op386UCOMISD, TypeFlags)
+ v0.AddArg(y)
+ v0.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValue386_OpLess8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Less8 x y)
+ // cond:
+ // result: (SETL (CMPB x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(Op386SETL)
+ v0 := b.NewValue0(v.Line, Op386CMPB, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValue386_OpLess8U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Less8U x y)
+ // cond:
+ // result: (SETB (CMPB x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(Op386SETB)
+ v0 := b.NewValue0(v.Line, Op386CMPB, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValue386_OpLoad(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Load <t> ptr mem)
+ // cond: (is32BitInt(t) || isPtr(t))
+ // result: (MOVLload ptr mem)
+ for {
+ t := v.Type
+ ptr := v.Args[0]
+ mem := v.Args[1]
+ if !(is32BitInt(t) || isPtr(t)) {
+ break
+ }
+ v.reset(Op386MOVLload)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (Load <t> ptr mem)
+ // cond: is16BitInt(t)
+ // result: (MOVWload ptr mem)
+ for {
+ t := v.Type
+ ptr := v.Args[0]
+ mem := v.Args[1]
+ if !(is16BitInt(t)) {
+ break
+ }
+ v.reset(Op386MOVWload)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (Load <t> ptr mem)
+ // cond: (t.IsBoolean() || is8BitInt(t))
+ // result: (MOVBload ptr mem)
+ for {
+ t := v.Type
+ ptr := v.Args[0]
+ mem := v.Args[1]
+ if !(t.IsBoolean() || is8BitInt(t)) {
+ break
+ }
+ v.reset(Op386MOVBload)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (Load <t> ptr mem)
+ // cond: is32BitFloat(t)
+ // result: (MOVSSload ptr mem)
+ for {
+ t := v.Type
+ ptr := v.Args[0]
+ mem := v.Args[1]
+ if !(is32BitFloat(t)) {
+ break
+ }
+ v.reset(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)
+ for {
+ t := v.Type
+ c := v.AuxInt
+ x := v.Args[0]
+ v.reset(Op386ROLBconst)
+ v.Type = t
+ v.AuxInt = c & 7
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValue386_OpLsh16x16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Lsh16x16 <t> x y)
+ // cond:
+ // result: (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPWconst y [32])))
+ for {
+ t := v.Type
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(Op386ANDL)
+ v0 := b.NewValue0(v.Line, 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)
+ v2.AuxInt = 32
+ v2.AddArg(y)
+ v1.AddArg(v2)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValue386_OpLsh16x32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Lsh16x32 <t> x y)
+ // cond:
+ // result: (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPLconst y [32])))
+ for {
+ t := v.Type
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(Op386ANDL)
+ v0 := b.NewValue0(v.Line, 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)
+ v2.AuxInt = 32
+ v2.AddArg(y)
+ v1.AddArg(v2)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValue386_OpLsh16x64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Lsh16x64 x (Const64 [c]))
+ // cond: uint64(c) < 16
+ // result: (SHLLconst x [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpConst64 {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint64(c) < 16) {
+ break
+ }
+ v.reset(Op386SHLLconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (Lsh16x64 _ (Const64 [c]))
+ // cond: uint64(c) >= 16
+ // result: (Const16 [0])
+ for {
+ v_1 := v.Args[1]
+ if v_1.Op != OpConst64 {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint64(c) >= 16) {
+ break
+ }
+ v.reset(OpConst16)
+ v.AuxInt = 0
+ return true
+ }
+ return false
+}
+func rewriteValue386_OpLsh16x8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Lsh16x8 <t> x y)
+ // cond:
+ // result: (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPBconst y [32])))
+ for {
+ t := v.Type
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(Op386ANDL)
+ v0 := b.NewValue0(v.Line, 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)
+ v2.AuxInt = 32
+ v2.AddArg(y)
+ v1.AddArg(v2)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValue386_OpLsh32x16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Lsh32x16 <t> x y)
+ // cond:
+ // result: (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPWconst y [32])))
+ for {
+ t := v.Type
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(Op386ANDL)
+ v0 := b.NewValue0(v.Line, 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)
+ v2.AuxInt = 32
+ v2.AddArg(y)
+ v1.AddArg(v2)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValue386_OpLsh32x32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Lsh32x32 <t> x y)
+ // cond:
+ // result: (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPLconst y [32])))
+ for {
+ t := v.Type
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(Op386ANDL)
+ v0 := b.NewValue0(v.Line, 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)
+ v2.AuxInt = 32
+ v2.AddArg(y)
+ v1.AddArg(v2)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValue386_OpLsh32x64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Lsh32x64 x (Const64 [c]))
+ // cond: uint64(c) < 32
+ // result: (SHLLconst x [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpConst64 {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint64(c) < 32) {
+ break
+ }
+ v.reset(Op386SHLLconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (Lsh32x64 _ (Const64 [c]))
+ // cond: uint64(c) >= 32
+ // result: (Const32 [0])
+ for {
+ v_1 := v.Args[1]
+ if v_1.Op != OpConst64 {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint64(c) >= 32) {
+ break
+ }
+ v.reset(OpConst32)
+ v.AuxInt = 0
+ return true
+ }
+ return false
+}
+func rewriteValue386_OpLsh32x8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Lsh32x8 <t> x y)
+ // cond:
+ // result: (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPBconst y [32])))
+ for {
+ t := v.Type
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(Op386ANDL)
+ v0 := b.NewValue0(v.Line, 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)
+ v2.AuxInt = 32
+ v2.AddArg(y)
+ v1.AddArg(v2)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValue386_OpLsh8x16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Lsh8x16 <t> x y)
+ // cond:
+ // result: (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPWconst y [32])))
+ for {
+ t := v.Type
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(Op386ANDL)
+ v0 := b.NewValue0(v.Line, 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)
+ v2.AuxInt = 32
+ v2.AddArg(y)
+ v1.AddArg(v2)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValue386_OpLsh8x32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Lsh8x32 <t> x y)
+ // cond:
+ // result: (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPLconst y [32])))
+ for {
+ t := v.Type
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(Op386ANDL)
+ v0 := b.NewValue0(v.Line, 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)
+ v2.AuxInt = 32
+ v2.AddArg(y)
+ v1.AddArg(v2)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValue386_OpLsh8x64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Lsh8x64 x (Const64 [c]))
+ // cond: uint64(c) < 8
+ // result: (SHLLconst x [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpConst64 {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint64(c) < 8) {
+ break
+ }
+ v.reset(Op386SHLLconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (Lsh8x64 _ (Const64 [c]))
+ // cond: uint64(c) >= 8
+ // result: (Const8 [0])
+ for {
+ v_1 := v.Args[1]
+ if v_1.Op != OpConst64 {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint64(c) >= 8) {
+ break
+ }
+ v.reset(OpConst8)
+ v.AuxInt = 0
+ return true
+ }
+ return false
+}
+func rewriteValue386_OpLsh8x8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Lsh8x8 <t> x y)
+ // cond:
+ // result: (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPBconst y [32])))
+ for {
+ t := v.Type
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(Op386ANDL)
+ v0 := b.NewValue0(v.Line, 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)
+ v2.AuxInt = 32
+ v2.AddArg(y)
+ v1.AddArg(v2)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValue386_OpMod16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Mod16 x y)
+ // cond:
+ // result: (MODW x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(Op386MODW)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValue386_OpMod16u(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Mod16u x y)
+ // cond:
+ // result: (MODWU x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(Op386MODWU)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValue386_OpMod32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Mod32 x y)
+ // cond:
+ // result: (MODL x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(Op386MODL)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValue386_OpMod32u(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Mod32u x y)
+ // cond:
+ // result: (MODLU x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(Op386MODLU)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValue386_OpMod8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Mod8 x y)
+ // cond:
+ // result: (MODW (SignExt8to16 x) (SignExt8to16 y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(Op386MODW)
+ v0 := b.NewValue0(v.Line, OpSignExt8to16, config.fe.TypeInt16())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpSignExt8to16, config.fe.TypeInt16())
+ v1.AddArg(y)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValue386_OpMod8u(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Mod8u x y)
+ // cond:
+ // result: (MODWU (ZeroExt8to16 x) (ZeroExt8to16 y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(Op386MODWU)
+ v0 := b.NewValue0(v.Line, OpZeroExt8to16, config.fe.TypeUInt16())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpZeroExt8to16, config.fe.TypeUInt16())
+ v1.AddArg(y)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValue386_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) {
+ 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) {
+ break
+ }
+ v.reset(Op386MOVBstore)
+ v.AddArg(dst)
+ v0 := b.NewValue0(v.Line, Op386MOVBload, 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) {
+ break
+ }
+ v.reset(Op386MOVWstore)
+ v.AddArg(dst)
+ v0 := b.NewValue0(v.Line, Op386MOVWload, 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) {
+ break
+ }
+ v.reset(Op386MOVLstore)
+ v.AddArg(dst)
+ v0 := b.NewValue0(v.Line, Op386MOVLload, 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() == 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) {
+ break
+ }
+ v.reset(Op386MOVBstore)
+ v.AuxInt = 2
+ v.AddArg(dst)
+ v0 := b.NewValue0(v.Line, Op386MOVBload, config.fe.TypeUInt8())
+ v0.AuxInt = 2
+ v0.AddArg(src)
+ v0.AddArg(mem)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, Op386MOVWstore, TypeMem)
+ v1.AddArg(dst)
+ v2 := b.NewValue0(v.Line, Op386MOVWload, config.fe.TypeUInt16())
+ v2.AddArg(src)
+ v2.AddArg(mem)
+ v1.AddArg(v2)
+ v1.AddArg(mem)
+ v.AddArg(v1)
+ 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))
+ for {
+ s := v.AuxInt
+ 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.AuxInt = 4
+ v0.AddArg(src)
+ v0.AddArg(mem)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, Op386MOVLstore, TypeMem)
+ v1.AddArg(dst)
+ v2 := b.NewValue0(v.Line, Op386MOVLload, config.fe.TypeUInt32())
+ v2.AddArg(src)
+ v2.AddArg(mem)
+ v1.AddArg(v2)
+ v1.AddArg(mem)
+ v.AddArg(v1)
+ 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))
+ for {
+ s := v.AuxInt
+ 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.AuxInt = 4
+ v0.AddArg(src)
+ v0.AddArg(mem)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, Op386MOVLstore, TypeMem)
+ v1.AddArg(dst)
+ v2 := b.NewValue0(v.Line, Op386MOVLload, config.fe.TypeUInt32())
+ v2.AddArg(src)
+ v2.AddArg(mem)
+ v1.AddArg(v2)
+ v1.AddArg(mem)
+ v.AddArg(v1)
+ 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))
+ for {
+ s := v.AuxInt
+ 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.AuxInt = 3
+ v0.AddArg(src)
+ v0.AddArg(mem)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, Op386MOVLstore, TypeMem)
+ v1.AddArg(dst)
+ v2 := b.NewValue0(v.Line, Op386MOVLload, config.fe.TypeUInt32())
+ v2.AddArg(src)
+ v2.AddArg(mem)
+ v1.AddArg(v2)
+ v1.AddArg(mem)
+ v.AddArg(v1)
+ return true
+ }
+ // match: (Move [s] dst src mem)
+ // cond: SizeAndAlign(s).Size() == 8
+ // result: (MOVLstore [4] dst (MOVLload [4] src mem) (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() == 8) {
+ break
+ }
+ v.reset(Op386MOVLstore)
+ v.AuxInt = 4
+ v.AddArg(dst)
+ v0 := b.NewValue0(v.Line, Op386MOVLload, config.fe.TypeUInt32())
+ v0.AuxInt = 4
+ v0.AddArg(src)
+ v0.AddArg(mem)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, Op386MOVLstore, TypeMem)
+ v1.AddArg(dst)
+ v2 := b.NewValue0(v.Line, Op386MOVLload, config.fe.TypeUInt32())
+ v2.AddArg(src)
+ v2.AddArg(mem)
+ v1.AddArg(v2)
+ v1.AddArg(mem)
+ v.AddArg(v1)
+ 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))
+ for {
+ s := v.AuxInt
+ dst := v.Args[0]
+ src := v.Args[1]
+ mem := v.Args[2]
+ if !(SizeAndAlign(s).Size() > 8 && SizeAndAlign(s).Size()%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
+ v0.AddArg(dst)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, Op386ADDLconst, src.Type)
+ v1.AuxInt = SizeAndAlign(s).Size() % 4
+ v1.AddArg(src)
+ v.AddArg(v1)
+ v2 := b.NewValue0(v.Line, Op386MOVLstore, TypeMem)
+ v2.AddArg(dst)
+ v3 := b.NewValue0(v.Line, Op386MOVLload, config.fe.TypeUInt32())
+ v3.AddArg(src)
+ v3.AddArg(mem)
+ v2.AddArg(v3)
+ v2.AddArg(mem)
+ v.AddArg(v2)
+ return true
+ }
+ // 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)
+ for {
+ s := v.AuxInt
+ 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) {
+ break
+ }
+ v.reset(Op386DUFFCOPY)
+ v.AuxInt = 10 * (128 - SizeAndAlign(s).Size()/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)
+ for {
+ s := v.AuxInt
+ 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) {
+ 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
+ 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)
+ // cond:
+ // result: (MULL x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(Op386MULL)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValue386_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(Op386MULL)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValue386_OpMul32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Mul32F x y)
+ // cond:
+ // result: (MULSS x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(Op386MULSS)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValue386_OpMul32uhilo(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Mul32uhilo x y)
+ // cond:
+ // result: (MULLQU x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(Op386MULLQU)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValue386_OpMul64F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Mul64F x y)
+ // cond:
+ // result: (MULSD x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(Op386MULSD)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValue386_OpMul8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Mul8 x y)
+ // cond:
+ // result: (MULL x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(Op386MULL)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValue386_OpNeg16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Neg16 x)
+ // cond:
+ // result: (NEGL x)
+ for {
+ x := v.Args[0]
+ v.reset(Op386NEGL)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValue386_OpNeg32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Neg32 x)
+ // cond:
+ // result: (NEGL x)
+ for {
+ x := v.Args[0]
+ v.reset(Op386NEGL)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValue386_OpNeg32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Neg32F x)
+ // cond: !config.use387
+ // result: (PXOR x (MOVSSconst <config.Frontend().TypeFloat32()> [f2i(math.Copysign(0, -1))]))
+ for {
+ x := v.Args[0]
+ if !(!config.use387) {
+ break
+ }
+ v.reset(Op386PXOR)
+ v.AddArg(x)
+ v0 := b.NewValue0(v.Line, Op386MOVSSconst, config.Frontend().TypeFloat32())
+ v0.AuxInt = f2i(math.Copysign(0, -1))
+ v.AddArg(v0)
+ return true
+ }
+ // match: (Neg32F x)
+ // cond: config.use387
+ // result: (FCHS x)
+ for {
+ x := v.Args[0]
+ if !(config.use387) {
+ break
+ }
+ v.reset(Op386FCHS)
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValue386_OpNeg64F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Neg64F x)
+ // cond: !config.use387
+ // result: (PXOR x (MOVSDconst <config.Frontend().TypeFloat64()> [f2i(math.Copysign(0, -1))]))
+ for {
+ x := v.Args[0]
+ if !(!config.use387) {
+ break
+ }
+ v.reset(Op386PXOR)
+ v.AddArg(x)
+ v0 := b.NewValue0(v.Line, Op386MOVSDconst, config.Frontend().TypeFloat64())
+ v0.AuxInt = f2i(math.Copysign(0, -1))
+ v.AddArg(v0)
+ return true
+ }
+ // match: (Neg64F x)
+ // cond: config.use387
+ // result: (FCHS x)
+ for {
+ x := v.Args[0]
+ if !(config.use387) {
+ break
+ }
+ v.reset(Op386FCHS)
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValue386_OpNeg8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Neg8 x)
+ // cond:
+ // result: (NEGL x)
+ for {
+ x := v.Args[0]
+ v.reset(Op386NEGL)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValue386_OpNeq16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Neq16 x y)
+ // cond:
+ // result: (SETNE (CMPW x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(Op386SETNE)
+ v0 := b.NewValue0(v.Line, Op386CMPW, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValue386_OpNeq32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Neq32 x y)
+ // cond:
+ // result: (SETNE (CMPL x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(Op386SETNE)
+ v0 := b.NewValue0(v.Line, Op386CMPL, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValue386_OpNeq32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Neq32F x y)
+ // cond:
+ // result: (SETNEF (UCOMISS x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(Op386SETNEF)
+ v0 := b.NewValue0(v.Line, Op386UCOMISS, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValue386_OpNeq64F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Neq64F x y)
+ // cond:
+ // result: (SETNEF (UCOMISD x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(Op386SETNEF)
+ v0 := b.NewValue0(v.Line, Op386UCOMISD, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValue386_OpNeq8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Neq8 x y)
+ // cond:
+ // result: (SETNE (CMPB x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(Op386SETNE)
+ v0 := b.NewValue0(v.Line, Op386CMPB, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValue386_OpNeqB(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (NeqB x y)
+ // cond:
+ // result: (SETNE (CMPB x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(Op386SETNE)
+ v0 := b.NewValue0(v.Line, Op386CMPB, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValue386_OpNeqPtr(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (NeqPtr x y)
+ // cond:
+ // result: (SETNE (CMPL x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(Op386SETNE)
+ v0 := b.NewValue0(v.Line, Op386CMPL, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValue386_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(Op386LoweredNilCheck)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+}
+func rewriteValue386_OpNot(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Not x)
+ // cond:
+ // result: (XORLconst [1] x)
+ for {
+ x := v.Args[0]
+ v.reset(Op386XORLconst)
+ v.AuxInt = 1
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValue386_OpOffPtr(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (OffPtr [off] ptr)
+ // cond:
+ // result: (ADDLconst [off] ptr)
+ for {
+ off := v.AuxInt
+ ptr := v.Args[0]
+ v.reset(Op386ADDLconst)
+ v.AuxInt = off
+ v.AddArg(ptr)
+ return true
+ }
+}
+func rewriteValue386_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(Op386ORL)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValue386_OpOr32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Or32 x y)
+ // cond:
+ // result: (ORL x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(Op386ORL)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValue386_OpOr8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Or8 x y)
+ // cond:
+ // result: (ORL x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(Op386ORL)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValue386_OpOrB(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (OrB x y)
+ // cond:
+ // result: (ORL x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(Op386ORL)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValue386_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(Op386ANDL)
+ v0 := b.NewValue0(v.Line, 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)
+ v2.AuxInt = 16
+ v2.AddArg(y)
+ v1.AddArg(v2)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValue386_OpRsh16Ux32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh16Ux32 <t> x y)
+ // cond:
+ // result: (ANDL (SHRW <t> x y) (SBBLcarrymask <t> (CMPLconst y [16])))
+ for {
+ t := v.Type
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(Op386ANDL)
+ v0 := b.NewValue0(v.Line, 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)
+ v2.AuxInt = 16
+ v2.AddArg(y)
+ v1.AddArg(v2)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValue386_OpRsh16Ux64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh16Ux64 x (Const64 [c]))
+ // cond: uint64(c) < 16
+ // result: (SHRWconst x [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpConst64 {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint64(c) < 16) {
+ break
+ }
+ v.reset(Op386SHRWconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (Rsh16Ux64 _ (Const64 [c]))
+ // cond: uint64(c) >= 16
+ // result: (Const16 [0])
+ for {
+ v_1 := v.Args[1]
+ if v_1.Op != OpConst64 {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint64(c) >= 16) {
+ break
+ }
+ v.reset(OpConst16)
+ v.AuxInt = 0
+ return true
+ }
+ return false
+}
+func rewriteValue386_OpRsh16Ux8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh16Ux8 <t> x y)
+ // cond:
+ // result: (ANDL (SHRW <t> x y) (SBBLcarrymask <t> (CMPBconst y [16])))
+ for {
+ t := v.Type
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(Op386ANDL)
+ v0 := b.NewValue0(v.Line, 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)
+ v2.AuxInt = 16
+ v2.AddArg(y)
+ v1.AddArg(v2)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValue386_OpRsh16x16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh16x16 <t> x y)
+ // cond:
+ // result: (SARW <t> x (ORL <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPWconst y [16])))))
+ for {
+ t := v.Type
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(Op386SARW)
+ v.Type = t
+ v.AddArg(x)
+ v0 := b.NewValue0(v.Line, 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)
+ v3.AuxInt = 16
+ v3.AddArg(y)
+ v2.AddArg(v3)
+ v1.AddArg(v2)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValue386_OpRsh16x32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh16x32 <t> x y)
+ // cond:
+ // result: (SARW <t> x (ORL <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPLconst y [16])))))
+ for {
+ t := v.Type
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(Op386SARW)
+ v.Type = t
+ v.AddArg(x)
+ v0 := b.NewValue0(v.Line, 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)
+ v3.AuxInt = 16
+ v3.AddArg(y)
+ v2.AddArg(v3)
+ v1.AddArg(v2)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValue386_OpRsh16x64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh16x64 x (Const64 [c]))
+ // cond: uint64(c) < 16
+ // result: (SARWconst x [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpConst64 {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint64(c) < 16) {
+ break
+ }
+ v.reset(Op386SARWconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (Rsh16x64 x (Const64 [c]))
+ // cond: uint64(c) >= 16
+ // result: (SARWconst x [15])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpConst64 {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint64(c) >= 16) {
+ break
+ }
+ v.reset(Op386SARWconst)
+ v.AuxInt = 15
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValue386_OpRsh16x8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh16x8 <t> x y)
+ // cond:
+ // result: (SARW <t> x (ORL <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPBconst y [16])))))
+ for {
+ t := v.Type
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(Op386SARW)
+ v.Type = t
+ v.AddArg(x)
+ v0 := b.NewValue0(v.Line, 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)
+ v3.AuxInt = 16
+ v3.AddArg(y)
+ v2.AddArg(v3)
+ v1.AddArg(v2)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValue386_OpRsh32Ux16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh32Ux16 <t> x y)
+ // cond:
+ // result: (ANDL (SHRL <t> x y) (SBBLcarrymask <t> (CMPWconst y [32])))
+ for {
+ t := v.Type
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(Op386ANDL)
+ v0 := b.NewValue0(v.Line, 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)
+ v2.AuxInt = 32
+ v2.AddArg(y)
+ v1.AddArg(v2)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValue386_OpRsh32Ux32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh32Ux32 <t> x y)
+ // cond:
+ // result: (ANDL (SHRL <t> x y) (SBBLcarrymask <t> (CMPLconst y [32])))
+ for {
+ t := v.Type
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(Op386ANDL)
+ v0 := b.NewValue0(v.Line, 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)
+ v2.AuxInt = 32
+ v2.AddArg(y)
+ v1.AddArg(v2)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValue386_OpRsh32Ux64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh32Ux64 x (Const64 [c]))
+ // cond: uint64(c) < 32
+ // result: (SHRLconst x [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpConst64 {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint64(c) < 32) {
+ break
+ }
+ v.reset(Op386SHRLconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (Rsh32Ux64 _ (Const64 [c]))
+ // cond: uint64(c) >= 32
+ // result: (Const32 [0])
+ for {
+ v_1 := v.Args[1]
+ if v_1.Op != OpConst64 {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint64(c) >= 32) {
+ break
+ }
+ v.reset(OpConst32)
+ v.AuxInt = 0
+ return true
+ }
+ return false
+}
+func rewriteValue386_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(Op386ANDL)
+ v0 := b.NewValue0(v.Line, 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)
+ v2.AuxInt = 32
+ v2.AddArg(y)
+ v1.AddArg(v2)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValue386_OpRsh32x16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh32x16 <t> x y)
+ // cond:
+ // result: (SARL <t> x (ORL <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPWconst y [32])))))
+ for {
+ t := v.Type
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(Op386SARL)
+ v.Type = t
+ v.AddArg(x)
+ v0 := b.NewValue0(v.Line, 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)
+ v3.AuxInt = 32
+ v3.AddArg(y)
+ v2.AddArg(v3)
+ v1.AddArg(v2)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValue386_OpRsh32x32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh32x32 <t> x y)
+ // cond:
+ // result: (SARL <t> x (ORL <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPLconst y [32])))))
+ for {
+ t := v.Type
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(Op386SARL)
+ v.Type = t
+ v.AddArg(x)
+ v0 := b.NewValue0(v.Line, 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)
+ v3.AuxInt = 32
+ v3.AddArg(y)
+ v2.AddArg(v3)
+ v1.AddArg(v2)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValue386_OpRsh32x64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh32x64 x (Const64 [c]))
+ // cond: uint64(c) < 32
+ // result: (SARLconst x [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpConst64 {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint64(c) < 32) {
+ break
+ }
+ v.reset(Op386SARLconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (Rsh32x64 x (Const64 [c]))
+ // cond: uint64(c) >= 32
+ // result: (SARLconst x [31])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpConst64 {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint64(c) >= 32) {
+ break
+ }
+ v.reset(Op386SARLconst)
+ v.AuxInt = 31
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValue386_OpRsh32x8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh32x8 <t> x y)
+ // cond:
+ // result: (SARL <t> x (ORL <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPBconst y [32])))))
+ for {
+ t := v.Type
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(Op386SARL)
+ v.Type = t
+ v.AddArg(x)
+ v0 := b.NewValue0(v.Line, 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)
+ v3.AuxInt = 32
+ v3.AddArg(y)
+ v2.AddArg(v3)
+ v1.AddArg(v2)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValue386_OpRsh8Ux16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh8Ux16 <t> x y)
+ // cond:
+ // result: (ANDL (SHRB <t> x y) (SBBLcarrymask <t> (CMPWconst y [8])))
+ for {
+ t := v.Type
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(Op386ANDL)
+ v0 := b.NewValue0(v.Line, 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)
+ v2.AuxInt = 8
+ v2.AddArg(y)
+ v1.AddArg(v2)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValue386_OpRsh8Ux32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh8Ux32 <t> x y)
+ // cond:
+ // result: (ANDL (SHRB <t> x y) (SBBLcarrymask <t> (CMPLconst y [8])))
+ for {
+ t := v.Type
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(Op386ANDL)
+ v0 := b.NewValue0(v.Line, 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)
+ v2.AuxInt = 8
+ v2.AddArg(y)
+ v1.AddArg(v2)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValue386_OpRsh8Ux64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh8Ux64 x (Const64 [c]))
+ // cond: uint64(c) < 8
+ // result: (SHRBconst x [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpConst64 {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint64(c) < 8) {
+ break
+ }
+ v.reset(Op386SHRBconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (Rsh8Ux64 _ (Const64 [c]))
+ // cond: uint64(c) >= 8
+ // result: (Const8 [0])
+ for {
+ v_1 := v.Args[1]
+ if v_1.Op != OpConst64 {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint64(c) >= 8) {
+ break
+ }
+ v.reset(OpConst8)
+ v.AuxInt = 0
+ return true
+ }
+ return false
+}
+func rewriteValue386_OpRsh8Ux8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh8Ux8 <t> x y)
+ // cond:
+ // result: (ANDL (SHRB <t> x y) (SBBLcarrymask <t> (CMPBconst y [8])))
+ for {
+ t := v.Type
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(Op386ANDL)
+ v0 := b.NewValue0(v.Line, 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)
+ v2.AuxInt = 8
+ v2.AddArg(y)
+ v1.AddArg(v2)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValue386_OpRsh8x16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh8x16 <t> x y)
+ // cond:
+ // result: (SARB <t> x (ORL <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPWconst y [8])))))
+ for {
+ t := v.Type
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(Op386SARB)
+ v.Type = t
+ v.AddArg(x)
+ v0 := b.NewValue0(v.Line, 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)
+ v3.AuxInt = 8
+ v3.AddArg(y)
+ v2.AddArg(v3)
+ v1.AddArg(v2)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValue386_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(Op386SARB)
+ v.Type = t
+ v.AddArg(x)
+ v0 := b.NewValue0(v.Line, 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)
+ v3.AuxInt = 8
+ v3.AddArg(y)
+ v2.AddArg(v3)
+ v1.AddArg(v2)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValue386_OpRsh8x64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh8x64 x (Const64 [c]))
+ // cond: uint64(c) < 8
+ // result: (SARBconst x [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpConst64 {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint64(c) < 8) {
+ break
+ }
+ v.reset(Op386SARBconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (Rsh8x64 x (Const64 [c]))
+ // cond: uint64(c) >= 8
+ // result: (SARBconst x [7])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpConst64 {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint64(c) >= 8) {
+ break
+ }
+ v.reset(Op386SARBconst)
+ v.AuxInt = 7
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValue386_OpRsh8x8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh8x8 <t> x y)
+ // cond:
+ // result: (SARB <t> x (ORL <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPBconst y [8])))))
+ for {
+ t := v.Type
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(Op386SARB)
+ v.Type = t
+ v.AddArg(x)
+ v0 := b.NewValue0(v.Line, 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)
+ v3.AuxInt = 8
+ v3.AddArg(y)
+ v2.AddArg(v3)
+ v1.AddArg(v2)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValue386_OpSignExt16to32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SignExt16to32 x)
+ // cond:
+ // result: (MOVWLSX x)
+ for {
+ x := v.Args[0]
+ v.reset(Op386MOVWLSX)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValue386_OpSignExt8to16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SignExt8to16 x)
+ // cond:
+ // result: (MOVBLSX x)
+ for {
+ x := v.Args[0]
+ v.reset(Op386MOVBLSX)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValue386_OpSignExt8to32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SignExt8to32 x)
+ // cond:
+ // result: (MOVBLSX x)
+ for {
+ x := v.Args[0]
+ v.reset(Op386MOVBLSX)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValue386_OpSignmask(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Signmask x)
+ // cond:
+ // result: (SARLconst x [31])
+ for {
+ x := v.Args[0]
+ v.reset(Op386SARLconst)
+ v.AuxInt = 31
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValue386_OpSlicemask(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Slicemask <t> x)
+ // cond:
+ // result: (XORLconst [-1] (SARLconst <t> (SUBLconst <t> x [1]) [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.AddArg(v0)
+ return true
+ }
+}
+func rewriteValue386_OpSqrt(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Sqrt x)
+ // cond:
+ // result: (SQRTSD x)
+ for {
+ x := v.Args[0]
+ v.reset(Op386SQRTSD)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValue386_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(Op386CALLstatic)
+ v.AuxInt = argwid
+ v.Aux = target
+ v.AddArg(mem)
+ return true
+ }
+}
+func rewriteValue386_OpStore(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Store [8] ptr val mem)
+ // cond: is64BitFloat(val.Type)
+ // result: (MOVSDstore ptr val mem)
+ for {
+ if v.AuxInt != 8 {
+ break
+ }
+ ptr := v.Args[0]
+ val := v.Args[1]
+ mem := v.Args[2]
+ if !(is64BitFloat(val.Type)) {
+ break
+ }
+ v.reset(Op386MOVSDstore)
+ v.AddArg(ptr)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (Store [4] ptr val mem)
+ // cond: is32BitFloat(val.Type)
+ // result: (MOVSSstore ptr val mem)
+ for {
+ if v.AuxInt != 4 {
+ break
+ }
+ ptr := v.Args[0]
+ val := v.Args[1]
+ mem := v.Args[2]
+ if !(is32BitFloat(val.Type)) {
+ break
+ }
+ v.reset(Op386MOVSSstore)
+ v.AddArg(ptr)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (Store [4] ptr val mem)
+ // cond:
+ // result: (MOVLstore ptr val mem)
+ for {
+ if v.AuxInt != 4 {
+ break
+ }
+ ptr := v.Args[0]
+ val := v.Args[1]
+ mem := v.Args[2]
+ v.reset(Op386MOVLstore)
+ v.AddArg(ptr)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (Store [2] ptr val mem)
+ // cond:
+ // result: (MOVWstore ptr val mem)
+ for {
+ if v.AuxInt != 2 {
+ break
+ }
+ ptr := v.Args[0]
+ val := v.Args[1]
+ mem := v.Args[2]
+ v.reset(Op386MOVWstore)
+ v.AddArg(ptr)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (Store [1] ptr val mem)
+ // cond:
+ // result: (MOVBstore ptr val mem)
+ for {
+ if v.AuxInt != 1 {
+ break
+ }
+ ptr := v.Args[0]
+ val := v.Args[1]
+ mem := v.Args[2]
+ v.reset(Op386MOVBstore)
+ v.AddArg(ptr)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValue386_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(Op386SUBL)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValue386_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(Op386SUBL)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValue386_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(Op386SUBSS)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValue386_OpSub32carry(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Sub32carry x y)
+ // cond:
+ // result: (SUBLcarry x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(Op386SUBLcarry)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValue386_OpSub32withcarry(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Sub32withcarry x y c)
+ // cond:
+ // result: (SBBL x y c)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ c := v.Args[2]
+ v.reset(Op386SBBL)
+ v.AddArg(x)
+ v.AddArg(y)
+ v.AddArg(c)
+ return true
+ }
+}
+func rewriteValue386_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(Op386SUBSD)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValue386_OpSub8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Sub8 x y)
+ // cond:
+ // result: (SUBL x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(Op386SUBL)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValue386_OpSubPtr(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SubPtr x y)
+ // cond:
+ // result: (SUBL x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(Op386SUBL)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValue386_OpTrunc16to8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Trunc16to8 x)
+ // cond:
+ // result: x
+ for {
+ x := v.Args[0]
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValue386_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 rewriteValue386_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 rewriteValue386_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(Op386XORL)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValue386_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(Op386XORL)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValue386_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(Op386XORL)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValue386_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) {
+ 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) {
+ break
+ }
+ v.reset(Op386MOVBstoreconst)
+ 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) {
+ break
+ }
+ v.reset(Op386MOVWstoreconst)
+ 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) {
+ break
+ }
+ v.reset(Op386MOVLstoreconst)
+ 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) {
+ break
+ }
+ v.reset(Op386MOVBstoreconst)
+ v.AuxInt = makeValAndOff(0, 2)
+ v.AddArg(destptr)
+ v0 := b.NewValue0(v.Line, Op386MOVWstoreconst, 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) {
+ break
+ }
+ v.reset(Op386MOVBstoreconst)
+ v.AuxInt = makeValAndOff(0, 4)
+ v.AddArg(destptr)
+ v0 := b.NewValue0(v.Line, Op386MOVLstoreconst, 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) {
+ break
+ }
+ v.reset(Op386MOVWstoreconst)
+ v.AuxInt = makeValAndOff(0, 4)
+ v.AddArg(destptr)
+ v0 := b.NewValue0(v.Line, Op386MOVLstoreconst, 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) {
+ break
+ }
+ v.reset(Op386MOVLstoreconst)
+ v.AuxInt = makeValAndOff(0, 3)
+ v.AddArg(destptr)
+ v0 := b.NewValue0(v.Line, Op386MOVLstoreconst, TypeMem)
+ v0.AuxInt = 0
+ v0.AddArg(destptr)
+ v0.AddArg(mem)
+ v.AddArg(v0)
+ 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))
+ for {
+ s := v.AuxInt
+ destptr := v.Args[0]
+ mem := v.Args[1]
+ if !(SizeAndAlign(s).Size()%4 != 0 && SizeAndAlign(s).Size() > 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
+ v0.AddArg(destptr)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, Op386MOVLstoreconst, 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
+ // 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) {
+ break
+ }
+ v.reset(Op386MOVLstoreconst)
+ v.AuxInt = makeValAndOff(0, 4)
+ v.AddArg(destptr)
+ v0 := b.NewValue0(v.Line, Op386MOVLstoreconst, 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
+ // 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) {
+ break
+ }
+ v.reset(Op386MOVLstoreconst)
+ v.AuxInt = makeValAndOff(0, 8)
+ v.AddArg(destptr)
+ v0 := b.NewValue0(v.Line, Op386MOVLstoreconst, TypeMem)
+ v0.AuxInt = makeValAndOff(0, 4)
+ v0.AddArg(destptr)
+ v1 := b.NewValue0(v.Line, Op386MOVLstoreconst, TypeMem)
+ v1.AuxInt = 0
+ v1.AddArg(destptr)
+ v1.AddArg(mem)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (Zero [s] destptr mem)
+ // cond: SizeAndAlign(s).Size() == 16
+ // 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) {
+ break
+ }
+ v.reset(Op386MOVLstoreconst)
+ v.AuxInt = makeValAndOff(0, 12)
+ v.AddArg(destptr)
+ v0 := b.NewValue0(v.Line, Op386MOVLstoreconst, TypeMem)
+ v0.AuxInt = makeValAndOff(0, 8)
+ v0.AddArg(destptr)
+ v1 := b.NewValue0(v.Line, Op386MOVLstoreconst, TypeMem)
+ v1.AuxInt = makeValAndOff(0, 4)
+ v1.AddArg(destptr)
+ v2 := b.NewValue0(v.Line, Op386MOVLstoreconst, 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() > 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)
+ for {
+ s := v.AuxInt
+ 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) {
+ break
+ }
+ v.reset(Op386DUFFZERO)
+ v.AuxInt = 1 * (128 - SizeAndAlign(s).Size()/4)
+ v.AddArg(destptr)
+ v0 := b.NewValue0(v.Line, Op386MOVLconst, config.fe.TypeUInt32())
+ 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)
+ for {
+ s := v.AuxInt
+ 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) {
+ break
+ }
+ v.reset(Op386REPSTOSL)
+ v.AddArg(destptr)
+ v0 := b.NewValue0(v.Line, Op386MOVLconst, config.fe.TypeUInt32())
+ v0.AuxInt = SizeAndAlign(s).Size() / 4
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, Op386MOVLconst, config.fe.TypeUInt32())
+ v1.AuxInt = 0
+ v.AddArg(v1)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValue386_OpZeroExt16to32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ZeroExt16to32 x)
+ // cond:
+ // result: (MOVWLZX x)
+ for {
+ x := v.Args[0]
+ v.reset(Op386MOVWLZX)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValue386_OpZeroExt8to16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ZeroExt8to16 x)
+ // cond:
+ // result: (MOVBLZX x)
+ for {
+ x := v.Args[0]
+ v.reset(Op386MOVBLZX)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValue386_OpZeroExt8to32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ZeroExt8to32 x)
+ // cond:
+ // result: (MOVBLZX x)
+ for {
+ x := v.Args[0]
+ v.reset(Op386MOVBLZX)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValue386_OpZeromask(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Zeromask <t> x)
+ // cond:
+ // result: (XORLconst [-1] (SBBLcarrymask <t> (CMPLconst x [1])))
+ for {
+ t := v.Type
+ x := v.Args[0]
+ v.reset(Op386XORLconst)
+ v.AuxInt = -1
+ v0 := b.NewValue0(v.Line, Op386SBBLcarrymask, t)
+ v1 := b.NewValue0(v.Line, Op386CMPLconst, TypeFlags)
+ v1.AuxInt = 1
+ v1.AddArg(x)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteBlock386(b *Block, config *Config) bool {
+ switch b.Kind {
+ case Block386EQ:
+ // match: (EQ (InvertFlags cmp) yes no)
+ // cond:
+ // result: (EQ cmp yes no)
+ for {
+ v := b.Control
+ if v.Op != Op386InvertFlags {
+ 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)
+ // cond:
+ // result: (First nil yes no)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil no yes)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil no yes)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil no yes)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil no yes)
+ for {
+ v := b.Control
+ 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:
+ // match: (GE (InvertFlags cmp) yes no)
+ // cond:
+ // result: (LE cmp yes no)
+ for {
+ v := b.Control
+ if v.Op != Op386InvertFlags {
+ 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)
+ // cond:
+ // result: (First nil yes no)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil no yes)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil no yes)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil yes no)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil yes no)
+ for {
+ v := b.Control
+ 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:
+ // match: (GT (InvertFlags cmp) yes no)
+ // cond:
+ // result: (LT cmp yes no)
+ for {
+ v := b.Control
+ if v.Op != Op386InvertFlags {
+ 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)
+ // cond:
+ // result: (First nil no yes)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil no yes)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil no yes)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil yes no)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil yes no)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (LT cmp yes no)
+ for {
+ v := b.Control
+ if v.Op != Op386SETL {
+ 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)
+ // cond:
+ // result: (LE cmp yes no)
+ for {
+ v := b.Control
+ if v.Op != Op386SETLE {
+ 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)
+ // cond:
+ // result: (GT cmp yes no)
+ for {
+ v := b.Control
+ if v.Op != Op386SETG {
+ 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)
+ // cond:
+ // result: (GE cmp yes no)
+ for {
+ v := b.Control
+ if v.Op != Op386SETGE {
+ 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)
+ // cond:
+ // result: (EQ cmp yes no)
+ for {
+ v := b.Control
+ if v.Op != Op386SETEQ {
+ 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)
+ // cond:
+ // result: (NE cmp yes no)
+ for {
+ v := b.Control
+ 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
+ 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]
+ yes := b.Succs[0]
+ no := b.Succs[1]
+ b.Kind = Block386ULT
+ 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 != Op386SETBE {
+ break
+ }
+ cmp := v.Args[0]
+ yes := b.Succs[0]
+ no := b.Succs[1]
+ b.Kind = Block386ULE
+ 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 != Op386SETA {
+ break
+ }
+ cmp := v.Args[0]
+ yes := b.Succs[0]
+ no := b.Succs[1]
+ b.Kind = Block386UGT
+ b.SetControl(cmp)
+ _ = yes
+ _ = no
+ return true
+ }
+ // match: (If (SETAE cmp) yes no)
+ // cond:
+ // result: (UGE cmp yes no)
+ for {
+ v := b.Control
+ if v.Op != Op386SETAE {
+ break
+ }
+ cmp := v.Args[0]
+ yes := b.Succs[0]
+ no := b.Succs[1]
+ b.Kind = Block386UGE
+ 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 != Op386SETGF {
+ break
+ }
+ cmp := v.Args[0]
+ yes := b.Succs[0]
+ no := b.Succs[1]
+ b.Kind = Block386UGT
+ 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 != Op386SETGEF {
+ break
+ }
+ cmp := v.Args[0]
+ yes := b.Succs[0]
+ no := b.Succs[1]
+ b.Kind = Block386UGE
+ b.SetControl(cmp)
+ _ = yes
+ _ = no
+ return true
+ }
+ // match: (If (SETEQF cmp) yes no)
+ // cond:
+ // result: (EQF cmp yes no)
+ for {
+ v := b.Control
+ if v.Op != Op386SETEQF {
+ break
+ }
+ cmp := v.Args[0]
+ yes := b.Succs[0]
+ no := b.Succs[1]
+ b.Kind = Block386EQF
+ b.SetControl(cmp)
+ _ = yes
+ _ = no
+ return true
+ }
+ // match: (If (SETNEF cmp) yes no)
+ // cond:
+ // result: (NEF cmp yes no)
+ for {
+ v := b.Control
+ if v.Op != Op386SETNEF {
+ break
+ }
+ cmp := v.Args[0]
+ yes := b.Succs[0]
+ no := b.Succs[1]
+ b.Kind = Block386NEF
+ b.SetControl(cmp)
+ _ = yes
+ _ = no
+ return true
+ }
+ // match: (If cond yes no)
+ // cond:
+ // result: (NE (TESTB cond cond) 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
+ 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]
+ yes := b.Succs[0]
+ no := b.Succs[1]
+ b.Kind = Block386GE
+ b.SetControl(cmp)
+ _ = yes
+ _ = no
+ return true
+ }
+ // match: (LE (FlagEQ) yes no)
+ // cond:
+ // result: (First nil yes no)
+ for {
+ v := b.Control
+ if v.Op != Op386FlagEQ {
+ 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 != Op386FlagLT_ULT {
+ break
+ }
+ yes := b.Succs[0]
+ no := b.Succs[1]
+ b.Kind = BlockFirst
+ b.SetControl(nil)
+ _ = yes
+ _ = no
+ return true
+ }
+ // match: (LE (FlagLT_UGT) yes no)
+ // cond:
+ // result: (First nil yes no)
+ for {
+ v := b.Control
+ if v.Op != Op386FlagLT_UGT {
+ break
+ }
+ yes := b.Succs[0]
+ no := b.Succs[1]
+ b.Kind = BlockFirst
+ b.SetControl(nil)
+ _ = yes
+ _ = no
+ return true
+ }
+ // match: (LE (FlagGT_ULT) yes no)
+ // cond:
+ // result: (First nil no yes)
+ for {
+ v := b.Control
+ if v.Op != Op386FlagGT_ULT {
+ break
+ }
+ yes := b.Succs[0]
+ no := b.Succs[1]
+ b.Kind = BlockFirst
+ b.SetControl(nil)
+ b.swapSuccessors()
+ _ = no
+ _ = yes
+ return true
+ }
+ // match: (LE (FlagGT_UGT) yes no)
+ // cond:
+ // result: (First nil no yes)
+ for {
+ v := b.Control
+ if v.Op != Op386FlagGT_UGT {
+ break
+ }
+ yes := b.Succs[0]
+ no := b.Succs[1]
+ b.Kind = BlockFirst
+ b.SetControl(nil)
+ b.swapSuccessors()
+ _ = no
+ _ = yes
+ return true
+ }
+ case Block386LT:
+ // match: (LT (InvertFlags cmp) yes no)
+ // cond:
+ // result: (GT cmp yes no)
+ for {
+ v := b.Control
+ if v.Op != Op386InvertFlags {
+ break
+ }
+ cmp := v.Args[0]
+ yes := b.Succs[0]
+ no := b.Succs[1]
+ b.Kind = Block386GT
+ b.SetControl(cmp)
+ _ = yes
+ _ = no
+ return true
+ }
+ // match: (LT (FlagEQ) yes no)
+ // cond:
+ // result: (First nil no yes)
+ for {
+ v := b.Control
+ if v.Op != Op386FlagEQ {
+ 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 {
+ break
+ }
+ yes := b.Succs[0]
+ no := b.Succs[1]
+ b.Kind = BlockFirst
+ b.SetControl(nil)
+ _ = yes
+ _ = no
+ return true
+ }
+ // match: (LT (FlagLT_UGT) yes no)
+ // cond:
+ // result: (First nil yes no)
+ for {
+ v := b.Control
+ if v.Op != Op386FlagLT_UGT {
+ break
+ }
+ yes := b.Succs[0]
+ no := b.Succs[1]
+ b.Kind = BlockFirst
+ b.SetControl(nil)
+ _ = yes
+ _ = no
+ return true
+ }
+ // match: (LT (FlagGT_ULT) yes no)
+ // cond:
+ // result: (First nil no yes)
+ for {
+ v := b.Control
+ if v.Op != Op386FlagGT_ULT {
+ break
+ }
+ yes := b.Succs[0]
+ no := b.Succs[1]
+ b.Kind = BlockFirst
+ b.SetControl(nil)
+ b.swapSuccessors()
+ _ = no
+ _ = yes
+ return true
+ }
+ // match: (LT (FlagGT_UGT) yes no)
+ // cond:
+ // result: (First nil no yes)
+ for {
+ v := b.Control
+ if v.Op != Op386FlagGT_UGT {
+ break
+ }
+ yes := b.Succs[0]
+ no := b.Succs[1]
+ b.Kind = BlockFirst
+ b.SetControl(nil)
+ b.swapSuccessors()
+ _ = no
+ _ = yes
+ return true
+ }
+ case Block386NE:
+ // match: (NE (TESTB (SETL cmp) (SETL cmp)) yes no)
+ // cond:
+ // result: (LT cmp yes no)
+ for {
+ v := b.Control
+ if v.Op != Op386TESTB {
+ break
+ }
+ 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
+ }
+ yes := b.Succs[0]
+ no := b.Succs[1]
+ b.Kind = Block386LT
+ b.SetControl(cmp)
+ _ = yes
+ _ = no
+ return true
+ }
+ // match: (NE (TESTB (SETLE cmp) (SETLE cmp)) yes no)
+ // cond:
+ // result: (LE cmp yes no)
+ for {
+ v := b.Control
+ if v.Op != Op386TESTB {
+ break
+ }
+ 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
+ }
+ yes := b.Succs[0]
+ no := b.Succs[1]
+ b.Kind = Block386LE
+ b.SetControl(cmp)
+ _ = yes
+ _ = no
+ return true
+ }
+ // match: (NE (TESTB (SETG cmp) (SETG cmp)) yes no)
+ // cond:
+ // result: (GT cmp yes no)
+ for {
+ v := b.Control
+ if v.Op != Op386TESTB {
+ break
+ }
+ 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
+ }
+ yes := b.Succs[0]
+ no := b.Succs[1]
+ b.Kind = Block386GT
+ b.SetControl(cmp)
+ _ = yes
+ _ = no
+ return true
+ }
+ // match: (NE (TESTB (SETGE cmp) (SETGE cmp)) yes no)
+ // cond:
+ // result: (GE cmp yes no)
+ for {
+ v := b.Control
+ if v.Op != Op386TESTB {
+ break
+ }
+ 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 = Block386GE
+ b.SetControl(cmp)
+ _ = yes
+ _ = no
+ return true
+ }
+ // match: (NE (TESTB (SETEQ cmp) (SETEQ cmp)) yes no)
+ // cond:
+ // result: (EQ cmp yes no)
+ for {
+ v := b.Control
+ if v.Op != Op386TESTB {
+ break
+ }
+ 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
+ }
+ yes := b.Succs[0]
+ no := b.Succs[1]
+ b.Kind = Block386EQ
+ b.SetControl(cmp)
+ _ = yes
+ _ = no
+ return true
+ }
+ // match: (NE (TESTB (SETNE cmp) (SETNE cmp)) yes no)
+ // cond:
+ // result: (NE cmp yes no)
+ for {
+ v := b.Control
+ if v.Op != Op386TESTB {
+ break
+ }
+ 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
+ }
+ yes := b.Succs[0]
+ no := b.Succs[1]
+ b.Kind = Block386NE
+ b.SetControl(cmp)
+ _ = yes
+ _ = no
+ return true
+ }
+ // match: (NE (TESTB (SETB cmp) (SETB cmp)) yes no)
+ // cond:
+ // result: (ULT cmp yes no)
+ for {
+ v := b.Control
+ if v.Op != Op386TESTB {
+ break
+ }
+ 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
+ }
+ yes := b.Succs[0]
+ no := b.Succs[1]
+ b.Kind = Block386ULT
+ b.SetControl(cmp)
+ _ = yes
+ _ = no
+ return true
+ }
+ // match: (NE (TESTB (SETBE cmp) (SETBE cmp)) yes no)
+ // cond:
+ // result: (ULE cmp yes no)
+ for {
+ v := b.Control
+ if v.Op != Op386TESTB {
+ break
+ }
+ v_0 := v.Args[0]
+ if v_0.Op != Op386SETBE {
+ break
+ }
+ cmp := v_0.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != Op386SETBE {
+ break
+ }
+ if cmp != v_1.Args[0] {
+ break
+ }
+ yes := b.Succs[0]
+ no := b.Succs[1]
+ b.Kind = Block386ULE
+ b.SetControl(cmp)
+ _ = yes
+ _ = no
+ return true
+ }
+ // match: (NE (TESTB (SETA cmp) (SETA cmp)) yes no)
+ // cond:
+ // result: (UGT cmp yes no)
+ for {
+ v := b.Control
+ if v.Op != Op386TESTB {
+ break
+ }
+ v_0 := v.Args[0]
+ if v_0.Op != Op386SETA {
+ break
+ }
+ cmp := v_0.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != Op386SETA {
+ 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)
+ // cond:
+ // result: (UGE cmp yes no)
+ for {
+ v := b.Control
+ if v.Op != Op386TESTB {
+ break
+ }
+ v_0 := v.Args[0]
+ if v_0.Op != Op386SETAE {
+ break
+ }
+ cmp := v_0.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != Op386SETAE {
+ 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)
+ // cond:
+ // result: (UGT cmp yes no)
+ for {
+ v := b.Control
+ if v.Op != Op386TESTB {
+ break
+ }
+ v_0 := v.Args[0]
+ if v_0.Op != Op386SETGF {
+ break
+ }
+ cmp := v_0.Args[0]
+ v_1 := v.Args[1]
+ 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 (SETGEF cmp) (SETGEF cmp)) yes no)
+ // cond:
+ // result: (UGE cmp yes no)
+ for {
+ v := b.Control
+ if v.Op != Op386TESTB {
+ break
+ }
+ v_0 := v.Args[0]
+ if v_0.Op != Op386SETGEF {
+ break
+ }
+ cmp := v_0.Args[0]
+ v_1 := v.Args[1]
+ 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 (SETEQF cmp) (SETEQF cmp)) yes no)
+ // cond:
+ // result: (EQF cmp yes no)
+ for {
+ v := b.Control
+ if v.Op != Op386TESTB {
+ break
+ }
+ v_0 := v.Args[0]
+ if v_0.Op != Op386SETEQF {
+ break
+ }
+ cmp := v_0.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != Op386SETEQF {
+ break
+ }
+ 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)
+ // cond:
+ // result: (NEF cmp yes no)
+ for {
+ v := b.Control
+ if v.Op != Op386TESTB {
+ break
+ }
+ 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
+ }
+ yes := b.Succs[0]
+ no := b.Succs[1]
+ b.Kind = Block386NEF
+ b.SetControl(cmp)
+ _ = yes
+ _ = no
+ return true
+ }
+ // match: (NE (InvertFlags cmp) yes no)
+ // cond:
+ // result: (NE cmp yes no)
+ for {
+ v := b.Control
+ if v.Op != Op386InvertFlags {
+ 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)
+ // cond:
+ // result: (First nil no yes)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil yes no)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil yes no)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil yes no)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil yes no)
+ for {
+ v := b.Control
+ 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:
+ // match: (UGE (InvertFlags cmp) yes no)
+ // cond:
+ // result: (ULE cmp yes no)
+ for {
+ v := b.Control
+ if v.Op != Op386InvertFlags {
+ 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)
+ // cond:
+ // result: (First nil yes no)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil no yes)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil yes no)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil no yes)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil yes no)
+ for {
+ v := b.Control
+ 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:
+ // match: (UGT (InvertFlags cmp) yes no)
+ // cond:
+ // result: (ULT cmp yes no)
+ for {
+ v := b.Control
+ if v.Op != Op386InvertFlags {
+ 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)
+ // cond:
+ // result: (First nil no yes)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil no yes)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil yes no)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil no yes)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil yes no)
+ for {
+ v := b.Control
+ 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:
+ // match: (ULE (InvertFlags cmp) yes no)
+ // cond:
+ // result: (UGE cmp yes no)
+ for {
+ v := b.Control
+ if v.Op != Op386InvertFlags {
+ 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)
+ // cond:
+ // result: (First nil yes no)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil yes no)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil no yes)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil yes no)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil no yes)
+ for {
+ v := b.Control
+ 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:
+ // match: (ULT (InvertFlags cmp) yes no)
+ // cond:
+ // result: (UGT cmp yes no)
+ for {
+ v := b.Control
+ if v.Op != Op386InvertFlags {
+ 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)
+ // cond:
+ // result: (First nil no yes)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil yes no)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil no yes)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil yes no)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil no yes)
+ for {
+ v := b.Control
+ 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
+ }
+ }
+ return false
+}
diff --git a/src/cmd/compile/internal/ssa/rewriteAMD64.go b/src/cmd/compile/internal/ssa/rewriteAMD64.go
index a2b9e15..1257ec6 100644
--- a/src/cmd/compile/internal/ssa/rewriteAMD64.go
+++ b/src/cmd/compile/internal/ssa/rewriteAMD64.go
@@ -24,6 +24,262 @@ func rewriteValueAMD64(v *Value, config *Config) bool {
return rewriteValueAMD64_OpAMD64ANDQ(v, config)
case OpAMD64ANDQconst:
return rewriteValueAMD64_OpAMD64ANDQconst(v, config)
+ case OpAMD64CMPB:
+ return rewriteValueAMD64_OpAMD64CMPB(v, config)
+ case OpAMD64CMPBconst:
+ return rewriteValueAMD64_OpAMD64CMPBconst(v, config)
+ case OpAMD64CMPL:
+ return rewriteValueAMD64_OpAMD64CMPL(v, config)
+ case OpAMD64CMPLconst:
+ return rewriteValueAMD64_OpAMD64CMPLconst(v, config)
+ case OpAMD64CMPQ:
+ return rewriteValueAMD64_OpAMD64CMPQ(v, config)
+ case OpAMD64CMPQconst:
+ return rewriteValueAMD64_OpAMD64CMPQconst(v, config)
+ case OpAMD64CMPW:
+ return rewriteValueAMD64_OpAMD64CMPW(v, config)
+ case OpAMD64CMPWconst:
+ return rewriteValueAMD64_OpAMD64CMPWconst(v, config)
+ case OpAMD64CMPXCHGLlock:
+ return rewriteValueAMD64_OpAMD64CMPXCHGLlock(v, config)
+ case OpAMD64CMPXCHGQlock:
+ return rewriteValueAMD64_OpAMD64CMPXCHGQlock(v, config)
+ case OpAMD64LEAL:
+ return rewriteValueAMD64_OpAMD64LEAL(v, config)
+ case OpAMD64LEAQ:
+ return rewriteValueAMD64_OpAMD64LEAQ(v, config)
+ case OpAMD64LEAQ1:
+ return rewriteValueAMD64_OpAMD64LEAQ1(v, config)
+ case OpAMD64LEAQ2:
+ return rewriteValueAMD64_OpAMD64LEAQ2(v, config)
+ case OpAMD64LEAQ4:
+ return rewriteValueAMD64_OpAMD64LEAQ4(v, config)
+ case OpAMD64LEAQ8:
+ return rewriteValueAMD64_OpAMD64LEAQ8(v, config)
+ case OpAMD64MOVBQSX:
+ return rewriteValueAMD64_OpAMD64MOVBQSX(v, config)
+ case OpAMD64MOVBQSXload:
+ return rewriteValueAMD64_OpAMD64MOVBQSXload(v, config)
+ case OpAMD64MOVBQZX:
+ return rewriteValueAMD64_OpAMD64MOVBQZX(v, config)
+ case OpAMD64MOVBload:
+ return rewriteValueAMD64_OpAMD64MOVBload(v, config)
+ case OpAMD64MOVBloadidx1:
+ return rewriteValueAMD64_OpAMD64MOVBloadidx1(v, config)
+ case OpAMD64MOVBstore:
+ return rewriteValueAMD64_OpAMD64MOVBstore(v, config)
+ case OpAMD64MOVBstoreconst:
+ return rewriteValueAMD64_OpAMD64MOVBstoreconst(v, config)
+ case OpAMD64MOVBstoreconstidx1:
+ return rewriteValueAMD64_OpAMD64MOVBstoreconstidx1(v, config)
+ case OpAMD64MOVBstoreidx1:
+ return rewriteValueAMD64_OpAMD64MOVBstoreidx1(v, config)
+ case OpAMD64MOVLQSX:
+ return rewriteValueAMD64_OpAMD64MOVLQSX(v, config)
+ case OpAMD64MOVLQSXload:
+ return rewriteValueAMD64_OpAMD64MOVLQSXload(v, config)
+ case OpAMD64MOVLQZX:
+ return rewriteValueAMD64_OpAMD64MOVLQZX(v, config)
+ case OpAMD64MOVLatomicload:
+ return rewriteValueAMD64_OpAMD64MOVLatomicload(v, config)
+ case OpAMD64MOVLload:
+ return rewriteValueAMD64_OpAMD64MOVLload(v, config)
+ case OpAMD64MOVLloadidx1:
+ return rewriteValueAMD64_OpAMD64MOVLloadidx1(v, config)
+ case OpAMD64MOVLloadidx4:
+ return rewriteValueAMD64_OpAMD64MOVLloadidx4(v, config)
+ case OpAMD64MOVLstore:
+ return rewriteValueAMD64_OpAMD64MOVLstore(v, config)
+ case OpAMD64MOVLstoreconst:
+ return rewriteValueAMD64_OpAMD64MOVLstoreconst(v, config)
+ case OpAMD64MOVLstoreconstidx1:
+ return rewriteValueAMD64_OpAMD64MOVLstoreconstidx1(v, config)
+ case OpAMD64MOVLstoreconstidx4:
+ return rewriteValueAMD64_OpAMD64MOVLstoreconstidx4(v, config)
+ case OpAMD64MOVLstoreidx1:
+ return rewriteValueAMD64_OpAMD64MOVLstoreidx1(v, config)
+ case OpAMD64MOVLstoreidx4:
+ return rewriteValueAMD64_OpAMD64MOVLstoreidx4(v, config)
+ case OpAMD64MOVOload:
+ return rewriteValueAMD64_OpAMD64MOVOload(v, config)
+ case OpAMD64MOVOstore:
+ return rewriteValueAMD64_OpAMD64MOVOstore(v, config)
+ case OpAMD64MOVQatomicload:
+ return rewriteValueAMD64_OpAMD64MOVQatomicload(v, config)
+ case OpAMD64MOVQload:
+ return rewriteValueAMD64_OpAMD64MOVQload(v, config)
+ case OpAMD64MOVQloadidx1:
+ return rewriteValueAMD64_OpAMD64MOVQloadidx1(v, config)
+ case OpAMD64MOVQloadidx8:
+ return rewriteValueAMD64_OpAMD64MOVQloadidx8(v, config)
+ case OpAMD64MOVQstore:
+ return rewriteValueAMD64_OpAMD64MOVQstore(v, config)
+ case OpAMD64MOVQstoreconst:
+ return rewriteValueAMD64_OpAMD64MOVQstoreconst(v, config)
+ case OpAMD64MOVQstoreconstidx1:
+ return rewriteValueAMD64_OpAMD64MOVQstoreconstidx1(v, config)
+ case OpAMD64MOVQstoreconstidx8:
+ return rewriteValueAMD64_OpAMD64MOVQstoreconstidx8(v, config)
+ case OpAMD64MOVQstoreidx1:
+ return rewriteValueAMD64_OpAMD64MOVQstoreidx1(v, config)
+ case OpAMD64MOVQstoreidx8:
+ return rewriteValueAMD64_OpAMD64MOVQstoreidx8(v, config)
+ case OpAMD64MOVSDload:
+ return rewriteValueAMD64_OpAMD64MOVSDload(v, config)
+ case OpAMD64MOVSDloadidx1:
+ return rewriteValueAMD64_OpAMD64MOVSDloadidx1(v, config)
+ case OpAMD64MOVSDloadidx8:
+ return rewriteValueAMD64_OpAMD64MOVSDloadidx8(v, config)
+ case OpAMD64MOVSDstore:
+ return rewriteValueAMD64_OpAMD64MOVSDstore(v, config)
+ case OpAMD64MOVSDstoreidx1:
+ return rewriteValueAMD64_OpAMD64MOVSDstoreidx1(v, config)
+ case OpAMD64MOVSDstoreidx8:
+ return rewriteValueAMD64_OpAMD64MOVSDstoreidx8(v, config)
+ case OpAMD64MOVSSload:
+ return rewriteValueAMD64_OpAMD64MOVSSload(v, config)
+ case OpAMD64MOVSSloadidx1:
+ return rewriteValueAMD64_OpAMD64MOVSSloadidx1(v, config)
+ case OpAMD64MOVSSloadidx4:
+ return rewriteValueAMD64_OpAMD64MOVSSloadidx4(v, config)
+ case OpAMD64MOVSSstore:
+ return rewriteValueAMD64_OpAMD64MOVSSstore(v, config)
+ case OpAMD64MOVSSstoreidx1:
+ return rewriteValueAMD64_OpAMD64MOVSSstoreidx1(v, config)
+ case OpAMD64MOVSSstoreidx4:
+ return rewriteValueAMD64_OpAMD64MOVSSstoreidx4(v, config)
+ case OpAMD64MOVWQSX:
+ return rewriteValueAMD64_OpAMD64MOVWQSX(v, config)
+ case OpAMD64MOVWQSXload:
+ return rewriteValueAMD64_OpAMD64MOVWQSXload(v, config)
+ case OpAMD64MOVWQZX:
+ return rewriteValueAMD64_OpAMD64MOVWQZX(v, config)
+ case OpAMD64MOVWload:
+ return rewriteValueAMD64_OpAMD64MOVWload(v, config)
+ case OpAMD64MOVWloadidx1:
+ return rewriteValueAMD64_OpAMD64MOVWloadidx1(v, config)
+ case OpAMD64MOVWloadidx2:
+ return rewriteValueAMD64_OpAMD64MOVWloadidx2(v, config)
+ case OpAMD64MOVWstore:
+ return rewriteValueAMD64_OpAMD64MOVWstore(v, config)
+ case OpAMD64MOVWstoreconst:
+ return rewriteValueAMD64_OpAMD64MOVWstoreconst(v, config)
+ case OpAMD64MOVWstoreconstidx1:
+ return rewriteValueAMD64_OpAMD64MOVWstoreconstidx1(v, config)
+ case OpAMD64MOVWstoreconstidx2:
+ return rewriteValueAMD64_OpAMD64MOVWstoreconstidx2(v, config)
+ case OpAMD64MOVWstoreidx1:
+ return rewriteValueAMD64_OpAMD64MOVWstoreidx1(v, config)
+ case OpAMD64MOVWstoreidx2:
+ return rewriteValueAMD64_OpAMD64MOVWstoreidx2(v, config)
+ case OpAMD64MULL:
+ return rewriteValueAMD64_OpAMD64MULL(v, config)
+ case OpAMD64MULLconst:
+ return rewriteValueAMD64_OpAMD64MULLconst(v, config)
+ case OpAMD64MULQ:
+ return rewriteValueAMD64_OpAMD64MULQ(v, config)
+ case OpAMD64MULQconst:
+ return rewriteValueAMD64_OpAMD64MULQconst(v, config)
+ case OpAMD64NEGL:
+ return rewriteValueAMD64_OpAMD64NEGL(v, config)
+ case OpAMD64NEGQ:
+ return rewriteValueAMD64_OpAMD64NEGQ(v, config)
+ case OpAMD64NOTL:
+ return rewriteValueAMD64_OpAMD64NOTL(v, config)
+ case OpAMD64NOTQ:
+ return rewriteValueAMD64_OpAMD64NOTQ(v, config)
+ case OpAMD64ORL:
+ return rewriteValueAMD64_OpAMD64ORL(v, config)
+ case OpAMD64ORLconst:
+ return rewriteValueAMD64_OpAMD64ORLconst(v, config)
+ case OpAMD64ORQ:
+ return rewriteValueAMD64_OpAMD64ORQ(v, config)
+ case OpAMD64ORQconst:
+ return rewriteValueAMD64_OpAMD64ORQconst(v, config)
+ case OpAMD64ROLBconst:
+ return rewriteValueAMD64_OpAMD64ROLBconst(v, config)
+ case OpAMD64ROLLconst:
+ return rewriteValueAMD64_OpAMD64ROLLconst(v, config)
+ case OpAMD64ROLQconst:
+ return rewriteValueAMD64_OpAMD64ROLQconst(v, config)
+ case OpAMD64ROLWconst:
+ return rewriteValueAMD64_OpAMD64ROLWconst(v, config)
+ case OpAMD64SARB:
+ return rewriteValueAMD64_OpAMD64SARB(v, config)
+ case OpAMD64SARBconst:
+ return rewriteValueAMD64_OpAMD64SARBconst(v, config)
+ case OpAMD64SARL:
+ return rewriteValueAMD64_OpAMD64SARL(v, config)
+ case OpAMD64SARLconst:
+ return rewriteValueAMD64_OpAMD64SARLconst(v, config)
+ case OpAMD64SARQ:
+ return rewriteValueAMD64_OpAMD64SARQ(v, config)
+ case OpAMD64SARQconst:
+ return rewriteValueAMD64_OpAMD64SARQconst(v, config)
+ case OpAMD64SARW:
+ return rewriteValueAMD64_OpAMD64SARW(v, config)
+ case OpAMD64SARWconst:
+ return rewriteValueAMD64_OpAMD64SARWconst(v, config)
+ case OpAMD64SBBLcarrymask:
+ return rewriteValueAMD64_OpAMD64SBBLcarrymask(v, config)
+ case OpAMD64SBBQcarrymask:
+ return rewriteValueAMD64_OpAMD64SBBQcarrymask(v, config)
+ case OpAMD64SETA:
+ return rewriteValueAMD64_OpAMD64SETA(v, config)
+ case OpAMD64SETAE:
+ return rewriteValueAMD64_OpAMD64SETAE(v, config)
+ case OpAMD64SETB:
+ return rewriteValueAMD64_OpAMD64SETB(v, config)
+ case OpAMD64SETBE:
+ return rewriteValueAMD64_OpAMD64SETBE(v, config)
+ case OpAMD64SETEQ:
+ return rewriteValueAMD64_OpAMD64SETEQ(v, config)
+ case OpAMD64SETG:
+ return rewriteValueAMD64_OpAMD64SETG(v, config)
+ case OpAMD64SETGE:
+ return rewriteValueAMD64_OpAMD64SETGE(v, config)
+ case OpAMD64SETL:
+ return rewriteValueAMD64_OpAMD64SETL(v, config)
+ case OpAMD64SETLE:
+ return rewriteValueAMD64_OpAMD64SETLE(v, config)
+ case OpAMD64SETNE:
+ return rewriteValueAMD64_OpAMD64SETNE(v, config)
+ case OpAMD64SHLL:
+ return rewriteValueAMD64_OpAMD64SHLL(v, config)
+ case OpAMD64SHLQ:
+ return rewriteValueAMD64_OpAMD64SHLQ(v, config)
+ case OpAMD64SHRB:
+ return rewriteValueAMD64_OpAMD64SHRB(v, config)
+ case OpAMD64SHRL:
+ return rewriteValueAMD64_OpAMD64SHRL(v, config)
+ case OpAMD64SHRQ:
+ return rewriteValueAMD64_OpAMD64SHRQ(v, config)
+ case OpAMD64SHRW:
+ return rewriteValueAMD64_OpAMD64SHRW(v, config)
+ case OpAMD64SUBL:
+ return rewriteValueAMD64_OpAMD64SUBL(v, config)
+ case OpAMD64SUBLconst:
+ return rewriteValueAMD64_OpAMD64SUBLconst(v, config)
+ case OpAMD64SUBQ:
+ return rewriteValueAMD64_OpAMD64SUBQ(v, config)
+ case OpAMD64SUBQconst:
+ return rewriteValueAMD64_OpAMD64SUBQconst(v, config)
+ case OpAMD64XADDLlock:
+ return rewriteValueAMD64_OpAMD64XADDLlock(v, config)
+ case OpAMD64XADDQlock:
+ return rewriteValueAMD64_OpAMD64XADDQlock(v, config)
+ case OpAMD64XCHGL:
+ return rewriteValueAMD64_OpAMD64XCHGL(v, config)
+ case OpAMD64XCHGQ:
+ return rewriteValueAMD64_OpAMD64XCHGQ(v, config)
+ case OpAMD64XORL:
+ return rewriteValueAMD64_OpAMD64XORL(v, config)
+ case OpAMD64XORLconst:
+ return rewriteValueAMD64_OpAMD64XORLconst(v, config)
+ case OpAMD64XORQ:
+ return rewriteValueAMD64_OpAMD64XORQ(v, config)
+ case OpAMD64XORQconst:
+ return rewriteValueAMD64_OpAMD64XORQconst(v, config)
case OpAdd16:
return rewriteValueAMD64_OpAdd16(v, config)
case OpAdd32:
@@ -50,34 +306,40 @@ func rewriteValueAMD64(v *Value, config *Config) bool {
return rewriteValueAMD64_OpAnd8(v, config)
case OpAndB:
return rewriteValueAMD64_OpAndB(v, config)
+ case OpAtomicAdd32:
+ return rewriteValueAMD64_OpAtomicAdd32(v, config)
+ case OpAtomicAdd64:
+ return rewriteValueAMD64_OpAtomicAdd64(v, config)
+ case OpAtomicAnd8:
+ return rewriteValueAMD64_OpAtomicAnd8(v, config)
+ case OpAtomicCompareAndSwap32:
+ return rewriteValueAMD64_OpAtomicCompareAndSwap32(v, config)
+ case OpAtomicCompareAndSwap64:
+ return rewriteValueAMD64_OpAtomicCompareAndSwap64(v, config)
+ case OpAtomicExchange32:
+ return rewriteValueAMD64_OpAtomicExchange32(v, config)
+ case OpAtomicExchange64:
+ return rewriteValueAMD64_OpAtomicExchange64(v, config)
+ case OpAtomicLoad32:
+ return rewriteValueAMD64_OpAtomicLoad32(v, config)
+ case OpAtomicLoad64:
+ return rewriteValueAMD64_OpAtomicLoad64(v, config)
+ case OpAtomicLoadPtr:
+ return rewriteValueAMD64_OpAtomicLoadPtr(v, config)
+ case OpAtomicOr8:
+ return rewriteValueAMD64_OpAtomicOr8(v, config)
+ case OpAtomicStore32:
+ return rewriteValueAMD64_OpAtomicStore32(v, config)
+ case OpAtomicStore64:
+ return rewriteValueAMD64_OpAtomicStore64(v, config)
+ case OpAtomicStorePtrNoWB:
+ return rewriteValueAMD64_OpAtomicStorePtrNoWB(v, config)
case OpAvg64u:
return rewriteValueAMD64_OpAvg64u(v, config)
case OpBswap32:
return rewriteValueAMD64_OpBswap32(v, config)
case OpBswap64:
return rewriteValueAMD64_OpBswap64(v, config)
- case OpAMD64CMOVLEQconst:
- return rewriteValueAMD64_OpAMD64CMOVLEQconst(v, config)
- case OpAMD64CMOVQEQconst:
- return rewriteValueAMD64_OpAMD64CMOVQEQconst(v, config)
- case OpAMD64CMOVWEQconst:
- return rewriteValueAMD64_OpAMD64CMOVWEQconst(v, config)
- case OpAMD64CMPB:
- return rewriteValueAMD64_OpAMD64CMPB(v, config)
- case OpAMD64CMPBconst:
- return rewriteValueAMD64_OpAMD64CMPBconst(v, config)
- case OpAMD64CMPL:
- return rewriteValueAMD64_OpAMD64CMPL(v, config)
- case OpAMD64CMPLconst:
- return rewriteValueAMD64_OpAMD64CMPLconst(v, config)
- case OpAMD64CMPQ:
- return rewriteValueAMD64_OpAMD64CMPQ(v, config)
- case OpAMD64CMPQconst:
- return rewriteValueAMD64_OpAMD64CMPQconst(v, config)
- case OpAMD64CMPW:
- return rewriteValueAMD64_OpAMD64CMPW(v, config)
- case OpAMD64CMPWconst:
- return rewriteValueAMD64_OpAMD64CMPWconst(v, config)
case OpClosureCall:
return rewriteValueAMD64_OpClosureCall(v, config)
case OpCom16:
@@ -106,8 +368,6 @@ func rewriteValueAMD64(v *Value, config *Config) bool {
return rewriteValueAMD64_OpConstNil(v, config)
case OpConvert:
return rewriteValueAMD64_OpConvert(v, config)
- case OpCtz16:
- return rewriteValueAMD64_OpCtz16(v, config)
case OpCtz32:
return rewriteValueAMD64_OpCtz32(v, config)
case OpCtz64:
@@ -134,6 +394,8 @@ func rewriteValueAMD64(v *Value, config *Config) bool {
return rewriteValueAMD64_OpCvt64to64F(v, config)
case OpDeferCall:
return rewriteValueAMD64_OpDeferCall(v, config)
+ case OpDiv128u:
+ return rewriteValueAMD64_OpDiv128u(v, config)
case OpDiv16:
return rewriteValueAMD64_OpDiv16(v, config)
case OpDiv16u:
@@ -232,8 +494,8 @@ func rewriteValueAMD64(v *Value, config *Config) bool {
return rewriteValueAMD64_OpHmul8(v, config)
case OpHmul8u:
return rewriteValueAMD64_OpHmul8u(v, config)
- case OpITab:
- return rewriteValueAMD64_OpITab(v, config)
+ case OpInt64Hi:
+ return rewriteValueAMD64_OpInt64Hi(v, config)
case OpInterCall:
return rewriteValueAMD64_OpInterCall(v, config)
case OpIsInBounds:
@@ -242,16 +504,6 @@ func rewriteValueAMD64(v *Value, config *Config) bool {
return rewriteValueAMD64_OpIsNonNil(v, config)
case OpIsSliceInBounds:
return rewriteValueAMD64_OpIsSliceInBounds(v, config)
- case OpAMD64LEAQ:
- return rewriteValueAMD64_OpAMD64LEAQ(v, config)
- case OpAMD64LEAQ1:
- return rewriteValueAMD64_OpAMD64LEAQ1(v, config)
- case OpAMD64LEAQ2:
- return rewriteValueAMD64_OpAMD64LEAQ2(v, config)
- case OpAMD64LEAQ4:
- return rewriteValueAMD64_OpAMD64LEAQ4(v, config)
- case OpAMD64LEAQ8:
- return rewriteValueAMD64_OpAMD64LEAQ8(v, config)
case OpLeq16:
return rewriteValueAMD64_OpLeq16(v, config)
case OpLeq16U:
@@ -334,126 +586,6 @@ func rewriteValueAMD64(v *Value, config *Config) bool {
return rewriteValueAMD64_OpLsh8x64(v, config)
case OpLsh8x8:
return rewriteValueAMD64_OpLsh8x8(v, config)
- case OpAMD64MOVBQSX:
- return rewriteValueAMD64_OpAMD64MOVBQSX(v, config)
- case OpAMD64MOVBQSXload:
- return rewriteValueAMD64_OpAMD64MOVBQSXload(v, config)
- case OpAMD64MOVBQZX:
- return rewriteValueAMD64_OpAMD64MOVBQZX(v, config)
- case OpAMD64MOVBload:
- return rewriteValueAMD64_OpAMD64MOVBload(v, config)
- case OpAMD64MOVBloadidx1:
- return rewriteValueAMD64_OpAMD64MOVBloadidx1(v, config)
- case OpAMD64MOVBstore:
- return rewriteValueAMD64_OpAMD64MOVBstore(v, config)
- case OpAMD64MOVBstoreconst:
- return rewriteValueAMD64_OpAMD64MOVBstoreconst(v, config)
- case OpAMD64MOVBstoreconstidx1:
- return rewriteValueAMD64_OpAMD64MOVBstoreconstidx1(v, config)
- case OpAMD64MOVBstoreidx1:
- return rewriteValueAMD64_OpAMD64MOVBstoreidx1(v, config)
- case OpAMD64MOVLQSX:
- return rewriteValueAMD64_OpAMD64MOVLQSX(v, config)
- case OpAMD64MOVLQSXload:
- return rewriteValueAMD64_OpAMD64MOVLQSXload(v, config)
- case OpAMD64MOVLQZX:
- return rewriteValueAMD64_OpAMD64MOVLQZX(v, config)
- case OpAMD64MOVLload:
- return rewriteValueAMD64_OpAMD64MOVLload(v, config)
- case OpAMD64MOVLloadidx1:
- return rewriteValueAMD64_OpAMD64MOVLloadidx1(v, config)
- case OpAMD64MOVLloadidx4:
- return rewriteValueAMD64_OpAMD64MOVLloadidx4(v, config)
- case OpAMD64MOVLstore:
- return rewriteValueAMD64_OpAMD64MOVLstore(v, config)
- case OpAMD64MOVLstoreconst:
- return rewriteValueAMD64_OpAMD64MOVLstoreconst(v, config)
- case OpAMD64MOVLstoreconstidx1:
- return rewriteValueAMD64_OpAMD64MOVLstoreconstidx1(v, config)
- case OpAMD64MOVLstoreconstidx4:
- return rewriteValueAMD64_OpAMD64MOVLstoreconstidx4(v, config)
- case OpAMD64MOVLstoreidx1:
- return rewriteValueAMD64_OpAMD64MOVLstoreidx1(v, config)
- case OpAMD64MOVLstoreidx4:
- return rewriteValueAMD64_OpAMD64MOVLstoreidx4(v, config)
- case OpAMD64MOVOload:
- return rewriteValueAMD64_OpAMD64MOVOload(v, config)
- case OpAMD64MOVOstore:
- return rewriteValueAMD64_OpAMD64MOVOstore(v, config)
- case OpAMD64MOVQload:
- return rewriteValueAMD64_OpAMD64MOVQload(v, config)
- case OpAMD64MOVQloadidx1:
- return rewriteValueAMD64_OpAMD64MOVQloadidx1(v, config)
- case OpAMD64MOVQloadidx8:
- return rewriteValueAMD64_OpAMD64MOVQloadidx8(v, config)
- case OpAMD64MOVQstore:
- return rewriteValueAMD64_OpAMD64MOVQstore(v, config)
- case OpAMD64MOVQstoreconst:
- return rewriteValueAMD64_OpAMD64MOVQstoreconst(v, config)
- case OpAMD64MOVQstoreconstidx1:
- return rewriteValueAMD64_OpAMD64MOVQstoreconstidx1(v, config)
- case OpAMD64MOVQstoreconstidx8:
- return rewriteValueAMD64_OpAMD64MOVQstoreconstidx8(v, config)
- case OpAMD64MOVQstoreidx1:
- return rewriteValueAMD64_OpAMD64MOVQstoreidx1(v, config)
- case OpAMD64MOVQstoreidx8:
- return rewriteValueAMD64_OpAMD64MOVQstoreidx8(v, config)
- case OpAMD64MOVSDload:
- return rewriteValueAMD64_OpAMD64MOVSDload(v, config)
- case OpAMD64MOVSDloadidx1:
- return rewriteValueAMD64_OpAMD64MOVSDloadidx1(v, config)
- case OpAMD64MOVSDloadidx8:
- return rewriteValueAMD64_OpAMD64MOVSDloadidx8(v, config)
- case OpAMD64MOVSDstore:
- return rewriteValueAMD64_OpAMD64MOVSDstore(v, config)
- case OpAMD64MOVSDstoreidx1:
- return rewriteValueAMD64_OpAMD64MOVSDstoreidx1(v, config)
- case OpAMD64MOVSDstoreidx8:
- return rewriteValueAMD64_OpAMD64MOVSDstoreidx8(v, config)
- case OpAMD64MOVSSload:
- return rewriteValueAMD64_OpAMD64MOVSSload(v, config)
- case OpAMD64MOVSSloadidx1:
- return rewriteValueAMD64_OpAMD64MOVSSloadidx1(v, config)
- case OpAMD64MOVSSloadidx4:
- return rewriteValueAMD64_OpAMD64MOVSSloadidx4(v, config)
- case OpAMD64MOVSSstore:
- return rewriteValueAMD64_OpAMD64MOVSSstore(v, config)
- case OpAMD64MOVSSstoreidx1:
- return rewriteValueAMD64_OpAMD64MOVSSstoreidx1(v, config)
- case OpAMD64MOVSSstoreidx4:
- return rewriteValueAMD64_OpAMD64MOVSSstoreidx4(v, config)
- case OpAMD64MOVWQSX:
- return rewriteValueAMD64_OpAMD64MOVWQSX(v, config)
- case OpAMD64MOVWQSXload:
- return rewriteValueAMD64_OpAMD64MOVWQSXload(v, config)
- case OpAMD64MOVWQZX:
- return rewriteValueAMD64_OpAMD64MOVWQZX(v, config)
- case OpAMD64MOVWload:
- return rewriteValueAMD64_OpAMD64MOVWload(v, config)
- case OpAMD64MOVWloadidx1:
- return rewriteValueAMD64_OpAMD64MOVWloadidx1(v, config)
- case OpAMD64MOVWloadidx2:
- return rewriteValueAMD64_OpAMD64MOVWloadidx2(v, config)
- case OpAMD64MOVWstore:
- return rewriteValueAMD64_OpAMD64MOVWstore(v, config)
- case OpAMD64MOVWstoreconst:
- return rewriteValueAMD64_OpAMD64MOVWstoreconst(v, config)
- case OpAMD64MOVWstoreconstidx1:
- return rewriteValueAMD64_OpAMD64MOVWstoreconstidx1(v, config)
- case OpAMD64MOVWstoreconstidx2:
- return rewriteValueAMD64_OpAMD64MOVWstoreconstidx2(v, config)
- case OpAMD64MOVWstoreidx1:
- return rewriteValueAMD64_OpAMD64MOVWstoreidx1(v, config)
- case OpAMD64MOVWstoreidx2:
- return rewriteValueAMD64_OpAMD64MOVWstoreidx2(v, config)
- case OpAMD64MULL:
- return rewriteValueAMD64_OpAMD64MULL(v, config)
- case OpAMD64MULLconst:
- return rewriteValueAMD64_OpAMD64MULLconst(v, config)
- case OpAMD64MULQ:
- return rewriteValueAMD64_OpAMD64MULQ(v, config)
- case OpAMD64MULQconst:
- return rewriteValueAMD64_OpAMD64MULQconst(v, config)
case OpMod16:
return rewriteValueAMD64_OpMod16(v, config)
case OpMod16u:
@@ -482,16 +614,10 @@ func rewriteValueAMD64(v *Value, config *Config) bool {
return rewriteValueAMD64_OpMul64(v, config)
case OpMul64F:
return rewriteValueAMD64_OpMul64F(v, config)
+ case OpMul64uhilo:
+ return rewriteValueAMD64_OpMul64uhilo(v, config)
case OpMul8:
return rewriteValueAMD64_OpMul8(v, config)
- case OpAMD64NEGL:
- return rewriteValueAMD64_OpAMD64NEGL(v, config)
- case OpAMD64NEGQ:
- return rewriteValueAMD64_OpAMD64NEGQ(v, config)
- case OpAMD64NOTL:
- return rewriteValueAMD64_OpAMD64NOTL(v, config)
- case OpAMD64NOTQ:
- return rewriteValueAMD64_OpAMD64NOTQ(v, config)
case OpNeg16:
return rewriteValueAMD64_OpNeg16(v, config)
case OpNeg32:
@@ -524,14 +650,6 @@ func rewriteValueAMD64(v *Value, config *Config) bool {
return rewriteValueAMD64_OpNilCheck(v, config)
case OpNot:
return rewriteValueAMD64_OpNot(v, config)
- case OpAMD64ORL:
- return rewriteValueAMD64_OpAMD64ORL(v, config)
- case OpAMD64ORLconst:
- return rewriteValueAMD64_OpAMD64ORLconst(v, config)
- case OpAMD64ORQ:
- return rewriteValueAMD64_OpAMD64ORQ(v, config)
- case OpAMD64ORQconst:
- return rewriteValueAMD64_OpAMD64ORQconst(v, config)
case OpOffPtr:
return rewriteValueAMD64_OpOffPtr(v, config)
case OpOr16:
@@ -608,66 +726,10 @@ func rewriteValueAMD64(v *Value, config *Config) bool {
return rewriteValueAMD64_OpRsh8x64(v, config)
case OpRsh8x8:
return rewriteValueAMD64_OpRsh8x8(v, config)
- case OpAMD64SARB:
- return rewriteValueAMD64_OpAMD64SARB(v, config)
- case OpAMD64SARBconst:
- return rewriteValueAMD64_OpAMD64SARBconst(v, config)
- case OpAMD64SARL:
- return rewriteValueAMD64_OpAMD64SARL(v, config)
- case OpAMD64SARLconst:
- return rewriteValueAMD64_OpAMD64SARLconst(v, config)
- case OpAMD64SARQ:
- return rewriteValueAMD64_OpAMD64SARQ(v, config)
- case OpAMD64SARQconst:
- return rewriteValueAMD64_OpAMD64SARQconst(v, config)
- case OpAMD64SARW:
- return rewriteValueAMD64_OpAMD64SARW(v, config)
- case OpAMD64SARWconst:
- return rewriteValueAMD64_OpAMD64SARWconst(v, config)
- case OpAMD64SBBLcarrymask:
- return rewriteValueAMD64_OpAMD64SBBLcarrymask(v, config)
- case OpAMD64SBBQcarrymask:
- return rewriteValueAMD64_OpAMD64SBBQcarrymask(v, config)
- case OpAMD64SETA:
- return rewriteValueAMD64_OpAMD64SETA(v, config)
- case OpAMD64SETAE:
- return rewriteValueAMD64_OpAMD64SETAE(v, config)
- case OpAMD64SETB:
- return rewriteValueAMD64_OpAMD64SETB(v, config)
- case OpAMD64SETBE:
- return rewriteValueAMD64_OpAMD64SETBE(v, config)
- case OpAMD64SETEQ:
- return rewriteValueAMD64_OpAMD64SETEQ(v, config)
- case OpAMD64SETG:
- return rewriteValueAMD64_OpAMD64SETG(v, config)
- case OpAMD64SETGE:
- return rewriteValueAMD64_OpAMD64SETGE(v, config)
- case OpAMD64SETL:
- return rewriteValueAMD64_OpAMD64SETL(v, config)
- case OpAMD64SETLE:
- return rewriteValueAMD64_OpAMD64SETLE(v, config)
- case OpAMD64SETNE:
- return rewriteValueAMD64_OpAMD64SETNE(v, config)
- case OpAMD64SHLL:
- return rewriteValueAMD64_OpAMD64SHLL(v, config)
- case OpAMD64SHLQ:
- return rewriteValueAMD64_OpAMD64SHLQ(v, config)
- case OpAMD64SHRB:
- return rewriteValueAMD64_OpAMD64SHRB(v, config)
- case OpAMD64SHRL:
- return rewriteValueAMD64_OpAMD64SHRL(v, config)
- case OpAMD64SHRQ:
- return rewriteValueAMD64_OpAMD64SHRQ(v, config)
- case OpAMD64SHRW:
- return rewriteValueAMD64_OpAMD64SHRW(v, config)
- case OpAMD64SUBL:
- return rewriteValueAMD64_OpAMD64SUBL(v, config)
- case OpAMD64SUBLconst:
- return rewriteValueAMD64_OpAMD64SUBLconst(v, config)
- case OpAMD64SUBQ:
- return rewriteValueAMD64_OpAMD64SUBQ(v, config)
- case OpAMD64SUBQconst:
- return rewriteValueAMD64_OpAMD64SUBQconst(v, config)
+ case OpSelect0:
+ return rewriteValueAMD64_OpSelect0(v, config)
+ case OpSelect1:
+ return rewriteValueAMD64_OpSelect1(v, config)
case OpSignExt16to32:
return rewriteValueAMD64_OpSignExt16to32(v, config)
case OpSignExt16to64:
@@ -680,6 +742,8 @@ func rewriteValueAMD64(v *Value, config *Config) bool {
return rewriteValueAMD64_OpSignExt8to32(v, config)
case OpSignExt8to64:
return rewriteValueAMD64_OpSignExt8to64(v, config)
+ case OpSlicemask:
+ return rewriteValueAMD64_OpSlicemask(v, config)
case OpSqrt:
return rewriteValueAMD64_OpSqrt(v, config)
case OpStaticCall:
@@ -712,14 +776,6 @@ func rewriteValueAMD64(v *Value, config *Config) bool {
return rewriteValueAMD64_OpTrunc64to32(v, config)
case OpTrunc64to8:
return rewriteValueAMD64_OpTrunc64to8(v, config)
- case OpAMD64XORL:
- return rewriteValueAMD64_OpAMD64XORL(v, config)
- case OpAMD64XORLconst:
- return rewriteValueAMD64_OpAMD64XORLconst(v, config)
- case OpAMD64XORQ:
- return rewriteValueAMD64_OpAMD64XORQ(v, config)
- case OpAMD64XORQconst:
- return rewriteValueAMD64_OpAMD64XORQconst(v, config)
case OpXor16:
return rewriteValueAMD64_OpXor16(v, config)
case OpXor32:
@@ -842,6 +898,27 @@ func rewriteValueAMD64_OpAMD64ADDLconst(v *Value, config *Config) bool {
v.AddArg(x)
return true
}
+ // match: (ADDLconst [c] (LEAL [d] {s} x))
+ // cond: is32Bit(c+d)
+ // result: (LEAL [c+d] {s} x)
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64LEAL {
+ break
+ }
+ d := v_0.AuxInt
+ s := v_0.Aux
+ x := v_0.Args[0]
+ if !(is32Bit(c + d)) {
+ break
+ }
+ v.reset(OpAMD64LEAL)
+ v.AuxInt = c + d
+ v.Aux = s
+ v.AddArg(x)
+ return true
+ }
return false
}
func rewriteValueAMD64_OpAMD64ADDQ(v *Value, config *Config) bool {
@@ -1334,6 +1411,30 @@ func rewriteValueAMD64_OpAMD64ANDLconst(v *Value, config *Config) bool {
v.AddArg(x)
return true
}
+ // match: (ANDLconst [0xFF] x)
+ // cond:
+ // result: (MOVBQZX x)
+ for {
+ if v.AuxInt != 0xFF {
+ break
+ }
+ x := v.Args[0]
+ v.reset(OpAMD64MOVBQZX)
+ v.AddArg(x)
+ return true
+ }
+ // match: (ANDLconst [0xFFFF] x)
+ // cond:
+ // result: (MOVWQZX x)
+ for {
+ if v.AuxInt != 0xFFFF {
+ break
+ }
+ x := v.Args[0]
+ v.reset(OpAMD64MOVWQZX)
+ v.AddArg(x)
+ return true
+ }
// match: (ANDLconst [c] _)
// cond: int32(c)==0
// result: (MOVLconst [0])
@@ -1525,2674 +1626,3832 @@ func rewriteValueAMD64_OpAMD64ANDQconst(v *Value, config *Config) bool {
}
return false
}
-func rewriteValueAMD64_OpAdd16(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpAMD64CMPB(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (Add16 x y)
+ // match: (CMPB x (MOVLconst [c]))
// cond:
- // result: (ADDL x y)
+ // result: (CMPBconst x [int64(int8(c))])
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_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)
- v.AddArg(y)
return true
}
-}
-func rewriteValueAMD64_OpAdd32F(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Add32F x y)
+ // match: (CMPB (MOVLconst [c]) x)
// cond:
- // result: (ADDSS x y)
+ // result: (InvertFlags (CMPBconst x [int64(int8(c))]))
for {
- x := v.Args[0]
- y := v.Args[1]
- v.reset(OpAMD64ADDSS)
- v.AddArg(x)
- v.AddArg(y)
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64MOVLconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ v.reset(OpAMD64InvertFlags)
+ v0 := b.NewValue0(v.Line, OpAMD64CMPBconst, TypeFlags)
+ v0.AuxInt = int64(int8(c))
+ v0.AddArg(x)
+ v.AddArg(v0)
return true
}
+ return false
}
-func rewriteValueAMD64_OpAdd64(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpAMD64CMPBconst(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (Add64 x y)
- // cond:
- // result: (ADDQ x y)
+ // match: (CMPBconst (MOVLconst [x]) [y])
+ // cond: int8(x)==int8(y)
+ // result: (FlagEQ)
for {
- x := v.Args[0]
- y := v.Args[1]
- v.reset(OpAMD64ADDQ)
- v.AddArg(x)
- v.AddArg(y)
+ y := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64MOVLconst {
+ break
+ }
+ x := v_0.AuxInt
+ if !(int8(x) == int8(y)) {
+ break
+ }
+ v.reset(OpAMD64FlagEQ)
return true
}
-}
-func rewriteValueAMD64_OpAdd64F(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Add64F x y)
- // cond:
- // result: (ADDSD x y)
+ // match: (CMPBconst (MOVLconst [x]) [y])
+ // cond: int8(x)<int8(y) && uint8(x)<uint8(y)
+ // result: (FlagLT_ULT)
for {
- x := v.Args[0]
- y := v.Args[1]
- v.reset(OpAMD64ADDSD)
- v.AddArg(x)
- v.AddArg(y)
+ y := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64MOVLconst {
+ break
+ }
+ x := v_0.AuxInt
+ if !(int8(x) < int8(y) && uint8(x) < uint8(y)) {
+ break
+ }
+ v.reset(OpAMD64FlagLT_ULT)
return true
}
-}
-func rewriteValueAMD64_OpAdd8(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Add8 x y)
- // cond:
- // result: (ADDL x y)
+ // match: (CMPBconst (MOVLconst [x]) [y])
+ // cond: int8(x)<int8(y) && uint8(x)>uint8(y)
+ // result: (FlagLT_UGT)
for {
- x := v.Args[0]
- y := v.Args[1]
- v.reset(OpAMD64ADDL)
- v.AddArg(x)
- v.AddArg(y)
+ y := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64MOVLconst {
+ break
+ }
+ x := v_0.AuxInt
+ if !(int8(x) < int8(y) && uint8(x) > uint8(y)) {
+ break
+ }
+ v.reset(OpAMD64FlagLT_UGT)
return true
}
-}
-func rewriteValueAMD64_OpAddPtr(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (AddPtr x y)
- // cond:
- // result: (ADDQ x y)
+ // match: (CMPBconst (MOVLconst [x]) [y])
+ // cond: int8(x)>int8(y) && uint8(x)<uint8(y)
+ // result: (FlagGT_ULT)
for {
- x := v.Args[0]
- y := v.Args[1]
- v.reset(OpAMD64ADDQ)
- v.AddArg(x)
- v.AddArg(y)
+ y := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64MOVLconst {
+ break
+ }
+ x := v_0.AuxInt
+ if !(int8(x) > int8(y) && uint8(x) < uint8(y)) {
+ break
+ }
+ v.reset(OpAMD64FlagGT_ULT)
return true
}
-}
-func rewriteValueAMD64_OpAddr(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Addr {sym} base)
- // cond:
- // result: (LEAQ {sym} base)
+ // match: (CMPBconst (MOVLconst [x]) [y])
+ // cond: int8(x)>int8(y) && uint8(x)>uint8(y)
+ // result: (FlagGT_UGT)
for {
- sym := v.Aux
- base := v.Args[0]
- v.reset(OpAMD64LEAQ)
- v.Aux = sym
- v.AddArg(base)
+ y := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64MOVLconst {
+ break
+ }
+ x := v_0.AuxInt
+ if !(int8(x) > int8(y) && uint8(x) > uint8(y)) {
+ break
+ }
+ v.reset(OpAMD64FlagGT_UGT)
return true
}
-}
-func rewriteValueAMD64_OpAnd16(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (And16 x y)
- // cond:
- // result: (ANDL x y)
+ // match: (CMPBconst (ANDLconst _ [m]) [n])
+ // cond: 0 <= int8(m) && int8(m) < int8(n)
+ // result: (FlagLT_ULT)
for {
- x := v.Args[0]
- y := v.Args[1]
- v.reset(OpAMD64ANDL)
- v.AddArg(x)
- v.AddArg(y)
+ n := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64ANDLconst {
+ break
+ }
+ m := v_0.AuxInt
+ if !(0 <= int8(m) && int8(m) < int8(n)) {
+ break
+ }
+ v.reset(OpAMD64FlagLT_ULT)
return true
}
-}
-func rewriteValueAMD64_OpAnd32(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (And32 x y)
+ // match: (CMPBconst (ANDL x y) [0])
// cond:
- // result: (ANDL x y)
+ // result: (TESTB x y)
for {
- x := v.Args[0]
- y := v.Args[1]
- v.reset(OpAMD64ANDL)
+ if v.AuxInt != 0 {
+ break
+ }
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64ANDL {
+ break
+ }
+ x := v_0.Args[0]
+ y := v_0.Args[1]
+ v.reset(OpAMD64TESTB)
v.AddArg(x)
v.AddArg(y)
return true
}
-}
-func rewriteValueAMD64_OpAnd64(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (And64 x y)
+ // match: (CMPBconst (ANDLconst [c] x) [0])
// cond:
- // result: (ANDQ x y)
+ // result: (TESTBconst [int64(int8(c))] x)
for {
- x := v.Args[0]
- y := v.Args[1]
- v.reset(OpAMD64ANDQ)
+ if v.AuxInt != 0 {
+ break
+ }
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64ANDLconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v_0.Args[0]
+ v.reset(OpAMD64TESTBconst)
+ v.AuxInt = int64(int8(c))
v.AddArg(x)
- v.AddArg(y)
return true
}
-}
-func rewriteValueAMD64_OpAnd8(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (And8 x y)
+ // match: (CMPBconst x [0])
// cond:
- // result: (ANDL x y)
+ // result: (TESTB x x)
for {
+ if v.AuxInt != 0 {
+ break
+ }
x := v.Args[0]
- y := v.Args[1]
- v.reset(OpAMD64ANDL)
+ v.reset(OpAMD64TESTB)
+ v.AddArg(x)
v.AddArg(x)
- v.AddArg(y)
return true
}
+ return false
}
-func rewriteValueAMD64_OpAndB(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpAMD64CMPL(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (AndB x y)
+ // match: (CMPL x (MOVLconst [c]))
// cond:
- // result: (ANDL x y)
- for {
- x := v.Args[0]
- y := v.Args[1]
- v.reset(OpAMD64ANDL)
- v.AddArg(x)
- v.AddArg(y)
- return true
- }
-}
-func rewriteValueAMD64_OpAvg64u(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Avg64u x y)
- // cond:
- // result: (AVGQU x y)
- for {
- x := v.Args[0]
- y := v.Args[1]
- v.reset(OpAMD64AVGQU)
- v.AddArg(x)
- v.AddArg(y)
- return true
- }
-}
-func rewriteValueAMD64_OpBswap32(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Bswap32 x)
- // cond:
- // result: (BSWAPL x)
+ // result: (CMPLconst x [c])
for {
x := v.Args[0]
- v.reset(OpAMD64BSWAPL)
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64MOVLconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpAMD64CMPLconst)
+ v.AuxInt = c
v.AddArg(x)
return true
}
-}
-func rewriteValueAMD64_OpBswap64(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Bswap64 x)
+ // match: (CMPL (MOVLconst [c]) x)
// cond:
- // result: (BSWAPQ x)
+ // result: (InvertFlags (CMPLconst x [c]))
for {
- x := v.Args[0]
- v.reset(OpAMD64BSWAPQ)
- v.AddArg(x)
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64MOVLconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ v.reset(OpAMD64InvertFlags)
+ v0 := b.NewValue0(v.Line, OpAMD64CMPLconst, TypeFlags)
+ v0.AuxInt = c
+ v0.AddArg(x)
+ v.AddArg(v0)
return true
}
+ return false
}
-func rewriteValueAMD64_OpAMD64CMOVLEQconst(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpAMD64CMPLconst(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (CMOVLEQconst x (InvertFlags y) [c])
- // cond:
- // result: (CMOVLNEconst x y [c])
+ // match: (CMPLconst (MOVLconst [x]) [y])
+ // cond: int32(x)==int32(y)
+ // result: (FlagEQ)
for {
- x := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64InvertFlags {
+ y := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64MOVLconst {
break
}
- y := v_1.Args[0]
- c := v.AuxInt
- v.reset(OpAMD64CMOVLNEconst)
- v.AddArg(x)
- v.AddArg(y)
- v.AuxInt = c
- return true
- }
- // match: (CMOVLEQconst _ (FlagEQ) [c])
- // cond:
- // result: (Const32 [c])
- for {
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64FlagEQ {
+ x := v_0.AuxInt
+ if !(int32(x) == int32(y)) {
break
}
- c := v.AuxInt
- v.reset(OpConst32)
- v.AuxInt = c
+ v.reset(OpAMD64FlagEQ)
return true
}
- // match: (CMOVLEQconst x (FlagLT_ULT))
- // cond:
- // result: x
+ // match: (CMPLconst (MOVLconst [x]) [y])
+ // cond: int32(x)<int32(y) && uint32(x)<uint32(y)
+ // result: (FlagLT_ULT)
for {
- x := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64FlagLT_ULT {
+ y := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64MOVLconst {
break
}
- v.reset(OpCopy)
- v.Type = x.Type
- v.AddArg(x)
- return true
- }
- // match: (CMOVLEQconst x (FlagLT_UGT))
- // cond:
- // result: x
- for {
- x := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64FlagLT_UGT {
+ x := v_0.AuxInt
+ if !(int32(x) < int32(y) && uint32(x) < uint32(y)) {
break
}
- v.reset(OpCopy)
- v.Type = x.Type
- v.AddArg(x)
+ v.reset(OpAMD64FlagLT_ULT)
return true
}
- // match: (CMOVLEQconst x (FlagGT_ULT))
- // cond:
- // result: x
+ // match: (CMPLconst (MOVLconst [x]) [y])
+ // cond: int32(x)<int32(y) && uint32(x)>uint32(y)
+ // result: (FlagLT_UGT)
for {
- x := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64FlagGT_ULT {
+ y := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64MOVLconst {
break
}
- v.reset(OpCopy)
- v.Type = x.Type
- v.AddArg(x)
+ x := v_0.AuxInt
+ if !(int32(x) < int32(y) && uint32(x) > uint32(y)) {
+ break
+ }
+ v.reset(OpAMD64FlagLT_UGT)
return true
}
- // match: (CMOVLEQconst x (FlagGT_UGT))
- // cond:
- // result: x
+ // match: (CMPLconst (MOVLconst [x]) [y])
+ // cond: int32(x)>int32(y) && uint32(x)<uint32(y)
+ // result: (FlagGT_ULT)
for {
- x := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64FlagGT_UGT {
+ y := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64MOVLconst {
break
}
- v.reset(OpCopy)
- v.Type = x.Type
- v.AddArg(x)
+ x := v_0.AuxInt
+ if !(int32(x) > int32(y) && uint32(x) < uint32(y)) {
+ break
+ }
+ v.reset(OpAMD64FlagGT_ULT)
return true
}
- return false
-}
-func rewriteValueAMD64_OpAMD64CMOVQEQconst(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (CMOVQEQconst x (InvertFlags y) [c])
- // cond:
- // result: (CMOVQNEconst x y [c])
+ // match: (CMPLconst (MOVLconst [x]) [y])
+ // cond: int32(x)>int32(y) && uint32(x)>uint32(y)
+ // result: (FlagGT_UGT)
for {
- x := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64InvertFlags {
+ y := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64MOVLconst {
break
}
- y := v_1.Args[0]
- c := v.AuxInt
- v.reset(OpAMD64CMOVQNEconst)
- v.AddArg(x)
- v.AddArg(y)
- v.AuxInt = c
+ x := v_0.AuxInt
+ if !(int32(x) > int32(y) && uint32(x) > uint32(y)) {
+ break
+ }
+ v.reset(OpAMD64FlagGT_UGT)
return true
}
- // match: (CMOVQEQconst _ (FlagEQ) [c])
- // cond:
- // result: (Const64 [c])
+ // match: (CMPLconst (SHRLconst _ [c]) [n])
+ // cond: 0 <= n && 0 < c && c <= 32 && (1<<uint64(32-c)) <= uint64(n)
+ // result: (FlagLT_ULT)
for {
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64FlagEQ {
+ n := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64SHRLconst {
break
}
- c := v.AuxInt
- v.reset(OpConst64)
- v.AuxInt = c
+ c := v_0.AuxInt
+ if !(0 <= n && 0 < c && c <= 32 && (1<<uint64(32-c)) <= uint64(n)) {
+ break
+ }
+ v.reset(OpAMD64FlagLT_ULT)
return true
}
- // match: (CMOVQEQconst x (FlagLT_ULT))
- // cond:
- // result: x
+ // match: (CMPLconst (ANDLconst _ [m]) [n])
+ // cond: 0 <= int32(m) && int32(m) < int32(n)
+ // result: (FlagLT_ULT)
for {
- x := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64FlagLT_ULT {
+ n := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64ANDLconst {
break
}
- v.reset(OpCopy)
- v.Type = x.Type
- v.AddArg(x)
+ m := v_0.AuxInt
+ if !(0 <= int32(m) && int32(m) < int32(n)) {
+ break
+ }
+ v.reset(OpAMD64FlagLT_ULT)
return true
}
- // match: (CMOVQEQconst x (FlagLT_UGT))
+ // match: (CMPLconst (ANDL x y) [0])
// cond:
- // result: x
+ // result: (TESTL x y)
for {
- x := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64FlagLT_UGT {
+ if v.AuxInt != 0 {
break
}
- v.reset(OpCopy)
- v.Type = x.Type
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64ANDL {
+ break
+ }
+ x := v_0.Args[0]
+ y := v_0.Args[1]
+ v.reset(OpAMD64TESTL)
v.AddArg(x)
+ v.AddArg(y)
return true
}
- // match: (CMOVQEQconst x (FlagGT_ULT))
+ // match: (CMPLconst (ANDLconst [c] x) [0])
// cond:
- // result: x
+ // result: (TESTLconst [c] x)
for {
- x := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64FlagGT_ULT {
+ if v.AuxInt != 0 {
break
}
- v.reset(OpCopy)
- v.Type = x.Type
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64ANDLconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v_0.Args[0]
+ v.reset(OpAMD64TESTLconst)
+ v.AuxInt = c
v.AddArg(x)
return true
}
- // match: (CMOVQEQconst x (FlagGT_UGT))
+ // match: (CMPLconst x [0])
// cond:
- // result: x
+ // result: (TESTL x x)
for {
- x := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64FlagGT_UGT {
+ if v.AuxInt != 0 {
break
}
- v.reset(OpCopy)
- v.Type = x.Type
+ x := v.Args[0]
+ v.reset(OpAMD64TESTL)
+ v.AddArg(x)
v.AddArg(x)
return true
}
return false
}
-func rewriteValueAMD64_OpAMD64CMOVWEQconst(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpAMD64CMPQ(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (CMOVWEQconst x (InvertFlags y) [c])
- // cond:
- // result: (CMOVWNEconst x y [c])
+ // match: (CMPQ x (MOVQconst [c]))
+ // cond: is32Bit(c)
+ // result: (CMPQconst x [c])
for {
x := v.Args[0]
v_1 := v.Args[1]
- if v_1.Op != OpAMD64InvertFlags {
+ if v_1.Op != OpAMD64MOVQconst {
break
}
- y := v_1.Args[0]
- c := v.AuxInt
- v.reset(OpAMD64CMOVWNEconst)
- v.AddArg(x)
- v.AddArg(y)
- v.AuxInt = c
- return true
- }
- // match: (CMOVWEQconst _ (FlagEQ) [c])
- // cond:
- // result: (Const16 [c])
- for {
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64FlagEQ {
+ c := v_1.AuxInt
+ if !(is32Bit(c)) {
break
}
- c := v.AuxInt
- v.reset(OpConst16)
+ v.reset(OpAMD64CMPQconst)
v.AuxInt = c
- return true
- }
- // match: (CMOVWEQconst x (FlagLT_ULT))
- // cond:
- // result: x
- for {
- x := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64FlagLT_ULT {
- break
- }
- v.reset(OpCopy)
- v.Type = x.Type
- v.AddArg(x)
- return true
- }
- // match: (CMOVWEQconst x (FlagLT_UGT))
- // cond:
- // result: x
- for {
- x := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64FlagLT_UGT {
- break
- }
- v.reset(OpCopy)
- v.Type = x.Type
- v.AddArg(x)
- return true
- }
- // match: (CMOVWEQconst x (FlagGT_ULT))
- // cond:
- // result: x
- for {
- x := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64FlagGT_ULT {
- break
- }
- v.reset(OpCopy)
- v.Type = x.Type
- v.AddArg(x)
- return true
- }
- // match: (CMOVWEQconst x (FlagGT_UGT))
- // cond:
- // result: x
- for {
- x := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64FlagGT_UGT {
- break
- }
- v.reset(OpCopy)
- v.Type = x.Type
- v.AddArg(x)
- return true
- }
- return false
-}
-func rewriteValueAMD64_OpAMD64CMPB(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (CMPB x (MOVLconst [c]))
- // cond:
- // result: (CMPBconst x [int64(int8(c))])
- for {
- x := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64MOVLconst {
- break
- }
- c := v_1.AuxInt
- v.reset(OpAMD64CMPBconst)
v.AddArg(x)
- v.AuxInt = int64(int8(c))
return true
}
- // match: (CMPB (MOVLconst [c]) x)
- // cond:
- // result: (InvertFlags (CMPBconst x [int64(int8(c))]))
+ // match: (CMPQ (MOVQconst [c]) x)
+ // cond: is32Bit(c)
+ // result: (InvertFlags (CMPQconst x [c]))
for {
v_0 := v.Args[0]
- if v_0.Op != OpAMD64MOVLconst {
+ if v_0.Op != OpAMD64MOVQconst {
break
}
c := v_0.AuxInt
x := v.Args[1]
+ if !(is32Bit(c)) {
+ break
+ }
v.reset(OpAMD64InvertFlags)
- v0 := b.NewValue0(v.Line, OpAMD64CMPBconst, TypeFlags)
+ v0 := b.NewValue0(v.Line, OpAMD64CMPQconst, TypeFlags)
+ v0.AuxInt = c
v0.AddArg(x)
- v0.AuxInt = int64(int8(c))
v.AddArg(v0)
return true
}
return false
}
-func rewriteValueAMD64_OpAMD64CMPBconst(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpAMD64CMPQconst(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (CMPBconst (MOVLconst [x]) [y])
- // cond: int8(x)==int8(y)
+ // match: (CMPQconst (MOVQconst [x]) [y])
+ // cond: x==y
// result: (FlagEQ)
for {
+ y := v.AuxInt
v_0 := v.Args[0]
- if v_0.Op != OpAMD64MOVLconst {
+ if v_0.Op != OpAMD64MOVQconst {
break
}
x := v_0.AuxInt
- y := v.AuxInt
- if !(int8(x) == int8(y)) {
+ if !(x == y) {
break
}
v.reset(OpAMD64FlagEQ)
return true
}
- // match: (CMPBconst (MOVLconst [x]) [y])
- // cond: int8(x)<int8(y) && uint8(x)<uint8(y)
+ // match: (CMPQconst (MOVQconst [x]) [y])
+ // cond: x<y && uint64(x)<uint64(y)
// result: (FlagLT_ULT)
for {
+ y := v.AuxInt
v_0 := v.Args[0]
- if v_0.Op != OpAMD64MOVLconst {
+ if v_0.Op != OpAMD64MOVQconst {
break
}
x := v_0.AuxInt
- y := v.AuxInt
- if !(int8(x) < int8(y) && uint8(x) < uint8(y)) {
+ if !(x < y && uint64(x) < uint64(y)) {
break
}
v.reset(OpAMD64FlagLT_ULT)
return true
}
- // match: (CMPBconst (MOVLconst [x]) [y])
- // cond: int8(x)<int8(y) && uint8(x)>uint8(y)
+ // match: (CMPQconst (MOVQconst [x]) [y])
+ // cond: x<y && uint64(x)>uint64(y)
// result: (FlagLT_UGT)
for {
+ y := v.AuxInt
v_0 := v.Args[0]
- if v_0.Op != OpAMD64MOVLconst {
+ if v_0.Op != OpAMD64MOVQconst {
break
}
x := v_0.AuxInt
- y := v.AuxInt
- if !(int8(x) < int8(y) && uint8(x) > uint8(y)) {
+ if !(x < y && uint64(x) > uint64(y)) {
break
}
v.reset(OpAMD64FlagLT_UGT)
return true
}
- // match: (CMPBconst (MOVLconst [x]) [y])
- // cond: int8(x)>int8(y) && uint8(x)<uint8(y)
+ // match: (CMPQconst (MOVQconst [x]) [y])
+ // cond: x>y && uint64(x)<uint64(y)
// result: (FlagGT_ULT)
for {
+ y := v.AuxInt
v_0 := v.Args[0]
- if v_0.Op != OpAMD64MOVLconst {
+ if v_0.Op != OpAMD64MOVQconst {
break
}
x := v_0.AuxInt
- y := v.AuxInt
- if !(int8(x) > int8(y) && uint8(x) < uint8(y)) {
+ if !(x > y && uint64(x) < uint64(y)) {
break
}
v.reset(OpAMD64FlagGT_ULT)
return true
}
- // match: (CMPBconst (MOVLconst [x]) [y])
- // cond: int8(x)>int8(y) && uint8(x)>uint8(y)
+ // match: (CMPQconst (MOVQconst [x]) [y])
+ // cond: x>y && uint64(x)>uint64(y)
// result: (FlagGT_UGT)
for {
+ y := v.AuxInt
v_0 := v.Args[0]
- if v_0.Op != OpAMD64MOVLconst {
+ if v_0.Op != OpAMD64MOVQconst {
break
}
x := v_0.AuxInt
- y := v.AuxInt
- if !(int8(x) > int8(y) && uint8(x) > uint8(y)) {
+ if !(x > y && uint64(x) > uint64(y)) {
break
}
v.reset(OpAMD64FlagGT_UGT)
return true
}
- // match: (CMPBconst (ANDLconst _ [m]) [n])
- // cond: 0 <= int8(m) && int8(m) < int8(n)
+ // match: (CMPQconst (MOVBQZX _) [c])
+ // cond: 0xFF < c
// result: (FlagLT_ULT)
for {
+ c := v.AuxInt
v_0 := v.Args[0]
- if v_0.Op != OpAMD64ANDLconst {
+ if v_0.Op != OpAMD64MOVBQZX {
break
}
- m := v_0.AuxInt
- n := v.AuxInt
- if !(0 <= int8(m) && int8(m) < int8(n)) {
+ if !(0xFF < c) {
break
}
v.reset(OpAMD64FlagLT_ULT)
return true
}
- // match: (CMPBconst (ANDL x y) [0])
- // cond:
- // result: (TESTB x y)
+ // match: (CMPQconst (MOVWQZX _) [c])
+ // cond: 0xFFFF < c
+ // result: (FlagLT_ULT)
for {
+ c := v.AuxInt
v_0 := v.Args[0]
- if v_0.Op != OpAMD64ANDL {
+ if v_0.Op != OpAMD64MOVWQZX {
break
}
- x := v_0.Args[0]
- y := v_0.Args[1]
- if v.AuxInt != 0 {
+ if !(0xFFFF < c) {
break
}
- v.reset(OpAMD64TESTB)
- v.AddArg(x)
- v.AddArg(y)
+ v.reset(OpAMD64FlagLT_ULT)
return true
}
- // match: (CMPBconst (ANDLconst [c] x) [0])
- // cond:
- // result: (TESTBconst [int64(int8(c))] x)
+ // match: (CMPQconst (MOVLQZX _) [c])
+ // cond: 0xFFFFFFFF < c
+ // result: (FlagLT_ULT)
for {
+ c := v.AuxInt
v_0 := v.Args[0]
- if v_0.Op != OpAMD64ANDLconst {
+ if v_0.Op != OpAMD64MOVLQZX {
+ break
+ }
+ if !(0xFFFFFFFF < c) {
+ break
+ }
+ v.reset(OpAMD64FlagLT_ULT)
+ return true
+ }
+ // match: (CMPQconst (SHRQconst _ [c]) [n])
+ // cond: 0 <= n && 0 < c && c <= 64 && (1<<uint64(64-c)) <= uint64(n)
+ // result: (FlagLT_ULT)
+ for {
+ n := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64SHRQconst {
break
}
c := v_0.AuxInt
- x := v_0.Args[0]
- if v.AuxInt != 0 {
+ if !(0 <= n && 0 < c && c <= 64 && (1<<uint64(64-c)) <= uint64(n)) {
break
}
- v.reset(OpAMD64TESTBconst)
- v.AuxInt = int64(int8(c))
- v.AddArg(x)
+ v.reset(OpAMD64FlagLT_ULT)
return true
}
- // match: (CMPBconst x [0])
- // cond:
- // result: (TESTB x x)
+ // match: (CMPQconst (ANDQconst _ [m]) [n])
+ // cond: 0 <= m && m < n
+ // result: (FlagLT_ULT)
for {
- x := v.Args[0]
- if v.AuxInt != 0 {
+ n := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64ANDQconst {
break
}
- v.reset(OpAMD64TESTB)
- v.AddArg(x)
- v.AddArg(x)
+ m := v_0.AuxInt
+ if !(0 <= m && m < n) {
+ break
+ }
+ v.reset(OpAMD64FlagLT_ULT)
return true
}
- return false
-}
-func rewriteValueAMD64_OpAMD64CMPL(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (CMPL x (MOVLconst [c]))
+ // match: (CMPQconst (ANDQ x y) [0])
// cond:
- // result: (CMPLconst x [c])
+ // result: (TESTQ x y)
for {
- x := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64MOVLconst {
+ if v.AuxInt != 0 {
break
}
- c := v_1.AuxInt
- v.reset(OpAMD64CMPLconst)
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64ANDQ {
+ break
+ }
+ x := v_0.Args[0]
+ y := v_0.Args[1]
+ v.reset(OpAMD64TESTQ)
v.AddArg(x)
- v.AuxInt = c
+ v.AddArg(y)
return true
}
- // match: (CMPL (MOVLconst [c]) x)
+ // match: (CMPQconst (ANDQconst [c] x) [0])
// cond:
- // result: (InvertFlags (CMPLconst x [c]))
+ // result: (TESTQconst [c] x)
for {
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64MOVLconst {
+ if v.AuxInt != 0 {
+ break
+ }
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64ANDQconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v_0.Args[0]
+ v.reset(OpAMD64TESTQconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (CMPQconst x [0])
+ // cond:
+ // result: (TESTQ x x)
+ for {
+ if v.AuxInt != 0 {
+ break
+ }
+ x := v.Args[0]
+ v.reset(OpAMD64TESTQ)
+ v.AddArg(x)
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValueAMD64_OpAMD64CMPW(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (CMPW x (MOVLconst [c]))
+ // cond:
+ // result: (CMPWconst x [int64(int16(c))])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64MOVLconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpAMD64CMPWconst)
+ v.AuxInt = int64(int16(c))
+ v.AddArg(x)
+ return true
+ }
+ // match: (CMPW (MOVLconst [c]) x)
+ // cond:
+ // result: (InvertFlags (CMPWconst x [int64(int16(c))]))
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64MOVLconst {
break
}
c := v_0.AuxInt
x := v.Args[1]
v.reset(OpAMD64InvertFlags)
- v0 := b.NewValue0(v.Line, OpAMD64CMPLconst, TypeFlags)
+ v0 := b.NewValue0(v.Line, OpAMD64CMPWconst, TypeFlags)
+ v0.AuxInt = int64(int16(c))
v0.AddArg(x)
- v0.AuxInt = c
v.AddArg(v0)
return true
}
return false
}
-func rewriteValueAMD64_OpAMD64CMPLconst(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpAMD64CMPWconst(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (CMPLconst (MOVLconst [x]) [y])
- // cond: int32(x)==int32(y)
+ // match: (CMPWconst (MOVLconst [x]) [y])
+ // cond: int16(x)==int16(y)
// result: (FlagEQ)
for {
+ y := v.AuxInt
v_0 := v.Args[0]
if v_0.Op != OpAMD64MOVLconst {
break
}
x := v_0.AuxInt
- y := v.AuxInt
- if !(int32(x) == int32(y)) {
+ if !(int16(x) == int16(y)) {
break
}
v.reset(OpAMD64FlagEQ)
return true
}
- // match: (CMPLconst (MOVLconst [x]) [y])
- // cond: int32(x)<int32(y) && uint32(x)<uint32(y)
+ // match: (CMPWconst (MOVLconst [x]) [y])
+ // cond: int16(x)<int16(y) && uint16(x)<uint16(y)
// result: (FlagLT_ULT)
for {
+ y := v.AuxInt
v_0 := v.Args[0]
if v_0.Op != OpAMD64MOVLconst {
break
}
x := v_0.AuxInt
- y := v.AuxInt
- if !(int32(x) < int32(y) && uint32(x) < uint32(y)) {
+ if !(int16(x) < int16(y) && uint16(x) < uint16(y)) {
break
}
v.reset(OpAMD64FlagLT_ULT)
return true
}
- // match: (CMPLconst (MOVLconst [x]) [y])
- // cond: int32(x)<int32(y) && uint32(x)>uint32(y)
+ // match: (CMPWconst (MOVLconst [x]) [y])
+ // cond: int16(x)<int16(y) && uint16(x)>uint16(y)
// result: (FlagLT_UGT)
for {
+ y := v.AuxInt
v_0 := v.Args[0]
if v_0.Op != OpAMD64MOVLconst {
break
}
x := v_0.AuxInt
- y := v.AuxInt
- if !(int32(x) < int32(y) && uint32(x) > uint32(y)) {
+ if !(int16(x) < int16(y) && uint16(x) > uint16(y)) {
break
}
v.reset(OpAMD64FlagLT_UGT)
return true
}
- // match: (CMPLconst (MOVLconst [x]) [y])
- // cond: int32(x)>int32(y) && uint32(x)<uint32(y)
+ // match: (CMPWconst (MOVLconst [x]) [y])
+ // cond: int16(x)>int16(y) && uint16(x)<uint16(y)
// result: (FlagGT_ULT)
for {
+ y := v.AuxInt
v_0 := v.Args[0]
if v_0.Op != OpAMD64MOVLconst {
break
}
x := v_0.AuxInt
- y := v.AuxInt
- if !(int32(x) > int32(y) && uint32(x) < uint32(y)) {
+ if !(int16(x) > int16(y) && uint16(x) < uint16(y)) {
break
}
v.reset(OpAMD64FlagGT_ULT)
return true
}
- // match: (CMPLconst (MOVLconst [x]) [y])
- // cond: int32(x)>int32(y) && uint32(x)>uint32(y)
+ // match: (CMPWconst (MOVLconst [x]) [y])
+ // cond: int16(x)>int16(y) && uint16(x)>uint16(y)
// result: (FlagGT_UGT)
for {
+ y := v.AuxInt
v_0 := v.Args[0]
if v_0.Op != OpAMD64MOVLconst {
break
}
x := v_0.AuxInt
- y := v.AuxInt
- if !(int32(x) > int32(y) && uint32(x) > uint32(y)) {
+ if !(int16(x) > int16(y) && uint16(x) > uint16(y)) {
break
}
v.reset(OpAMD64FlagGT_UGT)
return true
}
- // match: (CMPLconst (SHRLconst _ [c]) [n])
- // cond: 0 <= n && 0 < c && c <= 32 && (1<<uint64(32-c)) <= uint64(n)
+ // match: (CMPWconst (ANDLconst _ [m]) [n])
+ // cond: 0 <= int16(m) && int16(m) < int16(n)
// result: (FlagLT_ULT)
for {
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64SHRLconst {
- break
- }
- c := v_0.AuxInt
n := v.AuxInt
- if !(0 <= n && 0 < c && c <= 32 && (1<<uint64(32-c)) <= uint64(n)) {
- break
- }
- v.reset(OpAMD64FlagLT_ULT)
- return true
- }
- // match: (CMPLconst (ANDLconst _ [m]) [n])
- // cond: 0 <= int32(m) && int32(m) < int32(n)
- // result: (FlagLT_ULT)
- for {
v_0 := v.Args[0]
if v_0.Op != OpAMD64ANDLconst {
break
}
m := v_0.AuxInt
- n := v.AuxInt
- if !(0 <= int32(m) && int32(m) < int32(n)) {
+ if !(0 <= int16(m) && int16(m) < int16(n)) {
break
}
v.reset(OpAMD64FlagLT_ULT)
return true
}
- // match: (CMPLconst (ANDL x y) [0])
+ // match: (CMPWconst (ANDL x y) [0])
// cond:
- // result: (TESTL x y)
+ // result: (TESTW x y)
for {
+ if v.AuxInt != 0 {
+ break
+ }
v_0 := v.Args[0]
if v_0.Op != OpAMD64ANDL {
break
}
x := v_0.Args[0]
y := v_0.Args[1]
- if v.AuxInt != 0 {
- break
- }
- v.reset(OpAMD64TESTL)
+ v.reset(OpAMD64TESTW)
v.AddArg(x)
v.AddArg(y)
return true
}
- // match: (CMPLconst (ANDLconst [c] x) [0])
+ // match: (CMPWconst (ANDLconst [c] x) [0])
// cond:
- // result: (TESTLconst [c] x)
+ // result: (TESTWconst [int64(int16(c))] x)
for {
+ if v.AuxInt != 0 {
+ break
+ }
v_0 := v.Args[0]
if v_0.Op != OpAMD64ANDLconst {
break
}
c := v_0.AuxInt
x := v_0.Args[0]
- if v.AuxInt != 0 {
- break
- }
- v.reset(OpAMD64TESTLconst)
- v.AuxInt = c
+ v.reset(OpAMD64TESTWconst)
+ v.AuxInt = int64(int16(c))
v.AddArg(x)
return true
}
- // match: (CMPLconst x [0])
+ // match: (CMPWconst x [0])
// cond:
- // result: (TESTL x x)
+ // result: (TESTW x x)
for {
- x := v.Args[0]
if v.AuxInt != 0 {
break
}
- v.reset(OpAMD64TESTL)
+ x := v.Args[0]
+ v.reset(OpAMD64TESTW)
v.AddArg(x)
v.AddArg(x)
return true
}
return false
}
-func rewriteValueAMD64_OpAMD64CMPQ(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpAMD64CMPXCHGLlock(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (CMPQ x (MOVQconst [c]))
- // cond: is32Bit(c)
- // result: (CMPQconst x [c])
+ // match: (CMPXCHGLlock [off1] {sym} (ADDQconst [off2] ptr) old new_ mem)
+ // cond: is32Bit(off1+off2)
+ // result: (CMPXCHGLlock [off1+off2] {sym} ptr old new_ mem)
for {
- x := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64MOVQconst {
+ off1 := v.AuxInt
+ sym := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64ADDQconst {
break
}
- c := v_1.AuxInt
- if !(is32Bit(c)) {
+ off2 := v_0.AuxInt
+ ptr := v_0.Args[0]
+ old := v.Args[1]
+ new_ := v.Args[2]
+ mem := v.Args[3]
+ if !(is32Bit(off1 + off2)) {
break
}
- v.reset(OpAMD64CMPQconst)
- v.AddArg(x)
- v.AuxInt = c
+ v.reset(OpAMD64CMPXCHGLlock)
+ v.AuxInt = off1 + off2
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(old)
+ v.AddArg(new_)
+ v.AddArg(mem)
return true
}
- // match: (CMPQ (MOVQconst [c]) x)
- // cond: is32Bit(c)
- // result: (InvertFlags (CMPQconst x [c]))
+ return false
+}
+func rewriteValueAMD64_OpAMD64CMPXCHGQlock(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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_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]
+ old := v.Args[1]
+ new_ := v.Args[2]
+ mem := v.Args[3]
+ if !(is32Bit(off1 + off2)) {
break
}
- v.reset(OpAMD64InvertFlags)
- v0 := b.NewValue0(v.Line, OpAMD64CMPQconst, TypeFlags)
- v0.AddArg(x)
- v0.AuxInt = c
- v.AddArg(v0)
+ v.reset(OpAMD64CMPXCHGQlock)
+ v.AuxInt = off1 + off2
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(old)
+ v.AddArg(new_)
+ v.AddArg(mem)
return true
}
return false
}
-func rewriteValueAMD64_OpAMD64CMPQconst(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpAMD64LEAL(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (CMPQconst (MOVQconst [x]) [y])
- // cond: x==y
- // result: (FlagEQ)
+ // match: (LEAL [c] {s} (ADDLconst [d] x))
+ // cond: is32Bit(c+d)
+ // result: (LEAL [c+d] {s} x)
for {
+ c := v.AuxInt
+ s := v.Aux
v_0 := v.Args[0]
- if v_0.Op != OpAMD64MOVQconst {
+ if v_0.Op != OpAMD64ADDLconst {
break
}
- x := v_0.AuxInt
- y := v.AuxInt
- if !(x == y) {
+ d := v_0.AuxInt
+ x := v_0.Args[0]
+ if !(is32Bit(c + d)) {
break
}
- v.reset(OpAMD64FlagEQ)
+ v.reset(OpAMD64LEAL)
+ v.AuxInt = c + d
+ v.Aux = s
+ v.AddArg(x)
return true
}
- // match: (CMPQconst (MOVQconst [x]) [y])
- // cond: x<y && uint64(x)<uint64(y)
- // result: (FlagLT_ULT)
+ return false
+}
+func rewriteValueAMD64_OpAMD64LEAQ(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (LEAQ [c] {s} (ADDQconst [d] x))
+ // cond: is32Bit(c+d)
+ // result: (LEAQ [c+d] {s} x)
for {
+ c := v.AuxInt
+ s := v.Aux
v_0 := v.Args[0]
- if v_0.Op != OpAMD64MOVQconst {
+ if v_0.Op != OpAMD64ADDQconst {
break
}
- x := v_0.AuxInt
- y := v.AuxInt
- if !(x < y && uint64(x) < uint64(y)) {
+ d := v_0.AuxInt
+ x := v_0.Args[0]
+ if !(is32Bit(c + d)) {
break
}
- v.reset(OpAMD64FlagLT_ULT)
+ v.reset(OpAMD64LEAQ)
+ v.AuxInt = c + d
+ v.Aux = s
+ v.AddArg(x)
return true
}
- // match: (CMPQconst (MOVQconst [x]) [y])
- // cond: x<y && uint64(x)>uint64(y)
- // result: (FlagLT_UGT)
- for {
+ // match: (LEAQ [c] {s} (ADDQ x y))
+ // cond: x.Op != OpSB && y.Op != OpSB
+ // result: (LEAQ1 [c] {s} x y)
+ for {
+ c := v.AuxInt
+ s := v.Aux
v_0 := v.Args[0]
- if v_0.Op != OpAMD64MOVQconst {
+ if v_0.Op != OpAMD64ADDQ {
break
}
- x := v_0.AuxInt
- y := v.AuxInt
- if !(x < y && uint64(x) > uint64(y)) {
+ x := v_0.Args[0]
+ y := v_0.Args[1]
+ if !(x.Op != OpSB && y.Op != OpSB) {
break
}
- v.reset(OpAMD64FlagLT_UGT)
+ v.reset(OpAMD64LEAQ1)
+ v.AuxInt = c
+ v.Aux = s
+ v.AddArg(x)
+ v.AddArg(y)
return true
}
- // match: (CMPQconst (MOVQconst [x]) [y])
- // cond: x>y && uint64(x)<uint64(y)
- // result: (FlagGT_ULT)
+ // match: (LEAQ [off1] {sym1} (LEAQ [off2] {sym2} x))
+ // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+ // result: (LEAQ [off1+off2] {mergeSym(sym1,sym2)} x)
for {
+ off1 := v.AuxInt
+ sym1 := v.Aux
v_0 := v.Args[0]
- if v_0.Op != OpAMD64MOVQconst {
+ if v_0.Op != OpAMD64LEAQ {
break
}
- x := v_0.AuxInt
- y := v.AuxInt
- if !(x > y && uint64(x) < uint64(y)) {
+ off2 := v_0.AuxInt
+ sym2 := v_0.Aux
+ x := v_0.Args[0]
+ if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
break
}
- v.reset(OpAMD64FlagGT_ULT)
+ v.reset(OpAMD64LEAQ)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(x)
return true
}
- // match: (CMPQconst (MOVQconst [x]) [y])
- // cond: x>y && uint64(x)>uint64(y)
- // result: (FlagGT_UGT)
+ // match: (LEAQ [off1] {sym1} (LEAQ1 [off2] {sym2} x y))
+ // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+ // result: (LEAQ1 [off1+off2] {mergeSym(sym1,sym2)} x y)
for {
+ off1 := v.AuxInt
+ sym1 := v.Aux
v_0 := v.Args[0]
- if v_0.Op != OpAMD64MOVQconst {
+ if v_0.Op != OpAMD64LEAQ1 {
break
}
- x := v_0.AuxInt
- y := v.AuxInt
- if !(x > y && uint64(x) > uint64(y)) {
+ off2 := v_0.AuxInt
+ sym2 := v_0.Aux
+ x := v_0.Args[0]
+ y := v_0.Args[1]
+ if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
break
}
- v.reset(OpAMD64FlagGT_UGT)
+ v.reset(OpAMD64LEAQ1)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(x)
+ v.AddArg(y)
return true
}
- // match: (CMPQconst (MOVBQZX _) [c])
- // cond: 0xFF < c
- // result: (FlagLT_ULT)
+ // match: (LEAQ [off1] {sym1} (LEAQ2 [off2] {sym2} x y))
+ // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+ // result: (LEAQ2 [off1+off2] {mergeSym(sym1,sym2)} x y)
for {
+ off1 := v.AuxInt
+ sym1 := v.Aux
v_0 := v.Args[0]
- if v_0.Op != OpAMD64MOVBQZX {
+ if v_0.Op != OpAMD64LEAQ2 {
break
}
- c := v.AuxInt
- if !(0xFF < c) {
+ off2 := v_0.AuxInt
+ sym2 := v_0.Aux
+ x := v_0.Args[0]
+ y := v_0.Args[1]
+ if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
break
}
- v.reset(OpAMD64FlagLT_ULT)
+ v.reset(OpAMD64LEAQ2)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(x)
+ v.AddArg(y)
return true
}
- // match: (CMPQconst (MOVWQZX _) [c])
- // cond: 0xFFFF < c
- // result: (FlagLT_ULT)
+ // match: (LEAQ [off1] {sym1} (LEAQ4 [off2] {sym2} x y))
+ // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+ // result: (LEAQ4 [off1+off2] {mergeSym(sym1,sym2)} x y)
for {
+ off1 := v.AuxInt
+ sym1 := v.Aux
v_0 := v.Args[0]
- if v_0.Op != OpAMD64MOVWQZX {
+ if v_0.Op != OpAMD64LEAQ4 {
break
}
- c := v.AuxInt
- if !(0xFFFF < c) {
+ off2 := v_0.AuxInt
+ sym2 := v_0.Aux
+ x := v_0.Args[0]
+ y := v_0.Args[1]
+ if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
break
}
- v.reset(OpAMD64FlagLT_ULT)
+ v.reset(OpAMD64LEAQ4)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(x)
+ v.AddArg(y)
return true
}
- // match: (CMPQconst (MOVLQZX _) [c])
- // cond: 0xFFFFFFFF < c
- // result: (FlagLT_ULT)
+ // match: (LEAQ [off1] {sym1} (LEAQ8 [off2] {sym2} x y))
+ // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+ // result: (LEAQ8 [off1+off2] {mergeSym(sym1,sym2)} x y)
for {
+ off1 := v.AuxInt
+ sym1 := v.Aux
v_0 := v.Args[0]
- if v_0.Op != OpAMD64MOVLQZX {
+ if v_0.Op != OpAMD64LEAQ8 {
break
}
- c := v.AuxInt
- if !(0xFFFFFFFF < c) {
+ off2 := v_0.AuxInt
+ sym2 := v_0.Aux
+ x := v_0.Args[0]
+ y := v_0.Args[1]
+ if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
break
}
- v.reset(OpAMD64FlagLT_ULT)
+ v.reset(OpAMD64LEAQ8)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(x)
+ v.AddArg(y)
return true
}
- // match: (CMPQconst (SHRQconst _ [c]) [n])
- // cond: 0 <= n && 0 < c && c <= 64 && (1<<uint64(64-c)) <= uint64(n)
- // result: (FlagLT_ULT)
+ return false
+}
+func rewriteValueAMD64_OpAMD64LEAQ1(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (LEAQ1 [c] {s} (ADDQconst [d] x) y)
+ // cond: is32Bit(c+d) && x.Op != OpSB
+ // result: (LEAQ1 [c+d] {s} x y)
for {
+ c := v.AuxInt
+ s := v.Aux
v_0 := v.Args[0]
- if v_0.Op != OpAMD64SHRQconst {
+ if v_0.Op != OpAMD64ADDQconst {
break
}
- c := v_0.AuxInt
- n := v.AuxInt
- if !(0 <= n && 0 < c && c <= 64 && (1<<uint64(64-c)) <= uint64(n)) {
+ d := v_0.AuxInt
+ x := v_0.Args[0]
+ y := v.Args[1]
+ if !(is32Bit(c+d) && x.Op != OpSB) {
break
}
- v.reset(OpAMD64FlagLT_ULT)
+ v.reset(OpAMD64LEAQ1)
+ v.AuxInt = c + d
+ v.Aux = s
+ v.AddArg(x)
+ v.AddArg(y)
return true
}
- // match: (CMPQconst (ANDQconst _ [m]) [n])
- // cond: 0 <= m && m < n
- // result: (FlagLT_ULT)
+ // match: (LEAQ1 [c] {s} x (ADDQconst [d] y))
+ // cond: is32Bit(c+d) && y.Op != OpSB
+ // result: (LEAQ1 [c+d] {s} x y)
for {
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64ANDQconst {
+ c := v.AuxInt
+ s := v.Aux
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64ADDQconst {
break
}
- m := v_0.AuxInt
- n := v.AuxInt
- if !(0 <= m && m < n) {
+ d := v_1.AuxInt
+ y := v_1.Args[0]
+ if !(is32Bit(c+d) && y.Op != OpSB) {
break
}
- v.reset(OpAMD64FlagLT_ULT)
+ v.reset(OpAMD64LEAQ1)
+ v.AuxInt = c + d
+ v.Aux = s
+ v.AddArg(x)
+ v.AddArg(y)
return true
}
- // match: (CMPQconst (ANDQ x y) [0])
+ // match: (LEAQ1 [c] {s} x (SHLQconst [1] y))
// cond:
- // result: (TESTQ x y)
+ // result: (LEAQ2 [c] {s} x y)
for {
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64ANDQ {
+ c := v.AuxInt
+ s := v.Aux
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64SHLQconst {
break
}
- x := v_0.Args[0]
- y := v_0.Args[1]
- if v.AuxInt != 0 {
+ if v_1.AuxInt != 1 {
break
}
- v.reset(OpAMD64TESTQ)
+ y := v_1.Args[0]
+ v.reset(OpAMD64LEAQ2)
+ v.AuxInt = c
+ v.Aux = s
v.AddArg(x)
v.AddArg(y)
return true
}
- // match: (CMPQconst (ANDQconst [c] x) [0])
+ // match: (LEAQ1 [c] {s} (SHLQconst [1] x) y)
// cond:
- // result: (TESTQconst [c] x)
+ // result: (LEAQ2 [c] {s} y x)
for {
+ c := v.AuxInt
+ s := v.Aux
v_0 := v.Args[0]
- if v_0.Op != OpAMD64ANDQconst {
+ if v_0.Op != OpAMD64SHLQconst {
break
}
- c := v_0.AuxInt
- x := v_0.Args[0]
- if v.AuxInt != 0 {
+ if v_0.AuxInt != 1 {
break
}
- v.reset(OpAMD64TESTQconst)
+ x := v_0.Args[0]
+ y := v.Args[1]
+ v.reset(OpAMD64LEAQ2)
v.AuxInt = c
+ v.Aux = s
+ v.AddArg(y)
v.AddArg(x)
return true
}
- // match: (CMPQconst x [0])
+ // match: (LEAQ1 [c] {s} x (SHLQconst [2] y))
// cond:
- // result: (TESTQ x x)
+ // result: (LEAQ4 [c] {s} x y)
for {
+ c := v.AuxInt
+ s := v.Aux
x := v.Args[0]
- if v.AuxInt != 0 {
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64SHLQconst {
break
}
- v.reset(OpAMD64TESTQ)
- v.AddArg(x)
+ if v_1.AuxInt != 2 {
+ break
+ }
+ y := v_1.Args[0]
+ v.reset(OpAMD64LEAQ4)
+ v.AuxInt = c
+ v.Aux = s
v.AddArg(x)
+ v.AddArg(y)
return true
}
- return false
-}
-func rewriteValueAMD64_OpAMD64CMPW(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (CMPW x (MOVLconst [c]))
+ // match: (LEAQ1 [c] {s} (SHLQconst [2] x) y)
// cond:
- // result: (CMPWconst x [int64(int16(c))])
+ // result: (LEAQ4 [c] {s} y x)
for {
- x := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64MOVLconst {
+ c := v.AuxInt
+ s := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64SHLQconst {
break
}
- c := v_1.AuxInt
- v.reset(OpAMD64CMPWconst)
- v.AddArg(x)
- v.AuxInt = int64(int16(c))
- return true
- }
- // match: (CMPW (MOVLconst [c]) x)
- // cond:
- // result: (InvertFlags (CMPWconst x [int64(int16(c))]))
- for {
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64MOVLconst {
+ if v_0.AuxInt != 2 {
break
}
- c := v_0.AuxInt
- x := v.Args[1]
- v.reset(OpAMD64InvertFlags)
- v0 := b.NewValue0(v.Line, OpAMD64CMPWconst, TypeFlags)
- v0.AddArg(x)
- v0.AuxInt = int64(int16(c))
- v.AddArg(v0)
+ x := v_0.Args[0]
+ y := v.Args[1]
+ v.reset(OpAMD64LEAQ4)
+ v.AuxInt = c
+ v.Aux = s
+ v.AddArg(y)
+ v.AddArg(x)
return true
}
- return false
-}
-func rewriteValueAMD64_OpAMD64CMPWconst(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (CMPWconst (MOVLconst [x]) [y])
- // cond: int16(x)==int16(y)
- // result: (FlagEQ)
+ // match: (LEAQ1 [c] {s} x (SHLQconst [3] y))
+ // cond:
+ // result: (LEAQ8 [c] {s} x y)
for {
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64MOVLconst {
+ c := v.AuxInt
+ s := v.Aux
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64SHLQconst {
break
}
- x := v_0.AuxInt
- y := v.AuxInt
- if !(int16(x) == int16(y)) {
+ if v_1.AuxInt != 3 {
break
}
- v.reset(OpAMD64FlagEQ)
+ y := v_1.Args[0]
+ v.reset(OpAMD64LEAQ8)
+ v.AuxInt = c
+ v.Aux = s
+ v.AddArg(x)
+ v.AddArg(y)
return true
}
- // match: (CMPWconst (MOVLconst [x]) [y])
- // cond: int16(x)<int16(y) && uint16(x)<uint16(y)
- // result: (FlagLT_ULT)
+ // match: (LEAQ1 [c] {s} (SHLQconst [3] x) y)
+ // cond:
+ // result: (LEAQ8 [c] {s} y x)
for {
+ c := v.AuxInt
+ s := v.Aux
v_0 := v.Args[0]
- if v_0.Op != OpAMD64MOVLconst {
+ if v_0.Op != OpAMD64SHLQconst {
break
}
- x := v_0.AuxInt
- y := v.AuxInt
- if !(int16(x) < int16(y) && uint16(x) < uint16(y)) {
+ if v_0.AuxInt != 3 {
break
}
- v.reset(OpAMD64FlagLT_ULT)
+ x := v_0.Args[0]
+ y := v.Args[1]
+ v.reset(OpAMD64LEAQ8)
+ v.AuxInt = c
+ v.Aux = s
+ v.AddArg(y)
+ v.AddArg(x)
return true
}
- // match: (CMPWconst (MOVLconst [x]) [y])
- // cond: int16(x)<int16(y) && uint16(x)>uint16(y)
- // result: (FlagLT_UGT)
+ // match: (LEAQ1 [off1] {sym1} (LEAQ [off2] {sym2} x) y)
+ // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2) && x.Op != OpSB
+ // result: (LEAQ1 [off1+off2] {mergeSym(sym1,sym2)} x y)
for {
+ off1 := v.AuxInt
+ sym1 := v.Aux
v_0 := v.Args[0]
- if v_0.Op != OpAMD64MOVLconst {
+ if v_0.Op != OpAMD64LEAQ {
break
}
- x := v_0.AuxInt
- y := v.AuxInt
- if !(int16(x) < int16(y) && uint16(x) > uint16(y)) {
+ 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(OpAMD64FlagLT_UGT)
+ v.reset(OpAMD64LEAQ1)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(x)
+ v.AddArg(y)
return true
}
- // match: (CMPWconst (MOVLconst [x]) [y])
- // cond: int16(x)>int16(y) && uint16(x)<uint16(y)
- // result: (FlagGT_ULT)
+ // match: (LEAQ1 [off1] {sym1} x (LEAQ [off2] {sym2} y))
+ // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2) && y.Op != OpSB
+ // result: (LEAQ1 [off1+off2] {mergeSym(sym1,sym2)} x y)
for {
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64MOVLconst {
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64LEAQ {
break
}
- x := v_0.AuxInt
- y := v.AuxInt
- if !(int16(x) > int16(y) && uint16(x) < uint16(y)) {
+ 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(OpAMD64FlagGT_ULT)
+ v.reset(OpAMD64LEAQ1)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(x)
+ v.AddArg(y)
return true
}
- // match: (CMPWconst (MOVLconst [x]) [y])
- // cond: int16(x)>int16(y) && uint16(x)>uint16(y)
- // result: (FlagGT_UGT)
+ return false
+}
+func rewriteValueAMD64_OpAMD64LEAQ2(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (LEAQ2 [c] {s} (ADDQconst [d] x) y)
+ // cond: is32Bit(c+d) && x.Op != OpSB
+ // result: (LEAQ2 [c+d] {s} x y)
for {
+ c := v.AuxInt
+ s := v.Aux
v_0 := v.Args[0]
- if v_0.Op != OpAMD64MOVLconst {
+ if v_0.Op != OpAMD64ADDQconst {
break
}
- x := v_0.AuxInt
- y := v.AuxInt
- if !(int16(x) > int16(y) && uint16(x) > uint16(y)) {
+ d := v_0.AuxInt
+ x := v_0.Args[0]
+ y := v.Args[1]
+ if !(is32Bit(c+d) && x.Op != OpSB) {
break
}
- v.reset(OpAMD64FlagGT_UGT)
+ v.reset(OpAMD64LEAQ2)
+ v.AuxInt = c + d
+ v.Aux = s
+ v.AddArg(x)
+ v.AddArg(y)
return true
}
- // match: (CMPWconst (ANDLconst _ [m]) [n])
- // cond: 0 <= int16(m) && int16(m) < int16(n)
- // result: (FlagLT_ULT)
+ // match: (LEAQ2 [c] {s} x (ADDQconst [d] y))
+ // cond: is32Bit(c+2*d) && y.Op != OpSB
+ // result: (LEAQ2 [c+2*d] {s} x y)
for {
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64ANDLconst {
+ c := v.AuxInt
+ s := v.Aux
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64ADDQconst {
break
}
- m := v_0.AuxInt
- n := v.AuxInt
- if !(0 <= int16(m) && int16(m) < int16(n)) {
+ d := v_1.AuxInt
+ y := v_1.Args[0]
+ if !(is32Bit(c+2*d) && y.Op != OpSB) {
break
}
- v.reset(OpAMD64FlagLT_ULT)
+ v.reset(OpAMD64LEAQ2)
+ v.AuxInt = c + 2*d
+ v.Aux = s
+ v.AddArg(x)
+ v.AddArg(y)
return true
}
- // match: (CMPWconst (ANDL x y) [0])
+ // match: (LEAQ2 [c] {s} x (SHLQconst [1] y))
// cond:
- // result: (TESTW x y)
+ // result: (LEAQ4 [c] {s} x y)
for {
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64ANDL {
+ c := v.AuxInt
+ s := v.Aux
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64SHLQconst {
break
}
- x := v_0.Args[0]
- y := v_0.Args[1]
- if v.AuxInt != 0 {
+ if v_1.AuxInt != 1 {
break
}
- v.reset(OpAMD64TESTW)
+ y := v_1.Args[0]
+ v.reset(OpAMD64LEAQ4)
+ v.AuxInt = c
+ v.Aux = s
v.AddArg(x)
v.AddArg(y)
return true
}
- // match: (CMPWconst (ANDLconst [c] x) [0])
+ // match: (LEAQ2 [c] {s} x (SHLQconst [2] y))
// cond:
- // result: (TESTWconst [int64(int16(c))] x)
+ // result: (LEAQ8 [c] {s} x y)
for {
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64ANDLconst {
+ c := v.AuxInt
+ s := v.Aux
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64SHLQconst {
break
}
- c := v_0.AuxInt
- x := v_0.Args[0]
- if v.AuxInt != 0 {
+ if v_1.AuxInt != 2 {
break
}
- v.reset(OpAMD64TESTWconst)
- v.AuxInt = int64(int16(c))
+ y := v_1.Args[0]
+ v.reset(OpAMD64LEAQ8)
+ v.AuxInt = c
+ v.Aux = s
v.AddArg(x)
+ v.AddArg(y)
return true
}
- // match: (CMPWconst x [0])
- // cond:
- // result: (TESTW x x)
+ // match: (LEAQ2 [off1] {sym1} (LEAQ [off2] {sym2} x) y)
+ // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2) && x.Op != OpSB
+ // result: (LEAQ2 [off1+off2] {mergeSym(sym1,sym2)} x y)
for {
- x := v.Args[0]
- if v.AuxInt != 0 {
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64LEAQ {
break
}
- v.reset(OpAMD64TESTW)
- v.AddArg(x)
+ off2 := v_0.AuxInt
+ sym2 := v_0.Aux
+ x := v_0.Args[0]
+ y := v.Args[1]
+ if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2) && x.Op != OpSB) {
+ break
+ }
+ v.reset(OpAMD64LEAQ2)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
v.AddArg(x)
+ v.AddArg(y)
return true
}
return false
}
-func rewriteValueAMD64_OpClosureCall(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpAMD64LEAQ4(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (ClosureCall [argwid] entry closure mem)
- // cond:
- // result: (CALLclosure [argwid] entry closure mem)
- for {
- argwid := v.AuxInt
- entry := v.Args[0]
- closure := v.Args[1]
- mem := v.Args[2]
- v.reset(OpAMD64CALLclosure)
- v.AuxInt = argwid
- v.AddArg(entry)
- v.AddArg(closure)
- v.AddArg(mem)
- return true
- }
-}
-func rewriteValueAMD64_OpCom16(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Com16 x)
- // cond:
- // result: (NOTL x)
+ // match: (LEAQ4 [c] {s} (ADDQconst [d] x) y)
+ // cond: is32Bit(c+d) && x.Op != OpSB
+ // result: (LEAQ4 [c+d] {s} x y)
for {
- x := v.Args[0]
- v.reset(OpAMD64NOTL)
+ c := v.AuxInt
+ s := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64ADDQconst {
+ break
+ }
+ d := v_0.AuxInt
+ x := v_0.Args[0]
+ y := v.Args[1]
+ if !(is32Bit(c+d) && x.Op != OpSB) {
+ break
+ }
+ v.reset(OpAMD64LEAQ4)
+ v.AuxInt = c + d
+ v.Aux = s
v.AddArg(x)
+ v.AddArg(y)
return true
}
-}
-func rewriteValueAMD64_OpCom32(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Com32 x)
- // cond:
- // result: (NOTL x)
+ // match: (LEAQ4 [c] {s} x (ADDQconst [d] y))
+ // cond: is32Bit(c+4*d) && y.Op != OpSB
+ // result: (LEAQ4 [c+4*d] {s} x y)
for {
+ c := v.AuxInt
+ s := v.Aux
x := v.Args[0]
- v.reset(OpAMD64NOTL)
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64ADDQconst {
+ break
+ }
+ d := v_1.AuxInt
+ y := v_1.Args[0]
+ if !(is32Bit(c+4*d) && y.Op != OpSB) {
+ break
+ }
+ v.reset(OpAMD64LEAQ4)
+ v.AuxInt = c + 4*d
+ v.Aux = s
v.AddArg(x)
+ v.AddArg(y)
return true
}
-}
-func rewriteValueAMD64_OpCom64(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Com64 x)
+ // match: (LEAQ4 [c] {s} x (SHLQconst [1] y))
// cond:
- // result: (NOTQ x)
+ // result: (LEAQ8 [c] {s} x y)
for {
+ c := v.AuxInt
+ s := v.Aux
x := v.Args[0]
- v.reset(OpAMD64NOTQ)
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64SHLQconst {
+ break
+ }
+ if v_1.AuxInt != 1 {
+ break
+ }
+ y := v_1.Args[0]
+ v.reset(OpAMD64LEAQ8)
+ v.AuxInt = c
+ v.Aux = s
v.AddArg(x)
+ v.AddArg(y)
return true
}
-}
-func rewriteValueAMD64_OpCom8(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Com8 x)
- // cond:
- // result: (NOTL x)
+ // match: (LEAQ4 [off1] {sym1} (LEAQ [off2] {sym2} x) y)
+ // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2) && x.Op != OpSB
+ // result: (LEAQ4 [off1+off2] {mergeSym(sym1,sym2)} x y)
for {
- x := v.Args[0]
- v.reset(OpAMD64NOTL)
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64LEAQ {
+ break
+ }
+ off2 := v_0.AuxInt
+ sym2 := v_0.Aux
+ x := v_0.Args[0]
+ y := v.Args[1]
+ if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2) && x.Op != OpSB) {
+ break
+ }
+ v.reset(OpAMD64LEAQ4)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
v.AddArg(x)
+ v.AddArg(y)
return true
}
+ return false
}
-func rewriteValueAMD64_OpConst16(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpAMD64LEAQ8(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (Const16 [val])
- // cond:
- // result: (MOVLconst [val])
+ // match: (LEAQ8 [c] {s} (ADDQconst [d] x) y)
+ // cond: is32Bit(c+d) && x.Op != OpSB
+ // result: (LEAQ8 [c+d] {s} x y)
for {
- val := v.AuxInt
- v.reset(OpAMD64MOVLconst)
- v.AuxInt = val
+ c := v.AuxInt
+ s := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64ADDQconst {
+ break
+ }
+ d := v_0.AuxInt
+ x := v_0.Args[0]
+ y := v.Args[1]
+ if !(is32Bit(c+d) && x.Op != OpSB) {
+ break
+ }
+ v.reset(OpAMD64LEAQ8)
+ v.AuxInt = c + d
+ v.Aux = s
+ v.AddArg(x)
+ v.AddArg(y)
return true
}
-}
-func rewriteValueAMD64_OpConst32(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Const32 [val])
- // cond:
- // result: (MOVLconst [val])
+ // match: (LEAQ8 [c] {s} x (ADDQconst [d] y))
+ // cond: is32Bit(c+8*d) && y.Op != OpSB
+ // result: (LEAQ8 [c+8*d] {s} x y)
for {
- val := v.AuxInt
- v.reset(OpAMD64MOVLconst)
- v.AuxInt = val
+ c := v.AuxInt
+ s := v.Aux
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64ADDQconst {
+ break
+ }
+ d := v_1.AuxInt
+ y := v_1.Args[0]
+ if !(is32Bit(c+8*d) && y.Op != OpSB) {
+ break
+ }
+ v.reset(OpAMD64LEAQ8)
+ v.AuxInt = c + 8*d
+ v.Aux = s
+ v.AddArg(x)
+ v.AddArg(y)
return true
}
-}
-func rewriteValueAMD64_OpConst32F(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Const32F [val])
- // cond:
- // result: (MOVSSconst [val])
+ // match: (LEAQ8 [off1] {sym1} (LEAQ [off2] {sym2} x) y)
+ // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2) && x.Op != OpSB
+ // result: (LEAQ8 [off1+off2] {mergeSym(sym1,sym2)} x y)
for {
- val := v.AuxInt
- v.reset(OpAMD64MOVSSconst)
- v.AuxInt = val
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64LEAQ {
+ break
+ }
+ off2 := v_0.AuxInt
+ sym2 := v_0.Aux
+ x := v_0.Args[0]
+ y := v.Args[1]
+ if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2) && x.Op != OpSB) {
+ break
+ }
+ v.reset(OpAMD64LEAQ8)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(x)
+ v.AddArg(y)
return true
}
+ return false
}
-func rewriteValueAMD64_OpConst64(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpAMD64MOVBQSX(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (Const64 [val])
- // cond:
- // result: (MOVQconst [val])
+ // match: (MOVBQSX x:(MOVBload [off] {sym} ptr mem))
+ // cond: x.Uses == 1 && clobber(x)
+ // result: @x.Block (MOVBQSXload <v.Type> [off] {sym} ptr mem)
for {
- val := v.AuxInt
- v.reset(OpAMD64MOVQconst)
- v.AuxInt = val
+ x := v.Args[0]
+ if x.Op != OpAMD64MOVBload {
+ break
+ }
+ off := x.AuxInt
+ sym := x.Aux
+ ptr := x.Args[0]
+ mem := x.Args[1]
+ if !(x.Uses == 1 && clobber(x)) {
+ break
+ }
+ b = x.Block
+ v0 := b.NewValue0(v.Line, OpAMD64MOVBQSXload, v.Type)
+ v.reset(OpCopy)
+ v.AddArg(v0)
+ v0.AuxInt = off
+ v0.Aux = sym
+ v0.AddArg(ptr)
+ v0.AddArg(mem)
return true
}
-}
-func rewriteValueAMD64_OpConst64F(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Const64F [val])
- // cond:
- // result: (MOVSDconst [val])
+ // match: (MOVBQSX x:(MOVWload [off] {sym} ptr mem))
+ // cond: x.Uses == 1 && clobber(x)
+ // result: @x.Block (MOVBQSXload <v.Type> [off] {sym} ptr mem)
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])
+ x := v.Args[0]
+ if x.Op != OpAMD64MOVWload {
+ break
+ }
+ off := x.AuxInt
+ sym := x.Aux
+ ptr := x.Args[0]
+ mem := x.Args[1]
+ if !(x.Uses == 1 && clobber(x)) {
+ break
+ }
+ b = x.Block
+ v0 := b.NewValue0(v.Line, OpAMD64MOVBQSXload, v.Type)
+ v.reset(OpCopy)
+ v.AddArg(v0)
+ v0.AuxInt = off
+ v0.Aux = sym
+ v0.AddArg(ptr)
+ v0.AddArg(mem)
+ return true
+ }
+ // match: (MOVBQSX x:(MOVLload [off] {sym} ptr mem))
+ // cond: x.Uses == 1 && clobber(x)
+ // result: @x.Block (MOVBQSXload <v.Type> [off] {sym} ptr mem)
for {
- val := v.AuxInt
- v.reset(OpAMD64MOVLconst)
- v.AuxInt = val
+ x := v.Args[0]
+ if x.Op != OpAMD64MOVLload {
+ break
+ }
+ off := x.AuxInt
+ sym := x.Aux
+ ptr := x.Args[0]
+ mem := x.Args[1]
+ if !(x.Uses == 1 && clobber(x)) {
+ break
+ }
+ b = x.Block
+ v0 := b.NewValue0(v.Line, OpAMD64MOVBQSXload, v.Type)
+ v.reset(OpCopy)
+ v.AddArg(v0)
+ v0.AuxInt = off
+ v0.Aux = sym
+ v0.AddArg(ptr)
+ 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: (MOVBQSX x:(MOVQload [off] {sym} ptr mem))
+ // cond: x.Uses == 1 && clobber(x)
+ // result: @x.Block (MOVBQSXload <v.Type> [off] {sym} ptr mem)
for {
- b := v.AuxInt
- v.reset(OpAMD64MOVLconst)
- v.AuxInt = b
+ 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)) {
+ break
+ }
+ b = x.Block
+ v0 := b.NewValue0(v.Line, OpAMD64MOVBQSXload, v.Type)
+ v.reset(OpCopy)
+ v.AddArg(v0)
+ v0.AuxInt = off
+ v0.Aux = sym
+ v0.AddArg(ptr)
+ v0.AddArg(mem)
return true
}
-}
-func rewriteValueAMD64_OpConstNil(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (ConstNil)
- // cond:
- // result: (MOVQconst [0])
+ // match: (MOVBQSX (ANDLconst [c] x))
+ // cond: c & 0x80 == 0
+ // result: (ANDLconst [c & 0x7f] x)
for {
- v.reset(OpAMD64MOVQconst)
- v.AuxInt = 0
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64ANDLconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v_0.Args[0]
+ if !(c&0x80 == 0) {
+ break
+ }
+ v.reset(OpAMD64ANDLconst)
+ v.AuxInt = c & 0x7f
+ v.AddArg(x)
return true
}
+ return false
}
-func rewriteValueAMD64_OpConvert(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpAMD64MOVBQSXload(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (Convert <t> x mem)
- // cond:
- // result: (MOVQconvert <t> x mem)
+ // 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 {
- t := v.Type
- x := v.Args[0]
+ 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]
- v.reset(OpAMD64MOVQconvert)
- v.Type = t
- v.AddArg(x)
+ if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
+ break
+ }
+ v.reset(OpAMD64MOVBQSXload)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(base)
v.AddArg(mem)
return true
}
+ return false
}
-func rewriteValueAMD64_OpCtz16(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpAMD64MOVBQZX(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (Ctz16 <t> x)
- // cond:
- // result: (CMOVWEQconst (BSFW <t> x) (CMPWconst x [0]) [16])
+ // match: (MOVBQZX x:(MOVBload [off] {sym} ptr mem))
+ // cond: x.Uses == 1 && clobber(x)
+ // result: @x.Block (MOVBload <v.Type> [off] {sym} ptr mem)
for {
- t := v.Type
x := v.Args[0]
- v.reset(OpAMD64CMOVWEQconst)
- v0 := b.NewValue0(v.Line, OpAMD64BSFW, t)
- v0.AddArg(x)
+ if x.Op != OpAMD64MOVBload {
+ break
+ }
+ off := x.AuxInt
+ sym := x.Aux
+ ptr := x.Args[0]
+ mem := x.Args[1]
+ if !(x.Uses == 1 && clobber(x)) {
+ break
+ }
+ b = x.Block
+ v0 := b.NewValue0(v.Line, OpAMD64MOVBload, v.Type)
+ v.reset(OpCopy)
v.AddArg(v0)
- v1 := b.NewValue0(v.Line, OpAMD64CMPWconst, TypeFlags)
- v1.AddArg(x)
- v1.AuxInt = 0
- v.AddArg(v1)
- v.AuxInt = 16
+ v0.AuxInt = off
+ v0.Aux = sym
+ v0.AddArg(ptr)
+ v0.AddArg(mem)
return true
}
-}
-func rewriteValueAMD64_OpCtz32(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Ctz32 <t> x)
- // cond:
- // result: (CMOVLEQconst (BSFL <t> x) (CMPLconst x [0]) [32])
+ // match: (MOVBQZX x:(MOVWload [off] {sym} ptr mem))
+ // cond: x.Uses == 1 && clobber(x)
+ // result: @x.Block (MOVBload <v.Type> [off] {sym} ptr mem)
for {
- t := v.Type
x := v.Args[0]
- v.reset(OpAMD64CMOVLEQconst)
- v0 := b.NewValue0(v.Line, OpAMD64BSFL, t)
- v0.AddArg(x)
+ if x.Op != OpAMD64MOVWload {
+ break
+ }
+ off := x.AuxInt
+ sym := x.Aux
+ ptr := x.Args[0]
+ mem := x.Args[1]
+ if !(x.Uses == 1 && clobber(x)) {
+ break
+ }
+ b = x.Block
+ v0 := b.NewValue0(v.Line, OpAMD64MOVBload, v.Type)
+ v.reset(OpCopy)
v.AddArg(v0)
- v1 := b.NewValue0(v.Line, OpAMD64CMPLconst, TypeFlags)
- v1.AddArg(x)
- v1.AuxInt = 0
- v.AddArg(v1)
- v.AuxInt = 32
+ v0.AuxInt = off
+ v0.Aux = sym
+ v0.AddArg(ptr)
+ v0.AddArg(mem)
return true
}
-}
-func rewriteValueAMD64_OpCtz64(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Ctz64 <t> x)
- // cond:
- // result: (CMOVQEQconst (BSFQ <t> x) (CMPQconst x [0]) [64])
+ // match: (MOVBQZX x:(MOVLload [off] {sym} ptr mem))
+ // cond: x.Uses == 1 && clobber(x)
+ // result: @x.Block (MOVBload <v.Type> [off] {sym} ptr mem)
for {
- t := v.Type
x := v.Args[0]
- v.reset(OpAMD64CMOVQEQconst)
- v0 := b.NewValue0(v.Line, OpAMD64BSFQ, t)
- v0.AddArg(x)
+ if x.Op != OpAMD64MOVLload {
+ break
+ }
+ off := x.AuxInt
+ sym := x.Aux
+ ptr := x.Args[0]
+ mem := x.Args[1]
+ if !(x.Uses == 1 && clobber(x)) {
+ break
+ }
+ b = x.Block
+ v0 := b.NewValue0(v.Line, OpAMD64MOVBload, v.Type)
+ v.reset(OpCopy)
v.AddArg(v0)
- v1 := b.NewValue0(v.Line, OpAMD64CMPQconst, TypeFlags)
- v1.AddArg(x)
- v1.AuxInt = 0
- v.AddArg(v1)
- v.AuxInt = 64
+ v0.AuxInt = off
+ v0.Aux = sym
+ v0.AddArg(ptr)
+ 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: (MOVBQZX x:(MOVQload [off] {sym} ptr mem))
+ // cond: x.Uses == 1 && clobber(x)
+ // result: @x.Block (MOVBload <v.Type> [off] {sym} ptr mem)
for {
x := v.Args[0]
- v.reset(OpAMD64CVTTSS2SL)
- v.AddArg(x)
+ 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)) {
+ break
+ }
+ b = x.Block
+ v0 := b.NewValue0(v.Line, OpAMD64MOVBload, v.Type)
+ v.reset(OpCopy)
+ v.AddArg(v0)
+ v0.AuxInt = off
+ v0.Aux = sym
+ v0.AddArg(ptr)
+ v0.AddArg(mem)
return true
}
-}
-func rewriteValueAMD64_OpCvt32Fto64(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Cvt32Fto64 x)
- // cond:
- // result: (CVTTSS2SQ x)
+ // match: (MOVBQZX x:(MOVBloadidx1 [off] {sym} ptr idx mem))
+ // cond: x.Uses == 1 && clobber(x)
+ // result: @x.Block (MOVBloadidx1 <v.Type> [off] {sym} ptr idx mem)
for {
x := v.Args[0]
- v.reset(OpAMD64CVTTSS2SQ)
- v.AddArg(x)
+ if x.Op != OpAMD64MOVBloadidx1 {
+ break
+ }
+ off := x.AuxInt
+ sym := x.Aux
+ ptr := x.Args[0]
+ idx := x.Args[1]
+ mem := x.Args[2]
+ if !(x.Uses == 1 && clobber(x)) {
+ break
+ }
+ b = x.Block
+ v0 := b.NewValue0(v.Line, OpAMD64MOVBloadidx1, v.Type)
+ v.reset(OpCopy)
+ v.AddArg(v0)
+ v0.AuxInt = off
+ v0.Aux = sym
+ v0.AddArg(ptr)
+ v0.AddArg(idx)
+ v0.AddArg(mem)
return true
}
-}
-func rewriteValueAMD64_OpCvt32Fto64F(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Cvt32Fto64F x)
+ // match: (MOVBQZX (ANDLconst [c] x))
// cond:
- // result: (CVTSS2SD x)
+ // result: (ANDLconst [c & 0xff] x)
for {
- x := v.Args[0]
- v.reset(OpAMD64CVTSS2SD)
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64ANDLconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v_0.Args[0]
+ v.reset(OpAMD64ANDLconst)
+ v.AuxInt = c & 0xff
v.AddArg(x)
return true
}
+ return false
}
-func rewriteValueAMD64_OpCvt32to32F(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpAMD64MOVBload(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (Cvt32to32F x)
- // cond:
- // result: (CVTSL2SS x)
+ // match: (MOVBload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _))
+ // cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
+ // result: x
for {
- x := v.Args[0]
- v.reset(OpAMD64CVTSL2SS)
+ off := v.AuxInt
+ sym := v.Aux
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64MOVBstore {
+ break
+ }
+ off2 := v_1.AuxInt
+ sym2 := v_1.Aux
+ ptr2 := v_1.Args[0]
+ x := v_1.Args[1]
+ if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = x.Type
v.AddArg(x)
return true
}
-}
-func rewriteValueAMD64_OpCvt32to64F(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Cvt32to64F x)
- // cond:
- // result: (CVTSL2SD x)
+ // match: (MOVBload [off1] {sym} (ADDQconst [off2] ptr) mem)
+ // cond: is32Bit(off1+off2)
+ // result: (MOVBload [off1+off2] {sym} ptr mem)
for {
- x := v.Args[0]
- v.reset(OpAMD64CVTSL2SD)
- v.AddArg(x)
+ off1 := v.AuxInt
+ sym := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64ADDQconst {
+ break
+ }
+ off2 := v_0.AuxInt
+ ptr := v_0.Args[0]
+ mem := v.Args[1]
+ if !(is32Bit(off1 + off2)) {
+ break
+ }
+ v.reset(OpAMD64MOVBload)
+ v.AuxInt = off1 + off2
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(mem)
return true
}
-}
-func rewriteValueAMD64_OpCvt64Fto32(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Cvt64Fto32 x)
- // cond:
- // result: (CVTTSD2SL x)
+ // 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 {
- x := v.Args[0]
- v.reset(OpAMD64CVTTSD2SL)
- v.AddArg(x)
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64LEAQ {
+ break
+ }
+ off2 := v_0.AuxInt
+ sym2 := v_0.Aux
+ base := v_0.Args[0]
+ mem := v.Args[1]
+ if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
+ break
+ }
+ v.reset(OpAMD64MOVBload)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(base)
+ v.AddArg(mem)
return true
}
-}
-func rewriteValueAMD64_OpCvt64Fto32F(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Cvt64Fto32F x)
- // cond:
- // result: (CVTSD2SS x)
+ // match: (MOVBload [off1] {sym1} (LEAQ1 [off2] {sym2} ptr idx) mem)
+ // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+ // result: (MOVBloadidx1 [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem)
for {
- x := v.Args[0]
- v.reset(OpAMD64CVTSD2SS)
- v.AddArg(x)
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64LEAQ1 {
+ break
+ }
+ off2 := v_0.AuxInt
+ sym2 := v_0.Aux
+ ptr := v_0.Args[0]
+ idx := v_0.Args[1]
+ mem := v.Args[1]
+ if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
+ break
+ }
+ v.reset(OpAMD64MOVBloadidx1)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(mem)
return true
}
-}
-func rewriteValueAMD64_OpCvt64Fto64(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Cvt64Fto64 x)
- // cond:
- // result: (CVTTSD2SQ x)
+ // match: (MOVBload [off] {sym} (ADDQ ptr idx) mem)
+ // cond: ptr.Op != OpSB
+ // result: (MOVBloadidx1 [off] {sym} ptr idx mem)
for {
- x := v.Args[0]
- v.reset(OpAMD64CVTTSD2SQ)
- v.AddArg(x)
+ off := v.AuxInt
+ sym := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64ADDQ {
+ break
+ }
+ ptr := v_0.Args[0]
+ idx := v_0.Args[1]
+ mem := v.Args[1]
+ if !(ptr.Op != OpSB) {
+ break
+ }
+ v.reset(OpAMD64MOVBloadidx1)
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(mem)
return true
}
-}
-func rewriteValueAMD64_OpCvt64to32F(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Cvt64to32F x)
- // cond:
- // result: (CVTSQ2SS x)
+ // match: (MOVBload [off1] {sym1} (LEAL [off2] {sym2} base) mem)
+ // cond: canMergeSym(sym1, sym2)
+ // result: (MOVBload [off1+off2] {mergeSym(sym1,sym2)} base mem)
for {
- x := v.Args[0]
- v.reset(OpAMD64CVTSQ2SS)
- v.AddArg(x)
+ 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(OpAMD64MOVBload)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(base)
+ v.AddArg(mem)
+ return true
+ }
+ // 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_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(OpAMD64MOVBload)
+ v.AuxInt = off1 + off2
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(mem)
return true
}
+ return false
}
-func rewriteValueAMD64_OpCvt64to64F(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpAMD64MOVBloadidx1(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (Cvt64to64F x)
+ // match: (MOVBloadidx1 [c] {sym} (ADDQconst [d] ptr) idx mem)
// cond:
- // result: (CVTSQ2SD x)
+ // result: (MOVBloadidx1 [c+d] {sym} ptr idx mem)
for {
- x := v.Args[0]
- v.reset(OpAMD64CVTSQ2SD)
- v.AddArg(x)
- return true
- }
-}
-func rewriteValueAMD64_OpDeferCall(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (DeferCall [argwid] mem)
- // cond:
- // result: (CALLdefer [argwid] mem)
- for {
- argwid := v.AuxInt
- mem := v.Args[0]
- v.reset(OpAMD64CALLdefer)
- v.AuxInt = argwid
+ c := v.AuxInt
+ sym := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64ADDQconst {
+ break
+ }
+ d := v_0.AuxInt
+ ptr := v_0.Args[0]
+ idx := v.Args[1]
+ mem := v.Args[2]
+ v.reset(OpAMD64MOVBloadidx1)
+ v.AuxInt = c + d
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(idx)
v.AddArg(mem)
return true
}
-}
-func rewriteValueAMD64_OpDiv16(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Div16 x y)
+ // match: (MOVBloadidx1 [c] {sym} ptr (ADDQconst [d] idx) mem)
// cond:
- // result: (DIVW x y)
+ // result: (MOVBloadidx1 [c+d] {sym} ptr idx mem)
for {
- x := v.Args[0]
- y := v.Args[1]
- v.reset(OpAMD64DIVW)
- v.AddArg(x)
- v.AddArg(y)
+ c := v.AuxInt
+ sym := v.Aux
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64ADDQconst {
+ break
+ }
+ d := v_1.AuxInt
+ idx := v_1.Args[0]
+ mem := v.Args[2]
+ v.reset(OpAMD64MOVBloadidx1)
+ v.AuxInt = c + d
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(mem)
return true
}
+ return false
}
-func rewriteValueAMD64_OpDiv16u(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpAMD64MOVBstore(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (Div16u x y)
+ // match: (MOVBstore [off] {sym} ptr (MOVBQSX x) mem)
// cond:
- // result: (DIVWU x y)
+ // result: (MOVBstore [off] {sym} ptr x mem)
for {
- x := v.Args[0]
- y := v.Args[1]
- v.reset(OpAMD64DIVWU)
+ off := v.AuxInt
+ sym := v.Aux
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64MOVBQSX {
+ break
+ }
+ x := v_1.Args[0]
+ mem := v.Args[2]
+ v.reset(OpAMD64MOVBstore)
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(ptr)
v.AddArg(x)
- v.AddArg(y)
+ v.AddArg(mem)
return true
}
-}
-func rewriteValueAMD64_OpDiv32(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Div32 x y)
+ // match: (MOVBstore [off] {sym} ptr (MOVBQZX x) mem)
// cond:
- // result: (DIVL x y)
+ // result: (MOVBstore [off] {sym} ptr x mem)
for {
- x := v.Args[0]
- y := v.Args[1]
- v.reset(OpAMD64DIVL)
+ off := v.AuxInt
+ sym := v.Aux
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64MOVBQZX {
+ break
+ }
+ x := v_1.Args[0]
+ mem := v.Args[2]
+ v.reset(OpAMD64MOVBstore)
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(ptr)
v.AddArg(x)
- v.AddArg(y)
+ v.AddArg(mem)
return true
}
-}
-func rewriteValueAMD64_OpDiv32F(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Div32F x y)
- // cond:
- // result: (DIVSS x y)
+ // match: (MOVBstore [off1] {sym} (ADDQconst [off2] ptr) val mem)
+ // cond: is32Bit(off1+off2)
+ // result: (MOVBstore [off1+off2] {sym} ptr val mem)
for {
- x := v.Args[0]
- y := v.Args[1]
- v.reset(OpAMD64DIVSS)
- v.AddArg(x)
- v.AddArg(y)
+ off1 := v.AuxInt
+ sym := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64ADDQconst {
+ break
+ }
+ off2 := v_0.AuxInt
+ ptr := v_0.Args[0]
+ val := v.Args[1]
+ mem := v.Args[2]
+ if !(is32Bit(off1 + off2)) {
+ break
+ }
+ v.reset(OpAMD64MOVBstore)
+ v.AuxInt = off1 + off2
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(val)
+ v.AddArg(mem)
return true
}
-}
-func rewriteValueAMD64_OpDiv32u(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Div32u x y)
- // cond:
- // result: (DIVLU x y)
+ // match: (MOVBstore [off] {sym} ptr (MOVLconst [c]) mem)
+ // cond: validOff(off)
+ // result: (MOVBstoreconst [makeValAndOff(int64(int8(c)),off)] {sym} ptr mem)
for {
- x := v.Args[0]
- y := v.Args[1]
- v.reset(OpAMD64DIVLU)
- v.AddArg(x)
- v.AddArg(y)
+ off := v.AuxInt
+ sym := v.Aux
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64MOVLconst {
+ break
+ }
+ c := v_1.AuxInt
+ mem := v.Args[2]
+ if !(validOff(off)) {
+ break
+ }
+ v.reset(OpAMD64MOVBstoreconst)
+ v.AuxInt = makeValAndOff(int64(int8(c)), off)
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(mem)
return true
}
-}
-func rewriteValueAMD64_OpDiv64(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Div64 x y)
- // cond:
- // result: (DIVQ x y)
+ // 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 {
- x := v.Args[0]
- y := v.Args[1]
- v.reset(OpAMD64DIVQ)
- v.AddArg(x)
- v.AddArg(y)
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64LEAQ {
+ break
+ }
+ off2 := v_0.AuxInt
+ sym2 := v_0.Aux
+ base := v_0.Args[0]
+ val := v.Args[1]
+ mem := v.Args[2]
+ if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
+ break
+ }
+ v.reset(OpAMD64MOVBstore)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(base)
+ v.AddArg(val)
+ v.AddArg(mem)
return true
}
-}
-func rewriteValueAMD64_OpDiv64F(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Div64F x y)
- // cond:
- // result: (DIVSD x y)
+ // match: (MOVBstore [off1] {sym1} (LEAQ1 [off2] {sym2} ptr idx) val mem)
+ // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+ // result: (MOVBstoreidx1 [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem)
for {
- x := v.Args[0]
- y := v.Args[1]
- v.reset(OpAMD64DIVSD)
- v.AddArg(x)
- v.AddArg(y)
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64LEAQ1 {
+ break
+ }
+ off2 := v_0.AuxInt
+ sym2 := v_0.Aux
+ ptr := v_0.Args[0]
+ idx := v_0.Args[1]
+ val := v.Args[1]
+ mem := v.Args[2]
+ if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
+ break
+ }
+ v.reset(OpAMD64MOVBstoreidx1)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(val)
+ v.AddArg(mem)
return true
}
-}
-func rewriteValueAMD64_OpDiv64u(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Div64u x y)
- // cond:
- // result: (DIVQU x y)
+ // match: (MOVBstore [off] {sym} (ADDQ ptr idx) val mem)
+ // cond: ptr.Op != OpSB
+ // result: (MOVBstoreidx1 [off] {sym} ptr idx val mem)
for {
- x := v.Args[0]
- y := v.Args[1]
- v.reset(OpAMD64DIVQU)
- v.AddArg(x)
- v.AddArg(y)
- return true
- }
-}
-func rewriteValueAMD64_OpDiv8(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Div8 x y)
- // cond:
- // result: (DIVW (SignExt8to16 x) (SignExt8to16 y))
- for {
- x := v.Args[0]
- y := v.Args[1]
- v.reset(OpAMD64DIVW)
- v0 := b.NewValue0(v.Line, OpSignExt8to16, config.fe.TypeInt16())
- v0.AddArg(x)
- v.AddArg(v0)
- v1 := b.NewValue0(v.Line, OpSignExt8to16, config.fe.TypeInt16())
- v1.AddArg(y)
- v.AddArg(v1)
+ off := v.AuxInt
+ sym := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64ADDQ {
+ break
+ }
+ ptr := v_0.Args[0]
+ idx := v_0.Args[1]
+ val := v.Args[1]
+ mem := v.Args[2]
+ if !(ptr.Op != OpSB) {
+ break
+ }
+ v.reset(OpAMD64MOVBstoreidx1)
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(val)
+ v.AddArg(mem)
return true
}
-}
-func rewriteValueAMD64_OpDiv8u(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Div8u x y)
- // cond:
- // result: (DIVWU (ZeroExt8to16 x) (ZeroExt8to16 y))
+ // 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 {
- x := v.Args[0]
- y := v.Args[1]
- v.reset(OpAMD64DIVWU)
- v0 := b.NewValue0(v.Line, OpZeroExt8to16, config.fe.TypeUInt16())
- v0.AddArg(x)
+ i := v.AuxInt
+ s := v.Aux
+ p := v.Args[0]
+ w := v.Args[1]
+ x2 := v.Args[2]
+ if x2.Op != OpAMD64MOVBstore {
+ break
+ }
+ if x2.AuxInt != i-1 {
+ break
+ }
+ if x2.Aux != s {
+ break
+ }
+ if p != x2.Args[0] {
+ break
+ }
+ x2_1 := x2.Args[1]
+ if x2_1.Op != OpAMD64SHRLconst {
+ break
+ }
+ if x2_1.AuxInt != 8 {
+ break
+ }
+ if w != x2_1.Args[0] {
+ break
+ }
+ x1 := x2.Args[2]
+ if x1.Op != OpAMD64MOVBstore {
+ break
+ }
+ if x1.AuxInt != i-2 {
+ break
+ }
+ if x1.Aux != s {
+ break
+ }
+ if p != x1.Args[0] {
+ break
+ }
+ x1_1 := x1.Args[1]
+ if x1_1.Op != OpAMD64SHRLconst {
+ break
+ }
+ if x1_1.AuxInt != 16 {
+ break
+ }
+ if w != x1_1.Args[0] {
+ break
+ }
+ x0 := x1.Args[2]
+ if x0.Op != OpAMD64MOVBstore {
+ break
+ }
+ if x0.AuxInt != i-3 {
+ break
+ }
+ if x0.Aux != s {
+ break
+ }
+ if p != x0.Args[0] {
+ break
+ }
+ x0_1 := x0.Args[1]
+ if x0_1.Op != OpAMD64SHRLconst {
+ break
+ }
+ if x0_1.AuxInt != 24 {
+ break
+ }
+ if w != x0_1.Args[0] {
+ break
+ }
+ mem := x0.Args[2]
+ if !(x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && clobber(x0) && clobber(x1) && clobber(x2)) {
+ break
+ }
+ v.reset(OpAMD64MOVLstore)
+ v.AuxInt = i - 3
+ v.Aux = s
+ v.AddArg(p)
+ v0 := b.NewValue0(v.Line, OpAMD64BSWAPL, w.Type)
+ v0.AddArg(w)
v.AddArg(v0)
- v1 := b.NewValue0(v.Line, OpZeroExt8to16, config.fe.TypeUInt16())
- v1.AddArg(y)
- v.AddArg(v1)
+ v.AddArg(mem)
return true
}
-}
-func rewriteValueAMD64_OpEq16(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Eq16 x y)
- // cond:
- // result: (SETEQ (CMPW x y))
+ // 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 {
- x := v.Args[0]
- y := v.Args[1]
- v.reset(OpAMD64SETEQ)
- v0 := b.NewValue0(v.Line, OpAMD64CMPW, TypeFlags)
- v0.AddArg(x)
- v0.AddArg(y)
+ i := v.AuxInt
+ s := v.Aux
+ p := v.Args[0]
+ w := v.Args[1]
+ x6 := v.Args[2]
+ if x6.Op != OpAMD64MOVBstore {
+ break
+ }
+ if x6.AuxInt != i-1 {
+ break
+ }
+ if x6.Aux != s {
+ break
+ }
+ if p != x6.Args[0] {
+ break
+ }
+ x6_1 := x6.Args[1]
+ if x6_1.Op != OpAMD64SHRQconst {
+ break
+ }
+ if x6_1.AuxInt != 8 {
+ break
+ }
+ if w != x6_1.Args[0] {
+ break
+ }
+ x5 := x6.Args[2]
+ if x5.Op != OpAMD64MOVBstore {
+ break
+ }
+ if x5.AuxInt != i-2 {
+ break
+ }
+ if x5.Aux != s {
+ break
+ }
+ if p != x5.Args[0] {
+ break
+ }
+ x5_1 := x5.Args[1]
+ if x5_1.Op != OpAMD64SHRQconst {
+ break
+ }
+ if x5_1.AuxInt != 16 {
+ break
+ }
+ if w != x5_1.Args[0] {
+ break
+ }
+ x4 := x5.Args[2]
+ if x4.Op != OpAMD64MOVBstore {
+ break
+ }
+ if x4.AuxInt != i-3 {
+ break
+ }
+ if x4.Aux != s {
+ break
+ }
+ if p != x4.Args[0] {
+ break
+ }
+ x4_1 := x4.Args[1]
+ if x4_1.Op != OpAMD64SHRQconst {
+ break
+ }
+ if x4_1.AuxInt != 24 {
+ break
+ }
+ if w != x4_1.Args[0] {
+ break
+ }
+ x3 := x4.Args[2]
+ if x3.Op != OpAMD64MOVBstore {
+ break
+ }
+ if x3.AuxInt != i-4 {
+ break
+ }
+ if x3.Aux != s {
+ break
+ }
+ if p != x3.Args[0] {
+ break
+ }
+ x3_1 := x3.Args[1]
+ if x3_1.Op != OpAMD64SHRQconst {
+ break
+ }
+ if x3_1.AuxInt != 32 {
+ break
+ }
+ if w != x3_1.Args[0] {
+ break
+ }
+ x2 := x3.Args[2]
+ if x2.Op != OpAMD64MOVBstore {
+ break
+ }
+ if x2.AuxInt != i-5 {
+ break
+ }
+ if x2.Aux != s {
+ break
+ }
+ if p != x2.Args[0] {
+ break
+ }
+ x2_1 := x2.Args[1]
+ if x2_1.Op != OpAMD64SHRQconst {
+ break
+ }
+ if x2_1.AuxInt != 40 {
+ break
+ }
+ if w != x2_1.Args[0] {
+ break
+ }
+ x1 := x2.Args[2]
+ if x1.Op != OpAMD64MOVBstore {
+ break
+ }
+ if x1.AuxInt != i-6 {
+ break
+ }
+ if x1.Aux != s {
+ break
+ }
+ if p != x1.Args[0] {
+ break
+ }
+ x1_1 := x1.Args[1]
+ if x1_1.Op != OpAMD64SHRQconst {
+ break
+ }
+ if x1_1.AuxInt != 48 {
+ break
+ }
+ if w != x1_1.Args[0] {
+ break
+ }
+ x0 := x1.Args[2]
+ if x0.Op != OpAMD64MOVBstore {
+ break
+ }
+ if x0.AuxInt != i-7 {
+ break
+ }
+ if x0.Aux != s {
+ break
+ }
+ if p != x0.Args[0] {
+ break
+ }
+ x0_1 := x0.Args[1]
+ if x0_1.Op != OpAMD64SHRQconst {
+ break
+ }
+ if x0_1.AuxInt != 56 {
+ break
+ }
+ if w != x0_1.Args[0] {
+ break
+ }
+ mem := x0.Args[2]
+ 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(OpAMD64MOVQstore)
+ v.AuxInt = i - 7
+ v.Aux = s
+ v.AddArg(p)
+ v0 := b.NewValue0(v.Line, OpAMD64BSWAPQ, w.Type)
+ v0.AddArg(w)
v.AddArg(v0)
+ v.AddArg(mem)
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: (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 {
- x := v.Args[0]
- y := v.Args[1]
- v.reset(OpAMD64SETEQ)
- v0 := b.NewValue0(v.Line, OpAMD64CMPL, TypeFlags)
- v0.AddArg(x)
- v0.AddArg(y)
- v.AddArg(v0)
- return true
- }
-}
-func rewriteValueAMD64_OpEq32F(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Eq32F x y)
- // cond:
- // result: (SETEQF (UCOMISS x y))
- for {
- x := v.Args[0]
- y := v.Args[1]
- v.reset(OpAMD64SETEQF)
- v0 := b.NewValue0(v.Line, OpAMD64UCOMISS, TypeFlags)
- v0.AddArg(x)
- v0.AddArg(y)
- v.AddArg(v0)
+ i := v.AuxInt
+ s := v.Aux
+ p := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64SHRQconst {
+ break
+ }
+ if v_1.AuxInt != 8 {
+ break
+ }
+ w := v_1.Args[0]
+ x := v.Args[2]
+ if x.Op != OpAMD64MOVBstore {
+ break
+ }
+ if x.AuxInt != i-1 {
+ break
+ }
+ if x.Aux != s {
+ break
+ }
+ if p != x.Args[0] {
+ break
+ }
+ if w != x.Args[1] {
+ break
+ }
+ mem := x.Args[2]
+ if !(x.Uses == 1 && clobber(x)) {
+ break
+ }
+ v.reset(OpAMD64MOVWstore)
+ v.AuxInt = i - 1
+ v.Aux = s
+ v.AddArg(p)
+ v.AddArg(w)
+ v.AddArg(mem)
return true
}
-}
-func rewriteValueAMD64_OpEq64(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Eq64 x y)
- // cond:
- // result: (SETEQ (CMPQ x y))
+ // match: (MOVBstore [i] {s} p (SHRQconst [j] w) x:(MOVBstore [i-1] {s} p w0:(SHRQconst [j-8] w) mem))
+ // cond: x.Uses == 1 && clobber(x)
+ // result: (MOVWstore [i-1] {s} p w0 mem)
for {
- x := v.Args[0]
- y := v.Args[1]
- v.reset(OpAMD64SETEQ)
- v0 := b.NewValue0(v.Line, OpAMD64CMPQ, TypeFlags)
- v0.AddArg(x)
- v0.AddArg(y)
- v.AddArg(v0)
+ i := v.AuxInt
+ s := v.Aux
+ p := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64SHRQconst {
+ break
+ }
+ j := v_1.AuxInt
+ w := v_1.Args[0]
+ x := v.Args[2]
+ if x.Op != OpAMD64MOVBstore {
+ break
+ }
+ if x.AuxInt != i-1 {
+ break
+ }
+ if x.Aux != s {
+ break
+ }
+ if p != x.Args[0] {
+ break
+ }
+ w0 := x.Args[1]
+ if w0.Op != OpAMD64SHRQconst {
+ break
+ }
+ if w0.AuxInt != j-8 {
+ break
+ }
+ if w != w0.Args[0] {
+ break
+ }
+ mem := x.Args[2]
+ if !(x.Uses == 1 && clobber(x)) {
+ break
+ }
+ v.reset(OpAMD64MOVWstore)
+ v.AuxInt = i - 1
+ v.Aux = s
+ v.AddArg(p)
+ v.AddArg(w0)
+ v.AddArg(mem)
return true
}
-}
-func rewriteValueAMD64_OpEq64F(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Eq64F x y)
- // cond:
- // result: (SETEQF (UCOMISD x y))
+ // 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 {
- x := v.Args[0]
- y := v.Args[1]
- v.reset(OpAMD64SETEQF)
- v0 := b.NewValue0(v.Line, OpAMD64UCOMISD, TypeFlags)
- v0.AddArg(x)
- v0.AddArg(y)
- v.AddArg(v0)
+ 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(OpAMD64MOVBstore)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(base)
+ v.AddArg(val)
+ v.AddArg(mem)
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: (MOVBstore [off1] {sym} (ADDLconst [off2] ptr) val mem)
+ // cond: is32Bit(off1+off2)
+ // result: (MOVBstore [off1+off2] {sym} ptr val mem)
for {
- x := v.Args[0]
- y := v.Args[1]
- v.reset(OpAMD64SETEQ)
- v0 := b.NewValue0(v.Line, OpAMD64CMPB, TypeFlags)
- v0.AddArg(x)
- v0.AddArg(y)
- v.AddArg(v0)
+ 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]
+ val := v.Args[1]
+ mem := v.Args[2]
+ if !(is32Bit(off1 + off2)) {
+ break
+ }
+ v.reset(OpAMD64MOVBstore)
+ v.AuxInt = off1 + off2
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(val)
+ v.AddArg(mem)
return true
}
+ return false
}
-func rewriteValueAMD64_OpEqB(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpAMD64MOVBstoreconst(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (EqB x y)
- // cond:
- // result: (SETEQ (CMPB x y))
+ // match: (MOVBstoreconst [sc] {s} (ADDQconst [off] ptr) mem)
+ // cond: ValAndOff(sc).canAdd(off)
+ // result: (MOVBstoreconst [ValAndOff(sc).add(off)] {s} ptr mem)
for {
- x := v.Args[0]
- y := v.Args[1]
- v.reset(OpAMD64SETEQ)
- v0 := b.NewValue0(v.Line, OpAMD64CMPB, TypeFlags)
- v0.AddArg(x)
- v0.AddArg(y)
- v.AddArg(v0)
+ sc := v.AuxInt
+ s := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64ADDQconst {
+ break
+ }
+ off := v_0.AuxInt
+ ptr := v_0.Args[0]
+ mem := v.Args[1]
+ if !(ValAndOff(sc).canAdd(off)) {
+ break
+ }
+ v.reset(OpAMD64MOVBstoreconst)
+ v.AuxInt = ValAndOff(sc).add(off)
+ v.Aux = s
+ v.AddArg(ptr)
+ v.AddArg(mem)
return true
}
-}
-func rewriteValueAMD64_OpEqPtr(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (EqPtr x y)
- // cond:
- // result: (SETEQ (CMPQ x y))
+ // match: (MOVBstoreconst [sc] {sym1} (LEAQ [off] {sym2} ptr) mem)
+ // cond: canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd(off)
+ // result: (MOVBstoreconst [ValAndOff(sc).add(off)] {mergeSym(sym1, sym2)} ptr mem)
for {
- x := v.Args[0]
- y := v.Args[1]
- v.reset(OpAMD64SETEQ)
- v0 := b.NewValue0(v.Line, OpAMD64CMPQ, TypeFlags)
- v0.AddArg(x)
- v0.AddArg(y)
- v.AddArg(v0)
+ sc := v.AuxInt
+ sym1 := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64LEAQ {
+ break
+ }
+ off := v_0.AuxInt
+ sym2 := v_0.Aux
+ ptr := v_0.Args[0]
+ mem := v.Args[1]
+ if !(canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd(off)) {
+ break
+ }
+ v.reset(OpAMD64MOVBstoreconst)
+ v.AuxInt = ValAndOff(sc).add(off)
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(ptr)
+ v.AddArg(mem)
return true
}
-}
-func rewriteValueAMD64_OpGeq16(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Geq16 x y)
- // cond:
- // result: (SETGE (CMPW x y))
+ // match: (MOVBstoreconst [x] {sym1} (LEAQ1 [off] {sym2} ptr idx) mem)
+ // cond: canMergeSym(sym1, sym2)
+ // result: (MOVBstoreconstidx1 [ValAndOff(x).add(off)] {mergeSym(sym1,sym2)} ptr idx mem)
for {
- x := v.Args[0]
- y := v.Args[1]
- v.reset(OpAMD64SETGE)
- v0 := b.NewValue0(v.Line, OpAMD64CMPW, TypeFlags)
- v0.AddArg(x)
- v0.AddArg(y)
- v.AddArg(v0)
+ x := v.AuxInt
+ sym1 := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64LEAQ1 {
+ break
+ }
+ off := v_0.AuxInt
+ sym2 := v_0.Aux
+ ptr := v_0.Args[0]
+ idx := v_0.Args[1]
+ mem := v.Args[1]
+ if !(canMergeSym(sym1, sym2)) {
+ break
+ }
+ v.reset(OpAMD64MOVBstoreconstidx1)
+ v.AuxInt = ValAndOff(x).add(off)
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(mem)
return true
}
-}
-func rewriteValueAMD64_OpGeq16U(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Geq16U x y)
+ // match: (MOVBstoreconst [x] {sym} (ADDQ ptr idx) mem)
// cond:
- // result: (SETAE (CMPW x y))
+ // result: (MOVBstoreconstidx1 [x] {sym} ptr 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.AddArg(v0)
+ x := v.AuxInt
+ sym := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64ADDQ {
+ break
+ }
+ ptr := v_0.Args[0]
+ idx := v_0.Args[1]
+ mem := v.Args[1]
+ v.reset(OpAMD64MOVBstoreconstidx1)
+ v.AuxInt = x
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(mem)
return true
}
-}
-func rewriteValueAMD64_OpGeq32(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Geq32 x y)
- // cond:
- // result: (SETGE (CMPL x y))
+ // match: (MOVBstoreconst [c] {s} p x:(MOVBstoreconst [a] {s} p mem))
+ // cond: x.Uses == 1 && ValAndOff(a).Off() + 1 == ValAndOff(c).Off() && clobber(x)
+ // result: (MOVWstoreconst [makeValAndOff(ValAndOff(a).Val()&0xff | ValAndOff(c).Val()<<8, ValAndOff(a).Off())] {s} p mem)
for {
- x := v.Args[0]
- y := v.Args[1]
- v.reset(OpAMD64SETGE)
- v0 := b.NewValue0(v.Line, OpAMD64CMPL, TypeFlags)
- v0.AddArg(x)
- v0.AddArg(y)
- v.AddArg(v0)
+ c := v.AuxInt
+ s := v.Aux
+ p := v.Args[0]
+ x := v.Args[1]
+ if x.Op != OpAMD64MOVBstoreconst {
+ break
+ }
+ a := x.AuxInt
+ if x.Aux != s {
+ break
+ }
+ if p != x.Args[0] {
+ break
+ }
+ mem := x.Args[1]
+ if !(x.Uses == 1 && ValAndOff(a).Off()+1 == ValAndOff(c).Off() && clobber(x)) {
+ break
+ }
+ v.reset(OpAMD64MOVWstoreconst)
+ v.AuxInt = makeValAndOff(ValAndOff(a).Val()&0xff|ValAndOff(c).Val()<<8, ValAndOff(a).Off())
+ v.Aux = s
+ v.AddArg(p)
+ v.AddArg(mem)
return true
}
-}
-func rewriteValueAMD64_OpGeq32F(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Geq32F x y)
- // cond:
- // result: (SETGEF (UCOMISS x y))
+ // match: (MOVBstoreconst [sc] {sym1} (LEAL [off] {sym2} ptr) mem)
+ // cond: canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd(off)
+ // result: (MOVBstoreconst [ValAndOff(sc).add(off)] {mergeSym(sym1, sym2)} ptr 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.AddArg(v0)
+ sc := v.AuxInt
+ sym1 := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64LEAL {
+ break
+ }
+ off := v_0.AuxInt
+ sym2 := v_0.Aux
+ ptr := v_0.Args[0]
+ mem := v.Args[1]
+ if !(canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd(off)) {
+ break
+ }
+ v.reset(OpAMD64MOVBstoreconst)
+ v.AuxInt = ValAndOff(sc).add(off)
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(ptr)
+ v.AddArg(mem)
return true
}
+ // match: (MOVBstoreconst [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_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(OpAMD64MOVBstoreconst)
+ v.AuxInt = ValAndOff(sc).add(off)
+ v.Aux = s
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ return false
}
-func rewriteValueAMD64_OpGeq32U(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpAMD64MOVBstoreconstidx1(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (Geq32U x y)
+ // match: (MOVBstoreconstidx1 [x] {sym} (ADDQconst [c] ptr) idx mem)
// cond:
- // result: (SETAE (CMPL x y))
+ // result: (MOVBstoreconstidx1 [ValAndOff(x).add(c)] {sym} ptr 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.AddArg(v0)
+ x := v.AuxInt
+ sym := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64ADDQconst {
+ break
+ }
+ c := v_0.AuxInt
+ ptr := v_0.Args[0]
+ idx := v.Args[1]
+ mem := v.Args[2]
+ v.reset(OpAMD64MOVBstoreconstidx1)
+ v.AuxInt = ValAndOff(x).add(c)
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(mem)
return true
}
-}
-func rewriteValueAMD64_OpGeq64(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Geq64 x y)
+ // match: (MOVBstoreconstidx1 [x] {sym} ptr (ADDQconst [c] idx) mem)
// cond:
- // result: (SETGE (CMPQ x y))
+ // result: (MOVBstoreconstidx1 [ValAndOff(x).add(c)] {sym} ptr 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.AddArg(v0)
+ x := v.AuxInt
+ sym := v.Aux
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64ADDQconst {
+ break
+ }
+ c := v_1.AuxInt
+ idx := v_1.Args[0]
+ mem := v.Args[2]
+ v.reset(OpAMD64MOVBstoreconstidx1)
+ v.AuxInt = ValAndOff(x).add(c)
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVBstoreconstidx1 [c] {s} p i x:(MOVBstoreconstidx1 [a] {s} p i mem))
+ // cond: x.Uses == 1 && ValAndOff(a).Off() + 1 == ValAndOff(c).Off() && clobber(x)
+ // result: (MOVWstoreconstidx1 [makeValAndOff(ValAndOff(a).Val()&0xff | ValAndOff(c).Val()<<8, ValAndOff(a).Off())] {s} p i mem)
+ for {
+ c := v.AuxInt
+ s := v.Aux
+ p := v.Args[0]
+ i := v.Args[1]
+ x := v.Args[2]
+ if x.Op != OpAMD64MOVBstoreconstidx1 {
+ break
+ }
+ a := x.AuxInt
+ if x.Aux != s {
+ break
+ }
+ if p != x.Args[0] {
+ break
+ }
+ if i != x.Args[1] {
+ break
+ }
+ mem := x.Args[2]
+ if !(x.Uses == 1 && ValAndOff(a).Off()+1 == ValAndOff(c).Off() && clobber(x)) {
+ break
+ }
+ v.reset(OpAMD64MOVWstoreconstidx1)
+ v.AuxInt = makeValAndOff(ValAndOff(a).Val()&0xff|ValAndOff(c).Val()<<8, ValAndOff(a).Off())
+ v.Aux = s
+ v.AddArg(p)
+ v.AddArg(i)
+ v.AddArg(mem)
return true
}
+ return false
}
-func rewriteValueAMD64_OpGeq64F(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpAMD64MOVBstoreidx1(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (Geq64F x y)
+ // match: (MOVBstoreidx1 [c] {sym} (ADDQconst [d] ptr) idx val mem)
// cond:
- // result: (SETGEF (UCOMISD x y))
+ // result: (MOVBstoreidx1 [c+d] {sym} ptr idx val 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.AddArg(v0)
+ c := v.AuxInt
+ sym := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64ADDQconst {
+ break
+ }
+ d := v_0.AuxInt
+ ptr := v_0.Args[0]
+ idx := v.Args[1]
+ val := v.Args[2]
+ mem := v.Args[3]
+ v.reset(OpAMD64MOVBstoreidx1)
+ v.AuxInt = c + d
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(val)
+ v.AddArg(mem)
return true
}
-}
-func rewriteValueAMD64_OpGeq64U(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Geq64U x y)
+ // match: (MOVBstoreidx1 [c] {sym} ptr (ADDQconst [d] idx) val mem)
// cond:
- // result: (SETAE (CMPQ x y))
+ // result: (MOVBstoreidx1 [c+d] {sym} ptr idx val 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.AddArg(v0)
+ c := v.AuxInt
+ sym := v.Aux
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64ADDQconst {
+ break
+ }
+ d := v_1.AuxInt
+ idx := v_1.Args[0]
+ val := v.Args[2]
+ mem := v.Args[3]
+ v.reset(OpAMD64MOVBstoreidx1)
+ v.AuxInt = c + d
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(val)
+ v.AddArg(mem)
return true
}
-}
-func rewriteValueAMD64_OpGeq8(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Geq8 x y)
- // cond:
- // result: (SETGE (CMPB x y))
+ // match: (MOVBstoreidx1 [i] {s} p idx (SHRQconst [8] w) x:(MOVBstoreidx1 [i-1] {s} p idx w mem))
+ // cond: x.Uses == 1 && clobber(x)
+ // result: (MOVWstoreidx1 [i-1] {s} p idx w mem)
for {
- x := v.Args[0]
- y := v.Args[1]
- v.reset(OpAMD64SETGE)
- v0 := b.NewValue0(v.Line, OpAMD64CMPB, TypeFlags)
- v0.AddArg(x)
- v0.AddArg(y)
- v.AddArg(v0)
+ i := v.AuxInt
+ s := v.Aux
+ p := v.Args[0]
+ idx := v.Args[1]
+ v_2 := v.Args[2]
+ if v_2.Op != OpAMD64SHRQconst {
+ break
+ }
+ if v_2.AuxInt != 8 {
+ break
+ }
+ w := v_2.Args[0]
+ x := v.Args[3]
+ if x.Op != OpAMD64MOVBstoreidx1 {
+ break
+ }
+ if x.AuxInt != i-1 {
+ break
+ }
+ if x.Aux != s {
+ break
+ }
+ if p != x.Args[0] {
+ break
+ }
+ if idx != x.Args[1] {
+ break
+ }
+ if w != x.Args[2] {
+ break
+ }
+ mem := x.Args[3]
+ if !(x.Uses == 1 && clobber(x)) {
+ break
+ }
+ v.reset(OpAMD64MOVWstoreidx1)
+ v.AuxInt = i - 1
+ v.Aux = s
+ v.AddArg(p)
+ v.AddArg(idx)
+ v.AddArg(w)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVBstoreidx1 [i] {s} p idx (SHRQconst [j] w) x:(MOVBstoreidx1 [i-1] {s} p idx w0:(SHRQconst [j-8] w) mem))
+ // cond: x.Uses == 1 && clobber(x)
+ // result: (MOVWstoreidx1 [i-1] {s} p idx w0 mem)
+ for {
+ i := v.AuxInt
+ s := v.Aux
+ p := v.Args[0]
+ idx := v.Args[1]
+ v_2 := v.Args[2]
+ if v_2.Op != OpAMD64SHRQconst {
+ break
+ }
+ j := v_2.AuxInt
+ w := v_2.Args[0]
+ x := v.Args[3]
+ if x.Op != OpAMD64MOVBstoreidx1 {
+ break
+ }
+ if x.AuxInt != i-1 {
+ break
+ }
+ if x.Aux != s {
+ break
+ }
+ if p != x.Args[0] {
+ break
+ }
+ if idx != x.Args[1] {
+ break
+ }
+ w0 := x.Args[2]
+ if w0.Op != OpAMD64SHRQconst {
+ break
+ }
+ if w0.AuxInt != j-8 {
+ break
+ }
+ if w != w0.Args[0] {
+ break
+ }
+ mem := x.Args[3]
+ if !(x.Uses == 1 && clobber(x)) {
+ break
+ }
+ v.reset(OpAMD64MOVWstoreidx1)
+ v.AuxInt = i - 1
+ v.Aux = s
+ v.AddArg(p)
+ v.AddArg(idx)
+ v.AddArg(w0)
+ v.AddArg(mem)
return true
}
+ return false
}
-func rewriteValueAMD64_OpGeq8U(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpAMD64MOVLQSX(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (Geq8U x y)
- // cond:
- // result: (SETAE (CMPB x y))
+ // 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]
- y := v.Args[1]
- v.reset(OpAMD64SETAE)
- v0 := b.NewValue0(v.Line, OpAMD64CMPB, TypeFlags)
- v0.AddArg(x)
- v0.AddArg(y)
+ if x.Op != OpAMD64MOVLload {
+ break
+ }
+ off := x.AuxInt
+ sym := x.Aux
+ ptr := x.Args[0]
+ mem := x.Args[1]
+ if !(x.Uses == 1 && clobber(x)) {
+ break
+ }
+ b = x.Block
+ v0 := b.NewValue0(v.Line, OpAMD64MOVLQSXload, v.Type)
+ v.reset(OpCopy)
v.AddArg(v0)
+ v0.AuxInt = off
+ v0.Aux = sym
+ v0.AddArg(ptr)
+ v0.AddArg(mem)
return true
}
-}
-func rewriteValueAMD64_OpGetClosurePtr(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (GetClosurePtr)
- // cond:
- // result: (LoweredGetClosurePtr)
+ // 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 {
- v.reset(OpAMD64LoweredGetClosurePtr)
+ 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)) {
+ 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
}
-}
-func rewriteValueAMD64_OpGetG(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (GetG mem)
- // cond:
- // result: (LoweredGetG mem)
+ // match: (MOVLQSX (ANDLconst [c] x))
+ // cond: c & 0x80000000 == 0
+ // result: (ANDLconst [c & 0x7fffffff] x)
for {
- mem := v.Args[0]
- v.reset(OpAMD64LoweredGetG)
- v.AddArg(mem)
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64ANDLconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v_0.Args[0]
+ if !(c&0x80000000 == 0) {
+ break
+ }
+ v.reset(OpAMD64ANDLconst)
+ v.AuxInt = c & 0x7fffffff
+ v.AddArg(x)
return true
}
+ return false
}
-func rewriteValueAMD64_OpGoCall(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpAMD64MOVLQSXload(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (GoCall [argwid] mem)
- // cond:
- // result: (CALLgo [argwid] 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 {
- argwid := v.AuxInt
- mem := v.Args[0]
- v.reset(OpAMD64CALLgo)
- v.AuxInt = argwid
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64LEAQ {
+ break
+ }
+ off2 := v_0.AuxInt
+ sym2 := v_0.Aux
+ base := v_0.Args[0]
+ mem := v.Args[1]
+ if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
+ break
+ }
+ v.reset(OpAMD64MOVLQSXload)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(base)
v.AddArg(mem)
return true
}
+ return false
}
-func rewriteValueAMD64_OpGreater16(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpAMD64MOVLQZX(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (Greater16 x y)
- // cond:
- // result: (SETG (CMPW x y))
+ // 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]
- y := v.Args[1]
- v.reset(OpAMD64SETG)
- v0 := b.NewValue0(v.Line, OpAMD64CMPW, TypeFlags)
- v0.AddArg(x)
- v0.AddArg(y)
+ if x.Op != OpAMD64MOVLload {
+ break
+ }
+ off := x.AuxInt
+ sym := x.Aux
+ ptr := x.Args[0]
+ mem := x.Args[1]
+ if !(x.Uses == 1 && clobber(x)) {
+ break
+ }
+ b = x.Block
+ v0 := b.NewValue0(v.Line, OpAMD64MOVLload, v.Type)
+ v.reset(OpCopy)
v.AddArg(v0)
+ v0.AuxInt = off
+ v0.Aux = sym
+ v0.AddArg(ptr)
+ v0.AddArg(mem)
return true
}
-}
-func rewriteValueAMD64_OpGreater16U(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Greater16U x y)
- // cond:
- // result: (SETA (CMPW x y))
+ // 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]
- y := v.Args[1]
- v.reset(OpAMD64SETA)
- v0 := b.NewValue0(v.Line, OpAMD64CMPW, TypeFlags)
- v0.AddArg(x)
- v0.AddArg(y)
+ 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)) {
+ 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
}
-}
-func rewriteValueAMD64_OpGreater32(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Greater32 x y)
- // cond:
- // result: (SETG (CMPL x y))
+ // 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]
- y := v.Args[1]
- v.reset(OpAMD64SETG)
- v0 := b.NewValue0(v.Line, OpAMD64CMPL, TypeFlags)
- v0.AddArg(x)
- v0.AddArg(y)
+ if x.Op != OpAMD64MOVLloadidx1 {
+ break
+ }
+ off := x.AuxInt
+ sym := x.Aux
+ ptr := x.Args[0]
+ idx := x.Args[1]
+ mem := x.Args[2]
+ if !(x.Uses == 1 && clobber(x)) {
+ break
+ }
+ b = x.Block
+ v0 := b.NewValue0(v.Line, OpAMD64MOVLloadidx1, v.Type)
+ v.reset(OpCopy)
v.AddArg(v0)
+ v0.AuxInt = off
+ v0.Aux = sym
+ v0.AddArg(ptr)
+ v0.AddArg(idx)
+ v0.AddArg(mem)
return true
}
-}
-func rewriteValueAMD64_OpGreater32F(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Greater32F x y)
- // cond:
- // result: (SETGF (UCOMISS x y))
+ // 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]
- y := v.Args[1]
- v.reset(OpAMD64SETGF)
- v0 := b.NewValue0(v.Line, OpAMD64UCOMISS, TypeFlags)
- v0.AddArg(x)
- v0.AddArg(y)
+ if x.Op != OpAMD64MOVLloadidx4 {
+ break
+ }
+ off := x.AuxInt
+ sym := x.Aux
+ ptr := x.Args[0]
+ idx := x.Args[1]
+ mem := x.Args[2]
+ if !(x.Uses == 1 && clobber(x)) {
+ break
+ }
+ b = x.Block
+ v0 := b.NewValue0(v.Line, OpAMD64MOVLloadidx4, v.Type)
+ v.reset(OpCopy)
v.AddArg(v0)
+ v0.AuxInt = off
+ v0.Aux = sym
+ v0.AddArg(ptr)
+ v0.AddArg(idx)
+ v0.AddArg(mem)
return true
}
-}
-func rewriteValueAMD64_OpGreater32U(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Greater32U x y)
+ // match: (MOVLQZX (ANDLconst [c] x))
// cond:
- // result: (SETA (CMPL x y))
+ // result: (ANDLconst [c] x)
for {
- x := v.Args[0]
- y := v.Args[1]
- v.reset(OpAMD64SETA)
- v0 := b.NewValue0(v.Line, OpAMD64CMPL, TypeFlags)
- v0.AddArg(x)
- v0.AddArg(y)
- v.AddArg(v0)
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64ANDLconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v_0.Args[0]
+ v.reset(OpAMD64ANDLconst)
+ v.AuxInt = c
+ v.AddArg(x)
return true
}
+ return false
}
-func rewriteValueAMD64_OpGreater64(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpAMD64MOVLatomicload(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (Greater64 x y)
- // cond:
- // result: (SETG (CMPQ x y))
+ // match: (MOVLatomicload [off1] {sym} (ADDQconst [off2] ptr) mem)
+ // cond: is32Bit(off1+off2)
+ // result: (MOVLatomicload [off1+off2] {sym} ptr mem)
for {
- x := v.Args[0]
- y := v.Args[1]
- v.reset(OpAMD64SETG)
- v0 := b.NewValue0(v.Line, OpAMD64CMPQ, TypeFlags)
- v0.AddArg(x)
- v0.AddArg(y)
- v.AddArg(v0)
+ 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(OpAMD64MOVLatomicload)
+ v.AuxInt = off1 + off2
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(mem)
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: (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 {
- x := v.Args[0]
- y := v.Args[1]
- v.reset(OpAMD64SETGF)
- v0 := b.NewValue0(v.Line, OpAMD64UCOMISD, TypeFlags)
- v0.AddArg(x)
- v0.AddArg(y)
- v.AddArg(v0)
+ 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)) {
+ 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_OpGreater64U(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpAMD64MOVLload(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (Greater64U x y)
- // cond:
- // result: (SETA (CMPQ x y))
+ // match: (MOVLload [off] {sym} ptr (MOVLstore [off2] {sym2} ptr2 x _))
+ // cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
+ // result: x
for {
- x := v.Args[0]
- y := v.Args[1]
- v.reset(OpAMD64SETA)
- v0 := b.NewValue0(v.Line, OpAMD64CMPQ, TypeFlags)
- v0.AddArg(x)
- v0.AddArg(y)
- v.AddArg(v0)
- return true
- }
-}
-func rewriteValueAMD64_OpGreater8(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Greater8 x y)
- // cond:
- // result: (SETG (CMPB x y))
+ off := v.AuxInt
+ sym := v.Aux
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64MOVLstore {
+ break
+ }
+ off2 := v_1.AuxInt
+ sym2 := v_1.Aux
+ ptr2 := v_1.Args[0]
+ x := v_1.Args[1]
+ if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVLload [off1] {sym} (ADDQconst [off2] ptr) mem)
+ // cond: is32Bit(off1+off2)
+ // result: (MOVLload [off1+off2] {sym} ptr mem)
for {
- x := v.Args[0]
- y := v.Args[1]
- v.reset(OpAMD64SETG)
- v0 := b.NewValue0(v.Line, OpAMD64CMPB, TypeFlags)
- v0.AddArg(x)
- v0.AddArg(y)
- v.AddArg(v0)
+ off1 := v.AuxInt
+ sym := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64ADDQconst {
+ break
+ }
+ off2 := v_0.AuxInt
+ ptr := v_0.Args[0]
+ mem := v.Args[1]
+ if !(is32Bit(off1 + off2)) {
+ break
+ }
+ v.reset(OpAMD64MOVLload)
+ v.AuxInt = off1 + off2
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(mem)
return true
}
-}
-func rewriteValueAMD64_OpGreater8U(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Greater8U x y)
- // cond:
- // result: (SETA (CMPB x y))
+ // 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 {
- x := v.Args[0]
- y := v.Args[1]
- v.reset(OpAMD64SETA)
- v0 := b.NewValue0(v.Line, OpAMD64CMPB, TypeFlags)
- v0.AddArg(x)
- v0.AddArg(y)
- v.AddArg(v0)
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64LEAQ {
+ break
+ }
+ off2 := v_0.AuxInt
+ sym2 := v_0.Aux
+ base := v_0.Args[0]
+ mem := v.Args[1]
+ if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
+ break
+ }
+ v.reset(OpAMD64MOVLload)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(base)
+ v.AddArg(mem)
return true
}
-}
-func rewriteValueAMD64_OpHmul16(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Hmul16 x y)
- // cond:
- // result: (HMULW x y)
+ // 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 {
- x := v.Args[0]
- y := v.Args[1]
- v.reset(OpAMD64HMULW)
- v.AddArg(x)
- v.AddArg(y)
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64LEAQ1 {
+ break
+ }
+ off2 := v_0.AuxInt
+ sym2 := v_0.Aux
+ ptr := v_0.Args[0]
+ idx := v_0.Args[1]
+ mem := v.Args[1]
+ if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
+ break
+ }
+ v.reset(OpAMD64MOVLloadidx1)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(mem)
return true
}
-}
-func rewriteValueAMD64_OpHmul16u(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Hmul16u x y)
- // cond:
- // result: (HMULWU x y)
+ // 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 {
- x := v.Args[0]
- y := v.Args[1]
- v.reset(OpAMD64HMULWU)
- v.AddArg(x)
- v.AddArg(y)
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64LEAQ4 {
+ break
+ }
+ off2 := v_0.AuxInt
+ sym2 := v_0.Aux
+ ptr := v_0.Args[0]
+ idx := v_0.Args[1]
+ mem := v.Args[1]
+ if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
+ break
+ }
+ v.reset(OpAMD64MOVLloadidx4)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(mem)
return true
}
-}
-func rewriteValueAMD64_OpHmul32(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Hmul32 x y)
- // cond:
- // result: (HMULL x y)
+ // match: (MOVLload [off] {sym} (ADDQ ptr idx) mem)
+ // cond: ptr.Op != OpSB
+ // result: (MOVLloadidx1 [off] {sym} ptr idx mem)
for {
- x := v.Args[0]
- y := v.Args[1]
- v.reset(OpAMD64HMULL)
- v.AddArg(x)
- v.AddArg(y)
+ off := v.AuxInt
+ sym := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64ADDQ {
+ break
+ }
+ ptr := v_0.Args[0]
+ idx := v_0.Args[1]
+ mem := v.Args[1]
+ if !(ptr.Op != OpSB) {
+ break
+ }
+ v.reset(OpAMD64MOVLloadidx1)
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(mem)
return true
}
-}
-func rewriteValueAMD64_OpHmul32u(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Hmul32u x y)
- // cond:
- // result: (HMULLU x y)
+ // match: (MOVLload [off1] {sym1} (LEAL [off2] {sym2} base) mem)
+ // cond: canMergeSym(sym1, sym2)
+ // result: (MOVLload [off1+off2] {mergeSym(sym1,sym2)} base mem)
for {
- x := v.Args[0]
- y := v.Args[1]
- v.reset(OpAMD64HMULLU)
- v.AddArg(x)
- v.AddArg(y)
+ 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(OpAMD64MOVLload)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(base)
+ v.AddArg(mem)
return true
}
-}
-func rewriteValueAMD64_OpHmul64(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Hmul64 x y)
- // cond:
- // result: (HMULQ x y)
+ // match: (MOVLload [off1] {sym} (ADDLconst [off2] ptr) mem)
+ // cond: is32Bit(off1+off2)
+ // result: (MOVLload [off1+off2] {sym} ptr mem)
for {
- x := v.Args[0]
- y := v.Args[1]
- v.reset(OpAMD64HMULQ)
- v.AddArg(x)
- v.AddArg(y)
+ 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(OpAMD64MOVLload)
+ v.AuxInt = off1 + off2
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(mem)
return true
}
+ return false
}
-func rewriteValueAMD64_OpHmul64u(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpAMD64MOVLloadidx1(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (Hmul64u x y)
+ // match: (MOVLloadidx1 [c] {sym} ptr (SHLQconst [2] idx) mem)
// cond:
- // result: (HMULQU x y)
+ // result: (MOVLloadidx4 [c] {sym} ptr idx mem)
for {
- x := v.Args[0]
- y := v.Args[1]
- v.reset(OpAMD64HMULQU)
- v.AddArg(x)
- v.AddArg(y)
+ c := v.AuxInt
+ sym := v.Aux
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64SHLQconst {
+ break
+ }
+ if v_1.AuxInt != 2 {
+ break
+ }
+ idx := v_1.Args[0]
+ mem := v.Args[2]
+ v.reset(OpAMD64MOVLloadidx4)
+ v.AuxInt = c
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(mem)
return true
}
-}
-func rewriteValueAMD64_OpHmul8(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Hmul8 x y)
+ // match: (MOVLloadidx1 [c] {sym} (ADDQconst [d] ptr) idx mem)
// cond:
- // result: (HMULB x y)
+ // result: (MOVLloadidx1 [c+d] {sym} ptr idx mem)
for {
- x := v.Args[0]
- y := v.Args[1]
- v.reset(OpAMD64HMULB)
- v.AddArg(x)
- v.AddArg(y)
+ c := v.AuxInt
+ sym := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64ADDQconst {
+ break
+ }
+ d := v_0.AuxInt
+ ptr := v_0.Args[0]
+ idx := v.Args[1]
+ mem := v.Args[2]
+ v.reset(OpAMD64MOVLloadidx1)
+ v.AuxInt = c + d
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(mem)
return true
}
-}
-func rewriteValueAMD64_OpHmul8u(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Hmul8u x y)
+ // match: (MOVLloadidx1 [c] {sym} ptr (ADDQconst [d] idx) mem)
// cond:
- // result: (HMULBU x y)
+ // result: (MOVLloadidx1 [c+d] {sym} ptr idx mem)
for {
- x := v.Args[0]
- y := v.Args[1]
- v.reset(OpAMD64HMULBU)
- v.AddArg(x)
- v.AddArg(y)
+ c := v.AuxInt
+ sym := v.Aux
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64ADDQconst {
+ break
+ }
+ d := v_1.AuxInt
+ idx := v_1.Args[0]
+ mem := v.Args[2]
+ v.reset(OpAMD64MOVLloadidx1)
+ v.AuxInt = c + d
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(mem)
return true
}
+ return false
}
-func rewriteValueAMD64_OpITab(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpAMD64MOVLloadidx4(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (ITab (Load ptr mem))
+ // match: (MOVLloadidx4 [c] {sym} (ADDQconst [d] ptr) idx mem)
// cond:
- // result: (MOVQload ptr mem)
+ // result: (MOVLloadidx4 [c+d] {sym} ptr idx mem)
for {
+ c := v.AuxInt
+ sym := v.Aux
v_0 := v.Args[0]
- if v_0.Op != OpLoad {
+ if v_0.Op != OpAMD64ADDQconst {
break
}
+ d := v_0.AuxInt
ptr := v_0.Args[0]
- mem := v_0.Args[1]
- v.reset(OpAMD64MOVQload)
+ 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
}
- return false
-}
-func rewriteValueAMD64_OpInterCall(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (InterCall [argwid] entry mem)
+ // match: (MOVLloadidx4 [c] {sym} ptr (ADDQconst [d] idx) mem)
// cond:
- // result: (CALLinter [argwid] entry mem)
+ // result: (MOVLloadidx4 [c+4*d] {sym} ptr idx mem)
for {
- argwid := v.AuxInt
- entry := v.Args[0]
- mem := v.Args[1]
- v.reset(OpAMD64CALLinter)
- v.AuxInt = argwid
- v.AddArg(entry)
+ c := v.AuxInt
+ sym := v.Aux
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64ADDQconst {
+ break
+ }
+ d := v_1.AuxInt
+ idx := v_1.Args[0]
+ mem := v.Args[2]
+ v.reset(OpAMD64MOVLloadidx4)
+ v.AuxInt = c + 4*d
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(idx)
v.AddArg(mem)
return true
}
+ return false
}
-func rewriteValueAMD64_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 {
+func rewriteValueAMD64_OpAMD64MOVLstore(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (IsNonNil p)
+ // match: (MOVLstore [off] {sym} ptr (MOVLQSX x) mem)
// cond:
- // result: (SETNE (TESTQ p p))
+ // result: (MOVLstore [off] {sym} ptr x mem)
for {
- p := v.Args[0]
- v.reset(OpAMD64SETNE)
- v0 := b.NewValue0(v.Line, OpAMD64TESTQ, TypeFlags)
- v0.AddArg(p)
- v0.AddArg(p)
- v.AddArg(v0)
+ off := v.AuxInt
+ sym := v.Aux
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64MOVLQSX {
+ break
+ }
+ x := v_1.Args[0]
+ mem := v.Args[2]
+ v.reset(OpAMD64MOVLstore)
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(x)
+ v.AddArg(mem)
return true
}
-}
-func rewriteValueAMD64_OpIsSliceInBounds(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (IsSliceInBounds idx len)
+ // match: (MOVLstore [off] {sym} ptr (MOVLQZX x) mem)
// cond:
- // result: (SETBE (CMPQ idx len))
+ // result: (MOVLstore [off] {sym} ptr x mem)
for {
- idx := v.Args[0]
- len := v.Args[1]
- v.reset(OpAMD64SETBE)
- v0 := b.NewValue0(v.Line, OpAMD64CMPQ, TypeFlags)
- v0.AddArg(idx)
- v0.AddArg(len)
- v.AddArg(v0)
+ off := v.AuxInt
+ sym := v.Aux
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64MOVLQZX {
+ break
+ }
+ x := v_1.Args[0]
+ mem := v.Args[2]
+ v.reset(OpAMD64MOVLstore)
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(x)
+ v.AddArg(mem)
return true
}
-}
-func rewriteValueAMD64_OpAMD64LEAQ(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (LEAQ [c] {s} (ADDQconst [d] x))
- // cond: is32Bit(c+d)
- // result: (LEAQ [c+d] {s} x)
+ // match: (MOVLstore [off1] {sym} (ADDQconst [off2] ptr) val mem)
+ // cond: is32Bit(off1+off2)
+ // result: (MOVLstore [off1+off2] {sym} ptr val mem)
for {
- c := v.AuxInt
- s := v.Aux
+ off1 := v.AuxInt
+ sym := v.Aux
v_0 := v.Args[0]
if v_0.Op != OpAMD64ADDQconst {
break
}
- d := v_0.AuxInt
- x := v_0.Args[0]
- if !(is32Bit(c + d)) {
+ off2 := v_0.AuxInt
+ ptr := v_0.Args[0]
+ val := v.Args[1]
+ mem := v.Args[2]
+ if !(is32Bit(off1 + off2)) {
break
}
- v.reset(OpAMD64LEAQ)
- v.AuxInt = c + d
- v.Aux = s
- v.AddArg(x)
+ v.reset(OpAMD64MOVLstore)
+ v.AuxInt = off1 + off2
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(val)
+ v.AddArg(mem)
return true
}
- // match: (LEAQ [c] {s} (ADDQ x y))
- // cond: x.Op != OpSB && y.Op != OpSB
- // result: (LEAQ1 [c] {s} x y)
+ // match: (MOVLstore [off] {sym} ptr (MOVLconst [c]) mem)
+ // cond: validOff(off)
+ // result: (MOVLstoreconst [makeValAndOff(int64(int32(c)),off)] {sym} ptr mem)
for {
- c := v.AuxInt
- s := v.Aux
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64ADDQ {
+ off := v.AuxInt
+ sym := v.Aux
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64MOVLconst {
break
}
- x := v_0.Args[0]
- y := v_0.Args[1]
- if !(x.Op != OpSB && y.Op != OpSB) {
+ c := v_1.AuxInt
+ mem := v.Args[2]
+ if !(validOff(off)) {
break
}
- v.reset(OpAMD64LEAQ1)
- v.AuxInt = c
- v.Aux = s
- v.AddArg(x)
- v.AddArg(y)
+ v.reset(OpAMD64MOVLstoreconst)
+ v.AuxInt = makeValAndOff(int64(int32(c)), off)
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(mem)
return true
}
- // match: (LEAQ [off1] {sym1} (LEAQ [off2] {sym2} x))
+ // match: (MOVLstore [off1] {sym1} (LEAQ [off2] {sym2} base) val mem)
// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
- // result: (LEAQ [off1+off2] {mergeSym(sym1,sym2)} x)
+ // result: (MOVLstore [off1+off2] {mergeSym(sym1,sym2)} base val mem)
for {
off1 := v.AuxInt
sym1 := v.Aux
@@ -4202,19 +5461,23 @@ func rewriteValueAMD64_OpAMD64LEAQ(v *Value, config *Config) bool {
}
off2 := v_0.AuxInt
sym2 := v_0.Aux
- x := v_0.Args[0]
+ base := v_0.Args[0]
+ val := v.Args[1]
+ mem := v.Args[2]
if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
break
}
- v.reset(OpAMD64LEAQ)
+ v.reset(OpAMD64MOVLstore)
v.AuxInt = off1 + off2
v.Aux = mergeSym(sym1, sym2)
- v.AddArg(x)
+ v.AddArg(base)
+ v.AddArg(val)
+ v.AddArg(mem)
return true
}
- // match: (LEAQ [off1] {sym1} (LEAQ1 [off2] {sym2} x y))
+ // match: (MOVLstore [off1] {sym1} (LEAQ1 [off2] {sym2} ptr idx) val mem)
// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
- // result: (LEAQ1 [off1+off2] {mergeSym(sym1,sym2)} x y)
+ // result: (MOVLstoreidx1 [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem)
for {
off1 := v.AuxInt
sym1 := v.Aux
@@ -4224,45 +5487,25 @@ func rewriteValueAMD64_OpAMD64LEAQ(v *Value, config *Config) bool {
}
off2 := v_0.AuxInt
sym2 := v_0.Aux
- x := v_0.Args[0]
- y := v_0.Args[1]
- if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
- break
- }
- v.reset(OpAMD64LEAQ1)
- v.AuxInt = off1 + off2
- v.Aux = mergeSym(sym1, sym2)
- v.AddArg(x)
- v.AddArg(y)
- return true
- }
- // match: (LEAQ [off1] {sym1} (LEAQ2 [off2] {sym2} x y))
- // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
- // result: (LEAQ2 [off1+off2] {mergeSym(sym1,sym2)} x y)
- for {
- off1 := v.AuxInt
- sym1 := v.Aux
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64LEAQ2 {
- break
- }
- off2 := v_0.AuxInt
- sym2 := v_0.Aux
- x := v_0.Args[0]
- y := v_0.Args[1]
+ 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(OpAMD64LEAQ2)
+ v.reset(OpAMD64MOVLstoreidx1)
v.AuxInt = off1 + off2
v.Aux = mergeSym(sym1, sym2)
- v.AddArg(x)
- v.AddArg(y)
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(val)
+ v.AddArg(mem)
return true
}
- // match: (LEAQ [off1] {sym1} (LEAQ4 [off2] {sym2} x y))
+ // match: (MOVLstore [off1] {sym1} (LEAQ4 [off2] {sym2} ptr idx) val mem)
// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
- // result: (LEAQ4 [off1+off2] {mergeSym(sym1,sym2)} x y)
+ // result: (MOVLstoreidx4 [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem)
for {
off1 := v.AuxInt
sym1 := v.Aux
@@ -4272,1768 +5515,1864 @@ func rewriteValueAMD64_OpAMD64LEAQ(v *Value, config *Config) bool {
}
off2 := v_0.AuxInt
sym2 := v_0.Aux
- x := v_0.Args[0]
- y := 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(OpAMD64LEAQ4)
+ v.reset(OpAMD64MOVLstoreidx4)
v.AuxInt = off1 + off2
v.Aux = mergeSym(sym1, sym2)
- v.AddArg(x)
- v.AddArg(y)
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(val)
+ v.AddArg(mem)
return true
}
- // match: (LEAQ [off1] {sym1} (LEAQ8 [off2] {sym2} x y))
- // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
- // result: (LEAQ8 [off1+off2] {mergeSym(sym1,sym2)} x y)
+ // match: (MOVLstore [off] {sym} (ADDQ ptr idx) val mem)
+ // cond: ptr.Op != OpSB
+ // result: (MOVLstoreidx1 [off] {sym} ptr idx val mem)
for {
- off1 := v.AuxInt
- sym1 := v.Aux
+ off := v.AuxInt
+ sym := v.Aux
v_0 := v.Args[0]
- if v_0.Op != OpAMD64LEAQ8 {
+ if v_0.Op != OpAMD64ADDQ {
break
}
- off2 := v_0.AuxInt
- sym2 := v_0.Aux
- x := v_0.Args[0]
- y := v_0.Args[1]
- if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
+ 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(OpAMD64LEAQ8)
- v.AuxInt = off1 + off2
- v.Aux = mergeSym(sym1, sym2)
- v.AddArg(x)
- v.AddArg(y)
+ v.reset(OpAMD64MOVLstoreidx1)
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(val)
+ v.AddArg(mem)
return true
}
- return false
-}
-func rewriteValueAMD64_OpAMD64LEAQ1(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (LEAQ1 [c] {s} (ADDQconst [d] x) y)
- // cond: is32Bit(c+d) && x.Op != OpSB
- // result: (LEAQ1 [c+d] {s} x y)
+ // 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 {
- c := v.AuxInt
+ i := v.AuxInt
s := v.Aux
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64ADDQconst {
+ p := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64SHRQconst {
break
}
- d := v_0.AuxInt
- x := v_0.Args[0]
- y := v.Args[1]
- if !(is32Bit(c+d) && x.Op != OpSB) {
+ if v_1.AuxInt != 32 {
break
}
- v.reset(OpAMD64LEAQ1)
- v.AuxInt = c + d
- v.Aux = s
- v.AddArg(x)
- v.AddArg(y)
- return true
- }
- // match: (LEAQ1 [c] {s} x (ADDQconst [d] y))
- // cond: is32Bit(c+d) && y.Op != OpSB
- // result: (LEAQ1 [c+d] {s} x y)
- for {
- c := v.AuxInt
- s := v.Aux
- x := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64ADDQconst {
+ w := v_1.Args[0]
+ x := v.Args[2]
+ if x.Op != OpAMD64MOVLstore {
break
}
- d := v_1.AuxInt
- y := v_1.Args[0]
- if !(is32Bit(c+d) && y.Op != OpSB) {
+ if x.AuxInt != i-4 {
break
}
- v.reset(OpAMD64LEAQ1)
- v.AuxInt = c + d
- v.Aux = s
- v.AddArg(x)
- v.AddArg(y)
- return true
- }
- // match: (LEAQ1 [c] {s} x (SHLQconst [1] y))
- // cond:
- // result: (LEAQ2 [c] {s} x y)
- for {
- c := v.AuxInt
- s := v.Aux
- x := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64SHLQconst {
+ if x.Aux != s {
break
}
- if v_1.AuxInt != 1 {
+ if p != x.Args[0] {
break
}
- y := v_1.Args[0]
- v.reset(OpAMD64LEAQ2)
- v.AuxInt = c
- v.Aux = s
- v.AddArg(x)
- v.AddArg(y)
- return true
- }
- // match: (LEAQ1 [c] {s} (SHLQconst [1] x) y)
- // cond:
- // result: (LEAQ2 [c] {s} y x)
- for {
- c := v.AuxInt
- s := v.Aux
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64SHLQconst {
+ if w != x.Args[1] {
break
}
- if v_0.AuxInt != 1 {
+ mem := x.Args[2]
+ if !(x.Uses == 1 && clobber(x)) {
break
}
- x := v_0.Args[0]
- y := v.Args[1]
- v.reset(OpAMD64LEAQ2)
- v.AuxInt = c
+ v.reset(OpAMD64MOVQstore)
+ v.AuxInt = i - 4
v.Aux = s
- v.AddArg(y)
- v.AddArg(x)
+ v.AddArg(p)
+ v.AddArg(w)
+ v.AddArg(mem)
return true
}
- // match: (LEAQ1 [c] {s} x (SHLQconst [2] y))
- // cond:
- // result: (LEAQ4 [c] {s} x y)
+ // 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 {
- c := v.AuxInt
+ i := v.AuxInt
s := v.Aux
- x := v.Args[0]
+ p := v.Args[0]
v_1 := v.Args[1]
- if v_1.Op != OpAMD64SHLQconst {
+ if v_1.Op != OpAMD64SHRQconst {
break
}
- if v_1.AuxInt != 2 {
+ j := v_1.AuxInt
+ w := v_1.Args[0]
+ x := v.Args[2]
+ if x.Op != OpAMD64MOVLstore {
break
}
- y := v_1.Args[0]
- v.reset(OpAMD64LEAQ4)
- v.AuxInt = c
- v.Aux = s
- v.AddArg(x)
- v.AddArg(y)
- return true
- }
- // match: (LEAQ1 [c] {s} (SHLQconst [2] x) y)
- // cond:
- // result: (LEAQ4 [c] {s} y x)
- for {
- c := v.AuxInt
- s := v.Aux
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64SHLQconst {
+ if x.AuxInt != i-4 {
break
}
- if v_0.AuxInt != 2 {
+ if x.Aux != s {
break
}
- x := v_0.Args[0]
- y := v.Args[1]
- v.reset(OpAMD64LEAQ4)
- v.AuxInt = c
- v.Aux = s
- v.AddArg(y)
- v.AddArg(x)
- return true
- }
- // match: (LEAQ1 [c] {s} x (SHLQconst [3] y))
- // cond:
- // result: (LEAQ8 [c] {s} x y)
- for {
- c := v.AuxInt
- s := v.Aux
- x := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64SHLQconst {
+ if p != x.Args[0] {
break
}
- if v_1.AuxInt != 3 {
+ w0 := x.Args[1]
+ if w0.Op != OpAMD64SHRQconst {
break
}
- y := v_1.Args[0]
- v.reset(OpAMD64LEAQ8)
- v.AuxInt = c
- v.Aux = s
- v.AddArg(x)
- v.AddArg(y)
- return true
- }
- // match: (LEAQ1 [c] {s} (SHLQconst [3] x) y)
- // cond:
- // result: (LEAQ8 [c] {s} y x)
- for {
- c := v.AuxInt
- s := v.Aux
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64SHLQconst {
+ if w0.AuxInt != j-32 {
break
}
- if v_0.AuxInt != 3 {
+ if w != w0.Args[0] {
break
}
- x := v_0.Args[0]
- y := v.Args[1]
- v.reset(OpAMD64LEAQ8)
- v.AuxInt = c
+ mem := x.Args[2]
+ if !(x.Uses == 1 && clobber(x)) {
+ break
+ }
+ v.reset(OpAMD64MOVQstore)
+ v.AuxInt = i - 4
v.Aux = s
- v.AddArg(y)
- v.AddArg(x)
+ v.AddArg(p)
+ v.AddArg(w0)
+ v.AddArg(mem)
return true
}
- // match: (LEAQ1 [off1] {sym1} (LEAQ [off2] {sym2} x) y)
- // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2) && x.Op != OpSB
- // result: (LEAQ1 [off1+off2] {mergeSym(sym1,sym2)} x y)
+ // match: (MOVLstore [off1] {sym1} (LEAL [off2] {sym2} base) val mem)
+ // cond: 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 v_0.Op != OpAMD64LEAL {
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) {
+ base := v_0.Args[0]
+ val := v.Args[1]
+ mem := v.Args[2]
+ if !(canMergeSym(sym1, sym2)) {
break
}
- v.reset(OpAMD64LEAQ1)
+ v.reset(OpAMD64MOVLstore)
v.AuxInt = off1 + off2
v.Aux = mergeSym(sym1, sym2)
- v.AddArg(x)
- v.AddArg(y)
+ v.AddArg(base)
+ v.AddArg(val)
+ v.AddArg(mem)
return true
}
- // match: (LEAQ1 [off1] {sym1} x (LEAQ [off2] {sym2} y))
- // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2) && y.Op != OpSB
- // result: (LEAQ1 [off1+off2] {mergeSym(sym1,sym2)} x y)
+ // match: (MOVLstore [off1] {sym} (ADDLconst [off2] ptr) val mem)
+ // cond: is32Bit(off1+off2)
+ // result: (MOVLstore [off1+off2] {sym} ptr val mem)
for {
off1 := v.AuxInt
- sym1 := v.Aux
- x := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64LEAQ {
+ sym := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64ADDLconst {
break
}
- off2 := v_1.AuxInt
- sym2 := v_1.Aux
- y := v_1.Args[0]
- if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2) && y.Op != OpSB) {
+ off2 := v_0.AuxInt
+ ptr := v_0.Args[0]
+ val := v.Args[1]
+ mem := v.Args[2]
+ if !(is32Bit(off1 + off2)) {
break
}
- v.reset(OpAMD64LEAQ1)
+ v.reset(OpAMD64MOVLstore)
v.AuxInt = off1 + off2
- v.Aux = mergeSym(sym1, sym2)
- v.AddArg(x)
- v.AddArg(y)
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(val)
+ v.AddArg(mem)
return true
}
return false
}
-func rewriteValueAMD64_OpAMD64LEAQ2(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpAMD64MOVLstoreconst(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (LEAQ2 [c] {s} (ADDQconst [d] x) y)
- // cond: is32Bit(c+d) && x.Op != OpSB
- // result: (LEAQ2 [c+d] {s} x y)
+ // 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
+ sc := v.AuxInt
s := v.Aux
v_0 := v.Args[0]
if v_0.Op != OpAMD64ADDQconst {
break
}
- d := v_0.AuxInt
- x := v_0.Args[0]
- y := v.Args[1]
- if !(is32Bit(c+d) && x.Op != OpSB) {
- break
- }
- v.reset(OpAMD64LEAQ2)
- v.AuxInt = c + d
- v.Aux = s
- v.AddArg(x)
- v.AddArg(y)
- return true
- }
- // match: (LEAQ2 [c] {s} x (ADDQconst [d] y))
- // cond: is32Bit(c+2*d) && y.Op != OpSB
- // result: (LEAQ2 [c+2*d] {s} x y)
- for {
- c := v.AuxInt
- s := v.Aux
- x := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64ADDQconst {
- break
- }
- d := v_1.AuxInt
- y := v_1.Args[0]
- if !(is32Bit(c+2*d) && y.Op != OpSB) {
+ off := v_0.AuxInt
+ ptr := v_0.Args[0]
+ mem := v.Args[1]
+ if !(ValAndOff(sc).canAdd(off)) {
break
}
- v.reset(OpAMD64LEAQ2)
- v.AuxInt = c + 2*d
+ v.reset(OpAMD64MOVLstoreconst)
+ v.AuxInt = ValAndOff(sc).add(off)
v.Aux = s
- v.AddArg(x)
- v.AddArg(y)
+ v.AddArg(ptr)
+ v.AddArg(mem)
return true
}
- // match: (LEAQ2 [c] {s} x (SHLQconst [1] y))
- // cond:
- // result: (LEAQ4 [c] {s} x y)
+ // 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
- s := v.Aux
- x := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64SHLQconst {
+ sc := v.AuxInt
+ sym1 := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64LEAQ {
break
}
- if v_1.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)) {
break
}
- y := v_1.Args[0]
- v.reset(OpAMD64LEAQ4)
- v.AuxInt = c
- v.Aux = s
- v.AddArg(x)
- v.AddArg(y)
+ v.reset(OpAMD64MOVLstoreconst)
+ v.AuxInt = ValAndOff(sc).add(off)
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(ptr)
+ v.AddArg(mem)
return true
}
- // match: (LEAQ2 [c] {s} x (SHLQconst [2] y))
- // cond:
- // result: (LEAQ8 [c] {s} x y)
+ // 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
- s := v.Aux
- x := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64SHLQconst {
+ x := v.AuxInt
+ sym1 := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64LEAQ1 {
break
}
- if v_1.AuxInt != 2 {
+ 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
}
- y := v_1.Args[0]
- v.reset(OpAMD64LEAQ8)
- v.AuxInt = c
- v.Aux = s
- v.AddArg(x)
- v.AddArg(y)
+ v.reset(OpAMD64MOVLstoreconstidx1)
+ v.AuxInt = ValAndOff(x).add(off)
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(mem)
return true
}
- // match: (LEAQ2 [off1] {sym1} (LEAQ [off2] {sym2} x) y)
- // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2) && x.Op != OpSB
- // result: (LEAQ2 [off1+off2] {mergeSym(sym1,sym2)} x y)
+ // 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 {
- off1 := v.AuxInt
+ x := v.AuxInt
sym1 := v.Aux
v_0 := v.Args[0]
- if v_0.Op != OpAMD64LEAQ {
+ if v_0.Op != OpAMD64LEAQ4 {
break
}
- off2 := v_0.AuxInt
+ off := 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) {
+ ptr := v_0.Args[0]
+ idx := v_0.Args[1]
+ mem := v.Args[1]
+ if !(canMergeSym(sym1, sym2)) {
break
}
- v.reset(OpAMD64LEAQ2)
- v.AuxInt = off1 + off2
+ v.reset(OpAMD64MOVLstoreconstidx4)
+ v.AuxInt = ValAndOff(x).add(off)
v.Aux = mergeSym(sym1, sym2)
- v.AddArg(x)
- v.AddArg(y)
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(mem)
return true
}
- return false
-}
-func rewriteValueAMD64_OpAMD64LEAQ4(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (LEAQ4 [c] {s} (ADDQconst [d] x) y)
- // cond: is32Bit(c+d) && x.Op != OpSB
- // result: (LEAQ4 [c+d] {s} x y)
- for {
- c := v.AuxInt
- s := v.Aux
+ // match: (MOVLstoreconst [x] {sym} (ADDQ ptr idx) mem)
+ // cond:
+ // result: (MOVLstoreconstidx1 [x] {sym} ptr idx mem)
+ for {
+ x := v.AuxInt
+ sym := v.Aux
v_0 := v.Args[0]
- if v_0.Op != OpAMD64ADDQconst {
- break
- }
- d := v_0.AuxInt
- x := v_0.Args[0]
- y := v.Args[1]
- if !(is32Bit(c+d) && x.Op != OpSB) {
+ if v_0.Op != OpAMD64ADDQ {
break
}
- v.reset(OpAMD64LEAQ4)
- v.AuxInt = c + d
- v.Aux = s
- v.AddArg(x)
- v.AddArg(y)
+ ptr := v_0.Args[0]
+ idx := v_0.Args[1]
+ mem := v.Args[1]
+ v.reset(OpAMD64MOVLstoreconstidx1)
+ v.AuxInt = x
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(mem)
return true
}
- // match: (LEAQ4 [c] {s} x (ADDQconst [d] y))
- // cond: is32Bit(c+4*d) && y.Op != OpSB
- // result: (LEAQ4 [c+4*d] {s} x y)
+ // match: (MOVLstoreconst [c] {s} p x:(MOVLstoreconst [a] {s} p mem))
+ // cond: x.Uses == 1 && ValAndOff(a).Off() + 4 == ValAndOff(c).Off() && clobber(x)
+ // result: (MOVQstore [ValAndOff(a).Off()] {s} p (MOVQconst [ValAndOff(a).Val()&0xffffffff | ValAndOff(c).Val()<<32]) mem)
for {
c := v.AuxInt
s := v.Aux
- x := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64ADDQconst {
+ p := v.Args[0]
+ x := v.Args[1]
+ if x.Op != OpAMD64MOVLstoreconst {
break
}
- d := v_1.AuxInt
- y := v_1.Args[0]
- if !(is32Bit(c+4*d) && y.Op != OpSB) {
+ a := x.AuxInt
+ if x.Aux != s {
break
}
- v.reset(OpAMD64LEAQ4)
- v.AuxInt = c + 4*d
- v.Aux = s
- v.AddArg(x)
- v.AddArg(y)
- return true
- }
- // match: (LEAQ4 [c] {s} x (SHLQconst [1] y))
- // cond:
- // result: (LEAQ8 [c] {s} x y)
- for {
- c := v.AuxInt
- s := v.Aux
- x := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64SHLQconst {
+ if p != x.Args[0] {
break
}
- if v_1.AuxInt != 1 {
+ mem := x.Args[1]
+ if !(x.Uses == 1 && ValAndOff(a).Off()+4 == ValAndOff(c).Off() && clobber(x)) {
break
}
- y := v_1.Args[0]
- v.reset(OpAMD64LEAQ8)
- v.AuxInt = c
+ v.reset(OpAMD64MOVQstore)
+ v.AuxInt = ValAndOff(a).Off()
v.Aux = s
- v.AddArg(x)
- v.AddArg(y)
+ v.AddArg(p)
+ v0 := b.NewValue0(v.Line, OpAMD64MOVQconst, config.fe.TypeUInt64())
+ v0.AuxInt = ValAndOff(a).Val()&0xffffffff | ValAndOff(c).Val()<<32
+ v.AddArg(v0)
+ v.AddArg(mem)
return true
}
- // match: (LEAQ4 [off1] {sym1} (LEAQ [off2] {sym2} x) y)
- // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2) && x.Op != OpSB
- // result: (LEAQ4 [off1+off2] {mergeSym(sym1,sym2)} x y)
+ // 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_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
- x := v_0.Args[0]
- y := v.Args[1]
- if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2) && x.Op != OpSB) {
+ ptr := v_0.Args[0]
+ mem := v.Args[1]
+ if !(canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd(off)) {
break
}
- v.reset(OpAMD64LEAQ4)
- v.AuxInt = off1 + off2
+ v.reset(OpAMD64MOVLstoreconst)
+ v.AuxInt = ValAndOff(sc).add(off)
v.Aux = mergeSym(sym1, sym2)
- v.AddArg(x)
- v.AddArg(y)
+ v.AddArg(ptr)
+ v.AddArg(mem)
return true
}
- return false
-}
-func rewriteValueAMD64_OpAMD64LEAQ8(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (LEAQ8 [c] {s} (ADDQconst [d] x) y)
- // cond: is32Bit(c+d) && x.Op != OpSB
- // result: (LEAQ8 [c+d] {s} x y)
+ // 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
+ sc := v.AuxInt
s := v.Aux
v_0 := v.Args[0]
- if v_0.Op != OpAMD64ADDQconst {
+ if v_0.Op != OpAMD64ADDLconst {
break
}
- d := v_0.AuxInt
- x := v_0.Args[0]
- y := v.Args[1]
- if !(is32Bit(c+d) && x.Op != OpSB) {
+ off := v_0.AuxInt
+ ptr := v_0.Args[0]
+ mem := v.Args[1]
+ if !(ValAndOff(sc).canAdd(off)) {
break
}
- v.reset(OpAMD64LEAQ8)
- v.AuxInt = c + d
+ v.reset(OpAMD64MOVLstoreconst)
+ v.AuxInt = ValAndOff(sc).add(off)
v.Aux = s
- v.AddArg(x)
- v.AddArg(y)
+ v.AddArg(ptr)
+ v.AddArg(mem)
return true
}
- // match: (LEAQ8 [c] {s} x (ADDQconst [d] y))
- // cond: is32Bit(c+8*d) && y.Op != OpSB
- // result: (LEAQ8 [c+8*d] {s} x y)
+ return false
+}
+func rewriteValueAMD64_OpAMD64MOVLstoreconstidx1(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (MOVLstoreconstidx1 [c] {sym} ptr (SHLQconst [2] idx) mem)
+ // cond:
+ // result: (MOVLstoreconstidx4 [c] {sym} ptr idx mem)
for {
c := v.AuxInt
- s := v.Aux
- x := v.Args[0]
+ sym := v.Aux
+ ptr := v.Args[0]
v_1 := v.Args[1]
- if v_1.Op != OpAMD64ADDQconst {
+ if v_1.Op != OpAMD64SHLQconst {
break
}
- d := v_1.AuxInt
- y := v_1.Args[0]
- if !(is32Bit(c+8*d) && y.Op != OpSB) {
+ if v_1.AuxInt != 2 {
break
}
- v.reset(OpAMD64LEAQ8)
- v.AuxInt = c + 8*d
- v.Aux = s
- v.AddArg(x)
- v.AddArg(y)
+ idx := v_1.Args[0]
+ mem := v.Args[2]
+ v.reset(OpAMD64MOVLstoreconstidx4)
+ v.AuxInt = c
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(mem)
return true
}
- // match: (LEAQ8 [off1] {sym1} (LEAQ [off2] {sym2} x) y)
- // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2) && x.Op != OpSB
- // result: (LEAQ8 [off1+off2] {mergeSym(sym1,sym2)} x y)
+ // match: (MOVLstoreconstidx1 [x] {sym} (ADDQconst [c] ptr) idx mem)
+ // cond:
+ // result: (MOVLstoreconstidx1 [ValAndOff(x).add(c)] {sym} ptr idx mem)
for {
- off1 := v.AuxInt
- sym1 := v.Aux
+ x := v.AuxInt
+ sym := v.Aux
v_0 := v.Args[0]
- if v_0.Op != OpAMD64LEAQ {
- break
- }
- off2 := v_0.AuxInt
- sym2 := v_0.Aux
- x := v_0.Args[0]
- y := v.Args[1]
- if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2) && x.Op != OpSB) {
+ if v_0.Op != OpAMD64ADDQconst {
break
}
- v.reset(OpAMD64LEAQ8)
- v.AuxInt = off1 + off2
- v.Aux = mergeSym(sym1, sym2)
- v.AddArg(x)
- v.AddArg(y)
+ 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
}
- return false
-}
-func rewriteValueAMD64_OpLeq16(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Leq16 x y)
+ // match: (MOVLstoreconstidx1 [x] {sym} ptr (ADDQconst [c] idx) mem)
// cond:
- // result: (SETLE (CMPW x y))
+ // result: (MOVLstoreconstidx1 [ValAndOff(x).add(c)] {sym} ptr idx mem)
for {
- x := v.Args[0]
- y := v.Args[1]
- v.reset(OpAMD64SETLE)
- v0 := b.NewValue0(v.Line, OpAMD64CMPW, TypeFlags)
- v0.AddArg(x)
- v0.AddArg(y)
- v.AddArg(v0)
+ x := v.AuxInt
+ sym := v.Aux
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64ADDQconst {
+ break
+ }
+ c := v_1.AuxInt
+ idx := v_1.Args[0]
+ mem := v.Args[2]
+ v.reset(OpAMD64MOVLstoreconstidx1)
+ v.AuxInt = ValAndOff(x).add(c)
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(mem)
return true
}
-}
-func rewriteValueAMD64_OpLeq16U(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Leq16U x y)
- // cond:
- // result: (SETBE (CMPW x y))
+ // 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 {
- x := v.Args[0]
- y := v.Args[1]
- v.reset(OpAMD64SETBE)
- v0 := b.NewValue0(v.Line, OpAMD64CMPW, TypeFlags)
- v0.AddArg(x)
- v0.AddArg(y)
- v.AddArg(v0)
- return true
- }
-}
-func rewriteValueAMD64_OpLeq32(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Leq32 x y)
- // cond:
- // result: (SETLE (CMPL x y))
- for {
- x := v.Args[0]
- y := v.Args[1]
- v.reset(OpAMD64SETLE)
- v0 := b.NewValue0(v.Line, OpAMD64CMPL, TypeFlags)
- v0.AddArg(x)
- v0.AddArg(y)
+ c := v.AuxInt
+ s := v.Aux
+ p := v.Args[0]
+ i := v.Args[1]
+ x := v.Args[2]
+ if x.Op != OpAMD64MOVLstoreconstidx1 {
+ break
+ }
+ a := x.AuxInt
+ if x.Aux != s {
+ break
+ }
+ if p != x.Args[0] {
+ break
+ }
+ if i != x.Args[1] {
+ break
+ }
+ mem := x.Args[2]
+ if !(x.Uses == 1 && ValAndOff(a).Off()+4 == ValAndOff(c).Off() && clobber(x)) {
+ break
+ }
+ v.reset(OpAMD64MOVQstoreidx1)
+ v.AuxInt = ValAndOff(a).Off()
+ v.Aux = s
+ v.AddArg(p)
+ v.AddArg(i)
+ v0 := b.NewValue0(v.Line, OpAMD64MOVQconst, config.fe.TypeUInt64())
+ v0.AuxInt = ValAndOff(a).Val()&0xffffffff | ValAndOff(c).Val()<<32
v.AddArg(v0)
+ v.AddArg(mem)
return true
}
+ return false
}
-func rewriteValueAMD64_OpLeq32F(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpAMD64MOVLstoreconstidx4(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (Leq32F x y)
+ // match: (MOVLstoreconstidx4 [x] {sym} (ADDQconst [c] ptr) idx mem)
// cond:
- // result: (SETGEF (UCOMISS y x))
+ // result: (MOVLstoreconstidx4 [ValAndOff(x).add(c)] {sym} ptr idx mem)
for {
- x := v.Args[0]
- y := v.Args[1]
- v.reset(OpAMD64SETGEF)
- v0 := b.NewValue0(v.Line, OpAMD64UCOMISS, TypeFlags)
- v0.AddArg(y)
- v0.AddArg(x)
- v.AddArg(v0)
+ x := v.AuxInt
+ sym := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64ADDQconst {
+ break
+ }
+ c := v_0.AuxInt
+ ptr := v_0.Args[0]
+ idx := v.Args[1]
+ mem := v.Args[2]
+ v.reset(OpAMD64MOVLstoreconstidx4)
+ v.AuxInt = ValAndOff(x).add(c)
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(mem)
return true
}
-}
-func rewriteValueAMD64_OpLeq32U(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Leq32U x y)
+ // match: (MOVLstoreconstidx4 [x] {sym} ptr (ADDQconst [c] idx) mem)
// cond:
- // result: (SETBE (CMPL x y))
+ // result: (MOVLstoreconstidx4 [ValAndOff(x).add(4*c)] {sym} ptr idx mem)
for {
- x := v.Args[0]
- y := v.Args[1]
- v.reset(OpAMD64SETBE)
- v0 := b.NewValue0(v.Line, OpAMD64CMPL, TypeFlags)
- v0.AddArg(x)
- v0.AddArg(y)
- v.AddArg(v0)
+ x := v.AuxInt
+ sym := v.Aux
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64ADDQconst {
+ break
+ }
+ c := v_1.AuxInt
+ idx := v_1.Args[0]
+ mem := v.Args[2]
+ v.reset(OpAMD64MOVLstoreconstidx4)
+ v.AuxInt = ValAndOff(x).add(4 * c)
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(mem)
return true
}
-}
-func rewriteValueAMD64_OpLeq64(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Leq64 x y)
- // cond:
- // result: (SETLE (CMPQ x y))
+ // 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 {
- x := v.Args[0]
- y := v.Args[1]
- v.reset(OpAMD64SETLE)
- v0 := b.NewValue0(v.Line, OpAMD64CMPQ, TypeFlags)
- v0.AddArg(x)
- v0.AddArg(y)
+ c := v.AuxInt
+ s := v.Aux
+ p := v.Args[0]
+ i := v.Args[1]
+ x := v.Args[2]
+ if x.Op != OpAMD64MOVLstoreconstidx4 {
+ break
+ }
+ a := x.AuxInt
+ if x.Aux != s {
+ break
+ }
+ if p != x.Args[0] {
+ break
+ }
+ if i != x.Args[1] {
+ break
+ }
+ mem := x.Args[2]
+ if !(x.Uses == 1 && ValAndOff(a).Off()+4 == ValAndOff(c).Off() && clobber(x)) {
+ break
+ }
+ v.reset(OpAMD64MOVQstoreidx1)
+ v.AuxInt = ValAndOff(a).Off()
+ v.Aux = s
+ v.AddArg(p)
+ v0 := b.NewValue0(v.Line, OpAMD64SHLQconst, i.Type)
+ v0.AuxInt = 2
+ v0.AddArg(i)
v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpAMD64MOVQconst, config.fe.TypeUInt64())
+ v1.AuxInt = ValAndOff(a).Val()&0xffffffff | ValAndOff(c).Val()<<32
+ v.AddArg(v1)
+ v.AddArg(mem)
return true
}
+ return false
}
-func rewriteValueAMD64_OpLeq64F(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpAMD64MOVLstoreidx1(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (Leq64F x y)
+ // match: (MOVLstoreidx1 [c] {sym} ptr (SHLQconst [2] idx) val mem)
// cond:
- // result: (SETGEF (UCOMISD y x))
+ // result: (MOVLstoreidx4 [c] {sym} ptr idx val mem)
for {
- x := v.Args[0]
- y := v.Args[1]
- v.reset(OpAMD64SETGEF)
- v0 := b.NewValue0(v.Line, OpAMD64UCOMISD, TypeFlags)
- v0.AddArg(y)
- v0.AddArg(x)
- v.AddArg(v0)
+ c := v.AuxInt
+ sym := v.Aux
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64SHLQconst {
+ break
+ }
+ if v_1.AuxInt != 2 {
+ break
+ }
+ idx := v_1.Args[0]
+ val := v.Args[2]
+ mem := v.Args[3]
+ v.reset(OpAMD64MOVLstoreidx4)
+ v.AuxInt = c
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(val)
+ v.AddArg(mem)
return true
}
-}
-func rewriteValueAMD64_OpLeq64U(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Leq64U x y)
+ // match: (MOVLstoreidx1 [c] {sym} (ADDQconst [d] ptr) idx val mem)
// cond:
- // result: (SETBE (CMPQ x y))
+ // result: (MOVLstoreidx1 [c+d] {sym} ptr idx val mem)
for {
- x := v.Args[0]
- y := v.Args[1]
- v.reset(OpAMD64SETBE)
- v0 := b.NewValue0(v.Line, OpAMD64CMPQ, TypeFlags)
- v0.AddArg(x)
- v0.AddArg(y)
- v.AddArg(v0)
+ c := v.AuxInt
+ sym := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64ADDQconst {
+ break
+ }
+ d := v_0.AuxInt
+ ptr := v_0.Args[0]
+ idx := v.Args[1]
+ val := v.Args[2]
+ mem := v.Args[3]
+ v.reset(OpAMD64MOVLstoreidx1)
+ v.AuxInt = c + d
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(val)
+ v.AddArg(mem)
return true
}
-}
-func rewriteValueAMD64_OpLeq8(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Leq8 x y)
+ // match: (MOVLstoreidx1 [c] {sym} ptr (ADDQconst [d] idx) val mem)
// cond:
- // result: (SETLE (CMPB x y))
+ // result: (MOVLstoreidx1 [c+d] {sym} ptr idx val mem)
for {
- x := v.Args[0]
- y := v.Args[1]
- v.reset(OpAMD64SETLE)
- v0 := b.NewValue0(v.Line, OpAMD64CMPB, TypeFlags)
- v0.AddArg(x)
- v0.AddArg(y)
- v.AddArg(v0)
+ c := v.AuxInt
+ sym := v.Aux
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64ADDQconst {
+ break
+ }
+ d := v_1.AuxInt
+ idx := v_1.Args[0]
+ val := v.Args[2]
+ mem := v.Args[3]
+ v.reset(OpAMD64MOVLstoreidx1)
+ v.AuxInt = c + d
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(val)
+ v.AddArg(mem)
return true
}
-}
-func rewriteValueAMD64_OpLeq8U(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Leq8U x y)
- // cond:
- // result: (SETBE (CMPB x y))
+ // 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.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)
+ i := v.AuxInt
+ s := v.Aux
+ p := v.Args[0]
+ idx := v.Args[1]
+ v_2 := v.Args[2]
+ if v_2.Op != OpAMD64SHRQconst {
+ break
+ }
+ if v_2.AuxInt != 32 {
+ break
+ }
+ w := v_2.Args[0]
+ x := v.Args[3]
+ if x.Op != OpAMD64MOVLstoreidx1 {
+ break
+ }
+ if x.AuxInt != i-4 {
+ break
+ }
+ if x.Aux != s {
+ break
+ }
+ if p != x.Args[0] {
+ break
+ }
+ if idx != x.Args[1] {
+ break
+ }
+ if w != x.Args[2] {
+ break
+ }
+ mem := x.Args[3]
+ if !(x.Uses == 1 && clobber(x)) {
+ break
+ }
+ v.reset(OpAMD64MOVQstoreidx1)
+ v.AuxInt = i - 4
+ v.Aux = s
+ v.AddArg(p)
+ v.AddArg(idx)
+ v.AddArg(w)
+ v.AddArg(mem)
return true
}
-}
-func rewriteValueAMD64_OpLess16(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Less16 x y)
- // cond:
- // result: (SETL (CMPW x y))
+ // 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 {
- 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)
+ i := v.AuxInt
+ s := v.Aux
+ p := v.Args[0]
+ idx := v.Args[1]
+ v_2 := v.Args[2]
+ if v_2.Op != OpAMD64SHRQconst {
+ break
+ }
+ j := v_2.AuxInt
+ w := v_2.Args[0]
+ x := v.Args[3]
+ if x.Op != OpAMD64MOVLstoreidx1 {
+ break
+ }
+ if x.AuxInt != i-4 {
+ break
+ }
+ if x.Aux != s {
+ break
+ }
+ if p != x.Args[0] {
+ break
+ }
+ if idx != x.Args[1] {
+ break
+ }
+ w0 := x.Args[2]
+ if w0.Op != OpAMD64SHRQconst {
+ break
+ }
+ if w0.AuxInt != j-32 {
+ break
+ }
+ if w != w0.Args[0] {
+ break
+ }
+ mem := x.Args[3]
+ if !(x.Uses == 1 && clobber(x)) {
+ break
+ }
+ v.reset(OpAMD64MOVQstoreidx1)
+ v.AuxInt = i - 4
+ v.Aux = s
+ v.AddArg(p)
+ v.AddArg(idx)
+ v.AddArg(w0)
+ v.AddArg(mem)
return true
}
+ return false
}
-func rewriteValueAMD64_OpLess16U(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpAMD64MOVLstoreidx4(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (Less16U x y)
+ // match: (MOVLstoreidx4 [c] {sym} (ADDQconst [d] ptr) idx val mem)
// cond:
- // result: (SETB (CMPW x y))
+ // result: (MOVLstoreidx4 [c+d] {sym} ptr idx val mem)
for {
- x := v.Args[0]
- y := v.Args[1]
- v.reset(OpAMD64SETB)
- v0 := b.NewValue0(v.Line, OpAMD64CMPW, TypeFlags)
- v0.AddArg(x)
- v0.AddArg(y)
- v.AddArg(v0)
+ c := v.AuxInt
+ sym := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64ADDQconst {
+ break
+ }
+ d := v_0.AuxInt
+ ptr := v_0.Args[0]
+ idx := v.Args[1]
+ val := v.Args[2]
+ mem := v.Args[3]
+ v.reset(OpAMD64MOVLstoreidx4)
+ v.AuxInt = c + d
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(val)
+ v.AddArg(mem)
return true
}
-}
-func rewriteValueAMD64_OpLess32(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Less32 x y)
+ // match: (MOVLstoreidx4 [c] {sym} ptr (ADDQconst [d] idx) val mem)
// cond:
- // result: (SETL (CMPL x y))
+ // result: (MOVLstoreidx4 [c+4*d] {sym} ptr idx val mem)
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
+ sym := v.Aux
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64ADDQconst {
+ break
+ }
+ d := v_1.AuxInt
+ idx := v_1.Args[0]
+ val := v.Args[2]
+ mem := v.Args[3]
+ v.reset(OpAMD64MOVLstoreidx4)
+ v.AuxInt = c + 4*d
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(val)
+ v.AddArg(mem)
return true
}
-}
-func rewriteValueAMD64_OpLess32F(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Less32F x y)
- // cond:
- // result: (SETGF (UCOMISS y x))
+ // 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 {
- x := v.Args[0]
- y := v.Args[1]
- v.reset(OpAMD64SETGF)
- v0 := b.NewValue0(v.Line, OpAMD64UCOMISS, TypeFlags)
- v0.AddArg(y)
- v0.AddArg(x)
+ 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
}
-}
-func rewriteValueAMD64_OpLess32U(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Less32U x y)
- // cond:
- // result: (SETB (CMPL x y))
+ // 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 {
- x := v.Args[0]
- y := v.Args[1]
- v.reset(OpAMD64SETB)
- v0 := b.NewValue0(v.Line, OpAMD64CMPL, TypeFlags)
- v0.AddArg(x)
- v0.AddArg(y)
- v.AddArg(v0)
- return true
- }
-}
-func rewriteValueAMD64_OpLess64(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Less64 x y)
- // cond:
- // result: (SETL (CMPQ x y))
- for {
- x := v.Args[0]
- y := v.Args[1]
- v.reset(OpAMD64SETL)
- v0 := b.NewValue0(v.Line, OpAMD64CMPQ, TypeFlags)
- v0.AddArg(x)
- v0.AddArg(y)
+ i := v.AuxInt
+ s := v.Aux
+ p := v.Args[0]
+ idx := v.Args[1]
+ v_2 := v.Args[2]
+ if v_2.Op != OpAMD64SHRQconst {
+ break
+ }
+ j := v_2.AuxInt
+ w := v_2.Args[0]
+ x := v.Args[3]
+ if x.Op != OpAMD64MOVLstoreidx4 {
+ break
+ }
+ if x.AuxInt != i-4 {
+ break
+ }
+ if x.Aux != s {
+ break
+ }
+ if p != x.Args[0] {
+ break
+ }
+ if idx != x.Args[1] {
+ break
+ }
+ w0 := x.Args[2]
+ if w0.Op != OpAMD64SHRQconst {
+ break
+ }
+ if w0.AuxInt != j-32 {
+ break
+ }
+ if w != w0.Args[0] {
+ break
+ }
+ mem := x.Args[3]
+ if !(x.Uses == 1 && clobber(x)) {
+ break
+ }
+ v.reset(OpAMD64MOVQstoreidx1)
+ v.AuxInt = i - 4
+ v.Aux = s
+ v.AddArg(p)
+ v0 := b.NewValue0(v.Line, OpAMD64SHLQconst, idx.Type)
+ v0.AuxInt = 2
+ v0.AddArg(idx)
v.AddArg(v0)
+ v.AddArg(w0)
+ v.AddArg(mem)
return true
}
+ return false
}
-func rewriteValueAMD64_OpLess64F(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpAMD64MOVOload(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (Less64F x y)
- // cond:
- // result: (SETGF (UCOMISD y x))
+ // match: (MOVOload [off1] {sym} (ADDQconst [off2] ptr) mem)
+ // cond: is32Bit(off1+off2)
+ // result: (MOVOload [off1+off2] {sym} ptr mem)
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)
+ off1 := v.AuxInt
+ sym := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64ADDQconst {
+ break
+ }
+ off2 := v_0.AuxInt
+ ptr := v_0.Args[0]
+ mem := v.Args[1]
+ if !(is32Bit(off1 + off2)) {
+ break
+ }
+ v.reset(OpAMD64MOVOload)
+ v.AuxInt = off1 + off2
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(mem)
return true
}
-}
-func rewriteValueAMD64_OpLess64U(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Less64U x y)
- // cond:
- // result: (SETB (CMPQ x y))
+ // match: (MOVOload [off1] {sym1} (LEAQ [off2] {sym2} base) mem)
+ // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+ // result: (MOVOload [off1+off2] {mergeSym(sym1,sym2)} base mem)
for {
- 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)
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64LEAQ {
+ break
+ }
+ off2 := v_0.AuxInt
+ sym2 := v_0.Aux
+ base := v_0.Args[0]
+ mem := v.Args[1]
+ if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
+ break
+ }
+ v.reset(OpAMD64MOVOload)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(base)
+ v.AddArg(mem)
return true
}
+ return false
}
-func rewriteValueAMD64_OpLess8(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpAMD64MOVOstore(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (Less8 x y)
- // cond:
- // result: (SETL (CMPB x y))
+ // match: (MOVOstore [off1] {sym} (ADDQconst [off2] ptr) val mem)
+ // cond: is32Bit(off1+off2)
+ // result: (MOVOstore [off1+off2] {sym} ptr val mem)
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)
+ off1 := v.AuxInt
+ sym := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64ADDQconst {
+ break
+ }
+ off2 := v_0.AuxInt
+ ptr := v_0.Args[0]
+ val := v.Args[1]
+ mem := v.Args[2]
+ if !(is32Bit(off1 + off2)) {
+ break
+ }
+ v.reset(OpAMD64MOVOstore)
+ v.AuxInt = off1 + off2
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(val)
+ v.AddArg(mem)
return true
}
-}
-func rewriteValueAMD64_OpLess8U(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Less8U x y)
- // cond:
- // result: (SETB (CMPB x y))
+ // match: (MOVOstore [off1] {sym1} (LEAQ [off2] {sym2} base) val mem)
+ // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+ // result: (MOVOstore [off1+off2] {mergeSym(sym1,sym2)} base val mem)
for {
- 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)
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64LEAQ {
+ break
+ }
+ off2 := v_0.AuxInt
+ sym2 := v_0.Aux
+ base := v_0.Args[0]
+ val := v.Args[1]
+ mem := v.Args[2]
+ if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
+ break
+ }
+ v.reset(OpAMD64MOVOstore)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(base)
+ v.AddArg(val)
+ v.AddArg(mem)
return true
}
+ return false
}
-func rewriteValueAMD64_OpLoad(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpAMD64MOVQatomicload(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (Load <t> ptr mem)
- // cond: (is64BitInt(t) || isPtr(t))
- // result: (MOVQload ptr mem)
+ // match: (MOVQatomicload [off1] {sym} (ADDQconst [off2] ptr) mem)
+ // cond: is32Bit(off1+off2)
+ // result: (MOVQatomicload [off1+off2] {sym} ptr mem)
for {
- t := v.Type
- ptr := v.Args[0]
- mem := v.Args[1]
- if !(is64BitInt(t) || isPtr(t)) {
+ off1 := v.AuxInt
+ sym := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64ADDQconst {
break
}
- v.reset(OpAMD64MOVQload)
- v.AddArg(ptr)
- v.AddArg(mem)
- return true
- }
- // match: (Load <t> ptr mem)
- // cond: is32BitInt(t)
- // result: (MOVLload ptr mem)
- for {
- t := v.Type
- ptr := v.Args[0]
+ off2 := v_0.AuxInt
+ ptr := v_0.Args[0]
mem := v.Args[1]
- if !(is32BitInt(t)) {
+ if !(is32Bit(off1 + off2)) {
break
}
- v.reset(OpAMD64MOVLload)
+ v.reset(OpAMD64MOVQatomicload)
+ v.AuxInt = off1 + off2
+ v.Aux = sym
v.AddArg(ptr)
v.AddArg(mem)
return true
}
- // match: (Load <t> ptr mem)
- // cond: is16BitInt(t)
- // result: (MOVWload ptr 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 {
- t := v.Type
- ptr := v.Args[0]
+ 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 !(is16BitInt(t)) {
+ if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
break
}
- v.reset(OpAMD64MOVWload)
+ v.reset(OpAMD64MOVQatomicload)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
v.AddArg(ptr)
v.AddArg(mem)
return true
}
- // match: (Load <t> ptr mem)
- // cond: (t.IsBoolean() || is8BitInt(t))
- // result: (MOVBload ptr mem)
+ return false
+}
+func rewriteValueAMD64_OpAMD64MOVQload(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (MOVQload [off] {sym} ptr (MOVQstore [off2] {sym2} ptr2 x _))
+ // cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
+ // result: x
for {
- t := v.Type
+ off := v.AuxInt
+ sym := v.Aux
ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64MOVQstore {
+ break
+ }
+ off2 := v_1.AuxInt
+ sym2 := v_1.Aux
+ ptr2 := v_1.Args[0]
+ x := v_1.Args[1]
+ if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVQload [off1] {sym} (ADDQconst [off2] ptr) mem)
+ // cond: is32Bit(off1+off2)
+ // result: (MOVQload [off1+off2] {sym} ptr mem)
+ for {
+ off1 := v.AuxInt
+ sym := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64ADDQconst {
+ break
+ }
+ off2 := v_0.AuxInt
+ ptr := v_0.Args[0]
mem := v.Args[1]
- if !(t.IsBoolean() || is8BitInt(t)) {
+ if !(is32Bit(off1 + off2)) {
break
}
- v.reset(OpAMD64MOVBload)
+ v.reset(OpAMD64MOVQload)
+ v.AuxInt = off1 + off2
+ v.Aux = sym
v.AddArg(ptr)
v.AddArg(mem)
return true
}
- // match: (Load <t> ptr mem)
- // cond: is32BitFloat(t)
- // result: (MOVSSload ptr mem)
+ // match: (MOVQload [off1] {sym1} (LEAQ [off2] {sym2} base) mem)
+ // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+ // result: (MOVQload [off1+off2] {mergeSym(sym1,sym2)} base mem)
for {
- t := v.Type
- ptr := v.Args[0]
+ 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 !(is32BitFloat(t)) {
+ if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
break
}
- v.reset(OpAMD64MOVSSload)
+ v.reset(OpAMD64MOVQload)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(base)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVQload [off1] {sym1} (LEAQ1 [off2] {sym2} ptr idx) mem)
+ // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+ // result: (MOVQloadidx1 [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem)
+ for {
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64LEAQ1 {
+ break
+ }
+ off2 := v_0.AuxInt
+ sym2 := v_0.Aux
+ ptr := v_0.Args[0]
+ idx := v_0.Args[1]
+ mem := v.Args[1]
+ if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
+ break
+ }
+ v.reset(OpAMD64MOVQloadidx1)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
v.AddArg(ptr)
+ v.AddArg(idx)
v.AddArg(mem)
return true
}
- // match: (Load <t> ptr mem)
- // cond: is64BitFloat(t)
- // result: (MOVSDload ptr mem)
+ // match: (MOVQload [off1] {sym1} (LEAQ8 [off2] {sym2} ptr idx) mem)
+ // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+ // result: (MOVQloadidx8 [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem)
for {
- t := v.Type
- ptr := v.Args[0]
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64LEAQ8 {
+ break
+ }
+ off2 := v_0.AuxInt
+ sym2 := v_0.Aux
+ ptr := v_0.Args[0]
+ idx := v_0.Args[1]
mem := v.Args[1]
- if !(is64BitFloat(t)) {
+ if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
break
}
- v.reset(OpAMD64MOVSDload)
+ v.reset(OpAMD64MOVQloadidx8)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
v.AddArg(ptr)
+ v.AddArg(idx)
v.AddArg(mem)
return true
}
- return false
-}
-func rewriteValueAMD64_OpLrot16(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Lrot16 <t> x [c])
- // cond:
- // result: (ROLWconst <t> [c&15] x)
+ // match: (MOVQload [off] {sym} (ADDQ ptr idx) mem)
+ // cond: ptr.Op != OpSB
+ // result: (MOVQloadidx1 [off] {sym} ptr idx mem)
for {
- t := v.Type
- x := v.Args[0]
- c := v.AuxInt
- v.reset(OpAMD64ROLWconst)
- v.Type = t
- v.AuxInt = c & 15
- v.AddArg(x)
+ off := v.AuxInt
+ sym := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64ADDQ {
+ break
+ }
+ ptr := v_0.Args[0]
+ idx := v_0.Args[1]
+ mem := v.Args[1]
+ if !(ptr.Op != OpSB) {
+ break
+ }
+ v.reset(OpAMD64MOVQloadidx1)
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(mem)
return true
}
-}
-func rewriteValueAMD64_OpLrot32(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Lrot32 <t> x [c])
- // cond:
- // result: (ROLLconst <t> [c&31] x)
+ // match: (MOVQload [off1] {sym1} (LEAL [off2] {sym2} base) mem)
+ // cond: canMergeSym(sym1, sym2)
+ // result: (MOVQload [off1+off2] {mergeSym(sym1,sym2)} base mem)
for {
- t := v.Type
- x := v.Args[0]
- c := v.AuxInt
- v.reset(OpAMD64ROLLconst)
- v.Type = t
- v.AuxInt = c & 31
- v.AddArg(x)
+ 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(OpAMD64MOVQload)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(base)
+ v.AddArg(mem)
return true
}
-}
-func rewriteValueAMD64_OpLrot64(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Lrot64 <t> x [c])
- // cond:
- // result: (ROLQconst <t> [c&63] x)
+ // match: (MOVQload [off1] {sym} (ADDLconst [off2] ptr) mem)
+ // cond: is32Bit(off1+off2)
+ // result: (MOVQload [off1+off2] {sym} ptr mem)
for {
- t := v.Type
- x := v.Args[0]
- c := v.AuxInt
- v.reset(OpAMD64ROLQconst)
- v.Type = t
- v.AuxInt = c & 63
- v.AddArg(x)
+ 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(OpAMD64MOVQload)
+ v.AuxInt = off1 + off2
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(mem)
return true
}
+ return false
}
-func rewriteValueAMD64_OpLrot8(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpAMD64MOVQloadidx1(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (Lrot8 <t> x [c])
+ // match: (MOVQloadidx1 [c] {sym} ptr (SHLQconst [3] idx) mem)
// cond:
- // result: (ROLBconst <t> [c&7] x)
+ // result: (MOVQloadidx8 [c] {sym} ptr idx mem)
for {
- t := v.Type
- x := v.Args[0]
c := v.AuxInt
- v.reset(OpAMD64ROLBconst)
- v.Type = t
- v.AuxInt = c & 7
- v.AddArg(x)
+ sym := v.Aux
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64SHLQconst {
+ break
+ }
+ if v_1.AuxInt != 3 {
+ break
+ }
+ idx := v_1.Args[0]
+ mem := v.Args[2]
+ v.reset(OpAMD64MOVQloadidx8)
+ v.AuxInt = c
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(mem)
return true
}
-}
-func rewriteValueAMD64_OpLsh16x16(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Lsh16x16 <t> x y)
+ // match: (MOVQloadidx1 [c] {sym} (ADDQconst [d] ptr) idx mem)
// cond:
- // result: (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPWconst y [32])))
+ // result: (MOVQloadidx1 [c+d] {sym} ptr idx 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.AddArg(v0)
- v1 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, t)
- v2 := b.NewValue0(v.Line, OpAMD64CMPWconst, TypeFlags)
- v2.AddArg(y)
- v2.AuxInt = 32
- v1.AddArg(v2)
- v.AddArg(v1)
+ c := v.AuxInt
+ sym := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64ADDQconst {
+ break
+ }
+ d := v_0.AuxInt
+ ptr := v_0.Args[0]
+ idx := v.Args[1]
+ mem := v.Args[2]
+ v.reset(OpAMD64MOVQloadidx1)
+ v.AuxInt = c + d
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(mem)
return true
}
-}
-func rewriteValueAMD64_OpLsh16x32(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Lsh16x32 <t> x y)
+ // match: (MOVQloadidx1 [c] {sym} ptr (ADDQconst [d] idx) mem)
// cond:
- // result: (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPLconst y [32])))
+ // result: (MOVQloadidx1 [c+d] {sym} ptr idx 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.AddArg(v0)
- v1 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, t)
- v2 := b.NewValue0(v.Line, OpAMD64CMPLconst, TypeFlags)
- v2.AddArg(y)
- v2.AuxInt = 32
- v1.AddArg(v2)
- v.AddArg(v1)
+ c := v.AuxInt
+ sym := v.Aux
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64ADDQconst {
+ break
+ }
+ d := v_1.AuxInt
+ idx := v_1.Args[0]
+ mem := v.Args[2]
+ v.reset(OpAMD64MOVQloadidx1)
+ v.AuxInt = c + d
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(mem)
return true
}
+ return false
}
-func rewriteValueAMD64_OpLsh16x64(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpAMD64MOVQloadidx8(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (Lsh16x64 <t> x y)
+ // match: (MOVQloadidx8 [c] {sym} (ADDQconst [d] ptr) idx mem)
// cond:
- // result: (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPQconst y [32])))
+ // result: (MOVQloadidx8 [c+d] {sym} ptr idx 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.AddArg(v0)
- v1 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, t)
- v2 := b.NewValue0(v.Line, OpAMD64CMPQconst, TypeFlags)
- v2.AddArg(y)
- v2.AuxInt = 32
- v1.AddArg(v2)
- v.AddArg(v1)
+ c := v.AuxInt
+ sym := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64ADDQconst {
+ break
+ }
+ d := v_0.AuxInt
+ ptr := v_0.Args[0]
+ idx := v.Args[1]
+ mem := v.Args[2]
+ v.reset(OpAMD64MOVQloadidx8)
+ v.AuxInt = c + d
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(mem)
return true
}
-}
-func rewriteValueAMD64_OpLsh16x8(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Lsh16x8 <t> x y)
+ // match: (MOVQloadidx8 [c] {sym} ptr (ADDQconst [d] idx) mem)
// cond:
- // result: (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPBconst y [32])))
+ // result: (MOVQloadidx8 [c+8*d] {sym} ptr idx 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.AddArg(v0)
- v1 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, t)
- v2 := b.NewValue0(v.Line, OpAMD64CMPBconst, TypeFlags)
- v2.AddArg(y)
- v2.AuxInt = 32
- v1.AddArg(v2)
- v.AddArg(v1)
+ c := v.AuxInt
+ sym := v.Aux
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64ADDQconst {
+ break
+ }
+ d := v_1.AuxInt
+ idx := v_1.Args[0]
+ mem := v.Args[2]
+ v.reset(OpAMD64MOVQloadidx8)
+ v.AuxInt = c + 8*d
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(mem)
return true
}
+ return false
}
-func rewriteValueAMD64_OpLsh32x16(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpAMD64MOVQstore(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (Lsh32x16 <t> x y)
- // cond:
- // result: (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPWconst y [32])))
+ // match: (MOVQstore [off1] {sym} (ADDQconst [off2] ptr) val mem)
+ // cond: is32Bit(off1+off2)
+ // result: (MOVQstore [off1+off2] {sym} ptr val 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.AddArg(v0)
- v1 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, t)
- v2 := b.NewValue0(v.Line, OpAMD64CMPWconst, TypeFlags)
- v2.AddArg(y)
- v2.AuxInt = 32
- v1.AddArg(v2)
- v.AddArg(v1)
+ off1 := v.AuxInt
+ sym := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64ADDQconst {
+ break
+ }
+ off2 := v_0.AuxInt
+ ptr := v_0.Args[0]
+ val := v.Args[1]
+ mem := v.Args[2]
+ if !(is32Bit(off1 + off2)) {
+ break
+ }
+ v.reset(OpAMD64MOVQstore)
+ v.AuxInt = off1 + off2
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(val)
+ v.AddArg(mem)
return true
}
-}
-func rewriteValueAMD64_OpLsh32x32(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Lsh32x32 <t> x y)
- // cond:
- // result: (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPLconst y [32])))
+ // match: (MOVQstore [off] {sym} ptr (MOVQconst [c]) mem)
+ // cond: validValAndOff(c,off)
+ // result: (MOVQstoreconst [makeValAndOff(c,off)] {sym} ptr 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.AddArg(v0)
- v1 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, t)
- v2 := b.NewValue0(v.Line, OpAMD64CMPLconst, TypeFlags)
- v2.AddArg(y)
- v2.AuxInt = 32
- v1.AddArg(v2)
- v.AddArg(v1)
+ off := v.AuxInt
+ sym := v.Aux
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64MOVQconst {
+ break
+ }
+ c := v_1.AuxInt
+ mem := v.Args[2]
+ if !(validValAndOff(c, off)) {
+ break
+ }
+ v.reset(OpAMD64MOVQstoreconst)
+ v.AuxInt = makeValAndOff(c, off)
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(mem)
return true
}
-}
-func rewriteValueAMD64_OpLsh32x64(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Lsh32x64 <t> x y)
- // cond:
- // result: (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPQconst y [32])))
+ // match: (MOVQstore [off1] {sym1} (LEAQ [off2] {sym2} base) val mem)
+ // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+ // result: (MOVQstore [off1+off2] {mergeSym(sym1,sym2)} base val mem)
for {
- t := v.Type
- x := v.Args[0]
- y := v.Args[1]
- v.reset(OpAMD64ANDL)
- v0 := b.NewValue0(v.Line, OpAMD64SHLL, t)
- v0.AddArg(x)
- v0.AddArg(y)
- v.AddArg(v0)
- v1 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, t)
- v2 := b.NewValue0(v.Line, OpAMD64CMPQconst, TypeFlags)
- v2.AddArg(y)
- v2.AuxInt = 32
- v1.AddArg(v2)
- v.AddArg(v1)
- return true
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64LEAQ {
+ break
+ }
+ off2 := v_0.AuxInt
+ sym2 := v_0.Aux
+ base := v_0.Args[0]
+ val := v.Args[1]
+ mem := v.Args[2]
+ if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
+ break
+ }
+ v.reset(OpAMD64MOVQstore)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(base)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
}
-}
-func rewriteValueAMD64_OpLsh32x8(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Lsh32x8 <t> x y)
- // cond:
- // result: (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPBconst y [32])))
+ // match: (MOVQstore [off1] {sym1} (LEAQ1 [off2] {sym2} ptr idx) val mem)
+ // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+ // result: (MOVQstoreidx1 [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem)
for {
- t := v.Type
- x := v.Args[0]
- y := v.Args[1]
- v.reset(OpAMD64ANDL)
- v0 := b.NewValue0(v.Line, OpAMD64SHLL, t)
- v0.AddArg(x)
- v0.AddArg(y)
- v.AddArg(v0)
- v1 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, t)
- v2 := b.NewValue0(v.Line, OpAMD64CMPBconst, TypeFlags)
- v2.AddArg(y)
- v2.AuxInt = 32
- v1.AddArg(v2)
- v.AddArg(v1)
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64LEAQ1 {
+ break
+ }
+ off2 := v_0.AuxInt
+ sym2 := v_0.Aux
+ ptr := v_0.Args[0]
+ idx := v_0.Args[1]
+ val := v.Args[1]
+ mem := v.Args[2]
+ if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
+ break
+ }
+ v.reset(OpAMD64MOVQstoreidx1)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(val)
+ v.AddArg(mem)
return true
}
-}
-func rewriteValueAMD64_OpLsh64x16(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Lsh64x16 <t> x y)
- // cond:
- // result: (ANDQ (SHLQ <t> x y) (SBBQcarrymask <t> (CMPWconst y [64])))
+ // match: (MOVQstore [off1] {sym1} (LEAQ8 [off2] {sym2} ptr idx) val mem)
+ // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+ // result: (MOVQstoreidx8 [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem)
for {
- t := v.Type
- x := v.Args[0]
- y := v.Args[1]
- v.reset(OpAMD64ANDQ)
- v0 := b.NewValue0(v.Line, OpAMD64SHLQ, t)
- v0.AddArg(x)
- v0.AddArg(y)
- v.AddArg(v0)
- v1 := b.NewValue0(v.Line, OpAMD64SBBQcarrymask, t)
- v2 := b.NewValue0(v.Line, OpAMD64CMPWconst, TypeFlags)
- v2.AddArg(y)
- v2.AuxInt = 64
- v1.AddArg(v2)
- v.AddArg(v1)
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64LEAQ8 {
+ break
+ }
+ off2 := v_0.AuxInt
+ sym2 := v_0.Aux
+ ptr := v_0.Args[0]
+ idx := v_0.Args[1]
+ val := v.Args[1]
+ mem := v.Args[2]
+ if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
+ break
+ }
+ v.reset(OpAMD64MOVQstoreidx8)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(val)
+ v.AddArg(mem)
return true
}
-}
-func rewriteValueAMD64_OpLsh64x32(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Lsh64x32 <t> x y)
- // cond:
- // result: (ANDQ (SHLQ <t> x y) (SBBQcarrymask <t> (CMPLconst y [64])))
+ // match: (MOVQstore [off] {sym} (ADDQ ptr idx) val mem)
+ // cond: ptr.Op != OpSB
+ // result: (MOVQstoreidx1 [off] {sym} ptr idx val 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.AddArg(v0)
- v1 := b.NewValue0(v.Line, OpAMD64SBBQcarrymask, t)
- v2 := b.NewValue0(v.Line, OpAMD64CMPLconst, TypeFlags)
- v2.AddArg(y)
- v2.AuxInt = 64
- v1.AddArg(v2)
- v.AddArg(v1)
+ off := v.AuxInt
+ sym := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64ADDQ {
+ break
+ }
+ ptr := v_0.Args[0]
+ idx := v_0.Args[1]
+ val := v.Args[1]
+ mem := v.Args[2]
+ if !(ptr.Op != OpSB) {
+ break
+ }
+ v.reset(OpAMD64MOVQstoreidx1)
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(val)
+ v.AddArg(mem)
return true
}
-}
-func rewriteValueAMD64_OpLsh64x64(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Lsh64x64 <t> x y)
- // cond:
- // result: (ANDQ (SHLQ <t> x y) (SBBQcarrymask <t> (CMPQconst y [64])))
+ // 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 {
- t := v.Type
- x := v.Args[0]
- y := v.Args[1]
- v.reset(OpAMD64ANDQ)
- v0 := b.NewValue0(v.Line, OpAMD64SHLQ, t)
- v0.AddArg(x)
- v0.AddArg(y)
- v.AddArg(v0)
- v1 := b.NewValue0(v.Line, OpAMD64SBBQcarrymask, t)
- v2 := b.NewValue0(v.Line, OpAMD64CMPQconst, TypeFlags)
- v2.AddArg(y)
- v2.AuxInt = 64
- v1.AddArg(v2)
- v.AddArg(v1)
+ 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
}
-}
-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: (MOVQstore [off1] {sym} (ADDLconst [off2] ptr) val mem)
+ // cond: is32Bit(off1+off2)
+ // result: (MOVQstore [off1+off2] {sym} ptr val 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.AddArg(v0)
- v1 := b.NewValue0(v.Line, OpAMD64SBBQcarrymask, t)
- v2 := b.NewValue0(v.Line, OpAMD64CMPBconst, TypeFlags)
- v2.AddArg(y)
- v2.AuxInt = 64
- v1.AddArg(v2)
- v.AddArg(v1)
+ 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]
+ val := v.Args[1]
+ mem := v.Args[2]
+ if !(is32Bit(off1 + off2)) {
+ break
+ }
+ v.reset(OpAMD64MOVQstore)
+ v.AuxInt = off1 + off2
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(val)
+ v.AddArg(mem)
return true
}
+ return false
}
-func rewriteValueAMD64_OpLsh8x16(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpAMD64MOVQstoreconst(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (Lsh8x16 <t> x y)
- // cond:
- // result: (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPWconst y [32])))
- for {
- t := v.Type
- x := v.Args[0]
- y := v.Args[1]
- v.reset(OpAMD64ANDL)
- v0 := b.NewValue0(v.Line, OpAMD64SHLL, t)
- v0.AddArg(x)
- v0.AddArg(y)
- v.AddArg(v0)
- v1 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, t)
- v2 := b.NewValue0(v.Line, OpAMD64CMPWconst, TypeFlags)
- v2.AddArg(y)
- v2.AuxInt = 32
- v1.AddArg(v2)
- v.AddArg(v1)
- return true
- }
-}
-func rewriteValueAMD64_OpLsh8x32(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Lsh8x32 <t> x y)
- // cond:
- // result: (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPLconst y [32])))
- for {
- t := v.Type
- x := v.Args[0]
- y := v.Args[1]
- v.reset(OpAMD64ANDL)
- v0 := b.NewValue0(v.Line, OpAMD64SHLL, t)
- v0.AddArg(x)
- v0.AddArg(y)
- v.AddArg(v0)
- v1 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, t)
- v2 := b.NewValue0(v.Line, OpAMD64CMPLconst, TypeFlags)
- v2.AddArg(y)
- v2.AuxInt = 32
- v1.AddArg(v2)
- v.AddArg(v1)
- return true
- }
-}
-func rewriteValueAMD64_OpLsh8x64(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Lsh8x64 <t> x y)
- // cond:
- // result: (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPQconst y [32])))
- for {
- t := v.Type
- x := v.Args[0]
- y := v.Args[1]
- v.reset(OpAMD64ANDL)
- v0 := b.NewValue0(v.Line, OpAMD64SHLL, t)
- v0.AddArg(x)
- v0.AddArg(y)
- v.AddArg(v0)
- v1 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, t)
- v2 := b.NewValue0(v.Line, OpAMD64CMPQconst, TypeFlags)
- v2.AddArg(y)
- v2.AuxInt = 32
- v1.AddArg(v2)
- v.AddArg(v1)
- return true
- }
-}
-func rewriteValueAMD64_OpLsh8x8(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Lsh8x8 <t> x y)
- // cond:
- // result: (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPBconst y [32])))
- for {
- t := v.Type
- x := v.Args[0]
- y := v.Args[1]
- v.reset(OpAMD64ANDL)
- v0 := b.NewValue0(v.Line, OpAMD64SHLL, t)
- v0.AddArg(x)
- v0.AddArg(y)
- v.AddArg(v0)
- v1 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, t)
- v2 := b.NewValue0(v.Line, OpAMD64CMPBconst, TypeFlags)
- v2.AddArg(y)
- v2.AuxInt = 32
- v1.AddArg(v2)
- v.AddArg(v1)
- return true
- }
-}
-func rewriteValueAMD64_OpAMD64MOVBQSX(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (MOVBQSX x:(MOVBload [off] {sym} ptr mem))
- // cond: x.Uses == 1 && clobber(x)
- // result: @x.Block (MOVBQSXload <v.Type> [off] {sym} ptr mem)
- for {
- x := v.Args[0]
- if x.Op != OpAMD64MOVBload {
- break
- }
- off := x.AuxInt
- sym := x.Aux
- ptr := x.Args[0]
- mem := x.Args[1]
- if !(x.Uses == 1 && clobber(x)) {
- break
- }
- b = x.Block
- v0 := b.NewValue0(v.Line, OpAMD64MOVBQSXload, v.Type)
- v.reset(OpCopy)
- v.AddArg(v0)
- v0.AuxInt = off
- v0.Aux = sym
- v0.AddArg(ptr)
- v0.AddArg(mem)
- return true
- }
- // match: (MOVBQSX (ANDLconst [c] x))
- // cond: c & 0x80 == 0
- // result: (ANDLconst [c & 0x7f] x)
+ // match: (MOVQstoreconst [sc] {s} (ADDQconst [off] ptr) mem)
+ // cond: ValAndOff(sc).canAdd(off)
+ // result: (MOVQstoreconst [ValAndOff(sc).add(off)] {s} ptr mem)
for {
+ sc := v.AuxInt
+ s := v.Aux
v_0 := v.Args[0]
- if v_0.Op != OpAMD64ANDLconst {
+ if v_0.Op != OpAMD64ADDQconst {
break
}
- c := v_0.AuxInt
- x := v_0.Args[0]
- if !(c&0x80 == 0) {
+ off := v_0.AuxInt
+ ptr := v_0.Args[0]
+ mem := v.Args[1]
+ if !(ValAndOff(sc).canAdd(off)) {
break
}
- v.reset(OpAMD64ANDLconst)
- v.AuxInt = c & 0x7f
- v.AddArg(x)
+ v.reset(OpAMD64MOVQstoreconst)
+ v.AuxInt = ValAndOff(sc).add(off)
+ v.Aux = s
+ v.AddArg(ptr)
+ v.AddArg(mem)
return true
}
- return false
-}
-func rewriteValueAMD64_OpAMD64MOVBQSXload(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (MOVBQSXload [off1] {sym1} (LEAQ [off2] {sym2} base) mem)
- // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
- // result: (MOVBQSXload [off1+off2] {mergeSym(sym1,sym2)} base mem)
+ // 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 {
- off1 := v.AuxInt
+ sc := v.AuxInt
sym1 := v.Aux
v_0 := v.Args[0]
if v_0.Op != OpAMD64LEAQ {
break
}
- off2 := v_0.AuxInt
+ off := v_0.AuxInt
sym2 := v_0.Aux
- base := v_0.Args[0]
+ ptr := v_0.Args[0]
mem := v.Args[1]
- if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
+ if !(canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd(off)) {
break
}
- v.reset(OpAMD64MOVBQSXload)
- v.AuxInt = off1 + off2
+ v.reset(OpAMD64MOVQstoreconst)
+ v.AuxInt = ValAndOff(sc).add(off)
v.Aux = mergeSym(sym1, sym2)
- v.AddArg(base)
+ v.AddArg(ptr)
v.AddArg(mem)
return true
}
- return false
-}
-func rewriteValueAMD64_OpAMD64MOVBQZX(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (MOVBQZX x:(MOVBload [off] {sym} ptr mem))
- // cond: x.Uses == 1 && clobber(x)
- // result: @x.Block (MOVBload <v.Type> [off] {sym} ptr mem)
+ // 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.Args[0]
- if x.Op != OpAMD64MOVBload {
+ x := v.AuxInt
+ sym1 := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64LEAQ1 {
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]
+ idx := v_0.Args[1]
+ mem := v.Args[1]
+ if !(canMergeSym(sym1, sym2)) {
break
}
- b = x.Block
- v0 := b.NewValue0(v.Line, OpAMD64MOVBload, v.Type)
- v.reset(OpCopy)
- v.AddArg(v0)
- v0.AuxInt = off
- v0.Aux = sym
- v0.AddArg(ptr)
- v0.AddArg(mem)
+ v.reset(OpAMD64MOVQstoreconstidx1)
+ v.AuxInt = ValAndOff(x).add(off)
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(mem)
return true
}
- // match: (MOVBQZX x:(MOVBloadidx1 [off] {sym} ptr idx mem))
- // cond: x.Uses == 1 && clobber(x)
- // result: @x.Block (MOVBloadidx1 <v.Type> [off] {sym} ptr idx mem)
+ // match: (MOVQstoreconst [x] {sym1} (LEAQ8 [off] {sym2} ptr idx) mem)
+ // cond: canMergeSym(sym1, sym2)
+ // result: (MOVQstoreconstidx8 [ValAndOff(x).add(off)] {mergeSym(sym1,sym2)} ptr idx mem)
for {
- x := v.Args[0]
- if x.Op != OpAMD64MOVBloadidx1 {
+ x := v.AuxInt
+ sym1 := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64LEAQ8 {
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)) {
+ 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
}
- b = x.Block
- v0 := b.NewValue0(v.Line, OpAMD64MOVBloadidx1, v.Type)
- v.reset(OpCopy)
- v.AddArg(v0)
- v0.AuxInt = off
- v0.Aux = sym
- v0.AddArg(ptr)
- v0.AddArg(idx)
- v0.AddArg(mem)
+ v.reset(OpAMD64MOVQstoreconstidx8)
+ v.AuxInt = ValAndOff(x).add(off)
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(mem)
return true
}
- // match: (MOVBQZX (ANDLconst [c] x))
+ // match: (MOVQstoreconst [x] {sym} (ADDQ ptr idx) mem)
// cond:
- // result: (ANDLconst [c & 0xff] x)
+ // result: (MOVQstoreconstidx1 [x] {sym} ptr idx mem)
for {
+ x := v.AuxInt
+ sym := v.Aux
v_0 := v.Args[0]
- if v_0.Op != OpAMD64ANDLconst {
+ if v_0.Op != OpAMD64ADDQ {
break
}
- c := v_0.AuxInt
- x := v_0.Args[0]
- v.reset(OpAMD64ANDLconst)
- v.AuxInt = c & 0xff
- v.AddArg(x)
- return true
- }
- return false
-}
-func rewriteValueAMD64_OpAMD64MOVBload(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (MOVBload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _))
- // cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
- // result: x
- for {
- off := v.AuxInt
- sym := v.Aux
- ptr := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64MOVBstore {
- break
- }
- off2 := v_1.AuxInt
- sym2 := v_1.Aux
- ptr2 := v_1.Args[0]
- x := v_1.Args[1]
- if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
- break
- }
- v.reset(OpCopy)
- v.Type = x.Type
- v.AddArg(x)
- return true
- }
- // match: (MOVBload [off1] {sym} (ADDQconst [off2] ptr) mem)
- // cond: is32Bit(off1+off2)
- // result: (MOVBload [off1+off2] {sym} ptr mem)
- for {
- off1 := v.AuxInt
- sym := v.Aux
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64ADDQconst {
- break
- }
- off2 := v_0.AuxInt
ptr := v_0.Args[0]
+ idx := v_0.Args[1]
mem := v.Args[1]
- if !(is32Bit(off1 + off2)) {
- break
- }
- v.reset(OpAMD64MOVBload)
- v.AuxInt = off1 + off2
+ v.reset(OpAMD64MOVQstoreconstidx1)
+ v.AuxInt = x
v.Aux = sym
v.AddArg(ptr)
+ v.AddArg(idx)
v.AddArg(mem)
return true
}
- // match: (MOVBload [off1] {sym1} (LEAQ [off2] {sym2} base) mem)
- // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
- // result: (MOVBload [off1+off2] {mergeSym(sym1,sym2)} base mem)
+ // 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 {
- off1 := v.AuxInt
+ sc := v.AuxInt
sym1 := v.Aux
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]
+ ptr := v_0.Args[0]
mem := v.Args[1]
- if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
+ if !(canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd(off)) {
break
}
- v.reset(OpAMD64MOVBload)
- v.AuxInt = off1 + off2
+ v.reset(OpAMD64MOVQstoreconst)
+ v.AuxInt = ValAndOff(sc).add(off)
v.Aux = mergeSym(sym1, sym2)
- v.AddArg(base)
+ v.AddArg(ptr)
v.AddArg(mem)
return true
}
- // match: (MOVBload [off1] {sym1} (LEAQ1 [off2] {sym2} ptr idx) mem)
- // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
- // result: (MOVBloadidx1 [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem)
+ // match: (MOVQstoreconst [sc] {s} (ADDLconst [off] ptr) mem)
+ // cond: ValAndOff(sc).canAdd(off)
+ // result: (MOVQstoreconst [ValAndOff(sc).add(off)] {s} ptr mem)
for {
- off1 := v.AuxInt
- sym1 := v.Aux
+ sc := v.AuxInt
+ s := v.Aux
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]
mem := v.Args[1]
- if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
+ if !(ValAndOff(sc).canAdd(off)) {
break
}
- v.reset(OpAMD64MOVBloadidx1)
- v.AuxInt = off1 + off2
- v.Aux = mergeSym(sym1, sym2)
+ v.reset(OpAMD64MOVQstoreconst)
+ v.AuxInt = ValAndOff(sc).add(off)
+ v.Aux = s
v.AddArg(ptr)
- v.AddArg(idx)
v.AddArg(mem)
return true
}
- // match: (MOVBload [off] {sym} (ADDQ ptr idx) mem)
- // cond: ptr.Op != OpSB
- // result: (MOVBloadidx1 [off] {sym} ptr idx mem)
+ return false
+}
+func rewriteValueAMD64_OpAMD64MOVQstoreconstidx1(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (MOVQstoreconstidx1 [c] {sym} ptr (SHLQconst [3] idx) mem)
+ // cond:
+ // result: (MOVQstoreconstidx8 [c] {sym} ptr idx mem)
for {
- off := v.AuxInt
+ c := v.AuxInt
sym := v.Aux
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64ADDQ {
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64SHLQconst {
break
}
- ptr := v_0.Args[0]
- idx := v_0.Args[1]
- mem := v.Args[1]
- if !(ptr.Op != OpSB) {
+ if v_1.AuxInt != 3 {
break
}
- v.reset(OpAMD64MOVBloadidx1)
- v.AuxInt = off
+ 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
}
- return false
-}
-func rewriteValueAMD64_OpAMD64MOVBloadidx1(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (MOVBloadidx1 [c] {sym} (ADDQconst [d] ptr) idx mem)
+ // match: (MOVQstoreconstidx1 [x] {sym} (ADDQconst [c] ptr) idx mem)
// cond:
- // result: (MOVBloadidx1 [c+d] {sym} ptr idx mem)
+ // result: (MOVQstoreconstidx1 [ValAndOff(x).add(c)] {sym} ptr idx mem)
for {
- c := v.AuxInt
+ x := v.AuxInt
sym := v.Aux
v_0 := v.Args[0]
if v_0.Op != OpAMD64ADDQconst {
break
}
- d := v_0.AuxInt
+ c := v_0.AuxInt
ptr := v_0.Args[0]
idx := v.Args[1]
mem := v.Args[2]
- v.reset(OpAMD64MOVBloadidx1)
- v.AuxInt = c + d
+ v.reset(OpAMD64MOVQstoreconstidx1)
+ v.AuxInt = ValAndOff(x).add(c)
v.Aux = sym
v.AddArg(ptr)
v.AddArg(idx)
v.AddArg(mem)
return true
}
- // match: (MOVBloadidx1 [c] {sym} ptr (ADDQconst [d] idx) mem)
+ // match: (MOVQstoreconstidx1 [x] {sym} ptr (ADDQconst [c] idx) mem)
// cond:
- // result: (MOVBloadidx1 [c+d] {sym} ptr idx mem)
+ // result: (MOVQstoreconstidx1 [ValAndOff(x).add(c)] {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 {
break
}
- d := v_1.AuxInt
+ c := v_1.AuxInt
idx := v_1.Args[0]
mem := v.Args[2]
- v.reset(OpAMD64MOVBloadidx1)
- v.AuxInt = c + d
+ v.reset(OpAMD64MOVQstoreconstidx1)
+ v.AuxInt = ValAndOff(x).add(c)
v.Aux = sym
v.AddArg(ptr)
v.AddArg(idx)
@@ -6042,172 +7381,154 @@ func rewriteValueAMD64_OpAMD64MOVBloadidx1(v *Value, config *Config) bool {
}
return false
}
-func rewriteValueAMD64_OpAMD64MOVBstore(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpAMD64MOVQstoreconstidx8(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (MOVBstore [off] {sym} ptr (MOVBQSX x) mem)
+ // match: (MOVQstoreconstidx8 [x] {sym} (ADDQconst [c] ptr) idx mem)
// cond:
- // result: (MOVBstore [off] {sym} ptr x mem)
+ // result: (MOVQstoreconstidx8 [ValAndOff(x).add(c)] {sym} ptr idx mem)
for {
- off := v.AuxInt
+ x := v.AuxInt
sym := v.Aux
- ptr := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64MOVBQSX {
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64ADDQconst {
break
}
- x := v_1.Args[0]
+ c := v_0.AuxInt
+ ptr := v_0.Args[0]
+ idx := v.Args[1]
mem := v.Args[2]
- v.reset(OpAMD64MOVBstore)
- v.AuxInt = off
+ v.reset(OpAMD64MOVQstoreconstidx8)
+ v.AuxInt = ValAndOff(x).add(c)
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: (MOVQstoreconstidx8 [x] {sym} ptr (ADDQconst [c] idx) mem)
// cond:
- // result: (MOVBstore [off] {sym} ptr x mem)
+ // result: (MOVQstoreconstidx8 [ValAndOff(x).add(8*c)] {sym} ptr idx mem)
for {
- off := v.AuxInt
+ x := v.AuxInt
sym := v.Aux
ptr := v.Args[0]
v_1 := v.Args[1]
- if v_1.Op != OpAMD64MOVBQZX {
+ if v_1.Op != OpAMD64ADDQconst {
break
}
- x := v_1.Args[0]
+ c := v_1.AuxInt
+ idx := v_1.Args[0]
mem := v.Args[2]
- v.reset(OpAMD64MOVBstore)
- v.AuxInt = off
+ v.reset(OpAMD64MOVQstoreconstidx8)
+ v.AuxInt = ValAndOff(x).add(8 * c)
v.Aux = sym
v.AddArg(ptr)
- v.AddArg(x)
+ v.AddArg(idx)
v.AddArg(mem)
return true
}
- // match: (MOVBstore [off1] {sym} (ADDQconst [off2] ptr) val mem)
- // cond: is32Bit(off1+off2)
- // result: (MOVBstore [off1+off2] {sym} ptr val mem)
+ return false
+}
+func rewriteValueAMD64_OpAMD64MOVQstoreidx1(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (MOVQstoreidx1 [c] {sym} ptr (SHLQconst [3] idx) val mem)
+ // cond:
+ // result: (MOVQstoreidx8 [c] {sym} ptr idx val mem)
for {
- off1 := v.AuxInt
+ c := v.AuxInt
sym := v.Aux
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64ADDQconst {
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64SHLQconst {
break
}
- off2 := v_0.AuxInt
- ptr := v_0.Args[0]
- val := v.Args[1]
- mem := v.Args[2]
- if !(is32Bit(off1 + off2)) {
+ if v_1.AuxInt != 3 {
break
}
- v.reset(OpAMD64MOVBstore)
- v.AuxInt = off1 + off2
+ 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: (MOVBstore [off] {sym} ptr (MOVLconst [c]) mem)
- // cond: validOff(off)
- // result: (MOVBstoreconst [makeValAndOff(int64(int8(c)),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 {
- off := v.AuxInt
+ c := 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)) {
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64ADDQconst {
break
}
- v.reset(OpAMD64MOVBstoreconst)
- v.AuxInt = makeValAndOff(int64(int8(c)), off)
+ 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: (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)
+ // match: (MOVQstoreidx1 [c] {sym} ptr (ADDQconst [d] idx) val mem)
+ // cond:
+ // result: (MOVQstoreidx1 [c+d] {sym} ptr idx val mem)
for {
- off1 := v.AuxInt
- sym1 := v.Aux
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64LEAQ {
- break
- }
- off2 := v_0.AuxInt
- sym2 := v_0.Aux
- base := v_0.Args[0]
- val := v.Args[1]
- mem := v.Args[2]
- if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
- break
- }
- v.reset(OpAMD64MOVBstore)
- v.AuxInt = off1 + off2
- v.Aux = mergeSym(sym1, sym2)
- v.AddArg(base)
- v.AddArg(val)
- v.AddArg(mem)
- return true
- }
- // match: (MOVBstore [off1] {sym1} (LEAQ1 [off2] {sym2} ptr idx) val mem)
- // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
- // result: (MOVBstoreidx1 [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem)
- for {
- off1 := v.AuxInt
- sym1 := v.Aux
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64LEAQ1 {
- break
- }
- off2 := v_0.AuxInt
- sym2 := v_0.Aux
- ptr := v_0.Args[0]
- idx := v_0.Args[1]
- val := v.Args[1]
- mem := v.Args[2]
- if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
+ c := v.AuxInt
+ sym := v.Aux
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64ADDQconst {
break
}
- v.reset(OpAMD64MOVBstoreidx1)
- v.AuxInt = off1 + off2
- v.Aux = mergeSym(sym1, sym2)
+ 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: (MOVBstore [off] {sym} (ADDQ ptr idx) val mem)
- // cond: ptr.Op != OpSB
- // result: (MOVBstoreidx1 [off] {sym} ptr idx val mem)
+ return false
+}
+func rewriteValueAMD64_OpAMD64MOVQstoreidx8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (MOVQstoreidx8 [c] {sym} (ADDQconst [d] ptr) idx val mem)
+ // cond:
+ // result: (MOVQstoreidx8 [c+d] {sym} ptr idx val mem)
for {
- off := v.AuxInt
+ c := v.AuxInt
sym := v.Aux
v_0 := v.Args[0]
- if v_0.Op != OpAMD64ADDQ {
+ if v_0.Op != OpAMD64ADDQconst {
break
}
+ d := v_0.AuxInt
ptr := v_0.Args[0]
- idx := v_0.Args[1]
- val := v.Args[1]
- mem := v.Args[2]
- if !(ptr.Op != OpSB) {
- break
- }
- v.reset(OpAMD64MOVBstoreidx1)
- v.AuxInt = off
+ 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)
@@ -6215,316 +7536,239 @@ func rewriteValueAMD64_OpAMD64MOVBstore(v *Value, config *Config) bool {
v.AddArg(mem)
return true
}
- // match: (MOVBstore [i] {s} p (SHRQconst [8] w) x:(MOVBstore [i-1] {s} p w mem))
- // cond: x.Uses == 1 && clobber(x)
- // result: (MOVWstore [i-1] {s} p w mem)
- for {
- i := v.AuxInt
- s := v.Aux
- p := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64SHRQconst {
- break
- }
- if v_1.AuxInt != 8 {
- break
- }
- w := v_1.Args[0]
- x := v.Args[2]
- if x.Op != OpAMD64MOVBstore {
- break
- }
- if x.AuxInt != i-1 {
- break
- }
- if x.Aux != s {
- break
- }
- if p != x.Args[0] {
- break
- }
- if w != x.Args[1] {
- break
- }
- mem := x.Args[2]
- if !(x.Uses == 1 && clobber(x)) {
- break
- }
- v.reset(OpAMD64MOVWstore)
- v.AuxInt = i - 1
- v.Aux = s
- v.AddArg(p)
- v.AddArg(w)
- v.AddArg(mem)
- return true
- }
- // match: (MOVBstore [i] {s} p (SHRQconst [j] w) x:(MOVBstore [i-1] {s} p w0:(SHRQconst [j-8] w) mem))
- // cond: x.Uses == 1 && clobber(x)
- // result: (MOVWstore [i-1] {s} p w0 mem)
+ // match: (MOVQstoreidx8 [c] {sym} ptr (ADDQconst [d] idx) val mem)
+ // cond:
+ // result: (MOVQstoreidx8 [c+8*d] {sym} ptr idx val mem)
for {
- i := v.AuxInt
- s := v.Aux
- p := v.Args[0]
+ c := v.AuxInt
+ sym := v.Aux
+ 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 != OpAMD64MOVBstore {
- break
- }
- if x.AuxInt != i-1 {
- break
- }
- if x.Aux != s {
- break
- }
- if p != x.Args[0] {
- break
- }
- w0 := x.Args[1]
- if w0.Op != OpAMD64SHRQconst {
- break
- }
- if w0.AuxInt != j-8 {
- break
- }
- if w != w0.Args[0] {
- break
- }
- mem := x.Args[2]
- if !(x.Uses == 1 && clobber(x)) {
+ if v_1.Op != OpAMD64ADDQconst {
break
}
- v.reset(OpAMD64MOVWstore)
- v.AuxInt = i - 1
- v.Aux = s
- v.AddArg(p)
- v.AddArg(w0)
+ d := v_1.AuxInt
+ idx := v_1.Args[0]
+ val := v.Args[2]
+ mem := v.Args[3]
+ v.reset(OpAMD64MOVQstoreidx8)
+ v.AuxInt = c + 8*d
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(val)
v.AddArg(mem)
return true
}
return false
}
-func rewriteValueAMD64_OpAMD64MOVBstoreconst(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpAMD64MOVSDload(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (MOVBstoreconst [sc] {s} (ADDQconst [off] ptr) mem)
- // cond: ValAndOff(sc).canAdd(off)
- // result: (MOVBstoreconst [ValAndOff(sc).add(off)] {s} ptr mem)
+ // match: (MOVSDload [off1] {sym} (ADDQconst [off2] ptr) mem)
+ // cond: is32Bit(off1+off2)
+ // result: (MOVSDload [off1+off2] {sym} ptr mem)
for {
- sc := v.AuxInt
- s := v.Aux
+ off1 := v.AuxInt
+ sym := v.Aux
v_0 := v.Args[0]
if v_0.Op != OpAMD64ADDQconst {
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(OpAMD64MOVBstoreconst)
- v.AuxInt = ValAndOff(sc).add(off)
- v.Aux = s
+ v.reset(OpAMD64MOVSDload)
+ v.AuxInt = off1 + off2
+ v.Aux = sym
v.AddArg(ptr)
v.AddArg(mem)
return true
}
- // match: (MOVBstoreconst [sc] {sym1} (LEAQ [off] {sym2} ptr) mem)
- // cond: canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd(off)
- // result: (MOVBstoreconst [ValAndOff(sc).add(off)] {mergeSym(sym1, sym2)} ptr mem)
+ // match: (MOVSDload [off1] {sym1} (LEAQ [off2] {sym2} base) mem)
+ // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+ // result: (MOVSDload [off1+off2] {mergeSym(sym1,sym2)} base mem)
for {
- sc := v.AuxInt
+ off1 := v.AuxInt
sym1 := v.Aux
v_0 := v.Args[0]
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(OpAMD64MOVBstoreconst)
- v.AuxInt = ValAndOff(sc).add(off)
+ v.reset(OpAMD64MOVSDload)
+ v.AuxInt = off1 + off2
v.Aux = mergeSym(sym1, sym2)
- v.AddArg(ptr)
+ v.AddArg(base)
v.AddArg(mem)
return true
}
- // match: (MOVBstoreconst [x] {sym1} (LEAQ1 [off] {sym2} ptr idx) mem)
- // cond: canMergeSym(sym1, sym2)
- // result: (MOVBstoreconstidx1 [ValAndOff(x).add(off)] {mergeSym(sym1,sym2)} ptr idx mem)
+ // match: (MOVSDload [off1] {sym1} (LEAQ1 [off2] {sym2} ptr idx) mem)
+ // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+ // result: (MOVSDloadidx1 [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem)
for {
- x := v.AuxInt
+ off1 := v.AuxInt
sym1 := v.Aux
v_0 := v.Args[0]
if v_0.Op != OpAMD64LEAQ1 {
break
}
- off := v_0.AuxInt
+ off2 := 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)) {
+ if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
break
}
- v.reset(OpAMD64MOVBstoreconstidx1)
- v.AuxInt = ValAndOff(x).add(off)
+ v.reset(OpAMD64MOVSDloadidx1)
+ v.AuxInt = off1 + off2
v.Aux = mergeSym(sym1, sym2)
v.AddArg(ptr)
v.AddArg(idx)
v.AddArg(mem)
return true
}
- // match: (MOVBstoreconst [x] {sym} (ADDQ ptr idx) mem)
- // cond:
- // result: (MOVBstoreconstidx1 [x] {sym} ptr idx mem)
+ // match: (MOVSDload [off1] {sym1} (LEAQ8 [off2] {sym2} ptr idx) mem)
+ // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+ // result: (MOVSDloadidx8 [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem)
for {
- x := v.AuxInt
- sym := v.Aux
+ off1 := v.AuxInt
+ sym1 := v.Aux
v_0 := v.Args[0]
- if v_0.Op != OpAMD64ADDQ {
+ if v_0.Op != OpAMD64LEAQ8 {
break
}
+ off2 := v_0.AuxInt
+ sym2 := v_0.Aux
ptr := v_0.Args[0]
idx := v_0.Args[1]
mem := v.Args[1]
- v.reset(OpAMD64MOVBstoreconstidx1)
- v.AuxInt = x
- v.Aux = sym
+ if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
+ break
+ }
+ v.reset(OpAMD64MOVSDloadidx8)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
v.AddArg(ptr)
v.AddArg(idx)
v.AddArg(mem)
return true
}
- // match: (MOVBstoreconst [c] {s} p x:(MOVBstoreconst [a] {s} p mem))
- // cond: x.Uses == 1 && ValAndOff(a).Off() + 1 == ValAndOff(c).Off() && clobber(x)
- // result: (MOVWstoreconst [makeValAndOff(ValAndOff(a).Val()&0xff | ValAndOff(c).Val()<<8, ValAndOff(a).Off())] {s} p mem)
+ // match: (MOVSDload [off] {sym} (ADDQ ptr idx) mem)
+ // cond: ptr.Op != OpSB
+ // result: (MOVSDloadidx1 [off] {sym} ptr idx mem)
for {
- c := v.AuxInt
- s := v.Aux
- p := v.Args[0]
- x := v.Args[1]
- if x.Op != OpAMD64MOVBstoreconst {
- break
- }
- a := x.AuxInt
- if x.Aux != s {
- break
- }
- if p != x.Args[0] {
+ off := v.AuxInt
+ sym := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64ADDQ {
break
}
- mem := x.Args[1]
- if !(x.Uses == 1 && ValAndOff(a).Off()+1 == ValAndOff(c).Off() && clobber(x)) {
+ ptr := v_0.Args[0]
+ idx := v_0.Args[1]
+ mem := v.Args[1]
+ if !(ptr.Op != OpSB) {
break
}
- v.reset(OpAMD64MOVWstoreconst)
- v.AuxInt = makeValAndOff(ValAndOff(a).Val()&0xff|ValAndOff(c).Val()<<8, ValAndOff(a).Off())
- v.Aux = s
- v.AddArg(p)
+ v.reset(OpAMD64MOVSDloadidx1)
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(idx)
v.AddArg(mem)
return true
}
return false
}
-func rewriteValueAMD64_OpAMD64MOVBstoreconstidx1(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpAMD64MOVSDloadidx1(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (MOVBstoreconstidx1 [x] {sym} (ADDQconst [c] ptr) idx mem)
+ // match: (MOVSDloadidx1 [c] {sym} ptr (SHLQconst [3] idx) mem)
// cond:
- // result: (MOVBstoreconstidx1 [ValAndOff(x).add(c)] {sym} ptr idx mem)
+ // result: (MOVSDloadidx8 [c] {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 != OpAMD64SHLQconst {
+ break
+ }
+ if v_1.AuxInt != 3 {
+ break
+ }
+ idx := v_1.Args[0]
+ mem := v.Args[2]
+ v.reset(OpAMD64MOVSDloadidx8)
+ v.AuxInt = c
+ v.Aux = sym
+ 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)
+ for {
+ c := v.AuxInt
sym := v.Aux
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(OpAMD64MOVBstoreconstidx1)
- v.AuxInt = ValAndOff(x).add(c)
+ v.reset(OpAMD64MOVSDloadidx1)
+ v.AuxInt = c + d
v.Aux = sym
v.AddArg(ptr)
v.AddArg(idx)
v.AddArg(mem)
return true
}
- // match: (MOVBstoreconstidx1 [x] {sym} ptr (ADDQconst [c] idx) mem)
+ // match: (MOVSDloadidx1 [c] {sym} ptr (ADDQconst [d] idx) mem)
// cond:
- // result: (MOVBstoreconstidx1 [ValAndOff(x).add(c)] {sym} ptr idx mem)
+ // result: (MOVSDloadidx1 [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 != OpAMD64ADDQconst {
break
}
- c := v_1.AuxInt
+ d := v_1.AuxInt
idx := v_1.Args[0]
mem := v.Args[2]
- v.reset(OpAMD64MOVBstoreconstidx1)
- v.AuxInt = ValAndOff(x).add(c)
+ v.reset(OpAMD64MOVSDloadidx1)
+ v.AuxInt = c + d
v.Aux = sym
v.AddArg(ptr)
v.AddArg(idx)
v.AddArg(mem)
return true
}
- // match: (MOVBstoreconstidx1 [c] {s} p i x:(MOVBstoreconstidx1 [a] {s} p i mem))
- // cond: x.Uses == 1 && ValAndOff(a).Off() + 1 == ValAndOff(c).Off() && clobber(x)
- // result: (MOVWstoreconstidx1 [makeValAndOff(ValAndOff(a).Val()&0xff | ValAndOff(c).Val()<<8, ValAndOff(a).Off())] {s} p i mem)
- for {
- c := v.AuxInt
- s := v.Aux
- p := v.Args[0]
- i := v.Args[1]
- x := v.Args[2]
- if x.Op != OpAMD64MOVBstoreconstidx1 {
- break
- }
- a := x.AuxInt
- if x.Aux != s {
- break
- }
- if p != x.Args[0] {
- break
- }
- if i != x.Args[1] {
- break
- }
- mem := x.Args[2]
- if !(x.Uses == 1 && ValAndOff(a).Off()+1 == ValAndOff(c).Off() && clobber(x)) {
- break
- }
- v.reset(OpAMD64MOVWstoreconstidx1)
- v.AuxInt = makeValAndOff(ValAndOff(a).Val()&0xff|ValAndOff(c).Val()<<8, ValAndOff(a).Off())
- v.Aux = s
- v.AddArg(p)
- v.AddArg(i)
- v.AddArg(mem)
- return true
- }
return false
}
-func rewriteValueAMD64_OpAMD64MOVBstoreidx1(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpAMD64MOVSDloadidx8(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (MOVBstoreidx1 [c] {sym} (ADDQconst [d] ptr) idx val mem)
+ // match: (MOVSDloadidx8 [c] {sym} (ADDQconst [d] ptr) idx mem)
// cond:
- // result: (MOVBstoreidx1 [c+d] {sym} ptr idx val mem)
+ // result: (MOVSDloadidx8 [c+d] {sym} ptr idx mem)
for {
c := v.AuxInt
sym := v.Aux
@@ -6535,20 +7779,18 @@ func rewriteValueAMD64_OpAMD64MOVBstoreidx1(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(OpAMD64MOVBstoreidx1)
+ mem := v.Args[2]
+ v.reset(OpAMD64MOVSDloadidx8)
v.AuxInt = c + d
v.Aux = sym
v.AddArg(ptr)
v.AddArg(idx)
- v.AddArg(val)
v.AddArg(mem)
return true
}
- // match: (MOVBstoreidx1 [c] {sym} ptr (ADDQconst [d] idx) val mem)
+ // match: (MOVSDloadidx8 [c] {sym} ptr (ADDQconst [d] idx) mem)
// cond:
- // result: (MOVBstoreidx1 [c+d] {sym} ptr idx val mem)
+ // result: (MOVSDloadidx8 [c+8*d] {sym} ptr idx mem)
for {
c := v.AuxInt
sym := v.Aux
@@ -6559,174 +7801,316 @@ func rewriteValueAMD64_OpAMD64MOVBstoreidx1(v *Value, config *Config) bool {
}
d := v_1.AuxInt
idx := v_1.Args[0]
- val := v.Args[2]
- mem := v.Args[3]
- v.reset(OpAMD64MOVBstoreidx1)
- v.AuxInt = c + d
+ mem := v.Args[2]
+ v.reset(OpAMD64MOVSDloadidx8)
+ v.AuxInt = c + 8*d
v.Aux = sym
v.AddArg(ptr)
v.AddArg(idx)
- v.AddArg(val)
v.AddArg(mem)
return true
}
- // match: (MOVBstoreidx1 [i] {s} p idx (SHRQconst [8] w) x:(MOVBstoreidx1 [i-1] {s} p idx w mem))
- // cond: x.Uses == 1 && clobber(x)
- // result: (MOVWstoreidx1 [i-1] {s} p idx w mem)
+ return false
+}
+func rewriteValueAMD64_OpAMD64MOVSDstore(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (MOVSDstore [off1] {sym} (ADDQconst [off2] ptr) val mem)
+ // cond: is32Bit(off1+off2)
+ // result: (MOVSDstore [off1+off2] {sym} ptr val mem)
for {
- i := v.AuxInt
- s := v.Aux
- p := v.Args[0]
- idx := v.Args[1]
- v_2 := v.Args[2]
- if v_2.Op != OpAMD64SHRQconst {
- break
- }
- if v_2.AuxInt != 8 {
- break
- }
- w := v_2.Args[0]
- x := v.Args[3]
- if x.Op != OpAMD64MOVBstoreidx1 {
- break
- }
- if x.AuxInt != i-1 {
+ off1 := v.AuxInt
+ sym := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64ADDQconst {
break
}
- if x.Aux != s {
+ off2 := v_0.AuxInt
+ ptr := v_0.Args[0]
+ val := v.Args[1]
+ mem := v.Args[2]
+ if !(is32Bit(off1 + off2)) {
break
}
- if p != x.Args[0] {
+ v.reset(OpAMD64MOVSDstore)
+ v.AuxInt = off1 + off2
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVSDstore [off1] {sym1} (LEAQ [off2] {sym2} base) val mem)
+ // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+ // result: (MOVSDstore [off1+off2] {mergeSym(sym1,sym2)} base val mem)
+ for {
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64LEAQ {
break
}
- if idx != x.Args[1] {
+ 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
}
- if w != x.Args[2] {
+ v.reset(OpAMD64MOVSDstore)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(base)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVSDstore [off1] {sym1} (LEAQ1 [off2] {sym2} ptr idx) val mem)
+ // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+ // result: (MOVSDstoreidx1 [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem)
+ for {
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64LEAQ1 {
break
}
- mem := x.Args[3]
- if !(x.Uses == 1 && clobber(x)) {
+ off2 := v_0.AuxInt
+ sym2 := v_0.Aux
+ ptr := v_0.Args[0]
+ idx := v_0.Args[1]
+ val := v.Args[1]
+ mem := v.Args[2]
+ if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
break
}
- v.reset(OpAMD64MOVWstoreidx1)
- v.AuxInt = i - 1
- v.Aux = s
- v.AddArg(p)
+ v.reset(OpAMD64MOVSDstoreidx1)
+ 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: (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: (MOVSDstore [off1] {sym1} (LEAQ8 [off2] {sym2} ptr idx) val mem)
+ // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+ // result: (MOVSDstoreidx8 [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem)
for {
- i := v.AuxInt
- s := v.Aux
- p := v.Args[0]
- idx := v.Args[1]
- v_2 := v.Args[2]
- if v_2.Op != OpAMD64SHRQconst {
- break
- }
- j := v_2.AuxInt
- w := v_2.Args[0]
- x := v.Args[3]
- if x.Op != OpAMD64MOVBstoreidx1 {
- break
- }
- if x.AuxInt != i-1 {
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64LEAQ8 {
break
}
- if x.Aux != s {
+ off2 := v_0.AuxInt
+ sym2 := v_0.Aux
+ ptr := v_0.Args[0]
+ idx := v_0.Args[1]
+ val := v.Args[1]
+ mem := v.Args[2]
+ if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
break
}
- if p != x.Args[0] {
+ v.reset(OpAMD64MOVSDstoreidx8)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVSDstore [off] {sym} (ADDQ ptr idx) val mem)
+ // cond: ptr.Op != OpSB
+ // result: (MOVSDstoreidx1 [off] {sym} ptr idx val mem)
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64ADDQ {
break
}
- if idx != x.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
}
- w0 := x.Args[2]
- if w0.Op != OpAMD64SHRQconst {
+ v.reset(OpAMD64MOVSDstoreidx1)
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValueAMD64_OpAMD64MOVSDstoreidx1(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (MOVSDstoreidx1 [c] {sym} ptr (SHLQconst [3] idx) val mem)
+ // cond:
+ // result: (MOVSDstoreidx8 [c] {sym} ptr idx val mem)
+ for {
+ c := v.AuxInt
+ sym := v.Aux
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64SHLQconst {
break
}
- if w0.AuxInt != j-8 {
+ if v_1.AuxInt != 3 {
break
}
- if w != w0.Args[0] {
+ 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: (MOVSDstoreidx1 [c] {sym} (ADDQconst [d] ptr) idx val mem)
+ // cond:
+ // result: (MOVSDstoreidx1 [c+d] {sym} ptr idx val mem)
+ for {
+ c := v.AuxInt
+ sym := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64ADDQconst {
break
}
- mem := x.Args[3]
- 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(OpAMD64MOVSDstoreidx1)
+ v.AuxInt = c + d
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVSDstoreidx1 [c] {sym} ptr (ADDQconst [d] idx) val mem)
+ // cond:
+ // result: (MOVSDstoreidx1 [c+d] {sym} ptr idx val mem)
+ for {
+ c := v.AuxInt
+ sym := v.Aux
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64ADDQconst {
break
}
- v.reset(OpAMD64MOVWstoreidx1)
- v.AuxInt = i - 1
- v.Aux = s
- v.AddArg(p)
+ 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(w0)
+ v.AddArg(val)
v.AddArg(mem)
return true
}
return false
}
-func rewriteValueAMD64_OpAMD64MOVLQSX(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpAMD64MOVSDstoreidx8(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)
+ // match: (MOVSDstoreidx8 [c] {sym} (ADDQconst [d] ptr) idx val mem)
+ // cond:
+ // result: (MOVSDstoreidx8 [c+d] {sym} ptr idx val mem)
for {
- x := v.Args[0]
- if x.Op != OpAMD64MOVLload {
+ c := v.AuxInt
+ sym := v.Aux
+ 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(OpAMD64MOVSDstoreidx8)
+ v.AuxInt = c + d
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVSDstoreidx8 [c] {sym} ptr (ADDQconst [d] idx) val mem)
+ // cond:
+ // result: (MOVSDstoreidx8 [c+8*d] {sym} ptr idx val mem)
+ for {
+ c := v.AuxInt
+ sym := v.Aux
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64ADDQconst {
break
}
- 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)
+ 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: (MOVLQSX (ANDLconst [c] x))
- // cond: c & 0x80000000 == 0
- // result: (ANDLconst [c & 0x7fffffff] x)
+ 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 != OpAMD64ANDLconst {
+ if v_0.Op != OpAMD64ADDQconst {
break
}
- c := v_0.AuxInt
- x := v_0.Args[0]
- if !(c&0x80000000 == 0) {
+ off2 := v_0.AuxInt
+ ptr := v_0.Args[0]
+ mem := v.Args[1]
+ if !(is32Bit(off1 + off2)) {
break
}
- v.reset(OpAMD64ANDLconst)
- v.AuxInt = c & 0x7fffffff
- v.AddArg(x)
+ v.reset(OpAMD64MOVSSload)
+ v.AuxInt = off1 + off2
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(mem)
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)
+ // match: (MOVSSload [off1] {sym1} (LEAQ [off2] {sym2} base) mem)
// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
- // result: (MOVLQSXload [off1+off2] {mergeSym(sym1,sym2)} base mem)
+ // result: (MOVSSload [off1+off2] {mergeSym(sym1,sym2)} base mem)
for {
off1 := v.AuxInt
sym1 := v.Aux
@@ -6741,195 +8125,21 @@ func rewriteValueAMD64_OpAMD64MOVLQSXload(v *Value, config *Config) bool {
if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
break
}
- v.reset(OpAMD64MOVLQSXload)
+ v.reset(OpAMD64MOVSSload)
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)
+ // 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.Args[0]
- if x.Op != OpAMD64MOVLload {
- break
- }
- off := x.AuxInt
- sym := x.Aux
- ptr := x.Args[0]
- mem := x.Args[1]
- if !(x.Uses == 1 && clobber(x)) {
- break
- }
- b = x.Block
- v0 := b.NewValue0(v.Line, OpAMD64MOVLload, v.Type)
- v.reset(OpCopy)
- v.AddArg(v0)
- v0.AuxInt = off
- v0.Aux = sym
- v0.AddArg(ptr)
- v0.AddArg(mem)
- return true
- }
- // match: (MOVLQZX x:(MOVLloadidx1 [off] {sym} ptr idx mem))
- // cond: x.Uses == 1 && clobber(x)
- // result: @x.Block (MOVLloadidx1 <v.Type> [off] {sym} ptr idx mem)
- for {
- x := v.Args[0]
- if x.Op != OpAMD64MOVLloadidx1 {
- break
- }
- off := x.AuxInt
- sym := x.Aux
- ptr := x.Args[0]
- idx := x.Args[1]
- mem := x.Args[2]
- if !(x.Uses == 1 && clobber(x)) {
- break
- }
- b = x.Block
- v0 := b.NewValue0(v.Line, OpAMD64MOVLloadidx1, v.Type)
- v.reset(OpCopy)
- v.AddArg(v0)
- v0.AuxInt = off
- v0.Aux = sym
- v0.AddArg(ptr)
- v0.AddArg(idx)
- v0.AddArg(mem)
- return true
- }
- // match: (MOVLQZX x:(MOVLloadidx4 [off] {sym} ptr idx mem))
- // cond: x.Uses == 1 && clobber(x)
- // result: @x.Block (MOVLloadidx4 <v.Type> [off] {sym} ptr idx mem)
- for {
- x := v.Args[0]
- if x.Op != OpAMD64MOVLloadidx4 {
- break
- }
- off := x.AuxInt
- sym := x.Aux
- ptr := x.Args[0]
- idx := x.Args[1]
- mem := x.Args[2]
- if !(x.Uses == 1 && clobber(x)) {
- break
- }
- b = x.Block
- v0 := b.NewValue0(v.Line, OpAMD64MOVLloadidx4, v.Type)
- v.reset(OpCopy)
- v.AddArg(v0)
- v0.AuxInt = off
- v0.Aux = sym
- v0.AddArg(ptr)
- v0.AddArg(idx)
- v0.AddArg(mem)
- return true
- }
- // match: (MOVLQZX (ANDLconst [c] x))
- // cond:
- // result: (ANDLconst [c] x)
- for {
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64ANDLconst {
- break
- }
- c := v_0.AuxInt
- x := v_0.Args[0]
- v.reset(OpAMD64ANDLconst)
- v.AuxInt = c
- v.AddArg(x)
- return true
- }
- return false
-}
-func rewriteValueAMD64_OpAMD64MOVLload(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (MOVLload [off] {sym} ptr (MOVLstore [off2] {sym2} ptr2 x _))
- // cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
- // result: x
- for {
- off := v.AuxInt
- sym := v.Aux
- ptr := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64MOVLstore {
- break
- }
- off2 := v_1.AuxInt
- sym2 := v_1.Aux
- ptr2 := v_1.Args[0]
- x := v_1.Args[1]
- if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
- break
- }
- v.reset(OpCopy)
- v.Type = x.Type
- v.AddArg(x)
- return true
- }
- // match: (MOVLload [off1] {sym} (ADDQconst [off2] ptr) mem)
- // cond: is32Bit(off1+off2)
- // result: (MOVLload [off1+off2] {sym} ptr mem)
- for {
- off1 := v.AuxInt
- sym := v.Aux
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64ADDQconst {
- break
- }
- off2 := v_0.AuxInt
- ptr := v_0.Args[0]
- mem := v.Args[1]
- if !(is32Bit(off1 + off2)) {
- break
- }
- v.reset(OpAMD64MOVLload)
- v.AuxInt = off1 + off2
- v.Aux = sym
- v.AddArg(ptr)
- v.AddArg(mem)
- return true
- }
- // match: (MOVLload [off1] {sym1} (LEAQ [off2] {sym2} base) mem)
- // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
- // result: (MOVLload [off1+off2] {mergeSym(sym1,sym2)} base mem)
- for {
- off1 := v.AuxInt
- sym1 := v.Aux
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64LEAQ {
- break
- }
- off2 := v_0.AuxInt
- sym2 := v_0.Aux
- base := v_0.Args[0]
- mem := v.Args[1]
- if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
- break
- }
- v.reset(OpAMD64MOVLload)
- v.AuxInt = off1 + off2
- v.Aux = mergeSym(sym1, sym2)
- v.AddArg(base)
- v.AddArg(mem)
- return true
- }
- // match: (MOVLload [off1] {sym1} (LEAQ1 [off2] {sym2} ptr idx) mem)
- // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
- // result: (MOVLloadidx1 [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem)
- for {
- off1 := v.AuxInt
- sym1 := v.Aux
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64LEAQ1 {
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64LEAQ1 {
break
}
off2 := v_0.AuxInt
@@ -6940,7 +8150,7 @@ func rewriteValueAMD64_OpAMD64MOVLload(v *Value, config *Config) bool {
if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
break
}
- v.reset(OpAMD64MOVLloadidx1)
+ v.reset(OpAMD64MOVSSloadidx1)
v.AuxInt = off1 + off2
v.Aux = mergeSym(sym1, sym2)
v.AddArg(ptr)
@@ -6948,9 +8158,9 @@ func rewriteValueAMD64_OpAMD64MOVLload(v *Value, config *Config) bool {
v.AddArg(mem)
return true
}
- // match: (MOVLload [off1] {sym1} (LEAQ4 [off2] {sym2} ptr idx) mem)
+ // match: (MOVSSload [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)
+ // result: (MOVSSloadidx4 [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem)
for {
off1 := v.AuxInt
sym1 := v.Aux
@@ -6966,7 +8176,7 @@ func rewriteValueAMD64_OpAMD64MOVLload(v *Value, config *Config) bool {
if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
break
}
- v.reset(OpAMD64MOVLloadidx4)
+ v.reset(OpAMD64MOVSSloadidx4)
v.AuxInt = off1 + off2
v.Aux = mergeSym(sym1, sym2)
v.AddArg(ptr)
@@ -6974,9 +8184,9 @@ func rewriteValueAMD64_OpAMD64MOVLload(v *Value, config *Config) bool {
v.AddArg(mem)
return true
}
- // match: (MOVLload [off] {sym} (ADDQ ptr idx) mem)
+ // match: (MOVSSload [off] {sym} (ADDQ ptr idx) mem)
// cond: ptr.Op != OpSB
- // result: (MOVLloadidx1 [off] {sym} ptr idx mem)
+ // result: (MOVSSloadidx1 [off] {sym} ptr idx mem)
for {
off := v.AuxInt
sym := v.Aux
@@ -6990,7 +8200,7 @@ func rewriteValueAMD64_OpAMD64MOVLload(v *Value, config *Config) bool {
if !(ptr.Op != OpSB) {
break
}
- v.reset(OpAMD64MOVLloadidx1)
+ v.reset(OpAMD64MOVSSloadidx1)
v.AuxInt = off
v.Aux = sym
v.AddArg(ptr)
@@ -7000,12 +8210,12 @@ func rewriteValueAMD64_OpAMD64MOVLload(v *Value, config *Config) bool {
}
return false
}
-func rewriteValueAMD64_OpAMD64MOVLloadidx1(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpAMD64MOVSSloadidx1(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (MOVLloadidx1 [c] {sym} ptr (SHLQconst [2] idx) mem)
+ // match: (MOVSSloadidx1 [c] {sym} ptr (SHLQconst [2] idx) mem)
// cond:
- // result: (MOVLloadidx4 [c] {sym} ptr idx mem)
+ // result: (MOVSSloadidx4 [c] {sym} ptr idx mem)
for {
c := v.AuxInt
sym := v.Aux
@@ -7019,7 +8229,7 @@ func rewriteValueAMD64_OpAMD64MOVLloadidx1(v *Value, config *Config) bool {
}
idx := v_1.Args[0]
mem := v.Args[2]
- v.reset(OpAMD64MOVLloadidx4)
+ v.reset(OpAMD64MOVSSloadidx4)
v.AuxInt = c
v.Aux = sym
v.AddArg(ptr)
@@ -7027,9 +8237,9 @@ func rewriteValueAMD64_OpAMD64MOVLloadidx1(v *Value, config *Config) bool {
v.AddArg(mem)
return true
}
- // match: (MOVLloadidx1 [c] {sym} (ADDQconst [d] ptr) idx mem)
+ // match: (MOVSSloadidx1 [c] {sym} (ADDQconst [d] ptr) idx mem)
// cond:
- // result: (MOVLloadidx1 [c+d] {sym} ptr idx mem)
+ // result: (MOVSSloadidx1 [c+d] {sym} ptr idx mem)
for {
c := v.AuxInt
sym := v.Aux
@@ -7041,7 +8251,7 @@ func rewriteValueAMD64_OpAMD64MOVLloadidx1(v *Value, config *Config) bool {
ptr := v_0.Args[0]
idx := v.Args[1]
mem := v.Args[2]
- v.reset(OpAMD64MOVLloadidx1)
+ v.reset(OpAMD64MOVSSloadidx1)
v.AuxInt = c + d
v.Aux = sym
v.AddArg(ptr)
@@ -7049,9 +8259,9 @@ func rewriteValueAMD64_OpAMD64MOVLloadidx1(v *Value, config *Config) bool {
v.AddArg(mem)
return true
}
- // match: (MOVLloadidx1 [c] {sym} ptr (ADDQconst [d] idx) mem)
+ // match: (MOVSSloadidx1 [c] {sym} ptr (ADDQconst [d] idx) mem)
// cond:
- // result: (MOVLloadidx1 [c+d] {sym} ptr idx mem)
+ // result: (MOVSSloadidx1 [c+d] {sym} ptr idx mem)
for {
c := v.AuxInt
sym := v.Aux
@@ -7063,7 +8273,7 @@ func rewriteValueAMD64_OpAMD64MOVLloadidx1(v *Value, config *Config) bool {
d := v_1.AuxInt
idx := v_1.Args[0]
mem := v.Args[2]
- v.reset(OpAMD64MOVLloadidx1)
+ v.reset(OpAMD64MOVSSloadidx1)
v.AuxInt = c + d
v.Aux = sym
v.AddArg(ptr)
@@ -7073,12 +8283,12 @@ func rewriteValueAMD64_OpAMD64MOVLloadidx1(v *Value, config *Config) bool {
}
return false
}
-func rewriteValueAMD64_OpAMD64MOVLloadidx4(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpAMD64MOVSSloadidx4(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (MOVLloadidx4 [c] {sym} (ADDQconst [d] ptr) idx mem)
+ // match: (MOVSSloadidx4 [c] {sym} (ADDQconst [d] ptr) idx mem)
// cond:
- // result: (MOVLloadidx4 [c+d] {sym} ptr idx mem)
+ // result: (MOVSSloadidx4 [c+d] {sym} ptr idx mem)
for {
c := v.AuxInt
sym := v.Aux
@@ -7090,7 +8300,7 @@ func rewriteValueAMD64_OpAMD64MOVLloadidx4(v *Value, config *Config) bool {
ptr := v_0.Args[0]
idx := v.Args[1]
mem := v.Args[2]
- v.reset(OpAMD64MOVLloadidx4)
+ v.reset(OpAMD64MOVSSloadidx4)
v.AuxInt = c + d
v.Aux = sym
v.AddArg(ptr)
@@ -7098,9 +8308,9 @@ func rewriteValueAMD64_OpAMD64MOVLloadidx4(v *Value, config *Config) bool {
v.AddArg(mem)
return true
}
- // match: (MOVLloadidx4 [c] {sym} ptr (ADDQconst [d] idx) mem)
+ // match: (MOVSSloadidx4 [c] {sym} ptr (ADDQconst [d] idx) mem)
// cond:
- // result: (MOVLloadidx4 [c+4*d] {sym} ptr idx mem)
+ // result: (MOVSSloadidx4 [c+4*d] {sym} ptr idx mem)
for {
c := v.AuxInt
sym := v.Aux
@@ -7112,7 +8322,7 @@ func rewriteValueAMD64_OpAMD64MOVLloadidx4(v *Value, config *Config) bool {
d := v_1.AuxInt
idx := v_1.Args[0]
mem := v.Args[2]
- v.reset(OpAMD64MOVLloadidx4)
+ v.reset(OpAMD64MOVSSloadidx4)
v.AuxInt = c + 4*d
v.Aux = sym
v.AddArg(ptr)
@@ -7122,102 +8332,37 @@ func rewriteValueAMD64_OpAMD64MOVLloadidx4(v *Value, config *Config) bool {
}
return false
}
-func rewriteValueAMD64_OpAMD64MOVLstore(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpAMD64MOVSSstore(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)
+ // match: (MOVSSstore [off1] {sym} (ADDQconst [off2] ptr) val mem)
+ // cond: is32Bit(off1+off2)
+ // result: (MOVSSstore [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 != OpAMD64MOVLQSX {
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64ADDQconst {
break
}
- x := v_1.Args[0]
+ off2 := v_0.AuxInt
+ ptr := v_0.Args[0]
+ val := v.Args[1]
mem := v.Args[2]
- v.reset(OpAMD64MOVLstore)
- v.AuxInt = off
+ if !(is32Bit(off1 + off2)) {
+ break
+ }
+ v.reset(OpAMD64MOVSSstore)
+ v.AuxInt = off1 + off2
v.Aux = sym
v.AddArg(ptr)
- v.AddArg(x)
+ v.AddArg(val)
v.AddArg(mem)
return true
}
- // match: (MOVLstore [off] {sym} ptr (MOVLQZX x) mem)
- // cond:
- // result: (MOVLstore [off] {sym} ptr x mem)
- for {
- off := v.AuxInt
- sym := v.Aux
- ptr := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64MOVLQZX {
- break
- }
- x := v_1.Args[0]
- mem := v.Args[2]
- v.reset(OpAMD64MOVLstore)
- v.AuxInt = off
- v.Aux = sym
- v.AddArg(ptr)
- v.AddArg(x)
- v.AddArg(mem)
- return true
- }
- // match: (MOVLstore [off1] {sym} (ADDQconst [off2] ptr) val mem)
- // cond: is32Bit(off1+off2)
- // result: (MOVLstore [off1+off2] {sym} ptr val mem)
- for {
- off1 := v.AuxInt
- sym := v.Aux
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64ADDQconst {
- break
- }
- off2 := v_0.AuxInt
- ptr := v_0.Args[0]
- val := v.Args[1]
- mem := v.Args[2]
- if !(is32Bit(off1 + off2)) {
- break
- }
- v.reset(OpAMD64MOVLstore)
- v.AuxInt = off1 + off2
- v.Aux = sym
- v.AddArg(ptr)
- v.AddArg(val)
- v.AddArg(mem)
- return true
- }
- // match: (MOVLstore [off] {sym} ptr (MOVLconst [c]) mem)
- // cond: validOff(off)
- // result: (MOVLstoreconst [makeValAndOff(int64(int32(c)),off)] {sym} ptr mem)
- for {
- off := v.AuxInt
- sym := v.Aux
- ptr := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64MOVLconst {
- break
- }
- c := v_1.AuxInt
- mem := v.Args[2]
- if !(validOff(off)) {
- break
- }
- v.reset(OpAMD64MOVLstoreconst)
- v.AuxInt = makeValAndOff(int64(int32(c)), off)
- v.Aux = sym
- v.AddArg(ptr)
- v.AddArg(mem)
- return true
- }
- // match: (MOVLstore [off1] {sym1} (LEAQ [off2] {sym2} base) val mem)
- // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
- // result: (MOVLstore [off1+off2] {mergeSym(sym1,sym2)} base val mem)
+ // match: (MOVSSstore [off1] {sym1} (LEAQ [off2] {sym2} base) val mem)
+ // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+ // result: (MOVSSstore [off1+off2] {mergeSym(sym1,sym2)} base val mem)
for {
off1 := v.AuxInt
sym1 := v.Aux
@@ -7233,7 +8378,7 @@ func rewriteValueAMD64_OpAMD64MOVLstore(v *Value, config *Config) bool {
if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
break
}
- v.reset(OpAMD64MOVLstore)
+ v.reset(OpAMD64MOVSSstore)
v.AuxInt = off1 + off2
v.Aux = mergeSym(sym1, sym2)
v.AddArg(base)
@@ -7241,9 +8386,9 @@ func rewriteValueAMD64_OpAMD64MOVLstore(v *Value, config *Config) bool {
v.AddArg(mem)
return true
}
- // match: (MOVLstore [off1] {sym1} (LEAQ1 [off2] {sym2} ptr idx) val mem)
+ // match: (MOVSSstore [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)
+ // result: (MOVSSstoreidx1 [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem)
for {
off1 := v.AuxInt
sym1 := v.Aux
@@ -7260,7 +8405,7 @@ func rewriteValueAMD64_OpAMD64MOVLstore(v *Value, config *Config) bool {
if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
break
}
- v.reset(OpAMD64MOVLstoreidx1)
+ v.reset(OpAMD64MOVSSstoreidx1)
v.AuxInt = off1 + off2
v.Aux = mergeSym(sym1, sym2)
v.AddArg(ptr)
@@ -7269,9 +8414,9 @@ func rewriteValueAMD64_OpAMD64MOVLstore(v *Value, config *Config) bool {
v.AddArg(mem)
return true
}
- // match: (MOVLstore [off1] {sym1} (LEAQ4 [off2] {sym2} ptr idx) val mem)
+ // match: (MOVSSstore [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)
+ // result: (MOVSSstoreidx4 [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem)
for {
off1 := v.AuxInt
sym1 := v.Aux
@@ -7288,7 +8433,7 @@ func rewriteValueAMD64_OpAMD64MOVLstore(v *Value, config *Config) bool {
if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
break
}
- v.reset(OpAMD64MOVLstoreidx4)
+ v.reset(OpAMD64MOVSSstoreidx4)
v.AuxInt = off1 + off2
v.Aux = mergeSym(sym1, sym2)
v.AddArg(ptr)
@@ -7297,9 +8442,9 @@ func rewriteValueAMD64_OpAMD64MOVLstore(v *Value, config *Config) bool {
v.AddArg(mem)
return true
}
- // match: (MOVLstore [off] {sym} (ADDQ ptr idx) val mem)
+ // match: (MOVSSstore [off] {sym} (ADDQ ptr idx) val mem)
// cond: ptr.Op != OpSB
- // result: (MOVLstoreidx1 [off] {sym} ptr idx val mem)
+ // result: (MOVSSstoreidx1 [off] {sym} ptr idx val mem)
for {
off := v.AuxInt
sym := v.Aux
@@ -7314,7 +8459,7 @@ func rewriteValueAMD64_OpAMD64MOVLstore(v *Value, config *Config) bool {
if !(ptr.Op != OpSB) {
break
}
- v.reset(OpAMD64MOVLstoreidx1)
+ v.reset(OpAMD64MOVSSstoreidx1)
v.AuxInt = off
v.Aux = sym
v.AddArg(ptr)
@@ -7323,641 +8468,644 @@ func rewriteValueAMD64_OpAMD64MOVLstore(v *Value, config *Config) bool {
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)
+ 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)
for {
- i := v.AuxInt
- s := v.Aux
- p := v.Args[0]
+ c := v.AuxInt
+ sym := v.Aux
+ ptr := v.Args[0]
v_1 := v.Args[1]
- if v_1.Op != OpAMD64SHRQconst {
- break
- }
- if v_1.AuxInt != 32 {
- break
- }
- w := v_1.Args[0]
- x := v.Args[2]
- if x.Op != OpAMD64MOVLstore {
- break
- }
- if x.AuxInt != i-4 {
- break
- }
- if x.Aux != s {
- break
- }
- if p != x.Args[0] {
+ if v_1.Op != OpAMD64SHLQconst {
break
}
- if w != x.Args[1] {
+ if v_1.AuxInt != 2 {
break
}
- mem := x.Args[2]
- if !(x.Uses == 1 && clobber(x)) {
+ idx := v_1.Args[0]
+ val := v.Args[2]
+ mem := v.Args[3]
+ v.reset(OpAMD64MOVSSstoreidx4)
+ v.AuxInt = c
+ 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)
+ for {
+ c := v.AuxInt
+ sym := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64ADDQconst {
break
}
- v.reset(OpAMD64MOVQstore)
- v.AuxInt = i - 4
- v.Aux = s
- v.AddArg(p)
- v.AddArg(w)
+ d := v_0.AuxInt
+ ptr := v_0.Args[0]
+ idx := v.Args[1]
+ val := v.Args[2]
+ mem := v.Args[3]
+ v.reset(OpAMD64MOVSSstoreidx1)
+ v.AuxInt = c + d
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(val)
v.AddArg(mem)
return true
}
- // match: (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)
+ // match: (MOVSSstoreidx1 [c] {sym} ptr (ADDQconst [d] idx) val mem)
+ // cond:
+ // result: (MOVSSstoreidx1 [c+d] {sym} ptr idx val mem)
for {
- i := v.AuxInt
- s := v.Aux
- p := v.Args[0]
+ c := v.AuxInt
+ sym := v.Aux
+ 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 != OpAMD64MOVLstore {
- break
- }
- if x.AuxInt != i-4 {
- break
- }
- if x.Aux != s {
- break
- }
- if p != x.Args[0] {
- break
- }
- w0 := x.Args[1]
- if w0.Op != OpAMD64SHRQconst {
- break
- }
- if w0.AuxInt != j-32 {
- break
- }
- if w != w0.Args[0] {
- break
- }
- mem := x.Args[2]
- if !(x.Uses == 1 && clobber(x)) {
+ if v_1.Op != OpAMD64ADDQconst {
break
}
- v.reset(OpAMD64MOVQstore)
- v.AuxInt = i - 4
- v.Aux = s
- v.AddArg(p)
- v.AddArg(w0)
+ d := v_1.AuxInt
+ idx := v_1.Args[0]
+ val := v.Args[2]
+ mem := v.Args[3]
+ v.reset(OpAMD64MOVSSstoreidx1)
+ v.AuxInt = c + d
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(val)
v.AddArg(mem)
return true
}
return false
}
-func rewriteValueAMD64_OpAMD64MOVLstoreconst(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpAMD64MOVSSstoreidx4(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)
+ // match: (MOVSSstoreidx4 [c] {sym} (ADDQconst [d] ptr) idx val mem)
+ // cond:
+ // result: (MOVSSstoreidx4 [c+d] {sym} ptr idx val mem)
for {
- sc := v.AuxInt
- s := v.Aux
+ c := v.AuxInt
+ sym := v.Aux
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(OpAMD64MOVLstoreconst)
- v.AuxInt = ValAndOff(sc).add(off)
- v.Aux = s
+ 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: (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: (MOVSSstoreidx4 [c] {sym} ptr (ADDQconst [d] idx) val mem)
+ // cond:
+ // result: (MOVSSstoreidx4 [c+4*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
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64ADDQconst {
break
}
- v.reset(OpAMD64MOVLstoreconst)
- 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(OpAMD64MOVSSstoreidx4)
+ v.AuxInt = c + 4*d
+ v.Aux = sym
v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(val)
v.AddArg(mem)
return true
}
- // match: (MOVLstoreconst [x] {sym1} (LEAQ1 [off] {sym2} ptr idx) mem)
- // cond: canMergeSym(sym1, sym2)
- // result: (MOVLstoreconstidx1 [ValAndOff(x).add(off)] {mergeSym(sym1,sym2)} ptr idx mem)
+ return false
+}
+func rewriteValueAMD64_OpAMD64MOVWQSX(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (MOVWQSX x:(MOVWload [off] {sym} ptr mem))
+ // cond: x.Uses == 1 && clobber(x)
+ // result: @x.Block (MOVWQSXload <v.Type> [off] {sym} ptr mem)
for {
- x := v.AuxInt
- sym1 := v.Aux
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64LEAQ1 {
+ x := v.Args[0]
+ if x.Op != OpAMD64MOVWload {
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)) {
+ off := x.AuxInt
+ sym := x.Aux
+ ptr := x.Args[0]
+ mem := x.Args[1]
+ if !(x.Uses == 1 && clobber(x)) {
break
}
- v.reset(OpAMD64MOVLstoreconstidx1)
- v.AuxInt = ValAndOff(x).add(off)
- v.Aux = mergeSym(sym1, sym2)
- v.AddArg(ptr)
- v.AddArg(idx)
- v.AddArg(mem)
+ b = x.Block
+ v0 := b.NewValue0(v.Line, OpAMD64MOVWQSXload, v.Type)
+ v.reset(OpCopy)
+ v.AddArg(v0)
+ v0.AuxInt = off
+ v0.Aux = sym
+ v0.AddArg(ptr)
+ v0.AddArg(mem)
return true
}
- // match: (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: (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.AuxInt
- sym1 := v.Aux
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64LEAQ4 {
+ x := v.Args[0]
+ if x.Op != OpAMD64MOVLload {
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)) {
+ off := x.AuxInt
+ sym := x.Aux
+ ptr := x.Args[0]
+ mem := x.Args[1]
+ if !(x.Uses == 1 && clobber(x)) {
break
}
- v.reset(OpAMD64MOVLstoreconstidx4)
- v.AuxInt = ValAndOff(x).add(off)
- v.Aux = mergeSym(sym1, sym2)
- v.AddArg(ptr)
- v.AddArg(idx)
- v.AddArg(mem)
+ b = x.Block
+ v0 := b.NewValue0(v.Line, OpAMD64MOVWQSXload, v.Type)
+ v.reset(OpCopy)
+ v.AddArg(v0)
+ v0.AuxInt = off
+ v0.Aux = sym
+ v0.AddArg(ptr)
+ v0.AddArg(mem)
return true
}
- // match: (MOVLstoreconst [x] {sym} (ADDQ ptr idx) mem)
- // cond:
- // result: (MOVLstoreconstidx1 [x] {sym} ptr idx 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 {
- x := v.AuxInt
- sym := v.Aux
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64ADDQ {
+ x := v.Args[0]
+ if x.Op != OpAMD64MOVQload {
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)
+ off := x.AuxInt
+ sym := x.Aux
+ ptr := x.Args[0]
+ mem := x.Args[1]
+ if !(x.Uses == 1 && clobber(x)) {
+ break
+ }
+ b = x.Block
+ v0 := b.NewValue0(v.Line, OpAMD64MOVWQSXload, v.Type)
+ v.reset(OpCopy)
+ v.AddArg(v0)
+ v0.AuxInt = off
+ v0.Aux = sym
+ v0.AddArg(ptr)
+ v0.AddArg(mem)
return true
}
- // match: (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)
+ // match: (MOVWQSX (ANDLconst [c] x))
+ // cond: c & 0x8000 == 0
+ // result: (ANDLconst [c & 0x7fff] x)
for {
- c := v.AuxInt
- s := v.Aux
- p := v.Args[0]
- x := v.Args[1]
- if x.Op != OpAMD64MOVLstoreconst {
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64ANDLconst {
break
}
- a := x.AuxInt
- 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
+ }
+ return false
+}
+func rewriteValueAMD64_OpAMD64MOVWQSXload(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (MOVWQSXload [off1] {sym1} (LEAQ [off2] {sym2} base) mem)
+ // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+ // result: (MOVWQSXload [off1+off2] {mergeSym(sym1,sym2)} base mem)
+ for {
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64LEAQ {
break
}
- mem := x.Args[1]
- if !(x.Uses == 1 && ValAndOff(a).Off()+4 == ValAndOff(c).Off() && 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(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.reset(OpAMD64MOVWQSXload)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(base)
v.AddArg(mem)
return true
}
return false
}
-func rewriteValueAMD64_OpAMD64MOVLstoreconstidx1(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpAMD64MOVWQZX(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (MOVLstoreconstidx1 [c] {sym} ptr (SHLQconst [2] idx) mem)
- // cond:
- // result: (MOVLstoreconstidx4 [c] {sym} ptr idx mem)
+ // 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
- ptr := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64SHLQconst {
+ x := v.Args[0]
+ if x.Op != OpAMD64MOVWload {
break
}
- if v_1.AuxInt != 2 {
+ off := x.AuxInt
+ sym := x.Aux
+ 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.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: (MOVLstoreconstidx1 [x] {sym} (ADDQconst [c] ptr) idx mem)
- // cond:
- // result: (MOVLstoreconstidx1 [ValAndOff(x).add(c)] {sym} ptr idx 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 {
- x := v.AuxInt
- sym := v.Aux
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64ADDQconst {
+ x := v.Args[0]
+ if x.Op != OpAMD64MOVLload {
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
+ 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.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: (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: (MOVWQZX x:(MOVQload [off] {sym} ptr mem))
+ // cond: x.Uses == 1 && clobber(x)
+ // result: @x.Block (MOVWload <v.Type> [off] {sym} ptr 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 != OpAMD64MOVQload {
break
}
- if p != x.Args[0] {
+ off := x.AuxInt
+ sym := x.Aux
+ ptr := x.Args[0]
+ mem := x.Args[1]
+ if !(x.Uses == 1 && clobber(x)) {
break
}
- if i != x.Args[1] {
+ 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 && 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.Line, OpAMD64MOVWloadidx1, 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)
- // cond:
- // result: (MOVLstoreconstidx4 [ValAndOff(x).add(c)] {sym} ptr idx mem)
+ // 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.AuxInt
- sym := v.Aux
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64ADDQconst {
+ x := v.Args[0]
+ if x.Op != OpAMD64MOVWloadidx2 {
break
}
- c := v_0.AuxInt
- ptr := v_0.Args[0]
- idx := v.Args[1]
- mem := v.Args[2]
- v.reset(OpAMD64MOVLstoreconstidx4)
- v.AuxInt = ValAndOff(x).add(c)
- v.Aux = sym
- v.AddArg(ptr)
- v.AddArg(idx)
- v.AddArg(mem)
- return true
- }
- // match: (MOVLstoreconstidx4 [x] {sym} ptr (ADDQconst [c] idx) mem)
- // cond:
- // result: (MOVLstoreconstidx4 [ValAndOff(x).add(4*c)] {sym} ptr idx mem)
- for {
- x := v.AuxInt
- sym := v.Aux
- ptr := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64ADDQconst {
+ 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
}
- 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)
+ b = x.Block
+ v0 := b.NewValue0(v.Line, OpAMD64MOVWloadidx2, v.Type)
+ v.reset(OpCopy)
+ v.AddArg(v0)
+ v0.AuxInt = off
+ v0.Aux = sym
+ v0.AddArg(ptr)
+ v0.AddArg(idx)
+ v0.AddArg(mem)
return true
}
- // match: (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: (MOVWQZX (ANDLconst [c] x))
+ // cond:
+ // result: (ANDLconst [c & 0xffff] 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] {
- break
- }
- mem := x.Args[2]
- if !(x.Uses == 1 && ValAndOff(a).Off()+4 == ValAndOff(c).Off() && clobber(x)) {
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64ANDLconst {
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)
+ 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_OpAMD64MOVLstoreidx1(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpAMD64MOVWload(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)
+ // match: (MOVWload [off] {sym} ptr (MOVWstore [off2] {sym2} ptr2 x _))
+ // cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
+ // result: x
for {
- c := v.AuxInt
+ off := v.AuxInt
sym := v.Aux
ptr := v.Args[0]
v_1 := v.Args[1]
- if v_1.Op != OpAMD64SHLQconst {
+ if v_1.Op != OpAMD64MOVWstore {
break
}
- if v_1.AuxInt != 2 {
+ off2 := v_1.AuxInt
+ sym2 := v_1.Aux
+ ptr2 := v_1.Args[0]
+ x := v_1.Args[1]
+ if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
break
}
- idx := v_1.Args[0]
- val := v.Args[2]
- mem := v.Args[3]
- v.reset(OpAMD64MOVLstoreidx4)
- v.AuxInt = c
- v.Aux = sym
- v.AddArg(ptr)
- v.AddArg(idx)
- v.AddArg(val)
- v.AddArg(mem)
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
return true
}
- // match: (MOVLstoreidx1 [c] {sym} (ADDQconst [d] ptr) idx val mem)
- // cond:
- // result: (MOVLstoreidx1 [c+d] {sym} ptr idx val mem)
+ // match: (MOVWload [off1] {sym} (ADDQconst [off2] ptr) mem)
+ // cond: is32Bit(off1+off2)
+ // result: (MOVWload [off1+off2] {sym} ptr mem)
for {
- c := v.AuxInt
+ off1 := v.AuxInt
sym := v.Aux
v_0 := v.Args[0]
if v_0.Op != OpAMD64ADDQconst {
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(OpAMD64MOVLstoreidx1)
- v.AuxInt = c + d
+ mem := v.Args[1]
+ if !(is32Bit(off1 + off2)) {
+ break
+ }
+ v.reset(OpAMD64MOVWload)
+ 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} ptr (ADDQconst [d] idx) val mem)
- // cond:
- // result: (MOVLstoreidx1 [c+d] {sym} ptr idx val mem)
+ // 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
- sym := v.Aux
- ptr := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64ADDQconst {
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ 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(OpAMD64MOVLstoreidx1)
- v.AuxInt = c + d
- v.Aux = sym
- v.AddArg(ptr)
- v.AddArg(idx)
- v.AddArg(val)
+ off2 := v_0.AuxInt
+ sym2 := v_0.Aux
+ base := v_0.Args[0]
+ mem := v.Args[1]
+ if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
+ break
+ }
+ v.reset(OpAMD64MOVWload)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(base)
v.AddArg(mem)
return true
}
- // match: (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)
+ // 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 {
- i := v.AuxInt
- s := v.Aux
- p := v.Args[0]
- idx := v.Args[1]
- v_2 := v.Args[2]
- if v_2.Op != OpAMD64SHRQconst {
- break
- }
- if v_2.AuxInt != 32 {
- break
- }
- w := v_2.Args[0]
- x := v.Args[3]
- if x.Op != OpAMD64MOVLstoreidx1 {
- break
- }
- if x.AuxInt != i-4 {
- break
- }
- if x.Aux != s {
- break
- }
- if p != x.Args[0] {
- break
- }
- if idx != x.Args[1] {
- break
- }
- if w != x.Args[2] {
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ 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
+ 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(OpAMD64MOVWloadidx1)
+ 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: (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 {
- i := v.AuxInt
- s := v.Aux
- p := v.Args[0]
- idx := v.Args[1]
- v_2 := v.Args[2]
- if v_2.Op != OpAMD64SHRQconst {
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64LEAQ2 {
break
}
- j := v_2.AuxInt
- w := v_2.Args[0]
- x := v.Args[3]
- if x.Op != OpAMD64MOVLstoreidx1 {
+ 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
}
- if x.AuxInt != i-4 {
+ v.reset(OpAMD64MOVWloadidx2)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVWload [off] {sym} (ADDQ ptr idx) mem)
+ // cond: ptr.Op != OpSB
+ // result: (MOVWloadidx1 [off] {sym} ptr idx mem)
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64ADDQ {
break
}
- if x.Aux != s {
+ ptr := v_0.Args[0]
+ idx := v_0.Args[1]
+ mem := v.Args[1]
+ if !(ptr.Op != OpSB) {
break
}
- if p != x.Args[0] {
+ v.reset(OpAMD64MOVWloadidx1)
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ 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
}
- if idx != x.Args[1] {
+ off2 := v_0.AuxInt
+ sym2 := v_0.Aux
+ base := v_0.Args[0]
+ mem := v.Args[1]
+ if !(canMergeSym(sym1, sym2)) {
break
}
- w0 := x.Args[2]
- if w0.Op != OpAMD64SHRQconst {
+ 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
}
- if w0.AuxInt != j-32 {
+ off2 := v_0.AuxInt
+ ptr := v_0.Args[0]
+ mem := v.Args[1]
+ if !(is32Bit(off1 + off2)) {
break
}
- if w != w0.Args[0] {
+ 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)
+ // cond:
+ // result: (MOVWloadidx2 [c] {sym} ptr idx mem)
+ for {
+ c := v.AuxInt
+ sym := v.Aux
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64SHLQconst {
break
}
- mem := x.Args[3]
- if !(x.Uses == 1 && clobber(x)) {
+ if v_1.AuxInt != 1 {
break
}
- v.reset(OpAMD64MOVQstoreidx1)
- v.AuxInt = i - 4
- v.Aux = s
- v.AddArg(p)
+ 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(w0)
v.AddArg(mem)
return true
}
- return false
-}
-func rewriteValueAMD64_OpAMD64MOVLstoreidx4(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (MOVLstoreidx4 [c] {sym} (ADDQconst [d] ptr) idx val mem)
+ // match: (MOVWloadidx1 [c] {sym} (ADDQconst [d] ptr) idx mem)
// cond:
- // result: (MOVLstoreidx4 [c+d] {sym} ptr idx val mem)
+ // result: (MOVWloadidx1 [c+d] {sym} ptr idx mem)
for {
c := v.AuxInt
sym := v.Aux
@@ -7968,20 +9116,18 @@ func rewriteValueAMD64_OpAMD64MOVLstoreidx4(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(OpAMD64MOVLstoreidx4)
+ mem := v.Args[2]
+ v.reset(OpAMD64MOVWloadidx1)
v.AuxInt = c + d
v.Aux = sym
v.AddArg(ptr)
v.AddArg(idx)
- v.AddArg(val)
v.AddArg(mem)
return true
}
- // match: (MOVLstoreidx4 [c] {sym} ptr (ADDQconst [d] idx) val mem)
+ // match: (MOVWloadidx1 [c] {sym} ptr (ADDQconst [d] idx) mem)
// cond:
- // result: (MOVLstoreidx4 [c+4*d] {sym} ptr idx val mem)
+ // result: (MOVWloadidx1 [c+d] {sym} ptr idx mem)
for {
c := v.AuxInt
sym := v.Aux
@@ -7992,132 +9138,114 @@ func rewriteValueAMD64_OpAMD64MOVLstoreidx4(v *Value, config *Config) bool {
}
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(OpAMD64MOVWloadidx1)
+ v.AuxInt = c + d
v.Aux = sym
v.AddArg(ptr)
v.AddArg(idx)
- v.AddArg(val)
v.AddArg(mem)
return true
}
- // match: (MOVLstoreidx4 [i] {s} p idx (SHRQconst [32] w) x:(MOVLstoreidx4 [i-4] {s} p idx w mem))
- // cond: x.Uses == 1 && clobber(x)
- // result: (MOVQstoreidx1 [i-4] {s} p (SHLQconst <idx.Type> [2] idx) w mem)
+ return false
+}
+func rewriteValueAMD64_OpAMD64MOVWloadidx2(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (MOVWloadidx2 [c] {sym} (ADDQconst [d] ptr) idx mem)
+ // cond:
+ // result: (MOVWloadidx2 [c+d] {sym} ptr idx mem)
for {
- 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_0 := v.Args[0]
+ if v_0.Op != OpAMD64ADDQconst {
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)
+ 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: (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: (MOVWloadidx2 [c] {sym} ptr (ADDQconst [d] idx) mem)
+ // cond:
+ // result: (MOVWloadidx2 [c+2*d] {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] {
- break
- }
- mem := x.Args[3]
- if !(x.Uses == 1 && clobber(x)) {
+ c := v.AuxInt
+ sym := v.Aux
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64ADDQconst {
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)
+ d := v_1.AuxInt
+ idx := v_1.Args[0]
+ mem := v.Args[2]
+ v.reset(OpAMD64MOVWloadidx2)
+ v.AuxInt = c + 2*d
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(idx)
v.AddArg(mem)
return true
}
return false
}
-func rewriteValueAMD64_OpAMD64MOVOload(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpAMD64MOVWstore(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (MOVOload [off1] {sym} (ADDQconst [off2] ptr) mem)
+ // match: (MOVWstore [off] {sym} ptr (MOVWQSX x) mem)
+ // cond:
+ // result: (MOVWstore [off] {sym} ptr x mem)
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64MOVWQSX {
+ break
+ }
+ x := v_1.Args[0]
+ mem := v.Args[2]
+ v.reset(OpAMD64MOVWstore)
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(x)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVWstore [off] {sym} ptr (MOVWQZX x) mem)
+ // cond:
+ // result: (MOVWstore [off] {sym} ptr x mem)
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64MOVWQZX {
+ break
+ }
+ x := v_1.Args[0]
+ mem := v.Args[2]
+ v.reset(OpAMD64MOVWstore)
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(x)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVWstore [off1] {sym} (ADDQconst [off2] ptr) val mem)
// cond: is32Bit(off1+off2)
- // result: (MOVOload [off1+off2] {sym} ptr mem)
+ // result: (MOVWstore [off1+off2] {sym} ptr val mem)
for {
off1 := v.AuxInt
sym := v.Aux
@@ -8127,20 +9255,45 @@ func rewriteValueAMD64_OpAMD64MOVOload(v *Value, config *Config) bool {
}
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(OpAMD64MOVOload)
+ v.reset(OpAMD64MOVWstore)
v.AuxInt = off1 + off2
v.Aux = sym
v.AddArg(ptr)
+ v.AddArg(val)
v.AddArg(mem)
return true
}
- // match: (MOVOload [off1] {sym1} (LEAQ [off2] {sym2} base) mem)
+ // match: (MOVWstore [off] {sym} ptr (MOVLconst [c]) mem)
+ // cond: validOff(off)
+ // result: (MOVWstoreconst [makeValAndOff(int64(int16(c)),off)] {sym} ptr mem)
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64MOVLconst {
+ break
+ }
+ c := v_1.AuxInt
+ mem := v.Args[2]
+ if !(validOff(off)) {
+ break
+ }
+ v.reset(OpAMD64MOVWstoreconst)
+ v.AuxInt = makeValAndOff(int64(int16(c)), off)
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVWstore [off1] {sym1} (LEAQ [off2] {sym2} base) val mem)
// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
- // result: (MOVOload [off1+off2] {mergeSym(sym1,sym2)} base mem)
+ // result: (MOVWstore [off1+off2] {mergeSym(sym1,sym2)} base val mem)
for {
off1 := v.AuxInt
sym1 := v.Aux
@@ -8151,205 +9304,352 @@ func rewriteValueAMD64_OpAMD64MOVOload(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(OpAMD64MOVOload)
+ v.reset(OpAMD64MOVWstore)
v.AuxInt = off1 + off2
v.Aux = mergeSym(sym1, sym2)
v.AddArg(base)
+ v.AddArg(val)
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: (MOVWstore [off1] {sym1} (LEAQ1 [off2] {sym2} ptr idx) val mem)
+ // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+ // result: (MOVWstoreidx1 [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem)
for {
off1 := v.AuxInt
- sym := v.Aux
+ sym1 := v.Aux
v_0 := v.Args[0]
- if v_0.Op != OpAMD64ADDQconst {
+ if v_0.Op != OpAMD64LEAQ1 {
break
}
off2 := v_0.AuxInt
+ sym2 := v_0.Aux
ptr := v_0.Args[0]
+ idx := v_0.Args[1]
val := v.Args[1]
mem := v.Args[2]
- if !(is32Bit(off1 + off2)) {
+ if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
break
}
- v.reset(OpAMD64MOVOstore)
+ v.reset(OpAMD64MOVWstoreidx1)
v.AuxInt = off1 + off2
- v.Aux = sym
+ v.Aux = mergeSym(sym1, sym2)
v.AddArg(ptr)
+ v.AddArg(idx)
v.AddArg(val)
v.AddArg(mem)
return true
}
- // match: (MOVOstore [off1] {sym1} (LEAQ [off2] {sym2} base) val mem)
+ // match: (MOVWstore [off1] {sym1} (LEAQ2 [off2] {sym2} ptr idx) val mem)
// cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
- // result: (MOVOstore [off1+off2] {mergeSym(sym1,sym2)} base val mem)
+ // result: (MOVWstoreidx2 [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem)
for {
off1 := v.AuxInt
sym1 := v.Aux
v_0 := v.Args[0]
- if v_0.Op != OpAMD64LEAQ {
+ if v_0.Op != OpAMD64LEAQ2 {
break
}
off2 := v_0.AuxInt
sym2 := v_0.Aux
- base := v_0.Args[0]
+ 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(OpAMD64MOVOstore)
+ v.reset(OpAMD64MOVWstoreidx2)
v.AuxInt = off1 + off2
v.Aux = mergeSym(sym1, sym2)
- v.AddArg(base)
+ v.AddArg(ptr)
+ v.AddArg(idx)
v.AddArg(val)
v.AddArg(mem)
return true
}
- return false
-}
-func rewriteValueAMD64_OpAMD64MOVQload(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (MOVQload [off] {sym} ptr (MOVQstore [off2] {sym2} ptr2 x _))
- // cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
- // result: x
+ // 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
- ptr := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64MOVQstore {
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64ADDQ {
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)) {
+ 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(OpCopy)
- v.Type = x.Type
- v.AddArg(x)
+ v.reset(OpAMD64MOVWstoreidx1)
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(val)
+ v.AddArg(mem)
return true
}
- // match: (MOVQload [off1] {sym} (ADDQconst [off2] ptr) mem)
+ // match: (MOVWstore [i] {s} p (SHRQconst [16] w) x:(MOVWstore [i-2] {s} p w mem))
+ // cond: x.Uses == 1 && clobber(x)
+ // result: (MOVLstore [i-2] {s} p w mem)
+ for {
+ i := v.AuxInt
+ s := v.Aux
+ p := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64SHRQconst {
+ break
+ }
+ if v_1.AuxInt != 16 {
+ break
+ }
+ w := v_1.Args[0]
+ x := v.Args[2]
+ if x.Op != OpAMD64MOVWstore {
+ break
+ }
+ if x.AuxInt != i-2 {
+ break
+ }
+ if x.Aux != s {
+ break
+ }
+ if p != x.Args[0] {
+ break
+ }
+ if w != x.Args[1] {
+ break
+ }
+ mem := x.Args[2]
+ if !(x.Uses == 1 && clobber(x)) {
+ break
+ }
+ v.reset(OpAMD64MOVLstore)
+ v.AuxInt = i - 2
+ v.Aux = s
+ v.AddArg(p)
+ v.AddArg(w)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVWstore [i] {s} p (SHRQconst [j] w) x:(MOVWstore [i-2] {s} p w0:(SHRQconst [j-16] w) mem))
+ // cond: x.Uses == 1 && clobber(x)
+ // result: (MOVLstore [i-2] {s} p w0 mem)
+ for {
+ i := v.AuxInt
+ s := v.Aux
+ p := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64SHRQconst {
+ break
+ }
+ j := v_1.AuxInt
+ w := v_1.Args[0]
+ x := v.Args[2]
+ if x.Op != OpAMD64MOVWstore {
+ break
+ }
+ if x.AuxInt != i-2 {
+ break
+ }
+ if x.Aux != s {
+ break
+ }
+ if p != x.Args[0] {
+ break
+ }
+ w0 := x.Args[1]
+ if w0.Op != OpAMD64SHRQconst {
+ break
+ }
+ if w0.AuxInt != j-16 {
+ break
+ }
+ if w != w0.Args[0] {
+ break
+ }
+ mem := x.Args[2]
+ if !(x.Uses == 1 && clobber(x)) {
+ break
+ }
+ v.reset(OpAMD64MOVLstore)
+ v.AuxInt = i - 2
+ v.Aux = s
+ v.AddArg(p)
+ v.AddArg(w0)
+ v.AddArg(mem)
+ return true
+ }
+ // 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_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(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: (MOVQload [off1+off2] {sym} ptr mem)
+ // 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 {
+ if v_0.Op != OpAMD64ADDLconst {
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(OpAMD64MOVWstore)
v.AuxInt = off1 + off2
v.Aux = sym
v.AddArg(ptr)
+ v.AddArg(val)
v.AddArg(mem)
return true
}
- // match: (MOVQload [off1] {sym1} (LEAQ [off2] {sym2} base) mem)
- // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
- // result: (MOVQload [off1+off2] {mergeSym(sym1,sym2)} base mem)
+ 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 {
- off1 := v.AuxInt
+ sc := v.AuxInt
+ s := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64ADDQconst {
+ break
+ }
+ off := v_0.AuxInt
+ ptr := v_0.Args[0]
+ mem := v.Args[1]
+ if !(ValAndOff(sc).canAdd(off)) {
+ break
+ }
+ v.reset(OpAMD64MOVWstoreconst)
+ v.AuxInt = ValAndOff(sc).add(off)
+ v.Aux = s
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVWstoreconst [sc] {sym1} (LEAQ [off] {sym2} ptr) mem)
+ // cond: canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd(off)
+ // result: (MOVWstoreconst [ValAndOff(sc).add(off)] {mergeSym(sym1, sym2)} ptr mem)
+ for {
+ sc := v.AuxInt
sym1 := v.Aux
v_0 := v.Args[0]
if v_0.Op != OpAMD64LEAQ {
break
}
- off2 := v_0.AuxInt
+ off := v_0.AuxInt
sym2 := v_0.Aux
- base := v_0.Args[0]
+ ptr := v_0.Args[0]
mem := v.Args[1]
- if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
+ if !(canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd(off)) {
break
}
- v.reset(OpAMD64MOVQload)
- v.AuxInt = off1 + off2
+ v.reset(OpAMD64MOVWstoreconst)
+ v.AuxInt = ValAndOff(sc).add(off)
v.Aux = mergeSym(sym1, sym2)
- v.AddArg(base)
+ v.AddArg(ptr)
v.AddArg(mem)
return true
}
- // match: (MOVQload [off1] {sym1} (LEAQ1 [off2] {sym2} ptr idx) mem)
- // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
- // result: (MOVQloadidx1 [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem)
+ // 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 {
- off1 := v.AuxInt
+ x := v.AuxInt
sym1 := v.Aux
v_0 := v.Args[0]
if v_0.Op != OpAMD64LEAQ1 {
break
}
- off2 := v_0.AuxInt
+ off := 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 !(canMergeSym(sym1, sym2)) {
break
}
- v.reset(OpAMD64MOVQloadidx1)
- v.AuxInt = off1 + off2
+ 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: (MOVQload [off1] {sym1} (LEAQ8 [off2] {sym2} ptr idx) mem)
- // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
- // result: (MOVQloadidx8 [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem)
+ // 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 {
- off1 := v.AuxInt
+ x := v.AuxInt
sym1 := v.Aux
v_0 := v.Args[0]
- if v_0.Op != OpAMD64LEAQ8 {
+ if v_0.Op != OpAMD64LEAQ2 {
break
}
- off2 := v_0.AuxInt
+ off := 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 !(canMergeSym(sym1, sym2)) {
break
}
- v.reset(OpAMD64MOVQloadidx8)
- v.AuxInt = off1 + off2
+ 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: (MOVQload [off] {sym} (ADDQ ptr idx) mem)
- // cond: ptr.Op != OpSB
- // result: (MOVQloadidx1 [off] {sym} ptr idx mem)
+ // match: (MOVWstoreconst [x] {sym} (ADDQ ptr idx) mem)
+ // cond:
+ // result: (MOVWstoreconstidx1 [x] {sym} ptr idx mem)
for {
- off := v.AuxInt
+ x := v.AuxInt
sym := v.Aux
v_0 := v.Args[0]
if v_0.Op != OpAMD64ADDQ {
@@ -8358,433 +9658,291 @@ func rewriteValueAMD64_OpAMD64MOVQload(v *Value, config *Config) bool {
ptr := v_0.Args[0]
idx := v_0.Args[1]
mem := v.Args[1]
- if !(ptr.Op != OpSB) {
- break
- }
- v.reset(OpAMD64MOVQloadidx1)
- v.AuxInt = off
+ v.reset(OpAMD64MOVWstoreconstidx1)
+ v.AuxInt = x
v.Aux = sym
v.AddArg(ptr)
v.AddArg(idx)
v.AddArg(mem)
return true
}
- return false
-}
-func rewriteValueAMD64_OpAMD64MOVQloadidx1(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (MOVQloadidx1 [c] {sym} ptr (SHLQconst [3] idx) mem)
- // cond:
- // result: (MOVQloadidx8 [c] {sym} ptr idx mem)
+ // 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
- sym := v.Aux
- ptr := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64SHLQconst {
- break
- }
- if v_1.AuxInt != 3 {
+ s := v.Aux
+ p := v.Args[0]
+ x := v.Args[1]
+ if x.Op != OpAMD64MOVWstoreconst {
break
}
- idx := v_1.Args[0]
- mem := v.Args[2]
- v.reset(OpAMD64MOVQloadidx8)
- v.AuxInt = c
- v.Aux = sym
+ a := x.AuxInt
+ if x.Aux != s {
+ break
+ }
+ if p != x.Args[0] {
+ break
+ }
+ mem := x.Args[1]
+ if !(x.Uses == 1 && ValAndOff(a).Off()+2 == ValAndOff(c).Off() && clobber(x)) {
+ break
+ }
+ v.reset(OpAMD64MOVLstoreconst)
+ v.AuxInt = makeValAndOff(ValAndOff(a).Val()&0xffff|ValAndOff(c).Val()<<16, ValAndOff(a).Off())
+ v.Aux = s
+ v.AddArg(p)
+ v.AddArg(mem)
+ return true
+ }
+ // 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_0 := v.Args[0]
+ if v_0.Op != OpAMD64LEAL {
+ break
+ }
+ off := v_0.AuxInt
+ sym2 := v_0.Aux
+ ptr := v_0.Args[0]
+ mem := v.Args[1]
+ if !(canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd(off)) {
+ break
+ }
+ v.reset(OpAMD64MOVWstoreconst)
+ v.AuxInt = ValAndOff(sc).add(off)
+ v.Aux = mergeSym(sym1, sym2)
v.AddArg(ptr)
- v.AddArg(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: (MOVWstoreconst [sc] {s} (ADDLconst [off] ptr) mem)
+ // cond: ValAndOff(sc).canAdd(off)
+ // result: (MOVWstoreconst [ValAndOff(sc).add(off)] {s} ptr mem)
for {
- c := v.AuxInt
- sym := v.Aux
+ sc := v.AuxInt
+ s := v.Aux
v_0 := v.Args[0]
- if v_0.Op != OpAMD64ADDQconst {
+ if v_0.Op != OpAMD64ADDLconst {
break
}
- d := v_0.AuxInt
+ off := v_0.AuxInt
ptr := v_0.Args[0]
- idx := v.Args[1]
- mem := v.Args[2]
- v.reset(OpAMD64MOVQloadidx1)
- v.AuxInt = c + d
- v.Aux = sym
+ mem := v.Args[1]
+ if !(ValAndOff(sc).canAdd(off)) {
+ break
+ }
+ v.reset(OpAMD64MOVWstoreconst)
+ v.AuxInt = ValAndOff(sc).add(off)
+ v.Aux = s
v.AddArg(ptr)
- v.AddArg(idx)
v.AddArg(mem)
return true
}
- // match: (MOVQloadidx1 [c] {sym} ptr (ADDQconst [d] idx) mem)
+ return false
+}
+func rewriteValueAMD64_OpAMD64MOVWstoreconstidx1(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (MOVWstoreconstidx1 [c] {sym} ptr (SHLQconst [1] idx) mem)
// cond:
- // result: (MOVQloadidx1 [c+d] {sym} ptr idx mem)
+ // result: (MOVWstoreconstidx2 [c] {sym} ptr idx mem)
for {
c := v.AuxInt
sym := v.Aux
ptr := v.Args[0]
v_1 := v.Args[1]
- if v_1.Op != OpAMD64ADDQconst {
+ if v_1.Op != OpAMD64SHLQconst {
+ break
+ }
+ if v_1.AuxInt != 1 {
break
}
- d := v_1.AuxInt
idx := v_1.Args[0]
mem := v.Args[2]
- v.reset(OpAMD64MOVQloadidx1)
- v.AuxInt = c + d
+ v.reset(OpAMD64MOVWstoreconstidx2)
+ v.AuxInt = c
v.Aux = sym
v.AddArg(ptr)
v.AddArg(idx)
v.AddArg(mem)
return true
}
- return false
-}
-func rewriteValueAMD64_OpAMD64MOVQloadidx8(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (MOVQloadidx8 [c] {sym} (ADDQconst [d] ptr) idx mem)
+ // match: (MOVWstoreconstidx1 [x] {sym} (ADDQconst [c] ptr) idx mem)
// cond:
- // result: (MOVQloadidx8 [c+d] {sym} ptr idx mem)
+ // result: (MOVWstoreconstidx1 [ValAndOff(x).add(c)] {sym} ptr idx mem)
for {
- c := v.AuxInt
+ x := v.AuxInt
sym := v.Aux
v_0 := v.Args[0]
if v_0.Op != OpAMD64ADDQconst {
break
}
- d := v_0.AuxInt
+ c := v_0.AuxInt
ptr := v_0.Args[0]
idx := v.Args[1]
mem := v.Args[2]
- v.reset(OpAMD64MOVQloadidx8)
- v.AuxInt = c + d
+ v.reset(OpAMD64MOVWstoreconstidx1)
+ v.AuxInt = ValAndOff(x).add(c)
v.Aux = sym
v.AddArg(ptr)
v.AddArg(idx)
v.AddArg(mem)
return true
}
- // match: (MOVQloadidx8 [c] {sym} ptr (ADDQconst [d] idx) mem)
+ // match: (MOVWstoreconstidx1 [x] {sym} ptr (ADDQconst [c] idx) mem)
// cond:
- // result: (MOVQloadidx8 [c+8*d] {sym} ptr idx mem)
+ // result: (MOVWstoreconstidx1 [ValAndOff(x).add(c)] {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 {
break
}
- d := v_1.AuxInt
+ c := v_1.AuxInt
idx := v_1.Args[0]
mem := v.Args[2]
- v.reset(OpAMD64MOVQloadidx8)
- v.AuxInt = c + 8*d
+ v.reset(OpAMD64MOVWstoreconstidx1)
+ v.AuxInt = ValAndOff(x).add(c)
v.Aux = sym
v.AddArg(ptr)
v.AddArg(idx)
v.AddArg(mem)
return true
}
+ // match: (MOVWstoreconstidx1 [c] {s} p i x:(MOVWstoreconstidx1 [a] {s} p i mem))
+ // cond: x.Uses == 1 && ValAndOff(a).Off() + 2 == ValAndOff(c).Off() && clobber(x)
+ // result: (MOVLstoreconstidx1 [makeValAndOff(ValAndOff(a).Val()&0xffff | ValAndOff(c).Val()<<16, ValAndOff(a).Off())] {s} p i mem)
+ for {
+ c := v.AuxInt
+ s := v.Aux
+ p := v.Args[0]
+ i := v.Args[1]
+ x := v.Args[2]
+ if x.Op != OpAMD64MOVWstoreconstidx1 {
+ break
+ }
+ a := x.AuxInt
+ if x.Aux != s {
+ break
+ }
+ if p != x.Args[0] {
+ break
+ }
+ if i != x.Args[1] {
+ break
+ }
+ mem := x.Args[2]
+ if !(x.Uses == 1 && ValAndOff(a).Off()+2 == ValAndOff(c).Off() && clobber(x)) {
+ break
+ }
+ v.reset(OpAMD64MOVLstoreconstidx1)
+ v.AuxInt = makeValAndOff(ValAndOff(a).Val()&0xffff|ValAndOff(c).Val()<<16, ValAndOff(a).Off())
+ v.Aux = s
+ v.AddArg(p)
+ v.AddArg(i)
+ v.AddArg(mem)
+ return true
+ }
return false
}
-func rewriteValueAMD64_OpAMD64MOVQstore(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpAMD64MOVWstoreconstidx2(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: (MOVWstoreconstidx2 [x] {sym} (ADDQconst [c] ptr) idx mem)
+ // cond:
+ // result: (MOVWstoreconstidx2 [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 != OpAMD64ADDQconst {
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(OpAMD64MOVQstore)
- v.AuxInt = off1 + off2
+ v.reset(OpAMD64MOVWstoreconstidx2)
+ v.AuxInt = ValAndOff(x).add(c)
v.Aux = sym
v.AddArg(ptr)
- v.AddArg(val)
+ v.AddArg(idx)
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)
+ // match: (MOVWstoreconstidx2 [x] {sym} ptr (ADDQconst [c] idx) mem)
+ // cond:
+ // result: (MOVWstoreconstidx2 [ValAndOff(x).add(2*c)] {sym} ptr idx mem)
for {
- off := v.AuxInt
+ x := v.AuxInt
sym := v.Aux
ptr := v.Args[0]
v_1 := v.Args[1]
- if v_1.Op != OpAMD64MOVQconst {
+ if v_1.Op != OpAMD64ADDQconst {
break
}
c := v_1.AuxInt
+ idx := v_1.Args[0]
mem := v.Args[2]
- if !(validValAndOff(c, off)) {
- break
- }
- v.reset(OpAMD64MOVQstoreconst)
- v.AuxInt = makeValAndOff(c, off)
+ 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: (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: (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 {
- off1 := v.AuxInt
- sym1 := v.Aux
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64LEAQ {
+ c := v.AuxInt
+ s := v.Aux
+ p := v.Args[0]
+ i := v.Args[1]
+ x := v.Args[2]
+ if x.Op != OpAMD64MOVWstoreconstidx2 {
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)) {
+ a := x.AuxInt
+ if x.Aux != s {
break
}
- v.reset(OpAMD64MOVQstore)
- v.AuxInt = off1 + off2
- v.Aux = mergeSym(sym1, sym2)
- v.AddArg(base)
- v.AddArg(val)
- v.AddArg(mem)
- return true
- }
- // match: (MOVQstore [off1] {sym1} (LEAQ1 [off2] {sym2} ptr idx) val mem)
- // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
- // result: (MOVQstoreidx1 [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem)
- for {
- off1 := v.AuxInt
- sym1 := v.Aux
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64LEAQ1 {
+ if p != x.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 i != x.Args[1] {
break
}
- v.reset(OpAMD64MOVQstoreidx1)
- v.AuxInt = off1 + off2
- v.Aux = mergeSym(sym1, sym2)
- v.AddArg(ptr)
- v.AddArg(idx)
- v.AddArg(val)
- v.AddArg(mem)
- return true
- }
- // match: (MOVQstore [off1] {sym1} (LEAQ8 [off2] {sym2} ptr idx) val mem)
- // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
- // result: (MOVQstoreidx8 [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem)
- for {
- off1 := v.AuxInt
- sym1 := v.Aux
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64LEAQ8 {
- break
- }
- off2 := v_0.AuxInt
- sym2 := v_0.Aux
- ptr := v_0.Args[0]
- idx := v_0.Args[1]
- val := v.Args[1]
- mem := v.Args[2]
- if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
- break
- }
- v.reset(OpAMD64MOVQstoreidx8)
- v.AuxInt = off1 + off2
- v.Aux = mergeSym(sym1, sym2)
- v.AddArg(ptr)
- v.AddArg(idx)
- v.AddArg(val)
- v.AddArg(mem)
- return true
- }
- // match: (MOVQstore [off] {sym} (ADDQ ptr idx) val mem)
- // cond: ptr.Op != OpSB
- // result: (MOVQstoreidx1 [off] {sym} ptr idx val mem)
- for {
- off := v.AuxInt
- sym := v.Aux
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64ADDQ {
- break
- }
- ptr := v_0.Args[0]
- idx := v_0.Args[1]
- val := v.Args[1]
- mem := v.Args[2]
- if !(ptr.Op != OpSB) {
- break
- }
- v.reset(OpAMD64MOVQstoreidx1)
- v.AuxInt = off
- v.Aux = sym
- v.AddArg(ptr)
- v.AddArg(idx)
- v.AddArg(val)
- v.AddArg(mem)
- return true
- }
- return false
-}
-func rewriteValueAMD64_OpAMD64MOVQstoreconst(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (MOVQstoreconst [sc] {s} (ADDQconst [off] ptr) mem)
- // cond: ValAndOff(sc).canAdd(off)
- // result: (MOVQstoreconst [ValAndOff(sc).add(off)] {s} ptr mem)
- for {
- sc := v.AuxInt
- s := v.Aux
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64ADDQconst {
- break
- }
- off := v_0.AuxInt
- ptr := v_0.Args[0]
- mem := v.Args[1]
- if !(ValAndOff(sc).canAdd(off)) {
+ mem := x.Args[2]
+ if !(x.Uses == 1 && ValAndOff(a).Off()+2 == ValAndOff(c).Off() && clobber(x)) {
break
}
- v.reset(OpAMD64MOVQstoreconst)
- v.AuxInt = ValAndOff(sc).add(off)
+ v.reset(OpAMD64MOVLstoreconstidx1)
+ v.AuxInt = makeValAndOff(ValAndOff(a).Val()&0xffff|ValAndOff(c).Val()<<16, ValAndOff(a).Off())
v.Aux = s
- v.AddArg(ptr)
- v.AddArg(mem)
- return true
- }
- // match: (MOVQstoreconst [sc] {sym1} (LEAQ [off] {sym2} ptr) mem)
- // cond: canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd(off)
- // result: (MOVQstoreconst [ValAndOff(sc).add(off)] {mergeSym(sym1, sym2)} ptr mem)
- for {
- sc := v.AuxInt
- sym1 := v.Aux
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64LEAQ {
- break
- }
- off := v_0.AuxInt
- sym2 := v_0.Aux
- ptr := v_0.Args[0]
- mem := v.Args[1]
- if !(canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd(off)) {
- break
- }
- v.reset(OpAMD64MOVQstoreconst)
- v.AuxInt = ValAndOff(sc).add(off)
- v.Aux = mergeSym(sym1, sym2)
- v.AddArg(ptr)
- v.AddArg(mem)
- return true
- }
- // match: (MOVQstoreconst [x] {sym1} (LEAQ1 [off] {sym2} ptr idx) mem)
- // cond: canMergeSym(sym1, sym2)
- // result: (MOVQstoreconstidx1 [ValAndOff(x).add(off)] {mergeSym(sym1,sym2)} ptr idx mem)
- for {
- x := v.AuxInt
- sym1 := v.Aux
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64LEAQ1 {
- break
- }
- off := v_0.AuxInt
- sym2 := v_0.Aux
- ptr := v_0.Args[0]
- idx := v_0.Args[1]
- mem := v.Args[1]
- if !(canMergeSym(sym1, sym2)) {
- break
- }
- v.reset(OpAMD64MOVQstoreconstidx1)
- v.AuxInt = ValAndOff(x).add(off)
- v.Aux = mergeSym(sym1, sym2)
- v.AddArg(ptr)
- v.AddArg(idx)
- v.AddArg(mem)
- return true
- }
- // match: (MOVQstoreconst [x] {sym1} (LEAQ8 [off] {sym2} ptr idx) mem)
- // cond: canMergeSym(sym1, sym2)
- // result: (MOVQstoreconstidx8 [ValAndOff(x).add(off)] {mergeSym(sym1,sym2)} ptr idx mem)
- for {
- x := v.AuxInt
- sym1 := v.Aux
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64LEAQ8 {
- break
- }
- off := v_0.AuxInt
- sym2 := v_0.Aux
- ptr := v_0.Args[0]
- idx := v_0.Args[1]
- mem := v.Args[1]
- if !(canMergeSym(sym1, sym2)) {
- break
- }
- v.reset(OpAMD64MOVQstoreconstidx8)
- v.AuxInt = ValAndOff(x).add(off)
- v.Aux = mergeSym(sym1, sym2)
- v.AddArg(ptr)
- v.AddArg(idx)
- v.AddArg(mem)
- return true
- }
- // match: (MOVQstoreconst [x] {sym} (ADDQ ptr idx) mem)
- // cond:
- // result: (MOVQstoreconstidx1 [x] {sym} ptr idx mem)
- for {
- x := v.AuxInt
- sym := v.Aux
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64ADDQ {
- break
- }
- ptr := v_0.Args[0]
- idx := v_0.Args[1]
- mem := v.Args[1]
- v.reset(OpAMD64MOVQstoreconstidx1)
- v.AuxInt = x
- v.Aux = sym
- v.AddArg(ptr)
- v.AddArg(idx)
+ v.AddArg(p)
+ v0 := b.NewValue0(v.Line, OpAMD64SHLQconst, i.Type)
+ v0.AuxInt = 1
+ v0.AddArg(i)
+ v.AddArg(v0)
v.AddArg(mem)
return true
}
return false
}
-func rewriteValueAMD64_OpAMD64MOVQstoreconstidx1(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpAMD64MOVWstoreidx1(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (MOVQstoreconstidx1 [c] {sym} ptr (SHLQconst [3] idx) mem)
+ // match: (MOVWstoreidx1 [c] {sym} ptr (SHLQconst [1] idx) val mem)
// cond:
- // result: (MOVQstoreconstidx8 [c] {sym} ptr idx mem)
+ // result: (MOVWstoreidx2 [c] {sym} ptr idx val mem)
for {
c := v.AuxInt
sym := v.Aux
@@ -8793,199 +9951,178 @@ func rewriteValueAMD64_OpAMD64MOVQstoreconstidx1(v *Value, config *Config) bool
if v_1.Op != OpAMD64SHLQconst {
break
}
- if v_1.AuxInt != 3 {
+ if v_1.AuxInt != 1 {
break
}
idx := v_1.Args[0]
- mem := v.Args[2]
- v.reset(OpAMD64MOVQstoreconstidx8)
+ 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: (MOVQstoreconstidx1 [x] {sym} (ADDQconst [c] ptr) idx mem)
+ // match: (MOVWstoreidx1 [c] {sym} (ADDQconst [d] ptr) idx val mem)
// cond:
- // result: (MOVQstoreconstidx1 [ValAndOff(x).add(c)] {sym} ptr idx mem)
+ // result: (MOVWstoreidx1 [c+d] {sym} ptr idx val mem)
for {
- x := v.AuxInt
+ c := v.AuxInt
sym := v.Aux
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(OpAMD64MOVWstoreidx1)
+ 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: (MOVWstoreidx1 [c] {sym} ptr (ADDQconst [d] idx) val mem)
// cond:
- // result: (MOVQstoreconstidx1 [ValAndOff(x).add(c)] {sym} ptr idx mem)
+ // result: (MOVWstoreidx1 [c+d] {sym} ptr idx val mem)
for {
- x := v.AuxInt
+ c := v.AuxInt
sym := v.Aux
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(OpAMD64MOVWstoreidx1)
+ 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: (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 {
- x := v.AuxInt
- sym := v.Aux
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64ADDQconst {
+ 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
}
- 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 != 16 {
break
}
- c := v_1.AuxInt
- idx := v_1.Args[0]
- mem := v.Args[2]
- v.reset(OpAMD64MOVQstoreconstidx8)
- v.AuxInt = ValAndOff(x).add(8 * c)
- v.Aux = sym
- v.AddArg(ptr)
- v.AddArg(idx)
- v.AddArg(mem)
- return true
- }
- return false
-}
-func rewriteValueAMD64_OpAMD64MOVQstoreidx1(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (MOVQstoreidx1 [c] {sym} ptr (SHLQconst [3] idx) val mem)
- // cond:
- // result: (MOVQstoreidx8 [c] {sym} ptr idx val mem)
- for {
- c := v.AuxInt
- sym := v.Aux
- ptr := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64SHLQconst {
+ w := v_2.Args[0]
+ x := v.Args[3]
+ if x.Op != OpAMD64MOVWstoreidx1 {
break
}
- if v_1.AuxInt != 3 {
+ if x.AuxInt != i-2 {
break
}
- idx := v_1.Args[0]
- val := v.Args[2]
- mem := v.Args[3]
- v.reset(OpAMD64MOVQstoreidx8)
- v.AuxInt = c
- v.Aux = sym
- v.AddArg(ptr)
- v.AddArg(idx)
- v.AddArg(val)
- v.AddArg(mem)
- return true
- }
- // match: (MOVQstoreidx1 [c] {sym} (ADDQconst [d] ptr) idx val mem)
- // cond:
- // result: (MOVQstoreidx1 [c+d] {sym} ptr idx val mem)
- for {
- c := v.AuxInt
- sym := v.Aux
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64ADDQconst {
+ if x.Aux != s {
break
}
- d := v_0.AuxInt
- ptr := v_0.Args[0]
- idx := v.Args[1]
- val := v.Args[2]
- mem := v.Args[3]
- v.reset(OpAMD64MOVQstoreidx1)
- v.AuxInt = c + d
- v.Aux = sym
- v.AddArg(ptr)
+ if p != x.Args[0] {
+ break
+ }
+ if idx != x.Args[1] {
+ break
+ }
+ if w != x.Args[2] {
+ break
+ }
+ mem := x.Args[3]
+ if !(x.Uses == 1 && clobber(x)) {
+ break
+ }
+ v.reset(OpAMD64MOVLstoreidx1)
+ v.AuxInt = i - 2
+ v.Aux = s
+ v.AddArg(p)
v.AddArg(idx)
- v.AddArg(val)
+ v.AddArg(w)
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)
+ // 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 {
- 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
+ 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(OpAMD64MOVQstoreidx1)
- 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 != OpAMD64MOVWstoreidx1 {
+ break
+ }
+ if x.AuxInt != i-2 {
+ break
+ }
+ if x.Aux != s {
+ break
+ }
+ if p != x.Args[0] {
+ break
+ }
+ if idx != x.Args[1] {
+ break
+ }
+ w0 := x.Args[2]
+ if w0.Op != OpAMD64SHRQconst {
+ break
+ }
+ if w0.AuxInt != j-16 {
+ break
+ }
+ if w != w0.Args[0] {
+ break
+ }
+ mem := x.Args[3]
+ if !(x.Uses == 1 && clobber(x)) {
+ break
+ }
+ v.reset(OpAMD64MOVLstoreidx1)
+ v.AuxInt = i - 2
+ v.Aux = s
+ v.AddArg(p)
v.AddArg(idx)
- v.AddArg(val)
+ v.AddArg(w0)
v.AddArg(mem)
return true
}
return false
}
-func rewriteValueAMD64_OpAMD64MOVQstoreidx8(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpAMD64MOVWstoreidx2(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (MOVQstoreidx8 [c] {sym} (ADDQconst [d] ptr) idx val mem)
+ // match: (MOVWstoreidx2 [c] {sym} (ADDQconst [d] ptr) idx val mem)
// cond:
- // result: (MOVQstoreidx8 [c+d] {sym} ptr idx val mem)
+ // result: (MOVWstoreidx2 [c+d] {sym} ptr idx val mem)
for {
c := v.AuxInt
sym := v.Aux
@@ -8998,7 +10135,7 @@ func rewriteValueAMD64_OpAMD64MOVQstoreidx8(v *Value, config *Config) bool {
idx := v.Args[1]
val := v.Args[2]
mem := v.Args[3]
- v.reset(OpAMD64MOVQstoreidx8)
+ v.reset(OpAMD64MOVWstoreidx2)
v.AuxInt = c + d
v.Aux = sym
v.AddArg(ptr)
@@ -9007,9 +10144,9 @@ func rewriteValueAMD64_OpAMD64MOVQstoreidx8(v *Value, config *Config) bool {
v.AddArg(mem)
return true
}
- // match: (MOVQstoreidx8 [c] {sym} ptr (ADDQconst [d] idx) val mem)
+ // match: (MOVWstoreidx2 [c] {sym} ptr (ADDQconst [d] idx) val mem)
// cond:
- // result: (MOVQstoreidx8 [c+8*d] {sym} ptr idx val mem)
+ // result: (MOVWstoreidx2 [c+2*d] {sym} ptr idx val mem)
for {
c := v.AuxInt
sym := v.Aux
@@ -9022,8 +10159,8 @@ func rewriteValueAMD64_OpAMD64MOVQstoreidx8(v *Value, config *Config) bool {
idx := v_1.Args[0]
val := v.Args[2]
mem := v.Args[3]
- v.reset(OpAMD64MOVQstoreidx8)
- v.AuxInt = c + 8*d
+ v.reset(OpAMD64MOVWstoreidx2)
+ v.AuxInt = c + 2*d
v.Aux = sym
v.AddArg(ptr)
v.AddArg(idx)
@@ -9031,2419 +10168,1246 @@ func rewriteValueAMD64_OpAMD64MOVQstoreidx8(v *Value, config *Config) bool {
v.AddArg(mem)
return true
}
- return false
-}
-func rewriteValueAMD64_OpAMD64MOVSDload(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (MOVSDload [off1] {sym} (ADDQconst [off2] ptr) mem)
- // cond: is32Bit(off1+off2)
- // result: (MOVSDload [off1+off2] {sym} ptr mem)
+ // 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 {
- off1 := v.AuxInt
- sym := v.Aux
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64ADDQconst {
+ 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
}
- off2 := v_0.AuxInt
- ptr := v_0.Args[0]
- mem := v.Args[1]
- if !(is32Bit(off1 + off2)) {
+ if v_2.AuxInt != 16 {
break
}
- v.reset(OpAMD64MOVSDload)
- v.AuxInt = off1 + off2
- v.Aux = sym
- v.AddArg(ptr)
- v.AddArg(mem)
- return true
- }
- // match: (MOVSDload [off1] {sym1} (LEAQ [off2] {sym2} base) mem)
- // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
- // result: (MOVSDload [off1+off2] {mergeSym(sym1,sym2)} base mem)
- for {
- off1 := v.AuxInt
- sym1 := v.Aux
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64LEAQ {
+ w := v_2.Args[0]
+ x := v.Args[3]
+ if x.Op != OpAMD64MOVWstoreidx2 {
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 x.AuxInt != i-2 {
break
}
- v.reset(OpAMD64MOVSDload)
- v.AuxInt = off1 + off2
- v.Aux = mergeSym(sym1, sym2)
- v.AddArg(base)
- v.AddArg(mem)
- return true
- }
- // match: (MOVSDload [off1] {sym1} (LEAQ1 [off2] {sym2} ptr idx) mem)
- // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
- // result: (MOVSDloadidx1 [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem)
- for {
- off1 := v.AuxInt
- sym1 := v.Aux
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64LEAQ1 {
+ if x.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)) {
+ if p != x.Args[0] {
break
}
- v.reset(OpAMD64MOVSDloadidx1)
- v.AuxInt = off1 + off2
- v.Aux = mergeSym(sym1, sym2)
- v.AddArg(ptr)
- v.AddArg(idx)
- v.AddArg(mem)
- return true
- }
- // match: (MOVSDload [off1] {sym1} (LEAQ8 [off2] {sym2} ptr idx) mem)
- // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
- // result: (MOVSDloadidx8 [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem)
- for {
- off1 := v.AuxInt
- sym1 := v.Aux
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64LEAQ8 {
+ if idx != x.Args[1] {
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 w != x.Args[2] {
break
}
- v.reset(OpAMD64MOVSDloadidx8)
- v.AuxInt = off1 + off2
- v.Aux = mergeSym(sym1, sym2)
- v.AddArg(ptr)
- v.AddArg(idx)
+ mem := x.Args[3]
+ if !(x.Uses == 1 && clobber(x)) {
+ break
+ }
+ v.reset(OpAMD64MOVLstoreidx1)
+ v.AuxInt = i - 2
+ v.Aux = s
+ v.AddArg(p)
+ v0 := b.NewValue0(v.Line, OpAMD64SHLQconst, idx.Type)
+ v0.AuxInt = 1
+ v0.AddArg(idx)
+ v.AddArg(v0)
+ v.AddArg(w)
v.AddArg(mem)
return true
}
- // match: (MOVSDload [off] {sym} (ADDQ ptr idx) mem)
- // cond: ptr.Op != OpSB
- // result: (MOVSDloadidx1 [off] {sym} ptr idx mem)
+ // 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 {
- off := v.AuxInt
- sym := v.Aux
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64ADDQ {
+ 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
}
- ptr := v_0.Args[0]
- idx := v_0.Args[1]
- mem := v.Args[1]
- if !(ptr.Op != OpSB) {
+ j := v_2.AuxInt
+ w := v_2.Args[0]
+ x := v.Args[3]
+ if x.Op != OpAMD64MOVWstoreidx2 {
break
}
- v.reset(OpAMD64MOVSDloadidx1)
- v.AuxInt = off
- v.Aux = sym
- v.AddArg(ptr)
- v.AddArg(idx)
+ if x.AuxInt != i-2 {
+ break
+ }
+ if x.Aux != s {
+ break
+ }
+ if p != x.Args[0] {
+ break
+ }
+ if idx != x.Args[1] {
+ break
+ }
+ w0 := x.Args[2]
+ if w0.Op != OpAMD64SHRQconst {
+ break
+ }
+ if w0.AuxInt != j-16 {
+ break
+ }
+ if w != w0.Args[0] {
+ break
+ }
+ mem := x.Args[3]
+ if !(x.Uses == 1 && clobber(x)) {
+ break
+ }
+ v.reset(OpAMD64MOVLstoreidx1)
+ v.AuxInt = i - 2
+ v.Aux = s
+ v.AddArg(p)
+ v0 := b.NewValue0(v.Line, OpAMD64SHLQconst, idx.Type)
+ v0.AuxInt = 1
+ v0.AddArg(idx)
+ v.AddArg(v0)
+ v.AddArg(w0)
v.AddArg(mem)
return true
}
return false
}
-func rewriteValueAMD64_OpAMD64MOVSDloadidx1(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpAMD64MULL(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (MOVSDloadidx1 [c] {sym} (ADDQconst [d] ptr) idx mem)
+ // match: (MULL x (MOVLconst [c]))
// cond:
- // result: (MOVSDloadidx1 [c+d] {sym} ptr idx mem)
+ // result: (MULLconst [c] x)
for {
- c := v.AuxInt
- sym := v.Aux
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64ADDQconst {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64MOVLconst {
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)
+ c := v_1.AuxInt
+ v.reset(OpAMD64MULLconst)
+ v.AuxInt = c
+ v.AddArg(x)
return true
}
- // match: (MOVSDloadidx1 [c] {sym} ptr (ADDQconst [d] idx) mem)
+ // match: (MULL (MOVLconst [c]) x)
// cond:
- // result: (MOVSDloadidx1 [c+d] {sym} ptr idx mem)
+ // result: (MULLconst [c] x)
for {
- c := v.AuxInt
- sym := v.Aux
- ptr := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64ADDQconst {
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64MOVLconst {
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)
+ c := v_0.AuxInt
+ x := v.Args[1]
+ v.reset(OpAMD64MULLconst)
+ v.AuxInt = c
+ v.AddArg(x)
return true
}
return false
}
-func rewriteValueAMD64_OpAMD64MOVSDloadidx8(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpAMD64MULLconst(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (MOVSDloadidx8 [c] {sym} (ADDQconst [d] ptr) idx mem)
+ // match: (MULLconst [c] (MULLconst [d] x))
// cond:
- // result: (MOVSDloadidx8 [c+d] {sym} ptr idx mem)
+ // result: (MULLconst [int64(int32(c * d))] x)
for {
c := v.AuxInt
- sym := v.Aux
v_0 := v.Args[0]
- if v_0.Op != OpAMD64ADDQconst {
+ if v_0.Op != OpAMD64MULLconst {
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)
+ x := v_0.Args[0]
+ v.reset(OpAMD64MULLconst)
+ v.AuxInt = int64(int32(c * d))
+ v.AddArg(x)
return true
}
- // match: (MOVSDloadidx8 [c] {sym} ptr (ADDQconst [d] idx) mem)
+ // match: (MULLconst [c] (MOVLconst [d]))
// cond:
- // result: (MOVSDloadidx8 [c+8*d] {sym} ptr idx mem)
+ // result: (MOVLconst [int64(int32(c*d))])
for {
c := v.AuxInt
- sym := v.Aux
- ptr := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64ADDQconst {
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64MOVLconst {
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)
+ d := v_0.AuxInt
+ v.reset(OpAMD64MOVLconst)
+ v.AuxInt = int64(int32(c * d))
return true
}
return false
}
-func rewriteValueAMD64_OpAMD64MOVSDstore(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpAMD64MULQ(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (MOVSDstore [off1] {sym} (ADDQconst [off2] ptr) val mem)
- // cond: is32Bit(off1+off2)
- // result: (MOVSDstore [off1+off2] {sym} ptr val mem)
+ // match: (MULQ x (MOVQconst [c]))
+ // cond: is32Bit(c)
+ // result: (MULQconst [c] x)
for {
- off1 := v.AuxInt
- sym := v.Aux
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64ADDQconst {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64MOVQconst {
break
}
- off2 := v_0.AuxInt
- ptr := v_0.Args[0]
- val := v.Args[1]
- mem := v.Args[2]
- if !(is32Bit(off1 + off2)) {
+ c := v_1.AuxInt
+ if !(is32Bit(c)) {
break
}
- v.reset(OpAMD64MOVSDstore)
- v.AuxInt = off1 + off2
- v.Aux = sym
- v.AddArg(ptr)
- v.AddArg(val)
- v.AddArg(mem)
+ v.reset(OpAMD64MULQconst)
+ v.AuxInt = c
+ v.AddArg(x)
return true
}
- // match: (MOVSDstore [off1] {sym1} (LEAQ [off2] {sym2} base) val mem)
- // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
- // result: (MOVSDstore [off1+off2] {mergeSym(sym1,sym2)} base val mem)
+ // match: (MULQ (MOVQconst [c]) x)
+ // cond: is32Bit(c)
+ // result: (MULQconst [c] x)
for {
- off1 := v.AuxInt
- sym1 := v.Aux
v_0 := v.Args[0]
- if v_0.Op != OpAMD64LEAQ {
+ if v_0.Op != OpAMD64MOVQconst {
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)) {
+ c := v_0.AuxInt
+ x := v.Args[1]
+ if !(is32Bit(c)) {
break
}
- v.reset(OpAMD64MOVSDstore)
- v.AuxInt = off1 + off2
- v.Aux = mergeSym(sym1, sym2)
- v.AddArg(base)
- v.AddArg(val)
- v.AddArg(mem)
+ v.reset(OpAMD64MULQconst)
+ v.AuxInt = c
+ v.AddArg(x)
return true
}
- // match: (MOVSDstore [off1] {sym1} (LEAQ1 [off2] {sym2} ptr idx) val mem)
- // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
- // result: (MOVSDstoreidx1 [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem)
+ 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)
for {
- off1 := v.AuxInt
- sym1 := v.Aux
+ c := v.AuxInt
v_0 := v.Args[0]
- if v_0.Op != OpAMD64LEAQ1 {
+ if v_0.Op != OpAMD64MULQconst {
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)) {
+ d := v_0.AuxInt
+ x := v_0.Args[0]
+ if !(is32Bit(c * d)) {
break
}
- v.reset(OpAMD64MOVSDstoreidx1)
- v.AuxInt = off1 + off2
- v.Aux = mergeSym(sym1, sym2)
- v.AddArg(ptr)
- v.AddArg(idx)
- v.AddArg(val)
- v.AddArg(mem)
+ v.reset(OpAMD64MULQconst)
+ v.AuxInt = c * d
+ v.AddArg(x)
return true
}
- // match: (MOVSDstore [off1] {sym1} (LEAQ8 [off2] {sym2} ptr idx) val mem)
- // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
- // result: (MOVSDstoreidx8 [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem)
+ // match: (MULQconst [-1] x)
+ // cond:
+ // result: (NEGQ x)
for {
- off1 := v.AuxInt
- sym1 := v.Aux
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64LEAQ8 {
- break
- }
- off2 := v_0.AuxInt
- sym2 := v_0.Aux
- ptr := v_0.Args[0]
- idx := v_0.Args[1]
- val := v.Args[1]
- mem := v.Args[2]
- if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
+ if v.AuxInt != -1 {
break
}
- v.reset(OpAMD64MOVSDstoreidx8)
- v.AuxInt = off1 + off2
- v.Aux = mergeSym(sym1, sym2)
- v.AddArg(ptr)
- v.AddArg(idx)
- v.AddArg(val)
- v.AddArg(mem)
+ x := v.Args[0]
+ v.reset(OpAMD64NEGQ)
+ v.AddArg(x)
return true
}
- // match: (MOVSDstore [off] {sym} (ADDQ ptr idx) val mem)
- // cond: ptr.Op != OpSB
- // result: (MOVSDstoreidx1 [off] {sym} ptr idx val mem)
+ // match: (MULQconst [0] _)
+ // cond:
+ // result: (MOVQconst [0])
for {
- off := v.AuxInt
- sym := v.Aux
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64ADDQ {
- break
- }
- ptr := v_0.Args[0]
- idx := v_0.Args[1]
- val := v.Args[1]
- mem := v.Args[2]
- if !(ptr.Op != OpSB) {
+ if v.AuxInt != 0 {
break
}
- v.reset(OpAMD64MOVSDstoreidx1)
- v.AuxInt = off
- v.Aux = sym
- v.AddArg(ptr)
- v.AddArg(idx)
- v.AddArg(val)
- v.AddArg(mem)
+ v.reset(OpAMD64MOVQconst)
+ v.AuxInt = 0
return true
}
- return false
-}
-func rewriteValueAMD64_OpAMD64MOVSDstoreidx1(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (MOVSDstoreidx1 [c] {sym} (ADDQconst [d] ptr) idx val mem)
+ // match: (MULQconst [1] x)
// cond:
- // result: (MOVSDstoreidx1 [c+d] {sym} ptr idx val mem)
+ // result: x
for {
- c := v.AuxInt
- sym := v.Aux
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64ADDQconst {
+ if v.AuxInt != 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(OpAMD64MOVSDstoreidx1)
- v.AuxInt = c + d
- v.Aux = sym
- v.AddArg(ptr)
- v.AddArg(idx)
- v.AddArg(val)
- v.AddArg(mem)
+ x := v.Args[0]
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
return true
}
- // match: (MOVSDstoreidx1 [c] {sym} ptr (ADDQconst [d] idx) val mem)
+ // match: (MULQconst [3] x)
// cond:
- // result: (MOVSDstoreidx1 [c+d] {sym} ptr idx val mem)
+ // result: (LEAQ2 x x)
for {
- c := v.AuxInt
- sym := v.Aux
- ptr := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64ADDQconst {
+ if v.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
- v.Aux = sym
- v.AddArg(ptr)
- v.AddArg(idx)
- v.AddArg(val)
- v.AddArg(mem)
+ x := v.Args[0]
+ v.reset(OpAMD64LEAQ2)
+ v.AddArg(x)
+ v.AddArg(x)
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: (MULQconst [5] x)
// cond:
- // result: (MOVSDstoreidx8 [c+d] {sym} ptr idx val mem)
+ // result: (LEAQ4 x x)
for {
- c := v.AuxInt
- sym := v.Aux
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64ADDQconst {
+ if v.AuxInt != 5 {
break
}
- d := v_0.AuxInt
- ptr := v_0.Args[0]
- idx := v.Args[1]
- val := v.Args[2]
- mem := v.Args[3]
- v.reset(OpAMD64MOVSDstoreidx8)
- v.AuxInt = c + d
- v.Aux = sym
- v.AddArg(ptr)
- v.AddArg(idx)
- v.AddArg(val)
- v.AddArg(mem)
+ x := v.Args[0]
+ v.reset(OpAMD64LEAQ4)
+ v.AddArg(x)
+ v.AddArg(x)
return true
}
- // match: (MOVSDstoreidx8 [c] {sym} ptr (ADDQconst [d] idx) val mem)
+ // match: (MULQconst [7] x)
// cond:
- // result: (MOVSDstoreidx8 [c+8*d] {sym} ptr idx val mem)
+ // result: (LEAQ8 (NEGQ <v.Type> x) x)
for {
- c := v.AuxInt
- sym := v.Aux
- ptr := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64ADDQconst {
+ if v.AuxInt != 7 {
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)
+ x := v.Args[0]
+ v.reset(OpAMD64LEAQ8)
+ v0 := b.NewValue0(v.Line, OpAMD64NEGQ, v.Type)
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v.AddArg(x)
return true
}
- 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)
+ // match: (MULQconst [9] x)
+ // cond:
+ // result: (LEAQ8 x x)
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)) {
+ if v.AuxInt != 9 {
break
}
- v.reset(OpAMD64MOVSSload)
- v.AuxInt = off1 + off2
- v.Aux = sym
- v.AddArg(ptr)
- v.AddArg(mem)
+ x := v.Args[0]
+ v.reset(OpAMD64LEAQ8)
+ v.AddArg(x)
+ v.AddArg(x)
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)
+ // match: (MULQconst [11] x)
+ // cond:
+ // result: (LEAQ2 x (LEAQ4 <v.Type> x x))
for {
- off1 := v.AuxInt
- sym1 := v.Aux
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64LEAQ {
- break
- }
- off2 := v_0.AuxInt
- sym2 := v_0.Aux
- base := v_0.Args[0]
- mem := v.Args[1]
- if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
+ if v.AuxInt != 11 {
break
}
- v.reset(OpAMD64MOVSSload)
- v.AuxInt = off1 + off2
- v.Aux = mergeSym(sym1, sym2)
- v.AddArg(base)
- v.AddArg(mem)
+ x := v.Args[0]
+ v.reset(OpAMD64LEAQ2)
+ v.AddArg(x)
+ v0 := b.NewValue0(v.Line, OpAMD64LEAQ4, v.Type)
+ v0.AddArg(x)
+ v0.AddArg(x)
+ v.AddArg(v0)
return true
}
- // match: (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)) {
+ // match: (MULQconst [13] x)
+ // cond:
+ // result: (LEAQ4 x (LEAQ2 <v.Type> x x))
+ for {
+ if v.AuxInt != 13 {
break
}
- v.reset(OpAMD64MOVSSloadidx1)
- v.AuxInt = off1 + off2
- v.Aux = mergeSym(sym1, sym2)
- v.AddArg(ptr)
- v.AddArg(idx)
- v.AddArg(mem)
+ x := v.Args[0]
+ v.reset(OpAMD64LEAQ4)
+ v.AddArg(x)
+ v0 := b.NewValue0(v.Line, OpAMD64LEAQ2, v.Type)
+ v0.AddArg(x)
+ v0.AddArg(x)
+ v.AddArg(v0)
return true
}
- // match: (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)
+ // match: (MULQconst [21] x)
+ // cond:
+ // result: (LEAQ4 x (LEAQ4 <v.Type> x x))
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)) {
+ if v.AuxInt != 21 {
break
}
- v.reset(OpAMD64MOVSSloadidx4)
- v.AuxInt = off1 + off2
- v.Aux = mergeSym(sym1, sym2)
- v.AddArg(ptr)
- v.AddArg(idx)
- v.AddArg(mem)
+ x := v.Args[0]
+ v.reset(OpAMD64LEAQ4)
+ v.AddArg(x)
+ v0 := b.NewValue0(v.Line, OpAMD64LEAQ4, v.Type)
+ v0.AddArg(x)
+ v0.AddArg(x)
+ v.AddArg(v0)
return true
}
- // match: (MOVSSload [off] {sym} (ADDQ ptr idx) mem)
- // cond: ptr.Op != OpSB
- // result: (MOVSSloadidx1 [off] {sym} ptr idx mem)
+ // match: (MULQconst [25] x)
+ // cond:
+ // result: (LEAQ8 x (LEAQ2 <v.Type> x x))
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) {
+ if v.AuxInt != 25 {
break
}
- v.reset(OpAMD64MOVSSloadidx1)
- v.AuxInt = off
- v.Aux = sym
- v.AddArg(ptr)
- v.AddArg(idx)
- v.AddArg(mem)
+ x := v.Args[0]
+ v.reset(OpAMD64LEAQ8)
+ v.AddArg(x)
+ v0 := b.NewValue0(v.Line, OpAMD64LEAQ2, v.Type)
+ v0.AddArg(x)
+ v0.AddArg(x)
+ v.AddArg(v0)
return true
}
- return false
-}
-func rewriteValueAMD64_OpAMD64MOVSSloadidx1(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (MOVSSloadidx1 [c] {sym} (ADDQconst [d] ptr) idx mem)
+ // match: (MULQconst [37] x)
// cond:
- // result: (MOVSSloadidx1 [c+d] {sym} ptr idx mem)
+ // result: (LEAQ4 x (LEAQ8 <v.Type> x x))
for {
- c := v.AuxInt
- sym := v.Aux
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64ADDQconst {
+ if v.AuxInt != 37 {
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)
+ x := v.Args[0]
+ v.reset(OpAMD64LEAQ4)
+ v.AddArg(x)
+ v0 := b.NewValue0(v.Line, OpAMD64LEAQ8, v.Type)
+ v0.AddArg(x)
+ v0.AddArg(x)
+ v.AddArg(v0)
return true
}
- // match: (MOVSSloadidx1 [c] {sym} ptr (ADDQconst [d] idx) mem)
+ // match: (MULQconst [41] x)
// cond:
- // result: (MOVSSloadidx1 [c+d] {sym} ptr idx mem)
+ // result: (LEAQ8 x (LEAQ4 <v.Type> x x))
for {
- c := v.AuxInt
- sym := v.Aux
- ptr := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64ADDQconst {
+ if v.AuxInt != 41 {
break
}
- d := v_1.AuxInt
- idx := v_1.Args[0]
- mem := v.Args[2]
- v.reset(OpAMD64MOVSSloadidx1)
- v.AuxInt = c + d
- v.Aux = sym
- v.AddArg(ptr)
- v.AddArg(idx)
- v.AddArg(mem)
+ x := v.Args[0]
+ v.reset(OpAMD64LEAQ8)
+ v.AddArg(x)
+ v0 := b.NewValue0(v.Line, OpAMD64LEAQ4, v.Type)
+ v0.AddArg(x)
+ v0.AddArg(x)
+ v.AddArg(v0)
return true
}
- return false
-}
-func rewriteValueAMD64_OpAMD64MOVSSloadidx4(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (MOVSSloadidx4 [c] {sym} (ADDQconst [d] ptr) idx mem)
+ // match: (MULQconst [73] x)
// cond:
- // result: (MOVSSloadidx4 [c+d] {sym} ptr idx mem)
+ // result: (LEAQ8 x (LEAQ8 <v.Type> x x))
for {
- c := v.AuxInt
- sym := v.Aux
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64ADDQconst {
+ if v.AuxInt != 73 {
break
}
- d := v_0.AuxInt
- ptr := v_0.Args[0]
- idx := v.Args[1]
- mem := v.Args[2]
- v.reset(OpAMD64MOVSSloadidx4)
- v.AuxInt = c + d
- v.Aux = sym
- v.AddArg(ptr)
- v.AddArg(idx)
- v.AddArg(mem)
+ x := v.Args[0]
+ v.reset(OpAMD64LEAQ8)
+ v.AddArg(x)
+ v0 := b.NewValue0(v.Line, OpAMD64LEAQ8, v.Type)
+ v0.AddArg(x)
+ v0.AddArg(x)
+ v.AddArg(v0)
return true
}
- // match: (MOVSSloadidx4 [c] {sym} ptr (ADDQconst [d] idx) mem)
- // cond:
- // result: (MOVSSloadidx4 [c+4*d] {sym} ptr idx mem)
+ // match: (MULQconst [c] x)
+ // cond: isPowerOfTwo(c)
+ // result: (SHLQconst [log2(c)] x)
for {
c := v.AuxInt
- sym := v.Aux
- ptr := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64ADDQconst {
+ x := v.Args[0]
+ if !(isPowerOfTwo(c)) {
break
}
- d := v_1.AuxInt
- idx := v_1.Args[0]
- mem := v.Args[2]
- v.reset(OpAMD64MOVSSloadidx4)
- v.AuxInt = c + 4*d
- v.Aux = sym
- v.AddArg(ptr)
- v.AddArg(idx)
- v.AddArg(mem)
+ v.reset(OpAMD64SHLQconst)
+ v.AuxInt = log2(c)
+ v.AddArg(x)
return true
}
- return false
-}
-func rewriteValueAMD64_OpAMD64MOVSSstore(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (MOVSSstore [off1] {sym} (ADDQconst [off2] ptr) val mem)
- // cond: is32Bit(off1+off2)
- // result: (MOVSSstore [off1+off2] {sym} ptr val mem)
+ // match: (MULQconst [c] x)
+ // cond: isPowerOfTwo(c+1) && c >= 15
+ // result: (SUBQ (SHLQconst <v.Type> [log2(c+1)] x) x)
for {
- off1 := v.AuxInt
- sym := v.Aux
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64ADDQconst {
- break
- }
- off2 := v_0.AuxInt
- ptr := v_0.Args[0]
- val := v.Args[1]
- mem := v.Args[2]
- if !(is32Bit(off1 + off2)) {
+ c := v.AuxInt
+ x := v.Args[0]
+ if !(isPowerOfTwo(c+1) && c >= 15) {
break
}
- v.reset(OpAMD64MOVSSstore)
- v.AuxInt = off1 + off2
- v.Aux = sym
- v.AddArg(ptr)
- v.AddArg(val)
- v.AddArg(mem)
+ v.reset(OpAMD64SUBQ)
+ v0 := b.NewValue0(v.Line, OpAMD64SHLQconst, v.Type)
+ v0.AuxInt = log2(c + 1)
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v.AddArg(x)
return true
}
- // match: (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)
+ // match: (MULQconst [c] x)
+ // cond: isPowerOfTwo(c-1) && c >= 17
+ // result: (LEAQ1 (SHLQconst <v.Type> [log2(c-1)] x) x)
for {
- off1 := v.AuxInt
- sym1 := v.Aux
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64LEAQ {
+ c := v.AuxInt
+ x := v.Args[0]
+ if !(isPowerOfTwo(c-1) && c >= 17) {
break
}
- off2 := v_0.AuxInt
- sym2 := v_0.Aux
- base := v_0.Args[0]
- val := v.Args[1]
- mem := v.Args[2]
- if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
- break
- }
- v.reset(OpAMD64MOVSSstore)
- v.AuxInt = off1 + off2
- v.Aux = mergeSym(sym1, sym2)
- v.AddArg(base)
- v.AddArg(val)
- v.AddArg(mem)
+ 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: (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)
+ // match: (MULQconst [c] x)
+ // cond: isPowerOfTwo(c-2) && c >= 34
+ // result: (LEAQ2 (SHLQconst <v.Type> [log2(c-2)] x) x)
for {
- off1 := v.AuxInt
- sym1 := v.Aux
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64LEAQ1 {
+ c := v.AuxInt
+ x := v.Args[0]
+ if !(isPowerOfTwo(c-2) && c >= 34) {
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)) {
+ v.reset(OpAMD64LEAQ2)
+ v0 := b.NewValue0(v.Line, OpAMD64SHLQconst, v.Type)
+ v0.AuxInt = log2(c - 2)
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MULQconst [c] x)
+ // cond: isPowerOfTwo(c-4) && c >= 68
+ // result: (LEAQ4 (SHLQconst <v.Type> [log2(c-4)] x) x)
+ for {
+ c := v.AuxInt
+ x := v.Args[0]
+ if !(isPowerOfTwo(c-4) && c >= 68) {
break
}
- v.reset(OpAMD64MOVSSstoreidx1)
- v.AuxInt = off1 + off2
- v.Aux = mergeSym(sym1, sym2)
- v.AddArg(ptr)
- v.AddArg(idx)
- v.AddArg(val)
- v.AddArg(mem)
+ 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: (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)
+ // match: (MULQconst [c] x)
+ // cond: isPowerOfTwo(c-8) && c >= 136
+ // result: (LEAQ8 (SHLQconst <v.Type> [log2(c-8)] x) x)
for {
- off1 := v.AuxInt
- sym1 := v.Aux
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64LEAQ4 {
+ c := v.AuxInt
+ x := v.Args[0]
+ if !(isPowerOfTwo(c-8) && c >= 136) {
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)) {
+ v.reset(OpAMD64LEAQ8)
+ v0 := b.NewValue0(v.Line, OpAMD64SHLQconst, v.Type)
+ v0.AuxInt = log2(c - 8)
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MULQconst [c] x)
+ // cond: c%3 == 0 && isPowerOfTwo(c/3)
+ // result: (SHLQconst [log2(c/3)] (LEAQ2 <v.Type> x x))
+ for {
+ c := v.AuxInt
+ x := v.Args[0]
+ if !(c%3 == 0 && isPowerOfTwo(c/3)) {
break
}
- v.reset(OpAMD64MOVSSstoreidx4)
- v.AuxInt = off1 + off2
- v.Aux = mergeSym(sym1, sym2)
- v.AddArg(ptr)
- v.AddArg(idx)
- v.AddArg(val)
- v.AddArg(mem)
+ 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: (MOVSSstore [off] {sym} (ADDQ ptr idx) val mem)
- // cond: ptr.Op != OpSB
- // result: (MOVSSstoreidx1 [off] {sym} ptr idx val mem)
+ // match: (MULQconst [c] x)
+ // cond: c%5 == 0 && isPowerOfTwo(c/5)
+ // result: (SHLQconst [log2(c/5)] (LEAQ4 <v.Type> x x))
for {
- off := v.AuxInt
- sym := v.Aux
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64ADDQ {
+ c := v.AuxInt
+ x := v.Args[0]
+ if !(c%5 == 0 && isPowerOfTwo(c/5)) {
break
}
- ptr := v_0.Args[0]
- idx := v_0.Args[1]
- val := v.Args[1]
- mem := v.Args[2]
- if !(ptr.Op != OpSB) {
+ v.reset(OpAMD64SHLQconst)
+ v.AuxInt = log2(c / 5)
+ v0 := b.NewValue0(v.Line, OpAMD64LEAQ4, v.Type)
+ v0.AddArg(x)
+ v0.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (MULQconst [c] x)
+ // cond: c%9 == 0 && isPowerOfTwo(c/9)
+ // result: (SHLQconst [log2(c/9)] (LEAQ8 <v.Type> x x))
+ for {
+ c := v.AuxInt
+ x := v.Args[0]
+ if !(c%9 == 0 && isPowerOfTwo(c/9)) {
break
}
- v.reset(OpAMD64MOVSSstoreidx1)
- v.AuxInt = off
- v.Aux = sym
- v.AddArg(ptr)
- v.AddArg(idx)
- v.AddArg(val)
- v.AddArg(mem)
+ 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
}
- return false
-}
-func rewriteValueAMD64_OpAMD64MOVSSstoreidx1(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (MOVSSstoreidx1 [c] {sym} (ADDQconst [d] ptr) idx val mem)
+ // match: (MULQconst [c] (MOVQconst [d]))
// cond:
- // result: (MOVSSstoreidx1 [c+d] {sym} ptr idx val mem)
+ // result: (MOVQconst [c*d])
for {
c := v.AuxInt
- sym := v.Aux
v_0 := v.Args[0]
- if v_0.Op != OpAMD64ADDQconst {
+ if v_0.Op != OpAMD64MOVQconst {
break
}
d := v_0.AuxInt
- ptr := v_0.Args[0]
- idx := v.Args[1]
- val := v.Args[2]
- mem := v.Args[3]
- v.reset(OpAMD64MOVSSstoreidx1)
- v.AuxInt = c + d
- v.Aux = sym
- v.AddArg(ptr)
- v.AddArg(idx)
- v.AddArg(val)
- v.AddArg(mem)
+ v.reset(OpAMD64MOVQconst)
+ v.AuxInt = c * d
return true
}
- // match: (MOVSSstoreidx1 [c] {sym} ptr (ADDQconst [d] idx) val mem)
+ return false
+}
+func rewriteValueAMD64_OpAMD64NEGL(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (NEGL (MOVLconst [c]))
// cond:
- // result: (MOVSSstoreidx1 [c+d] {sym} ptr idx val mem)
+ // result: (MOVLconst [int64(int32(-c))])
for {
- c := v.AuxInt
- sym := v.Aux
- ptr := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64ADDQconst {
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64MOVLconst {
break
}
- d := v_1.AuxInt
- idx := v_1.Args[0]
- val := v.Args[2]
- mem := v.Args[3]
- v.reset(OpAMD64MOVSSstoreidx1)
- v.AuxInt = c + d
- v.Aux = sym
- v.AddArg(ptr)
- v.AddArg(idx)
- v.AddArg(val)
- v.AddArg(mem)
+ c := v_0.AuxInt
+ v.reset(OpAMD64MOVLconst)
+ v.AuxInt = int64(int32(-c))
return true
}
return false
}
-func rewriteValueAMD64_OpAMD64MOVSSstoreidx4(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpAMD64NEGQ(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (MOVSSstoreidx4 [c] {sym} (ADDQconst [d] ptr) idx val mem)
+ // match: (NEGQ (MOVQconst [c]))
// cond:
- // result: (MOVSSstoreidx4 [c+d] {sym} ptr idx val mem)
+ // result: (MOVQconst [-c])
for {
- c := v.AuxInt
- sym := v.Aux
v_0 := v.Args[0]
- if v_0.Op != OpAMD64ADDQconst {
+ if v_0.Op != OpAMD64MOVQconst {
break
}
- d := v_0.AuxInt
- ptr := v_0.Args[0]
- idx := v.Args[1]
- val := v.Args[2]
- mem := v.Args[3]
- v.reset(OpAMD64MOVSSstoreidx4)
- v.AuxInt = c + d
- v.Aux = sym
- v.AddArg(ptr)
- v.AddArg(idx)
- v.AddArg(val)
- v.AddArg(mem)
+ c := v_0.AuxInt
+ v.reset(OpAMD64MOVQconst)
+ v.AuxInt = -c
return true
}
- // match: (MOVSSstoreidx4 [c] {sym} ptr (ADDQconst [d] idx) val mem)
+ return false
+}
+func rewriteValueAMD64_OpAMD64NOTL(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (NOTL (MOVLconst [c]))
// cond:
- // result: (MOVSSstoreidx4 [c+4*d] {sym} ptr idx val mem)
+ // result: (MOVLconst [^c])
for {
- c := v.AuxInt
- sym := v.Aux
- ptr := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64ADDQconst {
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64MOVLconst {
break
}
- d := v_1.AuxInt
- idx := v_1.Args[0]
- val := v.Args[2]
- mem := v.Args[3]
- v.reset(OpAMD64MOVSSstoreidx4)
- v.AuxInt = c + 4*d
- v.Aux = sym
- v.AddArg(ptr)
- v.AddArg(idx)
- v.AddArg(val)
- v.AddArg(mem)
+ c := v_0.AuxInt
+ v.reset(OpAMD64MOVLconst)
+ v.AuxInt = ^c
return true
}
return false
}
-func rewriteValueAMD64_OpAMD64MOVWQSX(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpAMD64NOTQ(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (MOVWQSX x:(MOVWload [off] {sym} ptr mem))
- // cond: x.Uses == 1 && clobber(x)
- // result: @x.Block (MOVWQSXload <v.Type> [off] {sym} ptr mem)
- for {
- x := v.Args[0]
- if x.Op != OpAMD64MOVWload {
- break
- }
- off := x.AuxInt
- sym := x.Aux
- ptr := x.Args[0]
- mem := x.Args[1]
- if !(x.Uses == 1 && clobber(x)) {
- break
- }
- b = x.Block
- v0 := b.NewValue0(v.Line, OpAMD64MOVWQSXload, v.Type)
- v.reset(OpCopy)
- v.AddArg(v0)
- v0.AuxInt = off
- v0.Aux = sym
- v0.AddArg(ptr)
- v0.AddArg(mem)
- return true
- }
- // match: (MOVWQSX (ANDLconst [c] x))
- // cond: c & 0x8000 == 0
- // result: (ANDLconst [c & 0x7fff] x)
+ // match: (NOTQ (MOVQconst [c]))
+ // cond:
+ // result: (MOVQconst [^c])
for {
v_0 := v.Args[0]
- if v_0.Op != OpAMD64ANDLconst {
+ if v_0.Op != OpAMD64MOVQconst {
break
}
c := v_0.AuxInt
- x := v_0.Args[0]
- if !(c&0x8000 == 0) {
- break
- }
- v.reset(OpAMD64ANDLconst)
- v.AuxInt = c & 0x7fff
- v.AddArg(x)
+ v.reset(OpAMD64MOVQconst)
+ v.AuxInt = ^c
return true
}
return false
}
-func rewriteValueAMD64_OpAMD64MOVWQSXload(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpAMD64ORL(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)
+ // match: (ORL x (MOVLconst [c]))
+ // cond:
+ // result: (ORLconst [c] x)
for {
- off1 := v.AuxInt
- sym1 := v.Aux
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64LEAQ {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64MOVLconst {
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_1.AuxInt
+ v.reset(OpAMD64ORLconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (ORL (MOVLconst [c]) x)
+ // cond:
+ // result: (ORLconst [c] x)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64MOVLconst {
break
}
- v.reset(OpAMD64MOVWQSXload)
- v.AuxInt = off1 + off2
- v.Aux = mergeSym(sym1, sym2)
- v.AddArg(base)
- v.AddArg(mem)
+ c := v_0.AuxInt
+ x := v.Args[1]
+ v.reset(OpAMD64ORLconst)
+ v.AuxInt = c
+ v.AddArg(x)
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)
+ // match: (ORL x x)
+ // cond:
+ // result: x
for {
x := v.Args[0]
- if x.Op != OpAMD64MOVWload {
- break
- }
- off := x.AuxInt
- sym := x.Aux
- ptr := x.Args[0]
- mem := x.Args[1]
- if !(x.Uses == 1 && clobber(x)) {
+ if x != v.Args[1] {
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)
+ v.Type = x.Type
+ v.AddArg(x)
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)
+ // 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 {
- x := v.Args[0]
- if x.Op != OpAMD64MOVWloadidx1 {
+ x0 := v.Args[0]
+ if x0.Op != OpAMD64MOVBload {
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)) {
+ i := x0.AuxInt
+ s := x0.Aux
+ p := x0.Args[0]
+ mem := x0.Args[1]
+ s0 := v.Args[1]
+ if s0.Op != OpAMD64SHLLconst {
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 {
+ if s0.AuxInt != 8 {
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)) {
+ x1 := s0.Args[0]
+ if x1.Op != OpAMD64MOVBload {
break
}
- b = x.Block
- v0 := b.NewValue0(v.Line, OpAMD64MOVWloadidx2, v.Type)
- v.reset(OpCopy)
- v.AddArg(v0)
- v0.AuxInt = off
- v0.Aux = sym
- v0.AddArg(ptr)
- v0.AddArg(idx)
- v0.AddArg(mem)
- return true
- }
- // match: (MOVWQZX (ANDLconst [c] x))
- // cond:
- // result: (ANDLconst [c & 0xffff] x)
- for {
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64ANDLconst {
+ if x1.AuxInt != i+1 {
break
}
- c := v_0.AuxInt
- x := v_0.Args[0]
- v.reset(OpAMD64ANDLconst)
- v.AuxInt = c & 0xffff
- v.AddArg(x)
- return true
- }
- return false
-}
-func rewriteValueAMD64_OpAMD64MOVWload(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (MOVWload [off] {sym} ptr (MOVWstore [off2] {sym2} ptr2 x _))
- // cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
- // result: x
- for {
- off := v.AuxInt
- sym := v.Aux
- ptr := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64MOVWstore {
+ if x1.Aux != s {
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 != x1.Args[0] {
+ break
+ }
+ if mem != x1.Args[1] {
+ break
+ }
+ if !(x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0)) {
break
}
+ b = mergePoint(b, x0, x1)
+ v0 := b.NewValue0(v.Line, OpAMD64MOVWload, config.fe.TypeUInt16())
v.reset(OpCopy)
- v.Type = x.Type
- v.AddArg(x)
+ v.AddArg(v0)
+ v0.AuxInt = i
+ v0.Aux = s
+ v0.AddArg(p)
+ v0.AddArg(mem)
return true
}
- // match: (MOVWload [off1] {sym} (ADDQconst [off2] ptr) mem)
- // cond: is32Bit(off1+off2)
- // result: (MOVWload [off1+off2] {sym} ptr mem)
+ // 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 {
- off1 := v.AuxInt
- sym := v.Aux
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64ADDQconst {
+ o0 := v.Args[0]
+ if o0.Op != OpAMD64ORL {
break
}
- off2 := v_0.AuxInt
- ptr := v_0.Args[0]
- mem := v.Args[1]
- if !(is32Bit(off1 + off2)) {
+ x0 := o0.Args[0]
+ if x0.Op != OpAMD64MOVWload {
break
}
- v.reset(OpAMD64MOVWload)
- v.AuxInt = off1 + off2
- v.Aux = sym
- v.AddArg(ptr)
- v.AddArg(mem)
- return true
- }
- // match: (MOVWload [off1] {sym1} (LEAQ [off2] {sym2} base) mem)
- // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
- // result: (MOVWload [off1+off2] {mergeSym(sym1,sym2)} base mem)
- for {
- off1 := v.AuxInt
- sym1 := v.Aux
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64LEAQ {
+ i := x0.AuxInt
+ s := x0.Aux
+ p := x0.Args[0]
+ mem := x0.Args[1]
+ s0 := o0.Args[1]
+ if s0.Op != OpAMD64SHLLconst {
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 s0.AuxInt != 16 {
break
}
- v.reset(OpAMD64MOVWload)
- v.AuxInt = off1 + off2
- v.Aux = mergeSym(sym1, sym2)
- v.AddArg(base)
- v.AddArg(mem)
- return true
- }
- // match: (MOVWload [off1] {sym1} (LEAQ1 [off2] {sym2} ptr idx) mem)
- // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
- // result: (MOVWloadidx1 [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem)
- for {
- off1 := v.AuxInt
- sym1 := v.Aux
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64LEAQ1 {
+ x1 := s0.Args[0]
+ if x1.Op != OpAMD64MOVBload {
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 x1.AuxInt != i+2 {
break
}
- v.reset(OpAMD64MOVWloadidx1)
- v.AuxInt = off1 + off2
- v.Aux = mergeSym(sym1, sym2)
- v.AddArg(ptr)
- v.AddArg(idx)
- v.AddArg(mem)
- return true
- }
- // match: (MOVWload [off1] {sym1} (LEAQ2 [off2] {sym2} ptr idx) mem)
- // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
- // result: (MOVWloadidx2 [off1+off2] {mergeSym(sym1,sym2)} ptr idx mem)
- for {
- off1 := v.AuxInt
- sym1 := v.Aux
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64LEAQ2 {
+ 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)) {
+ if p != x1.Args[0] {
break
}
- v.reset(OpAMD64MOVWloadidx2)
- v.AuxInt = off1 + off2
- v.Aux = mergeSym(sym1, sym2)
- v.AddArg(ptr)
- v.AddArg(idx)
- v.AddArg(mem)
- return true
- }
- // match: (MOVWload [off] {sym} (ADDQ ptr idx) mem)
- // cond: ptr.Op != OpSB
- // result: (MOVWloadidx1 [off] {sym} ptr idx mem)
- for {
- off := v.AuxInt
- sym := v.Aux
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64ADDQ {
+ if mem != x1.Args[1] {
break
}
- ptr := v_0.Args[0]
- idx := v_0.Args[1]
- mem := v.Args[1]
- if !(ptr.Op != OpSB) {
+ s1 := v.Args[1]
+ if s1.Op != OpAMD64SHLLconst {
break
}
- v.reset(OpAMD64MOVWloadidx1)
- v.AuxInt = off
- v.Aux = sym
- v.AddArg(ptr)
- v.AddArg(idx)
- v.AddArg(mem)
- return true
- }
- return false
-}
-func rewriteValueAMD64_OpAMD64MOVWloadidx1(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (MOVWloadidx1 [c] {sym} ptr (SHLQconst [1] idx) mem)
- // cond:
- // result: (MOVWloadidx2 [c] {sym} ptr idx mem)
- for {
- c := v.AuxInt
- sym := v.Aux
- ptr := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64SHLQconst {
+ if s1.AuxInt != 24 {
break
}
- if v_1.AuxInt != 1 {
+ x2 := s1.Args[0]
+ if x2.Op != OpAMD64MOVBload {
break
}
- idx := v_1.Args[0]
- mem := v.Args[2]
- v.reset(OpAMD64MOVWloadidx2)
- v.AuxInt = c
- v.Aux = sym
- v.AddArg(ptr)
- v.AddArg(idx)
- v.AddArg(mem)
- return true
- }
- // match: (MOVWloadidx1 [c] {sym} (ADDQconst [d] ptr) idx mem)
- // cond:
- // result: (MOVWloadidx1 [c+d] {sym} ptr idx mem)
- for {
- c := v.AuxInt
- sym := v.Aux
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64ADDQconst {
+ if x2.AuxInt != i+3 {
break
}
- d := v_0.AuxInt
- ptr := v_0.Args[0]
- idx := v.Args[1]
- mem := v.Args[2]
- v.reset(OpAMD64MOVWloadidx1)
- v.AuxInt = c + d
- v.Aux = sym
- v.AddArg(ptr)
- v.AddArg(idx)
- v.AddArg(mem)
- return true
- }
- // match: (MOVWloadidx1 [c] {sym} ptr (ADDQconst [d] idx) mem)
- // cond:
- // result: (MOVWloadidx1 [c+d] {sym} ptr idx mem)
- for {
- c := v.AuxInt
- sym := v.Aux
- ptr := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64ADDQconst {
+ if x2.Aux != s {
break
}
- d := v_1.AuxInt
- idx := v_1.Args[0]
- mem := v.Args[2]
- v.reset(OpAMD64MOVWloadidx1)
- v.AuxInt = c + d
- v.Aux = sym
- v.AddArg(ptr)
- v.AddArg(idx)
- v.AddArg(mem)
- return true
- }
- return false
-}
-func rewriteValueAMD64_OpAMD64MOVWloadidx2(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (MOVWloadidx2 [c] {sym} (ADDQconst [d] ptr) idx mem)
- // cond:
- // result: (MOVWloadidx2 [c+d] {sym} ptr idx mem)
- for {
- c := v.AuxInt
- sym := v.Aux
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64ADDQconst {
+ if p != x2.Args[0] {
break
}
- d := v_0.AuxInt
- ptr := v_0.Args[0]
- idx := v.Args[1]
- mem := v.Args[2]
- v.reset(OpAMD64MOVWloadidx2)
- v.AuxInt = c + d
- v.Aux = sym
- v.AddArg(ptr)
- v.AddArg(idx)
- v.AddArg(mem)
- return true
- }
- // match: (MOVWloadidx2 [c] {sym} ptr (ADDQconst [d] idx) mem)
- // cond:
- // result: (MOVWloadidx2 [c+2*d] {sym} ptr idx mem)
- for {
- c := v.AuxInt
- sym := v.Aux
- ptr := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64ADDQconst {
+ if mem != x2.Args[1] {
break
}
- d := v_1.AuxInt
- idx := v_1.Args[0]
- mem := v.Args[2]
- v.reset(OpAMD64MOVWloadidx2)
- v.AuxInt = c + 2*d
- v.Aux = sym
- v.AddArg(ptr)
- v.AddArg(idx)
- v.AddArg(mem)
- return true
- }
- return false
-}
-func rewriteValueAMD64_OpAMD64MOVWstore(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (MOVWstore [off] {sym} ptr (MOVWQSX x) mem)
- // cond:
- // result: (MOVWstore [off] {sym} ptr x mem)
- for {
- off := v.AuxInt
- sym := v.Aux
- ptr := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64MOVWQSX {
+ 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)) {
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)
+ 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)
return true
}
- // match: (MOVWstore [off] {sym} ptr (MOVWQZX x) mem)
- // cond:
- // result: (MOVWstore [off] {sym} ptr x mem)
+ // match: (ORL x0:(MOVBloadidx1 [i] {s} p idx mem) s0:(SHLLconst [8] x1:(MOVBloadidx1 [i+1] {s} p idx mem)))
+ // cond: x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && mergePoint(b,x0,x1) != nil && clobber(x0) && clobber(x1) && clobber(s0)
+ // result: @mergePoint(b,x0,x1) (MOVWloadidx1 <v.Type> [i] {s} p idx mem)
for {
- off := v.AuxInt
- sym := v.Aux
- ptr := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64MOVWQZX {
+ x0 := v.Args[0]
+ if x0.Op != OpAMD64MOVBloadidx1 {
break
}
- x := v_1.Args[0]
- mem := v.Args[2]
- v.reset(OpAMD64MOVWstore)
- v.AuxInt = off
- v.Aux = sym
- v.AddArg(ptr)
- v.AddArg(x)
- v.AddArg(mem)
- return true
- }
- // match: (MOVWstore [off1] {sym} (ADDQconst [off2] ptr) val mem)
- // cond: is32Bit(off1+off2)
- // result: (MOVWstore [off1+off2] {sym} ptr val mem)
- for {
- off1 := v.AuxInt
- sym := v.Aux
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64ADDQconst {
- break
- }
- off2 := v_0.AuxInt
- ptr := v_0.Args[0]
- val := v.Args[1]
- mem := v.Args[2]
- if !(is32Bit(off1 + off2)) {
+ i := x0.AuxInt
+ s := x0.Aux
+ p := x0.Args[0]
+ idx := x0.Args[1]
+ mem := x0.Args[2]
+ s0 := v.Args[1]
+ if s0.Op != OpAMD64SHLLconst {
break
}
- v.reset(OpAMD64MOVWstore)
- v.AuxInt = off1 + off2
- v.Aux = sym
- v.AddArg(ptr)
- v.AddArg(val)
- v.AddArg(mem)
- return true
- }
- // match: (MOVWstore [off] {sym} ptr (MOVLconst [c]) mem)
- // cond: validOff(off)
- // result: (MOVWstoreconst [makeValAndOff(int64(int16(c)),off)] {sym} ptr mem)
- for {
- off := v.AuxInt
- sym := v.Aux
- ptr := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64MOVLconst {
+ if s0.AuxInt != 8 {
break
}
- c := v_1.AuxInt
- mem := v.Args[2]
- if !(validOff(off)) {
+ x1 := s0.Args[0]
+ if x1.Op != OpAMD64MOVBloadidx1 {
break
}
- v.reset(OpAMD64MOVWstoreconst)
- v.AuxInt = makeValAndOff(int64(int16(c)), off)
- v.Aux = sym
- v.AddArg(ptr)
- v.AddArg(mem)
- return true
- }
- // match: (MOVWstore [off1] {sym1} (LEAQ [off2] {sym2} base) val mem)
- // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
- // result: (MOVWstore [off1+off2] {mergeSym(sym1,sym2)} base val mem)
- for {
- off1 := v.AuxInt
- sym1 := v.Aux
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64LEAQ {
+ if x1.AuxInt != i+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 x1.Aux != s {
break
}
- v.reset(OpAMD64MOVWstore)
- v.AuxInt = off1 + off2
- v.Aux = mergeSym(sym1, sym2)
- v.AddArg(base)
- v.AddArg(val)
- v.AddArg(mem)
- return true
- }
- // match: (MOVWstore [off1] {sym1} (LEAQ1 [off2] {sym2} ptr idx) val mem)
- // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
- // result: (MOVWstoreidx1 [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem)
- for {
- off1 := v.AuxInt
- sym1 := v.Aux
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64LEAQ1 {
+ if p != 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 idx != x1.Args[1] {
break
}
- v.reset(OpAMD64MOVWstoreidx1)
- v.AuxInt = off1 + off2
- v.Aux = mergeSym(sym1, sym2)
- v.AddArg(ptr)
- v.AddArg(idx)
- v.AddArg(val)
- v.AddArg(mem)
- return true
- }
- // match: (MOVWstore [off1] {sym1} (LEAQ2 [off2] {sym2} ptr idx) val mem)
- // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
- // result: (MOVWstoreidx2 [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem)
- for {
- off1 := v.AuxInt
- sym1 := v.Aux
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64LEAQ2 {
+ if mem != x1.Args[2] {
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 !(x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0)) {
break
}
- v.reset(OpAMD64MOVWstoreidx2)
- v.AuxInt = off1 + off2
- v.Aux = mergeSym(sym1, sym2)
- v.AddArg(ptr)
- v.AddArg(idx)
- v.AddArg(val)
- v.AddArg(mem)
+ b = mergePoint(b, x0, x1)
+ v0 := b.NewValue0(v.Line, OpAMD64MOVWloadidx1, v.Type)
+ v.reset(OpCopy)
+ v.AddArg(v0)
+ v0.AuxInt = i
+ v0.Aux = s
+ v0.AddArg(p)
+ v0.AddArg(idx)
+ v0.AddArg(mem)
return true
}
- // match: (MOVWstore [off] {sym} (ADDQ ptr idx) val mem)
- // cond: ptr.Op != OpSB
- // result: (MOVWstoreidx1 [off] {sym} ptr idx val mem)
+ // 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)
for {
- off := v.AuxInt
- sym := v.Aux
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64ADDQ {
+ o0 := v.Args[0]
+ if o0.Op != OpAMD64ORL {
break
}
- ptr := v_0.Args[0]
- idx := v_0.Args[1]
- val := v.Args[1]
- mem := v.Args[2]
- if !(ptr.Op != OpSB) {
+ x0 := o0.Args[0]
+ if x0.Op != OpAMD64MOVWloadidx1 {
break
}
- v.reset(OpAMD64MOVWstoreidx1)
- v.AuxInt = off
- v.Aux = sym
- v.AddArg(ptr)
- v.AddArg(idx)
- v.AddArg(val)
- v.AddArg(mem)
- return true
- }
- // match: (MOVWstore [i] {s} p (SHRQconst [16] w) x:(MOVWstore [i-2] {s} p w mem))
- // cond: x.Uses == 1 && clobber(x)
- // result: (MOVLstore [i-2] {s} p w mem)
- for {
- i := v.AuxInt
- s := v.Aux
- p := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64SHRQconst {
+ 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 v_1.AuxInt != 16 {
+ if s0.AuxInt != 16 {
break
}
- w := v_1.Args[0]
- x := v.Args[2]
- if x.Op != OpAMD64MOVWstore {
+ x1 := s0.Args[0]
+ if x1.Op != OpAMD64MOVBloadidx1 {
break
}
- if x.AuxInt != i-2 {
+ if x1.AuxInt != i+2 {
break
}
- if x.Aux != s {
+ if x1.Aux != s {
break
}
- if p != x.Args[0] {
+ if p != x1.Args[0] {
break
}
- if w != x.Args[1] {
+ if idx != x1.Args[1] {
break
}
- mem := x.Args[2]
- if !(x.Uses == 1 && clobber(x)) {
+ if mem != x1.Args[2] {
break
}
- v.reset(OpAMD64MOVLstore)
- v.AuxInt = i - 2
- v.Aux = s
- v.AddArg(p)
- v.AddArg(w)
- v.AddArg(mem)
- return true
- }
- // match: (MOVWstore [i] {s} p (SHRQconst [j] w) x:(MOVWstore [i-2] {s} p w0:(SHRQconst [j-16] w) mem))
- // cond: x.Uses == 1 && clobber(x)
- // result: (MOVLstore [i-2] {s} p w0 mem)
- for {
- i := v.AuxInt
- s := v.Aux
- p := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64SHRQconst {
+ s1 := v.Args[1]
+ if s1.Op != OpAMD64SHLLconst {
break
}
- j := v_1.AuxInt
- w := v_1.Args[0]
- x := v.Args[2]
- if x.Op != OpAMD64MOVWstore {
+ if s1.AuxInt != 24 {
break
}
- if x.AuxInt != i-2 {
+ x2 := s1.Args[0]
+ if x2.Op != OpAMD64MOVBloadidx1 {
break
}
- if x.Aux != s {
+ if x2.AuxInt != i+3 {
break
}
- if p != x.Args[0] {
+ if x2.Aux != s {
break
}
- w0 := x.Args[1]
- if w0.Op != OpAMD64SHRQconst {
+ if p != x2.Args[0] {
break
}
- if w0.AuxInt != j-16 {
+ if idx != x2.Args[1] {
break
}
- if w != w0.Args[0] {
+ if mem != x2.Args[2] {
break
}
- mem := x.Args[2]
- if !(x.Uses == 1 && clobber(x)) {
+ 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)) {
break
}
- v.reset(OpAMD64MOVLstore)
- v.AuxInt = i - 2
- v.Aux = s
- v.AddArg(p)
- v.AddArg(w0)
- v.AddArg(mem)
+ b = mergePoint(b, x0, x1, x2)
+ v0 := b.NewValue0(v.Line, OpAMD64MOVLloadidx1, v.Type)
+ v.reset(OpCopy)
+ v.AddArg(v0)
+ v0.AuxInt = i
+ v0.Aux = s
+ v0.AddArg(p)
+ v0.AddArg(idx)
+ v0.AddArg(mem)
return true
}
- return false
-}
-func rewriteValueAMD64_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)
+ // 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))
for {
- sc := v.AuxInt
- s := v.Aux
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64ADDQconst {
+ o1 := v.Args[0]
+ if o1.Op != OpAMD64ORL {
break
}
- off := v_0.AuxInt
- ptr := v_0.Args[0]
- mem := v.Args[1]
- if !(ValAndOff(sc).canAdd(off)) {
+ o0 := o1.Args[0]
+ if o0.Op != OpAMD64ORL {
break
}
- v.reset(OpAMD64MOVWstoreconst)
- v.AuxInt = ValAndOff(sc).add(off)
- v.Aux = s
- v.AddArg(ptr)
- v.AddArg(mem)
- return true
- }
- // match: (MOVWstoreconst [sc] {sym1} (LEAQ [off] {sym2} ptr) mem)
- // cond: canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd(off)
- // result: (MOVWstoreconst [ValAndOff(sc).add(off)] {mergeSym(sym1, sym2)} ptr mem)
- for {
- sc := v.AuxInt
- sym1 := v.Aux
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64LEAQ {
+ x0 := o0.Args[0]
+ if x0.Op != OpAMD64MOVBload {
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)) {
+ i := x0.AuxInt
+ s := x0.Aux
+ p := x0.Args[0]
+ mem := x0.Args[1]
+ s0 := o0.Args[1]
+ if s0.Op != OpAMD64SHLLconst {
break
}
- v.reset(OpAMD64MOVWstoreconst)
- v.AuxInt = ValAndOff(sc).add(off)
- v.Aux = mergeSym(sym1, sym2)
- v.AddArg(ptr)
- v.AddArg(mem)
- return true
- }
- // match: (MOVWstoreconst [x] {sym1} (LEAQ1 [off] {sym2} ptr idx) mem)
- // cond: canMergeSym(sym1, sym2)
- // result: (MOVWstoreconstidx1 [ValAndOff(x).add(off)] {mergeSym(sym1,sym2)} ptr idx mem)
- for {
- x := v.AuxInt
- sym1 := v.Aux
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64LEAQ1 {
+ if s0.AuxInt != 8 {
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)) {
+ x1 := s0.Args[0]
+ if x1.Op != OpAMD64MOVBload {
break
}
- v.reset(OpAMD64MOVWstoreconstidx1)
- v.AuxInt = ValAndOff(x).add(off)
- v.Aux = mergeSym(sym1, sym2)
- v.AddArg(ptr)
- v.AddArg(idx)
- v.AddArg(mem)
- return true
- }
- // match: (MOVWstoreconst [x] {sym1} (LEAQ2 [off] {sym2} ptr idx) mem)
- // cond: canMergeSym(sym1, sym2)
- // result: (MOVWstoreconstidx2 [ValAndOff(x).add(off)] {mergeSym(sym1,sym2)} ptr idx mem)
- for {
- x := v.AuxInt
- sym1 := v.Aux
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64LEAQ2 {
+ if x1.AuxInt != i-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)) {
+ if x1.Aux != s {
break
}
- v.reset(OpAMD64MOVWstoreconstidx2)
- v.AuxInt = ValAndOff(x).add(off)
- v.Aux = mergeSym(sym1, sym2)
- v.AddArg(ptr)
- v.AddArg(idx)
- v.AddArg(mem)
- return true
- }
- // match: (MOVWstoreconst [x] {sym} (ADDQ ptr idx) mem)
- // cond:
- // result: (MOVWstoreconstidx1 [x] {sym} ptr idx mem)
- for {
- x := v.AuxInt
- sym := v.Aux
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64ADDQ {
+ if p != x1.Args[0] {
break
}
- ptr := v_0.Args[0]
- idx := v_0.Args[1]
- mem := v.Args[1]
- v.reset(OpAMD64MOVWstoreconstidx1)
- v.AuxInt = x
- v.Aux = sym
- v.AddArg(ptr)
- v.AddArg(idx)
- v.AddArg(mem)
- return true
- }
- // match: (MOVWstoreconst [c] {s} p x:(MOVWstoreconst [a] {s} p mem))
- // cond: x.Uses == 1 && ValAndOff(a).Off() + 2 == ValAndOff(c).Off() && clobber(x)
- // result: (MOVLstoreconst [makeValAndOff(ValAndOff(a).Val()&0xffff | ValAndOff(c).Val()<<16, ValAndOff(a).Off())] {s} p mem)
- for {
- c := v.AuxInt
- s := v.Aux
- p := v.Args[0]
- x := v.Args[1]
- if x.Op != OpAMD64MOVWstoreconst {
+ if mem != x1.Args[1] {
break
}
- a := x.AuxInt
- if x.Aux != s {
+ s1 := o1.Args[1]
+ if s1.Op != OpAMD64SHLLconst {
break
}
- if p != x.Args[0] {
+ if s1.AuxInt != 16 {
break
}
- mem := x.Args[1]
- if !(x.Uses == 1 && ValAndOff(a).Off()+2 == ValAndOff(c).Off() && clobber(x)) {
+ x2 := s1.Args[0]
+ if x2.Op != OpAMD64MOVBload {
break
}
- v.reset(OpAMD64MOVLstoreconst)
- v.AuxInt = makeValAndOff(ValAndOff(a).Val()&0xffff|ValAndOff(c).Val()<<16, ValAndOff(a).Off())
- v.Aux = s
- v.AddArg(p)
- v.AddArg(mem)
- return true
- }
- return false
-}
-func rewriteValueAMD64_OpAMD64MOVWstoreconstidx1(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (MOVWstoreconstidx1 [c] {sym} ptr (SHLQconst [1] idx) mem)
- // cond:
- // result: (MOVWstoreconstidx2 [c] {sym} ptr idx mem)
- for {
- c := v.AuxInt
- sym := v.Aux
- ptr := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64SHLQconst {
+ if x2.AuxInt != i-2 {
break
}
- if v_1.AuxInt != 1 {
+ if x2.Aux != s {
break
}
- idx := v_1.Args[0]
- mem := v.Args[2]
- v.reset(OpAMD64MOVWstoreconstidx2)
- v.AuxInt = c
- v.Aux = sym
- v.AddArg(ptr)
- v.AddArg(idx)
- v.AddArg(mem)
- return true
- }
- // match: (MOVWstoreconstidx1 [x] {sym} (ADDQconst [c] ptr) idx mem)
- // cond:
- // result: (MOVWstoreconstidx1 [ValAndOff(x).add(c)] {sym} ptr idx mem)
- for {
- x := v.AuxInt
- sym := v.Aux
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64ADDQconst {
+ if p != x2.Args[0] {
break
}
- c := v_0.AuxInt
- ptr := v_0.Args[0]
- idx := v.Args[1]
- mem := v.Args[2]
- v.reset(OpAMD64MOVWstoreconstidx1)
- v.AuxInt = ValAndOff(x).add(c)
- v.Aux = sym
- v.AddArg(ptr)
- v.AddArg(idx)
- v.AddArg(mem)
- return true
- }
- // match: (MOVWstoreconstidx1 [x] {sym} ptr (ADDQconst [c] idx) mem)
- // cond:
- // result: (MOVWstoreconstidx1 [ValAndOff(x).add(c)] {sym} ptr idx mem)
- for {
- x := v.AuxInt
- sym := v.Aux
- ptr := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64ADDQconst {
+ if mem != x2.Args[1] {
break
}
- c := v_1.AuxInt
- idx := v_1.Args[0]
- mem := v.Args[2]
- v.reset(OpAMD64MOVWstoreconstidx1)
- v.AuxInt = ValAndOff(x).add(c)
- v.Aux = sym
- v.AddArg(ptr)
- v.AddArg(idx)
- v.AddArg(mem)
- return true
- }
- // match: (MOVWstoreconstidx1 [c] {s} p i x:(MOVWstoreconstidx1 [a] {s} p i mem))
- // cond: x.Uses == 1 && ValAndOff(a).Off() + 2 == ValAndOff(c).Off() && clobber(x)
- // result: (MOVLstoreconstidx1 [makeValAndOff(ValAndOff(a).Val()&0xffff | ValAndOff(c).Val()<<16, ValAndOff(a).Off())] {s} p i mem)
- for {
- c := v.AuxInt
- s := v.Aux
- p := v.Args[0]
- i := v.Args[1]
- x := v.Args[2]
- if x.Op != OpAMD64MOVWstoreconstidx1 {
+ s2 := v.Args[1]
+ if s2.Op != OpAMD64SHLLconst {
break
}
- a := x.AuxInt
- if x.Aux != s {
+ if s2.AuxInt != 24 {
break
}
- if p != x.Args[0] {
+ x3 := s2.Args[0]
+ if x3.Op != OpAMD64MOVBload {
break
}
- if i != x.Args[1] {
+ if x3.AuxInt != i-3 {
break
}
- mem := x.Args[2]
- if !(x.Uses == 1 && ValAndOff(a).Off()+2 == ValAndOff(c).Off() && clobber(x)) {
+ if x3.Aux != s {
break
}
- v.reset(OpAMD64MOVLstoreconstidx1)
- v.AuxInt = makeValAndOff(ValAndOff(a).Val()&0xffff|ValAndOff(c).Val()<<16, ValAndOff(a).Off())
- v.Aux = s
- v.AddArg(p)
- v.AddArg(i)
- v.AddArg(mem)
- return true
- }
- return false
-}
-func rewriteValueAMD64_OpAMD64MOVWstoreconstidx2(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (MOVWstoreconstidx2 [x] {sym} (ADDQconst [c] ptr) idx mem)
- // cond:
- // result: (MOVWstoreconstidx2 [ValAndOff(x).add(c)] {sym} ptr idx mem)
- for {
- x := v.AuxInt
- sym := v.Aux
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64ADDQconst {
+ if p != x3.Args[0] {
break
}
- c := v_0.AuxInt
- ptr := v_0.Args[0]
- idx := v.Args[1]
- mem := v.Args[2]
- v.reset(OpAMD64MOVWstoreconstidx2)
- v.AuxInt = ValAndOff(x).add(c)
- v.Aux = sym
- v.AddArg(ptr)
- v.AddArg(idx)
- v.AddArg(mem)
- return true
- }
- // match: (MOVWstoreconstidx2 [x] {sym} ptr (ADDQconst [c] idx) mem)
- // cond:
- // result: (MOVWstoreconstidx2 [ValAndOff(x).add(2*c)] {sym} ptr idx mem)
- for {
- x := v.AuxInt
- sym := v.Aux
- ptr := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64ADDQconst {
+ if mem != x3.Args[1] {
break
}
- c := v_1.AuxInt
- idx := v_1.Args[0]
- mem := v.Args[2]
- v.reset(OpAMD64MOVWstoreconstidx2)
- v.AuxInt = ValAndOff(x).add(2 * c)
- v.Aux = sym
- v.AddArg(ptr)
- v.AddArg(idx)
- v.AddArg(mem)
+ if !(x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && x3.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && s2.Uses == 1 && o0.Uses == 1 && o1.Uses == 1 && mergePoint(b, x0, x1, x2, x3) != nil && clobber(x0) && clobber(x1) && clobber(x2) && clobber(x3) && clobber(s0) && clobber(s1) && clobber(s2) && clobber(o0) && clobber(o1)) {
+ break
+ }
+ b = mergePoint(b, x0, x1, x2, x3)
+ v0 := b.NewValue0(v.Line, 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)
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: (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))
for {
- c := v.AuxInt
- s := v.Aux
- p := v.Args[0]
- i := v.Args[1]
- x := v.Args[2]
- if x.Op != OpAMD64MOVWstoreconstidx2 {
+ o1 := v.Args[0]
+ if o1.Op != OpAMD64ORL {
break
}
- a := x.AuxInt
- if x.Aux != s {
+ o0 := o1.Args[0]
+ if o0.Op != OpAMD64ORL {
break
}
- if p != x.Args[0] {
+ x0 := o0.Args[0]
+ if x0.Op != OpAMD64MOVBloadidx1 {
break
}
- if i != x.Args[1] {
+ 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
}
- mem := x.Args[2]
- if !(x.Uses == 1 && ValAndOff(a).Off()+2 == ValAndOff(c).Off() && clobber(x)) {
+ if s0.AuxInt != 8 {
break
}
- v.reset(OpAMD64MOVLstoreconstidx1)
- v.AuxInt = makeValAndOff(ValAndOff(a).Val()&0xffff|ValAndOff(c).Val()<<16, ValAndOff(a).Off())
- v.Aux = s
- v.AddArg(p)
- v0 := b.NewValue0(v.Line, OpAMD64SHLQconst, i.Type)
- v0.AuxInt = 1
- v0.AddArg(i)
- v.AddArg(v0)
- v.AddArg(mem)
- return true
- }
- return false
-}
-func rewriteValueAMD64_OpAMD64MOVWstoreidx1(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (MOVWstoreidx1 [c] {sym} ptr (SHLQconst [1] idx) val mem)
- // cond:
- // result: (MOVWstoreidx2 [c] {sym} ptr idx val mem)
- for {
- c := v.AuxInt
- sym := v.Aux
- ptr := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64SHLQconst {
+ x1 := s0.Args[0]
+ if x1.Op != OpAMD64MOVBloadidx1 {
break
}
- if v_1.AuxInt != 1 {
+ if x1.AuxInt != i-1 {
break
}
- idx := v_1.Args[0]
- val := v.Args[2]
- mem := v.Args[3]
- v.reset(OpAMD64MOVWstoreidx2)
- v.AuxInt = c
- v.Aux = sym
- v.AddArg(ptr)
- v.AddArg(idx)
- v.AddArg(val)
- v.AddArg(mem)
- return true
- }
- // match: (MOVWstoreidx1 [c] {sym} (ADDQconst [d] ptr) idx val mem)
- // cond:
- // result: (MOVWstoreidx1 [c+d] {sym} ptr idx val mem)
- for {
- c := v.AuxInt
- sym := v.Aux
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64ADDQconst {
+ if x1.Aux != s {
break
}
- d := v_0.AuxInt
- ptr := v_0.Args[0]
- idx := v.Args[1]
- val := v.Args[2]
- mem := v.Args[3]
- v.reset(OpAMD64MOVWstoreidx1)
- v.AuxInt = c + d
- v.Aux = sym
- v.AddArg(ptr)
- v.AddArg(idx)
- v.AddArg(val)
- v.AddArg(mem)
- return true
- }
- // match: (MOVWstoreidx1 [c] {sym} ptr (ADDQconst [d] idx) val mem)
- // cond:
- // result: (MOVWstoreidx1 [c+d] {sym} ptr idx val mem)
- for {
- c := v.AuxInt
- sym := v.Aux
- ptr := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64ADDQconst {
+ if p != x1.Args[0] {
break
}
- d := v_1.AuxInt
- idx := v_1.Args[0]
- val := v.Args[2]
- mem := v.Args[3]
- v.reset(OpAMD64MOVWstoreidx1)
- v.AuxInt = c + d
- v.Aux = sym
- v.AddArg(ptr)
- v.AddArg(idx)
- v.AddArg(val)
- v.AddArg(mem)
- return true
- }
- // match: (MOVWstoreidx1 [i] {s} p idx (SHRQconst [16] w) x:(MOVWstoreidx1 [i-2] {s} p idx w mem))
- // cond: x.Uses == 1 && clobber(x)
- // result: (MOVLstoreidx1 [i-2] {s} p idx w mem)
- for {
- i := v.AuxInt
- s := v.Aux
- p := v.Args[0]
- idx := v.Args[1]
- v_2 := v.Args[2]
- if v_2.Op != OpAMD64SHRQconst {
+ if idx != x1.Args[1] {
break
}
- if v_2.AuxInt != 16 {
+ if mem != x1.Args[2] {
break
}
- w := v_2.Args[0]
- x := v.Args[3]
- if x.Op != OpAMD64MOVWstoreidx1 {
+ s1 := o1.Args[1]
+ if s1.Op != OpAMD64SHLLconst {
break
}
- if x.AuxInt != i-2 {
+ if s1.AuxInt != 16 {
break
}
- if x.Aux != s {
+ x2 := s1.Args[0]
+ if x2.Op != OpAMD64MOVBloadidx1 {
break
}
- if p != x.Args[0] {
+ if x2.AuxInt != i-2 {
break
}
- if idx != x.Args[1] {
+ if x2.Aux != s {
break
}
- if w != x.Args[2] {
+ if p != x2.Args[0] {
break
}
- mem := x.Args[3]
- if !(x.Uses == 1 && clobber(x)) {
+ if idx != x2.Args[1] {
break
}
- v.reset(OpAMD64MOVLstoreidx1)
- v.AuxInt = i - 2
- v.Aux = s
- v.AddArg(p)
- v.AddArg(idx)
- v.AddArg(w)
- v.AddArg(mem)
- return true
- }
- // match: (MOVWstoreidx1 [i] {s} p idx (SHRQconst [j] w) x:(MOVWstoreidx1 [i-2] {s} p idx w0:(SHRQconst [j-16] w) mem))
- // cond: x.Uses == 1 && clobber(x)
- // result: (MOVLstoreidx1 [i-2] {s} p idx w0 mem)
- for {
- i := v.AuxInt
- s := v.Aux
- p := v.Args[0]
- idx := v.Args[1]
- v_2 := v.Args[2]
- if v_2.Op != OpAMD64SHRQconst {
+ if mem != x2.Args[2] {
break
}
- j := v_2.AuxInt
- w := v_2.Args[0]
- x := v.Args[3]
- if x.Op != OpAMD64MOVWstoreidx1 {
+ s2 := v.Args[1]
+ if s2.Op != OpAMD64SHLLconst {
break
}
- if x.AuxInt != i-2 {
+ if s2.AuxInt != 24 {
break
}
- if x.Aux != s {
+ x3 := s2.Args[0]
+ if x3.Op != OpAMD64MOVBloadidx1 {
break
}
- if p != x.Args[0] {
+ if x3.AuxInt != i-3 {
break
}
- if idx != x.Args[1] {
+ if x3.Aux != s {
break
}
- w0 := x.Args[2]
- if w0.Op != OpAMD64SHRQconst {
+ if p != x3.Args[0] {
break
}
- if w0.AuxInt != j-16 {
+ if idx != x3.Args[1] {
break
}
- if w != w0.Args[0] {
+ if mem != x3.Args[2] {
break
}
- mem := x.Args[3]
- if !(x.Uses == 1 && clobber(x)) {
+ if !(x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && x3.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && s2.Uses == 1 && o0.Uses == 1 && o1.Uses == 1 && mergePoint(b, x0, x1, x2, x3) != nil && clobber(x0) && clobber(x1) && clobber(x2) && clobber(x3) && clobber(s0) && clobber(s1) && clobber(s2) && clobber(o0) && clobber(o1)) {
break
}
- v.reset(OpAMD64MOVLstoreidx1)
- v.AuxInt = i - 2
- v.Aux = s
- v.AddArg(p)
- v.AddArg(idx)
- v.AddArg(w0)
- v.AddArg(mem)
+ 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, OpAMD64MOVLloadidx1, v.Type)
+ v1.AuxInt = i - 3
+ v1.Aux = s
+ v1.AddArg(p)
+ v1.AddArg(idx)
+ v1.AddArg(mem)
+ v0.AddArg(v1)
return true
}
return false
}
-func rewriteValueAMD64_OpAMD64MOVWstoreidx2(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpAMD64ORLconst(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (MOVWstoreidx2 [c] {sym} (ADDQconst [d] ptr) idx val mem)
- // cond:
- // result: (MOVWstoreidx2 [c+d] {sym} ptr idx val mem)
+ // match: (ORLconst [c] x)
+ // cond: int32(c)==0
+ // result: x
for {
c := v.AuxInt
- sym := v.Aux
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64ADDQconst {
+ x := v.Args[0]
+ if !(int32(c) == 0) {
break
}
- d := v_0.AuxInt
- ptr := v_0.Args[0]
- idx := v.Args[1]
- val := v.Args[2]
- mem := v.Args[3]
- v.reset(OpAMD64MOVWstoreidx2)
- v.AuxInt = c + d
- v.Aux = sym
- v.AddArg(ptr)
- v.AddArg(idx)
- v.AddArg(val)
- v.AddArg(mem)
- return true
- }
- // match: (MOVWstoreidx2 [c] {sym} ptr (ADDQconst [d] idx) val mem)
- // cond:
- // result: (MOVWstoreidx2 [c+2*d] {sym} ptr idx val mem)
- for {
- c := v.AuxInt
- sym := v.Aux
- ptr := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64ADDQconst {
- break
- }
- d := v_1.AuxInt
- idx := v_1.Args[0]
- val := v.Args[2]
- mem := v.Args[3]
- v.reset(OpAMD64MOVWstoreidx2)
- v.AuxInt = c + 2*d
- v.Aux = sym
- v.AddArg(ptr)
- v.AddArg(idx)
- v.AddArg(val)
- v.AddArg(mem)
- return true
- }
- // match: (MOVWstoreidx2 [i] {s} p idx (SHRQconst [16] w) x:(MOVWstoreidx2 [i-2] {s} p idx w mem))
- // cond: x.Uses == 1 && clobber(x)
- // result: (MOVLstoreidx1 [i-2] {s} p (SHLQconst <idx.Type> [1] idx) w mem)
- for {
- i := v.AuxInt
- s := v.Aux
- p := v.Args[0]
- idx := v.Args[1]
- v_2 := v.Args[2]
- if v_2.Op != OpAMD64SHRQconst {
- break
- }
- if v_2.AuxInt != 16 {
- break
- }
- w := v_2.Args[0]
- x := v.Args[3]
- if x.Op != OpAMD64MOVWstoreidx2 {
- break
- }
- if x.AuxInt != i-2 {
- break
- }
- if x.Aux != s {
- break
- }
- if p != x.Args[0] {
- break
- }
- if idx != x.Args[1] {
- break
- }
- if w != x.Args[2] {
- break
- }
- mem := x.Args[3]
- if !(x.Uses == 1 && clobber(x)) {
- break
- }
- v.reset(OpAMD64MOVLstoreidx1)
- v.AuxInt = i - 2
- v.Aux = s
- v.AddArg(p)
- v0 := b.NewValue0(v.Line, OpAMD64SHLQconst, idx.Type)
- v0.AuxInt = 1
- v0.AddArg(idx)
- v.AddArg(v0)
- v.AddArg(w)
- v.AddArg(mem)
- return true
- }
- // match: (MOVWstoreidx2 [i] {s} p idx (SHRQconst [j] w) x:(MOVWstoreidx2 [i-2] {s} p idx w0:(SHRQconst [j-16] w) mem))
- // cond: x.Uses == 1 && clobber(x)
- // result: (MOVLstoreidx1 [i-2] {s} p (SHLQconst <idx.Type> [1] idx) w0 mem)
- for {
- i := v.AuxInt
- s := v.Aux
- p := v.Args[0]
- idx := v.Args[1]
- v_2 := v.Args[2]
- if v_2.Op != OpAMD64SHRQconst {
- break
- }
- j := v_2.AuxInt
- w := v_2.Args[0]
- x := v.Args[3]
- if x.Op != OpAMD64MOVWstoreidx2 {
- break
- }
- if x.AuxInt != i-2 {
- break
- }
- if x.Aux != s {
- break
- }
- if p != x.Args[0] {
- break
- }
- if idx != x.Args[1] {
- break
- }
- w0 := x.Args[2]
- if w0.Op != OpAMD64SHRQconst {
- break
- }
- if w0.AuxInt != j-16 {
- break
- }
- if w != w0.Args[0] {
- break
- }
- mem := x.Args[3]
- if !(x.Uses == 1 && clobber(x)) {
- break
- }
- v.reset(OpAMD64MOVLstoreidx1)
- v.AuxInt = i - 2
- v.Aux = s
- v.AddArg(p)
- v0 := b.NewValue0(v.Line, OpAMD64SHLQconst, idx.Type)
- v0.AuxInt = 1
- v0.AddArg(idx)
- v.AddArg(v0)
- v.AddArg(w0)
- v.AddArg(mem)
- return true
- }
- return false
-}
-func rewriteValueAMD64_OpAMD64MULL(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (MULL x (MOVLconst [c]))
- // cond:
- // result: (MULLconst [c] x)
- for {
- x := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64MOVLconst {
- break
- }
- c := v_1.AuxInt
- v.reset(OpAMD64MULLconst)
- v.AuxInt = c
+ v.reset(OpCopy)
+ v.Type = x.Type
v.AddArg(x)
return true
}
- // match: (MULL (MOVLconst [c]) x)
- // cond:
- // result: (MULLconst [c] x)
+ // match: (ORLconst [c] _)
+ // cond: int32(c)==-1
+ // result: (MOVLconst [-1])
for {
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64MOVLconst {
+ c := v.AuxInt
+ if !(int32(c) == -1) {
break
}
- c := v_0.AuxInt
- x := v.Args[1]
- v.reset(OpAMD64MULLconst)
- v.AuxInt = c
- v.AddArg(x)
+ v.reset(OpAMD64MOVLconst)
+ v.AuxInt = -1
return true
}
- return false
-}
-func rewriteValueAMD64_OpAMD64MULLconst(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (MULLconst [c] (MOVLconst [d]))
+ // match: (ORLconst [c] (MOVLconst [d]))
// cond:
- // result: (MOVLconst [int64(int32(c*d))])
+ // result: (MOVLconst [c|d])
for {
c := v.AuxInt
v_0 := v.Args[0]
@@ -11452,17 +11416,17 @@ func rewriteValueAMD64_OpAMD64MULLconst(v *Value, config *Config) bool {
}
d := v_0.AuxInt
v.reset(OpAMD64MOVLconst)
- v.AuxInt = int64(int32(c * d))
+ v.AuxInt = c | d
return true
}
return false
}
-func rewriteValueAMD64_OpAMD64MULQ(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpAMD64ORQ(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (MULQ x (MOVQconst [c]))
+ // match: (ORQ x (MOVQconst [c]))
// cond: is32Bit(c)
- // result: (MULQconst [c] x)
+ // result: (ORQconst [c] x)
for {
x := v.Args[0]
v_1 := v.Args[1]
@@ -11473,14 +11437,14 @@ func rewriteValueAMD64_OpAMD64MULQ(v *Value, config *Config) bool {
if !(is32Bit(c)) {
break
}
- v.reset(OpAMD64MULQconst)
+ v.reset(OpAMD64ORQconst)
v.AuxInt = c
v.AddArg(x)
return true
}
- // match: (MULQ (MOVQconst [c]) x)
+ // match: (ORQ (MOVQconst [c]) x)
// cond: is32Bit(c)
- // result: (MULQconst [c] x)
+ // result: (ORQconst [c] x)
for {
v_0 := v.Args[0]
if v_0.Op != OpAMD64MOVQconst {
@@ -11491,1517 +11455,458 @@ func rewriteValueAMD64_OpAMD64MULQ(v *Value, config *Config) bool {
if !(is32Bit(c)) {
break
}
- v.reset(OpAMD64MULQconst)
+ v.reset(OpAMD64ORQconst)
v.AuxInt = c
v.AddArg(x)
return true
}
- return false
-}
-func rewriteValueAMD64_OpAMD64MULQconst(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (MULQconst [-1] x)
+ // match: (ORQ x x)
// cond:
- // result: (NEGQ x)
+ // result: x
for {
- if v.AuxInt != -1 {
+ x := v.Args[0]
+ if x != v.Args[1] {
break
}
- x := v.Args[0]
- v.reset(OpAMD64NEGQ)
+ v.reset(OpCopy)
+ v.Type = x.Type
v.AddArg(x)
return true
}
- // match: (MULQconst [0] _)
- // cond:
- // result: (MOVQconst [0])
+ // match: (ORQ o0:(ORQ o1:(ORQ o2:(ORQ o3:(ORQ o4:(ORQ o5:(ORQ x0:(MOVBload [i] {s} p mem) s0:(SHLQconst [8] x1:(MOVBload [i+1] {s} p mem))) s1:(SHLQconst [16] x2:(MOVBload [i+2] {s} p mem))) s2:(SHLQconst [24] x3:(MOVBload [i+3] {s} p mem))) s3:(SHLQconst [32] x4:(MOVBload [i+4] {s} p mem))) s4:(SHLQconst [40] x5:(MOVBload [i+5] {s} p mem))) s5:(SHLQconst [48] x6:(MOVBload [i+6] {s} p mem))) s6:(SHLQconst [56] x7:(MOVBload [i+7] {s} [...]
+ // cond: x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && x3.Uses == 1 && x4.Uses == 1 && x5.Uses == 1 && x6.Uses == 1 && x7.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && s2.Uses == 1 && s3.Uses == 1 && s4.Uses == 1 && s5.Uses == 1 && s6.Uses == 1 && o0.Uses == 1 && o1.Uses == 1 && o2.Uses == 1 && o3.Uses == 1 && o4.Uses == 1 && o5.Uses == 1 && mergePoint(b,x0,x1,x2,x3,x4,x5,x6,x7) != nil && clobber(x0) && clobber(x1) && clobber(x2) && clo [...]
+ // result: @mergePoint(b,x0,x1,x2,x3,x4,x5,x6,x7) (MOVQload [i] {s} p mem)
for {
- if v.AuxInt != 0 {
+ o0 := v.Args[0]
+ if o0.Op != OpAMD64ORQ {
break
}
- v.reset(OpAMD64MOVQconst)
- v.AuxInt = 0
- return true
- }
- // match: (MULQconst [1] x)
- // cond:
- // result: x
- for {
- if v.AuxInt != 1 {
+ o1 := o0.Args[0]
+ if o1.Op != OpAMD64ORQ {
break
}
- x := v.Args[0]
- v.reset(OpCopy)
- v.Type = x.Type
- v.AddArg(x)
- return true
- }
- // match: (MULQconst [3] x)
- // cond:
- // result: (LEAQ2 x x)
- for {
- if v.AuxInt != 3 {
+ o2 := o1.Args[0]
+ if o2.Op != OpAMD64ORQ {
break
}
- x := v.Args[0]
- v.reset(OpAMD64LEAQ2)
- v.AddArg(x)
- v.AddArg(x)
- return true
- }
- // match: (MULQconst [5] x)
- // cond:
- // result: (LEAQ4 x x)
- for {
- if v.AuxInt != 5 {
+ o3 := o2.Args[0]
+ if o3.Op != OpAMD64ORQ {
break
}
- x := v.Args[0]
- v.reset(OpAMD64LEAQ4)
- v.AddArg(x)
- v.AddArg(x)
- return true
- }
- // match: (MULQconst [7] x)
- // cond:
- // result: (LEAQ8 (NEGQ <v.Type> x) x)
- for {
- if v.AuxInt != 7 {
+ o4 := o3.Args[0]
+ if o4.Op != OpAMD64ORQ {
break
}
- x := v.Args[0]
- v.reset(OpAMD64LEAQ8)
- v0 := b.NewValue0(v.Line, OpAMD64NEGQ, v.Type)
- v0.AddArg(x)
- v.AddArg(v0)
- v.AddArg(x)
- return true
- }
- // match: (MULQconst [9] x)
- // cond:
- // result: (LEAQ8 x x)
- for {
- if v.AuxInt != 9 {
+ o5 := o4.Args[0]
+ if o5.Op != OpAMD64ORQ {
break
}
- x := v.Args[0]
- v.reset(OpAMD64LEAQ8)
- v.AddArg(x)
- v.AddArg(x)
- return true
- }
- // match: (MULQconst [11] x)
- // cond:
- // result: (LEAQ2 x (LEAQ4 <v.Type> x x))
- for {
- if v.AuxInt != 11 {
+ x0 := o5.Args[0]
+ if x0.Op != OpAMD64MOVBload {
break
}
- x := v.Args[0]
- v.reset(OpAMD64LEAQ2)
- v.AddArg(x)
- v0 := b.NewValue0(v.Line, OpAMD64LEAQ4, v.Type)
- v0.AddArg(x)
- v0.AddArg(x)
- v.AddArg(v0)
- return true
- }
- // match: (MULQconst [13] x)
- // cond:
- // result: (LEAQ4 x (LEAQ2 <v.Type> x x))
- for {
- if v.AuxInt != 13 {
+ i := x0.AuxInt
+ s := x0.Aux
+ p := x0.Args[0]
+ mem := x0.Args[1]
+ s0 := o5.Args[1]
+ if s0.Op != OpAMD64SHLQconst {
break
}
- x := v.Args[0]
- v.reset(OpAMD64LEAQ4)
- v.AddArg(x)
- v0 := b.NewValue0(v.Line, OpAMD64LEAQ2, v.Type)
- v0.AddArg(x)
- v0.AddArg(x)
- v.AddArg(v0)
- return true
- }
- // match: (MULQconst [21] x)
- // cond:
- // result: (LEAQ4 x (LEAQ4 <v.Type> x x))
- for {
- if v.AuxInt != 21 {
+ if s0.AuxInt != 8 {
break
}
- x := v.Args[0]
- v.reset(OpAMD64LEAQ4)
- v.AddArg(x)
- v0 := b.NewValue0(v.Line, OpAMD64LEAQ4, v.Type)
- v0.AddArg(x)
- v0.AddArg(x)
- v.AddArg(v0)
- return true
- }
- // match: (MULQconst [25] x)
- // cond:
- // result: (LEAQ8 x (LEAQ2 <v.Type> x x))
- for {
- if v.AuxInt != 25 {
+ x1 := s0.Args[0]
+ if x1.Op != OpAMD64MOVBload {
break
}
- x := v.Args[0]
- v.reset(OpAMD64LEAQ8)
- v.AddArg(x)
- v0 := b.NewValue0(v.Line, OpAMD64LEAQ2, v.Type)
- v0.AddArg(x)
- v0.AddArg(x)
- v.AddArg(v0)
- return true
- }
- // match: (MULQconst [37] x)
- // cond:
- // result: (LEAQ4 x (LEAQ8 <v.Type> x x))
- for {
- if v.AuxInt != 37 {
+ if x1.AuxInt != i+1 {
break
}
- x := v.Args[0]
- v.reset(OpAMD64LEAQ4)
- v.AddArg(x)
- v0 := b.NewValue0(v.Line, OpAMD64LEAQ8, v.Type)
- v0.AddArg(x)
- v0.AddArg(x)
- v.AddArg(v0)
- return true
- }
- // match: (MULQconst [41] x)
- // cond:
- // result: (LEAQ8 x (LEAQ4 <v.Type> x x))
- for {
- if v.AuxInt != 41 {
+ if x1.Aux != s {
break
}
- x := v.Args[0]
- v.reset(OpAMD64LEAQ8)
- v.AddArg(x)
- v0 := b.NewValue0(v.Line, OpAMD64LEAQ4, v.Type)
- v0.AddArg(x)
- v0.AddArg(x)
- v.AddArg(v0)
- return true
- }
- // match: (MULQconst [73] x)
- // cond:
- // result: (LEAQ8 x (LEAQ8 <v.Type> x x))
- for {
- if v.AuxInt != 73 {
+ if p != x1.Args[0] {
break
}
- x := v.Args[0]
- v.reset(OpAMD64LEAQ8)
- v.AddArg(x)
- v0 := b.NewValue0(v.Line, OpAMD64LEAQ8, v.Type)
- v0.AddArg(x)
- v0.AddArg(x)
- v.AddArg(v0)
- return true
- }
- // match: (MULQconst [c] x)
- // cond: isPowerOfTwo(c)
- // result: (SHLQconst [log2(c)] x)
- for {
- c := v.AuxInt
- x := v.Args[0]
- if !(isPowerOfTwo(c)) {
+ if mem != x1.Args[1] {
break
}
- v.reset(OpAMD64SHLQconst)
- v.AuxInt = log2(c)
- v.AddArg(x)
- return true
- }
- // match: (MULQconst [c] x)
- // cond: isPowerOfTwo(c+1) && c >= 15
- // result: (SUBQ (SHLQconst <v.Type> [log2(c+1)] x) x)
- for {
- c := v.AuxInt
- x := v.Args[0]
- if !(isPowerOfTwo(c+1) && c >= 15) {
+ s1 := o4.Args[1]
+ if s1.Op != OpAMD64SHLQconst {
break
}
- v.reset(OpAMD64SUBQ)
- v0 := b.NewValue0(v.Line, OpAMD64SHLQconst, v.Type)
- v0.AuxInt = log2(c + 1)
- v0.AddArg(x)
- v.AddArg(v0)
- v.AddArg(x)
- return true
- }
- // match: (MULQconst [c] x)
- // cond: isPowerOfTwo(c-1) && c >= 17
- // result: (LEAQ1 (SHLQconst <v.Type> [log2(c-1)] x) x)
- for {
- c := v.AuxInt
- x := v.Args[0]
- if !(isPowerOfTwo(c-1) && c >= 17) {
+ if s1.AuxInt != 16 {
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) {
+ x2 := s1.Args[0]
+ if x2.Op != OpAMD64MOVBload {
break
}
- v.reset(OpAMD64LEAQ2)
- v0 := b.NewValue0(v.Line, OpAMD64SHLQconst, v.Type)
- v0.AuxInt = log2(c - 2)
- v0.AddArg(x)
- v.AddArg(v0)
- v.AddArg(x)
- return true
- }
- // match: (MULQconst [c] x)
- // cond: isPowerOfTwo(c-4) && c >= 68
- // result: (LEAQ4 (SHLQconst <v.Type> [log2(c-4)] x) x)
- for {
- c := v.AuxInt
- x := v.Args[0]
- if !(isPowerOfTwo(c-4) && c >= 68) {
+ if x2.AuxInt != i+2 {
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) {
+ if x2.Aux != s {
break
}
- v.reset(OpAMD64LEAQ8)
- v0 := b.NewValue0(v.Line, OpAMD64SHLQconst, v.Type)
- v0.AuxInt = log2(c - 8)
- v0.AddArg(x)
- v.AddArg(v0)
- v.AddArg(x)
- return true
- }
- // match: (MULQconst [c] x)
- // cond: c%3 == 0 && isPowerOfTwo(c/3)
- // result: (SHLQconst [log2(c/3)] (LEAQ2 <v.Type> x x))
- for {
- c := v.AuxInt
- x := v.Args[0]
- if !(c%3 == 0 && isPowerOfTwo(c/3)) {
+ if p != x2.Args[0] {
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)) {
+ if mem != x2.Args[1] {
break
}
- v.reset(OpAMD64SHLQconst)
- v.AuxInt = log2(c / 5)
- v0 := b.NewValue0(v.Line, OpAMD64LEAQ4, v.Type)
- v0.AddArg(x)
- v0.AddArg(x)
- v.AddArg(v0)
- return true
- }
- // match: (MULQconst [c] x)
- // cond: c%9 == 0 && isPowerOfTwo(c/9)
- // result: (SHLQconst [log2(c/9)] (LEAQ8 <v.Type> x x))
- for {
- c := v.AuxInt
- x := v.Args[0]
- if !(c%9 == 0 && isPowerOfTwo(c/9)) {
+ s2 := o3.Args[1]
+ if s2.Op != OpAMD64SHLQconst {
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 {
+ if s2.AuxInt != 24 {
break
}
- d := v_0.AuxInt
- v.reset(OpAMD64MOVQconst)
- v.AuxInt = c * d
- return true
- }
- return false
-}
-func rewriteValueAMD64_OpMod16(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Mod16 x y)
- // cond:
- // result: (MODW x y)
- for {
- x := v.Args[0]
- y := v.Args[1]
- v.reset(OpAMD64MODW)
- v.AddArg(x)
- v.AddArg(y)
- return true
- }
-}
-func rewriteValueAMD64_OpMod16u(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Mod16u x y)
- // cond:
- // result: (MODWU x y)
- for {
- x := v.Args[0]
- y := v.Args[1]
- v.reset(OpAMD64MODWU)
- v.AddArg(x)
- v.AddArg(y)
- return true
- }
-}
-func rewriteValueAMD64_OpMod32(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Mod32 x y)
- // cond:
- // result: (MODL x y)
- for {
- x := v.Args[0]
- y := v.Args[1]
- v.reset(OpAMD64MODL)
- v.AddArg(x)
- v.AddArg(y)
- return true
- }
-}
-func rewriteValueAMD64_OpMod32u(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Mod32u x y)
- // cond:
- // result: (MODLU x y)
- for {
- x := v.Args[0]
- y := v.Args[1]
- v.reset(OpAMD64MODLU)
- v.AddArg(x)
- v.AddArg(y)
- return true
- }
-}
-func rewriteValueAMD64_OpMod64(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Mod64 x y)
- // cond:
- // result: (MODQ x y)
- for {
- x := v.Args[0]
- y := v.Args[1]
- v.reset(OpAMD64MODQ)
- v.AddArg(x)
- v.AddArg(y)
- return true
- }
-}
-func rewriteValueAMD64_OpMod64u(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Mod64u x y)
- // cond:
- // result: (MODQU x y)
- for {
- x := v.Args[0]
- y := v.Args[1]
- v.reset(OpAMD64MODQU)
- v.AddArg(x)
- v.AddArg(y)
- return true
- }
-}
-func rewriteValueAMD64_OpMod8(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Mod8 x y)
- // cond:
- // result: (MODW (SignExt8to16 x) (SignExt8to16 y))
- for {
- x := v.Args[0]
- y := v.Args[1]
- v.reset(OpAMD64MODW)
- v0 := b.NewValue0(v.Line, OpSignExt8to16, config.fe.TypeInt16())
- v0.AddArg(x)
- v.AddArg(v0)
- v1 := b.NewValue0(v.Line, OpSignExt8to16, config.fe.TypeInt16())
- v1.AddArg(y)
- v.AddArg(v1)
- return true
- }
-}
-func rewriteValueAMD64_OpMod8u(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Mod8u x y)
- // cond:
- // result: (MODWU (ZeroExt8to16 x) (ZeroExt8to16 y))
- for {
- x := v.Args[0]
- y := v.Args[1]
- v.reset(OpAMD64MODWU)
- v0 := b.NewValue0(v.Line, OpZeroExt8to16, config.fe.TypeUInt16())
- v0.AddArg(x)
- v.AddArg(v0)
- v1 := b.NewValue0(v.Line, OpZeroExt8to16, config.fe.TypeUInt16())
- v1.AddArg(y)
- v.AddArg(v1)
- return true
- }
-}
-func rewriteValueAMD64_OpMove(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Move [0] _ _ mem)
- // cond:
- // result: mem
- for {
- if v.AuxInt != 0 {
+ x3 := s2.Args[0]
+ if x3.Op != OpAMD64MOVBload {
break
}
- mem := v.Args[2]
- v.reset(OpCopy)
- v.Type = mem.Type
- v.AddArg(mem)
- return true
- }
- // match: (Move [1] dst src mem)
- // cond:
- // result: (MOVBstore dst (MOVBload src mem) mem)
- for {
- if v.AuxInt != 1 {
+ if x3.AuxInt != i+3 {
break
}
- dst := v.Args[0]
- src := v.Args[1]
- mem := v.Args[2]
- v.reset(OpAMD64MOVBstore)
- v.AddArg(dst)
- v0 := b.NewValue0(v.Line, OpAMD64MOVBload, config.fe.TypeUInt8())
- v0.AddArg(src)
- v0.AddArg(mem)
- v.AddArg(v0)
- v.AddArg(mem)
- return true
- }
- // match: (Move [2] dst src mem)
- // cond:
- // result: (MOVWstore dst (MOVWload src mem) mem)
- for {
- if v.AuxInt != 2 {
+ if x3.Aux != s {
break
}
- dst := v.Args[0]
- src := v.Args[1]
- mem := v.Args[2]
- v.reset(OpAMD64MOVWstore)
- v.AddArg(dst)
- v0 := b.NewValue0(v.Line, OpAMD64MOVWload, config.fe.TypeUInt16())
- v0.AddArg(src)
- v0.AddArg(mem)
- v.AddArg(v0)
- v.AddArg(mem)
- return true
- }
- // match: (Move [4] dst src mem)
- // cond:
- // result: (MOVLstore dst (MOVLload src mem) mem)
- for {
- if v.AuxInt != 4 {
+ if p != x3.Args[0] {
break
}
- dst := v.Args[0]
- src := v.Args[1]
- mem := v.Args[2]
- v.reset(OpAMD64MOVLstore)
- v.AddArg(dst)
- v0 := b.NewValue0(v.Line, OpAMD64MOVLload, config.fe.TypeUInt32())
- v0.AddArg(src)
- v0.AddArg(mem)
- v.AddArg(v0)
- v.AddArg(mem)
- return true
- }
- // match: (Move [8] dst src mem)
- // cond:
- // result: (MOVQstore dst (MOVQload src mem) mem)
- for {
- if v.AuxInt != 8 {
+ if mem != x3.Args[1] {
break
}
- dst := v.Args[0]
- src := v.Args[1]
- mem := v.Args[2]
- v.reset(OpAMD64MOVQstore)
- v.AddArg(dst)
- v0 := b.NewValue0(v.Line, OpAMD64MOVQload, config.fe.TypeUInt64())
- v0.AddArg(src)
- v0.AddArg(mem)
- v.AddArg(v0)
- v.AddArg(mem)
- return true
- }
- // match: (Move [16] dst src mem)
- // cond:
- // result: (MOVOstore dst (MOVOload src mem) mem)
- for {
- if v.AuxInt != 16 {
+ s3 := o2.Args[1]
+ if s3.Op != OpAMD64SHLQconst {
break
}
- dst := v.Args[0]
- src := v.Args[1]
- mem := v.Args[2]
- v.reset(OpAMD64MOVOstore)
- v.AddArg(dst)
- v0 := b.NewValue0(v.Line, OpAMD64MOVOload, TypeInt128)
- v0.AddArg(src)
- v0.AddArg(mem)
- v.AddArg(v0)
- v.AddArg(mem)
- return true
- }
- // match: (Move [3] dst src mem)
- // cond:
- // result: (MOVBstore [2] dst (MOVBload [2] src mem) (MOVWstore dst (MOVWload src mem) mem))
- for {
- if v.AuxInt != 3 {
+ if s3.AuxInt != 32 {
break
}
- dst := v.Args[0]
- src := v.Args[1]
- mem := v.Args[2]
- v.reset(OpAMD64MOVBstore)
- v.AuxInt = 2
- v.AddArg(dst)
- v0 := b.NewValue0(v.Line, OpAMD64MOVBload, config.fe.TypeUInt8())
- v0.AuxInt = 2
- v0.AddArg(src)
- v0.AddArg(mem)
- v.AddArg(v0)
- v1 := b.NewValue0(v.Line, OpAMD64MOVWstore, TypeMem)
- v1.AddArg(dst)
- v2 := b.NewValue0(v.Line, OpAMD64MOVWload, config.fe.TypeUInt16())
- v2.AddArg(src)
- v2.AddArg(mem)
- v1.AddArg(v2)
- v1.AddArg(mem)
- v.AddArg(v1)
- return true
- }
- // match: (Move [5] dst src mem)
- // cond:
- // result: (MOVBstore [4] dst (MOVBload [4] src mem) (MOVLstore dst (MOVLload src mem) mem))
- for {
- if v.AuxInt != 5 {
+ x4 := s3.Args[0]
+ if x4.Op != OpAMD64MOVBload {
break
}
- dst := v.Args[0]
- src := v.Args[1]
- mem := v.Args[2]
- v.reset(OpAMD64MOVBstore)
- v.AuxInt = 4
- v.AddArg(dst)
- v0 := b.NewValue0(v.Line, OpAMD64MOVBload, config.fe.TypeUInt8())
- v0.AuxInt = 4
- v0.AddArg(src)
- v0.AddArg(mem)
- v.AddArg(v0)
- v1 := b.NewValue0(v.Line, OpAMD64MOVLstore, TypeMem)
- v1.AddArg(dst)
- v2 := b.NewValue0(v.Line, OpAMD64MOVLload, config.fe.TypeUInt32())
- v2.AddArg(src)
- v2.AddArg(mem)
- v1.AddArg(v2)
- v1.AddArg(mem)
- v.AddArg(v1)
- return true
- }
- // match: (Move [6] dst src mem)
- // cond:
- // result: (MOVWstore [4] dst (MOVWload [4] src mem) (MOVLstore dst (MOVLload src mem) mem))
- for {
- if v.AuxInt != 6 {
+ if x4.AuxInt != i+4 {
break
}
- dst := v.Args[0]
- src := v.Args[1]
- mem := v.Args[2]
- v.reset(OpAMD64MOVWstore)
- v.AuxInt = 4
- v.AddArg(dst)
- v0 := b.NewValue0(v.Line, OpAMD64MOVWload, config.fe.TypeUInt16())
- v0.AuxInt = 4
- v0.AddArg(src)
- v0.AddArg(mem)
- v.AddArg(v0)
- v1 := b.NewValue0(v.Line, OpAMD64MOVLstore, TypeMem)
- v1.AddArg(dst)
- v2 := b.NewValue0(v.Line, OpAMD64MOVLload, config.fe.TypeUInt32())
- v2.AddArg(src)
- v2.AddArg(mem)
- v1.AddArg(v2)
- v1.AddArg(mem)
- v.AddArg(v1)
- return true
- }
- // match: (Move [7] dst src mem)
- // cond:
- // result: (MOVLstore [3] dst (MOVLload [3] src mem) (MOVLstore dst (MOVLload src mem) mem))
- for {
- if v.AuxInt != 7 {
+ if x4.Aux != s {
break
}
- dst := v.Args[0]
- src := v.Args[1]
- mem := v.Args[2]
- v.reset(OpAMD64MOVLstore)
- v.AuxInt = 3
- v.AddArg(dst)
- v0 := b.NewValue0(v.Line, OpAMD64MOVLload, config.fe.TypeUInt32())
- v0.AuxInt = 3
- v0.AddArg(src)
- v0.AddArg(mem)
- v.AddArg(v0)
- v1 := b.NewValue0(v.Line, OpAMD64MOVLstore, TypeMem)
- v1.AddArg(dst)
- v2 := b.NewValue0(v.Line, OpAMD64MOVLload, config.fe.TypeUInt32())
- v2.AddArg(src)
- v2.AddArg(mem)
- v1.AddArg(v2)
- v1.AddArg(mem)
- v.AddArg(v1)
- return true
- }
- // match: (Move [size] dst src mem)
- // cond: size > 8 && size < 16
- // result: (MOVQstore [size-8] dst (MOVQload [size-8] src mem) (MOVQstore dst (MOVQload src mem) mem))
- for {
- size := v.AuxInt
- dst := v.Args[0]
- src := v.Args[1]
- mem := v.Args[2]
- if !(size > 8 && size < 16) {
+ if p != x4.Args[0] {
break
}
- v.reset(OpAMD64MOVQstore)
- v.AuxInt = size - 8
- v.AddArg(dst)
+ if mem != x4.Args[1] {
+ break
+ }
+ s4 := o1.Args[1]
+ if s4.Op != OpAMD64SHLQconst {
+ break
+ }
+ if s4.AuxInt != 40 {
+ break
+ }
+ x5 := s4.Args[0]
+ if x5.Op != OpAMD64MOVBload {
+ break
+ }
+ if x5.AuxInt != i+5 {
+ break
+ }
+ if x5.Aux != s {
+ break
+ }
+ if p != x5.Args[0] {
+ break
+ }
+ if mem != x5.Args[1] {
+ break
+ }
+ s5 := o0.Args[1]
+ if s5.Op != OpAMD64SHLQconst {
+ break
+ }
+ if s5.AuxInt != 48 {
+ break
+ }
+ x6 := s5.Args[0]
+ if x6.Op != OpAMD64MOVBload {
+ break
+ }
+ if x6.AuxInt != i+6 {
+ break
+ }
+ if x6.Aux != s {
+ break
+ }
+ if p != x6.Args[0] {
+ break
+ }
+ if mem != x6.Args[1] {
+ break
+ }
+ s6 := v.Args[1]
+ if s6.Op != OpAMD64SHLQconst {
+ break
+ }
+ if s6.AuxInt != 56 {
+ break
+ }
+ x7 := s6.Args[0]
+ if x7.Op != OpAMD64MOVBload {
+ break
+ }
+ if x7.AuxInt != i+7 {
+ break
+ }
+ if x7.Aux != s {
+ break
+ }
+ if p != x7.Args[0] {
+ break
+ }
+ if mem != x7.Args[1] {
+ break
+ }
+ if !(x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && x3.Uses == 1 && x4.Uses == 1 && x5.Uses == 1 && x6.Uses == 1 && x7.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && s2.Uses == 1 && s3.Uses == 1 && s4.Uses == 1 && s5.Uses == 1 && s6.Uses == 1 && o0.Uses == 1 && o1.Uses == 1 && o2.Uses == 1 && o3.Uses == 1 && o4.Uses == 1 && o5.Uses == 1 && mergePoint(b, x0, x1, x2, x3, x4, x5, x6, x7) != nil && clobber(x0) && clobber(x1) && clobber(x2) && clobber(x3) && clobber(x4) && clobber(x5) && clo [...]
+ break
+ }
+ b = mergePoint(b, x0, x1, x2, x3, x4, x5, x6, x7)
v0 := b.NewValue0(v.Line, OpAMD64MOVQload, config.fe.TypeUInt64())
- v0.AuxInt = size - 8
- v0.AddArg(src)
- v0.AddArg(mem)
+ 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)
- v2.AddArg(mem)
- v1.AddArg(v2)
- v1.AddArg(mem)
- v.AddArg(v1)
+ v0.AuxInt = i
+ v0.Aux = s
+ v0.AddArg(p)
+ v0.AddArg(mem)
return true
}
- // match: (Move [size] dst src mem)
- // cond: size > 16 && size%16 != 0 && size%16 <= 8
- // result: (Move [size-size%16] (ADDQconst <dst.Type> dst [size%16]) (ADDQconst <src.Type> src [size%16]) (MOVQstore dst (MOVQload src mem) mem))
+ // match: (ORQ o0:(ORQ o1:(ORQ o2:(ORQ o3:(ORQ o4:(ORQ o5:(ORQ x0:(MOVBloadidx1 [i] {s} p idx mem) s0:(SHLQconst [8] x1:(MOVBloadidx1 [i+1] {s} p idx mem))) s1:(SHLQconst [16] x2:(MOVBloadidx1 [i+2] {s} p idx mem))) s2:(SHLQconst [24] x3:(MOVBloadidx1 [i+3] {s} p idx mem))) s3:(SHLQconst [32] x4:(MOVBloadidx1 [i+4] {s} p idx mem))) s4:(SHLQconst [40] x5:(MOVBloadidx1 [i+5] {s} p idx mem))) s5:(SHLQconst [48] x6:(MOVBloadidx1 [i+6] {s} p [...]
+ // cond: x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && x3.Uses == 1 && x4.Uses == 1 && x5.Uses == 1 && x6.Uses == 1 && x7.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && s2.Uses == 1 && s3.Uses == 1 && s4.Uses == 1 && s5.Uses == 1 && s6.Uses == 1 && o0.Uses == 1 && o1.Uses == 1 && o2.Uses == 1 && o3.Uses == 1 && o4.Uses == 1 && o5.Uses == 1 && mergePoint(b,x0,x1,x2,x3,x4,x5,x6,x7) != nil && clobber(x0) && clobber(x1) && clobber(x2) && clo [...]
+ // result: @mergePoint(b,x0,x1,x2,x3,x4,x5,x6,x7) (MOVQloadidx1 <v.Type> [i] {s} p idx mem)
for {
- size := v.AuxInt
- dst := v.Args[0]
- src := v.Args[1]
- mem := v.Args[2]
- if !(size > 16 && size%16 != 0 && size%16 <= 8) {
+ o0 := v.Args[0]
+ if o0.Op != OpAMD64ORQ {
break
}
- v.reset(OpMove)
- v.AuxInt = size - size%16
- v0 := b.NewValue0(v.Line, OpAMD64ADDQconst, dst.Type)
- v0.AddArg(dst)
- v0.AuxInt = size % 16
- v.AddArg(v0)
- v1 := b.NewValue0(v.Line, OpAMD64ADDQconst, src.Type)
- v1.AddArg(src)
- v1.AuxInt = size % 16
- v.AddArg(v1)
- v2 := b.NewValue0(v.Line, OpAMD64MOVQstore, TypeMem)
- v2.AddArg(dst)
- v3 := b.NewValue0(v.Line, OpAMD64MOVQload, config.fe.TypeUInt64())
- v3.AddArg(src)
- v3.AddArg(mem)
- v2.AddArg(v3)
- v2.AddArg(mem)
- v.AddArg(v2)
- return true
- }
- // match: (Move [size] dst src mem)
- // cond: size > 16 && size%16 != 0 && size%16 > 8
- // result: (Move [size-size%16] (ADDQconst <dst.Type> dst [size%16]) (ADDQconst <src.Type> src [size%16]) (MOVOstore dst (MOVOload src mem) mem))
- for {
- size := v.AuxInt
- dst := v.Args[0]
- src := v.Args[1]
- mem := v.Args[2]
- if !(size > 16 && size%16 != 0 && size%16 > 8) {
+ o1 := o0.Args[0]
+ if o1.Op != OpAMD64ORQ {
break
}
- v.reset(OpMove)
- v.AuxInt = size - size%16
- v0 := b.NewValue0(v.Line, OpAMD64ADDQconst, dst.Type)
- v0.AddArg(dst)
- v0.AuxInt = size % 16
- v.AddArg(v0)
- v1 := b.NewValue0(v.Line, OpAMD64ADDQconst, src.Type)
- v1.AddArg(src)
- v1.AuxInt = size % 16
- v.AddArg(v1)
- v2 := b.NewValue0(v.Line, OpAMD64MOVOstore, TypeMem)
- v2.AddArg(dst)
- v3 := b.NewValue0(v.Line, OpAMD64MOVOload, TypeInt128)
- v3.AddArg(src)
- v3.AddArg(mem)
- v2.AddArg(v3)
- v2.AddArg(mem)
- v.AddArg(v2)
- return true
- }
- // match: (Move [size] dst src mem)
- // cond: size >= 32 && size <= 16*64 && size%16 == 0 && !config.noDuffDevice
- // result: (DUFFCOPY [14*(64-size/16)] dst src mem)
- for {
- size := v.AuxInt
- dst := v.Args[0]
- src := v.Args[1]
- mem := v.Args[2]
- if !(size >= 32 && size <= 16*64 && size%16 == 0 && !config.noDuffDevice) {
+ o2 := o1.Args[0]
+ if o2.Op != OpAMD64ORQ {
break
}
- v.reset(OpAMD64DUFFCOPY)
- v.AuxInt = 14 * (64 - size/16)
- v.AddArg(dst)
- v.AddArg(src)
- v.AddArg(mem)
- return true
- }
- // match: (Move [size] dst src mem)
- // cond: (size > 16*64 || config.noDuffDevice) && size%8 == 0
- // result: (REPMOVSQ dst src (MOVQconst [size/8]) mem)
- for {
- size := v.AuxInt
- dst := v.Args[0]
- src := v.Args[1]
- mem := v.Args[2]
- if !((size > 16*64 || config.noDuffDevice) && size%8 == 0) {
+ o3 := o2.Args[0]
+ if o3.Op != OpAMD64ORQ {
break
}
- v.reset(OpAMD64REPMOVSQ)
- v.AddArg(dst)
- v.AddArg(src)
- v0 := b.NewValue0(v.Line, OpAMD64MOVQconst, config.fe.TypeUInt64())
- v0.AuxInt = size / 8
- v.AddArg(v0)
- v.AddArg(mem)
- return true
- }
- return false
-}
-func rewriteValueAMD64_OpMul16(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Mul16 x y)
- // cond:
- // result: (MULL x y)
- for {
- x := v.Args[0]
- y := v.Args[1]
- v.reset(OpAMD64MULL)
- v.AddArg(x)
- v.AddArg(y)
- return true
- }
-}
-func rewriteValueAMD64_OpMul32(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Mul32 x y)
- // cond:
- // result: (MULL x y)
- for {
- x := v.Args[0]
- y := v.Args[1]
- v.reset(OpAMD64MULL)
- v.AddArg(x)
- v.AddArg(y)
- return true
- }
-}
-func rewriteValueAMD64_OpMul32F(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Mul32F x y)
- // cond:
- // result: (MULSS x y)
- for {
- x := v.Args[0]
- y := v.Args[1]
- v.reset(OpAMD64MULSS)
- v.AddArg(x)
- v.AddArg(y)
- return true
- }
-}
-func rewriteValueAMD64_OpMul64(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Mul64 x y)
- // cond:
- // result: (MULQ x y)
- for {
- x := v.Args[0]
- y := v.Args[1]
- v.reset(OpAMD64MULQ)
- v.AddArg(x)
- v.AddArg(y)
- return true
- }
-}
-func rewriteValueAMD64_OpMul64F(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Mul64F x y)
- // cond:
- // result: (MULSD x y)
- for {
- x := v.Args[0]
- y := v.Args[1]
- v.reset(OpAMD64MULSD)
- v.AddArg(x)
- v.AddArg(y)
- return true
- }
-}
-func rewriteValueAMD64_OpMul8(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Mul8 x y)
- // cond:
- // result: (MULL x y)
- for {
- x := v.Args[0]
- y := v.Args[1]
- v.reset(OpAMD64MULL)
- v.AddArg(x)
- v.AddArg(y)
- return true
- }
-}
-func rewriteValueAMD64_OpAMD64NEGL(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (NEGL (MOVLconst [c]))
- // cond:
- // result: (MOVLconst [int64(int32(-c))])
- for {
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64MOVLconst {
+ o4 := o3.Args[0]
+ if o4.Op != OpAMD64ORQ {
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 {
+ o5 := o4.Args[0]
+ if o5.Op != OpAMD64ORQ {
break
}
- c := v_0.AuxInt
- v.reset(OpAMD64MOVQconst)
- v.AuxInt = -c
- return true
- }
- return false
-}
-func rewriteValueAMD64_OpAMD64NOTL(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (NOTL (MOVLconst [c]))
- // cond:
- // result: (MOVLconst [^c])
- for {
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64MOVLconst {
+ x0 := o5.Args[0]
+ if x0.Op != OpAMD64MOVBloadidx1 {
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 {
+ i := x0.AuxInt
+ s := x0.Aux
+ p := x0.Args[0]
+ idx := x0.Args[1]
+ mem := x0.Args[2]
+ s0 := o5.Args[1]
+ if s0.Op != OpAMD64SHLQconst {
break
}
- c := v_0.AuxInt
- v.reset(OpAMD64MOVQconst)
- v.AuxInt = ^c
- return true
- }
- return false
-}
-func rewriteValueAMD64_OpNeg16(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Neg16 x)
- // cond:
- // result: (NEGL x)
- for {
- x := v.Args[0]
- v.reset(OpAMD64NEGL)
- v.AddArg(x)
- return true
- }
-}
-func rewriteValueAMD64_OpNeg32(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Neg32 x)
- // cond:
- // result: (NEGL x)
- for {
- x := v.Args[0]
- v.reset(OpAMD64NEGL)
- v.AddArg(x)
- return true
- }
-}
-func rewriteValueAMD64_OpNeg32F(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Neg32F x)
- // cond:
- // result: (PXOR x (MOVSSconst <config.Frontend().TypeFloat32()> [f2i(math.Copysign(0, -1))]))
- for {
- x := v.Args[0]
- v.reset(OpAMD64PXOR)
- v.AddArg(x)
- v0 := b.NewValue0(v.Line, OpAMD64MOVSSconst, config.Frontend().TypeFloat32())
- v0.AuxInt = f2i(math.Copysign(0, -1))
- v.AddArg(v0)
- return true
- }
-}
-func rewriteValueAMD64_OpNeg64(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Neg64 x)
- // cond:
- // result: (NEGQ x)
- for {
- x := v.Args[0]
- v.reset(OpAMD64NEGQ)
- v.AddArg(x)
- return true
- }
-}
-func rewriteValueAMD64_OpNeg64F(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Neg64F x)
- // cond:
- // result: (PXOR x (MOVSDconst <config.Frontend().TypeFloat64()> [f2i(math.Copysign(0, -1))]))
- for {
- x := v.Args[0]
- v.reset(OpAMD64PXOR)
- v.AddArg(x)
- v0 := b.NewValue0(v.Line, OpAMD64MOVSDconst, config.Frontend().TypeFloat64())
- v0.AuxInt = f2i(math.Copysign(0, -1))
- v.AddArg(v0)
- return true
- }
-}
-func rewriteValueAMD64_OpNeg8(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Neg8 x)
- // cond:
- // result: (NEGL x)
- for {
- x := v.Args[0]
- v.reset(OpAMD64NEGL)
- v.AddArg(x)
- return true
- }
-}
-func rewriteValueAMD64_OpNeq16(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Neq16 x y)
- // cond:
- // result: (SETNE (CMPW x y))
- for {
- x := v.Args[0]
- y := v.Args[1]
- v.reset(OpAMD64SETNE)
- v0 := b.NewValue0(v.Line, OpAMD64CMPW, TypeFlags)
- v0.AddArg(x)
- v0.AddArg(y)
- v.AddArg(v0)
- return true
- }
-}
-func rewriteValueAMD64_OpNeq32(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Neq32 x y)
- // cond:
- // result: (SETNE (CMPL x y))
- for {
- x := v.Args[0]
- y := v.Args[1]
- v.reset(OpAMD64SETNE)
- v0 := b.NewValue0(v.Line, OpAMD64CMPL, TypeFlags)
- v0.AddArg(x)
- v0.AddArg(y)
- v.AddArg(v0)
- return true
- }
-}
-func rewriteValueAMD64_OpNeq32F(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Neq32F x y)
- // cond:
- // result: (SETNEF (UCOMISS x y))
- for {
- x := v.Args[0]
- y := v.Args[1]
- v.reset(OpAMD64SETNEF)
- v0 := b.NewValue0(v.Line, OpAMD64UCOMISS, TypeFlags)
- v0.AddArg(x)
- v0.AddArg(y)
- v.AddArg(v0)
- return true
- }
-}
-func rewriteValueAMD64_OpNeq64(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Neq64 x y)
- // cond:
- // result: (SETNE (CMPQ x y))
- for {
- x := v.Args[0]
- y := v.Args[1]
- v.reset(OpAMD64SETNE)
- v0 := b.NewValue0(v.Line, OpAMD64CMPQ, TypeFlags)
- v0.AddArg(x)
- v0.AddArg(y)
- v.AddArg(v0)
- return true
- }
-}
-func rewriteValueAMD64_OpNeq64F(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Neq64F x y)
- // cond:
- // result: (SETNEF (UCOMISD x y))
- for {
- x := v.Args[0]
- y := v.Args[1]
- v.reset(OpAMD64SETNEF)
- v0 := b.NewValue0(v.Line, OpAMD64UCOMISD, TypeFlags)
- v0.AddArg(x)
- v0.AddArg(y)
- v.AddArg(v0)
- return true
- }
-}
-func rewriteValueAMD64_OpNeq8(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Neq8 x y)
- // cond:
- // result: (SETNE (CMPB x y))
- for {
- x := v.Args[0]
- y := v.Args[1]
- v.reset(OpAMD64SETNE)
- v0 := b.NewValue0(v.Line, OpAMD64CMPB, TypeFlags)
- v0.AddArg(x)
- v0.AddArg(y)
- v.AddArg(v0)
- return true
- }
-}
-func rewriteValueAMD64_OpNeqB(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (NeqB x y)
- // cond:
- // result: (SETNE (CMPB x y))
- for {
- x := v.Args[0]
- y := v.Args[1]
- v.reset(OpAMD64SETNE)
- v0 := b.NewValue0(v.Line, OpAMD64CMPB, TypeFlags)
- v0.AddArg(x)
- v0.AddArg(y)
- v.AddArg(v0)
- return true
- }
-}
-func rewriteValueAMD64_OpNeqPtr(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (NeqPtr x y)
- // cond:
- // result: (SETNE (CMPQ x y))
- for {
- x := v.Args[0]
- y := v.Args[1]
- v.reset(OpAMD64SETNE)
- v0 := b.NewValue0(v.Line, OpAMD64CMPQ, TypeFlags)
- v0.AddArg(x)
- v0.AddArg(y)
- v.AddArg(v0)
- return true
- }
-}
-func rewriteValueAMD64_OpNilCheck(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (NilCheck ptr mem)
- // cond:
- // result: (LoweredNilCheck ptr mem)
- for {
- ptr := v.Args[0]
- mem := v.Args[1]
- v.reset(OpAMD64LoweredNilCheck)
- v.AddArg(ptr)
- v.AddArg(mem)
- return true
- }
-}
-func rewriteValueAMD64_OpNot(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Not x)
- // cond:
- // result: (XORLconst [1] x)
- for {
- x := v.Args[0]
- v.reset(OpAMD64XORLconst)
- v.AuxInt = 1
- v.AddArg(x)
- return true
- }
-}
-func rewriteValueAMD64_OpAMD64ORL(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (ORL x (MOVLconst [c]))
- // cond:
- // result: (ORLconst [c] x)
- for {
- x := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64MOVLconst {
+ if s0.AuxInt != 8 {
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 {
+ x1 := s0.Args[0]
+ if x1.Op != OpAMD64MOVBloadidx1 {
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] {
+ if x1.AuxInt != i+1 {
break
}
- v.reset(OpCopy)
- v.Type = x.Type
- v.AddArg(x)
- return true
- }
- // match: (ORL x0:(MOVBload [i] {s} p mem) s0:(SHLLconst [8] x1:(MOVBload [i+1] {s} p mem)))
- // cond: x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && mergePoint(b,x0,x1) != nil && clobber(x0) && clobber(x1) && clobber(s0)
- // result: @mergePoint(b,x0,x1) (MOVWload [i] {s} p mem)
- for {
- x0 := v.Args[0]
- if x0.Op != OpAMD64MOVBload {
+ if x1.Aux != s {
break
}
- i := x0.AuxInt
- s := x0.Aux
- p := x0.Args[0]
- mem := x0.Args[1]
- s0 := v.Args[1]
- if s0.Op != OpAMD64SHLLconst {
+ if p != x1.Args[0] {
break
}
- if s0.AuxInt != 8 {
+ if idx != x1.Args[1] {
break
}
- x1 := s0.Args[0]
- if x1.Op != OpAMD64MOVBload {
+ if mem != x1.Args[2] {
break
}
- if x1.AuxInt != i+1 {
+ s1 := o4.Args[1]
+ if s1.Op != OpAMD64SHLQconst {
break
}
- if x1.Aux != s {
+ if s1.AuxInt != 16 {
break
}
- if p != x1.Args[0] {
+ x2 := s1.Args[0]
+ if x2.Op != OpAMD64MOVBloadidx1 {
break
}
- if mem != x1.Args[1] {
+ if x2.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 x2.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 o1:(ORL x0:(MOVBload [i] {s} p mem) s0:(SHLLconst [8] x1:(MOVBload [i+1] {s} p mem))) s1:(SHLLconst [16] x2:(MOVBload [i+2] {s} p mem))) s2:(SHLLconst [24] x3:(MOVBload [i+3] {s} p mem)))
- // cond: x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && x3.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && s2.Uses == 1 && o0.Uses == 1 && o1.Uses == 1 && mergePoint(b,x0,x1,x2,x3) != nil && clobber(x0) && clobber(x1) && clobber(x2) && clobber(x3) && clobber(s0) && clobber(s1) && clobber(s2) && clobber(o0) && clobber(o1)
- // result: @mergePoint(b,x0,x1,x2,x3) (MOVLload [i] {s} p mem)
- for {
- o0 := v.Args[0]
- if o0.Op != OpAMD64ORL {
+ if p != x2.Args[0] {
break
}
- o1 := o0.Args[0]
- if o1.Op != OpAMD64ORL {
+ if idx != x2.Args[1] {
break
}
- x0 := o1.Args[0]
- if x0.Op != OpAMD64MOVBload {
+ if mem != x2.Args[2] {
break
}
- i := x0.AuxInt
- s := x0.Aux
- p := x0.Args[0]
- mem := x0.Args[1]
- s0 := o1.Args[1]
- if s0.Op != OpAMD64SHLLconst {
+ s2 := o3.Args[1]
+ if s2.Op != OpAMD64SHLQconst {
break
}
- if s0.AuxInt != 8 {
+ if s2.AuxInt != 24 {
break
}
- x1 := s0.Args[0]
- if x1.Op != OpAMD64MOVBload {
+ x3 := s2.Args[0]
+ if x3.Op != OpAMD64MOVBloadidx1 {
break
}
- if x1.AuxInt != i+1 {
+ if x3.AuxInt != i+3 {
break
}
- if x1.Aux != s {
+ if x3.Aux != s {
break
}
- if p != x1.Args[0] {
+ if p != x3.Args[0] {
break
}
- if mem != x1.Args[1] {
+ if idx != x3.Args[1] {
break
}
- s1 := o0.Args[1]
- if s1.Op != OpAMD64SHLLconst {
+ if mem != x3.Args[2] {
break
}
- if s1.AuxInt != 16 {
+ s3 := o2.Args[1]
+ if s3.Op != OpAMD64SHLQconst {
break
}
- x2 := s1.Args[0]
- if x2.Op != OpAMD64MOVBload {
+ if s3.AuxInt != 32 {
break
}
- if x2.AuxInt != i+2 {
+ x4 := s3.Args[0]
+ if x4.Op != OpAMD64MOVBloadidx1 {
break
}
- if x2.Aux != s {
+ if x4.AuxInt != i+4 {
break
}
- if p != x2.Args[0] {
+ if x4.Aux != s {
break
}
- if mem != x2.Args[1] {
+ if p != x4.Args[0] {
break
}
- s2 := v.Args[1]
- if s2.Op != OpAMD64SHLLconst {
+ if idx != x4.Args[1] {
break
}
- if s2.AuxInt != 24 {
+ if mem != x4.Args[2] {
break
}
- x3 := s2.Args[0]
- if x3.Op != OpAMD64MOVBload {
+ s4 := o1.Args[1]
+ if s4.Op != OpAMD64SHLQconst {
break
}
- if x3.AuxInt != i+3 {
+ if s4.AuxInt != 40 {
break
}
- if x3.Aux != s {
+ x5 := s4.Args[0]
+ if x5.Op != OpAMD64MOVBloadidx1 {
break
}
- if p != x3.Args[0] {
+ if x5.AuxInt != i+5 {
break
}
- if mem != x3.Args[1] {
+ if x5.Aux != s {
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)) {
+ if p != x5.Args[0] {
break
}
- b = mergePoint(b, x0, x1, x2, x3)
- v0 := b.NewValue0(v.Line, OpAMD64MOVLload, config.fe.TypeUInt32())
- v.reset(OpCopy)
- v.AddArg(v0)
- v0.AuxInt = i
- v0.Aux = s
- v0.AddArg(p)
- v0.AddArg(mem)
- return true
- }
- // match: (ORL x0:(MOVBloadidx1 [i] {s} p idx mem) s0:(SHLLconst [8] x1:(MOVBloadidx1 [i+1] {s} p idx mem)))
- // cond: x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && mergePoint(b,x0,x1) != nil && clobber(x0) && clobber(x1) && clobber(s0)
- // result: @mergePoint(b,x0,x1) (MOVWloadidx1 <v.Type> [i] {s} p idx mem)
- for {
- x0 := v.Args[0]
- if x0.Op != OpAMD64MOVBloadidx1 {
+ if idx != x5.Args[1] {
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 {
+ if mem != x5.Args[2] {
break
}
- if s0.AuxInt != 8 {
+ s5 := o0.Args[1]
+ if s5.Op != OpAMD64SHLQconst {
break
}
- x1 := s0.Args[0]
- if x1.Op != OpAMD64MOVBloadidx1 {
+ if s5.AuxInt != 48 {
break
}
- if x1.AuxInt != i+1 {
+ x6 := s5.Args[0]
+ if x6.Op != OpAMD64MOVBloadidx1 {
break
}
- if x1.Aux != s {
+ if x6.AuxInt != i+6 {
break
}
- if p != x1.Args[0] {
+ if x6.Aux != s {
break
}
- if idx != x1.Args[1] {
+ if p != x6.Args[0] {
break
}
- if mem != x1.Args[2] {
+ if idx != x6.Args[1] {
break
}
- if !(x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0)) {
+ if mem != x6.Args[2] {
break
}
- b = mergePoint(b, x0, x1)
- v0 := b.NewValue0(v.Line, OpAMD64MOVWloadidx1, v.Type)
+ s6 := v.Args[1]
+ if s6.Op != OpAMD64SHLQconst {
+ break
+ }
+ if s6.AuxInt != 56 {
+ break
+ }
+ x7 := s6.Args[0]
+ if x7.Op != OpAMD64MOVBloadidx1 {
+ break
+ }
+ if x7.AuxInt != i+7 {
+ break
+ }
+ if x7.Aux != s {
+ break
+ }
+ if p != x7.Args[0] {
+ break
+ }
+ if idx != x7.Args[1] {
+ break
+ }
+ if mem != x7.Args[2] {
+ break
+ }
+ if !(x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && x3.Uses == 1 && x4.Uses == 1 && x5.Uses == 1 && x6.Uses == 1 && x7.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && s2.Uses == 1 && s3.Uses == 1 && s4.Uses == 1 && s5.Uses == 1 && s6.Uses == 1 && o0.Uses == 1 && o1.Uses == 1 && o2.Uses == 1 && o3.Uses == 1 && o4.Uses == 1 && o5.Uses == 1 && mergePoint(b, x0, x1, x2, x3, x4, x5, x6, x7) != nil && clobber(x0) && clobber(x1) && clobber(x2) && clobber(x3) && clobber(x4) && clobber(x5) && clo [...]
+ break
+ }
+ b = mergePoint(b, x0, x1, x2, x3, x4, x5, x6, x7)
+ v0 := b.NewValue0(v.Line, OpAMD64MOVQloadidx1, v.Type)
v.reset(OpCopy)
v.AddArg(v0)
v0.AuxInt = i
@@ -13011,39 +11916,54 @@ func rewriteValueAMD64_OpAMD64ORL(v *Value, config *Config) bool {
v0.AddArg(mem)
return true
}
- // match: (ORL o0:(ORL o1:(ORL x0:(MOVBloadidx1 [i] {s} p idx mem) s0:(SHLLconst [8] x1:(MOVBloadidx1 [i+1] {s} p idx mem))) s1:(SHLLconst [16] x2:(MOVBloadidx1 [i+2] {s} p idx mem))) s2:(SHLLconst [24] x3:(MOVBloadidx1 [i+3] {s} p idx mem)))
- // cond: x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && x3.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && s2.Uses == 1 && o0.Uses == 1 && o1.Uses == 1 && mergePoint(b,x0,x1,x2,x3) != nil && clobber(x0) && clobber(x1) && clobber(x2) && clobber(x3) && clobber(s0) && clobber(s1) && clobber(s2) && clobber(o0) && clobber(o1)
- // result: @mergePoint(b,x0,x1,x2,x3) (MOVLloadidx1 <v.Type> [i] {s} p idx mem)
+ // 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 {
- o0 := v.Args[0]
- if o0.Op != OpAMD64ORL {
+ o5 := v.Args[0]
+ if o5.Op != OpAMD64ORQ {
break
}
- o1 := o0.Args[0]
- if o1.Op != OpAMD64ORL {
+ o4 := o5.Args[0]
+ if o4.Op != OpAMD64ORQ {
break
}
- x0 := o1.Args[0]
- if x0.Op != OpAMD64MOVBloadidx1 {
+ o3 := o4.Args[0]
+ if o3.Op != OpAMD64ORQ {
+ break
+ }
+ o2 := o3.Args[0]
+ if o2.Op != OpAMD64ORQ {
+ break
+ }
+ o1 := o2.Args[0]
+ if o1.Op != OpAMD64ORQ {
+ break
+ }
+ o0 := o1.Args[0]
+ if o0.Op != OpAMD64ORQ {
+ break
+ }
+ x0 := o0.Args[0]
+ if x0.Op != OpAMD64MOVBload {
break
}
i := x0.AuxInt
s := x0.Aux
p := x0.Args[0]
- idx := x0.Args[1]
- mem := x0.Args[2]
- s0 := o1.Args[1]
- if s0.Op != OpAMD64SHLLconst {
+ mem := x0.Args[1]
+ s0 := o0.Args[1]
+ if s0.Op != OpAMD64SHLQconst {
break
}
if s0.AuxInt != 8 {
break
}
x1 := s0.Args[0]
- if x1.Op != OpAMD64MOVBloadidx1 {
+ if x1.Op != OpAMD64MOVBload {
break
}
- if x1.AuxInt != i+1 {
+ if x1.AuxInt != i-1 {
break
}
if x1.Aux != s {
@@ -13052,24 +11972,21 @@ func rewriteValueAMD64_OpAMD64ORL(v *Value, config *Config) bool {
if p != x1.Args[0] {
break
}
- if idx != x1.Args[1] {
- break
- }
- if mem != x1.Args[2] {
+ if mem != x1.Args[1] {
break
}
- s1 := o0.Args[1]
- if s1.Op != OpAMD64SHLLconst {
+ s1 := o1.Args[1]
+ if s1.Op != OpAMD64SHLQconst {
break
}
if s1.AuxInt != 16 {
break
}
x2 := s1.Args[0]
- if x2.Op != OpAMD64MOVBloadidx1 {
+ if x2.Op != OpAMD64MOVBload {
break
}
- if x2.AuxInt != i+2 {
+ if x2.AuxInt != i-2 {
break
}
if x2.Aux != s {
@@ -13078,24 +11995,21 @@ func rewriteValueAMD64_OpAMD64ORL(v *Value, config *Config) bool {
if p != x2.Args[0] {
break
}
- if idx != x2.Args[1] {
- break
- }
- if mem != x2.Args[2] {
+ if mem != x2.Args[1] {
break
}
- s2 := v.Args[1]
- if s2.Op != OpAMD64SHLLconst {
+ s2 := o2.Args[1]
+ if s2.Op != OpAMD64SHLQconst {
break
}
if s2.AuxInt != 24 {
break
}
x3 := s2.Args[0]
- if x3.Op != OpAMD64MOVBloadidx1 {
+ if x3.Op != OpAMD64MOVBload {
break
}
- if x3.AuxInt != i+3 {
+ if x3.AuxInt != i-3 {
break
}
if x3.Aux != s {
@@ -13104,242 +12018,21 @@ func rewriteValueAMD64_OpAMD64ORL(v *Value, config *Config) bool {
if p != x3.Args[0] {
break
}
- if idx != x3.Args[1] {
+ if mem != x3.Args[1] {
break
}
- if mem != x3.Args[2] {
+ s3 := o3.Args[1]
+ if s3.Op != OpAMD64SHLQconst {
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)) {
+ if s3.AuxInt != 32 {
break
}
- b = mergePoint(b, x0, x1, x2, x3)
- v0 := b.NewValue0(v.Line, OpAMD64MOVLloadidx1, v.Type)
- v.reset(OpCopy)
- v.AddArg(v0)
- v0.AuxInt = i
- v0.Aux = s
- v0.AddArg(p)
- v0.AddArg(idx)
- v0.AddArg(mem)
- return true
- }
- return false
-}
-func rewriteValueAMD64_OpAMD64ORLconst(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (ORLconst [c] x)
- // cond: int32(c)==0
- // result: x
- for {
- c := v.AuxInt
- x := v.Args[0]
- if !(int32(c) == 0) {
+ x4 := s3.Args[0]
+ if x4.Op != OpAMD64MOVBload {
break
}
- v.reset(OpCopy)
- v.Type = x.Type
- v.AddArg(x)
- return true
- }
- // match: (ORLconst [c] _)
- // cond: int32(c)==-1
- // result: (MOVLconst [-1])
- for {
- c := v.AuxInt
- if !(int32(c) == -1) {
- break
- }
- v.reset(OpAMD64MOVLconst)
- v.AuxInt = -1
- return true
- }
- // match: (ORLconst [c] (MOVLconst [d]))
- // cond:
- // result: (MOVLconst [c|d])
- for {
- c := v.AuxInt
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64MOVLconst {
- break
- }
- d := v_0.AuxInt
- v.reset(OpAMD64MOVLconst)
- v.AuxInt = c | d
- return true
- }
- return false
-}
-func rewriteValueAMD64_OpAMD64ORQ(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (ORQ x (MOVQconst [c]))
- // cond: is32Bit(c)
- // result: (ORQconst [c] x)
- for {
- x := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64MOVQconst {
- break
- }
- c := v_1.AuxInt
- if !(is32Bit(c)) {
- break
- }
- v.reset(OpAMD64ORQconst)
- v.AuxInt = c
- v.AddArg(x)
- return true
- }
- // match: (ORQ (MOVQconst [c]) x)
- // cond: is32Bit(c)
- // result: (ORQconst [c] x)
- for {
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64MOVQconst {
- break
- }
- c := v_0.AuxInt
- x := v.Args[1]
- if !(is32Bit(c)) {
- break
- }
- v.reset(OpAMD64ORQconst)
- v.AuxInt = c
- v.AddArg(x)
- return true
- }
- // match: (ORQ x x)
- // cond:
- // result: x
- for {
- x := v.Args[0]
- if x != v.Args[1] {
- break
- }
- v.reset(OpCopy)
- v.Type = x.Type
- v.AddArg(x)
- return true
- }
- // match: (ORQ o0:(ORQ o1:(ORQ o2:(ORQ o3:(ORQ o4:(ORQ o5:(ORQ x0:(MOVBload [i] {s} p mem) s0:(SHLQconst [8] x1:(MOVBload [i+1] {s} p mem))) s1:(SHLQconst [16] x2:(MOVBload [i+2] {s} p mem))) s2:(SHLQconst [24] x3:(MOVBload [i+3] {s} p mem))) s3:(SHLQconst [32] x4:(MOVBload [i+4] {s} p mem))) s4:(SHLQconst [40] x5:(MOVBload [i+5] {s} p mem))) s5:(SHLQconst [48] x6:(MOVBload [i+6] {s} p mem))) s6:(SHLQconst [56] x7:(MOVBload [i+7] {s} [...]
- // cond: x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && x3.Uses == 1 && x4.Uses == 1 && x5.Uses == 1 && x6.Uses == 1 && x7.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && s2.Uses == 1 && s3.Uses == 1 && s4.Uses == 1 && s5.Uses == 1 && s6.Uses == 1 && o0.Uses == 1 && o1.Uses == 1 && o2.Uses == 1 && o3.Uses == 1 && o4.Uses == 1 && o5.Uses == 1 && mergePoint(b,x0,x1,x2,x3,x4,x5,x6,x7) != nil && clobber(x0) && clobber(x1) && clobber(x2) && clo [...]
- // result: @mergePoint(b,x0,x1,x2,x3,x4,x5,x6,x7) (MOVQload [i] {s} p mem)
- for {
- o0 := v.Args[0]
- if o0.Op != OpAMD64ORQ {
- break
- }
- o1 := o0.Args[0]
- if o1.Op != OpAMD64ORQ {
- break
- }
- o2 := o1.Args[0]
- if o2.Op != OpAMD64ORQ {
- break
- }
- o3 := o2.Args[0]
- if o3.Op != OpAMD64ORQ {
- break
- }
- o4 := o3.Args[0]
- if o4.Op != OpAMD64ORQ {
- break
- }
- o5 := o4.Args[0]
- if o5.Op != OpAMD64ORQ {
- break
- }
- x0 := o5.Args[0]
- if x0.Op != OpAMD64MOVBload {
- break
- }
- i := x0.AuxInt
- s := x0.Aux
- p := x0.Args[0]
- mem := x0.Args[1]
- s0 := o5.Args[1]
- if s0.Op != OpAMD64SHLQconst {
- break
- }
- if s0.AuxInt != 8 {
- break
- }
- x1 := s0.Args[0]
- if x1.Op != OpAMD64MOVBload {
- break
- }
- if x1.AuxInt != i+1 {
- break
- }
- if x1.Aux != s {
- break
- }
- if p != x1.Args[0] {
- break
- }
- if mem != x1.Args[1] {
- break
- }
- s1 := o4.Args[1]
- if s1.Op != OpAMD64SHLQconst {
- break
- }
- if s1.AuxInt != 16 {
- break
- }
- x2 := s1.Args[0]
- if x2.Op != OpAMD64MOVBload {
- break
- }
- if x2.AuxInt != i+2 {
- break
- }
- if x2.Aux != s {
- break
- }
- if p != x2.Args[0] {
- break
- }
- if mem != x2.Args[1] {
- break
- }
- s2 := o3.Args[1]
- if s2.Op != OpAMD64SHLQconst {
- break
- }
- if s2.AuxInt != 24 {
- break
- }
- x3 := s2.Args[0]
- if x3.Op != OpAMD64MOVBload {
- break
- }
- if x3.AuxInt != i+3 {
- break
- }
- if x3.Aux != s {
- break
- }
- if p != x3.Args[0] {
- break
- }
- if mem != x3.Args[1] {
- break
- }
- s3 := o2.Args[1]
- if s3.Op != OpAMD64SHLQconst {
- break
- }
- if s3.AuxInt != 32 {
- break
- }
- x4 := s3.Args[0]
- if x4.Op != OpAMD64MOVBload {
- break
- }
- if x4.AuxInt != i+4 {
+ if x4.AuxInt != i-4 {
break
}
if x4.Aux != s {
@@ -13351,7 +12044,7 @@ func rewriteValueAMD64_OpAMD64ORQ(v *Value, config *Config) bool {
if mem != x4.Args[1] {
break
}
- s4 := o1.Args[1]
+ s4 := o4.Args[1]
if s4.Op != OpAMD64SHLQconst {
break
}
@@ -13362,7 +12055,7 @@ func rewriteValueAMD64_OpAMD64ORQ(v *Value, config *Config) bool {
if x5.Op != OpAMD64MOVBload {
break
}
- if x5.AuxInt != i+5 {
+ if x5.AuxInt != i-5 {
break
}
if x5.Aux != s {
@@ -13374,7 +12067,7 @@ func rewriteValueAMD64_OpAMD64ORQ(v *Value, config *Config) bool {
if mem != x5.Args[1] {
break
}
- s5 := o0.Args[1]
+ s5 := o5.Args[1]
if s5.Op != OpAMD64SHLQconst {
break
}
@@ -13385,7 +12078,7 @@ func rewriteValueAMD64_OpAMD64ORQ(v *Value, config *Config) bool {
if x6.Op != OpAMD64MOVBload {
break
}
- if x6.AuxInt != i+6 {
+ if x6.AuxInt != i-6 {
break
}
if x6.Aux != s {
@@ -13408,7 +12101,7 @@ func rewriteValueAMD64_OpAMD64ORQ(v *Value, config *Config) bool {
if x7.Op != OpAMD64MOVBload {
break
}
- if x7.AuxInt != i+7 {
+ if x7.AuxInt != i-7 {
break
}
if x7.Aux != s {
@@ -13424,44 +12117,46 @@ func rewriteValueAMD64_OpAMD64ORQ(v *Value, config *Config) bool {
break
}
b = mergePoint(b, x0, x1, x2, x3, x4, x5, x6, x7)
- v0 := b.NewValue0(v.Line, OpAMD64MOVQload, config.fe.TypeUInt64())
+ v0 := b.NewValue0(v.Line, OpAMD64BSWAPQ, v.Type)
v.reset(OpCopy)
v.AddArg(v0)
- v0.AuxInt = i
- v0.Aux = s
- v0.AddArg(p)
- v0.AddArg(mem)
+ 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 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 [...]
+ // 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) (MOVQloadidx1 <v.Type> [i] {s} p idx mem)
+ // result: @mergePoint(b,x0,x1,x2,x3,x4,x5,x6,x7) (BSWAPQ <v.Type> (MOVQloadidx1 <v.Type> [i-7] {s} p idx mem))
for {
- o0 := v.Args[0]
- if o0.Op != OpAMD64ORQ {
+ o5 := v.Args[0]
+ if o5.Op != OpAMD64ORQ {
break
}
- o1 := o0.Args[0]
- if o1.Op != OpAMD64ORQ {
+ o4 := o5.Args[0]
+ if o4.Op != OpAMD64ORQ {
break
}
- o2 := o1.Args[0]
- if o2.Op != OpAMD64ORQ {
+ o3 := o4.Args[0]
+ if o3.Op != OpAMD64ORQ {
break
}
- o3 := o2.Args[0]
- if o3.Op != OpAMD64ORQ {
+ o2 := o3.Args[0]
+ if o2.Op != OpAMD64ORQ {
break
}
- o4 := o3.Args[0]
- if o4.Op != OpAMD64ORQ {
+ o1 := o2.Args[0]
+ if o1.Op != OpAMD64ORQ {
break
}
- o5 := o4.Args[0]
- if o5.Op != OpAMD64ORQ {
+ o0 := o1.Args[0]
+ if o0.Op != OpAMD64ORQ {
break
}
- x0 := o5.Args[0]
+ x0 := o0.Args[0]
if x0.Op != OpAMD64MOVBloadidx1 {
break
}
@@ -13470,7 +12165,7 @@ func rewriteValueAMD64_OpAMD64ORQ(v *Value, config *Config) bool {
p := x0.Args[0]
idx := x0.Args[1]
mem := x0.Args[2]
- s0 := o5.Args[1]
+ s0 := o0.Args[1]
if s0.Op != OpAMD64SHLQconst {
break
}
@@ -13481,7 +12176,7 @@ func rewriteValueAMD64_OpAMD64ORQ(v *Value, config *Config) bool {
if x1.Op != OpAMD64MOVBloadidx1 {
break
}
- if x1.AuxInt != i+1 {
+ if x1.AuxInt != i-1 {
break
}
if x1.Aux != s {
@@ -13496,7 +12191,7 @@ func rewriteValueAMD64_OpAMD64ORQ(v *Value, config *Config) bool {
if mem != x1.Args[2] {
break
}
- s1 := o4.Args[1]
+ s1 := o1.Args[1]
if s1.Op != OpAMD64SHLQconst {
break
}
@@ -13507,7 +12202,7 @@ func rewriteValueAMD64_OpAMD64ORQ(v *Value, config *Config) bool {
if x2.Op != OpAMD64MOVBloadidx1 {
break
}
- if x2.AuxInt != i+2 {
+ if x2.AuxInt != i-2 {
break
}
if x2.Aux != s {
@@ -13522,7 +12217,7 @@ func rewriteValueAMD64_OpAMD64ORQ(v *Value, config *Config) bool {
if mem != x2.Args[2] {
break
}
- s2 := o3.Args[1]
+ s2 := o2.Args[1]
if s2.Op != OpAMD64SHLQconst {
break
}
@@ -13533,7 +12228,7 @@ func rewriteValueAMD64_OpAMD64ORQ(v *Value, config *Config) bool {
if x3.Op != OpAMD64MOVBloadidx1 {
break
}
- if x3.AuxInt != i+3 {
+ if x3.AuxInt != i-3 {
break
}
if x3.Aux != s {
@@ -13548,7 +12243,7 @@ func rewriteValueAMD64_OpAMD64ORQ(v *Value, config *Config) bool {
if mem != x3.Args[2] {
break
}
- s3 := o2.Args[1]
+ s3 := o3.Args[1]
if s3.Op != OpAMD64SHLQconst {
break
}
@@ -13559,7 +12254,7 @@ func rewriteValueAMD64_OpAMD64ORQ(v *Value, config *Config) bool {
if x4.Op != OpAMD64MOVBloadidx1 {
break
}
- if x4.AuxInt != i+4 {
+ if x4.AuxInt != i-4 {
break
}
if x4.Aux != s {
@@ -13574,7 +12269,7 @@ func rewriteValueAMD64_OpAMD64ORQ(v *Value, config *Config) bool {
if mem != x4.Args[2] {
break
}
- s4 := o1.Args[1]
+ s4 := o4.Args[1]
if s4.Op != OpAMD64SHLQconst {
break
}
@@ -13585,7 +12280,7 @@ func rewriteValueAMD64_OpAMD64ORQ(v *Value, config *Config) bool {
if x5.Op != OpAMD64MOVBloadidx1 {
break
}
- if x5.AuxInt != i+5 {
+ if x5.AuxInt != i-5 {
break
}
if x5.Aux != s {
@@ -13600,7 +12295,7 @@ func rewriteValueAMD64_OpAMD64ORQ(v *Value, config *Config) bool {
if mem != x5.Args[2] {
break
}
- s5 := o0.Args[1]
+ s5 := o5.Args[1]
if s5.Op != OpAMD64SHLQconst {
break
}
@@ -13611,7 +12306,7 @@ func rewriteValueAMD64_OpAMD64ORQ(v *Value, config *Config) bool {
if x6.Op != OpAMD64MOVBloadidx1 {
break
}
- if x6.AuxInt != i+6 {
+ if x6.AuxInt != i-6 {
break
}
if x6.Aux != s {
@@ -13637,7 +12332,7 @@ func rewriteValueAMD64_OpAMD64ORQ(v *Value, config *Config) bool {
if x7.Op != OpAMD64MOVBloadidx1 {
break
}
- if x7.AuxInt != i+7 {
+ if x7.AuxInt != i-7 {
break
}
if x7.Aux != s {
@@ -13652,2625 +12347,6920 @@ func rewriteValueAMD64_OpAMD64ORQ(v *Value, config *Config) bool {
if mem != x7.Args[2] {
break
}
- if !(x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && x3.Uses == 1 && x4.Uses == 1 && x5.Uses == 1 && x6.Uses == 1 && x7.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && s2.Uses == 1 && s3.Uses == 1 && s4.Uses == 1 && s5.Uses == 1 && s6.Uses == 1 && o0.Uses == 1 && o1.Uses == 1 && o2.Uses == 1 && o3.Uses == 1 && o4.Uses == 1 && o5.Uses == 1 && mergePoint(b, x0, x1, x2, x3, x4, x5, x6, x7) != nil && clobber(x0) && clobber(x1) && clobber(x2) && clobber(x3) && clobber(x4) && clobber(x5) && clo [...]
+ if !(x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && x3.Uses == 1 && x4.Uses == 1 && x5.Uses == 1 && x6.Uses == 1 && x7.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && s2.Uses == 1 && s3.Uses == 1 && s4.Uses == 1 && s5.Uses == 1 && s6.Uses == 1 && o0.Uses == 1 && o1.Uses == 1 && o2.Uses == 1 && o3.Uses == 1 && o4.Uses == 1 && o5.Uses == 1 && mergePoint(b, x0, x1, x2, x3, x4, x5, x6, x7) != nil && clobber(x0) && clobber(x1) && clobber(x2) && clobber(x3) && clobber(x4) && clobber(x5) && clo [...]
+ break
+ }
+ b = mergePoint(b, x0, x1, x2, x3, x4, x5, x6, x7)
+ v0 := b.NewValue0(v.Line, 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 {
+ 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_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 {
+ 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 {
+ break
+ }
+ x := v.Args[0]
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValueAMD64_OpAMD64ROLLconst(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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 [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
+ }
+ return false
+}
+func rewriteValueAMD64_OpAMD64ROLQconst(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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 [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
+ }
+ return false
+}
+func rewriteValueAMD64_OpAMD64ROLWconst(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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 [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
+ }
+ 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 {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpAMD64SARBconst)
+ v.AuxInt = c & 31
+ v.AddArg(x)
+ return true
+ }
+ // match: (SARB x (MOVLconst [c]))
+ // cond:
+ // result: (SARBconst [c&31] x)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64MOVLconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpAMD64SARBconst)
+ v.AuxInt = c & 31
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValueAMD64_OpAMD64SARBconst(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SARBconst [c] (MOVQconst [d]))
+ // cond:
+ // result: (MOVQconst [d>>uint64(c)])
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64MOVQconst {
+ break
+ }
+ d := v_0.AuxInt
+ v.reset(OpAMD64MOVQconst)
+ v.AuxInt = d >> uint64(c)
+ return true
+ }
+ return false
+}
+func rewriteValueAMD64_OpAMD64SARL(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SARL x (MOVQconst [c]))
+ // cond:
+ // result: (SARLconst [c&31] x)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64MOVQconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpAMD64SARLconst)
+ v.AuxInt = c & 31
+ v.AddArg(x)
+ return true
+ }
+ // match: (SARL x (MOVLconst [c]))
+ // cond:
+ // result: (SARLconst [c&31] x)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64MOVLconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpAMD64SARLconst)
+ v.AuxInt = c & 31
+ v.AddArg(x)
+ return true
+ }
+ // match: (SARL x (ANDLconst [31] y))
+ // cond:
+ // result: (SARL x y)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64ANDLconst {
+ break
+ }
+ if v_1.AuxInt != 31 {
+ break
+ }
+ y := v_1.Args[0]
+ v.reset(OpAMD64SARL)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ return false
+}
+func rewriteValueAMD64_OpAMD64SARLconst(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SARLconst [c] (MOVQconst [d]))
+ // cond:
+ // result: (MOVQconst [d>>uint64(c)])
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64MOVQconst {
+ break
+ }
+ d := v_0.AuxInt
+ v.reset(OpAMD64MOVQconst)
+ v.AuxInt = d >> uint64(c)
+ return true
+ }
+ return false
+}
+func rewriteValueAMD64_OpAMD64SARQ(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SARQ x (MOVQconst [c]))
+ // cond:
+ // result: (SARQconst [c&63] x)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64MOVQconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpAMD64SARQconst)
+ v.AuxInt = c & 63
+ v.AddArg(x)
+ return true
+ }
+ // match: (SARQ x (MOVLconst [c]))
+ // cond:
+ // result: (SARQconst [c&63] x)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64MOVLconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpAMD64SARQconst)
+ v.AuxInt = c & 63
+ v.AddArg(x)
+ return true
+ }
+ // match: (SARQ x (ANDQconst [63] y))
+ // cond:
+ // result: (SARQ x y)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64ANDQconst {
+ break
+ }
+ if v_1.AuxInt != 63 {
+ break
+ }
+ y := v_1.Args[0]
+ v.reset(OpAMD64SARQ)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ return false
+}
+func rewriteValueAMD64_OpAMD64SARQconst(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SARQconst [c] (MOVQconst [d]))
+ // cond:
+ // result: (MOVQconst [d>>uint64(c)])
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64MOVQconst {
+ break
+ }
+ d := v_0.AuxInt
+ v.reset(OpAMD64MOVQconst)
+ v.AuxInt = d >> uint64(c)
+ return true
+ }
+ return false
+}
+func rewriteValueAMD64_OpAMD64SARW(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SARW x (MOVQconst [c]))
+ // cond:
+ // result: (SARWconst [c&31] x)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64MOVQconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpAMD64SARWconst)
+ v.AuxInt = c & 31
+ v.AddArg(x)
+ return true
+ }
+ // match: (SARW x (MOVLconst [c]))
+ // cond:
+ // result: (SARWconst [c&31] x)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64MOVLconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpAMD64SARWconst)
+ v.AuxInt = c & 31
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValueAMD64_OpAMD64SARWconst(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SARWconst [c] (MOVQconst [d]))
+ // cond:
+ // result: (MOVQconst [d>>uint64(c)])
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64MOVQconst {
+ break
+ }
+ d := v_0.AuxInt
+ v.reset(OpAMD64MOVQconst)
+ v.AuxInt = d >> uint64(c)
+ return true
+ }
+ return false
+}
+func rewriteValueAMD64_OpAMD64SBBLcarrymask(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SBBLcarrymask (FlagEQ))
+ // cond:
+ // result: (MOVLconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64FlagEQ {
+ break
+ }
+ v.reset(OpAMD64MOVLconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (SBBLcarrymask (FlagLT_ULT))
+ // cond:
+ // result: (MOVLconst [-1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64FlagLT_ULT {
+ break
+ }
+ v.reset(OpAMD64MOVLconst)
+ v.AuxInt = -1
+ return true
+ }
+ // match: (SBBLcarrymask (FlagLT_UGT))
+ // cond:
+ // result: (MOVLconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64FlagLT_UGT {
+ break
+ }
+ v.reset(OpAMD64MOVLconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (SBBLcarrymask (FlagGT_ULT))
+ // cond:
+ // result: (MOVLconst [-1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64FlagGT_ULT {
+ break
+ }
+ v.reset(OpAMD64MOVLconst)
+ v.AuxInt = -1
+ return true
+ }
+ // match: (SBBLcarrymask (FlagGT_UGT))
+ // cond:
+ // result: (MOVLconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64FlagGT_UGT {
+ break
+ }
+ v.reset(OpAMD64MOVLconst)
+ v.AuxInt = 0
+ return true
+ }
+ return false
+}
+func rewriteValueAMD64_OpAMD64SBBQcarrymask(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SBBQcarrymask (FlagEQ))
+ // cond:
+ // result: (MOVQconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64FlagEQ {
+ break
+ }
+ v.reset(OpAMD64MOVQconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (SBBQcarrymask (FlagLT_ULT))
+ // cond:
+ // result: (MOVQconst [-1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64FlagLT_ULT {
+ break
+ }
+ v.reset(OpAMD64MOVQconst)
+ v.AuxInt = -1
+ return true
+ }
+ // match: (SBBQcarrymask (FlagLT_UGT))
+ // cond:
+ // result: (MOVQconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64FlagLT_UGT {
+ break
+ }
+ v.reset(OpAMD64MOVQconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (SBBQcarrymask (FlagGT_ULT))
+ // cond:
+ // result: (MOVQconst [-1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64FlagGT_ULT {
+ break
+ }
+ v.reset(OpAMD64MOVQconst)
+ v.AuxInt = -1
+ return true
+ }
+ // match: (SBBQcarrymask (FlagGT_UGT))
+ // cond:
+ // result: (MOVQconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64FlagGT_UGT {
+ break
+ }
+ v.reset(OpAMD64MOVQconst)
+ v.AuxInt = 0
+ return true
+ }
+ return false
+}
+func rewriteValueAMD64_OpAMD64SETA(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SETA (InvertFlags x))
+ // cond:
+ // result: (SETB x)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64InvertFlags {
+ break
+ }
+ x := v_0.Args[0]
+ v.reset(OpAMD64SETB)
+ v.AddArg(x)
+ return true
+ }
+ // match: (SETA (FlagEQ))
+ // cond:
+ // result: (MOVLconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64FlagEQ {
+ break
+ }
+ v.reset(OpAMD64MOVLconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (SETA (FlagLT_ULT))
+ // cond:
+ // result: (MOVLconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64FlagLT_ULT {
+ break
+ }
+ v.reset(OpAMD64MOVLconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (SETA (FlagLT_UGT))
+ // cond:
+ // result: (MOVLconst [1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64FlagLT_UGT {
+ break
+ }
+ v.reset(OpAMD64MOVLconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (SETA (FlagGT_ULT))
+ // cond:
+ // result: (MOVLconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64FlagGT_ULT {
+ break
+ }
+ v.reset(OpAMD64MOVLconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (SETA (FlagGT_UGT))
+ // cond:
+ // result: (MOVLconst [1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64FlagGT_UGT {
+ break
+ }
+ v.reset(OpAMD64MOVLconst)
+ v.AuxInt = 1
+ return true
+ }
+ return false
+}
+func rewriteValueAMD64_OpAMD64SETAE(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SETAE (InvertFlags x))
+ // cond:
+ // result: (SETBE x)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64InvertFlags {
+ break
+ }
+ x := v_0.Args[0]
+ v.reset(OpAMD64SETBE)
+ v.AddArg(x)
+ return true
+ }
+ // match: (SETAE (FlagEQ))
+ // cond:
+ // result: (MOVLconst [1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64FlagEQ {
+ break
+ }
+ v.reset(OpAMD64MOVLconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (SETAE (FlagLT_ULT))
+ // cond:
+ // result: (MOVLconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64FlagLT_ULT {
+ break
+ }
+ v.reset(OpAMD64MOVLconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (SETAE (FlagLT_UGT))
+ // cond:
+ // result: (MOVLconst [1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64FlagLT_UGT {
+ break
+ }
+ v.reset(OpAMD64MOVLconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (SETAE (FlagGT_ULT))
+ // cond:
+ // result: (MOVLconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64FlagGT_ULT {
+ break
+ }
+ v.reset(OpAMD64MOVLconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (SETAE (FlagGT_UGT))
+ // cond:
+ // result: (MOVLconst [1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64FlagGT_UGT {
+ break
+ }
+ v.reset(OpAMD64MOVLconst)
+ v.AuxInt = 1
+ return true
+ }
+ return false
+}
+func rewriteValueAMD64_OpAMD64SETB(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SETB (InvertFlags x))
+ // cond:
+ // result: (SETA x)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64InvertFlags {
+ break
+ }
+ x := v_0.Args[0]
+ v.reset(OpAMD64SETA)
+ v.AddArg(x)
+ return true
+ }
+ // match: (SETB (FlagEQ))
+ // cond:
+ // result: (MOVLconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64FlagEQ {
+ break
+ }
+ v.reset(OpAMD64MOVLconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (SETB (FlagLT_ULT))
+ // cond:
+ // result: (MOVLconst [1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64FlagLT_ULT {
+ break
+ }
+ v.reset(OpAMD64MOVLconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (SETB (FlagLT_UGT))
+ // cond:
+ // result: (MOVLconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64FlagLT_UGT {
+ break
+ }
+ v.reset(OpAMD64MOVLconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (SETB (FlagGT_ULT))
+ // cond:
+ // result: (MOVLconst [1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64FlagGT_ULT {
+ break
+ }
+ v.reset(OpAMD64MOVLconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (SETB (FlagGT_UGT))
+ // cond:
+ // result: (MOVLconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64FlagGT_UGT {
+ break
+ }
+ v.reset(OpAMD64MOVLconst)
+ v.AuxInt = 0
+ return true
+ }
+ return false
+}
+func rewriteValueAMD64_OpAMD64SETBE(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SETBE (InvertFlags x))
+ // cond:
+ // result: (SETAE x)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64InvertFlags {
+ break
+ }
+ x := v_0.Args[0]
+ v.reset(OpAMD64SETAE)
+ v.AddArg(x)
+ return true
+ }
+ // match: (SETBE (FlagEQ))
+ // cond:
+ // result: (MOVLconst [1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64FlagEQ {
+ break
+ }
+ v.reset(OpAMD64MOVLconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (SETBE (FlagLT_ULT))
+ // cond:
+ // result: (MOVLconst [1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64FlagLT_ULT {
+ break
+ }
+ v.reset(OpAMD64MOVLconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (SETBE (FlagLT_UGT))
+ // cond:
+ // result: (MOVLconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64FlagLT_UGT {
+ break
+ }
+ v.reset(OpAMD64MOVLconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (SETBE (FlagGT_ULT))
+ // cond:
+ // result: (MOVLconst [1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64FlagGT_ULT {
+ break
+ }
+ v.reset(OpAMD64MOVLconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (SETBE (FlagGT_UGT))
+ // cond:
+ // result: (MOVLconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64FlagGT_UGT {
+ break
+ }
+ v.reset(OpAMD64MOVLconst)
+ v.AuxInt = 0
+ return true
+ }
+ return false
+}
+func rewriteValueAMD64_OpAMD64SETEQ(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SETEQ (InvertFlags x))
+ // cond:
+ // result: (SETEQ x)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64InvertFlags {
+ break
+ }
+ x := v_0.Args[0]
+ v.reset(OpAMD64SETEQ)
+ v.AddArg(x)
+ return true
+ }
+ // match: (SETEQ (FlagEQ))
+ // cond:
+ // result: (MOVLconst [1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64FlagEQ {
+ break
+ }
+ v.reset(OpAMD64MOVLconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (SETEQ (FlagLT_ULT))
+ // cond:
+ // result: (MOVLconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64FlagLT_ULT {
+ break
+ }
+ v.reset(OpAMD64MOVLconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (SETEQ (FlagLT_UGT))
+ // cond:
+ // result: (MOVLconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64FlagLT_UGT {
+ break
+ }
+ v.reset(OpAMD64MOVLconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (SETEQ (FlagGT_ULT))
+ // cond:
+ // result: (MOVLconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64FlagGT_ULT {
+ break
+ }
+ v.reset(OpAMD64MOVLconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (SETEQ (FlagGT_UGT))
+ // cond:
+ // result: (MOVLconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64FlagGT_UGT {
+ break
+ }
+ v.reset(OpAMD64MOVLconst)
+ v.AuxInt = 0
+ return true
+ }
+ return false
+}
+func rewriteValueAMD64_OpAMD64SETG(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SETG (InvertFlags x))
+ // cond:
+ // result: (SETL x)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64InvertFlags {
+ break
+ }
+ x := v_0.Args[0]
+ v.reset(OpAMD64SETL)
+ v.AddArg(x)
+ return true
+ }
+ // match: (SETG (FlagEQ))
+ // cond:
+ // result: (MOVLconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64FlagEQ {
+ break
+ }
+ v.reset(OpAMD64MOVLconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (SETG (FlagLT_ULT))
+ // cond:
+ // result: (MOVLconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64FlagLT_ULT {
+ break
+ }
+ v.reset(OpAMD64MOVLconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (SETG (FlagLT_UGT))
+ // cond:
+ // result: (MOVLconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64FlagLT_UGT {
+ break
+ }
+ v.reset(OpAMD64MOVLconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (SETG (FlagGT_ULT))
+ // cond:
+ // result: (MOVLconst [1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64FlagGT_ULT {
+ break
+ }
+ v.reset(OpAMD64MOVLconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (SETG (FlagGT_UGT))
+ // cond:
+ // result: (MOVLconst [1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64FlagGT_UGT {
+ break
+ }
+ v.reset(OpAMD64MOVLconst)
+ v.AuxInt = 1
+ return true
+ }
+ return false
+}
+func rewriteValueAMD64_OpAMD64SETGE(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SETGE (InvertFlags x))
+ // cond:
+ // result: (SETLE x)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64InvertFlags {
+ break
+ }
+ x := v_0.Args[0]
+ v.reset(OpAMD64SETLE)
+ v.AddArg(x)
+ return true
+ }
+ // match: (SETGE (FlagEQ))
+ // cond:
+ // result: (MOVLconst [1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64FlagEQ {
+ break
+ }
+ v.reset(OpAMD64MOVLconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (SETGE (FlagLT_ULT))
+ // cond:
+ // result: (MOVLconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64FlagLT_ULT {
+ break
+ }
+ v.reset(OpAMD64MOVLconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (SETGE (FlagLT_UGT))
+ // cond:
+ // result: (MOVLconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64FlagLT_UGT {
+ break
+ }
+ v.reset(OpAMD64MOVLconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (SETGE (FlagGT_ULT))
+ // cond:
+ // result: (MOVLconst [1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64FlagGT_ULT {
+ break
+ }
+ v.reset(OpAMD64MOVLconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (SETGE (FlagGT_UGT))
+ // cond:
+ // result: (MOVLconst [1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64FlagGT_UGT {
+ break
+ }
+ v.reset(OpAMD64MOVLconst)
+ v.AuxInt = 1
+ return true
+ }
+ return false
+}
+func rewriteValueAMD64_OpAMD64SETL(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SETL (InvertFlags x))
+ // cond:
+ // result: (SETG x)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64InvertFlags {
+ break
+ }
+ x := v_0.Args[0]
+ v.reset(OpAMD64SETG)
+ v.AddArg(x)
+ return true
+ }
+ // match: (SETL (FlagEQ))
+ // cond:
+ // result: (MOVLconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64FlagEQ {
+ break
+ }
+ v.reset(OpAMD64MOVLconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (SETL (FlagLT_ULT))
+ // cond:
+ // result: (MOVLconst [1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64FlagLT_ULT {
+ break
+ }
+ v.reset(OpAMD64MOVLconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (SETL (FlagLT_UGT))
+ // cond:
+ // result: (MOVLconst [1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64FlagLT_UGT {
+ break
+ }
+ v.reset(OpAMD64MOVLconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (SETL (FlagGT_ULT))
+ // cond:
+ // result: (MOVLconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64FlagGT_ULT {
+ break
+ }
+ v.reset(OpAMD64MOVLconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (SETL (FlagGT_UGT))
+ // cond:
+ // result: (MOVLconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64FlagGT_UGT {
+ break
+ }
+ v.reset(OpAMD64MOVLconst)
+ v.AuxInt = 0
+ return true
+ }
+ return false
+}
+func rewriteValueAMD64_OpAMD64SETLE(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SETLE (InvertFlags x))
+ // cond:
+ // result: (SETGE x)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64InvertFlags {
+ break
+ }
+ x := v_0.Args[0]
+ v.reset(OpAMD64SETGE)
+ v.AddArg(x)
+ return true
+ }
+ // match: (SETLE (FlagEQ))
+ // cond:
+ // result: (MOVLconst [1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64FlagEQ {
+ break
+ }
+ v.reset(OpAMD64MOVLconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (SETLE (FlagLT_ULT))
+ // cond:
+ // result: (MOVLconst [1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64FlagLT_ULT {
+ break
+ }
+ v.reset(OpAMD64MOVLconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (SETLE (FlagLT_UGT))
+ // cond:
+ // result: (MOVLconst [1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64FlagLT_UGT {
+ break
+ }
+ v.reset(OpAMD64MOVLconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (SETLE (FlagGT_ULT))
+ // cond:
+ // result: (MOVLconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64FlagGT_ULT {
+ break
+ }
+ v.reset(OpAMD64MOVLconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (SETLE (FlagGT_UGT))
+ // cond:
+ // result: (MOVLconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64FlagGT_UGT {
+ break
+ }
+ v.reset(OpAMD64MOVLconst)
+ v.AuxInt = 0
+ return true
+ }
+ return false
+}
+func rewriteValueAMD64_OpAMD64SETNE(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SETNE (InvertFlags x))
+ // cond:
+ // result: (SETNE x)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64InvertFlags {
+ break
+ }
+ x := v_0.Args[0]
+ v.reset(OpAMD64SETNE)
+ v.AddArg(x)
+ return true
+ }
+ // match: (SETNE (FlagEQ))
+ // cond:
+ // result: (MOVLconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64FlagEQ {
+ break
+ }
+ v.reset(OpAMD64MOVLconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (SETNE (FlagLT_ULT))
+ // cond:
+ // result: (MOVLconst [1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64FlagLT_ULT {
+ break
+ }
+ v.reset(OpAMD64MOVLconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (SETNE (FlagLT_UGT))
+ // cond:
+ // result: (MOVLconst [1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64FlagLT_UGT {
+ break
+ }
+ v.reset(OpAMD64MOVLconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (SETNE (FlagGT_ULT))
+ // cond:
+ // result: (MOVLconst [1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64FlagGT_ULT {
+ break
+ }
+ v.reset(OpAMD64MOVLconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (SETNE (FlagGT_UGT))
+ // cond:
+ // result: (MOVLconst [1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64FlagGT_UGT {
+ break
+ }
+ v.reset(OpAMD64MOVLconst)
+ v.AuxInt = 1
+ return true
+ }
+ return false
+}
+func rewriteValueAMD64_OpAMD64SHLL(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SHLL x (MOVQconst [c]))
+ // cond:
+ // result: (SHLLconst [c&31] x)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64MOVQconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpAMD64SHLLconst)
+ v.AuxInt = c & 31
+ v.AddArg(x)
+ return true
+ }
+ // match: (SHLL x (MOVLconst [c]))
+ // cond:
+ // result: (SHLLconst [c&31] x)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64MOVLconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpAMD64SHLLconst)
+ v.AuxInt = c & 31
+ v.AddArg(x)
+ return true
+ }
+ // match: (SHLL x (ANDLconst [31] y))
+ // cond:
+ // result: (SHLL x y)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64ANDLconst {
+ break
+ }
+ if v_1.AuxInt != 31 {
+ break
+ }
+ y := v_1.Args[0]
+ v.reset(OpAMD64SHLL)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ return false
+}
+func rewriteValueAMD64_OpAMD64SHLQ(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SHLQ x (MOVQconst [c]))
+ // cond:
+ // result: (SHLQconst [c&63] x)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64MOVQconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpAMD64SHLQconst)
+ v.AuxInt = c & 63
+ v.AddArg(x)
+ return true
+ }
+ // match: (SHLQ x (MOVLconst [c]))
+ // cond:
+ // result: (SHLQconst [c&63] x)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64MOVLconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpAMD64SHLQconst)
+ v.AuxInt = c & 63
+ v.AddArg(x)
+ return true
+ }
+ // match: (SHLQ x (ANDQconst [63] y))
+ // cond:
+ // result: (SHLQ x y)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64ANDQconst {
+ break
+ }
+ if v_1.AuxInt != 63 {
+ break
+ }
+ y := v_1.Args[0]
+ v.reset(OpAMD64SHLQ)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ return false
+}
+func rewriteValueAMD64_OpAMD64SHRB(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SHRB x (MOVQconst [c]))
+ // cond:
+ // result: (SHRBconst [c&31] x)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64MOVQconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpAMD64SHRBconst)
+ v.AuxInt = c & 31
+ v.AddArg(x)
+ return true
+ }
+ // match: (SHRB x (MOVLconst [c]))
+ // cond:
+ // result: (SHRBconst [c&31] x)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64MOVLconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpAMD64SHRBconst)
+ v.AuxInt = c & 31
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValueAMD64_OpAMD64SHRL(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SHRL x (MOVQconst [c]))
+ // cond:
+ // result: (SHRLconst [c&31] x)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64MOVQconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpAMD64SHRLconst)
+ v.AuxInt = c & 31
+ v.AddArg(x)
+ return true
+ }
+ // match: (SHRL x (MOVLconst [c]))
+ // cond:
+ // result: (SHRLconst [c&31] x)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64MOVLconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpAMD64SHRLconst)
+ v.AuxInt = c & 31
+ v.AddArg(x)
+ return true
+ }
+ // match: (SHRL x (ANDLconst [31] y))
+ // cond:
+ // result: (SHRL x y)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64ANDLconst {
+ break
+ }
+ if v_1.AuxInt != 31 {
+ break
+ }
+ y := v_1.Args[0]
+ v.reset(OpAMD64SHRL)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ return false
+}
+func rewriteValueAMD64_OpAMD64SHRQ(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SHRQ x (MOVQconst [c]))
+ // cond:
+ // result: (SHRQconst [c&63] x)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64MOVQconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpAMD64SHRQconst)
+ v.AuxInt = c & 63
+ v.AddArg(x)
+ return true
+ }
+ // match: (SHRQ x (MOVLconst [c]))
+ // cond:
+ // result: (SHRQconst [c&63] x)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64MOVLconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpAMD64SHRQconst)
+ v.AuxInt = c & 63
+ v.AddArg(x)
+ return true
+ }
+ // match: (SHRQ x (ANDQconst [63] y))
+ // cond:
+ // result: (SHRQ x y)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64ANDQconst {
+ break
+ }
+ if v_1.AuxInt != 63 {
+ break
+ }
+ y := v_1.Args[0]
+ v.reset(OpAMD64SHRQ)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ return false
+}
+func rewriteValueAMD64_OpAMD64SHRW(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SHRW x (MOVQconst [c]))
+ // cond:
+ // result: (SHRWconst [c&31] x)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64MOVQconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpAMD64SHRWconst)
+ v.AuxInt = c & 31
+ v.AddArg(x)
+ return true
+ }
+ // match: (SHRW x (MOVLconst [c]))
+ // cond:
+ // result: (SHRWconst [c&31] x)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64MOVLconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpAMD64SHRWconst)
+ v.AuxInt = c & 31
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValueAMD64_OpAMD64SUBL(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SUBL x (MOVLconst [c]))
+ // cond:
+ // result: (SUBLconst x [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64MOVLconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpAMD64SUBLconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (SUBL (MOVLconst [c]) x)
+ // cond:
+ // result: (NEGL (SUBLconst <v.Type> x [c]))
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64MOVLconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ v.reset(OpAMD64NEGL)
+ v0 := b.NewValue0(v.Line, OpAMD64SUBLconst, v.Type)
+ v0.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] {
+ break
+ }
+ v.reset(OpAMD64MOVLconst)
+ v.AuxInt = 0
+ return true
+ }
+ return false
+}
+func rewriteValueAMD64_OpAMD64SUBLconst(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SUBLconst [c] x)
+ // cond: int32(c) == 0
+ // result: x
+ for {
+ c := v.AuxInt
+ x := v.Args[0]
+ if !(int32(c) == 0) {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ // match: (SUBLconst [c] x)
+ // cond:
+ // result: (ADDLconst [int64(int32(-c))] x)
+ for {
+ c := v.AuxInt
+ x := v.Args[0]
+ v.reset(OpAMD64ADDLconst)
+ v.AuxInt = int64(int32(-c))
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueAMD64_OpAMD64SUBQ(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SUBQ x (MOVQconst [c]))
+ // cond: is32Bit(c)
+ // result: (SUBQconst x [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64MOVQconst {
+ break
+ }
+ c := v_1.AuxInt
+ if !(is32Bit(c)) {
+ break
+ }
+ v.reset(OpAMD64SUBQconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (SUBQ (MOVQconst [c]) x)
+ // cond: is32Bit(c)
+ // result: (NEGQ (SUBQconst <v.Type> x [c]))
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64MOVQconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ if !(is32Bit(c)) {
+ break
+ }
+ v.reset(OpAMD64NEGQ)
+ v0 := b.NewValue0(v.Line, OpAMD64SUBQconst, v.Type)
+ v0.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] {
+ break
+ }
+ v.reset(OpAMD64MOVQconst)
+ v.AuxInt = 0
+ return true
+ }
+ return false
+}
+func rewriteValueAMD64_OpAMD64SUBQconst(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SUBQconst [0] x)
+ // cond:
+ // result: x
+ for {
+ if v.AuxInt != 0 {
+ break
+ }
+ x := v.Args[0]
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ // match: (SUBQconst [c] x)
+ // cond: c != -(1<<31)
+ // result: (ADDQconst [-c] x)
+ for {
+ c := v.AuxInt
+ x := v.Args[0]
+ if !(c != -(1 << 31)) {
+ break
+ }
+ v.reset(OpAMD64ADDQconst)
+ v.AuxInt = -c
+ v.AddArg(x)
+ return true
+ }
+ // match: (SUBQconst (MOVQconst [d]) [c])
+ // cond:
+ // result: (MOVQconst [d-c])
+ for {
+ 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_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 {
+ 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(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 {
+ 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(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]
+ 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
+ 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(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 {
+ 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
+ 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(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (XORL x (MOVLconst [c]))
+ // cond:
+ // result: (XORLconst [c] x)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64MOVLconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpAMD64XORLconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (XORL (MOVLconst [c]) x)
+ // cond:
+ // result: (XORLconst [c] x)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64MOVLconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ v.reset(OpAMD64XORLconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (XORL x x)
+ // cond:
+ // result: (MOVLconst [0])
+ for {
+ x := v.Args[0]
+ if x != v.Args[1] {
+ break
+ }
+ v.reset(OpAMD64MOVLconst)
+ v.AuxInt = 0
+ return true
+ }
+ return false
+}
+func rewriteValueAMD64_OpAMD64XORLconst(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (XORLconst [c] (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(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (XORQ x (MOVQconst [c]))
+ // cond: is32Bit(c)
+ // result: (XORQconst [c] x)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpAMD64MOVQconst {
+ break
+ }
+ c := v_1.AuxInt
+ if !(is32Bit(c)) {
+ break
+ }
+ v.reset(OpAMD64XORQconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (XORQ (MOVQconst [c]) x)
+ // cond: is32Bit(c)
+ // result: (XORQconst [c] x)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64MOVQconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ if !(is32Bit(c)) {
+ break
+ }
+ v.reset(OpAMD64XORQconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (XORQ x x)
+ // cond:
+ // result: (MOVQconst [0])
+ for {
+ x := v.Args[0]
+ if x != v.Args[1] {
+ break
+ }
+ v.reset(OpAMD64MOVQconst)
+ v.AuxInt = 0
+ return true
+ }
+ return false
+}
+func rewriteValueAMD64_OpAMD64XORQconst(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (XORQconst [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(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Add16 x y)
+ // cond:
+ // result: (ADDL x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpAMD64ADDL)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueAMD64_OpAdd32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Add32 x y)
+ // cond:
+ // result: (ADDL x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpAMD64ADDL)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueAMD64_OpAdd32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Add32F x y)
+ // cond:
+ // result: (ADDSS x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpAMD64ADDSS)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueAMD64_OpAdd64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Add64 x y)
+ // cond:
+ // result: (ADDQ x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpAMD64ADDQ)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueAMD64_OpAdd64F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Add64F x y)
+ // cond:
+ // result: (ADDSD x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpAMD64ADDSD)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueAMD64_OpAdd8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Add8 x y)
+ // cond:
+ // result: (ADDL x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpAMD64ADDL)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueAMD64_OpAddPtr(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (AddPtr x y)
+ // cond: config.PtrSize == 8
+ // result: (ADDQ x y)
+ for {
+ 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 {
+ 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(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (And16 x y)
+ // cond:
+ // result: (ANDL x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpAMD64ANDL)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueAMD64_OpAnd32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (And32 x y)
+ // cond:
+ // result: (ANDL x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpAMD64ANDL)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueAMD64_OpAnd64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (And64 x y)
+ // cond:
+ // result: (ANDQ x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpAMD64ANDQ)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueAMD64_OpAnd8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (And8 x y)
+ // cond:
+ // result: (ANDL x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpAMD64ANDL)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueAMD64_OpAndB(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (AndB x y)
+ // cond:
+ // result: (ANDL x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpAMD64ANDL)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueAMD64_OpAtomicAdd32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (AtomicAdd32 ptr val mem)
+ // cond:
+ // result: (AddTupleFirst32 (XADDLlock val ptr mem) val)
+ 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)
+ 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)
+ 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.AddArg(v0)
+ v.AddArg(val)
+ return true
+ }
+}
+func rewriteValueAMD64_OpAtomicAnd8(v *Value, config *Config) 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)
+ 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)
+ 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)
+ 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)
+ return true
+ }
+}
+func rewriteValueAMD64_OpAtomicLoad32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (AtomicLoad32 ptr mem)
+ // cond:
+ // result: (MOVLatomicload ptr mem)
+ for {
+ ptr := v.Args[0]
+ mem := v.Args[1]
+ v.reset(OpAMD64MOVLatomicload)
+ v.AddArg(ptr)
+ v.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)
+ for {
+ ptr := v.Args[0]
+ mem := v.Args[1]
+ v.reset(OpAMD64MOVQatomicload)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ 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)
+ for {
+ 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 {
+ 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(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)
+ 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))
+ 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.AddArg(v0)
+ 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))
+ 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.AddArg(v0)
+ 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))
+ for {
+ ptr := v.Args[0]
+ val := v.Args[1]
+ mem := v.Args[2]
+ if !(config.PtrSize == 8) {
+ break
+ }
+ v.reset(OpSelect1)
+ v0 := b.NewValue0(v.Line, OpAMD64XCHGQ, MakeTuple(config.Frontend().TypeBytePtr(), 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 <MakeTuple(config.Frontend().TypeBytePtr(),TypeMem)> val ptr mem))
+ for {
+ ptr := v.Args[0]
+ val := v.Args[1]
+ mem := v.Args[2]
+ if !(config.PtrSize == 4) {
+ break
+ }
+ v.reset(OpSelect1)
+ v0 := b.NewValue0(v.Line, OpAMD64XCHGL, MakeTuple(config.Frontend().TypeBytePtr(), TypeMem))
+ v0.AddArg(val)
+ v0.AddArg(ptr)
+ v0.AddArg(mem)
+ v.AddArg(v0)
+ 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 {
+ b := v.Block
+ _ = b
+ // match: (Bswap32 x)
+ // cond:
+ // result: (BSWAPL x)
+ for {
+ x := v.Args[0]
+ v.reset(OpAMD64BSWAPL)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueAMD64_OpBswap64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Bswap64 x)
+ // cond:
+ // result: (BSWAPQ x)
+ for {
+ x := v.Args[0]
+ v.reset(OpAMD64BSWAPQ)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueAMD64_OpClosureCall(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ClosureCall [argwid] entry closure mem)
+ // cond:
+ // result: (CALLclosure [argwid] entry closure mem)
+ for {
+ argwid := v.AuxInt
+ entry := v.Args[0]
+ closure := v.Args[1]
+ mem := v.Args[2]
+ v.reset(OpAMD64CALLclosure)
+ v.AuxInt = argwid
+ v.AddArg(entry)
+ v.AddArg(closure)
+ v.AddArg(mem)
+ return true
+ }
+}
+func rewriteValueAMD64_OpCom16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Com16 x)
+ // cond:
+ // result: (NOTL x)
+ for {
+ x := v.Args[0]
+ v.reset(OpAMD64NOTL)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueAMD64_OpCom32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Com32 x)
+ // cond:
+ // result: (NOTL x)
+ for {
+ x := v.Args[0]
+ v.reset(OpAMD64NOTL)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueAMD64_OpCom64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Com64 x)
+ // cond:
+ // result: (NOTQ x)
+ for {
+ x := v.Args[0]
+ v.reset(OpAMD64NOTQ)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueAMD64_OpCom8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Com8 x)
+ // cond:
+ // result: (NOTL x)
+ for {
+ x := v.Args[0]
+ v.reset(OpAMD64NOTL)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueAMD64_OpConst16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Const16 [val])
+ // cond:
+ // result: (MOVLconst [val])
+ for {
+ val := v.AuxInt
+ v.reset(OpAMD64MOVLconst)
+ v.AuxInt = val
+ return true
+ }
+}
+func rewriteValueAMD64_OpConst32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Const32 [val])
+ // cond:
+ // result: (MOVLconst [val])
+ for {
+ val := v.AuxInt
+ v.reset(OpAMD64MOVLconst)
+ v.AuxInt = val
+ return true
+ }
+}
+func rewriteValueAMD64_OpConst32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Const32F [val])
+ // cond:
+ // result: (MOVSSconst [val])
+ for {
+ val := v.AuxInt
+ v.reset(OpAMD64MOVSSconst)
+ v.AuxInt = val
+ return true
+ }
+}
+func rewriteValueAMD64_OpConst64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Const64 [val])
+ // cond:
+ // result: (MOVQconst [val])
+ for {
+ val := v.AuxInt
+ v.reset(OpAMD64MOVQconst)
+ v.AuxInt = val
+ return true
+ }
+}
+func rewriteValueAMD64_OpConst64F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Const64F [val])
+ // cond:
+ // result: (MOVSDconst [val])
+ for {
+ val := v.AuxInt
+ v.reset(OpAMD64MOVSDconst)
+ v.AuxInt = val
+ return true
+ }
+}
+func rewriteValueAMD64_OpConst8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Const8 [val])
+ // cond:
+ // result: (MOVLconst [val])
+ for {
+ val := v.AuxInt
+ v.reset(OpAMD64MOVLconst)
+ v.AuxInt = val
+ return true
+ }
+}
+func rewriteValueAMD64_OpConstBool(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ConstBool [b])
+ // cond:
+ // result: (MOVLconst [b])
+ for {
+ b := v.AuxInt
+ v.reset(OpAMD64MOVLconst)
+ v.AuxInt = b
+ return true
+ }
+}
+func rewriteValueAMD64_OpConstNil(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ConstNil)
+ // cond: 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(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Convert <t> x mem)
+ // cond: config.PtrSize == 8
+ // result: (MOVQconvert <t> x mem)
+ for {
+ t := v.Type
+ 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
+ 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(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)))
+ 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.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)
+ return true
+ }
+}
+func rewriteValueAMD64_OpCvt32Fto32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Cvt32Fto32 x)
+ // cond:
+ // result: (CVTTSS2SL x)
+ for {
+ x := v.Args[0]
+ v.reset(OpAMD64CVTTSS2SL)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueAMD64_OpCvt32Fto64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Cvt32Fto64 x)
+ // cond:
+ // result: (CVTTSS2SQ x)
+ for {
+ x := v.Args[0]
+ v.reset(OpAMD64CVTTSS2SQ)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueAMD64_OpCvt32Fto64F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Cvt32Fto64F x)
+ // cond:
+ // result: (CVTSS2SD x)
+ for {
+ x := v.Args[0]
+ v.reset(OpAMD64CVTSS2SD)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueAMD64_OpCvt32to32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Cvt32to32F x)
+ // cond:
+ // result: (CVTSL2SS x)
+ for {
+ x := v.Args[0]
+ v.reset(OpAMD64CVTSL2SS)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueAMD64_OpCvt32to64F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Cvt32to64F x)
+ // cond:
+ // result: (CVTSL2SD x)
+ for {
+ x := v.Args[0]
+ v.reset(OpAMD64CVTSL2SD)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueAMD64_OpCvt64Fto32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Cvt64Fto32 x)
+ // cond:
+ // result: (CVTTSD2SL x)
+ for {
+ x := v.Args[0]
+ v.reset(OpAMD64CVTTSD2SL)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueAMD64_OpCvt64Fto32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Cvt64Fto32F x)
+ // cond:
+ // result: (CVTSD2SS x)
+ for {
+ x := v.Args[0]
+ v.reset(OpAMD64CVTSD2SS)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueAMD64_OpCvt64Fto64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Cvt64Fto64 x)
+ // cond:
+ // result: (CVTTSD2SQ x)
+ for {
+ x := v.Args[0]
+ v.reset(OpAMD64CVTTSD2SQ)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueAMD64_OpCvt64to32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Cvt64to32F x)
+ // cond:
+ // result: (CVTSQ2SS x)
+ for {
+ x := v.Args[0]
+ v.reset(OpAMD64CVTSQ2SS)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueAMD64_OpCvt64to64F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Cvt64to64F x)
+ // cond:
+ // result: (CVTSQ2SD x)
+ for {
+ x := v.Args[0]
+ v.reset(OpAMD64CVTSQ2SD)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueAMD64_OpDeferCall(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (DeferCall [argwid] mem)
+ // cond:
+ // result: (CALLdefer [argwid] mem)
+ for {
+ argwid := v.AuxInt
+ mem := v.Args[0]
+ v.reset(OpAMD64CALLdefer)
+ v.AuxInt = argwid
+ v.AddArg(mem)
+ return true
+ }
+}
+func rewriteValueAMD64_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))
+ 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.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueAMD64_OpDiv16u(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Div16u x y)
+ // cond:
+ // result: (Select0 (DIVWU x 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.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueAMD64_OpDiv32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Div32 x y)
+ // cond:
+ // result: (Select0 (DIVL x 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.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueAMD64_OpDiv32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Div32F x y)
+ // cond:
+ // result: (DIVSS x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpAMD64DIVSS)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueAMD64_OpDiv32u(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Div32u x y)
+ // cond:
+ // result: (Select0 (DIVLU x 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.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueAMD64_OpDiv64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Div64 x y)
+ // cond:
+ // result: (Select0 (DIVQ x 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.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)
+ 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)))
+ 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.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.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpZeroExt8to16, config.fe.TypeUInt16())
+ v2.AddArg(y)
+ v0.AddArg(v2)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueAMD64_OpEq16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Eq16 x y)
+ // cond:
+ // result: (SETEQ (CMPW x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpAMD64SETEQ)
+ v0 := b.NewValue0(v.Line, OpAMD64CMPW, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueAMD64_OpEq32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Eq32 x y)
+ // cond:
+ // result: (SETEQ (CMPL x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpAMD64SETEQ)
+ v0 := b.NewValue0(v.Line, OpAMD64CMPL, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueAMD64_OpEq32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Eq32F x y)
+ // cond:
+ // result: (SETEQF (UCOMISS x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpAMD64SETEQF)
+ v0 := b.NewValue0(v.Line, OpAMD64UCOMISS, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueAMD64_OpEq64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Eq64 x y)
+ // cond:
+ // result: (SETEQ (CMPQ x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpAMD64SETEQ)
+ v0 := b.NewValue0(v.Line, OpAMD64CMPQ, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueAMD64_OpEq64F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Eq64F x y)
+ // cond:
+ // result: (SETEQF (UCOMISD x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpAMD64SETEQF)
+ v0 := b.NewValue0(v.Line, OpAMD64UCOMISD, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueAMD64_OpEq8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Eq8 x y)
+ // cond:
+ // result: (SETEQ (CMPB x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpAMD64SETEQ)
+ v0 := b.NewValue0(v.Line, OpAMD64CMPB, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueAMD64_OpEqB(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (EqB x y)
+ // cond:
+ // result: (SETEQ (CMPB x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpAMD64SETEQ)
+ v0 := b.NewValue0(v.Line, OpAMD64CMPB, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueAMD64_OpEqPtr(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (EqPtr x y)
+ // cond: config.PtrSize == 8
+ // result: (SETEQ (CMPQ x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ if !(config.PtrSize == 8) {
+ break
+ }
+ v.reset(OpAMD64SETEQ)
+ v0 := b.NewValue0(v.Line, OpAMD64CMPQ, 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 {
+ x := v.Args[0]
+ y := v.Args[1]
+ if !(config.PtrSize == 4) {
+ break
+ }
+ v.reset(OpAMD64SETEQ)
+ v0 := b.NewValue0(v.Line, OpAMD64CMPL, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ 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))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpAMD64SETGE)
+ v0 := b.NewValue0(v.Line, OpAMD64CMPW, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueAMD64_OpGeq16U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Geq16U x y)
+ // cond:
+ // result: (SETAE (CMPW x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpAMD64SETAE)
+ v0 := b.NewValue0(v.Line, OpAMD64CMPW, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueAMD64_OpGeq32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Geq32 x y)
+ // cond:
+ // result: (SETGE (CMPL x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpAMD64SETGE)
+ v0 := b.NewValue0(v.Line, OpAMD64CMPL, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueAMD64_OpGeq32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Geq32F x y)
+ // cond:
+ // result: (SETGEF (UCOMISS x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpAMD64SETGEF)
+ v0 := b.NewValue0(v.Line, OpAMD64UCOMISS, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueAMD64_OpGeq32U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Geq32U x y)
+ // cond:
+ // result: (SETAE (CMPL x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpAMD64SETAE)
+ v0 := b.NewValue0(v.Line, OpAMD64CMPL, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueAMD64_OpGeq64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Geq64 x y)
+ // cond:
+ // result: (SETGE (CMPQ x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpAMD64SETGE)
+ v0 := b.NewValue0(v.Line, OpAMD64CMPQ, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueAMD64_OpGeq64F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Geq64F x y)
+ // cond:
+ // result: (SETGEF (UCOMISD x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpAMD64SETGEF)
+ v0 := b.NewValue0(v.Line, OpAMD64UCOMISD, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueAMD64_OpGeq64U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Geq64U x y)
+ // cond:
+ // result: (SETAE (CMPQ x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpAMD64SETAE)
+ v0 := b.NewValue0(v.Line, OpAMD64CMPQ, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueAMD64_OpGeq8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Geq8 x y)
+ // cond:
+ // result: (SETGE (CMPB x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpAMD64SETGE)
+ v0 := b.NewValue0(v.Line, OpAMD64CMPB, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueAMD64_OpGeq8U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Geq8U x y)
+ // cond:
+ // result: (SETAE (CMPB x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpAMD64SETAE)
+ v0 := b.NewValue0(v.Line, OpAMD64CMPB, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueAMD64_OpGetClosurePtr(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (GetClosurePtr)
+ // cond:
+ // result: (LoweredGetClosurePtr)
+ for {
+ v.reset(OpAMD64LoweredGetClosurePtr)
+ return true
+ }
+}
+func rewriteValueAMD64_OpGetG(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (GetG mem)
+ // cond:
+ // result: (LoweredGetG mem)
+ for {
+ mem := v.Args[0]
+ v.reset(OpAMD64LoweredGetG)
+ v.AddArg(mem)
+ return true
+ }
+}
+func rewriteValueAMD64_OpGoCall(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (GoCall [argwid] mem)
+ // cond:
+ // result: (CALLgo [argwid] mem)
+ for {
+ argwid := v.AuxInt
+ mem := v.Args[0]
+ v.reset(OpAMD64CALLgo)
+ v.AuxInt = argwid
+ v.AddArg(mem)
+ return true
+ }
+}
+func rewriteValueAMD64_OpGreater16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Greater16 x y)
+ // cond:
+ // result: (SETG (CMPW x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpAMD64SETG)
+ v0 := b.NewValue0(v.Line, OpAMD64CMPW, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueAMD64_OpGreater16U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Greater16U x y)
+ // cond:
+ // result: (SETA (CMPW x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpAMD64SETA)
+ v0 := b.NewValue0(v.Line, OpAMD64CMPW, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueAMD64_OpGreater32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Greater32 x y)
+ // cond:
+ // result: (SETG (CMPL x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpAMD64SETG)
+ v0 := b.NewValue0(v.Line, OpAMD64CMPL, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueAMD64_OpGreater32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Greater32F x y)
+ // cond:
+ // result: (SETGF (UCOMISS x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpAMD64SETGF)
+ v0 := b.NewValue0(v.Line, OpAMD64UCOMISS, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueAMD64_OpGreater32U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Greater32U x y)
+ // cond:
+ // result: (SETA (CMPL x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpAMD64SETA)
+ v0 := b.NewValue0(v.Line, OpAMD64CMPL, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueAMD64_OpGreater64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Greater64 x y)
+ // cond:
+ // result: (SETG (CMPQ x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpAMD64SETG)
+ v0 := b.NewValue0(v.Line, OpAMD64CMPQ, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueAMD64_OpGreater64F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Greater64F x y)
+ // cond:
+ // result: (SETGF (UCOMISD x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpAMD64SETGF)
+ v0 := b.NewValue0(v.Line, OpAMD64UCOMISD, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueAMD64_OpGreater64U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Greater64U x y)
+ // cond:
+ // result: (SETA (CMPQ x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpAMD64SETA)
+ v0 := b.NewValue0(v.Line, OpAMD64CMPQ, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueAMD64_OpGreater8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Greater8 x y)
+ // cond:
+ // result: (SETG (CMPB x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpAMD64SETG)
+ v0 := b.NewValue0(v.Line, OpAMD64CMPB, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueAMD64_OpGreater8U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Greater8U x y)
+ // cond:
+ // result: (SETA (CMPB x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpAMD64SETA)
+ v0 := b.NewValue0(v.Line, OpAMD64CMPB, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueAMD64_OpHmul16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Hmul16 x y)
+ // cond:
+ // result: (HMULW x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpAMD64HMULW)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueAMD64_OpHmul16u(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Hmul16u x y)
+ // cond:
+ // result: (HMULWU x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpAMD64HMULWU)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueAMD64_OpHmul32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Hmul32 x y)
+ // cond:
+ // result: (HMULL x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpAMD64HMULL)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueAMD64_OpHmul32u(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Hmul32u x y)
+ // cond:
+ // result: (HMULLU x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpAMD64HMULLU)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueAMD64_OpHmul64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Hmul64 x y)
+ // cond:
+ // result: (HMULQ x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpAMD64HMULQ)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueAMD64_OpHmul64u(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Hmul64u x y)
+ // cond:
+ // result: (HMULQU x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpAMD64HMULQU)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueAMD64_OpHmul8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Hmul8 x y)
+ // cond:
+ // result: (HMULB x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpAMD64HMULB)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueAMD64_OpHmul8u(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Hmul8u x y)
+ // cond:
+ // result: (HMULBU x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpAMD64HMULBU)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueAMD64_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) {
+ break
+ }
+ v.reset(OpAMD64SETNE)
+ v0 := b.NewValue0(v.Line, OpAMD64TESTQ, 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
}
- 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
+ v.reset(OpAMD64SETNE)
+ v0 := b.NewValue0(v.Line, OpAMD64TESTL, TypeFlags)
v0.AddArg(p)
- v0.AddArg(idx)
- v0.AddArg(mem)
+ v0.AddArg(p)
+ v.AddArg(v0)
return true
}
return false
}
-func rewriteValueAMD64_OpAMD64ORQconst(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpIsSliceInBounds(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (ORQconst [0] x)
+ // match: (IsSliceInBounds idx len)
// cond:
- // result: x
+ // result: (SETBE (CMPQ idx len))
for {
- if v.AuxInt != 0 {
- break
- }
- x := v.Args[0]
- v.reset(OpCopy)
- v.Type = x.Type
- v.AddArg(x)
+ idx := v.Args[0]
+ len := v.Args[1]
+ v.reset(OpAMD64SETBE)
+ v0 := b.NewValue0(v.Line, OpAMD64CMPQ, TypeFlags)
+ v0.AddArg(idx)
+ v0.AddArg(len)
+ v.AddArg(v0)
return true
}
- // match: (ORQconst [-1] _)
+}
+func rewriteValueAMD64_OpLeq16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Leq16 x y)
// cond:
- // result: (MOVQconst [-1])
+ // result: (SETLE (CMPW x y))
for {
- if v.AuxInt != -1 {
- break
- }
- v.reset(OpAMD64MOVQconst)
- v.AuxInt = -1
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpAMD64SETLE)
+ v0 := b.NewValue0(v.Line, OpAMD64CMPW, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
return true
}
- // match: (ORQconst [c] (MOVQconst [d]))
+}
+func rewriteValueAMD64_OpLeq16U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Leq16U x y)
// cond:
- // result: (MOVQconst [c|d])
+ // result: (SETBE (CMPW x y))
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
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpAMD64SETBE)
+ v0 := b.NewValue0(v.Line, OpAMD64CMPW, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
return true
}
- return false
}
-func rewriteValueAMD64_OpOffPtr(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpLeq32(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (OffPtr [off] ptr)
- // cond: is32Bit(off)
- // result: (ADDQconst [off] ptr)
+ // match: (Leq32 x y)
+ // cond:
+ // result: (SETLE (CMPL x y))
for {
- off := v.AuxInt
- ptr := v.Args[0]
- if !(is32Bit(off)) {
- break
- }
- v.reset(OpAMD64ADDQconst)
- v.AuxInt = off
- v.AddArg(ptr)
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpAMD64SETLE)
+ v0 := b.NewValue0(v.Line, OpAMD64CMPL, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
return true
}
- // match: (OffPtr [off] ptr)
+}
+func rewriteValueAMD64_OpLeq32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Leq32F x y)
// cond:
- // result: (ADDQ (MOVQconst [off]) ptr)
+ // result: (SETGEF (UCOMISS y x))
for {
- off := v.AuxInt
- ptr := v.Args[0]
- v.reset(OpAMD64ADDQ)
- v0 := b.NewValue0(v.Line, OpAMD64MOVQconst, config.fe.TypeUInt64())
- v0.AuxInt = off
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpAMD64SETGEF)
+ v0 := b.NewValue0(v.Line, OpAMD64UCOMISS, TypeFlags)
+ v0.AddArg(y)
+ v0.AddArg(x)
v.AddArg(v0)
- v.AddArg(ptr)
return true
}
}
-func rewriteValueAMD64_OpOr16(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpLeq32U(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (Or16 x y)
+ // match: (Leq32U x y)
// cond:
- // result: (ORL x y)
+ // result: (SETBE (CMPL x y))
for {
x := v.Args[0]
y := v.Args[1]
- v.reset(OpAMD64ORL)
- v.AddArg(x)
- v.AddArg(y)
+ v.reset(OpAMD64SETBE)
+ v0 := b.NewValue0(v.Line, OpAMD64CMPL, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
return true
}
}
-func rewriteValueAMD64_OpOr32(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpLeq64(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (Or32 x y)
+ // match: (Leq64 x y)
// cond:
- // result: (ORL x y)
+ // result: (SETLE (CMPQ x y))
for {
x := v.Args[0]
y := v.Args[1]
- v.reset(OpAMD64ORL)
- v.AddArg(x)
- v.AddArg(y)
+ v.reset(OpAMD64SETLE)
+ v0 := b.NewValue0(v.Line, OpAMD64CMPQ, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
return true
}
}
-func rewriteValueAMD64_OpOr64(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpLeq64F(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (Or64 x y)
+ // match: (Leq64F x y)
// cond:
- // result: (ORQ x y)
+ // result: (SETGEF (UCOMISD y x))
for {
x := v.Args[0]
y := v.Args[1]
- v.reset(OpAMD64ORQ)
- v.AddArg(x)
- v.AddArg(y)
+ v.reset(OpAMD64SETGEF)
+ v0 := b.NewValue0(v.Line, OpAMD64UCOMISD, TypeFlags)
+ v0.AddArg(y)
+ v0.AddArg(x)
+ v.AddArg(v0)
return true
}
}
-func rewriteValueAMD64_OpOr8(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpLeq64U(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (Or8 x y)
+ // match: (Leq64U x y)
// cond:
- // result: (ORL x y)
+ // result: (SETBE (CMPQ x y))
for {
x := v.Args[0]
y := v.Args[1]
- v.reset(OpAMD64ORL)
- v.AddArg(x)
- v.AddArg(y)
+ v.reset(OpAMD64SETBE)
+ v0 := b.NewValue0(v.Line, OpAMD64CMPQ, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
return true
}
}
-func rewriteValueAMD64_OpOrB(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpLeq8(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (OrB x y)
+ // match: (Leq8 x y)
// cond:
- // result: (ORL x y)
+ // result: (SETLE (CMPB x y))
for {
x := v.Args[0]
y := v.Args[1]
- v.reset(OpAMD64ORL)
- v.AddArg(x)
- v.AddArg(y)
+ v.reset(OpAMD64SETLE)
+ v0 := b.NewValue0(v.Line, OpAMD64CMPB, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
return true
}
}
-func rewriteValueAMD64_OpRsh16Ux16(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpLeq8U(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (Rsh16Ux16 <t> x y)
+ // match: (Leq8U x y)
// cond:
- // result: (ANDL (SHRW <t> x y) (SBBLcarrymask <t> (CMPWconst y [16])))
+ // result: (SETBE (CMPB x y))
for {
- t := v.Type
x := v.Args[0]
y := v.Args[1]
- v.reset(OpAMD64ANDL)
- v0 := b.NewValue0(v.Line, OpAMD64SHRW, t)
+ v.reset(OpAMD64SETBE)
+ v0 := b.NewValue0(v.Line, OpAMD64CMPB, TypeFlags)
v0.AddArg(x)
v0.AddArg(y)
v.AddArg(v0)
- v1 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, t)
- v2 := b.NewValue0(v.Line, OpAMD64CMPWconst, TypeFlags)
- v2.AddArg(y)
- v2.AuxInt = 16
- v1.AddArg(v2)
- v.AddArg(v1)
return true
}
}
-func rewriteValueAMD64_OpRsh16Ux32(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpLess16(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (Rsh16Ux32 <t> x y)
+ // match: (Less16 x y)
// cond:
- // result: (ANDL (SHRW <t> x y) (SBBLcarrymask <t> (CMPLconst y [16])))
+ // result: (SETL (CMPW x y))
for {
- t := v.Type
x := v.Args[0]
y := v.Args[1]
- v.reset(OpAMD64ANDL)
- v0 := b.NewValue0(v.Line, OpAMD64SHRW, t)
+ v.reset(OpAMD64SETL)
+ v0 := b.NewValue0(v.Line, OpAMD64CMPW, TypeFlags)
v0.AddArg(x)
v0.AddArg(y)
v.AddArg(v0)
- v1 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, t)
- v2 := b.NewValue0(v.Line, OpAMD64CMPLconst, TypeFlags)
- v2.AddArg(y)
- v2.AuxInt = 16
- v1.AddArg(v2)
- v.AddArg(v1)
return true
}
}
-func rewriteValueAMD64_OpRsh16Ux64(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpLess16U(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (Rsh16Ux64 <t> x y)
+ // match: (Less16U x y)
// cond:
- // result: (ANDL (SHRW <t> x y) (SBBLcarrymask <t> (CMPQconst y [16])))
+ // result: (SETB (CMPW x y))
for {
- t := v.Type
x := v.Args[0]
y := v.Args[1]
- v.reset(OpAMD64ANDL)
- v0 := b.NewValue0(v.Line, OpAMD64SHRW, t)
+ v.reset(OpAMD64SETB)
+ v0 := b.NewValue0(v.Line, OpAMD64CMPW, TypeFlags)
v0.AddArg(x)
v0.AddArg(y)
v.AddArg(v0)
- v1 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, t)
- v2 := b.NewValue0(v.Line, OpAMD64CMPQconst, TypeFlags)
- v2.AddArg(y)
- v2.AuxInt = 16
- v1.AddArg(v2)
- v.AddArg(v1)
return true
}
}
-func rewriteValueAMD64_OpRsh16Ux8(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpLess32(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (Rsh16Ux8 <t> x y)
+ // match: (Less32 x y)
// cond:
- // result: (ANDL (SHRW <t> x y) (SBBLcarrymask <t> (CMPBconst y [16])))
+ // result: (SETL (CMPL x y))
for {
- t := v.Type
x := v.Args[0]
y := v.Args[1]
- v.reset(OpAMD64ANDL)
- v0 := b.NewValue0(v.Line, OpAMD64SHRW, t)
+ v.reset(OpAMD64SETL)
+ v0 := b.NewValue0(v.Line, OpAMD64CMPL, TypeFlags)
v0.AddArg(x)
v0.AddArg(y)
v.AddArg(v0)
- v1 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, t)
- v2 := b.NewValue0(v.Line, OpAMD64CMPBconst, TypeFlags)
- v2.AddArg(y)
- v2.AuxInt = 16
- v1.AddArg(v2)
- v.AddArg(v1)
return true
}
}
-func rewriteValueAMD64_OpRsh16x16(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpLess32F(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (Rsh16x16 <t> x y)
+ // match: (Less32F x y)
// cond:
- // result: (SARW <t> x (ORL <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPWconst y [16])))))
+ // result: (SETGF (UCOMISS y x))
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)
+ v.reset(OpAMD64SETGF)
+ v0 := b.NewValue0(v.Line, OpAMD64UCOMISS, TypeFlags)
v0.AddArg(y)
- v1 := b.NewValue0(v.Line, OpAMD64NOTL, y.Type)
- v2 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, y.Type)
- v3 := b.NewValue0(v.Line, OpAMD64CMPWconst, TypeFlags)
- v3.AddArg(y)
- v3.AuxInt = 16
- v2.AddArg(v3)
- v1.AddArg(v2)
- v0.AddArg(v1)
+ v0.AddArg(x)
v.AddArg(v0)
return true
}
}
-func rewriteValueAMD64_OpRsh16x32(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpLess32U(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (Rsh16x32 <t> x y)
+ // match: (Less32U x y)
// cond:
- // result: (SARW <t> x (ORL <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPLconst y [16])))))
+ // result: (SETB (CMPL x 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)
+ v.reset(OpAMD64SETB)
+ v0 := b.NewValue0(v.Line, OpAMD64CMPL, TypeFlags)
+ v0.AddArg(x)
v0.AddArg(y)
- v1 := b.NewValue0(v.Line, OpAMD64NOTL, y.Type)
- v2 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, y.Type)
- v3 := b.NewValue0(v.Line, OpAMD64CMPLconst, TypeFlags)
- v3.AddArg(y)
- v3.AuxInt = 16
- v2.AddArg(v3)
- v1.AddArg(v2)
- v0.AddArg(v1)
v.AddArg(v0)
return true
}
}
-func rewriteValueAMD64_OpRsh16x64(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpLess64(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (Rsh16x64 <t> x y)
+ // match: (Less64 x y)
// cond:
- // result: (SARW <t> x (ORQ <y.Type> y (NOTQ <y.Type> (SBBQcarrymask <y.Type> (CMPQconst y [16])))))
+ // result: (SETL (CMPQ x 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)
+ v.reset(OpAMD64SETL)
+ v0 := b.NewValue0(v.Line, OpAMD64CMPQ, TypeFlags)
+ v0.AddArg(x)
v0.AddArg(y)
- v1 := b.NewValue0(v.Line, OpAMD64NOTQ, y.Type)
- v2 := b.NewValue0(v.Line, OpAMD64SBBQcarrymask, y.Type)
- v3 := b.NewValue0(v.Line, OpAMD64CMPQconst, TypeFlags)
- v3.AddArg(y)
- v3.AuxInt = 16
- v2.AddArg(v3)
- v1.AddArg(v2)
- v0.AddArg(v1)
v.AddArg(v0)
return true
}
}
-func rewriteValueAMD64_OpRsh16x8(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpLess64F(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (Rsh16x8 <t> x y)
+ // match: (Less64F x y)
// cond:
- // result: (SARW <t> x (ORL <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPBconst y [16])))))
+ // result: (SETGF (UCOMISD y x))
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)
+ v.reset(OpAMD64SETGF)
+ v0 := b.NewValue0(v.Line, OpAMD64UCOMISD, TypeFlags)
v0.AddArg(y)
- v1 := b.NewValue0(v.Line, OpAMD64NOTL, y.Type)
- v2 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, y.Type)
- v3 := b.NewValue0(v.Line, OpAMD64CMPBconst, TypeFlags)
- v3.AddArg(y)
- v3.AuxInt = 16
- v2.AddArg(v3)
- v1.AddArg(v2)
- v0.AddArg(v1)
+ v0.AddArg(x)
v.AddArg(v0)
return true
}
}
-func rewriteValueAMD64_OpRsh32Ux16(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpLess64U(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (Rsh32Ux16 <t> x y)
+ // match: (Less64U x y)
// cond:
- // result: (ANDL (SHRL <t> x y) (SBBLcarrymask <t> (CMPWconst y [32])))
+ // result: (SETB (CMPQ x y))
for {
- t := v.Type
x := v.Args[0]
y := v.Args[1]
- v.reset(OpAMD64ANDL)
- v0 := b.NewValue0(v.Line, OpAMD64SHRL, t)
+ v.reset(OpAMD64SETB)
+ v0 := b.NewValue0(v.Line, OpAMD64CMPQ, TypeFlags)
v0.AddArg(x)
v0.AddArg(y)
v.AddArg(v0)
- v1 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, t)
- v2 := b.NewValue0(v.Line, OpAMD64CMPWconst, TypeFlags)
- v2.AddArg(y)
- v2.AuxInt = 32
- v1.AddArg(v2)
- v.AddArg(v1)
return true
}
}
-func rewriteValueAMD64_OpRsh32Ux32(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpLess8(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (Rsh32Ux32 <t> x y)
+ // match: (Less8 x y)
// cond:
- // result: (ANDL (SHRL <t> x y) (SBBLcarrymask <t> (CMPLconst y [32])))
+ // result: (SETL (CMPB x y))
for {
- t := v.Type
x := v.Args[0]
y := v.Args[1]
- v.reset(OpAMD64ANDL)
- v0 := b.NewValue0(v.Line, OpAMD64SHRL, t)
+ v.reset(OpAMD64SETL)
+ v0 := b.NewValue0(v.Line, OpAMD64CMPB, TypeFlags)
v0.AddArg(x)
v0.AddArg(y)
v.AddArg(v0)
- v1 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, t)
- v2 := b.NewValue0(v.Line, OpAMD64CMPLconst, TypeFlags)
- v2.AddArg(y)
- v2.AuxInt = 32
- v1.AddArg(v2)
- v.AddArg(v1)
return true
}
}
-func rewriteValueAMD64_OpRsh32Ux64(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpLess8U(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (Rsh32Ux64 <t> x y)
+ // match: (Less8U x y)
// cond:
- // result: (ANDL (SHRL <t> x y) (SBBLcarrymask <t> (CMPQconst y [32])))
+ // result: (SETB (CMPB x y))
for {
- t := v.Type
x := v.Args[0]
y := v.Args[1]
- v.reset(OpAMD64ANDL)
- v0 := b.NewValue0(v.Line, OpAMD64SHRL, t)
+ v.reset(OpAMD64SETB)
+ v0 := b.NewValue0(v.Line, OpAMD64CMPB, TypeFlags)
v0.AddArg(x)
v0.AddArg(y)
v.AddArg(v0)
- v1 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, t)
- v2 := b.NewValue0(v.Line, OpAMD64CMPQconst, TypeFlags)
- v2.AddArg(y)
- v2.AuxInt = 32
- v1.AddArg(v2)
- v.AddArg(v1)
return true
}
}
-func rewriteValueAMD64_OpRsh32Ux8(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpLoad(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])))
+ // match: (Load <t> ptr mem)
+ // cond: (is64BitInt(t) || isPtr(t) && config.PtrSize == 8)
+ // result: (MOVQload ptr mem)
for {
t := v.Type
- x := v.Args[0]
- y := v.Args[1]
- v.reset(OpAMD64ANDL)
- v0 := b.NewValue0(v.Line, OpAMD64SHRL, t)
- v0.AddArg(x)
- v0.AddArg(y)
- v.AddArg(v0)
- v1 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, t)
- v2 := b.NewValue0(v.Line, OpAMD64CMPBconst, TypeFlags)
- v2.AddArg(y)
- v2.AuxInt = 32
- v1.AddArg(v2)
- v.AddArg(v1)
+ 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
+ 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
+ ptr := v.Args[0]
+ mem := v.Args[1]
+ if !(is16BitInt(t)) {
+ break
+ }
+ v.reset(OpAMD64MOVWload)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (Load <t> ptr mem)
+ // cond: (t.IsBoolean() || is8BitInt(t))
+ // result: (MOVBload ptr mem)
+ for {
+ t := v.Type
+ ptr := v.Args[0]
+ mem := v.Args[1]
+ if !(t.IsBoolean() || is8BitInt(t)) {
+ break
+ }
+ v.reset(OpAMD64MOVBload)
+ v.AddArg(ptr)
+ v.AddArg(mem)
return true
}
+ // match: (Load <t> ptr mem)
+ // cond: is32BitFloat(t)
+ // result: (MOVSSload ptr mem)
+ for {
+ t := v.Type
+ ptr := v.Args[0]
+ mem := v.Args[1]
+ if !(is32BitFloat(t)) {
+ break
+ }
+ v.reset(OpAMD64MOVSSload)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (Load <t> ptr mem)
+ // cond: is64BitFloat(t)
+ // result: (MOVSDload ptr mem)
+ for {
+ t := v.Type
+ ptr := v.Args[0]
+ mem := v.Args[1]
+ if !(is64BitFloat(t)) {
+ break
+ }
+ v.reset(OpAMD64MOVSDload)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ return false
}
-func rewriteValueAMD64_OpRsh32x16(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpLrot16(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (Rsh32x16 <t> x y)
+ // match: (Lrot16 <t> x [c])
// cond:
- // result: (SARL <t> x (ORL <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPWconst y [32])))))
+ // result: (ROLWconst <t> [c&15] x)
for {
t := v.Type
+ c := v.AuxInt
x := v.Args[0]
- y := v.Args[1]
- v.reset(OpAMD64SARL)
+ v.reset(OpAMD64ROLWconst)
v.Type = t
+ v.AuxInt = c & 15
v.AddArg(x)
- v0 := b.NewValue0(v.Line, OpAMD64ORL, y.Type)
- v0.AddArg(y)
- v1 := b.NewValue0(v.Line, OpAMD64NOTL, y.Type)
- v2 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, y.Type)
- v3 := b.NewValue0(v.Line, OpAMD64CMPWconst, TypeFlags)
- v3.AddArg(y)
- v3.AuxInt = 32
- v2.AddArg(v3)
- v1.AddArg(v2)
- v0.AddArg(v1)
- v.AddArg(v0)
return true
}
}
-func rewriteValueAMD64_OpRsh32x32(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpLrot32(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (Rsh32x32 <t> x y)
+ // match: (Lrot32 <t> x [c])
// cond:
- // result: (SARL <t> x (ORL <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPLconst y [32])))))
+ // result: (ROLLconst <t> [c&31] x)
for {
t := v.Type
+ c := v.AuxInt
x := v.Args[0]
- y := v.Args[1]
- v.reset(OpAMD64SARL)
+ v.reset(OpAMD64ROLLconst)
v.Type = t
+ v.AuxInt = c & 31
v.AddArg(x)
- v0 := b.NewValue0(v.Line, OpAMD64ORL, y.Type)
- v0.AddArg(y)
- v1 := b.NewValue0(v.Line, OpAMD64NOTL, y.Type)
- v2 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, y.Type)
- v3 := b.NewValue0(v.Line, OpAMD64CMPLconst, TypeFlags)
- v3.AddArg(y)
- v3.AuxInt = 32
- v2.AddArg(v3)
- v1.AddArg(v2)
- v0.AddArg(v1)
- v.AddArg(v0)
return true
}
}
-func rewriteValueAMD64_OpRsh32x64(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpLrot64(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (Rsh32x64 <t> x y)
+ // match: (Lrot64 <t> x [c])
// cond:
- // result: (SARL <t> x (ORQ <y.Type> y (NOTQ <y.Type> (SBBQcarrymask <y.Type> (CMPQconst y [32])))))
+ // result: (ROLQconst <t> [c&63] x)
for {
t := v.Type
+ c := v.AuxInt
x := v.Args[0]
- y := v.Args[1]
- v.reset(OpAMD64SARL)
+ v.reset(OpAMD64ROLQconst)
v.Type = t
+ v.AuxInt = c & 63
v.AddArg(x)
- v0 := b.NewValue0(v.Line, OpAMD64ORQ, y.Type)
- v0.AddArg(y)
- v1 := b.NewValue0(v.Line, OpAMD64NOTQ, y.Type)
- v2 := b.NewValue0(v.Line, OpAMD64SBBQcarrymask, y.Type)
- v3 := b.NewValue0(v.Line, OpAMD64CMPQconst, TypeFlags)
- v3.AddArg(y)
- v3.AuxInt = 32
- v2.AddArg(v3)
- v1.AddArg(v2)
- v0.AddArg(v1)
- v.AddArg(v0)
return true
}
}
-func rewriteValueAMD64_OpRsh32x8(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpLrot8(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (Rsh32x8 <t> x y)
+ // match: (Lrot8 <t> x [c])
// cond:
- // result: (SARL <t> x (ORL <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPBconst y [32])))))
+ // result: (ROLBconst <t> [c&7] x)
for {
t := v.Type
+ c := v.AuxInt
x := v.Args[0]
- y := v.Args[1]
- v.reset(OpAMD64SARL)
+ v.reset(OpAMD64ROLBconst)
v.Type = t
+ v.AuxInt = c & 7
v.AddArg(x)
- v0 := b.NewValue0(v.Line, OpAMD64ORL, y.Type)
- v0.AddArg(y)
- v1 := b.NewValue0(v.Line, OpAMD64NOTL, y.Type)
- v2 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, y.Type)
- v3 := b.NewValue0(v.Line, OpAMD64CMPBconst, TypeFlags)
- v3.AddArg(y)
- v3.AuxInt = 32
- v2.AddArg(v3)
- v1.AddArg(v2)
- v0.AddArg(v1)
- v.AddArg(v0)
return true
}
}
-func rewriteValueAMD64_OpRsh64Ux16(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpLsh16x16(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (Rsh64Ux16 <t> x y)
+ // match: (Lsh16x16 <t> x y)
// cond:
- // result: (ANDQ (SHRQ <t> x y) (SBBQcarrymask <t> (CMPWconst y [64])))
+ // result: (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPWconst y [32])))
for {
t := v.Type
x := v.Args[0]
y := v.Args[1]
- v.reset(OpAMD64ANDQ)
- v0 := b.NewValue0(v.Line, OpAMD64SHRQ, t)
+ v.reset(OpAMD64ANDL)
+ v0 := b.NewValue0(v.Line, OpAMD64SHLL, t)
v0.AddArg(x)
v0.AddArg(y)
v.AddArg(v0)
- v1 := b.NewValue0(v.Line, OpAMD64SBBQcarrymask, t)
+ v1 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, t)
v2 := b.NewValue0(v.Line, OpAMD64CMPWconst, TypeFlags)
+ v2.AuxInt = 32
v2.AddArg(y)
- v2.AuxInt = 64
v1.AddArg(v2)
v.AddArg(v1)
return true
}
}
-func rewriteValueAMD64_OpRsh64Ux32(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpLsh16x32(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (Rsh64Ux32 <t> x y)
+ // match: (Lsh16x32 <t> x y)
// cond:
- // result: (ANDQ (SHRQ <t> x y) (SBBQcarrymask <t> (CMPLconst y [64])))
+ // result: (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPLconst y [32])))
for {
t := v.Type
x := v.Args[0]
y := v.Args[1]
- v.reset(OpAMD64ANDQ)
- v0 := b.NewValue0(v.Line, OpAMD64SHRQ, t)
+ v.reset(OpAMD64ANDL)
+ v0 := b.NewValue0(v.Line, OpAMD64SHLL, t)
v0.AddArg(x)
v0.AddArg(y)
v.AddArg(v0)
- v1 := b.NewValue0(v.Line, OpAMD64SBBQcarrymask, t)
+ v1 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, t)
v2 := b.NewValue0(v.Line, OpAMD64CMPLconst, TypeFlags)
+ v2.AuxInt = 32
v2.AddArg(y)
- v2.AuxInt = 64
v1.AddArg(v2)
v.AddArg(v1)
return true
}
}
-func rewriteValueAMD64_OpRsh64Ux64(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpLsh16x64(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (Rsh64Ux64 <t> x y)
+ // match: (Lsh16x64 <t> x y)
// cond:
- // result: (ANDQ (SHRQ <t> x y) (SBBQcarrymask <t> (CMPQconst y [64])))
+ // result: (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPQconst y [32])))
for {
t := v.Type
x := v.Args[0]
y := v.Args[1]
- v.reset(OpAMD64ANDQ)
- v0 := b.NewValue0(v.Line, OpAMD64SHRQ, t)
+ v.reset(OpAMD64ANDL)
+ v0 := b.NewValue0(v.Line, OpAMD64SHLL, t)
v0.AddArg(x)
v0.AddArg(y)
v.AddArg(v0)
- v1 := b.NewValue0(v.Line, OpAMD64SBBQcarrymask, t)
+ v1 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, t)
v2 := b.NewValue0(v.Line, OpAMD64CMPQconst, TypeFlags)
+ v2.AuxInt = 32
v2.AddArg(y)
- v2.AuxInt = 64
v1.AddArg(v2)
v.AddArg(v1)
return true
}
}
-func rewriteValueAMD64_OpRsh64Ux8(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpLsh16x8(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (Rsh64Ux8 <t> x y)
+ // match: (Lsh16x8 <t> x y)
// cond:
- // result: (ANDQ (SHRQ <t> x y) (SBBQcarrymask <t> (CMPBconst y [64])))
+ // result: (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPBconst y [32])))
for {
t := v.Type
x := v.Args[0]
y := v.Args[1]
- v.reset(OpAMD64ANDQ)
- v0 := b.NewValue0(v.Line, OpAMD64SHRQ, t)
+ v.reset(OpAMD64ANDL)
+ v0 := b.NewValue0(v.Line, OpAMD64SHLL, t)
v0.AddArg(x)
v0.AddArg(y)
v.AddArg(v0)
- v1 := b.NewValue0(v.Line, OpAMD64SBBQcarrymask, t)
+ v1 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, t)
v2 := b.NewValue0(v.Line, OpAMD64CMPBconst, TypeFlags)
+ v2.AuxInt = 32
v2.AddArg(y)
- v2.AuxInt = 64
v1.AddArg(v2)
v.AddArg(v1)
return true
}
}
-func rewriteValueAMD64_OpRsh64x16(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Rsh64x16 <t> x y)
- // cond:
- // result: (SARQ <t> x (ORL <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPWconst y [64])))))
- for {
- t := v.Type
- x := v.Args[0]
- y := v.Args[1]
- v.reset(OpAMD64SARQ)
- v.Type = t
- v.AddArg(x)
- v0 := b.NewValue0(v.Line, OpAMD64ORL, y.Type)
- v0.AddArg(y)
- v1 := b.NewValue0(v.Line, OpAMD64NOTL, y.Type)
- v2 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, y.Type)
- v3 := b.NewValue0(v.Line, OpAMD64CMPWconst, TypeFlags)
- v3.AddArg(y)
- v3.AuxInt = 64
- v2.AddArg(v3)
- v1.AddArg(v2)
- v0.AddArg(v1)
- v.AddArg(v0)
- return true
- }
-}
-func rewriteValueAMD64_OpRsh64x32(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Rsh64x32 <t> x y)
- // cond:
- // result: (SARQ <t> x (ORL <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPLconst y [64])))))
- for {
- t := v.Type
- x := v.Args[0]
- y := v.Args[1]
- v.reset(OpAMD64SARQ)
- v.Type = t
- v.AddArg(x)
- v0 := b.NewValue0(v.Line, OpAMD64ORL, y.Type)
- v0.AddArg(y)
- v1 := b.NewValue0(v.Line, OpAMD64NOTL, y.Type)
- v2 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, y.Type)
- v3 := b.NewValue0(v.Line, OpAMD64CMPLconst, TypeFlags)
- v3.AddArg(y)
- v3.AuxInt = 64
- v2.AddArg(v3)
- v1.AddArg(v2)
- v0.AddArg(v1)
- v.AddArg(v0)
- return true
- }
-}
-func rewriteValueAMD64_OpRsh64x64(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Rsh64x64 <t> x y)
- // cond:
- // result: (SARQ <t> x (ORQ <y.Type> y (NOTQ <y.Type> (SBBQcarrymask <y.Type> (CMPQconst y [64])))))
- for {
- t := v.Type
- x := v.Args[0]
- y := v.Args[1]
- v.reset(OpAMD64SARQ)
- v.Type = t
- v.AddArg(x)
- v0 := b.NewValue0(v.Line, OpAMD64ORQ, y.Type)
- v0.AddArg(y)
- v1 := b.NewValue0(v.Line, OpAMD64NOTQ, y.Type)
- v2 := b.NewValue0(v.Line, OpAMD64SBBQcarrymask, y.Type)
- v3 := b.NewValue0(v.Line, OpAMD64CMPQconst, TypeFlags)
- v3.AddArg(y)
- v3.AuxInt = 64
- v2.AddArg(v3)
- v1.AddArg(v2)
- v0.AddArg(v1)
- v.AddArg(v0)
- return true
- }
-}
-func rewriteValueAMD64_OpRsh64x8(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Rsh64x8 <t> x y)
- // cond:
- // result: (SARQ <t> x (ORL <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPBconst y [64])))))
- for {
- t := v.Type
- x := v.Args[0]
- y := v.Args[1]
- v.reset(OpAMD64SARQ)
- v.Type = t
- v.AddArg(x)
- v0 := b.NewValue0(v.Line, OpAMD64ORL, y.Type)
- v0.AddArg(y)
- v1 := b.NewValue0(v.Line, OpAMD64NOTL, y.Type)
- v2 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, y.Type)
- v3 := b.NewValue0(v.Line, OpAMD64CMPBconst, TypeFlags)
- v3.AddArg(y)
- v3.AuxInt = 64
- v2.AddArg(v3)
- v1.AddArg(v2)
- v0.AddArg(v1)
- v.AddArg(v0)
- return true
- }
-}
-func rewriteValueAMD64_OpRsh8Ux16(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpLsh32x16(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (Rsh8Ux16 <t> x y)
+ // match: (Lsh32x16 <t> x y)
// cond:
- // result: (ANDL (SHRB <t> x y) (SBBLcarrymask <t> (CMPWconst y [8])))
+ // result: (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPWconst y [32])))
for {
t := v.Type
x := v.Args[0]
y := v.Args[1]
v.reset(OpAMD64ANDL)
- v0 := b.NewValue0(v.Line, OpAMD64SHRB, t)
+ 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)
- v2.AuxInt = 8
v1.AddArg(v2)
v.AddArg(v1)
return true
}
}
-func rewriteValueAMD64_OpRsh8Ux32(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpLsh32x32(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (Rsh8Ux32 <t> x y)
+ // match: (Lsh32x32 <t> x y)
// cond:
- // result: (ANDL (SHRB <t> x y) (SBBLcarrymask <t> (CMPLconst y [8])))
+ // result: (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPLconst y [32])))
for {
t := v.Type
x := v.Args[0]
y := v.Args[1]
v.reset(OpAMD64ANDL)
- v0 := b.NewValue0(v.Line, OpAMD64SHRB, t)
+ 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)
- v2.AuxInt = 8
v1.AddArg(v2)
v.AddArg(v1)
return true
}
}
-func rewriteValueAMD64_OpRsh8Ux64(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpLsh32x64(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (Rsh8Ux64 <t> x y)
+ // match: (Lsh32x64 <t> x y)
// cond:
- // result: (ANDL (SHRB <t> x y) (SBBLcarrymask <t> (CMPQconst y [8])))
+ // result: (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPQconst y [32])))
for {
t := v.Type
x := v.Args[0]
y := v.Args[1]
v.reset(OpAMD64ANDL)
- v0 := b.NewValue0(v.Line, OpAMD64SHRB, t)
+ 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)
- v2.AuxInt = 8
v1.AddArg(v2)
v.AddArg(v1)
return true
}
}
-func rewriteValueAMD64_OpRsh8Ux8(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpLsh32x8(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (Rsh8Ux8 <t> x y)
+ // match: (Lsh32x8 <t> x y)
// cond:
- // result: (ANDL (SHRB <t> x y) (SBBLcarrymask <t> (CMPBconst y [8])))
+ // result: (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPBconst y [32])))
for {
t := v.Type
x := v.Args[0]
y := v.Args[1]
v.reset(OpAMD64ANDL)
- v0 := b.NewValue0(v.Line, OpAMD64SHRB, t)
+ 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)
- v2.AuxInt = 8
v1.AddArg(v2)
v.AddArg(v1)
return true
}
}
-func rewriteValueAMD64_OpRsh8x16(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpLsh64x16(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (Rsh8x16 <t> x y)
+ // match: (Lsh64x16 <t> x y)
// cond:
- // result: (SARB <t> x (ORL <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPWconst y [8])))))
+ // result: (ANDQ (SHLQ <t> x y) (SBBQcarrymask <t> (CMPWconst y [64])))
for {
t := v.Type
x := v.Args[0]
y := v.Args[1]
- v.reset(OpAMD64SARB)
- v.Type = t
- v.AddArg(x)
- v0 := b.NewValue0(v.Line, OpAMD64ORL, y.Type)
+ v.reset(OpAMD64ANDQ)
+ v0 := b.NewValue0(v.Line, OpAMD64SHLQ, t)
+ v0.AddArg(x)
v0.AddArg(y)
- v1 := b.NewValue0(v.Line, OpAMD64NOTL, y.Type)
- v2 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, y.Type)
- v3 := b.NewValue0(v.Line, OpAMD64CMPWconst, TypeFlags)
- v3.AddArg(y)
- v3.AuxInt = 8
- v2.AddArg(v3)
- v1.AddArg(v2)
- v0.AddArg(v1)
v.AddArg(v0)
+ 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)
return true
}
}
-func rewriteValueAMD64_OpRsh8x32(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpLsh64x32(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (Rsh8x32 <t> x y)
+ // match: (Lsh64x32 <t> x y)
// cond:
- // result: (SARB <t> x (ORL <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPLconst y [8])))))
+ // result: (ANDQ (SHLQ <t> x y) (SBBQcarrymask <t> (CMPLconst y [64])))
for {
t := v.Type
x := v.Args[0]
y := v.Args[1]
- v.reset(OpAMD64SARB)
- v.Type = t
- v.AddArg(x)
- v0 := b.NewValue0(v.Line, OpAMD64ORL, y.Type)
+ v.reset(OpAMD64ANDQ)
+ v0 := b.NewValue0(v.Line, OpAMD64SHLQ, t)
+ v0.AddArg(x)
v0.AddArg(y)
- v1 := b.NewValue0(v.Line, OpAMD64NOTL, y.Type)
- v2 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, y.Type)
- v3 := b.NewValue0(v.Line, OpAMD64CMPLconst, TypeFlags)
- v3.AddArg(y)
- v3.AuxInt = 8
- v2.AddArg(v3)
- v1.AddArg(v2)
- v0.AddArg(v1)
v.AddArg(v0)
+ 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_OpRsh8x64(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpLsh64x64(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (Rsh8x64 <t> x y)
+ // match: (Lsh64x64 <t> x y)
// cond:
- // result: (SARB <t> x (ORQ <y.Type> y (NOTQ <y.Type> (SBBQcarrymask <y.Type> (CMPQconst y [8])))))
+ // result: (ANDQ (SHLQ <t> x y) (SBBQcarrymask <t> (CMPQconst y [64])))
for {
t := v.Type
x := v.Args[0]
y := v.Args[1]
- v.reset(OpAMD64SARB)
- v.Type = t
- v.AddArg(x)
- v0 := b.NewValue0(v.Line, OpAMD64ORQ, y.Type)
+ v.reset(OpAMD64ANDQ)
+ v0 := b.NewValue0(v.Line, OpAMD64SHLQ, t)
+ v0.AddArg(x)
v0.AddArg(y)
- v1 := b.NewValue0(v.Line, OpAMD64NOTQ, y.Type)
- v2 := b.NewValue0(v.Line, OpAMD64SBBQcarrymask, y.Type)
- v3 := b.NewValue0(v.Line, OpAMD64CMPQconst, TypeFlags)
- v3.AddArg(y)
- v3.AuxInt = 8
- v2.AddArg(v3)
- v1.AddArg(v2)
- v0.AddArg(v1)
v.AddArg(v0)
+ 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)
return true
}
}
-func rewriteValueAMD64_OpRsh8x8(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpLsh64x8(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (Rsh8x8 <t> x y)
+ // match: (Lsh64x8 <t> x y)
// cond:
- // result: (SARB <t> x (ORL <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPBconst y [8])))))
+ // result: (ANDQ (SHLQ <t> x y) (SBBQcarrymask <t> (CMPBconst y [64])))
for {
t := v.Type
x := v.Args[0]
y := v.Args[1]
- v.reset(OpAMD64SARB)
- v.Type = t
- v.AddArg(x)
- v0 := b.NewValue0(v.Line, OpAMD64ORL, y.Type)
+ v.reset(OpAMD64ANDQ)
+ v0 := b.NewValue0(v.Line, OpAMD64SHLQ, t)
+ v0.AddArg(x)
v0.AddArg(y)
- v1 := b.NewValue0(v.Line, OpAMD64NOTL, y.Type)
- v2 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, y.Type)
- v3 := b.NewValue0(v.Line, OpAMD64CMPBconst, TypeFlags)
- v3.AddArg(y)
- v3.AuxInt = 8
- v2.AddArg(v3)
- v1.AddArg(v2)
- v0.AddArg(v1)
v.AddArg(v0)
+ 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
}
}
-func rewriteValueAMD64_OpAMD64SARB(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (SARB x (MOVQconst [c]))
- // cond:
- // result: (SARBconst [c&31] x)
- for {
- x := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64MOVQconst {
- break
- }
- c := v_1.AuxInt
- v.reset(OpAMD64SARBconst)
- v.AuxInt = c & 31
- v.AddArg(x)
- return true
- }
- // match: (SARB x (MOVLconst [c]))
- // cond:
- // result: (SARBconst [c&31] x)
- for {
- x := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64MOVLconst {
- break
- }
- c := v_1.AuxInt
- v.reset(OpAMD64SARBconst)
- v.AuxInt = c & 31
- v.AddArg(x)
- return true
- }
- return false
-}
-func rewriteValueAMD64_OpAMD64SARBconst(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (SARBconst [c] (MOVQconst [d]))
- // cond:
- // result: (MOVQconst [d>>uint64(c)])
- for {
- c := v.AuxInt
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64MOVQconst {
- break
- }
- d := v_0.AuxInt
- v.reset(OpAMD64MOVQconst)
- v.AuxInt = d >> uint64(c)
- return true
- }
- return false
-}
-func rewriteValueAMD64_OpAMD64SARL(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpLsh8x16(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (SARL x (MOVQconst [c]))
- // cond:
- // result: (SARLconst [c&31] x)
- for {
- x := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64MOVQconst {
- break
- }
- c := v_1.AuxInt
- v.reset(OpAMD64SARLconst)
- v.AuxInt = c & 31
- v.AddArg(x)
- return true
- }
- // match: (SARL x (MOVLconst [c]))
- // cond:
- // result: (SARLconst [c&31] x)
- for {
- x := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64MOVLconst {
- break
- }
- c := v_1.AuxInt
- v.reset(OpAMD64SARLconst)
- v.AuxInt = c & 31
- v.AddArg(x)
- return true
- }
- // match: (SARL x (ANDLconst [31] y))
+ // match: (Lsh8x16 <t> x y)
// cond:
- // result: (SARL x y)
+ // result: (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPWconst y [32])))
for {
+ t := v.Type
x := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64ANDLconst {
- break
- }
- if v_1.AuxInt != 31 {
- break
- }
- y := v_1.Args[0]
- v.reset(OpAMD64SARL)
- v.AddArg(x)
- v.AddArg(y)
+ 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)
return true
}
- return false
}
-func rewriteValueAMD64_OpAMD64SARLconst(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpLsh8x32(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (SARLconst [c] (MOVQconst [d]))
+ // match: (Lsh8x32 <t> x y)
// cond:
- // result: (MOVQconst [d>>uint64(c)])
+ // result: (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPLconst y [32])))
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)
+ 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)
return true
}
- return false
}
-func rewriteValueAMD64_OpAMD64SARQ(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpLsh8x64(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (SARQ x (MOVQconst [c]))
+ // match: (Lsh8x64 <t> x y)
// cond:
- // result: (SARQconst [c&63] x)
+ // result: (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPQconst y [32])))
for {
+ t := v.Type
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)
+ 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)
return true
}
- // match: (SARQ x (MOVLconst [c]))
+}
+func rewriteValueAMD64_OpLsh8x8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Lsh8x8 <t> x y)
// cond:
- // result: (SARQconst [c&63] x)
+ // result: (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPBconst y [32])))
for {
+ t := v.Type
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)
+ 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
}
- // match: (SARQ x (ANDQconst [63] y))
+}
+func rewriteValueAMD64_OpMod16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Mod16 x y)
// cond:
- // result: (SARQ x y)
+ // result: (Select1 (DIVW x y))
for {
x := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64ANDQconst {
- break
- }
- if v_1.AuxInt != 63 {
- break
- }
- y := v_1.Args[0]
- v.reset(OpAMD64SARQ)
- v.AddArg(x)
- v.AddArg(y)
+ 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.AddArg(v0)
return true
}
- return false
}
-func rewriteValueAMD64_OpAMD64SARQconst(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpMod16u(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (SARQconst [c] (MOVQconst [d]))
+ // match: (Mod16u x y)
// cond:
- // result: (MOVQconst [d>>uint64(c)])
+ // result: (Select1 (DIVWU x y))
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)
+ 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.AddArg(v0)
return true
}
- return false
}
-func rewriteValueAMD64_OpAMD64SARW(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpMod32(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (SARW x (MOVQconst [c]))
+ // match: (Mod32 x y)
// cond:
- // result: (SARWconst [c&31] x)
+ // result: (Select1 (DIVL x y))
for {
x := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64MOVQconst {
- break
- }
- c := v_1.AuxInt
- v.reset(OpAMD64SARWconst)
- v.AuxInt = c & 31
- v.AddArg(x)
+ y := v.Args[1]
+ v.reset(OpSelect1)
+ v0 := b.NewValue0(v.Line, OpAMD64DIVL, MakeTuple(config.fe.TypeInt32(), config.fe.TypeInt32()))
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
return true
}
- // match: (SARW x (MOVLconst [c]))
+}
+func rewriteValueAMD64_OpMod32u(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Mod32u x y)
// cond:
- // result: (SARWconst [c&31] x)
+ // result: (Select1 (DIVLU x y))
for {
x := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64MOVLconst {
- break
- }
- c := v_1.AuxInt
- v.reset(OpAMD64SARWconst)
- v.AuxInt = c & 31
- v.AddArg(x)
+ 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.AddArg(v0)
return true
}
- return false
}
-func rewriteValueAMD64_OpAMD64SARWconst(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpMod64(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (SARWconst [c] (MOVQconst [d]))
+ // match: (Mod64 x y)
// cond:
- // result: (MOVQconst [d>>uint64(c)])
+ // result: (Select1 (DIVQ x y))
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)
+ 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.AddArg(v0)
return true
}
- return false
}
-func rewriteValueAMD64_OpAMD64SBBLcarrymask(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpMod64u(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (SBBLcarrymask (FlagEQ))
- // cond:
- // result: (MOVLconst [0])
- for {
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64FlagEQ {
- break
- }
- v.reset(OpAMD64MOVLconst)
- v.AuxInt = 0
- return true
- }
- // match: (SBBLcarrymask (FlagLT_ULT))
- // cond:
- // result: (MOVLconst [-1])
- for {
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64FlagLT_ULT {
- break
- }
- v.reset(OpAMD64MOVLconst)
- v.AuxInt = -1
- return true
- }
- // match: (SBBLcarrymask (FlagLT_UGT))
- // cond:
- // result: (MOVLconst [0])
- for {
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64FlagLT_UGT {
- break
- }
- v.reset(OpAMD64MOVLconst)
- v.AuxInt = 0
- return true
- }
- // match: (SBBLcarrymask (FlagGT_ULT))
+ // match: (Mod64u x y)
// cond:
- // result: (MOVLconst [-1])
+ // result: (Select1 (DIVQU x y))
for {
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64FlagGT_ULT {
- break
- }
- v.reset(OpAMD64MOVLconst)
- v.AuxInt = -1
+ 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
}
- // match: (SBBLcarrymask (FlagGT_UGT))
+}
+func rewriteValueAMD64_OpMod8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Mod8 x y)
// cond:
- // result: (MOVLconst [0])
+ // result: (Select1 (DIVW (SignExt8to16 x) (SignExt8to16 y)))
for {
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64FlagGT_UGT {
- break
- }
- v.reset(OpAMD64MOVLconst)
- v.AuxInt = 0
+ 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
}
- return false
}
-func rewriteValueAMD64_OpAMD64SBBQcarrymask(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpMod8u(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (SBBQcarrymask (FlagEQ))
- // cond:
- // result: (MOVQconst [0])
- for {
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64FlagEQ {
- break
- }
- v.reset(OpAMD64MOVQconst)
- v.AuxInt = 0
- return true
- }
- // match: (SBBQcarrymask (FlagLT_ULT))
+ // match: (Mod8u x y)
// cond:
- // result: (MOVQconst [-1])
+ // result: (Select1 (DIVWU (ZeroExt8to16 x) (ZeroExt8to16 y)))
for {
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64FlagLT_ULT {
- break
- }
- v.reset(OpAMD64MOVQconst)
- v.AuxInt = -1
+ 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
}
- // match: (SBBQcarrymask (FlagLT_UGT))
- // cond:
- // result: (MOVQconst [0])
+}
+func rewriteValueAMD64_OpMove(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Move [s] _ _ mem)
+ // cond: SizeAndAlign(s).Size() == 0
+ // result: mem
for {
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64FlagLT_UGT {
+ s := v.AuxInt
+ mem := v.Args[2]
+ if !(SizeAndAlign(s).Size() == 0) {
break
}
- v.reset(OpAMD64MOVQconst)
- v.AuxInt = 0
+ v.reset(OpCopy)
+ v.Type = mem.Type
+ v.AddArg(mem)
return true
}
- // match: (SBBQcarrymask (FlagGT_ULT))
- // cond:
- // result: (MOVQconst [-1])
+ // match: (Move [s] dst src mem)
+ // cond: SizeAndAlign(s).Size() == 1
+ // result: (MOVBstore dst (MOVBload src mem) mem)
for {
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64FlagGT_ULT {
+ s := v.AuxInt
+ dst := v.Args[0]
+ src := v.Args[1]
+ mem := v.Args[2]
+ if !(SizeAndAlign(s).Size() == 1) {
break
}
- v.reset(OpAMD64MOVQconst)
- v.AuxInt = -1
+ 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: (SBBQcarrymask (FlagGT_UGT))
- // cond:
- // result: (MOVQconst [0])
+ // match: (Move [s] dst src mem)
+ // cond: SizeAndAlign(s).Size() == 2
+ // result: (MOVWstore dst (MOVWload src mem) mem)
for {
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64FlagGT_UGT {
+ s := v.AuxInt
+ dst := v.Args[0]
+ src := v.Args[1]
+ mem := v.Args[2]
+ if !(SizeAndAlign(s).Size() == 2) {
break
}
- v.reset(OpAMD64MOVQconst)
- v.AuxInt = 0
+ 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
}
- return false
-}
-func rewriteValueAMD64_OpAMD64SETA(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (SETA (InvertFlags x))
- // cond:
- // result: (SETB x)
+ // match: (Move [s] dst src mem)
+ // cond: SizeAndAlign(s).Size() == 4
+ // result: (MOVLstore dst (MOVLload src mem) mem)
for {
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64InvertFlags {
+ s := v.AuxInt
+ dst := v.Args[0]
+ src := v.Args[1]
+ mem := v.Args[2]
+ if !(SizeAndAlign(s).Size() == 4) {
break
}
- x := v_0.Args[0]
- v.reset(OpAMD64SETB)
- v.AddArg(x)
+ 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: (SETA (FlagEQ))
- // cond:
- // result: (MOVLconst [0])
+ // match: (Move [s] dst src mem)
+ // cond: SizeAndAlign(s).Size() == 8
+ // result: (MOVQstore dst (MOVQload src mem) mem)
for {
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64FlagEQ {
+ s := v.AuxInt
+ dst := v.Args[0]
+ src := v.Args[1]
+ mem := v.Args[2]
+ if !(SizeAndAlign(s).Size() == 8) {
break
}
- v.reset(OpAMD64MOVLconst)
- v.AuxInt = 0
+ 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: (SETA (FlagLT_ULT))
- // cond:
- // result: (MOVLconst [0])
+ // match: (Move [s] dst src mem)
+ // cond: SizeAndAlign(s).Size() == 16
+ // result: (MOVOstore dst (MOVOload src mem) mem)
for {
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64FlagLT_ULT {
+ s := v.AuxInt
+ dst := v.Args[0]
+ src := v.Args[1]
+ mem := v.Args[2]
+ if !(SizeAndAlign(s).Size() == 16) {
break
}
- v.reset(OpAMD64MOVLconst)
- v.AuxInt = 0
+ 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: (SETA (FlagLT_UGT))
- // cond:
- // result: (MOVLconst [1])
+ // 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 {
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64FlagLT_UGT {
+ s := v.AuxInt
+ dst := v.Args[0]
+ src := v.Args[1]
+ mem := v.Args[2]
+ if !(SizeAndAlign(s).Size() == 3) {
break
}
- v.reset(OpAMD64MOVLconst)
- v.AuxInt = 1
+ v.reset(OpAMD64MOVBstore)
+ v.AuxInt = 2
+ v.AddArg(dst)
+ v0 := b.NewValue0(v.Line, OpAMD64MOVBload, config.fe.TypeUInt8())
+ v0.AuxInt = 2
+ v0.AddArg(src)
+ v0.AddArg(mem)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpAMD64MOVWstore, TypeMem)
+ v1.AddArg(dst)
+ v2 := b.NewValue0(v.Line, OpAMD64MOVWload, config.fe.TypeUInt16())
+ v2.AddArg(src)
+ v2.AddArg(mem)
+ v1.AddArg(v2)
+ v1.AddArg(mem)
+ v.AddArg(v1)
return true
}
- // match: (SETA (FlagGT_ULT))
- // cond:
- // result: (MOVLconst [0])
+ // 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))
for {
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64FlagGT_ULT {
+ s := v.AuxInt
+ dst := v.Args[0]
+ src := v.Args[1]
+ mem := v.Args[2]
+ if !(SizeAndAlign(s).Size() == 5) {
break
}
- v.reset(OpAMD64MOVLconst)
- v.AuxInt = 0
+ v.reset(OpAMD64MOVBstore)
+ v.AuxInt = 4
+ v.AddArg(dst)
+ v0 := b.NewValue0(v.Line, OpAMD64MOVBload, config.fe.TypeUInt8())
+ v0.AuxInt = 4
+ v0.AddArg(src)
+ v0.AddArg(mem)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpAMD64MOVLstore, TypeMem)
+ v1.AddArg(dst)
+ v2 := b.NewValue0(v.Line, OpAMD64MOVLload, config.fe.TypeUInt32())
+ v2.AddArg(src)
+ v2.AddArg(mem)
+ v1.AddArg(v2)
+ v1.AddArg(mem)
+ v.AddArg(v1)
return true
}
- // match: (SETA (FlagGT_UGT))
- // cond:
- // result: (MOVLconst [1])
+ // 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))
for {
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64FlagGT_UGT {
+ s := v.AuxInt
+ dst := v.Args[0]
+ src := v.Args[1]
+ mem := v.Args[2]
+ if !(SizeAndAlign(s).Size() == 6) {
break
}
- v.reset(OpAMD64MOVLconst)
- v.AuxInt = 1
+ v.reset(OpAMD64MOVWstore)
+ v.AuxInt = 4
+ v.AddArg(dst)
+ v0 := b.NewValue0(v.Line, OpAMD64MOVWload, config.fe.TypeUInt16())
+ v0.AuxInt = 4
+ v0.AddArg(src)
+ v0.AddArg(mem)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpAMD64MOVLstore, TypeMem)
+ v1.AddArg(dst)
+ v2 := b.NewValue0(v.Line, OpAMD64MOVLload, config.fe.TypeUInt32())
+ v2.AddArg(src)
+ v2.AddArg(mem)
+ v1.AddArg(v2)
+ v1.AddArg(mem)
+ v.AddArg(v1)
return true
}
- return false
-}
-func rewriteValueAMD64_OpAMD64SETAE(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (SETAE (InvertFlags x))
- // cond:
- // result: (SETBE x)
+ // 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))
for {
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64InvertFlags {
+ s := v.AuxInt
+ dst := v.Args[0]
+ src := v.Args[1]
+ mem := v.Args[2]
+ if !(SizeAndAlign(s).Size() == 7) {
break
}
- x := v_0.Args[0]
- v.reset(OpAMD64SETBE)
- v.AddArg(x)
+ v.reset(OpAMD64MOVLstore)
+ v.AuxInt = 3
+ v.AddArg(dst)
+ v0 := b.NewValue0(v.Line, OpAMD64MOVLload, config.fe.TypeUInt32())
+ v0.AuxInt = 3
+ v0.AddArg(src)
+ v0.AddArg(mem)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpAMD64MOVLstore, TypeMem)
+ v1.AddArg(dst)
+ v2 := b.NewValue0(v.Line, OpAMD64MOVLload, config.fe.TypeUInt32())
+ v2.AddArg(src)
+ v2.AddArg(mem)
+ v1.AddArg(v2)
+ v1.AddArg(mem)
+ v.AddArg(v1)
return true
}
- // match: (SETAE (FlagEQ))
- // cond:
- // result: (MOVLconst [1])
+ // 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))
for {
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64FlagEQ {
+ s := v.AuxInt
+ dst := v.Args[0]
+ src := v.Args[1]
+ mem := v.Args[2]
+ if !(SizeAndAlign(s).Size() > 8 && SizeAndAlign(s).Size() < 16) {
break
}
- v.reset(OpAMD64MOVLconst)
- v.AuxInt = 1
+ 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)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpAMD64MOVQstore, TypeMem)
+ v1.AddArg(dst)
+ v2 := b.NewValue0(v.Line, OpAMD64MOVQload, config.fe.TypeUInt64())
+ v2.AddArg(src)
+ v2.AddArg(mem)
+ v1.AddArg(v2)
+ v1.AddArg(mem)
+ v.AddArg(v1)
return true
}
- // match: (SETAE (FlagLT_ULT))
- // cond:
- // result: (MOVLconst [0])
+ // 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))
for {
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64FlagLT_ULT {
+ 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) {
break
}
- v.reset(OpAMD64MOVLconst)
- v.AuxInt = 0
+ 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)
+ 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)
return true
}
- // match: (SETAE (FlagLT_UGT))
- // cond:
- // result: (MOVLconst [1])
+ // 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))
for {
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64FlagLT_UGT {
+ 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) {
break
}
- v.reset(OpAMD64MOVLconst)
- v.AuxInt = 1
+ 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)
+ 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)
return true
}
- // match: (SETAE (FlagGT_ULT))
- // cond:
- // result: (MOVLconst [0])
+ // 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)
for {
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64FlagGT_ULT {
+ 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) {
break
}
- v.reset(OpAMD64MOVLconst)
- v.AuxInt = 0
+ v.reset(OpAMD64DUFFCOPY)
+ v.AuxInt = 14 * (64 - SizeAndAlign(s).Size()/16)
+ v.AddArg(dst)
+ v.AddArg(src)
+ v.AddArg(mem)
return true
}
- // match: (SETAE (FlagGT_UGT))
- // cond:
- // result: (MOVLconst [1])
+ // 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)
for {
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64FlagGT_UGT {
+ 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) {
break
}
- v.reset(OpAMD64MOVLconst)
- v.AuxInt = 1
+ v.reset(OpAMD64REPMOVSQ)
+ v.AddArg(dst)
+ v.AddArg(src)
+ v0 := b.NewValue0(v.Line, OpAMD64MOVQconst, config.fe.TypeUInt64())
+ v0.AuxInt = SizeAndAlign(s).Size() / 8
+ v.AddArg(v0)
+ v.AddArg(mem)
return true
}
return false
}
-func rewriteValueAMD64_OpAMD64SETB(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpMul16(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (SETB (InvertFlags x))
+ // match: (Mul16 x y)
// cond:
- // result: (SETA x)
+ // result: (MULL x y)
for {
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64InvertFlags {
- break
- }
- x := v_0.Args[0]
- v.reset(OpAMD64SETA)
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpAMD64MULL)
v.AddArg(x)
+ v.AddArg(y)
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))
+}
+func rewriteValueAMD64_OpMul32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Mul32 x y)
// cond:
- // result: (MOVLconst [0])
+ // result: (MULL x y)
for {
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64FlagLT_UGT {
- break
- }
- v.reset(OpAMD64MOVLconst)
- v.AuxInt = 0
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpAMD64MULL)
+ v.AddArg(x)
+ v.AddArg(y)
return true
}
- // match: (SETB (FlagGT_ULT))
+}
+func rewriteValueAMD64_OpMul32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Mul32F x y)
// cond:
- // result: (MOVLconst [1])
+ // result: (MULSS x y)
for {
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64FlagGT_ULT {
- break
- }
- v.reset(OpAMD64MOVLconst)
- v.AuxInt = 1
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpAMD64MULSS)
+ v.AddArg(x)
+ v.AddArg(y)
return true
}
- // match: (SETB (FlagGT_UGT))
+}
+func rewriteValueAMD64_OpMul64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Mul64 x y)
// cond:
- // result: (MOVLconst [0])
+ // result: (MULQ x y)
for {
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64FlagGT_UGT {
- break
- }
- v.reset(OpAMD64MOVLconst)
- v.AuxInt = 0
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpAMD64MULQ)
+ v.AddArg(x)
+ v.AddArg(y)
return true
}
- return false
}
-func rewriteValueAMD64_OpAMD64SETBE(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpMul64F(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (SETBE (InvertFlags x))
+ // match: (Mul64F x y)
// cond:
- // result: (SETAE x)
+ // result: (MULSD x y)
for {
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64InvertFlags {
- break
- }
- x := v_0.Args[0]
- v.reset(OpAMD64SETAE)
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpAMD64MULSD)
v.AddArg(x)
+ v.AddArg(y)
return true
}
- // match: (SETBE (FlagEQ))
+}
+func rewriteValueAMD64_OpMul64uhilo(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Mul64uhilo x y)
// cond:
- // result: (MOVLconst [1])
+ // result: (MULQU2 x y)
for {
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64FlagEQ {
- break
- }
- v.reset(OpAMD64MOVLconst)
- v.AuxInt = 1
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpAMD64MULQU2)
+ v.AddArg(x)
+ v.AddArg(y)
return true
}
- // match: (SETBE (FlagLT_ULT))
+}
+func rewriteValueAMD64_OpMul8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Mul8 x y)
// cond:
- // result: (MOVLconst [1])
+ // result: (MULL x y)
for {
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64FlagLT_ULT {
- break
- }
- v.reset(OpAMD64MOVLconst)
- v.AuxInt = 1
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpAMD64MULL)
+ v.AddArg(x)
+ v.AddArg(y)
return true
}
- // match: (SETBE (FlagLT_UGT))
+}
+func rewriteValueAMD64_OpNeg16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Neg16 x)
// cond:
- // result: (MOVLconst [0])
+ // result: (NEGL x)
for {
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64FlagLT_UGT {
- break
- }
- v.reset(OpAMD64MOVLconst)
- v.AuxInt = 0
+ x := v.Args[0]
+ v.reset(OpAMD64NEGL)
+ v.AddArg(x)
return true
}
- // match: (SETBE (FlagGT_ULT))
+}
+func rewriteValueAMD64_OpNeg32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Neg32 x)
// cond:
- // result: (MOVLconst [1])
+ // result: (NEGL x)
for {
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64FlagGT_ULT {
- break
- }
- v.reset(OpAMD64MOVLconst)
- v.AuxInt = 1
+ x := v.Args[0]
+ v.reset(OpAMD64NEGL)
+ v.AddArg(x)
return true
}
- // match: (SETBE (FlagGT_UGT))
+}
+func rewriteValueAMD64_OpNeg32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Neg32F x)
// cond:
- // result: (MOVLconst [0])
+ // result: (PXOR x (MOVSSconst <config.Frontend().TypeFloat32()> [f2i(math.Copysign(0, -1))]))
for {
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64FlagGT_UGT {
- break
- }
- v.reset(OpAMD64MOVLconst)
- v.AuxInt = 0
+ x := v.Args[0]
+ v.reset(OpAMD64PXOR)
+ v.AddArg(x)
+ v0 := b.NewValue0(v.Line, OpAMD64MOVSSconst, config.Frontend().TypeFloat32())
+ v0.AuxInt = f2i(math.Copysign(0, -1))
+ v.AddArg(v0)
return true
}
- return false
}
-func rewriteValueAMD64_OpAMD64SETEQ(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpNeg64(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (SETEQ (InvertFlags x))
+ // match: (Neg64 x)
// cond:
- // result: (SETEQ x)
+ // result: (NEGQ x)
for {
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64InvertFlags {
- break
- }
- x := v_0.Args[0]
- v.reset(OpAMD64SETEQ)
+ x := v.Args[0]
+ v.reset(OpAMD64NEGQ)
v.AddArg(x)
return true
}
- // match: (SETEQ (FlagEQ))
+}
+func rewriteValueAMD64_OpNeg64F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Neg64F x)
// cond:
- // result: (MOVLconst [1])
+ // result: (PXOR x (MOVSDconst <config.Frontend().TypeFloat64()> [f2i(math.Copysign(0, -1))]))
for {
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64FlagEQ {
- break
- }
- v.reset(OpAMD64MOVLconst)
- v.AuxInt = 1
+ x := v.Args[0]
+ v.reset(OpAMD64PXOR)
+ v.AddArg(x)
+ v0 := b.NewValue0(v.Line, OpAMD64MOVSDconst, config.Frontend().TypeFloat64())
+ v0.AuxInt = f2i(math.Copysign(0, -1))
+ v.AddArg(v0)
return true
}
- // match: (SETEQ (FlagLT_ULT))
+}
+func rewriteValueAMD64_OpNeg8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Neg8 x)
// cond:
- // result: (MOVLconst [0])
+ // result: (NEGL x)
for {
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64FlagLT_ULT {
- break
- }
- v.reset(OpAMD64MOVLconst)
- v.AuxInt = 0
+ x := v.Args[0]
+ v.reset(OpAMD64NEGL)
+ v.AddArg(x)
return true
}
- // match: (SETEQ (FlagLT_UGT))
+}
+func rewriteValueAMD64_OpNeq16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Neq16 x y)
// cond:
- // result: (MOVLconst [0])
+ // result: (SETNE (CMPW x y))
for {
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64FlagLT_UGT {
- break
- }
- v.reset(OpAMD64MOVLconst)
- v.AuxInt = 0
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpAMD64SETNE)
+ v0 := b.NewValue0(v.Line, OpAMD64CMPW, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
return true
}
- // match: (SETEQ (FlagGT_ULT))
+}
+func rewriteValueAMD64_OpNeq32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Neq32 x y)
// cond:
- // result: (MOVLconst [0])
+ // result: (SETNE (CMPL x y))
for {
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64FlagGT_ULT {
- break
- }
- v.reset(OpAMD64MOVLconst)
- v.AuxInt = 0
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpAMD64SETNE)
+ v0 := b.NewValue0(v.Line, OpAMD64CMPL, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
return true
}
- // match: (SETEQ (FlagGT_UGT))
+}
+func rewriteValueAMD64_OpNeq32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Neq32F x y)
// cond:
- // result: (MOVLconst [0])
+ // result: (SETNEF (UCOMISS x y))
for {
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64FlagGT_UGT {
- break
- }
- v.reset(OpAMD64MOVLconst)
- v.AuxInt = 0
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpAMD64SETNEF)
+ v0 := b.NewValue0(v.Line, OpAMD64UCOMISS, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
return true
}
- return false
}
-func rewriteValueAMD64_OpAMD64SETG(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpNeq64(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (SETG (InvertFlags x))
+ // match: (Neq64 x y)
// cond:
- // result: (SETL x)
+ // result: (SETNE (CMPQ x y))
for {
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64InvertFlags {
- break
- }
- x := v_0.Args[0]
- v.reset(OpAMD64SETL)
- v.AddArg(x)
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpAMD64SETNE)
+ v0 := b.NewValue0(v.Line, OpAMD64CMPQ, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
return true
}
- // match: (SETG (FlagEQ))
+}
+func rewriteValueAMD64_OpNeq64F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Neq64F x y)
// cond:
- // result: (MOVLconst [0])
+ // result: (SETNEF (UCOMISD x y))
for {
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64FlagEQ {
- break
- }
- v.reset(OpAMD64MOVLconst)
- v.AuxInt = 0
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpAMD64SETNEF)
+ v0 := b.NewValue0(v.Line, OpAMD64UCOMISD, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
return true
}
- // match: (SETG (FlagLT_ULT))
+}
+func rewriteValueAMD64_OpNeq8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Neq8 x y)
// cond:
- // result: (MOVLconst [0])
+ // result: (SETNE (CMPB x y))
for {
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64FlagLT_ULT {
- break
- }
- v.reset(OpAMD64MOVLconst)
- v.AuxInt = 0
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpAMD64SETNE)
+ v0 := b.NewValue0(v.Line, OpAMD64CMPB, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
return true
}
- // match: (SETG (FlagLT_UGT))
+}
+func rewriteValueAMD64_OpNeqB(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (NeqB x y)
// cond:
- // result: (MOVLconst [0])
+ // result: (SETNE (CMPB x y))
for {
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64FlagLT_UGT {
- break
- }
- v.reset(OpAMD64MOVLconst)
- v.AuxInt = 0
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpAMD64SETNE)
+ v0 := b.NewValue0(v.Line, OpAMD64CMPB, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
return true
}
- // match: (SETG (FlagGT_ULT))
- // cond:
- // result: (MOVLconst [1])
+}
+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))
for {
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64FlagGT_ULT {
+ x := v.Args[0]
+ y := v.Args[1]
+ if !(config.PtrSize == 8) {
break
}
- v.reset(OpAMD64MOVLconst)
- v.AuxInt = 1
+ v.reset(OpAMD64SETNE)
+ v0 := b.NewValue0(v.Line, OpAMD64CMPQ, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
return true
}
- // match: (SETG (FlagGT_UGT))
- // cond:
- // result: (MOVLconst [1])
+ // match: (NeqPtr x y)
+ // cond: config.PtrSize == 4
+ // result: (SETNE (CMPL x y))
for {
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64FlagGT_UGT {
+ x := v.Args[0]
+ y := v.Args[1]
+ if !(config.PtrSize == 4) {
break
}
- v.reset(OpAMD64MOVLconst)
- v.AuxInt = 1
+ v.reset(OpAMD64SETNE)
+ v0 := b.NewValue0(v.Line, OpAMD64CMPL, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
return true
}
return false
}
-func rewriteValueAMD64_OpAMD64SETGE(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpNilCheck(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (SETGE (InvertFlags x))
+ // match: (NilCheck ptr mem)
// cond:
- // result: (SETLE x)
+ // result: (LoweredNilCheck ptr mem)
for {
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64InvertFlags {
- break
- }
- x := v_0.Args[0]
- v.reset(OpAMD64SETLE)
- v.AddArg(x)
+ ptr := v.Args[0]
+ mem := v.Args[1]
+ v.reset(OpAMD64LoweredNilCheck)
+ v.AddArg(ptr)
+ v.AddArg(mem)
return true
}
- // match: (SETGE (FlagEQ))
+}
+func rewriteValueAMD64_OpNot(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Not x)
// cond:
- // result: (MOVLconst [1])
+ // result: (XORLconst [1] x)
for {
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64FlagEQ {
- break
- }
- v.reset(OpAMD64MOVLconst)
+ x := v.Args[0]
+ v.reset(OpAMD64XORLconst)
v.AuxInt = 1
+ v.AddArg(x)
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])
+}
+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 {
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64FlagLT_UGT {
+ off := v.AuxInt
+ ptr := v.Args[0]
+ if !(config.PtrSize == 8 && is32Bit(off)) {
break
}
- v.reset(OpAMD64MOVLconst)
- v.AuxInt = 0
+ v.reset(OpAMD64ADDQconst)
+ v.AuxInt = off
+ v.AddArg(ptr)
return true
}
- // match: (SETGE (FlagGT_ULT))
- // cond:
- // result: (MOVLconst [1])
+ // match: (OffPtr [off] ptr)
+ // cond: config.PtrSize == 8
+ // result: (ADDQ (MOVQconst [off]) ptr)
for {
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64FlagGT_ULT {
+ off := v.AuxInt
+ ptr := v.Args[0]
+ if !(config.PtrSize == 8) {
break
}
- v.reset(OpAMD64MOVLconst)
- v.AuxInt = 1
+ v.reset(OpAMD64ADDQ)
+ v0 := b.NewValue0(v.Line, OpAMD64MOVQconst, config.fe.TypeUInt64())
+ v0.AuxInt = off
+ v.AddArg(v0)
+ v.AddArg(ptr)
return true
}
- // match: (SETGE (FlagGT_UGT))
- // cond:
- // result: (MOVLconst [1])
+ // match: (OffPtr [off] ptr)
+ // cond: config.PtrSize == 4
+ // result: (ADDLconst [off] ptr)
for {
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64FlagGT_UGT {
+ off := v.AuxInt
+ ptr := v.Args[0]
+ if !(config.PtrSize == 4) {
break
}
- v.reset(OpAMD64MOVLconst)
- v.AuxInt = 1
+ v.reset(OpAMD64ADDLconst)
+ v.AuxInt = off
+ v.AddArg(ptr)
return true
}
return false
}
-func rewriteValueAMD64_OpAMD64SETL(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpOr16(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (SETL (InvertFlags x))
+ // match: (Or16 x y)
// cond:
- // result: (SETG x)
+ // result: (ORL x y)
for {
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64InvertFlags {
- break
- }
- x := v_0.Args[0]
- v.reset(OpAMD64SETG)
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpAMD64ORL)
v.AddArg(x)
+ v.AddArg(y)
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))
+}
+func rewriteValueAMD64_OpOr32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Or32 x y)
// cond:
- // result: (MOVLconst [1])
+ // result: (ORL x y)
for {
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64FlagLT_UGT {
- break
- }
- v.reset(OpAMD64MOVLconst)
- v.AuxInt = 1
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpAMD64ORL)
+ v.AddArg(x)
+ v.AddArg(y)
return true
}
- // match: (SETL (FlagGT_ULT))
+}
+func rewriteValueAMD64_OpOr64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Or64 x y)
// cond:
- // result: (MOVLconst [0])
+ // result: (ORQ x y)
for {
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64FlagGT_ULT {
- break
- }
- v.reset(OpAMD64MOVLconst)
- v.AuxInt = 0
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpAMD64ORQ)
+ v.AddArg(x)
+ v.AddArg(y)
return true
}
- // match: (SETL (FlagGT_UGT))
+}
+func rewriteValueAMD64_OpOr8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Or8 x y)
// cond:
- // result: (MOVLconst [0])
+ // result: (ORL x y)
for {
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64FlagGT_UGT {
- break
- }
- v.reset(OpAMD64MOVLconst)
- v.AuxInt = 0
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpAMD64ORL)
+ v.AddArg(x)
+ v.AddArg(y)
return true
}
- return false
}
-func rewriteValueAMD64_OpAMD64SETLE(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpOrB(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (SETLE (InvertFlags x))
+ // match: (OrB x y)
// cond:
- // result: (SETGE x)
+ // result: (ORL x y)
for {
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64InvertFlags {
- break
- }
- x := v_0.Args[0]
- v.reset(OpAMD64SETGE)
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpAMD64ORL)
v.AddArg(x)
+ v.AddArg(y)
return true
}
- // match: (SETLE (FlagEQ))
+}
+func rewriteValueAMD64_OpRsh16Ux16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh16Ux16 <t> x y)
// cond:
- // result: (MOVLconst [1])
+ // result: (ANDL (SHRW <t> x y) (SBBLcarrymask <t> (CMPWconst y [16])))
for {
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64FlagEQ {
- break
- }
- v.reset(OpAMD64MOVLconst)
- v.AuxInt = 1
+ t := v.Type
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpAMD64ANDL)
+ v0 := b.NewValue0(v.Line, OpAMD64SHRW, t)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, t)
+ v2 := b.NewValue0(v.Line, OpAMD64CMPWconst, TypeFlags)
+ v2.AuxInt = 16
+ v2.AddArg(y)
+ v1.AddArg(v2)
+ v.AddArg(v1)
return true
}
- // match: (SETLE (FlagLT_ULT))
+}
+func rewriteValueAMD64_OpRsh16Ux32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh16Ux32 <t> x y)
// cond:
- // result: (MOVLconst [1])
+ // result: (ANDL (SHRW <t> x y) (SBBLcarrymask <t> (CMPLconst y [16])))
for {
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64FlagLT_ULT {
- break
- }
- v.reset(OpAMD64MOVLconst)
- v.AuxInt = 1
+ t := v.Type
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpAMD64ANDL)
+ v0 := b.NewValue0(v.Line, OpAMD64SHRW, t)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, t)
+ v2 := b.NewValue0(v.Line, OpAMD64CMPLconst, TypeFlags)
+ v2.AuxInt = 16
+ v2.AddArg(y)
+ v1.AddArg(v2)
+ v.AddArg(v1)
return true
}
- // match: (SETLE (FlagLT_UGT))
+}
+func rewriteValueAMD64_OpRsh16Ux64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh16Ux64 <t> x y)
// cond:
- // result: (MOVLconst [1])
+ // result: (ANDL (SHRW <t> x y) (SBBLcarrymask <t> (CMPQconst y [16])))
for {
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64FlagLT_UGT {
- break
- }
- v.reset(OpAMD64MOVLconst)
- v.AuxInt = 1
+ t := v.Type
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpAMD64ANDL)
+ v0 := b.NewValue0(v.Line, OpAMD64SHRW, t)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, t)
+ v2 := b.NewValue0(v.Line, OpAMD64CMPQconst, TypeFlags)
+ v2.AuxInt = 16
+ v2.AddArg(y)
+ v1.AddArg(v2)
+ v.AddArg(v1)
return true
}
- // match: (SETLE (FlagGT_ULT))
+}
+func rewriteValueAMD64_OpRsh16Ux8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh16Ux8 <t> x y)
// cond:
- // result: (MOVLconst [0])
+ // result: (ANDL (SHRW <t> x y) (SBBLcarrymask <t> (CMPBconst y [16])))
for {
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64FlagGT_ULT {
- break
- }
- v.reset(OpAMD64MOVLconst)
- v.AuxInt = 0
+ t := v.Type
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpAMD64ANDL)
+ v0 := b.NewValue0(v.Line, OpAMD64SHRW, t)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, t)
+ v2 := b.NewValue0(v.Line, OpAMD64CMPBconst, TypeFlags)
+ v2.AuxInt = 16
+ v2.AddArg(y)
+ v1.AddArg(v2)
+ v.AddArg(v1)
return true
}
- // match: (SETLE (FlagGT_UGT))
+}
+func rewriteValueAMD64_OpRsh16x16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh16x16 <t> x y)
// cond:
- // result: (MOVLconst [0])
+ // result: (SARW <t> x (ORL <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPWconst y [16])))))
for {
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64FlagGT_UGT {
- break
- }
- v.reset(OpAMD64MOVLconst)
- v.AuxInt = 0
+ 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)
+ v1.AddArg(v2)
+ v0.AddArg(v1)
+ v.AddArg(v0)
return true
}
- return false
}
-func rewriteValueAMD64_OpAMD64SETNE(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpRsh16x32(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (SETNE (InvertFlags x))
+ // match: (Rsh16x32 <t> x y)
// cond:
- // result: (SETNE x)
+ // result: (SARW <t> x (ORL <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPLconst y [16])))))
for {
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64InvertFlags {
- break
- }
- x := v_0.Args[0]
- v.reset(OpAMD64SETNE)
+ 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)
+ v1.AddArg(v2)
+ v0.AddArg(v1)
+ v.AddArg(v0)
return true
}
- // match: (SETNE (FlagEQ))
+}
+func rewriteValueAMD64_OpRsh16x64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh16x64 <t> x y)
// cond:
- // result: (MOVLconst [0])
+ // result: (SARW <t> x (ORQ <y.Type> y (NOTQ <y.Type> (SBBQcarrymask <y.Type> (CMPQconst y [16])))))
for {
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64FlagEQ {
- break
- }
- v.reset(OpAMD64MOVLconst)
- v.AuxInt = 0
+ 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)
+ v1.AddArg(v2)
+ v0.AddArg(v1)
+ v.AddArg(v0)
return true
}
- // match: (SETNE (FlagLT_ULT))
+}
+func rewriteValueAMD64_OpRsh16x8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh16x8 <t> x y)
// cond:
- // result: (MOVLconst [1])
+ // result: (SARW <t> x (ORL <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPBconst y [16])))))
for {
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64FlagLT_ULT {
- break
- }
- v.reset(OpAMD64MOVLconst)
- v.AuxInt = 1
+ 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)
+ v1.AddArg(v2)
+ v0.AddArg(v1)
+ v.AddArg(v0)
return true
}
- // match: (SETNE (FlagLT_UGT))
+}
+func rewriteValueAMD64_OpRsh32Ux16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh32Ux16 <t> x y)
// cond:
- // result: (MOVLconst [1])
+ // result: (ANDL (SHRL <t> x y) (SBBLcarrymask <t> (CMPWconst y [32])))
for {
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64FlagLT_UGT {
- break
- }
- v.reset(OpAMD64MOVLconst)
- v.AuxInt = 1
+ t := v.Type
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpAMD64ANDL)
+ v0 := b.NewValue0(v.Line, OpAMD64SHRL, t)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, t)
+ v2 := b.NewValue0(v.Line, OpAMD64CMPWconst, TypeFlags)
+ v2.AuxInt = 32
+ v2.AddArg(y)
+ v1.AddArg(v2)
+ v.AddArg(v1)
return true
}
- // match: (SETNE (FlagGT_ULT))
+}
+func rewriteValueAMD64_OpRsh32Ux32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh32Ux32 <t> x y)
// cond:
- // result: (MOVLconst [1])
+ // result: (ANDL (SHRL <t> x y) (SBBLcarrymask <t> (CMPLconst y [32])))
for {
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64FlagGT_ULT {
- break
- }
- v.reset(OpAMD64MOVLconst)
- v.AuxInt = 1
+ t := v.Type
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpAMD64ANDL)
+ v0 := b.NewValue0(v.Line, OpAMD64SHRL, t)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, t)
+ v2 := b.NewValue0(v.Line, OpAMD64CMPLconst, TypeFlags)
+ v2.AuxInt = 32
+ v2.AddArg(y)
+ v1.AddArg(v2)
+ v.AddArg(v1)
return true
}
- // match: (SETNE (FlagGT_UGT))
+}
+func rewriteValueAMD64_OpRsh32Ux64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh32Ux64 <t> x y)
// cond:
- // result: (MOVLconst [1])
+ // result: (ANDL (SHRL <t> x y) (SBBLcarrymask <t> (CMPQconst y [32])))
for {
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64FlagGT_UGT {
- break
- }
- v.reset(OpAMD64MOVLconst)
- v.AuxInt = 1
+ t := v.Type
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpAMD64ANDL)
+ v0 := b.NewValue0(v.Line, OpAMD64SHRL, t)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, t)
+ v2 := b.NewValue0(v.Line, OpAMD64CMPQconst, TypeFlags)
+ v2.AuxInt = 32
+ v2.AddArg(y)
+ v1.AddArg(v2)
+ v.AddArg(v1)
return true
}
- return false
}
-func rewriteValueAMD64_OpAMD64SHLL(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpRsh32Ux8(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (SHLL x (MOVQconst [c]))
+ // match: (Rsh32Ux8 <t> x y)
// cond:
- // result: (SHLLconst [c&31] x)
+ // result: (ANDL (SHRL <t> x y) (SBBLcarrymask <t> (CMPBconst y [32])))
for {
+ t := v.Type
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)
+ y := v.Args[1]
+ v.reset(OpAMD64ANDL)
+ v0 := b.NewValue0(v.Line, OpAMD64SHRL, t)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, t)
+ v2 := b.NewValue0(v.Line, OpAMD64CMPBconst, TypeFlags)
+ v2.AuxInt = 32
+ v2.AddArg(y)
+ v1.AddArg(v2)
+ v.AddArg(v1)
return true
}
- // match: (SHLL x (MOVLconst [c]))
+}
+func rewriteValueAMD64_OpRsh32x16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh32x16 <t> x y)
// cond:
- // result: (SHLLconst [c&31] x)
+ // result: (SARL <t> x (ORL <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPWconst y [32])))))
for {
+ t := v.Type
x := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64MOVLconst {
- break
- }
- c := v_1.AuxInt
- v.reset(OpAMD64SHLLconst)
- v.AuxInt = c & 31
+ 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)
+ v1.AddArg(v2)
+ v0.AddArg(v1)
+ v.AddArg(v0)
return true
}
- // match: (SHLL x (ANDLconst [31] y))
+}
+func rewriteValueAMD64_OpRsh32x32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh32x32 <t> x y)
// cond:
- // result: (SHLL x y)
+ // result: (SARL <t> x (ORL <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPLconst y [32])))))
for {
+ t := v.Type
x := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64ANDLconst {
- break
- }
- if v_1.AuxInt != 31 {
- break
- }
- y := v_1.Args[0]
- v.reset(OpAMD64SHLL)
+ y := v.Args[1]
+ v.reset(OpAMD64SARL)
+ v.Type = t
v.AddArg(x)
- v.AddArg(y)
+ 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)
+ v1.AddArg(v2)
+ v0.AddArg(v1)
+ v.AddArg(v0)
return true
}
- return false
}
-func rewriteValueAMD64_OpAMD64SHLQ(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpRsh32x64(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (SHLQ x (MOVQconst [c]))
+ // match: (Rsh32x64 <t> x y)
// cond:
- // result: (SHLQconst [c&63] x)
+ // result: (SARL <t> x (ORQ <y.Type> y (NOTQ <y.Type> (SBBQcarrymask <y.Type> (CMPQconst y [32])))))
for {
+ t := v.Type
x := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64MOVQconst {
- break
- }
- c := v_1.AuxInt
- v.reset(OpAMD64SHLQconst)
- v.AuxInt = c & 63
+ 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)
+ v1.AddArg(v2)
+ v0.AddArg(v1)
+ v.AddArg(v0)
return true
}
- // match: (SHLQ x (MOVLconst [c]))
+}
+func rewriteValueAMD64_OpRsh32x8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh32x8 <t> x y)
// cond:
- // result: (SHLQconst [c&63] x)
+ // result: (SARL <t> x (ORL <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPBconst y [32])))))
for {
+ t := v.Type
x := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64MOVLconst {
- break
- }
- c := v_1.AuxInt
- v.reset(OpAMD64SHLQconst)
- v.AuxInt = c & 63
+ 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)
+ v1.AddArg(v2)
+ v0.AddArg(v1)
+ v.AddArg(v0)
return true
}
- // match: (SHLQ x (ANDQconst [63] y))
+}
+func rewriteValueAMD64_OpRsh64Ux16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh64Ux16 <t> x y)
// cond:
- // result: (SHLQ x y)
+ // result: (ANDQ (SHRQ <t> x y) (SBBQcarrymask <t> (CMPWconst y [64])))
for {
+ t := v.Type
x := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64ANDQconst {
- break
- }
- if v_1.AuxInt != 63 {
- break
- }
- y := v_1.Args[0]
- v.reset(OpAMD64SHLQ)
- v.AddArg(x)
- v.AddArg(y)
+ y := v.Args[1]
+ v.reset(OpAMD64ANDQ)
+ v0 := b.NewValue0(v.Line, OpAMD64SHRQ, t)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpAMD64SBBQcarrymask, t)
+ v2 := b.NewValue0(v.Line, OpAMD64CMPWconst, TypeFlags)
+ v2.AuxInt = 64
+ v2.AddArg(y)
+ v1.AddArg(v2)
+ v.AddArg(v1)
return true
}
- return false
}
-func rewriteValueAMD64_OpAMD64SHRB(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpRsh64Ux32(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (SHRB x (MOVQconst [c]))
+ // match: (Rsh64Ux32 <t> x y)
// cond:
- // result: (SHRBconst [c&31] x)
+ // result: (ANDQ (SHRQ <t> x y) (SBBQcarrymask <t> (CMPLconst y [64])))
for {
+ t := v.Type
x := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64MOVQconst {
- break
- }
- c := v_1.AuxInt
- v.reset(OpAMD64SHRBconst)
- v.AuxInt = c & 31
- v.AddArg(x)
+ y := v.Args[1]
+ v.reset(OpAMD64ANDQ)
+ v0 := b.NewValue0(v.Line, OpAMD64SHRQ, t)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpAMD64SBBQcarrymask, t)
+ v2 := b.NewValue0(v.Line, OpAMD64CMPLconst, TypeFlags)
+ v2.AuxInt = 64
+ v2.AddArg(y)
+ v1.AddArg(v2)
+ v.AddArg(v1)
return true
}
- // match: (SHRB x (MOVLconst [c]))
+}
+func rewriteValueAMD64_OpRsh64Ux64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh64Ux64 <t> x y)
// cond:
- // result: (SHRBconst [c&31] x)
+ // result: (ANDQ (SHRQ <t> x y) (SBBQcarrymask <t> (CMPQconst y [64])))
for {
+ t := v.Type
x := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64MOVLconst {
- break
- }
- c := v_1.AuxInt
- v.reset(OpAMD64SHRBconst)
- v.AuxInt = c & 31
- v.AddArg(x)
+ y := v.Args[1]
+ v.reset(OpAMD64ANDQ)
+ v0 := b.NewValue0(v.Line, OpAMD64SHRQ, t)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpAMD64SBBQcarrymask, t)
+ v2 := b.NewValue0(v.Line, OpAMD64CMPQconst, TypeFlags)
+ v2.AuxInt = 64
+ v2.AddArg(y)
+ v1.AddArg(v2)
+ v.AddArg(v1)
return true
}
- return false
}
-func rewriteValueAMD64_OpAMD64SHRL(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpRsh64Ux8(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (SHRL x (MOVQconst [c]))
+ // match: (Rsh64Ux8 <t> x y)
// cond:
- // result: (SHRLconst [c&31] x)
+ // result: (ANDQ (SHRQ <t> x y) (SBBQcarrymask <t> (CMPBconst y [64])))
for {
+ t := v.Type
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)
+ y := v.Args[1]
+ v.reset(OpAMD64ANDQ)
+ v0 := b.NewValue0(v.Line, OpAMD64SHRQ, t)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpAMD64SBBQcarrymask, t)
+ v2 := b.NewValue0(v.Line, OpAMD64CMPBconst, TypeFlags)
+ v2.AuxInt = 64
+ v2.AddArg(y)
+ v1.AddArg(v2)
+ v.AddArg(v1)
return true
}
- // match: (SHRL x (MOVLconst [c]))
+}
+func rewriteValueAMD64_OpRsh64x16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh64x16 <t> x y)
// cond:
- // result: (SHRLconst [c&31] x)
+ // result: (SARQ <t> x (ORL <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPWconst y [64])))))
for {
+ t := v.Type
x := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64MOVLconst {
- break
- }
- c := v_1.AuxInt
- v.reset(OpAMD64SHRLconst)
- v.AuxInt = c & 31
+ 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)
+ v1.AddArg(v2)
+ v0.AddArg(v1)
+ v.AddArg(v0)
return true
}
- // match: (SHRL x (ANDLconst [31] y))
+}
+func rewriteValueAMD64_OpRsh64x32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh64x32 <t> x y)
// cond:
- // result: (SHRL x y)
+ // result: (SARQ <t> x (ORL <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPLconst y [64])))))
for {
+ t := v.Type
x := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64ANDLconst {
- break
- }
- if v_1.AuxInt != 31 {
- break
- }
- y := v_1.Args[0]
- v.reset(OpAMD64SHRL)
+ y := v.Args[1]
+ v.reset(OpAMD64SARQ)
+ v.Type = t
v.AddArg(x)
- v.AddArg(y)
+ 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)
+ v1.AddArg(v2)
+ v0.AddArg(v1)
+ v.AddArg(v0)
return true
}
- return false
}
-func rewriteValueAMD64_OpAMD64SHRQ(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpRsh64x64(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (SHRQ x (MOVQconst [c]))
+ // match: (Rsh64x64 <t> x y)
// cond:
- // result: (SHRQconst [c&63] x)
+ // result: (SARQ <t> x (ORQ <y.Type> y (NOTQ <y.Type> (SBBQcarrymask <y.Type> (CMPQconst y [64])))))
for {
+ t := v.Type
x := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64MOVQconst {
- break
- }
- c := v_1.AuxInt
- v.reset(OpAMD64SHRQconst)
- v.AuxInt = c & 63
+ 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)
+ v1.AddArg(v2)
+ v0.AddArg(v1)
+ v.AddArg(v0)
return true
}
- // match: (SHRQ x (MOVLconst [c]))
+}
+func rewriteValueAMD64_OpRsh64x8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh64x8 <t> x y)
// cond:
- // result: (SHRQconst [c&63] x)
+ // result: (SARQ <t> x (ORL <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPBconst y [64])))))
for {
+ t := v.Type
x := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64MOVLconst {
- break
- }
- c := v_1.AuxInt
- v.reset(OpAMD64SHRQconst)
- v.AuxInt = c & 63
+ 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)
+ v1.AddArg(v2)
+ v0.AddArg(v1)
+ v.AddArg(v0)
return true
}
- // match: (SHRQ x (ANDQconst [63] y))
+}
+func rewriteValueAMD64_OpRsh8Ux16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh8Ux16 <t> x y)
// cond:
- // result: (SHRQ x y)
+ // result: (ANDL (SHRB <t> x y) (SBBLcarrymask <t> (CMPWconst y [8])))
for {
+ t := v.Type
x := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64ANDQconst {
- break
- }
- if v_1.AuxInt != 63 {
- break
- }
- y := v_1.Args[0]
- v.reset(OpAMD64SHRQ)
- v.AddArg(x)
- v.AddArg(y)
+ y := v.Args[1]
+ v.reset(OpAMD64ANDL)
+ v0 := b.NewValue0(v.Line, OpAMD64SHRB, t)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, t)
+ v2 := b.NewValue0(v.Line, OpAMD64CMPWconst, TypeFlags)
+ v2.AuxInt = 8
+ v2.AddArg(y)
+ v1.AddArg(v2)
+ v.AddArg(v1)
return true
}
- return false
}
-func rewriteValueAMD64_OpAMD64SHRW(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpRsh8Ux32(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (SHRW x (MOVQconst [c]))
+ // match: (Rsh8Ux32 <t> x y)
// cond:
- // result: (SHRWconst [c&31] x)
+ // result: (ANDL (SHRB <t> x y) (SBBLcarrymask <t> (CMPLconst y [8])))
for {
+ t := v.Type
x := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64MOVQconst {
- break
- }
- c := v_1.AuxInt
- v.reset(OpAMD64SHRWconst)
- v.AuxInt = c & 31
- v.AddArg(x)
+ y := v.Args[1]
+ v.reset(OpAMD64ANDL)
+ v0 := b.NewValue0(v.Line, OpAMD64SHRB, t)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, t)
+ v2 := b.NewValue0(v.Line, OpAMD64CMPLconst, TypeFlags)
+ v2.AuxInt = 8
+ v2.AddArg(y)
+ v1.AddArg(v2)
+ v.AddArg(v1)
return true
}
- // match: (SHRW x (MOVLconst [c]))
+}
+func rewriteValueAMD64_OpRsh8Ux64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh8Ux64 <t> x y)
// cond:
- // result: (SHRWconst [c&31] x)
+ // result: (ANDL (SHRB <t> x y) (SBBLcarrymask <t> (CMPQconst y [8])))
for {
+ t := v.Type
x := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64MOVLconst {
- break
- }
- c := v_1.AuxInt
- v.reset(OpAMD64SHRWconst)
- v.AuxInt = c & 31
- v.AddArg(x)
+ y := v.Args[1]
+ v.reset(OpAMD64ANDL)
+ v0 := b.NewValue0(v.Line, OpAMD64SHRB, t)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, t)
+ v2 := b.NewValue0(v.Line, OpAMD64CMPQconst, TypeFlags)
+ v2.AuxInt = 8
+ v2.AddArg(y)
+ v1.AddArg(v2)
+ v.AddArg(v1)
return true
}
- return false
}
-func rewriteValueAMD64_OpAMD64SUBL(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpRsh8Ux8(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (SUBL x (MOVLconst [c]))
+ // match: (Rsh8Ux8 <t> x y)
// cond:
- // result: (SUBLconst x [c])
+ // result: (ANDL (SHRB <t> x y) (SBBLcarrymask <t> (CMPBconst y [8])))
for {
+ t := v.Type
x := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64MOVLconst {
- break
- }
- c := v_1.AuxInt
- v.reset(OpAMD64SUBLconst)
- v.AddArg(x)
- v.AuxInt = c
- return true
- }
- // match: (SUBL (MOVLconst [c]) x)
- // cond:
- // result: (NEGL (SUBLconst <v.Type> x [c]))
- for {
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64MOVLconst {
- break
- }
- c := v_0.AuxInt
- x := v.Args[1]
- v.reset(OpAMD64NEGL)
- v0 := b.NewValue0(v.Line, OpAMD64SUBLconst, v.Type)
+ y := v.Args[1]
+ v.reset(OpAMD64ANDL)
+ v0 := b.NewValue0(v.Line, OpAMD64SHRB, t)
v0.AddArg(x)
- v0.AuxInt = c
+ v0.AddArg(y)
v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpAMD64SBBLcarrymask, t)
+ v2 := b.NewValue0(v.Line, OpAMD64CMPBconst, TypeFlags)
+ v2.AuxInt = 8
+ v2.AddArg(y)
+ v1.AddArg(v2)
+ v.AddArg(v1)
return true
}
- // match: (SUBL x x)
+}
+func rewriteValueAMD64_OpRsh8x16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh8x16 <t> x y)
// cond:
- // result: (MOVLconst [0])
+ // result: (SARB <t> x (ORL <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPWconst y [8])))))
for {
+ t := v.Type
x := v.Args[0]
- if x != v.Args[1] {
- break
- }
- v.reset(OpAMD64MOVLconst)
- v.AuxInt = 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.AddArg(v0)
return true
}
- return false
}
-func rewriteValueAMD64_OpAMD64SUBLconst(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpRsh8x32(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (SUBLconst [c] x)
- // cond: int32(c) == 0
- // result: x
+ // match: (Rsh8x32 <t> x y)
+ // cond:
+ // result: (SARB <t> x (ORL <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPLconst y [8])))))
for {
- c := v.AuxInt
+ t := v.Type
x := v.Args[0]
- if !(int32(c) == 0) {
- break
- }
- v.reset(OpCopy)
- v.Type = x.Type
+ 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.AddArg(v2)
+ v0.AddArg(v1)
+ v.AddArg(v0)
return true
}
- // match: (SUBLconst [c] x)
+}
+func rewriteValueAMD64_OpRsh8x64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh8x64 <t> x y)
// cond:
- // result: (ADDLconst [int64(int32(-c))] x)
+ // result: (SARB <t> x (ORQ <y.Type> y (NOTQ <y.Type> (SBBQcarrymask <y.Type> (CMPQconst y [8])))))
for {
- c := v.AuxInt
+ t := v.Type
x := v.Args[0]
- v.reset(OpAMD64ADDLconst)
- v.AuxInt = int64(int32(-c))
+ 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)
+ v1.AddArg(v2)
+ v0.AddArg(v1)
+ v.AddArg(v0)
return true
}
}
-func rewriteValueAMD64_OpAMD64SUBQ(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpRsh8x8(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (SUBQ x (MOVQconst [c]))
- // cond: is32Bit(c)
- // result: (SUBQconst x [c])
+ // match: (Rsh8x8 <t> x y)
+ // cond:
+ // result: (SARB <t> x (ORL <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPBconst y [8])))))
for {
+ t := v.Type
x := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64MOVQconst {
- break
- }
- c := v_1.AuxInt
- if !(is32Bit(c)) {
- break
- }
- v.reset(OpAMD64SUBQconst)
+ y := v.Args[1]
+ v.reset(OpAMD64SARB)
+ v.Type = t
v.AddArg(x)
- v.AuxInt = c
+ 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)
+ v1.AddArg(v2)
+ v0.AddArg(v1)
+ v.AddArg(v0)
return true
}
- // match: (SUBQ (MOVQconst [c]) x)
- // cond: is32Bit(c)
- // result: (NEGQ (SUBQconst <v.Type> x [c]))
+}
+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))
for {
+ t := v.Type
v_0 := v.Args[0]
- if v_0.Op != OpAMD64MOVQconst {
- break
- }
- c := v_0.AuxInt
- x := v.Args[1]
- if !(is32Bit(c)) {
+ if v_0.Op != OpAMD64AddTupleFirst32 {
break
}
- v.reset(OpAMD64NEGQ)
- v0 := b.NewValue0(v.Line, OpAMD64SUBQconst, v.Type)
- v0.AddArg(x)
- v0.AuxInt = c
+ 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)
v.AddArg(v0)
return true
}
- // match: (SUBQ x x)
+ // match: (Select0 <t> (AddTupleFirst64 tuple val))
// cond:
- // result: (MOVQconst [0])
+ // result: (ADDQ val (Select0 <t> tuple))
for {
- x := v.Args[0]
- if x != v.Args[1] {
+ t := v.Type
+ v_0 := v.Args[0]
+ if v_0.Op != OpAMD64AddTupleFirst64 {
break
}
- v.reset(OpAMD64MOVQconst)
- v.AuxInt = 0
+ 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)
+ v.AddArg(v0)
return true
}
return false
}
-func rewriteValueAMD64_OpAMD64SUBQconst(v *Value, config *Config) bool {
+func rewriteValueAMD64_OpSelect1(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (SUBQconst [0] x)
- // cond:
- // result: x
- for {
- if v.AuxInt != 0 {
- break
- }
- x := v.Args[0]
- v.reset(OpCopy)
- v.Type = x.Type
- v.AddArg(x)
- return true
- }
- // match: (SUBQconst [c] x)
- // cond: c != -(1<<31)
- // result: (ADDQconst [-c] x)
- for {
- c := v.AuxInt
- x := v.Args[0]
- if !(c != -(1 << 31)) {
- break
- }
- v.reset(OpAMD64ADDQconst)
- v.AuxInt = -c
- v.AddArg(x)
- return true
- }
- // match: (SUBQconst (MOVQconst [d]) [c])
+ // match: (Select1 (AddTupleFirst32 tuple _ ))
// cond:
- // result: (MOVQconst [d-c])
+ // result: (Select1 tuple)
for {
v_0 := v.Args[0]
- if v_0.Op != OpAMD64MOVQconst {
+ if v_0.Op != OpAMD64AddTupleFirst32 {
break
}
- d := v_0.AuxInt
- c := v.AuxInt
- v.reset(OpAMD64MOVQconst)
- v.AuxInt = d - c
+ tuple := v_0.Args[0]
+ v.reset(OpSelect1)
+ v.AddArg(tuple)
return true
}
- // match: (SUBQconst (SUBQconst x [d]) [c])
- // cond: is32Bit(-c-d)
- // result: (ADDQconst [-c-d] x)
+ // match: (Select1 (AddTupleFirst64 tuple _ ))
+ // cond:
+ // result: (Select1 tuple)
for {
v_0 := v.Args[0]
- if v_0.Op != OpAMD64SUBQconst {
- break
- }
- x := v_0.Args[0]
- d := v_0.AuxInt
- c := v.AuxInt
- if !(is32Bit(-c - d)) {
+ if v_0.Op != OpAMD64AddTupleFirst64 {
break
}
- v.reset(OpAMD64ADDQconst)
- v.AuxInt = -c - d
- v.AddArg(x)
+ tuple := v_0.Args[0]
+ v.reset(OpSelect1)
+ v.AddArg(tuple)
return true
}
return false
@@ -16348,8 +19338,29 @@ func rewriteValueAMD64_OpSignExt8to64(v *Value, config *Config) bool {
// result: (MOVBQSX x)
for {
x := v.Args[0]
- v.reset(OpAMD64MOVBQSX)
- v.AddArg(x)
+ 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)
+ v.AddArg(v0)
return true
}
}
@@ -16584,16 +19595,34 @@ func rewriteValueAMD64_OpSubPtr(v *Value, config *Config) bool {
b := v.Block
_ = b
// match: (SubPtr x y)
- // cond:
- // result: (SUBQ x y)
+ // cond: config.PtrSize == 8
+ // result: (SUBQ x y)
for {
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 {
+ 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(v *Value, config *Config) bool {
b := v.Block
@@ -16679,171 +19708,6 @@ func rewriteValueAMD64_OpTrunc64to8(v *Value, config *Config) bool {
return true
}
}
-func rewriteValueAMD64_OpAMD64XORL(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (XORL x (MOVLconst [c]))
- // cond:
- // result: (XORLconst [c] x)
- for {
- x := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64MOVLconst {
- break
- }
- c := v_1.AuxInt
- v.reset(OpAMD64XORLconst)
- v.AuxInt = c
- v.AddArg(x)
- return true
- }
- // match: (XORL (MOVLconst [c]) x)
- // cond:
- // result: (XORLconst [c] x)
- for {
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64MOVLconst {
- break
- }
- c := v_0.AuxInt
- x := v.Args[1]
- v.reset(OpAMD64XORLconst)
- v.AuxInt = c
- v.AddArg(x)
- return true
- }
- // match: (XORL x x)
- // cond:
- // result: (MOVLconst [0])
- for {
- x := v.Args[0]
- if x != v.Args[1] {
- break
- }
- v.reset(OpAMD64MOVLconst)
- v.AuxInt = 0
- return true
- }
- return false
-}
-func rewriteValueAMD64_OpAMD64XORLconst(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (XORLconst [c] x)
- // cond: int32(c)==0
- // result: x
- for {
- c := v.AuxInt
- x := v.Args[0]
- if !(int32(c) == 0) {
- break
- }
- v.reset(OpCopy)
- v.Type = x.Type
- v.AddArg(x)
- return true
- }
- // match: (XORLconst [c] (MOVLconst [d]))
- // cond:
- // result: (MOVLconst [c^d])
- for {
- c := v.AuxInt
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64MOVLconst {
- break
- }
- d := v_0.AuxInt
- v.reset(OpAMD64MOVLconst)
- v.AuxInt = c ^ d
- return true
- }
- return false
-}
-func rewriteValueAMD64_OpAMD64XORQ(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (XORQ x (MOVQconst [c]))
- // cond: is32Bit(c)
- // result: (XORQconst [c] x)
- for {
- x := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpAMD64MOVQconst {
- break
- }
- c := v_1.AuxInt
- if !(is32Bit(c)) {
- break
- }
- v.reset(OpAMD64XORQconst)
- v.AuxInt = c
- v.AddArg(x)
- return true
- }
- // match: (XORQ (MOVQconst [c]) x)
- // cond: is32Bit(c)
- // result: (XORQconst [c] x)
- for {
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64MOVQconst {
- break
- }
- c := v_0.AuxInt
- x := v.Args[1]
- if !(is32Bit(c)) {
- break
- }
- v.reset(OpAMD64XORQconst)
- v.AuxInt = c
- v.AddArg(x)
- return true
- }
- // match: (XORQ x x)
- // cond:
- // result: (MOVQconst [0])
- for {
- x := v.Args[0]
- if x != v.Args[1] {
- break
- }
- v.reset(OpAMD64MOVQconst)
- v.AuxInt = 0
- return true
- }
- return false
-}
-func rewriteValueAMD64_OpAMD64XORQconst(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (XORQconst [0] x)
- // cond:
- // result: x
- for {
- if v.AuxInt != 0 {
- break
- }
- x := v.Args[0]
- v.reset(OpCopy)
- v.Type = x.Type
- v.AddArg(x)
- return true
- }
- // match: (XORQconst [c] (MOVQconst [d]))
- // cond:
- // result: (MOVQconst [c^d])
- for {
- c := v.AuxInt
- v_0 := v.Args[0]
- if v_0.Op != OpAMD64MOVQconst {
- break
- }
- d := v_0.AuxInt
- v.reset(OpAMD64MOVQconst)
- v.AuxInt = c ^ d
- return true
- }
- return false
-}
func rewriteValueAMD64_OpXor16(v *Value, config *Config) bool {
b := v.Block
_ = b
@@ -16907,88 +19771,94 @@ func rewriteValueAMD64_OpXor8(v *Value, config *Config) bool {
func rewriteValueAMD64_OpZero(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (Zero [0] _ mem)
- // cond:
+ // match: (Zero [s] _ mem)
+ // cond: SizeAndAlign(s).Size() == 0
// result: mem
for {
- if v.AuxInt != 0 {
+ s := v.AuxInt
+ mem := v.Args[1]
+ if !(SizeAndAlign(s).Size() == 0) {
break
}
- mem := v.Args[1]
v.reset(OpCopy)
v.Type = mem.Type
v.AddArg(mem)
return true
}
- // match: (Zero [1] destptr mem)
- // cond:
+ // match: (Zero [s] destptr mem)
+ // cond: SizeAndAlign(s).Size() == 1
// result: (MOVBstoreconst [0] destptr mem)
for {
- if v.AuxInt != 1 {
- break
- }
+ s := v.AuxInt
destptr := v.Args[0]
mem := v.Args[1]
+ if !(SizeAndAlign(s).Size() == 1) {
+ break
+ }
v.reset(OpAMD64MOVBstoreconst)
v.AuxInt = 0
v.AddArg(destptr)
v.AddArg(mem)
return true
}
- // match: (Zero [2] destptr mem)
- // cond:
+ // match: (Zero [s] destptr mem)
+ // cond: SizeAndAlign(s).Size() == 2
// result: (MOVWstoreconst [0] destptr mem)
for {
- if v.AuxInt != 2 {
- break
- }
+ s := v.AuxInt
destptr := v.Args[0]
mem := v.Args[1]
+ if !(SizeAndAlign(s).Size() == 2) {
+ break
+ }
v.reset(OpAMD64MOVWstoreconst)
v.AuxInt = 0
v.AddArg(destptr)
v.AddArg(mem)
return true
}
- // match: (Zero [4] destptr mem)
- // cond:
+ // match: (Zero [s] destptr mem)
+ // cond: SizeAndAlign(s).Size() == 4
// result: (MOVLstoreconst [0] destptr mem)
for {
- if v.AuxInt != 4 {
- break
- }
+ s := v.AuxInt
destptr := v.Args[0]
mem := v.Args[1]
+ if !(SizeAndAlign(s).Size() == 4) {
+ break
+ }
v.reset(OpAMD64MOVLstoreconst)
v.AuxInt = 0
v.AddArg(destptr)
v.AddArg(mem)
return true
}
- // match: (Zero [8] destptr mem)
- // cond:
+ // match: (Zero [s] destptr mem)
+ // cond: SizeAndAlign(s).Size() == 8
// result: (MOVQstoreconst [0] destptr mem)
for {
- if v.AuxInt != 8 {
- break
- }
+ s := v.AuxInt
destptr := v.Args[0]
mem := v.Args[1]
+ if !(SizeAndAlign(s).Size() == 8) {
+ break
+ }
v.reset(OpAMD64MOVQstoreconst)
v.AuxInt = 0
v.AddArg(destptr)
v.AddArg(mem)
return true
}
- // match: (Zero [3] destptr mem)
- // cond:
+ // match: (Zero [s] destptr mem)
+ // cond: SizeAndAlign(s).Size() == 3
// result: (MOVBstoreconst [makeValAndOff(0,2)] destptr (MOVWstoreconst [0] destptr mem))
for {
- if v.AuxInt != 3 {
- break
- }
+ s := v.AuxInt
destptr := v.Args[0]
mem := v.Args[1]
+ if !(SizeAndAlign(s).Size() == 3) {
+ break
+ }
v.reset(OpAMD64MOVBstoreconst)
v.AuxInt = makeValAndOff(0, 2)
v.AddArg(destptr)
@@ -16999,15 +19869,16 @@ func rewriteValueAMD64_OpZero(v *Value, config *Config) bool {
v.AddArg(v0)
return true
}
- // match: (Zero [5] destptr mem)
- // cond:
+ // match: (Zero [s] destptr mem)
+ // cond: SizeAndAlign(s).Size() == 5
// result: (MOVBstoreconst [makeValAndOff(0,4)] destptr (MOVLstoreconst [0] destptr mem))
for {
- if v.AuxInt != 5 {
- break
- }
+ s := v.AuxInt
destptr := v.Args[0]
mem := v.Args[1]
+ if !(SizeAndAlign(s).Size() == 5) {
+ break
+ }
v.reset(OpAMD64MOVBstoreconst)
v.AuxInt = makeValAndOff(0, 4)
v.AddArg(destptr)
@@ -17018,15 +19889,16 @@ func rewriteValueAMD64_OpZero(v *Value, config *Config) bool {
v.AddArg(v0)
return true
}
- // match: (Zero [6] destptr mem)
- // cond:
+ // match: (Zero [s] destptr mem)
+ // cond: SizeAndAlign(s).Size() == 6
// result: (MOVWstoreconst [makeValAndOff(0,4)] destptr (MOVLstoreconst [0] destptr mem))
for {
- if v.AuxInt != 6 {
- break
- }
+ s := v.AuxInt
destptr := v.Args[0]
mem := v.Args[1]
+ if !(SizeAndAlign(s).Size() == 6) {
+ break
+ }
v.reset(OpAMD64MOVWstoreconst)
v.AuxInt = makeValAndOff(0, 4)
v.AddArg(destptr)
@@ -17037,15 +19909,16 @@ func rewriteValueAMD64_OpZero(v *Value, config *Config) bool {
v.AddArg(v0)
return true
}
- // match: (Zero [7] destptr mem)
- // cond:
+ // match: (Zero [s] destptr mem)
+ // cond: SizeAndAlign(s).Size() == 7
// result: (MOVLstoreconst [makeValAndOff(0,3)] destptr (MOVLstoreconst [0] destptr mem))
for {
- if v.AuxInt != 7 {
- break
- }
+ s := v.AuxInt
destptr := v.Args[0]
mem := v.Args[1]
+ if !(SizeAndAlign(s).Size() == 7) {
+ break
+ }
v.reset(OpAMD64MOVLstoreconst)
v.AuxInt = makeValAndOff(0, 3)
v.AddArg(destptr)
@@ -17056,21 +19929,21 @@ func rewriteValueAMD64_OpZero(v *Value, config *Config) bool {
v.AddArg(v0)
return true
}
- // match: (Zero [size] destptr mem)
- // cond: size%8 != 0 && size > 8
- // result: (Zero [size-size%8] (ADDQconst destptr [size%8]) (MOVQstoreconst [0] destptr mem))
+ // 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))
for {
- size := v.AuxInt
+ s := v.AuxInt
destptr := v.Args[0]
mem := v.Args[1]
- if !(size%8 != 0 && size > 8) {
+ if !(SizeAndAlign(s).Size()%8 != 0 && SizeAndAlign(s).Size() > 8) {
break
}
v.reset(OpZero)
- v.AuxInt = size - size%8
- v0 := b.NewValue0(v.Line, OpAMD64ADDQconst, config.fe.TypeUInt64())
+ 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)
- v0.AuxInt = size % 8
v.AddArg(v0)
v1 := b.NewValue0(v.Line, OpAMD64MOVQstoreconst, TypeMem)
v1.AuxInt = 0
@@ -17079,15 +19952,16 @@ func rewriteValueAMD64_OpZero(v *Value, config *Config) bool {
v.AddArg(v1)
return true
}
- // match: (Zero [16] destptr mem)
- // cond:
+ // match: (Zero [s] destptr mem)
+ // cond: SizeAndAlign(s).Size() == 16
// result: (MOVQstoreconst [makeValAndOff(0,8)] destptr (MOVQstoreconst [0] destptr mem))
for {
- if v.AuxInt != 16 {
- break
- }
+ s := v.AuxInt
destptr := v.Args[0]
mem := v.Args[1]
+ if !(SizeAndAlign(s).Size() == 16) {
+ break
+ }
v.reset(OpAMD64MOVQstoreconst)
v.AuxInt = makeValAndOff(0, 8)
v.AddArg(destptr)
@@ -17098,15 +19972,16 @@ func rewriteValueAMD64_OpZero(v *Value, config *Config) bool {
v.AddArg(v0)
return true
}
- // match: (Zero [24] destptr mem)
- // cond:
+ // 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)))
for {
- if v.AuxInt != 24 {
- break
- }
+ s := v.AuxInt
destptr := v.Args[0]
mem := v.Args[1]
+ if !(SizeAndAlign(s).Size() == 24) {
+ break
+ }
v.reset(OpAMD64MOVQstoreconst)
v.AuxInt = makeValAndOff(0, 16)
v.AddArg(destptr)
@@ -17121,15 +19996,16 @@ func rewriteValueAMD64_OpZero(v *Value, config *Config) bool {
v.AddArg(v0)
return true
}
- // match: (Zero [32] destptr mem)
- // cond:
+ // 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))))
for {
- if v.AuxInt != 32 {
- break
- }
+ s := v.AuxInt
destptr := v.Args[0]
mem := v.Args[1]
+ if !(SizeAndAlign(s).Size() == 32) {
+ break
+ }
v.reset(OpAMD64MOVQstoreconst)
v.AuxInt = makeValAndOff(0, 24)
v.AddArg(destptr)
@@ -17148,19 +20024,19 @@ func rewriteValueAMD64_OpZero(v *Value, config *Config) bool {
v.AddArg(v0)
return true
}
- // match: (Zero [size] destptr mem)
- // cond: size <= 1024 && size%8 == 0 && size%16 != 0 && !config.noDuffDevice
- // result: (Zero [size-8] (ADDQconst [8] destptr) (MOVQstore destptr (MOVQconst [0]) mem))
+ // 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))
for {
- size := v.AuxInt
+ s := v.AuxInt
destptr := v.Args[0]
mem := v.Args[1]
- if !(size <= 1024 && size%8 == 0 && size%16 != 0 && !config.noDuffDevice) {
+ if !(SizeAndAlign(s).Size() <= 1024 && SizeAndAlign(s).Size()%8 == 0 && SizeAndAlign(s).Size()%16 != 0 && !config.noDuffDevice) {
break
}
v.reset(OpZero)
- v.AuxInt = size - 8
- v0 := b.NewValue0(v.Line, OpAMD64ADDQconst, config.fe.TypeUInt64())
+ v.AuxInt = SizeAndAlign(s).Size() - 8
+ v0 := b.NewValue0(v.Line, OpOffPtr, destptr.Type)
v0.AuxInt = 8
v0.AddArg(destptr)
v.AddArg(v0)
@@ -17173,18 +20049,18 @@ func rewriteValueAMD64_OpZero(v *Value, config *Config) bool {
v.AddArg(v1)
return true
}
- // match: (Zero [size] destptr mem)
- // cond: size <= 1024 && size%16 == 0 && !config.noDuffDevice
- // result: (DUFFZERO [size] destptr (MOVOconst [0]) mem)
+ // 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)
for {
- size := v.AuxInt
+ s := v.AuxInt
destptr := v.Args[0]
mem := v.Args[1]
- if !(size <= 1024 && size%16 == 0 && !config.noDuffDevice) {
+ if !(SizeAndAlign(s).Size() <= 1024 && SizeAndAlign(s).Size()%16 == 0 && !config.noDuffDevice) {
break
}
v.reset(OpAMD64DUFFZERO)
- v.AuxInt = size
+ v.AuxInt = SizeAndAlign(s).Size()
v.AddArg(destptr)
v0 := b.NewValue0(v.Line, OpAMD64MOVOconst, TypeInt128)
v0.AuxInt = 0
@@ -17192,20 +20068,20 @@ func rewriteValueAMD64_OpZero(v *Value, config *Config) bool {
v.AddArg(mem)
return true
}
- // match: (Zero [size] destptr mem)
- // cond: (size > 1024 || (config.noDuffDevice && size > 32)) && size%8 == 0
- // result: (REPSTOSQ destptr (MOVQconst [size/8]) (MOVQconst [0]) mem)
+ // 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)
for {
- size := v.AuxInt
+ s := v.AuxInt
destptr := v.Args[0]
mem := v.Args[1]
- if !((size > 1024 || (config.noDuffDevice && size > 32)) && size%8 == 0) {
+ if !((SizeAndAlign(s).Size() > 1024 || (config.noDuffDevice && SizeAndAlign(s).Size() > 32)) && SizeAndAlign(s).Size()%8 == 0) {
break
}
v.reset(OpAMD64REPSTOSQ)
v.AddArg(destptr)
v0 := b.NewValue0(v.Line, OpAMD64MOVQconst, config.fe.TypeUInt64())
- v0.AuxInt = size / 8
+ v0.AuxInt = SizeAndAlign(s).Size() / 8
v.AddArg(v0)
v1 := b.NewValue0(v.Line, OpAMD64MOVQconst, config.fe.TypeUInt64())
v1.AuxInt = 0
@@ -17293,7 +20169,7 @@ func rewriteValueAMD64_OpZeroExt8to64(v *Value, config *Config) bool {
return true
}
}
-func rewriteBlockAMD64(b *Block) bool {
+func rewriteBlockAMD64(b *Block, config *Config) bool {
switch b.Kind {
case BlockAMD64EQ:
// match: (EQ (InvertFlags cmp) yes no)
@@ -17842,6 +20718,7 @@ func rewriteBlockAMD64(b *Block) bool {
// result: (NE (TESTB cond cond) yes no)
for {
v := b.Control
+ _ = v
cond := b.Control
yes := b.Succs[0]
no := b.Succs[1]
diff --git a/src/cmd/compile/internal/ssa/rewriteARM.go b/src/cmd/compile/internal/ssa/rewriteARM.go
index b57283e..0f8a77f 100644
--- a/src/cmd/compile/internal/ssa/rewriteARM.go
+++ b/src/cmd/compile/internal/ssa/rewriteARM.go
@@ -8,37 +8,737 @@ import "math"
var _ = math.MinInt8 // in case not otherwise used
func rewriteValueARM(v *Value, config *Config) bool {
switch v.Op {
+ case OpARMADC:
+ return rewriteValueARM_OpARMADC(v, config)
+ case OpARMADCconst:
+ return rewriteValueARM_OpARMADCconst(v, config)
+ case OpARMADCshiftLL:
+ return rewriteValueARM_OpARMADCshiftLL(v, config)
+ case OpARMADCshiftLLreg:
+ return rewriteValueARM_OpARMADCshiftLLreg(v, config)
+ case OpARMADCshiftRA:
+ return rewriteValueARM_OpARMADCshiftRA(v, config)
+ case OpARMADCshiftRAreg:
+ return rewriteValueARM_OpARMADCshiftRAreg(v, config)
+ case OpARMADCshiftRL:
+ return rewriteValueARM_OpARMADCshiftRL(v, config)
+ case OpARMADCshiftRLreg:
+ return rewriteValueARM_OpARMADCshiftRLreg(v, config)
case OpARMADD:
return rewriteValueARM_OpARMADD(v, config)
+ case OpARMADDS:
+ return rewriteValueARM_OpARMADDS(v, config)
+ case OpARMADDSshiftLL:
+ return rewriteValueARM_OpARMADDSshiftLL(v, config)
+ case OpARMADDSshiftLLreg:
+ return rewriteValueARM_OpARMADDSshiftLLreg(v, config)
+ case OpARMADDSshiftRA:
+ return rewriteValueARM_OpARMADDSshiftRA(v, config)
+ case OpARMADDSshiftRAreg:
+ return rewriteValueARM_OpARMADDSshiftRAreg(v, config)
+ case OpARMADDSshiftRL:
+ return rewriteValueARM_OpARMADDSshiftRL(v, config)
+ case OpARMADDSshiftRLreg:
+ return rewriteValueARM_OpARMADDSshiftRLreg(v, config)
+ case OpARMADDconst:
+ return rewriteValueARM_OpARMADDconst(v, config)
+ case OpARMADDshiftLL:
+ return rewriteValueARM_OpARMADDshiftLL(v, config)
+ case OpARMADDshiftLLreg:
+ return rewriteValueARM_OpARMADDshiftLLreg(v, config)
+ case OpARMADDshiftRA:
+ return rewriteValueARM_OpARMADDshiftRA(v, config)
+ case OpARMADDshiftRAreg:
+ return rewriteValueARM_OpARMADDshiftRAreg(v, config)
+ case OpARMADDshiftRL:
+ return rewriteValueARM_OpARMADDshiftRL(v, config)
+ case OpARMADDshiftRLreg:
+ return rewriteValueARM_OpARMADDshiftRLreg(v, config)
+ case OpARMAND:
+ return rewriteValueARM_OpARMAND(v, config)
+ case OpARMANDconst:
+ return rewriteValueARM_OpARMANDconst(v, config)
+ case OpARMANDshiftLL:
+ return rewriteValueARM_OpARMANDshiftLL(v, config)
+ case OpARMANDshiftLLreg:
+ return rewriteValueARM_OpARMANDshiftLLreg(v, config)
+ case OpARMANDshiftRA:
+ return rewriteValueARM_OpARMANDshiftRA(v, config)
+ case OpARMANDshiftRAreg:
+ return rewriteValueARM_OpARMANDshiftRAreg(v, config)
+ case OpARMANDshiftRL:
+ return rewriteValueARM_OpARMANDshiftRL(v, config)
+ case OpARMANDshiftRLreg:
+ return rewriteValueARM_OpARMANDshiftRLreg(v, config)
+ case OpARMBIC:
+ return rewriteValueARM_OpARMBIC(v, config)
+ case OpARMBICconst:
+ return rewriteValueARM_OpARMBICconst(v, config)
+ case OpARMBICshiftLL:
+ return rewriteValueARM_OpARMBICshiftLL(v, config)
+ case OpARMBICshiftLLreg:
+ return rewriteValueARM_OpARMBICshiftLLreg(v, config)
+ case OpARMBICshiftRA:
+ return rewriteValueARM_OpARMBICshiftRA(v, config)
+ case OpARMBICshiftRAreg:
+ return rewriteValueARM_OpARMBICshiftRAreg(v, config)
+ case OpARMBICshiftRL:
+ return rewriteValueARM_OpARMBICshiftRL(v, config)
+ case OpARMBICshiftRLreg:
+ return rewriteValueARM_OpARMBICshiftRLreg(v, config)
+ case OpARMCMOVWHSconst:
+ return rewriteValueARM_OpARMCMOVWHSconst(v, config)
+ case OpARMCMOVWLSconst:
+ return rewriteValueARM_OpARMCMOVWLSconst(v, config)
+ case OpARMCMP:
+ return rewriteValueARM_OpARMCMP(v, config)
+ case OpARMCMPD:
+ return rewriteValueARM_OpARMCMPD(v, config)
+ case OpARMCMPF:
+ return rewriteValueARM_OpARMCMPF(v, config)
+ case OpARMCMPconst:
+ return rewriteValueARM_OpARMCMPconst(v, config)
+ case OpARMCMPshiftLL:
+ return rewriteValueARM_OpARMCMPshiftLL(v, config)
+ case OpARMCMPshiftLLreg:
+ return rewriteValueARM_OpARMCMPshiftLLreg(v, config)
+ case OpARMCMPshiftRA:
+ return rewriteValueARM_OpARMCMPshiftRA(v, config)
+ case OpARMCMPshiftRAreg:
+ return rewriteValueARM_OpARMCMPshiftRAreg(v, config)
+ case OpARMCMPshiftRL:
+ return rewriteValueARM_OpARMCMPshiftRL(v, config)
+ case OpARMCMPshiftRLreg:
+ return rewriteValueARM_OpARMCMPshiftRLreg(v, config)
+ case OpARMEqual:
+ return rewriteValueARM_OpARMEqual(v, config)
+ case OpARMGreaterEqual:
+ return rewriteValueARM_OpARMGreaterEqual(v, config)
+ case OpARMGreaterEqualU:
+ return rewriteValueARM_OpARMGreaterEqualU(v, config)
+ case OpARMGreaterThan:
+ return rewriteValueARM_OpARMGreaterThan(v, config)
+ case OpARMGreaterThanU:
+ return rewriteValueARM_OpARMGreaterThanU(v, config)
+ case OpARMLessEqual:
+ return rewriteValueARM_OpARMLessEqual(v, config)
+ case OpARMLessEqualU:
+ return rewriteValueARM_OpARMLessEqualU(v, config)
+ case OpARMLessThan:
+ return rewriteValueARM_OpARMLessThan(v, config)
+ case OpARMLessThanU:
+ return rewriteValueARM_OpARMLessThanU(v, config)
+ case OpARMMOVBUload:
+ return rewriteValueARM_OpARMMOVBUload(v, config)
+ case OpARMMOVBUreg:
+ return rewriteValueARM_OpARMMOVBUreg(v, config)
+ case OpARMMOVBload:
+ return rewriteValueARM_OpARMMOVBload(v, config)
+ case OpARMMOVBreg:
+ return rewriteValueARM_OpARMMOVBreg(v, config)
+ case OpARMMOVBstore:
+ return rewriteValueARM_OpARMMOVBstore(v, config)
+ case OpARMMOVDload:
+ return rewriteValueARM_OpARMMOVDload(v, config)
+ case OpARMMOVDstore:
+ return rewriteValueARM_OpARMMOVDstore(v, config)
+ case OpARMMOVFload:
+ return rewriteValueARM_OpARMMOVFload(v, config)
+ case OpARMMOVFstore:
+ return rewriteValueARM_OpARMMOVFstore(v, config)
+ case OpARMMOVHUload:
+ return rewriteValueARM_OpARMMOVHUload(v, config)
+ case OpARMMOVHUreg:
+ return rewriteValueARM_OpARMMOVHUreg(v, config)
+ case OpARMMOVHload:
+ return rewriteValueARM_OpARMMOVHload(v, config)
+ case OpARMMOVHreg:
+ return rewriteValueARM_OpARMMOVHreg(v, config)
+ case OpARMMOVHstore:
+ return rewriteValueARM_OpARMMOVHstore(v, config)
+ case OpARMMOVWload:
+ return rewriteValueARM_OpARMMOVWload(v, config)
+ case OpARMMOVWloadidx:
+ return rewriteValueARM_OpARMMOVWloadidx(v, config)
+ case OpARMMOVWloadshiftLL:
+ return rewriteValueARM_OpARMMOVWloadshiftLL(v, config)
+ case OpARMMOVWloadshiftRA:
+ return rewriteValueARM_OpARMMOVWloadshiftRA(v, config)
+ case OpARMMOVWloadshiftRL:
+ return rewriteValueARM_OpARMMOVWloadshiftRL(v, config)
+ case OpARMMOVWreg:
+ return rewriteValueARM_OpARMMOVWreg(v, config)
+ case OpARMMOVWstore:
+ return rewriteValueARM_OpARMMOVWstore(v, config)
+ case OpARMMOVWstoreidx:
+ return rewriteValueARM_OpARMMOVWstoreidx(v, config)
+ case OpARMMOVWstoreshiftLL:
+ return rewriteValueARM_OpARMMOVWstoreshiftLL(v, config)
+ case OpARMMOVWstoreshiftRA:
+ return rewriteValueARM_OpARMMOVWstoreshiftRA(v, config)
+ case OpARMMOVWstoreshiftRL:
+ return rewriteValueARM_OpARMMOVWstoreshiftRL(v, config)
+ case OpARMMUL:
+ return rewriteValueARM_OpARMMUL(v, config)
+ case OpARMMULA:
+ return rewriteValueARM_OpARMMULA(v, config)
+ case OpARMMVN:
+ return rewriteValueARM_OpARMMVN(v, config)
+ case OpARMMVNshiftLL:
+ return rewriteValueARM_OpARMMVNshiftLL(v, config)
+ case OpARMMVNshiftLLreg:
+ return rewriteValueARM_OpARMMVNshiftLLreg(v, config)
+ case OpARMMVNshiftRA:
+ return rewriteValueARM_OpARMMVNshiftRA(v, config)
+ case OpARMMVNshiftRAreg:
+ return rewriteValueARM_OpARMMVNshiftRAreg(v, config)
+ case OpARMMVNshiftRL:
+ return rewriteValueARM_OpARMMVNshiftRL(v, config)
+ case OpARMMVNshiftRLreg:
+ return rewriteValueARM_OpARMMVNshiftRLreg(v, config)
+ case OpARMNotEqual:
+ return rewriteValueARM_OpARMNotEqual(v, config)
+ case OpARMOR:
+ return rewriteValueARM_OpARMOR(v, config)
+ case OpARMORconst:
+ return rewriteValueARM_OpARMORconst(v, config)
+ case OpARMORshiftLL:
+ return rewriteValueARM_OpARMORshiftLL(v, config)
+ case OpARMORshiftLLreg:
+ return rewriteValueARM_OpARMORshiftLLreg(v, config)
+ case OpARMORshiftRA:
+ return rewriteValueARM_OpARMORshiftRA(v, config)
+ case OpARMORshiftRAreg:
+ return rewriteValueARM_OpARMORshiftRAreg(v, config)
+ case OpARMORshiftRL:
+ return rewriteValueARM_OpARMORshiftRL(v, config)
+ case OpARMORshiftRLreg:
+ return rewriteValueARM_OpARMORshiftRLreg(v, config)
+ case OpARMRSB:
+ return rewriteValueARM_OpARMRSB(v, config)
+ case OpARMRSBSshiftLL:
+ return rewriteValueARM_OpARMRSBSshiftLL(v, config)
+ case OpARMRSBSshiftLLreg:
+ return rewriteValueARM_OpARMRSBSshiftLLreg(v, config)
+ case OpARMRSBSshiftRA:
+ return rewriteValueARM_OpARMRSBSshiftRA(v, config)
+ case OpARMRSBSshiftRAreg:
+ return rewriteValueARM_OpARMRSBSshiftRAreg(v, config)
+ case OpARMRSBSshiftRL:
+ return rewriteValueARM_OpARMRSBSshiftRL(v, config)
+ case OpARMRSBSshiftRLreg:
+ return rewriteValueARM_OpARMRSBSshiftRLreg(v, config)
+ case OpARMRSBconst:
+ return rewriteValueARM_OpARMRSBconst(v, config)
+ case OpARMRSBshiftLL:
+ return rewriteValueARM_OpARMRSBshiftLL(v, config)
+ case OpARMRSBshiftLLreg:
+ return rewriteValueARM_OpARMRSBshiftLLreg(v, config)
+ case OpARMRSBshiftRA:
+ return rewriteValueARM_OpARMRSBshiftRA(v, config)
+ case OpARMRSBshiftRAreg:
+ return rewriteValueARM_OpARMRSBshiftRAreg(v, config)
+ case OpARMRSBshiftRL:
+ return rewriteValueARM_OpARMRSBshiftRL(v, config)
+ case OpARMRSBshiftRLreg:
+ return rewriteValueARM_OpARMRSBshiftRLreg(v, config)
+ case OpARMRSCconst:
+ return rewriteValueARM_OpARMRSCconst(v, config)
+ case OpARMRSCshiftLL:
+ return rewriteValueARM_OpARMRSCshiftLL(v, config)
+ case OpARMRSCshiftLLreg:
+ return rewriteValueARM_OpARMRSCshiftLLreg(v, config)
+ case OpARMRSCshiftRA:
+ return rewriteValueARM_OpARMRSCshiftRA(v, config)
+ case OpARMRSCshiftRAreg:
+ return rewriteValueARM_OpARMRSCshiftRAreg(v, config)
+ case OpARMRSCshiftRL:
+ return rewriteValueARM_OpARMRSCshiftRL(v, config)
+ case OpARMRSCshiftRLreg:
+ return rewriteValueARM_OpARMRSCshiftRLreg(v, config)
+ case OpARMSBC:
+ return rewriteValueARM_OpARMSBC(v, config)
+ case OpARMSBCconst:
+ return rewriteValueARM_OpARMSBCconst(v, config)
+ case OpARMSBCshiftLL:
+ return rewriteValueARM_OpARMSBCshiftLL(v, config)
+ case OpARMSBCshiftLLreg:
+ return rewriteValueARM_OpARMSBCshiftLLreg(v, config)
+ case OpARMSBCshiftRA:
+ return rewriteValueARM_OpARMSBCshiftRA(v, config)
+ case OpARMSBCshiftRAreg:
+ return rewriteValueARM_OpARMSBCshiftRAreg(v, config)
+ case OpARMSBCshiftRL:
+ return rewriteValueARM_OpARMSBCshiftRL(v, config)
+ case OpARMSBCshiftRLreg:
+ return rewriteValueARM_OpARMSBCshiftRLreg(v, config)
+ case OpARMSLL:
+ return rewriteValueARM_OpARMSLL(v, config)
+ case OpARMSLLconst:
+ return rewriteValueARM_OpARMSLLconst(v, config)
+ case OpARMSRA:
+ return rewriteValueARM_OpARMSRA(v, config)
+ case OpARMSRAcond:
+ return rewriteValueARM_OpARMSRAcond(v, config)
+ case OpARMSRAconst:
+ return rewriteValueARM_OpARMSRAconst(v, config)
+ case OpARMSRL:
+ return rewriteValueARM_OpARMSRL(v, config)
+ case OpARMSRLconst:
+ return rewriteValueARM_OpARMSRLconst(v, config)
+ case OpARMSUB:
+ return rewriteValueARM_OpARMSUB(v, config)
+ case OpARMSUBS:
+ return rewriteValueARM_OpARMSUBS(v, config)
+ case OpARMSUBSshiftLL:
+ return rewriteValueARM_OpARMSUBSshiftLL(v, config)
+ case OpARMSUBSshiftLLreg:
+ return rewriteValueARM_OpARMSUBSshiftLLreg(v, config)
+ case OpARMSUBSshiftRA:
+ return rewriteValueARM_OpARMSUBSshiftRA(v, config)
+ case OpARMSUBSshiftRAreg:
+ return rewriteValueARM_OpARMSUBSshiftRAreg(v, config)
+ case OpARMSUBSshiftRL:
+ return rewriteValueARM_OpARMSUBSshiftRL(v, config)
+ case OpARMSUBSshiftRLreg:
+ return rewriteValueARM_OpARMSUBSshiftRLreg(v, config)
+ case OpARMSUBconst:
+ return rewriteValueARM_OpARMSUBconst(v, config)
+ case OpARMSUBshiftLL:
+ return rewriteValueARM_OpARMSUBshiftLL(v, config)
+ case OpARMSUBshiftLLreg:
+ return rewriteValueARM_OpARMSUBshiftLLreg(v, config)
+ case OpARMSUBshiftRA:
+ return rewriteValueARM_OpARMSUBshiftRA(v, config)
+ case OpARMSUBshiftRAreg:
+ return rewriteValueARM_OpARMSUBshiftRAreg(v, config)
+ case OpARMSUBshiftRL:
+ return rewriteValueARM_OpARMSUBshiftRL(v, config)
+ case OpARMSUBshiftRLreg:
+ return rewriteValueARM_OpARMSUBshiftRLreg(v, config)
+ case OpARMXOR:
+ return rewriteValueARM_OpARMXOR(v, config)
+ case OpARMXORconst:
+ return rewriteValueARM_OpARMXORconst(v, config)
+ case OpARMXORshiftLL:
+ return rewriteValueARM_OpARMXORshiftLL(v, config)
+ case OpARMXORshiftLLreg:
+ return rewriteValueARM_OpARMXORshiftLLreg(v, config)
+ case OpARMXORshiftRA:
+ return rewriteValueARM_OpARMXORshiftRA(v, config)
+ case OpARMXORshiftRAreg:
+ return rewriteValueARM_OpARMXORshiftRAreg(v, config)
+ case OpARMXORshiftRL:
+ return rewriteValueARM_OpARMXORshiftRL(v, config)
+ case OpARMXORshiftRLreg:
+ return rewriteValueARM_OpARMXORshiftRLreg(v, config)
+ case OpARMXORshiftRR:
+ return rewriteValueARM_OpARMXORshiftRR(v, config)
+ case OpAdd16:
+ return rewriteValueARM_OpAdd16(v, config)
case OpAdd32:
return rewriteValueARM_OpAdd32(v, config)
+ case OpAdd32F:
+ return rewriteValueARM_OpAdd32F(v, config)
+ case OpAdd32carry:
+ return rewriteValueARM_OpAdd32carry(v, config)
+ case OpAdd32withcarry:
+ return rewriteValueARM_OpAdd32withcarry(v, config)
+ case OpAdd64F:
+ return rewriteValueARM_OpAdd64F(v, config)
+ case OpAdd8:
+ return rewriteValueARM_OpAdd8(v, config)
+ case OpAddPtr:
+ return rewriteValueARM_OpAddPtr(v, config)
case OpAddr:
return rewriteValueARM_OpAddr(v, config)
+ case OpAnd16:
+ return rewriteValueARM_OpAnd16(v, config)
+ case OpAnd32:
+ return rewriteValueARM_OpAnd32(v, config)
+ case OpAnd8:
+ return rewriteValueARM_OpAnd8(v, config)
+ case OpAndB:
+ return rewriteValueARM_OpAndB(v, config)
+ case OpBswap32:
+ return rewriteValueARM_OpBswap32(v, config)
+ case OpClosureCall:
+ return rewriteValueARM_OpClosureCall(v, config)
+ case OpCom16:
+ return rewriteValueARM_OpCom16(v, config)
+ case OpCom32:
+ return rewriteValueARM_OpCom32(v, config)
+ case OpCom8:
+ return rewriteValueARM_OpCom8(v, config)
+ case OpConst16:
+ return rewriteValueARM_OpConst16(v, config)
case OpConst32:
return rewriteValueARM_OpConst32(v, config)
+ case OpConst32F:
+ return rewriteValueARM_OpConst32F(v, config)
+ case OpConst64F:
+ return rewriteValueARM_OpConst64F(v, config)
+ case OpConst8:
+ return rewriteValueARM_OpConst8(v, config)
+ case OpConstBool:
+ return rewriteValueARM_OpConstBool(v, config)
+ case OpConstNil:
+ return rewriteValueARM_OpConstNil(v, config)
+ case OpConvert:
+ return rewriteValueARM_OpConvert(v, config)
+ case OpCtz32:
+ return rewriteValueARM_OpCtz32(v, config)
+ case OpCvt32Fto32:
+ return rewriteValueARM_OpCvt32Fto32(v, config)
+ case OpCvt32Fto32U:
+ return rewriteValueARM_OpCvt32Fto32U(v, config)
+ case OpCvt32Fto64F:
+ return rewriteValueARM_OpCvt32Fto64F(v, config)
+ case OpCvt32Uto32F:
+ return rewriteValueARM_OpCvt32Uto32F(v, config)
+ case OpCvt32Uto64F:
+ return rewriteValueARM_OpCvt32Uto64F(v, config)
+ case OpCvt32to32F:
+ return rewriteValueARM_OpCvt32to32F(v, config)
+ case OpCvt32to64F:
+ return rewriteValueARM_OpCvt32to64F(v, config)
+ case OpCvt64Fto32:
+ return rewriteValueARM_OpCvt64Fto32(v, config)
+ case OpCvt64Fto32F:
+ return rewriteValueARM_OpCvt64Fto32F(v, config)
+ case OpCvt64Fto32U:
+ return rewriteValueARM_OpCvt64Fto32U(v, config)
+ case OpDeferCall:
+ return rewriteValueARM_OpDeferCall(v, config)
+ case OpDiv16:
+ return rewriteValueARM_OpDiv16(v, config)
+ case OpDiv16u:
+ return rewriteValueARM_OpDiv16u(v, config)
+ case OpDiv32:
+ return rewriteValueARM_OpDiv32(v, config)
+ case OpDiv32F:
+ return rewriteValueARM_OpDiv32F(v, config)
+ case OpDiv32u:
+ return rewriteValueARM_OpDiv32u(v, config)
+ case OpDiv64F:
+ return rewriteValueARM_OpDiv64F(v, config)
+ case OpDiv8:
+ return rewriteValueARM_OpDiv8(v, config)
+ case OpDiv8u:
+ return rewriteValueARM_OpDiv8u(v, config)
+ case OpEq16:
+ return rewriteValueARM_OpEq16(v, config)
+ case OpEq32:
+ return rewriteValueARM_OpEq32(v, config)
+ case OpEq32F:
+ return rewriteValueARM_OpEq32F(v, config)
+ case OpEq64F:
+ return rewriteValueARM_OpEq64F(v, config)
+ case OpEq8:
+ return rewriteValueARM_OpEq8(v, config)
+ case OpEqB:
+ return rewriteValueARM_OpEqB(v, config)
+ case OpEqPtr:
+ return rewriteValueARM_OpEqPtr(v, config)
+ case OpGeq16:
+ return rewriteValueARM_OpGeq16(v, config)
+ case OpGeq16U:
+ return rewriteValueARM_OpGeq16U(v, config)
+ case OpGeq32:
+ return rewriteValueARM_OpGeq32(v, config)
+ case OpGeq32F:
+ return rewriteValueARM_OpGeq32F(v, config)
+ case OpGeq32U:
+ return rewriteValueARM_OpGeq32U(v, config)
+ case OpGeq64F:
+ return rewriteValueARM_OpGeq64F(v, config)
+ case OpGeq8:
+ return rewriteValueARM_OpGeq8(v, config)
+ case OpGeq8U:
+ return rewriteValueARM_OpGeq8U(v, config)
+ case OpGetClosurePtr:
+ return rewriteValueARM_OpGetClosurePtr(v, config)
+ case OpGoCall:
+ return rewriteValueARM_OpGoCall(v, config)
+ case OpGreater16:
+ return rewriteValueARM_OpGreater16(v, config)
+ case OpGreater16U:
+ return rewriteValueARM_OpGreater16U(v, config)
+ case OpGreater32:
+ return rewriteValueARM_OpGreater32(v, config)
+ case OpGreater32F:
+ return rewriteValueARM_OpGreater32F(v, config)
+ case OpGreater32U:
+ return rewriteValueARM_OpGreater32U(v, config)
+ case OpGreater64F:
+ return rewriteValueARM_OpGreater64F(v, config)
+ case OpGreater8:
+ return rewriteValueARM_OpGreater8(v, config)
+ case OpGreater8U:
+ return rewriteValueARM_OpGreater8U(v, config)
+ case OpHmul16:
+ return rewriteValueARM_OpHmul16(v, config)
+ case OpHmul16u:
+ return rewriteValueARM_OpHmul16u(v, config)
+ case OpHmul32:
+ return rewriteValueARM_OpHmul32(v, config)
+ case OpHmul32u:
+ return rewriteValueARM_OpHmul32u(v, config)
+ case OpHmul8:
+ return rewriteValueARM_OpHmul8(v, config)
+ case OpHmul8u:
+ return rewriteValueARM_OpHmul8u(v, config)
+ case OpInterCall:
+ return rewriteValueARM_OpInterCall(v, config)
+ case OpIsInBounds:
+ return rewriteValueARM_OpIsInBounds(v, config)
+ case OpIsNonNil:
+ return rewriteValueARM_OpIsNonNil(v, config)
+ case OpIsSliceInBounds:
+ return rewriteValueARM_OpIsSliceInBounds(v, config)
+ case OpLeq16:
+ return rewriteValueARM_OpLeq16(v, config)
+ case OpLeq16U:
+ return rewriteValueARM_OpLeq16U(v, config)
+ case OpLeq32:
+ return rewriteValueARM_OpLeq32(v, config)
+ case OpLeq32F:
+ return rewriteValueARM_OpLeq32F(v, config)
+ case OpLeq32U:
+ return rewriteValueARM_OpLeq32U(v, config)
+ case OpLeq64F:
+ return rewriteValueARM_OpLeq64F(v, config)
+ case OpLeq8:
+ return rewriteValueARM_OpLeq8(v, config)
+ case OpLeq8U:
+ return rewriteValueARM_OpLeq8U(v, config)
+ case OpLess16:
+ return rewriteValueARM_OpLess16(v, config)
+ case OpLess16U:
+ return rewriteValueARM_OpLess16U(v, config)
case OpLess32:
return rewriteValueARM_OpLess32(v, config)
+ case OpLess32F:
+ return rewriteValueARM_OpLess32F(v, config)
+ case OpLess32U:
+ return rewriteValueARM_OpLess32U(v, config)
+ case OpLess64F:
+ return rewriteValueARM_OpLess64F(v, config)
+ case OpLess8:
+ return rewriteValueARM_OpLess8(v, config)
+ case OpLess8U:
+ return rewriteValueARM_OpLess8U(v, config)
case OpLoad:
return rewriteValueARM_OpLoad(v, config)
- case OpARMMOVWload:
- return rewriteValueARM_OpARMMOVWload(v, config)
- case OpARMMOVWstore:
- return rewriteValueARM_OpARMMOVWstore(v, config)
+ case OpLrot16:
+ return rewriteValueARM_OpLrot16(v, config)
+ case OpLrot32:
+ return rewriteValueARM_OpLrot32(v, config)
+ case OpLrot8:
+ return rewriteValueARM_OpLrot8(v, config)
+ case OpLsh16x16:
+ return rewriteValueARM_OpLsh16x16(v, config)
+ case OpLsh16x32:
+ return rewriteValueARM_OpLsh16x32(v, config)
+ case OpLsh16x64:
+ return rewriteValueARM_OpLsh16x64(v, config)
+ case OpLsh16x8:
+ return rewriteValueARM_OpLsh16x8(v, config)
+ case OpLsh32x16:
+ return rewriteValueARM_OpLsh32x16(v, config)
+ case OpLsh32x32:
+ return rewriteValueARM_OpLsh32x32(v, config)
+ case OpLsh32x64:
+ return rewriteValueARM_OpLsh32x64(v, config)
+ case OpLsh32x8:
+ return rewriteValueARM_OpLsh32x8(v, config)
+ case OpLsh8x16:
+ return rewriteValueARM_OpLsh8x16(v, config)
+ case OpLsh8x32:
+ return rewriteValueARM_OpLsh8x32(v, config)
+ case OpLsh8x64:
+ return rewriteValueARM_OpLsh8x64(v, config)
+ case OpLsh8x8:
+ return rewriteValueARM_OpLsh8x8(v, config)
+ case OpMod16:
+ return rewriteValueARM_OpMod16(v, config)
+ case OpMod16u:
+ return rewriteValueARM_OpMod16u(v, config)
+ case OpMod32:
+ return rewriteValueARM_OpMod32(v, config)
+ case OpMod32u:
+ return rewriteValueARM_OpMod32u(v, config)
+ case OpMod8:
+ return rewriteValueARM_OpMod8(v, config)
+ case OpMod8u:
+ return rewriteValueARM_OpMod8u(v, config)
+ case OpMove:
+ return rewriteValueARM_OpMove(v, config)
+ case OpMul16:
+ return rewriteValueARM_OpMul16(v, config)
+ case OpMul32:
+ return rewriteValueARM_OpMul32(v, config)
+ case OpMul32F:
+ return rewriteValueARM_OpMul32F(v, config)
+ case OpMul32uhilo:
+ return rewriteValueARM_OpMul32uhilo(v, config)
+ case OpMul64F:
+ return rewriteValueARM_OpMul64F(v, config)
+ case OpMul8:
+ return rewriteValueARM_OpMul8(v, config)
+ case OpNeg16:
+ return rewriteValueARM_OpNeg16(v, config)
+ case OpNeg32:
+ return rewriteValueARM_OpNeg32(v, config)
+ case OpNeg32F:
+ return rewriteValueARM_OpNeg32F(v, config)
+ case OpNeg64F:
+ return rewriteValueARM_OpNeg64F(v, config)
+ case OpNeg8:
+ return rewriteValueARM_OpNeg8(v, config)
+ case OpNeq16:
+ return rewriteValueARM_OpNeq16(v, config)
+ case OpNeq32:
+ return rewriteValueARM_OpNeq32(v, config)
+ case OpNeq32F:
+ return rewriteValueARM_OpNeq32F(v, config)
+ case OpNeq64F:
+ return rewriteValueARM_OpNeq64F(v, config)
+ case OpNeq8:
+ return rewriteValueARM_OpNeq8(v, config)
+ case OpNeqB:
+ return rewriteValueARM_OpNeqB(v, config)
+ case OpNeqPtr:
+ return rewriteValueARM_OpNeqPtr(v, config)
+ case OpNilCheck:
+ return rewriteValueARM_OpNilCheck(v, config)
+ case OpNot:
+ return rewriteValueARM_OpNot(v, config)
case OpOffPtr:
return rewriteValueARM_OpOffPtr(v, config)
+ case OpOr16:
+ return rewriteValueARM_OpOr16(v, config)
+ case OpOr32:
+ return rewriteValueARM_OpOr32(v, config)
+ case OpOr8:
+ return rewriteValueARM_OpOr8(v, config)
+ case OpOrB:
+ return rewriteValueARM_OpOrB(v, config)
+ case OpRsh16Ux16:
+ return rewriteValueARM_OpRsh16Ux16(v, config)
+ case OpRsh16Ux32:
+ return rewriteValueARM_OpRsh16Ux32(v, config)
+ case OpRsh16Ux64:
+ return rewriteValueARM_OpRsh16Ux64(v, config)
+ case OpRsh16Ux8:
+ return rewriteValueARM_OpRsh16Ux8(v, config)
+ case OpRsh16x16:
+ return rewriteValueARM_OpRsh16x16(v, config)
+ case OpRsh16x32:
+ return rewriteValueARM_OpRsh16x32(v, config)
+ case OpRsh16x64:
+ return rewriteValueARM_OpRsh16x64(v, config)
+ case OpRsh16x8:
+ return rewriteValueARM_OpRsh16x8(v, config)
+ case OpRsh32Ux16:
+ return rewriteValueARM_OpRsh32Ux16(v, config)
+ case OpRsh32Ux32:
+ return rewriteValueARM_OpRsh32Ux32(v, config)
+ case OpRsh32Ux64:
+ return rewriteValueARM_OpRsh32Ux64(v, config)
+ case OpRsh32Ux8:
+ return rewriteValueARM_OpRsh32Ux8(v, config)
+ case OpRsh32x16:
+ return rewriteValueARM_OpRsh32x16(v, config)
+ case OpRsh32x32:
+ return rewriteValueARM_OpRsh32x32(v, config)
+ case OpRsh32x64:
+ return rewriteValueARM_OpRsh32x64(v, config)
+ case OpRsh32x8:
+ return rewriteValueARM_OpRsh32x8(v, config)
+ case OpRsh8Ux16:
+ return rewriteValueARM_OpRsh8Ux16(v, config)
+ case OpRsh8Ux32:
+ return rewriteValueARM_OpRsh8Ux32(v, config)
+ case OpRsh8Ux64:
+ return rewriteValueARM_OpRsh8Ux64(v, config)
+ case OpRsh8Ux8:
+ return rewriteValueARM_OpRsh8Ux8(v, config)
+ case OpRsh8x16:
+ return rewriteValueARM_OpRsh8x16(v, config)
+ case OpRsh8x32:
+ return rewriteValueARM_OpRsh8x32(v, config)
+ case OpRsh8x64:
+ return rewriteValueARM_OpRsh8x64(v, config)
+ case OpRsh8x8:
+ return rewriteValueARM_OpRsh8x8(v, config)
+ case OpSelect0:
+ return rewriteValueARM_OpSelect0(v, config)
+ case OpSelect1:
+ return rewriteValueARM_OpSelect1(v, config)
+ case OpSignExt16to32:
+ return rewriteValueARM_OpSignExt16to32(v, config)
+ case OpSignExt8to16:
+ return rewriteValueARM_OpSignExt8to16(v, config)
+ case OpSignExt8to32:
+ return rewriteValueARM_OpSignExt8to32(v, config)
+ case OpSignmask:
+ return rewriteValueARM_OpSignmask(v, config)
+ case OpSlicemask:
+ return rewriteValueARM_OpSlicemask(v, config)
+ case OpSqrt:
+ return rewriteValueARM_OpSqrt(v, config)
case OpStaticCall:
return rewriteValueARM_OpStaticCall(v, config)
case OpStore:
return rewriteValueARM_OpStore(v, config)
+ case OpSub16:
+ return rewriteValueARM_OpSub16(v, config)
+ case OpSub32:
+ return rewriteValueARM_OpSub32(v, config)
+ case OpSub32F:
+ return rewriteValueARM_OpSub32F(v, config)
+ case OpSub32carry:
+ return rewriteValueARM_OpSub32carry(v, config)
+ case OpSub32withcarry:
+ return rewriteValueARM_OpSub32withcarry(v, config)
+ case OpSub64F:
+ return rewriteValueARM_OpSub64F(v, config)
+ case OpSub8:
+ return rewriteValueARM_OpSub8(v, config)
+ case OpSubPtr:
+ return rewriteValueARM_OpSubPtr(v, config)
+ case OpTrunc16to8:
+ return rewriteValueARM_OpTrunc16to8(v, config)
+ case OpTrunc32to16:
+ return rewriteValueARM_OpTrunc32to16(v, config)
+ case OpTrunc32to8:
+ return rewriteValueARM_OpTrunc32to8(v, config)
+ case OpXor16:
+ return rewriteValueARM_OpXor16(v, config)
+ case OpXor32:
+ return rewriteValueARM_OpXor32(v, config)
+ case OpXor8:
+ return rewriteValueARM_OpXor8(v, config)
+ case OpZero:
+ return rewriteValueARM_OpZero(v, config)
+ case OpZeroExt16to32:
+ return rewriteValueARM_OpZeroExt16to32(v, config)
+ case OpZeroExt8to16:
+ return rewriteValueARM_OpZeroExt8to16(v, config)
+ case OpZeroExt8to32:
+ return rewriteValueARM_OpZeroExt8to32(v, config)
+ case OpZeromask:
+ return rewriteValueARM_OpZeromask(v, config)
}
return false
}
-func rewriteValueARM_OpARMADD(v *Value, config *Config) bool {
+func rewriteValueARM_OpARMADC(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (ADD (MOVWconst [c]) x)
+ // match: (ADC (MOVWconst [c]) x flags)
// cond:
- // result: (ADDconst [c] x)
+ // result: (ADCconst [c] x flags)
for {
v_0 := v.Args[0]
if v_0.Op != OpARMMOVWconst {
@@ -46,14 +746,16 @@ func rewriteValueARM_OpARMADD(v *Value, config *Config) bool {
}
c := v_0.AuxInt
x := v.Args[1]
- v.reset(OpARMADDconst)
+ flags := v.Args[2]
+ v.reset(OpARMADCconst)
v.AuxInt = c
v.AddArg(x)
+ v.AddArg(flags)
return true
}
- // match: (ADD x (MOVWconst [c]))
+ // match: (ADC x (MOVWconst [c]) flags)
// cond:
- // result: (ADDconst [c] x)
+ // result: (ADCconst [c] x flags)
for {
x := v.Args[0]
v_1 := v.Args[1]
@@ -61,224 +763,17857 @@ func rewriteValueARM_OpARMADD(v *Value, config *Config) bool {
break
}
c := v_1.AuxInt
- v.reset(OpARMADDconst)
+ flags := v.Args[2]
+ v.reset(OpARMADCconst)
v.AuxInt = c
v.AddArg(x)
+ v.AddArg(flags)
return true
}
- return false
-}
-func rewriteValueARM_OpAdd32(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Add32 x y)
+ // match: (ADC x (SLLconst [c] y) flags)
// cond:
- // result: (ADD x y)
+ // result: (ADCshiftLL x y [c] flags)
for {
x := v.Args[0]
- y := v.Args[1]
- v.reset(OpARMADD)
+ 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
}
-}
-func rewriteValueARM_OpAddr(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Addr {sym} base)
+ // match: (ADC (SLLconst [c] y) x flags)
// cond:
- // result: (ADDconst {sym} base)
+ // result: (ADCshiftLL x y [c] flags)
for {
- sym := v.Aux
- base := v.Args[0]
- v.reset(OpARMADDconst)
- v.Aux = sym
- v.AddArg(base)
+ 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
}
-}
-func rewriteValueARM_OpConst32(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Const32 [val])
+ // match: (ADC x (SRLconst [c] y) flags)
// cond:
- // result: (MOVWconst [val])
+ // result: (ADCshiftRL x y [c] flags)
for {
- val := v.AuxInt
- v.reset(OpARMMOVWconst)
- v.AuxInt = val
+ 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
}
-}
-func rewriteValueARM_OpLess32(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Less32 x y)
+ // match: (ADC (SRLconst [c] y) x flags)
// cond:
- // result: (LessThan (CMP x y))
+ // result: (ADCshiftRL x y [c] flags)
+ for {
+ 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
+ }
+ // match: (ADC x (SRAconst [c] y) flags)
+ // cond:
+ // result: (ADCshiftRA x y [c] flags)
for {
x := v.Args[0]
- y := v.Args[1]
- v.reset(OpARMLessThan)
- v0 := b.NewValue0(v.Line, OpARMCMP, TypeFlags)
- v0.AddArg(x)
- v0.AddArg(y)
- v.AddArg(v0)
+ 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
}
-}
-func rewriteValueARM_OpLoad(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Load <t> ptr mem)
- // cond: is32BitInt(t)
- // result: (MOVWload ptr mem)
+ // match: (ADC (SRAconst [c] y) x flags)
+ // cond:
+ // result: (ADCshiftRA x y [c] flags)
for {
- t := v.Type
- ptr := v.Args[0]
- mem := v.Args[1]
- if !(is32BitInt(t)) {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMSRAconst {
break
}
- v.reset(OpARMMOVWload)
- v.AddArg(ptr)
- v.AddArg(mem)
+ 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
}
- return false
-}
-func rewriteValueARM_OpARMMOVWload(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (MOVWload [off1] {sym1} (ADDconst [off2] {sym2} ptr) mem)
- // cond: canMergeSym(sym1,sym2)
- // result: (MOVWload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
+ // match: (ADC x (SLL y z) flags)
+ // cond:
+ // result: (ADCshiftLLreg x y z flags)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMSLL {
+ break
+ }
+ 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
+ }
+ // match: (ADC (SLL y z) x flags)
+ // cond:
+ // result: (ADCshiftLLreg x y z flags)
for {
- off1 := v.AuxInt
- sym1 := v.Aux
v_0 := v.Args[0]
- if v_0.Op != OpARMADDconst {
+ if v_0.Op != OpARMSLL {
break
}
- off2 := v_0.AuxInt
- sym2 := v_0.Aux
- ptr := v_0.Args[0]
- mem := v.Args[1]
- if !(canMergeSym(sym1, sym2)) {
+ 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 x (SRL y z) flags)
+ // cond:
+ // result: (ADCshiftRLreg x y z flags)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMSRL {
break
}
- v.reset(OpARMMOVWload)
- v.AuxInt = off1 + off2
- v.Aux = mergeSym(sym1, sym2)
- v.AddArg(ptr)
- v.AddArg(mem)
+ 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 (SRL y z) x flags)
+ // cond:
+ // result: (ADCshiftRLreg x y z flags)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMSRL {
+ break
+ }
+ 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 x (SRA y z) flags)
+ // cond:
+ // result: (ADCshiftRAreg x y z flags)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMSRA {
+ break
+ }
+ 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
+ }
+ // match: (ADC (SRA y z) x flags)
+ // cond:
+ // result: (ADCshiftRAreg x y z flags)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMSRA {
+ break
+ }
+ 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
}
return false
}
-func rewriteValueARM_OpARMMOVWstore(v *Value, config *Config) bool {
+func rewriteValueARM_OpARMADCconst(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (MOVWstore [off1] {sym1} (ADDconst [off2] {sym2} ptr) val mem)
- // cond: canMergeSym(sym1,sym2)
- // result: (MOVWstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
+ // match: (ADCconst [c] (ADDconst [d] x) flags)
+ // cond:
+ // result: (ADCconst [int64(int32(c+d))] x flags)
for {
- off1 := v.AuxInt
- sym1 := v.Aux
+ c := v.AuxInt
v_0 := v.Args[0]
if v_0.Op != OpARMADDconst {
break
}
- off2 := v_0.AuxInt
- sym2 := v_0.Aux
- ptr := v_0.Args[0]
- val := v.Args[1]
- mem := v.Args[2]
- if !(canMergeSym(sym1, sym2)) {
+ 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_0 := v.Args[0]
+ if v_0.Op != OpARMSUBconst {
break
}
- v.reset(OpARMMOVWstore)
- v.AuxInt = off1 + off2
- v.Aux = mergeSym(sym1, sym2)
- v.AddArg(ptr)
- v.AddArg(val)
- v.AddArg(mem)
+ 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
}
return false
}
-func rewriteValueARM_OpOffPtr(v *Value, config *Config) bool {
+func rewriteValueARM_OpARMADCshiftLL(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (OffPtr [off] ptr)
+ // match: (ADCshiftLL (MOVWconst [c]) x [d] flags)
// cond:
- // result: (ADD (MOVWconst <config.Frontend().TypeInt32()> [off]) ptr)
+ // result: (ADCconst [c] (SLLconst <x.Type> x [d]) flags)
for {
- off := v.AuxInt
- ptr := v.Args[0]
- v.reset(OpARMADD)
- v0 := b.NewValue0(v.Line, OpARMMOVWconst, config.Frontend().TypeInt32())
- v0.AuxInt = off
+ d := v.AuxInt
+ 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
+ v0 := b.NewValue0(v.Line, OpARMSLLconst, x.Type)
+ v0.AuxInt = d
+ v0.AddArg(x)
v.AddArg(v0)
- v.AddArg(ptr)
+ v.AddArg(flags)
return true
}
-}
-func rewriteValueARM_OpStaticCall(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (StaticCall [argwid] {target} mem)
+ // match: (ADCshiftLL x (MOVWconst [c]) [d] flags)
// cond:
- // result: (CALLstatic [argwid] {target} mem)
+ // result: (ADCconst x [int64(uint32(c)<<uint64(d))] flags)
for {
- argwid := v.AuxInt
- target := v.Aux
- mem := v.Args[0]
- v.reset(OpARMCALLstatic)
- v.AuxInt = argwid
- v.Aux = target
- v.AddArg(mem)
+ d := v.AuxInt
+ 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 = int64(uint32(c) << uint64(d))
+ v.AddArg(x)
+ v.AddArg(flags)
return true
}
+ return false
}
-func rewriteValueARM_OpStore(v *Value, config *Config) bool {
+func rewriteValueARM_OpARMADCshiftLLreg(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (Store [4] ptr val mem)
+ // match: (ADCshiftLLreg (MOVWconst [c]) x y flags)
// cond:
- // result: (MOVWstore ptr val mem)
+ // result: (ADCconst [c] (SLL <x.Type> x y) flags)
for {
- if v.AuxInt != 4 {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWconst {
break
}
- ptr := v.Args[0]
- val := v.Args[1]
- mem := v.Args[2]
- v.reset(OpARMMOVWstore)
- v.AddArg(ptr)
- v.AddArg(val)
- v.AddArg(mem)
+ c := v_0.AuxInt
+ x := v.Args[1]
+ y := v.Args[2]
+ flags := v.Args[3]
+ v.reset(OpARMADCconst)
+ v.AuxInt = c
+ v0 := b.NewValue0(v.Line, OpARMSLL, x.Type)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ v.AddArg(flags)
+ return true
+ }
+ // match: (ADCshiftLLreg x y (MOVWconst [c]) flags)
+ // cond:
+ // result: (ADCshiftLL x y [c] flags)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v_2 := v.Args[2]
+ if v_2.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_2.AuxInt
+ flags := v.Args[3]
+ v.reset(OpARMADCshiftLL)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ v.AddArg(flags)
return true
}
return false
}
-func rewriteBlockARM(b *Block) bool {
- switch b.Kind {
- case BlockIf:
- // match: (If (LessThan cc) yes no)
+func rewriteValueARM_OpARMADCshiftRA(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ADCshiftRA (MOVWconst [c]) x [d] flags)
+ // cond:
+ // result: (ADCconst [c] (SRAconst <x.Type> x [d]) flags)
+ for {
+ d := v.AuxInt
+ 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
+ v0 := b.NewValue0(v.Line, OpARMSRAconst, x.Type)
+ v0.AuxInt = d
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v.AddArg(flags)
+ return true
+ }
+ // match: (ADCshiftRA x (MOVWconst [c]) [d] flags)
+ // cond:
+ // result: (ADCconst x [int64(int32(c)>>uint64(d))] flags)
+ for {
+ d := v.AuxInt
+ 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 = int64(int32(c) >> uint64(d))
+ v.AddArg(x)
+ v.AddArg(flags)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMADCshiftRAreg(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ADCshiftRAreg (MOVWconst [c]) x y flags)
+ // cond:
+ // result: (ADCconst [c] (SRA <x.Type> x y) flags)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ y := v.Args[2]
+ flags := v.Args[3]
+ v.reset(OpARMADCconst)
+ v.AuxInt = c
+ v0 := b.NewValue0(v.Line, OpARMSRA, x.Type)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ v.AddArg(flags)
+ return true
+ }
+ // match: (ADCshiftRAreg x y (MOVWconst [c]) flags)
+ // cond:
+ // result: (ADCshiftRA x y [c] flags)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v_2 := v.Args[2]
+ if v_2.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_2.AuxInt
+ flags := v.Args[3]
+ v.reset(OpARMADCshiftRA)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ v.AddArg(flags)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMADCshiftRL(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ADCshiftRL (MOVWconst [c]) x [d] flags)
+ // cond:
+ // result: (ADCconst [c] (SRLconst <x.Type> x [d]) flags)
+ for {
+ d := v.AuxInt
+ 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
+ v0 := b.NewValue0(v.Line, OpARMSRLconst, x.Type)
+ v0.AuxInt = d
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v.AddArg(flags)
+ return true
+ }
+ // match: (ADCshiftRL x (MOVWconst [c]) [d] flags)
+ // cond:
+ // result: (ADCconst x [int64(uint32(c)>>uint64(d))] flags)
+ for {
+ d := v.AuxInt
+ 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 = int64(uint32(c) >> uint64(d))
+ v.AddArg(x)
+ v.AddArg(flags)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMADCshiftRLreg(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ADCshiftRLreg (MOVWconst [c]) x y flags)
+ // cond:
+ // result: (ADCconst [c] (SRL <x.Type> x y) flags)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ y := v.Args[2]
+ flags := v.Args[3]
+ v.reset(OpARMADCconst)
+ v.AuxInt = c
+ v0 := b.NewValue0(v.Line, OpARMSRL, x.Type)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ v.AddArg(flags)
+ return true
+ }
+ // match: (ADCshiftRLreg x y (MOVWconst [c]) flags)
+ // cond:
+ // result: (ADCshiftRL x y [c] flags)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v_2 := v.Args[2]
+ if v_2.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_2.AuxInt
+ flags := v.Args[3]
+ v.reset(OpARMADCshiftRL)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ v.AddArg(flags)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMADD(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ADD (MOVWconst [c]) x)
+ // cond:
+ // result: (ADDconst [c] x)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ v.reset(OpARMADDconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (ADD x (MOVWconst [c]))
+ // cond:
+ // result: (ADDconst [c] x)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpARMADDconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (ADD x (SLLconst [c] y))
+ // cond:
+ // result: (ADDshiftLL x y [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMSLLconst {
+ break
+ }
+ c := v_1.AuxInt
+ y := v_1.Args[0]
+ v.reset(OpARMADDshiftLL)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (ADD (SLLconst [c] y) x)
+ // cond:
+ // result: (ADDshiftLL x y [c])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMSLLconst {
+ break
+ }
+ c := v_0.AuxInt
+ y := v_0.Args[0]
+ x := v.Args[1]
+ v.reset(OpARMADDshiftLL)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (ADD x (SRLconst [c] y))
+ // cond:
+ // result: (ADDshiftRL x y [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMSRLconst {
+ break
+ }
+ c := v_1.AuxInt
+ y := v_1.Args[0]
+ v.reset(OpARMADDshiftRL)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (ADD (SRLconst [c] y) x)
+ // cond:
+ // result: (ADDshiftRL x y [c])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMSRLconst {
+ break
+ }
+ c := v_0.AuxInt
+ y := v_0.Args[0]
+ x := v.Args[1]
+ v.reset(OpARMADDshiftRL)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (ADD x (SRAconst [c] y))
+ // cond:
+ // result: (ADDshiftRA x y [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMSRAconst {
+ break
+ }
+ c := v_1.AuxInt
+ y := v_1.Args[0]
+ v.reset(OpARMADDshiftRA)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (ADD (SRAconst [c] y) x)
+ // cond:
+ // result: (ADDshiftRA x y [c])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMSRAconst {
+ break
+ }
+ c := v_0.AuxInt
+ y := v_0.Args[0]
+ x := v.Args[1]
+ v.reset(OpARMADDshiftRA)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (ADD x (SLL y z))
+ // cond:
+ // result: (ADDshiftLLreg x y z)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMSLL {
+ break
+ }
+ y := v_1.Args[0]
+ z := v_1.Args[1]
+ v.reset(OpARMADDshiftLLreg)
+ v.AddArg(x)
+ v.AddArg(y)
+ v.AddArg(z)
+ return true
+ }
+ // match: (ADD (SLL y z) x)
+ // cond:
+ // result: (ADDshiftLLreg x y z)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMSLL {
+ break
+ }
+ y := v_0.Args[0]
+ z := v_0.Args[1]
+ x := v.Args[1]
+ v.reset(OpARMADDshiftLLreg)
+ v.AddArg(x)
+ v.AddArg(y)
+ v.AddArg(z)
+ return true
+ }
+ // match: (ADD x (SRL y z))
+ // cond:
+ // result: (ADDshiftRLreg x y z)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMSRL {
+ break
+ }
+ y := v_1.Args[0]
+ z := v_1.Args[1]
+ v.reset(OpARMADDshiftRLreg)
+ v.AddArg(x)
+ v.AddArg(y)
+ v.AddArg(z)
+ return true
+ }
+ // match: (ADD (SRL y z) x)
+ // cond:
+ // result: (ADDshiftRLreg x y z)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMSRL {
+ break
+ }
+ y := v_0.Args[0]
+ z := v_0.Args[1]
+ x := v.Args[1]
+ v.reset(OpARMADDshiftRLreg)
+ v.AddArg(x)
+ v.AddArg(y)
+ v.AddArg(z)
+ return true
+ }
+ // match: (ADD x (SRA y z))
+ // cond:
+ // result: (ADDshiftRAreg x y z)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMSRA {
+ break
+ }
+ y := v_1.Args[0]
+ z := v_1.Args[1]
+ v.reset(OpARMADDshiftRAreg)
+ v.AddArg(x)
+ v.AddArg(y)
+ v.AddArg(z)
+ return true
+ }
+ // match: (ADD (SRA y z) x)
+ // cond:
+ // result: (ADDshiftRAreg x y z)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMSRA {
+ break
+ }
+ y := v_0.Args[0]
+ z := v_0.Args[1]
+ x := v.Args[1]
+ v.reset(OpARMADDshiftRAreg)
+ v.AddArg(x)
+ v.AddArg(y)
+ v.AddArg(z)
+ return true
+ }
+ // match: (ADD x (RSBconst [0] y))
+ // cond:
+ // result: (SUB x y)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMRSBconst {
+ break
+ }
+ if v_1.AuxInt != 0 {
+ break
+ }
+ y := v_1.Args[0]
+ v.reset(OpARMSUB)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (ADD (RSBconst [0] y) x)
+ // cond:
+ // result: (SUB x y)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMRSBconst {
+ break
+ }
+ if v_0.AuxInt != 0 {
+ break
+ }
+ y := v_0.Args[0]
+ x := v.Args[1]
+ v.reset(OpARMSUB)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (ADD (MUL x y) a)
+ // cond:
+ // result: (MULA x y a)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMUL {
+ break
+ }
+ x := v_0.Args[0]
+ y := v_0.Args[1]
+ a := v.Args[1]
+ v.reset(OpARMMULA)
+ v.AddArg(x)
+ v.AddArg(y)
+ v.AddArg(a)
+ return true
+ }
+ // match: (ADD a (MUL x y))
+ // cond:
+ // result: (MULA x y a)
+ for {
+ a := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMMUL {
+ break
+ }
+ x := v_1.Args[0]
+ y := v_1.Args[1]
+ v.reset(OpARMMULA)
+ v.AddArg(x)
+ v.AddArg(y)
+ v.AddArg(a)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMADDS(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ADDS (MOVWconst [c]) x)
+ // cond:
+ // result: (ADDSconst [c] x)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ v.reset(OpARMADDSconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (ADDS x (MOVWconst [c]))
+ // cond:
+ // result: (ADDSconst [c] x)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpARMADDSconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (ADDS x (SLLconst [c] y))
+ // cond:
+ // result: (ADDSshiftLL x y [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMSLLconst {
+ break
+ }
+ c := v_1.AuxInt
+ y := v_1.Args[0]
+ v.reset(OpARMADDSshiftLL)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (ADDS (SLLconst [c] y) x)
+ // cond:
+ // result: (ADDSshiftLL x y [c])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMSLLconst {
+ break
+ }
+ c := v_0.AuxInt
+ y := v_0.Args[0]
+ x := v.Args[1]
+ v.reset(OpARMADDSshiftLL)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (ADDS x (SRLconst [c] y))
+ // cond:
+ // result: (ADDSshiftRL x y [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMSRLconst {
+ break
+ }
+ c := v_1.AuxInt
+ y := v_1.Args[0]
+ v.reset(OpARMADDSshiftRL)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (ADDS (SRLconst [c] y) x)
+ // cond:
+ // result: (ADDSshiftRL x y [c])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMSRLconst {
+ break
+ }
+ c := v_0.AuxInt
+ y := v_0.Args[0]
+ x := v.Args[1]
+ v.reset(OpARMADDSshiftRL)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (ADDS x (SRAconst [c] y))
+ // cond:
+ // result: (ADDSshiftRA x y [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMSRAconst {
+ break
+ }
+ c := v_1.AuxInt
+ y := v_1.Args[0]
+ v.reset(OpARMADDSshiftRA)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (ADDS (SRAconst [c] y) x)
+ // cond:
+ // result: (ADDSshiftRA x y [c])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMSRAconst {
+ break
+ }
+ c := v_0.AuxInt
+ y := v_0.Args[0]
+ x := v.Args[1]
+ v.reset(OpARMADDSshiftRA)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (ADDS x (SLL y z))
+ // cond:
+ // result: (ADDSshiftLLreg x y z)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMSLL {
+ break
+ }
+ y := v_1.Args[0]
+ z := v_1.Args[1]
+ v.reset(OpARMADDSshiftLLreg)
+ v.AddArg(x)
+ v.AddArg(y)
+ v.AddArg(z)
+ return true
+ }
+ // match: (ADDS (SLL y z) x)
+ // cond:
+ // result: (ADDSshiftLLreg x y z)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMSLL {
+ break
+ }
+ y := v_0.Args[0]
+ z := v_0.Args[1]
+ x := v.Args[1]
+ v.reset(OpARMADDSshiftLLreg)
+ v.AddArg(x)
+ v.AddArg(y)
+ v.AddArg(z)
+ return true
+ }
+ // match: (ADDS x (SRL y z))
+ // cond:
+ // result: (ADDSshiftRLreg x y z)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMSRL {
+ break
+ }
+ y := v_1.Args[0]
+ z := v_1.Args[1]
+ v.reset(OpARMADDSshiftRLreg)
+ v.AddArg(x)
+ v.AddArg(y)
+ v.AddArg(z)
+ return true
+ }
+ // match: (ADDS (SRL y z) x)
+ // cond:
+ // result: (ADDSshiftRLreg x y z)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMSRL {
+ break
+ }
+ y := v_0.Args[0]
+ z := v_0.Args[1]
+ x := v.Args[1]
+ v.reset(OpARMADDSshiftRLreg)
+ v.AddArg(x)
+ v.AddArg(y)
+ v.AddArg(z)
+ return true
+ }
+ // match: (ADDS x (SRA y z))
+ // cond:
+ // result: (ADDSshiftRAreg x y z)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMSRA {
+ break
+ }
+ y := v_1.Args[0]
+ z := v_1.Args[1]
+ v.reset(OpARMADDSshiftRAreg)
+ v.AddArg(x)
+ v.AddArg(y)
+ v.AddArg(z)
+ return true
+ }
+ // match: (ADDS (SRA y z) x)
+ // cond:
+ // result: (ADDSshiftRAreg x y z)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMSRA {
+ break
+ }
+ y := v_0.Args[0]
+ z := v_0.Args[1]
+ x := v.Args[1]
+ v.reset(OpARMADDSshiftRAreg)
+ v.AddArg(x)
+ v.AddArg(y)
+ v.AddArg(z)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMADDSshiftLL(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ADDSshiftLL (MOVWconst [c]) x [d])
+ // cond:
+ // result: (ADDSconst [c] (SLLconst <x.Type> x [d]))
+ for {
+ d := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ v.reset(OpARMADDSconst)
+ v.AuxInt = c
+ v0 := b.NewValue0(v.Line, OpARMSLLconst, x.Type)
+ v0.AuxInt = d
+ v0.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (ADDSshiftLL x (MOVWconst [c]) [d])
+ // cond:
+ // result: (ADDSconst x [int64(uint32(c)<<uint64(d))])
+ for {
+ d := v.AuxInt
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpARMADDSconst)
+ v.AuxInt = int64(uint32(c) << uint64(d))
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMADDSshiftLLreg(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ADDSshiftLLreg (MOVWconst [c]) x y)
+ // cond:
+ // result: (ADDSconst [c] (SLL <x.Type> x y))
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ y := v.Args[2]
+ v.reset(OpARMADDSconst)
+ v.AuxInt = c
+ v0 := b.NewValue0(v.Line, OpARMSLL, x.Type)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (ADDSshiftLLreg x y (MOVWconst [c]))
+ // cond:
+ // result: (ADDSshiftLL x y [c])
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v_2 := v.Args[2]
+ if v_2.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_2.AuxInt
+ v.reset(OpARMADDSshiftLL)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMADDSshiftRA(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ADDSshiftRA (MOVWconst [c]) x [d])
+ // cond:
+ // result: (ADDSconst [c] (SRAconst <x.Type> x [d]))
+ for {
+ d := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ v.reset(OpARMADDSconst)
+ v.AuxInt = c
+ v0 := b.NewValue0(v.Line, OpARMSRAconst, x.Type)
+ v0.AuxInt = d
+ v0.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (ADDSshiftRA x (MOVWconst [c]) [d])
+ // cond:
+ // result: (ADDSconst x [int64(int32(c)>>uint64(d))])
+ for {
+ d := v.AuxInt
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpARMADDSconst)
+ v.AuxInt = int64(int32(c) >> uint64(d))
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMADDSshiftRAreg(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ADDSshiftRAreg (MOVWconst [c]) x y)
+ // cond:
+ // result: (ADDSconst [c] (SRA <x.Type> x y))
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ y := v.Args[2]
+ v.reset(OpARMADDSconst)
+ v.AuxInt = c
+ v0 := b.NewValue0(v.Line, OpARMSRA, x.Type)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (ADDSshiftRAreg x y (MOVWconst [c]))
+ // cond:
+ // result: (ADDSshiftRA x y [c])
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v_2 := v.Args[2]
+ if v_2.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_2.AuxInt
+ v.reset(OpARMADDSshiftRA)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMADDSshiftRL(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ADDSshiftRL (MOVWconst [c]) x [d])
+ // cond:
+ // result: (ADDSconst [c] (SRLconst <x.Type> x [d]))
+ for {
+ d := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ v.reset(OpARMADDSconst)
+ v.AuxInt = c
+ v0 := b.NewValue0(v.Line, OpARMSRLconst, x.Type)
+ v0.AuxInt = d
+ v0.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (ADDSshiftRL x (MOVWconst [c]) [d])
+ // cond:
+ // result: (ADDSconst x [int64(uint32(c)>>uint64(d))])
+ for {
+ d := v.AuxInt
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpARMADDSconst)
+ v.AuxInt = int64(uint32(c) >> uint64(d))
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMADDSshiftRLreg(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ADDSshiftRLreg (MOVWconst [c]) x y)
+ // cond:
+ // result: (ADDSconst [c] (SRL <x.Type> x y))
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ y := v.Args[2]
+ v.reset(OpARMADDSconst)
+ v.AuxInt = c
+ v0 := b.NewValue0(v.Line, OpARMSRL, x.Type)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (ADDSshiftRLreg x y (MOVWconst [c]))
+ // cond:
+ // result: (ADDSshiftRL x y [c])
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v_2 := v.Args[2]
+ if v_2.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_2.AuxInt
+ v.reset(OpARMADDSshiftRL)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMADDconst(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ADDconst [off1] (MOVWaddr [off2] {sym} ptr))
+ // cond:
+ // result: (MOVWaddr [off1+off2] {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 = off1 + off2
+ v.Aux = sym
+ v.AddArg(ptr)
+ return true
+ }
+ // match: (ADDconst [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: (ADDconst [c] (MOVWconst [d]))
+ // cond:
+ // result: (MOVWconst [int64(int32(c+d))])
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWconst {
+ break
+ }
+ d := v_0.AuxInt
+ v.reset(OpARMMOVWconst)
+ v.AuxInt = int64(int32(c + d))
+ return true
+ }
+ // match: (ADDconst [c] (ADDconst [d] x))
+ // cond:
+ // result: (ADDconst [int64(int32(c+d))] x)
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMADDconst {
+ break
+ }
+ d := v_0.AuxInt
+ x := v_0.Args[0]
+ v.reset(OpARMADDconst)
+ v.AuxInt = int64(int32(c + d))
+ v.AddArg(x)
+ return true
+ }
+ // match: (ADDconst [c] (SUBconst [d] x))
+ // cond:
+ // result: (ADDconst [int64(int32(c-d))] x)
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMSUBconst {
+ break
+ }
+ d := v_0.AuxInt
+ x := v_0.Args[0]
+ v.reset(OpARMADDconst)
+ v.AuxInt = int64(int32(c - d))
+ v.AddArg(x)
+ return true
+ }
+ // match: (ADDconst [c] (RSBconst [d] x))
+ // cond:
+ // result: (RSBconst [int64(int32(c+d))] x)
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMRSBconst {
+ break
+ }
+ d := v_0.AuxInt
+ x := v_0.Args[0]
+ v.reset(OpARMRSBconst)
+ v.AuxInt = int64(int32(c + d))
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMADDshiftLL(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ADDshiftLL (MOVWconst [c]) x [d])
+ // cond:
+ // result: (ADDconst [c] (SLLconst <x.Type> x [d]))
+ for {
+ d := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ v.reset(OpARMADDconst)
+ v.AuxInt = c
+ v0 := b.NewValue0(v.Line, OpARMSLLconst, x.Type)
+ v0.AuxInt = d
+ v0.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (ADDshiftLL x (MOVWconst [c]) [d])
+ // cond:
+ // result: (ADDconst x [int64(uint32(c)<<uint64(d))])
+ for {
+ d := v.AuxInt
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpARMADDconst)
+ v.AuxInt = int64(uint32(c) << uint64(d))
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMADDshiftLLreg(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ADDshiftLLreg (MOVWconst [c]) x y)
+ // cond:
+ // result: (ADDconst [c] (SLL <x.Type> x y))
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ y := v.Args[2]
+ v.reset(OpARMADDconst)
+ v.AuxInt = c
+ v0 := b.NewValue0(v.Line, OpARMSLL, x.Type)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (ADDshiftLLreg x y (MOVWconst [c]))
+ // cond:
+ // result: (ADDshiftLL x y [c])
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v_2 := v.Args[2]
+ if v_2.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_2.AuxInt
+ v.reset(OpARMADDshiftLL)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMADDshiftRA(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ADDshiftRA (MOVWconst [c]) x [d])
+ // cond:
+ // result: (ADDconst [c] (SRAconst <x.Type> x [d]))
+ for {
+ d := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ v.reset(OpARMADDconst)
+ v.AuxInt = c
+ v0 := b.NewValue0(v.Line, OpARMSRAconst, x.Type)
+ v0.AuxInt = d
+ v0.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (ADDshiftRA x (MOVWconst [c]) [d])
+ // cond:
+ // result: (ADDconst x [int64(int32(c)>>uint64(d))])
+ for {
+ d := v.AuxInt
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpARMADDconst)
+ v.AuxInt = int64(int32(c) >> uint64(d))
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMADDshiftRAreg(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ADDshiftRAreg (MOVWconst [c]) x y)
+ // cond:
+ // result: (ADDconst [c] (SRA <x.Type> x y))
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ y := v.Args[2]
+ v.reset(OpARMADDconst)
+ v.AuxInt = c
+ v0 := b.NewValue0(v.Line, OpARMSRA, x.Type)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (ADDshiftRAreg x y (MOVWconst [c]))
+ // cond:
+ // result: (ADDshiftRA x y [c])
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v_2 := v.Args[2]
+ if v_2.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_2.AuxInt
+ v.reset(OpARMADDshiftRA)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMADDshiftRL(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ADDshiftRL (MOVWconst [c]) x [d])
+ // cond:
+ // result: (ADDconst [c] (SRLconst <x.Type> x [d]))
+ for {
+ d := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ v.reset(OpARMADDconst)
+ v.AuxInt = c
+ v0 := b.NewValue0(v.Line, OpARMSRLconst, x.Type)
+ v0.AuxInt = d
+ v0.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (ADDshiftRL x (MOVWconst [c]) [d])
+ // cond:
+ // result: (ADDconst x [int64(uint32(c)>>uint64(d))])
+ for {
+ d := v.AuxInt
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpARMADDconst)
+ v.AuxInt = int64(uint32(c) >> uint64(d))
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMADDshiftRLreg(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ADDshiftRLreg (MOVWconst [c]) x y)
+ // cond:
+ // result: (ADDconst [c] (SRL <x.Type> x y))
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ y := v.Args[2]
+ v.reset(OpARMADDconst)
+ v.AuxInt = c
+ v0 := b.NewValue0(v.Line, OpARMSRL, x.Type)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (ADDshiftRLreg x y (MOVWconst [c]))
+ // cond:
+ // result: (ADDshiftRL x y [c])
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v_2 := v.Args[2]
+ if v_2.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_2.AuxInt
+ v.reset(OpARMADDshiftRL)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMAND(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (AND (MOVWconst [c]) x)
+ // cond:
+ // result: (ANDconst [c] x)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ v.reset(OpARMANDconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (AND x (MOVWconst [c]))
+ // cond:
+ // result: (ANDconst [c] x)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpARMANDconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (AND x (SLLconst [c] y))
+ // cond:
+ // result: (ANDshiftLL x y [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMSLLconst {
+ break
+ }
+ c := v_1.AuxInt
+ y := v_1.Args[0]
+ v.reset(OpARMANDshiftLL)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (AND (SLLconst [c] y) x)
+ // cond:
+ // result: (ANDshiftLL x y [c])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMSLLconst {
+ break
+ }
+ c := v_0.AuxInt
+ y := v_0.Args[0]
+ x := v.Args[1]
+ v.reset(OpARMANDshiftLL)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (AND x (SRLconst [c] y))
+ // cond:
+ // result: (ANDshiftRL x y [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMSRLconst {
+ break
+ }
+ c := v_1.AuxInt
+ y := v_1.Args[0]
+ v.reset(OpARMANDshiftRL)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (AND (SRLconst [c] y) x)
+ // cond:
+ // result: (ANDshiftRL x y [c])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMSRLconst {
+ break
+ }
+ c := v_0.AuxInt
+ y := v_0.Args[0]
+ x := v.Args[1]
+ v.reset(OpARMANDshiftRL)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (AND x (SRAconst [c] y))
+ // cond:
+ // result: (ANDshiftRA x y [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMSRAconst {
+ break
+ }
+ c := v_1.AuxInt
+ y := v_1.Args[0]
+ v.reset(OpARMANDshiftRA)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (AND (SRAconst [c] y) x)
+ // cond:
+ // result: (ANDshiftRA x y [c])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMSRAconst {
+ break
+ }
+ c := v_0.AuxInt
+ y := v_0.Args[0]
+ x := v.Args[1]
+ v.reset(OpARMANDshiftRA)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (AND x (SLL y z))
+ // cond:
+ // result: (ANDshiftLLreg x y z)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMSLL {
+ break
+ }
+ y := v_1.Args[0]
+ z := v_1.Args[1]
+ v.reset(OpARMANDshiftLLreg)
+ v.AddArg(x)
+ v.AddArg(y)
+ v.AddArg(z)
+ return true
+ }
+ // match: (AND (SLL y z) x)
+ // cond:
+ // result: (ANDshiftLLreg x y z)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMSLL {
+ break
+ }
+ y := v_0.Args[0]
+ z := v_0.Args[1]
+ x := v.Args[1]
+ v.reset(OpARMANDshiftLLreg)
+ v.AddArg(x)
+ v.AddArg(y)
+ v.AddArg(z)
+ return true
+ }
+ // match: (AND x (SRL y z))
+ // cond:
+ // result: (ANDshiftRLreg x y z)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMSRL {
+ break
+ }
+ y := v_1.Args[0]
+ z := v_1.Args[1]
+ v.reset(OpARMANDshiftRLreg)
+ v.AddArg(x)
+ v.AddArg(y)
+ v.AddArg(z)
+ return true
+ }
+ // match: (AND (SRL y z) x)
+ // cond:
+ // result: (ANDshiftRLreg x y z)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMSRL {
+ break
+ }
+ y := v_0.Args[0]
+ z := v_0.Args[1]
+ x := v.Args[1]
+ v.reset(OpARMANDshiftRLreg)
+ v.AddArg(x)
+ v.AddArg(y)
+ v.AddArg(z)
+ return true
+ }
+ // match: (AND x (SRA y z))
+ // cond:
+ // result: (ANDshiftRAreg x y z)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMSRA {
+ break
+ }
+ y := v_1.Args[0]
+ z := v_1.Args[1]
+ v.reset(OpARMANDshiftRAreg)
+ v.AddArg(x)
+ v.AddArg(y)
+ v.AddArg(z)
+ return true
+ }
+ // match: (AND (SRA y z) x)
+ // cond:
+ // result: (ANDshiftRAreg x y z)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMSRA {
+ break
+ }
+ y := v_0.Args[0]
+ z := v_0.Args[1]
+ x := v.Args[1]
+ v.reset(OpARMANDshiftRAreg)
+ v.AddArg(x)
+ v.AddArg(y)
+ v.AddArg(z)
+ return true
+ }
+ // match: (AND 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: (AND x (MVN y))
+ // cond:
+ // result: (BIC x y)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMMVN {
+ break
+ }
+ y := v_1.Args[0]
+ v.reset(OpARMBIC)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (AND (MVN y) x)
+ // cond:
+ // result: (BIC x y)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMVN {
+ break
+ }
+ y := v_0.Args[0]
+ x := v.Args[1]
+ v.reset(OpARMBIC)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (AND x (MVNshiftLL y [c]))
+ // cond:
+ // result: (BICshiftLL x y [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMMVNshiftLL {
+ break
+ }
+ c := v_1.AuxInt
+ y := v_1.Args[0]
+ v.reset(OpARMBICshiftLL)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (AND (MVNshiftLL y [c]) x)
+ // cond:
+ // result: (BICshiftLL x y [c])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMVNshiftLL {
+ break
+ }
+ c := v_0.AuxInt
+ y := v_0.Args[0]
+ x := v.Args[1]
+ v.reset(OpARMBICshiftLL)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (AND x (MVNshiftRL y [c]))
+ // cond:
+ // result: (BICshiftRL x y [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMMVNshiftRL {
+ break
+ }
+ c := v_1.AuxInt
+ y := v_1.Args[0]
+ v.reset(OpARMBICshiftRL)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (AND (MVNshiftRL y [c]) x)
+ // cond:
+ // result: (BICshiftRL x y [c])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMVNshiftRL {
+ break
+ }
+ c := v_0.AuxInt
+ y := v_0.Args[0]
+ x := v.Args[1]
+ v.reset(OpARMBICshiftRL)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (AND x (MVNshiftRA y [c]))
+ // cond:
+ // result: (BICshiftRA x y [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMMVNshiftRA {
+ break
+ }
+ c := v_1.AuxInt
+ y := v_1.Args[0]
+ v.reset(OpARMBICshiftRA)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (AND (MVNshiftRA y [c]) x)
+ // cond:
+ // result: (BICshiftRA x y [c])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMVNshiftRA {
+ break
+ }
+ c := v_0.AuxInt
+ y := v_0.Args[0]
+ x := v.Args[1]
+ v.reset(OpARMBICshiftRA)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMANDconst(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ANDconst [0] _)
+ // cond:
+ // result: (MOVWconst [0])
+ for {
+ if v.AuxInt != 0 {
+ break
+ }
+ v.reset(OpARMMOVWconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (ANDconst [c] x)
+ // cond: int32(c)==-1
+ // result: x
+ for {
+ c := v.AuxInt
+ x := v.Args[0]
+ if !(int32(c) == -1) {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ // match: (ANDconst [c] (MOVWconst [d]))
+ // cond:
+ // result: (MOVWconst [c&d])
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWconst {
+ break
+ }
+ d := v_0.AuxInt
+ v.reset(OpARMMOVWconst)
+ v.AuxInt = c & d
+ return true
+ }
+ // match: (ANDconst [c] (ANDconst [d] x))
+ // cond:
+ // result: (ANDconst [c&d] x)
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMANDconst {
+ break
+ }
+ d := v_0.AuxInt
+ x := v_0.Args[0]
+ v.reset(OpARMANDconst)
+ v.AuxInt = c & d
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMANDshiftLL(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ANDshiftLL (MOVWconst [c]) x [d])
+ // cond:
+ // result: (ANDconst [c] (SLLconst <x.Type> x [d]))
+ for {
+ d := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ v.reset(OpARMANDconst)
+ v.AuxInt = c
+ v0 := b.NewValue0(v.Line, OpARMSLLconst, x.Type)
+ v0.AuxInt = d
+ v0.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (ANDshiftLL x (MOVWconst [c]) [d])
+ // cond:
+ // result: (ANDconst x [int64(uint32(c)<<uint64(d))])
+ for {
+ d := v.AuxInt
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpARMANDconst)
+ v.AuxInt = int64(uint32(c) << uint64(d))
+ v.AddArg(x)
+ return true
+ }
+ // match: (ANDshiftLL x y:(SLLconst x [c]) [d])
+ // cond: c==d
+ // result: y
+ for {
+ d := v.AuxInt
+ x := v.Args[0]
+ y := v.Args[1]
+ if y.Op != OpARMSLLconst {
+ break
+ }
+ c := y.AuxInt
+ if x != y.Args[0] {
+ break
+ }
+ if !(c == d) {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = y.Type
+ v.AddArg(y)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMANDshiftLLreg(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ANDshiftLLreg (MOVWconst [c]) x y)
+ // cond:
+ // result: (ANDconst [c] (SLL <x.Type> x y))
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ y := v.Args[2]
+ v.reset(OpARMANDconst)
+ v.AuxInt = c
+ v0 := b.NewValue0(v.Line, OpARMSLL, x.Type)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (ANDshiftLLreg x y (MOVWconst [c]))
+ // cond:
+ // result: (ANDshiftLL x y [c])
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v_2 := v.Args[2]
+ if v_2.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_2.AuxInt
+ v.reset(OpARMANDshiftLL)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMANDshiftRA(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ANDshiftRA (MOVWconst [c]) x [d])
+ // cond:
+ // result: (ANDconst [c] (SRAconst <x.Type> x [d]))
+ for {
+ d := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ v.reset(OpARMANDconst)
+ v.AuxInt = c
+ v0 := b.NewValue0(v.Line, OpARMSRAconst, x.Type)
+ v0.AuxInt = d
+ v0.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (ANDshiftRA x (MOVWconst [c]) [d])
+ // cond:
+ // result: (ANDconst x [int64(int32(c)>>uint64(d))])
+ for {
+ d := v.AuxInt
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpARMANDconst)
+ v.AuxInt = int64(int32(c) >> uint64(d))
+ v.AddArg(x)
+ return true
+ }
+ // match: (ANDshiftRA x y:(SRAconst x [c]) [d])
+ // cond: c==d
+ // result: y
+ for {
+ d := v.AuxInt
+ x := v.Args[0]
+ y := v.Args[1]
+ if y.Op != OpARMSRAconst {
+ break
+ }
+ c := y.AuxInt
+ if x != y.Args[0] {
+ break
+ }
+ if !(c == d) {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = y.Type
+ v.AddArg(y)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMANDshiftRAreg(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ANDshiftRAreg (MOVWconst [c]) x y)
+ // cond:
+ // result: (ANDconst [c] (SRA <x.Type> x y))
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ y := v.Args[2]
+ v.reset(OpARMANDconst)
+ v.AuxInt = c
+ v0 := b.NewValue0(v.Line, OpARMSRA, x.Type)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (ANDshiftRAreg x y (MOVWconst [c]))
+ // cond:
+ // result: (ANDshiftRA x y [c])
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v_2 := v.Args[2]
+ if v_2.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_2.AuxInt
+ v.reset(OpARMANDshiftRA)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMANDshiftRL(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ANDshiftRL (MOVWconst [c]) x [d])
+ // cond:
+ // result: (ANDconst [c] (SRLconst <x.Type> x [d]))
+ for {
+ d := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ v.reset(OpARMANDconst)
+ v.AuxInt = c
+ v0 := b.NewValue0(v.Line, OpARMSRLconst, x.Type)
+ v0.AuxInt = d
+ v0.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (ANDshiftRL x (MOVWconst [c]) [d])
+ // cond:
+ // result: (ANDconst x [int64(uint32(c)>>uint64(d))])
+ for {
+ d := v.AuxInt
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpARMANDconst)
+ v.AuxInt = int64(uint32(c) >> uint64(d))
+ v.AddArg(x)
+ return true
+ }
+ // match: (ANDshiftRL x y:(SRLconst x [c]) [d])
+ // cond: c==d
+ // result: y
+ for {
+ d := v.AuxInt
+ x := v.Args[0]
+ y := v.Args[1]
+ if y.Op != OpARMSRLconst {
+ break
+ }
+ c := y.AuxInt
+ if x != y.Args[0] {
+ break
+ }
+ if !(c == d) {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = y.Type
+ v.AddArg(y)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMANDshiftRLreg(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ANDshiftRLreg (MOVWconst [c]) x y)
+ // cond:
+ // result: (ANDconst [c] (SRL <x.Type> x y))
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ y := v.Args[2]
+ v.reset(OpARMANDconst)
+ v.AuxInt = c
+ v0 := b.NewValue0(v.Line, OpARMSRL, x.Type)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (ANDshiftRLreg x y (MOVWconst [c]))
+ // cond:
+ // result: (ANDshiftRL x y [c])
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v_2 := v.Args[2]
+ if v_2.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_2.AuxInt
+ v.reset(OpARMANDshiftRL)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMBIC(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (BIC x (MOVWconst [c]))
+ // cond:
+ // result: (BICconst [c] x)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpARMBICconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (BIC x (SLLconst [c] y))
+ // cond:
+ // result: (BICshiftLL x y [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMSLLconst {
+ break
+ }
+ c := v_1.AuxInt
+ y := v_1.Args[0]
+ v.reset(OpARMBICshiftLL)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (BIC x (SRLconst [c] y))
+ // cond:
+ // result: (BICshiftRL x y [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMSRLconst {
+ break
+ }
+ c := v_1.AuxInt
+ y := v_1.Args[0]
+ v.reset(OpARMBICshiftRL)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (BIC x (SRAconst [c] y))
+ // cond:
+ // result: (BICshiftRA x y [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMSRAconst {
+ break
+ }
+ c := v_1.AuxInt
+ y := v_1.Args[0]
+ v.reset(OpARMBICshiftRA)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (BIC x (SLL y z))
+ // cond:
+ // result: (BICshiftLLreg x y z)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMSLL {
+ break
+ }
+ y := v_1.Args[0]
+ z := v_1.Args[1]
+ v.reset(OpARMBICshiftLLreg)
+ v.AddArg(x)
+ v.AddArg(y)
+ v.AddArg(z)
+ return true
+ }
+ // match: (BIC x (SRL y z))
+ // cond:
+ // result: (BICshiftRLreg x y z)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMSRL {
+ break
+ }
+ y := v_1.Args[0]
+ z := v_1.Args[1]
+ v.reset(OpARMBICshiftRLreg)
+ v.AddArg(x)
+ v.AddArg(y)
+ v.AddArg(z)
+ return true
+ }
+ // match: (BIC x (SRA y z))
+ // cond:
+ // result: (BICshiftRAreg x y z)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMSRA {
+ break
+ }
+ y := v_1.Args[0]
+ z := v_1.Args[1]
+ v.reset(OpARMBICshiftRAreg)
+ v.AddArg(x)
+ v.AddArg(y)
+ v.AddArg(z)
+ return true
+ }
+ // match: (BIC x x)
+ // cond:
+ // result: (MOVWconst [0])
+ for {
+ x := v.Args[0]
+ if x != v.Args[1] {
+ break
+ }
+ v.reset(OpARMMOVWconst)
+ v.AuxInt = 0
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMBICconst(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (BICconst [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: (BICconst [c] _)
+ // cond: int32(c)==-1
+ // result: (MOVWconst [0])
+ for {
+ c := v.AuxInt
+ if !(int32(c) == -1) {
+ break
+ }
+ v.reset(OpARMMOVWconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (BICconst [c] (MOVWconst [d]))
+ // cond:
+ // result: (MOVWconst [d&^c])
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWconst {
+ break
+ }
+ d := v_0.AuxInt
+ v.reset(OpARMMOVWconst)
+ v.AuxInt = d &^ c
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMBICshiftLL(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (BICshiftLL x (MOVWconst [c]) [d])
+ // cond:
+ // result: (BICconst x [int64(uint32(c)<<uint64(d))])
+ for {
+ d := v.AuxInt
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpARMBICconst)
+ v.AuxInt = int64(uint32(c) << uint64(d))
+ v.AddArg(x)
+ return true
+ }
+ // match: (BICshiftLL x (SLLconst x [c]) [d])
+ // cond: c==d
+ // result: (MOVWconst [0])
+ for {
+ d := v.AuxInt
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMSLLconst {
+ break
+ }
+ c := v_1.AuxInt
+ if x != v_1.Args[0] {
+ break
+ }
+ if !(c == d) {
+ break
+ }
+ v.reset(OpARMMOVWconst)
+ v.AuxInt = 0
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMBICshiftLLreg(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (BICshiftLLreg x y (MOVWconst [c]))
+ // cond:
+ // result: (BICshiftLL x y [c])
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v_2 := v.Args[2]
+ if v_2.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_2.AuxInt
+ v.reset(OpARMBICshiftLL)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMBICshiftRA(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (BICshiftRA x (MOVWconst [c]) [d])
+ // cond:
+ // result: (BICconst x [int64(int32(c)>>uint64(d))])
+ for {
+ d := v.AuxInt
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpARMBICconst)
+ v.AuxInt = int64(int32(c) >> uint64(d))
+ v.AddArg(x)
+ return true
+ }
+ // match: (BICshiftRA x (SRAconst x [c]) [d])
+ // cond: c==d
+ // result: (MOVWconst [0])
+ for {
+ d := v.AuxInt
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMSRAconst {
+ break
+ }
+ c := v_1.AuxInt
+ if x != v_1.Args[0] {
+ break
+ }
+ if !(c == d) {
+ break
+ }
+ v.reset(OpARMMOVWconst)
+ v.AuxInt = 0
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMBICshiftRAreg(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (BICshiftRAreg x y (MOVWconst [c]))
+ // cond:
+ // result: (BICshiftRA x y [c])
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v_2 := v.Args[2]
+ if v_2.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_2.AuxInt
+ v.reset(OpARMBICshiftRA)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMBICshiftRL(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (BICshiftRL x (MOVWconst [c]) [d])
+ // cond:
+ // result: (BICconst x [int64(uint32(c)>>uint64(d))])
+ for {
+ d := v.AuxInt
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpARMBICconst)
+ v.AuxInt = int64(uint32(c) >> uint64(d))
+ v.AddArg(x)
+ return true
+ }
+ // match: (BICshiftRL x (SRLconst x [c]) [d])
+ // cond: c==d
+ // result: (MOVWconst [0])
+ for {
+ d := v.AuxInt
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMSRLconst {
+ break
+ }
+ c := v_1.AuxInt
+ if x != v_1.Args[0] {
+ break
+ }
+ if !(c == d) {
+ break
+ }
+ v.reset(OpARMMOVWconst)
+ v.AuxInt = 0
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMBICshiftRLreg(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (BICshiftRLreg x y (MOVWconst [c]))
+ // cond:
+ // result: (BICshiftRL x y [c])
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v_2 := v.Args[2]
+ if v_2.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_2.AuxInt
+ v.reset(OpARMBICshiftRL)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMCMOVWHSconst(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (CMOVWHSconst _ (FlagEQ) [c])
+ // cond:
+ // result: (MOVWconst [c])
+ for {
+ c := v.AuxInt
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMFlagEQ {
+ break
+ }
+ v.reset(OpARMMOVWconst)
+ v.AuxInt = c
+ return true
+ }
+ // match: (CMOVWHSconst x (FlagLT_ULT))
+ // cond:
+ // result: x
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMFlagLT_ULT {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ // match: (CMOVWHSconst _ (FlagLT_UGT) [c])
+ // cond:
+ // result: (MOVWconst [c])
+ for {
+ c := v.AuxInt
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMFlagLT_UGT {
+ break
+ }
+ v.reset(OpARMMOVWconst)
+ v.AuxInt = c
+ return true
+ }
+ // match: (CMOVWHSconst x (FlagGT_ULT))
+ // cond:
+ // result: x
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMFlagGT_ULT {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ // match: (CMOVWHSconst _ (FlagGT_UGT) [c])
+ // cond:
+ // result: (MOVWconst [c])
+ for {
+ c := v.AuxInt
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMFlagGT_UGT {
+ break
+ }
+ v.reset(OpARMMOVWconst)
+ v.AuxInt = c
+ return true
+ }
+ // match: (CMOVWHSconst x (InvertFlags flags) [c])
+ // cond:
+ // result: (CMOVWLSconst x flags [c])
+ for {
+ c := v.AuxInt
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMInvertFlags {
+ break
+ }
+ flags := v_1.Args[0]
+ v.reset(OpARMCMOVWLSconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(flags)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMCMOVWLSconst(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (CMOVWLSconst _ (FlagEQ) [c])
+ // cond:
+ // result: (MOVWconst [c])
+ for {
+ c := v.AuxInt
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMFlagEQ {
+ break
+ }
+ v.reset(OpARMMOVWconst)
+ v.AuxInt = c
+ return true
+ }
+ // match: (CMOVWLSconst _ (FlagLT_ULT) [c])
+ // cond:
+ // result: (MOVWconst [c])
+ for {
+ c := v.AuxInt
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMFlagLT_ULT {
+ break
+ }
+ v.reset(OpARMMOVWconst)
+ v.AuxInt = c
+ return true
+ }
+ // match: (CMOVWLSconst x (FlagLT_UGT))
+ // cond:
+ // result: x
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMFlagLT_UGT {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ // match: (CMOVWLSconst _ (FlagGT_ULT) [c])
+ // cond:
+ // result: (MOVWconst [c])
+ for {
+ c := v.AuxInt
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMFlagGT_ULT {
+ break
+ }
+ v.reset(OpARMMOVWconst)
+ v.AuxInt = c
+ return true
+ }
+ // match: (CMOVWLSconst x (FlagGT_UGT))
+ // cond:
+ // result: x
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMFlagGT_UGT {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ // match: (CMOVWLSconst x (InvertFlags flags) [c])
+ // cond:
+ // result: (CMOVWHSconst x flags [c])
+ for {
+ c := v.AuxInt
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMInvertFlags {
+ break
+ }
+ flags := v_1.Args[0]
+ v.reset(OpARMCMOVWHSconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(flags)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMCMP(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (CMP x (MOVWconst [c]))
+ // cond:
+ // result: (CMPconst [c] x)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpARMCMPconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (CMP (MOVWconst [c]) x)
+ // cond:
+ // result: (InvertFlags (CMPconst [c] x))
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ v.reset(OpARMInvertFlags)
+ v0 := b.NewValue0(v.Line, OpARMCMPconst, TypeFlags)
+ v0.AuxInt = c
+ v0.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (CMP x (SLLconst [c] y))
+ // cond:
+ // result: (CMPshiftLL x y [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMSLLconst {
+ break
+ }
+ c := v_1.AuxInt
+ y := v_1.Args[0]
+ v.reset(OpARMCMPshiftLL)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (CMP (SLLconst [c] y) x)
+ // cond:
+ // result: (InvertFlags (CMPshiftLL x y [c]))
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMSLLconst {
+ break
+ }
+ c := v_0.AuxInt
+ y := v_0.Args[0]
+ x := v.Args[1]
+ v.reset(OpARMInvertFlags)
+ v0 := b.NewValue0(v.Line, OpARMCMPshiftLL, TypeFlags)
+ v0.AuxInt = c
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (CMP x (SRLconst [c] y))
+ // cond:
+ // result: (CMPshiftRL x y [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMSRLconst {
+ break
+ }
+ c := v_1.AuxInt
+ y := v_1.Args[0]
+ v.reset(OpARMCMPshiftRL)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (CMP (SRLconst [c] y) x)
+ // cond:
+ // result: (InvertFlags (CMPshiftRL x y [c]))
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMSRLconst {
+ break
+ }
+ c := v_0.AuxInt
+ y := v_0.Args[0]
+ x := v.Args[1]
+ v.reset(OpARMInvertFlags)
+ v0 := b.NewValue0(v.Line, OpARMCMPshiftRL, TypeFlags)
+ v0.AuxInt = c
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (CMP x (SRAconst [c] y))
+ // cond:
+ // result: (CMPshiftRA x y [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMSRAconst {
+ break
+ }
+ c := v_1.AuxInt
+ y := v_1.Args[0]
+ v.reset(OpARMCMPshiftRA)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (CMP (SRAconst [c] y) x)
+ // cond:
+ // result: (InvertFlags (CMPshiftRA x y [c]))
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMSRAconst {
+ break
+ }
+ c := v_0.AuxInt
+ y := v_0.Args[0]
+ x := v.Args[1]
+ v.reset(OpARMInvertFlags)
+ v0 := b.NewValue0(v.Line, OpARMCMPshiftRA, TypeFlags)
+ v0.AuxInt = c
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (CMP x (SLL y z))
+ // cond:
+ // result: (CMPshiftLLreg x y z)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMSLL {
+ break
+ }
+ y := v_1.Args[0]
+ z := v_1.Args[1]
+ v.reset(OpARMCMPshiftLLreg)
+ v.AddArg(x)
+ v.AddArg(y)
+ v.AddArg(z)
+ return true
+ }
+ // match: (CMP (SLL y z) x)
+ // cond:
+ // result: (InvertFlags (CMPshiftLLreg x y z))
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMSLL {
+ break
+ }
+ 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.AddArg(x)
+ v0.AddArg(y)
+ v0.AddArg(z)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (CMP x (SRL y z))
+ // cond:
+ // result: (CMPshiftRLreg x y z)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMSRL {
+ break
+ }
+ y := v_1.Args[0]
+ z := v_1.Args[1]
+ v.reset(OpARMCMPshiftRLreg)
+ v.AddArg(x)
+ v.AddArg(y)
+ v.AddArg(z)
+ return true
+ }
+ // match: (CMP (SRL y z) x)
+ // cond:
+ // result: (InvertFlags (CMPshiftRLreg x y z))
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMSRL {
+ break
+ }
+ 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.AddArg(x)
+ v0.AddArg(y)
+ v0.AddArg(z)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (CMP x (SRA y z))
+ // cond:
+ // result: (CMPshiftRAreg x y z)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMSRA {
+ break
+ }
+ y := v_1.Args[0]
+ z := v_1.Args[1]
+ v.reset(OpARMCMPshiftRAreg)
+ v.AddArg(x)
+ v.AddArg(y)
+ v.AddArg(z)
+ return true
+ }
+ // match: (CMP (SRA y z) x)
+ // cond:
+ // result: (InvertFlags (CMPshiftRAreg x y z))
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMSRA {
+ break
+ }
+ 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.AddArg(x)
+ v0.AddArg(y)
+ v0.AddArg(z)
+ v.AddArg(v0)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMCMPD(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (CMPD x (MOVDconst [0]))
+ // cond:
+ // result: (CMPD0 x)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMMOVDconst {
+ break
+ }
+ if v_1.AuxInt != 0 {
+ break
+ }
+ v.reset(OpARMCMPD0)
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMCMPF(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (CMPF x (MOVFconst [0]))
+ // cond:
+ // result: (CMPF0 x)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMMOVFconst {
+ break
+ }
+ if v_1.AuxInt != 0 {
+ break
+ }
+ v.reset(OpARMCMPF0)
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMCMPconst(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (CMPconst (MOVWconst [x]) [y])
+ // cond: int32(x)==int32(y)
+ // result: (FlagEQ)
+ for {
+ y := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWconst {
+ break
+ }
+ x := v_0.AuxInt
+ if !(int32(x) == int32(y)) {
+ break
+ }
+ v.reset(OpARMFlagEQ)
+ return true
+ }
+ // match: (CMPconst (MOVWconst [x]) [y])
+ // cond: int32(x)<int32(y) && uint32(x)<uint32(y)
+ // result: (FlagLT_ULT)
+ for {
+ y := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWconst {
+ break
+ }
+ x := v_0.AuxInt
+ if !(int32(x) < int32(y) && uint32(x) < uint32(y)) {
+ break
+ }
+ v.reset(OpARMFlagLT_ULT)
+ return true
+ }
+ // match: (CMPconst (MOVWconst [x]) [y])
+ // cond: int32(x)<int32(y) && uint32(x)>uint32(y)
+ // result: (FlagLT_UGT)
+ for {
+ y := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWconst {
+ break
+ }
+ x := v_0.AuxInt
+ if !(int32(x) < int32(y) && uint32(x) > uint32(y)) {
+ break
+ }
+ v.reset(OpARMFlagLT_UGT)
+ return true
+ }
+ // match: (CMPconst (MOVWconst [x]) [y])
+ // cond: int32(x)>int32(y) && uint32(x)<uint32(y)
+ // result: (FlagGT_ULT)
+ for {
+ y := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWconst {
+ break
+ }
+ x := v_0.AuxInt
+ if !(int32(x) > int32(y) && uint32(x) < uint32(y)) {
+ break
+ }
+ v.reset(OpARMFlagGT_ULT)
+ return true
+ }
+ // match: (CMPconst (MOVWconst [x]) [y])
+ // cond: int32(x)>int32(y) && uint32(x)>uint32(y)
+ // result: (FlagGT_UGT)
+ for {
+ y := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWconst {
+ break
+ }
+ x := v_0.AuxInt
+ if !(int32(x) > int32(y) && uint32(x) > uint32(y)) {
+ break
+ }
+ v.reset(OpARMFlagGT_UGT)
+ return true
+ }
+ // match: (CMPconst (MOVBUreg _) [c])
+ // cond: 0xff < c
+ // result: (FlagLT_ULT)
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMOVBUreg {
+ break
+ }
+ if !(0xff < c) {
+ break
+ }
+ v.reset(OpARMFlagLT_ULT)
+ return true
+ }
+ // match: (CMPconst (MOVHUreg _) [c])
+ // cond: 0xffff < c
+ // result: (FlagLT_ULT)
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMOVHUreg {
+ break
+ }
+ if !(0xffff < c) {
+ break
+ }
+ v.reset(OpARMFlagLT_ULT)
+ return true
+ }
+ // match: (CMPconst (ANDconst _ [m]) [n])
+ // cond: 0 <= int32(m) && int32(m) < int32(n)
+ // result: (FlagLT_ULT)
+ for {
+ n := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMANDconst {
+ break
+ }
+ m := v_0.AuxInt
+ if !(0 <= int32(m) && int32(m) < int32(n)) {
+ break
+ }
+ v.reset(OpARMFlagLT_ULT)
+ return true
+ }
+ // match: (CMPconst (SRLconst _ [c]) [n])
+ // cond: 0 <= n && 0 < c && c <= 32 && (1<<uint32(32-c)) <= uint32(n)
+ // result: (FlagLT_ULT)
+ for {
+ n := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMSRLconst {
+ break
+ }
+ c := v_0.AuxInt
+ if !(0 <= n && 0 < c && c <= 32 && (1<<uint32(32-c)) <= uint32(n)) {
+ break
+ }
+ v.reset(OpARMFlagLT_ULT)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMCMPshiftLL(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (CMPshiftLL (MOVWconst [c]) x [d])
+ // cond:
+ // result: (InvertFlags (CMPconst [c] (SLLconst <x.Type> x [d])))
+ for {
+ d := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ v.reset(OpARMInvertFlags)
+ v0 := b.NewValue0(v.Line, OpARMCMPconst, TypeFlags)
+ v0.AuxInt = c
+ v1 := b.NewValue0(v.Line, OpARMSLLconst, x.Type)
+ v1.AuxInt = d
+ v1.AddArg(x)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (CMPshiftLL x (MOVWconst [c]) [d])
+ // cond:
+ // result: (CMPconst x [int64(uint32(c)<<uint64(d))])
+ for {
+ d := v.AuxInt
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpARMCMPconst)
+ v.AuxInt = int64(uint32(c) << uint64(d))
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMCMPshiftLLreg(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (CMPshiftLLreg (MOVWconst [c]) x y)
+ // cond:
+ // result: (InvertFlags (CMPconst [c] (SLL <x.Type> x y)))
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ y := v.Args[2]
+ v.reset(OpARMInvertFlags)
+ v0 := b.NewValue0(v.Line, OpARMCMPconst, TypeFlags)
+ v0.AuxInt = c
+ v1 := b.NewValue0(v.Line, OpARMSLL, x.Type)
+ v1.AddArg(x)
+ v1.AddArg(y)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (CMPshiftLLreg x y (MOVWconst [c]))
+ // cond:
+ // result: (CMPshiftLL x y [c])
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v_2 := v.Args[2]
+ if v_2.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_2.AuxInt
+ v.reset(OpARMCMPshiftLL)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMCMPshiftRA(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (CMPshiftRA (MOVWconst [c]) x [d])
+ // cond:
+ // result: (InvertFlags (CMPconst [c] (SRAconst <x.Type> x [d])))
+ for {
+ d := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ v.reset(OpARMInvertFlags)
+ v0 := b.NewValue0(v.Line, OpARMCMPconst, TypeFlags)
+ v0.AuxInt = c
+ v1 := b.NewValue0(v.Line, OpARMSRAconst, x.Type)
+ v1.AuxInt = d
+ v1.AddArg(x)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (CMPshiftRA x (MOVWconst [c]) [d])
+ // cond:
+ // result: (CMPconst x [int64(int32(c)>>uint64(d))])
+ for {
+ d := v.AuxInt
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpARMCMPconst)
+ v.AuxInt = int64(int32(c) >> uint64(d))
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMCMPshiftRAreg(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (CMPshiftRAreg (MOVWconst [c]) x y)
+ // cond:
+ // result: (InvertFlags (CMPconst [c] (SRA <x.Type> x y)))
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ y := v.Args[2]
+ v.reset(OpARMInvertFlags)
+ v0 := b.NewValue0(v.Line, OpARMCMPconst, TypeFlags)
+ v0.AuxInt = c
+ v1 := b.NewValue0(v.Line, OpARMSRA, x.Type)
+ v1.AddArg(x)
+ v1.AddArg(y)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (CMPshiftRAreg x y (MOVWconst [c]))
+ // cond:
+ // result: (CMPshiftRA x y [c])
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v_2 := v.Args[2]
+ if v_2.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_2.AuxInt
+ v.reset(OpARMCMPshiftRA)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMCMPshiftRL(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (CMPshiftRL (MOVWconst [c]) x [d])
+ // cond:
+ // result: (InvertFlags (CMPconst [c] (SRLconst <x.Type> x [d])))
+ for {
+ d := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ v.reset(OpARMInvertFlags)
+ v0 := b.NewValue0(v.Line, OpARMCMPconst, TypeFlags)
+ v0.AuxInt = c
+ v1 := b.NewValue0(v.Line, OpARMSRLconst, x.Type)
+ v1.AuxInt = d
+ v1.AddArg(x)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (CMPshiftRL x (MOVWconst [c]) [d])
+ // cond:
+ // result: (CMPconst x [int64(uint32(c)>>uint64(d))])
+ for {
+ d := v.AuxInt
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpARMCMPconst)
+ v.AuxInt = int64(uint32(c) >> uint64(d))
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMCMPshiftRLreg(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (CMPshiftRLreg (MOVWconst [c]) x y)
+ // cond:
+ // result: (InvertFlags (CMPconst [c] (SRL <x.Type> x y)))
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ y := v.Args[2]
+ v.reset(OpARMInvertFlags)
+ v0 := b.NewValue0(v.Line, OpARMCMPconst, TypeFlags)
+ v0.AuxInt = c
+ v1 := b.NewValue0(v.Line, OpARMSRL, x.Type)
+ v1.AddArg(x)
+ v1.AddArg(y)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (CMPshiftRLreg x y (MOVWconst [c]))
+ // cond:
+ // result: (CMPshiftRL x y [c])
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v_2 := v.Args[2]
+ if v_2.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_2.AuxInt
+ v.reset(OpARMCMPshiftRL)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMEqual(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Equal (FlagEQ))
+ // cond:
+ // result: (MOVWconst [1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMFlagEQ {
+ break
+ }
+ v.reset(OpARMMOVWconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (Equal (FlagLT_ULT))
+ // cond:
+ // result: (MOVWconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMFlagLT_ULT {
+ break
+ }
+ v.reset(OpARMMOVWconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (Equal (FlagLT_UGT))
+ // cond:
+ // result: (MOVWconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMFlagLT_UGT {
+ break
+ }
+ v.reset(OpARMMOVWconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (Equal (FlagGT_ULT))
+ // cond:
+ // result: (MOVWconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMFlagGT_ULT {
+ break
+ }
+ v.reset(OpARMMOVWconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (Equal (FlagGT_UGT))
+ // cond:
+ // result: (MOVWconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMFlagGT_UGT {
+ break
+ }
+ v.reset(OpARMMOVWconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (Equal (InvertFlags x))
+ // cond:
+ // result: (Equal x)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMInvertFlags {
+ break
+ }
+ x := v_0.Args[0]
+ v.reset(OpARMEqual)
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMGreaterEqual(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (GreaterEqual (FlagEQ))
+ // cond:
+ // result: (MOVWconst [1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMFlagEQ {
+ break
+ }
+ v.reset(OpARMMOVWconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (GreaterEqual (FlagLT_ULT))
+ // cond:
+ // result: (MOVWconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMFlagLT_ULT {
+ break
+ }
+ v.reset(OpARMMOVWconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (GreaterEqual (FlagLT_UGT))
+ // cond:
+ // result: (MOVWconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMFlagLT_UGT {
+ break
+ }
+ v.reset(OpARMMOVWconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (GreaterEqual (FlagGT_ULT))
+ // cond:
+ // result: (MOVWconst [1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMFlagGT_ULT {
+ break
+ }
+ v.reset(OpARMMOVWconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (GreaterEqual (FlagGT_UGT))
+ // cond:
+ // result: (MOVWconst [1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMFlagGT_UGT {
+ break
+ }
+ v.reset(OpARMMOVWconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (GreaterEqual (InvertFlags x))
+ // cond:
+ // result: (LessEqual x)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMInvertFlags {
+ break
+ }
+ x := v_0.Args[0]
+ v.reset(OpARMLessEqual)
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMGreaterEqualU(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (GreaterEqualU (FlagEQ))
+ // cond:
+ // result: (MOVWconst [1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMFlagEQ {
+ break
+ }
+ v.reset(OpARMMOVWconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (GreaterEqualU (FlagLT_ULT))
+ // cond:
+ // result: (MOVWconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMFlagLT_ULT {
+ break
+ }
+ v.reset(OpARMMOVWconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (GreaterEqualU (FlagLT_UGT))
+ // cond:
+ // result: (MOVWconst [1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMFlagLT_UGT {
+ break
+ }
+ v.reset(OpARMMOVWconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (GreaterEqualU (FlagGT_ULT))
+ // cond:
+ // result: (MOVWconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMFlagGT_ULT {
+ break
+ }
+ v.reset(OpARMMOVWconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (GreaterEqualU (FlagGT_UGT))
+ // cond:
+ // result: (MOVWconst [1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMFlagGT_UGT {
+ break
+ }
+ v.reset(OpARMMOVWconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (GreaterEqualU (InvertFlags x))
+ // cond:
+ // result: (LessEqualU x)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMInvertFlags {
+ break
+ }
+ x := v_0.Args[0]
+ v.reset(OpARMLessEqualU)
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMGreaterThan(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (GreaterThan (FlagEQ))
+ // cond:
+ // result: (MOVWconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMFlagEQ {
+ break
+ }
+ v.reset(OpARMMOVWconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (GreaterThan (FlagLT_ULT))
+ // cond:
+ // result: (MOVWconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMFlagLT_ULT {
+ break
+ }
+ v.reset(OpARMMOVWconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (GreaterThan (FlagLT_UGT))
+ // cond:
+ // result: (MOVWconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMFlagLT_UGT {
+ break
+ }
+ v.reset(OpARMMOVWconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (GreaterThan (FlagGT_ULT))
+ // cond:
+ // result: (MOVWconst [1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMFlagGT_ULT {
+ break
+ }
+ v.reset(OpARMMOVWconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (GreaterThan (FlagGT_UGT))
+ // cond:
+ // result: (MOVWconst [1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMFlagGT_UGT {
+ break
+ }
+ v.reset(OpARMMOVWconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (GreaterThan (InvertFlags x))
+ // cond:
+ // result: (LessThan x)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMInvertFlags {
+ break
+ }
+ x := v_0.Args[0]
+ v.reset(OpARMLessThan)
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMGreaterThanU(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (GreaterThanU (FlagEQ))
+ // cond:
+ // result: (MOVWconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMFlagEQ {
+ break
+ }
+ v.reset(OpARMMOVWconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (GreaterThanU (FlagLT_ULT))
+ // cond:
+ // result: (MOVWconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMFlagLT_ULT {
+ break
+ }
+ v.reset(OpARMMOVWconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (GreaterThanU (FlagLT_UGT))
+ // cond:
+ // result: (MOVWconst [1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMFlagLT_UGT {
+ break
+ }
+ v.reset(OpARMMOVWconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (GreaterThanU (FlagGT_ULT))
+ // cond:
+ // result: (MOVWconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMFlagGT_ULT {
+ break
+ }
+ v.reset(OpARMMOVWconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (GreaterThanU (FlagGT_UGT))
+ // cond:
+ // result: (MOVWconst [1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMFlagGT_UGT {
+ break
+ }
+ v.reset(OpARMMOVWconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (GreaterThanU (InvertFlags x))
+ // cond:
+ // result: (LessThanU x)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMInvertFlags {
+ break
+ }
+ x := v_0.Args[0]
+ v.reset(OpARMLessThanU)
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMLessEqual(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (LessEqual (FlagEQ))
+ // cond:
+ // result: (MOVWconst [1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMFlagEQ {
+ break
+ }
+ v.reset(OpARMMOVWconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (LessEqual (FlagLT_ULT))
+ // cond:
+ // result: (MOVWconst [1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMFlagLT_ULT {
+ break
+ }
+ v.reset(OpARMMOVWconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (LessEqual (FlagLT_UGT))
+ // cond:
+ // result: (MOVWconst [1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMFlagLT_UGT {
+ break
+ }
+ v.reset(OpARMMOVWconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (LessEqual (FlagGT_ULT))
+ // cond:
+ // result: (MOVWconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMFlagGT_ULT {
+ break
+ }
+ v.reset(OpARMMOVWconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (LessEqual (FlagGT_UGT))
+ // cond:
+ // result: (MOVWconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMFlagGT_UGT {
+ break
+ }
+ v.reset(OpARMMOVWconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (LessEqual (InvertFlags x))
+ // cond:
+ // result: (GreaterEqual x)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMInvertFlags {
+ break
+ }
+ x := v_0.Args[0]
+ v.reset(OpARMGreaterEqual)
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMLessEqualU(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (LessEqualU (FlagEQ))
+ // cond:
+ // result: (MOVWconst [1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMFlagEQ {
+ break
+ }
+ v.reset(OpARMMOVWconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (LessEqualU (FlagLT_ULT))
+ // cond:
+ // result: (MOVWconst [1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMFlagLT_ULT {
+ break
+ }
+ v.reset(OpARMMOVWconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (LessEqualU (FlagLT_UGT))
+ // cond:
+ // result: (MOVWconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMFlagLT_UGT {
+ break
+ }
+ v.reset(OpARMMOVWconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (LessEqualU (FlagGT_ULT))
+ // cond:
+ // result: (MOVWconst [1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMFlagGT_ULT {
+ break
+ }
+ v.reset(OpARMMOVWconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (LessEqualU (FlagGT_UGT))
+ // cond:
+ // result: (MOVWconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMFlagGT_UGT {
+ break
+ }
+ v.reset(OpARMMOVWconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (LessEqualU (InvertFlags x))
+ // cond:
+ // result: (GreaterEqualU x)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMInvertFlags {
+ break
+ }
+ x := v_0.Args[0]
+ v.reset(OpARMGreaterEqualU)
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMLessThan(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (LessThan (FlagEQ))
+ // cond:
+ // result: (MOVWconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMFlagEQ {
+ break
+ }
+ v.reset(OpARMMOVWconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (LessThan (FlagLT_ULT))
+ // cond:
+ // result: (MOVWconst [1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMFlagLT_ULT {
+ break
+ }
+ v.reset(OpARMMOVWconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (LessThan (FlagLT_UGT))
+ // cond:
+ // result: (MOVWconst [1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMFlagLT_UGT {
+ break
+ }
+ v.reset(OpARMMOVWconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (LessThan (FlagGT_ULT))
+ // cond:
+ // result: (MOVWconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMFlagGT_ULT {
+ break
+ }
+ v.reset(OpARMMOVWconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (LessThan (FlagGT_UGT))
+ // cond:
+ // result: (MOVWconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMFlagGT_UGT {
+ break
+ }
+ v.reset(OpARMMOVWconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (LessThan (InvertFlags x))
+ // cond:
+ // result: (GreaterThan x)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMInvertFlags {
+ break
+ }
+ x := v_0.Args[0]
+ v.reset(OpARMGreaterThan)
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMLessThanU(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (LessThanU (FlagEQ))
+ // cond:
+ // result: (MOVWconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMFlagEQ {
+ break
+ }
+ v.reset(OpARMMOVWconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (LessThanU (FlagLT_ULT))
+ // cond:
+ // result: (MOVWconst [1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMFlagLT_ULT {
+ break
+ }
+ v.reset(OpARMMOVWconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (LessThanU (FlagLT_UGT))
+ // cond:
+ // result: (MOVWconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMFlagLT_UGT {
+ break
+ }
+ v.reset(OpARMMOVWconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (LessThanU (FlagGT_ULT))
+ // cond:
+ // result: (MOVWconst [1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMFlagGT_ULT {
+ break
+ }
+ v.reset(OpARMMOVWconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (LessThanU (FlagGT_UGT))
+ // cond:
+ // result: (MOVWconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMFlagGT_UGT {
+ break
+ }
+ v.reset(OpARMMOVWconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (LessThanU (InvertFlags x))
+ // cond:
+ // result: (GreaterThanU x)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMInvertFlags {
+ break
+ }
+ x := v_0.Args[0]
+ v.reset(OpARMGreaterThanU)
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMMOVBUload(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (MOVBUload [off1] {sym} (ADDconst [off2] ptr) mem)
+ // cond:
+ // result: (MOVBUload [off1+off2] {sym} ptr mem)
+ for {
+ off1 := v.AuxInt
+ sym := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMADDconst {
+ 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_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWaddr {
+ break
+ }
+ off2 := v_0.AuxInt
+ sym2 := v_0.Aux
+ ptr := v_0.Args[0]
+ mem := v.Args[1]
+ if !(canMergeSym(sym1, sym2)) {
+ break
+ }
+ v.reset(OpARMMOVBUload)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ 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
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMMOVBstore {
+ 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) && !isSigned(x.Type)) {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMMOVBUreg(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (MOVBUreg x:(MOVBUload _ _))
+ // cond:
+ // result: (MOVWreg x)
+ for {
+ x := v.Args[0]
+ if x.Op != OpARMMOVBUload {
+ break
+ }
+ v.reset(OpARMMOVWreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVBUreg (ANDconst [c] x))
+ // cond:
+ // result: (ANDconst [c&0xff] x)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMANDconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v_0.Args[0]
+ v.reset(OpARMANDconst)
+ v.AuxInt = c & 0xff
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVBUreg x:(MOVBUreg _))
+ // cond:
+ // result: (MOVWreg x)
+ for {
+ x := v.Args[0]
+ if x.Op != OpARMMOVBUreg {
+ break
+ }
+ v.reset(OpARMMOVWreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVBUreg (MOVWconst [c]))
+ // cond:
+ // result: (MOVWconst [int64(uint8(c))])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_0.AuxInt
+ v.reset(OpARMMOVWconst)
+ v.AuxInt = int64(uint8(c))
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMMOVBload(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (MOVBload [off1] {sym} (ADDconst [off2] ptr) mem)
+ // cond:
+ // result: (MOVBload [off1+off2] {sym} ptr mem)
+ for {
+ off1 := v.AuxInt
+ sym := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMADDconst {
+ 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_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWaddr {
+ break
+ }
+ off2 := v_0.AuxInt
+ sym2 := v_0.Aux
+ ptr := v_0.Args[0]
+ mem := v.Args[1]
+ if !(canMergeSym(sym1, sym2)) {
+ break
+ }
+ v.reset(OpARMMOVBload)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ 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
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMMOVBstore {
+ 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) && isSigned(x.Type)) {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMMOVBreg(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (MOVBreg x:(MOVBload _ _))
+ // cond:
+ // result: (MOVWreg x)
+ for {
+ x := v.Args[0]
+ if x.Op != OpARMMOVBload {
+ break
+ }
+ v.reset(OpARMMOVWreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVBreg (ANDconst [c] x))
+ // cond: c & 0x80 == 0
+ // result: (ANDconst [c&0x7f] x)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMANDconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v_0.Args[0]
+ if !(c&0x80 == 0) {
+ break
+ }
+ v.reset(OpARMANDconst)
+ v.AuxInt = c & 0x7f
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVBreg x:(MOVBreg _))
+ // cond:
+ // result: (MOVWreg x)
+ for {
+ x := v.Args[0]
+ if x.Op != OpARMMOVBreg {
+ break
+ }
+ v.reset(OpARMMOVWreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVBreg (MOVWconst [c]))
+ // cond:
+ // result: (MOVWconst [int64(int8(c))])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_0.AuxInt
+ v.reset(OpARMMOVWconst)
+ v.AuxInt = int64(int8(c))
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMMOVBstore(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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_0 := v.Args[0]
+ if v_0.Op != OpARMADDconst {
+ 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_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(OpARMMOVBstore)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(ptr)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVBstore [off] {sym} ptr (MOVBreg x) mem)
+ // cond:
+ // result: (MOVBstore [off] {sym} ptr x mem)
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMMOVBreg {
+ break
+ }
+ x := v_1.Args[0]
+ mem := v.Args[2]
+ v.reset(OpARMMOVBstore)
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(x)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVBstore [off] {sym} ptr (MOVBUreg x) mem)
+ // cond:
+ // result: (MOVBstore [off] {sym} ptr x mem)
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMMOVBUreg {
+ break
+ }
+ x := v_1.Args[0]
+ mem := v.Args[2]
+ v.reset(OpARMMOVBstore)
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(x)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVBstore [off] {sym} ptr (MOVHreg x) mem)
+ // cond:
+ // result: (MOVBstore [off] {sym} ptr x mem)
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMMOVHreg {
+ break
+ }
+ x := v_1.Args[0]
+ mem := v.Args[2]
+ v.reset(OpARMMOVBstore)
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(x)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVBstore [off] {sym} ptr (MOVHUreg x) mem)
+ // cond:
+ // result: (MOVBstore [off] {sym} ptr x mem)
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMMOVHUreg {
+ break
+ }
+ x := v_1.Args[0]
+ mem := v.Args[2]
+ v.reset(OpARMMOVBstore)
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(x)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMMOVDload(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (MOVDload [off1] {sym} (ADDconst [off2] ptr) mem)
+ // cond:
+ // result: (MOVDload [off1+off2] {sym} ptr mem)
+ for {
+ off1 := v.AuxInt
+ sym := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMADDconst {
+ 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_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWaddr {
+ break
+ }
+ off2 := v_0.AuxInt
+ sym2 := v_0.Aux
+ ptr := v_0.Args[0]
+ mem := v.Args[1]
+ if !(canMergeSym(sym1, sym2)) {
+ break
+ }
+ v.reset(OpARMMOVDload)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVDload [off] {sym} ptr (MOVDstore [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 != OpARMMOVDstore {
+ break
+ }
+ off2 := v_1.AuxInt
+ sym2 := v_1.Aux
+ ptr2 := v_1.Args[0]
+ x := v_1.Args[1]
+ if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMMOVDstore(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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_0 := v.Args[0]
+ if v_0.Op != OpARMADDconst {
+ 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_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(OpARMMOVDstore)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(ptr)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMMOVFload(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (MOVFload [off1] {sym} (ADDconst [off2] ptr) mem)
+ // cond:
+ // result: (MOVFload [off1+off2] {sym} ptr mem)
+ for {
+ off1 := v.AuxInt
+ sym := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMADDconst {
+ 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_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWaddr {
+ break
+ }
+ off2 := v_0.AuxInt
+ sym2 := v_0.Aux
+ ptr := v_0.Args[0]
+ mem := v.Args[1]
+ if !(canMergeSym(sym1, sym2)) {
+ break
+ }
+ v.reset(OpARMMOVFload)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVFload [off] {sym} ptr (MOVFstore [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 != OpARMMOVFstore {
+ break
+ }
+ off2 := v_1.AuxInt
+ sym2 := v_1.Aux
+ ptr2 := v_1.Args[0]
+ x := v_1.Args[1]
+ if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMMOVFstore(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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_0 := v.Args[0]
+ if v_0.Op != OpARMADDconst {
+ 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_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(OpARMMOVFstore)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(ptr)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMMOVHUload(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (MOVHUload [off1] {sym} (ADDconst [off2] ptr) mem)
+ // cond:
+ // result: (MOVHUload [off1+off2] {sym} ptr mem)
+ for {
+ off1 := v.AuxInt
+ sym := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMADDconst {
+ 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_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWaddr {
+ break
+ }
+ off2 := v_0.AuxInt
+ sym2 := v_0.Aux
+ ptr := v_0.Args[0]
+ mem := v.Args[1]
+ if !(canMergeSym(sym1, sym2)) {
+ break
+ }
+ v.reset(OpARMMOVHUload)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ 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
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMMOVHstore {
+ 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) && !isSigned(x.Type)) {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMMOVHUreg(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (MOVHUreg x:(MOVBUload _ _))
+ // cond:
+ // result: (MOVWreg x)
+ for {
+ x := v.Args[0]
+ if x.Op != OpARMMOVBUload {
+ break
+ }
+ v.reset(OpARMMOVWreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVHUreg x:(MOVHUload _ _))
+ // cond:
+ // result: (MOVWreg x)
+ for {
+ x := v.Args[0]
+ if x.Op != OpARMMOVHUload {
+ break
+ }
+ v.reset(OpARMMOVWreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVHUreg (ANDconst [c] x))
+ // cond:
+ // result: (ANDconst [c&0xffff] x)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMANDconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v_0.Args[0]
+ v.reset(OpARMANDconst)
+ v.AuxInt = c & 0xffff
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVHUreg x:(MOVBUreg _))
+ // cond:
+ // result: (MOVWreg x)
+ for {
+ x := v.Args[0]
+ if x.Op != OpARMMOVBUreg {
+ break
+ }
+ v.reset(OpARMMOVWreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVHUreg x:(MOVHUreg _))
+ // cond:
+ // result: (MOVWreg x)
+ for {
+ x := v.Args[0]
+ if x.Op != OpARMMOVHUreg {
+ break
+ }
+ v.reset(OpARMMOVWreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVHUreg (MOVWconst [c]))
+ // cond:
+ // result: (MOVWconst [int64(uint16(c))])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_0.AuxInt
+ v.reset(OpARMMOVWconst)
+ v.AuxInt = int64(uint16(c))
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMMOVHload(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (MOVHload [off1] {sym} (ADDconst [off2] ptr) mem)
+ // cond:
+ // result: (MOVHload [off1+off2] {sym} ptr mem)
+ for {
+ off1 := v.AuxInt
+ sym := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMADDconst {
+ 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_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWaddr {
+ break
+ }
+ off2 := v_0.AuxInt
+ sym2 := v_0.Aux
+ ptr := v_0.Args[0]
+ mem := v.Args[1]
+ if !(canMergeSym(sym1, sym2)) {
+ break
+ }
+ v.reset(OpARMMOVHload)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ 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
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMMOVHstore {
+ 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) && isSigned(x.Type)) {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMMOVHreg(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (MOVHreg x:(MOVBload _ _))
+ // cond:
+ // result: (MOVWreg x)
+ for {
+ x := v.Args[0]
+ if x.Op != OpARMMOVBload {
+ break
+ }
+ v.reset(OpARMMOVWreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVHreg x:(MOVBUload _ _))
+ // cond:
+ // result: (MOVWreg x)
+ for {
+ x := v.Args[0]
+ if x.Op != OpARMMOVBUload {
+ break
+ }
+ v.reset(OpARMMOVWreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVHreg x:(MOVHload _ _))
+ // cond:
+ // result: (MOVWreg x)
+ for {
+ x := v.Args[0]
+ if x.Op != OpARMMOVHload {
+ break
+ }
+ v.reset(OpARMMOVWreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVHreg (ANDconst [c] x))
+ // cond: c & 0x8000 == 0
+ // result: (ANDconst [c&0x7fff] x)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMANDconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v_0.Args[0]
+ if !(c&0x8000 == 0) {
+ break
+ }
+ v.reset(OpARMANDconst)
+ v.AuxInt = c & 0x7fff
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVHreg x:(MOVBreg _))
+ // cond:
+ // result: (MOVWreg x)
+ for {
+ x := v.Args[0]
+ if x.Op != OpARMMOVBreg {
+ break
+ }
+ v.reset(OpARMMOVWreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVHreg x:(MOVBUreg _))
+ // cond:
+ // result: (MOVWreg x)
+ for {
+ x := v.Args[0]
+ if x.Op != OpARMMOVBUreg {
+ break
+ }
+ v.reset(OpARMMOVWreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVHreg x:(MOVHreg _))
+ // cond:
+ // result: (MOVWreg x)
+ for {
+ x := v.Args[0]
+ if x.Op != OpARMMOVHreg {
+ break
+ }
+ v.reset(OpARMMOVWreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVHreg (MOVWconst [c]))
+ // cond:
+ // result: (MOVWconst [int64(int16(c))])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_0.AuxInt
+ v.reset(OpARMMOVWconst)
+ v.AuxInt = int64(int16(c))
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMMOVHstore(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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_0 := v.Args[0]
+ if v_0.Op != OpARMADDconst {
+ break
+ }
+ off2 := v_0.AuxInt
+ ptr := v_0.Args[0]
+ val := v.Args[1]
+ mem := v.Args[2]
+ v.reset(OpARMMOVHstore)
+ 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_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)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVHstore [off] {sym} ptr (MOVHreg 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 != OpARMMOVHreg {
+ break
+ }
+ x := v_1.Args[0]
+ mem := v.Args[2]
+ v.reset(OpARMMOVHstore)
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(x)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVHstore [off] {sym} ptr (MOVHUreg 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 != OpARMMOVHUreg {
+ break
+ }
+ x := v_1.Args[0]
+ mem := v.Args[2]
+ v.reset(OpARMMOVHstore)
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(x)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMMOVWload(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (MOVWload [off1] {sym} (ADDconst [off2] ptr) mem)
+ // cond:
+ // result: (MOVWload [off1+off2] {sym} ptr mem)
+ for {
+ off1 := v.AuxInt
+ sym := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMADDconst {
+ 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_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWaddr {
+ break
+ }
+ off2 := v_0.AuxInt
+ sym2 := v_0.Aux
+ ptr := v_0.Args[0]
+ mem := v.Args[1]
+ if !(canMergeSym(sym1, sym2)) {
+ break
+ }
+ v.reset(OpARMMOVWload)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVWload [off] {sym} ptr (MOVWstore [off2] {sym2} ptr2 x _))
+ // cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
+ // result: x
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMMOVWstore {
+ break
+ }
+ off2 := v_1.AuxInt
+ sym2 := v_1.Aux
+ ptr2 := v_1.Args[0]
+ x := v_1.Args[1]
+ if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVWload [0] {sym} (ADD ptr idx) mem)
+ // cond: sym == nil && !config.nacl
+ // result: (MOVWloadidx ptr idx mem)
+ for {
+ if v.AuxInt != 0 {
+ break
+ }
+ sym := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMADD {
+ break
+ }
+ ptr := v_0.Args[0]
+ idx := v_0.Args[1]
+ mem := v.Args[1]
+ if !(sym == nil && !config.nacl) {
+ break
+ }
+ v.reset(OpARMMOVWloadidx)
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVWload [0] {sym} (ADDshiftLL ptr idx [c]) mem)
+ // cond: sym == nil && !config.nacl
+ // result: (MOVWloadshiftLL ptr idx [c] mem)
+ for {
+ if v.AuxInt != 0 {
+ break
+ }
+ sym := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMADDshiftLL {
+ break
+ }
+ c := v_0.AuxInt
+ ptr := v_0.Args[0]
+ idx := v_0.Args[1]
+ mem := v.Args[1]
+ if !(sym == nil && !config.nacl) {
+ break
+ }
+ v.reset(OpARMMOVWloadshiftLL)
+ v.AuxInt = c
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVWload [0] {sym} (ADDshiftRL ptr idx [c]) mem)
+ // cond: sym == nil && !config.nacl
+ // result: (MOVWloadshiftRL ptr idx [c] mem)
+ for {
+ if v.AuxInt != 0 {
+ break
+ }
+ sym := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMADDshiftRL {
+ break
+ }
+ c := v_0.AuxInt
+ ptr := v_0.Args[0]
+ idx := v_0.Args[1]
+ mem := v.Args[1]
+ if !(sym == nil && !config.nacl) {
+ break
+ }
+ v.reset(OpARMMOVWloadshiftRL)
+ v.AuxInt = c
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVWload [0] {sym} (ADDshiftRA ptr idx [c]) mem)
+ // cond: sym == nil && !config.nacl
+ // result: (MOVWloadshiftRA ptr idx [c] mem)
+ for {
+ if v.AuxInt != 0 {
+ break
+ }
+ sym := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMADDshiftRA {
+ break
+ }
+ c := v_0.AuxInt
+ ptr := v_0.Args[0]
+ idx := v_0.Args[1]
+ mem := v.Args[1]
+ if !(sym == nil && !config.nacl) {
+ break
+ }
+ v.reset(OpARMMOVWloadshiftRA)
+ v.AuxInt = c
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMMOVWloadidx(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (MOVWloadidx ptr idx (MOVWstoreidx ptr2 idx x _))
+ // cond: isSamePtr(ptr, ptr2)
+ // result: x
+ for {
+ ptr := v.Args[0]
+ idx := v.Args[1]
+ v_2 := v.Args[2]
+ if v_2.Op != OpARMMOVWstoreidx {
+ break
+ }
+ ptr2 := v_2.Args[0]
+ if idx != v_2.Args[1] {
+ break
+ }
+ x := v_2.Args[2]
+ if !(isSamePtr(ptr, ptr2)) {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVWloadidx ptr (MOVWconst [c]) mem)
+ // cond:
+ // result: (MOVWload [c] ptr mem)
+ for {
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_1.AuxInt
+ mem := v.Args[2]
+ v.reset(OpARMMOVWload)
+ v.AuxInt = c
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVWloadidx (MOVWconst [c]) ptr mem)
+ // cond:
+ // result: (MOVWload [c] ptr mem)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_0.AuxInt
+ ptr := v.Args[1]
+ mem := v.Args[2]
+ v.reset(OpARMMOVWload)
+ v.AuxInt = c
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVWloadidx ptr (SLLconst idx [c]) mem)
+ // cond:
+ // result: (MOVWloadshiftLL ptr idx [c] mem)
+ for {
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMSLLconst {
+ break
+ }
+ c := v_1.AuxInt
+ idx := v_1.Args[0]
+ mem := v.Args[2]
+ v.reset(OpARMMOVWloadshiftLL)
+ v.AuxInt = c
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVWloadidx (SLLconst idx [c]) ptr mem)
+ // cond:
+ // result: (MOVWloadshiftLL ptr idx [c] mem)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMSLLconst {
+ break
+ }
+ c := v_0.AuxInt
+ idx := v_0.Args[0]
+ ptr := v.Args[1]
+ mem := v.Args[2]
+ v.reset(OpARMMOVWloadshiftLL)
+ v.AuxInt = c
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVWloadidx ptr (SRLconst idx [c]) mem)
+ // cond:
+ // result: (MOVWloadshiftRL ptr idx [c] mem)
+ for {
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMSRLconst {
+ break
+ }
+ c := v_1.AuxInt
+ idx := v_1.Args[0]
+ mem := v.Args[2]
+ v.reset(OpARMMOVWloadshiftRL)
+ v.AuxInt = c
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVWloadidx (SRLconst idx [c]) ptr mem)
+ // cond:
+ // result: (MOVWloadshiftRL ptr idx [c] mem)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMSRLconst {
+ break
+ }
+ c := v_0.AuxInt
+ idx := v_0.Args[0]
+ ptr := v.Args[1]
+ mem := v.Args[2]
+ v.reset(OpARMMOVWloadshiftRL)
+ v.AuxInt = c
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVWloadidx ptr (SRAconst idx [c]) mem)
+ // cond:
+ // result: (MOVWloadshiftRA ptr idx [c] mem)
+ for {
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMSRAconst {
+ break
+ }
+ c := v_1.AuxInt
+ idx := v_1.Args[0]
+ mem := v.Args[2]
+ v.reset(OpARMMOVWloadshiftRA)
+ v.AuxInt = c
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVWloadidx (SRAconst idx [c]) ptr mem)
+ // cond:
+ // result: (MOVWloadshiftRA ptr idx [c] mem)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMSRAconst {
+ break
+ }
+ c := v_0.AuxInt
+ idx := v_0.Args[0]
+ ptr := v.Args[1]
+ mem := v.Args[2]
+ v.reset(OpARMMOVWloadshiftRA)
+ v.AuxInt = c
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMMOVWloadshiftLL(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (MOVWloadshiftLL ptr idx [c] (MOVWstoreshiftLL ptr2 idx [d] x _))
+ // cond: c==d && isSamePtr(ptr, ptr2)
+ // result: x
+ for {
+ c := v.AuxInt
+ ptr := v.Args[0]
+ idx := v.Args[1]
+ v_2 := v.Args[2]
+ if v_2.Op != OpARMMOVWstoreshiftLL {
+ break
+ }
+ d := v_2.AuxInt
+ ptr2 := v_2.Args[0]
+ if idx != v_2.Args[1] {
+ break
+ }
+ x := v_2.Args[2]
+ if !(c == d && isSamePtr(ptr, ptr2)) {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVWloadshiftLL ptr (MOVWconst [c]) [d] mem)
+ // cond:
+ // result: (MOVWload [int64(uint32(c)<<uint64(d))] ptr mem)
+ for {
+ d := v.AuxInt
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_1.AuxInt
+ mem := v.Args[2]
+ v.reset(OpARMMOVWload)
+ v.AuxInt = int64(uint32(c) << uint64(d))
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMMOVWloadshiftRA(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (MOVWloadshiftRA ptr idx [c] (MOVWstoreshiftRA ptr2 idx [d] x _))
+ // cond: c==d && isSamePtr(ptr, ptr2)
+ // result: x
+ for {
+ c := v.AuxInt
+ ptr := v.Args[0]
+ idx := v.Args[1]
+ v_2 := v.Args[2]
+ if v_2.Op != OpARMMOVWstoreshiftRA {
+ break
+ }
+ d := v_2.AuxInt
+ ptr2 := v_2.Args[0]
+ if idx != v_2.Args[1] {
+ break
+ }
+ x := v_2.Args[2]
+ if !(c == d && isSamePtr(ptr, ptr2)) {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVWloadshiftRA ptr (MOVWconst [c]) [d] mem)
+ // cond:
+ // result: (MOVWload [int64(int32(c)>>uint64(d))] ptr mem)
+ for {
+ d := v.AuxInt
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_1.AuxInt
+ mem := v.Args[2]
+ v.reset(OpARMMOVWload)
+ v.AuxInt = int64(int32(c) >> uint64(d))
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMMOVWloadshiftRL(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (MOVWloadshiftRL ptr idx [c] (MOVWstoreshiftRL ptr2 idx [d] x _))
+ // cond: c==d && isSamePtr(ptr, ptr2)
+ // result: x
+ for {
+ c := v.AuxInt
+ ptr := v.Args[0]
+ idx := v.Args[1]
+ v_2 := v.Args[2]
+ if v_2.Op != OpARMMOVWstoreshiftRL {
+ break
+ }
+ d := v_2.AuxInt
+ ptr2 := v_2.Args[0]
+ if idx != v_2.Args[1] {
+ break
+ }
+ x := v_2.Args[2]
+ if !(c == d && isSamePtr(ptr, ptr2)) {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVWloadshiftRL ptr (MOVWconst [c]) [d] mem)
+ // cond:
+ // result: (MOVWload [int64(uint32(c)>>uint64(d))] ptr mem)
+ for {
+ d := v.AuxInt
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_1.AuxInt
+ mem := v.Args[2]
+ v.reset(OpARMMOVWload)
+ v.AuxInt = int64(uint32(c) >> uint64(d))
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMMOVWreg(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (MOVWreg x)
+ // cond: x.Uses == 1
+ // result: (MOVWnop x)
+ for {
+ x := v.Args[0]
+ if !(x.Uses == 1) {
+ break
+ }
+ v.reset(OpARMMOVWnop)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVWreg (MOVWconst [c]))
+ // cond:
+ // result: (MOVWconst [c])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_0.AuxInt
+ v.reset(OpARMMOVWconst)
+ v.AuxInt = c
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMMOVWstore(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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_0 := v.Args[0]
+ if v_0.Op != OpARMADDconst {
+ 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_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(OpARMMOVWstore)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(ptr)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVWstore [0] {sym} (ADD ptr idx) val mem)
+ // cond: sym == nil && !config.nacl
+ // result: (MOVWstoreidx ptr idx val mem)
+ for {
+ if v.AuxInt != 0 {
+ break
+ }
+ sym := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMADD {
+ break
+ }
+ ptr := v_0.Args[0]
+ idx := v_0.Args[1]
+ val := v.Args[1]
+ mem := v.Args[2]
+ if !(sym == nil && !config.nacl) {
+ break
+ }
+ v.reset(OpARMMOVWstoreidx)
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVWstore [0] {sym} (ADDshiftLL ptr idx [c]) val mem)
+ // cond: sym == nil && !config.nacl
+ // result: (MOVWstoreshiftLL ptr idx [c] val mem)
+ for {
+ if v.AuxInt != 0 {
+ break
+ }
+ sym := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMADDshiftLL {
+ break
+ }
+ c := v_0.AuxInt
+ ptr := v_0.Args[0]
+ idx := v_0.Args[1]
+ val := v.Args[1]
+ mem := v.Args[2]
+ if !(sym == nil && !config.nacl) {
+ break
+ }
+ v.reset(OpARMMOVWstoreshiftLL)
+ v.AuxInt = c
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVWstore [0] {sym} (ADDshiftRL ptr idx [c]) val mem)
+ // cond: sym == nil && !config.nacl
+ // result: (MOVWstoreshiftRL ptr idx [c] val mem)
+ for {
+ if v.AuxInt != 0 {
+ break
+ }
+ sym := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMADDshiftRL {
+ break
+ }
+ c := v_0.AuxInt
+ ptr := v_0.Args[0]
+ idx := v_0.Args[1]
+ val := v.Args[1]
+ mem := v.Args[2]
+ if !(sym == nil && !config.nacl) {
+ break
+ }
+ v.reset(OpARMMOVWstoreshiftRL)
+ v.AuxInt = c
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVWstore [0] {sym} (ADDshiftRA ptr idx [c]) val mem)
+ // cond: sym == nil && !config.nacl
+ // result: (MOVWstoreshiftRA ptr idx [c] val mem)
+ for {
+ if v.AuxInt != 0 {
+ break
+ }
+ sym := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMADDshiftRA {
+ break
+ }
+ c := v_0.AuxInt
+ ptr := v_0.Args[0]
+ idx := v_0.Args[1]
+ val := v.Args[1]
+ mem := v.Args[2]
+ if !(sym == nil && !config.nacl) {
+ break
+ }
+ v.reset(OpARMMOVWstoreshiftRA)
+ v.AuxInt = c
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMMOVWstoreidx(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (MOVWstoreidx ptr (MOVWconst [c]) val mem)
+ // cond:
+ // result: (MOVWstore [c] ptr val mem)
+ for {
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_1.AuxInt
+ val := v.Args[2]
+ mem := v.Args[3]
+ v.reset(OpARMMOVWstore)
+ v.AuxInt = c
+ v.AddArg(ptr)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVWstoreidx (MOVWconst [c]) ptr val mem)
+ // cond:
+ // result: (MOVWstore [c] ptr val mem)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_0.AuxInt
+ ptr := v.Args[1]
+ val := v.Args[2]
+ mem := v.Args[3]
+ v.reset(OpARMMOVWstore)
+ v.AuxInt = c
+ v.AddArg(ptr)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVWstoreidx ptr (SLLconst idx [c]) val mem)
+ // cond:
+ // result: (MOVWstoreshiftLL ptr idx [c] val mem)
+ for {
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMSLLconst {
+ break
+ }
+ c := v_1.AuxInt
+ idx := v_1.Args[0]
+ val := v.Args[2]
+ mem := v.Args[3]
+ v.reset(OpARMMOVWstoreshiftLL)
+ v.AuxInt = c
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVWstoreidx (SLLconst idx [c]) ptr val mem)
+ // cond:
+ // result: (MOVWstoreshiftLL ptr idx [c] val mem)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMSLLconst {
+ break
+ }
+ c := v_0.AuxInt
+ idx := v_0.Args[0]
+ ptr := v.Args[1]
+ val := v.Args[2]
+ mem := v.Args[3]
+ v.reset(OpARMMOVWstoreshiftLL)
+ v.AuxInt = c
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVWstoreidx ptr (SRLconst idx [c]) val mem)
+ // cond:
+ // result: (MOVWstoreshiftRL ptr idx [c] val mem)
+ for {
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMSRLconst {
+ break
+ }
+ c := v_1.AuxInt
+ idx := v_1.Args[0]
+ val := v.Args[2]
+ mem := v.Args[3]
+ v.reset(OpARMMOVWstoreshiftRL)
+ v.AuxInt = c
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVWstoreidx (SRLconst idx [c]) ptr val mem)
+ // cond:
+ // result: (MOVWstoreshiftRL ptr idx [c] val mem)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMSRLconst {
+ break
+ }
+ c := v_0.AuxInt
+ idx := v_0.Args[0]
+ ptr := v.Args[1]
+ val := v.Args[2]
+ mem := v.Args[3]
+ v.reset(OpARMMOVWstoreshiftRL)
+ v.AuxInt = c
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVWstoreidx ptr (SRAconst idx [c]) val mem)
+ // cond:
+ // result: (MOVWstoreshiftRA ptr idx [c] val mem)
+ for {
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMSRAconst {
+ break
+ }
+ c := v_1.AuxInt
+ idx := v_1.Args[0]
+ val := v.Args[2]
+ mem := v.Args[3]
+ v.reset(OpARMMOVWstoreshiftRA)
+ v.AuxInt = c
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVWstoreidx (SRAconst idx [c]) ptr val mem)
+ // cond:
+ // result: (MOVWstoreshiftRA ptr idx [c] val mem)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMSRAconst {
+ break
+ }
+ c := v_0.AuxInt
+ idx := v_0.Args[0]
+ ptr := v.Args[1]
+ val := v.Args[2]
+ mem := v.Args[3]
+ v.reset(OpARMMOVWstoreshiftRA)
+ v.AuxInt = c
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMMOVWstoreshiftLL(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (MOVWstoreshiftLL ptr (MOVWconst [c]) [d] val mem)
+ // cond:
+ // result: (MOVWstore [int64(uint32(c)<<uint64(d))] ptr val mem)
+ for {
+ d := v.AuxInt
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_1.AuxInt
+ val := v.Args[2]
+ mem := v.Args[3]
+ v.reset(OpARMMOVWstore)
+ v.AuxInt = int64(uint32(c) << uint64(d))
+ v.AddArg(ptr)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMMOVWstoreshiftRA(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (MOVWstoreshiftRA ptr (MOVWconst [c]) [d] val mem)
+ // cond:
+ // result: (MOVWstore [int64(int32(c)>>uint64(d))] ptr val mem)
+ for {
+ d := v.AuxInt
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_1.AuxInt
+ val := v.Args[2]
+ mem := v.Args[3]
+ v.reset(OpARMMOVWstore)
+ v.AuxInt = int64(int32(c) >> uint64(d))
+ v.AddArg(ptr)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMMOVWstoreshiftRL(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (MOVWstoreshiftRL ptr (MOVWconst [c]) [d] val mem)
+ // cond:
+ // result: (MOVWstore [int64(uint32(c)>>uint64(d))] ptr val mem)
+ for {
+ d := v.AuxInt
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_1.AuxInt
+ val := v.Args[2]
+ mem := v.Args[3]
+ v.reset(OpARMMOVWstore)
+ v.AuxInt = int64(uint32(c) >> uint64(d))
+ v.AddArg(ptr)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMMUL(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (MUL x (MOVWconst [c]))
+ // cond: int32(c) == -1
+ // result: (RSBconst [0] x)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_1.AuxInt
+ 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_1 := v.Args[1]
+ if v_1.Op != OpARMMOVWconst {
+ break
+ }
+ if v_1.AuxInt != 0 {
+ break
+ }
+ v.reset(OpARMMOVWconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (MUL x (MOVWconst [1]))
+ // cond:
+ // result: x
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMMOVWconst {
+ break
+ }
+ if v_1.AuxInt != 1 {
+ break
+ }
+ 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 {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_1.AuxInt
+ 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 {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_1.AuxInt
+ 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 x (MOVWconst [c]))
+ // 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 {
+ break
+ }
+ c := v_1.AuxInt
+ if !(isPowerOfTwo(c+1) && int32(c) >= 7) {
+ break
+ }
+ v.reset(OpARMRSBshiftLL)
+ v.AuxInt = log2(c + 1)
+ v.AddArg(x)
+ 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]))
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_1.AuxInt
+ if !(c%3 == 0 && isPowerOfTwo(c/3) && is32Bit(c)) {
+ 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)
+ 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]))
+ for {
+ 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)) {
+ break
+ }
+ v.reset(OpARMSLLconst)
+ v.AuxInt = log2(c / 5)
+ v0 := b.NewValue0(v.Line, OpARMADDshiftLL, x.Type)
+ v0.AuxInt = 2
+ 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]))
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_1.AuxInt
+ if !(c%7 == 0 && isPowerOfTwo(c/7) && is32Bit(c)) {
+ break
+ }
+ v.reset(OpARMSLLconst)
+ v.AuxInt = log2(c / 7)
+ v0 := b.NewValue0(v.Line, OpARMRSBshiftLL, x.Type)
+ v0.AuxInt = 3
+ 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]))
+ for {
+ 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)) {
+ break
+ }
+ v.reset(OpARMSLLconst)
+ v.AuxInt = log2(c / 9)
+ v0 := b.NewValue0(v.Line, OpARMADDshiftLL, x.Type)
+ v0.AuxInt = 3
+ 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)
+ for {
+ 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 (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)
+ 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]))
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWconst {
+ break
+ }
+ 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 / 3)
+ v0 := b.NewValue0(v.Line, OpARMADDshiftLL, x.Type)
+ v0.AuxInt = 1
+ 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]))
+ for {
+ 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)) {
+ break
+ }
+ v.reset(OpARMSLLconst)
+ v.AuxInt = log2(c / 5)
+ v0 := b.NewValue0(v.Line, OpARMADDshiftLL, x.Type)
+ v0.AuxInt = 2
+ 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]))
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ if !(c%7 == 0 && isPowerOfTwo(c/7) && is32Bit(c)) {
+ break
+ }
+ v.reset(OpARMSLLconst)
+ v.AuxInt = log2(c / 7)
+ v0 := b.NewValue0(v.Line, OpARMRSBshiftLL, x.Type)
+ v0.AuxInt = 3
+ v0.AddArg(x)
+ v0.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (MUL (MOVWconst [c]) x)
+ // 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 {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ if !(c%9 == 0 && isPowerOfTwo(c/9) && is32Bit(c)) {
+ break
+ }
+ v.reset(OpARMSLLconst)
+ v.AuxInt = log2(c / 9)
+ v0 := b.NewValue0(v.Line, OpARMADDshiftLL, x.Type)
+ v0.AuxInt = 3
+ v0.AddArg(x)
+ v0.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (MUL (MOVWconst [c]) (MOVWconst [d]))
+ // cond:
+ // result: (MOVWconst [int64(int32(c*d))])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_0.AuxInt
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMMOVWconst {
+ break
+ }
+ d := v_1.AuxInt
+ v.reset(OpARMMOVWconst)
+ v.AuxInt = int64(int32(c * d))
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMMULA(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (MULA x (MOVWconst [c]) a)
+ // cond: int32(c) == -1
+ // result: (SUB a x)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_1.AuxInt
+ a := v.Args[2]
+ if !(int32(c) == -1) {
+ break
+ }
+ v.reset(OpARMSUB)
+ v.AddArg(a)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MULA _ (MOVWconst [0]) a)
+ // cond:
+ // result: a
+ for {
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMMOVWconst {
+ break
+ }
+ if v_1.AuxInt != 0 {
+ break
+ }
+ a := v.Args[2]
+ v.reset(OpCopy)
+ v.Type = a.Type
+ v.AddArg(a)
+ return true
+ }
+ // match: (MULA x (MOVWconst [1]) a)
+ // cond:
+ // result: (ADD x a)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMMOVWconst {
+ break
+ }
+ if v_1.AuxInt != 1 {
+ break
+ }
+ a := v.Args[2]
+ v.reset(OpARMADD)
+ v.AddArg(x)
+ v.AddArg(a)
+ return true
+ }
+ // match: (MULA x (MOVWconst [c]) a)
+ // cond: isPowerOfTwo(c)
+ // result: (ADD (SLLconst <x.Type> [log2(c)] x) a)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_1.AuxInt
+ a := v.Args[2]
+ if !(isPowerOfTwo(c)) {
+ break
+ }
+ v.reset(OpARMADD)
+ v0 := b.NewValue0(v.Line, OpARMSLLconst, x.Type)
+ v0.AuxInt = log2(c)
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v.AddArg(a)
+ return true
+ }
+ // match: (MULA x (MOVWconst [c]) a)
+ // cond: isPowerOfTwo(c-1) && int32(c) >= 3
+ // result: (ADD (ADDshiftLL <x.Type> x x [log2(c-1)]) a)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_1.AuxInt
+ a := v.Args[2]
+ if !(isPowerOfTwo(c-1) && int32(c) >= 3) {
+ break
+ }
+ v.reset(OpARMADD)
+ v0 := b.NewValue0(v.Line, OpARMADDshiftLL, x.Type)
+ v0.AuxInt = log2(c - 1)
+ v0.AddArg(x)
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v.AddArg(a)
+ return true
+ }
+ // match: (MULA x (MOVWconst [c]) a)
+ // cond: isPowerOfTwo(c+1) && int32(c) >= 7
+ // result: (ADD (RSBshiftLL <x.Type> x x [log2(c+1)]) a)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_1.AuxInt
+ a := v.Args[2]
+ if !(isPowerOfTwo(c+1) && int32(c) >= 7) {
+ break
+ }
+ v.reset(OpARMADD)
+ v0 := b.NewValue0(v.Line, OpARMRSBshiftLL, x.Type)
+ v0.AuxInt = log2(c + 1)
+ v0.AddArg(x)
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v.AddArg(a)
+ return true
+ }
+ // match: (MULA x (MOVWconst [c]) a)
+ // 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 {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_1.AuxInt
+ a := v.Args[2]
+ if !(c%3 == 0 && isPowerOfTwo(c/3) && is32Bit(c)) {
+ break
+ }
+ v.reset(OpARMADD)
+ v0 := b.NewValue0(v.Line, OpARMSLLconst, x.Type)
+ v0.AuxInt = log2(c / 3)
+ v1 := b.NewValue0(v.Line, OpARMADDshiftLL, x.Type)
+ v1.AuxInt = 1
+ v1.AddArg(x)
+ v1.AddArg(x)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ v.AddArg(a)
+ return true
+ }
+ // match: (MULA x (MOVWconst [c]) a)
+ // 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 {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_1.AuxInt
+ a := v.Args[2]
+ if !(c%5 == 0 && isPowerOfTwo(c/5) && is32Bit(c)) {
+ break
+ }
+ v.reset(OpARMADD)
+ v0 := b.NewValue0(v.Line, OpARMSLLconst, x.Type)
+ v0.AuxInt = log2(c / 5)
+ v1 := b.NewValue0(v.Line, OpARMADDshiftLL, x.Type)
+ v1.AuxInt = 2
+ v1.AddArg(x)
+ v1.AddArg(x)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ v.AddArg(a)
+ return true
+ }
+ // match: (MULA x (MOVWconst [c]) a)
+ // 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 {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_1.AuxInt
+ a := v.Args[2]
+ if !(c%7 == 0 && isPowerOfTwo(c/7) && is32Bit(c)) {
+ break
+ }
+ v.reset(OpARMADD)
+ v0 := b.NewValue0(v.Line, OpARMSLLconst, x.Type)
+ v0.AuxInt = log2(c / 7)
+ v1 := b.NewValue0(v.Line, OpARMRSBshiftLL, x.Type)
+ v1.AuxInt = 3
+ v1.AddArg(x)
+ v1.AddArg(x)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ v.AddArg(a)
+ return true
+ }
+ // match: (MULA x (MOVWconst [c]) a)
+ // 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 {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_1.AuxInt
+ a := v.Args[2]
+ if !(c%9 == 0 && isPowerOfTwo(c/9) && is32Bit(c)) {
+ break
+ }
+ v.reset(OpARMADD)
+ v0 := b.NewValue0(v.Line, OpARMSLLconst, x.Type)
+ v0.AuxInt = log2(c / 9)
+ v1 := b.NewValue0(v.Line, OpARMADDshiftLL, x.Type)
+ v1.AuxInt = 3
+ v1.AddArg(x)
+ v1.AddArg(x)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ v.AddArg(a)
+ return true
+ }
+ // match: (MULA (MOVWconst [c]) x a)
+ // cond: int32(c) == -1
+ // result: (SUB a x)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ a := v.Args[2]
+ if !(int32(c) == -1) {
+ break
+ }
+ v.reset(OpARMSUB)
+ v.AddArg(a)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MULA (MOVWconst [0]) _ a)
+ // cond:
+ // result: a
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWconst {
+ break
+ }
+ if v_0.AuxInt != 0 {
+ break
+ }
+ a := v.Args[2]
+ v.reset(OpCopy)
+ v.Type = a.Type
+ v.AddArg(a)
+ return true
+ }
+ // match: (MULA (MOVWconst [1]) x a)
+ // cond:
+ // result: (ADD x a)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWconst {
+ break
+ }
+ if v_0.AuxInt != 1 {
+ break
+ }
+ x := v.Args[1]
+ a := v.Args[2]
+ v.reset(OpARMADD)
+ v.AddArg(x)
+ v.AddArg(a)
+ return true
+ }
+ // match: (MULA (MOVWconst [c]) x a)
+ // cond: isPowerOfTwo(c)
+ // result: (ADD (SLLconst <x.Type> [log2(c)] x) a)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ a := v.Args[2]
+ if !(isPowerOfTwo(c)) {
+ break
+ }
+ v.reset(OpARMADD)
+ v0 := b.NewValue0(v.Line, OpARMSLLconst, x.Type)
+ v0.AuxInt = log2(c)
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v.AddArg(a)
+ return true
+ }
+ // match: (MULA (MOVWconst [c]) x a)
+ // cond: isPowerOfTwo(c-1) && int32(c) >= 3
+ // result: (ADD (ADDshiftLL <x.Type> x x [log2(c-1)]) a)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ a := v.Args[2]
+ if !(isPowerOfTwo(c-1) && int32(c) >= 3) {
+ break
+ }
+ v.reset(OpARMADD)
+ v0 := b.NewValue0(v.Line, OpARMADDshiftLL, x.Type)
+ v0.AuxInt = log2(c - 1)
+ v0.AddArg(x)
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v.AddArg(a)
+ return true
+ }
+ // match: (MULA (MOVWconst [c]) x a)
+ // cond: isPowerOfTwo(c+1) && int32(c) >= 7
+ // result: (ADD (RSBshiftLL <x.Type> x x [log2(c+1)]) a)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ a := v.Args[2]
+ if !(isPowerOfTwo(c+1) && int32(c) >= 7) {
+ break
+ }
+ v.reset(OpARMADD)
+ v0 := b.NewValue0(v.Line, OpARMRSBshiftLL, x.Type)
+ v0.AuxInt = log2(c + 1)
+ v0.AddArg(x)
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v.AddArg(a)
+ return true
+ }
+ // match: (MULA (MOVWconst [c]) x a)
+ // 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_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ a := v.Args[2]
+ if !(c%3 == 0 && isPowerOfTwo(c/3) && is32Bit(c)) {
+ break
+ }
+ v.reset(OpARMADD)
+ v0 := b.NewValue0(v.Line, OpARMSLLconst, x.Type)
+ v0.AuxInt = log2(c / 3)
+ v1 := b.NewValue0(v.Line, OpARMADDshiftLL, x.Type)
+ v1.AuxInt = 1
+ v1.AddArg(x)
+ v1.AddArg(x)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ v.AddArg(a)
+ return true
+ }
+ // match: (MULA (MOVWconst [c]) x a)
+ // 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_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ a := v.Args[2]
+ if !(c%5 == 0 && isPowerOfTwo(c/5) && is32Bit(c)) {
+ break
+ }
+ v.reset(OpARMADD)
+ v0 := b.NewValue0(v.Line, OpARMSLLconst, x.Type)
+ v0.AuxInt = log2(c / 5)
+ v1 := b.NewValue0(v.Line, OpARMADDshiftLL, x.Type)
+ v1.AuxInt = 2
+ v1.AddArg(x)
+ v1.AddArg(x)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ v.AddArg(a)
+ return true
+ }
+ // match: (MULA (MOVWconst [c]) x a)
+ // 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_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ a := v.Args[2]
+ if !(c%7 == 0 && isPowerOfTwo(c/7) && is32Bit(c)) {
+ break
+ }
+ v.reset(OpARMADD)
+ v0 := b.NewValue0(v.Line, OpARMSLLconst, x.Type)
+ v0.AuxInt = log2(c / 7)
+ v1 := b.NewValue0(v.Line, OpARMRSBshiftLL, x.Type)
+ v1.AuxInt = 3
+ v1.AddArg(x)
+ v1.AddArg(x)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ v.AddArg(a)
+ return true
+ }
+ // match: (MULA (MOVWconst [c]) x a)
+ // 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_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ a := v.Args[2]
+ if !(c%9 == 0 && isPowerOfTwo(c/9) && is32Bit(c)) {
+ break
+ }
+ v.reset(OpARMADD)
+ v0 := b.NewValue0(v.Line, OpARMSLLconst, x.Type)
+ v0.AuxInt = log2(c / 9)
+ v1 := b.NewValue0(v.Line, OpARMADDshiftLL, x.Type)
+ v1.AuxInt = 3
+ v1.AddArg(x)
+ v1.AddArg(x)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ v.AddArg(a)
+ return true
+ }
+ // match: (MULA (MOVWconst [c]) (MOVWconst [d]) a)
+ // cond:
+ // result: (ADDconst [int64(int32(c*d))] a)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_0.AuxInt
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMMOVWconst {
+ break
+ }
+ d := v_1.AuxInt
+ a := v.Args[2]
+ v.reset(OpARMADDconst)
+ v.AuxInt = int64(int32(c * d))
+ v.AddArg(a)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMMVN(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (MVN (MOVWconst [c]))
+ // cond:
+ // result: (MOVWconst [^c])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_0.AuxInt
+ v.reset(OpARMMOVWconst)
+ v.AuxInt = ^c
+ return true
+ }
+ // match: (MVN (SLLconst [c] x))
+ // cond:
+ // result: (MVNshiftLL x [c])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMSLLconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v_0.Args[0]
+ v.reset(OpARMMVNshiftLL)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (MVN (SRLconst [c] x))
+ // cond:
+ // result: (MVNshiftRL x [c])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMSRLconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v_0.Args[0]
+ v.reset(OpARMMVNshiftRL)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (MVN (SRAconst [c] x))
+ // cond:
+ // result: (MVNshiftRA x [c])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMSRAconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v_0.Args[0]
+ v.reset(OpARMMVNshiftRA)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (MVN (SLL x y))
+ // cond:
+ // result: (MVNshiftLLreg x y)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMSLL {
+ break
+ }
+ x := v_0.Args[0]
+ y := v_0.Args[1]
+ v.reset(OpARMMVNshiftLLreg)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (MVN (SRL x y))
+ // cond:
+ // result: (MVNshiftRLreg x y)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMSRL {
+ break
+ }
+ x := v_0.Args[0]
+ y := v_0.Args[1]
+ v.reset(OpARMMVNshiftRLreg)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (MVN (SRA x y))
+ // cond:
+ // result: (MVNshiftRAreg x y)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMSRA {
+ break
+ }
+ x := v_0.Args[0]
+ y := v_0.Args[1]
+ v.reset(OpARMMVNshiftRAreg)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMMVNshiftLL(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (MVNshiftLL (MOVWconst [c]) [d])
+ // cond:
+ // result: (MOVWconst [^int64(uint32(c)<<uint64(d))])
+ for {
+ d := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_0.AuxInt
+ v.reset(OpARMMOVWconst)
+ v.AuxInt = ^int64(uint32(c) << uint64(d))
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMMVNshiftLLreg(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (MVNshiftLLreg x (MOVWconst [c]))
+ // cond:
+ // result: (MVNshiftLL x [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpARMMVNshiftLL)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMMVNshiftRA(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (MVNshiftRA (MOVWconst [c]) [d])
+ // cond:
+ // result: (MOVWconst [^int64(int32(c)>>uint64(d))])
+ for {
+ d := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_0.AuxInt
+ v.reset(OpARMMOVWconst)
+ v.AuxInt = ^int64(int32(c) >> uint64(d))
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMMVNshiftRAreg(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (MVNshiftRAreg x (MOVWconst [c]))
+ // cond:
+ // result: (MVNshiftRA x [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpARMMVNshiftRA)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMMVNshiftRL(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (MVNshiftRL (MOVWconst [c]) [d])
+ // cond:
+ // result: (MOVWconst [^int64(uint32(c)>>uint64(d))])
+ for {
+ d := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_0.AuxInt
+ v.reset(OpARMMOVWconst)
+ v.AuxInt = ^int64(uint32(c) >> uint64(d))
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMMVNshiftRLreg(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (MVNshiftRLreg x (MOVWconst [c]))
+ // cond:
+ // result: (MVNshiftRL x [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpARMMVNshiftRL)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMNotEqual(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (NotEqual (FlagEQ))
+ // cond:
+ // result: (MOVWconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMFlagEQ {
+ break
+ }
+ v.reset(OpARMMOVWconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (NotEqual (FlagLT_ULT))
+ // cond:
+ // result: (MOVWconst [1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMFlagLT_ULT {
+ break
+ }
+ v.reset(OpARMMOVWconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (NotEqual (FlagLT_UGT))
+ // cond:
+ // result: (MOVWconst [1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMFlagLT_UGT {
+ break
+ }
+ v.reset(OpARMMOVWconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (NotEqual (FlagGT_ULT))
+ // cond:
+ // result: (MOVWconst [1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMFlagGT_ULT {
+ break
+ }
+ v.reset(OpARMMOVWconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (NotEqual (FlagGT_UGT))
+ // cond:
+ // result: (MOVWconst [1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMFlagGT_UGT {
+ break
+ }
+ v.reset(OpARMMOVWconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (NotEqual (InvertFlags x))
+ // cond:
+ // result: (NotEqual x)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMInvertFlags {
+ break
+ }
+ x := v_0.Args[0]
+ v.reset(OpARMNotEqual)
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMOR(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (OR (MOVWconst [c]) x)
+ // cond:
+ // result: (ORconst [c] x)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ v.reset(OpARMORconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (OR x (MOVWconst [c]))
+ // cond:
+ // result: (ORconst [c] x)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpARMORconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (OR x (SLLconst [c] y))
+ // cond:
+ // result: (ORshiftLL x y [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMSLLconst {
+ break
+ }
+ c := v_1.AuxInt
+ y := v_1.Args[0]
+ v.reset(OpARMORshiftLL)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (OR (SLLconst [c] y) x)
+ // cond:
+ // result: (ORshiftLL x y [c])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMSLLconst {
+ break
+ }
+ c := v_0.AuxInt
+ y := v_0.Args[0]
+ x := v.Args[1]
+ v.reset(OpARMORshiftLL)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (OR x (SRLconst [c] y))
+ // cond:
+ // result: (ORshiftRL x y [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMSRLconst {
+ break
+ }
+ c := v_1.AuxInt
+ y := v_1.Args[0]
+ v.reset(OpARMORshiftRL)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (OR (SRLconst [c] y) x)
+ // cond:
+ // result: (ORshiftRL x y [c])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMSRLconst {
+ break
+ }
+ c := v_0.AuxInt
+ y := v_0.Args[0]
+ x := v.Args[1]
+ v.reset(OpARMORshiftRL)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (OR x (SRAconst [c] y))
+ // cond:
+ // result: (ORshiftRA x y [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMSRAconst {
+ break
+ }
+ c := v_1.AuxInt
+ y := v_1.Args[0]
+ v.reset(OpARMORshiftRA)
+ 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 != OpARMSRAconst {
+ break
+ }
+ c := v_0.AuxInt
+ y := v_0.Args[0]
+ x := v.Args[1]
+ v.reset(OpARMORshiftRA)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (OR x (SLL y z))
+ // cond:
+ // result: (ORshiftLLreg x y z)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMSLL {
+ break
+ }
+ y := v_1.Args[0]
+ z := v_1.Args[1]
+ v.reset(OpARMORshiftLLreg)
+ v.AddArg(x)
+ v.AddArg(y)
+ v.AddArg(z)
+ return true
+ }
+ // match: (OR (SLL y z) x)
+ // cond:
+ // result: (ORshiftLLreg x y z)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMSLL {
+ break
+ }
+ y := v_0.Args[0]
+ z := v_0.Args[1]
+ x := v.Args[1]
+ v.reset(OpARMORshiftLLreg)
+ v.AddArg(x)
+ v.AddArg(y)
+ v.AddArg(z)
+ return true
+ }
+ // match: (OR x (SRL y z))
+ // cond:
+ // result: (ORshiftRLreg x y z)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMSRL {
+ break
+ }
+ y := v_1.Args[0]
+ z := v_1.Args[1]
+ v.reset(OpARMORshiftRLreg)
+ v.AddArg(x)
+ v.AddArg(y)
+ v.AddArg(z)
+ return true
+ }
+ // match: (OR (SRL y z) x)
+ // cond:
+ // result: (ORshiftRLreg x y z)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMSRL {
+ break
+ }
+ y := v_0.Args[0]
+ z := v_0.Args[1]
+ x := v.Args[1]
+ v.reset(OpARMORshiftRLreg)
+ v.AddArg(x)
+ v.AddArg(y)
+ v.AddArg(z)
+ return true
+ }
+ // match: (OR x (SRA y z))
+ // cond:
+ // result: (ORshiftRAreg x y z)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMSRA {
+ break
+ }
+ y := v_1.Args[0]
+ z := v_1.Args[1]
+ v.reset(OpARMORshiftRAreg)
+ v.AddArg(x)
+ v.AddArg(y)
+ v.AddArg(z)
+ return true
+ }
+ // match: (OR (SRA y z) x)
+ // cond:
+ // result: (ORshiftRAreg x y z)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMSRA {
+ break
+ }
+ y := v_0.Args[0]
+ z := v_0.Args[1]
+ x := v.Args[1]
+ v.reset(OpARMORshiftRAreg)
+ v.AddArg(x)
+ v.AddArg(y)
+ v.AddArg(z)
+ return true
+ }
+ // match: (OR x x)
+ // cond:
+ // result: x
+ for {
+ x := v.Args[0]
+ if x != v.Args[1] {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMORconst(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ORconst [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: (ORconst [c] _)
+ // cond: int32(c)==-1
+ // result: (MOVWconst [-1])
+ for {
+ c := v.AuxInt
+ if !(int32(c) == -1) {
+ break
+ }
+ v.reset(OpARMMOVWconst)
+ v.AuxInt = -1
+ return true
+ }
+ // match: (ORconst [c] (MOVWconst [d]))
+ // cond:
+ // result: (MOVWconst [c|d])
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWconst {
+ break
+ }
+ d := v_0.AuxInt
+ v.reset(OpARMMOVWconst)
+ v.AuxInt = c | d
+ return true
+ }
+ // match: (ORconst [c] (ORconst [d] x))
+ // cond:
+ // result: (ORconst [c|d] x)
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMORconst {
+ break
+ }
+ d := v_0.AuxInt
+ x := v_0.Args[0]
+ v.reset(OpARMORconst)
+ v.AuxInt = c | d
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMORshiftLL(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ORshiftLL (MOVWconst [c]) x [d])
+ // cond:
+ // result: (ORconst [c] (SLLconst <x.Type> x [d]))
+ for {
+ d := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ v.reset(OpARMORconst)
+ v.AuxInt = c
+ v0 := b.NewValue0(v.Line, OpARMSLLconst, x.Type)
+ v0.AuxInt = d
+ v0.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (ORshiftLL x (MOVWconst [c]) [d])
+ // cond:
+ // result: (ORconst x [int64(uint32(c)<<uint64(d))])
+ for {
+ d := v.AuxInt
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpARMORconst)
+ v.AuxInt = int64(uint32(c) << uint64(d))
+ v.AddArg(x)
+ return true
+ }
+ // match: (ORshiftLL x y:(SLLconst x [c]) [d])
+ // cond: c==d
+ // result: y
+ for {
+ d := v.AuxInt
+ x := v.Args[0]
+ y := v.Args[1]
+ if y.Op != OpARMSLLconst {
+ break
+ }
+ c := y.AuxInt
+ if x != y.Args[0] {
+ break
+ }
+ if !(c == d) {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = y.Type
+ v.AddArg(y)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMORshiftLLreg(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ORshiftLLreg (MOVWconst [c]) x y)
+ // cond:
+ // result: (ORconst [c] (SLL <x.Type> x y))
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ y := v.Args[2]
+ v.reset(OpARMORconst)
+ v.AuxInt = c
+ v0 := b.NewValue0(v.Line, OpARMSLL, x.Type)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (ORshiftLLreg x y (MOVWconst [c]))
+ // cond:
+ // result: (ORshiftLL x y [c])
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v_2 := v.Args[2]
+ if v_2.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_2.AuxInt
+ v.reset(OpARMORshiftLL)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMORshiftRA(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ORshiftRA (MOVWconst [c]) x [d])
+ // cond:
+ // result: (ORconst [c] (SRAconst <x.Type> x [d]))
+ for {
+ d := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ v.reset(OpARMORconst)
+ v.AuxInt = c
+ v0 := b.NewValue0(v.Line, OpARMSRAconst, x.Type)
+ v0.AuxInt = d
+ v0.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (ORshiftRA x (MOVWconst [c]) [d])
+ // cond:
+ // result: (ORconst x [int64(int32(c)>>uint64(d))])
+ for {
+ d := v.AuxInt
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpARMORconst)
+ v.AuxInt = int64(int32(c) >> uint64(d))
+ v.AddArg(x)
+ return true
+ }
+ // match: (ORshiftRA x y:(SRAconst x [c]) [d])
+ // cond: c==d
+ // result: y
+ for {
+ d := v.AuxInt
+ x := v.Args[0]
+ y := v.Args[1]
+ if y.Op != OpARMSRAconst {
+ break
+ }
+ c := y.AuxInt
+ if x != y.Args[0] {
+ break
+ }
+ if !(c == d) {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = y.Type
+ v.AddArg(y)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMORshiftRAreg(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ORshiftRAreg (MOVWconst [c]) x y)
+ // cond:
+ // result: (ORconst [c] (SRA <x.Type> x y))
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ y := v.Args[2]
+ v.reset(OpARMORconst)
+ v.AuxInt = c
+ v0 := b.NewValue0(v.Line, OpARMSRA, x.Type)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (ORshiftRAreg x y (MOVWconst [c]))
+ // cond:
+ // result: (ORshiftRA x y [c])
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v_2 := v.Args[2]
+ if v_2.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_2.AuxInt
+ v.reset(OpARMORshiftRA)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMORshiftRL(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ORshiftRL (MOVWconst [c]) x [d])
+ // cond:
+ // result: (ORconst [c] (SRLconst <x.Type> x [d]))
+ for {
+ d := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ v.reset(OpARMORconst)
+ v.AuxInt = c
+ v0 := b.NewValue0(v.Line, OpARMSRLconst, x.Type)
+ v0.AuxInt = d
+ v0.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (ORshiftRL x (MOVWconst [c]) [d])
+ // cond:
+ // result: (ORconst x [int64(uint32(c)>>uint64(d))])
+ for {
+ d := v.AuxInt
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpARMORconst)
+ v.AuxInt = int64(uint32(c) >> uint64(d))
+ v.AddArg(x)
+ return true
+ }
+ // match: (ORshiftRL x y:(SRLconst x [c]) [d])
+ // cond: c==d
+ // result: y
+ for {
+ d := v.AuxInt
+ x := v.Args[0]
+ y := v.Args[1]
+ if y.Op != OpARMSRLconst {
+ break
+ }
+ c := y.AuxInt
+ if x != y.Args[0] {
+ break
+ }
+ if !(c == d) {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = y.Type
+ v.AddArg(y)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMORshiftRLreg(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ORshiftRLreg (MOVWconst [c]) x y)
+ // cond:
+ // result: (ORconst [c] (SRL <x.Type> x y))
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ y := v.Args[2]
+ v.reset(OpARMORconst)
+ v.AuxInt = c
+ v0 := b.NewValue0(v.Line, OpARMSRL, x.Type)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (ORshiftRLreg x y (MOVWconst [c]))
+ // cond:
+ // result: (ORshiftRL x y [c])
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v_2 := v.Args[2]
+ if v_2.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_2.AuxInt
+ v.reset(OpARMORshiftRL)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMRSB(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (RSB (MOVWconst [c]) x)
+ // cond:
+ // result: (SUBconst [c] x)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ v.reset(OpARMSUBconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (RSB x (MOVWconst [c]))
+ // cond:
+ // result: (RSBconst [c] x)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpARMRSBconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (RSB x (SLLconst [c] y))
+ // cond:
+ // result: (RSBshiftLL x y [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMSLLconst {
+ break
+ }
+ c := v_1.AuxInt
+ y := v_1.Args[0]
+ v.reset(OpARMRSBshiftLL)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (RSB (SLLconst [c] y) x)
+ // cond:
+ // result: (SUBshiftLL x y [c])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMSLLconst {
+ break
+ }
+ c := v_0.AuxInt
+ y := v_0.Args[0]
+ x := v.Args[1]
+ v.reset(OpARMSUBshiftLL)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (RSB x (SRLconst [c] y))
+ // cond:
+ // result: (RSBshiftRL x y [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMSRLconst {
+ break
+ }
+ c := v_1.AuxInt
+ y := v_1.Args[0]
+ v.reset(OpARMRSBshiftRL)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (RSB (SRLconst [c] y) x)
+ // cond:
+ // result: (SUBshiftRL x y [c])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMSRLconst {
+ break
+ }
+ c := v_0.AuxInt
+ y := v_0.Args[0]
+ x := v.Args[1]
+ v.reset(OpARMSUBshiftRL)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (RSB x (SRAconst [c] y))
+ // cond:
+ // result: (RSBshiftRA x y [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMSRAconst {
+ break
+ }
+ c := v_1.AuxInt
+ y := v_1.Args[0]
+ v.reset(OpARMRSBshiftRA)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (RSB (SRAconst [c] y) x)
+ // cond:
+ // result: (SUBshiftRA x y [c])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMSRAconst {
+ break
+ }
+ c := v_0.AuxInt
+ y := v_0.Args[0]
+ x := v.Args[1]
+ v.reset(OpARMSUBshiftRA)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (RSB x (SLL y z))
+ // cond:
+ // result: (RSBshiftLLreg x y z)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMSLL {
+ break
+ }
+ y := v_1.Args[0]
+ z := v_1.Args[1]
+ v.reset(OpARMRSBshiftLLreg)
+ v.AddArg(x)
+ v.AddArg(y)
+ v.AddArg(z)
+ return true
+ }
+ // match: (RSB (SLL y z) x)
+ // cond:
+ // result: (SUBshiftLLreg x y z)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMSLL {
+ break
+ }
+ y := v_0.Args[0]
+ z := v_0.Args[1]
+ x := v.Args[1]
+ v.reset(OpARMSUBshiftLLreg)
+ v.AddArg(x)
+ v.AddArg(y)
+ v.AddArg(z)
+ return true
+ }
+ // match: (RSB x (SRL y z))
+ // cond:
+ // result: (RSBshiftRLreg x y z)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMSRL {
+ break
+ }
+ y := v_1.Args[0]
+ z := v_1.Args[1]
+ v.reset(OpARMRSBshiftRLreg)
+ v.AddArg(x)
+ v.AddArg(y)
+ v.AddArg(z)
+ return true
+ }
+ // match: (RSB (SRL y z) x)
+ // cond:
+ // result: (SUBshiftRLreg x y z)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMSRL {
+ break
+ }
+ y := v_0.Args[0]
+ z := v_0.Args[1]
+ x := v.Args[1]
+ v.reset(OpARMSUBshiftRLreg)
+ v.AddArg(x)
+ v.AddArg(y)
+ v.AddArg(z)
+ return true
+ }
+ // match: (RSB x (SRA y z))
+ // cond:
+ // result: (RSBshiftRAreg x y z)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMSRA {
+ break
+ }
+ y := v_1.Args[0]
+ z := v_1.Args[1]
+ v.reset(OpARMRSBshiftRAreg)
+ v.AddArg(x)
+ v.AddArg(y)
+ v.AddArg(z)
+ return true
+ }
+ // match: (RSB (SRA y z) x)
+ // cond:
+ // result: (SUBshiftRAreg x y z)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMSRA {
+ break
+ }
+ y := v_0.Args[0]
+ z := v_0.Args[1]
+ x := v.Args[1]
+ v.reset(OpARMSUBshiftRAreg)
+ v.AddArg(x)
+ v.AddArg(y)
+ v.AddArg(z)
+ return true
+ }
+ // match: (RSB x x)
+ // cond:
+ // result: (MOVWconst [0])
+ for {
+ x := v.Args[0]
+ if x != v.Args[1] {
+ break
+ }
+ v.reset(OpARMMOVWconst)
+ v.AuxInt = 0
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMRSBSshiftLL(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (RSBSshiftLL (MOVWconst [c]) x [d])
+ // cond:
+ // result: (SUBSconst [c] (SLLconst <x.Type> x [d]))
+ for {
+ d := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ v.reset(OpARMSUBSconst)
+ v.AuxInt = c
+ v0 := b.NewValue0(v.Line, OpARMSLLconst, x.Type)
+ v0.AuxInt = d
+ v0.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (RSBSshiftLL x (MOVWconst [c]) [d])
+ // cond:
+ // result: (RSBSconst x [int64(uint32(c)<<uint64(d))])
+ for {
+ d := v.AuxInt
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpARMRSBSconst)
+ v.AuxInt = int64(uint32(c) << uint64(d))
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMRSBSshiftLLreg(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (RSBSshiftLLreg (MOVWconst [c]) x y)
+ // cond:
+ // result: (SUBSconst [c] (SLL <x.Type> x y))
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ y := v.Args[2]
+ v.reset(OpARMSUBSconst)
+ v.AuxInt = c
+ v0 := b.NewValue0(v.Line, OpARMSLL, x.Type)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (RSBSshiftLLreg x y (MOVWconst [c]))
+ // cond:
+ // result: (RSBSshiftLL x y [c])
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v_2 := v.Args[2]
+ if v_2.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_2.AuxInt
+ v.reset(OpARMRSBSshiftLL)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMRSBSshiftRA(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (RSBSshiftRA (MOVWconst [c]) x [d])
+ // cond:
+ // result: (SUBSconst [c] (SRAconst <x.Type> x [d]))
+ for {
+ d := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ v.reset(OpARMSUBSconst)
+ v.AuxInt = c
+ v0 := b.NewValue0(v.Line, OpARMSRAconst, x.Type)
+ v0.AuxInt = d
+ v0.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (RSBSshiftRA x (MOVWconst [c]) [d])
+ // cond:
+ // result: (RSBSconst x [int64(int32(c)>>uint64(d))])
+ for {
+ d := v.AuxInt
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpARMRSBSconst)
+ v.AuxInt = int64(int32(c) >> uint64(d))
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMRSBSshiftRAreg(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (RSBSshiftRAreg (MOVWconst [c]) x y)
+ // cond:
+ // result: (SUBSconst [c] (SRA <x.Type> x y))
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ y := v.Args[2]
+ v.reset(OpARMSUBSconst)
+ v.AuxInt = c
+ v0 := b.NewValue0(v.Line, OpARMSRA, x.Type)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (RSBSshiftRAreg x y (MOVWconst [c]))
+ // cond:
+ // result: (RSBSshiftRA x y [c])
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v_2 := v.Args[2]
+ if v_2.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_2.AuxInt
+ v.reset(OpARMRSBSshiftRA)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMRSBSshiftRL(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (RSBSshiftRL (MOVWconst [c]) x [d])
+ // cond:
+ // result: (SUBSconst [c] (SRLconst <x.Type> x [d]))
+ for {
+ d := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ v.reset(OpARMSUBSconst)
+ v.AuxInt = c
+ v0 := b.NewValue0(v.Line, OpARMSRLconst, x.Type)
+ v0.AuxInt = d
+ v0.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (RSBSshiftRL x (MOVWconst [c]) [d])
+ // cond:
+ // result: (RSBSconst x [int64(uint32(c)>>uint64(d))])
+ for {
+ d := v.AuxInt
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpARMRSBSconst)
+ v.AuxInt = int64(uint32(c) >> uint64(d))
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMRSBSshiftRLreg(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (RSBSshiftRLreg (MOVWconst [c]) x y)
+ // cond:
+ // result: (SUBSconst [c] (SRL <x.Type> x y))
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ y := v.Args[2]
+ v.reset(OpARMSUBSconst)
+ v.AuxInt = c
+ v0 := b.NewValue0(v.Line, OpARMSRL, x.Type)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (RSBSshiftRLreg x y (MOVWconst [c]))
+ // cond:
+ // result: (RSBSshiftRL x y [c])
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v_2 := v.Args[2]
+ if v_2.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_2.AuxInt
+ v.reset(OpARMRSBSshiftRL)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMRSBconst(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (RSBconst [c] (MOVWconst [d]))
+ // cond:
+ // result: (MOVWconst [int64(int32(c-d))])
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWconst {
+ break
+ }
+ d := v_0.AuxInt
+ v.reset(OpARMMOVWconst)
+ v.AuxInt = int64(int32(c - d))
+ return true
+ }
+ // match: (RSBconst [c] (RSBconst [d] x))
+ // cond:
+ // result: (ADDconst [int64(int32(c-d))] x)
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMRSBconst {
+ break
+ }
+ d := v_0.AuxInt
+ x := v_0.Args[0]
+ v.reset(OpARMADDconst)
+ v.AuxInt = int64(int32(c - d))
+ v.AddArg(x)
+ return true
+ }
+ // match: (RSBconst [c] (ADDconst [d] x))
+ // cond:
+ // result: (RSBconst [int64(int32(c-d))] x)
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMADDconst {
+ break
+ }
+ d := v_0.AuxInt
+ x := v_0.Args[0]
+ v.reset(OpARMRSBconst)
+ v.AuxInt = int64(int32(c - d))
+ v.AddArg(x)
+ return true
+ }
+ // match: (RSBconst [c] (SUBconst [d] x))
+ // cond:
+ // result: (RSBconst [int64(int32(c+d))] x)
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMSUBconst {
+ break
+ }
+ d := v_0.AuxInt
+ x := v_0.Args[0]
+ v.reset(OpARMRSBconst)
+ v.AuxInt = int64(int32(c + d))
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMRSBshiftLL(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (RSBshiftLL (MOVWconst [c]) x [d])
+ // cond:
+ // result: (SUBconst [c] (SLLconst <x.Type> x [d]))
+ for {
+ d := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ v.reset(OpARMSUBconst)
+ v.AuxInt = c
+ v0 := b.NewValue0(v.Line, OpARMSLLconst, x.Type)
+ v0.AuxInt = d
+ v0.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (RSBshiftLL x (MOVWconst [c]) [d])
+ // cond:
+ // result: (RSBconst x [int64(uint32(c)<<uint64(d))])
+ for {
+ d := v.AuxInt
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpARMRSBconst)
+ v.AuxInt = int64(uint32(c) << uint64(d))
+ v.AddArg(x)
+ return true
+ }
+ // match: (RSBshiftLL x (SLLconst x [c]) [d])
+ // cond: c==d
+ // result: (MOVWconst [0])
+ for {
+ d := v.AuxInt
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMSLLconst {
+ break
+ }
+ c := v_1.AuxInt
+ if x != v_1.Args[0] {
+ break
+ }
+ if !(c == d) {
+ break
+ }
+ v.reset(OpARMMOVWconst)
+ v.AuxInt = 0
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMRSBshiftLLreg(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (RSBshiftLLreg (MOVWconst [c]) x y)
+ // cond:
+ // result: (SUBconst [c] (SLL <x.Type> x y))
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ y := v.Args[2]
+ v.reset(OpARMSUBconst)
+ v.AuxInt = c
+ v0 := b.NewValue0(v.Line, OpARMSLL, x.Type)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (RSBshiftLLreg x y (MOVWconst [c]))
+ // cond:
+ // result: (RSBshiftLL x y [c])
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v_2 := v.Args[2]
+ if v_2.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_2.AuxInt
+ v.reset(OpARMRSBshiftLL)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMRSBshiftRA(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (RSBshiftRA (MOVWconst [c]) x [d])
+ // cond:
+ // result: (SUBconst [c] (SRAconst <x.Type> x [d]))
+ for {
+ d := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ v.reset(OpARMSUBconst)
+ v.AuxInt = c
+ v0 := b.NewValue0(v.Line, OpARMSRAconst, x.Type)
+ v0.AuxInt = d
+ v0.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (RSBshiftRA x (MOVWconst [c]) [d])
+ // cond:
+ // result: (RSBconst x [int64(int32(c)>>uint64(d))])
+ for {
+ d := v.AuxInt
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpARMRSBconst)
+ v.AuxInt = int64(int32(c) >> uint64(d))
+ v.AddArg(x)
+ return true
+ }
+ // match: (RSBshiftRA x (SRAconst x [c]) [d])
+ // cond: c==d
+ // result: (MOVWconst [0])
+ for {
+ d := v.AuxInt
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMSRAconst {
+ break
+ }
+ c := v_1.AuxInt
+ if x != v_1.Args[0] {
+ break
+ }
+ if !(c == d) {
+ break
+ }
+ v.reset(OpARMMOVWconst)
+ v.AuxInt = 0
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMRSBshiftRAreg(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (RSBshiftRAreg (MOVWconst [c]) x y)
+ // cond:
+ // result: (SUBconst [c] (SRA <x.Type> x y))
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ y := v.Args[2]
+ v.reset(OpARMSUBconst)
+ v.AuxInt = c
+ v0 := b.NewValue0(v.Line, OpARMSRA, x.Type)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (RSBshiftRAreg x y (MOVWconst [c]))
+ // cond:
+ // result: (RSBshiftRA x y [c])
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v_2 := v.Args[2]
+ if v_2.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_2.AuxInt
+ v.reset(OpARMRSBshiftRA)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMRSBshiftRL(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (RSBshiftRL (MOVWconst [c]) x [d])
+ // cond:
+ // result: (SUBconst [c] (SRLconst <x.Type> x [d]))
+ for {
+ d := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ v.reset(OpARMSUBconst)
+ v.AuxInt = c
+ v0 := b.NewValue0(v.Line, OpARMSRLconst, x.Type)
+ v0.AuxInt = d
+ v0.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (RSBshiftRL x (MOVWconst [c]) [d])
+ // cond:
+ // result: (RSBconst x [int64(uint32(c)>>uint64(d))])
+ for {
+ d := v.AuxInt
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpARMRSBconst)
+ v.AuxInt = int64(uint32(c) >> uint64(d))
+ v.AddArg(x)
+ return true
+ }
+ // match: (RSBshiftRL x (SRLconst x [c]) [d])
+ // cond: c==d
+ // result: (MOVWconst [0])
+ for {
+ d := v.AuxInt
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMSRLconst {
+ break
+ }
+ c := v_1.AuxInt
+ if x != v_1.Args[0] {
+ break
+ }
+ if !(c == d) {
+ break
+ }
+ v.reset(OpARMMOVWconst)
+ v.AuxInt = 0
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMRSBshiftRLreg(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (RSBshiftRLreg (MOVWconst [c]) x y)
+ // cond:
+ // result: (SUBconst [c] (SRL <x.Type> x y))
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ y := v.Args[2]
+ v.reset(OpARMSUBconst)
+ v.AuxInt = c
+ v0 := b.NewValue0(v.Line, OpARMSRL, x.Type)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (RSBshiftRLreg x y (MOVWconst [c]))
+ // cond:
+ // result: (RSBshiftRL x y [c])
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v_2 := v.Args[2]
+ if v_2.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_2.AuxInt
+ v.reset(OpARMRSBshiftRL)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMRSCconst(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (RSCconst [c] (ADDconst [d] x) flags)
+ // cond:
+ // result: (RSCconst [int64(int32(c-d))] x flags)
+ for {
+ c := v.AuxInt
+ 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(OpARMRSCconst)
+ v.AuxInt = int64(int32(c - d))
+ v.AddArg(x)
+ v.AddArg(flags)
+ return true
+ }
+ // match: (RSCconst [c] (SUBconst [d] x) flags)
+ // cond:
+ // result: (RSCconst [int64(int32(c+d))] x flags)
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMSUBconst {
+ break
+ }
+ d := v_0.AuxInt
+ x := v_0.Args[0]
+ flags := v.Args[1]
+ v.reset(OpARMRSCconst)
+ v.AuxInt = int64(int32(c + d))
+ v.AddArg(x)
+ v.AddArg(flags)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMRSCshiftLL(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (RSCshiftLL (MOVWconst [c]) x [d] flags)
+ // cond:
+ // result: (SBCconst [c] (SLLconst <x.Type> x [d]) flags)
+ for {
+ d := v.AuxInt
+ 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(OpARMSBCconst)
+ v.AuxInt = c
+ v0 := b.NewValue0(v.Line, OpARMSLLconst, x.Type)
+ v0.AuxInt = d
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v.AddArg(flags)
+ return true
+ }
+ // match: (RSCshiftLL x (MOVWconst [c]) [d] flags)
+ // cond:
+ // result: (RSCconst x [int64(uint32(c)<<uint64(d))] flags)
+ for {
+ d := v.AuxInt
+ 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(OpARMRSCconst)
+ v.AuxInt = int64(uint32(c) << uint64(d))
+ v.AddArg(x)
+ v.AddArg(flags)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMRSCshiftLLreg(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (RSCshiftLLreg (MOVWconst [c]) x y flags)
+ // cond:
+ // result: (SBCconst [c] (SLL <x.Type> x y) flags)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ y := v.Args[2]
+ flags := v.Args[3]
+ v.reset(OpARMSBCconst)
+ v.AuxInt = c
+ v0 := b.NewValue0(v.Line, OpARMSLL, x.Type)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ v.AddArg(flags)
+ return true
+ }
+ // match: (RSCshiftLLreg x y (MOVWconst [c]) flags)
+ // cond:
+ // result: (RSCshiftLL x y [c] flags)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v_2 := v.Args[2]
+ if v_2.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_2.AuxInt
+ flags := v.Args[3]
+ v.reset(OpARMRSCshiftLL)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ v.AddArg(flags)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMRSCshiftRA(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (RSCshiftRA (MOVWconst [c]) x [d] flags)
+ // cond:
+ // result: (SBCconst [c] (SRAconst <x.Type> x [d]) flags)
+ for {
+ d := v.AuxInt
+ 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(OpARMSBCconst)
+ v.AuxInt = c
+ v0 := b.NewValue0(v.Line, OpARMSRAconst, x.Type)
+ v0.AuxInt = d
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v.AddArg(flags)
+ return true
+ }
+ // match: (RSCshiftRA x (MOVWconst [c]) [d] flags)
+ // cond:
+ // result: (RSCconst x [int64(int32(c)>>uint64(d))] flags)
+ for {
+ d := v.AuxInt
+ 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(OpARMRSCconst)
+ v.AuxInt = int64(int32(c) >> uint64(d))
+ v.AddArg(x)
+ v.AddArg(flags)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMRSCshiftRAreg(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (RSCshiftRAreg (MOVWconst [c]) x y flags)
+ // cond:
+ // result: (SBCconst [c] (SRA <x.Type> x y) flags)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ y := v.Args[2]
+ flags := v.Args[3]
+ v.reset(OpARMSBCconst)
+ v.AuxInt = c
+ v0 := b.NewValue0(v.Line, OpARMSRA, x.Type)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ v.AddArg(flags)
+ return true
+ }
+ // match: (RSCshiftRAreg x y (MOVWconst [c]) flags)
+ // cond:
+ // result: (RSCshiftRA x y [c] flags)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v_2 := v.Args[2]
+ if v_2.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_2.AuxInt
+ flags := v.Args[3]
+ v.reset(OpARMRSCshiftRA)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ v.AddArg(flags)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMRSCshiftRL(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (RSCshiftRL (MOVWconst [c]) x [d] flags)
+ // cond:
+ // result: (SBCconst [c] (SRLconst <x.Type> x [d]) flags)
+ for {
+ d := v.AuxInt
+ 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(OpARMSBCconst)
+ v.AuxInt = c
+ v0 := b.NewValue0(v.Line, OpARMSRLconst, x.Type)
+ v0.AuxInt = d
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v.AddArg(flags)
+ return true
+ }
+ // match: (RSCshiftRL x (MOVWconst [c]) [d] flags)
+ // cond:
+ // result: (RSCconst x [int64(uint32(c)>>uint64(d))] flags)
+ for {
+ d := v.AuxInt
+ 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(OpARMRSCconst)
+ v.AuxInt = int64(uint32(c) >> uint64(d))
+ v.AddArg(x)
+ v.AddArg(flags)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMRSCshiftRLreg(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (RSCshiftRLreg (MOVWconst [c]) x y flags)
+ // cond:
+ // result: (SBCconst [c] (SRL <x.Type> x y) flags)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ y := v.Args[2]
+ flags := v.Args[3]
+ v.reset(OpARMSBCconst)
+ v.AuxInt = c
+ v0 := b.NewValue0(v.Line, OpARMSRL, x.Type)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ v.AddArg(flags)
+ return true
+ }
+ // match: (RSCshiftRLreg x y (MOVWconst [c]) flags)
+ // cond:
+ // result: (RSCshiftRL x y [c] flags)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v_2 := v.Args[2]
+ if v_2.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_2.AuxInt
+ flags := v.Args[3]
+ v.reset(OpARMRSCshiftRL)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ v.AddArg(flags)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMSBC(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SBC (MOVWconst [c]) x flags)
+ // cond:
+ // result: (RSCconst [c] x flags)
+ for {
+ 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(OpARMRSCconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(flags)
+ return true
+ }
+ // match: (SBC x (MOVWconst [c]) flags)
+ // cond:
+ // result: (SBCconst [c] x flags)
+ for {
+ 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(OpARMSBCconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(flags)
+ return true
+ }
+ // match: (SBC x (SLLconst [c] y) flags)
+ // cond:
+ // result: (SBCshiftLL x y [c] flags)
+ for {
+ 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(OpARMSBCshiftLL)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ v.AddArg(flags)
+ return true
+ }
+ // match: (SBC (SLLconst [c] y) x flags)
+ // cond:
+ // result: (RSCshiftLL x y [c] flags)
+ for {
+ 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(OpARMRSCshiftLL)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ v.AddArg(flags)
+ return true
+ }
+ // match: (SBC x (SRLconst [c] y) flags)
+ // cond:
+ // result: (SBCshiftRL x y [c] flags)
+ for {
+ 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(OpARMSBCshiftRL)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ v.AddArg(flags)
+ return true
+ }
+ // match: (SBC (SRLconst [c] y) x flags)
+ // cond:
+ // result: (RSCshiftRL x y [c] flags)
+ for {
+ 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(OpARMRSCshiftRL)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ v.AddArg(flags)
+ return true
+ }
+ // match: (SBC x (SRAconst [c] y) flags)
+ // cond:
+ // result: (SBCshiftRA x y [c] flags)
+ for {
+ 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(OpARMSBCshiftRA)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ v.AddArg(flags)
+ return true
+ }
+ // match: (SBC (SRAconst [c] y) x flags)
+ // cond:
+ // result: (RSCshiftRA x y [c] flags)
+ for {
+ 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(OpARMRSCshiftRA)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ v.AddArg(flags)
+ return true
+ }
+ // match: (SBC x (SLL y z) flags)
+ // cond:
+ // result: (SBCshiftLLreg x y z flags)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMSLL {
+ break
+ }
+ y := v_1.Args[0]
+ z := v_1.Args[1]
+ flags := v.Args[2]
+ v.reset(OpARMSBCshiftLLreg)
+ v.AddArg(x)
+ v.AddArg(y)
+ v.AddArg(z)
+ v.AddArg(flags)
+ return true
+ }
+ // match: (SBC (SLL y z) x flags)
+ // cond:
+ // result: (RSCshiftLLreg x y z flags)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMSLL {
+ break
+ }
+ y := v_0.Args[0]
+ z := v_0.Args[1]
+ x := v.Args[1]
+ flags := v.Args[2]
+ v.reset(OpARMRSCshiftLLreg)
+ v.AddArg(x)
+ v.AddArg(y)
+ v.AddArg(z)
+ v.AddArg(flags)
+ return true
+ }
+ // match: (SBC x (SRL y z) flags)
+ // cond:
+ // result: (SBCshiftRLreg x y z flags)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMSRL {
+ break
+ }
+ y := v_1.Args[0]
+ z := v_1.Args[1]
+ flags := v.Args[2]
+ v.reset(OpARMSBCshiftRLreg)
+ v.AddArg(x)
+ v.AddArg(y)
+ v.AddArg(z)
+ v.AddArg(flags)
+ return true
+ }
+ // match: (SBC (SRL y z) x flags)
+ // cond:
+ // result: (RSCshiftRLreg x y z flags)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMSRL {
+ break
+ }
+ y := v_0.Args[0]
+ z := v_0.Args[1]
+ x := v.Args[1]
+ flags := v.Args[2]
+ v.reset(OpARMRSCshiftRLreg)
+ v.AddArg(x)
+ v.AddArg(y)
+ v.AddArg(z)
+ v.AddArg(flags)
+ return true
+ }
+ // match: (SBC x (SRA y z) flags)
+ // cond:
+ // result: (SBCshiftRAreg x y z flags)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMSRA {
+ break
+ }
+ y := v_1.Args[0]
+ z := v_1.Args[1]
+ flags := v.Args[2]
+ v.reset(OpARMSBCshiftRAreg)
+ v.AddArg(x)
+ v.AddArg(y)
+ v.AddArg(z)
+ v.AddArg(flags)
+ return true
+ }
+ // match: (SBC (SRA y z) x flags)
+ // cond:
+ // result: (RSCshiftRAreg x y z flags)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMSRA {
+ break
+ }
+ y := v_0.Args[0]
+ z := v_0.Args[1]
+ x := v.Args[1]
+ flags := v.Args[2]
+ v.reset(OpARMRSCshiftRAreg)
+ v.AddArg(x)
+ v.AddArg(y)
+ v.AddArg(z)
+ v.AddArg(flags)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMSBCconst(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SBCconst [c] (ADDconst [d] x) flags)
+ // cond:
+ // result: (SBCconst [int64(int32(c-d))] x flags)
+ for {
+ c := v.AuxInt
+ 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(OpARMSBCconst)
+ v.AuxInt = int64(int32(c - d))
+ v.AddArg(x)
+ v.AddArg(flags)
+ return true
+ }
+ // match: (SBCconst [c] (SUBconst [d] x) flags)
+ // cond:
+ // result: (SBCconst [int64(int32(c+d))] x flags)
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMSUBconst {
+ break
+ }
+ d := v_0.AuxInt
+ x := v_0.Args[0]
+ flags := v.Args[1]
+ v.reset(OpARMSBCconst)
+ v.AuxInt = int64(int32(c + d))
+ v.AddArg(x)
+ v.AddArg(flags)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMSBCshiftLL(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SBCshiftLL (MOVWconst [c]) x [d] flags)
+ // cond:
+ // result: (RSCconst [c] (SLLconst <x.Type> x [d]) flags)
+ for {
+ d := v.AuxInt
+ 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(OpARMRSCconst)
+ v.AuxInt = c
+ v0 := b.NewValue0(v.Line, OpARMSLLconst, x.Type)
+ v0.AuxInt = d
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v.AddArg(flags)
+ return true
+ }
+ // match: (SBCshiftLL x (MOVWconst [c]) [d] flags)
+ // cond:
+ // result: (SBCconst x [int64(uint32(c)<<uint64(d))] flags)
+ for {
+ d := v.AuxInt
+ 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(OpARMSBCconst)
+ v.AuxInt = int64(uint32(c) << uint64(d))
+ v.AddArg(x)
+ v.AddArg(flags)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMSBCshiftLLreg(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SBCshiftLLreg (MOVWconst [c]) x y flags)
+ // cond:
+ // result: (RSCconst [c] (SLL <x.Type> x y) flags)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ y := v.Args[2]
+ flags := v.Args[3]
+ v.reset(OpARMRSCconst)
+ v.AuxInt = c
+ v0 := b.NewValue0(v.Line, OpARMSLL, x.Type)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ v.AddArg(flags)
+ return true
+ }
+ // match: (SBCshiftLLreg x y (MOVWconst [c]) flags)
+ // cond:
+ // result: (SBCshiftLL x y [c] flags)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v_2 := v.Args[2]
+ if v_2.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_2.AuxInt
+ flags := v.Args[3]
+ v.reset(OpARMSBCshiftLL)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ v.AddArg(flags)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMSBCshiftRA(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SBCshiftRA (MOVWconst [c]) x [d] flags)
+ // cond:
+ // result: (RSCconst [c] (SRAconst <x.Type> x [d]) flags)
+ for {
+ d := v.AuxInt
+ 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(OpARMRSCconst)
+ v.AuxInt = c
+ v0 := b.NewValue0(v.Line, OpARMSRAconst, x.Type)
+ v0.AuxInt = d
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v.AddArg(flags)
+ return true
+ }
+ // match: (SBCshiftRA x (MOVWconst [c]) [d] flags)
+ // cond:
+ // result: (SBCconst x [int64(int32(c)>>uint64(d))] flags)
+ for {
+ d := v.AuxInt
+ 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(OpARMSBCconst)
+ v.AuxInt = int64(int32(c) >> uint64(d))
+ v.AddArg(x)
+ v.AddArg(flags)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMSBCshiftRAreg(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SBCshiftRAreg (MOVWconst [c]) x y flags)
+ // cond:
+ // result: (RSCconst [c] (SRA <x.Type> x y) flags)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ y := v.Args[2]
+ flags := v.Args[3]
+ v.reset(OpARMRSCconst)
+ v.AuxInt = c
+ v0 := b.NewValue0(v.Line, OpARMSRA, x.Type)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ v.AddArg(flags)
+ return true
+ }
+ // match: (SBCshiftRAreg x y (MOVWconst [c]) flags)
+ // cond:
+ // result: (SBCshiftRA x y [c] flags)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v_2 := v.Args[2]
+ if v_2.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_2.AuxInt
+ flags := v.Args[3]
+ v.reset(OpARMSBCshiftRA)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ v.AddArg(flags)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMSBCshiftRL(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SBCshiftRL (MOVWconst [c]) x [d] flags)
+ // cond:
+ // result: (RSCconst [c] (SRLconst <x.Type> x [d]) flags)
+ for {
+ d := v.AuxInt
+ 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(OpARMRSCconst)
+ v.AuxInt = c
+ v0 := b.NewValue0(v.Line, OpARMSRLconst, x.Type)
+ v0.AuxInt = d
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v.AddArg(flags)
+ return true
+ }
+ // match: (SBCshiftRL x (MOVWconst [c]) [d] flags)
+ // cond:
+ // result: (SBCconst x [int64(uint32(c)>>uint64(d))] flags)
+ for {
+ d := v.AuxInt
+ 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(OpARMSBCconst)
+ v.AuxInt = int64(uint32(c) >> uint64(d))
+ v.AddArg(x)
+ v.AddArg(flags)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMSBCshiftRLreg(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SBCshiftRLreg (MOVWconst [c]) x y flags)
+ // cond:
+ // result: (RSCconst [c] (SRL <x.Type> x y) flags)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ y := v.Args[2]
+ flags := v.Args[3]
+ v.reset(OpARMRSCconst)
+ v.AuxInt = c
+ v0 := b.NewValue0(v.Line, OpARMSRL, x.Type)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ v.AddArg(flags)
+ return true
+ }
+ // match: (SBCshiftRLreg x y (MOVWconst [c]) flags)
+ // cond:
+ // result: (SBCshiftRL x y [c] flags)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v_2 := v.Args[2]
+ if v_2.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_2.AuxInt
+ flags := v.Args[3]
+ v.reset(OpARMSBCshiftRL)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ v.AddArg(flags)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMSLL(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SLL x (MOVWconst [c]))
+ // cond:
+ // result: (SLLconst x [c&31])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpARMSLLconst)
+ v.AuxInt = c & 31
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMSLLconst(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SLLconst [c] (MOVWconst [d]))
+ // cond:
+ // result: (MOVWconst [int64(uint32(d)<<uint64(c))])
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWconst {
+ break
+ }
+ d := v_0.AuxInt
+ v.reset(OpARMMOVWconst)
+ v.AuxInt = int64(uint32(d) << uint64(c))
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMSRA(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SRA x (MOVWconst [c]))
+ // cond:
+ // result: (SRAconst x [c&31])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpARMSRAconst)
+ v.AuxInt = c & 31
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMSRAcond(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SRAcond x _ (FlagEQ))
+ // cond:
+ // result: (SRAconst x [31])
+ for {
+ x := v.Args[0]
+ v_2 := v.Args[2]
+ if v_2.Op != OpARMFlagEQ {
+ break
+ }
+ v.reset(OpARMSRAconst)
+ v.AuxInt = 31
+ v.AddArg(x)
+ return true
+ }
+ // match: (SRAcond x y (FlagLT_ULT))
+ // cond:
+ // result: (SRA x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v_2 := v.Args[2]
+ if v_2.Op != OpARMFlagLT_ULT {
+ break
+ }
+ v.reset(OpARMSRA)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (SRAcond x _ (FlagLT_UGT))
+ // cond:
+ // result: (SRAconst x [31])
+ for {
+ x := v.Args[0]
+ v_2 := v.Args[2]
+ if v_2.Op != OpARMFlagLT_UGT {
+ break
+ }
+ v.reset(OpARMSRAconst)
+ v.AuxInt = 31
+ v.AddArg(x)
+ return true
+ }
+ // match: (SRAcond x y (FlagGT_ULT))
+ // cond:
+ // result: (SRA x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v_2 := v.Args[2]
+ if v_2.Op != OpARMFlagGT_ULT {
+ break
+ }
+ v.reset(OpARMSRA)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (SRAcond x _ (FlagGT_UGT))
+ // cond:
+ // result: (SRAconst x [31])
+ for {
+ x := v.Args[0]
+ v_2 := v.Args[2]
+ if v_2.Op != OpARMFlagGT_UGT {
+ break
+ }
+ v.reset(OpARMSRAconst)
+ v.AuxInt = 31
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMSRAconst(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SRAconst [c] (MOVWconst [d]))
+ // cond:
+ // result: (MOVWconst [int64(int32(d)>>uint64(c))])
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWconst {
+ break
+ }
+ d := v_0.AuxInt
+ v.reset(OpARMMOVWconst)
+ v.AuxInt = int64(int32(d) >> uint64(c))
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMSRL(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SRL x (MOVWconst [c]))
+ // cond:
+ // result: (SRLconst x [c&31])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpARMSRLconst)
+ v.AuxInt = c & 31
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMSRLconst(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SRLconst [c] (MOVWconst [d]))
+ // cond:
+ // result: (MOVWconst [int64(uint32(d)>>uint64(c))])
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWconst {
+ break
+ }
+ d := v_0.AuxInt
+ v.reset(OpARMMOVWconst)
+ v.AuxInt = int64(uint32(d) >> uint64(c))
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMSUB(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SUB (MOVWconst [c]) x)
+ // cond:
+ // result: (RSBconst [c] x)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ v.reset(OpARMRSBconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (SUB x (MOVWconst [c]))
+ // cond:
+ // result: (SUBconst [c] x)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpARMSUBconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (SUB x (SLLconst [c] y))
+ // cond:
+ // result: (SUBshiftLL x y [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMSLLconst {
+ break
+ }
+ c := v_1.AuxInt
+ y := v_1.Args[0]
+ v.reset(OpARMSUBshiftLL)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (SUB (SLLconst [c] y) x)
+ // cond:
+ // result: (RSBshiftLL x y [c])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMSLLconst {
+ break
+ }
+ c := v_0.AuxInt
+ y := v_0.Args[0]
+ x := v.Args[1]
+ v.reset(OpARMRSBshiftLL)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (SUB x (SRLconst [c] y))
+ // cond:
+ // result: (SUBshiftRL x y [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMSRLconst {
+ break
+ }
+ c := v_1.AuxInt
+ y := v_1.Args[0]
+ v.reset(OpARMSUBshiftRL)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (SUB (SRLconst [c] y) x)
+ // cond:
+ // result: (RSBshiftRL x y [c])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMSRLconst {
+ break
+ }
+ c := v_0.AuxInt
+ y := v_0.Args[0]
+ x := v.Args[1]
+ v.reset(OpARMRSBshiftRL)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (SUB x (SRAconst [c] y))
+ // cond:
+ // result: (SUBshiftRA x y [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMSRAconst {
+ break
+ }
+ c := v_1.AuxInt
+ y := v_1.Args[0]
+ v.reset(OpARMSUBshiftRA)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (SUB (SRAconst [c] y) x)
+ // cond:
+ // result: (RSBshiftRA x y [c])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMSRAconst {
+ break
+ }
+ c := v_0.AuxInt
+ y := v_0.Args[0]
+ x := v.Args[1]
+ v.reset(OpARMRSBshiftRA)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (SUB x (SLL y z))
+ // cond:
+ // result: (SUBshiftLLreg x y z)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMSLL {
+ break
+ }
+ y := v_1.Args[0]
+ z := v_1.Args[1]
+ v.reset(OpARMSUBshiftLLreg)
+ v.AddArg(x)
+ v.AddArg(y)
+ v.AddArg(z)
+ return true
+ }
+ // match: (SUB (SLL y z) x)
+ // cond:
+ // result: (RSBshiftLLreg x y z)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMSLL {
+ break
+ }
+ y := v_0.Args[0]
+ z := v_0.Args[1]
+ x := v.Args[1]
+ v.reset(OpARMRSBshiftLLreg)
+ v.AddArg(x)
+ v.AddArg(y)
+ v.AddArg(z)
+ return true
+ }
+ // match: (SUB x (SRL y z))
+ // cond:
+ // result: (SUBshiftRLreg x y z)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMSRL {
+ break
+ }
+ y := v_1.Args[0]
+ z := v_1.Args[1]
+ v.reset(OpARMSUBshiftRLreg)
+ v.AddArg(x)
+ v.AddArg(y)
+ v.AddArg(z)
+ return true
+ }
+ // match: (SUB (SRL y z) x)
+ // cond:
+ // result: (RSBshiftRLreg x y z)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMSRL {
+ break
+ }
+ y := v_0.Args[0]
+ z := v_0.Args[1]
+ x := v.Args[1]
+ v.reset(OpARMRSBshiftRLreg)
+ v.AddArg(x)
+ v.AddArg(y)
+ v.AddArg(z)
+ return true
+ }
+ // match: (SUB x (SRA y z))
+ // cond:
+ // result: (SUBshiftRAreg x y z)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMSRA {
+ break
+ }
+ y := v_1.Args[0]
+ z := v_1.Args[1]
+ v.reset(OpARMSUBshiftRAreg)
+ v.AddArg(x)
+ v.AddArg(y)
+ v.AddArg(z)
+ return true
+ }
+ // match: (SUB (SRA y z) x)
+ // cond:
+ // result: (RSBshiftRAreg x y z)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMSRA {
+ break
+ }
+ y := v_0.Args[0]
+ z := v_0.Args[1]
+ x := v.Args[1]
+ v.reset(OpARMRSBshiftRAreg)
+ v.AddArg(x)
+ v.AddArg(y)
+ v.AddArg(z)
+ return true
+ }
+ // match: (SUB x x)
+ // cond:
+ // result: (MOVWconst [0])
+ for {
+ x := v.Args[0]
+ if x != v.Args[1] {
+ break
+ }
+ v.reset(OpARMMOVWconst)
+ v.AuxInt = 0
+ return true
+ }
+ 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
+ }
+ // match: (SUBS x (MOVWconst [c]))
+ // cond:
+ // result: (SUBSconst [c] x)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpARMSUBSconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (SUBS x (SLLconst [c] y))
+ // cond:
+ // result: (SUBSshiftLL x y [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMSLLconst {
+ break
+ }
+ c := v_1.AuxInt
+ y := v_1.Args[0]
+ v.reset(OpARMSUBSshiftLL)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (SUBS (SLLconst [c] y) x)
+ // cond:
+ // result: (RSBSshiftLL x y [c])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMSLLconst {
+ break
+ }
+ c := v_0.AuxInt
+ y := v_0.Args[0]
+ x := v.Args[1]
+ v.reset(OpARMRSBSshiftLL)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (SUBS x (SRLconst [c] y))
+ // cond:
+ // result: (SUBSshiftRL x y [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMSRLconst {
+ break
+ }
+ c := v_1.AuxInt
+ y := v_1.Args[0]
+ v.reset(OpARMSUBSshiftRL)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (SUBS (SRLconst [c] y) x)
+ // cond:
+ // result: (RSBSshiftRL x y [c])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMSRLconst {
+ break
+ }
+ c := v_0.AuxInt
+ y := v_0.Args[0]
+ x := v.Args[1]
+ v.reset(OpARMRSBSshiftRL)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (SUBS x (SRAconst [c] y))
+ // cond:
+ // result: (SUBSshiftRA x y [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMSRAconst {
+ break
+ }
+ c := v_1.AuxInt
+ y := v_1.Args[0]
+ v.reset(OpARMSUBSshiftRA)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (SUBS (SRAconst [c] y) x)
+ // cond:
+ // result: (RSBSshiftRA x y [c])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMSRAconst {
+ break
+ }
+ c := v_0.AuxInt
+ y := v_0.Args[0]
+ x := v.Args[1]
+ v.reset(OpARMRSBSshiftRA)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (SUBS x (SLL y z))
+ // cond:
+ // result: (SUBSshiftLLreg x y z)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMSLL {
+ break
+ }
+ y := v_1.Args[0]
+ z := v_1.Args[1]
+ v.reset(OpARMSUBSshiftLLreg)
+ v.AddArg(x)
+ v.AddArg(y)
+ v.AddArg(z)
+ return true
+ }
+ // match: (SUBS (SLL y z) x)
+ // cond:
+ // result: (RSBSshiftLLreg x y z)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMSLL {
+ break
+ }
+ y := v_0.Args[0]
+ z := v_0.Args[1]
+ x := v.Args[1]
+ v.reset(OpARMRSBSshiftLLreg)
+ v.AddArg(x)
+ v.AddArg(y)
+ v.AddArg(z)
+ return true
+ }
+ // match: (SUBS x (SRL y z))
+ // cond:
+ // result: (SUBSshiftRLreg x y z)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMSRL {
+ break
+ }
+ y := v_1.Args[0]
+ z := v_1.Args[1]
+ v.reset(OpARMSUBSshiftRLreg)
+ v.AddArg(x)
+ v.AddArg(y)
+ v.AddArg(z)
+ return true
+ }
+ // match: (SUBS (SRL y z) x)
+ // cond:
+ // result: (RSBSshiftRLreg x y z)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMSRL {
+ break
+ }
+ y := v_0.Args[0]
+ z := v_0.Args[1]
+ x := v.Args[1]
+ v.reset(OpARMRSBSshiftRLreg)
+ v.AddArg(x)
+ v.AddArg(y)
+ v.AddArg(z)
+ return true
+ }
+ // match: (SUBS x (SRA y z))
+ // cond:
+ // result: (SUBSshiftRAreg x y z)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMSRA {
+ break
+ }
+ y := v_1.Args[0]
+ z := v_1.Args[1]
+ v.reset(OpARMSUBSshiftRAreg)
+ v.AddArg(x)
+ v.AddArg(y)
+ v.AddArg(z)
+ return true
+ }
+ // match: (SUBS (SRA y z) x)
+ // cond:
+ // result: (RSBSshiftRAreg x y z)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMSRA {
+ break
+ }
+ y := v_0.Args[0]
+ z := v_0.Args[1]
+ x := v.Args[1]
+ v.reset(OpARMRSBSshiftRAreg)
+ v.AddArg(x)
+ v.AddArg(y)
+ v.AddArg(z)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMSUBSshiftLL(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SUBSshiftLL (MOVWconst [c]) x [d])
+ // cond:
+ // result: (RSBSconst [c] (SLLconst <x.Type> x [d]))
+ for {
+ d := v.AuxInt
+ 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
+ v0 := b.NewValue0(v.Line, OpARMSLLconst, x.Type)
+ v0.AuxInt = d
+ v0.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (SUBSshiftLL x (MOVWconst [c]) [d])
+ // cond:
+ // result: (SUBSconst x [int64(uint32(c)<<uint64(d))])
+ for {
+ d := v.AuxInt
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpARMSUBSconst)
+ v.AuxInt = int64(uint32(c) << uint64(d))
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMSUBSshiftLLreg(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SUBSshiftLLreg (MOVWconst [c]) x y)
+ // cond:
+ // result: (RSBSconst [c] (SLL <x.Type> x y))
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ y := v.Args[2]
+ v.reset(OpARMRSBSconst)
+ v.AuxInt = c
+ v0 := b.NewValue0(v.Line, OpARMSLL, x.Type)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (SUBSshiftLLreg x y (MOVWconst [c]))
+ // cond:
+ // result: (SUBSshiftLL x y [c])
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v_2 := v.Args[2]
+ if v_2.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_2.AuxInt
+ v.reset(OpARMSUBSshiftLL)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMSUBSshiftRA(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SUBSshiftRA (MOVWconst [c]) x [d])
+ // cond:
+ // result: (RSBSconst [c] (SRAconst <x.Type> x [d]))
+ for {
+ d := v.AuxInt
+ 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
+ v0 := b.NewValue0(v.Line, OpARMSRAconst, x.Type)
+ v0.AuxInt = d
+ v0.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (SUBSshiftRA x (MOVWconst [c]) [d])
+ // cond:
+ // result: (SUBSconst x [int64(int32(c)>>uint64(d))])
+ for {
+ d := v.AuxInt
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpARMSUBSconst)
+ v.AuxInt = int64(int32(c) >> uint64(d))
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMSUBSshiftRAreg(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SUBSshiftRAreg (MOVWconst [c]) x y)
+ // cond:
+ // result: (RSBSconst [c] (SRA <x.Type> x y))
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ y := v.Args[2]
+ v.reset(OpARMRSBSconst)
+ v.AuxInt = c
+ v0 := b.NewValue0(v.Line, OpARMSRA, x.Type)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (SUBSshiftRAreg x y (MOVWconst [c]))
+ // cond:
+ // result: (SUBSshiftRA x y [c])
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v_2 := v.Args[2]
+ if v_2.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_2.AuxInt
+ v.reset(OpARMSUBSshiftRA)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMSUBSshiftRL(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SUBSshiftRL (MOVWconst [c]) x [d])
+ // cond:
+ // result: (RSBSconst [c] (SRLconst <x.Type> x [d]))
+ for {
+ d := v.AuxInt
+ 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
+ v0 := b.NewValue0(v.Line, OpARMSRLconst, x.Type)
+ v0.AuxInt = d
+ v0.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (SUBSshiftRL x (MOVWconst [c]) [d])
+ // cond:
+ // result: (SUBSconst x [int64(uint32(c)>>uint64(d))])
+ for {
+ d := v.AuxInt
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpARMSUBSconst)
+ v.AuxInt = int64(uint32(c) >> uint64(d))
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMSUBSshiftRLreg(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SUBSshiftRLreg (MOVWconst [c]) x y)
+ // cond:
+ // result: (RSBSconst [c] (SRL <x.Type> x y))
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ y := v.Args[2]
+ v.reset(OpARMRSBSconst)
+ v.AuxInt = c
+ v0 := b.NewValue0(v.Line, OpARMSRL, x.Type)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (SUBSshiftRLreg x y (MOVWconst [c]))
+ // cond:
+ // result: (SUBSshiftRL x y [c])
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v_2 := v.Args[2]
+ if v_2.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_2.AuxInt
+ v.reset(OpARMSUBSshiftRL)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMSUBconst(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SUBconst [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: (SUBconst [c] (MOVWconst [d]))
+ // cond:
+ // result: (MOVWconst [int64(int32(d-c))])
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWconst {
+ break
+ }
+ d := v_0.AuxInt
+ v.reset(OpARMMOVWconst)
+ v.AuxInt = int64(int32(d - c))
+ return true
+ }
+ // match: (SUBconst [c] (SUBconst [d] x))
+ // cond:
+ // result: (ADDconst [int64(int32(-c-d))] x)
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMSUBconst {
+ break
+ }
+ d := v_0.AuxInt
+ x := v_0.Args[0]
+ v.reset(OpARMADDconst)
+ v.AuxInt = int64(int32(-c - d))
+ v.AddArg(x)
+ return true
+ }
+ // match: (SUBconst [c] (ADDconst [d] x))
+ // cond:
+ // result: (ADDconst [int64(int32(-c+d))] x)
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMADDconst {
+ break
+ }
+ d := v_0.AuxInt
+ x := v_0.Args[0]
+ v.reset(OpARMADDconst)
+ v.AuxInt = int64(int32(-c + d))
+ v.AddArg(x)
+ return true
+ }
+ // match: (SUBconst [c] (RSBconst [d] x))
+ // cond:
+ // result: (RSBconst [int64(int32(-c+d))] x)
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMRSBconst {
+ break
+ }
+ d := v_0.AuxInt
+ x := v_0.Args[0]
+ v.reset(OpARMRSBconst)
+ v.AuxInt = int64(int32(-c + d))
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMSUBshiftLL(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SUBshiftLL (MOVWconst [c]) x [d])
+ // cond:
+ // result: (RSBconst [c] (SLLconst <x.Type> x [d]))
+ for {
+ d := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ v.reset(OpARMRSBconst)
+ v.AuxInt = c
+ v0 := b.NewValue0(v.Line, OpARMSLLconst, x.Type)
+ v0.AuxInt = d
+ v0.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (SUBshiftLL x (MOVWconst [c]) [d])
+ // cond:
+ // result: (SUBconst x [int64(uint32(c)<<uint64(d))])
+ for {
+ d := v.AuxInt
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpARMSUBconst)
+ v.AuxInt = int64(uint32(c) << uint64(d))
+ v.AddArg(x)
+ return true
+ }
+ // match: (SUBshiftLL x (SLLconst x [c]) [d])
+ // cond: c==d
+ // result: (MOVWconst [0])
+ for {
+ d := v.AuxInt
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMSLLconst {
+ break
+ }
+ c := v_1.AuxInt
+ if x != v_1.Args[0] {
+ break
+ }
+ if !(c == d) {
+ break
+ }
+ v.reset(OpARMMOVWconst)
+ v.AuxInt = 0
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMSUBshiftLLreg(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SUBshiftLLreg (MOVWconst [c]) x y)
+ // cond:
+ // result: (RSBconst [c] (SLL <x.Type> x y))
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ y := v.Args[2]
+ v.reset(OpARMRSBconst)
+ v.AuxInt = c
+ v0 := b.NewValue0(v.Line, OpARMSLL, x.Type)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (SUBshiftLLreg x y (MOVWconst [c]))
+ // cond:
+ // result: (SUBshiftLL x y [c])
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v_2 := v.Args[2]
+ if v_2.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_2.AuxInt
+ v.reset(OpARMSUBshiftLL)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMSUBshiftRA(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SUBshiftRA (MOVWconst [c]) x [d])
+ // cond:
+ // result: (RSBconst [c] (SRAconst <x.Type> x [d]))
+ for {
+ d := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ v.reset(OpARMRSBconst)
+ v.AuxInt = c
+ v0 := b.NewValue0(v.Line, OpARMSRAconst, x.Type)
+ v0.AuxInt = d
+ v0.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (SUBshiftRA x (MOVWconst [c]) [d])
+ // cond:
+ // result: (SUBconst x [int64(int32(c)>>uint64(d))])
+ for {
+ d := v.AuxInt
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpARMSUBconst)
+ v.AuxInt = int64(int32(c) >> uint64(d))
+ v.AddArg(x)
+ return true
+ }
+ // match: (SUBshiftRA x (SRAconst x [c]) [d])
+ // cond: c==d
+ // result: (MOVWconst [0])
+ for {
+ d := v.AuxInt
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMSRAconst {
+ break
+ }
+ c := v_1.AuxInt
+ if x != v_1.Args[0] {
+ break
+ }
+ if !(c == d) {
+ break
+ }
+ v.reset(OpARMMOVWconst)
+ v.AuxInt = 0
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMSUBshiftRAreg(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SUBshiftRAreg (MOVWconst [c]) x y)
+ // cond:
+ // result: (RSBconst [c] (SRA <x.Type> x y))
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ y := v.Args[2]
+ v.reset(OpARMRSBconst)
+ v.AuxInt = c
+ v0 := b.NewValue0(v.Line, OpARMSRA, x.Type)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (SUBshiftRAreg x y (MOVWconst [c]))
+ // cond:
+ // result: (SUBshiftRA x y [c])
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v_2 := v.Args[2]
+ if v_2.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_2.AuxInt
+ v.reset(OpARMSUBshiftRA)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMSUBshiftRL(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SUBshiftRL (MOVWconst [c]) x [d])
+ // cond:
+ // result: (RSBconst [c] (SRLconst <x.Type> x [d]))
+ for {
+ d := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ v.reset(OpARMRSBconst)
+ v.AuxInt = c
+ v0 := b.NewValue0(v.Line, OpARMSRLconst, x.Type)
+ v0.AuxInt = d
+ v0.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (SUBshiftRL x (MOVWconst [c]) [d])
+ // cond:
+ // result: (SUBconst x [int64(uint32(c)>>uint64(d))])
+ for {
+ d := v.AuxInt
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpARMSUBconst)
+ v.AuxInt = int64(uint32(c) >> uint64(d))
+ v.AddArg(x)
+ return true
+ }
+ // match: (SUBshiftRL x (SRLconst x [c]) [d])
+ // cond: c==d
+ // result: (MOVWconst [0])
+ for {
+ d := v.AuxInt
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMSRLconst {
+ break
+ }
+ c := v_1.AuxInt
+ if x != v_1.Args[0] {
+ break
+ }
+ if !(c == d) {
+ break
+ }
+ v.reset(OpARMMOVWconst)
+ v.AuxInt = 0
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMSUBshiftRLreg(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SUBshiftRLreg (MOVWconst [c]) x y)
+ // cond:
+ // result: (RSBconst [c] (SRL <x.Type> x y))
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ y := v.Args[2]
+ v.reset(OpARMRSBconst)
+ v.AuxInt = c
+ v0 := b.NewValue0(v.Line, OpARMSRL, x.Type)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (SUBshiftRLreg x y (MOVWconst [c]))
+ // cond:
+ // result: (SUBshiftRL x y [c])
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v_2 := v.Args[2]
+ if v_2.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_2.AuxInt
+ v.reset(OpARMSUBshiftRL)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMXOR(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (XOR (MOVWconst [c]) x)
+ // cond:
+ // result: (XORconst [c] x)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ v.reset(OpARMXORconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (XOR x (MOVWconst [c]))
+ // cond:
+ // result: (XORconst [c] x)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpARMXORconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (XOR x (SLLconst [c] y))
+ // cond:
+ // result: (XORshiftLL x y [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMSLLconst {
+ break
+ }
+ c := v_1.AuxInt
+ y := v_1.Args[0]
+ v.reset(OpARMXORshiftLL)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (XOR (SLLconst [c] y) x)
+ // cond:
+ // result: (XORshiftLL x y [c])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMSLLconst {
+ break
+ }
+ c := v_0.AuxInt
+ y := v_0.Args[0]
+ x := v.Args[1]
+ v.reset(OpARMXORshiftLL)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (XOR x (SRLconst [c] y))
+ // cond:
+ // result: (XORshiftRL x y [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMSRLconst {
+ break
+ }
+ c := v_1.AuxInt
+ y := v_1.Args[0]
+ v.reset(OpARMXORshiftRL)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (XOR (SRLconst [c] y) x)
+ // cond:
+ // result: (XORshiftRL x y [c])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMSRLconst {
+ break
+ }
+ c := v_0.AuxInt
+ y := v_0.Args[0]
+ x := v.Args[1]
+ v.reset(OpARMXORshiftRL)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (XOR x (SRAconst [c] y))
+ // cond:
+ // result: (XORshiftRA x y [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMSRAconst {
+ break
+ }
+ c := v_1.AuxInt
+ y := v_1.Args[0]
+ v.reset(OpARMXORshiftRA)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (XOR (SRAconst [c] y) x)
+ // cond:
+ // result: (XORshiftRA x y [c])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMSRAconst {
+ break
+ }
+ c := v_0.AuxInt
+ y := v_0.Args[0]
+ x := v.Args[1]
+ v.reset(OpARMXORshiftRA)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (XOR x (SRRconst [c] y))
+ // cond:
+ // result: (XORshiftRR x y [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMSRRconst {
+ break
+ }
+ c := v_1.AuxInt
+ y := v_1.Args[0]
+ v.reset(OpARMXORshiftRR)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (XOR (SRRconst [c] y) x)
+ // cond:
+ // result: (XORshiftRR x y [c])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMSRRconst {
+ break
+ }
+ c := v_0.AuxInt
+ y := v_0.Args[0]
+ x := v.Args[1]
+ v.reset(OpARMXORshiftRR)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (XOR x (SLL y z))
+ // cond:
+ // result: (XORshiftLLreg x y z)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMSLL {
+ break
+ }
+ y := v_1.Args[0]
+ z := v_1.Args[1]
+ v.reset(OpARMXORshiftLLreg)
+ v.AddArg(x)
+ v.AddArg(y)
+ v.AddArg(z)
+ return true
+ }
+ // match: (XOR (SLL y z) x)
+ // cond:
+ // result: (XORshiftLLreg x y z)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMSLL {
+ break
+ }
+ y := v_0.Args[0]
+ z := v_0.Args[1]
+ x := v.Args[1]
+ v.reset(OpARMXORshiftLLreg)
+ v.AddArg(x)
+ v.AddArg(y)
+ v.AddArg(z)
+ return true
+ }
+ // match: (XOR x (SRL y z))
+ // cond:
+ // result: (XORshiftRLreg x y z)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMSRL {
+ break
+ }
+ y := v_1.Args[0]
+ z := v_1.Args[1]
+ v.reset(OpARMXORshiftRLreg)
+ v.AddArg(x)
+ v.AddArg(y)
+ v.AddArg(z)
+ return true
+ }
+ // match: (XOR (SRL y z) x)
+ // cond:
+ // result: (XORshiftRLreg x y z)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMSRL {
+ break
+ }
+ y := v_0.Args[0]
+ z := v_0.Args[1]
+ x := v.Args[1]
+ v.reset(OpARMXORshiftRLreg)
+ v.AddArg(x)
+ v.AddArg(y)
+ v.AddArg(z)
+ return true
+ }
+ // match: (XOR x (SRA y z))
+ // cond:
+ // result: (XORshiftRAreg x y z)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMSRA {
+ break
+ }
+ y := v_1.Args[0]
+ z := v_1.Args[1]
+ v.reset(OpARMXORshiftRAreg)
+ v.AddArg(x)
+ v.AddArg(y)
+ v.AddArg(z)
+ return true
+ }
+ // match: (XOR (SRA y z) x)
+ // cond:
+ // result: (XORshiftRAreg x y z)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMSRA {
+ break
+ }
+ y := v_0.Args[0]
+ z := v_0.Args[1]
+ x := v.Args[1]
+ v.reset(OpARMXORshiftRAreg)
+ v.AddArg(x)
+ v.AddArg(y)
+ v.AddArg(z)
+ return true
+ }
+ // match: (XOR x x)
+ // cond:
+ // result: (MOVWconst [0])
+ for {
+ x := v.Args[0]
+ if x != v.Args[1] {
+ break
+ }
+ v.reset(OpARMMOVWconst)
+ v.AuxInt = 0
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMXORconst(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (XORconst [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: (XORconst [c] (MOVWconst [d]))
+ // cond:
+ // result: (MOVWconst [c^d])
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWconst {
+ break
+ }
+ d := v_0.AuxInt
+ v.reset(OpARMMOVWconst)
+ v.AuxInt = c ^ d
+ return true
+ }
+ // match: (XORconst [c] (XORconst [d] x))
+ // cond:
+ // result: (XORconst [c^d] x)
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMXORconst {
+ break
+ }
+ d := v_0.AuxInt
+ x := v_0.Args[0]
+ v.reset(OpARMXORconst)
+ v.AuxInt = c ^ d
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMXORshiftLL(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (XORshiftLL (MOVWconst [c]) x [d])
+ // cond:
+ // result: (XORconst [c] (SLLconst <x.Type> x [d]))
+ for {
+ d := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ v.reset(OpARMXORconst)
+ v.AuxInt = c
+ v0 := b.NewValue0(v.Line, OpARMSLLconst, x.Type)
+ v0.AuxInt = d
+ v0.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (XORshiftLL x (MOVWconst [c]) [d])
+ // cond:
+ // result: (XORconst x [int64(uint32(c)<<uint64(d))])
+ for {
+ d := v.AuxInt
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpARMXORconst)
+ v.AuxInt = int64(uint32(c) << uint64(d))
+ v.AddArg(x)
+ return true
+ }
+ // match: (XORshiftLL x (SLLconst x [c]) [d])
+ // cond: c==d
+ // result: (MOVWconst [0])
+ for {
+ d := v.AuxInt
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMSLLconst {
+ break
+ }
+ c := v_1.AuxInt
+ if x != v_1.Args[0] {
+ break
+ }
+ if !(c == d) {
+ break
+ }
+ v.reset(OpARMMOVWconst)
+ v.AuxInt = 0
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMXORshiftLLreg(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (XORshiftLLreg (MOVWconst [c]) x y)
+ // cond:
+ // result: (XORconst [c] (SLL <x.Type> x y))
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ y := v.Args[2]
+ v.reset(OpARMXORconst)
+ v.AuxInt = c
+ v0 := b.NewValue0(v.Line, OpARMSLL, x.Type)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (XORshiftLLreg x y (MOVWconst [c]))
+ // cond:
+ // result: (XORshiftLL x y [c])
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v_2 := v.Args[2]
+ if v_2.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_2.AuxInt
+ v.reset(OpARMXORshiftLL)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMXORshiftRA(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (XORshiftRA (MOVWconst [c]) x [d])
+ // cond:
+ // result: (XORconst [c] (SRAconst <x.Type> x [d]))
+ for {
+ d := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ v.reset(OpARMXORconst)
+ v.AuxInt = c
+ v0 := b.NewValue0(v.Line, OpARMSRAconst, x.Type)
+ v0.AuxInt = d
+ v0.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (XORshiftRA x (MOVWconst [c]) [d])
+ // cond:
+ // result: (XORconst x [int64(int32(c)>>uint64(d))])
+ for {
+ d := v.AuxInt
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpARMXORconst)
+ v.AuxInt = int64(int32(c) >> uint64(d))
+ v.AddArg(x)
+ return true
+ }
+ // match: (XORshiftRA x (SRAconst x [c]) [d])
+ // cond: c==d
+ // result: (MOVWconst [0])
+ for {
+ d := v.AuxInt
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMSRAconst {
+ break
+ }
+ c := v_1.AuxInt
+ if x != v_1.Args[0] {
+ break
+ }
+ if !(c == d) {
+ break
+ }
+ v.reset(OpARMMOVWconst)
+ v.AuxInt = 0
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMXORshiftRAreg(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (XORshiftRAreg (MOVWconst [c]) x y)
+ // cond:
+ // result: (XORconst [c] (SRA <x.Type> x y))
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ y := v.Args[2]
+ v.reset(OpARMXORconst)
+ v.AuxInt = c
+ v0 := b.NewValue0(v.Line, OpARMSRA, x.Type)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (XORshiftRAreg x y (MOVWconst [c]))
+ // cond:
+ // result: (XORshiftRA x y [c])
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v_2 := v.Args[2]
+ if v_2.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_2.AuxInt
+ v.reset(OpARMXORshiftRA)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMXORshiftRL(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (XORshiftRL (MOVWconst [c]) x [d])
+ // cond:
+ // result: (XORconst [c] (SRLconst <x.Type> x [d]))
+ for {
+ d := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ v.reset(OpARMXORconst)
+ v.AuxInt = c
+ v0 := b.NewValue0(v.Line, OpARMSRLconst, x.Type)
+ v0.AuxInt = d
+ v0.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (XORshiftRL x (MOVWconst [c]) [d])
+ // cond:
+ // result: (XORconst x [int64(uint32(c)>>uint64(d))])
+ for {
+ d := v.AuxInt
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpARMXORconst)
+ v.AuxInt = int64(uint32(c) >> uint64(d))
+ v.AddArg(x)
+ return true
+ }
+ // match: (XORshiftRL x (SRLconst x [c]) [d])
+ // cond: c==d
+ // result: (MOVWconst [0])
+ for {
+ d := v.AuxInt
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMSRLconst {
+ break
+ }
+ c := v_1.AuxInt
+ if x != v_1.Args[0] {
+ break
+ }
+ if !(c == d) {
+ break
+ }
+ v.reset(OpARMMOVWconst)
+ v.AuxInt = 0
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMXORshiftRLreg(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (XORshiftRLreg (MOVWconst [c]) x y)
+ // cond:
+ // result: (XORconst [c] (SRL <x.Type> x y))
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ y := v.Args[2]
+ v.reset(OpARMXORconst)
+ v.AuxInt = c
+ v0 := b.NewValue0(v.Line, OpARMSRL, x.Type)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (XORshiftRLreg x y (MOVWconst [c]))
+ // cond:
+ // result: (XORshiftRL x y [c])
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v_2 := v.Args[2]
+ if v_2.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_2.AuxInt
+ v.reset(OpARMXORshiftRL)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpARMXORshiftRR(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (XORshiftRR (MOVWconst [c]) x [d])
+ // cond:
+ // result: (XORconst [c] (SRRconst <x.Type> x [d]))
+ for {
+ d := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ v.reset(OpARMXORconst)
+ v.AuxInt = c
+ v0 := b.NewValue0(v.Line, OpARMSRRconst, x.Type)
+ v0.AuxInt = d
+ v0.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (XORshiftRR x (MOVWconst [c]) [d])
+ // cond:
+ // result: (XORconst x [int64(uint32(c)>>uint64(d)|uint32(c)<<uint64(32-d))])
+ for {
+ d := v.AuxInt
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpARMXORconst)
+ v.AuxInt = int64(uint32(c)>>uint64(d) | uint32(c)<<uint64(32-d))
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpAdd16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Add16 x y)
+ // cond:
+ // result: (ADD x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARMADD)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueARM_OpAdd32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Add32 x y)
+ // cond:
+ // result: (ADD x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARMADD)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueARM_OpAdd32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Add32F x y)
+ // cond:
+ // result: (ADDF x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARMADDF)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueARM_OpAdd32carry(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Add32carry x y)
+ // cond:
+ // result: (ADDS x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARMADDS)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueARM_OpAdd32withcarry(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Add32withcarry x y c)
+ // cond:
+ // result: (ADC x y c)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ c := v.Args[2]
+ v.reset(OpARMADC)
+ v.AddArg(x)
+ v.AddArg(y)
+ v.AddArg(c)
+ return true
+ }
+}
+func rewriteValueARM_OpAdd64F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Add64F x y)
+ // cond:
+ // result: (ADDD x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARMADDD)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueARM_OpAdd8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Add8 x y)
+ // cond:
+ // result: (ADD x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARMADD)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueARM_OpAddPtr(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (AddPtr x y)
+ // cond:
+ // result: (ADD x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARMADD)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueARM_OpAddr(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Addr {sym} base)
+ // cond:
+ // result: (MOVWaddr {sym} base)
+ for {
+ sym := v.Aux
+ base := v.Args[0]
+ v.reset(OpARMMOVWaddr)
+ v.Aux = sym
+ v.AddArg(base)
+ return true
+ }
+}
+func rewriteValueARM_OpAnd16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (And16 x y)
+ // cond:
+ // result: (AND x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARMAND)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueARM_OpAnd32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (And32 x y)
+ // cond:
+ // result: (AND x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARMAND)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueARM_OpAnd8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (And8 x y)
+ // cond:
+ // result: (AND x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARMAND)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueARM_OpAndB(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (AndB x y)
+ // cond:
+ // result: (AND x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARMAND)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueARM_OpBswap32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Bswap32 <t> x)
+ // cond:
+ // 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]
+ v.reset(OpARMXOR)
+ v.Type = t
+ v0 := b.NewValue0(v.Line, OpARMSRLconst, t)
+ v0.AuxInt = 8
+ v1 := b.NewValue0(v.Line, OpARMBICconst, t)
+ v1.AuxInt = 0xff0000
+ v2 := b.NewValue0(v.Line, OpARMXOR, t)
+ v2.AddArg(x)
+ v3 := b.NewValue0(v.Line, 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.AuxInt = 8
+ v4.AddArg(x)
+ v.AddArg(v4)
+ return true
+ }
+}
+func rewriteValueARM_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(OpARMCALLclosure)
+ v.AuxInt = argwid
+ v.AddArg(entry)
+ v.AddArg(closure)
+ v.AddArg(mem)
+ return true
+ }
+}
+func rewriteValueARM_OpCom16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Com16 x)
+ // cond:
+ // result: (MVN x)
+ for {
+ x := v.Args[0]
+ v.reset(OpARMMVN)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueARM_OpCom32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Com32 x)
+ // cond:
+ // result: (MVN x)
+ for {
+ x := v.Args[0]
+ v.reset(OpARMMVN)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueARM_OpCom8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Com8 x)
+ // cond:
+ // result: (MVN x)
+ for {
+ x := v.Args[0]
+ v.reset(OpARMMVN)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueARM_OpConst16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Const16 [val])
+ // cond:
+ // result: (MOVWconst [val])
+ for {
+ val := v.AuxInt
+ v.reset(OpARMMOVWconst)
+ v.AuxInt = val
+ return true
+ }
+}
+func rewriteValueARM_OpConst32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Const32 [val])
+ // cond:
+ // result: (MOVWconst [val])
+ for {
+ val := v.AuxInt
+ v.reset(OpARMMOVWconst)
+ v.AuxInt = val
+ return true
+ }
+}
+func rewriteValueARM_OpConst32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Const32F [val])
+ // cond:
+ // result: (MOVFconst [val])
+ for {
+ val := v.AuxInt
+ v.reset(OpARMMOVFconst)
+ v.AuxInt = val
+ return true
+ }
+}
+func rewriteValueARM_OpConst64F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Const64F [val])
+ // cond:
+ // result: (MOVDconst [val])
+ for {
+ val := v.AuxInt
+ v.reset(OpARMMOVDconst)
+ v.AuxInt = val
+ return true
+ }
+}
+func rewriteValueARM_OpConst8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Const8 [val])
+ // cond:
+ // result: (MOVWconst [val])
+ for {
+ val := v.AuxInt
+ v.reset(OpARMMOVWconst)
+ v.AuxInt = val
+ return true
+ }
+}
+func rewriteValueARM_OpConstBool(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ConstBool [b])
+ // cond:
+ // result: (MOVWconst [b])
+ for {
+ b := v.AuxInt
+ v.reset(OpARMMOVWconst)
+ v.AuxInt = b
+ return true
+ }
+}
+func rewriteValueARM_OpConstNil(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ConstNil)
+ // cond:
+ // result: (MOVWconst [0])
+ for {
+ v.reset(OpARMMOVWconst)
+ v.AuxInt = 0
+ return true
+ }
+}
+func rewriteValueARM_OpConvert(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Convert x mem)
+ // cond:
+ // result: (MOVWconvert x mem)
+ for {
+ x := v.Args[0]
+ mem := v.Args[1]
+ v.reset(OpARMMOVWconvert)
+ v.AddArg(x)
+ v.AddArg(mem)
+ return true
+ }
+}
+func rewriteValueARM_OpCtz32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Ctz32 <t> x)
+ // cond:
+ // result: (RSBconst [32] (CLZ <t> (SUBconst <t> (AND <t> x (RSBconst <t> [0] x)) [1])))
+ for {
+ t := v.Type
+ x := v.Args[0]
+ v.reset(OpARMRSBconst)
+ v.AuxInt = 32
+ v0 := b.NewValue0(v.Line, OpARMCLZ, t)
+ v1 := b.NewValue0(v.Line, OpARMSUBconst, t)
+ v1.AuxInt = 1
+ v2 := b.NewValue0(v.Line, OpARMAND, t)
+ v2.AddArg(x)
+ v3 := b.NewValue0(v.Line, OpARMRSBconst, t)
+ v3.AuxInt = 0
+ v3.AddArg(x)
+ v2.AddArg(v3)
+ v1.AddArg(v2)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueARM_OpCvt32Fto32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Cvt32Fto32 x)
+ // cond:
+ // result: (MOVFW x)
+ for {
+ x := v.Args[0]
+ v.reset(OpARMMOVFW)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueARM_OpCvt32Fto32U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Cvt32Fto32U x)
+ // cond:
+ // result: (MOVFWU x)
+ for {
+ x := v.Args[0]
+ v.reset(OpARMMOVFWU)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueARM_OpCvt32Fto64F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Cvt32Fto64F x)
+ // cond:
+ // result: (MOVFD x)
+ for {
+ x := v.Args[0]
+ v.reset(OpARMMOVFD)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueARM_OpCvt32Uto32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Cvt32Uto32F x)
+ // cond:
+ // result: (MOVWUF x)
+ for {
+ x := v.Args[0]
+ v.reset(OpARMMOVWUF)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueARM_OpCvt32Uto64F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Cvt32Uto64F x)
+ // cond:
+ // result: (MOVWUD x)
+ for {
+ x := v.Args[0]
+ v.reset(OpARMMOVWUD)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueARM_OpCvt32to32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Cvt32to32F x)
+ // cond:
+ // result: (MOVWF x)
+ for {
+ x := v.Args[0]
+ v.reset(OpARMMOVWF)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueARM_OpCvt32to64F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Cvt32to64F x)
+ // cond:
+ // result: (MOVWD x)
+ for {
+ x := v.Args[0]
+ v.reset(OpARMMOVWD)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueARM_OpCvt64Fto32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Cvt64Fto32 x)
+ // cond:
+ // result: (MOVDW x)
+ for {
+ x := v.Args[0]
+ v.reset(OpARMMOVDW)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueARM_OpCvt64Fto32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Cvt64Fto32F x)
+ // cond:
+ // result: (MOVDF x)
+ for {
+ x := v.Args[0]
+ v.reset(OpARMMOVDF)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueARM_OpCvt64Fto32U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Cvt64Fto32U x)
+ // cond:
+ // result: (MOVDWU x)
+ for {
+ x := v.Args[0]
+ v.reset(OpARMMOVDWU)
+ v.AddArg(x)
+ 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 {
+ b := v.Block
+ _ = b
+ // match: (Div16 x y)
+ // cond:
+ // result: (Div32 (SignExt16to32 x) (SignExt16to32 y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpDiv32)
+ v0 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
+ v1.AddArg(y)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueARM_OpDiv16u(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Div16u x y)
+ // cond:
+ // result: (Div32u (ZeroExt16to32 x) (ZeroExt16to32 y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpDiv32u)
+ v0 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+ v1.AddArg(y)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueARM_OpDiv32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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)))
+ for {
+ 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())
+ v4.AddArg(x)
+ v5 := b.NewValue0(v.Line, OpSignmask, config.fe.TypeInt32())
+ v5.AddArg(x)
+ v4.AddArg(v5)
+ v3.AddArg(v4)
+ v6 := b.NewValue0(v.Line, OpSignmask, config.fe.TypeInt32())
+ 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())
+ v8.AddArg(y)
+ v9 := b.NewValue0(v.Line, OpSignmask, config.fe.TypeInt32())
+ v9.AddArg(y)
+ v8.AddArg(v9)
+ v7.AddArg(v8)
+ v10 := b.NewValue0(v.Line, OpSignmask, config.fe.TypeInt32())
+ 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())
+ 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())
+ v14.AddArg(x)
+ v14.AddArg(y)
+ v13.AddArg(v14)
+ v.AddArg(v13)
+ return true
+ }
+}
+func rewriteValueARM_OpDiv32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Div32F x y)
+ // cond:
+ // result: (DIVF x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARMDIVF)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueARM_OpDiv32u(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Div32u x y)
+ // cond:
+ // result: (Select0 <config.fe.TypeUInt32()> (UDIVrtcall x y))
+ for {
+ 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()))
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueARM_OpDiv64F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Div64F x y)
+ // cond:
+ // result: (DIVD x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARMDIVD)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueARM_OpDiv8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Div8 x y)
+ // cond:
+ // result: (Div32 (SignExt8to32 x) (SignExt8to32 y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpDiv32)
+ v0 := b.NewValue0(v.Line, OpSignExt8to32, config.fe.TypeInt32())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpSignExt8to32, config.fe.TypeInt32())
+ v1.AddArg(y)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueARM_OpDiv8u(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Div8u x y)
+ // cond:
+ // result: (Div32u (ZeroExt8to32 x) (ZeroExt8to32 y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpDiv32u)
+ v0 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+ v1.AddArg(y)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueARM_OpEq16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Eq16 x y)
+ // cond:
+ // result: (Equal (CMP (ZeroExt16to32 x) (ZeroExt16to32 y)))
+ for {
+ 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())
+ 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 rewriteValueARM_OpEq32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Eq32 x y)
+ // cond:
+ // result: (Equal (CMP x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARMEqual)
+ v0 := b.NewValue0(v.Line, OpARMCMP, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueARM_OpEq32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Eq32F x y)
+ // cond:
+ // result: (Equal (CMPF x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARMEqual)
+ v0 := b.NewValue0(v.Line, OpARMCMPF, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueARM_OpEq64F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Eq64F x y)
+ // cond:
+ // result: (Equal (CMPD x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARMEqual)
+ v0 := b.NewValue0(v.Line, OpARMCMPD, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueARM_OpEq8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Eq8 x y)
+ // cond:
+ // result: (Equal (CMP (ZeroExt8to32 x) (ZeroExt8to32 y)))
+ for {
+ 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())
+ 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_OpEqB(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (EqB x y)
+ // cond:
+ // result: (XORconst [1] (XOR <config.fe.TypeBool()> x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARMXORconst)
+ v.AuxInt = 1
+ v0 := b.NewValue0(v.Line, OpARMXOR, config.fe.TypeBool())
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueARM_OpEqPtr(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (EqPtr x y)
+ // cond:
+ // result: (Equal (CMP x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARMEqual)
+ v0 := b.NewValue0(v.Line, OpARMCMP, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueARM_OpGeq16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Geq16 x y)
+ // cond:
+ // result: (GreaterEqual (CMP (SignExt16to32 x) (SignExt16to32 y)))
+ for {
+ 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())
+ 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_OpGeq16U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Geq16U x y)
+ // cond:
+ // result: (GreaterEqualU (CMP (ZeroExt16to32 x) (ZeroExt16to32 y)))
+ for {
+ 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())
+ 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 rewriteValueARM_OpGeq32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Geq32 x y)
+ // cond:
+ // result: (GreaterEqual (CMP x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARMGreaterEqual)
+ v0 := b.NewValue0(v.Line, OpARMCMP, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueARM_OpGeq32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Geq32F x y)
+ // cond:
+ // result: (GreaterEqual (CMPF x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARMGreaterEqual)
+ v0 := b.NewValue0(v.Line, OpARMCMPF, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueARM_OpGeq32U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Geq32U x y)
+ // cond:
+ // result: (GreaterEqualU (CMP x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARMGreaterEqualU)
+ v0 := b.NewValue0(v.Line, OpARMCMP, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueARM_OpGeq64F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Geq64F x y)
+ // cond:
+ // result: (GreaterEqual (CMPD x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARMGreaterEqual)
+ v0 := b.NewValue0(v.Line, OpARMCMPD, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueARM_OpGeq8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Geq8 x y)
+ // cond:
+ // result: (GreaterEqual (CMP (SignExt8to32 x) (SignExt8to32 y)))
+ for {
+ 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())
+ 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_OpGeq8U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Geq8U x y)
+ // cond:
+ // result: (GreaterEqualU (CMP (ZeroExt8to32 x) (ZeroExt8to32 y)))
+ for {
+ 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())
+ 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_OpGetClosurePtr(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (GetClosurePtr)
+ // cond:
+ // result: (LoweredGetClosurePtr)
+ for {
+ v.reset(OpARMLoweredGetClosurePtr)
+ 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 {
+ b := v.Block
+ _ = b
+ // match: (Greater16 x y)
+ // cond:
+ // result: (GreaterThan (CMP (SignExt16to32 x) (SignExt16to32 y)))
+ for {
+ 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())
+ 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_OpGreater16U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Greater16U x y)
+ // cond:
+ // result: (GreaterThanU (CMP (ZeroExt16to32 x) (ZeroExt16to32 y)))
+ for {
+ 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())
+ 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 rewriteValueARM_OpGreater32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Greater32 x y)
+ // cond:
+ // result: (GreaterThan (CMP x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARMGreaterThan)
+ v0 := b.NewValue0(v.Line, OpARMCMP, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueARM_OpGreater32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Greater32F x y)
+ // cond:
+ // result: (GreaterThan (CMPF x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARMGreaterThan)
+ v0 := b.NewValue0(v.Line, OpARMCMPF, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueARM_OpGreater32U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Greater32U x y)
+ // cond:
+ // result: (GreaterThanU (CMP x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARMGreaterThanU)
+ v0 := b.NewValue0(v.Line, OpARMCMP, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueARM_OpGreater64F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Greater64F x y)
+ // cond:
+ // result: (GreaterThan (CMPD x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARMGreaterThan)
+ v0 := b.NewValue0(v.Line, OpARMCMPD, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueARM_OpGreater8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Greater8 x y)
+ // cond:
+ // result: (GreaterThan (CMP (SignExt8to32 x) (SignExt8to32 y)))
+ for {
+ 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())
+ 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_OpGreater8U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Greater8U x y)
+ // cond:
+ // result: (GreaterThanU (CMP (ZeroExt8to32 x) (ZeroExt8to32 y)))
+ for {
+ 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())
+ 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 rewriteValueARM_OpHmul32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Hmul32 x y)
+ // cond:
+ // result: (HMUL x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARMHMUL)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueARM_OpHmul32u(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Hmul32u x y)
+ // cond:
+ // result: (HMULU x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARMHMULU)
+ v.AddArg(x)
+ v.AddArg(y)
+ 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
+ // 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(OpARMCALLinter)
+ v.AuxInt = argwid
+ v.AddArg(entry)
+ v.AddArg(mem)
+ return true
+ }
+}
+func rewriteValueARM_OpIsInBounds(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (IsInBounds idx len)
+ // cond:
+ // result: (LessThanU (CMP idx len))
+ for {
+ idx := v.Args[0]
+ len := v.Args[1]
+ v.reset(OpARMLessThanU)
+ v0 := b.NewValue0(v.Line, OpARMCMP, TypeFlags)
+ v0.AddArg(idx)
+ v0.AddArg(len)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueARM_OpIsNonNil(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (IsNonNil ptr)
+ // cond:
+ // result: (NotEqual (CMPconst [0] ptr))
+ for {
+ ptr := v.Args[0]
+ v.reset(OpARMNotEqual)
+ v0 := b.NewValue0(v.Line, OpARMCMPconst, TypeFlags)
+ v0.AuxInt = 0
+ v0.AddArg(ptr)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueARM_OpIsSliceInBounds(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (IsSliceInBounds idx len)
+ // cond:
+ // result: (LessEqualU (CMP idx len))
+ for {
+ idx := v.Args[0]
+ len := v.Args[1]
+ v.reset(OpARMLessEqualU)
+ v0 := b.NewValue0(v.Line, OpARMCMP, TypeFlags)
+ v0.AddArg(idx)
+ v0.AddArg(len)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueARM_OpLeq16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Leq16 x y)
+ // cond:
+ // result: (LessEqual (CMP (SignExt16to32 x) (SignExt16to32 y)))
+ for {
+ 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())
+ 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_OpLeq16U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Leq16U x y)
+ // cond:
+ // result: (LessEqualU (CMP (ZeroExt16to32 x) (ZeroExt16to32 y)))
+ for {
+ 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())
+ 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 rewriteValueARM_OpLeq32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Leq32 x y)
+ // cond:
+ // result: (LessEqual (CMP x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARMLessEqual)
+ v0 := b.NewValue0(v.Line, OpARMCMP, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueARM_OpLeq32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Leq32F x y)
+ // cond:
+ // result: (GreaterEqual (CMPF y x))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARMGreaterEqual)
+ v0 := b.NewValue0(v.Line, OpARMCMPF, TypeFlags)
+ v0.AddArg(y)
+ v0.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueARM_OpLeq32U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Leq32U x y)
+ // cond:
+ // result: (LessEqualU (CMP x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARMLessEqualU)
+ v0 := b.NewValue0(v.Line, OpARMCMP, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueARM_OpLeq64F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Leq64F x y)
+ // cond:
+ // result: (GreaterEqual (CMPD y x))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARMGreaterEqual)
+ v0 := b.NewValue0(v.Line, OpARMCMPD, TypeFlags)
+ v0.AddArg(y)
+ v0.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueARM_OpLeq8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Leq8 x y)
+ // cond:
+ // result: (LessEqual (CMP (SignExt8to32 x) (SignExt8to32 y)))
+ for {
+ 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())
+ 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_OpLeq8U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Leq8U x y)
+ // cond:
+ // result: (LessEqualU (CMP (ZeroExt8to32 x) (ZeroExt8to32 y)))
+ for {
+ 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())
+ 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_OpLess16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Less16 x y)
+ // cond:
+ // result: (LessThan (CMP (SignExt16to32 x) (SignExt16to32 y)))
+ for {
+ 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())
+ 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_OpLess16U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Less16U x y)
+ // cond:
+ // result: (LessThanU (CMP (ZeroExt16to32 x) (ZeroExt16to32 y)))
+ for {
+ 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())
+ 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 rewriteValueARM_OpLess32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Less32 x y)
+ // cond:
+ // result: (LessThan (CMP x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARMLessThan)
+ v0 := b.NewValue0(v.Line, OpARMCMP, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueARM_OpLess32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Less32F x y)
+ // cond:
+ // result: (GreaterThan (CMPF y x))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARMGreaterThan)
+ v0 := b.NewValue0(v.Line, OpARMCMPF, TypeFlags)
+ v0.AddArg(y)
+ v0.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueARM_OpLess32U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Less32U x y)
+ // cond:
+ // result: (LessThanU (CMP x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARMLessThanU)
+ v0 := b.NewValue0(v.Line, OpARMCMP, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueARM_OpLess64F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Less64F x y)
+ // cond:
+ // result: (GreaterThan (CMPD y x))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARMGreaterThan)
+ v0 := b.NewValue0(v.Line, OpARMCMPD, TypeFlags)
+ v0.AddArg(y)
+ v0.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueARM_OpLess8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Less8 x y)
+ // cond:
+ // result: (LessThan (CMP (SignExt8to32 x) (SignExt8to32 y)))
+ for {
+ 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())
+ 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_OpLess8U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Less8U x y)
+ // cond:
+ // result: (LessThanU (CMP (ZeroExt8to32 x) (ZeroExt8to32 y)))
+ for {
+ 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())
+ 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_OpLoad(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Load <t> ptr mem)
+ // cond: t.IsBoolean()
+ // result: (MOVBUload ptr mem)
+ for {
+ t := v.Type
+ ptr := v.Args[0]
+ mem := v.Args[1]
+ if !(t.IsBoolean()) {
+ break
+ }
+ v.reset(OpARMMOVBUload)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (Load <t> ptr mem)
+ // cond: (is8BitInt(t) && isSigned(t))
+ // result: (MOVBload ptr mem)
+ for {
+ t := v.Type
+ ptr := v.Args[0]
+ mem := v.Args[1]
+ if !(is8BitInt(t) && isSigned(t)) {
+ break
+ }
+ v.reset(OpARMMOVBload)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (Load <t> ptr mem)
+ // cond: (is8BitInt(t) && !isSigned(t))
+ // result: (MOVBUload ptr mem)
+ for {
+ t := v.Type
+ ptr := v.Args[0]
+ mem := v.Args[1]
+ if !(is8BitInt(t) && !isSigned(t)) {
+ break
+ }
+ v.reset(OpARMMOVBUload)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (Load <t> ptr mem)
+ // cond: (is16BitInt(t) && isSigned(t))
+ // result: (MOVHload ptr mem)
+ for {
+ t := v.Type
+ ptr := v.Args[0]
+ mem := v.Args[1]
+ if !(is16BitInt(t) && isSigned(t)) {
+ break
+ }
+ v.reset(OpARMMOVHload)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (Load <t> ptr mem)
+ // cond: (is16BitInt(t) && !isSigned(t))
+ // result: (MOVHUload ptr mem)
+ for {
+ t := v.Type
+ ptr := v.Args[0]
+ mem := v.Args[1]
+ if !(is16BitInt(t) && !isSigned(t)) {
+ break
+ }
+ v.reset(OpARMMOVHUload)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (Load <t> ptr mem)
+ // cond: (is32BitInt(t) || isPtr(t))
+ // result: (MOVWload ptr mem)
+ for {
+ t := v.Type
+ ptr := v.Args[0]
+ mem := v.Args[1]
+ if !(is32BitInt(t) || isPtr(t)) {
+ break
+ }
+ v.reset(OpARMMOVWload)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (Load <t> ptr mem)
+ // cond: is32BitFloat(t)
+ // result: (MOVFload ptr mem)
+ for {
+ t := v.Type
+ ptr := v.Args[0]
+ mem := v.Args[1]
+ if !(is32BitFloat(t)) {
+ break
+ }
+ v.reset(OpARMMOVFload)
+ v.AddArg(ptr)
+ 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> 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
+ v1.AddArg(x)
+ 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> x [8-c&7]))
+ 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
+ v1.AddArg(x)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueARM_OpLsh16x16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Lsh16x16 x y)
+ // cond:
+ // result: (CMOVWHSconst (SLL <x.Type> x (ZeroExt16to32 y)) (CMPconst [256] (ZeroExt16to32 y)) [0])
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARMCMOVWHSconst)
+ v.AuxInt = 0
+ v0 := b.NewValue0(v.Line, OpARMSLL, x.Type)
+ v0.AddArg(x)
+ v1 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+ v1.AddArg(y)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ v2 := b.NewValue0(v.Line, OpARMCMPconst, TypeFlags)
+ v2.AuxInt = 256
+ v3 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+ v3.AddArg(y)
+ v2.AddArg(v3)
+ v.AddArg(v2)
+ return true
+ }
+}
+func rewriteValueARM_OpLsh16x32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Lsh16x32 x y)
+ // cond:
+ // result: (CMOVWHSconst (SLL <x.Type> x y) (CMPconst [256] y) [0])
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARMCMOVWHSconst)
+ v.AuxInt = 0
+ v0 := b.NewValue0(v.Line, OpARMSLL, x.Type)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpARMCMPconst, TypeFlags)
+ v1.AuxInt = 256
+ v1.AddArg(y)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueARM_OpLsh16x64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Lsh16x64 x (Const64 [c]))
+ // cond: uint64(c) < 16
+ // result: (SLLconst x [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpConst64 {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint64(c) < 16) {
+ break
+ }
+ v.reset(OpARMSLLconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (Lsh16x64 _ (Const64 [c]))
+ // cond: uint64(c) >= 16
+ // result: (Const16 [0])
+ for {
+ v_1 := v.Args[1]
+ if v_1.Op != OpConst64 {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint64(c) >= 16) {
+ break
+ }
+ v.reset(OpConst16)
+ v.AuxInt = 0
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpLsh16x8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Lsh16x8 x y)
+ // cond:
+ // result: (SLL x (ZeroExt8to32 y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARMSLL)
+ v.AddArg(x)
+ v0 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueARM_OpLsh32x16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Lsh32x16 x y)
+ // cond:
+ // result: (CMOVWHSconst (SLL <x.Type> x (ZeroExt16to32 y)) (CMPconst [256] (ZeroExt16to32 y)) [0])
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARMCMOVWHSconst)
+ v.AuxInt = 0
+ v0 := b.NewValue0(v.Line, OpARMSLL, x.Type)
+ v0.AddArg(x)
+ v1 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+ v1.AddArg(y)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ v2 := b.NewValue0(v.Line, OpARMCMPconst, TypeFlags)
+ v2.AuxInt = 256
+ v3 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+ v3.AddArg(y)
+ v2.AddArg(v3)
+ v.AddArg(v2)
+ return true
+ }
+}
+func rewriteValueARM_OpLsh32x32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Lsh32x32 x y)
+ // cond:
+ // result: (CMOVWHSconst (SLL <x.Type> x y) (CMPconst [256] y) [0])
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARMCMOVWHSconst)
+ v.AuxInt = 0
+ v0 := b.NewValue0(v.Line, OpARMSLL, x.Type)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpARMCMPconst, TypeFlags)
+ v1.AuxInt = 256
+ v1.AddArg(y)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueARM_OpLsh32x64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Lsh32x64 x (Const64 [c]))
+ // cond: uint64(c) < 32
+ // result: (SLLconst x [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpConst64 {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint64(c) < 32) {
+ break
+ }
+ v.reset(OpARMSLLconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (Lsh32x64 _ (Const64 [c]))
+ // cond: uint64(c) >= 32
+ // result: (Const32 [0])
+ for {
+ v_1 := v.Args[1]
+ if v_1.Op != OpConst64 {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint64(c) >= 32) {
+ break
+ }
+ v.reset(OpConst32)
+ v.AuxInt = 0
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpLsh32x8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Lsh32x8 x y)
+ // cond:
+ // result: (SLL x (ZeroExt8to32 y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARMSLL)
+ v.AddArg(x)
+ v0 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueARM_OpLsh8x16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Lsh8x16 x y)
+ // cond:
+ // result: (CMOVWHSconst (SLL <x.Type> x (ZeroExt16to32 y)) (CMPconst [256] (ZeroExt16to32 y)) [0])
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARMCMOVWHSconst)
+ v.AuxInt = 0
+ v0 := b.NewValue0(v.Line, OpARMSLL, x.Type)
+ v0.AddArg(x)
+ v1 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+ v1.AddArg(y)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ v2 := b.NewValue0(v.Line, OpARMCMPconst, TypeFlags)
+ v2.AuxInt = 256
+ v3 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+ v3.AddArg(y)
+ v2.AddArg(v3)
+ v.AddArg(v2)
+ return true
+ }
+}
+func rewriteValueARM_OpLsh8x32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Lsh8x32 x y)
+ // cond:
+ // result: (CMOVWHSconst (SLL <x.Type> x y) (CMPconst [256] y) [0])
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARMCMOVWHSconst)
+ v.AuxInt = 0
+ v0 := b.NewValue0(v.Line, OpARMSLL, x.Type)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpARMCMPconst, TypeFlags)
+ v1.AuxInt = 256
+ v1.AddArg(y)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueARM_OpLsh8x64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Lsh8x64 x (Const64 [c]))
+ // cond: uint64(c) < 8
+ // result: (SLLconst x [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpConst64 {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint64(c) < 8) {
+ break
+ }
+ v.reset(OpARMSLLconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (Lsh8x64 _ (Const64 [c]))
+ // cond: uint64(c) >= 8
+ // result: (Const8 [0])
+ for {
+ v_1 := v.Args[1]
+ if v_1.Op != OpConst64 {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint64(c) >= 8) {
+ break
+ }
+ v.reset(OpConst8)
+ v.AuxInt = 0
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpLsh8x8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Lsh8x8 x y)
+ // cond:
+ // result: (SLL x (ZeroExt8to32 y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARMSLL)
+ v.AddArg(x)
+ v0 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueARM_OpMod16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Mod16 x y)
+ // cond:
+ // result: (Mod32 (SignExt16to32 x) (SignExt16to32 y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMod32)
+ v0 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
+ v1.AddArg(y)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueARM_OpMod16u(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Mod16u x y)
+ // cond:
+ // result: (Mod32u (ZeroExt16to32 x) (ZeroExt16to32 y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMod32u)
+ v0 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+ v1.AddArg(y)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueARM_OpMod32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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))
+ for {
+ 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())
+ v4.AddArg(x)
+ v5 := b.NewValue0(v.Line, OpSignmask, config.fe.TypeInt32())
+ v5.AddArg(x)
+ v4.AddArg(v5)
+ v3.AddArg(v4)
+ v6 := b.NewValue0(v.Line, OpSignmask, config.fe.TypeInt32())
+ 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())
+ v8.AddArg(y)
+ v9 := b.NewValue0(v.Line, OpSignmask, config.fe.TypeInt32())
+ v9.AddArg(y)
+ v8.AddArg(v9)
+ v7.AddArg(v8)
+ v10 := b.NewValue0(v.Line, OpSignmask, config.fe.TypeInt32())
+ 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.AddArg(x)
+ v0.AddArg(v11)
+ v.AddArg(v0)
+ v12 := b.NewValue0(v.Line, OpSignmask, config.fe.TypeInt32())
+ v12.AddArg(x)
+ v.AddArg(v12)
+ return true
+ }
+}
+func rewriteValueARM_OpMod32u(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Mod32u x y)
+ // cond:
+ // result: (Select1 <config.fe.TypeUInt32()> (UDIVrtcall x y))
+ for {
+ 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()))
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueARM_OpMod8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Mod8 x y)
+ // cond:
+ // result: (Mod32 (SignExt8to32 x) (SignExt8to32 y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMod32)
+ v0 := b.NewValue0(v.Line, OpSignExt8to32, config.fe.TypeInt32())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpSignExt8to32, config.fe.TypeInt32())
+ v1.AddArg(y)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueARM_OpMod8u(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Mod8u x y)
+ // cond:
+ // result: (Mod32u (ZeroExt8to32 x) (ZeroExt8to32 y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMod32u)
+ v0 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+ v1.AddArg(y)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueARM_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) {
+ 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 (MOVBUload src mem) mem)
+ for {
+ s := v.AuxInt
+ 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.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
+ // result: (MOVHstore dst (MOVHUload src mem) mem)
+ for {
+ s := v.AuxInt
+ 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(OpARMMOVHstore)
+ v.AddArg(dst)
+ v0 := b.NewValue0(v.Line, OpARMMOVHUload, 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() == 2
+ // result: (MOVBstore [1] dst (MOVBUload [1] src mem) (MOVBstore dst (MOVBUload src mem) mem))
+ for {
+ s := v.AuxInt
+ 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.AuxInt = 1
+ v0.AddArg(src)
+ v0.AddArg(mem)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpARMMOVBstore, TypeMem)
+ v1.AddArg(dst)
+ v2 := b.NewValue0(v.Line, OpARMMOVBUload, config.fe.TypeUInt8())
+ v2.AddArg(src)
+ v2.AddArg(mem)
+ v1.AddArg(v2)
+ v1.AddArg(mem)
+ v.AddArg(v1)
+ 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)
+ for {
+ s := v.AuxInt
+ dst := v.Args[0]
+ src := v.Args[1]
+ mem := v.Args[2]
+ if !(SizeAndAlign(s).Size() == 4 && SizeAndAlign(s).Align()%4 == 0) {
+ break
+ }
+ v.reset(OpARMMOVWstore)
+ v.AddArg(dst)
+ v0 := b.NewValue0(v.Line, OpARMMOVWload, 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() == 4 && SizeAndAlign(s).Align()%2 == 0
+ // result: (MOVHstore [2] dst (MOVHUload [2] src mem) (MOVHstore dst (MOVHUload src mem) mem))
+ for {
+ s := v.AuxInt
+ 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(OpARMMOVHstore)
+ v.AuxInt = 2
+ v.AddArg(dst)
+ v0 := b.NewValue0(v.Line, OpARMMOVHUload, config.fe.TypeUInt16())
+ v0.AuxInt = 2
+ v0.AddArg(src)
+ v0.AddArg(mem)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpARMMOVHstore, TypeMem)
+ v1.AddArg(dst)
+ v2 := b.NewValue0(v.Line, OpARMMOVHUload, config.fe.TypeUInt16())
+ v2.AddArg(src)
+ v2.AddArg(mem)
+ v1.AddArg(v2)
+ v1.AddArg(mem)
+ v.AddArg(v1)
+ return true
+ }
+ // match: (Move [s] dst src mem)
+ // cond: SizeAndAlign(s).Size() == 4
+ // 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
+ 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.AuxInt = 3
+ v0.AddArg(src)
+ v0.AddArg(mem)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpARMMOVBstore, TypeMem)
+ v1.AuxInt = 2
+ v1.AddArg(dst)
+ v2 := b.NewValue0(v.Line, OpARMMOVBUload, config.fe.TypeUInt8())
+ v2.AuxInt = 2
+ v2.AddArg(src)
+ v2.AddArg(mem)
+ v1.AddArg(v2)
+ v3 := b.NewValue0(v.Line, OpARMMOVBstore, TypeMem)
+ v3.AuxInt = 1
+ v3.AddArg(dst)
+ v4 := b.NewValue0(v.Line, OpARMMOVBUload, config.fe.TypeUInt8())
+ v4.AuxInt = 1
+ v4.AddArg(src)
+ v4.AddArg(mem)
+ v3.AddArg(v4)
+ v5 := b.NewValue0(v.Line, OpARMMOVBstore, TypeMem)
+ v5.AddArg(dst)
+ v6 := b.NewValue0(v.Line, OpARMMOVBUload, config.fe.TypeUInt8())
+ v6.AddArg(src)
+ v6.AddArg(mem)
+ v5.AddArg(v6)
+ v5.AddArg(mem)
+ v3.AddArg(v5)
+ v1.AddArg(v3)
+ v.AddArg(v1)
+ return true
+ }
+ // match: (Move [s] dst src mem)
+ // cond: SizeAndAlign(s).Size() == 3
+ // 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
+ 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.AuxInt = 2
+ v0.AddArg(src)
+ v0.AddArg(mem)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpARMMOVBstore, TypeMem)
+ v1.AuxInt = 1
+ v1.AddArg(dst)
+ v2 := b.NewValue0(v.Line, OpARMMOVBUload, config.fe.TypeUInt8())
+ v2.AuxInt = 1
+ v2.AddArg(src)
+ v2.AddArg(mem)
+ v1.AddArg(v2)
+ v3 := b.NewValue0(v.Line, OpARMMOVBstore, TypeMem)
+ v3.AddArg(dst)
+ v4 := b.NewValue0(v.Line, OpARMMOVBUload, config.fe.TypeUInt8())
+ v4.AddArg(src)
+ v4.AddArg(mem)
+ v3.AddArg(v4)
+ v3.AddArg(mem)
+ v1.AddArg(v3)
+ 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)
+ for {
+ s := v.AuxInt
+ 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) {
+ break
+ }
+ v.reset(OpARMDUFFCOPY)
+ v.AuxInt = 8 * (128 - int64(SizeAndAlign(s).Size()/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)
+ for {
+ s := v.AuxInt
+ dst := v.Args[0]
+ src := v.Args[1]
+ mem := v.Args[2]
+ if !((SizeAndAlign(s).Size() > 512 || config.noDuffDevice) || SizeAndAlign(s).Align()%4 != 0) {
+ break
+ }
+ v.reset(OpARMLoweredMove)
+ v.AuxInt = SizeAndAlign(s).Align()
+ 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.AddArg(src)
+ v.AddArg(v0)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpMul16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Mul16 x y)
+ // cond:
+ // result: (MUL x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARMMUL)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueARM_OpMul32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Mul32 x y)
+ // cond:
+ // result: (MUL x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARMMUL)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueARM_OpMul32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Mul32F x y)
+ // cond:
+ // result: (MULF x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARMMULF)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueARM_OpMul32uhilo(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Mul32uhilo x y)
+ // cond:
+ // result: (MULLU x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARMMULLU)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueARM_OpMul64F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Mul64F x y)
+ // cond:
+ // result: (MULD x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARMMULD)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueARM_OpMul8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Mul8 x y)
+ // cond:
+ // result: (MUL x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARMMUL)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueARM_OpNeg16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Neg16 x)
+ // cond:
+ // result: (RSBconst [0] x)
+ for {
+ x := v.Args[0]
+ v.reset(OpARMRSBconst)
+ v.AuxInt = 0
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueARM_OpNeg32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Neg32 x)
+ // cond:
+ // result: (RSBconst [0] x)
+ for {
+ x := v.Args[0]
+ v.reset(OpARMRSBconst)
+ v.AuxInt = 0
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueARM_OpNeg32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Neg32F x)
+ // cond:
+ // result: (NEGF x)
+ for {
+ x := v.Args[0]
+ v.reset(OpARMNEGF)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueARM_OpNeg64F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Neg64F x)
+ // cond:
+ // result: (NEGD x)
+ for {
+ x := v.Args[0]
+ v.reset(OpARMNEGD)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueARM_OpNeg8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Neg8 x)
+ // cond:
+ // result: (RSBconst [0] x)
+ for {
+ x := v.Args[0]
+ v.reset(OpARMRSBconst)
+ v.AuxInt = 0
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueARM_OpNeq16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Neq16 x y)
+ // cond:
+ // result: (NotEqual (CMP (ZeroExt16to32 x) (ZeroExt16to32 y)))
+ for {
+ 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())
+ 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 rewriteValueARM_OpNeq32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Neq32 x y)
+ // cond:
+ // result: (NotEqual (CMP x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARMNotEqual)
+ v0 := b.NewValue0(v.Line, OpARMCMP, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueARM_OpNeq32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Neq32F x y)
+ // cond:
+ // result: (NotEqual (CMPF x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARMNotEqual)
+ v0 := b.NewValue0(v.Line, OpARMCMPF, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueARM_OpNeq64F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Neq64F x y)
+ // cond:
+ // result: (NotEqual (CMPD x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARMNotEqual)
+ v0 := b.NewValue0(v.Line, OpARMCMPD, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueARM_OpNeq8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Neq8 x y)
+ // cond:
+ // result: (NotEqual (CMP (ZeroExt8to32 x) (ZeroExt8to32 y)))
+ for {
+ 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())
+ 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_OpNeqB(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (NeqB x y)
+ // cond:
+ // result: (XOR x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARMXOR)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueARM_OpNeqPtr(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (NeqPtr x y)
+ // cond:
+ // result: (NotEqual (CMP x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARMNotEqual)
+ v0 := b.NewValue0(v.Line, OpARMCMP, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueARM_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(OpARMLoweredNilCheck)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+}
+func rewriteValueARM_OpNot(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Not x)
+ // cond:
+ // result: (XORconst [1] x)
+ for {
+ x := v.Args[0]
+ v.reset(OpARMXORconst)
+ v.AuxInt = 1
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueARM_OpOffPtr(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (OffPtr [off] ptr:(SP))
+ // cond:
+ // result: (MOVWaddr [off] ptr)
+ for {
+ off := v.AuxInt
+ ptr := v.Args[0]
+ if ptr.Op != OpSP {
+ break
+ }
+ v.reset(OpARMMOVWaddr)
+ v.AuxInt = off
+ v.AddArg(ptr)
+ return true
+ }
+ // match: (OffPtr [off] ptr)
+ // cond:
+ // result: (ADDconst [off] ptr)
+ for {
+ off := v.AuxInt
+ ptr := v.Args[0]
+ v.reset(OpARMADDconst)
+ v.AuxInt = off
+ v.AddArg(ptr)
+ return true
+ }
+}
+func rewriteValueARM_OpOr16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Or16 x y)
+ // cond:
+ // result: (OR x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARMOR)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueARM_OpOr32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Or32 x y)
+ // cond:
+ // result: (OR x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARMOR)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueARM_OpOr8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Or8 x y)
+ // cond:
+ // result: (OR x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARMOR)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueARM_OpOrB(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (OrB x y)
+ // cond:
+ // result: (OR x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARMOR)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueARM_OpRsh16Ux16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh16Ux16 x y)
+ // cond:
+ // result: (CMOVWHSconst (SRL <x.Type> (ZeroExt16to32 x) (ZeroExt16to32 y)) (CMPconst [256] (ZeroExt16to32 y)) [0])
+ for {
+ 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())
+ v1.AddArg(x)
+ v0.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+ v2.AddArg(y)
+ v0.AddArg(v2)
+ v.AddArg(v0)
+ v3 := b.NewValue0(v.Line, OpARMCMPconst, TypeFlags)
+ v3.AuxInt = 256
+ v4 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+ v4.AddArg(y)
+ v3.AddArg(v4)
+ v.AddArg(v3)
+ return true
+ }
+}
+func rewriteValueARM_OpRsh16Ux32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh16Ux32 x y)
+ // cond:
+ // result: (CMOVWHSconst (SRL <x.Type> (ZeroExt16to32 x) y) (CMPconst [256] y) [0])
+ for {
+ 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())
+ v1.AddArg(x)
+ v0.AddArg(v1)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ v2 := b.NewValue0(v.Line, OpARMCMPconst, TypeFlags)
+ v2.AuxInt = 256
+ v2.AddArg(y)
+ v.AddArg(v2)
+ return true
+ }
+}
+func rewriteValueARM_OpRsh16Ux64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh16Ux64 x (Const64 [c]))
+ // cond: uint64(c) < 16
+ // result: (SRLconst (SLLconst <config.fe.TypeUInt32()> x [16]) [c+16])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpConst64 {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint64(c) < 16) {
+ break
+ }
+ v.reset(OpARMSRLconst)
+ v.AuxInt = c + 16
+ v0 := b.NewValue0(v.Line, OpARMSLLconst, config.fe.TypeUInt32())
+ v0.AuxInt = 16
+ v0.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (Rsh16Ux64 _ (Const64 [c]))
+ // cond: uint64(c) >= 16
+ // result: (Const16 [0])
+ for {
+ v_1 := v.Args[1]
+ if v_1.Op != OpConst64 {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint64(c) >= 16) {
+ break
+ }
+ v.reset(OpConst16)
+ v.AuxInt = 0
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpRsh16Ux8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh16Ux8 x y)
+ // cond:
+ // result: (SRL (ZeroExt16to32 x) (ZeroExt8to32 y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARMSRL)
+ v0 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+ v1.AddArg(y)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueARM_OpRsh16x16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh16x16 x y)
+ // cond:
+ // result: (SRAcond (SignExt16to32 x) (ZeroExt16to32 y) (CMPconst [256] (ZeroExt16to32 y)))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARMSRAcond)
+ v0 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+ v1.AddArg(y)
+ v.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpARMCMPconst, TypeFlags)
+ v2.AuxInt = 256
+ v3 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+ v3.AddArg(y)
+ v2.AddArg(v3)
+ v.AddArg(v2)
+ return true
+ }
+}
+func rewriteValueARM_OpRsh16x32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh16x32 x y)
+ // cond:
+ // result: (SRAcond (SignExt16to32 x) y (CMPconst [256] y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARMSRAcond)
+ v0 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v.AddArg(y)
+ v1 := b.NewValue0(v.Line, OpARMCMPconst, TypeFlags)
+ v1.AuxInt = 256
+ v1.AddArg(y)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueARM_OpRsh16x64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh16x64 x (Const64 [c]))
+ // cond: uint64(c) < 16
+ // result: (SRAconst (SLLconst <config.fe.TypeUInt32()> x [16]) [c+16])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpConst64 {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint64(c) < 16) {
+ break
+ }
+ v.reset(OpARMSRAconst)
+ v.AuxInt = c + 16
+ v0 := b.NewValue0(v.Line, OpARMSLLconst, config.fe.TypeUInt32())
+ v0.AuxInt = 16
+ v0.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (Rsh16x64 x (Const64 [c]))
+ // cond: uint64(c) >= 16
+ // result: (SRAconst (SLLconst <config.fe.TypeUInt32()> x [16]) [31])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpConst64 {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint64(c) >= 16) {
+ break
+ }
+ v.reset(OpARMSRAconst)
+ v.AuxInt = 31
+ v0 := b.NewValue0(v.Line, OpARMSLLconst, config.fe.TypeUInt32())
+ v0.AuxInt = 16
+ v0.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpRsh16x8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh16x8 x y)
+ // cond:
+ // result: (SRA (SignExt16to32 x) (ZeroExt8to32 y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARMSRA)
+ v0 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+ v1.AddArg(y)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueARM_OpRsh32Ux16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh32Ux16 x y)
+ // cond:
+ // result: (CMOVWHSconst (SRL <x.Type> x (ZeroExt16to32 y)) (CMPconst [256] (ZeroExt16to32 y)) [0])
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARMCMOVWHSconst)
+ v.AuxInt = 0
+ v0 := b.NewValue0(v.Line, OpARMSRL, x.Type)
+ v0.AddArg(x)
+ v1 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+ v1.AddArg(y)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ v2 := b.NewValue0(v.Line, OpARMCMPconst, TypeFlags)
+ v2.AuxInt = 256
+ v3 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+ v3.AddArg(y)
+ v2.AddArg(v3)
+ v.AddArg(v2)
+ return true
+ }
+}
+func rewriteValueARM_OpRsh32Ux32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh32Ux32 x y)
+ // cond:
+ // result: (CMOVWHSconst (SRL <x.Type> x y) (CMPconst [256] y) [0])
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARMCMOVWHSconst)
+ v.AuxInt = 0
+ v0 := b.NewValue0(v.Line, OpARMSRL, x.Type)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpARMCMPconst, TypeFlags)
+ v1.AuxInt = 256
+ v1.AddArg(y)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueARM_OpRsh32Ux64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh32Ux64 x (Const64 [c]))
+ // cond: uint64(c) < 32
+ // result: (SRLconst x [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpConst64 {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint64(c) < 32) {
+ break
+ }
+ v.reset(OpARMSRLconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (Rsh32Ux64 _ (Const64 [c]))
+ // cond: uint64(c) >= 32
+ // result: (Const32 [0])
+ for {
+ v_1 := v.Args[1]
+ if v_1.Op != OpConst64 {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint64(c) >= 32) {
+ break
+ }
+ v.reset(OpConst32)
+ v.AuxInt = 0
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpRsh32Ux8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh32Ux8 x y)
+ // cond:
+ // result: (SRL x (ZeroExt8to32 y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARMSRL)
+ v.AddArg(x)
+ v0 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueARM_OpRsh32x16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh32x16 x y)
+ // cond:
+ // result: (SRAcond x (ZeroExt16to32 y) (CMPconst [256] (ZeroExt16to32 y)))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARMSRAcond)
+ v.AddArg(x)
+ v0 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+ v0.AddArg(y)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpARMCMPconst, TypeFlags)
+ v1.AuxInt = 256
+ v2 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+ v2.AddArg(y)
+ v1.AddArg(v2)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueARM_OpRsh32x32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh32x32 x y)
+ // cond:
+ // result: (SRAcond x y (CMPconst [256] y))
+ for {
+ 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.AuxInt = 256
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueARM_OpRsh32x64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh32x64 x (Const64 [c]))
+ // cond: uint64(c) < 32
+ // result: (SRAconst x [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpConst64 {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint64(c) < 32) {
+ break
+ }
+ v.reset(OpARMSRAconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (Rsh32x64 x (Const64 [c]))
+ // cond: uint64(c) >= 32
+ // result: (SRAconst x [31])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpConst64 {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint64(c) >= 32) {
+ break
+ }
+ v.reset(OpARMSRAconst)
+ v.AuxInt = 31
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpRsh32x8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh32x8 x y)
+ // cond:
+ // result: (SRA x (ZeroExt8to32 y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARMSRA)
+ v.AddArg(x)
+ v0 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueARM_OpRsh8Ux16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh8Ux16 x y)
+ // cond:
+ // result: (CMOVWHSconst (SRL <x.Type> (ZeroExt8to32 x) (ZeroExt16to32 y)) (CMPconst [256] (ZeroExt16to32 y)) [0])
+ for {
+ 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())
+ v1.AddArg(x)
+ v0.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+ v2.AddArg(y)
+ v0.AddArg(v2)
+ v.AddArg(v0)
+ v3 := b.NewValue0(v.Line, OpARMCMPconst, TypeFlags)
+ v3.AuxInt = 256
+ v4 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+ v4.AddArg(y)
+ v3.AddArg(v4)
+ v.AddArg(v3)
+ return true
+ }
+}
+func rewriteValueARM_OpRsh8Ux32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh8Ux32 x y)
+ // cond:
+ // result: (CMOVWHSconst (SRL <x.Type> (ZeroExt8to32 x) y) (CMPconst [256] y) [0])
+ for {
+ 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())
+ v1.AddArg(x)
+ v0.AddArg(v1)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ v2 := b.NewValue0(v.Line, OpARMCMPconst, TypeFlags)
+ v2.AuxInt = 256
+ v2.AddArg(y)
+ v.AddArg(v2)
+ return true
+ }
+}
+func rewriteValueARM_OpRsh8Ux64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh8Ux64 x (Const64 [c]))
+ // cond: uint64(c) < 8
+ // result: (SRLconst (SLLconst <config.fe.TypeUInt32()> x [24]) [c+24])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpConst64 {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint64(c) < 8) {
+ break
+ }
+ v.reset(OpARMSRLconst)
+ v.AuxInt = c + 24
+ v0 := b.NewValue0(v.Line, OpARMSLLconst, config.fe.TypeUInt32())
+ v0.AuxInt = 24
+ v0.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (Rsh8Ux64 _ (Const64 [c]))
+ // cond: uint64(c) >= 8
+ // result: (Const8 [0])
+ for {
+ v_1 := v.Args[1]
+ if v_1.Op != OpConst64 {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint64(c) >= 8) {
+ break
+ }
+ v.reset(OpConst8)
+ v.AuxInt = 0
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpRsh8Ux8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh8Ux8 x y)
+ // cond:
+ // result: (SRL (ZeroExt8to32 x) (ZeroExt8to32 y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARMSRL)
+ v0 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+ v1.AddArg(y)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueARM_OpRsh8x16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh8x16 x y)
+ // cond:
+ // result: (SRAcond (SignExt8to32 x) (ZeroExt16to32 y) (CMPconst [256] (ZeroExt16to32 y)))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARMSRAcond)
+ v0 := b.NewValue0(v.Line, OpSignExt8to32, config.fe.TypeInt32())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+ v1.AddArg(y)
+ v.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpARMCMPconst, TypeFlags)
+ v2.AuxInt = 256
+ v3 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+ v3.AddArg(y)
+ v2.AddArg(v3)
+ v.AddArg(v2)
+ return true
+ }
+}
+func rewriteValueARM_OpRsh8x32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh8x32 x y)
+ // cond:
+ // result: (SRAcond (SignExt8to32 x) y (CMPconst [256] y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARMSRAcond)
+ v0 := b.NewValue0(v.Line, OpSignExt8to32, config.fe.TypeInt32())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v.AddArg(y)
+ v1 := b.NewValue0(v.Line, OpARMCMPconst, TypeFlags)
+ v1.AuxInt = 256
+ v1.AddArg(y)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueARM_OpRsh8x64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh8x64 x (Const64 [c]))
+ // cond: uint64(c) < 8
+ // result: (SRAconst (SLLconst <config.fe.TypeUInt32()> x [24]) [c+24])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpConst64 {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint64(c) < 8) {
+ break
+ }
+ v.reset(OpARMSRAconst)
+ v.AuxInt = c + 24
+ v0 := b.NewValue0(v.Line, OpARMSLLconst, config.fe.TypeUInt32())
+ v0.AuxInt = 24
+ v0.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (Rsh8x64 x (Const64 [c]))
+ // cond: uint64(c) >= 8
+ // result: (SRAconst (SLLconst <config.fe.TypeUInt32()> x [24]) [31])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpConst64 {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint64(c) >= 8) {
+ break
+ }
+ v.reset(OpARMSRAconst)
+ v.AuxInt = 31
+ v0 := b.NewValue0(v.Line, OpARMSLLconst, config.fe.TypeUInt32())
+ v0.AuxInt = 24
+ v0.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpRsh8x8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh8x8 x y)
+ // cond:
+ // result: (SRA (SignExt8to32 x) (ZeroExt8to32 y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARMSRA)
+ v0 := b.NewValue0(v.Line, OpSignExt8to32, config.fe.TypeInt32())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+ 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])))
+ // cond:
+ // result: x
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMUDIVrtcall {
+ break
+ }
+ x := v_0.Args[0]
+ v_0_1 := v_0.Args[1]
+ if v_0_1.Op != OpARMMOVWconst {
+ break
+ }
+ if v_0_1.AuxInt != 1 {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ // match: (Select0 (UDIVrtcall x (MOVWconst [c])))
+ // cond: isPowerOfTwo(c)
+ // result: (SRLconst [log2(c)] x)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMUDIVrtcall {
+ break
+ }
+ x := v_0.Args[0]
+ v_0_1 := v_0.Args[1]
+ if v_0_1.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_0_1.AuxInt
+ if !(isPowerOfTwo(c)) {
+ break
+ }
+ v.reset(OpARMSRLconst)
+ v.AuxInt = log2(c)
+ v.AddArg(x)
+ return true
+ }
+ // match: (Select0 (UDIVrtcall (MOVWconst [c]) (MOVWconst [d])))
+ // cond:
+ // result: (MOVWconst [int64(uint32(c)/uint32(d))])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMUDIVrtcall {
+ break
+ }
+ v_0_0 := v_0.Args[0]
+ if v_0_0.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_0_0.AuxInt
+ v_0_1 := v_0.Args[1]
+ if v_0_1.Op != OpARMMOVWconst {
+ break
+ }
+ d := v_0_1.AuxInt
+ v.reset(OpARMMOVWconst)
+ v.AuxInt = int64(uint32(c) / uint32(d))
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpSelect1(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Select1 (UDIVrtcall _ (MOVWconst [1])))
+ // cond:
+ // result: (MOVWconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMUDIVrtcall {
+ break
+ }
+ v_0_1 := v_0.Args[1]
+ if v_0_1.Op != OpARMMOVWconst {
+ break
+ }
+ if v_0_1.AuxInt != 1 {
+ break
+ }
+ v.reset(OpARMMOVWconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (Select1 (UDIVrtcall x (MOVWconst [c])))
+ // cond: isPowerOfTwo(c)
+ // result: (ANDconst [c-1] x)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMUDIVrtcall {
+ break
+ }
+ x := v_0.Args[0]
+ v_0_1 := v_0.Args[1]
+ if v_0_1.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_0_1.AuxInt
+ if !(isPowerOfTwo(c)) {
+ break
+ }
+ v.reset(OpARMANDconst)
+ v.AuxInt = c - 1
+ v.AddArg(x)
+ return true
+ }
+ // match: (Select1 (UDIVrtcall (MOVWconst [c]) (MOVWconst [d])))
+ // cond:
+ // result: (MOVWconst [int64(uint32(c)%uint32(d))])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMUDIVrtcall {
+ break
+ }
+ v_0_0 := v_0.Args[0]
+ if v_0_0.Op != OpARMMOVWconst {
+ break
+ }
+ c := v_0_0.AuxInt
+ v_0_1 := v_0.Args[1]
+ if v_0_1.Op != OpARMMOVWconst {
+ break
+ }
+ d := v_0_1.AuxInt
+ v.reset(OpARMMOVWconst)
+ v.AuxInt = int64(uint32(c) % uint32(d))
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpSignExt16to32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SignExt16to32 x)
+ // cond:
+ // result: (MOVHreg x)
+ for {
+ x := v.Args[0]
+ v.reset(OpARMMOVHreg)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueARM_OpSignExt8to16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SignExt8to16 x)
+ // cond:
+ // result: (MOVBreg x)
+ for {
+ x := v.Args[0]
+ v.reset(OpARMMOVBreg)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueARM_OpSignExt8to32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SignExt8to32 x)
+ // cond:
+ // result: (MOVBreg x)
+ for {
+ x := v.Args[0]
+ v.reset(OpARMMOVBreg)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueARM_OpSignmask(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Signmask x)
+ // cond:
+ // result: (SRAconst x [31])
+ for {
+ x := v.Args[0]
+ v.reset(OpARMSRAconst)
+ v.AuxInt = 31
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueARM_OpSlicemask(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Slicemask <t> x)
+ // cond:
+ // result: (MVN (SRAconst <t> (SUBconst <t> x [1]) [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.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueARM_OpSqrt(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Sqrt x)
+ // cond:
+ // result: (SQRTD x)
+ for {
+ x := v.Args[0]
+ v.reset(OpARMSQRTD)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueARM_OpStaticCall(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (StaticCall [argwid] {target} mem)
+ // cond:
+ // result: (CALLstatic [argwid] {target} mem)
+ for {
+ argwid := v.AuxInt
+ target := v.Aux
+ mem := v.Args[0]
+ v.reset(OpARMCALLstatic)
+ v.AuxInt = argwid
+ v.Aux = target
+ v.AddArg(mem)
+ return true
+ }
+}
+func rewriteValueARM_OpStore(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Store [1] ptr val mem)
+ // cond:
+ // result: (MOVBstore ptr val mem)
+ for {
+ if v.AuxInt != 1 {
+ break
+ }
+ ptr := v.Args[0]
+ val := v.Args[1]
+ mem := v.Args[2]
+ v.reset(OpARMMOVBstore)
+ 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 {
+ break
+ }
+ ptr := v.Args[0]
+ val := v.Args[1]
+ mem := v.Args[2]
+ v.reset(OpARMMOVHstore)
+ 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)
+ for {
+ if v.AuxInt != 4 {
+ break
+ }
+ ptr := v.Args[0]
+ val := v.Args[1]
+ mem := v.Args[2]
+ if !(!is32BitFloat(val.Type)) {
+ break
+ }
+ v.reset(OpARMMOVWstore)
+ v.AddArg(ptr)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (Store [4] ptr val mem)
+ // cond: is32BitFloat(val.Type)
+ // result: (MOVFstore ptr val mem)
+ for {
+ if v.AuxInt != 4 {
+ break
+ }
+ ptr := v.Args[0]
+ val := v.Args[1]
+ mem := v.Args[2]
+ if !(is32BitFloat(val.Type)) {
+ break
+ }
+ v.reset(OpARMMOVFstore)
+ v.AddArg(ptr)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (Store [8] ptr val mem)
+ // cond: is64BitFloat(val.Type)
+ // result: (MOVDstore ptr val mem)
+ for {
+ if v.AuxInt != 8 {
+ break
+ }
+ ptr := v.Args[0]
+ val := v.Args[1]
+ mem := v.Args[2]
+ if !(is64BitFloat(val.Type)) {
+ break
+ }
+ v.reset(OpARMMOVDstore)
+ v.AddArg(ptr)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpSub16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Sub16 x y)
+ // cond:
+ // result: (SUB x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARMSUB)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueARM_OpSub32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Sub32 x y)
+ // cond:
+ // result: (SUB x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARMSUB)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueARM_OpSub32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Sub32F x y)
+ // cond:
+ // result: (SUBF x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARMSUBF)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueARM_OpSub32carry(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Sub32carry x y)
+ // cond:
+ // result: (SUBS x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARMSUBS)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueARM_OpSub32withcarry(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Sub32withcarry x y c)
+ // cond:
+ // result: (SBC x y c)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ c := v.Args[2]
+ v.reset(OpARMSBC)
+ v.AddArg(x)
+ v.AddArg(y)
+ v.AddArg(c)
+ return true
+ }
+}
+func rewriteValueARM_OpSub64F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Sub64F x y)
+ // cond:
+ // result: (SUBD x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARMSUBD)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueARM_OpSub8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Sub8 x y)
+ // cond:
+ // result: (SUB x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARMSUB)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueARM_OpSubPtr(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SubPtr x y)
+ // cond:
+ // result: (SUB x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARMSUB)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueARM_OpTrunc16to8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Trunc16to8 x)
+ // cond:
+ // result: x
+ for {
+ x := v.Args[0]
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueARM_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 rewriteValueARM_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 rewriteValueARM_OpXor16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Xor16 x y)
+ // cond:
+ // result: (XOR x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARMXOR)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueARM_OpXor32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Xor32 x y)
+ // cond:
+ // result: (XOR x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARMXOR)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueARM_OpXor8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Xor8 x y)
+ // cond:
+ // result: (XOR x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARMXOR)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueARM_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) {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = mem.Type
+ v.AddArg(mem)
+ return true
+ }
+ // match: (Zero [s] ptr mem)
+ // cond: SizeAndAlign(s).Size() == 1
+ // result: (MOVBstore ptr (MOVWconst [0]) mem)
+ for {
+ s := v.AuxInt
+ ptr := v.Args[0]
+ mem := v.Args[1]
+ if !(SizeAndAlign(s).Size() == 1) {
+ break
+ }
+ v.reset(OpARMMOVBstore)
+ v.AddArg(ptr)
+ v0 := b.NewValue0(v.Line, OpARMMOVWconst, config.fe.TypeUInt32())
+ 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
+ // result: (MOVHstore ptr (MOVWconst [0]) mem)
+ for {
+ s := v.AuxInt
+ ptr := v.Args[0]
+ mem := v.Args[1]
+ if !(SizeAndAlign(s).Size() == 2 && SizeAndAlign(s).Align()%2 == 0) {
+ break
+ }
+ v.reset(OpARMMOVHstore)
+ v.AddArg(ptr)
+ v0 := b.NewValue0(v.Line, OpARMMOVWconst, config.fe.TypeUInt32())
+ v0.AuxInt = 0
+ v.AddArg(v0)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (Zero [s] ptr mem)
+ // cond: SizeAndAlign(s).Size() == 2
+ // 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) {
+ break
+ }
+ v.reset(OpARMMOVBstore)
+ v.AuxInt = 1
+ v.AddArg(ptr)
+ v0 := b.NewValue0(v.Line, OpARMMOVWconst, config.fe.TypeUInt32())
+ v0.AuxInt = 0
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpARMMOVBstore, TypeMem)
+ v1.AuxInt = 0
+ v1.AddArg(ptr)
+ v2 := b.NewValue0(v.Line, OpARMMOVWconst, config.fe.TypeUInt32())
+ 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
+ // result: (MOVWstore ptr (MOVWconst [0]) mem)
+ for {
+ s := v.AuxInt
+ ptr := v.Args[0]
+ mem := v.Args[1]
+ if !(SizeAndAlign(s).Size() == 4 && SizeAndAlign(s).Align()%4 == 0) {
+ break
+ }
+ v.reset(OpARMMOVWstore)
+ v.AddArg(ptr)
+ v0 := b.NewValue0(v.Line, OpARMMOVWconst, config.fe.TypeUInt32())
+ 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
+ // result: (MOVHstore [2] ptr (MOVWconst [0]) (MOVHstore [0] ptr (MOVWconst [0]) mem))
+ for {
+ s := v.AuxInt
+ ptr := v.Args[0]
+ mem := v.Args[1]
+ if !(SizeAndAlign(s).Size() == 4 && SizeAndAlign(s).Align()%2 == 0) {
+ break
+ }
+ v.reset(OpARMMOVHstore)
+ v.AuxInt = 2
+ v.AddArg(ptr)
+ v0 := b.NewValue0(v.Line, OpARMMOVWconst, config.fe.TypeUInt32())
+ v0.AuxInt = 0
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpARMMOVHstore, TypeMem)
+ v1.AuxInt = 0
+ v1.AddArg(ptr)
+ v2 := b.NewValue0(v.Line, OpARMMOVWconst, config.fe.TypeUInt32())
+ v2.AuxInt = 0
+ v1.AddArg(v2)
+ v1.AddArg(mem)
+ v.AddArg(v1)
+ return true
+ }
+ // match: (Zero [s] ptr mem)
+ // cond: SizeAndAlign(s).Size() == 4
+ // 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) {
+ break
+ }
+ v.reset(OpARMMOVBstore)
+ v.AuxInt = 3
+ v.AddArg(ptr)
+ v0 := b.NewValue0(v.Line, OpARMMOVWconst, config.fe.TypeUInt32())
+ v0.AuxInt = 0
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpARMMOVBstore, TypeMem)
+ v1.AuxInt = 2
+ v1.AddArg(ptr)
+ v2 := b.NewValue0(v.Line, OpARMMOVWconst, config.fe.TypeUInt32())
+ v2.AuxInt = 0
+ v1.AddArg(v2)
+ v3 := b.NewValue0(v.Line, OpARMMOVBstore, TypeMem)
+ v3.AuxInt = 1
+ v3.AddArg(ptr)
+ v4 := b.NewValue0(v.Line, OpARMMOVWconst, config.fe.TypeUInt32())
+ v4.AuxInt = 0
+ v3.AddArg(v4)
+ v5 := b.NewValue0(v.Line, OpARMMOVBstore, TypeMem)
+ v5.AuxInt = 0
+ v5.AddArg(ptr)
+ v6 := b.NewValue0(v.Line, OpARMMOVWconst, config.fe.TypeUInt32())
+ v6.AuxInt = 0
+ v5.AddArg(v6)
+ v5.AddArg(mem)
+ v3.AddArg(v5)
+ v1.AddArg(v3)
+ v.AddArg(v1)
+ return true
+ }
+ // match: (Zero [s] ptr mem)
+ // cond: SizeAndAlign(s).Size() == 3
+ // 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) {
+ break
+ }
+ v.reset(OpARMMOVBstore)
+ v.AuxInt = 2
+ v.AddArg(ptr)
+ v0 := b.NewValue0(v.Line, OpARMMOVWconst, config.fe.TypeUInt32())
+ v0.AuxInt = 0
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpARMMOVBstore, TypeMem)
+ v1.AuxInt = 1
+ v1.AddArg(ptr)
+ v2 := b.NewValue0(v.Line, OpARMMOVWconst, config.fe.TypeUInt32())
+ v2.AuxInt = 0
+ v1.AddArg(v2)
+ v3 := b.NewValue0(v.Line, OpARMMOVBstore, TypeMem)
+ v3.AuxInt = 0
+ v3.AddArg(ptr)
+ v4 := b.NewValue0(v.Line, OpARMMOVWconst, config.fe.TypeUInt32())
+ v4.AuxInt = 0
+ v3.AddArg(v4)
+ v3.AddArg(mem)
+ v1.AddArg(v3)
+ 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)
+ for {
+ s := v.AuxInt
+ 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) {
+ break
+ }
+ v.reset(OpARMDUFFZERO)
+ v.AuxInt = 4 * (128 - int64(SizeAndAlign(s).Size()/4))
+ v.AddArg(ptr)
+ v0 := b.NewValue0(v.Line, OpARMMOVWconst, config.fe.TypeUInt32())
+ 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)
+ for {
+ s := v.AuxInt
+ ptr := v.Args[0]
+ mem := v.Args[1]
+ if !((SizeAndAlign(s).Size() > 512 || config.noDuffDevice) || SizeAndAlign(s).Align()%4 != 0) {
+ break
+ }
+ v.reset(OpARMLoweredZero)
+ v.AuxInt = SizeAndAlign(s).Align()
+ v.AddArg(ptr)
+ v0 := b.NewValue0(v.Line, OpARMADDconst, ptr.Type)
+ v0.AuxInt = SizeAndAlign(s).Size() - moveSize(SizeAndAlign(s).Align(), config)
+ v0.AddArg(ptr)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpARMMOVWconst, config.fe.TypeUInt32())
+ v1.AuxInt = 0
+ v.AddArg(v1)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValueARM_OpZeroExt16to32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ZeroExt16to32 x)
+ // cond:
+ // result: (MOVHUreg x)
+ for {
+ x := v.Args[0]
+ v.reset(OpARMMOVHUreg)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueARM_OpZeroExt8to16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ZeroExt8to16 x)
+ // cond:
+ // result: (MOVBUreg x)
+ for {
+ x := v.Args[0]
+ v.reset(OpARMMOVBUreg)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueARM_OpZeroExt8to32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ZeroExt8to32 x)
+ // cond:
+ // result: (MOVBUreg x)
+ for {
+ x := v.Args[0]
+ v.reset(OpARMMOVBUreg)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueARM_OpZeromask(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Zeromask x)
+ // cond:
+ // result: (SRAconst (RSBshiftRL <config.fe.TypeInt32()> 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.AuxInt = 1
+ v0.AddArg(x)
+ v0.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteBlockARM(b *Block, config *Config) bool {
+ switch b.Kind {
+ case BlockARMEQ:
+ // match: (EQ (FlagEQ) yes no)
+ // cond:
+ // result: (First nil yes no)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil no yes)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil no yes)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil no yes)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil no yes)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (EQ cmp yes no)
+ for {
+ v := b.Control
+ if v.Op != OpARMInvertFlags {
+ 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:
+ // match: (GE (FlagEQ) yes no)
+ // cond:
+ // result: (First nil yes no)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil no yes)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil no yes)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil yes no)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil yes no)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (LE cmp yes no)
+ for {
+ v := b.Control
+ if v.Op != OpARMInvertFlags {
+ 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:
+ // match: (GT (FlagEQ) yes no)
+ // cond:
+ // result: (First nil no yes)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil no yes)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil no yes)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil yes no)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil yes no)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (LT cmp yes no)
+ for {
+ v := b.Control
+ if v.Op != OpARMInvertFlags {
+ 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:
+ // match: (If (Equal cc) yes no)
+ // cond:
+ // result: (EQ cc yes no)
+ for {
+ v := b.Control
+ if v.Op != OpARMEqual {
+ 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)
+ // cond:
+ // result: (NE cc yes no)
+ for {
+ v := b.Control
+ if v.Op != OpARMNotEqual {
+ 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)
+ // cond:
+ // result: (LT cc yes no)
+ for {
+ v := b.Control
+ if v.Op != OpARMLessThan {
+ break
+ }
+ cc := v.Args[0]
+ yes := b.Succs[0]
+ no := b.Succs[1]
+ b.Kind = BlockARMLT
+ b.SetControl(cc)
+ _ = yes
+ _ = no
+ return true
+ }
+ // match: (If (LessThanU cc) yes no)
+ // cond:
+ // result: (ULT cc yes no)
+ for {
+ v := b.Control
+ if v.Op != OpARMLessThanU {
+ 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)
+ // cond:
+ // result: (LE cc yes no)
+ for {
+ v := b.Control
+ if v.Op != OpARMLessEqual {
+ 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)
+ // cond:
+ // result: (ULE cc yes no)
+ for {
+ v := b.Control
+ if v.Op != OpARMLessEqualU {
+ 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)
+ // cond:
+ // result: (GT cc yes no)
+ for {
+ v := b.Control
+ if v.Op != OpARMGreaterThan {
+ 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)
+ // cond:
+ // result: (UGT cc yes no)
+ for {
+ v := b.Control
+ if v.Op != OpARMGreaterThanU {
+ 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)
+ // cond:
+ // result: (GE cc yes no)
+ for {
+ v := b.Control
+ if v.Op != OpARMGreaterEqual {
+ 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)
+ // cond:
+ // result: (UGE cc yes no)
+ for {
+ v := b.Control
+ if v.Op != OpARMGreaterEqualU {
+ 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)
+ // cond:
+ // result: (NE (CMPconst [0] cond) yes no)
+ for {
+ 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.AuxInt = 0
+ v0.AddArg(cond)
+ b.SetControl(v0)
+ _ = yes
+ _ = no
+ return true
+ }
+ case BlockARMLE:
+ // match: (LE (FlagEQ) yes no)
+ // cond:
+ // result: (First nil yes no)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil yes no)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil yes no)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil no yes)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil no yes)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (GE cmp yes no)
+ for {
+ v := b.Control
+ if v.Op != OpARMInvertFlags {
+ 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:
+ // match: (LT (FlagEQ) yes no)
+ // cond:
+ // result: (First nil no yes)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil yes no)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil yes no)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil no yes)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil no yes)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (GT cmp yes no)
+ for {
+ v := b.Control
+ if v.Op != OpARMInvertFlags {
+ 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:
+ // match: (NE (CMPconst [0] (Equal cc)) yes no)
+ // cond:
+ // result: (EQ cc yes no)
+ for {
+ v := b.Control
+ if v.Op != OpARMCMPconst {
+ break
+ }
+ if v.AuxInt != 0 {
+ break
+ }
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMEqual {
+ 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)
+ // cond:
+ // result: (NE cc yes no)
+ for {
+ v := b.Control
+ if v.Op != OpARMCMPconst {
+ break
+ }
+ if v.AuxInt != 0 {
+ break
+ }
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMNotEqual {
+ 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)
+ // cond:
+ // result: (LT cc yes no)
+ for {
+ v := b.Control
+ if v.Op != OpARMCMPconst {
+ break
+ }
+ if v.AuxInt != 0 {
+ break
+ }
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMLessThan {
+ 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)
+ // cond:
+ // result: (ULT cc yes no)
+ for {
+ v := b.Control
+ if v.Op != OpARMCMPconst {
+ break
+ }
+ if v.AuxInt != 0 {
+ break
+ }
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMLessThanU {
+ 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)
+ // cond:
+ // result: (LE cc yes no)
+ for {
+ v := b.Control
+ if v.Op != OpARMCMPconst {
+ break
+ }
+ if v.AuxInt != 0 {
+ break
+ }
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMLessEqual {
+ 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)
+ // cond:
+ // result: (ULE cc yes no)
+ for {
+ v := b.Control
+ if v.Op != OpARMCMPconst {
+ break
+ }
+ if v.AuxInt != 0 {
+ break
+ }
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMLessEqualU {
+ 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)
+ // cond:
+ // result: (GT cc yes no)
+ for {
+ v := b.Control
+ if v.Op != OpARMCMPconst {
+ break
+ }
+ if v.AuxInt != 0 {
+ break
+ }
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMGreaterThan {
+ 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)
+ // cond:
+ // result: (UGT cc yes no)
+ for {
+ v := b.Control
+ if v.Op != OpARMCMPconst {
+ break
+ }
+ if v.AuxInt != 0 {
+ break
+ }
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMGreaterThanU {
+ 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)
+ // cond:
+ // result: (GE cc yes no)
+ for {
+ v := b.Control
+ if v.Op != OpARMCMPconst {
+ break
+ }
+ if v.AuxInt != 0 {
+ break
+ }
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMGreaterEqual {
+ 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)
+ // cond:
+ // result: (UGE cc yes no)
+ for {
+ v := b.Control
+ if v.Op != OpARMCMPconst {
+ break
+ }
+ if v.AuxInt != 0 {
+ break
+ }
+ v_0 := v.Args[0]
+ if v_0.Op != OpARMGreaterEqualU {
+ 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)
+ // cond:
+ // result: (First nil no yes)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil yes no)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil yes no)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil yes no)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil yes no)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (NE cmp yes no)
+ for {
+ v := b.Control
+ if v.Op != OpARMInvertFlags {
+ 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:
+ // match: (UGE (FlagEQ) yes no)
+ // cond:
+ // result: (First nil yes no)
+ for {
+ v := b.Control
+ 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)
// cond:
- // result: (LT cc yes no)
+ // result: (First nil no yes)
for {
v := b.Control
- if v.Op != OpARMLessThan {
+ if v.Op != OpARMFlagLT_ULT {
break
}
- cc := v.Args[0]
yes := b.Succs[0]
no := b.Succs[1]
- b.Kind = BlockARMLT
- b.SetControl(cc)
+ b.Kind = BlockFirst
+ b.SetControl(nil)
+ b.swapSuccessors()
+ _ = no
+ _ = yes
+ return true
+ }
+ // match: (UGE (FlagLT_UGT) yes no)
+ // cond:
+ // result: (First nil yes no)
+ for {
+ v := b.Control
+ if v.Op != 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)
+ // cond:
+ // result: (First nil no yes)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil yes no)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (ULE cmp yes no)
+ for {
+ v := b.Control
+ if v.Op != OpARMInvertFlags {
+ 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:
+ // match: (UGT (FlagEQ) yes no)
+ // cond:
+ // result: (First nil no yes)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil no yes)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil yes no)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil no yes)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil yes no)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (ULT cmp yes no)
+ for {
+ v := b.Control
+ if v.Op != OpARMInvertFlags {
+ 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:
+ // match: (ULE (FlagEQ) yes no)
+ // cond:
+ // result: (First nil yes no)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil yes no)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil no yes)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil yes no)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil no yes)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (UGE cmp yes no)
+ for {
+ v := b.Control
+ if v.Op != OpARMInvertFlags {
+ 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:
+ // match: (ULT (FlagEQ) yes no)
+ // cond:
+ // result: (First nil no yes)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil yes no)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil no yes)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil yes no)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil no yes)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (UGT cmp yes no)
+ for {
+ v := b.Control
+ if v.Op != OpARMInvertFlags {
+ 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
new file mode 100644
index 0000000..dd5aa28
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/rewriteARM64.go
@@ -0,0 +1,16703 @@
+// autogenerated from gen/ARM64.rules: do not edit!
+// generated with: cd gen; go run *.go
+
+package ssa
+
+import "math"
+
+var _ = math.MinInt8 // in case not otherwise used
+func rewriteValueARM64(v *Value, config *Config) bool {
+ switch v.Op {
+ case OpARM64ADD:
+ return rewriteValueARM64_OpARM64ADD(v, config)
+ case OpARM64ADDconst:
+ return rewriteValueARM64_OpARM64ADDconst(v, config)
+ case OpARM64ADDshiftLL:
+ return rewriteValueARM64_OpARM64ADDshiftLL(v, config)
+ case OpARM64ADDshiftRA:
+ return rewriteValueARM64_OpARM64ADDshiftRA(v, config)
+ case OpARM64ADDshiftRL:
+ return rewriteValueARM64_OpARM64ADDshiftRL(v, config)
+ case OpARM64AND:
+ return rewriteValueARM64_OpARM64AND(v, config)
+ case OpARM64ANDconst:
+ return rewriteValueARM64_OpARM64ANDconst(v, config)
+ case OpARM64ANDshiftLL:
+ return rewriteValueARM64_OpARM64ANDshiftLL(v, config)
+ case OpARM64ANDshiftRA:
+ return rewriteValueARM64_OpARM64ANDshiftRA(v, config)
+ case OpARM64ANDshiftRL:
+ return rewriteValueARM64_OpARM64ANDshiftRL(v, config)
+ case OpARM64BIC:
+ return rewriteValueARM64_OpARM64BIC(v, config)
+ case OpARM64BICconst:
+ return rewriteValueARM64_OpARM64BICconst(v, config)
+ case OpARM64BICshiftLL:
+ return rewriteValueARM64_OpARM64BICshiftLL(v, config)
+ case OpARM64BICshiftRA:
+ return rewriteValueARM64_OpARM64BICshiftRA(v, config)
+ case OpARM64BICshiftRL:
+ return rewriteValueARM64_OpARM64BICshiftRL(v, config)
+ case OpARM64CMP:
+ return rewriteValueARM64_OpARM64CMP(v, config)
+ case OpARM64CMPW:
+ return rewriteValueARM64_OpARM64CMPW(v, config)
+ case OpARM64CMPWconst:
+ return rewriteValueARM64_OpARM64CMPWconst(v, config)
+ case OpARM64CMPconst:
+ return rewriteValueARM64_OpARM64CMPconst(v, config)
+ case OpARM64CMPshiftLL:
+ return rewriteValueARM64_OpARM64CMPshiftLL(v, config)
+ case OpARM64CMPshiftRA:
+ return rewriteValueARM64_OpARM64CMPshiftRA(v, config)
+ case OpARM64CMPshiftRL:
+ return rewriteValueARM64_OpARM64CMPshiftRL(v, config)
+ case OpARM64CSELULT:
+ return rewriteValueARM64_OpARM64CSELULT(v, config)
+ case OpARM64CSELULT0:
+ return rewriteValueARM64_OpARM64CSELULT0(v, config)
+ case OpARM64DIV:
+ return rewriteValueARM64_OpARM64DIV(v, config)
+ case OpARM64DIVW:
+ return rewriteValueARM64_OpARM64DIVW(v, config)
+ case OpARM64Equal:
+ return rewriteValueARM64_OpARM64Equal(v, config)
+ case OpARM64FMOVDload:
+ return rewriteValueARM64_OpARM64FMOVDload(v, config)
+ case OpARM64FMOVDstore:
+ return rewriteValueARM64_OpARM64FMOVDstore(v, config)
+ case OpARM64FMOVSload:
+ return rewriteValueARM64_OpARM64FMOVSload(v, config)
+ case OpARM64FMOVSstore:
+ return rewriteValueARM64_OpARM64FMOVSstore(v, config)
+ case OpARM64GreaterEqual:
+ return rewriteValueARM64_OpARM64GreaterEqual(v, config)
+ case OpARM64GreaterEqualU:
+ return rewriteValueARM64_OpARM64GreaterEqualU(v, config)
+ case OpARM64GreaterThan:
+ return rewriteValueARM64_OpARM64GreaterThan(v, config)
+ case OpARM64GreaterThanU:
+ return rewriteValueARM64_OpARM64GreaterThanU(v, config)
+ case OpARM64LessEqual:
+ return rewriteValueARM64_OpARM64LessEqual(v, config)
+ case OpARM64LessEqualU:
+ return rewriteValueARM64_OpARM64LessEqualU(v, config)
+ case OpARM64LessThan:
+ return rewriteValueARM64_OpARM64LessThan(v, config)
+ case OpARM64LessThanU:
+ return rewriteValueARM64_OpARM64LessThanU(v, config)
+ case OpARM64MOD:
+ return rewriteValueARM64_OpARM64MOD(v, config)
+ case OpARM64MODW:
+ return rewriteValueARM64_OpARM64MODW(v, config)
+ case OpARM64MOVBUload:
+ return rewriteValueARM64_OpARM64MOVBUload(v, config)
+ case OpARM64MOVBUreg:
+ return rewriteValueARM64_OpARM64MOVBUreg(v, config)
+ case OpARM64MOVBload:
+ return rewriteValueARM64_OpARM64MOVBload(v, config)
+ case OpARM64MOVBreg:
+ return rewriteValueARM64_OpARM64MOVBreg(v, config)
+ case OpARM64MOVBstore:
+ return rewriteValueARM64_OpARM64MOVBstore(v, config)
+ case OpARM64MOVBstorezero:
+ return rewriteValueARM64_OpARM64MOVBstorezero(v, config)
+ case OpARM64MOVDload:
+ return rewriteValueARM64_OpARM64MOVDload(v, config)
+ case OpARM64MOVDreg:
+ return rewriteValueARM64_OpARM64MOVDreg(v, config)
+ case OpARM64MOVDstore:
+ return rewriteValueARM64_OpARM64MOVDstore(v, config)
+ case OpARM64MOVDstorezero:
+ return rewriteValueARM64_OpARM64MOVDstorezero(v, config)
+ case OpARM64MOVHUload:
+ return rewriteValueARM64_OpARM64MOVHUload(v, config)
+ case OpARM64MOVHUreg:
+ return rewriteValueARM64_OpARM64MOVHUreg(v, config)
+ case OpARM64MOVHload:
+ return rewriteValueARM64_OpARM64MOVHload(v, config)
+ case OpARM64MOVHreg:
+ return rewriteValueARM64_OpARM64MOVHreg(v, config)
+ case OpARM64MOVHstore:
+ return rewriteValueARM64_OpARM64MOVHstore(v, config)
+ case OpARM64MOVHstorezero:
+ return rewriteValueARM64_OpARM64MOVHstorezero(v, config)
+ case OpARM64MOVWUload:
+ return rewriteValueARM64_OpARM64MOVWUload(v, config)
+ case OpARM64MOVWUreg:
+ return rewriteValueARM64_OpARM64MOVWUreg(v, config)
+ case OpARM64MOVWload:
+ return rewriteValueARM64_OpARM64MOVWload(v, config)
+ case OpARM64MOVWreg:
+ return rewriteValueARM64_OpARM64MOVWreg(v, config)
+ case OpARM64MOVWstore:
+ return rewriteValueARM64_OpARM64MOVWstore(v, config)
+ case OpARM64MOVWstorezero:
+ return rewriteValueARM64_OpARM64MOVWstorezero(v, config)
+ case OpARM64MUL:
+ return rewriteValueARM64_OpARM64MUL(v, config)
+ case OpARM64MULW:
+ return rewriteValueARM64_OpARM64MULW(v, config)
+ case OpARM64MVN:
+ return rewriteValueARM64_OpARM64MVN(v, config)
+ case OpARM64NEG:
+ return rewriteValueARM64_OpARM64NEG(v, config)
+ case OpARM64NotEqual:
+ return rewriteValueARM64_OpARM64NotEqual(v, config)
+ case OpARM64OR:
+ return rewriteValueARM64_OpARM64OR(v, config)
+ case OpARM64ORconst:
+ return rewriteValueARM64_OpARM64ORconst(v, config)
+ case OpARM64ORshiftLL:
+ return rewriteValueARM64_OpARM64ORshiftLL(v, config)
+ case OpARM64ORshiftRA:
+ return rewriteValueARM64_OpARM64ORshiftRA(v, config)
+ case OpARM64ORshiftRL:
+ return rewriteValueARM64_OpARM64ORshiftRL(v, config)
+ case OpARM64SLL:
+ return rewriteValueARM64_OpARM64SLL(v, config)
+ case OpARM64SLLconst:
+ return rewriteValueARM64_OpARM64SLLconst(v, config)
+ case OpARM64SRA:
+ return rewriteValueARM64_OpARM64SRA(v, config)
+ case OpARM64SRAconst:
+ return rewriteValueARM64_OpARM64SRAconst(v, config)
+ case OpARM64SRL:
+ return rewriteValueARM64_OpARM64SRL(v, config)
+ case OpARM64SRLconst:
+ return rewriteValueARM64_OpARM64SRLconst(v, config)
+ case OpARM64SUB:
+ return rewriteValueARM64_OpARM64SUB(v, config)
+ case OpARM64SUBconst:
+ return rewriteValueARM64_OpARM64SUBconst(v, config)
+ case OpARM64SUBshiftLL:
+ return rewriteValueARM64_OpARM64SUBshiftLL(v, config)
+ case OpARM64SUBshiftRA:
+ return rewriteValueARM64_OpARM64SUBshiftRA(v, config)
+ case OpARM64SUBshiftRL:
+ return rewriteValueARM64_OpARM64SUBshiftRL(v, config)
+ case OpARM64UDIV:
+ return rewriteValueARM64_OpARM64UDIV(v, config)
+ case OpARM64UDIVW:
+ return rewriteValueARM64_OpARM64UDIVW(v, config)
+ case OpARM64UMOD:
+ return rewriteValueARM64_OpARM64UMOD(v, config)
+ case OpARM64UMODW:
+ return rewriteValueARM64_OpARM64UMODW(v, config)
+ case OpARM64XOR:
+ return rewriteValueARM64_OpARM64XOR(v, config)
+ case OpARM64XORconst:
+ return rewriteValueARM64_OpARM64XORconst(v, config)
+ case OpARM64XORshiftLL:
+ return rewriteValueARM64_OpARM64XORshiftLL(v, config)
+ case OpARM64XORshiftRA:
+ return rewriteValueARM64_OpARM64XORshiftRA(v, config)
+ case OpARM64XORshiftRL:
+ return rewriteValueARM64_OpARM64XORshiftRL(v, config)
+ case OpAdd16:
+ return rewriteValueARM64_OpAdd16(v, config)
+ case OpAdd32:
+ return rewriteValueARM64_OpAdd32(v, config)
+ case OpAdd32F:
+ return rewriteValueARM64_OpAdd32F(v, config)
+ case OpAdd64:
+ return rewriteValueARM64_OpAdd64(v, config)
+ case OpAdd64F:
+ return rewriteValueARM64_OpAdd64F(v, config)
+ case OpAdd8:
+ return rewriteValueARM64_OpAdd8(v, config)
+ case OpAddPtr:
+ return rewriteValueARM64_OpAddPtr(v, config)
+ case OpAddr:
+ return rewriteValueARM64_OpAddr(v, config)
+ case OpAnd16:
+ return rewriteValueARM64_OpAnd16(v, config)
+ case OpAnd32:
+ return rewriteValueARM64_OpAnd32(v, config)
+ case OpAnd64:
+ return rewriteValueARM64_OpAnd64(v, config)
+ case OpAnd8:
+ return rewriteValueARM64_OpAnd8(v, config)
+ case OpAndB:
+ return rewriteValueARM64_OpAndB(v, config)
+ case OpAtomicAdd32:
+ return rewriteValueARM64_OpAtomicAdd32(v, config)
+ case OpAtomicAdd64:
+ return rewriteValueARM64_OpAtomicAdd64(v, config)
+ case OpAtomicAnd8:
+ return rewriteValueARM64_OpAtomicAnd8(v, config)
+ case OpAtomicCompareAndSwap32:
+ return rewriteValueARM64_OpAtomicCompareAndSwap32(v, config)
+ case OpAtomicCompareAndSwap64:
+ return rewriteValueARM64_OpAtomicCompareAndSwap64(v, config)
+ case OpAtomicExchange32:
+ return rewriteValueARM64_OpAtomicExchange32(v, config)
+ case OpAtomicExchange64:
+ return rewriteValueARM64_OpAtomicExchange64(v, config)
+ case OpAtomicLoad32:
+ return rewriteValueARM64_OpAtomicLoad32(v, config)
+ case OpAtomicLoad64:
+ return rewriteValueARM64_OpAtomicLoad64(v, config)
+ case OpAtomicLoadPtr:
+ return rewriteValueARM64_OpAtomicLoadPtr(v, config)
+ case OpAtomicOr8:
+ return rewriteValueARM64_OpAtomicOr8(v, config)
+ case OpAtomicStore32:
+ return rewriteValueARM64_OpAtomicStore32(v, config)
+ case OpAtomicStore64:
+ return rewriteValueARM64_OpAtomicStore64(v, config)
+ case OpAtomicStorePtrNoWB:
+ return rewriteValueARM64_OpAtomicStorePtrNoWB(v, config)
+ case OpAvg64u:
+ return rewriteValueARM64_OpAvg64u(v, config)
+ case OpBswap32:
+ return rewriteValueARM64_OpBswap32(v, config)
+ case OpBswap64:
+ return rewriteValueARM64_OpBswap64(v, config)
+ case OpClosureCall:
+ return rewriteValueARM64_OpClosureCall(v, config)
+ case OpCom16:
+ return rewriteValueARM64_OpCom16(v, config)
+ case OpCom32:
+ return rewriteValueARM64_OpCom32(v, config)
+ case OpCom64:
+ return rewriteValueARM64_OpCom64(v, config)
+ case OpCom8:
+ return rewriteValueARM64_OpCom8(v, config)
+ case OpConst16:
+ return rewriteValueARM64_OpConst16(v, config)
+ case OpConst32:
+ return rewriteValueARM64_OpConst32(v, config)
+ case OpConst32F:
+ return rewriteValueARM64_OpConst32F(v, config)
+ case OpConst64:
+ return rewriteValueARM64_OpConst64(v, config)
+ case OpConst64F:
+ return rewriteValueARM64_OpConst64F(v, config)
+ case OpConst8:
+ return rewriteValueARM64_OpConst8(v, config)
+ case OpConstBool:
+ return rewriteValueARM64_OpConstBool(v, config)
+ case OpConstNil:
+ return rewriteValueARM64_OpConstNil(v, config)
+ case OpConvert:
+ return rewriteValueARM64_OpConvert(v, config)
+ case OpCtz32:
+ return rewriteValueARM64_OpCtz32(v, config)
+ case OpCtz64:
+ return rewriteValueARM64_OpCtz64(v, config)
+ case OpCvt32Fto32:
+ return rewriteValueARM64_OpCvt32Fto32(v, config)
+ case OpCvt32Fto32U:
+ return rewriteValueARM64_OpCvt32Fto32U(v, config)
+ case OpCvt32Fto64:
+ return rewriteValueARM64_OpCvt32Fto64(v, config)
+ case OpCvt32Fto64F:
+ return rewriteValueARM64_OpCvt32Fto64F(v, config)
+ case OpCvt32Fto64U:
+ return rewriteValueARM64_OpCvt32Fto64U(v, config)
+ case OpCvt32Uto32F:
+ return rewriteValueARM64_OpCvt32Uto32F(v, config)
+ case OpCvt32Uto64F:
+ return rewriteValueARM64_OpCvt32Uto64F(v, config)
+ case OpCvt32to32F:
+ return rewriteValueARM64_OpCvt32to32F(v, config)
+ case OpCvt32to64F:
+ return rewriteValueARM64_OpCvt32to64F(v, config)
+ case OpCvt64Fto32:
+ return rewriteValueARM64_OpCvt64Fto32(v, config)
+ case OpCvt64Fto32F:
+ return rewriteValueARM64_OpCvt64Fto32F(v, config)
+ case OpCvt64Fto32U:
+ return rewriteValueARM64_OpCvt64Fto32U(v, config)
+ case OpCvt64Fto64:
+ return rewriteValueARM64_OpCvt64Fto64(v, config)
+ case OpCvt64Fto64U:
+ return rewriteValueARM64_OpCvt64Fto64U(v, config)
+ case OpCvt64Uto32F:
+ return rewriteValueARM64_OpCvt64Uto32F(v, config)
+ case OpCvt64Uto64F:
+ return rewriteValueARM64_OpCvt64Uto64F(v, config)
+ case OpCvt64to32F:
+ return rewriteValueARM64_OpCvt64to32F(v, config)
+ case OpCvt64to64F:
+ return rewriteValueARM64_OpCvt64to64F(v, config)
+ case OpDeferCall:
+ return rewriteValueARM64_OpDeferCall(v, config)
+ case OpDiv16:
+ return rewriteValueARM64_OpDiv16(v, config)
+ case OpDiv16u:
+ return rewriteValueARM64_OpDiv16u(v, config)
+ case OpDiv32:
+ return rewriteValueARM64_OpDiv32(v, config)
+ case OpDiv32F:
+ return rewriteValueARM64_OpDiv32F(v, config)
+ case OpDiv32u:
+ return rewriteValueARM64_OpDiv32u(v, config)
+ case OpDiv64:
+ return rewriteValueARM64_OpDiv64(v, config)
+ case OpDiv64F:
+ return rewriteValueARM64_OpDiv64F(v, config)
+ case OpDiv64u:
+ return rewriteValueARM64_OpDiv64u(v, config)
+ case OpDiv8:
+ return rewriteValueARM64_OpDiv8(v, config)
+ case OpDiv8u:
+ return rewriteValueARM64_OpDiv8u(v, config)
+ case OpEq16:
+ return rewriteValueARM64_OpEq16(v, config)
+ case OpEq32:
+ return rewriteValueARM64_OpEq32(v, config)
+ case OpEq32F:
+ return rewriteValueARM64_OpEq32F(v, config)
+ case OpEq64:
+ return rewriteValueARM64_OpEq64(v, config)
+ case OpEq64F:
+ return rewriteValueARM64_OpEq64F(v, config)
+ case OpEq8:
+ return rewriteValueARM64_OpEq8(v, config)
+ case OpEqB:
+ return rewriteValueARM64_OpEqB(v, config)
+ case OpEqPtr:
+ return rewriteValueARM64_OpEqPtr(v, config)
+ case OpGeq16:
+ return rewriteValueARM64_OpGeq16(v, config)
+ case OpGeq16U:
+ return rewriteValueARM64_OpGeq16U(v, config)
+ case OpGeq32:
+ return rewriteValueARM64_OpGeq32(v, config)
+ case OpGeq32F:
+ return rewriteValueARM64_OpGeq32F(v, config)
+ case OpGeq32U:
+ return rewriteValueARM64_OpGeq32U(v, config)
+ case OpGeq64:
+ return rewriteValueARM64_OpGeq64(v, config)
+ case OpGeq64F:
+ return rewriteValueARM64_OpGeq64F(v, config)
+ case OpGeq64U:
+ return rewriteValueARM64_OpGeq64U(v, config)
+ case OpGeq8:
+ return rewriteValueARM64_OpGeq8(v, config)
+ case OpGeq8U:
+ return rewriteValueARM64_OpGeq8U(v, config)
+ case OpGetClosurePtr:
+ return rewriteValueARM64_OpGetClosurePtr(v, config)
+ case OpGoCall:
+ return rewriteValueARM64_OpGoCall(v, config)
+ case OpGreater16:
+ return rewriteValueARM64_OpGreater16(v, config)
+ case OpGreater16U:
+ return rewriteValueARM64_OpGreater16U(v, config)
+ case OpGreater32:
+ return rewriteValueARM64_OpGreater32(v, config)
+ case OpGreater32F:
+ return rewriteValueARM64_OpGreater32F(v, config)
+ case OpGreater32U:
+ return rewriteValueARM64_OpGreater32U(v, config)
+ case OpGreater64:
+ return rewriteValueARM64_OpGreater64(v, config)
+ case OpGreater64F:
+ return rewriteValueARM64_OpGreater64F(v, config)
+ case OpGreater64U:
+ return rewriteValueARM64_OpGreater64U(v, config)
+ case OpGreater8:
+ return rewriteValueARM64_OpGreater8(v, config)
+ case OpGreater8U:
+ return rewriteValueARM64_OpGreater8U(v, config)
+ case OpHmul16:
+ return rewriteValueARM64_OpHmul16(v, config)
+ case OpHmul16u:
+ return rewriteValueARM64_OpHmul16u(v, config)
+ case OpHmul32:
+ return rewriteValueARM64_OpHmul32(v, config)
+ case OpHmul32u:
+ return rewriteValueARM64_OpHmul32u(v, config)
+ case OpHmul64:
+ return rewriteValueARM64_OpHmul64(v, config)
+ case OpHmul64u:
+ return rewriteValueARM64_OpHmul64u(v, config)
+ case OpHmul8:
+ return rewriteValueARM64_OpHmul8(v, config)
+ case OpHmul8u:
+ return rewriteValueARM64_OpHmul8u(v, config)
+ case OpInterCall:
+ return rewriteValueARM64_OpInterCall(v, config)
+ case OpIsInBounds:
+ return rewriteValueARM64_OpIsInBounds(v, config)
+ case OpIsNonNil:
+ return rewriteValueARM64_OpIsNonNil(v, config)
+ case OpIsSliceInBounds:
+ return rewriteValueARM64_OpIsSliceInBounds(v, config)
+ case OpLeq16:
+ return rewriteValueARM64_OpLeq16(v, config)
+ case OpLeq16U:
+ return rewriteValueARM64_OpLeq16U(v, config)
+ case OpLeq32:
+ return rewriteValueARM64_OpLeq32(v, config)
+ case OpLeq32F:
+ return rewriteValueARM64_OpLeq32F(v, config)
+ case OpLeq32U:
+ return rewriteValueARM64_OpLeq32U(v, config)
+ case OpLeq64:
+ return rewriteValueARM64_OpLeq64(v, config)
+ case OpLeq64F:
+ return rewriteValueARM64_OpLeq64F(v, config)
+ case OpLeq64U:
+ return rewriteValueARM64_OpLeq64U(v, config)
+ case OpLeq8:
+ return rewriteValueARM64_OpLeq8(v, config)
+ case OpLeq8U:
+ return rewriteValueARM64_OpLeq8U(v, config)
+ case OpLess16:
+ return rewriteValueARM64_OpLess16(v, config)
+ case OpLess16U:
+ return rewriteValueARM64_OpLess16U(v, config)
+ case OpLess32:
+ return rewriteValueARM64_OpLess32(v, config)
+ case OpLess32F:
+ return rewriteValueARM64_OpLess32F(v, config)
+ case OpLess32U:
+ return rewriteValueARM64_OpLess32U(v, config)
+ case OpLess64:
+ return rewriteValueARM64_OpLess64(v, config)
+ case OpLess64F:
+ return rewriteValueARM64_OpLess64F(v, config)
+ case OpLess64U:
+ return rewriteValueARM64_OpLess64U(v, config)
+ case OpLess8:
+ return rewriteValueARM64_OpLess8(v, config)
+ case OpLess8U:
+ return rewriteValueARM64_OpLess8U(v, config)
+ 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)
+ case OpLsh16x16:
+ return rewriteValueARM64_OpLsh16x16(v, config)
+ case OpLsh16x32:
+ return rewriteValueARM64_OpLsh16x32(v, config)
+ case OpLsh16x64:
+ return rewriteValueARM64_OpLsh16x64(v, config)
+ case OpLsh16x8:
+ return rewriteValueARM64_OpLsh16x8(v, config)
+ case OpLsh32x16:
+ return rewriteValueARM64_OpLsh32x16(v, config)
+ case OpLsh32x32:
+ return rewriteValueARM64_OpLsh32x32(v, config)
+ case OpLsh32x64:
+ return rewriteValueARM64_OpLsh32x64(v, config)
+ case OpLsh32x8:
+ return rewriteValueARM64_OpLsh32x8(v, config)
+ case OpLsh64x16:
+ return rewriteValueARM64_OpLsh64x16(v, config)
+ case OpLsh64x32:
+ return rewriteValueARM64_OpLsh64x32(v, config)
+ case OpLsh64x64:
+ return rewriteValueARM64_OpLsh64x64(v, config)
+ case OpLsh64x8:
+ return rewriteValueARM64_OpLsh64x8(v, config)
+ case OpLsh8x16:
+ return rewriteValueARM64_OpLsh8x16(v, config)
+ case OpLsh8x32:
+ return rewriteValueARM64_OpLsh8x32(v, config)
+ case OpLsh8x64:
+ return rewriteValueARM64_OpLsh8x64(v, config)
+ case OpLsh8x8:
+ return rewriteValueARM64_OpLsh8x8(v, config)
+ case OpMod16:
+ return rewriteValueARM64_OpMod16(v, config)
+ case OpMod16u:
+ return rewriteValueARM64_OpMod16u(v, config)
+ case OpMod32:
+ return rewriteValueARM64_OpMod32(v, config)
+ case OpMod32u:
+ return rewriteValueARM64_OpMod32u(v, config)
+ case OpMod64:
+ return rewriteValueARM64_OpMod64(v, config)
+ case OpMod64u:
+ return rewriteValueARM64_OpMod64u(v, config)
+ case OpMod8:
+ return rewriteValueARM64_OpMod8(v, config)
+ case OpMod8u:
+ return rewriteValueARM64_OpMod8u(v, config)
+ case OpMove:
+ return rewriteValueARM64_OpMove(v, config)
+ case OpMul16:
+ return rewriteValueARM64_OpMul16(v, config)
+ case OpMul32:
+ return rewriteValueARM64_OpMul32(v, config)
+ case OpMul32F:
+ return rewriteValueARM64_OpMul32F(v, config)
+ case OpMul64:
+ return rewriteValueARM64_OpMul64(v, config)
+ case OpMul64F:
+ return rewriteValueARM64_OpMul64F(v, config)
+ case OpMul8:
+ return rewriteValueARM64_OpMul8(v, config)
+ case OpNeg16:
+ return rewriteValueARM64_OpNeg16(v, config)
+ case OpNeg32:
+ return rewriteValueARM64_OpNeg32(v, config)
+ case OpNeg32F:
+ return rewriteValueARM64_OpNeg32F(v, config)
+ case OpNeg64:
+ return rewriteValueARM64_OpNeg64(v, config)
+ case OpNeg64F:
+ return rewriteValueARM64_OpNeg64F(v, config)
+ case OpNeg8:
+ return rewriteValueARM64_OpNeg8(v, config)
+ case OpNeq16:
+ return rewriteValueARM64_OpNeq16(v, config)
+ case OpNeq32:
+ return rewriteValueARM64_OpNeq32(v, config)
+ case OpNeq32F:
+ return rewriteValueARM64_OpNeq32F(v, config)
+ case OpNeq64:
+ return rewriteValueARM64_OpNeq64(v, config)
+ case OpNeq64F:
+ return rewriteValueARM64_OpNeq64F(v, config)
+ case OpNeq8:
+ return rewriteValueARM64_OpNeq8(v, config)
+ case OpNeqB:
+ return rewriteValueARM64_OpNeqB(v, config)
+ case OpNeqPtr:
+ return rewriteValueARM64_OpNeqPtr(v, config)
+ case OpNilCheck:
+ return rewriteValueARM64_OpNilCheck(v, config)
+ case OpNot:
+ return rewriteValueARM64_OpNot(v, config)
+ case OpOffPtr:
+ return rewriteValueARM64_OpOffPtr(v, config)
+ case OpOr16:
+ return rewriteValueARM64_OpOr16(v, config)
+ case OpOr32:
+ return rewriteValueARM64_OpOr32(v, config)
+ case OpOr64:
+ return rewriteValueARM64_OpOr64(v, config)
+ case OpOr8:
+ return rewriteValueARM64_OpOr8(v, config)
+ case OpOrB:
+ return rewriteValueARM64_OpOrB(v, config)
+ case OpRsh16Ux16:
+ return rewriteValueARM64_OpRsh16Ux16(v, config)
+ case OpRsh16Ux32:
+ return rewriteValueARM64_OpRsh16Ux32(v, config)
+ case OpRsh16Ux64:
+ return rewriteValueARM64_OpRsh16Ux64(v, config)
+ case OpRsh16Ux8:
+ return rewriteValueARM64_OpRsh16Ux8(v, config)
+ case OpRsh16x16:
+ return rewriteValueARM64_OpRsh16x16(v, config)
+ case OpRsh16x32:
+ return rewriteValueARM64_OpRsh16x32(v, config)
+ case OpRsh16x64:
+ return rewriteValueARM64_OpRsh16x64(v, config)
+ case OpRsh16x8:
+ return rewriteValueARM64_OpRsh16x8(v, config)
+ case OpRsh32Ux16:
+ return rewriteValueARM64_OpRsh32Ux16(v, config)
+ case OpRsh32Ux32:
+ return rewriteValueARM64_OpRsh32Ux32(v, config)
+ case OpRsh32Ux64:
+ return rewriteValueARM64_OpRsh32Ux64(v, config)
+ case OpRsh32Ux8:
+ return rewriteValueARM64_OpRsh32Ux8(v, config)
+ case OpRsh32x16:
+ return rewriteValueARM64_OpRsh32x16(v, config)
+ case OpRsh32x32:
+ return rewriteValueARM64_OpRsh32x32(v, config)
+ case OpRsh32x64:
+ return rewriteValueARM64_OpRsh32x64(v, config)
+ case OpRsh32x8:
+ return rewriteValueARM64_OpRsh32x8(v, config)
+ case OpRsh64Ux16:
+ return rewriteValueARM64_OpRsh64Ux16(v, config)
+ case OpRsh64Ux32:
+ return rewriteValueARM64_OpRsh64Ux32(v, config)
+ case OpRsh64Ux64:
+ return rewriteValueARM64_OpRsh64Ux64(v, config)
+ case OpRsh64Ux8:
+ return rewriteValueARM64_OpRsh64Ux8(v, config)
+ case OpRsh64x16:
+ return rewriteValueARM64_OpRsh64x16(v, config)
+ case OpRsh64x32:
+ return rewriteValueARM64_OpRsh64x32(v, config)
+ case OpRsh64x64:
+ return rewriteValueARM64_OpRsh64x64(v, config)
+ case OpRsh64x8:
+ return rewriteValueARM64_OpRsh64x8(v, config)
+ case OpRsh8Ux16:
+ return rewriteValueARM64_OpRsh8Ux16(v, config)
+ case OpRsh8Ux32:
+ return rewriteValueARM64_OpRsh8Ux32(v, config)
+ case OpRsh8Ux64:
+ return rewriteValueARM64_OpRsh8Ux64(v, config)
+ case OpRsh8Ux8:
+ return rewriteValueARM64_OpRsh8Ux8(v, config)
+ case OpRsh8x16:
+ return rewriteValueARM64_OpRsh8x16(v, config)
+ case OpRsh8x32:
+ return rewriteValueARM64_OpRsh8x32(v, config)
+ case OpRsh8x64:
+ return rewriteValueARM64_OpRsh8x64(v, config)
+ case OpRsh8x8:
+ return rewriteValueARM64_OpRsh8x8(v, config)
+ case OpSignExt16to32:
+ return rewriteValueARM64_OpSignExt16to32(v, config)
+ case OpSignExt16to64:
+ return rewriteValueARM64_OpSignExt16to64(v, config)
+ case OpSignExt32to64:
+ return rewriteValueARM64_OpSignExt32to64(v, config)
+ case OpSignExt8to16:
+ return rewriteValueARM64_OpSignExt8to16(v, config)
+ case OpSignExt8to32:
+ return rewriteValueARM64_OpSignExt8to32(v, config)
+ case OpSignExt8to64:
+ return rewriteValueARM64_OpSignExt8to64(v, config)
+ case OpSlicemask:
+ return rewriteValueARM64_OpSlicemask(v, config)
+ case OpSqrt:
+ return rewriteValueARM64_OpSqrt(v, config)
+ case OpStaticCall:
+ return rewriteValueARM64_OpStaticCall(v, config)
+ case OpStore:
+ return rewriteValueARM64_OpStore(v, config)
+ case OpSub16:
+ return rewriteValueARM64_OpSub16(v, config)
+ case OpSub32:
+ return rewriteValueARM64_OpSub32(v, config)
+ case OpSub32F:
+ return rewriteValueARM64_OpSub32F(v, config)
+ case OpSub64:
+ return rewriteValueARM64_OpSub64(v, config)
+ case OpSub64F:
+ return rewriteValueARM64_OpSub64F(v, config)
+ case OpSub8:
+ return rewriteValueARM64_OpSub8(v, config)
+ case OpSubPtr:
+ return rewriteValueARM64_OpSubPtr(v, config)
+ case OpTrunc16to8:
+ return rewriteValueARM64_OpTrunc16to8(v, config)
+ case OpTrunc32to16:
+ return rewriteValueARM64_OpTrunc32to16(v, config)
+ case OpTrunc32to8:
+ return rewriteValueARM64_OpTrunc32to8(v, config)
+ case OpTrunc64to16:
+ return rewriteValueARM64_OpTrunc64to16(v, config)
+ case OpTrunc64to32:
+ return rewriteValueARM64_OpTrunc64to32(v, config)
+ case OpTrunc64to8:
+ return rewriteValueARM64_OpTrunc64to8(v, config)
+ case OpXor16:
+ return rewriteValueARM64_OpXor16(v, config)
+ case OpXor32:
+ return rewriteValueARM64_OpXor32(v, config)
+ case OpXor64:
+ return rewriteValueARM64_OpXor64(v, config)
+ case OpXor8:
+ return rewriteValueARM64_OpXor8(v, config)
+ case OpZero:
+ return rewriteValueARM64_OpZero(v, config)
+ case OpZeroExt16to32:
+ return rewriteValueARM64_OpZeroExt16to32(v, config)
+ case OpZeroExt16to64:
+ return rewriteValueARM64_OpZeroExt16to64(v, config)
+ case OpZeroExt32to64:
+ return rewriteValueARM64_OpZeroExt32to64(v, config)
+ case OpZeroExt8to16:
+ return rewriteValueARM64_OpZeroExt8to16(v, config)
+ case OpZeroExt8to32:
+ return rewriteValueARM64_OpZeroExt8to32(v, config)
+ case OpZeroExt8to64:
+ return rewriteValueARM64_OpZeroExt8to64(v, config)
+ }
+ return false
+}
+func rewriteValueARM64_OpARM64ADD(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ADD (MOVDconst [c]) x)
+ // cond:
+ // result: (ADDconst [c] x)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64MOVDconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ v.reset(OpARM64ADDconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (ADD x (MOVDconst [c]))
+ // cond:
+ // result: (ADDconst [c] x)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64MOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpARM64ADDconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (ADD x (NEG y))
+ // cond:
+ // result: (SUB x y)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64NEG {
+ break
+ }
+ y := v_1.Args[0]
+ v.reset(OpARM64SUB)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (ADD (NEG y) x)
+ // cond:
+ // result: (SUB x y)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64NEG {
+ break
+ }
+ y := v_0.Args[0]
+ x := v.Args[1]
+ v.reset(OpARM64SUB)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (ADD x (SLLconst [c] y))
+ // cond:
+ // result: (ADDshiftLL x y [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64SLLconst {
+ break
+ }
+ c := v_1.AuxInt
+ y := v_1.Args[0]
+ v.reset(OpARM64ADDshiftLL)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (ADD (SLLconst [c] y) x)
+ // cond:
+ // result: (ADDshiftLL x y [c])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64SLLconst {
+ break
+ }
+ c := v_0.AuxInt
+ y := v_0.Args[0]
+ x := v.Args[1]
+ v.reset(OpARM64ADDshiftLL)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (ADD x (SRLconst [c] y))
+ // cond:
+ // result: (ADDshiftRL x y [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64SRLconst {
+ break
+ }
+ c := v_1.AuxInt
+ y := v_1.Args[0]
+ v.reset(OpARM64ADDshiftRL)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (ADD (SRLconst [c] y) x)
+ // cond:
+ // result: (ADDshiftRL x y [c])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64SRLconst {
+ break
+ }
+ c := v_0.AuxInt
+ y := v_0.Args[0]
+ x := v.Args[1]
+ v.reset(OpARM64ADDshiftRL)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (ADD x (SRAconst [c] y))
+ // cond:
+ // result: (ADDshiftRA x y [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64SRAconst {
+ break
+ }
+ c := v_1.AuxInt
+ y := v_1.Args[0]
+ v.reset(OpARM64ADDshiftRA)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (ADD (SRAconst [c] y) x)
+ // cond:
+ // result: (ADDshiftRA x y [c])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64SRAconst {
+ break
+ }
+ c := v_0.AuxInt
+ y := v_0.Args[0]
+ x := v.Args[1]
+ v.reset(OpARM64ADDshiftRA)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ return false
+}
+func rewriteValueARM64_OpARM64ADDconst(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ADDconst [off1] (MOVDaddr [off2] {sym} ptr))
+ // cond:
+ // result: (MOVDaddr [off1+off2] {sym} ptr)
+ for {
+ off1 := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64MOVDaddr {
+ break
+ }
+ off2 := v_0.AuxInt
+ sym := v_0.Aux
+ ptr := v_0.Args[0]
+ v.reset(OpARM64MOVDaddr)
+ v.AuxInt = off1 + off2
+ v.Aux = sym
+ v.AddArg(ptr)
+ return true
+ }
+ // match: (ADDconst [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: (ADDconst [c] (MOVDconst [d]))
+ // cond:
+ // result: (MOVDconst [c+d])
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64MOVDconst {
+ break
+ }
+ d := v_0.AuxInt
+ v.reset(OpARM64MOVDconst)
+ v.AuxInt = c + d
+ return true
+ }
+ // match: (ADDconst [c] (ADDconst [d] x))
+ // cond:
+ // result: (ADDconst [c+d] x)
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64ADDconst {
+ break
+ }
+ d := v_0.AuxInt
+ x := v_0.Args[0]
+ v.reset(OpARM64ADDconst)
+ v.AuxInt = c + d
+ v.AddArg(x)
+ return true
+ }
+ // match: (ADDconst [c] (SUBconst [d] x))
+ // cond:
+ // result: (ADDconst [c-d] x)
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64SUBconst {
+ break
+ }
+ d := v_0.AuxInt
+ x := v_0.Args[0]
+ v.reset(OpARM64ADDconst)
+ v.AuxInt = c - d
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValueARM64_OpARM64ADDshiftLL(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ADDshiftLL (MOVDconst [c]) x [d])
+ // cond:
+ // result: (ADDconst [c] (SLLconst <x.Type> x [d]))
+ for {
+ d := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64MOVDconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ v.reset(OpARM64ADDconst)
+ v.AuxInt = c
+ v0 := b.NewValue0(v.Line, OpARM64SLLconst, x.Type)
+ v0.AuxInt = d
+ v0.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (ADDshiftLL x (MOVDconst [c]) [d])
+ // cond:
+ // result: (ADDconst x [int64(uint64(c)<<uint64(d))])
+ for {
+ d := v.AuxInt
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64MOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpARM64ADDconst)
+ v.AuxInt = int64(uint64(c) << uint64(d))
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValueARM64_OpARM64ADDshiftRA(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ADDshiftRA (MOVDconst [c]) x [d])
+ // cond:
+ // result: (ADDconst [c] (SRAconst <x.Type> x [d]))
+ for {
+ d := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64MOVDconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ v.reset(OpARM64ADDconst)
+ v.AuxInt = c
+ v0 := b.NewValue0(v.Line, OpARM64SRAconst, x.Type)
+ v0.AuxInt = d
+ v0.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (ADDshiftRA x (MOVDconst [c]) [d])
+ // cond:
+ // result: (ADDconst x [int64(int64(c)>>uint64(d))])
+ for {
+ d := v.AuxInt
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64MOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpARM64ADDconst)
+ v.AuxInt = int64(int64(c) >> uint64(d))
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValueARM64_OpARM64ADDshiftRL(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ADDshiftRL (MOVDconst [c]) x [d])
+ // cond:
+ // result: (ADDconst [c] (SRLconst <x.Type> x [d]))
+ for {
+ d := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64MOVDconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ v.reset(OpARM64ADDconst)
+ v.AuxInt = c
+ v0 := b.NewValue0(v.Line, OpARM64SRLconst, x.Type)
+ v0.AuxInt = d
+ v0.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (ADDshiftRL x (MOVDconst [c]) [d])
+ // cond:
+ // result: (ADDconst x [int64(uint64(c)>>uint64(d))])
+ for {
+ d := v.AuxInt
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64MOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpARM64ADDconst)
+ v.AuxInt = int64(uint64(c) >> uint64(d))
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValueARM64_OpARM64AND(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (AND (MOVDconst [c]) x)
+ // cond:
+ // result: (ANDconst [c] x)
+ for {
+ 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 (MOVDconst [c]))
+ // cond:
+ // result: (ANDconst [c] x)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64MOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpARM64ANDconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (AND 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: (AND x (MVN y))
+ // cond:
+ // result: (BIC x y)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64MVN {
+ break
+ }
+ y := v_1.Args[0]
+ v.reset(OpARM64BIC)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (AND x (SLLconst [c] y))
+ // cond:
+ // result: (ANDshiftLL x y [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64SLLconst {
+ break
+ }
+ c := v_1.AuxInt
+ y := v_1.Args[0]
+ v.reset(OpARM64ANDshiftLL)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (AND (SLLconst [c] y) x)
+ // cond:
+ // result: (ANDshiftLL x y [c])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64SLLconst {
+ break
+ }
+ c := v_0.AuxInt
+ y := v_0.Args[0]
+ x := v.Args[1]
+ v.reset(OpARM64ANDshiftLL)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (AND x (SRLconst [c] y))
+ // cond:
+ // result: (ANDshiftRL x y [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64SRLconst {
+ break
+ }
+ c := v_1.AuxInt
+ y := v_1.Args[0]
+ v.reset(OpARM64ANDshiftRL)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (AND (SRLconst [c] y) x)
+ // cond:
+ // result: (ANDshiftRL x y [c])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64SRLconst {
+ break
+ }
+ c := v_0.AuxInt
+ y := v_0.Args[0]
+ x := v.Args[1]
+ v.reset(OpARM64ANDshiftRL)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (AND x (SRAconst [c] y))
+ // cond:
+ // result: (ANDshiftRA x y [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64SRAconst {
+ break
+ }
+ c := v_1.AuxInt
+ y := v_1.Args[0]
+ v.reset(OpARM64ANDshiftRA)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (AND (SRAconst [c] y) x)
+ // cond:
+ // result: (ANDshiftRA x y [c])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64SRAconst {
+ break
+ }
+ c := v_0.AuxInt
+ y := v_0.Args[0]
+ x := v.Args[1]
+ v.reset(OpARM64ANDshiftRA)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ return false
+}
+func rewriteValueARM64_OpARM64ANDconst(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ANDconst [0] _)
+ // cond:
+ // result: (MOVDconst [0])
+ for {
+ if v.AuxInt != 0 {
+ break
+ }
+ v.reset(OpARM64MOVDconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (ANDconst [-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: (ANDconst [c] (MOVDconst [d]))
+ // cond:
+ // result: (MOVDconst [c&d])
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64MOVDconst {
+ break
+ }
+ d := v_0.AuxInt
+ v.reset(OpARM64MOVDconst)
+ v.AuxInt = c & d
+ return true
+ }
+ // match: (ANDconst [c] (ANDconst [d] x))
+ // cond:
+ // result: (ANDconst [c&d] x)
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64ANDconst {
+ break
+ }
+ d := v_0.AuxInt
+ x := v_0.Args[0]
+ v.reset(OpARM64ANDconst)
+ v.AuxInt = c & d
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValueARM64_OpARM64ANDshiftLL(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ANDshiftLL (MOVDconst [c]) x [d])
+ // cond:
+ // result: (ANDconst [c] (SLLconst <x.Type> x [d]))
+ for {
+ d := v.AuxInt
+ 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
+ v0 := b.NewValue0(v.Line, OpARM64SLLconst, x.Type)
+ v0.AuxInt = d
+ v0.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (ANDshiftLL x (MOVDconst [c]) [d])
+ // cond:
+ // result: (ANDconst x [int64(uint64(c)<<uint64(d))])
+ for {
+ d := v.AuxInt
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64MOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpARM64ANDconst)
+ v.AuxInt = int64(uint64(c) << uint64(d))
+ v.AddArg(x)
+ return true
+ }
+ // match: (ANDshiftLL x y:(SLLconst x [c]) [d])
+ // cond: c==d
+ // result: y
+ for {
+ d := v.AuxInt
+ x := v.Args[0]
+ y := v.Args[1]
+ if y.Op != OpARM64SLLconst {
+ break
+ }
+ c := y.AuxInt
+ if x != y.Args[0] {
+ break
+ }
+ if !(c == d) {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = y.Type
+ v.AddArg(y)
+ return true
+ }
+ return false
+}
+func rewriteValueARM64_OpARM64ANDshiftRA(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ANDshiftRA (MOVDconst [c]) x [d])
+ // cond:
+ // result: (ANDconst [c] (SRAconst <x.Type> x [d]))
+ for {
+ d := v.AuxInt
+ 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
+ v0 := b.NewValue0(v.Line, OpARM64SRAconst, x.Type)
+ v0.AuxInt = d
+ v0.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (ANDshiftRA x (MOVDconst [c]) [d])
+ // cond:
+ // result: (ANDconst x [int64(int64(c)>>uint64(d))])
+ for {
+ d := v.AuxInt
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64MOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpARM64ANDconst)
+ v.AuxInt = int64(int64(c) >> uint64(d))
+ v.AddArg(x)
+ return true
+ }
+ // match: (ANDshiftRA x y:(SRAconst x [c]) [d])
+ // cond: c==d
+ // result: y
+ for {
+ d := v.AuxInt
+ x := v.Args[0]
+ y := v.Args[1]
+ if y.Op != OpARM64SRAconst {
+ break
+ }
+ c := y.AuxInt
+ if x != y.Args[0] {
+ break
+ }
+ if !(c == d) {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = y.Type
+ v.AddArg(y)
+ return true
+ }
+ return false
+}
+func rewriteValueARM64_OpARM64ANDshiftRL(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ANDshiftRL (MOVDconst [c]) x [d])
+ // cond:
+ // result: (ANDconst [c] (SRLconst <x.Type> x [d]))
+ for {
+ d := v.AuxInt
+ 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
+ v0 := b.NewValue0(v.Line, OpARM64SRLconst, x.Type)
+ v0.AuxInt = d
+ v0.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (ANDshiftRL x (MOVDconst [c]) [d])
+ // cond:
+ // result: (ANDconst x [int64(uint64(c)>>uint64(d))])
+ for {
+ d := v.AuxInt
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64MOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpARM64ANDconst)
+ v.AuxInt = int64(uint64(c) >> uint64(d))
+ v.AddArg(x)
+ return true
+ }
+ // match: (ANDshiftRL x y:(SRLconst x [c]) [d])
+ // cond: c==d
+ // result: y
+ for {
+ d := v.AuxInt
+ x := v.Args[0]
+ y := v.Args[1]
+ if y.Op != OpARM64SRLconst {
+ break
+ }
+ c := y.AuxInt
+ if x != y.Args[0] {
+ break
+ }
+ if !(c == d) {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = y.Type
+ v.AddArg(y)
+ return true
+ }
+ return false
+}
+func rewriteValueARM64_OpARM64BIC(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (BIC x (MOVDconst [c]))
+ // cond:
+ // result: (BICconst [c] x)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64MOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpARM64BICconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (BIC x x)
+ // cond:
+ // result: (MOVDconst [0])
+ for {
+ x := v.Args[0]
+ if x != v.Args[1] {
+ break
+ }
+ v.reset(OpARM64MOVDconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (BIC x (SLLconst [c] y))
+ // cond:
+ // result: (BICshiftLL x y [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64SLLconst {
+ break
+ }
+ c := v_1.AuxInt
+ y := v_1.Args[0]
+ v.reset(OpARM64BICshiftLL)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (BIC x (SRLconst [c] y))
+ // cond:
+ // result: (BICshiftRL x y [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64SRLconst {
+ break
+ }
+ c := v_1.AuxInt
+ y := v_1.Args[0]
+ v.reset(OpARM64BICshiftRL)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (BIC x (SRAconst [c] y))
+ // cond:
+ // result: (BICshiftRA x y [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64SRAconst {
+ break
+ }
+ c := v_1.AuxInt
+ y := v_1.Args[0]
+ v.reset(OpARM64BICshiftRA)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ return false
+}
+func rewriteValueARM64_OpARM64BICconst(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (BICconst [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: (BICconst [-1] _)
+ // cond:
+ // result: (MOVDconst [0])
+ for {
+ if v.AuxInt != -1 {
+ break
+ }
+ v.reset(OpARM64MOVDconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (BICconst [c] (MOVDconst [d]))
+ // cond:
+ // result: (MOVDconst [d&^c])
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64MOVDconst {
+ break
+ }
+ d := v_0.AuxInt
+ v.reset(OpARM64MOVDconst)
+ v.AuxInt = d &^ c
+ return true
+ }
+ return false
+}
+func rewriteValueARM64_OpARM64BICshiftLL(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (BICshiftLL x (MOVDconst [c]) [d])
+ // cond:
+ // result: (BICconst x [int64(uint64(c)<<uint64(d))])
+ for {
+ d := v.AuxInt
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64MOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpARM64BICconst)
+ v.AuxInt = int64(uint64(c) << uint64(d))
+ v.AddArg(x)
+ return true
+ }
+ // match: (BICshiftLL x (SLLconst x [c]) [d])
+ // cond: c==d
+ // result: (MOVDconst [0])
+ for {
+ d := v.AuxInt
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64SLLconst {
+ break
+ }
+ c := v_1.AuxInt
+ if x != v_1.Args[0] {
+ break
+ }
+ if !(c == d) {
+ break
+ }
+ v.reset(OpARM64MOVDconst)
+ v.AuxInt = 0
+ return true
+ }
+ return false
+}
+func rewriteValueARM64_OpARM64BICshiftRA(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (BICshiftRA x (MOVDconst [c]) [d])
+ // cond:
+ // result: (BICconst x [int64(int64(c)>>uint64(d))])
+ for {
+ d := v.AuxInt
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64MOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpARM64BICconst)
+ v.AuxInt = int64(int64(c) >> uint64(d))
+ v.AddArg(x)
+ return true
+ }
+ // match: (BICshiftRA x (SRAconst x [c]) [d])
+ // cond: c==d
+ // result: (MOVDconst [0])
+ for {
+ d := v.AuxInt
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64SRAconst {
+ break
+ }
+ c := v_1.AuxInt
+ if x != v_1.Args[0] {
+ break
+ }
+ if !(c == d) {
+ break
+ }
+ v.reset(OpARM64MOVDconst)
+ v.AuxInt = 0
+ return true
+ }
+ return false
+}
+func rewriteValueARM64_OpARM64BICshiftRL(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (BICshiftRL x (MOVDconst [c]) [d])
+ // cond:
+ // result: (BICconst x [int64(uint64(c)>>uint64(d))])
+ for {
+ d := v.AuxInt
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64MOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpARM64BICconst)
+ v.AuxInt = int64(uint64(c) >> uint64(d))
+ v.AddArg(x)
+ return true
+ }
+ // match: (BICshiftRL x (SRLconst x [c]) [d])
+ // cond: c==d
+ // result: (MOVDconst [0])
+ for {
+ d := v.AuxInt
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64SRLconst {
+ break
+ }
+ c := v_1.AuxInt
+ if x != v_1.Args[0] {
+ break
+ }
+ if !(c == d) {
+ break
+ }
+ v.reset(OpARM64MOVDconst)
+ v.AuxInt = 0
+ return true
+ }
+ return false
+}
+func rewriteValueARM64_OpARM64CMP(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (CMP x (MOVDconst [c]))
+ // cond:
+ // result: (CMPconst [c] x)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64MOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpARM64CMPconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (CMP (MOVDconst [c]) x)
+ // cond:
+ // result: (InvertFlags (CMPconst [c] x))
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64MOVDconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ v.reset(OpARM64InvertFlags)
+ v0 := b.NewValue0(v.Line, OpARM64CMPconst, TypeFlags)
+ v0.AuxInt = c
+ v0.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (CMP x (SLLconst [c] y))
+ // cond:
+ // result: (CMPshiftLL x y [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64SLLconst {
+ break
+ }
+ c := v_1.AuxInt
+ y := v_1.Args[0]
+ v.reset(OpARM64CMPshiftLL)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (CMP (SLLconst [c] y) x)
+ // cond:
+ // result: (InvertFlags (CMPshiftLL x y [c]))
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64SLLconst {
+ break
+ }
+ c := v_0.AuxInt
+ y := v_0.Args[0]
+ x := v.Args[1]
+ v.reset(OpARM64InvertFlags)
+ v0 := b.NewValue0(v.Line, OpARM64CMPshiftLL, TypeFlags)
+ v0.AuxInt = c
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (CMP x (SRLconst [c] y))
+ // cond:
+ // result: (CMPshiftRL x y [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64SRLconst {
+ break
+ }
+ c := v_1.AuxInt
+ y := v_1.Args[0]
+ v.reset(OpARM64CMPshiftRL)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (CMP (SRLconst [c] y) x)
+ // cond:
+ // result: (InvertFlags (CMPshiftRL x y [c]))
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64SRLconst {
+ break
+ }
+ c := v_0.AuxInt
+ y := v_0.Args[0]
+ x := v.Args[1]
+ v.reset(OpARM64InvertFlags)
+ v0 := b.NewValue0(v.Line, OpARM64CMPshiftRL, TypeFlags)
+ v0.AuxInt = c
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (CMP x (SRAconst [c] y))
+ // cond:
+ // result: (CMPshiftRA x y [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64SRAconst {
+ break
+ }
+ c := v_1.AuxInt
+ y := v_1.Args[0]
+ v.reset(OpARM64CMPshiftRA)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (CMP (SRAconst [c] y) x)
+ // cond:
+ // result: (InvertFlags (CMPshiftRA x y [c]))
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64SRAconst {
+ break
+ }
+ c := v_0.AuxInt
+ y := v_0.Args[0]
+ x := v.Args[1]
+ v.reset(OpARM64InvertFlags)
+ v0 := b.NewValue0(v.Line, OpARM64CMPshiftRA, TypeFlags)
+ v0.AuxInt = c
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+ return false
+}
+func rewriteValueARM64_OpARM64CMPW(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (CMPW x (MOVDconst [c]))
+ // cond:
+ // result: (CMPWconst [int64(int32(c))] x)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64MOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpARM64CMPWconst)
+ v.AuxInt = int64(int32(c))
+ v.AddArg(x)
+ return true
+ }
+ // match: (CMPW (MOVDconst [c]) x)
+ // cond:
+ // result: (InvertFlags (CMPWconst [int64(int32(c))] x))
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64MOVDconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ v.reset(OpARM64InvertFlags)
+ v0 := b.NewValue0(v.Line, OpARM64CMPWconst, TypeFlags)
+ v0.AuxInt = int64(int32(c))
+ v0.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+ return false
+}
+func rewriteValueARM64_OpARM64CMPWconst(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (CMPWconst (MOVDconst [x]) [y])
+ // cond: int32(x)==int32(y)
+ // result: (FlagEQ)
+ for {
+ y := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64MOVDconst {
+ break
+ }
+ x := v_0.AuxInt
+ if !(int32(x) == int32(y)) {
+ break
+ }
+ v.reset(OpARM64FlagEQ)
+ return true
+ }
+ // match: (CMPWconst (MOVDconst [x]) [y])
+ // cond: int32(x)<int32(y) && uint32(x)<uint32(y)
+ // result: (FlagLT_ULT)
+ for {
+ y := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64MOVDconst {
+ break
+ }
+ x := v_0.AuxInt
+ if !(int32(x) < int32(y) && uint32(x) < uint32(y)) {
+ break
+ }
+ v.reset(OpARM64FlagLT_ULT)
+ return true
+ }
+ // match: (CMPWconst (MOVDconst [x]) [y])
+ // cond: int32(x)<int32(y) && uint32(x)>uint32(y)
+ // result: (FlagLT_UGT)
+ for {
+ y := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64MOVDconst {
+ break
+ }
+ x := v_0.AuxInt
+ if !(int32(x) < int32(y) && uint32(x) > uint32(y)) {
+ break
+ }
+ v.reset(OpARM64FlagLT_UGT)
+ return true
+ }
+ // match: (CMPWconst (MOVDconst [x]) [y])
+ // cond: int32(x)>int32(y) && uint32(x)<uint32(y)
+ // result: (FlagGT_ULT)
+ for {
+ y := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64MOVDconst {
+ break
+ }
+ x := v_0.AuxInt
+ if !(int32(x) > int32(y) && uint32(x) < uint32(y)) {
+ break
+ }
+ v.reset(OpARM64FlagGT_ULT)
+ return true
+ }
+ // match: (CMPWconst (MOVDconst [x]) [y])
+ // cond: int32(x)>int32(y) && uint32(x)>uint32(y)
+ // result: (FlagGT_UGT)
+ for {
+ y := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64MOVDconst {
+ break
+ }
+ x := v_0.AuxInt
+ if !(int32(x) > int32(y) && uint32(x) > uint32(y)) {
+ break
+ }
+ v.reset(OpARM64FlagGT_UGT)
+ return true
+ }
+ // match: (CMPWconst (MOVBUreg _) [c])
+ // cond: 0xff < int32(c)
+ // result: (FlagLT_ULT)
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64MOVBUreg {
+ break
+ }
+ if !(0xff < int32(c)) {
+ break
+ }
+ v.reset(OpARM64FlagLT_ULT)
+ return true
+ }
+ // match: (CMPWconst (MOVHUreg _) [c])
+ // cond: 0xffff < int32(c)
+ // result: (FlagLT_ULT)
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64MOVHUreg {
+ break
+ }
+ if !(0xffff < int32(c)) {
+ break
+ }
+ v.reset(OpARM64FlagLT_ULT)
+ return true
+ }
+ return false
+}
+func rewriteValueARM64_OpARM64CMPconst(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (CMPconst (MOVDconst [x]) [y])
+ // cond: x==y
+ // result: (FlagEQ)
+ for {
+ y := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64MOVDconst {
+ break
+ }
+ x := v_0.AuxInt
+ if !(x == y) {
+ break
+ }
+ v.reset(OpARM64FlagEQ)
+ return true
+ }
+ // match: (CMPconst (MOVDconst [x]) [y])
+ // cond: int64(x)<int64(y) && uint64(x)<uint64(y)
+ // result: (FlagLT_ULT)
+ for {
+ y := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64MOVDconst {
+ break
+ }
+ x := v_0.AuxInt
+ if !(int64(x) < int64(y) && uint64(x) < uint64(y)) {
+ break
+ }
+ v.reset(OpARM64FlagLT_ULT)
+ return true
+ }
+ // match: (CMPconst (MOVDconst [x]) [y])
+ // cond: int64(x)<int64(y) && uint64(x)>uint64(y)
+ // result: (FlagLT_UGT)
+ for {
+ y := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64MOVDconst {
+ break
+ }
+ x := v_0.AuxInt
+ if !(int64(x) < int64(y) && uint64(x) > uint64(y)) {
+ break
+ }
+ v.reset(OpARM64FlagLT_UGT)
+ return true
+ }
+ // match: (CMPconst (MOVDconst [x]) [y])
+ // cond: int64(x)>int64(y) && uint64(x)<uint64(y)
+ // result: (FlagGT_ULT)
+ for {
+ y := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64MOVDconst {
+ break
+ }
+ x := v_0.AuxInt
+ if !(int64(x) > int64(y) && uint64(x) < uint64(y)) {
+ break
+ }
+ v.reset(OpARM64FlagGT_ULT)
+ return true
+ }
+ // match: (CMPconst (MOVDconst [x]) [y])
+ // cond: int64(x)>int64(y) && uint64(x)>uint64(y)
+ // result: (FlagGT_UGT)
+ for {
+ y := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64MOVDconst {
+ break
+ }
+ x := v_0.AuxInt
+ if !(int64(x) > int64(y) && uint64(x) > uint64(y)) {
+ break
+ }
+ v.reset(OpARM64FlagGT_UGT)
+ return true
+ }
+ // match: (CMPconst (MOVBUreg _) [c])
+ // cond: 0xff < c
+ // result: (FlagLT_ULT)
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64MOVBUreg {
+ break
+ }
+ if !(0xff < c) {
+ break
+ }
+ v.reset(OpARM64FlagLT_ULT)
+ return true
+ }
+ // match: (CMPconst (MOVHUreg _) [c])
+ // cond: 0xffff < c
+ // result: (FlagLT_ULT)
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64MOVHUreg {
+ break
+ }
+ if !(0xffff < c) {
+ break
+ }
+ v.reset(OpARM64FlagLT_ULT)
+ return true
+ }
+ // match: (CMPconst (MOVWUreg _) [c])
+ // cond: 0xffffffff < c
+ // result: (FlagLT_ULT)
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64MOVWUreg {
+ break
+ }
+ if !(0xffffffff < c) {
+ break
+ }
+ v.reset(OpARM64FlagLT_ULT)
+ return true
+ }
+ // match: (CMPconst (ANDconst _ [m]) [n])
+ // cond: 0 <= m && m < n
+ // result: (FlagLT_ULT)
+ for {
+ n := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64ANDconst {
+ break
+ }
+ m := v_0.AuxInt
+ if !(0 <= m && m < n) {
+ break
+ }
+ v.reset(OpARM64FlagLT_ULT)
+ return true
+ }
+ // match: (CMPconst (SRLconst _ [c]) [n])
+ // cond: 0 <= n && 0 < c && c <= 63 && (1<<uint64(64-c)) <= uint64(n)
+ // result: (FlagLT_ULT)
+ for {
+ n := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64SRLconst {
+ break
+ }
+ c := v_0.AuxInt
+ if !(0 <= n && 0 < c && c <= 63 && (1<<uint64(64-c)) <= uint64(n)) {
+ break
+ }
+ v.reset(OpARM64FlagLT_ULT)
+ return true
+ }
+ return false
+}
+func rewriteValueARM64_OpARM64CMPshiftLL(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (CMPshiftLL (MOVDconst [c]) x [d])
+ // cond:
+ // result: (InvertFlags (CMPconst [c] (SLLconst <x.Type> x [d])))
+ for {
+ d := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64MOVDconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ v.reset(OpARM64InvertFlags)
+ v0 := b.NewValue0(v.Line, OpARM64CMPconst, TypeFlags)
+ v0.AuxInt = c
+ v1 := b.NewValue0(v.Line, OpARM64SLLconst, x.Type)
+ v1.AuxInt = d
+ v1.AddArg(x)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (CMPshiftLL x (MOVDconst [c]) [d])
+ // cond:
+ // result: (CMPconst x [int64(uint64(c)<<uint64(d))])
+ for {
+ d := v.AuxInt
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64MOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpARM64CMPconst)
+ v.AuxInt = int64(uint64(c) << uint64(d))
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValueARM64_OpARM64CMPshiftRA(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (CMPshiftRA (MOVDconst [c]) x [d])
+ // cond:
+ // result: (InvertFlags (CMPconst [c] (SRAconst <x.Type> x [d])))
+ for {
+ d := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64MOVDconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ v.reset(OpARM64InvertFlags)
+ v0 := b.NewValue0(v.Line, OpARM64CMPconst, TypeFlags)
+ v0.AuxInt = c
+ v1 := b.NewValue0(v.Line, OpARM64SRAconst, x.Type)
+ v1.AuxInt = d
+ v1.AddArg(x)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (CMPshiftRA x (MOVDconst [c]) [d])
+ // cond:
+ // result: (CMPconst x [int64(int64(c)>>uint64(d))])
+ for {
+ d := v.AuxInt
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64MOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpARM64CMPconst)
+ v.AuxInt = int64(int64(c) >> uint64(d))
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValueARM64_OpARM64CMPshiftRL(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (CMPshiftRL (MOVDconst [c]) x [d])
+ // cond:
+ // result: (InvertFlags (CMPconst [c] (SRLconst <x.Type> x [d])))
+ for {
+ d := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64MOVDconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ v.reset(OpARM64InvertFlags)
+ v0 := b.NewValue0(v.Line, OpARM64CMPconst, TypeFlags)
+ v0.AuxInt = c
+ v1 := b.NewValue0(v.Line, OpARM64SRLconst, x.Type)
+ v1.AuxInt = d
+ v1.AddArg(x)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (CMPshiftRL x (MOVDconst [c]) [d])
+ // cond:
+ // result: (CMPconst x [int64(uint64(c)>>uint64(d))])
+ for {
+ d := v.AuxInt
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64MOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpARM64CMPconst)
+ v.AuxInt = int64(uint64(c) >> uint64(d))
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValueARM64_OpARM64CSELULT(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (CSELULT x (MOVDconst [0]) flag)
+ // cond:
+ // result: (CSELULT0 x flag)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64MOVDconst {
+ break
+ }
+ if v_1.AuxInt != 0 {
+ break
+ }
+ flag := v.Args[2]
+ v.reset(OpARM64CSELULT0)
+ v.AddArg(x)
+ v.AddArg(flag)
+ return true
+ }
+ // match: (CSELULT _ y (FlagEQ))
+ // cond:
+ // result: y
+ for {
+ y := v.Args[1]
+ v_2 := v.Args[2]
+ if v_2.Op != OpARM64FlagEQ {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = y.Type
+ v.AddArg(y)
+ return true
+ }
+ // match: (CSELULT x _ (FlagLT_ULT))
+ // cond:
+ // result: x
+ for {
+ x := v.Args[0]
+ v_2 := v.Args[2]
+ if v_2.Op != OpARM64FlagLT_ULT {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ // match: (CSELULT _ y (FlagLT_UGT))
+ // cond:
+ // result: y
+ for {
+ y := v.Args[1]
+ v_2 := v.Args[2]
+ if v_2.Op != OpARM64FlagLT_UGT {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = y.Type
+ v.AddArg(y)
+ return true
+ }
+ // match: (CSELULT x _ (FlagGT_ULT))
+ // cond:
+ // result: x
+ for {
+ x := v.Args[0]
+ v_2 := v.Args[2]
+ if v_2.Op != OpARM64FlagGT_ULT {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ // match: (CSELULT _ y (FlagGT_UGT))
+ // cond:
+ // result: y
+ for {
+ y := v.Args[1]
+ v_2 := v.Args[2]
+ if v_2.Op != OpARM64FlagGT_UGT {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = y.Type
+ v.AddArg(y)
+ return true
+ }
+ return false
+}
+func rewriteValueARM64_OpARM64CSELULT0(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (CSELULT0 _ (FlagEQ))
+ // cond:
+ // result: (MOVDconst [0])
+ for {
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64FlagEQ {
+ break
+ }
+ v.reset(OpARM64MOVDconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (CSELULT0 x (FlagLT_ULT))
+ // cond:
+ // result: x
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64FlagLT_ULT {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ // match: (CSELULT0 _ (FlagLT_UGT))
+ // cond:
+ // result: (MOVDconst [0])
+ for {
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64FlagLT_UGT {
+ break
+ }
+ v.reset(OpARM64MOVDconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (CSELULT0 x (FlagGT_ULT))
+ // cond:
+ // result: x
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64FlagGT_ULT {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ // match: (CSELULT0 _ (FlagGT_UGT))
+ // cond:
+ // result: (MOVDconst [0])
+ for {
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64FlagGT_UGT {
+ break
+ }
+ v.reset(OpARM64MOVDconst)
+ v.AuxInt = 0
+ return true
+ }
+ return false
+}
+func rewriteValueARM64_OpARM64DIV(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (DIV (MOVDconst [c]) (MOVDconst [d]))
+ // cond:
+ // result: (MOVDconst [int64(c)/int64(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 = int64(c) / int64(d)
+ return true
+ }
+ return false
+}
+func rewriteValueARM64_OpARM64DIVW(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (DIVW (MOVDconst [c]) (MOVDconst [d]))
+ // cond:
+ // result: (MOVDconst [int64(int32(c)/int32(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 = int64(int32(c) / int32(d))
+ return true
+ }
+ return false
+}
+func rewriteValueARM64_OpARM64Equal(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Equal (FlagEQ))
+ // cond:
+ // result: (MOVDconst [1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64FlagEQ {
+ break
+ }
+ v.reset(OpARM64MOVDconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (Equal (FlagLT_ULT))
+ // cond:
+ // result: (MOVDconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64FlagLT_ULT {
+ break
+ }
+ v.reset(OpARM64MOVDconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (Equal (FlagLT_UGT))
+ // cond:
+ // result: (MOVDconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64FlagLT_UGT {
+ break
+ }
+ v.reset(OpARM64MOVDconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (Equal (FlagGT_ULT))
+ // cond:
+ // result: (MOVDconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64FlagGT_ULT {
+ break
+ }
+ v.reset(OpARM64MOVDconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (Equal (FlagGT_UGT))
+ // cond:
+ // result: (MOVDconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64FlagGT_UGT {
+ break
+ }
+ v.reset(OpARM64MOVDconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (Equal (InvertFlags x))
+ // cond:
+ // result: (Equal x)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64InvertFlags {
+ break
+ }
+ x := v_0.Args[0]
+ v.reset(OpARM64Equal)
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValueARM64_OpARM64FMOVDload(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (FMOVDload [off1] {sym} (ADDconst [off2] ptr) mem)
+ // cond: (off1+off2)%8==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym)
+ // result: (FMOVDload [off1+off2] {sym} ptr mem)
+ for {
+ off1 := v.AuxInt
+ sym := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64ADDconst {
+ break
+ }
+ off2 := v_0.AuxInt
+ ptr := v_0.Args[0]
+ mem := v.Args[1]
+ if !((off1+off2)%8 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym) && !isAuto(sym)) {
+ break
+ }
+ v.reset(OpARM64FMOVDload)
+ v.AuxInt = off1 + off2
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (FMOVDload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
+ // cond: canMergeSym(sym1,sym2) && ((off1+off2)%8==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym1) && !isAuto(sym1))
+ // result: (FMOVDload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
+ for {
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64MOVDaddr {
+ break
+ }
+ off2 := v_0.AuxInt
+ sym2 := v_0.Aux
+ ptr := v_0.Args[0]
+ mem := v.Args[1]
+ if !(canMergeSym(sym1, sym2) && ((off1+off2)%8 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym1) && !isAuto(sym1))) {
+ break
+ }
+ v.reset(OpARM64FMOVDload)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValueARM64_OpARM64FMOVDstore(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (FMOVDstore [off1] {sym} (ADDconst [off2] ptr) val mem)
+ // cond: (off1+off2)%8==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym)
+ // result: (FMOVDstore [off1+off2] {sym} ptr val mem)
+ for {
+ off1 := v.AuxInt
+ sym := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64ADDconst {
+ break
+ }
+ off2 := v_0.AuxInt
+ ptr := v_0.Args[0]
+ val := v.Args[1]
+ mem := v.Args[2]
+ if !((off1+off2)%8 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym) && !isAuto(sym)) {
+ break
+ }
+ v.reset(OpARM64FMOVDstore)
+ v.AuxInt = off1 + off2
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (FMOVDstore [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) val mem)
+ // cond: canMergeSym(sym1,sym2) && ((off1+off2)%8==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym1) && !isAuto(sym1))
+ // result: (FMOVDstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
+ for {
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64MOVDaddr {
+ 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) && ((off1+off2)%8 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym1) && !isAuto(sym1))) {
+ break
+ }
+ v.reset(OpARM64FMOVDstore)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(ptr)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValueARM64_OpARM64FMOVSload(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (FMOVSload [off1] {sym} (ADDconst [off2] ptr) mem)
+ // cond: (off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym)
+ // result: (FMOVSload [off1+off2] {sym} ptr mem)
+ for {
+ off1 := v.AuxInt
+ sym := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64ADDconst {
+ break
+ }
+ off2 := v_0.AuxInt
+ ptr := v_0.Args[0]
+ mem := v.Args[1]
+ if !((off1+off2)%4 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym) && !isAuto(sym)) {
+ break
+ }
+ v.reset(OpARM64FMOVSload)
+ v.AuxInt = off1 + off2
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (FMOVSload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
+ // cond: canMergeSym(sym1,sym2) && ((off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym1) && !isAuto(sym1))
+ // result: (FMOVSload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
+ for {
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64MOVDaddr {
+ break
+ }
+ off2 := v_0.AuxInt
+ sym2 := v_0.Aux
+ ptr := v_0.Args[0]
+ mem := v.Args[1]
+ if !(canMergeSym(sym1, sym2) && ((off1+off2)%4 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym1) && !isAuto(sym1))) {
+ break
+ }
+ v.reset(OpARM64FMOVSload)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValueARM64_OpARM64FMOVSstore(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (FMOVSstore [off1] {sym} (ADDconst [off2] ptr) val mem)
+ // cond: (off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym)
+ // result: (FMOVSstore [off1+off2] {sym} ptr val mem)
+ for {
+ off1 := v.AuxInt
+ sym := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64ADDconst {
+ break
+ }
+ off2 := v_0.AuxInt
+ ptr := v_0.Args[0]
+ val := v.Args[1]
+ mem := v.Args[2]
+ if !((off1+off2)%4 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym) && !isAuto(sym)) {
+ break
+ }
+ v.reset(OpARM64FMOVSstore)
+ v.AuxInt = off1 + off2
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (FMOVSstore [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) val mem)
+ // cond: canMergeSym(sym1,sym2) && ((off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym1) && !isAuto(sym1))
+ // result: (FMOVSstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
+ for {
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64MOVDaddr {
+ 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) && ((off1+off2)%4 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym1) && !isAuto(sym1))) {
+ break
+ }
+ v.reset(OpARM64FMOVSstore)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(ptr)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValueARM64_OpARM64GreaterEqual(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (GreaterEqual (FlagEQ))
+ // cond:
+ // result: (MOVDconst [1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64FlagEQ {
+ break
+ }
+ v.reset(OpARM64MOVDconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (GreaterEqual (FlagLT_ULT))
+ // cond:
+ // result: (MOVDconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64FlagLT_ULT {
+ break
+ }
+ v.reset(OpARM64MOVDconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (GreaterEqual (FlagLT_UGT))
+ // cond:
+ // result: (MOVDconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64FlagLT_UGT {
+ break
+ }
+ v.reset(OpARM64MOVDconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (GreaterEqual (FlagGT_ULT))
+ // cond:
+ // result: (MOVDconst [1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64FlagGT_ULT {
+ break
+ }
+ v.reset(OpARM64MOVDconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (GreaterEqual (FlagGT_UGT))
+ // cond:
+ // result: (MOVDconst [1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64FlagGT_UGT {
+ break
+ }
+ v.reset(OpARM64MOVDconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (GreaterEqual (InvertFlags x))
+ // cond:
+ // result: (LessEqual x)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64InvertFlags {
+ break
+ }
+ x := v_0.Args[0]
+ v.reset(OpARM64LessEqual)
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValueARM64_OpARM64GreaterEqualU(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (GreaterEqualU (FlagEQ))
+ // cond:
+ // result: (MOVDconst [1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64FlagEQ {
+ break
+ }
+ v.reset(OpARM64MOVDconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (GreaterEqualU (FlagLT_ULT))
+ // cond:
+ // result: (MOVDconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64FlagLT_ULT {
+ break
+ }
+ v.reset(OpARM64MOVDconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (GreaterEqualU (FlagLT_UGT))
+ // cond:
+ // result: (MOVDconst [1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64FlagLT_UGT {
+ break
+ }
+ v.reset(OpARM64MOVDconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (GreaterEqualU (FlagGT_ULT))
+ // cond:
+ // result: (MOVDconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64FlagGT_ULT {
+ break
+ }
+ v.reset(OpARM64MOVDconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (GreaterEqualU (FlagGT_UGT))
+ // cond:
+ // result: (MOVDconst [1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64FlagGT_UGT {
+ break
+ }
+ v.reset(OpARM64MOVDconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (GreaterEqualU (InvertFlags x))
+ // cond:
+ // result: (LessEqualU x)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64InvertFlags {
+ break
+ }
+ x := v_0.Args[0]
+ v.reset(OpARM64LessEqualU)
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValueARM64_OpARM64GreaterThan(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (GreaterThan (FlagEQ))
+ // cond:
+ // result: (MOVDconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64FlagEQ {
+ break
+ }
+ v.reset(OpARM64MOVDconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (GreaterThan (FlagLT_ULT))
+ // cond:
+ // result: (MOVDconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64FlagLT_ULT {
+ break
+ }
+ v.reset(OpARM64MOVDconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (GreaterThan (FlagLT_UGT))
+ // cond:
+ // result: (MOVDconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64FlagLT_UGT {
+ break
+ }
+ v.reset(OpARM64MOVDconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (GreaterThan (FlagGT_ULT))
+ // cond:
+ // result: (MOVDconst [1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64FlagGT_ULT {
+ break
+ }
+ v.reset(OpARM64MOVDconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (GreaterThan (FlagGT_UGT))
+ // cond:
+ // result: (MOVDconst [1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64FlagGT_UGT {
+ break
+ }
+ v.reset(OpARM64MOVDconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (GreaterThan (InvertFlags x))
+ // cond:
+ // result: (LessThan x)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64InvertFlags {
+ break
+ }
+ x := v_0.Args[0]
+ v.reset(OpARM64LessThan)
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValueARM64_OpARM64GreaterThanU(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (GreaterThanU (FlagEQ))
+ // cond:
+ // result: (MOVDconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64FlagEQ {
+ break
+ }
+ v.reset(OpARM64MOVDconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (GreaterThanU (FlagLT_ULT))
+ // cond:
+ // result: (MOVDconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64FlagLT_ULT {
+ break
+ }
+ v.reset(OpARM64MOVDconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (GreaterThanU (FlagLT_UGT))
+ // cond:
+ // result: (MOVDconst [1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64FlagLT_UGT {
+ break
+ }
+ v.reset(OpARM64MOVDconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (GreaterThanU (FlagGT_ULT))
+ // cond:
+ // result: (MOVDconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64FlagGT_ULT {
+ break
+ }
+ v.reset(OpARM64MOVDconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (GreaterThanU (FlagGT_UGT))
+ // cond:
+ // result: (MOVDconst [1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64FlagGT_UGT {
+ break
+ }
+ v.reset(OpARM64MOVDconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (GreaterThanU (InvertFlags x))
+ // cond:
+ // result: (LessThanU x)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64InvertFlags {
+ break
+ }
+ x := v_0.Args[0]
+ v.reset(OpARM64LessThanU)
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValueARM64_OpARM64LessEqual(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (LessEqual (FlagEQ))
+ // cond:
+ // result: (MOVDconst [1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64FlagEQ {
+ break
+ }
+ v.reset(OpARM64MOVDconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (LessEqual (FlagLT_ULT))
+ // cond:
+ // result: (MOVDconst [1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64FlagLT_ULT {
+ break
+ }
+ v.reset(OpARM64MOVDconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (LessEqual (FlagLT_UGT))
+ // cond:
+ // result: (MOVDconst [1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64FlagLT_UGT {
+ break
+ }
+ v.reset(OpARM64MOVDconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (LessEqual (FlagGT_ULT))
+ // cond:
+ // result: (MOVDconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64FlagGT_ULT {
+ break
+ }
+ v.reset(OpARM64MOVDconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (LessEqual (FlagGT_UGT))
+ // cond:
+ // result: (MOVDconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64FlagGT_UGT {
+ break
+ }
+ v.reset(OpARM64MOVDconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (LessEqual (InvertFlags x))
+ // cond:
+ // result: (GreaterEqual x)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64InvertFlags {
+ break
+ }
+ x := v_0.Args[0]
+ v.reset(OpARM64GreaterEqual)
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValueARM64_OpARM64LessEqualU(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (LessEqualU (FlagEQ))
+ // cond:
+ // result: (MOVDconst [1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64FlagEQ {
+ break
+ }
+ v.reset(OpARM64MOVDconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (LessEqualU (FlagLT_ULT))
+ // cond:
+ // result: (MOVDconst [1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64FlagLT_ULT {
+ break
+ }
+ v.reset(OpARM64MOVDconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (LessEqualU (FlagLT_UGT))
+ // cond:
+ // result: (MOVDconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64FlagLT_UGT {
+ break
+ }
+ v.reset(OpARM64MOVDconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (LessEqualU (FlagGT_ULT))
+ // cond:
+ // result: (MOVDconst [1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64FlagGT_ULT {
+ break
+ }
+ v.reset(OpARM64MOVDconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (LessEqualU (FlagGT_UGT))
+ // cond:
+ // result: (MOVDconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64FlagGT_UGT {
+ break
+ }
+ v.reset(OpARM64MOVDconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (LessEqualU (InvertFlags x))
+ // cond:
+ // result: (GreaterEqualU x)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64InvertFlags {
+ break
+ }
+ x := v_0.Args[0]
+ v.reset(OpARM64GreaterEqualU)
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValueARM64_OpARM64LessThan(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (LessThan (FlagEQ))
+ // cond:
+ // result: (MOVDconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64FlagEQ {
+ break
+ }
+ v.reset(OpARM64MOVDconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (LessThan (FlagLT_ULT))
+ // cond:
+ // result: (MOVDconst [1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64FlagLT_ULT {
+ break
+ }
+ v.reset(OpARM64MOVDconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (LessThan (FlagLT_UGT))
+ // cond:
+ // result: (MOVDconst [1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64FlagLT_UGT {
+ break
+ }
+ v.reset(OpARM64MOVDconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (LessThan (FlagGT_ULT))
+ // cond:
+ // result: (MOVDconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64FlagGT_ULT {
+ break
+ }
+ v.reset(OpARM64MOVDconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (LessThan (FlagGT_UGT))
+ // cond:
+ // result: (MOVDconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64FlagGT_UGT {
+ break
+ }
+ v.reset(OpARM64MOVDconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (LessThan (InvertFlags x))
+ // cond:
+ // result: (GreaterThan x)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64InvertFlags {
+ break
+ }
+ x := v_0.Args[0]
+ v.reset(OpARM64GreaterThan)
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValueARM64_OpARM64LessThanU(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (LessThanU (FlagEQ))
+ // cond:
+ // result: (MOVDconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64FlagEQ {
+ break
+ }
+ v.reset(OpARM64MOVDconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (LessThanU (FlagLT_ULT))
+ // cond:
+ // result: (MOVDconst [1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64FlagLT_ULT {
+ break
+ }
+ v.reset(OpARM64MOVDconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (LessThanU (FlagLT_UGT))
+ // cond:
+ // result: (MOVDconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64FlagLT_UGT {
+ break
+ }
+ v.reset(OpARM64MOVDconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (LessThanU (FlagGT_ULT))
+ // cond:
+ // result: (MOVDconst [1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64FlagGT_ULT {
+ break
+ }
+ v.reset(OpARM64MOVDconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (LessThanU (FlagGT_UGT))
+ // cond:
+ // result: (MOVDconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64FlagGT_UGT {
+ break
+ }
+ v.reset(OpARM64MOVDconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (LessThanU (InvertFlags x))
+ // cond:
+ // result: (GreaterThanU x)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64InvertFlags {
+ break
+ }
+ x := v_0.Args[0]
+ v.reset(OpARM64GreaterThanU)
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValueARM64_OpARM64MOD(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (MOD (MOVDconst [c]) (MOVDconst [d]))
+ // cond:
+ // result: (MOVDconst [int64(c)%int64(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 = int64(c) % int64(d)
+ return true
+ }
+ return false
+}
+func rewriteValueARM64_OpARM64MODW(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (MODW (MOVDconst [c]) (MOVDconst [d]))
+ // cond:
+ // result: (MOVDconst [int64(int32(c)%int32(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 = int64(int32(c) % int32(d))
+ return true
+ }
+ return false
+}
+func rewriteValueARM64_OpARM64MOVBUload(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (MOVBUload [off1] {sym} (ADDconst [off2] ptr) mem)
+ // cond:
+ // result: (MOVBUload [off1+off2] {sym} ptr mem)
+ for {
+ off1 := v.AuxInt
+ sym := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64ADDconst {
+ break
+ }
+ off2 := v_0.AuxInt
+ ptr := v_0.Args[0]
+ mem := v.Args[1]
+ v.reset(OpARM64MOVBUload)
+ v.AuxInt = off1 + off2
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVBUload [off1] {sym1} (MOVDaddr [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_0 := v.Args[0]
+ if v_0.Op != OpARM64MOVDaddr {
+ break
+ }
+ off2 := v_0.AuxInt
+ sym2 := v_0.Aux
+ ptr := v_0.Args[0]
+ mem := v.Args[1]
+ if !(canMergeSym(sym1, sym2)) {
+ break
+ }
+ v.reset(OpARM64MOVBUload)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVBUload [off] {sym} ptr (MOVBstorezero [off2] {sym2} ptr2 _))
+ // cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
+ // result: (MOVDconst [0])
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64MOVBstorezero {
+ break
+ }
+ off2 := v_1.AuxInt
+ sym2 := v_1.Aux
+ ptr2 := v_1.Args[0]
+ if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
+ break
+ }
+ v.reset(OpARM64MOVDconst)
+ v.AuxInt = 0
+ return true
+ }
+ return false
+}
+func rewriteValueARM64_OpARM64MOVBUreg(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (MOVBUreg x:(MOVBUload _ _))
+ // cond:
+ // result: (MOVDreg x)
+ for {
+ x := v.Args[0]
+ if x.Op != OpARM64MOVBUload {
+ break
+ }
+ v.reset(OpARM64MOVDreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVBUreg x:(MOVBUreg _))
+ // cond:
+ // result: (MOVDreg x)
+ for {
+ x := v.Args[0]
+ if x.Op != OpARM64MOVBUreg {
+ break
+ }
+ v.reset(OpARM64MOVDreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVBUreg (MOVDconst [c]))
+ // cond:
+ // result: (MOVDconst [int64(uint8(c))])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64MOVDconst {
+ break
+ }
+ c := v_0.AuxInt
+ v.reset(OpARM64MOVDconst)
+ v.AuxInt = int64(uint8(c))
+ return true
+ }
+ return false
+}
+func rewriteValueARM64_OpARM64MOVBload(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (MOVBload [off1] {sym} (ADDconst [off2] ptr) mem)
+ // cond:
+ // result: (MOVBload [off1+off2] {sym} ptr mem)
+ for {
+ off1 := v.AuxInt
+ sym := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64ADDconst {
+ break
+ }
+ off2 := v_0.AuxInt
+ ptr := v_0.Args[0]
+ mem := v.Args[1]
+ v.reset(OpARM64MOVBload)
+ v.AuxInt = off1 + off2
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVBload [off1] {sym1} (MOVDaddr [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_0 := v.Args[0]
+ if v_0.Op != OpARM64MOVDaddr {
+ break
+ }
+ off2 := v_0.AuxInt
+ sym2 := v_0.Aux
+ ptr := v_0.Args[0]
+ mem := v.Args[1]
+ if !(canMergeSym(sym1, sym2)) {
+ break
+ }
+ v.reset(OpARM64MOVBload)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVBload [off] {sym} ptr (MOVBstorezero [off2] {sym2} ptr2 _))
+ // cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
+ // result: (MOVDconst [0])
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64MOVBstorezero {
+ break
+ }
+ off2 := v_1.AuxInt
+ sym2 := v_1.Aux
+ ptr2 := v_1.Args[0]
+ if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
+ break
+ }
+ v.reset(OpARM64MOVDconst)
+ v.AuxInt = 0
+ return true
+ }
+ return false
+}
+func rewriteValueARM64_OpARM64MOVBreg(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (MOVBreg x:(MOVBload _ _))
+ // cond:
+ // result: (MOVDreg x)
+ for {
+ x := v.Args[0]
+ if x.Op != OpARM64MOVBload {
+ break
+ }
+ v.reset(OpARM64MOVDreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVBreg x:(MOVBreg _))
+ // cond:
+ // result: (MOVDreg x)
+ for {
+ x := v.Args[0]
+ if x.Op != OpARM64MOVBreg {
+ break
+ }
+ v.reset(OpARM64MOVDreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVBreg (MOVDconst [c]))
+ // cond:
+ // result: (MOVDconst [int64(int8(c))])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64MOVDconst {
+ break
+ }
+ c := v_0.AuxInt
+ v.reset(OpARM64MOVDconst)
+ v.AuxInt = int64(int8(c))
+ return true
+ }
+ return false
+}
+func rewriteValueARM64_OpARM64MOVBstore(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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_0 := v.Args[0]
+ if v_0.Op != OpARM64ADDconst {
+ break
+ }
+ off2 := v_0.AuxInt
+ ptr := v_0.Args[0]
+ val := v.Args[1]
+ mem := v.Args[2]
+ v.reset(OpARM64MOVBstore)
+ v.AuxInt = off1 + off2
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVBstore [off1] {sym1} (MOVDaddr [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_0 := v.Args[0]
+ if v_0.Op != OpARM64MOVDaddr {
+ 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(OpARM64MOVBstore)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(ptr)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVBstore [off] {sym} ptr (MOVDconst [0]) mem)
+ // cond:
+ // result: (MOVBstorezero [off] {sym} ptr mem)
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64MOVDconst {
+ break
+ }
+ if v_1.AuxInt != 0 {
+ break
+ }
+ mem := v.Args[2]
+ v.reset(OpARM64MOVBstorezero)
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVBstore [off] {sym} ptr (MOVBreg x) mem)
+ // cond:
+ // result: (MOVBstore [off] {sym} ptr x mem)
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64MOVBreg {
+ break
+ }
+ x := v_1.Args[0]
+ mem := v.Args[2]
+ v.reset(OpARM64MOVBstore)
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(x)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVBstore [off] {sym} ptr (MOVBUreg x) mem)
+ // cond:
+ // result: (MOVBstore [off] {sym} ptr x mem)
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64MOVBUreg {
+ break
+ }
+ x := v_1.Args[0]
+ mem := v.Args[2]
+ v.reset(OpARM64MOVBstore)
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(x)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVBstore [off] {sym} ptr (MOVHreg x) mem)
+ // cond:
+ // result: (MOVBstore [off] {sym} ptr x mem)
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64MOVHreg {
+ break
+ }
+ x := v_1.Args[0]
+ mem := v.Args[2]
+ v.reset(OpARM64MOVBstore)
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(x)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVBstore [off] {sym} ptr (MOVHUreg x) mem)
+ // cond:
+ // result: (MOVBstore [off] {sym} ptr x mem)
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64MOVHUreg {
+ break
+ }
+ x := v_1.Args[0]
+ mem := v.Args[2]
+ v.reset(OpARM64MOVBstore)
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(x)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVBstore [off] {sym} ptr (MOVWreg x) mem)
+ // cond:
+ // result: (MOVBstore [off] {sym} ptr x mem)
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64MOVWreg {
+ break
+ }
+ x := v_1.Args[0]
+ mem := v.Args[2]
+ v.reset(OpARM64MOVBstore)
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(x)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVBstore [off] {sym} ptr (MOVWUreg x) mem)
+ // cond:
+ // result: (MOVBstore [off] {sym} ptr x mem)
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64MOVWUreg {
+ break
+ }
+ x := v_1.Args[0]
+ mem := v.Args[2]
+ v.reset(OpARM64MOVBstore)
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(x)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValueARM64_OpARM64MOVBstorezero(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (MOVBstorezero [off1] {sym} (ADDconst [off2] ptr) mem)
+ // cond:
+ // result: (MOVBstorezero [off1+off2] {sym} ptr mem)
+ for {
+ off1 := v.AuxInt
+ sym := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64ADDconst {
+ break
+ }
+ off2 := v_0.AuxInt
+ ptr := v_0.Args[0]
+ mem := v.Args[1]
+ v.reset(OpARM64MOVBstorezero)
+ v.AuxInt = off1 + off2
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVBstorezero [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
+ // cond: canMergeSym(sym1,sym2)
+ // result: (MOVBstorezero [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
+ for {
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64MOVDaddr {
+ break
+ }
+ off2 := v_0.AuxInt
+ sym2 := v_0.Aux
+ ptr := v_0.Args[0]
+ mem := v.Args[1]
+ if !(canMergeSym(sym1, sym2)) {
+ break
+ }
+ v.reset(OpARM64MOVBstorezero)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValueARM64_OpARM64MOVDload(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (MOVDload [off1] {sym} (ADDconst [off2] ptr) mem)
+ // cond: (off1+off2)%8==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym)
+ // result: (MOVDload [off1+off2] {sym} ptr mem)
+ for {
+ off1 := v.AuxInt
+ sym := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64ADDconst {
+ break
+ }
+ off2 := v_0.AuxInt
+ ptr := v_0.Args[0]
+ mem := v.Args[1]
+ if !((off1+off2)%8 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym) && !isAuto(sym)) {
+ break
+ }
+ v.reset(OpARM64MOVDload)
+ v.AuxInt = off1 + off2
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVDload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
+ // cond: canMergeSym(sym1,sym2) && ((off1+off2)%8==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym1) && !isAuto(sym1))
+ // result: (MOVDload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
+ for {
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64MOVDaddr {
+ break
+ }
+ off2 := v_0.AuxInt
+ sym2 := v_0.Aux
+ ptr := v_0.Args[0]
+ mem := v.Args[1]
+ if !(canMergeSym(sym1, sym2) && ((off1+off2)%8 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym1) && !isAuto(sym1))) {
+ break
+ }
+ v.reset(OpARM64MOVDload)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVDload [off] {sym} ptr (MOVDstorezero [off2] {sym2} ptr2 _))
+ // cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
+ // result: (MOVDconst [0])
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64MOVDstorezero {
+ break
+ }
+ off2 := v_1.AuxInt
+ sym2 := v_1.Aux
+ ptr2 := v_1.Args[0]
+ if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
+ break
+ }
+ v.reset(OpARM64MOVDconst)
+ v.AuxInt = 0
+ return true
+ }
+ return false
+}
+func rewriteValueARM64_OpARM64MOVDreg(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (MOVDreg x)
+ // cond: x.Uses == 1
+ // result: (MOVDnop x)
+ for {
+ x := v.Args[0]
+ if !(x.Uses == 1) {
+ break
+ }
+ v.reset(OpARM64MOVDnop)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVDreg (MOVDconst [c]))
+ // cond:
+ // result: (MOVDconst [c])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64MOVDconst {
+ break
+ }
+ c := v_0.AuxInt
+ v.reset(OpARM64MOVDconst)
+ v.AuxInt = c
+ return true
+ }
+ return false
+}
+func rewriteValueARM64_OpARM64MOVDstore(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (MOVDstore [off1] {sym} (ADDconst [off2] ptr) val mem)
+ // cond: (off1+off2)%8==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym)
+ // result: (MOVDstore [off1+off2] {sym} ptr val mem)
+ for {
+ off1 := v.AuxInt
+ sym := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64ADDconst {
+ break
+ }
+ off2 := v_0.AuxInt
+ ptr := v_0.Args[0]
+ val := v.Args[1]
+ mem := v.Args[2]
+ if !((off1+off2)%8 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym) && !isAuto(sym)) {
+ break
+ }
+ v.reset(OpARM64MOVDstore)
+ v.AuxInt = off1 + off2
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVDstore [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) val mem)
+ // cond: canMergeSym(sym1,sym2) && ((off1+off2)%8==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym1) && !isAuto(sym1))
+ // result: (MOVDstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
+ for {
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64MOVDaddr {
+ 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) && ((off1+off2)%8 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym1) && !isAuto(sym1))) {
+ break
+ }
+ v.reset(OpARM64MOVDstore)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(ptr)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVDstore [off] {sym} ptr (MOVDconst [0]) mem)
+ // cond:
+ // result: (MOVDstorezero [off] {sym} ptr mem)
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64MOVDconst {
+ break
+ }
+ if v_1.AuxInt != 0 {
+ break
+ }
+ mem := v.Args[2]
+ v.reset(OpARM64MOVDstorezero)
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValueARM64_OpARM64MOVDstorezero(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (MOVDstorezero [off1] {sym} (ADDconst [off2] ptr) mem)
+ // cond: (off1+off2)%2==8 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym)
+ // result: (MOVDstorezero [off1+off2] {sym} ptr mem)
+ for {
+ off1 := v.AuxInt
+ sym := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64ADDconst {
+ break
+ }
+ off2 := v_0.AuxInt
+ ptr := v_0.Args[0]
+ mem := v.Args[1]
+ if !((off1+off2)%2 == 8 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym) && !isAuto(sym)) {
+ break
+ }
+ v.reset(OpARM64MOVDstorezero)
+ v.AuxInt = off1 + off2
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVDstorezero [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
+ // cond: canMergeSym(sym1,sym2) && ((off1+off2)%8==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym1) && !isAuto(sym1))
+ // result: (MOVDstorezero [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
+ for {
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64MOVDaddr {
+ break
+ }
+ off2 := v_0.AuxInt
+ sym2 := v_0.Aux
+ ptr := v_0.Args[0]
+ mem := v.Args[1]
+ if !(canMergeSym(sym1, sym2) && ((off1+off2)%8 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym1) && !isAuto(sym1))) {
+ break
+ }
+ v.reset(OpARM64MOVDstorezero)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValueARM64_OpARM64MOVHUload(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (MOVHUload [off1] {sym} (ADDconst [off2] ptr) mem)
+ // cond: (off1+off2)%2==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym)
+ // result: (MOVHUload [off1+off2] {sym} ptr mem)
+ for {
+ off1 := v.AuxInt
+ sym := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64ADDconst {
+ break
+ }
+ off2 := v_0.AuxInt
+ ptr := v_0.Args[0]
+ mem := v.Args[1]
+ if !((off1+off2)%2 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym) && !isAuto(sym)) {
+ break
+ }
+ v.reset(OpARM64MOVHUload)
+ v.AuxInt = off1 + off2
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVHUload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
+ // cond: canMergeSym(sym1,sym2) && ((off1+off2)%2==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym1) && !isAuto(sym1))
+ // result: (MOVHUload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
+ for {
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64MOVDaddr {
+ break
+ }
+ off2 := v_0.AuxInt
+ sym2 := v_0.Aux
+ ptr := v_0.Args[0]
+ mem := v.Args[1]
+ if !(canMergeSym(sym1, sym2) && ((off1+off2)%2 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym1) && !isAuto(sym1))) {
+ break
+ }
+ v.reset(OpARM64MOVHUload)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVHUload [off] {sym} ptr (MOVHstorezero [off2] {sym2} ptr2 _))
+ // cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
+ // result: (MOVDconst [0])
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64MOVHstorezero {
+ break
+ }
+ off2 := v_1.AuxInt
+ sym2 := v_1.Aux
+ ptr2 := v_1.Args[0]
+ if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
+ break
+ }
+ v.reset(OpARM64MOVDconst)
+ v.AuxInt = 0
+ return true
+ }
+ return false
+}
+func rewriteValueARM64_OpARM64MOVHUreg(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (MOVHUreg x:(MOVBUload _ _))
+ // cond:
+ // result: (MOVDreg x)
+ for {
+ x := v.Args[0]
+ if x.Op != OpARM64MOVBUload {
+ break
+ }
+ v.reset(OpARM64MOVDreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVHUreg x:(MOVHUload _ _))
+ // cond:
+ // result: (MOVDreg x)
+ for {
+ x := v.Args[0]
+ if x.Op != OpARM64MOVHUload {
+ break
+ }
+ v.reset(OpARM64MOVDreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVHUreg x:(MOVBUreg _))
+ // cond:
+ // result: (MOVDreg x)
+ for {
+ x := v.Args[0]
+ if x.Op != OpARM64MOVBUreg {
+ break
+ }
+ v.reset(OpARM64MOVDreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVHUreg x:(MOVHUreg _))
+ // cond:
+ // result: (MOVDreg x)
+ for {
+ x := v.Args[0]
+ if x.Op != OpARM64MOVHUreg {
+ break
+ }
+ v.reset(OpARM64MOVDreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVHUreg (MOVDconst [c]))
+ // cond:
+ // result: (MOVDconst [int64(uint16(c))])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64MOVDconst {
+ break
+ }
+ c := v_0.AuxInt
+ v.reset(OpARM64MOVDconst)
+ v.AuxInt = int64(uint16(c))
+ return true
+ }
+ return false
+}
+func rewriteValueARM64_OpARM64MOVHload(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (MOVHload [off1] {sym} (ADDconst [off2] ptr) mem)
+ // cond: (off1+off2)%2==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym)
+ // result: (MOVHload [off1+off2] {sym} ptr mem)
+ for {
+ off1 := v.AuxInt
+ sym := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64ADDconst {
+ break
+ }
+ off2 := v_0.AuxInt
+ ptr := v_0.Args[0]
+ mem := v.Args[1]
+ if !((off1+off2)%2 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym) && !isAuto(sym)) {
+ break
+ }
+ v.reset(OpARM64MOVHload)
+ v.AuxInt = off1 + off2
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVHload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
+ // cond: canMergeSym(sym1,sym2) && ((off1+off2)%2==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym1) && !isAuto(sym1))
+ // result: (MOVHload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
+ for {
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64MOVDaddr {
+ break
+ }
+ off2 := v_0.AuxInt
+ sym2 := v_0.Aux
+ ptr := v_0.Args[0]
+ mem := v.Args[1]
+ if !(canMergeSym(sym1, sym2) && ((off1+off2)%2 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym1) && !isAuto(sym1))) {
+ break
+ }
+ v.reset(OpARM64MOVHload)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVHload [off] {sym} ptr (MOVHstorezero [off2] {sym2} ptr2 _))
+ // cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
+ // result: (MOVDconst [0])
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64MOVHstorezero {
+ break
+ }
+ off2 := v_1.AuxInt
+ sym2 := v_1.Aux
+ ptr2 := v_1.Args[0]
+ if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
+ break
+ }
+ v.reset(OpARM64MOVDconst)
+ v.AuxInt = 0
+ return true
+ }
+ return false
+}
+func rewriteValueARM64_OpARM64MOVHreg(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 != OpARM64MOVBload {
+ break
+ }
+ v.reset(OpARM64MOVDreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVHreg x:(MOVBUload _ _))
+ // cond:
+ // result: (MOVDreg x)
+ for {
+ x := v.Args[0]
+ if x.Op != OpARM64MOVBUload {
+ break
+ }
+ v.reset(OpARM64MOVDreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVHreg x:(MOVHload _ _))
+ // cond:
+ // result: (MOVDreg x)
+ for {
+ x := v.Args[0]
+ if x.Op != OpARM64MOVHload {
+ break
+ }
+ v.reset(OpARM64MOVDreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVHreg x:(MOVBreg _))
+ // cond:
+ // result: (MOVDreg x)
+ for {
+ x := v.Args[0]
+ if x.Op != OpARM64MOVBreg {
+ break
+ }
+ v.reset(OpARM64MOVDreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVHreg x:(MOVBUreg _))
+ // cond:
+ // result: (MOVDreg x)
+ for {
+ x := v.Args[0]
+ if x.Op != OpARM64MOVBUreg {
+ break
+ }
+ v.reset(OpARM64MOVDreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVHreg x:(MOVHreg _))
+ // cond:
+ // result: (MOVDreg x)
+ for {
+ x := v.Args[0]
+ if x.Op != OpARM64MOVHreg {
+ break
+ }
+ v.reset(OpARM64MOVDreg)
+ 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 != OpARM64MOVDconst {
+ break
+ }
+ c := v_0.AuxInt
+ v.reset(OpARM64MOVDconst)
+ v.AuxInt = int64(int16(c))
+ return true
+ }
+ return false
+}
+func rewriteValueARM64_OpARM64MOVHstore(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (MOVHstore [off1] {sym} (ADDconst [off2] ptr) val mem)
+ // cond: (off1+off2)%2==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym)
+ // result: (MOVHstore [off1+off2] {sym} ptr val mem)
+ for {
+ off1 := v.AuxInt
+ sym := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64ADDconst {
+ break
+ }
+ off2 := v_0.AuxInt
+ ptr := v_0.Args[0]
+ val := v.Args[1]
+ mem := v.Args[2]
+ if !((off1+off2)%2 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym) && !isAuto(sym)) {
+ break
+ }
+ v.reset(OpARM64MOVHstore)
+ v.AuxInt = off1 + off2
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVHstore [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) val mem)
+ // cond: canMergeSym(sym1,sym2) && ((off1+off2)%2==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym1) && !isAuto(sym1))
+ // result: (MOVHstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
+ for {
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64MOVDaddr {
+ 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) && ((off1+off2)%2 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym1) && !isAuto(sym1))) {
+ break
+ }
+ v.reset(OpARM64MOVHstore)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(ptr)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVHstore [off] {sym} ptr (MOVDconst [0]) mem)
+ // cond:
+ // result: (MOVHstorezero [off] {sym} ptr mem)
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64MOVDconst {
+ break
+ }
+ if v_1.AuxInt != 0 {
+ break
+ }
+ mem := v.Args[2]
+ v.reset(OpARM64MOVHstorezero)
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVHstore [off] {sym} ptr (MOVHreg 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 != OpARM64MOVHreg {
+ break
+ }
+ x := v_1.Args[0]
+ mem := v.Args[2]
+ v.reset(OpARM64MOVHstore)
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(x)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVHstore [off] {sym} ptr (MOVHUreg 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 != OpARM64MOVHUreg {
+ break
+ }
+ x := v_1.Args[0]
+ mem := v.Args[2]
+ v.reset(OpARM64MOVHstore)
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(x)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVHstore [off] {sym} ptr (MOVWreg 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 != OpARM64MOVWreg {
+ break
+ }
+ x := v_1.Args[0]
+ mem := v.Args[2]
+ v.reset(OpARM64MOVHstore)
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(x)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVHstore [off] {sym} ptr (MOVWUreg 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 != OpARM64MOVWUreg {
+ break
+ }
+ x := v_1.Args[0]
+ mem := v.Args[2]
+ v.reset(OpARM64MOVHstore)
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(x)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValueARM64_OpARM64MOVHstorezero(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (MOVHstorezero [off1] {sym} (ADDconst [off2] ptr) mem)
+ // cond: (off1+off2)%2==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym)
+ // result: (MOVHstorezero [off1+off2] {sym} ptr mem)
+ for {
+ off1 := v.AuxInt
+ sym := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64ADDconst {
+ break
+ }
+ off2 := v_0.AuxInt
+ ptr := v_0.Args[0]
+ mem := v.Args[1]
+ if !((off1+off2)%2 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym) && !isAuto(sym)) {
+ break
+ }
+ v.reset(OpARM64MOVHstorezero)
+ v.AuxInt = off1 + off2
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVHstorezero [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
+ // cond: canMergeSym(sym1,sym2) && ((off1+off2)%2==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym1) && !isAuto(sym1))
+ // result: (MOVHstorezero [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
+ for {
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64MOVDaddr {
+ break
+ }
+ off2 := v_0.AuxInt
+ sym2 := v_0.Aux
+ ptr := v_0.Args[0]
+ mem := v.Args[1]
+ if !(canMergeSym(sym1, sym2) && ((off1+off2)%2 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym1) && !isAuto(sym1))) {
+ break
+ }
+ v.reset(OpARM64MOVHstorezero)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValueARM64_OpARM64MOVWUload(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (MOVWUload [off1] {sym} (ADDconst [off2] ptr) mem)
+ // cond: (off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym)
+ // result: (MOVWUload [off1+off2] {sym} ptr mem)
+ for {
+ off1 := v.AuxInt
+ sym := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64ADDconst {
+ break
+ }
+ off2 := v_0.AuxInt
+ ptr := v_0.Args[0]
+ mem := v.Args[1]
+ if !((off1+off2)%4 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym) && !isAuto(sym)) {
+ break
+ }
+ v.reset(OpARM64MOVWUload)
+ v.AuxInt = off1 + off2
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVWUload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
+ // cond: canMergeSym(sym1,sym2) && ((off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym1) && !isAuto(sym1))
+ // result: (MOVWUload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
+ for {
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64MOVDaddr {
+ break
+ }
+ off2 := v_0.AuxInt
+ sym2 := v_0.Aux
+ ptr := v_0.Args[0]
+ mem := v.Args[1]
+ if !(canMergeSym(sym1, sym2) && ((off1+off2)%4 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym1) && !isAuto(sym1))) {
+ break
+ }
+ v.reset(OpARM64MOVWUload)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVWUload [off] {sym} ptr (MOVWstorezero [off2] {sym2} ptr2 _))
+ // cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
+ // result: (MOVDconst [0])
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64MOVWstorezero {
+ break
+ }
+ off2 := v_1.AuxInt
+ sym2 := v_1.Aux
+ ptr2 := v_1.Args[0]
+ if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
+ break
+ }
+ v.reset(OpARM64MOVDconst)
+ v.AuxInt = 0
+ return true
+ }
+ return false
+}
+func rewriteValueARM64_OpARM64MOVWUreg(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (MOVWUreg x:(MOVBUload _ _))
+ // cond:
+ // result: (MOVDreg x)
+ for {
+ x := v.Args[0]
+ if x.Op != OpARM64MOVBUload {
+ break
+ }
+ v.reset(OpARM64MOVDreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVWUreg x:(MOVHUload _ _))
+ // cond:
+ // result: (MOVDreg x)
+ for {
+ x := v.Args[0]
+ if x.Op != OpARM64MOVHUload {
+ break
+ }
+ v.reset(OpARM64MOVDreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVWUreg x:(MOVWUload _ _))
+ // cond:
+ // result: (MOVDreg x)
+ for {
+ x := v.Args[0]
+ if x.Op != OpARM64MOVWUload {
+ break
+ }
+ v.reset(OpARM64MOVDreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVWUreg x:(MOVBUreg _))
+ // cond:
+ // result: (MOVDreg x)
+ for {
+ x := v.Args[0]
+ if x.Op != OpARM64MOVBUreg {
+ break
+ }
+ v.reset(OpARM64MOVDreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVWUreg x:(MOVHUreg _))
+ // cond:
+ // result: (MOVDreg x)
+ for {
+ x := v.Args[0]
+ if x.Op != OpARM64MOVHUreg {
+ break
+ }
+ v.reset(OpARM64MOVDreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVWUreg x:(MOVWUreg _))
+ // cond:
+ // result: (MOVDreg x)
+ for {
+ x := v.Args[0]
+ if x.Op != OpARM64MOVWUreg {
+ break
+ }
+ v.reset(OpARM64MOVDreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVWUreg (MOVDconst [c]))
+ // cond:
+ // result: (MOVDconst [int64(uint32(c))])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64MOVDconst {
+ break
+ }
+ c := v_0.AuxInt
+ v.reset(OpARM64MOVDconst)
+ v.AuxInt = int64(uint32(c))
+ return true
+ }
+ return false
+}
+func rewriteValueARM64_OpARM64MOVWload(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (MOVWload [off1] {sym} (ADDconst [off2] ptr) mem)
+ // cond: (off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym)
+ // result: (MOVWload [off1+off2] {sym} ptr mem)
+ for {
+ off1 := v.AuxInt
+ sym := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64ADDconst {
+ break
+ }
+ off2 := v_0.AuxInt
+ ptr := v_0.Args[0]
+ mem := v.Args[1]
+ if !((off1+off2)%4 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym) && !isAuto(sym)) {
+ break
+ }
+ v.reset(OpARM64MOVWload)
+ v.AuxInt = off1 + off2
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVWload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
+ // cond: canMergeSym(sym1,sym2) && ((off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym1) && !isAuto(sym1))
+ // result: (MOVWload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
+ for {
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64MOVDaddr {
+ break
+ }
+ off2 := v_0.AuxInt
+ sym2 := v_0.Aux
+ ptr := v_0.Args[0]
+ mem := v.Args[1]
+ if !(canMergeSym(sym1, sym2) && ((off1+off2)%4 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym1) && !isAuto(sym1))) {
+ break
+ }
+ v.reset(OpARM64MOVWload)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVWload [off] {sym} ptr (MOVWstorezero [off2] {sym2} ptr2 _))
+ // cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
+ // result: (MOVDconst [0])
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64MOVWstorezero {
+ break
+ }
+ off2 := v_1.AuxInt
+ sym2 := v_1.Aux
+ ptr2 := v_1.Args[0]
+ if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
+ break
+ }
+ v.reset(OpARM64MOVDconst)
+ v.AuxInt = 0
+ return true
+ }
+ return false
+}
+func rewriteValueARM64_OpARM64MOVWreg(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 != OpARM64MOVBload {
+ break
+ }
+ v.reset(OpARM64MOVDreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVWreg x:(MOVBUload _ _))
+ // cond:
+ // result: (MOVDreg x)
+ for {
+ x := v.Args[0]
+ if x.Op != OpARM64MOVBUload {
+ break
+ }
+ v.reset(OpARM64MOVDreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVWreg x:(MOVHload _ _))
+ // cond:
+ // result: (MOVDreg x)
+ for {
+ x := v.Args[0]
+ if x.Op != OpARM64MOVHload {
+ break
+ }
+ v.reset(OpARM64MOVDreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVWreg x:(MOVHUload _ _))
+ // cond:
+ // result: (MOVDreg x)
+ for {
+ x := v.Args[0]
+ if x.Op != OpARM64MOVHUload {
+ break
+ }
+ v.reset(OpARM64MOVDreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVWreg x:(MOVWload _ _))
+ // cond:
+ // result: (MOVDreg x)
+ for {
+ x := v.Args[0]
+ if x.Op != OpARM64MOVWload {
+ break
+ }
+ v.reset(OpARM64MOVDreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVWreg x:(MOVBreg _))
+ // cond:
+ // result: (MOVDreg x)
+ for {
+ x := v.Args[0]
+ if x.Op != OpARM64MOVBreg {
+ break
+ }
+ v.reset(OpARM64MOVDreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVWreg x:(MOVBUreg _))
+ // cond:
+ // result: (MOVDreg x)
+ for {
+ x := v.Args[0]
+ if x.Op != OpARM64MOVBUreg {
+ break
+ }
+ v.reset(OpARM64MOVDreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVWreg x:(MOVHreg _))
+ // cond:
+ // result: (MOVDreg x)
+ for {
+ x := v.Args[0]
+ if x.Op != OpARM64MOVHreg {
+ break
+ }
+ v.reset(OpARM64MOVDreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVWreg x:(MOVHreg _))
+ // cond:
+ // result: (MOVDreg x)
+ for {
+ x := v.Args[0]
+ if x.Op != OpARM64MOVHreg {
+ break
+ }
+ v.reset(OpARM64MOVDreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVWreg x:(MOVWreg _))
+ // cond:
+ // result: (MOVDreg x)
+ for {
+ x := v.Args[0]
+ if x.Op != OpARM64MOVWreg {
+ break
+ }
+ v.reset(OpARM64MOVDreg)
+ 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 != OpARM64MOVDconst {
+ break
+ }
+ c := v_0.AuxInt
+ v.reset(OpARM64MOVDconst)
+ v.AuxInt = int64(int32(c))
+ return true
+ }
+ return false
+}
+func rewriteValueARM64_OpARM64MOVWstore(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (MOVWstore [off1] {sym} (ADDconst [off2] ptr) val mem)
+ // cond: (off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym)
+ // result: (MOVWstore [off1+off2] {sym} ptr val mem)
+ for {
+ off1 := v.AuxInt
+ sym := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64ADDconst {
+ break
+ }
+ off2 := v_0.AuxInt
+ ptr := v_0.Args[0]
+ val := v.Args[1]
+ mem := v.Args[2]
+ if !((off1+off2)%4 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym) && !isAuto(sym)) {
+ break
+ }
+ v.reset(OpARM64MOVWstore)
+ v.AuxInt = off1 + off2
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVWstore [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) val mem)
+ // cond: canMergeSym(sym1,sym2) && ((off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym1) && !isAuto(sym1))
+ // result: (MOVWstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
+ for {
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64MOVDaddr {
+ 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) && ((off1+off2)%4 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym1) && !isAuto(sym1))) {
+ break
+ }
+ v.reset(OpARM64MOVWstore)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(ptr)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVWstore [off] {sym} ptr (MOVDconst [0]) mem)
+ // cond:
+ // result: (MOVWstorezero [off] {sym} ptr mem)
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64MOVDconst {
+ break
+ }
+ if v_1.AuxInt != 0 {
+ break
+ }
+ mem := v.Args[2]
+ v.reset(OpARM64MOVWstorezero)
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // 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 != OpARM64MOVWreg {
+ break
+ }
+ x := v_1.Args[0]
+ mem := v.Args[2]
+ v.reset(OpARM64MOVWstore)
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(x)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVWstore [off] {sym} ptr (MOVWUreg 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 != OpARM64MOVWUreg {
+ break
+ }
+ x := v_1.Args[0]
+ mem := v.Args[2]
+ v.reset(OpARM64MOVWstore)
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(x)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValueARM64_OpARM64MOVWstorezero(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (MOVWstorezero [off1] {sym} (ADDconst [off2] ptr) mem)
+ // cond: (off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym) && !isAuto(sym)
+ // result: (MOVWstorezero [off1+off2] {sym} ptr mem)
+ for {
+ off1 := v.AuxInt
+ sym := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64ADDconst {
+ break
+ }
+ off2 := v_0.AuxInt
+ ptr := v_0.Args[0]
+ mem := v.Args[1]
+ if !((off1+off2)%4 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym) && !isAuto(sym)) {
+ break
+ }
+ v.reset(OpARM64MOVWstorezero)
+ v.AuxInt = off1 + off2
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVWstorezero [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
+ // cond: canMergeSym(sym1,sym2) && ((off1+off2)%4==0 || off1+off2<256 && off1+off2>-256 && !isArg(sym1) && !isAuto(sym1))
+ // result: (MOVWstorezero [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
+ for {
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64MOVDaddr {
+ break
+ }
+ off2 := v_0.AuxInt
+ sym2 := v_0.Aux
+ ptr := v_0.Args[0]
+ mem := v.Args[1]
+ if !(canMergeSym(sym1, sym2) && ((off1+off2)%4 == 0 || off1+off2 < 256 && off1+off2 > -256 && !isArg(sym1) && !isAuto(sym1))) {
+ break
+ }
+ v.reset(OpARM64MOVWstorezero)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValueARM64_OpARM64MUL(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (MUL x (MOVDconst [-1]))
+ // cond:
+ // result: (NEG x)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64MOVDconst {
+ break
+ }
+ if v_1.AuxInt != -1 {
+ break
+ }
+ v.reset(OpARM64NEG)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MUL _ (MOVDconst [0]))
+ // cond:
+ // result: (MOVDconst [0])
+ for {
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64MOVDconst {
+ break
+ }
+ if v_1.AuxInt != 0 {
+ break
+ }
+ v.reset(OpARM64MOVDconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (MUL x (MOVDconst [1]))
+ // cond:
+ // result: x
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64MOVDconst {
+ break
+ }
+ if v_1.AuxInt != 1 {
+ break
+ }
+ 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 {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64MOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ 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 {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64MOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ if !(isPowerOfTwo(c-1) && c >= 3) {
+ break
+ }
+ v.reset(OpARM64ADDshiftLL)
+ v.AuxInt = log2(c - 1)
+ v.AddArg(x)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MUL x (MOVDconst [c]))
+ // cond: isPowerOfTwo(c+1) && 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 {
+ break
+ }
+ c := v_1.AuxInt
+ if !(isPowerOfTwo(c+1) && 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: (MUL x (MOVDconst [c]))
+ // cond: c%3 == 0 && isPowerOfTwo(c/3)
+ // 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 {
+ break
+ }
+ c := v_1.AuxInt
+ if !(c%3 == 0 && isPowerOfTwo(c/3)) {
+ 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: (MUL x (MOVDconst [c]))
+ // cond: c%5 == 0 && isPowerOfTwo(c/5)
+ // result: (SLLconst [log2(c/5)] (ADDshiftLL <x.Type> x x [2]))
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64MOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ if !(c%5 == 0 && isPowerOfTwo(c/5)) {
+ 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: (MUL x (MOVDconst [c]))
+ // cond: c%7 == 0 && isPowerOfTwo(c/7)
+ // result: (SLLconst [log2(c/7)] (ADDshiftLL <x.Type> (NEG <x.Type> x) x [3]))
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64MOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ if !(c%7 == 0 && isPowerOfTwo(c/7)) {
+ 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: (MUL x (MOVDconst [c]))
+ // cond: c%9 == 0 && isPowerOfTwo(c/9)
+ // result: (SLLconst [log2(c/9)] (ADDshiftLL <x.Type> x x [3]))
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64MOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ if !(c%9 == 0 && isPowerOfTwo(c/9)) {
+ 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 [-1]) x)
+ // cond:
+ // result: (NEG x)
+ for {
+ 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_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 (MOVDconst [1]) x)
+ // cond:
+ // result: x
+ for {
+ 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 (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: (MUL (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: (MUL (MOVDconst [c]) x)
+ // cond: isPowerOfTwo(c-1) && 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) && c >= 3) {
+ break
+ }
+ v.reset(OpARM64ADDshiftLL)
+ v.AuxInt = log2(c - 1)
+ v.AddArg(x)
+ 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_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.Line, OpARM64NEG, x.Type)
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v.AddArg(x)
+ 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_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.Line, OpARM64ADDshiftLL, x.Type)
+ v0.AuxInt = 1
+ 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_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.Line, OpARM64ADDshiftLL, x.Type)
+ v0.AuxInt = 2
+ v0.AddArg(x)
+ 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_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.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: (MUL (MOVDconst [c]) x)
+ // cond: c%9 == 0 && isPowerOfTwo(c/9)
+ // result: (SLLconst [log2(c/9)] (ADDshiftLL <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%9 == 0 && isPowerOfTwo(c/9)) {
+ 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
+ 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)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64MOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ if !(int32(c) == -1) {
+ break
+ }
+ v.reset(OpARM64NEG)
+ 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
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64MOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ if !(int32(c) == 1) {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ // match: (MULW x (MOVDconst [c]))
+ // cond: isPowerOfTwo(c)
+ // result: (SLLconst [log2(c)] x)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64MOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ if !(isPowerOfTwo(c)) {
+ break
+ }
+ v.reset(OpARM64SLLconst)
+ v.AuxInt = log2(c)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MULW x (MOVDconst [c]))
+ // 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 {
+ break
+ }
+ c := v_1.AuxInt
+ 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 x (MOVDconst [c]))
+ // 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 {
+ break
+ }
+ c := v_1.AuxInt
+ 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 x (MOVDconst [c]))
+ // 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 {
+ break
+ }
+ c := v_1.AuxInt
+ 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 x (MOVDconst [c]))
+ // cond: c%5 == 0 && isPowerOfTwo(c/5) && is32Bit(c)
+ // result: (SLLconst [log2(c/5)] (ADDshiftLL <x.Type> x x [2]))
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64MOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ 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 x (MOVDconst [c]))
+ // cond: c%7 == 0 && isPowerOfTwo(c/7) && is32Bit(c)
+ // result: (SLLconst [log2(c/7)] (ADDshiftLL <x.Type> (NEG <x.Type> x) x [3]))
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64MOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ 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 x (MOVDconst [c]))
+ // cond: c%9 == 0 && isPowerOfTwo(c/9) && is32Bit(c)
+ // result: (SLLconst [log2(c/9)] (ADDshiftLL <x.Type> x x [3]))
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64MOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ if !(c%9 == 0 && isPowerOfTwo(c/9) && is32Bit(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: (MULW (MOVDconst [c]) x)
+ // cond: int32(c)==-1
+ // result: (NEG 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(OpARM64NEG)
+ v.AddArg(x)
+ 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]))
+ for {
+ 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)) {
+ 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: (MULW (MOVDconst [c]) (MOVDconst [d]))
+ // cond:
+ // result: (MOVDconst [int64(int32(c)*int32(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 = int64(int32(c) * int32(d))
+ return true
+ }
+ return false
+}
+func rewriteValueARM64_OpARM64MVN(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (MVN (MOVDconst [c]))
+ // cond:
+ // result: (MOVDconst [^c])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64MOVDconst {
+ break
+ }
+ c := v_0.AuxInt
+ v.reset(OpARM64MOVDconst)
+ v.AuxInt = ^c
+ return true
+ }
+ return false
+}
+func rewriteValueARM64_OpARM64NEG(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 != OpARM64MOVDconst {
+ break
+ }
+ c := v_0.AuxInt
+ v.reset(OpARM64MOVDconst)
+ v.AuxInt = -c
+ return true
+ }
+ return false
+}
+func rewriteValueARM64_OpARM64NotEqual(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (NotEqual (FlagEQ))
+ // cond:
+ // result: (MOVDconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64FlagEQ {
+ break
+ }
+ v.reset(OpARM64MOVDconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (NotEqual (FlagLT_ULT))
+ // cond:
+ // result: (MOVDconst [1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64FlagLT_ULT {
+ break
+ }
+ v.reset(OpARM64MOVDconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (NotEqual (FlagLT_UGT))
+ // cond:
+ // result: (MOVDconst [1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64FlagLT_UGT {
+ break
+ }
+ v.reset(OpARM64MOVDconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (NotEqual (FlagGT_ULT))
+ // cond:
+ // result: (MOVDconst [1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64FlagGT_ULT {
+ break
+ }
+ v.reset(OpARM64MOVDconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (NotEqual (FlagGT_UGT))
+ // cond:
+ // result: (MOVDconst [1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64FlagGT_UGT {
+ break
+ }
+ v.reset(OpARM64MOVDconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (NotEqual (InvertFlags x))
+ // cond:
+ // result: (NotEqual x)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64InvertFlags {
+ break
+ }
+ x := v_0.Args[0]
+ v.reset(OpARM64NotEqual)
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValueARM64_OpARM64OR(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (OR (MOVDconst [c]) x)
+ // cond:
+ // result: (ORconst [c] x)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64MOVDconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ v.reset(OpARM64ORconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (OR x (MOVDconst [c]))
+ // cond:
+ // result: (ORconst [c] x)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64MOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpARM64ORconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (OR 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: (OR x s:(SLLconst [c] y))
+ // cond: s.Uses == 1 && clobber(s)
+ // result: (ORshiftLL x y [c])
+ for {
+ 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)) {
+ break
+ }
+ 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)
+ // result: (ORshiftLL x y [c])
+ for {
+ s := v.Args[0]
+ if s.Op != OpARM64SLLconst {
+ break
+ }
+ c := s.AuxInt
+ y := s.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))
+ // cond:
+ // result: (ORshiftLL x y [c])
+ for {
+ x := v.Args[0]
+ 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 (SLLconst [c] y) x)
+ // cond:
+ // result: (ORshiftLL x y [c])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64SLLconst {
+ break
+ }
+ c := v_0.AuxInt
+ y := v_0.Args[0]
+ x := v.Args[1]
+ v.reset(OpARM64ORshiftLL)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (OR x (SRLconst [c] y))
+ // cond:
+ // result: (ORshiftRL x y [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64SRLconst {
+ break
+ }
+ c := v_1.AuxInt
+ y := v_1.Args[0]
+ v.reset(OpARM64ORshiftRL)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (OR (SRLconst [c] y) x)
+ // cond:
+ // result: (ORshiftRL x y [c])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64SRLconst {
+ break
+ }
+ c := v_0.AuxInt
+ y := v_0.Args[0]
+ x := v.Args[1]
+ v.reset(OpARM64ORshiftRL)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (OR x (SRAconst [c] y))
+ // cond:
+ // result: (ORshiftRA x y [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64SRAconst {
+ 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 {
+ 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)
+ 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)
+ 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)) {
+ break
+ }
+ b = mergePoint(b, x0, x1, x2, x3)
+ v0 := b.NewValue0(v.Line, OpARM64MOVWUload, 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)
+ 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))
+ 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
+ }
+ o2 := o1.Args[0]
+ if o2.Op != OpARM64ORshiftLL {
+ break
+ }
+ if o2.AuxInt != 24 {
+ break
+ }
+ o3 := o2.Args[0]
+ if o3.Op != OpARM64ORshiftLL {
+ break
+ }
+ if o3.AuxInt != 32 {
+ break
+ }
+ o4 := o3.Args[0]
+ if o4.Op != OpARM64ORshiftLL {
+ break
+ }
+ if o4.AuxInt != 40 {
+ break
+ }
+ o5 := o4.Args[0]
+ if o5.Op != OpARM64ORshiftLL {
+ break
+ }
+ if o5.AuxInt != 48 {
+ break
+ }
+ 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
+ }
+ i := x0.AuxInt
+ s := x0.Aux
+ 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
+ }
+ if x1.AuxInt != i-1 {
+ break
+ }
+ if x1.Aux != s {
+ break
+ }
+ 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
+ }
+ if x2.AuxInt != i-2 {
+ break
+ }
+ if x2.Aux != s {
+ break
+ }
+ 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
+ }
+ if x3.AuxInt != i-3 {
+ break
+ }
+ if x3.Aux != s {
+ break
+ }
+ 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
+ }
+ if x4.AuxInt != i-4 {
+ break
+ }
+ if x4.Aux != s {
+ break
+ }
+ 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
+ }
+ if x5.AuxInt != i-5 {
+ break
+ }
+ if x5.Aux != s {
+ break
+ }
+ 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
+ }
+ if x6.AuxInt != i-6 {
+ break
+ }
+ if x6.Aux != s {
+ break
+ }
+ 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 [...]
+ break
+ }
+ b = mergePoint(b, x0, x1, x2, x3, x4, x5, x6, x7)
+ v0 := b.NewValue0(v.Line, OpARM64REV, t)
+ v.reset(OpCopy)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpARM64MOVDload, t)
+ v1.Aux = s
+ v2 := b.NewValue0(v.Line, OpOffPtr, p.Type)
+ v2.AuxInt = i - 7
+ 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))
+ 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)) {
+ 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]
+ if o0.Op != OpARM64ORshiftLL {
+ break
+ }
+ if o0.AuxInt != 8 {
+ break
+ }
+ o1 := o0.Args[0]
+ if o1.Op != OpARM64ORshiftLL {
+ break
+ }
+ if o1.AuxInt != 16 {
+ break
+ }
+ o2 := o1.Args[0]
+ if o2.Op != OpARM64ORshiftLL {
+ break
+ }
+ if o2.AuxInt != 24 {
+ break
+ }
+ o3 := o2.Args[0]
+ if o3.Op != OpARM64ORshiftLL {
+ break
+ }
+ if o3.AuxInt != 32 {
+ break
+ }
+ o4 := o3.Args[0]
+ if o4.Op != OpARM64ORshiftLL {
+ break
+ }
+ if o4.AuxInt != 40 {
+ break
+ }
+ o5 := o4.Args[0]
+ if o5.Op != OpARM64ORshiftLL {
+ break
+ }
+ if o5.AuxInt != 48 {
+ break
+ }
+ 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
+ }
+ i := x0.AuxInt
+ s := x0.Aux
+ 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
+ }
+ if x1.AuxInt != i+1 {
+ break
+ }
+ if x1.Aux != s {
+ break
+ }
+ 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
+ }
+ if x2.AuxInt != i+2 {
+ break
+ }
+ if x2.Aux != s {
+ break
+ }
+ 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
+ }
+ if x3.AuxInt != i+3 {
+ break
+ }
+ if x3.Aux != s {
+ break
+ }
+ 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
+ }
+ if x4.AuxInt != i+4 {
+ break
+ }
+ if x4.Aux != s {
+ break
+ }
+ 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
+ }
+ if x5.AuxInt != i+5 {
+ break
+ }
+ if x5.Aux != s {
+ break
+ }
+ 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
+ }
+ if x6.AuxInt != i+6 {
+ break
+ }
+ if x6.Aux != s {
+ break
+ }
+ 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 [...]
+ break
+ }
+ b = mergePoint(b, x0, x1, x2, x3, x4, x5, x6, x7)
+ v0 := b.NewValue0(v.Line, OpARM64REV, t)
+ v.reset(OpCopy)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpARM64MOVDload, 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
+ }
+ return false
+}
+func rewriteValueARM64_OpARM64ORconst(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ORconst [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: (ORconst [-1] _)
+ // cond:
+ // result: (MOVDconst [-1])
+ for {
+ if v.AuxInt != -1 {
+ break
+ }
+ v.reset(OpARM64MOVDconst)
+ v.AuxInt = -1
+ return true
+ }
+ // match: (ORconst [c] (MOVDconst [d]))
+ // cond:
+ // result: (MOVDconst [c|d])
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64MOVDconst {
+ break
+ }
+ d := v_0.AuxInt
+ v.reset(OpARM64MOVDconst)
+ v.AuxInt = c | d
+ return true
+ }
+ // match: (ORconst [c] (ORconst [d] x))
+ // cond:
+ // result: (ORconst [c|d] x)
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64ORconst {
+ break
+ }
+ d := v_0.AuxInt
+ x := v_0.Args[0]
+ v.reset(OpARM64ORconst)
+ v.AuxInt = c | d
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValueARM64_OpARM64ORshiftLL(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ORshiftLL (MOVDconst [c]) x [d])
+ // cond:
+ // result: (ORconst [c] (SLLconst <x.Type> x [d]))
+ for {
+ d := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64MOVDconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ v.reset(OpARM64ORconst)
+ v.AuxInt = c
+ v0 := b.NewValue0(v.Line, OpARM64SLLconst, x.Type)
+ v0.AuxInt = d
+ v0.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (ORshiftLL x (MOVDconst [c]) [d])
+ // cond:
+ // result: (ORconst x [int64(uint64(c)<<uint64(d))])
+ for {
+ d := v.AuxInt
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64MOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpARM64ORconst)
+ v.AuxInt = int64(uint64(c) << uint64(d))
+ v.AddArg(x)
+ return true
+ }
+ // match: (ORshiftLL x y:(SLLconst x [c]) [d])
+ // cond: c==d
+ // result: y
+ for {
+ d := v.AuxInt
+ x := v.Args[0]
+ y := v.Args[1]
+ if y.Op != OpARM64SLLconst {
+ break
+ }
+ c := y.AuxInt
+ if x != y.Args[0] {
+ break
+ }
+ if !(c == d) {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = y.Type
+ 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)
+ for {
+ t := v.Type
+ if v.AuxInt != 8 {
+ break
+ }
+ y0 := v.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 := v.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
+ }
+ 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)) {
+ break
+ }
+ b = mergePoint(b, x0, x1)
+ v0 := b.NewValue0(v.Line, OpARM64MOVHUload, t)
+ v.reset(OpCopy)
+ v.AddArg(v0)
+ v0.Aux = s
+ v1 := b.NewValue0(v.Line, OpOffPtr, p.Type)
+ v1.AuxInt = i
+ 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)
+ for {
+ t := v.Type
+ if v.AuxInt != 24 {
+ break
+ }
+ o0 := v.Args[0]
+ if o0.Op != OpARM64ORshiftLL {
+ break
+ }
+ if o0.AuxInt != 16 {
+ break
+ }
+ x0 := o0.Args[0]
+ if x0.Op != OpARM64MOVHUload {
+ break
+ }
+ i := x0.AuxInt
+ s := x0.Aux
+ p := x0.Args[0]
+ mem := x0.Args[1]
+ y1 := o0.Args[1]
+ if y1.Op != OpARM64MOVDnop {
+ break
+ }
+ x1 := y1.Args[0]
+ if x1.Op != OpARM64MOVBUload {
+ break
+ }
+ if x1.AuxInt != i+2 {
+ break
+ }
+ if x1.Aux != s {
+ break
+ }
+ if p != x1.Args[0] {
+ break
+ }
+ if mem != x1.Args[1] {
+ break
+ }
+ y2 := v.Args[1]
+ if y2.Op != OpARM64MOVDnop {
+ break
+ }
+ x2 := y2.Args[0]
+ if x2.Op != OpARM64MOVBUload {
+ break
+ }
+ if x2.AuxInt != i+3 {
+ break
+ }
+ if x2.Aux != s {
+ break
+ }
+ 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)) {
+ break
+ }
+ b = mergePoint(b, x0, x1, x2)
+ v0 := b.NewValue0(v.Line, OpARM64MOVWUload, t)
+ v.reset(OpCopy)
+ v.AddArg(v0)
+ v0.Aux = s
+ v1 := b.NewValue0(v.Line, OpOffPtr, p.Type)
+ v1.AuxInt = i
+ 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)
+ for {
+ t := v.Type
+ if v.AuxInt != 56 {
+ break
+ }
+ o0 := v.Args[0]
+ if o0.Op != OpARM64ORshiftLL {
+ break
+ }
+ if o0.AuxInt != 48 {
+ break
+ }
+ o1 := o0.Args[0]
+ if o1.Op != OpARM64ORshiftLL {
+ break
+ }
+ if o1.AuxInt != 40 {
+ break
+ }
+ o2 := o1.Args[0]
+ if o2.Op != OpARM64ORshiftLL {
+ break
+ }
+ if o2.AuxInt != 32 {
+ break
+ }
+ x0 := o2.Args[0]
+ if x0.Op != OpARM64MOVWUload {
+ break
+ }
+ i := x0.AuxInt
+ s := x0.Aux
+ p := x0.Args[0]
+ mem := x0.Args[1]
+ y1 := o2.Args[1]
+ if y1.Op != OpARM64MOVDnop {
+ break
+ }
+ x1 := y1.Args[0]
+ if x1.Op != OpARM64MOVBUload {
+ break
+ }
+ if x1.AuxInt != i+4 {
+ break
+ }
+ if x1.Aux != s {
+ break
+ }
+ if p != x1.Args[0] {
+ break
+ }
+ if mem != x1.Args[1] {
+ break
+ }
+ y2 := o1.Args[1]
+ if y2.Op != OpARM64MOVDnop {
+ break
+ }
+ x2 := y2.Args[0]
+ if x2.Op != OpARM64MOVBUload {
+ break
+ }
+ if x2.AuxInt != i+5 {
+ break
+ }
+ if x2.Aux != s {
+ break
+ }
+ if p != x2.Args[0] {
+ break
+ }
+ if mem != x2.Args[1] {
+ break
+ }
+ y3 := o0.Args[1]
+ if y3.Op != OpARM64MOVDnop {
+ break
+ }
+ x3 := y3.Args[0]
+ if x3.Op != OpARM64MOVBUload {
+ break
+ }
+ if x3.AuxInt != i+6 {
+ break
+ }
+ if x3.Aux != s {
+ break
+ }
+ if p != x3.Args[0] {
+ break
+ }
+ if mem != x3.Args[1] {
+ break
+ }
+ y4 := v.Args[1]
+ if y4.Op != OpARM64MOVDnop {
+ break
+ }
+ x4 := y4.Args[0]
+ if x4.Op != OpARM64MOVBUload {
+ break
+ }
+ if x4.AuxInt != i+7 {
+ break
+ }
+ if x4.Aux != s {
+ break
+ }
+ 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)) {
+ break
+ }
+ b = mergePoint(b, x0, x1, x2, x3, x4)
+ v0 := b.NewValue0(v.Line, OpARM64MOVDload, t)
+ v.reset(OpCopy)
+ v.AddArg(v0)
+ v0.Aux = s
+ v1 := b.NewValue0(v.Line, OpOffPtr, p.Type)
+ v1.AuxInt = i
+ 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))
+ for {
+ t := v.Type
+ if v.AuxInt != 8 {
+ break
+ }
+ y0 := v.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 := v.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
+ }
+ 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)) {
+ break
+ }
+ b = mergePoint(b, x0, x1)
+ v0 := b.NewValue0(v.Line, OpARM64REV16W, t)
+ v.reset(OpCopy)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpARM64MOVHUload, t)
+ v1.AuxInt = i - 1
+ 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))
+ for {
+ t := v.Type
+ if v.AuxInt != 24 {
+ break
+ }
+ o0 := v.Args[0]
+ if o0.Op != OpARM64ORshiftLL {
+ break
+ }
+ if o0.AuxInt != 16 {
+ break
+ }
+ y0 := o0.Args[0]
+ if y0.Op != OpARM64REV16W {
+ break
+ }
+ x0 := y0.Args[0]
+ if x0.Op != OpARM64MOVHUload {
+ break
+ }
+ i := x0.AuxInt
+ s := x0.Aux
+ p := x0.Args[0]
+ mem := x0.Args[1]
+ y1 := o0.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 := v.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
+ }
+ 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)) {
+ break
+ }
+ b = mergePoint(b, x0, x1, x2)
+ 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 - 2
+ 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))
+ for {
+ t := v.Type
+ if v.AuxInt != 56 {
+ break
+ }
+ o0 := v.Args[0]
+ if o0.Op != OpARM64ORshiftLL {
+ break
+ }
+ if o0.AuxInt != 48 {
+ break
+ }
+ o1 := o0.Args[0]
+ if o1.Op != OpARM64ORshiftLL {
+ break
+ }
+ if o1.AuxInt != 40 {
+ break
+ }
+ o2 := o1.Args[0]
+ if o2.Op != OpARM64ORshiftLL {
+ break
+ }
+ if o2.AuxInt != 32 {
+ break
+ }
+ y0 := o2.Args[0]
+ if y0.Op != OpARM64REVW {
+ break
+ }
+ x0 := y0.Args[0]
+ if x0.Op != OpARM64MOVWUload {
+ break
+ }
+ i := x0.AuxInt
+ s := x0.Aux
+ p := x0.Args[0]
+ mem := x0.Args[1]
+ y1 := o2.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 := o1.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 := o0.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
+ }
+ y4 := v.Args[1]
+ if y4.Op != OpARM64MOVDnop {
+ break
+ }
+ x4 := y4.Args[0]
+ if x4.Op != OpARM64MOVBUload {
+ break
+ }
+ if x4.AuxInt != i-4 {
+ break
+ }
+ if x4.Aux != s {
+ break
+ }
+ 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)) {
+ break
+ }
+ b = mergePoint(b, x0, x1, x2, x3, x4)
+ v0 := b.NewValue0(v.Line, OpARM64REV, t)
+ v.reset(OpCopy)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpARM64MOVDload, t)
+ v1.Aux = s
+ v2 := b.NewValue0(v.Line, OpOffPtr, p.Type)
+ v2.AuxInt = i - 4
+ v2.AddArg(p)
+ v1.AddArg(v2)
+ v1.AddArg(mem)
+ v0.AddArg(v1)
+ return true
+ }
+ return false
+}
+func rewriteValueARM64_OpARM64ORshiftRA(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ORshiftRA (MOVDconst [c]) x [d])
+ // cond:
+ // result: (ORconst [c] (SRAconst <x.Type> x [d]))
+ for {
+ d := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64MOVDconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ v.reset(OpARM64ORconst)
+ v.AuxInt = c
+ v0 := b.NewValue0(v.Line, OpARM64SRAconst, x.Type)
+ v0.AuxInt = d
+ v0.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (ORshiftRA x (MOVDconst [c]) [d])
+ // cond:
+ // result: (ORconst x [int64(int64(c)>>uint64(d))])
+ for {
+ d := v.AuxInt
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64MOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpARM64ORconst)
+ v.AuxInt = int64(int64(c) >> uint64(d))
+ v.AddArg(x)
+ return true
+ }
+ // match: (ORshiftRA x y:(SRAconst x [c]) [d])
+ // cond: c==d
+ // result: y
+ for {
+ d := v.AuxInt
+ x := v.Args[0]
+ y := v.Args[1]
+ if y.Op != OpARM64SRAconst {
+ break
+ }
+ c := y.AuxInt
+ if x != y.Args[0] {
+ break
+ }
+ if !(c == d) {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = y.Type
+ v.AddArg(y)
+ return true
+ }
+ return false
+}
+func rewriteValueARM64_OpARM64ORshiftRL(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ORshiftRL (MOVDconst [c]) x [d])
+ // cond:
+ // result: (ORconst [c] (SRLconst <x.Type> x [d]))
+ for {
+ d := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64MOVDconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ v.reset(OpARM64ORconst)
+ v.AuxInt = c
+ v0 := b.NewValue0(v.Line, OpARM64SRLconst, x.Type)
+ v0.AuxInt = d
+ v0.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (ORshiftRL x (MOVDconst [c]) [d])
+ // cond:
+ // result: (ORconst x [int64(uint64(c)>>uint64(d))])
+ for {
+ d := v.AuxInt
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64MOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpARM64ORconst)
+ v.AuxInt = int64(uint64(c) >> uint64(d))
+ v.AddArg(x)
+ return true
+ }
+ // match: (ORshiftRL x y:(SRLconst x [c]) [d])
+ // cond: c==d
+ // result: y
+ for {
+ d := v.AuxInt
+ x := v.Args[0]
+ y := v.Args[1]
+ if y.Op != OpARM64SRLconst {
+ break
+ }
+ c := y.AuxInt
+ if x != y.Args[0] {
+ break
+ }
+ if !(c == d) {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = y.Type
+ v.AddArg(y)
+ return true
+ }
+ return false
+}
+func rewriteValueARM64_OpARM64SLL(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SLL x (MOVDconst [c]))
+ // cond:
+ // result: (SLLconst x [c&63])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64MOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpARM64SLLconst)
+ v.AuxInt = c & 63
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValueARM64_OpARM64SLLconst(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SLLconst [c] (MOVDconst [d]))
+ // cond:
+ // result: (MOVDconst [int64(d)<<uint64(c)])
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64MOVDconst {
+ break
+ }
+ d := v_0.AuxInt
+ v.reset(OpARM64MOVDconst)
+ v.AuxInt = int64(d) << uint64(c)
+ return true
+ }
+ return false
+}
+func rewriteValueARM64_OpARM64SRA(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SRA x (MOVDconst [c]))
+ // cond:
+ // result: (SRAconst x [c&63])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64MOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpARM64SRAconst)
+ v.AuxInt = c & 63
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValueARM64_OpARM64SRAconst(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SRAconst [c] (MOVDconst [d]))
+ // cond:
+ // result: (MOVDconst [int64(d)>>uint64(c)])
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64MOVDconst {
+ break
+ }
+ d := v_0.AuxInt
+ v.reset(OpARM64MOVDconst)
+ v.AuxInt = int64(d) >> uint64(c)
+ return true
+ }
+ return false
+}
+func rewriteValueARM64_OpARM64SRL(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SRL x (MOVDconst [c]))
+ // cond:
+ // result: (SRLconst x [c&63])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64MOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpARM64SRLconst)
+ v.AuxInt = c & 63
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValueARM64_OpARM64SRLconst(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SRLconst [c] (MOVDconst [d]))
+ // cond:
+ // result: (MOVDconst [int64(uint64(d)>>uint64(c))])
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64MOVDconst {
+ break
+ }
+ d := v_0.AuxInt
+ v.reset(OpARM64MOVDconst)
+ v.AuxInt = int64(uint64(d) >> uint64(c))
+ return true
+ }
+ return false
+}
+func rewriteValueARM64_OpARM64SUB(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SUB x (MOVDconst [c]))
+ // cond:
+ // result: (SUBconst [c] x)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64MOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpARM64SUBconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (SUB x x)
+ // cond:
+ // result: (MOVDconst [0])
+ for {
+ x := v.Args[0]
+ if x != v.Args[1] {
+ break
+ }
+ v.reset(OpARM64MOVDconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (SUB x (SLLconst [c] y))
+ // cond:
+ // result: (SUBshiftLL x y [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64SLLconst {
+ break
+ }
+ c := v_1.AuxInt
+ y := v_1.Args[0]
+ v.reset(OpARM64SUBshiftLL)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (SUB x (SRLconst [c] y))
+ // cond:
+ // result: (SUBshiftRL x y [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64SRLconst {
+ break
+ }
+ c := v_1.AuxInt
+ y := v_1.Args[0]
+ v.reset(OpARM64SUBshiftRL)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (SUB x (SRAconst [c] y))
+ // cond:
+ // result: (SUBshiftRA x y [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64SRAconst {
+ break
+ }
+ c := v_1.AuxInt
+ y := v_1.Args[0]
+ v.reset(OpARM64SUBshiftRA)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ return false
+}
+func rewriteValueARM64_OpARM64SUBconst(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SUBconst [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: (SUBconst [c] (MOVDconst [d]))
+ // cond:
+ // result: (MOVDconst [d-c])
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64MOVDconst {
+ break
+ }
+ d := v_0.AuxInt
+ v.reset(OpARM64MOVDconst)
+ v.AuxInt = d - c
+ return true
+ }
+ // match: (SUBconst [c] (SUBconst [d] x))
+ // cond:
+ // result: (ADDconst [-c-d] x)
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64SUBconst {
+ break
+ }
+ d := v_0.AuxInt
+ x := v_0.Args[0]
+ v.reset(OpARM64ADDconst)
+ v.AuxInt = -c - d
+ v.AddArg(x)
+ return true
+ }
+ // match: (SUBconst [c] (ADDconst [d] x))
+ // cond:
+ // result: (ADDconst [-c+d] x)
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64ADDconst {
+ break
+ }
+ d := v_0.AuxInt
+ x := v_0.Args[0]
+ v.reset(OpARM64ADDconst)
+ v.AuxInt = -c + d
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValueARM64_OpARM64SUBshiftLL(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SUBshiftLL x (MOVDconst [c]) [d])
+ // cond:
+ // result: (SUBconst x [int64(uint64(c)<<uint64(d))])
+ for {
+ d := v.AuxInt
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64MOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpARM64SUBconst)
+ v.AuxInt = int64(uint64(c) << uint64(d))
+ v.AddArg(x)
+ return true
+ }
+ // match: (SUBshiftLL x (SLLconst x [c]) [d])
+ // cond: c==d
+ // result: (MOVDconst [0])
+ for {
+ d := v.AuxInt
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64SLLconst {
+ break
+ }
+ c := v_1.AuxInt
+ if x != v_1.Args[0] {
+ break
+ }
+ if !(c == d) {
+ break
+ }
+ v.reset(OpARM64MOVDconst)
+ v.AuxInt = 0
+ return true
+ }
+ return false
+}
+func rewriteValueARM64_OpARM64SUBshiftRA(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SUBshiftRA x (MOVDconst [c]) [d])
+ // cond:
+ // result: (SUBconst x [int64(int64(c)>>uint64(d))])
+ for {
+ d := v.AuxInt
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64MOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpARM64SUBconst)
+ v.AuxInt = int64(int64(c) >> uint64(d))
+ v.AddArg(x)
+ return true
+ }
+ // match: (SUBshiftRA x (SRAconst x [c]) [d])
+ // cond: c==d
+ // result: (MOVDconst [0])
+ for {
+ d := v.AuxInt
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64SRAconst {
+ break
+ }
+ c := v_1.AuxInt
+ if x != v_1.Args[0] {
+ break
+ }
+ if !(c == d) {
+ break
+ }
+ v.reset(OpARM64MOVDconst)
+ v.AuxInt = 0
+ return true
+ }
+ return false
+}
+func rewriteValueARM64_OpARM64SUBshiftRL(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SUBshiftRL x (MOVDconst [c]) [d])
+ // cond:
+ // result: (SUBconst x [int64(uint64(c)>>uint64(d))])
+ for {
+ d := v.AuxInt
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64MOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpARM64SUBconst)
+ v.AuxInt = int64(uint64(c) >> uint64(d))
+ v.AddArg(x)
+ return true
+ }
+ // match: (SUBshiftRL x (SRLconst x [c]) [d])
+ // cond: c==d
+ // result: (MOVDconst [0])
+ for {
+ d := v.AuxInt
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64SRLconst {
+ break
+ }
+ c := v_1.AuxInt
+ if x != v_1.Args[0] {
+ break
+ }
+ if !(c == d) {
+ break
+ }
+ v.reset(OpARM64MOVDconst)
+ v.AuxInt = 0
+ return true
+ }
+ return false
+}
+func rewriteValueARM64_OpARM64UDIV(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (UDIV x (MOVDconst [1]))
+ // cond:
+ // result: x
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64MOVDconst {
+ break
+ }
+ if v_1.AuxInt != 1 {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ // match: (UDIV x (MOVDconst [c]))
+ // cond: isPowerOfTwo(c)
+ // result: (SRLconst [log2(c)] x)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64MOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ if !(isPowerOfTwo(c)) {
+ break
+ }
+ v.reset(OpARM64SRLconst)
+ v.AuxInt = log2(c)
+ v.AddArg(x)
+ return true
+ }
+ // match: (UDIV (MOVDconst [c]) (MOVDconst [d]))
+ // cond:
+ // result: (MOVDconst [int64(uint64(c)/uint64(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 = int64(uint64(c) / uint64(d))
+ return true
+ }
+ return false
+}
+func rewriteValueARM64_OpARM64UDIVW(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (UDIVW x (MOVDconst [c]))
+ // cond: uint32(c)==1
+ // result: x
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64MOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint32(c) == 1) {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ // match: (UDIVW x (MOVDconst [c]))
+ // cond: isPowerOfTwo(c) && is32Bit(c)
+ // result: (SRLconst [log2(c)] x)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64MOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ if !(isPowerOfTwo(c) && is32Bit(c)) {
+ break
+ }
+ v.reset(OpARM64SRLconst)
+ v.AuxInt = log2(c)
+ v.AddArg(x)
+ return true
+ }
+ // match: (UDIVW (MOVDconst [c]) (MOVDconst [d]))
+ // cond:
+ // result: (MOVDconst [int64(uint32(c)/uint32(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 = int64(uint32(c) / uint32(d))
+ return true
+ }
+ return false
+}
+func rewriteValueARM64_OpARM64UMOD(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (UMOD _ (MOVDconst [1]))
+ // cond:
+ // result: (MOVDconst [0])
+ for {
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64MOVDconst {
+ break
+ }
+ if v_1.AuxInt != 1 {
+ break
+ }
+ v.reset(OpARM64MOVDconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (UMOD x (MOVDconst [c]))
+ // cond: isPowerOfTwo(c)
+ // result: (ANDconst [c-1] x)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64MOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ if !(isPowerOfTwo(c)) {
+ break
+ }
+ v.reset(OpARM64ANDconst)
+ v.AuxInt = c - 1
+ v.AddArg(x)
+ return true
+ }
+ // match: (UMOD (MOVDconst [c]) (MOVDconst [d]))
+ // cond:
+ // result: (MOVDconst [int64(uint64(c)%uint64(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 = int64(uint64(c) % uint64(d))
+ return true
+ }
+ return false
+}
+func rewriteValueARM64_OpARM64UMODW(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (UMODW _ (MOVDconst [c]))
+ // cond: uint32(c)==1
+ // result: (MOVDconst [0])
+ for {
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64MOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint32(c) == 1) {
+ break
+ }
+ v.reset(OpARM64MOVDconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (UMODW x (MOVDconst [c]))
+ // cond: isPowerOfTwo(c) && is32Bit(c)
+ // result: (ANDconst [c-1] x)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64MOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ if !(isPowerOfTwo(c) && is32Bit(c)) {
+ break
+ }
+ v.reset(OpARM64ANDconst)
+ v.AuxInt = c - 1
+ v.AddArg(x)
+ return true
+ }
+ // match: (UMODW (MOVDconst [c]) (MOVDconst [d]))
+ // cond:
+ // result: (MOVDconst [int64(uint32(c)%uint32(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 = int64(uint32(c) % uint32(d))
+ return true
+ }
+ return false
+}
+func rewriteValueARM64_OpARM64XOR(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (XOR (MOVDconst [c]) x)
+ // cond:
+ // result: (XORconst [c] x)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64MOVDconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ v.reset(OpARM64XORconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (XOR x (MOVDconst [c]))
+ // cond:
+ // result: (XORconst [c] x)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64MOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpARM64XORconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (XOR x x)
+ // cond:
+ // result: (MOVDconst [0])
+ for {
+ x := v.Args[0]
+ if x != v.Args[1] {
+ break
+ }
+ v.reset(OpARM64MOVDconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (XOR x (SLLconst [c] y))
+ // cond:
+ // result: (XORshiftLL x y [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64SLLconst {
+ break
+ }
+ c := v_1.AuxInt
+ y := v_1.Args[0]
+ v.reset(OpARM64XORshiftLL)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (XOR (SLLconst [c] y) x)
+ // cond:
+ // result: (XORshiftLL x y [c])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64SLLconst {
+ break
+ }
+ c := v_0.AuxInt
+ y := v_0.Args[0]
+ x := v.Args[1]
+ v.reset(OpARM64XORshiftLL)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (XOR x (SRLconst [c] y))
+ // cond:
+ // result: (XORshiftRL x y [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64SRLconst {
+ break
+ }
+ c := v_1.AuxInt
+ y := v_1.Args[0]
+ v.reset(OpARM64XORshiftRL)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (XOR (SRLconst [c] y) x)
+ // cond:
+ // result: (XORshiftRL x y [c])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64SRLconst {
+ break
+ }
+ c := v_0.AuxInt
+ y := v_0.Args[0]
+ x := v.Args[1]
+ v.reset(OpARM64XORshiftRL)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (XOR x (SRAconst [c] y))
+ // cond:
+ // result: (XORshiftRA x y [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64SRAconst {
+ break
+ }
+ c := v_1.AuxInt
+ y := v_1.Args[0]
+ v.reset(OpARM64XORshiftRA)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (XOR (SRAconst [c] y) x)
+ // cond:
+ // result: (XORshiftRA x y [c])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64SRAconst {
+ break
+ }
+ c := v_0.AuxInt
+ y := v_0.Args[0]
+ x := v.Args[1]
+ v.reset(OpARM64XORshiftRA)
+ v.AuxInt = c
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ return false
+}
+func rewriteValueARM64_OpARM64XORconst(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (XORconst [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: (XORconst [-1] x)
+ // cond:
+ // result: (MVN x)
+ for {
+ if v.AuxInt != -1 {
+ break
+ }
+ x := v.Args[0]
+ v.reset(OpARM64MVN)
+ v.AddArg(x)
+ return true
+ }
+ // match: (XORconst [c] (MOVDconst [d]))
+ // cond:
+ // result: (MOVDconst [c^d])
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64MOVDconst {
+ break
+ }
+ d := v_0.AuxInt
+ v.reset(OpARM64MOVDconst)
+ v.AuxInt = c ^ d
+ return true
+ }
+ // match: (XORconst [c] (XORconst [d] x))
+ // cond:
+ // result: (XORconst [c^d] x)
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64XORconst {
+ break
+ }
+ d := v_0.AuxInt
+ x := v_0.Args[0]
+ v.reset(OpARM64XORconst)
+ v.AuxInt = c ^ d
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValueARM64_OpARM64XORshiftLL(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (XORshiftLL (MOVDconst [c]) x [d])
+ // cond:
+ // result: (XORconst [c] (SLLconst <x.Type> x [d]))
+ for {
+ d := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64MOVDconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ v.reset(OpARM64XORconst)
+ v.AuxInt = c
+ v0 := b.NewValue0(v.Line, OpARM64SLLconst, x.Type)
+ v0.AuxInt = d
+ v0.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (XORshiftLL x (MOVDconst [c]) [d])
+ // cond:
+ // result: (XORconst x [int64(uint64(c)<<uint64(d))])
+ for {
+ d := v.AuxInt
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64MOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpARM64XORconst)
+ v.AuxInt = int64(uint64(c) << uint64(d))
+ v.AddArg(x)
+ return true
+ }
+ // match: (XORshiftLL x (SLLconst x [c]) [d])
+ // cond: c==d
+ // result: (MOVDconst [0])
+ for {
+ d := v.AuxInt
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64SLLconst {
+ break
+ }
+ c := v_1.AuxInt
+ if x != v_1.Args[0] {
+ break
+ }
+ if !(c == d) {
+ break
+ }
+ v.reset(OpARM64MOVDconst)
+ v.AuxInt = 0
+ return true
+ }
+ return false
+}
+func rewriteValueARM64_OpARM64XORshiftRA(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (XORshiftRA (MOVDconst [c]) x [d])
+ // cond:
+ // result: (XORconst [c] (SRAconst <x.Type> x [d]))
+ for {
+ d := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64MOVDconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ v.reset(OpARM64XORconst)
+ v.AuxInt = c
+ v0 := b.NewValue0(v.Line, OpARM64SRAconst, x.Type)
+ v0.AuxInt = d
+ v0.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (XORshiftRA x (MOVDconst [c]) [d])
+ // cond:
+ // result: (XORconst x [int64(int64(c)>>uint64(d))])
+ for {
+ d := v.AuxInt
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64MOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpARM64XORconst)
+ v.AuxInt = int64(int64(c) >> uint64(d))
+ v.AddArg(x)
+ return true
+ }
+ // match: (XORshiftRA x (SRAconst x [c]) [d])
+ // cond: c==d
+ // result: (MOVDconst [0])
+ for {
+ d := v.AuxInt
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64SRAconst {
+ break
+ }
+ c := v_1.AuxInt
+ if x != v_1.Args[0] {
+ break
+ }
+ if !(c == d) {
+ break
+ }
+ v.reset(OpARM64MOVDconst)
+ v.AuxInt = 0
+ return true
+ }
+ return false
+}
+func rewriteValueARM64_OpARM64XORshiftRL(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (XORshiftRL (MOVDconst [c]) x [d])
+ // cond:
+ // result: (XORconst [c] (SRLconst <x.Type> x [d]))
+ for {
+ d := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpARM64MOVDconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ v.reset(OpARM64XORconst)
+ v.AuxInt = c
+ v0 := b.NewValue0(v.Line, OpARM64SRLconst, x.Type)
+ v0.AuxInt = d
+ v0.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (XORshiftRL x (MOVDconst [c]) [d])
+ // cond:
+ // result: (XORconst x [int64(uint64(c)>>uint64(d))])
+ for {
+ d := v.AuxInt
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64MOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpARM64XORconst)
+ v.AuxInt = int64(uint64(c) >> uint64(d))
+ v.AddArg(x)
+ return true
+ }
+ // match: (XORshiftRL x (SRLconst x [c]) [d])
+ // cond: c==d
+ // result: (MOVDconst [0])
+ for {
+ d := v.AuxInt
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64SRLconst {
+ break
+ }
+ c := v_1.AuxInt
+ if x != v_1.Args[0] {
+ break
+ }
+ if !(c == d) {
+ break
+ }
+ v.reset(OpARM64MOVDconst)
+ v.AuxInt = 0
+ return true
+ }
+ return false
+}
+func rewriteValueARM64_OpAdd16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Add16 x y)
+ // cond:
+ // result: (ADD x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64ADD)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueARM64_OpAdd32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Add32 x y)
+ // cond:
+ // result: (ADD x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64ADD)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueARM64_OpAdd32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Add32F x y)
+ // cond:
+ // result: (FADDS x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64FADDS)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueARM64_OpAdd64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Add64 x y)
+ // cond:
+ // result: (ADD x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64ADD)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueARM64_OpAdd64F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Add64F x y)
+ // cond:
+ // result: (FADDD x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64FADDD)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueARM64_OpAdd8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Add8 x y)
+ // cond:
+ // result: (ADD x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64ADD)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueARM64_OpAddPtr(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (AddPtr x y)
+ // cond:
+ // result: (ADD x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64ADD)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueARM64_OpAddr(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Addr {sym} base)
+ // cond:
+ // result: (MOVDaddr {sym} base)
+ for {
+ sym := v.Aux
+ base := v.Args[0]
+ v.reset(OpARM64MOVDaddr)
+ v.Aux = sym
+ v.AddArg(base)
+ return true
+ }
+}
+func rewriteValueARM64_OpAnd16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (And16 x y)
+ // cond:
+ // result: (AND x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64AND)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueARM64_OpAnd32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (And32 x y)
+ // cond:
+ // result: (AND x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64AND)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueARM64_OpAnd64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (And64 x y)
+ // cond:
+ // result: (AND x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64AND)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueARM64_OpAnd8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (And8 x y)
+ // cond:
+ // result: (AND x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64AND)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueARM64_OpAndB(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (AndB x y)
+ // cond:
+ // result: (AND x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64AND)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueARM64_OpAtomicAdd32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (AtomicAdd32 ptr val mem)
+ // cond:
+ // result: (LoweredAtomicAdd32 ptr val mem)
+ for {
+ ptr := v.Args[0]
+ val := v.Args[1]
+ mem := v.Args[2]
+ v.reset(OpARM64LoweredAtomicAdd32)
+ v.AddArg(ptr)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+}
+func rewriteValueARM64_OpAtomicAdd64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (AtomicAdd64 ptr val mem)
+ // cond:
+ // result: (LoweredAtomicAdd64 ptr val mem)
+ for {
+ ptr := v.Args[0]
+ val := v.Args[1]
+ mem := v.Args[2]
+ v.reset(OpARM64LoweredAtomicAdd64)
+ v.AddArg(ptr)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+}
+func rewriteValueARM64_OpAtomicAnd8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (AtomicAnd8 ptr val mem)
+ // cond:
+ // result: (LoweredAtomicAnd8 ptr val mem)
+ for {
+ ptr := v.Args[0]
+ val := v.Args[1]
+ mem := v.Args[2]
+ v.reset(OpARM64LoweredAtomicAnd8)
+ v.AddArg(ptr)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+}
+func rewriteValueARM64_OpAtomicCompareAndSwap32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (AtomicCompareAndSwap32 ptr old new_ mem)
+ // cond:
+ // result: (LoweredAtomicCas32 ptr old new_ mem)
+ for {
+ ptr := v.Args[0]
+ old := v.Args[1]
+ new_ := v.Args[2]
+ mem := v.Args[3]
+ v.reset(OpARM64LoweredAtomicCas32)
+ v.AddArg(ptr)
+ v.AddArg(old)
+ v.AddArg(new_)
+ v.AddArg(mem)
+ return true
+ }
+}
+func rewriteValueARM64_OpAtomicCompareAndSwap64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (AtomicCompareAndSwap64 ptr old new_ mem)
+ // cond:
+ // result: (LoweredAtomicCas64 ptr old new_ mem)
+ for {
+ ptr := v.Args[0]
+ old := v.Args[1]
+ new_ := v.Args[2]
+ mem := v.Args[3]
+ v.reset(OpARM64LoweredAtomicCas64)
+ v.AddArg(ptr)
+ v.AddArg(old)
+ v.AddArg(new_)
+ v.AddArg(mem)
+ return true
+ }
+}
+func rewriteValueARM64_OpAtomicExchange32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (AtomicExchange32 ptr val mem)
+ // cond:
+ // result: (LoweredAtomicExchange32 ptr val mem)
+ for {
+ ptr := v.Args[0]
+ val := v.Args[1]
+ mem := v.Args[2]
+ v.reset(OpARM64LoweredAtomicExchange32)
+ v.AddArg(ptr)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+}
+func rewriteValueARM64_OpAtomicExchange64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (AtomicExchange64 ptr val mem)
+ // cond:
+ // result: (LoweredAtomicExchange64 ptr val mem)
+ for {
+ ptr := v.Args[0]
+ val := v.Args[1]
+ mem := v.Args[2]
+ v.reset(OpARM64LoweredAtomicExchange64)
+ v.AddArg(ptr)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+}
+func rewriteValueARM64_OpAtomicLoad32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (AtomicLoad32 ptr mem)
+ // cond:
+ // result: (LDARW ptr mem)
+ for {
+ ptr := v.Args[0]
+ mem := v.Args[1]
+ v.reset(OpARM64LDARW)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+}
+func rewriteValueARM64_OpAtomicLoad64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (AtomicLoad64 ptr mem)
+ // cond:
+ // result: (LDAR ptr mem)
+ for {
+ ptr := v.Args[0]
+ mem := v.Args[1]
+ v.reset(OpARM64LDAR)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+}
+func rewriteValueARM64_OpAtomicLoadPtr(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (AtomicLoadPtr ptr mem)
+ // cond:
+ // result: (LDAR ptr mem)
+ for {
+ ptr := v.Args[0]
+ mem := v.Args[1]
+ v.reset(OpARM64LDAR)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+}
+func rewriteValueARM64_OpAtomicOr8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (AtomicOr8 ptr val mem)
+ // cond:
+ // result: (LoweredAtomicOr8 ptr val mem)
+ for {
+ ptr := v.Args[0]
+ val := v.Args[1]
+ mem := v.Args[2]
+ v.reset(OpARM64LoweredAtomicOr8)
+ v.AddArg(ptr)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+}
+func rewriteValueARM64_OpAtomicStore32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (AtomicStore32 ptr val mem)
+ // cond:
+ // result: (STLRW ptr val mem)
+ for {
+ ptr := v.Args[0]
+ val := v.Args[1]
+ mem := v.Args[2]
+ v.reset(OpARM64STLRW)
+ v.AddArg(ptr)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+}
+func rewriteValueARM64_OpAtomicStore64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (AtomicStore64 ptr val mem)
+ // cond:
+ // result: (STLR ptr val mem)
+ for {
+ ptr := v.Args[0]
+ val := v.Args[1]
+ mem := v.Args[2]
+ v.reset(OpARM64STLR)
+ v.AddArg(ptr)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+}
+func rewriteValueARM64_OpAtomicStorePtrNoWB(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (AtomicStorePtrNoWB ptr val mem)
+ // cond:
+ // result: (STLR ptr val mem)
+ for {
+ ptr := v.Args[0]
+ val := v.Args[1]
+ mem := v.Args[2]
+ v.reset(OpARM64STLR)
+ v.AddArg(ptr)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+}
+func rewriteValueARM64_OpAvg64u(v *Value, config *Config) 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])))
+ for {
+ t := v.Type
+ 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
+ v1.AddArg(x)
+ 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)
+ return true
+ }
+}
+func rewriteValueARM64_OpBswap32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Bswap32 x)
+ // cond:
+ // result: (REVW x)
+ for {
+ x := v.Args[0]
+ v.reset(OpARM64REVW)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueARM64_OpBswap64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Bswap64 x)
+ // cond:
+ // result: (REV x)
+ for {
+ x := v.Args[0]
+ v.reset(OpARM64REV)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueARM64_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(OpARM64CALLclosure)
+ v.AuxInt = argwid
+ v.AddArg(entry)
+ v.AddArg(closure)
+ v.AddArg(mem)
+ return true
+ }
+}
+func rewriteValueARM64_OpCom16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Com16 x)
+ // cond:
+ // result: (MVN x)
+ for {
+ x := v.Args[0]
+ v.reset(OpARM64MVN)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueARM64_OpCom32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Com32 x)
+ // cond:
+ // result: (MVN x)
+ for {
+ x := v.Args[0]
+ v.reset(OpARM64MVN)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueARM64_OpCom64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Com64 x)
+ // cond:
+ // result: (MVN x)
+ for {
+ x := v.Args[0]
+ v.reset(OpARM64MVN)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueARM64_OpCom8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Com8 x)
+ // cond:
+ // result: (MVN x)
+ for {
+ x := v.Args[0]
+ v.reset(OpARM64MVN)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueARM64_OpConst16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Const16 [val])
+ // cond:
+ // result: (MOVDconst [val])
+ for {
+ val := v.AuxInt
+ v.reset(OpARM64MOVDconst)
+ v.AuxInt = val
+ return true
+ }
+}
+func rewriteValueARM64_OpConst32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Const32 [val])
+ // cond:
+ // result: (MOVDconst [val])
+ for {
+ val := v.AuxInt
+ v.reset(OpARM64MOVDconst)
+ v.AuxInt = val
+ return true
+ }
+}
+func rewriteValueARM64_OpConst32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Const32F [val])
+ // cond:
+ // result: (FMOVSconst [val])
+ for {
+ val := v.AuxInt
+ v.reset(OpARM64FMOVSconst)
+ v.AuxInt = val
+ return true
+ }
+}
+func rewriteValueARM64_OpConst64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Const64 [val])
+ // cond:
+ // result: (MOVDconst [val])
+ for {
+ val := v.AuxInt
+ v.reset(OpARM64MOVDconst)
+ v.AuxInt = val
+ return true
+ }
+}
+func rewriteValueARM64_OpConst64F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Const64F [val])
+ // cond:
+ // result: (FMOVDconst [val])
+ for {
+ val := v.AuxInt
+ v.reset(OpARM64FMOVDconst)
+ v.AuxInt = val
+ return true
+ }
+}
+func rewriteValueARM64_OpConst8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Const8 [val])
+ // cond:
+ // result: (MOVDconst [val])
+ for {
+ val := v.AuxInt
+ v.reset(OpARM64MOVDconst)
+ v.AuxInt = val
+ return true
+ }
+}
+func rewriteValueARM64_OpConstBool(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ConstBool [b])
+ // cond:
+ // result: (MOVDconst [b])
+ for {
+ b := v.AuxInt
+ v.reset(OpARM64MOVDconst)
+ v.AuxInt = b
+ return true
+ }
+}
+func rewriteValueARM64_OpConstNil(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ConstNil)
+ // cond:
+ // result: (MOVDconst [0])
+ for {
+ v.reset(OpARM64MOVDconst)
+ v.AuxInt = 0
+ return true
+ }
+}
+func rewriteValueARM64_OpConvert(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Convert x mem)
+ // cond:
+ // result: (MOVDconvert x mem)
+ for {
+ x := v.Args[0]
+ mem := v.Args[1]
+ v.reset(OpARM64MOVDconvert)
+ v.AddArg(x)
+ v.AddArg(mem)
+ return true
+ }
+}
+func rewriteValueARM64_OpCtz32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Ctz32 <t> x)
+ // cond:
+ // result: (CLZW (RBITW <t> x))
+ for {
+ t := v.Type
+ x := v.Args[0]
+ v.reset(OpARM64CLZW)
+ v0 := b.NewValue0(v.Line, OpARM64RBITW, t)
+ v0.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueARM64_OpCtz64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Ctz64 <t> x)
+ // cond:
+ // result: (CLZ (RBIT <t> x))
+ for {
+ t := v.Type
+ x := v.Args[0]
+ v.reset(OpARM64CLZ)
+ v0 := b.NewValue0(v.Line, OpARM64RBIT, t)
+ v0.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueARM64_OpCvt32Fto32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Cvt32Fto32 x)
+ // cond:
+ // result: (FCVTZSSW x)
+ for {
+ x := v.Args[0]
+ v.reset(OpARM64FCVTZSSW)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueARM64_OpCvt32Fto32U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Cvt32Fto32U x)
+ // cond:
+ // result: (FCVTZUSW x)
+ for {
+ x := v.Args[0]
+ v.reset(OpARM64FCVTZUSW)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueARM64_OpCvt32Fto64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Cvt32Fto64 x)
+ // cond:
+ // result: (FCVTZSS x)
+ for {
+ x := v.Args[0]
+ v.reset(OpARM64FCVTZSS)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueARM64_OpCvt32Fto64F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Cvt32Fto64F x)
+ // cond:
+ // result: (FCVTSD x)
+ for {
+ x := v.Args[0]
+ v.reset(OpARM64FCVTSD)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueARM64_OpCvt32Fto64U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Cvt32Fto64U x)
+ // cond:
+ // result: (FCVTZUS x)
+ for {
+ x := v.Args[0]
+ v.reset(OpARM64FCVTZUS)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueARM64_OpCvt32Uto32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Cvt32Uto32F x)
+ // cond:
+ // result: (UCVTFWS x)
+ for {
+ x := v.Args[0]
+ v.reset(OpARM64UCVTFWS)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueARM64_OpCvt32Uto64F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Cvt32Uto64F x)
+ // cond:
+ // result: (UCVTFWD x)
+ for {
+ x := v.Args[0]
+ v.reset(OpARM64UCVTFWD)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueARM64_OpCvt32to32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Cvt32to32F x)
+ // cond:
+ // result: (SCVTFWS x)
+ for {
+ x := v.Args[0]
+ v.reset(OpARM64SCVTFWS)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueARM64_OpCvt32to64F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Cvt32to64F x)
+ // cond:
+ // result: (SCVTFWD x)
+ for {
+ x := v.Args[0]
+ v.reset(OpARM64SCVTFWD)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueARM64_OpCvt64Fto32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Cvt64Fto32 x)
+ // cond:
+ // result: (FCVTZSDW x)
+ for {
+ x := v.Args[0]
+ v.reset(OpARM64FCVTZSDW)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueARM64_OpCvt64Fto32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Cvt64Fto32F x)
+ // cond:
+ // result: (FCVTDS x)
+ for {
+ x := v.Args[0]
+ v.reset(OpARM64FCVTDS)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueARM64_OpCvt64Fto32U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Cvt64Fto32U x)
+ // cond:
+ // result: (FCVTZUDW x)
+ for {
+ x := v.Args[0]
+ v.reset(OpARM64FCVTZUDW)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueARM64_OpCvt64Fto64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Cvt64Fto64 x)
+ // cond:
+ // result: (FCVTZSD x)
+ for {
+ x := v.Args[0]
+ v.reset(OpARM64FCVTZSD)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueARM64_OpCvt64Fto64U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Cvt64Fto64U x)
+ // cond:
+ // result: (FCVTZUD x)
+ for {
+ x := v.Args[0]
+ v.reset(OpARM64FCVTZUD)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueARM64_OpCvt64Uto32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Cvt64Uto32F x)
+ // cond:
+ // result: (UCVTFS x)
+ for {
+ x := v.Args[0]
+ v.reset(OpARM64UCVTFS)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueARM64_OpCvt64Uto64F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Cvt64Uto64F x)
+ // cond:
+ // result: (UCVTFD x)
+ for {
+ x := v.Args[0]
+ v.reset(OpARM64UCVTFD)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueARM64_OpCvt64to32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Cvt64to32F x)
+ // cond:
+ // result: (SCVTFS x)
+ for {
+ x := v.Args[0]
+ v.reset(OpARM64SCVTFS)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueARM64_OpCvt64to64F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Cvt64to64F x)
+ // cond:
+ // result: (SCVTFD x)
+ for {
+ x := v.Args[0]
+ v.reset(OpARM64SCVTFD)
+ v.AddArg(x)
+ 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 {
+ b := v.Block
+ _ = b
+ // match: (Div16 x y)
+ // cond:
+ // result: (DIVW (SignExt16to32 x) (SignExt16to32 y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64DIVW)
+ v0 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
+ v1.AddArg(y)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueARM64_OpDiv16u(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Div16u x y)
+ // cond:
+ // result: (UDIVW (ZeroExt16to32 x) (ZeroExt16to32 y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64UDIVW)
+ v0 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+ v1.AddArg(y)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueARM64_OpDiv32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Div32 x y)
+ // cond:
+ // result: (DIVW x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64DIVW)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueARM64_OpDiv32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Div32F x y)
+ // cond:
+ // result: (FDIVS x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64FDIVS)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueARM64_OpDiv32u(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Div32u x y)
+ // cond:
+ // result: (UDIVW x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64UDIVW)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueARM64_OpDiv64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Div64 x y)
+ // cond:
+ // result: (DIV x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64DIV)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueARM64_OpDiv64F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Div64F x y)
+ // cond:
+ // result: (FDIVD x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64FDIVD)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueARM64_OpDiv64u(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Div64u x y)
+ // cond:
+ // result: (UDIV x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64UDIV)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueARM64_OpDiv8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Div8 x y)
+ // cond:
+ // result: (DIVW (SignExt8to32 x) (SignExt8to32 y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64DIVW)
+ v0 := b.NewValue0(v.Line, OpSignExt8to32, config.fe.TypeInt32())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpSignExt8to32, config.fe.TypeInt32())
+ v1.AddArg(y)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueARM64_OpDiv8u(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Div8u x y)
+ // cond:
+ // result: (UDIVW (ZeroExt8to32 x) (ZeroExt8to32 y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64UDIVW)
+ v0 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+ v1.AddArg(y)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueARM64_OpEq16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Eq16 x y)
+ // cond:
+ // result: (Equal (CMPW (ZeroExt16to32 x) (ZeroExt16to32 y)))
+ for {
+ 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())
+ 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 rewriteValueARM64_OpEq32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Eq32 x y)
+ // cond:
+ // result: (Equal (CMPW x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64Equal)
+ v0 := b.NewValue0(v.Line, OpARM64CMPW, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueARM64_OpEq32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Eq32F x y)
+ // cond:
+ // result: (Equal (FCMPS x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64Equal)
+ v0 := b.NewValue0(v.Line, OpARM64FCMPS, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueARM64_OpEq64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Eq64 x y)
+ // cond:
+ // result: (Equal (CMP x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64Equal)
+ v0 := b.NewValue0(v.Line, OpARM64CMP, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueARM64_OpEq64F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Eq64F x y)
+ // cond:
+ // result: (Equal (FCMPD x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64Equal)
+ v0 := b.NewValue0(v.Line, OpARM64FCMPD, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueARM64_OpEq8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Eq8 x y)
+ // cond:
+ // result: (Equal (CMPW (ZeroExt8to32 x) (ZeroExt8to32 y)))
+ for {
+ 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())
+ 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_OpEqB(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (EqB x y)
+ // cond:
+ // result: (XOR (MOVDconst [1]) (XOR <config.fe.TypeBool()> x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64XOR)
+ v0 := b.NewValue0(v.Line, OpARM64MOVDconst, config.fe.TypeUInt64())
+ v0.AuxInt = 1
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpARM64XOR, config.fe.TypeBool())
+ v1.AddArg(x)
+ v1.AddArg(y)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueARM64_OpEqPtr(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (EqPtr x y)
+ // cond:
+ // result: (Equal (CMP x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64Equal)
+ v0 := b.NewValue0(v.Line, OpARM64CMP, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueARM64_OpGeq16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Geq16 x y)
+ // cond:
+ // result: (GreaterEqual (CMPW (SignExt16to32 x) (SignExt16to32 y)))
+ for {
+ 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())
+ 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_OpGeq16U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Geq16U x y)
+ // cond:
+ // result: (GreaterEqualU (CMPW (ZeroExt16to32 x) (ZeroExt16to32 y)))
+ for {
+ 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())
+ 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 rewriteValueARM64_OpGeq32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Geq32 x y)
+ // cond:
+ // result: (GreaterEqual (CMPW x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64GreaterEqual)
+ v0 := b.NewValue0(v.Line, OpARM64CMPW, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueARM64_OpGeq32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Geq32F x y)
+ // cond:
+ // result: (GreaterEqual (FCMPS x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64GreaterEqual)
+ v0 := b.NewValue0(v.Line, OpARM64FCMPS, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueARM64_OpGeq32U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Geq32U x y)
+ // cond:
+ // result: (GreaterEqualU (CMPW x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64GreaterEqualU)
+ v0 := b.NewValue0(v.Line, OpARM64CMPW, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueARM64_OpGeq64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Geq64 x y)
+ // cond:
+ // result: (GreaterEqual (CMP x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64GreaterEqual)
+ v0 := b.NewValue0(v.Line, OpARM64CMP, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueARM64_OpGeq64F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Geq64F x y)
+ // cond:
+ // result: (GreaterEqual (FCMPD x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64GreaterEqual)
+ v0 := b.NewValue0(v.Line, OpARM64FCMPD, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueARM64_OpGeq64U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Geq64U x y)
+ // cond:
+ // result: (GreaterEqualU (CMP x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64GreaterEqualU)
+ v0 := b.NewValue0(v.Line, OpARM64CMP, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueARM64_OpGeq8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Geq8 x y)
+ // cond:
+ // result: (GreaterEqual (CMPW (SignExt8to32 x) (SignExt8to32 y)))
+ for {
+ 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())
+ 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_OpGeq8U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Geq8U x y)
+ // cond:
+ // result: (GreaterEqualU (CMPW (ZeroExt8to32 x) (ZeroExt8to32 y)))
+ for {
+ 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())
+ 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_OpGetClosurePtr(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (GetClosurePtr)
+ // cond:
+ // result: (LoweredGetClosurePtr)
+ for {
+ v.reset(OpARM64LoweredGetClosurePtr)
+ 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 {
+ b := v.Block
+ _ = b
+ // match: (Greater16 x y)
+ // cond:
+ // result: (GreaterThan (CMPW (SignExt16to32 x) (SignExt16to32 y)))
+ for {
+ 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())
+ 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_OpGreater16U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Greater16U x y)
+ // cond:
+ // result: (GreaterThanU (CMPW (ZeroExt16to32 x) (ZeroExt16to32 y)))
+ for {
+ 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())
+ 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 rewriteValueARM64_OpGreater32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Greater32 x y)
+ // cond:
+ // result: (GreaterThan (CMPW x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64GreaterThan)
+ v0 := b.NewValue0(v.Line, OpARM64CMPW, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueARM64_OpGreater32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Greater32F x y)
+ // cond:
+ // result: (GreaterThan (FCMPS x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64GreaterThan)
+ v0 := b.NewValue0(v.Line, OpARM64FCMPS, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueARM64_OpGreater32U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Greater32U x y)
+ // cond:
+ // result: (GreaterThanU (CMPW x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64GreaterThanU)
+ v0 := b.NewValue0(v.Line, OpARM64CMPW, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueARM64_OpGreater64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Greater64 x y)
+ // cond:
+ // result: (GreaterThan (CMP x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64GreaterThan)
+ v0 := b.NewValue0(v.Line, OpARM64CMP, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueARM64_OpGreater64F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Greater64F x y)
+ // cond:
+ // result: (GreaterThan (FCMPD x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64GreaterThan)
+ v0 := b.NewValue0(v.Line, OpARM64FCMPD, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueARM64_OpGreater64U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Greater64U x y)
+ // cond:
+ // result: (GreaterThanU (CMP x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64GreaterThanU)
+ v0 := b.NewValue0(v.Line, OpARM64CMP, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueARM64_OpGreater8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Greater8 x y)
+ // cond:
+ // result: (GreaterThan (CMPW (SignExt8to32 x) (SignExt8to32 y)))
+ for {
+ 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())
+ 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_OpGreater8U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Greater8U x y)
+ // cond:
+ // result: (GreaterThanU (CMPW (ZeroExt8to32 x) (ZeroExt8to32 y)))
+ for {
+ 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())
+ 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 rewriteValueARM64_OpHmul32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Hmul32 x y)
+ // cond:
+ // result: (SRAconst (MULL <config.fe.TypeInt64()> x y) [32])
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64SRAconst)
+ v.AuxInt = 32
+ v0 := b.NewValue0(v.Line, OpARM64MULL, config.fe.TypeInt64())
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueARM64_OpHmul32u(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Hmul32u x y)
+ // cond:
+ // result: (SRAconst (UMULL <config.fe.TypeUInt64()> x y) [32])
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64SRAconst)
+ v.AuxInt = 32
+ v0 := b.NewValue0(v.Line, OpARM64UMULL, config.fe.TypeUInt64())
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueARM64_OpHmul64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Hmul64 x y)
+ // cond:
+ // result: (MULH x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64MULH)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueARM64_OpHmul64u(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Hmul64u x y)
+ // cond:
+ // result: (UMULH x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64UMULH)
+ v.AddArg(x)
+ v.AddArg(y)
+ 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
+ // 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(OpARM64CALLinter)
+ v.AuxInt = argwid
+ v.AddArg(entry)
+ v.AddArg(mem)
+ return true
+ }
+}
+func rewriteValueARM64_OpIsInBounds(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (IsInBounds idx len)
+ // cond:
+ // result: (LessThanU (CMP idx len))
+ for {
+ idx := v.Args[0]
+ len := v.Args[1]
+ v.reset(OpARM64LessThanU)
+ v0 := b.NewValue0(v.Line, OpARM64CMP, TypeFlags)
+ v0.AddArg(idx)
+ v0.AddArg(len)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueARM64_OpIsNonNil(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (IsNonNil ptr)
+ // cond:
+ // result: (NotEqual (CMPconst [0] ptr))
+ for {
+ ptr := v.Args[0]
+ v.reset(OpARM64NotEqual)
+ v0 := b.NewValue0(v.Line, OpARM64CMPconst, TypeFlags)
+ v0.AuxInt = 0
+ v0.AddArg(ptr)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueARM64_OpIsSliceInBounds(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (IsSliceInBounds idx len)
+ // cond:
+ // result: (LessEqualU (CMP idx len))
+ for {
+ idx := v.Args[0]
+ len := v.Args[1]
+ v.reset(OpARM64LessEqualU)
+ v0 := b.NewValue0(v.Line, OpARM64CMP, TypeFlags)
+ v0.AddArg(idx)
+ v0.AddArg(len)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueARM64_OpLeq16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Leq16 x y)
+ // cond:
+ // result: (LessEqual (CMPW (SignExt16to32 x) (SignExt16to32 y)))
+ for {
+ 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())
+ 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_OpLeq16U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Leq16U x y)
+ // cond:
+ // result: (LessEqualU (CMPW (ZeroExt16to32 x) (ZeroExt16to32 y)))
+ for {
+ 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())
+ 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 rewriteValueARM64_OpLeq32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Leq32 x y)
+ // cond:
+ // result: (LessEqual (CMPW x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64LessEqual)
+ v0 := b.NewValue0(v.Line, OpARM64CMPW, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueARM64_OpLeq32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Leq32F x y)
+ // cond:
+ // result: (GreaterEqual (FCMPS y x))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64GreaterEqual)
+ v0 := b.NewValue0(v.Line, OpARM64FCMPS, TypeFlags)
+ v0.AddArg(y)
+ v0.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueARM64_OpLeq32U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Leq32U x y)
+ // cond:
+ // result: (LessEqualU (CMPW x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64LessEqualU)
+ v0 := b.NewValue0(v.Line, OpARM64CMPW, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueARM64_OpLeq64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Leq64 x y)
+ // cond:
+ // result: (LessEqual (CMP x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64LessEqual)
+ v0 := b.NewValue0(v.Line, OpARM64CMP, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueARM64_OpLeq64F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Leq64F x y)
+ // cond:
+ // result: (GreaterEqual (FCMPD y x))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64GreaterEqual)
+ v0 := b.NewValue0(v.Line, OpARM64FCMPD, TypeFlags)
+ v0.AddArg(y)
+ v0.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueARM64_OpLeq64U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Leq64U x y)
+ // cond:
+ // result: (LessEqualU (CMP x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64LessEqualU)
+ v0 := b.NewValue0(v.Line, OpARM64CMP, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueARM64_OpLeq8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Leq8 x y)
+ // cond:
+ // result: (LessEqual (CMPW (SignExt8to32 x) (SignExt8to32 y)))
+ for {
+ 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())
+ 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_OpLeq8U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Leq8U x y)
+ // cond:
+ // result: (LessEqualU (CMPW (ZeroExt8to32 x) (ZeroExt8to32 y)))
+ for {
+ 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())
+ 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_OpLess16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Less16 x y)
+ // cond:
+ // result: (LessThan (CMPW (SignExt16to32 x) (SignExt16to32 y)))
+ for {
+ 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())
+ 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_OpLess16U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Less16U x y)
+ // cond:
+ // result: (LessThanU (CMPW (ZeroExt16to32 x) (ZeroExt16to32 y)))
+ for {
+ 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())
+ 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 rewriteValueARM64_OpLess32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Less32 x y)
+ // cond:
+ // result: (LessThan (CMPW x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64LessThan)
+ v0 := b.NewValue0(v.Line, OpARM64CMPW, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueARM64_OpLess32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Less32F x y)
+ // cond:
+ // result: (GreaterThan (FCMPS y x))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64GreaterThan)
+ v0 := b.NewValue0(v.Line, OpARM64FCMPS, TypeFlags)
+ v0.AddArg(y)
+ v0.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueARM64_OpLess32U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Less32U x y)
+ // cond:
+ // result: (LessThanU (CMPW x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64LessThanU)
+ v0 := b.NewValue0(v.Line, OpARM64CMPW, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueARM64_OpLess64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Less64 x y)
+ // cond:
+ // result: (LessThan (CMP x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64LessThan)
+ v0 := b.NewValue0(v.Line, OpARM64CMP, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueARM64_OpLess64F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Less64F x y)
+ // cond:
+ // result: (GreaterThan (FCMPD y x))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64GreaterThan)
+ v0 := b.NewValue0(v.Line, OpARM64FCMPD, TypeFlags)
+ v0.AddArg(y)
+ v0.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueARM64_OpLess64U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Less64U x y)
+ // cond:
+ // result: (LessThanU (CMP x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64LessThanU)
+ v0 := b.NewValue0(v.Line, OpARM64CMP, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueARM64_OpLess8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Less8 x y)
+ // cond:
+ // result: (LessThan (CMPW (SignExt8to32 x) (SignExt8to32 y)))
+ for {
+ 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())
+ 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_OpLess8U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Less8U x y)
+ // cond:
+ // result: (LessThanU (CMPW (ZeroExt8to32 x) (ZeroExt8to32 y)))
+ for {
+ 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())
+ 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_OpLoad(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Load <t> ptr mem)
+ // cond: t.IsBoolean()
+ // result: (MOVBUload ptr mem)
+ for {
+ t := v.Type
+ ptr := v.Args[0]
+ mem := v.Args[1]
+ if !(t.IsBoolean()) {
+ break
+ }
+ v.reset(OpARM64MOVBUload)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (Load <t> ptr mem)
+ // cond: (is8BitInt(t) && isSigned(t))
+ // result: (MOVBload ptr mem)
+ for {
+ t := v.Type
+ ptr := v.Args[0]
+ mem := v.Args[1]
+ if !(is8BitInt(t) && isSigned(t)) {
+ break
+ }
+ v.reset(OpARM64MOVBload)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (Load <t> ptr mem)
+ // cond: (is8BitInt(t) && !isSigned(t))
+ // result: (MOVBUload ptr mem)
+ for {
+ t := v.Type
+ ptr := v.Args[0]
+ mem := v.Args[1]
+ if !(is8BitInt(t) && !isSigned(t)) {
+ break
+ }
+ v.reset(OpARM64MOVBUload)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (Load <t> ptr mem)
+ // cond: (is16BitInt(t) && isSigned(t))
+ // result: (MOVHload ptr mem)
+ for {
+ t := v.Type
+ ptr := v.Args[0]
+ mem := v.Args[1]
+ if !(is16BitInt(t) && isSigned(t)) {
+ break
+ }
+ v.reset(OpARM64MOVHload)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (Load <t> ptr mem)
+ // cond: (is16BitInt(t) && !isSigned(t))
+ // result: (MOVHUload ptr mem)
+ for {
+ t := v.Type
+ ptr := v.Args[0]
+ mem := v.Args[1]
+ if !(is16BitInt(t) && !isSigned(t)) {
+ break
+ }
+ v.reset(OpARM64MOVHUload)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (Load <t> ptr mem)
+ // cond: (is32BitInt(t) && isSigned(t))
+ // result: (MOVWload ptr mem)
+ for {
+ t := v.Type
+ ptr := v.Args[0]
+ mem := v.Args[1]
+ if !(is32BitInt(t) && isSigned(t)) {
+ break
+ }
+ v.reset(OpARM64MOVWload)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (Load <t> ptr mem)
+ // cond: (is32BitInt(t) && !isSigned(t))
+ // result: (MOVWUload ptr mem)
+ for {
+ t := v.Type
+ ptr := v.Args[0]
+ mem := v.Args[1]
+ if !(is32BitInt(t) && !isSigned(t)) {
+ break
+ }
+ v.reset(OpARM64MOVWUload)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (Load <t> ptr mem)
+ // cond: (is64BitInt(t) || isPtr(t))
+ // result: (MOVDload ptr mem)
+ for {
+ t := v.Type
+ ptr := v.Args[0]
+ mem := v.Args[1]
+ if !(is64BitInt(t) || isPtr(t)) {
+ break
+ }
+ v.reset(OpARM64MOVDload)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (Load <t> ptr mem)
+ // cond: is32BitFloat(t)
+ // result: (FMOVSload ptr mem)
+ for {
+ t := v.Type
+ ptr := v.Args[0]
+ mem := v.Args[1]
+ if !(is32BitFloat(t)) {
+ break
+ }
+ v.reset(OpARM64FMOVSload)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (Load <t> ptr mem)
+ // cond: is64BitFloat(t)
+ // result: (FMOVDload ptr mem)
+ for {
+ t := v.Type
+ ptr := v.Args[0]
+ mem := v.Args[1]
+ if !(is64BitFloat(t)) {
+ break
+ }
+ v.reset(OpARM64FMOVDload)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ 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 {
+ b := v.Block
+ _ = b
+ // match: (Lsh16x16 <t> x y)
+ // cond:
+ // result: (CSELULT (SLL <t> x (ZeroExt16to64 y)) (Const64 <t> [0]) (CMPconst [64] (ZeroExt16to64 y)))
+ for {
+ t := v.Type
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64CSELULT)
+ v0 := b.NewValue0(v.Line, OpARM64SLL, t)
+ v0.AddArg(x)
+ v1 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+ v1.AddArg(y)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ v2 := b.NewValue0(v.Line, OpConst64, t)
+ v2.AuxInt = 0
+ v.AddArg(v2)
+ v3 := b.NewValue0(v.Line, OpARM64CMPconst, TypeFlags)
+ v3.AuxInt = 64
+ v4 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+ v4.AddArg(y)
+ v3.AddArg(v4)
+ v.AddArg(v3)
+ return true
+ }
+}
+func rewriteValueARM64_OpLsh16x32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Lsh16x32 <t> x y)
+ // cond:
+ // result: (CSELULT (SLL <t> x (ZeroExt32to64 y)) (Const64 <t> [0]) (CMPconst [64] (ZeroExt32to64 y)))
+ for {
+ t := v.Type
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64CSELULT)
+ v0 := b.NewValue0(v.Line, OpARM64SLL, t)
+ v0.AddArg(x)
+ v1 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+ v1.AddArg(y)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ v2 := b.NewValue0(v.Line, OpConst64, t)
+ v2.AuxInt = 0
+ v.AddArg(v2)
+ v3 := b.NewValue0(v.Line, OpARM64CMPconst, TypeFlags)
+ v3.AuxInt = 64
+ v4 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+ v4.AddArg(y)
+ v3.AddArg(v4)
+ v.AddArg(v3)
+ return true
+ }
+}
+func rewriteValueARM64_OpLsh16x64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Lsh16x64 x (MOVDconst [c]))
+ // cond: uint64(c) < 16
+ // result: (SLLconst x [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64MOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint64(c) < 16) {
+ break
+ }
+ v.reset(OpARM64SLLconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (Lsh16x64 _ (MOVDconst [c]))
+ // cond: uint64(c) >= 16
+ // result: (MOVDconst [0])
+ for {
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64MOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint64(c) >= 16) {
+ break
+ }
+ v.reset(OpARM64MOVDconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (Lsh16x64 <t> x y)
+ // cond:
+ // result: (CSELULT (SLL <t> x y) (Const64 <t> [0]) (CMPconst [64] y))
+ for {
+ t := v.Type
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64CSELULT)
+ v0 := b.NewValue0(v.Line, OpARM64SLL, t)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpConst64, t)
+ v1.AuxInt = 0
+ v.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpARM64CMPconst, TypeFlags)
+ v2.AuxInt = 64
+ v2.AddArg(y)
+ v.AddArg(v2)
+ return true
+ }
+}
+func rewriteValueARM64_OpLsh16x8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Lsh16x8 <t> x y)
+ // cond:
+ // result: (CSELULT (SLL <t> x (ZeroExt8to64 y)) (Const64 <t> [0]) (CMPconst [64] (ZeroExt8to64 y)))
+ for {
+ t := v.Type
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64CSELULT)
+ v0 := b.NewValue0(v.Line, OpARM64SLL, t)
+ v0.AddArg(x)
+ v1 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+ v1.AddArg(y)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ v2 := b.NewValue0(v.Line, OpConst64, t)
+ v2.AuxInt = 0
+ v.AddArg(v2)
+ v3 := b.NewValue0(v.Line, OpARM64CMPconst, TypeFlags)
+ v3.AuxInt = 64
+ v4 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+ v4.AddArg(y)
+ v3.AddArg(v4)
+ v.AddArg(v3)
+ return true
+ }
+}
+func rewriteValueARM64_OpLsh32x16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Lsh32x16 <t> x y)
+ // cond:
+ // result: (CSELULT (SLL <t> x (ZeroExt16to64 y)) (Const64 <t> [0]) (CMPconst [64] (ZeroExt16to64 y)))
+ for {
+ t := v.Type
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64CSELULT)
+ v0 := b.NewValue0(v.Line, OpARM64SLL, t)
+ v0.AddArg(x)
+ v1 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+ v1.AddArg(y)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ v2 := b.NewValue0(v.Line, OpConst64, t)
+ v2.AuxInt = 0
+ v.AddArg(v2)
+ v3 := b.NewValue0(v.Line, OpARM64CMPconst, TypeFlags)
+ v3.AuxInt = 64
+ v4 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+ v4.AddArg(y)
+ v3.AddArg(v4)
+ v.AddArg(v3)
+ return true
+ }
+}
+func rewriteValueARM64_OpLsh32x32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Lsh32x32 <t> x y)
+ // cond:
+ // result: (CSELULT (SLL <t> x (ZeroExt32to64 y)) (Const64 <t> [0]) (CMPconst [64] (ZeroExt32to64 y)))
+ for {
+ t := v.Type
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64CSELULT)
+ v0 := b.NewValue0(v.Line, OpARM64SLL, t)
+ v0.AddArg(x)
+ v1 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+ v1.AddArg(y)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ v2 := b.NewValue0(v.Line, OpConst64, t)
+ v2.AuxInt = 0
+ v.AddArg(v2)
+ v3 := b.NewValue0(v.Line, OpARM64CMPconst, TypeFlags)
+ v3.AuxInt = 64
+ v4 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+ v4.AddArg(y)
+ v3.AddArg(v4)
+ v.AddArg(v3)
+ return true
+ }
+}
+func rewriteValueARM64_OpLsh32x64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Lsh32x64 x (MOVDconst [c]))
+ // cond: uint64(c) < 32
+ // result: (SLLconst x [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64MOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint64(c) < 32) {
+ break
+ }
+ v.reset(OpARM64SLLconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (Lsh32x64 _ (MOVDconst [c]))
+ // cond: uint64(c) >= 32
+ // result: (MOVDconst [0])
+ for {
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64MOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint64(c) >= 32) {
+ break
+ }
+ v.reset(OpARM64MOVDconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (Lsh32x64 <t> x y)
+ // cond:
+ // result: (CSELULT (SLL <t> x y) (Const64 <t> [0]) (CMPconst [64] y))
+ for {
+ t := v.Type
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64CSELULT)
+ v0 := b.NewValue0(v.Line, OpARM64SLL, t)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpConst64, t)
+ v1.AuxInt = 0
+ v.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpARM64CMPconst, TypeFlags)
+ v2.AuxInt = 64
+ v2.AddArg(y)
+ v.AddArg(v2)
+ return true
+ }
+}
+func rewriteValueARM64_OpLsh32x8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Lsh32x8 <t> x y)
+ // cond:
+ // result: (CSELULT (SLL <t> x (ZeroExt8to64 y)) (Const64 <t> [0]) (CMPconst [64] (ZeroExt8to64 y)))
+ for {
+ t := v.Type
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64CSELULT)
+ v0 := b.NewValue0(v.Line, OpARM64SLL, t)
+ v0.AddArg(x)
+ v1 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+ v1.AddArg(y)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ v2 := b.NewValue0(v.Line, OpConst64, t)
+ v2.AuxInt = 0
+ v.AddArg(v2)
+ v3 := b.NewValue0(v.Line, OpARM64CMPconst, TypeFlags)
+ v3.AuxInt = 64
+ v4 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+ v4.AddArg(y)
+ v3.AddArg(v4)
+ v.AddArg(v3)
+ return true
+ }
+}
+func rewriteValueARM64_OpLsh64x16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Lsh64x16 <t> x y)
+ // cond:
+ // result: (CSELULT (SLL <t> x (ZeroExt16to64 y)) (Const64 <t> [0]) (CMPconst [64] (ZeroExt16to64 y)))
+ for {
+ t := v.Type
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64CSELULT)
+ v0 := b.NewValue0(v.Line, OpARM64SLL, t)
+ v0.AddArg(x)
+ v1 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+ v1.AddArg(y)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ v2 := b.NewValue0(v.Line, OpConst64, t)
+ v2.AuxInt = 0
+ v.AddArg(v2)
+ v3 := b.NewValue0(v.Line, OpARM64CMPconst, TypeFlags)
+ v3.AuxInt = 64
+ v4 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+ v4.AddArg(y)
+ v3.AddArg(v4)
+ v.AddArg(v3)
+ return true
+ }
+}
+func rewriteValueARM64_OpLsh64x32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Lsh64x32 <t> x y)
+ // cond:
+ // result: (CSELULT (SLL <t> x (ZeroExt32to64 y)) (Const64 <t> [0]) (CMPconst [64] (ZeroExt32to64 y)))
+ for {
+ t := v.Type
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64CSELULT)
+ v0 := b.NewValue0(v.Line, OpARM64SLL, t)
+ v0.AddArg(x)
+ v1 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+ v1.AddArg(y)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ v2 := b.NewValue0(v.Line, OpConst64, t)
+ v2.AuxInt = 0
+ v.AddArg(v2)
+ v3 := b.NewValue0(v.Line, OpARM64CMPconst, TypeFlags)
+ v3.AuxInt = 64
+ v4 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+ v4.AddArg(y)
+ v3.AddArg(v4)
+ v.AddArg(v3)
+ return true
+ }
+}
+func rewriteValueARM64_OpLsh64x64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Lsh64x64 x (MOVDconst [c]))
+ // cond: uint64(c) < 64
+ // result: (SLLconst x [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64MOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint64(c) < 64) {
+ break
+ }
+ v.reset(OpARM64SLLconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (Lsh64x64 _ (MOVDconst [c]))
+ // cond: uint64(c) >= 64
+ // result: (MOVDconst [0])
+ for {
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64MOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint64(c) >= 64) {
+ break
+ }
+ v.reset(OpARM64MOVDconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (Lsh64x64 <t> x y)
+ // cond:
+ // result: (CSELULT (SLL <t> x y) (Const64 <t> [0]) (CMPconst [64] y))
+ for {
+ t := v.Type
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64CSELULT)
+ v0 := b.NewValue0(v.Line, OpARM64SLL, t)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpConst64, t)
+ v1.AuxInt = 0
+ v.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpARM64CMPconst, TypeFlags)
+ v2.AuxInt = 64
+ v2.AddArg(y)
+ v.AddArg(v2)
+ return true
+ }
+}
+func rewriteValueARM64_OpLsh64x8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Lsh64x8 <t> x y)
+ // cond:
+ // result: (CSELULT (SLL <t> x (ZeroExt8to64 y)) (Const64 <t> [0]) (CMPconst [64] (ZeroExt8to64 y)))
+ for {
+ t := v.Type
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64CSELULT)
+ v0 := b.NewValue0(v.Line, OpARM64SLL, t)
+ v0.AddArg(x)
+ v1 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+ v1.AddArg(y)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ v2 := b.NewValue0(v.Line, OpConst64, t)
+ v2.AuxInt = 0
+ v.AddArg(v2)
+ v3 := b.NewValue0(v.Line, OpARM64CMPconst, TypeFlags)
+ v3.AuxInt = 64
+ v4 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+ v4.AddArg(y)
+ v3.AddArg(v4)
+ v.AddArg(v3)
+ return true
+ }
+}
+func rewriteValueARM64_OpLsh8x16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Lsh8x16 <t> x y)
+ // cond:
+ // result: (CSELULT (SLL <t> x (ZeroExt16to64 y)) (Const64 <t> [0]) (CMPconst [64] (ZeroExt16to64 y)))
+ for {
+ t := v.Type
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64CSELULT)
+ v0 := b.NewValue0(v.Line, OpARM64SLL, t)
+ v0.AddArg(x)
+ v1 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+ v1.AddArg(y)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ v2 := b.NewValue0(v.Line, OpConst64, t)
+ v2.AuxInt = 0
+ v.AddArg(v2)
+ v3 := b.NewValue0(v.Line, OpARM64CMPconst, TypeFlags)
+ v3.AuxInt = 64
+ v4 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+ v4.AddArg(y)
+ v3.AddArg(v4)
+ v.AddArg(v3)
+ return true
+ }
+}
+func rewriteValueARM64_OpLsh8x32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Lsh8x32 <t> x y)
+ // cond:
+ // result: (CSELULT (SLL <t> x (ZeroExt32to64 y)) (Const64 <t> [0]) (CMPconst [64] (ZeroExt32to64 y)))
+ for {
+ t := v.Type
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64CSELULT)
+ v0 := b.NewValue0(v.Line, OpARM64SLL, t)
+ v0.AddArg(x)
+ v1 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+ v1.AddArg(y)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ v2 := b.NewValue0(v.Line, OpConst64, t)
+ v2.AuxInt = 0
+ v.AddArg(v2)
+ v3 := b.NewValue0(v.Line, OpARM64CMPconst, TypeFlags)
+ v3.AuxInt = 64
+ v4 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+ v4.AddArg(y)
+ v3.AddArg(v4)
+ v.AddArg(v3)
+ return true
+ }
+}
+func rewriteValueARM64_OpLsh8x64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Lsh8x64 x (MOVDconst [c]))
+ // cond: uint64(c) < 8
+ // result: (SLLconst x [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64MOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint64(c) < 8) {
+ break
+ }
+ v.reset(OpARM64SLLconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (Lsh8x64 _ (MOVDconst [c]))
+ // cond: uint64(c) >= 8
+ // result: (MOVDconst [0])
+ for {
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64MOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint64(c) >= 8) {
+ break
+ }
+ v.reset(OpARM64MOVDconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (Lsh8x64 <t> x y)
+ // cond:
+ // result: (CSELULT (SLL <t> x y) (Const64 <t> [0]) (CMPconst [64] y))
+ for {
+ t := v.Type
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64CSELULT)
+ v0 := b.NewValue0(v.Line, OpARM64SLL, t)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpConst64, t)
+ v1.AuxInt = 0
+ v.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpARM64CMPconst, TypeFlags)
+ v2.AuxInt = 64
+ v2.AddArg(y)
+ v.AddArg(v2)
+ return true
+ }
+}
+func rewriteValueARM64_OpLsh8x8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Lsh8x8 <t> x y)
+ // cond:
+ // result: (CSELULT (SLL <t> x (ZeroExt8to64 y)) (Const64 <t> [0]) (CMPconst [64] (ZeroExt8to64 y)))
+ for {
+ t := v.Type
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64CSELULT)
+ v0 := b.NewValue0(v.Line, OpARM64SLL, t)
+ v0.AddArg(x)
+ v1 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+ v1.AddArg(y)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ v2 := b.NewValue0(v.Line, OpConst64, t)
+ v2.AuxInt = 0
+ v.AddArg(v2)
+ v3 := b.NewValue0(v.Line, OpARM64CMPconst, TypeFlags)
+ v3.AuxInt = 64
+ v4 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+ v4.AddArg(y)
+ v3.AddArg(v4)
+ v.AddArg(v3)
+ return true
+ }
+}
+func rewriteValueARM64_OpMod16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Mod16 x y)
+ // cond:
+ // result: (MODW (SignExt16to32 x) (SignExt16to32 y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64MODW)
+ v0 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
+ v1.AddArg(y)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueARM64_OpMod16u(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Mod16u x y)
+ // cond:
+ // result: (UMODW (ZeroExt16to32 x) (ZeroExt16to32 y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64UMODW)
+ v0 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+ v1.AddArg(y)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueARM64_OpMod32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Mod32 x y)
+ // cond:
+ // result: (MODW x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64MODW)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueARM64_OpMod32u(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Mod32u x y)
+ // cond:
+ // result: (UMODW x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64UMODW)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueARM64_OpMod64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Mod64 x y)
+ // cond:
+ // result: (MOD x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64MOD)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueARM64_OpMod64u(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Mod64u x y)
+ // cond:
+ // result: (UMOD x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64UMOD)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueARM64_OpMod8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Mod8 x y)
+ // cond:
+ // result: (MODW (SignExt8to32 x) (SignExt8to32 y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64MODW)
+ v0 := b.NewValue0(v.Line, OpSignExt8to32, config.fe.TypeInt32())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpSignExt8to32, config.fe.TypeInt32())
+ v1.AddArg(y)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueARM64_OpMod8u(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Mod8u x y)
+ // cond:
+ // result: (UMODW (ZeroExt8to32 x) (ZeroExt8to32 y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64UMODW)
+ v0 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+ v1.AddArg(y)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueARM64_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) {
+ 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 (MOVBUload src mem) mem)
+ for {
+ s := v.AuxInt
+ 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.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: (MOVHstore dst (MOVHUload src mem) mem)
+ for {
+ s := v.AuxInt
+ 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.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: (MOVWstore dst (MOVWUload src mem) mem)
+ for {
+ s := v.AuxInt
+ 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.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: (MOVDstore dst (MOVDload src mem) mem)
+ for {
+ s := v.AuxInt
+ 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.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 (MOVBUload [2] src mem) (MOVHstore dst (MOVHUload src mem) mem))
+ for {
+ s := v.AuxInt
+ 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.AuxInt = 2
+ v0.AddArg(src)
+ v0.AddArg(mem)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpARM64MOVHstore, TypeMem)
+ v1.AddArg(dst)
+ v2 := b.NewValue0(v.Line, OpARM64MOVHUload, config.fe.TypeUInt16())
+ v2.AddArg(src)
+ v2.AddArg(mem)
+ v1.AddArg(v2)
+ v1.AddArg(mem)
+ v.AddArg(v1)
+ return true
+ }
+ // match: (Move [s] dst src mem)
+ // cond: SizeAndAlign(s).Size() == 5
+ // result: (MOVBstore [4] dst (MOVBUload [4] src mem) (MOVWstore dst (MOVWUload src mem) mem))
+ for {
+ s := v.AuxInt
+ 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.AuxInt = 4
+ v0.AddArg(src)
+ v0.AddArg(mem)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpARM64MOVWstore, TypeMem)
+ v1.AddArg(dst)
+ v2 := b.NewValue0(v.Line, OpARM64MOVWUload, config.fe.TypeUInt32())
+ v2.AddArg(src)
+ v2.AddArg(mem)
+ v1.AddArg(v2)
+ v1.AddArg(mem)
+ v.AddArg(v1)
+ return true
+ }
+ // match: (Move [s] dst src mem)
+ // cond: SizeAndAlign(s).Size() == 6
+ // result: (MOVHstore [4] dst (MOVHUload [4] src mem) (MOVWstore dst (MOVWUload src mem) mem))
+ for {
+ s := v.AuxInt
+ 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.AuxInt = 4
+ v0.AddArg(src)
+ v0.AddArg(mem)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpARM64MOVWstore, TypeMem)
+ v1.AddArg(dst)
+ v2 := b.NewValue0(v.Line, OpARM64MOVWUload, config.fe.TypeUInt32())
+ v2.AddArg(src)
+ v2.AddArg(mem)
+ v1.AddArg(v2)
+ v1.AddArg(mem)
+ v.AddArg(v1)
+ return true
+ }
+ // match: (Move [s] dst src mem)
+ // cond: SizeAndAlign(s).Size() == 7
+ // 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
+ 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.AuxInt = 6
+ v0.AddArg(src)
+ v0.AddArg(mem)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpARM64MOVHstore, TypeMem)
+ v1.AuxInt = 4
+ v1.AddArg(dst)
+ v2 := b.NewValue0(v.Line, OpARM64MOVHUload, config.fe.TypeUInt16())
+ v2.AuxInt = 4
+ v2.AddArg(src)
+ v2.AddArg(mem)
+ v1.AddArg(v2)
+ v3 := b.NewValue0(v.Line, OpARM64MOVWstore, TypeMem)
+ v3.AddArg(dst)
+ v4 := b.NewValue0(v.Line, OpARM64MOVWUload, config.fe.TypeUInt32())
+ v4.AddArg(src)
+ v4.AddArg(mem)
+ v3.AddArg(v4)
+ v3.AddArg(mem)
+ v1.AddArg(v3)
+ v.AddArg(v1)
+ return true
+ }
+ // match: (Move [s] dst src mem)
+ // cond: SizeAndAlign(s).Size() == 12
+ // result: (MOVWstore [8] dst (MOVWUload [8] src mem) (MOVDstore dst (MOVDload src mem) mem))
+ for {
+ s := v.AuxInt
+ 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.AuxInt = 8
+ v0.AddArg(src)
+ v0.AddArg(mem)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpARM64MOVDstore, TypeMem)
+ v1.AddArg(dst)
+ v2 := b.NewValue0(v.Line, OpARM64MOVDload, config.fe.TypeUInt64())
+ v2.AddArg(src)
+ v2.AddArg(mem)
+ v1.AddArg(v2)
+ v1.AddArg(mem)
+ v.AddArg(v1)
+ return true
+ }
+ // match: (Move [s] dst src mem)
+ // cond: SizeAndAlign(s).Size() == 16
+ // result: (MOVDstore [8] dst (MOVDload [8] src mem) (MOVDstore dst (MOVDload src mem) mem))
+ for {
+ s := v.AuxInt
+ 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.AuxInt = 8
+ v0.AddArg(src)
+ v0.AddArg(mem)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpARM64MOVDstore, TypeMem)
+ v1.AddArg(dst)
+ v2 := b.NewValue0(v.Line, OpARM64MOVDload, config.fe.TypeUInt64())
+ v2.AddArg(src)
+ v2.AddArg(mem)
+ v1.AddArg(v2)
+ v1.AddArg(mem)
+ v.AddArg(v1)
+ return true
+ }
+ // match: (Move [s] dst src mem)
+ // cond: SizeAndAlign(s).Size() == 24
+ // 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
+ 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.AuxInt = 16
+ v0.AddArg(src)
+ v0.AddArg(mem)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpARM64MOVDstore, TypeMem)
+ v1.AuxInt = 8
+ v1.AddArg(dst)
+ v2 := b.NewValue0(v.Line, OpARM64MOVDload, config.fe.TypeUInt64())
+ v2.AuxInt = 8
+ v2.AddArg(src)
+ v2.AddArg(mem)
+ v1.AddArg(v2)
+ v3 := b.NewValue0(v.Line, OpARM64MOVDstore, TypeMem)
+ v3.AddArg(dst)
+ v4 := b.NewValue0(v.Line, OpARM64MOVDload, config.fe.TypeUInt64())
+ v4.AddArg(src)
+ v4.AddArg(mem)
+ v3.AddArg(v4)
+ v3.AddArg(mem)
+ v1.AddArg(v3)
+ v.AddArg(v1)
+ 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))
+ for {
+ s := v.AuxInt
+ dst := v.Args[0]
+ src := v.Args[1]
+ mem := v.Args[2]
+ if !(SizeAndAlign(s).Size()%8 != 0 && SizeAndAlign(s).Size() > 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
+ v0.AddArg(dst)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpOffPtr, src.Type)
+ v1.AuxInt = SizeAndAlign(s).Size() - SizeAndAlign(s).Size()%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.AddArg(dst)
+ v2.AddArg(src)
+ v2.AddArg(mem)
+ v.AddArg(v2)
+ 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)
+ for {
+ s := v.AuxInt
+ 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) {
+ break
+ }
+ v.reset(OpARM64DUFFCOPY)
+ v.AuxInt = 8 * (128 - int64(SizeAndAlign(s).Size()/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)
+ for {
+ s := v.AuxInt
+ dst := v.Args[0]
+ src := v.Args[1]
+ mem := v.Args[2]
+ if !(SizeAndAlign(s).Size() > 24 && SizeAndAlign(s).Size()%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.AddArg(src)
+ v.AddArg(v0)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValueARM64_OpMul16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Mul16 x y)
+ // cond:
+ // result: (MULW x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64MULW)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueARM64_OpMul32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Mul32 x y)
+ // cond:
+ // result: (MULW x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64MULW)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueARM64_OpMul32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Mul32F x y)
+ // cond:
+ // result: (FMULS x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64FMULS)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueARM64_OpMul64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Mul64 x y)
+ // cond:
+ // result: (MUL x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64MUL)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueARM64_OpMul64F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Mul64F x y)
+ // cond:
+ // result: (FMULD x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64FMULD)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueARM64_OpMul8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Mul8 x y)
+ // cond:
+ // result: (MULW x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64MULW)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueARM64_OpNeg16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Neg16 x)
+ // cond:
+ // result: (NEG x)
+ for {
+ x := v.Args[0]
+ v.reset(OpARM64NEG)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueARM64_OpNeg32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Neg32 x)
+ // cond:
+ // result: (NEG x)
+ for {
+ x := v.Args[0]
+ v.reset(OpARM64NEG)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueARM64_OpNeg32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Neg32F x)
+ // cond:
+ // result: (FNEGS x)
+ for {
+ x := v.Args[0]
+ v.reset(OpARM64FNEGS)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueARM64_OpNeg64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Neg64 x)
+ // cond:
+ // result: (NEG x)
+ for {
+ x := v.Args[0]
+ v.reset(OpARM64NEG)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueARM64_OpNeg64F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Neg64F x)
+ // cond:
+ // result: (FNEGD x)
+ for {
+ x := v.Args[0]
+ v.reset(OpARM64FNEGD)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueARM64_OpNeg8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Neg8 x)
+ // cond:
+ // result: (NEG x)
+ for {
+ x := v.Args[0]
+ v.reset(OpARM64NEG)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueARM64_OpNeq16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Neq16 x y)
+ // cond:
+ // result: (NotEqual (CMPW (ZeroExt16to32 x) (ZeroExt16to32 y)))
+ for {
+ 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())
+ 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 rewriteValueARM64_OpNeq32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Neq32 x y)
+ // cond:
+ // result: (NotEqual (CMPW x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64NotEqual)
+ v0 := b.NewValue0(v.Line, OpARM64CMPW, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueARM64_OpNeq32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Neq32F x y)
+ // cond:
+ // result: (NotEqual (FCMPS x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64NotEqual)
+ v0 := b.NewValue0(v.Line, OpARM64FCMPS, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueARM64_OpNeq64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Neq64 x y)
+ // cond:
+ // result: (NotEqual (CMP x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64NotEqual)
+ v0 := b.NewValue0(v.Line, OpARM64CMP, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueARM64_OpNeq64F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Neq64F x y)
+ // cond:
+ // result: (NotEqual (FCMPD x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64NotEqual)
+ v0 := b.NewValue0(v.Line, OpARM64FCMPD, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueARM64_OpNeq8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Neq8 x y)
+ // cond:
+ // result: (NotEqual (CMPW (ZeroExt8to32 x) (ZeroExt8to32 y)))
+ for {
+ 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())
+ 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_OpNeqB(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (NeqB x y)
+ // cond:
+ // result: (XOR x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64XOR)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueARM64_OpNeqPtr(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (NeqPtr x y)
+ // cond:
+ // result: (NotEqual (CMP x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64NotEqual)
+ v0 := b.NewValue0(v.Line, OpARM64CMP, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueARM64_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(OpARM64LoweredNilCheck)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+}
+func rewriteValueARM64_OpNot(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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.AuxInt = 1
+ v.AddArg(v0)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueARM64_OpOffPtr(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (OffPtr [off] ptr:(SP))
+ // cond:
+ // result: (MOVDaddr [off] ptr)
+ for {
+ off := v.AuxInt
+ ptr := v.Args[0]
+ if ptr.Op != OpSP {
+ break
+ }
+ v.reset(OpARM64MOVDaddr)
+ v.AuxInt = off
+ v.AddArg(ptr)
+ return true
+ }
+ // match: (OffPtr [off] ptr)
+ // cond:
+ // result: (ADDconst [off] ptr)
+ for {
+ off := v.AuxInt
+ ptr := v.Args[0]
+ v.reset(OpARM64ADDconst)
+ v.AuxInt = off
+ v.AddArg(ptr)
+ return true
+ }
+}
+func rewriteValueARM64_OpOr16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Or16 x y)
+ // cond:
+ // result: (OR x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64OR)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueARM64_OpOr32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Or32 x y)
+ // cond:
+ // result: (OR x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64OR)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueARM64_OpOr64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Or64 x y)
+ // cond:
+ // result: (OR x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64OR)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueARM64_OpOr8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Or8 x y)
+ // cond:
+ // result: (OR x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64OR)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueARM64_OpOrB(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (OrB x y)
+ // cond:
+ // result: (OR x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64OR)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueARM64_OpRsh16Ux16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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
+ 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())
+ v1.AddArg(x)
+ v0.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+ v2.AddArg(y)
+ v0.AddArg(v2)
+ v.AddArg(v0)
+ v3 := b.NewValue0(v.Line, OpConst64, t)
+ v3.AuxInt = 0
+ v.AddArg(v3)
+ v4 := b.NewValue0(v.Line, OpARM64CMPconst, TypeFlags)
+ v4.AuxInt = 64
+ v5 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+ v5.AddArg(y)
+ v4.AddArg(v5)
+ v.AddArg(v4)
+ return true
+ }
+}
+func rewriteValueARM64_OpRsh16Ux32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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
+ 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())
+ v1.AddArg(x)
+ v0.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+ v2.AddArg(y)
+ v0.AddArg(v2)
+ v.AddArg(v0)
+ v3 := b.NewValue0(v.Line, OpConst64, t)
+ v3.AuxInt = 0
+ v.AddArg(v3)
+ v4 := b.NewValue0(v.Line, OpARM64CMPconst, TypeFlags)
+ v4.AuxInt = 64
+ v5 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+ v5.AddArg(y)
+ v4.AddArg(v5)
+ v.AddArg(v4)
+ return true
+ }
+}
+func rewriteValueARM64_OpRsh16Ux64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh16Ux64 x (MOVDconst [c]))
+ // cond: uint64(c) < 16
+ // result: (SRLconst (ZeroExt16to64 x) [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64MOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint64(c) < 16) {
+ break
+ }
+ v.reset(OpARM64SRLconst)
+ v.AuxInt = c
+ v0 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (Rsh16Ux64 _ (MOVDconst [c]))
+ // cond: uint64(c) >= 16
+ // result: (MOVDconst [0])
+ for {
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64MOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint64(c) >= 16) {
+ break
+ }
+ v.reset(OpARM64MOVDconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (Rsh16Ux64 <t> x y)
+ // cond:
+ // result: (CSELULT (SRL <t> (ZeroExt16to64 x) y) (Const64 <t> [0]) (CMPconst [64] y))
+ for {
+ t := v.Type
+ 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())
+ v1.AddArg(x)
+ v0.AddArg(v1)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ v2 := b.NewValue0(v.Line, OpConst64, t)
+ v2.AuxInt = 0
+ v.AddArg(v2)
+ v3 := b.NewValue0(v.Line, OpARM64CMPconst, TypeFlags)
+ v3.AuxInt = 64
+ v3.AddArg(y)
+ v.AddArg(v3)
+ return true
+ }
+}
+func rewriteValueARM64_OpRsh16Ux8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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
+ 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())
+ v1.AddArg(x)
+ v0.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+ v2.AddArg(y)
+ v0.AddArg(v2)
+ v.AddArg(v0)
+ v3 := b.NewValue0(v.Line, OpConst64, t)
+ v3.AuxInt = 0
+ v.AddArg(v3)
+ v4 := b.NewValue0(v.Line, OpARM64CMPconst, TypeFlags)
+ v4.AuxInt = 64
+ v5 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+ v5.AddArg(y)
+ v4.AddArg(v5)
+ v.AddArg(v4)
+ return true
+ }
+}
+func rewriteValueARM64_OpRsh16x16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh16x16 x y)
+ // cond:
+ // result: (SRA (SignExt16to64 x) (CSELULT <y.Type> (ZeroExt16to64 y) (Const64 <y.Type> [63]) (CMPconst [64] (ZeroExt16to64 y))))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64SRA)
+ v0 := b.NewValue0(v.Line, OpSignExt16to64, config.fe.TypeInt64())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpARM64CSELULT, y.Type)
+ v2 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+ v2.AddArg(y)
+ v1.AddArg(v2)
+ v3 := b.NewValue0(v.Line, OpConst64, y.Type)
+ v3.AuxInt = 63
+ v1.AddArg(v3)
+ v4 := b.NewValue0(v.Line, OpARM64CMPconst, TypeFlags)
+ v4.AuxInt = 64
+ v5 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+ v5.AddArg(y)
+ v4.AddArg(v5)
+ v1.AddArg(v4)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueARM64_OpRsh16x32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh16x32 x y)
+ // cond:
+ // result: (SRA (SignExt16to64 x) (CSELULT <y.Type> (ZeroExt32to64 y) (Const64 <y.Type> [63]) (CMPconst [64] (ZeroExt32to64 y))))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64SRA)
+ v0 := b.NewValue0(v.Line, OpSignExt16to64, config.fe.TypeInt64())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpARM64CSELULT, y.Type)
+ v2 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+ v2.AddArg(y)
+ v1.AddArg(v2)
+ v3 := b.NewValue0(v.Line, OpConst64, y.Type)
+ v3.AuxInt = 63
+ v1.AddArg(v3)
+ v4 := b.NewValue0(v.Line, OpARM64CMPconst, TypeFlags)
+ v4.AuxInt = 64
+ v5 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+ v5.AddArg(y)
+ v4.AddArg(v5)
+ v1.AddArg(v4)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueARM64_OpRsh16x64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh16x64 x (MOVDconst [c]))
+ // cond: uint64(c) < 16
+ // result: (SRAconst (SignExt16to64 x) [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64MOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint64(c) < 16) {
+ break
+ }
+ v.reset(OpARM64SRAconst)
+ v.AuxInt = c
+ v0 := b.NewValue0(v.Line, OpSignExt16to64, config.fe.TypeInt64())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (Rsh16x64 x (MOVDconst [c]))
+ // cond: uint64(c) >= 16
+ // result: (SRAconst (SignExt16to64 x) [63])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64MOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint64(c) >= 16) {
+ break
+ }
+ v.reset(OpARM64SRAconst)
+ v.AuxInt = 63
+ v0 := b.NewValue0(v.Line, OpSignExt16to64, config.fe.TypeInt64())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (Rsh16x64 x y)
+ // cond:
+ // result: (SRA (SignExt16to64 x) (CSELULT <y.Type> y (Const64 <y.Type> [63]) (CMPconst [64] y)))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64SRA)
+ v0 := b.NewValue0(v.Line, OpSignExt16to64, config.fe.TypeInt64())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpARM64CSELULT, y.Type)
+ v1.AddArg(y)
+ v2 := b.NewValue0(v.Line, OpConst64, y.Type)
+ v2.AuxInt = 63
+ v1.AddArg(v2)
+ v3 := b.NewValue0(v.Line, OpARM64CMPconst, TypeFlags)
+ v3.AuxInt = 64
+ v3.AddArg(y)
+ v1.AddArg(v3)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueARM64_OpRsh16x8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh16x8 x y)
+ // cond:
+ // result: (SRA (SignExt16to64 x) (CSELULT <y.Type> (ZeroExt8to64 y) (Const64 <y.Type> [63]) (CMPconst [64] (ZeroExt8to64 y))))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64SRA)
+ v0 := b.NewValue0(v.Line, OpSignExt16to64, config.fe.TypeInt64())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpARM64CSELULT, y.Type)
+ v2 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+ v2.AddArg(y)
+ v1.AddArg(v2)
+ v3 := b.NewValue0(v.Line, OpConst64, y.Type)
+ v3.AuxInt = 63
+ v1.AddArg(v3)
+ v4 := b.NewValue0(v.Line, OpARM64CMPconst, TypeFlags)
+ v4.AuxInt = 64
+ v5 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+ v5.AddArg(y)
+ v4.AddArg(v5)
+ v1.AddArg(v4)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueARM64_OpRsh32Ux16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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
+ 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())
+ v1.AddArg(x)
+ v0.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+ v2.AddArg(y)
+ v0.AddArg(v2)
+ v.AddArg(v0)
+ v3 := b.NewValue0(v.Line, OpConst64, t)
+ v3.AuxInt = 0
+ v.AddArg(v3)
+ v4 := b.NewValue0(v.Line, OpARM64CMPconst, TypeFlags)
+ v4.AuxInt = 64
+ v5 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+ v5.AddArg(y)
+ v4.AddArg(v5)
+ v.AddArg(v4)
+ return true
+ }
+}
+func rewriteValueARM64_OpRsh32Ux32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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
+ 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())
+ v1.AddArg(x)
+ v0.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+ v2.AddArg(y)
+ v0.AddArg(v2)
+ v.AddArg(v0)
+ v3 := b.NewValue0(v.Line, OpConst64, t)
+ v3.AuxInt = 0
+ v.AddArg(v3)
+ v4 := b.NewValue0(v.Line, OpARM64CMPconst, TypeFlags)
+ v4.AuxInt = 64
+ v5 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+ v5.AddArg(y)
+ v4.AddArg(v5)
+ v.AddArg(v4)
+ return true
+ }
+}
+func rewriteValueARM64_OpRsh32Ux64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh32Ux64 x (MOVDconst [c]))
+ // cond: uint64(c) < 32
+ // result: (SRLconst (ZeroExt32to64 x) [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64MOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint64(c) < 32) {
+ break
+ }
+ v.reset(OpARM64SRLconst)
+ v.AuxInt = c
+ v0 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (Rsh32Ux64 _ (MOVDconst [c]))
+ // cond: uint64(c) >= 32
+ // result: (MOVDconst [0])
+ for {
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64MOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint64(c) >= 32) {
+ break
+ }
+ v.reset(OpARM64MOVDconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (Rsh32Ux64 <t> x y)
+ // cond:
+ // result: (CSELULT (SRL <t> (ZeroExt32to64 x) y) (Const64 <t> [0]) (CMPconst [64] y))
+ for {
+ t := v.Type
+ 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())
+ v1.AddArg(x)
+ v0.AddArg(v1)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ v2 := b.NewValue0(v.Line, OpConst64, t)
+ v2.AuxInt = 0
+ v.AddArg(v2)
+ v3 := b.NewValue0(v.Line, OpARM64CMPconst, TypeFlags)
+ v3.AuxInt = 64
+ v3.AddArg(y)
+ v.AddArg(v3)
+ return true
+ }
+}
+func rewriteValueARM64_OpRsh32Ux8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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
+ 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())
+ v1.AddArg(x)
+ v0.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+ v2.AddArg(y)
+ v0.AddArg(v2)
+ v.AddArg(v0)
+ v3 := b.NewValue0(v.Line, OpConst64, t)
+ v3.AuxInt = 0
+ v.AddArg(v3)
+ v4 := b.NewValue0(v.Line, OpARM64CMPconst, TypeFlags)
+ v4.AuxInt = 64
+ v5 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+ v5.AddArg(y)
+ v4.AddArg(v5)
+ v.AddArg(v4)
+ return true
+ }
+}
+func rewriteValueARM64_OpRsh32x16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh32x16 x y)
+ // cond:
+ // result: (SRA (SignExt32to64 x) (CSELULT <y.Type> (ZeroExt16to64 y) (Const64 <y.Type> [63]) (CMPconst [64] (ZeroExt16to64 y))))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64SRA)
+ v0 := b.NewValue0(v.Line, OpSignExt32to64, config.fe.TypeInt64())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpARM64CSELULT, y.Type)
+ v2 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+ v2.AddArg(y)
+ v1.AddArg(v2)
+ v3 := b.NewValue0(v.Line, OpConst64, y.Type)
+ v3.AuxInt = 63
+ v1.AddArg(v3)
+ v4 := b.NewValue0(v.Line, OpARM64CMPconst, TypeFlags)
+ v4.AuxInt = 64
+ v5 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+ v5.AddArg(y)
+ v4.AddArg(v5)
+ v1.AddArg(v4)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueARM64_OpRsh32x32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh32x32 x y)
+ // cond:
+ // result: (SRA (SignExt32to64 x) (CSELULT <y.Type> (ZeroExt32to64 y) (Const64 <y.Type> [63]) (CMPconst [64] (ZeroExt32to64 y))))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64SRA)
+ v0 := b.NewValue0(v.Line, OpSignExt32to64, config.fe.TypeInt64())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpARM64CSELULT, y.Type)
+ v2 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+ v2.AddArg(y)
+ v1.AddArg(v2)
+ v3 := b.NewValue0(v.Line, OpConst64, y.Type)
+ v3.AuxInt = 63
+ v1.AddArg(v3)
+ v4 := b.NewValue0(v.Line, OpARM64CMPconst, TypeFlags)
+ v4.AuxInt = 64
+ v5 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+ v5.AddArg(y)
+ v4.AddArg(v5)
+ v1.AddArg(v4)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueARM64_OpRsh32x64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh32x64 x (MOVDconst [c]))
+ // cond: uint64(c) < 32
+ // result: (SRAconst (SignExt32to64 x) [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64MOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint64(c) < 32) {
+ break
+ }
+ v.reset(OpARM64SRAconst)
+ v.AuxInt = c
+ v0 := b.NewValue0(v.Line, OpSignExt32to64, config.fe.TypeInt64())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (Rsh32x64 x (MOVDconst [c]))
+ // cond: uint64(c) >= 32
+ // result: (SRAconst (SignExt32to64 x) [63])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64MOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint64(c) >= 32) {
+ break
+ }
+ v.reset(OpARM64SRAconst)
+ v.AuxInt = 63
+ v0 := b.NewValue0(v.Line, OpSignExt32to64, config.fe.TypeInt64())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (Rsh32x64 x y)
+ // cond:
+ // result: (SRA (SignExt32to64 x) (CSELULT <y.Type> y (Const64 <y.Type> [63]) (CMPconst [64] y)))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64SRA)
+ v0 := b.NewValue0(v.Line, OpSignExt32to64, config.fe.TypeInt64())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpARM64CSELULT, y.Type)
+ v1.AddArg(y)
+ v2 := b.NewValue0(v.Line, OpConst64, y.Type)
+ v2.AuxInt = 63
+ v1.AddArg(v2)
+ v3 := b.NewValue0(v.Line, OpARM64CMPconst, TypeFlags)
+ v3.AuxInt = 64
+ v3.AddArg(y)
+ v1.AddArg(v3)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueARM64_OpRsh32x8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh32x8 x y)
+ // cond:
+ // result: (SRA (SignExt32to64 x) (CSELULT <y.Type> (ZeroExt8to64 y) (Const64 <y.Type> [63]) (CMPconst [64] (ZeroExt8to64 y))))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64SRA)
+ v0 := b.NewValue0(v.Line, OpSignExt32to64, config.fe.TypeInt64())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpARM64CSELULT, y.Type)
+ v2 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+ v2.AddArg(y)
+ v1.AddArg(v2)
+ v3 := b.NewValue0(v.Line, OpConst64, y.Type)
+ v3.AuxInt = 63
+ v1.AddArg(v3)
+ v4 := b.NewValue0(v.Line, OpARM64CMPconst, TypeFlags)
+ v4.AuxInt = 64
+ v5 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+ v5.AddArg(y)
+ v4.AddArg(v5)
+ v1.AddArg(v4)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueARM64_OpRsh64Ux16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh64Ux16 <t> x y)
+ // cond:
+ // result: (CSELULT (SRL <t> x (ZeroExt16to64 y)) (Const64 <t> [0]) (CMPconst [64] (ZeroExt16to64 y)))
+ for {
+ t := v.Type
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64CSELULT)
+ v0 := b.NewValue0(v.Line, OpARM64SRL, t)
+ v0.AddArg(x)
+ v1 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+ v1.AddArg(y)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ v2 := b.NewValue0(v.Line, OpConst64, t)
+ v2.AuxInt = 0
+ v.AddArg(v2)
+ v3 := b.NewValue0(v.Line, OpARM64CMPconst, TypeFlags)
+ v3.AuxInt = 64
+ v4 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+ v4.AddArg(y)
+ v3.AddArg(v4)
+ v.AddArg(v3)
+ return true
+ }
+}
+func rewriteValueARM64_OpRsh64Ux32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh64Ux32 <t> x y)
+ // cond:
+ // result: (CSELULT (SRL <t> x (ZeroExt32to64 y)) (Const64 <t> [0]) (CMPconst [64] (ZeroExt32to64 y)))
+ for {
+ t := v.Type
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64CSELULT)
+ v0 := b.NewValue0(v.Line, OpARM64SRL, t)
+ v0.AddArg(x)
+ v1 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+ v1.AddArg(y)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ v2 := b.NewValue0(v.Line, OpConst64, t)
+ v2.AuxInt = 0
+ v.AddArg(v2)
+ v3 := b.NewValue0(v.Line, OpARM64CMPconst, TypeFlags)
+ v3.AuxInt = 64
+ v4 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+ v4.AddArg(y)
+ v3.AddArg(v4)
+ v.AddArg(v3)
+ return true
+ }
+}
+func rewriteValueARM64_OpRsh64Ux64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh64Ux64 x (MOVDconst [c]))
+ // cond: uint64(c) < 64
+ // result: (SRLconst x [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64MOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint64(c) < 64) {
+ break
+ }
+ v.reset(OpARM64SRLconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (Rsh64Ux64 _ (MOVDconst [c]))
+ // cond: uint64(c) >= 64
+ // result: (MOVDconst [0])
+ for {
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64MOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint64(c) >= 64) {
+ break
+ }
+ v.reset(OpARM64MOVDconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (Rsh64Ux64 <t> x y)
+ // cond:
+ // result: (CSELULT (SRL <t> x y) (Const64 <t> [0]) (CMPconst [64] y))
+ for {
+ t := v.Type
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64CSELULT)
+ v0 := b.NewValue0(v.Line, OpARM64SRL, t)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpConst64, t)
+ v1.AuxInt = 0
+ v.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpARM64CMPconst, TypeFlags)
+ v2.AuxInt = 64
+ v2.AddArg(y)
+ v.AddArg(v2)
+ return true
+ }
+}
+func rewriteValueARM64_OpRsh64Ux8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh64Ux8 <t> x y)
+ // cond:
+ // result: (CSELULT (SRL <t> x (ZeroExt8to64 y)) (Const64 <t> [0]) (CMPconst [64] (ZeroExt8to64 y)))
+ for {
+ t := v.Type
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64CSELULT)
+ v0 := b.NewValue0(v.Line, OpARM64SRL, t)
+ v0.AddArg(x)
+ v1 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+ v1.AddArg(y)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ v2 := b.NewValue0(v.Line, OpConst64, t)
+ v2.AuxInt = 0
+ v.AddArg(v2)
+ v3 := b.NewValue0(v.Line, OpARM64CMPconst, TypeFlags)
+ v3.AuxInt = 64
+ v4 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+ v4.AddArg(y)
+ v3.AddArg(v4)
+ v.AddArg(v3)
+ return true
+ }
+}
+func rewriteValueARM64_OpRsh64x16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh64x16 x y)
+ // cond:
+ // result: (SRA x (CSELULT <y.Type> (ZeroExt16to64 y) (Const64 <y.Type> [63]) (CMPconst [64] (ZeroExt16to64 y))))
+ for {
+ 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())
+ v1.AddArg(y)
+ v0.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpConst64, y.Type)
+ v2.AuxInt = 63
+ v0.AddArg(v2)
+ v3 := b.NewValue0(v.Line, OpARM64CMPconst, TypeFlags)
+ v3.AuxInt = 64
+ v4 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+ v4.AddArg(y)
+ v3.AddArg(v4)
+ v0.AddArg(v3)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueARM64_OpRsh64x32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh64x32 x y)
+ // cond:
+ // result: (SRA x (CSELULT <y.Type> (ZeroExt32to64 y) (Const64 <y.Type> [63]) (CMPconst [64] (ZeroExt32to64 y))))
+ for {
+ 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())
+ v1.AddArg(y)
+ v0.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpConst64, y.Type)
+ v2.AuxInt = 63
+ v0.AddArg(v2)
+ v3 := b.NewValue0(v.Line, OpARM64CMPconst, TypeFlags)
+ v3.AuxInt = 64
+ v4 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+ v4.AddArg(y)
+ v3.AddArg(v4)
+ v0.AddArg(v3)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueARM64_OpRsh64x64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh64x64 x (MOVDconst [c]))
+ // cond: uint64(c) < 64
+ // result: (SRAconst x [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64MOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint64(c) < 64) {
+ break
+ }
+ v.reset(OpARM64SRAconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (Rsh64x64 x (MOVDconst [c]))
+ // cond: uint64(c) >= 64
+ // result: (SRAconst x [63])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64MOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint64(c) >= 64) {
+ break
+ }
+ v.reset(OpARM64SRAconst)
+ v.AuxInt = 63
+ v.AddArg(x)
+ return true
+ }
+ // match: (Rsh64x64 x y)
+ // cond:
+ // result: (SRA x (CSELULT <y.Type> y (Const64 <y.Type> [63]) (CMPconst [64] y)))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64SRA)
+ v.AddArg(x)
+ v0 := b.NewValue0(v.Line, OpARM64CSELULT, y.Type)
+ v0.AddArg(y)
+ v1 := b.NewValue0(v.Line, OpConst64, y.Type)
+ v1.AuxInt = 63
+ v0.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpARM64CMPconst, TypeFlags)
+ v2.AuxInt = 64
+ v2.AddArg(y)
+ v0.AddArg(v2)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueARM64_OpRsh64x8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh64x8 x y)
+ // cond:
+ // result: (SRA x (CSELULT <y.Type> (ZeroExt8to64 y) (Const64 <y.Type> [63]) (CMPconst [64] (ZeroExt8to64 y))))
+ for {
+ 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())
+ v1.AddArg(y)
+ v0.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpConst64, y.Type)
+ v2.AuxInt = 63
+ v0.AddArg(v2)
+ v3 := b.NewValue0(v.Line, OpARM64CMPconst, TypeFlags)
+ v3.AuxInt = 64
+ v4 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+ v4.AddArg(y)
+ v3.AddArg(v4)
+ v0.AddArg(v3)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueARM64_OpRsh8Ux16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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
+ 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())
+ v1.AddArg(x)
+ v0.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+ v2.AddArg(y)
+ v0.AddArg(v2)
+ v.AddArg(v0)
+ v3 := b.NewValue0(v.Line, OpConst64, t)
+ v3.AuxInt = 0
+ v.AddArg(v3)
+ v4 := b.NewValue0(v.Line, OpARM64CMPconst, TypeFlags)
+ v4.AuxInt = 64
+ v5 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+ v5.AddArg(y)
+ v4.AddArg(v5)
+ v.AddArg(v4)
+ return true
+ }
+}
+func rewriteValueARM64_OpRsh8Ux32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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
+ 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())
+ v1.AddArg(x)
+ v0.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+ v2.AddArg(y)
+ v0.AddArg(v2)
+ v.AddArg(v0)
+ v3 := b.NewValue0(v.Line, OpConst64, t)
+ v3.AuxInt = 0
+ v.AddArg(v3)
+ v4 := b.NewValue0(v.Line, OpARM64CMPconst, TypeFlags)
+ v4.AuxInt = 64
+ v5 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+ v5.AddArg(y)
+ v4.AddArg(v5)
+ v.AddArg(v4)
+ return true
+ }
+}
+func rewriteValueARM64_OpRsh8Ux64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh8Ux64 x (MOVDconst [c]))
+ // cond: uint64(c) < 8
+ // result: (SRLconst (ZeroExt8to64 x) [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64MOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint64(c) < 8) {
+ break
+ }
+ v.reset(OpARM64SRLconst)
+ v.AuxInt = c
+ v0 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (Rsh8Ux64 _ (MOVDconst [c]))
+ // cond: uint64(c) >= 8
+ // result: (MOVDconst [0])
+ for {
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64MOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint64(c) >= 8) {
+ break
+ }
+ v.reset(OpARM64MOVDconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (Rsh8Ux64 <t> x y)
+ // cond:
+ // result: (CSELULT (SRL <t> (ZeroExt8to64 x) y) (Const64 <t> [0]) (CMPconst [64] y))
+ for {
+ t := v.Type
+ 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())
+ v1.AddArg(x)
+ v0.AddArg(v1)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ v2 := b.NewValue0(v.Line, OpConst64, t)
+ v2.AuxInt = 0
+ v.AddArg(v2)
+ v3 := b.NewValue0(v.Line, OpARM64CMPconst, TypeFlags)
+ v3.AuxInt = 64
+ v3.AddArg(y)
+ v.AddArg(v3)
+ return true
+ }
+}
+func rewriteValueARM64_OpRsh8Ux8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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
+ 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())
+ v1.AddArg(x)
+ v0.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+ v2.AddArg(y)
+ v0.AddArg(v2)
+ v.AddArg(v0)
+ v3 := b.NewValue0(v.Line, OpConst64, t)
+ v3.AuxInt = 0
+ v.AddArg(v3)
+ v4 := b.NewValue0(v.Line, OpARM64CMPconst, TypeFlags)
+ v4.AuxInt = 64
+ v5 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+ v5.AddArg(y)
+ v4.AddArg(v5)
+ v.AddArg(v4)
+ return true
+ }
+}
+func rewriteValueARM64_OpRsh8x16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh8x16 x y)
+ // cond:
+ // result: (SRA (SignExt8to64 x) (CSELULT <y.Type> (ZeroExt16to64 y) (Const64 <y.Type> [63]) (CMPconst [64] (ZeroExt16to64 y))))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64SRA)
+ v0 := b.NewValue0(v.Line, OpSignExt8to64, config.fe.TypeInt64())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpARM64CSELULT, y.Type)
+ v2 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+ v2.AddArg(y)
+ v1.AddArg(v2)
+ v3 := b.NewValue0(v.Line, OpConst64, y.Type)
+ v3.AuxInt = 63
+ v1.AddArg(v3)
+ v4 := b.NewValue0(v.Line, OpARM64CMPconst, TypeFlags)
+ v4.AuxInt = 64
+ v5 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+ v5.AddArg(y)
+ v4.AddArg(v5)
+ v1.AddArg(v4)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueARM64_OpRsh8x32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh8x32 x y)
+ // cond:
+ // result: (SRA (SignExt8to64 x) (CSELULT <y.Type> (ZeroExt32to64 y) (Const64 <y.Type> [63]) (CMPconst [64] (ZeroExt32to64 y))))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64SRA)
+ v0 := b.NewValue0(v.Line, OpSignExt8to64, config.fe.TypeInt64())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpARM64CSELULT, y.Type)
+ v2 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+ v2.AddArg(y)
+ v1.AddArg(v2)
+ v3 := b.NewValue0(v.Line, OpConst64, y.Type)
+ v3.AuxInt = 63
+ v1.AddArg(v3)
+ v4 := b.NewValue0(v.Line, OpARM64CMPconst, TypeFlags)
+ v4.AuxInt = 64
+ v5 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+ v5.AddArg(y)
+ v4.AddArg(v5)
+ v1.AddArg(v4)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueARM64_OpRsh8x64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh8x64 x (MOVDconst [c]))
+ // cond: uint64(c) < 8
+ // result: (SRAconst (SignExt8to64 x) [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64MOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint64(c) < 8) {
+ break
+ }
+ v.reset(OpARM64SRAconst)
+ v.AuxInt = c
+ v0 := b.NewValue0(v.Line, OpSignExt8to64, config.fe.TypeInt64())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (Rsh8x64 x (MOVDconst [c]))
+ // cond: uint64(c) >= 8
+ // result: (SRAconst (SignExt8to64 x) [63])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpARM64MOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint64(c) >= 8) {
+ break
+ }
+ v.reset(OpARM64SRAconst)
+ v.AuxInt = 63
+ v0 := b.NewValue0(v.Line, OpSignExt8to64, config.fe.TypeInt64())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (Rsh8x64 x y)
+ // cond:
+ // result: (SRA (SignExt8to64 x) (CSELULT <y.Type> y (Const64 <y.Type> [63]) (CMPconst [64] y)))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64SRA)
+ v0 := b.NewValue0(v.Line, OpSignExt8to64, config.fe.TypeInt64())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpARM64CSELULT, y.Type)
+ v1.AddArg(y)
+ v2 := b.NewValue0(v.Line, OpConst64, y.Type)
+ v2.AuxInt = 63
+ v1.AddArg(v2)
+ v3 := b.NewValue0(v.Line, OpARM64CMPconst, TypeFlags)
+ v3.AuxInt = 64
+ v3.AddArg(y)
+ v1.AddArg(v3)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueARM64_OpRsh8x8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh8x8 x y)
+ // cond:
+ // result: (SRA (SignExt8to64 x) (CSELULT <y.Type> (ZeroExt8to64 y) (Const64 <y.Type> [63]) (CMPconst [64] (ZeroExt8to64 y))))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64SRA)
+ v0 := b.NewValue0(v.Line, OpSignExt8to64, config.fe.TypeInt64())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpARM64CSELULT, y.Type)
+ v2 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+ v2.AddArg(y)
+ v1.AddArg(v2)
+ v3 := b.NewValue0(v.Line, OpConst64, y.Type)
+ v3.AuxInt = 63
+ v1.AddArg(v3)
+ v4 := b.NewValue0(v.Line, OpARM64CMPconst, TypeFlags)
+ v4.AuxInt = 64
+ v5 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+ v5.AddArg(y)
+ v4.AddArg(v5)
+ v1.AddArg(v4)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueARM64_OpSignExt16to32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SignExt16to32 x)
+ // cond:
+ // result: (MOVHreg x)
+ for {
+ x := v.Args[0]
+ v.reset(OpARM64MOVHreg)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueARM64_OpSignExt16to64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SignExt16to64 x)
+ // cond:
+ // result: (MOVHreg x)
+ for {
+ x := v.Args[0]
+ v.reset(OpARM64MOVHreg)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueARM64_OpSignExt32to64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SignExt32to64 x)
+ // cond:
+ // result: (MOVWreg x)
+ for {
+ x := v.Args[0]
+ v.reset(OpARM64MOVWreg)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueARM64_OpSignExt8to16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SignExt8to16 x)
+ // cond:
+ // result: (MOVBreg x)
+ for {
+ x := v.Args[0]
+ v.reset(OpARM64MOVBreg)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueARM64_OpSignExt8to32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SignExt8to32 x)
+ // cond:
+ // result: (MOVBreg x)
+ for {
+ x := v.Args[0]
+ v.reset(OpARM64MOVBreg)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueARM64_OpSignExt8to64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SignExt8to64 x)
+ // cond:
+ // result: (MOVBreg x)
+ for {
+ x := v.Args[0]
+ v.reset(OpARM64MOVBreg)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueARM64_OpSlicemask(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Slicemask <t> x)
+ // cond:
+ // result: (MVN (SRAconst <t> (SUBconst <t> x [1]) [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.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueARM64_OpSqrt(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Sqrt x)
+ // cond:
+ // result: (FSQRTD x)
+ for {
+ x := v.Args[0]
+ v.reset(OpARM64FSQRTD)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueARM64_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(OpARM64CALLstatic)
+ v.AuxInt = argwid
+ v.Aux = target
+ v.AddArg(mem)
+ return true
+ }
+}
+func rewriteValueARM64_OpStore(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Store [1] ptr val mem)
+ // cond:
+ // result: (MOVBstore ptr val mem)
+ for {
+ if v.AuxInt != 1 {
+ break
+ }
+ ptr := v.Args[0]
+ val := v.Args[1]
+ mem := v.Args[2]
+ v.reset(OpARM64MOVBstore)
+ 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 {
+ break
+ }
+ ptr := v.Args[0]
+ val := v.Args[1]
+ mem := v.Args[2]
+ v.reset(OpARM64MOVHstore)
+ 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)
+ for {
+ if v.AuxInt != 4 {
+ break
+ }
+ ptr := v.Args[0]
+ val := v.Args[1]
+ mem := v.Args[2]
+ if !(!is32BitFloat(val.Type)) {
+ break
+ }
+ v.reset(OpARM64MOVWstore)
+ v.AddArg(ptr)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (Store [8] ptr val mem)
+ // cond: !is64BitFloat(val.Type)
+ // result: (MOVDstore ptr val mem)
+ for {
+ if v.AuxInt != 8 {
+ break
+ }
+ ptr := v.Args[0]
+ val := v.Args[1]
+ mem := v.Args[2]
+ if !(!is64BitFloat(val.Type)) {
+ break
+ }
+ v.reset(OpARM64MOVDstore)
+ v.AddArg(ptr)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (Store [4] ptr val mem)
+ // cond: is32BitFloat(val.Type)
+ // result: (FMOVSstore ptr val mem)
+ for {
+ if v.AuxInt != 4 {
+ break
+ }
+ ptr := v.Args[0]
+ val := v.Args[1]
+ mem := v.Args[2]
+ if !(is32BitFloat(val.Type)) {
+ break
+ }
+ v.reset(OpARM64FMOVSstore)
+ v.AddArg(ptr)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (Store [8] ptr val mem)
+ // cond: is64BitFloat(val.Type)
+ // result: (FMOVDstore ptr val mem)
+ for {
+ if v.AuxInt != 8 {
+ break
+ }
+ ptr := v.Args[0]
+ val := v.Args[1]
+ mem := v.Args[2]
+ if !(is64BitFloat(val.Type)) {
+ break
+ }
+ v.reset(OpARM64FMOVDstore)
+ v.AddArg(ptr)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValueARM64_OpSub16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Sub16 x y)
+ // cond:
+ // result: (SUB x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64SUB)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueARM64_OpSub32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Sub32 x y)
+ // cond:
+ // result: (SUB x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64SUB)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueARM64_OpSub32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Sub32F x y)
+ // cond:
+ // result: (FSUBS x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64FSUBS)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueARM64_OpSub64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Sub64 x y)
+ // cond:
+ // result: (SUB x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64SUB)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueARM64_OpSub64F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Sub64F x y)
+ // cond:
+ // result: (FSUBD x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64FSUBD)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueARM64_OpSub8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Sub8 x y)
+ // cond:
+ // result: (SUB x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64SUB)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueARM64_OpSubPtr(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SubPtr x y)
+ // cond:
+ // result: (SUB x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64SUB)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueARM64_OpTrunc16to8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Trunc16to8 x)
+ // cond:
+ // result: x
+ for {
+ x := v.Args[0]
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueARM64_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 rewriteValueARM64_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 rewriteValueARM64_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 rewriteValueARM64_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 rewriteValueARM64_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 rewriteValueARM64_OpXor16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Xor16 x y)
+ // cond:
+ // result: (XOR x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64XOR)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueARM64_OpXor32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Xor32 x y)
+ // cond:
+ // result: (XOR x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64XOR)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueARM64_OpXor64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Xor64 x y)
+ // cond:
+ // result: (XOR x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64XOR)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueARM64_OpXor8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Xor8 x y)
+ // cond:
+ // result: (XOR x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpARM64XOR)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueARM64_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) {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = mem.Type
+ v.AddArg(mem)
+ return true
+ }
+ // match: (Zero [s] ptr mem)
+ // cond: SizeAndAlign(s).Size() == 1
+ // result: (MOVBstore ptr (MOVDconst [0]) mem)
+ for {
+ s := v.AuxInt
+ ptr := v.Args[0]
+ mem := v.Args[1]
+ if !(SizeAndAlign(s).Size() == 1) {
+ break
+ }
+ v.reset(OpARM64MOVBstore)
+ v.AddArg(ptr)
+ v0 := b.NewValue0(v.Line, OpARM64MOVDconst, config.fe.TypeUInt64())
+ v0.AuxInt = 0
+ v.AddArg(v0)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (Zero [s] ptr mem)
+ // cond: SizeAndAlign(s).Size() == 2
+ // result: (MOVHstore ptr (MOVDconst [0]) mem)
+ for {
+ s := v.AuxInt
+ ptr := v.Args[0]
+ mem := v.Args[1]
+ if !(SizeAndAlign(s).Size() == 2) {
+ break
+ }
+ v.reset(OpARM64MOVHstore)
+ v.AddArg(ptr)
+ v0 := b.NewValue0(v.Line, OpARM64MOVDconst, config.fe.TypeUInt64())
+ v0.AuxInt = 0
+ v.AddArg(v0)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (Zero [s] ptr mem)
+ // cond: SizeAndAlign(s).Size() == 4
+ // result: (MOVWstore ptr (MOVDconst [0]) mem)
+ for {
+ s := v.AuxInt
+ ptr := v.Args[0]
+ mem := v.Args[1]
+ if !(SizeAndAlign(s).Size() == 4) {
+ break
+ }
+ v.reset(OpARM64MOVWstore)
+ v.AddArg(ptr)
+ v0 := b.NewValue0(v.Line, OpARM64MOVDconst, config.fe.TypeUInt64())
+ v0.AuxInt = 0
+ v.AddArg(v0)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (Zero [s] ptr mem)
+ // cond: SizeAndAlign(s).Size() == 8
+ // result: (MOVDstore ptr (MOVDconst [0]) mem)
+ for {
+ s := v.AuxInt
+ ptr := v.Args[0]
+ mem := v.Args[1]
+ if !(SizeAndAlign(s).Size() == 8) {
+ break
+ }
+ v.reset(OpARM64MOVDstore)
+ v.AddArg(ptr)
+ v0 := b.NewValue0(v.Line, OpARM64MOVDconst, config.fe.TypeUInt64())
+ v0.AuxInt = 0
+ v.AddArg(v0)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (Zero [s] ptr mem)
+ // cond: SizeAndAlign(s).Size() == 3
+ // 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) {
+ break
+ }
+ v.reset(OpARM64MOVBstore)
+ v.AuxInt = 2
+ v.AddArg(ptr)
+ v0 := b.NewValue0(v.Line, OpARM64MOVDconst, config.fe.TypeUInt64())
+ v0.AuxInt = 0
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpARM64MOVHstore, TypeMem)
+ v1.AddArg(ptr)
+ v2 := b.NewValue0(v.Line, OpARM64MOVDconst, config.fe.TypeUInt64())
+ v2.AuxInt = 0
+ v1.AddArg(v2)
+ v1.AddArg(mem)
+ v.AddArg(v1)
+ return true
+ }
+ // match: (Zero [s] ptr mem)
+ // cond: SizeAndAlign(s).Size() == 5
+ // 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) {
+ break
+ }
+ v.reset(OpARM64MOVBstore)
+ v.AuxInt = 4
+ v.AddArg(ptr)
+ v0 := b.NewValue0(v.Line, OpARM64MOVDconst, config.fe.TypeUInt64())
+ v0.AuxInt = 0
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpARM64MOVWstore, TypeMem)
+ v1.AddArg(ptr)
+ v2 := b.NewValue0(v.Line, OpARM64MOVDconst, config.fe.TypeUInt64())
+ v2.AuxInt = 0
+ v1.AddArg(v2)
+ v1.AddArg(mem)
+ v.AddArg(v1)
+ return true
+ }
+ // match: (Zero [s] ptr mem)
+ // cond: SizeAndAlign(s).Size() == 6
+ // 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) {
+ break
+ }
+ v.reset(OpARM64MOVHstore)
+ v.AuxInt = 4
+ v.AddArg(ptr)
+ v0 := b.NewValue0(v.Line, OpARM64MOVDconst, config.fe.TypeUInt64())
+ v0.AuxInt = 0
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpARM64MOVWstore, TypeMem)
+ v1.AddArg(ptr)
+ v2 := b.NewValue0(v.Line, OpARM64MOVDconst, config.fe.TypeUInt64())
+ v2.AuxInt = 0
+ v1.AddArg(v2)
+ v1.AddArg(mem)
+ v.AddArg(v1)
+ return true
+ }
+ // match: (Zero [s] ptr mem)
+ // cond: SizeAndAlign(s).Size() == 7
+ // 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) {
+ break
+ }
+ v.reset(OpARM64MOVBstore)
+ v.AuxInt = 6
+ v.AddArg(ptr)
+ v0 := b.NewValue0(v.Line, OpARM64MOVDconst, config.fe.TypeUInt64())
+ v0.AuxInt = 0
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpARM64MOVHstore, TypeMem)
+ v1.AuxInt = 4
+ v1.AddArg(ptr)
+ v2 := b.NewValue0(v.Line, OpARM64MOVDconst, config.fe.TypeUInt64())
+ v2.AuxInt = 0
+ v1.AddArg(v2)
+ v3 := b.NewValue0(v.Line, OpARM64MOVWstore, TypeMem)
+ v3.AddArg(ptr)
+ v4 := b.NewValue0(v.Line, OpARM64MOVDconst, config.fe.TypeUInt64())
+ v4.AuxInt = 0
+ v3.AddArg(v4)
+ v3.AddArg(mem)
+ v1.AddArg(v3)
+ v.AddArg(v1)
+ return true
+ }
+ // match: (Zero [s] ptr mem)
+ // cond: SizeAndAlign(s).Size() == 12
+ // 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) {
+ break
+ }
+ v.reset(OpARM64MOVWstore)
+ v.AuxInt = 8
+ v.AddArg(ptr)
+ v0 := b.NewValue0(v.Line, OpARM64MOVDconst, config.fe.TypeUInt64())
+ v0.AuxInt = 0
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpARM64MOVDstore, TypeMem)
+ v1.AddArg(ptr)
+ v2 := b.NewValue0(v.Line, OpARM64MOVDconst, config.fe.TypeUInt64())
+ v2.AuxInt = 0
+ v1.AddArg(v2)
+ v1.AddArg(mem)
+ v.AddArg(v1)
+ return true
+ }
+ // match: (Zero [s] ptr mem)
+ // cond: SizeAndAlign(s).Size() == 16
+ // 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) {
+ break
+ }
+ v.reset(OpARM64MOVDstore)
+ v.AuxInt = 8
+ v.AddArg(ptr)
+ v0 := b.NewValue0(v.Line, OpARM64MOVDconst, config.fe.TypeUInt64())
+ v0.AuxInt = 0
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpARM64MOVDstore, TypeMem)
+ v1.AddArg(ptr)
+ v2 := b.NewValue0(v.Line, OpARM64MOVDconst, config.fe.TypeUInt64())
+ v2.AuxInt = 0
+ v1.AddArg(v2)
+ v1.AddArg(mem)
+ v.AddArg(v1)
+ return true
+ }
+ // match: (Zero [s] ptr mem)
+ // cond: SizeAndAlign(s).Size() == 24
+ // 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) {
+ break
+ }
+ v.reset(OpARM64MOVDstore)
+ v.AuxInt = 16
+ v.AddArg(ptr)
+ v0 := b.NewValue0(v.Line, OpARM64MOVDconst, config.fe.TypeUInt64())
+ v0.AuxInt = 0
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpARM64MOVDstore, TypeMem)
+ v1.AuxInt = 8
+ v1.AddArg(ptr)
+ v2 := b.NewValue0(v.Line, OpARM64MOVDconst, config.fe.TypeUInt64())
+ v2.AuxInt = 0
+ v1.AddArg(v2)
+ v3 := b.NewValue0(v.Line, OpARM64MOVDstore, TypeMem)
+ v3.AddArg(ptr)
+ v4 := b.NewValue0(v.Line, OpARM64MOVDconst, config.fe.TypeUInt64())
+ v4.AuxInt = 0
+ v3.AddArg(v4)
+ v3.AddArg(mem)
+ v1.AddArg(v3)
+ v.AddArg(v1)
+ 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))
+ for {
+ s := v.AuxInt
+ ptr := v.Args[0]
+ mem := v.Args[1]
+ if !(SizeAndAlign(s).Size()%8 != 0 && SizeAndAlign(s).Size() > 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
+ 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.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)
+ for {
+ s := v.AuxInt
+ 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) {
+ break
+ }
+ v.reset(OpARM64DUFFZERO)
+ v.AuxInt = 4 * (128 - int64(SizeAndAlign(s).Size()/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)
+ for {
+ s := v.AuxInt
+ ptr := v.Args[0]
+ mem := v.Args[1]
+ if !(SizeAndAlign(s).Size()%8 == 0 && (SizeAndAlign(s).Size() > 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.AddArg(ptr)
+ v.AddArg(v0)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValueARM64_OpZeroExt16to32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ZeroExt16to32 x)
+ // cond:
+ // result: (MOVHUreg x)
+ for {
+ x := v.Args[0]
+ v.reset(OpARM64MOVHUreg)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueARM64_OpZeroExt16to64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ZeroExt16to64 x)
+ // cond:
+ // result: (MOVHUreg x)
+ for {
+ x := v.Args[0]
+ v.reset(OpARM64MOVHUreg)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueARM64_OpZeroExt32to64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ZeroExt32to64 x)
+ // cond:
+ // result: (MOVWUreg x)
+ for {
+ x := v.Args[0]
+ v.reset(OpARM64MOVWUreg)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueARM64_OpZeroExt8to16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ZeroExt8to16 x)
+ // cond:
+ // result: (MOVBUreg x)
+ for {
+ x := v.Args[0]
+ v.reset(OpARM64MOVBUreg)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueARM64_OpZeroExt8to32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ZeroExt8to32 x)
+ // cond:
+ // result: (MOVBUreg x)
+ for {
+ x := v.Args[0]
+ v.reset(OpARM64MOVBUreg)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueARM64_OpZeroExt8to64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ZeroExt8to64 x)
+ // cond:
+ // result: (MOVBUreg x)
+ for {
+ x := v.Args[0]
+ v.reset(OpARM64MOVBUreg)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteBlockARM64(b *Block, config *Config) bool {
+ switch b.Kind {
+ case BlockARM64EQ:
+ // match: (EQ (CMPconst [0] x) yes no)
+ // cond:
+ // result: (Z x yes no)
+ for {
+ v := b.Control
+ if v.Op != OpARM64CMPconst {
+ break
+ }
+ if v.AuxInt != 0 {
+ 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)
+ // cond:
+ // result: (ZW x yes no)
+ for {
+ v := b.Control
+ if v.Op != OpARM64CMPWconst {
+ break
+ }
+ if v.AuxInt != 0 {
+ 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)
+ // cond:
+ // result: (First nil yes no)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil no yes)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil no yes)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil no yes)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil no yes)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (EQ cmp yes no)
+ for {
+ v := b.Control
+ if v.Op != OpARM64InvertFlags {
+ 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:
+ // match: (GE (FlagEQ) yes no)
+ // cond:
+ // result: (First nil yes no)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil no yes)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil no yes)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil yes no)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil yes no)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (LE cmp yes no)
+ for {
+ v := b.Control
+ if v.Op != OpARM64InvertFlags {
+ 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:
+ // match: (GT (FlagEQ) yes no)
+ // cond:
+ // result: (First nil no yes)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil no yes)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil no yes)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil yes no)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil yes no)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (LT cmp yes no)
+ for {
+ v := b.Control
+ if v.Op != OpARM64InvertFlags {
+ 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:
+ // match: (If (Equal cc) yes no)
+ // cond:
+ // result: (EQ cc yes no)
+ for {
+ v := b.Control
+ if v.Op != OpARM64Equal {
+ 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)
+ // cond:
+ // result: (NE cc yes no)
+ for {
+ v := b.Control
+ if v.Op != OpARM64NotEqual {
+ 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)
+ // cond:
+ // result: (LT cc yes no)
+ for {
+ v := b.Control
+ if v.Op != OpARM64LessThan {
+ 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)
+ // cond:
+ // result: (ULT cc yes no)
+ for {
+ v := b.Control
+ if v.Op != OpARM64LessThanU {
+ 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)
+ // cond:
+ // result: (LE cc yes no)
+ for {
+ v := b.Control
+ if v.Op != OpARM64LessEqual {
+ 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)
+ // cond:
+ // result: (ULE cc yes no)
+ for {
+ v := b.Control
+ if v.Op != OpARM64LessEqualU {
+ 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)
+ // cond:
+ // result: (GT cc yes no)
+ for {
+ v := b.Control
+ if v.Op != OpARM64GreaterThan {
+ 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)
+ // cond:
+ // result: (UGT cc yes no)
+ for {
+ v := b.Control
+ if v.Op != OpARM64GreaterThanU {
+ 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)
+ // cond:
+ // result: (GE cc yes no)
+ for {
+ v := b.Control
+ if v.Op != OpARM64GreaterEqual {
+ 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)
+ // cond:
+ // result: (UGE cc yes no)
+ for {
+ v := b.Control
+ if v.Op != OpARM64GreaterEqualU {
+ 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)
+ // cond:
+ // result: (NZ cond yes no)
+ for {
+ 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:
+ // match: (LE (FlagEQ) yes no)
+ // cond:
+ // result: (First nil yes no)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil yes no)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil yes no)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil no yes)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil no yes)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (GE cmp yes no)
+ for {
+ v := b.Control
+ if v.Op != OpARM64InvertFlags {
+ 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:
+ // match: (LT (FlagEQ) yes no)
+ // cond:
+ // result: (First nil no yes)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil yes no)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil yes no)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil no yes)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil no yes)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (GT cmp yes no)
+ for {
+ v := b.Control
+ if v.Op != OpARM64InvertFlags {
+ 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:
+ // match: (NE (CMPconst [0] x) yes no)
+ // cond:
+ // result: (NZ x yes no)
+ for {
+ v := b.Control
+ if v.Op != OpARM64CMPconst {
+ break
+ }
+ if v.AuxInt != 0 {
+ 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)
+ // cond:
+ // result: (NZW x yes no)
+ for {
+ v := b.Control
+ if v.Op != OpARM64CMPWconst {
+ break
+ }
+ if v.AuxInt != 0 {
+ 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)
+ // cond:
+ // result: (First nil no yes)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil yes no)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil yes no)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil yes no)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil yes no)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (NE cmp yes no)
+ for {
+ v := b.Control
+ if v.Op != OpARM64InvertFlags {
+ 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:
+ // match: (NZ (Equal cc) yes no)
+ // cond:
+ // result: (EQ cc yes no)
+ for {
+ v := b.Control
+ if v.Op != OpARM64Equal {
+ 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)
+ // cond:
+ // result: (NE cc yes no)
+ for {
+ v := b.Control
+ if v.Op != OpARM64NotEqual {
+ 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)
+ // cond:
+ // result: (LT cc yes no)
+ for {
+ v := b.Control
+ if v.Op != OpARM64LessThan {
+ 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)
+ // cond:
+ // result: (ULT cc yes no)
+ for {
+ v := b.Control
+ if v.Op != OpARM64LessThanU {
+ 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)
+ // cond:
+ // result: (LE cc yes no)
+ for {
+ v := b.Control
+ if v.Op != OpARM64LessEqual {
+ 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)
+ // cond:
+ // result: (ULE cc yes no)
+ for {
+ v := b.Control
+ if v.Op != OpARM64LessEqualU {
+ 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)
+ // cond:
+ // result: (GT cc yes no)
+ for {
+ v := b.Control
+ if v.Op != OpARM64GreaterThan {
+ 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)
+ // cond:
+ // result: (UGT cc yes no)
+ for {
+ v := b.Control
+ if v.Op != OpARM64GreaterThanU {
+ 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)
+ // cond:
+ // result: (GE cc yes no)
+ for {
+ v := b.Control
+ if v.Op != OpARM64GreaterEqual {
+ 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)
+ // cond:
+ // result: (UGE cc yes no)
+ for {
+ v := b.Control
+ if v.Op != OpARM64GreaterEqualU {
+ 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)
+ // cond:
+ // result: (First nil no yes)
+ for {
+ v := b.Control
+ if v.Op != OpARM64MOVDconst {
+ break
+ }
+ 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)
+ // cond: c != 0
+ // result: (First nil yes no)
+ for {
+ v := b.Control
+ if v.Op != OpARM64MOVDconst {
+ 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:
+ // match: (NZW (MOVDconst [c]) yes no)
+ // cond: int32(c) == 0
+ // result: (First nil no yes)
+ for {
+ v := b.Control
+ if v.Op != OpARM64MOVDconst {
+ 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)
+ // cond: int32(c) != 0
+ // result: (First nil yes no)
+ for {
+ v := b.Control
+ if v.Op != OpARM64MOVDconst {
+ 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:
+ // match: (UGE (FlagEQ) yes no)
+ // cond:
+ // result: (First nil yes no)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil no yes)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil yes no)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil no yes)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil yes no)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (ULE cmp yes no)
+ for {
+ v := b.Control
+ if v.Op != OpARM64InvertFlags {
+ 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:
+ // match: (UGT (FlagEQ) yes no)
+ // cond:
+ // result: (First nil no yes)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil no yes)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil yes no)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil no yes)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil yes no)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (ULT cmp yes no)
+ for {
+ v := b.Control
+ if v.Op != OpARM64InvertFlags {
+ 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:
+ // match: (ULE (FlagEQ) yes no)
+ // cond:
+ // result: (First nil yes no)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil yes no)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil no yes)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil yes no)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil no yes)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (UGE cmp yes no)
+ for {
+ v := b.Control
+ if v.Op != OpARM64InvertFlags {
+ 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:
+ // match: (ULT (FlagEQ) yes no)
+ // cond:
+ // result: (First nil no yes)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil yes no)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil no yes)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil yes no)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil no yes)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (UGT cmp yes no)
+ for {
+ v := b.Control
+ if v.Op != OpARM64InvertFlags {
+ 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:
+ // match: (Z (MOVDconst [0]) yes no)
+ // cond:
+ // result: (First nil yes no)
+ for {
+ v := b.Control
+ if v.Op != OpARM64MOVDconst {
+ break
+ }
+ 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)
+ // cond: c != 0
+ // result: (First nil no yes)
+ for {
+ v := b.Control
+ if v.Op != OpARM64MOVDconst {
+ 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:
+ // match: (ZW (MOVDconst [c]) yes no)
+ // cond: int32(c) == 0
+ // result: (First nil yes no)
+ for {
+ v := b.Control
+ if v.Op != OpARM64MOVDconst {
+ 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)
+ // cond: int32(c) != 0
+ // result: (First nil no yes)
+ for {
+ v := b.Control
+ if v.Op != OpARM64MOVDconst {
+ 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
+ }
+ }
+ return false
+}
diff --git a/src/cmd/compile/internal/ssa/rewriteMIPS.go b/src/cmd/compile/internal/ssa/rewriteMIPS.go
new file mode 100644
index 0000000..cbe9f1b
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/rewriteMIPS.go
@@ -0,0 +1,9831 @@
+// autogenerated from gen/MIPS.rules: do not edit!
+// generated with: cd gen; go run *.go
+
+package ssa
+
+import "math"
+
+var _ = math.MinInt8 // in case not otherwise used
+func rewriteValueMIPS(v *Value, config *Config) bool {
+ switch v.Op {
+ case OpAdd16:
+ return rewriteValueMIPS_OpAdd16(v, config)
+ case OpAdd32:
+ return rewriteValueMIPS_OpAdd32(v, config)
+ case OpAdd32F:
+ return rewriteValueMIPS_OpAdd32F(v, config)
+ case OpAdd32withcarry:
+ return rewriteValueMIPS_OpAdd32withcarry(v, config)
+ case OpAdd64F:
+ return rewriteValueMIPS_OpAdd64F(v, config)
+ case OpAdd8:
+ return rewriteValueMIPS_OpAdd8(v, config)
+ case OpAddPtr:
+ return rewriteValueMIPS_OpAddPtr(v, config)
+ case OpAddr:
+ return rewriteValueMIPS_OpAddr(v, config)
+ case OpAnd16:
+ return rewriteValueMIPS_OpAnd16(v, config)
+ case OpAnd32:
+ return rewriteValueMIPS_OpAnd32(v, config)
+ case OpAnd8:
+ return rewriteValueMIPS_OpAnd8(v, config)
+ case OpAndB:
+ return rewriteValueMIPS_OpAndB(v, config)
+ case OpAtomicAdd32:
+ return rewriteValueMIPS_OpAtomicAdd32(v, config)
+ case OpAtomicAnd8:
+ return rewriteValueMIPS_OpAtomicAnd8(v, config)
+ case OpAtomicCompareAndSwap32:
+ return rewriteValueMIPS_OpAtomicCompareAndSwap32(v, config)
+ case OpAtomicExchange32:
+ return rewriteValueMIPS_OpAtomicExchange32(v, config)
+ case OpAtomicLoad32:
+ return rewriteValueMIPS_OpAtomicLoad32(v, config)
+ case OpAtomicLoadPtr:
+ return rewriteValueMIPS_OpAtomicLoadPtr(v, config)
+ case OpAtomicOr8:
+ return rewriteValueMIPS_OpAtomicOr8(v, config)
+ case OpAtomicStore32:
+ return rewriteValueMIPS_OpAtomicStore32(v, config)
+ case OpAtomicStorePtrNoWB:
+ return rewriteValueMIPS_OpAtomicStorePtrNoWB(v, config)
+ case OpClosureCall:
+ return rewriteValueMIPS_OpClosureCall(v, config)
+ case OpCom16:
+ return rewriteValueMIPS_OpCom16(v, config)
+ case OpCom32:
+ return rewriteValueMIPS_OpCom32(v, config)
+ case OpCom8:
+ return rewriteValueMIPS_OpCom8(v, config)
+ case OpConst16:
+ return rewriteValueMIPS_OpConst16(v, config)
+ case OpConst32:
+ return rewriteValueMIPS_OpConst32(v, config)
+ case OpConst32F:
+ return rewriteValueMIPS_OpConst32F(v, config)
+ case OpConst64F:
+ return rewriteValueMIPS_OpConst64F(v, config)
+ case OpConst8:
+ return rewriteValueMIPS_OpConst8(v, config)
+ case OpConstBool:
+ return rewriteValueMIPS_OpConstBool(v, config)
+ case OpConstNil:
+ return rewriteValueMIPS_OpConstNil(v, config)
+ case OpConvert:
+ return rewriteValueMIPS_OpConvert(v, config)
+ case OpCtz32:
+ return rewriteValueMIPS_OpCtz32(v, config)
+ case OpCvt32Fto32:
+ return rewriteValueMIPS_OpCvt32Fto32(v, config)
+ case OpCvt32Fto64F:
+ return rewriteValueMIPS_OpCvt32Fto64F(v, config)
+ case OpCvt32to32F:
+ return rewriteValueMIPS_OpCvt32to32F(v, config)
+ case OpCvt32to64F:
+ return rewriteValueMIPS_OpCvt32to64F(v, config)
+ case OpCvt64Fto32:
+ return rewriteValueMIPS_OpCvt64Fto32(v, config)
+ case OpCvt64Fto32F:
+ return rewriteValueMIPS_OpCvt64Fto32F(v, config)
+ case OpDeferCall:
+ return rewriteValueMIPS_OpDeferCall(v, config)
+ case OpDiv16:
+ return rewriteValueMIPS_OpDiv16(v, config)
+ case OpDiv16u:
+ return rewriteValueMIPS_OpDiv16u(v, config)
+ case OpDiv32:
+ return rewriteValueMIPS_OpDiv32(v, config)
+ case OpDiv32F:
+ return rewriteValueMIPS_OpDiv32F(v, config)
+ case OpDiv32u:
+ return rewriteValueMIPS_OpDiv32u(v, config)
+ case OpDiv64F:
+ return rewriteValueMIPS_OpDiv64F(v, config)
+ case OpDiv8:
+ return rewriteValueMIPS_OpDiv8(v, config)
+ case OpDiv8u:
+ return rewriteValueMIPS_OpDiv8u(v, config)
+ case OpEq16:
+ return rewriteValueMIPS_OpEq16(v, config)
+ case OpEq32:
+ return rewriteValueMIPS_OpEq32(v, config)
+ case OpEq32F:
+ return rewriteValueMIPS_OpEq32F(v, config)
+ case OpEq64F:
+ return rewriteValueMIPS_OpEq64F(v, config)
+ case OpEq8:
+ return rewriteValueMIPS_OpEq8(v, config)
+ case OpEqB:
+ return rewriteValueMIPS_OpEqB(v, config)
+ case OpEqPtr:
+ return rewriteValueMIPS_OpEqPtr(v, config)
+ case OpGeq16:
+ return rewriteValueMIPS_OpGeq16(v, config)
+ case OpGeq16U:
+ return rewriteValueMIPS_OpGeq16U(v, config)
+ case OpGeq32:
+ return rewriteValueMIPS_OpGeq32(v, config)
+ case OpGeq32F:
+ return rewriteValueMIPS_OpGeq32F(v, config)
+ case OpGeq32U:
+ return rewriteValueMIPS_OpGeq32U(v, config)
+ case OpGeq64F:
+ return rewriteValueMIPS_OpGeq64F(v, config)
+ case OpGeq8:
+ return rewriteValueMIPS_OpGeq8(v, config)
+ case OpGeq8U:
+ return rewriteValueMIPS_OpGeq8U(v, config)
+ case OpGetClosurePtr:
+ return rewriteValueMIPS_OpGetClosurePtr(v, config)
+ case OpGoCall:
+ return rewriteValueMIPS_OpGoCall(v, config)
+ case OpGreater16:
+ return rewriteValueMIPS_OpGreater16(v, config)
+ case OpGreater16U:
+ return rewriteValueMIPS_OpGreater16U(v, config)
+ case OpGreater32:
+ return rewriteValueMIPS_OpGreater32(v, config)
+ case OpGreater32F:
+ return rewriteValueMIPS_OpGreater32F(v, config)
+ case OpGreater32U:
+ return rewriteValueMIPS_OpGreater32U(v, config)
+ case OpGreater64F:
+ return rewriteValueMIPS_OpGreater64F(v, config)
+ case OpGreater8:
+ return rewriteValueMIPS_OpGreater8(v, config)
+ case OpGreater8U:
+ return rewriteValueMIPS_OpGreater8U(v, config)
+ case OpHmul16:
+ return rewriteValueMIPS_OpHmul16(v, config)
+ case OpHmul16u:
+ return rewriteValueMIPS_OpHmul16u(v, config)
+ case OpHmul32:
+ return rewriteValueMIPS_OpHmul32(v, config)
+ case OpHmul32u:
+ return rewriteValueMIPS_OpHmul32u(v, config)
+ case OpHmul8:
+ return rewriteValueMIPS_OpHmul8(v, config)
+ case OpHmul8u:
+ return rewriteValueMIPS_OpHmul8u(v, config)
+ case OpInterCall:
+ return rewriteValueMIPS_OpInterCall(v, config)
+ case OpIsInBounds:
+ return rewriteValueMIPS_OpIsInBounds(v, config)
+ case OpIsNonNil:
+ return rewriteValueMIPS_OpIsNonNil(v, config)
+ case OpIsSliceInBounds:
+ return rewriteValueMIPS_OpIsSliceInBounds(v, config)
+ case OpLeq16:
+ return rewriteValueMIPS_OpLeq16(v, config)
+ case OpLeq16U:
+ return rewriteValueMIPS_OpLeq16U(v, config)
+ case OpLeq32:
+ return rewriteValueMIPS_OpLeq32(v, config)
+ case OpLeq32F:
+ return rewriteValueMIPS_OpLeq32F(v, config)
+ case OpLeq32U:
+ return rewriteValueMIPS_OpLeq32U(v, config)
+ case OpLeq64F:
+ return rewriteValueMIPS_OpLeq64F(v, config)
+ case OpLeq8:
+ return rewriteValueMIPS_OpLeq8(v, config)
+ case OpLeq8U:
+ return rewriteValueMIPS_OpLeq8U(v, config)
+ case OpLess16:
+ return rewriteValueMIPS_OpLess16(v, config)
+ case OpLess16U:
+ return rewriteValueMIPS_OpLess16U(v, config)
+ case OpLess32:
+ return rewriteValueMIPS_OpLess32(v, config)
+ case OpLess32F:
+ return rewriteValueMIPS_OpLess32F(v, config)
+ case OpLess32U:
+ return rewriteValueMIPS_OpLess32U(v, config)
+ case OpLess64F:
+ return rewriteValueMIPS_OpLess64F(v, config)
+ case OpLess8:
+ return rewriteValueMIPS_OpLess8(v, config)
+ case OpLess8U:
+ return rewriteValueMIPS_OpLess8U(v, config)
+ case OpLoad:
+ return rewriteValueMIPS_OpLoad(v, config)
+ case OpLsh16x16:
+ return rewriteValueMIPS_OpLsh16x16(v, config)
+ case OpLsh16x32:
+ return rewriteValueMIPS_OpLsh16x32(v, config)
+ case OpLsh16x64:
+ return rewriteValueMIPS_OpLsh16x64(v, config)
+ case OpLsh16x8:
+ return rewriteValueMIPS_OpLsh16x8(v, config)
+ case OpLsh32x16:
+ return rewriteValueMIPS_OpLsh32x16(v, config)
+ case OpLsh32x32:
+ return rewriteValueMIPS_OpLsh32x32(v, config)
+ case OpLsh32x64:
+ return rewriteValueMIPS_OpLsh32x64(v, config)
+ case OpLsh32x8:
+ return rewriteValueMIPS_OpLsh32x8(v, config)
+ case OpLsh8x16:
+ return rewriteValueMIPS_OpLsh8x16(v, config)
+ case OpLsh8x32:
+ return rewriteValueMIPS_OpLsh8x32(v, config)
+ case OpLsh8x64:
+ return rewriteValueMIPS_OpLsh8x64(v, config)
+ case OpLsh8x8:
+ return rewriteValueMIPS_OpLsh8x8(v, config)
+ case OpMIPSADD:
+ return rewriteValueMIPS_OpMIPSADD(v, config)
+ case OpMIPSADDconst:
+ return rewriteValueMIPS_OpMIPSADDconst(v, config)
+ case OpMIPSAND:
+ return rewriteValueMIPS_OpMIPSAND(v, config)
+ case OpMIPSANDconst:
+ return rewriteValueMIPS_OpMIPSANDconst(v, config)
+ case OpMIPSCMOVZ:
+ return rewriteValueMIPS_OpMIPSCMOVZ(v, config)
+ case OpMIPSCMOVZzero:
+ return rewriteValueMIPS_OpMIPSCMOVZzero(v, config)
+ case OpMIPSLoweredAtomicAdd:
+ return rewriteValueMIPS_OpMIPSLoweredAtomicAdd(v, config)
+ case OpMIPSLoweredAtomicStore:
+ return rewriteValueMIPS_OpMIPSLoweredAtomicStore(v, config)
+ case OpMIPSMOVBUload:
+ return rewriteValueMIPS_OpMIPSMOVBUload(v, config)
+ case OpMIPSMOVBUreg:
+ return rewriteValueMIPS_OpMIPSMOVBUreg(v, config)
+ case OpMIPSMOVBload:
+ return rewriteValueMIPS_OpMIPSMOVBload(v, config)
+ case OpMIPSMOVBreg:
+ return rewriteValueMIPS_OpMIPSMOVBreg(v, config)
+ case OpMIPSMOVBstore:
+ return rewriteValueMIPS_OpMIPSMOVBstore(v, config)
+ case OpMIPSMOVBstorezero:
+ return rewriteValueMIPS_OpMIPSMOVBstorezero(v, config)
+ case OpMIPSMOVDload:
+ return rewriteValueMIPS_OpMIPSMOVDload(v, config)
+ case OpMIPSMOVDstore:
+ return rewriteValueMIPS_OpMIPSMOVDstore(v, config)
+ case OpMIPSMOVFload:
+ return rewriteValueMIPS_OpMIPSMOVFload(v, config)
+ case OpMIPSMOVFstore:
+ return rewriteValueMIPS_OpMIPSMOVFstore(v, config)
+ case OpMIPSMOVHUload:
+ return rewriteValueMIPS_OpMIPSMOVHUload(v, config)
+ case OpMIPSMOVHUreg:
+ return rewriteValueMIPS_OpMIPSMOVHUreg(v, config)
+ case OpMIPSMOVHload:
+ return rewriteValueMIPS_OpMIPSMOVHload(v, config)
+ case OpMIPSMOVHreg:
+ return rewriteValueMIPS_OpMIPSMOVHreg(v, config)
+ case OpMIPSMOVHstore:
+ return rewriteValueMIPS_OpMIPSMOVHstore(v, config)
+ case OpMIPSMOVHstorezero:
+ return rewriteValueMIPS_OpMIPSMOVHstorezero(v, config)
+ case OpMIPSMOVWload:
+ return rewriteValueMIPS_OpMIPSMOVWload(v, config)
+ case OpMIPSMOVWreg:
+ return rewriteValueMIPS_OpMIPSMOVWreg(v, config)
+ case OpMIPSMOVWstore:
+ return rewriteValueMIPS_OpMIPSMOVWstore(v, config)
+ case OpMIPSMOVWstorezero:
+ return rewriteValueMIPS_OpMIPSMOVWstorezero(v, config)
+ case OpMIPSMUL:
+ return rewriteValueMIPS_OpMIPSMUL(v, config)
+ case OpMIPSNEG:
+ return rewriteValueMIPS_OpMIPSNEG(v, config)
+ case OpMIPSNOR:
+ return rewriteValueMIPS_OpMIPSNOR(v, config)
+ case OpMIPSNORconst:
+ return rewriteValueMIPS_OpMIPSNORconst(v, config)
+ case OpMIPSOR:
+ return rewriteValueMIPS_OpMIPSOR(v, config)
+ case OpMIPSORconst:
+ return rewriteValueMIPS_OpMIPSORconst(v, config)
+ case OpMIPSSGT:
+ return rewriteValueMIPS_OpMIPSSGT(v, config)
+ case OpMIPSSGTU:
+ return rewriteValueMIPS_OpMIPSSGTU(v, config)
+ case OpMIPSSGTUconst:
+ return rewriteValueMIPS_OpMIPSSGTUconst(v, config)
+ case OpMIPSSGTUzero:
+ return rewriteValueMIPS_OpMIPSSGTUzero(v, config)
+ case OpMIPSSGTconst:
+ return rewriteValueMIPS_OpMIPSSGTconst(v, config)
+ case OpMIPSSGTzero:
+ return rewriteValueMIPS_OpMIPSSGTzero(v, config)
+ case OpMIPSSLL:
+ return rewriteValueMIPS_OpMIPSSLL(v, config)
+ case OpMIPSSLLconst:
+ return rewriteValueMIPS_OpMIPSSLLconst(v, config)
+ case OpMIPSSRA:
+ return rewriteValueMIPS_OpMIPSSRA(v, config)
+ case OpMIPSSRAconst:
+ return rewriteValueMIPS_OpMIPSSRAconst(v, config)
+ case OpMIPSSRL:
+ return rewriteValueMIPS_OpMIPSSRL(v, config)
+ case OpMIPSSRLconst:
+ return rewriteValueMIPS_OpMIPSSRLconst(v, config)
+ case OpMIPSSUB:
+ return rewriteValueMIPS_OpMIPSSUB(v, config)
+ case OpMIPSSUBconst:
+ return rewriteValueMIPS_OpMIPSSUBconst(v, config)
+ case OpMIPSXOR:
+ return rewriteValueMIPS_OpMIPSXOR(v, config)
+ case OpMIPSXORconst:
+ return rewriteValueMIPS_OpMIPSXORconst(v, config)
+ case OpMod16:
+ return rewriteValueMIPS_OpMod16(v, config)
+ case OpMod16u:
+ return rewriteValueMIPS_OpMod16u(v, config)
+ case OpMod32:
+ return rewriteValueMIPS_OpMod32(v, config)
+ case OpMod32u:
+ return rewriteValueMIPS_OpMod32u(v, config)
+ case OpMod8:
+ return rewriteValueMIPS_OpMod8(v, config)
+ case OpMod8u:
+ return rewriteValueMIPS_OpMod8u(v, config)
+ case OpMove:
+ return rewriteValueMIPS_OpMove(v, config)
+ case OpMul16:
+ return rewriteValueMIPS_OpMul16(v, config)
+ case OpMul32:
+ return rewriteValueMIPS_OpMul32(v, config)
+ case OpMul32F:
+ return rewriteValueMIPS_OpMul32F(v, config)
+ case OpMul32uhilo:
+ return rewriteValueMIPS_OpMul32uhilo(v, config)
+ case OpMul64F:
+ return rewriteValueMIPS_OpMul64F(v, config)
+ case OpMul8:
+ return rewriteValueMIPS_OpMul8(v, config)
+ case OpNeg16:
+ return rewriteValueMIPS_OpNeg16(v, config)
+ case OpNeg32:
+ return rewriteValueMIPS_OpNeg32(v, config)
+ case OpNeg32F:
+ return rewriteValueMIPS_OpNeg32F(v, config)
+ case OpNeg64F:
+ return rewriteValueMIPS_OpNeg64F(v, config)
+ case OpNeg8:
+ return rewriteValueMIPS_OpNeg8(v, config)
+ case OpNeq16:
+ return rewriteValueMIPS_OpNeq16(v, config)
+ case OpNeq32:
+ return rewriteValueMIPS_OpNeq32(v, config)
+ case OpNeq32F:
+ return rewriteValueMIPS_OpNeq32F(v, config)
+ case OpNeq64F:
+ return rewriteValueMIPS_OpNeq64F(v, config)
+ case OpNeq8:
+ return rewriteValueMIPS_OpNeq8(v, config)
+ case OpNeqB:
+ return rewriteValueMIPS_OpNeqB(v, config)
+ case OpNeqPtr:
+ return rewriteValueMIPS_OpNeqPtr(v, config)
+ case OpNilCheck:
+ return rewriteValueMIPS_OpNilCheck(v, config)
+ case OpNot:
+ return rewriteValueMIPS_OpNot(v, config)
+ case OpOffPtr:
+ return rewriteValueMIPS_OpOffPtr(v, config)
+ case OpOr16:
+ return rewriteValueMIPS_OpOr16(v, config)
+ case OpOr32:
+ return rewriteValueMIPS_OpOr32(v, config)
+ case OpOr8:
+ return rewriteValueMIPS_OpOr8(v, config)
+ case OpOrB:
+ return rewriteValueMIPS_OpOrB(v, config)
+ case OpRsh16Ux16:
+ return rewriteValueMIPS_OpRsh16Ux16(v, config)
+ case OpRsh16Ux32:
+ return rewriteValueMIPS_OpRsh16Ux32(v, config)
+ case OpRsh16Ux64:
+ return rewriteValueMIPS_OpRsh16Ux64(v, config)
+ case OpRsh16Ux8:
+ return rewriteValueMIPS_OpRsh16Ux8(v, config)
+ case OpRsh16x16:
+ return rewriteValueMIPS_OpRsh16x16(v, config)
+ case OpRsh16x32:
+ return rewriteValueMIPS_OpRsh16x32(v, config)
+ case OpRsh16x64:
+ return rewriteValueMIPS_OpRsh16x64(v, config)
+ case OpRsh16x8:
+ return rewriteValueMIPS_OpRsh16x8(v, config)
+ case OpRsh32Ux16:
+ return rewriteValueMIPS_OpRsh32Ux16(v, config)
+ case OpRsh32Ux32:
+ return rewriteValueMIPS_OpRsh32Ux32(v, config)
+ case OpRsh32Ux64:
+ return rewriteValueMIPS_OpRsh32Ux64(v, config)
+ case OpRsh32Ux8:
+ return rewriteValueMIPS_OpRsh32Ux8(v, config)
+ case OpRsh32x16:
+ return rewriteValueMIPS_OpRsh32x16(v, config)
+ case OpRsh32x32:
+ return rewriteValueMIPS_OpRsh32x32(v, config)
+ case OpRsh32x64:
+ return rewriteValueMIPS_OpRsh32x64(v, config)
+ case OpRsh32x8:
+ return rewriteValueMIPS_OpRsh32x8(v, config)
+ case OpRsh8Ux16:
+ return rewriteValueMIPS_OpRsh8Ux16(v, config)
+ case OpRsh8Ux32:
+ return rewriteValueMIPS_OpRsh8Ux32(v, config)
+ case OpRsh8Ux64:
+ return rewriteValueMIPS_OpRsh8Ux64(v, config)
+ case OpRsh8Ux8:
+ return rewriteValueMIPS_OpRsh8Ux8(v, config)
+ case OpRsh8x16:
+ return rewriteValueMIPS_OpRsh8x16(v, config)
+ case OpRsh8x32:
+ return rewriteValueMIPS_OpRsh8x32(v, config)
+ case OpRsh8x64:
+ return rewriteValueMIPS_OpRsh8x64(v, config)
+ case OpRsh8x8:
+ return rewriteValueMIPS_OpRsh8x8(v, config)
+ case OpSelect0:
+ return rewriteValueMIPS_OpSelect0(v, config)
+ case OpSelect1:
+ return rewriteValueMIPS_OpSelect1(v, config)
+ case OpSignExt16to32:
+ return rewriteValueMIPS_OpSignExt16to32(v, config)
+ case OpSignExt8to16:
+ return rewriteValueMIPS_OpSignExt8to16(v, config)
+ case OpSignExt8to32:
+ return rewriteValueMIPS_OpSignExt8to32(v, config)
+ case OpSignmask:
+ return rewriteValueMIPS_OpSignmask(v, config)
+ case OpSlicemask:
+ return rewriteValueMIPS_OpSlicemask(v, config)
+ case OpSqrt:
+ return rewriteValueMIPS_OpSqrt(v, config)
+ case OpStaticCall:
+ return rewriteValueMIPS_OpStaticCall(v, config)
+ case OpStore:
+ return rewriteValueMIPS_OpStore(v, config)
+ case OpSub16:
+ return rewriteValueMIPS_OpSub16(v, config)
+ case OpSub32:
+ return rewriteValueMIPS_OpSub32(v, config)
+ case OpSub32F:
+ return rewriteValueMIPS_OpSub32F(v, config)
+ case OpSub32withcarry:
+ return rewriteValueMIPS_OpSub32withcarry(v, config)
+ case OpSub64F:
+ return rewriteValueMIPS_OpSub64F(v, config)
+ case OpSub8:
+ return rewriteValueMIPS_OpSub8(v, config)
+ case OpSubPtr:
+ return rewriteValueMIPS_OpSubPtr(v, config)
+ case OpTrunc16to8:
+ return rewriteValueMIPS_OpTrunc16to8(v, config)
+ case OpTrunc32to16:
+ return rewriteValueMIPS_OpTrunc32to16(v, config)
+ case OpTrunc32to8:
+ return rewriteValueMIPS_OpTrunc32to8(v, config)
+ case OpXor16:
+ return rewriteValueMIPS_OpXor16(v, config)
+ case OpXor32:
+ return rewriteValueMIPS_OpXor32(v, config)
+ case OpXor8:
+ return rewriteValueMIPS_OpXor8(v, config)
+ case OpZero:
+ return rewriteValueMIPS_OpZero(v, config)
+ case OpZeroExt16to32:
+ return rewriteValueMIPS_OpZeroExt16to32(v, config)
+ case OpZeroExt8to16:
+ return rewriteValueMIPS_OpZeroExt8to16(v, config)
+ case OpZeroExt8to32:
+ return rewriteValueMIPS_OpZeroExt8to32(v, config)
+ case OpZeromask:
+ return rewriteValueMIPS_OpZeromask(v, config)
+ }
+ return false
+}
+func rewriteValueMIPS_OpAdd16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Add16 x y)
+ // cond:
+ // result: (ADD x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPSADD)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueMIPS_OpAdd32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Add32 x y)
+ // cond:
+ // result: (ADD x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPSADD)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueMIPS_OpAdd32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Add32F x y)
+ // cond:
+ // result: (ADDF x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPSADDF)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueMIPS_OpAdd32withcarry(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Add32withcarry <t> x y c)
+ // cond:
+ // result: (ADD c (ADD <t> x y))
+ for {
+ t := v.Type
+ 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.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueMIPS_OpAdd64F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Add64F x y)
+ // cond:
+ // result: (ADDD x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPSADDD)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueMIPS_OpAdd8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Add8 x y)
+ // cond:
+ // result: (ADD x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPSADD)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueMIPS_OpAddPtr(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (AddPtr x y)
+ // cond:
+ // result: (ADD x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPSADD)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueMIPS_OpAddr(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Addr {sym} base)
+ // cond:
+ // result: (MOVWaddr {sym} base)
+ for {
+ sym := v.Aux
+ base := v.Args[0]
+ v.reset(OpMIPSMOVWaddr)
+ v.Aux = sym
+ v.AddArg(base)
+ return true
+ }
+}
+func rewriteValueMIPS_OpAnd16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (And16 x y)
+ // cond:
+ // result: (AND x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPSAND)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueMIPS_OpAnd32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (And32 x y)
+ // cond:
+ // result: (AND x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPSAND)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueMIPS_OpAnd8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (And8 x y)
+ // cond:
+ // result: (AND x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPSAND)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueMIPS_OpAndB(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (AndB x y)
+ // cond:
+ // result: (AND x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPSAND)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueMIPS_OpAtomicAdd32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (AtomicAdd32 ptr val mem)
+ // cond:
+ // result: (LoweredAtomicAdd ptr val mem)
+ for {
+ ptr := v.Args[0]
+ val := v.Args[1]
+ mem := v.Args[2]
+ v.reset(OpMIPSLoweredAtomicAdd)
+ v.AddArg(ptr)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+}
+func rewriteValueMIPS_OpAtomicAnd8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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] (XORconst <config.fe.TypeUInt32()> [3] ptr)))))) mem)
+ for {
+ ptr := v.Args[0]
+ val := v.Args[1]
+ mem := v.Args[2]
+ if !(!config.BigEndian) {
+ break
+ }
+ v.reset(OpMIPSLoweredAtomicAnd)
+ v0 := b.NewValue0(v.Line, OpMIPSAND, config.fe.TypeUInt32().PtrTo())
+ v1 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+ 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())
+ v4.AddArg(val)
+ v3.AddArg(v4)
+ v5 := b.NewValue0(v.Line, OpMIPSSLLconst, config.fe.TypeUInt32())
+ v5.AuxInt = 3
+ v6 := b.NewValue0(v.Line, OpMIPSANDconst, config.fe.TypeUInt32())
+ 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.AuxInt = 0
+ v8 := b.NewValue0(v.Line, OpMIPSSLL, config.fe.TypeUInt32())
+ v9 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+ v9.AuxInt = 0xff
+ v8.AddArg(v9)
+ v10 := b.NewValue0(v.Line, OpMIPSSLLconst, config.fe.TypeUInt32())
+ v10.AuxInt = 3
+ v11 := b.NewValue0(v.Line, OpMIPSANDconst, config.fe.TypeUInt32())
+ v11.AuxInt = 3
+ v12 := b.NewValue0(v.Line, OpMIPSXORconst, config.fe.TypeUInt32())
+ v12.AuxInt = 3
+ v12.AddArg(ptr)
+ v11.AddArg(v12)
+ v10.AddArg(v11)
+ v8.AddArg(v10)
+ v7.AddArg(v8)
+ v2.AddArg(v7)
+ v.AddArg(v2)
+ v.AddArg(mem)
+ return true
+ }
+ // 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 [...]
+ for {
+ ptr := v.Args[0]
+ val := v.Args[1]
+ mem := v.Args[2]
+ if !(config.BigEndian) {
+ break
+ }
+ v.reset(OpMIPSLoweredAtomicAnd)
+ v0 := b.NewValue0(v.Line, OpMIPSAND, config.fe.TypeUInt32().PtrTo())
+ v1 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+ 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())
+ v4.AddArg(val)
+ v3.AddArg(v4)
+ v5 := b.NewValue0(v.Line, OpMIPSSLLconst, config.fe.TypeUInt32())
+ v5.AuxInt = 3
+ v6 := b.NewValue0(v.Line, OpMIPSANDconst, config.fe.TypeUInt32())
+ v6.AuxInt = 3
+ v7 := b.NewValue0(v.Line, OpMIPSXORconst, config.fe.TypeUInt32())
+ 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.AuxInt = 0
+ v9 := b.NewValue0(v.Line, OpMIPSSLL, config.fe.TypeUInt32())
+ v10 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+ v10.AuxInt = 0xff
+ v9.AddArg(v10)
+ v11 := b.NewValue0(v.Line, OpMIPSSLLconst, config.fe.TypeUInt32())
+ v11.AuxInt = 3
+ v12 := b.NewValue0(v.Line, OpMIPSANDconst, config.fe.TypeUInt32())
+ v12.AuxInt = 3
+ v13 := b.NewValue0(v.Line, OpMIPSXORconst, config.fe.TypeUInt32())
+ v13.AuxInt = 3
+ v13.AddArg(ptr)
+ v12.AddArg(v13)
+ v11.AddArg(v12)
+ v9.AddArg(v11)
+ v8.AddArg(v9)
+ v2.AddArg(v8)
+ v.AddArg(v2)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS_OpAtomicCompareAndSwap32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (AtomicCompareAndSwap32 ptr old new_ mem)
+ // cond:
+ // result: (LoweredAtomicCas ptr old new_ mem)
+ for {
+ ptr := v.Args[0]
+ old := v.Args[1]
+ new_ := v.Args[2]
+ mem := v.Args[3]
+ v.reset(OpMIPSLoweredAtomicCas)
+ v.AddArg(ptr)
+ v.AddArg(old)
+ v.AddArg(new_)
+ v.AddArg(mem)
+ return true
+ }
+}
+func rewriteValueMIPS_OpAtomicExchange32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (AtomicExchange32 ptr val mem)
+ // cond:
+ // result: (LoweredAtomicExchange ptr val mem)
+ for {
+ ptr := v.Args[0]
+ val := v.Args[1]
+ mem := v.Args[2]
+ v.reset(OpMIPSLoweredAtomicExchange)
+ v.AddArg(ptr)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+}
+func rewriteValueMIPS_OpAtomicLoad32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (AtomicLoad32 ptr mem)
+ // cond:
+ // result: (LoweredAtomicLoad ptr mem)
+ for {
+ ptr := v.Args[0]
+ mem := v.Args[1]
+ v.reset(OpMIPSLoweredAtomicLoad)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+}
+func rewriteValueMIPS_OpAtomicLoadPtr(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (AtomicLoadPtr ptr mem)
+ // cond:
+ // result: (LoweredAtomicLoad ptr mem)
+ for {
+ ptr := v.Args[0]
+ mem := v.Args[1]
+ v.reset(OpMIPSLoweredAtomicLoad)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+}
+func rewriteValueMIPS_OpAtomicOr8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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)
+ for {
+ ptr := v.Args[0]
+ val := v.Args[1]
+ mem := v.Args[2]
+ if !(!config.BigEndian) {
+ break
+ }
+ v.reset(OpMIPSLoweredAtomicOr)
+ v0 := b.NewValue0(v.Line, OpMIPSAND, config.fe.TypeUInt32().PtrTo())
+ v1 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+ 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())
+ v3.AddArg(val)
+ v2.AddArg(v3)
+ v4 := b.NewValue0(v.Line, OpMIPSSLLconst, config.fe.TypeUInt32())
+ v4.AuxInt = 3
+ v5 := b.NewValue0(v.Line, OpMIPSANDconst, config.fe.TypeUInt32())
+ v5.AuxInt = 3
+ v5.AddArg(ptr)
+ v4.AddArg(v5)
+ v2.AddArg(v4)
+ v.AddArg(v2)
+ v.AddArg(mem)
+ return true
+ }
+ // 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)
+ for {
+ ptr := v.Args[0]
+ val := v.Args[1]
+ mem := v.Args[2]
+ if !(config.BigEndian) {
+ break
+ }
+ v.reset(OpMIPSLoweredAtomicOr)
+ v0 := b.NewValue0(v.Line, OpMIPSAND, config.fe.TypeUInt32().PtrTo())
+ v1 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+ 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())
+ v3.AddArg(val)
+ v2.AddArg(v3)
+ v4 := b.NewValue0(v.Line, OpMIPSSLLconst, config.fe.TypeUInt32())
+ v4.AuxInt = 3
+ v5 := b.NewValue0(v.Line, OpMIPSANDconst, config.fe.TypeUInt32())
+ v5.AuxInt = 3
+ v6 := b.NewValue0(v.Line, OpMIPSXORconst, config.fe.TypeUInt32())
+ v6.AuxInt = 3
+ v6.AddArg(ptr)
+ v5.AddArg(v6)
+ v4.AddArg(v5)
+ v2.AddArg(v4)
+ v.AddArg(v2)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS_OpAtomicStore32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (AtomicStore32 ptr val mem)
+ // cond:
+ // result: (LoweredAtomicStore ptr val mem)
+ for {
+ ptr := v.Args[0]
+ val := v.Args[1]
+ mem := v.Args[2]
+ v.reset(OpMIPSLoweredAtomicStore)
+ v.AddArg(ptr)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+}
+func rewriteValueMIPS_OpAtomicStorePtrNoWB(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (AtomicStorePtrNoWB ptr val mem)
+ // cond:
+ // result: (LoweredAtomicStore ptr val mem)
+ for {
+ ptr := v.Args[0]
+ val := v.Args[1]
+ mem := v.Args[2]
+ v.reset(OpMIPSLoweredAtomicStore)
+ v.AddArg(ptr)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+}
+func rewriteValueMIPS_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(OpMIPSCALLclosure)
+ v.AuxInt = argwid
+ v.AddArg(entry)
+ v.AddArg(closure)
+ v.AddArg(mem)
+ return true
+ }
+}
+func rewriteValueMIPS_OpCom16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Com16 x)
+ // cond:
+ // result: (NORconst [0] x)
+ for {
+ x := v.Args[0]
+ v.reset(OpMIPSNORconst)
+ v.AuxInt = 0
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueMIPS_OpCom32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Com32 x)
+ // cond:
+ // result: (NORconst [0] x)
+ for {
+ x := v.Args[0]
+ v.reset(OpMIPSNORconst)
+ v.AuxInt = 0
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueMIPS_OpCom8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Com8 x)
+ // cond:
+ // result: (NORconst [0] x)
+ for {
+ x := v.Args[0]
+ v.reset(OpMIPSNORconst)
+ v.AuxInt = 0
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueMIPS_OpConst16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Const16 [val])
+ // cond:
+ // result: (MOVWconst [val])
+ for {
+ val := v.AuxInt
+ v.reset(OpMIPSMOVWconst)
+ v.AuxInt = val
+ return true
+ }
+}
+func rewriteValueMIPS_OpConst32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Const32 [val])
+ // cond:
+ // result: (MOVWconst [val])
+ for {
+ val := v.AuxInt
+ v.reset(OpMIPSMOVWconst)
+ v.AuxInt = val
+ return true
+ }
+}
+func rewriteValueMIPS_OpConst32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Const32F [val])
+ // cond:
+ // result: (MOVFconst [val])
+ for {
+ val := v.AuxInt
+ v.reset(OpMIPSMOVFconst)
+ v.AuxInt = val
+ return true
+ }
+}
+func rewriteValueMIPS_OpConst64F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Const64F [val])
+ // cond:
+ // result: (MOVDconst [val])
+ for {
+ val := v.AuxInt
+ v.reset(OpMIPSMOVDconst)
+ v.AuxInt = val
+ return true
+ }
+}
+func rewriteValueMIPS_OpConst8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Const8 [val])
+ // cond:
+ // result: (MOVWconst [val])
+ for {
+ val := v.AuxInt
+ v.reset(OpMIPSMOVWconst)
+ v.AuxInt = val
+ return true
+ }
+}
+func rewriteValueMIPS_OpConstBool(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ConstBool [b])
+ // cond:
+ // result: (MOVWconst [b])
+ for {
+ b := v.AuxInt
+ v.reset(OpMIPSMOVWconst)
+ v.AuxInt = b
+ return true
+ }
+}
+func rewriteValueMIPS_OpConstNil(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ConstNil)
+ // cond:
+ // result: (MOVWconst [0])
+ for {
+ v.reset(OpMIPSMOVWconst)
+ v.AuxInt = 0
+ return true
+ }
+}
+func rewriteValueMIPS_OpConvert(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Convert x mem)
+ // cond:
+ // result: (MOVWconvert x mem)
+ for {
+ x := v.Args[0]
+ mem := v.Args[1]
+ v.reset(OpMIPSMOVWconvert)
+ v.AddArg(x)
+ v.AddArg(mem)
+ return true
+ }
+}
+func rewriteValueMIPS_OpCtz32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Ctz32 <t> x)
+ // cond:
+ // result: (SUB (MOVWconst [32]) (CLZ <t> (SUBconst <t> [1] (AND <t> x (NEG <t> x)))))
+ for {
+ t := v.Type
+ x := v.Args[0]
+ v.reset(OpMIPSSUB)
+ v0 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+ v0.AuxInt = 32
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpMIPSCLZ, t)
+ v2 := b.NewValue0(v.Line, OpMIPSSUBconst, t)
+ v2.AuxInt = 1
+ v3 := b.NewValue0(v.Line, OpMIPSAND, t)
+ v3.AddArg(x)
+ v4 := b.NewValue0(v.Line, OpMIPSNEG, t)
+ v4.AddArg(x)
+ v3.AddArg(v4)
+ v2.AddArg(v3)
+ v1.AddArg(v2)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueMIPS_OpCvt32Fto32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Cvt32Fto32 x)
+ // cond:
+ // result: (TRUNCFW x)
+ for {
+ x := v.Args[0]
+ v.reset(OpMIPSTRUNCFW)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueMIPS_OpCvt32Fto64F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Cvt32Fto64F x)
+ // cond:
+ // result: (MOVFD x)
+ for {
+ x := v.Args[0]
+ v.reset(OpMIPSMOVFD)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueMIPS_OpCvt32to32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Cvt32to32F x)
+ // cond:
+ // result: (MOVWF x)
+ for {
+ x := v.Args[0]
+ v.reset(OpMIPSMOVWF)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueMIPS_OpCvt32to64F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Cvt32to64F x)
+ // cond:
+ // result: (MOVWD x)
+ for {
+ x := v.Args[0]
+ v.reset(OpMIPSMOVWD)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueMIPS_OpCvt64Fto32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Cvt64Fto32 x)
+ // cond:
+ // result: (TRUNCDW x)
+ for {
+ x := v.Args[0]
+ v.reset(OpMIPSTRUNCDW)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueMIPS_OpCvt64Fto32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Cvt64Fto32F x)
+ // cond:
+ // result: (MOVDF x)
+ for {
+ x := v.Args[0]
+ v.reset(OpMIPSMOVDF)
+ v.AddArg(x)
+ 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 {
+ b := v.Block
+ _ = b
+ // match: (Div16 x y)
+ // cond:
+ // result: (Select1 (DIV (SignExt16to32 x) (SignExt16to32 y)))
+ for {
+ 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())
+ 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_OpDiv16u(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Div16u x y)
+ // cond:
+ // result: (Select1 (DIVU (ZeroExt16to32 x) (ZeroExt16to32 y)))
+ for {
+ 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())
+ 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_OpDiv32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Div32 x y)
+ // cond:
+ // result: (Select1 (DIV x y))
+ for {
+ 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.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueMIPS_OpDiv32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Div32F x y)
+ // cond:
+ // result: (DIVF x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPSDIVF)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueMIPS_OpDiv32u(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Div32u x y)
+ // cond:
+ // result: (Select1 (DIVU x y))
+ for {
+ 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.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueMIPS_OpDiv64F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Div64F x y)
+ // cond:
+ // result: (DIVD x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPSDIVD)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueMIPS_OpDiv8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Div8 x y)
+ // cond:
+ // result: (Select1 (DIV (SignExt8to32 x) (SignExt8to32 y)))
+ for {
+ 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())
+ 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_OpDiv8u(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Div8u x y)
+ // cond:
+ // result: (Select1 (DIVU (ZeroExt8to32 x) (ZeroExt8to32 y)))
+ for {
+ 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())
+ 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_OpEq16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Eq16 x y)
+ // cond:
+ // result: (SGTUconst [1] (XOR (ZeroExt16to32 x) (ZeroExt16to32 y)))
+ for {
+ 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())
+ 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_OpEq32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Eq32 x y)
+ // cond:
+ // result: (SGTUconst [1] (XOR x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPSSGTUconst)
+ v.AuxInt = 1
+ v0 := b.NewValue0(v.Line, OpMIPSXOR, config.fe.TypeUInt32())
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueMIPS_OpEq32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Eq32F x y)
+ // cond:
+ // result: (FPFlagTrue (CMPEQF x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPSFPFlagTrue)
+ v0 := b.NewValue0(v.Line, OpMIPSCMPEQF, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueMIPS_OpEq64F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Eq64F x y)
+ // cond:
+ // result: (FPFlagTrue (CMPEQD x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPSFPFlagTrue)
+ v0 := b.NewValue0(v.Line, OpMIPSCMPEQD, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueMIPS_OpEq8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Eq8 x y)
+ // cond:
+ // result: (SGTUconst [1] (XOR (ZeroExt8to32 x) (ZeroExt8to32 y)))
+ for {
+ 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())
+ 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_OpEqB(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (EqB x y)
+ // cond:
+ // result: (XORconst [1] (XOR <config.fe.TypeBool()> x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPSXORconst)
+ v.AuxInt = 1
+ v0 := b.NewValue0(v.Line, OpMIPSXOR, config.fe.TypeBool())
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueMIPS_OpEqPtr(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (EqPtr x y)
+ // cond:
+ // result: (SGTUconst [1] (XOR x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPSSGTUconst)
+ v.AuxInt = 1
+ v0 := b.NewValue0(v.Line, OpMIPSXOR, config.fe.TypeUInt32())
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueMIPS_OpGeq16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Geq16 x y)
+ // cond:
+ // result: (XORconst [1] (SGT (SignExt16to32 y) (SignExt16to32 x)))
+ for {
+ 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())
+ v1.AddArg(y)
+ v0.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
+ v2.AddArg(x)
+ v0.AddArg(v2)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueMIPS_OpGeq16U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Geq16U x y)
+ // cond:
+ // result: (XORconst [1] (SGTU (ZeroExt16to32 y) (ZeroExt16to32 x)))
+ for {
+ 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())
+ v1.AddArg(y)
+ v0.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+ v2.AddArg(x)
+ v0.AddArg(v2)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueMIPS_OpGeq32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Geq32 x y)
+ // cond:
+ // result: (XORconst [1] (SGT y x))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPSXORconst)
+ v.AuxInt = 1
+ v0 := b.NewValue0(v.Line, OpMIPSSGT, config.fe.TypeBool())
+ v0.AddArg(y)
+ v0.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueMIPS_OpGeq32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Geq32F x y)
+ // cond:
+ // result: (FPFlagTrue (CMPGEF x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPSFPFlagTrue)
+ v0 := b.NewValue0(v.Line, OpMIPSCMPGEF, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueMIPS_OpGeq32U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Geq32U x y)
+ // cond:
+ // result: (XORconst [1] (SGTU y x))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPSXORconst)
+ v.AuxInt = 1
+ v0 := b.NewValue0(v.Line, OpMIPSSGTU, config.fe.TypeBool())
+ v0.AddArg(y)
+ v0.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueMIPS_OpGeq64F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Geq64F x y)
+ // cond:
+ // result: (FPFlagTrue (CMPGED x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPSFPFlagTrue)
+ v0 := b.NewValue0(v.Line, OpMIPSCMPGED, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueMIPS_OpGeq8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Geq8 x y)
+ // cond:
+ // result: (XORconst [1] (SGT (SignExt8to32 y) (SignExt8to32 x)))
+ for {
+ 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())
+ v1.AddArg(y)
+ v0.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpSignExt8to32, config.fe.TypeInt32())
+ v2.AddArg(x)
+ v0.AddArg(v2)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueMIPS_OpGeq8U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Geq8U x y)
+ // cond:
+ // result: (XORconst [1] (SGTU (ZeroExt8to32 y) (ZeroExt8to32 x)))
+ for {
+ 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())
+ v1.AddArg(y)
+ v0.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+ v2.AddArg(x)
+ v0.AddArg(v2)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueMIPS_OpGetClosurePtr(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (GetClosurePtr)
+ // cond:
+ // result: (LoweredGetClosurePtr)
+ for {
+ v.reset(OpMIPSLoweredGetClosurePtr)
+ 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 {
+ b := v.Block
+ _ = b
+ // match: (Greater16 x y)
+ // cond:
+ // result: (SGT (SignExt16to32 x) (SignExt16to32 y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPSSGT)
+ v0 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
+ v1.AddArg(y)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueMIPS_OpGreater16U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Greater16U x y)
+ // cond:
+ // result: (SGTU (ZeroExt16to32 x) (ZeroExt16to32 y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPSSGTU)
+ v0 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+ v1.AddArg(y)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueMIPS_OpGreater32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Greater32 x y)
+ // cond:
+ // result: (SGT x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPSSGT)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueMIPS_OpGreater32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Greater32F x y)
+ // cond:
+ // result: (FPFlagTrue (CMPGTF x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPSFPFlagTrue)
+ v0 := b.NewValue0(v.Line, OpMIPSCMPGTF, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueMIPS_OpGreater32U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Greater32U x y)
+ // cond:
+ // result: (SGTU x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPSSGTU)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueMIPS_OpGreater64F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Greater64F x y)
+ // cond:
+ // result: (FPFlagTrue (CMPGTD x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPSFPFlagTrue)
+ v0 := b.NewValue0(v.Line, OpMIPSCMPGTD, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueMIPS_OpGreater8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Greater8 x y)
+ // cond:
+ // result: (SGT (SignExt8to32 x) (SignExt8to32 y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPSSGT)
+ v0 := b.NewValue0(v.Line, OpSignExt8to32, config.fe.TypeInt32())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpSignExt8to32, config.fe.TypeInt32())
+ v1.AddArg(y)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueMIPS_OpGreater8U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Greater8U x y)
+ // cond:
+ // result: (SGTU (ZeroExt8to32 x) (ZeroExt8to32 y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPSSGTU)
+ v0 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+ 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 {
+ b := v.Block
+ _ = b
+ // match: (Hmul32 x y)
+ // cond:
+ // result: (Select0 (MULT x y))
+ for {
+ 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.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueMIPS_OpHmul32u(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Hmul32u x y)
+ // cond:
+ // result: (Select0 (MULTU x y))
+ for {
+ 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.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
+ // 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(OpMIPSCALLinter)
+ v.AuxInt = argwid
+ v.AddArg(entry)
+ v.AddArg(mem)
+ return true
+ }
+}
+func rewriteValueMIPS_OpIsInBounds(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (IsInBounds idx len)
+ // cond:
+ // result: (SGTU len idx)
+ for {
+ idx := v.Args[0]
+ len := v.Args[1]
+ v.reset(OpMIPSSGTU)
+ v.AddArg(len)
+ v.AddArg(idx)
+ return true
+ }
+}
+func rewriteValueMIPS_OpIsNonNil(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (IsNonNil ptr)
+ // cond:
+ // result: (SGTU ptr (MOVWconst [0]))
+ for {
+ ptr := v.Args[0]
+ v.reset(OpMIPSSGTU)
+ v.AddArg(ptr)
+ v0 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+ v0.AuxInt = 0
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueMIPS_OpIsSliceInBounds(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (IsSliceInBounds idx len)
+ // cond:
+ // result: (XORconst [1] (SGTU idx len))
+ for {
+ idx := v.Args[0]
+ len := v.Args[1]
+ v.reset(OpMIPSXORconst)
+ v.AuxInt = 1
+ v0 := b.NewValue0(v.Line, OpMIPSSGTU, config.fe.TypeBool())
+ v0.AddArg(idx)
+ v0.AddArg(len)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueMIPS_OpLeq16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Leq16 x y)
+ // cond:
+ // result: (XORconst [1] (SGT (SignExt16to32 x) (SignExt16to32 y)))
+ for {
+ 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())
+ 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_OpLeq16U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Leq16U x y)
+ // cond:
+ // result: (XORconst [1] (SGTU (ZeroExt16to32 x) (ZeroExt16to32 y)))
+ for {
+ 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())
+ 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_OpLeq32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Leq32 x y)
+ // cond:
+ // result: (XORconst [1] (SGT x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPSXORconst)
+ v.AuxInt = 1
+ v0 := b.NewValue0(v.Line, OpMIPSSGT, config.fe.TypeBool())
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueMIPS_OpLeq32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Leq32F x y)
+ // cond:
+ // result: (FPFlagTrue (CMPGEF y x))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPSFPFlagTrue)
+ v0 := b.NewValue0(v.Line, OpMIPSCMPGEF, TypeFlags)
+ v0.AddArg(y)
+ v0.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueMIPS_OpLeq32U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Leq32U x y)
+ // cond:
+ // result: (XORconst [1] (SGTU x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPSXORconst)
+ v.AuxInt = 1
+ v0 := b.NewValue0(v.Line, OpMIPSSGTU, config.fe.TypeBool())
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueMIPS_OpLeq64F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Leq64F x y)
+ // cond:
+ // result: (FPFlagTrue (CMPGED y x))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPSFPFlagTrue)
+ v0 := b.NewValue0(v.Line, OpMIPSCMPGED, TypeFlags)
+ v0.AddArg(y)
+ v0.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueMIPS_OpLeq8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Leq8 x y)
+ // cond:
+ // result: (XORconst [1] (SGT (SignExt8to32 x) (SignExt8to32 y)))
+ for {
+ 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())
+ 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_OpLeq8U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Leq8U x y)
+ // cond:
+ // result: (XORconst [1] (SGTU (ZeroExt8to32 x) (ZeroExt8to32 y)))
+ for {
+ 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())
+ 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_OpLess16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Less16 x y)
+ // cond:
+ // result: (SGT (SignExt16to32 y) (SignExt16to32 x))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPSSGT)
+ v0 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
+ v0.AddArg(y)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
+ v1.AddArg(x)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueMIPS_OpLess16U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Less16U x y)
+ // cond:
+ // result: (SGTU (ZeroExt16to32 y) (ZeroExt16to32 x))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPSSGTU)
+ v0 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+ v0.AddArg(y)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+ v1.AddArg(x)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueMIPS_OpLess32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Less32 x y)
+ // cond:
+ // result: (SGT y x)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPSSGT)
+ v.AddArg(y)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueMIPS_OpLess32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Less32F x y)
+ // cond:
+ // result: (FPFlagTrue (CMPGTF y x))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPSFPFlagTrue)
+ v0 := b.NewValue0(v.Line, OpMIPSCMPGTF, TypeFlags)
+ v0.AddArg(y)
+ v0.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueMIPS_OpLess32U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Less32U x y)
+ // cond:
+ // result: (SGTU y x)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPSSGTU)
+ v.AddArg(y)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueMIPS_OpLess64F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Less64F x y)
+ // cond:
+ // result: (FPFlagTrue (CMPGTD y x))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPSFPFlagTrue)
+ v0 := b.NewValue0(v.Line, OpMIPSCMPGTD, TypeFlags)
+ v0.AddArg(y)
+ v0.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueMIPS_OpLess8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Less8 x y)
+ // cond:
+ // result: (SGT (SignExt8to32 y) (SignExt8to32 x))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPSSGT)
+ v0 := b.NewValue0(v.Line, OpSignExt8to32, config.fe.TypeInt32())
+ v0.AddArg(y)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpSignExt8to32, config.fe.TypeInt32())
+ v1.AddArg(x)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueMIPS_OpLess8U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Less8U x y)
+ // cond:
+ // result: (SGTU (ZeroExt8to32 y) (ZeroExt8to32 x))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPSSGTU)
+ v0 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+ v0.AddArg(y)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+ v1.AddArg(x)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueMIPS_OpLoad(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Load <t> ptr mem)
+ // cond: t.IsBoolean()
+ // result: (MOVBUload ptr mem)
+ for {
+ t := v.Type
+ ptr := v.Args[0]
+ mem := v.Args[1]
+ if !(t.IsBoolean()) {
+ break
+ }
+ v.reset(OpMIPSMOVBUload)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (Load <t> ptr mem)
+ // cond: (is8BitInt(t) && isSigned(t))
+ // result: (MOVBload ptr mem)
+ for {
+ t := v.Type
+ ptr := v.Args[0]
+ mem := v.Args[1]
+ if !(is8BitInt(t) && isSigned(t)) {
+ break
+ }
+ v.reset(OpMIPSMOVBload)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (Load <t> ptr mem)
+ // cond: (is8BitInt(t) && !isSigned(t))
+ // result: (MOVBUload ptr mem)
+ for {
+ t := v.Type
+ ptr := v.Args[0]
+ mem := v.Args[1]
+ if !(is8BitInt(t) && !isSigned(t)) {
+ break
+ }
+ v.reset(OpMIPSMOVBUload)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (Load <t> ptr mem)
+ // cond: (is16BitInt(t) && isSigned(t))
+ // result: (MOVHload ptr mem)
+ for {
+ t := v.Type
+ ptr := v.Args[0]
+ mem := v.Args[1]
+ if !(is16BitInt(t) && isSigned(t)) {
+ break
+ }
+ v.reset(OpMIPSMOVHload)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (Load <t> ptr mem)
+ // cond: (is16BitInt(t) && !isSigned(t))
+ // result: (MOVHUload ptr mem)
+ for {
+ t := v.Type
+ ptr := v.Args[0]
+ mem := v.Args[1]
+ if !(is16BitInt(t) && !isSigned(t)) {
+ break
+ }
+ v.reset(OpMIPSMOVHUload)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (Load <t> ptr mem)
+ // cond: (is32BitInt(t) || isPtr(t))
+ // result: (MOVWload ptr mem)
+ for {
+ t := v.Type
+ ptr := v.Args[0]
+ mem := v.Args[1]
+ if !(is32BitInt(t) || isPtr(t)) {
+ break
+ }
+ v.reset(OpMIPSMOVWload)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (Load <t> ptr mem)
+ // cond: is32BitFloat(t)
+ // result: (MOVFload ptr mem)
+ for {
+ t := v.Type
+ ptr := v.Args[0]
+ mem := v.Args[1]
+ if !(is32BitFloat(t)) {
+ break
+ }
+ v.reset(OpMIPSMOVFload)
+ v.AddArg(ptr)
+ 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(OpMIPSMOVDload)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS_OpLsh16x16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Lsh16x16 <t> x y)
+ // cond:
+ // result: (CMOVZ (SLL <t> x (ZeroExt16to32 y) ) (MOVWconst [0]) (SGTUconst [32] (ZeroExt16to32 y)))
+ for {
+ t := v.Type
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPSCMOVZ)
+ v0 := b.NewValue0(v.Line, OpMIPSSLL, t)
+ v0.AddArg(x)
+ v1 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+ v1.AddArg(y)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ v2 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+ v2.AuxInt = 0
+ v.AddArg(v2)
+ v3 := b.NewValue0(v.Line, OpMIPSSGTUconst, config.fe.TypeBool())
+ v3.AuxInt = 32
+ v4 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+ v4.AddArg(y)
+ v3.AddArg(v4)
+ v.AddArg(v3)
+ return true
+ }
+}
+func rewriteValueMIPS_OpLsh16x32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Lsh16x32 <t> x y)
+ // cond:
+ // result: (CMOVZ (SLL <t> x y) (MOVWconst [0]) (SGTUconst [32] y))
+ for {
+ t := v.Type
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPSCMOVZ)
+ v0 := b.NewValue0(v.Line, OpMIPSSLL, t)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+ v1.AuxInt = 0
+ v.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpMIPSSGTUconst, config.fe.TypeBool())
+ v2.AuxInt = 32
+ v2.AddArg(y)
+ v.AddArg(v2)
+ return true
+ }
+}
+func rewriteValueMIPS_OpLsh16x64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Lsh16x64 x (Const64 [c]))
+ // cond: uint32(c) < 16
+ // result: (SLLconst x [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpConst64 {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint32(c) < 16) {
+ break
+ }
+ v.reset(OpMIPSSLLconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (Lsh16x64 _ (Const64 [c]))
+ // cond: uint32(c) >= 16
+ // result: (MOVWconst [0])
+ for {
+ v_1 := v.Args[1]
+ if v_1.Op != OpConst64 {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint32(c) >= 16) {
+ break
+ }
+ v.reset(OpMIPSMOVWconst)
+ v.AuxInt = 0
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS_OpLsh16x8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Lsh16x8 <t> x y)
+ // cond:
+ // result: (CMOVZ (SLL <t> x (ZeroExt8to32 y) ) (MOVWconst [0]) (SGTUconst [32] (ZeroExt8to32 y)))
+ for {
+ t := v.Type
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPSCMOVZ)
+ v0 := b.NewValue0(v.Line, OpMIPSSLL, t)
+ v0.AddArg(x)
+ v1 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+ v1.AddArg(y)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ v2 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+ v2.AuxInt = 0
+ v.AddArg(v2)
+ v3 := b.NewValue0(v.Line, OpMIPSSGTUconst, config.fe.TypeBool())
+ v3.AuxInt = 32
+ v4 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+ v4.AddArg(y)
+ v3.AddArg(v4)
+ v.AddArg(v3)
+ return true
+ }
+}
+func rewriteValueMIPS_OpLsh32x16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Lsh32x16 <t> x y)
+ // cond:
+ // result: (CMOVZ (SLL <t> x (ZeroExt16to32 y) ) (MOVWconst [0]) (SGTUconst [32] (ZeroExt16to32 y)))
+ for {
+ t := v.Type
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPSCMOVZ)
+ v0 := b.NewValue0(v.Line, OpMIPSSLL, t)
+ v0.AddArg(x)
+ v1 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+ v1.AddArg(y)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ v2 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+ v2.AuxInt = 0
+ v.AddArg(v2)
+ v3 := b.NewValue0(v.Line, OpMIPSSGTUconst, config.fe.TypeBool())
+ v3.AuxInt = 32
+ v4 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+ v4.AddArg(y)
+ v3.AddArg(v4)
+ v.AddArg(v3)
+ return true
+ }
+}
+func rewriteValueMIPS_OpLsh32x32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Lsh32x32 <t> x y)
+ // cond:
+ // result: (CMOVZ (SLL <t> x y) (MOVWconst [0]) (SGTUconst [32] y))
+ for {
+ t := v.Type
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPSCMOVZ)
+ v0 := b.NewValue0(v.Line, OpMIPSSLL, t)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+ v1.AuxInt = 0
+ v.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpMIPSSGTUconst, config.fe.TypeBool())
+ v2.AuxInt = 32
+ v2.AddArg(y)
+ v.AddArg(v2)
+ return true
+ }
+}
+func rewriteValueMIPS_OpLsh32x64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Lsh32x64 x (Const64 [c]))
+ // cond: uint32(c) < 32
+ // result: (SLLconst x [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpConst64 {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint32(c) < 32) {
+ break
+ }
+ v.reset(OpMIPSSLLconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (Lsh32x64 _ (Const64 [c]))
+ // cond: uint32(c) >= 32
+ // result: (MOVWconst [0])
+ for {
+ v_1 := v.Args[1]
+ if v_1.Op != OpConst64 {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint32(c) >= 32) {
+ break
+ }
+ v.reset(OpMIPSMOVWconst)
+ v.AuxInt = 0
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS_OpLsh32x8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Lsh32x8 <t> x y)
+ // cond:
+ // result: (CMOVZ (SLL <t> x (ZeroExt8to32 y) ) (MOVWconst [0]) (SGTUconst [32] (ZeroExt8to32 y)))
+ for {
+ t := v.Type
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPSCMOVZ)
+ v0 := b.NewValue0(v.Line, OpMIPSSLL, t)
+ v0.AddArg(x)
+ v1 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+ v1.AddArg(y)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ v2 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+ v2.AuxInt = 0
+ v.AddArg(v2)
+ v3 := b.NewValue0(v.Line, OpMIPSSGTUconst, config.fe.TypeBool())
+ v3.AuxInt = 32
+ v4 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+ v4.AddArg(y)
+ v3.AddArg(v4)
+ v.AddArg(v3)
+ return true
+ }
+}
+func rewriteValueMIPS_OpLsh8x16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Lsh8x16 <t> x y)
+ // cond:
+ // result: (CMOVZ (SLL <t> x (ZeroExt16to32 y) ) (MOVWconst [0]) (SGTUconst [32] (ZeroExt16to32 y)))
+ for {
+ t := v.Type
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPSCMOVZ)
+ v0 := b.NewValue0(v.Line, OpMIPSSLL, t)
+ v0.AddArg(x)
+ v1 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+ v1.AddArg(y)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ v2 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+ v2.AuxInt = 0
+ v.AddArg(v2)
+ v3 := b.NewValue0(v.Line, OpMIPSSGTUconst, config.fe.TypeBool())
+ v3.AuxInt = 32
+ v4 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+ v4.AddArg(y)
+ v3.AddArg(v4)
+ v.AddArg(v3)
+ return true
+ }
+}
+func rewriteValueMIPS_OpLsh8x32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Lsh8x32 <t> x y)
+ // cond:
+ // result: (CMOVZ (SLL <t> x y) (MOVWconst [0]) (SGTUconst [32] y))
+ for {
+ t := v.Type
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPSCMOVZ)
+ v0 := b.NewValue0(v.Line, OpMIPSSLL, t)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+ v1.AuxInt = 0
+ v.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpMIPSSGTUconst, config.fe.TypeBool())
+ v2.AuxInt = 32
+ v2.AddArg(y)
+ v.AddArg(v2)
+ return true
+ }
+}
+func rewriteValueMIPS_OpLsh8x64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Lsh8x64 x (Const64 [c]))
+ // cond: uint32(c) < 8
+ // result: (SLLconst x [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpConst64 {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint32(c) < 8) {
+ break
+ }
+ v.reset(OpMIPSSLLconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (Lsh8x64 _ (Const64 [c]))
+ // cond: uint32(c) >= 8
+ // result: (MOVWconst [0])
+ for {
+ v_1 := v.Args[1]
+ if v_1.Op != OpConst64 {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint32(c) >= 8) {
+ break
+ }
+ v.reset(OpMIPSMOVWconst)
+ v.AuxInt = 0
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS_OpLsh8x8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Lsh8x8 <t> x y)
+ // cond:
+ // result: (CMOVZ (SLL <t> x (ZeroExt8to32 y) ) (MOVWconst [0]) (SGTUconst [32] (ZeroExt8to32 y)))
+ for {
+ t := v.Type
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPSCMOVZ)
+ v0 := b.NewValue0(v.Line, OpMIPSSLL, t)
+ v0.AddArg(x)
+ v1 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+ v1.AddArg(y)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ v2 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+ v2.AuxInt = 0
+ v.AddArg(v2)
+ v3 := b.NewValue0(v.Line, OpMIPSSGTUconst, config.fe.TypeBool())
+ v3.AuxInt = 32
+ v4 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+ 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)
+ // cond:
+ // result: (ADDconst [c] x)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPSMOVWconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ v.reset(OpMIPSADDconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (ADD x (MOVWconst [c]))
+ // cond:
+ // result: (ADDconst [c] x)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpMIPSMOVWconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpMIPSADDconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (ADD x (NEG y))
+ // cond:
+ // result: (SUB x y)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpMIPSNEG {
+ break
+ }
+ y := v_1.Args[0]
+ v.reset(OpMIPSSUB)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (ADD (NEG y) x)
+ // cond:
+ // result: (SUB x y)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPSNEG {
+ break
+ }
+ y := v_0.Args[0]
+ x := v.Args[1]
+ v.reset(OpMIPSSUB)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS_OpMIPSADDconst(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ADDconst [off1] (MOVWaddr [off2] {sym} ptr))
+ // cond:
+ // result: (MOVWaddr [off1+off2] {sym} ptr)
+ for {
+ off1 := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPSMOVWaddr {
+ break
+ }
+ off2 := v_0.AuxInt
+ sym := v_0.Aux
+ ptr := v_0.Args[0]
+ v.reset(OpMIPSMOVWaddr)
+ v.AuxInt = off1 + off2
+ v.Aux = sym
+ v.AddArg(ptr)
+ return true
+ }
+ // match: (ADDconst [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: (ADDconst [c] (MOVWconst [d]))
+ // cond:
+ // result: (MOVWconst [int64(int32(c+d))])
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPSMOVWconst {
+ break
+ }
+ d := v_0.AuxInt
+ v.reset(OpMIPSMOVWconst)
+ v.AuxInt = int64(int32(c + d))
+ return true
+ }
+ // match: (ADDconst [c] (ADDconst [d] x))
+ // cond:
+ // result: (ADDconst [int64(int32(c+d))] x)
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPSADDconst {
+ break
+ }
+ d := v_0.AuxInt
+ x := v_0.Args[0]
+ v.reset(OpMIPSADDconst)
+ v.AuxInt = int64(int32(c + d))
+ v.AddArg(x)
+ return true
+ }
+ // match: (ADDconst [c] (SUBconst [d] x))
+ // cond:
+ // result: (ADDconst [int64(int32(c-d))] x)
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPSSUBconst {
+ break
+ }
+ d := v_0.AuxInt
+ x := v_0.Args[0]
+ v.reset(OpMIPSADDconst)
+ v.AuxInt = int64(int32(c - d))
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS_OpMIPSAND(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (AND (MOVWconst [c]) x)
+ // cond:
+ // result: (ANDconst [c] x)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPSMOVWconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ v.reset(OpMIPSANDconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (AND x (MOVWconst [c]))
+ // cond:
+ // result: (ANDconst [c] x)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpMIPSMOVWconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpMIPSANDconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (AND 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: (AND (SGTUconst [1] x) (SGTUconst [1] y))
+ // cond:
+ // result: (SGTUconst [1] (OR <x.Type> x y))
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPSSGTUconst {
+ break
+ }
+ if v_0.AuxInt != 1 {
+ break
+ }
+ x := v_0.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpMIPSSGTUconst {
+ break
+ }
+ if v_1.AuxInt != 1 {
+ break
+ }
+ y := v_1.Args[0]
+ v.reset(OpMIPSSGTUconst)
+ v.AuxInt = 1
+ v0 := b.NewValue0(v.Line, 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] _)
+ // cond:
+ // result: (MOVWconst [0])
+ for {
+ if v.AuxInt != 0 {
+ break
+ }
+ v.reset(OpMIPSMOVWconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (ANDconst [-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: (ANDconst [c] (MOVWconst [d]))
+ // cond:
+ // result: (MOVWconst [c&d])
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPSMOVWconst {
+ break
+ }
+ d := v_0.AuxInt
+ v.reset(OpMIPSMOVWconst)
+ v.AuxInt = c & d
+ return true
+ }
+ // match: (ANDconst [c] (ANDconst [d] x))
+ // cond:
+ // result: (ANDconst [c&d] x)
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPSANDconst {
+ break
+ }
+ d := v_0.AuxInt
+ x := v_0.Args[0]
+ v.reset(OpMIPSANDconst)
+ v.AuxInt = c & d
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS_OpMIPSCMOVZ(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (CMOVZ _ b (MOVWconst [0]))
+ // cond:
+ // result: b
+ for {
+ b := v.Args[1]
+ v_2 := v.Args[2]
+ if v_2.Op != OpMIPSMOVWconst {
+ break
+ }
+ if v_2.AuxInt != 0 {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = b.Type
+ v.AddArg(b)
+ return true
+ }
+ // match: (CMOVZ a _ (MOVWconst [c]))
+ // cond: c!=0
+ // result: a
+ for {
+ a := v.Args[0]
+ v_2 := v.Args[2]
+ if v_2.Op != OpMIPSMOVWconst {
+ break
+ }
+ c := v_2.AuxInt
+ if !(c != 0) {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = a.Type
+ v.AddArg(a)
+ return true
+ }
+ // match: (CMOVZ a (MOVWconst [0]) c)
+ // cond:
+ // result: (CMOVZzero a c)
+ for {
+ a := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpMIPSMOVWconst {
+ break
+ }
+ if v_1.AuxInt != 0 {
+ break
+ }
+ c := v.Args[2]
+ v.reset(OpMIPSCMOVZzero)
+ v.AddArg(a)
+ v.AddArg(c)
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS_OpMIPSCMOVZzero(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (CMOVZzero _ (MOVWconst [0]))
+ // cond:
+ // result: (MOVWconst [0])
+ for {
+ 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: (CMOVZzero a (MOVWconst [c]))
+ // cond: c!=0
+ // result: a
+ for {
+ a := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpMIPSMOVWconst {
+ break
+ }
+ c := v_1.AuxInt
+ if !(c != 0) {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = a.Type
+ v.AddArg(a)
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS_OpMIPSLoweredAtomicAdd(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (LoweredAtomicAdd ptr (MOVWconst [c]) mem)
+ // cond: is16Bit(c)
+ // result: (LoweredAtomicAddconst [c] ptr mem)
+ for {
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpMIPSMOVWconst {
+ break
+ }
+ c := v_1.AuxInt
+ mem := v.Args[2]
+ if !(is16Bit(c)) {
+ break
+ }
+ v.reset(OpMIPSLoweredAtomicAddconst)
+ v.AuxInt = c
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS_OpMIPSLoweredAtomicStore(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (LoweredAtomicStore ptr (MOVWconst [0]) mem)
+ // cond:
+ // result: (LoweredAtomicStorezero ptr mem)
+ for {
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpMIPSMOVWconst {
+ break
+ }
+ if v_1.AuxInt != 0 {
+ break
+ }
+ mem := v.Args[2]
+ v.reset(OpMIPSLoweredAtomicStorezero)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS_OpMIPSMOVBUload(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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
+ x := v.Args[0]
+ if x.Op != OpMIPSADDconst {
+ break
+ }
+ off2 := x.AuxInt
+ ptr := x.Args[0]
+ mem := v.Args[1]
+ if !(is16Bit(off1+off2) || x.Uses == 1) {
+ break
+ }
+ v.reset(OpMIPSMOVBUload)
+ 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_0 := v.Args[0]
+ if v_0.Op != OpMIPSMOVWaddr {
+ break
+ }
+ off2 := v_0.AuxInt
+ sym2 := v_0.Aux
+ ptr := v_0.Args[0]
+ mem := v.Args[1]
+ if !(canMergeSym(sym1, sym2)) {
+ break
+ }
+ v.reset(OpMIPSMOVBUload)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ 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
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpMIPSMOVBstore {
+ 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) && !isSigned(x.Type)) {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS_OpMIPSMOVBUreg(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (MOVBUreg x:(MOVBUload _ _))
+ // cond:
+ // result: (MOVWreg x)
+ for {
+ x := v.Args[0]
+ if x.Op != OpMIPSMOVBUload {
+ break
+ }
+ v.reset(OpMIPSMOVWreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVBUreg x:(MOVBUreg _))
+ // cond:
+ // result: (MOVWreg x)
+ for {
+ x := v.Args[0]
+ if x.Op != OpMIPSMOVBUreg {
+ break
+ }
+ v.reset(OpMIPSMOVWreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVBUreg <t> x:(MOVBload [off] {sym} ptr mem))
+ // cond: x.Uses == 1 && clobber(x)
+ // result: @x.Block (MOVBUload <t> [off] {sym} ptr mem)
+ for {
+ t := v.Type
+ x := v.Args[0]
+ if x.Op != OpMIPSMOVBload {
+ 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, OpMIPSMOVBUload, t)
+ v.reset(OpCopy)
+ v.AddArg(v0)
+ v0.AuxInt = off
+ v0.Aux = sym
+ v0.AddArg(ptr)
+ v0.AddArg(mem)
+ return true
+ }
+ // match: (MOVBUreg (ANDconst [c] x))
+ // cond:
+ // result: (ANDconst [c&0xff] x)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPSANDconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v_0.Args[0]
+ v.reset(OpMIPSANDconst)
+ v.AuxInt = c & 0xff
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVBUreg (MOVWconst [c]))
+ // cond:
+ // result: (MOVWconst [int64(uint8(c))])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPSMOVWconst {
+ break
+ }
+ c := v_0.AuxInt
+ v.reset(OpMIPSMOVWconst)
+ v.AuxInt = int64(uint8(c))
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS_OpMIPSMOVBload(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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
+ x := v.Args[0]
+ if x.Op != OpMIPSADDconst {
+ break
+ }
+ off2 := x.AuxInt
+ ptr := x.Args[0]
+ mem := v.Args[1]
+ if !(is16Bit(off1+off2) || x.Uses == 1) {
+ break
+ }
+ v.reset(OpMIPSMOVBload)
+ 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_0 := v.Args[0]
+ if v_0.Op != OpMIPSMOVWaddr {
+ break
+ }
+ off2 := v_0.AuxInt
+ sym2 := v_0.Aux
+ ptr := v_0.Args[0]
+ mem := v.Args[1]
+ if !(canMergeSym(sym1, sym2)) {
+ break
+ }
+ v.reset(OpMIPSMOVBload)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ 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
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpMIPSMOVBstore {
+ 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) && isSigned(x.Type)) {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS_OpMIPSMOVBreg(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (MOVBreg x:(MOVBload _ _))
+ // cond:
+ // result: (MOVWreg x)
+ for {
+ x := v.Args[0]
+ if x.Op != OpMIPSMOVBload {
+ break
+ }
+ v.reset(OpMIPSMOVWreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVBreg x:(MOVBreg _))
+ // cond:
+ // result: (MOVWreg x)
+ for {
+ x := v.Args[0]
+ if x.Op != OpMIPSMOVBreg {
+ break
+ }
+ v.reset(OpMIPSMOVWreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVBreg <t> x:(MOVBUload [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 != OpMIPSMOVBUload {
+ 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, OpMIPSMOVBload, t)
+ v.reset(OpCopy)
+ v.AddArg(v0)
+ v0.AuxInt = off
+ v0.Aux = sym
+ v0.AddArg(ptr)
+ v0.AddArg(mem)
+ return true
+ }
+ // match: (MOVBreg (ANDconst [c] x))
+ // cond: c & 0x80 == 0
+ // result: (ANDconst [c&0x7f] x)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPSANDconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v_0.Args[0]
+ if !(c&0x80 == 0) {
+ break
+ }
+ v.reset(OpMIPSANDconst)
+ v.AuxInt = c & 0x7f
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVBreg (MOVWconst [c]))
+ // cond:
+ // result: (MOVWconst [int64(int8(c))])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPSMOVWconst {
+ break
+ }
+ c := v_0.AuxInt
+ v.reset(OpMIPSMOVWconst)
+ v.AuxInt = int64(int8(c))
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS_OpMIPSMOVBstore(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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
+ x := v.Args[0]
+ if x.Op != OpMIPSADDconst {
+ break
+ }
+ off2 := x.AuxInt
+ ptr := x.Args[0]
+ val := v.Args[1]
+ mem := v.Args[2]
+ if !(is16Bit(off1+off2) || x.Uses == 1) {
+ break
+ }
+ v.reset(OpMIPSMOVBstore)
+ 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_0 := v.Args[0]
+ if v_0.Op != OpMIPSMOVWaddr {
+ 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(OpMIPSMOVBstore)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(ptr)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVBstore [off] {sym} ptr (MOVWconst [0]) mem)
+ // cond:
+ // result: (MOVBstorezero [off] {sym} ptr mem)
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpMIPSMOVWconst {
+ break
+ }
+ if v_1.AuxInt != 0 {
+ break
+ }
+ mem := v.Args[2]
+ v.reset(OpMIPSMOVBstorezero)
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVBstore [off] {sym} ptr (MOVBreg x) mem)
+ // cond:
+ // result: (MOVBstore [off] {sym} ptr x mem)
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpMIPSMOVBreg {
+ break
+ }
+ x := v_1.Args[0]
+ mem := v.Args[2]
+ v.reset(OpMIPSMOVBstore)
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(x)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVBstore [off] {sym} ptr (MOVBUreg x) mem)
+ // cond:
+ // result: (MOVBstore [off] {sym} ptr x mem)
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpMIPSMOVBUreg {
+ break
+ }
+ x := v_1.Args[0]
+ mem := v.Args[2]
+ v.reset(OpMIPSMOVBstore)
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(x)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVBstore [off] {sym} ptr (MOVHreg x) mem)
+ // cond:
+ // result: (MOVBstore [off] {sym} ptr x mem)
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpMIPSMOVHreg {
+ break
+ }
+ x := v_1.Args[0]
+ mem := v.Args[2]
+ v.reset(OpMIPSMOVBstore)
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(x)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVBstore [off] {sym} ptr (MOVHUreg x) mem)
+ // cond:
+ // result: (MOVBstore [off] {sym} ptr x mem)
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpMIPSMOVHUreg {
+ break
+ }
+ x := v_1.Args[0]
+ mem := v.Args[2]
+ v.reset(OpMIPSMOVBstore)
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(x)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVBstore [off] {sym} ptr (MOVWreg x) mem)
+ // cond:
+ // result: (MOVBstore [off] {sym} ptr x mem)
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpMIPSMOVWreg {
+ break
+ }
+ x := v_1.Args[0]
+ mem := v.Args[2]
+ v.reset(OpMIPSMOVBstore)
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(x)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS_OpMIPSMOVBstorezero(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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
+ x := v.Args[0]
+ if x.Op != OpMIPSADDconst {
+ break
+ }
+ off2 := x.AuxInt
+ ptr := x.Args[0]
+ mem := v.Args[1]
+ if !(is16Bit(off1+off2) || x.Uses == 1) {
+ break
+ }
+ v.reset(OpMIPSMOVBstorezero)
+ v.AuxInt = off1 + off2
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVBstorezero [off1] {sym1} (MOVWaddr [off2] {sym2} ptr) mem)
+ // cond: canMergeSym(sym1,sym2)
+ // result: (MOVBstorezero [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
+ for {
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPSMOVWaddr {
+ break
+ }
+ off2 := v_0.AuxInt
+ sym2 := v_0.Aux
+ ptr := v_0.Args[0]
+ mem := v.Args[1]
+ if !(canMergeSym(sym1, sym2)) {
+ break
+ }
+ v.reset(OpMIPSMOVBstorezero)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS_OpMIPSMOVDload(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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
+ x := v.Args[0]
+ if x.Op != OpMIPSADDconst {
+ break
+ }
+ off2 := x.AuxInt
+ ptr := x.Args[0]
+ mem := v.Args[1]
+ if !(is16Bit(off1+off2) || x.Uses == 1) {
+ break
+ }
+ v.reset(OpMIPSMOVDload)
+ 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_0 := v.Args[0]
+ if v_0.Op != OpMIPSMOVWaddr {
+ break
+ }
+ off2 := v_0.AuxInt
+ sym2 := v_0.Aux
+ ptr := v_0.Args[0]
+ mem := v.Args[1]
+ if !(canMergeSym(sym1, sym2)) {
+ break
+ }
+ v.reset(OpMIPSMOVDload)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVDload [off] {sym} ptr (MOVDstore [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 != OpMIPSMOVDstore {
+ break
+ }
+ off2 := v_1.AuxInt
+ sym2 := v_1.Aux
+ ptr2 := v_1.Args[0]
+ x := v_1.Args[1]
+ if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS_OpMIPSMOVDstore(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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
+ x := v.Args[0]
+ if x.Op != OpMIPSADDconst {
+ break
+ }
+ off2 := x.AuxInt
+ ptr := x.Args[0]
+ val := v.Args[1]
+ mem := v.Args[2]
+ if !(is16Bit(off1+off2) || x.Uses == 1) {
+ break
+ }
+ v.reset(OpMIPSMOVDstore)
+ 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_0 := v.Args[0]
+ if v_0.Op != OpMIPSMOVWaddr {
+ 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(OpMIPSMOVDstore)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(ptr)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS_OpMIPSMOVFload(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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
+ x := v.Args[0]
+ if x.Op != OpMIPSADDconst {
+ break
+ }
+ off2 := x.AuxInt
+ ptr := x.Args[0]
+ mem := v.Args[1]
+ if !(is16Bit(off1+off2) || x.Uses == 1) {
+ break
+ }
+ v.reset(OpMIPSMOVFload)
+ 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_0 := v.Args[0]
+ if v_0.Op != OpMIPSMOVWaddr {
+ break
+ }
+ off2 := v_0.AuxInt
+ sym2 := v_0.Aux
+ ptr := v_0.Args[0]
+ mem := v.Args[1]
+ if !(canMergeSym(sym1, sym2)) {
+ break
+ }
+ v.reset(OpMIPSMOVFload)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVFload [off] {sym} ptr (MOVFstore [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 != OpMIPSMOVFstore {
+ break
+ }
+ off2 := v_1.AuxInt
+ sym2 := v_1.Aux
+ ptr2 := v_1.Args[0]
+ x := v_1.Args[1]
+ if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS_OpMIPSMOVFstore(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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
+ x := v.Args[0]
+ if x.Op != OpMIPSADDconst {
+ break
+ }
+ off2 := x.AuxInt
+ ptr := x.Args[0]
+ val := v.Args[1]
+ mem := v.Args[2]
+ if !(is16Bit(off1+off2) || x.Uses == 1) {
+ break
+ }
+ v.reset(OpMIPSMOVFstore)
+ 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_0 := v.Args[0]
+ if v_0.Op != OpMIPSMOVWaddr {
+ 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(OpMIPSMOVFstore)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(ptr)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS_OpMIPSMOVHUload(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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
+ x := v.Args[0]
+ if x.Op != OpMIPSADDconst {
+ break
+ }
+ off2 := x.AuxInt
+ ptr := x.Args[0]
+ mem := v.Args[1]
+ if !(is16Bit(off1+off2) || x.Uses == 1) {
+ break
+ }
+ v.reset(OpMIPSMOVHUload)
+ 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_0 := v.Args[0]
+ if v_0.Op != OpMIPSMOVWaddr {
+ break
+ }
+ off2 := v_0.AuxInt
+ sym2 := v_0.Aux
+ ptr := v_0.Args[0]
+ mem := v.Args[1]
+ if !(canMergeSym(sym1, sym2)) {
+ break
+ }
+ v.reset(OpMIPSMOVHUload)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ 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
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpMIPSMOVHstore {
+ 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) && !isSigned(x.Type)) {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS_OpMIPSMOVHUreg(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (MOVHUreg x:(MOVBUload _ _))
+ // cond:
+ // result: (MOVWreg x)
+ for {
+ x := v.Args[0]
+ if x.Op != OpMIPSMOVBUload {
+ break
+ }
+ v.reset(OpMIPSMOVWreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVHUreg x:(MOVHUload _ _))
+ // cond:
+ // result: (MOVWreg x)
+ for {
+ x := v.Args[0]
+ if x.Op != OpMIPSMOVHUload {
+ break
+ }
+ v.reset(OpMIPSMOVWreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVHUreg x:(MOVBUreg _))
+ // cond:
+ // result: (MOVWreg x)
+ for {
+ x := v.Args[0]
+ if x.Op != OpMIPSMOVBUreg {
+ break
+ }
+ v.reset(OpMIPSMOVWreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVHUreg x:(MOVHUreg _))
+ // cond:
+ // result: (MOVWreg x)
+ for {
+ x := v.Args[0]
+ if x.Op != OpMIPSMOVHUreg {
+ break
+ }
+ v.reset(OpMIPSMOVWreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVHUreg <t> x:(MOVHload [off] {sym} ptr mem))
+ // cond: x.Uses == 1 && clobber(x)
+ // result: @x.Block (MOVHUload <t> [off] {sym} ptr mem)
+ for {
+ t := v.Type
+ x := v.Args[0]
+ if x.Op != OpMIPSMOVHload {
+ 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, OpMIPSMOVHUload, t)
+ v.reset(OpCopy)
+ v.AddArg(v0)
+ v0.AuxInt = off
+ v0.Aux = sym
+ v0.AddArg(ptr)
+ v0.AddArg(mem)
+ return true
+ }
+ // match: (MOVHUreg (ANDconst [c] x))
+ // cond:
+ // result: (ANDconst [c&0xffff] x)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPSANDconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v_0.Args[0]
+ v.reset(OpMIPSANDconst)
+ v.AuxInt = c & 0xffff
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVHUreg (MOVWconst [c]))
+ // cond:
+ // result: (MOVWconst [int64(uint16(c))])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPSMOVWconst {
+ break
+ }
+ c := v_0.AuxInt
+ v.reset(OpMIPSMOVWconst)
+ v.AuxInt = int64(uint16(c))
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS_OpMIPSMOVHload(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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
+ x := v.Args[0]
+ if x.Op != OpMIPSADDconst {
+ break
+ }
+ off2 := x.AuxInt
+ ptr := x.Args[0]
+ mem := v.Args[1]
+ if !(is16Bit(off1+off2) || x.Uses == 1) {
+ break
+ }
+ v.reset(OpMIPSMOVHload)
+ 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_0 := v.Args[0]
+ if v_0.Op != OpMIPSMOVWaddr {
+ break
+ }
+ off2 := v_0.AuxInt
+ sym2 := v_0.Aux
+ ptr := v_0.Args[0]
+ mem := v.Args[1]
+ if !(canMergeSym(sym1, sym2)) {
+ break
+ }
+ v.reset(OpMIPSMOVHload)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ 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
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpMIPSMOVHstore {
+ 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) && isSigned(x.Type)) {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS_OpMIPSMOVHreg(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (MOVHreg x:(MOVBload _ _))
+ // cond:
+ // result: (MOVWreg x)
+ for {
+ x := v.Args[0]
+ if x.Op != OpMIPSMOVBload {
+ break
+ }
+ v.reset(OpMIPSMOVWreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVHreg x:(MOVBUload _ _))
+ // cond:
+ // result: (MOVWreg x)
+ for {
+ x := v.Args[0]
+ if x.Op != OpMIPSMOVBUload {
+ break
+ }
+ v.reset(OpMIPSMOVWreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVHreg x:(MOVHload _ _))
+ // cond:
+ // result: (MOVWreg x)
+ for {
+ x := v.Args[0]
+ if x.Op != OpMIPSMOVHload {
+ break
+ }
+ v.reset(OpMIPSMOVWreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVHreg x:(MOVBreg _))
+ // cond:
+ // result: (MOVWreg x)
+ for {
+ x := v.Args[0]
+ if x.Op != OpMIPSMOVBreg {
+ break
+ }
+ v.reset(OpMIPSMOVWreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVHreg x:(MOVBUreg _))
+ // cond:
+ // result: (MOVWreg x)
+ for {
+ x := v.Args[0]
+ if x.Op != OpMIPSMOVBUreg {
+ break
+ }
+ v.reset(OpMIPSMOVWreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVHreg x:(MOVHreg _))
+ // cond:
+ // result: (MOVWreg x)
+ for {
+ x := v.Args[0]
+ if x.Op != OpMIPSMOVHreg {
+ break
+ }
+ v.reset(OpMIPSMOVWreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVHreg <t> x:(MOVHUload [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 != OpMIPSMOVHUload {
+ 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, OpMIPSMOVHload, t)
+ v.reset(OpCopy)
+ v.AddArg(v0)
+ v0.AuxInt = off
+ v0.Aux = sym
+ v0.AddArg(ptr)
+ v0.AddArg(mem)
+ return true
+ }
+ // match: (MOVHreg (ANDconst [c] x))
+ // cond: c & 0x8000 == 0
+ // result: (ANDconst [c&0x7fff] x)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPSANDconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v_0.Args[0]
+ if !(c&0x8000 == 0) {
+ break
+ }
+ v.reset(OpMIPSANDconst)
+ v.AuxInt = c & 0x7fff
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVHreg (MOVWconst [c]))
+ // cond:
+ // result: (MOVWconst [int64(int16(c))])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPSMOVWconst {
+ break
+ }
+ c := v_0.AuxInt
+ v.reset(OpMIPSMOVWconst)
+ v.AuxInt = int64(int16(c))
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS_OpMIPSMOVHstore(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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
+ x := v.Args[0]
+ if x.Op != OpMIPSADDconst {
+ break
+ }
+ off2 := x.AuxInt
+ ptr := x.Args[0]
+ val := v.Args[1]
+ mem := v.Args[2]
+ if !(is16Bit(off1+off2) || x.Uses == 1) {
+ break
+ }
+ v.reset(OpMIPSMOVHstore)
+ 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_0 := v.Args[0]
+ if v_0.Op != OpMIPSMOVWaddr {
+ 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(OpMIPSMOVHstore)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(ptr)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVHstore [off] {sym} ptr (MOVWconst [0]) mem)
+ // cond:
+ // result: (MOVHstorezero [off] {sym} ptr mem)
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpMIPSMOVWconst {
+ break
+ }
+ if v_1.AuxInt != 0 {
+ break
+ }
+ mem := v.Args[2]
+ v.reset(OpMIPSMOVHstorezero)
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVHstore [off] {sym} ptr (MOVHreg 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 != OpMIPSMOVHreg {
+ break
+ }
+ x := v_1.Args[0]
+ mem := v.Args[2]
+ v.reset(OpMIPSMOVHstore)
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(x)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVHstore [off] {sym} ptr (MOVHUreg 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 != OpMIPSMOVHUreg {
+ break
+ }
+ x := v_1.Args[0]
+ mem := v.Args[2]
+ v.reset(OpMIPSMOVHstore)
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(x)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVHstore [off] {sym} ptr (MOVWreg 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 != OpMIPSMOVWreg {
+ break
+ }
+ x := v_1.Args[0]
+ mem := v.Args[2]
+ v.reset(OpMIPSMOVHstore)
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(x)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS_OpMIPSMOVHstorezero(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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
+ x := v.Args[0]
+ if x.Op != OpMIPSADDconst {
+ break
+ }
+ off2 := x.AuxInt
+ ptr := x.Args[0]
+ mem := v.Args[1]
+ if !(is16Bit(off1+off2) || x.Uses == 1) {
+ break
+ }
+ v.reset(OpMIPSMOVHstorezero)
+ v.AuxInt = off1 + off2
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVHstorezero [off1] {sym1} (MOVWaddr [off2] {sym2} ptr) mem)
+ // cond: canMergeSym(sym1,sym2)
+ // result: (MOVHstorezero [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
+ for {
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPSMOVWaddr {
+ break
+ }
+ off2 := v_0.AuxInt
+ sym2 := v_0.Aux
+ ptr := v_0.Args[0]
+ mem := v.Args[1]
+ if !(canMergeSym(sym1, sym2)) {
+ break
+ }
+ v.reset(OpMIPSMOVHstorezero)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS_OpMIPSMOVWload(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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
+ x := v.Args[0]
+ if x.Op != OpMIPSADDconst {
+ break
+ }
+ off2 := x.AuxInt
+ ptr := x.Args[0]
+ mem := v.Args[1]
+ if !(is16Bit(off1+off2) || x.Uses == 1) {
+ break
+ }
+ v.reset(OpMIPSMOVWload)
+ 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_0 := v.Args[0]
+ if v_0.Op != OpMIPSMOVWaddr {
+ break
+ }
+ off2 := v_0.AuxInt
+ sym2 := v_0.Aux
+ ptr := v_0.Args[0]
+ mem := v.Args[1]
+ if !(canMergeSym(sym1, sym2)) {
+ break
+ }
+ v.reset(OpMIPSMOVWload)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVWload [off] {sym} ptr (MOVWstore [off2] {sym2} ptr2 x _))
+ // cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
+ // result: x
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpMIPSMOVWstore {
+ break
+ }
+ off2 := v_1.AuxInt
+ sym2 := v_1.Aux
+ ptr2 := v_1.Args[0]
+ x := v_1.Args[1]
+ if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS_OpMIPSMOVWreg(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (MOVWreg x)
+ // cond: x.Uses == 1
+ // result: (MOVWnop x)
+ for {
+ x := v.Args[0]
+ if !(x.Uses == 1) {
+ break
+ }
+ v.reset(OpMIPSMOVWnop)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVWreg (MOVWconst [c]))
+ // cond:
+ // result: (MOVWconst [c])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPSMOVWconst {
+ break
+ }
+ c := v_0.AuxInt
+ v.reset(OpMIPSMOVWconst)
+ v.AuxInt = c
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS_OpMIPSMOVWstore(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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
+ x := v.Args[0]
+ if x.Op != OpMIPSADDconst {
+ break
+ }
+ off2 := x.AuxInt
+ ptr := x.Args[0]
+ val := v.Args[1]
+ mem := v.Args[2]
+ if !(is16Bit(off1+off2) || x.Uses == 1) {
+ break
+ }
+ v.reset(OpMIPSMOVWstore)
+ 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_0 := v.Args[0]
+ if v_0.Op != OpMIPSMOVWaddr {
+ 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(OpMIPSMOVWstore)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(ptr)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVWstore [off] {sym} ptr (MOVWconst [0]) mem)
+ // cond:
+ // result: (MOVWstorezero [off] {sym} ptr mem)
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpMIPSMOVWconst {
+ break
+ }
+ if v_1.AuxInt != 0 {
+ break
+ }
+ mem := v.Args[2]
+ v.reset(OpMIPSMOVWstorezero)
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // 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 != OpMIPSMOVWreg {
+ break
+ }
+ x := v_1.Args[0]
+ mem := v.Args[2]
+ v.reset(OpMIPSMOVWstore)
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(x)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS_OpMIPSMOVWstorezero(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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
+ x := v.Args[0]
+ if x.Op != OpMIPSADDconst {
+ break
+ }
+ off2 := x.AuxInt
+ ptr := x.Args[0]
+ mem := v.Args[1]
+ if !(is16Bit(off1+off2) || x.Uses == 1) {
+ break
+ }
+ v.reset(OpMIPSMOVWstorezero)
+ v.AuxInt = off1 + off2
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVWstorezero [off1] {sym1} (MOVWaddr [off2] {sym2} ptr) mem)
+ // cond: canMergeSym(sym1,sym2)
+ // result: (MOVWstorezero [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
+ for {
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPSMOVWaddr {
+ break
+ }
+ off2 := v_0.AuxInt
+ sym2 := v_0.Aux
+ ptr := v_0.Args[0]
+ mem := v.Args[1]
+ if !(canMergeSym(sym1, sym2)) {
+ break
+ }
+ v.reset(OpMIPSMOVWstorezero)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS_OpMIPSMUL(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (MUL (MOVWconst [0]) _ )
+ // cond:
+ // result: (MOVWconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPSMOVWconst {
+ break
+ }
+ if v_0.AuxInt != 0 {
+ break
+ }
+ v.reset(OpMIPSMOVWconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (MUL (MOVWconst [1]) x )
+ // cond:
+ // result: x
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPSMOVWconst {
+ 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 [-1]) x )
+ // cond:
+ // result: (NEG x)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPSMOVWconst {
+ break
+ }
+ if v_0.AuxInt != -1 {
+ break
+ }
+ x := v.Args[1]
+ 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_0 := v.Args[0]
+ if v_0.Op != OpMIPSMOVWconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ 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_0 := v.Args[0]
+ if v_0.Op != OpMIPSMOVWconst {
+ break
+ }
+ c := v_0.AuxInt
+ v_1 := v.Args[1]
+ if v_1.Op != OpMIPSMOVWconst {
+ break
+ }
+ d := 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
+ // match: (NEG (MOVWconst [c]))
+ // cond:
+ // result: (MOVWconst [int64(int32(-c))])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPSMOVWconst {
+ break
+ }
+ c := v_0.AuxInt
+ v.reset(OpMIPSMOVWconst)
+ v.AuxInt = int64(int32(-c))
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS_OpMIPSNOR(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (NOR (MOVWconst [c]) x)
+ // cond:
+ // result: (NORconst [c] x)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPSMOVWconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ v.reset(OpMIPSNORconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (NOR x (MOVWconst [c]))
+ // cond:
+ // result: (NORconst [c] x)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpMIPSMOVWconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpMIPSNORconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS_OpMIPSNORconst(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (NORconst [c] (MOVWconst [d]))
+ // cond:
+ // result: (MOVWconst [^(c|d)])
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPSMOVWconst {
+ break
+ }
+ d := v_0.AuxInt
+ v.reset(OpMIPSMOVWconst)
+ v.AuxInt = ^(c | d)
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS_OpMIPSOR(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (OR (MOVWconst [c]) x)
+ // cond:
+ // result: (ORconst [c] x)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPSMOVWconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ v.reset(OpMIPSORconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (OR x (MOVWconst [c]))
+ // cond:
+ // result: (ORconst [c] x)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpMIPSMOVWconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpMIPSORconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (OR 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: (OR (SGTUzero x) (SGTUzero y))
+ // cond:
+ // result: (SGTUzero (OR <x.Type> x y))
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPSSGTUzero {
+ break
+ }
+ x := v_0.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpMIPSSGTUzero {
+ break
+ }
+ y := v_1.Args[0]
+ v.reset(OpMIPSSGTUzero)
+ v0 := b.NewValue0(v.Line, OpMIPSOR, x.Type)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS_OpMIPSORconst(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ORconst [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: (ORconst [-1] _)
+ // cond:
+ // result: (MOVWconst [-1])
+ for {
+ if v.AuxInt != -1 {
+ break
+ }
+ v.reset(OpMIPSMOVWconst)
+ v.AuxInt = -1
+ return true
+ }
+ // match: (ORconst [c] (MOVWconst [d]))
+ // cond:
+ // result: (MOVWconst [c|d])
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPSMOVWconst {
+ break
+ }
+ d := v_0.AuxInt
+ v.reset(OpMIPSMOVWconst)
+ v.AuxInt = c | d
+ return true
+ }
+ // match: (ORconst [c] (ORconst [d] x))
+ // cond:
+ // result: (ORconst [c|d] x)
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPSORconst {
+ break
+ }
+ d := v_0.AuxInt
+ x := v_0.Args[0]
+ v.reset(OpMIPSORconst)
+ v.AuxInt = c | d
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS_OpMIPSSGT(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SGT (MOVWconst [c]) x)
+ // cond:
+ // result: (SGTconst [c] x)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPSMOVWconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ v.reset(OpMIPSSGTconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (SGT x (MOVWconst [0]))
+ // cond:
+ // result: (SGTzero x)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpMIPSMOVWconst {
+ break
+ }
+ if v_1.AuxInt != 0 {
+ break
+ }
+ v.reset(OpMIPSSGTzero)
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS_OpMIPSSGTU(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SGTU (MOVWconst [c]) x)
+ // cond:
+ // result: (SGTUconst [c] x)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPSMOVWconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ v.reset(OpMIPSSGTUconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (SGTU x (MOVWconst [0]))
+ // cond:
+ // result: (SGTUzero x)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpMIPSMOVWconst {
+ break
+ }
+ if v_1.AuxInt != 0 {
+ break
+ }
+ v.reset(OpMIPSSGTUzero)
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS_OpMIPSSGTUconst(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SGTUconst [c] (MOVWconst [d]))
+ // cond: uint32(c)>uint32(d)
+ // result: (MOVWconst [1])
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPSMOVWconst {
+ break
+ }
+ d := v_0.AuxInt
+ if !(uint32(c) > uint32(d)) {
+ break
+ }
+ v.reset(OpMIPSMOVWconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (SGTUconst [c] (MOVWconst [d]))
+ // cond: uint32(c)<=uint32(d)
+ // result: (MOVWconst [0])
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPSMOVWconst {
+ break
+ }
+ d := v_0.AuxInt
+ if !(uint32(c) <= uint32(d)) {
+ break
+ }
+ v.reset(OpMIPSMOVWconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (SGTUconst [c] (MOVBUreg _))
+ // cond: 0xff < uint32(c)
+ // result: (MOVWconst [1])
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPSMOVBUreg {
+ break
+ }
+ if !(0xff < uint32(c)) {
+ break
+ }
+ v.reset(OpMIPSMOVWconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (SGTUconst [c] (MOVHUreg _))
+ // cond: 0xffff < uint32(c)
+ // result: (MOVWconst [1])
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPSMOVHUreg {
+ break
+ }
+ if !(0xffff < uint32(c)) {
+ break
+ }
+ v.reset(OpMIPSMOVWconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (SGTUconst [c] (ANDconst [m] _))
+ // cond: uint32(m) < uint32(c)
+ // result: (MOVWconst [1])
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPSANDconst {
+ break
+ }
+ m := v_0.AuxInt
+ if !(uint32(m) < uint32(c)) {
+ break
+ }
+ v.reset(OpMIPSMOVWconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (SGTUconst [c] (SRLconst _ [d]))
+ // cond: uint32(d) <= 31 && 1<<(32-uint32(d)) <= uint32(c)
+ // result: (MOVWconst [1])
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPSSRLconst {
+ break
+ }
+ d := v_0.AuxInt
+ if !(uint32(d) <= 31 && 1<<(32-uint32(d)) <= uint32(c)) {
+ break
+ }
+ v.reset(OpMIPSMOVWconst)
+ v.AuxInt = 1
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS_OpMIPSSGTUzero(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SGTUzero (MOVWconst [d]))
+ // cond: uint32(d) != 0
+ // result: (MOVWconst [1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPSMOVWconst {
+ break
+ }
+ d := v_0.AuxInt
+ if !(uint32(d) != 0) {
+ break
+ }
+ v.reset(OpMIPSMOVWconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (SGTUzero (MOVWconst [d]))
+ // cond: uint32(d) == 0
+ // result: (MOVWconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPSMOVWconst {
+ break
+ }
+ d := v_0.AuxInt
+ if !(uint32(d) == 0) {
+ break
+ }
+ v.reset(OpMIPSMOVWconst)
+ v.AuxInt = 0
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS_OpMIPSSGTconst(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SGTconst [c] (MOVWconst [d]))
+ // cond: int32(c) > int32(d)
+ // result: (MOVWconst [1])
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPSMOVWconst {
+ break
+ }
+ d := v_0.AuxInt
+ if !(int32(c) > int32(d)) {
+ break
+ }
+ v.reset(OpMIPSMOVWconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (SGTconst [c] (MOVWconst [d]))
+ // cond: int32(c) <= int32(d)
+ // result: (MOVWconst [0])
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPSMOVWconst {
+ break
+ }
+ d := v_0.AuxInt
+ if !(int32(c) <= int32(d)) {
+ break
+ }
+ v.reset(OpMIPSMOVWconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (SGTconst [c] (MOVBreg _))
+ // cond: 0x7f < int32(c)
+ // result: (MOVWconst [1])
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPSMOVBreg {
+ break
+ }
+ if !(0x7f < int32(c)) {
+ break
+ }
+ v.reset(OpMIPSMOVWconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (SGTconst [c] (MOVBreg _))
+ // cond: int32(c) <= -0x80
+ // result: (MOVWconst [0])
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPSMOVBreg {
+ break
+ }
+ if !(int32(c) <= -0x80) {
+ break
+ }
+ v.reset(OpMIPSMOVWconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (SGTconst [c] (MOVBUreg _))
+ // cond: 0xff < int32(c)
+ // result: (MOVWconst [1])
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPSMOVBUreg {
+ break
+ }
+ if !(0xff < int32(c)) {
+ break
+ }
+ v.reset(OpMIPSMOVWconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (SGTconst [c] (MOVBUreg _))
+ // cond: int32(c) < 0
+ // result: (MOVWconst [0])
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPSMOVBUreg {
+ break
+ }
+ if !(int32(c) < 0) {
+ break
+ }
+ v.reset(OpMIPSMOVWconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (SGTconst [c] (MOVHreg _))
+ // cond: 0x7fff < int32(c)
+ // result: (MOVWconst [1])
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPSMOVHreg {
+ break
+ }
+ if !(0x7fff < int32(c)) {
+ break
+ }
+ v.reset(OpMIPSMOVWconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (SGTconst [c] (MOVHreg _))
+ // cond: int32(c) <= -0x8000
+ // result: (MOVWconst [0])
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPSMOVHreg {
+ break
+ }
+ if !(int32(c) <= -0x8000) {
+ break
+ }
+ v.reset(OpMIPSMOVWconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (SGTconst [c] (MOVHUreg _))
+ // cond: 0xffff < int32(c)
+ // result: (MOVWconst [1])
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPSMOVHUreg {
+ break
+ }
+ if !(0xffff < int32(c)) {
+ break
+ }
+ v.reset(OpMIPSMOVWconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (SGTconst [c] (MOVHUreg _))
+ // cond: int32(c) < 0
+ // result: (MOVWconst [0])
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPSMOVHUreg {
+ break
+ }
+ if !(int32(c) < 0) {
+ break
+ }
+ v.reset(OpMIPSMOVWconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (SGTconst [c] (ANDconst [m] _))
+ // cond: 0 <= int32(m) && int32(m) < int32(c)
+ // result: (MOVWconst [1])
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPSANDconst {
+ break
+ }
+ m := v_0.AuxInt
+ if !(0 <= int32(m) && int32(m) < int32(c)) {
+ break
+ }
+ v.reset(OpMIPSMOVWconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (SGTconst [c] (SRLconst _ [d]))
+ // cond: 0 <= int32(c) && uint32(d) <= 31 && 1<<(32-uint32(d)) <= int32(c)
+ // result: (MOVWconst [1])
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPSSRLconst {
+ break
+ }
+ d := v_0.AuxInt
+ if !(0 <= int32(c) && uint32(d) <= 31 && 1<<(32-uint32(d)) <= int32(c)) {
+ break
+ }
+ v.reset(OpMIPSMOVWconst)
+ v.AuxInt = 1
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS_OpMIPSSGTzero(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SGTzero (MOVWconst [d]))
+ // cond: int32(d) > 0
+ // result: (MOVWconst [1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPSMOVWconst {
+ break
+ }
+ d := v_0.AuxInt
+ if !(int32(d) > 0) {
+ break
+ }
+ v.reset(OpMIPSMOVWconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (SGTzero (MOVWconst [d]))
+ // cond: int32(d) <= 0
+ // result: (MOVWconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPSMOVWconst {
+ break
+ }
+ d := v_0.AuxInt
+ if !(int32(d) <= 0) {
+ break
+ }
+ v.reset(OpMIPSMOVWconst)
+ v.AuxInt = 0
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS_OpMIPSSLL(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SLL _ (MOVWconst [c]))
+ // cond: uint32(c)>=32
+ // result: (MOVWconst [0])
+ for {
+ v_1 := v.Args[1]
+ if v_1.Op != OpMIPSMOVWconst {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint32(c) >= 32) {
+ break
+ }
+ v.reset(OpMIPSMOVWconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (SLL x (MOVWconst [c]))
+ // cond:
+ // result: (SLLconst x [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpMIPSMOVWconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpMIPSSLLconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS_OpMIPSSLLconst(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SLLconst [c] (MOVWconst [d]))
+ // cond:
+ // result: (MOVWconst [int64(int32(uint32(d)<<uint32(c)))])
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPSMOVWconst {
+ break
+ }
+ d := v_0.AuxInt
+ v.reset(OpMIPSMOVWconst)
+ v.AuxInt = int64(int32(uint32(d) << uint32(c)))
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS_OpMIPSSRA(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SRA x (MOVWconst [c]))
+ // cond: uint32(c)>=32
+ // result: (SRAconst x [31])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpMIPSMOVWconst {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint32(c) >= 32) {
+ break
+ }
+ v.reset(OpMIPSSRAconst)
+ v.AuxInt = 31
+ v.AddArg(x)
+ return true
+ }
+ // match: (SRA x (MOVWconst [c]))
+ // cond:
+ // result: (SRAconst x [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpMIPSMOVWconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpMIPSSRAconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS_OpMIPSSRAconst(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SRAconst [c] (MOVWconst [d]))
+ // cond:
+ // result: (MOVWconst [int64(int32(d)>>uint32(c))])
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPSMOVWconst {
+ break
+ }
+ d := v_0.AuxInt
+ v.reset(OpMIPSMOVWconst)
+ v.AuxInt = int64(int32(d) >> uint32(c))
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS_OpMIPSSRL(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SRL _ (MOVWconst [c]))
+ // cond: uint32(c)>=32
+ // result: (MOVWconst [0])
+ for {
+ v_1 := v.Args[1]
+ if v_1.Op != OpMIPSMOVWconst {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint32(c) >= 32) {
+ break
+ }
+ v.reset(OpMIPSMOVWconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (SRL x (MOVWconst [c]))
+ // cond:
+ // result: (SRLconst x [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpMIPSMOVWconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpMIPSSRLconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS_OpMIPSSRLconst(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SRLconst [c] (MOVWconst [d]))
+ // cond:
+ // result: (MOVWconst [int64(uint32(d)>>uint32(c))])
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPSMOVWconst {
+ break
+ }
+ d := v_0.AuxInt
+ v.reset(OpMIPSMOVWconst)
+ v.AuxInt = int64(uint32(d) >> uint32(c))
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS_OpMIPSSUB(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SUB x (MOVWconst [c]))
+ // cond:
+ // result: (SUBconst [c] x)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpMIPSMOVWconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpMIPSSUBconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (SUB x x)
+ // cond:
+ // result: (MOVWconst [0])
+ for {
+ x := v.Args[0]
+ if x != v.Args[1] {
+ break
+ }
+ v.reset(OpMIPSMOVWconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (SUB (MOVWconst [0]) x)
+ // cond:
+ // result: (NEG x)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPSMOVWconst {
+ break
+ }
+ if v_0.AuxInt != 0 {
+ break
+ }
+ x := v.Args[1]
+ v.reset(OpMIPSNEG)
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS_OpMIPSSUBconst(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SUBconst [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: (SUBconst [c] (MOVWconst [d]))
+ // cond:
+ // result: (MOVWconst [int64(int32(d-c))])
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPSMOVWconst {
+ break
+ }
+ d := v_0.AuxInt
+ v.reset(OpMIPSMOVWconst)
+ v.AuxInt = int64(int32(d - c))
+ return true
+ }
+ // match: (SUBconst [c] (SUBconst [d] x))
+ // cond:
+ // result: (ADDconst [int64(int32(-c-d))] x)
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPSSUBconst {
+ break
+ }
+ d := v_0.AuxInt
+ x := v_0.Args[0]
+ v.reset(OpMIPSADDconst)
+ v.AuxInt = int64(int32(-c - d))
+ v.AddArg(x)
+ return true
+ }
+ // match: (SUBconst [c] (ADDconst [d] x))
+ // cond:
+ // result: (ADDconst [int64(int32(-c+d))] x)
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPSADDconst {
+ break
+ }
+ d := v_0.AuxInt
+ x := v_0.Args[0]
+ v.reset(OpMIPSADDconst)
+ v.AuxInt = int64(int32(-c + d))
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS_OpMIPSXOR(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (XOR (MOVWconst [c]) x)
+ // cond:
+ // result: (XORconst [c] x)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPSMOVWconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ v.reset(OpMIPSXORconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (XOR x (MOVWconst [c]))
+ // cond:
+ // result: (XORconst [c] x)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpMIPSMOVWconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpMIPSXORconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (XOR x x)
+ // cond:
+ // result: (MOVWconst [0])
+ for {
+ x := v.Args[0]
+ if x != v.Args[1] {
+ break
+ }
+ v.reset(OpMIPSMOVWconst)
+ v.AuxInt = 0
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS_OpMIPSXORconst(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (XORconst [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: (XORconst [-1] x)
+ // cond:
+ // result: (NORconst [0] x)
+ for {
+ if v.AuxInt != -1 {
+ break
+ }
+ x := v.Args[0]
+ v.reset(OpMIPSNORconst)
+ v.AuxInt = 0
+ v.AddArg(x)
+ return true
+ }
+ // match: (XORconst [c] (MOVWconst [d]))
+ // cond:
+ // result: (MOVWconst [c^d])
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPSMOVWconst {
+ break
+ }
+ d := v_0.AuxInt
+ v.reset(OpMIPSMOVWconst)
+ v.AuxInt = c ^ d
+ return true
+ }
+ // match: (XORconst [c] (XORconst [d] x))
+ // cond:
+ // result: (XORconst [c^d] x)
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPSXORconst {
+ break
+ }
+ d := v_0.AuxInt
+ x := v_0.Args[0]
+ v.reset(OpMIPSXORconst)
+ v.AuxInt = c ^ d
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS_OpMod16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Mod16 x y)
+ // cond:
+ // result: (Select0 (DIV (SignExt16to32 x) (SignExt16to32 y)))
+ for {
+ 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())
+ 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_OpMod16u(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Mod16u x y)
+ // cond:
+ // result: (Select0 (DIVU (ZeroExt16to32 x) (ZeroExt16to32 y)))
+ for {
+ 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())
+ 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_OpMod32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Mod32 x y)
+ // cond:
+ // result: (Select0 (DIV x y))
+ for {
+ 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.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueMIPS_OpMod32u(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Mod32u x y)
+ // cond:
+ // result: (Select0 (DIVU x y))
+ for {
+ 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.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueMIPS_OpMod8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Mod8 x y)
+ // cond:
+ // result: (Select0 (DIV (SignExt8to32 x) (SignExt8to32 y)))
+ for {
+ 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())
+ 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_OpMod8u(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Mod8u x y)
+ // cond:
+ // result: (Select0 (DIVU (ZeroExt8to32 x) (ZeroExt8to32 y)))
+ for {
+ 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())
+ 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_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) {
+ 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 (MOVBUload src mem) mem)
+ for {
+ s := v.AuxInt
+ 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.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
+ // result: (MOVHstore dst (MOVHUload src mem) mem)
+ for {
+ s := v.AuxInt
+ 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(OpMIPSMOVHstore)
+ v.AddArg(dst)
+ v0 := b.NewValue0(v.Line, OpMIPSMOVHUload, 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() == 2
+ // result: (MOVBstore [1] dst (MOVBUload [1] src mem) (MOVBstore dst (MOVBUload src mem) mem))
+ for {
+ s := v.AuxInt
+ 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.AuxInt = 1
+ v0.AddArg(src)
+ v0.AddArg(mem)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpMIPSMOVBstore, TypeMem)
+ v1.AddArg(dst)
+ v2 := b.NewValue0(v.Line, OpMIPSMOVBUload, config.fe.TypeUInt8())
+ v2.AddArg(src)
+ v2.AddArg(mem)
+ v1.AddArg(v2)
+ v1.AddArg(mem)
+ v.AddArg(v1)
+ 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)
+ for {
+ s := v.AuxInt
+ dst := v.Args[0]
+ src := v.Args[1]
+ mem := v.Args[2]
+ if !(SizeAndAlign(s).Size() == 4 && SizeAndAlign(s).Align()%4 == 0) {
+ break
+ }
+ v.reset(OpMIPSMOVWstore)
+ v.AddArg(dst)
+ v0 := b.NewValue0(v.Line, OpMIPSMOVWload, 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() == 4 && SizeAndAlign(s).Align()%2 == 0
+ // result: (MOVHstore [2] dst (MOVHUload [2] src mem) (MOVHstore dst (MOVHUload src mem) mem))
+ for {
+ s := v.AuxInt
+ 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(OpMIPSMOVHstore)
+ v.AuxInt = 2
+ v.AddArg(dst)
+ v0 := b.NewValue0(v.Line, OpMIPSMOVHUload, config.fe.TypeUInt16())
+ v0.AuxInt = 2
+ v0.AddArg(src)
+ v0.AddArg(mem)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpMIPSMOVHstore, TypeMem)
+ v1.AddArg(dst)
+ v2 := b.NewValue0(v.Line, OpMIPSMOVHUload, config.fe.TypeUInt16())
+ v2.AddArg(src)
+ v2.AddArg(mem)
+ v1.AddArg(v2)
+ v1.AddArg(mem)
+ v.AddArg(v1)
+ return true
+ }
+ // match: (Move [s] dst src mem)
+ // cond: SizeAndAlign(s).Size() == 4
+ // 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
+ 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.AuxInt = 3
+ v0.AddArg(src)
+ v0.AddArg(mem)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpMIPSMOVBstore, TypeMem)
+ v1.AuxInt = 2
+ v1.AddArg(dst)
+ v2 := b.NewValue0(v.Line, OpMIPSMOVBUload, config.fe.TypeUInt8())
+ v2.AuxInt = 2
+ v2.AddArg(src)
+ v2.AddArg(mem)
+ v1.AddArg(v2)
+ v3 := b.NewValue0(v.Line, OpMIPSMOVBstore, TypeMem)
+ v3.AuxInt = 1
+ v3.AddArg(dst)
+ v4 := b.NewValue0(v.Line, OpMIPSMOVBUload, config.fe.TypeUInt8())
+ v4.AuxInt = 1
+ v4.AddArg(src)
+ v4.AddArg(mem)
+ v3.AddArg(v4)
+ v5 := b.NewValue0(v.Line, OpMIPSMOVBstore, TypeMem)
+ v5.AddArg(dst)
+ v6 := b.NewValue0(v.Line, OpMIPSMOVBUload, config.fe.TypeUInt8())
+ v6.AddArg(src)
+ v6.AddArg(mem)
+ v5.AddArg(v6)
+ v5.AddArg(mem)
+ v3.AddArg(v5)
+ v1.AddArg(v3)
+ v.AddArg(v1)
+ return true
+ }
+ // match: (Move [s] dst src mem)
+ // cond: SizeAndAlign(s).Size() == 3
+ // 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
+ 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.AuxInt = 2
+ v0.AddArg(src)
+ v0.AddArg(mem)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpMIPSMOVBstore, TypeMem)
+ v1.AuxInt = 1
+ v1.AddArg(dst)
+ v2 := b.NewValue0(v.Line, OpMIPSMOVBUload, config.fe.TypeUInt8())
+ v2.AuxInt = 1
+ v2.AddArg(src)
+ v2.AddArg(mem)
+ v1.AddArg(v2)
+ v3 := b.NewValue0(v.Line, OpMIPSMOVBstore, TypeMem)
+ v3.AddArg(dst)
+ v4 := b.NewValue0(v.Line, OpMIPSMOVBUload, config.fe.TypeUInt8())
+ v4.AddArg(src)
+ v4.AddArg(mem)
+ v3.AddArg(v4)
+ v3.AddArg(mem)
+ v1.AddArg(v3)
+ v.AddArg(v1)
+ return true
+ }
+ // match: (Move [s] dst src mem)
+ // cond: SizeAndAlign(s).Size() == 8 && SizeAndAlign(s).Align()%4 == 0
+ // result: (MOVWstore [4] dst (MOVWload [4] 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() == 8 && SizeAndAlign(s).Align()%4 == 0) {
+ break
+ }
+ v.reset(OpMIPSMOVWstore)
+ v.AuxInt = 4
+ v.AddArg(dst)
+ v0 := b.NewValue0(v.Line, OpMIPSMOVWload, config.fe.TypeUInt32())
+ v0.AuxInt = 4
+ v0.AddArg(src)
+ v0.AddArg(mem)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpMIPSMOVWstore, TypeMem)
+ v1.AddArg(dst)
+ v2 := b.NewValue0(v.Line, OpMIPSMOVWload, config.fe.TypeUInt32())
+ v2.AddArg(src)
+ v2.AddArg(mem)
+ v1.AddArg(v2)
+ v1.AddArg(mem)
+ 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 (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
+ 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(OpMIPSMOVHstore)
+ v.AuxInt = 6
+ v.AddArg(dst)
+ v0 := b.NewValue0(v.Line, OpMIPSMOVHload, config.fe.TypeInt16())
+ v0.AuxInt = 6
+ v0.AddArg(src)
+ v0.AddArg(mem)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpMIPSMOVHstore, TypeMem)
+ v1.AuxInt = 4
+ v1.AddArg(dst)
+ v2 := b.NewValue0(v.Line, OpMIPSMOVHload, config.fe.TypeInt16())
+ v2.AuxInt = 4
+ v2.AddArg(src)
+ v2.AddArg(mem)
+ v1.AddArg(v2)
+ v3 := b.NewValue0(v.Line, OpMIPSMOVHstore, TypeMem)
+ v3.AuxInt = 2
+ v3.AddArg(dst)
+ v4 := b.NewValue0(v.Line, OpMIPSMOVHload, config.fe.TypeInt16())
+ v4.AuxInt = 2
+ v4.AddArg(src)
+ v4.AddArg(mem)
+ v3.AddArg(v4)
+ v5 := b.NewValue0(v.Line, OpMIPSMOVHstore, TypeMem)
+ v5.AddArg(dst)
+ v6 := b.NewValue0(v.Line, OpMIPSMOVHload, config.fe.TypeInt16())
+ v6.AddArg(src)
+ v6.AddArg(mem)
+ v5.AddArg(v6)
+ v5.AddArg(mem)
+ v3.AddArg(v5)
+ v1.AddArg(v3)
+ v.AddArg(v1)
+ return true
+ }
+ // match: (Move [s] dst src mem)
+ // cond: SizeAndAlign(s).Size() == 6 && SizeAndAlign(s).Align()%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
+ dst := v.Args[0]
+ src := v.Args[1]
+ mem := v.Args[2]
+ if !(SizeAndAlign(s).Size() == 6 && SizeAndAlign(s).Align()%2 == 0) {
+ break
+ }
+ v.reset(OpMIPSMOVHstore)
+ v.AuxInt = 4
+ v.AddArg(dst)
+ v0 := b.NewValue0(v.Line, OpMIPSMOVHload, config.fe.TypeInt16())
+ v0.AuxInt = 4
+ v0.AddArg(src)
+ v0.AddArg(mem)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpMIPSMOVHstore, TypeMem)
+ v1.AuxInt = 2
+ v1.AddArg(dst)
+ v2 := b.NewValue0(v.Line, OpMIPSMOVHload, config.fe.TypeInt16())
+ v2.AuxInt = 2
+ v2.AddArg(src)
+ v2.AddArg(mem)
+ v1.AddArg(v2)
+ v3 := b.NewValue0(v.Line, OpMIPSMOVHstore, TypeMem)
+ v3.AddArg(dst)
+ v4 := b.NewValue0(v.Line, OpMIPSMOVHload, config.fe.TypeInt16())
+ v4.AddArg(src)
+ v4.AddArg(mem)
+ v3.AddArg(v4)
+ v3.AddArg(mem)
+ v1.AddArg(v3)
+ v.AddArg(v1)
+ return true
+ }
+ // match: (Move [s] dst src mem)
+ // cond: SizeAndAlign(s).Size() == 12 && SizeAndAlign(s).Align()%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
+ dst := v.Args[0]
+ src := v.Args[1]
+ mem := v.Args[2]
+ if !(SizeAndAlign(s).Size() == 12 && SizeAndAlign(s).Align()%4 == 0) {
+ break
+ }
+ v.reset(OpMIPSMOVWstore)
+ v.AuxInt = 8
+ v.AddArg(dst)
+ v0 := b.NewValue0(v.Line, OpMIPSMOVWload, config.fe.TypeUInt32())
+ v0.AuxInt = 8
+ v0.AddArg(src)
+ v0.AddArg(mem)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpMIPSMOVWstore, TypeMem)
+ v1.AuxInt = 4
+ v1.AddArg(dst)
+ v2 := b.NewValue0(v.Line, OpMIPSMOVWload, config.fe.TypeUInt32())
+ v2.AuxInt = 4
+ v2.AddArg(src)
+ v2.AddArg(mem)
+ v1.AddArg(v2)
+ v3 := b.NewValue0(v.Line, OpMIPSMOVWstore, TypeMem)
+ v3.AddArg(dst)
+ v4 := b.NewValue0(v.Line, OpMIPSMOVWload, config.fe.TypeUInt32())
+ v4.AddArg(src)
+ v4.AddArg(mem)
+ v3.AddArg(v4)
+ v3.AddArg(mem)
+ v1.AddArg(v3)
+ v.AddArg(v1)
+ return true
+ }
+ // match: (Move [s] dst src mem)
+ // cond: SizeAndAlign(s).Size() == 16 && SizeAndAlign(s).Align()%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
+ dst := v.Args[0]
+ src := v.Args[1]
+ mem := v.Args[2]
+ if !(SizeAndAlign(s).Size() == 16 && SizeAndAlign(s).Align()%4 == 0) {
+ break
+ }
+ v.reset(OpMIPSMOVWstore)
+ v.AuxInt = 12
+ v.AddArg(dst)
+ v0 := b.NewValue0(v.Line, OpMIPSMOVWload, config.fe.TypeUInt32())
+ v0.AuxInt = 12
+ v0.AddArg(src)
+ v0.AddArg(mem)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpMIPSMOVWstore, TypeMem)
+ v1.AuxInt = 8
+ v1.AddArg(dst)
+ v2 := b.NewValue0(v.Line, OpMIPSMOVWload, config.fe.TypeUInt32())
+ v2.AuxInt = 8
+ v2.AddArg(src)
+ v2.AddArg(mem)
+ v1.AddArg(v2)
+ v3 := b.NewValue0(v.Line, OpMIPSMOVWstore, TypeMem)
+ v3.AuxInt = 4
+ v3.AddArg(dst)
+ v4 := b.NewValue0(v.Line, OpMIPSMOVWload, config.fe.TypeUInt32())
+ v4.AuxInt = 4
+ v4.AddArg(src)
+ v4.AddArg(mem)
+ v3.AddArg(v4)
+ v5 := b.NewValue0(v.Line, OpMIPSMOVWstore, TypeMem)
+ v5.AddArg(dst)
+ v6 := b.NewValue0(v.Line, OpMIPSMOVWload, config.fe.TypeUInt32())
+ v6.AddArg(src)
+ v6.AddArg(mem)
+ v5.AddArg(v6)
+ v5.AddArg(mem)
+ v3.AddArg(v5)
+ v1.AddArg(v3)
+ 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)
+ for {
+ s := v.AuxInt
+ dst := v.Args[0]
+ src := v.Args[1]
+ mem := v.Args[2]
+ if !(SizeAndAlign(s).Size() > 16 || SizeAndAlign(s).Align()%4 != 0) {
+ break
+ }
+ v.reset(OpMIPSLoweredMove)
+ v.AuxInt = SizeAndAlign(s).Align()
+ 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.AddArg(src)
+ v.AddArg(v0)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS_OpMul16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Mul16 x y)
+ // cond:
+ // result: (MUL x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPSMUL)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueMIPS_OpMul32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Mul32 x y)
+ // cond:
+ // result: (MUL x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPSMUL)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueMIPS_OpMul32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Mul32F x y)
+ // cond:
+ // result: (MULF x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPSMULF)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueMIPS_OpMul32uhilo(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Mul32uhilo x y)
+ // cond:
+ // result: (MULTU x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPSMULTU)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueMIPS_OpMul64F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Mul64F x y)
+ // cond:
+ // result: (MULD x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPSMULD)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueMIPS_OpMul8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Mul8 x y)
+ // cond:
+ // result: (MUL x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPSMUL)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueMIPS_OpNeg16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Neg16 x)
+ // cond:
+ // result: (NEG x)
+ for {
+ x := v.Args[0]
+ v.reset(OpMIPSNEG)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueMIPS_OpNeg32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Neg32 x)
+ // cond:
+ // result: (NEG x)
+ for {
+ x := v.Args[0]
+ v.reset(OpMIPSNEG)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueMIPS_OpNeg32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Neg32F x)
+ // cond:
+ // result: (NEGF x)
+ for {
+ x := v.Args[0]
+ v.reset(OpMIPSNEGF)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueMIPS_OpNeg64F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Neg64F x)
+ // cond:
+ // result: (NEGD x)
+ for {
+ x := v.Args[0]
+ v.reset(OpMIPSNEGD)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueMIPS_OpNeg8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Neg8 x)
+ // cond:
+ // result: (NEG x)
+ for {
+ x := v.Args[0]
+ v.reset(OpMIPSNEG)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueMIPS_OpNeq16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Neq16 x y)
+ // cond:
+ // result: (SGTU (XOR (ZeroExt16to32 x) (ZeroExt16to32 y)) (MOVWconst [0]))
+ for {
+ 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())
+ v1.AddArg(x)
+ v0.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+ v2.AddArg(y)
+ v0.AddArg(v2)
+ v.AddArg(v0)
+ v3 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+ v3.AuxInt = 0
+ v.AddArg(v3)
+ return true
+ }
+}
+func rewriteValueMIPS_OpNeq32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Neq32 x y)
+ // cond:
+ // result: (SGTU (XOR x y) (MOVWconst [0]))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPSSGTU)
+ v0 := b.NewValue0(v.Line, OpMIPSXOR, config.fe.TypeUInt32())
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+ v1.AuxInt = 0
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueMIPS_OpNeq32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Neq32F x y)
+ // cond:
+ // result: (FPFlagFalse (CMPEQF x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPSFPFlagFalse)
+ v0 := b.NewValue0(v.Line, OpMIPSCMPEQF, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueMIPS_OpNeq64F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Neq64F x y)
+ // cond:
+ // result: (FPFlagFalse (CMPEQD x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPSFPFlagFalse)
+ v0 := b.NewValue0(v.Line, OpMIPSCMPEQD, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueMIPS_OpNeq8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Neq8 x y)
+ // cond:
+ // result: (SGTU (XOR (ZeroExt8to32 x) (ZeroExt8to32 y)) (MOVWconst [0]))
+ for {
+ 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())
+ v1.AddArg(x)
+ v0.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+ v2.AddArg(y)
+ v0.AddArg(v2)
+ v.AddArg(v0)
+ v3 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+ v3.AuxInt = 0
+ v.AddArg(v3)
+ return true
+ }
+}
+func rewriteValueMIPS_OpNeqB(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (NeqB x y)
+ // cond:
+ // result: (XOR x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPSXOR)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueMIPS_OpNeqPtr(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (NeqPtr x y)
+ // cond:
+ // result: (SGTU (XOR x y) (MOVWconst [0]))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPSSGTU)
+ v0 := b.NewValue0(v.Line, OpMIPSXOR, config.fe.TypeUInt32())
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+ v1.AuxInt = 0
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueMIPS_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(OpMIPSLoweredNilCheck)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+}
+func rewriteValueMIPS_OpNot(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Not x)
+ // cond:
+ // result: (XORconst [1] x)
+ for {
+ x := v.Args[0]
+ v.reset(OpMIPSXORconst)
+ v.AuxInt = 1
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueMIPS_OpOffPtr(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (OffPtr [off] ptr:(SP))
+ // cond:
+ // result: (MOVWaddr [off] ptr)
+ for {
+ off := v.AuxInt
+ ptr := v.Args[0]
+ if ptr.Op != OpSP {
+ break
+ }
+ v.reset(OpMIPSMOVWaddr)
+ v.AuxInt = off
+ v.AddArg(ptr)
+ return true
+ }
+ // match: (OffPtr [off] ptr)
+ // cond:
+ // result: (ADDconst [off] ptr)
+ for {
+ off := v.AuxInt
+ ptr := v.Args[0]
+ v.reset(OpMIPSADDconst)
+ v.AuxInt = off
+ v.AddArg(ptr)
+ return true
+ }
+}
+func rewriteValueMIPS_OpOr16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Or16 x y)
+ // cond:
+ // result: (OR x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPSOR)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueMIPS_OpOr32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Or32 x y)
+ // cond:
+ // result: (OR x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPSOR)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueMIPS_OpOr8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Or8 x y)
+ // cond:
+ // result: (OR x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPSOR)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueMIPS_OpOrB(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (OrB x y)
+ // cond:
+ // result: (OR x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPSOR)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueMIPS_OpRsh16Ux16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh16Ux16 <t> x y)
+ // cond:
+ // result: (CMOVZ (SRL <t> (ZeroExt16to32 x) (ZeroExt16to32 y) ) (MOVWconst [0]) (SGTUconst [32] (ZeroExt16to32 y)))
+ for {
+ t := v.Type
+ 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())
+ v1.AddArg(x)
+ v0.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+ v2.AddArg(y)
+ v0.AddArg(v2)
+ v.AddArg(v0)
+ v3 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+ v3.AuxInt = 0
+ v.AddArg(v3)
+ v4 := b.NewValue0(v.Line, OpMIPSSGTUconst, config.fe.TypeBool())
+ v4.AuxInt = 32
+ v5 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+ v5.AddArg(y)
+ v4.AddArg(v5)
+ v.AddArg(v4)
+ return true
+ }
+}
+func rewriteValueMIPS_OpRsh16Ux32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh16Ux32 <t> x y)
+ // cond:
+ // result: (CMOVZ (SRL <t> (ZeroExt16to32 x) y) (MOVWconst [0]) (SGTUconst [32] y))
+ for {
+ t := v.Type
+ 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())
+ v1.AddArg(x)
+ v0.AddArg(v1)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ v2 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+ v2.AuxInt = 0
+ v.AddArg(v2)
+ v3 := b.NewValue0(v.Line, OpMIPSSGTUconst, config.fe.TypeBool())
+ v3.AuxInt = 32
+ v3.AddArg(y)
+ v.AddArg(v3)
+ return true
+ }
+}
+func rewriteValueMIPS_OpRsh16Ux64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh16Ux64 x (Const64 [c]))
+ // cond: uint32(c) < 16
+ // result: (SRLconst (SLLconst <config.fe.TypeUInt32()> x [16]) [c+16])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpConst64 {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint32(c) < 16) {
+ break
+ }
+ v.reset(OpMIPSSRLconst)
+ v.AuxInt = c + 16
+ v0 := b.NewValue0(v.Line, OpMIPSSLLconst, config.fe.TypeUInt32())
+ v0.AuxInt = 16
+ v0.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (Rsh16Ux64 _ (Const64 [c]))
+ // cond: uint32(c) >= 16
+ // result: (MOVWconst [0])
+ for {
+ v_1 := v.Args[1]
+ if v_1.Op != OpConst64 {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint32(c) >= 16) {
+ break
+ }
+ v.reset(OpMIPSMOVWconst)
+ v.AuxInt = 0
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS_OpRsh16Ux8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh16Ux8 <t> x y)
+ // cond:
+ // result: (CMOVZ (SRL <t> (ZeroExt16to32 x) (ZeroExt8to32 y) ) (MOVWconst [0]) (SGTUconst [32] (ZeroExt8to32 y)))
+ for {
+ t := v.Type
+ 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())
+ v1.AddArg(x)
+ v0.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+ v2.AddArg(y)
+ v0.AddArg(v2)
+ v.AddArg(v0)
+ v3 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+ v3.AuxInt = 0
+ v.AddArg(v3)
+ v4 := b.NewValue0(v.Line, OpMIPSSGTUconst, config.fe.TypeBool())
+ v4.AuxInt = 32
+ v5 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+ v5.AddArg(y)
+ v4.AddArg(v5)
+ v.AddArg(v4)
+ return true
+ }
+}
+func rewriteValueMIPS_OpRsh16x16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh16x16 x y)
+ // cond:
+ // result: (SRA (SignExt16to32 x) ( CMOVZ <config.fe.TypeUInt32()> (ZeroExt16to32 y) (MOVWconst [-1]) (SGTUconst [32] (ZeroExt16to32 y))))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPSSRA)
+ v0 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpMIPSCMOVZ, config.fe.TypeUInt32())
+ v2 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+ v2.AddArg(y)
+ v1.AddArg(v2)
+ v3 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+ v3.AuxInt = -1
+ v1.AddArg(v3)
+ v4 := b.NewValue0(v.Line, OpMIPSSGTUconst, config.fe.TypeBool())
+ v4.AuxInt = 32
+ v5 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+ v5.AddArg(y)
+ v4.AddArg(v5)
+ v1.AddArg(v4)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueMIPS_OpRsh16x32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh16x32 x y)
+ // cond:
+ // result: (SRA (SignExt16to32 x) ( CMOVZ <config.fe.TypeUInt32()> y (MOVWconst [-1]) (SGTUconst [32] y)))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPSSRA)
+ v0 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpMIPSCMOVZ, config.fe.TypeUInt32())
+ v1.AddArg(y)
+ v2 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+ v2.AuxInt = -1
+ v1.AddArg(v2)
+ v3 := b.NewValue0(v.Line, OpMIPSSGTUconst, config.fe.TypeBool())
+ v3.AuxInt = 32
+ v3.AddArg(y)
+ v1.AddArg(v3)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueMIPS_OpRsh16x64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh16x64 x (Const64 [c]))
+ // cond: uint32(c) < 16
+ // result: (SRAconst (SLLconst <config.fe.TypeUInt32()> x [16]) [c+16])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpConst64 {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint32(c) < 16) {
+ break
+ }
+ v.reset(OpMIPSSRAconst)
+ v.AuxInt = c + 16
+ v0 := b.NewValue0(v.Line, OpMIPSSLLconst, config.fe.TypeUInt32())
+ v0.AuxInt = 16
+ v0.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (Rsh16x64 x (Const64 [c]))
+ // cond: uint32(c) >= 16
+ // result: (SRAconst (SLLconst <config.fe.TypeUInt32()> x [16]) [31])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpConst64 {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint32(c) >= 16) {
+ break
+ }
+ v.reset(OpMIPSSRAconst)
+ v.AuxInt = 31
+ v0 := b.NewValue0(v.Line, OpMIPSSLLconst, config.fe.TypeUInt32())
+ v0.AuxInt = 16
+ v0.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS_OpRsh16x8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh16x8 x y)
+ // cond:
+ // result: (SRA (SignExt16to32 x) ( CMOVZ <config.fe.TypeUInt32()> (ZeroExt8to32 y) (MOVWconst [-1]) (SGTUconst [32] (ZeroExt8to32 y))))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPSSRA)
+ v0 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpMIPSCMOVZ, config.fe.TypeUInt32())
+ v2 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+ v2.AddArg(y)
+ v1.AddArg(v2)
+ v3 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+ v3.AuxInt = -1
+ v1.AddArg(v3)
+ v4 := b.NewValue0(v.Line, OpMIPSSGTUconst, config.fe.TypeBool())
+ v4.AuxInt = 32
+ v5 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+ v5.AddArg(y)
+ v4.AddArg(v5)
+ v1.AddArg(v4)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueMIPS_OpRsh32Ux16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh32Ux16 <t> x y)
+ // cond:
+ // result: (CMOVZ (SRL <t> x (ZeroExt16to32 y) ) (MOVWconst [0]) (SGTUconst [32] (ZeroExt16to32 y)))
+ for {
+ t := v.Type
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPSCMOVZ)
+ v0 := b.NewValue0(v.Line, OpMIPSSRL, t)
+ v0.AddArg(x)
+ v1 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+ v1.AddArg(y)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ v2 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+ v2.AuxInt = 0
+ v.AddArg(v2)
+ v3 := b.NewValue0(v.Line, OpMIPSSGTUconst, config.fe.TypeBool())
+ v3.AuxInt = 32
+ v4 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+ v4.AddArg(y)
+ v3.AddArg(v4)
+ v.AddArg(v3)
+ return true
+ }
+}
+func rewriteValueMIPS_OpRsh32Ux32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh32Ux32 <t> x y)
+ // cond:
+ // result: (CMOVZ (SRL <t> x y) (MOVWconst [0]) (SGTUconst [32] y))
+ for {
+ t := v.Type
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPSCMOVZ)
+ v0 := b.NewValue0(v.Line, OpMIPSSRL, t)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+ v1.AuxInt = 0
+ v.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpMIPSSGTUconst, config.fe.TypeBool())
+ v2.AuxInt = 32
+ v2.AddArg(y)
+ v.AddArg(v2)
+ return true
+ }
+}
+func rewriteValueMIPS_OpRsh32Ux64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh32Ux64 x (Const64 [c]))
+ // cond: uint32(c) < 32
+ // result: (SRLconst x [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpConst64 {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint32(c) < 32) {
+ break
+ }
+ v.reset(OpMIPSSRLconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (Rsh32Ux64 _ (Const64 [c]))
+ // cond: uint32(c) >= 32
+ // result: (MOVWconst [0])
+ for {
+ v_1 := v.Args[1]
+ if v_1.Op != OpConst64 {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint32(c) >= 32) {
+ break
+ }
+ v.reset(OpMIPSMOVWconst)
+ v.AuxInt = 0
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS_OpRsh32Ux8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh32Ux8 <t> x y)
+ // cond:
+ // result: (CMOVZ (SRL <t> x (ZeroExt8to32 y) ) (MOVWconst [0]) (SGTUconst [32] (ZeroExt8to32 y)))
+ for {
+ t := v.Type
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPSCMOVZ)
+ v0 := b.NewValue0(v.Line, OpMIPSSRL, t)
+ v0.AddArg(x)
+ v1 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+ v1.AddArg(y)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ v2 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+ v2.AuxInt = 0
+ v.AddArg(v2)
+ v3 := b.NewValue0(v.Line, OpMIPSSGTUconst, config.fe.TypeBool())
+ v3.AuxInt = 32
+ v4 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+ v4.AddArg(y)
+ v3.AddArg(v4)
+ v.AddArg(v3)
+ return true
+ }
+}
+func rewriteValueMIPS_OpRsh32x16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh32x16 x y)
+ // cond:
+ // result: (SRA x ( CMOVZ <config.fe.TypeUInt32()> (ZeroExt16to32 y) (MOVWconst [-1]) (SGTUconst [32] (ZeroExt16to32 y))))
+ for {
+ 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())
+ v1.AddArg(y)
+ v0.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+ v2.AuxInt = -1
+ v0.AddArg(v2)
+ v3 := b.NewValue0(v.Line, OpMIPSSGTUconst, config.fe.TypeBool())
+ v3.AuxInt = 32
+ v4 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+ v4.AddArg(y)
+ v3.AddArg(v4)
+ v0.AddArg(v3)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueMIPS_OpRsh32x32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh32x32 x y)
+ // cond:
+ // result: (SRA x ( CMOVZ <config.fe.TypeUInt32()> y (MOVWconst [-1]) (SGTUconst [32] y)))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPSSRA)
+ v.AddArg(x)
+ v0 := b.NewValue0(v.Line, OpMIPSCMOVZ, config.fe.TypeUInt32())
+ v0.AddArg(y)
+ v1 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+ v1.AuxInt = -1
+ v0.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpMIPSSGTUconst, config.fe.TypeBool())
+ v2.AuxInt = 32
+ v2.AddArg(y)
+ v0.AddArg(v2)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueMIPS_OpRsh32x64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh32x64 x (Const64 [c]))
+ // cond: uint32(c) < 32
+ // result: (SRAconst x [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpConst64 {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint32(c) < 32) {
+ break
+ }
+ v.reset(OpMIPSSRAconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (Rsh32x64 x (Const64 [c]))
+ // cond: uint32(c) >= 32
+ // result: (SRAconst x [31])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpConst64 {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint32(c) >= 32) {
+ break
+ }
+ v.reset(OpMIPSSRAconst)
+ v.AuxInt = 31
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS_OpRsh32x8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh32x8 x y)
+ // cond:
+ // result: (SRA x ( CMOVZ <config.fe.TypeUInt32()> (ZeroExt8to32 y) (MOVWconst [-1]) (SGTUconst [32] (ZeroExt8to32 y))))
+ for {
+ 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())
+ v1.AddArg(y)
+ v0.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+ v2.AuxInt = -1
+ v0.AddArg(v2)
+ v3 := b.NewValue0(v.Line, OpMIPSSGTUconst, config.fe.TypeBool())
+ v3.AuxInt = 32
+ v4 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+ v4.AddArg(y)
+ v3.AddArg(v4)
+ v0.AddArg(v3)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueMIPS_OpRsh8Ux16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh8Ux16 <t> x y)
+ // cond:
+ // result: (CMOVZ (SRL <t> (ZeroExt8to32 x) (ZeroExt16to32 y) ) (MOVWconst [0]) (SGTUconst [32] (ZeroExt16to32 y)))
+ for {
+ t := v.Type
+ 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())
+ v1.AddArg(x)
+ v0.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+ v2.AddArg(y)
+ v0.AddArg(v2)
+ v.AddArg(v0)
+ v3 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+ v3.AuxInt = 0
+ v.AddArg(v3)
+ v4 := b.NewValue0(v.Line, OpMIPSSGTUconst, config.fe.TypeBool())
+ v4.AuxInt = 32
+ v5 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+ v5.AddArg(y)
+ v4.AddArg(v5)
+ v.AddArg(v4)
+ return true
+ }
+}
+func rewriteValueMIPS_OpRsh8Ux32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh8Ux32 <t> x y)
+ // cond:
+ // result: (CMOVZ (SRL <t> (ZeroExt8to32 x) y) (MOVWconst [0]) (SGTUconst [32] y))
+ for {
+ t := v.Type
+ 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())
+ v1.AddArg(x)
+ v0.AddArg(v1)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ v2 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+ v2.AuxInt = 0
+ v.AddArg(v2)
+ v3 := b.NewValue0(v.Line, OpMIPSSGTUconst, config.fe.TypeBool())
+ v3.AuxInt = 32
+ v3.AddArg(y)
+ v.AddArg(v3)
+ return true
+ }
+}
+func rewriteValueMIPS_OpRsh8Ux64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh8Ux64 x (Const64 [c]))
+ // cond: uint32(c) < 8
+ // result: (SRLconst (SLLconst <config.fe.TypeUInt32()> x [24]) [c+24])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpConst64 {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint32(c) < 8) {
+ break
+ }
+ v.reset(OpMIPSSRLconst)
+ v.AuxInt = c + 24
+ v0 := b.NewValue0(v.Line, OpMIPSSLLconst, config.fe.TypeUInt32())
+ v0.AuxInt = 24
+ v0.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (Rsh8Ux64 _ (Const64 [c]))
+ // cond: uint32(c) >= 8
+ // result: (MOVWconst [0])
+ for {
+ v_1 := v.Args[1]
+ if v_1.Op != OpConst64 {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint32(c) >= 8) {
+ break
+ }
+ v.reset(OpMIPSMOVWconst)
+ v.AuxInt = 0
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS_OpRsh8Ux8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh8Ux8 <t> x y)
+ // cond:
+ // result: (CMOVZ (SRL <t> (ZeroExt8to32 x) (ZeroExt8to32 y) ) (MOVWconst [0]) (SGTUconst [32] (ZeroExt8to32 y)))
+ for {
+ t := v.Type
+ 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())
+ v1.AddArg(x)
+ v0.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+ v2.AddArg(y)
+ v0.AddArg(v2)
+ v.AddArg(v0)
+ v3 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+ v3.AuxInt = 0
+ v.AddArg(v3)
+ v4 := b.NewValue0(v.Line, OpMIPSSGTUconst, config.fe.TypeBool())
+ v4.AuxInt = 32
+ v5 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+ v5.AddArg(y)
+ v4.AddArg(v5)
+ v.AddArg(v4)
+ return true
+ }
+}
+func rewriteValueMIPS_OpRsh8x16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh8x16 x y)
+ // cond:
+ // result: (SRA (SignExt16to32 x) ( CMOVZ <config.fe.TypeUInt32()> (ZeroExt16to32 y) (MOVWconst [-1]) (SGTUconst [32] (ZeroExt16to32 y))))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPSSRA)
+ v0 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpMIPSCMOVZ, config.fe.TypeUInt32())
+ v2 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+ v2.AddArg(y)
+ v1.AddArg(v2)
+ v3 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+ v3.AuxInt = -1
+ v1.AddArg(v3)
+ v4 := b.NewValue0(v.Line, OpMIPSSGTUconst, config.fe.TypeBool())
+ v4.AuxInt = 32
+ v5 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+ v5.AddArg(y)
+ v4.AddArg(v5)
+ v1.AddArg(v4)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueMIPS_OpRsh8x32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh8x32 x y)
+ // cond:
+ // result: (SRA (SignExt16to32 x) ( CMOVZ <config.fe.TypeUInt32()> y (MOVWconst [-1]) (SGTUconst [32] y)))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPSSRA)
+ v0 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpMIPSCMOVZ, config.fe.TypeUInt32())
+ v1.AddArg(y)
+ v2 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+ v2.AuxInt = -1
+ v1.AddArg(v2)
+ v3 := b.NewValue0(v.Line, OpMIPSSGTUconst, config.fe.TypeBool())
+ v3.AuxInt = 32
+ v3.AddArg(y)
+ v1.AddArg(v3)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueMIPS_OpRsh8x64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh8x64 x (Const64 [c]))
+ // cond: uint32(c) < 8
+ // result: (SRAconst (SLLconst <config.fe.TypeUInt32()> x [24]) [c+24])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpConst64 {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint32(c) < 8) {
+ break
+ }
+ v.reset(OpMIPSSRAconst)
+ v.AuxInt = c + 24
+ v0 := b.NewValue0(v.Line, OpMIPSSLLconst, config.fe.TypeUInt32())
+ v0.AuxInt = 24
+ v0.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (Rsh8x64 x (Const64 [c]))
+ // cond: uint32(c) >= 8
+ // result: (SRAconst (SLLconst <config.fe.TypeUInt32()> x [24]) [31])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpConst64 {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint32(c) >= 8) {
+ break
+ }
+ v.reset(OpMIPSSRAconst)
+ v.AuxInt = 31
+ v0 := b.NewValue0(v.Line, OpMIPSSLLconst, config.fe.TypeUInt32())
+ v0.AuxInt = 24
+ v0.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS_OpRsh8x8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh8x8 x y)
+ // cond:
+ // result: (SRA (SignExt16to32 x) ( CMOVZ <config.fe.TypeUInt32()> (ZeroExt8to32 y) (MOVWconst [-1]) (SGTUconst [32] (ZeroExt8to32 y))))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPSSRA)
+ v0 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpMIPSCMOVZ, config.fe.TypeUInt32())
+ v2 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+ v2.AddArg(y)
+ v1.AddArg(v2)
+ v3 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+ v3.AuxInt = -1
+ v1.AddArg(v3)
+ v4 := b.NewValue0(v.Line, OpMIPSSGTUconst, config.fe.TypeBool())
+ v4.AuxInt = 32
+ v5 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+ v5.AddArg(y)
+ v4.AddArg(v5)
+ v1.AddArg(v4)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueMIPS_OpSelect0(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Select0 (Add32carry <t> x y))
+ // cond:
+ // result: (ADD <t.FieldType(0)> x y)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpAdd32carry {
+ break
+ }
+ t := v_0.Type
+ x := v_0.Args[0]
+ y := v_0.Args[1]
+ v.reset(OpMIPSADD)
+ v.Type = t.FieldType(0)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (Select0 (Sub32carry <t> x y))
+ // cond:
+ // result: (SUB <t.FieldType(0)> x y)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpSub32carry {
+ break
+ }
+ t := v_0.Type
+ x := v_0.Args[0]
+ y := v_0.Args[1]
+ v.reset(OpMIPSSUB)
+ v.Type = t.FieldType(0)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (Select0 (MULTU x (MOVWconst [c])))
+ // cond: x.Op != OpMIPSMOVWconst
+ // result: (Select0 (MULTU (MOVWconst [c]) x ))
+ 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 {
+ break
+ }
+ c := v_0_1.AuxInt
+ if !(x.Op != OpMIPSMOVWconst) {
+ 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)
+ 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_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 [1]) _ ))
+ // cond:
+ // result: (MOVWconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPSMULTU {
+ break
+ }
+ v_0_0 := v_0.Args[0]
+ if v_0_0.Op != OpMIPSMOVWconst {
+ break
+ }
+ if v_0_0.AuxInt != 1 {
+ break
+ }
+ v.reset(OpMIPSMOVWconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (Select0 (MULTU (MOVWconst [-1]) x ))
+ // 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_0 := v_0.Args[0]
+ if v_0_0.Op != OpMIPSMOVWconst {
+ break
+ }
+ if v_0_0.AuxInt != -1 {
+ break
+ }
+ x := v_0.Args[1]
+ v.reset(OpMIPSCMOVZ)
+ v0 := b.NewValue0(v.Line, OpMIPSADDconst, x.Type)
+ v0.AuxInt = -1
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+ v1.AuxInt = 0
+ v.AddArg(v1)
+ v.AddArg(x)
+ return true
+ }
+ // match: (Select0 (MULTU (MOVWconst [c]) x ))
+ // 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_0 := v_0.Args[0]
+ if v_0_0.Op != OpMIPSMOVWconst {
+ break
+ }
+ c := v_0_0.AuxInt
+ x := v_0.Args[1]
+ if !(isPowerOfTwo(int64(uint32(c)))) {
+ break
+ }
+ v.reset(OpMIPSSRLconst)
+ v.AuxInt = 32 - log2(int64(uint32(c)))
+ v.AddArg(x)
+ return true
+ }
+ // match: (Select0 (MULTU (MOVWconst [c]) (MOVWconst [d])))
+ // cond:
+ // result: (MOVWconst [(c*d)>>32])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPSMULTU {
+ break
+ }
+ 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 = (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_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])))
+ // cond:
+ // result: (MOVWconst [int64(int32(uint32(c)%uint32(d)))])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPSDIVU {
+ break
+ }
+ 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(uint32(c) % uint32(d)))
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS_OpSelect1(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Select1 (Add32carry <t> x y))
+ // cond:
+ // result: (SGTU <config.fe.TypeBool()> x (ADD <t.FieldType(0)> x y))
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpAdd32carry {
+ break
+ }
+ t := v_0.Type
+ x := v_0.Args[0]
+ y := v_0.Args[1]
+ v.reset(OpMIPSSGTU)
+ v.Type = config.fe.TypeBool()
+ v.AddArg(x)
+ v0 := b.NewValue0(v.Line, OpMIPSADD, t.FieldType(0))
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (Select1 (Sub32carry <t> x y))
+ // cond:
+ // result: (SGTU <config.fe.TypeBool()> (SUB <t.FieldType(0)> x y) x)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpSub32carry {
+ break
+ }
+ t := v_0.Type
+ 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))
+ 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 ))
+ 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 {
+ break
+ }
+ c := v_0_1.AuxInt
+ if !(x.Op != OpMIPSMOVWconst) {
+ 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)
+ return true
+ }
+ // match: (Select1 (MULTU (MOVWconst [0]) _ ))
+ // cond:
+ // result: (MOVWconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPSMULTU {
+ break
+ }
+ 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: (Select1 (MULTU (MOVWconst [1]) x ))
+ // cond:
+ // result: x
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPSMULTU {
+ break
+ }
+ v_0_0 := v_0.Args[0]
+ if v_0_0.Op != OpMIPSMOVWconst {
+ 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 (MULTU (MOVWconst [-1]) x ))
+ // cond:
+ // result: (NEG <x.Type> x)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPSMULTU {
+ break
+ }
+ v_0_0 := v_0.Args[0]
+ if v_0_0.Op != OpMIPSMOVWconst {
+ break
+ }
+ if v_0_0.AuxInt != -1 {
+ break
+ }
+ x := v_0.Args[1]
+ 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 {
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPSMULTU {
+ break
+ }
+ v_0_0 := v_0.Args[0]
+ if v_0_0.Op != OpMIPSMOVWconst {
+ break
+ }
+ c := v_0_0.AuxInt
+ x := v_0.Args[1]
+ if !(isPowerOfTwo(int64(uint32(c)))) {
+ break
+ }
+ v.reset(OpMIPSSLLconst)
+ v.AuxInt = log2(int64(uint32(c)))
+ v.AddArg(x)
+ return true
+ }
+ // match: (Select1 (MULTU (MOVWconst [c]) (MOVWconst [d])))
+ // cond:
+ // result: (MOVWconst [int64(int32(uint32(c)*uint32(d)))])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPSMULTU {
+ break
+ }
+ 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(uint32(c) * uint32(d)))
+ return true
+ }
+ // match: (Select1 (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_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: (Select1 (DIVU (MOVWconst [c]) (MOVWconst [d])))
+ // cond:
+ // result: (MOVWconst [int64(int32(uint32(c)/uint32(d)))])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPSDIVU {
+ break
+ }
+ 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(uint32(c) / uint32(d)))
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS_OpSignExt16to32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SignExt16to32 x)
+ // cond:
+ // result: (MOVHreg x)
+ for {
+ x := v.Args[0]
+ v.reset(OpMIPSMOVHreg)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueMIPS_OpSignExt8to16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SignExt8to16 x)
+ // cond:
+ // result: (MOVBreg x)
+ for {
+ x := v.Args[0]
+ v.reset(OpMIPSMOVBreg)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueMIPS_OpSignExt8to32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SignExt8to32 x)
+ // cond:
+ // result: (MOVBreg x)
+ for {
+ x := v.Args[0]
+ v.reset(OpMIPSMOVBreg)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueMIPS_OpSignmask(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Signmask x)
+ // cond:
+ // result: (SRAconst x [31])
+ for {
+ x := v.Args[0]
+ v.reset(OpMIPSSRAconst)
+ v.AuxInt = 31
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueMIPS_OpSlicemask(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Slicemask x)
+ // cond:
+ // result: (NEG (SGT x (MOVWconst [0])))
+ for {
+ x := v.Args[0]
+ v.reset(OpMIPSNEG)
+ v0 := b.NewValue0(v.Line, OpMIPSSGT, config.fe.TypeBool())
+ 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
+ // match: (Sqrt x)
+ // cond:
+ // result: (SQRTD x)
+ for {
+ x := v.Args[0]
+ v.reset(OpMIPSSQRTD)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueMIPS_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(OpMIPSCALLstatic)
+ v.AuxInt = argwid
+ v.Aux = target
+ v.AddArg(mem)
+ return true
+ }
+}
+func rewriteValueMIPS_OpStore(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Store [1] ptr val mem)
+ // cond:
+ // result: (MOVBstore ptr val mem)
+ for {
+ if v.AuxInt != 1 {
+ break
+ }
+ ptr := v.Args[0]
+ val := v.Args[1]
+ mem := v.Args[2]
+ v.reset(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 {
+ break
+ }
+ ptr := v.Args[0]
+ val := v.Args[1]
+ mem := v.Args[2]
+ v.reset(OpMIPSMOVHstore)
+ 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)
+ for {
+ if v.AuxInt != 4 {
+ break
+ }
+ ptr := v.Args[0]
+ val := v.Args[1]
+ mem := v.Args[2]
+ if !(!is32BitFloat(val.Type)) {
+ break
+ }
+ v.reset(OpMIPSMOVWstore)
+ v.AddArg(ptr)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (Store [8] ptr val mem)
+ // cond: !is64BitFloat(val.Type)
+ // result: (MOVWstore ptr val mem)
+ for {
+ if v.AuxInt != 8 {
+ break
+ }
+ ptr := v.Args[0]
+ val := v.Args[1]
+ mem := v.Args[2]
+ if !(!is64BitFloat(val.Type)) {
+ break
+ }
+ v.reset(OpMIPSMOVWstore)
+ v.AddArg(ptr)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (Store [4] ptr val mem)
+ // cond: is32BitFloat(val.Type)
+ // result: (MOVFstore ptr val mem)
+ for {
+ if v.AuxInt != 4 {
+ break
+ }
+ ptr := v.Args[0]
+ val := v.Args[1]
+ mem := v.Args[2]
+ if !(is32BitFloat(val.Type)) {
+ break
+ }
+ v.reset(OpMIPSMOVFstore)
+ v.AddArg(ptr)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (Store [8] ptr val mem)
+ // cond: is64BitFloat(val.Type)
+ // result: (MOVDstore ptr val mem)
+ for {
+ if v.AuxInt != 8 {
+ break
+ }
+ ptr := v.Args[0]
+ val := v.Args[1]
+ mem := v.Args[2]
+ if !(is64BitFloat(val.Type)) {
+ break
+ }
+ v.reset(OpMIPSMOVDstore)
+ v.AddArg(ptr)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS_OpSub16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Sub16 x y)
+ // cond:
+ // result: (SUB x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPSSUB)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueMIPS_OpSub32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Sub32 x y)
+ // cond:
+ // result: (SUB x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPSSUB)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueMIPS_OpSub32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Sub32F x y)
+ // cond:
+ // result: (SUBF x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPSSUBF)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueMIPS_OpSub32withcarry(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Sub32withcarry <t> x y c)
+ // cond:
+ // result: (SUB (SUB <t> x y) c)
+ for {
+ t := v.Type
+ x := v.Args[0]
+ y := v.Args[1]
+ c := v.Args[2]
+ v.reset(OpMIPSSUB)
+ v0 := b.NewValue0(v.Line, OpMIPSSUB, t)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ v.AddArg(c)
+ return true
+ }
+}
+func rewriteValueMIPS_OpSub64F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Sub64F x y)
+ // cond:
+ // result: (SUBD x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPSSUBD)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueMIPS_OpSub8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Sub8 x y)
+ // cond:
+ // result: (SUB x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPSSUB)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueMIPS_OpSubPtr(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SubPtr x y)
+ // cond:
+ // result: (SUB x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPSSUB)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueMIPS_OpTrunc16to8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Trunc16to8 x)
+ // cond:
+ // result: x
+ for {
+ x := v.Args[0]
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueMIPS_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 rewriteValueMIPS_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 rewriteValueMIPS_OpXor16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Xor16 x y)
+ // cond:
+ // result: (XOR x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPSXOR)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueMIPS_OpXor32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Xor32 x y)
+ // cond:
+ // result: (XOR x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPSXOR)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueMIPS_OpXor8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Xor8 x y)
+ // cond:
+ // result: (XOR x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPSXOR)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueMIPS_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) {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = mem.Type
+ v.AddArg(mem)
+ return true
+ }
+ // match: (Zero [s] ptr mem)
+ // cond: SizeAndAlign(s).Size() == 1
+ // result: (MOVBstore ptr (MOVWconst [0]) mem)
+ for {
+ s := v.AuxInt
+ ptr := v.Args[0]
+ mem := v.Args[1]
+ if !(SizeAndAlign(s).Size() == 1) {
+ break
+ }
+ v.reset(OpMIPSMOVBstore)
+ v.AddArg(ptr)
+ v0 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+ 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
+ // result: (MOVHstore ptr (MOVWconst [0]) mem)
+ for {
+ s := v.AuxInt
+ ptr := v.Args[0]
+ mem := v.Args[1]
+ if !(SizeAndAlign(s).Size() == 2 && SizeAndAlign(s).Align()%2 == 0) {
+ break
+ }
+ v.reset(OpMIPSMOVHstore)
+ v.AddArg(ptr)
+ v0 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+ v0.AuxInt = 0
+ v.AddArg(v0)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (Zero [s] ptr mem)
+ // cond: SizeAndAlign(s).Size() == 2
+ // 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) {
+ break
+ }
+ v.reset(OpMIPSMOVBstore)
+ v.AuxInt = 1
+ v.AddArg(ptr)
+ v0 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+ v0.AuxInt = 0
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpMIPSMOVBstore, TypeMem)
+ v1.AuxInt = 0
+ v1.AddArg(ptr)
+ v2 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+ 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
+ // result: (MOVWstore ptr (MOVWconst [0]) mem)
+ for {
+ s := v.AuxInt
+ ptr := v.Args[0]
+ mem := v.Args[1]
+ if !(SizeAndAlign(s).Size() == 4 && SizeAndAlign(s).Align()%4 == 0) {
+ break
+ }
+ v.reset(OpMIPSMOVWstore)
+ v.AddArg(ptr)
+ v0 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+ 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
+ // result: (MOVHstore [2] ptr (MOVWconst [0]) (MOVHstore [0] ptr (MOVWconst [0]) mem))
+ for {
+ s := v.AuxInt
+ ptr := v.Args[0]
+ mem := v.Args[1]
+ if !(SizeAndAlign(s).Size() == 4 && SizeAndAlign(s).Align()%2 == 0) {
+ break
+ }
+ v.reset(OpMIPSMOVHstore)
+ v.AuxInt = 2
+ v.AddArg(ptr)
+ v0 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+ v0.AuxInt = 0
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpMIPSMOVHstore, TypeMem)
+ v1.AuxInt = 0
+ v1.AddArg(ptr)
+ v2 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+ v2.AuxInt = 0
+ v1.AddArg(v2)
+ v1.AddArg(mem)
+ v.AddArg(v1)
+ return true
+ }
+ // match: (Zero [s] ptr mem)
+ // cond: SizeAndAlign(s).Size() == 4
+ // 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) {
+ break
+ }
+ v.reset(OpMIPSMOVBstore)
+ v.AuxInt = 3
+ v.AddArg(ptr)
+ v0 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+ v0.AuxInt = 0
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpMIPSMOVBstore, TypeMem)
+ v1.AuxInt = 2
+ v1.AddArg(ptr)
+ v2 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+ v2.AuxInt = 0
+ v1.AddArg(v2)
+ v3 := b.NewValue0(v.Line, OpMIPSMOVBstore, TypeMem)
+ v3.AuxInt = 1
+ v3.AddArg(ptr)
+ v4 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+ v4.AuxInt = 0
+ v3.AddArg(v4)
+ v5 := b.NewValue0(v.Line, OpMIPSMOVBstore, TypeMem)
+ v5.AuxInt = 0
+ v5.AddArg(ptr)
+ v6 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+ v6.AuxInt = 0
+ v5.AddArg(v6)
+ v5.AddArg(mem)
+ v3.AddArg(v5)
+ v1.AddArg(v3)
+ v.AddArg(v1)
+ return true
+ }
+ // match: (Zero [s] ptr mem)
+ // cond: SizeAndAlign(s).Size() == 3
+ // 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) {
+ break
+ }
+ v.reset(OpMIPSMOVBstore)
+ v.AuxInt = 2
+ v.AddArg(ptr)
+ v0 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+ v0.AuxInt = 0
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpMIPSMOVBstore, TypeMem)
+ v1.AuxInt = 1
+ v1.AddArg(ptr)
+ v2 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+ v2.AuxInt = 0
+ v1.AddArg(v2)
+ v3 := b.NewValue0(v.Line, OpMIPSMOVBstore, TypeMem)
+ v3.AuxInt = 0
+ v3.AddArg(ptr)
+ v4 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+ v4.AuxInt = 0
+ v3.AddArg(v4)
+ v3.AddArg(mem)
+ v1.AddArg(v3)
+ v.AddArg(v1)
+ return true
+ }
+ // match: (Zero [s] ptr mem)
+ // cond: SizeAndAlign(s).Size() == 6 && SizeAndAlign(s).Align()%2 == 0
+ // result: (MOVHstore [4] ptr (MOVWconst [0]) (MOVHstore [2] ptr (MOVWconst [0]) (MOVHstore [0] ptr (MOVWconst [0]) mem)))
+ for {
+ s := v.AuxInt
+ ptr := v.Args[0]
+ mem := v.Args[1]
+ if !(SizeAndAlign(s).Size() == 6 && SizeAndAlign(s).Align()%2 == 0) {
+ break
+ }
+ v.reset(OpMIPSMOVHstore)
+ v.AuxInt = 4
+ v.AddArg(ptr)
+ v0 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+ v0.AuxInt = 0
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpMIPSMOVHstore, TypeMem)
+ v1.AuxInt = 2
+ v1.AddArg(ptr)
+ v2 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+ v2.AuxInt = 0
+ v1.AddArg(v2)
+ v3 := b.NewValue0(v.Line, OpMIPSMOVHstore, TypeMem)
+ v3.AuxInt = 0
+ v3.AddArg(ptr)
+ v4 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+ v4.AuxInt = 0
+ v3.AddArg(v4)
+ v3.AddArg(mem)
+ v1.AddArg(v3)
+ v.AddArg(v1)
+ return true
+ }
+ // match: (Zero [s] ptr mem)
+ // cond: SizeAndAlign(s).Size() == 8 && SizeAndAlign(s).Align()%4 == 0
+ // result: (MOVWstore [4] ptr (MOVWconst [0]) (MOVWstore [0] ptr (MOVWconst [0]) mem))
+ for {
+ s := v.AuxInt
+ ptr := v.Args[0]
+ mem := v.Args[1]
+ if !(SizeAndAlign(s).Size() == 8 && SizeAndAlign(s).Align()%4 == 0) {
+ break
+ }
+ v.reset(OpMIPSMOVWstore)
+ v.AuxInt = 4
+ v.AddArg(ptr)
+ v0 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+ v0.AuxInt = 0
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpMIPSMOVWstore, TypeMem)
+ v1.AuxInt = 0
+ v1.AddArg(ptr)
+ v2 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+ 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
+ // result: (MOVWstore [8] ptr (MOVWconst [0]) (MOVWstore [4] ptr (MOVWconst [0]) (MOVWstore [0] ptr (MOVWconst [0]) mem)))
+ for {
+ s := v.AuxInt
+ ptr := v.Args[0]
+ mem := v.Args[1]
+ if !(SizeAndAlign(s).Size() == 12 && SizeAndAlign(s).Align()%4 == 0) {
+ break
+ }
+ v.reset(OpMIPSMOVWstore)
+ v.AuxInt = 8
+ v.AddArg(ptr)
+ v0 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+ v0.AuxInt = 0
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpMIPSMOVWstore, TypeMem)
+ v1.AuxInt = 4
+ v1.AddArg(ptr)
+ v2 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+ v2.AuxInt = 0
+ v1.AddArg(v2)
+ v3 := b.NewValue0(v.Line, OpMIPSMOVWstore, TypeMem)
+ v3.AuxInt = 0
+ v3.AddArg(ptr)
+ v4 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+ v4.AuxInt = 0
+ v3.AddArg(v4)
+ v3.AddArg(mem)
+ v1.AddArg(v3)
+ v.AddArg(v1)
+ return true
+ }
+ // match: (Zero [s] ptr mem)
+ // cond: SizeAndAlign(s).Size() == 16 && SizeAndAlign(s).Align()%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
+ ptr := v.Args[0]
+ mem := v.Args[1]
+ if !(SizeAndAlign(s).Size() == 16 && SizeAndAlign(s).Align()%4 == 0) {
+ break
+ }
+ v.reset(OpMIPSMOVWstore)
+ v.AuxInt = 12
+ v.AddArg(ptr)
+ v0 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+ v0.AuxInt = 0
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpMIPSMOVWstore, TypeMem)
+ v1.AuxInt = 8
+ v1.AddArg(ptr)
+ v2 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+ v2.AuxInt = 0
+ v1.AddArg(v2)
+ v3 := b.NewValue0(v.Line, OpMIPSMOVWstore, TypeMem)
+ v3.AuxInt = 4
+ v3.AddArg(ptr)
+ v4 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+ v4.AuxInt = 0
+ v3.AddArg(v4)
+ v5 := b.NewValue0(v.Line, OpMIPSMOVWstore, TypeMem)
+ v5.AuxInt = 0
+ v5.AddArg(ptr)
+ v6 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+ v6.AuxInt = 0
+ v5.AddArg(v6)
+ v5.AddArg(mem)
+ v3.AddArg(v5)
+ v1.AddArg(v3)
+ 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)
+ for {
+ s := v.AuxInt
+ ptr := v.Args[0]
+ mem := v.Args[1]
+ if !(SizeAndAlign(s).Size() > 16 || SizeAndAlign(s).Align()%4 != 0) {
+ break
+ }
+ v.reset(OpMIPSLoweredZero)
+ v.AuxInt = SizeAndAlign(s).Align()
+ v.AddArg(ptr)
+ v0 := b.NewValue0(v.Line, OpMIPSADDconst, 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 rewriteValueMIPS_OpZeroExt16to32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ZeroExt16to32 x)
+ // cond:
+ // result: (MOVHUreg x)
+ for {
+ x := v.Args[0]
+ v.reset(OpMIPSMOVHUreg)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueMIPS_OpZeroExt8to16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ZeroExt8to16 x)
+ // cond:
+ // result: (MOVBUreg x)
+ for {
+ x := v.Args[0]
+ v.reset(OpMIPSMOVBUreg)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueMIPS_OpZeroExt8to32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ZeroExt8to32 x)
+ // cond:
+ // result: (MOVBUreg x)
+ for {
+ x := v.Args[0]
+ v.reset(OpMIPSMOVBUreg)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueMIPS_OpZeromask(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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.AddArg(x)
+ v1 := b.NewValue0(v.Line, OpMIPSMOVWconst, config.fe.TypeUInt32())
+ v1.AuxInt = 0
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteBlockMIPS(b *Block, config *Config) bool {
+ switch b.Kind {
+ case BlockMIPSEQ:
+ // match: (EQ (FPFlagTrue cmp) yes no)
+ // cond:
+ // result: (FPF cmp yes no)
+ for {
+ v := b.Control
+ if v.Op != OpMIPSFPFlagTrue {
+ 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)
+ // cond:
+ // result: (FPT cmp yes no)
+ for {
+ v := b.Control
+ if v.Op != OpMIPSFPFlagFalse {
+ 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)
+ // cond:
+ // result: (NE cmp yes no)
+ for {
+ v := b.Control
+ if v.Op != OpMIPSXORconst {
+ break
+ }
+ if v.AuxInt != 1 {
+ break
+ }
+ cmp := v.Args[0]
+ if cmp.Op != OpMIPSSGT {
+ break
+ }
+ yes := b.Succs[0]
+ no := b.Succs[1]
+ b.Kind = BlockMIPSNE
+ b.SetControl(cmp)
+ _ = yes
+ _ = no
+ return true
+ }
+ // match: (EQ (XORconst [1] cmp:(SGTU _ _)) yes no)
+ // cond:
+ // result: (NE cmp yes no)
+ for {
+ v := b.Control
+ if v.Op != OpMIPSXORconst {
+ break
+ }
+ if v.AuxInt != 1 {
+ break
+ }
+ cmp := v.Args[0]
+ if cmp.Op != OpMIPSSGTU {
+ break
+ }
+ yes := b.Succs[0]
+ no := b.Succs[1]
+ b.Kind = BlockMIPSNE
+ b.SetControl(cmp)
+ _ = yes
+ _ = no
+ return true
+ }
+ // match: (EQ (XORconst [1] cmp:(SGTconst _)) yes no)
+ // cond:
+ // result: (NE cmp yes no)
+ for {
+ v := b.Control
+ if v.Op != OpMIPSXORconst {
+ break
+ }
+ if v.AuxInt != 1 {
+ break
+ }
+ cmp := v.Args[0]
+ 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)
+ // cond:
+ // result: (NE cmp yes no)
+ for {
+ v := b.Control
+ if v.Op != OpMIPSXORconst {
+ break
+ }
+ if v.AuxInt != 1 {
+ break
+ }
+ cmp := v.Args[0]
+ 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)
+ // cond:
+ // result: (NE cmp yes no)
+ for {
+ v := b.Control
+ if v.Op != OpMIPSXORconst {
+ break
+ }
+ if v.AuxInt != 1 {
+ break
+ }
+ cmp := v.Args[0]
+ 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)
+ // cond:
+ // result: (NE cmp yes no)
+ for {
+ v := b.Control
+ if v.Op != OpMIPSXORconst {
+ break
+ }
+ if v.AuxInt != 1 {
+ break
+ }
+ cmp := v.Args[0]
+ 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)
+ // cond:
+ // result: (NE x yes no)
+ for {
+ v := b.Control
+ if v.Op != OpMIPSSGTUconst {
+ break
+ }
+ if v.AuxInt != 1 {
+ 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)
+ // cond:
+ // result: (EQ x yes no)
+ for {
+ v := b.Control
+ if v.Op != OpMIPSSGTUzero {
+ 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)
+ // cond:
+ // result: (GEZ x yes no)
+ for {
+ v := b.Control
+ if v.Op != OpMIPSSGTconst {
+ break
+ }
+ if v.AuxInt != 0 {
+ 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)
+ // cond:
+ // result: (LEZ x yes no)
+ for {
+ v := b.Control
+ if v.Op != OpMIPSSGTzero {
+ 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)
+ // cond:
+ // result: (First nil yes no)
+ for {
+ v := b.Control
+ if v.Op != OpMIPSMOVWconst {
+ break
+ }
+ 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)
+ // cond: c != 0
+ // result: (First nil no yes)
+ for {
+ v := b.Control
+ if v.Op != OpMIPSMOVWconst {
+ 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:
+ // match: (GEZ (MOVWconst [c]) yes no)
+ // cond: int32(c) >= 0
+ // result: (First nil yes no)
+ for {
+ v := b.Control
+ if v.Op != OpMIPSMOVWconst {
+ 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)
+ // cond: int32(c) < 0
+ // result: (First nil no yes)
+ for {
+ v := b.Control
+ if v.Op != OpMIPSMOVWconst {
+ 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:
+ // match: (GTZ (MOVWconst [c]) yes no)
+ // cond: int32(c) > 0
+ // result: (First nil yes no)
+ for {
+ v := b.Control
+ if v.Op != OpMIPSMOVWconst {
+ 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)
+ // cond: int32(c) <= 0
+ // result: (First nil no yes)
+ for {
+ v := b.Control
+ if v.Op != OpMIPSMOVWconst {
+ 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:
+ // match: (If cond yes no)
+ // cond:
+ // result: (NE cond yes no)
+ for {
+ 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:
+ // match: (LEZ (MOVWconst [c]) yes no)
+ // cond: int32(c) <= 0
+ // result: (First nil yes no)
+ for {
+ v := b.Control
+ if v.Op != OpMIPSMOVWconst {
+ 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)
+ // cond: int32(c) > 0
+ // result: (First nil no yes)
+ for {
+ v := b.Control
+ if v.Op != OpMIPSMOVWconst {
+ 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:
+ // match: (LTZ (MOVWconst [c]) yes no)
+ // cond: int32(c) < 0
+ // result: (First nil yes no)
+ for {
+ v := b.Control
+ if v.Op != OpMIPSMOVWconst {
+ 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)
+ // cond: int32(c) >= 0
+ // result: (First nil no yes)
+ for {
+ v := b.Control
+ if v.Op != OpMIPSMOVWconst {
+ 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:
+ // match: (NE (FPFlagTrue cmp) yes no)
+ // cond:
+ // result: (FPT cmp yes no)
+ for {
+ v := b.Control
+ if v.Op != OpMIPSFPFlagTrue {
+ 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)
+ // cond:
+ // result: (FPF cmp yes no)
+ for {
+ v := b.Control
+ if v.Op != OpMIPSFPFlagFalse {
+ 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)
+ // cond:
+ // result: (EQ cmp yes no)
+ for {
+ v := b.Control
+ if v.Op != OpMIPSXORconst {
+ break
+ }
+ if v.AuxInt != 1 {
+ break
+ }
+ cmp := v.Args[0]
+ if cmp.Op != OpMIPSSGT {
+ break
+ }
+ yes := b.Succs[0]
+ no := b.Succs[1]
+ b.Kind = BlockMIPSEQ
+ b.SetControl(cmp)
+ _ = yes
+ _ = no
+ return true
+ }
+ // match: (NE (XORconst [1] cmp:(SGTU _ _)) yes no)
+ // cond:
+ // result: (EQ cmp yes no)
+ for {
+ v := b.Control
+ if v.Op != OpMIPSXORconst {
+ break
+ }
+ if v.AuxInt != 1 {
+ break
+ }
+ cmp := v.Args[0]
+ if cmp.Op != OpMIPSSGTU {
+ break
+ }
+ yes := b.Succs[0]
+ no := b.Succs[1]
+ b.Kind = BlockMIPSEQ
+ b.SetControl(cmp)
+ _ = yes
+ _ = no
+ return true
+ }
+ // match: (NE (XORconst [1] cmp:(SGTconst _)) yes no)
+ // cond:
+ // result: (EQ cmp yes no)
+ for {
+ v := b.Control
+ if v.Op != OpMIPSXORconst {
+ break
+ }
+ if v.AuxInt != 1 {
+ break
+ }
+ cmp := v.Args[0]
+ 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)
+ // cond:
+ // result: (EQ cmp yes no)
+ for {
+ v := b.Control
+ if v.Op != OpMIPSXORconst {
+ break
+ }
+ if v.AuxInt != 1 {
+ break
+ }
+ cmp := v.Args[0]
+ 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)
+ // cond:
+ // result: (EQ cmp yes no)
+ for {
+ v := b.Control
+ if v.Op != OpMIPSXORconst {
+ break
+ }
+ if v.AuxInt != 1 {
+ break
+ }
+ cmp := v.Args[0]
+ 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)
+ // cond:
+ // result: (EQ cmp yes no)
+ for {
+ v := b.Control
+ if v.Op != OpMIPSXORconst {
+ break
+ }
+ if v.AuxInt != 1 {
+ break
+ }
+ cmp := v.Args[0]
+ 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)
+ // cond:
+ // result: (EQ x yes no)
+ for {
+ v := b.Control
+ if v.Op != OpMIPSSGTUconst {
+ break
+ }
+ if v.AuxInt != 1 {
+ 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)
+ // cond:
+ // result: (NE x yes no)
+ for {
+ v := b.Control
+ if v.Op != OpMIPSSGTUzero {
+ 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)
+ // cond:
+ // result: (LTZ x yes no)
+ for {
+ v := b.Control
+ if v.Op != OpMIPSSGTconst {
+ break
+ }
+ if v.AuxInt != 0 {
+ 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)
+ // cond:
+ // result: (GTZ x yes no)
+ for {
+ v := b.Control
+ if v.Op != OpMIPSSGTzero {
+ 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)
+ // cond:
+ // result: (First nil no yes)
+ for {
+ v := b.Control
+ if v.Op != OpMIPSMOVWconst {
+ break
+ }
+ 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)
+ // cond: c != 0
+ // result: (First nil yes no)
+ for {
+ v := b.Control
+ if v.Op != OpMIPSMOVWconst {
+ 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
+ }
+ }
+ return false
+}
diff --git a/src/cmd/compile/internal/ssa/rewriteMIPS64.go b/src/cmd/compile/internal/ssa/rewriteMIPS64.go
new file mode 100644
index 0000000..76c6412
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/rewriteMIPS64.go
@@ -0,0 +1,10432 @@
+// autogenerated from gen/MIPS64.rules: do not edit!
+// generated with: cd gen; go run *.go
+
+package ssa
+
+import "math"
+
+var _ = math.MinInt8 // in case not otherwise used
+func rewriteValueMIPS64(v *Value, config *Config) bool {
+ switch v.Op {
+ case OpAdd16:
+ return rewriteValueMIPS64_OpAdd16(v, config)
+ case OpAdd32:
+ return rewriteValueMIPS64_OpAdd32(v, config)
+ case OpAdd32F:
+ return rewriteValueMIPS64_OpAdd32F(v, config)
+ case OpAdd64:
+ return rewriteValueMIPS64_OpAdd64(v, config)
+ case OpAdd64F:
+ return rewriteValueMIPS64_OpAdd64F(v, config)
+ case OpAdd8:
+ return rewriteValueMIPS64_OpAdd8(v, config)
+ case OpAddPtr:
+ return rewriteValueMIPS64_OpAddPtr(v, config)
+ case OpAddr:
+ return rewriteValueMIPS64_OpAddr(v, config)
+ case OpAnd16:
+ return rewriteValueMIPS64_OpAnd16(v, config)
+ case OpAnd32:
+ return rewriteValueMIPS64_OpAnd32(v, config)
+ case OpAnd64:
+ return rewriteValueMIPS64_OpAnd64(v, config)
+ case OpAnd8:
+ return rewriteValueMIPS64_OpAnd8(v, config)
+ case OpAndB:
+ return rewriteValueMIPS64_OpAndB(v, config)
+ case OpAvg64u:
+ return rewriteValueMIPS64_OpAvg64u(v, config)
+ case OpClosureCall:
+ return rewriteValueMIPS64_OpClosureCall(v, config)
+ case OpCom16:
+ return rewriteValueMIPS64_OpCom16(v, config)
+ case OpCom32:
+ return rewriteValueMIPS64_OpCom32(v, config)
+ case OpCom64:
+ return rewriteValueMIPS64_OpCom64(v, config)
+ case OpCom8:
+ return rewriteValueMIPS64_OpCom8(v, config)
+ case OpConst16:
+ return rewriteValueMIPS64_OpConst16(v, config)
+ case OpConst32:
+ return rewriteValueMIPS64_OpConst32(v, config)
+ case OpConst32F:
+ return rewriteValueMIPS64_OpConst32F(v, config)
+ case OpConst64:
+ return rewriteValueMIPS64_OpConst64(v, config)
+ case OpConst64F:
+ return rewriteValueMIPS64_OpConst64F(v, config)
+ case OpConst8:
+ return rewriteValueMIPS64_OpConst8(v, config)
+ case OpConstBool:
+ return rewriteValueMIPS64_OpConstBool(v, config)
+ case OpConstNil:
+ return rewriteValueMIPS64_OpConstNil(v, config)
+ case OpConvert:
+ return rewriteValueMIPS64_OpConvert(v, config)
+ case OpCvt32Fto32:
+ return rewriteValueMIPS64_OpCvt32Fto32(v, config)
+ case OpCvt32Fto64:
+ return rewriteValueMIPS64_OpCvt32Fto64(v, config)
+ case OpCvt32Fto64F:
+ return rewriteValueMIPS64_OpCvt32Fto64F(v, config)
+ case OpCvt32to32F:
+ return rewriteValueMIPS64_OpCvt32to32F(v, config)
+ case OpCvt32to64F:
+ return rewriteValueMIPS64_OpCvt32to64F(v, config)
+ case OpCvt64Fto32:
+ return rewriteValueMIPS64_OpCvt64Fto32(v, config)
+ case OpCvt64Fto32F:
+ return rewriteValueMIPS64_OpCvt64Fto32F(v, config)
+ case OpCvt64Fto64:
+ return rewriteValueMIPS64_OpCvt64Fto64(v, config)
+ case OpCvt64to32F:
+ return rewriteValueMIPS64_OpCvt64to32F(v, config)
+ case OpCvt64to64F:
+ return rewriteValueMIPS64_OpCvt64to64F(v, config)
+ case OpDeferCall:
+ return rewriteValueMIPS64_OpDeferCall(v, config)
+ case OpDiv16:
+ return rewriteValueMIPS64_OpDiv16(v, config)
+ case OpDiv16u:
+ return rewriteValueMIPS64_OpDiv16u(v, config)
+ case OpDiv32:
+ return rewriteValueMIPS64_OpDiv32(v, config)
+ case OpDiv32F:
+ return rewriteValueMIPS64_OpDiv32F(v, config)
+ case OpDiv32u:
+ return rewriteValueMIPS64_OpDiv32u(v, config)
+ case OpDiv64:
+ return rewriteValueMIPS64_OpDiv64(v, config)
+ case OpDiv64F:
+ return rewriteValueMIPS64_OpDiv64F(v, config)
+ case OpDiv64u:
+ return rewriteValueMIPS64_OpDiv64u(v, config)
+ case OpDiv8:
+ return rewriteValueMIPS64_OpDiv8(v, config)
+ case OpDiv8u:
+ return rewriteValueMIPS64_OpDiv8u(v, config)
+ case OpEq16:
+ return rewriteValueMIPS64_OpEq16(v, config)
+ case OpEq32:
+ return rewriteValueMIPS64_OpEq32(v, config)
+ case OpEq32F:
+ return rewriteValueMIPS64_OpEq32F(v, config)
+ case OpEq64:
+ return rewriteValueMIPS64_OpEq64(v, config)
+ case OpEq64F:
+ return rewriteValueMIPS64_OpEq64F(v, config)
+ case OpEq8:
+ return rewriteValueMIPS64_OpEq8(v, config)
+ case OpEqB:
+ return rewriteValueMIPS64_OpEqB(v, config)
+ case OpEqPtr:
+ return rewriteValueMIPS64_OpEqPtr(v, config)
+ case OpGeq16:
+ return rewriteValueMIPS64_OpGeq16(v, config)
+ case OpGeq16U:
+ return rewriteValueMIPS64_OpGeq16U(v, config)
+ case OpGeq32:
+ return rewriteValueMIPS64_OpGeq32(v, config)
+ case OpGeq32F:
+ return rewriteValueMIPS64_OpGeq32F(v, config)
+ case OpGeq32U:
+ return rewriteValueMIPS64_OpGeq32U(v, config)
+ case OpGeq64:
+ return rewriteValueMIPS64_OpGeq64(v, config)
+ case OpGeq64F:
+ return rewriteValueMIPS64_OpGeq64F(v, config)
+ case OpGeq64U:
+ return rewriteValueMIPS64_OpGeq64U(v, config)
+ case OpGeq8:
+ return rewriteValueMIPS64_OpGeq8(v, config)
+ case OpGeq8U:
+ return rewriteValueMIPS64_OpGeq8U(v, config)
+ case OpGetClosurePtr:
+ return rewriteValueMIPS64_OpGetClosurePtr(v, config)
+ case OpGoCall:
+ return rewriteValueMIPS64_OpGoCall(v, config)
+ case OpGreater16:
+ return rewriteValueMIPS64_OpGreater16(v, config)
+ case OpGreater16U:
+ return rewriteValueMIPS64_OpGreater16U(v, config)
+ case OpGreater32:
+ return rewriteValueMIPS64_OpGreater32(v, config)
+ case OpGreater32F:
+ return rewriteValueMIPS64_OpGreater32F(v, config)
+ case OpGreater32U:
+ return rewriteValueMIPS64_OpGreater32U(v, config)
+ case OpGreater64:
+ return rewriteValueMIPS64_OpGreater64(v, config)
+ case OpGreater64F:
+ return rewriteValueMIPS64_OpGreater64F(v, config)
+ case OpGreater64U:
+ return rewriteValueMIPS64_OpGreater64U(v, config)
+ case OpGreater8:
+ return rewriteValueMIPS64_OpGreater8(v, config)
+ case OpGreater8U:
+ return rewriteValueMIPS64_OpGreater8U(v, config)
+ case OpHmul16:
+ return rewriteValueMIPS64_OpHmul16(v, config)
+ case OpHmul16u:
+ return rewriteValueMIPS64_OpHmul16u(v, config)
+ case OpHmul32:
+ return rewriteValueMIPS64_OpHmul32(v, config)
+ case OpHmul32u:
+ return rewriteValueMIPS64_OpHmul32u(v, config)
+ case OpHmul64:
+ return rewriteValueMIPS64_OpHmul64(v, config)
+ case OpHmul64u:
+ return rewriteValueMIPS64_OpHmul64u(v, config)
+ case OpHmul8:
+ return rewriteValueMIPS64_OpHmul8(v, config)
+ case OpHmul8u:
+ return rewriteValueMIPS64_OpHmul8u(v, config)
+ case OpInterCall:
+ return rewriteValueMIPS64_OpInterCall(v, config)
+ case OpIsInBounds:
+ return rewriteValueMIPS64_OpIsInBounds(v, config)
+ case OpIsNonNil:
+ return rewriteValueMIPS64_OpIsNonNil(v, config)
+ case OpIsSliceInBounds:
+ return rewriteValueMIPS64_OpIsSliceInBounds(v, config)
+ case OpLeq16:
+ return rewriteValueMIPS64_OpLeq16(v, config)
+ case OpLeq16U:
+ return rewriteValueMIPS64_OpLeq16U(v, config)
+ case OpLeq32:
+ return rewriteValueMIPS64_OpLeq32(v, config)
+ case OpLeq32F:
+ return rewriteValueMIPS64_OpLeq32F(v, config)
+ case OpLeq32U:
+ return rewriteValueMIPS64_OpLeq32U(v, config)
+ case OpLeq64:
+ return rewriteValueMIPS64_OpLeq64(v, config)
+ case OpLeq64F:
+ return rewriteValueMIPS64_OpLeq64F(v, config)
+ case OpLeq64U:
+ return rewriteValueMIPS64_OpLeq64U(v, config)
+ case OpLeq8:
+ return rewriteValueMIPS64_OpLeq8(v, config)
+ case OpLeq8U:
+ return rewriteValueMIPS64_OpLeq8U(v, config)
+ case OpLess16:
+ return rewriteValueMIPS64_OpLess16(v, config)
+ case OpLess16U:
+ return rewriteValueMIPS64_OpLess16U(v, config)
+ case OpLess32:
+ return rewriteValueMIPS64_OpLess32(v, config)
+ case OpLess32F:
+ return rewriteValueMIPS64_OpLess32F(v, config)
+ case OpLess32U:
+ return rewriteValueMIPS64_OpLess32U(v, config)
+ case OpLess64:
+ return rewriteValueMIPS64_OpLess64(v, config)
+ case OpLess64F:
+ return rewriteValueMIPS64_OpLess64F(v, config)
+ case OpLess64U:
+ return rewriteValueMIPS64_OpLess64U(v, config)
+ case OpLess8:
+ return rewriteValueMIPS64_OpLess8(v, config)
+ case OpLess8U:
+ return rewriteValueMIPS64_OpLess8U(v, config)
+ case OpLoad:
+ return rewriteValueMIPS64_OpLoad(v, config)
+ case OpLsh16x16:
+ return rewriteValueMIPS64_OpLsh16x16(v, config)
+ case OpLsh16x32:
+ return rewriteValueMIPS64_OpLsh16x32(v, config)
+ case OpLsh16x64:
+ return rewriteValueMIPS64_OpLsh16x64(v, config)
+ case OpLsh16x8:
+ return rewriteValueMIPS64_OpLsh16x8(v, config)
+ case OpLsh32x16:
+ return rewriteValueMIPS64_OpLsh32x16(v, config)
+ case OpLsh32x32:
+ return rewriteValueMIPS64_OpLsh32x32(v, config)
+ case OpLsh32x64:
+ return rewriteValueMIPS64_OpLsh32x64(v, config)
+ case OpLsh32x8:
+ return rewriteValueMIPS64_OpLsh32x8(v, config)
+ case OpLsh64x16:
+ return rewriteValueMIPS64_OpLsh64x16(v, config)
+ case OpLsh64x32:
+ return rewriteValueMIPS64_OpLsh64x32(v, config)
+ case OpLsh64x64:
+ return rewriteValueMIPS64_OpLsh64x64(v, config)
+ case OpLsh64x8:
+ return rewriteValueMIPS64_OpLsh64x8(v, config)
+ case OpLsh8x16:
+ return rewriteValueMIPS64_OpLsh8x16(v, config)
+ case OpLsh8x32:
+ return rewriteValueMIPS64_OpLsh8x32(v, config)
+ case OpLsh8x64:
+ return rewriteValueMIPS64_OpLsh8x64(v, config)
+ case OpLsh8x8:
+ return rewriteValueMIPS64_OpLsh8x8(v, config)
+ case OpMIPS64ADDV:
+ return rewriteValueMIPS64_OpMIPS64ADDV(v, config)
+ case OpMIPS64ADDVconst:
+ return rewriteValueMIPS64_OpMIPS64ADDVconst(v, config)
+ case OpMIPS64AND:
+ return rewriteValueMIPS64_OpMIPS64AND(v, config)
+ case OpMIPS64ANDconst:
+ return rewriteValueMIPS64_OpMIPS64ANDconst(v, config)
+ case OpMIPS64MOVBUload:
+ return rewriteValueMIPS64_OpMIPS64MOVBUload(v, config)
+ case OpMIPS64MOVBUreg:
+ return rewriteValueMIPS64_OpMIPS64MOVBUreg(v, config)
+ case OpMIPS64MOVBload:
+ return rewriteValueMIPS64_OpMIPS64MOVBload(v, config)
+ case OpMIPS64MOVBreg:
+ return rewriteValueMIPS64_OpMIPS64MOVBreg(v, config)
+ case OpMIPS64MOVBstore:
+ return rewriteValueMIPS64_OpMIPS64MOVBstore(v, config)
+ case OpMIPS64MOVBstorezero:
+ return rewriteValueMIPS64_OpMIPS64MOVBstorezero(v, config)
+ case OpMIPS64MOVDload:
+ return rewriteValueMIPS64_OpMIPS64MOVDload(v, config)
+ case OpMIPS64MOVDstore:
+ return rewriteValueMIPS64_OpMIPS64MOVDstore(v, config)
+ case OpMIPS64MOVFload:
+ return rewriteValueMIPS64_OpMIPS64MOVFload(v, config)
+ case OpMIPS64MOVFstore:
+ return rewriteValueMIPS64_OpMIPS64MOVFstore(v, config)
+ case OpMIPS64MOVHUload:
+ return rewriteValueMIPS64_OpMIPS64MOVHUload(v, config)
+ case OpMIPS64MOVHUreg:
+ return rewriteValueMIPS64_OpMIPS64MOVHUreg(v, config)
+ case OpMIPS64MOVHload:
+ return rewriteValueMIPS64_OpMIPS64MOVHload(v, config)
+ case OpMIPS64MOVHreg:
+ return rewriteValueMIPS64_OpMIPS64MOVHreg(v, config)
+ case OpMIPS64MOVHstore:
+ return rewriteValueMIPS64_OpMIPS64MOVHstore(v, config)
+ case OpMIPS64MOVHstorezero:
+ return rewriteValueMIPS64_OpMIPS64MOVHstorezero(v, config)
+ case OpMIPS64MOVVload:
+ return rewriteValueMIPS64_OpMIPS64MOVVload(v, config)
+ case OpMIPS64MOVVreg:
+ return rewriteValueMIPS64_OpMIPS64MOVVreg(v, config)
+ case OpMIPS64MOVVstore:
+ return rewriteValueMIPS64_OpMIPS64MOVVstore(v, config)
+ case OpMIPS64MOVVstorezero:
+ return rewriteValueMIPS64_OpMIPS64MOVVstorezero(v, config)
+ case OpMIPS64MOVWUload:
+ return rewriteValueMIPS64_OpMIPS64MOVWUload(v, config)
+ case OpMIPS64MOVWUreg:
+ return rewriteValueMIPS64_OpMIPS64MOVWUreg(v, config)
+ case OpMIPS64MOVWload:
+ return rewriteValueMIPS64_OpMIPS64MOVWload(v, config)
+ case OpMIPS64MOVWreg:
+ return rewriteValueMIPS64_OpMIPS64MOVWreg(v, config)
+ case OpMIPS64MOVWstore:
+ return rewriteValueMIPS64_OpMIPS64MOVWstore(v, config)
+ case OpMIPS64MOVWstorezero:
+ return rewriteValueMIPS64_OpMIPS64MOVWstorezero(v, config)
+ case OpMIPS64NEGV:
+ return rewriteValueMIPS64_OpMIPS64NEGV(v, config)
+ case OpMIPS64NOR:
+ return rewriteValueMIPS64_OpMIPS64NOR(v, config)
+ case OpMIPS64NORconst:
+ return rewriteValueMIPS64_OpMIPS64NORconst(v, config)
+ case OpMIPS64OR:
+ return rewriteValueMIPS64_OpMIPS64OR(v, config)
+ case OpMIPS64ORconst:
+ return rewriteValueMIPS64_OpMIPS64ORconst(v, config)
+ case OpMIPS64SGT:
+ return rewriteValueMIPS64_OpMIPS64SGT(v, config)
+ case OpMIPS64SGTU:
+ return rewriteValueMIPS64_OpMIPS64SGTU(v, config)
+ case OpMIPS64SGTUconst:
+ return rewriteValueMIPS64_OpMIPS64SGTUconst(v, config)
+ case OpMIPS64SGTconst:
+ return rewriteValueMIPS64_OpMIPS64SGTconst(v, config)
+ case OpMIPS64SLLV:
+ return rewriteValueMIPS64_OpMIPS64SLLV(v, config)
+ case OpMIPS64SLLVconst:
+ return rewriteValueMIPS64_OpMIPS64SLLVconst(v, config)
+ case OpMIPS64SRAV:
+ return rewriteValueMIPS64_OpMIPS64SRAV(v, config)
+ case OpMIPS64SRAVconst:
+ return rewriteValueMIPS64_OpMIPS64SRAVconst(v, config)
+ case OpMIPS64SRLV:
+ return rewriteValueMIPS64_OpMIPS64SRLV(v, config)
+ case OpMIPS64SRLVconst:
+ return rewriteValueMIPS64_OpMIPS64SRLVconst(v, config)
+ case OpMIPS64SUBV:
+ return rewriteValueMIPS64_OpMIPS64SUBV(v, config)
+ case OpMIPS64SUBVconst:
+ return rewriteValueMIPS64_OpMIPS64SUBVconst(v, config)
+ case OpMIPS64XOR:
+ return rewriteValueMIPS64_OpMIPS64XOR(v, config)
+ case OpMIPS64XORconst:
+ return rewriteValueMIPS64_OpMIPS64XORconst(v, config)
+ case OpMod16:
+ return rewriteValueMIPS64_OpMod16(v, config)
+ case OpMod16u:
+ return rewriteValueMIPS64_OpMod16u(v, config)
+ case OpMod32:
+ return rewriteValueMIPS64_OpMod32(v, config)
+ case OpMod32u:
+ return rewriteValueMIPS64_OpMod32u(v, config)
+ case OpMod64:
+ return rewriteValueMIPS64_OpMod64(v, config)
+ case OpMod64u:
+ return rewriteValueMIPS64_OpMod64u(v, config)
+ case OpMod8:
+ return rewriteValueMIPS64_OpMod8(v, config)
+ case OpMod8u:
+ return rewriteValueMIPS64_OpMod8u(v, config)
+ case OpMove:
+ return rewriteValueMIPS64_OpMove(v, config)
+ case OpMul16:
+ return rewriteValueMIPS64_OpMul16(v, config)
+ case OpMul32:
+ return rewriteValueMIPS64_OpMul32(v, config)
+ case OpMul32F:
+ return rewriteValueMIPS64_OpMul32F(v, config)
+ case OpMul64:
+ return rewriteValueMIPS64_OpMul64(v, config)
+ case OpMul64F:
+ return rewriteValueMIPS64_OpMul64F(v, config)
+ case OpMul8:
+ return rewriteValueMIPS64_OpMul8(v, config)
+ case OpNeg16:
+ return rewriteValueMIPS64_OpNeg16(v, config)
+ case OpNeg32:
+ return rewriteValueMIPS64_OpNeg32(v, config)
+ case OpNeg32F:
+ return rewriteValueMIPS64_OpNeg32F(v, config)
+ case OpNeg64:
+ return rewriteValueMIPS64_OpNeg64(v, config)
+ case OpNeg64F:
+ return rewriteValueMIPS64_OpNeg64F(v, config)
+ case OpNeg8:
+ return rewriteValueMIPS64_OpNeg8(v, config)
+ case OpNeq16:
+ return rewriteValueMIPS64_OpNeq16(v, config)
+ case OpNeq32:
+ return rewriteValueMIPS64_OpNeq32(v, config)
+ case OpNeq32F:
+ return rewriteValueMIPS64_OpNeq32F(v, config)
+ case OpNeq64:
+ return rewriteValueMIPS64_OpNeq64(v, config)
+ case OpNeq64F:
+ return rewriteValueMIPS64_OpNeq64F(v, config)
+ case OpNeq8:
+ return rewriteValueMIPS64_OpNeq8(v, config)
+ case OpNeqB:
+ return rewriteValueMIPS64_OpNeqB(v, config)
+ case OpNeqPtr:
+ return rewriteValueMIPS64_OpNeqPtr(v, config)
+ case OpNilCheck:
+ return rewriteValueMIPS64_OpNilCheck(v, config)
+ case OpNot:
+ return rewriteValueMIPS64_OpNot(v, config)
+ case OpOffPtr:
+ return rewriteValueMIPS64_OpOffPtr(v, config)
+ case OpOr16:
+ return rewriteValueMIPS64_OpOr16(v, config)
+ case OpOr32:
+ return rewriteValueMIPS64_OpOr32(v, config)
+ case OpOr64:
+ return rewriteValueMIPS64_OpOr64(v, config)
+ case OpOr8:
+ return rewriteValueMIPS64_OpOr8(v, config)
+ case OpOrB:
+ return rewriteValueMIPS64_OpOrB(v, config)
+ case OpRsh16Ux16:
+ return rewriteValueMIPS64_OpRsh16Ux16(v, config)
+ case OpRsh16Ux32:
+ return rewriteValueMIPS64_OpRsh16Ux32(v, config)
+ case OpRsh16Ux64:
+ return rewriteValueMIPS64_OpRsh16Ux64(v, config)
+ case OpRsh16Ux8:
+ return rewriteValueMIPS64_OpRsh16Ux8(v, config)
+ case OpRsh16x16:
+ return rewriteValueMIPS64_OpRsh16x16(v, config)
+ case OpRsh16x32:
+ return rewriteValueMIPS64_OpRsh16x32(v, config)
+ case OpRsh16x64:
+ return rewriteValueMIPS64_OpRsh16x64(v, config)
+ case OpRsh16x8:
+ return rewriteValueMIPS64_OpRsh16x8(v, config)
+ case OpRsh32Ux16:
+ return rewriteValueMIPS64_OpRsh32Ux16(v, config)
+ case OpRsh32Ux32:
+ return rewriteValueMIPS64_OpRsh32Ux32(v, config)
+ case OpRsh32Ux64:
+ return rewriteValueMIPS64_OpRsh32Ux64(v, config)
+ case OpRsh32Ux8:
+ return rewriteValueMIPS64_OpRsh32Ux8(v, config)
+ case OpRsh32x16:
+ return rewriteValueMIPS64_OpRsh32x16(v, config)
+ case OpRsh32x32:
+ return rewriteValueMIPS64_OpRsh32x32(v, config)
+ case OpRsh32x64:
+ return rewriteValueMIPS64_OpRsh32x64(v, config)
+ case OpRsh32x8:
+ return rewriteValueMIPS64_OpRsh32x8(v, config)
+ case OpRsh64Ux16:
+ return rewriteValueMIPS64_OpRsh64Ux16(v, config)
+ case OpRsh64Ux32:
+ return rewriteValueMIPS64_OpRsh64Ux32(v, config)
+ case OpRsh64Ux64:
+ return rewriteValueMIPS64_OpRsh64Ux64(v, config)
+ case OpRsh64Ux8:
+ return rewriteValueMIPS64_OpRsh64Ux8(v, config)
+ case OpRsh64x16:
+ return rewriteValueMIPS64_OpRsh64x16(v, config)
+ case OpRsh64x32:
+ return rewriteValueMIPS64_OpRsh64x32(v, config)
+ case OpRsh64x64:
+ return rewriteValueMIPS64_OpRsh64x64(v, config)
+ case OpRsh64x8:
+ return rewriteValueMIPS64_OpRsh64x8(v, config)
+ case OpRsh8Ux16:
+ return rewriteValueMIPS64_OpRsh8Ux16(v, config)
+ case OpRsh8Ux32:
+ return rewriteValueMIPS64_OpRsh8Ux32(v, config)
+ case OpRsh8Ux64:
+ return rewriteValueMIPS64_OpRsh8Ux64(v, config)
+ case OpRsh8Ux8:
+ return rewriteValueMIPS64_OpRsh8Ux8(v, config)
+ case OpRsh8x16:
+ return rewriteValueMIPS64_OpRsh8x16(v, config)
+ case OpRsh8x32:
+ return rewriteValueMIPS64_OpRsh8x32(v, config)
+ case OpRsh8x64:
+ return rewriteValueMIPS64_OpRsh8x64(v, config)
+ case OpRsh8x8:
+ return rewriteValueMIPS64_OpRsh8x8(v, config)
+ case OpSelect0:
+ return rewriteValueMIPS64_OpSelect0(v, config)
+ case OpSelect1:
+ return rewriteValueMIPS64_OpSelect1(v, config)
+ case OpSignExt16to32:
+ return rewriteValueMIPS64_OpSignExt16to32(v, config)
+ case OpSignExt16to64:
+ return rewriteValueMIPS64_OpSignExt16to64(v, config)
+ case OpSignExt32to64:
+ return rewriteValueMIPS64_OpSignExt32to64(v, config)
+ case OpSignExt8to16:
+ return rewriteValueMIPS64_OpSignExt8to16(v, config)
+ case OpSignExt8to32:
+ return rewriteValueMIPS64_OpSignExt8to32(v, config)
+ case OpSignExt8to64:
+ return rewriteValueMIPS64_OpSignExt8to64(v, config)
+ case OpSlicemask:
+ return rewriteValueMIPS64_OpSlicemask(v, config)
+ case OpStaticCall:
+ return rewriteValueMIPS64_OpStaticCall(v, config)
+ case OpStore:
+ return rewriteValueMIPS64_OpStore(v, config)
+ case OpSub16:
+ return rewriteValueMIPS64_OpSub16(v, config)
+ case OpSub32:
+ return rewriteValueMIPS64_OpSub32(v, config)
+ case OpSub32F:
+ return rewriteValueMIPS64_OpSub32F(v, config)
+ case OpSub64:
+ return rewriteValueMIPS64_OpSub64(v, config)
+ case OpSub64F:
+ return rewriteValueMIPS64_OpSub64F(v, config)
+ case OpSub8:
+ return rewriteValueMIPS64_OpSub8(v, config)
+ case OpSubPtr:
+ return rewriteValueMIPS64_OpSubPtr(v, config)
+ case OpTrunc16to8:
+ return rewriteValueMIPS64_OpTrunc16to8(v, config)
+ case OpTrunc32to16:
+ return rewriteValueMIPS64_OpTrunc32to16(v, config)
+ case OpTrunc32to8:
+ return rewriteValueMIPS64_OpTrunc32to8(v, config)
+ case OpTrunc64to16:
+ return rewriteValueMIPS64_OpTrunc64to16(v, config)
+ case OpTrunc64to32:
+ return rewriteValueMIPS64_OpTrunc64to32(v, config)
+ case OpTrunc64to8:
+ return rewriteValueMIPS64_OpTrunc64to8(v, config)
+ case OpXor16:
+ return rewriteValueMIPS64_OpXor16(v, config)
+ case OpXor32:
+ return rewriteValueMIPS64_OpXor32(v, config)
+ case OpXor64:
+ return rewriteValueMIPS64_OpXor64(v, config)
+ case OpXor8:
+ return rewriteValueMIPS64_OpXor8(v, config)
+ case OpZero:
+ return rewriteValueMIPS64_OpZero(v, config)
+ case OpZeroExt16to32:
+ return rewriteValueMIPS64_OpZeroExt16to32(v, config)
+ case OpZeroExt16to64:
+ return rewriteValueMIPS64_OpZeroExt16to64(v, config)
+ case OpZeroExt32to64:
+ return rewriteValueMIPS64_OpZeroExt32to64(v, config)
+ case OpZeroExt8to16:
+ return rewriteValueMIPS64_OpZeroExt8to16(v, config)
+ case OpZeroExt8to32:
+ return rewriteValueMIPS64_OpZeroExt8to32(v, config)
+ case OpZeroExt8to64:
+ return rewriteValueMIPS64_OpZeroExt8to64(v, config)
+ }
+ return false
+}
+func rewriteValueMIPS64_OpAdd16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Add16 x y)
+ // cond:
+ // result: (ADDV x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPS64ADDV)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpAdd32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Add32 x y)
+ // cond:
+ // result: (ADDV x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPS64ADDV)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpAdd32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Add32F x y)
+ // cond:
+ // result: (ADDF x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPS64ADDF)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpAdd64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Add64 x y)
+ // cond:
+ // result: (ADDV x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPS64ADDV)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpAdd64F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Add64F x y)
+ // cond:
+ // result: (ADDD x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPS64ADDD)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpAdd8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Add8 x y)
+ // cond:
+ // result: (ADDV x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPS64ADDV)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpAddPtr(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (AddPtr x y)
+ // cond:
+ // result: (ADDV x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPS64ADDV)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpAddr(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Addr {sym} base)
+ // cond:
+ // result: (MOVVaddr {sym} base)
+ for {
+ sym := v.Aux
+ base := v.Args[0]
+ v.reset(OpMIPS64MOVVaddr)
+ v.Aux = sym
+ v.AddArg(base)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpAnd16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (And16 x y)
+ // cond:
+ // result: (AND x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPS64AND)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpAnd32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (And32 x y)
+ // cond:
+ // result: (AND x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPS64AND)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpAnd64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (And64 x y)
+ // cond:
+ // result: (AND x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPS64AND)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpAnd8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (And8 x y)
+ // cond:
+ // result: (AND x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPS64AND)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpAndB(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (AndB x y)
+ // cond:
+ // result: (AND x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPS64AND)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpAvg64u(v *Value, config *Config) 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])))
+ for {
+ t := v.Type
+ 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
+ v1.AddArg(x)
+ 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)
+ return true
+ }
+}
+func rewriteValueMIPS64_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(OpMIPS64CALLclosure)
+ v.AuxInt = argwid
+ v.AddArg(entry)
+ v.AddArg(closure)
+ v.AddArg(mem)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpCom16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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.AuxInt = 0
+ v.AddArg(v0)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpCom32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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.AuxInt = 0
+ v.AddArg(v0)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpCom64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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.AuxInt = 0
+ v.AddArg(v0)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpCom8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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.AuxInt = 0
+ v.AddArg(v0)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpConst16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Const16 [val])
+ // cond:
+ // result: (MOVVconst [val])
+ for {
+ val := v.AuxInt
+ v.reset(OpMIPS64MOVVconst)
+ v.AuxInt = val
+ return true
+ }
+}
+func rewriteValueMIPS64_OpConst32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Const32 [val])
+ // cond:
+ // result: (MOVVconst [val])
+ for {
+ val := v.AuxInt
+ v.reset(OpMIPS64MOVVconst)
+ v.AuxInt = val
+ return true
+ }
+}
+func rewriteValueMIPS64_OpConst32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Const32F [val])
+ // cond:
+ // result: (MOVFconst [val])
+ for {
+ val := v.AuxInt
+ v.reset(OpMIPS64MOVFconst)
+ v.AuxInt = val
+ return true
+ }
+}
+func rewriteValueMIPS64_OpConst64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Const64 [val])
+ // cond:
+ // result: (MOVVconst [val])
+ for {
+ val := v.AuxInt
+ v.reset(OpMIPS64MOVVconst)
+ v.AuxInt = val
+ return true
+ }
+}
+func rewriteValueMIPS64_OpConst64F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Const64F [val])
+ // cond:
+ // result: (MOVDconst [val])
+ for {
+ val := v.AuxInt
+ v.reset(OpMIPS64MOVDconst)
+ v.AuxInt = val
+ return true
+ }
+}
+func rewriteValueMIPS64_OpConst8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Const8 [val])
+ // cond:
+ // result: (MOVVconst [val])
+ for {
+ val := v.AuxInt
+ v.reset(OpMIPS64MOVVconst)
+ v.AuxInt = val
+ return true
+ }
+}
+func rewriteValueMIPS64_OpConstBool(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ConstBool [b])
+ // cond:
+ // result: (MOVVconst [b])
+ for {
+ b := v.AuxInt
+ v.reset(OpMIPS64MOVVconst)
+ v.AuxInt = b
+ return true
+ }
+}
+func rewriteValueMIPS64_OpConstNil(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ConstNil)
+ // cond:
+ // result: (MOVVconst [0])
+ for {
+ v.reset(OpMIPS64MOVVconst)
+ v.AuxInt = 0
+ return true
+ }
+}
+func rewriteValueMIPS64_OpConvert(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Convert x mem)
+ // cond:
+ // result: (MOVVconvert x mem)
+ for {
+ x := v.Args[0]
+ mem := v.Args[1]
+ v.reset(OpMIPS64MOVVconvert)
+ v.AddArg(x)
+ v.AddArg(mem)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpCvt32Fto32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Cvt32Fto32 x)
+ // cond:
+ // result: (TRUNCFW x)
+ for {
+ x := v.Args[0]
+ v.reset(OpMIPS64TRUNCFW)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpCvt32Fto64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Cvt32Fto64 x)
+ // cond:
+ // result: (TRUNCFV x)
+ for {
+ x := v.Args[0]
+ v.reset(OpMIPS64TRUNCFV)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpCvt32Fto64F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Cvt32Fto64F x)
+ // cond:
+ // result: (MOVFD x)
+ for {
+ x := v.Args[0]
+ v.reset(OpMIPS64MOVFD)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpCvt32to32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Cvt32to32F x)
+ // cond:
+ // result: (MOVWF x)
+ for {
+ x := v.Args[0]
+ v.reset(OpMIPS64MOVWF)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpCvt32to64F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Cvt32to64F x)
+ // cond:
+ // result: (MOVWD x)
+ for {
+ x := v.Args[0]
+ v.reset(OpMIPS64MOVWD)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpCvt64Fto32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Cvt64Fto32 x)
+ // cond:
+ // result: (TRUNCDW x)
+ for {
+ x := v.Args[0]
+ v.reset(OpMIPS64TRUNCDW)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpCvt64Fto32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Cvt64Fto32F x)
+ // cond:
+ // result: (MOVDF x)
+ for {
+ x := v.Args[0]
+ v.reset(OpMIPS64MOVDF)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpCvt64Fto64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Cvt64Fto64 x)
+ // cond:
+ // result: (TRUNCDV x)
+ for {
+ x := v.Args[0]
+ v.reset(OpMIPS64TRUNCDV)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpCvt64to32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Cvt64to32F x)
+ // cond:
+ // result: (MOVVF x)
+ for {
+ x := v.Args[0]
+ v.reset(OpMIPS64MOVVF)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpCvt64to64F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Cvt64to64F x)
+ // cond:
+ // result: (MOVVD x)
+ for {
+ x := v.Args[0]
+ v.reset(OpMIPS64MOVVD)
+ v.AddArg(x)
+ 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 {
+ b := v.Block
+ _ = b
+ // match: (Div16 x y)
+ // cond:
+ // result: (Select1 (DIVV (SignExt16to64 x) (SignExt16to64 y)))
+ for {
+ 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())
+ v1.AddArg(x)
+ v0.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpSignExt16to64, config.fe.TypeInt64())
+ v2.AddArg(y)
+ v0.AddArg(v2)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpDiv16u(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Div16u x y)
+ // cond:
+ // result: (Select1 (DIVVU (ZeroExt16to64 x) (ZeroExt16to64 y)))
+ for {
+ 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())
+ v1.AddArg(x)
+ v0.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+ v2.AddArg(y)
+ v0.AddArg(v2)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpDiv32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Div32 x y)
+ // cond:
+ // result: (Select1 (DIVV (SignExt32to64 x) (SignExt32to64 y)))
+ for {
+ 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())
+ v1.AddArg(x)
+ v0.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpSignExt32to64, config.fe.TypeInt64())
+ v2.AddArg(y)
+ v0.AddArg(v2)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpDiv32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Div32F x y)
+ // cond:
+ // result: (DIVF x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPS64DIVF)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpDiv32u(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Div32u x y)
+ // cond:
+ // result: (Select1 (DIVVU (ZeroExt32to64 x) (ZeroExt32to64 y)))
+ for {
+ 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())
+ v1.AddArg(x)
+ v0.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+ v2.AddArg(y)
+ v0.AddArg(v2)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpDiv64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Div64 x y)
+ // cond:
+ // result: (Select1 (DIVV x y))
+ for {
+ 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.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpDiv64F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Div64F x y)
+ // cond:
+ // result: (DIVD x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPS64DIVD)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpDiv64u(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Div64u x y)
+ // cond:
+ // result: (Select1 (DIVVU x y))
+ for {
+ 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.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpDiv8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Div8 x y)
+ // cond:
+ // result: (Select1 (DIVV (SignExt8to64 x) (SignExt8to64 y)))
+ for {
+ 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())
+ v1.AddArg(x)
+ v0.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpSignExt8to64, config.fe.TypeInt64())
+ v2.AddArg(y)
+ v0.AddArg(v2)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpDiv8u(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Div8u x y)
+ // cond:
+ // result: (Select1 (DIVVU (ZeroExt8to64 x) (ZeroExt8to64 y)))
+ for {
+ 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())
+ v1.AddArg(x)
+ v0.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+ v2.AddArg(y)
+ v0.AddArg(v2)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpEq16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Eq16 x y)
+ // cond:
+ // result: (SGTU (MOVVconst [1]) (XOR (ZeroExt16to64 x) (ZeroExt16to64 y)))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPS64SGTU)
+ v0 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+ v0.AuxInt = 1
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpMIPS64XOR, 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)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpEq32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Eq32 x y)
+ // cond:
+ // result: (SGTU (MOVVconst [1]) (XOR (ZeroExt32to64 x) (ZeroExt32to64 y)))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPS64SGTU)
+ v0 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+ v0.AuxInt = 1
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpMIPS64XOR, config.fe.TypeUInt64())
+ v2 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+ v2.AddArg(x)
+ v1.AddArg(v2)
+ v3 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+ v3.AddArg(y)
+ v1.AddArg(v3)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpEq32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Eq32F x y)
+ // cond:
+ // result: (FPFlagTrue (CMPEQF x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPS64FPFlagTrue)
+ v0 := b.NewValue0(v.Line, OpMIPS64CMPEQF, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpEq64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Eq64 x y)
+ // cond:
+ // result: (SGTU (MOVVconst [1]) (XOR x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPS64SGTU)
+ v0 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+ v0.AuxInt = 1
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpMIPS64XOR, config.fe.TypeUInt64())
+ v1.AddArg(x)
+ v1.AddArg(y)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpEq64F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Eq64F x y)
+ // cond:
+ // result: (FPFlagTrue (CMPEQD x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPS64FPFlagTrue)
+ v0 := b.NewValue0(v.Line, OpMIPS64CMPEQD, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpEq8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Eq8 x y)
+ // cond:
+ // result: (SGTU (MOVVconst [1]) (XOR (ZeroExt8to64 x) (ZeroExt8to64 y)))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPS64SGTU)
+ v0 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+ v0.AuxInt = 1
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpMIPS64XOR, 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)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpEqB(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (EqB x y)
+ // cond:
+ // result: (XOR (MOVVconst [1]) (XOR <config.fe.TypeBool()> x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPS64XOR)
+ v0 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+ v0.AuxInt = 1
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpMIPS64XOR, config.fe.TypeBool())
+ v1.AddArg(x)
+ v1.AddArg(y)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpEqPtr(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (EqPtr x y)
+ // cond:
+ // result: (SGTU (MOVVconst [1]) (XOR x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPS64SGTU)
+ v0 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+ v0.AuxInt = 1
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpMIPS64XOR, config.fe.TypeUInt64())
+ v1.AddArg(x)
+ v1.AddArg(y)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpGeq16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Geq16 x y)
+ // cond:
+ // result: (XOR (MOVVconst [1]) (SGT (SignExt16to64 y) (SignExt16to64 x)))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPS64XOR)
+ v0 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+ v0.AuxInt = 1
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpMIPS64SGT, config.fe.TypeBool())
+ v2 := b.NewValue0(v.Line, OpSignExt16to64, config.fe.TypeInt64())
+ v2.AddArg(y)
+ v1.AddArg(v2)
+ v3 := b.NewValue0(v.Line, OpSignExt16to64, config.fe.TypeInt64())
+ v3.AddArg(x)
+ v1.AddArg(v3)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpGeq16U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Geq16U x y)
+ // cond:
+ // result: (XOR (MOVVconst [1]) (SGTU (ZeroExt16to64 y) (ZeroExt16to64 x)))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPS64XOR)
+ v0 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+ v0.AuxInt = 1
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpMIPS64SGTU, config.fe.TypeBool())
+ v2 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+ v2.AddArg(y)
+ v1.AddArg(v2)
+ v3 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+ v3.AddArg(x)
+ v1.AddArg(v3)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpGeq32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Geq32 x y)
+ // cond:
+ // result: (XOR (MOVVconst [1]) (SGT (SignExt32to64 y) (SignExt32to64 x)))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPS64XOR)
+ v0 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+ v0.AuxInt = 1
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpMIPS64SGT, config.fe.TypeBool())
+ v2 := b.NewValue0(v.Line, OpSignExt32to64, config.fe.TypeInt64())
+ v2.AddArg(y)
+ v1.AddArg(v2)
+ v3 := b.NewValue0(v.Line, OpSignExt32to64, config.fe.TypeInt64())
+ v3.AddArg(x)
+ v1.AddArg(v3)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpGeq32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Geq32F x y)
+ // cond:
+ // result: (FPFlagTrue (CMPGEF x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPS64FPFlagTrue)
+ v0 := b.NewValue0(v.Line, OpMIPS64CMPGEF, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpGeq32U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Geq32U x y)
+ // cond:
+ // result: (XOR (MOVVconst [1]) (SGTU (ZeroExt32to64 y) (ZeroExt32to64 x)))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPS64XOR)
+ v0 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+ v0.AuxInt = 1
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpMIPS64SGTU, config.fe.TypeBool())
+ v2 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+ v2.AddArg(y)
+ v1.AddArg(v2)
+ v3 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+ v3.AddArg(x)
+ v1.AddArg(v3)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpGeq64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Geq64 x y)
+ // cond:
+ // result: (XOR (MOVVconst [1]) (SGT y x))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPS64XOR)
+ v0 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+ v0.AuxInt = 1
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpMIPS64SGT, config.fe.TypeBool())
+ v1.AddArg(y)
+ v1.AddArg(x)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpGeq64F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Geq64F x y)
+ // cond:
+ // result: (FPFlagTrue (CMPGED x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPS64FPFlagTrue)
+ v0 := b.NewValue0(v.Line, OpMIPS64CMPGED, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpGeq64U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Geq64U x y)
+ // cond:
+ // result: (XOR (MOVVconst [1]) (SGTU y x))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPS64XOR)
+ v0 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+ v0.AuxInt = 1
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpMIPS64SGTU, config.fe.TypeBool())
+ v1.AddArg(y)
+ v1.AddArg(x)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpGeq8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Geq8 x y)
+ // cond:
+ // result: (XOR (MOVVconst [1]) (SGT (SignExt8to64 y) (SignExt8to64 x)))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPS64XOR)
+ v0 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+ v0.AuxInt = 1
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpMIPS64SGT, config.fe.TypeBool())
+ v2 := b.NewValue0(v.Line, OpSignExt8to64, config.fe.TypeInt64())
+ v2.AddArg(y)
+ v1.AddArg(v2)
+ v3 := b.NewValue0(v.Line, OpSignExt8to64, config.fe.TypeInt64())
+ v3.AddArg(x)
+ v1.AddArg(v3)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpGeq8U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Geq8U x y)
+ // cond:
+ // result: (XOR (MOVVconst [1]) (SGTU (ZeroExt8to64 y) (ZeroExt8to64 x)))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPS64XOR)
+ v0 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+ v0.AuxInt = 1
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpMIPS64SGTU, config.fe.TypeBool())
+ v2 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+ v2.AddArg(y)
+ v1.AddArg(v2)
+ v3 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+ v3.AddArg(x)
+ v1.AddArg(v3)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpGetClosurePtr(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (GetClosurePtr)
+ // cond:
+ // result: (LoweredGetClosurePtr)
+ for {
+ v.reset(OpMIPS64LoweredGetClosurePtr)
+ 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 {
+ b := v.Block
+ _ = b
+ // match: (Greater16 x y)
+ // cond:
+ // result: (SGT (SignExt16to64 x) (SignExt16to64 y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPS64SGT)
+ v0 := b.NewValue0(v.Line, OpSignExt16to64, config.fe.TypeInt64())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpSignExt16to64, config.fe.TypeInt64())
+ v1.AddArg(y)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpGreater16U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Greater16U x y)
+ // cond:
+ // result: (SGTU (ZeroExt16to64 x) (ZeroExt16to64 y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPS64SGTU)
+ v0 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+ v1.AddArg(y)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpGreater32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Greater32 x y)
+ // cond:
+ // result: (SGT (SignExt32to64 x) (SignExt32to64 y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPS64SGT)
+ v0 := b.NewValue0(v.Line, OpSignExt32to64, config.fe.TypeInt64())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpSignExt32to64, config.fe.TypeInt64())
+ v1.AddArg(y)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpGreater32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Greater32F x y)
+ // cond:
+ // result: (FPFlagTrue (CMPGTF x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPS64FPFlagTrue)
+ v0 := b.NewValue0(v.Line, OpMIPS64CMPGTF, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpGreater32U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Greater32U x y)
+ // cond:
+ // result: (SGTU (ZeroExt32to64 x) (ZeroExt32to64 y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPS64SGTU)
+ v0 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+ v1.AddArg(y)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpGreater64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Greater64 x y)
+ // cond:
+ // result: (SGT x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPS64SGT)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpGreater64F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Greater64F x y)
+ // cond:
+ // result: (FPFlagTrue (CMPGTD x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPS64FPFlagTrue)
+ v0 := b.NewValue0(v.Line, OpMIPS64CMPGTD, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpGreater64U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Greater64U x y)
+ // cond:
+ // result: (SGTU x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPS64SGTU)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpGreater8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Greater8 x y)
+ // cond:
+ // result: (SGT (SignExt8to64 x) (SignExt8to64 y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPS64SGT)
+ v0 := b.NewValue0(v.Line, OpSignExt8to64, config.fe.TypeInt64())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpSignExt8to64, config.fe.TypeInt64())
+ v1.AddArg(y)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpGreater8U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Greater8U x y)
+ // cond:
+ // result: (SGTU (ZeroExt8to64 x) (ZeroExt8to64 y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPS64SGTU)
+ v0 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+ 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 {
+ b := v.Block
+ _ = b
+ // match: (Hmul32 x y)
+ // cond:
+ // result: (SRAVconst (Select1 <config.fe.TypeInt64()> (MULV (SignExt32to64 x) (SignExt32to64 y))) [32])
+ for {
+ 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())
+ v2.AddArg(x)
+ v1.AddArg(v2)
+ v3 := b.NewValue0(v.Line, OpSignExt32to64, config.fe.TypeInt64())
+ v3.AddArg(y)
+ v1.AddArg(v3)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpHmul32u(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Hmul32u x y)
+ // cond:
+ // result: (SRLVconst (Select1 <config.fe.TypeUInt64()> (MULVU (ZeroExt32to64 x) (ZeroExt32to64 y))) [32])
+ for {
+ 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())
+ v2.AddArg(x)
+ v1.AddArg(v2)
+ v3 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+ v3.AddArg(y)
+ v1.AddArg(v3)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpHmul64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Hmul64 x y)
+ // cond:
+ // result: (Select0 (MULV x y))
+ for {
+ 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.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpHmul64u(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Hmul64u x y)
+ // cond:
+ // result: (Select0 (MULVU x y))
+ for {
+ 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.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
+ // 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(OpMIPS64CALLinter)
+ v.AuxInt = argwid
+ v.AddArg(entry)
+ v.AddArg(mem)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpIsInBounds(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (IsInBounds idx len)
+ // cond:
+ // result: (SGTU len idx)
+ for {
+ idx := v.Args[0]
+ len := v.Args[1]
+ v.reset(OpMIPS64SGTU)
+ v.AddArg(len)
+ v.AddArg(idx)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpIsNonNil(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (IsNonNil ptr)
+ // cond:
+ // result: (SGTU ptr (MOVVconst [0]))
+ for {
+ ptr := v.Args[0]
+ v.reset(OpMIPS64SGTU)
+ v.AddArg(ptr)
+ v0 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+ v0.AuxInt = 0
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpIsSliceInBounds(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (IsSliceInBounds idx len)
+ // cond:
+ // result: (XOR (MOVVconst [1]) (SGTU idx len))
+ for {
+ idx := v.Args[0]
+ len := v.Args[1]
+ v.reset(OpMIPS64XOR)
+ v0 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+ v0.AuxInt = 1
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpMIPS64SGTU, config.fe.TypeBool())
+ v1.AddArg(idx)
+ v1.AddArg(len)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpLeq16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Leq16 x y)
+ // cond:
+ // result: (XOR (MOVVconst [1]) (SGT (SignExt16to64 x) (SignExt16to64 y)))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPS64XOR)
+ v0 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+ v0.AuxInt = 1
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpMIPS64SGT, config.fe.TypeBool())
+ 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)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpLeq16U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Leq16U x y)
+ // cond:
+ // result: (XOR (MOVVconst [1]) (SGTU (ZeroExt16to64 x) (ZeroExt16to64 y)))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPS64XOR)
+ v0 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+ v0.AuxInt = 1
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpMIPS64SGTU, config.fe.TypeBool())
+ 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)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpLeq32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Leq32 x y)
+ // cond:
+ // result: (XOR (MOVVconst [1]) (SGT (SignExt32to64 x) (SignExt32to64 y)))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPS64XOR)
+ v0 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+ v0.AuxInt = 1
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpMIPS64SGT, config.fe.TypeBool())
+ v2 := b.NewValue0(v.Line, OpSignExt32to64, config.fe.TypeInt64())
+ v2.AddArg(x)
+ v1.AddArg(v2)
+ v3 := b.NewValue0(v.Line, OpSignExt32to64, config.fe.TypeInt64())
+ v3.AddArg(y)
+ v1.AddArg(v3)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpLeq32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Leq32F x y)
+ // cond:
+ // result: (FPFlagTrue (CMPGEF y x))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPS64FPFlagTrue)
+ v0 := b.NewValue0(v.Line, OpMIPS64CMPGEF, TypeFlags)
+ v0.AddArg(y)
+ v0.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpLeq32U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Leq32U x y)
+ // cond:
+ // result: (XOR (MOVVconst [1]) (SGTU (ZeroExt32to64 x) (ZeroExt32to64 y)))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPS64XOR)
+ v0 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+ v0.AuxInt = 1
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpMIPS64SGTU, config.fe.TypeBool())
+ v2 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+ v2.AddArg(x)
+ v1.AddArg(v2)
+ v3 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+ v3.AddArg(y)
+ v1.AddArg(v3)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpLeq64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Leq64 x y)
+ // cond:
+ // result: (XOR (MOVVconst [1]) (SGT x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPS64XOR)
+ v0 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+ v0.AuxInt = 1
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpMIPS64SGT, config.fe.TypeBool())
+ v1.AddArg(x)
+ v1.AddArg(y)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpLeq64F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Leq64F x y)
+ // cond:
+ // result: (FPFlagTrue (CMPGED y x))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPS64FPFlagTrue)
+ v0 := b.NewValue0(v.Line, OpMIPS64CMPGED, TypeFlags)
+ v0.AddArg(y)
+ v0.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpLeq64U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Leq64U x y)
+ // cond:
+ // result: (XOR (MOVVconst [1]) (SGTU x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPS64XOR)
+ v0 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+ v0.AuxInt = 1
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpMIPS64SGTU, config.fe.TypeBool())
+ v1.AddArg(x)
+ v1.AddArg(y)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpLeq8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Leq8 x y)
+ // cond:
+ // result: (XOR (MOVVconst [1]) (SGT (SignExt8to64 x) (SignExt8to64 y)))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPS64XOR)
+ v0 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+ v0.AuxInt = 1
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpMIPS64SGT, config.fe.TypeBool())
+ 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)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpLeq8U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Leq8U x y)
+ // cond:
+ // result: (XOR (MOVVconst [1]) (SGTU (ZeroExt8to64 x) (ZeroExt8to64 y)))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPS64XOR)
+ v0 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+ v0.AuxInt = 1
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpMIPS64SGTU, config.fe.TypeBool())
+ 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)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpLess16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Less16 x y)
+ // cond:
+ // result: (SGT (SignExt16to64 y) (SignExt16to64 x))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPS64SGT)
+ v0 := b.NewValue0(v.Line, OpSignExt16to64, config.fe.TypeInt64())
+ v0.AddArg(y)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpSignExt16to64, config.fe.TypeInt64())
+ v1.AddArg(x)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpLess16U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Less16U x y)
+ // cond:
+ // result: (SGTU (ZeroExt16to64 y) (ZeroExt16to64 x))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPS64SGTU)
+ v0 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+ v0.AddArg(y)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+ v1.AddArg(x)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpLess32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Less32 x y)
+ // cond:
+ // result: (SGT (SignExt32to64 y) (SignExt32to64 x))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPS64SGT)
+ v0 := b.NewValue0(v.Line, OpSignExt32to64, config.fe.TypeInt64())
+ v0.AddArg(y)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpSignExt32to64, config.fe.TypeInt64())
+ v1.AddArg(x)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpLess32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Less32F x y)
+ // cond:
+ // result: (FPFlagTrue (CMPGTF y x))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPS64FPFlagTrue)
+ v0 := b.NewValue0(v.Line, OpMIPS64CMPGTF, TypeFlags)
+ v0.AddArg(y)
+ v0.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpLess32U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Less32U x y)
+ // cond:
+ // result: (SGTU (ZeroExt32to64 y) (ZeroExt32to64 x))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPS64SGTU)
+ v0 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+ v0.AddArg(y)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+ v1.AddArg(x)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpLess64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Less64 x y)
+ // cond:
+ // result: (SGT y x)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPS64SGT)
+ v.AddArg(y)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpLess64F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Less64F x y)
+ // cond:
+ // result: (FPFlagTrue (CMPGTD y x))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPS64FPFlagTrue)
+ v0 := b.NewValue0(v.Line, OpMIPS64CMPGTD, TypeFlags)
+ v0.AddArg(y)
+ v0.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpLess64U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Less64U x y)
+ // cond:
+ // result: (SGTU y x)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPS64SGTU)
+ v.AddArg(y)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpLess8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Less8 x y)
+ // cond:
+ // result: (SGT (SignExt8to64 y) (SignExt8to64 x))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPS64SGT)
+ v0 := b.NewValue0(v.Line, OpSignExt8to64, config.fe.TypeInt64())
+ v0.AddArg(y)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpSignExt8to64, config.fe.TypeInt64())
+ v1.AddArg(x)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpLess8U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Less8U x y)
+ // cond:
+ // result: (SGTU (ZeroExt8to64 y) (ZeroExt8to64 x))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPS64SGTU)
+ v0 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+ v0.AddArg(y)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+ v1.AddArg(x)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpLoad(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Load <t> ptr mem)
+ // cond: t.IsBoolean()
+ // result: (MOVBUload ptr mem)
+ for {
+ t := v.Type
+ ptr := v.Args[0]
+ mem := v.Args[1]
+ if !(t.IsBoolean()) {
+ break
+ }
+ v.reset(OpMIPS64MOVBUload)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (Load <t> ptr mem)
+ // cond: (is8BitInt(t) && isSigned(t))
+ // result: (MOVBload ptr mem)
+ for {
+ t := v.Type
+ ptr := v.Args[0]
+ mem := v.Args[1]
+ if !(is8BitInt(t) && isSigned(t)) {
+ break
+ }
+ v.reset(OpMIPS64MOVBload)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (Load <t> ptr mem)
+ // cond: (is8BitInt(t) && !isSigned(t))
+ // result: (MOVBUload ptr mem)
+ for {
+ t := v.Type
+ ptr := v.Args[0]
+ mem := v.Args[1]
+ if !(is8BitInt(t) && !isSigned(t)) {
+ break
+ }
+ v.reset(OpMIPS64MOVBUload)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (Load <t> ptr mem)
+ // cond: (is16BitInt(t) && isSigned(t))
+ // result: (MOVHload ptr mem)
+ for {
+ t := v.Type
+ ptr := v.Args[0]
+ mem := v.Args[1]
+ if !(is16BitInt(t) && isSigned(t)) {
+ break
+ }
+ v.reset(OpMIPS64MOVHload)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (Load <t> ptr mem)
+ // cond: (is16BitInt(t) && !isSigned(t))
+ // result: (MOVHUload ptr mem)
+ for {
+ t := v.Type
+ ptr := v.Args[0]
+ mem := v.Args[1]
+ if !(is16BitInt(t) && !isSigned(t)) {
+ break
+ }
+ v.reset(OpMIPS64MOVHUload)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (Load <t> ptr mem)
+ // cond: (is32BitInt(t) && isSigned(t))
+ // result: (MOVWload ptr mem)
+ for {
+ t := v.Type
+ ptr := v.Args[0]
+ mem := v.Args[1]
+ if !(is32BitInt(t) && isSigned(t)) {
+ break
+ }
+ v.reset(OpMIPS64MOVWload)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (Load <t> ptr mem)
+ // cond: (is32BitInt(t) && !isSigned(t))
+ // result: (MOVWUload ptr mem)
+ for {
+ t := v.Type
+ ptr := v.Args[0]
+ mem := v.Args[1]
+ if !(is32BitInt(t) && !isSigned(t)) {
+ break
+ }
+ v.reset(OpMIPS64MOVWUload)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (Load <t> ptr mem)
+ // cond: (is64BitInt(t) || isPtr(t))
+ // result: (MOVVload ptr mem)
+ for {
+ t := v.Type
+ ptr := v.Args[0]
+ mem := v.Args[1]
+ if !(is64BitInt(t) || isPtr(t)) {
+ break
+ }
+ v.reset(OpMIPS64MOVVload)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (Load <t> ptr mem)
+ // cond: is32BitFloat(t)
+ // result: (MOVFload ptr mem)
+ for {
+ t := v.Type
+ ptr := v.Args[0]
+ mem := v.Args[1]
+ if !(is32BitFloat(t)) {
+ break
+ }
+ v.reset(OpMIPS64MOVFload)
+ v.AddArg(ptr)
+ 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(OpMIPS64MOVDload)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS64_OpLsh16x16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Lsh16x16 <t> x y)
+ // cond:
+ // result: (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt16to64 y))) (SLLV <t> x (ZeroExt16to64 y)))
+ 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, OpMIPS64SLLV, t)
+ v4.AddArg(x)
+ v5 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+ v5.AddArg(y)
+ v4.AddArg(v5)
+ v.AddArg(v4)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpLsh16x32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Lsh16x32 <t> x y)
+ // cond:
+ // result: (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt32to64 y))) (SLLV <t> x (ZeroExt32to64 y)))
+ 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, OpZeroExt32to64, config.fe.TypeUInt64())
+ v3.AddArg(y)
+ v1.AddArg(v3)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ v4 := b.NewValue0(v.Line, OpMIPS64SLLV, t)
+ v4.AddArg(x)
+ v5 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+ v5.AddArg(y)
+ v4.AddArg(v5)
+ v.AddArg(v4)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpLsh16x64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Lsh16x64 <t> x y)
+ // cond:
+ // result: (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) y)) (SLLV <t> x y))
+ 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)
+ v1.AddArg(y)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ v3 := b.NewValue0(v.Line, OpMIPS64SLLV, t)
+ v3.AddArg(x)
+ v3.AddArg(y)
+ v.AddArg(v3)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpLsh16x8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Lsh16x8 <t> x y)
+ // cond:
+ // result: (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt8to64 y))) (SLLV <t> x (ZeroExt8to64 y)))
+ 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, OpZeroExt8to64, config.fe.TypeUInt64())
+ v3.AddArg(y)
+ v1.AddArg(v3)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ v4 := b.NewValue0(v.Line, OpMIPS64SLLV, t)
+ v4.AddArg(x)
+ v5 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+ v5.AddArg(y)
+ v4.AddArg(v5)
+ v.AddArg(v4)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpLsh32x16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Lsh32x16 <t> x y)
+ // cond:
+ // result: (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt16to64 y))) (SLLV <t> x (ZeroExt16to64 y)))
+ 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, OpMIPS64SLLV, t)
+ v4.AddArg(x)
+ v5 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+ v5.AddArg(y)
+ v4.AddArg(v5)
+ v.AddArg(v4)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpLsh32x32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Lsh32x32 <t> x y)
+ // cond:
+ // result: (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt32to64 y))) (SLLV <t> x (ZeroExt32to64 y)))
+ 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, OpZeroExt32to64, config.fe.TypeUInt64())
+ v3.AddArg(y)
+ v1.AddArg(v3)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ v4 := b.NewValue0(v.Line, OpMIPS64SLLV, t)
+ v4.AddArg(x)
+ v5 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+ v5.AddArg(y)
+ v4.AddArg(v5)
+ v.AddArg(v4)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpLsh32x64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Lsh32x64 <t> x y)
+ // cond:
+ // result: (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) y)) (SLLV <t> x y))
+ 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)
+ v1.AddArg(y)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ v3 := b.NewValue0(v.Line, OpMIPS64SLLV, t)
+ v3.AddArg(x)
+ v3.AddArg(y)
+ v.AddArg(v3)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpLsh32x8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Lsh32x8 <t> x y)
+ // cond:
+ // result: (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt8to64 y))) (SLLV <t> x (ZeroExt8to64 y)))
+ 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, OpZeroExt8to64, config.fe.TypeUInt64())
+ v3.AddArg(y)
+ v1.AddArg(v3)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ v4 := b.NewValue0(v.Line, OpMIPS64SLLV, t)
+ v4.AddArg(x)
+ v5 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+ v5.AddArg(y)
+ v4.AddArg(v5)
+ v.AddArg(v4)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpLsh64x16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Lsh64x16 <t> x y)
+ // cond:
+ // result: (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt16to64 y))) (SLLV <t> x (ZeroExt16to64 y)))
+ 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, OpMIPS64SLLV, t)
+ v4.AddArg(x)
+ v5 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+ v5.AddArg(y)
+ v4.AddArg(v5)
+ v.AddArg(v4)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpLsh64x32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Lsh64x32 <t> x y)
+ // cond:
+ // result: (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt32to64 y))) (SLLV <t> x (ZeroExt32to64 y)))
+ 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, OpZeroExt32to64, config.fe.TypeUInt64())
+ v3.AddArg(y)
+ v1.AddArg(v3)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ v4 := b.NewValue0(v.Line, OpMIPS64SLLV, t)
+ v4.AddArg(x)
+ v5 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+ v5.AddArg(y)
+ v4.AddArg(v5)
+ v.AddArg(v4)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpLsh64x64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Lsh64x64 <t> x y)
+ // cond:
+ // result: (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) y)) (SLLV <t> x y))
+ 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)
+ v1.AddArg(y)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ v3 := b.NewValue0(v.Line, OpMIPS64SLLV, t)
+ v3.AddArg(x)
+ v3.AddArg(y)
+ v.AddArg(v3)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpLsh64x8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Lsh64x8 <t> x y)
+ // cond:
+ // result: (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt8to64 y))) (SLLV <t> x (ZeroExt8to64 y)))
+ 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, OpZeroExt8to64, config.fe.TypeUInt64())
+ v3.AddArg(y)
+ v1.AddArg(v3)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ v4 := b.NewValue0(v.Line, OpMIPS64SLLV, t)
+ v4.AddArg(x)
+ v5 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+ v5.AddArg(y)
+ v4.AddArg(v5)
+ v.AddArg(v4)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpLsh8x16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Lsh8x16 <t> x y)
+ // cond:
+ // result: (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt16to64 y))) (SLLV <t> x (ZeroExt16to64 y)))
+ 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, OpMIPS64SLLV, t)
+ v4.AddArg(x)
+ v5 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+ v5.AddArg(y)
+ v4.AddArg(v5)
+ v.AddArg(v4)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpLsh8x32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Lsh8x32 <t> x y)
+ // cond:
+ // result: (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt32to64 y))) (SLLV <t> x (ZeroExt32to64 y)))
+ 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, OpZeroExt32to64, config.fe.TypeUInt64())
+ v3.AddArg(y)
+ v1.AddArg(v3)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ v4 := b.NewValue0(v.Line, OpMIPS64SLLV, t)
+ v4.AddArg(x)
+ v5 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+ v5.AddArg(y)
+ v4.AddArg(v5)
+ v.AddArg(v4)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpLsh8x64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Lsh8x64 <t> x y)
+ // cond:
+ // result: (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) y)) (SLLV <t> x y))
+ 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)
+ v1.AddArg(y)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ v3 := b.NewValue0(v.Line, OpMIPS64SLLV, t)
+ v3.AddArg(x)
+ v3.AddArg(y)
+ v.AddArg(v3)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpLsh8x8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Lsh8x8 <t> x y)
+ // cond:
+ // result: (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt8to64 y))) (SLLV <t> x (ZeroExt8to64 y)))
+ 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, OpZeroExt8to64, config.fe.TypeUInt64())
+ v3.AddArg(y)
+ v1.AddArg(v3)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ v4 := b.NewValue0(v.Line, OpMIPS64SLLV, t)
+ v4.AddArg(x)
+ v5 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+ 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)
+ // cond: is32Bit(c)
+ // result: (ADDVconst [c] x)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPS64MOVVconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ if !(is32Bit(c)) {
+ break
+ }
+ v.reset(OpMIPS64ADDVconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (ADDV x (MOVVconst [c]))
+ // cond: is32Bit(c)
+ // result: (ADDVconst [c] x)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpMIPS64MOVVconst {
+ break
+ }
+ c := v_1.AuxInt
+ if !(is32Bit(c)) {
+ break
+ }
+ v.reset(OpMIPS64ADDVconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (ADDV x (NEGV y))
+ // cond:
+ // result: (SUBV x y)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpMIPS64NEGV {
+ break
+ }
+ y := v_1.Args[0]
+ v.reset(OpMIPS64SUBV)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (ADDV (NEGV y) x)
+ // cond:
+ // result: (SUBV x y)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPS64NEGV {
+ break
+ }
+ y := v_0.Args[0]
+ x := v.Args[1]
+ v.reset(OpMIPS64SUBV)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS64_OpMIPS64ADDVconst(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ADDVconst [off1] (MOVVaddr [off2] {sym} ptr))
+ // cond:
+ // result: (MOVVaddr [off1+off2] {sym} ptr)
+ for {
+ off1 := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPS64MOVVaddr {
+ break
+ }
+ off2 := v_0.AuxInt
+ sym := v_0.Aux
+ ptr := v_0.Args[0]
+ v.reset(OpMIPS64MOVVaddr)
+ v.AuxInt = off1 + off2
+ v.Aux = sym
+ v.AddArg(ptr)
+ return true
+ }
+ // match: (ADDVconst [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: (ADDVconst [c] (MOVVconst [d]))
+ // cond:
+ // result: (MOVVconst [c+d])
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPS64MOVVconst {
+ break
+ }
+ d := v_0.AuxInt
+ v.reset(OpMIPS64MOVVconst)
+ v.AuxInt = c + d
+ return true
+ }
+ // match: (ADDVconst [c] (ADDVconst [d] x))
+ // cond: is32Bit(c+d)
+ // result: (ADDVconst [c+d] x)
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPS64ADDVconst {
+ break
+ }
+ d := v_0.AuxInt
+ x := v_0.Args[0]
+ if !(is32Bit(c + d)) {
+ break
+ }
+ v.reset(OpMIPS64ADDVconst)
+ v.AuxInt = c + d
+ v.AddArg(x)
+ return true
+ }
+ // match: (ADDVconst [c] (SUBVconst [d] x))
+ // cond: is32Bit(c-d)
+ // result: (ADDVconst [c-d] x)
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPS64SUBVconst {
+ break
+ }
+ d := v_0.AuxInt
+ x := v_0.Args[0]
+ if !(is32Bit(c - d)) {
+ break
+ }
+ v.reset(OpMIPS64ADDVconst)
+ v.AuxInt = c - d
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS64_OpMIPS64AND(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (AND (MOVVconst [c]) x)
+ // cond: is32Bit(c)
+ // result: (ANDconst [c] x)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPS64MOVVconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ if !(is32Bit(c)) {
+ break
+ }
+ v.reset(OpMIPS64ANDconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (AND x (MOVVconst [c]))
+ // cond: is32Bit(c)
+ // result: (ANDconst [c] x)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpMIPS64MOVVconst {
+ break
+ }
+ c := v_1.AuxInt
+ if !(is32Bit(c)) {
+ break
+ }
+ v.reset(OpMIPS64ANDconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (AND x x)
+ // cond:
+ // result: x
+ for {
+ x := v.Args[0]
+ if x != v.Args[1] {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS64_OpMIPS64ANDconst(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ANDconst [0] _)
+ // cond:
+ // result: (MOVVconst [0])
+ for {
+ if v.AuxInt != 0 {
+ break
+ }
+ v.reset(OpMIPS64MOVVconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (ANDconst [-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: (ANDconst [c] (MOVVconst [d]))
+ // cond:
+ // result: (MOVVconst [c&d])
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPS64MOVVconst {
+ break
+ }
+ d := v_0.AuxInt
+ v.reset(OpMIPS64MOVVconst)
+ v.AuxInt = c & d
+ return true
+ }
+ // match: (ANDconst [c] (ANDconst [d] x))
+ // cond:
+ // result: (ANDconst [c&d] x)
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPS64ANDconst {
+ break
+ }
+ d := v_0.AuxInt
+ x := v_0.Args[0]
+ v.reset(OpMIPS64ANDconst)
+ v.AuxInt = c & d
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS64_OpMIPS64MOVBUload(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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_0 := v.Args[0]
+ if v_0.Op != OpMIPS64ADDVconst {
+ break
+ }
+ off2 := v_0.AuxInt
+ ptr := v_0.Args[0]
+ mem := v.Args[1]
+ if !(is32Bit(off1 + off2)) {
+ break
+ }
+ v.reset(OpMIPS64MOVBUload)
+ v.AuxInt = off1 + off2
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVBUload [off1] {sym1} (MOVVaddr [off2] {sym2} ptr) mem)
+ // cond: canMergeSym(sym1,sym2) && is32Bit(off1+off2)
+ // result: (MOVBUload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
+ for {
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPS64MOVVaddr {
+ break
+ }
+ off2 := v_0.AuxInt
+ sym2 := v_0.Aux
+ ptr := v_0.Args[0]
+ mem := v.Args[1]
+ if !(canMergeSym(sym1, sym2) && is32Bit(off1+off2)) {
+ break
+ }
+ v.reset(OpMIPS64MOVBUload)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS64_OpMIPS64MOVBUreg(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (MOVBUreg x:(MOVBUload _ _))
+ // cond:
+ // result: (MOVVreg x)
+ for {
+ x := v.Args[0]
+ if x.Op != OpMIPS64MOVBUload {
+ break
+ }
+ v.reset(OpMIPS64MOVVreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVBUreg x:(MOVBUreg _))
+ // cond:
+ // result: (MOVVreg x)
+ for {
+ x := v.Args[0]
+ if x.Op != OpMIPS64MOVBUreg {
+ break
+ }
+ v.reset(OpMIPS64MOVVreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVBUreg (MOVVconst [c]))
+ // cond:
+ // result: (MOVVconst [int64(uint8(c))])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPS64MOVVconst {
+ break
+ }
+ c := v_0.AuxInt
+ v.reset(OpMIPS64MOVVconst)
+ v.AuxInt = int64(uint8(c))
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS64_OpMIPS64MOVBload(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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_0 := v.Args[0]
+ if v_0.Op != OpMIPS64ADDVconst {
+ break
+ }
+ off2 := v_0.AuxInt
+ ptr := v_0.Args[0]
+ mem := v.Args[1]
+ if !(is32Bit(off1 + off2)) {
+ break
+ }
+ v.reset(OpMIPS64MOVBload)
+ v.AuxInt = off1 + off2
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVBload [off1] {sym1} (MOVVaddr [off2] {sym2} ptr) mem)
+ // cond: canMergeSym(sym1,sym2) && is32Bit(off1+off2)
+ // result: (MOVBload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
+ for {
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPS64MOVVaddr {
+ break
+ }
+ off2 := v_0.AuxInt
+ sym2 := v_0.Aux
+ ptr := v_0.Args[0]
+ mem := v.Args[1]
+ if !(canMergeSym(sym1, sym2) && is32Bit(off1+off2)) {
+ break
+ }
+ v.reset(OpMIPS64MOVBload)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS64_OpMIPS64MOVBreg(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (MOVBreg x:(MOVBload _ _))
+ // cond:
+ // result: (MOVVreg x)
+ for {
+ x := v.Args[0]
+ if x.Op != OpMIPS64MOVBload {
+ break
+ }
+ v.reset(OpMIPS64MOVVreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVBreg x:(MOVBreg _))
+ // cond:
+ // result: (MOVVreg x)
+ for {
+ x := v.Args[0]
+ if x.Op != OpMIPS64MOVBreg {
+ break
+ }
+ v.reset(OpMIPS64MOVVreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVBreg (MOVVconst [c]))
+ // cond:
+ // result: (MOVVconst [int64(int8(c))])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPS64MOVVconst {
+ break
+ }
+ c := v_0.AuxInt
+ v.reset(OpMIPS64MOVVconst)
+ v.AuxInt = int64(int8(c))
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS64_OpMIPS64MOVBstore(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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_0 := v.Args[0]
+ if v_0.Op != OpMIPS64ADDVconst {
+ break
+ }
+ off2 := v_0.AuxInt
+ ptr := v_0.Args[0]
+ val := v.Args[1]
+ mem := v.Args[2]
+ if !(is32Bit(off1 + off2)) {
+ break
+ }
+ v.reset(OpMIPS64MOVBstore)
+ v.AuxInt = off1 + off2
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVBstore [off1] {sym1} (MOVVaddr [off2] {sym2} ptr) val mem)
+ // cond: canMergeSym(sym1,sym2) && is32Bit(off1+off2)
+ // result: (MOVBstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
+ for {
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPS64MOVVaddr {
+ 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) && is32Bit(off1+off2)) {
+ break
+ }
+ v.reset(OpMIPS64MOVBstore)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(ptr)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVBstore [off] {sym} ptr (MOVVconst [0]) mem)
+ // cond:
+ // result: (MOVBstorezero [off] {sym} ptr mem)
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpMIPS64MOVVconst {
+ break
+ }
+ if v_1.AuxInt != 0 {
+ break
+ }
+ mem := v.Args[2]
+ v.reset(OpMIPS64MOVBstorezero)
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVBstore [off] {sym} ptr (MOVBreg x) mem)
+ // cond:
+ // result: (MOVBstore [off] {sym} ptr x mem)
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpMIPS64MOVBreg {
+ break
+ }
+ x := v_1.Args[0]
+ mem := v.Args[2]
+ v.reset(OpMIPS64MOVBstore)
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(x)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVBstore [off] {sym} ptr (MOVBUreg x) mem)
+ // cond:
+ // result: (MOVBstore [off] {sym} ptr x mem)
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpMIPS64MOVBUreg {
+ break
+ }
+ x := v_1.Args[0]
+ mem := v.Args[2]
+ v.reset(OpMIPS64MOVBstore)
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(x)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVBstore [off] {sym} ptr (MOVHreg x) mem)
+ // cond:
+ // result: (MOVBstore [off] {sym} ptr x mem)
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpMIPS64MOVHreg {
+ break
+ }
+ x := v_1.Args[0]
+ mem := v.Args[2]
+ v.reset(OpMIPS64MOVBstore)
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(x)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVBstore [off] {sym} ptr (MOVHUreg x) mem)
+ // cond:
+ // result: (MOVBstore [off] {sym} ptr x mem)
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpMIPS64MOVHUreg {
+ break
+ }
+ x := v_1.Args[0]
+ mem := v.Args[2]
+ v.reset(OpMIPS64MOVBstore)
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(x)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVBstore [off] {sym} ptr (MOVWreg x) mem)
+ // cond:
+ // result: (MOVBstore [off] {sym} ptr x mem)
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpMIPS64MOVWreg {
+ break
+ }
+ x := v_1.Args[0]
+ mem := v.Args[2]
+ v.reset(OpMIPS64MOVBstore)
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(x)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVBstore [off] {sym} ptr (MOVWUreg x) mem)
+ // cond:
+ // result: (MOVBstore [off] {sym} ptr x mem)
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpMIPS64MOVWUreg {
+ break
+ }
+ x := v_1.Args[0]
+ mem := v.Args[2]
+ v.reset(OpMIPS64MOVBstore)
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(x)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS64_OpMIPS64MOVBstorezero(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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_0 := v.Args[0]
+ if v_0.Op != OpMIPS64ADDVconst {
+ break
+ }
+ off2 := v_0.AuxInt
+ ptr := v_0.Args[0]
+ mem := v.Args[1]
+ if !(is32Bit(off1 + off2)) {
+ break
+ }
+ v.reset(OpMIPS64MOVBstorezero)
+ v.AuxInt = off1 + off2
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVBstorezero [off1] {sym1} (MOVVaddr [off2] {sym2} ptr) mem)
+ // cond: canMergeSym(sym1,sym2) && is32Bit(off1+off2)
+ // result: (MOVBstorezero [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
+ for {
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPS64MOVVaddr {
+ break
+ }
+ off2 := v_0.AuxInt
+ sym2 := v_0.Aux
+ ptr := v_0.Args[0]
+ mem := v.Args[1]
+ if !(canMergeSym(sym1, sym2) && is32Bit(off1+off2)) {
+ break
+ }
+ v.reset(OpMIPS64MOVBstorezero)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS64_OpMIPS64MOVDload(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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_0 := v.Args[0]
+ if v_0.Op != OpMIPS64ADDVconst {
+ break
+ }
+ off2 := v_0.AuxInt
+ ptr := v_0.Args[0]
+ mem := v.Args[1]
+ if !(is32Bit(off1 + off2)) {
+ break
+ }
+ v.reset(OpMIPS64MOVDload)
+ v.AuxInt = off1 + off2
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVDload [off1] {sym1} (MOVVaddr [off2] {sym2} ptr) mem)
+ // cond: canMergeSym(sym1,sym2) && is32Bit(off1+off2)
+ // result: (MOVDload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
+ for {
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPS64MOVVaddr {
+ break
+ }
+ off2 := v_0.AuxInt
+ sym2 := v_0.Aux
+ ptr := v_0.Args[0]
+ mem := v.Args[1]
+ if !(canMergeSym(sym1, sym2) && is32Bit(off1+off2)) {
+ break
+ }
+ v.reset(OpMIPS64MOVDload)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS64_OpMIPS64MOVDstore(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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_0 := v.Args[0]
+ if v_0.Op != OpMIPS64ADDVconst {
+ break
+ }
+ off2 := v_0.AuxInt
+ ptr := v_0.Args[0]
+ val := v.Args[1]
+ mem := v.Args[2]
+ if !(is32Bit(off1 + off2)) {
+ break
+ }
+ v.reset(OpMIPS64MOVDstore)
+ v.AuxInt = off1 + off2
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVDstore [off1] {sym1} (MOVVaddr [off2] {sym2} ptr) val mem)
+ // cond: canMergeSym(sym1,sym2) && is32Bit(off1+off2)
+ // result: (MOVDstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
+ for {
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPS64MOVVaddr {
+ 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) && is32Bit(off1+off2)) {
+ break
+ }
+ v.reset(OpMIPS64MOVDstore)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(ptr)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS64_OpMIPS64MOVFload(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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_0 := v.Args[0]
+ if v_0.Op != OpMIPS64ADDVconst {
+ break
+ }
+ off2 := v_0.AuxInt
+ ptr := v_0.Args[0]
+ mem := v.Args[1]
+ if !(is32Bit(off1 + off2)) {
+ break
+ }
+ v.reset(OpMIPS64MOVFload)
+ v.AuxInt = off1 + off2
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVFload [off1] {sym1} (MOVVaddr [off2] {sym2} ptr) mem)
+ // cond: canMergeSym(sym1,sym2) && is32Bit(off1+off2)
+ // result: (MOVFload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
+ for {
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPS64MOVVaddr {
+ break
+ }
+ off2 := v_0.AuxInt
+ sym2 := v_0.Aux
+ ptr := v_0.Args[0]
+ mem := v.Args[1]
+ if !(canMergeSym(sym1, sym2) && is32Bit(off1+off2)) {
+ break
+ }
+ v.reset(OpMIPS64MOVFload)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS64_OpMIPS64MOVFstore(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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_0 := v.Args[0]
+ if v_0.Op != OpMIPS64ADDVconst {
+ break
+ }
+ off2 := v_0.AuxInt
+ ptr := v_0.Args[0]
+ val := v.Args[1]
+ mem := v.Args[2]
+ if !(is32Bit(off1 + off2)) {
+ break
+ }
+ v.reset(OpMIPS64MOVFstore)
+ v.AuxInt = off1 + off2
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVFstore [off1] {sym1} (MOVVaddr [off2] {sym2} ptr) val mem)
+ // cond: canMergeSym(sym1,sym2) && is32Bit(off1+off2)
+ // result: (MOVFstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
+ for {
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPS64MOVVaddr {
+ 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) && is32Bit(off1+off2)) {
+ break
+ }
+ v.reset(OpMIPS64MOVFstore)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(ptr)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS64_OpMIPS64MOVHUload(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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_0 := v.Args[0]
+ if v_0.Op != OpMIPS64ADDVconst {
+ break
+ }
+ off2 := v_0.AuxInt
+ ptr := v_0.Args[0]
+ mem := v.Args[1]
+ if !(is32Bit(off1 + off2)) {
+ break
+ }
+ v.reset(OpMIPS64MOVHUload)
+ v.AuxInt = off1 + off2
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVHUload [off1] {sym1} (MOVVaddr [off2] {sym2} ptr) mem)
+ // cond: canMergeSym(sym1,sym2) && is32Bit(off1+off2)
+ // result: (MOVHUload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
+ for {
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPS64MOVVaddr {
+ break
+ }
+ off2 := v_0.AuxInt
+ sym2 := v_0.Aux
+ ptr := v_0.Args[0]
+ mem := v.Args[1]
+ if !(canMergeSym(sym1, sym2) && is32Bit(off1+off2)) {
+ break
+ }
+ v.reset(OpMIPS64MOVHUload)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS64_OpMIPS64MOVHUreg(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (MOVHUreg x:(MOVBUload _ _))
+ // cond:
+ // result: (MOVVreg x)
+ for {
+ x := v.Args[0]
+ if x.Op != OpMIPS64MOVBUload {
+ break
+ }
+ v.reset(OpMIPS64MOVVreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVHUreg x:(MOVHUload _ _))
+ // cond:
+ // result: (MOVVreg x)
+ for {
+ x := v.Args[0]
+ if x.Op != OpMIPS64MOVHUload {
+ break
+ }
+ v.reset(OpMIPS64MOVVreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVHUreg x:(MOVBUreg _))
+ // cond:
+ // result: (MOVVreg x)
+ for {
+ x := v.Args[0]
+ if x.Op != OpMIPS64MOVBUreg {
+ break
+ }
+ v.reset(OpMIPS64MOVVreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVHUreg x:(MOVHUreg _))
+ // cond:
+ // result: (MOVVreg x)
+ for {
+ x := v.Args[0]
+ if x.Op != OpMIPS64MOVHUreg {
+ break
+ }
+ v.reset(OpMIPS64MOVVreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVHUreg (MOVVconst [c]))
+ // cond:
+ // result: (MOVVconst [int64(uint16(c))])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPS64MOVVconst {
+ break
+ }
+ c := v_0.AuxInt
+ v.reset(OpMIPS64MOVVconst)
+ v.AuxInt = int64(uint16(c))
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS64_OpMIPS64MOVHload(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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_0 := v.Args[0]
+ if v_0.Op != OpMIPS64ADDVconst {
+ break
+ }
+ off2 := v_0.AuxInt
+ ptr := v_0.Args[0]
+ mem := v.Args[1]
+ if !(is32Bit(off1 + off2)) {
+ break
+ }
+ v.reset(OpMIPS64MOVHload)
+ v.AuxInt = off1 + off2
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVHload [off1] {sym1} (MOVVaddr [off2] {sym2} ptr) mem)
+ // cond: canMergeSym(sym1,sym2) && is32Bit(off1+off2)
+ // result: (MOVHload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
+ for {
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPS64MOVVaddr {
+ break
+ }
+ off2 := v_0.AuxInt
+ sym2 := v_0.Aux
+ ptr := v_0.Args[0]
+ mem := v.Args[1]
+ if !(canMergeSym(sym1, sym2) && is32Bit(off1+off2)) {
+ break
+ }
+ v.reset(OpMIPS64MOVHload)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS64_OpMIPS64MOVHreg(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (MOVHreg x:(MOVBload _ _))
+ // cond:
+ // result: (MOVVreg x)
+ for {
+ x := v.Args[0]
+ if x.Op != OpMIPS64MOVBload {
+ break
+ }
+ v.reset(OpMIPS64MOVVreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVHreg x:(MOVBUload _ _))
+ // cond:
+ // result: (MOVVreg x)
+ for {
+ x := v.Args[0]
+ if x.Op != OpMIPS64MOVBUload {
+ break
+ }
+ v.reset(OpMIPS64MOVVreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVHreg x:(MOVHload _ _))
+ // cond:
+ // result: (MOVVreg x)
+ for {
+ x := v.Args[0]
+ if x.Op != OpMIPS64MOVHload {
+ break
+ }
+ v.reset(OpMIPS64MOVVreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVHreg x:(MOVBreg _))
+ // cond:
+ // result: (MOVVreg x)
+ for {
+ x := v.Args[0]
+ if x.Op != OpMIPS64MOVBreg {
+ break
+ }
+ v.reset(OpMIPS64MOVVreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVHreg x:(MOVBUreg _))
+ // cond:
+ // result: (MOVVreg x)
+ for {
+ x := v.Args[0]
+ if x.Op != OpMIPS64MOVBUreg {
+ break
+ }
+ v.reset(OpMIPS64MOVVreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVHreg x:(MOVHreg _))
+ // cond:
+ // result: (MOVVreg x)
+ for {
+ x := v.Args[0]
+ if x.Op != OpMIPS64MOVHreg {
+ break
+ }
+ v.reset(OpMIPS64MOVVreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVHreg (MOVVconst [c]))
+ // cond:
+ // result: (MOVVconst [int64(int16(c))])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPS64MOVVconst {
+ break
+ }
+ c := v_0.AuxInt
+ v.reset(OpMIPS64MOVVconst)
+ v.AuxInt = int64(int16(c))
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS64_OpMIPS64MOVHstore(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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_0 := v.Args[0]
+ if v_0.Op != OpMIPS64ADDVconst {
+ break
+ }
+ off2 := v_0.AuxInt
+ ptr := v_0.Args[0]
+ val := v.Args[1]
+ mem := v.Args[2]
+ if !(is32Bit(off1 + off2)) {
+ break
+ }
+ v.reset(OpMIPS64MOVHstore)
+ v.AuxInt = off1 + off2
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVHstore [off1] {sym1} (MOVVaddr [off2] {sym2} ptr) val mem)
+ // cond: canMergeSym(sym1,sym2) && is32Bit(off1+off2)
+ // result: (MOVHstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
+ for {
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPS64MOVVaddr {
+ 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) && is32Bit(off1+off2)) {
+ break
+ }
+ v.reset(OpMIPS64MOVHstore)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(ptr)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVHstore [off] {sym} ptr (MOVVconst [0]) mem)
+ // cond:
+ // result: (MOVHstorezero [off] {sym} ptr mem)
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpMIPS64MOVVconst {
+ break
+ }
+ if v_1.AuxInt != 0 {
+ break
+ }
+ mem := v.Args[2]
+ v.reset(OpMIPS64MOVHstorezero)
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVHstore [off] {sym} ptr (MOVHreg 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 != OpMIPS64MOVHreg {
+ break
+ }
+ x := v_1.Args[0]
+ mem := v.Args[2]
+ v.reset(OpMIPS64MOVHstore)
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(x)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVHstore [off] {sym} ptr (MOVHUreg 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 != OpMIPS64MOVHUreg {
+ break
+ }
+ x := v_1.Args[0]
+ mem := v.Args[2]
+ v.reset(OpMIPS64MOVHstore)
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(x)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVHstore [off] {sym} ptr (MOVWreg 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 != OpMIPS64MOVWreg {
+ break
+ }
+ x := v_1.Args[0]
+ mem := v.Args[2]
+ v.reset(OpMIPS64MOVHstore)
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(x)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVHstore [off] {sym} ptr (MOVWUreg 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 != OpMIPS64MOVWUreg {
+ break
+ }
+ x := v_1.Args[0]
+ mem := v.Args[2]
+ v.reset(OpMIPS64MOVHstore)
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(x)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS64_OpMIPS64MOVHstorezero(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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_0 := v.Args[0]
+ if v_0.Op != OpMIPS64ADDVconst {
+ break
+ }
+ off2 := v_0.AuxInt
+ ptr := v_0.Args[0]
+ mem := v.Args[1]
+ if !(is32Bit(off1 + off2)) {
+ break
+ }
+ v.reset(OpMIPS64MOVHstorezero)
+ v.AuxInt = off1 + off2
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVHstorezero [off1] {sym1} (MOVVaddr [off2] {sym2} ptr) mem)
+ // cond: canMergeSym(sym1,sym2) && is32Bit(off1+off2)
+ // result: (MOVHstorezero [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
+ for {
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPS64MOVVaddr {
+ break
+ }
+ off2 := v_0.AuxInt
+ sym2 := v_0.Aux
+ ptr := v_0.Args[0]
+ mem := v.Args[1]
+ if !(canMergeSym(sym1, sym2) && is32Bit(off1+off2)) {
+ break
+ }
+ v.reset(OpMIPS64MOVHstorezero)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS64_OpMIPS64MOVVload(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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_0 := v.Args[0]
+ if v_0.Op != OpMIPS64ADDVconst {
+ break
+ }
+ off2 := v_0.AuxInt
+ ptr := v_0.Args[0]
+ mem := v.Args[1]
+ if !(is32Bit(off1 + off2)) {
+ break
+ }
+ v.reset(OpMIPS64MOVVload)
+ v.AuxInt = off1 + off2
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVVload [off1] {sym1} (MOVVaddr [off2] {sym2} ptr) mem)
+ // cond: canMergeSym(sym1,sym2) && is32Bit(off1+off2)
+ // result: (MOVVload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
+ for {
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPS64MOVVaddr {
+ break
+ }
+ off2 := v_0.AuxInt
+ sym2 := v_0.Aux
+ ptr := v_0.Args[0]
+ mem := v.Args[1]
+ if !(canMergeSym(sym1, sym2) && is32Bit(off1+off2)) {
+ break
+ }
+ v.reset(OpMIPS64MOVVload)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS64_OpMIPS64MOVVreg(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (MOVVreg x)
+ // cond: x.Uses == 1
+ // result: (MOVVnop x)
+ for {
+ x := v.Args[0]
+ if !(x.Uses == 1) {
+ break
+ }
+ v.reset(OpMIPS64MOVVnop)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVVreg (MOVVconst [c]))
+ // cond:
+ // result: (MOVVconst [c])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPS64MOVVconst {
+ break
+ }
+ c := v_0.AuxInt
+ v.reset(OpMIPS64MOVVconst)
+ v.AuxInt = c
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS64_OpMIPS64MOVVstore(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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_0 := v.Args[0]
+ if v_0.Op != OpMIPS64ADDVconst {
+ break
+ }
+ off2 := v_0.AuxInt
+ ptr := v_0.Args[0]
+ val := v.Args[1]
+ mem := v.Args[2]
+ if !(is32Bit(off1 + off2)) {
+ break
+ }
+ v.reset(OpMIPS64MOVVstore)
+ v.AuxInt = off1 + off2
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVVstore [off1] {sym1} (MOVVaddr [off2] {sym2} ptr) val mem)
+ // cond: canMergeSym(sym1,sym2) && is32Bit(off1+off2)
+ // result: (MOVVstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
+ for {
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPS64MOVVaddr {
+ 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) && is32Bit(off1+off2)) {
+ break
+ }
+ v.reset(OpMIPS64MOVVstore)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(ptr)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVVstore [off] {sym} ptr (MOVVconst [0]) mem)
+ // cond:
+ // result: (MOVVstorezero [off] {sym} ptr mem)
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpMIPS64MOVVconst {
+ break
+ }
+ if v_1.AuxInt != 0 {
+ break
+ }
+ mem := v.Args[2]
+ v.reset(OpMIPS64MOVVstorezero)
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS64_OpMIPS64MOVVstorezero(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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_0 := v.Args[0]
+ if v_0.Op != OpMIPS64ADDVconst {
+ break
+ }
+ off2 := v_0.AuxInt
+ ptr := v_0.Args[0]
+ mem := v.Args[1]
+ if !(is32Bit(off1 + off2)) {
+ break
+ }
+ v.reset(OpMIPS64MOVVstorezero)
+ v.AuxInt = off1 + off2
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVVstorezero [off1] {sym1} (MOVVaddr [off2] {sym2} ptr) mem)
+ // cond: canMergeSym(sym1,sym2) && is32Bit(off1+off2)
+ // result: (MOVVstorezero [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
+ for {
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPS64MOVVaddr {
+ break
+ }
+ off2 := v_0.AuxInt
+ sym2 := v_0.Aux
+ ptr := v_0.Args[0]
+ mem := v.Args[1]
+ if !(canMergeSym(sym1, sym2) && is32Bit(off1+off2)) {
+ break
+ }
+ v.reset(OpMIPS64MOVVstorezero)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS64_OpMIPS64MOVWUload(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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_0 := v.Args[0]
+ if v_0.Op != OpMIPS64ADDVconst {
+ break
+ }
+ off2 := v_0.AuxInt
+ ptr := v_0.Args[0]
+ mem := v.Args[1]
+ if !(is32Bit(off1 + off2)) {
+ break
+ }
+ v.reset(OpMIPS64MOVWUload)
+ v.AuxInt = off1 + off2
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVWUload [off1] {sym1} (MOVVaddr [off2] {sym2} ptr) mem)
+ // cond: canMergeSym(sym1,sym2) && is32Bit(off1+off2)
+ // result: (MOVWUload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
+ for {
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPS64MOVVaddr {
+ break
+ }
+ off2 := v_0.AuxInt
+ sym2 := v_0.Aux
+ ptr := v_0.Args[0]
+ mem := v.Args[1]
+ if !(canMergeSym(sym1, sym2) && is32Bit(off1+off2)) {
+ break
+ }
+ v.reset(OpMIPS64MOVWUload)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS64_OpMIPS64MOVWUreg(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (MOVWUreg x:(MOVBUload _ _))
+ // cond:
+ // result: (MOVVreg x)
+ for {
+ x := v.Args[0]
+ if x.Op != OpMIPS64MOVBUload {
+ break
+ }
+ v.reset(OpMIPS64MOVVreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVWUreg x:(MOVHUload _ _))
+ // cond:
+ // result: (MOVVreg x)
+ for {
+ x := v.Args[0]
+ if x.Op != OpMIPS64MOVHUload {
+ break
+ }
+ v.reset(OpMIPS64MOVVreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVWUreg x:(MOVWUload _ _))
+ // cond:
+ // result: (MOVVreg x)
+ for {
+ x := v.Args[0]
+ if x.Op != OpMIPS64MOVWUload {
+ break
+ }
+ v.reset(OpMIPS64MOVVreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVWUreg x:(MOVBUreg _))
+ // cond:
+ // result: (MOVVreg x)
+ for {
+ x := v.Args[0]
+ if x.Op != OpMIPS64MOVBUreg {
+ break
+ }
+ v.reset(OpMIPS64MOVVreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVWUreg x:(MOVHUreg _))
+ // cond:
+ // result: (MOVVreg x)
+ for {
+ x := v.Args[0]
+ if x.Op != OpMIPS64MOVHUreg {
+ break
+ }
+ v.reset(OpMIPS64MOVVreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVWUreg x:(MOVWUreg _))
+ // cond:
+ // result: (MOVVreg x)
+ for {
+ x := v.Args[0]
+ if x.Op != OpMIPS64MOVWUreg {
+ break
+ }
+ v.reset(OpMIPS64MOVVreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVWUreg (MOVVconst [c]))
+ // cond:
+ // result: (MOVVconst [int64(uint32(c))])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPS64MOVVconst {
+ break
+ }
+ c := v_0.AuxInt
+ v.reset(OpMIPS64MOVVconst)
+ v.AuxInt = int64(uint32(c))
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS64_OpMIPS64MOVWload(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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_0 := v.Args[0]
+ if v_0.Op != OpMIPS64ADDVconst {
+ break
+ }
+ off2 := v_0.AuxInt
+ ptr := v_0.Args[0]
+ mem := v.Args[1]
+ if !(is32Bit(off1 + off2)) {
+ break
+ }
+ v.reset(OpMIPS64MOVWload)
+ v.AuxInt = off1 + off2
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVWload [off1] {sym1} (MOVVaddr [off2] {sym2} ptr) mem)
+ // cond: canMergeSym(sym1,sym2) && is32Bit(off1+off2)
+ // result: (MOVWload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
+ for {
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPS64MOVVaddr {
+ break
+ }
+ off2 := v_0.AuxInt
+ sym2 := v_0.Aux
+ ptr := v_0.Args[0]
+ mem := v.Args[1]
+ if !(canMergeSym(sym1, sym2) && is32Bit(off1+off2)) {
+ break
+ }
+ v.reset(OpMIPS64MOVWload)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS64_OpMIPS64MOVWreg(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (MOVWreg x:(MOVBload _ _))
+ // cond:
+ // result: (MOVVreg x)
+ for {
+ x := v.Args[0]
+ if x.Op != OpMIPS64MOVBload {
+ break
+ }
+ v.reset(OpMIPS64MOVVreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVWreg x:(MOVBUload _ _))
+ // cond:
+ // result: (MOVVreg x)
+ for {
+ x := v.Args[0]
+ if x.Op != OpMIPS64MOVBUload {
+ break
+ }
+ v.reset(OpMIPS64MOVVreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVWreg x:(MOVHload _ _))
+ // cond:
+ // result: (MOVVreg x)
+ for {
+ x := v.Args[0]
+ if x.Op != OpMIPS64MOVHload {
+ break
+ }
+ v.reset(OpMIPS64MOVVreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVWreg x:(MOVHUload _ _))
+ // cond:
+ // result: (MOVVreg x)
+ for {
+ x := v.Args[0]
+ if x.Op != OpMIPS64MOVHUload {
+ break
+ }
+ v.reset(OpMIPS64MOVVreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVWreg x:(MOVWload _ _))
+ // cond:
+ // result: (MOVVreg x)
+ for {
+ x := v.Args[0]
+ if x.Op != OpMIPS64MOVWload {
+ break
+ }
+ v.reset(OpMIPS64MOVVreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVWreg x:(MOVBreg _))
+ // cond:
+ // result: (MOVVreg x)
+ for {
+ x := v.Args[0]
+ if x.Op != OpMIPS64MOVBreg {
+ break
+ }
+ v.reset(OpMIPS64MOVVreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVWreg x:(MOVBUreg _))
+ // cond:
+ // result: (MOVVreg x)
+ for {
+ x := v.Args[0]
+ if x.Op != OpMIPS64MOVBUreg {
+ break
+ }
+ v.reset(OpMIPS64MOVVreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVWreg x:(MOVHreg _))
+ // cond:
+ // result: (MOVVreg x)
+ for {
+ x := v.Args[0]
+ if x.Op != OpMIPS64MOVHreg {
+ break
+ }
+ v.reset(OpMIPS64MOVVreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVWreg x:(MOVHreg _))
+ // cond:
+ // result: (MOVVreg x)
+ for {
+ x := v.Args[0]
+ if x.Op != OpMIPS64MOVHreg {
+ break
+ }
+ v.reset(OpMIPS64MOVVreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVWreg x:(MOVWreg _))
+ // cond:
+ // result: (MOVVreg x)
+ for {
+ x := v.Args[0]
+ if x.Op != OpMIPS64MOVWreg {
+ break
+ }
+ v.reset(OpMIPS64MOVVreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVWreg (MOVVconst [c]))
+ // cond:
+ // result: (MOVVconst [int64(int32(c))])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPS64MOVVconst {
+ break
+ }
+ c := v_0.AuxInt
+ v.reset(OpMIPS64MOVVconst)
+ v.AuxInt = int64(int32(c))
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS64_OpMIPS64MOVWstore(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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_0 := v.Args[0]
+ if v_0.Op != OpMIPS64ADDVconst {
+ break
+ }
+ off2 := v_0.AuxInt
+ ptr := v_0.Args[0]
+ val := v.Args[1]
+ mem := v.Args[2]
+ if !(is32Bit(off1 + off2)) {
+ break
+ }
+ v.reset(OpMIPS64MOVWstore)
+ v.AuxInt = off1 + off2
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVWstore [off1] {sym1} (MOVVaddr [off2] {sym2} ptr) val mem)
+ // cond: canMergeSym(sym1,sym2) && is32Bit(off1+off2)
+ // result: (MOVWstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
+ for {
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPS64MOVVaddr {
+ 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) && is32Bit(off1+off2)) {
+ break
+ }
+ v.reset(OpMIPS64MOVWstore)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(ptr)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVWstore [off] {sym} ptr (MOVVconst [0]) mem)
+ // cond:
+ // result: (MOVWstorezero [off] {sym} ptr mem)
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpMIPS64MOVVconst {
+ break
+ }
+ if v_1.AuxInt != 0 {
+ break
+ }
+ mem := v.Args[2]
+ v.reset(OpMIPS64MOVWstorezero)
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // 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 != OpMIPS64MOVWreg {
+ break
+ }
+ x := v_1.Args[0]
+ mem := v.Args[2]
+ v.reset(OpMIPS64MOVWstore)
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(x)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVWstore [off] {sym} ptr (MOVWUreg 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 != OpMIPS64MOVWUreg {
+ break
+ }
+ x := v_1.Args[0]
+ mem := v.Args[2]
+ v.reset(OpMIPS64MOVWstore)
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(x)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS64_OpMIPS64MOVWstorezero(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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_0 := v.Args[0]
+ if v_0.Op != OpMIPS64ADDVconst {
+ break
+ }
+ off2 := v_0.AuxInt
+ ptr := v_0.Args[0]
+ mem := v.Args[1]
+ if !(is32Bit(off1 + off2)) {
+ break
+ }
+ v.reset(OpMIPS64MOVWstorezero)
+ v.AuxInt = off1 + off2
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVWstorezero [off1] {sym1} (MOVVaddr [off2] {sym2} ptr) mem)
+ // cond: canMergeSym(sym1,sym2) && is32Bit(off1+off2)
+ // result: (MOVWstorezero [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
+ for {
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPS64MOVVaddr {
+ break
+ }
+ off2 := v_0.AuxInt
+ sym2 := v_0.Aux
+ ptr := v_0.Args[0]
+ mem := v.Args[1]
+ if !(canMergeSym(sym1, sym2) && is32Bit(off1+off2)) {
+ break
+ }
+ v.reset(OpMIPS64MOVWstorezero)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS64_OpMIPS64NEGV(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (NEGV (MOVVconst [c]))
+ // cond:
+ // result: (MOVVconst [-c])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPS64MOVVconst {
+ break
+ }
+ c := v_0.AuxInt
+ v.reset(OpMIPS64MOVVconst)
+ v.AuxInt = -c
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS64_OpMIPS64NOR(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (NOR (MOVVconst [c]) x)
+ // cond: is32Bit(c)
+ // result: (NORconst [c] x)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPS64MOVVconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ if !(is32Bit(c)) {
+ break
+ }
+ v.reset(OpMIPS64NORconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (NOR x (MOVVconst [c]))
+ // cond: is32Bit(c)
+ // result: (NORconst [c] x)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpMIPS64MOVVconst {
+ break
+ }
+ c := v_1.AuxInt
+ if !(is32Bit(c)) {
+ break
+ }
+ v.reset(OpMIPS64NORconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS64_OpMIPS64NORconst(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (NORconst [c] (MOVVconst [d]))
+ // cond:
+ // result: (MOVVconst [^(c|d)])
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPS64MOVVconst {
+ break
+ }
+ d := v_0.AuxInt
+ v.reset(OpMIPS64MOVVconst)
+ v.AuxInt = ^(c | d)
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS64_OpMIPS64OR(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (OR (MOVVconst [c]) x)
+ // cond: is32Bit(c)
+ // result: (ORconst [c] x)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPS64MOVVconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ if !(is32Bit(c)) {
+ break
+ }
+ v.reset(OpMIPS64ORconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (OR x (MOVVconst [c]))
+ // cond: is32Bit(c)
+ // result: (ORconst [c] x)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpMIPS64MOVVconst {
+ break
+ }
+ c := v_1.AuxInt
+ if !(is32Bit(c)) {
+ break
+ }
+ v.reset(OpMIPS64ORconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (OR x x)
+ // cond:
+ // result: x
+ for {
+ x := v.Args[0]
+ if x != v.Args[1] {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS64_OpMIPS64ORconst(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ORconst [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: (ORconst [-1] _)
+ // cond:
+ // result: (MOVVconst [-1])
+ for {
+ if v.AuxInt != -1 {
+ break
+ }
+ v.reset(OpMIPS64MOVVconst)
+ v.AuxInt = -1
+ return true
+ }
+ // match: (ORconst [c] (MOVVconst [d]))
+ // cond:
+ // result: (MOVVconst [c|d])
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPS64MOVVconst {
+ break
+ }
+ d := v_0.AuxInt
+ v.reset(OpMIPS64MOVVconst)
+ v.AuxInt = c | d
+ return true
+ }
+ // match: (ORconst [c] (ORconst [d] x))
+ // cond: is32Bit(c|d)
+ // result: (ORconst [c|d] x)
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPS64ORconst {
+ break
+ }
+ d := v_0.AuxInt
+ x := v_0.Args[0]
+ if !(is32Bit(c | d)) {
+ break
+ }
+ v.reset(OpMIPS64ORconst)
+ v.AuxInt = c | d
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS64_OpMIPS64SGT(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SGT (MOVVconst [c]) x)
+ // cond: is32Bit(c)
+ // result: (SGTconst [c] x)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPS64MOVVconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ if !(is32Bit(c)) {
+ break
+ }
+ v.reset(OpMIPS64SGTconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS64_OpMIPS64SGTU(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SGTU (MOVVconst [c]) x)
+ // cond: is32Bit(c)
+ // result: (SGTUconst [c] x)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPS64MOVVconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ if !(is32Bit(c)) {
+ break
+ }
+ v.reset(OpMIPS64SGTUconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS64_OpMIPS64SGTUconst(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SGTUconst [c] (MOVVconst [d]))
+ // cond: uint64(c)>uint64(d)
+ // result: (MOVVconst [1])
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPS64MOVVconst {
+ break
+ }
+ d := v_0.AuxInt
+ if !(uint64(c) > uint64(d)) {
+ break
+ }
+ v.reset(OpMIPS64MOVVconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (SGTUconst [c] (MOVVconst [d]))
+ // cond: uint64(c)<=uint64(d)
+ // result: (MOVVconst [0])
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPS64MOVVconst {
+ break
+ }
+ d := v_0.AuxInt
+ if !(uint64(c) <= uint64(d)) {
+ break
+ }
+ v.reset(OpMIPS64MOVVconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (SGTUconst [c] (MOVBUreg _))
+ // cond: 0xff < uint64(c)
+ // result: (MOVVconst [1])
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPS64MOVBUreg {
+ break
+ }
+ if !(0xff < uint64(c)) {
+ break
+ }
+ v.reset(OpMIPS64MOVVconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (SGTUconst [c] (MOVHUreg _))
+ // cond: 0xffff < uint64(c)
+ // result: (MOVVconst [1])
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPS64MOVHUreg {
+ break
+ }
+ if !(0xffff < uint64(c)) {
+ break
+ }
+ v.reset(OpMIPS64MOVVconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (SGTUconst [c] (ANDconst [m] _))
+ // cond: uint64(m) < uint64(c)
+ // result: (MOVVconst [1])
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPS64ANDconst {
+ break
+ }
+ m := v_0.AuxInt
+ if !(uint64(m) < uint64(c)) {
+ break
+ }
+ v.reset(OpMIPS64MOVVconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (SGTUconst [c] (SRLVconst _ [d]))
+ // cond: 0 < d && d <= 63 && 1<<uint64(64-d) <= uint64(c)
+ // result: (MOVVconst [1])
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPS64SRLVconst {
+ break
+ }
+ d := v_0.AuxInt
+ if !(0 < d && d <= 63 && 1<<uint64(64-d) <= uint64(c)) {
+ break
+ }
+ v.reset(OpMIPS64MOVVconst)
+ v.AuxInt = 1
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS64_OpMIPS64SGTconst(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SGTconst [c] (MOVVconst [d]))
+ // cond: int64(c)>int64(d)
+ // result: (MOVVconst [1])
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPS64MOVVconst {
+ break
+ }
+ d := v_0.AuxInt
+ if !(int64(c) > int64(d)) {
+ break
+ }
+ v.reset(OpMIPS64MOVVconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (SGTconst [c] (MOVVconst [d]))
+ // cond: int64(c)<=int64(d)
+ // result: (MOVVconst [0])
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPS64MOVVconst {
+ break
+ }
+ d := v_0.AuxInt
+ if !(int64(c) <= int64(d)) {
+ break
+ }
+ v.reset(OpMIPS64MOVVconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (SGTconst [c] (MOVBreg _))
+ // cond: 0x7f < int64(c)
+ // result: (MOVVconst [1])
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPS64MOVBreg {
+ break
+ }
+ if !(0x7f < int64(c)) {
+ break
+ }
+ v.reset(OpMIPS64MOVVconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (SGTconst [c] (MOVBreg _))
+ // cond: int64(c) <= -0x80
+ // result: (MOVVconst [0])
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPS64MOVBreg {
+ break
+ }
+ if !(int64(c) <= -0x80) {
+ break
+ }
+ v.reset(OpMIPS64MOVVconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (SGTconst [c] (MOVBUreg _))
+ // cond: 0xff < int64(c)
+ // result: (MOVVconst [1])
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPS64MOVBUreg {
+ break
+ }
+ if !(0xff < int64(c)) {
+ break
+ }
+ v.reset(OpMIPS64MOVVconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (SGTconst [c] (MOVBUreg _))
+ // cond: int64(c) < 0
+ // result: (MOVVconst [0])
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPS64MOVBUreg {
+ break
+ }
+ if !(int64(c) < 0) {
+ break
+ }
+ v.reset(OpMIPS64MOVVconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (SGTconst [c] (MOVHreg _))
+ // cond: 0x7fff < int64(c)
+ // result: (MOVVconst [1])
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPS64MOVHreg {
+ break
+ }
+ if !(0x7fff < int64(c)) {
+ break
+ }
+ v.reset(OpMIPS64MOVVconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (SGTconst [c] (MOVHreg _))
+ // cond: int64(c) <= -0x8000
+ // result: (MOVVconst [0])
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPS64MOVHreg {
+ break
+ }
+ if !(int64(c) <= -0x8000) {
+ break
+ }
+ v.reset(OpMIPS64MOVVconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (SGTconst [c] (MOVHUreg _))
+ // cond: 0xffff < int64(c)
+ // result: (MOVVconst [1])
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPS64MOVHUreg {
+ break
+ }
+ if !(0xffff < int64(c)) {
+ break
+ }
+ v.reset(OpMIPS64MOVVconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (SGTconst [c] (MOVHUreg _))
+ // cond: int64(c) < 0
+ // result: (MOVVconst [0])
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPS64MOVHUreg {
+ break
+ }
+ if !(int64(c) < 0) {
+ break
+ }
+ v.reset(OpMIPS64MOVVconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (SGTconst [c] (MOVWUreg _))
+ // cond: int64(c) < 0
+ // result: (MOVVconst [0])
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPS64MOVWUreg {
+ break
+ }
+ if !(int64(c) < 0) {
+ break
+ }
+ v.reset(OpMIPS64MOVVconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (SGTconst [c] (ANDconst [m] _))
+ // cond: 0 <= m && m < c
+ // result: (MOVVconst [1])
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPS64ANDconst {
+ break
+ }
+ m := v_0.AuxInt
+ if !(0 <= m && m < c) {
+ break
+ }
+ v.reset(OpMIPS64MOVVconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (SGTconst [c] (SRLVconst _ [d]))
+ // cond: 0 <= c && 0 < d && d <= 63 && 1<<uint64(64-d) <= c
+ // result: (MOVVconst [1])
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPS64SRLVconst {
+ break
+ }
+ d := v_0.AuxInt
+ if !(0 <= c && 0 < d && d <= 63 && 1<<uint64(64-d) <= c) {
+ break
+ }
+ v.reset(OpMIPS64MOVVconst)
+ v.AuxInt = 1
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS64_OpMIPS64SLLV(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SLLV _ (MOVVconst [c]))
+ // cond: uint64(c)>=64
+ // result: (MOVVconst [0])
+ for {
+ v_1 := v.Args[1]
+ if v_1.Op != OpMIPS64MOVVconst {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint64(c) >= 64) {
+ break
+ }
+ v.reset(OpMIPS64MOVVconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (SLLV x (MOVVconst [c]))
+ // cond:
+ // result: (SLLVconst x [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpMIPS64MOVVconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpMIPS64SLLVconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS64_OpMIPS64SLLVconst(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SLLVconst [c] (MOVVconst [d]))
+ // cond:
+ // result: (MOVVconst [int64(d)<<uint64(c)])
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPS64MOVVconst {
+ break
+ }
+ d := v_0.AuxInt
+ v.reset(OpMIPS64MOVVconst)
+ v.AuxInt = int64(d) << uint64(c)
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS64_OpMIPS64SRAV(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SRAV x (MOVVconst [c]))
+ // cond: uint64(c)>=64
+ // result: (SRAVconst x [63])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpMIPS64MOVVconst {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint64(c) >= 64) {
+ break
+ }
+ v.reset(OpMIPS64SRAVconst)
+ v.AuxInt = 63
+ v.AddArg(x)
+ return true
+ }
+ // match: (SRAV x (MOVVconst [c]))
+ // cond:
+ // result: (SRAVconst x [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpMIPS64MOVVconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpMIPS64SRAVconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS64_OpMIPS64SRAVconst(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SRAVconst [c] (MOVVconst [d]))
+ // cond:
+ // result: (MOVVconst [int64(d)>>uint64(c)])
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPS64MOVVconst {
+ break
+ }
+ d := v_0.AuxInt
+ v.reset(OpMIPS64MOVVconst)
+ v.AuxInt = int64(d) >> uint64(c)
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS64_OpMIPS64SRLV(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SRLV _ (MOVVconst [c]))
+ // cond: uint64(c)>=64
+ // result: (MOVVconst [0])
+ for {
+ v_1 := v.Args[1]
+ if v_1.Op != OpMIPS64MOVVconst {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint64(c) >= 64) {
+ break
+ }
+ v.reset(OpMIPS64MOVVconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (SRLV x (MOVVconst [c]))
+ // cond:
+ // result: (SRLVconst x [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpMIPS64MOVVconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpMIPS64SRLVconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS64_OpMIPS64SRLVconst(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SRLVconst [c] (MOVVconst [d]))
+ // cond:
+ // result: (MOVVconst [int64(uint64(d)>>uint64(c))])
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPS64MOVVconst {
+ break
+ }
+ d := v_0.AuxInt
+ v.reset(OpMIPS64MOVVconst)
+ v.AuxInt = int64(uint64(d) >> uint64(c))
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS64_OpMIPS64SUBV(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SUBV x (MOVVconst [c]))
+ // cond: is32Bit(c)
+ // result: (SUBVconst [c] x)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpMIPS64MOVVconst {
+ break
+ }
+ c := v_1.AuxInt
+ if !(is32Bit(c)) {
+ break
+ }
+ v.reset(OpMIPS64SUBVconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (SUBV x x)
+ // cond:
+ // result: (MOVVconst [0])
+ for {
+ x := v.Args[0]
+ if x != v.Args[1] {
+ break
+ }
+ v.reset(OpMIPS64MOVVconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (SUBV (MOVVconst [0]) x)
+ // cond:
+ // result: (NEGV x)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPS64MOVVconst {
+ break
+ }
+ if v_0.AuxInt != 0 {
+ break
+ }
+ x := v.Args[1]
+ v.reset(OpMIPS64NEGV)
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS64_OpMIPS64SUBVconst(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SUBVconst [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: (SUBVconst [c] (MOVVconst [d]))
+ // cond:
+ // result: (MOVVconst [d-c])
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPS64MOVVconst {
+ break
+ }
+ d := v_0.AuxInt
+ v.reset(OpMIPS64MOVVconst)
+ v.AuxInt = d - c
+ return true
+ }
+ // match: (SUBVconst [c] (SUBVconst [d] x))
+ // cond: is32Bit(-c-d)
+ // result: (ADDVconst [-c-d] x)
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPS64SUBVconst {
+ break
+ }
+ d := v_0.AuxInt
+ x := v_0.Args[0]
+ if !(is32Bit(-c - d)) {
+ break
+ }
+ v.reset(OpMIPS64ADDVconst)
+ v.AuxInt = -c - d
+ v.AddArg(x)
+ return true
+ }
+ // match: (SUBVconst [c] (ADDVconst [d] x))
+ // cond: is32Bit(-c+d)
+ // result: (ADDVconst [-c+d] x)
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPS64ADDVconst {
+ break
+ }
+ d := v_0.AuxInt
+ x := v_0.Args[0]
+ if !(is32Bit(-c + d)) {
+ break
+ }
+ v.reset(OpMIPS64ADDVconst)
+ v.AuxInt = -c + d
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS64_OpMIPS64XOR(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (XOR (MOVVconst [c]) x)
+ // cond: is32Bit(c)
+ // result: (XORconst [c] x)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPS64MOVVconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ if !(is32Bit(c)) {
+ break
+ }
+ v.reset(OpMIPS64XORconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (XOR x (MOVVconst [c]))
+ // cond: is32Bit(c)
+ // result: (XORconst [c] x)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpMIPS64MOVVconst {
+ break
+ }
+ c := v_1.AuxInt
+ if !(is32Bit(c)) {
+ break
+ }
+ v.reset(OpMIPS64XORconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (XOR x x)
+ // cond:
+ // result: (MOVVconst [0])
+ for {
+ x := v.Args[0]
+ if x != v.Args[1] {
+ break
+ }
+ v.reset(OpMIPS64MOVVconst)
+ v.AuxInt = 0
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS64_OpMIPS64XORconst(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (XORconst [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: (XORconst [-1] x)
+ // cond:
+ // result: (NORconst [0] x)
+ for {
+ if v.AuxInt != -1 {
+ break
+ }
+ x := v.Args[0]
+ v.reset(OpMIPS64NORconst)
+ v.AuxInt = 0
+ v.AddArg(x)
+ return true
+ }
+ // match: (XORconst [c] (MOVVconst [d]))
+ // cond:
+ // result: (MOVVconst [c^d])
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPS64MOVVconst {
+ break
+ }
+ d := v_0.AuxInt
+ v.reset(OpMIPS64MOVVconst)
+ v.AuxInt = c ^ d
+ return true
+ }
+ // match: (XORconst [c] (XORconst [d] x))
+ // cond: is32Bit(c^d)
+ // result: (XORconst [c^d] x)
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPS64XORconst {
+ break
+ }
+ d := v_0.AuxInt
+ x := v_0.Args[0]
+ if !(is32Bit(c ^ d)) {
+ break
+ }
+ v.reset(OpMIPS64XORconst)
+ v.AuxInt = c ^ d
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS64_OpMod16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Mod16 x y)
+ // cond:
+ // result: (Select0 (DIVV (SignExt16to64 x) (SignExt16to64 y)))
+ for {
+ 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())
+ v1.AddArg(x)
+ v0.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpSignExt16to64, config.fe.TypeInt64())
+ v2.AddArg(y)
+ v0.AddArg(v2)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpMod16u(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Mod16u x y)
+ // cond:
+ // result: (Select0 (DIVVU (ZeroExt16to64 x) (ZeroExt16to64 y)))
+ for {
+ 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())
+ v1.AddArg(x)
+ v0.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+ v2.AddArg(y)
+ v0.AddArg(v2)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpMod32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Mod32 x y)
+ // cond:
+ // result: (Select0 (DIVV (SignExt32to64 x) (SignExt32to64 y)))
+ for {
+ 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())
+ v1.AddArg(x)
+ v0.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpSignExt32to64, config.fe.TypeInt64())
+ v2.AddArg(y)
+ v0.AddArg(v2)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpMod32u(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Mod32u x y)
+ // cond:
+ // result: (Select0 (DIVVU (ZeroExt32to64 x) (ZeroExt32to64 y)))
+ for {
+ 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())
+ v1.AddArg(x)
+ v0.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+ v2.AddArg(y)
+ v0.AddArg(v2)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpMod64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Mod64 x y)
+ // cond:
+ // result: (Select0 (DIVV x y))
+ for {
+ 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.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpMod64u(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Mod64u x y)
+ // cond:
+ // result: (Select0 (DIVVU x y))
+ for {
+ 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.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpMod8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Mod8 x y)
+ // cond:
+ // result: (Select0 (DIVV (SignExt8to64 x) (SignExt8to64 y)))
+ for {
+ 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())
+ v1.AddArg(x)
+ v0.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpSignExt8to64, config.fe.TypeInt64())
+ v2.AddArg(y)
+ v0.AddArg(v2)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpMod8u(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Mod8u x y)
+ // cond:
+ // result: (Select0 (DIVVU (ZeroExt8to64 x) (ZeroExt8to64 y)))
+ for {
+ 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())
+ v1.AddArg(x)
+ v0.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+ v2.AddArg(y)
+ v0.AddArg(v2)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueMIPS64_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) {
+ 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) {
+ break
+ }
+ v.reset(OpMIPS64MOVBstore)
+ v.AddArg(dst)
+ v0 := b.NewValue0(v.Line, OpMIPS64MOVBload, config.fe.TypeInt8())
+ 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
+ // result: (MOVHstore dst (MOVHload src mem) mem)
+ for {
+ s := v.AuxInt
+ 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(OpMIPS64MOVHstore)
+ v.AddArg(dst)
+ v0 := b.NewValue0(v.Line, OpMIPS64MOVHload, config.fe.TypeInt16())
+ 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 (MOVBload [1] src mem) (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() == 2) {
+ break
+ }
+ v.reset(OpMIPS64MOVBstore)
+ v.AuxInt = 1
+ v.AddArg(dst)
+ v0 := b.NewValue0(v.Line, OpMIPS64MOVBload, config.fe.TypeInt8())
+ v0.AuxInt = 1
+ v0.AddArg(src)
+ v0.AddArg(mem)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpMIPS64MOVBstore, TypeMem)
+ v1.AddArg(dst)
+ v2 := b.NewValue0(v.Line, OpMIPS64MOVBload, config.fe.TypeInt8())
+ v2.AddArg(src)
+ v2.AddArg(mem)
+ v1.AddArg(v2)
+ v1.AddArg(mem)
+ v.AddArg(v1)
+ 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)
+ for {
+ s := v.AuxInt
+ dst := v.Args[0]
+ src := v.Args[1]
+ mem := v.Args[2]
+ if !(SizeAndAlign(s).Size() == 4 && SizeAndAlign(s).Align()%4 == 0) {
+ break
+ }
+ v.reset(OpMIPS64MOVWstore)
+ v.AddArg(dst)
+ v0 := b.NewValue0(v.Line, OpMIPS64MOVWload, config.fe.TypeInt32())
+ 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 (MOVHload [2] src mem) (MOVHstore dst (MOVHload src mem) mem))
+ for {
+ s := v.AuxInt
+ 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(OpMIPS64MOVHstore)
+ v.AuxInt = 2
+ v.AddArg(dst)
+ v0 := b.NewValue0(v.Line, OpMIPS64MOVHload, config.fe.TypeInt16())
+ v0.AuxInt = 2
+ v0.AddArg(src)
+ v0.AddArg(mem)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpMIPS64MOVHstore, TypeMem)
+ v1.AddArg(dst)
+ v2 := b.NewValue0(v.Line, OpMIPS64MOVHload, config.fe.TypeInt16())
+ v2.AddArg(src)
+ v2.AddArg(mem)
+ v1.AddArg(v2)
+ v1.AddArg(mem)
+ v.AddArg(v1)
+ return true
+ }
+ // match: (Move [s] dst src mem)
+ // cond: SizeAndAlign(s).Size() == 4
+ // 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
+ 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.AuxInt = 3
+ v0.AddArg(src)
+ v0.AddArg(mem)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpMIPS64MOVBstore, TypeMem)
+ v1.AuxInt = 2
+ v1.AddArg(dst)
+ v2 := b.NewValue0(v.Line, OpMIPS64MOVBload, config.fe.TypeInt8())
+ v2.AuxInt = 2
+ v2.AddArg(src)
+ v2.AddArg(mem)
+ v1.AddArg(v2)
+ v3 := b.NewValue0(v.Line, OpMIPS64MOVBstore, TypeMem)
+ v3.AuxInt = 1
+ v3.AddArg(dst)
+ v4 := b.NewValue0(v.Line, OpMIPS64MOVBload, config.fe.TypeInt8())
+ v4.AuxInt = 1
+ v4.AddArg(src)
+ v4.AddArg(mem)
+ v3.AddArg(v4)
+ v5 := b.NewValue0(v.Line, OpMIPS64MOVBstore, TypeMem)
+ v5.AddArg(dst)
+ v6 := b.NewValue0(v.Line, OpMIPS64MOVBload, config.fe.TypeInt8())
+ v6.AddArg(src)
+ v6.AddArg(mem)
+ v5.AddArg(v6)
+ v5.AddArg(mem)
+ v3.AddArg(v5)
+ v1.AddArg(v3)
+ v.AddArg(v1)
+ return true
+ }
+ // match: (Move [s] dst src mem)
+ // cond: SizeAndAlign(s).Size() == 8 && SizeAndAlign(s).Align()%8 == 0
+ // result: (MOVVstore dst (MOVVload 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) {
+ break
+ }
+ v.reset(OpMIPS64MOVVstore)
+ v.AddArg(dst)
+ v0 := b.NewValue0(v.Line, OpMIPS64MOVVload, 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() == 8 && SizeAndAlign(s).Align()%4 == 0
+ // result: (MOVWstore [4] dst (MOVWload [4] 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() == 8 && SizeAndAlign(s).Align()%4 == 0) {
+ break
+ }
+ v.reset(OpMIPS64MOVWstore)
+ v.AuxInt = 4
+ v.AddArg(dst)
+ v0 := b.NewValue0(v.Line, OpMIPS64MOVWload, config.fe.TypeInt32())
+ v0.AuxInt = 4
+ v0.AddArg(src)
+ v0.AddArg(mem)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpMIPS64MOVWstore, TypeMem)
+ v1.AddArg(dst)
+ v2 := b.NewValue0(v.Line, OpMIPS64MOVWload, config.fe.TypeInt32())
+ v2.AddArg(src)
+ v2.AddArg(mem)
+ v1.AddArg(v2)
+ v1.AddArg(mem)
+ 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 (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
+ 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(OpMIPS64MOVHstore)
+ v.AuxInt = 6
+ v.AddArg(dst)
+ v0 := b.NewValue0(v.Line, OpMIPS64MOVHload, config.fe.TypeInt16())
+ v0.AuxInt = 6
+ v0.AddArg(src)
+ v0.AddArg(mem)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpMIPS64MOVHstore, TypeMem)
+ v1.AuxInt = 4
+ v1.AddArg(dst)
+ v2 := b.NewValue0(v.Line, OpMIPS64MOVHload, config.fe.TypeInt16())
+ v2.AuxInt = 4
+ v2.AddArg(src)
+ v2.AddArg(mem)
+ v1.AddArg(v2)
+ v3 := b.NewValue0(v.Line, OpMIPS64MOVHstore, TypeMem)
+ v3.AuxInt = 2
+ v3.AddArg(dst)
+ v4 := b.NewValue0(v.Line, OpMIPS64MOVHload, config.fe.TypeInt16())
+ v4.AuxInt = 2
+ v4.AddArg(src)
+ v4.AddArg(mem)
+ v3.AddArg(v4)
+ v5 := b.NewValue0(v.Line, OpMIPS64MOVHstore, TypeMem)
+ v5.AddArg(dst)
+ v6 := b.NewValue0(v.Line, OpMIPS64MOVHload, config.fe.TypeInt16())
+ v6.AddArg(src)
+ v6.AddArg(mem)
+ v5.AddArg(v6)
+ v5.AddArg(mem)
+ v3.AddArg(v5)
+ v1.AddArg(v3)
+ v.AddArg(v1)
+ return true
+ }
+ // match: (Move [s] dst src mem)
+ // cond: SizeAndAlign(s).Size() == 3
+ // 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
+ 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.AuxInt = 2
+ v0.AddArg(src)
+ v0.AddArg(mem)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpMIPS64MOVBstore, TypeMem)
+ v1.AuxInt = 1
+ v1.AddArg(dst)
+ v2 := b.NewValue0(v.Line, OpMIPS64MOVBload, config.fe.TypeInt8())
+ v2.AuxInt = 1
+ v2.AddArg(src)
+ v2.AddArg(mem)
+ v1.AddArg(v2)
+ v3 := b.NewValue0(v.Line, OpMIPS64MOVBstore, TypeMem)
+ v3.AddArg(dst)
+ v4 := b.NewValue0(v.Line, OpMIPS64MOVBload, config.fe.TypeInt8())
+ v4.AddArg(src)
+ v4.AddArg(mem)
+ v3.AddArg(v4)
+ v3.AddArg(mem)
+ v1.AddArg(v3)
+ v.AddArg(v1)
+ return true
+ }
+ // match: (Move [s] dst src mem)
+ // cond: SizeAndAlign(s).Size() == 6 && SizeAndAlign(s).Align()%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
+ dst := v.Args[0]
+ src := v.Args[1]
+ mem := v.Args[2]
+ if !(SizeAndAlign(s).Size() == 6 && SizeAndAlign(s).Align()%2 == 0) {
+ break
+ }
+ v.reset(OpMIPS64MOVHstore)
+ v.AuxInt = 4
+ v.AddArg(dst)
+ v0 := b.NewValue0(v.Line, OpMIPS64MOVHload, config.fe.TypeInt16())
+ v0.AuxInt = 4
+ v0.AddArg(src)
+ v0.AddArg(mem)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpMIPS64MOVHstore, TypeMem)
+ v1.AuxInt = 2
+ v1.AddArg(dst)
+ v2 := b.NewValue0(v.Line, OpMIPS64MOVHload, config.fe.TypeInt16())
+ v2.AuxInt = 2
+ v2.AddArg(src)
+ v2.AddArg(mem)
+ v1.AddArg(v2)
+ v3 := b.NewValue0(v.Line, OpMIPS64MOVHstore, TypeMem)
+ v3.AddArg(dst)
+ v4 := b.NewValue0(v.Line, OpMIPS64MOVHload, config.fe.TypeInt16())
+ v4.AddArg(src)
+ v4.AddArg(mem)
+ v3.AddArg(v4)
+ v3.AddArg(mem)
+ v1.AddArg(v3)
+ v.AddArg(v1)
+ return true
+ }
+ // match: (Move [s] dst src mem)
+ // cond: SizeAndAlign(s).Size() == 12 && SizeAndAlign(s).Align()%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
+ dst := v.Args[0]
+ src := v.Args[1]
+ mem := v.Args[2]
+ if !(SizeAndAlign(s).Size() == 12 && SizeAndAlign(s).Align()%4 == 0) {
+ break
+ }
+ v.reset(OpMIPS64MOVWstore)
+ v.AuxInt = 8
+ v.AddArg(dst)
+ v0 := b.NewValue0(v.Line, OpMIPS64MOVWload, config.fe.TypeInt32())
+ v0.AuxInt = 8
+ v0.AddArg(src)
+ v0.AddArg(mem)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpMIPS64MOVWstore, TypeMem)
+ v1.AuxInt = 4
+ v1.AddArg(dst)
+ v2 := b.NewValue0(v.Line, OpMIPS64MOVWload, config.fe.TypeInt32())
+ v2.AuxInt = 4
+ v2.AddArg(src)
+ v2.AddArg(mem)
+ v1.AddArg(v2)
+ v3 := b.NewValue0(v.Line, OpMIPS64MOVWstore, TypeMem)
+ v3.AddArg(dst)
+ v4 := b.NewValue0(v.Line, OpMIPS64MOVWload, config.fe.TypeInt32())
+ v4.AddArg(src)
+ v4.AddArg(mem)
+ v3.AddArg(v4)
+ v3.AddArg(mem)
+ v1.AddArg(v3)
+ v.AddArg(v1)
+ return true
+ }
+ // match: (Move [s] dst src mem)
+ // cond: SizeAndAlign(s).Size() == 16 && SizeAndAlign(s).Align()%8 == 0
+ // result: (MOVVstore [8] dst (MOVVload [8] src mem) (MOVVstore dst (MOVVload src mem) mem))
+ for {
+ s := v.AuxInt
+ dst := v.Args[0]
+ src := v.Args[1]
+ mem := v.Args[2]
+ if !(SizeAndAlign(s).Size() == 16 && SizeAndAlign(s).Align()%8 == 0) {
+ break
+ }
+ v.reset(OpMIPS64MOVVstore)
+ v.AuxInt = 8
+ v.AddArg(dst)
+ v0 := b.NewValue0(v.Line, OpMIPS64MOVVload, config.fe.TypeUInt64())
+ v0.AuxInt = 8
+ v0.AddArg(src)
+ v0.AddArg(mem)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpMIPS64MOVVstore, TypeMem)
+ v1.AddArg(dst)
+ v2 := b.NewValue0(v.Line, OpMIPS64MOVVload, config.fe.TypeUInt64())
+ v2.AddArg(src)
+ v2.AddArg(mem)
+ v1.AddArg(v2)
+ v1.AddArg(mem)
+ v.AddArg(v1)
+ return true
+ }
+ // match: (Move [s] dst src mem)
+ // cond: SizeAndAlign(s).Size() == 24 && SizeAndAlign(s).Align()%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
+ dst := v.Args[0]
+ src := v.Args[1]
+ mem := v.Args[2]
+ if !(SizeAndAlign(s).Size() == 24 && SizeAndAlign(s).Align()%8 == 0) {
+ break
+ }
+ v.reset(OpMIPS64MOVVstore)
+ v.AuxInt = 16
+ v.AddArg(dst)
+ v0 := b.NewValue0(v.Line, OpMIPS64MOVVload, config.fe.TypeUInt64())
+ v0.AuxInt = 16
+ v0.AddArg(src)
+ v0.AddArg(mem)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpMIPS64MOVVstore, TypeMem)
+ v1.AuxInt = 8
+ v1.AddArg(dst)
+ v2 := b.NewValue0(v.Line, OpMIPS64MOVVload, config.fe.TypeUInt64())
+ v2.AuxInt = 8
+ v2.AddArg(src)
+ v2.AddArg(mem)
+ v1.AddArg(v2)
+ v3 := b.NewValue0(v.Line, OpMIPS64MOVVstore, TypeMem)
+ v3.AddArg(dst)
+ v4 := b.NewValue0(v.Line, OpMIPS64MOVVload, config.fe.TypeUInt64())
+ v4.AddArg(src)
+ v4.AddArg(mem)
+ v3.AddArg(v4)
+ v3.AddArg(mem)
+ v1.AddArg(v3)
+ 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)
+ for {
+ s := v.AuxInt
+ dst := v.Args[0]
+ src := v.Args[1]
+ mem := v.Args[2]
+ if !(SizeAndAlign(s).Size() > 24 || SizeAndAlign(s).Align()%8 != 0) {
+ break
+ }
+ v.reset(OpMIPS64LoweredMove)
+ v.AuxInt = SizeAndAlign(s).Align()
+ 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.AddArg(src)
+ v.AddArg(v0)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS64_OpMul16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Mul16 x y)
+ // cond:
+ // result: (Select1 (MULVU x y))
+ for {
+ 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.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpMul32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Mul32 x y)
+ // cond:
+ // result: (Select1 (MULVU x y))
+ for {
+ 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.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpMul32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Mul32F x y)
+ // cond:
+ // result: (MULF x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPS64MULF)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpMul64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Mul64 x y)
+ // cond:
+ // result: (Select1 (MULVU x y))
+ for {
+ 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.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpMul64F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Mul64F x y)
+ // cond:
+ // result: (MULD x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPS64MULD)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpMul8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Mul8 x y)
+ // cond:
+ // result: (Select1 (MULVU x y))
+ for {
+ 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.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpNeg16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Neg16 x)
+ // cond:
+ // result: (NEGV x)
+ for {
+ x := v.Args[0]
+ v.reset(OpMIPS64NEGV)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpNeg32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Neg32 x)
+ // cond:
+ // result: (NEGV x)
+ for {
+ x := v.Args[0]
+ v.reset(OpMIPS64NEGV)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpNeg32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Neg32F x)
+ // cond:
+ // result: (NEGF x)
+ for {
+ x := v.Args[0]
+ v.reset(OpMIPS64NEGF)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpNeg64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Neg64 x)
+ // cond:
+ // result: (NEGV x)
+ for {
+ x := v.Args[0]
+ v.reset(OpMIPS64NEGV)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpNeg64F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Neg64F x)
+ // cond:
+ // result: (NEGD x)
+ for {
+ x := v.Args[0]
+ v.reset(OpMIPS64NEGD)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpNeg8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Neg8 x)
+ // cond:
+ // result: (NEGV x)
+ for {
+ x := v.Args[0]
+ v.reset(OpMIPS64NEGV)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpNeq16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Neq16 x y)
+ // cond:
+ // result: (SGTU (XOR (ZeroExt16to32 x) (ZeroExt16to64 y)) (MOVVconst [0]))
+ for {
+ 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())
+ v1.AddArg(x)
+ v0.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+ v2.AddArg(y)
+ v0.AddArg(v2)
+ v.AddArg(v0)
+ v3 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+ v3.AuxInt = 0
+ v.AddArg(v3)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpNeq32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Neq32 x y)
+ // cond:
+ // result: (SGTU (XOR (ZeroExt32to64 x) (ZeroExt32to64 y)) (MOVVconst [0]))
+ for {
+ 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())
+ v1.AddArg(x)
+ v0.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+ v2.AddArg(y)
+ v0.AddArg(v2)
+ v.AddArg(v0)
+ v3 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+ v3.AuxInt = 0
+ v.AddArg(v3)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpNeq32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Neq32F x y)
+ // cond:
+ // result: (FPFlagFalse (CMPEQF x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPS64FPFlagFalse)
+ v0 := b.NewValue0(v.Line, OpMIPS64CMPEQF, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpNeq64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Neq64 x y)
+ // cond:
+ // result: (SGTU (XOR x y) (MOVVconst [0]))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPS64SGTU)
+ v0 := b.NewValue0(v.Line, OpMIPS64XOR, config.fe.TypeUInt64())
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+ v1.AuxInt = 0
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpNeq64F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Neq64F x y)
+ // cond:
+ // result: (FPFlagFalse (CMPEQD x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPS64FPFlagFalse)
+ v0 := b.NewValue0(v.Line, OpMIPS64CMPEQD, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpNeq8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Neq8 x y)
+ // cond:
+ // result: (SGTU (XOR (ZeroExt8to64 x) (ZeroExt8to64 y)) (MOVVconst [0]))
+ for {
+ 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())
+ v1.AddArg(x)
+ v0.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+ v2.AddArg(y)
+ v0.AddArg(v2)
+ v.AddArg(v0)
+ v3 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+ v3.AuxInt = 0
+ v.AddArg(v3)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpNeqB(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (NeqB x y)
+ // cond:
+ // result: (XOR x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPS64XOR)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpNeqPtr(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (NeqPtr x y)
+ // cond:
+ // result: (SGTU (XOR x y) (MOVVconst [0]))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPS64SGTU)
+ v0 := b.NewValue0(v.Line, OpMIPS64XOR, config.fe.TypeUInt64())
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+ v1.AuxInt = 0
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueMIPS64_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(OpMIPS64LoweredNilCheck)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpNot(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Not x)
+ // cond:
+ // result: (XORconst [1] x)
+ for {
+ x := v.Args[0]
+ v.reset(OpMIPS64XORconst)
+ v.AuxInt = 1
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpOffPtr(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (OffPtr [off] ptr:(SP))
+ // cond:
+ // result: (MOVVaddr [off] ptr)
+ for {
+ off := v.AuxInt
+ ptr := v.Args[0]
+ if ptr.Op != OpSP {
+ break
+ }
+ v.reset(OpMIPS64MOVVaddr)
+ v.AuxInt = off
+ v.AddArg(ptr)
+ return true
+ }
+ // match: (OffPtr [off] ptr)
+ // cond:
+ // result: (ADDVconst [off] ptr)
+ for {
+ off := v.AuxInt
+ ptr := v.Args[0]
+ v.reset(OpMIPS64ADDVconst)
+ v.AuxInt = off
+ v.AddArg(ptr)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpOr16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Or16 x y)
+ // cond:
+ // result: (OR x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPS64OR)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpOr32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Or32 x y)
+ // cond:
+ // result: (OR x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPS64OR)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpOr64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Or64 x y)
+ // cond:
+ // result: (OR x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPS64OR)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpOr8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Or8 x y)
+ // cond:
+ // result: (OR x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPS64OR)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpOrB(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (OrB x y)
+ // cond:
+ // result: (OR x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPS64OR)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpRsh16Ux16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh16Ux16 <t> x y)
+ // cond:
+ // result: (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt16to64 y))) (SRLV <t> (ZeroExt16to64 x) (ZeroExt16to64 y)))
+ 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
+ }
+}
+func rewriteValueMIPS64_OpRsh16Ux32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh16Ux32 <t> x y)
+ // cond:
+ // result: (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt32to64 y))) (SRLV <t> (ZeroExt16to64 x) (ZeroExt32to64 y)))
+ 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, OpZeroExt32to64, 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, OpZeroExt32to64, config.fe.TypeUInt64())
+ v6.AddArg(y)
+ v4.AddArg(v6)
+ v.AddArg(v4)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpRsh16Ux64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh16Ux64 <t> x y)
+ // cond:
+ // result: (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) y)) (SRLV <t> (ZeroExt16to64 x) y))
+ 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)
+ 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())
+ v4.AddArg(x)
+ v3.AddArg(v4)
+ v3.AddArg(y)
+ v.AddArg(v3)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpRsh16Ux8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh16Ux8 <t> x y)
+ // cond:
+ // result: (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt8to64 y))) (SRLV <t> (ZeroExt16to64 x) (ZeroExt8to64 y)))
+ 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, OpZeroExt8to64, 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, OpZeroExt8to64, config.fe.TypeUInt64())
+ v6.AddArg(y)
+ v4.AddArg(v6)
+ v.AddArg(v4)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpRsh16x16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh16x16 <t> x y)
+ // cond:
+ // result: (SRAV (SignExt16to64 x) (OR <t> (NEGV <t> (SGTU (ZeroExt16to64 y) (Const64 <config.fe.TypeUInt64()> [63]))) (ZeroExt16to64 y)))
+ for {
+ t := v.Type
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPS64SRAV)
+ v0 := b.NewValue0(v.Line, OpSignExt16to64, config.fe.TypeInt64())
+ 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())
+ v4.AddArg(y)
+ v3.AddArg(v4)
+ v5 := b.NewValue0(v.Line, OpConst64, config.fe.TypeUInt64())
+ v5.AuxInt = 63
+ v3.AddArg(v5)
+ v2.AddArg(v3)
+ v1.AddArg(v2)
+ v6 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+ v6.AddArg(y)
+ v1.AddArg(v6)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpRsh16x32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh16x32 <t> x y)
+ // cond:
+ // result: (SRAV (SignExt16to64 x) (OR <t> (NEGV <t> (SGTU (ZeroExt32to64 y) (Const64 <config.fe.TypeUInt64()> [63]))) (ZeroExt32to64 y)))
+ for {
+ t := v.Type
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPS64SRAV)
+ v0 := b.NewValue0(v.Line, OpSignExt16to64, config.fe.TypeInt64())
+ 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())
+ v4.AddArg(y)
+ v3.AddArg(v4)
+ v5 := b.NewValue0(v.Line, OpConst64, config.fe.TypeUInt64())
+ v5.AuxInt = 63
+ v3.AddArg(v5)
+ v2.AddArg(v3)
+ v1.AddArg(v2)
+ v6 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+ v6.AddArg(y)
+ v1.AddArg(v6)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpRsh16x64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh16x64 <t> x y)
+ // cond:
+ // result: (SRAV (SignExt16to64 x) (OR <t> (NEGV <t> (SGTU y (Const64 <config.fe.TypeUInt64()> [63]))) y))
+ for {
+ t := v.Type
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPS64SRAV)
+ v0 := b.NewValue0(v.Line, OpSignExt16to64, config.fe.TypeInt64())
+ 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())
+ v3.AddArg(y)
+ v4 := b.NewValue0(v.Line, OpConst64, config.fe.TypeUInt64())
+ v4.AuxInt = 63
+ v3.AddArg(v4)
+ v2.AddArg(v3)
+ v1.AddArg(v2)
+ v1.AddArg(y)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpRsh16x8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh16x8 <t> x y)
+ // cond:
+ // result: (SRAV (SignExt16to64 x) (OR <t> (NEGV <t> (SGTU (ZeroExt8to64 y) (Const64 <config.fe.TypeUInt64()> [63]))) (ZeroExt8to64 y)))
+ for {
+ t := v.Type
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPS64SRAV)
+ v0 := b.NewValue0(v.Line, OpSignExt16to64, config.fe.TypeInt64())
+ 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())
+ v4.AddArg(y)
+ v3.AddArg(v4)
+ v5 := b.NewValue0(v.Line, OpConst64, config.fe.TypeUInt64())
+ v5.AuxInt = 63
+ v3.AddArg(v5)
+ v2.AddArg(v3)
+ v1.AddArg(v2)
+ v6 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+ v6.AddArg(y)
+ v1.AddArg(v6)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpRsh32Ux16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh32Ux16 <t> x y)
+ // cond:
+ // result: (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt16to64 y))) (SRLV <t> (ZeroExt32to64 x) (ZeroExt16to64 y)))
+ 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, OpZeroExt32to64, 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
+ }
+}
+func rewriteValueMIPS64_OpRsh32Ux32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh32Ux32 <t> x y)
+ // cond:
+ // result: (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt32to64 y))) (SRLV <t> (ZeroExt32to64 x) (ZeroExt32to64 y)))
+ 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, OpZeroExt32to64, 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, OpZeroExt32to64, config.fe.TypeUInt64())
+ v5.AddArg(x)
+ v4.AddArg(v5)
+ v6 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+ v6.AddArg(y)
+ v4.AddArg(v6)
+ v.AddArg(v4)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpRsh32Ux64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh32Ux64 <t> x y)
+ // cond:
+ // result: (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) y)) (SRLV <t> (ZeroExt32to64 x) y))
+ 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)
+ 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())
+ v4.AddArg(x)
+ v3.AddArg(v4)
+ v3.AddArg(y)
+ v.AddArg(v3)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpRsh32Ux8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh32Ux8 <t> x y)
+ // cond:
+ // result: (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt8to64 y))) (SRLV <t> (ZeroExt32to64 x) (ZeroExt8to64 y)))
+ 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, OpZeroExt8to64, 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, OpZeroExt32to64, config.fe.TypeUInt64())
+ v5.AddArg(x)
+ v4.AddArg(v5)
+ v6 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+ v6.AddArg(y)
+ v4.AddArg(v6)
+ v.AddArg(v4)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpRsh32x16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh32x16 <t> x y)
+ // cond:
+ // result: (SRAV (SignExt32to64 x) (OR <t> (NEGV <t> (SGTU (ZeroExt16to64 y) (Const64 <config.fe.TypeUInt64()> [63]))) (ZeroExt16to64 y)))
+ for {
+ t := v.Type
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPS64SRAV)
+ v0 := b.NewValue0(v.Line, OpSignExt32to64, config.fe.TypeInt64())
+ 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())
+ v4.AddArg(y)
+ v3.AddArg(v4)
+ v5 := b.NewValue0(v.Line, OpConst64, config.fe.TypeUInt64())
+ v5.AuxInt = 63
+ v3.AddArg(v5)
+ v2.AddArg(v3)
+ v1.AddArg(v2)
+ v6 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+ v6.AddArg(y)
+ v1.AddArg(v6)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpRsh32x32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh32x32 <t> x y)
+ // cond:
+ // result: (SRAV (SignExt32to64 x) (OR <t> (NEGV <t> (SGTU (ZeroExt32to64 y) (Const64 <config.fe.TypeUInt64()> [63]))) (ZeroExt32to64 y)))
+ for {
+ t := v.Type
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPS64SRAV)
+ v0 := b.NewValue0(v.Line, OpSignExt32to64, config.fe.TypeInt64())
+ 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())
+ v4.AddArg(y)
+ v3.AddArg(v4)
+ v5 := b.NewValue0(v.Line, OpConst64, config.fe.TypeUInt64())
+ v5.AuxInt = 63
+ v3.AddArg(v5)
+ v2.AddArg(v3)
+ v1.AddArg(v2)
+ v6 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+ v6.AddArg(y)
+ v1.AddArg(v6)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpRsh32x64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh32x64 <t> x y)
+ // cond:
+ // result: (SRAV (SignExt32to64 x) (OR <t> (NEGV <t> (SGTU y (Const64 <config.fe.TypeUInt64()> [63]))) y))
+ for {
+ t := v.Type
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPS64SRAV)
+ v0 := b.NewValue0(v.Line, OpSignExt32to64, config.fe.TypeInt64())
+ 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())
+ v3.AddArg(y)
+ v4 := b.NewValue0(v.Line, OpConst64, config.fe.TypeUInt64())
+ v4.AuxInt = 63
+ v3.AddArg(v4)
+ v2.AddArg(v3)
+ v1.AddArg(v2)
+ v1.AddArg(y)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpRsh32x8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh32x8 <t> x y)
+ // cond:
+ // result: (SRAV (SignExt32to64 x) (OR <t> (NEGV <t> (SGTU (ZeroExt8to64 y) (Const64 <config.fe.TypeUInt64()> [63]))) (ZeroExt8to64 y)))
+ for {
+ t := v.Type
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPS64SRAV)
+ v0 := b.NewValue0(v.Line, OpSignExt32to64, config.fe.TypeInt64())
+ 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())
+ v4.AddArg(y)
+ v3.AddArg(v4)
+ v5 := b.NewValue0(v.Line, OpConst64, config.fe.TypeUInt64())
+ v5.AuxInt = 63
+ v3.AddArg(v5)
+ v2.AddArg(v3)
+ v1.AddArg(v2)
+ v6 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+ v6.AddArg(y)
+ v1.AddArg(v6)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpRsh64Ux16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh64Ux16 <t> x y)
+ // cond:
+ // result: (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt16to64 y))) (SRLV <t> x (ZeroExt16to64 y)))
+ 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)
+ v4.AddArg(x)
+ v5 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+ v5.AddArg(y)
+ v4.AddArg(v5)
+ v.AddArg(v4)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpRsh64Ux32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh64Ux32 <t> x y)
+ // cond:
+ // result: (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt32to64 y))) (SRLV <t> x (ZeroExt32to64 y)))
+ 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, OpZeroExt32to64, config.fe.TypeUInt64())
+ v3.AddArg(y)
+ v1.AddArg(v3)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ v4 := b.NewValue0(v.Line, OpMIPS64SRLV, t)
+ v4.AddArg(x)
+ v5 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+ v5.AddArg(y)
+ v4.AddArg(v5)
+ v.AddArg(v4)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpRsh64Ux64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh64Ux64 <t> x y)
+ // cond:
+ // result: (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) y)) (SRLV <t> x y))
+ 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)
+ v1.AddArg(y)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ v3 := b.NewValue0(v.Line, OpMIPS64SRLV, t)
+ v3.AddArg(x)
+ v3.AddArg(y)
+ v.AddArg(v3)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpRsh64Ux8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh64Ux8 <t> x y)
+ // cond:
+ // result: (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt8to64 y))) (SRLV <t> x (ZeroExt8to64 y)))
+ 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, OpZeroExt8to64, config.fe.TypeUInt64())
+ v3.AddArg(y)
+ v1.AddArg(v3)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ v4 := b.NewValue0(v.Line, OpMIPS64SRLV, t)
+ v4.AddArg(x)
+ v5 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+ v5.AddArg(y)
+ v4.AddArg(v5)
+ v.AddArg(v4)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpRsh64x16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh64x16 <t> x y)
+ // cond:
+ // result: (SRAV x (OR <t> (NEGV <t> (SGTU (ZeroExt16to64 y) (Const64 <config.fe.TypeUInt64()> [63]))) (ZeroExt16to64 y)))
+ for {
+ t := v.Type
+ 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())
+ v3.AddArg(y)
+ v2.AddArg(v3)
+ v4 := b.NewValue0(v.Line, OpConst64, config.fe.TypeUInt64())
+ v4.AuxInt = 63
+ v2.AddArg(v4)
+ v1.AddArg(v2)
+ v0.AddArg(v1)
+ v5 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+ v5.AddArg(y)
+ v0.AddArg(v5)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpRsh64x32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh64x32 <t> x y)
+ // cond:
+ // result: (SRAV x (OR <t> (NEGV <t> (SGTU (ZeroExt32to64 y) (Const64 <config.fe.TypeUInt64()> [63]))) (ZeroExt32to64 y)))
+ for {
+ t := v.Type
+ 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())
+ v3.AddArg(y)
+ v2.AddArg(v3)
+ v4 := b.NewValue0(v.Line, OpConst64, config.fe.TypeUInt64())
+ v4.AuxInt = 63
+ v2.AddArg(v4)
+ v1.AddArg(v2)
+ v0.AddArg(v1)
+ v5 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+ v5.AddArg(y)
+ v0.AddArg(v5)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpRsh64x64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh64x64 <t> x y)
+ // cond:
+ // result: (SRAV x (OR <t> (NEGV <t> (SGTU y (Const64 <config.fe.TypeUInt64()> [63]))) y))
+ for {
+ t := v.Type
+ 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())
+ v2.AddArg(y)
+ v3 := b.NewValue0(v.Line, OpConst64, config.fe.TypeUInt64())
+ v3.AuxInt = 63
+ v2.AddArg(v3)
+ v1.AddArg(v2)
+ v0.AddArg(v1)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpRsh64x8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh64x8 <t> x y)
+ // cond:
+ // result: (SRAV x (OR <t> (NEGV <t> (SGTU (ZeroExt8to64 y) (Const64 <config.fe.TypeUInt64()> [63]))) (ZeroExt8to64 y)))
+ for {
+ t := v.Type
+ 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())
+ v3.AddArg(y)
+ v2.AddArg(v3)
+ v4 := b.NewValue0(v.Line, OpConst64, config.fe.TypeUInt64())
+ v4.AuxInt = 63
+ v2.AddArg(v4)
+ v1.AddArg(v2)
+ v0.AddArg(v1)
+ v5 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+ v5.AddArg(y)
+ v0.AddArg(v5)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpRsh8Ux16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh8Ux16 <t> x y)
+ // cond:
+ // result: (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt16to64 y))) (SRLV <t> (ZeroExt8to64 x) (ZeroExt16to64 y)))
+ 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, OpZeroExt8to64, 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
+ }
+}
+func rewriteValueMIPS64_OpRsh8Ux32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh8Ux32 <t> x y)
+ // cond:
+ // result: (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt32to64 y))) (SRLV <t> (ZeroExt8to64 x) (ZeroExt32to64 y)))
+ 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, OpZeroExt32to64, 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, OpZeroExt8to64, config.fe.TypeUInt64())
+ v5.AddArg(x)
+ v4.AddArg(v5)
+ v6 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+ v6.AddArg(y)
+ v4.AddArg(v6)
+ v.AddArg(v4)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpRsh8Ux64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh8Ux64 <t> x y)
+ // cond:
+ // result: (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) y)) (SRLV <t> (ZeroExt8to64 x) y))
+ 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)
+ 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())
+ v4.AddArg(x)
+ v3.AddArg(v4)
+ v3.AddArg(y)
+ v.AddArg(v3)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpRsh8Ux8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh8Ux8 <t> x y)
+ // cond:
+ // result: (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt8to64 y))) (SRLV <t> (ZeroExt8to64 x) (ZeroExt8to64 y)))
+ 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, OpZeroExt8to64, 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, OpZeroExt8to64, config.fe.TypeUInt64())
+ v5.AddArg(x)
+ v4.AddArg(v5)
+ v6 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+ v6.AddArg(y)
+ v4.AddArg(v6)
+ v.AddArg(v4)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpRsh8x16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh8x16 <t> x y)
+ // cond:
+ // result: (SRAV (SignExt8to64 x) (OR <t> (NEGV <t> (SGTU (ZeroExt16to64 y) (Const64 <config.fe.TypeUInt64()> [63]))) (ZeroExt16to64 y)))
+ for {
+ t := v.Type
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPS64SRAV)
+ v0 := b.NewValue0(v.Line, OpSignExt8to64, config.fe.TypeInt64())
+ 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())
+ v4.AddArg(y)
+ v3.AddArg(v4)
+ v5 := b.NewValue0(v.Line, OpConst64, config.fe.TypeUInt64())
+ v5.AuxInt = 63
+ v3.AddArg(v5)
+ v2.AddArg(v3)
+ v1.AddArg(v2)
+ v6 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+ v6.AddArg(y)
+ v1.AddArg(v6)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpRsh8x32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh8x32 <t> x y)
+ // cond:
+ // result: (SRAV (SignExt8to64 x) (OR <t> (NEGV <t> (SGTU (ZeroExt32to64 y) (Const64 <config.fe.TypeUInt64()> [63]))) (ZeroExt32to64 y)))
+ for {
+ t := v.Type
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPS64SRAV)
+ v0 := b.NewValue0(v.Line, OpSignExt8to64, config.fe.TypeInt64())
+ 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())
+ v4.AddArg(y)
+ v3.AddArg(v4)
+ v5 := b.NewValue0(v.Line, OpConst64, config.fe.TypeUInt64())
+ v5.AuxInt = 63
+ v3.AddArg(v5)
+ v2.AddArg(v3)
+ v1.AddArg(v2)
+ v6 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+ v6.AddArg(y)
+ v1.AddArg(v6)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpRsh8x64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh8x64 <t> x y)
+ // cond:
+ // result: (SRAV (SignExt8to64 x) (OR <t> (NEGV <t> (SGTU y (Const64 <config.fe.TypeUInt64()> [63]))) y))
+ for {
+ t := v.Type
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPS64SRAV)
+ v0 := b.NewValue0(v.Line, OpSignExt8to64, config.fe.TypeInt64())
+ 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())
+ v3.AddArg(y)
+ v4 := b.NewValue0(v.Line, OpConst64, config.fe.TypeUInt64())
+ v4.AuxInt = 63
+ v3.AddArg(v4)
+ v2.AddArg(v3)
+ v1.AddArg(v2)
+ v1.AddArg(y)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpRsh8x8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh8x8 <t> x y)
+ // cond:
+ // result: (SRAV (SignExt8to64 x) (OR <t> (NEGV <t> (SGTU (ZeroExt8to64 y) (Const64 <config.fe.TypeUInt64()> [63]))) (ZeroExt8to64 y)))
+ for {
+ t := v.Type
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPS64SRAV)
+ v0 := b.NewValue0(v.Line, OpSignExt8to64, config.fe.TypeInt64())
+ 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())
+ v4.AddArg(y)
+ v3.AddArg(v4)
+ v5 := b.NewValue0(v.Line, OpConst64, config.fe.TypeUInt64())
+ v5.AuxInt = 63
+ v3.AddArg(v5)
+ v2.AddArg(v3)
+ v1.AddArg(v2)
+ v6 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+ v6.AddArg(y)
+ v1.AddArg(v6)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpSelect0(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Select0 (DIVVU _ (MOVVconst [1])))
+ // cond:
+ // result: (MOVVconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPS64DIVVU {
+ break
+ }
+ v_0_1 := v_0.Args[1]
+ if v_0_1.Op != OpMIPS64MOVVconst {
+ break
+ }
+ if v_0_1.AuxInt != 1 {
+ break
+ }
+ v.reset(OpMIPS64MOVVconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (Select0 (DIVVU x (MOVVconst [c])))
+ // cond: isPowerOfTwo(c)
+ // result: (ANDconst [c-1] x)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPS64DIVVU {
+ break
+ }
+ 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(OpMIPS64ANDconst)
+ v.AuxInt = c - 1
+ v.AddArg(x)
+ return true
+ }
+ // match: (Select0 (DIVV (MOVVconst [c]) (MOVVconst [d])))
+ // cond:
+ // result: (MOVVconst [int64(c)%int64(d)])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPS64DIVV {
+ break
+ }
+ v_0_0 := v_0.Args[0]
+ if v_0_0.Op != OpMIPS64MOVVconst {
+ break
+ }
+ c := v_0_0.AuxInt
+ v_0_1 := v_0.Args[1]
+ if v_0_1.Op != OpMIPS64MOVVconst {
+ break
+ }
+ d := v_0_1.AuxInt
+ v.reset(OpMIPS64MOVVconst)
+ v.AuxInt = int64(c) % int64(d)
+ return true
+ }
+ // match: (Select0 (DIVVU (MOVVconst [c]) (MOVVconst [d])))
+ // cond:
+ // result: (MOVVconst [int64(uint64(c)%uint64(d))])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPS64DIVVU {
+ break
+ }
+ v_0_0 := v_0.Args[0]
+ if v_0_0.Op != OpMIPS64MOVVconst {
+ break
+ }
+ c := v_0_0.AuxInt
+ v_0_1 := v_0.Args[1]
+ if v_0_1.Op != OpMIPS64MOVVconst {
+ break
+ }
+ d := v_0_1.AuxInt
+ v.reset(OpMIPS64MOVVconst)
+ v.AuxInt = int64(uint64(c) % uint64(d))
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS64_OpSelect1(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Select1 (MULVU x (MOVVconst [-1])))
+ // cond:
+ // result: (NEGV x)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPS64MULVU {
+ break
+ }
+ 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
+ }
+ // match: (Select1 (MULVU _ (MOVVconst [0])))
+ // cond:
+ // result: (MOVVconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPS64MULVU {
+ break
+ }
+ 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 x (MOVVconst [1])))
+ // cond:
+ // result: x
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPS64MULVU {
+ break
+ }
+ 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 x (MOVVconst [c])))
+ // cond: isPowerOfTwo(c)
+ // result: (SLLVconst [log2(c)] x)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPS64MULVU {
+ break
+ }
+ 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 (MULVU (MOVVconst [-1]) x))
+ // cond:
+ // result: (NEGV x)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPS64MULVU {
+ break
+ }
+ 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])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPS64MULVU {
+ break
+ }
+ 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 (MOVVconst [1]) x))
+ // cond:
+ // result: x
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPS64MULVU {
+ break
+ }
+ 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 (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_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 (DIVVU x (MOVVconst [1])))
+ // cond:
+ // result: x
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPS64DIVVU {
+ break
+ }
+ 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 (DIVVU x (MOVVconst [c])))
+ // cond: isPowerOfTwo(c)
+ // result: (SRLVconst [log2(c)] x)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPS64DIVVU {
+ break
+ }
+ 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(OpMIPS64SRLVconst)
+ v.AuxInt = log2(c)
+ v.AddArg(x)
+ return true
+ }
+ // match: (Select1 (MULVU (MOVVconst [c]) (MOVVconst [d])))
+ // cond:
+ // result: (MOVVconst [c*d])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPS64MULVU {
+ break
+ }
+ v_0_0 := v_0.Args[0]
+ if v_0_0.Op != OpMIPS64MOVVconst {
+ break
+ }
+ c := v_0_0.AuxInt
+ v_0_1 := v_0.Args[1]
+ if v_0_1.Op != OpMIPS64MOVVconst {
+ break
+ }
+ d := v_0_1.AuxInt
+ v.reset(OpMIPS64MOVVconst)
+ v.AuxInt = c * d
+ return true
+ }
+ // match: (Select1 (DIVV (MOVVconst [c]) (MOVVconst [d])))
+ // cond:
+ // result: (MOVVconst [int64(c)/int64(d)])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPS64DIVV {
+ break
+ }
+ v_0_0 := v_0.Args[0]
+ if v_0_0.Op != OpMIPS64MOVVconst {
+ break
+ }
+ c := v_0_0.AuxInt
+ v_0_1 := v_0.Args[1]
+ if v_0_1.Op != OpMIPS64MOVVconst {
+ break
+ }
+ d := v_0_1.AuxInt
+ v.reset(OpMIPS64MOVVconst)
+ v.AuxInt = int64(c) / int64(d)
+ return true
+ }
+ // match: (Select1 (DIVVU (MOVVconst [c]) (MOVVconst [d])))
+ // cond:
+ // result: (MOVVconst [int64(uint64(c)/uint64(d))])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpMIPS64DIVVU {
+ break
+ }
+ v_0_0 := v_0.Args[0]
+ if v_0_0.Op != OpMIPS64MOVVconst {
+ break
+ }
+ c := v_0_0.AuxInt
+ v_0_1 := v_0.Args[1]
+ if v_0_1.Op != OpMIPS64MOVVconst {
+ break
+ }
+ d := v_0_1.AuxInt
+ v.reset(OpMIPS64MOVVconst)
+ v.AuxInt = int64(uint64(c) / uint64(d))
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS64_OpSignExt16to32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SignExt16to32 x)
+ // cond:
+ // result: (MOVHreg x)
+ for {
+ x := v.Args[0]
+ v.reset(OpMIPS64MOVHreg)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpSignExt16to64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SignExt16to64 x)
+ // cond:
+ // result: (MOVHreg x)
+ for {
+ x := v.Args[0]
+ v.reset(OpMIPS64MOVHreg)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpSignExt32to64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SignExt32to64 x)
+ // cond:
+ // result: (MOVWreg x)
+ for {
+ x := v.Args[0]
+ v.reset(OpMIPS64MOVWreg)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpSignExt8to16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SignExt8to16 x)
+ // cond:
+ // result: (MOVBreg x)
+ for {
+ x := v.Args[0]
+ v.reset(OpMIPS64MOVBreg)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpSignExt8to32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SignExt8to32 x)
+ // cond:
+ // result: (MOVBreg x)
+ for {
+ x := v.Args[0]
+ v.reset(OpMIPS64MOVBreg)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpSignExt8to64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SignExt8to64 x)
+ // cond:
+ // result: (MOVBreg x)
+ for {
+ x := v.Args[0]
+ v.reset(OpMIPS64MOVBreg)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpSlicemask(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Slicemask <t> x)
+ // cond:
+ // result: (NORconst [0] (SRAVconst <t> (SUBVconst <t> x [1]) [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.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueMIPS64_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(OpMIPS64CALLstatic)
+ v.AuxInt = argwid
+ v.Aux = target
+ v.AddArg(mem)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpStore(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Store [1] ptr val mem)
+ // cond:
+ // result: (MOVBstore ptr val mem)
+ for {
+ if v.AuxInt != 1 {
+ break
+ }
+ ptr := v.Args[0]
+ val := v.Args[1]
+ mem := v.Args[2]
+ v.reset(OpMIPS64MOVBstore)
+ 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 {
+ break
+ }
+ ptr := v.Args[0]
+ val := v.Args[1]
+ mem := v.Args[2]
+ v.reset(OpMIPS64MOVHstore)
+ 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)
+ for {
+ if v.AuxInt != 4 {
+ break
+ }
+ ptr := v.Args[0]
+ val := v.Args[1]
+ mem := v.Args[2]
+ if !(!is32BitFloat(val.Type)) {
+ break
+ }
+ v.reset(OpMIPS64MOVWstore)
+ v.AddArg(ptr)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (Store [8] ptr val mem)
+ // cond: !is64BitFloat(val.Type)
+ // result: (MOVVstore ptr val mem)
+ for {
+ if v.AuxInt != 8 {
+ break
+ }
+ ptr := v.Args[0]
+ val := v.Args[1]
+ mem := v.Args[2]
+ if !(!is64BitFloat(val.Type)) {
+ break
+ }
+ v.reset(OpMIPS64MOVVstore)
+ v.AddArg(ptr)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (Store [4] ptr val mem)
+ // cond: is32BitFloat(val.Type)
+ // result: (MOVFstore ptr val mem)
+ for {
+ if v.AuxInt != 4 {
+ break
+ }
+ ptr := v.Args[0]
+ val := v.Args[1]
+ mem := v.Args[2]
+ if !(is32BitFloat(val.Type)) {
+ break
+ }
+ v.reset(OpMIPS64MOVFstore)
+ v.AddArg(ptr)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (Store [8] ptr val mem)
+ // cond: is64BitFloat(val.Type)
+ // result: (MOVDstore ptr val mem)
+ for {
+ if v.AuxInt != 8 {
+ break
+ }
+ ptr := v.Args[0]
+ val := v.Args[1]
+ mem := v.Args[2]
+ if !(is64BitFloat(val.Type)) {
+ break
+ }
+ v.reset(OpMIPS64MOVDstore)
+ v.AddArg(ptr)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValueMIPS64_OpSub16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Sub16 x y)
+ // cond:
+ // result: (SUBV x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPS64SUBV)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpSub32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Sub32 x y)
+ // cond:
+ // result: (SUBV x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPS64SUBV)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpSub32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Sub32F x y)
+ // cond:
+ // result: (SUBF x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPS64SUBF)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpSub64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Sub64 x y)
+ // cond:
+ // result: (SUBV x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPS64SUBV)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpSub64F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Sub64F x y)
+ // cond:
+ // result: (SUBD x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPS64SUBD)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpSub8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Sub8 x y)
+ // cond:
+ // result: (SUBV x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPS64SUBV)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpSubPtr(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SubPtr x y)
+ // cond:
+ // result: (SUBV x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPS64SUBV)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpTrunc16to8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Trunc16to8 x)
+ // cond:
+ // result: x
+ for {
+ x := v.Args[0]
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueMIPS64_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 rewriteValueMIPS64_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 rewriteValueMIPS64_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 rewriteValueMIPS64_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 rewriteValueMIPS64_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 rewriteValueMIPS64_OpXor16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Xor16 x y)
+ // cond:
+ // result: (XOR x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPS64XOR)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpXor32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Xor32 x y)
+ // cond:
+ // result: (XOR x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPS64XOR)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpXor64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Xor64 x y)
+ // cond:
+ // result: (XOR x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPS64XOR)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpXor8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Xor8 x y)
+ // cond:
+ // result: (XOR x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMIPS64XOR)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueMIPS64_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) {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = mem.Type
+ v.AddArg(mem)
+ return true
+ }
+ // match: (Zero [s] ptr mem)
+ // cond: SizeAndAlign(s).Size() == 1
+ // result: (MOVBstore ptr (MOVVconst [0]) mem)
+ for {
+ s := v.AuxInt
+ ptr := v.Args[0]
+ mem := v.Args[1]
+ if !(SizeAndAlign(s).Size() == 1) {
+ break
+ }
+ v.reset(OpMIPS64MOVBstore)
+ v.AddArg(ptr)
+ v0 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+ 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
+ // result: (MOVHstore ptr (MOVVconst [0]) mem)
+ for {
+ s := v.AuxInt
+ ptr := v.Args[0]
+ mem := v.Args[1]
+ if !(SizeAndAlign(s).Size() == 2 && SizeAndAlign(s).Align()%2 == 0) {
+ break
+ }
+ v.reset(OpMIPS64MOVHstore)
+ v.AddArg(ptr)
+ v0 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+ v0.AuxInt = 0
+ v.AddArg(v0)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (Zero [s] ptr mem)
+ // cond: SizeAndAlign(s).Size() == 2
+ // 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) {
+ break
+ }
+ v.reset(OpMIPS64MOVBstore)
+ v.AuxInt = 1
+ v.AddArg(ptr)
+ v0 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+ v0.AuxInt = 0
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpMIPS64MOVBstore, TypeMem)
+ v1.AuxInt = 0
+ v1.AddArg(ptr)
+ v2 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+ 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
+ // result: (MOVWstore ptr (MOVVconst [0]) mem)
+ for {
+ s := v.AuxInt
+ ptr := v.Args[0]
+ mem := v.Args[1]
+ if !(SizeAndAlign(s).Size() == 4 && SizeAndAlign(s).Align()%4 == 0) {
+ break
+ }
+ v.reset(OpMIPS64MOVWstore)
+ v.AddArg(ptr)
+ v0 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+ 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
+ // result: (MOVHstore [2] ptr (MOVVconst [0]) (MOVHstore [0] ptr (MOVVconst [0]) mem))
+ for {
+ s := v.AuxInt
+ ptr := v.Args[0]
+ mem := v.Args[1]
+ if !(SizeAndAlign(s).Size() == 4 && SizeAndAlign(s).Align()%2 == 0) {
+ break
+ }
+ v.reset(OpMIPS64MOVHstore)
+ v.AuxInt = 2
+ v.AddArg(ptr)
+ v0 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+ v0.AuxInt = 0
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpMIPS64MOVHstore, TypeMem)
+ v1.AuxInt = 0
+ v1.AddArg(ptr)
+ v2 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+ v2.AuxInt = 0
+ v1.AddArg(v2)
+ v1.AddArg(mem)
+ v.AddArg(v1)
+ return true
+ }
+ // match: (Zero [s] ptr mem)
+ // cond: SizeAndAlign(s).Size() == 4
+ // 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) {
+ break
+ }
+ v.reset(OpMIPS64MOVBstore)
+ v.AuxInt = 3
+ v.AddArg(ptr)
+ v0 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+ v0.AuxInt = 0
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpMIPS64MOVBstore, TypeMem)
+ v1.AuxInt = 2
+ v1.AddArg(ptr)
+ v2 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+ v2.AuxInt = 0
+ v1.AddArg(v2)
+ v3 := b.NewValue0(v.Line, OpMIPS64MOVBstore, TypeMem)
+ v3.AuxInt = 1
+ v3.AddArg(ptr)
+ v4 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+ v4.AuxInt = 0
+ v3.AddArg(v4)
+ v5 := b.NewValue0(v.Line, OpMIPS64MOVBstore, TypeMem)
+ v5.AuxInt = 0
+ v5.AddArg(ptr)
+ v6 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+ v6.AuxInt = 0
+ v5.AddArg(v6)
+ v5.AddArg(mem)
+ v3.AddArg(v5)
+ v1.AddArg(v3)
+ v.AddArg(v1)
+ return true
+ }
+ // match: (Zero [s] ptr mem)
+ // cond: SizeAndAlign(s).Size() == 8 && SizeAndAlign(s).Align()%8 == 0
+ // result: (MOVVstore ptr (MOVVconst [0]) mem)
+ for {
+ s := v.AuxInt
+ ptr := v.Args[0]
+ mem := v.Args[1]
+ if !(SizeAndAlign(s).Size() == 8 && SizeAndAlign(s).Align()%8 == 0) {
+ break
+ }
+ v.reset(OpMIPS64MOVVstore)
+ v.AddArg(ptr)
+ v0 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+ 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
+ // result: (MOVWstore [4] ptr (MOVVconst [0]) (MOVWstore [0] ptr (MOVVconst [0]) mem))
+ for {
+ s := v.AuxInt
+ ptr := v.Args[0]
+ mem := v.Args[1]
+ if !(SizeAndAlign(s).Size() == 8 && SizeAndAlign(s).Align()%4 == 0) {
+ break
+ }
+ v.reset(OpMIPS64MOVWstore)
+ v.AuxInt = 4
+ v.AddArg(ptr)
+ v0 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+ v0.AuxInt = 0
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpMIPS64MOVWstore, TypeMem)
+ v1.AuxInt = 0
+ v1.AddArg(ptr)
+ v2 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+ v2.AuxInt = 0
+ v1.AddArg(v2)
+ v1.AddArg(mem)
+ v.AddArg(v1)
+ return true
+ }
+ // match: (Zero [s] ptr mem)
+ // cond: SizeAndAlign(s).Size() == 4
+ // 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
+ ptr := v.Args[0]
+ mem := v.Args[1]
+ if !(SizeAndAlign(s).Size() == 4) {
+ break
+ }
+ v.reset(OpMIPS64MOVHstore)
+ v.AuxInt = 6
+ v.AddArg(ptr)
+ v0 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+ v0.AuxInt = 0
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpMIPS64MOVHstore, TypeMem)
+ v1.AuxInt = 4
+ v1.AddArg(ptr)
+ v2 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+ v2.AuxInt = 0
+ v1.AddArg(v2)
+ v3 := b.NewValue0(v.Line, OpMIPS64MOVHstore, TypeMem)
+ v3.AuxInt = 2
+ v3.AddArg(ptr)
+ v4 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+ v4.AuxInt = 0
+ v3.AddArg(v4)
+ v5 := b.NewValue0(v.Line, OpMIPS64MOVHstore, TypeMem)
+ v5.AuxInt = 0
+ v5.AddArg(ptr)
+ v6 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+ v6.AuxInt = 0
+ v5.AddArg(v6)
+ v5.AddArg(mem)
+ v3.AddArg(v5)
+ v1.AddArg(v3)
+ v.AddArg(v1)
+ return true
+ }
+ // match: (Zero [s] ptr mem)
+ // cond: SizeAndAlign(s).Size() == 3
+ // 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) {
+ break
+ }
+ v.reset(OpMIPS64MOVBstore)
+ v.AuxInt = 2
+ v.AddArg(ptr)
+ v0 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+ v0.AuxInt = 0
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpMIPS64MOVBstore, TypeMem)
+ v1.AuxInt = 1
+ v1.AddArg(ptr)
+ v2 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+ v2.AuxInt = 0
+ v1.AddArg(v2)
+ v3 := b.NewValue0(v.Line, OpMIPS64MOVBstore, TypeMem)
+ v3.AuxInt = 0
+ v3.AddArg(ptr)
+ v4 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+ v4.AuxInt = 0
+ v3.AddArg(v4)
+ v3.AddArg(mem)
+ v1.AddArg(v3)
+ v.AddArg(v1)
+ return true
+ }
+ // match: (Zero [s] ptr mem)
+ // cond: SizeAndAlign(s).Size() == 6 && SizeAndAlign(s).Align()%2 == 0
+ // result: (MOVHstore [4] ptr (MOVVconst [0]) (MOVHstore [2] ptr (MOVVconst [0]) (MOVHstore [0] ptr (MOVVconst [0]) mem)))
+ for {
+ s := v.AuxInt
+ ptr := v.Args[0]
+ mem := v.Args[1]
+ if !(SizeAndAlign(s).Size() == 6 && SizeAndAlign(s).Align()%2 == 0) {
+ break
+ }
+ v.reset(OpMIPS64MOVHstore)
+ v.AuxInt = 4
+ v.AddArg(ptr)
+ v0 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+ v0.AuxInt = 0
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpMIPS64MOVHstore, TypeMem)
+ v1.AuxInt = 2
+ v1.AddArg(ptr)
+ v2 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+ v2.AuxInt = 0
+ v1.AddArg(v2)
+ v3 := b.NewValue0(v.Line, OpMIPS64MOVHstore, TypeMem)
+ v3.AuxInt = 0
+ v3.AddArg(ptr)
+ v4 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+ v4.AuxInt = 0
+ v3.AddArg(v4)
+ v3.AddArg(mem)
+ v1.AddArg(v3)
+ v.AddArg(v1)
+ return true
+ }
+ // match: (Zero [s] ptr mem)
+ // cond: SizeAndAlign(s).Size() == 12 && SizeAndAlign(s).Align()%4 == 0
+ // result: (MOVWstore [8] ptr (MOVVconst [0]) (MOVWstore [4] ptr (MOVVconst [0]) (MOVWstore [0] ptr (MOVVconst [0]) mem)))
+ for {
+ s := v.AuxInt
+ ptr := v.Args[0]
+ mem := v.Args[1]
+ if !(SizeAndAlign(s).Size() == 12 && SizeAndAlign(s).Align()%4 == 0) {
+ break
+ }
+ v.reset(OpMIPS64MOVWstore)
+ v.AuxInt = 8
+ v.AddArg(ptr)
+ v0 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+ v0.AuxInt = 0
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpMIPS64MOVWstore, TypeMem)
+ v1.AuxInt = 4
+ v1.AddArg(ptr)
+ v2 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+ v2.AuxInt = 0
+ v1.AddArg(v2)
+ v3 := b.NewValue0(v.Line, OpMIPS64MOVWstore, TypeMem)
+ v3.AuxInt = 0
+ v3.AddArg(ptr)
+ v4 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+ v4.AuxInt = 0
+ v3.AddArg(v4)
+ v3.AddArg(mem)
+ v1.AddArg(v3)
+ v.AddArg(v1)
+ return true
+ }
+ // match: (Zero [s] ptr mem)
+ // cond: SizeAndAlign(s).Size() == 16 && SizeAndAlign(s).Align()%8 == 0
+ // result: (MOVVstore [8] ptr (MOVVconst [0]) (MOVVstore [0] ptr (MOVVconst [0]) mem))
+ for {
+ s := v.AuxInt
+ ptr := v.Args[0]
+ mem := v.Args[1]
+ if !(SizeAndAlign(s).Size() == 16 && SizeAndAlign(s).Align()%8 == 0) {
+ break
+ }
+ v.reset(OpMIPS64MOVVstore)
+ v.AuxInt = 8
+ v.AddArg(ptr)
+ v0 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+ v0.AuxInt = 0
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpMIPS64MOVVstore, TypeMem)
+ v1.AuxInt = 0
+ v1.AddArg(ptr)
+ v2 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+ 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
+ // result: (MOVVstore [16] ptr (MOVVconst [0]) (MOVVstore [8] ptr (MOVVconst [0]) (MOVVstore [0] ptr (MOVVconst [0]) mem)))
+ for {
+ s := v.AuxInt
+ ptr := v.Args[0]
+ mem := v.Args[1]
+ if !(SizeAndAlign(s).Size() == 24 && SizeAndAlign(s).Align()%8 == 0) {
+ break
+ }
+ v.reset(OpMIPS64MOVVstore)
+ v.AuxInt = 16
+ v.AddArg(ptr)
+ v0 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+ v0.AuxInt = 0
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpMIPS64MOVVstore, TypeMem)
+ v1.AuxInt = 8
+ v1.AddArg(ptr)
+ v2 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+ v2.AuxInt = 0
+ v1.AddArg(v2)
+ v3 := b.NewValue0(v.Line, OpMIPS64MOVVstore, TypeMem)
+ v3.AuxInt = 0
+ v3.AddArg(ptr)
+ v4 := b.NewValue0(v.Line, OpMIPS64MOVVconst, config.fe.TypeUInt64())
+ v4.AuxInt = 0
+ v3.AddArg(v4)
+ v3.AddArg(mem)
+ v1.AddArg(v3)
+ 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)
+ for {
+ s := v.AuxInt
+ 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) {
+ break
+ }
+ v.reset(OpMIPS64DUFFZERO)
+ v.AuxInt = 8 * (128 - int64(SizeAndAlign(s).Size()/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)
+ for {
+ s := v.AuxInt
+ ptr := v.Args[0]
+ mem := v.Args[1]
+ if !((SizeAndAlign(s).Size() > 8*128 || config.noDuffDevice) || SizeAndAlign(s).Align()%8 != 0) {
+ break
+ }
+ v.reset(OpMIPS64LoweredZero)
+ v.AuxInt = SizeAndAlign(s).Align()
+ v.AddArg(ptr)
+ v0 := b.NewValue0(v.Line, OpMIPS64ADDVconst, 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 rewriteValueMIPS64_OpZeroExt16to32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ZeroExt16to32 x)
+ // cond:
+ // result: (MOVHUreg x)
+ for {
+ x := v.Args[0]
+ v.reset(OpMIPS64MOVHUreg)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpZeroExt16to64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ZeroExt16to64 x)
+ // cond:
+ // result: (MOVHUreg x)
+ for {
+ x := v.Args[0]
+ v.reset(OpMIPS64MOVHUreg)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpZeroExt32to64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ZeroExt32to64 x)
+ // cond:
+ // result: (MOVWUreg x)
+ for {
+ x := v.Args[0]
+ v.reset(OpMIPS64MOVWUreg)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpZeroExt8to16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ZeroExt8to16 x)
+ // cond:
+ // result: (MOVBUreg x)
+ for {
+ x := v.Args[0]
+ v.reset(OpMIPS64MOVBUreg)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpZeroExt8to32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ZeroExt8to32 x)
+ // cond:
+ // result: (MOVBUreg x)
+ for {
+ x := v.Args[0]
+ v.reset(OpMIPS64MOVBUreg)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueMIPS64_OpZeroExt8to64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ZeroExt8to64 x)
+ // cond:
+ // result: (MOVBUreg x)
+ for {
+ x := v.Args[0]
+ v.reset(OpMIPS64MOVBUreg)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteBlockMIPS64(b *Block, config *Config) bool {
+ switch b.Kind {
+ case BlockMIPS64EQ:
+ // match: (EQ (FPFlagTrue cmp) yes no)
+ // cond:
+ // result: (FPF cmp yes no)
+ for {
+ v := b.Control
+ if v.Op != OpMIPS64FPFlagTrue {
+ 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)
+ // cond:
+ // result: (FPT cmp yes no)
+ for {
+ v := b.Control
+ if v.Op != OpMIPS64FPFlagFalse {
+ 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)
+ // cond:
+ // result: (NE cmp yes no)
+ for {
+ v := b.Control
+ if v.Op != OpMIPS64XORconst {
+ break
+ }
+ if v.AuxInt != 1 {
+ break
+ }
+ cmp := v.Args[0]
+ if cmp.Op != OpMIPS64SGT {
+ break
+ }
+ yes := b.Succs[0]
+ no := b.Succs[1]
+ b.Kind = BlockMIPS64NE
+ b.SetControl(cmp)
+ _ = yes
+ _ = no
+ return true
+ }
+ // match: (EQ (XORconst [1] cmp:(SGTU _ _)) yes no)
+ // cond:
+ // result: (NE cmp yes no)
+ for {
+ v := b.Control
+ if v.Op != OpMIPS64XORconst {
+ break
+ }
+ if v.AuxInt != 1 {
+ break
+ }
+ cmp := v.Args[0]
+ if cmp.Op != OpMIPS64SGTU {
+ break
+ }
+ yes := b.Succs[0]
+ no := b.Succs[1]
+ b.Kind = BlockMIPS64NE
+ b.SetControl(cmp)
+ _ = yes
+ _ = no
+ return true
+ }
+ // match: (EQ (XORconst [1] cmp:(SGTconst _)) yes no)
+ // cond:
+ // result: (NE cmp yes no)
+ for {
+ v := b.Control
+ if v.Op != OpMIPS64XORconst {
+ break
+ }
+ if v.AuxInt != 1 {
+ break
+ }
+ cmp := v.Args[0]
+ 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)
+ // cond:
+ // result: (NE cmp yes no)
+ for {
+ v := b.Control
+ if v.Op != OpMIPS64XORconst {
+ break
+ }
+ if v.AuxInt != 1 {
+ break
+ }
+ cmp := v.Args[0]
+ 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)
+ // cond:
+ // result: (NE x yes no)
+ for {
+ v := b.Control
+ if v.Op != OpMIPS64SGTUconst {
+ break
+ }
+ if v.AuxInt != 1 {
+ 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)
+ // cond:
+ // result: (EQ x yes no)
+ for {
+ v := b.Control
+ if v.Op != OpMIPS64SGTU {
+ break
+ }
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpMIPS64MOVVconst {
+ break
+ }
+ 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)
+ // cond:
+ // result: (GEZ x yes no)
+ for {
+ v := b.Control
+ if v.Op != OpMIPS64SGTconst {
+ break
+ }
+ if v.AuxInt != 0 {
+ 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)
+ // cond:
+ // result: (LEZ x yes no)
+ for {
+ v := b.Control
+ if v.Op != OpMIPS64SGT {
+ break
+ }
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpMIPS64MOVVconst {
+ break
+ }
+ 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)
+ // cond:
+ // result: (First nil yes no)
+ for {
+ v := b.Control
+ if v.Op != OpMIPS64MOVVconst {
+ break
+ }
+ 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)
+ // cond: c != 0
+ // result: (First nil no yes)
+ for {
+ v := b.Control
+ if v.Op != OpMIPS64MOVVconst {
+ 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:
+ // match: (GEZ (MOVVconst [c]) yes no)
+ // cond: c >= 0
+ // result: (First nil yes no)
+ for {
+ v := b.Control
+ if v.Op != OpMIPS64MOVVconst {
+ 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)
+ // cond: c < 0
+ // result: (First nil no yes)
+ for {
+ v := b.Control
+ if v.Op != OpMIPS64MOVVconst {
+ 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:
+ // match: (GTZ (MOVVconst [c]) yes no)
+ // cond: c > 0
+ // result: (First nil yes no)
+ for {
+ v := b.Control
+ if v.Op != OpMIPS64MOVVconst {
+ 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)
+ // cond: c <= 0
+ // result: (First nil no yes)
+ for {
+ v := b.Control
+ if v.Op != OpMIPS64MOVVconst {
+ 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:
+ // match: (If cond yes no)
+ // cond:
+ // result: (NE cond yes no)
+ for {
+ 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:
+ // match: (LEZ (MOVVconst [c]) yes no)
+ // cond: c <= 0
+ // result: (First nil yes no)
+ for {
+ v := b.Control
+ if v.Op != OpMIPS64MOVVconst {
+ 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)
+ // cond: c > 0
+ // result: (First nil no yes)
+ for {
+ v := b.Control
+ if v.Op != OpMIPS64MOVVconst {
+ 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:
+ // match: (LTZ (MOVVconst [c]) yes no)
+ // cond: c < 0
+ // result: (First nil yes no)
+ for {
+ v := b.Control
+ if v.Op != OpMIPS64MOVVconst {
+ 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)
+ // cond: c >= 0
+ // result: (First nil no yes)
+ for {
+ v := b.Control
+ if v.Op != OpMIPS64MOVVconst {
+ 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:
+ // match: (NE (FPFlagTrue cmp) yes no)
+ // cond:
+ // result: (FPT cmp yes no)
+ for {
+ v := b.Control
+ if v.Op != OpMIPS64FPFlagTrue {
+ 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)
+ // cond:
+ // result: (FPF cmp yes no)
+ for {
+ v := b.Control
+ if v.Op != OpMIPS64FPFlagFalse {
+ 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)
+ // cond:
+ // result: (EQ cmp yes no)
+ for {
+ v := b.Control
+ if v.Op != OpMIPS64XORconst {
+ break
+ }
+ if v.AuxInt != 1 {
+ break
+ }
+ cmp := v.Args[0]
+ if cmp.Op != OpMIPS64SGT {
+ break
+ }
+ yes := b.Succs[0]
+ no := b.Succs[1]
+ b.Kind = BlockMIPS64EQ
+ b.SetControl(cmp)
+ _ = yes
+ _ = no
+ return true
+ }
+ // match: (NE (XORconst [1] cmp:(SGTU _ _)) yes no)
+ // cond:
+ // result: (EQ cmp yes no)
+ for {
+ v := b.Control
+ if v.Op != OpMIPS64XORconst {
+ break
+ }
+ if v.AuxInt != 1 {
+ break
+ }
+ cmp := v.Args[0]
+ if cmp.Op != OpMIPS64SGTU {
+ break
+ }
+ yes := b.Succs[0]
+ no := b.Succs[1]
+ b.Kind = BlockMIPS64EQ
+ b.SetControl(cmp)
+ _ = yes
+ _ = no
+ return true
+ }
+ // match: (NE (XORconst [1] cmp:(SGTconst _)) yes no)
+ // cond:
+ // result: (EQ cmp yes no)
+ for {
+ v := b.Control
+ if v.Op != OpMIPS64XORconst {
+ break
+ }
+ if v.AuxInt != 1 {
+ break
+ }
+ cmp := v.Args[0]
+ 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)
+ // cond:
+ // result: (EQ cmp yes no)
+ for {
+ v := b.Control
+ if v.Op != OpMIPS64XORconst {
+ break
+ }
+ if v.AuxInt != 1 {
+ break
+ }
+ cmp := v.Args[0]
+ 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)
+ // cond:
+ // result: (EQ x yes no)
+ for {
+ v := b.Control
+ if v.Op != OpMIPS64SGTUconst {
+ break
+ }
+ if v.AuxInt != 1 {
+ 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)
+ // cond:
+ // result: (NE x yes no)
+ for {
+ v := b.Control
+ if v.Op != OpMIPS64SGTU {
+ break
+ }
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpMIPS64MOVVconst {
+ break
+ }
+ 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)
+ // cond:
+ // result: (LTZ x yes no)
+ for {
+ v := b.Control
+ if v.Op != OpMIPS64SGTconst {
+ break
+ }
+ if v.AuxInt != 0 {
+ 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)
+ // cond:
+ // result: (GTZ x yes no)
+ for {
+ v := b.Control
+ if v.Op != OpMIPS64SGT {
+ break
+ }
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpMIPS64MOVVconst {
+ break
+ }
+ 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)
+ // cond:
+ // result: (First nil no yes)
+ for {
+ v := b.Control
+ if v.Op != OpMIPS64MOVVconst {
+ break
+ }
+ 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)
+ // cond: c != 0
+ // result: (First nil yes no)
+ for {
+ v := b.Control
+ if v.Op != OpMIPS64MOVVconst {
+ 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
+ }
+ }
+ return false
+}
diff --git a/src/cmd/compile/internal/ssa/rewritePPC64.go b/src/cmd/compile/internal/ssa/rewritePPC64.go
new file mode 100644
index 0000000..8c8373b
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/rewritePPC64.go
@@ -0,0 +1,10848 @@
+// autogenerated from gen/PPC64.rules: do not edit!
+// generated with: cd gen; go run *.go
+
+package ssa
+
+import "math"
+
+var _ = math.MinInt8 // in case not otherwise used
+func rewriteValuePPC64(v *Value, config *Config) bool {
+ switch v.Op {
+ case OpAdd16:
+ return rewriteValuePPC64_OpAdd16(v, config)
+ case OpAdd32:
+ return rewriteValuePPC64_OpAdd32(v, config)
+ case OpAdd32F:
+ return rewriteValuePPC64_OpAdd32F(v, config)
+ case OpAdd64:
+ return rewriteValuePPC64_OpAdd64(v, config)
+ case OpAdd64F:
+ return rewriteValuePPC64_OpAdd64F(v, config)
+ case OpAdd8:
+ return rewriteValuePPC64_OpAdd8(v, config)
+ case OpAddPtr:
+ return rewriteValuePPC64_OpAddPtr(v, config)
+ case OpAddr:
+ return rewriteValuePPC64_OpAddr(v, config)
+ case OpAnd16:
+ return rewriteValuePPC64_OpAnd16(v, config)
+ case OpAnd32:
+ return rewriteValuePPC64_OpAnd32(v, config)
+ case OpAnd64:
+ return rewriteValuePPC64_OpAnd64(v, config)
+ case OpAnd8:
+ return rewriteValuePPC64_OpAnd8(v, config)
+ case OpAndB:
+ return rewriteValuePPC64_OpAndB(v, config)
+ case OpAvg64u:
+ return rewriteValuePPC64_OpAvg64u(v, config)
+ case OpClosureCall:
+ return rewriteValuePPC64_OpClosureCall(v, config)
+ case OpCom16:
+ return rewriteValuePPC64_OpCom16(v, config)
+ case OpCom32:
+ return rewriteValuePPC64_OpCom32(v, config)
+ case OpCom64:
+ return rewriteValuePPC64_OpCom64(v, config)
+ case OpCom8:
+ return rewriteValuePPC64_OpCom8(v, config)
+ case OpConst16:
+ return rewriteValuePPC64_OpConst16(v, config)
+ case OpConst32:
+ return rewriteValuePPC64_OpConst32(v, config)
+ case OpConst32F:
+ return rewriteValuePPC64_OpConst32F(v, config)
+ case OpConst64:
+ return rewriteValuePPC64_OpConst64(v, config)
+ case OpConst64F:
+ return rewriteValuePPC64_OpConst64F(v, config)
+ case OpConst8:
+ return rewriteValuePPC64_OpConst8(v, config)
+ case OpConstBool:
+ return rewriteValuePPC64_OpConstBool(v, config)
+ case OpConstNil:
+ return rewriteValuePPC64_OpConstNil(v, config)
+ case OpConvert:
+ return rewriteValuePPC64_OpConvert(v, config)
+ case OpCvt32Fto32:
+ return rewriteValuePPC64_OpCvt32Fto32(v, config)
+ case OpCvt32Fto64:
+ return rewriteValuePPC64_OpCvt32Fto64(v, config)
+ case OpCvt32Fto64F:
+ return rewriteValuePPC64_OpCvt32Fto64F(v, config)
+ case OpCvt32to32F:
+ return rewriteValuePPC64_OpCvt32to32F(v, config)
+ case OpCvt32to64F:
+ return rewriteValuePPC64_OpCvt32to64F(v, config)
+ case OpCvt64Fto32:
+ return rewriteValuePPC64_OpCvt64Fto32(v, config)
+ case OpCvt64Fto32F:
+ return rewriteValuePPC64_OpCvt64Fto32F(v, config)
+ case OpCvt64Fto64:
+ return rewriteValuePPC64_OpCvt64Fto64(v, config)
+ case OpCvt64to32F:
+ return rewriteValuePPC64_OpCvt64to32F(v, config)
+ case OpCvt64to64F:
+ return rewriteValuePPC64_OpCvt64to64F(v, config)
+ case OpDeferCall:
+ return rewriteValuePPC64_OpDeferCall(v, config)
+ case OpDiv16:
+ return rewriteValuePPC64_OpDiv16(v, config)
+ case OpDiv16u:
+ return rewriteValuePPC64_OpDiv16u(v, config)
+ case OpDiv32:
+ return rewriteValuePPC64_OpDiv32(v, config)
+ case OpDiv32F:
+ return rewriteValuePPC64_OpDiv32F(v, config)
+ case OpDiv32u:
+ return rewriteValuePPC64_OpDiv32u(v, config)
+ case OpDiv64:
+ return rewriteValuePPC64_OpDiv64(v, config)
+ case OpDiv64F:
+ return rewriteValuePPC64_OpDiv64F(v, config)
+ case OpDiv64u:
+ return rewriteValuePPC64_OpDiv64u(v, config)
+ case OpDiv8:
+ return rewriteValuePPC64_OpDiv8(v, config)
+ case OpDiv8u:
+ return rewriteValuePPC64_OpDiv8u(v, config)
+ case OpEq16:
+ return rewriteValuePPC64_OpEq16(v, config)
+ case OpEq32:
+ return rewriteValuePPC64_OpEq32(v, config)
+ case OpEq32F:
+ return rewriteValuePPC64_OpEq32F(v, config)
+ case OpEq64:
+ return rewriteValuePPC64_OpEq64(v, config)
+ case OpEq64F:
+ return rewriteValuePPC64_OpEq64F(v, config)
+ case OpEq8:
+ return rewriteValuePPC64_OpEq8(v, config)
+ case OpEqB:
+ return rewriteValuePPC64_OpEqB(v, config)
+ case OpEqPtr:
+ return rewriteValuePPC64_OpEqPtr(v, config)
+ case OpGeq16:
+ return rewriteValuePPC64_OpGeq16(v, config)
+ case OpGeq16U:
+ return rewriteValuePPC64_OpGeq16U(v, config)
+ case OpGeq32:
+ return rewriteValuePPC64_OpGeq32(v, config)
+ case OpGeq32F:
+ return rewriteValuePPC64_OpGeq32F(v, config)
+ case OpGeq32U:
+ return rewriteValuePPC64_OpGeq32U(v, config)
+ case OpGeq64:
+ return rewriteValuePPC64_OpGeq64(v, config)
+ case OpGeq64F:
+ return rewriteValuePPC64_OpGeq64F(v, config)
+ case OpGeq64U:
+ return rewriteValuePPC64_OpGeq64U(v, config)
+ case OpGeq8:
+ return rewriteValuePPC64_OpGeq8(v, config)
+ case OpGeq8U:
+ return rewriteValuePPC64_OpGeq8U(v, config)
+ case OpGetClosurePtr:
+ return rewriteValuePPC64_OpGetClosurePtr(v, config)
+ case OpGoCall:
+ return rewriteValuePPC64_OpGoCall(v, config)
+ case OpGreater16:
+ return rewriteValuePPC64_OpGreater16(v, config)
+ case OpGreater16U:
+ return rewriteValuePPC64_OpGreater16U(v, config)
+ case OpGreater32:
+ return rewriteValuePPC64_OpGreater32(v, config)
+ case OpGreater32F:
+ return rewriteValuePPC64_OpGreater32F(v, config)
+ case OpGreater32U:
+ return rewriteValuePPC64_OpGreater32U(v, config)
+ case OpGreater64:
+ return rewriteValuePPC64_OpGreater64(v, config)
+ case OpGreater64F:
+ return rewriteValuePPC64_OpGreater64F(v, config)
+ case OpGreater64U:
+ return rewriteValuePPC64_OpGreater64U(v, config)
+ case OpGreater8:
+ return rewriteValuePPC64_OpGreater8(v, config)
+ case OpGreater8U:
+ return rewriteValuePPC64_OpGreater8U(v, config)
+ case OpHmul16:
+ return rewriteValuePPC64_OpHmul16(v, config)
+ case OpHmul16u:
+ return rewriteValuePPC64_OpHmul16u(v, config)
+ case OpHmul32:
+ return rewriteValuePPC64_OpHmul32(v, config)
+ case OpHmul32u:
+ return rewriteValuePPC64_OpHmul32u(v, config)
+ case OpHmul64:
+ return rewriteValuePPC64_OpHmul64(v, config)
+ case OpHmul64u:
+ return rewriteValuePPC64_OpHmul64u(v, config)
+ case OpHmul8:
+ return rewriteValuePPC64_OpHmul8(v, config)
+ case OpHmul8u:
+ return rewriteValuePPC64_OpHmul8u(v, config)
+ case OpInterCall:
+ return rewriteValuePPC64_OpInterCall(v, config)
+ case OpIsInBounds:
+ return rewriteValuePPC64_OpIsInBounds(v, config)
+ case OpIsNonNil:
+ return rewriteValuePPC64_OpIsNonNil(v, config)
+ case OpIsSliceInBounds:
+ return rewriteValuePPC64_OpIsSliceInBounds(v, config)
+ case OpLeq16:
+ return rewriteValuePPC64_OpLeq16(v, config)
+ case OpLeq16U:
+ return rewriteValuePPC64_OpLeq16U(v, config)
+ case OpLeq32:
+ return rewriteValuePPC64_OpLeq32(v, config)
+ case OpLeq32F:
+ return rewriteValuePPC64_OpLeq32F(v, config)
+ case OpLeq32U:
+ return rewriteValuePPC64_OpLeq32U(v, config)
+ case OpLeq64:
+ return rewriteValuePPC64_OpLeq64(v, config)
+ case OpLeq64F:
+ return rewriteValuePPC64_OpLeq64F(v, config)
+ case OpLeq64U:
+ return rewriteValuePPC64_OpLeq64U(v, config)
+ case OpLeq8:
+ return rewriteValuePPC64_OpLeq8(v, config)
+ case OpLeq8U:
+ return rewriteValuePPC64_OpLeq8U(v, config)
+ case OpLess16:
+ return rewriteValuePPC64_OpLess16(v, config)
+ case OpLess16U:
+ return rewriteValuePPC64_OpLess16U(v, config)
+ case OpLess32:
+ return rewriteValuePPC64_OpLess32(v, config)
+ case OpLess32F:
+ return rewriteValuePPC64_OpLess32F(v, config)
+ case OpLess32U:
+ return rewriteValuePPC64_OpLess32U(v, config)
+ case OpLess64:
+ return rewriteValuePPC64_OpLess64(v, config)
+ case OpLess64F:
+ return rewriteValuePPC64_OpLess64F(v, config)
+ case OpLess64U:
+ return rewriteValuePPC64_OpLess64U(v, config)
+ case OpLess8:
+ return rewriteValuePPC64_OpLess8(v, config)
+ case OpLess8U:
+ return rewriteValuePPC64_OpLess8U(v, config)
+ case OpLoad:
+ return rewriteValuePPC64_OpLoad(v, config)
+ case OpLsh16x16:
+ return rewriteValuePPC64_OpLsh16x16(v, config)
+ case OpLsh16x32:
+ return rewriteValuePPC64_OpLsh16x32(v, config)
+ case OpLsh16x64:
+ return rewriteValuePPC64_OpLsh16x64(v, config)
+ case OpLsh16x8:
+ return rewriteValuePPC64_OpLsh16x8(v, config)
+ case OpLsh32x16:
+ return rewriteValuePPC64_OpLsh32x16(v, config)
+ case OpLsh32x32:
+ return rewriteValuePPC64_OpLsh32x32(v, config)
+ case OpLsh32x64:
+ return rewriteValuePPC64_OpLsh32x64(v, config)
+ case OpLsh32x8:
+ return rewriteValuePPC64_OpLsh32x8(v, config)
+ case OpLsh64x16:
+ return rewriteValuePPC64_OpLsh64x16(v, config)
+ case OpLsh64x32:
+ return rewriteValuePPC64_OpLsh64x32(v, config)
+ case OpLsh64x64:
+ return rewriteValuePPC64_OpLsh64x64(v, config)
+ case OpLsh64x8:
+ return rewriteValuePPC64_OpLsh64x8(v, config)
+ case OpLsh8x16:
+ return rewriteValuePPC64_OpLsh8x16(v, config)
+ case OpLsh8x32:
+ return rewriteValuePPC64_OpLsh8x32(v, config)
+ case OpLsh8x64:
+ return rewriteValuePPC64_OpLsh8x64(v, config)
+ case OpLsh8x8:
+ return rewriteValuePPC64_OpLsh8x8(v, config)
+ case OpMod16:
+ return rewriteValuePPC64_OpMod16(v, config)
+ case OpMod16u:
+ return rewriteValuePPC64_OpMod16u(v, config)
+ case OpMod32:
+ return rewriteValuePPC64_OpMod32(v, config)
+ case OpMod32u:
+ return rewriteValuePPC64_OpMod32u(v, config)
+ case OpMod64:
+ return rewriteValuePPC64_OpMod64(v, config)
+ case OpMod64u:
+ return rewriteValuePPC64_OpMod64u(v, config)
+ case OpMod8:
+ return rewriteValuePPC64_OpMod8(v, config)
+ case OpMod8u:
+ return rewriteValuePPC64_OpMod8u(v, config)
+ case OpMove:
+ return rewriteValuePPC64_OpMove(v, config)
+ case OpMul16:
+ return rewriteValuePPC64_OpMul16(v, config)
+ case OpMul32:
+ return rewriteValuePPC64_OpMul32(v, config)
+ case OpMul32F:
+ return rewriteValuePPC64_OpMul32F(v, config)
+ case OpMul64:
+ return rewriteValuePPC64_OpMul64(v, config)
+ case OpMul64F:
+ return rewriteValuePPC64_OpMul64F(v, config)
+ case OpMul8:
+ return rewriteValuePPC64_OpMul8(v, config)
+ case OpNeg16:
+ return rewriteValuePPC64_OpNeg16(v, config)
+ case OpNeg32:
+ return rewriteValuePPC64_OpNeg32(v, config)
+ case OpNeg32F:
+ return rewriteValuePPC64_OpNeg32F(v, config)
+ case OpNeg64:
+ return rewriteValuePPC64_OpNeg64(v, config)
+ case OpNeg64F:
+ return rewriteValuePPC64_OpNeg64F(v, config)
+ case OpNeg8:
+ return rewriteValuePPC64_OpNeg8(v, config)
+ case OpNeq16:
+ return rewriteValuePPC64_OpNeq16(v, config)
+ case OpNeq32:
+ return rewriteValuePPC64_OpNeq32(v, config)
+ case OpNeq32F:
+ return rewriteValuePPC64_OpNeq32F(v, config)
+ case OpNeq64:
+ return rewriteValuePPC64_OpNeq64(v, config)
+ case OpNeq64F:
+ return rewriteValuePPC64_OpNeq64F(v, config)
+ case OpNeq8:
+ return rewriteValuePPC64_OpNeq8(v, config)
+ case OpNeqB:
+ return rewriteValuePPC64_OpNeqB(v, config)
+ case OpNeqPtr:
+ return rewriteValuePPC64_OpNeqPtr(v, config)
+ case OpNilCheck:
+ return rewriteValuePPC64_OpNilCheck(v, config)
+ case OpNot:
+ return rewriteValuePPC64_OpNot(v, config)
+ case OpOffPtr:
+ return rewriteValuePPC64_OpOffPtr(v, config)
+ case OpOr16:
+ return rewriteValuePPC64_OpOr16(v, config)
+ case OpOr32:
+ return rewriteValuePPC64_OpOr32(v, config)
+ case OpOr64:
+ return rewriteValuePPC64_OpOr64(v, config)
+ case OpOr8:
+ return rewriteValuePPC64_OpOr8(v, config)
+ case OpOrB:
+ return rewriteValuePPC64_OpOrB(v, config)
+ case OpPPC64ADD:
+ return rewriteValuePPC64_OpPPC64ADD(v, config)
+ case OpPPC64ADDconst:
+ return rewriteValuePPC64_OpPPC64ADDconst(v, config)
+ case OpPPC64AND:
+ return rewriteValuePPC64_OpPPC64AND(v, config)
+ case OpPPC64ANDconst:
+ return rewriteValuePPC64_OpPPC64ANDconst(v, config)
+ case OpPPC64CMP:
+ return rewriteValuePPC64_OpPPC64CMP(v, config)
+ case OpPPC64CMPU:
+ return rewriteValuePPC64_OpPPC64CMPU(v, config)
+ case OpPPC64CMPUconst:
+ return rewriteValuePPC64_OpPPC64CMPUconst(v, config)
+ case OpPPC64CMPW:
+ return rewriteValuePPC64_OpPPC64CMPW(v, config)
+ case OpPPC64CMPWU:
+ return rewriteValuePPC64_OpPPC64CMPWU(v, config)
+ case OpPPC64CMPWUconst:
+ return rewriteValuePPC64_OpPPC64CMPWUconst(v, config)
+ case OpPPC64CMPWconst:
+ return rewriteValuePPC64_OpPPC64CMPWconst(v, config)
+ case OpPPC64CMPconst:
+ return rewriteValuePPC64_OpPPC64CMPconst(v, config)
+ case OpPPC64Equal:
+ return rewriteValuePPC64_OpPPC64Equal(v, config)
+ case OpPPC64FMOVDload:
+ return rewriteValuePPC64_OpPPC64FMOVDload(v, config)
+ case OpPPC64FMOVDstore:
+ return rewriteValuePPC64_OpPPC64FMOVDstore(v, config)
+ case OpPPC64FMOVSload:
+ return rewriteValuePPC64_OpPPC64FMOVSload(v, config)
+ case OpPPC64FMOVSstore:
+ return rewriteValuePPC64_OpPPC64FMOVSstore(v, config)
+ case OpPPC64GreaterEqual:
+ return rewriteValuePPC64_OpPPC64GreaterEqual(v, config)
+ case OpPPC64GreaterThan:
+ return rewriteValuePPC64_OpPPC64GreaterThan(v, config)
+ case OpPPC64LessEqual:
+ return rewriteValuePPC64_OpPPC64LessEqual(v, config)
+ case OpPPC64LessThan:
+ return rewriteValuePPC64_OpPPC64LessThan(v, config)
+ case OpPPC64MOVBZload:
+ return rewriteValuePPC64_OpPPC64MOVBZload(v, config)
+ case OpPPC64MOVBZreg:
+ return rewriteValuePPC64_OpPPC64MOVBZreg(v, config)
+ case OpPPC64MOVBreg:
+ return rewriteValuePPC64_OpPPC64MOVBreg(v, config)
+ case OpPPC64MOVBstore:
+ return rewriteValuePPC64_OpPPC64MOVBstore(v, config)
+ case OpPPC64MOVBstorezero:
+ return rewriteValuePPC64_OpPPC64MOVBstorezero(v, config)
+ case OpPPC64MOVDload:
+ return rewriteValuePPC64_OpPPC64MOVDload(v, config)
+ case OpPPC64MOVDstore:
+ return rewriteValuePPC64_OpPPC64MOVDstore(v, config)
+ case OpPPC64MOVDstorezero:
+ return rewriteValuePPC64_OpPPC64MOVDstorezero(v, config)
+ case OpPPC64MOVHZload:
+ return rewriteValuePPC64_OpPPC64MOVHZload(v, config)
+ case OpPPC64MOVHZreg:
+ return rewriteValuePPC64_OpPPC64MOVHZreg(v, config)
+ case OpPPC64MOVHload:
+ return rewriteValuePPC64_OpPPC64MOVHload(v, config)
+ case OpPPC64MOVHreg:
+ return rewriteValuePPC64_OpPPC64MOVHreg(v, config)
+ case OpPPC64MOVHstore:
+ return rewriteValuePPC64_OpPPC64MOVHstore(v, config)
+ case OpPPC64MOVHstorezero:
+ return rewriteValuePPC64_OpPPC64MOVHstorezero(v, config)
+ case OpPPC64MOVWZload:
+ return rewriteValuePPC64_OpPPC64MOVWZload(v, config)
+ case OpPPC64MOVWZreg:
+ return rewriteValuePPC64_OpPPC64MOVWZreg(v, config)
+ case OpPPC64MOVWload:
+ return rewriteValuePPC64_OpPPC64MOVWload(v, config)
+ case OpPPC64MOVWreg:
+ return rewriteValuePPC64_OpPPC64MOVWreg(v, config)
+ case OpPPC64MOVWstore:
+ return rewriteValuePPC64_OpPPC64MOVWstore(v, config)
+ case OpPPC64MOVWstorezero:
+ return rewriteValuePPC64_OpPPC64MOVWstorezero(v, config)
+ case OpPPC64MaskIfNotCarry:
+ return rewriteValuePPC64_OpPPC64MaskIfNotCarry(v, config)
+ case OpPPC64NotEqual:
+ return rewriteValuePPC64_OpPPC64NotEqual(v, config)
+ case OpPPC64OR:
+ return rewriteValuePPC64_OpPPC64OR(v, config)
+ case OpPPC64ORN:
+ return rewriteValuePPC64_OpPPC64ORN(v, config)
+ case OpPPC64ORconst:
+ return rewriteValuePPC64_OpPPC64ORconst(v, config)
+ case OpPPC64SUB:
+ return rewriteValuePPC64_OpPPC64SUB(v, config)
+ case OpPPC64XOR:
+ return rewriteValuePPC64_OpPPC64XOR(v, config)
+ case OpPPC64XORconst:
+ return rewriteValuePPC64_OpPPC64XORconst(v, config)
+ case OpRsh16Ux16:
+ return rewriteValuePPC64_OpRsh16Ux16(v, config)
+ case OpRsh16Ux32:
+ return rewriteValuePPC64_OpRsh16Ux32(v, config)
+ case OpRsh16Ux64:
+ return rewriteValuePPC64_OpRsh16Ux64(v, config)
+ case OpRsh16Ux8:
+ return rewriteValuePPC64_OpRsh16Ux8(v, config)
+ case OpRsh16x16:
+ return rewriteValuePPC64_OpRsh16x16(v, config)
+ case OpRsh16x32:
+ return rewriteValuePPC64_OpRsh16x32(v, config)
+ case OpRsh16x64:
+ return rewriteValuePPC64_OpRsh16x64(v, config)
+ case OpRsh16x8:
+ return rewriteValuePPC64_OpRsh16x8(v, config)
+ case OpRsh32Ux16:
+ return rewriteValuePPC64_OpRsh32Ux16(v, config)
+ case OpRsh32Ux32:
+ return rewriteValuePPC64_OpRsh32Ux32(v, config)
+ case OpRsh32Ux64:
+ return rewriteValuePPC64_OpRsh32Ux64(v, config)
+ case OpRsh32Ux8:
+ return rewriteValuePPC64_OpRsh32Ux8(v, config)
+ case OpRsh32x16:
+ return rewriteValuePPC64_OpRsh32x16(v, config)
+ case OpRsh32x32:
+ return rewriteValuePPC64_OpRsh32x32(v, config)
+ case OpRsh32x64:
+ return rewriteValuePPC64_OpRsh32x64(v, config)
+ case OpRsh32x8:
+ return rewriteValuePPC64_OpRsh32x8(v, config)
+ case OpRsh64Ux16:
+ return rewriteValuePPC64_OpRsh64Ux16(v, config)
+ case OpRsh64Ux32:
+ return rewriteValuePPC64_OpRsh64Ux32(v, config)
+ case OpRsh64Ux64:
+ return rewriteValuePPC64_OpRsh64Ux64(v, config)
+ case OpRsh64Ux8:
+ return rewriteValuePPC64_OpRsh64Ux8(v, config)
+ case OpRsh64x16:
+ return rewriteValuePPC64_OpRsh64x16(v, config)
+ case OpRsh64x32:
+ return rewriteValuePPC64_OpRsh64x32(v, config)
+ case OpRsh64x64:
+ return rewriteValuePPC64_OpRsh64x64(v, config)
+ case OpRsh64x8:
+ return rewriteValuePPC64_OpRsh64x8(v, config)
+ case OpRsh8Ux16:
+ return rewriteValuePPC64_OpRsh8Ux16(v, config)
+ case OpRsh8Ux32:
+ return rewriteValuePPC64_OpRsh8Ux32(v, config)
+ case OpRsh8Ux64:
+ return rewriteValuePPC64_OpRsh8Ux64(v, config)
+ case OpRsh8Ux8:
+ return rewriteValuePPC64_OpRsh8Ux8(v, config)
+ case OpRsh8x16:
+ return rewriteValuePPC64_OpRsh8x16(v, config)
+ case OpRsh8x32:
+ return rewriteValuePPC64_OpRsh8x32(v, config)
+ case OpRsh8x64:
+ return rewriteValuePPC64_OpRsh8x64(v, config)
+ case OpRsh8x8:
+ return rewriteValuePPC64_OpRsh8x8(v, config)
+ case OpSignExt16to32:
+ return rewriteValuePPC64_OpSignExt16to32(v, config)
+ case OpSignExt16to64:
+ return rewriteValuePPC64_OpSignExt16to64(v, config)
+ case OpSignExt32to64:
+ return rewriteValuePPC64_OpSignExt32to64(v, config)
+ case OpSignExt8to16:
+ return rewriteValuePPC64_OpSignExt8to16(v, config)
+ case OpSignExt8to32:
+ return rewriteValuePPC64_OpSignExt8to32(v, config)
+ case OpSignExt8to64:
+ return rewriteValuePPC64_OpSignExt8to64(v, config)
+ case OpSlicemask:
+ return rewriteValuePPC64_OpSlicemask(v, config)
+ case OpSqrt:
+ return rewriteValuePPC64_OpSqrt(v, config)
+ case OpStaticCall:
+ return rewriteValuePPC64_OpStaticCall(v, config)
+ case OpStore:
+ return rewriteValuePPC64_OpStore(v, config)
+ case OpSub16:
+ return rewriteValuePPC64_OpSub16(v, config)
+ case OpSub32:
+ return rewriteValuePPC64_OpSub32(v, config)
+ case OpSub32F:
+ return rewriteValuePPC64_OpSub32F(v, config)
+ case OpSub64:
+ return rewriteValuePPC64_OpSub64(v, config)
+ case OpSub64F:
+ return rewriteValuePPC64_OpSub64F(v, config)
+ case OpSub8:
+ return rewriteValuePPC64_OpSub8(v, config)
+ case OpSubPtr:
+ return rewriteValuePPC64_OpSubPtr(v, config)
+ case OpTrunc16to8:
+ return rewriteValuePPC64_OpTrunc16to8(v, config)
+ case OpTrunc32to16:
+ return rewriteValuePPC64_OpTrunc32to16(v, config)
+ case OpTrunc32to8:
+ return rewriteValuePPC64_OpTrunc32to8(v, config)
+ case OpTrunc64to16:
+ return rewriteValuePPC64_OpTrunc64to16(v, config)
+ case OpTrunc64to32:
+ return rewriteValuePPC64_OpTrunc64to32(v, config)
+ case OpTrunc64to8:
+ return rewriteValuePPC64_OpTrunc64to8(v, config)
+ case OpXor16:
+ return rewriteValuePPC64_OpXor16(v, config)
+ case OpXor32:
+ return rewriteValuePPC64_OpXor32(v, config)
+ case OpXor64:
+ return rewriteValuePPC64_OpXor64(v, config)
+ case OpXor8:
+ return rewriteValuePPC64_OpXor8(v, config)
+ case OpZero:
+ return rewriteValuePPC64_OpZero(v, config)
+ case OpZeroExt16to32:
+ return rewriteValuePPC64_OpZeroExt16to32(v, config)
+ case OpZeroExt16to64:
+ return rewriteValuePPC64_OpZeroExt16to64(v, config)
+ case OpZeroExt32to64:
+ return rewriteValuePPC64_OpZeroExt32to64(v, config)
+ case OpZeroExt8to16:
+ return rewriteValuePPC64_OpZeroExt8to16(v, config)
+ case OpZeroExt8to32:
+ return rewriteValuePPC64_OpZeroExt8to32(v, config)
+ case OpZeroExt8to64:
+ return rewriteValuePPC64_OpZeroExt8to64(v, config)
+ }
+ return false
+}
+func rewriteValuePPC64_OpAdd16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Add16 x y)
+ // cond:
+ // result: (ADD x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64ADD)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValuePPC64_OpAdd32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Add32 x y)
+ // cond:
+ // result: (ADD x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64ADD)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValuePPC64_OpAdd32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Add32F x y)
+ // cond:
+ // result: (FADDS x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64FADDS)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValuePPC64_OpAdd64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Add64 x y)
+ // cond:
+ // result: (ADD x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64ADD)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValuePPC64_OpAdd64F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Add64F x y)
+ // cond:
+ // result: (FADD x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64FADD)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValuePPC64_OpAdd8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Add8 x y)
+ // cond:
+ // result: (ADD x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64ADD)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValuePPC64_OpAddPtr(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (AddPtr x y)
+ // cond:
+ // result: (ADD x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64ADD)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValuePPC64_OpAddr(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Addr {sym} base)
+ // cond:
+ // result: (MOVDaddr {sym} base)
+ for {
+ sym := v.Aux
+ base := v.Args[0]
+ v.reset(OpPPC64MOVDaddr)
+ v.Aux = sym
+ v.AddArg(base)
+ return true
+ }
+}
+func rewriteValuePPC64_OpAnd16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (And16 x y)
+ // cond:
+ // result: (AND x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64AND)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValuePPC64_OpAnd32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (And32 x y)
+ // cond:
+ // result: (AND x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64AND)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValuePPC64_OpAnd64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (And64 x y)
+ // cond:
+ // result: (AND x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64AND)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValuePPC64_OpAnd8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (And8 x y)
+ // cond:
+ // result: (AND x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64AND)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValuePPC64_OpAndB(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (AndB x y)
+ // cond:
+ // result: (AND x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64AND)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValuePPC64_OpAvg64u(v *Value, config *Config) 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]))
+ for {
+ t := v.Type
+ 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)
+ v1.AddArg(x)
+ v2 := b.NewValue0(v.Line, OpPPC64MOVDconst, t)
+ v2.AuxInt = 1
+ v1.AddArg(v2)
+ 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)
+ return true
+ }
+}
+func rewriteValuePPC64_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(OpPPC64CALLclosure)
+ v.AuxInt = argwid
+ v.AddArg(entry)
+ v.AddArg(closure)
+ v.AddArg(mem)
+ return true
+ }
+}
+func rewriteValuePPC64_OpCom16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Com16 x)
+ // cond:
+ // result: (XORconst [-1] x)
+ for {
+ x := v.Args[0]
+ v.reset(OpPPC64XORconst)
+ v.AuxInt = -1
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValuePPC64_OpCom32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Com32 x)
+ // cond:
+ // result: (XORconst [-1] x)
+ for {
+ x := v.Args[0]
+ v.reset(OpPPC64XORconst)
+ v.AuxInt = -1
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValuePPC64_OpCom64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Com64 x)
+ // cond:
+ // result: (XORconst [-1] x)
+ for {
+ x := v.Args[0]
+ v.reset(OpPPC64XORconst)
+ v.AuxInt = -1
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValuePPC64_OpCom8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Com8 x)
+ // cond:
+ // result: (XORconst [-1] x)
+ for {
+ x := v.Args[0]
+ v.reset(OpPPC64XORconst)
+ v.AuxInt = -1
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValuePPC64_OpConst16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Const16 [val])
+ // cond:
+ // result: (MOVDconst [val])
+ for {
+ val := v.AuxInt
+ v.reset(OpPPC64MOVDconst)
+ v.AuxInt = val
+ return true
+ }
+}
+func rewriteValuePPC64_OpConst32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Const32 [val])
+ // cond:
+ // result: (MOVDconst [val])
+ for {
+ val := v.AuxInt
+ v.reset(OpPPC64MOVDconst)
+ v.AuxInt = val
+ return true
+ }
+}
+func rewriteValuePPC64_OpConst32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Const32F [val])
+ // cond:
+ // result: (FMOVSconst [val])
+ for {
+ val := v.AuxInt
+ v.reset(OpPPC64FMOVSconst)
+ v.AuxInt = val
+ return true
+ }
+}
+func rewriteValuePPC64_OpConst64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Const64 [val])
+ // cond:
+ // result: (MOVDconst [val])
+ for {
+ val := v.AuxInt
+ v.reset(OpPPC64MOVDconst)
+ v.AuxInt = val
+ return true
+ }
+}
+func rewriteValuePPC64_OpConst64F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Const64F [val])
+ // cond:
+ // result: (FMOVDconst [val])
+ for {
+ val := v.AuxInt
+ v.reset(OpPPC64FMOVDconst)
+ v.AuxInt = val
+ return true
+ }
+}
+func rewriteValuePPC64_OpConst8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Const8 [val])
+ // cond:
+ // result: (MOVDconst [val])
+ for {
+ val := v.AuxInt
+ v.reset(OpPPC64MOVDconst)
+ v.AuxInt = val
+ return true
+ }
+}
+func rewriteValuePPC64_OpConstBool(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ConstBool [b])
+ // cond:
+ // result: (MOVDconst [b])
+ for {
+ b := v.AuxInt
+ v.reset(OpPPC64MOVDconst)
+ v.AuxInt = b
+ return true
+ }
+}
+func rewriteValuePPC64_OpConstNil(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ConstNil)
+ // cond:
+ // result: (MOVDconst [0])
+ for {
+ v.reset(OpPPC64MOVDconst)
+ v.AuxInt = 0
+ return true
+ }
+}
+func rewriteValuePPC64_OpConvert(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Convert <t> x mem)
+ // cond:
+ // result: (MOVDconvert <t> x mem)
+ for {
+ t := v.Type
+ x := v.Args[0]
+ mem := v.Args[1]
+ v.reset(OpPPC64MOVDconvert)
+ v.Type = t
+ v.AddArg(x)
+ v.AddArg(mem)
+ return true
+ }
+}
+func rewriteValuePPC64_OpCvt32Fto32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValuePPC64_OpCvt32Fto64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValuePPC64_OpCvt32Fto64F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Cvt32Fto64F x)
+ // cond:
+ // result: x
+ for {
+ x := v.Args[0]
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValuePPC64_OpCvt32to32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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())
+ v2.AddArg(x)
+ v1.AddArg(v2)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValuePPC64_OpCvt32to64F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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())
+ v1.AddArg(x)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValuePPC64_OpCvt64Fto32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValuePPC64_OpCvt64Fto32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Cvt64Fto32F x)
+ // cond:
+ // result: (FRSP x)
+ for {
+ x := v.Args[0]
+ v.reset(OpPPC64FRSP)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValuePPC64_OpCvt64Fto64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValuePPC64_OpCvt64to32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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())
+ v1.AddArg(x)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValuePPC64_OpCvt64to64F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValuePPC64_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(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))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64DIVW)
+ v0 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
+ v1.AddArg(y)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValuePPC64_OpDiv16u(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Div16u x y)
+ // cond:
+ // result: (DIVWU (ZeroExt16to32 x) (ZeroExt16to32 y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64DIVWU)
+ v0 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+ v1.AddArg(y)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValuePPC64_OpDiv32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Div32 x y)
+ // cond:
+ // result: (DIVW x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64DIVW)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValuePPC64_OpDiv32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Div32F x y)
+ // cond:
+ // result: (FDIVS x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64FDIVS)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValuePPC64_OpDiv32u(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Div32u x y)
+ // cond:
+ // result: (DIVWU x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64DIVWU)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValuePPC64_OpDiv64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Div64 x y)
+ // cond:
+ // result: (DIVD x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64DIVD)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValuePPC64_OpDiv64F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Div64F x y)
+ // cond:
+ // result: (FDIV x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64FDIV)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValuePPC64_OpDiv64u(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Div64u x y)
+ // cond:
+ // result: (DIVDU x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64DIVDU)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValuePPC64_OpDiv8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Div8 x y)
+ // cond:
+ // result: (DIVW (SignExt8to32 x) (SignExt8to32 y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64DIVW)
+ v0 := b.NewValue0(v.Line, OpSignExt8to32, config.fe.TypeInt32())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpSignExt8to32, config.fe.TypeInt32())
+ v1.AddArg(y)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValuePPC64_OpDiv8u(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Div8u x y)
+ // cond:
+ // result: (DIVWU (ZeroExt8to32 x) (ZeroExt8to32 y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64DIVWU)
+ v0 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+ v1.AddArg(y)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValuePPC64_OpEq16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Eq16 x y)
+ // cond: isSigned(x.Type) && isSigned(y.Type)
+ // result: (Equal (CMPW (SignExt16to32 x) (SignExt16to32 y)))
+ for {
+ 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())
+ 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
+ }
+ // match: (Eq16 x y)
+ // cond:
+ // result: (Equal (CMPW (ZeroExt16to32 x) (ZeroExt16to32 y)))
+ for {
+ 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())
+ 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 rewriteValuePPC64_OpEq32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Eq32 x y)
+ // cond:
+ // result: (Equal (CMPW x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64Equal)
+ v0 := b.NewValue0(v.Line, OpPPC64CMPW, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValuePPC64_OpEq32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Eq32F x y)
+ // cond:
+ // result: (Equal (FCMPU x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64Equal)
+ v0 := b.NewValue0(v.Line, OpPPC64FCMPU, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValuePPC64_OpEq64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Eq64 x y)
+ // cond:
+ // result: (Equal (CMP x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64Equal)
+ v0 := b.NewValue0(v.Line, OpPPC64CMP, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValuePPC64_OpEq64F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Eq64F x y)
+ // cond:
+ // result: (Equal (FCMPU x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64Equal)
+ v0 := b.NewValue0(v.Line, OpPPC64FCMPU, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValuePPC64_OpEq8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Eq8 x y)
+ // cond: isSigned(x.Type) && isSigned(y.Type)
+ // result: (Equal (CMPW (SignExt8to32 x) (SignExt8to32 y)))
+ for {
+ 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())
+ 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
+ }
+ // match: (Eq8 x y)
+ // cond:
+ // result: (Equal (CMPW (ZeroExt8to32 x) (ZeroExt8to32 y)))
+ for {
+ 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())
+ 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_OpEqB(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (EqB x y)
+ // cond:
+ // result: (ANDconst [1] (EQV x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64ANDconst)
+ v.AuxInt = 1
+ v0 := b.NewValue0(v.Line, OpPPC64EQV, config.fe.TypeInt64())
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValuePPC64_OpEqPtr(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (EqPtr x y)
+ // cond:
+ // result: (Equal (CMP x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64Equal)
+ v0 := b.NewValue0(v.Line, OpPPC64CMP, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValuePPC64_OpGeq16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Geq16 x y)
+ // cond:
+ // result: (GreaterEqual (CMPW (SignExt16to32 x) (SignExt16to32 y)))
+ for {
+ 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())
+ 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_OpGeq16U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Geq16U x y)
+ // cond:
+ // result: (GreaterEqual (CMPU (ZeroExt16to32 x) (ZeroExt16to32 y)))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64GreaterEqual)
+ v0 := b.NewValue0(v.Line, OpPPC64CMPU, TypeFlags)
+ 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 rewriteValuePPC64_OpGeq32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Geq32 x y)
+ // cond:
+ // result: (GreaterEqual (CMPW x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64GreaterEqual)
+ v0 := b.NewValue0(v.Line, OpPPC64CMPW, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValuePPC64_OpGeq32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Geq32F x y)
+ // cond:
+ // result: (FGreaterEqual (FCMPU x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64FGreaterEqual)
+ v0 := b.NewValue0(v.Line, OpPPC64FCMPU, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValuePPC64_OpGeq32U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Geq32U x y)
+ // cond:
+ // result: (GreaterEqual (CMPU x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64GreaterEqual)
+ v0 := b.NewValue0(v.Line, OpPPC64CMPU, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValuePPC64_OpGeq64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Geq64 x y)
+ // cond:
+ // result: (GreaterEqual (CMP x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64GreaterEqual)
+ v0 := b.NewValue0(v.Line, OpPPC64CMP, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValuePPC64_OpGeq64F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Geq64F x y)
+ // cond:
+ // result: (FGreaterEqual (FCMPU x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64FGreaterEqual)
+ v0 := b.NewValue0(v.Line, OpPPC64FCMPU, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValuePPC64_OpGeq64U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Geq64U x y)
+ // cond:
+ // result: (GreaterEqual (CMPU x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64GreaterEqual)
+ v0 := b.NewValue0(v.Line, OpPPC64CMPU, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValuePPC64_OpGeq8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Geq8 x y)
+ // cond:
+ // result: (GreaterEqual (CMPW (SignExt8to32 x) (SignExt8to32 y)))
+ for {
+ 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())
+ 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_OpGeq8U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Geq8U x y)
+ // cond:
+ // result: (GreaterEqual (CMPU (ZeroExt8to32 x) (ZeroExt8to32 y)))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64GreaterEqual)
+ v0 := b.NewValue0(v.Line, OpPPC64CMPU, 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_OpGetClosurePtr(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (GetClosurePtr)
+ // cond:
+ // result: (LoweredGetClosurePtr)
+ for {
+ v.reset(OpPPC64LoweredGetClosurePtr)
+ 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 {
+ b := v.Block
+ _ = b
+ // match: (Greater16 x y)
+ // cond:
+ // result: (GreaterThan (CMPW (SignExt16to32 x) (SignExt16to32 y)))
+ for {
+ 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())
+ 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_OpGreater16U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Greater16U x y)
+ // cond:
+ // result: (GreaterThan (CMPWU (ZeroExt16to32 x) (ZeroExt16to32 y)))
+ for {
+ 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())
+ 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 rewriteValuePPC64_OpGreater32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Greater32 x y)
+ // cond:
+ // result: (GreaterThan (CMPW x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64GreaterThan)
+ v0 := b.NewValue0(v.Line, OpPPC64CMPW, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValuePPC64_OpGreater32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Greater32F x y)
+ // cond:
+ // result: (FGreaterThan (FCMPU x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64FGreaterThan)
+ v0 := b.NewValue0(v.Line, OpPPC64FCMPU, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValuePPC64_OpGreater32U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Greater32U x y)
+ // cond:
+ // result: (GreaterThan (CMPWU x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64GreaterThan)
+ v0 := b.NewValue0(v.Line, OpPPC64CMPWU, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValuePPC64_OpGreater64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Greater64 x y)
+ // cond:
+ // result: (GreaterThan (CMP x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64GreaterThan)
+ v0 := b.NewValue0(v.Line, OpPPC64CMP, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValuePPC64_OpGreater64F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Greater64F x y)
+ // cond:
+ // result: (FGreaterThan (FCMPU x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64FGreaterThan)
+ v0 := b.NewValue0(v.Line, OpPPC64FCMPU, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValuePPC64_OpGreater64U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Greater64U x y)
+ // cond:
+ // result: (GreaterThan (CMPU x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64GreaterThan)
+ v0 := b.NewValue0(v.Line, OpPPC64CMPU, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValuePPC64_OpGreater8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Greater8 x y)
+ // cond:
+ // result: (GreaterThan (CMPW (SignExt8to32 x) (SignExt8to32 y)))
+ for {
+ 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())
+ 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_OpGreater8U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Greater8U x y)
+ // cond:
+ // result: (GreaterThan (CMPWU (ZeroExt8to32 x) (ZeroExt8to32 y)))
+ for {
+ 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())
+ 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 rewriteValuePPC64_OpHmul32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Hmul32 x y)
+ // cond:
+ // result: (MULHW x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64MULHW)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValuePPC64_OpHmul32u(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Hmul32u x y)
+ // cond:
+ // result: (MULHWU x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64MULHWU)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValuePPC64_OpHmul64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Hmul64 x y)
+ // cond:
+ // result: (MULHD x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64MULHD)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValuePPC64_OpHmul64u(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Hmul64u x y)
+ // cond:
+ // result: (MULHDU x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64MULHDU)
+ v.AddArg(x)
+ v.AddArg(y)
+ 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
+ // 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(OpPPC64CALLinter)
+ v.AuxInt = argwid
+ v.AddArg(entry)
+ v.AddArg(mem)
+ return true
+ }
+}
+func rewriteValuePPC64_OpIsInBounds(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (IsInBounds idx len)
+ // cond:
+ // result: (LessThan (CMPU idx len))
+ for {
+ idx := v.Args[0]
+ len := v.Args[1]
+ v.reset(OpPPC64LessThan)
+ v0 := b.NewValue0(v.Line, OpPPC64CMPU, TypeFlags)
+ v0.AddArg(idx)
+ v0.AddArg(len)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValuePPC64_OpIsNonNil(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (IsNonNil ptr)
+ // cond:
+ // result: (NotEqual (CMPconst [0] ptr))
+ for {
+ ptr := v.Args[0]
+ v.reset(OpPPC64NotEqual)
+ v0 := b.NewValue0(v.Line, OpPPC64CMPconst, TypeFlags)
+ v0.AuxInt = 0
+ v0.AddArg(ptr)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValuePPC64_OpIsSliceInBounds(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (IsSliceInBounds idx len)
+ // cond:
+ // result: (LessEqual (CMPU idx len))
+ for {
+ idx := v.Args[0]
+ len := v.Args[1]
+ v.reset(OpPPC64LessEqual)
+ v0 := b.NewValue0(v.Line, OpPPC64CMPU, TypeFlags)
+ v0.AddArg(idx)
+ v0.AddArg(len)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValuePPC64_OpLeq16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Leq16 x y)
+ // cond:
+ // result: (LessEqual (CMPW (SignExt16to32 x) (SignExt16to32 y)))
+ for {
+ 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())
+ 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_OpLeq16U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Leq16U x y)
+ // cond:
+ // result: (LessEqual (CMPWU (ZeroExt16to32 x) (ZeroExt16to32 y)))
+ for {
+ 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())
+ 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 rewriteValuePPC64_OpLeq32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Leq32 x y)
+ // cond:
+ // result: (LessEqual (CMPW x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64LessEqual)
+ v0 := b.NewValue0(v.Line, OpPPC64CMPW, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValuePPC64_OpLeq32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Leq32F x y)
+ // cond:
+ // result: (FLessEqual (FCMPU x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64FLessEqual)
+ v0 := b.NewValue0(v.Line, OpPPC64FCMPU, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValuePPC64_OpLeq32U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Leq32U x y)
+ // cond:
+ // result: (LessEqual (CMPWU x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64LessEqual)
+ v0 := b.NewValue0(v.Line, OpPPC64CMPWU, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValuePPC64_OpLeq64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Leq64 x y)
+ // cond:
+ // result: (LessEqual (CMP x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64LessEqual)
+ v0 := b.NewValue0(v.Line, OpPPC64CMP, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValuePPC64_OpLeq64F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Leq64F x y)
+ // cond:
+ // result: (FLessEqual (FCMPU x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64FLessEqual)
+ v0 := b.NewValue0(v.Line, OpPPC64FCMPU, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValuePPC64_OpLeq64U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Leq64U x y)
+ // cond:
+ // result: (LessEqual (CMPU x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64LessEqual)
+ v0 := b.NewValue0(v.Line, OpPPC64CMPU, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValuePPC64_OpLeq8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Leq8 x y)
+ // cond:
+ // result: (LessEqual (CMPW (SignExt8to32 x) (SignExt8to32 y)))
+ for {
+ 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())
+ 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_OpLeq8U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Leq8U x y)
+ // cond:
+ // result: (LessEqual (CMPWU (ZeroExt8to32 x) (ZeroExt8to32 y)))
+ for {
+ 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())
+ 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_OpLess16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Less16 x y)
+ // cond:
+ // result: (LessThan (CMPW (SignExt16to32 x) (SignExt16to32 y)))
+ for {
+ 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())
+ 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_OpLess16U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Less16U x y)
+ // cond:
+ // result: (LessThan (CMPWU (ZeroExt16to32 x) (ZeroExt16to32 y)))
+ for {
+ 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())
+ 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 rewriteValuePPC64_OpLess32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Less32 x y)
+ // cond:
+ // result: (LessThan (CMPW x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64LessThan)
+ v0 := b.NewValue0(v.Line, OpPPC64CMPW, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValuePPC64_OpLess32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Less32F x y)
+ // cond:
+ // result: (FLessThan (FCMPU x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64FLessThan)
+ v0 := b.NewValue0(v.Line, OpPPC64FCMPU, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValuePPC64_OpLess32U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Less32U x y)
+ // cond:
+ // result: (LessThan (CMPWU x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64LessThan)
+ v0 := b.NewValue0(v.Line, OpPPC64CMPWU, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValuePPC64_OpLess64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Less64 x y)
+ // cond:
+ // result: (LessThan (CMP x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64LessThan)
+ v0 := b.NewValue0(v.Line, OpPPC64CMP, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValuePPC64_OpLess64F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Less64F x y)
+ // cond:
+ // result: (FLessThan (FCMPU x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64FLessThan)
+ v0 := b.NewValue0(v.Line, OpPPC64FCMPU, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValuePPC64_OpLess64U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Less64U x y)
+ // cond:
+ // result: (LessThan (CMPU x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64LessThan)
+ v0 := b.NewValue0(v.Line, OpPPC64CMPU, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValuePPC64_OpLess8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Less8 x y)
+ // cond:
+ // result: (LessThan (CMPW (SignExt8to32 x) (SignExt8to32 y)))
+ for {
+ 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())
+ 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_OpLess8U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Less8U x y)
+ // cond:
+ // result: (LessThan (CMPWU (ZeroExt8to32 x) (ZeroExt8to32 y)))
+ for {
+ 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())
+ 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_OpLoad(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Load <t> ptr mem)
+ // cond: (is64BitInt(t) || isPtr(t))
+ // result: (MOVDload ptr mem)
+ for {
+ t := v.Type
+ ptr := v.Args[0]
+ mem := v.Args[1]
+ if !(is64BitInt(t) || isPtr(t)) {
+ break
+ }
+ v.reset(OpPPC64MOVDload)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (Load <t> ptr mem)
+ // cond: is32BitInt(t) && isSigned(t)
+ // result: (MOVWload ptr mem)
+ for {
+ t := v.Type
+ ptr := v.Args[0]
+ mem := v.Args[1]
+ if !(is32BitInt(t) && isSigned(t)) {
+ break
+ }
+ v.reset(OpPPC64MOVWload)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (Load <t> ptr mem)
+ // cond: is32BitInt(t) && !isSigned(t)
+ // result: (MOVWZload ptr mem)
+ for {
+ t := v.Type
+ ptr := v.Args[0]
+ mem := v.Args[1]
+ if !(is32BitInt(t) && !isSigned(t)) {
+ break
+ }
+ v.reset(OpPPC64MOVWZload)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (Load <t> ptr mem)
+ // cond: is16BitInt(t) && isSigned(t)
+ // result: (MOVHload ptr mem)
+ for {
+ t := v.Type
+ ptr := v.Args[0]
+ mem := v.Args[1]
+ if !(is16BitInt(t) && isSigned(t)) {
+ break
+ }
+ v.reset(OpPPC64MOVHload)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (Load <t> ptr mem)
+ // cond: is16BitInt(t) && !isSigned(t)
+ // result: (MOVHZload ptr mem)
+ for {
+ t := v.Type
+ ptr := v.Args[0]
+ mem := v.Args[1]
+ if !(is16BitInt(t) && !isSigned(t)) {
+ break
+ }
+ v.reset(OpPPC64MOVHZload)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (Load <t> ptr mem)
+ // cond: t.IsBoolean()
+ // result: (MOVBZload ptr mem)
+ for {
+ t := v.Type
+ ptr := v.Args[0]
+ mem := v.Args[1]
+ if !(t.IsBoolean()) {
+ break
+ }
+ v.reset(OpPPC64MOVBZload)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (Load <t> ptr mem)
+ // cond: is8BitInt(t) && isSigned(t)
+ // result: (MOVBreg (MOVBZload ptr mem))
+ for {
+ t := v.Type
+ 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.AddArg(ptr)
+ v0.AddArg(mem)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (Load <t> ptr mem)
+ // cond: is8BitInt(t) && !isSigned(t)
+ // result: (MOVBZload ptr mem)
+ for {
+ t := v.Type
+ ptr := v.Args[0]
+ mem := v.Args[1]
+ if !(is8BitInt(t) && !isSigned(t)) {
+ break
+ }
+ v.reset(OpPPC64MOVBZload)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (Load <t> ptr mem)
+ // cond: is32BitFloat(t)
+ // result: (FMOVSload ptr mem)
+ for {
+ t := v.Type
+ ptr := v.Args[0]
+ mem := v.Args[1]
+ if !(is32BitFloat(t)) {
+ break
+ }
+ v.reset(OpPPC64FMOVSload)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (Load <t> ptr mem)
+ // cond: is64BitFloat(t)
+ // result: (FMOVDload ptr mem)
+ for {
+ t := v.Type
+ ptr := v.Args[0]
+ mem := v.Args[1]
+ if !(is64BitFloat(t)) {
+ break
+ }
+ v.reset(OpPPC64FMOVDload)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValuePPC64_OpLsh16x16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Lsh16x16 x y)
+ // cond:
+ // result: (SLW x (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-16] (ZeroExt16to64 y)))))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64SLW)
+ v.AddArg(x)
+ v0 := b.NewValue0(v.Line, OpPPC64ORN, config.fe.TypeInt64())
+ v0.AddArg(y)
+ v1 := b.NewValue0(v.Line, OpPPC64MaskIfNotCarry, config.fe.TypeInt64())
+ v2 := b.NewValue0(v.Line, OpPPC64ADDconstForCarry, TypeFlags)
+ v2.AuxInt = -16
+ v3 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+ v3.AddArg(y)
+ v2.AddArg(v3)
+ v1.AddArg(v2)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValuePPC64_OpLsh16x32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Lsh16x32 x (Const64 [c]))
+ // cond: uint32(c) < 16
+ // result: (SLWconst x [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpConst64 {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint32(c) < 16) {
+ break
+ }
+ v.reset(OpPPC64SLWconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (Lsh16x32 x (MOVDconst [c]))
+ // cond: uint32(c) < 16
+ // result: (SLWconst x [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpPPC64MOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint32(c) < 16) {
+ break
+ }
+ v.reset(OpPPC64SLWconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (Lsh16x32 x y)
+ // cond:
+ // result: (SLW x (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-16] (ZeroExt32to64 y)))))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64SLW)
+ v.AddArg(x)
+ v0 := b.NewValue0(v.Line, OpPPC64ORN, config.fe.TypeInt64())
+ v0.AddArg(y)
+ v1 := b.NewValue0(v.Line, OpPPC64MaskIfNotCarry, config.fe.TypeInt64())
+ v2 := b.NewValue0(v.Line, OpPPC64ADDconstForCarry, TypeFlags)
+ v2.AuxInt = -16
+ v3 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+ v3.AddArg(y)
+ v2.AddArg(v3)
+ v1.AddArg(v2)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValuePPC64_OpLsh16x64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Lsh16x64 x (Const64 [c]))
+ // cond: uint64(c) < 16
+ // result: (SLWconst x [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpConst64 {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint64(c) < 16) {
+ break
+ }
+ v.reset(OpPPC64SLWconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (Lsh16x64 _ (Const64 [c]))
+ // cond: uint64(c) >= 16
+ // result: (MOVDconst [0])
+ for {
+ v_1 := v.Args[1]
+ if v_1.Op != OpConst64 {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint64(c) >= 16) {
+ break
+ }
+ v.reset(OpPPC64MOVDconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (Lsh16x64 x (MOVDconst [c]))
+ // cond: uint64(c) < 16
+ // result: (SLWconst x [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpPPC64MOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint64(c) < 16) {
+ break
+ }
+ v.reset(OpPPC64SLWconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (Lsh16x64 x y)
+ // cond:
+ // result: (SLW x (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-16] y))))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64SLW)
+ v.AddArg(x)
+ v0 := b.NewValue0(v.Line, OpPPC64ORN, config.fe.TypeInt64())
+ v0.AddArg(y)
+ v1 := b.NewValue0(v.Line, OpPPC64MaskIfNotCarry, config.fe.TypeInt64())
+ v2 := b.NewValue0(v.Line, OpPPC64ADDconstForCarry, TypeFlags)
+ v2.AuxInt = -16
+ v2.AddArg(y)
+ v1.AddArg(v2)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValuePPC64_OpLsh16x8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Lsh16x8 x y)
+ // cond:
+ // result: (SLW x (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-16] (ZeroExt8to64 y)))))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64SLW)
+ v.AddArg(x)
+ v0 := b.NewValue0(v.Line, OpPPC64ORN, config.fe.TypeInt64())
+ v0.AddArg(y)
+ v1 := b.NewValue0(v.Line, OpPPC64MaskIfNotCarry, config.fe.TypeInt64())
+ v2 := b.NewValue0(v.Line, OpPPC64ADDconstForCarry, TypeFlags)
+ v2.AuxInt = -16
+ v3 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+ v3.AddArg(y)
+ v2.AddArg(v3)
+ v1.AddArg(v2)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValuePPC64_OpLsh32x16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Lsh32x16 x y)
+ // cond:
+ // result: (SLW x (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-32] (ZeroExt16to64 y)))))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64SLW)
+ v.AddArg(x)
+ v0 := b.NewValue0(v.Line, OpPPC64ORN, config.fe.TypeInt64())
+ v0.AddArg(y)
+ v1 := b.NewValue0(v.Line, OpPPC64MaskIfNotCarry, config.fe.TypeInt64())
+ v2 := b.NewValue0(v.Line, OpPPC64ADDconstForCarry, TypeFlags)
+ v2.AuxInt = -32
+ v3 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+ v3.AddArg(y)
+ v2.AddArg(v3)
+ v1.AddArg(v2)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValuePPC64_OpLsh32x32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Lsh32x32 x (Const64 [c]))
+ // cond: uint32(c) < 32
+ // result: (SLWconst x [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpConst64 {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint32(c) < 32) {
+ break
+ }
+ v.reset(OpPPC64SLWconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (Lsh32x32 x (MOVDconst [c]))
+ // cond: uint32(c) < 32
+ // result: (SLWconst x [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpPPC64MOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint32(c) < 32) {
+ break
+ }
+ v.reset(OpPPC64SLWconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (Lsh32x32 x y)
+ // cond:
+ // result: (SLW x (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-32] (ZeroExt32to64 y)))))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64SLW)
+ v.AddArg(x)
+ v0 := b.NewValue0(v.Line, OpPPC64ORN, config.fe.TypeInt64())
+ v0.AddArg(y)
+ v1 := b.NewValue0(v.Line, OpPPC64MaskIfNotCarry, config.fe.TypeInt64())
+ v2 := b.NewValue0(v.Line, OpPPC64ADDconstForCarry, TypeFlags)
+ v2.AuxInt = -32
+ v3 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+ v3.AddArg(y)
+ v2.AddArg(v3)
+ v1.AddArg(v2)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValuePPC64_OpLsh32x64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Lsh32x64 x (Const64 [c]))
+ // cond: uint64(c) < 32
+ // result: (SLWconst x [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpConst64 {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint64(c) < 32) {
+ break
+ }
+ v.reset(OpPPC64SLWconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (Lsh32x64 _ (Const64 [c]))
+ // cond: uint64(c) >= 32
+ // result: (MOVDconst [0])
+ for {
+ v_1 := v.Args[1]
+ if v_1.Op != OpConst64 {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint64(c) >= 32) {
+ break
+ }
+ v.reset(OpPPC64MOVDconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (Lsh32x64 x (MOVDconst [c]))
+ // cond: uint64(c) < 32
+ // result: (SLWconst x [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpPPC64MOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint64(c) < 32) {
+ break
+ }
+ v.reset(OpPPC64SLWconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (Lsh32x64 x y)
+ // cond:
+ // result: (SLW x (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-32] y))))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64SLW)
+ v.AddArg(x)
+ v0 := b.NewValue0(v.Line, OpPPC64ORN, config.fe.TypeInt64())
+ v0.AddArg(y)
+ v1 := b.NewValue0(v.Line, OpPPC64MaskIfNotCarry, config.fe.TypeInt64())
+ v2 := b.NewValue0(v.Line, OpPPC64ADDconstForCarry, TypeFlags)
+ v2.AuxInt = -32
+ v2.AddArg(y)
+ v1.AddArg(v2)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValuePPC64_OpLsh32x8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Lsh32x8 x y)
+ // cond:
+ // result: (SLW x (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-32] (ZeroExt8to64 y)))))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64SLW)
+ v.AddArg(x)
+ v0 := b.NewValue0(v.Line, OpPPC64ORN, config.fe.TypeInt64())
+ v0.AddArg(y)
+ v1 := b.NewValue0(v.Line, OpPPC64MaskIfNotCarry, config.fe.TypeInt64())
+ v2 := b.NewValue0(v.Line, OpPPC64ADDconstForCarry, TypeFlags)
+ v2.AuxInt = -32
+ v3 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+ v3.AddArg(y)
+ v2.AddArg(v3)
+ v1.AddArg(v2)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValuePPC64_OpLsh64x16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Lsh64x16 x y)
+ // cond:
+ // result: (SLD x (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-64] (ZeroExt16to64 y)))))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64SLD)
+ v.AddArg(x)
+ v0 := b.NewValue0(v.Line, OpPPC64ORN, config.fe.TypeInt64())
+ v0.AddArg(y)
+ v1 := b.NewValue0(v.Line, OpPPC64MaskIfNotCarry, config.fe.TypeInt64())
+ v2 := b.NewValue0(v.Line, OpPPC64ADDconstForCarry, TypeFlags)
+ v2.AuxInt = -64
+ v3 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+ v3.AddArg(y)
+ v2.AddArg(v3)
+ v1.AddArg(v2)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValuePPC64_OpLsh64x32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Lsh64x32 x (Const64 [c]))
+ // cond: uint32(c) < 64
+ // result: (SLDconst x [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpConst64 {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint32(c) < 64) {
+ break
+ }
+ v.reset(OpPPC64SLDconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (Lsh64x32 x (MOVDconst [c]))
+ // cond: uint32(c) < 64
+ // result: (SLDconst x [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpPPC64MOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint32(c) < 64) {
+ break
+ }
+ v.reset(OpPPC64SLDconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (Lsh64x32 x y)
+ // cond:
+ // result: (SLD x (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-64] (ZeroExt32to64 y)))))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64SLD)
+ v.AddArg(x)
+ v0 := b.NewValue0(v.Line, OpPPC64ORN, config.fe.TypeInt64())
+ v0.AddArg(y)
+ v1 := b.NewValue0(v.Line, OpPPC64MaskIfNotCarry, config.fe.TypeInt64())
+ v2 := b.NewValue0(v.Line, OpPPC64ADDconstForCarry, TypeFlags)
+ v2.AuxInt = -64
+ v3 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+ v3.AddArg(y)
+ v2.AddArg(v3)
+ v1.AddArg(v2)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValuePPC64_OpLsh64x64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Lsh64x64 x (Const64 [c]))
+ // cond: uint64(c) < 64
+ // result: (SLDconst x [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpConst64 {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint64(c) < 64) {
+ break
+ }
+ v.reset(OpPPC64SLDconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (Lsh64x64 _ (Const64 [c]))
+ // cond: uint64(c) >= 64
+ // result: (MOVDconst [0])
+ for {
+ v_1 := v.Args[1]
+ if v_1.Op != OpConst64 {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint64(c) >= 64) {
+ break
+ }
+ v.reset(OpPPC64MOVDconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (Lsh64x64 x (MOVDconst [c]))
+ // cond: uint64(c) < 64
+ // result: (SLDconst x [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpPPC64MOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint64(c) < 64) {
+ break
+ }
+ v.reset(OpPPC64SLDconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (Lsh64x64 x y)
+ // cond:
+ // result: (SLD x (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-64] y))))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64SLD)
+ v.AddArg(x)
+ v0 := b.NewValue0(v.Line, OpPPC64ORN, config.fe.TypeInt64())
+ v0.AddArg(y)
+ v1 := b.NewValue0(v.Line, OpPPC64MaskIfNotCarry, config.fe.TypeInt64())
+ v2 := b.NewValue0(v.Line, OpPPC64ADDconstForCarry, TypeFlags)
+ v2.AuxInt = -64
+ v2.AddArg(y)
+ v1.AddArg(v2)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValuePPC64_OpLsh64x8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Lsh64x8 x y)
+ // cond:
+ // result: (SLD x (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-64] (ZeroExt8to64 y)))))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64SLD)
+ v.AddArg(x)
+ v0 := b.NewValue0(v.Line, OpPPC64ORN, config.fe.TypeInt64())
+ v0.AddArg(y)
+ v1 := b.NewValue0(v.Line, OpPPC64MaskIfNotCarry, config.fe.TypeInt64())
+ v2 := b.NewValue0(v.Line, OpPPC64ADDconstForCarry, TypeFlags)
+ v2.AuxInt = -64
+ v3 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+ v3.AddArg(y)
+ v2.AddArg(v3)
+ v1.AddArg(v2)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValuePPC64_OpLsh8x16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Lsh8x16 x y)
+ // cond:
+ // result: (SLW x (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-8] (ZeroExt16to64 y)))))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64SLW)
+ v.AddArg(x)
+ v0 := b.NewValue0(v.Line, OpPPC64ORN, config.fe.TypeInt64())
+ v0.AddArg(y)
+ v1 := b.NewValue0(v.Line, OpPPC64MaskIfNotCarry, config.fe.TypeInt64())
+ v2 := b.NewValue0(v.Line, OpPPC64ADDconstForCarry, TypeFlags)
+ v2.AuxInt = -8
+ v3 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+ v3.AddArg(y)
+ v2.AddArg(v3)
+ v1.AddArg(v2)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValuePPC64_OpLsh8x32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Lsh8x32 x (Const64 [c]))
+ // cond: uint32(c) < 8
+ // result: (SLWconst x [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpConst64 {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint32(c) < 8) {
+ break
+ }
+ v.reset(OpPPC64SLWconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (Lsh8x32 x (MOVDconst [c]))
+ // cond: uint32(c) < 8
+ // result: (SLWconst x [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpPPC64MOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint32(c) < 8) {
+ break
+ }
+ v.reset(OpPPC64SLWconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (Lsh8x32 x y)
+ // cond:
+ // result: (SLW x (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-8] (ZeroExt32to64 y)))))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64SLW)
+ v.AddArg(x)
+ v0 := b.NewValue0(v.Line, OpPPC64ORN, config.fe.TypeInt64())
+ v0.AddArg(y)
+ v1 := b.NewValue0(v.Line, OpPPC64MaskIfNotCarry, config.fe.TypeInt64())
+ v2 := b.NewValue0(v.Line, OpPPC64ADDconstForCarry, TypeFlags)
+ v2.AuxInt = -8
+ v3 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+ v3.AddArg(y)
+ v2.AddArg(v3)
+ v1.AddArg(v2)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValuePPC64_OpLsh8x64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Lsh8x64 x (Const64 [c]))
+ // cond: uint64(c) < 8
+ // result: (SLWconst x [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpConst64 {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint64(c) < 8) {
+ break
+ }
+ v.reset(OpPPC64SLWconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (Lsh8x64 _ (Const64 [c]))
+ // cond: uint64(c) >= 8
+ // result: (MOVDconst [0])
+ for {
+ v_1 := v.Args[1]
+ if v_1.Op != OpConst64 {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint64(c) >= 8) {
+ break
+ }
+ v.reset(OpPPC64MOVDconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (Lsh8x64 x (MOVDconst [c]))
+ // cond: uint64(c) < 8
+ // result: (SLWconst x [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpPPC64MOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint64(c) < 8) {
+ break
+ }
+ v.reset(OpPPC64SLWconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (Lsh8x64 x y)
+ // cond:
+ // result: (SLW x (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-8] y))))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64SLW)
+ v.AddArg(x)
+ v0 := b.NewValue0(v.Line, OpPPC64ORN, config.fe.TypeInt64())
+ v0.AddArg(y)
+ v1 := b.NewValue0(v.Line, OpPPC64MaskIfNotCarry, config.fe.TypeInt64())
+ v2 := b.NewValue0(v.Line, OpPPC64ADDconstForCarry, TypeFlags)
+ v2.AuxInt = -8
+ v2.AddArg(y)
+ v1.AddArg(v2)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValuePPC64_OpLsh8x8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Lsh8x8 x y)
+ // cond:
+ // result: (SLW x (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-8] (ZeroExt8to64 y)))))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64SLW)
+ v.AddArg(x)
+ v0 := b.NewValue0(v.Line, OpPPC64ORN, config.fe.TypeInt64())
+ v0.AddArg(y)
+ v1 := b.NewValue0(v.Line, OpPPC64MaskIfNotCarry, config.fe.TypeInt64())
+ v2 := b.NewValue0(v.Line, OpPPC64ADDconstForCarry, TypeFlags)
+ v2.AuxInt = -8
+ v3 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+ v3.AddArg(y)
+ v2.AddArg(v3)
+ v1.AddArg(v2)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValuePPC64_OpMod16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Mod16 x y)
+ // cond:
+ // result: (Mod32 (SignExt16to32 x) (SignExt16to32 y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMod32)
+ v0 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
+ v1.AddArg(y)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValuePPC64_OpMod16u(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Mod16u x y)
+ // cond:
+ // result: (Mod32u (ZeroExt16to32 x) (ZeroExt16to32 y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMod32u)
+ v0 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+ v1.AddArg(y)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValuePPC64_OpMod32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Mod32 x y)
+ // cond:
+ // result: (SUB x (MULLW y (DIVW x y)))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64SUB)
+ v.AddArg(x)
+ v0 := b.NewValue0(v.Line, OpPPC64MULLW, config.fe.TypeInt32())
+ v0.AddArg(y)
+ v1 := b.NewValue0(v.Line, OpPPC64DIVW, config.fe.TypeInt32())
+ v1.AddArg(x)
+ v1.AddArg(y)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValuePPC64_OpMod32u(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Mod32u x y)
+ // cond:
+ // result: (SUB x (MULLW y (DIVWU x y)))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64SUB)
+ v.AddArg(x)
+ v0 := b.NewValue0(v.Line, OpPPC64MULLW, config.fe.TypeInt32())
+ v0.AddArg(y)
+ v1 := b.NewValue0(v.Line, OpPPC64DIVWU, config.fe.TypeInt32())
+ v1.AddArg(x)
+ v1.AddArg(y)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValuePPC64_OpMod64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Mod64 x y)
+ // cond:
+ // result: (SUB x (MULLD y (DIVD x y)))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64SUB)
+ v.AddArg(x)
+ v0 := b.NewValue0(v.Line, OpPPC64MULLD, config.fe.TypeInt64())
+ v0.AddArg(y)
+ v1 := b.NewValue0(v.Line, OpPPC64DIVD, config.fe.TypeInt64())
+ v1.AddArg(x)
+ v1.AddArg(y)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValuePPC64_OpMod64u(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Mod64u x y)
+ // cond:
+ // result: (SUB x (MULLD y (DIVDU x y)))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64SUB)
+ v.AddArg(x)
+ v0 := b.NewValue0(v.Line, OpPPC64MULLD, config.fe.TypeInt64())
+ v0.AddArg(y)
+ v1 := b.NewValue0(v.Line, OpPPC64DIVDU, config.fe.TypeInt64())
+ v1.AddArg(x)
+ v1.AddArg(y)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValuePPC64_OpMod8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Mod8 x y)
+ // cond:
+ // result: (Mod32 (SignExt8to32 x) (SignExt8to32 y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMod32)
+ v0 := b.NewValue0(v.Line, OpSignExt8to32, config.fe.TypeInt32())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpSignExt8to32, config.fe.TypeInt32())
+ v1.AddArg(y)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValuePPC64_OpMod8u(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Mod8u x y)
+ // cond:
+ // result: (Mod32u (ZeroExt8to32 x) (ZeroExt8to32 y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpMod32u)
+ v0 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+ v1.AddArg(y)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValuePPC64_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) {
+ 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 (MOVBZload src mem) mem)
+ for {
+ s := v.AuxInt
+ 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.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
+ // result: (MOVHstore dst (MOVHZload src mem) mem)
+ for {
+ s := v.AuxInt
+ 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.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))
+ for {
+ s := v.AuxInt
+ 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.AddArg(dst)
+ v0 := b.NewValue0(v.Line, OpPPC64MOVBZload, config.fe.TypeUInt8())
+ v0.AuxInt = 1
+ 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)
+ 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)
+ for {
+ s := v.AuxInt
+ dst := v.Args[0]
+ src := v.Args[1]
+ mem := v.Args[2]
+ if !(SizeAndAlign(s).Size() == 4 && SizeAndAlign(s).Align()%4 == 0) {
+ break
+ }
+ v.reset(OpPPC64MOVWstore)
+ v.AddArg(dst)
+ v0 := b.NewValue0(v.Line, OpPPC64MOVWload, config.fe.TypeInt32())
+ 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))
+ for {
+ s := v.AuxInt
+ 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.AddArg(dst)
+ v0 := b.NewValue0(v.Line, OpPPC64MOVHZload, config.fe.TypeUInt16())
+ v0.AuxInt = 2
+ v0.AddArg(src)
+ v0.AddArg(mem)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpPPC64MOVHstore, TypeMem)
+ v1.AddArg(dst)
+ v2 := b.NewValue0(v.Line, OpPPC64MOVHZload, config.fe.TypeUInt16())
+ v2.AddArg(src)
+ v2.AddArg(mem)
+ v1.AddArg(v2)
+ v1.AddArg(mem)
+ 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))))
+ for {
+ s := v.AuxInt
+ 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.AddArg(dst)
+ v0 := b.NewValue0(v.Line, OpPPC64MOVBZload, config.fe.TypeUInt8())
+ v0.AuxInt = 3
+ v0.AddArg(src)
+ v0.AddArg(mem)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpPPC64MOVBstore, TypeMem)
+ v1.AuxInt = 2
+ v1.AddArg(dst)
+ v2 := b.NewValue0(v.Line, OpPPC64MOVBZload, config.fe.TypeUInt8())
+ v2.AuxInt = 2
+ 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)
+ 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)
+ 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) {
+ 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
+ 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.AuxInt = 4
+ v.AddArg(dst)
+ v0 := b.NewValue0(v.Line, OpPPC64MOVWZload, config.fe.TypeUInt32())
+ v0.AuxInt = 4
+ v0.AddArg(src)
+ v0.AddArg(mem)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpPPC64MOVWstore, TypeMem)
+ v1.AddArg(dst)
+ v2 := b.NewValue0(v.Line, OpPPC64MOVWZload, config.fe.TypeUInt32())
+ v2.AddArg(src)
+ v2.AddArg(mem)
+ v1.AddArg(v2)
+ v1.AddArg(mem)
+ 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))))
+ for {
+ s := v.AuxInt
+ 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.AddArg(dst)
+ v0 := b.NewValue0(v.Line, OpPPC64MOVHZload, config.fe.TypeUInt16())
+ v0.AuxInt = 6
+ v0.AddArg(src)
+ v0.AddArg(mem)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpPPC64MOVHstore, TypeMem)
+ v1.AuxInt = 4
+ v1.AddArg(dst)
+ v2 := b.NewValue0(v.Line, OpPPC64MOVHZload, config.fe.TypeUInt16())
+ v2.AuxInt = 4
+ 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)
+ 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)))
+ for {
+ s := v.AuxInt
+ 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.AddArg(dst)
+ v0 := b.NewValue0(v.Line, OpPPC64MOVBZload, config.fe.TypeUInt8())
+ v0.AuxInt = 2
+ v0.AddArg(src)
+ v0.AddArg(mem)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpPPC64MOVBstore, TypeMem)
+ v1.AuxInt = 1
+ v1.AddArg(dst)
+ v2 := b.NewValue0(v.Line, OpPPC64MOVBZload, config.fe.TypeUInt8())
+ v2.AuxInt = 1
+ v2.AddArg(src)
+ v2.AddArg(mem)
+ v1.AddArg(v2)
+ v3 := b.NewValue0(v.Line, OpPPC64MOVBstore, TypeMem)
+ v3.AddArg(dst)
+ v4 := b.NewValue0(v.Line, OpPPC64MOVBZload, config.fe.TypeUInt8())
+ v4.AddArg(src)
+ v4.AddArg(mem)
+ v3.AddArg(v4)
+ v3.AddArg(mem)
+ v1.AddArg(v3)
+ v.AddArg(v1)
+ return true
+ }
+ // 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)
+ for {
+ s := v.AuxInt
+ dst := v.Args[0]
+ src := v.Args[1]
+ mem := v.Args[2]
+ if !((SizeAndAlign(s).Size() > 512 || config.noDuffDevice) || SizeAndAlign(s).Align()%8 != 0) {
+ break
+ }
+ v.reset(OpPPC64LoweredMove)
+ v.AuxInt = SizeAndAlign(s).Align()
+ 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)
+ // cond:
+ // result: (MULLW x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64MULLW)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValuePPC64_OpMul32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Mul32 x y)
+ // cond:
+ // result: (MULLW x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64MULLW)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValuePPC64_OpMul32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Mul32F x y)
+ // cond:
+ // result: (FMULS x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64FMULS)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValuePPC64_OpMul64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Mul64 x y)
+ // cond:
+ // result: (MULLD x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64MULLD)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValuePPC64_OpMul64F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Mul64F x y)
+ // cond:
+ // result: (FMUL x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64FMUL)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValuePPC64_OpMul8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Mul8 x y)
+ // cond:
+ // result: (MULLW x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64MULLW)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValuePPC64_OpNeg16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Neg16 x)
+ // cond:
+ // result: (NEG x)
+ for {
+ x := v.Args[0]
+ v.reset(OpPPC64NEG)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValuePPC64_OpNeg32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Neg32 x)
+ // cond:
+ // result: (NEG x)
+ for {
+ x := v.Args[0]
+ v.reset(OpPPC64NEG)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValuePPC64_OpNeg32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Neg32F x)
+ // cond:
+ // result: (FNEG x)
+ for {
+ x := v.Args[0]
+ v.reset(OpPPC64FNEG)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValuePPC64_OpNeg64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Neg64 x)
+ // cond:
+ // result: (NEG x)
+ for {
+ x := v.Args[0]
+ v.reset(OpPPC64NEG)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValuePPC64_OpNeg64F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Neg64F x)
+ // cond:
+ // result: (FNEG x)
+ for {
+ x := v.Args[0]
+ v.reset(OpPPC64FNEG)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValuePPC64_OpNeg8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Neg8 x)
+ // cond:
+ // result: (NEG x)
+ for {
+ x := v.Args[0]
+ v.reset(OpPPC64NEG)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValuePPC64_OpNeq16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Neq16 x y)
+ // cond: isSigned(x.Type) && isSigned(y.Type)
+ // result: (NotEqual (CMPW (SignExt16to32 x) (SignExt16to32 y)))
+ for {
+ 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())
+ 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
+ }
+ // match: (Neq16 x y)
+ // cond:
+ // result: (NotEqual (CMPW (ZeroExt16to32 x) (ZeroExt16to32 y)))
+ for {
+ 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())
+ 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 rewriteValuePPC64_OpNeq32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Neq32 x y)
+ // cond:
+ // result: (NotEqual (CMPW x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64NotEqual)
+ v0 := b.NewValue0(v.Line, OpPPC64CMPW, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValuePPC64_OpNeq32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Neq32F x y)
+ // cond:
+ // result: (NotEqual (FCMPU x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64NotEqual)
+ v0 := b.NewValue0(v.Line, OpPPC64FCMPU, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValuePPC64_OpNeq64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Neq64 x y)
+ // cond:
+ // result: (NotEqual (CMP x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64NotEqual)
+ v0 := b.NewValue0(v.Line, OpPPC64CMP, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValuePPC64_OpNeq64F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Neq64F x y)
+ // cond:
+ // result: (NotEqual (FCMPU x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64NotEqual)
+ v0 := b.NewValue0(v.Line, OpPPC64FCMPU, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValuePPC64_OpNeq8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Neq8 x y)
+ // cond: isSigned(x.Type) && isSigned(y.Type)
+ // result: (NotEqual (CMPW (SignExt8to32 x) (SignExt8to32 y)))
+ for {
+ 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())
+ 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
+ }
+ // match: (Neq8 x y)
+ // cond:
+ // result: (NotEqual (CMPW (ZeroExt8to32 x) (ZeroExt8to32 y)))
+ for {
+ 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())
+ 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_OpNeqB(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (NeqB x y)
+ // cond:
+ // result: (XOR x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64XOR)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValuePPC64_OpNeqPtr(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (NeqPtr x y)
+ // cond:
+ // result: (NotEqual (CMP x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64NotEqual)
+ v0 := b.NewValue0(v.Line, OpPPC64CMP, TypeFlags)
+ v0.AddArg(x)
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValuePPC64_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(OpPPC64LoweredNilCheck)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+}
+func rewriteValuePPC64_OpNot(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Not x)
+ // cond:
+ // result: (XORconst [1] x)
+ for {
+ x := v.Args[0]
+ v.reset(OpPPC64XORconst)
+ v.AuxInt = 1
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValuePPC64_OpOffPtr(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (OffPtr [off] ptr)
+ // cond:
+ // result: (ADD (MOVDconst <config.Frontend().TypeInt64()> [off]) ptr)
+ for {
+ off := v.AuxInt
+ ptr := v.Args[0]
+ v.reset(OpPPC64ADD)
+ v0 := b.NewValue0(v.Line, OpPPC64MOVDconst, config.Frontend().TypeInt64())
+ v0.AuxInt = off
+ v.AddArg(v0)
+ v.AddArg(ptr)
+ return true
+ }
+}
+func rewriteValuePPC64_OpOr16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Or16 x y)
+ // cond:
+ // result: (OR x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64OR)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValuePPC64_OpOr32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Or32 x y)
+ // cond:
+ // result: (OR x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64OR)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValuePPC64_OpOr64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Or64 x y)
+ // cond:
+ // result: (OR x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64OR)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValuePPC64_OpOr8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Or8 x y)
+ // cond:
+ // result: (OR x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64OR)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValuePPC64_OpOrB(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (OrB x y)
+ // cond:
+ // result: (OR x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64OR)
+ v.AddArg(x)
+ v.AddArg(y)
+ 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)
+ for {
+ 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
+ }
+ // match: (ADD x (MOVDconst [c]))
+ // cond: is32Bit(c)
+ // result: (ADDconst [c] x)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpPPC64MOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ 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
+ // match: (ADDconst [c] (ADDconst [d] x))
+ // cond: is32Bit(c+d)
+ // result: (ADDconst [c+d] x)
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpPPC64ADDconst {
+ break
+ }
+ d := v_0.AuxInt
+ x := v_0.Args[0]
+ if !(is32Bit(c + d)) {
+ break
+ }
+ v.reset(OpPPC64ADDconst)
+ v.AuxInt = c + d
+ v.AddArg(x)
+ return true
+ }
+ // match: (ADDconst [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: (ADDconst [c] (MOVDaddr [d] {sym} x))
+ // cond:
+ // result: (MOVDaddr [c+d] {sym} x)
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpPPC64MOVDaddr {
+ break
+ }
+ d := v_0.AuxInt
+ sym := v_0.Aux
+ x := v_0.Args[0]
+ v.reset(OpPPC64MOVDaddr)
+ v.AuxInt = c + d
+ v.Aux = sym
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValuePPC64_OpPPC64AND(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (AND x (XORconst [-1] y))
+ // cond:
+ // result: (ANDN x y)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpPPC64XORconst {
+ break
+ }
+ if v_1.AuxInt != -1 {
+ break
+ }
+ y := v_1.Args[0]
+ v.reset(OpPPC64ANDN)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (AND (MOVDconst [c]) (MOVDconst [d]))
+ // cond:
+ // result: (MOVDconst [c&d])
+ for {
+ 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: (AND x (MOVDconst [c]))
+ // cond: isU16Bit(c)
+ // result: (ANDconst [c] x)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpPPC64MOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ if !(isU16Bit(c)) {
+ break
+ }
+ v.reset(OpPPC64ANDconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (AND (MOVDconst [c]) x)
+ // cond: isU16Bit(c)
+ // result: (ANDconst [c] x)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpPPC64MOVDconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ if !(isU16Bit(c)) {
+ break
+ }
+ v.reset(OpPPC64ANDconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (AND (MOVDconst [c]) x:(MOVBZload _ _))
+ // cond:
+ // result: (ANDconst [c&0xFF] x)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpPPC64MOVDconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ if x.Op != OpPPC64MOVBZload {
+ break
+ }
+ 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 {
+ x := v.Args[0]
+ if x.Op != OpPPC64MOVBZload {
+ break
+ }
+ 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)
+ return true
+ }
+ return false
+}
+func rewriteValuePPC64_OpPPC64ANDconst(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ANDconst [c] (ANDconst [d] x))
+ // cond:
+ // result: (ANDconst [c&d] x)
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpPPC64ANDconst {
+ break
+ }
+ d := v_0.AuxInt
+ x := v_0.Args[0]
+ v.reset(OpPPC64ANDconst)
+ v.AuxInt = c & d
+ v.AddArg(x)
+ return true
+ }
+ // match: (ANDconst [-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: (ANDconst [0] _)
+ // cond:
+ // result: (MOVDconst [0])
+ for {
+ if v.AuxInt != 0 {
+ break
+ }
+ v.reset(OpPPC64MOVDconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (ANDconst [c] y:(MOVBZreg _))
+ // cond: c&0xFF == 0xFF
+ // result: y
+ for {
+ c := v.AuxInt
+ y := v.Args[0]
+ if y.Op != OpPPC64MOVBZreg {
+ break
+ }
+ if !(c&0xFF == 0xFF) {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = y.Type
+ v.AddArg(y)
+ return true
+ }
+ // match: (ANDconst [c] y:(MOVHZreg _))
+ // cond: c&0xFFFF == 0xFFFF
+ // result: y
+ for {
+ c := v.AuxInt
+ y := v.Args[0]
+ if y.Op != OpPPC64MOVHZreg {
+ break
+ }
+ if !(c&0xFFFF == 0xFFFF) {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = y.Type
+ v.AddArg(y)
+ return true
+ }
+ // match: (ANDconst [c] y:(MOVWZreg _))
+ // cond: c&0xFFFFFFFF == 0xFFFFFFFF
+ // result: y
+ for {
+ c := v.AuxInt
+ y := v.Args[0]
+ if y.Op != OpPPC64MOVWZreg {
+ break
+ }
+ if !(c&0xFFFFFFFF == 0xFFFFFFFF) {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = y.Type
+ v.AddArg(y)
+ return true
+ }
+ // match: (ANDconst [c] (MOVBZreg x))
+ // cond:
+ // result: (ANDconst [c&0xFF] x)
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpPPC64MOVBZreg {
+ break
+ }
+ x := v_0.Args[0]
+ v.reset(OpPPC64ANDconst)
+ v.AuxInt = c & 0xFF
+ v.AddArg(x)
+ return true
+ }
+ // match: (ANDconst [c] (MOVHZreg x))
+ // cond:
+ // result: (ANDconst [c&0xFFFF] x)
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpPPC64MOVHZreg {
+ break
+ }
+ x := v_0.Args[0]
+ v.reset(OpPPC64ANDconst)
+ v.AuxInt = c & 0xFFFF
+ v.AddArg(x)
+ return true
+ }
+ // match: (ANDconst [c] (MOVWZreg x))
+ // cond:
+ // result: (ANDconst [c&0xFFFFFFFF] x)
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpPPC64MOVWZreg {
+ break
+ }
+ x := v_0.Args[0]
+ v.reset(OpPPC64ANDconst)
+ v.AuxInt = c & 0xFFFFFFFF
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValuePPC64_OpPPC64CMP(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (CMP x (MOVDconst [c]))
+ // cond: is16Bit(c)
+ // result: (CMPconst x [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpPPC64MOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ if !(is16Bit(c)) {
+ break
+ }
+ v.reset(OpPPC64CMPconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (CMP (MOVDconst [c]) y)
+ // cond: is16Bit(c)
+ // result: (InvertFlags (CMPconst y [c]))
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpPPC64MOVDconst {
+ break
+ }
+ c := v_0.AuxInt
+ y := v.Args[1]
+ if !(is16Bit(c)) {
+ break
+ }
+ v.reset(OpPPC64InvertFlags)
+ v0 := b.NewValue0(v.Line, OpPPC64CMPconst, TypeFlags)
+ v0.AuxInt = c
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+ return false
+}
+func rewriteValuePPC64_OpPPC64CMPU(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (CMPU x (MOVDconst [c]))
+ // cond: isU16Bit(c)
+ // result: (CMPUconst x [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpPPC64MOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ if !(isU16Bit(c)) {
+ break
+ }
+ v.reset(OpPPC64CMPUconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (CMPU (MOVDconst [c]) y)
+ // cond: isU16Bit(c)
+ // result: (InvertFlags (CMPUconst y [c]))
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpPPC64MOVDconst {
+ break
+ }
+ c := v_0.AuxInt
+ y := v.Args[1]
+ if !(isU16Bit(c)) {
+ break
+ }
+ v.reset(OpPPC64InvertFlags)
+ v0 := b.NewValue0(v.Line, OpPPC64CMPUconst, TypeFlags)
+ v0.AuxInt = c
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+ return false
+}
+func rewriteValuePPC64_OpPPC64CMPUconst(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (CMPUconst (MOVDconst [x]) [y])
+ // cond: int64(x)==int64(y)
+ // result: (FlagEQ)
+ for {
+ y := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpPPC64MOVDconst {
+ break
+ }
+ x := v_0.AuxInt
+ if !(int64(x) == int64(y)) {
+ break
+ }
+ v.reset(OpPPC64FlagEQ)
+ return true
+ }
+ // match: (CMPUconst (MOVDconst [x]) [y])
+ // cond: uint64(x)<uint64(y)
+ // result: (FlagLT)
+ for {
+ y := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpPPC64MOVDconst {
+ break
+ }
+ x := v_0.AuxInt
+ if !(uint64(x) < uint64(y)) {
+ break
+ }
+ v.reset(OpPPC64FlagLT)
+ return true
+ }
+ // match: (CMPUconst (MOVDconst [x]) [y])
+ // cond: uint64(x)>uint64(y)
+ // result: (FlagGT)
+ for {
+ y := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpPPC64MOVDconst {
+ break
+ }
+ x := v_0.AuxInt
+ if !(uint64(x) > uint64(y)) {
+ break
+ }
+ v.reset(OpPPC64FlagGT)
+ return true
+ }
+ return false
+}
+func rewriteValuePPC64_OpPPC64CMPW(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (CMPW x (MOVWreg y))
+ // cond:
+ // result: (CMPW x y)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpPPC64MOVWreg {
+ break
+ }
+ y := v_1.Args[0]
+ v.reset(OpPPC64CMPW)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (CMPW (MOVWreg x) y)
+ // cond:
+ // result: (CMPW x y)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpPPC64MOVWreg {
+ break
+ }
+ x := v_0.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64CMPW)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (CMPW x (MOVDconst [c]))
+ // cond: is16Bit(c)
+ // result: (CMPWconst x [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpPPC64MOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ if !(is16Bit(c)) {
+ break
+ }
+ v.reset(OpPPC64CMPWconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (CMPW (MOVDconst [c]) y)
+ // cond: is16Bit(c)
+ // result: (InvertFlags (CMPWconst y [c]))
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpPPC64MOVDconst {
+ break
+ }
+ c := v_0.AuxInt
+ y := v.Args[1]
+ if !(is16Bit(c)) {
+ break
+ }
+ v.reset(OpPPC64InvertFlags)
+ v0 := b.NewValue0(v.Line, OpPPC64CMPWconst, TypeFlags)
+ v0.AuxInt = c
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+ return false
+}
+func rewriteValuePPC64_OpPPC64CMPWU(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (CMPWU x (MOVWZreg y))
+ // cond:
+ // result: (CMPWU x y)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpPPC64MOVWZreg {
+ break
+ }
+ y := v_1.Args[0]
+ v.reset(OpPPC64CMPWU)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (CMPWU (MOVWZreg x) y)
+ // cond:
+ // result: (CMPWU x y)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpPPC64MOVWZreg {
+ break
+ }
+ x := v_0.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64CMPWU)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (CMPWU x (MOVDconst [c]))
+ // cond: isU16Bit(c)
+ // result: (CMPWUconst x [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpPPC64MOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ if !(isU16Bit(c)) {
+ break
+ }
+ v.reset(OpPPC64CMPWUconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (CMPWU (MOVDconst [c]) y)
+ // cond: isU16Bit(c)
+ // result: (InvertFlags (CMPWUconst y [c]))
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpPPC64MOVDconst {
+ break
+ }
+ c := v_0.AuxInt
+ y := v.Args[1]
+ if !(isU16Bit(c)) {
+ break
+ }
+ v.reset(OpPPC64InvertFlags)
+ v0 := b.NewValue0(v.Line, OpPPC64CMPWUconst, TypeFlags)
+ v0.AuxInt = c
+ v0.AddArg(y)
+ v.AddArg(v0)
+ return true
+ }
+ return false
+}
+func rewriteValuePPC64_OpPPC64CMPWUconst(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (CMPWUconst (MOVDconst [x]) [y])
+ // cond: int32(x)==int32(y)
+ // result: (FlagEQ)
+ for {
+ y := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpPPC64MOVDconst {
+ break
+ }
+ x := v_0.AuxInt
+ if !(int32(x) == int32(y)) {
+ break
+ }
+ v.reset(OpPPC64FlagEQ)
+ return true
+ }
+ // match: (CMPWUconst (MOVDconst [x]) [y])
+ // cond: uint32(x)<uint32(y)
+ // result: (FlagLT)
+ for {
+ y := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpPPC64MOVDconst {
+ break
+ }
+ x := v_0.AuxInt
+ if !(uint32(x) < uint32(y)) {
+ break
+ }
+ v.reset(OpPPC64FlagLT)
+ return true
+ }
+ // match: (CMPWUconst (MOVDconst [x]) [y])
+ // cond: uint32(x)>uint32(y)
+ // result: (FlagGT)
+ for {
+ y := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpPPC64MOVDconst {
+ break
+ }
+ x := v_0.AuxInt
+ if !(uint32(x) > uint32(y)) {
+ break
+ }
+ v.reset(OpPPC64FlagGT)
+ return true
+ }
+ return false
+}
+func rewriteValuePPC64_OpPPC64CMPWconst(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (CMPWconst (MOVDconst [x]) [y])
+ // cond: int32(x)==int32(y)
+ // result: (FlagEQ)
+ for {
+ y := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpPPC64MOVDconst {
+ break
+ }
+ x := v_0.AuxInt
+ if !(int32(x) == int32(y)) {
+ break
+ }
+ v.reset(OpPPC64FlagEQ)
+ return true
+ }
+ // match: (CMPWconst (MOVDconst [x]) [y])
+ // cond: int32(x)<int32(y)
+ // result: (FlagLT)
+ for {
+ y := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpPPC64MOVDconst {
+ break
+ }
+ x := v_0.AuxInt
+ if !(int32(x) < int32(y)) {
+ break
+ }
+ v.reset(OpPPC64FlagLT)
+ return true
+ }
+ // match: (CMPWconst (MOVDconst [x]) [y])
+ // cond: int32(x)>int32(y)
+ // result: (FlagGT)
+ for {
+ y := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpPPC64MOVDconst {
+ break
+ }
+ x := v_0.AuxInt
+ if !(int32(x) > int32(y)) {
+ break
+ }
+ v.reset(OpPPC64FlagGT)
+ return true
+ }
+ return false
+}
+func rewriteValuePPC64_OpPPC64CMPconst(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (CMPconst (MOVDconst [x]) [y])
+ // cond: int64(x)==int64(y)
+ // result: (FlagEQ)
+ for {
+ y := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpPPC64MOVDconst {
+ break
+ }
+ x := v_0.AuxInt
+ if !(int64(x) == int64(y)) {
+ break
+ }
+ v.reset(OpPPC64FlagEQ)
+ return true
+ }
+ // match: (CMPconst (MOVDconst [x]) [y])
+ // cond: int64(x)<int64(y)
+ // result: (FlagLT)
+ for {
+ y := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpPPC64MOVDconst {
+ break
+ }
+ x := v_0.AuxInt
+ if !(int64(x) < int64(y)) {
+ break
+ }
+ v.reset(OpPPC64FlagLT)
+ return true
+ }
+ // match: (CMPconst (MOVDconst [x]) [y])
+ // cond: int64(x)>int64(y)
+ // result: (FlagGT)
+ for {
+ y := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpPPC64MOVDconst {
+ break
+ }
+ x := v_0.AuxInt
+ if !(int64(x) > int64(y)) {
+ break
+ }
+ v.reset(OpPPC64FlagGT)
+ return true
+ }
+ return false
+}
+func rewriteValuePPC64_OpPPC64Equal(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Equal (FlagEQ))
+ // cond:
+ // result: (MOVDconst [1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpPPC64FlagEQ {
+ break
+ }
+ v.reset(OpPPC64MOVDconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (Equal (FlagLT))
+ // cond:
+ // result: (MOVDconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpPPC64FlagLT {
+ break
+ }
+ v.reset(OpPPC64MOVDconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (Equal (FlagGT))
+ // cond:
+ // result: (MOVDconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpPPC64FlagGT {
+ break
+ }
+ v.reset(OpPPC64MOVDconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (Equal (InvertFlags x))
+ // cond:
+ // result: (Equal x)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpPPC64InvertFlags {
+ break
+ }
+ x := v_0.Args[0]
+ v.reset(OpPPC64Equal)
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValuePPC64_OpPPC64FMOVDload(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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_0 := v.Args[0]
+ if v_0.Op != OpPPC64MOVDaddr {
+ break
+ }
+ off2 := v_0.AuxInt
+ sym2 := v_0.Aux
+ ptr := v_0.Args[0]
+ mem := v.Args[1]
+ if !(canMergeSym(sym1, sym2)) {
+ break
+ }
+ v.reset(OpPPC64FMOVDload)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (FMOVDload [off1] {sym} (ADDconst [off2] ptr) mem)
+ // cond: is16Bit(off1+off2)
+ // result: (FMOVDload [off1+off2] {sym} ptr mem)
+ for {
+ off1 := v.AuxInt
+ sym := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpPPC64ADDconst {
+ break
+ }
+ off2 := v_0.AuxInt
+ ptr := v_0.Args[0]
+ mem := v.Args[1]
+ if !(is16Bit(off1 + off2)) {
+ break
+ }
+ v.reset(OpPPC64FMOVDload)
+ v.AuxInt = off1 + off2
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValuePPC64_OpPPC64FMOVDstore(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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_0 := v.Args[0]
+ if v_0.Op != OpPPC64ADDconst {
+ break
+ }
+ off2 := v_0.AuxInt
+ ptr := v_0.Args[0]
+ val := v.Args[1]
+ mem := v.Args[2]
+ if !(is16Bit(off1 + off2)) {
+ break
+ }
+ v.reset(OpPPC64FMOVDstore)
+ v.AuxInt = off1 + off2
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (FMOVDstore [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) val mem)
+ // cond: canMergeSym(sym1,sym2)
+ // result: (FMOVDstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
+ for {
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpPPC64MOVDaddr {
+ 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(OpPPC64FMOVDstore)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(ptr)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValuePPC64_OpPPC64FMOVSload(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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_0 := v.Args[0]
+ if v_0.Op != OpPPC64MOVDaddr {
+ break
+ }
+ off2 := v_0.AuxInt
+ sym2 := v_0.Aux
+ ptr := v_0.Args[0]
+ mem := v.Args[1]
+ if !(canMergeSym(sym1, sym2)) {
+ break
+ }
+ v.reset(OpPPC64FMOVSload)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (FMOVSload [off1] {sym} (ADDconst [off2] ptr) mem)
+ // cond: is16Bit(off1+off2)
+ // result: (FMOVSload [off1+off2] {sym} ptr mem)
+ for {
+ off1 := v.AuxInt
+ sym := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpPPC64ADDconst {
+ break
+ }
+ off2 := v_0.AuxInt
+ ptr := v_0.Args[0]
+ mem := v.Args[1]
+ if !(is16Bit(off1 + off2)) {
+ break
+ }
+ v.reset(OpPPC64FMOVSload)
+ v.AuxInt = off1 + off2
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValuePPC64_OpPPC64FMOVSstore(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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_0 := v.Args[0]
+ if v_0.Op != OpPPC64ADDconst {
+ break
+ }
+ off2 := v_0.AuxInt
+ ptr := v_0.Args[0]
+ val := v.Args[1]
+ mem := v.Args[2]
+ if !(is16Bit(off1 + off2)) {
+ break
+ }
+ v.reset(OpPPC64FMOVSstore)
+ v.AuxInt = off1 + off2
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (FMOVSstore [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) val mem)
+ // cond: canMergeSym(sym1,sym2)
+ // result: (FMOVSstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
+ for {
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpPPC64MOVDaddr {
+ 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(OpPPC64FMOVSstore)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(ptr)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValuePPC64_OpPPC64GreaterEqual(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (GreaterEqual (FlagEQ))
+ // cond:
+ // result: (MOVDconst [1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpPPC64FlagEQ {
+ break
+ }
+ v.reset(OpPPC64MOVDconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (GreaterEqual (FlagLT))
+ // cond:
+ // result: (MOVDconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpPPC64FlagLT {
+ break
+ }
+ v.reset(OpPPC64MOVDconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (GreaterEqual (FlagGT))
+ // cond:
+ // result: (MOVDconst [1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpPPC64FlagGT {
+ break
+ }
+ v.reset(OpPPC64MOVDconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (GreaterEqual (InvertFlags x))
+ // cond:
+ // result: (LessEqual x)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpPPC64InvertFlags {
+ break
+ }
+ x := v_0.Args[0]
+ v.reset(OpPPC64LessEqual)
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValuePPC64_OpPPC64GreaterThan(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (GreaterThan (FlagEQ))
+ // cond:
+ // result: (MOVDconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpPPC64FlagEQ {
+ break
+ }
+ v.reset(OpPPC64MOVDconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (GreaterThan (FlagLT))
+ // cond:
+ // result: (MOVDconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpPPC64FlagLT {
+ break
+ }
+ v.reset(OpPPC64MOVDconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (GreaterThan (FlagGT))
+ // cond:
+ // result: (MOVDconst [1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpPPC64FlagGT {
+ break
+ }
+ v.reset(OpPPC64MOVDconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (GreaterThan (InvertFlags x))
+ // cond:
+ // result: (LessThan x)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpPPC64InvertFlags {
+ break
+ }
+ x := v_0.Args[0]
+ v.reset(OpPPC64LessThan)
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValuePPC64_OpPPC64LessEqual(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (LessEqual (FlagEQ))
+ // cond:
+ // result: (MOVDconst [1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpPPC64FlagEQ {
+ break
+ }
+ v.reset(OpPPC64MOVDconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (LessEqual (FlagLT))
+ // cond:
+ // result: (MOVDconst [1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpPPC64FlagLT {
+ break
+ }
+ v.reset(OpPPC64MOVDconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (LessEqual (FlagGT))
+ // cond:
+ // result: (MOVDconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpPPC64FlagGT {
+ break
+ }
+ v.reset(OpPPC64MOVDconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (LessEqual (InvertFlags x))
+ // cond:
+ // result: (GreaterEqual x)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpPPC64InvertFlags {
+ break
+ }
+ x := v_0.Args[0]
+ v.reset(OpPPC64GreaterEqual)
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValuePPC64_OpPPC64LessThan(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (LessThan (FlagEQ))
+ // cond:
+ // result: (MOVDconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpPPC64FlagEQ {
+ break
+ }
+ v.reset(OpPPC64MOVDconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (LessThan (FlagLT))
+ // cond:
+ // result: (MOVDconst [1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpPPC64FlagLT {
+ break
+ }
+ v.reset(OpPPC64MOVDconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (LessThan (FlagGT))
+ // cond:
+ // result: (MOVDconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpPPC64FlagGT {
+ break
+ }
+ v.reset(OpPPC64MOVDconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (LessThan (InvertFlags x))
+ // cond:
+ // result: (GreaterThan x)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpPPC64InvertFlags {
+ break
+ }
+ x := v_0.Args[0]
+ v.reset(OpPPC64GreaterThan)
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValuePPC64_OpPPC64MOVBZload(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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_0 := v.Args[0]
+ if v_0.Op != OpPPC64MOVDaddr {
+ break
+ }
+ off2 := v_0.AuxInt
+ sym2 := v_0.Aux
+ ptr := v_0.Args[0]
+ mem := v.Args[1]
+ if !(canMergeSym(sym1, sym2)) {
+ break
+ }
+ v.reset(OpPPC64MOVBZload)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVBZload [off1] {sym} (ADDconst [off2] x) mem)
+ // cond: is16Bit(off1+off2)
+ // result: (MOVBZload [off1+off2] {sym} x mem)
+ for {
+ off1 := v.AuxInt
+ sym := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpPPC64ADDconst {
+ break
+ }
+ off2 := v_0.AuxInt
+ x := v_0.Args[0]
+ mem := v.Args[1]
+ if !(is16Bit(off1 + off2)) {
+ break
+ }
+ v.reset(OpPPC64MOVBZload)
+ v.AuxInt = off1 + off2
+ v.Aux = sym
+ v.AddArg(x)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValuePPC64_OpPPC64MOVBZreg(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (MOVBZreg y:(ANDconst [c] _))
+ // cond: uint64(c) <= 0xFF
+ // result: y
+ for {
+ y := v.Args[0]
+ if y.Op != OpPPC64ANDconst {
+ break
+ }
+ c := y.AuxInt
+ if !(uint64(c) <= 0xFF) {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = y.Type
+ v.AddArg(y)
+ return true
+ }
+ // match: (MOVBZreg y:(MOVBZreg _))
+ // cond:
+ // result: y
+ for {
+ y := v.Args[0]
+ if y.Op != OpPPC64MOVBZreg {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = y.Type
+ v.AddArg(y)
+ return true
+ }
+ // match: (MOVBZreg (MOVBreg x))
+ // cond:
+ // result: (MOVBZreg x)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpPPC64MOVBreg {
+ break
+ }
+ x := v_0.Args[0]
+ v.reset(OpPPC64MOVBZreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVBZreg x:(MOVBZload _ _))
+ // cond:
+ // result: x
+ for {
+ x := v.Args[0]
+ if x.Op != OpPPC64MOVBZload {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVBZreg (MOVDconst [c]))
+ // cond:
+ // result: (MOVDconst [int64(uint8(c))])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpPPC64MOVDconst {
+ break
+ }
+ c := v_0.AuxInt
+ v.reset(OpPPC64MOVDconst)
+ v.AuxInt = int64(uint8(c))
+ return true
+ }
+ return false
+}
+func rewriteValuePPC64_OpPPC64MOVBreg(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (MOVBreg y:(ANDconst [c] _))
+ // cond: uint64(c) <= 0x7F
+ // result: y
+ for {
+ y := v.Args[0]
+ if y.Op != OpPPC64ANDconst {
+ break
+ }
+ c := y.AuxInt
+ if !(uint64(c) <= 0x7F) {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = y.Type
+ v.AddArg(y)
+ return true
+ }
+ // match: (MOVBreg y:(MOVBreg _))
+ // cond:
+ // result: y
+ for {
+ y := v.Args[0]
+ if y.Op != OpPPC64MOVBreg {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = y.Type
+ v.AddArg(y)
+ return true
+ }
+ // match: (MOVBreg (MOVBZreg x))
+ // cond:
+ // result: (MOVBreg x)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpPPC64MOVBZreg {
+ break
+ }
+ x := v_0.Args[0]
+ v.reset(OpPPC64MOVBreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVBreg (MOVDconst [c]))
+ // cond:
+ // result: (MOVDconst [int64(int8(c))])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpPPC64MOVDconst {
+ break
+ }
+ c := v_0.AuxInt
+ v.reset(OpPPC64MOVDconst)
+ v.AuxInt = int64(int8(c))
+ return true
+ }
+ return false
+}
+func rewriteValuePPC64_OpPPC64MOVBstore(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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_0 := v.Args[0]
+ if v_0.Op != OpPPC64ADDconst {
+ break
+ }
+ off2 := v_0.AuxInt
+ x := v_0.Args[0]
+ val := v.Args[1]
+ mem := v.Args[2]
+ if !(is16Bit(off1 + off2)) {
+ break
+ }
+ v.reset(OpPPC64MOVBstore)
+ v.AuxInt = off1 + off2
+ v.Aux = sym
+ v.AddArg(x)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVBstore [off1] {sym1} (MOVDaddr [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_0 := v.Args[0]
+ if v_0.Op != OpPPC64MOVDaddr {
+ 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(OpPPC64MOVBstore)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(ptr)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVBstore [off] {sym} ptr (MOVDconst [c]) mem)
+ // cond: c == 0
+ // result: (MOVBstorezero [off] {sym} ptr mem)
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpPPC64MOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ mem := v.Args[2]
+ if !(c == 0) {
+ break
+ }
+ v.reset(OpPPC64MOVBstorezero)
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVBstore [off] {sym} ptr (MOVBreg x) mem)
+ // cond:
+ // result: (MOVBstore [off] {sym} ptr x mem)
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpPPC64MOVBreg {
+ break
+ }
+ x := v_1.Args[0]
+ mem := v.Args[2]
+ v.reset(OpPPC64MOVBstore)
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(x)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVBstore [off] {sym} ptr (MOVBZreg x) mem)
+ // cond:
+ // result: (MOVBstore [off] {sym} ptr x mem)
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpPPC64MOVBZreg {
+ break
+ }
+ x := v_1.Args[0]
+ mem := v.Args[2]
+ v.reset(OpPPC64MOVBstore)
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(x)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValuePPC64_OpPPC64MOVBstorezero(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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_0 := v.Args[0]
+ if v_0.Op != OpPPC64ADDconst {
+ break
+ }
+ off2 := v_0.AuxInt
+ x := v_0.Args[0]
+ mem := v.Args[1]
+ if !(is16Bit(off1 + off2)) {
+ break
+ }
+ v.reset(OpPPC64MOVBstorezero)
+ v.AuxInt = off1 + off2
+ v.Aux = sym
+ v.AddArg(x)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVBstorezero [off1] {sym1} (MOVDaddr [off2] {sym2} x) mem)
+ // cond: canMergeSym(sym1,sym2)
+ // result: (MOVBstorezero [off1+off2] {mergeSym(sym1,sym2)} x mem)
+ for {
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpPPC64MOVDaddr {
+ break
+ }
+ off2 := v_0.AuxInt
+ sym2 := v_0.Aux
+ x := v_0.Args[0]
+ mem := v.Args[1]
+ if !(canMergeSym(sym1, sym2)) {
+ break
+ }
+ v.reset(OpPPC64MOVBstorezero)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(x)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValuePPC64_OpPPC64MOVDload(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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_0 := v.Args[0]
+ if v_0.Op != OpPPC64MOVDaddr {
+ break
+ }
+ off2 := v_0.AuxInt
+ sym2 := v_0.Aux
+ ptr := v_0.Args[0]
+ mem := v.Args[1]
+ if !(canMergeSym(sym1, sym2)) {
+ break
+ }
+ v.reset(OpPPC64MOVDload)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVDload [off1] {sym} (ADDconst [off2] x) mem)
+ // cond: is16Bit(off1+off2)
+ // result: (MOVDload [off1+off2] {sym} x mem)
+ for {
+ off1 := v.AuxInt
+ sym := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpPPC64ADDconst {
+ break
+ }
+ off2 := v_0.AuxInt
+ x := v_0.Args[0]
+ mem := v.Args[1]
+ if !(is16Bit(off1 + off2)) {
+ break
+ }
+ v.reset(OpPPC64MOVDload)
+ v.AuxInt = off1 + off2
+ v.Aux = sym
+ v.AddArg(x)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValuePPC64_OpPPC64MOVDstore(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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_0 := v.Args[0]
+ if v_0.Op != OpPPC64ADDconst {
+ break
+ }
+ off2 := v_0.AuxInt
+ x := v_0.Args[0]
+ val := v.Args[1]
+ mem := v.Args[2]
+ if !(is16Bit(off1 + off2)) {
+ break
+ }
+ v.reset(OpPPC64MOVDstore)
+ v.AuxInt = off1 + off2
+ v.Aux = sym
+ v.AddArg(x)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVDstore [off1] {sym1} (MOVDaddr [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_0 := v.Args[0]
+ if v_0.Op != OpPPC64MOVDaddr {
+ 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(OpPPC64MOVDstore)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(ptr)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVDstore [off] {sym} ptr (MOVDconst [c]) mem)
+ // cond: c == 0
+ // result: (MOVDstorezero [off] {sym} ptr mem)
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpPPC64MOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ mem := v.Args[2]
+ if !(c == 0) {
+ break
+ }
+ v.reset(OpPPC64MOVDstorezero)
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValuePPC64_OpPPC64MOVDstorezero(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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_0 := v.Args[0]
+ if v_0.Op != OpPPC64ADDconst {
+ break
+ }
+ off2 := v_0.AuxInt
+ x := v_0.Args[0]
+ mem := v.Args[1]
+ if !(is16Bit(off1 + off2)) {
+ break
+ }
+ v.reset(OpPPC64MOVDstorezero)
+ v.AuxInt = off1 + off2
+ v.Aux = sym
+ v.AddArg(x)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVDstorezero [off1] {sym1} (MOVDaddr [off2] {sym2} x) mem)
+ // cond: canMergeSym(sym1,sym2)
+ // result: (MOVDstorezero [off1+off2] {mergeSym(sym1,sym2)} x mem)
+ for {
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpPPC64MOVDaddr {
+ break
+ }
+ off2 := v_0.AuxInt
+ sym2 := v_0.Aux
+ x := v_0.Args[0]
+ mem := v.Args[1]
+ if !(canMergeSym(sym1, sym2)) {
+ break
+ }
+ v.reset(OpPPC64MOVDstorezero)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(x)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValuePPC64_OpPPC64MOVHZload(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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_0 := v.Args[0]
+ if v_0.Op != OpPPC64MOVDaddr {
+ break
+ }
+ off2 := v_0.AuxInt
+ sym2 := v_0.Aux
+ ptr := v_0.Args[0]
+ mem := v.Args[1]
+ if !(canMergeSym(sym1, sym2)) {
+ break
+ }
+ v.reset(OpPPC64MOVHZload)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVHZload [off1] {sym} (ADDconst [off2] x) mem)
+ // cond: is16Bit(off1+off2)
+ // result: (MOVHZload [off1+off2] {sym} x mem)
+ for {
+ off1 := v.AuxInt
+ sym := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpPPC64ADDconst {
+ break
+ }
+ off2 := v_0.AuxInt
+ x := v_0.Args[0]
+ mem := v.Args[1]
+ if !(is16Bit(off1 + off2)) {
+ break
+ }
+ v.reset(OpPPC64MOVHZload)
+ v.AuxInt = off1 + off2
+ v.Aux = sym
+ v.AddArg(x)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValuePPC64_OpPPC64MOVHZreg(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (MOVHZreg y:(ANDconst [c] _))
+ // cond: uint64(c) <= 0xFFFF
+ // result: y
+ for {
+ y := v.Args[0]
+ if y.Op != OpPPC64ANDconst {
+ break
+ }
+ c := y.AuxInt
+ if !(uint64(c) <= 0xFFFF) {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = y.Type
+ v.AddArg(y)
+ return true
+ }
+ // match: (MOVHZreg y:(MOVHZreg _))
+ // cond:
+ // result: y
+ for {
+ y := v.Args[0]
+ if y.Op != OpPPC64MOVHZreg {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = y.Type
+ v.AddArg(y)
+ return true
+ }
+ // match: (MOVHZreg y:(MOVBZreg _))
+ // cond:
+ // result: y
+ for {
+ y := v.Args[0]
+ if y.Op != OpPPC64MOVBZreg {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = y.Type
+ v.AddArg(y)
+ return true
+ }
+ // match: (MOVHZreg y:(MOVHreg x))
+ // cond:
+ // result: (MOVHZreg x)
+ for {
+ y := v.Args[0]
+ if y.Op != OpPPC64MOVHreg {
+ break
+ }
+ x := y.Args[0]
+ v.reset(OpPPC64MOVHZreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVHZreg x:(MOVHZload _ _))
+ // cond:
+ // result: x
+ for {
+ x := v.Args[0]
+ if x.Op != OpPPC64MOVHZload {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = x.Type
+ 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 != OpPPC64MOVDconst {
+ break
+ }
+ c := v_0.AuxInt
+ v.reset(OpPPC64MOVDconst)
+ v.AuxInt = int64(uint16(c))
+ return true
+ }
+ return false
+}
+func rewriteValuePPC64_OpPPC64MOVHload(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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_0 := v.Args[0]
+ if v_0.Op != OpPPC64MOVDaddr {
+ break
+ }
+ off2 := v_0.AuxInt
+ sym2 := v_0.Aux
+ ptr := v_0.Args[0]
+ mem := v.Args[1]
+ if !(canMergeSym(sym1, sym2)) {
+ break
+ }
+ v.reset(OpPPC64MOVHload)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVHload [off1] {sym} (ADDconst [off2] x) mem)
+ // cond: is16Bit(off1+off2)
+ // result: (MOVHload [off1+off2] {sym} x mem)
+ for {
+ off1 := v.AuxInt
+ sym := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpPPC64ADDconst {
+ break
+ }
+ off2 := v_0.AuxInt
+ x := v_0.Args[0]
+ mem := v.Args[1]
+ if !(is16Bit(off1 + off2)) {
+ break
+ }
+ v.reset(OpPPC64MOVHload)
+ v.AuxInt = off1 + off2
+ v.Aux = sym
+ v.AddArg(x)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValuePPC64_OpPPC64MOVHreg(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (MOVHreg y:(ANDconst [c] _))
+ // cond: uint64(c) <= 0x7FFF
+ // result: y
+ for {
+ y := v.Args[0]
+ if y.Op != OpPPC64ANDconst {
+ break
+ }
+ c := y.AuxInt
+ if !(uint64(c) <= 0x7FFF) {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = y.Type
+ v.AddArg(y)
+ return true
+ }
+ // match: (MOVHreg y:(MOVHreg _))
+ // cond:
+ // result: y
+ for {
+ y := v.Args[0]
+ if y.Op != OpPPC64MOVHreg {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = y.Type
+ v.AddArg(y)
+ return true
+ }
+ // match: (MOVHreg y:(MOVBreg _))
+ // cond:
+ // result: y
+ for {
+ y := v.Args[0]
+ if y.Op != OpPPC64MOVBreg {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = y.Type
+ v.AddArg(y)
+ return true
+ }
+ // match: (MOVHreg y:(MOVHZreg x))
+ // cond:
+ // result: (MOVHreg x)
+ for {
+ y := v.Args[0]
+ if y.Op != OpPPC64MOVHZreg {
+ break
+ }
+ x := y.Args[0]
+ v.reset(OpPPC64MOVHreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVHreg x:(MOVHload _ _))
+ // cond:
+ // result: x
+ for {
+ x := v.Args[0]
+ if x.Op != OpPPC64MOVHload {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = x.Type
+ 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 != OpPPC64MOVDconst {
+ break
+ }
+ c := v_0.AuxInt
+ v.reset(OpPPC64MOVDconst)
+ v.AuxInt = int64(int16(c))
+ return true
+ }
+ return false
+}
+func rewriteValuePPC64_OpPPC64MOVHstore(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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_0 := v.Args[0]
+ if v_0.Op != OpPPC64ADDconst {
+ break
+ }
+ off2 := v_0.AuxInt
+ x := v_0.Args[0]
+ val := v.Args[1]
+ mem := v.Args[2]
+ if !(is16Bit(off1 + off2)) {
+ break
+ }
+ v.reset(OpPPC64MOVHstore)
+ v.AuxInt = off1 + off2
+ v.Aux = sym
+ v.AddArg(x)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVHstore [off1] {sym1} (MOVDaddr [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_0 := v.Args[0]
+ if v_0.Op != OpPPC64MOVDaddr {
+ 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(OpPPC64MOVHstore)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(ptr)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVHstore [off] {sym} ptr (MOVDconst [c]) mem)
+ // cond: c == 0
+ // result: (MOVHstorezero [off] {sym} ptr mem)
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpPPC64MOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ mem := v.Args[2]
+ if !(c == 0) {
+ break
+ }
+ v.reset(OpPPC64MOVHstorezero)
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVHstore [off] {sym} ptr (MOVHreg 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 != OpPPC64MOVHreg {
+ break
+ }
+ x := v_1.Args[0]
+ mem := v.Args[2]
+ v.reset(OpPPC64MOVHstore)
+ 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 != OpPPC64MOVHZreg {
+ break
+ }
+ x := v_1.Args[0]
+ mem := v.Args[2]
+ v.reset(OpPPC64MOVHstore)
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(x)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValuePPC64_OpPPC64MOVHstorezero(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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_0 := v.Args[0]
+ if v_0.Op != OpPPC64ADDconst {
+ break
+ }
+ off2 := v_0.AuxInt
+ x := v_0.Args[0]
+ mem := v.Args[1]
+ if !(is16Bit(off1 + off2)) {
+ break
+ }
+ v.reset(OpPPC64MOVHstorezero)
+ v.AuxInt = off1 + off2
+ v.Aux = sym
+ v.AddArg(x)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVHstorezero [off1] {sym1} (MOVDaddr [off2] {sym2} x) mem)
+ // cond: canMergeSym(sym1,sym2)
+ // result: (MOVHstorezero [off1+off2] {mergeSym(sym1,sym2)} x mem)
+ for {
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpPPC64MOVDaddr {
+ break
+ }
+ off2 := v_0.AuxInt
+ sym2 := v_0.Aux
+ x := v_0.Args[0]
+ mem := v.Args[1]
+ if !(canMergeSym(sym1, sym2)) {
+ break
+ }
+ v.reset(OpPPC64MOVHstorezero)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(x)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValuePPC64_OpPPC64MOVWZload(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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_0 := v.Args[0]
+ if v_0.Op != OpPPC64MOVDaddr {
+ break
+ }
+ off2 := v_0.AuxInt
+ sym2 := v_0.Aux
+ ptr := v_0.Args[0]
+ mem := v.Args[1]
+ if !(canMergeSym(sym1, sym2)) {
+ break
+ }
+ v.reset(OpPPC64MOVWZload)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVWZload [off1] {sym} (ADDconst [off2] x) mem)
+ // cond: is16Bit(off1+off2)
+ // result: (MOVWZload [off1+off2] {sym} x mem)
+ for {
+ off1 := v.AuxInt
+ sym := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpPPC64ADDconst {
+ break
+ }
+ off2 := v_0.AuxInt
+ x := v_0.Args[0]
+ mem := v.Args[1]
+ if !(is16Bit(off1 + off2)) {
+ break
+ }
+ v.reset(OpPPC64MOVWZload)
+ v.AuxInt = off1 + off2
+ v.Aux = sym
+ v.AddArg(x)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValuePPC64_OpPPC64MOVWZreg(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (MOVWZreg y:(ANDconst [c] _))
+ // cond: uint64(c) <= 0xFFFFFFFF
+ // result: y
+ for {
+ y := v.Args[0]
+ if y.Op != OpPPC64ANDconst {
+ break
+ }
+ c := y.AuxInt
+ if !(uint64(c) <= 0xFFFFFFFF) {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = y.Type
+ 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_0 := y.Args[0]
+ if y_0.Op != OpPPC64MOVDconst {
+ break
+ }
+ c := y_0.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
+ for {
+ y := v.Args[0]
+ if y.Op != OpPPC64MOVWZreg {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = y.Type
+ v.AddArg(y)
+ return true
+ }
+ // match: (MOVWZreg y:(MOVHZreg _))
+ // cond:
+ // result: y
+ for {
+ y := v.Args[0]
+ if y.Op != OpPPC64MOVHZreg {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = y.Type
+ v.AddArg(y)
+ return true
+ }
+ // match: (MOVWZreg y:(MOVBZreg _))
+ // cond:
+ // result: y
+ for {
+ y := v.Args[0]
+ if y.Op != OpPPC64MOVBZreg {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = y.Type
+ v.AddArg(y)
+ return true
+ }
+ // match: (MOVWZreg y:(MOVWreg x))
+ // cond:
+ // result: (MOVWZreg x)
+ for {
+ y := v.Args[0]
+ if y.Op != OpPPC64MOVWreg {
+ break
+ }
+ x := y.Args[0]
+ v.reset(OpPPC64MOVWZreg)
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValuePPC64_OpPPC64MOVWload(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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_0 := v.Args[0]
+ if v_0.Op != OpPPC64MOVDaddr {
+ break
+ }
+ off2 := v_0.AuxInt
+ sym2 := v_0.Aux
+ ptr := v_0.Args[0]
+ mem := v.Args[1]
+ if !(canMergeSym(sym1, sym2)) {
+ break
+ }
+ v.reset(OpPPC64MOVWload)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVWload [off1] {sym} (ADDconst [off2] x) mem)
+ // cond: is16Bit(off1+off2)
+ // result: (MOVWload [off1+off2] {sym} x mem)
+ for {
+ off1 := v.AuxInt
+ sym := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpPPC64ADDconst {
+ break
+ }
+ off2 := v_0.AuxInt
+ x := v_0.Args[0]
+ mem := v.Args[1]
+ if !(is16Bit(off1 + off2)) {
+ break
+ }
+ v.reset(OpPPC64MOVWload)
+ v.AuxInt = off1 + off2
+ v.Aux = sym
+ v.AddArg(x)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValuePPC64_OpPPC64MOVWreg(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (MOVWreg y:(ANDconst [c] _))
+ // cond: uint64(c) <= 0xFFFF
+ // result: y
+ for {
+ y := v.Args[0]
+ if y.Op != OpPPC64ANDconst {
+ break
+ }
+ c := y.AuxInt
+ if !(uint64(c) <= 0xFFFF) {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = y.Type
+ 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_0 := y.Args[0]
+ if y_0.Op != OpPPC64MOVDconst {
+ break
+ }
+ c := y_0.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
+ for {
+ y := v.Args[0]
+ if y.Op != OpPPC64MOVWreg {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = y.Type
+ v.AddArg(y)
+ return true
+ }
+ // match: (MOVWreg y:(MOVHreg _))
+ // cond:
+ // result: y
+ for {
+ y := v.Args[0]
+ if y.Op != OpPPC64MOVHreg {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = y.Type
+ v.AddArg(y)
+ return true
+ }
+ // match: (MOVWreg y:(MOVBreg _))
+ // cond:
+ // result: y
+ for {
+ y := v.Args[0]
+ if y.Op != OpPPC64MOVBreg {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = y.Type
+ v.AddArg(y)
+ return true
+ }
+ // match: (MOVWreg y:(MOVWZreg x))
+ // cond:
+ // result: (MOVWreg x)
+ for {
+ y := v.Args[0]
+ if y.Op != OpPPC64MOVWZreg {
+ break
+ }
+ x := y.Args[0]
+ v.reset(OpPPC64MOVWreg)
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValuePPC64_OpPPC64MOVWstore(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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_0 := v.Args[0]
+ if v_0.Op != OpPPC64ADDconst {
+ break
+ }
+ off2 := v_0.AuxInt
+ x := v_0.Args[0]
+ val := v.Args[1]
+ mem := v.Args[2]
+ if !(is16Bit(off1 + off2)) {
+ break
+ }
+ v.reset(OpPPC64MOVWstore)
+ v.AuxInt = off1 + off2
+ v.Aux = sym
+ v.AddArg(x)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVWstore [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) val mem)
+ // cond: canMergeSym(sym1,sym2)
+ // result: (MOVWstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
+ for {
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpPPC64MOVDaddr {
+ 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(OpPPC64MOVWstore)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(ptr)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVWstore [off] {sym} ptr (MOVDconst [c]) mem)
+ // cond: c == 0
+ // result: (MOVWstorezero [off] {sym} ptr mem)
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpPPC64MOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ mem := v.Args[2]
+ if !(c == 0) {
+ break
+ }
+ v.reset(OpPPC64MOVWstorezero)
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // 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 != OpPPC64MOVWreg {
+ break
+ }
+ x := v_1.Args[0]
+ mem := v.Args[2]
+ v.reset(OpPPC64MOVWstore)
+ 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 != OpPPC64MOVWZreg {
+ break
+ }
+ x := v_1.Args[0]
+ mem := v.Args[2]
+ v.reset(OpPPC64MOVWstore)
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(x)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValuePPC64_OpPPC64MOVWstorezero(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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_0 := v.Args[0]
+ if v_0.Op != OpPPC64ADDconst {
+ break
+ }
+ off2 := v_0.AuxInt
+ x := v_0.Args[0]
+ mem := v.Args[1]
+ if !(is16Bit(off1 + off2)) {
+ break
+ }
+ v.reset(OpPPC64MOVWstorezero)
+ v.AuxInt = off1 + off2
+ v.Aux = sym
+ v.AddArg(x)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVWstorezero [off1] {sym1} (MOVDaddr [off2] {sym2} x) mem)
+ // cond: canMergeSym(sym1,sym2)
+ // result: (MOVWstorezero [off1+off2] {mergeSym(sym1,sym2)} x mem)
+ for {
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpPPC64MOVDaddr {
+ break
+ }
+ off2 := v_0.AuxInt
+ sym2 := v_0.Aux
+ x := v_0.Args[0]
+ mem := v.Args[1]
+ if !(canMergeSym(sym1, sym2)) {
+ break
+ }
+ v.reset(OpPPC64MOVWstorezero)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(x)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValuePPC64_OpPPC64MaskIfNotCarry(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (MaskIfNotCarry (ADDconstForCarry [c] (ANDconst [d] _)))
+ // cond: c < 0 && d > 0 && c + d < 0
+ // result: (MOVDconst [-1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpPPC64ADDconstForCarry {
+ break
+ }
+ c := v_0.AuxInt
+ v_0_0 := v_0.Args[0]
+ if v_0_0.Op != OpPPC64ANDconst {
+ break
+ }
+ d := v_0_0.AuxInt
+ if !(c < 0 && d > 0 && c+d < 0) {
+ break
+ }
+ v.reset(OpPPC64MOVDconst)
+ v.AuxInt = -1
+ return true
+ }
+ return false
+}
+func rewriteValuePPC64_OpPPC64NotEqual(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (NotEqual (FlagEQ))
+ // cond:
+ // result: (MOVDconst [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpPPC64FlagEQ {
+ break
+ }
+ v.reset(OpPPC64MOVDconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (NotEqual (FlagLT))
+ // cond:
+ // result: (MOVDconst [1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpPPC64FlagLT {
+ break
+ }
+ v.reset(OpPPC64MOVDconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (NotEqual (FlagGT))
+ // cond:
+ // result: (MOVDconst [1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpPPC64FlagGT {
+ break
+ }
+ v.reset(OpPPC64MOVDconst)
+ v.AuxInt = 1
+ return true
+ }
+ // match: (NotEqual (InvertFlags x))
+ // cond:
+ // result: (NotEqual x)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpPPC64InvertFlags {
+ break
+ }
+ x := v_0.Args[0]
+ v.reset(OpPPC64NotEqual)
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValuePPC64_OpPPC64OR(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (OR (MOVDconst [c]) (MOVDconst [d]))
+ // cond:
+ // result: (MOVDconst [c|d])
+ for {
+ 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: (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 != OpPPC64MOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ if !(isU32Bit(c)) {
+ break
+ }
+ v.reset(OpPPC64ORconst)
+ 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 != OpPPC64MOVDconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ if !(isU32Bit(c)) {
+ break
+ }
+ v.reset(OpPPC64ORconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValuePPC64_OpPPC64ORN(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ORN x (MOVDconst [-1]))
+ // cond:
+ // result: x
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpPPC64MOVDconst {
+ break
+ }
+ if v_1.AuxInt != -1 {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValuePPC64_OpPPC64ORconst(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ORconst [c] (ORconst [d] x))
+ // cond:
+ // result: (ORconst [c|d] x)
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpPPC64ORconst {
+ break
+ }
+ d := v_0.AuxInt
+ x := v_0.Args[0]
+ v.reset(OpPPC64ORconst)
+ v.AuxInt = c | d
+ v.AddArg(x)
+ return true
+ }
+ // match: (ORconst [-1] _)
+ // cond:
+ // result: (MOVDconst [-1])
+ for {
+ if v.AuxInt != -1 {
+ break
+ }
+ v.reset(OpPPC64MOVDconst)
+ v.AuxInt = -1
+ return true
+ }
+ // match: (ORconst [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
+ }
+ return false
+}
+func rewriteValuePPC64_OpPPC64SUB(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SUB x (MOVDconst [c]))
+ // cond: is32Bit(-c)
+ // result: (ADDconst [-c] x)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpPPC64MOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ if !(is32Bit(-c)) {
+ break
+ }
+ v.reset(OpPPC64ADDconst)
+ v.AuxInt = -c
+ v.AddArg(x)
+ return true
+ }
+ 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])
+ for {
+ 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 x (MOVDconst [c]))
+ // cond: isU32Bit(c)
+ // result: (XORconst [c] x)
+ for {
+ 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_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(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (XORconst [c] (XORconst [d] x))
+ // cond:
+ // result: (XORconst [c^d] x)
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpPPC64XORconst {
+ break
+ }
+ d := v_0.AuxInt
+ x := v_0.Args[0]
+ v.reset(OpPPC64XORconst)
+ v.AuxInt = c ^ d
+ v.AddArg(x)
+ return true
+ }
+ // match: (XORconst [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
+ }
+ return false
+}
+func rewriteValuePPC64_OpRsh16Ux16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh16Ux16 x y)
+ // cond:
+ // result: (SRW (ZeroExt16to32 x) (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-16] (ZeroExt16to64 y)))))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64SRW)
+ v0 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpPPC64ORN, config.fe.TypeInt64())
+ v1.AddArg(y)
+ v2 := b.NewValue0(v.Line, OpPPC64MaskIfNotCarry, config.fe.TypeInt64())
+ v3 := b.NewValue0(v.Line, OpPPC64ADDconstForCarry, TypeFlags)
+ v3.AuxInt = -16
+ v4 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+ v4.AddArg(y)
+ v3.AddArg(v4)
+ v2.AddArg(v3)
+ v1.AddArg(v2)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValuePPC64_OpRsh16Ux32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh16Ux32 x (Const64 [c]))
+ // cond: uint32(c) < 16
+ // result: (SRWconst (ZeroExt16to32 x) [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpConst64 {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint32(c) < 16) {
+ break
+ }
+ v.reset(OpPPC64SRWconst)
+ v.AuxInt = c
+ v0 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (Rsh16Ux32 x (MOVDconst [c]))
+ // cond: uint32(c) < 16
+ // result: (SRWconst (ZeroExt16to32 x) [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpPPC64MOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint32(c) < 16) {
+ break
+ }
+ v.reset(OpPPC64SRWconst)
+ v.AuxInt = c
+ v0 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+ 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)))))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64SRW)
+ v0 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpPPC64ORN, config.fe.TypeInt64())
+ v1.AddArg(y)
+ v2 := b.NewValue0(v.Line, OpPPC64MaskIfNotCarry, config.fe.TypeInt64())
+ v3 := b.NewValue0(v.Line, OpPPC64ADDconstForCarry, TypeFlags)
+ v3.AuxInt = -16
+ v4 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+ v4.AddArg(y)
+ v3.AddArg(v4)
+ v2.AddArg(v3)
+ v1.AddArg(v2)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValuePPC64_OpRsh16Ux64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh16Ux64 x (Const64 [c]))
+ // cond: uint64(c) < 16
+ // result: (SRWconst (ZeroExt16to32 x) [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpConst64 {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint64(c) < 16) {
+ break
+ }
+ v.reset(OpPPC64SRWconst)
+ v.AuxInt = c
+ v0 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (Rsh16Ux64 _ (Const64 [c]))
+ // cond: uint64(c) >= 16
+ // result: (MOVDconst [0])
+ for {
+ v_1 := v.Args[1]
+ if v_1.Op != OpConst64 {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint64(c) >= 16) {
+ break
+ }
+ v.reset(OpPPC64MOVDconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (Rsh16Ux64 x (MOVDconst [c]))
+ // cond: uint64(c) < 16
+ // result: (SRWconst (ZeroExt16to32 x) [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpPPC64MOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint64(c) < 16) {
+ break
+ }
+ v.reset(OpPPC64SRWconst)
+ v.AuxInt = c
+ v0 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+ 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))))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64SRW)
+ v0 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpPPC64ORN, config.fe.TypeInt64())
+ v1.AddArg(y)
+ v2 := b.NewValue0(v.Line, OpPPC64MaskIfNotCarry, config.fe.TypeInt64())
+ v3 := b.NewValue0(v.Line, OpPPC64ADDconstForCarry, TypeFlags)
+ v3.AuxInt = -16
+ v3.AddArg(y)
+ v2.AddArg(v3)
+ v1.AddArg(v2)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValuePPC64_OpRsh16Ux8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh16Ux8 x y)
+ // cond:
+ // result: (SRW (ZeroExt16to32 x) (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-16] (ZeroExt8to64 y)))))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64SRW)
+ v0 := b.NewValue0(v.Line, OpZeroExt16to32, config.fe.TypeUInt32())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpPPC64ORN, config.fe.TypeInt64())
+ v1.AddArg(y)
+ v2 := b.NewValue0(v.Line, OpPPC64MaskIfNotCarry, config.fe.TypeInt64())
+ v3 := b.NewValue0(v.Line, OpPPC64ADDconstForCarry, TypeFlags)
+ v3.AuxInt = -16
+ v4 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+ v4.AddArg(y)
+ v3.AddArg(v4)
+ v2.AddArg(v3)
+ v1.AddArg(v2)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValuePPC64_OpRsh16x16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh16x16 x y)
+ // cond:
+ // result: (SRAW (SignExt16to32 x) (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-16] (ZeroExt16to64 y)))))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64SRAW)
+ v0 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpPPC64ORN, config.fe.TypeInt64())
+ v1.AddArg(y)
+ v2 := b.NewValue0(v.Line, OpPPC64MaskIfNotCarry, config.fe.TypeInt64())
+ v3 := b.NewValue0(v.Line, OpPPC64ADDconstForCarry, TypeFlags)
+ v3.AuxInt = -16
+ v4 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+ v4.AddArg(y)
+ v3.AddArg(v4)
+ v2.AddArg(v3)
+ v1.AddArg(v2)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValuePPC64_OpRsh16x32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh16x32 x (Const64 [c]))
+ // cond: uint32(c) < 16
+ // result: (SRAWconst (SignExt16to32 x) [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpConst64 {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint32(c) < 16) {
+ break
+ }
+ v.reset(OpPPC64SRAWconst)
+ v.AuxInt = c
+ v0 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (Rsh16x32 x (MOVDconst [c]))
+ // cond: uint32(c) < 16
+ // result: (SRAWconst (SignExt16to32 x) [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpPPC64MOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint32(c) < 16) {
+ break
+ }
+ v.reset(OpPPC64SRAWconst)
+ v.AuxInt = c
+ v0 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
+ 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)))))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64SRAW)
+ v0 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpPPC64ORN, config.fe.TypeInt64())
+ v1.AddArg(y)
+ v2 := b.NewValue0(v.Line, OpPPC64MaskIfNotCarry, config.fe.TypeInt64())
+ v3 := b.NewValue0(v.Line, OpPPC64ADDconstForCarry, TypeFlags)
+ v3.AuxInt = -16
+ v4 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+ v4.AddArg(y)
+ v3.AddArg(v4)
+ v2.AddArg(v3)
+ v1.AddArg(v2)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValuePPC64_OpRsh16x64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh16x64 x (Const64 [c]))
+ // cond: uint64(c) < 16
+ // result: (SRAWconst (SignExt16to32 x) [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpConst64 {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint64(c) < 16) {
+ break
+ }
+ v.reset(OpPPC64SRAWconst)
+ v.AuxInt = c
+ v0 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (Rsh16x64 x (Const64 [c]))
+ // cond: uint64(c) >= 16
+ // result: (SRAWconst (SignExt16to32 x) [63])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpConst64 {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint64(c) >= 16) {
+ break
+ }
+ v.reset(OpPPC64SRAWconst)
+ v.AuxInt = 63
+ v0 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (Rsh16x64 x (MOVDconst [c]))
+ // cond: uint64(c) < 16
+ // result: (SRAWconst (SignExt16to32 x) [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpPPC64MOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint64(c) < 16) {
+ break
+ }
+ v.reset(OpPPC64SRAWconst)
+ v.AuxInt = c
+ v0 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
+ 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))))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64SRAW)
+ v0 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpPPC64ORN, config.fe.TypeInt64())
+ v1.AddArg(y)
+ v2 := b.NewValue0(v.Line, OpPPC64MaskIfNotCarry, config.fe.TypeInt64())
+ v3 := b.NewValue0(v.Line, OpPPC64ADDconstForCarry, TypeFlags)
+ v3.AuxInt = -16
+ v3.AddArg(y)
+ v2.AddArg(v3)
+ v1.AddArg(v2)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValuePPC64_OpRsh16x8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh16x8 x y)
+ // cond:
+ // result: (SRAW (SignExt16to32 x) (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-16] (ZeroExt8to64 y)))))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64SRAW)
+ v0 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpPPC64ORN, config.fe.TypeInt64())
+ v1.AddArg(y)
+ v2 := b.NewValue0(v.Line, OpPPC64MaskIfNotCarry, config.fe.TypeInt64())
+ v3 := b.NewValue0(v.Line, OpPPC64ADDconstForCarry, TypeFlags)
+ v3.AuxInt = -16
+ v4 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+ v4.AddArg(y)
+ v3.AddArg(v4)
+ v2.AddArg(v3)
+ v1.AddArg(v2)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValuePPC64_OpRsh32Ux16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh32Ux16 x y)
+ // cond:
+ // result: (SRW x (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-32] (ZeroExt16to64 y)))))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64SRW)
+ v.AddArg(x)
+ v0 := b.NewValue0(v.Line, OpPPC64ORN, config.fe.TypeInt64())
+ v0.AddArg(y)
+ v1 := b.NewValue0(v.Line, OpPPC64MaskIfNotCarry, config.fe.TypeInt64())
+ v2 := b.NewValue0(v.Line, OpPPC64ADDconstForCarry, TypeFlags)
+ v2.AuxInt = -32
+ v3 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+ v3.AddArg(y)
+ v2.AddArg(v3)
+ v1.AddArg(v2)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValuePPC64_OpRsh32Ux32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh32Ux32 x (Const64 [c]))
+ // cond: uint32(c) < 32
+ // result: (SRWconst x [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpConst64 {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint32(c) < 32) {
+ break
+ }
+ v.reset(OpPPC64SRWconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (Rsh32Ux32 x (MOVDconst [c]))
+ // cond: uint32(c) < 32
+ // result: (SRWconst x [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpPPC64MOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint32(c) < 32) {
+ break
+ }
+ v.reset(OpPPC64SRWconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (Rsh32Ux32 x y)
+ // cond:
+ // result: (SRW x (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-32] (ZeroExt32to64 y)))))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64SRW)
+ v.AddArg(x)
+ v0 := b.NewValue0(v.Line, OpPPC64ORN, config.fe.TypeInt64())
+ v0.AddArg(y)
+ v1 := b.NewValue0(v.Line, OpPPC64MaskIfNotCarry, config.fe.TypeInt64())
+ v2 := b.NewValue0(v.Line, OpPPC64ADDconstForCarry, TypeFlags)
+ v2.AuxInt = -32
+ v3 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+ v3.AddArg(y)
+ v2.AddArg(v3)
+ v1.AddArg(v2)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValuePPC64_OpRsh32Ux64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh32Ux64 x (Const64 [c]))
+ // cond: uint64(c) < 32
+ // result: (SRWconst x [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpConst64 {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint64(c) < 32) {
+ break
+ }
+ v.reset(OpPPC64SRWconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (Rsh32Ux64 _ (Const64 [c]))
+ // cond: uint64(c) >= 32
+ // result: (MOVDconst [0])
+ for {
+ v_1 := v.Args[1]
+ if v_1.Op != OpConst64 {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint64(c) >= 32) {
+ break
+ }
+ v.reset(OpPPC64MOVDconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (Rsh32Ux64 x (MOVDconst [c]))
+ // cond: uint64(c) < 32
+ // result: (SRWconst x [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpPPC64MOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint64(c) < 32) {
+ break
+ }
+ v.reset(OpPPC64SRWconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (Rsh32Ux64 x y)
+ // cond:
+ // result: (SRW x (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-32] y))))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64SRW)
+ v.AddArg(x)
+ v0 := b.NewValue0(v.Line, OpPPC64ORN, config.fe.TypeInt64())
+ v0.AddArg(y)
+ v1 := b.NewValue0(v.Line, OpPPC64MaskIfNotCarry, config.fe.TypeInt64())
+ v2 := b.NewValue0(v.Line, OpPPC64ADDconstForCarry, TypeFlags)
+ v2.AuxInt = -32
+ v2.AddArg(y)
+ v1.AddArg(v2)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValuePPC64_OpRsh32Ux8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh32Ux8 x y)
+ // cond:
+ // result: (SRW x (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-32] (ZeroExt8to64 y)))))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64SRW)
+ v.AddArg(x)
+ v0 := b.NewValue0(v.Line, OpPPC64ORN, config.fe.TypeInt64())
+ v0.AddArg(y)
+ v1 := b.NewValue0(v.Line, OpPPC64MaskIfNotCarry, config.fe.TypeInt64())
+ v2 := b.NewValue0(v.Line, OpPPC64ADDconstForCarry, TypeFlags)
+ v2.AuxInt = -32
+ v3 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+ v3.AddArg(y)
+ v2.AddArg(v3)
+ v1.AddArg(v2)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValuePPC64_OpRsh32x16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh32x16 x y)
+ // cond:
+ // result: (SRAW x (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-32] (ZeroExt16to64 y)))))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64SRAW)
+ v.AddArg(x)
+ v0 := b.NewValue0(v.Line, OpPPC64ORN, config.fe.TypeInt64())
+ v0.AddArg(y)
+ v1 := b.NewValue0(v.Line, OpPPC64MaskIfNotCarry, config.fe.TypeInt64())
+ v2 := b.NewValue0(v.Line, OpPPC64ADDconstForCarry, TypeFlags)
+ v2.AuxInt = -32
+ v3 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+ v3.AddArg(y)
+ v2.AddArg(v3)
+ v1.AddArg(v2)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValuePPC64_OpRsh32x32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh32x32 x (Const64 [c]))
+ // cond: uint32(c) < 32
+ // result: (SRAWconst x [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpConst64 {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint32(c) < 32) {
+ break
+ }
+ v.reset(OpPPC64SRAWconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (Rsh32x32 x (MOVDconst [c]))
+ // cond: uint32(c) < 32
+ // result: (SRAWconst x [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpPPC64MOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint32(c) < 32) {
+ break
+ }
+ v.reset(OpPPC64SRAWconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (Rsh32x32 x y)
+ // cond:
+ // result: (SRAW x (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-32] (ZeroExt32to64 y)))))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64SRAW)
+ v.AddArg(x)
+ v0 := b.NewValue0(v.Line, OpPPC64ORN, config.fe.TypeInt64())
+ v0.AddArg(y)
+ v1 := b.NewValue0(v.Line, OpPPC64MaskIfNotCarry, config.fe.TypeInt64())
+ v2 := b.NewValue0(v.Line, OpPPC64ADDconstForCarry, TypeFlags)
+ v2.AuxInt = -32
+ v3 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+ v3.AddArg(y)
+ v2.AddArg(v3)
+ v1.AddArg(v2)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValuePPC64_OpRsh32x64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh32x64 x (Const64 [c]))
+ // cond: uint64(c) < 32
+ // result: (SRAWconst x [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpConst64 {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint64(c) < 32) {
+ break
+ }
+ v.reset(OpPPC64SRAWconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (Rsh32x64 x (Const64 [c]))
+ // cond: uint64(c) >= 32
+ // result: (SRAWconst x [63])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpConst64 {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint64(c) >= 32) {
+ break
+ }
+ v.reset(OpPPC64SRAWconst)
+ v.AuxInt = 63
+ v.AddArg(x)
+ return true
+ }
+ // match: (Rsh32x64 x (MOVDconst [c]))
+ // cond: uint64(c) < 32
+ // result: (SRAWconst x [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpPPC64MOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint64(c) < 32) {
+ break
+ }
+ v.reset(OpPPC64SRAWconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (Rsh32x64 x y)
+ // cond:
+ // result: (SRAW x (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-32] y))))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64SRAW)
+ v.AddArg(x)
+ v0 := b.NewValue0(v.Line, OpPPC64ORN, config.fe.TypeInt64())
+ v0.AddArg(y)
+ v1 := b.NewValue0(v.Line, OpPPC64MaskIfNotCarry, config.fe.TypeInt64())
+ v2 := b.NewValue0(v.Line, OpPPC64ADDconstForCarry, TypeFlags)
+ v2.AuxInt = -32
+ v2.AddArg(y)
+ v1.AddArg(v2)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValuePPC64_OpRsh32x8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh32x8 x y)
+ // cond:
+ // result: (SRAW x (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-32] (ZeroExt8to64 y)))))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64SRAW)
+ v.AddArg(x)
+ v0 := b.NewValue0(v.Line, OpPPC64ORN, config.fe.TypeInt64())
+ v0.AddArg(y)
+ v1 := b.NewValue0(v.Line, OpPPC64MaskIfNotCarry, config.fe.TypeInt64())
+ v2 := b.NewValue0(v.Line, OpPPC64ADDconstForCarry, TypeFlags)
+ v2.AuxInt = -32
+ v3 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+ v3.AddArg(y)
+ v2.AddArg(v3)
+ v1.AddArg(v2)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValuePPC64_OpRsh64Ux16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh64Ux16 x y)
+ // cond:
+ // result: (SRD x (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-64] (ZeroExt16to64 y)))))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64SRD)
+ v.AddArg(x)
+ v0 := b.NewValue0(v.Line, OpPPC64ORN, config.fe.TypeInt64())
+ v0.AddArg(y)
+ v1 := b.NewValue0(v.Line, OpPPC64MaskIfNotCarry, config.fe.TypeInt64())
+ v2 := b.NewValue0(v.Line, OpPPC64ADDconstForCarry, TypeFlags)
+ v2.AuxInt = -64
+ v3 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+ v3.AddArg(y)
+ v2.AddArg(v3)
+ v1.AddArg(v2)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValuePPC64_OpRsh64Ux32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh64Ux32 x (Const64 [c]))
+ // cond: uint32(c) < 64
+ // result: (SRDconst x [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpConst64 {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint32(c) < 64) {
+ break
+ }
+ v.reset(OpPPC64SRDconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (Rsh64Ux32 x (MOVDconst [c]))
+ // cond: uint32(c) < 64
+ // result: (SRDconst x [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpPPC64MOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint32(c) < 64) {
+ break
+ }
+ v.reset(OpPPC64SRDconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (Rsh64Ux32 x y)
+ // cond:
+ // result: (SRD x (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-64] (ZeroExt32to64 y)))))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64SRD)
+ v.AddArg(x)
+ v0 := b.NewValue0(v.Line, OpPPC64ORN, config.fe.TypeInt64())
+ v0.AddArg(y)
+ v1 := b.NewValue0(v.Line, OpPPC64MaskIfNotCarry, config.fe.TypeInt64())
+ v2 := b.NewValue0(v.Line, OpPPC64ADDconstForCarry, TypeFlags)
+ v2.AuxInt = -64
+ v3 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+ v3.AddArg(y)
+ v2.AddArg(v3)
+ v1.AddArg(v2)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValuePPC64_OpRsh64Ux64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh64Ux64 x (Const64 [c]))
+ // cond: uint64(c) < 64
+ // result: (SRDconst x [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpConst64 {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint64(c) < 64) {
+ break
+ }
+ v.reset(OpPPC64SRDconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (Rsh64Ux64 _ (Const64 [c]))
+ // cond: uint64(c) >= 64
+ // result: (MOVDconst [0])
+ for {
+ v_1 := v.Args[1]
+ if v_1.Op != OpConst64 {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint64(c) >= 64) {
+ break
+ }
+ v.reset(OpPPC64MOVDconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (Rsh64Ux64 x (MOVDconst [c]))
+ // cond: uint64(c) < 64
+ // result: (SRDconst x [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpPPC64MOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint64(c) < 64) {
+ break
+ }
+ v.reset(OpPPC64SRDconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (Rsh64Ux64 x y)
+ // cond:
+ // result: (SRD x (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-64] y))))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64SRD)
+ v.AddArg(x)
+ v0 := b.NewValue0(v.Line, OpPPC64ORN, config.fe.TypeInt64())
+ v0.AddArg(y)
+ v1 := b.NewValue0(v.Line, OpPPC64MaskIfNotCarry, config.fe.TypeInt64())
+ v2 := b.NewValue0(v.Line, OpPPC64ADDconstForCarry, TypeFlags)
+ v2.AuxInt = -64
+ v2.AddArg(y)
+ v1.AddArg(v2)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValuePPC64_OpRsh64Ux8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh64Ux8 x y)
+ // cond:
+ // result: (SRD x (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-64] (ZeroExt8to64 y)))))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64SRD)
+ v.AddArg(x)
+ v0 := b.NewValue0(v.Line, OpPPC64ORN, config.fe.TypeInt64())
+ v0.AddArg(y)
+ v1 := b.NewValue0(v.Line, OpPPC64MaskIfNotCarry, config.fe.TypeInt64())
+ v2 := b.NewValue0(v.Line, OpPPC64ADDconstForCarry, TypeFlags)
+ v2.AuxInt = -64
+ v3 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+ v3.AddArg(y)
+ v2.AddArg(v3)
+ v1.AddArg(v2)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValuePPC64_OpRsh64x16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh64x16 x y)
+ // cond:
+ // result: (SRAD x (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-64] (ZeroExt16to64 y)))))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64SRAD)
+ v.AddArg(x)
+ v0 := b.NewValue0(v.Line, OpPPC64ORN, config.fe.TypeInt64())
+ v0.AddArg(y)
+ v1 := b.NewValue0(v.Line, OpPPC64MaskIfNotCarry, config.fe.TypeInt64())
+ v2 := b.NewValue0(v.Line, OpPPC64ADDconstForCarry, TypeFlags)
+ v2.AuxInt = -64
+ v3 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+ v3.AddArg(y)
+ v2.AddArg(v3)
+ v1.AddArg(v2)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValuePPC64_OpRsh64x32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh64x32 x (Const64 [c]))
+ // cond: uint32(c) < 64
+ // result: (SRADconst x [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpConst64 {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint32(c) < 64) {
+ break
+ }
+ v.reset(OpPPC64SRADconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (Rsh64x32 x (MOVDconst [c]))
+ // cond: uint32(c) < 64
+ // result: (SRADconst x [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpPPC64MOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint32(c) < 64) {
+ break
+ }
+ v.reset(OpPPC64SRADconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (Rsh64x32 x y)
+ // cond:
+ // result: (SRAD x (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-64] (ZeroExt32to64 y)))))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64SRAD)
+ v.AddArg(x)
+ v0 := b.NewValue0(v.Line, OpPPC64ORN, config.fe.TypeInt64())
+ v0.AddArg(y)
+ v1 := b.NewValue0(v.Line, OpPPC64MaskIfNotCarry, config.fe.TypeInt64())
+ v2 := b.NewValue0(v.Line, OpPPC64ADDconstForCarry, TypeFlags)
+ v2.AuxInt = -64
+ v3 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+ v3.AddArg(y)
+ v2.AddArg(v3)
+ v1.AddArg(v2)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValuePPC64_OpRsh64x64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh64x64 x (Const64 [c]))
+ // cond: uint64(c) < 64
+ // result: (SRADconst x [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpConst64 {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint64(c) < 64) {
+ break
+ }
+ v.reset(OpPPC64SRADconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (Rsh64x64 x (Const64 [c]))
+ // cond: uint64(c) >= 64
+ // result: (SRADconst x [63])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpConst64 {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint64(c) >= 64) {
+ break
+ }
+ v.reset(OpPPC64SRADconst)
+ v.AuxInt = 63
+ v.AddArg(x)
+ return true
+ }
+ // match: (Rsh64x64 x (MOVDconst [c]))
+ // cond: uint64(c) < 64
+ // result: (SRADconst x [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpPPC64MOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint64(c) < 64) {
+ break
+ }
+ v.reset(OpPPC64SRADconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (Rsh64x64 x y)
+ // cond:
+ // result: (SRAD x (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-64] y))))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64SRAD)
+ v.AddArg(x)
+ v0 := b.NewValue0(v.Line, OpPPC64ORN, config.fe.TypeInt64())
+ v0.AddArg(y)
+ v1 := b.NewValue0(v.Line, OpPPC64MaskIfNotCarry, config.fe.TypeInt64())
+ v2 := b.NewValue0(v.Line, OpPPC64ADDconstForCarry, TypeFlags)
+ v2.AuxInt = -64
+ v2.AddArg(y)
+ v1.AddArg(v2)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValuePPC64_OpRsh64x8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh64x8 x y)
+ // cond:
+ // result: (SRAD x (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-64] (ZeroExt8to64 y)))))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64SRAD)
+ v.AddArg(x)
+ v0 := b.NewValue0(v.Line, OpPPC64ORN, config.fe.TypeInt64())
+ v0.AddArg(y)
+ v1 := b.NewValue0(v.Line, OpPPC64MaskIfNotCarry, config.fe.TypeInt64())
+ v2 := b.NewValue0(v.Line, OpPPC64ADDconstForCarry, TypeFlags)
+ v2.AuxInt = -64
+ v3 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+ v3.AddArg(y)
+ v2.AddArg(v3)
+ v1.AddArg(v2)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValuePPC64_OpRsh8Ux16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh8Ux16 x y)
+ // cond:
+ // result: (SRW (ZeroExt8to32 x) (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-8] (ZeroExt16to64 y)))))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64SRW)
+ v0 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpPPC64ORN, config.fe.TypeInt64())
+ v1.AddArg(y)
+ v2 := b.NewValue0(v.Line, OpPPC64MaskIfNotCarry, config.fe.TypeInt64())
+ v3 := b.NewValue0(v.Line, OpPPC64ADDconstForCarry, TypeFlags)
+ v3.AuxInt = -8
+ v4 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+ v4.AddArg(y)
+ v3.AddArg(v4)
+ v2.AddArg(v3)
+ v1.AddArg(v2)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValuePPC64_OpRsh8Ux32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh8Ux32 x (Const64 [c]))
+ // cond: uint32(c) < 8
+ // result: (SRWconst (ZeroExt8to32 x) [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpConst64 {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint32(c) < 8) {
+ break
+ }
+ v.reset(OpPPC64SRWconst)
+ v.AuxInt = c
+ v0 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (Rsh8Ux32 x (MOVDconst [c]))
+ // cond: uint32(c) < 8
+ // result: (SRWconst (ZeroExt8to32 x) [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpPPC64MOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint32(c) < 8) {
+ break
+ }
+ v.reset(OpPPC64SRWconst)
+ v.AuxInt = c
+ v0 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+ 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)))))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64SRW)
+ v0 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpPPC64ORN, config.fe.TypeInt64())
+ v1.AddArg(y)
+ v2 := b.NewValue0(v.Line, OpPPC64MaskIfNotCarry, config.fe.TypeInt64())
+ v3 := b.NewValue0(v.Line, OpPPC64ADDconstForCarry, TypeFlags)
+ v3.AuxInt = -8
+ v4 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+ v4.AddArg(y)
+ v3.AddArg(v4)
+ v2.AddArg(v3)
+ v1.AddArg(v2)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValuePPC64_OpRsh8Ux64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh8Ux64 x (Const64 [c]))
+ // cond: uint64(c) < 8
+ // result: (SRWconst (ZeroExt8to32 x) [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpConst64 {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint64(c) < 8) {
+ break
+ }
+ v.reset(OpPPC64SRWconst)
+ v.AuxInt = c
+ v0 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (Rsh8Ux64 _ (Const64 [c]))
+ // cond: uint64(c) >= 8
+ // result: (MOVDconst [0])
+ for {
+ v_1 := v.Args[1]
+ if v_1.Op != OpConst64 {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint64(c) >= 8) {
+ break
+ }
+ v.reset(OpPPC64MOVDconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (Rsh8Ux64 x (MOVDconst [c]))
+ // cond: uint64(c) < 8
+ // result: (SRWconst (ZeroExt8to32 x) [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpPPC64MOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint64(c) < 8) {
+ break
+ }
+ v.reset(OpPPC64SRWconst)
+ v.AuxInt = c
+ v0 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+ 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))))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64SRW)
+ v0 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpPPC64ORN, config.fe.TypeInt64())
+ v1.AddArg(y)
+ v2 := b.NewValue0(v.Line, OpPPC64MaskIfNotCarry, config.fe.TypeInt64())
+ v3 := b.NewValue0(v.Line, OpPPC64ADDconstForCarry, TypeFlags)
+ v3.AuxInt = -8
+ v3.AddArg(y)
+ v2.AddArg(v3)
+ v1.AddArg(v2)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValuePPC64_OpRsh8Ux8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh8Ux8 x y)
+ // cond:
+ // result: (SRW (ZeroExt8to32 x) (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-8] (ZeroExt8to64 y)))))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64SRW)
+ v0 := b.NewValue0(v.Line, OpZeroExt8to32, config.fe.TypeUInt32())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpPPC64ORN, config.fe.TypeInt64())
+ v1.AddArg(y)
+ v2 := b.NewValue0(v.Line, OpPPC64MaskIfNotCarry, config.fe.TypeInt64())
+ v3 := b.NewValue0(v.Line, OpPPC64ADDconstForCarry, TypeFlags)
+ v3.AuxInt = -8
+ v4 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+ v4.AddArg(y)
+ v3.AddArg(v4)
+ v2.AddArg(v3)
+ v1.AddArg(v2)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValuePPC64_OpRsh8x16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh8x16 x y)
+ // cond:
+ // result: (SRAW (SignExt8to32 x) (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-8] (ZeroExt16to64 y)))))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64SRAW)
+ v0 := b.NewValue0(v.Line, OpSignExt8to32, config.fe.TypeInt32())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpPPC64ORN, config.fe.TypeInt64())
+ v1.AddArg(y)
+ v2 := b.NewValue0(v.Line, OpPPC64MaskIfNotCarry, config.fe.TypeInt64())
+ v3 := b.NewValue0(v.Line, OpPPC64ADDconstForCarry, TypeFlags)
+ v3.AuxInt = -8
+ v4 := b.NewValue0(v.Line, OpZeroExt16to64, config.fe.TypeUInt64())
+ v4.AddArg(y)
+ v3.AddArg(v4)
+ v2.AddArg(v3)
+ v1.AddArg(v2)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValuePPC64_OpRsh8x32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh8x32 x (Const64 [c]))
+ // cond: uint32(c) < 8
+ // result: (SRAWconst (SignExt8to32 x) [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpConst64 {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint32(c) < 8) {
+ break
+ }
+ v.reset(OpPPC64SRAWconst)
+ v.AuxInt = c
+ v0 := b.NewValue0(v.Line, OpSignExt8to32, config.fe.TypeInt32())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (Rsh8x32 x (MOVDconst [c]))
+ // cond: uint32(c) < 8
+ // result: (SRAWconst (SignExt8to32 x) [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpPPC64MOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint32(c) < 8) {
+ break
+ }
+ v.reset(OpPPC64SRAWconst)
+ v.AuxInt = c
+ v0 := b.NewValue0(v.Line, OpSignExt8to32, config.fe.TypeInt32())
+ 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)))))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64SRAW)
+ v0 := b.NewValue0(v.Line, OpSignExt8to32, config.fe.TypeInt32())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpPPC64ORN, config.fe.TypeInt64())
+ v1.AddArg(y)
+ v2 := b.NewValue0(v.Line, OpPPC64MaskIfNotCarry, config.fe.TypeInt64())
+ v3 := b.NewValue0(v.Line, OpPPC64ADDconstForCarry, TypeFlags)
+ v3.AuxInt = -8
+ v4 := b.NewValue0(v.Line, OpZeroExt32to64, config.fe.TypeUInt64())
+ v4.AddArg(y)
+ v3.AddArg(v4)
+ v2.AddArg(v3)
+ v1.AddArg(v2)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValuePPC64_OpRsh8x64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh8x64 x (Const64 [c]))
+ // cond: uint64(c) < 8
+ // result: (SRAWconst (SignExt8to32 x) [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpConst64 {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint64(c) < 8) {
+ break
+ }
+ v.reset(OpPPC64SRAWconst)
+ v.AuxInt = c
+ v0 := b.NewValue0(v.Line, OpSignExt8to32, config.fe.TypeInt32())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (Rsh8x64 x (Const64 [c]))
+ // cond: uint64(c) >= 8
+ // result: (SRAWconst (SignExt8to32 x) [63])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpConst64 {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint64(c) >= 8) {
+ break
+ }
+ v.reset(OpPPC64SRAWconst)
+ v.AuxInt = 63
+ v0 := b.NewValue0(v.Line, OpSignExt8to32, config.fe.TypeInt32())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (Rsh8x64 x (MOVDconst [c]))
+ // cond: uint64(c) < 8
+ // result: (SRAWconst (SignExt8to32 x) [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpPPC64MOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ if !(uint64(c) < 8) {
+ break
+ }
+ v.reset(OpPPC64SRAWconst)
+ v.AuxInt = c
+ v0 := b.NewValue0(v.Line, OpSignExt8to32, config.fe.TypeInt32())
+ 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))))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64SRAW)
+ v0 := b.NewValue0(v.Line, OpSignExt8to32, config.fe.TypeInt32())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpPPC64ORN, config.fe.TypeInt64())
+ v1.AddArg(y)
+ v2 := b.NewValue0(v.Line, OpPPC64MaskIfNotCarry, config.fe.TypeInt64())
+ v3 := b.NewValue0(v.Line, OpPPC64ADDconstForCarry, TypeFlags)
+ v3.AuxInt = -8
+ v3.AddArg(y)
+ v2.AddArg(v3)
+ v1.AddArg(v2)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValuePPC64_OpRsh8x8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh8x8 x y)
+ // cond:
+ // result: (SRAW (SignExt8to32 x) (ORN y <config.fe.TypeInt64()> (MaskIfNotCarry (ADDconstForCarry [-8] (ZeroExt8to64 y)))))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64SRAW)
+ v0 := b.NewValue0(v.Line, OpSignExt8to32, config.fe.TypeInt32())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpPPC64ORN, config.fe.TypeInt64())
+ v1.AddArg(y)
+ v2 := b.NewValue0(v.Line, OpPPC64MaskIfNotCarry, config.fe.TypeInt64())
+ v3 := b.NewValue0(v.Line, OpPPC64ADDconstForCarry, TypeFlags)
+ v3.AuxInt = -8
+ v4 := b.NewValue0(v.Line, OpZeroExt8to64, config.fe.TypeUInt64())
+ v4.AddArg(y)
+ v3.AddArg(v4)
+ v2.AddArg(v3)
+ v1.AddArg(v2)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValuePPC64_OpSignExt16to32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SignExt16to32 x)
+ // cond:
+ // result: (MOVHreg x)
+ for {
+ x := v.Args[0]
+ v.reset(OpPPC64MOVHreg)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValuePPC64_OpSignExt16to64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SignExt16to64 x)
+ // cond:
+ // result: (MOVHreg x)
+ for {
+ x := v.Args[0]
+ v.reset(OpPPC64MOVHreg)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValuePPC64_OpSignExt32to64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SignExt32to64 x)
+ // cond:
+ // result: (MOVWreg x)
+ for {
+ x := v.Args[0]
+ v.reset(OpPPC64MOVWreg)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValuePPC64_OpSignExt8to16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SignExt8to16 x)
+ // cond:
+ // result: (MOVBreg x)
+ for {
+ x := v.Args[0]
+ v.reset(OpPPC64MOVBreg)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValuePPC64_OpSignExt8to32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SignExt8to32 x)
+ // cond:
+ // result: (MOVBreg x)
+ for {
+ x := v.Args[0]
+ v.reset(OpPPC64MOVBreg)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValuePPC64_OpSignExt8to64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SignExt8to64 x)
+ // cond:
+ // result: (MOVBreg x)
+ for {
+ x := v.Args[0]
+ v.reset(OpPPC64MOVBreg)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValuePPC64_OpSlicemask(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Slicemask <t> x)
+ // cond:
+ // result: (XORconst [-1] (SRADconst <t> (ADDconst <t> x [-1]) [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.AddArg(v0)
+ return true
+ }
+}
+func rewriteValuePPC64_OpSqrt(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Sqrt x)
+ // cond:
+ // result: (FSQRT x)
+ for {
+ x := v.Args[0]
+ v.reset(OpPPC64FSQRT)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValuePPC64_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(OpPPC64CALLstatic)
+ v.AuxInt = argwid
+ v.Aux = target
+ v.AddArg(mem)
+ return true
+ }
+}
+func rewriteValuePPC64_OpStore(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Store [8] ptr val mem)
+ // cond: is64BitFloat(val.Type)
+ // result: (FMOVDstore ptr val mem)
+ for {
+ if v.AuxInt != 8 {
+ break
+ }
+ ptr := v.Args[0]
+ val := v.Args[1]
+ mem := v.Args[2]
+ if !(is64BitFloat(val.Type)) {
+ break
+ }
+ v.reset(OpPPC64FMOVDstore)
+ v.AddArg(ptr)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (Store [8] ptr val mem)
+ // cond: is32BitFloat(val.Type)
+ // result: (FMOVDstore ptr val mem)
+ for {
+ if v.AuxInt != 8 {
+ break
+ }
+ ptr := v.Args[0]
+ val := v.Args[1]
+ mem := v.Args[2]
+ if !(is32BitFloat(val.Type)) {
+ break
+ }
+ v.reset(OpPPC64FMOVDstore)
+ v.AddArg(ptr)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (Store [4] ptr val mem)
+ // cond: is32BitFloat(val.Type)
+ // result: (FMOVSstore ptr val mem)
+ for {
+ if v.AuxInt != 4 {
+ break
+ }
+ ptr := v.Args[0]
+ val := v.Args[1]
+ mem := v.Args[2]
+ if !(is32BitFloat(val.Type)) {
+ break
+ }
+ v.reset(OpPPC64FMOVSstore)
+ v.AddArg(ptr)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (Store [8] ptr val mem)
+ // cond: (is64BitInt(val.Type) || isPtr(val.Type))
+ // result: (MOVDstore ptr val mem)
+ for {
+ if v.AuxInt != 8 {
+ break
+ }
+ ptr := v.Args[0]
+ val := v.Args[1]
+ mem := v.Args[2]
+ if !(is64BitInt(val.Type) || isPtr(val.Type)) {
+ break
+ }
+ v.reset(OpPPC64MOVDstore)
+ v.AddArg(ptr)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (Store [4] ptr val mem)
+ // cond: is32BitInt(val.Type)
+ // result: (MOVWstore ptr val mem)
+ for {
+ if v.AuxInt != 4 {
+ break
+ }
+ ptr := v.Args[0]
+ val := v.Args[1]
+ mem := v.Args[2]
+ if !(is32BitInt(val.Type)) {
+ break
+ }
+ v.reset(OpPPC64MOVWstore)
+ 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 {
+ break
+ }
+ ptr := v.Args[0]
+ val := v.Args[1]
+ mem := v.Args[2]
+ v.reset(OpPPC64MOVHstore)
+ v.AddArg(ptr)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (Store [1] ptr val mem)
+ // cond:
+ // result: (MOVBstore ptr val mem)
+ for {
+ if v.AuxInt != 1 {
+ break
+ }
+ ptr := v.Args[0]
+ val := v.Args[1]
+ mem := v.Args[2]
+ v.reset(OpPPC64MOVBstore)
+ v.AddArg(ptr)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValuePPC64_OpSub16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Sub16 x y)
+ // cond:
+ // result: (SUB x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64SUB)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValuePPC64_OpSub32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Sub32 x y)
+ // cond:
+ // result: (SUB x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64SUB)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValuePPC64_OpSub32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Sub32F x y)
+ // cond:
+ // result: (FSUBS x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64FSUBS)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValuePPC64_OpSub64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Sub64 x y)
+ // cond:
+ // result: (SUB x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64SUB)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValuePPC64_OpSub64F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Sub64F x y)
+ // cond:
+ // result: (FSUB x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64FSUB)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValuePPC64_OpSub8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Sub8 x y)
+ // cond:
+ // result: (SUB x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64SUB)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValuePPC64_OpSubPtr(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SubPtr x y)
+ // cond:
+ // result: (SUB x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64SUB)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValuePPC64_OpTrunc16to8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Trunc16to8 x)
+ // cond:
+ // result: (MOVBreg x)
+ for {
+ x := v.Args[0]
+ v.reset(OpPPC64MOVBreg)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValuePPC64_OpTrunc32to16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Trunc32to16 x)
+ // cond:
+ // result: (MOVHreg x)
+ for {
+ x := v.Args[0]
+ v.reset(OpPPC64MOVHreg)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValuePPC64_OpTrunc32to8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Trunc32to8 x)
+ // cond:
+ // result: (MOVBreg x)
+ for {
+ x := v.Args[0]
+ v.reset(OpPPC64MOVBreg)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValuePPC64_OpTrunc64to16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Trunc64to16 x)
+ // cond:
+ // result: (MOVHreg x)
+ for {
+ x := v.Args[0]
+ v.reset(OpPPC64MOVHreg)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValuePPC64_OpTrunc64to32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Trunc64to32 x)
+ // cond:
+ // result: (MOVWreg x)
+ for {
+ x := v.Args[0]
+ v.reset(OpPPC64MOVWreg)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValuePPC64_OpTrunc64to8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Trunc64to8 x)
+ // cond:
+ // result: (MOVBreg x)
+ for {
+ x := v.Args[0]
+ v.reset(OpPPC64MOVBreg)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValuePPC64_OpXor16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Xor16 x y)
+ // cond:
+ // result: (XOR x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64XOR)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValuePPC64_OpXor32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Xor32 x y)
+ // cond:
+ // result: (XOR x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64XOR)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValuePPC64_OpXor64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Xor64 x y)
+ // cond:
+ // result: (XOR x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64XOR)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValuePPC64_OpXor8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Xor8 x y)
+ // cond:
+ // result: (XOR x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpPPC64XOR)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValuePPC64_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) {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = mem.Type
+ v.AddArg(mem)
+ return true
+ }
+ // match: (Zero [s] destptr mem)
+ // cond: SizeAndAlign(s).Size() == 1
+ // result: (MOVBstorezero destptr mem)
+ for {
+ s := v.AuxInt
+ destptr := v.Args[0]
+ mem := v.Args[1]
+ if !(SizeAndAlign(s).Size() == 1) {
+ break
+ }
+ 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
+ // 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) {
+ break
+ }
+ 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))
+ for {
+ s := v.AuxInt
+ destptr := v.Args[0]
+ mem := v.Args[1]
+ if !(SizeAndAlign(s).Size() == 2) {
+ break
+ }
+ v.reset(OpPPC64MOVBstorezero)
+ v.AuxInt = 1
+ v.AddArg(destptr)
+ v0 := b.NewValue0(v.Line, OpPPC64MOVBstorezero, TypeMem)
+ v0.AuxInt = 0
+ 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
+ // 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) {
+ break
+ }
+ 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))
+ for {
+ s := v.AuxInt
+ destptr := v.Args[0]
+ mem := v.Args[1]
+ if !(SizeAndAlign(s).Size() == 4 && SizeAndAlign(s).Align()%2 == 0) {
+ break
+ }
+ v.reset(OpPPC64MOVHstorezero)
+ v.AuxInt = 2
+ v.AddArg(destptr)
+ v0 := b.NewValue0(v.Line, OpPPC64MOVHstorezero, TypeMem)
+ v0.AuxInt = 0
+ 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))))
+ for {
+ s := v.AuxInt
+ destptr := v.Args[0]
+ mem := v.Args[1]
+ if !(SizeAndAlign(s).Size() == 4) {
+ break
+ }
+ v.reset(OpPPC64MOVBstorezero)
+ v.AuxInt = 3
+ v.AddArg(destptr)
+ v0 := b.NewValue0(v.Line, OpPPC64MOVBstorezero, TypeMem)
+ v0.AuxInt = 2
+ v0.AddArg(destptr)
+ v1 := b.NewValue0(v.Line, OpPPC64MOVBstorezero, TypeMem)
+ v1.AuxInt = 1
+ v1.AddArg(destptr)
+ v2 := b.NewValue0(v.Line, OpPPC64MOVBstorezero, 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() == 8 && SizeAndAlign(s).Align()%8 == 0
+ // result: (MOVDstorezero [0] destptr mem)
+ for {
+ s := v.AuxInt
+ destptr := v.Args[0]
+ mem := v.Args[1]
+ if !(SizeAndAlign(s).Size() == 8 && SizeAndAlign(s).Align()%8 == 0) {
+ break
+ }
+ 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))
+ for {
+ s := v.AuxInt
+ destptr := v.Args[0]
+ mem := v.Args[1]
+ if !(SizeAndAlign(s).Size() == 8 && SizeAndAlign(s).Align()%4 == 0) {
+ break
+ }
+ v.reset(OpPPC64MOVWstorezero)
+ v.AuxInt = 4
+ v.AddArg(destptr)
+ v0 := b.NewValue0(v.Line, OpPPC64MOVWstorezero, 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))))
+ for {
+ s := v.AuxInt
+ destptr := v.Args[0]
+ mem := v.Args[1]
+ if !(SizeAndAlign(s).Size() == 8 && SizeAndAlign(s).Align()%2 == 0) {
+ break
+ }
+ v.reset(OpPPC64MOVHstorezero)
+ v.AuxInt = 6
+ v.AddArg(destptr)
+ v0 := b.NewValue0(v.Line, OpPPC64MOVHstorezero, TypeMem)
+ v0.AuxInt = 4
+ 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)
+ 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)))
+ for {
+ s := v.AuxInt
+ destptr := v.Args[0]
+ mem := v.Args[1]
+ if !(SizeAndAlign(s).Size() == 3) {
+ break
+ }
+ v.reset(OpPPC64MOVBstorezero)
+ v.AuxInt = 2
+ v.AddArg(destptr)
+ v0 := b.NewValue0(v.Line, OpPPC64MOVBstorezero, TypeMem)
+ v0.AuxInt = 1
+ v0.AddArg(destptr)
+ v1 := b.NewValue0(v.Line, OpPPC64MOVBstorezero, TypeMem)
+ v1.AuxInt = 0
+ v1.AddArg(destptr)
+ v1.AddArg(mem)
+ v0.AddArg(v1)
+ 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))
+ for {
+ s := v.AuxInt
+ destptr := v.Args[0]
+ mem := v.Args[1]
+ if !(SizeAndAlign(s).Size() == 16 && SizeAndAlign(s).Align()%8 == 0) {
+ break
+ }
+ v.reset(OpPPC64MOVDstorezero)
+ v.AuxInt = 8
+ v.AddArg(destptr)
+ v0 := b.NewValue0(v.Line, OpPPC64MOVDstorezero, TypeMem)
+ v0.AuxInt = 0
+ v0.AddArg(destptr)
+ v0.AddArg(mem)
+ 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)))
+ for {
+ s := v.AuxInt
+ destptr := v.Args[0]
+ mem := v.Args[1]
+ if !(SizeAndAlign(s).Size() == 24 && SizeAndAlign(s).Align()%8 == 0) {
+ break
+ }
+ v.reset(OpPPC64MOVDstorezero)
+ v.AuxInt = 16
+ v.AddArg(destptr)
+ v0 := b.NewValue0(v.Line, OpPPC64MOVDstorezero, TypeMem)
+ v0.AuxInt = 8
+ v0.AddArg(destptr)
+ v1 := b.NewValue0(v.Line, OpPPC64MOVDstorezero, TypeMem)
+ v1.AuxInt = 0
+ v1.AddArg(destptr)
+ v1.AddArg(mem)
+ 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))))
+ for {
+ s := v.AuxInt
+ destptr := v.Args[0]
+ mem := v.Args[1]
+ if !(SizeAndAlign(s).Size() == 32 && SizeAndAlign(s).Align()%8 == 0) {
+ break
+ }
+ v.reset(OpPPC64MOVDstorezero)
+ v.AuxInt = 24
+ v.AddArg(destptr)
+ v0 := b.NewValue0(v.Line, OpPPC64MOVDstorezero, TypeMem)
+ v0.AuxInt = 16
+ v0.AddArg(destptr)
+ v1 := b.NewValue0(v.Line, OpPPC64MOVDstorezero, TypeMem)
+ v1.AuxInt = 8
+ v1.AddArg(destptr)
+ v2 := b.NewValue0(v.Line, OpPPC64MOVDstorezero, TypeMem)
+ v2.AuxInt = 0
+ v2.AddArg(destptr)
+ v2.AddArg(mem)
+ 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)
+ for {
+ s := v.AuxInt
+ 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.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
+ // match: (ZeroExt16to32 x)
+ // cond:
+ // result: (MOVHZreg x)
+ for {
+ x := v.Args[0]
+ v.reset(OpPPC64MOVHZreg)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValuePPC64_OpZeroExt16to64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ZeroExt16to64 x)
+ // cond:
+ // result: (MOVHZreg x)
+ for {
+ x := v.Args[0]
+ v.reset(OpPPC64MOVHZreg)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValuePPC64_OpZeroExt32to64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ZeroExt32to64 x)
+ // cond:
+ // result: (MOVWZreg x)
+ for {
+ x := v.Args[0]
+ v.reset(OpPPC64MOVWZreg)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValuePPC64_OpZeroExt8to16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ZeroExt8to16 x)
+ // cond:
+ // result: (MOVBZreg x)
+ for {
+ x := v.Args[0]
+ v.reset(OpPPC64MOVBZreg)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValuePPC64_OpZeroExt8to32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ZeroExt8to32 x)
+ // cond:
+ // result: (MOVBZreg x)
+ for {
+ x := v.Args[0]
+ v.reset(OpPPC64MOVBZreg)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValuePPC64_OpZeroExt8to64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ZeroExt8to64 x)
+ // cond:
+ // result: (MOVBZreg x)
+ for {
+ x := v.Args[0]
+ v.reset(OpPPC64MOVBZreg)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteBlockPPC64(b *Block, config *Config) bool {
+ switch b.Kind {
+ case BlockPPC64EQ:
+ // match: (EQ (CMPconst [0] (ANDconst [c] x)) yes no)
+ // cond:
+ // result: (EQ (ANDCCconst [c] x) yes no)
+ for {
+ v := b.Control
+ if v.Op != OpPPC64CMPconst {
+ break
+ }
+ if v.AuxInt != 0 {
+ break
+ }
+ v_0 := v.Args[0]
+ if v_0.Op != OpPPC64ANDconst {
+ break
+ }
+ 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.AuxInt = c
+ v0.AddArg(x)
+ b.SetControl(v0)
+ _ = yes
+ _ = no
+ return true
+ }
+ // match: (EQ (CMPWconst [0] (ANDconst [c] x)) yes no)
+ // cond:
+ // result: (EQ (ANDCCconst [c] x) yes no)
+ for {
+ v := b.Control
+ if v.Op != OpPPC64CMPWconst {
+ break
+ }
+ if v.AuxInt != 0 {
+ break
+ }
+ v_0 := v.Args[0]
+ if v_0.Op != OpPPC64ANDconst {
+ break
+ }
+ 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.AuxInt = c
+ v0.AddArg(x)
+ b.SetControl(v0)
+ _ = yes
+ _ = no
+ return true
+ }
+ // match: (EQ (FlagEQ) yes no)
+ // cond:
+ // result: (First nil yes no)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil no yes)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil no yes)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (EQ cmp yes no)
+ for {
+ v := b.Control
+ if v.Op != OpPPC64InvertFlags {
+ 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:
+ // match: (GE (FlagEQ) yes no)
+ // cond:
+ // result: (First nil yes no)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil no yes)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil yes no)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (LE cmp yes no)
+ for {
+ v := b.Control
+ if v.Op != OpPPC64InvertFlags {
+ 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:
+ // match: (GT (FlagEQ) yes no)
+ // cond:
+ // result: (First nil no yes)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil no yes)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil yes no)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (LT cmp yes no)
+ for {
+ v := b.Control
+ if v.Op != OpPPC64InvertFlags {
+ 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:
+ // match: (If (Equal cc) yes no)
+ // cond:
+ // result: (EQ cc yes no)
+ for {
+ v := b.Control
+ if v.Op != OpPPC64Equal {
+ 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)
+ // cond:
+ // result: (NE cc yes no)
+ for {
+ v := b.Control
+ if v.Op != OpPPC64NotEqual {
+ 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)
+ // cond:
+ // result: (LT cc yes no)
+ for {
+ v := b.Control
+ if v.Op != OpPPC64LessThan {
+ 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)
+ // cond:
+ // result: (LE cc yes no)
+ for {
+ v := b.Control
+ if v.Op != OpPPC64LessEqual {
+ 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)
+ // cond:
+ // result: (GT cc yes no)
+ for {
+ v := b.Control
+ if v.Op != OpPPC64GreaterThan {
+ 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)
+ // cond:
+ // result: (GE cc yes no)
+ for {
+ v := b.Control
+ if v.Op != OpPPC64GreaterEqual {
+ 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)
+ // cond:
+ // result: (FLT cc yes no)
+ for {
+ v := b.Control
+ if v.Op != OpPPC64FLessThan {
+ 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)
+ // cond:
+ // result: (FLE cc yes no)
+ for {
+ v := b.Control
+ if v.Op != OpPPC64FLessEqual {
+ 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)
+ // cond:
+ // result: (FGT cc yes no)
+ for {
+ v := b.Control
+ if v.Op != OpPPC64FGreaterThan {
+ 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)
+ // cond:
+ // result: (FGE cc yes no)
+ for {
+ v := b.Control
+ if v.Op != OpPPC64FGreaterEqual {
+ 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)
+ // cond:
+ // result: (NE (CMPWconst [0] cond) yes no)
+ for {
+ 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.AuxInt = 0
+ v0.AddArg(cond)
+ b.SetControl(v0)
+ _ = yes
+ _ = no
+ return true
+ }
+ case BlockPPC64LE:
+ // match: (LE (FlagEQ) yes no)
+ // cond:
+ // result: (First nil yes no)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil yes no)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil no yes)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (GE cmp yes no)
+ for {
+ v := b.Control
+ if v.Op != OpPPC64InvertFlags {
+ 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:
+ // match: (LT (FlagEQ) yes no)
+ // cond:
+ // result: (First nil no yes)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil yes no)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil no yes)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (GT cmp yes no)
+ for {
+ v := b.Control
+ if v.Op != OpPPC64InvertFlags {
+ 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:
+ // match: (NE (CMPWconst [0] (Equal cc)) yes no)
+ // cond:
+ // result: (EQ cc yes no)
+ for {
+ v := b.Control
+ if v.Op != OpPPC64CMPWconst {
+ break
+ }
+ if v.AuxInt != 0 {
+ break
+ }
+ v_0 := v.Args[0]
+ if v_0.Op != OpPPC64Equal {
+ 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)
+ // cond:
+ // result: (NE cc yes no)
+ for {
+ v := b.Control
+ if v.Op != OpPPC64CMPWconst {
+ break
+ }
+ if v.AuxInt != 0 {
+ break
+ }
+ v_0 := v.Args[0]
+ if v_0.Op != OpPPC64NotEqual {
+ 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)
+ // cond:
+ // result: (LT cc yes no)
+ for {
+ v := b.Control
+ if v.Op != OpPPC64CMPWconst {
+ break
+ }
+ if v.AuxInt != 0 {
+ break
+ }
+ v_0 := v.Args[0]
+ if v_0.Op != OpPPC64LessThan {
+ 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)
+ // cond:
+ // result: (LE cc yes no)
+ for {
+ v := b.Control
+ if v.Op != OpPPC64CMPWconst {
+ break
+ }
+ if v.AuxInt != 0 {
+ break
+ }
+ v_0 := v.Args[0]
+ if v_0.Op != OpPPC64LessEqual {
+ 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)
+ // cond:
+ // result: (GT cc yes no)
+ for {
+ v := b.Control
+ if v.Op != OpPPC64CMPWconst {
+ break
+ }
+ if v.AuxInt != 0 {
+ break
+ }
+ v_0 := v.Args[0]
+ if v_0.Op != OpPPC64GreaterThan {
+ 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)
+ // cond:
+ // result: (GE cc yes no)
+ for {
+ v := b.Control
+ if v.Op != OpPPC64CMPWconst {
+ break
+ }
+ if v.AuxInt != 0 {
+ break
+ }
+ v_0 := v.Args[0]
+ if v_0.Op != OpPPC64GreaterEqual {
+ 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)
+ // cond:
+ // result: (FLT cc yes no)
+ for {
+ v := b.Control
+ if v.Op != OpPPC64CMPWconst {
+ break
+ }
+ if v.AuxInt != 0 {
+ break
+ }
+ v_0 := v.Args[0]
+ if v_0.Op != OpPPC64FLessThan {
+ 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)
+ // cond:
+ // result: (FLE cc yes no)
+ for {
+ v := b.Control
+ if v.Op != OpPPC64CMPWconst {
+ break
+ }
+ if v.AuxInt != 0 {
+ break
+ }
+ v_0 := v.Args[0]
+ if v_0.Op != OpPPC64FLessEqual {
+ 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)
+ // cond:
+ // result: (FGT cc yes no)
+ for {
+ v := b.Control
+ if v.Op != OpPPC64CMPWconst {
+ break
+ }
+ if v.AuxInt != 0 {
+ break
+ }
+ v_0 := v.Args[0]
+ if v_0.Op != OpPPC64FGreaterThan {
+ 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)
+ // cond:
+ // result: (FGE cc yes no)
+ for {
+ v := b.Control
+ if v.Op != OpPPC64CMPWconst {
+ break
+ }
+ if v.AuxInt != 0 {
+ break
+ }
+ v_0 := v.Args[0]
+ if v_0.Op != OpPPC64FGreaterEqual {
+ 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)
+ // cond:
+ // result: (NE (ANDCCconst [c] x) yes no)
+ for {
+ v := b.Control
+ if v.Op != OpPPC64CMPconst {
+ break
+ }
+ if v.AuxInt != 0 {
+ break
+ }
+ v_0 := v.Args[0]
+ if v_0.Op != OpPPC64ANDconst {
+ break
+ }
+ 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.AuxInt = c
+ v0.AddArg(x)
+ b.SetControl(v0)
+ _ = yes
+ _ = no
+ return true
+ }
+ // match: (NE (CMPWconst [0] (ANDconst [c] x)) yes no)
+ // cond:
+ // result: (NE (ANDCCconst [c] x) yes no)
+ for {
+ v := b.Control
+ if v.Op != OpPPC64CMPWconst {
+ break
+ }
+ if v.AuxInt != 0 {
+ break
+ }
+ v_0 := v.Args[0]
+ if v_0.Op != OpPPC64ANDconst {
+ break
+ }
+ 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.AuxInt = c
+ v0.AddArg(x)
+ b.SetControl(v0)
+ _ = yes
+ _ = no
+ return true
+ }
+ // match: (NE (FlagEQ) yes no)
+ // cond:
+ // result: (First nil no yes)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil yes no)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil yes no)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (NE cmp yes no)
+ for {
+ v := b.Control
+ if v.Op != OpPPC64InvertFlags {
+ break
+ }
+ cmp := v.Args[0]
+ yes := b.Succs[0]
+ no := b.Succs[1]
+ b.Kind = BlockPPC64NE
+ b.SetControl(cmp)
+ _ = yes
+ _ = no
+ return true
+ }
+ }
+ return false
+}
diff --git a/src/cmd/compile/internal/ssa/rewriteS390X.go b/src/cmd/compile/internal/ssa/rewriteS390X.go
new file mode 100644
index 0000000..7d023bc
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/rewriteS390X.go
@@ -0,0 +1,18694 @@
+// autogenerated from gen/S390X.rules: do not edit!
+// generated with: cd gen; go run *.go
+
+package ssa
+
+import "math"
+
+var _ = math.MinInt8 // in case not otherwise used
+func rewriteValueS390X(v *Value, config *Config) bool {
+ switch v.Op {
+ case OpAdd16:
+ return rewriteValueS390X_OpAdd16(v, config)
+ case OpAdd32:
+ return rewriteValueS390X_OpAdd32(v, config)
+ case OpAdd32F:
+ return rewriteValueS390X_OpAdd32F(v, config)
+ case OpAdd64:
+ return rewriteValueS390X_OpAdd64(v, config)
+ case OpAdd64F:
+ return rewriteValueS390X_OpAdd64F(v, config)
+ case OpAdd8:
+ return rewriteValueS390X_OpAdd8(v, config)
+ case OpAddPtr:
+ return rewriteValueS390X_OpAddPtr(v, config)
+ case OpAddr:
+ return rewriteValueS390X_OpAddr(v, config)
+ case OpAnd16:
+ return rewriteValueS390X_OpAnd16(v, config)
+ case OpAnd32:
+ return rewriteValueS390X_OpAnd32(v, config)
+ case OpAnd64:
+ return rewriteValueS390X_OpAnd64(v, config)
+ case OpAnd8:
+ return rewriteValueS390X_OpAnd8(v, config)
+ case OpAndB:
+ return rewriteValueS390X_OpAndB(v, config)
+ case OpAtomicAdd32:
+ return rewriteValueS390X_OpAtomicAdd32(v, config)
+ case OpAtomicAdd64:
+ return rewriteValueS390X_OpAtomicAdd64(v, config)
+ case OpAtomicCompareAndSwap32:
+ return rewriteValueS390X_OpAtomicCompareAndSwap32(v, config)
+ case OpAtomicCompareAndSwap64:
+ return rewriteValueS390X_OpAtomicCompareAndSwap64(v, config)
+ case OpAtomicExchange32:
+ return rewriteValueS390X_OpAtomicExchange32(v, config)
+ case OpAtomicExchange64:
+ return rewriteValueS390X_OpAtomicExchange64(v, config)
+ case OpAtomicLoad32:
+ return rewriteValueS390X_OpAtomicLoad32(v, config)
+ case OpAtomicLoad64:
+ return rewriteValueS390X_OpAtomicLoad64(v, config)
+ case OpAtomicLoadPtr:
+ return rewriteValueS390X_OpAtomicLoadPtr(v, config)
+ case OpAtomicStore32:
+ return rewriteValueS390X_OpAtomicStore32(v, config)
+ case OpAtomicStore64:
+ return rewriteValueS390X_OpAtomicStore64(v, config)
+ case OpAtomicStorePtrNoWB:
+ return rewriteValueS390X_OpAtomicStorePtrNoWB(v, config)
+ case OpAvg64u:
+ return rewriteValueS390X_OpAvg64u(v, config)
+ case OpBswap32:
+ return rewriteValueS390X_OpBswap32(v, config)
+ case OpBswap64:
+ return rewriteValueS390X_OpBswap64(v, config)
+ case OpClosureCall:
+ return rewriteValueS390X_OpClosureCall(v, config)
+ case OpCom16:
+ return rewriteValueS390X_OpCom16(v, config)
+ case OpCom32:
+ return rewriteValueS390X_OpCom32(v, config)
+ case OpCom64:
+ return rewriteValueS390X_OpCom64(v, config)
+ case OpCom8:
+ return rewriteValueS390X_OpCom8(v, config)
+ case OpConst16:
+ return rewriteValueS390X_OpConst16(v, config)
+ case OpConst32:
+ return rewriteValueS390X_OpConst32(v, config)
+ case OpConst32F:
+ return rewriteValueS390X_OpConst32F(v, config)
+ case OpConst64:
+ return rewriteValueS390X_OpConst64(v, config)
+ case OpConst64F:
+ return rewriteValueS390X_OpConst64F(v, config)
+ case OpConst8:
+ return rewriteValueS390X_OpConst8(v, config)
+ case OpConstBool:
+ return rewriteValueS390X_OpConstBool(v, config)
+ case OpConstNil:
+ return rewriteValueS390X_OpConstNil(v, config)
+ case OpConvert:
+ return rewriteValueS390X_OpConvert(v, config)
+ case OpCtz32:
+ return rewriteValueS390X_OpCtz32(v, config)
+ case OpCtz64:
+ return rewriteValueS390X_OpCtz64(v, config)
+ case OpCvt32Fto32:
+ return rewriteValueS390X_OpCvt32Fto32(v, config)
+ case OpCvt32Fto64:
+ return rewriteValueS390X_OpCvt32Fto64(v, config)
+ case OpCvt32Fto64F:
+ return rewriteValueS390X_OpCvt32Fto64F(v, config)
+ case OpCvt32to32F:
+ return rewriteValueS390X_OpCvt32to32F(v, config)
+ case OpCvt32to64F:
+ return rewriteValueS390X_OpCvt32to64F(v, config)
+ case OpCvt64Fto32:
+ return rewriteValueS390X_OpCvt64Fto32(v, config)
+ case OpCvt64Fto32F:
+ return rewriteValueS390X_OpCvt64Fto32F(v, config)
+ case OpCvt64Fto64:
+ return rewriteValueS390X_OpCvt64Fto64(v, config)
+ case OpCvt64to32F:
+ return rewriteValueS390X_OpCvt64to32F(v, config)
+ case OpCvt64to64F:
+ return rewriteValueS390X_OpCvt64to64F(v, config)
+ case OpDeferCall:
+ return rewriteValueS390X_OpDeferCall(v, config)
+ case OpDiv16:
+ return rewriteValueS390X_OpDiv16(v, config)
+ case OpDiv16u:
+ return rewriteValueS390X_OpDiv16u(v, config)
+ case OpDiv32:
+ return rewriteValueS390X_OpDiv32(v, config)
+ case OpDiv32F:
+ return rewriteValueS390X_OpDiv32F(v, config)
+ case OpDiv32u:
+ return rewriteValueS390X_OpDiv32u(v, config)
+ case OpDiv64:
+ return rewriteValueS390X_OpDiv64(v, config)
+ case OpDiv64F:
+ return rewriteValueS390X_OpDiv64F(v, config)
+ case OpDiv64u:
+ return rewriteValueS390X_OpDiv64u(v, config)
+ case OpDiv8:
+ return rewriteValueS390X_OpDiv8(v, config)
+ case OpDiv8u:
+ return rewriteValueS390X_OpDiv8u(v, config)
+ case OpEq16:
+ return rewriteValueS390X_OpEq16(v, config)
+ case OpEq32:
+ return rewriteValueS390X_OpEq32(v, config)
+ case OpEq32F:
+ return rewriteValueS390X_OpEq32F(v, config)
+ case OpEq64:
+ return rewriteValueS390X_OpEq64(v, config)
+ case OpEq64F:
+ return rewriteValueS390X_OpEq64F(v, config)
+ case OpEq8:
+ return rewriteValueS390X_OpEq8(v, config)
+ case OpEqB:
+ return rewriteValueS390X_OpEqB(v, config)
+ case OpEqPtr:
+ return rewriteValueS390X_OpEqPtr(v, config)
+ case OpGeq16:
+ return rewriteValueS390X_OpGeq16(v, config)
+ case OpGeq16U:
+ return rewriteValueS390X_OpGeq16U(v, config)
+ case OpGeq32:
+ return rewriteValueS390X_OpGeq32(v, config)
+ case OpGeq32F:
+ return rewriteValueS390X_OpGeq32F(v, config)
+ case OpGeq32U:
+ return rewriteValueS390X_OpGeq32U(v, config)
+ case OpGeq64:
+ return rewriteValueS390X_OpGeq64(v, config)
+ case OpGeq64F:
+ return rewriteValueS390X_OpGeq64F(v, config)
+ case OpGeq64U:
+ return rewriteValueS390X_OpGeq64U(v, config)
+ case OpGeq8:
+ return rewriteValueS390X_OpGeq8(v, config)
+ case OpGeq8U:
+ return rewriteValueS390X_OpGeq8U(v, config)
+ case OpGetClosurePtr:
+ return rewriteValueS390X_OpGetClosurePtr(v, config)
+ case OpGetG:
+ return rewriteValueS390X_OpGetG(v, config)
+ case OpGoCall:
+ return rewriteValueS390X_OpGoCall(v, config)
+ case OpGreater16:
+ return rewriteValueS390X_OpGreater16(v, config)
+ case OpGreater16U:
+ return rewriteValueS390X_OpGreater16U(v, config)
+ case OpGreater32:
+ return rewriteValueS390X_OpGreater32(v, config)
+ case OpGreater32F:
+ return rewriteValueS390X_OpGreater32F(v, config)
+ case OpGreater32U:
+ return rewriteValueS390X_OpGreater32U(v, config)
+ case OpGreater64:
+ return rewriteValueS390X_OpGreater64(v, config)
+ case OpGreater64F:
+ return rewriteValueS390X_OpGreater64F(v, config)
+ case OpGreater64U:
+ return rewriteValueS390X_OpGreater64U(v, config)
+ case OpGreater8:
+ return rewriteValueS390X_OpGreater8(v, config)
+ case OpGreater8U:
+ return rewriteValueS390X_OpGreater8U(v, config)
+ case OpHmul16:
+ return rewriteValueS390X_OpHmul16(v, config)
+ case OpHmul16u:
+ return rewriteValueS390X_OpHmul16u(v, config)
+ case OpHmul32:
+ return rewriteValueS390X_OpHmul32(v, config)
+ case OpHmul32u:
+ return rewriteValueS390X_OpHmul32u(v, config)
+ case OpHmul64:
+ return rewriteValueS390X_OpHmul64(v, config)
+ case OpHmul64u:
+ return rewriteValueS390X_OpHmul64u(v, config)
+ case OpHmul8:
+ return rewriteValueS390X_OpHmul8(v, config)
+ case OpHmul8u:
+ return rewriteValueS390X_OpHmul8u(v, config)
+ case OpITab:
+ return rewriteValueS390X_OpITab(v, config)
+ case OpInterCall:
+ return rewriteValueS390X_OpInterCall(v, config)
+ case OpIsInBounds:
+ return rewriteValueS390X_OpIsInBounds(v, config)
+ case OpIsNonNil:
+ return rewriteValueS390X_OpIsNonNil(v, config)
+ case OpIsSliceInBounds:
+ return rewriteValueS390X_OpIsSliceInBounds(v, config)
+ case OpLeq16:
+ return rewriteValueS390X_OpLeq16(v, config)
+ case OpLeq16U:
+ return rewriteValueS390X_OpLeq16U(v, config)
+ case OpLeq32:
+ return rewriteValueS390X_OpLeq32(v, config)
+ case OpLeq32F:
+ return rewriteValueS390X_OpLeq32F(v, config)
+ case OpLeq32U:
+ return rewriteValueS390X_OpLeq32U(v, config)
+ case OpLeq64:
+ return rewriteValueS390X_OpLeq64(v, config)
+ case OpLeq64F:
+ return rewriteValueS390X_OpLeq64F(v, config)
+ case OpLeq64U:
+ return rewriteValueS390X_OpLeq64U(v, config)
+ case OpLeq8:
+ return rewriteValueS390X_OpLeq8(v, config)
+ case OpLeq8U:
+ return rewriteValueS390X_OpLeq8U(v, config)
+ case OpLess16:
+ return rewriteValueS390X_OpLess16(v, config)
+ case OpLess16U:
+ return rewriteValueS390X_OpLess16U(v, config)
+ case OpLess32:
+ return rewriteValueS390X_OpLess32(v, config)
+ case OpLess32F:
+ return rewriteValueS390X_OpLess32F(v, config)
+ case OpLess32U:
+ return rewriteValueS390X_OpLess32U(v, config)
+ case OpLess64:
+ return rewriteValueS390X_OpLess64(v, config)
+ case OpLess64F:
+ return rewriteValueS390X_OpLess64F(v, config)
+ case OpLess64U:
+ return rewriteValueS390X_OpLess64U(v, config)
+ case OpLess8:
+ return rewriteValueS390X_OpLess8(v, config)
+ case OpLess8U:
+ return rewriteValueS390X_OpLess8U(v, config)
+ case OpLoad:
+ return rewriteValueS390X_OpLoad(v, config)
+ case OpLrot32:
+ return rewriteValueS390X_OpLrot32(v, config)
+ case OpLrot64:
+ return rewriteValueS390X_OpLrot64(v, config)
+ case OpLsh16x16:
+ return rewriteValueS390X_OpLsh16x16(v, config)
+ case OpLsh16x32:
+ return rewriteValueS390X_OpLsh16x32(v, config)
+ case OpLsh16x64:
+ return rewriteValueS390X_OpLsh16x64(v, config)
+ case OpLsh16x8:
+ return rewriteValueS390X_OpLsh16x8(v, config)
+ case OpLsh32x16:
+ return rewriteValueS390X_OpLsh32x16(v, config)
+ case OpLsh32x32:
+ return rewriteValueS390X_OpLsh32x32(v, config)
+ case OpLsh32x64:
+ return rewriteValueS390X_OpLsh32x64(v, config)
+ case OpLsh32x8:
+ return rewriteValueS390X_OpLsh32x8(v, config)
+ case OpLsh64x16:
+ return rewriteValueS390X_OpLsh64x16(v, config)
+ case OpLsh64x32:
+ return rewriteValueS390X_OpLsh64x32(v, config)
+ case OpLsh64x64:
+ return rewriteValueS390X_OpLsh64x64(v, config)
+ case OpLsh64x8:
+ return rewriteValueS390X_OpLsh64x8(v, config)
+ case OpLsh8x16:
+ return rewriteValueS390X_OpLsh8x16(v, config)
+ case OpLsh8x32:
+ return rewriteValueS390X_OpLsh8x32(v, config)
+ case OpLsh8x64:
+ return rewriteValueS390X_OpLsh8x64(v, config)
+ case OpLsh8x8:
+ return rewriteValueS390X_OpLsh8x8(v, config)
+ case OpMod16:
+ return rewriteValueS390X_OpMod16(v, config)
+ case OpMod16u:
+ return rewriteValueS390X_OpMod16u(v, config)
+ case OpMod32:
+ return rewriteValueS390X_OpMod32(v, config)
+ case OpMod32u:
+ return rewriteValueS390X_OpMod32u(v, config)
+ case OpMod64:
+ return rewriteValueS390X_OpMod64(v, config)
+ case OpMod64u:
+ return rewriteValueS390X_OpMod64u(v, config)
+ case OpMod8:
+ return rewriteValueS390X_OpMod8(v, config)
+ case OpMod8u:
+ return rewriteValueS390X_OpMod8u(v, config)
+ case OpMove:
+ return rewriteValueS390X_OpMove(v, config)
+ case OpMul16:
+ return rewriteValueS390X_OpMul16(v, config)
+ case OpMul32:
+ return rewriteValueS390X_OpMul32(v, config)
+ case OpMul32F:
+ return rewriteValueS390X_OpMul32F(v, config)
+ case OpMul64:
+ return rewriteValueS390X_OpMul64(v, config)
+ case OpMul64F:
+ return rewriteValueS390X_OpMul64F(v, config)
+ case OpMul8:
+ return rewriteValueS390X_OpMul8(v, config)
+ case OpNeg16:
+ return rewriteValueS390X_OpNeg16(v, config)
+ case OpNeg32:
+ return rewriteValueS390X_OpNeg32(v, config)
+ case OpNeg32F:
+ return rewriteValueS390X_OpNeg32F(v, config)
+ case OpNeg64:
+ return rewriteValueS390X_OpNeg64(v, config)
+ case OpNeg64F:
+ return rewriteValueS390X_OpNeg64F(v, config)
+ case OpNeg8:
+ return rewriteValueS390X_OpNeg8(v, config)
+ case OpNeq16:
+ return rewriteValueS390X_OpNeq16(v, config)
+ case OpNeq32:
+ return rewriteValueS390X_OpNeq32(v, config)
+ case OpNeq32F:
+ return rewriteValueS390X_OpNeq32F(v, config)
+ case OpNeq64:
+ return rewriteValueS390X_OpNeq64(v, config)
+ case OpNeq64F:
+ return rewriteValueS390X_OpNeq64F(v, config)
+ case OpNeq8:
+ return rewriteValueS390X_OpNeq8(v, config)
+ case OpNeqB:
+ return rewriteValueS390X_OpNeqB(v, config)
+ case OpNeqPtr:
+ return rewriteValueS390X_OpNeqPtr(v, config)
+ case OpNilCheck:
+ return rewriteValueS390X_OpNilCheck(v, config)
+ case OpNot:
+ return rewriteValueS390X_OpNot(v, config)
+ case OpOffPtr:
+ return rewriteValueS390X_OpOffPtr(v, config)
+ case OpOr16:
+ return rewriteValueS390X_OpOr16(v, config)
+ case OpOr32:
+ return rewriteValueS390X_OpOr32(v, config)
+ case OpOr64:
+ return rewriteValueS390X_OpOr64(v, config)
+ case OpOr8:
+ return rewriteValueS390X_OpOr8(v, config)
+ case OpOrB:
+ return rewriteValueS390X_OpOrB(v, config)
+ case OpRsh16Ux16:
+ return rewriteValueS390X_OpRsh16Ux16(v, config)
+ case OpRsh16Ux32:
+ return rewriteValueS390X_OpRsh16Ux32(v, config)
+ case OpRsh16Ux64:
+ return rewriteValueS390X_OpRsh16Ux64(v, config)
+ case OpRsh16Ux8:
+ return rewriteValueS390X_OpRsh16Ux8(v, config)
+ case OpRsh16x16:
+ return rewriteValueS390X_OpRsh16x16(v, config)
+ case OpRsh16x32:
+ return rewriteValueS390X_OpRsh16x32(v, config)
+ case OpRsh16x64:
+ return rewriteValueS390X_OpRsh16x64(v, config)
+ case OpRsh16x8:
+ return rewriteValueS390X_OpRsh16x8(v, config)
+ case OpRsh32Ux16:
+ return rewriteValueS390X_OpRsh32Ux16(v, config)
+ case OpRsh32Ux32:
+ return rewriteValueS390X_OpRsh32Ux32(v, config)
+ case OpRsh32Ux64:
+ return rewriteValueS390X_OpRsh32Ux64(v, config)
+ case OpRsh32Ux8:
+ return rewriteValueS390X_OpRsh32Ux8(v, config)
+ case OpRsh32x16:
+ return rewriteValueS390X_OpRsh32x16(v, config)
+ case OpRsh32x32:
+ return rewriteValueS390X_OpRsh32x32(v, config)
+ case OpRsh32x64:
+ return rewriteValueS390X_OpRsh32x64(v, config)
+ case OpRsh32x8:
+ return rewriteValueS390X_OpRsh32x8(v, config)
+ case OpRsh64Ux16:
+ return rewriteValueS390X_OpRsh64Ux16(v, config)
+ case OpRsh64Ux32:
+ return rewriteValueS390X_OpRsh64Ux32(v, config)
+ case OpRsh64Ux64:
+ return rewriteValueS390X_OpRsh64Ux64(v, config)
+ case OpRsh64Ux8:
+ return rewriteValueS390X_OpRsh64Ux8(v, config)
+ case OpRsh64x16:
+ return rewriteValueS390X_OpRsh64x16(v, config)
+ case OpRsh64x32:
+ return rewriteValueS390X_OpRsh64x32(v, config)
+ case OpRsh64x64:
+ return rewriteValueS390X_OpRsh64x64(v, config)
+ case OpRsh64x8:
+ return rewriteValueS390X_OpRsh64x8(v, config)
+ case OpRsh8Ux16:
+ return rewriteValueS390X_OpRsh8Ux16(v, config)
+ case OpRsh8Ux32:
+ return rewriteValueS390X_OpRsh8Ux32(v, config)
+ case OpRsh8Ux64:
+ return rewriteValueS390X_OpRsh8Ux64(v, config)
+ case OpRsh8Ux8:
+ return rewriteValueS390X_OpRsh8Ux8(v, config)
+ case OpRsh8x16:
+ return rewriteValueS390X_OpRsh8x16(v, config)
+ case OpRsh8x32:
+ return rewriteValueS390X_OpRsh8x32(v, config)
+ case OpRsh8x64:
+ return rewriteValueS390X_OpRsh8x64(v, config)
+ case OpRsh8x8:
+ return rewriteValueS390X_OpRsh8x8(v, config)
+ case OpS390XADD:
+ return rewriteValueS390X_OpS390XADD(v, config)
+ case OpS390XADDW:
+ return rewriteValueS390X_OpS390XADDW(v, config)
+ case OpS390XADDWconst:
+ return rewriteValueS390X_OpS390XADDWconst(v, config)
+ case OpS390XADDconst:
+ return rewriteValueS390X_OpS390XADDconst(v, config)
+ case OpS390XAND:
+ return rewriteValueS390X_OpS390XAND(v, config)
+ case OpS390XANDW:
+ return rewriteValueS390X_OpS390XANDW(v, config)
+ case OpS390XANDWconst:
+ return rewriteValueS390X_OpS390XANDWconst(v, config)
+ case OpS390XANDconst:
+ return rewriteValueS390X_OpS390XANDconst(v, config)
+ case OpS390XCMP:
+ return rewriteValueS390X_OpS390XCMP(v, config)
+ case OpS390XCMPU:
+ return rewriteValueS390X_OpS390XCMPU(v, config)
+ case OpS390XCMPUconst:
+ return rewriteValueS390X_OpS390XCMPUconst(v, config)
+ case OpS390XCMPW:
+ return rewriteValueS390X_OpS390XCMPW(v, config)
+ case OpS390XCMPWU:
+ return rewriteValueS390X_OpS390XCMPWU(v, config)
+ case OpS390XCMPWUconst:
+ return rewriteValueS390X_OpS390XCMPWUconst(v, config)
+ case OpS390XCMPWconst:
+ return rewriteValueS390X_OpS390XCMPWconst(v, config)
+ case OpS390XCMPconst:
+ return rewriteValueS390X_OpS390XCMPconst(v, config)
+ case OpS390XFMOVDload:
+ return rewriteValueS390X_OpS390XFMOVDload(v, config)
+ case OpS390XFMOVDloadidx:
+ return rewriteValueS390X_OpS390XFMOVDloadidx(v, config)
+ case OpS390XFMOVDstore:
+ return rewriteValueS390X_OpS390XFMOVDstore(v, config)
+ case OpS390XFMOVDstoreidx:
+ return rewriteValueS390X_OpS390XFMOVDstoreidx(v, config)
+ case OpS390XFMOVSload:
+ return rewriteValueS390X_OpS390XFMOVSload(v, config)
+ case OpS390XFMOVSloadidx:
+ return rewriteValueS390X_OpS390XFMOVSloadidx(v, config)
+ case OpS390XFMOVSstore:
+ return rewriteValueS390X_OpS390XFMOVSstore(v, config)
+ case OpS390XFMOVSstoreidx:
+ return rewriteValueS390X_OpS390XFMOVSstoreidx(v, config)
+ case OpS390XMOVBZload:
+ return rewriteValueS390X_OpS390XMOVBZload(v, config)
+ case OpS390XMOVBZloadidx:
+ return rewriteValueS390X_OpS390XMOVBZloadidx(v, config)
+ case OpS390XMOVBZreg:
+ return rewriteValueS390X_OpS390XMOVBZreg(v, config)
+ case OpS390XMOVBload:
+ return rewriteValueS390X_OpS390XMOVBload(v, config)
+ case OpS390XMOVBreg:
+ return rewriteValueS390X_OpS390XMOVBreg(v, config)
+ case OpS390XMOVBstore:
+ return rewriteValueS390X_OpS390XMOVBstore(v, config)
+ case OpS390XMOVBstoreconst:
+ return rewriteValueS390X_OpS390XMOVBstoreconst(v, config)
+ case OpS390XMOVBstoreidx:
+ return rewriteValueS390X_OpS390XMOVBstoreidx(v, config)
+ case OpS390XMOVDEQ:
+ return rewriteValueS390X_OpS390XMOVDEQ(v, config)
+ case OpS390XMOVDGE:
+ return rewriteValueS390X_OpS390XMOVDGE(v, config)
+ case OpS390XMOVDGT:
+ return rewriteValueS390X_OpS390XMOVDGT(v, config)
+ case OpS390XMOVDLE:
+ return rewriteValueS390X_OpS390XMOVDLE(v, config)
+ case OpS390XMOVDLT:
+ return rewriteValueS390X_OpS390XMOVDLT(v, config)
+ case OpS390XMOVDNE:
+ return rewriteValueS390X_OpS390XMOVDNE(v, config)
+ case OpS390XMOVDaddridx:
+ return rewriteValueS390X_OpS390XMOVDaddridx(v, config)
+ case OpS390XMOVDload:
+ return rewriteValueS390X_OpS390XMOVDload(v, config)
+ case OpS390XMOVDloadidx:
+ return rewriteValueS390X_OpS390XMOVDloadidx(v, config)
+ case OpS390XMOVDstore:
+ return rewriteValueS390X_OpS390XMOVDstore(v, config)
+ case OpS390XMOVDstoreconst:
+ return rewriteValueS390X_OpS390XMOVDstoreconst(v, config)
+ case OpS390XMOVDstoreidx:
+ return rewriteValueS390X_OpS390XMOVDstoreidx(v, config)
+ case OpS390XMOVHBRstore:
+ return rewriteValueS390X_OpS390XMOVHBRstore(v, config)
+ case OpS390XMOVHBRstoreidx:
+ return rewriteValueS390X_OpS390XMOVHBRstoreidx(v, config)
+ case OpS390XMOVHZload:
+ return rewriteValueS390X_OpS390XMOVHZload(v, config)
+ case OpS390XMOVHZloadidx:
+ return rewriteValueS390X_OpS390XMOVHZloadidx(v, config)
+ case OpS390XMOVHZreg:
+ return rewriteValueS390X_OpS390XMOVHZreg(v, config)
+ case OpS390XMOVHload:
+ return rewriteValueS390X_OpS390XMOVHload(v, config)
+ case OpS390XMOVHreg:
+ return rewriteValueS390X_OpS390XMOVHreg(v, config)
+ case OpS390XMOVHstore:
+ return rewriteValueS390X_OpS390XMOVHstore(v, config)
+ case OpS390XMOVHstoreconst:
+ return rewriteValueS390X_OpS390XMOVHstoreconst(v, config)
+ case OpS390XMOVHstoreidx:
+ return rewriteValueS390X_OpS390XMOVHstoreidx(v, config)
+ case OpS390XMOVWBRstore:
+ return rewriteValueS390X_OpS390XMOVWBRstore(v, config)
+ case OpS390XMOVWBRstoreidx:
+ return rewriteValueS390X_OpS390XMOVWBRstoreidx(v, config)
+ case OpS390XMOVWZload:
+ return rewriteValueS390X_OpS390XMOVWZload(v, config)
+ case OpS390XMOVWZloadidx:
+ return rewriteValueS390X_OpS390XMOVWZloadidx(v, config)
+ case OpS390XMOVWZreg:
+ return rewriteValueS390X_OpS390XMOVWZreg(v, config)
+ case OpS390XMOVWload:
+ return rewriteValueS390X_OpS390XMOVWload(v, config)
+ case OpS390XMOVWreg:
+ return rewriteValueS390X_OpS390XMOVWreg(v, config)
+ case OpS390XMOVWstore:
+ return rewriteValueS390X_OpS390XMOVWstore(v, config)
+ case OpS390XMOVWstoreconst:
+ return rewriteValueS390X_OpS390XMOVWstoreconst(v, config)
+ case OpS390XMOVWstoreidx:
+ return rewriteValueS390X_OpS390XMOVWstoreidx(v, config)
+ case OpS390XMULLD:
+ return rewriteValueS390X_OpS390XMULLD(v, config)
+ case OpS390XMULLDconst:
+ return rewriteValueS390X_OpS390XMULLDconst(v, config)
+ case OpS390XMULLW:
+ return rewriteValueS390X_OpS390XMULLW(v, config)
+ case OpS390XMULLWconst:
+ return rewriteValueS390X_OpS390XMULLWconst(v, config)
+ case OpS390XNEG:
+ return rewriteValueS390X_OpS390XNEG(v, config)
+ case OpS390XNEGW:
+ return rewriteValueS390X_OpS390XNEGW(v, config)
+ case OpS390XNOT:
+ return rewriteValueS390X_OpS390XNOT(v, config)
+ case OpS390XNOTW:
+ return rewriteValueS390X_OpS390XNOTW(v, config)
+ case OpS390XOR:
+ return rewriteValueS390X_OpS390XOR(v, config)
+ case OpS390XORW:
+ return rewriteValueS390X_OpS390XORW(v, config)
+ case OpS390XORWconst:
+ return rewriteValueS390X_OpS390XORWconst(v, config)
+ case OpS390XORconst:
+ return rewriteValueS390X_OpS390XORconst(v, config)
+ case OpS390XSLD:
+ return rewriteValueS390X_OpS390XSLD(v, config)
+ case OpS390XSLW:
+ return rewriteValueS390X_OpS390XSLW(v, config)
+ case OpS390XSRAD:
+ return rewriteValueS390X_OpS390XSRAD(v, config)
+ case OpS390XSRADconst:
+ return rewriteValueS390X_OpS390XSRADconst(v, config)
+ case OpS390XSRAW:
+ return rewriteValueS390X_OpS390XSRAW(v, config)
+ case OpS390XSRAWconst:
+ return rewriteValueS390X_OpS390XSRAWconst(v, config)
+ case OpS390XSRD:
+ return rewriteValueS390X_OpS390XSRD(v, config)
+ case OpS390XSRW:
+ return rewriteValueS390X_OpS390XSRW(v, config)
+ case OpS390XSTM2:
+ return rewriteValueS390X_OpS390XSTM2(v, config)
+ case OpS390XSTMG2:
+ return rewriteValueS390X_OpS390XSTMG2(v, config)
+ case OpS390XSUB:
+ return rewriteValueS390X_OpS390XSUB(v, config)
+ case OpS390XSUBEWcarrymask:
+ return rewriteValueS390X_OpS390XSUBEWcarrymask(v, config)
+ case OpS390XSUBEcarrymask:
+ return rewriteValueS390X_OpS390XSUBEcarrymask(v, config)
+ case OpS390XSUBW:
+ return rewriteValueS390X_OpS390XSUBW(v, config)
+ case OpS390XSUBWconst:
+ return rewriteValueS390X_OpS390XSUBWconst(v, config)
+ case OpS390XSUBconst:
+ return rewriteValueS390X_OpS390XSUBconst(v, config)
+ case OpS390XXOR:
+ return rewriteValueS390X_OpS390XXOR(v, config)
+ case OpS390XXORW:
+ return rewriteValueS390X_OpS390XXORW(v, config)
+ case OpS390XXORWconst:
+ return rewriteValueS390X_OpS390XXORWconst(v, config)
+ case OpS390XXORconst:
+ return rewriteValueS390X_OpS390XXORconst(v, config)
+ case OpSelect0:
+ return rewriteValueS390X_OpSelect0(v, config)
+ case OpSelect1:
+ return rewriteValueS390X_OpSelect1(v, config)
+ case OpSignExt16to32:
+ return rewriteValueS390X_OpSignExt16to32(v, config)
+ case OpSignExt16to64:
+ return rewriteValueS390X_OpSignExt16to64(v, config)
+ case OpSignExt32to64:
+ return rewriteValueS390X_OpSignExt32to64(v, config)
+ case OpSignExt8to16:
+ return rewriteValueS390X_OpSignExt8to16(v, config)
+ case OpSignExt8to32:
+ return rewriteValueS390X_OpSignExt8to32(v, config)
+ case OpSignExt8to64:
+ return rewriteValueS390X_OpSignExt8to64(v, config)
+ case OpSlicemask:
+ return rewriteValueS390X_OpSlicemask(v, config)
+ case OpSqrt:
+ return rewriteValueS390X_OpSqrt(v, config)
+ case OpStaticCall:
+ return rewriteValueS390X_OpStaticCall(v, config)
+ case OpStore:
+ return rewriteValueS390X_OpStore(v, config)
+ case OpSub16:
+ return rewriteValueS390X_OpSub16(v, config)
+ case OpSub32:
+ return rewriteValueS390X_OpSub32(v, config)
+ case OpSub32F:
+ return rewriteValueS390X_OpSub32F(v, config)
+ case OpSub64:
+ return rewriteValueS390X_OpSub64(v, config)
+ case OpSub64F:
+ return rewriteValueS390X_OpSub64F(v, config)
+ case OpSub8:
+ return rewriteValueS390X_OpSub8(v, config)
+ case OpSubPtr:
+ return rewriteValueS390X_OpSubPtr(v, config)
+ case OpTrunc16to8:
+ return rewriteValueS390X_OpTrunc16to8(v, config)
+ case OpTrunc32to16:
+ return rewriteValueS390X_OpTrunc32to16(v, config)
+ case OpTrunc32to8:
+ return rewriteValueS390X_OpTrunc32to8(v, config)
+ case OpTrunc64to16:
+ return rewriteValueS390X_OpTrunc64to16(v, config)
+ case OpTrunc64to32:
+ return rewriteValueS390X_OpTrunc64to32(v, config)
+ case OpTrunc64to8:
+ return rewriteValueS390X_OpTrunc64to8(v, config)
+ case OpXor16:
+ return rewriteValueS390X_OpXor16(v, config)
+ case OpXor32:
+ return rewriteValueS390X_OpXor32(v, config)
+ case OpXor64:
+ return rewriteValueS390X_OpXor64(v, config)
+ case OpXor8:
+ return rewriteValueS390X_OpXor8(v, config)
+ case OpZero:
+ return rewriteValueS390X_OpZero(v, config)
+ case OpZeroExt16to32:
+ return rewriteValueS390X_OpZeroExt16to32(v, config)
+ case OpZeroExt16to64:
+ return rewriteValueS390X_OpZeroExt16to64(v, config)
+ case OpZeroExt32to64:
+ return rewriteValueS390X_OpZeroExt32to64(v, config)
+ case OpZeroExt8to16:
+ return rewriteValueS390X_OpZeroExt8to16(v, config)
+ case OpZeroExt8to32:
+ return rewriteValueS390X_OpZeroExt8to32(v, config)
+ case OpZeroExt8to64:
+ return rewriteValueS390X_OpZeroExt8to64(v, config)
+ }
+ return false
+}
+func rewriteValueS390X_OpAdd16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Add16 x y)
+ // cond:
+ // result: (ADDW x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XADDW)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueS390X_OpAdd32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Add32 x y)
+ // cond:
+ // result: (ADDW x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XADDW)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueS390X_OpAdd32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Add32F x y)
+ // cond:
+ // result: (FADDS x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XFADDS)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueS390X_OpAdd64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Add64 x y)
+ // cond:
+ // result: (ADD x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XADD)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueS390X_OpAdd64F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Add64F x y)
+ // cond:
+ // result: (FADD x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XFADD)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueS390X_OpAdd8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Add8 x y)
+ // cond:
+ // result: (ADDW x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XADDW)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueS390X_OpAddPtr(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (AddPtr x y)
+ // cond:
+ // result: (ADD x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XADD)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueS390X_OpAddr(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Addr {sym} base)
+ // cond:
+ // result: (MOVDaddr {sym} base)
+ for {
+ sym := v.Aux
+ base := v.Args[0]
+ v.reset(OpS390XMOVDaddr)
+ v.Aux = sym
+ v.AddArg(base)
+ return true
+ }
+}
+func rewriteValueS390X_OpAnd16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (And16 x y)
+ // cond:
+ // result: (ANDW x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XANDW)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueS390X_OpAnd32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (And32 x y)
+ // cond:
+ // result: (ANDW x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XANDW)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueS390X_OpAnd64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (And64 x y)
+ // cond:
+ // result: (AND x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XAND)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueS390X_OpAnd8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (And8 x y)
+ // cond:
+ // result: (ANDW x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XANDW)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueS390X_OpAndB(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (AndB x y)
+ // cond:
+ // result: (ANDW x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XANDW)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueS390X_OpAtomicAdd32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (AtomicAdd32 ptr val mem)
+ // cond:
+ // result: (AddTupleFirst32 (LAA ptr val mem) val)
+ for {
+ 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))
+ 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 {
+ b := v.Block
+ _ = b
+ // match: (AtomicAdd64 ptr val mem)
+ // cond:
+ // result: (AddTupleFirst64 (LAAG ptr val mem) val)
+ for {
+ 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))
+ 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
+ // match: (AtomicCompareAndSwap32 ptr old new_ mem)
+ // cond:
+ // result: (LoweredAtomicCas32 ptr old new_ mem)
+ for {
+ ptr := v.Args[0]
+ old := v.Args[1]
+ new_ := v.Args[2]
+ mem := v.Args[3]
+ v.reset(OpS390XLoweredAtomicCas32)
+ v.AddArg(ptr)
+ v.AddArg(old)
+ v.AddArg(new_)
+ v.AddArg(mem)
+ return true
+ }
+}
+func rewriteValueS390X_OpAtomicCompareAndSwap64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (AtomicCompareAndSwap64 ptr old new_ mem)
+ // cond:
+ // result: (LoweredAtomicCas64 ptr old new_ mem)
+ for {
+ ptr := v.Args[0]
+ old := v.Args[1]
+ new_ := v.Args[2]
+ mem := v.Args[3]
+ v.reset(OpS390XLoweredAtomicCas64)
+ v.AddArg(ptr)
+ v.AddArg(old)
+ v.AddArg(new_)
+ v.AddArg(mem)
+ return true
+ }
+}
+func rewriteValueS390X_OpAtomicExchange32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (AtomicExchange32 ptr val mem)
+ // cond:
+ // result: (LoweredAtomicExchange32 ptr val mem)
+ for {
+ ptr := v.Args[0]
+ val := v.Args[1]
+ mem := v.Args[2]
+ v.reset(OpS390XLoweredAtomicExchange32)
+ v.AddArg(ptr)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+}
+func rewriteValueS390X_OpAtomicExchange64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (AtomicExchange64 ptr val mem)
+ // cond:
+ // result: (LoweredAtomicExchange64 ptr val mem)
+ for {
+ ptr := v.Args[0]
+ val := v.Args[1]
+ mem := v.Args[2]
+ v.reset(OpS390XLoweredAtomicExchange64)
+ v.AddArg(ptr)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+}
+func rewriteValueS390X_OpAtomicLoad32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (AtomicLoad32 ptr mem)
+ // cond:
+ // result: (MOVWZatomicload ptr mem)
+ for {
+ ptr := v.Args[0]
+ mem := v.Args[1]
+ v.reset(OpS390XMOVWZatomicload)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+}
+func rewriteValueS390X_OpAtomicLoad64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (AtomicLoad64 ptr mem)
+ // cond:
+ // result: (MOVDatomicload ptr mem)
+ for {
+ ptr := v.Args[0]
+ mem := v.Args[1]
+ v.reset(OpS390XMOVDatomicload)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+}
+func rewriteValueS390X_OpAtomicLoadPtr(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (AtomicLoadPtr ptr mem)
+ // cond:
+ // result: (MOVDatomicload ptr mem)
+ for {
+ ptr := v.Args[0]
+ mem := v.Args[1]
+ v.reset(OpS390XMOVDatomicload)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+}
+func rewriteValueS390X_OpAtomicStore32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (AtomicStore32 ptr val mem)
+ // cond:
+ // result: (MOVWatomicstore ptr val mem)
+ for {
+ ptr := v.Args[0]
+ val := v.Args[1]
+ mem := v.Args[2]
+ v.reset(OpS390XMOVWatomicstore)
+ v.AddArg(ptr)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+}
+func rewriteValueS390X_OpAtomicStore64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (AtomicStore64 ptr val mem)
+ // cond:
+ // result: (MOVDatomicstore ptr val mem)
+ for {
+ ptr := v.Args[0]
+ val := v.Args[1]
+ mem := v.Args[2]
+ v.reset(OpS390XMOVDatomicstore)
+ v.AddArg(ptr)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+}
+func rewriteValueS390X_OpAtomicStorePtrNoWB(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (AtomicStorePtrNoWB ptr val mem)
+ // cond:
+ // result: (MOVDatomicstore ptr val mem)
+ for {
+ ptr := v.Args[0]
+ val := v.Args[1]
+ mem := v.Args[2]
+ v.reset(OpS390XMOVDatomicstore)
+ v.AddArg(ptr)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+}
+func rewriteValueS390X_OpAvg64u(v *Value, config *Config) 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]))
+ for {
+ t := v.Type
+ 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
+ v1.AddArg(x)
+ 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)
+ return true
+ }
+}
+func rewriteValueS390X_OpBswap32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Bswap32 x)
+ // cond:
+ // result: (MOVWBR x)
+ for {
+ x := v.Args[0]
+ v.reset(OpS390XMOVWBR)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueS390X_OpBswap64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Bswap64 x)
+ // cond:
+ // result: (MOVDBR x)
+ for {
+ x := v.Args[0]
+ v.reset(OpS390XMOVDBR)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueS390X_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(OpS390XCALLclosure)
+ v.AuxInt = argwid
+ v.AddArg(entry)
+ v.AddArg(closure)
+ v.AddArg(mem)
+ return true
+ }
+}
+func rewriteValueS390X_OpCom16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Com16 x)
+ // cond:
+ // result: (NOTW x)
+ for {
+ x := v.Args[0]
+ v.reset(OpS390XNOTW)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueS390X_OpCom32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Com32 x)
+ // cond:
+ // result: (NOTW x)
+ for {
+ x := v.Args[0]
+ v.reset(OpS390XNOTW)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueS390X_OpCom64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Com64 x)
+ // cond:
+ // result: (NOT x)
+ for {
+ x := v.Args[0]
+ v.reset(OpS390XNOT)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueS390X_OpCom8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Com8 x)
+ // cond:
+ // result: (NOTW x)
+ for {
+ x := v.Args[0]
+ v.reset(OpS390XNOTW)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueS390X_OpConst16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Const16 [val])
+ // cond:
+ // result: (MOVDconst [val])
+ for {
+ val := v.AuxInt
+ v.reset(OpS390XMOVDconst)
+ v.AuxInt = val
+ return true
+ }
+}
+func rewriteValueS390X_OpConst32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Const32 [val])
+ // cond:
+ // result: (MOVDconst [val])
+ for {
+ val := v.AuxInt
+ v.reset(OpS390XMOVDconst)
+ v.AuxInt = val
+ return true
+ }
+}
+func rewriteValueS390X_OpConst32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Const32F [val])
+ // cond:
+ // result: (FMOVSconst [val])
+ for {
+ val := v.AuxInt
+ v.reset(OpS390XFMOVSconst)
+ v.AuxInt = val
+ return true
+ }
+}
+func rewriteValueS390X_OpConst64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Const64 [val])
+ // cond:
+ // result: (MOVDconst [val])
+ for {
+ val := v.AuxInt
+ v.reset(OpS390XMOVDconst)
+ v.AuxInt = val
+ return true
+ }
+}
+func rewriteValueS390X_OpConst64F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Const64F [val])
+ // cond:
+ // result: (FMOVDconst [val])
+ for {
+ val := v.AuxInt
+ v.reset(OpS390XFMOVDconst)
+ v.AuxInt = val
+ return true
+ }
+}
+func rewriteValueS390X_OpConst8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Const8 [val])
+ // cond:
+ // result: (MOVDconst [val])
+ for {
+ val := v.AuxInt
+ v.reset(OpS390XMOVDconst)
+ v.AuxInt = val
+ return true
+ }
+}
+func rewriteValueS390X_OpConstBool(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ConstBool [b])
+ // cond:
+ // result: (MOVDconst [b])
+ for {
+ b := v.AuxInt
+ v.reset(OpS390XMOVDconst)
+ v.AuxInt = b
+ return true
+ }
+}
+func rewriteValueS390X_OpConstNil(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ConstNil)
+ // cond:
+ // result: (MOVDconst [0])
+ for {
+ v.reset(OpS390XMOVDconst)
+ v.AuxInt = 0
+ return true
+ }
+}
+func rewriteValueS390X_OpConvert(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Convert <t> x mem)
+ // cond:
+ // result: (MOVDconvert <t> x mem)
+ for {
+ t := v.Type
+ x := v.Args[0]
+ mem := v.Args[1]
+ v.reset(OpS390XMOVDconvert)
+ v.Type = t
+ v.AddArg(x)
+ v.AddArg(mem)
+ return true
+ }
+}
+func rewriteValueS390X_OpCtz32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Ctz32 <t> x)
+ // cond:
+ // result: (SUB (MOVDconst [64]) (FLOGR (MOVWZreg (ANDW <t> (SUBWconst <t> [1] x) (NOTW <t> x)))))
+ for {
+ t := v.Type
+ x := v.Args[0]
+ v.reset(OpS390XSUB)
+ v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ 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)
+ v4.AuxInt = 1
+ v4.AddArg(x)
+ v3.AddArg(v4)
+ v5 := b.NewValue0(v.Line, OpS390XNOTW, t)
+ v5.AddArg(x)
+ v3.AddArg(v5)
+ v2.AddArg(v3)
+ v1.AddArg(v2)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueS390X_OpCtz64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Ctz64 <t> x)
+ // cond:
+ // result: (SUB (MOVDconst [64]) (FLOGR (AND <t> (SUBconst <t> [1] x) (NOT <t> x))))
+ for {
+ t := v.Type
+ x := v.Args[0]
+ v.reset(OpS390XSUB)
+ v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ 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)
+ v3.AuxInt = 1
+ v3.AddArg(x)
+ v2.AddArg(v3)
+ v4 := b.NewValue0(v.Line, OpS390XNOT, t)
+ v4.AddArg(x)
+ v2.AddArg(v4)
+ v1.AddArg(v2)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueS390X_OpCvt32Fto32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Cvt32Fto32 x)
+ // cond:
+ // result: (CFEBRA x)
+ for {
+ x := v.Args[0]
+ v.reset(OpS390XCFEBRA)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueS390X_OpCvt32Fto64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Cvt32Fto64 x)
+ // cond:
+ // result: (CGEBRA x)
+ for {
+ x := v.Args[0]
+ v.reset(OpS390XCGEBRA)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueS390X_OpCvt32Fto64F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Cvt32Fto64F x)
+ // cond:
+ // result: (LDEBR x)
+ for {
+ x := v.Args[0]
+ v.reset(OpS390XLDEBR)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueS390X_OpCvt32to32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Cvt32to32F x)
+ // cond:
+ // result: (CEFBRA x)
+ for {
+ x := v.Args[0]
+ v.reset(OpS390XCEFBRA)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueS390X_OpCvt32to64F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Cvt32to64F x)
+ // cond:
+ // result: (CDFBRA x)
+ for {
+ x := v.Args[0]
+ v.reset(OpS390XCDFBRA)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueS390X_OpCvt64Fto32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Cvt64Fto32 x)
+ // cond:
+ // result: (CFDBRA x)
+ for {
+ x := v.Args[0]
+ v.reset(OpS390XCFDBRA)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueS390X_OpCvt64Fto32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Cvt64Fto32F x)
+ // cond:
+ // result: (LEDBR x)
+ for {
+ x := v.Args[0]
+ v.reset(OpS390XLEDBR)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueS390X_OpCvt64Fto64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Cvt64Fto64 x)
+ // cond:
+ // result: (CGDBRA x)
+ for {
+ x := v.Args[0]
+ v.reset(OpS390XCGDBRA)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueS390X_OpCvt64to32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Cvt64to32F x)
+ // cond:
+ // result: (CEGBRA x)
+ for {
+ x := v.Args[0]
+ v.reset(OpS390XCEGBRA)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueS390X_OpCvt64to64F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Cvt64to64F x)
+ // cond:
+ // result: (CDGBRA x)
+ for {
+ x := v.Args[0]
+ v.reset(OpS390XCDGBRA)
+ v.AddArg(x)
+ 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 {
+ b := v.Block
+ _ = b
+ // match: (Div16 x y)
+ // cond:
+ // result: (DIVW (MOVHreg x) (MOVHreg y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XDIVW)
+ v0 := b.NewValue0(v.Line, OpS390XMOVHreg, config.fe.TypeInt64())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpS390XMOVHreg, config.fe.TypeInt64())
+ v1.AddArg(y)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueS390X_OpDiv16u(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Div16u x y)
+ // cond:
+ // result: (DIVWU (MOVHZreg x) (MOVHZreg y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XDIVWU)
+ v0 := b.NewValue0(v.Line, OpS390XMOVHZreg, config.fe.TypeUInt64())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpS390XMOVHZreg, config.fe.TypeUInt64())
+ v1.AddArg(y)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueS390X_OpDiv32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Div32 x y)
+ // cond:
+ // result: (DIVW (MOVWreg x) y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XDIVW)
+ v0 := b.NewValue0(v.Line, OpS390XMOVWreg, config.fe.TypeInt64())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueS390X_OpDiv32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Div32F x y)
+ // cond:
+ // result: (FDIVS x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XFDIVS)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueS390X_OpDiv32u(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Div32u x y)
+ // cond:
+ // result: (DIVWU (MOVWZreg x) y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XDIVWU)
+ v0 := b.NewValue0(v.Line, OpS390XMOVWZreg, config.fe.TypeUInt64())
+ 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)
+ // cond:
+ // result: (DIVD x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XDIVD)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueS390X_OpDiv64F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Div64F x y)
+ // cond:
+ // result: (FDIV x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XFDIV)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueS390X_OpDiv64u(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Div64u x y)
+ // cond:
+ // result: (DIVDU x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XDIVDU)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueS390X_OpDiv8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Div8 x y)
+ // cond:
+ // result: (DIVW (MOVBreg x) (MOVBreg y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XDIVW)
+ v0 := b.NewValue0(v.Line, OpS390XMOVBreg, config.fe.TypeInt64())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpS390XMOVBreg, config.fe.TypeInt64())
+ v1.AddArg(y)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueS390X_OpDiv8u(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Div8u x y)
+ // cond:
+ // result: (DIVWU (MOVBZreg x) (MOVBZreg y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XDIVWU)
+ v0 := b.NewValue0(v.Line, OpS390XMOVBZreg, config.fe.TypeUInt64())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpS390XMOVBZreg, config.fe.TypeUInt64())
+ v1.AddArg(y)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueS390X_OpEq16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Eq16 x y)
+ // cond:
+ // result: (MOVDEQ (MOVDconst [0]) (MOVDconst [1]) (CMP (MOVHreg x) (MOVHreg y)))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XMOVDEQ)
+ v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v0.AuxInt = 0
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v1.AuxInt = 1
+ v.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpS390XCMP, TypeFlags)
+ v3 := b.NewValue0(v.Line, OpS390XMOVHreg, config.fe.TypeInt64())
+ v3.AddArg(x)
+ v2.AddArg(v3)
+ v4 := b.NewValue0(v.Line, OpS390XMOVHreg, config.fe.TypeInt64())
+ v4.AddArg(y)
+ v2.AddArg(v4)
+ v.AddArg(v2)
+ return true
+ }
+}
+func rewriteValueS390X_OpEq32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Eq32 x y)
+ // cond:
+ // result: (MOVDEQ (MOVDconst [0]) (MOVDconst [1]) (CMPW x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XMOVDEQ)
+ v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v0.AuxInt = 0
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v1.AuxInt = 1
+ v.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpS390XCMPW, TypeFlags)
+ v2.AddArg(x)
+ v2.AddArg(y)
+ v.AddArg(v2)
+ return true
+ }
+}
+func rewriteValueS390X_OpEq32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Eq32F x y)
+ // cond:
+ // result: (MOVDEQ (MOVDconst [0]) (MOVDconst [1]) (FCMPS x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XMOVDEQ)
+ v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v0.AuxInt = 0
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v1.AuxInt = 1
+ v.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpS390XFCMPS, TypeFlags)
+ v2.AddArg(x)
+ v2.AddArg(y)
+ v.AddArg(v2)
+ return true
+ }
+}
+func rewriteValueS390X_OpEq64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Eq64 x y)
+ // cond:
+ // result: (MOVDEQ (MOVDconst [0]) (MOVDconst [1]) (CMP x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XMOVDEQ)
+ v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v0.AuxInt = 0
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v1.AuxInt = 1
+ v.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpS390XCMP, TypeFlags)
+ v2.AddArg(x)
+ v2.AddArg(y)
+ v.AddArg(v2)
+ return true
+ }
+}
+func rewriteValueS390X_OpEq64F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Eq64F x y)
+ // cond:
+ // result: (MOVDEQ (MOVDconst [0]) (MOVDconst [1]) (FCMP x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XMOVDEQ)
+ v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v0.AuxInt = 0
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v1.AuxInt = 1
+ v.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpS390XFCMP, TypeFlags)
+ v2.AddArg(x)
+ v2.AddArg(y)
+ v.AddArg(v2)
+ return true
+ }
+}
+func rewriteValueS390X_OpEq8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Eq8 x y)
+ // cond:
+ // result: (MOVDEQ (MOVDconst [0]) (MOVDconst [1]) (CMP (MOVBreg x) (MOVBreg y)))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XMOVDEQ)
+ v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v0.AuxInt = 0
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v1.AuxInt = 1
+ v.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpS390XCMP, TypeFlags)
+ v3 := b.NewValue0(v.Line, OpS390XMOVBreg, config.fe.TypeInt64())
+ v3.AddArg(x)
+ v2.AddArg(v3)
+ v4 := b.NewValue0(v.Line, OpS390XMOVBreg, config.fe.TypeInt64())
+ v4.AddArg(y)
+ v2.AddArg(v4)
+ v.AddArg(v2)
+ return true
+ }
+}
+func rewriteValueS390X_OpEqB(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (EqB x y)
+ // cond:
+ // result: (MOVDEQ (MOVDconst [0]) (MOVDconst [1]) (CMP (MOVBreg x) (MOVBreg y)))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XMOVDEQ)
+ v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v0.AuxInt = 0
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v1.AuxInt = 1
+ v.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpS390XCMP, TypeFlags)
+ v3 := b.NewValue0(v.Line, OpS390XMOVBreg, config.fe.TypeInt64())
+ v3.AddArg(x)
+ v2.AddArg(v3)
+ v4 := b.NewValue0(v.Line, OpS390XMOVBreg, config.fe.TypeInt64())
+ v4.AddArg(y)
+ v2.AddArg(v4)
+ v.AddArg(v2)
+ return true
+ }
+}
+func rewriteValueS390X_OpEqPtr(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (EqPtr x y)
+ // cond:
+ // result: (MOVDEQ (MOVDconst [0]) (MOVDconst [1]) (CMP x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XMOVDEQ)
+ v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v0.AuxInt = 0
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v1.AuxInt = 1
+ v.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpS390XCMP, TypeFlags)
+ v2.AddArg(x)
+ v2.AddArg(y)
+ v.AddArg(v2)
+ return true
+ }
+}
+func rewriteValueS390X_OpGeq16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Geq16 x y)
+ // cond:
+ // result: (MOVDGE (MOVDconst [0]) (MOVDconst [1]) (CMP (MOVHreg x) (MOVHreg y)))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XMOVDGE)
+ v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v0.AuxInt = 0
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v1.AuxInt = 1
+ v.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpS390XCMP, TypeFlags)
+ v3 := b.NewValue0(v.Line, OpS390XMOVHreg, config.fe.TypeInt64())
+ v3.AddArg(x)
+ v2.AddArg(v3)
+ v4 := b.NewValue0(v.Line, OpS390XMOVHreg, config.fe.TypeInt64())
+ v4.AddArg(y)
+ v2.AddArg(v4)
+ v.AddArg(v2)
+ return true
+ }
+}
+func rewriteValueS390X_OpGeq16U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Geq16U x y)
+ // cond:
+ // result: (MOVDGE (MOVDconst [0]) (MOVDconst [1]) (CMPU (MOVHZreg x) (MOVHZreg y)))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XMOVDGE)
+ v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v0.AuxInt = 0
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v1.AuxInt = 1
+ v.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpS390XCMPU, TypeFlags)
+ v3 := b.NewValue0(v.Line, OpS390XMOVHZreg, config.fe.TypeUInt64())
+ v3.AddArg(x)
+ v2.AddArg(v3)
+ v4 := b.NewValue0(v.Line, OpS390XMOVHZreg, config.fe.TypeUInt64())
+ v4.AddArg(y)
+ v2.AddArg(v4)
+ v.AddArg(v2)
+ return true
+ }
+}
+func rewriteValueS390X_OpGeq32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Geq32 x y)
+ // cond:
+ // result: (MOVDGE (MOVDconst [0]) (MOVDconst [1]) (CMPW x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XMOVDGE)
+ v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v0.AuxInt = 0
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v1.AuxInt = 1
+ v.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpS390XCMPW, TypeFlags)
+ v2.AddArg(x)
+ v2.AddArg(y)
+ v.AddArg(v2)
+ return true
+ }
+}
+func rewriteValueS390X_OpGeq32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Geq32F x y)
+ // cond:
+ // result: (MOVDGEnoinv (MOVDconst [0]) (MOVDconst [1]) (FCMPS x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XMOVDGEnoinv)
+ v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v0.AuxInt = 0
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v1.AuxInt = 1
+ v.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpS390XFCMPS, TypeFlags)
+ v2.AddArg(x)
+ v2.AddArg(y)
+ v.AddArg(v2)
+ return true
+ }
+}
+func rewriteValueS390X_OpGeq32U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Geq32U x y)
+ // cond:
+ // result: (MOVDGE (MOVDconst [0]) (MOVDconst [1]) (CMPWU x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XMOVDGE)
+ v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v0.AuxInt = 0
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v1.AuxInt = 1
+ v.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpS390XCMPWU, TypeFlags)
+ v2.AddArg(x)
+ v2.AddArg(y)
+ v.AddArg(v2)
+ return true
+ }
+}
+func rewriteValueS390X_OpGeq64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Geq64 x y)
+ // cond:
+ // result: (MOVDGE (MOVDconst [0]) (MOVDconst [1]) (CMP x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XMOVDGE)
+ v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v0.AuxInt = 0
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v1.AuxInt = 1
+ v.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpS390XCMP, TypeFlags)
+ v2.AddArg(x)
+ v2.AddArg(y)
+ v.AddArg(v2)
+ return true
+ }
+}
+func rewriteValueS390X_OpGeq64F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Geq64F x y)
+ // cond:
+ // result: (MOVDGEnoinv (MOVDconst [0]) (MOVDconst [1]) (FCMP x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XMOVDGEnoinv)
+ v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v0.AuxInt = 0
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v1.AuxInt = 1
+ v.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpS390XFCMP, TypeFlags)
+ v2.AddArg(x)
+ v2.AddArg(y)
+ v.AddArg(v2)
+ return true
+ }
+}
+func rewriteValueS390X_OpGeq64U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Geq64U x y)
+ // cond:
+ // result: (MOVDGE (MOVDconst [0]) (MOVDconst [1]) (CMPU x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XMOVDGE)
+ v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v0.AuxInt = 0
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v1.AuxInt = 1
+ v.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpS390XCMPU, TypeFlags)
+ v2.AddArg(x)
+ v2.AddArg(y)
+ v.AddArg(v2)
+ return true
+ }
+}
+func rewriteValueS390X_OpGeq8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Geq8 x y)
+ // cond:
+ // result: (MOVDGE (MOVDconst [0]) (MOVDconst [1]) (CMP (MOVBreg x) (MOVBreg y)))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XMOVDGE)
+ v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v0.AuxInt = 0
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v1.AuxInt = 1
+ v.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpS390XCMP, TypeFlags)
+ v3 := b.NewValue0(v.Line, OpS390XMOVBreg, config.fe.TypeInt64())
+ v3.AddArg(x)
+ v2.AddArg(v3)
+ v4 := b.NewValue0(v.Line, OpS390XMOVBreg, config.fe.TypeInt64())
+ v4.AddArg(y)
+ v2.AddArg(v4)
+ v.AddArg(v2)
+ return true
+ }
+}
+func rewriteValueS390X_OpGeq8U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Geq8U x y)
+ // cond:
+ // result: (MOVDGE (MOVDconst [0]) (MOVDconst [1]) (CMPU (MOVBZreg x) (MOVBZreg y)))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XMOVDGE)
+ v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v0.AuxInt = 0
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v1.AuxInt = 1
+ v.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpS390XCMPU, TypeFlags)
+ v3 := b.NewValue0(v.Line, OpS390XMOVBZreg, config.fe.TypeUInt64())
+ v3.AddArg(x)
+ v2.AddArg(v3)
+ v4 := b.NewValue0(v.Line, OpS390XMOVBZreg, config.fe.TypeUInt64())
+ v4.AddArg(y)
+ v2.AddArg(v4)
+ v.AddArg(v2)
+ return true
+ }
+}
+func rewriteValueS390X_OpGetClosurePtr(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (GetClosurePtr)
+ // cond:
+ // result: (LoweredGetClosurePtr)
+ for {
+ v.reset(OpS390XLoweredGetClosurePtr)
+ return true
+ }
+}
+func rewriteValueS390X_OpGetG(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (GetG mem)
+ // cond:
+ // result: (LoweredGetG mem)
+ for {
+ mem := v.Args[0]
+ v.reset(OpS390XLoweredGetG)
+ v.AddArg(mem)
+ return true
+ }
+}
+func rewriteValueS390X_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(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)
+ // cond:
+ // result: (MOVDGT (MOVDconst [0]) (MOVDconst [1]) (CMP (MOVHreg x) (MOVHreg y)))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XMOVDGT)
+ v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v0.AuxInt = 0
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v1.AuxInt = 1
+ v.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpS390XCMP, TypeFlags)
+ v3 := b.NewValue0(v.Line, OpS390XMOVHreg, config.fe.TypeInt64())
+ v3.AddArg(x)
+ v2.AddArg(v3)
+ v4 := b.NewValue0(v.Line, OpS390XMOVHreg, config.fe.TypeInt64())
+ v4.AddArg(y)
+ v2.AddArg(v4)
+ v.AddArg(v2)
+ return true
+ }
+}
+func rewriteValueS390X_OpGreater16U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Greater16U x y)
+ // cond:
+ // result: (MOVDGT (MOVDconst [0]) (MOVDconst [1]) (CMPU (MOVHZreg x) (MOVHZreg y)))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XMOVDGT)
+ v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v0.AuxInt = 0
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v1.AuxInt = 1
+ v.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpS390XCMPU, TypeFlags)
+ v3 := b.NewValue0(v.Line, OpS390XMOVHZreg, config.fe.TypeUInt64())
+ v3.AddArg(x)
+ v2.AddArg(v3)
+ v4 := b.NewValue0(v.Line, OpS390XMOVHZreg, config.fe.TypeUInt64())
+ v4.AddArg(y)
+ v2.AddArg(v4)
+ v.AddArg(v2)
+ return true
+ }
+}
+func rewriteValueS390X_OpGreater32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Greater32 x y)
+ // cond:
+ // result: (MOVDGT (MOVDconst [0]) (MOVDconst [1]) (CMPW x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XMOVDGT)
+ v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v0.AuxInt = 0
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v1.AuxInt = 1
+ v.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpS390XCMPW, TypeFlags)
+ v2.AddArg(x)
+ v2.AddArg(y)
+ v.AddArg(v2)
+ return true
+ }
+}
+func rewriteValueS390X_OpGreater32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Greater32F x y)
+ // cond:
+ // result: (MOVDGTnoinv (MOVDconst [0]) (MOVDconst [1]) (FCMPS x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XMOVDGTnoinv)
+ v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v0.AuxInt = 0
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v1.AuxInt = 1
+ v.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpS390XFCMPS, TypeFlags)
+ v2.AddArg(x)
+ v2.AddArg(y)
+ v.AddArg(v2)
+ return true
+ }
+}
+func rewriteValueS390X_OpGreater32U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Greater32U x y)
+ // cond:
+ // result: (MOVDGT (MOVDconst [0]) (MOVDconst [1]) (CMPWU x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XMOVDGT)
+ v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v0.AuxInt = 0
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v1.AuxInt = 1
+ v.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpS390XCMPWU, TypeFlags)
+ v2.AddArg(x)
+ v2.AddArg(y)
+ v.AddArg(v2)
+ return true
+ }
+}
+func rewriteValueS390X_OpGreater64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Greater64 x y)
+ // cond:
+ // result: (MOVDGT (MOVDconst [0]) (MOVDconst [1]) (CMP x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XMOVDGT)
+ v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v0.AuxInt = 0
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v1.AuxInt = 1
+ v.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpS390XCMP, TypeFlags)
+ v2.AddArg(x)
+ v2.AddArg(y)
+ v.AddArg(v2)
+ return true
+ }
+}
+func rewriteValueS390X_OpGreater64F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Greater64F x y)
+ // cond:
+ // result: (MOVDGTnoinv (MOVDconst [0]) (MOVDconst [1]) (FCMP x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XMOVDGTnoinv)
+ v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v0.AuxInt = 0
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v1.AuxInt = 1
+ v.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpS390XFCMP, TypeFlags)
+ v2.AddArg(x)
+ v2.AddArg(y)
+ v.AddArg(v2)
+ return true
+ }
+}
+func rewriteValueS390X_OpGreater64U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Greater64U x y)
+ // cond:
+ // result: (MOVDGT (MOVDconst [0]) (MOVDconst [1]) (CMPU x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XMOVDGT)
+ v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v0.AuxInt = 0
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v1.AuxInt = 1
+ v.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpS390XCMPU, TypeFlags)
+ v2.AddArg(x)
+ v2.AddArg(y)
+ v.AddArg(v2)
+ return true
+ }
+}
+func rewriteValueS390X_OpGreater8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Greater8 x y)
+ // cond:
+ // result: (MOVDGT (MOVDconst [0]) (MOVDconst [1]) (CMP (MOVBreg x) (MOVBreg y)))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XMOVDGT)
+ v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v0.AuxInt = 0
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v1.AuxInt = 1
+ v.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpS390XCMP, TypeFlags)
+ v3 := b.NewValue0(v.Line, OpS390XMOVBreg, config.fe.TypeInt64())
+ v3.AddArg(x)
+ v2.AddArg(v3)
+ v4 := b.NewValue0(v.Line, OpS390XMOVBreg, config.fe.TypeInt64())
+ v4.AddArg(y)
+ v2.AddArg(v4)
+ v.AddArg(v2)
+ return true
+ }
+}
+func rewriteValueS390X_OpGreater8U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Greater8U x y)
+ // cond:
+ // result: (MOVDGT (MOVDconst [0]) (MOVDconst [1]) (CMPU (MOVBZreg x) (MOVBZreg y)))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XMOVDGT)
+ v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v0.AuxInt = 0
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v1.AuxInt = 1
+ v.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpS390XCMPU, TypeFlags)
+ v3 := b.NewValue0(v.Line, OpS390XMOVBZreg, config.fe.TypeUInt64())
+ v3.AddArg(x)
+ v2.AddArg(v3)
+ v4 := b.NewValue0(v.Line, OpS390XMOVBZreg, config.fe.TypeUInt64())
+ 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 {
+ b := v.Block
+ _ = b
+ // match: (Hmul32 x y)
+ // cond:
+ // result: (SRDconst [32] (MULLD (MOVWreg x) (MOVWreg y)))
+ for {
+ 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())
+ v1.AddArg(x)
+ v0.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpS390XMOVWreg, config.fe.TypeInt64())
+ v2.AddArg(y)
+ v0.AddArg(v2)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueS390X_OpHmul32u(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Hmul32u x y)
+ // cond:
+ // result: (SRDconst [32] (MULLD (MOVWZreg x) (MOVWZreg y)))
+ for {
+ 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())
+ v1.AddArg(x)
+ v0.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpS390XMOVWZreg, config.fe.TypeUInt64())
+ 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)
+ // cond:
+ // result: (MULHD x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XMULHD)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueS390X_OpHmul64u(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Hmul64u x y)
+ // cond:
+ // result: (MULHDU x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XMULHDU)
+ v.AddArg(x)
+ v.AddArg(y)
+ 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
+ // match: (ITab (Load ptr mem))
+ // cond:
+ // result: (MOVDload ptr mem)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpLoad {
+ break
+ }
+ ptr := v_0.Args[0]
+ mem := v_0.Args[1]
+ v.reset(OpS390XMOVDload)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValueS390X_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(OpS390XCALLinter)
+ v.AuxInt = argwid
+ v.AddArg(entry)
+ v.AddArg(mem)
+ return true
+ }
+}
+func rewriteValueS390X_OpIsInBounds(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (IsInBounds idx len)
+ // cond:
+ // result: (MOVDLT (MOVDconst [0]) (MOVDconst [1]) (CMPU idx len))
+ for {
+ idx := v.Args[0]
+ len := v.Args[1]
+ v.reset(OpS390XMOVDLT)
+ v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v0.AuxInt = 0
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v1.AuxInt = 1
+ v.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpS390XCMPU, TypeFlags)
+ v2.AddArg(idx)
+ v2.AddArg(len)
+ v.AddArg(v2)
+ return true
+ }
+}
+func rewriteValueS390X_OpIsNonNil(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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.AuxInt = 0
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v1.AuxInt = 1
+ v.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpS390XCMPconst, TypeFlags)
+ v2.AuxInt = 0
+ v2.AddArg(p)
+ v.AddArg(v2)
+ return true
+ }
+}
+func rewriteValueS390X_OpIsSliceInBounds(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (IsSliceInBounds idx len)
+ // cond:
+ // result: (MOVDLE (MOVDconst [0]) (MOVDconst [1]) (CMPU idx len))
+ for {
+ idx := v.Args[0]
+ len := v.Args[1]
+ v.reset(OpS390XMOVDLE)
+ v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v0.AuxInt = 0
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v1.AuxInt = 1
+ v.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpS390XCMPU, TypeFlags)
+ v2.AddArg(idx)
+ v2.AddArg(len)
+ v.AddArg(v2)
+ return true
+ }
+}
+func rewriteValueS390X_OpLeq16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Leq16 x y)
+ // cond:
+ // result: (MOVDLE (MOVDconst [0]) (MOVDconst [1]) (CMP (MOVHreg x) (MOVHreg y)))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XMOVDLE)
+ v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v0.AuxInt = 0
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v1.AuxInt = 1
+ v.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpS390XCMP, TypeFlags)
+ v3 := b.NewValue0(v.Line, OpS390XMOVHreg, config.fe.TypeInt64())
+ v3.AddArg(x)
+ v2.AddArg(v3)
+ v4 := b.NewValue0(v.Line, OpS390XMOVHreg, config.fe.TypeInt64())
+ v4.AddArg(y)
+ v2.AddArg(v4)
+ v.AddArg(v2)
+ return true
+ }
+}
+func rewriteValueS390X_OpLeq16U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Leq16U x y)
+ // cond:
+ // result: (MOVDLE (MOVDconst [0]) (MOVDconst [1]) (CMPU (MOVHZreg x) (MOVHZreg y)))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XMOVDLE)
+ v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v0.AuxInt = 0
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v1.AuxInt = 1
+ v.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpS390XCMPU, TypeFlags)
+ v3 := b.NewValue0(v.Line, OpS390XMOVHZreg, config.fe.TypeUInt64())
+ v3.AddArg(x)
+ v2.AddArg(v3)
+ v4 := b.NewValue0(v.Line, OpS390XMOVHZreg, config.fe.TypeUInt64())
+ v4.AddArg(y)
+ v2.AddArg(v4)
+ v.AddArg(v2)
+ return true
+ }
+}
+func rewriteValueS390X_OpLeq32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Leq32 x y)
+ // cond:
+ // result: (MOVDLE (MOVDconst [0]) (MOVDconst [1]) (CMPW x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XMOVDLE)
+ v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v0.AuxInt = 0
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v1.AuxInt = 1
+ v.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpS390XCMPW, TypeFlags)
+ v2.AddArg(x)
+ v2.AddArg(y)
+ v.AddArg(v2)
+ return true
+ }
+}
+func rewriteValueS390X_OpLeq32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Leq32F x y)
+ // cond:
+ // result: (MOVDGEnoinv (MOVDconst [0]) (MOVDconst [1]) (FCMPS y x))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XMOVDGEnoinv)
+ v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v0.AuxInt = 0
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v1.AuxInt = 1
+ v.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpS390XFCMPS, TypeFlags)
+ v2.AddArg(y)
+ v2.AddArg(x)
+ v.AddArg(v2)
+ return true
+ }
+}
+func rewriteValueS390X_OpLeq32U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Leq32U x y)
+ // cond:
+ // result: (MOVDLE (MOVDconst [0]) (MOVDconst [1]) (CMPWU x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XMOVDLE)
+ v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v0.AuxInt = 0
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v1.AuxInt = 1
+ v.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpS390XCMPWU, TypeFlags)
+ v2.AddArg(x)
+ v2.AddArg(y)
+ v.AddArg(v2)
+ return true
+ }
+}
+func rewriteValueS390X_OpLeq64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Leq64 x y)
+ // cond:
+ // result: (MOVDLE (MOVDconst [0]) (MOVDconst [1]) (CMP x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XMOVDLE)
+ v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v0.AuxInt = 0
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v1.AuxInt = 1
+ v.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpS390XCMP, TypeFlags)
+ v2.AddArg(x)
+ v2.AddArg(y)
+ v.AddArg(v2)
+ return true
+ }
+}
+func rewriteValueS390X_OpLeq64F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Leq64F x y)
+ // cond:
+ // result: (MOVDGEnoinv (MOVDconst [0]) (MOVDconst [1]) (FCMP y x))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XMOVDGEnoinv)
+ v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v0.AuxInt = 0
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v1.AuxInt = 1
+ v.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpS390XFCMP, TypeFlags)
+ v2.AddArg(y)
+ v2.AddArg(x)
+ v.AddArg(v2)
+ return true
+ }
+}
+func rewriteValueS390X_OpLeq64U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Leq64U x y)
+ // cond:
+ // result: (MOVDLE (MOVDconst [0]) (MOVDconst [1]) (CMPU x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XMOVDLE)
+ v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v0.AuxInt = 0
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v1.AuxInt = 1
+ v.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpS390XCMPU, TypeFlags)
+ v2.AddArg(x)
+ v2.AddArg(y)
+ v.AddArg(v2)
+ return true
+ }
+}
+func rewriteValueS390X_OpLeq8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Leq8 x y)
+ // cond:
+ // result: (MOVDLE (MOVDconst [0]) (MOVDconst [1]) (CMP (MOVBreg x) (MOVBreg y)))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XMOVDLE)
+ v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v0.AuxInt = 0
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v1.AuxInt = 1
+ v.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpS390XCMP, TypeFlags)
+ v3 := b.NewValue0(v.Line, OpS390XMOVBreg, config.fe.TypeInt64())
+ v3.AddArg(x)
+ v2.AddArg(v3)
+ v4 := b.NewValue0(v.Line, OpS390XMOVBreg, config.fe.TypeInt64())
+ v4.AddArg(y)
+ v2.AddArg(v4)
+ v.AddArg(v2)
+ return true
+ }
+}
+func rewriteValueS390X_OpLeq8U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Leq8U x y)
+ // cond:
+ // result: (MOVDLE (MOVDconst [0]) (MOVDconst [1]) (CMPU (MOVBZreg x) (MOVBZreg y)))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XMOVDLE)
+ v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v0.AuxInt = 0
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v1.AuxInt = 1
+ v.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpS390XCMPU, TypeFlags)
+ v3 := b.NewValue0(v.Line, OpS390XMOVBZreg, config.fe.TypeUInt64())
+ v3.AddArg(x)
+ v2.AddArg(v3)
+ v4 := b.NewValue0(v.Line, OpS390XMOVBZreg, config.fe.TypeUInt64())
+ v4.AddArg(y)
+ v2.AddArg(v4)
+ v.AddArg(v2)
+ return true
+ }
+}
+func rewriteValueS390X_OpLess16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Less16 x y)
+ // cond:
+ // result: (MOVDLT (MOVDconst [0]) (MOVDconst [1]) (CMP (MOVHreg x) (MOVHreg y)))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XMOVDLT)
+ v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v0.AuxInt = 0
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v1.AuxInt = 1
+ v.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpS390XCMP, TypeFlags)
+ v3 := b.NewValue0(v.Line, OpS390XMOVHreg, config.fe.TypeInt64())
+ v3.AddArg(x)
+ v2.AddArg(v3)
+ v4 := b.NewValue0(v.Line, OpS390XMOVHreg, config.fe.TypeInt64())
+ v4.AddArg(y)
+ v2.AddArg(v4)
+ v.AddArg(v2)
+ return true
+ }
+}
+func rewriteValueS390X_OpLess16U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Less16U x y)
+ // cond:
+ // result: (MOVDLT (MOVDconst [0]) (MOVDconst [1]) (CMPU (MOVHZreg x) (MOVHZreg y)))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XMOVDLT)
+ v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v0.AuxInt = 0
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v1.AuxInt = 1
+ v.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpS390XCMPU, TypeFlags)
+ v3 := b.NewValue0(v.Line, OpS390XMOVHZreg, config.fe.TypeUInt64())
+ v3.AddArg(x)
+ v2.AddArg(v3)
+ v4 := b.NewValue0(v.Line, OpS390XMOVHZreg, config.fe.TypeUInt64())
+ v4.AddArg(y)
+ v2.AddArg(v4)
+ v.AddArg(v2)
+ return true
+ }
+}
+func rewriteValueS390X_OpLess32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Less32 x y)
+ // cond:
+ // result: (MOVDLT (MOVDconst [0]) (MOVDconst [1]) (CMPW x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XMOVDLT)
+ v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v0.AuxInt = 0
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v1.AuxInt = 1
+ v.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpS390XCMPW, TypeFlags)
+ v2.AddArg(x)
+ v2.AddArg(y)
+ v.AddArg(v2)
+ return true
+ }
+}
+func rewriteValueS390X_OpLess32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Less32F x y)
+ // cond:
+ // result: (MOVDGTnoinv (MOVDconst [0]) (MOVDconst [1]) (FCMPS y x))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XMOVDGTnoinv)
+ v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v0.AuxInt = 0
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v1.AuxInt = 1
+ v.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpS390XFCMPS, TypeFlags)
+ v2.AddArg(y)
+ v2.AddArg(x)
+ v.AddArg(v2)
+ return true
+ }
+}
+func rewriteValueS390X_OpLess32U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Less32U x y)
+ // cond:
+ // result: (MOVDLT (MOVDconst [0]) (MOVDconst [1]) (CMPWU x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XMOVDLT)
+ v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v0.AuxInt = 0
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v1.AuxInt = 1
+ v.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpS390XCMPWU, TypeFlags)
+ v2.AddArg(x)
+ v2.AddArg(y)
+ v.AddArg(v2)
+ return true
+ }
+}
+func rewriteValueS390X_OpLess64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Less64 x y)
+ // cond:
+ // result: (MOVDLT (MOVDconst [0]) (MOVDconst [1]) (CMP x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XMOVDLT)
+ v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v0.AuxInt = 0
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v1.AuxInt = 1
+ v.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpS390XCMP, TypeFlags)
+ v2.AddArg(x)
+ v2.AddArg(y)
+ v.AddArg(v2)
+ return true
+ }
+}
+func rewriteValueS390X_OpLess64F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Less64F x y)
+ // cond:
+ // result: (MOVDGTnoinv (MOVDconst [0]) (MOVDconst [1]) (FCMP y x))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XMOVDGTnoinv)
+ v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v0.AuxInt = 0
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v1.AuxInt = 1
+ v.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpS390XFCMP, TypeFlags)
+ v2.AddArg(y)
+ v2.AddArg(x)
+ v.AddArg(v2)
+ return true
+ }
+}
+func rewriteValueS390X_OpLess64U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Less64U x y)
+ // cond:
+ // result: (MOVDLT (MOVDconst [0]) (MOVDconst [1]) (CMPU x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XMOVDLT)
+ v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v0.AuxInt = 0
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v1.AuxInt = 1
+ v.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpS390XCMPU, TypeFlags)
+ v2.AddArg(x)
+ v2.AddArg(y)
+ v.AddArg(v2)
+ return true
+ }
+}
+func rewriteValueS390X_OpLess8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Less8 x y)
+ // cond:
+ // result: (MOVDLT (MOVDconst [0]) (MOVDconst [1]) (CMP (MOVBreg x) (MOVBreg y)))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XMOVDLT)
+ v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v0.AuxInt = 0
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v1.AuxInt = 1
+ v.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpS390XCMP, TypeFlags)
+ v3 := b.NewValue0(v.Line, OpS390XMOVBreg, config.fe.TypeInt64())
+ v3.AddArg(x)
+ v2.AddArg(v3)
+ v4 := b.NewValue0(v.Line, OpS390XMOVBreg, config.fe.TypeInt64())
+ v4.AddArg(y)
+ v2.AddArg(v4)
+ v.AddArg(v2)
+ return true
+ }
+}
+func rewriteValueS390X_OpLess8U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Less8U x y)
+ // cond:
+ // result: (MOVDLT (MOVDconst [0]) (MOVDconst [1]) (CMPU (MOVBZreg x) (MOVBZreg y)))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XMOVDLT)
+ v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v0.AuxInt = 0
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v1.AuxInt = 1
+ v.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpS390XCMPU, TypeFlags)
+ v3 := b.NewValue0(v.Line, OpS390XMOVBZreg, config.fe.TypeUInt64())
+ v3.AddArg(x)
+ v2.AddArg(v3)
+ v4 := b.NewValue0(v.Line, OpS390XMOVBZreg, config.fe.TypeUInt64())
+ v4.AddArg(y)
+ v2.AddArg(v4)
+ v.AddArg(v2)
+ return true
+ }
+}
+func rewriteValueS390X_OpLoad(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Load <t> ptr mem)
+ // cond: (is64BitInt(t) || isPtr(t))
+ // result: (MOVDload ptr mem)
+ for {
+ t := v.Type
+ ptr := v.Args[0]
+ mem := v.Args[1]
+ if !(is64BitInt(t) || isPtr(t)) {
+ break
+ }
+ v.reset(OpS390XMOVDload)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (Load <t> ptr mem)
+ // cond: is32BitInt(t)
+ // result: (MOVWZload ptr mem)
+ for {
+ t := v.Type
+ ptr := v.Args[0]
+ mem := v.Args[1]
+ if !(is32BitInt(t)) {
+ break
+ }
+ v.reset(OpS390XMOVWZload)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (Load <t> ptr mem)
+ // cond: is16BitInt(t)
+ // result: (MOVHZload ptr mem)
+ for {
+ t := v.Type
+ ptr := v.Args[0]
+ mem := v.Args[1]
+ if !(is16BitInt(t)) {
+ break
+ }
+ v.reset(OpS390XMOVHZload)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (Load <t> ptr mem)
+ // cond: (t.IsBoolean() || is8BitInt(t))
+ // result: (MOVBZload ptr mem)
+ for {
+ t := v.Type
+ ptr := v.Args[0]
+ mem := v.Args[1]
+ if !(t.IsBoolean() || is8BitInt(t)) {
+ break
+ }
+ v.reset(OpS390XMOVBZload)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (Load <t> ptr mem)
+ // cond: is32BitFloat(t)
+ // result: (FMOVSload ptr mem)
+ for {
+ t := v.Type
+ ptr := v.Args[0]
+ mem := v.Args[1]
+ if !(is32BitFloat(t)) {
+ break
+ }
+ v.reset(OpS390XFMOVSload)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (Load <t> ptr mem)
+ // cond: is64BitFloat(t)
+ // result: (FMOVDload ptr mem)
+ for {
+ t := v.Type
+ ptr := v.Args[0]
+ mem := v.Args[1]
+ if !(is64BitFloat(t)) {
+ break
+ }
+ v.reset(OpS390XFMOVDload)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ 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 {
+ b := v.Block
+ _ = b
+ // match: (Lsh16x16 <t> x y)
+ // cond:
+ // result: (ANDW (SLW <t> x y) (SUBEWcarrymask <t> (CMPWUconst (MOVHZreg y) [31])))
+ for {
+ t := v.Type
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XANDW)
+ v0 := b.NewValue0(v.Line, 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)
+ v2.AuxInt = 31
+ v3 := b.NewValue0(v.Line, OpS390XMOVHZreg, config.fe.TypeUInt64())
+ v3.AddArg(y)
+ v2.AddArg(v3)
+ v1.AddArg(v2)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueS390X_OpLsh16x32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Lsh16x32 <t> x y)
+ // cond:
+ // result: (ANDW (SLW <t> x y) (SUBEWcarrymask <t> (CMPWUconst y [31])))
+ for {
+ t := v.Type
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XANDW)
+ v0 := b.NewValue0(v.Line, 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)
+ v2.AuxInt = 31
+ v2.AddArg(y)
+ v1.AddArg(v2)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueS390X_OpLsh16x64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Lsh16x64 <t> x y)
+ // cond:
+ // result: (ANDW (SLW <t> x y) (SUBEWcarrymask <t> (CMPUconst y [31])))
+ for {
+ t := v.Type
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XANDW)
+ v0 := b.NewValue0(v.Line, 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)
+ v2.AuxInt = 31
+ v2.AddArg(y)
+ v1.AddArg(v2)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueS390X_OpLsh16x8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Lsh16x8 <t> x y)
+ // cond:
+ // result: (ANDW (SLW <t> x y) (SUBEWcarrymask <t> (CMPWUconst (MOVBZreg y) [31])))
+ for {
+ t := v.Type
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XANDW)
+ v0 := b.NewValue0(v.Line, 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)
+ v2.AuxInt = 31
+ v3 := b.NewValue0(v.Line, OpS390XMOVBZreg, config.fe.TypeUInt64())
+ v3.AddArg(y)
+ v2.AddArg(v3)
+ v1.AddArg(v2)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueS390X_OpLsh32x16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Lsh32x16 <t> x y)
+ // cond:
+ // result: (ANDW (SLW <t> x y) (SUBEWcarrymask <t> (CMPWUconst (MOVHZreg y) [31])))
+ for {
+ t := v.Type
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XANDW)
+ v0 := b.NewValue0(v.Line, 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)
+ v2.AuxInt = 31
+ v3 := b.NewValue0(v.Line, OpS390XMOVHZreg, config.fe.TypeUInt64())
+ v3.AddArg(y)
+ v2.AddArg(v3)
+ v1.AddArg(v2)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueS390X_OpLsh32x32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Lsh32x32 <t> x y)
+ // cond:
+ // result: (ANDW (SLW <t> x y) (SUBEWcarrymask <t> (CMPWUconst y [31])))
+ for {
+ t := v.Type
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XANDW)
+ v0 := b.NewValue0(v.Line, 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)
+ v2.AuxInt = 31
+ v2.AddArg(y)
+ v1.AddArg(v2)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueS390X_OpLsh32x64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Lsh32x64 <t> x y)
+ // cond:
+ // result: (ANDW (SLW <t> x y) (SUBEWcarrymask <t> (CMPUconst y [31])))
+ for {
+ t := v.Type
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XANDW)
+ v0 := b.NewValue0(v.Line, 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)
+ v2.AuxInt = 31
+ v2.AddArg(y)
+ v1.AddArg(v2)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueS390X_OpLsh32x8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Lsh32x8 <t> x y)
+ // cond:
+ // result: (ANDW (SLW <t> x y) (SUBEWcarrymask <t> (CMPWUconst (MOVBZreg y) [31])))
+ for {
+ t := v.Type
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XANDW)
+ v0 := b.NewValue0(v.Line, 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)
+ v2.AuxInt = 31
+ v3 := b.NewValue0(v.Line, OpS390XMOVBZreg, config.fe.TypeUInt64())
+ v3.AddArg(y)
+ v2.AddArg(v3)
+ v1.AddArg(v2)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueS390X_OpLsh64x16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Lsh64x16 <t> x y)
+ // cond:
+ // result: (AND (SLD <t> x y) (SUBEcarrymask <t> (CMPWUconst (MOVHZreg y) [63])))
+ for {
+ t := v.Type
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XAND)
+ v0 := b.NewValue0(v.Line, 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)
+ v2.AuxInt = 63
+ v3 := b.NewValue0(v.Line, OpS390XMOVHZreg, config.fe.TypeUInt64())
+ v3.AddArg(y)
+ v2.AddArg(v3)
+ v1.AddArg(v2)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueS390X_OpLsh64x32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Lsh64x32 <t> x y)
+ // cond:
+ // result: (AND (SLD <t> x y) (SUBEcarrymask <t> (CMPWUconst y [63])))
+ for {
+ t := v.Type
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XAND)
+ v0 := b.NewValue0(v.Line, 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)
+ v2.AuxInt = 63
+ v2.AddArg(y)
+ v1.AddArg(v2)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueS390X_OpLsh64x64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Lsh64x64 <t> x y)
+ // cond:
+ // result: (AND (SLD <t> x y) (SUBEcarrymask <t> (CMPUconst y [63])))
+ for {
+ t := v.Type
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XAND)
+ v0 := b.NewValue0(v.Line, 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)
+ v2.AuxInt = 63
+ v2.AddArg(y)
+ v1.AddArg(v2)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueS390X_OpLsh64x8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Lsh64x8 <t> x y)
+ // cond:
+ // result: (AND (SLD <t> x y) (SUBEcarrymask <t> (CMPWUconst (MOVBZreg y) [63])))
+ for {
+ t := v.Type
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XAND)
+ v0 := b.NewValue0(v.Line, 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)
+ v2.AuxInt = 63
+ v3 := b.NewValue0(v.Line, OpS390XMOVBZreg, config.fe.TypeUInt64())
+ v3.AddArg(y)
+ v2.AddArg(v3)
+ v1.AddArg(v2)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueS390X_OpLsh8x16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Lsh8x16 <t> x y)
+ // cond:
+ // result: (ANDW (SLW <t> x y) (SUBEWcarrymask <t> (CMPWUconst (MOVHZreg y) [31])))
+ for {
+ t := v.Type
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XANDW)
+ v0 := b.NewValue0(v.Line, 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)
+ v2.AuxInt = 31
+ v3 := b.NewValue0(v.Line, OpS390XMOVHZreg, config.fe.TypeUInt64())
+ v3.AddArg(y)
+ v2.AddArg(v3)
+ v1.AddArg(v2)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueS390X_OpLsh8x32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Lsh8x32 <t> x y)
+ // cond:
+ // result: (ANDW (SLW <t> x y) (SUBEWcarrymask <t> (CMPWUconst y [31])))
+ for {
+ t := v.Type
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XANDW)
+ v0 := b.NewValue0(v.Line, 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)
+ v2.AuxInt = 31
+ v2.AddArg(y)
+ v1.AddArg(v2)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueS390X_OpLsh8x64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Lsh8x64 <t> x y)
+ // cond:
+ // result: (ANDW (SLW <t> x y) (SUBEWcarrymask <t> (CMPUconst y [31])))
+ for {
+ t := v.Type
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XANDW)
+ v0 := b.NewValue0(v.Line, 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)
+ v2.AuxInt = 31
+ v2.AddArg(y)
+ v1.AddArg(v2)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueS390X_OpLsh8x8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Lsh8x8 <t> x y)
+ // cond:
+ // result: (ANDW (SLW <t> x y) (SUBEWcarrymask <t> (CMPWUconst (MOVBZreg y) [31])))
+ for {
+ t := v.Type
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XANDW)
+ v0 := b.NewValue0(v.Line, 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)
+ v2.AuxInt = 31
+ v3 := b.NewValue0(v.Line, OpS390XMOVBZreg, config.fe.TypeUInt64())
+ v3.AddArg(y)
+ v2.AddArg(v3)
+ v1.AddArg(v2)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueS390X_OpMod16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Mod16 x y)
+ // cond:
+ // result: (MODW (MOVHreg x) (MOVHreg y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XMODW)
+ v0 := b.NewValue0(v.Line, OpS390XMOVHreg, config.fe.TypeInt64())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpS390XMOVHreg, config.fe.TypeInt64())
+ v1.AddArg(y)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueS390X_OpMod16u(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Mod16u x y)
+ // cond:
+ // result: (MODWU (MOVHZreg x) (MOVHZreg y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XMODWU)
+ v0 := b.NewValue0(v.Line, OpS390XMOVHZreg, config.fe.TypeUInt64())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpS390XMOVHZreg, config.fe.TypeUInt64())
+ v1.AddArg(y)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueS390X_OpMod32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Mod32 x y)
+ // cond:
+ // result: (MODW (MOVWreg x) y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XMODW)
+ v0 := b.NewValue0(v.Line, OpS390XMOVWreg, config.fe.TypeInt64())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueS390X_OpMod32u(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Mod32u x y)
+ // cond:
+ // result: (MODWU (MOVWZreg x) y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XMODWU)
+ v0 := b.NewValue0(v.Line, OpS390XMOVWZreg, config.fe.TypeUInt64())
+ 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)
+ // cond:
+ // result: (MODD x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XMODD)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueS390X_OpMod64u(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Mod64u x y)
+ // cond:
+ // result: (MODDU x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XMODDU)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueS390X_OpMod8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Mod8 x y)
+ // cond:
+ // result: (MODW (MOVBreg x) (MOVBreg y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XMODW)
+ v0 := b.NewValue0(v.Line, OpS390XMOVBreg, config.fe.TypeInt64())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpS390XMOVBreg, config.fe.TypeInt64())
+ v1.AddArg(y)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueS390X_OpMod8u(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Mod8u x y)
+ // cond:
+ // result: (MODWU (MOVBZreg x) (MOVBZreg y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XMODWU)
+ v0 := b.NewValue0(v.Line, OpS390XMOVBZreg, config.fe.TypeUInt64())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpS390XMOVBZreg, config.fe.TypeUInt64())
+ v1.AddArg(y)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueS390X_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) {
+ 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 (MOVBZload src mem) mem)
+ for {
+ s := v.AuxInt
+ 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.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: (MOVHstore dst (MOVHZload src mem) mem)
+ for {
+ s := v.AuxInt
+ 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.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: (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() == 4) {
+ break
+ }
+ v.reset(OpS390XMOVWstore)
+ v.AddArg(dst)
+ v0 := b.NewValue0(v.Line, OpS390XMOVWZload, 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: (MOVDstore dst (MOVDload src mem) mem)
+ for {
+ s := v.AuxInt
+ 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.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: (MOVDstore [8] dst (MOVDload [8] src mem) (MOVDstore dst (MOVDload src mem) mem))
+ for {
+ s := v.AuxInt
+ 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.AuxInt = 8
+ v0.AddArg(src)
+ v0.AddArg(mem)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpS390XMOVDstore, TypeMem)
+ v1.AddArg(dst)
+ v2 := b.NewValue0(v.Line, OpS390XMOVDload, config.fe.TypeUInt64())
+ v2.AddArg(src)
+ v2.AddArg(mem)
+ v1.AddArg(v2)
+ v1.AddArg(mem)
+ v.AddArg(v1)
+ return true
+ }
+ // match: (Move [s] dst src mem)
+ // cond: SizeAndAlign(s).Size() == 24
+ // 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
+ 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.AuxInt = 16
+ v0.AddArg(src)
+ v0.AddArg(mem)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpS390XMOVDstore, TypeMem)
+ v1.AuxInt = 8
+ v1.AddArg(dst)
+ v2 := b.NewValue0(v.Line, OpS390XMOVDload, config.fe.TypeUInt64())
+ v2.AuxInt = 8
+ v2.AddArg(src)
+ v2.AddArg(mem)
+ v1.AddArg(v2)
+ v3 := b.NewValue0(v.Line, OpS390XMOVDstore, TypeMem)
+ v3.AddArg(dst)
+ v4 := b.NewValue0(v.Line, OpS390XMOVDload, config.fe.TypeUInt64())
+ v4.AddArg(src)
+ v4.AddArg(mem)
+ v3.AddArg(v4)
+ v3.AddArg(mem)
+ v1.AddArg(v3)
+ v.AddArg(v1)
+ return true
+ }
+ // match: (Move [s] dst src mem)
+ // cond: SizeAndAlign(s).Size() == 3
+ // result: (MOVBstore [2] dst (MOVBZload [2] src mem) (MOVHstore dst (MOVHZload src mem) mem))
+ for {
+ s := v.AuxInt
+ 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.AuxInt = 2
+ v0.AddArg(src)
+ v0.AddArg(mem)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpS390XMOVHstore, TypeMem)
+ v1.AddArg(dst)
+ v2 := b.NewValue0(v.Line, OpS390XMOVHZload, config.fe.TypeUInt16())
+ v2.AddArg(src)
+ v2.AddArg(mem)
+ v1.AddArg(v2)
+ v1.AddArg(mem)
+ v.AddArg(v1)
+ return true
+ }
+ // match: (Move [s] dst src mem)
+ // cond: SizeAndAlign(s).Size() == 5
+ // 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() == 5) {
+ break
+ }
+ v.reset(OpS390XMOVBstore)
+ v.AuxInt = 4
+ v.AddArg(dst)
+ v0 := b.NewValue0(v.Line, OpS390XMOVBZload, config.fe.TypeUInt8())
+ v0.AuxInt = 4
+ v0.AddArg(src)
+ v0.AddArg(mem)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpS390XMOVWstore, TypeMem)
+ v1.AddArg(dst)
+ v2 := b.NewValue0(v.Line, OpS390XMOVWZload, config.fe.TypeUInt32())
+ v2.AddArg(src)
+ v2.AddArg(mem)
+ v1.AddArg(v2)
+ v1.AddArg(mem)
+ v.AddArg(v1)
+ return true
+ }
+ // match: (Move [s] dst src mem)
+ // cond: SizeAndAlign(s).Size() == 6
+ // result: (MOVHstore [4] dst (MOVHZload [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() == 6) {
+ break
+ }
+ v.reset(OpS390XMOVHstore)
+ v.AuxInt = 4
+ v.AddArg(dst)
+ v0 := b.NewValue0(v.Line, OpS390XMOVHZload, config.fe.TypeUInt16())
+ v0.AuxInt = 4
+ v0.AddArg(src)
+ v0.AddArg(mem)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpS390XMOVWstore, TypeMem)
+ v1.AddArg(dst)
+ v2 := b.NewValue0(v.Line, OpS390XMOVWZload, config.fe.TypeUInt32())
+ v2.AddArg(src)
+ v2.AddArg(mem)
+ v1.AddArg(v2)
+ v1.AddArg(mem)
+ v.AddArg(v1)
+ return true
+ }
+ // match: (Move [s] dst src mem)
+ // cond: SizeAndAlign(s).Size() == 7
+ // 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
+ 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.AuxInt = 6
+ v0.AddArg(src)
+ v0.AddArg(mem)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpS390XMOVHstore, TypeMem)
+ v1.AuxInt = 4
+ v1.AddArg(dst)
+ v2 := b.NewValue0(v.Line, OpS390XMOVHZload, config.fe.TypeUInt16())
+ v2.AuxInt = 4
+ v2.AddArg(src)
+ v2.AddArg(mem)
+ v1.AddArg(v2)
+ v3 := b.NewValue0(v.Line, OpS390XMOVWstore, TypeMem)
+ v3.AddArg(dst)
+ v4 := b.NewValue0(v.Line, OpS390XMOVWZload, config.fe.TypeUInt32())
+ v4.AddArg(src)
+ v4.AddArg(mem)
+ v3.AddArg(v4)
+ v3.AddArg(mem)
+ v1.AddArg(v3)
+ v.AddArg(v1)
+ 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)
+ for {
+ s := v.AuxInt
+ dst := v.Args[0]
+ src := v.Args[1]
+ mem := v.Args[2]
+ if !(SizeAndAlign(s).Size() > 0 && SizeAndAlign(s).Size() <= 256) {
+ break
+ }
+ v.reset(OpS390XMVC)
+ v.AuxInt = makeValAndOff(SizeAndAlign(s).Size(), 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))
+ for {
+ s := v.AuxInt
+ dst := v.Args[0]
+ src := v.Args[1]
+ mem := v.Args[2]
+ if !(SizeAndAlign(s).Size() > 256 && SizeAndAlign(s).Size() <= 512) {
+ break
+ }
+ v.reset(OpS390XMVC)
+ v.AuxInt = makeValAndOff(SizeAndAlign(s).Size()-256, 256)
+ v.AddArg(dst)
+ v.AddArg(src)
+ v0 := b.NewValue0(v.Line, OpS390XMVC, TypeMem)
+ v0.AuxInt = makeValAndOff(256, 0)
+ v0.AddArg(dst)
+ v0.AddArg(src)
+ v0.AddArg(mem)
+ v.AddArg(v0)
+ 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)))
+ for {
+ s := v.AuxInt
+ dst := v.Args[0]
+ src := v.Args[1]
+ mem := v.Args[2]
+ if !(SizeAndAlign(s).Size() > 512 && SizeAndAlign(s).Size() <= 768) {
+ break
+ }
+ v.reset(OpS390XMVC)
+ v.AuxInt = makeValAndOff(SizeAndAlign(s).Size()-512, 512)
+ v.AddArg(dst)
+ v.AddArg(src)
+ v0 := b.NewValue0(v.Line, OpS390XMVC, TypeMem)
+ v0.AuxInt = makeValAndOff(256, 256)
+ v0.AddArg(dst)
+ v0.AddArg(src)
+ v1 := b.NewValue0(v.Line, OpS390XMVC, TypeMem)
+ v1.AuxInt = makeValAndOff(256, 0)
+ v1.AddArg(dst)
+ v1.AddArg(src)
+ v1.AddArg(mem)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ 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))))
+ for {
+ s := v.AuxInt
+ dst := v.Args[0]
+ src := v.Args[1]
+ mem := v.Args[2]
+ if !(SizeAndAlign(s).Size() > 768 && SizeAndAlign(s).Size() <= 1024) {
+ break
+ }
+ v.reset(OpS390XMVC)
+ v.AuxInt = makeValAndOff(SizeAndAlign(s).Size()-768, 768)
+ v.AddArg(dst)
+ v.AddArg(src)
+ v0 := b.NewValue0(v.Line, OpS390XMVC, TypeMem)
+ v0.AuxInt = makeValAndOff(256, 512)
+ v0.AddArg(dst)
+ v0.AddArg(src)
+ v1 := b.NewValue0(v.Line, OpS390XMVC, TypeMem)
+ v1.AuxInt = makeValAndOff(256, 256)
+ v1.AddArg(dst)
+ v1.AddArg(src)
+ v2 := b.NewValue0(v.Line, OpS390XMVC, TypeMem)
+ v2.AuxInt = makeValAndOff(256, 0)
+ v2.AddArg(dst)
+ v2.AddArg(src)
+ v2.AddArg(mem)
+ v1.AddArg(v2)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ 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)
+ for {
+ s := v.AuxInt
+ dst := v.Args[0]
+ src := v.Args[1]
+ mem := v.Args[2]
+ if !(SizeAndAlign(s).Size() > 1024) {
+ break
+ }
+ v.reset(OpS390XLoweredMove)
+ v.AuxInt = SizeAndAlign(s).Size() % 256
+ v.AddArg(dst)
+ v.AddArg(src)
+ v0 := b.NewValue0(v.Line, OpS390XADDconst, src.Type)
+ v0.AuxInt = (SizeAndAlign(s).Size() / 256) * 256
+ v0.AddArg(src)
+ v.AddArg(v0)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValueS390X_OpMul16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Mul16 x y)
+ // cond:
+ // result: (MULLW x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XMULLW)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueS390X_OpMul32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Mul32 x y)
+ // cond:
+ // result: (MULLW x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XMULLW)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueS390X_OpMul32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Mul32F x y)
+ // cond:
+ // result: (FMULS x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XFMULS)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueS390X_OpMul64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Mul64 x y)
+ // cond:
+ // result: (MULLD x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XMULLD)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueS390X_OpMul64F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Mul64F x y)
+ // cond:
+ // result: (FMUL x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XFMUL)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueS390X_OpMul8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Mul8 x y)
+ // cond:
+ // result: (MULLW x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XMULLW)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueS390X_OpNeg16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueS390X_OpNeg32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Neg32 x)
+ // cond:
+ // result: (NEGW x)
+ for {
+ x := v.Args[0]
+ v.reset(OpS390XNEGW)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueS390X_OpNeg32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Neg32F x)
+ // cond:
+ // result: (FNEGS x)
+ for {
+ x := v.Args[0]
+ v.reset(OpS390XFNEGS)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueS390X_OpNeg64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Neg64 x)
+ // cond:
+ // result: (NEG x)
+ for {
+ x := v.Args[0]
+ v.reset(OpS390XNEG)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueS390X_OpNeg64F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Neg64F x)
+ // cond:
+ // result: (FNEG x)
+ for {
+ x := v.Args[0]
+ v.reset(OpS390XFNEG)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueS390X_OpNeg8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueS390X_OpNeq16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Neq16 x y)
+ // cond:
+ // result: (MOVDNE (MOVDconst [0]) (MOVDconst [1]) (CMP (MOVHreg x) (MOVHreg y)))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XMOVDNE)
+ v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v0.AuxInt = 0
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v1.AuxInt = 1
+ v.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpS390XCMP, TypeFlags)
+ v3 := b.NewValue0(v.Line, OpS390XMOVHreg, config.fe.TypeInt64())
+ v3.AddArg(x)
+ v2.AddArg(v3)
+ v4 := b.NewValue0(v.Line, OpS390XMOVHreg, config.fe.TypeInt64())
+ v4.AddArg(y)
+ v2.AddArg(v4)
+ v.AddArg(v2)
+ return true
+ }
+}
+func rewriteValueS390X_OpNeq32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Neq32 x y)
+ // cond:
+ // result: (MOVDNE (MOVDconst [0]) (MOVDconst [1]) (CMPW x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XMOVDNE)
+ v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v0.AuxInt = 0
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v1.AuxInt = 1
+ v.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpS390XCMPW, TypeFlags)
+ v2.AddArg(x)
+ v2.AddArg(y)
+ v.AddArg(v2)
+ return true
+ }
+}
+func rewriteValueS390X_OpNeq32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Neq32F x y)
+ // cond:
+ // result: (MOVDNE (MOVDconst [0]) (MOVDconst [1]) (FCMPS x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XMOVDNE)
+ v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v0.AuxInt = 0
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v1.AuxInt = 1
+ v.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpS390XFCMPS, TypeFlags)
+ v2.AddArg(x)
+ v2.AddArg(y)
+ v.AddArg(v2)
+ return true
+ }
+}
+func rewriteValueS390X_OpNeq64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Neq64 x y)
+ // cond:
+ // result: (MOVDNE (MOVDconst [0]) (MOVDconst [1]) (CMP x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XMOVDNE)
+ v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v0.AuxInt = 0
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v1.AuxInt = 1
+ v.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpS390XCMP, TypeFlags)
+ v2.AddArg(x)
+ v2.AddArg(y)
+ v.AddArg(v2)
+ return true
+ }
+}
+func rewriteValueS390X_OpNeq64F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Neq64F x y)
+ // cond:
+ // result: (MOVDNE (MOVDconst [0]) (MOVDconst [1]) (FCMP x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XMOVDNE)
+ v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v0.AuxInt = 0
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v1.AuxInt = 1
+ v.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpS390XFCMP, TypeFlags)
+ v2.AddArg(x)
+ v2.AddArg(y)
+ v.AddArg(v2)
+ return true
+ }
+}
+func rewriteValueS390X_OpNeq8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Neq8 x y)
+ // cond:
+ // result: (MOVDNE (MOVDconst [0]) (MOVDconst [1]) (CMP (MOVBreg x) (MOVBreg y)))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XMOVDNE)
+ v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v0.AuxInt = 0
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v1.AuxInt = 1
+ v.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpS390XCMP, TypeFlags)
+ v3 := b.NewValue0(v.Line, OpS390XMOVBreg, config.fe.TypeInt64())
+ v3.AddArg(x)
+ v2.AddArg(v3)
+ v4 := b.NewValue0(v.Line, OpS390XMOVBreg, config.fe.TypeInt64())
+ v4.AddArg(y)
+ v2.AddArg(v4)
+ v.AddArg(v2)
+ return true
+ }
+}
+func rewriteValueS390X_OpNeqB(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (NeqB x y)
+ // cond:
+ // result: (MOVDNE (MOVDconst [0]) (MOVDconst [1]) (CMP (MOVBreg x) (MOVBreg y)))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XMOVDNE)
+ v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v0.AuxInt = 0
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v1.AuxInt = 1
+ v.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpS390XCMP, TypeFlags)
+ v3 := b.NewValue0(v.Line, OpS390XMOVBreg, config.fe.TypeInt64())
+ v3.AddArg(x)
+ v2.AddArg(v3)
+ v4 := b.NewValue0(v.Line, OpS390XMOVBreg, config.fe.TypeInt64())
+ v4.AddArg(y)
+ v2.AddArg(v4)
+ v.AddArg(v2)
+ return true
+ }
+}
+func rewriteValueS390X_OpNeqPtr(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (NeqPtr x y)
+ // cond:
+ // result: (MOVDNE (MOVDconst [0]) (MOVDconst [1]) (CMP x y))
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XMOVDNE)
+ v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v0.AuxInt = 0
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v1.AuxInt = 1
+ v.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpS390XCMP, TypeFlags)
+ v2.AddArg(x)
+ v2.AddArg(y)
+ v.AddArg(v2)
+ return true
+ }
+}
+func rewriteValueS390X_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(OpS390XLoweredNilCheck)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+}
+func rewriteValueS390X_OpNot(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Not x)
+ // cond:
+ // result: (XORWconst [1] x)
+ for {
+ x := v.Args[0]
+ v.reset(OpS390XXORWconst)
+ v.AuxInt = 1
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueS390X_OpOffPtr(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (OffPtr [off] ptr:(SP))
+ // cond:
+ // result: (MOVDaddr [off] ptr)
+ for {
+ off := v.AuxInt
+ ptr := v.Args[0]
+ if ptr.Op != OpSP {
+ break
+ }
+ v.reset(OpS390XMOVDaddr)
+ v.AuxInt = off
+ v.AddArg(ptr)
+ return true
+ }
+ // match: (OffPtr [off] ptr)
+ // cond: is32Bit(off)
+ // result: (ADDconst [off] ptr)
+ for {
+ off := v.AuxInt
+ ptr := v.Args[0]
+ if !(is32Bit(off)) {
+ break
+ }
+ v.reset(OpS390XADDconst)
+ v.AuxInt = off
+ v.AddArg(ptr)
+ return true
+ }
+ // match: (OffPtr [off] ptr)
+ // cond:
+ // result: (ADD (MOVDconst [off]) ptr)
+ for {
+ off := v.AuxInt
+ ptr := v.Args[0]
+ v.reset(OpS390XADD)
+ v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v0.AuxInt = off
+ v.AddArg(v0)
+ v.AddArg(ptr)
+ return true
+ }
+}
+func rewriteValueS390X_OpOr16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Or16 x y)
+ // cond:
+ // result: (ORW x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XORW)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueS390X_OpOr32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Or32 x y)
+ // cond:
+ // result: (ORW x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XORW)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueS390X_OpOr64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Or64 x y)
+ // cond:
+ // result: (OR x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XOR)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueS390X_OpOr8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Or8 x y)
+ // cond:
+ // result: (ORW x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XORW)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueS390X_OpOrB(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (OrB x y)
+ // cond:
+ // result: (ORW x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XORW)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueS390X_OpRsh16Ux16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh16Ux16 <t> x y)
+ // cond:
+ // result: (ANDW (SRW <t> (MOVHZreg x) y) (SUBEWcarrymask <t> (CMPWUconst (MOVHZreg y) [15])))
+ for {
+ t := v.Type
+ 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())
+ 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)
+ v3.AuxInt = 15
+ v4 := b.NewValue0(v.Line, OpS390XMOVHZreg, config.fe.TypeUInt64())
+ v4.AddArg(y)
+ v3.AddArg(v4)
+ v2.AddArg(v3)
+ v.AddArg(v2)
+ return true
+ }
+}
+func rewriteValueS390X_OpRsh16Ux32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh16Ux32 <t> x y)
+ // cond:
+ // result: (ANDW (SRW <t> (MOVHZreg x) y) (SUBEWcarrymask <t> (CMPWUconst y [15])))
+ for {
+ t := v.Type
+ 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())
+ 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)
+ v3.AuxInt = 15
+ v3.AddArg(y)
+ v2.AddArg(v3)
+ v.AddArg(v2)
+ return true
+ }
+}
+func rewriteValueS390X_OpRsh16Ux64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh16Ux64 <t> x y)
+ // cond:
+ // result: (ANDW (SRW <t> (MOVHZreg x) y) (SUBEWcarrymask <t> (CMPUconst y [15])))
+ for {
+ t := v.Type
+ 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())
+ 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)
+ v3.AuxInt = 15
+ v3.AddArg(y)
+ v2.AddArg(v3)
+ v.AddArg(v2)
+ return true
+ }
+}
+func rewriteValueS390X_OpRsh16Ux8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh16Ux8 <t> x y)
+ // cond:
+ // result: (ANDW (SRW <t> (MOVHZreg x) y) (SUBEWcarrymask <t> (CMPWUconst (MOVBZreg y) [15])))
+ for {
+ t := v.Type
+ 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())
+ 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)
+ v3.AuxInt = 15
+ v4 := b.NewValue0(v.Line, OpS390XMOVBZreg, config.fe.TypeUInt64())
+ v4.AddArg(y)
+ v3.AddArg(v4)
+ v2.AddArg(v3)
+ v.AddArg(v2)
+ return true
+ }
+}
+func rewriteValueS390X_OpRsh16x16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XSRAW)
+ v.Type = t
+ v0 := b.NewValue0(v.Line, OpS390XMOVHreg, config.fe.TypeInt64())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, 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)
+ v4.AuxInt = 15
+ v5 := b.NewValue0(v.Line, OpS390XMOVHZreg, config.fe.TypeUInt64())
+ v5.AddArg(y)
+ v4.AddArg(v5)
+ v3.AddArg(v4)
+ v2.AddArg(v3)
+ v1.AddArg(v2)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueS390X_OpRsh16x32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XSRAW)
+ v.Type = t
+ v0 := b.NewValue0(v.Line, OpS390XMOVHreg, config.fe.TypeInt64())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, 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)
+ v4.AuxInt = 15
+ v4.AddArg(y)
+ v3.AddArg(v4)
+ v2.AddArg(v3)
+ v1.AddArg(v2)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueS390X_OpRsh16x64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XSRAW)
+ v.Type = t
+ v0 := b.NewValue0(v.Line, OpS390XMOVHreg, config.fe.TypeInt64())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, 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)
+ v4.AuxInt = 15
+ v4.AddArg(y)
+ v3.AddArg(v4)
+ v2.AddArg(v3)
+ v1.AddArg(v2)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueS390X_OpRsh16x8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XSRAW)
+ v.Type = t
+ v0 := b.NewValue0(v.Line, OpS390XMOVHreg, config.fe.TypeInt64())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, 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)
+ v4.AuxInt = 15
+ v5 := b.NewValue0(v.Line, OpS390XMOVBZreg, config.fe.TypeUInt64())
+ v5.AddArg(y)
+ v4.AddArg(v5)
+ v3.AddArg(v4)
+ v2.AddArg(v3)
+ v1.AddArg(v2)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueS390X_OpRsh32Ux16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh32Ux16 <t> x y)
+ // cond:
+ // result: (ANDW (SRW <t> x y) (SUBEWcarrymask <t> (CMPWUconst (MOVHZreg y) [31])))
+ for {
+ t := v.Type
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XANDW)
+ v0 := b.NewValue0(v.Line, 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)
+ v2.AuxInt = 31
+ v3 := b.NewValue0(v.Line, OpS390XMOVHZreg, config.fe.TypeUInt64())
+ v3.AddArg(y)
+ v2.AddArg(v3)
+ v1.AddArg(v2)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueS390X_OpRsh32Ux32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh32Ux32 <t> x y)
+ // cond:
+ // result: (ANDW (SRW <t> x y) (SUBEWcarrymask <t> (CMPWUconst y [31])))
+ for {
+ t := v.Type
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XANDW)
+ v0 := b.NewValue0(v.Line, 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)
+ v2.AuxInt = 31
+ v2.AddArg(y)
+ v1.AddArg(v2)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueS390X_OpRsh32Ux64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh32Ux64 <t> x y)
+ // cond:
+ // result: (ANDW (SRW <t> x y) (SUBEWcarrymask <t> (CMPUconst y [31])))
+ for {
+ t := v.Type
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XANDW)
+ v0 := b.NewValue0(v.Line, 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)
+ v2.AuxInt = 31
+ v2.AddArg(y)
+ v1.AddArg(v2)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueS390X_OpRsh32Ux8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh32Ux8 <t> x y)
+ // cond:
+ // result: (ANDW (SRW <t> x y) (SUBEWcarrymask <t> (CMPWUconst (MOVBZreg y) [31])))
+ for {
+ t := v.Type
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XANDW)
+ v0 := b.NewValue0(v.Line, 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)
+ v2.AuxInt = 31
+ v3 := b.NewValue0(v.Line, OpS390XMOVBZreg, config.fe.TypeUInt64())
+ v3.AddArg(y)
+ v2.AddArg(v3)
+ v1.AddArg(v2)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueS390X_OpRsh32x16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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
+ 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.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)
+ v3.AuxInt = 31
+ v4 := b.NewValue0(v.Line, OpS390XMOVHZreg, config.fe.TypeUInt64())
+ v4.AddArg(y)
+ v3.AddArg(v4)
+ v2.AddArg(v3)
+ v1.AddArg(v2)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueS390X_OpRsh32x32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh32x32 <t> x y)
+ // cond:
+ // result: (SRAW <t> x (ORW <y.Type> y (NOTW <y.Type> (SUBEWcarrymask <y.Type> (CMPWUconst y [31])))))
+ for {
+ t := v.Type
+ 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.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)
+ v3.AuxInt = 31
+ v3.AddArg(y)
+ v2.AddArg(v3)
+ v1.AddArg(v2)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueS390X_OpRsh32x64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh32x64 <t> x y)
+ // cond:
+ // result: (SRAW <t> x (OR <y.Type> y (NOT <y.Type> (SUBEcarrymask <y.Type> (CMPUconst y [31])))))
+ for {
+ t := v.Type
+ 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.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)
+ v3.AuxInt = 31
+ v3.AddArg(y)
+ v2.AddArg(v3)
+ v1.AddArg(v2)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueS390X_OpRsh32x8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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
+ 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.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)
+ v3.AuxInt = 31
+ v4 := b.NewValue0(v.Line, OpS390XMOVBZreg, config.fe.TypeUInt64())
+ v4.AddArg(y)
+ v3.AddArg(v4)
+ v2.AddArg(v3)
+ v1.AddArg(v2)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueS390X_OpRsh64Ux16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh64Ux16 <t> x y)
+ // cond:
+ // result: (AND (SRD <t> x y) (SUBEcarrymask <t> (CMPWUconst (MOVHZreg y) [63])))
+ for {
+ t := v.Type
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XAND)
+ v0 := b.NewValue0(v.Line, 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)
+ v2.AuxInt = 63
+ v3 := b.NewValue0(v.Line, OpS390XMOVHZreg, config.fe.TypeUInt64())
+ v3.AddArg(y)
+ v2.AddArg(v3)
+ v1.AddArg(v2)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueS390X_OpRsh64Ux32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh64Ux32 <t> x y)
+ // cond:
+ // result: (AND (SRD <t> x y) (SUBEcarrymask <t> (CMPWUconst y [63])))
+ for {
+ t := v.Type
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XAND)
+ v0 := b.NewValue0(v.Line, 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)
+ v2.AuxInt = 63
+ v2.AddArg(y)
+ v1.AddArg(v2)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueS390X_OpRsh64Ux64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh64Ux64 <t> x y)
+ // cond:
+ // result: (AND (SRD <t> x y) (SUBEcarrymask <t> (CMPUconst y [63])))
+ for {
+ t := v.Type
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XAND)
+ v0 := b.NewValue0(v.Line, 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)
+ v2.AuxInt = 63
+ v2.AddArg(y)
+ v1.AddArg(v2)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueS390X_OpRsh64Ux8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh64Ux8 <t> x y)
+ // cond:
+ // result: (AND (SRD <t> x y) (SUBEcarrymask <t> (CMPWUconst (MOVBZreg y) [63])))
+ for {
+ t := v.Type
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XAND)
+ v0 := b.NewValue0(v.Line, 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)
+ v2.AuxInt = 63
+ v3 := b.NewValue0(v.Line, OpS390XMOVBZreg, config.fe.TypeUInt64())
+ v3.AddArg(y)
+ v2.AddArg(v3)
+ v1.AddArg(v2)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueS390X_OpRsh64x16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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
+ 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.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)
+ v3.AuxInt = 63
+ v4 := b.NewValue0(v.Line, OpS390XMOVHZreg, config.fe.TypeUInt64())
+ v4.AddArg(y)
+ v3.AddArg(v4)
+ v2.AddArg(v3)
+ v1.AddArg(v2)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueS390X_OpRsh64x32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh64x32 <t> x y)
+ // cond:
+ // result: (SRAD <t> x (ORW <y.Type> y (NOTW <y.Type> (SUBEWcarrymask <y.Type> (CMPWUconst y [63])))))
+ for {
+ t := v.Type
+ 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.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)
+ v3.AuxInt = 63
+ v3.AddArg(y)
+ v2.AddArg(v3)
+ v1.AddArg(v2)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueS390X_OpRsh64x64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh64x64 <t> x y)
+ // cond:
+ // result: (SRAD <t> x (OR <y.Type> y (NOT <y.Type> (SUBEcarrymask <y.Type> (CMPUconst y [63])))))
+ for {
+ t := v.Type
+ 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.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)
+ v3.AuxInt = 63
+ v3.AddArg(y)
+ v2.AddArg(v3)
+ v1.AddArg(v2)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueS390X_OpRsh64x8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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
+ 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.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)
+ v3.AuxInt = 63
+ v4 := b.NewValue0(v.Line, OpS390XMOVBZreg, config.fe.TypeUInt64())
+ v4.AddArg(y)
+ v3.AddArg(v4)
+ v2.AddArg(v3)
+ v1.AddArg(v2)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValueS390X_OpRsh8Ux16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh8Ux16 <t> x y)
+ // cond:
+ // result: (ANDW (SRW <t> (MOVBZreg x) y) (SUBEWcarrymask <t> (CMPWUconst (MOVHZreg y) [7])))
+ for {
+ t := v.Type
+ 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())
+ 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)
+ v3.AuxInt = 7
+ v4 := b.NewValue0(v.Line, OpS390XMOVHZreg, config.fe.TypeUInt64())
+ v4.AddArg(y)
+ v3.AddArg(v4)
+ v2.AddArg(v3)
+ v.AddArg(v2)
+ return true
+ }
+}
+func rewriteValueS390X_OpRsh8Ux32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh8Ux32 <t> x y)
+ // cond:
+ // result: (ANDW (SRW <t> (MOVBZreg x) y) (SUBEWcarrymask <t> (CMPWUconst y [7])))
+ for {
+ t := v.Type
+ 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())
+ 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)
+ v3.AuxInt = 7
+ v3.AddArg(y)
+ v2.AddArg(v3)
+ v.AddArg(v2)
+ return true
+ }
+}
+func rewriteValueS390X_OpRsh8Ux64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh8Ux64 <t> x y)
+ // cond:
+ // result: (ANDW (SRW <t> (MOVBZreg x) y) (SUBEWcarrymask <t> (CMPUconst y [7])))
+ for {
+ t := v.Type
+ 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())
+ 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)
+ v3.AuxInt = 7
+ v3.AddArg(y)
+ v2.AddArg(v3)
+ v.AddArg(v2)
+ return true
+ }
+}
+func rewriteValueS390X_OpRsh8Ux8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh8Ux8 <t> x y)
+ // cond:
+ // result: (ANDW (SRW <t> (MOVBZreg x) y) (SUBEWcarrymask <t> (CMPWUconst (MOVBZreg y) [7])))
+ for {
+ t := v.Type
+ 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())
+ 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)
+ v3.AuxInt = 7
+ v4 := b.NewValue0(v.Line, OpS390XMOVBZreg, config.fe.TypeUInt64())
+ v4.AddArg(y)
+ v3.AddArg(v4)
+ v2.AddArg(v3)
+ v.AddArg(v2)
+ return true
+ }
+}
+func rewriteValueS390X_OpRsh8x16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XSRAW)
+ v.Type = t
+ v0 := b.NewValue0(v.Line, OpS390XMOVBreg, config.fe.TypeInt64())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, 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)
+ v4.AuxInt = 7
+ v5 := b.NewValue0(v.Line, OpS390XMOVHZreg, config.fe.TypeUInt64())
+ v5.AddArg(y)
+ v4.AddArg(v5)
+ v3.AddArg(v4)
+ v2.AddArg(v3)
+ v1.AddArg(v2)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueS390X_OpRsh8x32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XSRAW)
+ v.Type = t
+ v0 := b.NewValue0(v.Line, OpS390XMOVBreg, config.fe.TypeInt64())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, 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)
+ v4.AuxInt = 7
+ v4.AddArg(y)
+ v3.AddArg(v4)
+ v2.AddArg(v3)
+ v1.AddArg(v2)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueS390X_OpRsh8x64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XSRAW)
+ v.Type = t
+ v0 := b.NewValue0(v.Line, OpS390XMOVBreg, config.fe.TypeInt64())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, 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)
+ v4.AuxInt = 7
+ v4.AddArg(y)
+ v3.AddArg(v4)
+ v2.AddArg(v3)
+ v1.AddArg(v2)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueS390X_OpRsh8x8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XSRAW)
+ v.Type = t
+ v0 := b.NewValue0(v.Line, OpS390XMOVBreg, config.fe.TypeInt64())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, 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)
+ v4.AuxInt = 7
+ v5 := b.NewValue0(v.Line, OpS390XMOVBZreg, config.fe.TypeUInt64())
+ v5.AddArg(y)
+ v4.AddArg(v5)
+ v3.AddArg(v4)
+ v2.AddArg(v3)
+ v1.AddArg(v2)
+ v.AddArg(v1)
+ return true
+ }
+}
+func rewriteValueS390X_OpS390XADD(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ADD x (MOVDconst [c]))
+ // cond: is32Bit(c)
+ // result: (ADDconst [c] x)
+ for {
+ 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(OpS390XADDconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (ADD (MOVDconst [c]) x)
+ // cond: is32Bit(c)
+ // result: (ADDconst [c] x)
+ for {
+ 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(OpS390XADDconst)
+ v.AuxInt = c
+ 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)
+ for {
+ x := 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) {
+ break
+ }
+ v.reset(OpS390XMOVDaddridx)
+ v.AuxInt = c
+ v.Aux = s
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (ADD (MOVDaddr [c] {s} x) y)
+ // cond: x.Op != OpSB && y.Op != OpSB
+ // result: (MOVDaddridx [c] {s} x y)
+ for {
+ 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) {
+ break
+ }
+ v.reset(OpS390XMOVDaddridx)
+ v.AuxInt = c
+ v.Aux = s
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (ADD x (NEG y))
+ // cond:
+ // result: (SUB x y)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpS390XNEG {
+ break
+ }
+ y := v_1.Args[0]
+ 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)
+ // result: (ADDload <t> [off] {sym} x ptr mem)
+ for {
+ t := v.Type
+ x := v.Args[0]
+ g := v.Args[1]
+ if g.Op != OpS390XMOVDload {
+ 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)) {
+ 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> g:(MOVDload [off] {sym} ptr mem) x)
+ // cond: g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)
+ // result: (ADDload <t> [off] {sym} x ptr mem)
+ for {
+ t := v.Type
+ g := v.Args[0]
+ if g.Op != OpS390XMOVDload {
+ 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)) {
+ 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(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ADDW x (MOVDconst [c]))
+ // cond:
+ // result: (ADDWconst [c] x)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpS390XMOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpS390XADDWconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (ADDW (MOVDconst [c]) x)
+ // cond:
+ // result: (ADDWconst [c] x)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpS390XMOVDconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ v.reset(OpS390XADDWconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (ADDW x (NEGW y))
+ // cond:
+ // result: (SUBW x y)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpS390XNEGW {
+ break
+ }
+ y := v_1.Args[0]
+ 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)
+ // result: (ADDWload <t> [off] {sym} x ptr mem)
+ 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)) {
+ 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: g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)
+ // result: (ADDWload <t> [off] {sym} x ptr mem)
+ for {
+ t := v.Type
+ g := v.Args[0]
+ if g.Op != OpS390XMOVWload {
+ 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)) {
+ 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: g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)
+ // result: (ADDWload <t> [off] {sym} x ptr mem)
+ for {
+ t := v.Type
+ x := v.Args[0]
+ g := v.Args[1]
+ if g.Op != OpS390XMOVWZload {
+ 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)) {
+ 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: g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)
+ // result: (ADDWload <t> [off] {sym} x ptr mem)
+ for {
+ t := v.Type
+ g := v.Args[0]
+ if g.Op != OpS390XMOVWZload {
+ 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)) {
+ break
+ }
+ v.reset(OpS390XADDWload)
+ v.Type = t
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(x)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValueS390X_OpS390XADDWconst(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ADDWconst [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: (ADDWconst [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
+ }
+ // match: (ADDWconst [c] (ADDWconst [d] x))
+ // cond:
+ // result: (ADDWconst [int64(int32(c+d))] x)
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpS390XADDWconst {
+ break
+ }
+ d := v_0.AuxInt
+ x := v_0.Args[0]
+ v.reset(OpS390XADDWconst)
+ v.AuxInt = int64(int32(c + d))
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValueS390X_OpS390XADDconst(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ADDconst [c] (MOVDaddr [d] {s} x:(SB)))
+ // cond: ((c+d)&1 == 0) && is32Bit(c+d)
+ // result: (MOVDaddr [c+d] {s} x)
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpS390XMOVDaddr {
+ break
+ }
+ d := v_0.AuxInt
+ s := v_0.Aux
+ x := v_0.Args[0]
+ if x.Op != OpSB {
+ break
+ }
+ if !(((c+d)&1 == 0) && is32Bit(c+d)) {
+ break
+ }
+ v.reset(OpS390XMOVDaddr)
+ v.AuxInt = c + d
+ v.Aux = s
+ v.AddArg(x)
+ return true
+ }
+ // match: (ADDconst [c] (MOVDaddr [d] {s} x))
+ // cond: x.Op != OpSB && is20Bit(c+d)
+ // result: (MOVDaddr [c+d] {s} x)
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpS390XMOVDaddr {
+ break
+ }
+ d := v_0.AuxInt
+ s := v_0.Aux
+ x := v_0.Args[0]
+ if !(x.Op != OpSB && is20Bit(c+d)) {
+ break
+ }
+ v.reset(OpS390XMOVDaddr)
+ v.AuxInt = c + d
+ v.Aux = s
+ v.AddArg(x)
+ return true
+ }
+ // match: (ADDconst [c] (MOVDaddridx [d] {s} x y))
+ // cond: is20Bit(c+d)
+ // result: (MOVDaddridx [c+d] {s} x y)
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpS390XMOVDaddridx {
+ break
+ }
+ d := v_0.AuxInt
+ s := v_0.Aux
+ x := v_0.Args[0]
+ y := v_0.Args[1]
+ if !(is20Bit(c + d)) {
+ break
+ }
+ v.reset(OpS390XMOVDaddridx)
+ v.AuxInt = c + d
+ v.Aux = s
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (ADDconst [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: (ADDconst [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
+ }
+ // match: (ADDconst [c] (ADDconst [d] x))
+ // cond: is32Bit(c+d)
+ // result: (ADDconst [c+d] x)
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpS390XADDconst {
+ break
+ }
+ 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_OpS390XAND(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (AND x (MOVDconst [c]))
+ // cond: is32Bit(c) && c < 0
+ // result: (ANDconst [c] x)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpS390XMOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ if !(is32Bit(c) && c < 0) {
+ break
+ }
+ v.reset(OpS390XANDconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (AND (MOVDconst [c]) x)
+ // cond: is32Bit(c) && c < 0
+ // result: (ANDconst [c] x)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpS390XMOVDconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ if !(is32Bit(c) && c < 0) {
+ break
+ }
+ v.reset(OpS390XANDconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (AND (MOVDconst [0xFF]) x)
+ // cond:
+ // result: (MOVBZreg x)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpS390XMOVDconst {
+ break
+ }
+ if v_0.AuxInt != 0xFF {
+ break
+ }
+ x := v.Args[1]
+ v.reset(OpS390XMOVBZreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (AND x (MOVDconst [0xFF]))
+ // cond:
+ // result: (MOVBZreg x)
+ for {
+ 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 [0xFFFF]) x)
+ // cond:
+ // result: (MOVHZreg x)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpS390XMOVDconst {
+ break
+ }
+ if v_0.AuxInt != 0xFFFF {
+ break
+ }
+ x := v.Args[1]
+ v.reset(OpS390XMOVHZreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (AND x (MOVDconst [0xFFFF]))
+ // cond:
+ // result: (MOVHZreg x)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpS390XMOVDconst {
+ break
+ }
+ if v_1.AuxInt != 0xFFFF {
+ break
+ }
+ v.reset(OpS390XMOVHZreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (AND (MOVDconst [0xFFFFFFFF]) x)
+ // cond:
+ // result: (MOVWZreg x)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpS390XMOVDconst {
+ break
+ }
+ if v_0.AuxInt != 0xFFFFFFFF {
+ break
+ }
+ x := v.Args[1]
+ v.reset(OpS390XMOVWZreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (AND x (MOVDconst [0xFFFFFFFF]))
+ // cond:
+ // result: (MOVWZreg x)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpS390XMOVDconst {
+ break
+ }
+ if v_1.AuxInt != 0xFFFFFFFF {
+ break
+ }
+ v.reset(OpS390XMOVWZreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (AND (MOVDconst [c]) (MOVDconst [d]))
+ // cond:
+ // result: (MOVDconst [c&d])
+ for {
+ 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: (AND 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: (AND <t> x g:(MOVDload [off] {sym} ptr mem))
+ // cond: g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)
+ // result: (ANDload <t> [off] {sym} x ptr mem)
+ for {
+ t := v.Type
+ x := v.Args[0]
+ g := v.Args[1]
+ if g.Op != OpS390XMOVDload {
+ 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)) {
+ 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: (AND <t> g:(MOVDload [off] {sym} ptr mem) x)
+ // cond: g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)
+ // result: (ANDload <t> [off] {sym} x ptr mem)
+ for {
+ t := v.Type
+ g := v.Args[0]
+ if g.Op != OpS390XMOVDload {
+ 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)) {
+ 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(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ANDW x (MOVDconst [c]))
+ // cond:
+ // result: (ANDWconst [c] x)
+ for {
+ 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_0 := v.Args[0]
+ if v_0.Op != OpS390XMOVDconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ v.reset(OpS390XANDWconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (ANDW 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: (ANDW <t> x g:(MOVWload [off] {sym} ptr mem))
+ // cond: g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)
+ // result: (ANDWload <t> [off] {sym} x ptr mem)
+ 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)) {
+ 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: g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)
+ // result: (ANDWload <t> [off] {sym} x ptr mem)
+ for {
+ t := v.Type
+ g := v.Args[0]
+ if g.Op != OpS390XMOVWload {
+ 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)) {
+ 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:(MOVWZload [off] {sym} ptr mem))
+ // cond: g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)
+ // result: (ANDWload <t> [off] {sym} x ptr mem)
+ for {
+ t := v.Type
+ x := v.Args[0]
+ g := v.Args[1]
+ if g.Op != OpS390XMOVWZload {
+ 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)) {
+ 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: g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)
+ // result: (ANDWload <t> [off] {sym} x ptr mem)
+ for {
+ t := v.Type
+ g := v.Args[0]
+ if g.Op != OpS390XMOVWZload {
+ 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)) {
+ 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(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ANDWconst [c] (ANDWconst [d] x))
+ // cond:
+ // result: (ANDWconst [c & d] x)
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpS390XANDWconst {
+ break
+ }
+ d := v_0.AuxInt
+ x := v_0.Args[0]
+ v.reset(OpS390XANDWconst)
+ v.AuxInt = c & d
+ v.AddArg(x)
+ return true
+ }
+ // match: (ANDWconst [0xFF] x)
+ // cond:
+ // result: (MOVBZreg x)
+ for {
+ if v.AuxInt != 0xFF {
+ break
+ }
+ x := v.Args[0]
+ v.reset(OpS390XMOVBZreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (ANDWconst [0xFFFF] x)
+ // cond:
+ // result: (MOVHZreg x)
+ for {
+ if v.AuxInt != 0xFFFF {
+ break
+ }
+ x := v.Args[0]
+ v.reset(OpS390XMOVHZreg)
+ v.AddArg(x)
+ return true
+ }
+ // match: (ANDWconst [c] _)
+ // cond: int32(c)==0
+ // result: (MOVDconst [0])
+ for {
+ c := v.AuxInt
+ if !(int32(c) == 0) {
+ break
+ }
+ v.reset(OpS390XMOVDconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (ANDWconst [c] x)
+ // cond: int32(c)==-1
+ // result: x
+ for {
+ c := v.AuxInt
+ x := v.Args[0]
+ if !(int32(c) == -1) {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ // match: (ANDWconst [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_OpS390XANDconst(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ANDconst [c] (ANDconst [d] x))
+ // cond:
+ // result: (ANDconst [c & d] x)
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpS390XANDconst {
+ break
+ }
+ d := v_0.AuxInt
+ x := v_0.Args[0]
+ v.reset(OpS390XANDconst)
+ v.AuxInt = c & d
+ v.AddArg(x)
+ return true
+ }
+ // match: (ANDconst [0] _)
+ // cond:
+ // result: (MOVDconst [0])
+ for {
+ if v.AuxInt != 0 {
+ break
+ }
+ v.reset(OpS390XMOVDconst)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (ANDconst [-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: (ANDconst [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_OpS390XCMP(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (CMP x (MOVDconst [c]))
+ // cond: is32Bit(c)
+ // result: (CMPconst x [c])
+ for {
+ 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(OpS390XCMPconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (CMP (MOVDconst [c]) x)
+ // cond: is32Bit(c)
+ // result: (InvertFlags (CMPconst x [c]))
+ for {
+ 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(OpS390XInvertFlags)
+ v0 := b.NewValue0(v.Line, OpS390XCMPconst, TypeFlags)
+ v0.AuxInt = c
+ v0.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+ return false
+}
+func rewriteValueS390X_OpS390XCMPU(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (CMPU x (MOVDconst [c]))
+ // cond: is32Bit(c)
+ // result: (CMPUconst x [int64(uint32(c))])
+ for {
+ 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(OpS390XCMPUconst)
+ v.AuxInt = int64(uint32(c))
+ v.AddArg(x)
+ return true
+ }
+ // match: (CMPU (MOVDconst [c]) x)
+ // cond: is32Bit(c)
+ // result: (InvertFlags (CMPUconst x [int64(uint32(c))]))
+ for {
+ 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(OpS390XInvertFlags)
+ v0 := b.NewValue0(v.Line, OpS390XCMPUconst, TypeFlags)
+ v0.AuxInt = int64(uint32(c))
+ v0.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+ return false
+}
+func rewriteValueS390X_OpS390XCMPUconst(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (CMPUconst (MOVDconst [x]) [y])
+ // cond: uint64(x)==uint64(y)
+ // result: (FlagEQ)
+ for {
+ y := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpS390XMOVDconst {
+ break
+ }
+ x := v_0.AuxInt
+ if !(uint64(x) == uint64(y)) {
+ break
+ }
+ v.reset(OpS390XFlagEQ)
+ return true
+ }
+ // match: (CMPUconst (MOVDconst [x]) [y])
+ // cond: uint64(x)<uint64(y)
+ // result: (FlagLT)
+ for {
+ y := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpS390XMOVDconst {
+ break
+ }
+ x := v_0.AuxInt
+ if !(uint64(x) < uint64(y)) {
+ break
+ }
+ v.reset(OpS390XFlagLT)
+ return true
+ }
+ // match: (CMPUconst (MOVDconst [x]) [y])
+ // cond: uint64(x)>uint64(y)
+ // result: (FlagGT)
+ for {
+ y := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpS390XMOVDconst {
+ break
+ }
+ x := v_0.AuxInt
+ if !(uint64(x) > uint64(y)) {
+ break
+ }
+ v.reset(OpS390XFlagGT)
+ return true
+ }
+ return false
+}
+func rewriteValueS390X_OpS390XCMPW(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (CMPW x (MOVDconst [c]))
+ // cond:
+ // result: (CMPWconst x [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpS390XMOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpS390XCMPWconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (CMPW (MOVDconst [c]) x)
+ // cond:
+ // result: (InvertFlags (CMPWconst x [c]))
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpS390XMOVDconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ v.reset(OpS390XInvertFlags)
+ v0 := b.NewValue0(v.Line, OpS390XCMPWconst, TypeFlags)
+ v0.AuxInt = c
+ v0.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+ return false
+}
+func rewriteValueS390X_OpS390XCMPWU(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (CMPWU x (MOVDconst [c]))
+ // cond:
+ // result: (CMPWUconst x [int64(uint32(c))])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpS390XMOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpS390XCMPWUconst)
+ v.AuxInt = int64(uint32(c))
+ v.AddArg(x)
+ return true
+ }
+ // match: (CMPWU (MOVDconst [c]) x)
+ // cond:
+ // result: (InvertFlags (CMPWUconst x [int64(uint32(c))]))
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpS390XMOVDconst {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ v.reset(OpS390XInvertFlags)
+ v0 := b.NewValue0(v.Line, OpS390XCMPWUconst, TypeFlags)
+ v0.AuxInt = int64(uint32(c))
+ v0.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+ return false
+}
+func rewriteValueS390X_OpS390XCMPWUconst(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (CMPWUconst (MOVDconst [x]) [y])
+ // cond: uint32(x)==uint32(y)
+ // result: (FlagEQ)
+ for {
+ y := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpS390XMOVDconst {
+ break
+ }
+ x := v_0.AuxInt
+ if !(uint32(x) == uint32(y)) {
+ break
+ }
+ v.reset(OpS390XFlagEQ)
+ return true
+ }
+ // match: (CMPWUconst (MOVDconst [x]) [y])
+ // cond: uint32(x)<uint32(y)
+ // result: (FlagLT)
+ for {
+ y := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpS390XMOVDconst {
+ break
+ }
+ x := v_0.AuxInt
+ if !(uint32(x) < uint32(y)) {
+ break
+ }
+ v.reset(OpS390XFlagLT)
+ return true
+ }
+ // match: (CMPWUconst (MOVDconst [x]) [y])
+ // cond: uint32(x)>uint32(y)
+ // result: (FlagGT)
+ for {
+ y := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpS390XMOVDconst {
+ break
+ }
+ x := v_0.AuxInt
+ if !(uint32(x) > uint32(y)) {
+ break
+ }
+ v.reset(OpS390XFlagGT)
+ return true
+ }
+ return false
+}
+func rewriteValueS390X_OpS390XCMPWconst(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (CMPWconst (MOVDconst [x]) [y])
+ // cond: int32(x)==int32(y)
+ // result: (FlagEQ)
+ for {
+ y := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpS390XMOVDconst {
+ break
+ }
+ x := v_0.AuxInt
+ if !(int32(x) == int32(y)) {
+ break
+ }
+ v.reset(OpS390XFlagEQ)
+ return true
+ }
+ // match: (CMPWconst (MOVDconst [x]) [y])
+ // cond: int32(x)<int32(y)
+ // result: (FlagLT)
+ for {
+ y := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpS390XMOVDconst {
+ break
+ }
+ x := v_0.AuxInt
+ if !(int32(x) < int32(y)) {
+ break
+ }
+ v.reset(OpS390XFlagLT)
+ return true
+ }
+ // match: (CMPWconst (MOVDconst [x]) [y])
+ // cond: int32(x)>int32(y)
+ // result: (FlagGT)
+ for {
+ y := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpS390XMOVDconst {
+ break
+ }
+ x := v_0.AuxInt
+ if !(int32(x) > int32(y)) {
+ break
+ }
+ v.reset(OpS390XFlagGT)
+ return true
+ }
+ // match: (CMPWconst (SRWconst _ [c]) [n])
+ // cond: 0 <= n && 0 < c && c <= 32 && (1<<uint64(32-c)) <= uint64(n)
+ // result: (FlagLT)
+ for {
+ n := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpS390XSRWconst {
+ break
+ }
+ c := v_0.AuxInt
+ if !(0 <= n && 0 < c && c <= 32 && (1<<uint64(32-c)) <= uint64(n)) {
+ break
+ }
+ v.reset(OpS390XFlagLT)
+ return true
+ }
+ // match: (CMPWconst (ANDWconst _ [m]) [n])
+ // cond: 0 <= int32(m) && int32(m) < int32(n)
+ // result: (FlagLT)
+ for {
+ n := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpS390XANDWconst {
+ break
+ }
+ m := v_0.AuxInt
+ if !(0 <= int32(m) && int32(m) < int32(n)) {
+ break
+ }
+ v.reset(OpS390XFlagLT)
+ return true
+ }
+ return false
+}
+func rewriteValueS390X_OpS390XCMPconst(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (CMPconst (MOVDconst [x]) [y])
+ // cond: x==y
+ // result: (FlagEQ)
+ for {
+ y := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpS390XMOVDconst {
+ break
+ }
+ x := v_0.AuxInt
+ if !(x == y) {
+ break
+ }
+ v.reset(OpS390XFlagEQ)
+ return true
+ }
+ // match: (CMPconst (MOVDconst [x]) [y])
+ // cond: x<y
+ // result: (FlagLT)
+ for {
+ y := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpS390XMOVDconst {
+ break
+ }
+ x := v_0.AuxInt
+ if !(x < y) {
+ break
+ }
+ v.reset(OpS390XFlagLT)
+ return true
+ }
+ // match: (CMPconst (MOVDconst [x]) [y])
+ // cond: x>y
+ // result: (FlagGT)
+ for {
+ y := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpS390XMOVDconst {
+ break
+ }
+ x := v_0.AuxInt
+ if !(x > y) {
+ break
+ }
+ v.reset(OpS390XFlagGT)
+ return true
+ }
+ // match: (CMPconst (MOVBZreg _) [c])
+ // cond: 0xFF < c
+ // result: (FlagLT)
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpS390XMOVBZreg {
+ break
+ }
+ if !(0xFF < c) {
+ break
+ }
+ v.reset(OpS390XFlagLT)
+ return true
+ }
+ // match: (CMPconst (MOVHZreg _) [c])
+ // cond: 0xFFFF < c
+ // result: (FlagLT)
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpS390XMOVHZreg {
+ break
+ }
+ if !(0xFFFF < c) {
+ break
+ }
+ v.reset(OpS390XFlagLT)
+ return true
+ }
+ // match: (CMPconst (MOVWZreg _) [c])
+ // cond: 0xFFFFFFFF < c
+ // result: (FlagLT)
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpS390XMOVWZreg {
+ break
+ }
+ if !(0xFFFFFFFF < c) {
+ break
+ }
+ v.reset(OpS390XFlagLT)
+ return true
+ }
+ // match: (CMPconst (SRDconst _ [c]) [n])
+ // cond: 0 <= n && 0 < c && c <= 64 && (1<<uint64(64-c)) <= uint64(n)
+ // result: (FlagLT)
+ for {
+ n := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpS390XSRDconst {
+ break
+ }
+ c := v_0.AuxInt
+ if !(0 <= n && 0 < c && c <= 64 && (1<<uint64(64-c)) <= uint64(n)) {
+ break
+ }
+ v.reset(OpS390XFlagLT)
+ return true
+ }
+ // match: (CMPconst (ANDconst _ [m]) [n])
+ // cond: 0 <= m && m < n
+ // result: (FlagLT)
+ for {
+ n := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpS390XANDconst {
+ break
+ }
+ m := v_0.AuxInt
+ if !(0 <= m && m < n) {
+ break
+ }
+ v.reset(OpS390XFlagLT)
+ return true
+ }
+ return false
+}
+func rewriteValueS390X_OpS390XFMOVDload(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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_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(OpS390XFMOVDload)
+ v.AuxInt = off1 + off2
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (FMOVDload [off1] {sym1} (MOVDaddr [off2] {sym2} base) mem)
+ // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+ // result: (FMOVDload [off1+off2] {mergeSym(sym1,sym2)} base mem)
+ for {
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ 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(OpS390XFMOVDload)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(base)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (FMOVDload [off1] {sym1} (MOVDaddridx [off2] {sym2} ptr idx) mem)
+ // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+ // result: (FMOVDloadidx [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 {
+ 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(OpS390XFMOVDloadidx)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (FMOVDload [off] {sym} (ADD ptr idx) mem)
+ // cond: ptr.Op != OpSB
+ // result: (FMOVDloadidx [off] {sym} ptr idx mem)
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpS390XADD {
+ break
+ }
+ ptr := v_0.Args[0]
+ idx := v_0.Args[1]
+ mem := v.Args[1]
+ if !(ptr.Op != OpSB) {
+ break
+ }
+ v.reset(OpS390XFMOVDloadidx)
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValueS390X_OpS390XFMOVDloadidx(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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_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(OpS390XFMOVDloadidx)
+ v.AuxInt = c + d
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (FMOVDloadidx [c] {sym} ptr (ADDconst [d] idx) mem)
+ // cond:
+ // result: (FMOVDloadidx [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 {
+ break
+ }
+ d := v_1.AuxInt
+ idx := v_1.Args[0]
+ mem := v.Args[2]
+ v.reset(OpS390XFMOVDloadidx)
+ v.AuxInt = c + d
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValueS390X_OpS390XFMOVDstore(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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_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(OpS390XFMOVDstore)
+ v.AuxInt = off1 + off2
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (FMOVDstore [off1] {sym1} (MOVDaddr [off2] {sym2} base) val mem)
+ // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+ // result: (FMOVDstore [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 {
+ 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(OpS390XFMOVDstore)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(base)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (FMOVDstore [off1] {sym1} (MOVDaddridx [off2] {sym2} ptr idx) val mem)
+ // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+ // result: (FMOVDstoreidx [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 {
+ break
+ }
+ off2 := v_0.AuxInt
+ sym2 := v_0.Aux
+ ptr := v_0.Args[0]
+ idx := v_0.Args[1]
+ val := v.Args[1]
+ mem := v.Args[2]
+ if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
+ break
+ }
+ v.reset(OpS390XFMOVDstoreidx)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (FMOVDstore [off] {sym} (ADD ptr idx) val mem)
+ // cond: ptr.Op != OpSB
+ // result: (FMOVDstoreidx [off] {sym} ptr idx val mem)
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpS390XADD {
+ break
+ }
+ ptr := v_0.Args[0]
+ idx := v_0.Args[1]
+ val := v.Args[1]
+ mem := v.Args[2]
+ if !(ptr.Op != OpSB) {
+ break
+ }
+ v.reset(OpS390XFMOVDstoreidx)
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValueS390X_OpS390XFMOVDstoreidx(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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_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(OpS390XFMOVDstoreidx)
+ v.AuxInt = c + d
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (FMOVDstoreidx [c] {sym} ptr (ADDconst [d] idx) val mem)
+ // cond:
+ // result: (FMOVDstoreidx [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 {
+ break
+ }
+ d := v_1.AuxInt
+ idx := v_1.Args[0]
+ val := v.Args[2]
+ mem := v.Args[3]
+ v.reset(OpS390XFMOVDstoreidx)
+ 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_OpS390XFMOVSload(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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_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(OpS390XFMOVSload)
+ v.AuxInt = off1 + off2
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (FMOVSload [off1] {sym1} (MOVDaddr [off2] {sym2} base) mem)
+ // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+ // result: (FMOVSload [off1+off2] {mergeSym(sym1,sym2)} base mem)
+ for {
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ 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(OpS390XFMOVSload)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(base)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (FMOVSload [off1] {sym1} (MOVDaddridx [off2] {sym2} ptr idx) mem)
+ // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+ // result: (FMOVSloadidx [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 {
+ 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(OpS390XFMOVSloadidx)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (FMOVSload [off] {sym} (ADD ptr idx) mem)
+ // cond: ptr.Op != OpSB
+ // result: (FMOVSloadidx [off] {sym} ptr idx mem)
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpS390XADD {
+ break
+ }
+ ptr := v_0.Args[0]
+ idx := v_0.Args[1]
+ mem := v.Args[1]
+ if !(ptr.Op != OpSB) {
+ break
+ }
+ v.reset(OpS390XFMOVSloadidx)
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValueS390X_OpS390XFMOVSloadidx(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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_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(OpS390XFMOVSloadidx)
+ v.AuxInt = c + d
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (FMOVSloadidx [c] {sym} ptr (ADDconst [d] idx) mem)
+ // cond:
+ // result: (FMOVSloadidx [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 {
+ break
+ }
+ d := v_1.AuxInt
+ idx := v_1.Args[0]
+ mem := v.Args[2]
+ v.reset(OpS390XFMOVSloadidx)
+ v.AuxInt = c + d
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValueS390X_OpS390XFMOVSstore(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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_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(OpS390XFMOVSstore)
+ v.AuxInt = off1 + off2
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (FMOVSstore [off1] {sym1} (MOVDaddr [off2] {sym2} base) val mem)
+ // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+ // result: (FMOVSstore [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 {
+ 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(OpS390XFMOVSstore)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(base)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (FMOVSstore [off1] {sym1} (MOVDaddridx [off2] {sym2} ptr idx) val mem)
+ // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+ // result: (FMOVSstoreidx [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 {
+ break
+ }
+ off2 := v_0.AuxInt
+ sym2 := v_0.Aux
+ ptr := v_0.Args[0]
+ idx := v_0.Args[1]
+ val := v.Args[1]
+ mem := v.Args[2]
+ if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
+ break
+ }
+ v.reset(OpS390XFMOVSstoreidx)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (FMOVSstore [off] {sym} (ADD ptr idx) val mem)
+ // cond: ptr.Op != OpSB
+ // result: (FMOVSstoreidx [off] {sym} ptr idx val mem)
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpS390XADD {
+ break
+ }
+ ptr := v_0.Args[0]
+ idx := v_0.Args[1]
+ val := v.Args[1]
+ mem := v.Args[2]
+ if !(ptr.Op != OpSB) {
+ break
+ }
+ v.reset(OpS390XFMOVSstoreidx)
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValueS390X_OpS390XFMOVSstoreidx(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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_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(OpS390XFMOVSstoreidx)
+ v.AuxInt = c + d
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (FMOVSstoreidx [c] {sym} ptr (ADDconst [d] idx) val mem)
+ // cond:
+ // result: (FMOVSstoreidx [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 {
+ break
+ }
+ d := v_1.AuxInt
+ idx := v_1.Args[0]
+ val := v.Args[2]
+ mem := v.Args[3]
+ v.reset(OpS390XFMOVSstoreidx)
+ 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_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: x
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpS390XMOVBstore {
+ break
+ }
+ off2 := v_1.AuxInt
+ sym2 := v_1.Aux
+ ptr2 := v_1.Args[0]
+ x := v_1.Args[1]
+ if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ // match: (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_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(OpS390XMOVBZload)
+ v.AuxInt = off1 + off2
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // 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_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(OpS390XMOVBZload)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(base)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVBZload [off1] {sym1} (MOVDaddridx [off2] {sym2} ptr idx) mem)
+ // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+ // result: (MOVBZloadidx [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 {
+ 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(OpS390XMOVBZloadidx)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVBZload [off] {sym} (ADD ptr idx) mem)
+ // cond: ptr.Op != OpSB
+ // result: (MOVBZloadidx [off] {sym} ptr idx mem)
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpS390XADD {
+ break
+ }
+ ptr := v_0.Args[0]
+ idx := v_0.Args[1]
+ mem := v.Args[1]
+ if !(ptr.Op != OpSB) {
+ break
+ }
+ v.reset(OpS390XMOVBZloadidx)
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValueS390X_OpS390XMOVBZloadidx(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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_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(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
+ 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(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
+ // match: (MOVBZreg x:(MOVDLT (MOVDconst [c]) (MOVDconst [d]) _))
+ // cond: int64(uint8(c)) == c && int64(uint8(d)) == d
+ // result: x
+ for {
+ x := v.Args[0]
+ if x.Op != OpS390XMOVDLT {
+ break
+ }
+ x_0 := x.Args[0]
+ if x_0.Op != OpS390XMOVDconst {
+ break
+ }
+ c := x_0.AuxInt
+ x_1 := x.Args[1]
+ if x_1.Op != OpS390XMOVDconst {
+ break
+ }
+ d := x_1.AuxInt
+ if !(int64(uint8(c)) == c && int64(uint8(d)) == d) {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVBZreg x:(MOVDLE (MOVDconst [c]) (MOVDconst [d]) _))
+ // cond: int64(uint8(c)) == c && int64(uint8(d)) == d
+ // result: x
+ for {
+ x := v.Args[0]
+ if x.Op != OpS390XMOVDLE {
+ break
+ }
+ x_0 := x.Args[0]
+ if x_0.Op != OpS390XMOVDconst {
+ break
+ }
+ c := x_0.AuxInt
+ x_1 := x.Args[1]
+ if x_1.Op != OpS390XMOVDconst {
+ break
+ }
+ d := x_1.AuxInt
+ if !(int64(uint8(c)) == c && int64(uint8(d)) == d) {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVBZreg x:(MOVDGT (MOVDconst [c]) (MOVDconst [d]) _))
+ // cond: int64(uint8(c)) == c && int64(uint8(d)) == d
+ // result: x
+ for {
+ x := v.Args[0]
+ if x.Op != OpS390XMOVDGT {
+ break
+ }
+ x_0 := x.Args[0]
+ if x_0.Op != OpS390XMOVDconst {
+ break
+ }
+ c := x_0.AuxInt
+ x_1 := x.Args[1]
+ if x_1.Op != OpS390XMOVDconst {
+ break
+ }
+ d := x_1.AuxInt
+ if !(int64(uint8(c)) == c && int64(uint8(d)) == d) {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVBZreg x:(MOVDGE (MOVDconst [c]) (MOVDconst [d]) _))
+ // cond: int64(uint8(c)) == c && int64(uint8(d)) == d
+ // result: x
+ for {
+ x := v.Args[0]
+ if x.Op != OpS390XMOVDGE {
+ break
+ }
+ x_0 := x.Args[0]
+ if x_0.Op != OpS390XMOVDconst {
+ break
+ }
+ c := x_0.AuxInt
+ x_1 := x.Args[1]
+ if x_1.Op != OpS390XMOVDconst {
+ break
+ }
+ d := x_1.AuxInt
+ if !(int64(uint8(c)) == c && int64(uint8(d)) == d) {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVBZreg x:(MOVDEQ (MOVDconst [c]) (MOVDconst [d]) _))
+ // cond: int64(uint8(c)) == c && int64(uint8(d)) == d
+ // result: x
+ for {
+ x := v.Args[0]
+ if x.Op != OpS390XMOVDEQ {
+ break
+ }
+ x_0 := x.Args[0]
+ if x_0.Op != OpS390XMOVDconst {
+ break
+ }
+ c := x_0.AuxInt
+ x_1 := x.Args[1]
+ if x_1.Op != OpS390XMOVDconst {
+ break
+ }
+ d := x_1.AuxInt
+ if !(int64(uint8(c)) == c && int64(uint8(d)) == d) {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVBZreg x:(MOVDNE (MOVDconst [c]) (MOVDconst [d]) _))
+ // cond: int64(uint8(c)) == c && int64(uint8(d)) == d
+ // result: x
+ for {
+ x := v.Args[0]
+ if x.Op != OpS390XMOVDNE {
+ break
+ }
+ x_0 := x.Args[0]
+ if x_0.Op != OpS390XMOVDconst {
+ break
+ }
+ c := x_0.AuxInt
+ x_1 := x.Args[1]
+ if x_1.Op != OpS390XMOVDconst {
+ break
+ }
+ d := x_1.AuxInt
+ if !(int64(uint8(c)) == c && int64(uint8(d)) == d) {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVBZreg x:(MOVDGTnoinv (MOVDconst [c]) (MOVDconst [d]) _))
+ // cond: int64(uint8(c)) == c && int64(uint8(d)) == d
+ // result: x
+ for {
+ x := v.Args[0]
+ if x.Op != OpS390XMOVDGTnoinv {
+ break
+ }
+ x_0 := x.Args[0]
+ if x_0.Op != OpS390XMOVDconst {
+ break
+ }
+ c := x_0.AuxInt
+ x_1 := x.Args[1]
+ if x_1.Op != OpS390XMOVDconst {
+ break
+ }
+ d := x_1.AuxInt
+ if !(int64(uint8(c)) == c && int64(uint8(d)) == d) {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVBZreg x:(MOVDGEnoinv (MOVDconst [c]) (MOVDconst [d]) _))
+ // cond: int64(uint8(c)) == c && int64(uint8(d)) == d
+ // result: x
+ for {
+ x := v.Args[0]
+ if x.Op != OpS390XMOVDGEnoinv {
+ break
+ }
+ x_0 := x.Args[0]
+ if x_0.Op != OpS390XMOVDconst {
+ break
+ }
+ c := x_0.AuxInt
+ x_1 := x.Args[1]
+ if x_1.Op != OpS390XMOVDconst {
+ break
+ }
+ d := x_1.AuxInt
+ if !(int64(uint8(c)) == c && int64(uint8(d)) == d) {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVBZreg x:(MOVBZload _ _))
+ // cond:
+ // result: x
+ for {
+ x := v.Args[0]
+ if x.Op != OpS390XMOVBZload {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVBZreg x:(Arg <t>))
+ // cond: is8BitInt(t) && !isSigned(t)
+ // result: x
+ for {
+ x := v.Args[0]
+ if x.Op != OpArg {
+ break
+ }
+ t := x.Type
+ if !(is8BitInt(t) && !isSigned(t)) {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVBZreg x:(MOVBZreg _))
+ // cond:
+ // result: x
+ for {
+ x := v.Args[0]
+ if x.Op != OpS390XMOVBZreg {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVBZreg (MOVDconst [c]))
+ // cond:
+ // result: (MOVDconst [int64(uint8(c))])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpS390XMOVDconst {
+ break
+ }
+ c := v_0.AuxInt
+ v.reset(OpS390XMOVDconst)
+ v.AuxInt = int64(uint8(c))
+ return true
+ }
+ // match: (MOVBZreg x:(MOVBZload [off] {sym} ptr mem))
+ // cond: x.Uses == 1 && clobber(x)
+ // result: @x.Block (MOVBZload <v.Type> [off] {sym} ptr mem)
+ for {
+ x := v.Args[0]
+ if x.Op != OpS390XMOVBZload {
+ 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, OpS390XMOVBZload, v.Type)
+ v.reset(OpCopy)
+ v.AddArg(v0)
+ v0.AuxInt = off
+ v0.Aux = sym
+ v0.AddArg(ptr)
+ v0.AddArg(mem)
+ return true
+ }
+ // match: (MOVBZreg x:(MOVBZloadidx [off] {sym} ptr idx mem))
+ // cond: x.Uses == 1 && clobber(x)
+ // result: @x.Block (MOVBZloadidx <v.Type> [off] {sym} ptr idx mem)
+ for {
+ x := v.Args[0]
+ if x.Op != OpS390XMOVBZloadidx {
+ 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, OpS390XMOVBZloadidx, 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_OpS390XMOVBload(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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_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(OpS390XMOVBload)
+ v.AuxInt = off1 + off2
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVBload [off1] {sym1} (MOVDaddr [off2] {sym2} base) mem)
+ // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+ // result: (MOVBload [off1+off2] {mergeSym(sym1,sym2)} base mem)
+ for {
+ off1 := v.AuxInt
+ sym1 := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != 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(OpS390XMOVBload)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(base)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValueS390X_OpS390XMOVBreg(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (MOVBreg x:(MOVBload _ _))
+ // cond:
+ // result: x
+ for {
+ x := v.Args[0]
+ if x.Op != OpS390XMOVBload {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVBreg x:(Arg <t>))
+ // cond: is8BitInt(t) && isSigned(t)
+ // result: x
+ for {
+ x := v.Args[0]
+ if x.Op != OpArg {
+ break
+ }
+ t := x.Type
+ if !(is8BitInt(t) && isSigned(t)) {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVBreg x:(MOVBreg _))
+ // cond:
+ // result: x
+ for {
+ x := v.Args[0]
+ if x.Op != OpS390XMOVBreg {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVBreg (MOVDconst [c]))
+ // cond:
+ // result: (MOVDconst [int64(int8(c))])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpS390XMOVDconst {
+ break
+ }
+ c := v_0.AuxInt
+ v.reset(OpS390XMOVDconst)
+ v.AuxInt = int64(int8(c))
+ return true
+ }
+ // match: (MOVBreg x:(MOVBZload [off] {sym} ptr mem))
+ // cond: x.Uses == 1 && clobber(x)
+ // result: @x.Block (MOVBload <v.Type> [off] {sym} ptr mem)
+ for {
+ x := v.Args[0]
+ if x.Op != OpS390XMOVBZload {
+ 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, OpS390XMOVBload, 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_OpS390XMOVBstore(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (MOVBstore [off] {sym} ptr (MOVBreg x) mem)
+ // cond:
+ // result: (MOVBstore [off] {sym} ptr x mem)
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpS390XMOVBreg {
+ break
+ }
+ x := v_1.Args[0]
+ mem := v.Args[2]
+ v.reset(OpS390XMOVBstore)
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(x)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVBstore [off] {sym} ptr (MOVBZreg x) mem)
+ // cond:
+ // result: (MOVBstore [off] {sym} ptr x mem)
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpS390XMOVBZreg {
+ break
+ }
+ x := v_1.Args[0]
+ mem := v.Args[2]
+ v.reset(OpS390XMOVBstore)
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(x)
+ v.AddArg(mem)
+ return true
+ }
+ // 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_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(OpS390XMOVBstore)
+ v.AuxInt = off1 + off2
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVBstore [off] {sym} ptr (MOVDconst [c]) mem)
+ // cond: validOff(off) && ptr.Op != OpSB
+ // result: (MOVBstoreconst [makeValAndOff(int64(int8(c)),off)] {sym} ptr mem)
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpS390XMOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ mem := v.Args[2]
+ if !(validOff(off) && ptr.Op != OpSB) {
+ break
+ }
+ v.reset(OpS390XMOVBstoreconst)
+ v.AuxInt = makeValAndOff(int64(int8(c)), off)
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // 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_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(OpS390XMOVBstore)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(base)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVBstore [off1] {sym1} (MOVDaddridx [off2] {sym2} ptr idx) val mem)
+ // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
+ // result: (MOVBstoreidx [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 {
+ break
+ }
+ off2 := v_0.AuxInt
+ sym2 := v_0.Aux
+ ptr := v_0.Args[0]
+ idx := v_0.Args[1]
+ val := v.Args[1]
+ mem := v.Args[2]
+ if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
+ break
+ }
+ v.reset(OpS390XMOVBstoreidx)
+ v.AuxInt = off1 + off2
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVBstore [off] {sym} (ADD ptr idx) val mem)
+ // cond: ptr.Op != OpSB
+ // result: (MOVBstoreidx [off] {sym} ptr idx val mem)
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpS390XADD {
+ break
+ }
+ ptr := v_0.Args[0]
+ idx := v_0.Args[1]
+ val := v.Args[1]
+ mem := v.Args[2]
+ if !(ptr.Op != OpSB) {
+ break
+ }
+ v.reset(OpS390XMOVBstoreidx)
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(ptr)
+ v.AddArg(idx)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVBstore [i] {s} p w x:(MOVBstore [i-1] {s} p (SRDconst [8] w) mem))
+ // cond: p.Op != OpSB && x.Uses == 1 && clobber(x)
+ // result: (MOVHstore [i-1] {s} p w mem)
+ for {
+ i := v.AuxInt
+ s := v.Aux
+ p := v.Args[0]
+ w := v.Args[1]
+ x := v.Args[2]
+ if x.Op != OpS390XMOVBstore {
+ break
+ }
+ if x.AuxInt != i-1 {
+ break
+ }
+ if x.Aux != s {
+ break
+ }
+ if p != x.Args[0] {
+ break
+ }
+ x_1 := x.Args[1]
+ if x_1.Op != OpS390XSRDconst {
+ break
+ }
+ if x_1.AuxInt != 8 {
+ break
+ }
+ if w != x_1.Args[0] {
+ break
+ }
+ mem := x.Args[2]
+ if !(p.Op != OpSB && x.Uses == 1 && clobber(x)) {
+ break
+ }
+ v.reset(OpS390XMOVHstore)
+ v.AuxInt = i - 1
+ v.Aux = s
+ v.AddArg(p)
+ v.AddArg(w)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVBstore [i] {s} p w0:(SRDconst [j] w) x:(MOVBstore [i-1] {s} p (SRDconst [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
+ 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 != OpS390XMOVBstore {
+ break
+ }
+ if x.AuxInt != i-1 {
+ break
+ }
+ if x.Aux != s {
+ break
+ }
+ if p != x.Args[0] {
+ break
+ }
+ x_1 := x.Args[1]
+ if x_1.Op != OpS390XSRDconst {
+ break
+ }
+ if x_1.AuxInt != j+8 {
+ break
+ }
+ if w != x_1.Args[0] {
+ break
+ }
+ mem := x.Args[2]
+ if !(p.Op != OpSB && x.Uses == 1 && clobber(x)) {
+ break
+ }
+ v.reset(OpS390XMOVHstore)
+ v.AuxInt = i - 1
+ v.Aux = s
+ v.AddArg(p)
+ v.AddArg(w0)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVBstore [i] {s} p w x:(MOVBstore [i-1] {s} p (SRWconst [8] w) mem))
+ // cond: p.Op != OpSB && x.Uses == 1 && clobber(x)
+ // result: (MOVHstore [i-1] {s} p w mem)
+ for {
+ i := v.AuxInt
+ s := v.Aux
+ p := v.Args[0]
+ w := v.Args[1]
+ x := v.Args[2]
+ if x.Op != OpS390XMOVBstore {
+ break
+ }
+ if x.AuxInt != i-1 {
+ break
+ }
+ if x.Aux != s {
+ break
+ }
+ if p != x.Args[0] {
+ break
+ }
+ x_1 := x.Args[1]
+ if x_1.Op != OpS390XSRWconst {
+ break
+ }
+ if x_1.AuxInt != 8 {
+ break
+ }
+ if w != x_1.Args[0] {
+ break
+ }
+ mem := x.Args[2]
+ if !(p.Op != OpSB && x.Uses == 1 && clobber(x)) {
+ break
+ }
+ v.reset(OpS390XMOVHstore)
+ v.AuxInt = i - 1
+ v.Aux = s
+ v.AddArg(p)
+ v.AddArg(w)
+ v.AddArg(mem)
+ return true
+ }
+ // 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
+ 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 != OpS390XMOVBstore {
+ break
+ }
+ if x.AuxInt != i-1 {
+ break
+ }
+ if x.Aux != s {
+ break
+ }
+ if p != x.Args[0] {
+ break
+ }
+ x_1 := x.Args[1]
+ if x_1.Op != OpS390XSRWconst {
+ break
+ }
+ if x_1.AuxInt != j+8 {
+ break
+ }
+ if w != x_1.Args[0] {
+ break
+ }
+ mem := x.Args[2]
+ if !(p.Op != OpSB && x.Uses == 1 && clobber(x)) {
+ break
+ }
+ v.reset(OpS390XMOVHstore)
+ v.AuxInt = i - 1
+ v.Aux = s
+ v.AddArg(p)
+ v.AddArg(w0)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVBstore [i] {s} p (SRDconst [8] w) x:(MOVBstore [i-1] {s} p w mem))
+ // cond: p.Op != OpSB && x.Uses == 1 && clobber(x)
+ // result: (MOVHBRstore [i-1] {s} p w mem)
+ for {
+ i := v.AuxInt
+ s := v.Aux
+ p := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpS390XSRDconst {
+ break
+ }
+ if v_1.AuxInt != 8 {
+ break
+ }
+ w := v_1.Args[0]
+ x := v.Args[2]
+ if x.Op != OpS390XMOVBstore {
+ break
+ }
+ if x.AuxInt != i-1 {
+ break
+ }
+ if x.Aux != s {
+ break
+ }
+ if p != x.Args[0] {
+ break
+ }
+ if w != x.Args[1] {
+ break
+ }
+ mem := x.Args[2]
+ if !(p.Op != OpSB && x.Uses == 1 && clobber(x)) {
+ break
+ }
+ v.reset(OpS390XMOVHBRstore)
+ v.AuxInt = i - 1
+ v.Aux = s
+ v.AddArg(p)
+ v.AddArg(w)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVBstore [i] {s} p (SRDconst [j] w) x:(MOVBstore [i-1] {s} p w0:(SRDconst [j-8] w) mem))
+ // cond: p.Op != OpSB && x.Uses == 1 && clobber(x)
+ // result: (MOVHBRstore [i-1] {s} p w0 mem)
+ for {
+ i := v.AuxInt
+ s := v.Aux
+ p := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpS390XSRDconst {
+ break
+ }
+ j := v_1.AuxInt
+ w := v_1.Args[0]
+ x := v.Args[2]
+ if x.Op != OpS390XMOVBstore {
+ break
+ }
+ if x.AuxInt != i-1 {
+ break
+ }
+ if x.Aux != s {
+ break
+ }
+ if p != x.Args[0] {
+ break
+ }
+ w0 := x.Args[1]
+ if w0.Op != OpS390XSRDconst {
+ break
+ }
+ if w0.AuxInt != j-8 {
+ break
+ }
+ if w != w0.Args[0] {
+ break
+ }
+ mem := x.Args[2]
+ if !(p.Op != OpSB && x.Uses == 1 && clobber(x)) {
+ break
+ }
+ v.reset(OpS390XMOVHBRstore)
+ v.AuxInt = i - 1
+ v.Aux = s
+ v.AddArg(p)
+ v.AddArg(w0)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVBstore [i] {s} p (SRWconst [8] w) x:(MOVBstore [i-1] {s} p w mem))
+ // cond: p.Op != OpSB && x.Uses == 1 && clobber(x)
+ // result: (MOVHBRstore [i-1] {s} p w mem)
+ for {
+ i := v.AuxInt
+ s := v.Aux
+ p := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpS390XSRWconst {
+ break
+ }
+ if v_1.AuxInt != 8 {
+ break
+ }
+ w := v_1.Args[0]
+ x := v.Args[2]
+ if x.Op != OpS390XMOVBstore {
+ break
+ }
+ if x.AuxInt != i-1 {
+ break
+ }
+ if x.Aux != s {
+ break
+ }
+ if p != x.Args[0] {
+ break
+ }
+ if w != x.Args[1] {
+ break
+ }
+ mem := x.Args[2]
+ if !(p.Op != OpSB && x.Uses == 1 && clobber(x)) {
+ break
+ }
+ v.reset(OpS390XMOVHBRstore)
+ v.AuxInt = i - 1
+ v.Aux = s
+ v.AddArg(p)
+ v.AddArg(w)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVBstore [i] {s} p (SRWconst [j] w) x:(MOVBstore [i-1] {s} p w0:(SRWconst [j-8] w) mem))
+ // cond: p.Op != OpSB && x.Uses == 1 && clobber(x)
+ // result: (MOVHBRstore [i-1] {s} p w0 mem)
+ for {
+ i := v.AuxInt
+ s := v.Aux
+ p := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpS390XSRWconst {
+ break
+ }
+ j := v_1.AuxInt
+ w := v_1.Args[0]
+ x := v.Args[2]
+ if x.Op != OpS390XMOVBstore {
+ break
+ }
+ if x.AuxInt != i-1 {
+ break
+ }
+ if x.Aux != s {
+ break
+ }
+ if p != x.Args[0] {
+ break
+ }
+ w0 := x.Args[1]
+ if w0.Op != OpS390XSRWconst {
+ break
+ }
+ if w0.AuxInt != j-8 {
+ break
+ }
+ if w != w0.Args[0] {
+ break
+ }
+ mem := x.Args[2]
+ if !(p.Op != OpSB && x.Uses == 1 && clobber(x)) {
+ break
+ }
+ v.reset(OpS390XMOVHBRstore)
+ v.AuxInt = i - 1
+ v.Aux = s
+ v.AddArg(p)
+ v.AddArg(w0)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValueS390X_OpS390XMOVBstoreconst(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (MOVBstoreconst [sc] {s} (ADDconst [off] ptr) mem)
+ // cond: ValAndOff(sc).canAdd(off)
+ // result: (MOVBstoreconst [ValAndOff(sc).add(off)] {s} ptr mem)
+ for {
+ sc := v.AuxInt
+ s := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpS390XADDconst {
+ break
+ }
+ off := v_0.AuxInt
+ ptr := v_0.Args[0]
+ mem := v.Args[1]
+ if !(ValAndOff(sc).canAdd(off)) {
+ break
+ }
+ v.reset(OpS390XMOVBstoreconst)
+ v.AuxInt = ValAndOff(sc).add(off)
+ v.Aux = s
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVBstoreconst [sc] {sym1} (MOVDaddr [off] {sym2} ptr) mem)
+ // cond: canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd(off)
+ // result: (MOVBstoreconst [ValAndOff(sc).add(off)] {mergeSym(sym1, sym2)} ptr mem)
+ for {
+ sc := v.AuxInt
+ sym1 := v.Aux
+ v_0 := v.Args[0]
+ if v_0.Op != OpS390XMOVDaddr {
+ break
+ }
+ off := v_0.AuxInt
+ sym2 := v_0.Aux
+ ptr := v_0.Args[0]
+ mem := v.Args[1]
+ if !(canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd(off)) {
+ break
+ }
+ v.reset(OpS390XMOVBstoreconst)
+ v.AuxInt = ValAndOff(sc).add(off)
+ v.Aux = mergeSym(sym1, sym2)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (MOVBstoreconst [c] {s} p x:(MOVBstoreconst [a] {s} p mem))
+ // cond: p.Op != OpSB && x.Uses == 1 && ValAndOff(a).Off() + 1 == ValAndOff(c).Off() && clobber(x)
+ // result: (MOVHstoreconst [makeValAndOff(ValAndOff(c).Val()&0xff | ValAndOff(a).Val()<<8, ValAndOff(a).Off())] {s} p mem)
+ for {
+ c := v.AuxInt
+ s := v.Aux
+ p := v.Args[0]
+ x := v.Args[1]
+ if x.Op != OpS390XMOVBstoreconst {
+ break
+ }
+ a := x.AuxInt
+ if x.Aux != s {
+ break
+ }
+ if p != x.Args[0] {
+ break
+ }
+ mem := x.Args[1]
+ if !(p.Op != OpSB && x.Uses == 1 && ValAndOff(a).Off()+1 == ValAndOff(c).Off() && clobber(x)) {
+ break
+ }
+ v.reset(OpS390XMOVHstoreconst)
+ v.AuxInt = makeValAndOff(ValAndOff(c).Val()&0xff|ValAndOff(a).Val()<<8, ValAndOff(a).Off())
+ v.Aux = s
+ v.AddArg(p)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValueS390X_OpS390XMOVBstoreidx(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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_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(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
+ 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(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
+ p := v.Args[0]
+ idx := 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
+ }
+ 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 != 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:(SRDconst [j] w) x:(MOVBstoreidx [i-1] {s} p idx (SRDconst [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
+ 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 != OpS390XMOVBstoreidx {
+ break
+ }
+ if x.AuxInt != i-1 {
+ break
+ }
+ if x.Aux != s {
+ break
+ }
+ 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+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 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
+ p := v.Args[0]
+ idx := 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
+ }
+ 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} 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
+ 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
+ }
+ 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 (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
+ 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
+ }
+ 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 [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
+ 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
+ }
+ 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 (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
+ 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
+ }
+ 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 [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
+ 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
+ }
+ 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
+ }
+ 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)
+ for {
+ 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 {
+ 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 {
+ 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 {
+ 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(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 {
+ 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 {
+ 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 {
+ 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 {
+ 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 {
+ 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 {
+ 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 {
+ 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 {
+ 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(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]
+ 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 {
+ 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 {
+ 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 {
+ 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(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (MOVDLT x y (InvertFlags cmp))
+ // cond:
+ // result: (MOVDGT x y cmp)
+ for {
+ 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 {
+ 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 {
+ 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 {
+ 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(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (MOVDNE x y (InvertFlags cmp))
+ // cond:
+ // result: (MOVDNE x y cmp)
+ for {
+ 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 {
+ y := v.Args[1]
+ 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 {
+ x := v.Args[0]
+ 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 {
+ x := v.Args[0]
+ 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(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)
+ for {
+ c := v.AuxInt
+ s := v.Aux
+ 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
+ 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_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
+ 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(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: x
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpS390XMOVDstore {
+ break
+ }
+ off2 := v_1.AuxInt
+ sym2 := v_1.Aux
+ ptr2 := v_1.Args[0]
+ x := v_1.Args[1]
+ if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ // match: (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 {
+ 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_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_0 := v.Args[0]
+ if v_0.Op != OpS390XMOVDaddridx {
+ 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(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 {
+ break
+ }
+ 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(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 {
+ 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 {
+ 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
+ }
+ 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 {
+ 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: 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 {
+ break
+ }
+ c := v_1.AuxInt
+ mem := v.Args[2]
+ if !(validValAndOff(c, off) && int64(int16(c)) == c && 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_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_0 := v.Args[0]
+ if v_0.Op != OpS390XMOVDaddridx {
+ break
+ }
+ off2 := v_0.AuxInt
+ sym2 := v_0.Aux
+ ptr := v_0.Args[0]
+ idx := v_0.Args[1]
+ val := v.Args[1]
+ mem := v.Args[2]
+ if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
+ break
+ }
+ v.reset(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 {
+ break
+ }
+ ptr := v_0.Args[0]
+ idx := v_0.Args[1]
+ val := v.Args[1]
+ mem := v.Args[2]
+ if !(ptr.Op != OpSB) {
+ break
+ }
+ v.reset(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
+ 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
+ }
+ 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
+ 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
+ }
+ 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
+ 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
+ }
+ 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(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 {
+ break
+ }
+ off := v_0.AuxInt
+ ptr := v_0.Args[0]
+ mem := v.Args[1]
+ if !(ValAndOff(sc).canAdd(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: 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 {
+ break
+ }
+ off := v_0.AuxInt
+ sym2 := v_0.Aux
+ ptr := v_0.Args[0]
+ mem := v.Args[1]
+ if !(canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd(off)) {
+ break
+ }
+ v.reset(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 {
+ 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 {
+ 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
+ }
+ 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)
+ 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 != 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
+ }
+ 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
+ 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
+ }
+ 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
+ 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
+ }
+ 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
+ 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
+ }
+ 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(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)
+ 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
+ }
+ 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
+ }
+ 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 [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
+ 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
+ }
+ 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 (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
+ 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
+ }
+ 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 [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 {
+ 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
+ }
+ 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
+ }
+ 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: x
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpS390XMOVHstore {
+ break
+ }
+ off2 := v_1.AuxInt
+ sym2 := v_1.Aux
+ ptr2 := v_1.Args[0]
+ x := v_1.Args[1]
+ if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ // match: (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_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_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_0 := v.Args[0]
+ if v_0.Op != OpS390XMOVDaddridx {
+ 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(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_0 := v.Args[0]
+ if v_0.Op != OpS390XADD {
+ break
+ }
+ 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(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)
+ for {
+ c := v.AuxInt
+ sym := v.Aux
+ 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} ptr (ADDconst [d] idx) mem)
+ // cond:
+ // result: (MOVHZloadidx [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 {
+ 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
+ }
+ return false
+}
+func rewriteValueS390X_OpS390XMOVHZreg(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (MOVHZreg x:(MOVBZload _ _))
+ // cond:
+ // result: x
+ for {
+ x := v.Args[0]
+ if x.Op != OpS390XMOVBZload {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVHZreg x:(MOVHZload _ _))
+ // cond:
+ // result: x
+ for {
+ x := v.Args[0]
+ if x.Op != OpS390XMOVHZload {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVHZreg x:(Arg <t>))
+ // cond: (is8BitInt(t) || is16BitInt(t)) && !isSigned(t)
+ // result: x
+ for {
+ x := v.Args[0]
+ if x.Op != OpArg {
+ break
+ }
+ t := x.Type
+ if !((is8BitInt(t) || is16BitInt(t)) && !isSigned(t)) {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVHZreg x:(MOVBZreg _))
+ // cond:
+ // result: x
+ for {
+ x := v.Args[0]
+ if x.Op != OpS390XMOVBZreg {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVHZreg x:(MOVHZreg _))
+ // cond:
+ // result: x
+ for {
+ x := v.Args[0]
+ if x.Op != OpS390XMOVHZreg {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = x.Type
+ 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
+ ptr := x.Args[0]
+ mem := x.Args[1]
+ if !(x.Uses == 1 && clobber(x)) {
+ break
+ }
+ b = x.Block
+ v0 := b.NewValue0(v.Line, 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
+ 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, 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(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)
+ 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)) {
+ 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 {
+ 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(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (MOVHreg x:(MOVBload _ _))
+ // cond:
+ // result: x
+ for {
+ x := v.Args[0]
+ if x.Op != OpS390XMOVBload {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVHreg x:(MOVBZload _ _))
+ // cond:
+ // result: x
+ for {
+ x := v.Args[0]
+ if x.Op != OpS390XMOVBZload {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVHreg x:(MOVHload _ _))
+ // cond:
+ // result: x
+ for {
+ x := v.Args[0]
+ if x.Op != OpS390XMOVHload {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVHreg x:(Arg <t>))
+ // cond: (is8BitInt(t) || is16BitInt(t)) && isSigned(t)
+ // result: x
+ for {
+ x := v.Args[0]
+ if x.Op != OpArg {
+ break
+ }
+ t := x.Type
+ if !((is8BitInt(t) || is16BitInt(t)) && isSigned(t)) {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVHreg x:(MOVBreg _))
+ // cond:
+ // result: x
+ for {
+ x := v.Args[0]
+ if x.Op != OpS390XMOVBreg {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVHreg x:(MOVBZreg _))
+ // cond:
+ // result: x
+ for {
+ x := v.Args[0]
+ if x.Op != OpS390XMOVBZreg {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVHreg x:(MOVHreg _))
+ // cond:
+ // result: x
+ for {
+ x := v.Args[0]
+ if x.Op != OpS390XMOVHreg {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = x.Type
+ 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
+ ptr := x.Args[0]
+ mem := x.Args[1]
+ if !(x.Uses == 1 && clobber(x)) {
+ break
+ }
+ b = x.Block
+ v0 := b.NewValue0(v.Line, 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(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)
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ 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
+ 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_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: 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 {
+ break
+ }
+ c := v_1.AuxInt
+ mem := v.Args[2]
+ if !(validOff(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_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_0 := v.Args[0]
+ if v_0.Op != OpS390XMOVDaddridx {
+ break
+ }
+ off2 := v_0.AuxInt
+ sym2 := v_0.Aux
+ ptr := v_0.Args[0]
+ idx := v_0.Args[1]
+ val := v.Args[1]
+ mem := v.Args[2]
+ if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
+ break
+ }
+ v.reset(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 {
+ break
+ }
+ ptr := v_0.Args[0]
+ idx := v_0.Args[1]
+ val := v.Args[1]
+ mem := v.Args[2]
+ if !(ptr.Op != OpSB) {
+ break
+ }
+ v.reset(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
+ 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
+ }
+ 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
+ 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
+ }
+ 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
+ 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
+ }
+ 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
+ }
+ // 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
+ 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
+ }
+ 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(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)
+ for {
+ sc := v.AuxInt
+ s := v.Aux
+ 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 !(ValAndOff(sc).canAdd(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: 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 {
+ break
+ }
+ off := v_0.AuxInt
+ sym2 := v_0.Aux
+ ptr := v_0.Args[0]
+ mem := v.Args[1]
+ if !(canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd(off)) {
+ break
+ }
+ v.reset(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 {
+ break
+ }
+ a := x.AuxInt
+ if x.Aux != s {
+ break
+ }
+ 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(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 {
+ 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} ptr (ADDconst [d] idx) val mem)
+ // cond:
+ // result: (MOVHstoreidx [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 {
+ 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 [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
+ 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
+ }
+ 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 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
+ 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
+ }
+ 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 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
+ 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
+ }
+ 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 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
+ 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
+ }
+ 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
+ }
+ return false
+}
+func rewriteValueS390X_OpS390XMOVWBRstore(v *Value, config *Config) 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)
+ 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 != OpS390XMOVWBRstore {
+ break
+ }
+ if x.AuxInt != i-4 {
+ break
+ }
+ if x.Aux != s {
+ break
+ }
+ if p != x.Args[0] {
+ break
+ }
+ if w != x.Args[1] {
+ break
+ }
+ mem := x.Args[2]
+ if !(x.Uses == 1 && clobber(x)) {
+ break
+ }
+ v.reset(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
+ 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
+ }
+ 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(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)
+ 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
+ }
+ 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
+ }
+ 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 [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
+ 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] {
+ 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
+ }
+ 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: x
+ for {
+ off := v.AuxInt
+ sym := v.Aux
+ ptr := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpS390XMOVWstore {
+ break
+ }
+ off2 := v_1.AuxInt
+ sym2 := v_1.Aux
+ ptr2 := v_1.Args[0]
+ x := v_1.Args[1]
+ if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ // match: (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_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_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_0 := v.Args[0]
+ if v_0.Op != OpS390XMOVDaddridx {
+ 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(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 {
+ break
+ }
+ 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(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 {
+ 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} ptr (ADDconst [d] idx) mem)
+ // cond:
+ // result: (MOVWZloadidx [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 {
+ 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: x
+ for {
+ x := v.Args[0]
+ if x.Op != OpS390XMOVBZload {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVWZreg x:(MOVHZload _ _))
+ // cond:
+ // result: x
+ for {
+ x := v.Args[0]
+ if x.Op != OpS390XMOVHZload {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVWZreg x:(MOVWZload _ _))
+ // cond:
+ // result: x
+ for {
+ x := v.Args[0]
+ if x.Op != OpS390XMOVWZload {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVWZreg x:(Arg <t>))
+ // cond: (is8BitInt(t) || is16BitInt(t) || is32BitInt(t)) && !isSigned(t)
+ // result: 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(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVWZreg x:(MOVBZreg _))
+ // cond:
+ // result: x
+ for {
+ x := v.Args[0]
+ if x.Op != OpS390XMOVBZreg {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVWZreg x:(MOVHZreg _))
+ // cond:
+ // result: x
+ for {
+ x := v.Args[0]
+ if x.Op != OpS390XMOVHZreg {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVWZreg x:(MOVWZreg _))
+ // cond:
+ // result: x
+ for {
+ x := v.Args[0]
+ if x.Op != OpS390XMOVWZreg {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = x.Type
+ 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
+ ptr := x.Args[0]
+ mem := x.Args[1]
+ if !(x.Uses == 1 && clobber(x)) {
+ break
+ }
+ b = x.Block
+ v0 := b.NewValue0(v.Line, 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
+ 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, 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(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)
+ 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)) {
+ 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 {
+ 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(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (MOVWreg x:(MOVBload _ _))
+ // cond:
+ // result: x
+ for {
+ x := v.Args[0]
+ if x.Op != OpS390XMOVBload {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVWreg x:(MOVBZload _ _))
+ // cond:
+ // result: x
+ for {
+ x := v.Args[0]
+ if x.Op != OpS390XMOVBZload {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVWreg x:(MOVHload _ _))
+ // cond:
+ // result: x
+ for {
+ x := v.Args[0]
+ if x.Op != OpS390XMOVHload {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVWreg x:(MOVHZload _ _))
+ // cond:
+ // result: x
+ for {
+ x := v.Args[0]
+ if x.Op != OpS390XMOVHZload {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVWreg x:(MOVWload _ _))
+ // cond:
+ // result: x
+ for {
+ x := v.Args[0]
+ if x.Op != OpS390XMOVWload {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVWreg x:(Arg <t>))
+ // cond: (is8BitInt(t) || is16BitInt(t) || is32BitInt(t)) && isSigned(t)
+ // result: 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(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVWreg x:(MOVBreg _))
+ // cond:
+ // result: x
+ for {
+ x := v.Args[0]
+ if x.Op != OpS390XMOVBreg {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVWreg x:(MOVBZreg _))
+ // cond:
+ // result: x
+ for {
+ x := v.Args[0]
+ if x.Op != OpS390XMOVBZreg {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVWreg x:(MOVHreg _))
+ // cond:
+ // result: x
+ for {
+ x := v.Args[0]
+ if x.Op != OpS390XMOVHreg {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVWreg x:(MOVHreg _))
+ // cond:
+ // result: x
+ for {
+ x := v.Args[0]
+ if x.Op != OpS390XMOVHreg {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ // match: (MOVWreg x:(MOVWreg _))
+ // cond:
+ // result: x
+ for {
+ x := v.Args[0]
+ if x.Op != OpS390XMOVWreg {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = x.Type
+ 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
+ ptr := x.Args[0]
+ mem := x.Args[1]
+ if !(x.Uses == 1 && clobber(x)) {
+ break
+ }
+ b = x.Block
+ v0 := b.NewValue0(v.Line, 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(v *Value, config *Config) 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)
+ 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]
+ 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: 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 {
+ break
+ }
+ c := v_1.AuxInt
+ mem := v.Args[2]
+ if !(validOff(off) && int64(int16(c)) == c && 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_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_0 := v.Args[0]
+ if v_0.Op != OpS390XMOVDaddridx {
+ break
+ }
+ off2 := v_0.AuxInt
+ sym2 := v_0.Aux
+ ptr := v_0.Args[0]
+ idx := v_0.Args[1]
+ val := v.Args[1]
+ mem := v.Args[2]
+ if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) {
+ break
+ }
+ v.reset(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 {
+ break
+ }
+ ptr := v_0.Args[0]
+ idx := v_0.Args[1]
+ val := v.Args[1]
+ mem := v.Args[2]
+ if !(ptr.Op != OpSB) {
+ break
+ }
+ v.reset(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
+ 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
+ }
+ 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
+ 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
+ }
+ 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
+ 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
+ }
+ 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
+ }
+ // 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
+ 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
+ }
+ 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
+ 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
+ }
+ 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(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)
+ for {
+ sc := v.AuxInt
+ s := v.Aux
+ 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 !(ValAndOff(sc).canAdd(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: 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 {
+ break
+ }
+ off := v_0.AuxInt
+ sym2 := v_0.Aux
+ ptr := v_0.Args[0]
+ mem := v.Args[1]
+ if !(canMergeSym(sym1, sym2) && ValAndOff(sc).canAdd(off)) {
+ break
+ }
+ v.reset(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 {
+ break
+ }
+ a := x.AuxInt
+ if x.Aux != s {
+ break
+ }
+ 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.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 {
+ 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 {
+ 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 [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
+ 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
+ }
+ 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 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
+ 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
+ }
+ 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
+ }
+ 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)
+ for {
+ 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_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: 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 {
+ 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)) {
+ 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 {
+ 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)) {
+ 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 {
+ 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.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) {
+ break
+ }
+ v.reset(OpS390XADD)
+ 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] (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(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (MULLW x (MOVDconst [c]))
+ // cond:
+ // result: (MULLWconst [c] x)
+ for {
+ 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_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: 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 {
+ 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)) {
+ 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 {
+ 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)) {
+ 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 {
+ 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)) {
+ 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 {
+ 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)) {
+ 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(v *Value, config *Config) 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.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) {
+ break
+ }
+ v.reset(OpS390XADDW)
+ 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] (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(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 {
+ 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 {
+ 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) {
+ break
+ }
+ v.reset(OpS390XXOR)
+ v0 := b.NewValue0(v.Line, OpS390XMOVDconst, config.fe.TypeUInt64())
+ v0.AuxInt = -1
+ v.AddArg(v0)
+ v.AddArg(x)
+ 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)
+ for {
+ x := v.Args[0]
+ if !(true) {
+ 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 {
+ 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_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 (MOVDconst [c]) (MOVDconst [d]))
+ // cond:
+ // result: (MOVDconst [c|d])
+ for {
+ 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 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: (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)
+ for {
+ t := v.Type
+ x := v.Args[0]
+ g := v.Args[1]
+ if g.Op != OpS390XMOVDload {
+ 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)) {
+ 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 {
+ 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)) {
+ 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 {
+ break
+ }
+ o1 := o0.Args[0]
+ if o1.Op != OpS390XOR {
+ break
+ }
+ o2 := o1.Args[0]
+ if o2.Op != OpS390XOR {
+ break
+ }
+ o3 := o2.Args[0]
+ if o3.Op != OpS390XOR {
+ break
+ }
+ o4 := o3.Args[0]
+ if o4.Op != OpS390XOR {
+ break
+ }
+ o5 := o4.Args[0]
+ if o5.Op != OpS390XOR {
+ break
+ }
+ x0 := o5.Args[0]
+ if x0.Op != OpS390XMOVBZload {
+ break
+ }
+ i := x0.AuxInt
+ s := x0.Aux
+ p := x0.Args[0]
+ mem := x0.Args[1]
+ s0 := o5.Args[1]
+ if s0.Op != OpS390XSLDconst {
+ break
+ }
+ if s0.AuxInt != 8 {
+ break
+ }
+ x1 := s0.Args[0]
+ if x1.Op != OpS390XMOVBZload {
+ break
+ }
+ if x1.AuxInt != i+1 {
+ break
+ }
+ if x1.Aux != s {
+ break
+ }
+ if p != x1.Args[0] {
+ break
+ }
+ if mem != x1.Args[1] {
+ break
+ }
+ s1 := o4.Args[1]
+ if s1.Op != OpS390XSLDconst {
+ break
+ }
+ if s1.AuxInt != 16 {
+ break
+ }
+ x2 := s1.Args[0]
+ if x2.Op != OpS390XMOVBZload {
+ break
+ }
+ if x2.AuxInt != i+2 {
+ break
+ }
+ if x2.Aux != s {
+ break
+ }
+ if p != x2.Args[0] {
+ break
+ }
+ if mem != x2.Args[1] {
+ break
+ }
+ s2 := o3.Args[1]
+ if s2.Op != OpS390XSLDconst {
+ break
+ }
+ if s2.AuxInt != 24 {
+ break
+ }
+ x3 := s2.Args[0]
+ if x3.Op != OpS390XMOVBZload {
+ break
+ }
+ if x3.AuxInt != i+3 {
+ break
+ }
+ if x3.Aux != s {
+ break
+ }
+ if p != x3.Args[0] {
+ break
+ }
+ if mem != x3.Args[1] {
+ break
+ }
+ s3 := o2.Args[1]
+ if s3.Op != OpS390XSLDconst {
+ break
+ }
+ if s3.AuxInt != 32 {
+ break
+ }
+ x4 := s3.Args[0]
+ if x4.Op != OpS390XMOVBZload {
+ break
+ }
+ if x4.AuxInt != i+4 {
+ break
+ }
+ if x4.Aux != s {
+ break
+ }
+ if p != x4.Args[0] {
+ break
+ }
+ if mem != x4.Args[1] {
+ break
+ }
+ s4 := o1.Args[1]
+ if s4.Op != OpS390XSLDconst {
+ break
+ }
+ if s4.AuxInt != 40 {
+ break
+ }
+ x5 := s4.Args[0]
+ if x5.Op != OpS390XMOVBZload {
+ break
+ }
+ if x5.AuxInt != i+5 {
+ break
+ }
+ if x5.Aux != s {
+ break
+ }
+ if p != x5.Args[0] {
+ break
+ }
+ if mem != x5.Args[1] {
+ break
+ }
+ s5 := o0.Args[1]
+ if s5.Op != OpS390XSLDconst {
+ break
+ }
+ if s5.AuxInt != 48 {
+ break
+ }
+ x6 := s5.Args[0]
+ if x6.Op != OpS390XMOVBZload {
+ break
+ }
+ if x6.AuxInt != i+6 {
+ break
+ }
+ if x6.Aux != s {
+ break
+ }
+ if p != x6.Args[0] {
+ break
+ }
+ if mem != x6.Args[1] {
+ break
+ }
+ s6 := v.Args[1]
+ if s6.Op != OpS390XSLDconst {
+ break
+ }
+ if s6.AuxInt != 56 {
+ break
+ }
+ x7 := s6.Args[0]
+ if x7.Op != OpS390XMOVBZload {
+ 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 !(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 [...]
+ break
+ }
+ b = mergePoint(b, x0, x1, x2, x3, x4, x5, x6, x7)
+ v0 := b.NewValue0(v.Line, OpS390XMOVDBRload, config.fe.TypeUInt64())
+ v.reset(OpCopy)
+ v.AddArg(v0)
+ v0.AuxInt = i
+ v0.Aux = s
+ v0.AddArg(p)
+ 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) (MOVDBRloadidx <v.Type> [i] {s} p idx mem)
+ for {
+ o0 := v.Args[0]
+ if o0.Op != OpS390XOR {
+ break
+ }
+ o1 := o0.Args[0]
+ if o1.Op != OpS390XOR {
+ break
+ }
+ o2 := o1.Args[0]
+ if o2.Op != OpS390XOR {
+ break
+ }
+ o3 := o2.Args[0]
+ if o3.Op != OpS390XOR {
+ break
+ }
+ o4 := o3.Args[0]
+ if o4.Op != OpS390XOR {
+ break
+ }
+ o5 := o4.Args[0]
+ if o5.Op != OpS390XOR {
+ break
+ }
+ x0 := o5.Args[0]
+ if x0.Op != OpS390XMOVBZloadidx {
+ 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 {
+ break
+ }
+ if s0.AuxInt != 8 {
+ break
+ }
+ x1 := s0.Args[0]
+ if x1.Op != OpS390XMOVBZloadidx {
+ break
+ }
+ if x1.AuxInt != i+1 {
+ break
+ }
+ if x1.Aux != s {
+ break
+ }
+ if p != x1.Args[0] {
+ break
+ }
+ if idx != x1.Args[1] {
+ break
+ }
+ if mem != x1.Args[2] {
+ break
+ }
+ s1 := o4.Args[1]
+ if s1.Op != OpS390XSLDconst {
+ break
+ }
+ if s1.AuxInt != 16 {
+ break
+ }
+ x2 := s1.Args[0]
+ if x2.Op != OpS390XMOVBZloadidx {
+ break
+ }
+ if x2.AuxInt != i+2 {
+ break
+ }
+ if x2.Aux != s {
+ break
+ }
+ if p != x2.Args[0] {
+ break
+ }
+ if idx != x2.Args[1] {
+ break
+ }
+ if mem != x2.Args[2] {
+ break
+ }
+ s2 := o3.Args[1]
+ if s2.Op != OpS390XSLDconst {
+ break
+ }
+ if s2.AuxInt != 24 {
+ break
+ }
+ x3 := s2.Args[0]
+ if x3.Op != OpS390XMOVBZloadidx {
+ break
+ }
+ if x3.AuxInt != i+3 {
+ break
+ }
+ if x3.Aux != s {
+ break
+ }
+ if p != x3.Args[0] {
+ break
+ }
+ if idx != x3.Args[1] {
+ break
+ }
+ if mem != x3.Args[2] {
+ break
+ }
+ s3 := o2.Args[1]
+ if s3.Op != OpS390XSLDconst {
+ break
+ }
+ if s3.AuxInt != 32 {
+ break
+ }
+ x4 := s3.Args[0]
+ if x4.Op != OpS390XMOVBZloadidx {
+ break
+ }
+ if x4.AuxInt != i+4 {
+ break
+ }
+ if x4.Aux != s {
+ break
+ }
+ if p != x4.Args[0] {
+ break
+ }
+ if idx != x4.Args[1] {
+ break
+ }
+ if mem != x4.Args[2] {
+ break
+ }
+ s4 := o1.Args[1]
+ if s4.Op != OpS390XSLDconst {
+ break
+ }
+ if s4.AuxInt != 40 {
+ break
+ }
+ x5 := s4.Args[0]
+ if x5.Op != OpS390XMOVBZloadidx {
+ break
+ }
+ if x5.AuxInt != i+5 {
+ break
+ }
+ if x5.Aux != s {
+ break
+ }
+ if p != x5.Args[0] {
+ break
+ }
+ if idx != x5.Args[1] {
+ break
+ }
+ if mem != x5.Args[2] {
+ break
+ }
+ s5 := o0.Args[1]
+ if s5.Op != OpS390XSLDconst {
+ break
+ }
+ if s5.AuxInt != 48 {
+ break
+ }
+ x6 := s5.Args[0]
+ if x6.Op != OpS390XMOVBZloadidx {
+ break
+ }
+ if x6.AuxInt != i+6 {
+ break
+ }
+ if x6.Aux != s {
+ break
+ }
+ if p != x6.Args[0] {
+ break
+ }
+ if idx != x6.Args[1] {
+ break
+ }
+ if mem != x6.Args[2] {
+ break
+ }
+ s6 := v.Args[1]
+ if s6.Op != OpS390XSLDconst {
+ break
+ }
+ if s6.AuxInt != 56 {
+ break
+ }
+ x7 := s6.Args[0]
+ if x7.Op != OpS390XMOVBZloadidx {
+ break
+ }
+ if x7.AuxInt != i+7 {
+ break
+ }
+ if x7.Aux != s {
+ break
+ }
+ if p != x7.Args[0] {
+ break
+ }
+ if idx != x7.Args[1] {
+ break
+ }
+ if mem != x7.Args[2] {
+ break
+ }
+ if !(x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && x3.Uses == 1 && x4.Uses == 1 && x5.Uses == 1 && x6.Uses == 1 && x7.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && s2.Uses == 1 && s3.Uses == 1 && s4.Uses == 1 && s5.Uses == 1 && s6.Uses == 1 && o0.Uses == 1 && o1.Uses == 1 && o2.Uses == 1 && o3.Uses == 1 && o4.Uses == 1 && o5.Uses == 1 && mergePoint(b, x0, x1, x2, x3, x4, x5, x6, x7) != nil && clobber(x0) && clobber(x1) && clobber(x2) && clobber(x3) && clobber(x4) && clobber(x5) && clo [...]
+ break
+ }
+ b = mergePoint(b, x0, x1, x2, x3, x4, x5, x6, x7)
+ v0 := b.NewValue0(v.Line, OpS390XMOVDBRloadidx, 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: (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)
+ for {
+ o0 := v.Args[0]
+ if o0.Op != OpS390XOR {
+ break
+ }
+ o1 := o0.Args[0]
+ if o1.Op != OpS390XOR {
+ break
+ }
+ o2 := o1.Args[0]
+ if o2.Op != OpS390XOR {
+ break
+ }
+ o3 := o2.Args[0]
+ if o3.Op != OpS390XOR {
+ break
+ }
+ o4 := o3.Args[0]
+ if o4.Op != OpS390XOR {
+ break
+ }
+ o5 := o4.Args[0]
+ if o5.Op != OpS390XOR {
+ break
+ }
+ x0 := o5.Args[0]
+ if x0.Op != OpS390XMOVBZload {
+ break
+ }
+ i := x0.AuxInt
+ s := x0.Aux
+ p := x0.Args[0]
+ mem := x0.Args[1]
+ s0 := o5.Args[1]
+ if s0.Op != OpS390XSLDconst {
+ break
+ }
+ if s0.AuxInt != 8 {
+ break
+ }
+ x1 := s0.Args[0]
+ if x1.Op != OpS390XMOVBZload {
+ break
+ }
+ if x1.AuxInt != i-1 {
+ break
+ }
+ if x1.Aux != s {
+ break
+ }
+ if p != x1.Args[0] {
+ break
+ }
+ if mem != x1.Args[1] {
+ break
+ }
+ s1 := o4.Args[1]
+ if s1.Op != OpS390XSLDconst {
+ break
+ }
+ if s1.AuxInt != 16 {
+ break
+ }
+ x2 := s1.Args[0]
+ if x2.Op != OpS390XMOVBZload {
+ break
+ }
+ if x2.AuxInt != i-2 {
+ break
+ }
+ if x2.Aux != s {
+ break
+ }
+ if p != x2.Args[0] {
+ break
+ }
+ if mem != x2.Args[1] {
+ break
+ }
+ s2 := o3.Args[1]
+ if s2.Op != OpS390XSLDconst {
+ break
+ }
+ if s2.AuxInt != 24 {
+ break
+ }
+ x3 := s2.Args[0]
+ if x3.Op != OpS390XMOVBZload {
+ break
+ }
+ if x3.AuxInt != i-3 {
+ break
+ }
+ if x3.Aux != s {
+ break
+ }
+ if p != x3.Args[0] {
+ break
+ }
+ if mem != x3.Args[1] {
+ break
+ }
+ s3 := o2.Args[1]
+ if s3.Op != OpS390XSLDconst {
+ break
+ }
+ if s3.AuxInt != 32 {
+ break
+ }
+ x4 := s3.Args[0]
+ if x4.Op != OpS390XMOVBZload {
+ break
+ }
+ if x4.AuxInt != i-4 {
+ break
+ }
+ if x4.Aux != s {
+ break
+ }
+ if p != x4.Args[0] {
+ break
+ }
+ if mem != x4.Args[1] {
+ break
+ }
+ s4 := o1.Args[1]
+ if s4.Op != OpS390XSLDconst {
+ break
+ }
+ if s4.AuxInt != 40 {
+ break
+ }
+ x5 := s4.Args[0]
+ if x5.Op != OpS390XMOVBZload {
+ break
+ }
+ if x5.AuxInt != i-5 {
+ break
+ }
+ if x5.Aux != s {
+ break
+ }
+ if p != x5.Args[0] {
+ break
+ }
+ if mem != x5.Args[1] {
+ break
+ }
+ s5 := o0.Args[1]
+ if s5.Op != OpS390XSLDconst {
+ break
+ }
+ if s5.AuxInt != 48 {
+ break
+ }
+ x6 := s5.Args[0]
+ if x6.Op != OpS390XMOVBZload {
+ break
+ }
+ if x6.AuxInt != i-6 {
+ break
+ }
+ if x6.Aux != s {
+ break
+ }
+ if p != x6.Args[0] {
+ break
+ }
+ if mem != x6.Args[1] {
+ break
+ }
+ s6 := v.Args[1]
+ if s6.Op != OpS390XSLDconst {
+ break
+ }
+ if s6.AuxInt != 56 {
+ break
+ }
+ x7 := s6.Args[0]
+ if x7.Op != OpS390XMOVBZload {
+ 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 !(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 [...]
+ break
+ }
+ b = mergePoint(b, x0, x1, x2, x3, x4, x5, x6, x7)
+ v0 := b.NewValue0(v.Line, OpS390XMOVDload, config.fe.TypeUInt64())
+ v.reset(OpCopy)
+ v.AddArg(v0)
+ v0.AuxInt = i - 7
+ v0.Aux = s
+ v0.AddArg(p)
+ 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)
+ for {
+ o0 := v.Args[0]
+ if o0.Op != OpS390XOR {
+ break
+ }
+ o1 := o0.Args[0]
+ if o1.Op != OpS390XOR {
+ break
+ }
+ o2 := o1.Args[0]
+ if o2.Op != OpS390XOR {
+ break
+ }
+ o3 := o2.Args[0]
+ if o3.Op != OpS390XOR {
+ break
+ }
+ o4 := o3.Args[0]
+ if o4.Op != OpS390XOR {
+ break
+ }
+ o5 := o4.Args[0]
+ if o5.Op != OpS390XOR {
+ break
+ }
+ x0 := o5.Args[0]
+ if x0.Op != OpS390XMOVBZloadidx {
+ 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 {
+ break
+ }
+ if s0.AuxInt != 8 {
+ break
+ }
+ x1 := s0.Args[0]
+ if x1.Op != OpS390XMOVBZloadidx {
+ break
+ }
+ if x1.AuxInt != i-1 {
+ break
+ }
+ if x1.Aux != s {
+ break
+ }
+ if p != x1.Args[0] {
+ break
+ }
+ if idx != x1.Args[1] {
+ break
+ }
+ if mem != x1.Args[2] {
+ break
+ }
+ s1 := o4.Args[1]
+ if s1.Op != OpS390XSLDconst {
+ break
+ }
+ if s1.AuxInt != 16 {
+ break
+ }
+ x2 := s1.Args[0]
+ if x2.Op != OpS390XMOVBZloadidx {
+ break
+ }
+ if x2.AuxInt != i-2 {
+ break
+ }
+ if x2.Aux != s {
+ break
+ }
+ if p != x2.Args[0] {
+ break
+ }
+ if idx != x2.Args[1] {
+ break
+ }
+ if mem != x2.Args[2] {
+ break
+ }
+ s2 := o3.Args[1]
+ if s2.Op != OpS390XSLDconst {
+ break
+ }
+ if s2.AuxInt != 24 {
+ break
+ }
+ x3 := s2.Args[0]
+ if x3.Op != OpS390XMOVBZloadidx {
+ break
+ }
+ if x3.AuxInt != i-3 {
+ break
+ }
+ if x3.Aux != s {
+ break
+ }
+ if p != x3.Args[0] {
+ break
+ }
+ if idx != x3.Args[1] {
+ break
+ }
+ if mem != x3.Args[2] {
+ break
+ }
+ s3 := o2.Args[1]
+ if s3.Op != OpS390XSLDconst {
+ break
+ }
+ if s3.AuxInt != 32 {
+ break
+ }
+ x4 := s3.Args[0]
+ if x4.Op != OpS390XMOVBZloadidx {
+ break
+ }
+ if x4.AuxInt != i-4 {
+ break
+ }
+ if x4.Aux != s {
+ break
+ }
+ if p != x4.Args[0] {
+ break
+ }
+ if idx != x4.Args[1] {
+ break
+ }
+ if mem != x4.Args[2] {
+ break
+ }
+ s4 := o1.Args[1]
+ if s4.Op != OpS390XSLDconst {
+ break
+ }
+ if s4.AuxInt != 40 {
+ break
+ }
+ x5 := s4.Args[0]
+ if x5.Op != OpS390XMOVBZloadidx {
+ break
+ }
+ if x5.AuxInt != i-5 {
+ break
+ }
+ if x5.Aux != s {
+ break
+ }
+ if p != x5.Args[0] {
+ break
+ }
+ if idx != x5.Args[1] {
+ break
+ }
+ if mem != x5.Args[2] {
+ break
+ }
+ s5 := o0.Args[1]
+ if s5.Op != OpS390XSLDconst {
+ break
+ }
+ if s5.AuxInt != 48 {
+ break
+ }
+ x6 := s5.Args[0]
+ if x6.Op != OpS390XMOVBZloadidx {
+ break
+ }
+ if x6.AuxInt != i-6 {
+ break
+ }
+ if x6.Aux != s {
+ break
+ }
+ if p != x6.Args[0] {
+ break
+ }
+ if idx != x6.Args[1] {
+ break
+ }
+ if mem != x6.Args[2] {
+ break
+ }
+ s6 := v.Args[1]
+ if s6.Op != OpS390XSLDconst {
+ break
+ }
+ if s6.AuxInt != 56 {
+ break
+ }
+ x7 := s6.Args[0]
+ if x7.Op != OpS390XMOVBZloadidx {
+ break
+ }
+ if x7.AuxInt != i-7 {
+ break
+ }
+ if x7.Aux != s {
+ break
+ }
+ if p != x7.Args[0] {
+ break
+ }
+ if idx != x7.Args[1] {
+ break
+ }
+ if mem != x7.Args[2] {
+ break
+ }
+ if !(x0.Uses == 1 && x1.Uses == 1 && x2.Uses == 1 && x3.Uses == 1 && x4.Uses == 1 && x5.Uses == 1 && x6.Uses == 1 && x7.Uses == 1 && s0.Uses == 1 && s1.Uses == 1 && s2.Uses == 1 && s3.Uses == 1 && s4.Uses == 1 && s5.Uses == 1 && s6.Uses == 1 && o0.Uses == 1 && o1.Uses == 1 && o2.Uses == 1 && o3.Uses == 1 && o4.Uses == 1 && o5.Uses == 1 && mergePoint(b, x0, x1, x2, x3, x4, x5, x6, x7) != nil && clobber(x0) && clobber(x1) && clobber(x2) && clobber(x3) && clobber(x4) && clobber(x5) && clo [...]
+ break
+ }
+ b = mergePoint(b, x0, x1, x2, x3, x4, x5, x6, x7)
+ v0 := b.NewValue0(v.Line, OpS390XMOVDloadidx, v.Type)
+ v.reset(OpCopy)
+ v.AddArg(v0)
+ v0.AuxInt = i - 7
+ v0.Aux = s
+ v0.AddArg(p)
+ v0.AddArg(idx)
+ v0.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValueS390X_OpS390XORW(v *Value, config *Config) 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)
+ 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)) {
+ 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 {
+ 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)) {
+ 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 {
+ 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)) {
+ 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 {
+ 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)) {
+ 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 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))
+ for {
+ x0 := v.Args[0]
+ if x0.Op != OpS390XMOVBZload {
+ break
+ }
+ i := x0.AuxInt
+ s := x0.Aux
+ p := x0.Args[0]
+ mem := x0.Args[1]
+ s0 := v.Args[1]
+ if s0.Op != OpS390XSLWconst {
+ break
+ }
+ if s0.AuxInt != 8 {
+ break
+ }
+ x1 := s0.Args[0]
+ if x1.Op != OpS390XMOVBZload {
+ break
+ }
+ if x1.AuxInt != i+1 {
+ break
+ }
+ if x1.Aux != s {
+ break
+ }
+ if p != x1.Args[0] {
+ break
+ }
+ if mem != x1.Args[1] {
+ break
+ }
+ if !(p.Op != OpSB && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0)) {
+ break
+ }
+ b = mergePoint(b, x0, x1)
+ v0 := b.NewValue0(v.Line, OpS390XMOVHZreg, config.fe.TypeUInt64())
+ 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)
+ v0.AddArg(v1)
+ 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)
+ for {
+ o0 := v.Args[0]
+ if o0.Op != OpS390XORW {
+ break
+ }
+ z0 := o0.Args[0]
+ if z0.Op != OpS390XMOVHZreg {
+ break
+ }
+ x0 := z0.Args[0]
+ if x0.Op != OpS390XMOVHBRload {
+ break
+ }
+ i := x0.AuxInt
+ s := x0.Aux
+ p := x0.Args[0]
+ mem := x0.Args[1]
+ s0 := o0.Args[1]
+ if s0.Op != OpS390XSLWconst {
+ break
+ }
+ if s0.AuxInt != 16 {
+ break
+ }
+ x1 := s0.Args[0]
+ if x1.Op != OpS390XMOVBZload {
+ break
+ }
+ if x1.AuxInt != i+2 {
+ break
+ }
+ if x1.Aux != s {
+ break
+ }
+ if p != x1.Args[0] {
+ break
+ }
+ if mem != x1.Args[1] {
+ break
+ }
+ s1 := v.Args[1]
+ if s1.Op != OpS390XSLWconst {
+ break
+ }
+ if s1.AuxInt != 24 {
+ break
+ }
+ x2 := s1.Args[0]
+ if x2.Op != OpS390XMOVBZload {
+ break
+ }
+ if x2.AuxInt != i+3 {
+ break
+ }
+ if x2.Aux != s {
+ break
+ }
+ if p != x2.Args[0] {
+ break
+ }
+ if mem != x2.Args[1] {
+ 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)) {
+ break
+ }
+ b = mergePoint(b, x0, x1, x2)
+ v0 := b.NewValue0(v.Line, OpS390XMOVWBRload, config.fe.TypeUInt32())
+ v.reset(OpCopy)
+ v.AddArg(v0)
+ v0.AuxInt = i
+ v0.Aux = s
+ v0.AddArg(p)
+ v0.AddArg(mem)
+ 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))
+ for {
+ x0 := v.Args[0]
+ if x0.Op != OpS390XMOVBZloadidx {
+ 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 {
+ break
+ }
+ if s0.AuxInt != 8 {
+ break
+ }
+ x1 := s0.Args[0]
+ if x1.Op != OpS390XMOVBZloadidx {
+ break
+ }
+ if x1.AuxInt != i+1 {
+ break
+ }
+ if x1.Aux != s {
+ break
+ }
+ if p != x1.Args[0] {
+ break
+ }
+ if idx != x1.Args[1] {
+ break
+ }
+ if mem != x1.Args[2] {
+ break
+ }
+ if !(x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0)) {
+ break
+ }
+ b = mergePoint(b, x0, x1)
+ v0 := b.NewValue0(v.Line, OpS390XMOVHZreg, config.fe.TypeUInt64())
+ 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)
+ v0.AddArg(v1)
+ 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))
+ for {
+ o0 := v.Args[0]
+ if o0.Op != OpS390XORW {
+ break
+ }
+ z0 := o0.Args[0]
+ if z0.Op != OpS390XMOVHZreg {
+ break
+ }
+ x0 := z0.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 := o0.Args[1]
+ if s0.Op != OpS390XSLWconst {
+ break
+ }
+ if s0.AuxInt != 16 {
+ break
+ }
+ x1 := s0.Args[0]
+ if x1.Op != OpS390XMOVBZloadidx {
+ break
+ }
+ if x1.AuxInt != i+2 {
+ break
+ }
+ if x1.Aux != s {
+ break
+ }
+ if p != x1.Args[0] {
+ break
+ }
+ if idx != x1.Args[1] {
+ break
+ }
+ if mem != x1.Args[2] {
+ break
+ }
+ s1 := v.Args[1]
+ if s1.Op != OpS390XSLWconst {
+ break
+ }
+ if s1.AuxInt != 24 {
+ break
+ }
+ x2 := s1.Args[0]
+ if x2.Op != OpS390XMOVBZloadidx {
+ break
+ }
+ if x2.AuxInt != i+3 {
+ break
+ }
+ if x2.Aux != s {
+ break
+ }
+ if p != x2.Args[0] {
+ break
+ }
+ if idx != x2.Args[1] {
+ break
+ }
+ if mem != x2.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)) {
+ break
+ }
+ b = mergePoint(b, x0, x1, x2)
+ v0 := b.NewValue0(v.Line, OpS390XMOVWZreg, config.fe.TypeUInt64())
+ 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)
+ v0.AddArg(v1)
+ 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)
+ for {
+ x0 := v.Args[0]
+ if x0.Op != OpS390XMOVBZload {
+ break
+ }
+ i := x0.AuxInt
+ s := x0.Aux
+ p := x0.Args[0]
+ mem := x0.Args[1]
+ s0 := v.Args[1]
+ if s0.Op != OpS390XSLWconst {
+ break
+ }
+ if s0.AuxInt != 8 {
+ break
+ }
+ x1 := s0.Args[0]
+ if x1.Op != OpS390XMOVBZload {
+ break
+ }
+ if x1.AuxInt != i-1 {
+ break
+ }
+ if x1.Aux != s {
+ break
+ }
+ if p != x1.Args[0] {
+ break
+ }
+ if mem != x1.Args[1] {
+ break
+ }
+ if !(p.Op != OpSB && x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0)) {
+ break
+ }
+ b = mergePoint(b, x0, x1)
+ v0 := b.NewValue0(v.Line, OpS390XMOVHZload, config.fe.TypeUInt16())
+ v.reset(OpCopy)
+ v.AddArg(v0)
+ v0.AuxInt = i - 1
+ v0.Aux = s
+ v0.AddArg(p)
+ v0.AddArg(mem)
+ 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)
+ for {
+ o0 := v.Args[0]
+ if o0.Op != OpS390XORW {
+ break
+ }
+ x0 := o0.Args[0]
+ if x0.Op != OpS390XMOVHZload {
+ break
+ }
+ i := x0.AuxInt
+ s := x0.Aux
+ p := x0.Args[0]
+ mem := x0.Args[1]
+ s0 := o0.Args[1]
+ if s0.Op != OpS390XSLWconst {
+ break
+ }
+ if s0.AuxInt != 16 {
+ break
+ }
+ x1 := s0.Args[0]
+ if x1.Op != OpS390XMOVBZload {
+ break
+ }
+ if x1.AuxInt != i-1 {
+ break
+ }
+ if x1.Aux != s {
+ break
+ }
+ if p != x1.Args[0] {
+ break
+ }
+ if mem != x1.Args[1] {
+ break
+ }
+ s1 := v.Args[1]
+ if s1.Op != OpS390XSLWconst {
+ break
+ }
+ if s1.AuxInt != 24 {
+ break
+ }
+ x2 := s1.Args[0]
+ if x2.Op != OpS390XMOVBZload {
+ break
+ }
+ if x2.AuxInt != i-2 {
+ break
+ }
+ if x2.Aux != s {
+ break
+ }
+ if p != x2.Args[0] {
+ break
+ }
+ if mem != x2.Args[1] {
+ 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)) {
+ break
+ }
+ b = mergePoint(b, x0, x1, x2)
+ v0 := b.NewValue0(v.Line, OpS390XMOVWZload, config.fe.TypeUInt32())
+ v.reset(OpCopy)
+ v.AddArg(v0)
+ v0.AuxInt = i - 2
+ v0.Aux = s
+ v0.AddArg(p)
+ v0.AddArg(mem)
+ 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)
+ for {
+ x0 := v.Args[0]
+ if x0.Op != OpS390XMOVBZloadidx {
+ 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 {
+ break
+ }
+ if s0.AuxInt != 8 {
+ break
+ }
+ x1 := s0.Args[0]
+ if x1.Op != OpS390XMOVBZloadidx {
+ break
+ }
+ if x1.AuxInt != i-1 {
+ break
+ }
+ if x1.Aux != s {
+ break
+ }
+ if p != x1.Args[0] {
+ break
+ }
+ if idx != x1.Args[1] {
+ break
+ }
+ if mem != x1.Args[2] {
+ break
+ }
+ if !(x0.Uses == 1 && x1.Uses == 1 && s0.Uses == 1 && mergePoint(b, x0, x1) != nil && clobber(x0) && clobber(x1) && clobber(s0)) {
+ break
+ }
+ b = mergePoint(b, x0, x1)
+ v0 := b.NewValue0(v.Line, OpS390XMOVHZloadidx, v.Type)
+ v.reset(OpCopy)
+ v.AddArg(v0)
+ v0.AuxInt = i - 1
+ v0.Aux = s
+ v0.AddArg(p)
+ v0.AddArg(idx)
+ v0.AddArg(mem)
+ 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)
+ for {
+ o0 := v.Args[0]
+ if o0.Op != OpS390XORW {
+ break
+ }
+ x0 := o0.Args[0]
+ if x0.Op != OpS390XMOVHZloadidx {
+ 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 != OpS390XSLWconst {
+ break
+ }
+ if s0.AuxInt != 16 {
+ break
+ }
+ x1 := s0.Args[0]
+ if x1.Op != OpS390XMOVBZloadidx {
+ break
+ }
+ if x1.AuxInt != i-1 {
+ break
+ }
+ if x1.Aux != s {
+ break
+ }
+ if p != x1.Args[0] {
+ break
+ }
+ if idx != x1.Args[1] {
+ break
+ }
+ if mem != x1.Args[2] {
+ break
+ }
+ s1 := v.Args[1]
+ if s1.Op != OpS390XSLWconst {
+ break
+ }
+ if s1.AuxInt != 24 {
+ break
+ }
+ x2 := s1.Args[0]
+ if x2.Op != OpS390XMOVBZloadidx {
+ break
+ }
+ if x2.AuxInt != i-2 {
+ break
+ }
+ if x2.Aux != s {
+ break
+ }
+ if p != x2.Args[0] {
+ break
+ }
+ if idx != x2.Args[1] {
+ break
+ }
+ if mem != x2.Args[2] {
+ break
+ }
+ 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)) {
+ break
+ }
+ b = mergePoint(b, x0, x1, x2)
+ v0 := b.NewValue0(v.Line, OpS390XMOVWZloadidx, v.Type)
+ v.reset(OpCopy)
+ v.AddArg(v0)
+ v0.AuxInt = i - 2
+ v0.Aux = s
+ v0.AddArg(p)
+ v0.AddArg(idx)
+ v0.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValueS390X_OpS390XORWconst(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ORWconst [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: (ORWconst [c] _)
+ // cond: int32(c)==-1
+ // result: (MOVDconst [-1])
+ for {
+ c := v.AuxInt
+ if !(int32(c) == -1) {
+ break
+ }
+ v.reset(OpS390XMOVDconst)
+ v.AuxInt = -1
+ return true
+ }
+ // match: (ORWconst [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_OpS390XORconst(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ORconst [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: (ORconst [-1] _)
+ // cond:
+ // result: (MOVDconst [-1])
+ for {
+ if v.AuxInt != -1 {
+ break
+ }
+ v.reset(OpS390XMOVDconst)
+ v.AuxInt = -1
+ return true
+ }
+ // match: (ORconst [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_OpS390XSLD(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SLD x (MOVDconst [c]))
+ // cond:
+ // result: (SLDconst [c&63] x)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpS390XMOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpS390XSLDconst)
+ v.AuxInt = c & 63
+ v.AddArg(x)
+ return true
+ }
+ // match: (SLD x (ANDconst [63] y))
+ // cond:
+ // result: (SLD x y)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpS390XANDconst {
+ break
+ }
+ if v_1.AuxInt != 63 {
+ break
+ }
+ y := v_1.Args[0]
+ v.reset(OpS390XSLD)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ return false
+}
+func rewriteValueS390X_OpS390XSLW(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SLW x (MOVDconst [c]))
+ // cond:
+ // result: (SLWconst [c&63] x)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpS390XMOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpS390XSLWconst)
+ v.AuxInt = c & 63
+ v.AddArg(x)
+ return true
+ }
+ // match: (SLW x (ANDWconst [63] y))
+ // cond:
+ // result: (SLW x y)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpS390XANDWconst {
+ break
+ }
+ if v_1.AuxInt != 63 {
+ break
+ }
+ y := v_1.Args[0]
+ v.reset(OpS390XSLW)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ return false
+}
+func rewriteValueS390X_OpS390XSRAD(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SRAD x (MOVDconst [c]))
+ // cond:
+ // result: (SRADconst [c&63] x)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpS390XMOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpS390XSRADconst)
+ v.AuxInt = c & 63
+ v.AddArg(x)
+ return true
+ }
+ // match: (SRAD x (ANDconst [63] y))
+ // cond:
+ // result: (SRAD x y)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpS390XANDconst {
+ break
+ }
+ if v_1.AuxInt != 63 {
+ break
+ }
+ y := v_1.Args[0]
+ v.reset(OpS390XSRAD)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ return false
+}
+func rewriteValueS390X_OpS390XSRADconst(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SRADconst [c] (MOVDconst [d]))
+ // cond:
+ // result: (MOVDconst [d>>uint64(c)])
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpS390XMOVDconst {
+ break
+ }
+ d := v_0.AuxInt
+ v.reset(OpS390XMOVDconst)
+ v.AuxInt = d >> uint64(c)
+ return true
+ }
+ return false
+}
+func rewriteValueS390X_OpS390XSRAW(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SRAW x (MOVDconst [c]))
+ // cond:
+ // result: (SRAWconst [c&63] x)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpS390XMOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpS390XSRAWconst)
+ v.AuxInt = c & 63
+ v.AddArg(x)
+ return true
+ }
+ // match: (SRAW x (ANDWconst [63] y))
+ // cond:
+ // result: (SRAW x y)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpS390XANDWconst {
+ break
+ }
+ if v_1.AuxInt != 63 {
+ break
+ }
+ y := v_1.Args[0]
+ v.reset(OpS390XSRAW)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ return false
+}
+func rewriteValueS390X_OpS390XSRAWconst(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SRAWconst [c] (MOVDconst [d]))
+ // cond:
+ // result: (MOVDconst [d>>uint64(c)])
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpS390XMOVDconst {
+ break
+ }
+ d := v_0.AuxInt
+ v.reset(OpS390XMOVDconst)
+ v.AuxInt = d >> uint64(c)
+ return true
+ }
+ return false
+}
+func rewriteValueS390X_OpS390XSRD(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SRD x (MOVDconst [c]))
+ // cond:
+ // result: (SRDconst [c&63] x)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpS390XMOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpS390XSRDconst)
+ v.AuxInt = c & 63
+ v.AddArg(x)
+ return true
+ }
+ // match: (SRD x (ANDconst [63] y))
+ // cond:
+ // result: (SRD x y)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpS390XANDconst {
+ break
+ }
+ if v_1.AuxInt != 63 {
+ break
+ }
+ y := v_1.Args[0]
+ v.reset(OpS390XSRD)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ return false
+}
+func rewriteValueS390X_OpS390XSRW(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SRW x (MOVDconst [c]))
+ // cond:
+ // result: (SRWconst [c&63] x)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpS390XMOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpS390XSRWconst)
+ v.AuxInt = c & 63
+ v.AddArg(x)
+ return true
+ }
+ // match: (SRW x (ANDWconst [63] y))
+ // cond:
+ // result: (SRW x y)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpS390XANDWconst {
+ break
+ }
+ if v_1.AuxInt != 63 {
+ break
+ }
+ y := v_1.Args[0]
+ v.reset(OpS390XSRW)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ return false
+}
+func rewriteValueS390X_OpS390XSTM2(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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
+ p := v.Args[0]
+ w2 := v.Args[1]
+ w3 := v.Args[2]
+ x := v.Args[3]
+ if x.Op != OpS390XSTM2 {
+ break
+ }
+ if x.AuxInt != i-8 {
+ break
+ }
+ if x.Aux != s {
+ break
+ }
+ 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(OpS390XSTM4)
+ v.AuxInt = i - 8
+ v.Aux = s
+ v.AddArg(p)
+ v.AddArg(w0)
+ v.AddArg(w1)
+ v.AddArg(w2)
+ v.AddArg(w3)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (STM2 [i] {s} p (SRDconst [32] x) x mem)
+ // cond:
+ // result: (MOVDstore [i] {s} p x mem)
+ 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
+ }
+ x := v_1.Args[0]
+ if x != v.Args[2] {
+ break
+ }
+ mem := v.Args[3]
+ v.reset(OpS390XMOVDstore)
+ v.AuxInt = i
+ v.Aux = s
+ v.AddArg(p)
+ v.AddArg(x)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValueS390X_OpS390XSTMG2(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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
+ p := v.Args[0]
+ w2 := v.Args[1]
+ w3 := v.Args[2]
+ x := v.Args[3]
+ if x.Op != OpS390XSTMG2 {
+ break
+ }
+ if x.AuxInt != i-16 {
+ break
+ }
+ if x.Aux != s {
+ break
+ }
+ 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(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(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SUB x (MOVDconst [c]))
+ // cond: is32Bit(c)
+ // result: (SUBconst x [c])
+ for {
+ 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_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)
+ v0.AuxInt = c
+ v0.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (SUB 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: (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)
+ for {
+ t := v.Type
+ x := v.Args[0]
+ g := v.Args[1]
+ if g.Op != OpS390XMOVDload {
+ 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)) {
+ 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(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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(OpS390XMOVDconst)
+ v.AuxInt = 0
+ return true
+ }
+ return false
+}
+func rewriteValueS390X_OpS390XSUBW(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SUBW x (MOVDconst [c]))
+ // cond:
+ // result: (SUBWconst x [c])
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpS390XMOVDconst {
+ break
+ }
+ c := v_1.AuxInt
+ v.reset(OpS390XSUBWconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (SUBW (MOVDconst [c]) x)
+ // cond:
+ // result: (NEGW (SUBWconst <v.Type> x [c]))
+ for {
+ 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)
+ return true
+ }
+ // match: (SUBW 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: (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)
+ 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)) {
+ break
+ }
+ 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: g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)
+ // result: (SUBWload <t> [off] {sym} x ptr mem)
+ for {
+ t := v.Type
+ x := v.Args[0]
+ g := v.Args[1]
+ if g.Op != OpS390XMOVWZload {
+ 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)) {
+ break
+ }
+ v.reset(OpS390XSUBWload)
+ v.Type = t
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(x)
+ v.AddArg(ptr)
+ 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
+ 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: (ADDWconst [int64(int32(-c))] x)
+ for {
+ c := v.AuxInt
+ x := v.Args[0]
+ v.reset(OpS390XADDWconst)
+ v.AuxInt = int64(int32(-c))
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueS390X_OpS390XSUBconst(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SUBconst [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: (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 [d-c])
+ for {
+ c := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpS390XMOVDconst {
+ break
+ }
+ d := v_0.AuxInt
+ v.reset(OpS390XMOVDconst)
+ v.AuxInt = d - c
+ return true
+ }
+ // 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 != OpS390XSUBconst {
+ break
+ }
+ 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_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 {
+ break
+ }
+ c := v_1.AuxInt
+ if !(isU32Bit(c)) {
+ break
+ }
+ v.reset(OpS390XXORconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ return true
+ }
+ // match: (XOR (MOVDconst [c]) x)
+ // cond: isU32Bit(c)
+ // result: (XORconst [c] x)
+ for {
+ 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(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 {
+ 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: (XOR 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: (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)
+ for {
+ t := v.Type
+ x := v.Args[0]
+ g := v.Args[1]
+ if g.Op != OpS390XMOVDload {
+ 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)) {
+ 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: (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)
+ for {
+ t := v.Type
+ g := v.Args[0]
+ if g.Op != OpS390XMOVDload {
+ 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)) {
+ 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_OpS390XXORW(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (XORW x (MOVDconst [c]))
+ // cond:
+ // result: (XORWconst [c] x)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpS390XMOVDconst {
+ 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 {
+ break
+ }
+ c := v_0.AuxInt
+ x := v.Args[1]
+ v.reset(OpS390XXORWconst)
+ v.AuxInt = c
+ v.AddArg(x)
+ 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)
+ // result: (XORWload <t> [off] {sym} x ptr mem)
+ 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)) {
+ 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: g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)
+ // result: (XORWload <t> [off] {sym} x ptr mem)
+ for {
+ t := v.Type
+ g := v.Args[0]
+ if g.Op != OpS390XMOVWload {
+ 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)) {
+ 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> x g:(MOVWZload [off] {sym} ptr mem))
+ // cond: g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)
+ // result: (XORWload <t> [off] {sym} x ptr mem)
+ for {
+ t := v.Type
+ x := v.Args[0]
+ g := v.Args[1]
+ if g.Op != OpS390XMOVWZload {
+ 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)) {
+ 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:(MOVWZload [off] {sym} ptr mem) x)
+ // cond: g.Uses == 1 && ptr.Op != OpSB && is20Bit(off) && canMergeLoad(v, g) && clobber(g)
+ // result: (XORWload <t> [off] {sym} x ptr mem)
+ for {
+ t := v.Type
+ g := v.Args[0]
+ if g.Op != OpS390XMOVWZload {
+ 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)) {
+ break
+ }
+ v.reset(OpS390XXORWload)
+ v.Type = t
+ v.AuxInt = off
+ v.Aux = sym
+ v.AddArg(x)
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValueS390X_OpS390XXORWconst(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (XORWconst [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: (XORWconst [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_OpS390XXORconst(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (XORconst [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: (XORconst [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_OpSelect0(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Select0 <t> (AddTupleFirst32 tuple val))
+ // cond:
+ // result: (ADDW val (Select0 <t> tuple))
+ for {
+ t := v.Type
+ v_0 := v.Args[0]
+ if v_0.Op != OpS390XAddTupleFirst32 {
+ break
+ }
+ tuple := v_0.Args[0]
+ val := v_0.Args[1]
+ v.reset(OpS390XADDW)
+ v.AddArg(val)
+ v0 := b.NewValue0(v.Line, OpSelect0, t)
+ v0.AddArg(tuple)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (Select0 <t> (AddTupleFirst64 tuple val))
+ // cond:
+ // result: (ADD val (Select0 <t> tuple))
+ for {
+ t := v.Type
+ v_0 := v.Args[0]
+ if v_0.Op != OpS390XAddTupleFirst64 {
+ break
+ }
+ tuple := v_0.Args[0]
+ val := v_0.Args[1]
+ v.reset(OpS390XADD)
+ v.AddArg(val)
+ v0 := b.NewValue0(v.Line, 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 _ ))
+ // cond:
+ // result: (Select1 tuple)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpS390XAddTupleFirst32 {
+ 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 != OpS390XAddTupleFirst64 {
+ break
+ }
+ tuple := v_0.Args[0]
+ v.reset(OpSelect1)
+ v.AddArg(tuple)
+ return true
+ }
+ return false
+}
+func rewriteValueS390X_OpSignExt16to32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SignExt16to32 x)
+ // cond:
+ // result: (MOVHreg x)
+ for {
+ x := v.Args[0]
+ v.reset(OpS390XMOVHreg)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueS390X_OpSignExt16to64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SignExt16to64 x)
+ // cond:
+ // result: (MOVHreg x)
+ for {
+ x := v.Args[0]
+ v.reset(OpS390XMOVHreg)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueS390X_OpSignExt32to64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SignExt32to64 x)
+ // cond:
+ // result: (MOVWreg x)
+ for {
+ x := v.Args[0]
+ v.reset(OpS390XMOVWreg)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueS390X_OpSignExt8to16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SignExt8to16 x)
+ // cond:
+ // result: (MOVBreg x)
+ for {
+ x := v.Args[0]
+ v.reset(OpS390XMOVBreg)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueS390X_OpSignExt8to32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SignExt8to32 x)
+ // cond:
+ // result: (MOVBreg x)
+ for {
+ x := v.Args[0]
+ v.reset(OpS390XMOVBreg)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueS390X_OpSignExt8to64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SignExt8to64 x)
+ // cond:
+ // result: (MOVBreg x)
+ for {
+ x := v.Args[0]
+ v.reset(OpS390XMOVBreg)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueS390X_OpSlicemask(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Slicemask <t> x)
+ // cond:
+ // result: (XOR (MOVDconst [-1]) (SRADconst <t> (SUBconst <t> x [1]) [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.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
+ // match: (Sqrt x)
+ // cond:
+ // result: (FSQRT x)
+ for {
+ x := v.Args[0]
+ v.reset(OpS390XFSQRT)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueS390X_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(OpS390XCALLstatic)
+ v.AuxInt = argwid
+ v.Aux = target
+ v.AddArg(mem)
+ return true
+ }
+}
+func rewriteValueS390X_OpStore(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Store [8] ptr val mem)
+ // cond: is64BitFloat(val.Type)
+ // result: (FMOVDstore ptr val mem)
+ for {
+ if v.AuxInt != 8 {
+ break
+ }
+ ptr := v.Args[0]
+ val := v.Args[1]
+ mem := v.Args[2]
+ if !(is64BitFloat(val.Type)) {
+ break
+ }
+ v.reset(OpS390XFMOVDstore)
+ v.AddArg(ptr)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (Store [4] ptr val mem)
+ // cond: is32BitFloat(val.Type)
+ // result: (FMOVSstore ptr val mem)
+ for {
+ if v.AuxInt != 4 {
+ break
+ }
+ ptr := v.Args[0]
+ val := v.Args[1]
+ mem := v.Args[2]
+ if !(is32BitFloat(val.Type)) {
+ break
+ }
+ v.reset(OpS390XFMOVSstore)
+ v.AddArg(ptr)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (Store [8] ptr val mem)
+ // cond:
+ // result: (MOVDstore ptr val mem)
+ for {
+ if v.AuxInt != 8 {
+ break
+ }
+ ptr := v.Args[0]
+ val := v.Args[1]
+ mem := v.Args[2]
+ v.reset(OpS390XMOVDstore)
+ v.AddArg(ptr)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (Store [4] ptr val mem)
+ // cond:
+ // result: (MOVWstore ptr val mem)
+ for {
+ if v.AuxInt != 4 {
+ break
+ }
+ ptr := v.Args[0]
+ val := v.Args[1]
+ mem := v.Args[2]
+ v.reset(OpS390XMOVWstore)
+ 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 {
+ break
+ }
+ ptr := v.Args[0]
+ val := v.Args[1]
+ mem := v.Args[2]
+ v.reset(OpS390XMOVHstore)
+ v.AddArg(ptr)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (Store [1] ptr val mem)
+ // cond:
+ // result: (MOVBstore ptr val mem)
+ for {
+ if v.AuxInt != 1 {
+ break
+ }
+ ptr := v.Args[0]
+ val := v.Args[1]
+ mem := v.Args[2]
+ v.reset(OpS390XMOVBstore)
+ v.AddArg(ptr)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValueS390X_OpSub16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Sub16 x y)
+ // cond:
+ // result: (SUBW x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XSUBW)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueS390X_OpSub32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Sub32 x y)
+ // cond:
+ // result: (SUBW x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XSUBW)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueS390X_OpSub32F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Sub32F x y)
+ // cond:
+ // result: (FSUBS x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XFSUBS)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueS390X_OpSub64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Sub64 x y)
+ // cond:
+ // result: (SUB x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XSUB)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueS390X_OpSub64F(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Sub64F x y)
+ // cond:
+ // result: (FSUB x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XFSUB)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueS390X_OpSub8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Sub8 x y)
+ // cond:
+ // result: (SUBW x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XSUBW)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueS390X_OpSubPtr(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SubPtr x y)
+ // cond:
+ // result: (SUB x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XSUB)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueS390X_OpTrunc16to8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Trunc16to8 x)
+ // cond:
+ // result: x
+ for {
+ x := v.Args[0]
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueS390X_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 rewriteValueS390X_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 rewriteValueS390X_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 rewriteValueS390X_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 rewriteValueS390X_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 rewriteValueS390X_OpXor16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Xor16 x y)
+ // cond:
+ // result: (XORW x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XXORW)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueS390X_OpXor32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Xor32 x y)
+ // cond:
+ // result: (XORW x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XXORW)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueS390X_OpXor64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Xor64 x y)
+ // cond:
+ // result: (XOR x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XXOR)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueS390X_OpXor8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Xor8 x y)
+ // cond:
+ // result: (XORW x y)
+ for {
+ x := v.Args[0]
+ y := v.Args[1]
+ v.reset(OpS390XXORW)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+}
+func rewriteValueS390X_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) {
+ 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) {
+ break
+ }
+ v.reset(OpS390XMOVBstoreconst)
+ v.AuxInt = 0
+ v.AddArg(destptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (Zero [s] destptr mem)
+ // cond: SizeAndAlign(s).Size() == 2
+ // result: (MOVHstoreconst [0] destptr mem)
+ for {
+ s := v.AuxInt
+ destptr := v.Args[0]
+ mem := v.Args[1]
+ if !(SizeAndAlign(s).Size() == 2) {
+ break
+ }
+ v.reset(OpS390XMOVHstoreconst)
+ v.AuxInt = 0
+ v.AddArg(destptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (Zero [s] destptr mem)
+ // cond: SizeAndAlign(s).Size() == 4
+ // result: (MOVWstoreconst [0] destptr mem)
+ for {
+ s := v.AuxInt
+ destptr := v.Args[0]
+ mem := v.Args[1]
+ if !(SizeAndAlign(s).Size() == 4) {
+ break
+ }
+ v.reset(OpS390XMOVWstoreconst)
+ v.AuxInt = 0
+ v.AddArg(destptr)
+ v.AddArg(mem)
+ return true
+ }
+ // match: (Zero [s] destptr mem)
+ // cond: SizeAndAlign(s).Size() == 8
+ // result: (MOVDstoreconst [0] destptr mem)
+ for {
+ s := v.AuxInt
+ destptr := v.Args[0]
+ mem := v.Args[1]
+ if !(SizeAndAlign(s).Size() == 8) {
+ break
+ }
+ v.reset(OpS390XMOVDstoreconst)
+ 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 (MOVHstoreconst [0] destptr mem))
+ for {
+ s := v.AuxInt
+ destptr := v.Args[0]
+ mem := v.Args[1]
+ if !(SizeAndAlign(s).Size() == 3) {
+ break
+ }
+ v.reset(OpS390XMOVBstoreconst)
+ v.AuxInt = makeValAndOff(0, 2)
+ v.AddArg(destptr)
+ v0 := b.NewValue0(v.Line, OpS390XMOVHstoreconst, 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 (MOVWstoreconst [0] destptr mem))
+ for {
+ s := v.AuxInt
+ destptr := v.Args[0]
+ mem := v.Args[1]
+ if !(SizeAndAlign(s).Size() == 5) {
+ break
+ }
+ v.reset(OpS390XMOVBstoreconst)
+ v.AuxInt = makeValAndOff(0, 4)
+ v.AddArg(destptr)
+ v0 := b.NewValue0(v.Line, OpS390XMOVWstoreconst, 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: (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) {
+ break
+ }
+ v.reset(OpS390XMOVHstoreconst)
+ v.AuxInt = makeValAndOff(0, 4)
+ v.AddArg(destptr)
+ v0 := b.NewValue0(v.Line, OpS390XMOVWstoreconst, 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: (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) {
+ break
+ }
+ v.reset(OpS390XMOVWstoreconst)
+ v.AuxInt = makeValAndOff(0, 3)
+ v.AddArg(destptr)
+ v0 := b.NewValue0(v.Line, OpS390XMOVWstoreconst, TypeMem)
+ v0.AuxInt = 0
+ v0.AddArg(destptr)
+ v0.AddArg(mem)
+ v.AddArg(v0)
+ 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)
+ for {
+ s := v.AuxInt
+ destptr := v.Args[0]
+ mem := v.Args[1]
+ if !(SizeAndAlign(s).Size() > 0 && SizeAndAlign(s).Size() <= 1024) {
+ break
+ }
+ v.reset(OpS390XCLEAR)
+ v.AuxInt = makeValAndOff(SizeAndAlign(s).Size(), 0)
+ v.AddArg(destptr)
+ v.AddArg(mem)
+ return true
+ }
+ // 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)
+ for {
+ s := v.AuxInt
+ destptr := v.Args[0]
+ mem := v.Args[1]
+ if !(SizeAndAlign(s).Size() > 1024) {
+ break
+ }
+ v.reset(OpS390XLoweredZero)
+ v.AuxInt = SizeAndAlign(s).Size() % 256
+ v.AddArg(destptr)
+ v0 := b.NewValue0(v.Line, OpS390XADDconst, destptr.Type)
+ v0.AuxInt = (SizeAndAlign(s).Size() / 256) * 256
+ v0.AddArg(destptr)
+ v.AddArg(v0)
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValueS390X_OpZeroExt16to32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ZeroExt16to32 x)
+ // cond:
+ // result: (MOVHZreg x)
+ for {
+ x := v.Args[0]
+ v.reset(OpS390XMOVHZreg)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueS390X_OpZeroExt16to64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ZeroExt16to64 x)
+ // cond:
+ // result: (MOVHZreg x)
+ for {
+ x := v.Args[0]
+ v.reset(OpS390XMOVHZreg)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueS390X_OpZeroExt32to64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ZeroExt32to64 x)
+ // cond:
+ // result: (MOVWZreg x)
+ for {
+ x := v.Args[0]
+ v.reset(OpS390XMOVWZreg)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueS390X_OpZeroExt8to16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ZeroExt8to16 x)
+ // cond:
+ // result: (MOVBZreg x)
+ for {
+ x := v.Args[0]
+ v.reset(OpS390XMOVBZreg)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueS390X_OpZeroExt8to32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ZeroExt8to32 x)
+ // cond:
+ // result: (MOVBZreg x)
+ for {
+ x := v.Args[0]
+ v.reset(OpS390XMOVBZreg)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValueS390X_OpZeroExt8to64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ZeroExt8to64 x)
+ // cond:
+ // result: (MOVBZreg x)
+ for {
+ x := v.Args[0]
+ v.reset(OpS390XMOVBZreg)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteBlockS390X(b *Block, config *Config) bool {
+ switch b.Kind {
+ case BlockS390XEQ:
+ // match: (EQ (InvertFlags cmp) yes no)
+ // cond:
+ // result: (EQ cmp yes no)
+ for {
+ v := b.Control
+ if v.Op != OpS390XInvertFlags {
+ 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)
+ // cond:
+ // result: (First nil yes no)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil no yes)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil no yes)
+ for {
+ v := b.Control
+ 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:
+ // match: (GE (InvertFlags cmp) yes no)
+ // cond:
+ // result: (LE cmp yes no)
+ for {
+ v := b.Control
+ if v.Op != OpS390XInvertFlags {
+ 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)
+ // cond:
+ // result: (First nil yes no)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil no yes)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil yes no)
+ for {
+ v := b.Control
+ 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:
+ // match: (GT (InvertFlags cmp) yes no)
+ // cond:
+ // result: (LT cmp yes no)
+ for {
+ v := b.Control
+ if v.Op != OpS390XInvertFlags {
+ 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)
+ // cond:
+ // result: (First nil no yes)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil no yes)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil yes no)
+ for {
+ v := b.Control
+ 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:
+ // match: (If (MOVDLT (MOVDconst [0]) (MOVDconst [1]) cmp) yes no)
+ // cond:
+ // result: (LT cmp yes no)
+ for {
+ v := b.Control
+ if v.Op != OpS390XMOVDLT {
+ break
+ }
+ v_0 := v.Args[0]
+ if v_0.Op != OpS390XMOVDconst {
+ break
+ }
+ if v_0.AuxInt != 0 {
+ break
+ }
+ v_1 := v.Args[1]
+ if v_1.Op != OpS390XMOVDconst {
+ break
+ }
+ if v_1.AuxInt != 1 {
+ 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)
+ // cond:
+ // result: (LE cmp yes no)
+ for {
+ v := b.Control
+ if v.Op != OpS390XMOVDLE {
+ break
+ }
+ v_0 := v.Args[0]
+ if v_0.Op != OpS390XMOVDconst {
+ break
+ }
+ if v_0.AuxInt != 0 {
+ break
+ }
+ v_1 := v.Args[1]
+ if v_1.Op != OpS390XMOVDconst {
+ break
+ }
+ if v_1.AuxInt != 1 {
+ 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)
+ // cond:
+ // result: (GT cmp yes no)
+ for {
+ v := b.Control
+ if v.Op != OpS390XMOVDGT {
+ break
+ }
+ v_0 := v.Args[0]
+ if v_0.Op != OpS390XMOVDconst {
+ break
+ }
+ if v_0.AuxInt != 0 {
+ break
+ }
+ v_1 := v.Args[1]
+ if v_1.Op != OpS390XMOVDconst {
+ break
+ }
+ if v_1.AuxInt != 1 {
+ 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)
+ // cond:
+ // result: (GE cmp yes no)
+ for {
+ v := b.Control
+ if v.Op != OpS390XMOVDGE {
+ break
+ }
+ v_0 := v.Args[0]
+ if v_0.Op != OpS390XMOVDconst {
+ break
+ }
+ if v_0.AuxInt != 0 {
+ break
+ }
+ v_1 := v.Args[1]
+ if v_1.Op != OpS390XMOVDconst {
+ break
+ }
+ if v_1.AuxInt != 1 {
+ 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)
+ // cond:
+ // result: (EQ cmp yes no)
+ for {
+ v := b.Control
+ if v.Op != OpS390XMOVDEQ {
+ break
+ }
+ v_0 := v.Args[0]
+ if v_0.Op != OpS390XMOVDconst {
+ break
+ }
+ if v_0.AuxInt != 0 {
+ break
+ }
+ v_1 := v.Args[1]
+ if v_1.Op != OpS390XMOVDconst {
+ break
+ }
+ if v_1.AuxInt != 1 {
+ 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)
+ // cond:
+ // result: (NE cmp yes no)
+ for {
+ v := b.Control
+ if v.Op != OpS390XMOVDNE {
+ break
+ }
+ v_0 := v.Args[0]
+ if v_0.Op != OpS390XMOVDconst {
+ break
+ }
+ if v_0.AuxInt != 0 {
+ break
+ }
+ v_1 := v.Args[1]
+ if v_1.Op != OpS390XMOVDconst {
+ break
+ }
+ if v_1.AuxInt != 1 {
+ 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)
+ // cond:
+ // result: (GTF cmp yes no)
+ for {
+ v := b.Control
+ if v.Op != OpS390XMOVDGTnoinv {
+ break
+ }
+ v_0 := v.Args[0]
+ if v_0.Op != OpS390XMOVDconst {
+ break
+ }
+ if v_0.AuxInt != 0 {
+ break
+ }
+ v_1 := v.Args[1]
+ if v_1.Op != OpS390XMOVDconst {
+ break
+ }
+ if v_1.AuxInt != 1 {
+ 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)
+ // cond:
+ // result: (GEF cmp yes no)
+ for {
+ v := b.Control
+ if v.Op != OpS390XMOVDGEnoinv {
+ break
+ }
+ v_0 := v.Args[0]
+ if v_0.Op != OpS390XMOVDconst {
+ break
+ }
+ if v_0.AuxInt != 0 {
+ break
+ }
+ v_1 := v.Args[1]
+ if v_1.Op != OpS390XMOVDconst {
+ break
+ }
+ if v_1.AuxInt != 1 {
+ 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 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.AuxInt = 0
+ v1 := b.NewValue0(v.Line, OpS390XMOVBZreg, config.fe.TypeUInt64())
+ v1.AddArg(cond)
+ v0.AddArg(v1)
+ b.SetControl(v0)
+ _ = yes
+ _ = no
+ return true
+ }
+ case BlockS390XLE:
+ // match: (LE (InvertFlags cmp) yes no)
+ // cond:
+ // result: (GE cmp yes no)
+ for {
+ v := b.Control
+ if v.Op != OpS390XInvertFlags {
+ 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)
+ // cond:
+ // result: (First nil yes no)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil yes no)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil no yes)
+ for {
+ v := b.Control
+ 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:
+ // match: (LT (InvertFlags cmp) yes no)
+ // cond:
+ // result: (GT cmp yes no)
+ for {
+ v := b.Control
+ if v.Op != OpS390XInvertFlags {
+ 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)
+ // cond:
+ // result: (First nil no yes)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil yes no)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil no yes)
+ for {
+ v := b.Control
+ 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:
+ // match: (NE (CMPWconst [0] (MOVDLT (MOVDconst [0]) (MOVDconst [1]) cmp)) yes no)
+ // cond:
+ // result: (LT cmp yes no)
+ for {
+ v := b.Control
+ if v.Op != OpS390XCMPWconst {
+ break
+ }
+ if v.AuxInt != 0 {
+ break
+ }
+ v_0 := v.Args[0]
+ if v_0.Op != OpS390XMOVDLT {
+ break
+ }
+ v_0_0 := v_0.Args[0]
+ if v_0_0.Op != OpS390XMOVDconst {
+ break
+ }
+ if v_0_0.AuxInt != 0 {
+ break
+ }
+ v_0_1 := v_0.Args[1]
+ if v_0_1.Op != OpS390XMOVDconst {
+ break
+ }
+ if v_0_1.AuxInt != 1 {
+ 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)
+ // cond:
+ // result: (LE cmp yes no)
+ for {
+ v := b.Control
+ if v.Op != OpS390XCMPWconst {
+ break
+ }
+ if v.AuxInt != 0 {
+ break
+ }
+ v_0 := v.Args[0]
+ if v_0.Op != OpS390XMOVDLE {
+ break
+ }
+ v_0_0 := v_0.Args[0]
+ if v_0_0.Op != OpS390XMOVDconst {
+ break
+ }
+ if v_0_0.AuxInt != 0 {
+ break
+ }
+ v_0_1 := v_0.Args[1]
+ if v_0_1.Op != OpS390XMOVDconst {
+ break
+ }
+ if v_0_1.AuxInt != 1 {
+ 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)
+ // cond:
+ // result: (GT cmp yes no)
+ for {
+ v := b.Control
+ if v.Op != OpS390XCMPWconst {
+ break
+ }
+ if v.AuxInt != 0 {
+ break
+ }
+ v_0 := v.Args[0]
+ if v_0.Op != OpS390XMOVDGT {
+ break
+ }
+ v_0_0 := v_0.Args[0]
+ if v_0_0.Op != OpS390XMOVDconst {
+ break
+ }
+ if v_0_0.AuxInt != 0 {
+ break
+ }
+ v_0_1 := v_0.Args[1]
+ if v_0_1.Op != OpS390XMOVDconst {
+ break
+ }
+ if v_0_1.AuxInt != 1 {
+ 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)
+ // cond:
+ // result: (GE cmp yes no)
+ for {
+ v := b.Control
+ if v.Op != OpS390XCMPWconst {
+ break
+ }
+ if v.AuxInt != 0 {
+ break
+ }
+ v_0 := v.Args[0]
+ if v_0.Op != OpS390XMOVDGE {
+ break
+ }
+ v_0_0 := v_0.Args[0]
+ if v_0_0.Op != OpS390XMOVDconst {
+ break
+ }
+ if v_0_0.AuxInt != 0 {
+ break
+ }
+ v_0_1 := v_0.Args[1]
+ if v_0_1.Op != OpS390XMOVDconst {
+ break
+ }
+ if v_0_1.AuxInt != 1 {
+ 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)
+ // cond:
+ // result: (EQ cmp yes no)
+ for {
+ v := b.Control
+ if v.Op != OpS390XCMPWconst {
+ break
+ }
+ if v.AuxInt != 0 {
+ break
+ }
+ v_0 := v.Args[0]
+ if v_0.Op != OpS390XMOVDEQ {
+ break
+ }
+ v_0_0 := v_0.Args[0]
+ if v_0_0.Op != OpS390XMOVDconst {
+ break
+ }
+ if v_0_0.AuxInt != 0 {
+ break
+ }
+ v_0_1 := v_0.Args[1]
+ if v_0_1.Op != OpS390XMOVDconst {
+ break
+ }
+ if v_0_1.AuxInt != 1 {
+ 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)
+ // cond:
+ // result: (NE cmp yes no)
+ for {
+ v := b.Control
+ if v.Op != OpS390XCMPWconst {
+ break
+ }
+ if v.AuxInt != 0 {
+ break
+ }
+ v_0 := v.Args[0]
+ if v_0.Op != OpS390XMOVDNE {
+ break
+ }
+ v_0_0 := v_0.Args[0]
+ if v_0_0.Op != OpS390XMOVDconst {
+ break
+ }
+ if v_0_0.AuxInt != 0 {
+ break
+ }
+ v_0_1 := v_0.Args[1]
+ if v_0_1.Op != OpS390XMOVDconst {
+ break
+ }
+ if v_0_1.AuxInt != 1 {
+ 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)
+ // cond:
+ // result: (GTF cmp yes no)
+ for {
+ v := b.Control
+ if v.Op != OpS390XCMPWconst {
+ break
+ }
+ if v.AuxInt != 0 {
+ break
+ }
+ v_0 := v.Args[0]
+ if v_0.Op != OpS390XMOVDGTnoinv {
+ break
+ }
+ v_0_0 := v_0.Args[0]
+ if v_0_0.Op != OpS390XMOVDconst {
+ break
+ }
+ if v_0_0.AuxInt != 0 {
+ break
+ }
+ v_0_1 := v_0.Args[1]
+ if v_0_1.Op != OpS390XMOVDconst {
+ break
+ }
+ if v_0_1.AuxInt != 1 {
+ 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)
+ // cond:
+ // result: (GEF cmp yes no)
+ for {
+ v := b.Control
+ if v.Op != OpS390XCMPWconst {
+ break
+ }
+ if v.AuxInt != 0 {
+ break
+ }
+ v_0 := v.Args[0]
+ if v_0.Op != OpS390XMOVDGEnoinv {
+ break
+ }
+ v_0_0 := v_0.Args[0]
+ if v_0_0.Op != OpS390XMOVDconst {
+ break
+ }
+ if v_0_0.AuxInt != 0 {
+ break
+ }
+ v_0_1 := v_0.Args[1]
+ if v_0_1.Op != OpS390XMOVDconst {
+ break
+ }
+ if v_0_1.AuxInt != 1 {
+ 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)
+ // cond:
+ // result: (NE cmp yes no)
+ for {
+ v := b.Control
+ if v.Op != OpS390XInvertFlags {
+ 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)
+ // cond:
+ // result: (First nil no yes)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil yes no)
+ for {
+ v := b.Control
+ 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)
+ // cond:
+ // result: (First nil yes no)
+ for {
+ v := b.Control
+ if v.Op != OpS390XFlagGT {
+ break
+ }
+ yes := b.Succs[0]
+ no := b.Succs[1]
+ b.Kind = BlockFirst
+ b.SetControl(nil)
+ _ = yes
+ _ = no
+ return true
+ }
+ }
+ return false
+}
diff --git a/src/cmd/compile/internal/ssa/rewrite_test.go b/src/cmd/compile/internal/ssa/rewrite_test.go
index b786df8..7bd32ff 100644
--- a/src/cmd/compile/internal/ssa/rewrite_test.go
+++ b/src/cmd/compile/internal/ssa/rewrite_test.go
@@ -92,6 +92,9 @@ func TestLog2(t *testing.T) {
{1, 0},
{2, 1},
{4, 2},
+ {7, 2},
+ {8, 3},
+ {9, 3},
{1024, 10}}
for _, tc := range log2Tests {
diff --git a/src/cmd/compile/internal/ssa/rewritedec.go b/src/cmd/compile/internal/ssa/rewritedec.go
index c32d54e..fd52751 100644
--- a/src/cmd/compile/internal/ssa/rewritedec.go
+++ b/src/cmd/compile/internal/ssa/rewritedec.go
@@ -500,7 +500,7 @@ func rewriteValuedec_OpStringPtr(v *Value, config *Config) bool {
}
return false
}
-func rewriteBlockdec(b *Block) bool {
+func rewriteBlockdec(b *Block, config *Config) bool {
switch b.Kind {
}
return false
diff --git a/src/cmd/compile/internal/ssa/rewritedec64.go b/src/cmd/compile/internal/ssa/rewritedec64.go
new file mode 100644
index 0000000..deca007
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/rewritedec64.go
@@ -0,0 +1,2720 @@
+// autogenerated from gen/dec64.rules: do not edit!
+// generated with: cd gen; go run *.go
+
+package ssa
+
+import "math"
+
+var _ = math.MinInt8 // in case not otherwise used
+func rewriteValuedec64(v *Value, config *Config) bool {
+ switch v.Op {
+ case OpAdd64:
+ return rewriteValuedec64_OpAdd64(v, config)
+ case OpAnd64:
+ return rewriteValuedec64_OpAnd64(v, config)
+ case OpArg:
+ return rewriteValuedec64_OpArg(v, config)
+ case OpBswap64:
+ return rewriteValuedec64_OpBswap64(v, config)
+ case OpCom64:
+ return rewriteValuedec64_OpCom64(v, config)
+ case OpConst64:
+ return rewriteValuedec64_OpConst64(v, config)
+ case OpCtz64:
+ return rewriteValuedec64_OpCtz64(v, config)
+ case OpEq64:
+ return rewriteValuedec64_OpEq64(v, config)
+ case OpGeq64:
+ return rewriteValuedec64_OpGeq64(v, config)
+ case OpGeq64U:
+ return rewriteValuedec64_OpGeq64U(v, config)
+ case OpGreater64:
+ return rewriteValuedec64_OpGreater64(v, config)
+ case OpGreater64U:
+ return rewriteValuedec64_OpGreater64U(v, config)
+ case OpInt64Hi:
+ return rewriteValuedec64_OpInt64Hi(v, config)
+ case OpInt64Lo:
+ return rewriteValuedec64_OpInt64Lo(v, config)
+ case OpLeq64:
+ return rewriteValuedec64_OpLeq64(v, config)
+ case OpLeq64U:
+ return rewriteValuedec64_OpLeq64U(v, config)
+ case OpLess64:
+ return rewriteValuedec64_OpLess64(v, config)
+ case OpLess64U:
+ return rewriteValuedec64_OpLess64U(v, config)
+ case OpLoad:
+ return rewriteValuedec64_OpLoad(v, config)
+ case OpLrot64:
+ return rewriteValuedec64_OpLrot64(v, config)
+ case OpLsh16x64:
+ return rewriteValuedec64_OpLsh16x64(v, config)
+ case OpLsh32x64:
+ return rewriteValuedec64_OpLsh32x64(v, config)
+ case OpLsh64x16:
+ return rewriteValuedec64_OpLsh64x16(v, config)
+ case OpLsh64x32:
+ return rewriteValuedec64_OpLsh64x32(v, config)
+ case OpLsh64x64:
+ return rewriteValuedec64_OpLsh64x64(v, config)
+ case OpLsh64x8:
+ return rewriteValuedec64_OpLsh64x8(v, config)
+ case OpLsh8x64:
+ return rewriteValuedec64_OpLsh8x64(v, config)
+ case OpMul64:
+ return rewriteValuedec64_OpMul64(v, config)
+ case OpNeg64:
+ return rewriteValuedec64_OpNeg64(v, config)
+ case OpNeq64:
+ return rewriteValuedec64_OpNeq64(v, config)
+ case OpOr64:
+ return rewriteValuedec64_OpOr64(v, config)
+ case OpRsh16Ux64:
+ return rewriteValuedec64_OpRsh16Ux64(v, config)
+ case OpRsh16x64:
+ return rewriteValuedec64_OpRsh16x64(v, config)
+ case OpRsh32Ux64:
+ return rewriteValuedec64_OpRsh32Ux64(v, config)
+ case OpRsh32x64:
+ return rewriteValuedec64_OpRsh32x64(v, config)
+ case OpRsh64Ux16:
+ return rewriteValuedec64_OpRsh64Ux16(v, config)
+ case OpRsh64Ux32:
+ return rewriteValuedec64_OpRsh64Ux32(v, config)
+ case OpRsh64Ux64:
+ return rewriteValuedec64_OpRsh64Ux64(v, config)
+ case OpRsh64Ux8:
+ return rewriteValuedec64_OpRsh64Ux8(v, config)
+ case OpRsh64x16:
+ return rewriteValuedec64_OpRsh64x16(v, config)
+ case OpRsh64x32:
+ return rewriteValuedec64_OpRsh64x32(v, config)
+ case OpRsh64x64:
+ return rewriteValuedec64_OpRsh64x64(v, config)
+ case OpRsh64x8:
+ return rewriteValuedec64_OpRsh64x8(v, config)
+ case OpRsh8Ux64:
+ return rewriteValuedec64_OpRsh8Ux64(v, config)
+ case OpRsh8x64:
+ return rewriteValuedec64_OpRsh8x64(v, config)
+ case OpSignExt16to64:
+ return rewriteValuedec64_OpSignExt16to64(v, config)
+ case OpSignExt32to64:
+ return rewriteValuedec64_OpSignExt32to64(v, config)
+ case OpSignExt8to64:
+ return rewriteValuedec64_OpSignExt8to64(v, config)
+ case OpStore:
+ return rewriteValuedec64_OpStore(v, config)
+ case OpSub64:
+ return rewriteValuedec64_OpSub64(v, config)
+ case OpTrunc64to16:
+ return rewriteValuedec64_OpTrunc64to16(v, config)
+ case OpTrunc64to32:
+ return rewriteValuedec64_OpTrunc64to32(v, config)
+ case OpTrunc64to8:
+ return rewriteValuedec64_OpTrunc64to8(v, config)
+ case OpXor64:
+ return rewriteValuedec64_OpXor64(v, config)
+ case OpZeroExt16to64:
+ return rewriteValuedec64_OpZeroExt16to64(v, config)
+ case OpZeroExt32to64:
+ return rewriteValuedec64_OpZeroExt32to64(v, config)
+ case OpZeroExt8to64:
+ return rewriteValuedec64_OpZeroExt8to64(v, config)
+ }
+ return false
+}
+func rewriteValuedec64_OpAdd64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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))))
+ for {
+ 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())
+ v1.AddArg(x)
+ v0.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpInt64Hi, config.fe.TypeUInt32())
+ 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())
+ v5.AddArg(x)
+ v4.AddArg(v5)
+ v6 := b.NewValue0(v.Line, OpInt64Lo, config.fe.TypeUInt32())
+ 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())
+ v9.AddArg(x)
+ v8.AddArg(v9)
+ v10 := b.NewValue0(v.Line, OpInt64Lo, config.fe.TypeUInt32())
+ v10.AddArg(y)
+ v8.AddArg(v10)
+ v7.AddArg(v8)
+ v.AddArg(v7)
+ return true
+ }
+}
+func rewriteValuedec64_OpAnd64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (And64 x y)
+ // cond:
+ // result: (Int64Make (And32 <config.fe.TypeUInt32()> (Int64Hi x) (Int64Hi y)) (And32 <config.fe.TypeUInt32()> (Int64Lo x) (Int64Lo y)))
+ for {
+ 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())
+ v1.AddArg(x)
+ v0.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpInt64Hi, config.fe.TypeUInt32())
+ 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())
+ v4.AddArg(x)
+ v3.AddArg(v4)
+ v5 := b.NewValue0(v.Line, OpInt64Lo, config.fe.TypeUInt32())
+ v5.AddArg(y)
+ v3.AddArg(v5)
+ v.AddArg(v3)
+ return true
+ }
+}
+func rewriteValuedec64_OpArg(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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]))
+ for {
+ off := v.AuxInt
+ n := v.Aux
+ if !(is64BitInt(v.Type) && !config.BigEndian && v.Type.IsSigned()) {
+ break
+ }
+ v.reset(OpInt64Make)
+ v0 := b.NewValue0(v.Line, OpArg, config.fe.TypeInt32())
+ v0.AuxInt = off + 4
+ v0.Aux = n
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpArg, config.fe.TypeUInt32())
+ v1.AuxInt = off
+ v1.Aux = n
+ v.AddArg(v1)
+ return true
+ }
+ // 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]))
+ for {
+ off := v.AuxInt
+ n := v.Aux
+ if !(is64BitInt(v.Type) && !config.BigEndian && !v.Type.IsSigned()) {
+ break
+ }
+ v.reset(OpInt64Make)
+ v0 := b.NewValue0(v.Line, OpArg, config.fe.TypeUInt32())
+ v0.AuxInt = off + 4
+ v0.Aux = n
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpArg, config.fe.TypeUInt32())
+ v1.AuxInt = off
+ v1.Aux = n
+ v.AddArg(v1)
+ return true
+ }
+ // 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]))
+ for {
+ off := v.AuxInt
+ n := v.Aux
+ if !(is64BitInt(v.Type) && config.BigEndian && v.Type.IsSigned()) {
+ break
+ }
+ v.reset(OpInt64Make)
+ v0 := b.NewValue0(v.Line, OpArg, config.fe.TypeInt32())
+ v0.AuxInt = off
+ v0.Aux = n
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpArg, config.fe.TypeUInt32())
+ v1.AuxInt = off + 4
+ v1.Aux = n
+ v.AddArg(v1)
+ return true
+ }
+ // 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]))
+ for {
+ off := v.AuxInt
+ n := v.Aux
+ if !(is64BitInt(v.Type) && config.BigEndian && !v.Type.IsSigned()) {
+ break
+ }
+ v.reset(OpInt64Make)
+ v0 := b.NewValue0(v.Line, OpArg, config.fe.TypeUInt32())
+ v0.AuxInt = off
+ v0.Aux = n
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpArg, config.fe.TypeUInt32())
+ v1.AuxInt = off + 4
+ v1.Aux = n
+ v.AddArg(v1)
+ return true
+ }
+ return false
+}
+func rewriteValuedec64_OpBswap64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Bswap64 x)
+ // cond:
+ // result: (Int64Make (Bswap32 <config.fe.TypeUInt32()> (Int64Lo x)) (Bswap32 <config.fe.TypeUInt32()> (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())
+ 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())
+ v3.AddArg(x)
+ v2.AddArg(v3)
+ v.AddArg(v2)
+ return true
+ }
+}
+func rewriteValuedec64_OpCom64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Com64 x)
+ // cond:
+ // result: (Int64Make (Com32 <config.fe.TypeUInt32()> (Int64Hi x)) (Com32 <config.fe.TypeUInt32()> (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())
+ 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())
+ v3.AddArg(x)
+ v2.AddArg(v3)
+ v.AddArg(v2)
+ return true
+ }
+}
+func rewriteValuedec64_OpConst64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Const64 <t> [c])
+ // cond: t.IsSigned()
+ // result: (Int64Make (Const32 <config.fe.TypeInt32()> [c>>32]) (Const32 <config.fe.TypeUInt32()> [int64(int32(c))]))
+ for {
+ t := v.Type
+ c := v.AuxInt
+ if !(t.IsSigned()) {
+ break
+ }
+ v.reset(OpInt64Make)
+ v0 := b.NewValue0(v.Line, OpConst32, config.fe.TypeInt32())
+ v0.AuxInt = c >> 32
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpConst32, config.fe.TypeUInt32())
+ 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))]))
+ for {
+ t := v.Type
+ c := v.AuxInt
+ if !(!t.IsSigned()) {
+ break
+ }
+ v.reset(OpInt64Make)
+ v0 := b.NewValue0(v.Line, OpConst32, config.fe.TypeUInt32())
+ v0.AuxInt = c >> 32
+ v.AddArg(v0)
+ v1 := b.NewValue0(v.Line, OpConst32, config.fe.TypeUInt32())
+ v1.AuxInt = int64(int32(c))
+ v.AddArg(v1)
+ return true
+ }
+ return false
+}
+func rewriteValuedec64_OpCtz64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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)))))
+ for {
+ x := v.Args[0]
+ v.reset(OpInt64Make)
+ v0 := b.NewValue0(v.Line, OpConst32, config.fe.TypeUInt32())
+ v0.AuxInt = 0
+ 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.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())
+ 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)
+ return true
+ }
+}
+func rewriteValuedec64_OpEq64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Eq64 x y)
+ // cond:
+ // result: (AndB (Eq32 (Int64Hi x) (Int64Hi y)) (Eq32 (Int64Lo x) (Int64Lo y)))
+ for {
+ 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())
+ v1.AddArg(x)
+ v0.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpInt64Hi, config.fe.TypeUInt32())
+ 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())
+ v4.AddArg(x)
+ v3.AddArg(v4)
+ v5 := b.NewValue0(v.Line, OpInt64Lo, config.fe.TypeUInt32())
+ v5.AddArg(y)
+ v3.AddArg(v5)
+ v.AddArg(v3)
+ return true
+ }
+}
+func rewriteValuedec64_OpGeq64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Geq64 x y)
+ // cond:
+ // result: (OrB (Greater32 (Int64Hi x) (Int64Hi y)) (AndB (Eq32 (Int64Hi x) (Int64Hi y)) (Geq32U (Int64Lo x) (Int64Lo y))))
+ for {
+ 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())
+ v1.AddArg(x)
+ v0.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpInt64Hi, config.fe.TypeUInt32())
+ 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())
+ v5.AddArg(x)
+ v4.AddArg(v5)
+ v6 := b.NewValue0(v.Line, OpInt64Hi, config.fe.TypeUInt32())
+ 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())
+ v8.AddArg(x)
+ v7.AddArg(v8)
+ v9 := b.NewValue0(v.Line, OpInt64Lo, config.fe.TypeUInt32())
+ v9.AddArg(y)
+ v7.AddArg(v9)
+ v3.AddArg(v7)
+ v.AddArg(v3)
+ return true
+ }
+}
+func rewriteValuedec64_OpGeq64U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Geq64U x y)
+ // cond:
+ // result: (OrB (Greater32U (Int64Hi x) (Int64Hi y)) (AndB (Eq32 (Int64Hi x) (Int64Hi y)) (Geq32U (Int64Lo x) (Int64Lo y))))
+ for {
+ 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())
+ v1.AddArg(x)
+ v0.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpInt64Hi, config.fe.TypeUInt32())
+ 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())
+ v5.AddArg(x)
+ v4.AddArg(v5)
+ v6 := b.NewValue0(v.Line, OpInt64Hi, config.fe.TypeUInt32())
+ 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())
+ v8.AddArg(x)
+ v7.AddArg(v8)
+ v9 := b.NewValue0(v.Line, OpInt64Lo, config.fe.TypeUInt32())
+ v9.AddArg(y)
+ v7.AddArg(v9)
+ v3.AddArg(v7)
+ v.AddArg(v3)
+ return true
+ }
+}
+func rewriteValuedec64_OpGreater64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Greater64 x y)
+ // cond:
+ // result: (OrB (Greater32 (Int64Hi x) (Int64Hi y)) (AndB (Eq32 (Int64Hi x) (Int64Hi y)) (Greater32U (Int64Lo x) (Int64Lo y))))
+ for {
+ 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())
+ v1.AddArg(x)
+ v0.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpInt64Hi, config.fe.TypeUInt32())
+ 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())
+ v5.AddArg(x)
+ v4.AddArg(v5)
+ v6 := b.NewValue0(v.Line, OpInt64Hi, config.fe.TypeUInt32())
+ 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())
+ v8.AddArg(x)
+ v7.AddArg(v8)
+ v9 := b.NewValue0(v.Line, OpInt64Lo, config.fe.TypeUInt32())
+ v9.AddArg(y)
+ v7.AddArg(v9)
+ v3.AddArg(v7)
+ v.AddArg(v3)
+ return true
+ }
+}
+func rewriteValuedec64_OpGreater64U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Greater64U x y)
+ // cond:
+ // result: (OrB (Greater32U (Int64Hi x) (Int64Hi y)) (AndB (Eq32 (Int64Hi x) (Int64Hi y)) (Greater32U (Int64Lo x) (Int64Lo y))))
+ for {
+ 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())
+ v1.AddArg(x)
+ v0.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpInt64Hi, config.fe.TypeUInt32())
+ 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())
+ v5.AddArg(x)
+ v4.AddArg(v5)
+ v6 := b.NewValue0(v.Line, OpInt64Hi, config.fe.TypeUInt32())
+ 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())
+ v8.AddArg(x)
+ v7.AddArg(v8)
+ v9 := b.NewValue0(v.Line, OpInt64Lo, config.fe.TypeUInt32())
+ v9.AddArg(y)
+ v7.AddArg(v9)
+ v3.AddArg(v7)
+ v.AddArg(v3)
+ return true
+ }
+}
+func rewriteValuedec64_OpInt64Hi(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Int64Hi (Int64Make hi _))
+ // cond:
+ // result: hi
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpInt64Make {
+ break
+ }
+ hi := v_0.Args[0]
+ v.reset(OpCopy)
+ v.Type = hi.Type
+ v.AddArg(hi)
+ return true
+ }
+ return false
+}
+func rewriteValuedec64_OpInt64Lo(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Int64Lo (Int64Make _ lo))
+ // cond:
+ // result: lo
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpInt64Make {
+ break
+ }
+ lo := v_0.Args[1]
+ v.reset(OpCopy)
+ v.Type = lo.Type
+ v.AddArg(lo)
+ return true
+ }
+ return false
+}
+func rewriteValuedec64_OpLeq64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Leq64 x y)
+ // cond:
+ // result: (OrB (Less32 (Int64Hi x) (Int64Hi y)) (AndB (Eq32 (Int64Hi x) (Int64Hi y)) (Leq32U (Int64Lo x) (Int64Lo y))))
+ for {
+ 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())
+ v1.AddArg(x)
+ v0.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpInt64Hi, config.fe.TypeUInt32())
+ 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())
+ v5.AddArg(x)
+ v4.AddArg(v5)
+ v6 := b.NewValue0(v.Line, OpInt64Hi, config.fe.TypeUInt32())
+ 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())
+ v8.AddArg(x)
+ v7.AddArg(v8)
+ v9 := b.NewValue0(v.Line, OpInt64Lo, config.fe.TypeUInt32())
+ v9.AddArg(y)
+ v7.AddArg(v9)
+ v3.AddArg(v7)
+ v.AddArg(v3)
+ return true
+ }
+}
+func rewriteValuedec64_OpLeq64U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Leq64U x y)
+ // cond:
+ // result: (OrB (Less32U (Int64Hi x) (Int64Hi y)) (AndB (Eq32 (Int64Hi x) (Int64Hi y)) (Leq32U (Int64Lo x) (Int64Lo y))))
+ for {
+ 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())
+ v1.AddArg(x)
+ v0.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpInt64Hi, config.fe.TypeUInt32())
+ 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())
+ v5.AddArg(x)
+ v4.AddArg(v5)
+ v6 := b.NewValue0(v.Line, OpInt64Hi, config.fe.TypeUInt32())
+ 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())
+ v8.AddArg(x)
+ v7.AddArg(v8)
+ v9 := b.NewValue0(v.Line, OpInt64Lo, config.fe.TypeUInt32())
+ v9.AddArg(y)
+ v7.AddArg(v9)
+ v3.AddArg(v7)
+ v.AddArg(v3)
+ return true
+ }
+}
+func rewriteValuedec64_OpLess64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Less64 x y)
+ // cond:
+ // result: (OrB (Less32 (Int64Hi x) (Int64Hi y)) (AndB (Eq32 (Int64Hi x) (Int64Hi y)) (Less32U (Int64Lo x) (Int64Lo y))))
+ for {
+ 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())
+ v1.AddArg(x)
+ v0.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpInt64Hi, config.fe.TypeUInt32())
+ 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())
+ v5.AddArg(x)
+ v4.AddArg(v5)
+ v6 := b.NewValue0(v.Line, OpInt64Hi, config.fe.TypeUInt32())
+ 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())
+ v8.AddArg(x)
+ v7.AddArg(v8)
+ v9 := b.NewValue0(v.Line, OpInt64Lo, config.fe.TypeUInt32())
+ v9.AddArg(y)
+ v7.AddArg(v9)
+ v3.AddArg(v7)
+ v.AddArg(v3)
+ return true
+ }
+}
+func rewriteValuedec64_OpLess64U(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Less64U x y)
+ // cond:
+ // result: (OrB (Less32U (Int64Hi x) (Int64Hi y)) (AndB (Eq32 (Int64Hi x) (Int64Hi y)) (Less32U (Int64Lo x) (Int64Lo y))))
+ for {
+ 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())
+ v1.AddArg(x)
+ v0.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpInt64Hi, config.fe.TypeUInt32())
+ 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())
+ v5.AddArg(x)
+ v4.AddArg(v5)
+ v6 := b.NewValue0(v.Line, OpInt64Hi, config.fe.TypeUInt32())
+ 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())
+ v8.AddArg(x)
+ v7.AddArg(v8)
+ v9 := b.NewValue0(v.Line, OpInt64Lo, config.fe.TypeUInt32())
+ v9.AddArg(y)
+ v7.AddArg(v9)
+ v3.AddArg(v7)
+ v.AddArg(v3)
+ return true
+ }
+}
+func rewriteValuedec64_OpLoad(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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))
+ for {
+ t := v.Type
+ 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())
+ 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.AddArg(ptr)
+ v2.AddArg(mem)
+ v.AddArg(v2)
+ return true
+ }
+ // 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))
+ for {
+ t := v.Type
+ 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())
+ 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.AddArg(ptr)
+ v2.AddArg(mem)
+ v.AddArg(v2)
+ return true
+ }
+ // 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))
+ for {
+ t := v.Type
+ 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.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())
+ v2.AuxInt = 4
+ v2.AddArg(ptr)
+ v1.AddArg(v2)
+ v1.AddArg(mem)
+ v.AddArg(v1)
+ return true
+ }
+ // 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))
+ for {
+ t := v.Type
+ 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.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())
+ v2.AuxInt = 4
+ v2.AddArg(ptr)
+ v1.AddArg(v2)
+ v1.AddArg(mem)
+ v.AddArg(v1)
+ return true
+ }
+ 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 {
+ b := v.Block
+ _ = b
+ // match: (Lsh16x64 _ (Int64Make (Const32 [c]) _))
+ // cond: c != 0
+ // result: (Const32 [0])
+ for {
+ v_1 := v.Args[1]
+ if v_1.Op != OpInt64Make {
+ break
+ }
+ v_1_0 := v_1.Args[0]
+ if v_1_0.Op != OpConst32 {
+ break
+ }
+ c := v_1_0.AuxInt
+ if !(c != 0) {
+ break
+ }
+ v.reset(OpConst32)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (Lsh16x64 x (Int64Make (Const32 [0]) lo))
+ // cond:
+ // result: (Lsh16x32 x lo)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpInt64Make {
+ break
+ }
+ v_1_0 := v_1.Args[0]
+ if v_1_0.Op != OpConst32 {
+ break
+ }
+ if v_1_0.AuxInt != 0 {
+ break
+ }
+ lo := v_1.Args[1]
+ v.reset(OpLsh16x32)
+ v.AddArg(x)
+ v.AddArg(lo)
+ return true
+ }
+ // match: (Lsh16x64 x (Int64Make hi lo))
+ // cond: hi.Op != OpConst32
+ // result: (Lsh16x32 x (Or32 <config.fe.TypeUInt32()> (Zeromask hi) lo))
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpInt64Make {
+ break
+ }
+ hi := v_1.Args[0]
+ lo := v_1.Args[1]
+ if !(hi.Op != OpConst32) {
+ break
+ }
+ v.reset(OpLsh16x32)
+ v.AddArg(x)
+ v0 := b.NewValue0(v.Line, OpOr32, config.fe.TypeUInt32())
+ v1 := b.NewValue0(v.Line, OpZeromask, config.fe.TypeUInt32())
+ v1.AddArg(hi)
+ v0.AddArg(v1)
+ v0.AddArg(lo)
+ v.AddArg(v0)
+ return true
+ }
+ return false
+}
+func rewriteValuedec64_OpLsh32x64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Lsh32x64 _ (Int64Make (Const32 [c]) _))
+ // cond: c != 0
+ // result: (Const32 [0])
+ for {
+ v_1 := v.Args[1]
+ if v_1.Op != OpInt64Make {
+ break
+ }
+ v_1_0 := v_1.Args[0]
+ if v_1_0.Op != OpConst32 {
+ break
+ }
+ c := v_1_0.AuxInt
+ if !(c != 0) {
+ break
+ }
+ v.reset(OpConst32)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (Lsh32x64 x (Int64Make (Const32 [0]) lo))
+ // cond:
+ // result: (Lsh32x32 x lo)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpInt64Make {
+ break
+ }
+ v_1_0 := v_1.Args[0]
+ if v_1_0.Op != OpConst32 {
+ break
+ }
+ if v_1_0.AuxInt != 0 {
+ break
+ }
+ lo := v_1.Args[1]
+ v.reset(OpLsh32x32)
+ v.AddArg(x)
+ v.AddArg(lo)
+ return true
+ }
+ // match: (Lsh32x64 x (Int64Make hi lo))
+ // cond: hi.Op != OpConst32
+ // result: (Lsh32x32 x (Or32 <config.fe.TypeUInt32()> (Zeromask hi) lo))
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpInt64Make {
+ break
+ }
+ hi := v_1.Args[0]
+ lo := v_1.Args[1]
+ if !(hi.Op != OpConst32) {
+ break
+ }
+ v.reset(OpLsh32x32)
+ v.AddArg(x)
+ v0 := b.NewValue0(v.Line, OpOr32, config.fe.TypeUInt32())
+ v1 := b.NewValue0(v.Line, OpZeromask, config.fe.TypeUInt32())
+ v1.AddArg(hi)
+ v0.AddArg(v1)
+ v0.AddArg(lo)
+ v.AddArg(v0)
+ return true
+ }
+ return false
+}
+func rewriteValuedec64_OpLsh64x16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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))
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpInt64Make {
+ break
+ }
+ 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())
+ v2.AddArg(hi)
+ v2.AddArg(s)
+ v1.AddArg(v2)
+ v3 := b.NewValue0(v.Line, OpRsh32Ux16, config.fe.TypeUInt32())
+ v3.AddArg(lo)
+ v4 := b.NewValue0(v.Line, OpSub16, config.fe.TypeUInt16())
+ v5 := b.NewValue0(v.Line, OpConst16, config.fe.TypeUInt16())
+ 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.AddArg(lo)
+ v7 := b.NewValue0(v.Line, OpSub16, config.fe.TypeUInt16())
+ v7.AddArg(s)
+ v8 := b.NewValue0(v.Line, OpConst16, config.fe.TypeUInt16())
+ 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.AddArg(lo)
+ v9.AddArg(s)
+ v.AddArg(v9)
+ return true
+ }
+ return false
+}
+func rewriteValuedec64_OpLsh64x32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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))
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpInt64Make {
+ break
+ }
+ 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())
+ v2.AddArg(hi)
+ v2.AddArg(s)
+ v1.AddArg(v2)
+ v3 := b.NewValue0(v.Line, OpRsh32Ux32, config.fe.TypeUInt32())
+ v3.AddArg(lo)
+ v4 := b.NewValue0(v.Line, OpSub32, config.fe.TypeUInt32())
+ v5 := b.NewValue0(v.Line, OpConst32, config.fe.TypeUInt32())
+ 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.AddArg(lo)
+ v7 := b.NewValue0(v.Line, OpSub32, config.fe.TypeUInt32())
+ v7.AddArg(s)
+ v8 := b.NewValue0(v.Line, OpConst32, config.fe.TypeUInt32())
+ 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.AddArg(lo)
+ v9.AddArg(s)
+ v.AddArg(v9)
+ return true
+ }
+ return false
+}
+func rewriteValuedec64_OpLsh64x64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Lsh64x64 _ (Int64Make (Const32 [c]) _))
+ // cond: c != 0
+ // result: (Const64 [0])
+ for {
+ v_1 := v.Args[1]
+ if v_1.Op != OpInt64Make {
+ break
+ }
+ v_1_0 := v_1.Args[0]
+ if v_1_0.Op != OpConst32 {
+ break
+ }
+ c := v_1_0.AuxInt
+ if !(c != 0) {
+ break
+ }
+ v.reset(OpConst64)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (Lsh64x64 x (Int64Make (Const32 [0]) lo))
+ // cond:
+ // result: (Lsh64x32 x lo)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpInt64Make {
+ break
+ }
+ v_1_0 := v_1.Args[0]
+ if v_1_0.Op != OpConst32 {
+ break
+ }
+ if v_1_0.AuxInt != 0 {
+ break
+ }
+ lo := v_1.Args[1]
+ v.reset(OpLsh64x32)
+ v.AddArg(x)
+ v.AddArg(lo)
+ return true
+ }
+ // match: (Lsh64x64 x (Int64Make hi lo))
+ // cond: hi.Op != OpConst32
+ // result: (Lsh64x32 x (Or32 <config.fe.TypeUInt32()> (Zeromask hi) lo))
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpInt64Make {
+ break
+ }
+ hi := v_1.Args[0]
+ lo := v_1.Args[1]
+ if !(hi.Op != OpConst32) {
+ break
+ }
+ v.reset(OpLsh64x32)
+ v.AddArg(x)
+ v0 := b.NewValue0(v.Line, OpOr32, config.fe.TypeUInt32())
+ v1 := b.NewValue0(v.Line, OpZeromask, config.fe.TypeUInt32())
+ v1.AddArg(hi)
+ v0.AddArg(v1)
+ v0.AddArg(lo)
+ v.AddArg(v0)
+ return true
+ }
+ return false
+}
+func rewriteValuedec64_OpLsh64x8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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))
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpInt64Make {
+ break
+ }
+ 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())
+ v2.AddArg(hi)
+ v2.AddArg(s)
+ v1.AddArg(v2)
+ v3 := b.NewValue0(v.Line, OpRsh32Ux8, config.fe.TypeUInt32())
+ v3.AddArg(lo)
+ v4 := b.NewValue0(v.Line, OpSub8, config.fe.TypeUInt8())
+ v5 := b.NewValue0(v.Line, OpConst8, config.fe.TypeUInt8())
+ 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.AddArg(lo)
+ v7 := b.NewValue0(v.Line, OpSub8, config.fe.TypeUInt8())
+ v7.AddArg(s)
+ v8 := b.NewValue0(v.Line, OpConst8, config.fe.TypeUInt8())
+ 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.AddArg(lo)
+ v9.AddArg(s)
+ v.AddArg(v9)
+ return true
+ }
+ return false
+}
+func rewriteValuedec64_OpLsh8x64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Lsh8x64 _ (Int64Make (Const32 [c]) _))
+ // cond: c != 0
+ // result: (Const32 [0])
+ for {
+ v_1 := v.Args[1]
+ if v_1.Op != OpInt64Make {
+ break
+ }
+ v_1_0 := v_1.Args[0]
+ if v_1_0.Op != OpConst32 {
+ break
+ }
+ c := v_1_0.AuxInt
+ if !(c != 0) {
+ break
+ }
+ v.reset(OpConst32)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (Lsh8x64 x (Int64Make (Const32 [0]) lo))
+ // cond:
+ // result: (Lsh8x32 x lo)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpInt64Make {
+ break
+ }
+ v_1_0 := v_1.Args[0]
+ if v_1_0.Op != OpConst32 {
+ break
+ }
+ if v_1_0.AuxInt != 0 {
+ break
+ }
+ lo := v_1.Args[1]
+ v.reset(OpLsh8x32)
+ v.AddArg(x)
+ v.AddArg(lo)
+ return true
+ }
+ // match: (Lsh8x64 x (Int64Make hi lo))
+ // cond: hi.Op != OpConst32
+ // result: (Lsh8x32 x (Or32 <config.fe.TypeUInt32()> (Zeromask hi) lo))
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpInt64Make {
+ break
+ }
+ hi := v_1.Args[0]
+ lo := v_1.Args[1]
+ if !(hi.Op != OpConst32) {
+ break
+ }
+ v.reset(OpLsh8x32)
+ v.AddArg(x)
+ v0 := b.NewValue0(v.Line, OpOr32, config.fe.TypeUInt32())
+ v1 := b.NewValue0(v.Line, OpZeromask, config.fe.TypeUInt32())
+ v1.AddArg(hi)
+ v0.AddArg(v1)
+ v0.AddArg(lo)
+ v.AddArg(v0)
+ return true
+ }
+ return false
+}
+func rewriteValuedec64_OpMul64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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))))
+ for {
+ 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())
+ v2.AddArg(x)
+ v1.AddArg(v2)
+ v3 := b.NewValue0(v.Line, OpInt64Hi, config.fe.TypeUInt32())
+ 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())
+ v6.AddArg(x)
+ v5.AddArg(v6)
+ v7 := b.NewValue0(v.Line, OpInt64Lo, config.fe.TypeUInt32())
+ 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())
+ v10.AddArg(x)
+ v9.AddArg(v10)
+ v11 := b.NewValue0(v.Line, OpInt64Lo, config.fe.TypeUInt32())
+ 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())
+ v14.AddArg(x)
+ v13.AddArg(v14)
+ v15 := b.NewValue0(v.Line, OpInt64Lo, config.fe.TypeUInt32())
+ v15.AddArg(y)
+ v13.AddArg(v15)
+ v12.AddArg(v13)
+ v.AddArg(v12)
+ return true
+ }
+}
+func rewriteValuedec64_OpNeg64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Neg64 <t> x)
+ // cond:
+ // result: (Sub64 (Const64 <t> [0]) x)
+ for {
+ t := v.Type
+ x := v.Args[0]
+ v.reset(OpSub64)
+ v0 := b.NewValue0(v.Line, OpConst64, t)
+ v0.AuxInt = 0
+ v.AddArg(v0)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValuedec64_OpNeq64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Neq64 x y)
+ // cond:
+ // result: (OrB (Neq32 (Int64Hi x) (Int64Hi y)) (Neq32 (Int64Lo x) (Int64Lo y)))
+ for {
+ 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())
+ v1.AddArg(x)
+ v0.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpInt64Hi, config.fe.TypeUInt32())
+ 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())
+ v4.AddArg(x)
+ v3.AddArg(v4)
+ v5 := b.NewValue0(v.Line, OpInt64Lo, config.fe.TypeUInt32())
+ v5.AddArg(y)
+ v3.AddArg(v5)
+ v.AddArg(v3)
+ return true
+ }
+}
+func rewriteValuedec64_OpOr64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Or64 x y)
+ // cond:
+ // result: (Int64Make (Or32 <config.fe.TypeUInt32()> (Int64Hi x) (Int64Hi y)) (Or32 <config.fe.TypeUInt32()> (Int64Lo x) (Int64Lo y)))
+ for {
+ 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())
+ v1.AddArg(x)
+ v0.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpInt64Hi, config.fe.TypeUInt32())
+ 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())
+ v4.AddArg(x)
+ v3.AddArg(v4)
+ v5 := b.NewValue0(v.Line, OpInt64Lo, config.fe.TypeUInt32())
+ v5.AddArg(y)
+ v3.AddArg(v5)
+ v.AddArg(v3)
+ return true
+ }
+}
+func rewriteValuedec64_OpRsh16Ux64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh16Ux64 _ (Int64Make (Const32 [c]) _))
+ // cond: c != 0
+ // result: (Const32 [0])
+ for {
+ v_1 := v.Args[1]
+ if v_1.Op != OpInt64Make {
+ break
+ }
+ v_1_0 := v_1.Args[0]
+ if v_1_0.Op != OpConst32 {
+ break
+ }
+ c := v_1_0.AuxInt
+ if !(c != 0) {
+ break
+ }
+ v.reset(OpConst32)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (Rsh16Ux64 x (Int64Make (Const32 [0]) lo))
+ // cond:
+ // result: (Rsh16Ux32 x lo)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpInt64Make {
+ break
+ }
+ v_1_0 := v_1.Args[0]
+ if v_1_0.Op != OpConst32 {
+ break
+ }
+ if v_1_0.AuxInt != 0 {
+ break
+ }
+ lo := v_1.Args[1]
+ v.reset(OpRsh16Ux32)
+ v.AddArg(x)
+ v.AddArg(lo)
+ return true
+ }
+ // match: (Rsh16Ux64 x (Int64Make hi lo))
+ // cond: hi.Op != OpConst32
+ // result: (Rsh16Ux32 x (Or32 <config.fe.TypeUInt32()> (Zeromask hi) lo))
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpInt64Make {
+ break
+ }
+ hi := v_1.Args[0]
+ lo := v_1.Args[1]
+ if !(hi.Op != OpConst32) {
+ break
+ }
+ v.reset(OpRsh16Ux32)
+ v.AddArg(x)
+ v0 := b.NewValue0(v.Line, OpOr32, config.fe.TypeUInt32())
+ v1 := b.NewValue0(v.Line, OpZeromask, config.fe.TypeUInt32())
+ v1.AddArg(hi)
+ v0.AddArg(v1)
+ v0.AddArg(lo)
+ v.AddArg(v0)
+ return true
+ }
+ return false
+}
+func rewriteValuedec64_OpRsh16x64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh16x64 x (Int64Make (Const32 [c]) _))
+ // cond: c != 0
+ // result: (Signmask (SignExt16to32 x))
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpInt64Make {
+ break
+ }
+ v_1_0 := v_1.Args[0]
+ if v_1_0.Op != OpConst32 {
+ break
+ }
+ c := v_1_0.AuxInt
+ if !(c != 0) {
+ break
+ }
+ v.reset(OpSignmask)
+ v0 := b.NewValue0(v.Line, OpSignExt16to32, config.fe.TypeInt32())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (Rsh16x64 x (Int64Make (Const32 [0]) lo))
+ // cond:
+ // result: (Rsh16x32 x lo)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpInt64Make {
+ break
+ }
+ v_1_0 := v_1.Args[0]
+ if v_1_0.Op != OpConst32 {
+ break
+ }
+ if v_1_0.AuxInt != 0 {
+ break
+ }
+ lo := v_1.Args[1]
+ v.reset(OpRsh16x32)
+ v.AddArg(x)
+ v.AddArg(lo)
+ return true
+ }
+ // match: (Rsh16x64 x (Int64Make hi lo))
+ // cond: hi.Op != OpConst32
+ // result: (Rsh16x32 x (Or32 <config.fe.TypeUInt32()> (Zeromask hi) lo))
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpInt64Make {
+ break
+ }
+ hi := v_1.Args[0]
+ lo := v_1.Args[1]
+ if !(hi.Op != OpConst32) {
+ break
+ }
+ v.reset(OpRsh16x32)
+ v.AddArg(x)
+ v0 := b.NewValue0(v.Line, OpOr32, config.fe.TypeUInt32())
+ v1 := b.NewValue0(v.Line, OpZeromask, config.fe.TypeUInt32())
+ v1.AddArg(hi)
+ v0.AddArg(v1)
+ v0.AddArg(lo)
+ v.AddArg(v0)
+ return true
+ }
+ return false
+}
+func rewriteValuedec64_OpRsh32Ux64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh32Ux64 _ (Int64Make (Const32 [c]) _))
+ // cond: c != 0
+ // result: (Const32 [0])
+ for {
+ v_1 := v.Args[1]
+ if v_1.Op != OpInt64Make {
+ break
+ }
+ v_1_0 := v_1.Args[0]
+ if v_1_0.Op != OpConst32 {
+ break
+ }
+ c := v_1_0.AuxInt
+ if !(c != 0) {
+ break
+ }
+ v.reset(OpConst32)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (Rsh32Ux64 x (Int64Make (Const32 [0]) lo))
+ // cond:
+ // result: (Rsh32Ux32 x lo)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpInt64Make {
+ break
+ }
+ v_1_0 := v_1.Args[0]
+ if v_1_0.Op != OpConst32 {
+ break
+ }
+ if v_1_0.AuxInt != 0 {
+ break
+ }
+ lo := v_1.Args[1]
+ v.reset(OpRsh32Ux32)
+ v.AddArg(x)
+ v.AddArg(lo)
+ return true
+ }
+ // match: (Rsh32Ux64 x (Int64Make hi lo))
+ // cond: hi.Op != OpConst32
+ // result: (Rsh32Ux32 x (Or32 <config.fe.TypeUInt32()> (Zeromask hi) lo))
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpInt64Make {
+ break
+ }
+ hi := v_1.Args[0]
+ lo := v_1.Args[1]
+ if !(hi.Op != OpConst32) {
+ break
+ }
+ v.reset(OpRsh32Ux32)
+ v.AddArg(x)
+ v0 := b.NewValue0(v.Line, OpOr32, config.fe.TypeUInt32())
+ v1 := b.NewValue0(v.Line, OpZeromask, config.fe.TypeUInt32())
+ v1.AddArg(hi)
+ v0.AddArg(v1)
+ v0.AddArg(lo)
+ v.AddArg(v0)
+ return true
+ }
+ return false
+}
+func rewriteValuedec64_OpRsh32x64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh32x64 x (Int64Make (Const32 [c]) _))
+ // cond: c != 0
+ // result: (Signmask x)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpInt64Make {
+ break
+ }
+ v_1_0 := v_1.Args[0]
+ if v_1_0.Op != OpConst32 {
+ break
+ }
+ c := v_1_0.AuxInt
+ if !(c != 0) {
+ break
+ }
+ v.reset(OpSignmask)
+ v.AddArg(x)
+ return true
+ }
+ // match: (Rsh32x64 x (Int64Make (Const32 [0]) lo))
+ // cond:
+ // result: (Rsh32x32 x lo)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpInt64Make {
+ break
+ }
+ v_1_0 := v_1.Args[0]
+ if v_1_0.Op != OpConst32 {
+ break
+ }
+ if v_1_0.AuxInt != 0 {
+ break
+ }
+ lo := v_1.Args[1]
+ v.reset(OpRsh32x32)
+ v.AddArg(x)
+ v.AddArg(lo)
+ return true
+ }
+ // match: (Rsh32x64 x (Int64Make hi lo))
+ // cond: hi.Op != OpConst32
+ // result: (Rsh32x32 x (Or32 <config.fe.TypeUInt32()> (Zeromask hi) lo))
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpInt64Make {
+ break
+ }
+ hi := v_1.Args[0]
+ lo := v_1.Args[1]
+ if !(hi.Op != OpConst32) {
+ break
+ }
+ v.reset(OpRsh32x32)
+ v.AddArg(x)
+ v0 := b.NewValue0(v.Line, OpOr32, config.fe.TypeUInt32())
+ v1 := b.NewValue0(v.Line, OpZeromask, config.fe.TypeUInt32())
+ v1.AddArg(hi)
+ v0.AddArg(v1)
+ v0.AddArg(lo)
+ v.AddArg(v0)
+ return true
+ }
+ return false
+}
+func rewriteValuedec64_OpRsh64Ux16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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])))))
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpInt64Make {
+ break
+ }
+ 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.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())
+ v3.AddArg(lo)
+ v3.AddArg(s)
+ v2.AddArg(v3)
+ v4 := b.NewValue0(v.Line, OpLsh32x16, config.fe.TypeUInt32())
+ v4.AddArg(hi)
+ v5 := b.NewValue0(v.Line, OpSub16, config.fe.TypeUInt16())
+ v6 := b.NewValue0(v.Line, OpConst16, config.fe.TypeUInt16())
+ 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.AddArg(hi)
+ v8 := b.NewValue0(v.Line, OpSub16, config.fe.TypeUInt16())
+ v8.AddArg(s)
+ v9 := b.NewValue0(v.Line, OpConst16, config.fe.TypeUInt16())
+ v9.AuxInt = 32
+ v8.AddArg(v9)
+ v7.AddArg(v8)
+ v1.AddArg(v7)
+ v.AddArg(v1)
+ return true
+ }
+ return false
+}
+func rewriteValuedec64_OpRsh64Ux32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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])))))
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpInt64Make {
+ break
+ }
+ 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.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())
+ v3.AddArg(lo)
+ v3.AddArg(s)
+ v2.AddArg(v3)
+ v4 := b.NewValue0(v.Line, OpLsh32x32, config.fe.TypeUInt32())
+ v4.AddArg(hi)
+ v5 := b.NewValue0(v.Line, OpSub32, config.fe.TypeUInt32())
+ v6 := b.NewValue0(v.Line, OpConst32, config.fe.TypeUInt32())
+ 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.AddArg(hi)
+ v8 := b.NewValue0(v.Line, OpSub32, config.fe.TypeUInt32())
+ v8.AddArg(s)
+ v9 := b.NewValue0(v.Line, OpConst32, config.fe.TypeUInt32())
+ v9.AuxInt = 32
+ v8.AddArg(v9)
+ v7.AddArg(v8)
+ v1.AddArg(v7)
+ v.AddArg(v1)
+ return true
+ }
+ return false
+}
+func rewriteValuedec64_OpRsh64Ux64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh64Ux64 _ (Int64Make (Const32 [c]) _))
+ // cond: c != 0
+ // result: (Const64 [0])
+ for {
+ v_1 := v.Args[1]
+ if v_1.Op != OpInt64Make {
+ break
+ }
+ v_1_0 := v_1.Args[0]
+ if v_1_0.Op != OpConst32 {
+ break
+ }
+ c := v_1_0.AuxInt
+ if !(c != 0) {
+ break
+ }
+ v.reset(OpConst64)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (Rsh64Ux64 x (Int64Make (Const32 [0]) lo))
+ // cond:
+ // result: (Rsh64Ux32 x lo)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpInt64Make {
+ break
+ }
+ v_1_0 := v_1.Args[0]
+ if v_1_0.Op != OpConst32 {
+ break
+ }
+ if v_1_0.AuxInt != 0 {
+ break
+ }
+ lo := v_1.Args[1]
+ v.reset(OpRsh64Ux32)
+ v.AddArg(x)
+ v.AddArg(lo)
+ return true
+ }
+ // match: (Rsh64Ux64 x (Int64Make hi lo))
+ // cond: hi.Op != OpConst32
+ // result: (Rsh64Ux32 x (Or32 <config.fe.TypeUInt32()> (Zeromask hi) lo))
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpInt64Make {
+ break
+ }
+ hi := v_1.Args[0]
+ lo := v_1.Args[1]
+ if !(hi.Op != OpConst32) {
+ break
+ }
+ v.reset(OpRsh64Ux32)
+ v.AddArg(x)
+ v0 := b.NewValue0(v.Line, OpOr32, config.fe.TypeUInt32())
+ v1 := b.NewValue0(v.Line, OpZeromask, config.fe.TypeUInt32())
+ v1.AddArg(hi)
+ v0.AddArg(v1)
+ v0.AddArg(lo)
+ v.AddArg(v0)
+ return true
+ }
+ return false
+}
+func rewriteValuedec64_OpRsh64Ux8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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])))))
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpInt64Make {
+ break
+ }
+ 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.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())
+ v3.AddArg(lo)
+ v3.AddArg(s)
+ v2.AddArg(v3)
+ v4 := b.NewValue0(v.Line, OpLsh32x8, config.fe.TypeUInt32())
+ v4.AddArg(hi)
+ v5 := b.NewValue0(v.Line, OpSub8, config.fe.TypeUInt8())
+ v6 := b.NewValue0(v.Line, OpConst8, config.fe.TypeUInt8())
+ 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.AddArg(hi)
+ v8 := b.NewValue0(v.Line, OpSub8, config.fe.TypeUInt8())
+ v8.AddArg(s)
+ v9 := b.NewValue0(v.Line, OpConst8, config.fe.TypeUInt8())
+ v9.AuxInt = 32
+ v8.AddArg(v9)
+ v7.AddArg(v8)
+ v1.AddArg(v7)
+ v.AddArg(v1)
+ return true
+ }
+ return false
+}
+func rewriteValuedec64_OpRsh64x16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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 [...]
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpInt64Make {
+ break
+ }
+ 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.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())
+ v3.AddArg(lo)
+ v3.AddArg(s)
+ v2.AddArg(v3)
+ v4 := b.NewValue0(v.Line, OpLsh32x16, config.fe.TypeUInt32())
+ v4.AddArg(hi)
+ v5 := b.NewValue0(v.Line, OpSub16, config.fe.TypeUInt16())
+ v6 := b.NewValue0(v.Line, OpConst16, config.fe.TypeUInt16())
+ 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())
+ v8.AddArg(hi)
+ v9 := b.NewValue0(v.Line, OpSub16, config.fe.TypeUInt16())
+ v9.AddArg(s)
+ v10 := b.NewValue0(v.Line, OpConst16, config.fe.TypeUInt16())
+ 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())
+ v13.AddArg(s)
+ v14 := b.NewValue0(v.Line, OpConst32, config.fe.TypeUInt32())
+ v14.AuxInt = 5
+ v13.AddArg(v14)
+ v12.AddArg(v13)
+ v11.AddArg(v12)
+ v7.AddArg(v11)
+ v1.AddArg(v7)
+ v.AddArg(v1)
+ return true
+ }
+ return false
+}
+func rewriteValuedec64_OpRsh64x32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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 [...]
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpInt64Make {
+ break
+ }
+ 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.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())
+ v3.AddArg(lo)
+ v3.AddArg(s)
+ v2.AddArg(v3)
+ v4 := b.NewValue0(v.Line, OpLsh32x32, config.fe.TypeUInt32())
+ v4.AddArg(hi)
+ v5 := b.NewValue0(v.Line, OpSub32, config.fe.TypeUInt32())
+ v6 := b.NewValue0(v.Line, OpConst32, config.fe.TypeUInt32())
+ 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())
+ v8.AddArg(hi)
+ v9 := b.NewValue0(v.Line, OpSub32, config.fe.TypeUInt32())
+ v9.AddArg(s)
+ v10 := b.NewValue0(v.Line, OpConst32, config.fe.TypeUInt32())
+ 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())
+ v12.AddArg(s)
+ v13 := b.NewValue0(v.Line, OpConst32, config.fe.TypeUInt32())
+ v13.AuxInt = 5
+ v12.AddArg(v13)
+ v11.AddArg(v12)
+ v7.AddArg(v11)
+ v1.AddArg(v7)
+ v.AddArg(v1)
+ return true
+ }
+ return false
+}
+func rewriteValuedec64_OpRsh64x64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh64x64 x (Int64Make (Const32 [c]) _))
+ // cond: c != 0
+ // result: (Int64Make (Signmask (Int64Hi x)) (Signmask (Int64Hi x)))
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpInt64Make {
+ break
+ }
+ v_1_0 := v_1.Args[0]
+ if v_1_0.Op != OpConst32 {
+ break
+ }
+ c := v_1_0.AuxInt
+ if !(c != 0) {
+ break
+ }
+ v.reset(OpInt64Make)
+ v0 := b.NewValue0(v.Line, OpSignmask, config.fe.TypeInt32())
+ v1 := b.NewValue0(v.Line, OpInt64Hi, config.fe.TypeUInt32())
+ 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())
+ v3.AddArg(x)
+ v2.AddArg(v3)
+ v.AddArg(v2)
+ return true
+ }
+ // match: (Rsh64x64 x (Int64Make (Const32 [0]) lo))
+ // cond:
+ // result: (Rsh64x32 x lo)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpInt64Make {
+ break
+ }
+ v_1_0 := v_1.Args[0]
+ if v_1_0.Op != OpConst32 {
+ break
+ }
+ if v_1_0.AuxInt != 0 {
+ break
+ }
+ lo := v_1.Args[1]
+ v.reset(OpRsh64x32)
+ v.AddArg(x)
+ v.AddArg(lo)
+ return true
+ }
+ // match: (Rsh64x64 x (Int64Make hi lo))
+ // cond: hi.Op != OpConst32
+ // result: (Rsh64x32 x (Or32 <config.fe.TypeUInt32()> (Zeromask hi) lo))
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpInt64Make {
+ break
+ }
+ hi := v_1.Args[0]
+ lo := v_1.Args[1]
+ if !(hi.Op != OpConst32) {
+ break
+ }
+ v.reset(OpRsh64x32)
+ v.AddArg(x)
+ v0 := b.NewValue0(v.Line, OpOr32, config.fe.TypeUInt32())
+ v1 := b.NewValue0(v.Line, OpZeromask, config.fe.TypeUInt32())
+ v1.AddArg(hi)
+ v0.AddArg(v1)
+ v0.AddArg(lo)
+ v.AddArg(v0)
+ return true
+ }
+ return false
+}
+func rewriteValuedec64_OpRsh64x8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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 [...]
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpInt64Make {
+ break
+ }
+ 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.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())
+ v3.AddArg(lo)
+ v3.AddArg(s)
+ v2.AddArg(v3)
+ v4 := b.NewValue0(v.Line, OpLsh32x8, config.fe.TypeUInt32())
+ v4.AddArg(hi)
+ v5 := b.NewValue0(v.Line, OpSub8, config.fe.TypeUInt8())
+ v6 := b.NewValue0(v.Line, OpConst8, config.fe.TypeUInt8())
+ 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())
+ v8.AddArg(hi)
+ v9 := b.NewValue0(v.Line, OpSub8, config.fe.TypeUInt8())
+ v9.AddArg(s)
+ v10 := b.NewValue0(v.Line, OpConst8, config.fe.TypeUInt8())
+ 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())
+ v13.AddArg(s)
+ v14 := b.NewValue0(v.Line, OpConst32, config.fe.TypeUInt32())
+ v14.AuxInt = 5
+ v13.AddArg(v14)
+ v12.AddArg(v13)
+ v11.AddArg(v12)
+ v7.AddArg(v11)
+ v1.AddArg(v7)
+ v.AddArg(v1)
+ return true
+ }
+ return false
+}
+func rewriteValuedec64_OpRsh8Ux64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh8Ux64 _ (Int64Make (Const32 [c]) _))
+ // cond: c != 0
+ // result: (Const32 [0])
+ for {
+ v_1 := v.Args[1]
+ if v_1.Op != OpInt64Make {
+ break
+ }
+ v_1_0 := v_1.Args[0]
+ if v_1_0.Op != OpConst32 {
+ break
+ }
+ c := v_1_0.AuxInt
+ if !(c != 0) {
+ break
+ }
+ v.reset(OpConst32)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (Rsh8Ux64 x (Int64Make (Const32 [0]) lo))
+ // cond:
+ // result: (Rsh8Ux32 x lo)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpInt64Make {
+ break
+ }
+ v_1_0 := v_1.Args[0]
+ if v_1_0.Op != OpConst32 {
+ break
+ }
+ if v_1_0.AuxInt != 0 {
+ break
+ }
+ lo := v_1.Args[1]
+ v.reset(OpRsh8Ux32)
+ v.AddArg(x)
+ v.AddArg(lo)
+ return true
+ }
+ // match: (Rsh8Ux64 x (Int64Make hi lo))
+ // cond: hi.Op != OpConst32
+ // result: (Rsh8Ux32 x (Or32 <config.fe.TypeUInt32()> (Zeromask hi) lo))
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpInt64Make {
+ break
+ }
+ hi := v_1.Args[0]
+ lo := v_1.Args[1]
+ if !(hi.Op != OpConst32) {
+ break
+ }
+ v.reset(OpRsh8Ux32)
+ v.AddArg(x)
+ v0 := b.NewValue0(v.Line, OpOr32, config.fe.TypeUInt32())
+ v1 := b.NewValue0(v.Line, OpZeromask, config.fe.TypeUInt32())
+ v1.AddArg(hi)
+ v0.AddArg(v1)
+ v0.AddArg(lo)
+ v.AddArg(v0)
+ return true
+ }
+ return false
+}
+func rewriteValuedec64_OpRsh8x64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Rsh8x64 x (Int64Make (Const32 [c]) _))
+ // cond: c != 0
+ // result: (Signmask (SignExt8to32 x))
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpInt64Make {
+ break
+ }
+ v_1_0 := v_1.Args[0]
+ if v_1_0.Op != OpConst32 {
+ break
+ }
+ c := v_1_0.AuxInt
+ if !(c != 0) {
+ break
+ }
+ v.reset(OpSignmask)
+ v0 := b.NewValue0(v.Line, OpSignExt8to32, config.fe.TypeInt32())
+ v0.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+ // match: (Rsh8x64 x (Int64Make (Const32 [0]) lo))
+ // cond:
+ // result: (Rsh8x32 x lo)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpInt64Make {
+ break
+ }
+ v_1_0 := v_1.Args[0]
+ if v_1_0.Op != OpConst32 {
+ break
+ }
+ if v_1_0.AuxInt != 0 {
+ break
+ }
+ lo := v_1.Args[1]
+ v.reset(OpRsh8x32)
+ v.AddArg(x)
+ v.AddArg(lo)
+ return true
+ }
+ // match: (Rsh8x64 x (Int64Make hi lo))
+ // cond: hi.Op != OpConst32
+ // result: (Rsh8x32 x (Or32 <config.fe.TypeUInt32()> (Zeromask hi) lo))
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpInt64Make {
+ break
+ }
+ hi := v_1.Args[0]
+ lo := v_1.Args[1]
+ if !(hi.Op != OpConst32) {
+ break
+ }
+ v.reset(OpRsh8x32)
+ v.AddArg(x)
+ v0 := b.NewValue0(v.Line, OpOr32, config.fe.TypeUInt32())
+ v1 := b.NewValue0(v.Line, OpZeromask, config.fe.TypeUInt32())
+ v1.AddArg(hi)
+ v0.AddArg(v1)
+ v0.AddArg(lo)
+ v.AddArg(v0)
+ return true
+ }
+ return false
+}
+func rewriteValuedec64_OpSignExt16to64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValuedec64_OpSignExt32to64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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.AddArg(x)
+ v.AddArg(v0)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValuedec64_OpSignExt8to64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValuedec64_OpStore(v *Value, config *Config) 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
+ }
+ dst := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpInt64Make {
+ break
+ }
+ hi := v_1.Args[0]
+ lo := v_1.Args[1]
+ mem := v.Args[2]
+ if !(!config.BigEndian) {
+ break
+ }
+ v.reset(OpStore)
+ v.AuxInt = 4
+ v0 := b.NewValue0(v.Line, 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.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))
+ for {
+ if v.AuxInt != 8 {
+ break
+ }
+ dst := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpInt64Make {
+ break
+ }
+ hi := v_1.Args[0]
+ lo := v_1.Args[1]
+ mem := v.Args[2]
+ if !(config.BigEndian) {
+ break
+ }
+ v.reset(OpStore)
+ v.AuxInt = 4
+ v0 := b.NewValue0(v.Line, 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.AddArg(dst)
+ v1.AddArg(hi)
+ v1.AddArg(mem)
+ v.AddArg(v1)
+ return true
+ }
+ return false
+}
+func rewriteValuedec64_OpSub64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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))))
+ for {
+ 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())
+ v1.AddArg(x)
+ v0.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpInt64Hi, config.fe.TypeUInt32())
+ 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())
+ v5.AddArg(x)
+ v4.AddArg(v5)
+ v6 := b.NewValue0(v.Line, OpInt64Lo, config.fe.TypeUInt32())
+ 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())
+ v9.AddArg(x)
+ v8.AddArg(v9)
+ v10 := b.NewValue0(v.Line, OpInt64Lo, config.fe.TypeUInt32())
+ v10.AddArg(y)
+ v8.AddArg(v10)
+ v7.AddArg(v8)
+ v.AddArg(v7)
+ return true
+ }
+}
+func rewriteValuedec64_OpTrunc64to16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Trunc64to16 (Int64Make _ lo))
+ // cond:
+ // result: (Trunc32to16 lo)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpInt64Make {
+ break
+ }
+ lo := v_0.Args[1]
+ v.reset(OpTrunc32to16)
+ v.AddArg(lo)
+ return true
+ }
+ return false
+}
+func rewriteValuedec64_OpTrunc64to32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Trunc64to32 (Int64Make _ lo))
+ // cond:
+ // result: lo
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpInt64Make {
+ break
+ }
+ lo := v_0.Args[1]
+ v.reset(OpCopy)
+ v.Type = lo.Type
+ v.AddArg(lo)
+ return true
+ }
+ return false
+}
+func rewriteValuedec64_OpTrunc64to8(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Trunc64to8 (Int64Make _ lo))
+ // cond:
+ // result: (Trunc32to8 lo)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpInt64Make {
+ break
+ }
+ lo := v_0.Args[1]
+ v.reset(OpTrunc32to8)
+ v.AddArg(lo)
+ return true
+ }
+ return false
+}
+func rewriteValuedec64_OpXor64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Xor64 x y)
+ // cond:
+ // result: (Int64Make (Xor32 <config.fe.TypeUInt32()> (Int64Hi x) (Int64Hi y)) (Xor32 <config.fe.TypeUInt32()> (Int64Lo x) (Int64Lo y)))
+ for {
+ 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())
+ v1.AddArg(x)
+ v0.AddArg(v1)
+ v2 := b.NewValue0(v.Line, OpInt64Hi, config.fe.TypeUInt32())
+ 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())
+ v4.AddArg(x)
+ v3.AddArg(v4)
+ v5 := b.NewValue0(v.Line, OpInt64Lo, config.fe.TypeUInt32())
+ v5.AddArg(y)
+ v3.AddArg(v5)
+ v.AddArg(v3)
+ return true
+ }
+}
+func rewriteValuedec64_OpZeroExt16to64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteValuedec64_OpZeroExt32to64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ZeroExt32to64 x)
+ // cond:
+ // result: (Int64Make (Const32 <config.fe.TypeUInt32()> [0]) x)
+ for {
+ x := v.Args[0]
+ v.reset(OpInt64Make)
+ v0 := b.NewValue0(v.Line, OpConst32, config.fe.TypeUInt32())
+ v0.AuxInt = 0
+ v.AddArg(v0)
+ v.AddArg(x)
+ return true
+ }
+}
+func rewriteValuedec64_OpZeroExt8to64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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.AddArg(x)
+ v.AddArg(v0)
+ return true
+ }
+}
+func rewriteBlockdec64(b *Block, config *Config) bool {
+ switch b.Kind {
+ }
+ return false
+}
diff --git a/src/cmd/compile/internal/ssa/rewritegeneric.go b/src/cmd/compile/internal/ssa/rewritegeneric.go
index 9f08b3c..1a2eacc 100644
--- a/src/cmd/compile/internal/ssa/rewritegeneric.go
+++ b/src/cmd/compile/internal/ssa/rewritegeneric.go
@@ -32,8 +32,8 @@ func rewriteValuegeneric(v *Value, config *Config) bool {
return rewriteValuegeneric_OpAnd8(v, config)
case OpArg:
return rewriteValuegeneric_OpArg(v, config)
- case OpArrayIndex:
- return rewriteValuegeneric_OpArrayIndex(v, config)
+ case OpArraySelect:
+ return rewriteValuegeneric_OpArraySelect(v, config)
case OpCom16:
return rewriteValuegeneric_OpCom16(v, config)
case OpCom32:
@@ -54,8 +54,12 @@ func rewriteValuegeneric(v *Value, config *Config) bool {
return rewriteValuegeneric_OpCvt32Fto64F(v, config)
case OpCvt64Fto32F:
return rewriteValuegeneric_OpCvt64Fto32F(v, config)
+ case OpDiv32F:
+ return rewriteValuegeneric_OpDiv32F(v, config)
case OpDiv64:
return rewriteValuegeneric_OpDiv64(v, config)
+ case OpDiv64F:
+ return rewriteValuegeneric_OpDiv64F(v, config)
case OpDiv64u:
return rewriteValuegeneric_OpDiv64u(v, config)
case OpEq16:
@@ -106,6 +110,8 @@ func rewriteValuegeneric(v *Value, config *Config) bool {
return rewriteValuegeneric_OpGreater8(v, config)
case OpGreater8U:
return rewriteValuegeneric_OpGreater8U(v, config)
+ case OpIMake:
+ return rewriteValuegeneric_OpIMake(v, config)
case OpIsInBounds:
return rewriteValuegeneric_OpIsInBounds(v, config)
case OpIsSliceInBounds:
@@ -228,6 +234,10 @@ func rewriteValuegeneric(v *Value, config *Config) bool {
return rewriteValuegeneric_OpNeqPtr(v, config)
case OpNeqSlice:
return rewriteValuegeneric_OpNeqSlice(v, config)
+ case OpNilCheck:
+ return rewriteValuegeneric_OpNilCheck(v, config)
+ case OpNot:
+ return rewriteValuegeneric_OpNot(v, config)
case OpOffPtr:
return rewriteValuegeneric_OpOffPtr(v, config)
case OpOr16:
@@ -306,12 +316,28 @@ func rewriteValuegeneric(v *Value, config *Config) bool {
return rewriteValuegeneric_OpRsh8x64(v, config)
case OpRsh8x8:
return rewriteValuegeneric_OpRsh8x8(v, config)
+ case OpSignExt16to32:
+ return rewriteValuegeneric_OpSignExt16to32(v, config)
+ case OpSignExt16to64:
+ return rewriteValuegeneric_OpSignExt16to64(v, config)
+ case OpSignExt32to64:
+ return rewriteValuegeneric_OpSignExt32to64(v, config)
+ case OpSignExt8to16:
+ return rewriteValuegeneric_OpSignExt8to16(v, config)
+ case OpSignExt8to32:
+ return rewriteValuegeneric_OpSignExt8to32(v, config)
+ case OpSignExt8to64:
+ return rewriteValuegeneric_OpSignExt8to64(v, config)
case OpSliceCap:
return rewriteValuegeneric_OpSliceCap(v, config)
case OpSliceLen:
return rewriteValuegeneric_OpSliceLen(v, config)
case OpSlicePtr:
return rewriteValuegeneric_OpSlicePtr(v, config)
+ case OpSlicemask:
+ return rewriteValuegeneric_OpSlicemask(v, config)
+ case OpSqrt:
+ return rewriteValuegeneric_OpSqrt(v, config)
case OpStore:
return rewriteValuegeneric_OpStore(v, config)
case OpStringLen:
@@ -352,6 +378,20 @@ func rewriteValuegeneric(v *Value, config *Config) bool {
return rewriteValuegeneric_OpXor64(v, config)
case OpXor8:
return rewriteValuegeneric_OpXor8(v, config)
+ case OpZero:
+ return rewriteValuegeneric_OpZero(v, config)
+ case OpZeroExt16to32:
+ return rewriteValuegeneric_OpZeroExt16to32(v, config)
+ case OpZeroExt16to64:
+ return rewriteValuegeneric_OpZeroExt16to64(v, config)
+ case OpZeroExt32to64:
+ return rewriteValuegeneric_OpZeroExt32to64(v, config)
+ case OpZeroExt8to16:
+ return rewriteValuegeneric_OpZeroExt8to16(v, config)
+ case OpZeroExt8to32:
+ return rewriteValuegeneric_OpZeroExt8to32(v, config)
+ case OpZeroExt8to64:
+ return rewriteValuegeneric_OpZeroExt8to64(v, config)
}
return false
}
@@ -498,6 +538,40 @@ func rewriteValuegeneric_OpAdd32F(v *Value, config *Config) bool {
v.AuxInt = f2i(float64(i2f32(c) + i2f32(d)))
return true
}
+ // match: (Add32F x (Const32F [0]))
+ // cond:
+ // result: x
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpConst32F {
+ break
+ }
+ if v_1.AuxInt != 0 {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ // match: (Add32F (Const32F [0]) x)
+ // cond:
+ // result: x
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpConst32F {
+ break
+ }
+ if v_0.AuxInt != 0 {
+ break
+ }
+ x := v.Args[1]
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
return false
}
func rewriteValuegeneric_OpAdd64(v *Value, config *Config) bool {
@@ -582,6 +656,40 @@ func rewriteValuegeneric_OpAdd64F(v *Value, config *Config) bool {
v.AuxInt = f2i(i2f(c) + i2f(d))
return true
}
+ // match: (Add64F x (Const64F [0]))
+ // cond:
+ // result: x
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpConst64F {
+ break
+ }
+ if v_1.AuxInt != 0 {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ // match: (Add64F (Const64F [0]) x)
+ // cond:
+ // result: x
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpConst64F {
+ break
+ }
+ if v_0.AuxInt != 0 {
+ break
+ }
+ x := v.Args[1]
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
return false
}
func rewriteValuegeneric_OpAdd8(v *Value, config *Config) bool {
@@ -661,8 +769,8 @@ func rewriteValuegeneric_OpAddPtr(v *Value, config *Config) bool {
c := v_1.AuxInt
v.reset(OpOffPtr)
v.Type = t
- v.AddArg(x)
v.AuxInt = c
+ v.AddArg(x)
return true
}
return false
@@ -1298,19 +1406,19 @@ func rewriteValuegeneric_OpArg(v *Value, config *Config) bool {
// cond: v.Type.IsString()
// result: (StringMake (Arg <config.fe.TypeBytePtr()> {n} [off]) (Arg <config.fe.TypeInt()> {n} [off+config.PtrSize]))
for {
- n := v.Aux
off := v.AuxInt
+ n := v.Aux
if !(v.Type.IsString()) {
break
}
v.reset(OpStringMake)
v0 := b.NewValue0(v.Line, OpArg, config.fe.TypeBytePtr())
- v0.Aux = n
v0.AuxInt = off
+ v0.Aux = n
v.AddArg(v0)
v1 := b.NewValue0(v.Line, OpArg, config.fe.TypeInt())
- v1.Aux = n
v1.AuxInt = off + config.PtrSize
+ v1.Aux = n
v.AddArg(v1)
return true
}
@@ -1318,23 +1426,23 @@ func rewriteValuegeneric_OpArg(v *Value, config *Config) bool {
// cond: v.Type.IsSlice()
// result: (SliceMake (Arg <v.Type.ElemType().PtrTo()> {n} [off]) (Arg <config.fe.TypeInt()> {n} [off+config.PtrSize]) (Arg <config.fe.TypeInt()> {n} [off+2*config.PtrSize]))
for {
- n := v.Aux
off := v.AuxInt
+ n := v.Aux
if !(v.Type.IsSlice()) {
break
}
v.reset(OpSliceMake)
v0 := b.NewValue0(v.Line, OpArg, v.Type.ElemType().PtrTo())
- v0.Aux = n
v0.AuxInt = off
+ v0.Aux = n
v.AddArg(v0)
v1 := b.NewValue0(v.Line, OpArg, config.fe.TypeInt())
- v1.Aux = n
v1.AuxInt = off + config.PtrSize
+ v1.Aux = n
v.AddArg(v1)
v2 := b.NewValue0(v.Line, OpArg, config.fe.TypeInt())
- v2.Aux = n
v2.AuxInt = off + 2*config.PtrSize
+ v2.Aux = n
v.AddArg(v2)
return true
}
@@ -1342,19 +1450,19 @@ func rewriteValuegeneric_OpArg(v *Value, config *Config) bool {
// cond: v.Type.IsInterface()
// result: (IMake (Arg <config.fe.TypeBytePtr()> {n} [off]) (Arg <config.fe.TypeBytePtr()> {n} [off+config.PtrSize]))
for {
- n := v.Aux
off := v.AuxInt
+ n := v.Aux
if !(v.Type.IsInterface()) {
break
}
v.reset(OpIMake)
v0 := b.NewValue0(v.Line, OpArg, config.fe.TypeBytePtr())
- v0.Aux = n
v0.AuxInt = off
+ v0.Aux = n
v.AddArg(v0)
v1 := b.NewValue0(v.Line, OpArg, config.fe.TypeBytePtr())
- v1.Aux = n
v1.AuxInt = off + config.PtrSize
+ v1.Aux = n
v.AddArg(v1)
return true
}
@@ -1362,19 +1470,19 @@ func rewriteValuegeneric_OpArg(v *Value, config *Config) bool {
// cond: v.Type.IsComplex() && v.Type.Size() == 16
// result: (ComplexMake (Arg <config.fe.TypeFloat64()> {n} [off]) (Arg <config.fe.TypeFloat64()> {n} [off+8]))
for {
- n := v.Aux
off := v.AuxInt
+ n := v.Aux
if !(v.Type.IsComplex() && v.Type.Size() == 16) {
break
}
v.reset(OpComplexMake)
v0 := b.NewValue0(v.Line, OpArg, config.fe.TypeFloat64())
- v0.Aux = n
v0.AuxInt = off
+ v0.Aux = n
v.AddArg(v0)
v1 := b.NewValue0(v.Line, OpArg, config.fe.TypeFloat64())
- v1.Aux = n
v1.AuxInt = off + 8
+ v1.Aux = n
v.AddArg(v1)
return true
}
@@ -1382,19 +1490,19 @@ func rewriteValuegeneric_OpArg(v *Value, config *Config) bool {
// cond: v.Type.IsComplex() && v.Type.Size() == 8
// result: (ComplexMake (Arg <config.fe.TypeFloat32()> {n} [off]) (Arg <config.fe.TypeFloat32()> {n} [off+4]))
for {
- n := v.Aux
off := v.AuxInt
+ n := v.Aux
if !(v.Type.IsComplex() && v.Type.Size() == 8) {
break
}
v.reset(OpComplexMake)
v0 := b.NewValue0(v.Line, OpArg, config.fe.TypeFloat32())
- v0.Aux = n
v0.AuxInt = off
+ v0.Aux = n
v.AddArg(v0)
v1 := b.NewValue0(v.Line, OpArg, config.fe.TypeFloat32())
- v1.Aux = n
v1.AuxInt = off + 4
+ v1.Aux = n
v.AddArg(v1)
return true
}
@@ -1414,15 +1522,15 @@ func rewriteValuegeneric_OpArg(v *Value, config *Config) bool {
// result: (StructMake1 (Arg <t.FieldType(0)> {n} [off+t.FieldOff(0)]))
for {
t := v.Type
- n := v.Aux
off := v.AuxInt
+ n := v.Aux
if !(t.IsStruct() && t.NumFields() == 1 && config.fe.CanSSA(t)) {
break
}
v.reset(OpStructMake1)
v0 := b.NewValue0(v.Line, OpArg, t.FieldType(0))
- v0.Aux = n
v0.AuxInt = off + t.FieldOff(0)
+ v0.Aux = n
v.AddArg(v0)
return true
}
@@ -1431,19 +1539,19 @@ func rewriteValuegeneric_OpArg(v *Value, config *Config) bool {
// result: (StructMake2 (Arg <t.FieldType(0)> {n} [off+t.FieldOff(0)]) (Arg <t.FieldType(1)> {n} [off+t.FieldOff(1)]))
for {
t := v.Type
- n := v.Aux
off := v.AuxInt
+ n := v.Aux
if !(t.IsStruct() && t.NumFields() == 2 && config.fe.CanSSA(t)) {
break
}
v.reset(OpStructMake2)
v0 := b.NewValue0(v.Line, OpArg, t.FieldType(0))
- v0.Aux = n
v0.AuxInt = off + t.FieldOff(0)
+ v0.Aux = n
v.AddArg(v0)
v1 := b.NewValue0(v.Line, OpArg, t.FieldType(1))
- v1.Aux = n
v1.AuxInt = off + t.FieldOff(1)
+ v1.Aux = n
v.AddArg(v1)
return true
}
@@ -1452,23 +1560,23 @@ func rewriteValuegeneric_OpArg(v *Value, config *Config) bool {
// result: (StructMake3 (Arg <t.FieldType(0)> {n} [off+t.FieldOff(0)]) (Arg <t.FieldType(1)> {n} [off+t.FieldOff(1)]) (Arg <t.FieldType(2)> {n} [off+t.FieldOff(2)]))
for {
t := v.Type
- n := v.Aux
off := v.AuxInt
+ n := v.Aux
if !(t.IsStruct() && t.NumFields() == 3 && config.fe.CanSSA(t)) {
break
}
v.reset(OpStructMake3)
v0 := b.NewValue0(v.Line, OpArg, t.FieldType(0))
- v0.Aux = n
v0.AuxInt = off + t.FieldOff(0)
+ v0.Aux = n
v.AddArg(v0)
v1 := b.NewValue0(v.Line, OpArg, t.FieldType(1))
- v1.Aux = n
v1.AuxInt = off + t.FieldOff(1)
+ v1.Aux = n
v.AddArg(v1)
v2 := b.NewValue0(v.Line, OpArg, t.FieldType(2))
- v2.Aux = n
v2.AuxInt = off + t.FieldOff(2)
+ v2.Aux = n
v.AddArg(v2)
return true
}
@@ -1477,55 +1585,109 @@ func rewriteValuegeneric_OpArg(v *Value, config *Config) bool {
// result: (StructMake4 (Arg <t.FieldType(0)> {n} [off+t.FieldOff(0)]) (Arg <t.FieldType(1)> {n} [off+t.FieldOff(1)]) (Arg <t.FieldType(2)> {n} [off+t.FieldOff(2)]) (Arg <t.FieldType(3)> {n} [off+t.FieldOff(3)]))
for {
t := v.Type
- n := v.Aux
off := v.AuxInt
+ n := v.Aux
if !(t.IsStruct() && t.NumFields() == 4 && config.fe.CanSSA(t)) {
break
}
v.reset(OpStructMake4)
v0 := b.NewValue0(v.Line, OpArg, t.FieldType(0))
- v0.Aux = n
v0.AuxInt = off + t.FieldOff(0)
+ v0.Aux = n
v.AddArg(v0)
v1 := b.NewValue0(v.Line, OpArg, t.FieldType(1))
- v1.Aux = n
v1.AuxInt = off + t.FieldOff(1)
+ v1.Aux = n
v.AddArg(v1)
v2 := b.NewValue0(v.Line, OpArg, t.FieldType(2))
- v2.Aux = n
v2.AuxInt = off + t.FieldOff(2)
+ v2.Aux = n
v.AddArg(v2)
v3 := b.NewValue0(v.Line, OpArg, t.FieldType(3))
- v3.Aux = n
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) {
+ 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)) {
+ break
+ }
+ v.reset(OpArrayMake1)
+ v0 := b.NewValue0(v.Line, OpArg, t.ElemType())
+ v0.AuxInt = off
+ v0.Aux = n
+ v.AddArg(v0)
+ return true
+ }
return false
}
-func rewriteValuegeneric_OpArrayIndex(v *Value, config *Config) bool {
+func rewriteValuegeneric_OpArraySelect(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (ArrayIndex <t> [0] x:(Load ptr mem))
+ // match: (ArraySelect (ArrayMake1 x))
// cond:
- // result: @x.Block (Load <t> ptr mem)
+ // 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
+ }
+ 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 {
- t := v.Type
if v.AuxInt != 0 {
break
}
x := v.Args[0]
- if x.Op != OpLoad {
+ if x.Op != OpIData {
break
}
- ptr := x.Args[0]
- mem := x.Args[1]
- b = x.Block
- v0 := b.NewValue0(v.Line, OpLoad, t)
v.reset(OpCopy)
- v.AddArg(v0)
- v0.AddArg(ptr)
- v0.AddArg(mem)
+ v.Type = x.Type
+ v.AddArg(x)
return true
}
return false
@@ -1842,6 +2004,44 @@ func rewriteValuegeneric_OpCvt64Fto32F(v *Value, config *Config) bool {
}
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 {
+ break
+ }
+ if v_1.AuxInt != f2i(1) {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ // match: (Div32F x (Const32F [f2i(-1)]))
+ // cond:
+ // result: (Neg32F x)
+ for {
+ 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
+ }
+ return false
+}
func rewriteValuegeneric_OpDiv64(v *Value, config *Config) bool {
b := v.Block
_ = b
@@ -1997,6 +2197,44 @@ func rewriteValuegeneric_OpDiv64(v *Value, config *Config) bool {
}
return false
}
+func rewriteValuegeneric_OpDiv64F(v *Value, config *Config) 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)]))
+ // cond:
+ // result: (Neg32F 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(OpNeg32F)
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
func rewriteValuegeneric_OpDiv64u(v *Value, config *Config) bool {
b := v.Block
_ = b
@@ -2919,22 +3157,57 @@ func rewriteValuegeneric_OpGreater8U(v *Value, config *Config) bool {
}
return false
}
-func rewriteValuegeneric_OpIsInBounds(v *Value, config *Config) bool {
+func rewriteValuegeneric_OpIMake(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (IsInBounds (ZeroExt8to32 _) (Const32 [c]))
- // cond: (1 << 8) <= c
- // result: (ConstBool [1])
+ // match: (IMake typ (StructMake1 val))
+ // cond:
+ // result: (IMake typ val)
for {
- v_0 := v.Args[0]
- if v_0.Op != OpZeroExt8to32 {
- break
- }
+ typ := v.Args[0]
v_1 := v.Args[1]
- if v_1.Op != OpConst32 {
+ if v_1.Op != OpStructMake1 {
break
}
- c := v_1.AuxInt
+ 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 {
+ break
+ }
+ val := v_1.Args[0]
+ v.reset(OpIMake)
+ v.AddArg(typ)
+ v.AddArg(val)
+ return true
+ }
+ return false
+}
+func rewriteValuegeneric_OpIsInBounds(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (IsInBounds (ZeroExt8to32 _) (Const32 [c]))
+ // cond: (1 << 8) <= c
+ // result: (ConstBool [1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpZeroExt8to32 {
+ break
+ }
+ v_1 := v.Args[1]
+ if v_1.Op != OpConst32 {
+ break
+ }
+ c := v_1.AuxInt
if !((1 << 8) <= c) {
break
}
@@ -3800,6 +4073,34 @@ func rewriteValuegeneric_OpLoad(v *Value, config *Config) bool {
v.AddArg(v5)
return true
}
+ // match: (Load <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: (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)) {
+ break
+ }
+ v.reset(OpArrayMake1)
+ v0 := b.NewValue0(v.Line, OpLoad, t.ElemType())
+ v0.AddArg(ptr)
+ v0.AddArg(mem)
+ v.AddArg(v0)
+ return true
+ }
return false
}
func rewriteValuegeneric_OpLsh16x16(v *Value, config *Config) bool {
@@ -5122,6 +5423,22 @@ func rewriteValuegeneric_OpMul16(v *Value, config *Config) bool {
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 {
+ break
+ }
+ if v_0.AuxInt != -1 {
+ break
+ }
+ x := v.Args[1]
+ v.reset(OpNeg16)
+ v.AddArg(x)
+ return true
+ }
// match: (Mul16 x (Const16 <t> [c]))
// cond: x.Op != OpConst16
// result: (Mul16 (Const16 <t> [c]) x)
@@ -5181,6 +5498,22 @@ func rewriteValuegeneric_OpMul32(v *Value, config *Config) bool {
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 {
+ break
+ }
+ if v_0.AuxInt != -1 {
+ break
+ }
+ x := v.Args[1]
+ v.reset(OpNeg32)
+ v.AddArg(x)
+ return true
+ }
// match: (Mul32 x (Const32 <t> [c]))
// cond: x.Op != OpConst32
// result: (Mul32 (Const32 <t> [c]) x)
@@ -5278,6 +5611,72 @@ func rewriteValuegeneric_OpMul32F(v *Value, config *Config) bool {
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 {
+ 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_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 {
+ 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_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
+ }
return false
}
func rewriteValuegeneric_OpMul64(v *Value, config *Config) bool {
@@ -5301,6 +5700,22 @@ func rewriteValuegeneric_OpMul64(v *Value, config *Config) bool {
v.AuxInt = c * d
return true
}
+ // match: (Mul64 (Const64 [-1]) x)
+ // cond:
+ // result: (Neg64 x)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpConst64 {
+ break
+ }
+ if v_0.AuxInt != -1 {
+ break
+ }
+ x := v.Args[1]
+ v.reset(OpNeg64)
+ v.AddArg(x)
+ return true
+ }
// match: (Mul64 x (Const64 <t> [c]))
// cond: x.Op != OpConst64
// result: (Mul64 (Const64 <t> [c]) x)
@@ -5398,6 +5813,72 @@ func rewriteValuegeneric_OpMul64F(v *Value, config *Config) bool {
v.AuxInt = f2i(i2f(c) * i2f(d))
return true
}
+ // match: (Mul64F 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: (Mul64F (Const64F [f2i(1)]) x)
+ // cond:
+ // result: x
+ for {
+ 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 {
+ 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_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
+ }
return false
}
func rewriteValuegeneric_OpMul8(v *Value, config *Config) bool {
@@ -5421,6 +5902,22 @@ func rewriteValuegeneric_OpMul8(v *Value, config *Config) bool {
v.AuxInt = int64(int8(c * d))
return true
}
+ // match: (Mul8 (Const8 [-1]) x)
+ // cond:
+ // result: (Neg8 x)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpConst8 {
+ break
+ }
+ if v_0.AuxInt != -1 {
+ break
+ }
+ x := v.Args[1]
+ v.reset(OpNeg8)
+ v.AddArg(x)
+ return true
+ }
// match: (Mul8 x (Const8 <t> [c]))
// cond: x.Op != OpConst8
// result: (Mul8 (Const8 <t> [c]) x)
@@ -6008,64 +6505,779 @@ func rewriteValuegeneric_OpNeqSlice(v *Value, config *Config) bool {
return true
}
}
-func rewriteValuegeneric_OpOffPtr(v *Value, config *Config) bool {
+func rewriteValuegeneric_OpNilCheck(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (OffPtr (OffPtr p [b]) [a])
+ // match: (NilCheck (GetG mem) mem)
// cond:
- // result: (OffPtr p [a+b])
+ // result: mem
for {
v_0 := v.Args[0]
- if v_0.Op != OpOffPtr {
- break
- }
- p := v_0.Args[0]
- b := v_0.AuxInt
- a := v.AuxInt
- v.reset(OpOffPtr)
- v.AddArg(p)
- v.AuxInt = a + b
- return true
- }
- // match: (OffPtr p [0])
- // cond: v.Type.Compare(p.Type) == CMPeq
- // result: p
- for {
- p := v.Args[0]
- if v.AuxInt != 0 {
+ if v_0.Op != OpGetG {
break
}
- if !(v.Type.Compare(p.Type) == CMPeq) {
+ mem := v_0.Args[0]
+ if mem != v.Args[1] {
break
}
v.reset(OpCopy)
- v.Type = p.Type
- v.AddArg(p)
+ v.Type = mem.Type
+ v.AddArg(mem)
return true
}
- return false
-}
-func rewriteValuegeneric_OpOr16(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (Or16 x (Const16 <t> [c]))
- // cond: x.Op != OpConst16
- // result: (Or16 (Const16 <t> [c]) x)
+ // 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)
for {
- x := v.Args[0]
- v_1 := v.Args[1]
- if v_1.Op != OpConst16 {
+ v_0 := v.Args[0]
+ if v_0.Op != OpLoad {
break
}
- t := v_1.Type
- c := v_1.AuxInt
- if !(x.Op != OpConst16) {
+ v_0_0 := v_0.Args[0]
+ if v_0_0.Op != OpOffPtr {
break
}
- v.reset(OpOr16)
- v0 := b.NewValue0(v.Line, OpConst16, t)
- v0.AuxInt = c
- v.AddArg(v0)
+ 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(config.Debug_checknil() && int(v.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(config.Debug_checknil() && int(v.Line) > 1, v, "removed nil check")
+ // result: (Invalid)
+ for {
+ 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_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(config.Debug_checknil() && int(v.Line) > 1, v, "removed nil check")) {
+ break
+ }
+ v.reset(OpInvalid)
+ return true
+ }
+ return false
+}
+func rewriteValuegeneric_OpNot(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Not (Eq64 x y))
+ // cond:
+ // result: (Neq64 x y)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpEq64 {
+ break
+ }
+ 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
+ }
+ 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
+ }
+ 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
+ }
+ 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
+ }
+ 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
+ }
+ 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
+ }
+ 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
+ }
+ 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
+ }
+ 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
+ }
+ x := v_0.Args[0]
+ y := v_0.Args[1]
+ v.reset(OpEqB)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (Not (Greater64 x y))
+ // cond:
+ // result: (Leq64 x y)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpGreater64 {
+ break
+ }
+ 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
+ }
+ 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
+ }
+ 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
+ }
+ 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
+ }
+ 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
+ }
+ 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
+ }
+ 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
+ }
+ 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
+ }
+ 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
+ }
+ x := v_0.Args[0]
+ y := v_0.Args[1]
+ v.reset(OpLess32)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (Not (Geq16 x y))
+ // cond:
+ // result: (Less16 x y)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpGeq16 {
+ break
+ }
+ 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
+ }
+ 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
+ }
+ 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
+ }
+ 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
+ }
+ 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
+ }
+ 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
+ }
+ 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
+ }
+ 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
+ }
+ 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
+ }
+ x := v_0.Args[0]
+ y := v_0.Args[1]
+ v.reset(OpGeq8)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (Not (Less64U x y))
+ // cond:
+ // result: (Geq64U x y)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpLess64U {
+ break
+ }
+ 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
+ }
+ 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
+ }
+ 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
+ }
+ 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
+ }
+ 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
+ }
+ 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
+ }
+ 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
+ }
+ 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
+ }
+ 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
+ }
+ x := v_0.Args[0]
+ y := v_0.Args[1]
+ v.reset(OpGreater32U)
+ v.AddArg(x)
+ v.AddArg(y)
+ return true
+ }
+ // match: (Not (Leq16U x y))
+ // cond:
+ // result: (Greater16U x y)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpLeq16U {
+ break
+ }
+ 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
+ }
+ 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(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // 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) == CMPeq
+ // result: p
+ for {
+ if v.AuxInt != 0 {
+ break
+ }
+ p := v.Args[0]
+ if !(v.Type.Compare(p.Type) == CMPeq) {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = p.Type
+ v.AddArg(p)
+ return true
+ }
+ return false
+}
+func rewriteValuegeneric_OpOr16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Or16 x (Const16 <t> [c]))
+ // cond: x.Op != OpConst16
+ // result: (Or16 (Const16 <t> [c]) x)
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpConst16 {
+ break
+ }
+ t := v_1.Type
+ c := v_1.AuxInt
+ if !(x.Op != OpConst16) {
+ break
+ }
+ v.reset(OpOr16)
+ v0 := b.NewValue0(v.Line, OpConst16, t)
+ v0.AuxInt = c
+ v.AddArg(v0)
v.AddArg(x)
return true
}
@@ -8567,6 +9779,186 @@ func rewriteValuegeneric_OpRsh8x8(v *Value, config *Config) bool {
}
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
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpTrunc32to16 {
+ break
+ }
+ x := v_0.Args[0]
+ if x.Op != OpRsh32x64 {
+ break
+ }
+ x_1 := x.Args[1]
+ if x_1.Op != OpConst64 {
+ break
+ }
+ s := x_1.AuxInt
+ if !(s >= 16) {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = x.Type
+ 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
+ // result: x
+ for {
+ 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 {
+ break
+ }
+ s := x_1.AuxInt
+ if !(s >= 48) {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = x.Type
+ 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
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpTrunc64to32 {
+ break
+ }
+ x := v_0.Args[0]
+ if x.Op != OpRsh64x64 {
+ break
+ }
+ x_1 := x.Args[1]
+ if x_1.Op != OpConst64 {
+ break
+ }
+ s := x_1.AuxInt
+ if !(s >= 32) {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ 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
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpTrunc16to8 {
+ break
+ }
+ x := v_0.Args[0]
+ if x.Op != OpRsh16x64 {
+ break
+ }
+ x_1 := x.Args[1]
+ if x_1.Op != OpConst64 {
+ break
+ }
+ s := x_1.AuxInt
+ if !(s >= 8) {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValuegeneric_OpSignExt8to32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SignExt8to32 (Trunc32to8 x:(Rsh32x64 _ (Const64 [s]))))
+ // cond: s >= 24
+ // result: x
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpTrunc32to8 {
+ break
+ }
+ x := v_0.Args[0]
+ if x.Op != OpRsh32x64 {
+ break
+ }
+ 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_OpSignExt8to64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SignExt8to64 (Trunc64to8 x:(Rsh64x64 _ (Const64 [s]))))
+ // cond: s >= 56
+ // result: x
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpTrunc64to8 {
+ break
+ }
+ x := v_0.Args[0]
+ if x.Op != OpRsh64x64 {
+ break
+ }
+ x_1 := x.Args[1]
+ if x_1.Op != OpConst64 {
+ break
+ }
+ s := x_1.AuxInt
+ if !(s >= 56) {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
func rewriteValuegeneric_OpSliceCap(v *Value, config *Config) bool {
b := v.Block
_ = b
@@ -8589,6 +9981,25 @@ func rewriteValuegeneric_OpSliceCap(v *Value, config *Config) bool {
v.AuxInt = c
return true
}
+ // match: (SliceCap (SliceMake _ _ (Const32 <t> [c])))
+ // cond:
+ // result: (Const32 <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 != OpConst32 {
+ break
+ }
+ t := v_0_2.Type
+ c := v_0_2.AuxInt
+ v.reset(OpConst32)
+ v.Type = t
+ v.AuxInt = c
+ return true
+ }
// match: (SliceCap (SliceMake _ _ (SliceCap x)))
// cond:
// result: (SliceCap x)
@@ -8623,67 +10034,171 @@ func rewriteValuegeneric_OpSliceCap(v *Value, config *Config) bool {
v.AddArg(x)
return true
}
- return false
-}
-func rewriteValuegeneric_OpSliceLen(v *Value, config *Config) bool {
- b := v.Block
- _ = b
- // match: (SliceLen (SliceMake _ (Const64 <t> [c]) _))
- // cond:
- // result: (Const64 <t> [c])
+ return false
+}
+func rewriteValuegeneric_OpSliceLen(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SliceLen (SliceMake _ (Const64 <t> [c]) _))
+ // cond:
+ // result: (Const64 <t> [c])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpSliceMake {
+ break
+ }
+ v_0_1 := v_0.Args[1]
+ if v_0_1.Op != OpConst64 {
+ break
+ }
+ t := v_0_1.Type
+ c := v_0_1.AuxInt
+ v.reset(OpConst64)
+ v.Type = t
+ v.AuxInt = c
+ return true
+ }
+ // match: (SliceLen (SliceMake _ (Const32 <t> [c]) _))
+ // cond:
+ // result: (Const32 <t> [c])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpSliceMake {
+ break
+ }
+ v_0_1 := v_0.Args[1]
+ if v_0_1.Op != OpConst32 {
+ break
+ }
+ t := v_0_1.Type
+ c := v_0_1.AuxInt
+ v.reset(OpConst32)
+ v.Type = t
+ v.AuxInt = c
+ return true
+ }
+ // match: (SliceLen (SliceMake _ (SliceLen x) _))
+ // cond:
+ // result: (SliceLen x)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpSliceMake {
+ break
+ }
+ v_0_1 := v_0.Args[1]
+ if v_0_1.Op != OpSliceLen {
+ break
+ }
+ x := v_0_1.Args[0]
+ v.reset(OpSliceLen)
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValuegeneric_OpSlicePtr(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (SlicePtr (SliceMake (SlicePtr x) _ _))
+ // cond:
+ // result: (SlicePtr x)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpSliceMake {
+ break
+ }
+ v_0_0 := v_0.Args[0]
+ if v_0_0.Op != OpSlicePtr {
+ break
+ }
+ x := v_0_0.Args[0]
+ v.reset(OpSlicePtr)
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValuegeneric_OpSlicemask(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Slicemask (Const32 [x]))
+ // cond: x > 0
+ // result: (Const32 [-1])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpConst32 {
+ break
+ }
+ x := v_0.AuxInt
+ if !(x > 0) {
+ break
+ }
+ v.reset(OpConst32)
+ v.AuxInt = -1
+ return true
+ }
+ // match: (Slicemask (Const32 [0]))
+ // cond:
+ // result: (Const32 [0])
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpConst32 {
+ break
+ }
+ if v_0.AuxInt != 0 {
+ break
+ }
+ v.reset(OpConst32)
+ v.AuxInt = 0
+ return true
+ }
+ // match: (Slicemask (Const64 [x]))
+ // cond: x > 0
+ // result: (Const64 [-1])
for {
v_0 := v.Args[0]
- if v_0.Op != OpSliceMake {
+ if v_0.Op != OpConst64 {
break
}
- v_0_1 := v_0.Args[1]
- if v_0_1.Op != OpConst64 {
+ x := v_0.AuxInt
+ if !(x > 0) {
break
}
- t := v_0_1.Type
- c := v_0_1.AuxInt
v.reset(OpConst64)
- v.Type = t
- v.AuxInt = c
+ v.AuxInt = -1
return true
}
- // match: (SliceLen (SliceMake _ (SliceLen x) _))
+ // match: (Slicemask (Const64 [0]))
// cond:
- // result: (SliceLen x)
+ // result: (Const64 [0])
for {
v_0 := v.Args[0]
- if v_0.Op != OpSliceMake {
+ if v_0.Op != OpConst64 {
break
}
- v_0_1 := v_0.Args[1]
- if v_0_1.Op != OpSliceLen {
+ if v_0.AuxInt != 0 {
break
}
- x := v_0_1.Args[0]
- v.reset(OpSliceLen)
- v.AddArg(x)
+ v.reset(OpConst64)
+ v.AuxInt = 0
return true
}
return false
}
-func rewriteValuegeneric_OpSlicePtr(v *Value, config *Config) bool {
+func rewriteValuegeneric_OpSqrt(v *Value, config *Config) bool {
b := v.Block
_ = b
- // match: (SlicePtr (SliceMake (SlicePtr x) _ _))
+ // match: (Sqrt (Const64F [c]))
// cond:
- // result: (SlicePtr x)
+ // result: (Const64F [f2i(math.Sqrt(i2f(c)))])
for {
v_0 := v.Args[0]
- if v_0.Op != OpSliceMake {
- break
- }
- v_0_0 := v_0.Args[0]
- if v_0_0.Op != OpSlicePtr {
+ if v_0.Op != OpConst64F {
break
}
- x := v_0_0.Args[0]
- v.reset(OpSlicePtr)
- v.AddArg(x)
+ c := v_0.AuxInt
+ v.reset(OpConst64F)
+ v.AuxInt = f2i(math.Sqrt(i2f(c)))
return true
}
return false
@@ -8837,7 +10352,7 @@ func rewriteValuegeneric_OpStore(v *Value, config *Config) bool {
}
// match: (Store [size] dst (Load <t> src mem) mem)
// cond: !config.fe.CanSSA(t)
- // result: (Move [size] dst src mem)
+ // result: (Move [MakeSizeAndAlign(size, t.Alignment()).Int64()] dst src mem)
for {
size := v.AuxInt
dst := v.Args[0]
@@ -8855,7 +10370,7 @@ func rewriteValuegeneric_OpStore(v *Value, config *Config) bool {
break
}
v.reset(OpMove)
- v.AuxInt = size
+ v.AuxInt = MakeSizeAndAlign(size, t.Alignment()).Int64()
v.AddArg(dst)
v.AddArg(src)
v.AddArg(mem)
@@ -8863,7 +10378,7 @@ func rewriteValuegeneric_OpStore(v *Value, config *Config) bool {
}
// match: (Store [size] dst (Load <t> src mem) (VarDef {x} mem))
// cond: !config.fe.CanSSA(t)
- // result: (Move [size] dst src (VarDef {x} mem))
+ // result: (Move [MakeSizeAndAlign(size, t.Alignment()).Int64()] dst src (VarDef {x} mem))
for {
size := v.AuxInt
dst := v.Args[0]
@@ -8886,7 +10401,7 @@ func rewriteValuegeneric_OpStore(v *Value, config *Config) bool {
break
}
v.reset(OpMove)
- v.AuxInt = size
+ v.AuxInt = MakeSizeAndAlign(size, t.Alignment()).Int64()
v.AddArg(dst)
v.AddArg(src)
v0 := b.NewValue0(v.Line, OpVarDef, TypeMem)
@@ -8895,6 +10410,39 @@ func rewriteValuegeneric_OpStore(v *Value, config *Config) bool {
v.AddArg(v0)
return true
}
+ // match: (Store _ (ArrayMake0) mem)
+ // cond:
+ // result: mem
+ for {
+ v_1 := v.Args[1]
+ if v_1.Op != OpArrayMake0 {
+ break
+ }
+ mem := v.Args[2]
+ v.reset(OpCopy)
+ v.Type = mem.Type
+ v.AddArg(mem)
+ return true
+ }
+ // match: (Store [size] dst (ArrayMake1 e) mem)
+ // cond:
+ // result: (Store [size] dst e mem)
+ for {
+ size := v.AuxInt
+ dst := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpArrayMake1 {
+ 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)
+ return true
+ }
return false
}
func rewriteValuegeneric_OpStringLen(v *Value, config *Config) bool {
@@ -9141,6 +10689,22 @@ func rewriteValuegeneric_OpStructSelect(v *Value, config *Config) bool {
v0.AddArg(mem)
return true
}
+ // match: (StructSelect [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_OpSub16(v *Value, config *Config) bool {
@@ -9348,6 +10912,23 @@ func rewriteValuegeneric_OpSub32F(v *Value, config *Config) bool {
v.AuxInt = f2i(float64(i2f32(c) - i2f32(d)))
return true
}
+ // match: (Sub32F x (Const32F [0]))
+ // cond:
+ // result: x
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpConst32F {
+ break
+ }
+ if v_1.AuxInt != 0 {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
return false
}
func rewriteValuegeneric_OpSub64(v *Value, config *Config) bool {
@@ -9463,6 +11044,23 @@ func rewriteValuegeneric_OpSub64F(v *Value, config *Config) bool {
v.AuxInt = f2i(i2f(c) - i2f(d))
return true
}
+ // match: (Sub64F x (Const64F [0]))
+ // cond:
+ // result: x
+ for {
+ x := v.Args[0]
+ v_1 := v.Args[1]
+ if v_1.Op != OpConst64F {
+ break
+ }
+ if v_1.AuxInt != 0 {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
return false
}
func rewriteValuegeneric_OpSub8(v *Value, config *Config) bool {
@@ -9573,6 +11171,34 @@ func rewriteValuegeneric_OpTrunc16to8(v *Value, config *Config) bool {
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 {
+ break
+ }
+ x := v_0.Args[0]
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ // match: (Trunc16to8 (SignExt8to16 x))
+ // cond:
+ // result: x
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpSignExt8to16 {
+ break
+ }
+ x := v_0.Args[0]
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
// match: (Trunc16to8 (And16 (Const16 [y]) x))
// cond: y&0xFF == 0xFF
// result: (Trunc16to8 x)
@@ -9612,6 +11238,60 @@ func rewriteValuegeneric_OpTrunc32to16(v *Value, config *Config) bool {
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 {
+ break
+ }
+ x := v_0.Args[0]
+ v.reset(OpZeroExt8to16)
+ v.AddArg(x)
+ return true
+ }
+ // match: (Trunc32to16 (ZeroExt16to32 x))
+ // cond:
+ // result: x
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpZeroExt16to32 {
+ break
+ }
+ x := v_0.Args[0]
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ // match: (Trunc32to16 (SignExt8to32 x))
+ // cond:
+ // result: (SignExt8to16 x)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpSignExt8to32 {
+ break
+ }
+ x := v_0.Args[0]
+ v.reset(OpSignExt8to16)
+ v.AddArg(x)
+ return true
+ }
+ // match: (Trunc32to16 (SignExt16to32 x))
+ // cond:
+ // result: x
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpSignExt16to32 {
+ break
+ }
+ 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)
@@ -9651,6 +11331,34 @@ func rewriteValuegeneric_OpTrunc32to8(v *Value, config *Config) bool {
v.AuxInt = int64(int8(c))
return true
}
+ // match: (Trunc32to8 (ZeroExt8to32 x))
+ // cond:
+ // result: x
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpZeroExt8to32 {
+ break
+ }
+ x := v_0.Args[0]
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ // match: (Trunc32to8 (SignExt8to32 x))
+ // cond:
+ // result: x
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpSignExt8to32 {
+ break
+ }
+ x := v_0.Args[0]
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
// match: (Trunc32to8 (And32 (Const32 [y]) x))
// cond: y&0xFF == 0xFF
// result: (Trunc32to8 x)
@@ -9685,9 +11393,63 @@ func rewriteValuegeneric_OpTrunc64to16(v *Value, config *Config) bool {
if v_0.Op != OpConst64 {
break
}
- c := v_0.AuxInt
- v.reset(OpConst16)
- v.AuxInt = int64(int16(c))
+ c := v_0.AuxInt
+ v.reset(OpConst16)
+ v.AuxInt = int64(int16(c))
+ return true
+ }
+ // match: (Trunc64to16 (ZeroExt8to64 x))
+ // cond:
+ // result: (ZeroExt8to16 x)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpZeroExt8to64 {
+ break
+ }
+ x := v_0.Args[0]
+ v.reset(OpZeroExt8to16)
+ v.AddArg(x)
+ return true
+ }
+ // match: (Trunc64to16 (ZeroExt16to64 x))
+ // cond:
+ // result: x
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpZeroExt16to64 {
+ break
+ }
+ x := v_0.Args[0]
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ // match: (Trunc64to16 (SignExt8to64 x))
+ // cond:
+ // result: (SignExt8to16 x)
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpSignExt8to64 {
+ break
+ }
+ x := v_0.Args[0]
+ v.reset(OpSignExt8to16)
+ v.AddArg(x)
+ return true
+ }
+ // match: (Trunc64to16 (SignExt16to64 x))
+ // cond:
+ // result: x
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpSignExt16to64 {
+ break
+ }
+ x := v_0.Args[0]
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
return true
}
// match: (Trunc64to16 (And64 (Const64 [y]) x))
@@ -9729,6 +11491,86 @@ func rewriteValuegeneric_OpTrunc64to32(v *Value, config *Config) bool {
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 {
+ 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 {
+ break
+ }
+ x := v_0.Args[0]
+ v.reset(OpZeroExt16to32)
+ v.AddArg(x)
+ return true
+ }
+ // match: (Trunc64to32 (ZeroExt32to64 x))
+ // cond:
+ // result: x
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpZeroExt32to64 {
+ 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 {
+ break
+ }
+ x := v_0.Args[0]
+ 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
+ }
+ x := v_0.Args[0]
+ v.reset(OpSignExt16to32)
+ v.AddArg(x)
+ return true
+ }
+ // match: (Trunc64to32 (SignExt32to64 x))
+ // cond:
+ // result: x
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpSignExt32to64 {
+ 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)
@@ -9768,6 +11610,34 @@ func rewriteValuegeneric_OpTrunc64to8(v *Value, config *Config) bool {
v.AuxInt = int64(int8(c))
return true
}
+ // match: (Trunc64to8 (ZeroExt8to64 x))
+ // cond:
+ // result: x
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpZeroExt8to64 {
+ break
+ }
+ x := v_0.Args[0]
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ // match: (Trunc64to8 (SignExt8to64 x))
+ // cond:
+ // result: x
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpSignExt8to64 {
+ break
+ }
+ 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)
@@ -10299,27 +12169,222 @@ func rewriteValuegeneric_OpXor8(v *Value, config *Config) bool {
}
return false
}
-func rewriteBlockgeneric(b *Block) bool {
- switch b.Kind {
- case BlockCheck:
- // match: (Check (NilCheck (GetG _) _) next)
- // cond:
- // result: (Plain nil next)
- for {
- v := b.Control
- if v.Op != OpNilCheck {
- break
- }
- v_0 := v.Args[0]
- if v_0.Op != OpGetG {
- break
- }
- next := b.Succs[0]
- b.Kind = BlockPlain
- b.SetControl(nil)
- _ = next
- return true
+func rewriteValuegeneric_OpZero(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (Zero (Load (OffPtr [c] (SP)) mem) mem)
+ // cond: mem.Op == OpStaticCall && isSameSym(mem.Aux, "runtime.newobject") && c == config.ctxt.FixedFrameSize() + config.PtrSize
+ // result: mem
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpLoad {
+ break
+ }
+ 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.PtrSize) {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = mem.Type
+ v.AddArg(mem)
+ return true
+ }
+ return false
+}
+func rewriteValuegeneric_OpZeroExt16to32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ZeroExt16to32 (Trunc32to16 x:(Rsh32Ux64 _ (Const64 [s]))))
+ // cond: s >= 16
+ // result: x
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpTrunc32to16 {
+ break
+ }
+ x := v_0.Args[0]
+ if x.Op != OpRsh32Ux64 {
+ break
+ }
+ x_1 := x.Args[1]
+ if x_1.Op != OpConst64 {
+ break
+ }
+ s := x_1.AuxInt
+ if !(s >= 16) {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValuegeneric_OpZeroExt16to64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ZeroExt16to64 (Trunc64to16 x:(Rsh64Ux64 _ (Const64 [s]))))
+ // cond: s >= 48
+ // result: x
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpTrunc64to16 {
+ break
+ }
+ x := v_0.Args[0]
+ if x.Op != OpRsh64Ux64 {
+ break
+ }
+ 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
+ }
+ return false
+}
+func rewriteValuegeneric_OpZeroExt32to64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ZeroExt32to64 (Trunc64to32 x:(Rsh64Ux64 _ (Const64 [s]))))
+ // cond: s >= 32
+ // result: x
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpTrunc64to32 {
+ break
+ }
+ x := v_0.Args[0]
+ if x.Op != OpRsh64Ux64 {
+ break
+ }
+ x_1 := x.Args[1]
+ if x_1.Op != OpConst64 {
+ break
+ }
+ s := x_1.AuxInt
+ if !(s >= 32) {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValuegeneric_OpZeroExt8to16(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ZeroExt8to16 (Trunc16to8 x:(Rsh16Ux64 _ (Const64 [s]))))
+ // cond: s >= 8
+ // result: x
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpTrunc16to8 {
+ break
+ }
+ x := v_0.Args[0]
+ if x.Op != OpRsh16Ux64 {
+ break
+ }
+ x_1 := x.Args[1]
+ if x_1.Op != OpConst64 {
+ break
+ }
+ s := x_1.AuxInt
+ if !(s >= 8) {
+ break
+ }
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteValuegeneric_OpZeroExt8to32(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ZeroExt8to32 (Trunc32to8 x:(Rsh32Ux64 _ (Const64 [s]))))
+ // cond: s >= 24
+ // result: x
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpTrunc32to8 {
+ break
+ }
+ x := v_0.Args[0]
+ if x.Op != OpRsh32Ux64 {
+ break
+ }
+ 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_OpZeroExt8to64(v *Value, config *Config) bool {
+ b := v.Block
+ _ = b
+ // match: (ZeroExt8to64 (Trunc64to8 x:(Rsh64Ux64 _ (Const64 [s]))))
+ // cond: s >= 56
+ // result: x
+ for {
+ v_0 := v.Args[0]
+ if v_0.Op != OpTrunc64to8 {
+ break
+ }
+ x := v_0.Args[0]
+ if x.Op != OpRsh64Ux64 {
+ break
+ }
+ x_1 := x.Args[1]
+ if x_1.Op != OpConst64 {
+ break
+ }
+ s := x_1.AuxInt
+ if !(s >= 56) {
+ break
}
+ v.reset(OpCopy)
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ return false
+}
+func rewriteBlockgeneric(b *Block, config *Config) bool {
+ switch b.Kind {
case BlockIf:
// match: (If (Not cond) yes no)
// cond:
diff --git a/src/cmd/compile/internal/ssa/schedule.go b/src/cmd/compile/internal/ssa/schedule.go
index 765f0c1..f2a89d8 100644
--- a/src/cmd/compile/internal/ssa/schedule.go
+++ b/src/cmd/compile/internal/ssa/schedule.go
@@ -8,6 +8,8 @@ import "container/heap"
const (
ScorePhi = iota // towards top of block
+ ScoreNilCheck
+ ScoreReadTuple
ScoreVarDef
ScoreMemory
ScoreDefault
@@ -83,7 +85,10 @@ func schedule(f *Func) {
// Compute score. Larger numbers are scheduled closer to the end of the block.
for _, v := range b.Values {
switch {
- case v.Op == OpAMD64LoweredGetClosurePtr:
+ case v.Op == OpAMD64LoweredGetClosurePtr || v.Op == OpPPC64LoweredGetClosurePtr ||
+ v.Op == OpARMLoweredGetClosurePtr || v.Op == OpARM64LoweredGetClosurePtr ||
+ v.Op == Op386LoweredGetClosurePtr || v.Op == OpMIPS64LoweredGetClosurePtr ||
+ v.Op == OpS390XLoweredGetClosurePtr || v.Op == OpMIPSLoweredGetClosurePtr:
// We also score GetLoweredClosurePtr as early as possible to ensure that the
// context register is not stomped. GetLoweredClosurePtr should only appear
// in the entry block where there are no phi functions, so there is no
@@ -92,6 +97,12 @@ func schedule(f *Func) {
f.Fatalf("LoweredGetClosurePtr appeared outside of entry block, b=%s", b.String())
}
score[v.ID] = ScorePhi
+ case v.Op == OpAMD64LoweredNilCheck || v.Op == OpPPC64LoweredNilCheck ||
+ v.Op == OpARMLoweredNilCheck || v.Op == OpARM64LoweredNilCheck ||
+ v.Op == Op386LoweredNilCheck || v.Op == OpMIPS64LoweredNilCheck ||
+ v.Op == OpS390XLoweredNilCheck || v.Op == OpMIPSLoweredNilCheck:
+ // Nil checks must come before loads from the same address.
+ score[v.ID] = ScoreNilCheck
case v.Op == OpPhi:
// We want all the phis first.
score[v.ID] = ScorePhi
@@ -103,7 +114,14 @@ func schedule(f *Func) {
// reduce register pressure. It also helps make sure
// VARDEF ops are scheduled before the corresponding LEA.
score[v.ID] = ScoreMemory
- case v.Type.IsFlags():
+ case v.Op == OpSelect0 || v.Op == OpSelect1:
+ // Schedule the pseudo-op of reading part of a tuple
+ // immediately after the tuple-generating op, since
+ // this value is already live. This also removes its
+ // false dependency on the other part of the tuple.
+ // Also ensures tuple is never spilled.
+ score[v.ID] = ScoreReadTuple
+ case v.Type.IsFlags() || v.Type.IsTuple():
// Schedule flag register generation as late as possible.
// This makes sure that we only have one live flags
// value at a time.
@@ -120,9 +138,13 @@ func schedule(f *Func) {
// the calculated store chain is good only for this block.
for _, v := range b.Values {
if v.Op != OpPhi && v.Type.IsMemory() {
+ mem := v
+ if v.Op == OpSelect1 {
+ v = v.Args[0]
+ }
for _, w := range v.Args {
if w.Type.IsMemory() {
- nextMem[w.ID] = v
+ nextMem[w.ID] = mem
}
}
}
@@ -188,6 +210,7 @@ func schedule(f *Func) {
// Schedule highest priority value, update use counts, repeat.
order = order[:0]
+ tuples := make(map[ID][]*Value)
for {
// Find highest priority schedulable value.
// Note that schedule is assembled backwards.
@@ -199,7 +222,31 @@ func schedule(f *Func) {
v := heap.Pop(priq).(*Value)
// Add it to the schedule.
- order = append(order, v)
+ // Do not emit tuple-reading ops until we're ready to emit the tuple-generating op.
+ //TODO: maybe remove ReadTuple score above, if it does not help on performance
+ switch {
+ case v.Op == OpSelect0:
+ if tuples[v.Args[0].ID] == nil {
+ tuples[v.Args[0].ID] = make([]*Value, 2)
+ }
+ tuples[v.Args[0].ID][0] = v
+ case v.Op == OpSelect1:
+ if tuples[v.Args[0].ID] == nil {
+ tuples[v.Args[0].ID] = make([]*Value, 2)
+ }
+ tuples[v.Args[0].ID][1] = v
+ case v.Type.IsTuple() && tuples[v.ID] != nil:
+ if tuples[v.ID][1] != nil {
+ order = append(order, tuples[v.ID][1])
+ }
+ if tuples[v.ID][0] != nil {
+ order = append(order, tuples[v.ID][0])
+ }
+ delete(tuples, v.ID)
+ fallthrough
+ default:
+ order = append(order, v)
+ }
// Update use counts of arguments.
for _, w := range v.Args {
diff --git a/src/cmd/compile/internal/ssa/sparsemap.go b/src/cmd/compile/internal/ssa/sparsemap.go
index afb9f60..70c4f61 100644
--- a/src/cmd/compile/internal/ssa/sparsemap.go
+++ b/src/cmd/compile/internal/ssa/sparsemap.go
@@ -10,6 +10,7 @@ package ssa
type sparseEntry struct {
key ID
val int32
+ aux int32
}
type sparseMap struct {
@@ -42,13 +43,14 @@ func (s *sparseMap) get(k ID) int32 {
return -1
}
-func (s *sparseMap) set(k ID, v int32) {
+func (s *sparseMap) set(k ID, v, a int32) {
i := s.sparse[k]
if i < int32(len(s.dense)) && s.dense[i].key == k {
s.dense[i].val = v
+ s.dense[i].aux = a
return
}
- s.dense = append(s.dense, sparseEntry{k, v})
+ s.dense = append(s.dense, sparseEntry{k, v, a})
s.sparse[k] = int32(len(s.dense)) - 1
}
@@ -62,7 +64,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})
+ s.dense = append(s.dense, sparseEntry{k, 1 << v, 0})
s.sparse[k] = int32(len(s.dense)) - 1
}
diff --git a/src/cmd/compile/internal/ssa/sparsetreemap.go b/src/cmd/compile/internal/ssa/sparsetreemap.go
index 3e6f296..d264675 100644
--- a/src/cmd/compile/internal/ssa/sparsetreemap.go
+++ b/src/cmd/compile/internal/ssa/sparsetreemap.go
@@ -57,7 +57,7 @@ type SparseTreeHelper struct {
// NewSparseTreeHelper returns a SparseTreeHelper for use
// in the gc package, for example in phi-function placement.
func NewSparseTreeHelper(f *Func) *SparseTreeHelper {
- dom := dominators(f)
+ dom := f.Idom()
ponums := make([]int32, f.NumBlocks())
po := postorderWithNumbering(f, ponums)
return makeSparseTreeHelper(newSparseTree(f, dom), dom, po, ponums)
diff --git a/src/cmd/compile/internal/ssa/stackalloc.go b/src/cmd/compile/internal/ssa/stackalloc.go
index 83f65d0..dc2fd7d 100644
--- a/src/cmd/compile/internal/ssa/stackalloc.go
+++ b/src/cmd/compile/internal/ssa/stackalloc.go
@@ -273,7 +273,7 @@ func (s *stackAllocState) computeLive(spillLive [][]ID) {
// Instead of iterating over f.Blocks, iterate over their postordering.
// Liveness information flows backward, so starting at the end
// increases the probability that we will stabilize quickly.
- po := postorder(s.f)
+ po := s.f.postorder()
for {
changed := false
for _, b := range po {
diff --git a/src/cmd/compile/internal/ssa/stackframe.go b/src/cmd/compile/internal/ssa/stackframe.go
new file mode 100644
index 0000000..de32c60
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/stackframe.go
@@ -0,0 +1,10 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ssa
+
+// stackframe calls back into the frontend to assign frame offsets.
+func stackframe(f *Func) {
+ f.Config.fe.AllocFrame(f)
+}
diff --git a/src/cmd/compile/internal/ssa/tighten.go b/src/cmd/compile/internal/ssa/tighten.go
index 2f7c309..6f19263 100644
--- a/src/cmd/compile/internal/ssa/tighten.go
+++ b/src/cmd/compile/internal/ssa/tighten.go
@@ -7,81 +7,135 @@ package ssa
// tighten moves Values closer to the Blocks in which they are used.
// This can reduce the amount of register spilling required,
// if it doesn't also create more live values.
-// For now, it handles only the trivial case in which a
-// Value with one or fewer args is only used in a single Block,
-// and not in a phi value.
-// TODO: Do something smarter.
// A Value can be moved to any block that
// dominates all blocks in which it is used.
-// Figure out when that will be an improvement.
func tighten(f *Func) {
- // For each value, the number of blocks in which it is used.
- uses := make([]int32, f.NumValues())
+ canMove := make([]bool, f.NumValues())
+ for _, b := range f.Blocks {
+ for _, v := range b.Values {
+ switch v.Op {
+ case OpPhi, OpGetClosurePtr, OpArg, OpSelect0, OpSelect1:
+ // Phis need to stay in their block.
+ // GetClosurePtr & Arg must stay in the entry block.
+ // Tuple selectors must stay with the tuple generator.
+ continue
+ }
+ if len(v.Args) > 0 && v.Args[len(v.Args)-1].Type.IsMemory() {
+ // We can't move values which have a memory arg - it might
+ // make two memory values live across a block boundary.
+ continue
+ }
+ // Count arguments which will need a register.
+ narg := 0
+ for _, a := range v.Args {
+ switch a.Op {
+ case OpConst8, OpConst16, OpConst32, OpConst64, OpAddr:
+ // Probably foldable into v, don't count as an argument needing a register.
+ // TODO: move tighten to a machine-dependent phase and use v.rematerializeable()?
+ default:
+ narg++
+ }
+ }
+ if narg >= 2 && !v.Type.IsBoolean() {
+ // Don't move values with more than one input, as that may
+ // increase register pressure.
+ // We make an exception for boolean-typed values, as they will
+ // likely be converted to flags, and we want flag generators
+ // moved next to uses (because we only have 1 flag register).
+ continue
+ }
+ canMove[v.ID] = true
+ }
+ }
- // For each value, whether that value is ever an arg to a phi value.
- phi := make([]bool, f.NumValues())
+ // Build data structure for fast least-common-ancestor queries.
+ lca := makeLCArange(f)
- // For each value, one block in which that value is used.
- home := make([]*Block, f.NumValues())
+ // For each moveable value, record the block that dominates all uses found so far.
+ target := make([]*Block, f.NumValues())
+
+ // Grab loop information.
+ // We use this to make sure we don't tighten a value into a (deeper) loop.
+ idom := f.Idom()
+ loops := f.loopnest()
+ loops.calculateDepths()
changed := true
for changed {
changed = false
- // Reset uses
- for i := range uses {
- uses[i] = 0
+ // Reset target
+ for i := range target {
+ target[i] = nil
}
- // No need to reset home; any relevant values will be written anew anyway.
- // No need to reset phi; once used in a phi, always used in a phi.
+ // Compute target locations (for moveable values only).
+ // target location = the least common ancestor of all uses in the dominator tree.
for _, b := range f.Blocks {
for _, v := range b.Values {
- for _, w := range v.Args {
+ for i, a := range v.Args {
+ if !canMove[a.ID] {
+ continue
+ }
+ use := b
if v.Op == OpPhi {
- phi[w.ID] = true
+ use = b.Preds[i].b
+ }
+ if target[a.ID] == nil {
+ target[a.ID] = use
+ } else {
+ target[a.ID] = lca.find(target[a.ID], use)
}
- uses[w.ID]++
- home[w.ID] = b
}
}
- if b.Control != nil {
- uses[b.Control.ID]++
- home[b.Control.ID] = b
+ if c := b.Control; c != nil {
+ if !canMove[c.ID] {
+ continue
+ }
+ if target[c.ID] == nil {
+ target[c.ID] = b
+ } else {
+ target[c.ID] = lca.find(target[c.ID], b)
+ }
}
}
+ // If the target location is inside a loop,
+ // move the target location up to just before the loop head.
for _, b := range f.Blocks {
- for i := 0; i < len(b.Values); i++ {
- v := b.Values[i]
- if v.Op == OpPhi || v.Op == OpGetClosurePtr || v.Op == OpConvert || v.Op == OpArg {
- // GetClosurePtr & Arg must stay in entry block.
- // OpConvert must not float over call sites.
- // TODO do we instead need a dependence edge of some sort for OpConvert?
- // Would memory do the trick, or do we need something else that relates
- // to safe point operations?
+ origloop := loops.b2l[b.ID]
+ for _, v := range b.Values {
+ t := target[v.ID]
+ if t == nil {
continue
}
- if len(v.Args) > 0 && v.Args[len(v.Args)-1].Type.IsMemory() {
- // We can't move values which have a memory arg - it might
- // make two memory values live across a block boundary.
- continue
+ targetloop := loops.b2l[t.ID]
+ for targetloop != nil && (origloop == nil || targetloop.depth > origloop.depth) {
+ t = idom[targetloop.header.ID]
+ target[v.ID] = t
+ targetloop = loops.b2l[t.ID]
}
- if uses[v.ID] == 1 && !phi[v.ID] && home[v.ID] != b && len(v.Args) < 2 {
- // v is used in exactly one block, and it is not b.
- // Furthermore, it takes at most one input,
- // so moving it will not increase the
- // number of live values anywhere.
- // Move v to that block.
- c := home[v.ID]
- c.Values = append(c.Values, v)
- v.Block = c
- last := len(b.Values) - 1
- b.Values[i] = b.Values[last]
- b.Values[last] = nil
- b.Values = b.Values[:last]
- changed = true
+ }
+ }
+
+ // Move values to target locations.
+ for _, b := range f.Blocks {
+ for i := 0; i < len(b.Values); i++ {
+ v := b.Values[i]
+ t := target[v.ID]
+ if t == nil || t == b {
+ // v is not moveable, or is already in correct place.
+ continue
}
+ // Move v to the block which dominates its uses.
+ t.Values = append(t.Values, v)
+ v.Block = t
+ last := len(b.Values) - 1
+ b.Values[i] = b.Values[last]
+ b.Values[last] = nil
+ b.Values = b.Values[:last]
+ changed = true
+ i--
}
}
}
diff --git a/src/cmd/compile/internal/ssa/trim.go b/src/cmd/compile/internal/ssa/trim.go
index 8ffb459..09e80bd 100644
--- a/src/cmd/compile/internal/ssa/trim.go
+++ b/src/cmd/compile/internal/ssa/trim.go
@@ -9,24 +9,129 @@ package ssa
func trim(f *Func) {
n := 0
for _, b := range f.Blocks {
- if b.Kind != BlockPlain || len(b.Values) != 0 || len(b.Preds) != 1 {
+ if !trimmableBlock(b) {
f.Blocks[n] = b
n++
continue
}
- // TODO: handle len(b.Preds)>1 case.
- // Splice b out of the graph.
- p := b.Preds[0].b
- i := b.Preds[0].i
- s := b.Succs[0].b
- j := b.Succs[0].i
+ // Splice b out of the graph. NOTE: `mergePhi` depends on the
+ // order, in which the predecessors edges are merged here.
+ p, i := b.Preds[0].b, b.Preds[0].i
+ s, j := b.Succs[0].b, b.Succs[0].i
+ ns := len(s.Preds)
p.Succs[i] = Edge{s, j}
s.Preds[j] = Edge{p, i}
+
+ for _, e := range b.Preds[1:] {
+ p, i := e.b, e.i
+ p.Succs[i] = Edge{s, len(s.Preds)}
+ s.Preds = append(s.Preds, Edge{p, i})
+ }
+
+ // If `s` had more than one predecessor, update its phi-ops to
+ // account for the merge.
+ if ns > 1 {
+ for _, v := range s.Values {
+ if v.Op == OpPhi {
+ mergePhi(v, j, b)
+ }
+ }
+ // Remove the phi-ops from `b` if they were merged into the
+ // phi-ops of `s`.
+ k := 0
+ for _, v := range b.Values {
+ if v.Op == OpPhi {
+ if v.Uses == 0 {
+ v.resetArgs()
+ continue
+ }
+ // 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])
+ }
+ }
+ b.Values[k] = v
+ k++
+ }
+ b.Values = b.Values[:k]
+ }
+
+ // Merge the blocks' values.
+ for _, v := range b.Values {
+ v.Block = s
+ }
+ k := len(b.Values)
+ m := len(s.Values)
+ for i := 0; i < k; i++ {
+ s.Values = append(s.Values, nil)
+ }
+ copy(s.Values[k:], s.Values[:m])
+ copy(s.Values, b.Values)
+ }
+ if n < len(f.Blocks) {
+ f.invalidateCFG()
+ tail := f.Blocks[n:]
+ for i := range tail {
+ tail[i] = nil
+ }
+ f.Blocks = f.Blocks[:n]
+ }
+}
+
+// emptyBlock returns true if the block does not contain actual
+// instructions
+func emptyBlock(b *Block) bool {
+ for _, v := range b.Values {
+ if v.Op != OpPhi {
+ return false
+ }
+ }
+ return true
+}
+
+// trimmableBlock returns true if the block can be trimmed from the CFG,
+// subject to the following criteria:
+// - it should not be the first block
+// - it should be BlockPlain
+// - it should not loop back to itself
+// - it either is the single predecessor of the successor block or
+// contains no actual instructions
+func trimmableBlock(b *Block) bool {
+ if b.Kind != BlockPlain || b == b.Func.Entry {
+ return false
}
- tail := f.Blocks[n:]
- for i := range tail {
- tail[i] = nil
+ s := b.Succs[0].b
+ return s != b && (len(s.Preds) == 1 || emptyBlock(b))
+}
+
+// mergePhi adjusts the number of `v`s arguments to account for merge
+// of `b`, which was `i`th predecessor of the `v`s block. Returns
+// `v`.
+func mergePhi(v *Value, i int, b *Block) *Value {
+ u := v.Args[i]
+ if u.Block == b {
+ if u.Op != OpPhi {
+ b.Func.Fatalf("value %s is not a phi operation", u.LongString())
+ }
+ // If the original block contained u = φ(u0, u1, ..., un) and
+ // the current phi is
+ // v = φ(v0, v1, ..., u, ..., vk)
+ // then the merged phi is
+ // v = φ(v0, v1, ..., u0, ..., vk, u1, ..., un)
+ v.SetArg(i, u.Args[0])
+ v.AddArgs(u.Args[1:]...)
+ } else {
+ // If the original block contained u = φ(u0, u1, ..., un) and
+ // the current phi is
+ // v = φ(v0, v1, ..., vi, ..., vk)
+ // i.e. it does not use a value from the predecessor block,
+ // then the merged phi is
+ // v = φ(v0, v1, ..., vk, vi, vi, ...)
+ for j := 1; j < len(b.Preds); j++ {
+ v.AddArg(v.Args[i])
+ }
}
- f.Blocks = f.Blocks[:n]
+ return v
}
diff --git a/src/cmd/compile/internal/ssa/type.go b/src/cmd/compile/internal/ssa/type.go
index 91a4efe..3ebee6a 100644
--- a/src/cmd/compile/internal/ssa/type.go
+++ b/src/cmd/compile/internal/ssa/type.go
@@ -27,12 +27,13 @@ type Type interface {
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
+ 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
@@ -69,6 +70,7 @@ 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") }
@@ -79,6 +81,48 @@ 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
@@ -116,6 +160,25 @@ func (t *CompilerType) Compare(u Type) Cmp {
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}
@@ -123,3 +186,7 @@ var (
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
index 3b1a892..a76a065 100644
--- a/src/cmd/compile/internal/ssa/type_test.go
+++ b/src/cmd/compile/internal/ssa/type_test.go
@@ -39,6 +39,7 @@ 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 }
diff --git a/src/cmd/compile/internal/ssa/value.go b/src/cmd/compile/internal/ssa/value.go
index 867221b..489ed35 100644
--- a/src/cmd/compile/internal/ssa/value.go
+++ b/src/cmd/compile/internal/ssa/value.go
@@ -26,6 +26,7 @@ type Value struct {
// 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.
+ // Floats are stored in AuxInt using math.Float64bits(f).
AuxInt int64
Aux interface{}
@@ -96,7 +97,7 @@ func (v *Value) AuxValAndOff() ValAndOff {
// long form print. v# = opcode <type> [aux] args [: reg]
func (v *Value) LongString() string {
- s := fmt.Sprintf("v%d = %s", v.ID, v.Op.String())
+ s := fmt.Sprintf("v%d = %s", v.ID, v.Op)
s += " <" + v.Type.String() + ">"
s += v.auxString()
for _, a := range v.Args {
@@ -125,18 +126,20 @@ 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:
if v.Aux != nil {
- return fmt.Sprintf(" {%s}", v.Aux)
+ return fmt.Sprintf(" {%v}", v.Aux)
}
case auxSymOff, auxSymInt32:
s := ""
if v.Aux != nil {
- s = fmt.Sprintf(" {%s}", v.Aux)
+ s = fmt.Sprintf(" {%v}", v.Aux)
}
if v.AuxInt != 0 {
s += fmt.Sprintf(" [%v]", v.AuxInt)
@@ -145,9 +148,15 @@ func (v *Value) auxString() string {
case auxSymValAndOff:
s := ""
if v.Aux != nil {
- s = fmt.Sprintf(" {%s}", v.Aux)
+ 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 ""
}
@@ -225,9 +234,6 @@ func (v *Value) Log() bool { return v.Block.Log() }
func (v *Value) Fatalf(msg string, args ...interface{}) {
v.Block.Func.Config.Fatalf(v.Line, msg, args...)
}
-func (v *Value) Unimplementedf(msg string, args ...interface{}) {
- v.Block.Func.Config.Unimplementedf(v.Line, msg, args...)
-}
// isGenericIntConst returns whether v is a generic integer constant.
func (v *Value) isGenericIntConst() bool {
@@ -268,3 +274,38 @@ func (s *ArgSymbol) String() string {
func (s *AutoSymbol) String() string {
return s.Node.String()
}
+
+// Reg returns the register assigned to v, in cmd/internal/obj/$ARCH numbering.
+func (v *Value) Reg() int16 {
+ reg := v.Block.Func.RegAlloc[v.ID]
+ if reg == nil {
+ v.Fatalf("nil register for value: %s\n%s\n", v.LongString(), v.Block.Func)
+ }
+ return reg.(*Register).objNum
+}
+
+// Reg0 returns the register assigned to the first output of v, in cmd/internal/obj/$ARCH numbering.
+func (v *Value) Reg0() int16 {
+ reg := v.Block.Func.RegAlloc[v.ID].(LocPair)[0]
+ if reg == nil {
+ v.Fatalf("nil first register for value: %s\n%s\n", v.LongString(), v.Block.Func)
+ }
+ return reg.(*Register).objNum
+}
+
+// Reg1 returns the register assigned to the second output of v, in cmd/internal/obj/$ARCH numbering.
+func (v *Value) Reg1() int16 {
+ reg := v.Block.Func.RegAlloc[v.ID].(LocPair)[1]
+ if reg == nil {
+ v.Fatalf("nil second register for value: %s\n%s\n", v.LongString(), v.Block.Func)
+ }
+ return reg.(*Register).objNum
+}
+
+func (v *Value) RegName() string {
+ reg := v.Block.Func.RegAlloc[v.ID]
+ if reg == nil {
+ v.Fatalf("nil register for value: %s\n%s\n", v.LongString(), v.Block.Func)
+ }
+ return reg.(*Register).name
+}
diff --git a/src/cmd/compile/internal/ssa/writebarrier.go b/src/cmd/compile/internal/ssa/writebarrier.go
new file mode 100644
index 0000000..b914154
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/writebarrier.go
@@ -0,0 +1,278 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ssa
+
+import "fmt"
+
+// writebarrier expands write barrier ops (StoreWB, MoveWB, etc.) into
+// branches and runtime calls, like
+//
+// if writeBarrier.enabled {
+// writebarrierptr(ptr, val)
+// } else {
+// *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 {
+ switch v.Op {
+ case OpStoreWB, OpMoveWB, OpMoveWBVolatile:
+ if IsStackAddr(v.Args[0]) {
+ 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
+ }
+ 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)
+ }
+
+ mem := v.Args[2]
+ 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)
+ }
+ }
+
+ // 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)
+ }
+ }
+ }
+
+ 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
+ }
+
+ // 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
+ }
+
+ // then block: emit write barrier call
+ memThen = wbcall(line, bThen, fn, typ, ptr, val, memThen, sp, sb, w.Op == OpMoveWBVolatile)
+
+ // 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)
+ }
+ }
+
+ // 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.
+ v = storeWBs[len(storeWBs)-1]
+ bEnd.Values = append(bEnd.Values, v)
+ v.Block = bEnd
+ v.reset(OpPhi)
+ v.Type = TypeMem
+ v.AddArg(memThen)
+ v.AddArg(memElse)
+ for _, w := range storeWBs[:len(storeWBs)-1] {
+ for _, a := range w.Args {
+ a.Uses--
+ }
+ }
+ for _, w := range storeWBs[:len(storeWBs)-1] {
+ f.freeValue(w)
+ }
+
+ if f.Config.fe.Debug_wb() {
+ f.Config.Warnl(line, "write barrier")
+ }
+
+ break valueLoop
+ }
+ }
+ }
+}
+
+// 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 {
+ config := b.Func.Config
+
+ var tmp GCNode
+ if valIsVolatile {
+ // Copy to temp location if the source is volatile (will be clobbered by
+ // a function call). Marshaling the args to typedmemmove might clobber the
+ // value we're trying to move.
+ 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)
+ val = tmpaddr
+ }
+
+ // put arguments on stack
+ off := config.ctxt.FixedFrameSize()
+
+ if typ != nil { // for typedmemmove
+ taddr := b.NewValue1A(line, OpAddr, config.fe.TypeUintptr(), 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)
+ 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)
+ 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)
+ off += val.Type.Size()
+ }
+ off = round(off, config.PtrSize)
+
+ // issue call
+ mem = b.NewValue1A(line, OpStaticCall, TypeMem, fn, mem)
+ mem.AuxInt = off - config.ctxt.FixedFrameSize()
+
+ if valIsVolatile {
+ mem = b.NewValue1A(line, OpVarKill, TypeMem, tmp, mem) // mark temp dead
+ }
+
+ return mem
+}
+
+// round to a multiple of r, r is a power of 2
+func round(o int64, r int64) int64 {
+ return (o + r - 1) &^ (r - 1)
+}
+
+// IsStackAddr returns whether v is known to be an address of a stack slot
+func IsStackAddr(v *Value) bool {
+ for v.Op == OpOffPtr || v.Op == OpAddPtr || v.Op == OpPtrIndex || v.Op == OpCopy {
+ v = v.Args[0]
+ }
+ switch v.Op {
+ case OpSP:
+ return true
+ case OpAddr:
+ return v.Args[0].Op == OpSP
+ }
+ return false
+}
diff --git a/src/cmd/compile/internal/syntax/dumper.go b/src/cmd/compile/internal/syntax/dumper.go
new file mode 100644
index 0000000..bb369fc
--- /dev/null
+++ b/src/cmd/compile/internal/syntax/dumper.go
@@ -0,0 +1,212 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file implements printing of syntax tree structures.
+
+package syntax
+
+import (
+ "fmt"
+ "io"
+ "reflect"
+ "unicode"
+ "unicode/utf8"
+)
+
+// Fdump dumps the structure of the syntax tree rooted at n to w.
+// It is intended for debugging purposes; no specific output format
+// is guaranteed.
+func Fdump(w io.Writer, n Node) (err error) {
+ p := dumper{
+ output: w,
+ ptrmap: make(map[Node]int),
+ last: '\n', // force printing of line number on first line
+ }
+
+ defer func() {
+ if e := recover(); e != nil {
+ err = e.(localError).err // re-panics if it's not a localError
+ }
+ }()
+
+ if n == nil {
+ p.printf("nil\n")
+ return
+ }
+ p.dump(reflect.ValueOf(n), n)
+ p.printf("\n")
+
+ return
+}
+
+type dumper struct {
+ output io.Writer
+ ptrmap map[Node]int // node -> dump line number
+ indent int // current indentation level
+ last byte // last byte processed by Write
+ line int // current line number
+}
+
+var indentBytes = []byte(". ")
+
+func (p *dumper) Write(data []byte) (n int, err error) {
+ var m int
+ for i, b := range data {
+ // invariant: data[0:n] has been written
+ if b == '\n' {
+ m, err = p.output.Write(data[n : i+1])
+ n += m
+ if err != nil {
+ return
+ }
+ } else if p.last == '\n' {
+ p.line++
+ _, err = fmt.Fprintf(p.output, "%6d ", p.line)
+ if err != nil {
+ return
+ }
+ for j := p.indent; j > 0; j-- {
+ _, err = p.output.Write(indentBytes)
+ if err != nil {
+ return
+ }
+ }
+ }
+ p.last = b
+ }
+ if len(data) > n {
+ m, err = p.output.Write(data[n:])
+ n += m
+ }
+ return
+}
+
+// localError wraps locally caught errors so we can distinguish
+// them from genuine panics which we don't want to return as errors.
+type localError struct {
+ err error
+}
+
+// printf is a convenience wrapper that takes care of print errors.
+func (p *dumper) printf(format string, args ...interface{}) {
+ if _, err := fmt.Fprintf(p, format, args...); err != nil {
+ panic(localError{err})
+ }
+}
+
+// dump prints the contents of x.
+// If x is the reflect.Value of a struct s, where &s
+// implements Node, then &s should be passed for n -
+// this permits printing of the unexported span and
+// comments fields of the embedded isNode field by
+// calling the Span() and Comment() instead of using
+// reflection.
+func (p *dumper) dump(x reflect.Value, n Node) {
+ switch x.Kind() {
+ case reflect.Interface:
+ if x.IsNil() {
+ p.printf("nil")
+ return
+ }
+ p.dump(x.Elem(), nil)
+
+ case reflect.Ptr:
+ if x.IsNil() {
+ p.printf("nil")
+ return
+ }
+
+ // special cases for identifiers w/o attached comments (common case)
+ if x, ok := x.Interface().(*Name); ok {
+ p.printf(x.Value)
+ return
+ }
+
+ p.printf("*")
+ // Fields may share type expressions, and declarations
+ // may share the same group - use ptrmap to keep track
+ // of nodes that have been printed already.
+ if ptr, ok := x.Interface().(Node); ok {
+ if line, exists := p.ptrmap[ptr]; exists {
+ p.printf("(Node @ %d)", line)
+ return
+ }
+ p.ptrmap[ptr] = p.line
+ n = ptr
+ }
+ p.dump(x.Elem(), n)
+
+ case reflect.Slice:
+ if x.IsNil() {
+ p.printf("nil")
+ return
+ }
+ p.printf("%s (%d entries) {", x.Type(), x.Len())
+ if x.Len() > 0 {
+ p.indent++
+ p.printf("\n")
+ for i, n := 0, x.Len(); i < n; i++ {
+ p.printf("%d: ", i)
+ p.dump(x.Index(i), nil)
+ p.printf("\n")
+ }
+ p.indent--
+ }
+ p.printf("}")
+
+ case reflect.Struct:
+ typ := x.Type()
+
+ // if span, ok := x.Interface().(lexical.Span); ok {
+ // p.printf("%s", &span)
+ // return
+ // }
+
+ p.printf("%s {", typ)
+ p.indent++
+
+ first := true
+ if n != nil {
+ p.printf("\n")
+ first = false
+ // p.printf("Span: %s\n", n.Span())
+ // if c := *n.Comments(); c != nil {
+ // p.printf("Comments: ")
+ // p.dump(reflect.ValueOf(c), nil) // a Comment is not a Node
+ // p.printf("\n")
+ // }
+ }
+
+ for i, n := 0, typ.NumField(); i < n; i++ {
+ // Exclude non-exported fields because their
+ // values cannot be accessed via reflection.
+ if name := typ.Field(i).Name; isExported(name) {
+ if first {
+ p.printf("\n")
+ first = false
+ }
+ p.printf("%s: ", name)
+ p.dump(x.Field(i), nil)
+ p.printf("\n")
+ }
+ }
+
+ p.indent--
+ p.printf("}")
+
+ default:
+ switch x := x.Interface().(type) {
+ case string:
+ // print strings in quotes
+ p.printf("%q", x)
+ default:
+ p.printf("%v", x)
+ }
+ }
+}
+
+func isExported(name string) bool {
+ ch, _ := utf8.DecodeRuneInString(name)
+ return unicode.IsUpper(ch)
+}
diff --git a/src/cmd/compile/internal/syntax/dumper_test.go b/src/cmd/compile/internal/syntax/dumper_test.go
new file mode 100644
index 0000000..2b20cbd
--- /dev/null
+++ b/src/cmd/compile/internal/syntax/dumper_test.go
@@ -0,0 +1,22 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package syntax
+
+import (
+ "os"
+ "testing"
+)
+
+func TestDump(t *testing.T) {
+ if testing.Short() {
+ t.Skip("skipping test in short mode")
+ }
+
+ ast, err := ParseFile(*src, nil, nil, 0)
+ if err != nil {
+ t.Fatal(err)
+ }
+ Fdump(os.Stdout, ast)
+}
diff --git a/src/cmd/compile/internal/syntax/nodes.go b/src/cmd/compile/internal/syntax/nodes.go
new file mode 100644
index 0000000..fadba84
--- /dev/null
+++ b/src/cmd/compile/internal/syntax/nodes.go
@@ -0,0 +1,452 @@
+// Copyright 2016 The Go Authors. 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
+
+// ----------------------------------------------------------------------------
+// Nodes
+
+type Node interface {
+ Line() uint32
+ 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
+}
+
+func (n *node) init(p *parser) {
+ n.pos = uint32(p.pos)
+ n.line = uint32(p.line)
+}
+
+// ----------------------------------------------------------------------------
+// Files
+
+// package PkgName; DeclList[0], DeclList[1], ...
+type File struct {
+ PkgName *Name
+ DeclList []Decl
+ Lines int
+ node
+}
+
+// ----------------------------------------------------------------------------
+// Declarations
+
+type (
+ Decl interface {
+ Node
+ aDecl()
+ }
+
+ // Path
+ // LocalPkgName Path
+ ImportDecl struct {
+ LocalPkgName *Name // including "."; nil means no rename present
+ Path *BasicLit
+ Group *Group // nil means not part of a group
+ decl
+ }
+
+ // NameList
+ // NameList = Values
+ // NameList Type = Values
+ ConstDecl struct {
+ NameList []*Name
+ Type Expr // nil means no type
+ Values Expr // nil means no values
+ Group *Group // nil means not part of a group
+ decl
+ }
+
+ // Name Type
+ TypeDecl struct {
+ Name *Name
+ Type Expr
+ Group *Group // nil means not part of a group
+ Pragma Pragma
+ decl
+ }
+
+ // NameList Type
+ // NameList Type = Values
+ // NameList = Values
+ VarDecl struct {
+ NameList []*Name
+ Type Expr // nil means no type
+ Values Expr // nil means no values
+ Group *Group // nil means not part of a group
+ decl
+ }
+
+ // func Name Type { Body }
+ // func Name 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.
+ decl
+ }
+)
+
+type decl struct{ node }
+
+func (*decl) aDecl() {}
+
+// All declarations belonging to the same group point to the same Group node.
+type Group struct {
+ dummy int // not empty so we are guaranteed different Group instances
+}
+
+// ----------------------------------------------------------------------------
+// Expressions
+
+type (
+ Expr interface {
+ Node
+ aExpr()
+ }
+
+ // Value
+ Name struct {
+ Value string
+ expr
+ }
+
+ // Value
+ BasicLit struct {
+ Value string
+ Kind LitKind
+ expr
+ }
+
+ // Type { ElemList[0], ElemList[1], ... }
+ CompositeLit struct {
+ Type Expr // nil means no literal type
+ ElemList []Expr
+ NKeys int // number of elements with keys
+ EndLine uint32 // TODO(mdempsky): Cleaner solution.
+ expr
+ }
+
+ // Key: Value
+ KeyValueExpr struct {
+ Key, Value Expr
+ expr
+ }
+
+ // func Type { Body }
+ FuncLit struct {
+ Type *FuncType
+ Body []Stmt
+ EndLine uint32 // TODO(mdempsky): Cleaner solution.
+ expr
+ }
+
+ // (X)
+ ParenExpr struct {
+ X Expr
+ expr
+ }
+
+ // X.Sel
+ SelectorExpr struct {
+ X Expr
+ Sel *Name
+ expr
+ }
+
+ // X[Index]
+ IndexExpr struct {
+ X Expr
+ Index Expr
+ expr
+ }
+
+ // X[Index[0] : Index[1] : Index[2]]
+ SliceExpr struct {
+ X Expr
+ Index [3]Expr
+ // Full indicates whether this is a simple or full slice expression.
+ // In a valid AST, this is equivalent to Index[2] != nil.
+ // TODO(mdempsky): This is only needed to report the "3-index
+ // slice of string" error when Index[2] is missing.
+ Full bool
+ expr
+ }
+
+ // X.(Type)
+ AssertExpr struct {
+ X Expr
+ // TODO(gri) consider using Name{"..."} instead of nil (permits attaching of comments)
+ Type Expr
+ expr
+ }
+
+ Operation struct {
+ Op Operator
+ X, Y Expr // Y == nil means unary expression
+ expr
+ }
+
+ // Fun(ArgList[0], ArgList[1], ...)
+ CallExpr struct {
+ Fun Expr
+ ArgList []Expr
+ HasDots bool // last argument is followed by ...
+ expr
+ }
+
+ // ElemList[0], ElemList[1], ...
+ ListExpr struct {
+ ElemList []Expr
+ expr
+ }
+
+ // [Len]Elem
+ ArrayType struct {
+ // TODO(gri) consider using Name{"..."} instead of nil (permits attaching of comments)
+ Len Expr // nil means Len is ...
+ Elem Expr
+ expr
+ }
+
+ // []Elem
+ SliceType struct {
+ Elem Expr
+ expr
+ }
+
+ // ...Elem
+ DotsType struct {
+ Elem Expr
+ expr
+ }
+
+ // struct { FieldList[0] TagList[0]; FieldList[1] TagList[1]; ... }
+ StructType struct {
+ FieldList []*Field
+ TagList []*BasicLit // i >= len(TagList) || TagList[i] == nil means no tag for field i
+ expr
+ }
+
+ // Name Type
+ // Type
+ Field struct {
+ Name *Name // nil means anonymous field/parameter (structs/parameters), or embedded interface (interfaces)
+ Type Expr // field names declared in a list share the same Type (identical pointers)
+ node
+ }
+
+ // interface { MethodList[0]; MethodList[1]; ... }
+ InterfaceType struct {
+ MethodList []*Field
+ expr
+ }
+
+ FuncType struct {
+ ParamList []*Field
+ ResultList []*Field
+ expr
+ }
+
+ // map[Key]Value
+ MapType struct {
+ Key Expr
+ Value Expr
+ expr
+ }
+
+ // chan Elem
+ // <-chan Elem
+ // chan<- Elem
+ ChanType struct {
+ Dir ChanDir // 0 means no direction
+ Elem Expr
+ expr
+ }
+)
+
+type expr struct{ node }
+
+func (*expr) aExpr() {}
+
+type ChanDir uint
+
+const (
+ _ ChanDir = iota
+ SendOnly
+ RecvOnly
+)
+
+// ----------------------------------------------------------------------------
+// Statements
+
+type (
+ Stmt interface {
+ Node
+ aStmt()
+ }
+
+ SimpleStmt interface {
+ Stmt
+ aSimpleStmt()
+ }
+
+ EmptyStmt struct {
+ simpleStmt
+ }
+
+ LabeledStmt struct {
+ Label *Name
+ Stmt Stmt
+ stmt
+ }
+
+ BlockStmt struct {
+ Body []Stmt
+ stmt
+ }
+
+ ExprStmt struct {
+ X Expr
+ simpleStmt
+ }
+
+ SendStmt struct {
+ Chan, Value Expr // Chan <- Value
+ simpleStmt
+ }
+
+ DeclStmt struct {
+ DeclList []Decl
+ stmt
+ }
+
+ AssignStmt struct {
+ Op Operator // 0 means no operation
+ Lhs, Rhs Expr // Rhs == ImplicitOne means Lhs++ (Op == Add) or Lhs-- (Op == Sub)
+ simpleStmt
+ }
+
+ BranchStmt struct {
+ Tok token // Break, Continue, Fallthrough, or Goto
+ Label *Name
+ stmt
+ }
+
+ CallStmt struct {
+ Tok token // Go or Defer
+ Call *CallExpr
+ stmt
+ }
+
+ ReturnStmt struct {
+ Results Expr // nil means no explicit return values
+ stmt
+ }
+
+ IfStmt struct {
+ Init SimpleStmt
+ Cond Expr
+ Then []Stmt
+ Else Stmt // either *IfStmt or *BlockStmt
+ stmt
+ }
+
+ ForStmt struct {
+ Init SimpleStmt // incl. *RangeClause
+ Cond Expr
+ Post SimpleStmt
+ Body []Stmt
+ stmt
+ }
+
+ SwitchStmt struct {
+ Init SimpleStmt
+ Tag Expr
+ Body []*CaseClause
+ stmt
+ }
+
+ SelectStmt struct {
+ Body []*CommClause
+ stmt
+ }
+)
+
+type (
+ RangeClause struct {
+ Lhs Expr // nil means no Lhs = or Lhs :=
+ Def bool // means :=
+ X Expr // range X
+ simpleStmt
+ }
+
+ TypeSwitchGuard struct {
+ // TODO(gri) consider using Name{"..."} instead of nil (permits attaching of comments)
+ Lhs *Name // nil means no Lhs :=
+ X Expr // X.(type)
+ expr
+ }
+
+ CaseClause struct {
+ Cases Expr // nil means default clause
+ Body []Stmt
+ node
+ }
+
+ CommClause struct {
+ Comm SimpleStmt // send or receive stmt; nil means default clause
+ Body []Stmt
+ node
+ }
+)
+
+type stmt struct{ node }
+
+func (stmt) aStmt() {}
+
+type simpleStmt struct {
+ stmt
+}
+
+func (simpleStmt) aSimpleStmt() {}
+
+// ----------------------------------------------------------------------------
+// Comments
+
+// TODO(gri) Consider renaming to CommentPos, CommentPlacement, etc.
+// Kind = Above doesn't make much sense.
+type CommentKind uint
+
+const (
+ Above CommentKind = iota
+ Below
+ Left
+ Right
+)
+
+type Comment struct {
+ Kind CommentKind
+ Text string
+ Next *Comment
+}
diff --git a/src/cmd/compile/internal/syntax/parser.go b/src/cmd/compile/internal/syntax/parser.go
new file mode 100644
index 0000000..a2e307f
--- /dev/null
+++ b/src/cmd/compile/internal/syntax/parser.go
@@ -0,0 +1,2143 @@
+// Copyright 2016 The Go Authors. 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"
+ "io"
+ "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 {
+ scanner
+
+ fnest int // function nesting level (for error handling)
+ xnest int // expression nesting level (for complit ambiguity resolution)
+ indent []byte // tracing support
+}
+
+type parserError string // for error recovery if no error handler was installed
+
+func (p *parser) init(src io.Reader, errh ErrorHandler, pragh PragmaHandler) {
+ p.scanner.init(src, errh, pragh)
+
+ p.fnest = 0
+ p.xnest = 0
+ p.indent = nil
+}
+
+func (p *parser) got(tok token) bool {
+ if p.tok == tok {
+ p.next()
+ return true
+ }
+ return false
+}
+
+func (p *parser) want(tok token) {
+ if !p.got(tok) {
+ p.syntax_error("expecting " + tok.String())
+ p.advance()
+ }
+}
+
+// ----------------------------------------------------------------------------
+// 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)
+}
+
+// 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) {
+ if trace {
+ defer p.trace("syntax_error (" + msg + ")")()
+ }
+
+ if p.tok == _EOF && p.first != nil {
+ return // avoid meaningless follow-up errors
+ }
+
+ // add punctuation etc. as needed to msg
+ switch {
+ case msg == "":
+ // nothing to do
+ case strings.HasPrefix(msg, "in"), strings.HasPrefix(msg, "at"), strings.HasPrefix(msg, "after"):
+ msg = " " + msg
+ case strings.HasPrefix(msg, "expecting"):
+ msg = ", " + msg
+ default:
+ // plain error - we don't care about current token
+ p.error_at(pos, line, "syntax error: "+msg)
+ return
+ }
+
+ // determine token string
+ var tok string
+ switch p.tok {
+ case _Name:
+ tok = p.lit
+ case _Literal:
+ tok = "literal " + p.lit
+ case _Operator:
+ tok = p.op.String()
+ case _AssignOp:
+ tok = p.op.String() + "="
+ case _IncOp:
+ tok = p.op.String()
+ tok += tok
+ default:
+ tok = tokstring(p.tok)
+ }
+
+ p.error_at(pos, line, "syntax error: unexpected "+tok+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.
+const stopset uint64 = 1<<_Break |
+ 1<<_Const |
+ 1<<_Continue |
+ 1<<_Defer |
+ 1<<_Fallthrough |
+ 1<<_For |
+ 1<<_Func |
+ 1<<_Go |
+ 1<<_Goto |
+ 1<<_If |
+ 1<<_Return |
+ 1<<_Select |
+ 1<<_Switch |
+ 1<<_Type |
+ 1<<_Var
+
+// Advance consumes tokens until it finds a token of the stopset or followlist.
+// The stopset is only considered if we are inside a function (p.fnest > 0).
+// The followlist is the list of valid tokens that can follow a production;
+// if it is empty, exactly one token is consumed to ensure progress.
+func (p *parser) advance(followlist ...token) {
+ if len(followlist) == 0 {
+ p.next()
+ return
+ }
+
+ // compute follow set
+ // TODO(gri) the args are constants - do as constant expressions?
+ var followset uint64 = 1 << _EOF // never skip over EOF
+ for _, tok := range followlist {
+ followset |= 1 << tok
+ }
+
+ for !(contains(followset, p.tok) || p.fnest > 0 && contains(stopset, p.tok)) {
+ p.next()
+ }
+}
+
+func tokstring(tok token) string {
+ switch tok {
+ case _EOF:
+ return "EOF"
+ case _Comma:
+ return "comma"
+ case _Semi:
+ return "semicolon or newline"
+ }
+ return tok.String()
+}
+
+// usage: defer p.trace(msg)()
+func (p *parser) trace(msg string) func() {
+ fmt.Printf("%5d: %s%s (\n", p.line, p.indent, msg)
+ const tab = ". "
+ p.indent = append(p.indent, tab...)
+ return func() {
+ p.indent = p.indent[:len(p.indent)-len(tab)]
+ if x := recover(); x != nil {
+ panic(x) // skip print_trace
+ }
+ fmt.Printf("%5d: %s)\n", p.line, p.indent)
+ }
+}
+
+// ----------------------------------------------------------------------------
+// Package files
+//
+// 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.
+
+// SourceFile = PackageClause ";" { ImportDecl ";" } { TopLevelDecl ";" } .
+func (p *parser) file() *File {
+ if trace {
+ defer p.trace("file")()
+ }
+
+ f := new(File)
+ f.init(p)
+
+ // PackageClause
+ if !p.got(_Package) {
+ p.syntax_error("package statement must be first")
+ return nil
+ }
+ f.PkgName = p.name()
+ p.want(_Semi)
+
+ // don't bother continuing if package clause has errors
+ if p.first != nil {
+ return nil
+ }
+
+ // { ImportDecl ";" }
+ for p.got(_Import) {
+ f.DeclList = p.appendGroup(f.DeclList, p.importDecl)
+ p.want(_Semi)
+ }
+
+ // { TopLevelDecl ";" }
+ for p.tok != _EOF {
+ switch p.tok {
+ case _Const:
+ p.next()
+ f.DeclList = p.appendGroup(f.DeclList, p.constDecl)
+
+ case _Type:
+ p.next()
+ f.DeclList = p.appendGroup(f.DeclList, p.typeDecl)
+
+ case _Var:
+ p.next()
+ f.DeclList = p.appendGroup(f.DeclList, p.varDecl)
+
+ case _Func:
+ p.next()
+ f.DeclList = append(f.DeclList, p.funcDecl())
+
+ default:
+ if p.tok == _Lbrace && len(f.DeclList) > 0 && emptyFuncDecl(f.DeclList[len(f.DeclList)-1]) {
+ // opening { of function declaration on next line
+ p.syntax_error("unexpected semicolon or newline before {")
+ } else {
+ p.syntax_error("non-declaration statement outside function body")
+ }
+ p.advance(_Const, _Type, _Var, _Func)
+ continue
+ }
+
+ // Reset p.pragma BEFORE advancing to the next token (consuming ';')
+ // since comments before may set pragmas for the next function decl.
+ p.pragma = 0
+
+ if p.tok != _EOF && !p.got(_Semi) {
+ p.syntax_error("after top level declaration")
+ p.advance(_Const, _Type, _Var, _Func)
+ }
+ }
+ // p.tok == _EOF
+
+ f.Lines = p.source.line
+
+ return f
+}
+
+func emptyFuncDecl(dcl Decl) bool {
+ f, ok := dcl.(*FuncDecl)
+ return ok && f.Body == nil
+}
+
+// ----------------------------------------------------------------------------
+// Declarations
+
+// appendGroup(f) = f | "(" { f ";" } ")" .
+func (p *parser) appendGroup(list []Decl, f func(*Group) Decl) []Decl {
+ if p.got(_Lparen) {
+ g := new(Group)
+ for p.tok != _EOF && p.tok != _Rparen {
+ list = append(list, f(g))
+ if !p.osemi(_Rparen) {
+ break
+ }
+ }
+ p.want(_Rparen)
+ return list
+ }
+
+ return append(list, f(nil))
+}
+
+func (p *parser) importDecl(group *Group) Decl {
+ if trace {
+ defer p.trace("importDecl")()
+ }
+
+ d := new(ImportDecl)
+ d.init(p)
+
+ switch p.tok {
+ case _Name:
+ d.LocalPkgName = p.name()
+ case _Dot:
+ n := new(Name)
+ n.init(p)
+ n.Value = "."
+ d.LocalPkgName = n
+ p.next()
+ }
+ if p.tok == _Literal && (gcCompat || p.kind == StringLit) {
+ d.Path = p.oliteral()
+ } else {
+ p.syntax_error("missing import path; require quoted string")
+ p.advance(_Semi, _Rparen)
+ }
+ d.Group = group
+
+ return d
+}
+
+// ConstSpec = IdentifierList [ [ Type ] "=" ExpressionList ] .
+func (p *parser) constDecl(group *Group) Decl {
+ if trace {
+ defer p.trace("constDecl")()
+ }
+
+ d := new(ConstDecl)
+ d.init(p)
+
+ d.NameList = p.nameList(p.name())
+ if p.tok != _EOF && p.tok != _Semi && p.tok != _Rparen {
+ d.Type = p.tryType()
+ if p.got(_Assign) {
+ d.Values = p.exprList()
+ }
+ }
+ d.Group = group
+
+ return d
+}
+
+// TypeSpec = identifier Type .
+func (p *parser) typeDecl(group *Group) Decl {
+ if trace {
+ defer p.trace("typeDecl")()
+ }
+
+ d := new(TypeDecl)
+ d.init(p)
+
+ d.Name = p.name()
+ d.Type = p.tryType()
+ if d.Type == nil {
+ p.syntax_error("in type declaration")
+ p.advance(_Semi, _Rparen)
+ }
+ d.Group = group
+ d.Pragma = p.pragma
+
+ return d
+}
+
+// VarSpec = IdentifierList ( Type [ "=" ExpressionList ] | "=" ExpressionList ) .
+func (p *parser) varDecl(group *Group) Decl {
+ if trace {
+ defer p.trace("varDecl")()
+ }
+
+ d := new(VarDecl)
+ d.init(p)
+
+ d.NameList = p.nameList(p.name())
+ if p.got(_Assign) {
+ d.Values = p.exprList()
+ } else {
+ d.Type = p.type_()
+ if p.got(_Assign) {
+ d.Values = p.exprList()
+ }
+ }
+ d.Group = group
+ if gcCompat {
+ d.init(p)
+ }
+
+ return d
+}
+
+// FunctionDecl = "func" FunctionName ( Function | Signature ) .
+// FunctionName = identifier .
+// Function = Signature FunctionBody .
+// MethodDecl = "func" Receiver MethodName ( Function | Signature ) .
+// Receiver = Parameters .
+func (p *parser) funcDecl() *FuncDecl {
+ if trace {
+ defer p.trace("funcDecl")()
+ }
+
+ f := new(FuncDecl)
+ f.init(p)
+
+ 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
+ }
+ }
+
+ if p.tok != _Name {
+ p.syntax_error("expecting name or (")
+ p.advance(_Lbrace, _Semi)
+ return nil
+ }
+
+ // TODO(gri) check for regular functions only
+ // if name.Sym.Name == "init" {
+ // name = renameinit()
+ // if params != nil || result != nil {
+ // p.error("func init must have no arguments and no return values")
+ // }
+ // }
+
+ // if localpkg.Name == "main" && name.Name == "main" {
+ // if params != nil || result != nil {
+ // p.error("func main must have no arguments and no return values")
+ // }
+ // }
+
+ f.Name = p.name()
+ f.Type = p.funcType()
+ if gcCompat {
+ f.node = f.Type.node
+ }
+ 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
+}
+
+// ----------------------------------------------------------------------------
+// Expressions
+
+func (p *parser) expr() Expr {
+ if trace {
+ defer p.trace("expr")()
+ }
+
+ return p.binaryExpr(0)
+}
+
+// Expression = UnaryExpr | Expression binary_op Expression .
+func (p *parser) binaryExpr(prec int) Expr {
+ // don't trace binaryExpr - only leads to overly nested trace output
+
+ x := p.unaryExpr()
+ for (p.tok == _Operator || p.tok == _Star) && p.prec > prec {
+ t := new(Operation)
+ t.init(p)
+ 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
+}
+
+// UnaryExpr = PrimaryExpr | unary_op UnaryExpr .
+func (p *parser) unaryExpr() Expr {
+ if trace {
+ defer p.trace("unaryExpr")()
+ }
+
+ switch p.tok {
+ case _Operator, _Star:
+ switch p.op {
+ case Mul, Add, Sub, Not, Xor:
+ x := new(Operation)
+ x.init(p)
+ 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.Op = And
+ // unaryExpr may have returned a parenthesized composite literal
+ // (see comment in operand) - remove parentheses if any
+ x.X = unparen(p.unaryExpr())
+ return x
+ }
+
+ case _Arrow:
+ // receive op (<-x) or receive-only channel (<-chan E)
+ p.next()
+
+ // If the next token is _Chan we still don't know if it is
+ // a channel (<-chan int) or a receive op (<-chan int(ch)).
+ // We only know once we have found the end of the unaryExpr.
+
+ x := p.unaryExpr()
+
+ // There are two cases:
+ //
+ // <-chan... => <-x is a channel type
+ // <-x => <-x is a receive operation
+ //
+ // In the first case, <- must be re-associated with
+ // the channel type parsed already:
+ //
+ // <-(chan E) => (<-chan E)
+ // <-(chan<-E) => (<-chan (<-E))
+
+ if _, ok := x.(*ChanType); ok {
+ // x is a channel type => re-associate <-
+ dir := SendOnly
+ t := x
+ for dir == SendOnly {
+ c, ok := t.(*ChanType)
+ if !ok {
+ break
+ }
+ dir = c.Dir
+ if dir == RecvOnly {
+ // t is type <-chan E but <-<-chan E is not permitted
+ // (report same error as for "type _ <-<-chan E")
+ p.syntax_error("unexpected <-, expecting chan")
+ // already progressed, no need to advance
+ }
+ c.Dir = RecvOnly
+ t = c.Elem
+ }
+ if dir == SendOnly {
+ // channel dir is <- but channel element E is not a channel
+ // (report same error as for "type _ <-chan<-E")
+ p.syntax_error(fmt.Sprintf("unexpected %s, expecting chan", String(t)))
+ // already progressed, no need to advance
+ }
+ return x
+ }
+
+ // x is not a channel type => we have a receive op
+ return &Operation{Op: Recv, X: x}
+ }
+
+ // TODO(mdempsky): We need parens here so we can report an
+ // error for "(x) := true". It should be possible to detect
+ // and reject that more efficiently though.
+ return p.pexpr(true)
+}
+
+// callStmt parses call-like statements that can be preceded by 'defer' and 'go'.
+func (p *parser) callStmt() *CallStmt {
+ if trace {
+ defer p.trace("callStmt")()
+ }
+
+ s := new(CallStmt)
+ s.init(p)
+ s.Tok = p.tok
+ 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:
+ p.error(fmt.Sprintf("expression in %s must not be parenthesized", s.Tok))
+ // already progressed, no need to advance
+ default:
+ p.error(fmt.Sprintf("expression in %s must be function call", s.Tok))
+ // already progressed, no need to advance
+ }
+
+ return s // TODO(gri) should we return nil in case of failure?
+}
+
+// Operand = Literal | OperandName | MethodExpr | "(" Expression ")" .
+// Literal = BasicLit | CompositeLit | FunctionLit .
+// BasicLit = int_lit | float_lit | imaginary_lit | rune_lit | string_lit .
+// OperandName = identifier | QualifiedIdent.
+func (p *parser) operand(keep_parens bool) Expr {
+ if trace {
+ defer p.trace("operand " + p.tok.String())()
+ }
+
+ switch p.tok {
+ case _Name:
+ return p.name()
+
+ case _Literal:
+ return p.oliteral()
+
+ case _Lparen:
+ p.next()
+ p.xnest++
+ x := p.expr() // expr_or_type
+ p.xnest--
+ p.want(_Rparen)
+
+ // Optimization: Record presence of ()'s only where needed
+ // for error reporting. Don't bother in other cases; it is
+ // just a waste of memory and time.
+
+ // Parentheses are not permitted on lhs of := .
+ // switch x.Op {
+ // case ONAME, ONONAME, OPACK, OTYPE, OLITERAL, OTYPESW:
+ // keep_parens = true
+ // }
+
+ // Parentheses are not permitted around T in a composite
+ // literal T{}. If the next token is a {, assume x is a
+ // composite literal type T (it may not be, { could be
+ // the opening brace of a block, but we don't know yet).
+ if p.tok == _Lbrace {
+ keep_parens = true
+ }
+
+ // Parentheses are also not permitted around the expression
+ // in a go/defer statement. In that case, operand is called
+ // with keep_parens set.
+ if keep_parens {
+ x = &ParenExpr{X: x}
+ }
+ return x
+
+ case _Func:
+ p.next()
+ t := p.funcType()
+ if p.tok == _Lbrace {
+ p.fnest++
+ p.xnest++
+ f := new(FuncLit)
+ f.init(p)
+ f.Type = t
+ f.Body = p.funcBody()
+ f.EndLine = uint32(p.line)
+ p.xnest--
+ p.fnest--
+ return f
+ }
+ return t
+
+ 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:
+ p.syntax_error("expecting expression")
+ p.advance()
+ return nil
+ }
+
+ // Syntactically, composite literals are operands. Because a complit
+ // type may be a qualified identifier which is handled by pexpr
+ // (together with selector expressions), complits are parsed there
+ // as well (operand is only called from pexpr).
+}
+
+// PrimaryExpr =
+// Operand |
+// Conversion |
+// PrimaryExpr Selector |
+// PrimaryExpr Index |
+// PrimaryExpr Slice |
+// PrimaryExpr TypeAssertion |
+// PrimaryExpr Arguments .
+//
+// Selector = "." identifier .
+// Index = "[" Expression "]" .
+// Slice = "[" ( [ Expression ] ":" [ Expression ] ) |
+// ( [ Expression ] ":" Expression ":" Expression )
+// "]" .
+// TypeAssertion = "." "(" Type ")" .
+// Arguments = "(" [ ( ExpressionList | Type [ "," ExpressionList ] ) [ "..." ] [ "," ] ] ")" .
+func (p *parser) pexpr(keep_parens bool) Expr {
+ if trace {
+ defer p.trace("pexpr")()
+ }
+
+ x := p.operand(keep_parens)
+
+loop:
+ for {
+ switch p.tok {
+ case _Dot:
+ p.next()
+ switch p.tok {
+ case _Name:
+ // pexpr '.' sym
+ t := new(SelectorExpr)
+ t.init(p)
+ t.X = x
+ t.Sel = p.name()
+ x = t
+
+ case _Lparen:
+ p.next()
+ if p.got(_Type) {
+ t := new(TypeSwitchGuard)
+ t.init(p)
+ t.X = x
+ x = t
+ } else {
+ t := new(AssertExpr)
+ t.init(p)
+ t.X = x
+ t.Type = p.expr()
+ x = t
+ }
+ p.want(_Rparen)
+
+ default:
+ p.syntax_error("expecting name or (")
+ p.advance(_Semi, _Rparen)
+ }
+ if gcCompat {
+ x.init(p)
+ }
+
+ case _Lbrack:
+ p.next()
+ p.xnest++
+
+ var i Expr
+ if p.tok != _Colon {
+ i = p.expr()
+ if p.got(_Rbrack) {
+ // x[i]
+ t := new(IndexExpr)
+ t.init(p)
+ t.X = x
+ t.Index = i
+ x = t
+ p.xnest--
+ break
+ }
+ }
+
+ // x[i:...
+ t := new(SliceExpr)
+ t.init(p)
+ t.X = x
+ t.Index[0] = i
+ p.want(_Colon)
+ if p.tok != _Colon && p.tok != _Rbrack {
+ // x[i:j...
+ t.Index[1] = p.expr()
+ }
+ if p.got(_Colon) {
+ t.Full = true
+ // x[i:j:...]
+ if t.Index[1] == nil {
+ p.error("middle index required in 3-index slice")
+ }
+ if p.tok != _Rbrack {
+ // x[i:j:k...
+ t.Index[2] = p.expr()
+ } else {
+ p.error("final index required in 3-index slice")
+ }
+ }
+ p.want(_Rbrack)
+
+ x = t
+ p.xnest--
+
+ case _Lparen:
+ x = p.call(x)
+
+ case _Lbrace:
+ // 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
+ complit_ok := false
+ switch t.(type) {
+ case *Name, *SelectorExpr:
+ if p.xnest >= 0 {
+ // x is considered a comptype
+ complit_ok = true
+ }
+ case *ArrayType, *SliceType, *StructType, *MapType:
+ // x is a comptype
+ complit_ok = true
+ }
+ if !complit_ok {
+ break loop
+ }
+ if t != x {
+ p.syntax_error("cannot parenthesize type in composite literal")
+ // already progressed, no need to advance
+ }
+ n := p.complitexpr()
+ n.Type = x
+ x = n
+
+ default:
+ break loop
+ }
+ }
+
+ return x
+}
+
+// Element = Expression | LiteralValue .
+func (p *parser) bare_complitexpr() Expr {
+ if trace {
+ defer p.trace("bare_complitexpr")()
+ }
+
+ if p.tok == _Lbrace {
+ // '{' start_complit braced_keyval_list '}'
+ return p.complitexpr()
+ }
+
+ return p.expr()
+}
+
+// LiteralValue = "{" [ ElementList [ "," ] ] "}" .
+func (p *parser) complitexpr() *CompositeLit {
+ if trace {
+ defer p.trace("complitexpr")()
+ }
+
+ x := new(CompositeLit)
+ x.init(p)
+
+ p.want(_Lbrace)
+ p.xnest++
+
+ for p.tok != _EOF && p.tok != _Rbrace {
+ // value
+ e := p.bare_complitexpr()
+ if p.got(_Colon) {
+ // key ':' value
+ l := new(KeyValueExpr)
+ l.init(p)
+ l.Key = e
+ l.Value = p.bare_complitexpr()
+ if gcCompat {
+ l.init(p)
+ }
+ e = l
+ x.NKeys++
+ }
+ x.ElemList = append(x.ElemList, e)
+ if !p.ocomma(_Rbrace) {
+ break
+ }
+ }
+
+ x.EndLine = uint32(p.line)
+ p.xnest--
+ p.want(_Rbrace)
+
+ return x
+}
+
+// ----------------------------------------------------------------------------
+// Types
+
+func (p *parser) type_() Expr {
+ if trace {
+ defer p.trace("type_")()
+ }
+
+ if typ := p.tryType(); typ != nil {
+ return typ
+ }
+
+ p.syntax_error("")
+ p.advance()
+ return nil
+}
+
+func indirect(typ Expr) Expr {
+ return &Operation{Op: Mul, X: typ}
+}
+
+// tryType 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 {
+ if trace {
+ defer p.trace("tryType")()
+ }
+
+ switch p.tok {
+ case _Star:
+ // ptrtype
+ p.next()
+ return indirect(p.type_())
+
+ case _Arrow:
+ // recvchantype
+ p.next()
+ p.want(_Chan)
+ t := new(ChanType)
+ t.init(p)
+ t.Dir = RecvOnly
+ t.Elem = p.chanElem()
+ return t
+
+ case _Func:
+ // fntype
+ p.next()
+ return p.funcType()
+
+ case _Lbrack:
+ // '[' oexpr ']' ntype
+ // '[' _DotDotDot ']' ntype
+ p.next()
+ p.xnest++
+ if p.got(_Rbrack) {
+ // []T
+ p.xnest--
+ t := new(SliceType)
+ t.init(p)
+ t.Elem = p.type_()
+ return t
+ }
+
+ // [n]T
+ t := new(ArrayType)
+ t.init(p)
+ if !p.got(_DotDotDot) {
+ t.Len = p.expr()
+ }
+ p.want(_Rbrack)
+ p.xnest--
+ t.Elem = p.type_()
+ return t
+
+ case _Chan:
+ // _Chan non_recvchantype
+ // _Chan _Comm ntype
+ p.next()
+ t := new(ChanType)
+ t.init(p)
+ if p.got(_Arrow) {
+ t.Dir = SendOnly
+ }
+ t.Elem = p.chanElem()
+ return t
+
+ case _Map:
+ // _Map '[' ntype ']' ntype
+ p.next()
+ p.want(_Lbrack)
+ t := new(MapType)
+ t.init(p)
+ t.Key = p.type_()
+ p.want(_Rbrack)
+ t.Value = p.type_()
+ return t
+
+ case _Struct:
+ return p.structType()
+
+ case _Interface:
+ return p.interfaceType()
+
+ case _Name:
+ return p.dotname(p.name())
+
+ case _Lparen:
+ p.next()
+ t := p.type_()
+ p.want(_Rparen)
+ return t
+ }
+
+ return nil
+}
+
+func (p *parser) funcType() *FuncType {
+ if trace {
+ defer p.trace("funcType")()
+ }
+
+ typ := new(FuncType)
+ typ.init(p)
+ typ.ParamList = p.paramList()
+ typ.ResultList = p.funcResult()
+ if gcCompat {
+ typ.init(p)
+ }
+ return typ
+}
+
+func (p *parser) chanElem() Expr {
+ if trace {
+ defer p.trace("chanElem")()
+ }
+
+ if typ := p.tryType(); typ != nil {
+ return typ
+ }
+
+ p.syntax_error("missing channel element type")
+ // assume element type is simply absent - don't advance
+ return nil
+}
+
+func (p *parser) dotname(name *Name) Expr {
+ if trace {
+ defer p.trace("dotname")()
+ }
+
+ if p.got(_Dot) {
+ s := new(SelectorExpr)
+ s.init(p)
+ s.X = name
+ s.Sel = p.name()
+ return s
+ }
+ return name
+}
+
+// StructType = "struct" "{" { FieldDecl ";" } "}" .
+func (p *parser) structType() *StructType {
+ if trace {
+ defer p.trace("structType")()
+ }
+
+ typ := new(StructType)
+ typ.init(p)
+
+ p.want(_Struct)
+ p.want(_Lbrace)
+ for p.tok != _EOF && p.tok != _Rbrace {
+ p.fieldDecl(typ)
+ if !p.osemi(_Rbrace) {
+ break
+ }
+ }
+ if gcCompat {
+ typ.init(p)
+ }
+ p.want(_Rbrace)
+
+ return typ
+}
+
+// InterfaceType = "interface" "{" { MethodSpec ";" } "}" .
+func (p *parser) interfaceType() *InterfaceType {
+ if trace {
+ defer p.trace("interfaceType")()
+ }
+
+ typ := new(InterfaceType)
+ typ.init(p)
+
+ p.want(_Interface)
+ p.want(_Lbrace)
+ for p.tok != _EOF && p.tok != _Rbrace {
+ if m := p.methodDecl(); m != nil {
+ typ.MethodList = append(typ.MethodList, m)
+ }
+ if !p.osemi(_Rbrace) {
+ break
+ }
+ }
+ if gcCompat {
+ typ.init(p)
+ }
+ p.want(_Rbrace)
+
+ return typ
+}
+
+// FunctionBody = Block .
+func (p *parser) funcBody() []Stmt {
+ if trace {
+ 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
+ }
+
+ return nil
+}
+
+// Result = Parameters | Type .
+func (p *parser) funcResult() []*Field {
+ if trace {
+ defer p.trace("funcResult")()
+ }
+
+ if p.tok == _Lparen {
+ return p.paramList()
+ }
+
+ if result := p.tryType(); result != nil {
+ f := new(Field)
+ f.init(p)
+ f.Type = result
+ return []*Field{f}
+ }
+
+ return nil
+}
+
+func (p *parser) addField(styp *StructType, 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)
+ }
+ styp.TagList = append(styp.TagList, tag)
+ }
+
+ f := new(Field)
+ f.init(p)
+ 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")
+ }
+}
+
+// FieldDecl = (IdentifierList Type | AnonymousField) [ Tag ] .
+// AnonymousField = [ "*" ] TypeName .
+// Tag = string_lit .
+func (p *parser) fieldDecl(styp *StructType) {
+ if trace {
+ defer p.trace("fieldDecl")()
+ }
+
+ var name *Name
+ switch p.tok {
+ case _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)
+ return
+ }
+
+ // new_name_list ntype oliteral
+ names := p.nameList(name)
+ typ := p.type_()
+ tag := p.oliteral()
+
+ for _, name := range names {
+ p.addField(styp, name, typ, tag)
+ }
+
+ case _Lparen:
+ p.next()
+ if p.tok == _Star {
+ // '(' '*' embed ')' oliteral
+ p.next()
+ typ := indirect(p.qualifiedName(nil))
+ p.want(_Rparen)
+ tag := p.oliteral()
+ p.addField(styp, nil, typ, tag)
+ p.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")
+ }
+
+ case _Star:
+ p.next()
+ if p.got(_Lparen) {
+ // '*' '(' embed ')' oliteral
+ typ := indirect(p.qualifiedName(nil))
+ p.want(_Rparen)
+ tag := p.oliteral()
+ p.addField(styp, nil, typ, tag)
+ p.error("cannot parenthesize embedded type")
+
+ } else {
+ // '*' embed oliteral
+ typ := indirect(p.qualifiedName(nil))
+ tag := p.oliteral()
+ p.addField(styp, nil, typ, tag)
+ }
+
+ default:
+ p.syntax_error("expecting field name or embedded type")
+ p.advance(_Semi, _Rbrace)
+ }
+}
+
+func (p *parser) oliteral() *BasicLit {
+ if p.tok == _Literal {
+ b := new(BasicLit)
+ b.init(p)
+ b.Value = p.lit
+ b.Kind = p.kind
+ p.next()
+ return b
+ }
+ return nil
+}
+
+// MethodSpec = MethodName Signature | InterfaceTypeName .
+// MethodName = identifier .
+// InterfaceTypeName = TypeName .
+func (p *parser) methodDecl() *Field {
+ if trace {
+ defer p.trace("methodDecl")()
+ }
+
+ switch p.tok {
+ case _Name:
+ name := p.name()
+
+ // accept potential name list but complain
+ hasNameList := false
+ for p.got(_Comma) {
+ p.name()
+ hasNameList = true
+ }
+ if hasNameList {
+ p.syntax_error("name list not allowed in interface type")
+ // already progressed, no need to advance
+ }
+
+ f := new(Field)
+ f.init(p)
+ if p.tok != _Lparen {
+ // packname
+ f.Type = p.qualifiedName(name)
+ return f
+ }
+
+ f.Name = name
+ f.Type = p.funcType()
+ return f
+
+ case _Lparen:
+ p.next()
+ f := new(Field)
+ f.init(p)
+ f.Type = p.qualifiedName(nil)
+ p.want(_Rparen)
+ p.error("cannot parenthesize embedded type")
+ return f
+
+ default:
+ p.syntax_error("")
+ p.advance(_Semi, _Rbrace)
+ return nil
+ }
+}
+
+// ParameterDecl = [ IdentifierList ] [ "..." ] Type .
+func (p *parser) paramDecl() *Field {
+ if trace {
+ defer p.trace("paramDecl")()
+ }
+
+ f := new(Field)
+ f.init(p)
+
+ switch p.tok {
+ case _Name:
+ f.Name = p.name()
+ switch p.tok {
+ case _Name, _Star, _Arrow, _Func, _Lbrack, _Chan, _Map, _Struct, _Interface, _Lparen:
+ // sym name_or_type
+ f.Type = p.type_()
+
+ case _DotDotDot:
+ // sym dotdotdot
+ f.Type = p.dotsType()
+
+ case _Dot:
+ // name_or_type
+ // from dotname
+ f.Type = p.dotname(f.Name)
+ f.Name = nil
+ }
+
+ case _Arrow, _Star, _Func, _Lbrack, _Chan, _Map, _Struct, _Interface, _Lparen:
+ // name_or_type
+ f.Type = p.type_()
+
+ case _DotDotDot:
+ // dotdotdot
+ f.Type = p.dotsType()
+
+ default:
+ p.syntax_error("expecting )")
+ p.advance(_Comma, _Rparen)
+ return nil
+ }
+
+ return f
+}
+
+// ...Type
+func (p *parser) dotsType() *DotsType {
+ if trace {
+ defer p.trace("dotsType")()
+ }
+
+ t := new(DotsType)
+ t.init(p)
+
+ p.want(_DotDotDot)
+ t.Elem = p.tryType()
+ if t.Elem == nil {
+ p.error("final argument in variadic function missing type")
+ }
+
+ return t
+}
+
+// Parameters = "(" [ ParameterList [ "," ] ] ")" .
+// ParameterList = ParameterDecl { "," ParameterDecl } .
+func (p *parser) paramList() (list []*Field) {
+ if trace {
+ defer p.trace("paramList")()
+ }
+
+ 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 debug && par.Name == nil && par.Type == nil {
+ panic("parameter without name or type")
+ }
+ if par.Name != nil && par.Type != nil {
+ named++
+ }
+ list = append(list, par)
+ }
+ if !p.ocomma(_Rparen) {
+ break
+ }
+ }
+
+ // distribute parameter types
+ if named == 0 {
+ // all unnamed => found names are named types
+ for _, par := range list {
+ if typ := par.Name; typ != nil {
+ par.Type = typ
+ par.Name = nil
+ }
+ }
+ } else if named != len(list) {
+ // some named => all must be named
+ 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
+ }
+ } else {
+ par.Type = typ
+ }
+ if typ == nil {
+ p.syntax_error("mixed named and unnamed function parameters")
+ break
+ }
+ }
+ }
+
+ p.want(_Rparen)
+ return
+}
+
+// ----------------------------------------------------------------------------
+// Statements
+
+// We represent x++, x-- as assignments x += ImplicitOne, x -= ImplicitOne.
+// ImplicitOne should not be used elsewhere.
+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) {
+ // _Range expr
+ if debug && lhs != nil {
+ panic("invalid call of simpleStmt")
+ }
+ return p.rangeClause(nil, false)
+ }
+
+ if lhs == nil {
+ lhs = p.exprList()
+ }
+
+ if _, ok := lhs.(*ListExpr); !ok && p.tok != _Assign && p.tok != _Define {
+ // expr
+ switch p.tok {
+ case _AssignOp:
+ // lhs op= rhs
+ op := p.op
+ p.next()
+ return p.newAssignStmt(op, lhs, p.expr())
+
+ case _IncOp:
+ // lhs++ or lhs--
+ op := p.op
+ p.next()
+ return p.newAssignStmt(op, lhs, ImplicitOne)
+
+ case _Arrow:
+ // lhs <- rhs
+ p.next()
+ s := new(SendStmt)
+ s.init(p)
+ s.Chan = lhs
+ s.Value = p.expr()
+ if gcCompat {
+ s.init(p)
+ }
+ return s
+
+ default:
+ // expr
+ return &ExprStmt{X: lhs}
+ }
+ }
+
+ // expr_list
+ switch p.tok {
+ case _Assign:
+ p.next()
+
+ if rangeOk && p.got(_Range) {
+ // expr_list '=' _Range expr
+ return p.rangeClause(lhs, false)
+ }
+
+ // expr_list '=' expr_list
+ return p.newAssignStmt(0, lhs, p.exprList())
+
+ case _Define:
+ var n node
+ n.init(p)
+ p.next()
+
+ if rangeOk && p.got(_Range) {
+ // expr_list ':=' range expr
+ return p.rangeClause(lhs, true)
+ }
+
+ // expr_list ':=' expr_list
+ rhs := p.exprList()
+
+ if x, ok := rhs.(*TypeSwitchGuard); ok {
+ switch lhs := lhs.(type) {
+ case *Name:
+ x.Lhs = lhs
+ case *ListExpr:
+ p.error(fmt.Sprintf("argument count mismatch: %d = %d", len(lhs.ElemList), 1))
+ default:
+ // TODO(mdempsky): Have Expr types implement Stringer?
+ p.error(fmt.Sprintf("invalid variable name %s in type switch", lhs))
+ }
+ return &ExprStmt{X: x}
+ }
+
+ as := p.newAssignStmt(Def, lhs, rhs)
+ if gcCompat {
+ as.node = n
+ }
+ return as
+
+ default:
+ p.syntax_error("expecting := or = or comma")
+ p.advance(_Semi, _Rbrace)
+ return nil
+ }
+}
+
+func (p *parser) rangeClause(lhs Expr, def bool) *RangeClause {
+ r := new(RangeClause)
+ r.init(p)
+ 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 {
+ a := new(AssignStmt)
+ a.init(p)
+ a.Op = op
+ a.Lhs = lhs
+ a.Rhs = rhs
+ return a
+}
+
+func (p *parser) labeledStmt(label *Name) Stmt {
+ if trace {
+ defer p.trace("labeledStmt")()
+ }
+
+ s := new(LabeledStmt)
+ s.init(p)
+ 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
+ }
+ }
+
+ return s
+}
+
+func (p *parser) blockStmt() *BlockStmt {
+ if trace {
+ defer p.trace("blockStmt")()
+ }
+
+ s := new(BlockStmt)
+ s.init(p)
+ p.want(_Lbrace)
+ s.Body = p.stmtList()
+ p.want(_Rbrace)
+
+ return s
+}
+
+func (p *parser) declStmt(f func(*Group) Decl) *DeclStmt {
+ if trace {
+ defer p.trace("declStmt")()
+ }
+
+ s := new(DeclStmt)
+ s.init(p)
+
+ p.next() // _Const, _Type, or _Var
+ s.DeclList = p.appendGroup(nil, f)
+
+ return s
+}
+
+func (p *parser) forStmt() Stmt {
+ if trace {
+ defer p.trace("forStmt")()
+ }
+
+ s := new(ForStmt)
+ s.init(p)
+
+ p.want(_For)
+ s.Init, s.Cond, s.Post = p.header(true)
+ if gcCompat {
+ s.init(p)
+ }
+ s.Body = p.stmtBody("for clause")
+
+ return s
+}
+
+// stmtBody parses if and for statement bodies.
+func (p *parser) stmtBody(context string) []Stmt {
+ if trace {
+ defer p.trace("stmtBody")()
+ }
+
+ if !p.got(_Lbrace) {
+ p.syntax_error("missing { after " + context)
+ p.advance(_Name, _Rbrace)
+ }
+
+ body := p.stmtList()
+ p.want(_Rbrace)
+
+ return body
+}
+
+func (p *parser) header(forStmt bool) (init SimpleStmt, cond Expr, post SimpleStmt) {
+ if p.tok == _Lbrace {
+ return
+ }
+
+ 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")
+ }
+ init = p.simpleStmt(nil, forStmt)
+ // If we have a range clause, we are done.
+ if _, ok := init.(*RangeClause); ok {
+ p.xnest = outer
+ return
+ }
+ }
+
+ var condStmt SimpleStmt
+ if p.got(_Semi) {
+ if forStmt {
+ if p.tok != _Semi {
+ condStmt = p.simpleStmt(nil, false)
+ }
+ p.want(_Semi)
+ if p.tok != _Lbrace {
+ post = p.simpleStmt(nil, false)
+ }
+ } else if p.tok != _Lbrace {
+ condStmt = p.simpleStmt(nil, false)
+ }
+ } else {
+ condStmt = init
+ init = nil
+ }
+
+ // unpack condStmt
+ switch s := condStmt.(type) {
+ case nil:
+ // nothing to do
+ case *ExprStmt:
+ cond = s.X
+ default:
+ p.error("invalid condition, tag, or type switch guard")
+ }
+
+ p.xnest = outer
+ return
+}
+
+func (p *parser) ifStmt() *IfStmt {
+ if trace {
+ defer p.trace("ifStmt")()
+ }
+
+ s := new(IfStmt)
+ s.init(p)
+
+ 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")
+
+ if p.got(_Else) {
+ switch p.tok {
+ case _If:
+ s.Else = p.ifStmt()
+ case _Lbrace:
+ s.Else = p.blockStmt()
+ default:
+ p.error("else must be followed by if or statement block")
+ p.advance(_Name, _Rbrace)
+ }
+ }
+
+ return s
+}
+
+func (p *parser) switchStmt() *SwitchStmt {
+ if trace {
+ defer p.trace("switchStmt")()
+ }
+
+ p.want(_Switch)
+ s := new(SwitchStmt)
+ s.init(p)
+
+ s.Init, s.Tag, _ = p.header(false)
+
+ if !p.got(_Lbrace) {
+ p.syntax_error("missing { after switch clause")
+ p.advance(_Case, _Default, _Rbrace)
+ }
+ for p.tok != _EOF && p.tok != _Rbrace {
+ s.Body = append(s.Body, p.caseClause())
+ }
+ p.want(_Rbrace)
+
+ return s
+}
+
+func (p *parser) selectStmt() *SelectStmt {
+ if trace {
+ defer p.trace("selectStmt")()
+ }
+
+ p.want(_Select)
+ s := new(SelectStmt)
+ s.init(p)
+
+ if !p.got(_Lbrace) {
+ p.syntax_error("missing { after select clause")
+ p.advance(_Case, _Default, _Rbrace)
+ }
+ for p.tok != _EOF && p.tok != _Rbrace {
+ s.Body = append(s.Body, p.commClause())
+ }
+ p.want(_Rbrace)
+
+ return s
+}
+
+func (p *parser) caseClause() *CaseClause {
+ if trace {
+ defer p.trace("caseClause")()
+ }
+
+ c := new(CaseClause)
+ c.init(p)
+
+ switch p.tok {
+ case _Case:
+ p.next()
+ c.Cases = p.exprList()
+
+ case _Default:
+ p.next()
+
+ default:
+ p.syntax_error("expecting case or default or }")
+ p.advance(_Case, _Default, _Rbrace)
+ }
+
+ if gcCompat {
+ c.init(p)
+ }
+ p.want(_Colon)
+ c.Body = p.stmtList()
+
+ return c
+}
+
+func (p *parser) commClause() *CommClause {
+ if trace {
+ defer p.trace("commClause")()
+ }
+
+ c := new(CommClause)
+ c.init(p)
+
+ switch p.tok {
+ case _Case:
+ p.next()
+ c.Comm = p.simpleStmt(nil, false)
+
+ // The syntax restricts the possible simple statements here to:
+ //
+ // lhs <- x (send statement)
+ // <-x
+ // lhs = <-x
+ // lhs := <-x
+ //
+ // All these (and more) are recognized by simpleStmt and invalid
+ // syntax trees are flagged later, during type checking.
+ // TODO(gri) eventually may want to restrict valid syntax trees
+ // here.
+
+ case _Default:
+ p.next()
+
+ default:
+ p.syntax_error("expecting case or default or }")
+ p.advance(_Case, _Default, _Rbrace)
+ }
+
+ if gcCompat {
+ c.init(p)
+ }
+ 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 {
+ if trace {
+ defer p.trace("stmt " + p.tok.String())()
+ }
+
+ // Most statements (assignments) start with an identifier;
+ // look for it first before doing anything more expensive.
+ if p.tok == _Name {
+ lhs := p.exprList()
+ if label, ok := lhs.(*Name); ok && p.tok == _Colon {
+ return p.labeledStmt(label)
+ }
+ return p.simpleStmt(lhs, false)
+ }
+
+ switch p.tok {
+ case _Lbrace:
+ return p.blockStmt()
+
+ case _Var:
+ return p.declStmt(p.varDecl)
+
+ case _Const:
+ return p.declStmt(p.constDecl)
+
+ case _Type:
+ return p.declStmt(p.typeDecl)
+
+ case _Operator, _Star:
+ switch p.op {
+ case Add, Sub, Mul, And, Xor, Not:
+ return p.simpleStmt(nil, false) // unary operators
+ }
+
+ case _Literal, _Func, _Lparen, // operands
+ _Lbrack, _Struct, _Map, _Chan, _Interface, // composite types
+ _Arrow: // receive operator
+ return p.simpleStmt(nil, false)
+
+ case _For:
+ return p.forStmt()
+
+ case _Switch:
+ return p.switchStmt()
+
+ case _Select:
+ return p.selectStmt()
+
+ case _If:
+ return p.ifStmt()
+
+ case _Fallthrough:
+ p.next()
+ s := new(BranchStmt)
+ s.init(p)
+ 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
+ if p.tok == _Name {
+ s.Label = p.name()
+ }
+ return s
+
+ case _Go, _Defer:
+ return p.callStmt()
+
+ case _Goto:
+ p.next()
+ s := new(BranchStmt)
+ s.init(p)
+ s.Tok = _Goto
+ 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)
+ 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)
+ return s
+ }
+
+ return missing_stmt
+}
+
+// StatementList = { Statement ";" } .
+func (p *parser) stmtList() (l []Stmt) {
+ if trace {
+ defer p.trace("stmtList")()
+ }
+
+ for p.tok != _EOF && p.tok != _Rbrace && p.tok != _Case && p.tok != _Default {
+ s := p.stmt()
+ if s == missing_stmt {
+ break
+ }
+ l = append(l, s)
+ // customized version of osemi:
+ // ';' is optional before a closing ')' or '}'
+ if p.tok == _Rparen || p.tok == _Rbrace {
+ continue
+ }
+ if !p.got(_Semi) {
+ p.syntax_error("at end of statement")
+ p.advance(_Semi, _Rbrace)
+ }
+ }
+ return
+}
+
+// Arguments = "(" [ ( ExpressionList | Type [ "," ExpressionList ] ) [ "..." ] [ "," ] ] ")" .
+func (p *parser) call(fun Expr) *CallExpr {
+ if trace {
+ defer p.trace("call")()
+ }
+
+ // call or conversion
+ // convtype '(' expr ocomma ')'
+ c := new(CallExpr)
+ c.init(p)
+ 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.HasDots = p.got(_DotDotDot)
+ if !p.ocomma(_Rparen) || c.HasDots {
+ break
+ }
+ }
+
+ p.xnest--
+ if gcCompat {
+ c.init(p)
+ }
+ p.want(_Rparen)
+
+ return c
+}
+
+// ----------------------------------------------------------------------------
+// Common productions
+
+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
+ p.next()
+ } else {
+ n.Value = "_"
+ p.syntax_error("expecting name")
+ p.advance()
+ }
+
+ return n
+}
+
+// IdentifierList = identifier { "," identifier } .
+// The first name must be provided.
+func (p *parser) nameList(first *Name) []*Name {
+ if trace {
+ defer p.trace("nameList")()
+ }
+
+ if debug && first == nil {
+ panic("first name not provided")
+ }
+
+ l := []*Name{first}
+ for p.got(_Comma) {
+ l = append(l, p.name())
+ }
+
+ return l
+}
+
+// The first name may be provided, or nil.
+func (p *parser) qualifiedName(name *Name) Expr {
+ if trace {
+ defer p.trace("qualifiedName")()
+ }
+
+ switch {
+ case name != nil:
+ // name is provided
+ case p.tok == _Name:
+ name = p.name()
+ default:
+ name = new(Name)
+ name.init(p)
+ p.syntax_error("expecting name")
+ p.advance(_Dot, _Semi, _Rbrace)
+ }
+
+ return p.dotname(name)
+}
+
+// ExpressionList = Expression { "," Expression } .
+func (p *parser) exprList() Expr {
+ if trace {
+ defer p.trace("exprList")()
+ }
+
+ x := p.expr()
+ if p.got(_Comma) {
+ list := []Expr{x, p.expr()}
+ for p.got(_Comma) {
+ list = append(list, p.expr())
+ }
+ t := new(ListExpr)
+ t.init(p) // TODO(gri) what is the correct thing here?
+ t.ElemList = list
+ x = t
+ }
+ return x
+}
+
+// osemi parses an optional semicolon.
+func (p *parser) osemi(follow token) bool {
+ switch p.tok {
+ case _Semi:
+ p.next()
+ return true
+
+ case _Rparen, _Rbrace:
+ // semicolon is optional before ) or }
+ return true
+ }
+
+ p.syntax_error("expecting semicolon, newline, or " + tokstring(follow))
+ p.advance(follow)
+ return false
+}
+
+// ocomma parses an optional comma.
+func (p *parser) ocomma(follow token) bool {
+ switch p.tok {
+ case _Comma:
+ p.next()
+ return true
+
+ case _Rparen, _Rbrace:
+ // comma is optional before ) or }
+ return true
+ }
+
+ p.syntax_error("expecting comma or " + tokstring(follow))
+ p.advance(follow)
+ return false
+}
+
+// unparen removes all parentheses around an expression.
+func unparen(x Expr) Expr {
+ for {
+ p, ok := x.(*ParenExpr)
+ if !ok {
+ break
+ }
+ x = p.X
+ }
+ return x
+}
diff --git a/src/cmd/compile/internal/syntax/parser_test.go b/src/cmd/compile/internal/syntax/parser_test.go
new file mode 100644
index 0000000..c4b43bf
--- /dev/null
+++ b/src/cmd/compile/internal/syntax/parser_test.go
@@ -0,0 +1,184 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package syntax
+
+import (
+ "bytes"
+ "flag"
+ "fmt"
+ "io/ioutil"
+ "path/filepath"
+ "runtime"
+ "strings"
+ "sync"
+ "testing"
+ "time"
+)
+
+var fast = flag.Bool("fast", false, "parse package files in parallel")
+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)
+ }
+}
+
+func TestStdLib(t *testing.T) {
+ if testing.Short() {
+ t.Skip("skipping test in short mode")
+ }
+
+ var m1 runtime.MemStats
+ runtime.ReadMemStats(&m1)
+ start := time.Now()
+
+ type parseResult struct {
+ filename string
+ lines int
+ }
+
+ results := make(chan parseResult)
+ go func() {
+ defer close(results)
+ for _, dir := range []string{
+ runtime.GOROOT(),
+ } {
+ walkDirs(t, dir, func(filename string) {
+ if debug {
+ fmt.Printf("parsing %s\n", filename)
+ }
+ ast, err := ParseFile(filename, nil, nil, 0)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ if *verify {
+ verifyPrint(filename, ast)
+ }
+ results <- parseResult{filename, ast.Lines}
+ })
+ }
+ }()
+
+ var count, lines int
+ for res := range results {
+ count++
+ lines += res.lines
+ if testing.Verbose() {
+ fmt.Printf("%5d %s (%d lines)\n", count, res.filename, res.lines)
+ }
+ }
+
+ dt := time.Since(start)
+ var m2 runtime.MemStats
+ runtime.ReadMemStats(&m2)
+ dm := float64(m2.TotalAlloc-m1.TotalAlloc) / 1e6
+
+ fmt.Printf("parsed %d lines (%d files) in %v (%d lines/s)\n", lines, count, dt, int64(float64(lines)/dt.Seconds()))
+ fmt.Printf("allocated %.3fMb (%.3fMb/s)\n", dm, dm/dt.Seconds())
+}
+
+func walkDirs(t *testing.T, dir string, action func(string)) {
+ fis, err := ioutil.ReadDir(dir)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+
+ var files, dirs []string
+ for _, fi := range fis {
+ if fi.Mode().IsRegular() {
+ if strings.HasSuffix(fi.Name(), ".go") {
+ path := filepath.Join(dir, fi.Name())
+ files = append(files, path)
+ }
+ } else if fi.IsDir() && fi.Name() != "testdata" {
+ path := filepath.Join(dir, fi.Name())
+ if !strings.HasSuffix(path, "/test") {
+ dirs = append(dirs, path)
+ }
+ }
+ }
+
+ if *fast {
+ var wg sync.WaitGroup
+ wg.Add(len(files))
+ for _, filename := range files {
+ go func(filename string) {
+ defer wg.Done()
+ action(filename)
+ }(filename)
+ }
+ wg.Wait()
+ } else {
+ for _, filename := range files {
+ action(filename)
+ }
+ }
+
+ for _, dir := range dirs {
+ walkDirs(t, dir, action)
+ }
+}
+
+func verifyPrint(filename string, ast1 *File) {
+ var buf1 bytes.Buffer
+ _, err := Fprint(&buf1, ast1, true)
+ if err != nil {
+ panic(err)
+ }
+
+ ast2, err := ParseBytes(buf1.Bytes(), nil, nil, 0)
+ if err != nil {
+ panic(err)
+ }
+
+ var buf2 bytes.Buffer
+ _, err = Fprint(&buf2, ast2, true)
+ if err != nil {
+ panic(err)
+ }
+
+ if bytes.Compare(buf1.Bytes(), buf2.Bytes()) != 0 {
+ fmt.Printf("--- %s ---\n", filename)
+ fmt.Printf("%s\n", buf1.Bytes())
+ fmt.Println()
+
+ fmt.Printf("--- %s ---\n", filename)
+ fmt.Printf("%s\n", buf2.Bytes())
+ fmt.Println()
+ panic("not equal")
+ }
+}
+
+func TestIssue17697(t *testing.T) {
+ _, err := ParseBytes(nil, nil, nil, 0) // return with parser error, don't panic
+ if err == nil {
+ t.Errorf("no error reported")
+ }
+}
+
+func TestParseFile(t *testing.T) {
+ _, err := ParseFile("", nil, nil, 0)
+ if err == nil {
+ t.Error("missing io error")
+ }
+
+ var first error
+ _, err = ParseFile("", func(err error) {
+ if first == nil {
+ first = err
+ }
+ }, nil, 0)
+ if err == nil || first == nil {
+ t.Error("missing io error")
+ }
+ if err != first {
+ t.Errorf("got %v; want first error %v", err, first)
+ }
+}
diff --git a/src/cmd/compile/internal/syntax/printer.go b/src/cmd/compile/internal/syntax/printer.go
new file mode 100644
index 0000000..0cacf1e
--- /dev/null
+++ b/src/cmd/compile/internal/syntax/printer.go
@@ -0,0 +1,942 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file implements printing of syntax trees in source format.
+
+package syntax
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+ "strings"
+)
+
+// TODO(gri) Consider removing the linebreaks flag from this signature.
+// Its likely rarely used in common cases.
+
+func Fprint(w io.Writer, x Node, linebreaks bool) (n int, err error) {
+ p := printer{
+ output: w,
+ linebreaks: linebreaks,
+ }
+
+ defer func() {
+ n = p.written
+ if e := recover(); e != nil {
+ err = e.(localError).err // re-panics if it's not a localError
+ }
+ }()
+
+ p.print(x)
+ p.flush(_EOF)
+
+ return
+}
+
+func String(n Node) string {
+ var buf bytes.Buffer
+ _, err := Fprint(&buf, n, false)
+ if err != nil {
+ panic(err) // TODO(gri) print something sensible into buf instead
+ }
+ return buf.String()
+}
+
+type ctrlSymbol int
+
+const (
+ none ctrlSymbol = iota
+ semi
+ blank
+ newline
+ indent
+ outdent
+ // comment
+ // eolComment
+)
+
+type whitespace struct {
+ last token
+ kind ctrlSymbol
+ //text string // comment text (possibly ""); valid if kind == comment
+}
+
+type printer struct {
+ output io.Writer
+ written int // number of bytes written
+ linebreaks bool // print linebreaks instead of semis
+
+ indent int // current indentation level
+ nlcount int // number of consecutive newlines
+
+ pending []whitespace // pending whitespace
+ lastTok token // last token (after any pending semi) processed by print
+}
+
+// write is a thin wrapper around p.output.Write
+// that takes care of accounting and error handling.
+func (p *printer) write(data []byte) {
+ n, err := p.output.Write(data)
+ p.written += n
+ if err != nil {
+ panic(localError{err})
+ }
+}
+
+var (
+ tabBytes = []byte("\t\t\t\t\t\t\t\t")
+ newlineByte = []byte("\n")
+ blankByte = []byte(" ")
+)
+
+func (p *printer) writeBytes(data []byte) {
+ if len(data) == 0 {
+ panic("expected non-empty []byte")
+ }
+ if p.nlcount > 0 && p.indent > 0 {
+ // write indentation
+ n := p.indent
+ for n > len(tabBytes) {
+ p.write(tabBytes)
+ n -= len(tabBytes)
+ }
+ p.write(tabBytes[:n])
+ }
+ p.write(data)
+ p.nlcount = 0
+}
+
+func (p *printer) writeString(s string) {
+ p.writeBytes([]byte(s))
+}
+
+// If impliesSemi returns true for a non-blank line's final token tok,
+// a semicolon is automatically inserted. Vice versa, a semicolon may
+// be omitted in those cases.
+func impliesSemi(tok token) bool {
+ switch tok {
+ case _Name,
+ _Break, _Continue, _Fallthrough, _Return,
+ /*_Inc, _Dec,*/ _Rparen, _Rbrack, _Rbrace: // TODO(gri) fix this
+ return true
+ }
+ return false
+}
+
+// TODO(gri) provide table of []byte values for all tokens to avoid repeated string conversion
+
+func lineComment(text string) bool {
+ return strings.HasPrefix(text, "//")
+}
+
+func (p *printer) addWhitespace(kind ctrlSymbol, text string) {
+ p.pending = append(p.pending, whitespace{p.lastTok, kind /*text*/})
+ switch kind {
+ case semi:
+ p.lastTok = _Semi
+ case newline:
+ p.lastTok = 0
+ // TODO(gri) do we need to handle /*-style comments containing newlines here?
+ }
+}
+
+func (p *printer) flush(next token) {
+ // eliminate semis and redundant whitespace
+ sawNewline := next == _EOF
+ sawParen := next == _Rparen || next == _Rbrace
+ for i := len(p.pending) - 1; i >= 0; i-- {
+ switch p.pending[i].kind {
+ case semi:
+ k := semi
+ if sawParen {
+ sawParen = false
+ k = none // eliminate semi
+ } else if sawNewline && impliesSemi(p.pending[i].last) {
+ sawNewline = false
+ k = none // eliminate semi
+ }
+ p.pending[i].kind = k
+ case newline:
+ sawNewline = true
+ case blank, indent, outdent:
+ // nothing to do
+ // case comment:
+ // // A multi-line comment acts like a newline; and a ""
+ // // comment implies by definition at least one newline.
+ // if text := p.pending[i].text; strings.HasPrefix(text, "/*") && strings.ContainsRune(text, '\n') {
+ // sawNewline = true
+ // }
+ // case eolComment:
+ // // TODO(gri) act depending on sawNewline
+ default:
+ panic("unreachable")
+ }
+ }
+
+ // print pending
+ prev := none
+ for i := range p.pending {
+ switch p.pending[i].kind {
+ case none:
+ // nothing to do
+ case semi:
+ p.writeString(";")
+ p.nlcount = 0
+ prev = semi
+ case blank:
+ if prev != blank {
+ // at most one blank
+ p.writeBytes(blankByte)
+ p.nlcount = 0
+ prev = blank
+ }
+ case newline:
+ const maxEmptyLines = 1
+ if p.nlcount <= maxEmptyLines {
+ p.write(newlineByte)
+ p.nlcount++
+ prev = newline
+ }
+ case indent:
+ p.indent++
+ case outdent:
+ p.indent--
+ if p.indent < 0 {
+ panic("negative indentation")
+ }
+ // case comment:
+ // if text := p.pending[i].text; text != "" {
+ // p.writeString(text)
+ // p.nlcount = 0
+ // prev = comment
+ // }
+ // // TODO(gri) should check that line comments are always followed by newline
+ default:
+ panic("unreachable")
+ }
+ }
+
+ p.pending = p.pending[:0] // re-use underlying array
+}
+
+func mayCombine(prev token, next byte) (b bool) {
+ return // for now
+ // switch prev {
+ // case lexical.Int:
+ // b = next == '.' // 1.
+ // case lexical.Add:
+ // b = next == '+' // ++
+ // case lexical.Sub:
+ // b = next == '-' // --
+ // case lexical.Quo:
+ // b = next == '*' // /*
+ // case lexical.Lss:
+ // b = next == '-' || next == '<' // <- or <<
+ // case lexical.And:
+ // b = next == '&' || next == '^' // && or &^
+ // }
+ // return
+}
+
+func (p *printer) print(args ...interface{}) {
+ for i := 0; i < len(args); i++ {
+ switch x := args[i].(type) {
+ case nil:
+ // we should not reach here but don't crash
+
+ case Node:
+ p.printNode(x)
+
+ case token:
+ // _Name implies an immediately following string
+ // argument which is the actual value to print.
+ var s string
+ if x == _Name {
+ i++
+ if i >= len(args) {
+ panic("missing string argument after _Name")
+ }
+ s = args[i].(string)
+ } else {
+ s = x.String()
+ }
+
+ // TODO(gri) This check seems at the wrong place since it doesn't
+ // take into account pending white space.
+ if mayCombine(p.lastTok, s[0]) {
+ panic("adjacent tokens combine without whitespace")
+ }
+
+ if x == _Semi {
+ // delay printing of semi
+ p.addWhitespace(semi, "")
+ } else {
+ p.flush(x)
+ p.writeString(s)
+ p.nlcount = 0
+ p.lastTok = x
+ }
+
+ case Operator:
+ if x != 0 {
+ p.flush(_Operator)
+ p.writeString(x.String())
+ }
+
+ case ctrlSymbol:
+ switch x {
+ case none, semi /*, comment*/ :
+ panic("unreachable")
+ case newline:
+ // TODO(gri) need to handle mandatory newlines after a //-style comment
+ if !p.linebreaks {
+ x = blank
+ }
+ }
+ p.addWhitespace(x, "")
+
+ // case *Comment: // comments are not Nodes
+ // p.addWhitespace(comment, x.Text)
+
+ default:
+ panic(fmt.Sprintf("unexpected argument %v (%T)", x, x))
+ }
+ }
+}
+
+func (p *printer) printNode(n Node) {
+ // ncom := *n.Comments()
+ // if ncom != nil {
+ // // TODO(gri) in general we cannot make assumptions about whether
+ // // a comment is a /*- or a //-style comment since the syntax
+ // // tree may have been manipulated. Need to make sure the correct
+ // // whitespace is emitted.
+ // for _, c := range ncom.Alone {
+ // p.print(c, newline)
+ // }
+ // for _, c := range ncom.Before {
+ // if c.Text == "" || lineComment(c.Text) {
+ // panic("unexpected empty line or //-style 'before' comment")
+ // }
+ // p.print(c, blank)
+ // }
+ // }
+
+ p.printRawNode(n)
+
+ // if ncom != nil && len(ncom.After) > 0 {
+ // for i, c := range ncom.After {
+ // if i+1 < len(ncom.After) {
+ // if c.Text == "" || lineComment(c.Text) {
+ // panic("unexpected empty line or //-style non-final 'after' comment")
+ // }
+ // }
+ // p.print(blank, c)
+ // }
+ // //p.print(newline)
+ // }
+}
+
+func (p *printer) printRawNode(n Node) {
+ switch n := n.(type) {
+ // expressions and types
+ case *Name:
+ p.print(_Name, n.Value) // _Name requires actual value following immediately
+
+ case *BasicLit:
+ p.print(_Name, n.Value) // _Name requires actual value following immediately
+
+ case *FuncLit:
+ p.print(n.Type, blank)
+ p.printBody(n.Body)
+
+ case *CompositeLit:
+ if n.Type != nil {
+ p.print(n.Type)
+ }
+ p.print(_Lbrace)
+ if n.NKeys > 0 && n.NKeys == len(n.ElemList) {
+ p.printExprLines(n.ElemList)
+ } else {
+ p.printExprList(n.ElemList)
+ }
+ p.print(_Rbrace)
+
+ case *ParenExpr:
+ p.print(_Lparen, n.X, _Rparen)
+
+ case *SelectorExpr:
+ p.print(n.X, _Dot, n.Sel)
+
+ case *IndexExpr:
+ p.print(n.X, _Lbrack, n.Index, _Rbrack)
+
+ case *SliceExpr:
+ p.print(n.X, _Lbrack)
+ if i := n.Index[0]; i != nil {
+ p.printNode(i)
+ }
+ p.print(_Colon)
+ if j := n.Index[1]; j != nil {
+ p.printNode(j)
+ }
+ if k := n.Index[2]; k != nil {
+ p.print(_Colon, k)
+ }
+ p.print(_Rbrack)
+
+ case *AssertExpr:
+ p.print(n.X, _Dot, _Lparen)
+ if n.Type != nil {
+ p.printNode(n.Type)
+ } else {
+ p.print(_Type)
+ }
+ p.print(_Rparen)
+
+ case *CallExpr:
+ p.print(n.Fun, _Lparen)
+ p.printExprList(n.ArgList)
+ if n.HasDots {
+ p.print(_DotDotDot)
+ }
+ p.print(_Rparen)
+
+ case *Operation:
+ if n.Y == nil {
+ // unary expr
+ p.print(n.Op)
+ // if n.Op == lexical.Range {
+ // p.print(blank)
+ // }
+ p.print(n.X)
+ } else {
+ // binary expr
+ // TODO(gri) eventually take precedence into account
+ // to control possibly missing parentheses
+ p.print(n.X, blank, n.Op, blank, n.Y)
+ }
+
+ case *KeyValueExpr:
+ p.print(n.Key, _Colon, blank, n.Value)
+
+ case *ListExpr:
+ p.printExprList(n.ElemList)
+
+ case *ArrayType:
+ var len interface{} = _DotDotDot
+ if n.Len != nil {
+ len = n.Len
+ }
+ p.print(_Lbrack, len, _Rbrack, n.Elem)
+
+ case *SliceType:
+ p.print(_Lbrack, _Rbrack, n.Elem)
+
+ case *DotsType:
+ p.print(_DotDotDot, n.Elem)
+
+ case *StructType:
+ p.print(_Struct)
+ if len(n.FieldList) > 0 && p.linebreaks {
+ p.print(blank)
+ }
+ p.print(_Lbrace)
+ if len(n.FieldList) > 0 {
+ p.print(newline, indent)
+ p.printFieldList(n.FieldList, n.TagList)
+ p.print(outdent, newline)
+ }
+ p.print(_Rbrace)
+
+ case *FuncType:
+ p.print(_Func)
+ p.printSignature(n)
+
+ case *InterfaceType:
+ p.print(_Interface)
+ if len(n.MethodList) > 0 && p.linebreaks {
+ p.print(blank)
+ }
+ p.print(_Lbrace)
+ if len(n.MethodList) > 0 {
+ p.print(newline, indent)
+ p.printMethodList(n.MethodList)
+ p.print(outdent, newline)
+ }
+ p.print(_Rbrace)
+
+ case *MapType:
+ p.print(_Map, _Lbrack, n.Key, _Rbrack, n.Value)
+
+ case *ChanType:
+ if n.Dir == RecvOnly {
+ p.print(_Arrow)
+ }
+ p.print(_Chan)
+ if n.Dir == SendOnly {
+ p.print(_Arrow)
+ }
+ p.print(blank, n.Elem)
+
+ // statements
+ case *DeclStmt:
+ p.printDecl(n.DeclList)
+
+ case *EmptyStmt:
+ // nothing to print
+
+ case *LabeledStmt:
+ p.print(outdent, n.Label, _Colon, indent, newline, n.Stmt)
+
+ case *ExprStmt:
+ p.print(n.X)
+
+ case *SendStmt:
+ p.print(n.Chan, blank, _Arrow, blank, n.Value)
+
+ case *AssignStmt:
+ p.print(n.Lhs)
+ if n.Rhs == ImplicitOne {
+ // TODO(gri) This is going to break the mayCombine
+ // check once we enable that again.
+ p.print(n.Op, n.Op) // ++ or --
+ } else {
+ p.print(blank, n.Op, _Assign, blank)
+ p.print(n.Rhs)
+ }
+
+ case *CallStmt:
+ p.print(n.Tok, blank, n.Call)
+
+ case *ReturnStmt:
+ p.print(_Return)
+ if n.Results != nil {
+ p.print(blank, n.Results)
+ }
+
+ case *BranchStmt:
+ p.print(n.Tok)
+ if n.Label != nil {
+ p.print(blank, n.Label)
+ }
+
+ case *BlockStmt:
+ p.printBody(n.Body)
+
+ 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)
+ if n.Else != nil {
+ p.print(blank, _Else, blank, n.Else)
+ }
+
+ case *SwitchStmt:
+ p.print(_Switch, blank)
+ if n.Init != nil {
+ p.print(n.Init, _Semi, blank)
+ }
+ if n.Tag != nil {
+ p.print(n.Tag, blank)
+ }
+ p.printSwitchBody(n.Body)
+
+ case *TypeSwitchGuard:
+ if n.Lhs != nil {
+ p.print(n.Lhs, blank, _Define, blank)
+ }
+ p.print(n.X, _Dot, _Lparen, _Type, _Rparen)
+
+ case *SelectStmt:
+ p.print(_Select, blank) // for now
+ p.printSelectBody(n.Body)
+
+ case *RangeClause:
+ if n.Lhs != nil {
+ tok := _Assign
+ if n.Def {
+ tok = _Define
+ }
+ p.print(n.Lhs, blank, tok, blank)
+ }
+ p.print(_Range, blank, n.X)
+
+ case *ForStmt:
+ p.print(_For, blank)
+ if n.Init == nil && n.Post == nil {
+ if n.Cond != nil {
+ p.print(n.Cond, blank)
+ }
+ } else {
+ if n.Init != nil {
+ p.print(n.Init)
+ // TODO(gri) clean this up
+ if _, ok := n.Init.(*RangeClause); ok {
+ p.print(blank)
+ p.printBody(n.Body)
+ break
+ }
+ }
+ p.print(_Semi, blank)
+ if n.Cond != nil {
+ p.print(n.Cond)
+ }
+ p.print(_Semi, blank)
+ if n.Post != nil {
+ p.print(n.Post, blank)
+ }
+ }
+ p.printBody(n.Body)
+
+ case *ImportDecl:
+ if n.Group == nil {
+ p.print(_Import, blank)
+ }
+ if n.LocalPkgName != nil {
+ p.print(n.LocalPkgName, blank)
+ }
+ p.print(n.Path)
+
+ case *ConstDecl:
+ if n.Group == nil {
+ p.print(_Const, blank)
+ }
+ p.printNameList(n.NameList)
+ if n.Type != nil {
+ p.print(blank, n.Type)
+ }
+ if n.Values != nil {
+ p.print(blank, _Assign, blank, n.Values)
+ }
+
+ case *TypeDecl:
+ if n.Group == nil {
+ p.print(_Type, blank)
+ }
+ p.print(n.Name, blank, n.Type)
+
+ case *VarDecl:
+ if n.Group == nil {
+ p.print(_Var, blank)
+ }
+ p.printNameList(n.NameList)
+ if n.Type != nil {
+ p.print(blank, n.Type)
+ }
+ if n.Values != nil {
+ p.print(blank, _Assign, blank, n.Values)
+ }
+
+ case *FuncDecl:
+ p.print(_Func, blank)
+ if r := n.Recv; r != nil {
+ p.print(_Lparen)
+ if r.Name != nil {
+ p.print(r.Name, blank)
+ }
+ p.printNode(r.Type)
+ p.print(_Rparen, blank)
+ }
+ p.print(n.Name)
+ p.printSignature(n.Type)
+ if n.Body != nil {
+ p.print(blank)
+ p.printBody(n.Body)
+ }
+
+ case *printGroup:
+ p.print(n.Tok, blank, _Lparen)
+ if len(n.Decls) > 0 {
+ p.print(newline, indent)
+ for _, d := range n.Decls {
+ p.printNode(d)
+ p.print(_Semi, newline)
+ }
+ p.print(outdent)
+ }
+ p.print(_Rparen)
+
+ // files
+ case *File:
+ p.print(_Package, blank, n.PkgName)
+ if len(n.DeclList) > 0 {
+ p.print(_Semi, newline, newline)
+ p.printDeclList(n.DeclList)
+ }
+
+ default:
+ panic(fmt.Sprintf("syntax.Iterate: unexpected node type %T", n))
+ }
+}
+
+func (p *printer) printFields(fields []*Field, tags []*BasicLit, i, j int) {
+ if i+1 == j && fields[i].Name == nil {
+ // anonymous field
+ p.printNode(fields[i].Type)
+ } else {
+ for k, f := range fields[i:j] {
+ if k > 0 {
+ p.print(_Comma, blank)
+ }
+ p.printNode(f.Name)
+ }
+ p.print(blank)
+ p.printNode(fields[i].Type)
+ }
+ if i < len(tags) && tags[i] != nil {
+ p.print(blank)
+ p.printNode(tags[i])
+ }
+}
+
+func (p *printer) printFieldList(fields []*Field, tags []*BasicLit) {
+ i0 := 0
+ var typ Expr
+ for i, f := range fields {
+ if f.Name == nil || f.Type != typ {
+ if i0 < i {
+ p.printFields(fields, tags, i0, i)
+ p.print(_Semi, newline)
+ i0 = i
+ }
+ typ = f.Type
+ }
+ }
+ p.printFields(fields, tags, i0, len(fields))
+}
+
+func (p *printer) printMethodList(methods []*Field) {
+ for i, m := range methods {
+ if i > 0 {
+ p.print(_Semi, newline)
+ }
+ if m.Name != nil {
+ p.printNode(m.Name)
+ p.printSignature(m.Type.(*FuncType))
+ } else {
+ p.printNode(m.Type)
+ }
+ }
+}
+
+func (p *printer) printNameList(list []*Name) {
+ for i, x := range list {
+ if i > 0 {
+ p.print(_Comma, blank)
+ }
+ p.printNode(x)
+ }
+}
+
+func (p *printer) printExprList(list []Expr) {
+ for i, x := range list {
+ if i > 0 {
+ p.print(_Comma, blank)
+ }
+ p.printNode(x)
+ }
+}
+
+func (p *printer) printExprLines(list []Expr) {
+ if len(list) > 0 {
+ p.print(newline, indent)
+ for _, x := range list {
+ p.print(x, _Comma, newline)
+ }
+ p.print(outdent)
+ }
+}
+
+func groupFor(d Decl) (token, *Group) {
+ switch d := d.(type) {
+ case *ImportDecl:
+ return _Import, d.Group
+ case *ConstDecl:
+ return _Const, d.Group
+ case *TypeDecl:
+ return _Type, d.Group
+ case *VarDecl:
+ return _Var, d.Group
+ case *FuncDecl:
+ return _Func, nil
+ default:
+ panic("unreachable")
+ }
+}
+
+type printGroup struct {
+ node
+ Tok token
+ Decls []Decl
+}
+
+func (p *printer) printDecl(list []Decl) {
+ tok, group := groupFor(list[0])
+
+ if group == nil {
+ if len(list) != 1 {
+ panic("unreachable")
+ }
+ p.printNode(list[0])
+ return
+ }
+
+ // if _, ok := list[0].(*EmptyDecl); ok {
+ // if len(list) != 1 {
+ // panic("unreachable")
+ // }
+ // // TODO(gri) if there are comments inside the empty
+ // // group, we may need to keep the list non-nil
+ // list = nil
+ // }
+
+ // printGroup is here for consistent comment handling
+ // (this is not yet used)
+ var pg printGroup
+ // *pg.Comments() = *group.Comments()
+ pg.Tok = tok
+ pg.Decls = list
+ p.printNode(&pg)
+}
+
+func (p *printer) printDeclList(list []Decl) {
+ i0 := 0
+ var tok token
+ var group *Group
+ for i, x := range list {
+ if s, g := groupFor(x); g == nil || g != group {
+ if i0 < i {
+ p.printDecl(list[i0:i])
+ p.print(_Semi, newline)
+ // print empty line between different declaration groups,
+ // different kinds of declarations, or between functions
+ if g != group || s != tok || s == _Func {
+ p.print(newline)
+ }
+ i0 = i
+ }
+ tok, group = s, g
+ }
+ }
+ p.printDecl(list[i0:])
+}
+
+func (p *printer) printSignature(sig *FuncType) {
+ p.printParameterList(sig.ParamList)
+ if list := sig.ResultList; list != nil {
+ p.print(blank)
+ if len(list) == 1 && list[0].Name == nil {
+ p.printNode(list[0].Type)
+ } else {
+ p.printParameterList(list)
+ }
+ }
+}
+
+func (p *printer) printParameterList(list []*Field) {
+ p.print(_Lparen)
+ if len(list) > 0 {
+ for i, f := range list {
+ if i > 0 {
+ p.print(_Comma, blank)
+ }
+ if f.Name != nil {
+ p.printNode(f.Name)
+ if i+1 < len(list) {
+ f1 := list[i+1]
+ if f1.Name != nil && f1.Type == f.Type {
+ continue // no need to print type
+ }
+ }
+ p.print(blank)
+ }
+ p.printNode(f.Type)
+ }
+ }
+ p.print(_Rparen)
+}
+
+func (p *printer) printStmtList(list []Stmt, braces bool) {
+ for i, x := range list {
+ p.print(x, _Semi)
+ if i+1 < len(list) {
+ p.print(newline)
+ } else if braces {
+ // Print an extra semicolon if the last statement is
+ // an empty statement and we are in a braced block
+ // because one semicolon is automatically removed.
+ if _, ok := x.(*EmptyStmt); ok {
+ p.print(x, _Semi)
+ }
+ }
+ }
+}
+
+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 {
+ p.print(newline)
+ for i, c := range list {
+ p.printCaseClause(c, i+1 == len(list))
+ p.print(newline)
+ }
+ }
+ p.print(_Rbrace)
+}
+
+func (p *printer) printSelectBody(list []*CommClause) {
+ p.print(_Lbrace)
+ if len(list) > 0 {
+ p.print(newline)
+ for i, c := range list {
+ p.printCommClause(c, i+1 == len(list))
+ p.print(newline)
+ }
+ }
+ p.print(_Rbrace)
+}
+
+func (p *printer) printCaseClause(c *CaseClause, braces bool) {
+ if c.Cases != nil {
+ p.print(_Case, blank, c.Cases)
+ } else {
+ p.print(_Default)
+ }
+ p.print(_Colon)
+ if len(c.Body) > 0 {
+ p.print(newline, indent)
+ p.printStmtList(c.Body, braces)
+ p.print(outdent)
+ }
+}
+
+func (p *printer) printCommClause(c *CommClause, braces bool) {
+ if c.Comm != nil {
+ p.print(_Case, blank)
+ p.print(c.Comm)
+ } else {
+ p.print(_Default)
+ }
+ p.print(_Colon)
+ if len(c.Body) > 0 {
+ p.print(newline, indent)
+ p.printStmtList(c.Body, braces)
+ p.print(outdent)
+ }
+}
diff --git a/src/cmd/compile/internal/syntax/printer_test.go b/src/cmd/compile/internal/syntax/printer_test.go
new file mode 100644
index 0000000..5c0fc77
--- /dev/null
+++ b/src/cmd/compile/internal/syntax/printer_test.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 syntax
+
+import (
+ "fmt"
+ "os"
+ "testing"
+)
+
+func TestPrint(t *testing.T) {
+ if testing.Short() {
+ t.Skip("skipping test in short mode")
+ }
+
+ ast, err := ParseFile(*src, nil, nil, 0)
+ if err != nil {
+ t.Fatal(err)
+ }
+ Fprint(os.Stdout, ast, true)
+ fmt.Println()
+}
diff --git a/src/cmd/compile/internal/syntax/scanner.go b/src/cmd/compile/internal/syntax/scanner.go
new file mode 100644
index 0000000..b84fcc5
--- /dev/null
+++ b/src/cmd/compile/internal/syntax/scanner.go
@@ -0,0 +1,664 @@
+// Copyright 2016 The Go Authors. 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"
+ "io"
+ "strings"
+ "unicode"
+ "unicode/utf8"
+)
+
+type scanner struct {
+ source
+ nlsemi bool // if set '\n' and EOF translate to ';'
+ pragma Pragma
+
+ // current token, valid after calling next()
+ pos, line int
+ tok token
+ lit string // valid if tok is _Name or _Literal
+ 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) {
+ s.source.init(src, errh)
+ s.nlsemi = false
+ s.pragh = pragh
+}
+
+func (s *scanner) next() {
+ nlsemi := s.nlsemi
+ s.nlsemi = false
+
+redo:
+ // skip white space
+ c := s.getr()
+ for c == ' ' || c == '\t' || c == '\n' && !nlsemi || c == '\r' {
+ c = s.getr()
+ }
+
+ // token start
+ s.pos, s.line = s.source.pos0(), s.source.line0
+
+ if isLetter(c) || c >= utf8.RuneSelf && (unicode.IsLetter(c) || s.isCompatRune(c, true)) {
+ s.ident()
+ return
+ }
+
+ switch c {
+ case -1:
+ if nlsemi {
+ s.tok = _Semi
+ break
+ }
+ s.tok = _EOF
+
+ case '\n':
+ s.tok = _Semi
+
+ case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
+ s.number(c)
+
+ case '"':
+ s.stdString()
+
+ case '`':
+ s.rawString()
+
+ case '\'':
+ s.rune()
+
+ case '(':
+ s.tok = _Lparen
+
+ case '[':
+ s.tok = _Lbrack
+
+ case '{':
+ s.tok = _Lbrace
+
+ case ',':
+ s.tok = _Comma
+
+ case ';':
+ s.tok = _Semi
+
+ case ')':
+ s.nlsemi = true
+ s.tok = _Rparen
+
+ case ']':
+ s.nlsemi = true
+ s.tok = _Rbrack
+
+ case '}':
+ s.nlsemi = true
+ s.tok = _Rbrace
+
+ case ':':
+ if s.getr() == '=' {
+ s.tok = _Define
+ break
+ }
+ s.ungetr()
+ s.tok = _Colon
+
+ case '.':
+ c = s.getr()
+ if isDigit(c) {
+ s.ungetr()
+ s.source.r0-- // make sure '.' is part of literal (line cannot have changed)
+ s.number('.')
+ break
+ }
+ if c == '.' {
+ c = s.getr()
+ if c == '.' {
+ s.tok = _DotDotDot
+ break
+ }
+ s.ungetr()
+ s.source.r0-- // make next ungetr work (line cannot have changed)
+ }
+ s.ungetr()
+ s.tok = _Dot
+
+ case '+':
+ s.op, s.prec = Add, precAdd
+ c = s.getr()
+ if c != '+' {
+ goto assignop
+ }
+ s.nlsemi = true
+ s.tok = _IncOp
+
+ case '-':
+ s.op, s.prec = Sub, precAdd
+ c = s.getr()
+ if c != '-' {
+ goto assignop
+ }
+ s.nlsemi = true
+ s.tok = _IncOp
+
+ case '*':
+ s.op, s.prec = Mul, precMul
+ // don't goto assignop - want _Star token
+ if s.getr() == '=' {
+ s.tok = _AssignOp
+ break
+ }
+ s.ungetr()
+ s.tok = _Star
+
+ case '/':
+ c = s.getr()
+ if c == '/' {
+ s.lineComment()
+ goto redo
+ }
+ if c == '*' {
+ s.fullComment()
+ if s.source.line > s.line && nlsemi {
+ // A multi-line comment acts like a newline;
+ // it translates to a ';' if nlsemi is set.
+ s.tok = _Semi
+ break
+ }
+ goto redo
+ }
+ s.op, s.prec = Div, precMul
+ goto assignop
+
+ case '%':
+ s.op, s.prec = Rem, precMul
+ c = s.getr()
+ goto assignop
+
+ case '&':
+ c = s.getr()
+ if c == '&' {
+ s.op, s.prec = AndAnd, precAndAnd
+ s.tok = _Operator
+ break
+ }
+ s.op, s.prec = And, precMul
+ if c == '^' {
+ s.op = AndNot
+ c = s.getr()
+ }
+ goto assignop
+
+ case '|':
+ c = s.getr()
+ if c == '|' {
+ s.op, s.prec = OrOr, precOrOr
+ s.tok = _Operator
+ break
+ }
+ s.op, s.prec = Or, precAdd
+ goto assignop
+
+ case '~':
+ s.error("bitwise complement operator is ^")
+ fallthrough
+
+ case '^':
+ s.op, s.prec = Xor, precAdd
+ c = s.getr()
+ goto assignop
+
+ case '<':
+ c = s.getr()
+ if c == '=' {
+ s.op, s.prec = Leq, precCmp
+ s.tok = _Operator
+ break
+ }
+ if c == '<' {
+ s.op, s.prec = Shl, precMul
+ c = s.getr()
+ goto assignop
+ }
+ if c == '-' {
+ s.tok = _Arrow
+ break
+ }
+ s.ungetr()
+ s.op, s.prec = Lss, precCmp
+ s.tok = _Operator
+
+ case '>':
+ c = s.getr()
+ if c == '=' {
+ s.op, s.prec = Geq, precCmp
+ s.tok = _Operator
+ break
+ }
+ if c == '>' {
+ s.op, s.prec = Shr, precMul
+ c = s.getr()
+ goto assignop
+ }
+ s.ungetr()
+ s.op, s.prec = Gtr, precCmp
+ s.tok = _Operator
+
+ case '=':
+ if s.getr() == '=' {
+ s.op, s.prec = Eql, precCmp
+ s.tok = _Operator
+ break
+ }
+ s.ungetr()
+ s.tok = _Assign
+
+ case '!':
+ if s.getr() == '=' {
+ s.op, s.prec = Neq, precCmp
+ s.tok = _Operator
+ break
+ }
+ s.ungetr()
+ s.op, s.prec = Not, 0
+ s.tok = _Operator
+
+ default:
+ s.tok = 0
+ s.error(fmt.Sprintf("illegal character %#U", c))
+ goto redo
+ }
+
+ return
+
+assignop:
+ if c == '=' {
+ s.tok = _AssignOp
+ return
+ }
+ s.ungetr()
+ s.tok = _Operator
+}
+
+func isLetter(c rune) bool {
+ return 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' || c == '_'
+}
+
+func isDigit(c rune) bool {
+ return '0' <= c && c <= '9'
+}
+
+func (s *scanner) ident() {
+ s.startLit()
+
+ // accelerate common case (7bit ASCII)
+ c := s.getr()
+ for isLetter(c) || isDigit(c) {
+ c = s.getr()
+ }
+
+ // general case
+ if c >= utf8.RuneSelf {
+ for unicode.IsLetter(c) || c == '_' || unicode.IsDigit(c) || s.isCompatRune(c, false) {
+ c = s.getr()
+ }
+ }
+ s.ungetr()
+
+ lit := s.stopLit()
+
+ // possibly a keyword
+ if len(lit) >= 2 {
+ if tok := keywordMap[hash(lit)]; tok != 0 && tokstrings[tok] == string(lit) {
+ s.nlsemi = contains(1<<_Break|1<<_Continue|1<<_Fallthrough|1<<_Return, tok)
+ s.tok = tok
+ return
+ }
+ }
+
+ s.nlsemi = true
+ s.lit = string(lit)
+ 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 {
+ s.error(fmt.Sprintf("invalid identifier character %#U", c))
+ }
+ return true
+}
+
+// hash is a perfect hash function for keywords.
+// It assumes that s has at least length 2.
+func hash(s []byte) uint {
+ return (uint(s[0])<<4 ^ uint(s[1]) + uint(len(s))) & uint(len(keywordMap)-1)
+}
+
+var keywordMap [1 << 6]token // size must be power of two
+
+func init() {
+ // populate keywordMap
+ for tok := _Break; tok <= _Var; tok++ {
+ h := hash([]byte(tokstrings[tok]))
+ if keywordMap[h] != 0 {
+ panic("imperfect hash")
+ }
+ keywordMap[h] = tok
+ }
+}
+
+func (s *scanner) number(c rune) {
+ s.startLit()
+
+ if c != '.' {
+ s.kind = IntLit // until proven otherwise
+ if c == '0' {
+ c = s.getr()
+ if c == 'x' || c == 'X' {
+ // hex
+ c = s.getr()
+ hasDigit := false
+ for isDigit(c) || 'a' <= c && c <= 'f' || 'A' <= c && c <= 'F' {
+ c = s.getr()
+ hasDigit = true
+ }
+ if !hasDigit {
+ s.error("malformed hex constant")
+ }
+ goto done
+ }
+
+ // decimal 0, octal, or float
+ has8or9 := false
+ for isDigit(c) {
+ if c > '7' {
+ has8or9 = true
+ }
+ c = s.getr()
+ }
+ if c != '.' && c != 'e' && c != 'E' && c != 'i' {
+ // octal
+ if has8or9 {
+ s.error("malformed octal constant")
+ }
+ goto done
+ }
+
+ } else {
+ // decimal or float
+ for isDigit(c) {
+ c = s.getr()
+ }
+ }
+ }
+
+ // float
+ if c == '.' {
+ s.kind = FloatLit
+ c = s.getr()
+ for isDigit(c) {
+ c = s.getr()
+ }
+ }
+
+ // exponent
+ if c == 'e' || c == 'E' {
+ s.kind = FloatLit
+ c = s.getr()
+ if c == '-' || c == '+' {
+ c = s.getr()
+ }
+ if !isDigit(c) {
+ s.error("malformed floating-point constant exponent")
+ }
+ for isDigit(c) {
+ c = s.getr()
+ }
+ }
+
+ // complex
+ if c == 'i' {
+ s.kind = ImagLit
+ s.getr()
+ }
+
+done:
+ s.ungetr()
+ s.nlsemi = true
+ s.lit = string(s.stopLit())
+ s.tok = _Literal
+}
+
+func (s *scanner) stdString() {
+ s.startLit()
+
+ for {
+ r := s.getr()
+ if r == '"' {
+ break
+ }
+ if r == '\\' {
+ s.escape('"')
+ continue
+ }
+ if r == '\n' {
+ s.ungetr() // assume newline is not part of literal
+ s.error("newline in string")
+ break
+ }
+ if r < 0 {
+ s.error_at(s.pos, s.line, "string not terminated")
+ break
+ }
+ }
+
+ s.nlsemi = true
+ s.lit = string(s.stopLit())
+ s.kind = StringLit
+ s.tok = _Literal
+}
+
+func (s *scanner) rawString() {
+ s.startLit()
+
+ for {
+ r := s.getr()
+ if r == '`' {
+ break
+ }
+ if r < 0 {
+ s.error_at(s.pos, s.line, "string not terminated")
+ break
+ }
+ }
+ // We leave CRs in the string since they are part of the
+ // literal (even though they are not part of the literal
+ // value).
+
+ s.nlsemi = true
+ s.lit = string(s.stopLit())
+ s.kind = StringLit
+ 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 '")
+ }
+ s.ungetr()
+ }
+
+ 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
+ }
+
+ switch r {
+ case 'g':
+ prefix = "go:"
+ case 'l':
+ prefix = "line "
+ default:
+ goto skip
+ }
+
+ s.startLit()
+ for _, m := range prefix {
+ if r != m {
+ s.stopLit()
+ goto skip
+ }
+ r = s.getr()
+ }
+
+ for r >= 0 {
+ if r == '\n' {
+ s.ungetr()
+ break
+ }
+ r = s.getr()
+ }
+ 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
+}
+
+func (s *scanner) fullComment() {
+ for {
+ r := s.getr()
+ for r == '*' {
+ r = s.getr()
+ if r == '/' {
+ return
+ }
+ }
+ if r < 0 {
+ s.error_at(s.pos, s.line, "comment not terminated")
+ return
+ }
+ }
+}
+
+func (s *scanner) escape(quote rune) bool {
+ var n int
+ var base, max uint32
+
+ c := s.getr()
+ switch c {
+ case 'a', 'b', 'f', 'n', 'r', 't', 'v', '\\', quote:
+ return true
+ case '0', '1', '2', '3', '4', '5', '6', '7':
+ n, base, max = 3, 8, 255
+ case 'x':
+ c = s.getr()
+ n, base, max = 2, 16, 255
+ case 'u':
+ c = s.getr()
+ n, base, max = 4, 16, unicode.MaxRune
+ case 'U':
+ c = s.getr()
+ n, base, max = 8, 16, unicode.MaxRune
+ default:
+ if c < 0 {
+ return true // complain in caller about EOF
+ }
+ s.error("unknown escape sequence")
+ return false
+ }
+
+ var x uint32
+ for i := n; i > 0; i-- {
+ d := base
+ switch {
+ case isDigit(c):
+ d = uint32(c) - '0'
+ case 'a' <= c && c <= 'f':
+ d = uint32(c) - ('a' - 10)
+ case 'A' <= c && c <= 'F':
+ d = uint32(c) - ('A' - 10)
+ }
+ if d >= base {
+ 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")
+ }
+ }
+ s.ungetr()
+ return false
+ }
+ // d < base
+ x = x*base + d
+ c = s.getr()
+ }
+ s.ungetr()
+
+ if x > max && base == 8 {
+ s.error(fmt.Sprintf("octal escape value > 255: %d", x))
+ return false
+ }
+
+ if x > max || 0xD800 <= x && x < 0xE000 /* surrogate range */ {
+ s.error("escape sequence is invalid Unicode code point")
+ return false
+ }
+
+ return true
+}
diff --git a/src/cmd/compile/internal/syntax/scanner_test.go b/src/cmd/compile/internal/syntax/scanner_test.go
new file mode 100644
index 0000000..0e81c4e
--- /dev/null
+++ b/src/cmd/compile/internal/syntax/scanner_test.go
@@ -0,0 +1,355 @@
+// Copyright 2016 The Go Authors. 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"
+ "os"
+ "testing"
+)
+
+func TestScanner(t *testing.T) {
+ if testing.Short() {
+ t.Skip("skipping test in short mode")
+ }
+
+ src, err := os.Open("parser.go")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer src.Close()
+
+ var s scanner
+ s.init(src, nil, nil)
+ for {
+ s.next()
+ if s.tok == _EOF {
+ break
+ }
+ switch s.tok {
+ case _Name:
+ fmt.Println(s.line, s.tok, "=>", s.lit)
+ case _Operator:
+ fmt.Println(s.line, s.tok, "=>", s.op, s.prec)
+ default:
+ fmt.Println(s.line, s.tok)
+ }
+ }
+}
+
+func TestTokens(t *testing.T) {
+ // make source
+ var buf []byte
+ for i, s := range sampleTokens {
+ buf = append(buf, "\t\t\t\t"[:i&3]...) // leading indentation
+ buf = append(buf, s.src...) // token
+ buf = append(buf, " "[:i&7]...) // trailing spaces
+ buf = append(buf, "/* foo */ // bar\n"...) // comments
+ }
+
+ // scan source
+ var got scanner
+ got.init(&bytesReader{buf}, nil, nil)
+ got.next()
+ 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.tok != want.tok {
+ t.Errorf("got tok = %s; want %s", got.tok, want.tok)
+ continue
+ }
+
+ switch want.tok {
+ case _Name, _Literal:
+ if got.lit != want.src {
+ t.Errorf("got lit = %q; want %q", got.lit, want.src)
+ continue
+ }
+ nlsemi = true
+
+ case _Operator, _AssignOp, _IncOp:
+ if got.op != want.op {
+ t.Errorf("got op = %s; want %s", got.op, want.op)
+ continue
+ }
+ if got.prec != want.prec {
+ t.Errorf("got prec = %d; want %d", got.prec, want.prec)
+ continue
+ }
+ nlsemi = want.tok == _IncOp
+
+ case _Rparen, _Rbrack, _Rbrace, _Break, _Continue, _Fallthrough, _Return:
+ nlsemi = true
+ }
+
+ if nlsemi {
+ got.next()
+ if got.tok != _Semi {
+ t.Errorf("got tok = %s; want ;", got.tok)
+ continue
+ }
+ }
+
+ got.next()
+ }
+
+ if got.tok != _EOF {
+ t.Errorf("got %q; want _EOF", got.tok)
+ }
+}
+
+var sampleTokens = [...]struct {
+ tok token
+ src string
+ op Operator
+ prec int
+}{
+ // name samples
+ {_Name, "x", 0, 0},
+ {_Name, "X123", 0, 0},
+ {_Name, "foo", 0, 0},
+ {_Name, "Foo123", 0, 0},
+ {_Name, "foo_bar", 0, 0},
+ {_Name, "_", 0, 0},
+ {_Name, "_foobar", 0, 0},
+ {_Name, "a۰۱۸", 0, 0},
+ {_Name, "foo६४", 0, 0},
+ {_Name, "bar9876", 0, 0},
+ {_Name, "ŝ", 0, 0},
+ {_Name, "ŝfoo", 0, 0},
+
+ // literal samples
+ {_Literal, "0", 0, 0},
+ {_Literal, "1", 0, 0},
+ {_Literal, "12345", 0, 0},
+ {_Literal, "123456789012345678890123456789012345678890", 0, 0},
+ {_Literal, "01234567", 0, 0},
+ {_Literal, "0x0", 0, 0},
+ {_Literal, "0xcafebabe", 0, 0},
+ {_Literal, "0.", 0, 0},
+ {_Literal, "0.e0", 0, 0},
+ {_Literal, "0.e-1", 0, 0},
+ {_Literal, "0.e+123", 0, 0},
+ {_Literal, ".0", 0, 0},
+ {_Literal, ".0E00", 0, 0},
+ {_Literal, ".0E-0123", 0, 0},
+ {_Literal, ".0E+12345678901234567890", 0, 0},
+ {_Literal, ".45e1", 0, 0},
+ {_Literal, "3.14159265", 0, 0},
+ {_Literal, "1e0", 0, 0},
+ {_Literal, "1e+100", 0, 0},
+ {_Literal, "1e-100", 0, 0},
+ {_Literal, "2.71828e-1000", 0, 0},
+ {_Literal, "0i", 0, 0},
+ {_Literal, "1i", 0, 0},
+ {_Literal, "012345678901234567889i", 0, 0},
+ {_Literal, "123456789012345678890i", 0, 0},
+ {_Literal, "0.i", 0, 0},
+ {_Literal, ".0i", 0, 0},
+ {_Literal, "3.14159265i", 0, 0},
+ {_Literal, "1e0i", 0, 0},
+ {_Literal, "1e+100i", 0, 0},
+ {_Literal, "1e-100i", 0, 0},
+ {_Literal, "2.71828e-1000i", 0, 0},
+ {_Literal, "'a'", 0, 0},
+ {_Literal, "'\\000'", 0, 0},
+ {_Literal, "'\\xFF'", 0, 0},
+ {_Literal, "'\\uff16'", 0, 0},
+ {_Literal, "'\\U0000ff16'", 0, 0},
+ {_Literal, "`foobar`", 0, 0},
+ {_Literal, "`foo\tbar`", 0, 0},
+ {_Literal, "`\r`", 0, 0},
+
+ // operators
+ {_Operator, "||", OrOr, precOrOr},
+
+ {_Operator, "&&", AndAnd, precAndAnd},
+
+ {_Operator, "==", Eql, precCmp},
+ {_Operator, "!=", Neq, precCmp},
+ {_Operator, "<", Lss, precCmp},
+ {_Operator, "<=", Leq, precCmp},
+ {_Operator, ">", Gtr, precCmp},
+ {_Operator, ">=", Geq, precCmp},
+
+ {_Operator, "+", Add, precAdd},
+ {_Operator, "-", Sub, precAdd},
+ {_Operator, "|", Or, precAdd},
+ {_Operator, "^", Xor, precAdd},
+
+ {_Star, "*", Mul, precMul},
+ {_Operator, "/", Div, precMul},
+ {_Operator, "%", Rem, precMul},
+ {_Operator, "&", And, precMul},
+ {_Operator, "&^", AndNot, precMul},
+ {_Operator, "<<", Shl, precMul},
+ {_Operator, ">>", Shr, precMul},
+
+ // assignment operations
+ {_AssignOp, "+=", Add, precAdd},
+ {_AssignOp, "-=", Sub, precAdd},
+ {_AssignOp, "|=", Or, precAdd},
+ {_AssignOp, "^=", Xor, precAdd},
+
+ {_AssignOp, "*=", Mul, precMul},
+ {_AssignOp, "/=", Div, precMul},
+ {_AssignOp, "%=", Rem, precMul},
+ {_AssignOp, "&=", And, precMul},
+ {_AssignOp, "&^=", AndNot, precMul},
+ {_AssignOp, "<<=", Shl, precMul},
+ {_AssignOp, ">>=", Shr, precMul},
+
+ // other operations
+ {_IncOp, "++", Add, precAdd},
+ {_IncOp, "--", Sub, precAdd},
+ {_Assign, "=", 0, 0},
+ {_Define, ":=", 0, 0},
+ {_Arrow, "<-", 0, 0},
+
+ // delimiters
+ {_Lparen, "(", 0, 0},
+ {_Lbrack, "[", 0, 0},
+ {_Lbrace, "{", 0, 0},
+ {_Rparen, ")", 0, 0},
+ {_Rbrack, "]", 0, 0},
+ {_Rbrace, "}", 0, 0},
+ {_Comma, ",", 0, 0},
+ {_Semi, ";", 0, 0},
+ {_Colon, ":", 0, 0},
+ {_Dot, ".", 0, 0},
+ {_DotDotDot, "...", 0, 0},
+
+ // keywords
+ {_Break, "break", 0, 0},
+ {_Case, "case", 0, 0},
+ {_Chan, "chan", 0, 0},
+ {_Const, "const", 0, 0},
+ {_Continue, "continue", 0, 0},
+ {_Default, "default", 0, 0},
+ {_Defer, "defer", 0, 0},
+ {_Else, "else", 0, 0},
+ {_Fallthrough, "fallthrough", 0, 0},
+ {_For, "for", 0, 0},
+ {_Func, "func", 0, 0},
+ {_Go, "go", 0, 0},
+ {_Goto, "goto", 0, 0},
+ {_If, "if", 0, 0},
+ {_Import, "import", 0, 0},
+ {_Interface, "interface", 0, 0},
+ {_Map, "map", 0, 0},
+ {_Package, "package", 0, 0},
+ {_Range, "range", 0, 0},
+ {_Return, "return", 0, 0},
+ {_Select, "select", 0, 0},
+ {_Struct, "struct", 0, 0},
+ {_Switch, "switch", 0, 0},
+ {_Type, "type", 0, 0},
+ {_Var, "var", 0, 0},
+}
+
+func TestScanErrors(t *testing.T) {
+ for _, test := range []struct {
+ src, msg string
+ pos, line int
+ }{
+ // 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},
+
+ // 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},
+
+ // former problem cases
+ {"package p\n\n\xef", "invalid UTF-8 encoding", 11, 3},
+ } {
+ var s scanner
+ nerrors := 0
+ s.init(&bytesReader{[]byte(test.src)}, func(err error) {
+ 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 e.Pos != test.pos {
+ t.Errorf("%q: got pos = %d; want %d", test.src, e.Pos, test.pos)
+ }
+ if e.Line != test.line {
+ t.Errorf("%q: got line = %d; want %d", test.src, e.Line, test.line)
+ }
+ } else if nerrors > 1 {
+ t.Errorf("%q: got unexpected %q at pos = %d, line = %d", test.src, e.Msg, e.Pos, e.Line)
+ }
+ }, nil)
+
+ for {
+ s.next()
+ if s.tok == _EOF {
+ break
+ }
+ }
+
+ if nerrors == 0 {
+ t.Errorf("%q: got no error; want %q", test.src, test.msg)
+ }
+ }
+}
diff --git a/src/cmd/compile/internal/syntax/source.go b/src/cmd/compile/internal/syntax/source.go
new file mode 100644
index 0000000..05a1196
--- /dev/null
+++ b/src/cmd/compile/internal/syntax/source.go
@@ -0,0 +1,181 @@
+// Copyright 2016 The Go Authors. 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 (
+ "io"
+ "unicode/utf8"
+)
+
+// buf [...read...|...|...unread...|s|...free...]
+// ^ ^ ^ ^
+// | | | |
+// suf r0 r w
+
+type source struct {
+ src io.Reader
+ errh ErrorHandler
+ first error // first error encountered
+
+ // 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
+
+ // 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) {
+ 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.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)
+}
+
+// pos0 returns the byte position of the last character read.
+func (s *source) pos0() int {
+ return s.offs + s.r0
+}
+
+func (s *source) ungetr() {
+ s.r, s.line = s.r0, s.line0
+}
+
+func (s *source) getr() rune {
+redo:
+ s.r0, s.line0 = s.r, s.line
+
+ // We could avoid at least one test that is always taken in the
+ // for loop below by duplicating the common case code (ASCII)
+ // here since we always have at least the sentinel (utf8.RuneSelf)
+ // 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) {
+ s.fill() // s.w-s.r < len(s.buf) => buffer is not full
+ }
+
+ // common case: ASCII and enough bytes
+ // (invariant: s.buf[s.w] == utf8.RuneSelf)
+ if b := s.buf[s.r]; b < utf8.RuneSelf {
+ s.r++
+ if b == 0 {
+ s.error("invalid NUL character")
+ goto redo
+ }
+ if b == '\n' {
+ s.line++
+ }
+ return rune(b)
+ }
+
+ // EOF
+ if s.r == s.w {
+ if s.err != io.EOF {
+ s.error(s.err.Error())
+ }
+ return -1
+ }
+
+ // uncommon case: not ASCII
+ r, w := utf8.DecodeRune(s.buf[s.r:s.w])
+ s.r += w
+
+ if r == utf8.RuneError && w == 1 {
+ s.error("invalid UTF-8 encoding")
+ goto redo
+ }
+
+ // BOM's are only allowed as the first character in a file
+ const BOM = 0xfeff
+ if r == BOM {
+ if s.r0 > 0 { // s.r0 is always > 0 after 1st character (fill will set it to 1)
+ s.error("invalid BOM in the middle of the file")
+ }
+ goto redo
+ }
+
+ return r
+}
+
+func (s *source) fill() {
+ // Slide unread bytes to beginning but preserve last read char
+ // (for one ungetr call) plus one extra byte (for a 2nd ungetr
+ // call, only for ".." character sequence and float literals
+ // starting with ".").
+ if s.r0 > 1 {
+ // save literal prefix, if any
+ // (We see at most one ungetr call while reading
+ // a literal, so make sure s.r0 remains in buf.)
+ if s.suf >= 0 {
+ s.lit = append(s.lit, s.buf[s.suf:s.r0]...)
+ s.suf = 1 // == s.r0 after slide below
+ }
+ s.offs += s.r0 - 1
+ r := s.r - s.r0 + 1 // last read char plus one byte
+ s.w = r + copy(s.buf[r:], s.buf[s.r:s.w])
+ s.r = r
+ s.r0 = 1
+ }
+
+ // read more data: try a limited number of times
+ for i := 100; i > 0; i-- {
+ n, err := s.src.Read(s.buf[s.w : len(s.buf)-1]) // -1 to leave space for sentinel
+ if n < 0 {
+ panic("negative read") // incorrect underlying io.Reader implementation
+ }
+ s.w += n
+ if n > 0 || err != nil {
+ s.buf[s.w] = utf8.RuneSelf // sentinel
+ if err != nil {
+ s.err = err
+ }
+ return
+ }
+ }
+
+ s.err = io.ErrNoProgress
+}
+
+func (s *source) startLit() {
+ s.suf = s.r0
+ s.lit = s.lit[:0] // reuse lit
+}
+
+func (s *source) stopLit() []byte {
+ lit := s.buf[s.suf:s.r]
+ if len(s.lit) > 0 {
+ lit = append(s.lit, lit...)
+ }
+ s.suf = -1 // no pending literal
+ return lit
+}
diff --git a/src/cmd/compile/internal/syntax/syntax.go b/src/cmd/compile/internal/syntax/syntax.go
new file mode 100644
index 0000000..b1e56ee
--- /dev/null
+++ b/src/cmd/compile/internal/syntax/syntax.go
@@ -0,0 +1,100 @@
+// Copyright 2016 The Go Authors. 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"
+ "io"
+ "os"
+)
+
+// Mode describes the parser mode.
+type Mode uint
+
+// 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
+}
+
+func (err Error) Error() string {
+ return fmt.Sprintf("%d: %s", err.Line, err.Msg)
+}
+
+var _ error = Error{} // verify that Error implements error
+
+// An ErrorHandler is called for each error encountered reading a .go file.
+type ErrorHandler func(err error)
+
+// A Pragma value is a set of flags that augment a function or
+// type declaration. Callers may assign meaning to the flags as
+// appropriate.
+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
+
+// 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.
+//
+// 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
+// immediately upon encountering an error.
+//
+// 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) {
+ defer func() {
+ if p := recover(); p != nil {
+ var ok bool
+ if err, ok = p.(Error); ok {
+ return
+ }
+ panic(p)
+ }
+ }()
+
+ var p parser
+ p.init(src, errh, pragh)
+ p.next()
+ return p.file(), 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)
+}
+
+type bytesReader struct {
+ data []byte
+}
+
+func (r *bytesReader) Read(p []byte) (int, error) {
+ if len(r.data) > 0 {
+ n := copy(p, r.data)
+ r.data = r.data[n:]
+ return n, nil
+ }
+ return 0, io.EOF
+}
+
+// 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)
+ if err != nil {
+ if errh != nil {
+ errh(err)
+ }
+ return nil, err
+ }
+ defer src.Close()
+ return Parse(src, errh, pragh, mode)
+}
diff --git a/src/cmd/compile/internal/syntax/tokens.go b/src/cmd/compile/internal/syntax/tokens.go
new file mode 100644
index 0000000..bd0118a
--- /dev/null
+++ b/src/cmd/compile/internal/syntax/tokens.go
@@ -0,0 +1,263 @@
+// Copyright 2016 The Go Authors. 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"
+
+type token uint
+
+const (
+ _ token = iota
+ _EOF
+
+ // names and literals
+ _Name
+ _Literal
+
+ // operators and operations
+ _Operator // excluding '*' (_Star)
+ _AssignOp
+ _IncOp
+ _Assign
+ _Define
+ _Arrow
+ _Star
+
+ // delimitors
+ _Lparen
+ _Lbrack
+ _Lbrace
+ _Rparen
+ _Rbrack
+ _Rbrace
+ _Comma
+ _Semi
+ _Colon
+ _Dot
+ _DotDotDot
+
+ // keywords
+ _Break
+ _Case
+ _Chan
+ _Const
+ _Continue
+ _Default
+ _Defer
+ _Else
+ _Fallthrough
+ _For
+ _Func
+ _Go
+ _Goto
+ _If
+ _Import
+ _Interface
+ _Map
+ _Package
+ _Range
+ _Return
+ _Select
+ _Struct
+ _Switch
+ _Type
+ _Var
+
+ tokenCount
+)
+
+const (
+ // for BranchStmt
+ Break = _Break
+ Continue = _Continue
+ Fallthrough = _Fallthrough
+ Goto = _Goto
+
+ // for CallStmt
+ Go = _Go
+ Defer = _Defer
+)
+
+var tokstrings = [...]string{
+ // source control
+ _EOF: "EOF",
+
+ // names and literals
+ _Name: "name",
+ _Literal: "literal",
+
+ // operators and operations
+ _Operator: "op",
+ _AssignOp: "op=",
+ _IncOp: "opop",
+ _Assign: "=",
+ _Define: ":=",
+ _Arrow: "<-",
+ _Star: "*",
+
+ // delimitors
+ _Lparen: "(",
+ _Lbrack: "[",
+ _Lbrace: "{",
+ _Rparen: ")",
+ _Rbrack: "]",
+ _Rbrace: "}",
+ _Comma: ",",
+ _Semi: ";",
+ _Colon: ":",
+ _Dot: ".",
+ _DotDotDot: "...",
+
+ // keywords
+ _Break: "break",
+ _Case: "case",
+ _Chan: "chan",
+ _Const: "const",
+ _Continue: "continue",
+ _Default: "default",
+ _Defer: "defer",
+ _Else: "else",
+ _Fallthrough: "fallthrough",
+ _For: "for",
+ _Func: "func",
+ _Go: "go",
+ _Goto: "goto",
+ _If: "if",
+ _Import: "import",
+ _Interface: "interface",
+ _Map: "map",
+ _Package: "package",
+ _Range: "range",
+ _Return: "return",
+ _Select: "select",
+ _Struct: "struct",
+ _Switch: "switch",
+ _Type: "type",
+ _Var: "var",
+}
+
+func (tok token) String() string {
+ var s string
+ if 0 <= tok && int(tok) < len(tokstrings) {
+ s = tokstrings[tok]
+ }
+ if s == "" {
+ s = fmt.Sprintf("<tok-%d>", tok)
+ }
+ return s
+}
+
+// Make sure we have at most 64 tokens so we can use them in a set.
+const _ uint64 = 1 << (tokenCount - 1)
+
+// contains reports whether tok is in tokset.
+func contains(tokset uint64, tok token) bool {
+ return tokset&(1<<tok) != 0
+}
+
+type LitKind uint
+
+const (
+ IntLit LitKind = iota
+ FloatLit
+ ImagLit
+ RuneLit
+ StringLit
+)
+
+type Operator uint
+
+const (
+ _ Operator = iota
+ Def // :=
+ Not // !
+ Recv // <-
+
+ // precOrOr
+ OrOr // ||
+
+ // precAndAnd
+ AndAnd // &&
+
+ // precCmp
+ Eql // ==
+ Neq // !=
+ Lss // <
+ Leq // <=
+ Gtr // >
+ Geq // >=
+
+ // precAdd
+ Add // +
+ Sub // -
+ Or // |
+ Xor // ^
+
+ // precMul
+ Mul // *
+ Div // /
+ Rem // %
+ And // &
+ AndNot // &^
+ Shl // <<
+ Shr // >>
+)
+
+var opstrings = [...]string{
+ // prec == 0
+ Def: ":", // : in :=
+ Not: "!",
+ Recv: "<-",
+
+ // precOrOr
+ OrOr: "||",
+
+ // precAndAnd
+ AndAnd: "&&",
+
+ // precCmp
+ Eql: "==",
+ Neq: "!=",
+ Lss: "<",
+ Leq: "<=",
+ Gtr: ">",
+ Geq: ">=",
+
+ // precAdd
+ Add: "+",
+ Sub: "-",
+ Or: "|",
+ Xor: "^",
+
+ // precMul
+ Mul: "*",
+ Div: "/",
+ Rem: "%",
+ And: "&",
+ AndNot: "&^",
+ Shl: "<<",
+ Shr: ">>",
+}
+
+func (op Operator) String() string {
+ var s string
+ if 0 <= op && int(op) < len(opstrings) {
+ s = opstrings[op]
+ }
+ if s == "" {
+ s = fmt.Sprintf("<op-%d>", op)
+ }
+ return s
+}
+
+// Operator precedences
+const (
+ _ = iota
+ precOrOr
+ precAndAnd
+ precCmp
+ precAdd
+ precMul
+)
diff --git a/src/cmd/compile/internal/x86/387.go b/src/cmd/compile/internal/x86/387.go
new file mode 100644
index 0000000..248fec6
--- /dev/null
+++ b/src/cmd/compile/internal/x86/387.go
@@ -0,0 +1,357 @@
+// Copyright 2016 The Go Authors. 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/compile/internal/ssa"
+ "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 {
+ // 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
+ // function does.
+
+ switch v.Op {
+ case ssa.Op386MOVSSconst, ssa.Op386MOVSDconst:
+ p := gc.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.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.From.Type = obj.TYPE_MEM
+ p.From.Reg = v.Args[0].Reg()
+ gc.AddAux(&p.From, v)
+ switch v.Op {
+ case ssa.Op386MOVSSloadidx1, ssa.Op386MOVSDloadidx1:
+ p.From.Scale = 1
+ p.From.Index = v.Args[1].Reg()
+ case ssa.Op386MOVSSloadidx4:
+ p.From.Scale = 4
+ p.From.Index = v.Args[1].Reg()
+ case ssa.Op386MOVSDloadidx8:
+ p.From.Scale = 8
+ p.From.Index = v.Args[1].Reg()
+ }
+ 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.
+ push(s, v.Args[1])
+
+ // Pop and store value.
+ var op obj.As
+ switch v.Op {
+ case ssa.Op386MOVSSstore:
+ op = x86.AFMOVFP
+ case ssa.Op386MOVSDstore:
+ op = x86.AFMOVDP
+ }
+ p := gc.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])
+ var op obj.As
+ switch v.Op {
+ case ssa.Op386MOVSSstoreidx1, ssa.Op386MOVSSstoreidx4:
+ op = x86.AFMOVFP
+ case ssa.Op386MOVSDstoreidx1, ssa.Op386MOVSDstoreidx8:
+ op = x86.AFMOVDP
+ }
+ p := gc.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)
+ switch v.Op {
+ case ssa.Op386MOVSSstoreidx1, ssa.Op386MOVSDstoreidx1:
+ p.To.Scale = 1
+ p.To.Index = v.Args[1].Reg()
+ case ssa.Op386MOVSSstoreidx4:
+ p.To.Scale = 4
+ p.To.Index = v.Args[1].Reg()
+ case ssa.Op386MOVSDstoreidx8:
+ 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:
+ if v.Reg() != v.Args[0].Reg() {
+ v.Fatalf("input[0] and output not in same register %s", v.LongString())
+ }
+
+ // Push arg1 on top of stack
+ push(s, v.Args[1])
+
+ // 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)
+ s.AddrScratch(&p.To)
+ p = gc.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))
+ }
+
+ var op obj.As
+ switch v.Op {
+ case ssa.Op386ADDSS, ssa.Op386ADDSD:
+ op = x86.AFADDDP
+ case ssa.Op386SUBSS, ssa.Op386SUBSD:
+ op = x86.AFSUBDP
+ case ssa.Op386MULSS, ssa.Op386MULSD:
+ op = x86.AFMULDP
+ case ssa.Op386DIVSS, ssa.Op386DIVSD:
+ op = x86.AFDIVDP
+ }
+ p := gc.Prog(op)
+ p.From.Type = obj.TYPE_REG
+ p.From.Reg = x86.REG_F0
+ p.To.Type = obj.TYPE_REG
+ p.To.Reg = s.SSEto387[v.Reg()] + 1
+
+ // Restore precision if needed.
+ switch v.Op {
+ case ssa.Op386ADDSS, ssa.Op386SUBSS, ssa.Op386MULSS, ssa.Op386DIVSS:
+ p := gc.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.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.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.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)
+
+ // Restore AX.
+ p = gc.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)
+ popAndSave(s, v)
+ return true
+
+ case ssa.Op386FCHS:
+ push(s, v.Args[0])
+ gc.Prog(x86.AFCHS)
+ popAndSave(s, v)
+ return true
+
+ case ssa.Op386CVTSL2SS, ssa.Op386CVTSL2SD:
+ p := gc.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)
+ 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)
+ s.AddrScratch(&p.To)
+ p.To.Offset += 4
+
+ // Load control word which truncates (rounds towards zero).
+ p = gc.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))
+
+ // Now do the conversion.
+ p = gc.Prog(x86.AFMOVLP)
+ p.From.Type = obj.TYPE_REG
+ p.From.Reg = x86.REG_F0
+ s.AddrScratch(&p.To)
+ p = gc.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)
+ 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.From.Type = obj.TYPE_REG
+ p.From.Reg = x86.REG_F0
+ s.AddrScratch(&p.To)
+ p = gc.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
+ }
+ // Load+push the value we need.
+ p := gc.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
+ }
+ push(s, v.Args[0])
+ var op obj.As
+ switch v.Type.Size() {
+ case 4:
+ op = x86.AFMOVFP
+ case 8:
+ op = x86.AFMOVDP
+ }
+ p := gc.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
+ }
+ 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
+ }
+ 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.From.Type = obj.TYPE_REG
+ p.From.Reg = s.SSEto387[v.Reg()]
+ p.To.Type = obj.TYPE_REG
+ p.To.Reg = x86.REG_F0
+}
+
+// popAndSave pops a value off of the floating-point stack and stores
+// it in the reigster assigned to v.
+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.From.Type = obj.TYPE_REG
+ p.From.Reg = x86.REG_F0
+ p.To.Type = obj.TYPE_REG
+ p.To.Reg = s.SSEto387[v.Reg()] + 1
+ } else {
+ // Don't actually pop value. This 387 register is now the
+ // new home for the not-yet-assigned-a-home SSE register.
+ // Increase the register mapping of all other registers by one.
+ for rSSE, r387 := range s.SSEto387 {
+ s.SSEto387[rSSE] = r387 + 1
+ }
+ s.SSEto387[r] = x86.REG_F0
+ }
+}
+
+// loadPush returns the opcode for load+push of the given type.
+func loadPush(t ssa.Type) obj.As {
+ if t.Size() == 4 {
+ return x86.AFMOVF
+ }
+ return x86.AFMOVD
+}
+
+// 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.From.Type = obj.TYPE_REG
+ p.From.Reg = x86.REG_F0
+ p.To.Type = obj.TYPE_REG
+ p.To.Reg = x86.REG_F0
+ delete(s.SSEto387, k)
+ }
+}
diff --git a/src/cmd/compile/internal/x86/cgen.go b/src/cmd/compile/internal/x86/cgen.go
deleted file mode 100644
index 90a773d..0000000
--- a/src/cmd/compile/internal/x86/cgen.go
+++ /dev/null
@@ -1,159 +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 x86
-
-import (
- "cmd/compile/internal/gc"
- "cmd/internal/obj"
- "cmd/internal/obj/x86"
-)
-
-/*
- * generate an addressable node in res, containing the value of n.
- * n is an array index, and might be any size; res width is <= 32-bit.
- * returns Prog* to patch to panic call.
- */
-func igenindex(n *gc.Node, res *gc.Node, bounded bool) *obj.Prog {
- if !gc.Is64(n.Type) {
- if n.Addable && (gc.Simtype[n.Etype] == gc.TUINT32 || gc.Simtype[n.Etype] == gc.TINT32) {
- // nothing to do.
- *res = *n
- } else {
- gc.Tempname(res, gc.Types[gc.TUINT32])
- gc.Cgen(n, res)
- }
-
- return nil
- }
-
- var tmp gc.Node
- gc.Tempname(&tmp, gc.Types[gc.TINT64])
- gc.Cgen(n, &tmp)
- var lo gc.Node
- var hi gc.Node
- split64(&tmp, &lo, &hi)
- gc.Tempname(res, gc.Types[gc.TUINT32])
- gmove(&lo, res)
- if bounded {
- splitclean()
- return nil
- }
-
- var zero gc.Node
- gc.Nodconst(&zero, gc.Types[gc.TINT32], 0)
- gins(x86.ACMPL, &hi, &zero)
- splitclean()
- return gc.Gbranch(x86.AJNE, nil, +1)
-}
-
-func blockcopy(n, res *gc.Node, osrc, odst, w int64) {
- var dst gc.Node
- gc.Nodreg(&dst, gc.Types[gc.Tptr], x86.REG_DI)
- var src gc.Node
- gc.Nodreg(&src, gc.Types[gc.Tptr], x86.REG_SI)
-
- var tsrc gc.Node
- gc.Tempname(&tsrc, gc.Types[gc.Tptr])
- var tdst gc.Node
- gc.Tempname(&tdst, gc.Types[gc.Tptr])
- if !n.Addable {
- gc.Agen(n, &tsrc)
- }
- if !res.Addable {
- gc.Agen(res, &tdst)
- }
- if n.Addable {
- gc.Agen(n, &src)
- } else {
- gmove(&tsrc, &src)
- }
-
- if res.Op == gc.ONAME {
- gc.Gvardef(res)
- }
-
- if res.Addable {
- gc.Agen(res, &dst)
- } else {
- gmove(&tdst, &dst)
- }
-
- c := int32(w % 4) // bytes
- q := int32(w / 4) // doublewords
-
- // if we are copying forward on the stack and
- // the src and dst overlap, then reverse direction
- if osrc < odst && odst < osrc+w {
- // reverse direction
- gins(x86.ASTD, nil, nil) // set direction flag
- if c > 0 {
- gconreg(x86.AADDL, w-1, x86.REG_SI)
- gconreg(x86.AADDL, w-1, x86.REG_DI)
-
- gconreg(x86.AMOVL, int64(c), x86.REG_CX)
- gins(x86.AREP, nil, nil) // repeat
- gins(x86.AMOVSB, nil, nil) // MOVB *(SI)-,*(DI)-
- }
-
- if q > 0 {
- if c > 0 {
- gconreg(x86.AADDL, -3, x86.REG_SI)
- gconreg(x86.AADDL, -3, x86.REG_DI)
- } else {
- gconreg(x86.AADDL, w-4, x86.REG_SI)
- gconreg(x86.AADDL, w-4, x86.REG_DI)
- }
-
- gconreg(x86.AMOVL, int64(q), x86.REG_CX)
- gins(x86.AREP, nil, nil) // repeat
- gins(x86.AMOVSL, nil, nil) // MOVL *(SI)-,*(DI)-
- }
-
- // we leave with the flag clear
- gins(x86.ACLD, nil, nil)
- } else {
- gins(x86.ACLD, nil, nil) // paranoia. TODO(rsc): remove?
-
- // normal direction
- if q > 128 || (q >= 4 && gc.Nacl) {
- gconreg(x86.AMOVL, int64(q), x86.REG_CX)
- gins(x86.AREP, nil, nil) // repeat
- gins(x86.AMOVSL, nil, nil) // MOVL *(SI)+,*(DI)+
- } else if q >= 4 {
- p := gins(obj.ADUFFCOPY, nil, nil)
- p.To.Type = obj.TYPE_ADDR
- p.To.Sym = gc.Linksym(gc.Pkglookup("duffcopy", gc.Runtimepkg))
-
- // 10 and 128 = magic constants: see ../../runtime/asm_386.s
- p.To.Offset = 10 * (128 - int64(q))
- } else if !gc.Nacl && c == 0 {
- var cx gc.Node
- gc.Nodreg(&cx, gc.Types[gc.TINT32], x86.REG_CX)
-
- // We don't need the MOVSL side-effect of updating SI and DI,
- // and issuing a sequence of MOVLs directly is faster.
- src.Op = gc.OINDREG
-
- dst.Op = gc.OINDREG
- for q > 0 {
- gmove(&src, &cx) // MOVL x+(SI),CX
- gmove(&cx, &dst) // MOVL CX,x+(DI)
- src.Xoffset += 4
- dst.Xoffset += 4
- q--
- }
- } else {
- for q > 0 {
- gins(x86.AMOVSL, nil, nil) // MOVL *(SI)+,*(DI)+
- q--
- }
- }
-
- for c > 0 {
- gins(x86.AMOVSB, nil, nil) // MOVB *(SI)+,*(DI)+
- c--
- }
- }
-}
diff --git a/src/cmd/compile/internal/x86/cgen64.go b/src/cmd/compile/internal/x86/cgen64.go
deleted file mode 100644
index ea52d69..0000000
--- a/src/cmd/compile/internal/x86/cgen64.go
+++ /dev/null
@@ -1,598 +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 x86
-
-import (
- "cmd/compile/internal/gc"
- "cmd/internal/obj"
- "cmd/internal/obj/x86"
-)
-
-/*
- * attempt to generate 64-bit
- * res = n
- * return 1 on success, 0 if op not handled.
- */
-func cgen64(n *gc.Node, res *gc.Node) {
- if res.Op != gc.OINDREG && res.Op != gc.ONAME {
- gc.Dump("n", n)
- gc.Dump("res", res)
- gc.Fatalf("cgen64 %v of %v", n.Op, res.Op)
- }
-
- switch n.Op {
- default:
- gc.Fatalf("cgen64 %v", n.Op)
-
- case gc.OMINUS:
- gc.Cgen(n.Left, res)
- var hi1 gc.Node
- var lo1 gc.Node
- split64(res, &lo1, &hi1)
- gins(x86.ANEGL, nil, &lo1)
- gins(x86.AADCL, ncon(0), &hi1)
- gins(x86.ANEGL, nil, &hi1)
- splitclean()
- return
-
- case gc.OCOM:
- gc.Cgen(n.Left, res)
- var lo1 gc.Node
- var hi1 gc.Node
- split64(res, &lo1, &hi1)
- gins(x86.ANOTL, nil, &lo1)
- gins(x86.ANOTL, nil, &hi1)
- splitclean()
- return
-
- // binary operators.
- // common setup below.
- case gc.OADD,
- gc.OSUB,
- gc.OMUL,
- gc.OLROT,
- gc.OLSH,
- gc.ORSH,
- gc.OAND,
- gc.OOR,
- gc.OXOR:
- break
- }
-
- l := n.Left
- r := n.Right
- if !l.Addable {
- var t1 gc.Node
- gc.Tempname(&t1, l.Type)
- gc.Cgen(l, &t1)
- l = &t1
- }
-
- if r != nil && !r.Addable {
- var t2 gc.Node
- gc.Tempname(&t2, r.Type)
- gc.Cgen(r, &t2)
- r = &t2
- }
-
- var ax gc.Node
- gc.Nodreg(&ax, gc.Types[gc.TINT32], x86.REG_AX)
- var cx gc.Node
- gc.Nodreg(&cx, gc.Types[gc.TINT32], x86.REG_CX)
- var dx gc.Node
- gc.Nodreg(&dx, gc.Types[gc.TINT32], x86.REG_DX)
-
- // Setup for binary operation.
- var hi1 gc.Node
- var lo1 gc.Node
- split64(l, &lo1, &hi1)
-
- var lo2 gc.Node
- var hi2 gc.Node
- if gc.Is64(r.Type) {
- split64(r, &lo2, &hi2)
- }
-
- // Do op. Leave result in DX:AX.
- switch n.Op {
- // TODO: Constants
- case gc.OADD:
- gins(x86.AMOVL, &lo1, &ax)
-
- gins(x86.AMOVL, &hi1, &dx)
- gins(x86.AADDL, &lo2, &ax)
- gins(x86.AADCL, &hi2, &dx)
-
- // TODO: Constants.
- case gc.OSUB:
- gins(x86.AMOVL, &lo1, &ax)
-
- gins(x86.AMOVL, &hi1, &dx)
- gins(x86.ASUBL, &lo2, &ax)
- gins(x86.ASBBL, &hi2, &dx)
-
- case gc.OMUL:
- // let's call the next three EX, FX and GX
- var ex, fx, gx gc.Node
- gc.Regalloc(&ex, gc.Types[gc.TPTR32], nil)
- gc.Regalloc(&fx, gc.Types[gc.TPTR32], nil)
- gc.Regalloc(&gx, gc.Types[gc.TPTR32], nil)
-
- // load args into DX:AX and EX:GX.
- gins(x86.AMOVL, &lo1, &ax)
-
- gins(x86.AMOVL, &hi1, &dx)
- gins(x86.AMOVL, &lo2, &gx)
- gins(x86.AMOVL, &hi2, &ex)
-
- // if DX and EX are zero, use 32 x 32 -> 64 unsigned multiply.
- gins(x86.AMOVL, &dx, &fx)
-
- gins(x86.AORL, &ex, &fx)
- p1 := gc.Gbranch(x86.AJNE, nil, 0)
- gins(x86.AMULL, &gx, nil) // implicit &ax
- p2 := gc.Gbranch(obj.AJMP, nil, 0)
- gc.Patch(p1, gc.Pc)
-
- // full 64x64 -> 64, from 32x32 -> 64.
- gins(x86.AIMULL, &gx, &dx)
-
- gins(x86.AMOVL, &ax, &fx)
- gins(x86.AIMULL, &ex, &fx)
- gins(x86.AADDL, &dx, &fx)
- gins(x86.AMOVL, &gx, &dx)
- gins(x86.AMULL, &dx, nil) // implicit &ax
- gins(x86.AADDL, &fx, &dx)
- gc.Patch(p2, gc.Pc)
-
- gc.Regfree(&ex)
- gc.Regfree(&fx)
- gc.Regfree(&gx)
-
- // We only rotate by a constant c in [0,64).
- // if c >= 32:
- // lo, hi = hi, lo
- // c -= 32
- // if c == 0:
- // no-op
- // else:
- // t = hi
- // shld hi:lo, c
- // shld lo:t, c
- case gc.OLROT:
- v := uint64(r.Int64())
-
- if v >= 32 {
- // reverse during load to do the first 32 bits of rotate
- v -= 32
-
- gins(x86.AMOVL, &lo1, &dx)
- gins(x86.AMOVL, &hi1, &ax)
- } else {
- gins(x86.AMOVL, &lo1, &ax)
- gins(x86.AMOVL, &hi1, &dx)
- }
-
- if v == 0 {
- } else // done
- {
- gins(x86.AMOVL, &dx, &cx)
- p1 := gins(x86.ASHLL, ncon(uint32(v)), &dx)
- p1.From.Index = x86.REG_AX // double-width shift
- p1.From.Scale = 0
- p1 = gins(x86.ASHLL, ncon(uint32(v)), &ax)
- p1.From.Index = x86.REG_CX // double-width shift
- p1.From.Scale = 0
- }
-
- case gc.OLSH:
- if r.Op == gc.OLITERAL {
- v := uint64(r.Int64())
- if v >= 64 {
- if gc.Is64(r.Type) {
- splitclean()
- }
- splitclean()
- split64(res, &lo2, &hi2)
- gins(x86.AMOVL, ncon(0), &lo2)
- gins(x86.AMOVL, ncon(0), &hi2)
- splitclean()
- return
- }
-
- if v >= 32 {
- if gc.Is64(r.Type) {
- splitclean()
- }
- split64(res, &lo2, &hi2)
- gmove(&lo1, &hi2)
- if v > 32 {
- gins(x86.ASHLL, ncon(uint32(v-32)), &hi2)
- }
-
- gins(x86.AMOVL, ncon(0), &lo2)
- splitclean()
- splitclean()
- return
- }
-
- // general shift
- gins(x86.AMOVL, &lo1, &ax)
-
- gins(x86.AMOVL, &hi1, &dx)
- p1 := gins(x86.ASHLL, ncon(uint32(v)), &dx)
- p1.From.Index = x86.REG_AX // double-width shift
- p1.From.Scale = 0
- gins(x86.ASHLL, ncon(uint32(v)), &ax)
- break
- }
-
- // load value into DX:AX.
- gins(x86.AMOVL, &lo1, &ax)
-
- gins(x86.AMOVL, &hi1, &dx)
-
- // load shift value into register.
- // if high bits are set, zero value.
- var p1 *obj.Prog
-
- if gc.Is64(r.Type) {
- gins(x86.ACMPL, &hi2, ncon(0))
- p1 = gc.Gbranch(x86.AJNE, nil, +1)
- gins(x86.AMOVL, &lo2, &cx)
- } else {
- cx.Type = gc.Types[gc.TUINT32]
- gmove(r, &cx)
- }
-
- // if shift count is >=64, zero value
- gins(x86.ACMPL, &cx, ncon(64))
-
- p2 := gc.Gbranch(optoas(gc.OLT, gc.Types[gc.TUINT32]), nil, +1)
- if p1 != nil {
- gc.Patch(p1, gc.Pc)
- }
- gins(x86.AXORL, &dx, &dx)
- gins(x86.AXORL, &ax, &ax)
- gc.Patch(p2, gc.Pc)
-
- // if shift count is >= 32, zero low.
- gins(x86.ACMPL, &cx, ncon(32))
-
- p1 = gc.Gbranch(optoas(gc.OLT, gc.Types[gc.TUINT32]), nil, +1)
- gins(x86.AMOVL, &ax, &dx)
- gins(x86.ASHLL, &cx, &dx) // SHLL only uses bottom 5 bits of count
- gins(x86.AXORL, &ax, &ax)
- p2 = gc.Gbranch(obj.AJMP, nil, 0)
- gc.Patch(p1, gc.Pc)
-
- // general shift
- p1 = gins(x86.ASHLL, &cx, &dx)
-
- p1.From.Index = x86.REG_AX // double-width shift
- p1.From.Scale = 0
- gins(x86.ASHLL, &cx, &ax)
- gc.Patch(p2, gc.Pc)
-
- case gc.ORSH:
- if r.Op == gc.OLITERAL {
- v := uint64(r.Int64())
- if v >= 64 {
- if gc.Is64(r.Type) {
- splitclean()
- }
- splitclean()
- split64(res, &lo2, &hi2)
- if hi1.Type.Etype == gc.TINT32 {
- gmove(&hi1, &lo2)
- gins(x86.ASARL, ncon(31), &lo2)
- gmove(&hi1, &hi2)
- gins(x86.ASARL, ncon(31), &hi2)
- } else {
- gins(x86.AMOVL, ncon(0), &lo2)
- gins(x86.AMOVL, ncon(0), &hi2)
- }
-
- splitclean()
- return
- }
-
- if v >= 32 {
- if gc.Is64(r.Type) {
- splitclean()
- }
- split64(res, &lo2, &hi2)
- gmove(&hi1, &lo2)
- if v > 32 {
- gins(optoas(gc.ORSH, hi1.Type), ncon(uint32(v-32)), &lo2)
- }
- if hi1.Type.Etype == gc.TINT32 {
- gmove(&hi1, &hi2)
- gins(x86.ASARL, ncon(31), &hi2)
- } else {
- gins(x86.AMOVL, ncon(0), &hi2)
- }
- splitclean()
- splitclean()
- return
- }
-
- // general shift
- gins(x86.AMOVL, &lo1, &ax)
-
- gins(x86.AMOVL, &hi1, &dx)
- p1 := gins(x86.ASHRL, ncon(uint32(v)), &ax)
- p1.From.Index = x86.REG_DX // double-width shift
- p1.From.Scale = 0
- gins(optoas(gc.ORSH, hi1.Type), ncon(uint32(v)), &dx)
- break
- }
-
- // load value into DX:AX.
- gins(x86.AMOVL, &lo1, &ax)
-
- gins(x86.AMOVL, &hi1, &dx)
-
- // load shift value into register.
- // if high bits are set, zero value.
- var p1 *obj.Prog
-
- if gc.Is64(r.Type) {
- gins(x86.ACMPL, &hi2, ncon(0))
- p1 = gc.Gbranch(x86.AJNE, nil, +1)
- gins(x86.AMOVL, &lo2, &cx)
- } else {
- cx.Type = gc.Types[gc.TUINT32]
- gmove(r, &cx)
- }
-
- // if shift count is >=64, zero or sign-extend value
- gins(x86.ACMPL, &cx, ncon(64))
-
- p2 := gc.Gbranch(optoas(gc.OLT, gc.Types[gc.TUINT32]), nil, +1)
- if p1 != nil {
- gc.Patch(p1, gc.Pc)
- }
- if hi1.Type.Etype == gc.TINT32 {
- gins(x86.ASARL, ncon(31), &dx)
- gins(x86.AMOVL, &dx, &ax)
- } else {
- gins(x86.AXORL, &dx, &dx)
- gins(x86.AXORL, &ax, &ax)
- }
-
- gc.Patch(p2, gc.Pc)
-
- // if shift count is >= 32, sign-extend hi.
- gins(x86.ACMPL, &cx, ncon(32))
-
- p1 = gc.Gbranch(optoas(gc.OLT, gc.Types[gc.TUINT32]), nil, +1)
- gins(x86.AMOVL, &dx, &ax)
- if hi1.Type.Etype == gc.TINT32 {
- gins(x86.ASARL, &cx, &ax) // SARL only uses bottom 5 bits of count
- gins(x86.ASARL, ncon(31), &dx)
- } else {
- gins(x86.ASHRL, &cx, &ax)
- gins(x86.AXORL, &dx, &dx)
- }
-
- p2 = gc.Gbranch(obj.AJMP, nil, 0)
- gc.Patch(p1, gc.Pc)
-
- // general shift
- p1 = gins(x86.ASHRL, &cx, &ax)
-
- p1.From.Index = x86.REG_DX // double-width shift
- p1.From.Scale = 0
- gins(optoas(gc.ORSH, hi1.Type), &cx, &dx)
- gc.Patch(p2, gc.Pc)
-
- // make constant the right side (it usually is anyway).
- case gc.OXOR,
- gc.OAND,
- gc.OOR:
- if lo1.Op == gc.OLITERAL {
- nswap(&lo1, &lo2)
- nswap(&hi1, &hi2)
- }
-
- if lo2.Op == gc.OLITERAL {
- // special cases for constants.
- lv := uint32(lo2.Int64())
- hv := uint32(hi2.Int64())
- splitclean() // right side
- split64(res, &lo2, &hi2)
- switch n.Op {
- case gc.OXOR:
- gmove(&lo1, &lo2)
- gmove(&hi1, &hi2)
- switch lv {
- case 0:
- break
-
- case 0xffffffff:
- gins(x86.ANOTL, nil, &lo2)
-
- default:
- gins(x86.AXORL, ncon(lv), &lo2)
- }
-
- switch hv {
- case 0:
- break
-
- case 0xffffffff:
- gins(x86.ANOTL, nil, &hi2)
-
- default:
- gins(x86.AXORL, ncon(hv), &hi2)
- }
-
- case gc.OAND:
- switch lv {
- case 0:
- gins(x86.AMOVL, ncon(0), &lo2)
-
- default:
- gmove(&lo1, &lo2)
- if lv != 0xffffffff {
- gins(x86.AANDL, ncon(lv), &lo2)
- }
- }
-
- switch hv {
- case 0:
- gins(x86.AMOVL, ncon(0), &hi2)
-
- default:
- gmove(&hi1, &hi2)
- if hv != 0xffffffff {
- gins(x86.AANDL, ncon(hv), &hi2)
- }
- }
-
- case gc.OOR:
- switch lv {
- case 0:
- gmove(&lo1, &lo2)
-
- case 0xffffffff:
- gins(x86.AMOVL, ncon(0xffffffff), &lo2)
-
- default:
- gmove(&lo1, &lo2)
- gins(x86.AORL, ncon(lv), &lo2)
- }
-
- switch hv {
- case 0:
- gmove(&hi1, &hi2)
-
- case 0xffffffff:
- gins(x86.AMOVL, ncon(0xffffffff), &hi2)
-
- default:
- gmove(&hi1, &hi2)
- gins(x86.AORL, ncon(hv), &hi2)
- }
- }
-
- splitclean()
- splitclean()
- return
- }
-
- gins(x86.AMOVL, &lo1, &ax)
- gins(x86.AMOVL, &hi1, &dx)
- gins(optoas(n.Op, lo1.Type), &lo2, &ax)
- gins(optoas(n.Op, lo1.Type), &hi2, &dx)
- }
-
- if gc.Is64(r.Type) {
- splitclean()
- }
- splitclean()
-
- split64(res, &lo1, &hi1)
- gins(x86.AMOVL, &ax, &lo1)
- gins(x86.AMOVL, &dx, &hi1)
- splitclean()
-}
-
-/*
- * generate comparison of nl, nr, both 64-bit.
- * nl is memory; nr is constant or memory.
- */
-func cmp64(nl *gc.Node, nr *gc.Node, op gc.Op, likely int, to *obj.Prog) {
- var lo1 gc.Node
- var hi1 gc.Node
- var lo2 gc.Node
- var hi2 gc.Node
- var rr gc.Node
-
- split64(nl, &lo1, &hi1)
- split64(nr, &lo2, &hi2)
-
- // compare most significant word;
- // if they differ, we're done.
- t := hi1.Type
-
- if nl.Op == gc.OLITERAL || nr.Op == gc.OLITERAL {
- gins(x86.ACMPL, &hi1, &hi2)
- } else {
- gc.Regalloc(&rr, gc.Types[gc.TINT32], nil)
- gins(x86.AMOVL, &hi1, &rr)
- gins(x86.ACMPL, &rr, &hi2)
- gc.Regfree(&rr)
- }
-
- var br *obj.Prog
- switch op {
- default:
- gc.Fatalf("cmp64 %v %v", op, t)
-
- // cmp hi
- // jne L
- // cmp lo
- // jeq to
- // L:
- case gc.OEQ:
- br = gc.Gbranch(x86.AJNE, nil, -likely)
-
- // cmp hi
- // jne to
- // cmp lo
- // jne to
- case gc.ONE:
- gc.Patch(gc.Gbranch(x86.AJNE, nil, likely), to)
-
- // cmp hi
- // jgt to
- // jlt L
- // cmp lo
- // jge to (or jgt to)
- // L:
- case gc.OGE,
- gc.OGT:
- gc.Patch(gc.Gbranch(optoas(gc.OGT, t), nil, likely), to)
-
- br = gc.Gbranch(optoas(gc.OLT, t), nil, -likely)
-
- // cmp hi
- // jlt to
- // jgt L
- // cmp lo
- // jle to (or jlt to)
- // L:
- case gc.OLE,
- gc.OLT:
- gc.Patch(gc.Gbranch(optoas(gc.OLT, t), nil, likely), to)
-
- br = gc.Gbranch(optoas(gc.OGT, t), nil, -likely)
- }
-
- // compare least significant word
- t = lo1.Type
-
- if nl.Op == gc.OLITERAL || nr.Op == gc.OLITERAL {
- gins(x86.ACMPL, &lo1, &lo2)
- } else {
- gc.Regalloc(&rr, gc.Types[gc.TINT32], nil)
- gins(x86.AMOVL, &lo1, &rr)
- gins(x86.ACMPL, &rr, &lo2)
- gc.Regfree(&rr)
- }
-
- // jump again
- gc.Patch(gc.Gbranch(optoas(op, t), nil, likely), to)
-
- // point first branch down here if appropriate
- if br != nil {
- gc.Patch(br, gc.Pc)
- }
-
- splitclean()
- splitclean()
-}
diff --git a/src/cmd/compile/internal/x86/galign.go b/src/cmd/compile/internal/x86/galign.go
index 738d887..edac6a0 100644
--- a/src/cmd/compile/internal/x86/galign.go
+++ b/src/cmd/compile/internal/x86/galign.go
@@ -12,71 +12,23 @@ import (
"os"
)
-func betypeinit() {
-}
-
-func Main() {
+func Init() {
gc.Thearch.LinkArch = &x86.Link386
gc.Thearch.REGSP = x86.REGSP
- gc.Thearch.REGCTXT = x86.REGCTXT
- gc.Thearch.REGCALLX = x86.REG_BX
- gc.Thearch.REGCALLX2 = x86.REG_AX
- gc.Thearch.REGRETURN = x86.REG_AX
- gc.Thearch.REGMIN = x86.REG_AX
- gc.Thearch.REGMAX = x86.REG_DI
- switch v := obj.Getgo386(); v {
+ switch v := obj.GO386; v {
case "387":
- gc.Thearch.FREGMIN = x86.REG_F0
- gc.Thearch.FREGMAX = x86.REG_F7
gc.Thearch.Use387 = true
case "sse2":
- gc.Thearch.FREGMIN = x86.REG_X0
- gc.Thearch.FREGMAX = x86.REG_X7
default:
fmt.Fprintf(os.Stderr, "unsupported setting GO386=%s\n", v)
gc.Exit(1)
}
gc.Thearch.MAXWIDTH = (1 << 32) - 1
- gc.Thearch.ReservedRegs = resvd
- gc.Thearch.Betypeinit = betypeinit
- gc.Thearch.Bgen_float = bgen_float
- gc.Thearch.Cgen64 = cgen64
- gc.Thearch.Cgen_bmul = cgen_bmul
- gc.Thearch.Cgen_float = cgen_float
- gc.Thearch.Cgen_hmul = cgen_hmul
- gc.Thearch.Cgen_shift = cgen_shift
- gc.Thearch.Clearfat = clearfat
- gc.Thearch.Cmp64 = cmp64
gc.Thearch.Defframe = defframe
- gc.Thearch.Dodiv = cgen_div
- gc.Thearch.Excise = excise
- gc.Thearch.Expandchecks = expandchecks
- gc.Thearch.Getg = getg
- gc.Thearch.Gins = gins
- gc.Thearch.Ginscmp = ginscmp
- gc.Thearch.Ginscon = ginscon
- gc.Thearch.Ginsnop = ginsnop
- gc.Thearch.Gmove = gmove
- gc.Thearch.Igenindex = igenindex
- gc.Thearch.Peep = peep
gc.Thearch.Proginfo = proginfo
- gc.Thearch.Regtyp = regtyp
- gc.Thearch.Sameaddr = sameaddr
- gc.Thearch.Smallindir = smallindir
- gc.Thearch.Stackaddr = stackaddr
- gc.Thearch.Blockcopy = blockcopy
- gc.Thearch.Sudoaddable = sudoaddable
- gc.Thearch.Sudoclean = sudoclean
- gc.Thearch.Excludedregs = excludedregs
- gc.Thearch.RtoB = RtoB
- gc.Thearch.FtoB = FtoB
- gc.Thearch.BtoR = BtoR
- gc.Thearch.BtoF = BtoF
- gc.Thearch.Optoas = optoas
- gc.Thearch.Doregbits = doregbits
- gc.Thearch.Regnames = regnames
- gc.Main()
- gc.Exit(0)
+ gc.Thearch.SSAMarkMoves = ssaMarkMoves
+ gc.Thearch.SSAGenValue = ssaGenValue
+ gc.Thearch.SSAGenBlock = ssaGenBlock
}
diff --git a/src/cmd/compile/internal/x86/ggen.go b/src/cmd/compile/internal/x86/ggen.go
index 21d989c..25769b4 100644
--- a/src/cmd/compile/internal/x86/ggen.go
+++ b/src/cmd/compile/internal/x86/ggen.go
@@ -34,9 +34,9 @@ func defframe(ptxt *obj.Prog) {
gc.Fatalf("needzero class %d", n.Class)
}
if n.Type.Width%int64(gc.Widthptr) != 0 || n.Xoffset%int64(gc.Widthptr) != 0 || n.Type.Width == 0 {
- gc.Fatalf("var %v has size %d offset %d", gc.Nconv(n, gc.FmtLong), int(n.Type.Width), int(n.Xoffset))
+ 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) {
+ if lo != hi && n.Xoffset+n.Type.Width >= lo-int64(2*gc.Widthptr) {
// merge with range we already have
lo = n.Xoffset
@@ -62,858 +62,32 @@ func zerorange(p *obj.Prog, frame int64, lo int64, hi int64, ax *uint32) *obj.Pr
return p
}
if *ax == 0 {
- p = appendpp(p, x86.AMOVL, obj.TYPE_CONST, 0, 0, obj.TYPE_REG, x86.REG_AX, 0)
+ p = gc.Appendpp(p, x86.AMOVL, obj.TYPE_CONST, 0, 0, obj.TYPE_REG, x86.REG_AX, 0)
*ax = 1
}
if cnt <= int64(4*gc.Widthreg) {
for i := int64(0); i < cnt; i += int64(gc.Widthreg) {
- p = appendpp(p, x86.AMOVL, obj.TYPE_REG, x86.REG_AX, 0, obj.TYPE_MEM, x86.REG_SP, frame+lo+i)
+ p = gc.Appendpp(p, x86.AMOVL, obj.TYPE_REG, x86.REG_AX, 0, obj.TYPE_MEM, x86.REG_SP, frame+lo+i)
}
} else if !gc.Nacl && cnt <= int64(128*gc.Widthreg) {
- p = appendpp(p, x86.ALEAL, obj.TYPE_MEM, x86.REG_SP, frame+lo, obj.TYPE_REG, x86.REG_DI, 0)
- p = appendpp(p, obj.ADUFFZERO, obj.TYPE_NONE, 0, 0, obj.TYPE_ADDR, 0, 1*(128-cnt/int64(gc.Widthreg)))
+ p = 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))
} else {
- p = appendpp(p, x86.AMOVL, obj.TYPE_CONST, 0, cnt/int64(gc.Widthreg), obj.TYPE_REG, x86.REG_CX, 0)
- p = appendpp(p, x86.ALEAL, obj.TYPE_MEM, x86.REG_SP, frame+lo, obj.TYPE_REG, x86.REG_DI, 0)
- p = appendpp(p, x86.AREP, obj.TYPE_NONE, 0, 0, obj.TYPE_NONE, 0, 0)
- p = appendpp(p, x86.ASTOSL, obj.TYPE_NONE, 0, 0, obj.TYPE_NONE, 0, 0)
+ 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)
}
return p
}
-func appendpp(p *obj.Prog, as obj.As, ftype obj.AddrType, freg int, foffset int64, ttype obj.AddrType, treg int, toffset int64) *obj.Prog {
- q := gc.Ctxt.NewProg()
- gc.Clearp(q)
- q.As = as
- q.Lineno = p.Lineno
- q.From.Type = ftype
- q.From.Reg = int16(freg)
- q.From.Offset = foffset
- q.To.Type = ttype
- q.To.Reg = int16(treg)
- q.To.Offset = toffset
- q.Link = p.Link
- p.Link = q
- return q
-}
-
-func clearfat(nl *gc.Node) {
- /* clear a fat object */
- if gc.Debug['g'] != 0 {
- gc.Dump("\nclearfat", nl)
- }
-
- w := uint32(nl.Type.Width)
-
- // Avoid taking the address for simple enough types.
- if gc.Componentgen(nil, nl) {
- return
- }
-
- c := w % 4 // bytes
- q := w / 4 // quads
-
- if q < 4 {
- // Write sequence of MOV 0, off(base) instead of using STOSL.
- // The hope is that although the code will be slightly longer,
- // the MOVs will have no dependencies and pipeline better
- // than the unrolled STOSL loop.
- // NOTE: Must use agen, not igen, so that optimizer sees address
- // being taken. We are not writing on field boundaries.
- var n1 gc.Node
- gc.Regalloc(&n1, gc.Types[gc.Tptr], nil)
-
- gc.Agen(nl, &n1)
- n1.Op = gc.OINDREG
- var z gc.Node
- gc.Nodconst(&z, gc.Types[gc.TUINT64], 0)
- for ; q > 0; q-- {
- n1.Type = z.Type
- gins(x86.AMOVL, &z, &n1)
- n1.Xoffset += 4
- }
-
- gc.Nodconst(&z, gc.Types[gc.TUINT8], 0)
- for ; c > 0; c-- {
- n1.Type = z.Type
- gins(x86.AMOVB, &z, &n1)
- n1.Xoffset++
- }
-
- gc.Regfree(&n1)
- return
- }
-
- var n1 gc.Node
- gc.Nodreg(&n1, gc.Types[gc.Tptr], x86.REG_DI)
- gc.Agen(nl, &n1)
- gconreg(x86.AMOVL, 0, x86.REG_AX)
-
- if q > 128 || (q >= 4 && gc.Nacl) {
- gconreg(x86.AMOVL, int64(q), x86.REG_CX)
- gins(x86.AREP, nil, nil) // repeat
- gins(x86.ASTOSL, nil, nil) // STOL AL,*(DI)+
- } else if q >= 4 {
- p := gins(obj.ADUFFZERO, nil, nil)
- p.To.Type = obj.TYPE_ADDR
- p.To.Sym = gc.Linksym(gc.Pkglookup("duffzero", gc.Runtimepkg))
-
- // 1 and 128 = magic constants: see ../../runtime/asm_386.s
- p.To.Offset = 1 * (128 - int64(q))
- } else {
- for q > 0 {
- gins(x86.ASTOSL, nil, nil) // STOL AL,*(DI)+
- q--
- }
- }
-
- for c > 0 {
- gins(x86.ASTOSB, nil, nil) // STOB AL,*(DI)+
- c--
- }
-}
-
-var panicdiv *gc.Node
-
-/*
- * generate division.
- * caller must set:
- * ax = allocated AX register
- * dx = allocated DX register
- * generates one of:
- * res = nl / nr
- * res = nl % nr
- * according to op.
- */
-func dodiv(op gc.Op, nl *gc.Node, nr *gc.Node, res *gc.Node, ax *gc.Node, dx *gc.Node) {
- // Have to be careful about handling
- // most negative int divided by -1 correctly.
- // The hardware will trap.
- // Also the byte divide instruction needs AH,
- // which we otherwise don't have to deal with.
- // Easiest way to avoid for int8, int16: use int32.
- // For int32 and int64, use explicit test.
- // Could use int64 hw for int32.
- t := nl.Type
-
- t0 := t
- check := false
- if t.IsSigned() {
- check = true
- if gc.Isconst(nl, gc.CTINT) && nl.Int64() != -1<<uint64(t.Width*8-1) {
- check = false
- } else if gc.Isconst(nr, gc.CTINT) && nr.Int64() != -1 {
- check = false
- }
- }
-
- if t.Width < 4 {
- if t.IsSigned() {
- t = gc.Types[gc.TINT32]
- } else {
- t = gc.Types[gc.TUINT32]
- }
- check = false
- }
-
- var t1 gc.Node
- gc.Tempname(&t1, t)
- var t2 gc.Node
- gc.Tempname(&t2, t)
- if t0 != t {
- var t3 gc.Node
- gc.Tempname(&t3, t0)
- var t4 gc.Node
- gc.Tempname(&t4, t0)
- gc.Cgen(nl, &t3)
- gc.Cgen(nr, &t4)
-
- // Convert.
- gmove(&t3, &t1)
-
- gmove(&t4, &t2)
- } else {
- gc.Cgen(nl, &t1)
- gc.Cgen(nr, &t2)
- }
-
- var n1 gc.Node
- if !gc.Samereg(ax, res) && !gc.Samereg(dx, res) {
- gc.Regalloc(&n1, t, res)
- } else {
- gc.Regalloc(&n1, t, nil)
- }
- gmove(&t2, &n1)
- gmove(&t1, ax)
- var p2 *obj.Prog
- var n4 gc.Node
- if gc.Nacl {
- // Native Client does not relay the divide-by-zero trap
- // to the executing program, so we must insert a check
- // for ourselves.
- gc.Nodconst(&n4, t, 0)
-
- gins(optoas(gc.OCMP, t), &n1, &n4)
- p1 := gc.Gbranch(optoas(gc.ONE, t), nil, +1)
- if panicdiv == nil {
- panicdiv = gc.Sysfunc("panicdivide")
- }
- gc.Ginscall(panicdiv, -1)
- gc.Patch(p1, gc.Pc)
- }
-
- if check {
- gc.Nodconst(&n4, t, -1)
- gins(optoas(gc.OCMP, t), &n1, &n4)
- p1 := gc.Gbranch(optoas(gc.ONE, t), nil, +1)
- if op == gc.ODIV {
- // a / (-1) is -a.
- gins(optoas(gc.OMINUS, t), nil, ax)
-
- gmove(ax, res)
- } else {
- // a % (-1) is 0.
- gc.Nodconst(&n4, t, 0)
-
- gmove(&n4, res)
- }
-
- p2 = gc.Gbranch(obj.AJMP, nil, 0)
- gc.Patch(p1, gc.Pc)
- }
-
- if !t.IsSigned() {
- var nz gc.Node
- gc.Nodconst(&nz, t, 0)
- gmove(&nz, dx)
- } else {
- gins(optoas(gc.OEXTEND, t), nil, nil)
- }
- gins(optoas(op, t), &n1, nil)
- gc.Regfree(&n1)
-
- if op == gc.ODIV {
- gmove(ax, res)
- } else {
- gmove(dx, res)
- }
- if check {
- gc.Patch(p2, gc.Pc)
- }
-}
-
-func savex(dr int, x *gc.Node, oldx *gc.Node, res *gc.Node, t *gc.Type) {
- r := gc.GetReg(dr)
- gc.Nodreg(x, gc.Types[gc.TINT32], dr)
-
- // save current ax and dx if they are live
- // and not the destination
- *oldx = gc.Node{}
-
- if r > 0 && !gc.Samereg(x, res) {
- gc.Tempname(oldx, gc.Types[gc.TINT32])
- gmove(x, oldx)
- }
-
- gc.Regalloc(x, t, x)
-}
-
-func restx(x *gc.Node, oldx *gc.Node) {
- gc.Regfree(x)
-
- if oldx.Op != 0 {
- x.Type = gc.Types[gc.TINT32]
- gmove(oldx, x)
- }
-}
-
-/*
- * generate division according to op, one of:
- * res = nl / nr
- * res = nl % nr
- */
-func cgen_div(op gc.Op, nl *gc.Node, nr *gc.Node, res *gc.Node) {
- if gc.Is64(nl.Type) {
- gc.Fatalf("cgen_div %v", nl.Type)
- }
-
- var t *gc.Type
- if nl.Type.IsSigned() {
- t = gc.Types[gc.TINT32]
- } else {
- t = gc.Types[gc.TUINT32]
- }
- var ax gc.Node
- var oldax gc.Node
- savex(x86.REG_AX, &ax, &oldax, res, t)
- var olddx gc.Node
- var dx gc.Node
- savex(x86.REG_DX, &dx, &olddx, res, t)
- dodiv(op, nl, nr, res, &ax, &dx)
- restx(&dx, &olddx)
- restx(&ax, &oldax)
-}
-
-/*
- * generate shift according to op, one of:
- * res = nl << nr
- * res = nl >> nr
- */
-func cgen_shift(op gc.Op, bounded bool, nl *gc.Node, nr *gc.Node, res *gc.Node) {
- if nl.Type.Width > 4 {
- gc.Fatalf("cgen_shift %v", nl.Type)
- }
-
- w := int(nl.Type.Width * 8)
-
- a := optoas(op, nl.Type)
-
- if nr.Op == gc.OLITERAL {
- var n2 gc.Node
- gc.Tempname(&n2, nl.Type)
- gc.Cgen(nl, &n2)
- var n1 gc.Node
- gc.Regalloc(&n1, nl.Type, res)
- gmove(&n2, &n1)
- sc := uint64(nr.Int64())
- if sc >= uint64(nl.Type.Width*8) {
- // large shift gets 2 shifts by width-1
- gins(a, ncon(uint32(w)-1), &n1)
-
- gins(a, ncon(uint32(w)-1), &n1)
- } else {
- gins(a, nr, &n1)
- }
- gmove(&n1, res)
- gc.Regfree(&n1)
- return
- }
-
- var oldcx gc.Node
- var cx gc.Node
- gc.Nodreg(&cx, gc.Types[gc.TUINT32], x86.REG_CX)
- if gc.GetReg(x86.REG_CX) > 1 && !gc.Samereg(&cx, res) {
- gc.Tempname(&oldcx, gc.Types[gc.TUINT32])
- gmove(&cx, &oldcx)
- }
-
- var n1 gc.Node
- var nt gc.Node
- if nr.Type.Width > 4 {
- gc.Tempname(&nt, nr.Type)
- n1 = nt
- } else {
- gc.Nodreg(&n1, gc.Types[gc.TUINT32], x86.REG_CX)
- gc.Regalloc(&n1, nr.Type, &n1) // to hold the shift type in CX
- }
-
- var n2 gc.Node
- if gc.Samereg(&cx, res) {
- gc.Regalloc(&n2, nl.Type, nil)
- } else {
- gc.Regalloc(&n2, nl.Type, res)
- }
- if nl.Ullman >= nr.Ullman {
- gc.Cgen(nl, &n2)
- gc.Cgen(nr, &n1)
- } else {
- gc.Cgen(nr, &n1)
- gc.Cgen(nl, &n2)
- }
-
- // test and fix up large shifts
- if bounded {
- if nr.Type.Width > 4 {
- // delayed reg alloc
- gc.Nodreg(&n1, gc.Types[gc.TUINT32], x86.REG_CX)
-
- gc.Regalloc(&n1, gc.Types[gc.TUINT32], &n1) // to hold the shift type in CX
- var lo gc.Node
- var hi gc.Node
- split64(&nt, &lo, &hi)
- gmove(&lo, &n1)
- splitclean()
- }
- } else {
- var p1 *obj.Prog
- if nr.Type.Width > 4 {
- // delayed reg alloc
- gc.Nodreg(&n1, gc.Types[gc.TUINT32], x86.REG_CX)
-
- gc.Regalloc(&n1, gc.Types[gc.TUINT32], &n1) // to hold the shift type in CX
- var lo gc.Node
- var hi gc.Node
- split64(&nt, &lo, &hi)
- gmove(&lo, &n1)
- gins(optoas(gc.OCMP, gc.Types[gc.TUINT32]), &hi, ncon(0))
- p2 := gc.Gbranch(optoas(gc.ONE, gc.Types[gc.TUINT32]), nil, +1)
- gins(optoas(gc.OCMP, gc.Types[gc.TUINT32]), &n1, ncon(uint32(w)))
- p1 = gc.Gbranch(optoas(gc.OLT, gc.Types[gc.TUINT32]), nil, +1)
- splitclean()
- gc.Patch(p2, gc.Pc)
- } else {
- gins(optoas(gc.OCMP, nr.Type), &n1, ncon(uint32(w)))
- p1 = gc.Gbranch(optoas(gc.OLT, gc.Types[gc.TUINT32]), nil, +1)
- }
-
- if op == gc.ORSH && nl.Type.IsSigned() {
- gins(a, ncon(uint32(w)-1), &n2)
- } else {
- gmove(ncon(0), &n2)
- }
-
- gc.Patch(p1, gc.Pc)
- }
-
- gins(a, &n1, &n2)
-
- if oldcx.Op != 0 {
- gmove(&oldcx, &cx)
- }
-
- gmove(&n2, res)
-
- gc.Regfree(&n1)
- gc.Regfree(&n2)
-}
-
-/*
- * generate byte multiply:
- * res = nl * nr
- * there is no 2-operand byte multiply instruction so
- * we do a full-width multiplication and truncate afterwards.
- */
-func cgen_bmul(op gc.Op, nl *gc.Node, nr *gc.Node, res *gc.Node) bool {
- if optoas(op, nl.Type) != x86.AIMULB {
- return false
- }
-
- // copy from byte to full registers
- t := gc.Types[gc.TUINT32]
-
- if nl.Type.IsSigned() {
- t = gc.Types[gc.TINT32]
- }
-
- // largest ullman on left.
- if nl.Ullman < nr.Ullman {
- nl, nr = nr, nl
- }
-
- var nt gc.Node
- gc.Tempname(&nt, nl.Type)
- gc.Cgen(nl, &nt)
- var n1 gc.Node
- gc.Regalloc(&n1, t, res)
- gc.Cgen(nr, &n1)
- var n2 gc.Node
- gc.Regalloc(&n2, t, nil)
- gmove(&nt, &n2)
- a := optoas(op, t)
- gins(a, &n2, &n1)
- gc.Regfree(&n2)
- gmove(&n1, res)
- gc.Regfree(&n1)
-
- return true
-}
-
-/*
- * generate high multiply:
- * res = (nl*nr) >> width
- */
-func cgen_hmul(nl *gc.Node, nr *gc.Node, res *gc.Node) {
- var n1 gc.Node
- var n2 gc.Node
-
- t := nl.Type
- a := optoas(gc.OHMUL, t)
-
- // gen nl in n1.
- gc.Tempname(&n1, t)
- gc.Cgen(nl, &n1)
-
- // gen nr in n2.
- gc.Regalloc(&n2, t, res)
- gc.Cgen(nr, &n2)
-
- var ax, oldax, dx, olddx gc.Node
- savex(x86.REG_AX, &ax, &oldax, res, gc.Types[gc.TUINT32])
- savex(x86.REG_DX, &dx, &olddx, res, gc.Types[gc.TUINT32])
-
- gmove(&n2, &ax)
- gins(a, &n1, nil)
- gc.Regfree(&n2)
-
- if t.Width == 1 {
- // byte multiply behaves differently.
- var byteAH, byteDX gc.Node
- gc.Nodreg(&byteAH, t, x86.REG_AH)
- gc.Nodreg(&byteDX, t, x86.REG_DX)
- gmove(&byteAH, &byteDX)
- }
-
- gmove(&dx, res)
-
- restx(&ax, &oldax)
- restx(&dx, &olddx)
-}
-
-/*
- * generate floating-point operation.
- */
-func cgen_float(n *gc.Node, res *gc.Node) {
- nl := n.Left
- switch n.Op {
- case gc.OEQ,
- gc.ONE,
- gc.OLT,
- gc.OLE,
- gc.OGE:
- p1 := gc.Gbranch(obj.AJMP, nil, 0)
- p2 := gc.Pc
- gmove(gc.Nodbool(true), res)
- p3 := gc.Gbranch(obj.AJMP, nil, 0)
- gc.Patch(p1, gc.Pc)
- gc.Bgen(n, true, 0, p2)
- gmove(gc.Nodbool(false), res)
- gc.Patch(p3, gc.Pc)
- return
-
- case gc.OPLUS:
- gc.Cgen(nl, res)
- return
-
- case gc.OCONV:
- if gc.Eqtype(n.Type, nl.Type) || gc.Noconv(n.Type, nl.Type) {
- gc.Cgen(nl, res)
- return
- }
-
- var n2 gc.Node
- gc.Tempname(&n2, n.Type)
- var n1 gc.Node
- gc.Mgen(nl, &n1, res)
- gmove(&n1, &n2)
- gmove(&n2, res)
- gc.Mfree(&n1)
- return
- }
-
- if gc.Thearch.Use387 {
- cgen_float387(n, res)
- } else {
- cgen_floatsse(n, res)
- }
-}
-
-// floating-point. 387 (not SSE2)
-func cgen_float387(n *gc.Node, res *gc.Node) {
- var f0 gc.Node
- var f1 gc.Node
-
- nl := n.Left
- nr := n.Right
- gc.Nodreg(&f0, nl.Type, x86.REG_F0)
- gc.Nodreg(&f1, n.Type, x86.REG_F0+1)
- if nr != nil {
- // binary
- if nl.Ullman >= nr.Ullman {
- gc.Cgen(nl, &f0)
- if nr.Addable {
- gins(foptoas(n.Op, n.Type, 0), nr, &f0)
- } else {
- gc.Cgen(nr, &f0)
- gins(foptoas(n.Op, n.Type, Fpop), &f0, &f1)
- }
- } else {
- gc.Cgen(nr, &f0)
- if nl.Addable {
- gins(foptoas(n.Op, n.Type, Frev), nl, &f0)
- } else {
- gc.Cgen(nl, &f0)
- gins(foptoas(n.Op, n.Type, Frev|Fpop), &f0, &f1)
- }
- }
-
- gmove(&f0, res)
- return
- }
-
- // unary
- gc.Cgen(nl, &f0)
-
- if n.Op != gc.OCONV && n.Op != gc.OPLUS {
- gins(foptoas(n.Op, n.Type, 0), nil, nil)
- }
- gmove(&f0, res)
- return
-}
-
-func cgen_floatsse(n *gc.Node, res *gc.Node) {
- var a obj.As
-
- nl := n.Left
- nr := n.Right
- switch n.Op {
- default:
- gc.Dump("cgen_floatsse", n)
- gc.Fatalf("cgen_floatsse %v", n.Op)
- return
-
- case gc.OMINUS,
- gc.OCOM:
- nr = gc.NegOne(n.Type)
- a = foptoas(gc.OMUL, nl.Type, 0)
- goto sbop
-
- // symmetric binary
- case gc.OADD,
- gc.OMUL:
- a = foptoas(n.Op, nl.Type, 0)
-
- goto sbop
-
- // asymmetric binary
- case gc.OSUB,
- gc.OMOD,
- gc.ODIV:
- a = foptoas(n.Op, nl.Type, 0)
-
- goto abop
- }
-
-sbop: // symmetric binary
- if nl.Ullman < nr.Ullman || nl.Op == gc.OLITERAL {
- nl, nr = nr, nl
- }
-
-abop: // asymmetric binary
- if nl.Ullman >= nr.Ullman {
- var nt gc.Node
- gc.Tempname(&nt, nl.Type)
- gc.Cgen(nl, &nt)
- var n2 gc.Node
- gc.Mgen(nr, &n2, nil)
- var n1 gc.Node
- gc.Regalloc(&n1, nl.Type, res)
- gmove(&nt, &n1)
- gins(a, &n2, &n1)
- gmove(&n1, res)
- gc.Regfree(&n1)
- gc.Mfree(&n2)
- } else {
- var n2 gc.Node
- gc.Regalloc(&n2, nr.Type, res)
- gc.Cgen(nr, &n2)
- var n1 gc.Node
- gc.Regalloc(&n1, nl.Type, nil)
- gc.Cgen(nl, &n1)
- gins(a, &n2, &n1)
- gc.Regfree(&n2)
- gmove(&n1, res)
- gc.Regfree(&n1)
- }
-
- return
-}
-
-func bgen_float(n *gc.Node, wantTrue bool, likely int, to *obj.Prog) {
- nl := n.Left
- nr := n.Right
- op := n.Op
- if !wantTrue {
- // brcom is not valid on floats when NaN is involved.
- p1 := gc.Gbranch(obj.AJMP, nil, 0)
- p2 := gc.Gbranch(obj.AJMP, nil, 0)
- gc.Patch(p1, gc.Pc)
-
- // No need to avoid re-genning ninit.
- bgen_float(n, true, -likely, p2)
-
- gc.Patch(gc.Gbranch(obj.AJMP, nil, 0), to)
- gc.Patch(p2, gc.Pc)
- return
- }
-
- if gc.Thearch.Use387 {
- op = gc.Brrev(op) // because the args are stacked
- if op == gc.OGE || op == gc.OGT {
- // only < and <= work right with NaN; reverse if needed
- nl, nr = nr, nl
- op = gc.Brrev(op)
- }
-
- var ax, n2, tmp gc.Node
- gc.Nodreg(&tmp, nr.Type, x86.REG_F0)
- gc.Nodreg(&n2, nr.Type, x86.REG_F0+1)
- gc.Nodreg(&ax, gc.Types[gc.TUINT16], x86.REG_AX)
- if gc.Simsimtype(nr.Type) == gc.TFLOAT64 {
- if nl.Ullman > nr.Ullman {
- gc.Cgen(nl, &tmp)
- gc.Cgen(nr, &tmp)
- gins(x86.AFXCHD, &tmp, &n2)
- } else {
- gc.Cgen(nr, &tmp)
- gc.Cgen(nl, &tmp)
- }
- gins(x86.AFUCOMPP, &tmp, &n2)
- } else {
- // TODO(rsc): The moves back and forth to memory
- // here are for truncating the value to 32 bits.
- // This handles 32-bit comparison but presumably
- // all the other ops have the same problem.
- // We need to figure out what the right general
- // solution is, besides telling people to use float64.
- var t1 gc.Node
- gc.Tempname(&t1, gc.Types[gc.TFLOAT32])
-
- var t2 gc.Node
- gc.Tempname(&t2, gc.Types[gc.TFLOAT32])
- gc.Cgen(nr, &t1)
- gc.Cgen(nl, &t2)
- gmove(&t2, &tmp)
- gins(x86.AFCOMFP, &t1, &tmp)
- }
- gins(x86.AFSTSW, nil, &ax)
- gins(x86.ASAHF, nil, nil)
- } else {
- // Not 387
- if !nl.Addable {
- nl = gc.CgenTemp(nl)
- }
- if !nr.Addable {
- nr = gc.CgenTemp(nr)
- }
-
- var n2 gc.Node
- gc.Regalloc(&n2, nr.Type, nil)
- gmove(nr, &n2)
- nr = &n2
-
- if nl.Op != gc.OREGISTER {
- var n3 gc.Node
- gc.Regalloc(&n3, nl.Type, nil)
- gmove(nl, &n3)
- nl = &n3
- }
-
- if op == gc.OGE || op == gc.OGT {
- // only < and <= work right with NopN; reverse if needed
- nl, nr = nr, nl
- op = gc.Brrev(op)
- }
-
- gins(foptoas(gc.OCMP, nr.Type, 0), nl, nr)
- if nl.Op == gc.OREGISTER {
- gc.Regfree(nl)
- }
- gc.Regfree(nr)
- }
-
- switch op {
- case gc.OEQ:
- // neither NE nor P
- p1 := gc.Gbranch(x86.AJNE, nil, -likely)
- p2 := gc.Gbranch(x86.AJPS, nil, -likely)
- gc.Patch(gc.Gbranch(obj.AJMP, nil, 0), to)
- gc.Patch(p1, gc.Pc)
- gc.Patch(p2, gc.Pc)
- case gc.ONE:
- // either NE or P
- gc.Patch(gc.Gbranch(x86.AJNE, nil, likely), to)
- gc.Patch(gc.Gbranch(x86.AJPS, nil, likely), to)
- default:
- gc.Patch(gc.Gbranch(optoas(op, nr.Type), nil, likely), to)
- }
-}
-
-// Called after regopt and peep have run.
-// Expand CHECKNIL pseudo-op into actual nil pointer check.
-func expandchecks(firstp *obj.Prog) {
- var p1 *obj.Prog
- var p2 *obj.Prog
-
- for p := firstp; p != nil; p = p.Link {
- if p.As != obj.ACHECKNIL {
- continue
- }
- if gc.Debug_checknil != 0 && p.Lineno > 1 { // p->lineno==1 in generated wrappers
- gc.Warnl(p.Lineno, "generated nil check")
- }
-
- // check is
- // CMP arg, $0
- // JNE 2(PC) (likely)
- // MOV AX, 0
- p1 = gc.Ctxt.NewProg()
-
- p2 = gc.Ctxt.NewProg()
- gc.Clearp(p1)
- gc.Clearp(p2)
- p1.Link = p2
- p2.Link = p.Link
- p.Link = p1
- p1.Lineno = p.Lineno
- p2.Lineno = p.Lineno
- p1.Pc = 9999
- p2.Pc = 9999
- p.As = x86.ACMPL
- p.To.Type = obj.TYPE_CONST
- p.To.Offset = 0
- p1.As = x86.AJNE
- p1.From.Type = obj.TYPE_CONST
- p1.From.Offset = 1 // likely
- p1.To.Type = obj.TYPE_BRANCH
- p1.To.Val = p2.Link
-
- // crash by write to memory address 0.
- // if possible, since we know arg is 0, use 0(arg),
- // which will be shorter to encode than plain 0.
- p2.As = x86.AMOVL
-
- p2.From.Type = obj.TYPE_REG
- p2.From.Reg = x86.REG_AX
- if regtyp(&p.From) {
- p2.To.Type = obj.TYPE_MEM
- p2.To.Reg = p.From.Reg
- } else {
- p2.To.Type = obj.TYPE_MEM
- }
- p2.To.Offset = 0
- }
-}
-
-// addr += index*width if possible.
-func addindex(index *gc.Node, width int64, addr *gc.Node) bool {
- switch width {
- case 1, 2, 4, 8:
- p1 := gins(x86.ALEAL, index, addr)
- p1.From.Type = obj.TYPE_MEM
- p1.From.Scale = int16(width)
- p1.From.Index = p1.From.Reg
- p1.From.Reg = p1.To.Reg
- return true
- }
- return false
-}
-
-// res = runtime.getg()
-func getg(res *gc.Node) {
- var n1 gc.Node
- gc.Regalloc(&n1, res.Type, res)
- mov := optoas(gc.OAS, gc.Types[gc.Tptr])
- p := gins(mov, nil, &n1)
+func ginsnop() {
+ p := gc.Prog(x86.AXCHGL)
p.From.Type = obj.TYPE_REG
- p.From.Reg = x86.REG_TLS
- p = gins(mov, nil, &n1)
- p.From = p.To
- p.From.Type = obj.TYPE_MEM
- p.From.Index = x86.REG_TLS
- p.From.Scale = 1
- gmove(&n1, res)
- gc.Regfree(&n1)
+ p.From.Reg = x86.REG_AX
+ p.To.Type = obj.TYPE_REG
+ p.To.Reg = x86.REG_AX
}
diff --git a/src/cmd/compile/internal/x86/gsubr.go b/src/cmd/compile/internal/x86/gsubr.go
deleted file mode 100644
index 6406326..0000000
--- a/src/cmd/compile/internal/x86/gsubr.go
+++ /dev/null
@@ -1,1844 +0,0 @@
-// Derived from Inferno utils/8c/txt.c
-// http://code.google.com/p/inferno-os/source/browse/utils/8c/txt.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth at terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth at terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// Portions Copyright © 2009 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-package x86
-
-import (
- "cmd/compile/internal/big"
- "cmd/compile/internal/gc"
- "cmd/internal/obj"
- "cmd/internal/obj/x86"
- "fmt"
-)
-
-// TODO(rsc): Can make this bigger if we move
-// the text segment up higher in 8l for all GOOS.
-// At the same time, can raise StackBig in ../../runtime/stack.h.
-var unmappedzero uint32 = 4096
-
-// foptoas flags
-const (
- Frev = 1 << 0
- Fpop = 1 << 1
- Fpop2 = 1 << 2
-)
-
-/*
- * return Axxx for Oxxx on type t.
- */
-func optoas(op gc.Op, t *gc.Type) obj.As {
- if t == nil {
- gc.Fatalf("optoas: t is nil")
- }
-
- // avoid constant conversions in switches below
- const (
- OMINUS_ = uint32(gc.OMINUS) << 16
- OLSH_ = uint32(gc.OLSH) << 16
- ORSH_ = uint32(gc.ORSH) << 16
- OADD_ = uint32(gc.OADD) << 16
- OSUB_ = uint32(gc.OSUB) << 16
- OMUL_ = uint32(gc.OMUL) << 16
- ODIV_ = uint32(gc.ODIV) << 16
- OMOD_ = uint32(gc.OMOD) << 16
- OOR_ = uint32(gc.OOR) << 16
- OAND_ = uint32(gc.OAND) << 16
- OXOR_ = uint32(gc.OXOR) << 16
- OEQ_ = uint32(gc.OEQ) << 16
- ONE_ = uint32(gc.ONE) << 16
- OLT_ = uint32(gc.OLT) << 16
- OLE_ = uint32(gc.OLE) << 16
- OGE_ = uint32(gc.OGE) << 16
- OGT_ = uint32(gc.OGT) << 16
- OCMP_ = uint32(gc.OCMP) << 16
- OAS_ = uint32(gc.OAS) << 16
- OHMUL_ = uint32(gc.OHMUL) << 16
- OADDR_ = uint32(gc.OADDR) << 16
- OINC_ = uint32(gc.OINC) << 16
- ODEC_ = uint32(gc.ODEC) << 16
- OLROT_ = uint32(gc.OLROT) << 16
- OEXTEND_ = uint32(gc.OEXTEND) << 16
- OCOM_ = uint32(gc.OCOM) << 16
- )
-
- a := obj.AXXX
- switch uint32(op)<<16 | uint32(gc.Simtype[t.Etype]) {
- default:
- gc.Fatalf("optoas: no entry %v-%v", op, t)
-
- case OADDR_ | gc.TPTR32:
- a = x86.ALEAL
-
- case OEQ_ | gc.TBOOL,
- OEQ_ | gc.TINT8,
- OEQ_ | gc.TUINT8,
- OEQ_ | gc.TINT16,
- OEQ_ | gc.TUINT16,
- OEQ_ | gc.TINT32,
- OEQ_ | gc.TUINT32,
- OEQ_ | gc.TINT64,
- OEQ_ | gc.TUINT64,
- OEQ_ | gc.TPTR32,
- OEQ_ | gc.TPTR64,
- OEQ_ | gc.TFLOAT32,
- OEQ_ | gc.TFLOAT64:
- a = x86.AJEQ
-
- case ONE_ | gc.TBOOL,
- ONE_ | gc.TINT8,
- ONE_ | gc.TUINT8,
- ONE_ | gc.TINT16,
- ONE_ | gc.TUINT16,
- ONE_ | gc.TINT32,
- ONE_ | gc.TUINT32,
- ONE_ | gc.TINT64,
- ONE_ | gc.TUINT64,
- ONE_ | gc.TPTR32,
- ONE_ | gc.TPTR64,
- ONE_ | gc.TFLOAT32,
- ONE_ | gc.TFLOAT64:
- a = x86.AJNE
-
- case OLT_ | gc.TINT8,
- OLT_ | gc.TINT16,
- OLT_ | gc.TINT32,
- OLT_ | gc.TINT64:
- a = x86.AJLT
-
- case OLT_ | gc.TUINT8,
- OLT_ | gc.TUINT16,
- OLT_ | gc.TUINT32,
- OLT_ | gc.TUINT64:
- a = x86.AJCS
-
- case OLE_ | gc.TINT8,
- OLE_ | gc.TINT16,
- OLE_ | gc.TINT32,
- OLE_ | gc.TINT64:
- a = x86.AJLE
-
- case OLE_ | gc.TUINT8,
- OLE_ | gc.TUINT16,
- OLE_ | gc.TUINT32,
- OLE_ | gc.TUINT64:
- a = x86.AJLS
-
- case OGT_ | gc.TINT8,
- OGT_ | gc.TINT16,
- OGT_ | gc.TINT32,
- OGT_ | gc.TINT64:
- a = x86.AJGT
-
- case OGT_ | gc.TUINT8,
- OGT_ | gc.TUINT16,
- OGT_ | gc.TUINT32,
- OGT_ | gc.TUINT64,
- OLT_ | gc.TFLOAT32,
- OLT_ | gc.TFLOAT64:
- a = x86.AJHI
-
- case OGE_ | gc.TINT8,
- OGE_ | gc.TINT16,
- OGE_ | gc.TINT32,
- OGE_ | gc.TINT64:
- a = x86.AJGE
-
- case OGE_ | gc.TUINT8,
- OGE_ | gc.TUINT16,
- OGE_ | gc.TUINT32,
- OGE_ | gc.TUINT64,
- OLE_ | gc.TFLOAT32,
- OLE_ | gc.TFLOAT64:
- a = x86.AJCC
-
- case OCMP_ | gc.TBOOL,
- OCMP_ | gc.TINT8,
- OCMP_ | gc.TUINT8:
- a = x86.ACMPB
-
- case OCMP_ | gc.TINT16,
- OCMP_ | gc.TUINT16:
- a = x86.ACMPW
-
- case OCMP_ | gc.TINT32,
- OCMP_ | gc.TUINT32,
- OCMP_ | gc.TPTR32:
- a = x86.ACMPL
-
- case OAS_ | gc.TBOOL,
- OAS_ | gc.TINT8,
- OAS_ | gc.TUINT8:
- a = x86.AMOVB
-
- case OAS_ | gc.TINT16,
- OAS_ | gc.TUINT16:
- a = x86.AMOVW
-
- case OAS_ | gc.TINT32,
- OAS_ | gc.TUINT32,
- OAS_ | gc.TPTR32:
- a = x86.AMOVL
-
- case OAS_ | gc.TFLOAT32:
- a = x86.AMOVSS
-
- case OAS_ | gc.TFLOAT64:
- a = x86.AMOVSD
-
- case OADD_ | gc.TINT8,
- OADD_ | gc.TUINT8:
- a = x86.AADDB
-
- case OADD_ | gc.TINT16,
- OADD_ | gc.TUINT16:
- a = x86.AADDW
-
- case OADD_ | gc.TINT32,
- OADD_ | gc.TUINT32,
- OADD_ | gc.TPTR32:
- a = x86.AADDL
-
- case OSUB_ | gc.TINT8,
- OSUB_ | gc.TUINT8:
- a = x86.ASUBB
-
- case OSUB_ | gc.TINT16,
- OSUB_ | gc.TUINT16:
- a = x86.ASUBW
-
- case OSUB_ | gc.TINT32,
- OSUB_ | gc.TUINT32,
- OSUB_ | gc.TPTR32:
- a = x86.ASUBL
-
- case OINC_ | gc.TINT8,
- OINC_ | gc.TUINT8:
- a = x86.AINCB
-
- case OINC_ | gc.TINT16,
- OINC_ | gc.TUINT16:
- a = x86.AINCW
-
- case OINC_ | gc.TINT32,
- OINC_ | gc.TUINT32,
- OINC_ | gc.TPTR32:
- a = x86.AINCL
-
- case ODEC_ | gc.TINT8,
- ODEC_ | gc.TUINT8:
- a = x86.ADECB
-
- case ODEC_ | gc.TINT16,
- ODEC_ | gc.TUINT16:
- a = x86.ADECW
-
- case ODEC_ | gc.TINT32,
- ODEC_ | gc.TUINT32,
- ODEC_ | gc.TPTR32:
- a = x86.ADECL
-
- case OCOM_ | gc.TINT8,
- OCOM_ | gc.TUINT8:
- a = x86.ANOTB
-
- case OCOM_ | gc.TINT16,
- OCOM_ | gc.TUINT16:
- a = x86.ANOTW
-
- case OCOM_ | gc.TINT32,
- OCOM_ | gc.TUINT32,
- OCOM_ | gc.TPTR32:
- a = x86.ANOTL
-
- case OMINUS_ | gc.TINT8,
- OMINUS_ | gc.TUINT8:
- a = x86.ANEGB
-
- case OMINUS_ | gc.TINT16,
- OMINUS_ | gc.TUINT16:
- a = x86.ANEGW
-
- case OMINUS_ | gc.TINT32,
- OMINUS_ | gc.TUINT32,
- OMINUS_ | gc.TPTR32:
- a = x86.ANEGL
-
- case OAND_ | gc.TINT8,
- OAND_ | gc.TUINT8:
- a = x86.AANDB
-
- case OAND_ | gc.TINT16,
- OAND_ | gc.TUINT16:
- a = x86.AANDW
-
- case OAND_ | gc.TINT32,
- OAND_ | gc.TUINT32,
- OAND_ | gc.TPTR32:
- a = x86.AANDL
-
- case OOR_ | gc.TINT8,
- OOR_ | gc.TUINT8:
- a = x86.AORB
-
- case OOR_ | gc.TINT16,
- OOR_ | gc.TUINT16:
- a = x86.AORW
-
- case OOR_ | gc.TINT32,
- OOR_ | gc.TUINT32,
- OOR_ | gc.TPTR32:
- a = x86.AORL
-
- case OXOR_ | gc.TINT8,
- OXOR_ | gc.TUINT8:
- a = x86.AXORB
-
- case OXOR_ | gc.TINT16,
- OXOR_ | gc.TUINT16:
- a = x86.AXORW
-
- case OXOR_ | gc.TINT32,
- OXOR_ | gc.TUINT32,
- OXOR_ | gc.TPTR32:
- a = x86.AXORL
-
- case OLROT_ | gc.TINT8,
- OLROT_ | gc.TUINT8:
- a = x86.AROLB
-
- case OLROT_ | gc.TINT16,
- OLROT_ | gc.TUINT16:
- a = x86.AROLW
-
- case OLROT_ | gc.TINT32,
- OLROT_ | gc.TUINT32,
- OLROT_ | gc.TPTR32:
- a = x86.AROLL
-
- case OLSH_ | gc.TINT8,
- OLSH_ | gc.TUINT8:
- a = x86.ASHLB
-
- case OLSH_ | gc.TINT16,
- OLSH_ | gc.TUINT16:
- a = x86.ASHLW
-
- case OLSH_ | gc.TINT32,
- OLSH_ | gc.TUINT32,
- OLSH_ | gc.TPTR32:
- a = x86.ASHLL
-
- case ORSH_ | gc.TUINT8:
- a = x86.ASHRB
-
- case ORSH_ | gc.TUINT16:
- a = x86.ASHRW
-
- case ORSH_ | gc.TUINT32,
- ORSH_ | gc.TPTR32:
- a = x86.ASHRL
-
- case ORSH_ | gc.TINT8:
- a = x86.ASARB
-
- case ORSH_ | gc.TINT16:
- a = x86.ASARW
-
- case ORSH_ | gc.TINT32:
- a = x86.ASARL
-
- case OHMUL_ | gc.TINT8,
- OMUL_ | gc.TINT8,
- OMUL_ | gc.TUINT8:
- a = x86.AIMULB
-
- case OHMUL_ | gc.TINT16,
- OMUL_ | gc.TINT16,
- OMUL_ | gc.TUINT16:
- a = x86.AIMULW
-
- case OHMUL_ | gc.TINT32,
- OMUL_ | gc.TINT32,
- OMUL_ | gc.TUINT32,
- OMUL_ | gc.TPTR32:
- a = x86.AIMULL
-
- case OHMUL_ | gc.TUINT8:
- a = x86.AMULB
-
- case OHMUL_ | gc.TUINT16:
- a = x86.AMULW
-
- case OHMUL_ | gc.TUINT32,
- OHMUL_ | gc.TPTR32:
- a = x86.AMULL
-
- case ODIV_ | gc.TINT8,
- OMOD_ | gc.TINT8:
- a = x86.AIDIVB
-
- case ODIV_ | gc.TUINT8,
- OMOD_ | gc.TUINT8:
- a = x86.ADIVB
-
- case ODIV_ | gc.TINT16,
- OMOD_ | gc.TINT16:
- a = x86.AIDIVW
-
- case ODIV_ | gc.TUINT16,
- OMOD_ | gc.TUINT16:
- a = x86.ADIVW
-
- case ODIV_ | gc.TINT32,
- OMOD_ | gc.TINT32:
- a = x86.AIDIVL
-
- case ODIV_ | gc.TUINT32,
- ODIV_ | gc.TPTR32,
- OMOD_ | gc.TUINT32,
- OMOD_ | gc.TPTR32:
- a = x86.ADIVL
-
- case OEXTEND_ | gc.TINT16:
- a = x86.ACWD
-
- case OEXTEND_ | gc.TINT32:
- a = x86.ACDQ
- }
-
- return a
-}
-
-func foptoas(op gc.Op, t *gc.Type, flg int) obj.As {
- a := obj.AXXX
- et := gc.Simtype[t.Etype]
-
- // avoid constant conversions in switches below
- const (
- OCMP_ = uint32(gc.OCMP) << 16
- OAS_ = uint32(gc.OAS) << 16
- OADD_ = uint32(gc.OADD) << 16
- OSUB_ = uint32(gc.OSUB) << 16
- OMUL_ = uint32(gc.OMUL) << 16
- ODIV_ = uint32(gc.ODIV) << 16
- OMINUS_ = uint32(gc.OMINUS) << 16
- )
-
- if !gc.Thearch.Use387 {
- switch uint32(op)<<16 | uint32(et) {
- default:
- gc.Fatalf("foptoas-sse: no entry %v-%v", op, t)
-
- case OCMP_ | gc.TFLOAT32:
- a = x86.AUCOMISS
-
- case OCMP_ | gc.TFLOAT64:
- a = x86.AUCOMISD
-
- case OAS_ | gc.TFLOAT32:
- a = x86.AMOVSS
-
- case OAS_ | gc.TFLOAT64:
- a = x86.AMOVSD
-
- case OADD_ | gc.TFLOAT32:
- a = x86.AADDSS
-
- case OADD_ | gc.TFLOAT64:
- a = x86.AADDSD
-
- case OSUB_ | gc.TFLOAT32:
- a = x86.ASUBSS
-
- case OSUB_ | gc.TFLOAT64:
- a = x86.ASUBSD
-
- case OMUL_ | gc.TFLOAT32:
- a = x86.AMULSS
-
- case OMUL_ | gc.TFLOAT64:
- a = x86.AMULSD
-
- case ODIV_ | gc.TFLOAT32:
- a = x86.ADIVSS
-
- case ODIV_ | gc.TFLOAT64:
- a = x86.ADIVSD
- }
-
- return a
- }
-
- // If we need Fpop, it means we're working on
- // two different floating-point registers, not memory.
- // There the instruction only has a float64 form.
- if flg&Fpop != 0 {
- et = gc.TFLOAT64
- }
-
- // clear Frev if unneeded
- switch op {
- case gc.OADD,
- gc.OMUL:
- flg &^= Frev
- }
-
- switch uint32(op)<<16 | (uint32(et)<<8 | uint32(flg)) {
- case OADD_ | (gc.TFLOAT32<<8 | 0):
- return x86.AFADDF
-
- case OADD_ | (gc.TFLOAT64<<8 | 0):
- return x86.AFADDD
-
- case OADD_ | (gc.TFLOAT64<<8 | Fpop):
- return x86.AFADDDP
-
- case OSUB_ | (gc.TFLOAT32<<8 | 0):
- return x86.AFSUBF
-
- case OSUB_ | (gc.TFLOAT32<<8 | Frev):
- return x86.AFSUBRF
-
- case OSUB_ | (gc.TFLOAT64<<8 | 0):
- return x86.AFSUBD
-
- case OSUB_ | (gc.TFLOAT64<<8 | Frev):
- return x86.AFSUBRD
-
- case OSUB_ | (gc.TFLOAT64<<8 | Fpop):
- return x86.AFSUBDP
-
- case OSUB_ | (gc.TFLOAT64<<8 | (Fpop | Frev)):
- return x86.AFSUBRDP
-
- case OMUL_ | (gc.TFLOAT32<<8 | 0):
- return x86.AFMULF
-
- case OMUL_ | (gc.TFLOAT64<<8 | 0):
- return x86.AFMULD
-
- case OMUL_ | (gc.TFLOAT64<<8 | Fpop):
- return x86.AFMULDP
-
- case ODIV_ | (gc.TFLOAT32<<8 | 0):
- return x86.AFDIVF
-
- case ODIV_ | (gc.TFLOAT32<<8 | Frev):
- return x86.AFDIVRF
-
- case ODIV_ | (gc.TFLOAT64<<8 | 0):
- return x86.AFDIVD
-
- case ODIV_ | (gc.TFLOAT64<<8 | Frev):
- return x86.AFDIVRD
-
- case ODIV_ | (gc.TFLOAT64<<8 | Fpop):
- return x86.AFDIVDP
-
- case ODIV_ | (gc.TFLOAT64<<8 | (Fpop | Frev)):
- return x86.AFDIVRDP
-
- case OCMP_ | (gc.TFLOAT32<<8 | 0):
- return x86.AFCOMF
-
- case OCMP_ | (gc.TFLOAT32<<8 | Fpop):
- return x86.AFCOMFP
-
- case OCMP_ | (gc.TFLOAT64<<8 | 0):
- return x86.AFCOMD
-
- case OCMP_ | (gc.TFLOAT64<<8 | Fpop):
- return x86.AFCOMDP
-
- case OCMP_ | (gc.TFLOAT64<<8 | Fpop2):
- return x86.AFCOMDPP
-
- case OMINUS_ | (gc.TFLOAT32<<8 | 0):
- return x86.AFCHS
-
- case OMINUS_ | (gc.TFLOAT64<<8 | 0):
- return x86.AFCHS
- }
-
- gc.Fatalf("foptoas %v %v %#x", op, t, flg)
- return 0
-}
-
-var resvd = []int{
- // REG_DI, // for movstring
- // REG_SI, // for movstring
-
- x86.REG_AX, // for divide
- x86.REG_CX, // for shift
- x86.REG_DX, // for divide, context
- x86.REG_SP, // for stack
-}
-
-/*
- * generate
- * as $c, reg
- */
-func gconreg(as obj.As, c int64, reg int) {
- var n1 gc.Node
- var n2 gc.Node
-
- gc.Nodconst(&n1, gc.Types[gc.TINT64], c)
- gc.Nodreg(&n2, gc.Types[gc.TINT64], reg)
- gins(as, &n1, &n2)
-}
-
-/*
- * generate
- * as $c, n
- */
-func ginscon(as obj.As, c int64, n2 *gc.Node) {
- var n1 gc.Node
- gc.Nodconst(&n1, gc.Types[gc.TINT32], c)
- gins(as, &n1, n2)
-}
-
-func ginscmp(op gc.Op, t *gc.Type, n1, n2 *gc.Node, likely int) *obj.Prog {
- if t.IsInteger() || t.Etype == gc.Tptr {
- if (n1.Op == gc.OLITERAL || n1.Op == gc.OADDR && n1.Left.Op == gc.ONAME) && n2.Op != gc.OLITERAL {
- // Reverse comparison to place constant (including address constant) last.
- op = gc.Brrev(op)
- n1, n2 = n2, n1
- }
- }
-
- // General case.
- var r1, r2, g1, g2 gc.Node
-
- // A special case to make write barriers more efficient.
- // Comparing the first field of a named struct can be done directly.
- base := n1
- if n1.Op == gc.ODOT && n1.Left.Type.IsStruct() && n1.Left.Type.Field(0).Sym == n1.Sym {
- base = n1.Left
- }
-
- if base.Op == gc.ONAME && base.Class != gc.PAUTOHEAP || n1.Op == gc.OINDREG {
- r1 = *n1
- } else {
- gc.Regalloc(&r1, t, n1)
- gc.Regalloc(&g1, n1.Type, &r1)
- gc.Cgen(n1, &g1)
- gmove(&g1, &r1)
- }
- if n2.Op == gc.OLITERAL && t.IsInteger() || n2.Op == gc.OADDR && n2.Left.Op == gc.ONAME && n2.Left.Class == gc.PEXTERN {
- r2 = *n2
- } else {
- gc.Regalloc(&r2, t, n2)
- gc.Regalloc(&g2, n1.Type, &r2)
- gc.Cgen(n2, &g2)
- gmove(&g2, &r2)
- }
- gins(optoas(gc.OCMP, t), &r1, &r2)
- if r1.Op == gc.OREGISTER {
- gc.Regfree(&g1)
- gc.Regfree(&r1)
- }
- if r2.Op == gc.OREGISTER {
- gc.Regfree(&g2)
- gc.Regfree(&r2)
- }
- return gc.Gbranch(optoas(op, t), nil, likely)
-}
-
-/*
- * swap node contents
- */
-func nswap(a *gc.Node, b *gc.Node) {
- t := *a
- *a = *b
- *b = t
-}
-
-/*
- * return constant i node.
- * overwritten by next call, but useful in calls to gins.
- */
-
-var ncon_n gc.Node
-
-func ncon(i uint32) *gc.Node {
- if ncon_n.Type == nil {
- gc.Nodconst(&ncon_n, gc.Types[gc.TUINT32], 0)
- }
- ncon_n.SetInt(int64(i))
- return &ncon_n
-}
-
-var sclean [10]gc.Node
-
-var nsclean int
-
-/*
- * n is a 64-bit value. fill in lo and hi to refer to its 32-bit halves.
- */
-func split64(n *gc.Node, lo *gc.Node, hi *gc.Node) {
- if !gc.Is64(n.Type) {
- gc.Fatalf("split64 %v", n.Type)
- }
-
- if nsclean >= len(sclean) {
- gc.Fatalf("split64 clean")
- }
- sclean[nsclean].Op = gc.OEMPTY
- nsclean++
- switch n.Op {
- default:
- switch n.Op {
- default:
- var n1 gc.Node
- if !dotaddable(n, &n1) {
- gc.Igen(n, &n1, nil)
- sclean[nsclean-1] = n1
- }
-
- n = &n1
-
- case gc.ONAME, gc.OINDREG:
- // nothing
- }
-
- *lo = *n
- *hi = *n
- lo.Type = gc.Types[gc.TUINT32]
- if n.Type.Etype == gc.TINT64 {
- hi.Type = gc.Types[gc.TINT32]
- } else {
- hi.Type = gc.Types[gc.TUINT32]
- }
- hi.Xoffset += 4
-
- case gc.OLITERAL:
- var n1 gc.Node
- n.Convconst(&n1, n.Type)
- i := n1.Int64()
- gc.Nodconst(lo, gc.Types[gc.TUINT32], int64(uint32(i)))
- i >>= 32
- if n.Type.Etype == gc.TINT64 {
- gc.Nodconst(hi, gc.Types[gc.TINT32], int64(int32(i)))
- } else {
- gc.Nodconst(hi, gc.Types[gc.TUINT32], int64(uint32(i)))
- }
- }
-}
-
-func splitclean() {
- if nsclean <= 0 {
- gc.Fatalf("splitclean")
- }
- nsclean--
- if sclean[nsclean].Op != gc.OEMPTY {
- gc.Regfree(&sclean[nsclean])
- }
-}
-
-// set up nodes representing fp constants
-var (
- zerof gc.Node
- two63f gc.Node
- two64f gc.Node
- bignodes_did bool
-)
-
-func bignodes() {
- if bignodes_did {
- return
- }
- bignodes_did = true
-
- gc.Nodconst(&zerof, gc.Types[gc.TINT64], 0)
- zerof.Convconst(&zerof, gc.Types[gc.TFLOAT64])
-
- var i big.Int
- i.SetInt64(1)
- i.Lsh(&i, 63)
- var bigi gc.Node
-
- gc.Nodconst(&bigi, gc.Types[gc.TUINT64], 0)
- bigi.SetBigInt(&i)
- bigi.Convconst(&two63f, gc.Types[gc.TFLOAT64])
-
- gc.Nodconst(&bigi, gc.Types[gc.TUINT64], 0)
- i.Lsh(&i, 1)
- bigi.SetBigInt(&i)
- bigi.Convconst(&two64f, gc.Types[gc.TFLOAT64])
-}
-
-func memname(n *gc.Node, t *gc.Type) {
- gc.Tempname(n, t)
- n.Sym = gc.Lookup("." + n.Sym.Name[1:]) // keep optimizer from registerizing
- n.Orig.Sym = n.Sym
-}
-
-func gmove(f *gc.Node, t *gc.Node) {
- if gc.Debug['M'] != 0 {
- fmt.Printf("gmove %v -> %v\n", f, t)
- }
-
- ft := gc.Simsimtype(f.Type)
- tt := gc.Simsimtype(t.Type)
- cvt := t.Type
-
- if gc.Iscomplex[ft] || gc.Iscomplex[tt] {
- gc.Complexmove(f, t)
- return
- }
-
- if gc.Isfloat[ft] || gc.Isfloat[tt] {
- floatmove(f, t)
- return
- }
-
- // cannot have two integer memory operands;
- // except 64-bit, which always copies via registers anyway.
- var r1 gc.Node
- var a obj.As
- if gc.Isint[ft] && gc.Isint[tt] && !gc.Is64(f.Type) && !gc.Is64(t.Type) && gc.Ismem(f) && gc.Ismem(t) {
- goto hard
- }
-
- // convert constant to desired type
- if f.Op == gc.OLITERAL {
- var con gc.Node
- f.Convconst(&con, t.Type)
- f = &con
- ft = gc.Simsimtype(con.Type)
- }
-
- // value -> value copy, only one memory operand.
- // figure out the instruction to use.
- // break out of switch for one-instruction gins.
- // goto rdst for "destination must be register".
- // goto hard for "convert to cvt type first".
- // otherwise handle and return.
-
- switch uint32(ft)<<16 | uint32(tt) {
- default:
- // should not happen
- gc.Fatalf("gmove %v -> %v", f, t)
- return
-
- /*
- * integer copy and truncate
- */
- case gc.TINT8<<16 | gc.TINT8, // same size
- gc.TINT8<<16 | gc.TUINT8,
- gc.TUINT8<<16 | gc.TINT8,
- gc.TUINT8<<16 | gc.TUINT8:
- a = x86.AMOVB
-
- case gc.TINT16<<16 | gc.TINT8, // truncate
- gc.TUINT16<<16 | gc.TINT8,
- gc.TINT32<<16 | gc.TINT8,
- gc.TUINT32<<16 | gc.TINT8,
- gc.TINT16<<16 | gc.TUINT8,
- gc.TUINT16<<16 | gc.TUINT8,
- gc.TINT32<<16 | gc.TUINT8,
- gc.TUINT32<<16 | gc.TUINT8:
- a = x86.AMOVB
-
- goto rsrc
-
- case gc.TINT64<<16 | gc.TINT8, // truncate low word
- gc.TUINT64<<16 | gc.TINT8,
- gc.TINT64<<16 | gc.TUINT8,
- gc.TUINT64<<16 | gc.TUINT8:
- var flo gc.Node
- var fhi gc.Node
- split64(f, &flo, &fhi)
-
- var r1 gc.Node
- gc.Nodreg(&r1, t.Type, x86.REG_AX)
- gmove(&flo, &r1)
- gins(x86.AMOVB, &r1, t)
- splitclean()
- return
-
- case gc.TINT16<<16 | gc.TINT16, // same size
- gc.TINT16<<16 | gc.TUINT16,
- gc.TUINT16<<16 | gc.TINT16,
- gc.TUINT16<<16 | gc.TUINT16:
- a = x86.AMOVW
-
- case gc.TINT32<<16 | gc.TINT16, // truncate
- gc.TUINT32<<16 | gc.TINT16,
- gc.TINT32<<16 | gc.TUINT16,
- gc.TUINT32<<16 | gc.TUINT16:
- a = x86.AMOVW
-
- goto rsrc
-
- case gc.TINT64<<16 | gc.TINT16, // truncate low word
- gc.TUINT64<<16 | gc.TINT16,
- gc.TINT64<<16 | gc.TUINT16,
- gc.TUINT64<<16 | gc.TUINT16:
- var flo gc.Node
- var fhi gc.Node
- split64(f, &flo, &fhi)
-
- var r1 gc.Node
- gc.Nodreg(&r1, t.Type, x86.REG_AX)
- gmove(&flo, &r1)
- gins(x86.AMOVW, &r1, t)
- splitclean()
- return
-
- case gc.TINT32<<16 | gc.TINT32, // same size
- gc.TINT32<<16 | gc.TUINT32,
- gc.TUINT32<<16 | gc.TINT32,
- gc.TUINT32<<16 | gc.TUINT32:
- a = x86.AMOVL
-
- case gc.TINT64<<16 | gc.TINT32, // truncate
- gc.TUINT64<<16 | gc.TINT32,
- gc.TINT64<<16 | gc.TUINT32,
- gc.TUINT64<<16 | gc.TUINT32:
- var fhi gc.Node
- var flo gc.Node
- split64(f, &flo, &fhi)
-
- var r1 gc.Node
- gc.Nodreg(&r1, t.Type, x86.REG_AX)
- gmove(&flo, &r1)
- gins(x86.AMOVL, &r1, t)
- splitclean()
- return
-
- case gc.TINT64<<16 | gc.TINT64, // same size
- gc.TINT64<<16 | gc.TUINT64,
- gc.TUINT64<<16 | gc.TINT64,
- gc.TUINT64<<16 | gc.TUINT64:
- var fhi gc.Node
- var flo gc.Node
- split64(f, &flo, &fhi)
-
- var tlo gc.Node
- var thi gc.Node
- split64(t, &tlo, &thi)
- if f.Op == gc.OLITERAL {
- gins(x86.AMOVL, &flo, &tlo)
- gins(x86.AMOVL, &fhi, &thi)
- } else {
- // Implementation of conversion-free x = y for int64 or uint64 x.
- // This is generated by the code that copies small values out of closures,
- // and that code has DX live, so avoid DX and just use AX twice.
- var r1 gc.Node
- gc.Nodreg(&r1, gc.Types[gc.TUINT32], x86.REG_AX)
- gins(x86.AMOVL, &flo, &r1)
- gins(x86.AMOVL, &r1, &tlo)
- gins(x86.AMOVL, &fhi, &r1)
- gins(x86.AMOVL, &r1, &thi)
- }
-
- splitclean()
- splitclean()
- return
-
- /*
- * integer up-conversions
- */
- case gc.TINT8<<16 | gc.TINT16, // sign extend int8
- gc.TINT8<<16 | gc.TUINT16:
- a = x86.AMOVBWSX
-
- goto rdst
-
- case gc.TINT8<<16 | gc.TINT32,
- gc.TINT8<<16 | gc.TUINT32:
- a = x86.AMOVBLSX
- goto rdst
-
- case gc.TINT8<<16 | gc.TINT64, // convert via int32
- gc.TINT8<<16 | gc.TUINT64:
- cvt = gc.Types[gc.TINT32]
-
- goto hard
-
- case gc.TUINT8<<16 | gc.TINT16, // zero extend uint8
- gc.TUINT8<<16 | gc.TUINT16:
- a = x86.AMOVBWZX
-
- goto rdst
-
- case gc.TUINT8<<16 | gc.TINT32,
- gc.TUINT8<<16 | gc.TUINT32:
- a = x86.AMOVBLZX
- goto rdst
-
- case gc.TUINT8<<16 | gc.TINT64, // convert via uint32
- gc.TUINT8<<16 | gc.TUINT64:
- cvt = gc.Types[gc.TUINT32]
-
- goto hard
-
- case gc.TINT16<<16 | gc.TINT32, // sign extend int16
- gc.TINT16<<16 | gc.TUINT32:
- a = x86.AMOVWLSX
-
- goto rdst
-
- case gc.TINT16<<16 | gc.TINT64, // convert via int32
- gc.TINT16<<16 | gc.TUINT64:
- cvt = gc.Types[gc.TINT32]
-
- goto hard
-
- case gc.TUINT16<<16 | gc.TINT32, // zero extend uint16
- gc.TUINT16<<16 | gc.TUINT32:
- a = x86.AMOVWLZX
-
- goto rdst
-
- case gc.TUINT16<<16 | gc.TINT64, // convert via uint32
- gc.TUINT16<<16 | gc.TUINT64:
- cvt = gc.Types[gc.TUINT32]
-
- goto hard
-
- case gc.TINT32<<16 | gc.TINT64, // sign extend int32
- gc.TINT32<<16 | gc.TUINT64:
- var thi gc.Node
- var tlo gc.Node
- split64(t, &tlo, &thi)
-
- var flo gc.Node
- gc.Nodreg(&flo, tlo.Type, x86.REG_AX)
- var fhi gc.Node
- gc.Nodreg(&fhi, thi.Type, x86.REG_DX)
- gmove(f, &flo)
- gins(x86.ACDQ, nil, nil)
- gins(x86.AMOVL, &flo, &tlo)
- gins(x86.AMOVL, &fhi, &thi)
- splitclean()
- return
-
- case gc.TUINT32<<16 | gc.TINT64, // zero extend uint32
- gc.TUINT32<<16 | gc.TUINT64:
- var tlo gc.Node
- var thi gc.Node
- split64(t, &tlo, &thi)
-
- gmove(f, &tlo)
- gins(x86.AMOVL, ncon(0), &thi)
- splitclean()
- return
- }
-
- gins(a, f, t)
- return
-
- // requires register source
-rsrc:
- gc.Regalloc(&r1, f.Type, t)
-
- gmove(f, &r1)
- gins(a, &r1, t)
- gc.Regfree(&r1)
- return
-
- // requires register destination
-rdst:
- {
- gc.Regalloc(&r1, t.Type, t)
-
- gins(a, f, &r1)
- gmove(&r1, t)
- gc.Regfree(&r1)
- return
- }
-
- // requires register intermediate
-hard:
- gc.Regalloc(&r1, cvt, t)
-
- gmove(f, &r1)
- gmove(&r1, t)
- gc.Regfree(&r1)
- return
-}
-
-func floatmove(f *gc.Node, t *gc.Node) {
- var r1 gc.Node
-
- ft := gc.Simsimtype(f.Type)
- tt := gc.Simsimtype(t.Type)
- cvt := t.Type
-
- // cannot have two floating point memory operands.
- if gc.Isfloat[ft] && gc.Isfloat[tt] && gc.Ismem(f) && gc.Ismem(t) {
- goto hard
- }
-
- // convert constant to desired type
- if f.Op == gc.OLITERAL {
- var con gc.Node
- f.Convconst(&con, t.Type)
- f = &con
- ft = gc.Simsimtype(con.Type)
-
- // some constants can't move directly to memory.
- if gc.Ismem(t) {
- // float constants come from memory.
- if gc.Isfloat[tt] {
- goto hard
- }
- }
- }
-
- // value -> value copy, only one memory operand.
- // figure out the instruction to use.
- // break out of switch for one-instruction gins.
- // goto rdst for "destination must be register".
- // goto hard for "convert to cvt type first".
- // otherwise handle and return.
-
- switch uint32(ft)<<16 | uint32(tt) {
- default:
- if gc.Thearch.Use387 {
- floatmove_387(f, t)
- } else {
- floatmove_sse(f, t)
- }
- return
-
- // float to very long integer.
- case gc.TFLOAT32<<16 | gc.TINT64,
- gc.TFLOAT64<<16 | gc.TINT64:
- if f.Op == gc.OREGISTER {
- cvt = f.Type
- goto hardmem
- }
-
- var r1 gc.Node
- gc.Nodreg(&r1, gc.Types[ft], x86.REG_F0)
- if ft == gc.TFLOAT32 {
- gins(x86.AFMOVF, f, &r1)
- } else {
- gins(x86.AFMOVD, f, &r1)
- }
-
- // set round to zero mode during conversion
- var t1 gc.Node
- memname(&t1, gc.Types[gc.TUINT16])
-
- var t2 gc.Node
- memname(&t2, gc.Types[gc.TUINT16])
- gins(x86.AFSTCW, nil, &t1)
- gins(x86.AMOVW, ncon(0xf7f), &t2)
- gins(x86.AFLDCW, &t2, nil)
- if tt == gc.TINT16 {
- gins(x86.AFMOVWP, &r1, t)
- } else if tt == gc.TINT32 {
- gins(x86.AFMOVLP, &r1, t)
- } else {
- gins(x86.AFMOVVP, &r1, t)
- }
- gins(x86.AFLDCW, &t1, nil)
- return
-
- case gc.TFLOAT32<<16 | gc.TUINT64,
- gc.TFLOAT64<<16 | gc.TUINT64:
- if !gc.Ismem(f) {
- cvt = f.Type
- goto hardmem
- }
-
- bignodes()
- var f0 gc.Node
- gc.Nodreg(&f0, gc.Types[ft], x86.REG_F0)
- var f1 gc.Node
- gc.Nodreg(&f1, gc.Types[ft], x86.REG_F0+1)
- var ax gc.Node
- gc.Nodreg(&ax, gc.Types[gc.TUINT16], x86.REG_AX)
-
- if ft == gc.TFLOAT32 {
- gins(x86.AFMOVF, f, &f0)
- } else {
- gins(x86.AFMOVD, f, &f0)
- }
-
- // if 0 > v { answer = 0 }
- gins(x86.AFMOVD, &zerof, &f0)
- gins(x86.AFUCOMP, &f0, &f1)
- gins(x86.AFSTSW, nil, &ax)
- gins(x86.ASAHF, nil, nil)
- p1 := gc.Gbranch(optoas(gc.OGT, gc.Types[tt]), nil, 0)
-
- // if 1<<64 <= v { answer = 0 too }
- gins(x86.AFMOVD, &two64f, &f0)
-
- gins(x86.AFUCOMP, &f0, &f1)
- gins(x86.AFSTSW, nil, &ax)
- gins(x86.ASAHF, nil, nil)
- p2 := gc.Gbranch(optoas(gc.OGT, gc.Types[tt]), nil, 0)
- gc.Patch(p1, gc.Pc)
- gins(x86.AFMOVVP, &f0, t) // don't care about t, but will pop the stack
- var thi gc.Node
- var tlo gc.Node
- split64(t, &tlo, &thi)
- gins(x86.AMOVL, ncon(0), &tlo)
- gins(x86.AMOVL, ncon(0), &thi)
- splitclean()
- p1 = gc.Gbranch(obj.AJMP, nil, 0)
- gc.Patch(p2, gc.Pc)
-
- // in range; algorithm is:
- // if small enough, use native float64 -> int64 conversion.
- // otherwise, subtract 2^63, convert, and add it back.
-
- // set round to zero mode during conversion
- var t1 gc.Node
- memname(&t1, gc.Types[gc.TUINT16])
-
- var t2 gc.Node
- memname(&t2, gc.Types[gc.TUINT16])
- gins(x86.AFSTCW, nil, &t1)
- gins(x86.AMOVW, ncon(0xf7f), &t2)
- gins(x86.AFLDCW, &t2, nil)
-
- // actual work
- gins(x86.AFMOVD, &two63f, &f0)
-
- gins(x86.AFUCOMP, &f0, &f1)
- gins(x86.AFSTSW, nil, &ax)
- gins(x86.ASAHF, nil, nil)
- p2 = gc.Gbranch(optoas(gc.OLE, gc.Types[tt]), nil, 0)
- gins(x86.AFMOVVP, &f0, t)
- p3 := gc.Gbranch(obj.AJMP, nil, 0)
- gc.Patch(p2, gc.Pc)
- gins(x86.AFMOVD, &two63f, &f0)
- gins(x86.AFSUBDP, &f0, &f1)
- gins(x86.AFMOVVP, &f0, t)
- split64(t, &tlo, &thi)
- gins(x86.AXORL, ncon(0x80000000), &thi) // + 2^63
- gc.Patch(p3, gc.Pc)
- splitclean()
-
- // restore rounding mode
- gins(x86.AFLDCW, &t1, nil)
-
- gc.Patch(p1, gc.Pc)
- return
-
- /*
- * integer to float
- */
- case gc.TINT64<<16 | gc.TFLOAT32,
- gc.TINT64<<16 | gc.TFLOAT64:
- if t.Op == gc.OREGISTER {
- goto hardmem
- }
- var f0 gc.Node
- gc.Nodreg(&f0, t.Type, x86.REG_F0)
- gins(x86.AFMOVV, f, &f0)
- if tt == gc.TFLOAT32 {
- gins(x86.AFMOVFP, &f0, t)
- } else {
- gins(x86.AFMOVDP, &f0, t)
- }
- return
-
- // algorithm is:
- // if small enough, use native int64 -> float64 conversion.
- // otherwise, halve (rounding to odd?), convert, and double.
- case gc.TUINT64<<16 | gc.TFLOAT32,
- gc.TUINT64<<16 | gc.TFLOAT64:
- var ax gc.Node
- gc.Nodreg(&ax, gc.Types[gc.TUINT32], x86.REG_AX)
-
- var dx gc.Node
- gc.Nodreg(&dx, gc.Types[gc.TUINT32], x86.REG_DX)
- var cx gc.Node
- gc.Nodreg(&cx, gc.Types[gc.TUINT32], x86.REG_CX)
- var t1 gc.Node
- gc.Tempname(&t1, f.Type)
- var tlo gc.Node
- var thi gc.Node
- split64(&t1, &tlo, &thi)
- gmove(f, &t1)
- gins(x86.ACMPL, &thi, ncon(0))
- p1 := gc.Gbranch(x86.AJLT, nil, 0)
-
- // native
- var r1 gc.Node
- gc.Nodreg(&r1, gc.Types[tt], x86.REG_F0)
-
- gins(x86.AFMOVV, &t1, &r1)
- if tt == gc.TFLOAT32 {
- gins(x86.AFMOVFP, &r1, t)
- } else {
- gins(x86.AFMOVDP, &r1, t)
- }
- p2 := gc.Gbranch(obj.AJMP, nil, 0)
-
- // simulated
- gc.Patch(p1, gc.Pc)
-
- gmove(&tlo, &ax)
- gmove(&thi, &dx)
- p1 = gins(x86.ASHRL, ncon(1), &ax)
- p1.From.Index = x86.REG_DX // double-width shift DX -> AX
- p1.From.Scale = 0
- gins(x86.AMOVL, ncon(0), &cx)
- gins(x86.ASETCC, nil, &cx)
- gins(x86.AORL, &cx, &ax)
- gins(x86.ASHRL, ncon(1), &dx)
- gmove(&dx, &thi)
- gmove(&ax, &tlo)
- gc.Nodreg(&r1, gc.Types[tt], x86.REG_F0)
- var r2 gc.Node
- gc.Nodreg(&r2, gc.Types[tt], x86.REG_F0+1)
- gins(x86.AFMOVV, &t1, &r1)
- gins(x86.AFMOVD, &r1, &r1)
- gins(x86.AFADDDP, &r1, &r2)
- if tt == gc.TFLOAT32 {
- gins(x86.AFMOVFP, &r1, t)
- } else {
- gins(x86.AFMOVDP, &r1, t)
- }
- gc.Patch(p2, gc.Pc)
- splitclean()
- return
- }
-
- // requires register intermediate
-hard:
- gc.Regalloc(&r1, cvt, t)
-
- gmove(f, &r1)
- gmove(&r1, t)
- gc.Regfree(&r1)
- return
-
- // requires memory intermediate
-hardmem:
- gc.Tempname(&r1, cvt)
-
- gmove(f, &r1)
- gmove(&r1, t)
- return
-}
-
-func floatmove_387(f *gc.Node, t *gc.Node) {
- var r1 gc.Node
- var a obj.As
-
- ft := gc.Simsimtype(f.Type)
- tt := gc.Simsimtype(t.Type)
- cvt := t.Type
-
- switch uint32(ft)<<16 | uint32(tt) {
- default:
- goto fatal
-
- /*
- * float to integer
- */
- case gc.TFLOAT32<<16 | gc.TINT16,
- gc.TFLOAT32<<16 | gc.TINT32,
- gc.TFLOAT32<<16 | gc.TINT64,
- gc.TFLOAT64<<16 | gc.TINT16,
- gc.TFLOAT64<<16 | gc.TINT32,
- gc.TFLOAT64<<16 | gc.TINT64:
- if t.Op == gc.OREGISTER {
- goto hardmem
- }
- var r1 gc.Node
- gc.Nodreg(&r1, gc.Types[ft], x86.REG_F0)
- if f.Op != gc.OREGISTER {
- if ft == gc.TFLOAT32 {
- gins(x86.AFMOVF, f, &r1)
- } else {
- gins(x86.AFMOVD, f, &r1)
- }
- }
-
- // set round to zero mode during conversion
- var t1 gc.Node
- memname(&t1, gc.Types[gc.TUINT16])
-
- var t2 gc.Node
- memname(&t2, gc.Types[gc.TUINT16])
- gins(x86.AFSTCW, nil, &t1)
- gins(x86.AMOVW, ncon(0xf7f), &t2)
- gins(x86.AFLDCW, &t2, nil)
- if tt == gc.TINT16 {
- gins(x86.AFMOVWP, &r1, t)
- } else if tt == gc.TINT32 {
- gins(x86.AFMOVLP, &r1, t)
- } else {
- gins(x86.AFMOVVP, &r1, t)
- }
- gins(x86.AFLDCW, &t1, nil)
- return
-
- // convert via int32.
- case gc.TFLOAT32<<16 | gc.TINT8,
- gc.TFLOAT32<<16 | gc.TUINT16,
- gc.TFLOAT32<<16 | gc.TUINT8,
- gc.TFLOAT64<<16 | gc.TINT8,
- gc.TFLOAT64<<16 | gc.TUINT16,
- gc.TFLOAT64<<16 | gc.TUINT8:
- var t1 gc.Node
- gc.Tempname(&t1, gc.Types[gc.TINT32])
-
- gmove(f, &t1)
- switch tt {
- default:
- gc.Fatalf("gmove %v", t)
-
- case gc.TINT8:
- gins(x86.ACMPL, &t1, ncon(-0x80&(1<<32-1)))
- p1 := gc.Gbranch(optoas(gc.OLT, gc.Types[gc.TINT32]), nil, -1)
- gins(x86.ACMPL, &t1, ncon(0x7f))
- p2 := gc.Gbranch(optoas(gc.OGT, gc.Types[gc.TINT32]), nil, -1)
- p3 := gc.Gbranch(obj.AJMP, nil, 0)
- gc.Patch(p1, gc.Pc)
- gc.Patch(p2, gc.Pc)
- gmove(ncon(-0x80&(1<<32-1)), &t1)
- gc.Patch(p3, gc.Pc)
- gmove(&t1, t)
-
- case gc.TUINT8:
- gins(x86.ATESTL, ncon(0xffffff00), &t1)
- p1 := gc.Gbranch(x86.AJEQ, nil, +1)
- gins(x86.AMOVL, ncon(0), &t1)
- gc.Patch(p1, gc.Pc)
- gmove(&t1, t)
-
- case gc.TUINT16:
- gins(x86.ATESTL, ncon(0xffff0000), &t1)
- p1 := gc.Gbranch(x86.AJEQ, nil, +1)
- gins(x86.AMOVL, ncon(0), &t1)
- gc.Patch(p1, gc.Pc)
- gmove(&t1, t)
- }
-
- return
-
- // convert via int64.
- case gc.TFLOAT32<<16 | gc.TUINT32,
- gc.TFLOAT64<<16 | gc.TUINT32:
- cvt = gc.Types[gc.TINT64]
-
- goto hardmem
-
- /*
- * integer to float
- */
- case gc.TINT16<<16 | gc.TFLOAT32,
- gc.TINT16<<16 | gc.TFLOAT64,
- gc.TINT32<<16 | gc.TFLOAT32,
- gc.TINT32<<16 | gc.TFLOAT64,
- gc.TINT64<<16 | gc.TFLOAT32,
- gc.TINT64<<16 | gc.TFLOAT64:
- if t.Op != gc.OREGISTER {
- goto hard
- }
- if f.Op == gc.OREGISTER {
- cvt = f.Type
- goto hardmem
- }
-
- switch ft {
- case gc.TINT16:
- a = x86.AFMOVW
-
- case gc.TINT32:
- a = x86.AFMOVL
-
- default:
- a = x86.AFMOVV
- }
-
- // convert via int32 memory
- case gc.TINT8<<16 | gc.TFLOAT32,
- gc.TINT8<<16 | gc.TFLOAT64,
- gc.TUINT16<<16 | gc.TFLOAT32,
- gc.TUINT16<<16 | gc.TFLOAT64,
- gc.TUINT8<<16 | gc.TFLOAT32,
- gc.TUINT8<<16 | gc.TFLOAT64:
- cvt = gc.Types[gc.TINT32]
-
- goto hardmem
-
- // convert via int64 memory
- case gc.TUINT32<<16 | gc.TFLOAT32,
- gc.TUINT32<<16 | gc.TFLOAT64:
- cvt = gc.Types[gc.TINT64]
-
- goto hardmem
-
- // The way the code generator uses floating-point
- // registers, a move from F0 to F0 is intended as a no-op.
- // On the x86, it's not: it pushes a second copy of F0
- // on the floating point stack. So toss it away here.
- // Also, F0 is the *only* register we ever evaluate
- // into, so we should only see register/register as F0/F0.
- /*
- * float to float
- */
- case gc.TFLOAT32<<16 | gc.TFLOAT32,
- gc.TFLOAT64<<16 | gc.TFLOAT64:
- if gc.Ismem(f) && gc.Ismem(t) {
- goto hard
- }
- if f.Op == gc.OREGISTER && t.Op == gc.OREGISTER {
- if f.Reg != x86.REG_F0 || t.Reg != x86.REG_F0 {
- goto fatal
- }
- return
- }
-
- a = x86.AFMOVF
- if ft == gc.TFLOAT64 {
- a = x86.AFMOVD
- }
- if gc.Ismem(t) {
- if f.Op != gc.OREGISTER || f.Reg != x86.REG_F0 {
- gc.Fatalf("gmove %v", f)
- }
- a = x86.AFMOVFP
- if ft == gc.TFLOAT64 {
- a = x86.AFMOVDP
- }
- }
-
- case gc.TFLOAT32<<16 | gc.TFLOAT64:
- if gc.Ismem(f) && gc.Ismem(t) {
- goto hard
- }
- if f.Op == gc.OREGISTER && t.Op == gc.OREGISTER {
- if f.Reg != x86.REG_F0 || t.Reg != x86.REG_F0 {
- goto fatal
- }
- return
- }
-
- if f.Op == gc.OREGISTER {
- gins(x86.AFMOVDP, f, t)
- } else {
- gins(x86.AFMOVF, f, t)
- }
- return
-
- case gc.TFLOAT64<<16 | gc.TFLOAT32:
- if gc.Ismem(f) && gc.Ismem(t) {
- goto hard
- }
- if f.Op == gc.OREGISTER && t.Op == gc.OREGISTER {
- var r1 gc.Node
- gc.Tempname(&r1, gc.Types[gc.TFLOAT32])
- gins(x86.AFMOVFP, f, &r1)
- gins(x86.AFMOVF, &r1, t)
- return
- }
-
- if f.Op == gc.OREGISTER {
- gins(x86.AFMOVFP, f, t)
- } else {
- gins(x86.AFMOVD, f, t)
- }
- return
- }
-
- gins(a, f, t)
- return
-
- // requires register intermediate
-hard:
- gc.Regalloc(&r1, cvt, t)
-
- gmove(f, &r1)
- gmove(&r1, t)
- gc.Regfree(&r1)
- return
-
- // requires memory intermediate
-hardmem:
- gc.Tempname(&r1, cvt)
-
- gmove(f, &r1)
- gmove(&r1, t)
- return
-
- // should not happen
-fatal:
- gc.Fatalf("gmove %v -> %v", gc.Nconv(f, gc.FmtLong), gc.Nconv(t, gc.FmtLong))
-
- return
-}
-
-func floatmove_sse(f *gc.Node, t *gc.Node) {
- var r1 gc.Node
- var cvt *gc.Type
- var a obj.As
-
- ft := gc.Simsimtype(f.Type)
- tt := gc.Simsimtype(t.Type)
-
- switch uint32(ft)<<16 | uint32(tt) {
- // should not happen
- default:
- gc.Fatalf("gmove %v -> %v", f, t)
-
- return
-
- // convert via int32.
- /*
- * float to integer
- */
- case gc.TFLOAT32<<16 | gc.TINT16,
- gc.TFLOAT32<<16 | gc.TINT8,
- gc.TFLOAT32<<16 | gc.TUINT16,
- gc.TFLOAT32<<16 | gc.TUINT8,
- gc.TFLOAT64<<16 | gc.TINT16,
- gc.TFLOAT64<<16 | gc.TINT8,
- gc.TFLOAT64<<16 | gc.TUINT16,
- gc.TFLOAT64<<16 | gc.TUINT8:
- cvt = gc.Types[gc.TINT32]
-
- goto hard
-
- // convert via int64.
- case gc.TFLOAT32<<16 | gc.TUINT32,
- gc.TFLOAT64<<16 | gc.TUINT32:
- cvt = gc.Types[gc.TINT64]
-
- goto hardmem
-
- case gc.TFLOAT32<<16 | gc.TINT32:
- a = x86.ACVTTSS2SL
- goto rdst
-
- case gc.TFLOAT64<<16 | gc.TINT32:
- a = x86.ACVTTSD2SL
- goto rdst
-
- // convert via int32 memory
- /*
- * integer to float
- */
- case gc.TINT8<<16 | gc.TFLOAT32,
- gc.TINT8<<16 | gc.TFLOAT64,
- gc.TINT16<<16 | gc.TFLOAT32,
- gc.TINT16<<16 | gc.TFLOAT64,
- gc.TUINT16<<16 | gc.TFLOAT32,
- gc.TUINT16<<16 | gc.TFLOAT64,
- gc.TUINT8<<16 | gc.TFLOAT32,
- gc.TUINT8<<16 | gc.TFLOAT64:
- cvt = gc.Types[gc.TINT32]
-
- goto hard
-
- // convert via int64 memory
- case gc.TUINT32<<16 | gc.TFLOAT32,
- gc.TUINT32<<16 | gc.TFLOAT64:
- cvt = gc.Types[gc.TINT64]
-
- goto hardmem
-
- case gc.TINT32<<16 | gc.TFLOAT32:
- a = x86.ACVTSL2SS
- goto rdst
-
- case gc.TINT32<<16 | gc.TFLOAT64:
- a = x86.ACVTSL2SD
- goto rdst
-
- /*
- * float to float
- */
- case gc.TFLOAT32<<16 | gc.TFLOAT32:
- a = x86.AMOVSS
-
- case gc.TFLOAT64<<16 | gc.TFLOAT64:
- a = x86.AMOVSD
-
- case gc.TFLOAT32<<16 | gc.TFLOAT64:
- a = x86.ACVTSS2SD
- goto rdst
-
- case gc.TFLOAT64<<16 | gc.TFLOAT32:
- a = x86.ACVTSD2SS
- goto rdst
- }
-
- gins(a, f, t)
- return
-
- // requires register intermediate
-hard:
- gc.Regalloc(&r1, cvt, t)
-
- gmove(f, &r1)
- gmove(&r1, t)
- gc.Regfree(&r1)
- return
-
- // requires memory intermediate
-hardmem:
- gc.Tempname(&r1, cvt)
-
- gmove(f, &r1)
- gmove(&r1, t)
- return
-
- // requires register destination
-rdst:
- gc.Regalloc(&r1, t.Type, t)
-
- gins(a, f, &r1)
- gmove(&r1, t)
- gc.Regfree(&r1)
- return
-}
-
-func samaddr(f *gc.Node, t *gc.Node) bool {
- if f.Op != t.Op {
- return false
- }
-
- switch f.Op {
- case gc.OREGISTER:
- if f.Reg != t.Reg {
- break
- }
- return true
- }
-
- return false
-}
-
-/*
- * generate one instruction:
- * as f, t
- */
-func gins(as obj.As, f *gc.Node, t *gc.Node) *obj.Prog {
- if as == x86.AFMOVF && f != nil && f.Op == gc.OREGISTER && t != nil && t.Op == gc.OREGISTER {
- gc.Fatalf("gins MOVF reg, reg")
- }
- if as == x86.ACVTSD2SS && f != nil && f.Op == gc.OLITERAL {
- gc.Fatalf("gins CVTSD2SS const")
- }
- if as == x86.AMOVSD && t != nil && t.Op == gc.OREGISTER && t.Reg == x86.REG_F0 {
- gc.Fatalf("gins MOVSD into F0")
- }
-
- if as == x86.AMOVL && f != nil && f.Op == gc.OADDR && f.Left.Op == gc.ONAME && f.Left.Class != gc.PEXTERN && f.Left.Class != gc.PFUNC {
- // Turn MOVL $xxx(FP/SP) into LEAL xxx.
- // These should be equivalent but most of the backend
- // only expects to see LEAL, because that's what we had
- // historically generated. Various hidden assumptions are baked in by now.
- as = x86.ALEAL
- f = f.Left
- }
-
- switch as {
- case x86.AMOVB,
- x86.AMOVW,
- x86.AMOVL:
- if f != nil && t != nil && samaddr(f, t) {
- return nil
- }
-
- case x86.ALEAL:
- if f != nil && gc.Isconst(f, gc.CTNIL) {
- gc.Fatalf("gins LEAL nil %v", f.Type)
- }
- }
-
- p := gc.Prog(as)
- gc.Naddr(&p.From, f)
- gc.Naddr(&p.To, t)
-
- if gc.Debug['g'] != 0 {
- fmt.Printf("%v\n", p)
- }
-
- w := 0
- switch as {
- case x86.AMOVB:
- w = 1
-
- case x86.AMOVW:
- w = 2
-
- case x86.AMOVL:
- w = 4
- }
-
- if true && w != 0 && f != nil && (p.From.Width > int64(w) || p.To.Width > int64(w)) {
- gc.Dump("bad width from:", f)
- gc.Dump("bad width to:", t)
- gc.Fatalf("bad width: %v (%d, %d)\n", p, p.From.Width, p.To.Width)
- }
-
- if p.To.Type == obj.TYPE_ADDR && w > 0 {
- gc.Fatalf("bad use of addr: %v", p)
- }
-
- return p
-}
-
-func ginsnop() {
- var reg gc.Node
- gc.Nodreg(®, gc.Types[gc.TINT], x86.REG_AX)
- gins(x86.AXCHGL, ®, ®)
-}
-
-func dotaddable(n *gc.Node, n1 *gc.Node) bool {
- if n.Op != gc.ODOT {
- return false
- }
-
- var oary [10]int64
- var nn *gc.Node
- o := gc.Dotoffset(n, oary[:], &nn)
- if nn != nil && nn.Addable && o == 1 && oary[0] >= 0 {
- *n1 = *nn
- n1.Type = n.Type
- n1.Xoffset += oary[0]
- return true
- }
-
- return false
-}
-
-func sudoclean() {
-}
-
-func sudoaddable(as obj.As, n *gc.Node, a *obj.Addr) bool {
- *a = obj.Addr{}
- return false
-}
diff --git a/src/cmd/compile/internal/x86/peep.go b/src/cmd/compile/internal/x86/peep.go
deleted file mode 100644
index e70c10f..0000000
--- a/src/cmd/compile/internal/x86/peep.go
+++ /dev/null
@@ -1,807 +0,0 @@
-// Derived from Inferno utils/6c/peep.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6c/peep.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth at terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth at terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// Portions Copyright © 2009 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-package x86
-
-import (
- "cmd/compile/internal/gc"
- "cmd/internal/obj"
- "cmd/internal/obj/x86"
- "fmt"
-)
-
-const (
- REGEXT = 0
- exregoffset = x86.REG_DI
-)
-
-var gactive uint32
-
-// do we need the carry bit
-func needc(p *obj.Prog) bool {
- for p != nil {
- if p.Info.Flags&gc.UseCarry != 0 {
- return true
- }
- if p.Info.Flags&(gc.SetCarry|gc.KillCarry) != 0 {
- return false
- }
- p = p.Link
- }
-
- return false
-}
-
-func rnops(r *gc.Flow) *gc.Flow {
- if r != nil {
- var p *obj.Prog
- var r1 *gc.Flow
- for {
- p = r.Prog
- if p.As != obj.ANOP || p.From.Type != obj.TYPE_NONE || p.To.Type != obj.TYPE_NONE {
- break
- }
- r1 = gc.Uniqs(r)
- if r1 == nil {
- break
- }
- r = r1
- }
- }
-
- return r
-}
-
-func peep(firstp *obj.Prog) {
- g := gc.Flowstart(firstp, nil)
- if g == nil {
- return
- }
- gactive = 0
-
- // byte, word arithmetic elimination.
- elimshortmov(g)
-
- // constant propagation
- // find MOV $con,R followed by
- // another MOV $con,R without
- // setting R in the interim
- var p *obj.Prog
- for r := g.Start; r != nil; r = r.Link {
- p = r.Prog
- switch p.As {
- case x86.ALEAL:
- if regtyp(&p.To) {
- if p.From.Sym != nil {
- if p.From.Index == x86.REG_NONE {
- conprop(r)
- }
- }
- }
-
- case x86.AMOVB,
- x86.AMOVW,
- x86.AMOVL,
- x86.AMOVSS,
- x86.AMOVSD:
- if regtyp(&p.To) {
- if p.From.Type == obj.TYPE_CONST || p.From.Type == obj.TYPE_FCONST {
- conprop(r)
- }
- }
- }
- }
-
- var r1 *gc.Flow
- var p1 *obj.Prog
- var r *gc.Flow
- var t int
-loop1:
- if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
- gc.Dumpit("loop1", g.Start, 0)
- }
-
- t = 0
- for r = g.Start; r != nil; r = r.Link {
- p = r.Prog
- switch p.As {
- case x86.AMOVL,
- x86.AMOVSS,
- x86.AMOVSD:
- if regtyp(&p.To) {
- if regtyp(&p.From) {
- if copyprop(g, r) {
- excise(r)
- t++
- } else if subprop(r) && copyprop(g, r) {
- excise(r)
- t++
- }
- }
- }
-
- case x86.AMOVBLZX,
- x86.AMOVWLZX,
- x86.AMOVBLSX,
- x86.AMOVWLSX:
- if regtyp(&p.To) {
- r1 = rnops(gc.Uniqs(r))
- if r1 != nil {
- p1 = r1.Prog
- if p.As == p1.As && p.To.Type == p1.From.Type && p.To.Reg == p1.From.Reg {
- p1.As = x86.AMOVL
- t++
- }
- }
- }
-
- case x86.AADDL,
- x86.AADDW:
- if p.From.Type != obj.TYPE_CONST || needc(p.Link) {
- break
- }
- if p.From.Offset == -1 {
- if p.As == x86.AADDL {
- p.As = x86.ADECL
- } else {
- p.As = x86.ADECW
- }
- p.From = obj.Addr{}
- break
- }
-
- if p.From.Offset == 1 {
- if p.As == x86.AADDL {
- p.As = x86.AINCL
- } else {
- p.As = x86.AINCW
- }
- p.From = obj.Addr{}
- break
- }
-
- case x86.ASUBL,
- x86.ASUBW:
- if p.From.Type != obj.TYPE_CONST || needc(p.Link) {
- break
- }
- if p.From.Offset == -1 {
- if p.As == x86.ASUBL {
- p.As = x86.AINCL
- } else {
- p.As = x86.AINCW
- }
- p.From = obj.Addr{}
- break
- }
-
- if p.From.Offset == 1 {
- if p.As == x86.ASUBL {
- p.As = x86.ADECL
- } else {
- p.As = x86.ADECW
- }
- p.From = obj.Addr{}
- break
- }
- }
- }
-
- if t != 0 {
- goto loop1
- }
-
- // MOVSD removal.
- // We never use packed registers, so a MOVSD between registers
- // can be replaced by MOVAPD, which moves the pair of float64s
- // instead of just the lower one. We only use the lower one, but
- // the processor can do better if we do moves using both.
- for r := g.Start; r != nil; r = r.Link {
- p = r.Prog
- if p.As == x86.AMOVSD {
- if regtyp(&p.From) {
- if regtyp(&p.To) {
- p.As = x86.AMOVAPD
- }
- }
- }
- }
-
- gc.Flowend(g)
-}
-
-func excise(r *gc.Flow) {
- p := r.Prog
- if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
- fmt.Printf("%v ===delete===\n", p)
- }
-
- obj.Nopout(p)
-
- gc.Ostats.Ndelmov++
-}
-
-func regtyp(a *obj.Addr) bool {
- if gc.Ctxt.Flag_shared && a.Type == obj.TYPE_REG && a.Reg == x86.REG_CX {
- // don't propagate CX, it is used implicitly by PIC global references
- return false
- }
- return a.Type == obj.TYPE_REG && (x86.REG_AX <= a.Reg && a.Reg <= x86.REG_DI || x86.REG_X0 <= a.Reg && a.Reg <= x86.REG_X7)
-}
-
-// movb elimination.
-// movb is simulated by the linker
-// when a register other than ax, bx, cx, dx
-// is used, so rewrite to other instructions
-// when possible. a movb into a register
-// can smash the entire 64-bit register without
-// causing any trouble.
-func elimshortmov(g *gc.Graph) {
- var p *obj.Prog
-
- for r := g.Start; r != nil; r = r.Link {
- p = r.Prog
- if regtyp(&p.To) {
- switch p.As {
- case x86.AINCB,
- x86.AINCW:
- p.As = x86.AINCL
-
- case x86.ADECB,
- x86.ADECW:
- p.As = x86.ADECL
-
- case x86.ANEGB,
- x86.ANEGW:
- p.As = x86.ANEGL
-
- case x86.ANOTB,
- x86.ANOTW:
- p.As = x86.ANOTL
- }
-
- if regtyp(&p.From) || p.From.Type == obj.TYPE_CONST {
- // move or arithmetic into partial register.
- // from another register or constant can be movl.
- // we don't switch to 32-bit arithmetic if it can
- // change how the carry bit is set (and the carry bit is needed).
- switch p.As {
- case x86.AMOVB,
- x86.AMOVW:
- p.As = x86.AMOVL
-
- case x86.AADDB,
- x86.AADDW:
- if !needc(p.Link) {
- p.As = x86.AADDL
- }
-
- case x86.ASUBB,
- x86.ASUBW:
- if !needc(p.Link) {
- p.As = x86.ASUBL
- }
-
- case x86.AMULB,
- x86.AMULW:
- p.As = x86.AMULL
-
- case x86.AIMULB,
- x86.AIMULW:
- p.As = x86.AIMULL
-
- case x86.AANDB,
- x86.AANDW:
- p.As = x86.AANDL
-
- case x86.AORB,
- x86.AORW:
- p.As = x86.AORL
-
- case x86.AXORB,
- x86.AXORW:
- p.As = x86.AXORL
-
- case x86.ASHLB,
- x86.ASHLW:
- p.As = x86.ASHLL
- }
- } else {
- // explicit zero extension
- switch p.As {
- case x86.AMOVB:
- p.As = x86.AMOVBLZX
-
- case x86.AMOVW:
- p.As = x86.AMOVWLZX
- }
- }
- }
- }
-}
-
-/*
- * the idea is to substitute
- * one register for another
- * from one MOV to another
- * MOV a, R0
- * ADD b, R0 / no use of R1
- * MOV R0, R1
- * would be converted to
- * MOV a, R1
- * ADD b, R1
- * MOV R1, R0
- * hopefully, then the former or latter MOV
- * will be eliminated by copy propagation.
- */
-func subprop(r0 *gc.Flow) bool {
- p := r0.Prog
- v1 := &p.From
- if !regtyp(v1) {
- return false
- }
- v2 := &p.To
- if !regtyp(v2) {
- return false
- }
- for r := gc.Uniqp(r0); r != nil; r = gc.Uniqp(r) {
- if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
- fmt.Printf("\t? %v\n", r.Prog)
- }
- if gc.Uniqs(r) == nil {
- break
- }
- p = r.Prog
- if p.As == obj.AVARDEF || p.As == obj.AVARKILL {
- continue
- }
- if p.Info.Flags&gc.Call != 0 {
- return false
- }
-
- if p.Info.Reguse|p.Info.Regset != 0 {
- return false
- }
-
- if (p.Info.Flags&gc.Move != 0) && (p.Info.Flags&(gc.SizeL|gc.SizeQ|gc.SizeF|gc.SizeD) != 0) && p.To.Type == v1.Type && p.To.Reg == v1.Reg {
- copysub(&p.To, v1, v2, true)
- if gc.Debug['P'] != 0 {
- fmt.Printf("gotit: %v->%v\n%v", gc.Ctxt.Dconv(v1), gc.Ctxt.Dconv(v2), r.Prog)
- if p.From.Type == v2.Type && p.From.Reg == v2.Reg {
- fmt.Printf(" excise")
- }
- fmt.Printf("\n")
- }
-
- for r = gc.Uniqs(r); r != r0; r = gc.Uniqs(r) {
- p = r.Prog
- copysub(&p.From, v1, v2, true)
- copysub(&p.To, v1, v2, true)
- if gc.Debug['P'] != 0 {
- fmt.Printf("%v\n", r.Prog)
- }
- }
-
- t := int(v1.Reg)
- v1.Reg = v2.Reg
- v2.Reg = int16(t)
- if gc.Debug['P'] != 0 {
- fmt.Printf("%v last\n", r.Prog)
- }
- return true
- }
-
- if copyau(&p.From, v2) || copyau(&p.To, v2) {
- break
- }
- if copysub(&p.From, v1, v2, false) || copysub(&p.To, v1, v2, false) {
- break
- }
- }
-
- return false
-}
-
-/*
- * The idea is to remove redundant copies.
- * v1->v2 F=0
- * (use v2 s/v2/v1/)*
- * set v1 F=1
- * use v2 return fail
- * -----------------
- * v1->v2 F=0
- * (use v2 s/v2/v1/)*
- * set v1 F=1
- * set v2 return success
- */
-func copyprop(g *gc.Graph, r0 *gc.Flow) bool {
- p := r0.Prog
- v1 := &p.From
- v2 := &p.To
- if copyas(v1, v2) {
- return true
- }
- gactive++
- return copy1(v1, v2, r0.S1, false)
-}
-
-func copy1(v1 *obj.Addr, v2 *obj.Addr, r *gc.Flow, f bool) bool {
- if uint32(r.Active) == gactive {
- if gc.Debug['P'] != 0 {
- fmt.Printf("act set; return 1\n")
- }
- return true
- }
-
- r.Active = int32(gactive)
- if gc.Debug['P'] != 0 {
- fmt.Printf("copy %v->%v f=%v\n", gc.Ctxt.Dconv(v1), gc.Ctxt.Dconv(v2), f)
- }
- for ; r != nil; r = r.S1 {
- p := r.Prog
- if gc.Debug['P'] != 0 {
- fmt.Printf("%v", p)
- }
- if !f && gc.Uniqp(r) == nil {
- f = true
- if gc.Debug['P'] != 0 {
- fmt.Printf("; merge; f=%v", f)
- }
- }
-
- switch t := copyu(p, v2, nil); t {
- case 2: /* rar, can't split */
- if gc.Debug['P'] != 0 {
- fmt.Printf("; %v rar; return 0\n", gc.Ctxt.Dconv(v2))
- }
- return false
-
- case 3: /* set */
- if gc.Debug['P'] != 0 {
- fmt.Printf("; %v set; return 1\n", gc.Ctxt.Dconv(v2))
- }
- return true
-
- case 1, /* used, substitute */
- 4: /* use and set */
- if f {
- if gc.Debug['P'] == 0 {
- return false
- }
- if t == 4 {
- fmt.Printf("; %v used+set and f=%v; return 0\n", gc.Ctxt.Dconv(v2), f)
- } else {
- fmt.Printf("; %v used and f=%v; return 0\n", gc.Ctxt.Dconv(v2), f)
- }
- return false
- }
-
- if copyu(p, v2, v1) != 0 {
- if gc.Debug['P'] != 0 {
- fmt.Printf("; sub fail; return 0\n")
- }
- return false
- }
-
- if gc.Debug['P'] != 0 {
- fmt.Printf("; sub %v/%v", gc.Ctxt.Dconv(v2), gc.Ctxt.Dconv(v1))
- }
- if t == 4 {
- if gc.Debug['P'] != 0 {
- fmt.Printf("; %v used+set; return 1\n", gc.Ctxt.Dconv(v2))
- }
- return true
- }
- }
-
- if !f {
- t := copyu(p, v1, nil)
- if t == 2 || t == 3 || t == 4 {
- f = true
- if gc.Debug['P'] != 0 {
- fmt.Printf("; %v set and !f; f=%v", gc.Ctxt.Dconv(v1), f)
- }
- }
- }
-
- if gc.Debug['P'] != 0 {
- fmt.Printf("\n")
- }
- if r.S2 != nil {
- if !copy1(v1, v2, r.S2, f) {
- return false
- }
- }
- }
- return true
-}
-
-/*
- * return
- * 1 if v only used (and substitute),
- * 2 if read-alter-rewrite
- * 3 if set
- * 4 if set and used
- * 0 otherwise (not touched)
- */
-func copyu(p *obj.Prog, v *obj.Addr, s *obj.Addr) int {
- switch p.As {
- case obj.AJMP:
- if s != nil {
- if copysub(&p.To, v, s, true) {
- return 1
- }
- return 0
- }
-
- if copyau(&p.To, v) {
- return 1
- }
- return 0
-
- case obj.ARET:
- if s != nil {
- return 1
- }
- return 3
-
- case obj.ACALL:
- if REGEXT != 0 /*TypeKind(100016)*/ && v.Type == obj.TYPE_REG && v.Reg <= REGEXT && v.Reg > exregoffset {
- return 2
- }
- if x86.REGARG >= 0 && v.Type == obj.TYPE_REG && v.Reg == x86.REGARG {
- return 2
- }
- if v.Type == p.From.Type && v.Reg == p.From.Reg {
- return 2
- }
-
- if s != nil {
- if copysub(&p.To, v, s, true) {
- return 1
- }
- return 0
- }
-
- if copyau(&p.To, v) {
- return 4
- }
- return 3
-
- case obj.ATEXT:
- if x86.REGARG >= 0 && v.Type == obj.TYPE_REG && v.Reg == x86.REGARG {
- return 3
- }
- return 0
- }
-
- if p.As == obj.AVARDEF || p.As == obj.AVARKILL {
- return 0
- }
-
- if (p.Info.Reguse|p.Info.Regset)&RtoB(int(v.Reg)) != 0 {
- return 2
- }
-
- if p.Info.Flags&gc.LeftAddr != 0 {
- if copyas(&p.From, v) {
- return 2
- }
- }
-
- if p.Info.Flags&(gc.RightRead|gc.RightWrite) == gc.RightRead|gc.RightWrite {
- if copyas(&p.To, v) {
- return 2
- }
- }
-
- if p.Info.Flags&gc.RightWrite != 0 {
- if copyas(&p.To, v) {
- if s != nil {
- if copysub(&p.From, v, s, true) {
- return 1
- }
- return 0
- }
- if copyau(&p.From, v) {
- return 4
- }
- return 3
- }
- }
-
- if p.Info.Flags&(gc.LeftAddr|gc.LeftRead|gc.LeftWrite|gc.RightAddr|gc.RightRead|gc.RightWrite) != 0 {
- if s != nil {
- if copysub(&p.From, v, s, true) {
- return 1
- }
- if copysub(&p.To, v, s, true) {
- return 1
- }
- return 0
- }
- if copyau(&p.From, v) {
- return 1
- }
- if copyau(&p.To, v) {
- return 1
- }
- }
- return 0
-}
-
-/*
- * direct reference,
- * could be set/use depending on
- * semantics
- */
-func copyas(a *obj.Addr, v *obj.Addr) bool {
- if x86.REG_AL <= a.Reg && a.Reg <= x86.REG_BL {
- gc.Fatalf("use of byte register")
- }
- if x86.REG_AL <= v.Reg && v.Reg <= x86.REG_BL {
- gc.Fatalf("use of byte register")
- }
-
- if a.Type != v.Type || a.Name != v.Name || a.Reg != v.Reg {
- return false
- }
- if regtyp(v) {
- return true
- }
- if (v.Type == obj.TYPE_MEM || v.Type == obj.TYPE_ADDR) && (v.Name == obj.NAME_AUTO || v.Name == obj.NAME_PARAM) {
- if v.Offset == a.Offset {
- return true
- }
- }
- return false
-}
-
-func sameaddr(a *obj.Addr, v *obj.Addr) bool {
- if a.Type != v.Type || a.Name != v.Name || a.Reg != v.Reg {
- return false
- }
- if regtyp(v) {
- return true
- }
- if (v.Type == obj.TYPE_MEM || v.Type == obj.TYPE_ADDR) && (v.Name == obj.NAME_AUTO || v.Name == obj.NAME_PARAM) {
- if v.Offset == a.Offset {
- return true
- }
- }
- return false
-}
-
-/*
- * either direct or indirect
- */
-func copyau(a *obj.Addr, v *obj.Addr) bool {
- if copyas(a, v) {
- return true
- }
- if regtyp(v) {
- if (a.Type == obj.TYPE_MEM || a.Type == obj.TYPE_ADDR) && a.Reg == v.Reg {
- return true
- }
- if a.Index == v.Reg {
- return true
- }
- }
-
- return false
-}
-
-// copysub substitute s for v in a.
-// copysub returns true on failure to substitute.
-// TODO(dfc) reverse this logic to return false on sunstitution failure.
-func copysub(a *obj.Addr, v *obj.Addr, s *obj.Addr, f bool) bool {
- if copyas(a, v) {
- if s.Reg >= x86.REG_AX && s.Reg <= x86.REG_DI || s.Reg >= x86.REG_X0 && s.Reg <= x86.REG_X7 {
- if f {
- a.Reg = s.Reg
- }
- }
- return false
- }
-
- if regtyp(v) {
- if (a.Type == obj.TYPE_MEM || a.Type == obj.TYPE_ADDR) && a.Reg == v.Reg {
- if (s.Reg == x86.REG_BP) && a.Index != x86.REG_NONE {
- return true /* can't use BP-base with index */
- }
- if f {
- a.Reg = s.Reg
- }
- }
-
- if a.Index == v.Reg {
- if f {
- a.Index = s.Reg
- }
- }
- }
- return false
-}
-
-func conprop(r0 *gc.Flow) {
- var p *obj.Prog
-
- p0 := r0.Prog
- v0 := &p0.To
- r := r0
-
-loop:
- r = gc.Uniqs(r)
- if r == nil || r == r0 {
- return
- }
- if gc.Uniqp(r) == nil {
- return
- }
-
- p = r.Prog
- switch copyu(p, v0, nil) {
- case 0, // miss
- 1: // use
- goto loop
-
- case 2, // rar
- 4: // use and set
- break
-
- case 3: // set
- if p.As == p0.As {
- if p.From.Type == p0.From.Type {
- if p.From.Reg == p0.From.Reg {
- if p.From.Node == p0.From.Node {
- if p.From.Offset == p0.From.Offset {
- if p.From.Scale == p0.From.Scale {
- if p.From.Type == obj.TYPE_FCONST && p.From.Val.(float64) == p0.From.Val.(float64) {
- if p.From.Index == p0.From.Index {
- excise(r)
- goto loop
- }
- }
- }
- }
- }
- }
- }
- }
- }
-}
-
-func smallindir(a *obj.Addr, reg *obj.Addr) bool {
- return regtyp(reg) && a.Type == obj.TYPE_MEM && a.Reg == reg.Reg && a.Index == x86.REG_NONE && 0 <= a.Offset && a.Offset < 4096
-}
-
-func stackaddr(a *obj.Addr) bool {
- return a.Type == obj.TYPE_REG && a.Reg == x86.REG_SP
-}
diff --git a/src/cmd/compile/internal/x86/prog.go b/src/cmd/compile/internal/x86/prog.go
index f2b4a65..e46bdb7 100644
--- a/src/cmd/compile/internal/x86/prog.go
+++ b/src/cmd/compile/internal/x86/prog.go
@@ -10,13 +10,7 @@ import (
"cmd/internal/obj/x86"
)
-var (
- AX = RtoB(x86.REG_AX)
- BX = RtoB(x86.REG_BX)
- CX = RtoB(x86.REG_CX)
- DX = RtoB(x86.REG_DX)
- DI = RtoB(x86.REG_DI)
- SI = RtoB(x86.REG_SI)
+const (
LeftRdwr uint32 = gc.LeftRead | gc.LeftWrite
RightRdwr uint32 = gc.RightRead | gc.RightWrite
)
@@ -30,14 +24,13 @@ var (
// size variants of an operation even if we just use a subset.
//
// The table is formatted for 8-space tabs.
-var progtable = [x86.ALAST & obj.AMask]obj.ProgInfo{
+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.ACHECKNIL: {Flags: gc.LeftRead},
obj.AVARDEF: {Flags: gc.Pseudo | gc.RightWrite},
obj.AVARKILL: {Flags: gc.Pseudo | gc.RightWrite},
obj.AVARLIVE: {Flags: gc.Pseudo | gc.LeftRead},
@@ -56,8 +49,8 @@ var progtable = [x86.ALAST & obj.AMask]obj.ProgInfo{
x86.AANDL & obj.AMask: {Flags: gc.SizeL | gc.LeftRead | RightRdwr | gc.SetCarry},
x86.AANDW & obj.AMask: {Flags: gc.SizeW | gc.LeftRead | RightRdwr | gc.SetCarry},
obj.ACALL: {Flags: gc.RightAddr | gc.Call | gc.KillCarry},
- x86.ACDQ & obj.AMask: {Flags: gc.OK, Reguse: AX, Regset: AX | DX},
- x86.ACWD & obj.AMask: {Flags: gc.OK, Reguse: AX, Regset: AX | DX},
+ x86.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},
@@ -76,9 +69,9 @@ var progtable = [x86.ALAST & obj.AMask]obj.ProgInfo{
x86.ADECB & obj.AMask: {Flags: gc.SizeB | RightRdwr},
x86.ADECL & obj.AMask: {Flags: gc.SizeL | RightRdwr},
x86.ADECW & obj.AMask: {Flags: gc.SizeW | RightRdwr},
- x86.ADIVB & obj.AMask: {Flags: gc.SizeB | gc.LeftRead | gc.SetCarry, Reguse: AX, Regset: AX},
- x86.ADIVL & obj.AMask: {Flags: gc.SizeL | gc.LeftRead | gc.SetCarry, Reguse: AX | DX, Regset: AX | DX},
- x86.ADIVW & obj.AMask: {Flags: gc.SizeW | gc.LeftRead | gc.SetCarry, Reguse: AX | DX, Regset: AX | DX},
+ x86.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},
@@ -131,10 +124,10 @@ var progtable = [x86.ALAST & obj.AMask]obj.ProgInfo{
x86.AFMULD & obj.AMask: {Flags: gc.SizeD | gc.LeftAddr | RightRdwr},
x86.AFMULDP & obj.AMask: {Flags: gc.SizeD | gc.LeftAddr | RightRdwr},
x86.AFMULF & obj.AMask: {Flags: gc.SizeF | gc.LeftAddr | RightRdwr},
- x86.AIDIVB & obj.AMask: {Flags: gc.SizeB | gc.LeftRead | gc.SetCarry, Reguse: AX, Regset: AX},
- x86.AIDIVL & obj.AMask: {Flags: gc.SizeL | gc.LeftRead | gc.SetCarry, Reguse: AX | DX, Regset: AX | DX},
- x86.AIDIVW & obj.AMask: {Flags: gc.SizeW | gc.LeftRead | gc.SetCarry, Reguse: AX | DX, Regset: AX | DX},
- x86.AIMULB & obj.AMask: {Flags: gc.SizeB | gc.LeftRead | gc.SetCarry, Reguse: AX, Regset: AX},
+ x86.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},
@@ -168,18 +161,18 @@ var progtable = [x86.ALAST & obj.AMask]obj.ProgInfo{
x86.AMOVB & obj.AMask: {Flags: gc.SizeB | gc.LeftRead | gc.RightWrite | gc.Move},
x86.AMOVL & obj.AMask: {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Move},
x86.AMOVW & obj.AMask: {Flags: gc.SizeW | gc.LeftRead | gc.RightWrite | gc.Move},
- x86.AMOVSB & obj.AMask: {Flags: gc.OK, Reguse: DI | SI, Regset: DI | SI},
- x86.AMOVSL & obj.AMask: {Flags: gc.OK, Reguse: DI | SI, Regset: DI | SI},
- x86.AMOVSW & obj.AMask: {Flags: gc.OK, Reguse: DI | SI, Regset: DI | SI},
- obj.ADUFFCOPY: {Flags: gc.OK, Reguse: DI | SI, Regset: DI | SI | CX},
+ x86.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, Reguse: AX, Regset: AX},
- x86.AMULL & obj.AMask: {Flags: gc.SizeL | gc.LeftRead | gc.SetCarry, Reguse: AX, Regset: AX | DX},
- x86.AMULW & obj.AMask: {Flags: gc.SizeW | gc.LeftRead | gc.SetCarry, Reguse: AX, Regset: AX | DX},
+ x86.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},
@@ -200,8 +193,8 @@ var progtable = [x86.ALAST & obj.AMask]obj.ProgInfo{
x86.ARCRB & obj.AMask: {Flags: gc.SizeB | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry | gc.UseCarry},
x86.ARCRL & obj.AMask: {Flags: gc.SizeL | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry | gc.UseCarry},
x86.ARCRW & obj.AMask: {Flags: gc.SizeW | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry | gc.UseCarry},
- x86.AREP & obj.AMask: {Flags: gc.OK, Reguse: CX, Regset: CX},
- x86.AREPN & obj.AMask: {Flags: gc.OK, Reguse: CX, Regset: CX},
+ 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},
@@ -209,7 +202,7 @@ var progtable = [x86.ALAST & obj.AMask]obj.ProgInfo{
x86.ARORB & obj.AMask: {Flags: gc.SizeB | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry},
x86.ARORL & obj.AMask: {Flags: gc.SizeL | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry},
x86.ARORW & obj.AMask: {Flags: gc.SizeW | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry},
- x86.ASAHF & obj.AMask: {Flags: gc.OK, Reguse: AX, Regset: AX},
+ x86.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},
@@ -241,10 +234,10 @@ var progtable = [x86.ALAST & obj.AMask]obj.ProgInfo{
x86.ASHRB & obj.AMask: {Flags: gc.SizeB | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry},
x86.ASHRL & obj.AMask: {Flags: gc.SizeL | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry},
x86.ASHRW & obj.AMask: {Flags: gc.SizeW | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry},
- x86.ASTOSB & obj.AMask: {Flags: gc.OK, Reguse: AX | DI, Regset: DI},
- x86.ASTOSL & obj.AMask: {Flags: gc.OK, Reguse: AX | DI, Regset: DI},
- x86.ASTOSW & obj.AMask: {Flags: gc.OK, Reguse: AX | DI, Regset: DI},
- obj.ADUFFZERO: {Flags: gc.OK, Reguse: AX | DI, Regset: DI},
+ x86.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},
@@ -263,37 +256,15 @@ var progtable = [x86.ALAST & obj.AMask]obj.ProgInfo{
x86.AXORW & obj.AMask: {Flags: gc.SizeW | gc.LeftRead | RightRdwr | gc.SetCarry},
}
-func proginfo(p *obj.Prog) {
- info := &p.Info
- *info = progtable[p.As&obj.AMask]
+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.ShiftCX != 0) && p.From.Type != obj.TYPE_CONST {
- info.Reguse |= CX
+ if info.Flags&gc.ImulAXDX != 0 && p.To.Type != obj.TYPE_NONE {
+ info.Flags |= RightRdwr
}
- if info.Flags&gc.ImulAXDX != 0 {
- if p.To.Type == obj.TYPE_NONE {
- info.Reguse |= AX
- info.Regset |= AX | DX
- } else {
- info.Flags |= RightRdwr
- }
- }
-
- // Addressing makes some registers used.
- if p.From.Type == obj.TYPE_MEM && p.From.Name == obj.NAME_NONE {
- info.Regindex |= RtoB(int(p.From.Reg))
- }
- if p.From.Index != x86.REG_NONE {
- info.Regindex |= RtoB(int(p.From.Index))
- }
- if p.To.Type == obj.TYPE_MEM && p.To.Name == obj.NAME_NONE {
- info.Regindex |= RtoB(int(p.To.Reg))
- }
- if p.To.Index != x86.REG_NONE {
- info.Regindex |= RtoB(int(p.To.Index))
- }
+ return info
}
diff --git a/src/cmd/compile/internal/x86/reg.go b/src/cmd/compile/internal/x86/reg.go
deleted file mode 100644
index cc94d72..0000000
--- a/src/cmd/compile/internal/x86/reg.go
+++ /dev/null
@@ -1,114 +0,0 @@
-// Derived from Inferno utils/6c/reg.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6c/reg.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth at terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth at terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// Portions Copyright © 2009 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-package x86
-
-import "cmd/internal/obj/x86"
-import "cmd/compile/internal/gc"
-
-const (
- NREGVAR = 16 /* 8 integer + 8 floating */
-)
-
-var regname = []string{
- ".ax",
- ".cx",
- ".dx",
- ".bx",
- ".sp",
- ".bp",
- ".si",
- ".di",
- ".x0",
- ".x1",
- ".x2",
- ".x3",
- ".x4",
- ".x5",
- ".x6",
- ".x7",
-}
-
-func regnames(n *int) []string {
- *n = NREGVAR
- return regname
-}
-
-func excludedregs() uint64 {
- if gc.Ctxt.Flag_shared {
- return RtoB(x86.REG_SP) | RtoB(x86.REG_CX)
- } else {
- return RtoB(x86.REG_SP)
- }
-}
-
-func doregbits(r int) uint64 {
- b := uint64(0)
- if r >= x86.REG_AX && r <= x86.REG_DI {
- b |= RtoB(r)
- } else if r >= x86.REG_AL && r <= x86.REG_BL {
- b |= RtoB(r - x86.REG_AL + x86.REG_AX)
- } else if r >= x86.REG_AH && r <= x86.REG_BH {
- b |= RtoB(r - x86.REG_AH + x86.REG_AX)
- } else if r >= x86.REG_X0 && r <= x86.REG_X0+7 {
- b |= FtoB(r)
- }
- return b
-}
-
-func RtoB(r int) uint64 {
- if r < x86.REG_AX || r > x86.REG_DI {
- return 0
- }
- return 1 << uint(r-x86.REG_AX)
-}
-
-func BtoR(b uint64) int {
- b &= 0xff
- if b == 0 {
- return 0
- }
- return gc.Bitno(b) + x86.REG_AX
-}
-
-func FtoB(f int) uint64 {
- if f < x86.REG_X0 || f > x86.REG_X7 {
- return 0
- }
- return 1 << uint(f-x86.REG_X0+8)
-}
-
-func BtoF(b uint64) int {
- b &= 0xFF00
- if b == 0 {
- return 0
- }
- return gc.Bitno(b) - 8 + x86.REG_X0
-}
diff --git a/src/cmd/compile/internal/x86/ssa.go b/src/cmd/compile/internal/x86/ssa.go
new file mode 100644
index 0000000..21be634
--- /dev/null
+++ b/src/cmd/compile/internal/x86/ssa.go
@@ -0,0 +1,918 @@
+// Copyright 2016 The Go Authors. 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 (
+ "fmt"
+ "math"
+
+ "cmd/compile/internal/gc"
+ "cmd/compile/internal/ssa"
+ "cmd/internal/obj"
+ "cmd/internal/obj/x86"
+)
+
+// markMoves marks any MOVXconst ops that need to avoid clobbering flags.
+func ssaMarkMoves(s *gc.SSAGenState, b *ssa.Block) {
+ flive := b.FlagsLiveAtEnd
+ if b.Control != nil && b.Control.Type.IsFlags() {
+ flive = true
+ }
+ for i := len(b.Values) - 1; i >= 0; i-- {
+ v := b.Values[i]
+ if flive && v.Op == ssa.Op386MOVLconst {
+ // The "mark" is any non-nil Aux value.
+ v.Aux = v
+ }
+ if v.Type.IsFlags() {
+ flive = false
+ }
+ for _, a := range v.Args {
+ if a.Type.IsFlags() {
+ flive = true
+ }
+ }
+ }
+}
+
+// loadByType returns the load instruction of the given type.
+func loadByType(t ssa.Type) obj.As {
+ // Avoid partial register write
+ if !t.IsFloat() && t.Size() <= 2 {
+ if t.Size() == 1 {
+ return x86.AMOVBLZX
+ } else {
+ return x86.AMOVWLZX
+ }
+ }
+ // Otherwise, there's no difference between load and store opcodes.
+ return storeByType(t)
+}
+
+// storeByType returns the store instruction of the given type.
+func storeByType(t ssa.Type) obj.As {
+ width := t.Size()
+ if t.IsFloat() {
+ switch width {
+ case 4:
+ return x86.AMOVSS
+ case 8:
+ return x86.AMOVSD
+ }
+ } else {
+ switch width {
+ case 1:
+ return x86.AMOVB
+ case 2:
+ return x86.AMOVW
+ case 4:
+ return x86.AMOVL
+ }
+ }
+ panic("bad store type")
+}
+
+// moveByType returns the reg->reg move instruction of the given type.
+func moveByType(t ssa.Type) obj.As {
+ if t.IsFloat() {
+ switch t.Size() {
+ case 4:
+ return x86.AMOVSS
+ case 8:
+ return x86.AMOVSD
+ default:
+ panic(fmt.Sprintf("bad float register width %d:%s", t.Size(), t))
+ }
+ } else {
+ switch t.Size() {
+ case 1:
+ // Avoids partial register write
+ return x86.AMOVL
+ case 2:
+ return x86.AMOVL
+ case 4:
+ return x86.AMOVL
+ default:
+ panic(fmt.Sprintf("bad int register width %d:%s", t.Size(), t))
+ }
+ }
+}
+
+// opregreg emits instructions for
+// dest := dest(To) op src(From)
+// and also returns the created obj.Prog so it
+// may be further adjusted (offset, scale, etc).
+func opregreg(op obj.As, dest, src int16) *obj.Prog {
+ p := gc.Prog(op)
+ p.From.Type = obj.TYPE_REG
+ p.To.Type = obj.TYPE_REG
+ p.To.Reg = dest
+ p.From.Reg = src
+ return p
+}
+
+func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
+ s.SetLineno(v.Line)
+
+ if gc.Thearch.Use387 {
+ if ssaGenValue387(s, v) {
+ return // v was handled by 387 generation.
+ }
+ }
+
+ switch v.Op {
+ case ssa.Op386ADDL:
+ r := v.Reg()
+ r1 := v.Args[0].Reg()
+ r2 := v.Args[1].Reg()
+ switch {
+ case r == r1:
+ p := gc.Prog(v.Op.Asm())
+ p.From.Type = obj.TYPE_REG
+ p.From.Reg = r2
+ p.To.Type = obj.TYPE_REG
+ p.To.Reg = r
+ case r == r2:
+ p := gc.Prog(v.Op.Asm())
+ p.From.Type = obj.TYPE_REG
+ p.From.Reg = r1
+ p.To.Type = obj.TYPE_REG
+ p.To.Reg = r
+ default:
+ p := gc.Prog(x86.ALEAL)
+ p.From.Type = obj.TYPE_MEM
+ p.From.Reg = r1
+ p.From.Scale = 1
+ p.From.Index = r2
+ p.To.Type = obj.TYPE_REG
+ p.To.Reg = r
+ }
+
+ // 2-address opcode arithmetic
+ case ssa.Op386SUBL,
+ ssa.Op386MULL,
+ ssa.Op386ANDL,
+ ssa.Op386ORL,
+ ssa.Op386XORL,
+ ssa.Op386SHLL,
+ ssa.Op386SHRL, ssa.Op386SHRW, ssa.Op386SHRB,
+ ssa.Op386SARL, ssa.Op386SARW, ssa.Op386SARB,
+ ssa.Op386ADDSS, ssa.Op386ADDSD, ssa.Op386SUBSS, ssa.Op386SUBSD,
+ ssa.Op386MULSS, ssa.Op386MULSD, ssa.Op386DIVSS, ssa.Op386DIVSD,
+ ssa.Op386PXOR,
+ ssa.Op386ADCL,
+ ssa.Op386SBBL:
+ r := v.Reg()
+ 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())
+
+ case ssa.Op386ADDLcarry, ssa.Op386SUBLcarry:
+ // output 0 is carry/borrow, output 1 is the low 32 bits.
+ r := v.Reg0()
+ 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())
+
+ case ssa.Op386ADDLconstcarry, ssa.Op386SUBLconstcarry:
+ // output 0 is carry/borrow, output 1 is the low 32 bits.
+ r := v.Reg0()
+ 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.From.Type = obj.TYPE_CONST
+ p.From.Offset = v.AuxInt
+ p.To.Type = obj.TYPE_REG
+ p.To.Reg = r
+
+ case ssa.Op386DIVL, ssa.Op386DIVW,
+ ssa.Op386DIVLU, ssa.Op386DIVWU,
+ ssa.Op386MODL, ssa.Op386MODW,
+ ssa.Op386MODLU, ssa.Op386MODWU:
+
+ // Arg[0] is already in AX as it's the only register we allow
+ // and AX is the only output
+ x := v.Args[1].Reg()
+
+ // CPU faults upon signed overflow, which occurs when most
+ // negative int is divided by -1.
+ var j *obj.Prog
+ if v.Op == ssa.Op386DIVL || v.Op == ssa.Op386DIVW ||
+ v.Op == ssa.Op386MODL || v.Op == ssa.Op386MODW {
+
+ 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
+
+ case ssa.Op386DIVW, ssa.Op386MODW:
+ c = gc.Prog(x86.ACMPW)
+ j = gc.Prog(x86.AJEQ)
+ gc.Prog(x86.ACWD)
+ }
+ c.From.Type = obj.TYPE_REG
+ c.From.Reg = x
+ c.To.Type = obj.TYPE_CONST
+ c.To.Offset = -1
+
+ j.To.Type = obj.TYPE_BRANCH
+ }
+
+ // for unsigned ints, we sign extend by setting DX = 0
+ // signed ints were sign extended above
+ if v.Op == ssa.Op386DIVLU || v.Op == ssa.Op386MODLU ||
+ v.Op == ssa.Op386DIVWU || v.Op == ssa.Op386MODWU {
+ c := gc.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.From.Type = obj.TYPE_REG
+ p.From.Reg = x
+
+ // signed division, rest of the check for -1 case
+ if j != nil {
+ j2 := gc.Prog(obj.AJMP)
+ j2.To.Type = obj.TYPE_BRANCH
+
+ var n *obj.Prog
+ if v.Op == ssa.Op386DIVL || v.Op == ssa.Op386DIVW {
+ // n * -1 = -n
+ n = gc.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.From.Type = obj.TYPE_REG
+ n.From.Reg = x86.REG_DX
+ n.To.Type = obj.TYPE_REG
+ n.To.Reg = x86.REG_DX
+ }
+
+ j.To.Val = n
+ j2.To.Val = s.Pc()
+ }
+
+ case ssa.Op386HMULL, ssa.Op386HMULW, ssa.Op386HMULB,
+ ssa.Op386HMULLU, ssa.Op386HMULWU, ssa.Op386HMULBU:
+ // the frontend rewrites constant division by 8/16/32 bit integers into
+ // HMUL by a constant
+ // SSA rewrites generate the 64 bit versions
+
+ // Arg[0] is already in AX as it's the only register we allow
+ // and DX is the only output we care about (the high bits)
+ p := gc.Prog(v.Op.Asm())
+ p.From.Type = obj.TYPE_REG
+ p.From.Reg = 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.From.Type = obj.TYPE_REG
+ m.From.Reg = x86.REG_AH
+ m.To.Type = obj.TYPE_REG
+ m.To.Reg = x86.REG_DX
+ }
+
+ case ssa.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.From.Type = obj.TYPE_REG
+ p.From.Reg = v.Args[1].Reg()
+
+ case ssa.Op386ADDLconst:
+ r := v.Reg()
+ a := v.Args[0].Reg()
+ if r == a {
+ if v.AuxInt == 1 {
+ p := gc.Prog(x86.AINCL)
+ p.To.Type = obj.TYPE_REG
+ p.To.Reg = r
+ return
+ }
+ if v.AuxInt == -1 {
+ p := gc.Prog(x86.ADECL)
+ p.To.Type = obj.TYPE_REG
+ p.To.Reg = r
+ return
+ }
+ p := gc.Prog(v.Op.Asm())
+ p.From.Type = obj.TYPE_CONST
+ p.From.Offset = v.AuxInt
+ p.To.Type = obj.TYPE_REG
+ p.To.Reg = r
+ return
+ }
+ p := gc.Prog(x86.ALEAL)
+ p.From.Type = obj.TYPE_MEM
+ p.From.Reg = a
+ p.From.Offset = v.AuxInt
+ p.To.Type = obj.TYPE_REG
+ p.To.Reg = r
+
+ case ssa.Op386MULLconst:
+ r := v.Reg()
+ 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.From.Type = obj.TYPE_CONST
+ p.From.Offset = v.AuxInt
+ p.To.Type = obj.TYPE_REG
+ p.To.Reg = r
+ // TODO: Teach doasm to compile the three-address multiply imul $c, r1, r2
+ // then we don't need to use resultInArg0 for these ops.
+ //p.From3 = new(obj.Addr)
+ //p.From3.Type = obj.TYPE_REG
+ //p.From3.Reg = v.Args[0].Reg()
+
+ case ssa.Op386SUBLconst,
+ ssa.Op386ADCLconst,
+ ssa.Op386SBBLconst,
+ ssa.Op386ANDLconst,
+ ssa.Op386ORLconst,
+ ssa.Op386XORLconst,
+ ssa.Op386SHLLconst,
+ ssa.Op386SHRLconst, ssa.Op386SHRWconst, ssa.Op386SHRBconst,
+ ssa.Op386SARLconst, ssa.Op386SARWconst, ssa.Op386SARBconst,
+ ssa.Op386ROLLconst, ssa.Op386ROLWconst, ssa.Op386ROLBconst:
+ r := v.Reg()
+ 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.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.From.Type = obj.TYPE_REG
+ p.From.Reg = r
+ p.To.Type = obj.TYPE_REG
+ p.To.Reg = r
+ case ssa.Op386LEAL1, ssa.Op386LEAL2, ssa.Op386LEAL4, ssa.Op386LEAL8:
+ r := v.Args[0].Reg()
+ i := v.Args[1].Reg()
+ p := gc.Prog(x86.ALEAL)
+ switch v.Op {
+ case ssa.Op386LEAL1:
+ p.From.Scale = 1
+ if i == x86.REG_SP {
+ r, i = i, r
+ }
+ case ssa.Op386LEAL2:
+ p.From.Scale = 2
+ case ssa.Op386LEAL4:
+ p.From.Scale = 4
+ case ssa.Op386LEAL8:
+ p.From.Scale = 8
+ }
+ p.From.Type = obj.TYPE_MEM
+ p.From.Reg = r
+ p.From.Index = i
+ gc.AddAux(&p.From, v)
+ p.To.Type = obj.TYPE_REG
+ p.To.Reg = v.Reg()
+ case ssa.Op386LEAL:
+ p := gc.Prog(x86.ALEAL)
+ 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.Op386CMPL, ssa.Op386CMPW, ssa.Op386CMPB,
+ ssa.Op386TESTL, ssa.Op386TESTW, ssa.Op386TESTB:
+ opregreg(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())
+ case ssa.Op386CMPLconst, ssa.Op386CMPWconst, ssa.Op386CMPBconst:
+ p := gc.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.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.From.Type = obj.TYPE_CONST
+ p.From.Offset = v.AuxInt
+ p.To.Type = obj.TYPE_REG
+ p.To.Reg = x
+ // If flags are live at this instruction, suppress the
+ // MOV $0,AX -> XOR AX,AX optimization.
+ if v.Aux != nil {
+ p.Mark |= x86.PRESERVEFLAGS
+ }
+ case ssa.Op386MOVSSconst, ssa.Op386MOVSDconst:
+ x := v.Reg()
+ p := gc.Prog(v.Op.Asm())
+ p.From.Type = obj.TYPE_FCONST
+ p.From.Val = math.Float64frombits(uint64(v.AuxInt))
+ p.To.Type = obj.TYPE_REG
+ p.To.Reg = x
+ case ssa.Op386MOVSSconst1, ssa.Op386MOVSDconst1:
+ var literal string
+ if v.Op == ssa.Op386MOVSDconst1 {
+ literal = fmt.Sprintf("$f64.%016x", uint64(v.AuxInt))
+ } else {
+ literal = fmt.Sprintf("$f32.%08x", math.Float32bits(float32(math.Float64frombits(uint64(v.AuxInt)))))
+ }
+ 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.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.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.From.Type = obj.TYPE_MEM
+ p.From.Reg = v.Args[0].Reg()
+ gc.AddAux(&p.From, v)
+ p.From.Scale = 8
+ p.From.Index = v.Args[1].Reg()
+ p.To.Type = obj.TYPE_REG
+ p.To.Reg = v.Reg()
+ case ssa.Op386MOVLloadidx4, ssa.Op386MOVSSloadidx4:
+ p := gc.Prog(v.Op.Asm())
+ p.From.Type = obj.TYPE_MEM
+ p.From.Reg = v.Args[0].Reg()
+ gc.AddAux(&p.From, v)
+ p.From.Scale = 4
+ p.From.Index = v.Args[1].Reg()
+ p.To.Type = obj.TYPE_REG
+ p.To.Reg = v.Reg()
+ case ssa.Op386MOVWloadidx2:
+ p := gc.Prog(v.Op.Asm())
+ p.From.Type = obj.TYPE_MEM
+ p.From.Reg = v.Args[0].Reg()
+ gc.AddAux(&p.From, v)
+ p.From.Scale = 2
+ p.From.Index = v.Args[1].Reg()
+ p.To.Type = obj.TYPE_REG
+ p.To.Reg = v.Reg()
+ case ssa.Op386MOVBloadidx1, ssa.Op386MOVWloadidx1, ssa.Op386MOVLloadidx1, ssa.Op386MOVSSloadidx1, ssa.Op386MOVSDloadidx1:
+ r := v.Args[0].Reg()
+ i := v.Args[1].Reg()
+ if i == x86.REG_SP {
+ r, i = i, r
+ }
+ p := gc.Prog(v.Op.Asm())
+ p.From.Type = obj.TYPE_MEM
+ p.From.Reg = r
+ p.From.Scale = 1
+ p.From.Index = i
+ gc.AddAux(&p.From, v)
+ p.To.Type = obj.TYPE_REG
+ p.To.Reg = v.Reg()
+ case ssa.Op386MOVSSstore, ssa.Op386MOVSDstore, ssa.Op386MOVLstore, ssa.Op386MOVWstore, ssa.Op386MOVBstore:
+ p := gc.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.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()
+ p.To.Scale = 8
+ p.To.Index = v.Args[1].Reg()
+ gc.AddAux(&p.To, v)
+ case ssa.Op386MOVSSstoreidx4, ssa.Op386MOVLstoreidx4:
+ p := gc.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()
+ p.To.Scale = 4
+ p.To.Index = v.Args[1].Reg()
+ gc.AddAux(&p.To, v)
+ case ssa.Op386MOVWstoreidx2:
+ p := gc.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()
+ p.To.Scale = 2
+ p.To.Index = v.Args[1].Reg()
+ gc.AddAux(&p.To, v)
+ case ssa.Op386MOVBstoreidx1, ssa.Op386MOVWstoreidx1, ssa.Op386MOVLstoreidx1, ssa.Op386MOVSSstoreidx1, ssa.Op386MOVSDstoreidx1:
+ r := v.Args[0].Reg()
+ i := v.Args[1].Reg()
+ if i == x86.REG_SP {
+ r, i = i, r
+ }
+ p := gc.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 = r
+ p.To.Scale = 1
+ p.To.Index = i
+ gc.AddAux(&p.To, v)
+ case ssa.Op386MOVLstoreconst, ssa.Op386MOVWstoreconst, ssa.Op386MOVBstoreconst:
+ p := gc.Prog(v.Op.Asm())
+ p.From.Type = obj.TYPE_CONST
+ sc := v.AuxValAndOff()
+ p.From.Offset = sc.Val()
+ p.To.Type = obj.TYPE_MEM
+ p.To.Reg = 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.From.Type = obj.TYPE_CONST
+ sc := v.AuxValAndOff()
+ p.From.Offset = sc.Val()
+ r := v.Args[0].Reg()
+ i := v.Args[1].Reg()
+ switch v.Op {
+ case ssa.Op386MOVBstoreconstidx1, ssa.Op386MOVWstoreconstidx1, ssa.Op386MOVLstoreconstidx1:
+ p.To.Scale = 1
+ if i == x86.REG_SP {
+ r, i = i, r
+ }
+ case ssa.Op386MOVWstoreconstidx2:
+ p.To.Scale = 2
+ case ssa.Op386MOVLstoreconstidx4:
+ p.To.Scale = 4
+ }
+ p.To.Type = obj.TYPE_MEM
+ p.To.Reg = r
+ p.To.Index = i
+ gc.AddAux2(&p.To, v, sc.Off())
+ case ssa.Op386MOVWLSX, ssa.Op386MOVBLSX, ssa.Op386MOVWLZX, ssa.Op386MOVBLZX,
+ ssa.Op386CVTSL2SS, ssa.Op386CVTSL2SD,
+ ssa.Op386CVTTSS2SL, ssa.Op386CVTTSD2SL,
+ ssa.Op386CVTSS2SD, ssa.Op386CVTSD2SS:
+ opregreg(v.Op.Asm(), v.Reg(), v.Args[0].Reg())
+ case ssa.Op386DUFFZERO:
+ p := gc.Prog(obj.ADUFFZERO)
+ p.To.Type = obj.TYPE_ADDR
+ p.To.Sym = gc.Linksym(gc.Pkglookup("duffzero", gc.Runtimepkg))
+ p.To.Offset = v.AuxInt
+ case ssa.Op386DUFFCOPY:
+ p := gc.Prog(obj.ADUFFCOPY)
+ p.To.Type = obj.TYPE_ADDR
+ p.To.Sym = gc.Linksym(gc.Pkglookup("duffcopy", gc.Runtimepkg))
+ p.To.Offset = v.AuxInt
+
+ case ssa.OpCopy, ssa.Op386MOVLconvert: // TODO: use MOVLreg for reg->reg copies instead of OpCopy?
+ if v.Type.IsMemory() {
+ return
+ }
+ x := v.Args[0].Reg()
+ y := v.Reg()
+ if x != y {
+ opregreg(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))
+ gc.AddrAuto(&p.From, v.Args[0])
+ p.To.Type = obj.TYPE_REG
+ p.To.Reg = v.Reg()
+
+ case ssa.OpStoreReg:
+ if v.Type.IsFlags() {
+ v.Fatalf("store flags not implemented: %v", v.LongString())
+ return
+ }
+ p := gc.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)
+ case ssa.Op386LoweredGetG:
+ r := v.Reg()
+ // See the comments in cmd/internal/obj/x86/obj6.go
+ // near CanUse1InsnTLS for a detailed explanation of these instructions.
+ if x86.CanUse1InsnTLS(gc.Ctxt) {
+ // MOVL (TLS), r
+ p := gc.Prog(x86.AMOVL)
+ p.From.Type = obj.TYPE_MEM
+ p.From.Reg = x86.REG_TLS
+ p.To.Type = obj.TYPE_REG
+ p.To.Reg = r
+ } else {
+ // MOVL TLS, r
+ // MOVL (r)(TLS*1), r
+ p := gc.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.From.Type = obj.TYPE_MEM
+ q.From.Reg = r
+ q.From.Index = x86.REG_TLS
+ q.From.Scale = 1
+ q.To.Type = obj.TYPE_REG
+ q.To.Reg = r
+ }
+ case ssa.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.Op386NEGL,
+ ssa.Op386BSWAPL,
+ ssa.Op386NOTL:
+ r := v.Reg()
+ 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.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.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,
+ ssa.Op386SETGF, ssa.Op386SETGEF,
+ ssa.Op386SETB, ssa.Op386SETBE,
+ ssa.Op386SETORD, ssa.Op386SETNAN,
+ ssa.Op386SETA, ssa.Op386SETAE:
+ p := gc.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.To.Type = obj.TYPE_REG
+ p.To.Reg = v.Reg()
+ q := gc.Prog(x86.ASETPS)
+ q.To.Type = obj.TYPE_REG
+ q.To.Reg = x86.REG_AX
+ opregreg(x86.AORL, v.Reg(), x86.REG_AX)
+
+ case ssa.Op386SETEQF:
+ p := gc.Prog(v.Op.Asm())
+ p.To.Type = obj.TYPE_REG
+ p.To.Reg = v.Reg()
+ q := gc.Prog(x86.ASETPC)
+ q.To.Type = obj.TYPE_REG
+ q.To.Reg = x86.REG_AX
+ opregreg(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)
+ 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)
+ 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).
+ // Should we use the 3-byte TESTB $0, (reg) instead? It is larger
+ // but it doesn't have false dependency on AX.
+ // Or maybe allocate an output register and use MOVL (reg),reg2 ?
+ // That trades clobbering flags for clobbering a register.
+ p := gc.Prog(x86.ATESTB)
+ p.From.Type = obj.TYPE_REG
+ p.From.Reg = x86.REG_AX
+ p.To.Type = obj.TYPE_MEM
+ p.To.Reg = 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")
+ }
+ case ssa.Op386FCHS:
+ v.Fatalf("FCHS in non-387 mode")
+ default:
+ v.Fatalf("genValue not implemented: %s", v.LongString())
+ }
+}
+
+var blockJump = [...]struct {
+ asm, invasm obj.As
+}{
+ ssa.Block386EQ: {x86.AJEQ, x86.AJNE},
+ ssa.Block386NE: {x86.AJNE, x86.AJEQ},
+ ssa.Block386LT: {x86.AJLT, x86.AJGE},
+ ssa.Block386GE: {x86.AJGE, x86.AJLT},
+ ssa.Block386LE: {x86.AJLE, x86.AJGT},
+ ssa.Block386GT: {x86.AJGT, x86.AJLE},
+ ssa.Block386ULT: {x86.AJCS, x86.AJCC},
+ ssa.Block386UGE: {x86.AJCC, x86.AJCS},
+ ssa.Block386UGT: {x86.AJHI, x86.AJLS},
+ ssa.Block386ULE: {x86.AJLS, x86.AJHI},
+ ssa.Block386ORD: {x86.AJPC, x86.AJPS},
+ ssa.Block386NAN: {x86.AJPS, x86.AJPC},
+}
+
+var eqfJumps = [2][2]gc.FloatingEQNEJump{
+ {{Jump: x86.AJNE, Index: 1}, {Jump: x86.AJPS, Index: 1}}, // next == b.Succs[0]
+ {{Jump: x86.AJNE, Index: 1}, {Jump: x86.AJPC, Index: 0}}, // next == b.Succs[1]
+}
+var nefJumps = [2][2]gc.FloatingEQNEJump{
+ {{Jump: x86.AJNE, Index: 0}, {Jump: x86.AJPC, Index: 1}}, // next == b.Succs[0]
+ {{Jump: x86.AJNE, Index: 0}, {Jump: x86.AJPS, Index: 0}}, // next == b.Succs[1]
+}
+
+func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) {
+ s.SetLineno(b.Line)
+
+ 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.To.Type = obj.TYPE_BRANCH
+ s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()})
+ }
+ case ssa.BlockDefer:
+ // defer returns in rax:
+ // 0 if we should continue executing
+ // 1 if we should jump to deferreturn call
+ p := gc.Prog(x86.ATESTL)
+ p.From.Type = obj.TYPE_REG
+ p.From.Reg = x86.REG_AX
+ p.To.Type = obj.TYPE_REG
+ p.To.Reg = x86.REG_AX
+ p = gc.Prog(x86.AJNE)
+ p.To.Type = obj.TYPE_BRANCH
+ s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[1].Block()})
+ if b.Succs[0].Block() != next {
+ p := gc.Prog(obj.AJMP)
+ p.To.Type = obj.TYPE_BRANCH
+ s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()})
+ }
+ case ssa.BlockExit:
+ gc.Prog(obj.AUNDEF) // tell plive.go that we never reach here
+ case ssa.BlockRet:
+ gc.Prog(obj.ARET)
+ case ssa.BlockRetJmp:
+ p := gc.Prog(obj.AJMP)
+ p.To.Type = obj.TYPE_MEM
+ p.To.Name = obj.NAME_EXTERN
+ p.To.Sym = gc.Linksym(b.Aux.(*gc.Sym))
+
+ case ssa.Block386EQF:
+ gc.SSAGenFPJump(s, b, next, &eqfJumps)
+
+ case ssa.Block386NEF:
+ gc.SSAGenFPJump(s, b, next, &nefJumps)
+
+ case ssa.Block386EQ, ssa.Block386NE,
+ ssa.Block386LT, ssa.Block386GE,
+ ssa.Block386LE, ssa.Block386GT,
+ 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.To.Type = obj.TYPE_BRANCH
+ s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[1].Block()})
+ case b.Succs[1].Block():
+ p = gc.Prog(jmp.asm)
+ p.To.Type = obj.TYPE_BRANCH
+ s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()})
+ default:
+ p = gc.Prog(jmp.asm)
+ p.To.Type = obj.TYPE_BRANCH
+ s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()})
+ q := gc.Prog(obj.AJMP)
+ q.To.Type = obj.TYPE_BRANCH
+ s.Branches = append(s.Branches, gc.Branch{P: q, B: b.Succs[1].Block()})
+ }
+
+ // liblink reorders the instruction stream as it sees fit.
+ // Pass along what we know so liblink can make use of it.
+ // TODO: Once we've fully switched to SSA,
+ // make liblink leave our output alone.
+ switch likely {
+ case ssa.BranchUnlikely:
+ p.From.Type = obj.TYPE_CONST
+ p.From.Offset = 0
+ case ssa.BranchLikely:
+ p.From.Type = obj.TYPE_CONST
+ p.From.Offset = 1
+ }
+
+ default:
+ b.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 8b8161e..c3c0b6a 100644
--- a/src/cmd/compile/main.go
+++ b/src/cmd/compile/main.go
@@ -8,6 +8,8 @@ import (
"cmd/compile/internal/amd64"
"cmd/compile/internal/arm"
"cmd/compile/internal/arm64"
+ "cmd/compile/internal/gc"
+ "cmd/compile/internal/mips"
"cmd/compile/internal/mips64"
"cmd/compile/internal/ppc64"
"cmd/compile/internal/s390x"
@@ -23,23 +25,28 @@ func main() {
log.SetFlags(0)
log.SetPrefix("compile: ")
- switch obj.Getgoarch() {
+ switch obj.GOARCH {
default:
- fmt.Fprintf(os.Stderr, "compile: unknown architecture %q\n", obj.Getgoarch())
+ fmt.Fprintf(os.Stderr, "compile: unknown architecture %q\n", obj.GOARCH)
os.Exit(2)
case "386":
- x86.Main()
+ x86.Init()
case "amd64", "amd64p32":
- amd64.Main()
+ amd64.Init()
case "arm":
- arm.Main()
+ arm.Init()
case "arm64":
- arm64.Main()
+ arm64.Init()
+ case "mips", "mipsle":
+ mips.Init()
case "mips64", "mips64le":
- mips64.Main()
+ mips64.Init()
case "ppc64", "ppc64le":
- ppc64.Main()
+ ppc64.Init()
case "s390x":
- s390x.Main()
+ s390x.Init()
}
+
+ gc.Main()
+ gc.Exit(0)
}
diff --git a/src/cmd/cover/cover.go b/src/cmd/cover/cover.go
index a9ed66e..b7d9125 100644
--- a/src/cmd/cover/cover.go
+++ b/src/cmd/cover/cover.go
@@ -168,13 +168,13 @@ func (f *File) Visit(node ast.Node) ast.Visitor {
case *ast.CaseClause: // switch
for _, n := range n.List {
clause := n.(*ast.CaseClause)
- clause.Body = f.addCounters(clause.Pos(), clause.End(), clause.Body, false)
+ clause.Body = f.addCounters(clause.Colon+1, clause.End(), clause.Body, false)
}
return f
case *ast.CommClause: // select
for _, n := range n.List {
clause := n.(*ast.CommClause)
- clause.Body = f.addCounters(clause.Pos(), clause.End(), clause.Body, false)
+ clause.Body = f.addCounters(clause.Colon+1, clause.End(), clause.Body, false)
}
return f
}
@@ -240,6 +240,18 @@ func (f *File) Visit(node ast.Node) ast.Visitor {
ast.Walk(f, n.Assign)
return nil
}
+ case *ast.CommentGroup:
+ var list []*ast.Comment
+ // Drop all but the //go: comments, some of which are semantically important.
+ // We drop all others because they can appear in places that cause our counters
+ // to appear in syntactically incorrect places. //go: appears at the beginning of
+ // the line and is syntactically safe.
+ for _, c := range n.List {
+ if strings.HasPrefix(c.Text, "//go:") && f.fset.Position(c.Slash).Column == 1 {
+ list = append(list, c)
+ }
+ }
+ n.List = list
}
return f
}
@@ -348,7 +360,8 @@ func annotate(name string) {
if err != nil {
log.Fatalf("cover: %s: %s", name, err)
}
- parsedFile.Comments = trimComments(parsedFile, fset)
+ // Remove comments. Or else they interfere with new AST.
+ parsedFile.Comments = nil
file := &File{
fset: fset,
@@ -374,26 +387,6 @@ func annotate(name string) {
file.addVariables(fd)
}
-// trimComments drops all but the //go: comments, some of which are semantically important.
-// We drop all others because they can appear in places that cause our counters
-// to appear in syntactically incorrect places. //go: appears at the beginning of
-// the line and is syntactically safe.
-func trimComments(file *ast.File, fset *token.FileSet) []*ast.CommentGroup {
- var comments []*ast.CommentGroup
- for _, group := range file.Comments {
- var list []*ast.Comment
- for _, comment := range group.List {
- if strings.HasPrefix(comment.Text, "//go:") && fset.Position(comment.Slash).Column == 1 {
- list = append(list, comment)
- }
- }
- if list != nil {
- comments = append(comments, &ast.CommentGroup{List: list})
- }
- }
- return comments
-}
-
func (f *File) print(w io.Writer) {
printer.Fprint(w, f.fset, f.astFile)
}
@@ -488,10 +481,35 @@ func (f *File) addCounters(pos, blockEnd token.Pos, list []ast.Stmt, extendToClo
var last int
end := blockEnd
for last = 0; last < len(list); last++ {
- end = f.statementBoundary(list[last])
- if f.endsBasicSourceBlock(list[last]) {
- extendToClosingBrace = false // Block is broken up now.
+ stmt := list[last]
+ end = f.statementBoundary(stmt)
+ if f.endsBasicSourceBlock(stmt) {
+ // If it is a labeled statement, we need to place a counter between
+ // the label and its statement because it may be the target of a goto
+ // and thus start a basic block. That is, given
+ // foo: stmt
+ // we need to create
+ // foo: ; stmt
+ // and mark the label as a block-terminating statement.
+ // The result will then be
+ // foo: COUNTER[n]++; stmt
+ // However, we can't do this if the labeled statement is already
+ // a control statement, such as a labeled for.
+ if label, isLabel := stmt.(*ast.LabeledStmt); isLabel && !f.isControl(label.Stmt) {
+ newLabel := *label
+ newLabel.Stmt = &ast.EmptyStmt{
+ Semicolon: label.Stmt.Pos(),
+ Implicit: true,
+ }
+ end = label.Pos() // Previous block ends before the label.
+ list[last] = &newLabel
+ // Open a gap and drop in the old statement, now without a label.
+ list = append(list, nil)
+ copy(list[last+1:], list[last:])
+ list[last+1] = label.Stmt
+ }
last++
+ extendToClosingBrace = false // Block is broken up now.
break
}
}
@@ -610,7 +628,7 @@ func (f *File) endsBasicSourceBlock(s ast.Stmt) bool {
case *ast.IfStmt:
return true
case *ast.LabeledStmt:
- return f.endsBasicSourceBlock(s.Stmt)
+ return true // A goto may branch here, starting a new basic block.
case *ast.RangeStmt:
return true
case *ast.SwitchStmt:
@@ -634,6 +652,16 @@ func (f *File) endsBasicSourceBlock(s ast.Stmt) bool {
return found
}
+// isControl reports whether s is a control statement that, if labeled, cannot be
+// separated from its label.
+func (f *File) isControl(s ast.Stmt) bool {
+ switch s.(type) {
+ case *ast.ForStmt, *ast.RangeStmt, *ast.SwitchStmt, *ast.SelectStmt, *ast.TypeSwitchStmt:
+ return true
+ }
+ return false
+}
+
// funcLitFinder implements the ast.Visitor pattern to find the location of any
// function literal in a subtree.
type funcLitFinder token.Pos
diff --git a/src/cmd/cover/cover_test.go b/src/cmd/cover/cover_test.go
index 68e9e9f..50a7ce8 100644
--- a/src/cmd/cover/cover_test.go
+++ b/src/cmd/cover/cover_test.go
@@ -12,6 +12,7 @@ import (
"os"
"os/exec"
"path/filepath"
+ "regexp"
"testing"
)
@@ -62,14 +63,14 @@ func TestCover(t *testing.T) {
}
// go build -o testcover
- cmd := exec.Command("go", "build", "-o", testcover)
+ cmd := exec.Command(testenv.GoToolPath(t), "build", "-o", testcover)
run(cmd, t)
// defer removal of testcover
defer os.Remove(testcover)
- // ./testcover -mode=count -var=coverTest -o ./testdata/test_cover.go testdata/test_line.go
- cmd = exec.Command(testcover, "-mode=count", "-var=coverTest", "-o", coverOutput, coverInput)
+ // ./testcover -mode=count -var=thisNameMustBeVeryLongToCauseOverflowOfCounterIncrementStatementOntoNextLineForTest -o ./testdata/test_cover.go testdata/test_line.go
+ cmd = exec.Command(testcover, "-mode=count", "-var=thisNameMustBeVeryLongToCauseOverflowOfCounterIncrementStatementOntoNextLineForTest", "-o", coverOutput, coverInput)
run(cmd, t)
// defer removal of ./testdata/test_cover.go
@@ -78,8 +79,22 @@ func TestCover(t *testing.T) {
}
// go run ./testdata/main.go ./testdata/test.go
- cmd = exec.Command("go", "run", testMain, coverOutput)
+ cmd = exec.Command(testenv.GoToolPath(t), "run", testMain, coverOutput)
run(cmd, t)
+
+ file, err = ioutil.ReadFile(coverOutput)
+ if err != nil {
+ t.Fatal(err)
+ }
+ // compiler directive must appear right next to function declaration.
+ if got, err := regexp.MatchString(".*\n//go:nosplit\nfunc someFunction().*", string(file)); err != nil || !got {
+ t.Errorf("misplaced compiler directive: got=(%v, %v); want=(true; nil)", got, err)
+ }
+ // No other comments should be present in generated code.
+ c := ".*// This comment shouldn't appear in generated go code.*"
+ if got, err := regexp.MatchString(c, string(file)); err != nil || got {
+ t.Errorf("non compiler directive comment %q found. got=(%v, %v); want=(false; nil)", c, got, err)
+ }
}
func run(c *exec.Cmd, t *testing.T) {
diff --git a/src/cmd/cover/html.go b/src/cmd/cover/html.go
index d0ac447..04dc76f 100644
--- a/src/cmd/cover/html.go
+++ b/src/cmd/cover/html.go
@@ -7,15 +7,14 @@ package main
import (
"bufio"
"bytes"
+ "cmd/internal/browser"
"fmt"
"html/template"
"io"
"io/ioutil"
"math"
"os"
- "os/exec"
"path/filepath"
- "runtime"
)
// htmlOutput reads the profile data from profile and generates an HTML
@@ -65,16 +64,19 @@ func htmlOutput(profile, outfile string) error {
} else {
out, err = os.Create(outfile)
}
+ if err != nil {
+ return err
+ }
err = htmlTemplate.Execute(out, d)
- if err == nil {
- err = out.Close()
+ if err2 := out.Close(); err == nil {
+ err = err2
}
if err != nil {
return err
}
if outfile == "" {
- if !startBrowser("file://" + out.Name()) {
+ if !browser.Open("file://" + out.Name()) {
fmt.Fprintf(os.Stderr, "HTML output written to %s\n", out.Name())
}
}
@@ -133,23 +135,6 @@ func htmlGen(w io.Writer, src []byte, boundaries []Boundary) error {
return dst.Flush()
}
-// startBrowser tries to open the URL in a browser
-// and reports whether it succeeds.
-func startBrowser(url string) bool {
- // try to start the browser
- var args []string
- switch runtime.GOOS {
- case "darwin":
- args = []string{"open"}
- case "windows":
- args = []string{"cmd", "/c", "start"}
- default:
- args = []string{"xdg-open"}
- }
- cmd := exec.Command(args[0], append(args[1:], url)...)
- return cmd.Start() == nil
-}
-
// rgb returns an rgb value for the specified coverage value
// between 0 (no coverage) and 10 (max coverage).
func rgb(n int) string {
diff --git a/src/cmd/cover/profile.go b/src/cmd/cover/profile.go
index a03b5d5..5628b91 100644
--- a/src/cmd/cover/profile.go
+++ b/src/cmd/cover/profile.go
@@ -93,6 +93,29 @@ func ParseProfiles(fileName string) ([]*Profile, error) {
}
for _, p := range files {
sort.Sort(blocksByStart(p.Blocks))
+ // Merge samples from the same location.
+ j := 1
+ for i := 1; i < len(p.Blocks); i++ {
+ b := p.Blocks[i]
+ last := p.Blocks[j-1]
+ if b.StartLine == last.StartLine &&
+ b.StartCol == last.StartCol &&
+ b.EndLine == last.EndLine &&
+ b.EndCol == last.EndCol {
+ if b.NumStmt != last.NumStmt {
+ return nil, fmt.Errorf("inconsistent NumStmt: changed from %d to %d", last.NumStmt, b.NumStmt)
+ }
+ if mode == "set" {
+ p.Blocks[j-1].Count |= b.Count
+ } else {
+ p.Blocks[j-1].Count += b.Count
+ }
+ continue
+ }
+ p.Blocks[j] = b
+ j++
+ }
+ p.Blocks = p.Blocks[:j]
}
// Generate a sorted slice.
profiles := make([]*Profile, 0, len(files))
diff --git a/src/cmd/cover/testdata/main.go b/src/cmd/cover/testdata/main.go
index 6ed39c4..be74b4a 100644
--- a/src/cmd/cover/testdata/main.go
+++ b/src/cmd/cover/testdata/main.go
@@ -3,7 +3,8 @@
// license that can be found in the LICENSE file.
// Test runner for coverage test. This file is not coverage-annotated; test.go is.
-// It knows the coverage counter is called "coverTest".
+// It knows the coverage counter is called
+// "thisNameMustBeVeryLongToCauseOverflowOfCounterIncrementStatementOntoNextLineForTest".
package main
@@ -24,6 +25,9 @@ type block struct {
var counters = make(map[block]bool)
+// shorthand for the long counter variable.
+var coverTest = &thisNameMustBeVeryLongToCauseOverflowOfCounterIncrementStatementOntoNextLineForTest
+
// check records the location and expected value for a counter.
func check(line, count uint32) {
b := block{
diff --git a/src/cmd/cover/testdata/test.go b/src/cmd/cover/testdata/test.go
index c4c0e15..61b40ea 100644
--- a/src/cmd/cover/testdata/test.go
+++ b/src/cmd/cover/testdata/test.go
@@ -25,6 +25,7 @@ func testAll() {
testPanic()
testEmptySwitches()
testFunctionLiteral()
+ testGoto()
}
// The indexes of the counters in testPanic are known to main.go
@@ -245,4 +246,46 @@ func testFunctionLiteral() {
check(LINE, 2)
}) {
}
+
+ x := 2
+ switch x {
+ case func() int { check(LINE, 1); return 1 }():
+ check(LINE, 0)
+ panic("2=1")
+ case func() int { check(LINE, 1); return 2 }():
+ check(LINE, 1)
+ case func() int { check(LINE, 0); return 3 }():
+ check(LINE, 0)
+ panic("2=3")
+ }
+}
+
+func testGoto() {
+ for i := 0; i < 2; i++ {
+ if i == 0 {
+ goto Label
+ }
+ check(LINE, 1)
+ Label:
+ check(LINE, 2)
+ }
+ // Now test that we don't inject empty statements
+ // between a label and a loop.
+loop:
+ for {
+ check(LINE, 1)
+ break loop
+ }
+}
+
+// This comment shouldn't appear in generated go code.
+func haha() {
+ // Needed for cover to add counter increment here.
+ _ = 42
+}
+
+// Some someFunction.
+//
+//go:nosplit
+func someFunction() {
}
diff --git a/src/cmd/dist/build.go b/src/cmd/dist/build.go
index 9eb9caf..6fb7884 100644
--- a/src/cmd/dist/build.go
+++ b/src/cmd/dist/build.go
@@ -21,30 +21,31 @@ import (
// The usual variables.
var (
- goarch string
- gobin string
- gohostarch string
- gohostos string
- goos string
- goarm string
- go386 string
- goroot string
- goroot_final string
- goextlinkenabled string
- gogcflags string // For running built compiler
- workdir string
- tooldir string
- oldgoos string
- oldgoarch string
- slash string
- exe string
- defaultcc string
- defaultcflags string
- defaultldflags string
- defaultcxxtarget string
- defaultcctarget string
- rebuildall bool
- defaultclang bool
+ goarch string
+ gobin string
+ gohostarch string
+ gohostos string
+ goos string
+ goarm string
+ go386 string
+ goroot string
+ goroot_final string
+ goextlinkenabled string
+ gogcflags string // For running built compiler
+ workdir string
+ tooldir string
+ oldgoos string
+ oldgoarch string
+ slash string
+ exe string
+ defaultcc string
+ defaultcflags string
+ defaultldflags string
+ defaultcxxtarget string
+ defaultcctarget string
+ defaultpkgconfigtarget string
+ rebuildall bool
+ defaultclang bool
vflag int // verbosity
)
@@ -56,6 +57,8 @@ var okgoarch = []string{
"amd64p32",
"arm",
"arm64",
+ "mips",
+ "mipsle",
"mips64",
"mips64le",
"ppc64",
@@ -208,6 +211,12 @@ func xinit() {
}
defaultcxxtarget = b
+ b = os.Getenv("PKG_CONFIG")
+ if b == "" {
+ b = "pkg-config"
+ }
+ defaultpkgconfigtarget = b
+
// For tools being invoked but also for os.ExpandEnv.
os.Setenv("GO386", go386)
os.Setenv("GOARCH", goarch)
@@ -1098,6 +1107,8 @@ var cgoEnabled = map[string]bool{
"linux/arm64": true,
"linux/ppc64": false,
"linux/ppc64le": true,
+ "linux/mips": false,
+ "linux/mipsle": false,
"linux/mips64": true,
"linux/mips64le": true,
"linux/s390x": true,
diff --git a/src/cmd/dist/buildgo.go b/src/cmd/dist/buildgo.go
index 3fab235..27976fb 100644
--- a/src/cmd/dist/buildgo.go
+++ b/src/cmd/dist/buildgo.go
@@ -7,6 +7,7 @@ package main
import (
"bytes"
"fmt"
+ "os"
"sort"
)
@@ -19,6 +20,7 @@ import (
// package main
// const defaultCC = <defaultcc>
// const defaultCXX = <defaultcxx>
+// const defaultPkgConfig = <defaultpkgconfig>
//
// It is invoked to write cmd/go/zdefaultcc.go
// but we also write cmd/cgo/zdefaultcc.go
@@ -29,8 +31,9 @@ func mkzdefaultcc(dir, file string) {
"package main\n"+
"\n"+
"const defaultCC = `%s`\n"+
- "const defaultCXX = `%s`\n",
- defaultcctarget, defaultcxxtarget)
+ "const defaultCXX = `%s`\n"+
+ "const defaultPkgConfig = `%s`\n",
+ defaultcctarget, defaultcxxtarget, defaultpkgconfigtarget)
writefile(out, file, writeSkipSame)
@@ -83,7 +86,8 @@ func mkzcgo(dir, file string) {
"\n"+
"package build\n"+
"\n"+
- "var cgoEnabled = map[string]bool{\n")
+ "const defaultCGO_ENABLED = %q\n\n"+
+ "var cgoEnabled = map[string]bool{\n", os.Getenv("CGO_ENABLED"))
for _, plat := range list {
fmt.Fprintf(&buf, "\t%q: true,\n", plat)
}
diff --git a/src/cmd/dist/buildtool.go b/src/cmd/dist/buildtool.go
index a535316..b0b9b25 100644
--- a/src/cmd/dist/buildtool.go
+++ b/src/cmd/dist/buildtool.go
@@ -18,46 +18,62 @@ import (
// bootstrapDirs is a list of directories holding code that must be
// compiled with a Go 1.4 toolchain to produce the bootstrapTargets.
-// All directories in this list are relative to and must be below $GOROOT/src/cmd.
-// The list is assumed to have two kinds of entries: names without slashes,
-// which are commands, and entries beginning with internal/, which are
-// packages supporting the commands.
+// All directories in this list are relative to and must be below $GOROOT/src.
+//
+// The list has have two kinds of entries: names beginning with cmd/ with
+// no other slashes, which are commands, and other paths, which are packages
+// supporting the commands. Packages in the standard library can be listed
+// if a newer copy needs to be substituted for the Go 1.4 copy when used
+// by the command packages.
+// These will be imported during bootstrap as bootstrap/name, like bootstrap/math/big.
var bootstrapDirs = []string{
- "asm",
- "asm/internal/arch",
- "asm/internal/asm",
- "asm/internal/flags",
- "asm/internal/lex",
- "compile",
- "compile/internal/amd64",
- "compile/internal/arm",
- "compile/internal/arm64",
- "compile/internal/big",
- "compile/internal/gc",
- "compile/internal/mips64",
- "compile/internal/ppc64",
- "compile/internal/ssa",
- "compile/internal/x86",
- "compile/internal/s390x",
- "internal/bio",
- "internal/gcprog",
- "internal/obj",
- "internal/obj/arm",
- "internal/obj/arm64",
- "internal/obj/mips",
- "internal/obj/ppc64",
- "internal/obj/s390x",
- "internal/obj/x86",
- "internal/sys",
- "link",
- "link/internal/amd64",
- "link/internal/arm",
- "link/internal/arm64",
- "link/internal/ld",
- "link/internal/mips64",
- "link/internal/ppc64",
- "link/internal/s390x",
- "link/internal/x86",
+ "cmd/asm",
+ "cmd/asm/internal/arch",
+ "cmd/asm/internal/asm",
+ "cmd/asm/internal/flags",
+ "cmd/asm/internal/lex",
+ "cmd/compile",
+ "cmd/compile/internal/amd64",
+ "cmd/compile/internal/arm",
+ "cmd/compile/internal/arm64",
+ "cmd/compile/internal/gc",
+ "cmd/compile/internal/mips",
+ "cmd/compile/internal/mips64",
+ "cmd/compile/internal/ppc64",
+ "cmd/compile/internal/s390x",
+ "cmd/compile/internal/ssa",
+ "cmd/compile/internal/syntax",
+ "cmd/compile/internal/x86",
+ "cmd/internal/bio",
+ "cmd/internal/gcprog",
+ "cmd/internal/dwarf",
+ "cmd/internal/obj",
+ "cmd/internal/obj/arm",
+ "cmd/internal/obj/arm64",
+ "cmd/internal/obj/mips",
+ "cmd/internal/obj/ppc64",
+ "cmd/internal/obj/s390x",
+ "cmd/internal/obj/x86",
+ "cmd/internal/sys",
+ "cmd/link",
+ "cmd/link/internal/amd64",
+ "cmd/link/internal/arm",
+ "cmd/link/internal/arm64",
+ "cmd/link/internal/ld",
+ "cmd/link/internal/mips",
+ "cmd/link/internal/mips64",
+ "cmd/link/internal/ppc64",
+ "cmd/link/internal/s390x",
+ "cmd/link/internal/x86",
+ "debug/pe",
+ "math/big",
+}
+
+// File suffixes that use build tags introduced since Go 1.4.
+// These must not be copied into the bootstrap build directory.
+var ignoreSuffixes = []string{
+ "_arm64.s",
+ "_arm64.go",
}
func bootstrapBuildTools() {
@@ -81,10 +97,16 @@ func bootstrapBuildTools() {
// Copy source code into $GOROOT/pkg/bootstrap and rewrite import paths.
for _, dir := range bootstrapDirs {
- src := pathf("%s/src/cmd/%s", goroot, dir)
+ src := pathf("%s/src/%s", goroot, dir)
dst := pathf("%s/%s", base, dir)
xmkdirall(dst)
+ Dir:
for _, name := range xreaddirfiles(src) {
+ for _, suf := range ignoreSuffixes {
+ if strings.HasSuffix(name, suf) {
+ continue Dir
+ }
+ }
srcFile := pathf("%s/%s", src, name)
text := readfile(srcFile)
text = bootstrapFixImports(text, srcFile)
@@ -119,10 +141,16 @@ func bootstrapBuildTools() {
// Run Go 1.4 to build binaries. Use -gcflags=-l to disable inlining to
// workaround bugs in Go 1.4's compiler. See discussion thread:
// https://groups.google.com/d/msg/golang-dev/Ss7mCKsvk8w/Gsq7VYI0AwAJ
- run(workspace, ShowOutput|CheckExit, pathf("%s/bin/go", goroot_bootstrap), "install", "-gcflags=-l", "-v", "bootstrap/...")
+ // 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/...")
// Copy binaries into tool binary directory.
for _, name := range bootstrapDirs {
+ if !strings.HasPrefix(name, "cmd/") {
+ continue
+ }
+ name = name[len("cmd/"):]
if !strings.Contains(name, "/") {
copyfile(pathf("%s/%s%s", tooldir, name, exe), pathf("%s/bin/%s%s", workspace, name, exe), writeExec)
}
@@ -145,7 +173,14 @@ func bootstrapFixImports(text, srcFile string) string {
}
if strings.HasPrefix(line, `import "`) || strings.HasPrefix(line, `import . "`) ||
inBlock && (strings.HasPrefix(line, "\t\"") || strings.HasPrefix(line, "\t. \"")) {
- lines[i] = strings.Replace(line, `"cmd/`, `"bootstrap/`, -1)
+ line = strings.Replace(line, `"cmd/`, `"bootstrap/cmd/`, -1)
+ for _, dir := range bootstrapDirs {
+ if strings.HasPrefix(dir, "cmd/") {
+ continue
+ }
+ line = strings.Replace(line, `"`+dir+`"`, `"bootstrap/`+dir+`"`, -1)
+ }
+ lines[i] = line
}
}
diff --git a/src/cmd/dist/deps.go b/src/cmd/dist/deps.go
index e8dd6cf..817484f 100644
--- a/src/cmd/dist/deps.go
+++ b/src/cmd/dist/deps.go
@@ -7,7 +7,7 @@ var builddeps = map[string][]string{
"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": {"runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort"},
+ "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"},
@@ -35,7 +35,7 @@ var builddeps = map[string][]string{
"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", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "time", "unicode", "unicode/utf16", "unicode/utf8"},
+ "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"},
@@ -43,14 +43,14 @@ var builddeps = map[string][]string{
"os/exec": {"bytes", "context", "errors", "fmt", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "math", "os", "path/filepath", "reflect", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "syscall", "time", "unicode", "unicode/utf16", "unicode/utf8"},
"os/signal": {"errors", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "os", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sync", "sync/atomic", "syscall", "time", "unicode/utf16", "unicode/utf8"},
"path": {"errors", "internal/race", "io", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "strings", "sync", "sync/atomic", "unicode", "unicode/utf8"},
- "path/filepath": {"errors", "internal/race", "internal/syscall/windows", "internal/syscall/windows/registry", "internal/syscall/windows/sysdll", "io", "os", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strings", "sync", "sync/atomic", "syscall", "time", "unicode", "unicode/utf16", "unicode/utf8"},
+ "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", "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", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sort", "strconv", "strings", "sync", "sync/atomic", "unicode", "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"},
"runtime": {"runtime/internal/atomic", "runtime/internal/sys"},
"runtime/internal/atomic": {"runtime/internal/sys"},
"runtime/internal/sys": {},
- "sort": {"runtime", "runtime/internal/atomic", "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"},
"sync": {"internal/race", "runtime", "runtime/internal/atomic", "runtime/internal/sys", "sync/atomic"},
diff --git a/src/cmd/dist/test.go b/src/cmd/dist/test.go
index e56d108..508863f 100644
--- a/src/cmd/dist/test.go
+++ b/src/cmd/dist/test.go
@@ -9,6 +9,7 @@ import (
"errors"
"flag"
"fmt"
+ "io/ioutil"
"log"
"os"
"os/exec"
@@ -328,6 +329,21 @@ func (t *tester) registerRaceBenchTest(pkg string) {
}
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
+ },
+ })
+ return
+ }
+
// Fast path to avoid the ~1 second of `go list std cmd` when
// the caller lists specific tests to run. (as the continuous
// build coordinator does).
@@ -351,7 +367,7 @@ func (t *tester) registerTests() {
if !t.race {
cmd.Args = append(cmd.Args, "cmd")
}
- all, err := cmd.CombinedOutput()
+ all, err := cmd.Output()
if err != nil {
log.Fatalf("Error running go list std cmd: %v, %s", err, all)
}
@@ -361,7 +377,9 @@ func (t *tester) registerTests() {
}
if t.race {
for _, pkg := range pkgs {
- t.registerRaceBenchTest(pkg)
+ if t.packageHasBenchmarks(pkg) {
+ t.registerRaceBenchTest(pkg)
+ }
}
}
}
@@ -391,9 +409,7 @@ func (t *tester) registerTests() {
// release on a system that does not have a C compiler
// installed and still build Go programs (that don't use cgo).
for _, pkg := range cgoPackages {
-
- // Internal linking is not currently supported on Dragonfly.
- if t.goos == "dragonfly" {
+ if !t.internalLink() {
break
}
@@ -402,11 +418,6 @@ func (t *tester) registerTests() {
break
}
- // Darwin/Android ARM64 fails with internal linking.
- if (t.goos == "darwin" || t.goos == "android") && t.goarch == "arm64" {
- break
- }
-
pkg := pkg
var run string
if pkg == "net" {
@@ -422,6 +433,18 @@ func (t *tester) registerTests() {
})
}
+ // Test internal linking of PIE binaries where it is supported.
+ if t.goos == "linux" && t.goarch == "amd64" {
+ t.tests = append(t.tests, distTest{
+ name: "pie_internal",
+ heading: "internal linking of -buildmode=pie",
+ fn: func(dt *distTest) error {
+ t.addCmd(dt, "src", "go", "test", "reflect", "-short", "-buildmode=pie", "-ldflags=-linkmode=internal", t.timeout(60), t.tags(), t.runFlag(""))
+ return nil
+ },
+ })
+ }
+
// sync tests
t.tests = append(t.tests, distTest{
name: "sync_cpu",
@@ -502,7 +525,7 @@ func (t *tester) registerTests() {
})
}
if t.supportedBuildmode("c-archive") {
- t.registerHostTest("testcarchive", "misc/cgo/testcarchive", "carchive_test.go")
+ t.registerHostTest("testcarchive", "../misc/cgo/testcarchive", "misc/cgo/testcarchive", "carchive_test.go")
}
if t.supportedBuildmode("c-shared") {
t.registerTest("testcshared", "../misc/cgo/testcshared", "./test.bash")
@@ -510,6 +533,9 @@ func (t *tester) registerTests() {
if t.supportedBuildmode("shared") {
t.registerTest("testshared", "../misc/cgo/testshared", "go", "test")
}
+ if t.supportedBuildmode("plugin") {
+ t.registerTest("testplugin", "../misc/cgo/testplugin", "./test.bash")
+ }
if t.gohostos == "linux" && t.goarch == "amd64" {
t.registerTest("testasan", "../misc/cgo/testasan", "go", "run", "main.go")
}
@@ -667,6 +693,31 @@ func (t *tester) extLink() bool {
return false
}
+func (t *tester) internalLink() bool {
+ if t.gohostos == "dragonfly" {
+ // linkmode=internal fails on dragonfly since errno is a TLS relocation.
+ return false
+ }
+ if t.gohostarch == "ppc64le" {
+ // linkmode=internal fails on ppc64le because cmd/link doesn't
+ // handle the TOC correctly (issue 15409).
+ return false
+ }
+ if t.goos == "android" {
+ return false
+ }
+ if t.goos == "darwin" && (t.goarch == "arm" || t.goarch == "arm64") {
+ return false
+ }
+ // Internally linking cgo is incomplete on some architectures.
+ // https://golang.org/issue/10373
+ // https://golang.org/issue/14449
+ if t.goarch == "arm64" || t.goarch == "mips64" || t.goarch == "mips64le" {
+ return false
+ }
+ return true
+}
+
func (t *tester) supportedBuildmode(mode string) bool {
pair := t.goos + "-" + t.goarch
switch mode {
@@ -694,32 +745,49 @@ func (t *tester) supportedBuildmode(mode string) bool {
return true
}
return false
+ case "plugin":
+ if os.Getenv("GO_BUILDER_NAME") == "linux-amd64-noopt" {
+ // Skip the plugin tests on noopt. They're
+ // causing build failures potentially
+ // obscuring other issues. This is hopefully a
+ // temporary workaround. See golang.org/issue/17937.
+ 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",
+ "darwin-amd64":
+ return true
+ }
+ return false
default:
log.Fatalf("internal error: unknown buildmode %s", mode)
return false
}
}
-func (t *tester) registerHostTest(name, dirBanner, pkg string) {
+func (t *tester) registerHostTest(name, heading, dir, pkg string) {
t.tests = append(t.tests, distTest{
name: name,
- heading: dirBanner,
+ heading: heading,
fn: func(dt *distTest) error {
t.runPending(dt)
- return t.runHostTest(dirBanner, pkg)
+ return t.runHostTest(dir, pkg)
},
})
}
-func (t *tester) runHostTest(dirBanner, pkg string) error {
+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, dirBanner, "test.test"))
- cmd := t.dirCmd(dirBanner, "go", "test", t.tags(), "-c", "-o", "test.test", pkg)
+ 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
if err := cmd.Run(); err != nil {
return err
}
- return t.dirCmd(dirBanner, "./test.test").Run()
+ return t.dirCmd(dir, "./test.test").Run()
}
func (t *tester) cgoTest(dt *distTest) error {
@@ -728,10 +796,7 @@ func (t *tester) cgoTest(dt *distTest) error {
cmd := t.addCmd(dt, "misc/cgo/test", "go", "test", t.tags(), "-ldflags", "-linkmode=auto", t.runFlag(""))
cmd.Env = env
- if t.gohostos != "dragonfly" && t.gohostarch != "ppc64le" && t.goos != "android" && (t.goos != "darwin" || t.goarch != "arm") {
- // linkmode=internal fails on dragonfly since errno is a TLS relocation.
- // linkmode=internal fails on ppc64le because cmd/link doesn't
- // handle the TOC correctly (issue 15409).
+ if t.internalLink() {
cmd := t.addCmd(dt, "misc/cgo/test", "go", "test", "-ldflags", "-linkmode=internal", t.runFlag(""))
cmd.Env = env
}
@@ -752,7 +817,7 @@ func (t *tester) cgoTest(dt *distTest) error {
case "android-arm",
"dragonfly-386", "dragonfly-amd64",
"freebsd-386", "freebsd-amd64", "freebsd-arm",
- "linux-386", "linux-amd64", "linux-arm", "linux-s390x",
+ "linux-386", "linux-amd64", "linux-arm", "linux-ppc64le", "linux-s390x",
"netbsd-386", "netbsd-amd64":
cmd := t.addCmd(dt, "misc/cgo/test", "go", "test", "-ldflags", "-linkmode=external")
@@ -998,7 +1063,7 @@ 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", t.runFlag("Output"), "runtime/race")
- t.addCmd(dt, "src", "go", "test", "-race", "-short", t.runFlag("TestParse|TestEcho"), "flag", "os/exec")
+ t.addCmd(dt, "src", "go", "test", "-race", "-short", t.runFlag("TestParse|TestEcho|TestStdinCloseRace"), "flag", "os/exec")
// We don't want the following line, because it
// slows down all.bash (by 10 seconds on my laptop).
// The race builder should catch any error here, but doesn't.
@@ -1011,7 +1076,7 @@ func (t *tester) raceTest(dt *distTest) error {
}
if t.extLink() {
// Test with external linking; see issue 9133.
- t.addCmd(dt, "src", "go", "test", "-race", "-short", "-ldflags=-linkmode=external", t.runFlag("TestParse|TestEcho"), "flag", "os/exec")
+ t.addCmd(dt, "src", "go", "test", "-race", "-short", "-ldflags=-linkmode=external", t.runFlag("TestParse|TestEcho|TestStdinCloseRace"), "flag", "os/exec")
}
return nil
}
@@ -1073,3 +1138,38 @@ var cgoPackages = []string{
"net",
"os/user",
}
+
+var funcBenchmark = []byte("\nfunc Benchmark")
+
+// packageHasBenchmarks reports whether pkg has benchmarks.
+// On any error, it conservatively returns true.
+//
+// This exists just to eliminate work on the builders, since compiling
+// a test in race mode just to discover it has no benchmarks costs a
+// second or two per package, and this function returns false for
+// about 100 packages.
+func (t *tester) packageHasBenchmarks(pkg string) bool {
+ pkgDir := filepath.Join(t.goroot, "src", pkg)
+ d, err := os.Open(pkgDir)
+ if err != nil {
+ return true // conservatively
+ }
+ defer d.Close()
+ names, err := d.Readdirnames(-1)
+ if err != nil {
+ return true // conservatively
+ }
+ for _, name := range names {
+ if !strings.HasSuffix(name, "_test.go") {
+ continue
+ }
+ slurp, err := ioutil.ReadFile(filepath.Join(pkgDir, name))
+ if err != nil {
+ return true // conservatively
+ }
+ if bytes.Contains(slurp, funcBenchmark) {
+ return true
+ }
+ }
+ return false
+}
diff --git a/src/cmd/dist/util.go b/src/cmd/dist/util.go
index bbf3b75..e2f22df 100644
--- a/src/cmd/dist/util.go
+++ b/src/cmd/dist/util.go
@@ -445,6 +445,11 @@ func main() {
if elfIsLittleEndian(os.Args[0]) {
gohostarch = "mips64le"
}
+ case strings.Contains(out, "mips"):
+ gohostarch = "mips"
+ if elfIsLittleEndian(os.Args[0]) {
+ gohostarch = "mipsle"
+ }
case strings.Contains(out, "s390x"):
gohostarch = "s390x"
case gohostos == "darwin":
diff --git a/src/cmd/doc/dirs.go b/src/cmd/doc/dirs.go
index 2982eee..a4ef8d2 100644
--- a/src/cmd/doc/dirs.go
+++ b/src/cmd/doc/dirs.go
@@ -77,14 +77,14 @@ func (d *Dirs) bfsWalkRoot(root string) {
for _, dir := range this {
fd, err := os.Open(dir)
if err != nil {
- log.Printf("error opening %s: %v", dir, err)
- return // TODO? There may be entry before the error.
+ log.Print(err)
+ continue
}
entries, err := fd.Readdir(0)
fd.Close()
if err != nil {
- log.Printf("error reading %s: %v", dir, err)
- return // TODO? There may be entry before the error.
+ log.Print(err)
+ continue
}
hasGoFiles := false
for _, entry := range entries {
diff --git a/src/cmd/doc/doc_test.go b/src/cmd/doc/doc_test.go
index 453a3d5..1c054fd 100644
--- a/src/cmd/doc/doc_test.go
+++ b/src/cmd/doc/doc_test.go
@@ -55,16 +55,22 @@ var tests = []test{
[]string{p},
[]string{
`Package comment`,
- `const ExportedConstant = 1`, // Simple constant.
- `const ConstOne = 1`, // First entry in constant block.
- `const ConstFive ...`, // From block starting with unexported constant.
- `var ExportedVariable = 1`, // Simple variable.
- `var VarOne = 1`, // First entry in variable block.
- `func ExportedFunc\(a int\) bool`, // Function.
- `func ReturnUnexported\(\) unexportedType`, // Function with unexported return type.
- `type ExportedType struct { ... }`, // Exported type.
- `const ExportedTypedConstant ExportedType = iota`, // Typed constant.
- `const ExportedTypedConstant_unexported unexportedType`, // Typed constant, exported for unexported type.
+ `const ExportedConstant = 1`, // Simple constant.
+ `const ConstOne = 1`, // First entry in constant block.
+ `const ConstFive ...`, // From block starting with unexported constant.
+ `var ExportedVariable = 1`, // Simple variable.
+ `var VarOne = 1`, // First entry in variable block.
+ `func ExportedFunc\(a int\) bool`, // Function.
+ `func ReturnUnexported\(\) unexportedType`, // Function with unexported return type.
+ `type ExportedType struct{ ... }`, // Exported type.
+ `const ExportedTypedConstant ExportedType = iota`, // Typed constant.
+ `const ExportedTypedConstant_unexported unexportedType`, // Typed constant, exported for unexported type.
+ `const ConstLeft2 uint64 ...`, // Typed constant using unexported iota.
+ `const ConstGroup1 unexportedType = iota ...`, // Typed constant using unexported type.
+ `const ConstGroup4 ExportedType = ExportedType{}`, // Typed constant using exported type.
+ `const MultiLineConst = ...`, // Multi line constant.
+ `var MultiLineVar = map\[struct{ ... }\]struct{ ... }{ ... }`, // Multi line variable.
+ `func MultiLineFunc\(x interface{ ... }\) \(r struct{ ... }\)`, // Multi line function.
},
[]string{
`const internalConstant = 2`, // No internal constants.
@@ -99,6 +105,7 @@ var tests = []test{
`Comment about exported constant`, // No comment for simple constant.
`Comment about block of constants`, // No comment for constant block.
`Comment about internal function`, // No comment for internal function.
+ `MultiLine(String|Method|Field)`, // No data from multi line portions.
},
},
@@ -144,6 +151,30 @@ var tests = []test{
},
nil,
},
+ // Block of constants with carryover type from unexported field.
+ {
+ "block of constants with carryover type",
+ []string{p, `ConstLeft2`},
+ []string{
+ `ConstLeft2, constRight2 uint64`,
+ `constLeft3, ConstRight3`,
+ `ConstLeft4, ConstRight4`,
+ },
+ nil,
+ },
+ // Block of constants -u with carryover type from unexported field.
+ {
+ "block of constants with carryover type",
+ []string{"-u", p, `ConstLeft2`},
+ []string{
+ `_, _ uint64 = 2 \* iota, 1 << iota`,
+ `constLeft1, constRight1`,
+ `ConstLeft2, constRight2`,
+ `constLeft3, ConstRight3`,
+ `ConstLeft4, ConstRight4`,
+ },
+ nil,
+ },
// Single variable.
{
@@ -273,7 +304,7 @@ var tests = []test{
// Interface.
{
- "type",
+ "interface type",
[]string{p, `ExportedInterface`},
[]string{
`Comment about exported interface`, // Include comment.
@@ -293,7 +324,7 @@ var tests = []test{
},
// Interface -u with unexported methods.
{
- "type with unexported methods and -u",
+ "interface type with unexported methods and -u",
[]string{"-u", p, `ExportedInterface`},
[]string{
`Comment about exported interface`, // Include comment.
@@ -309,6 +340,19 @@ var tests = []test{
},
},
+ // Interface method.
+ {
+ "interface method",
+ []string{p, `ExportedInterface.ExportedMethod`},
+ []string{
+ `Comment before exported method.*\n.*ExportedMethod\(\)` +
+ `.*Comment on line with exported method`,
+ },
+ []string{
+ `Comment about exported interface.`,
+ },
+ },
+
// Method.
{
"method",
diff --git a/src/cmd/doc/pkg.go b/src/cmd/doc/pkg.go
index defddfd..daa6ed3 100644
--- a/src/cmd/doc/pkg.go
+++ b/src/cmd/doc/pkg.go
@@ -194,60 +194,176 @@ func (pkg *Package) emit(comment string, node ast.Node) {
}
}
-var formatBuf bytes.Buffer // Reusable to avoid allocation.
-
-// formatNode is a helper function for printing.
-func (pkg *Package) formatNode(node ast.Node) []byte {
- formatBuf.Reset()
- format.Node(&formatBuf, pkg.fs, node)
- return formatBuf.Bytes()
+// oneLineNode returns a one-line summary of the given input node.
+func (pkg *Package) oneLineNode(node ast.Node) string {
+ const maxDepth = 10
+ return pkg.oneLineNodeDepth(node, maxDepth)
}
-// oneLineFunc prints a function declaration as a single line.
-func (pkg *Package) oneLineFunc(decl *ast.FuncDecl) {
- decl.Doc = nil
- decl.Body = nil
- pkg.emit("", decl)
-}
+// oneLineNodeDepth returns a one-line summary of the given input node.
+// The depth specifies the maximum depth when traversing the AST.
+func (pkg *Package) oneLineNodeDepth(node ast.Node, depth int) string {
+ const dotDotDot = "..."
+ if depth == 0 {
+ return dotDotDot
+ }
+ depth--
-// oneLineValueGenDecl prints a var or const declaration as a single line.
-func (pkg *Package) oneLineValueGenDecl(decl *ast.GenDecl) {
- decl.Doc = nil
- dotDotDot := ""
- if len(decl.Specs) > 1 {
- dotDotDot = " ..."
- }
- // Find the first relevant spec.
- for i, spec := range decl.Specs {
- valueSpec := spec.(*ast.ValueSpec) // Must succeed; we can't mix types in one genDecl.
- if !isExported(valueSpec.Names[0].Name) {
- continue
+ switch n := node.(type) {
+ case nil:
+ return ""
+
+ case *ast.GenDecl:
+ // Formats const and var declarations.
+ trailer := ""
+ if len(n.Specs) > 1 {
+ trailer = " " + dotDotDot
}
+
+ // Find the first relevant spec.
typ := ""
- if valueSpec.Type != nil {
- typ = fmt.Sprintf(" %s", pkg.formatNode(valueSpec.Type))
+ for i, spec := range n.Specs {
+ valueSpec := spec.(*ast.ValueSpec) // Must succeed; we can't mix types in one GenDecl.
+
+ // The type name may carry over from a previous specification in the
+ // case of constants and iota.
+ if valueSpec.Type != nil {
+ typ = fmt.Sprintf(" %s", pkg.oneLineNodeDepth(valueSpec.Type, depth))
+ } else if len(valueSpec.Values) > 0 {
+ typ = ""
+ }
+
+ if !isExported(valueSpec.Names[0].Name) {
+ continue
+ }
+ val := ""
+ if i < len(valueSpec.Values) && valueSpec.Values[i] != nil {
+ val = fmt.Sprintf(" = %s", pkg.oneLineNodeDepth(valueSpec.Values[i], depth))
+ }
+ return fmt.Sprintf("%s %s%s%s%s", n.Tok, valueSpec.Names[0], typ, val, trailer)
}
- val := ""
- if i < len(valueSpec.Values) && valueSpec.Values[i] != nil {
- val = fmt.Sprintf(" = %s", pkg.formatNode(valueSpec.Values[i]))
+ return ""
+
+ case *ast.FuncDecl:
+ // Formats func declarations.
+ name := n.Name.Name
+ recv := pkg.oneLineNodeDepth(n.Recv, depth)
+ if len(recv) > 0 {
+ recv = "(" + recv + ") "
}
- pkg.Printf("%s %s%s%s%s\n", decl.Tok, valueSpec.Names[0], typ, val, dotDotDot)
- break
- }
-}
+ fnc := pkg.oneLineNodeDepth(n.Type, depth)
+ if strings.Index(fnc, "func") == 0 {
+ fnc = fnc[4:]
+ }
+ 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))
+
+ case *ast.FuncType:
+ var params []string
+ if n.Params != nil {
+ for _, field := range n.Params.List {
+ params = append(params, pkg.oneLineField(field, depth))
+ }
+ }
+ needParens := false
+ var results []string
+ if n.Results != nil {
+ needParens = needParens || len(n.Results.List) > 1
+ for _, field := range n.Results.List {
+ needParens = needParens || len(field.Names) > 0
+ results = append(results, pkg.oneLineField(field, depth))
+ }
+ }
+
+ param := strings.Join(params, ", ")
+ if len(results) == 0 {
+ return fmt.Sprintf("func(%s)", param)
+ }
+ result := strings.Join(results, ", ")
+ if !needParens {
+ return fmt.Sprintf("func(%s) %s", param, result)
+ }
+ return fmt.Sprintf("func(%s) (%s)", param, result)
-// oneLineTypeDecl prints a type declaration as a single line.
-func (pkg *Package) oneLineTypeDecl(spec *ast.TypeSpec) {
- spec.Doc = nil
- spec.Comment = nil
- switch spec.Type.(type) {
- case *ast.InterfaceType:
- pkg.Printf("type %s interface { ... }\n", spec.Name)
case *ast.StructType:
- pkg.Printf("type %s struct { ... }\n", spec.Name)
+ if n.Fields == nil || len(n.Fields.List) == 0 {
+ return "struct{}"
+ }
+ return "struct{ ... }"
+
+ case *ast.InterfaceType:
+ if n.Methods == nil || len(n.Methods.List) == 0 {
+ return "interface{}"
+ }
+ return "interface{ ... }"
+
+ case *ast.FieldList:
+ if n == nil || len(n.List) == 0 {
+ return ""
+ }
+ if len(n.List) == 1 {
+ return pkg.oneLineField(n.List[0], depth)
+ }
+ return dotDotDot
+
+ case *ast.FuncLit:
+ return pkg.oneLineNodeDepth(n.Type, depth) + " { ... }"
+
+ case *ast.CompositeLit:
+ typ := pkg.oneLineNodeDepth(n.Type, depth)
+ if len(n.Elts) == 0 {
+ return fmt.Sprintf("%s{}", typ)
+ }
+ return fmt.Sprintf("%s{ %s }", typ, dotDotDot)
+
+ case *ast.ArrayType:
+ length := pkg.oneLineNodeDepth(n.Len, depth)
+ element := pkg.oneLineNodeDepth(n.Elt, depth)
+ return fmt.Sprintf("[%s]%s", length, element)
+
+ case *ast.MapType:
+ key := pkg.oneLineNodeDepth(n.Key, depth)
+ value := pkg.oneLineNodeDepth(n.Value, depth)
+ return fmt.Sprintf("map[%s]%s", key, value)
+
+ case *ast.CallExpr:
+ fnc := pkg.oneLineNodeDepth(n.Fun, depth)
+ var args []string
+ for _, arg := range n.Args {
+ args = append(args, pkg.oneLineNodeDepth(arg, depth))
+ }
+ return fmt.Sprintf("%s(%s)", fnc, strings.Join(args, ", "))
+
+ case *ast.UnaryExpr:
+ return fmt.Sprintf("%s%s", n.Op, pkg.oneLineNodeDepth(n.X, depth))
+
+ case *ast.Ident:
+ return n.Name
+
default:
- pkg.Printf("type %s %s\n", spec.Name, pkg.formatNode(spec.Type))
+ // As a fallback, use default formatter for all unknown node types.
+ buf := new(bytes.Buffer)
+ format.Node(buf, pkg.fs, node)
+ s := buf.String()
+ if strings.Contains(s, "\n") {
+ return dotDotDot
+ }
+ return s
+ }
+}
+
+// oneLineField returns a one-line summary of the field.
+func (pkg *Package) oneLineField(field *ast.Field, depth int) string {
+ var names []string
+ for _, name := range field.Names {
+ names = append(names, name.Name)
+ }
+ if len(names) == 0 {
+ return pkg.oneLineNodeDepth(field.Type, depth)
}
+ return strings.Join(names, ", ") + " " + pkg.oneLineNodeDepth(field.Type, depth)
}
// packageDoc prints the docs for the package (package doc plus one-liners of the rest).
@@ -266,8 +382,8 @@ func (pkg *Package) packageDoc() {
}
pkg.newlines(2) // Guarantee blank line before the components.
- pkg.valueSummary(pkg.doc.Consts)
- pkg.valueSummary(pkg.doc.Vars)
+ pkg.valueSummary(pkg.doc.Consts, false)
+ pkg.valueSummary(pkg.doc.Vars, false)
pkg.funcSummary(pkg.doc.Funcs, false)
pkg.typeSummary()
pkg.bugs()
@@ -302,9 +418,31 @@ func (pkg *Package) packageClause(checkUserPath bool) {
}
// valueSummary prints a one-line summary for each set of values and constants.
-func (pkg *Package) valueSummary(values []*doc.Value) {
+// If all the types in a constant or variable declaration belong to the same
+// type they can be printed by typeSummary, and so can be suppressed here.
+func (pkg *Package) valueSummary(values []*doc.Value, showGrouped bool) {
+ var isGrouped map[*doc.Value]bool
+ if !showGrouped {
+ isGrouped = make(map[*doc.Value]bool)
+ for _, typ := range pkg.doc.Types {
+ if !isExported(typ.Name) {
+ continue
+ }
+ for _, c := range typ.Consts {
+ isGrouped[c] = true
+ }
+ for _, v := range typ.Vars {
+ isGrouped[v] = true
+ }
+ }
+ }
+
for _, value := range values {
- pkg.oneLineValueGenDecl(value.Decl)
+ if !isGrouped[value] {
+ if decl := pkg.oneLineNode(value.Decl); decl != "" {
+ pkg.Printf("%s\n", decl)
+ }
+ }
}
}
@@ -316,19 +454,18 @@ func (pkg *Package) funcSummary(funcs []*doc.Func, showConstructors bool) {
if !showConstructors {
isConstructor = make(map[*doc.Func]bool)
for _, typ := range pkg.doc.Types {
- for _, constructor := range typ.Funcs {
- if isExported(typ.Name) {
- isConstructor[constructor] = true
+ if isExported(typ.Name) {
+ for _, f := range typ.Funcs {
+ isConstructor[f] = true
}
}
}
}
for _, fun := range funcs {
- decl := fun.Decl
// Exported functions only. The go/doc package does not include methods here.
if isExported(fun.Name) {
if !isConstructor[fun] {
- pkg.oneLineFunc(decl)
+ pkg.Printf("%s\n", pkg.oneLineNode(fun.Decl))
}
}
}
@@ -340,12 +477,21 @@ func (pkg *Package) typeSummary() {
for _, spec := range typ.Decl.Specs {
typeSpec := spec.(*ast.TypeSpec) // Must succeed.
if isExported(typeSpec.Name.Name) {
- pkg.oneLineTypeDecl(typeSpec)
- // Now print the constructors.
+ pkg.Printf("%s\n", pkg.oneLineNode(typeSpec))
+ // Now print the consts, vars, and constructors.
+ for _, c := range typ.Consts {
+ if decl := pkg.oneLineNode(c.Decl); decl != "" {
+ pkg.Printf(indent+"%s\n", decl)
+ }
+ }
+ for _, v := range typ.Vars {
+ if decl := pkg.oneLineNode(v.Decl); decl != "" {
+ pkg.Printf(indent+"%s\n", decl)
+ }
+ }
for _, constructor := range typ.Funcs {
if isExported(constructor.Name) {
- pkg.Printf(indent)
- pkg.oneLineFunc(constructor.Decl)
+ pkg.Printf(indent+"%s\n", pkg.oneLineNode(constructor.Decl))
}
}
}
@@ -437,11 +583,29 @@ func (pkg *Package) symbolDoc(symbol string) bool {
// It's an unlikely scenario, probably not worth the trouble.
// TODO: Would be nice if go/doc did this for us.
specs := make([]ast.Spec, 0, len(value.Decl.Specs))
+ var typ ast.Expr
for _, spec := range value.Decl.Specs {
vspec := spec.(*ast.ValueSpec)
+
+ // The type name may carry over from a previous specification in the
+ // case of constants and iota.
+ if vspec.Type != nil {
+ typ = vspec.Type
+ }
+
for _, ident := range vspec.Names {
if isExported(ident.Name) {
+ if vspec.Type == nil && vspec.Values == nil && typ != nil {
+ // This a standalone identifier, as in the case of iota usage.
+ // Thus, assume the type comes from the previous type.
+ vspec.Type = &ast.Ident{
+ Name: string(pkg.oneLineNode(typ)),
+ NamePos: vspec.End() - 1,
+ }
+ }
+
specs = append(specs, vspec)
+ typ = nil // Only inject type on first exported identifier
break
}
}
@@ -473,8 +637,8 @@ func (pkg *Package) symbolDoc(symbol string) bool {
if len(typ.Consts) > 0 || len(typ.Vars) > 0 || len(typ.Funcs) > 0 || len(typ.Methods) > 0 {
pkg.Printf("\n")
}
- pkg.valueSummary(typ.Consts)
- pkg.valueSummary(typ.Vars)
+ pkg.valueSummary(typ.Consts, true)
+ pkg.valueSummary(typ.Vars, true)
pkg.funcSummary(typ.Funcs, true)
pkg.funcSummary(typ.Methods, true)
found = true
@@ -591,11 +755,48 @@ func (pkg *Package) printMethodDoc(symbol, method string) bool {
}
found := false
for _, typ := range types {
- for _, meth := range typ.Methods {
- if match(method, meth.Name) {
- decl := meth.Decl
- decl.Body = nil
- pkg.emit(meth.Doc, decl)
+ if len(typ.Methods) > 0 {
+ for _, meth := range typ.Methods {
+ if match(method, meth.Name) {
+ decl := meth.Decl
+ decl.Body = nil
+ pkg.emit(meth.Doc, decl)
+ found = true
+ }
+ }
+ continue
+ }
+ // Type may be an interface. The go/doc package does not attach
+ // an interface's methods to the doc.Type. We need to dig around.
+ spec := pkg.findTypeSpec(typ.Decl, typ.Name)
+ 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 {
+ // This is an interface, so there can be only one name.
+ // TODO: Anonymous methods (embedding)
+ if len(iMethod.Names) == 0 {
+ continue
+ }
+ 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)
+ }
+ }
+ s := pkg.oneLineNode(iMethod.Type)
+ // Hack: s starts "func" but there is no name present.
+ // We could instead build a FuncDecl but it's not worthwhile.
+ lineComment := ""
+ if iMethod.Comment != nil {
+ lineComment = fmt.Sprintf(" %s", iMethod.Comment.List[0].Text)
+ }
+ pkg.Printf("func %s%s%s\n", name, s[4:], lineComment)
found = true
}
}
diff --git a/src/cmd/doc/testdata/pkg.go b/src/cmd/doc/testdata/pkg.go
index 6a52ac2..924daa1 100644
--- a/src/cmd/doc/testdata/pkg.go
+++ b/src/cmd/doc/testdata/pkg.go
@@ -126,3 +126,49 @@ const Casematch = 2
func ReturnUnexported() unexportedType { return 0 }
func ReturnExported() ExportedType { return ExportedType{} }
+
+const MultiLineConst = `
+ MultiLineString1
+ MultiLineString2
+ MultiLineString3
+`
+
+func MultiLineFunc(x interface {
+ MultiLineMethod1() int
+ MultiLineMethod2() int
+ MultiLineMethod3() int
+}) (r struct {
+ MultiLineField1 int
+ MultiLineField2 int
+ MultiLineField3 int
+}) {
+ return r
+}
+
+var MultiLineVar = map[struct {
+ MultiLineField1 string
+ MultiLineField2 uint64
+}]struct {
+ MultiLineField3 error
+ MultiLineField2 error
+}{
+ {"FieldVal1", 1}: {},
+ {"FieldVal2", 2}: {},
+ {"FieldVal3", 3}: {},
+}
+
+const (
+ _, _ uint64 = 2 * iota, 1 << iota
+ constLeft1, constRight1
+ ConstLeft2, constRight2
+ constLeft3, ConstRight3
+ ConstLeft4, ConstRight4
+)
+
+const (
+ ConstGroup1 unexportedType = iota
+ ConstGroup2
+ ConstGroup3
+)
+
+const ConstGroup4 ExportedType = ExportedType{}
diff --git a/src/cmd/fix/context.go b/src/cmd/fix/context.go
new file mode 100644
index 0000000..926a06c
--- /dev/null
+++ b/src/cmd/fix/context.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 (
+ "go/ast"
+)
+
+func init() {
+ register(contextFix)
+}
+
+var contextFix = fix{
+ name: "context",
+ date: "2016-09-09",
+ f: ctxfix,
+ desc: `Change imports of golang.org/x/net/context to context`,
+ disabled: true,
+}
+
+func ctxfix(f *ast.File) bool {
+ return rewriteImport(f, "golang.org/x/net/context", "context")
+}
diff --git a/src/cmd/fix/context_test.go b/src/cmd/fix/context_test.go
new file mode 100644
index 0000000..935d0d7
--- /dev/null
+++ b/src/cmd/fix/context_test.go
@@ -0,0 +1,42 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func init() {
+ addTestCases(contextTests, ctxfix)
+}
+
+var contextTests = []testCase{
+ {
+ Name: "context.0",
+ In: `package main
+
+import "golang.org/x/net/context"
+
+var _ = "golang.org/x/net/context"
+`,
+ Out: `package main
+
+import "context"
+
+var _ = "golang.org/x/net/context"
+`,
+ },
+ {
+ Name: "context.1",
+ In: `package main
+
+import ctx "golang.org/x/net/context"
+
+var _ = ctx.Background()
+`,
+ Out: `package main
+
+import ctx "context"
+
+var _ = ctx.Background()
+`,
+ },
+}
diff --git a/src/cmd/fix/fix.go b/src/cmd/fix/fix.go
index ab16a21..03c828a 100644
--- a/src/cmd/fix/fix.go
+++ b/src/cmd/fix/fix.go
@@ -17,10 +17,11 @@ import (
)
type fix struct {
- name string
- date string // date that fix was introduced, in YYYY-MM-DD format
- f func(*ast.File) bool
- desc string
+ name string
+ date string // date that fix was introduced, in YYYY-MM-DD format
+ f func(*ast.File) bool
+ desc string
+ disabled bool // whether this fix should be disabled by default
}
// main runs sort.Sort(byName(fixes)) before printing list of fixes.
diff --git a/src/cmd/fix/gotypes.go b/src/cmd/fix/gotypes.go
index bb29a0c..8a4019c 100644
--- a/src/cmd/fix/gotypes.go
+++ b/src/cmd/fix/gotypes.go
@@ -14,10 +14,10 @@ func init() {
}
var gotypesFix = fix{
- "gotypes",
- "2015-07-16",
- gotypes,
- `Change imports of golang.org/x/tools/go/{exact,types} to go/{constant,types}`,
+ name: "gotypes",
+ date: "2015-07-16",
+ f: gotypes,
+ desc: `Change imports of golang.org/x/tools/go/{exact,types} to go/{constant,types}`,
}
func gotypes(f *ast.File) bool {
diff --git a/src/cmd/fix/main.go b/src/cmd/fix/main.go
index 8b62346..3b4130b 100644
--- a/src/cmd/fix/main.go
+++ b/src/cmd/fix/main.go
@@ -45,7 +45,11 @@ func usage() {
fmt.Fprintf(os.Stderr, "\nAvailable rewrites are:\n")
sort.Sort(byName(fixes))
for _, f := range fixes {
- fmt.Fprintf(os.Stderr, "\n%s\n", f.name)
+ if f.disabled {
+ fmt.Fprintf(os.Stderr, "\n%s (disabled)\n", f.name)
+ } else {
+ fmt.Fprintf(os.Stderr, "\n%s\n", f.name)
+ }
desc := strings.TrimSpace(f.desc)
desc = strings.Replace(desc, "\n", "\n\t", -1)
fmt.Fprintf(os.Stderr, "\t%s\n", desc)
@@ -139,6 +143,9 @@ func processFile(filename string, useStdin bool) error {
if allowed != nil && !allowed[fix.name] {
continue
}
+ if fix.disabled && !force[fix.name] {
+ continue
+ }
if fix.f(newFile) {
fixed = true
fmt.Fprintf(&fixlog, " %s", fix.name)
diff --git a/src/cmd/fix/netipv6zone.go b/src/cmd/fix/netipv6zone.go
index 49cd307..3e502bd 100644
--- a/src/cmd/fix/netipv6zone.go
+++ b/src/cmd/fix/netipv6zone.go
@@ -11,10 +11,10 @@ func init() {
}
var netipv6zoneFix = fix{
- "netipv6zone",
- "2012-11-26",
- netipv6zone,
- `Adapt element key to IPAddr, UDPAddr or TCPAddr composite literals.
+ name: "netipv6zone",
+ date: "2012-11-26",
+ f: netipv6zone,
+ desc: `Adapt element key to IPAddr, UDPAddr or TCPAddr composite literals.
https://codereview.appspot.com/6849045/
`,
diff --git a/src/cmd/fix/printerconfig.go b/src/cmd/fix/printerconfig.go
index 286c5f2..6d93996 100644
--- a/src/cmd/fix/printerconfig.go
+++ b/src/cmd/fix/printerconfig.go
@@ -11,10 +11,10 @@ func init() {
}
var printerconfigFix = fix{
- "printerconfig",
- "2012-12-11",
- printerconfig,
- `Add element keys to Config composite literals.`,
+ name: "printerconfig",
+ date: "2012-12-11",
+ f: printerconfig,
+ desc: `Add element keys to Config composite literals.`,
}
func printerconfig(f *ast.File) bool {
diff --git a/src/cmd/go/alldocs.go b/src/cmd/go/alldocs.go
index 58b0d16..b480742 100644
--- a/src/cmd/go/alldocs.go
+++ b/src/cmd/go/alldocs.go
@@ -17,6 +17,7 @@
// clean remove object files
// doc show documentation for package or symbol
// env print Go environment information
+// bug print information for bug reports
// fix run go tool fix on packages
// fmt run gofmt on package sources
// generate generate Go files by processing source
@@ -323,6 +324,17 @@
// each named variable on its own line.
//
//
+// Print information for bug reports
+//
+// Usage:
+//
+// go bug
+//
+// Bug prints information that helps file effective bug reports.
+//
+// Bugs may be reported at https://golang.org/issue/new.
+//
+//
// Run go tool fix on packages
//
// Usage:
@@ -367,7 +379,7 @@
//
// Generate runs commands described by directives within existing
// files. Those commands can run any process but the intent is to
-// create or update Go source files, for instance by running yacc.
+// 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.
@@ -430,10 +442,10 @@
// can be used to create aliases or to handle multiword generators.
// For example,
//
-// //go:generate -command yacc go tool yacc
+// //go:generate -command foo go tool foo
//
-// specifies that the command "yacc" represents the generator
-// "go tool yacc".
+// 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
@@ -496,11 +508,13 @@
// 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. See 'go help gopath'.
+// 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
@@ -584,6 +598,8 @@
// 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
@@ -594,20 +610,23 @@
// CgoPkgConfig []string // cgo: pkg-config names
//
// // Dependency information
-// Imports []string // import paths used by this package
-// Deps []string // all (recursively) imported dependencies
+// 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
-//
-// TestGoFiles []string // _test.go files in package
-// TestImports []string // imports from TestGoFiles
-// XTestGoFiles []string // _test.go files outside package
-// XTestImports []string // imports from XTestGoFiles
// }
//
+// 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 {
@@ -852,6 +871,10 @@
// 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.
+//
//
// File types
//
@@ -906,8 +929,11 @@
// On Windows, the value is a semicolon-separated string.
// On Plan 9, the value is a list.
//
-// GOPATH must be set to get, build and install packages outside the
-// standard Go tree.
+// 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.
//
// Each directory listed in GOPATH must have a prescribed structure:
//
@@ -935,9 +961,9 @@
//
// Here's an example directory layout:
//
-// GOPATH=/home/user/gocode
+// GOPATH=/home/user/go
//
-// /home/user/gocode/
+// /home/user/go/
// src/
// foo/
// bar/ (go code in package bar)
@@ -963,7 +989,7 @@
// by code in the directory tree rooted at the parent of "internal".
// Here's an extended version of the directory layout above:
//
-// /home/user/gocode/
+// /home/user/go/
// src/
// crash/
// bang/ (go code in package bang)
@@ -1001,7 +1027,7 @@
// but with the "internal" directory renamed to "vendor"
// and a new foo/vendor/crash/bang directory added:
//
-// /home/user/gocode/
+// /home/user/go/
// src/
// crash/
// bang/ (go code in package bang)
@@ -1060,7 +1086,7 @@
// The operating system for which to compile code.
// Examples are linux, darwin, windows, netbsd.
// GOPATH
-// See 'go help gopath'.
+// For more details see: 'go help gopath'.
// GORACE
// Options for the race detector.
// See https://golang.org/doc/articles/race_detector.html.
@@ -1082,10 +1108,15 @@
// 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:
//
@@ -1107,14 +1138,18 @@
// 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'.
//
//
// Import path syntax
//
-// An import path (see 'go help packages') denotes a package
-// stored in the local file system. In general, an import path denotes
-// either a standard package (such as "unicode/utf8") or a package
-// found in one of the work spaces (see 'go help gopath').
+// 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
//
@@ -1206,6 +1241,11 @@
// 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
@@ -1246,8 +1286,8 @@
// same meta tag and then git clone https://code.org/r/p/exproj into
// GOPATH/src/example.org.
//
-// New downloaded packages are written to the first directory
-// listed in the GOPATH environment variable (see 'go help gopath').
+// 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.
@@ -1291,7 +1331,7 @@
//
// Otherwise, the import path P denotes the package found in
// the directory DIR/src/P for some DIR listed in the GOPATH
-// environment variable (see 'go help gopath').
+// 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.
@@ -1311,6 +1351,9 @@
// - "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
@@ -1366,28 +1409,11 @@
// By default, no benchmarks run. To run all benchmarks,
// use '-bench .' or '-bench=.'.
//
-// -benchmem
-// Print memory allocation statistics for benchmarks.
-//
// -benchtime t
// Run enough iterations of each benchmark to take t, specified
// as a time.Duration (for example, -benchtime 1h30s).
// The default is 1 second (1s).
//
-// -blockprofile block.out
-// Write a goroutine blocking profile to the specified file
-// when all tests are complete.
-// Writes test binary as -c would.
-//
-// -blockprofilerate n
-// Control the detail provided in goroutine blocking profiles by
-// calling runtime.SetBlockProfileRate with n.
-// See 'go doc runtime.SetBlockProfileRate'.
-// The profiler aims to sample, on average, one blocking event every
-// n nanoseconds the program spends blocked. By default,
-// if -test.blockprofile is set without this flag, all blocking events
-// are recorded, equivalent to -test.blockprofilerate=1.
-//
// -count n
// Run each test and benchmark n times (default 1).
// If -cpu is set, run n times for each GOMAXPROCS value.
@@ -1413,33 +1439,11 @@
// Packages are specified as import paths.
// Sets -cover.
//
-// -coverprofile cover.out
-// Write a coverage profile to the file after all tests have passed.
-// Sets -cover.
-//
// -cpu 1,2,4
// Specify a list of GOMAXPROCS values for which the tests or
// benchmarks should be executed. The default is the current value
// of GOMAXPROCS.
//
-// -cpuprofile cpu.out
-// Write a CPU profile to the specified file before exiting.
-// Writes test binary as -c would.
-//
-// -memprofile mem.out
-// Write a memory profile to the file after all tests have passed.
-// Writes test binary as -c would.
-//
-// -memprofilerate n
-// Enable more precise (and expensive) memory profiles by setting
-// runtime.MemProfileRate. See 'go doc runtime.MemProfileRate'.
-// To profile all memory allocations, use -test.memprofilerate=1
-// and pass --alloc_space flag to the pprof tool.
-//
-// -outputdir directory
-// Place output files from profiling in the specified directory,
-// by default the directory in which "go test" is running.
-//
// -parallel n
// Allow parallel execution of test functions that call t.Parallel.
// The value of this flag is the maximum number of tests to run
@@ -1465,13 +1469,64 @@
// If a test runs longer than t, panic.
// The default is 10 minutes (10m).
//
-// -trace trace.out
-// Write an execution trace to the specified file before exiting.
-//
// -v
// Verbose output: log all tests as they are run. Also print all
// text from Log and Logf calls even if the test succeeds.
//
+// 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.
diff --git a/src/cmd/go/bootstrap.go b/src/cmd/go/bootstrap.go
index caa9676..2148d12 100644
--- a/src/cmd/go/bootstrap.go
+++ b/src/cmd/go/bootstrap.go
@@ -36,3 +36,6 @@ func httpsOrHTTP(importPath string, security securityMode) (string, io.ReadClose
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
new file mode 100644
index 0000000..2977c94
--- /dev/null
+++ b/src/cmd/go/bug.go
@@ -0,0 +1,209 @@
+// Copyright 2016 The Go Authors. 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: "print information for bug reports",
+ Long: `
+Bug prints information that helps file effective bug reports.
+
+Bugs may be reported at https://golang.org/issue/new.
+ `,
+}
+
+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 {
+ 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
index 3c0b994..684d033 100644
--- a/src/cmd/go/build.go
+++ b/src/cmd/go/build.go
@@ -338,6 +338,13 @@ func buildModeInit() {
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"
@@ -399,6 +406,22 @@ func buildModeInit() {
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",
+ "darwin/amd64":
+ default:
+ fatalf("-buildmode=plugin not supported on %s\n", platform)
+ }
+ codegenArg = "-dynlink"
+ }
+ exeSuffix = ".so"
+ ldBuildmode = "plugin"
default:
fatalf("buildmode=%s not supported", buildBuildmode)
}
@@ -424,10 +447,13 @@ func buildModeInit() {
buildAsmflags = append(buildAsmflags, codegenArg)
buildGcflags = append(buildGcflags, codegenArg)
}
- if buildContext.InstallSuffix != "" {
- buildContext.InstallSuffix += "_"
+ // Don't alter InstallSuffix when modifying default codegen args.
+ if buildBuildmode != "default" || buildLinkshared {
+ if buildContext.InstallSuffix != "" {
+ buildContext.InstallSuffix += "_"
+ }
+ buildContext.InstallSuffix += codegenArg[1:]
}
- buildContext.InstallSuffix += codegenArg[1:]
}
}
@@ -444,6 +470,11 @@ func runBuild(cmd *Command, args []string) {
*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":
@@ -572,6 +603,10 @@ func libname(args []string, pkgs []*Package) (string, error) {
}
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")
}
@@ -591,7 +626,7 @@ func runInstall(cmd *Command, args []string) {
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)
+ "\tFor more details see: 'go help gopath'", p.Dir)
}
}
}
@@ -599,6 +634,8 @@ func runInstall(cmd *Command, args []string) {
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 {
@@ -689,6 +726,8 @@ type builder struct {
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
@@ -1272,6 +1311,8 @@ func (b *builder) do(root *action) {
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)
}
@@ -1358,7 +1399,7 @@ func (b *builder) build(a *action) (err error) {
}
defer func() {
- if err != nil && err != errPrintedOutput {
+ 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)
}
}()
@@ -1389,7 +1430,7 @@ func (b *builder) build(a *action) (err error) {
}
}
- var gofiles, cgofiles, cfiles, sfiles, cxxfiles, objects, cgoObjects, pcCFLAGS, pcLDFLAGS []string
+ var gofiles, cgofiles, objdirCgofiles, cfiles, sfiles, cxxfiles, objects, cgoObjects, pcCFLAGS, pcLDFLAGS []string
gofiles = append(gofiles, a.p.GoFiles...)
cgofiles = append(cgofiles, a.p.CgoFiles...)
@@ -1411,7 +1452,7 @@ func (b *builder) build(a *action) (err error) {
if err != nil {
return err
}
- cgofiles = append(cgofiles, outGo...)
+ objdirCgofiles = append(objdirCgofiles, outGo...)
cfiles = append(cfiles, outC...)
cxxfiles = append(cxxfiles, outCXX...)
}
@@ -1446,7 +1487,7 @@ func (b *builder) build(a *action) (err error) {
if a.cgo != nil && a.cgo.target != "" {
cgoExe = a.cgo.target
}
- outGo, outObj, err := b.cgo(a.p, cgoExe, obj, pcCFLAGS, pcLDFLAGS, cgofiles, gccfiles, cxxfiles, a.p.MFiles, a.p.FFiles)
+ 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
}
@@ -1544,12 +1585,12 @@ func (b *builder) build(a *action) (err error) {
}
// Assemble .s files.
- for _, file := range sfiles {
- out := file[:len(file)-len(".s")] + ".o"
- if err := buildToolchain.asm(b, a.p, obj, obj+out, file); err != nil {
+ if len(sfiles) > 0 {
+ ofiles, err := buildToolchain.asm(b, a.p, obj, sfiles)
+ if err != nil {
return err
}
- objects = append(objects, out)
+ objects = append(objects, ofiles...)
}
// NOTE(rsc): On Windows, it is critically important that the
@@ -1588,23 +1629,62 @@ func (b *builder) build(a *action) (err error) {
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, "pkg-config", "--cflags", pkgs)
+ out, err = b.runOut(p.Dir, p.ImportPath, nil, b.pkgconfigCmd(), "--cflags", pkgs)
if err != nil {
- b.showOutput(p.Dir, "pkg-config --cflags "+strings.Join(pkgs, " "), string(out))
+ 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 = strings.Fields(string(out))
+ cflags = splitPkgConfigOutput(out)
}
- out, err = b.runOut(p.Dir, p.ImportPath, nil, "pkg-config", "--libs", pkgs)
+ out, err = b.runOut(p.Dir, p.ImportPath, nil, b.pkgconfigCmd(), "--libs", pkgs)
if err != nil {
- b.showOutput(p.Dir, "pkg-config --libs "+strings.Join(pkgs, " "), string(out))
+ b.showOutput(p.Dir, b.pkgconfigCmd()+" --libs "+strings.Join(pkgs, " "), string(out))
b.print(err.Error() + "\n")
err = errPrintedOutput
return
@@ -1645,7 +1725,7 @@ func (b *builder) install(a *action) (err error) {
perm := os.FileMode(0666)
if a1.link {
switch buildBuildmode {
- case "c-archive", "c-shared":
+ case "c-archive", "c-shared", "plugin":
default:
perm = 0777
}
@@ -2186,9 +2266,9 @@ type toolchain interface {
// 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 a specific file
- // to generate the named output file.
- asm(b *builder, p *Package, obj, ofile, sfile 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
@@ -2225,8 +2305,8 @@ func (noToolchain) gc(b *builder, p *Package, archive, obj string, asmhdr bool,
return "", nil, noCompiler()
}
-func (noToolchain) asm(b *builder, p *Package, obj, ofile, sfile string) error {
- return 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 {
@@ -2323,10 +2403,10 @@ func (gcToolchain) gc(b *builder, p *Package, archive, obj string, asmhdr bool,
return ofile, output, err
}
-func (gcToolchain) asm(b *builder, p *Package, obj, ofile, sfile string) error {
+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")
- sfile = mkAbs(p.Dir, sfile)
+ ofile := obj + "asm.o"
args := []interface{}{buildToolExec, tool("asm"), "-o", ofile, "-trimpath", b.work, "-I", obj, "-I", inc, "-D", "GOOS_" + goos, "-D", "GOARCH_" + goarch, buildAsmflags}
if p.ImportPath == "runtime" && goarch == "386" {
for _, arg := range buildAsmflags {
@@ -2335,11 +2415,13 @@ func (gcToolchain) asm(b *builder, p *Package, obj, ofile, sfile string) error {
}
}
}
- args = append(args, sfile)
+ for _, sfile := range sfiles {
+ args = append(args, mkAbs(p.Dir, sfile))
+ }
if err := b.run(p.Dir, p.ImportPath, nil, args...); err != nil {
- return err
+ return nil, err
}
- return nil
+ return []string{ofile}, nil
}
// toolVerify checks that the command line args writes the same output file
@@ -2497,6 +2579,13 @@ func (gcToolchain) ld(b *builder, root *action, out string, allactions []*action
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
@@ -2606,15 +2695,24 @@ func (tools gccgoToolchain) gc(b *builder, p *Package, archive, obj string, asmh
return ofile, output, err
}
-func (tools gccgoToolchain) asm(b *builder, p *Package, obj, ofile, sfile string) error {
- sfile = mkAbs(p.Dir, sfile)
- defs := []string{"-D", "GOOS_" + goos, "-D", "GOARCH_" + goarch}
- if pkgpath := gccgoCleanPkgpath(p); pkgpath != "" {
- defs = append(defs, `-D`, `GOPKGPATH=`+pkgpath)
+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
+ }
}
- defs = tools.maybePIC(defs)
- defs = append(defs, b.gccArchArgs()...)
- return b.run(p.Dir, p.ImportPath, nil, tools.compiler(), "-xassembler-with-cpp", "-I", obj, "-c", "-o", ofile, defs, sfile)
+ return ofiles, nil
}
func (gccgoToolchain) pkgpath(basedir string, p *Package) string {
@@ -2736,7 +2834,7 @@ func (tools gccgoToolchain) link(b *builder, root *action, out string, allaction
if !apackagePathsSeen[a.p.ImportPath] {
apackagePathsSeen[a.p.ImportPath] = true
target := a.target
- if len(a.p.CgoFiles) > 0 {
+ if len(a.p.CgoFiles) > 0 || a.p.usesSwig() {
target, err = readAndRemoveCgoFlags(target)
if err != nil {
return
@@ -2928,7 +3026,7 @@ func (tools gccgoToolchain) cc(b *builder, p *Package, objdir, ofile, cfile stri
// maybePIC adds -fPIC to the list of arguments if needed.
func (tools gccgoToolchain) maybePIC(args []string) []string {
switch buildBuildmode {
- case "c-shared", "shared":
+ case "c-shared", "shared", "plugin":
args = append(args, "-fPIC")
}
return args
@@ -2969,9 +3067,19 @@ func (b *builder) gfortran(p *Package, out string, flags []string, ffile string)
}
// ccompile runs the given C or C++ compiler and creates an object from a single source file.
-func (b *builder) ccompile(p *Package, out string, flags []string, file string, compiler []string) error {
+func (b *builder) ccompile(p *Package, outfile string, flags []string, file string, compiler []string) error {
file = mkAbs(p.Dir, file)
- return b.run(p.Dir, p.ImportPath, nil, compiler, flags, "-o", out, "-c", file)
+ desc := p.ImportPath
+ output, err := b.runOut(p.Dir, desc, nil, compiler, flags, "-o", outfile, "-c", file)
+ if len(output) > 0 {
+ 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.
@@ -3125,11 +3233,8 @@ func envList(key, def string) []string {
}
// Return the flags to use when invoking the C, C++ or Fortran compilers, or cgo.
-func (b *builder) cflags(p *Package, def bool) (cppflags, cflags, cxxflags, fflags, ldflags []string) {
- var defaults string
- if def {
- defaults = "-g -O2"
- }
+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)
@@ -3141,9 +3246,9 @@ func (b *builder) cflags(p *Package, def bool) (cppflags, cflags, cxxflags, ffla
var cgoRe = regexp.MustCompile(`[/\\:]`)
-func (b *builder) cgo(p *Package, cgoExe, obj string, pcCFLAGS, pcLDFLAGS, cgofiles, gccfiles, gxxfiles, mfiles, ffiles []string) (outGo, outObj []string, err error) {
- cgoCPPFLAGS, cgoCFLAGS, cgoCXXFLAGS, cgoFFLAGS, cgoLDFLAGS := b.cflags(p, true)
- _, cgoexeCFLAGS, _, _, _ := b.cflags(p, false)
+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
@@ -3164,7 +3269,7 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, pcCFLAGS, pcLDFLAGS, cgofi
}
}
- if buildMSan && p.ImportPath != "runtime/cgo" {
+ if buildMSan {
cgoCFLAGS = append([]string{"-fsanitize=memory"}, cgoCFLAGS...)
cgoLDFLAGS = append([]string{"-fsanitize=memory"}, cgoLDFLAGS...)
}
@@ -3172,20 +3277,33 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, pcCFLAGS, pcLDFLAGS, cgofi
// 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_main.c", "_cgo_export.c"}
+ 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")
}
- defunC := obj + "_cgo_defun.c"
- cgoflags := []string{}
// TODO: make cgo not depend on $GOARCH?
+ cgoflags := []string{}
if p.Standard && p.ImportPath == "runtime/cgo" {
cgoflags = append(cgoflags, "-import_runtime_cgo=false")
}
@@ -3222,165 +3340,166 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, pcCFLAGS, pcLDFLAGS, cgofi
cgoflags = append(cgoflags, "-exportheader="+obj+"_cgo_install.h")
}
- if err := b.run(p.Dir, p.ImportPath, cgoenv, buildToolExec, cgoExe, "-objdir", obj, "-importpath", p.ImportPath, cgoflags, "--", cgoCPPFLAGS, cgoexeCFLAGS, cgofiles); err != nil {
+ 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...)
- // cc _cgo_defun.c
- _, gccgo := buildToolchain.(gccgoToolchain)
- if gccgo {
- defunObj := obj + "_cgo_defun.o"
- if err := buildToolchain.cc(b, p, obj, defunObj, defunC); err != nil {
- return nil, nil, err
- }
- outObj = append(outObj, defunObj)
- }
-
// gcc
- var linkobj []string
-
- var bareLDFLAGS []string
- // When linking relocatable objects, various flags need to be
- // filtered out as they are inapplicable and can cause some linkers
- // to fail.
- 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}"
- case strings.HasSuffix(f, ".dylib"),
- strings.HasSuffix(f, ".so"),
- strings.HasSuffix(f, ".dll"):
- // 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:
- bareLDFLAGS = append(bareLDFLAGS, f)
- }
- }
-
- var staticLibs []string
- if goos == "windows" {
- // libmingw32 and libmingwex have some inter-dependencies,
- // so must use linker groups.
- staticLibs = []string{"-Wl,--start-group", "-lmingwex", "-lmingw32", "-Wl,--end-group"}
- }
-
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
}
- linkobj = append(linkobj, ofile)
- if !strings.HasSuffix(ofile, "_cgo_main.o") {
- outObj = append(outObj, ofile)
- }
+ outObj = append(outObj, ofile)
}
for _, file := range gccfiles {
- ofile := obj + cgoRe.ReplaceAllString(file[:len(file)-1], "_") + "o"
+ 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
}
- linkobj = append(linkobj, ofile)
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(file, "_") + ".o"
+ ofile := obj + cgoRe.ReplaceAllString(filepath.Base(file), "_") + ".o"
if err := b.gxx(p, ofile, cxxflags, file); err != nil {
return nil, nil, err
}
- linkobj = append(linkobj, ofile)
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(file, "_") + ".o"
+ ofile := obj + cgoRe.ReplaceAllString(filepath.Base(file), "_") + ".o"
if err := b.gcc(p, ofile, cflags, file); err != nil {
return nil, nil, err
}
- linkobj = append(linkobj, ofile)
outObj = append(outObj, ofile)
}
fflags := stringList(cgoCPPFLAGS, cgoFFLAGS)
for _, file := range ffiles {
// Append .o to the file, just in case the pkg has file.c and file.f
- ofile := obj + cgoRe.ReplaceAllString(file, "_") + ".o"
+ ofile := obj + cgoRe.ReplaceAllString(filepath.Base(file), "_") + ".o"
if err := b.gfortran(p, ofile, fflags, file); err != nil {
return nil, nil, err
}
- linkobj = append(linkobj, ofile)
outObj = append(outObj, ofile)
}
- linkobj = append(linkobj, p.SysoFiles...)
- dynobj := obj + "_cgo_.o"
- pie := (goarch == "arm" && goos == "linux") || goos == "android"
- if pie { // we need to use -pie for Linux/ARM to get accurate imported sym
- cgoLDFLAGS = append(cgoLDFLAGS, "-pie")
- }
- if err := b.gccld(p, dynobj, cgoLDFLAGS, linkobj); err != nil {
- return nil, nil, err
+ 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()
}
- if pie { // but we don't need -pie for normal cgo programs
- cgoLDFLAGS = cgoLDFLAGS[0 : len(cgoLDFLAGS)-1]
+
+ 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
}
- if _, ok := buildToolchain.(gccgoToolchain); ok {
- // we don't use dynimport when using gccgo.
- return outGo, outObj, nil
+ 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
- importGo := obj + "_cgo_import.go"
- cgoflags = []string{}
+ var cgoflags []string
if p.Standard && p.ImportPath == "runtime/cgo" {
- cgoflags = append(cgoflags, "-dynlinker") // record path to dynamic linker
+ cgoflags = []string{"-dynlinker"} // record path to dynamic linker
}
- if err := b.run(p.Dir, p.ImportPath, nil, buildToolExec, cgoExe, "-objdir", obj, "-dynpackage", p.Name, "-dynimport", dynobj, "-dynout", importGo, cgoflags); err != nil {
- return nil, nil, err
- }
- outGo = append(outGo, importGo)
+ return b.run(p.Dir, p.ImportPath, nil, buildToolExec, cgoExe, "-dynpackage", p.Name, "-dynimport", dynobj, "-dynout", importGo, cgoflags)
+}
- ofile := obj + "_all.o"
- var gccObjs, nonGccObjs []string
- for _, f := range outObj {
- if strings.HasSuffix(f, ".o") {
- gccObjs = append(gccObjs, f)
- } else {
- nonGccObjs = append(nonGccObjs, f)
+// 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 := stringList(bareLDFLAGS, "-Wl,-r", "-nostdlib", staticLibs)
+
+ ldflags = append(ldflags, "-Wl,-r", "-nostdlib")
if b.gccSupportsNoPie() {
ldflags = append(ldflags, "-no-pie")
@@ -3389,16 +3508,7 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, pcCFLAGS, pcLDFLAGS, cgofi
// We are creating an object file, so we don't want a build ID.
ldflags = b.disableBuildID(ldflags)
- if err := b.gccld(p, ofile, ldflags, gccObjs); err != nil {
- return nil, nil, err
- }
-
- // NOTE(rsc): The importObj is a 5c/6c/8c object and on Windows
- // must be processed before the gcc-generated objects.
- // Put it first. https://golang.org/issue/2601
- outObj = stringList(nonGccObjs, ofile)
-
- return outGo, outObj, nil
+ return b.gccld(p, ofile, ldflags, outObj)
}
// Run SWIG on all SWIG input files.
@@ -3551,7 +3661,7 @@ func (b *builder) swigIntSize(obj string) (intsize string, err error) {
// Run SWIG on one SWIG input file.
func (b *builder) swigOne(p *Package, file, obj string, pcCFLAGS []string, cxx bool, intgosize string) (outGo, outC string, err error) {
- cgoCPPFLAGS, cgoCFLAGS, cgoCXXFLAGS, _, _ := b.cflags(p, true)
+ cgoCPPFLAGS, cgoCFLAGS, cgoCXXFLAGS, _, _ := b.cflags(p)
var cflags []string
if cxx {
cflags = stringList(cgoCPPFLAGS, pcCFLAGS, cgoCXXFLAGS)
@@ -3614,7 +3724,7 @@ func (b *builder) swigOne(p *Package, file, obj string, pcCFLAGS []string, cxx b
b.showOutput(p.Dir, p.ImportPath, b.processOutput(out)) // swig warning
}
- return obj + goFile, obj + gccBase + gccExt, nil
+ return goFile, obj + gccBase + gccExt, nil
}
// disableBuildID adjusts a linker command line to avoid creating a
diff --git a/src/cmd/go/build_test.go b/src/cmd/go/build_test.go
new file mode 100644
index 0000000..79bbd54
--- /dev/null
+++ b/src/cmd/go/build_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 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/env.go b/src/cmd/go/env.go
index 8aaaf46..31710b7 100644
--- a/src/cmd/go/env.go
+++ b/src/cmd/go/env.go
@@ -40,7 +40,7 @@ func mkEnv() []envVar {
{"GOHOSTARCH", runtime.GOARCH},
{"GOHOSTOS", runtime.GOOS},
{"GOOS", goos},
- {"GOPATH", os.Getenv("GOPATH")},
+ {"GOPATH", buildContext.GOPATH},
{"GORACE", os.Getenv("GORACE")},
{"GOROOT", goroot},
{"GOTOOLDIR", toolDir},
@@ -49,14 +49,25 @@ func mkEnv() []envVar {
{"TERM", "dumb"},
}
- if goos != "plan9" {
- 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 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 {
@@ -75,8 +86,24 @@ func findEnv(env []envVar, name string) string {
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 := mkEnv()
+ env := newEnv
+ env = append(env, extraEnvVars()...)
if len(args) > 0 {
for _, name := range args {
fmt.Printf("%s\n", findEnv(env, name))
diff --git a/src/cmd/go/generate.go b/src/cmd/go/generate.go
index 3c6065e..2d92a0c 100644
--- a/src/cmd/go/generate.go
+++ b/src/cmd/go/generate.go
@@ -25,7 +25,7 @@ var cmdGenerate = &Command{
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, for instance by running yacc.
+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.
@@ -88,10 +88,10 @@ string xxx represents the command identified by the arguments. This
can be used to create aliases or to handle multiword generators.
For example,
- //go:generate -command yacc go tool yacc
+ //go:generate -command foo go tool foo
-specifies that the command "yacc" represents the generator
-"go tool yacc".
+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
@@ -136,6 +136,8 @@ func init() {
}
func runGenerate(cmd *Command, args []string) {
+ ignoreImports = true
+
if generateRunFlag != "" {
var err error
generateRunRE, err = regexp.Compile(generateRunFlag)
diff --git a/src/cmd/go/get.go b/src/cmd/go/get.go
index 19858f7..82408d6 100644
--- a/src/cmd/go/get.go
+++ b/src/cmd/go/get.go
@@ -43,11 +43,13 @@ 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. See 'go help gopath'.
+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
@@ -96,13 +98,31 @@ func runGet(cmd *Command, args []string) {
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
}
- for _, arg := range downloadPaths(args) {
+ args = downloadPaths(args)
+ for _, arg := range args {
download(arg, nil, &stk, mode)
}
exitIfErrors()
@@ -137,7 +157,7 @@ func runGet(cmd *Command, args []string) {
return
}
- runInstall(cmd, args)
+ installPackages(args, true)
}
// downloadPaths prepares the list of paths to pass to download.
@@ -177,7 +197,7 @@ 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 code.google.com/p/codesearch repo
+// 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{}
@@ -368,7 +388,7 @@ func downloadPackage(p *Package) error {
repo = resolved
}
}
- if remote != repo && p.ImportComment != "" {
+ 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)
}
}
@@ -391,12 +411,16 @@ func downloadPackage(p *Package) error {
// 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")
+ return fmt.Errorf("cannot download, $GOPATH not set. For more details see: 'go help gopath'")
}
// Guard against people setting GOPATH=$GOROOT.
if list[0] == goroot {
- return fmt.Errorf("cannot download, $GOPATH must not be set to $GOROOT. For more details see: go help gopath")
+ 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")
}
@@ -425,11 +449,19 @@ func downloadPackage(p *Package) error {
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
}
diff --git a/src/cmd/go/go_test.go b/src/cmd/go/go_test.go
index 66c6413..5731066 100644
--- a/src/cmd/go/go_test.go
+++ b/src/cmd/go/go_test.go
@@ -6,7 +6,6 @@ package main_test
import (
"bytes"
- "flag"
"fmt"
"go/build"
"go/format"
@@ -50,6 +49,17 @@ func init() {
// many linux/arm machines are too slow to run
// the full set of external tests.
skipExternal = true
+ case "mips", "mipsle", "mips64", "mips64le":
+ // Also slow.
+ skipExternal = true
+ if testenv.Builder() != "" {
+ // On the builders, skip the cmd/go
+ // tests. They're too slow and already
+ // covered by other ports. There's
+ // nothing os/arch specific in the
+ // tests.
+ canRun = false
+ }
}
case "freebsd":
switch runtime.GOARCH {
@@ -67,8 +77,6 @@ func init() {
// The TestMain function creates a go command for testing purposes and
// deletes it after the tests have been run.
func TestMain(m *testing.M) {
- flag.Parse()
-
if canRun {
args := []string{"build", "-tags", "testgo", "-o", "testgo" + exeSuffix}
if race.Enabled {
@@ -99,6 +107,14 @@ func TestMain(m *testing.M) {
// Don't let these environment variables confuse the test.
os.Unsetenv("GOBIN")
os.Unsetenv("GOPATH")
+ os.Unsetenv("GIT_ALLOW_PROTOCOL")
+ 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.
+ os.Setenv("CCACHE_DIR", filepath.Join(home, ".ccache"))
+ }
+ os.Setenv("HOME", "/test-go-home-does-not-exist")
r := m.Run()
@@ -627,6 +643,7 @@ func TestProgramNameInCrashMessages(t *testing.T) {
func TestBrokenTestsWithoutTestFunctionsAllFail(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
+ // TODO: tg.parallel()
tg.runFail("test", "./testdata/src/badtest/...")
tg.grepBothNot("^ok", "test passed unexpectedly")
tg.grepBoth("FAIL.*badtest/badexec", "test did not run everything")
@@ -742,6 +759,7 @@ func TestNewReleaseRebuildsStalePackagesInGOPATH(t *testing.T) {
func TestGoListStandard(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
+ // TODO: tg.parallel()
tg.cd(runtime.GOROOT() + "/src")
tg.run("list", "-f", "{{if not .Standard}}{{.ImportPath}}{{end}}", "./...")
stdout := tg.getStdout()
@@ -766,6 +784,7 @@ func TestGoListStandard(t *testing.T) {
func TestGoInstallCleansUpAfterGoBuild(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
+ // TODO: tg.parallel()
tg.tempFile("src/mycmd/main.go", `package main; func main(){}`)
tg.setenv("GOPATH", tg.path("."))
tg.cd(tg.path("src/mycmd"))
@@ -857,6 +876,7 @@ func TestGoInstallDetectsRemovedFiles(t *testing.T) {
func TestWildcardMatchesSyntaxErrorDirs(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
+ // TODO: tg.parallel()
tg.tempFile("src/mypkg/x.go", `package mypkg`)
tg.tempFile("src/mypkg/y.go", `pkg mypackage`)
tg.setenv("GOPATH", tg.path("."))
@@ -1013,6 +1033,7 @@ func copyBad(tg *testgoData) {
func TestBadImportsEasy(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
+ // TODO: tg.parallel()
copyBad(tg)
testLocalEasy(tg, badDirName)
}
@@ -1042,14 +1063,14 @@ func TestInternalPackagesInGOROOTAreRespected(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
tg.runFail("build", "-v", "./testdata/testinternal")
- tg.grepBoth("use of internal package not allowed", "wrong error message for testdata/testinternal")
+ tg.grepBoth(`testinternal(\/|\\)p\.go\:3\:8\: use of internal package not allowed`, "wrong error message for testdata/testinternal")
}
func TestInternalPackagesOutsideGOROOTAreRespected(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
tg.runFail("build", "-v", "./testdata/testinternal2")
- tg.grepBoth("use of internal package not allowed", "wrote error message for testdata/testinternal2")
+ tg.grepBoth(`testinternal2(\/|\\)p\.go\:3\:8\: use of internal package not allowed`, "wrote error message for testdata/testinternal2")
}
func TestRunInternal(t *testing.T) {
@@ -1059,7 +1080,7 @@ func TestRunInternal(t *testing.T) {
tg.setenv("GOPATH", dir)
tg.run("run", filepath.Join(dir, "src/run/good.go"))
tg.runFail("run", filepath.Join(dir, "src/run/bad.go"))
- tg.grepStderr("use of internal package not allowed", "unexpected error for run/bad.go")
+ tg.grepStderr(`testdata(\/|\\)src(\/|\\)run(\/|\\)bad\.go\:3\:8\: use of internal package not allowed`, "unexpected error for run/bad.go")
}
func testMove(t *testing.T, vcs, url, base, config string) {
@@ -1180,6 +1201,23 @@ func TestIssue10952(t *testing.T) {
tg.run("get", "-d", "-u", importPath)
}
+func TestIssue16471(t *testing.T) {
+ testenv.MustHaveExternalNetwork(t)
+ if _, err := exec.LookPath("git"); err != nil {
+ t.Skip("skipping because git binary not found")
+ }
+
+ tg := testgo(t)
+ defer tg.cleanup()
+ tg.parallel()
+ tg.tempDir("src")
+ tg.setenv("GOPATH", tg.path("."))
+ tg.must(os.MkdirAll(tg.path("src/rsc.io/go-get-issue-10952"), 0755))
+ tg.runGit(tg.path("src/rsc.io"), "clone", "https://github.com/zombiezen/go-get-issue-10952")
+ tg.runFail("get", "-u", "rsc.io/go-get-issue-10952")
+ tg.grepStderr("rsc.io/go-get-issue-10952 is a custom import path for https://github.com/rsc/go-get-issue-10952, but .* is checked out from https://github.com/zombiezen/go-get-issue-10952", "did not detect updated import path")
+}
+
// Test git clone URL that uses SCP-like syntax and custom import path checking.
func TestIssue11457(t *testing.T) {
testenv.MustHaveExternalNetwork(t)
@@ -1192,7 +1230,7 @@ func TestIssue11457(t *testing.T) {
tg.parallel()
tg.tempDir("src")
tg.setenv("GOPATH", tg.path("."))
- const importPath = "github.com/rsc/go-get-issue-11457"
+ const importPath = "rsc.io/go-get-issue-11457"
tg.run("get", "-d", "-u", importPath)
repoDir := tg.path("src/" + importPath)
tg.runGit(repoDir, "remote", "set-url", "origin", "git at github.com:rsc/go-get-issue-11457")
@@ -1267,11 +1305,23 @@ func TestRelativeImportsGoTestDashI(t *testing.T) {
func TestRelativeImportsInCommandLinePackage(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
+ // TODO: tg.parallel()
files, err := filepath.Glob("./testdata/testimport/*.go")
tg.must(err)
tg.run(append([]string{"test"}, files...)...)
}
+func TestNonCanonicalImportPaths(t *testing.T) {
+ tg := testgo(t)
+ defer tg.cleanup()
+ tg.parallel()
+ tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
+ tg.runFail("build", "canonical/d")
+ tg.grepStderr("package canonical/d", "did not report canonical/d")
+ tg.grepStderr("imports canonical/b", "did not report canonical/b")
+ tg.grepStderr("imports canonical/a/: non-canonical", "did not report canonical/a/")
+}
+
func TestVersionControlErrorMessageIncludesCorrectDirectory(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
@@ -1317,9 +1367,6 @@ func TestInstallIntoGOPATH(t *testing.T) {
// Issue 12407
func TestBuildOutputToDevNull(t *testing.T) {
- if runtime.GOOS == "plan9" {
- t.Skip("skipping because /dev/null is a regular file on plan9")
- }
tg := testgo(t)
defer tg.cleanup()
tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
@@ -1430,6 +1477,17 @@ func TestGoGetNonPkg(t *testing.T) {
tg.grepStderr("golang.org/x/tools: no buildable Go source files", "missing error")
}
+func TestGoGetTestOnlyPkg(t *testing.T) {
+ testenv.MustHaveExternalNetwork(t)
+
+ tg := testgo(t)
+ defer tg.cleanup()
+ tg.tempDir("gopath")
+ tg.setenv("GOPATH", tg.path("gopath"))
+ tg.run("get", "golang.org/x/tour/content")
+ tg.run("get", "-t", "golang.org/x/tour/content")
+}
+
func TestInstalls(t *testing.T) {
if testing.Short() {
t.Skip("don't install into GOROOT in short mode")
@@ -1511,6 +1569,7 @@ func TestGoTestWithPackageListedMultipleTimes(t *testing.T) {
func TestGoListHasAConsistentOrder(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
+ tg.parallel()
tg.run("list", "std")
first := tg.getStdout()
tg.run("list", "std")
@@ -1522,6 +1581,7 @@ func TestGoListHasAConsistentOrder(t *testing.T) {
func TestGoListStdDoesNotIncludeCommands(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
+ tg.parallel()
tg.run("list", "std")
tg.grepStdoutNot("cmd/", "go list std shows commands")
}
@@ -1529,6 +1589,7 @@ func TestGoListStdDoesNotIncludeCommands(t *testing.T) {
func TestGoListCmdOnlyShowsCommands(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
+ tg.parallel()
tg.run("list", "cmd")
out := strings.TrimSpace(tg.getStdout())
for _, line := range strings.Split(out, "\n") {
@@ -1542,6 +1603,7 @@ func TestGoListCmdOnlyShowsCommands(t *testing.T) {
func TestGoListDedupsPackages(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
+ // TODO: tg.parallel()
tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
tg.run("list", "xtestonly", "./testdata/src/xtestonly/...")
got := strings.TrimSpace(tg.getStdout())
@@ -1555,6 +1617,7 @@ func TestGoListDedupsPackages(t *testing.T) {
func TestUnsuccessfulGoInstallShouldMentionMissingPackage(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
+ tg.parallel()
tg.runFail("install", "foo/quxx")
if tg.grepCountBoth(`cannot find package "foo/quxx" in any of`) != 1 {
t.Error(`go install foo/quxx expected error: .*cannot find package "foo/quxx" in any of`)
@@ -1564,6 +1627,7 @@ func TestUnsuccessfulGoInstallShouldMentionMissingPackage(t *testing.T) {
func TestGOROOTSearchFailureReporting(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
+ tg.parallel()
tg.runFail("install", "foo/quxx")
if tg.grepCountBoth(regexp.QuoteMeta(filepath.Join("foo", "quxx"))+` \(from \$GOROOT\)$`) != 1 {
t.Error(`go install foo/quxx expected error: .*foo/quxx (from $GOROOT)`)
@@ -1573,6 +1637,7 @@ func TestGOROOTSearchFailureReporting(t *testing.T) {
func TestMultipleGOPATHEntriesReportedSeparately(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
+ tg.parallel()
sep := string(filepath.ListSeparator)
tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata", "a")+sep+filepath.Join(tg.pwd(), "testdata", "b"))
tg.runFail("install", "foo/quxx")
@@ -1585,6 +1650,7 @@ func TestMultipleGOPATHEntriesReportedSeparately(t *testing.T) {
func TestMentionGOPATHInFirstGOPATHEntry(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
+ tg.parallel()
sep := string(filepath.ListSeparator)
tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata", "a")+sep+filepath.Join(tg.pwd(), "testdata", "b"))
tg.runFail("install", "foo/quxx")
@@ -1597,6 +1663,7 @@ func TestMentionGOPATHInFirstGOPATHEntry(t *testing.T) {
func TestMentionGOPATHNotOnSecondEntry(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
+ tg.parallel()
sep := string(filepath.ListSeparator)
tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata", "a")+sep+filepath.Join(tg.pwd(), "testdata", "b"))
tg.runFail("install", "foo/quxx")
@@ -1605,14 +1672,150 @@ func TestMentionGOPATHNotOnSecondEntry(t *testing.T) {
}
}
-// Test missing GOPATH is reported.
-func TestMissingGOPATHIsReported(t *testing.T) {
+func homeEnvName() string {
+ switch runtime.GOOS {
+ case "windows":
+ return "USERPROFILE"
+ case "plan9":
+ return "home"
+ default:
+ return "HOME"
+ }
+}
+
+// Test go env missing GOPATH shows default.
+func TestMissingGOPATHEnvShowsDefault(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
+ tg.parallel()
tg.setenv("GOPATH", "")
- tg.runFail("install", "foo/quxx")
- if tg.grepCountBoth(`\(\$GOPATH not set\)$`) != 1 {
- t.Error(`go install foo/quxx expected error: ($GOPATH not set)`)
+ tg.run("env", "GOPATH")
+
+ want := filepath.Join(os.Getenv(homeEnvName()), "go")
+ got := strings.TrimSpace(tg.getStdout())
+ if got != want {
+ t.Errorf("got %q; want %q", got, want)
+ }
+}
+
+// Test go get missing GOPATH causes go get to warn if directory doesn't exist.
+func TestMissingGOPATHGetWarnsIfNotExists(t *testing.T) {
+ if _, err := exec.LookPath("git"); err != nil {
+ t.Skip("skipping because git binary not found")
+ }
+
+ tg := testgo(t)
+ defer tg.cleanup()
+
+ // setenv variables for test and defer deleting temporary home directory.
+ tg.setenv("GOPATH", "")
+ tmp, err := ioutil.TempDir("", "")
+ if err != nil {
+ t.Fatalf("could not create tmp home: %v", err)
+ }
+ defer os.RemoveAll(tmp)
+ tg.setenv(homeEnvName(), tmp)
+
+ tg.run("get", "-v", "github.com/golang/example/hello")
+
+ want := fmt.Sprintf("created GOPATH=%s; see 'go help gopath'", filepath.Join(tmp, "go"))
+ got := strings.TrimSpace(tg.getStderr())
+ if !strings.Contains(got, want) {
+ t.Errorf("got %q; want %q", got, want)
+ }
+}
+
+// Test go get missing GOPATH causes no warning if directory exists.
+func TestMissingGOPATHGetDoesntWarnIfExists(t *testing.T) {
+ if _, err := exec.LookPath("git"); err != nil {
+ t.Skip("skipping because git binary not found")
+ }
+
+ tg := testgo(t)
+ defer tg.cleanup()
+
+ // setenv variables for test and defer resetting them.
+ tg.setenv("GOPATH", "")
+ tmp, err := ioutil.TempDir("", "")
+ if err != nil {
+ t.Fatalf("could not create tmp home: %v", err)
+ }
+ defer os.RemoveAll(tmp)
+ if err := os.Mkdir(filepath.Join(tmp, "go"), 0777); err != nil {
+ t.Fatalf("could not create $HOME/go: %v", err)
+ }
+
+ tg.setenv(homeEnvName(), tmp)
+
+ tg.run("get", "github.com/golang/example/hello")
+
+ got := strings.TrimSpace(tg.getStderr())
+ if got != "" {
+ t.Errorf("got %q; wants empty", got)
+ }
+}
+
+// Test go get missing GOPATH fails if pointed file is not a directory.
+func TestMissingGOPATHGetFailsIfItsNotDirectory(t *testing.T) {
+ tg := testgo(t)
+ defer tg.cleanup()
+
+ // setenv variables for test and defer resetting them.
+ tg.setenv("GOPATH", "")
+ tmp, err := ioutil.TempDir("", "")
+ if err != nil {
+ t.Fatalf("could not create tmp home: %v", err)
+ }
+ defer os.RemoveAll(tmp)
+
+ path := filepath.Join(tmp, "go")
+ if err := ioutil.WriteFile(path, nil, 0777); err != nil {
+ t.Fatalf("could not create GOPATH at %s: %v", path, err)
+ }
+ tg.setenv(homeEnvName(), tmp)
+
+ const pkg = "github.com/golang/example/hello"
+ tg.runFail("get", pkg)
+
+ msg := "not a directory"
+ if runtime.GOOS == "windows" {
+ msg = "The system cannot find the path specified."
+ }
+ want := fmt.Sprintf("package %s: mkdir %s: %s", pkg, filepath.Join(tmp, "go"), msg)
+ got := strings.TrimSpace(tg.getStderr())
+ if got != want {
+ t.Errorf("got %q; wants %q", got, want)
+ }
+}
+
+// Test go install of missing package when missing GOPATH fails and shows default GOPATH.
+func TestMissingGOPATHInstallMissingPackageFailsAndShowsDefault(t *testing.T) {
+ tg := testgo(t)
+ defer tg.cleanup()
+
+ // setenv variables for test and defer resetting them.
+ tg.setenv("GOPATH", "")
+ tmp, err := ioutil.TempDir("", "")
+ if err != nil {
+ t.Fatalf("could not create tmp home: %v", err)
+ }
+ defer os.RemoveAll(tmp)
+ if err := os.Mkdir(filepath.Join(tmp, "go"), 0777); err != nil {
+ t.Fatalf("could not create $HOME/go: %v", err)
+ }
+ tg.setenv(homeEnvName(), tmp)
+
+ const pkg = "github.com/golang/example/hello"
+ tg.runFail("install", pkg)
+
+ pkgPath := filepath.Join(strings.Split(pkg, "/")...)
+ want := fmt.Sprintf("can't load package: package %s: cannot find package \"%s\" in any of:", pkg, pkg) +
+ fmt.Sprintf("\n\t%s (from $GOROOT)", filepath.Join(runtime.GOROOT(), "src", pkgPath)) +
+ fmt.Sprintf("\n\t%s (from $GOPATH)", filepath.Join(tmp, "go", "src", pkgPath))
+
+ got := strings.TrimSpace(tg.getStderr())
+ if got != want {
+ t.Errorf("got %q; wants %q", got, want)
}
}
@@ -1659,6 +1862,7 @@ func TestLdflagsArgumentsWithSpacesIssue3941(t *testing.T) {
func TestGoTestCpuprofileLeavesBinaryBehind(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
+ // TODO: tg.parallel()
tg.makeTempdir()
tg.cd(tg.path("."))
tg.run("test", "-cpuprofile", "errors.prof", "errors")
@@ -1668,6 +1872,7 @@ func TestGoTestCpuprofileLeavesBinaryBehind(t *testing.T) {
func TestGoTestCpuprofileDashOControlsBinaryLocation(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
+ // TODO: tg.parallel()
tg.makeTempdir()
tg.cd(tg.path("."))
tg.run("test", "-cpuprofile", "errors.prof", "-o", "myerrors.test"+exeSuffix, "errors")
@@ -1692,6 +1897,16 @@ func TestGoTestDashOWritesBinary(t *testing.T) {
tg.wantExecutable(tg.path("myerrors.test"+exeSuffix), "go test -o myerrors.test did not create myerrors.test")
}
+func TestGoTestDashIDashOWritesBinary(t *testing.T) {
+ tg := testgo(t)
+ defer tg.cleanup()
+ tg.parallel()
+ tg.makeTempdir()
+ tg.run("test", "-v", "-i", "-o", tg.path("myerrors.test"+exeSuffix), "errors")
+ tg.grepBothNot("PASS|FAIL", "test should not have run")
+ tg.wantExecutable(tg.path("myerrors.test"+exeSuffix), "go test -o myerrors.test did not create myerrors.test")
+}
+
// Issue 4568.
func TestSymlinksList(t *testing.T) {
switch runtime.GOOS {
@@ -1701,6 +1916,7 @@ func TestSymlinksList(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
+ // TODO: tg.parallel()
tg.tempDir("src")
tg.must(os.Symlink(tg.path("."), tg.path("src/dir1")))
tg.tempFile("src/dir1/p.go", "package p")
@@ -1721,6 +1937,7 @@ func TestSymlinksVendor(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
+ // TODO: tg.parallel()
tg.tempDir("gopath/src/dir1/vendor/v")
tg.tempFile("gopath/src/dir1/p.go", "package main\nimport _ `v`\nfunc main(){}")
tg.tempFile("gopath/src/dir1/vendor/v/v.go", "package v")
@@ -1738,6 +1955,27 @@ func TestSymlinksVendor(t *testing.T) {
tg.run("install")
}
+// Issue 15201.
+func TestSymlinksVendor15201(t *testing.T) {
+ switch runtime.GOOS {
+ case "plan9", "windows":
+ t.Skipf("skipping symlink test on %s", runtime.GOOS)
+ }
+
+ tg := testgo(t)
+ defer tg.cleanup()
+
+ tg.tempDir("gopath/src/x/y/_vendor/src/x")
+ tg.must(os.Symlink("../../..", tg.path("gopath/src/x/y/_vendor/src/x/y")))
+ tg.tempFile("gopath/src/x/y/w/w.go", "package w\nimport \"x/y/z\"\n")
+ tg.must(os.Symlink("../_vendor/src", tg.path("gopath/src/x/y/w/vendor")))
+ tg.tempFile("gopath/src/x/y/z/z.go", "package z\n")
+
+ tg.setenv("GOPATH", tg.path("gopath/src/x/y/_vendor")+string(filepath.ListSeparator)+tg.path("gopath"))
+ tg.cd(tg.path("gopath/src"))
+ tg.run("list", "./...")
+}
+
func TestSymlinksInternal(t *testing.T) {
switch runtime.GOOS {
case "plan9", "windows":
@@ -1840,7 +2078,7 @@ func TestGoGetDashTIssue8181(t *testing.T) {
tg.setenv("GOPATH", tg.path("."))
tg.run("get", "-v", "-t", "github.com/rsc/go-get-issue-8181/a", "github.com/rsc/go-get-issue-8181/b")
tg.run("list", "...")
- tg.grepStdout("x/build/cmd/cl", "missing expected x/build/cmd/cl")
+ tg.grepStdout("x/build/gerrit", "missing expected x/build/gerrit")
}
func TestIssue11307(t *testing.T) {
@@ -1997,6 +2235,16 @@ func TestCoverageUsesActualSettingToOverrideEvenForRace(t *testing.T) {
checkCoverage(tg, data)
}
+func TestCoverageImportMainLoop(t *testing.T) {
+ tg := testgo(t)
+ defer tg.cleanup()
+ tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
+ tg.runFail("test", "importmain/test")
+ tg.grepStderr("not an importable package", "did not detect import main")
+ tg.runFail("test", "-cover", "importmain/test")
+ tg.grepStderr("not an importable package", "did not detect import main")
+}
+
func TestBuildDryRunWithCgo(t *testing.T) {
if !canCgo {
t.Skip("skipping because cgo not enabled")
@@ -2023,11 +2271,17 @@ func TestCoverageWithCgo(t *testing.T) {
t.Skip("skipping because cgo not enabled")
}
- tg := testgo(t)
- defer tg.cleanup()
- tg.run("test", "-short", "-cover", "./testdata/cgocover")
- data := tg.getStdout() + tg.getStderr()
- checkCoverage(tg, data)
+ for _, dir := range []string{"cgocover", "cgocover2", "cgocover3", "cgocover4"} {
+ t.Run(dir, func(t *testing.T) {
+ tg := testgo(t)
+ tg.parallel()
+ defer tg.cleanup()
+ tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
+ tg.run("test", "-short", "-cover", dir)
+ data := tg.getStdout() + tg.getStderr()
+ checkCoverage(tg, data)
+ })
+ }
}
func TestCgoDependsOnSyscall(t *testing.T) {
@@ -2090,10 +2344,57 @@ func TestCgoHandlesWlORIGIN(t *testing.T) {
tg.run("build", "origin")
}
+func TestCgoPkgConfig(t *testing.T) {
+ if !canCgo {
+ t.Skip("skipping because cgo not enabled")
+ }
+ tg := testgo(t)
+ defer tg.cleanup()
+ tg.parallel()
+
+ tg.run("env", "PKG_CONFIG")
+ pkgConfig := strings.TrimSpace(tg.getStdout())
+ if out, err := exec.Command(pkgConfig, "--atleast-pkgconfig-version", "0.24").CombinedOutput(); err != nil {
+ t.Skipf("%s --atleast-pkgconfig-version 0.24: %v\n%s", pkgConfig, err, out)
+ }
+
+ // OpenBSD's pkg-config is strict about whitespace and only
+ // supports backslash-escaped whitespace. It does not support
+ // quotes, which the normal freedesktop.org pkg-config does
+ // support. See http://man.openbsd.org/pkg-config.1
+ tg.tempFile("foo.pc", `
+Name: foo
+Description: The foo library
+Version: 1.0.0
+Cflags: -Dhello=10 -Dworld=+32 -DDEFINED_FROM_PKG_CONFIG=hello\ world
+`)
+ tg.tempFile("foo.go", `package main
+
+/*
+#cgo pkg-config: foo
+int value() {
+ return DEFINED_FROM_PKG_CONFIG;
+}
+*/
+import "C"
+import "os"
+
+func main() {
+ if C.value() != 42 {
+ println("value() =", C.value(), "wanted 42")
+ os.Exit(1)
+ }
+}
+`)
+ tg.setenv("PKG_CONFIG_PATH", tg.path("."))
+ tg.run("run", tg.path("foo.go"))
+}
+
// "go test -c -test.bench=XXX errors" should not hang
func TestIssue6480(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
+ // TODO: tg.parallel()
tg.makeTempdir()
tg.cd(tg.path("."))
tg.run("test", "-c", "-test.bench=XXX", "errors")
@@ -2124,8 +2425,7 @@ func main() { C.f() }`)
}
func TestListTemplateContextFunction(t *testing.T) {
- tg := testgo(t)
- defer tg.cleanup()
+ t.Parallel()
for _, tt := range []struct {
v string
want string
@@ -2141,14 +2441,20 @@ func TestListTemplateContextFunction(t *testing.T) {
{"ReleaseTags", ""},
{"InstallSuffix", ""},
} {
- tmpl := "{{context." + tt.v + "}}"
- tg.run("list", "-f", tmpl)
- if tt.want == "" {
- continue
- }
- if got := strings.TrimSpace(tg.getStdout()); got != tt.want {
- t.Errorf("go list -f %q: got %q; want %q", tmpl, got, tt.want)
- }
+ tt := tt
+ t.Run(tt.v, func(t *testing.T) {
+ tg := testgo(t)
+ tg.parallel()
+ defer tg.cleanup()
+ tmpl := "{{context." + tt.v + "}}"
+ tg.run("list", "-f", tmpl)
+ if tt.want == "" {
+ return
+ }
+ if got := strings.TrimSpace(tg.getStdout()); got != tt.want {
+ t.Errorf("go list -f %q: got %q; want %q", tmpl, got, tt.want)
+ }
+ })
}
}
@@ -2307,6 +2613,20 @@ func TestGoGenerateEnv(t *testing.T) {
}
}
+func TestGoGenerateBadImports(t *testing.T) {
+ if runtime.GOOS == "windows" {
+ t.Skip("skipping because windows has no echo command")
+ }
+
+ // This package has an invalid import causing an import cycle,
+ // but go generate is supposed to still run.
+ tg := testgo(t)
+ defer tg.cleanup()
+ tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
+ tg.run("generate", "gencycle")
+ tg.grepStdout("hello world", "go generate gencycle did not run generator")
+}
+
func TestGoGetCustomDomainWildcard(t *testing.T) {
testenv.MustHaveExternalNetwork(t)
@@ -2382,35 +2702,254 @@ func TestGoGetHTTPS404(t *testing.T) {
}
// Test that you cannot import a main package.
-func TestIssue4210(t *testing.T) {
+// See golang.org/issue/4210 and golang.org/issue/17475.
+func TestImportMain(t *testing.T) {
tg := testgo(t)
+ tg.parallel()
defer tg.cleanup()
+
+ // Importing package main from that package main's test should work.
tg.tempFile("src/x/main.go", `package main
var X int
func main() {}`)
- tg.tempFile("src/y/main.go", `package main
- import "fmt"
+ tg.tempFile("src/x/main_test.go", `package main_test
import xmain "x"
- func main() {
- fmt.Println(xmain.X)
- }`)
+ import "testing"
+ var _ = xmain.X
+ func TestFoo(t *testing.T) {}
+ `)
+ tg.setenv("GOPATH", tg.path("."))
+ tg.creatingTemp("x")
+ tg.run("build", "x")
+ tg.run("test", "x")
+
+ // Importing package main from another package should fail.
+ tg.tempFile("src/p1/p.go", `package p1
+ import xmain "x"
+ var _ = xmain.X
+ `)
+ tg.runFail("build", "p1")
+ tg.grepStderr("import \"x\" is a program, not an importable package", "did not diagnose package main")
+
+ // ... even in that package's test.
+ tg.tempFile("src/p2/p.go", `package p2
+ `)
+ tg.tempFile("src/p2/p_test.go", `package p2
+ import xmain "x"
+ import "testing"
+ var _ = xmain.X
+ func TestFoo(t *testing.T) {}
+ `)
+ tg.run("build", "p2")
+ tg.runFail("test", "p2")
+ tg.grepStderr("import \"x\" is a program, not an importable package", "did not diagnose package main")
+
+ // ... even if that package's test is an xtest.
+ tg.tempFile("src/p3/p.go", `package p
+ `)
+ tg.tempFile("src/p3/p_test.go", `package p_test
+ import xmain "x"
+ import "testing"
+ var _ = xmain.X
+ func TestFoo(t *testing.T) {}
+ `)
+ tg.run("build", "p3")
+ tg.runFail("test", "p3")
+ tg.grepStderr("import \"x\" is a program, not an importable package", "did not diagnose package main")
+
+ // ... even if that package is a package main
+ tg.tempFile("src/p4/p.go", `package main
+ func main() {}
+ `)
+ tg.tempFile("src/p4/p_test.go", `package main
+ import xmain "x"
+ import "testing"
+ var _ = xmain.X
+ func TestFoo(t *testing.T) {}
+ `)
+ tg.creatingTemp("p4" + exeSuffix)
+ tg.run("build", "p4")
+ tg.runFail("test", "p4")
+ tg.grepStderr("import \"x\" is a program, not an importable package", "did not diagnose package main")
+
+ // ... even if that package is a package main using an xtest.
+ tg.tempFile("src/p5/p.go", `package main
+ func main() {}
+ `)
+ tg.tempFile("src/p5/p_test.go", `package main_test
+ import xmain "x"
+ import "testing"
+ var _ = xmain.X
+ func TestFoo(t *testing.T) {}
+ `)
+ tg.creatingTemp("p5" + exeSuffix)
+ tg.run("build", "p5")
+ tg.runFail("test", "p5")
+ tg.grepStderr("import \"x\" is a program, not an importable package", "did not diagnose package main")
+}
+
+// Test that you cannot use a local import in a package
+// accessed by a non-local import (found in a GOPATH/GOROOT).
+// See golang.org/issue/17475.
+func TestImportLocal(t *testing.T) {
+ tg := testgo(t)
+ tg.parallel()
+ defer tg.cleanup()
+
+ tg.tempFile("src/dir/x/x.go", `package x
+ var X int
+ `)
tg.setenv("GOPATH", tg.path("."))
- tg.runFail("build", "y")
- tg.grepBoth("is a program", `did not find expected error message ("is a program")`)
+ tg.run("build", "dir/x")
+
+ // Ordinary import should work.
+ tg.tempFile("src/dir/p0/p.go", `package p0
+ import "dir/x"
+ var _ = x.X
+ `)
+ tg.run("build", "dir/p0")
+
+ // Relative import should not.
+ tg.tempFile("src/dir/p1/p.go", `package p1
+ import "../x"
+ var _ = x.X
+ `)
+ tg.runFail("build", "dir/p1")
+ tg.grepStderr("local import.*in non-local package", "did not diagnose local import")
+
+ // ... even in a test.
+ tg.tempFile("src/dir/p2/p.go", `package p2
+ `)
+ tg.tempFile("src/dir/p2/p_test.go", `package p2
+ import "../x"
+ import "testing"
+ var _ = x.X
+ func TestFoo(t *testing.T) {}
+ `)
+ tg.run("build", "dir/p2")
+ tg.runFail("test", "dir/p2")
+ tg.grepStderr("local import.*in non-local package", "did not diagnose local import")
+
+ // ... even in an xtest.
+ tg.tempFile("src/dir/p2/p_test.go", `package p2_test
+ import "../x"
+ import "testing"
+ var _ = x.X
+ func TestFoo(t *testing.T) {}
+ `)
+ tg.run("build", "dir/p2")
+ tg.runFail("test", "dir/p2")
+ tg.grepStderr("local import.*in non-local package", "did not diagnose local import")
+
+ // Relative import starting with ./ should not work either.
+ tg.tempFile("src/dir/d.go", `package dir
+ import "./x"
+ var _ = x.X
+ `)
+ tg.runFail("build", "dir")
+ tg.grepStderr("local import.*in non-local package", "did not diagnose local import")
+
+ // ... even in a test.
+ tg.tempFile("src/dir/d.go", `package dir
+ `)
+ tg.tempFile("src/dir/d_test.go", `package dir
+ import "./x"
+ import "testing"
+ var _ = x.X
+ func TestFoo(t *testing.T) {}
+ `)
+ tg.run("build", "dir")
+ tg.runFail("test", "dir")
+ tg.grepStderr("local import.*in non-local package", "did not diagnose local import")
+
+ // ... even in an xtest.
+ tg.tempFile("src/dir/d_test.go", `package dir_test
+ import "./x"
+ import "testing"
+ var _ = x.X
+ func TestFoo(t *testing.T) {}
+ `)
+ tg.run("build", "dir")
+ tg.runFail("test", "dir")
+ tg.grepStderr("local import.*in non-local package", "did not diagnose local import")
+
+ // Relative import plain ".." should not work.
+ tg.tempFile("src/dir/x/y/y.go", `package dir
+ import ".."
+ var _ = x.X
+ `)
+ tg.runFail("build", "dir/x/y")
+ tg.grepStderr("local import.*in non-local package", "did not diagnose local import")
+
+ // ... even in a test.
+ tg.tempFile("src/dir/x/y/y.go", `package y
+ `)
+ tg.tempFile("src/dir/x/y/y_test.go", `package y
+ import ".."
+ import "testing"
+ var _ = x.X
+ func TestFoo(t *testing.T) {}
+ `)
+ tg.run("build", "dir/x/y")
+ tg.runFail("test", "dir/x/y")
+ tg.grepStderr("local import.*in non-local package", "did not diagnose local import")
+
+ // ... even in an x test.
+ tg.tempFile("src/dir/x/y/y_test.go", `package y_test
+ import ".."
+ import "testing"
+ var _ = x.X
+ func TestFoo(t *testing.T) {}
+ `)
+ tg.run("build", "dir/x/y")
+ tg.runFail("test", "dir/x/y")
+ tg.grepStderr("local import.*in non-local package", "did not diagnose local import")
+
+ // Relative import "." should not work.
+ tg.tempFile("src/dir/x/xx.go", `package x
+ import "."
+ var _ = x.X
+ `)
+ tg.runFail("build", "dir/x")
+ tg.grepStderr("local import.*in non-local package", "did not diagnose local import")
+
+ // ... even in a test.
+ tg.tempFile("src/dir/x/xx.go", `package x
+ `)
+ tg.tempFile("src/dir/x/xx_test.go", `package x
+ import "."
+ import "testing"
+ var _ = x.X
+ func TestFoo(t *testing.T) {}
+ `)
+ tg.run("build", "dir/x")
+ tg.runFail("test", "dir/x")
+ tg.grepStderr("local import.*in non-local package", "did not diagnose local import")
+
+ // ... even in an xtest.
+ tg.tempFile("src/dir/x/xx.go", `package x
+ `)
+ tg.tempFile("src/dir/x/xx_test.go", `package x_test
+ import "."
+ import "testing"
+ var _ = x.X
+ func TestFoo(t *testing.T) {}
+ `)
+ tg.run("build", "dir/x")
+ tg.runFail("test", "dir/x")
+ tg.grepStderr("local import.*in non-local package", "did not diagnose local import")
}
func TestGoGetInsecure(t *testing.T) {
testenv.MustHaveExternalNetwork(t)
- t.Skip("golang.org/issue/15410")
-
tg := testgo(t)
defer tg.cleanup()
tg.makeTempdir()
tg.setenv("GOPATH", tg.path("."))
tg.failSSH()
- const repo = "wh3rd.net/git.git"
+ const repo = "insecure.go-get-issue-15410.appspot.com/pkg/p"
// Try go get -d of HTTP-only repo (should fail).
tg.runFail("get", "-d", repo)
@@ -2454,7 +2993,7 @@ func TestGoGetInsecureCustomDomain(t *testing.T) {
tg.makeTempdir()
tg.setenv("GOPATH", tg.path("."))
- const repo = "wh3rd.net/repo"
+ const repo = "insecure.go-get-issue-15410.appspot.com/pkg/p"
tg.runFail("get", "-d", repo)
tg.run("get", "-d", "-insecure", repo)
}
@@ -2471,6 +3010,7 @@ func TestGoRunDirs(t *testing.T) {
func TestGoInstallPkgdir(t *testing.T) {
tg := testgo(t)
+ tg.parallel()
defer tg.cleanup()
tg.makeTempdir()
pkg := tg.path(".")
@@ -2509,6 +3049,27 @@ func TestGoTestRaceInstallCgo(t *testing.T) {
}
}
+func TestGoTestRaceFailures(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", "testrace")
+ tg.grepStdout("FAIL: TestRace", "TestRace did not fail")
+ tg.grepBothNot("PASS", "something passed")
+
+ tg.runFail("test", "-race", "testrace", "-run", "XXX", "-bench", ".")
+ tg.grepStdout("FAIL: BenchmarkRace", "BenchmarkRace did not fail")
+ tg.grepBothNot("PASS", "something passed")
+}
+
func TestGoTestImportErrorStack(t *testing.T) {
const out = `package testdep/p1 (test)
imports testdep/p2
@@ -2773,6 +3334,7 @@ func TestIssue13655(t *testing.T) {
// For issue 14337.
func TestParallelTest(t *testing.T) {
tg := testgo(t)
+ tg.parallel()
defer tg.cleanup()
tg.makeTempdir()
const testSrc = `package package_test
@@ -2832,10 +3394,23 @@ func TestGoGetUpdateAllDoesNotTryToLoadDuplicates(t *testing.T) {
tg.grepStderrNot("duplicate loads of", "did not remove old packages from cache")
}
+// Issue 17119 more duplicate load errors
+func TestIssue17119(t *testing.T) {
+ testenv.MustHaveExternalNetwork(t)
+
+ tg := testgo(t)
+ defer tg.cleanup()
+ tg.parallel()
+ tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
+ tg.runFail("build", "dupload")
+ tg.grepBothNot("duplicate load|internal error", "internal error")
+}
+
func TestFatalInBenchmarkCauseNonZeroExitStatus(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
- tg.runFail("test", "-bench", ".", "./testdata/src/benchfatal")
+ // TODO: tg.parallel()
+ tg.runFail("test", "-run", "^$", "-bench", ".", "./testdata/src/benchfatal")
tg.grepBothNot("^ok", "test passed unexpectedly")
tg.grepBoth("FAIL.*benchfatal", "test did not run everything")
}
@@ -2843,6 +3418,7 @@ func TestFatalInBenchmarkCauseNonZeroExitStatus(t *testing.T) {
func TestBinaryOnlyPackages(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
+ tg.parallel()
tg.makeTempdir()
tg.setenv("GOPATH", tg.path("."))
@@ -2907,6 +3483,16 @@ func TestBinaryOnlyPackages(t *testing.T) {
tg.run("run", tg.path("src/p3/p3.go"))
tg.grepStdout("hello from p1", "did not see message from p1")
+
+ tg.tempFile("src/p4/p4.go", `package main`)
+ tg.tempFile("src/p4/p4not.go", `//go:binary-only-package
+
+ // +build asdf
+
+ package main
+ `)
+ tg.run("list", "-f", "{{.BinaryOnly}}", "p4")
+ tg.grepStdout("false", "did not see BinaryOnly=false for p4")
}
// Issue 16050.
@@ -2954,3 +3540,179 @@ func TestGenerateUsesBuildContext(t *testing.T) {
tg.run("generate", "gen")
tg.grepStdout("darwin 386", "unexpected GOOS/GOARCH combination")
}
+
+// Issue 14450: go get -u .../ tried to import not downloaded package
+func TestGoGetUpdateWithWildcard(t *testing.T) {
+ testenv.MustHaveExternalNetwork(t)
+
+ tg := testgo(t)
+ defer tg.cleanup()
+ tg.parallel()
+ tg.makeTempdir()
+ tg.setenv("GOPATH", tg.path("."))
+ const aPkgImportPath = "github.com/tmwh/go-get-issue-14450/a"
+ tg.run("get", aPkgImportPath)
+ tg.run("get", "-u", ".../")
+ tg.grepStderrNot("cannot find package", "did not update packages given wildcard path")
+
+ var expectedPkgPaths = []string{
+ "src/github.com/tmwh/go-get-issue-14450/b",
+ "src/github.com/tmwh/go-get-issue-14450-b-dependency/c",
+ "src/github.com/tmwh/go-get-issue-14450-b-dependency/d",
+ }
+
+ for _, importPath := range expectedPkgPaths {
+ _, err := os.Stat(tg.path(importPath))
+ tg.must(err)
+ }
+ const notExpectedPkgPath = "src/github.com/tmwh/go-get-issue-14450-c-dependency/e"
+ tg.mustNotExist(tg.path(notExpectedPkgPath))
+}
+
+func TestGoEnv(t *testing.T) {
+ tg := testgo(t)
+ tg.parallel()
+ defer tg.cleanup()
+ tg.setenv("GOARCH", "arm")
+ tg.run("env", "GOARCH")
+ tg.grepStdout("^arm$", "GOARCH not honored")
+
+ tg.run("env", "GCCGO")
+ tg.grepStdout(".", "GCCGO unexpectedly empty")
+
+ tg.run("env", "CGO_CFLAGS")
+ tg.grepStdout(".", "default CGO_CFLAGS unexpectedly empty")
+
+ tg.setenv("CGO_CFLAGS", "-foobar")
+ tg.run("env", "CGO_CFLAGS")
+ tg.grepStdout("^-foobar$", "CGO_CFLAGS not honored")
+
+ tg.setenv("CC", "gcc -fmust -fgo -ffaster")
+ tg.run("env", "CC")
+ tg.grepStdout("gcc", "CC not found")
+ tg.run("env", "GOGCCFLAGS")
+ tg.grepStdout("-ffaster", "CC arguments not found")
+}
+
+const (
+ noMatchesPattern = `(?m)^ok.*\[no tests to run\]`
+ okPattern = `(?m)^ok`
+)
+
+func TestMatchesNoTests(t *testing.T) {
+ tg := testgo(t)
+ defer tg.cleanup()
+ // TODO: tg.parallel()
+ tg.run("test", "-run", "ThisWillNotMatch", "testdata/standalone_test.go")
+ tg.grepBoth(noMatchesPattern, "go test did not say [no tests to run]")
+}
+
+func TestMatchesNoTestsDoesNotOverrideBuildFailure(t *testing.T) {
+ tg := testgo(t)
+ defer tg.cleanup()
+ tg.parallel()
+ tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
+ tg.runFail("test", "-run", "ThisWillNotMatch", "syntaxerror")
+ tg.grepBothNot(noMatchesPattern, "go test did say [no tests to run]")
+ tg.grepBoth("FAIL", "go test did not say FAIL")
+}
+
+func TestMatchesNoBenchmarksIsOK(t *testing.T) {
+ tg := testgo(t)
+ defer tg.cleanup()
+ // TODO: tg.parallel()
+ tg.run("test", "-run", "^$", "-bench", "ThisWillNotMatch", "testdata/standalone_benchmark_test.go")
+ tg.grepBothNot(noMatchesPattern, "go test did say [no tests to run]")
+ tg.grepBoth(okPattern, "go test did not say ok")
+}
+
+func TestMatchesOnlyExampleIsOK(t *testing.T) {
+ tg := testgo(t)
+ defer tg.cleanup()
+ // TODO: tg.parallel()
+ tg.run("test", "-run", "Example", "testdata/example1_test.go")
+ tg.grepBothNot(noMatchesPattern, "go test did say [no tests to run]")
+ tg.grepBoth(okPattern, "go test did not say ok")
+}
+
+func TestMatchesOnlyBenchmarkIsOK(t *testing.T) {
+ tg := testgo(t)
+ defer tg.cleanup()
+ // TODO: tg.parallel()
+ tg.run("test", "-run", "^$", "-bench", ".", "testdata/standalone_benchmark_test.go")
+ tg.grepBothNot(noMatchesPattern, "go test did say [no tests to run]")
+ tg.grepBoth(okPattern, "go test did not say ok")
+}
+
+func TestMatchesOnlyTestIsOK(t *testing.T) {
+ tg := testgo(t)
+ defer tg.cleanup()
+ // TODO: tg.parallel()
+ tg.run("test", "-run", "Test", "testdata/standalone_test.go")
+ tg.grepBothNot(noMatchesPattern, "go test did say [no tests to run]")
+ tg.grepBoth(okPattern, "go test did not say ok")
+}
+
+func TestMatchesNoTestsWithSubtests(t *testing.T) {
+ tg := testgo(t)
+ defer tg.cleanup()
+ tg.run("test", "-run", "ThisWillNotMatch", "testdata/standalone_sub_test.go")
+ tg.grepBoth(noMatchesPattern, "go test did not say [no tests to run]")
+}
+
+func TestMatchesNoSubtestsMatch(t *testing.T) {
+ tg := testgo(t)
+ defer tg.cleanup()
+ tg.run("test", "-run", "Test/ThisWillNotMatch", "testdata/standalone_sub_test.go")
+ tg.grepBoth(noMatchesPattern, "go test did not say [no tests to run]")
+}
+
+func TestMatchesNoSubtestsDoesNotOverrideFailure(t *testing.T) {
+ tg := testgo(t)
+ defer tg.cleanup()
+ tg.runFail("test", "-run", "TestThatFails/ThisWillNotMatch", "testdata/standalone_fail_sub_test.go")
+ tg.grepBothNot(noMatchesPattern, "go test did say [no tests to run]")
+ tg.grepBoth("FAIL", "go test did not say FAIL")
+}
+
+func TestMatchesOnlySubtestIsOK(t *testing.T) {
+ tg := testgo(t)
+ defer tg.cleanup()
+ tg.run("test", "-run", "Test/Sub", "testdata/standalone_sub_test.go")
+ tg.grepBothNot(noMatchesPattern, "go test did say [no tests to run]")
+ tg.grepBoth(okPattern, "go test did not say ok")
+}
+
+func TestMatchesNoSubtestsParallel(t *testing.T) {
+ tg := testgo(t)
+ defer tg.cleanup()
+ tg.run("test", "-run", "Test/Sub/ThisWillNotMatch", "testdata/standalone_parallel_sub_test.go")
+ tg.grepBoth(noMatchesPattern, "go test did not say [no tests to run]")
+}
+
+func TestMatchesOnlySubtestParallelIsOK(t *testing.T) {
+ tg := testgo(t)
+ defer tg.cleanup()
+ tg.run("test", "-run", "Test/Sub/Nested", "testdata/standalone_parallel_sub_test.go")
+ tg.grepBothNot(noMatchesPattern, "go test did say [no tests to run]")
+ tg.grepBoth(okPattern, "go test did not say ok")
+}
+
+func TestLinkXImportPathEscape(t *testing.T) {
+ // golang.org/issue/16710
+ tg := testgo(t)
+ defer tg.cleanup()
+ tg.parallel()
+ tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
+ exe := "./linkx" + exeSuffix
+ tg.creatingTemp(exe)
+ tg.run("build", "-o", exe, "-ldflags", "-X=my.pkg.Text=linkXworked", "my.pkg/main")
+ out, err := exec.Command(exe).CombinedOutput()
+ if err != nil {
+ tg.t.Fatal(err)
+ }
+ if string(out) != "linkXworked\n" {
+ tg.t.Log(string(out))
+ tg.t.Fatal(`incorrect output: expected "linkXworked\n"`)
+ }
+}
diff --git a/src/cmd/go/go_windows_test.go b/src/cmd/go/go_windows_test.go
index 53d695c..d8d04aa 100644
--- a/src/cmd/go/go_windows_test.go
+++ b/src/cmd/go/go_windows_test.go
@@ -5,6 +5,7 @@
package main
import (
+ "internal/testenv"
"io/ioutil"
"os"
"os/exec"
@@ -45,7 +46,7 @@ func TestAbsolutePath(t *testing.T) {
noVolume := file[len(filepath.VolumeName(file)):]
wrongPath := filepath.Join(dir, noVolume)
- output, err := exec.Command("go", "build", noVolume).CombinedOutput()
+ output, err := exec.Command(testenv.GoToolPath(t), "build", noVolume).CombinedOutput()
if err == nil {
t.Fatal("build should fail")
}
diff --git a/src/cmd/go/help.go b/src/cmd/go/help.go
index 056a0af..fb69d8e 100644
--- a/src/cmd/go/help.go
+++ b/src/cmd/go/help.go
@@ -42,7 +42,7 @@ denotes the package in that directory.
Otherwise, the import path P denotes the package found in
the directory DIR/src/P for some DIR listed in the GOPATH
-environment variable (see 'go help gopath').
+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.
@@ -62,6 +62,9 @@ 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
@@ -102,10 +105,10 @@ var helpImportPath = &Command{
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 (see 'go help gopath').
+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
@@ -197,6 +200,11 @@ 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
@@ -237,8 +245,8 @@ the go tool will verify that https://example.org/?go-get=1 contains the
same meta tag and then git clone https://code.org/r/p/exproj into
GOPATH/src/example.org.
-New downloaded packages are written to the first directory
-listed in the GOPATH environment variable (see 'go help gopath').
+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.
@@ -281,8 +289,11 @@ On Unix, the value is a colon-separated string.
On Windows, the value is a semicolon-separated string.
On Plan 9, the value is a list.
-GOPATH must be set to get, build and install packages outside the
-standard Go tree.
+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.
Each directory listed in GOPATH must have a prescribed structure:
@@ -310,9 +321,9 @@ of DIR/bin. GOBIN must be an absolute path.
Here's an example directory layout:
- GOPATH=/home/user/gocode
+ GOPATH=/home/user/go
- /home/user/gocode/
+ /home/user/go/
src/
foo/
bar/ (go code in package bar)
@@ -338,7 +349,7 @@ Code in or below a directory named "internal" is importable only
by code in the directory tree rooted at the parent of "internal".
Here's an extended version of the directory layout above:
- /home/user/gocode/
+ /home/user/go/
src/
crash/
bang/ (go code in package bang)
@@ -376,7 +387,7 @@ Here's the example from the previous section,
but with the "internal" directory renamed to "vendor"
and a new foo/vendor/crash/bang directory added:
- /home/user/gocode/
+ /home/user/go/
src/
crash/
bang/ (go code in package bang)
@@ -439,7 +450,7 @@ General-purpose environment variables:
The operating system for which to compile code.
Examples are linux, darwin, windows, netbsd.
GOPATH
- See 'go help gopath'.
+ For more details see: 'go help gopath'.
GORACE
Options for the race detector.
See https://golang.org/doc/articles/race_detector.html.
@@ -461,10 +472,15 @@ Environment variables for use with cgo:
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:
@@ -486,6 +502,10 @@ Special-purpose environment variables:
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'.
`,
}
@@ -577,5 +597,9 @@ are:
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
index 05ea503..1dc2c12 100644
--- a/src/cmd/go/http.go
+++ b/src/cmd/go/http.go
@@ -12,6 +12,7 @@
package main
import (
+ "cmd/internal/browser"
"crypto/tls"
"fmt"
"io"
@@ -113,3 +114,6 @@ func httpsOrHTTP(importPath string, security securityMode) (urlStr string, body
}
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/list.go b/src/cmd/go/list.go
index 48678e7..2f24083 100644
--- a/src/cmd/go/list.go
+++ b/src/cmd/go/list.go
@@ -59,6 +59,8 @@ syntax of package template. The default output is equivalent to -f
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
@@ -69,20 +71,23 @@ syntax of package template. The default output is equivalent to -f
CgoPkgConfig []string // cgo: pkg-config names
// Dependency information
- Imports []string // import paths used by this package
- Deps []string // all (recursively) imported dependencies
+ 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
-
- TestGoFiles []string // _test.go files in package
- TestImports []string // imports from TestGoFiles
- XTestGoFiles []string // _test.go files outside package
- XTestImports []string // imports from XTestGoFiles
}
+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 {
diff --git a/src/cmd/go/main.go b/src/cmd/go/main.go
index 65ec61b..07fc4e2 100644
--- a/src/cmd/go/main.go
+++ b/src/cmd/go/main.go
@@ -79,6 +79,7 @@ var commands = []*Command{
cmdClean,
cmdDoc,
cmdEnv,
+ cmdBug,
cmdFix,
cmdFmt,
cmdGenerate,
@@ -114,6 +115,7 @@ func setExitStatus(n int) {
}
var origEnv []string
+var newEnv []envVar
func main() {
_ = go11tag
@@ -134,7 +136,7 @@ func main() {
// 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 := os.Getenv("GOPATH"); gopath == runtime.GOROOT() {
+ if gopath := buildContext.GOPATH; gopath == runtime.GOROOT() {
fmt.Fprintf(os.Stderr, "warning: GOPATH set to GOROOT (%s) has no effect\n", gopath)
} else {
for _, p := range filepath.SplitList(gopath) {
@@ -146,7 +148,7 @@ func main() {
os.Exit(2)
}
if !filepath.IsAbs(p) {
- fmt.Fprintf(os.Stderr, "go: GOPATH entry is relative; must be absolute path: %q.\nRun 'go help gopath' for usage.\n", p)
+ fmt.Fprintf(os.Stderr, "go: GOPATH entry is relative; must be absolute path: %q.\nFor more details see: 'go help gopath'\n", p)
os.Exit(2)
}
}
@@ -163,7 +165,8 @@ func main() {
// but in practice there might be skew
// This makes sure we all agree.
origEnv = os.Environ()
- for _, env := range mkEnv() {
+ newEnv = mkEnv()
+ for _, env := range newEnv {
if os.Getenv(env.name) != env.value {
os.Setenv(env.name, env.value)
}
diff --git a/src/cmd/go/pkg.go b/src/cmd/go/pkg.go
index 07aa3ff..852a1a0 100644
--- a/src/cmd/go/pkg.go
+++ b/src/cmd/go/pkg.go
@@ -24,6 +24,8 @@ import (
"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.
@@ -181,6 +183,11 @@ func (p *Package) copyBuild(pp *build.Package) {
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
@@ -334,62 +341,98 @@ func loadImport(path, srcDir string, parent *Package, stk *importStack, importPo
importPath = path
}
- if p := packageCache[importPath]; p != nil {
- if perr := disallowInternal(srcDir, p, stk); perr != p {
- return perr
+ 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
}
- if mode&useVendor != 0 {
- if perr := disallowVendor(srcDir, origPath, p, stk); perr != p {
- return perr
- }
+ 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)
}
- return reusePackage(p, stk)
- }
-
- 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 == "" && len(importPos) > 0 {
- pos := importPos[0]
- pos.Filename = shortPath(pos.Filename)
- p.Error.Pos = pos.String()
+ 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 perr
+ return setErrorPos(perr, importPos)
}
if mode&useVendor != 0 {
if perr := disallowVendor(srcDir, origPath, p, stk); perr != p {
- return perr
+ 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 != ".." && path != "." && !strings.HasPrefix(path, "../") {
+ path = "./" + path
+ }
+ return path
+}
+
var isDirCache = map[string]bool{}
func isDir(path string) bool {
@@ -415,13 +458,26 @@ func vendoredImportPath(parent *Package, path string) (found string) {
dir := filepath.Clean(parent.Dir)
root := filepath.Join(parent.Root, "src")
- if !hasFilePathPrefix(dir, root) {
+ 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 {
- fatalf("invalid vendoredImportPath: dir=%q root=%q separator=%q", dir, root, string(filepath.Separator))
+
+ 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
@@ -519,6 +575,19 @@ func disallowInternal(srcDir string, p *Package, stk *importStack) *Package {
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
@@ -691,24 +760,23 @@ const (
// 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,
- "cmd/yacc": toTool,
+ "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,
@@ -776,7 +844,7 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package
useBindir := p.Name == "main"
if !p.Standard {
switch buildBuildmode {
- case "c-archive", "c-shared":
+ case "c-archive", "c-shared", "plugin":
useBindir = false
}
}
@@ -847,11 +915,25 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package
importPaths = append(importPaths, "syscall")
}
- // Currently build modes c-shared, pie, and -linkshared force
- // external linking mode, and external linking mode forces an
- // import of runtime/cgo.
- if p.Name == "main" && !p.Goroot && (buildBuildmode == "c-shared" || buildBuildmode == "pie" || buildLinkshared) {
- importPaths = append(importPaths, "runtime/cgo")
+ 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
@@ -933,33 +1015,21 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package
// 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 p1.Name == "main" {
- p.Error = &PackageError{
- ImportStack: stk.copy(),
- Err: fmt.Sprintf("import %q is a program, not an importable package", path),
- }
- pos := p.build.ImportPos[path]
- if len(pos) > 0 {
- p.Error.Pos = pos[0].String()
- }
- }
- if p1.local {
- if !p.local && p.Error == nil {
- p.Error = &PackageError{
- ImportStack: stk.copy(),
- Err: fmt.Sprintf("local import %q in non-local package", path),
- }
- pos := p.build.ImportPos[path]
- if len(pos) > 0 {
- p.Error.Pos = pos[0].String()
- }
- }
- }
if p.Standard && p.Error == nil && !p1.Standard && p1.Error == nil {
p.Error = &PackageError{
ImportStack: stk.copy(),
@@ -976,15 +1046,11 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package
if i < len(p.Imports) {
p.Imports[i] = path
}
- deps[path] = p1
+
+ save(path, p1)
imports = append(imports, p1)
for _, dep := range p1.deps {
- // The same import path could produce an error or not,
- // depending on what tries to import it.
- // Prefer to record entries with errors, so we can report them.
- if deps[dep.ImportPath] == nil || dep.Error != nil {
- deps[dep.ImportPath] = dep
- }
+ save(dep.ImportPath, dep)
}
if p1.Incomplete {
p.Incomplete = true
@@ -1570,7 +1636,7 @@ func computeBuildID(p *Package) {
// 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" {
+ 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)
diff --git a/src/cmd/go/test.go b/src/cmd/go/test.go
index e1527da..95914d5 100644
--- a/src/cmd/go/test.go
+++ b/src/cmd/go/test.go
@@ -13,6 +13,7 @@ import (
"go/doc"
"go/parser"
"go/token"
+ "io"
"os"
"os/exec"
"path"
@@ -135,28 +136,11 @@ const testFlag2 = `
By default, no benchmarks run. To run all benchmarks,
use '-bench .' or '-bench=.'.
- -benchmem
- Print memory allocation statistics for benchmarks.
-
-benchtime t
Run enough iterations of each benchmark to take t, specified
as a time.Duration (for example, -benchtime 1h30s).
The default is 1 second (1s).
- -blockprofile block.out
- Write a goroutine blocking profile to the specified file
- when all tests are complete.
- Writes test binary as -c would.
-
- -blockprofilerate n
- Control the detail provided in goroutine blocking profiles by
- calling runtime.SetBlockProfileRate with n.
- See 'go doc runtime.SetBlockProfileRate'.
- The profiler aims to sample, on average, one blocking event every
- n nanoseconds the program spends blocked. By default,
- if -test.blockprofile is set without this flag, all blocking events
- are recorded, equivalent to -test.blockprofilerate=1.
-
-count n
Run each test and benchmark n times (default 1).
If -cpu is set, run n times for each GOMAXPROCS value.
@@ -182,33 +166,11 @@ const testFlag2 = `
Packages are specified as import paths.
Sets -cover.
- -coverprofile cover.out
- Write a coverage profile to the file after all tests have passed.
- Sets -cover.
-
-cpu 1,2,4
Specify a list of GOMAXPROCS values for which the tests or
benchmarks should be executed. The default is the current value
of GOMAXPROCS.
- -cpuprofile cpu.out
- Write a CPU profile to the specified file before exiting.
- Writes test binary as -c would.
-
- -memprofile mem.out
- Write a memory profile to the file after all tests have passed.
- Writes test binary as -c would.
-
- -memprofilerate n
- Enable more precise (and expensive) memory profiles by setting
- runtime.MemProfileRate. See 'go doc runtime.MemProfileRate'.
- To profile all memory allocations, use -test.memprofilerate=1
- and pass --alloc_space flag to the pprof tool.
-
- -outputdir directory
- Place output files from profiling in the specified directory,
- by default the directory in which "go test" is running.
-
-parallel n
Allow parallel execution of test functions that call t.Parallel.
The value of this flag is the maximum number of tests to run
@@ -234,13 +196,64 @@ const testFlag2 = `
If a test runs longer than t, panic.
The default is 10 minutes (10m).
- -trace trace.out
- Write an execution trace to the specified file before exiting.
-
-v
Verbose output: log all tests as they are run. Also print all
text from Log and Logf calls even if the test succeeds.
+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.
@@ -381,9 +394,9 @@ var (
var testMainDeps = map[string]bool{
// Dependencies for testmain.
- "testing": true,
- "regexp": true,
- "os": true,
+ "testing": true,
+ "testing/internal/testdeps": true,
+ "os": true,
}
func runTest(cmd *Command, args []string) {
@@ -432,6 +445,11 @@ func runTest(cmd *Command, args []string) {
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()
@@ -849,7 +867,7 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action,
if err != nil {
return nil, nil, nil, err
}
- if len(ptest.GoFiles) > 0 {
+ if len(ptest.GoFiles)+len(ptest.CgoFiles) > 0 {
pmain.imports = append(pmain.imports, ptest)
t.ImportTest = true
}
@@ -1077,6 +1095,8 @@ func declareCoverVars(importPath string, files ...string) map[string]*CoverVar {
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)
@@ -1102,8 +1122,12 @@ func (b *builder) runTest(a *action) error {
cmd.Env = envForDir(cmd.Dir, origEnv)
var buf bytes.Buffer
if testStreamOutput {
- cmd.Stdout = os.Stdout
- cmd.Stderr = os.Stderr
+ // The only way to keep the ordering of the messages and still
+ // intercept its contents. os/exec will share the same Pipe for
+ // both Stdout and Stderr when running the test program.
+ mw := io.MultiWriter(os.Stdout, &buf)
+ cmd.Stdout = mw
+ cmd.Stderr = mw
} else {
cmd.Stdout = &buf
cmd.Stderr = &buf
@@ -1167,16 +1191,22 @@ func (b *builder) runTest(a *action) error {
out := buf.Bytes()
t := fmt.Sprintf("%.3fs", time.Since(t0).Seconds())
if err == nil {
- if testShowPass {
+ norun := ""
+ if testShowPass && !testStreamOutput {
a.testOutput.Write(out)
}
- fmt.Fprintf(a.testOutput, "ok \t%s\t%s%s\n", a.p.ImportPath, t, coveragePercentage(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)
+ if !testStreamOutput {
+ a.testOutput.Write(out)
+ }
// assume printing the test binary's exit status is superfluous
} else {
fmt.Fprintf(a.testOutput, "%s\n", err)
@@ -1394,7 +1424,7 @@ func (t *testFuncs) load(filename, pkg string, doImport, seen *bool) error {
}
}
ex := doc.Examples(f)
- sort.Sort(byOrder(ex))
+ 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 {
@@ -1416,12 +1446,6 @@ func checkTestFunc(fn *ast.FuncDecl, arg string) error {
return nil
}
-type byOrder []*doc.Example
-
-func (x byOrder) Len() int { return len(x) }
-func (x byOrder) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
-func (x byOrder) Less(i, j int) bool { return x[i].Order < x[j].Order }
-
var testmainTmpl = template.Must(template.New("main").Parse(`
package main
@@ -1429,8 +1453,8 @@ import (
{{if not .TestMain}}
"os"
{{end}}
- "regexp"
"testing"
+ "testing/internal/testdeps"
{{if .ImportTest}}
{{if .NeedTest}}_test{{else}}_{{end}} {{.Package.ImportPath | printf "%q"}}
@@ -1465,20 +1489,6 @@ var examples = []testing.InternalExample{
{{end}}
}
-var matchPat string
-var matchRe *regexp.Regexp
-
-func matchString(pat, str string) (result bool, err error) {
- if matchRe == nil || matchPat != pat {
- matchPat = pat
- matchRe, err = regexp.Compile(matchPat)
- if err != nil {
- return
- }
- }
- return matchRe.MatchString(str), nil
-}
-
{{if .CoverEnabled}}
// Only updated by init functions, so no need for atomicity.
@@ -1527,7 +1537,7 @@ func main() {
CoveredPackages: {{printf "%q" .Covered}},
})
{{end}}
- m := testing.MainStart(matchString, tests, benchmarks, examples)
+ m := testing.MainStart(testdeps.TestDeps{}, tests, benchmarks, examples)
{{with .TestMain}}
{{.Package}}.{{.Name}}(m)
{{else}}
diff --git a/src/cmd/go/testdata/src/canonical/a/a.go b/src/cmd/go/testdata/src/canonical/a/a.go
new file mode 100644
index 0000000..486cc48
--- /dev/null
+++ b/src/cmd/go/testdata/src/canonical/a/a.go
@@ -0,0 +1,3 @@
+package a
+
+import _ "c"
diff --git a/src/cmd/go/testdata/src/canonical/a/vendor/c/c.go b/src/cmd/go/testdata/src/canonical/a/vendor/c/c.go
new file mode 100644
index 0000000..7f96c22
--- /dev/null
+++ b/src/cmd/go/testdata/src/canonical/a/vendor/c/c.go
@@ -0,0 +1 @@
+package c
diff --git a/src/cmd/go/testdata/src/canonical/b/b.go b/src/cmd/go/testdata/src/canonical/b/b.go
new file mode 100644
index 0000000..ce0f4ce
--- /dev/null
+++ b/src/cmd/go/testdata/src/canonical/b/b.go
@@ -0,0 +1,3 @@
+package b
+
+import _ "canonical/a/"
diff --git a/src/cmd/go/testdata/src/canonical/d/d.go b/src/cmd/go/testdata/src/canonical/d/d.go
new file mode 100644
index 0000000..ef7dd7d
--- /dev/null
+++ b/src/cmd/go/testdata/src/canonical/d/d.go
@@ -0,0 +1,3 @@
+package d
+
+import _ "canonical/b"
diff --git a/src/cmd/go/testdata/cgocover/p.go b/src/cmd/go/testdata/src/cgocover/p.go
similarity index 100%
copy from src/cmd/go/testdata/cgocover/p.go
copy to src/cmd/go/testdata/src/cgocover/p.go
diff --git a/src/cmd/go/testdata/cgocover/p_test.go b/src/cmd/go/testdata/src/cgocover/p_test.go
similarity index 100%
rename from src/cmd/go/testdata/cgocover/p_test.go
rename to src/cmd/go/testdata/src/cgocover/p_test.go
diff --git a/src/cmd/go/testdata/cgocover/p.go b/src/cmd/go/testdata/src/cgocover2/p.go
similarity index 100%
copy from src/cmd/go/testdata/cgocover/p.go
copy to src/cmd/go/testdata/src/cgocover2/p.go
diff --git a/src/cmd/go/testdata/src/cgocover2/x_test.go b/src/cmd/go/testdata/src/cgocover2/x_test.go
new file mode 100644
index 0000000..f4790d2
--- /dev/null
+++ b/src/cmd/go/testdata/src/cgocover2/x_test.go
@@ -0,0 +1,10 @@
+package p_test
+
+import (
+ . "cgocover2"
+ "testing"
+)
+
+func TestF(t *testing.T) {
+ F()
+}
diff --git a/src/cmd/go/testdata/cgocover/p.go b/src/cmd/go/testdata/src/cgocover3/p.go
similarity index 100%
copy from src/cmd/go/testdata/cgocover/p.go
copy to src/cmd/go/testdata/src/cgocover3/p.go
diff --git a/src/cmd/go/testdata/src/cgocover3/p_test.go b/src/cmd/go/testdata/src/cgocover3/p_test.go
new file mode 100644
index 0000000..c89cd18
--- /dev/null
+++ b/src/cmd/go/testdata/src/cgocover3/p_test.go
@@ -0,0 +1 @@
+package p
diff --git a/src/cmd/go/testdata/src/cgocover3/x_test.go b/src/cmd/go/testdata/src/cgocover3/x_test.go
new file mode 100644
index 0000000..97d0e0f
--- /dev/null
+++ b/src/cmd/go/testdata/src/cgocover3/x_test.go
@@ -0,0 +1,10 @@
+package p_test
+
+import (
+ . "cgocover3"
+ "testing"
+)
+
+func TestF(t *testing.T) {
+ F()
+}
diff --git a/src/cmd/go/testdata/src/cgocover4/notcgo.go b/src/cmd/go/testdata/src/cgocover4/notcgo.go
new file mode 100644
index 0000000..c89cd18
--- /dev/null
+++ b/src/cmd/go/testdata/src/cgocover4/notcgo.go
@@ -0,0 +1 @@
+package p
diff --git a/src/cmd/go/testdata/cgocover/p.go b/src/cmd/go/testdata/src/cgocover4/p.go
similarity index 100%
rename from src/cmd/go/testdata/cgocover/p.go
rename to src/cmd/go/testdata/src/cgocover4/p.go
diff --git a/src/cmd/go/testdata/src/cgocover4/x_test.go b/src/cmd/go/testdata/src/cgocover4/x_test.go
new file mode 100644
index 0000000..fd9bae7
--- /dev/null
+++ b/src/cmd/go/testdata/src/cgocover4/x_test.go
@@ -0,0 +1,10 @@
+package p_test
+
+import (
+ . "cgocover4"
+ "testing"
+)
+
+func TestF(t *testing.T) {
+ F()
+}
diff --git a/src/cmd/go/testdata/src/dupload/dupload.go b/src/cmd/go/testdata/src/dupload/dupload.go
new file mode 100644
index 0000000..2f07852
--- /dev/null
+++ b/src/cmd/go/testdata/src/dupload/dupload.go
@@ -0,0 +1,8 @@
+package main
+
+import (
+ _ "dupload/p2"
+ _ "p"
+)
+
+func main() {}
diff --git a/src/cmd/go/testdata/src/dupload/p/p.go b/src/cmd/go/testdata/src/dupload/p/p.go
new file mode 100644
index 0000000..c89cd18
--- /dev/null
+++ b/src/cmd/go/testdata/src/dupload/p/p.go
@@ -0,0 +1 @@
+package p
diff --git a/src/cmd/go/testdata/src/dupload/p2/p2.go b/src/cmd/go/testdata/src/dupload/p2/p2.go
new file mode 100644
index 0000000..40f5a5b
--- /dev/null
+++ b/src/cmd/go/testdata/src/dupload/p2/p2.go
@@ -0,0 +1,2 @@
+package p2
+import _ "dupload/vendor/p"
diff --git a/src/cmd/go/testdata/src/dupload/vendor/p/p.go b/src/cmd/go/testdata/src/dupload/vendor/p/p.go
new file mode 100644
index 0000000..c89cd18
--- /dev/null
+++ b/src/cmd/go/testdata/src/dupload/vendor/p/p.go
@@ -0,0 +1 @@
+package p
diff --git a/src/cmd/go/testdata/src/gencycle/gencycle.go b/src/cmd/go/testdata/src/gencycle/gencycle.go
new file mode 100644
index 0000000..600afd9
--- /dev/null
+++ b/src/cmd/go/testdata/src/gencycle/gencycle.go
@@ -0,0 +1,5 @@
+//go:generate echo hello world
+
+package gencycle
+
+import _ "gencycle"
diff --git a/src/cmd/go/testdata/src/importmain/ismain/main.go b/src/cmd/go/testdata/src/importmain/ismain/main.go
new file mode 100644
index 0000000..bf01907
--- /dev/null
+++ b/src/cmd/go/testdata/src/importmain/ismain/main.go
@@ -0,0 +1,5 @@
+package main
+
+import _ "importmain/test"
+
+func main() {}
diff --git a/src/cmd/go/testdata/src/importmain/test/test.go b/src/cmd/go/testdata/src/importmain/test/test.go
new file mode 100644
index 0000000..56e5404
--- /dev/null
+++ b/src/cmd/go/testdata/src/importmain/test/test.go
@@ -0,0 +1 @@
+package test
diff --git a/src/cmd/go/testdata/src/importmain/test/test_test.go b/src/cmd/go/testdata/src/importmain/test/test_test.go
new file mode 100644
index 0000000..2268a82
--- /dev/null
+++ b/src/cmd/go/testdata/src/importmain/test/test_test.go
@@ -0,0 +1,6 @@
+package test_test
+
+import "testing"
+import _ "importmain/ismain"
+
+func TestCase(t *testing.T) {}
diff --git a/src/cmd/go/testdata/src/my.pkg/main/main.go b/src/cmd/go/testdata/src/my.pkg/main/main.go
new file mode 100644
index 0000000..397e8b6
--- /dev/null
+++ b/src/cmd/go/testdata/src/my.pkg/main/main.go
@@ -0,0 +1,5 @@
+package main
+import "my.pkg"
+func main() {
+ println(pkg.Text)
+}
diff --git a/src/cmd/go/testdata/src/my.pkg/pkg.go b/src/cmd/go/testdata/src/my.pkg/pkg.go
new file mode 100644
index 0000000..17702a6
--- /dev/null
+++ b/src/cmd/go/testdata/src/my.pkg/pkg.go
@@ -0,0 +1,3 @@
+package pkg
+
+var Text = "unset"
diff --git a/src/cmd/go/testdata/src/testrace/race_test.go b/src/cmd/go/testdata/src/testrace/race_test.go
new file mode 100644
index 0000000..264dcf0
--- /dev/null
+++ b/src/cmd/go/testdata/src/testrace/race_test.go
@@ -0,0 +1,29 @@
+package testrace
+
+import "testing"
+
+func TestRace(t *testing.T) {
+ for i := 0; i < 10; i++ {
+ c := make(chan int)
+ x := 1
+ go func() {
+ x = 2
+ c <- 1
+ }()
+ x = 3
+ <-c
+ }
+}
+
+func BenchmarkRace(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ c := make(chan int)
+ x := 1
+ go func() {
+ x = 2
+ c <- 1
+ }()
+ x = 3
+ <-c
+ }
+}
diff --git a/src/cmd/go/testdata/standalone_benchmark_test.go b/src/cmd/go/testdata/standalone_benchmark_test.go
new file mode 100644
index 0000000..4850f98
--- /dev/null
+++ b/src/cmd/go/testdata/standalone_benchmark_test.go
@@ -0,0 +1,6 @@
+package standalone_benchmark
+
+import "testing"
+
+func Benchmark(b *testing.B) {
+}
diff --git a/src/cmd/go/testdata/standalone_fail_sub_test.go b/src/cmd/go/testdata/standalone_fail_sub_test.go
new file mode 100644
index 0000000..ac483f9
--- /dev/null
+++ b/src/cmd/go/testdata/standalone_fail_sub_test.go
@@ -0,0 +1,8 @@
+package standalone_fail_sub_test
+
+import "testing"
+
+func TestThatFails(t *testing.T) {
+ t.Run("Sub", func(t *testing.T) {})
+ t.Fail()
+}
diff --git a/src/cmd/go/testdata/standalone_parallel_sub_test.go b/src/cmd/go/testdata/standalone_parallel_sub_test.go
new file mode 100644
index 0000000..d326de0
--- /dev/null
+++ b/src/cmd/go/testdata/standalone_parallel_sub_test.go
@@ -0,0 +1,14 @@
+package standalone_parallel_sub_test
+
+import "testing"
+
+func Test(t *testing.T) {
+ ch := make(chan bool, 1)
+ t.Run("Sub", func(t *testing.T) {
+ t.Parallel()
+ <-ch
+ t.Run("Nested", func(t *testing.T) {})
+ })
+ // Ensures that Sub will finish after its t.Run call already returned.
+ ch <- true
+}
diff --git a/src/cmd/go/testdata/standalone_sub_test.go b/src/cmd/go/testdata/standalone_sub_test.go
new file mode 100644
index 0000000..f6c31db
--- /dev/null
+++ b/src/cmd/go/testdata/standalone_sub_test.go
@@ -0,0 +1,7 @@
+package standalone_sub_test
+
+import "testing"
+
+func Test(t *testing.T) {
+ t.Run("Sub", func(t *testing.T) {})
+}
diff --git a/src/cmd/go/testflag.go b/src/cmd/go/testflag.go
index a65ed1f..cf4d2b4 100644
--- a/src/cmd/go/testflag.go
+++ b/src/cmd/go/testflag.go
@@ -50,6 +50,8 @@ var testFlagDefn = []*testFlagSpec{
{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},
@@ -152,7 +154,7 @@ func testFlags(args []string) (packageNames, passToTest []string) {
case "blockprofile", "cpuprofile", "memprofile":
testProfile = true
testNeedBinary = true
- case "trace":
+ case "mutexprofile", "trace":
testProfile = true
case "coverpkg":
testCover = true
diff --git a/src/cmd/go/tool.go b/src/cmd/go/tool.go
index b829037..38110cf 100644
--- a/src/cmd/go/tool.go
+++ b/src/cmd/go/tool.go
@@ -60,7 +60,7 @@ func tool(toolName string) string {
} else {
fmt.Fprintf(os.Stderr, "go tool: no such tool %q\n", toolName)
}
- setExitStatus(3)
+ setExitStatus(2)
exit()
}
return toolPath
diff --git a/src/cmd/go/vcs.go b/src/cmd/go/vcs.go
index 53ddbe6..fcdce22 100644
--- a/src/cmd/go/vcs.go
+++ b/src/cmd/go/vcs.go
@@ -41,7 +41,7 @@ type vcsCmd struct {
resolveRepo func(v *vcsCmd, rootDir, remoteRepo string) (realRepo string, err error)
}
-var isSecureScheme = map[string]bool{
+var defaultSecureScheme = map[string]bool{
"https": true,
"git+ssh": true,
"bzr+ssh": true,
@@ -55,7 +55,25 @@ func (v *vcsCmd) isSecure(repo string) bool {
// If repo is not a URL, it's not secure.
return false
}
- return isSecureScheme[u.Scheme]
+ 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
@@ -482,7 +500,7 @@ func vcsFromDir(dir, srcRoot string) (vcs *vcsCmd, root string, err error) {
origDir := dir
for len(dir) > len(srcRoot) {
for _, vcs := range vcsList {
- if fi, err := os.Stat(filepath.Join(dir, "."+vcs.cmd)); err == nil && fi.IsDir() {
+ if _, err := os.Stat(filepath.Join(dir, "."+vcs.cmd)); err == nil {
return vcs, filepath.ToSlash(dir[len(srcRoot)+1:]), nil
}
}
@@ -510,6 +528,9 @@ type repoRoot struct {
// 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?:`)
@@ -612,7 +633,7 @@ func repoRootFromVCSPaths(importPath, scheme string, security securityMode, vcsP
match["repo"] = scheme + "://" + match["repo"]
} else {
for _, scheme := range vcs.scheme {
- if security == secure && !isSecureScheme[scheme] {
+ if security == secure && !vcs.isSecureScheme(scheme) {
continue
}
if vcs.ping(scheme, match["repo"]) == nil {
@@ -661,10 +682,10 @@ func repoRootForImportDynamic(importPath string, security securityMode) (*repoRo
// Find the matched meta import.
mmi, err := matchGoImport(imports, importPath)
if err != nil {
- if err != errNoMatch {
+ 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", urlStr)
+ 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)
@@ -695,9 +716,10 @@ func repoRootForImportDynamic(importPath string, security securityMode) (*repoRo
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,
+ 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)
@@ -764,9 +786,6 @@ type metaImport struct {
Prefix, VCS, RepoRoot string
}
-// errNoMatch is returned from matchGoImport when there's no applicable match.
-var errNoMatch = errors.New("no import match")
-
func splitPathHasPrefix(path, prefix []string) bool {
if len(path) < len(prefix) {
return false
@@ -779,28 +798,45 @@ func splitPathHasPrefix(path, prefix []string) bool {
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, err error) {
+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 {
- err = fmt.Errorf("multiple meta tags match import path %q", importPath)
- return
+ return metaImport{}, fmt.Errorf("multiple meta tags match import path %q", importPath)
}
match = i
}
+
if match == -1 {
- err = errNoMatch
- return
+ return metaImport{}, errImportMismatch
}
return imports[match], nil
}
diff --git a/src/cmd/go/vcs_test.go b/src/cmd/go/vcs_test.go
index 25e3866..c73f5d0 100644
--- a/src/cmd/go/vcs_test.go
+++ b/src/cmd/go/vcs_test.go
@@ -102,7 +102,7 @@ func TestRepoRootForImportPath(t *testing.T) {
"git.openstack.org/openstack/swift.git",
&repoRoot{
vcs: vcsGit,
- repo: "https://git.openstack.org/openstack/swift",
+ repo: "https://git.openstack.org/openstack/swift.git",
},
},
{
@@ -174,11 +174,23 @@ func TestFromDir(t *testing.T) {
}
defer os.RemoveAll(tempDir)
- for _, vcs := range vcsList {
+ for j, vcs := range vcsList {
dir := filepath.Join(tempDir, "example.com", vcs.name, "."+vcs.cmd)
- err := os.MkdirAll(dir, 0755)
- if err != nil {
- t.Fatal(err)
+ 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{
@@ -229,6 +241,46 @@ func TestIsSecure(t *testing.T) {
}
}
+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
@@ -306,6 +358,13 @@ func TestMatchGoImport(t *testing.T) {
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 {
diff --git a/src/cmd/gofmt/doc.go b/src/cmd/gofmt/doc.go
index 9d0cd32..8b22f03 100644
--- a/src/cmd/gofmt/doc.go
+++ b/src/cmd/gofmt/doc.go
@@ -32,7 +32,8 @@ The flags are:
-w
Do not print reformatted sources to standard output.
If a file's formatting is different from gofmt's, overwrite it
- with gofmt's version.
+ with gofmt's version. If an error occurred during overwriting,
+ the original file is restored from an automatic backup.
Debugging support:
-cpuprofile filename
@@ -98,3 +99,5 @@ This may result in changes that are incompatible with earlier versions of Go.
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.
diff --git a/src/cmd/gofmt/gofmt.go b/src/cmd/gofmt/gofmt.go
index f29b6cb..e1ef0dd 100644
--- a/src/cmd/gofmt/gofmt.go
+++ b/src/cmd/gofmt/gofmt.go
@@ -18,6 +18,7 @@ import (
"os"
"os/exec"
"path/filepath"
+ "runtime"
"runtime/pprof"
"strings"
)
@@ -72,13 +73,19 @@ func isGoFile(f os.FileInfo) bool {
// If in == nil, the source is the contents of the file with the given filename.
func processFile(filename string, in io.Reader, out io.Writer, stdin bool) error {
+ var perm os.FileMode = 0644
if in == nil {
f, err := os.Open(filename)
if err != nil {
return err
}
defer f.Close()
+ fi, err := f.Stat()
+ if err != nil {
+ return err
+ }
in = f
+ perm = fi.Mode().Perm()
}
src, err := ioutil.ReadAll(in)
@@ -116,7 +123,17 @@ func processFile(filename string, in io.Reader, out io.Writer, stdin bool) error
fmt.Fprintln(out, filename)
}
if *write {
- err = ioutil.WriteFile(filename, res, 0644)
+ // make a temporary backup before overwriting original
+ bakname, err := backupFile(filename+".", src, perm)
+ if err != nil {
+ return err
+ }
+ err = ioutil.WriteFile(filename, res, perm)
+ if err != nil {
+ os.Rename(bakname, filename)
+ return err
+ }
+ err = os.Remove(bakname)
if err != nil {
return err
}
@@ -235,3 +252,36 @@ func diff(b1, b2 []byte) (data []byte, err error) {
return
}
+
+const chmodSupported = runtime.GOOS != "windows"
+
+// backupFile writes data to a new file named filename<number> with permissions perm,
+// with <number randomly chosen such that the file name is unique. backupFile returns
+// the chosen file name.
+func backupFile(filename string, data []byte, perm os.FileMode) (string, error) {
+ // create backup file
+ f, err := ioutil.TempFile(filepath.Dir(filename), filepath.Base(filename))
+ if err != nil {
+ return "", err
+ }
+ bakname := f.Name()
+ if chmodSupported {
+ err = f.Chmod(perm)
+ if err != nil {
+ f.Close()
+ os.Remove(bakname)
+ return bakname, err
+ }
+ }
+
+ // write data to backup file
+ n, err := f.Write(data)
+ if err == nil && n < len(data) {
+ err = io.ErrShortWrite
+ }
+ if err1 := f.Close(); err == nil {
+ err = err1
+ }
+
+ return bakname, err
+}
diff --git a/src/cmd/gofmt/gofmt_test.go b/src/cmd/gofmt/gofmt_test.go
index dea0127..b7ca9e8 100644
--- a/src/cmd/gofmt/gofmt_test.go
+++ b/src/cmd/gofmt/gofmt_test.go
@@ -171,3 +171,16 @@ func TestCRLF(t *testing.T) {
t.Errorf("%s contains CR's", golden)
}
}
+
+func TestBackupFile(t *testing.T) {
+ dir, err := ioutil.TempDir("", "gofmt_test")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer os.RemoveAll(dir)
+ name, err := backupFile(filepath.Join(dir, "foo.go"), []byte(" package main"), 0644)
+ if err != nil {
+ t.Fatal(err)
+ }
+ t.Logf("Created: %s", name)
+}
diff --git a/src/cmd/gofmt/simplify.go b/src/cmd/gofmt/simplify.go
index 2ebf4cd..1a0e817 100644
--- a/src/cmd/gofmt/simplify.go
+++ b/src/cmd/gofmt/simplify.go
@@ -17,47 +17,33 @@ func (s simplifier) Visit(node ast.Node) ast.Visitor {
case *ast.CompositeLit:
// array, slice, and map composite literals may be simplified
outer := n
- var eltType ast.Expr
+ var keyType, eltType ast.Expr
switch typ := outer.Type.(type) {
case *ast.ArrayType:
eltType = typ.Elt
case *ast.MapType:
+ keyType = typ.Key
eltType = typ.Value
}
if eltType != nil {
+ var ktyp reflect.Value
+ if keyType != nil {
+ ktyp = reflect.ValueOf(keyType)
+ }
typ := reflect.ValueOf(eltType)
for i, x := range outer.Elts {
px := &outer.Elts[i]
// look at value of indexed/named elements
if t, ok := x.(*ast.KeyValueExpr); ok {
+ if keyType != nil {
+ s.simplifyLiteral(ktyp, keyType, t.Key, &t.Key)
+ }
x = t.Value
px = &t.Value
}
- ast.Walk(s, x) // simplify x
- // if the element is a composite literal and its literal type
- // matches the outer literal's element type exactly, the inner
- // literal type may be omitted
- if inner, ok := x.(*ast.CompositeLit); ok {
- if match(nil, typ, reflect.ValueOf(inner.Type)) {
- inner.Type = nil
- }
- }
- // if the outer literal's element type is a pointer type *T
- // and the element is & of a composite literal of type T,
- // the inner &T may be omitted.
- if ptr, ok := eltType.(*ast.StarExpr); ok {
- if addr, ok := x.(*ast.UnaryExpr); ok && addr.Op == token.AND {
- if inner, ok := addr.X.(*ast.CompositeLit); ok {
- if match(nil, reflect.ValueOf(ptr.X), reflect.ValueOf(inner.Type)) {
- inner.Type = nil // drop T
- *px = inner // drop &
- }
- }
- }
- }
+ s.simplifyLiteral(typ, eltType, x, px)
}
-
// node was simplified - stop walk (there are no subnodes to simplify)
return nil
}
@@ -113,6 +99,32 @@ func (s simplifier) Visit(node ast.Node) ast.Visitor {
return s
}
+func (s simplifier) simplifyLiteral(typ reflect.Value, astType, x ast.Expr, px *ast.Expr) {
+ ast.Walk(s, x) // simplify x
+
+ // if the element is a composite literal and its literal type
+ // matches the outer literal's element type exactly, the inner
+ // literal type may be omitted
+ if inner, ok := x.(*ast.CompositeLit); ok {
+ if match(nil, typ, reflect.ValueOf(inner.Type)) {
+ inner.Type = nil
+ }
+ }
+ // if the outer literal's element type is a pointer type *T
+ // and the element is & of a composite literal of type T,
+ // the inner &T may be omitted.
+ if ptr, ok := astType.(*ast.StarExpr); ok {
+ if addr, ok := x.(*ast.UnaryExpr); ok && addr.Op == token.AND {
+ if inner, ok := addr.X.(*ast.CompositeLit); ok {
+ if match(nil, reflect.ValueOf(ptr.X), reflect.ValueOf(inner.Type)) {
+ inner.Type = nil // drop T
+ *px = inner // drop &
+ }
+ }
+ }
+ }
+}
+
func isBlank(x ast.Expr) bool {
ident, ok := x.(*ast.Ident)
return ok && ident.Name == "_"
diff --git a/src/cmd/gofmt/testdata/composites.golden b/src/cmd/gofmt/testdata/composites.golden
index fc9c98e..a06a69d 100644
--- a/src/cmd/gofmt/testdata/composites.golden
+++ b/src/cmd/gofmt/testdata/composites.golden
@@ -6,6 +6,10 @@ type T struct {
x, y int
}
+type T2 struct {
+ w, z int
+}
+
var _ = [42]T{
{},
{1, 2},
@@ -202,3 +206,13 @@ var pieces4 = []*Piece{
{2, 0, Point{4, 1}, []Point{{0, 0}, {1, 0}, {1, 0}, {1, 0}}, nil, nil},
{3, 0, Point{1, 4}, []Point{{0, 0}, {0, 1}, {0, 1}, {0, 1}}, nil, nil},
}
+
+var _ = map[T]T2{
+ {1, 2}: {3, 4},
+ {5, 6}: {7, 8},
+}
+
+var _ = map[*T]*T2{
+ {1, 2}: {3, 4},
+ {5, 6}: {7, 8},
+}
diff --git a/src/cmd/gofmt/testdata/composites.input b/src/cmd/gofmt/testdata/composites.input
index fc7598a..9d28ac7 100644
--- a/src/cmd/gofmt/testdata/composites.input
+++ b/src/cmd/gofmt/testdata/composites.input
@@ -6,6 +6,10 @@ type T struct {
x, y int
}
+type T2 struct {
+ w, z int
+}
+
var _ = [42]T{
T{},
T{1, 2},
@@ -202,3 +206,13 @@ var pieces4 = []*Piece{
&Piece{2, 0, Point{4, 1}, []Point{Point{0, 0}, Point{1, 0}, Point{1, 0}, Point{1, 0}}, nil, nil},
&Piece{3, 0, Point{1, 4}, []Point{Point{0, 0}, Point{0, 1}, Point{0, 1}, Point{0, 1}}, nil, nil},
}
+
+var _ = map[T]T2{
+ T{1, 2}: T2{3, 4},
+ T{5, 6}: T2{7, 8},
+}
+
+var _ = map[*T]*T2{
+ &T{1, 2}: &T2{3, 4},
+ &T{5, 6}: &T2{7, 8},
+}
diff --git a/src/cmd/internal/browser/browser.go b/src/cmd/internal/browser/browser.go
new file mode 100644
index 0000000..897086f
--- /dev/null
+++ b/src/cmd/internal/browser/browser.go
@@ -0,0 +1,46 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package browser provides utilities for interacting with users' browsers.
+package browser
+
+import (
+ "os"
+ "os/exec"
+ "runtime"
+)
+
+// Commands returns a list of possible commands to use to open a url.
+func Commands() [][]string {
+ var cmds [][]string
+ if exe := os.Getenv("BROWSER"); exe != "" {
+ cmds = append(cmds, []string{exe})
+ }
+ switch runtime.GOOS {
+ case "darwin":
+ cmds = append(cmds, []string{"/usr/bin/open"})
+ case "windows":
+ cmds = append(cmds, []string{"cmd", "/c", "start"})
+ default:
+ cmds = append(cmds, []string{"xdg-open"})
+ }
+ cmds = append(cmds,
+ []string{"chrome"},
+ []string{"google-chrome"},
+ []string{"chromium"},
+ []string{"firefox"},
+ )
+ return cmds
+}
+
+// Open tries to open url in a browser and reports whether it succeeded.
+func Open(url string) bool {
+ for _, args := range Commands() {
+ cmd := exec.Command(args[0], append(args[1:], url)...)
+ if cmd.Start() == nil {
+ return true
+ }
+ }
+ return false
+}
diff --git a/src/cmd/internal/dwarf/dwarf.go b/src/cmd/internal/dwarf/dwarf.go
new file mode 100644
index 0000000..725f502
--- /dev/null
+++ b/src/cmd/internal/dwarf/dwarf.go
@@ -0,0 +1,604 @@
+// Copyright 2016 The Go Authors. 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 generates DWARF debugging information.
+// DWARF generation is split between the compiler and the linker,
+// this package contains the shared code.
+package dwarf
+
+import (
+ "fmt"
+ "strings"
+)
+
+// InfoPrefix is the prefix for all the symbols containing DWARF info entries.
+const InfoPrefix = "go.info."
+
+// Sym represents a symbol.
+type Sym interface {
+}
+
+// A Var represents a local variable or a function parameter.
+type Var struct {
+ Name string
+ Abbrev int // Either DW_ABRV_AUTO or DW_ABRV_PARAM
+ Offset int32
+ Type Sym
+ Link *Var
+}
+
+// A Context specifies how to add data to a Sym.
+type Context interface {
+ PtrSize() int
+ AddInt(s Sym, size int, i int64)
+ AddBytes(s Sym, b []byte)
+ AddAddress(s Sym, t interface{}, ofs int64)
+ AddSectionOffset(s Sym, size int, t interface{}, ofs int64)
+ AddString(s Sym, v string)
+ SymValue(s Sym) int64
+}
+
+// AppendUleb128 appends v to b using DWARF's unsigned LEB128 encoding.
+func AppendUleb128(b []byte, v uint64) []byte {
+ for {
+ c := uint8(v & 0x7f)
+ v >>= 7
+ if v != 0 {
+ c |= 0x80
+ }
+ b = append(b, c)
+ if c&0x80 == 0 {
+ break
+ }
+ }
+ return b
+}
+
+// AppendSleb128 appends v to b using DWARF's signed LEB128 encoding.
+func AppendSleb128(b []byte, v int64) []byte {
+ for {
+ c := uint8(v & 0x7f)
+ s := uint8(v & 0x40)
+ v >>= 7
+ if (v != -1 || s == 0) && (v != 0 || s != 0) {
+ c |= 0x80
+ }
+ b = append(b, c)
+ if c&0x80 == 0 {
+ break
+ }
+ }
+ return b
+}
+
+var encbuf [20]byte
+
+// AppendUleb128 appends v to s using DWARF's unsigned LEB128 encoding.
+func Uleb128put(ctxt Context, s Sym, v int64) {
+ b := AppendUleb128(encbuf[:0], uint64(v))
+ ctxt.AddBytes(s, b)
+}
+
+// AppendUleb128 appends v to s using DWARF's signed LEB128 encoding.
+func Sleb128put(ctxt Context, s Sym, v int64) {
+ b := AppendSleb128(encbuf[:0], v)
+ ctxt.AddBytes(s, b)
+}
+
+/*
+ * Defining Abbrevs. This is hardcoded, and there will be
+ * only a handful of them. The DWARF spec places no restriction on
+ * the ordering of attributes in the Abbrevs and DIEs, and we will
+ * always write them out in the order of declaration in the abbrev.
+ */
+type dwAttrForm struct {
+ attr uint16
+ form uint8
+}
+
+// Go-specific type attributes.
+const (
+ DW_AT_go_kind = 0x2900
+ DW_AT_go_key = 0x2901
+ DW_AT_go_elem = 0x2902
+
+ DW_AT_internal_location = 253 // params and locals; not emitted
+)
+
+// Index into the abbrevs table below.
+// Keep in sync with ispubname() and ispubtype() below.
+// ispubtype considers >= NULLTYPE public
+const (
+ DW_ABRV_NULL = iota
+ DW_ABRV_COMPUNIT
+ DW_ABRV_FUNCTION
+ DW_ABRV_VARIABLE
+ DW_ABRV_AUTO
+ DW_ABRV_PARAM
+ DW_ABRV_STRUCTFIELD
+ DW_ABRV_FUNCTYPEPARAM
+ DW_ABRV_DOTDOTDOT
+ DW_ABRV_ARRAYRANGE
+ DW_ABRV_NULLTYPE
+ DW_ABRV_BASETYPE
+ DW_ABRV_ARRAYTYPE
+ DW_ABRV_CHANTYPE
+ DW_ABRV_FUNCTYPE
+ DW_ABRV_IFACETYPE
+ DW_ABRV_MAPTYPE
+ DW_ABRV_PTRTYPE
+ DW_ABRV_BARE_PTRTYPE // only for void*, no DW_AT_type attr to please gdb 6.
+ DW_ABRV_SLICETYPE
+ DW_ABRV_STRINGTYPE
+ DW_ABRV_STRUCTTYPE
+ DW_ABRV_TYPEDECL
+ DW_NABRV
+)
+
+type dwAbbrev struct {
+ tag uint8
+ children uint8
+ attr []dwAttrForm
+}
+
+var abbrevs = [DW_NABRV]dwAbbrev{
+ /* The mandatory DW_ABRV_NULL entry. */
+ {0, 0, []dwAttrForm{}},
+
+ /* COMPUNIT */
+ {
+ DW_TAG_compile_unit,
+ DW_CHILDREN_yes,
+ []dwAttrForm{
+ {DW_AT_name, DW_FORM_string},
+ {DW_AT_language, DW_FORM_data1},
+ {DW_AT_low_pc, DW_FORM_addr},
+ {DW_AT_high_pc, DW_FORM_addr},
+ {DW_AT_stmt_list, DW_FORM_data4},
+ {DW_AT_comp_dir, DW_FORM_string},
+ },
+ },
+
+ /* FUNCTION */
+ {
+ DW_TAG_subprogram,
+ DW_CHILDREN_yes,
+ []dwAttrForm{
+ {DW_AT_name, DW_FORM_string},
+ {DW_AT_low_pc, DW_FORM_addr},
+ {DW_AT_high_pc, DW_FORM_addr},
+ {DW_AT_external, DW_FORM_flag},
+ },
+ },
+
+ /* VARIABLE */
+ {
+ DW_TAG_variable,
+ DW_CHILDREN_no,
+ []dwAttrForm{
+ {DW_AT_name, DW_FORM_string},
+ {DW_AT_location, DW_FORM_block1},
+ {DW_AT_type, DW_FORM_ref_addr},
+ {DW_AT_external, DW_FORM_flag},
+ },
+ },
+
+ /* AUTO */
+ {
+ DW_TAG_variable,
+ DW_CHILDREN_no,
+ []dwAttrForm{
+ {DW_AT_name, DW_FORM_string},
+ {DW_AT_location, DW_FORM_block1},
+ {DW_AT_type, DW_FORM_ref_addr},
+ },
+ },
+
+ /* PARAM */
+ {
+ DW_TAG_formal_parameter,
+ DW_CHILDREN_no,
+ []dwAttrForm{
+ {DW_AT_name, DW_FORM_string},
+ {DW_AT_location, DW_FORM_block1},
+ {DW_AT_type, DW_FORM_ref_addr},
+ },
+ },
+
+ /* STRUCTFIELD */
+ {
+ DW_TAG_member,
+ DW_CHILDREN_no,
+ []dwAttrForm{
+ {DW_AT_name, DW_FORM_string},
+ {DW_AT_data_member_location, DW_FORM_block1},
+ {DW_AT_type, DW_FORM_ref_addr},
+ },
+ },
+
+ /* FUNCTYPEPARAM */
+ {
+ DW_TAG_formal_parameter,
+ DW_CHILDREN_no,
+
+ // No name!
+ []dwAttrForm{
+ {DW_AT_type, DW_FORM_ref_addr},
+ },
+ },
+
+ /* DOTDOTDOT */
+ {
+ DW_TAG_unspecified_parameters,
+ DW_CHILDREN_no,
+ []dwAttrForm{},
+ },
+
+ /* ARRAYRANGE */
+ {
+ DW_TAG_subrange_type,
+ DW_CHILDREN_no,
+
+ // No name!
+ []dwAttrForm{
+ {DW_AT_type, DW_FORM_ref_addr},
+ {DW_AT_count, DW_FORM_udata},
+ },
+ },
+
+ // Below here are the types considered public by ispubtype
+ /* NULLTYPE */
+ {
+ DW_TAG_unspecified_type,
+ DW_CHILDREN_no,
+ []dwAttrForm{
+ {DW_AT_name, DW_FORM_string},
+ },
+ },
+
+ /* BASETYPE */
+ {
+ DW_TAG_base_type,
+ DW_CHILDREN_no,
+ []dwAttrForm{
+ {DW_AT_name, DW_FORM_string},
+ {DW_AT_encoding, DW_FORM_data1},
+ {DW_AT_byte_size, DW_FORM_data1},
+ {DW_AT_go_kind, DW_FORM_data1},
+ },
+ },
+
+ /* ARRAYTYPE */
+ // child is subrange with upper bound
+ {
+ DW_TAG_array_type,
+ DW_CHILDREN_yes,
+ []dwAttrForm{
+ {DW_AT_name, DW_FORM_string},
+ {DW_AT_type, DW_FORM_ref_addr},
+ {DW_AT_byte_size, DW_FORM_udata},
+ {DW_AT_go_kind, DW_FORM_data1},
+ },
+ },
+
+ /* CHANTYPE */
+ {
+ DW_TAG_typedef,
+ DW_CHILDREN_no,
+ []dwAttrForm{
+ {DW_AT_name, DW_FORM_string},
+ {DW_AT_type, DW_FORM_ref_addr},
+ {DW_AT_go_kind, DW_FORM_data1},
+ {DW_AT_go_elem, DW_FORM_ref_addr},
+ },
+ },
+
+ /* FUNCTYPE */
+ {
+ DW_TAG_subroutine_type,
+ DW_CHILDREN_yes,
+ []dwAttrForm{
+ {DW_AT_name, DW_FORM_string},
+ // {DW_AT_type, DW_FORM_ref_addr},
+ {DW_AT_go_kind, DW_FORM_data1},
+ },
+ },
+
+ /* IFACETYPE */
+ {
+ DW_TAG_typedef,
+ DW_CHILDREN_yes,
+ []dwAttrForm{
+ {DW_AT_name, DW_FORM_string},
+ {DW_AT_type, DW_FORM_ref_addr},
+ {DW_AT_go_kind, DW_FORM_data1},
+ },
+ },
+
+ /* MAPTYPE */
+ {
+ DW_TAG_typedef,
+ DW_CHILDREN_no,
+ []dwAttrForm{
+ {DW_AT_name, DW_FORM_string},
+ {DW_AT_type, DW_FORM_ref_addr},
+ {DW_AT_go_kind, DW_FORM_data1},
+ {DW_AT_go_key, DW_FORM_ref_addr},
+ {DW_AT_go_elem, DW_FORM_ref_addr},
+ },
+ },
+
+ /* PTRTYPE */
+ {
+ DW_TAG_pointer_type,
+ DW_CHILDREN_no,
+ []dwAttrForm{
+ {DW_AT_name, DW_FORM_string},
+ {DW_AT_type, DW_FORM_ref_addr},
+ {DW_AT_go_kind, DW_FORM_data1},
+ },
+ },
+
+ /* BARE_PTRTYPE */
+ {
+ DW_TAG_pointer_type,
+ DW_CHILDREN_no,
+ []dwAttrForm{
+ {DW_AT_name, DW_FORM_string},
+ },
+ },
+
+ /* SLICETYPE */
+ {
+ DW_TAG_structure_type,
+ DW_CHILDREN_yes,
+ []dwAttrForm{
+ {DW_AT_name, DW_FORM_string},
+ {DW_AT_byte_size, DW_FORM_udata},
+ {DW_AT_go_kind, DW_FORM_data1},
+ {DW_AT_go_elem, DW_FORM_ref_addr},
+ },
+ },
+
+ /* STRINGTYPE */
+ {
+ DW_TAG_structure_type,
+ DW_CHILDREN_yes,
+ []dwAttrForm{
+ {DW_AT_name, DW_FORM_string},
+ {DW_AT_byte_size, DW_FORM_udata},
+ {DW_AT_go_kind, DW_FORM_data1},
+ },
+ },
+
+ /* STRUCTTYPE */
+ {
+ DW_TAG_structure_type,
+ DW_CHILDREN_yes,
+ []dwAttrForm{
+ {DW_AT_name, DW_FORM_string},
+ {DW_AT_byte_size, DW_FORM_udata},
+ {DW_AT_go_kind, DW_FORM_data1},
+ },
+ },
+
+ /* TYPEDECL */
+ {
+ DW_TAG_typedef,
+ DW_CHILDREN_no,
+ []dwAttrForm{
+ {DW_AT_name, DW_FORM_string},
+ {DW_AT_type, DW_FORM_ref_addr},
+ },
+ },
+}
+
+// GetAbbrev returns the contents of the .debug_abbrev section.
+func GetAbbrev() []byte {
+ var buf []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 {
+ buf = AppendUleb128(buf, uint64(f.attr))
+ buf = AppendUleb128(buf, uint64(f.form))
+ }
+ buf = append(buf, 0, 0)
+ }
+ return append(buf, 0)
+}
+
+/*
+ * Debugging Information Entries and their attributes.
+ */
+
+// DWAttr represents an attribute of a DWDie.
+//
+// For DW_CLS_string and _block, value should contain the length, and
+// data the data, for _reference, value is 0 and data is a DWDie* to
+// the referenced instance, for all others, value is the whole thing
+// and data is null.
+type DWAttr struct {
+ Link *DWAttr
+ Atr uint16 // DW_AT_
+ Cls uint8 // DW_CLS_
+ Value int64
+ Data interface{}
+}
+
+// DWDie represents a DWARF debug info entry.
+type DWDie struct {
+ Abbrev int
+ Link *DWDie
+ Child *DWDie
+ Attr *DWAttr
+ Sym Sym
+}
+
+func putattr(ctxt Context, s Sym, abbrev int, form int, cls int, value int64, data interface{}) error {
+ switch form {
+ case DW_FORM_addr: // address
+ ctxt.AddAddress(s, data, value)
+
+ case DW_FORM_block1: // block
+ if cls == DW_CLS_ADDRESS {
+ ctxt.AddInt(s, 1, int64(1+ctxt.PtrSize()))
+ ctxt.AddInt(s, 1, DW_OP_addr)
+ ctxt.AddAddress(s, data, 0)
+ break
+ }
+
+ value &= 0xff
+ ctxt.AddInt(s, 1, value)
+ p := data.([]byte)[:value]
+ ctxt.AddBytes(s, p)
+
+ case DW_FORM_block2: // block
+ value &= 0xffff
+
+ ctxt.AddInt(s, 2, value)
+ p := data.([]byte)[:value]
+ ctxt.AddBytes(s, p)
+
+ case DW_FORM_block4: // block
+ value &= 0xffffffff
+
+ ctxt.AddInt(s, 4, value)
+ p := data.([]byte)[:value]
+ ctxt.AddBytes(s, p)
+
+ case DW_FORM_block: // block
+ Uleb128put(ctxt, s, value)
+
+ p := data.([]byte)[:value]
+ ctxt.AddBytes(s, p)
+
+ case DW_FORM_data1: // constant
+ ctxt.AddInt(s, 1, value)
+
+ case DW_FORM_data2: // constant
+ 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)
+ break
+ }
+ ctxt.AddInt(s, 4, value)
+
+ case DW_FORM_data8: // constant, {line,loclist,mac,rangelist}ptr
+ ctxt.AddInt(s, 8, value)
+
+ case DW_FORM_sdata: // constant
+ Sleb128put(ctxt, s, value)
+
+ case DW_FORM_udata: // constant
+ Uleb128put(ctxt, s, value)
+
+ case DW_FORM_string: // string
+ str := data.(string)
+ ctxt.AddString(s, str)
+ // TODO(ribrdb): verify padded strings are never used and remove this
+ for i := int64(len(str)); i < value; i++ {
+ ctxt.AddInt(s, 1, 0)
+ }
+
+ case DW_FORM_flag: // flag
+ if value != 0 {
+ ctxt.AddInt(s, 1, 1)
+ } else {
+ 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
+ // (> 4 GB of debug info aka "64-bit") unit, which we don't implement.
+ case DW_FORM_ref_addr: // reference to a DIE in the .info section
+ if data == nil {
+ return fmt.Errorf("dwarf: null reference in %d", abbrev)
+ } else {
+ ctxt.AddSectionOffset(s, ctxt.PtrSize(), data, 0)
+ }
+
+ case DW_FORM_ref1, // reference within the compilation unit
+ DW_FORM_ref2, // reference
+ DW_FORM_ref4, // reference
+ DW_FORM_ref8, // reference
+ DW_FORM_ref_udata, // reference
+
+ DW_FORM_strp, // string
+ DW_FORM_indirect: // (see Section 7.5.3)
+ fallthrough
+ default:
+ return fmt.Errorf("dwarf: unsupported attribute form %d / class %d", form, cls)
+ }
+ return nil
+}
+
+// PutAttrs writes the attributes for a DIE to symbol 's'.
+//
+// Note that we can (and do) add arbitrary attributes to a DIE, but
+// only the ones actually listed in the Abbrev will be written out.
+func PutAttrs(ctxt Context, s Sym, abbrev int, attr *DWAttr) {
+Outer:
+ for _, f := range abbrevs[abbrev].attr {
+ for ap := attr; ap != nil; ap = ap.Link {
+ if ap.Atr == f.attr {
+ putattr(ctxt, s, abbrev, int(f.form), int(ap.Cls), ap.Value, ap.Data)
+ continue Outer
+ }
+ }
+
+ putattr(ctxt, s, abbrev, int(f.form), 0, 0, nil)
+ }
+}
+
+// HasChildren returns true if 'die' uses an abbrev that supports children.
+func HasChildren(die *DWDie) bool {
+ return abbrevs[die.Abbrev].children != 0
+}
+
+// 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) {
+ 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)
+ 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
+ }
+ var n string
+ if names[v.Name] {
+ n = fmt.Sprintf("%s#%d", v.Name, len(names))
+ } else {
+ n = v.Name
+ }
+ 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)
+ }
+ 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)
+
+ }
+ Uleb128put(ctxt, s, 0)
+}
diff --git a/src/cmd/internal/dwarf/dwarf_defs.go b/src/cmd/internal/dwarf/dwarf_defs.go
new file mode 100644
index 0000000..d1870b5
--- /dev/null
+++ b/src/cmd/internal/dwarf/dwarf_defs.go
@@ -0,0 +1,483 @@
+// Copyright 2010 The Go Authors. 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
+
+// Cut, pasted, tr-and-awk'ed from tables in
+// http://dwarfstd.org/doc/Dwarf3.pdf
+
+// Table 18
+const (
+ DW_TAG_array_type = 0x01
+ DW_TAG_class_type = 0x02
+ DW_TAG_entry_point = 0x03
+ DW_TAG_enumeration_type = 0x04
+ DW_TAG_formal_parameter = 0x05
+ DW_TAG_imported_declaration = 0x08
+ DW_TAG_label = 0x0a
+ DW_TAG_lexical_block = 0x0b
+ DW_TAG_member = 0x0d
+ DW_TAG_pointer_type = 0x0f
+ DW_TAG_reference_type = 0x10
+ DW_TAG_compile_unit = 0x11
+ DW_TAG_string_type = 0x12
+ DW_TAG_structure_type = 0x13
+ DW_TAG_subroutine_type = 0x15
+ DW_TAG_typedef = 0x16
+ DW_TAG_union_type = 0x17
+ DW_TAG_unspecified_parameters = 0x18
+ DW_TAG_variant = 0x19
+ DW_TAG_common_block = 0x1a
+ DW_TAG_common_inclusion = 0x1b
+ DW_TAG_inheritance = 0x1c
+ DW_TAG_inlined_subroutine = 0x1d
+ DW_TAG_module = 0x1e
+ DW_TAG_ptr_to_member_type = 0x1f
+ DW_TAG_set_type = 0x20
+ DW_TAG_subrange_type = 0x21
+ DW_TAG_with_stmt = 0x22
+ DW_TAG_access_declaration = 0x23
+ DW_TAG_base_type = 0x24
+ DW_TAG_catch_block = 0x25
+ DW_TAG_const_type = 0x26
+ DW_TAG_constant = 0x27
+ DW_TAG_enumerator = 0x28
+ DW_TAG_file_type = 0x29
+ DW_TAG_friend = 0x2a
+ DW_TAG_namelist = 0x2b
+ DW_TAG_namelist_item = 0x2c
+ DW_TAG_packed_type = 0x2d
+ DW_TAG_subprogram = 0x2e
+ DW_TAG_template_type_parameter = 0x2f
+ DW_TAG_template_value_parameter = 0x30
+ DW_TAG_thrown_type = 0x31
+ DW_TAG_try_block = 0x32
+ DW_TAG_variant_part = 0x33
+ DW_TAG_variable = 0x34
+ DW_TAG_volatile_type = 0x35
+ // Dwarf3
+ DW_TAG_dwarf_procedure = 0x36
+ DW_TAG_restrict_type = 0x37
+ DW_TAG_interface_type = 0x38
+ DW_TAG_namespace = 0x39
+ DW_TAG_imported_module = 0x3a
+ DW_TAG_unspecified_type = 0x3b
+ DW_TAG_partial_unit = 0x3c
+ DW_TAG_imported_unit = 0x3d
+ DW_TAG_condition = 0x3f
+ DW_TAG_shared_type = 0x40
+ // Dwarf4
+ DW_TAG_type_unit = 0x41
+ DW_TAG_rvalue_reference_type = 0x42
+ DW_TAG_template_alias = 0x43
+
+ // User defined
+ DW_TAG_lo_user = 0x4080
+ DW_TAG_hi_user = 0xffff
+)
+
+// Table 19
+const (
+ DW_CHILDREN_no = 0x00
+ DW_CHILDREN_yes = 0x01
+)
+
+// Not from the spec, but logically belongs here
+const (
+ DW_CLS_ADDRESS = 0x01 + iota
+ DW_CLS_BLOCK
+ DW_CLS_CONSTANT
+ DW_CLS_FLAG
+ DW_CLS_PTR // lineptr, loclistptr, macptr, rangelistptr
+ DW_CLS_REFERENCE
+ DW_CLS_ADDRLOC
+ DW_CLS_STRING
+)
+
+// Table 20
+const (
+ DW_AT_sibling = 0x01 // reference
+ DW_AT_location = 0x02 // block, loclistptr
+ DW_AT_name = 0x03 // string
+ DW_AT_ordering = 0x09 // constant
+ DW_AT_byte_size = 0x0b // block, constant, reference
+ DW_AT_bit_offset = 0x0c // block, constant, reference
+ DW_AT_bit_size = 0x0d // block, constant, reference
+ DW_AT_stmt_list = 0x10 // lineptr
+ DW_AT_low_pc = 0x11 // address
+ DW_AT_high_pc = 0x12 // address
+ DW_AT_language = 0x13 // constant
+ DW_AT_discr = 0x15 // reference
+ DW_AT_discr_value = 0x16 // constant
+ DW_AT_visibility = 0x17 // constant
+ DW_AT_import = 0x18 // reference
+ DW_AT_string_length = 0x19 // block, loclistptr
+ DW_AT_common_reference = 0x1a // reference
+ DW_AT_comp_dir = 0x1b // string
+ DW_AT_const_value = 0x1c // block, constant, string
+ DW_AT_containing_type = 0x1d // reference
+ DW_AT_default_value = 0x1e // reference
+ DW_AT_inline = 0x20 // constant
+ DW_AT_is_optional = 0x21 // flag
+ DW_AT_lower_bound = 0x22 // block, constant, reference
+ DW_AT_producer = 0x25 // string
+ DW_AT_prototyped = 0x27 // flag
+ DW_AT_return_addr = 0x2a // block, loclistptr
+ DW_AT_start_scope = 0x2c // constant
+ DW_AT_bit_stride = 0x2e // constant
+ DW_AT_upper_bound = 0x2f // block, constant, reference
+ DW_AT_abstract_origin = 0x31 // reference
+ DW_AT_accessibility = 0x32 // constant
+ DW_AT_address_class = 0x33 // constant
+ DW_AT_artificial = 0x34 // flag
+ DW_AT_base_types = 0x35 // reference
+ DW_AT_calling_convention = 0x36 // constant
+ DW_AT_count = 0x37 // block, constant, reference
+ DW_AT_data_member_location = 0x38 // block, constant, loclistptr
+ DW_AT_decl_column = 0x39 // constant
+ DW_AT_decl_file = 0x3a // constant
+ DW_AT_decl_line = 0x3b // constant
+ DW_AT_declaration = 0x3c // flag
+ DW_AT_discr_list = 0x3d // block
+ DW_AT_encoding = 0x3e // constant
+ DW_AT_external = 0x3f // flag
+ DW_AT_frame_base = 0x40 // block, loclistptr
+ DW_AT_friend = 0x41 // reference
+ DW_AT_identifier_case = 0x42 // constant
+ DW_AT_macro_info = 0x43 // macptr
+ DW_AT_namelist_item = 0x44 // block
+ DW_AT_priority = 0x45 // reference
+ DW_AT_segment = 0x46 // block, loclistptr
+ DW_AT_specification = 0x47 // reference
+ DW_AT_static_link = 0x48 // block, loclistptr
+ DW_AT_type = 0x49 // reference
+ DW_AT_use_location = 0x4a // block, loclistptr
+ DW_AT_variable_parameter = 0x4b // flag
+ DW_AT_virtuality = 0x4c // constant
+ DW_AT_vtable_elem_location = 0x4d // block, loclistptr
+ // Dwarf3
+ DW_AT_allocated = 0x4e // block, constant, reference
+ DW_AT_associated = 0x4f // block, constant, reference
+ DW_AT_data_location = 0x50 // block
+ DW_AT_byte_stride = 0x51 // block, constant, reference
+ DW_AT_entry_pc = 0x52 // address
+ DW_AT_use_UTF8 = 0x53 // flag
+ DW_AT_extension = 0x54 // reference
+ DW_AT_ranges = 0x55 // rangelistptr
+ DW_AT_trampoline = 0x56 // address, flag, reference, string
+ DW_AT_call_column = 0x57 // constant
+ DW_AT_call_file = 0x58 // constant
+ DW_AT_call_line = 0x59 // constant
+ DW_AT_description = 0x5a // string
+ DW_AT_binary_scale = 0x5b // constant
+ DW_AT_decimal_scale = 0x5c // constant
+ DW_AT_small = 0x5d // reference
+ DW_AT_decimal_sign = 0x5e // constant
+ DW_AT_digit_count = 0x5f // constant
+ DW_AT_picture_string = 0x60 // string
+ DW_AT_mutable = 0x61 // flag
+ DW_AT_threads_scaled = 0x62 // flag
+ DW_AT_explicit = 0x63 // flag
+ DW_AT_object_pointer = 0x64 // reference
+ DW_AT_endianity = 0x65 // constant
+ DW_AT_elemental = 0x66 // flag
+ DW_AT_pure = 0x67 // flag
+ DW_AT_recursive = 0x68 // flag
+
+ DW_AT_lo_user = 0x2000 // ---
+ DW_AT_hi_user = 0x3fff // ---
+)
+
+// Table 21
+const (
+ DW_FORM_addr = 0x01 // address
+ DW_FORM_block2 = 0x03 // block
+ DW_FORM_block4 = 0x04 // block
+ DW_FORM_data2 = 0x05 // constant
+ DW_FORM_data4 = 0x06 // constant, lineptr, loclistptr, macptr, rangelistptr
+ DW_FORM_data8 = 0x07 // constant, lineptr, loclistptr, macptr, rangelistptr
+ DW_FORM_string = 0x08 // string
+ DW_FORM_block = 0x09 // block
+ DW_FORM_block1 = 0x0a // block
+ DW_FORM_data1 = 0x0b // constant
+ DW_FORM_flag = 0x0c // flag
+ DW_FORM_sdata = 0x0d // constant
+ DW_FORM_strp = 0x0e // string
+ DW_FORM_udata = 0x0f // constant
+ DW_FORM_ref_addr = 0x10 // reference
+ DW_FORM_ref1 = 0x11 // reference
+ DW_FORM_ref2 = 0x12 // reference
+ DW_FORM_ref4 = 0x13 // reference
+ DW_FORM_ref8 = 0x14 // reference
+ DW_FORM_ref_udata = 0x15 // reference
+ DW_FORM_indirect = 0x16 // (see Section 7.5.3)
+)
+
+// Table 24 (#operands, notes)
+const (
+ DW_OP_addr = 0x03 // 1 constant address (size target specific)
+ DW_OP_deref = 0x06 // 0
+ DW_OP_const1u = 0x08 // 1 1-byte constant
+ DW_OP_const1s = 0x09 // 1 1-byte constant
+ DW_OP_const2u = 0x0a // 1 2-byte constant
+ DW_OP_const2s = 0x0b // 1 2-byte constant
+ DW_OP_const4u = 0x0c // 1 4-byte constant
+ DW_OP_const4s = 0x0d // 1 4-byte constant
+ DW_OP_const8u = 0x0e // 1 8-byte constant
+ DW_OP_const8s = 0x0f // 1 8-byte constant
+ DW_OP_constu = 0x10 // 1 ULEB128 constant
+ DW_OP_consts = 0x11 // 1 SLEB128 constant
+ DW_OP_dup = 0x12 // 0
+ DW_OP_drop = 0x13 // 0
+ DW_OP_over = 0x14 // 0
+ DW_OP_pick = 0x15 // 1 1-byte stack index
+ DW_OP_swap = 0x16 // 0
+ DW_OP_rot = 0x17 // 0
+ DW_OP_xderef = 0x18 // 0
+ DW_OP_abs = 0x19 // 0
+ DW_OP_and = 0x1a // 0
+ DW_OP_div = 0x1b // 0
+ DW_OP_minus = 0x1c // 0
+ DW_OP_mod = 0x1d // 0
+ DW_OP_mul = 0x1e // 0
+ DW_OP_neg = 0x1f // 0
+ DW_OP_not = 0x20 // 0
+ DW_OP_or = 0x21 // 0
+ DW_OP_plus = 0x22 // 0
+ DW_OP_plus_uconst = 0x23 // 1 ULEB128 addend
+ DW_OP_shl = 0x24 // 0
+ DW_OP_shr = 0x25 // 0
+ DW_OP_shra = 0x26 // 0
+ DW_OP_xor = 0x27 // 0
+ DW_OP_skip = 0x2f // 1 signed 2-byte constant
+ DW_OP_bra = 0x28 // 1 signed 2-byte constant
+ DW_OP_eq = 0x29 // 0
+ DW_OP_ge = 0x2a // 0
+ DW_OP_gt = 0x2b // 0
+ DW_OP_le = 0x2c // 0
+ DW_OP_lt = 0x2d // 0
+ DW_OP_ne = 0x2e // 0
+ DW_OP_lit0 = 0x30 // 0 ...
+ DW_OP_lit31 = 0x4f // 0 literals 0..31 = (DW_OP_lit0 + literal)
+ DW_OP_reg0 = 0x50 // 0 ..
+ DW_OP_reg31 = 0x6f // 0 reg 0..31 = (DW_OP_reg0 + regnum)
+ DW_OP_breg0 = 0x70 // 1 ...
+ DW_OP_breg31 = 0x8f // 1 SLEB128 offset base register 0..31 = (DW_OP_breg0 + regnum)
+ DW_OP_regx = 0x90 // 1 ULEB128 register
+ DW_OP_fbreg = 0x91 // 1 SLEB128 offset
+ DW_OP_bregx = 0x92 // 2 ULEB128 register followed by SLEB128 offset
+ DW_OP_piece = 0x93 // 1 ULEB128 size of piece addressed
+ DW_OP_deref_size = 0x94 // 1 1-byte size of data retrieved
+ DW_OP_xderef_size = 0x95 // 1 1-byte size of data retrieved
+ DW_OP_nop = 0x96 // 0
+ DW_OP_push_object_address = 0x97 // 0
+ DW_OP_call2 = 0x98 // 1 2-byte offset of DIE
+ DW_OP_call4 = 0x99 // 1 4-byte offset of DIE
+ DW_OP_call_ref = 0x9a // 1 4- or 8-byte offset of DIE
+ DW_OP_form_tls_address = 0x9b // 0
+ DW_OP_call_frame_cfa = 0x9c // 0
+ DW_OP_bit_piece = 0x9d // 2
+ DW_OP_lo_user = 0xe0
+ DW_OP_hi_user = 0xff
+)
+
+// Table 25
+const (
+ DW_ATE_address = 0x01
+ DW_ATE_boolean = 0x02
+ DW_ATE_complex_float = 0x03
+ DW_ATE_float = 0x04
+ DW_ATE_signed = 0x05
+ DW_ATE_signed_char = 0x06
+ DW_ATE_unsigned = 0x07
+ DW_ATE_unsigned_char = 0x08
+ DW_ATE_imaginary_float = 0x09
+ DW_ATE_packed_decimal = 0x0a
+ DW_ATE_numeric_string = 0x0b
+ DW_ATE_edited = 0x0c
+ DW_ATE_signed_fixed = 0x0d
+ DW_ATE_unsigned_fixed = 0x0e
+ DW_ATE_decimal_float = 0x0f
+ DW_ATE_lo_user = 0x80
+ DW_ATE_hi_user = 0xff
+)
+
+// Table 26
+const (
+ DW_DS_unsigned = 0x01
+ DW_DS_leading_overpunch = 0x02
+ DW_DS_trailing_overpunch = 0x03
+ DW_DS_leading_separate = 0x04
+ DW_DS_trailing_separate = 0x05
+)
+
+// Table 27
+const (
+ DW_END_default = 0x00
+ DW_END_big = 0x01
+ DW_END_little = 0x02
+ DW_END_lo_user = 0x40
+ DW_END_hi_user = 0xff
+)
+
+// Table 28
+const (
+ DW_ACCESS_public = 0x01
+ DW_ACCESS_protected = 0x02
+ DW_ACCESS_private = 0x03
+)
+
+// Table 29
+const (
+ DW_VIS_local = 0x01
+ DW_VIS_exported = 0x02
+ DW_VIS_qualified = 0x03
+)
+
+// Table 30
+const (
+ DW_VIRTUALITY_none = 0x00
+ DW_VIRTUALITY_virtual = 0x01
+ DW_VIRTUALITY_pure_virtual = 0x02
+)
+
+// Table 31
+const (
+ DW_LANG_C89 = 0x0001
+ DW_LANG_C = 0x0002
+ DW_LANG_Ada83 = 0x0003
+ DW_LANG_C_plus_plus = 0x0004
+ DW_LANG_Cobol74 = 0x0005
+ DW_LANG_Cobol85 = 0x0006
+ DW_LANG_Fortran77 = 0x0007
+ DW_LANG_Fortran90 = 0x0008
+ DW_LANG_Pascal83 = 0x0009
+ DW_LANG_Modula2 = 0x000a
+ // Dwarf3
+ DW_LANG_Java = 0x000b
+ DW_LANG_C99 = 0x000c
+ DW_LANG_Ada95 = 0x000d
+ DW_LANG_Fortran95 = 0x000e
+ DW_LANG_PLI = 0x000f
+ DW_LANG_ObjC = 0x0010
+ DW_LANG_ObjC_plus_plus = 0x0011
+ DW_LANG_UPC = 0x0012
+ DW_LANG_D = 0x0013
+ // Dwarf4
+ DW_LANG_Python = 0x0014
+ // Dwarf5
+ DW_LANG_Go = 0x0016
+
+ DW_LANG_lo_user = 0x8000
+ DW_LANG_hi_user = 0xffff
+)
+
+// Table 32
+const (
+ DW_ID_case_sensitive = 0x00
+ DW_ID_up_case = 0x01
+ DW_ID_down_case = 0x02
+ DW_ID_case_insensitive = 0x03
+)
+
+// Table 33
+const (
+ DW_CC_normal = 0x01
+ DW_CC_program = 0x02
+ DW_CC_nocall = 0x03
+ DW_CC_lo_user = 0x40
+ DW_CC_hi_user = 0xff
+)
+
+// Table 34
+const (
+ DW_INL_not_inlined = 0x00
+ DW_INL_inlined = 0x01
+ DW_INL_declared_not_inlined = 0x02
+ DW_INL_declared_inlined = 0x03
+)
+
+// Table 35
+const (
+ DW_ORD_row_major = 0x00
+ DW_ORD_col_major = 0x01
+)
+
+// Table 36
+const (
+ DW_DSC_label = 0x00
+ DW_DSC_range = 0x01
+)
+
+// Table 37
+const (
+ DW_LNS_copy = 0x01
+ DW_LNS_advance_pc = 0x02
+ DW_LNS_advance_line = 0x03
+ DW_LNS_set_file = 0x04
+ DW_LNS_set_column = 0x05
+ DW_LNS_negate_stmt = 0x06
+ DW_LNS_set_basic_block = 0x07
+ DW_LNS_const_add_pc = 0x08
+ DW_LNS_fixed_advance_pc = 0x09
+ // Dwarf3
+ DW_LNS_set_prologue_end = 0x0a
+ DW_LNS_set_epilogue_begin = 0x0b
+ DW_LNS_set_isa = 0x0c
+)
+
+// Table 38
+const (
+ DW_LNE_end_sequence = 0x01
+ DW_LNE_set_address = 0x02
+ DW_LNE_define_file = 0x03
+ DW_LNE_lo_user = 0x80
+ DW_LNE_hi_user = 0xff
+)
+
+// Table 39
+const (
+ DW_MACINFO_define = 0x01
+ DW_MACINFO_undef = 0x02
+ DW_MACINFO_start_file = 0x03
+ DW_MACINFO_end_file = 0x04
+ DW_MACINFO_vendor_ext = 0xff
+)
+
+// Table 40.
+const (
+ // operand,...
+ DW_CFA_nop = 0x00
+ DW_CFA_set_loc = 0x01 // address
+ DW_CFA_advance_loc1 = 0x02 // 1-byte delta
+ DW_CFA_advance_loc2 = 0x03 // 2-byte delta
+ DW_CFA_advance_loc4 = 0x04 // 4-byte delta
+ DW_CFA_offset_extended = 0x05 // ULEB128 register, ULEB128 offset
+ DW_CFA_restore_extended = 0x06 // ULEB128 register
+ DW_CFA_undefined = 0x07 // ULEB128 register
+ DW_CFA_same_value = 0x08 // ULEB128 register
+ DW_CFA_register = 0x09 // ULEB128 register, ULEB128 register
+ DW_CFA_remember_state = 0x0a
+ DW_CFA_restore_state = 0x0b
+
+ DW_CFA_def_cfa = 0x0c // ULEB128 register, ULEB128 offset
+ DW_CFA_def_cfa_register = 0x0d // ULEB128 register
+ DW_CFA_def_cfa_offset = 0x0e // ULEB128 offset
+ DW_CFA_def_cfa_expression = 0x0f // BLOCK
+ DW_CFA_expression = 0x10 // ULEB128 register, BLOCK
+ DW_CFA_offset_extended_sf = 0x11 // ULEB128 register, SLEB128 offset
+ DW_CFA_def_cfa_sf = 0x12 // ULEB128 register, SLEB128 offset
+ DW_CFA_def_cfa_offset_sf = 0x13 // SLEB128 offset
+ DW_CFA_val_offset = 0x14 // ULEB128, ULEB128
+ DW_CFA_val_offset_sf = 0x15 // ULEB128, SLEB128
+ DW_CFA_val_expression = 0x16 // ULEB128, BLOCK
+
+ DW_CFA_lo_user = 0x1c
+ DW_CFA_hi_user = 0x3f
+
+ // Opcodes that take an addend operand.
+ DW_CFA_advance_loc = 0x1 << 6 // +delta
+ DW_CFA_offset = 0x2 << 6 // +register (ULEB128 offset)
+ DW_CFA_restore = 0x3 << 6 // +register
+)
diff --git a/src/cmd/internal/gcprog/gcprog.go b/src/cmd/internal/gcprog/gcprog.go
index 7880917..c8bf206 100644
--- a/src/cmd/internal/gcprog/gcprog.go
+++ b/src/cmd/internal/gcprog/gcprog.go
@@ -37,7 +37,6 @@ const progMaxLiteral = 127 // maximum n for literal n bit code
// to describe the data type, and then finally call End.
type Writer struct {
writeByte func(byte)
- symoff int
index int64
b [progMaxLiteral]byte
nb int
diff --git a/src/cmd/internal/goobj/read.go b/src/cmd/internal/goobj/read.go
index 214f65c..ff4aa59 100644
--- a/src/cmd/internal/goobj/read.go
+++ b/src/cmd/internal/goobj/read.go
@@ -29,50 +29,48 @@ type SymKind int
// TODO(rsc): Give idiomatic Go names.
// TODO(rsc): Reduce the number of symbol types in the object files.
const (
- _ SymKind = iota
-
// readonly, executable
- STEXT SymKind = obj.STEXT
- SELFRXSECT SymKind = obj.SELFRXSECT
+ 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
+ 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
+ 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
+ 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{
@@ -163,7 +161,7 @@ type Data struct {
// A Reloc describes a relocation applied to a memory image to refer
// to an address within a particular symbol.
type Reloc struct {
- // The bytes at [Offset, Offset+Size) within the memory image
+ // The bytes at [Offset, Offset+Size) within the containing Sym
// should be updated to refer to the address Add bytes after the start
// of the symbol Sym.
Offset int
@@ -174,7 +172,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 int
+ Type obj.RelocType
}
// A Var describes a variable in a function stack frame: a declared
@@ -220,6 +218,7 @@ type Package struct {
SymRefs []SymID // list of symbol names and versions referred to by this pack
Syms []*Sym // symbols defined by this package
MaxVersion int // maximum Version in any SymID in Syms
+ Arch string // architecture
}
var (
@@ -243,7 +242,6 @@ type objReader struct {
dataOffset int64
limit int64
tmp [256]byte
- pkg string
pkgprefix string
}
@@ -561,14 +559,13 @@ func (r *objReader) parseArchive() error {
// The format of that part is defined in a comment at the top
// of src/liblink/objfile.c.
func (r *objReader) parseObject(prefix []byte) error {
- // TODO(rsc): Maybe use prefix and the initial input to
- // record the header line from the file, which would
- // give the architecture and other version information.
-
r.p.MaxVersion++
+ h := make([]byte, 0, 256)
+ h = append(h, prefix...)
var c1, c2, c3 byte
for {
c1, c2, c3 = c2, c3, r.readByte()
+ h = append(h, c3)
// The new export format can contain 0 bytes.
// Don't consider them errors, only look for r.err != nil.
if r.err != nil {
@@ -579,6 +576,12 @@ func (r *objReader) parseObject(prefix []byte) error {
}
}
+ hs := strings.Fields(string(h))
+ if len(hs) >= 4 {
+ r.p.Arch = hs[3]
+ }
+ // TODO: extract OS + build ID if/when we need it
+
r.readFull(r.tmp[:8])
if !bytes.Equal(r.tmp[:8], []byte("\x00\x00go17ld")) {
return r.error(errCorruptObject)
@@ -643,7 +646,7 @@ func (r *objReader) parseObject(prefix []byte) error {
rel := &s.Reloc[i]
rel.Offset = r.readInt()
rel.Size = r.readInt()
- rel.Type = r.readInt()
+ rel.Type = obj.RelocType(r.readInt())
rel.Add = r.readInt()
rel.Sym = r.readSymID()
}
@@ -693,3 +696,18 @@ func (r *objReader) parseObject(prefix []byte) error {
return nil
}
+
+func (r *Reloc) String(insnOffset uint64) string {
+ delta := r.Offset - int(insnOffset)
+ s := fmt.Sprintf("[%d:%d]%s", delta, delta+r.Size, r.Type)
+ if r.Sym.Name != "" {
+ if r.Add != 0 {
+ return fmt.Sprintf("%s:%s+%d", s, r.Sym.Name, r.Add)
+ }
+ return fmt.Sprintf("%s:%s", s, r.Sym.Name)
+ }
+ if r.Add != 0 {
+ return fmt.Sprintf("%s:%d", s, r.Add)
+ }
+ return s
+}
diff --git a/src/cmd/internal/obj/addrtype_string.go b/src/cmd/internal/obj/addrtype_string.go
new file mode 100644
index 0000000..48d498d
--- /dev/null
+++ b/src/cmd/internal/obj/addrtype_string.go
@@ -0,0 +1,27 @@
+// Code generated by "stringer -type AddrType cmd/internal/obj"; DO NOT EDIT
+
+package obj
+
+import "fmt"
+
+const (
+ _AddrType_name_0 = "TYPE_NONE"
+ _AddrType_name_1 = "TYPE_BRANCHTYPE_TEXTSIZETYPE_MEMTYPE_CONSTTYPE_FCONSTTYPE_SCONSTTYPE_REGTYPE_ADDRTYPE_SHIFTTYPE_REGREGTYPE_REGREG2TYPE_INDIRTYPE_REGLIST"
+)
+
+var (
+ _AddrType_index_0 = [...]uint8{0, 9}
+ _AddrType_index_1 = [...]uint8{0, 11, 24, 32, 42, 53, 64, 72, 81, 91, 102, 114, 124, 136}
+)
+
+func (i AddrType) String() string {
+ switch {
+ case i == 0:
+ return _AddrType_name_0
+ case 6 <= i && i <= 18:
+ i -= 6
+ return _AddrType_name_1[_AddrType_index_1[i]:_AddrType_index_1[i+1]]
+ default:
+ return fmt.Sprintf("AddrType(%d)", i)
+ }
+}
diff --git a/src/cmd/internal/obj/arm/a.out.go b/src/cmd/internal/obj/arm/a.out.go
index 4234b59..ad19f2d 100644
--- a/src/cmd/internal/obj/arm/a.out.go
+++ b/src/cmd/internal/obj/arm/a.out.go
@@ -1,5 +1,5 @@
// Inferno utils/5c/5.out.h
-// http://code.google.com/p/inferno-os/source/browse/utils/5c/5.out.h
+// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5c/5.out.h
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth at terzarima.net)
@@ -234,6 +234,8 @@ const (
ASQRTD
AABSF
AABSD
+ ANEGF
+ ANEGD
ASRL
ASRA
diff --git a/src/cmd/internal/obj/arm/anames.go b/src/cmd/internal/obj/arm/anames.go
index 0ef68a6..6d7db2d 100644
--- a/src/cmd/internal/obj/arm/anames.go
+++ b/src/cmd/internal/obj/arm/anames.go
@@ -59,6 +59,8 @@ var Anames = []string{
"SQRTD",
"ABSF",
"ABSD",
+ "NEGF",
+ "NEGD",
"SRL",
"SRA",
"SLL",
diff --git a/src/cmd/internal/obj/arm/asm5.go b/src/cmd/internal/obj/arm/asm5.go
index d37091f..a1213bc 100644
--- a/src/cmd/internal/obj/arm/asm5.go
+++ b/src/cmd/internal/obj/arm/asm5.go
@@ -1,5 +1,5 @@
// Inferno utils/5l/span.c
-// http://code.google.com/p/inferno-os/source/browse/utils/5l/span.c
+// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5l/span.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth at terzarima.net)
@@ -648,7 +648,7 @@ func span5(ctxt *obj.Link, cursym *obj.LSym) {
var out [6 + 3]uint32
for {
if ctxt.Debugvlog != 0 {
- fmt.Fprintf(ctxt.Bso, "%5.2f span1\n", obj.Cputime())
+ ctxt.Logf("%5.2f span1\n", obj.Cputime())
}
bflag = 0
c = 0
@@ -1026,16 +1026,15 @@ func aclass(ctxt *obj.Link, a *obj.Addr) int {
case obj.NAME_AUTO:
ctxt.Instoffset = int64(ctxt.Autosize) + a.Offset
- t := int(immaddr(int32(ctxt.Instoffset)))
- if t != 0 {
+ if t := immaddr(int32(ctxt.Instoffset)); t != 0 {
if immhalf(int32(ctxt.Instoffset)) {
- if immfloat(int32(t)) {
+ if immfloat(t) {
return C_HFAUTO
}
return C_HAUTO
}
- if immfloat(int32(t)) {
+ if immfloat(t) {
return C_FAUTO
}
return C_SAUTO
@@ -1045,16 +1044,15 @@ func aclass(ctxt *obj.Link, a *obj.Addr) int {
case obj.NAME_PARAM:
ctxt.Instoffset = int64(ctxt.Autosize) + a.Offset + 4
- t := int(immaddr(int32(ctxt.Instoffset)))
- if t != 0 {
+ if t := immaddr(int32(ctxt.Instoffset)); t != 0 {
if immhalf(int32(ctxt.Instoffset)) {
- if immfloat(int32(t)) {
+ if immfloat(t) {
return C_HFAUTO
}
return C_HAUTO
}
- if immfloat(int32(t)) {
+ if immfloat(t) {
return C_FAUTO
}
return C_SAUTO
@@ -1064,20 +1062,18 @@ func aclass(ctxt *obj.Link, a *obj.Addr) int {
case obj.NAME_NONE:
ctxt.Instoffset = a.Offset
- t := int(immaddr(int32(ctxt.Instoffset)))
- if t != 0 {
+ if t := immaddr(int32(ctxt.Instoffset)); t != 0 {
if immhalf(int32(ctxt.Instoffset)) { /* n.b. that it will also satisfy immrot */
- if immfloat(int32(t)) {
+ if immfloat(t) {
return C_HFOREG
}
return C_HOREG
}
- if immfloat(int32(t)) {
+ if immfloat(t) {
return C_FOREG /* n.b. that it will also satisfy immrot */
}
- t := int(immrot(uint32(ctxt.Instoffset)))
- if t != 0 {
+ if immrot(uint32(ctxt.Instoffset)) != 0 {
return C_SROREG
}
if immhalf(int32(ctxt.Instoffset)) {
@@ -1086,8 +1082,7 @@ func aclass(ctxt *obj.Link, a *obj.Addr) int {
return C_SOREG
}
- t = int(immrot(uint32(ctxt.Instoffset)))
- if t != 0 {
+ if immrot(uint32(ctxt.Instoffset)) != 0 {
return C_ROREG
}
return C_LOREG
@@ -1116,12 +1111,10 @@ func aclass(ctxt *obj.Link, a *obj.Addr) int {
return aconsize(ctxt)
}
- t := int(immrot(uint32(ctxt.Instoffset)))
- if t != 0 {
+ if immrot(uint32(ctxt.Instoffset)) != 0 {
return C_RCON
}
- t = int(immrot(^uint32(ctxt.Instoffset)))
- if t != 0 {
+ if immrot(^uint32(ctxt.Instoffset)) != 0 {
return C_NCON
}
return C_LCON
@@ -1155,8 +1148,10 @@ func aclass(ctxt *obj.Link, a *obj.Addr) int {
}
func aconsize(ctxt *obj.Link) int {
- t := int(immrot(uint32(ctxt.Instoffset)))
- if t != 0 {
+ if immrot(uint32(ctxt.Instoffset)) != 0 {
+ return C_RACON
+ }
+ if immrot(uint32(-ctxt.Instoffset)) != 0 {
return C_RACON
}
return C_LACON
@@ -1191,7 +1186,7 @@ func oplook(ctxt *obj.Link, p *obj.Prog) *Optab {
}
if false { /*debug['O']*/
- fmt.Printf("oplook %v %v %v %v\n", obj.Aconv(p.As), DRconv(a1), DRconv(a2), DRconv(a3))
+ fmt.Printf("oplook %v %v %v %v\n", p.As, DRconv(a1), DRconv(a2), DRconv(a3))
fmt.Printf("\t\t%d %d\n", p.From.Type, p.To.Type)
}
@@ -1343,7 +1338,7 @@ func buildop(ctxt *obj.Link) {
switch r {
default:
- ctxt.Diag("unknown op in build: %v", obj.Aconv(r))
+ ctxt.Diag("unknown op in build: %v", r)
log.Fatalf("bad code")
case AADD:
@@ -1434,6 +1429,8 @@ func buildop(ctxt *obj.Link) {
opset(AMOVDF, r0)
opset(AABSF, r0)
opset(AABSD, r0)
+ opset(ANEGF, r0)
+ opset(ANEGD, r0)
case ACMPF:
opset(ACMPD, r0)
@@ -1535,11 +1532,15 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
case 3: /* add R<<[IR],[R],R */
o1 = mov(ctxt, p)
- case 4: /* add $I,[R],R */
+ case 4: /* MOVW $off(R), R -> add $off,[R],R */
aclass(ctxt, &p.From)
-
- o1 = oprrr(ctxt, AADD, int(p.Scond))
- o1 |= uint32(immrot(uint32(ctxt.Instoffset)))
+ if ctxt.Instoffset < 0 {
+ o1 = oprrr(ctxt, ASUB, int(p.Scond))
+ o1 |= uint32(immrot(uint32(-ctxt.Instoffset)))
+ } else {
+ o1 = oprrr(ctxt, AADD, int(p.Scond))
+ o1 |= uint32(immrot(uint32(ctxt.Instoffset)))
+ }
r := int(p.From.Reg)
if r == 0 {
r = int(o.param)
@@ -1930,7 +1931,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
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 {
+ 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
}
}
@@ -2357,7 +2358,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
o1 |= uint32(p.From.Offset & 0xfff)
}
- // This is supposed to be something that stops execution.
+ // This is supposed to be something that stops execution.
// It's not supposed to be reached, ever, but if it is, we'd
// like to be able to tell how we got there. Assemble as
// 0xf7fabcfd which is guaranteed to raise undefined instruction
@@ -2386,7 +2387,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
o1 |= (uint32(p.Reg) & 15) << 0
o1 |= uint32((p.To.Offset & 15) << 16)
- // DATABUNDLE: BKPT $0x5be0, signify the start of NaCl data bundle;
+ // DATABUNDLE: BKPT $0x5be0, signify the start of NaCl data bundle;
// DATABUNDLEEND: zero width alignment marker
case 100:
if p.As == ADATABUNDLE {
@@ -2508,6 +2509,10 @@ func oprrr(ctxt *obj.Link, a obj.As, sc int) uint32 {
return o | 0xe<<24 | 0xb<<20 | 0<<16 | 0xb<<8 | 0xc<<4
case AABSF:
return o | 0xe<<24 | 0xb<<20 | 0<<16 | 0xa<<8 | 0xc<<4
+ case ANEGD:
+ return o | 0xe<<24 | 0xb<<20 | 1<<16 | 0xb<<8 | 0x4<<4
+ case ANEGF:
+ return o | 0xe<<24 | 0xb<<20 | 1<<16 | 0xa<<8 | 0x4<<4
case ACMPD:
return o | 0xe<<24 | 0xb<<20 | 4<<16 | 0xb<<8 | 0xc<<4
case ACMPF:
@@ -2630,7 +2635,7 @@ func opbra(ctxt *obj.Link, p *obj.Prog, a obj.As, sc int) uint32 {
return 0xe<<28 | 0x5<<25
}
- ctxt.Diag("bad bra %v", obj.Aconv(a))
+ ctxt.Diag("bad bra %v", a)
prasm(ctxt.Curp)
return 0
}
@@ -2750,7 +2755,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", obj.Aconv(a))
+ ctxt.Diag("bad fst %v", a)
fallthrough
case AMOVD:
@@ -2788,7 +2793,7 @@ func omvl(ctxt *obj.Link, p *obj.Prog, a *obj.Addr, dr int) uint32 {
func chipzero5(ctxt *obj.Link, e float64) int {
// We use GOARM=7 to gate the use of VFPv3 vmov (imm) instructions.
- if ctxt.Goarm < 7 || e != 0 {
+ if obj.GOARM < 7 || e != 0 {
return -1
}
return 0
@@ -2796,7 +2801,7 @@ func chipzero5(ctxt *obj.Link, e float64) int {
func chipfloat5(ctxt *obj.Link, e float64) int {
// We use GOARM=7 to gate the use of VFPv3 vmov (imm) instructions.
- if ctxt.Goarm < 7 {
+ if obj.GOARM < 7 {
return -1
}
diff --git a/src/cmd/internal/obj/arm/list5.go b/src/cmd/internal/obj/arm/list5.go
index a0c210e..c25a8b7 100644
--- a/src/cmd/internal/obj/arm/list5.go
+++ b/src/cmd/internal/obj/arm/list5.go
@@ -1,5 +1,5 @@
// Inferno utils/5c/list.c
-// http://code.google.com/p/inferno-os/source/browse/utils/5c/list.c
+// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5c/list.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth at terzarima.net)
diff --git a/src/cmd/internal/obj/arm/obj5.go b/src/cmd/internal/obj/arm/obj5.go
index 9cf2f29..6e5390c 100644
--- a/src/cmd/internal/obj/arm/obj5.go
+++ b/src/cmd/internal/obj/arm/obj5.go
@@ -1,5 +1,5 @@
// Derived from Inferno utils/5c/swt.c
-// http://code.google.com/p/inferno-os/source/browse/utils/5c/swt.c
+// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5c/swt.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth at terzarima.net)
@@ -66,7 +66,7 @@ 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 ctxt.Goarm < 7 {
+ if obj.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)
@@ -175,7 +175,7 @@ func rewriteToUseGot(ctxt *obj.Link, p *obj.Prog) {
// We only care about global data: NAME_EXTERN means a global
// symbol in the Go sense, and p.Sym.Local is true for a few
// internally defined symbols.
- if p.From.Type == obj.TYPE_ADDR && p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local {
+ if p.From.Type == obj.TYPE_ADDR && p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local() {
// 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 {
@@ -202,12 +202,12 @@ func rewriteToUseGot(ctxt *obj.Link, p *obj.Prog) {
// MOVx sym, Ry becomes MOVW sym at GOT, R9; MOVx (R9), Ry
// MOVx Ry, sym becomes MOVW sym at GOT, R9; MOVx Ry, (R9)
// 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 {
+ if p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local() {
+ if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local() {
ctxt.Diag("cannot handle NAME_EXTERN on both sides in %v with -dynlink", p)
}
source = &p.From
- } else if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local {
+ } else if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local() {
source = &p.To
} else {
return
@@ -359,15 +359,14 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
if autosize == 0 && cursym.Text.Mark&LEAF == 0 {
if ctxt.Debugvlog != 0 {
- fmt.Fprintf(ctxt.Bso, "save suppressed in: %s\n", cursym.Name)
- ctxt.Bso.Flush()
+ ctxt.Logf("save suppressed in: %s\n", cursym.Name)
}
cursym.Text.Mark |= LEAF
}
if cursym.Text.Mark&LEAF != 0 {
- cursym.Leaf = true
+ cursym.Set(obj.AttrLeaf, true)
if autosize == 0 {
break
}
@@ -566,7 +565,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
p.To.Reg = REGTMP
p.To.Offset = 8 * 4 // offset of m.divmod
- /* MOV b,REGTMP */
+ /* MOV b, R8 */
p = obj.Appendp(ctxt, p)
p.As = AMOVW
p.Lineno = q1.Lineno
@@ -576,7 +575,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
p.From.Reg = q1.To.Reg
}
p.To.Type = obj.TYPE_REG
- p.To.Reg = REGTMP
+ p.To.Reg = REG_R8
p.To.Offset = 0
/* CALL appropriate */
@@ -627,7 +626,7 @@ func isfloatreg(a *obj.Addr) bool {
}
func softfloat(ctxt *obj.Link, cursym *obj.LSym) {
- if ctxt.Goarm > 5 {
+ if obj.GOARM > 5 {
return
}
@@ -669,7 +668,9 @@ func softfloat(ctxt *obj.Link, cursym *obj.LSym) {
ASQRTF,
ASQRTD,
AABSF,
- AABSD:
+ AABSD,
+ ANEGF,
+ ANEGD:
goto soft
default:
@@ -709,7 +710,7 @@ func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32) *obj.Prog {
p.From.Type = obj.TYPE_MEM
p.From.Reg = REGG
p.From.Offset = 2 * int64(ctxt.Arch.PtrSize) // G.stackguard0
- if ctxt.Cursym.Cfunc {
+ if ctxt.Cursym.CFunc() {
p.From.Offset = 3 * int64(ctxt.Arch.PtrSize) // G.stackguard1
}
p.To.Type = obj.TYPE_REG
@@ -802,12 +803,24 @@ func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32) *obj.Prog {
for last = ctxt.Cursym.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.As = obj.ANOP
spfix.Spadj = -framesize
+ pcdata := obj.Appendp(ctxt, spfix)
+ pcdata.Lineno = ctxt.Cursym.Text.Lineno
+ pcdata.Mode = ctxt.Cursym.Text.Mode
+ pcdata.As = obj.APCDATA
+ pcdata.From.Type = obj.TYPE_CONST
+ pcdata.From.Offset = obj.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, spfix)
+ movw := obj.Appendp(ctxt, pcdata)
movw.As = AMOVW
movw.From.Type = obj.TYPE_REG
movw.From.Reg = REGLINK
@@ -822,7 +835,7 @@ func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32) *obj.Prog {
call.To.Type = obj.TYPE_BRANCH
morestack := "runtime.morestack"
switch {
- case ctxt.Cursym.Cfunc:
+ case ctxt.Cursym.CFunc():
morestack = "runtime.morestackc"
case ctxt.Cursym.Text.From3.Offset&obj.NEEDCTXT == 0:
morestack = "runtime.morestack_noctxt"
diff --git a/src/cmd/internal/obj/arm64/a.out.go b/src/cmd/internal/obj/arm64/a.out.go
index ab05894..bed129d89 100644
--- a/src/cmd/internal/obj/arm64/a.out.go
+++ b/src/cmd/internal/obj/arm64/a.out.go
@@ -229,14 +229,10 @@ const (
REGZERO = REG_R31
REGSP = REG_RSP
- FREGRET = REG_F0
- FREGMIN = REG_F7 // first register variable
- FREGMAX = REG_F26 // last register variable for 7g only
- FREGEXT = REG_F26 // first external register
- FREGZERO = REG_F28 // both float and double
- FREGHALF = REG_F29 // double
- FREGONE = REG_F30 // double
- FREGTWO = REG_F31 // double
+ FREGRET = REG_F0
+ FREGMIN = REG_F7 // first register variable
+ FREGMAX = REG_F26 // last register variable for 7g only
+ FREGEXT = REG_F26 // first external register
)
const (
@@ -274,6 +270,7 @@ const (
C_ADDCON // 12-bit unsigned, shifted left by 0 or 12
C_MOVCON // generated by a 16-bit constant, optionally inverted and/or shifted by multiple of 16
C_BITCON // bitfield and logical immediate masks
+ C_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
@@ -713,3 +710,10 @@ const (
AB = obj.AJMP
ABL = obj.ACALL
)
+
+const (
+ // shift types
+ SHIFT_LL = 0 << 22
+ SHIFT_LR = 1 << 22
+ SHIFT_AR = 2 << 22
+)
diff --git a/src/cmd/internal/obj/arm64/anames7.go b/src/cmd/internal/obj/arm64/anames7.go
index eb348d4..d55b34f 100644
--- a/src/cmd/internal/obj/arm64/anames7.go
+++ b/src/cmd/internal/obj/arm64/anames7.go
@@ -20,6 +20,7 @@ var cnames7 = []string{
"ADDCON",
"MOVCON",
"BITCON",
+ "ABCON0",
"ABCON",
"MBCON",
"LCON",
diff --git a/src/cmd/internal/obj/arm64/asm7.go b/src/cmd/internal/obj/arm64/asm7.go
index 28bebaa..3409957 100644
--- a/src/cmd/internal/obj/arm64/asm7.go
+++ b/src/cmd/internal/obj/arm64/asm7.go
@@ -39,7 +39,7 @@ import (
)
const (
- FuncAlign = 16
+ funcAlign = 16
)
const (
@@ -161,10 +161,12 @@ var optab = []Optab{
{AADD, C_ADDCON, C_RSP, C_RSP, 2, 4, 0, 0, 0},
{AADD, C_ADDCON, C_NONE, C_RSP, 2, 4, 0, 0, 0},
{ACMP, C_ADDCON, C_RSP, C_NONE, 2, 4, 0, 0, 0},
- // TODO: these don't work properly.
- // {AADD, C_MBCON, C_RSP, C_RSP, 2, 4, 0, 0, 0},
- // {AADD, C_MBCON, C_NONE, C_RSP, 2, 4, 0, 0, 0},
- // {ACMP, C_MBCON, C_RSP, C_NONE, 2, 4, 0, 0, 0},
+ {AADD, C_MOVCON, C_RSP, C_RSP, 62, 8, 0, 0, 0},
+ {AADD, C_MOVCON, C_NONE, C_RSP, 62, 8, 0, 0, 0},
+ {ACMP, C_MOVCON, C_RSP, C_NONE, 62, 8, 0, 0, 0},
+ {AADD, C_BITCON, C_RSP, C_RSP, 62, 8, 0, 0, 0},
+ {AADD, C_BITCON, C_NONE, C_RSP, 62, 8, 0, 0, 0},
+ {ACMP, C_BITCON, C_RSP, C_NONE, 62, 8, 0, 0, 0},
{AADD, C_VCON, C_RSP, C_RSP, 13, 8, 0, LFROM, 0},
{AADD, C_VCON, C_NONE, C_RSP, 13, 8, 0, LFROM, 0},
{ACMP, C_VCON, C_REG, C_NONE, 13, 8, 0, LFROM, 0},
@@ -188,11 +190,14 @@ 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},
- // TODO: these don't work properly.
- // {AAND, C_BITCON, C_REG, C_REG, 53, 4, 0, 0, 0},
- // {AAND, C_BITCON, C_NONE, C_REG, 53, 4, 0, 0, 0},
- // {ABIC, C_BITCON, C_REG, C_REG, 53, 4, 0, 0, 0},
- // {ABIC, C_BITCON, C_NONE, C_REG, 53, 4, 0, 0, 0},
+ {AAND, C_BITCON, C_REG, C_REG, 53, 4, 0, 0, 0},
+ {AAND, C_BITCON, C_NONE, C_REG, 53, 4, 0, 0, 0},
+ {ABIC, C_BITCON, C_REG, C_REG, 53, 4, 0, 0, 0},
+ {ABIC, C_BITCON, C_NONE, C_REG, 53, 4, 0, 0, 0},
+ {AAND, C_MOVCON, C_REG, C_REG, 62, 8, 0, 0, 0},
+ {AAND, C_MOVCON, C_NONE, C_REG, 62, 8, 0, 0, 0},
+ {ABIC, C_MOVCON, C_REG, C_REG, 62, 8, 0, 0, 0},
+ {ABIC, C_MOVCON, C_NONE, C_REG, 62, 8, 0, 0, 0},
{AAND, C_VCON, C_REG, C_REG, 28, 8, 0, LFROM, 0},
{AAND, C_VCON, C_NONE, C_REG, 28, 8, 0, LFROM, 0},
{ABIC, C_VCON, C_REG, C_REG, 28, 8, 0, LFROM, 0},
@@ -216,8 +221,8 @@ var optab = []Optab{
// TODO: these don't work properly.
// { AMOVW, C_ADDCON, C_NONE, C_REG, 2, 4, 0 , 0},
// { AMOVD, C_ADDCON, C_NONE, C_REG, 2, 4, 0 , 0},
- // { AMOVW, C_BITCON, C_NONE, C_REG, 53, 4, 0 , 0},
- // { AMOVD, C_BITCON, C_NONE, C_REG, 53, 4, 0 , 0},
+ {AMOVW, C_BITCON, C_NONE, C_REG, 32, 4, 0, 0, 0},
+ {AMOVD, C_BITCON, C_NONE, C_REG, 32, 4, 0, 0, 0},
{AMOVK, C_VCON, C_NONE, C_REG, 33, 4, 0, 0, 0},
{AMOVD, C_AACON, C_NONE, C_REG, 4, 4, REGFROM, 0, 0},
@@ -461,6 +466,10 @@ var optab = []Optab{
{AFMOVD, C_FREG, C_NONE, C_FREG, 54, 4, 0, 0, 0},
{AFCVTZSD, C_FREG, C_NONE, C_REG, 29, 4, 0, 0, 0},
{ASCVTFD, C_REG, C_NONE, C_FREG, 29, 4, 0, 0, 0},
+ {AFMOVS, C_REG, C_NONE, C_FREG, 29, 4, 0, 0, 0},
+ {AFMOVS, C_FREG, C_NONE, C_REG, 29, 4, 0, 0, 0},
+ {AFMOVD, C_REG, C_NONE, C_FREG, 29, 4, 0, 0, 0},
+ {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},
@@ -580,7 +589,7 @@ func span7(ctxt *obj.Link, cursym *obj.LSym) {
*/
for bflag != 0 {
if ctxt.Debugvlog != 0 {
- fmt.Fprintf(ctxt.Bso, "%5.2f span1\n", obj.Cputime())
+ ctxt.Logf("%5.2f span1\n", obj.Cputime())
}
bflag = 0
c = 0
@@ -592,7 +601,7 @@ func span7(ctxt *obj.Link, cursym *obj.LSym) {
o = oplook(ctxt, p)
/* very large branches */
- if o.type_ == 7 && p.Pcond != nil {
+ if (o.type_ == 7 || o.type_ == 39) && p.Pcond != nil { // 7: BEQ and like, 39: CBZ and like
otxt := p.Pcond.Pc - c
if otxt <= -(1<<18)+10 || otxt >= (1<<18)-10 {
q := ctxt.NewProg()
@@ -624,7 +633,7 @@ func span7(ctxt *obj.Link, cursym *obj.LSym) {
}
}
- c += -c & (FuncAlign - 1)
+ c += -c & (funcAlign - 1)
cursym.Size = c
/*
@@ -715,15 +724,18 @@ func flushpool(ctxt *obj.Link, p *obj.Prog, skip int) {
*/
func addpool(ctxt *obj.Link, p *obj.Prog, a *obj.Addr) {
c := aclass(ctxt, a)
+ lit := ctxt.Instoffset
t := *ctxt.NewProg()
t.As = AWORD
sz := 4
- // MOVW foo(SB), R is actually
- // MOV addr, REGTEMP
- // MOVW REGTEMP, R
+ // MOVD foo(SB), R is actually
+ // 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 {
+ if p.As == AMOVD || c == C_ADDR || c == 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
}
@@ -740,29 +752,12 @@ func addpool(ctxt *obj.Link, p *obj.Prog, a *obj.Addr) {
t.To.Type = a.Type
t.To.Name = a.Name
- /* This is here to work around a bug where we generate negative
- operands that match C_MOVCON, but we use them with
- instructions that only accept unsigned immediates. This
- will cause oplook to return a variant of the instruction
- that loads the negative constant from memory, rather than
- using the immediate form. Because of that load, we get here,
- so we need to know what to do with C_MOVCON.
-
- The correct fix is to use the "negation" instruction variant,
- e.g. CMN $1, R instead of CMP $-1, R, or SUB $1, R instead
- of ADD $-1, R. */
- case C_MOVCON,
-
- /* This is here because MOV uint12<<12, R is disabled in optab.
- Because of this, we need to load the constant from memory. */
- C_ADDCON,
-
- /* These are here because they are disabled in optab.
- Because of this, we need to load the constant from memory. */
- C_BITCON,
- C_ABCON,
- C_MBCON,
- C_PSAUTO,
+ /* This is here because MOV uint12<<12, R is disabled in optab.
+ Because of this, we need to load the constant from memory. */
+ case C_ADDCON:
+ fallthrough
+
+ case C_PSAUTO,
C_PPAUTO,
C_UAUTO4K,
C_UAUTO8K,
@@ -790,7 +785,7 @@ func addpool(ctxt *obj.Link, p *obj.Prog, a *obj.Addr) {
}
t.To.Type = obj.TYPE_CONST
- t.To.Offset = ctxt.Instoffset
+ t.To.Offset = lit
break
}
@@ -811,7 +806,7 @@ func addpool(ctxt *obj.Link, p *obj.Prog, a *obj.Addr) {
ctxt.Elitrl.Link = q
}
ctxt.Elitrl = q
- pool.size = -pool.size & (FuncAlign - 1)
+ pool.size = -pool.size & (funcAlign - 1)
pool.size += uint32(sz)
p.Pcond = q
}
@@ -844,11 +839,137 @@ func isaddcon(v int64) bool {
return v <= 0xFFF
}
-func isbitcon(v uint64) bool {
- /* fancy bimm32 or bimm64? */
- // TODO(aram):
- return false
- // return findmask(v) != nil || (v>>32) == 0 && findmask(v|(v<<32)) != nil
+// isbitcon returns whether a constant can be encoded into a logical instruction.
+// bitcon has a binary form of repetition of a bit sequence of length 2, 4, 8, 16, 32, or 64,
+// which itself is a rotate (w.r.t. the length of the unit) of a sequence of ones.
+// special cases: 0 and -1 are not bitcon.
+// this function needs to run against virtually all the constants, so it needs to be fast.
+// for this reason, bitcon testing and bitcon encoding are separate functions.
+func isbitcon(x uint64) bool {
+ if x == 1<<64-1 || x == 0 {
+ return false
+ }
+ // determine the period and sign-extend a unit to 64 bits
+ switch {
+ case x != x>>32|x<<32:
+ // period is 64
+ // nothing to do
+ case x != x>>16|x<<48:
+ // period is 32
+ x = uint64(int64(int32(x)))
+ case x != x>>8|x<<56:
+ // period is 16
+ x = uint64(int64(int16(x)))
+ case x != x>>4|x<<60:
+ // period is 8
+ x = uint64(int64(int8(x)))
+ default:
+ // period is 4 or 2, always true
+ // 0001, 0010, 0100, 1000 -- 0001 rotate
+ // 0011, 0110, 1100, 1001 -- 0011 rotate
+ // 0111, 1011, 1101, 1110 -- 0111 rotate
+ // 0101, 1010 -- 01 rotate, repeat
+ return true
+ }
+ return sequenceOfOnes(x) || sequenceOfOnes(^x)
+}
+
+// sequenceOfOnes tests whether a constant is a sequence of ones in binary, with leading and trailing zeros
+func sequenceOfOnes(x uint64) bool {
+ y := x & -x // lowest set bit of x. x is good iff x+y is a power of 2
+ y += x
+ return (y-1)&y == 0
+}
+
+// bitconEncode returns the encoding of a bitcon used in logical instructions
+// x is known to be a bitcon
+// a bitcon is a sequence of n ones at low bits (i.e. 1<<n-1), right rotated
+// by R bits, and repeated with period of 64, 32, 16, 8, 4, or 2.
+// it is encoded in logical instructions with 3 bitfields
+// N (1 bit) : R (6 bits) : S (6 bits), where
+// N=1 -- period=64
+// N=0, S=0xxxxx -- period=32
+// N=0, S=10xxxx -- period=16
+// N=0, S=110xxx -- period=8
+// N=0, S=1110xx -- period=4
+// N=0, S=11110x -- period=2
+// R is the shift amount, low bits of S = n-1
+func bitconEncode(x uint64, mode int) uint32 {
+ var period uint32
+ // determine the period and sign-extend a unit to 64 bits
+ switch {
+ case x != x>>32|x<<32:
+ period = 64
+ case x != x>>16|x<<48:
+ period = 32
+ x = uint64(int64(int32(x)))
+ case x != x>>8|x<<56:
+ period = 16
+ x = uint64(int64(int16(x)))
+ case x != x>>4|x<<60:
+ period = 8
+ x = uint64(int64(int8(x)))
+ case x != x>>2|x<<62:
+ period = 4
+ x = uint64(int64(x<<60) >> 60)
+ default:
+ period = 2
+ x = uint64(int64(x<<62) >> 62)
+ }
+ neg := false
+ if int64(x) < 0 {
+ x = ^x
+ neg = true
+ }
+ y := x & -x // lowest set bit of x.
+ s := log2(y)
+ n := log2(x+y) - s // x (or ^x) is a sequence of n ones left shifted by s bits
+ if neg {
+ // ^x is a sequence of n ones left shifted by s bits
+ // adjust n, s for x
+ s = n + s
+ n = period - n
+ }
+
+ N := uint32(0)
+ if mode == 64 && period == 64 {
+ N = 1
+ }
+ R := (period - s) & (period - 1) & uint32(mode-1) // shift amount of right rotate
+ S := (n - 1) | 63&^(period<<1-1) // low bits = #ones - 1, high bits encodes period
+ return N<<22 | R<<16 | S<<10
+}
+
+func log2(x uint64) uint32 {
+ if x == 0 {
+ panic("log2 of 0")
+ }
+ n := uint32(0)
+ if x >= 1<<32 {
+ x >>= 32
+ n += 32
+ }
+ if x >= 1<<16 {
+ x >>= 16
+ n += 16
+ }
+ if x >= 1<<8 {
+ x >>= 8
+ n += 8
+ }
+ if x >= 1<<4 {
+ x >>= 4
+ n += 4
+ }
+ if x >= 1<<2 {
+ x >>= 2
+ n += 2
+ }
+ if x >= 1<<1 {
+ x >>= 1
+ n += 1
+ }
+ return n
}
func autoclass(l int64) int {
@@ -1019,6 +1140,9 @@ func aclass(ctxt *obj.Link, a *obj.Addr) int {
}
if isaddcon(v) {
if v <= 0xFFF {
+ if isbitcon(uint64(v)) {
+ return C_ABCON0
+ }
return C_ADDCON0
}
if isbitcon(uint64(v)) {
@@ -1085,6 +1209,10 @@ func aclass(ctxt *obj.Link, a *obj.Addr) int {
return C_GOK
}
+func oclass(a *obj.Addr) int {
+ return int(a.Class) - 1
+}
+
func oplook(ctxt *obj.Link, p *obj.Prog) *Optab {
a1 := int(p.Optab)
if a1 != 0 {
@@ -1110,7 +1238,7 @@ func oplook(ctxt *obj.Link, p *obj.Prog) *Optab {
}
if false {
- fmt.Printf("oplook %v %d %d %d\n", obj.Aconv(p.As), a1, a2, a3)
+ fmt.Printf("oplook %v %d %d %d\n", p.As, a1, a2, a3)
fmt.Printf("\t\t%d %d\n", p.From.Type, p.To.Type)
}
@@ -1151,17 +1279,17 @@ func cmp(a int, b int) bool {
}
case C_ADDCON0:
- if b == C_ZCON {
+ if b == C_ZCON || b == C_ABCON0 {
return true
}
case C_ADDCON:
- if b == C_ZCON || b == C_ADDCON0 || b == C_ABCON {
+ if b == C_ZCON || b == C_ABCON0 || b == C_ADDCON0 || b == C_ABCON {
return true
}
case C_BITCON:
- if b == C_ABCON || b == C_MBCON {
+ if b == C_ABCON0 || b == C_ABCON || b == C_MBCON {
return true
}
@@ -1171,7 +1299,7 @@ func cmp(a int, b int) bool {
}
case C_LCON:
- if b == C_ZCON || b == C_BITCON || b == C_ADDCON || b == C_ADDCON0 || b == C_ABCON || b == C_MBCON || b == C_MOVCON {
+ if b == C_ZCON || b == C_BITCON || b == C_ADDCON || b == C_ADDCON0 || b == C_ABCON || b == C_ABCON0 || b == C_MBCON || b == C_MOVCON {
return true
}
@@ -1336,7 +1464,7 @@ func buildop(ctxt *obj.Link) {
oprangeset(r, t)
switch r {
default:
- ctxt.Diag("unknown op in build: %v", obj.Aconv(r))
+ ctxt.Diag("unknown op in build: %v", r)
log.Fatalf("bad code")
case AADD:
@@ -1706,6 +1834,8 @@ func buildop(ctxt *obj.Link) {
oprangeset(ALDXRW, t)
case ALDAXR:
+ oprangeset(ALDAXRB, t)
+ oprangeset(ALDAXRH, t)
oprangeset(ALDAXRW, t)
case ALDXP:
@@ -1720,6 +1850,8 @@ func buildop(ctxt *obj.Link) {
oprangeset(ASTXRW, t)
case ASTLXR:
+ oprangeset(ASTLXRB, t)
+ oprangeset(ASTLXRH, t)
oprangeset(ASTLXRW, t)
case ASTXP:
@@ -2121,12 +2253,13 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
case 20: /* movT R,O(R) -> strT */
v := int32(regoff(ctxt, &p.To))
+ sz := int32(1 << uint(movesize(p.As)))
r := int(p.To.Reg)
if r == 0 {
r = int(o.param)
}
- if v < 0 { /* unscaled 9-bit signed */
+ if v < 0 || v%sz != 0 { /* unscaled 9-bit signed */
o1 = olsr9s(ctxt, int32(opstr9(ctxt, p.As)), v, r, int(p.From.Reg))
} else {
v = int32(offsetshift(ctxt, int64(v), int(o.a3)))
@@ -2135,16 +2268,16 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
case 21: /* movT O(R),R -> ldrT */
v := int32(regoff(ctxt, &p.From))
+ sz := int32(1 << uint(movesize(p.As)))
r := int(p.From.Reg)
if r == 0 {
r = int(o.param)
}
- if v < 0 { /* unscaled 9-bit signed */
+ if v < 0 || v%sz != 0 { /* unscaled 9-bit signed */
o1 = olsr9s(ctxt, int32(opldr9(ctxt, p.As)), v, r, int(p.To.Reg))
} else {
v = int32(offsetshift(ctxt, int64(v), int(o.a1)))
-
//print("offset=%lld v=%ld a1=%d\n", instoffset, v, o->a1);
o1 = olsr12u(ctxt, int32(opldr12(ctxt, p.As)), v, r, int(p.To.Reg))
}
@@ -2247,15 +2380,27 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
o2 |= uint32(p.To.Reg & 31)
case 29: /* op Rn, Rd */
- o1 = oprrr(ctxt, p.As)
-
+ fc := aclass(ctxt, &p.From)
+ tc := aclass(ctxt, &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)
+ if p.As == AFMOVD {
+ o1 |= 1<<31 | 1<<22 // 64-bit
+ }
+ if fc == C_REG || fc == C_ZCON {
+ o1 |= 1 << 16 // FMOV Rx, Fy
+ }
+ } else {
+ o1 = oprrr(ctxt, p.As)
+ }
o1 |= uint32(p.From.Reg&31)<<5 | uint32(p.To.Reg&31)
case 30: /* movT R,L(R) -> strT */
s := movesize(o.as)
if s < 0 {
- ctxt.Diag("unexpected long move, op %v tab %v\n%v", obj.Aconv(p.As), obj.Aconv(o.as), p)
+ 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 {
@@ -2282,7 +2427,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
s := movesize(o.as)
if s < 0 {
- ctxt.Diag("unexpected long move, op %v tab %v\n%v", obj.Aconv(p.As), obj.Aconv(o.as), p)
+ 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 {
@@ -2306,34 +2451,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
o2 = olsr12u(ctxt, int32(opldr12(ctxt, p.As)), ((v-hi)>>uint(s))&0xFFF, REGTMP, int(p.To.Reg))
case 32: /* mov $con, R -> movz/movn */
- r := 32
-
- if p.As == AMOVD {
- r = 64
- }
- d := p.From.Offset
- s := movcon(d)
- if s < 0 || s >= r {
- d = ^d
- s = movcon(d)
- if s < 0 || s >= r {
- ctxt.Diag("impossible move wide: %#x\n%v", uint64(p.From.Offset), p)
- }
- if p.As == AMOVD {
- o1 = opirr(ctxt, AMOVN)
- } else {
- o1 = opirr(ctxt, AMOVNW)
- }
- } else {
- if p.As == AMOVD {
- o1 = opirr(ctxt, AMOVZ)
- } else {
- o1 = opirr(ctxt, AMOVZW)
- }
- }
-
- rt := int(p.To.Reg)
- o1 |= uint32((((d >> uint(s*16)) & 0xFFFF) << 5) | int64((uint32(s)&3)<<21) | int64(rt&31))
+ o1 = omovconst(ctxt, p.As, p, &p.From, int(p.To.Reg))
case 33: /* movk $uimm16 << pos */
o1 = opirr(ctxt, p.As)
@@ -2540,7 +2658,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
o1 = opbfm(ctxt, AUBFMW, 0, 15, rf, rt)
default:
- ctxt.Diag("bad sxt %v", obj.Aconv(as))
+ ctxt.Diag("bad sxt %v", as)
break
}
@@ -2601,8 +2719,26 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
o1 |= uint32((p.From.Offset & 0x7F) << 5)
- case 53: /* and/or/eor/bic/... $bimmN, Rn, Rd -> op (N,r,s), Rn, Rd */
- ctxt.Diag("bitmask immediate not implemented\n%v", p)
+ case 53: /* and/or/eor/bic/... $bitcon, Rn, Rd */
+ a := p.As
+ rt := int(p.To.Reg)
+ r := int(p.Reg)
+ if r == 0 {
+ r = rt
+ }
+ mode := 64
+ v := uint64(p.From.Offset)
+ switch p.As {
+ case AANDW, AORRW, AEORW, AANDSW:
+ mode = 32
+ case ABIC, AORN, AEON, ABICS:
+ v = ^v
+ case ABICW, AORNW, AEONW, ABICSW:
+ v = ^v
+ mode = 32
+ }
+ o1 = opirr(ctxt, a)
+ o1 |= bitconEncode(v, mode) | uint32(r&31)<<5 | uint32(rt&31)
case 54: /* floating point arith */
o1 = oprrr(ctxt, p.As)
@@ -2694,6 +2830,31 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
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)
+ }
+ o1 = omovconst(ctxt, AMOVD, p, &p.From, REGTMP)
+
+ rt := int(p.To.Reg)
+ if p.To.Type == obj.TYPE_NONE {
+ rt = REGZERO
+ }
+ r := int(p.Reg)
+ if r == 0 {
+ r = rt
+ }
+ if p.To.Type != obj.TYPE_NONE && (p.To.Reg == REGSP || r == REGSP) {
+ o2 = opxrrr(ctxt, p.As)
+ o2 |= REGTMP & 31 << 16
+ o2 |= LSL0_64
+ } else {
+ o2 = oprrr(ctxt, p.As)
+ o2 |= REGTMP & 31 << 16 /* shift is 0 */
+ }
+ o2 |= uint32(r&31) << 5
+ o2 |= uint32(rt & 31)
+
/* reloc ops */
case 64: /* movT R,addr -> adrp + add + movT R, (REGTMP) */
o1 = ADR(1, 0, REGTMP)
@@ -3330,7 +3491,7 @@ func oprrr(ctxt *obj.Link, a obj.As) uint32 {
return FPOP1S(0, 0, 3, 5)
}
- ctxt.Diag("bad rrr %d %v", a, obj.Aconv(a))
+ ctxt.Diag("bad rrr %d %v", a, a)
prasm(ctxt.Curp)
return 0
}
@@ -3374,28 +3535,28 @@ func opirr(ctxt *obj.Link, a obj.As) uint32 {
return 1<<31 | 0x10<<24
/* op $bimm, Rn, Rd */
- case AAND:
+ case AAND, ABIC:
return S64 | 0<<29 | 0x24<<23
- case AANDW:
+ case AANDW, ABICW:
return S32 | 0<<29 | 0x24<<23 | 0<<22
- case AORR:
+ case AORR, AORN:
return S64 | 1<<29 | 0x24<<23
- case AORRW:
+ case AORRW, AORNW:
return S32 | 1<<29 | 0x24<<23 | 0<<22
- case AEOR:
+ case AEOR, AEON:
return S64 | 2<<29 | 0x24<<23
- case AEORW:
+ case AEORW, AEONW:
return S32 | 2<<29 | 0x24<<23 | 0<<22
- case AANDS:
+ case AANDS, ABICS:
return S64 | 3<<29 | 0x24<<23
- case AANDSW:
+ case AANDSW, ABICSW:
return S32 | 3<<29 | 0x24<<23 | 0<<22
case AASR:
@@ -3517,7 +3678,7 @@ func opirr(ctxt *obj.Link, a obj.As) uint32 {
return SYSOP(0, 0, 3, 2, 0, 0, 0x1F)
}
- ctxt.Diag("bad irr %v", obj.Aconv(a))
+ ctxt.Diag("bad irr %v", a)
prasm(ctxt.Curp)
return 0
}
@@ -3593,7 +3754,7 @@ 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", obj.Aconv(a), ctxt.Curp)
+ ctxt.Diag("bad opxrrr %v\n%v", a, ctxt.Curp)
return 0
}
@@ -3627,7 +3788,7 @@ func opimm(ctxt *obj.Link, a obj.As) uint32 {
return SYSOP(0, 0, 3, 3, 0, 2, 0x1F)
}
- ctxt.Diag("bad imm %v", obj.Aconv(a))
+ ctxt.Diag("bad imm %v", a)
prasm(ctxt.Curp)
return 0
}
@@ -3707,12 +3868,11 @@ func opbra(ctxt *obj.Link, a obj.As) uint32 {
case AB:
return 0<<31 | 5<<26 /* imm26 */
- case obj.ADUFFZERO,
- ABL:
+ case obj.ADUFFZERO, obj.ADUFFCOPY, ABL:
return 1<<31 | 5<<26
}
- ctxt.Diag("bad bra %v", obj.Aconv(a))
+ ctxt.Diag("bad bra %v", a)
prasm(ctxt.Curp)
return 0
}
@@ -3729,7 +3889,7 @@ func opbrr(ctxt *obj.Link, a obj.As) uint32 {
return OPBLR(2) /* RET */
}
- ctxt.Diag("bad brr %v", obj.Aconv(a))
+ ctxt.Diag("bad brr %v", a)
prasm(ctxt.Curp)
return 0
}
@@ -3761,7 +3921,7 @@ func op0(ctxt *obj.Link, a obj.As) uint32 {
return SYSHINT(5)
}
- ctxt.Diag("bad op0 %v", obj.Aconv(a))
+ ctxt.Diag("bad op0 %v", a)
prasm(ctxt.Curp)
return 0
}
@@ -3826,7 +3986,7 @@ 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", obj.Aconv(a), ctxt.Curp)
+ ctxt.Diag("bad opload %v\n%v", a, ctxt.Curp)
return 0
}
@@ -3893,7 +4053,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", obj.Aconv(a), ctxt.Curp)
+ ctxt.Diag("bad opstore %v\n%v", a, ctxt.Curp)
return 0
}
@@ -3941,7 +4101,7 @@ func opldr12(ctxt *obj.Link, a obj.As) uint32 {
return LDSTR12U(3, 1, 1)
}
- ctxt.Diag("bad opldr12 %v\n%v", obj.Aconv(a), ctxt.Curp)
+ ctxt.Diag("bad opldr12 %v\n%v", a, ctxt.Curp)
return 0
}
@@ -3992,7 +4152,7 @@ func opldr9(ctxt *obj.Link, a obj.As) uint32 {
return LDSTR9S(3, 1, 1)
}
- ctxt.Diag("bad opldr9 %v\n%v", obj.Aconv(a), ctxt.Curp)
+ ctxt.Diag("bad opldr9 %v\n%v", a, ctxt.Curp)
return 0
}
@@ -4024,7 +4184,7 @@ 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", obj.Aconv(a), ctxt.Curp)
+ ctxt.Diag("bad opldr %v\n%v", a, ctxt.Curp)
return 0
}
@@ -4056,7 +4216,7 @@ func omovlit(ctxt *obj.Link, as obj.As, p *obj.Prog, a *obj.Addr, dr int) uint32
var o1 int32
if p.Pcond == nil { /* not in literal pool */
aclass(ctxt, a)
- fmt.Fprintf(ctxt.Bso, "omovlit add %d (%#x)\n", ctxt.Instoffset, uint64(ctxt.Instoffset))
+ ctxt.Logf("omovlit add %d (%#x)\n", ctxt.Instoffset, uint64(ctxt.Instoffset))
/* TODO: could be clever, and use general constant builder */
o1 = int32(opirr(ctxt, AADD))
@@ -4100,6 +4260,52 @@ func omovlit(ctxt *obj.Link, as obj.As, p *obj.Prog, a *obj.Addr, dr int) uint32
return uint32(o1)
}
+// 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 {
+ // or $bitcon, REGZERO, rt
+ mode := 64
+ var as1 obj.As
+ switch as {
+ case AMOVW:
+ as1 = AORRW
+ mode = 32
+ case AMOVD:
+ as1 = AORR
+ }
+ o1 = opirr(ctxt, as1)
+ o1 |= bitconEncode(uint64(a.Offset), mode) | uint32(REGZERO&31)<<5 | uint32(rt&31)
+ return o1
+ }
+
+ r := 32
+ if as == AMOVD {
+ r = 64
+ }
+ d := a.Offset
+ s := movcon(d)
+ if s < 0 || s >= r {
+ d = ^d
+ s = movcon(d)
+ if s < 0 || s >= r {
+ ctxt.Diag("impossible move wide: %#x\n%v", uint64(a.Offset), p)
+ }
+ if as == AMOVD {
+ o1 = opirr(ctxt, AMOVN)
+ } else {
+ o1 = opirr(ctxt, AMOVNW)
+ }
+ } else {
+ if as == AMOVD {
+ o1 = opirr(ctxt, AMOVZ)
+ } else {
+ o1 = opirr(ctxt, 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)
diff --git a/src/cmd/internal/obj/arm64/asm_test.go b/src/cmd/internal/obj/arm64/asm_test.go
new file mode 100644
index 0000000..369c48f
--- /dev/null
+++ b/src/cmd/internal/obj/arm64/asm_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 arm64
+
+import (
+ "bytes"
+ "fmt"
+ "internal/testenv"
+ "io/ioutil"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "testing"
+)
+
+// TestLarge generates a very large file to verify that large
+// program builds successfully, in particular, too-far
+// conditional branches are fixed.
+func TestLarge(t *testing.T) {
+ if testing.Short() {
+ t.Skip("Skip in short mode")
+ }
+ testenv.MustHaveGoBuild(t)
+
+ dir, err := ioutil.TempDir("", "testlarge")
+ if err != nil {
+ t.Fatalf("could not create directory: %v", err)
+ }
+ defer os.RemoveAll(dir)
+
+ // generate a very large function
+ buf := bytes.NewBuffer(make([]byte, 0, 7000000))
+ gen(buf)
+
+ tmpfile := filepath.Join(dir, "x.s")
+ err = ioutil.WriteFile(tmpfile, buf.Bytes(), 0644)
+ if err != nil {
+ t.Fatalf("can't write output: %v\n", err)
+ }
+
+ // build generated file
+ cmd := exec.Command(testenv.GoToolPath(t), "tool", "asm", "-o", filepath.Join(dir, "x.o"), tmpfile)
+ cmd.Env = []string{"GOARCH=arm64", "GOOS=linux"}
+ out, err := cmd.CombinedOutput()
+ if err != nil {
+ t.Errorf("Build failed: %v, output: %s", err, out)
+ }
+}
+
+// gen generates a very large program, with a very far conditional branch.
+func gen(buf *bytes.Buffer) {
+ fmt.Fprintln(buf, "TEXT f(SB),0,$0-0")
+ fmt.Fprintln(buf, "CBZ R0, label")
+ fmt.Fprintln(buf, "BEQ label")
+ for i := 0; i < 1<<19; i++ {
+ fmt.Fprintln(buf, "MOVD R0, R1")
+ }
+ fmt.Fprintln(buf, "label:")
+ fmt.Fprintln(buf, "RET")
+}
diff --git a/src/cmd/internal/obj/arm64/obj7.go b/src/cmd/internal/obj/arm64/obj7.go
index ffa1b41..3ea78cd 100644
--- a/src/cmd/internal/obj/arm64/obj7.go
+++ b/src/cmd/internal/obj/arm64/obj7.go
@@ -57,7 +57,7 @@ func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32) *obj.Prog {
p.From.Type = obj.TYPE_MEM
p.From.Reg = REGG
p.From.Offset = 2 * int64(ctxt.Arch.PtrSize) // G.stackguard0
- if ctxt.Cursym.Cfunc {
+ if ctxt.Cursym.CFunc() {
p.From.Offset = 3 * int64(ctxt.Arch.PtrSize) // G.stackguard1
}
p.To.Type = obj.TYPE_REG
@@ -161,12 +161,24 @@ func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32) *obj.Prog {
for last = ctxt.Cursym.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.As = obj.ANOP
spfix.Spadj = -framesize
+ pcdata := obj.Appendp(ctxt, spfix)
+ pcdata.Lineno = ctxt.Cursym.Text.Lineno
+ pcdata.Mode = ctxt.Cursym.Text.Mode
+ pcdata.As = obj.APCDATA
+ pcdata.From.Type = obj.TYPE_CONST
+ pcdata.From.Offset = obj.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, spfix)
+ movlr := obj.Appendp(ctxt, pcdata)
movlr.As = AMOVD
movlr.From.Type = obj.TYPE_REG
movlr.From.Reg = REGLINK
@@ -193,7 +205,7 @@ func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32) *obj.Prog {
call.To.Type = obj.TYPE_BRANCH
morestack := "runtime.morestack"
switch {
- case ctxt.Cursym.Cfunc:
+ case ctxt.Cursym.CFunc():
morestack = "runtime.morestackc"
case ctxt.Cursym.Text.From3.Offset&obj.NEEDCTXT == 0:
morestack = "runtime.morestack_noctxt"
@@ -250,12 +262,17 @@ func progedit(ctxt *obj.Link, p *obj.Prog) {
if p.From.Type == obj.TYPE_FCONST {
f32 := float32(p.From.Val.(float64))
i32 := math.Float32bits(f32)
+ if i32 == 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.Local = true
+ p.From.Sym.Set(obj.AttrLocal, true)
p.From.Name = obj.NAME_EXTERN
p.From.Offset = 0
}
@@ -263,12 +280,17 @@ func progedit(ctxt *obj.Link, p *obj.Prog) {
case AFMOVD:
if p.From.Type == obj.TYPE_FCONST {
i64 := math.Float64bits(p.From.Val.(float64))
+ if i64 == 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.Local = true
+ p.From.Sym.Set(obj.AttrLocal, true)
p.From.Name = obj.NAME_EXTERN
p.From.Offset = 0
}
@@ -279,20 +301,30 @@ func progedit(ctxt *obj.Link, p *obj.Prog) {
// Rewrite negative immediates as positive immediates with
// complementary instruction.
switch p.As {
- case AADD,
- AADDW,
- ASUB,
- ASUBW,
- ACMP,
- ACMPW,
- ACMN,
- ACMNW:
- if p.From.Type == obj.NAME_EXTERN && p.From.Offset < 0 {
+ case AADD, ASUB, ACMP, ACMN:
+ if p.From.Type == obj.TYPE_CONST && p.From.Offset < 0 && p.From.Offset != -1<<63 {
+ p.From.Offset = -p.From.Offset
+ p.As = complements[p.As]
+ }
+ case AADDW, ASUBW, ACMPW, ACMNW:
+ if p.From.Type == obj.TYPE_CONST && p.From.Offset < 0 && int32(p.From.Offset) != -1<<31 {
p.From.Offset = -p.From.Offset
p.As = complements[p.As]
}
+ }
- break
+ // For 32-bit logical instruction with constant,
+ // rewrite the high 32-bit to be a repetition of
+ // the low 32-bit, so that the BITCON test can be
+ // shared for both 32-bit and 64-bit. 32-bit ops
+ // will zero the high 32-bit of the destination
+ // register anyway.
+ switch p.As {
+ case AANDW, AORRW, AEORW, AANDSW:
+ if p.From.Type == obj.TYPE_CONST {
+ v := p.From.Offset & 0xffffffff
+ p.From.Offset = v | v<<32
+ }
}
if ctxt.Flag_dynlink {
@@ -339,7 +371,7 @@ func rewriteToUseGot(ctxt *obj.Link, p *obj.Prog) {
// We only care about global data: NAME_EXTERN means a global
// symbol in the Go sense, and p.Sym.Local is true for a few
// internally defined symbols.
- if p.From.Type == obj.TYPE_ADDR && p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local {
+ if p.From.Type == obj.TYPE_ADDR && p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local() {
// MOVD $sym, Rx becomes MOVD sym at GOT, Rx
// MOVD $sym+<off>, Rx becomes MOVD sym at GOT, Rx; ADD <off>, Rx
if p.As != AMOVD {
@@ -366,12 +398,12 @@ func rewriteToUseGot(ctxt *obj.Link, p *obj.Prog) {
// MOVx sym, Ry becomes MOVD sym at GOT, REGTMP; MOVx (REGTMP), Ry
// MOVx Ry, sym becomes MOVD sym at GOT, REGTMP; MOVD Ry, (REGTMP)
// An addition may be inserted between the two MOVs if there is an offset.
- if p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local {
- if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local {
+ if p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local() {
+ if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local() {
ctxt.Diag("cannot handle NAME_EXTERN on both sides in %v with -dynlink", p)
}
source = &p.From
- } else if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local {
+ } else if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local() {
source = &p.To
} else {
return
@@ -455,9 +487,17 @@ func relinv(a obj.As) obj.As {
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])
+ log.Fatalf("unknown relation: %s", Anames[a-obj.ABaseARM64])
return 0
}
@@ -607,7 +647,6 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
* strip NOPs
* expand RET
*/
- ctxt.Bso.Flush()
q := (*obj.Prog)(nil)
var q1 *obj.Prog
for p := cursym.Text; p != nil; p = p.Link {
@@ -703,9 +742,8 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
p.To.Offset = int64(ctxt.Autosize) - 8
if ctxt.Autosize == 0 && !(cursym.Text.Mark&LEAF != 0) {
if ctxt.Debugvlog != 0 {
- fmt.Fprintf(ctxt.Bso, "save suppressed in: %s\n", cursym.Text.From.Sym.Name)
+ ctxt.Logf("save suppressed in: %s\n", cursym.Text.From.Sym.Name)
}
- ctxt.Bso.Flush()
cursym.Text.Mark |= LEAF
}
@@ -718,42 +756,58 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
aoffset = 0xF0
}
if cursym.Text.Mark&LEAF != 0 {
- cursym.Leaf = true
+ cursym.Set(obj.AttrLeaf, true)
if ctxt.Autosize == 0 {
break
}
- aoffset = 0
}
+ // 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 {
- q = ctxt.NewProg()
- q.As = ASUB
+ // 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.As = ASUB
q.From.Type = obj.TYPE_CONST
- q.From.Offset = int64(ctxt.Autosize) - int64(aoffset)
+ q.From.Offset = int64(ctxt.Autosize)
+ q.Reg = REGSP
q.To.Type = obj.TYPE_REG
- q.To.Reg = REGSP
- q.Spadj = int32(q.From.Offset)
- q.Link = p.Link
- p.Link = q
- if cursym.Text.Mark&LEAF != 0 {
- break
- }
- }
+ q.To.Reg = REGTMP
- q1 = ctxt.NewProg()
- q1.As = AMOVD
- q1.Lineno = p.Lineno
- q1.From.Type = obj.TYPE_REG
- q1.From.Reg = REGLINK
- q1.To.Type = obj.TYPE_MEM
- q1.Scond = C_XPRE
- q1.To.Offset = int64(-aoffset)
- q1.To.Reg = REGSP
- q1.Link = q.Link
- q1.Spadj = aoffset
- q.Link = q1
+ q = obj.Appendp(ctxt, q)
+ q.Lineno = p.Lineno
+ 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.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
+ } else {
+ // small frame, update SP and save LR in a single MOVD.W instruction
+ q1 = obj.Appendp(ctxt, q)
+ q1.As = AMOVD
+ q1.Lineno = p.Lineno
+ q1.From.Type = obj.TYPE_REG
+ q1.From.Reg = REGLINK
+ q1.To.Type = obj.TYPE_MEM
+ q1.Scond = C_XPRE
+ q1.To.Offset = int64(-aoffset)
+ q1.To.Reg = REGSP
+ q1.Spadj = aoffset
+ }
if cursym.Text.From3.Offset&obj.WRAPPER != 0 {
// if(g->panic != nil && g->panic->argp == FP) g->panic->argp = bottom-of-frame
diff --git a/src/cmd/internal/obj/data.go b/src/cmd/internal/obj/data.go
index 29530fa..d5565f2 100644
--- a/src/cmd/internal/obj/data.go
+++ b/src/cmd/internal/obj/data.go
@@ -1,6 +1,6 @@
// Derived from Inferno utils/6l/obj.c and utils/6l/span.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6l/obj.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6l/span.c
+// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/obj.c
+// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/span.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth at terzarima.net)
@@ -145,6 +145,22 @@ func (s *LSym) WriteOff(ctxt *Link, off int64, rsym *LSym, roff int64) {
r.Add = roff
}
+// WriteWeakOff writes a weak 4 byte offset to rsym+roff into s at offset off.
+// After linking the 4 bytes stored at s+off will be
+// rsym+roff-(start of section that s is in).
+func (s *LSym) WriteWeakOff(ctxt *Link, off int64, rsym *LSym, roff int64) {
+ s.prepwrite(ctxt, off, 4)
+ r := Addrel(s)
+ r.Off = int32(off)
+ if int64(r.Off) != off {
+ ctxt.Diag("WriteOff: off overflow %d in %s", off, s.Name)
+ }
+ r.Siz = 4
+ r.Sym = rsym
+ r.Type = R_WEAKADDROFF
+ r.Add = roff
+}
+
// WriteString writes a string of size siz into s at offset off.
func (s *LSym) WriteString(ctxt *Link, off int64, siz int, str string) {
if siz < len(str) {
diff --git a/src/cmd/internal/obj/ld.go b/src/cmd/internal/obj/ld.go
index 81a16d1..54fde2f 100644
--- a/src/cmd/internal/obj/ld.go
+++ b/src/cmd/internal/obj/ld.go
@@ -1,6 +1,6 @@
// Derived from Inferno utils/6l/obj.c and utils/6l/span.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6l/obj.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6l/span.c
+// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/obj.c
+// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/span.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth at terzarima.net)
diff --git a/src/cmd/internal/obj/link.go b/src/cmd/internal/obj/link.go
index b6861f4..2ab2aec 100644
--- a/src/cmd/internal/obj/link.go
+++ b/src/cmd/internal/obj/link.go
@@ -1,5 +1,5 @@
// Derived from Inferno utils/6l/l.h and related files.
-// http://code.google.com/p/inferno-os/source/browse/utils/6l/l.h
+// 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)
@@ -33,6 +33,7 @@ package obj
import (
"bufio"
"cmd/internal/sys"
+ "fmt"
)
// An Addr is an argument to an instruction.
@@ -112,13 +113,17 @@ import (
// val = int32(y)
//
// reg<<shift, reg>>shift, reg->shift, reg@>shift
-// Shifted register value, for ARM.
+// Shifted register value, for ARM and ARM64.
// In this form, reg must be a register and shift can be a register or an integer constant.
// Encoding:
// type = TYPE_SHIFT
+// On ARM:
// offset = (reg&15) | shifttype<<5 | count
// shifttype = 0, 1, 2, 3 for <<, >>, ->, @>
// count = (reg&15)<<8 | 1<<4 for a register shift count, (n&31)<<7 for an integer constant.
+// On ARM64:
+// offset = (reg&31)<<16 | shifttype<<22 | (count&63)<<10
+// shifttype = 0, 1, 2 for <<, >>, ->
//
// (reg, reg)
// A destination register pair. When used as the last argument of an instruction,
@@ -153,11 +158,8 @@ type Addr struct {
Type AddrType
Name int8
Class int8
- Etype uint8
Offset int64
- Width int64
Sym *LSym
- Gotype *LSym
// argument value:
// for TYPE_SCONST, a string
@@ -200,34 +202,55 @@ const (
TYPE_REGLIST
)
-// TODO(rsc): Describe prog.
-// TODO(rsc): Describe TEXT/GLOBL flag in from3
+// Prog describes a single machine instruction.
+//
+// The general instruction form is:
+//
+// As.Scond From, Reg, From3, To, RegTo2
+//
+// where As is an opcode and the others are arguments:
+// From, Reg, From3 are sources, and To, RegTo2 are destinations.
+// Usually, not all arguments are present.
+// For example, MOVL R1, R2 encodes using only As=MOVL, From=R1, To=R2.
+// The Scond field holds additional condition bits for systems (like arm)
+// that have generalized conditional execution.
+//
+// Jump instructions use the Pcond field to point to the target instruction,
+// which must be in the same linked list as the jump instruction.
+//
+// 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).
+//
+// 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
- Link *Prog
- From Addr
- From3 *Addr // optional
- To Addr
- Opt interface{}
- Forwd *Prog
- Pcond *Prog
- Rel *Prog // Source of forward jumps on x86; pcrel on arm
- Pc int64
- Lineno int32
- Spadj int32
- As As // Assembler opcode.
- Reg int16
- RegTo2 int16 // 2nd register output operand
- Mark uint16 // bitmask of arch-specific items
- Optab uint16
- Scond uint8
- Back uint8
- Ft uint8
- Tt uint8
- Isize uint8 // size of the instruction in bytes (x86 only)
- Mode int8
-
- Info ProgInfo
+ 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
}
// From3Type returns From3.Type, or TYPE_NONE when From3 is nil.
@@ -246,17 +269,6 @@ func (p *Prog) From3Offset() int64 {
return p.From3.Offset
}
-// ProgInfo holds information about the instruction for use
-// by clients such as the compiler. The exact meaning of this
-// data is up to the client and is not interpreted by the cmd/internal/obj/... packages.
-type ProgInfo struct {
- _ struct{} // to prevent unkeyed literals. Trailing zero-sized field will take space.
- Flags uint32 // flag bits
- Reguse uint64 // registers implicitly used by this instruction
- Regset uint64 // registers implicitly set by this instruction
- Regindex uint64 // registers used by addressing mode
-}
-
// An As denotes an assembler opcode.
// There are some portable opcodes, declared here in package obj,
// that are common to all architectures.
@@ -268,12 +280,10 @@ type As int16
const (
AXXX As = iota
ACALL
- ACHECKNIL
ADUFFCOPY
ADUFFZERO
AEND
AFUNCDATA
- AGLOBL
AJMP
ANOP
APCDATA
@@ -296,28 +306,50 @@ const (
// Subspaces are aligned to a power of two so opcodes can be masked
// with AMask and used as compact array indices.
const (
- ABase386 = (1 + iota) << 12
+ ABase386 = (1 + iota) << 10
ABaseARM
ABaseAMD64
ABasePPC64
ABaseARM64
- ABaseMIPS64
+ ABaseMIPS
ABaseS390X
- AMask = 1<<12 - 1 // AND with this to use the opcode as an array index.
+ AllowedOpCodes = 1 << 10 // The number of opcodes available for any given architecture.
+ AMask = AllowedOpCodes - 1 // AND with this to use the opcode as an array index.
)
// An LSym is the sort of symbol that is written to an object file.
type LSym struct {
- Name string
- Type int16
- Version int16
- Dupok bool
- Cfunc bool
- Nosplit bool
- Leaf bool
- Seenglobl bool
- Onlist bool
+ Name string
+ Type SymKind
+ Version int16
+ 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
+}
+
+// Attribute is a set of symbol attributes.
+type Attribute int16
+
+const (
+ AttrDuplicateOK Attribute = 1 << iota
+ AttrCFunc
+ AttrNoSplit
+ AttrLeaf
+ AttrSeenGlobl
+ AttrOnList
+
+ // MakeTypelink means that the type should have an entry in the typelink table.
+ AttrMakeTypelink
// ReflectMethod means the function may call reflect.Type.Method or
// reflect.Type.MethodByName. Matching is imprecise (as reflect.Type
@@ -325,7 +357,7 @@ type LSym struct {
// set in some cases when the reflect package is not called.
//
// Used by the linker to determine what methods can be pruned.
- ReflectMethod bool
+ AttrReflectMethod
// Local means make the symbol local even when compiling Go code to reference Go
// symbols in other shared libraries, as in this mode symbols are global by
@@ -333,18 +365,25 @@ type LSym struct {
// visible outside of the module (shared library or executable) that contains its
// definition. (When not compiling to support Go shared libraries, all symbols are
// local in this sense unless there is a cgo_export_* directive).
- Local bool
+ AttrLocal
+)
- 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 (a Attribute) DuplicateOK() bool { return a&AttrDuplicateOK != 0 }
+func (a Attribute) MakeTypelink() bool { return a&AttrMakeTypelink != 0 }
+func (a Attribute) CFunc() bool { return a&AttrCFunc != 0 }
+func (a Attribute) NoSplit() bool { return a&AttrNoSplit != 0 }
+func (a Attribute) Leaf() bool { return a&AttrLeaf != 0 }
+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) Set(flag Attribute, value bool) {
+ if value {
+ *a |= flag
+ } else {
+ *a &^= flag
+ }
}
// The compiler needs LSym to satisfy fmt.Stringer, because it stores
@@ -365,21 +404,33 @@ type Pcln struct {
Lastindex int
}
-// LSym.type
+// 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 = iota
+ Sxxx SymKind = iota
STEXT
SELFRXSECT
+ // Read-only sections.
STYPE
SSTRING
SGOSTRING
- SGOSTRINGHDR
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
@@ -393,18 +444,18 @@ const (
STYPERELRO
SSTRINGRELRO
SGOSTRINGRELRO
- SGOSTRINGHDRRELRO
SGOFUNCRELRO
SGCBITSRELRO
SRODATARELRO
SFUNCTABRELRO
+ // Part of .data.rel.ro if it exists, otherwise part of .rodata.
STYPELINK
SITABLINK
SSYMTAB
SPCLNTAB
- SELFROSECT
- SMACHOPLT
+
+ // Writable sections.
SELFSECT
SMACHO
SMACHOGOT
@@ -428,23 +479,50 @@ const (
SHOSTOBJ
SDWARFSECT
SDWARFINFO
- SSUB = 1 << 8
- SMASK = SSUB - 1
- SHIDDEN = 1 << 9
- SCONTAINER = 1 << 10 // has a sub-symbol
+ 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,
+}
+
type Reloc struct {
Off int32
Siz uint8
- Type int32
+ Type RelocType
Add int64
Sym *LSym
}
-// Reloc.type
+type RelocType int32
+
+//go:generate stringer -type=RelocType
const (
- R_ADDR = 1 + iota
+ 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
@@ -454,12 +532,17 @@ const (
// R_ADDRARM64 relocates an adrp, add pair to compute the address of the
// referenced symbol.
R_ADDRARM64
- // R_ADDRMIPS (only used on mips64) resolves to the low 16 bits of an external
+ // 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
@@ -582,7 +665,7 @@ const (
// TODO(mundaym): remove once variants can be serialized - see issue 14218.
R_PCRELDBL
- // R_ADDRMIPSU (only used on mips64) resolves to the sign-adjusted "upper" 16
+ // 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
@@ -590,6 +673,20 @@ const (
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
@@ -617,8 +714,7 @@ const (
// Link holds the context for writing object code from a compiler
// to be linker input or for reading that input into the linker.
type Link struct {
- Goarm int32
- Headtype int
+ Headtype HeadType
Arch *LinkArch
Debugasm int32
Debugvlog int32
@@ -629,13 +725,10 @@ type Link struct {
Flag_optimize bool
Bso *bufio.Writer
Pathname string
- Goroot string
- Goroot_final string
Hash map[SymVer]*LSym
LineHist LineHist
Imports []string
- Plist *Plist
- Plast *Plist
+ Plists []*Plist
Sym_div *LSym
Sym_divu *LSym
Sym_mod *LSym
@@ -660,8 +753,6 @@ type Link struct {
Mode int
Cursym *LSym
Version int
- Textp *LSym
- Etextp *LSym
Errors int
Framepointer_enabled bool
@@ -680,6 +771,11 @@ func (ctxt *Link) Diag(format string, args ...interface{}) {
ctxt.DiagFunc(format, args...)
}
+func (ctxt *Link) Logf(format string, args ...interface{}) {
+ fmt.Fprintf(ctxt.Bso, format, args...)
+ ctxt.Bso.Flush()
+}
+
// The smallest possible offset from the hardware stack pointer to a local
// variable on the stack. Architectures that use a link register save its value
// on the stack in the function prologue and so always have a pointer between
@@ -712,9 +808,11 @@ type LinkArch struct {
UnaryDst map[As]bool // Instruction takes one operand, a destination.
}
-/* executable header types */
+// HeadType is the executable header type.
+type HeadType uint8
+
const (
- Hunknown = 0 + iota
+ Hunknown HeadType = iota
Hdarwin
Hdragonfly
Hfreebsd
@@ -725,8 +823,67 @@ const (
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
diff --git a/src/cmd/internal/obj/mips/a.out.go b/src/cmd/internal/obj/mips/a.out.go
index bc6b69d..f732ed5 100644
--- a/src/cmd/internal/obj/mips/a.out.go
+++ b/src/cmd/internal/obj/mips/a.out.go
@@ -44,7 +44,7 @@ const (
)
const (
- REG_R0 = obj.RBaseMIPS64 + iota
+ REG_R0 = obj.RBaseMIPS + iota
REG_R1
REG_R2
REG_R3
@@ -185,22 +185,18 @@ const (
REG_SPECIAL = REG_M0
- REGZERO = REG_R0 /* set to zero */
- REGSP = REG_R29
- REGSB = REG_R28
- REGLINK = REG_R31
- REGRET = REG_R1
- REGARG = -1 /* -1 disables passing the first argument in register */
- REGRT1 = REG_R1 /* reserved for runtime, duffzero and duffcopy */
- REGRT2 = REG_R2 /* reserved for runtime, duffcopy */
- REGCTXT = REG_R22 /* context for closures */
- REGG = REG_R30 /* G */
- REGTMP = REG_R23 /* used by the linker */
- FREGRET = REG_F0
- FREGZERO = REG_F24 /* both float and double */
- FREGHALF = REG_F26 /* double */
- FREGONE = REG_F28 /* double */
- FREGTWO = REG_F30 /* double */
+ REGZERO = REG_R0 /* set to zero */
+ REGSP = REG_R29
+ REGSB = REG_R28
+ REGLINK = REG_R31
+ REGRET = REG_R1
+ REGARG = -1 /* -1 disables passing the first argument in register */
+ REGRT1 = REG_R1 /* reserved for runtime, duffzero and duffcopy */
+ REGRT2 = REG_R2 /* reserved for runtime, duffcopy */
+ REGCTXT = REG_R22 /* context for closures */
+ REGG = REG_R30 /* G */
+ REGTMP = REG_R23 /* used by the linker */
+ FREGRET = REG_F0
)
const (
@@ -222,6 +218,11 @@ const (
)
const (
+ Mips32 = 32
+ Mips64 = 64
+)
+
+const (
C_NONE = iota
C_REG
C_FREG
@@ -262,7 +263,7 @@ const (
)
const (
- AABSD = obj.ABaseMIPS64 + obj.A_ARCHSPECIFIC + iota
+ AABSD = obj.ABaseMIPS + obj.A_ARCHSPECIFIC + iota
AABSF
AABSW
AADD
@@ -282,6 +283,12 @@ const (
ABLTZAL
ABNE
ABREAK
+ ACLO
+ ACLZ
+ ACMOVF
+ ACMOVN
+ ACMOVT
+ ACMOVZ
ACMPEQD
ACMPEQF
ACMPGED
@@ -294,6 +301,7 @@ const (
ADIVU
ADIVW
AGOK
+ ALL
ALUI
AMOVB
AMOVBU
@@ -323,9 +331,12 @@ const (
AREM
AREMU
ARFE
+ ASC
ASGT
ASGTU
ASLL
+ ASQRTD
+ ASQRTF
ASRA
ASRL
ASUB
@@ -333,11 +344,14 @@ const (
ASUBF
ASUBU
ASUBW
+ ASYNC
ASYSCALL
+ ATEQ
ATLBP
ATLBR
ATLBWI
ATLBWR
+ ATNE
AWORD
AXOR
diff --git a/src/cmd/internal/obj/mips/anames.go b/src/cmd/internal/obj/mips/anames.go
index c784809..8482a9e 100644
--- a/src/cmd/internal/obj/mips/anames.go
+++ b/src/cmd/internal/obj/mips/anames.go
@@ -26,6 +26,12 @@ var Anames = []string{
"BLTZAL",
"BNE",
"BREAK",
+ "CLO",
+ "CLZ",
+ "CMOVF",
+ "CMOVN",
+ "CMOVT",
+ "CMOVZ",
"CMPEQD",
"CMPEQF",
"CMPGED",
@@ -38,6 +44,7 @@ var Anames = []string{
"DIVU",
"DIVW",
"GOK",
+ "LL",
"LUI",
"MOVB",
"MOVBU",
@@ -67,9 +74,12 @@ var Anames = []string{
"REM",
"REMU",
"RFE",
+ "SC",
"SGT",
"SGTU",
"SLL",
+ "SQRTD",
+ "SQRTF",
"SRA",
"SRL",
"SUB",
@@ -77,11 +87,14 @@ var Anames = []string{
"SUBF",
"SUBU",
"SUBW",
+ "SYNC",
"SYSCALL",
+ "TEQ",
"TLBP",
"TLBR",
"TLBWI",
"TLBWR",
+ "TNE",
"WORD",
"XOR",
"MOVV",
diff --git a/src/cmd/internal/obj/mips/asm0.go b/src/cmd/internal/obj/mips/asm0.go
index 11aa202..c421dee 100644
--- a/src/cmd/internal/obj/mips/asm0.go
+++ b/src/cmd/internal/obj/mips/asm0.go
@@ -39,7 +39,7 @@ import (
// Instruction layout.
const (
- FuncAlign = 8
+ mips64FuncAlign = 8
)
const (
@@ -54,270 +54,319 @@ type Optab struct {
type_ int8
size int8
param int16
+ mode int
}
var optab = []Optab{
- {obj.ATEXT, C_LEXT, C_NONE, C_TEXTSIZE, 0, 0, 0},
- {obj.ATEXT, C_ADDR, C_NONE, C_TEXTSIZE, 0, 0, 0},
-
- {AMOVW, C_REG, C_NONE, C_REG, 1, 4, 0},
- {AMOVV, C_REG, C_NONE, C_REG, 1, 4, 0},
- {AMOVB, C_REG, C_NONE, C_REG, 12, 8, 0},
- {AMOVBU, C_REG, C_NONE, C_REG, 13, 4, 0},
- {AMOVWU, C_REG, C_NONE, C_REG, 14, 8, 0},
-
- {ASUB, C_REG, C_REG, C_REG, 2, 4, 0},
- {AADD, C_REG, C_REG, C_REG, 2, 4, 0},
- {AAND, C_REG, C_REG, C_REG, 2, 4, 0},
- {ASUB, C_REG, C_NONE, C_REG, 2, 4, 0},
- {AADD, C_REG, C_NONE, C_REG, 2, 4, 0},
- {AAND, C_REG, C_NONE, C_REG, 2, 4, 0},
-
- {ASLL, C_REG, C_NONE, C_REG, 9, 4, 0},
- {ASLL, C_REG, C_REG, C_REG, 9, 4, 0},
-
- {AADDF, C_FREG, C_NONE, C_FREG, 32, 4, 0},
- {AADDF, C_FREG, C_REG, C_FREG, 32, 4, 0},
- {ACMPEQF, C_FREG, C_REG, C_NONE, 32, 4, 0},
- {AABSF, C_FREG, C_NONE, C_FREG, 33, 4, 0},
- {AMOVF, C_FREG, C_NONE, C_FREG, 33, 4, 0},
- {AMOVD, C_FREG, C_NONE, C_FREG, 33, 4, 0},
-
- {AMOVW, C_REG, C_NONE, C_SEXT, 7, 4, REGSB},
- {AMOVWU, C_REG, C_NONE, C_SEXT, 7, 4, REGSB},
- {AMOVV, C_REG, C_NONE, C_SEXT, 7, 4, REGSB},
- {AMOVB, C_REG, C_NONE, C_SEXT, 7, 4, REGSB},
- {AMOVBU, C_REG, C_NONE, C_SEXT, 7, 4, REGSB},
- {AMOVWL, C_REG, C_NONE, C_SEXT, 7, 4, REGSB},
- {AMOVW, C_REG, C_NONE, C_SAUTO, 7, 4, REGSP},
- {AMOVWU, C_REG, C_NONE, C_SAUTO, 7, 4, REGSP},
- {AMOVV, C_REG, C_NONE, C_SAUTO, 7, 4, REGSP},
- {AMOVB, C_REG, C_NONE, C_SAUTO, 7, 4, REGSP},
- {AMOVBU, C_REG, C_NONE, C_SAUTO, 7, 4, REGSP},
- {AMOVWL, C_REG, C_NONE, C_SAUTO, 7, 4, REGSP},
- {AMOVW, C_REG, C_NONE, C_SOREG, 7, 4, REGZERO},
- {AMOVWU, C_REG, C_NONE, C_SOREG, 7, 4, REGZERO},
- {AMOVV, C_REG, C_NONE, C_SOREG, 7, 4, REGZERO},
- {AMOVB, C_REG, C_NONE, C_SOREG, 7, 4, REGZERO},
- {AMOVBU, C_REG, C_NONE, C_SOREG, 7, 4, REGZERO},
- {AMOVWL, C_REG, C_NONE, C_SOREG, 7, 4, REGZERO},
-
- {AMOVW, C_SEXT, C_NONE, C_REG, 8, 4, REGSB},
- {AMOVWU, C_SEXT, C_NONE, C_REG, 8, 4, REGSB},
- {AMOVV, C_SEXT, C_NONE, C_REG, 8, 4, REGSB},
- {AMOVB, C_SEXT, C_NONE, C_REG, 8, 4, REGSB},
- {AMOVBU, C_SEXT, C_NONE, C_REG, 8, 4, REGSB},
- {AMOVWL, C_SEXT, C_NONE, C_REG, 8, 4, REGSB},
- {AMOVW, C_SAUTO, C_NONE, C_REG, 8, 4, REGSP},
- {AMOVWU, C_SAUTO, C_NONE, C_REG, 8, 4, REGSP},
- {AMOVV, C_SAUTO, C_NONE, C_REG, 8, 4, REGSP},
- {AMOVB, C_SAUTO, C_NONE, C_REG, 8, 4, REGSP},
- {AMOVBU, C_SAUTO, C_NONE, C_REG, 8, 4, REGSP},
- {AMOVWL, C_SAUTO, C_NONE, C_REG, 8, 4, REGSP},
- {AMOVW, C_SOREG, C_NONE, C_REG, 8, 4, REGZERO},
- {AMOVWU, C_SOREG, C_NONE, C_REG, 8, 4, REGZERO},
- {AMOVV, C_SOREG, C_NONE, C_REG, 8, 4, REGZERO},
- {AMOVB, C_SOREG, C_NONE, C_REG, 8, 4, REGZERO},
- {AMOVBU, C_SOREG, C_NONE, C_REG, 8, 4, REGZERO},
- {AMOVWL, C_SOREG, C_NONE, C_REG, 8, 4, REGZERO},
-
- {AMOVW, C_REG, C_NONE, C_LEXT, 35, 12, REGSB},
- {AMOVWU, C_REG, C_NONE, C_LEXT, 35, 12, REGSB},
- {AMOVV, C_REG, C_NONE, C_LEXT, 35, 12, REGSB},
- {AMOVB, C_REG, C_NONE, C_LEXT, 35, 12, REGSB},
- {AMOVBU, C_REG, C_NONE, C_LEXT, 35, 12, REGSB},
- {AMOVW, C_REG, C_NONE, C_LAUTO, 35, 12, REGSP},
- {AMOVWU, C_REG, C_NONE, C_LAUTO, 35, 12, REGSP},
- {AMOVV, C_REG, C_NONE, C_LAUTO, 35, 12, REGSP},
- {AMOVB, C_REG, C_NONE, C_LAUTO, 35, 12, REGSP},
- {AMOVBU, C_REG, C_NONE, C_LAUTO, 35, 12, REGSP},
- {AMOVW, C_REG, C_NONE, C_LOREG, 35, 12, REGZERO},
- {AMOVWU, C_REG, C_NONE, C_LOREG, 35, 12, REGZERO},
- {AMOVV, C_REG, C_NONE, C_LOREG, 35, 12, REGZERO},
- {AMOVB, C_REG, C_NONE, C_LOREG, 35, 12, REGZERO},
- {AMOVBU, C_REG, C_NONE, C_LOREG, 35, 12, REGZERO},
- {AMOVW, C_REG, C_NONE, C_ADDR, 50, 12, 0},
- {AMOVWU, C_REG, C_NONE, C_ADDR, 50, 12, 0},
- {AMOVV, C_REG, C_NONE, C_ADDR, 50, 12, 0},
- {AMOVB, C_REG, C_NONE, C_ADDR, 50, 12, 0},
- {AMOVBU, C_REG, C_NONE, C_ADDR, 50, 12, 0},
- {AMOVW, C_REG, C_NONE, C_TLS, 53, 8, 0},
- {AMOVWU, C_REG, C_NONE, C_TLS, 53, 8, 0},
- {AMOVV, C_REG, C_NONE, C_TLS, 53, 8, 0},
- {AMOVB, C_REG, C_NONE, C_TLS, 53, 8, 0},
- {AMOVBU, C_REG, C_NONE, C_TLS, 53, 8, 0},
-
- {AMOVW, C_LEXT, C_NONE, C_REG, 36, 12, REGSB},
- {AMOVWU, C_LEXT, C_NONE, C_REG, 36, 12, REGSB},
- {AMOVV, C_LEXT, C_NONE, C_REG, 36, 12, REGSB},
- {AMOVB, C_LEXT, C_NONE, C_REG, 36, 12, REGSB},
- {AMOVBU, C_LEXT, C_NONE, C_REG, 36, 12, REGSB},
- {AMOVW, C_LAUTO, C_NONE, C_REG, 36, 12, REGSP},
- {AMOVWU, C_LAUTO, C_NONE, C_REG, 36, 12, REGSP},
- {AMOVV, C_LAUTO, C_NONE, C_REG, 36, 12, REGSP},
- {AMOVB, C_LAUTO, C_NONE, C_REG, 36, 12, REGSP},
- {AMOVBU, C_LAUTO, C_NONE, C_REG, 36, 12, REGSP},
- {AMOVW, C_LOREG, C_NONE, C_REG, 36, 12, REGZERO},
- {AMOVWU, C_LOREG, C_NONE, C_REG, 36, 12, REGZERO},
- {AMOVV, C_LOREG, C_NONE, C_REG, 36, 12, REGZERO},
- {AMOVB, C_LOREG, C_NONE, C_REG, 36, 12, REGZERO},
- {AMOVBU, C_LOREG, C_NONE, C_REG, 36, 12, REGZERO},
- {AMOVW, C_ADDR, C_NONE, C_REG, 51, 12, 0},
- {AMOVWU, C_ADDR, C_NONE, C_REG, 51, 12, 0},
- {AMOVV, C_ADDR, C_NONE, C_REG, 51, 12, 0},
- {AMOVB, C_ADDR, C_NONE, C_REG, 51, 12, 0},
- {AMOVBU, C_ADDR, C_NONE, C_REG, 51, 12, 0},
- {AMOVW, C_TLS, C_NONE, C_REG, 54, 8, 0},
- {AMOVWU, C_TLS, C_NONE, C_REG, 54, 8, 0},
- {AMOVV, C_TLS, C_NONE, C_REG, 54, 8, 0},
- {AMOVB, C_TLS, C_NONE, C_REG, 54, 8, 0},
- {AMOVBU, C_TLS, C_NONE, C_REG, 54, 8, 0},
-
- {AMOVW, C_SECON, C_NONE, C_REG, 3, 4, REGSB},
- {AMOVV, C_SECON, C_NONE, C_REG, 3, 4, REGSB},
- {AMOVW, C_SACON, C_NONE, C_REG, 3, 4, REGSP},
- {AMOVV, C_SACON, C_NONE, C_REG, 3, 4, REGSP},
- {AMOVW, C_LECON, C_NONE, C_REG, 52, 12, REGSB},
- {AMOVV, C_LECON, C_NONE, C_REG, 52, 12, REGSB},
- {AMOVW, C_LACON, C_NONE, C_REG, 26, 12, REGSP},
- {AMOVV, C_LACON, C_NONE, C_REG, 26, 12, REGSP},
- {AMOVW, C_ADDCON, C_NONE, C_REG, 3, 4, REGZERO},
- {AMOVV, C_ADDCON, C_NONE, C_REG, 3, 4, REGZERO},
- {AMOVW, C_ANDCON, C_NONE, C_REG, 3, 4, REGZERO},
- {AMOVV, C_ANDCON, C_NONE, C_REG, 3, 4, REGZERO},
- {AMOVW, C_STCON, C_NONE, C_REG, 55, 8, 0},
- {AMOVV, C_STCON, C_NONE, C_REG, 55, 8, 0},
-
- {AMOVW, C_UCON, C_NONE, C_REG, 24, 4, 0},
- {AMOVV, C_UCON, C_NONE, C_REG, 24, 4, 0},
- {AMOVW, C_LCON, C_NONE, C_REG, 19, 8, 0},
- {AMOVV, C_LCON, C_NONE, C_REG, 19, 8, 0},
-
- {AMOVW, C_HI, C_NONE, C_REG, 20, 4, 0},
- {AMOVV, C_HI, C_NONE, C_REG, 20, 4, 0},
- {AMOVW, C_LO, C_NONE, C_REG, 20, 4, 0},
- {AMOVV, C_LO, C_NONE, C_REG, 20, 4, 0},
- {AMOVW, C_REG, C_NONE, C_HI, 21, 4, 0},
- {AMOVV, C_REG, C_NONE, C_HI, 21, 4, 0},
- {AMOVW, C_REG, C_NONE, C_LO, 21, 4, 0},
- {AMOVV, C_REG, C_NONE, C_LO, 21, 4, 0},
-
- {AMUL, C_REG, C_REG, C_NONE, 22, 4, 0},
-
- {AADD, C_ADD0CON, C_REG, C_REG, 4, 4, 0},
- {AADD, C_ADD0CON, C_NONE, C_REG, 4, 4, 0},
- {AADD, C_ANDCON, C_REG, C_REG, 10, 8, 0},
- {AADD, C_ANDCON, C_NONE, C_REG, 10, 8, 0},
-
- {AAND, C_AND0CON, C_REG, C_REG, 4, 4, 0},
- {AAND, C_AND0CON, C_NONE, C_REG, 4, 4, 0},
- {AAND, C_ADDCON, C_REG, C_REG, 10, 8, 0},
- {AAND, C_ADDCON, C_NONE, C_REG, 10, 8, 0},
-
- {AADD, C_UCON, C_REG, C_REG, 25, 8, 0},
- {AADD, C_UCON, C_NONE, C_REG, 25, 8, 0},
- {AAND, C_UCON, C_REG, C_REG, 25, 8, 0},
- {AAND, C_UCON, C_NONE, C_REG, 25, 8, 0},
-
- {AADD, C_LCON, C_NONE, C_REG, 23, 12, 0},
- {AAND, C_LCON, C_NONE, C_REG, 23, 12, 0},
- {AADD, C_LCON, C_REG, C_REG, 23, 12, 0},
- {AAND, C_LCON, C_REG, C_REG, 23, 12, 0},
-
- {ASLL, C_SCON, C_REG, C_REG, 16, 4, 0},
- {ASLL, C_SCON, C_NONE, C_REG, 16, 4, 0},
-
- {ASYSCALL, C_NONE, C_NONE, C_NONE, 5, 4, 0},
-
- {ABEQ, C_REG, C_REG, C_SBRA, 6, 4, 0},
- {ABEQ, C_REG, C_NONE, C_SBRA, 6, 4, 0},
- {ABLEZ, C_REG, C_NONE, C_SBRA, 6, 4, 0},
- {ABFPT, C_NONE, C_NONE, C_SBRA, 6, 8, 0},
-
- {AJMP, C_NONE, C_NONE, C_LBRA, 11, 4, 0},
- {AJAL, C_NONE, C_NONE, C_LBRA, 11, 4, 0},
-
- {AJMP, C_NONE, C_NONE, C_ZOREG, 18, 4, REGZERO},
- {AJAL, C_NONE, C_NONE, C_ZOREG, 18, 4, REGLINK},
-
- {AMOVW, C_SEXT, C_NONE, C_FREG, 27, 4, REGSB},
- {AMOVF, C_SEXT, C_NONE, C_FREG, 27, 4, REGSB},
- {AMOVD, C_SEXT, C_NONE, C_FREG, 27, 4, REGSB},
- {AMOVW, C_SAUTO, C_NONE, C_FREG, 27, 4, REGSP},
- {AMOVF, C_SAUTO, C_NONE, C_FREG, 27, 4, REGSP},
- {AMOVD, C_SAUTO, C_NONE, C_FREG, 27, 4, REGSP},
- {AMOVW, C_SOREG, C_NONE, C_FREG, 27, 4, REGZERO},
- {AMOVF, C_SOREG, C_NONE, C_FREG, 27, 4, REGZERO},
- {AMOVD, C_SOREG, C_NONE, C_FREG, 27, 4, REGZERO},
-
- {AMOVW, C_LEXT, C_NONE, C_FREG, 27, 12, REGSB},
- {AMOVF, C_LEXT, C_NONE, C_FREG, 27, 12, REGSB},
- {AMOVD, C_LEXT, C_NONE, C_FREG, 27, 12, REGSB},
- {AMOVW, C_LAUTO, C_NONE, C_FREG, 27, 12, REGSP},
- {AMOVF, C_LAUTO, C_NONE, C_FREG, 27, 12, REGSP},
- {AMOVD, C_LAUTO, C_NONE, C_FREG, 27, 12, REGSP},
- {AMOVW, C_LOREG, C_NONE, C_FREG, 27, 12, REGZERO},
- {AMOVF, C_LOREG, C_NONE, C_FREG, 27, 12, REGZERO},
- {AMOVD, C_LOREG, C_NONE, C_FREG, 27, 12, REGZERO},
- {AMOVF, C_ADDR, C_NONE, C_FREG, 51, 12, 0},
- {AMOVD, C_ADDR, C_NONE, C_FREG, 51, 12, 0},
-
- {AMOVW, C_FREG, C_NONE, C_SEXT, 28, 4, REGSB},
- {AMOVF, C_FREG, C_NONE, C_SEXT, 28, 4, REGSB},
- {AMOVD, C_FREG, C_NONE, C_SEXT, 28, 4, REGSB},
- {AMOVW, C_FREG, C_NONE, C_SAUTO, 28, 4, REGSP},
- {AMOVF, C_FREG, C_NONE, C_SAUTO, 28, 4, REGSP},
- {AMOVD, C_FREG, C_NONE, C_SAUTO, 28, 4, REGSP},
- {AMOVW, C_FREG, C_NONE, C_SOREG, 28, 4, REGZERO},
- {AMOVF, C_FREG, C_NONE, C_SOREG, 28, 4, REGZERO},
- {AMOVD, C_FREG, C_NONE, C_SOREG, 28, 4, REGZERO},
-
- {AMOVW, C_FREG, C_NONE, C_LEXT, 28, 12, REGSB},
- {AMOVF, C_FREG, C_NONE, C_LEXT, 28, 12, REGSB},
- {AMOVD, C_FREG, C_NONE, C_LEXT, 28, 12, REGSB},
- {AMOVW, C_FREG, C_NONE, C_LAUTO, 28, 12, REGSP},
- {AMOVF, C_FREG, C_NONE, C_LAUTO, 28, 12, REGSP},
- {AMOVD, C_FREG, C_NONE, C_LAUTO, 28, 12, REGSP},
- {AMOVW, C_FREG, C_NONE, C_LOREG, 28, 12, REGZERO},
- {AMOVF, C_FREG, C_NONE, C_LOREG, 28, 12, REGZERO},
- {AMOVD, C_FREG, C_NONE, C_LOREG, 28, 12, REGZERO},
- {AMOVF, C_FREG, C_NONE, C_ADDR, 50, 12, 0},
- {AMOVD, C_FREG, C_NONE, C_ADDR, 50, 12, 0},
-
- {AMOVW, C_REG, C_NONE, C_FREG, 30, 4, 0},
- {AMOVW, C_FREG, C_NONE, C_REG, 31, 4, 0},
- {AMOVV, C_REG, C_NONE, C_FREG, 47, 4, 0},
- {AMOVV, C_FREG, C_NONE, C_REG, 48, 4, 0},
-
- {AMOVW, C_ADDCON, C_NONE, C_FREG, 34, 8, 0},
- {AMOVW, C_ANDCON, C_NONE, C_FREG, 34, 8, 0},
-
- {AMOVW, C_REG, C_NONE, C_MREG, 37, 4, 0},
- {AMOVV, C_REG, C_NONE, C_MREG, 37, 4, 0},
- {AMOVW, C_MREG, C_NONE, C_REG, 38, 4, 0},
- {AMOVV, C_MREG, C_NONE, C_REG, 38, 4, 0},
-
- {AWORD, C_LCON, C_NONE, C_NONE, 40, 4, 0},
-
- {AMOVW, C_REG, C_NONE, C_FCREG, 41, 8, 0},
- {AMOVV, C_REG, C_NONE, C_FCREG, 41, 8, 0},
- {AMOVW, C_FCREG, C_NONE, C_REG, 42, 4, 0},
- {AMOVV, C_FCREG, C_NONE, C_REG, 42, 4, 0},
-
- {ABREAK, C_REG, C_NONE, C_SEXT, 7, 4, REGSB}, /* really CACHE instruction */
- {ABREAK, C_REG, C_NONE, C_SAUTO, 7, 4, REGSP},
- {ABREAK, C_REG, C_NONE, C_SOREG, 7, 4, REGZERO},
- {ABREAK, C_NONE, C_NONE, C_NONE, 5, 4, 0},
-
- {obj.AUNDEF, C_NONE, C_NONE, C_NONE, 49, 4, 0},
- {obj.AUSEFIELD, C_ADDR, C_NONE, C_NONE, 0, 0, 0},
- {obj.APCDATA, C_LCON, C_NONE, C_LCON, 0, 0, 0},
- {obj.AFUNCDATA, C_SCON, C_NONE, C_ADDR, 0, 0, 0},
- {obj.ANOP, C_NONE, C_NONE, C_NONE, 0, 0, 0},
- {obj.ADUFFZERO, C_NONE, C_NONE, C_LBRA, 11, 4, 0}, // same as AJMP
- {obj.ADUFFCOPY, C_NONE, C_NONE, C_LBRA, 11, 4, 0}, // same as AJMP
-
- {obj.AXXX, C_NONE, C_NONE, C_NONE, 0, 4, 0},
+ {obj.ATEXT, C_LEXT, C_NONE, C_TEXTSIZE, 0, 0, 0, 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},
+ {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},
+
+ {ASUB, C_REG, C_REG, C_REG, 2, 4, 0, 0},
+ {ASUBV, C_REG, C_REG, C_REG, 2, 4, 0, Mips64},
+ {AADD, C_REG, C_REG, C_REG, 2, 4, 0, 0},
+ {AADDV, C_REG, C_REG, C_REG, 2, 4, 0, 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},
+ {AADD, C_REG, C_NONE, C_REG, 2, 4, 0, 0},
+ {AADDV, C_REG, C_NONE, C_REG, 2, 4, 0, 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},
+ {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},
+ {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_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},
+ {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},
+ {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},
+ {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},
+ {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},
+ {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},
+ {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},
+ {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},
+ {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},
+ {ALL, C_SOREG, C_NONE, C_REG, 8, 4, REGZERO, 0},
+
+ {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_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},
+ {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},
+ {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_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},
+ {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_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},
+ {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},
+ {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_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},
+ {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_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},
+
+ {AMOVW, C_LACON, C_NONE, C_REG, 26, 12, REGSP, 0},
+ {AMOVV, C_LACON, C_NONE, C_REG, 26, 12, REGSP, Mips64},
+ {AMOVW, C_ADDCON, C_NONE, C_REG, 3, 4, REGZERO, 0},
+ {AMOVV, C_ADDCON, C_NONE, C_REG, 3, 4, REGZERO, Mips64},
+ {AMOVW, C_ANDCON, C_NONE, C_REG, 3, 4, REGZERO, 0},
+ {AMOVV, C_ANDCON, C_NONE, C_REG, 3, 4, REGZERO, Mips64},
+ {AMOVW, C_STCON, C_NONE, C_REG, 55, 8, 0, 0},
+ {AMOVV, C_STCON, C_NONE, C_REG, 55, 8, 0, Mips64},
+
+ {AMOVW, C_UCON, C_NONE, C_REG, 24, 4, 0, 0},
+ {AMOVV, C_UCON, C_NONE, C_REG, 24, 4, 0, Mips64},
+ {AMOVW, C_LCON, C_NONE, C_REG, 19, 8, 0, 0},
+ {AMOVV, C_LCON, C_NONE, C_REG, 19, 8, 0, Mips64},
+
+ {AMOVW, C_HI, C_NONE, C_REG, 20, 4, 0, 0},
+ {AMOVV, C_HI, C_NONE, C_REG, 20, 4, 0, Mips64},
+ {AMOVW, C_LO, C_NONE, C_REG, 20, 4, 0, 0},
+ {AMOVV, C_LO, C_NONE, C_REG, 20, 4, 0, Mips64},
+ {AMOVW, C_REG, C_NONE, C_HI, 21, 4, 0, 0},
+ {AMOVV, C_REG, C_NONE, C_HI, 21, 4, 0, Mips64},
+ {AMOVW, C_REG, C_NONE, C_LO, 21, 4, 0, 0},
+ {AMOVV, C_REG, C_NONE, C_LO, 21, 4, 0, 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},
+
+ {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},
+
+ {AAND, C_AND0CON, C_REG, C_REG, 4, 4, 0, 0},
+ {AAND, C_AND0CON, C_NONE, C_REG, 4, 4, 0, 0},
+ {AAND, C_ADDCON, C_REG, C_REG, 10, 8, 0, 0},
+ {AAND, C_ADDCON, C_NONE, C_REG, 10, 8, 0, 0},
+
+ {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},
+ {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},
+ {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},
+ {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},
+
+ {ASYSCALL, C_NONE, C_NONE, C_NONE, 5, 4, 0, 0},
+
+ {ABEQ, C_REG, C_REG, C_SBRA, 6, 4, 0, 0},
+ {ABEQ, C_REG, C_NONE, C_SBRA, 6, 4, 0, 0},
+ {ABLEZ, C_REG, C_NONE, C_SBRA, 6, 4, 0, 0},
+ {ABFPT, C_NONE, C_NONE, C_SBRA, 6, 8, 0, 0},
+
+ {AJMP, C_NONE, C_NONE, C_LBRA, 11, 4, 0, 0},
+ {AJAL, C_NONE, C_NONE, C_LBRA, 11, 4, 0, 0},
+
+ {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},
+ {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},
+ {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},
+ {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},
+ {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_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},
+ {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},
+ {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},
+ {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},
+
+ {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},
+
+ {AMOVW, C_ADDCON, C_NONE, C_FREG, 34, 8, 0, Mips64},
+ {AMOVW, C_ANDCON, C_NONE, C_FREG, 34, 8, 0, Mips64},
+
+ {AMOVW, C_REG, C_NONE, C_MREG, 37, 4, 0, 0},
+ {AMOVV, C_REG, C_NONE, C_MREG, 37, 4, 0, Mips64},
+ {AMOVW, C_MREG, C_NONE, C_REG, 38, 4, 0, 0},
+ {AMOVV, C_MREG, C_NONE, C_REG, 38, 4, 0, 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},
+ {AMOVW, C_FCREG, C_NONE, C_REG, 42, 4, 0, 0},
+ {AMOVV, C_FCREG, C_NONE, C_REG, 42, 4, 0, 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_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},
+ {obj.ADUFFZERO, C_NONE, C_NONE, C_LBRA, 11, 4, 0, 0}, // same as AJMP
+ {obj.ADUFFCOPY, C_NONE, C_NONE, C_LBRA, 11, 4, 0, 0}, // same as AJMP
+
+ {obj.AXXX, C_NONE, C_NONE, C_NONE, 0, 4, 0, 0},
}
var oprange [ALAST & obj.AMask][]Optab
@@ -330,7 +379,7 @@ func span0(ctxt *obj.Link, cursym *obj.LSym) {
return
}
ctxt.Cursym = cursym
- ctxt.Autosize = int32(p.To.Offset + 8)
+ ctxt.Autosize = int32(p.To.Offset + ctxt.FixedFrameSize())
if oprange[AOR&obj.AMask] == nil {
buildop(ctxt)
@@ -370,7 +419,7 @@ func span0(ctxt *obj.Link, cursym *obj.LSym) {
var q *obj.Prog
for bflag != 0 {
if ctxt.Debugvlog != 0 {
- fmt.Fprintf(ctxt.Bso, "%5.2f span1\n", obj.Cputime())
+ ctxt.Logf("%5.2f span1\n", obj.Cputime())
}
bflag = 0
c = 0
@@ -417,8 +466,9 @@ func span0(ctxt *obj.Link, cursym *obj.LSym) {
cursym.Size = c
}
-
- c += -c & (FuncAlign - 1)
+ if ctxt.Mode&Mips64 != 0 {
+ c += -c & (mips64FuncAlign - 1)
+ }
cursym.Size = c
/*
@@ -503,7 +553,7 @@ func aclass(ctxt *obj.Link, a *obj.Addr) int {
return C_LAUTO
case obj.NAME_PARAM:
- ctxt.Instoffset = int64(ctxt.Autosize) + a.Offset + 8
+ ctxt.Instoffset = int64(ctxt.Autosize) + a.Offset + ctxt.FixedFrameSize()
if ctxt.Instoffset >= -BIG && ctxt.Instoffset < BIG {
return C_SAUTO
}
@@ -567,7 +617,7 @@ func aclass(ctxt *obj.Link, a *obj.Addr) int {
return C_LACON
case obj.NAME_PARAM:
- ctxt.Instoffset = int64(ctxt.Autosize) + a.Offset + 8
+ ctxt.Instoffset = int64(ctxt.Autosize) + a.Offset + ctxt.FixedFrameSize()
if ctxt.Instoffset >= -BIG && ctxt.Instoffset < BIG {
return C_SACON
}
@@ -653,13 +703,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] {
+ if int(op.a2) == a2 && c1[op.a1] && c3[op.a3] && (ctxt.Mode&op.mode == op.mode) {
p.Optab = uint16(cap(optab) - cap(ops) + i + 1)
return op
}
}
- ctxt.Diag("illegal combination %v %v %v %v", obj.Aconv(p.As), DRconv(a1), DRconv(a2), DRconv(a3))
+ ctxt.Diag("illegal combination %v %v %v %v", p.As, DRconv(a1), DRconv(a2), DRconv(a3))
prasm(p)
if ops == nil {
ops = optab
@@ -809,7 +859,7 @@ func buildop(ctxt *obj.Link) {
switch r {
default:
- ctxt.Diag("unknown op in build: %v", obj.Aconv(r))
+ ctxt.Diag("unknown op in build: %v", r)
log.Fatalf("bad code")
case AABSF:
@@ -824,18 +874,22 @@ func buildop(ctxt *obj.Link) {
opset(AABSD, r0)
opset(ATRUNCDW, r0)
opset(ATRUNCFW, r0)
- opset(ATRUNCDV, r0)
- opset(ATRUNCFV, r0)
- opset(AMOVVF, r0)
- opset(AMOVFV, r0)
+ opset(ASQRTF, r0)
+ opset(ASQRTD, r0)
+
+ case AMOVVF:
opset(AMOVVD, r0)
+ opset(AMOVFV, r0)
opset(AMOVDV, r0)
+ opset(ATRUNCDV, r0)
+ opset(ATRUNCFV, r0)
case AADD:
opset(ASGT, r0)
opset(ASGTU, r0)
opset(AADDU, r0)
- opset(AADDV, r0)
+
+ case AADDV:
opset(AADDVU, r0)
case AADDF:
@@ -873,9 +927,10 @@ func buildop(ctxt *obj.Link) {
opset(ADIVU, r0)
opset(AMULU, r0)
opset(ADIV, r0)
+
+ case AMULV:
opset(ADIVV, r0)
opset(ADIVVU, r0)
- opset(AMULV, r0)
opset(AMULVU, r0)
opset(AREMV, r0)
opset(AREMVU, r0)
@@ -883,17 +938,20 @@ func buildop(ctxt *obj.Link) {
case ASLL:
opset(ASRL, r0)
opset(ASRA, r0)
- opset(ASLLV, r0)
+
+ case ASLLV:
opset(ASRAV, r0)
opset(ASRLV, r0)
case ASUB:
opset(ASUBU, r0)
- opset(ASUBV, r0)
- opset(ASUBVU, r0)
opset(ANOR, r0)
+ case ASUBV:
+ opset(ASUBVU, r0)
+
case ASYSCALL:
+ opset(ASYNC, r0)
opset(ATLBP, r0)
opset(ATLBR, r0)
opset(ATLBWI, r0)
@@ -911,8 +969,9 @@ func buildop(ctxt *obj.Link) {
case AMOVWL:
opset(AMOVWR, r0)
+
+ case AMOVVL:
opset(AMOVVR, r0)
- opset(AMOVVL, r0)
case AMOVW,
AMOVD,
@@ -923,6 +982,8 @@ func buildop(ctxt *obj.Link) {
AJAL,
AJMP,
AMOVWU,
+ ALL,
+ ASC,
AWORD,
obj.ANOP,
obj.ATEXT,
@@ -933,6 +994,18 @@ func buildop(ctxt *obj.Link) {
obj.ADUFFZERO,
obj.ADUFFCOPY:
break
+
+ case ACMOVN:
+ opset(ACMOVZ, r0)
+
+ case ACMOVT:
+ opset(ACMOVF, r0)
+
+ case ACLO:
+ opset(ACLZ, r0)
+
+ case ATEQ:
+ opset(ATNE, r0)
}
}
}
@@ -995,6 +1068,11 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
o3 := uint32(0)
o4 := uint32(0)
+ add := AADDU
+
+ if ctxt.Mode&Mips64 != 0 {
+ add = AADDVU
+ }
switch o.type_ {
default:
ctxt.Diag("unknown type %d %v", o.type_)
@@ -1005,10 +1083,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 {
+ if p.As == AMOVW && ctxt.Mode&Mips64 != 0 {
a = AADDU // sign-extended to high 32 bits
}
- o1 = OP_RRR(oprrr(ctxt, a), uint32(p.From.Reg), uint32(REGZERO), uint32(p.To.Reg))
+ o1 = OP_RRR(oprrr(ctxt, a), uint32(REGZERO), uint32(p.From.Reg), uint32(p.To.Reg))
case 2: /* add/sub r1,[r2],r3 */
r := int(p.Reg)
@@ -1025,7 +1103,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
if r == 0 {
r = int(o.param)
}
- a := AADDVU
+ a := add
if o.a1 == C_ANDCON {
a = AOR
}
@@ -1152,6 +1230,15 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
o1 = OP_SRR(opirr(ctxt, -ASLLV), uint32(0), uint32(p.From.Reg), uint32(p.To.Reg))
o2 = OP_SRR(opirr(ctxt, -ASRLV), uint32(0), uint32(p.To.Reg), uint32(p.To.Reg))
+ case 15: /* teq $c r,r */
+ v := regoff(ctxt, &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))
+
case 16: /* sll $c,[r1],r2 */
v := regoff(ctxt, &p.From)
r := int(p.Reg)
@@ -1166,6 +1253,9 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
o1 = OP_SRR(opirr(ctxt, 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))
+
case 18: /* jmp [r1],0(r2) */
r := int(p.Reg)
if r == 0 {
@@ -1196,8 +1286,17 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
}
o1 = OP_RRR(a, uint32(REGZERO), uint32(p.From.Reg), uint32(REGZERO))
- case 22: /* mul r1,r2 */
- o1 = OP_RRR(oprrr(ctxt, p.As), uint32(p.From.Reg), uint32(p.Reg), uint32(REGZERO))
+ case 22: /* mul r1,r2 [r3]*/
+ if p.To.Reg != 0 {
+ r := int(p.Reg)
+ if r == 0 {
+ r = int(p.To.Reg)
+ }
+ 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))
+ }
case 23: /* add $lcon,r1,r2 ==> lu+or+add */
v := regoff(ctxt, &p.From)
@@ -1230,7 +1329,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
if r == 0 {
r = int(o.param)
}
- o3 = OP_RRR(oprrr(ctxt, AADDVU), uint32(REGTMP), uint32(r), uint32(p.To.Reg))
+ o3 = OP_RRR(oprrr(ctxt, 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)
@@ -1245,7 +1344,7 @@ 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, AADDVU), uint32(r), uint32(REGTMP), 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))
case 4:
@@ -1265,7 +1364,7 @@ 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, AADDVU), uint32(r), uint32(REGTMP), 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))
case 4:
@@ -1306,7 +1405,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
r = int(o.param)
}
o1 = OP_IRR(opirr(ctxt, ALUI), uint32((v+1<<15)>>16), uint32(REGZERO), uint32(REGTMP))
- o2 = OP_RRR(oprrr(ctxt, AADDVU), uint32(r), uint32(REGTMP), uint32(REGTMP))
+ 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))
case 36: /* mov lext/auto/oreg,r ==> lw o(REGTMP) */
@@ -1316,7 +1415,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
r = int(o.param)
}
o1 = OP_IRR(opirr(ctxt, ALUI), uint32((v+1<<15)>>16), uint32(REGZERO), uint32(REGTMP))
- o2 = OP_RRR(oprrr(ctxt, AADDVU), uint32(r), uint32(REGTMP), uint32(REGTMP))
+ 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))
case 37: /* movw r,mr */
@@ -1363,15 +1462,20 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
rel.Sym = p.To.Sym
rel.Add = p.To.Offset
rel.Type = obj.R_ADDRMIPSU
- o2 = OP_RRR(oprrr(ctxt, AADDVU), uint32(REGSB), uint32(REGTMP), uint32(REGTMP))
- o3 = OP_IRR(opirr(ctxt, p.As), uint32(0), uint32(REGTMP), uint32(p.From.Reg))
+ 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 + 8)
+ rel2.Off = int32(ctxt.Pc + 4)
rel2.Siz = 4
rel2.Sym = p.To.Sym
rel2.Add = p.To.Offset
rel2.Type = obj.R_ADDRMIPS
+ if o.size == 12 {
+ o3 = o2
+ o2 = OP_RRR(oprrr(ctxt, 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)
@@ -1380,15 +1484,20 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
rel.Sym = p.From.Sym
rel.Add = p.From.Offset
rel.Type = obj.R_ADDRMIPSU
- o2 = OP_RRR(oprrr(ctxt, AADDVU), uint32(REGSB), uint32(REGTMP), uint32(REGTMP))
- o3 = OP_IRR(opirr(ctxt, -p.As), uint32(0), uint32(REGTMP), uint32(p.To.Reg))
+ 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 + 8)
+ rel2.Off = int32(ctxt.Pc + 4)
rel2.Siz = 4
rel2.Sym = p.From.Sym
rel2.Add = p.From.Offset
rel2.Type = obj.R_ADDRMIPS
+ if o.size == 12 {
+ o3 = o2
+ o2 = OP_RRR(oprrr(ctxt, 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)
@@ -1397,15 +1506,20 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
rel.Sym = p.From.Sym
rel.Add = p.From.Offset
rel.Type = obj.R_ADDRMIPSU
- o2 = OP_RRR(oprrr(ctxt, AADDVU), uint32(REGSB), uint32(p.To.Reg), uint32(p.To.Reg))
- o3 = OP_IRR(opirr(ctxt, AADDVU), uint32(0), uint32(p.To.Reg), uint32(p.To.Reg))
+ 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 + 8)
+ rel2.Off = int32(ctxt.Pc + 4)
rel2.Siz = 4
rel2.Sym = p.From.Sym
rel2.Add = p.From.Offset
rel2.Type = obj.R_ADDRMIPS
+ if o.size == 12 {
+ o3 = o2
+ o2 = OP_RRR(oprrr(ctxt, AADDVU), uint32(REGSB), uint32(p.To.Reg), uint32(p.To.Reg))
+ rel2.Off += 4
+ }
+
case 53: /* mov r, tlsvar ==> rdhwr + sw o(r3) */
// clobbers R3 !
// load thread pointer with RDHWR, R3 is used for fast kernel emulation on Linux
@@ -1432,7 +1546,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
case 55: /* mov $tlsvar, r ==> rdhwr + add */
// clobbers R3 !
o1 = (037<<26 + 073) | (29 << 11) | (3 << 16) // rdhwr $29, r3
- o2 = OP_IRR(opirr(ctxt, AADDVU), uint32(0), uint32(REG_R3), uint32(p.To.Reg))
+ 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)
rel.Siz = 4
@@ -1609,12 +1723,33 @@ func oprrr(ctxt *obj.Link, a obj.As) uint32 {
return FPF(7, 6)
case ACMPGED:
return FPD(7, 6)
+
+ case ASQRTF:
+ return FPF(0, 4)
+ case ASQRTD:
+ return FPD(0, 4)
+
+ case ASYNC:
+ return OP(1, 7)
+
+ case ACMOVN:
+ return OP(1, 3)
+ case ACMOVZ:
+ return OP(1, 2)
+ case ACMOVT:
+ return OP(0, 1) | (1 << 16)
+ case ACMOVF:
+ return OP(0, 1) | (0 << 16)
+ case ACLO:
+ return SP(3, 4) | OP(4, 1)
+ case ACLZ:
+ return SP(3, 4) | OP(4, 0)
}
if a < 0 {
- ctxt.Diag("bad rrr opcode -%v", obj.Aconv(-a))
+ ctxt.Diag("bad rrr opcode -%v", -a)
} else {
- ctxt.Diag("bad rrr opcode %v", obj.Aconv(a))
+ ctxt.Diag("bad rrr opcode %v", a)
}
return 0
}
@@ -1761,12 +1896,21 @@ func opirr(ctxt *obj.Link, a obj.As) uint32 {
return OP(7, 6)
case -ASRAV:
return OP(7, 7)
+
+ case ATEQ:
+ return OP(6, 4)
+ case ATNE:
+ return OP(6, 6)
+ case -ALL:
+ return SP(6, 0)
+ case ASC:
+ return SP(7, 0)
}
if a < 0 {
- ctxt.Diag("bad irr opcode -%v", obj.Aconv(-a))
+ ctxt.Diag("bad irr opcode -%v", -a)
} else {
- ctxt.Diag("bad irr opcode %v", obj.Aconv(a))
+ 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 28881e8..4dd5e80 100644
--- a/src/cmd/internal/obj/mips/list0.go
+++ b/src/cmd/internal/obj/mips/list0.go
@@ -35,8 +35,8 @@ import (
)
func init() {
- obj.RegisterRegister(obj.RBaseMIPS64, REG_LAST&^1023+1024, Rconv)
- obj.RegisterOpcode(obj.ABaseMIPS64, Anames)
+ obj.RegisterRegister(obj.RBaseMIPS, REG_LAST+1, Rconv)
+ obj.RegisterOpcode(obj.ABaseMIPS, Anames)
}
func Rconv(r int) string {
@@ -70,7 +70,7 @@ func Rconv(r int) string {
return "LO"
}
- return fmt.Sprintf("Rgok(%d)", r-obj.RBaseMIPS64)
+ return fmt.Sprintf("Rgok(%d)", r-obj.RBaseMIPS)
}
func DRconv(a int) string {
diff --git a/src/cmd/internal/obj/mips/obj0.go b/src/cmd/internal/obj/mips/obj0.go
index ade1ee5..221fd42 100644
--- a/src/cmd/internal/obj/mips/obj0.go
+++ b/src/cmd/internal/obj/mips/obj0.go
@@ -37,6 +37,18 @@ import (
)
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
+ }
+ }
+
p.From.Class = 0
p.To.Class = 0
@@ -58,6 +70,12 @@ func progedit(ctxt *obj.Link, p *obj.Prog) {
if p.From.Type == obj.TYPE_FCONST {
f32 := float32(p.From.Val.(float64))
i32 := math.Float32bits(f32)
+ if i32 == 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
@@ -70,6 +88,12 @@ func progedit(ctxt *obj.Link, p *obj.Prog) {
case AMOVD:
if p.From.Type == obj.TYPE_FCONST {
i64 := math.Float64bits(p.From.Val.(float64))
+ if i64 == 0 && ctxt.Mode&Mips64 != 0 {
+ 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
@@ -144,9 +168,8 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
* expand BECOME pseudo
*/
if ctxt.Debugvlog != 0 {
- fmt.Fprintf(ctxt.Bso, "%5.2f noops\n", obj.Cputime())
+ ctxt.Logf("%5.2f noops\n", obj.Cputime())
}
- ctxt.Bso.Flush()
var q *obj.Prog
var q1 *obj.Prog
@@ -260,6 +283,15 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
}
}
+ var mov, add obj.As
+ if ctxt.Mode&Mips64 != 0 {
+ add = AADDV
+ mov = AMOVV
+ } else {
+ add = AADDU
+ mov = AMOVW
+ }
+
autosize := int32(0)
var p1 *obj.Prog
var p2 *obj.Prog
@@ -267,13 +299,14 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
o := p.As
switch o {
case obj.ATEXT:
- autosize = int32(textstksiz + 8)
- if (p.Mark&LEAF != 0) && autosize <= 8 {
+ autosize = int32(textstksiz + ctxt.FixedFrameSize())
+ if (p.Mark&LEAF != 0) && autosize <= int32(ctxt.FixedFrameSize()) {
autosize = 0
- } else if autosize&4 != 0 {
+ } else if autosize&4 != 0 && ctxt.Mode&Mips64 != 0 {
autosize += 4
}
- p.To.Offset = int64(autosize) - 8
+
+ p.To.Offset = int64(autosize) - ctxt.FixedFrameSize()
if p.From3.Offset&obj.NOSPLIT == 0 {
p = stacksplit(ctxt, p, autosize) // emit split check
@@ -282,8 +315,22 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
q = p
if autosize != 0 {
- q = obj.Appendp(ctxt, p)
- q.As = AADDV
+ // Make sure to save link register for non-empty frame, even if
+ // it is a leaf function, so that traceback works.
+ // 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.As = mov
+ q.Lineno = p.Lineno
+ 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.As = add
q.Lineno = p.Lineno
q.From.Type = obj.TYPE_CONST
q.From.Offset = int64(-autosize)
@@ -293,8 +340,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
} else if cursym.Text.Mark&LEAF == 0 {
if cursym.Text.From3.Offset&obj.NOSPLIT != 0 {
if ctxt.Debugvlog != 0 {
- fmt.Fprintf(ctxt.Bso, "save suppressed in: %s\n", cursym.Name)
- ctxt.Bso.Flush()
+ ctxt.Logf("save suppressed in: %s\n", cursym.Name)
}
cursym.Text.Mark |= LEAF
@@ -302,29 +348,20 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
}
if cursym.Text.Mark&LEAF != 0 {
- cursym.Leaf = true
+ cursym.Set(obj.AttrLeaf, true)
break
}
- q = obj.Appendp(ctxt, q)
- q.As = AMOVV
- q.Lineno = p.Lineno
- q.From.Type = obj.TYPE_REG
- q.From.Reg = REGLINK
- q.To.Type = obj.TYPE_MEM
- q.To.Offset = int64(0)
- q.To.Reg = REGSP
-
if cursym.Text.From3.Offset&obj.WRAPPER != 0 {
// if(g->panic != nil && g->panic->argp == FP) g->panic->argp = bottom-of-frame
//
- // MOVV g_panic(g), R1
- // BEQ R1, end
- // MOVV panic_argp(R1), R2
- // ADDV $(autosize+8), R29, R3
- // BNE R2, R3, end
- // ADDV $8, R29, R2
- // MOVV R2, panic_argp(R1)
+ // MOV g_panic(g), R1
+ // BEQ R1, end
+ // MOV panic_argp(R1), R2
+ // ADD $(autosize+FIXED_FRAME), R29, R3
+ // BNE R2, R3, end
+ // ADD $FIXED_FRAME, R29, R2
+ // MOV R2, panic_argp(R1)
// end:
// NOP
//
@@ -333,7 +370,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
q = obj.Appendp(ctxt, q)
- q.As = AMOVV
+ q.As = mov
q.From.Type = obj.TYPE_MEM
q.From.Reg = REGG
q.From.Offset = 4 * int64(ctxt.Arch.PtrSize) // G.panic
@@ -349,7 +386,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
p1 = q
q = obj.Appendp(ctxt, q)
- q.As = AMOVV
+ q.As = mov
q.From.Type = obj.TYPE_MEM
q.From.Reg = REG_R1
q.From.Offset = 0 // Panic.argp
@@ -357,9 +394,9 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
q.To.Reg = REG_R2
q = obj.Appendp(ctxt, q)
- q.As = AADDV
+ q.As = add
q.From.Type = obj.TYPE_CONST
- q.From.Offset = int64(autosize) + 8
+ q.From.Offset = int64(autosize) + ctxt.FixedFrameSize()
q.Reg = REGSP
q.To.Type = obj.TYPE_REG
q.To.Reg = REG_R3
@@ -374,15 +411,15 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
p2 = q
q = obj.Appendp(ctxt, q)
- q.As = AADDV
+ q.As = add
q.From.Type = obj.TYPE_CONST
- q.From.Offset = 8
+ q.From.Offset = ctxt.FixedFrameSize()
q.Reg = REGSP
q.To.Type = obj.TYPE_REG
q.To.Reg = REG_R2
q = obj.Appendp(ctxt, q)
- q.As = AMOVV
+ q.As = mov
q.From.Type = obj.TYPE_REG
q.From.Reg = REG_R2
q.To.Type = obj.TYPE_MEM
@@ -402,24 +439,28 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
break
}
- if p.To.Sym != nil { // retjmp
- p.As = AJMP
- p.To.Type = obj.TYPE_BRANCH
- break
- }
+ retSym := p.To.Sym
+ 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 autosize == 0 {
p.As = AJMP
p.From = obj.Addr{}
- p.To.Type = obj.TYPE_MEM
- p.To.Offset = 0
- p.To.Reg = REGLINK
+ if retSym != nil { // retjmp
+ p.To.Type = obj.TYPE_BRANCH
+ p.To.Name = obj.NAME_EXTERN
+ p.To.Sym = retSym
+ } else {
+ p.To.Type = obj.TYPE_MEM
+ p.To.Reg = REGLINK
+ p.To.Offset = 0
+ }
p.Mark |= BRANCH
break
}
- p.As = AADDV
+ p.As = add
p.From.Type = obj.TYPE_CONST
p.From.Offset = int64(autosize)
p.To.Type = obj.TYPE_REG
@@ -440,33 +481,19 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
break
}
- p.As = AMOVV
+ p.As = mov
p.From.Type = obj.TYPE_MEM
p.From.Offset = 0
p.From.Reg = REGSP
p.To.Type = obj.TYPE_REG
p.To.Reg = REG_R4
-
- if false {
- // Debug bad returns
- q = ctxt.NewProg()
-
- q.As = AMOVV
- q.Lineno = p.Lineno
- q.From.Type = obj.TYPE_MEM
- q.From.Offset = 0
- q.From.Reg = REG_R4
- q.To.Type = obj.TYPE_REG
- q.To.Reg = REGTMP
-
- q.Link = p.Link
- p.Link = q
- p = q
+ if retSym != nil { // retjmp from non-leaf, need to restore LINK register
+ p.To.Reg = REGLINK
}
if autosize != 0 {
q = ctxt.NewProg()
- q.As = AADDV
+ q.As = add
q.Lineno = p.Lineno
q.From.Type = obj.TYPE_CONST
q.From.Offset = int64(autosize)
@@ -481,16 +508,24 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
q1 = ctxt.NewProg()
q1.As = AJMP
q1.Lineno = p.Lineno
- q1.To.Type = obj.TYPE_MEM
- q1.To.Offset = 0
- q1.To.Reg = REG_R4
+ if retSym != nil { // retjmp
+ q1.To.Type = obj.TYPE_BRANCH
+ q1.To.Name = obj.NAME_EXTERN
+ q1.To.Sym = retSym
+ } else {
+ q1.To.Type = obj.TYPE_MEM
+ q1.To.Offset = 0
+ q1.To.Reg = REG_R4
+ }
q1.Mark |= BRANCH
q1.Spadj = +autosize
q1.Link = q.Link
q.Link = q1
- case AADDV,
+ case AADD,
+ AADDU,
+ AADDV,
AADDVU:
if p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP && p.From.Type == obj.TYPE_CONST {
p.Spadj = int32(-p.From.Offset)
@@ -553,14 +588,31 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
}
func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32) *obj.Prog {
- // MOVV g_stackguard(g), R1
+ // Leaf function with no frame is effectively NOSPLIT.
+ if framesize == 0 {
+ return p
+ }
+
+ var mov, add, sub obj.As
+
+ if ctxt.Mode&Mips64 != 0 {
+ add = AADDV
+ mov = AMOVV
+ sub = ASUBVU
+ } else {
+ add = AADDU
+ mov = AMOVW
+ sub = ASUBU
+ }
+
+ // MOV g_stackguard(g), R1
p = obj.Appendp(ctxt, p)
- p.As = AMOVV
+ 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 {
+ if ctxt.Cursym.CFunc() {
p.From.Offset = 3 * int64(ctxt.Arch.PtrSize) // G.stackguard1
}
p.To.Type = obj.TYPE_REG
@@ -580,11 +632,11 @@ func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32) *obj.Prog {
p.To.Reg = REG_R1
} else if framesize <= obj.StackBig {
// large stack: SP-framesize < stackguard-StackSmall
- // ADDV $-framesize, SP, R2
+ // ADD $-framesize, SP, R2
// SGTU R2, stackguard, R1
p = obj.Appendp(ctxt, p)
- p.As = AADDV
+ p.As = add
p.From.Type = obj.TYPE_CONST
p.From.Offset = int64(-framesize)
p.Reg = REGSP
@@ -608,15 +660,15 @@ func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32) *obj.Prog {
// Preemption sets stackguard to StackPreempt, a very large value.
// That breaks the math above, so we have to check for that explicitly.
// // stackguard is R1
- // MOVV $StackPreempt, R2
+ // MOV $StackPreempt, R2
// BEQ R1, R2, label-of-call-to-morestack
- // ADDV $StackGuard, SP, R2
- // SUBVU R1, R2
- // MOVV $(framesize+(StackGuard-StackSmall)), R1
+ // ADD $StackGuard, SP, R2
+ // SUB R1, R2
+ // MOV $(framesize+(StackGuard-StackSmall)), R1
// SGTU R2, R1, R1
p = obj.Appendp(ctxt, p)
- p.As = AMOVV
+ p.As = mov
p.From.Type = obj.TYPE_CONST
p.From.Offset = obj.StackPreempt
p.To.Type = obj.TYPE_REG
@@ -632,7 +684,7 @@ func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32) *obj.Prog {
p.Mark |= BRANCH
p = obj.Appendp(ctxt, p)
- p.As = AADDV
+ p.As = add
p.From.Type = obj.TYPE_CONST
p.From.Offset = obj.StackGuard
p.Reg = REGSP
@@ -640,14 +692,14 @@ func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32) *obj.Prog {
p.To.Reg = REG_R2
p = obj.Appendp(ctxt, p)
- p.As = ASUBVU
+ 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.As = AMOVV
+ p.As = mov
p.From.Type = obj.TYPE_CONST
p.From.Offset = int64(framesize) + obj.StackGuard - obj.StackSmall
p.To.Type = obj.TYPE_REG
@@ -672,10 +724,10 @@ func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32) *obj.Prog {
p.To.Type = obj.TYPE_BRANCH
p.Mark |= BRANCH
- // MOVV LINK, R3
+ // MOV LINK, R3
p = obj.Appendp(ctxt, p)
- p.As = AMOVV
+ p.As = mov
p.From.Type = obj.TYPE_REG
p.From.Reg = REGLINK
p.To.Type = obj.TYPE_REG
@@ -690,7 +742,7 @@ func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32) *obj.Prog {
p.As = AJAL
p.To.Type = obj.TYPE_BRANCH
- if ctxt.Cursym.Cfunc {
+ 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)
@@ -1483,3 +1535,19 @@ var Linkmips64le = obj.LinkArch{
Follow: follow,
Progedit: progedit,
}
+
+var Linkmips = obj.LinkArch{
+ Arch: sys.ArchMIPS,
+ Preprocess: preprocess,
+ Assemble: span0,
+ Follow: follow,
+ Progedit: progedit,
+}
+
+var Linkmipsle = obj.LinkArch{
+ Arch: sys.ArchMIPSLE,
+ Preprocess: preprocess,
+ Assemble: span0,
+ Follow: follow,
+ Progedit: progedit,
+}
diff --git a/src/cmd/internal/obj/obj.go b/src/cmd/internal/obj/obj.go
index 3eb37b3..566263d 100644
--- a/src/cmd/internal/obj/obj.go
+++ b/src/cmd/internal/obj/obj.go
@@ -31,7 +31,6 @@ type LineHist struct {
TrimPathPrefix string // remove leading TrimPath from recorded file names
PrintFilenameOnly bool // ignore path when pretty-printing a line; internal use only
GOROOT string // current GOROOT
- GOROOT_FINAL string // target GOROOT
}
// A LineStack is an entry in the recorded line history.
diff --git a/src/cmd/internal/obj/objfile.go b/src/cmd/internal/obj/objfile.go
index a1fdee6..eb56c6f 100644
--- a/src/cmd/internal/obj/objfile.go
+++ b/src/cmd/internal/obj/objfile.go
@@ -52,7 +52,9 @@
// - type [int]
// - name & version [symref index]
// - flags [int]
-// 1 dupok
+// 1<<0 dupok
+// 1<<1 local
+// 1<<2 add to typelink table
// - size [int]
// - gotype [symref index]
// - p [data block]
@@ -109,6 +111,7 @@ package obj
import (
"bufio"
+ "cmd/internal/dwarf"
"cmd/internal/sys"
"fmt"
"log"
@@ -317,19 +320,19 @@ func (w *objWriter) writeSymDebug(s *LSym) {
if s.Type != 0 {
fmt.Fprintf(ctxt.Bso, "t=%d ", s.Type)
}
- if s.Dupok {
+ if s.DuplicateOK() {
fmt.Fprintf(ctxt.Bso, "dupok ")
}
- if s.Cfunc {
+ if s.CFunc() {
fmt.Fprintf(ctxt.Bso, "cfunc ")
}
- if s.Nosplit {
+ if s.NoSplit() {
fmt.Fprintf(ctxt.Bso, "nosplit ")
}
fmt.Fprintf(ctxt.Bso, "size=%d", s.Size)
if s.Type == STEXT {
fmt.Fprintf(ctxt.Bso, " args=%#x locals=%#x", uint64(s.Args), uint64(s.Locals))
- if s.Leaf {
+ if s.Leaf() {
fmt.Fprintf(ctxt.Bso, " leaf")
}
}
@@ -388,12 +391,15 @@ func (w *objWriter) writeSym(s *LSym) {
w.writeInt(int64(s.Type))
w.writeRefIndex(s)
flags := int64(0)
- if s.Dupok {
+ if s.DuplicateOK() {
flags |= 1
}
- if s.Local {
+ if s.Local() {
flags |= 1 << 1
}
+ if s.MakeTypelink() {
+ flags |= 1 << 2
+ }
w.writeInt(flags)
w.writeInt(s.Size)
w.writeRefIndex(s.Gotype)
@@ -416,19 +422,19 @@ func (w *objWriter) writeSym(s *LSym) {
w.writeInt(int64(s.Args))
w.writeInt(int64(s.Locals))
- if s.Nosplit {
+ if s.NoSplit() {
w.writeInt(1)
} else {
w.writeInt(0)
}
flags = int64(0)
- if s.Leaf {
+ if s.Leaf() {
flags |= 1
}
- if s.Cfunc {
+ if s.CFunc() {
flags |= 1 << 1
}
- if s.ReflectMethod {
+ if s.ReflectMethod() {
flags |= 1 << 2
}
w.writeInt(flags)
@@ -506,3 +512,94 @@ type relocByOff []Reloc
func (x relocByOff) Len() int { return len(x) }
func (x relocByOff) Less(i, j int) bool { return x[i].Off < x[j].Off }
func (x relocByOff) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
+
+// implement dwarf.Context
+type dwCtxt struct{ *Link }
+
+func (c dwCtxt) PtrSize() int {
+ return c.Arch.PtrSize
+}
+func (c dwCtxt) AddInt(s dwarf.Sym, size int, i int64) {
+ ls := s.(*LSym)
+ ls.WriteInt(c.Link, ls.Size, size, i)
+}
+func (c dwCtxt) AddBytes(s dwarf.Sym, b []byte) {
+ ls := s.(*LSym)
+ ls.WriteBytes(c.Link, ls.Size, b)
+}
+func (c dwCtxt) AddString(s dwarf.Sym, v string) {
+ ls := s.(*LSym)
+ ls.WriteString(c.Link, ls.Size, len(v), v)
+ ls.WriteInt(c.Link, ls.Size, 1, 0)
+}
+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)
+}
+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
+}
+
+func gendwarf(ctxt *Link, text []*LSym) []*LSym {
+ dctxt := dwCtxt{ctxt}
+ var dw []*LSym
+
+ 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)
+ }
+ return dw
+}
diff --git a/src/cmd/internal/obj/pass.go b/src/cmd/internal/obj/pass.go
index ffbff74..1d2f74b 100644
--- a/src/cmd/internal/obj/pass.go
+++ b/src/cmd/internal/obj/pass.go
@@ -1,5 +1,5 @@
// Inferno utils/6l/pass.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6l/pass.c
+// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/pass.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth at terzarima.net)
diff --git a/src/cmd/internal/obj/pcln.go b/src/cmd/internal/obj/pcln.go
index b1536eb..d9893e4 100644
--- a/src/cmd/internal/obj/pcln.go
+++ b/src/cmd/internal/obj/pcln.go
@@ -4,10 +4,7 @@
package obj
-import (
- "fmt"
- "log"
-)
+import "log"
func addvarint(ctxt *Link, d *Pcdata, val uint32) {
var v uint32
@@ -28,18 +25,19 @@ func addvarint(ctxt *Link, d *Pcdata, val 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 second line and change name.
+ // To debug a specific function, uncomment lines and change name.
dbg := 0
- //dbg = strcmp(func->name, "main.main") == 0;
- //dbg = strcmp(desc, "pctofile") == 0;
+ //if func_.Name == "main.main" || desc == "pctospadj" {
+ // dbg = 1
+ //}
ctxt.Debugpcln += int32(dbg)
dst.P = dst.P[:0]
if ctxt.Debugpcln != 0 {
- fmt.Fprintf(ctxt.Bso, "funcpctab %s [valfunc=%s]\n", func_.Name, desc)
+ ctxt.Logf("funcpctab %s [valfunc=%s]\n", func_.Name, desc)
}
val := int32(-1)
@@ -52,7 +50,7 @@ func funcpctab(ctxt *Link, dst *Pcdata, func_ *LSym, desc string, valfunc func(*
pc := func_.Text.Pc
if ctxt.Debugpcln != 0 {
- fmt.Fprintf(ctxt.Bso, "%6x %6d %v\n", uint64(pc), val, func_.Text)
+ ctxt.Logf("%6x %6d %v\n", uint64(pc), val, func_.Text)
}
started := int32(0)
@@ -64,7 +62,7 @@ func funcpctab(ctxt *Link, dst *Pcdata, func_ *LSym, desc string, valfunc func(*
if val == oldval && started != 0 {
val = valfunc(ctxt, func_, val, p, 1, arg)
if ctxt.Debugpcln != 0 {
- fmt.Fprintf(ctxt.Bso, "%6x %6s %v\n", uint64(p.Pc), "", p)
+ ctxt.Logf("%6x %6s %v\n", uint64(p.Pc), "", p)
}
continue
}
@@ -76,7 +74,7 @@ func funcpctab(ctxt *Link, dst *Pcdata, func_ *LSym, desc string, valfunc func(*
if p.Link != nil && p.Link.Pc == p.Pc {
val = valfunc(ctxt, func_, val, p, 1, arg)
if ctxt.Debugpcln != 0 {
- fmt.Fprintf(ctxt.Bso, "%6x %6s %v\n", uint64(p.Pc), "", p)
+ ctxt.Logf("%6x %6s %v\n", uint64(p.Pc), "", p)
}
continue
}
@@ -96,7 +94,7 @@ func funcpctab(ctxt *Link, dst *Pcdata, func_ *LSym, desc string, valfunc func(*
// where the 0x80 bit indicates that the integer continues.
if ctxt.Debugpcln != 0 {
- fmt.Fprintf(ctxt.Bso, "%6x %6d %v\n", uint64(p.Pc), val, p)
+ ctxt.Logf("%6x %6d %v\n", uint64(p.Pc), val, p)
}
if started != 0 {
@@ -118,18 +116,18 @@ func funcpctab(ctxt *Link, dst *Pcdata, func_ *LSym, desc string, valfunc func(*
if started != 0 {
if ctxt.Debugpcln != 0 {
- fmt.Fprintf(ctxt.Bso, "%6x done\n", uint64(func_.Text.Pc+func_.Size))
+ ctxt.Logf("%6x done\n", uint64(func_.Text.Pc+func_.Size))
}
addvarint(ctxt, dst, uint32((func_.Size-pc)/int64(ctxt.Arch.MinLC)))
addvarint(ctxt, dst, 0) // terminator
}
if ctxt.Debugpcln != 0 {
- fmt.Fprintf(ctxt.Bso, "wrote %d bytes to %p\n", len(dst.P), dst)
+ ctxt.Logf("wrote %d bytes to %p\n", len(dst.P), dst)
for i := 0; i < len(dst.P); i++ {
- fmt.Fprintf(ctxt.Bso, " %02x", dst.P[i])
+ ctxt.Logf(" %02x", dst.P[i])
}
- fmt.Fprintf(ctxt.Bso, "\n")
+ ctxt.Logf("\n")
}
ctxt.Debugpcln -= int32(dbg)
@@ -217,9 +215,15 @@ func linkpcln(ctxt *Link, cursym *LSym) {
npcdata := 0
nfuncdata := 0
for p := cursym.Text; p != nil; p = p.Link {
- if p.As == APCDATA && p.From.Offset >= int64(npcdata) {
+ // 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
+ // To.Offset is data
+ if p.As == APCDATA && p.From.Offset >= int64(npcdata) && p.To.Offset != -1 { // ignore -1 as we start at -1, if we only see -1, nothing changed
npcdata = int(p.From.Offset + 1)
}
+ // Find the highest ID of any FUNCDATA table.
+ // From.Offset is table ID
if p.As == AFUNCDATA && p.From.Offset >= int64(nfuncdata) {
nfuncdata = int(p.From.Offset + 1)
}
@@ -246,7 +250,7 @@ func linkpcln(ctxt *Link, cursym *LSym) {
havefunc[p.From.Offset/32] |= 1 << uint64(p.From.Offset%32)
}
- if p.As == APCDATA {
+ if p.As == APCDATA && p.To.Offset != -1 {
havepc[p.From.Offset/32] |= 1 << uint64(p.From.Offset%32)
}
}
diff --git a/src/cmd/internal/obj/plist.go b/src/cmd/internal/obj/plist.go
index e55dbec..804ea63 100644
--- a/src/cmd/internal/obj/plist.go
+++ b/src/cmd/internal/obj/plist.go
@@ -11,10 +11,7 @@ import (
)
type Plist struct {
- Name *LSym
Firstpc *Prog
- Recur int
- Link *Plist
}
/*
@@ -22,12 +19,7 @@ type Plist struct {
*/
func Linknewplist(ctxt *Link) *Plist {
pl := new(Plist)
- if ctxt.Plist == nil {
- ctxt.Plist = pl
- } else {
- ctxt.Plast.Link = pl
- }
- ctxt.Plast = pl
+ ctxt.Plists = append(ctxt.Plists, pl)
return pl
}
@@ -45,7 +37,7 @@ func flushplist(ctxt *Link, freeProgs bool) {
var etext *Prog
var text []*LSym
- for pl := ctxt.Plist; pl != nil; pl = pl.Link {
+ for _, pl := range ctxt.Plists {
var plink *Prog
for p := pl.Firstpc; p != nil; p = plink {
if ctxt.Debugasm != 0 && ctxt.Debugvlog != 0 {
@@ -77,39 +69,11 @@ func flushplist(ctxt *Link, freeProgs bool) {
a.Asym = p.From.Sym
a.Aoffset = int32(p.From.Offset)
a.Name = int16(p.From.Name)
- a.Gotype = p.From.Gotype
+ a.Gotype = p.To.Sym
a.Link = curtext.Autom
curtext.Autom = a
continue
- case AGLOBL:
- s := p.From.Sym
- if s.Seenglobl {
- fmt.Printf("duplicate %v\n", p)
- }
- s.Seenglobl = true
- if s.Onlist {
- log.Fatalf("symbol %s listed multiple times", s.Name)
- }
- s.Onlist = true
- ctxt.Data = append(ctxt.Data, s)
- s.Size = p.To.Offset
- if s.Type == 0 || s.Type == SXREF {
- s.Type = SBSS
- }
- flag := int(p.From3.Offset)
- if flag&DUPOK != 0 {
- s.Dupok = true
- }
- if flag&RODATA != 0 {
- s.Type = SRODATA
- } else if flag&NOPTR != 0 {
- s.Type = SNOPTRBSS
- } else if flag&TLSBSS != 0 {
- s.Type = STLSBSS
- }
- continue
-
case ATEXT:
s := p.From.Sym
if s == nil {
@@ -122,20 +86,20 @@ func flushplist(ctxt *Link, freeProgs bool) {
if s.Text != nil {
log.Fatalf("duplicate TEXT for %s", s.Name)
}
- if s.Onlist {
+ if s.OnList() {
log.Fatalf("symbol %s listed multiple times", s.Name)
}
- s.Onlist = true
+ s.Set(AttrOnList, true)
text = append(text, s)
flag := int(p.From3Offset())
if flag&DUPOK != 0 {
- s.Dupok = true
+ s.Set(AttrDuplicateOK, true)
}
if flag&NOSPLIT != 0 {
- s.Nosplit = true
+ s.Set(AttrNoSplit, true)
}
if flag&REFLECTMETHOD != 0 {
- s.ReflectMethod = true
+ s.Set(AttrReflectMethod, true)
}
s.Type = STEXT
s.Text = p
@@ -209,10 +173,36 @@ func flushplist(ctxt *Link, freeProgs bool) {
// Add to running list in ctxt.
ctxt.Text = append(ctxt.Text, text...)
- ctxt.Plist = nil
- ctxt.Plast = nil
+ ctxt.Data = append(ctxt.Data, gendwarf(ctxt, text)...)
+ ctxt.Plists = nil
ctxt.Curp = nil
if freeProgs {
ctxt.freeProgs()
}
}
+
+func (ctxt *Link) Globl(s *LSym, size int64, flag int) {
+ if s.SeenGlobl() {
+ fmt.Printf("duplicate %v\n", s)
+ }
+ s.Set(AttrSeenGlobl, true)
+ if s.OnList() {
+ log.Fatalf("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 flag&DUPOK != 0 {
+ s.Set(AttrDuplicateOK, true)
+ }
+ if flag&RODATA != 0 {
+ s.Type = SRODATA
+ } else if flag&NOPTR != 0 {
+ s.Type = SNOPTRBSS
+ } else if flag&TLSBSS != 0 {
+ s.Type = STLSBSS
+ }
+}
diff --git a/src/cmd/internal/obj/ppc64/a.out.go b/src/cmd/internal/obj/ppc64/a.out.go
index 8e58c59..6078131 100644
--- a/src/cmd/internal/obj/ppc64/a.out.go
+++ b/src/cmd/internal/obj/ppc64/a.out.go
@@ -44,6 +44,8 @@ const (
)
const (
+ /* RBasePPC64 = 4096 */
+ /* R0=4096 ... R31=4127 */
REG_R0 = obj.RBasePPC64 + iota
REG_R1
REG_R2
@@ -77,6 +79,7 @@ const (
REG_R30
REG_R31
+ /* F0=4128 ... F31=4159 */
REG_F0
REG_F1
REG_F2
@@ -110,6 +113,106 @@ const (
REG_F30
REG_F31
+ /* V0=4160 ... V31=4191 */
+ REG_V0
+ REG_V1
+ REG_V2
+ REG_V3
+ REG_V4
+ REG_V5
+ REG_V6
+ REG_V7
+ REG_V8
+ REG_V9
+ REG_V10
+ REG_V11
+ REG_V12
+ REG_V13
+ REG_V14
+ REG_V15
+ REG_V16
+ REG_V17
+ REG_V18
+ REG_V19
+ REG_V20
+ REG_V21
+ REG_V22
+ REG_V23
+ REG_V24
+ REG_V25
+ REG_V26
+ REG_V27
+ REG_V28
+ REG_V29
+ REG_V30
+ REG_V31
+
+ /* VS0=4192 ... VS63=4255 */
+ REG_VS0
+ REG_VS1
+ REG_VS2
+ REG_VS3
+ REG_VS4
+ REG_VS5
+ REG_VS6
+ REG_VS7
+ REG_VS8
+ REG_VS9
+ REG_VS10
+ REG_VS11
+ REG_VS12
+ REG_VS13
+ REG_VS14
+ REG_VS15
+ REG_VS16
+ REG_VS17
+ REG_VS18
+ REG_VS19
+ REG_VS20
+ REG_VS21
+ REG_VS22
+ REG_VS23
+ REG_VS24
+ REG_VS25
+ REG_VS26
+ REG_VS27
+ REG_VS28
+ REG_VS29
+ REG_VS30
+ REG_VS31
+ REG_VS32
+ REG_VS33
+ REG_VS34
+ REG_VS35
+ REG_VS36
+ REG_VS37
+ REG_VS38
+ REG_VS39
+ REG_VS40
+ REG_VS41
+ REG_VS42
+ REG_VS43
+ REG_VS44
+ REG_VS45
+ REG_VS46
+ REG_VS47
+ REG_VS48
+ REG_VS49
+ REG_VS50
+ REG_VS51
+ REG_VS52
+ REG_VS53
+ REG_VS54
+ REG_VS55
+ REG_VS56
+ REG_VS57
+ REG_VS58
+ REG_VS59
+ REG_VS60
+ REG_VS61
+ REG_VS62
+ REG_VS63
+
REG_CR0
REG_CR1
REG_CR2
@@ -132,29 +235,24 @@ const (
REG_LR = REG_SPR0 + 8
REG_CTR = REG_SPR0 + 9
- REGZERO = REG_R0 /* set to zero */
- REGSP = REG_R1
- REGSB = REG_R2
- REGRET = REG_R3
- REGARG = -1 /* -1 disables passing the first argument in register */
- REGRT1 = REG_R3 /* reserved for runtime, duffzero and duffcopy */
- REGRT2 = REG_R4 /* reserved for runtime, duffcopy */
- REGMIN = REG_R7 /* register variables allocated from here to REGMAX */
- REGCTXT = REG_R11 /* context for closures */
- REGTLS = REG_R13 /* C ABI TLS base pointer */
- REGMAX = REG_R27
- REGEXT = REG_R30 /* external registers allocated from here down */
- REGG = REG_R30 /* G */
- REGTMP = REG_R31 /* used by the linker */
- FREGRET = REG_F0
- FREGMIN = REG_F17 /* first register variable */
- FREGMAX = REG_F26 /* last register variable for 9g only */
- FREGEXT = REG_F26 /* first external register */
- FREGCVI = REG_F27 /* floating conversion constant */
- FREGZERO = REG_F28 /* both float and double */
- FREGHALF = REG_F29 /* double */
- FREGONE = REG_F30 /* double */
- FREGTWO = REG_F31 /* double */
+ REGZERO = REG_R0 /* set to zero */
+ REGSP = REG_R1
+ REGSB = REG_R2
+ REGRET = REG_R3
+ REGARG = -1 /* -1 disables passing the first argument in register */
+ REGRT1 = REG_R3 /* reserved for runtime, duffzero and duffcopy */
+ REGRT2 = REG_R4 /* reserved for runtime, duffcopy */
+ REGMIN = REG_R7 /* register variables allocated from here to REGMAX */
+ REGCTXT = REG_R11 /* context for closures */
+ REGTLS = REG_R13 /* C ABI TLS base pointer */
+ REGMAX = REG_R27
+ REGEXT = REG_R30 /* external registers allocated from here down */
+ REGG = REG_R30 /* G */
+ REGTMP = REG_R31 /* used by the linker */
+ FREGRET = REG_F0
+ FREGMIN = REG_F17 /* first register variable */
+ FREGMAX = REG_F26 /* last register variable for 9g only */
+ FREGEXT = REG_F26 /* first external register */
)
/*
@@ -185,10 +283,58 @@ const (
NOSCHED = 1 << 9
)
+// Values for use in branch instruction BC
+// BC B0,BI,label
+// BO is type of branch + likely bits described below
+// BI is CR value + branch type
+// ex: BEQ CR2,label is BC 12,10,label
+// 12 = BO_BCR
+// 10 = BI_CR2 + BI_EQ
+
+const (
+ BI_CR0 = 0
+ BI_CR1 = 4
+ BI_CR2 = 8
+ BI_CR3 = 12
+ BI_CR4 = 16
+ BI_CR5 = 20
+ BI_CR6 = 24
+ BI_CR7 = 28
+ BI_LT = 0
+ BI_GT = 1
+ BI_EQ = 2
+ BI_OVF = 3
+)
+
+// Values for the BO field. Add the branch type to
+// the likely bits, if a likely setting is known.
+// If branch likely or unlikely is not known, don't set it.
+// e.g. branch on cr+likely = 15
+
+const (
+ BO_BCTR = 16 // branch on ctr value
+ BO_BCR = 12 // branch on cr value
+ BO_BCRBCTR = 8 // branch on ctr and cr value
+ BO_NOTBCR = 4 // branch on not cr value
+ BO_UNLIKELY = 2 // value for unlikely
+ BO_LIKELY = 3 // value for likely
+)
+
+// Bit settings from the CR
+
+const (
+ C_COND_LT = iota // 0 result is negative
+ C_COND_GT // 1 result is positive
+ C_COND_EQ // 2 result is zero
+ C_COND_SO // 3 summary overflow or FP compare w/ NaN
+)
+
const (
C_NONE = iota
C_REG
C_FREG
+ C_VREG
+ C_VSREG
C_CREG
C_SPR /* special processor register */
C_ZCON
@@ -210,8 +356,8 @@ const (
C_LAUTO
C_SEXT
C_LEXT
- C_ZOREG
- C_SOREG
+ C_ZOREG // conjecture: either (1) register + zeroed offset, or (2) "R0" implies zero or C_REG
+ C_SOREG // register + signed offset
C_LOREG
C_FPSCR
C_MSR
@@ -257,13 +403,13 @@ const (
ABC
ABCL
ABEQ
- ABGE
+ ABGE // not LT = G/E/U
ABGT
- ABLE
+ ABLE // not GT = L/E/U
ABLT
- ABNE
- ABVC
- ABVS
+ ABNE // not EQ = L/G/U
+ ABVC // Unordered-clear
+ ABVS // Unordered-set
ACMP
ACMPU
ACNTLZW
@@ -315,6 +461,8 @@ const (
AFMOVDU
AFMOVS
AFMOVSU
+ AFMOVSX
+ AFMOVSZ
AFMSUB
AFMSUBCC
AFMSUBS
@@ -341,11 +489,13 @@ const (
AFSUBCC
AFSUBS
AFSUBSCC
+ AISEL
AMOVMW
ALBAR
ALSW
ALWAR
ALWSYNC
+ AMOVDBR
AMOVWBR
AMOVB
AMOVBU
@@ -455,6 +605,12 @@ const (
/* optional on 32-bit */
AFRES
AFRESCC
+ AFRIM
+ AFRIMCC
+ AFRIP
+ AFRIPCC
+ AFRIZ
+ AFRIZCC
AFRSQRTE
AFRSQRTECC
AFSEL
@@ -472,6 +628,10 @@ const (
ACMPWU
ADIVD
ADIVDCC
+ ADIVDE
+ ADIVDECC
+ ADIVDEU
+ ADIVDEUCC
ADIVDVCC
ADIVDV
ADIVDU
@@ -505,12 +665,18 @@ const (
ARFID
ARLDMI
ARLDMICC
+ ARLDIMI
+ ARLDIMICC
ARLDC
ARLDCCC
ARLDCR
ARLDCRCC
+ ARLDICR
+ ARLDICRCC
ARLDCL
ARLDCLCC
+ ARLDICL
+ ARLDICLCC
ASLBIA
ASLBIE
ASLBMFEE
@@ -539,6 +705,234 @@ const (
/* more 64-bit operations */
AHRFID
+ /* Vector */
+ ALV
+ ALVEBX
+ ALVEHX
+ ALVEWX
+ ALVX
+ ALVXL
+ ALVSL
+ ALVSR
+ ASTV
+ ASTVEBX
+ ASTVEHX
+ ASTVEWX
+ ASTVX
+ ASTVXL
+ AVAND
+ AVANDL
+ AVANDC
+ AVNAND
+ AVOR
+ AVORL
+ AVORC
+ AVNOR
+ AVXOR
+ AVEQV
+ AVADDUM
+ AVADDUBM
+ AVADDUHM
+ AVADDUWM
+ AVADDUDM
+ AVADDUQM
+ AVADDCU
+ AVADDCUQ
+ AVADDCUW
+ AVADDUS
+ AVADDUBS
+ AVADDUHS
+ AVADDUWS
+ AVADDSS
+ AVADDSBS
+ AVADDSHS
+ AVADDSWS
+ AVADDE
+ AVADDEUQM
+ AVADDECUQ
+ AVSUBUM
+ AVSUBUBM
+ AVSUBUHM
+ AVSUBUWM
+ AVSUBUDM
+ AVSUBUQM
+ AVSUBCU
+ AVSUBCUQ
+ AVSUBCUW
+ AVSUBUS
+ AVSUBUBS
+ AVSUBUHS
+ AVSUBUWS
+ AVSUBSS
+ AVSUBSBS
+ AVSUBSHS
+ AVSUBSWS
+ AVSUBE
+ AVSUBEUQM
+ AVSUBECUQ
+ AVR
+ AVRLB
+ AVRLH
+ AVRLW
+ AVRLD
+ AVS
+ AVSLB
+ AVSLH
+ AVSLW
+ AVSL
+ AVSLO
+ AVSRB
+ AVSRH
+ AVSRW
+ AVSR
+ AVSRO
+ AVSLD
+ AVSRD
+ AVSA
+ AVSRAB
+ AVSRAH
+ AVSRAW
+ AVSRAD
+ AVSOI
+ AVSLDOI
+ AVCLZ
+ AVCLZB
+ AVCLZH
+ AVCLZW
+ AVCLZD
+ AVPOPCNT
+ AVPOPCNTB
+ AVPOPCNTH
+ AVPOPCNTW
+ AVPOPCNTD
+ AVCMPEQ
+ AVCMPEQUB
+ AVCMPEQUBCC
+ AVCMPEQUH
+ AVCMPEQUHCC
+ AVCMPEQUW
+ AVCMPEQUWCC
+ AVCMPEQUD
+ AVCMPEQUDCC
+ AVCMPGT
+ AVCMPGTUB
+ AVCMPGTUBCC
+ AVCMPGTUH
+ AVCMPGTUHCC
+ AVCMPGTUW
+ AVCMPGTUWCC
+ AVCMPGTUD
+ AVCMPGTUDCC
+ AVCMPGTSB
+ AVCMPGTSBCC
+ AVCMPGTSH
+ AVCMPGTSHCC
+ AVCMPGTSW
+ AVCMPGTSWCC
+ AVCMPGTSD
+ AVCMPGTSDCC
+ AVPERM
+ AVSEL
+ AVSPLT
+ AVSPLTB
+ AVSPLTH
+ AVSPLTW
+ AVSPLTI
+ AVSPLTISB
+ AVSPLTISH
+ AVSPLTISW
+ AVCIPH
+ AVCIPHER
+ AVCIPHERLAST
+ AVNCIPH
+ AVNCIPHER
+ AVNCIPHERLAST
+ AVSBOX
+ AVSHASIGMA
+ AVSHASIGMAW
+ AVSHASIGMAD
+
+ /* VSX */
+ ALXV
+ ALXVD2X
+ ALXVDSX
+ ALXVW4X
+ ASTXV
+ ASTXVD2X
+ ASTXVW4X
+ ALXS
+ ALXSDX
+ ASTXS
+ ASTXSDX
+ ALXSI
+ ALXSIWAX
+ ALXSIWZX
+ ASTXSI
+ ASTXSIWX
+ AMFVSR
+ AMFVSRD
+ AMFVSRWZ
+ AMTVSR
+ AMTVSRD
+ AMTVSRWA
+ AMTVSRWZ
+ AXXLAND
+ AXXLANDQ
+ AXXLANDC
+ AXXLEQV
+ AXXLNAND
+ AXXLOR
+ AXXLORC
+ AXXLNOR
+ AXXLORQ
+ AXXLXOR
+ AXXSEL
+ AXXMRG
+ AXXMRGHW
+ AXXMRGLW
+ AXXSPLT
+ AXXSPLTW
+ AXXPERM
+ AXXPERMDI
+ AXXSI
+ AXXSLDWI
+ AXSCV
+ AXSCVDPSP
+ AXSCVSPDP
+ AXSCVDPSPN
+ AXSCVSPDPN
+ AXVCV
+ AXVCVDPSP
+ AXVCVSPDP
+ AXSCVX
+ AXSCVDPSXDS
+ AXSCVDPSXWS
+ AXSCVDPUXDS
+ AXSCVDPUXWS
+ AXSCVXP
+ AXSCVSXDDP
+ AXSCVUXDDP
+ AXSCVSXDSP
+ AXSCVUXDSP
+ AXVCVX
+ AXVCVDPSXDS
+ AXVCVDPSXWS
+ AXVCVDPUXDS
+ AXVCVDPUXWS
+ AXVCVSPSXDS
+ AXVCVSPSXWS
+ AXVCVSPUXDS
+ AXVCVSPUXWS
+ AXVCVXP
+ AXVCVSXDDP
+ AXVCVSXWDP
+ AXVCVUXDDP
+ AXVCVUXWDP
+ AXVCVSXDSP
+ AXVCVSXWSP
+ AXVCVUXDSP
+ AXVCVUXWSP
+
ALAST
// aliases
diff --git a/src/cmd/internal/obj/ppc64/anames.go b/src/cmd/internal/obj/ppc64/anames.go
index eb42c9a..19ddd3c 100644
--- a/src/cmd/internal/obj/ppc64/anames.go
+++ b/src/cmd/internal/obj/ppc64/anames.go
@@ -91,6 +91,8 @@ var Anames = []string{
"FMOVDU",
"FMOVS",
"FMOVSU",
+ "FMOVSX",
+ "FMOVSZ",
"FMSUB",
"FMSUBCC",
"FMSUBS",
@@ -117,11 +119,13 @@ var Anames = []string{
"FSUBCC",
"FSUBS",
"FSUBSCC",
+ "ISEL",
"MOVMW",
"LBAR",
"LSW",
"LWAR",
"LWSYNC",
+ "MOVDBR",
"MOVWBR",
"MOVB",
"MOVBU",
@@ -226,6 +230,12 @@ var Anames = []string{
"RFCI",
"FRES",
"FRESCC",
+ "FRIM",
+ "FRIMCC",
+ "FRIP",
+ "FRIPCC",
+ "FRIZ",
+ "FRIZCC",
"FRSQRTE",
"FRSQRTECC",
"FSEL",
@@ -240,6 +250,10 @@ var Anames = []string{
"CMPWU",
"DIVD",
"DIVDCC",
+ "DIVDE",
+ "DIVDECC",
+ "DIVDEU",
+ "DIVDEUCC",
"DIVDVCC",
"DIVDV",
"DIVDU",
@@ -272,12 +286,18 @@ var Anames = []string{
"RFID",
"RLDMI",
"RLDMICC",
+ "RLDIMI",
+ "RLDIMICC",
"RLDC",
"RLDCCC",
"RLDCR",
"RLDCRCC",
+ "RLDICR",
+ "RLDICRCC",
"RLDCL",
"RLDCLCC",
+ "RLDICL",
+ "RLDICLCC",
"SLBIA",
"SLBIE",
"SLBMFEE",
@@ -301,5 +321,229 @@ var Anames = []string{
"REMDUV",
"REMDUVCC",
"HRFID",
+ "LV",
+ "LVEBX",
+ "LVEHX",
+ "LVEWX",
+ "LVX",
+ "LVXL",
+ "LVSL",
+ "LVSR",
+ "STV",
+ "STVEBX",
+ "STVEHX",
+ "STVEWX",
+ "STVX",
+ "STVXL",
+ "VAND",
+ "VANDL",
+ "VANDC",
+ "VNAND",
+ "VOR",
+ "VORL",
+ "VORC",
+ "VNOR",
+ "VXOR",
+ "VEQV",
+ "VADDUM",
+ "VADDUBM",
+ "VADDUHM",
+ "VADDUWM",
+ "VADDUDM",
+ "VADDUQM",
+ "VADDCU",
+ "VADDCUQ",
+ "VADDCUW",
+ "VADDUS",
+ "VADDUBS",
+ "VADDUHS",
+ "VADDUWS",
+ "VADDSS",
+ "VADDSBS",
+ "VADDSHS",
+ "VADDSWS",
+ "VADDE",
+ "VADDEUQM",
+ "VADDECUQ",
+ "VSUBUM",
+ "VSUBUBM",
+ "VSUBUHM",
+ "VSUBUWM",
+ "VSUBUDM",
+ "VSUBUQM",
+ "VSUBCU",
+ "VSUBCUQ",
+ "VSUBCUW",
+ "VSUBUS",
+ "VSUBUBS",
+ "VSUBUHS",
+ "VSUBUWS",
+ "VSUBSS",
+ "VSUBSBS",
+ "VSUBSHS",
+ "VSUBSWS",
+ "VSUBE",
+ "VSUBEUQM",
+ "VSUBECUQ",
+ "VR",
+ "VRLB",
+ "VRLH",
+ "VRLW",
+ "VRLD",
+ "VS",
+ "VSLB",
+ "VSLH",
+ "VSLW",
+ "VSL",
+ "VSLO",
+ "VSRB",
+ "VSRH",
+ "VSRW",
+ "VSR",
+ "VSRO",
+ "VSLD",
+ "VSRD",
+ "VSA",
+ "VSRAB",
+ "VSRAH",
+ "VSRAW",
+ "VSRAD",
+ "VSOI",
+ "VSLDOI",
+ "VCLZ",
+ "VCLZB",
+ "VCLZH",
+ "VCLZW",
+ "VCLZD",
+ "VPOPCNT",
+ "VPOPCNTB",
+ "VPOPCNTH",
+ "VPOPCNTW",
+ "VPOPCNTD",
+ "VCMPEQ",
+ "VCMPEQUB",
+ "VCMPEQUBCC",
+ "VCMPEQUH",
+ "VCMPEQUHCC",
+ "VCMPEQUW",
+ "VCMPEQUWCC",
+ "VCMPEQUD",
+ "VCMPEQUDCC",
+ "VCMPGT",
+ "VCMPGTUB",
+ "VCMPGTUBCC",
+ "VCMPGTUH",
+ "VCMPGTUHCC",
+ "VCMPGTUW",
+ "VCMPGTUWCC",
+ "VCMPGTUD",
+ "VCMPGTUDCC",
+ "VCMPGTSB",
+ "VCMPGTSBCC",
+ "VCMPGTSH",
+ "VCMPGTSHCC",
+ "VCMPGTSW",
+ "VCMPGTSWCC",
+ "VCMPGTSD",
+ "VCMPGTSDCC",
+ "VPERM",
+ "VSEL",
+ "VSPLT",
+ "VSPLTB",
+ "VSPLTH",
+ "VSPLTW",
+ "VSPLTI",
+ "VSPLTISB",
+ "VSPLTISH",
+ "VSPLTISW",
+ "VCIPH",
+ "VCIPHER",
+ "VCIPHERLAST",
+ "VNCIPH",
+ "VNCIPHER",
+ "VNCIPHERLAST",
+ "VSBOX",
+ "VSHASIGMA",
+ "VSHASIGMAW",
+ "VSHASIGMAD",
+ "LXV",
+ "LXVD2X",
+ "LXVDSX",
+ "LXVW4X",
+ "STXV",
+ "STXVD2X",
+ "STXVW4X",
+ "LXS",
+ "LXSDX",
+ "STXS",
+ "STXSDX",
+ "LXSI",
+ "LXSIWAX",
+ "LXSIWZX",
+ "STXSI",
+ "STXSIWX",
+ "MFVSR",
+ "MFVSRD",
+ "MFVSRWZ",
+ "MTVSR",
+ "MTVSRD",
+ "MTVSRWA",
+ "MTVSRWZ",
+ "XXLAND",
+ "XXLANDQ",
+ "XXLANDC",
+ "XXLEQV",
+ "XXLNAND",
+ "XXLOR",
+ "XXLORC",
+ "XXLNOR",
+ "XXLORQ",
+ "XXLXOR",
+ "XXSEL",
+ "XXMRG",
+ "XXMRGHW",
+ "XXMRGLW",
+ "XXSPLT",
+ "XXSPLTW",
+ "XXPERM",
+ "XXPERMDI",
+ "XXSI",
+ "XXSLDWI",
+ "XSCV",
+ "XSCVDPSP",
+ "XSCVSPDP",
+ "XSCVDPSPN",
+ "XSCVSPDPN",
+ "XVCV",
+ "XVCVDPSP",
+ "XVCVSPDP",
+ "XSCVX",
+ "XSCVDPSXDS",
+ "XSCVDPSXWS",
+ "XSCVDPUXDS",
+ "XSCVDPUXWS",
+ "XSCVXP",
+ "XSCVSXDDP",
+ "XSCVUXDDP",
+ "XSCVSXDSP",
+ "XSCVUXDSP",
+ "XVCVX",
+ "XVCVDPSXDS",
+ "XVCVDPSXWS",
+ "XVCVDPUXDS",
+ "XVCVDPUXWS",
+ "XVCVSPSXDS",
+ "XVCVSPSXWS",
+ "XVCVSPUXDS",
+ "XVCVSPUXWS",
+ "XVCVXP",
+ "XVCVSXDDP",
+ "XVCVSXWDP",
+ "XVCVUXDDP",
+ "XVCVUXWDP",
+ "XVCVSXDSP",
+ "XVCVSXWSP",
+ "XVCVUXDSP",
+ "XVCVUXWSP",
"LAST",
}
diff --git a/src/cmd/internal/obj/ppc64/anames9.go b/src/cmd/internal/obj/ppc64/anames9.go
index f7d1d77..6ec7b7b 100644
--- a/src/cmd/internal/obj/ppc64/anames9.go
+++ b/src/cmd/internal/obj/ppc64/anames9.go
@@ -8,6 +8,8 @@ var cnames9 = []string{
"NONE",
"REG",
"FREG",
+ "VREG",
+ "VSREG",
"CREG",
"SPR",
"ZCON",
diff --git a/src/cmd/internal/obj/ppc64/asm9.go b/src/cmd/internal/obj/ppc64/asm9.go
index 5366809..4f86554 100644
--- a/src/cmd/internal/obj/ppc64/asm9.go
+++ b/src/cmd/internal/obj/ppc64/asm9.go
@@ -40,7 +40,7 @@ import (
// Instruction layout.
const (
- FuncAlign = 8
+ funcAlign = 8
)
const (
@@ -48,12 +48,12 @@ const (
)
type Optab struct {
- as obj.As
+ as obj.As // Opcode
a1 uint8
a2 uint8
a3 uint8
a4 uint8
- type_ int8
+ type_ int8 // cases in asmout below. E.g., 44 = st r,(ra+rb); 45 = ld (ra+rb), r
size int8
param int16
}
@@ -139,15 +139,17 @@ var optab = []Optab{
{ARLDC, C_SCON, C_REG, C_LCON, C_REG, 29, 4, 0},
{ARLDCL, C_SCON, C_REG, C_LCON, C_REG, 29, 4, 0},
{ARLDCL, C_REG, C_REG, C_LCON, C_REG, 14, 4, 0},
+ {ARLDICL, C_REG, C_REG, C_LCON, C_REG, 14, 4, 0},
+ {ARLDICL, C_SCON, C_REG, C_LCON, C_REG, 14, 4, 0},
{ARLDCL, C_REG, C_NONE, C_LCON, C_REG, 14, 4, 0},
{AFADD, C_FREG, C_NONE, C_NONE, C_FREG, 2, 4, 0},
- {AFADD, C_FREG, C_REG, C_NONE, C_FREG, 2, 4, 0},
+ {AFADD, C_FREG, C_FREG, C_NONE, C_FREG, 2, 4, 0},
{AFABS, C_FREG, C_NONE, C_NONE, C_FREG, 33, 4, 0},
{AFABS, C_NONE, C_NONE, C_NONE, C_FREG, 33, 4, 0},
{AFMOVD, C_FREG, C_NONE, C_NONE, C_FREG, 33, 4, 0},
- {AFMADD, C_FREG, C_REG, C_FREG, C_FREG, 34, 4, 0},
+ {AFMADD, C_FREG, C_FREG, C_FREG, C_FREG, 34, 4, 0},
{AFMUL, C_FREG, C_NONE, C_NONE, C_FREG, 32, 4, 0},
- {AFMUL, C_FREG, C_REG, C_NONE, C_FREG, 32, 4, 0},
+ {AFMUL, C_FREG, C_FREG, C_NONE, C_FREG, 32, 4, 0},
/* store, short offset */
{AMOVD, C_REG, C_REG, C_NONE, C_ZOREG, 7, 4, REGZERO},
@@ -310,6 +312,12 @@ var optab = []Optab{
{AFMOVD, C_FREG, C_NONE, C_NONE, C_LAUTO, 35, 8, REGSP},
{AFMOVD, C_FREG, C_NONE, C_NONE, C_LOREG, 35, 8, REGZERO},
{AFMOVD, C_FREG, C_NONE, C_NONE, C_ADDR, 74, 8, 0},
+ {AFMOVSX, C_ZOREG, C_REG, C_NONE, C_FREG, 45, 4, 0},
+ {AFMOVSX, C_ZOREG, C_NONE, C_NONE, C_FREG, 45, 4, 0},
+ {AFMOVSX, C_FREG, C_REG, C_NONE, C_ZOREG, 44, 4, 0},
+ {AFMOVSX, C_FREG, C_NONE, C_NONE, C_ZOREG, 44, 4, 0},
+ {AFMOVSZ, C_ZOREG, C_REG, C_NONE, C_FREG, 45, 4, 0},
+ {AFMOVSZ, C_ZOREG, C_NONE, C_NONE, C_FREG, 45, 4, 0},
{ASYNC, C_NONE, C_NONE, C_NONE, C_NONE, 46, 4, 0},
{AWORD, C_LCON, C_NONE, C_NONE, C_NONE, 40, 4, 0},
{ADWORD, C_LCON, C_NONE, C_NONE, C_NONE, 31, 8, 0},
@@ -317,6 +325,8 @@ var optab = []Optab{
{AADDME, C_REG, C_NONE, C_NONE, C_REG, 47, 4, 0},
{AEXTSB, C_REG, C_NONE, C_NONE, C_REG, 48, 4, 0},
{AEXTSB, C_NONE, C_NONE, C_NONE, C_REG, 48, 4, 0},
+ {AISEL, C_LCON, C_REG, C_REG, C_REG, 84, 4, 0},
+ {AISEL, C_ZCON, C_REG, C_REG, C_REG, 84, 4, 0},
{ANEG, C_REG, C_NONE, C_NONE, C_REG, 47, 4, 0},
{ANEG, C_NONE, C_NONE, C_NONE, C_REG, 47, 4, 0},
{AREM, C_REG, C_NONE, C_NONE, C_REG, 50, 12, 0},
@@ -336,6 +346,129 @@ 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 */
+ /* Vector instructions */
+
+ /* Vector load */
+ {ALV, C_SOREG, C_NONE, C_NONE, C_VREG, 45, 4, 0}, /* vector load, x-form */
+
+ /* Vector store */
+ {ASTV, C_VREG, C_NONE, C_NONE, C_SOREG, 44, 4, 0}, /* vector store, x-form */
+
+ /* Vector logical */
+ {AVAND, C_VREG, C_VREG, C_NONE, C_VREG, 82, 4, 0}, /* vector and, vx-form */
+ {AVOR, C_VREG, C_VREG, C_NONE, C_VREG, 82, 4, 0}, /* vector or, vx-form */
+
+ /* Vector add */
+ {AVADDUM, C_VREG, C_VREG, C_NONE, C_VREG, 82, 4, 0}, /* vector add unsigned modulo, vx-form */
+ {AVADDCU, C_VREG, C_VREG, C_NONE, C_VREG, 82, 4, 0}, /* vector add & write carry unsigned, vx-form */
+ {AVADDUS, C_VREG, C_VREG, C_NONE, C_VREG, 82, 4, 0}, /* vector add unsigned saturate, vx-form */
+ {AVADDSS, C_VREG, C_VREG, C_NONE, C_VREG, 82, 4, 0}, /* vector add signed saturate, vx-form */
+ {AVADDE, C_VREG, C_VREG, C_VREG, C_VREG, 83, 4, 0}, /* vector add extended, va-form */
+
+ /* Vector subtract */
+ {AVSUBUM, C_VREG, C_VREG, C_NONE, C_VREG, 82, 4, 0}, /* vector subtract unsigned modulo, vx-form */
+ {AVSUBCU, C_VREG, C_VREG, C_NONE, C_VREG, 82, 4, 0}, /* vector subtract & write carry unsigned, vx-form */
+ {AVSUBUS, C_VREG, C_VREG, C_NONE, C_VREG, 82, 4, 0}, /* vector subtract unsigned saturate, vx-form */
+ {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 rotate */
+ {AVR, C_VREG, C_VREG, C_NONE, C_VREG, 82, 4, 0}, /* vector rotate, vx-form */
+
+ /* Vector shift */
+ {AVS, C_VREG, C_VREG, C_NONE, C_VREG, 82, 4, 0}, /* vector shift, vx-form */
+ {AVSA, C_VREG, C_VREG, C_NONE, C_VREG, 82, 4, 0}, /* vector shift algebraic, vx-form */
+ {AVSOI, C_ANDCON, C_VREG, C_VREG, C_VREG, 83, 4, 0}, /* vector shift by octet immediate, va-form */
+
+ /* Vector count */
+ {AVCLZ, C_VREG, C_NONE, C_NONE, C_VREG, 85, 4, 0}, /* vector count leading zeros, vx-form */
+ {AVPOPCNT, C_VREG, C_NONE, C_NONE, C_VREG, 85, 4, 0}, /* vector population count, vx-form */
+
+ /* Vector compare */
+ {AVCMPEQ, C_VREG, C_VREG, C_NONE, C_VREG, 82, 4, 0}, /* vector compare equal, vc-form */
+ {AVCMPGT, C_VREG, C_VREG, C_NONE, C_VREG, 82, 4, 0}, /* vector compare greater than, vc-form */
+
+ /* Vector permute */
+ {AVPERM, C_VREG, C_VREG, C_VREG, C_VREG, 83, 4, 0}, /* vector permute, va-form */
+
+ /* Vector select */
+ {AVSEL, C_VREG, C_VREG, C_VREG, C_VREG, 83, 4, 0}, /* vector select, va-form */
+
+ /* Vector splat */
+ {AVSPLT, C_SCON, C_VREG, C_NONE, C_VREG, 82, 4, 0}, /* vector splat, vx-form */
+ {AVSPLT, C_ADDCON, C_VREG, C_NONE, C_VREG, 82, 4, 0},
+ {AVSPLTI, C_SCON, C_NONE, C_NONE, C_VREG, 82, 4, 0}, /* vector splat immediate, vx-form */
+ {AVSPLTI, C_ADDCON, C_NONE, C_NONE, C_VREG, 82, 4, 0},
+
+ /* Vector AES */
+ {AVCIPH, C_VREG, C_VREG, C_NONE, C_VREG, 82, 4, 0}, /* vector AES cipher, vx-form */
+ {AVNCIPH, C_VREG, C_VREG, C_NONE, C_VREG, 82, 4, 0}, /* vector AES inverse cipher, vx-form */
+ {AVSBOX, C_VREG, C_NONE, C_NONE, C_VREG, 82, 4, 0}, /* vector AES subbytes, vx-form */
+
+ /* Vector SHA */
+ {AVSHASIGMA, C_ANDCON, C_VREG, C_ANDCON, C_VREG, 82, 4, 0}, /* vector SHA sigma, vx-form */
+
+ /* VSX vector load */
+ {ALXV, C_SOREG, C_NONE, C_NONE, C_VSREG, 87, 4, 0}, /* vsx vector load, xx1-form */
+
+ /* VSX vector store */
+ {ASTXV, C_VSREG, C_NONE, C_NONE, C_SOREG, 86, 4, 0}, /* vsx vector store, xx1-form */
+
+ /* VSX scalar load */
+ {ALXS, C_SOREG, C_NONE, C_NONE, C_VSREG, 87, 4, 0}, /* vsx scalar load, xx1-form */
+
+ /* VSX scalar store */
+ {ASTXS, C_VSREG, C_NONE, C_NONE, C_SOREG, 86, 4, 0}, /* vsx scalar store, xx1-form */
+
+ /* VSX scalar as integer load */
+ {ALXSI, C_SOREG, C_NONE, C_NONE, C_VSREG, 87, 4, 0}, /* vsx scalar as integer load, xx1-form */
+
+ /* VSX scalar store as integer */
+ {ASTXSI, C_VSREG, C_NONE, C_NONE, C_SOREG, 86, 4, 0}, /* vsx scalar as integer store, xx1-form */
+
+ /* VSX move from VSR */
+ {AMFVSR, C_VSREG, C_NONE, C_NONE, C_REG, 88, 4, 0}, /* vsx move from vsr, xx1-form */
+
+ /* VSX move to VSR */
+ {AMTVSR, C_REG, C_NONE, C_NONE, C_VSREG, 88, 4, 0}, /* vsx move to vsr, xx1-form */
+
+ /* VSX logical */
+ {AXXLAND, C_VSREG, C_VSREG, C_NONE, C_VSREG, 90, 4, 0}, /* vsx and, xx3-form */
+ {AXXLOR, C_VSREG, C_VSREG, C_NONE, C_VSREG, 90, 4, 0}, /* vsx or, xx3-form */
+
+ /* VSX select */
+ {AXXSEL, C_VSREG, C_VSREG, C_VSREG, C_VSREG, 91, 4, 0}, /* vsx select, xx4-form */
+
+ /* VSX merge */
+ {AXXMRG, C_VSREG, C_VSREG, C_NONE, C_VSREG, 90, 4, 0}, /* vsx merge, xx3-form */
+
+ /* VSX splat */
+ {AXXSPLT, C_VSREG, C_NONE, C_SCON, C_VSREG, 89, 4, 0}, /* vsx splat, xx2-form */
+
+ /* VSX permute */
+ {AXXPERM, C_VSREG, C_VSREG, C_SCON, C_VSREG, 90, 4, 0}, /* vsx permute, xx3-form */
+
+ /* VSX shift */
+ {AXXSI, C_VSREG, C_VSREG, C_SCON, C_VSREG, 90, 4, 0}, /* vsx shift immediate, xx3-form */
+
+ /* VSX scalar FP-FP conversion */
+ {AXSCV, C_VSREG, C_NONE, C_NONE, C_VSREG, 89, 4, 0}, /* vsx scalar fp-fp conversion, xx2-form */
+
+ /* VSX vector FP-FP conversion */
+ {AXVCV, C_VSREG, C_NONE, C_NONE, C_VSREG, 89, 4, 0}, /* vsx vector fp-fp conversion, xx2-form */
+
+ /* VSX scalar FP-integer conversion */
+ {AXSCVX, C_VSREG, C_NONE, C_NONE, C_VSREG, 89, 4, 0}, /* vsx scalar fp-integer conversion, xx2-form */
+
+ /* VSX scalar integer-FP conversion */
+ {AXSCVXP, C_VSREG, C_NONE, C_NONE, C_VSREG, 89, 4, 0}, /* vsx scalar integer-fp conversion, xx2-form */
+
+ /* VSX vector FP-integer conversion */
+ {AXVCVX, C_VSREG, C_NONE, C_NONE, C_VSREG, 89, 4, 0}, /* vsx vector fp-integer conversion, xx2-form */
+
+ /* VSX vector integer-FP conversion */
+ {AXVCVXP, C_VSREG, C_NONE, C_NONE, C_VSREG, 89, 4, 0}, /* vsx vector integer-fp conversion, xx2-form */
+
/* 64-bit special registers */
{AMOVD, C_REG, C_NONE, C_NONE, C_SPR, 66, 4, 0},
{AMOVD, C_REG, C_NONE, C_NONE, C_LR, 66, 4, 0},
@@ -453,7 +586,7 @@ func span9(ctxt *obj.Link, cursym *obj.LSym) {
var q *obj.Prog
for bflag != 0 {
if ctxt.Debugvlog != 0 {
- fmt.Fprintf(ctxt.Bso, "%5.2f span1\n", obj.Cputime())
+ ctxt.Logf("%5.2f span1\n", obj.Cputime())
}
bflag = 0
c = 0
@@ -499,7 +632,7 @@ func span9(ctxt *obj.Link, cursym *obj.LSym) {
cursym.Size = c
}
- c += -c & (FuncAlign - 1)
+ c += -c & (funcAlign - 1)
cursym.Size = c
/*
@@ -546,6 +679,12 @@ func aclass(ctxt *obj.Link, a *obj.Addr) int {
if REG_F0 <= a.Reg && a.Reg <= REG_F31 {
return C_FREG
}
+ if REG_V0 <= a.Reg && a.Reg <= REG_V31 {
+ return C_VREG
+ }
+ if REG_VS0 <= a.Reg && a.Reg <= REG_VS63 {
+ return C_VSREG
+ }
if REG_CR0 <= a.Reg && a.Reg <= REG_CR7 || a.Reg == REG_CR {
return C_CREG
}
@@ -754,7 +893,15 @@ func oplook(ctxt *obj.Link, p *obj.Prog) *Optab {
a4--
a2 := C_NONE
if p.Reg != 0 {
- a2 = C_REG
+ if REG_R0 <= p.Reg && p.Reg <= REG_R31 {
+ a2 = C_REG
+ } else if REG_V0 <= p.Reg && p.Reg <= REG_V31 {
+ a2 = C_VREG
+ } else if REG_VS0 <= p.Reg && p.Reg <= REG_VS63 {
+ a2 = C_VSREG
+ } else if REG_F0 <= p.Reg && p.Reg <= REG_F31 {
+ a2 = C_FREG
+ }
}
//print("oplook %v %d %d %d %d\n", p, a1, a2, a3, a4);
@@ -770,7 +917,7 @@ func oplook(ctxt *obj.Link, p *obj.Prog) *Optab {
}
}
- ctxt.Diag("illegal combination %v %v %v %v %v", obj.Aconv(p.As), DRconv(a1), DRconv(a2), DRconv(a3), DRconv(a4))
+ 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
@@ -919,8 +1066,8 @@ func buildop(ctxt *obj.Link) {
switch r {
default:
- ctxt.Diag("unknown op in build: %v", obj.Aconv(r))
- log.Fatalf("bad code")
+ ctxt.Diag("unknown op in build: %v", r)
+ log.Fatalf("instruction missing from switch in asm9.go:buildop: %v", r)
case ADCBF: /* unary indexed: op (b+a); op (b) */
opset(ADCBI, r0)
@@ -1003,6 +1150,10 @@ func buildop(ctxt *obj.Link) {
opset(AMULLDV, r0)
opset(ADIVD, r0)
opset(ADIVDCC, r0)
+ opset(ADIVDE, r0)
+ opset(ADIVDEU, r0)
+ opset(ADIVDECC, r0)
+ opset(ADIVDEUCC, r0)
opset(ADIVDVCC, r0)
opset(ADIVDV, r0)
opset(ADIVDU, r0)
@@ -1024,6 +1175,285 @@ func buildop(ctxt *obj.Link) {
opset(AMOVDU, r0)
opset(AMOVMW, r0)
+ case ALV: /* lvebx, lvehx, lvewx, lvx, lvxl, lvsl, lvsr */
+ opset(ALVEBX, r0)
+ opset(ALVEHX, r0)
+ opset(ALVEWX, r0)
+ opset(ALVX, r0)
+ opset(ALVXL, r0)
+ opset(ALVSL, r0)
+ opset(ALVSR, r0)
+
+ case ASTV: /* stvebx, stvehx, stvewx, stvx, stvxl */
+ opset(ASTVEBX, r0)
+ opset(ASTVEHX, r0)
+ opset(ASTVEWX, r0)
+ opset(ASTVX, r0)
+ opset(ASTVXL, r0)
+
+ case AVAND: /* vand, vandc, vnand */
+ opset(AVANDL, r0)
+ opset(AVANDC, r0)
+ opset(AVNAND, r0)
+
+ case AVOR: /* vor, vorc, vxor, vnor, veqv */
+ opset(AVORL, r0)
+ opset(AVORC, r0)
+ opset(AVXOR, r0)
+ opset(AVNOR, r0)
+ opset(AVEQV, r0)
+
+ case AVADDUM: /* vaddubm, vadduhm, vadduwm, vaddudm, vadduqm */
+ opset(AVADDUBM, r0)
+ opset(AVADDUHM, r0)
+ opset(AVADDUWM, r0)
+ opset(AVADDUDM, r0)
+ opset(AVADDUQM, r0)
+
+ case AVADDCU: /* vaddcuq, vaddcuw */
+ opset(AVADDCUQ, r0)
+ opset(AVADDCUW, r0)
+
+ case AVADDUS: /* vaddubs, vadduhs, vadduws */
+ opset(AVADDUBS, r0)
+ opset(AVADDUHS, r0)
+ opset(AVADDUWS, r0)
+
+ case AVADDSS: /* vaddsbs, vaddshs, vaddsws */
+ opset(AVADDSBS, r0)
+ opset(AVADDSHS, r0)
+ opset(AVADDSWS, r0)
+
+ case AVADDE: /* vaddeuqm, vaddecuq */
+ opset(AVADDEUQM, r0)
+ opset(AVADDECUQ, r0)
+
+ case AVSUBUM: /* vsububm, vsubuhm, vsubuwm, vsubudm, vsubuqm */
+ opset(AVSUBUBM, r0)
+ opset(AVSUBUHM, r0)
+ opset(AVSUBUWM, r0)
+ opset(AVSUBUDM, r0)
+ opset(AVSUBUQM, r0)
+
+ case AVSUBCU: /* vsubcuq, vsubcuw */
+ opset(AVSUBCUQ, r0)
+ opset(AVSUBCUW, r0)
+
+ case AVSUBUS: /* vsububs, vsubuhs, vsubuws */
+ opset(AVSUBUBS, r0)
+ opset(AVSUBUHS, r0)
+ opset(AVSUBUWS, r0)
+
+ case AVSUBSS: /* vsubsbs, vsubshs, vsubsws */
+ opset(AVSUBSBS, r0)
+ opset(AVSUBSHS, r0)
+ opset(AVSUBSWS, r0)
+
+ case AVSUBE: /* vsubeuqm, vsubecuq */
+ opset(AVSUBEUQM, r0)
+ opset(AVSUBECUQ, r0)
+
+ case AVR: /* vrlb, vrlh, vrlw, vrld */
+ opset(AVRLB, r0)
+ opset(AVRLH, r0)
+ opset(AVRLW, r0)
+ opset(AVRLD, r0)
+
+ case AVS: /* vs[l,r], vs[l,r]o, vs[l,r]b, vs[l,r]h, vs[l,r]w, vs[l,r]d */
+ opset(AVSLB, r0)
+ opset(AVSLH, r0)
+ opset(AVSLW, r0)
+ opset(AVSL, r0)
+ opset(AVSLO, r0)
+ opset(AVSRB, r0)
+ opset(AVSRH, r0)
+ opset(AVSRW, r0)
+ opset(AVSR, r0)
+ opset(AVSRO, r0)
+ opset(AVSLD, r0)
+ opset(AVSRD, r0)
+
+ case AVSA: /* vsrab, vsrah, vsraw, vsrad */
+ opset(AVSRAB, r0)
+ opset(AVSRAH, r0)
+ opset(AVSRAW, r0)
+ opset(AVSRAD, r0)
+
+ case AVSOI: /* vsldoi */
+ opset(AVSLDOI, r0)
+
+ case AVCLZ: /* vclzb, vclzh, vclzw, vclzd */
+ opset(AVCLZB, r0)
+ opset(AVCLZH, r0)
+ opset(AVCLZW, r0)
+ opset(AVCLZD, r0)
+
+ case AVPOPCNT: /* vpopcntb, vpopcnth, vpopcntw, vpopcntd */
+ opset(AVPOPCNTB, r0)
+ opset(AVPOPCNTH, r0)
+ opset(AVPOPCNTW, r0)
+ opset(AVPOPCNTD, r0)
+
+ case AVCMPEQ: /* vcmpequb[.], vcmpequh[.], vcmpequw[.], vcmpequd[.] */
+ opset(AVCMPEQUB, r0)
+ opset(AVCMPEQUBCC, r0)
+ opset(AVCMPEQUH, r0)
+ opset(AVCMPEQUHCC, r0)
+ opset(AVCMPEQUW, r0)
+ opset(AVCMPEQUWCC, r0)
+ opset(AVCMPEQUD, r0)
+ opset(AVCMPEQUDCC, r0)
+
+ case AVCMPGT: /* vcmpgt[u,s]b[.], vcmpgt[u,s]h[.], vcmpgt[u,s]w[.], vcmpgt[u,s]d[.] */
+ opset(AVCMPGTUB, r0)
+ opset(AVCMPGTUBCC, r0)
+ opset(AVCMPGTUH, r0)
+ opset(AVCMPGTUHCC, r0)
+ opset(AVCMPGTUW, r0)
+ opset(AVCMPGTUWCC, r0)
+ opset(AVCMPGTUD, r0)
+ opset(AVCMPGTUDCC, r0)
+ opset(AVCMPGTSB, r0)
+ opset(AVCMPGTSBCC, r0)
+ opset(AVCMPGTSH, r0)
+ opset(AVCMPGTSHCC, r0)
+ opset(AVCMPGTSW, r0)
+ opset(AVCMPGTSWCC, r0)
+ opset(AVCMPGTSD, r0)
+ opset(AVCMPGTSDCC, r0)
+
+ case AVPERM: /* vperm */
+ opset(AVPERM, r0)
+
+ case AVSEL: /* vsel */
+ opset(AVSEL, r0)
+
+ case AVSPLT: /* vspltb, vsplth, vspltw */
+ opset(AVSPLTB, r0)
+ opset(AVSPLTH, r0)
+ opset(AVSPLTW, r0)
+
+ case AVSPLTI: /* vspltisb, vspltish, vspltisw */
+ opset(AVSPLTISB, r0)
+ opset(AVSPLTISH, r0)
+ opset(AVSPLTISW, r0)
+
+ case AVCIPH: /* vcipher, vcipherlast */
+ opset(AVCIPHER, r0)
+ opset(AVCIPHERLAST, r0)
+
+ case AVNCIPH: /* vncipher, vncipherlast */
+ opset(AVNCIPHER, r0)
+ opset(AVNCIPHERLAST, r0)
+
+ case AVSBOX: /* vsbox */
+ opset(AVSBOX, r0)
+
+ case AVSHASIGMA: /* vshasigmaw, vshasigmad */
+ opset(AVSHASIGMAW, r0)
+ opset(AVSHASIGMAD, r0)
+
+ case ALXV: /* lxvd2x, lxvdsx, lxvw4x */
+ opset(ALXVD2X, r0)
+ opset(ALXVDSX, r0)
+ opset(ALXVW4X, r0)
+
+ case ASTXV: /* stxvd2x, stxvdsx, stxvw4x */
+ opset(ASTXVD2X, r0)
+ opset(ASTXVW4X, r0)
+
+ case ALXS: /* lxsdx */
+ opset(ALXSDX, r0)
+
+ case ASTXS: /* stxsdx */
+ opset(ASTXSDX, r0)
+
+ case ALXSI: /* lxsiwax, lxsiwzx */
+ opset(ALXSIWAX, r0)
+ opset(ALXSIWZX, r0)
+
+ case ASTXSI: /* stxsiwx */
+ opset(ASTXSIWX, r0)
+
+ case AMFVSR: /* mfvsrd, mfvsrwz */
+ opset(AMFVSRD, r0)
+ opset(AMFVSRWZ, r0)
+
+ case AMTVSR: /* mtvsrd, mtvsrwa, mtvsrwz */
+ opset(AMTVSRD, r0)
+ opset(AMTVSRWA, r0)
+ opset(AMTVSRWZ, r0)
+
+ case AXXLAND: /* xxland, xxlandc, xxleqv, xxlnand */
+ opset(AXXLANDQ, r0)
+ opset(AXXLANDC, r0)
+ opset(AXXLEQV, r0)
+ opset(AXXLNAND, r0)
+
+ case AXXLOR: /* xxlorc, xxlnor, xxlor, xxlxor */
+ opset(AXXLORC, r0)
+ opset(AXXLNOR, r0)
+ opset(AXXLORQ, r0)
+ opset(AXXLXOR, r0)
+
+ case AXXSEL: /* xxsel */
+ opset(AXXSEL, r0)
+
+ case AXXMRG: /* xxmrghw, xxmrglw */
+ opset(AXXMRGHW, r0)
+ opset(AXXMRGLW, r0)
+
+ case AXXSPLT: /* xxspltw */
+ opset(AXXSPLTW, r0)
+
+ case AXXPERM: /* xxpermdi */
+ opset(AXXPERMDI, r0)
+
+ case AXXSI: /* xxsldwi */
+ opset(AXXSLDWI, r0)
+
+ case AXSCV: /* xscvdpsp, xscvspdp, xscvdpspn, xscvspdpn */
+ opset(AXSCVDPSP, r0)
+ opset(AXSCVSPDP, r0)
+ opset(AXSCVDPSPN, r0)
+ opset(AXSCVSPDPN, r0)
+
+ case AXVCV: /* xvcvdpsp, xvcvspdp */
+ opset(AXVCVDPSP, r0)
+ opset(AXVCVSPDP, r0)
+
+ case AXSCVX: /* xscvdpsxds, xscvdpsxws, xscvdpuxds, xscvdpuxws */
+ opset(AXSCVDPSXDS, r0)
+ opset(AXSCVDPSXWS, r0)
+ opset(AXSCVDPUXDS, r0)
+ opset(AXSCVDPUXWS, r0)
+
+ case AXSCVXP: /* xscvsxddp, xscvuxddp, xscvsxdsp, xscvuxdsp */
+ opset(AXSCVSXDDP, r0)
+ opset(AXSCVUXDDP, r0)
+ opset(AXSCVSXDSP, r0)
+ opset(AXSCVUXDSP, r0)
+
+ case AXVCVX: /* xvcvdpsxds, xvcvdpsxws, xvcvdpuxds, xvcvdpuxws, xvcvspsxds, xvcvspsxws, xvcvspuxds, xvcvspuxws */
+ opset(AXVCVDPSXDS, r0)
+ opset(AXVCVDPSXWS, r0)
+ opset(AXVCVDPUXDS, r0)
+ opset(AXVCVDPUXWS, r0)
+ opset(AXVCVSPSXDS, r0)
+ opset(AXVCVSPSXWS, r0)
+ opset(AXVCVSPUXDS, r0)
+ opset(AXVCVSPUXWS, r0)
+
+ case AXVCVXP: /* xvcvsxddp, xvcvsxwdp, xvcvuxddp, xvcvuxwdp, xvcvsxdsp, xvcvsxwsp, xvcvuxdsp, xvcvuxwsp */
+ opset(AXVCVSXDDP, r0)
+ opset(AXVCVSXWDP, r0)
+ opset(AXVCVUXDDP, r0)
+ opset(AXVCVUXWDP, r0)
+ opset(AXVCVSXDSP, r0)
+ opset(AXVCVSXWSP, r0)
+ opset(AXVCVUXDSP, r0)
+ opset(AXVCVUXWSP, r0)
+
case AAND: /* logical op Rb,Rs,Ra; no literal */
opset(AANDN, r0)
@@ -1110,6 +1540,12 @@ func buildop(ctxt *obj.Link) {
opset(AFCFIDUCC, r0)
opset(AFRES, r0)
opset(AFRESCC, r0)
+ opset(AFRIM, r0)
+ opset(AFRIMCC, r0)
+ opset(AFRIP, r0)
+ opset(AFRIPCC, r0)
+ opset(AFRIZ, r0)
+ opset(AFRIZCC, r0)
opset(AFRSQRTE, r0)
opset(AFRSQRTECC, r0)
opset(AFSQRT, r0)
@@ -1157,6 +1593,9 @@ func buildop(ctxt *obj.Link) {
case AFCMPO:
opset(AFCMPU, r0)
+ case AISEL:
+ opset(AISEL, r0)
+
case AMTFSB0:
opset(AMTFSB0CC, r0)
opset(AMTFSB1, r0)
@@ -1214,6 +1653,8 @@ func buildop(ctxt *obj.Link) {
case ARLDMI:
opset(ARLDMICC, r0)
+ opset(ARLDIMI, r0)
+ opset(ARLDIMICC, r0)
case ARLDC:
opset(ARLDCCC, r0)
@@ -1223,6 +1664,11 @@ func buildop(ctxt *obj.Link) {
opset(ARLDCLCC, r0)
opset(ARLDCRCC, r0)
+ case ARLDICL:
+ opset(ARLDICLCC, r0)
+ opset(ARLDICR, r0)
+ opset(ARLDICRCC, r0)
+
case AFMOVD:
opset(AFMOVDCC, r0)
opset(AFMOVDU, r0)
@@ -1243,6 +1689,7 @@ func buildop(ctxt *obj.Link) {
case AMOVHBR:
opset(AMOVWBR, r0)
+ opset(AMOVDBR, r0)
case ASLBMFEE:
opset(ASLBMFEV, r0)
@@ -1265,6 +1712,8 @@ func buildop(ctxt *obj.Link) {
case AADD,
AANDCC, /* and. Rb,Rs,Ra; andi. $uimm,Rs,Ra; andis. $uimm,Rs,Ra */
+ AFMOVSX,
+ AFMOVSZ,
ALSW,
AMOVW,
/* load/store/move word with sign extension; special 32-bit move; move 32-bit literals */
@@ -1293,6 +1742,30 @@ func buildop(ctxt *obj.Link) {
}
}
+func OPVXX1(o uint32, xo uint32, oe uint32) uint32 {
+ return o<<26 | xo<<1 | oe<<11
+}
+
+func OPVXX2(o uint32, xo uint32, oe uint32) uint32 {
+ return o<<26 | xo<<2 | oe<<11
+}
+
+func OPVXX3(o uint32, xo uint32, oe uint32) uint32 {
+ return o<<26 | xo<<3 | oe<<11
+}
+
+func OPVXX4(o uint32, xo uint32, oe uint32) uint32 {
+ return o<<26 | xo<<4 | oe<<11
+}
+
+func OPVX(o uint32, xo uint32, oe uint32, rc uint32) uint32 {
+ return o<<26 | xo | oe<<11 | rc&1
+}
+
+func OPVC(o uint32, xo uint32, oe uint32, rc uint32) uint32 {
+ return o<<26 | xo | oe<<11 | (rc&1)<<10
+}
+
func OPVCC(o uint32, xo uint32, oe uint32, rc uint32) uint32 {
return o<<26 | xo<<1 | oe<<10 | rc&1
}
@@ -1310,10 +1783,80 @@ 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 */
+func AOP_RR(op uint32, d uint32, a uint32) uint32 {
+ return op | (d&31)<<21 | (a&31)<<11
+}
+
+/* VA-form 4-register operands */
+func AOP_RRRR(op uint32, d uint32, a uint32, b uint32, c uint32) uint32 {
+ return op | (d&31)<<21 | (a&31)<<16 | (b&31)<<11 | (c&31)<<6
+}
+
func AOP_IRR(op uint32, d uint32, a uint32, simm uint32) uint32 {
return op | (d&31)<<21 | (a&31)<<16 | simm&0xFFFF
}
+/* VX-form 2-register + UIM operands */
+func AOP_VIRR(op uint32, d uint32, a uint32, simm uint32) uint32 {
+ return op | (d&31)<<21 | (simm&0xFFFF)<<16 | (a&31)<<11
+}
+
+/* VX-form 2-register + ST + SIX operands */
+func AOP_IIRR(op uint32, d uint32, a uint32, sbit uint32, simm uint32) uint32 {
+ return op | (d&31)<<21 | (a&31)<<16 | (sbit&1)<<15 | (simm&0xF)<<11
+}
+
+/* VA-form 3-register + SHB operands */
+func AOP_IRRR(op uint32, d uint32, a uint32, b uint32, simm uint32) uint32 {
+ return op | (d&31)<<21 | (a&31)<<16 | (b&31)<<11 | (simm&0xF)<<6
+}
+
+/* VX-form 1-register + SIM operands */
+func AOP_IR(op uint32, d uint32, simm uint32) uint32 {
+ return op | (d&31)<<21 | (simm&31)<<16
+}
+
+/* XX1-form 3-register operands, 1 VSR operand */
+func AOP_XX1(op uint32, d uint32, a uint32, b uint32) uint32 {
+ /* For the XX-form encodings, we need the VSX register number to be exactly */
+ /* between 0-63, so we can properly set the rightmost bits. */
+ r := d - REG_VS0
+ return op | (r&31)<<21 | (a&31)<<16 | (b&31)<<11 | (r&32)>>5
+}
+
+/* XX2-form 3-register operands, 2 VSR operands */
+func AOP_XX2(op uint32, d uint32, a uint32, b uint32) uint32 {
+ xt := d - REG_VS0
+ xb := b - REG_VS0
+ return op | (xt&31)<<21 | (a&3)<<16 | (xb&31)<<11 | (xb&32)>>4 | (xt&32)>>5
+}
+
+/* XX3-form 3 VSR operands */
+func AOP_XX3(op uint32, d uint32, a uint32, b uint32) uint32 {
+ xt := d - REG_VS0
+ xa := a - REG_VS0
+ xb := b - REG_VS0
+ return op | (xt&31)<<21 | (xa&31)<<16 | (xb&31)<<11 | (xa&32)>>3 | (xb&32)>>4 | (xt&32)>>5
+}
+
+/* XX3-form 3 VSR operands + immediate */
+func AOP_XX3I(op uint32, d uint32, a uint32, b uint32, c uint32) uint32 {
+ xt := d - REG_VS0
+ xa := a - REG_VS0
+ xb := b - REG_VS0
+ return op | (xt&31)<<21 | (xa&31)<<16 | (xb&31)<<11 | (c&3)<<8 | (xa&32)>>3 | (xb&32)>>4 | (xt&32)>>5
+}
+
+/* XX4-form, 4 VSR operands */
+func AOP_XX4(op uint32, d uint32, a uint32, b uint32, c uint32) uint32 {
+ xt := d - REG_VS0
+ xa := a - REG_VS0
+ xb := b - REG_VS0
+ xc := c - REG_VS0
+ return op | (xt&31)<<21 | (xa&31)<<16 | (xb&31)<<11 | (xc&31)<<6 | (xc&32)>>2 | (xa&32)>>3 | (xb&32)>>4 | (xt&32)>>5
+}
+
func LOP_RRR(op uint32, a uint32, s uint32, b uint32) uint32 {
return op | (s&31)<<21 | (a&31)<<16 | (b&31)<<11
}
@@ -1338,6 +1881,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_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
+}
+
const (
/* each rhs is OPVCC(_, _, _, _) */
OP_ADD = 31<<26 | 266<<1 | 0<<10 | 0
@@ -1347,6 +1894,7 @@ const (
OP_EXTSB = 31<<26 | 954<<1 | 0<<10 | 0
OP_EXTSH = 31<<26 | 922<<1 | 0<<10 | 0
OP_EXTSW = 31<<26 | 986<<1 | 0<<10 | 0
+ OP_ISEL = 31<<26 | 15<<1 | 0<<10 | 0
OP_MCRF = 19<<26 | 0<<1 | 0<<10 | 0
OP_MCRFS = 63<<26 | 64<<1 | 0<<10 | 0
OP_MCRXR = 31<<26 | 512<<1 | 0<<10 | 0
@@ -1791,22 +2339,34 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
r = int(p.To.Reg)
}
d := vregoff(ctxt, p.From3)
- var mask [2]uint8
- maskgen64(ctxt, p, mask[:], uint64(d))
var a int
switch p.As {
+
+ // These opcodes expect a mask operand that has to be converted into the
+ // appropriate operand. The way these were defined, not all valid masks are possible.
+ // Left here for compatibility in case they were used or generated.
case ARLDCL, ARLDCLCC:
+ var mask [2]uint8
+ maskgen64(ctxt, 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)
}
case ARLDCR, ARLDCRCC:
+ var mask [2]uint8
+ maskgen64(ctxt, 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)
}
+ // These opcodes use a shift count like the ppc64 asm, no mask conversion done
+ case ARLDICR, ARLDICRCC, ARLDICL, ARLDICLCC:
+ a = int(d)
+
default:
ctxt.Diag("unexpected op in rldc case\n%v", p)
a = 0
@@ -1822,12 +2382,35 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
16: /* bc bo,bi,sbra */
a := 0
+ r := int(p.Reg)
+
if p.From.Type == obj.TYPE_CONST {
a = int(regoff(ctxt, &p.From))
- }
- r := int(p.Reg)
- if r == 0 {
- r = 0
+ } else if p.From.Type == obj.TYPE_REG {
+ if r != 0 {
+ ctxt.Diag("unexpected register setting for branch with CR: %d\n", r)
+ }
+ // BI values for the CR
+ switch p.From.Reg {
+ case REG_CR0:
+ r = BI_CR0
+ case REG_CR1:
+ r = BI_CR1
+ case REG_CR2:
+ r = BI_CR2
+ case REG_CR3:
+ r = BI_CR3
+ case REG_CR4:
+ r = BI_CR4
+ case REG_CR5:
+ r = BI_CR5
+ case REG_CR6:
+ r = BI_CR6
+ case REG_CR7:
+ r = BI_CR7
+ default:
+ ctxt.Diag("unrecognized register: expecting CR\n")
+ }
}
v := int32(0)
if p.Pcond != nil {
@@ -2064,18 +2647,32 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
v := regoff(ctxt, &p.From)
d := vregoff(ctxt, p.From3)
- var mask [2]uint8
- maskgen64(ctxt, p, mask[:], uint64(d))
- if int32(mask[1]) != (63 - v) {
- ctxt.Diag("invalid mask for shift: %x (shift %d)\n%v", uint64(d), v, p)
- }
- o1 = AOP_RRR(opirr(ctxt, p.As), uint32(p.Reg), uint32(p.To.Reg), (uint32(v) & 0x1F))
- o1 |= (uint32(mask[0]) & 31) << 6
- if v&0x20 != 0 {
- o1 |= 1 << 1
- }
- if mask[0]&0x20 != 0 {
- o1 |= 1 << 5 /* mb[5] is top bit */
+
+ // 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))
+ if int32(mask[1]) != (63 - v) {
+ 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 |= (uint32(mask[0]) & 31) << 6
+ if v&0x20 != 0 {
+ o1 |= 1 << 1
+ }
+ if mask[0]&0x20 != 0 {
+ o1 |= 1 << 5 /* mb[5] is top bit */
+ }
+
+ // 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 |= (uint32(d) & 31) << 6
+ if v&0x20 != 0 {
+ o1 |= 1 << 1
+ }
}
case 31: /* dword */
@@ -2510,6 +3107,98 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
rel.Siz = 8
rel.Sym = p.From.Sym
rel.Type = obj.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))
+ } 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))
+ } 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))
+ } 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))
+ }
+
+ 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))
+ } 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))
+ }
+
+ case 84: // ISEL BC,RA,RB,RT -> isel rt,ra,rb,bc
+ bc := vregoff(ctxt, &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))
+
+ 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))
+
+ 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))
+
+ 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))
+
+ case 88: /* VSX instructions, XX1-form */
+ /* reg reg none OR reg reg reg */
+ /* 3-register operand order: RA, RB, XT */
+ /* 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))
+ } 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))
+ }
+
+ 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))
+
+ 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))
+ } 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))
+ }
+
+ 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))
+
}
out[0] = o1
@@ -2662,6 +3351,18 @@ func oprrr(ctxt *obj.Link, a obj.As) uint32 {
case AREMDCC, ADIVDCC:
return OPVCC(31, 489, 0, 1)
+ case ADIVDE:
+ return OPVCC(31, 425, 0, 0)
+
+ case ADIVDECC:
+ return OPVCC(31, 425, 0, 1)
+
+ case ADIVDEU:
+ return OPVCC(31, 393, 0, 0)
+
+ case ADIVDEUCC:
+ return OPVCC(31, 393, 0, 1)
+
case AREMDV, ADIVDV:
return OPVCC(31, 489, 1, 0)
@@ -2806,6 +3507,18 @@ func oprrr(ctxt *obj.Link, a obj.As) uint32 {
return OPVCC(59, 24, 0, 0)
case AFRESCC:
return OPVCC(59, 24, 0, 1)
+ case AFRIM:
+ return OPVCC(63, 488, 0, 0)
+ case AFRIMCC:
+ return OPVCC(63, 488, 0, 1)
+ case AFRIP:
+ return OPVCC(63, 456, 0, 0)
+ case AFRIPCC:
+ return OPVCC(63, 456, 0, 1)
+ case AFRIZ:
+ return OPVCC(63, 424, 0, 0)
+ case AFRIZCC:
+ return OPVCC(63, 424, 0, 1)
case AFRSP:
return OPVCC(63, 12, 0, 0)
case AFRSPCC:
@@ -2931,6 +3644,15 @@ func oprrr(ctxt *obj.Link, a obj.As) uint32 {
case ARLDCR:
return OPVCC(30, 9, 0, 0)
+ case ARLDICL:
+ return OPVCC(30, 0, 0, 0)
+ case ARLDICLCC:
+ return OPVCC(30, 0, 0, 1)
+ case ARLDICR:
+ return OPVCC(30, 0, 0, 0) | 2<<1 // rldicr
+ case ARLDICRCC:
+ return OPVCC(30, 0, 0, 1) | 2<<1 // rldicr.
+
case ASYSCALL:
return OPVCC(17, 1, 0, 0)
@@ -3032,13 +3754,376 @@ func oprrr(ctxt *obj.Link, a obj.As) uint32 {
case ATD:
return OPVCC(31, 68, 0, 0)
+ /* 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:
+ 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:
+ return OPVX(4, 1156, 0, 0) /* vor - v2.03 */
+ case AVORC:
+ return OPVX(4, 1348, 0, 0) /* vorc - v2.07 */
+ case AVNOR:
+ return OPVX(4, 1284, 0, 0) /* vnor - v2.03 */
+ case AVXOR:
+ return OPVX(4, 1220, 0, 0) /* vxor - v2.03 */
+ case AVEQV:
+ return OPVX(4, 1668, 0, 0) /* veqv - v2.07 */
+
+ case AVADDUBM:
+ return OPVX(4, 0, 0, 0) /* vaddubm - v2.03 */
+ case AVADDUHM:
+ return OPVX(4, 64, 0, 0) /* vadduhm - v2.03 */
+ case AVADDUWM:
+ return OPVX(4, 128, 0, 0) /* vadduwm - v2.03 */
+ case AVADDUDM:
+ return OPVX(4, 192, 0, 0) /* vaddudm - v2.07 */
+ case AVADDUQM:
+ return OPVX(4, 256, 0, 0) /* vadduqm - v2.07 */
+
+ case AVADDCUQ:
+ return OPVX(4, 320, 0, 0) /* vaddcuq - v2.07 */
+ case AVADDCUW:
+ return OPVX(4, 384, 0, 0) /* vaddcuw - v2.03 */
+
+ case AVADDUBS:
+ return OPVX(4, 512, 0, 0) /* vaddubs - v2.03 */
+ case AVADDUHS:
+ return OPVX(4, 576, 0, 0) /* vadduhs - v2.03 */
+ case AVADDUWS:
+ return OPVX(4, 640, 0, 0) /* vadduws - v2.03 */
+
+ case AVADDSBS:
+ return OPVX(4, 768, 0, 0) /* vaddsbs - v2.03 */
+ case AVADDSHS:
+ return OPVX(4, 832, 0, 0) /* vaddshs - v2.03 */
+ case AVADDSWS:
+ return OPVX(4, 896, 0, 0) /* vaddsws - v2.03 */
+
+ case AVADDEUQM:
+ return OPVX(4, 60, 0, 0) /* vaddeuqm - v2.07 */
+ case AVADDECUQ:
+ return OPVX(4, 61, 0, 0) /* vaddecuq - v2.07 */
+
+ case AVSUBUBM:
+ return OPVX(4, 1024, 0, 0) /* vsububm - v2.03 */
+ case AVSUBUHM:
+ return OPVX(4, 1088, 0, 0) /* vsubuhm - v2.03 */
+ case AVSUBUWM:
+ return OPVX(4, 1152, 0, 0) /* vsubuwm - v2.03 */
+ case AVSUBUDM:
+ return OPVX(4, 1216, 0, 0) /* vsubudm - v2.07 */
+ case AVSUBUQM:
+ return OPVX(4, 1280, 0, 0) /* vsubuqm - v2.07 */
+
+ case AVSUBCUQ:
+ return OPVX(4, 1344, 0, 0) /* vsubcuq - v2.07 */
+ case AVSUBCUW:
+ return OPVX(4, 1408, 0, 0) /* vsubcuw - v2.03 */
+
+ case AVSUBUBS:
+ return OPVX(4, 1536, 0, 0) /* vsububs - v2.03 */
+ case AVSUBUHS:
+ return OPVX(4, 1600, 0, 0) /* vsubuhs - v2.03 */
+ case AVSUBUWS:
+ return OPVX(4, 1664, 0, 0) /* vsubuws - v2.03 */
+
+ case AVSUBSBS:
+ return OPVX(4, 1792, 0, 0) /* vsubsbs - v2.03 */
+ case AVSUBSHS:
+ return OPVX(4, 1856, 0, 0) /* vsubshs - v2.03 */
+ case AVSUBSWS:
+ return OPVX(4, 1920, 0, 0) /* vsubsws - v2.03 */
+
+ case AVSUBEUQM:
+ return OPVX(4, 62, 0, 0) /* vsubeuqm - v2.07 */
+ case AVSUBECUQ:
+ return OPVX(4, 63, 0, 0) /* vsubecuq - v2.07 */
+
+ case AVRLB:
+ return OPVX(4, 4, 0, 0) /* vrlb - v2.03 */
+ case AVRLH:
+ return OPVX(4, 68, 0, 0) /* vrlh - v2.03 */
+ case AVRLW:
+ return OPVX(4, 132, 0, 0) /* vrlw - v2.03 */
+ case AVRLD:
+ return OPVX(4, 196, 0, 0) /* vrld - v2.07 */
+
+ case AVSLB:
+ return OPVX(4, 260, 0, 0) /* vslh - v2.03 */
+ case AVSLH:
+ return OPVX(4, 324, 0, 0) /* vslh - v2.03 */
+ case AVSLW:
+ return OPVX(4, 388, 0, 0) /* vslw - v2.03 */
+ case AVSL:
+ return OPVX(4, 452, 0, 0) /* vsl - v2.03 */
+ case AVSLO:
+ return OPVX(4, 1036, 0, 0) /* vsl - v2.03 */
+ case AVSRB:
+ return OPVX(4, 516, 0, 0) /* vsrb - v2.03 */
+ case AVSRH:
+ return OPVX(4, 580, 0, 0) /* vsrh - v2.03 */
+ case AVSRW:
+ return OPVX(4, 644, 0, 0) /* vsrw - v2.03 */
+ case AVSR:
+ return OPVX(4, 708, 0, 0) /* vsr - v2.03 */
+ case AVSRO:
+ return OPVX(4, 1100, 0, 0) /* vsro - v2.03 */
+ case AVSLD:
+ return OPVX(4, 1476, 0, 0) /* vsld - v2.07 */
+ case AVSRD:
+ return OPVX(4, 1732, 0, 0) /* vsrd - v2.07 */
+
+ case AVSRAB:
+ return OPVX(4, 772, 0, 0) /* vsrab - v2.03 */
+ case AVSRAH:
+ return OPVX(4, 836, 0, 0) /* vsrah - v2.03 */
+ case AVSRAW:
+ return OPVX(4, 900, 0, 0) /* vsraw - v2.03 */
+ case AVSRAD:
+ return OPVX(4, 964, 0, 0) /* vsrad - v2.07 */
+
+ case AVCLZB:
+ return OPVX(4, 1794, 0, 0) /* vclzb - v2.07 */
+ case AVCLZH:
+ return OPVX(4, 1858, 0, 0) /* vclzh - v2.07 */
+ case AVCLZW:
+ return OPVX(4, 1922, 0, 0) /* vclzw - v2.07 */
+ case AVCLZD:
+ return OPVX(4, 1986, 0, 0) /* vclzd - v2.07 */
+
+ case AVPOPCNTB:
+ return OPVX(4, 1795, 0, 0) /* vpopcntb - v2.07 */
+ case AVPOPCNTH:
+ return OPVX(4, 1859, 0, 0) /* vpopcnth - v2.07 */
+ case AVPOPCNTW:
+ return OPVX(4, 1923, 0, 0) /* vpopcntw - v2.07 */
+ case AVPOPCNTD:
+ return OPVX(4, 1987, 0, 0) /* vpopcntd - v2.07 */
+
+ case AVCMPEQUB:
+ return OPVC(4, 6, 0, 0) /* vcmpequb - v2.03 */
+ case AVCMPEQUBCC:
+ return OPVC(4, 6, 0, 1) /* vcmpequb. - v2.03 */
+ case AVCMPEQUH:
+ return OPVC(4, 70, 0, 0) /* vcmpequh - v2.03 */
+ case AVCMPEQUHCC:
+ return OPVC(4, 70, 0, 1) /* vcmpequh. - v2.03 */
+ case AVCMPEQUW:
+ return OPVC(4, 134, 0, 0) /* vcmpequw - v2.03 */
+ case AVCMPEQUWCC:
+ return OPVC(4, 134, 0, 1) /* vcmpequw. - v2.03 */
+ case AVCMPEQUD:
+ return OPVC(4, 199, 0, 0) /* vcmpequd - v2.07 */
+ case AVCMPEQUDCC:
+ return OPVC(4, 199, 0, 1) /* vcmpequd. - v2.07 */
+
+ case AVCMPGTUB:
+ return OPVC(4, 518, 0, 0) /* vcmpgtub - v2.03 */
+ case AVCMPGTUBCC:
+ return OPVC(4, 518, 0, 1) /* vcmpgtub. - v2.03 */
+ case AVCMPGTUH:
+ return OPVC(4, 582, 0, 0) /* vcmpgtuh - v2.03 */
+ case AVCMPGTUHCC:
+ return OPVC(4, 582, 0, 1) /* vcmpgtuh. - v2.03 */
+ case AVCMPGTUW:
+ return OPVC(4, 646, 0, 0) /* vcmpgtuw - v2.03 */
+ case AVCMPGTUWCC:
+ return OPVC(4, 646, 0, 1) /* vcmpgtuw. - v2.03 */
+ case AVCMPGTUD:
+ return OPVC(4, 711, 0, 0) /* vcmpgtud - v2.07 */
+ case AVCMPGTUDCC:
+ return OPVC(4, 711, 0, 1) /* vcmpgtud. v2.07 */
+ case AVCMPGTSB:
+ return OPVC(4, 774, 0, 0) /* vcmpgtsb - v2.03 */
+ case AVCMPGTSBCC:
+ return OPVC(4, 774, 0, 1) /* vcmpgtsb. - v2.03 */
+ case AVCMPGTSH:
+ return OPVC(4, 838, 0, 0) /* vcmpgtsh - v2.03 */
+ case AVCMPGTSHCC:
+ return OPVC(4, 838, 0, 1) /* vcmpgtsh. - v2.03 */
+ case AVCMPGTSW:
+ return OPVC(4, 902, 0, 0) /* vcmpgtsw - v2.03 */
+ case AVCMPGTSWCC:
+ return OPVC(4, 902, 0, 1) /* vcmpgtsw. - v2.03 */
+ case AVCMPGTSD:
+ return OPVC(4, 967, 0, 0) /* vcmpgtsd - v2.07 */
+ case AVCMPGTSDCC:
+ return OPVC(4, 967, 0, 1) /* vcmpgtsd. - v2.07 */
+
+ case AVPERM:
+ return OPVX(4, 43, 0, 0) /* vperm - v2.03 */
+
+ case AVSEL:
+ return OPVX(4, 42, 0, 0) /* vsel - v2.03 */
+
+ case AVCIPHER:
+ return OPVX(4, 1288, 0, 0) /* vcipher - v2.07 */
+ case AVCIPHERLAST:
+ return OPVX(4, 1289, 0, 0) /* vcipherlast - v2.07 */
+ case AVNCIPHER:
+ return OPVX(4, 1352, 0, 0) /* vncipher - v2.07 */
+ case AVNCIPHERLAST:
+ return OPVX(4, 1353, 0, 0) /* vncipherlast - v2.07 */
+ case AVSBOX:
+ return OPVX(4, 1480, 0, 0) /* vsbox - v2.07 */
+ /* End of vector instructions */
+
+ /* Vector scalar (VSX) instructions */
+ /* ISA 2.06 enables these for POWER7. */
+ case AMFVSRD:
+ return OPVXX1(31, 51, 0) /* mfvsrd - v2.07 */
+ case AMFVSRWZ:
+ return OPVXX1(31, 115, 0) /* mfvsrwz - v2.07 */
+
+ case AMTVSRD:
+ return OPVXX1(31, 179, 0) /* mtvsrd - v2.07 */
+ case AMTVSRWA:
+ return OPVXX1(31, 211, 0) /* mtvsrwa - v2.07 */
+ case AMTVSRWZ:
+ return OPVXX1(31, 243, 0) /* mtvsrwz - v2.07 */
+
+ case AXXLANDQ:
+ return OPVXX3(60, 130, 0) /* xxland - v2.06 */
+ case AXXLANDC:
+ return OPVXX3(60, 138, 0) /* xxlandc - v2.06 */
+ case AXXLEQV:
+ return OPVXX3(60, 186, 0) /* xxleqv - v2.07 */
+ case AXXLNAND:
+ return OPVXX3(60, 178, 0) /* xxlnand - v2.07 */
+
+ case AXXLORC:
+ return OPVXX3(60, 170, 0) /* xxlorc - v2.07 */
+ case AXXLNOR:
+ return OPVXX3(60, 162, 0) /* xxlnor - v2.06 */
+ case AXXLORQ:
+ return OPVXX3(60, 146, 0) /* xxlor - v2.06 */
+ case AXXLXOR:
+ return OPVXX3(60, 154, 0) /* xxlxor - v2.06 */
+
+ case AXXSEL:
+ return OPVXX4(60, 3, 0) /* xxsel - v2.06 */
+
+ case AXXMRGHW:
+ return OPVXX3(60, 18, 0) /* xxmrghw - v2.06 */
+ case AXXMRGLW:
+ return OPVXX3(60, 50, 0) /* xxmrglw - v2.06 */
+
+ case AXXSPLTW:
+ return OPVXX2(60, 164, 0) /* xxspltw - v2.06 */
+
+ case AXXPERMDI:
+ return OPVXX3(60, 10, 0) /* xxpermdi - v2.06 */
+
+ case AXXSLDWI:
+ return OPVXX3(60, 2, 0) /* xxsldwi - v2.06 */
+
+ case AXSCVDPSP:
+ return OPVXX2(60, 265, 0) /* xscvdpsp - v2.06 */
+ case AXSCVSPDP:
+ return OPVXX2(60, 329, 0) /* xscvspdp - v2.06 */
+ case AXSCVDPSPN:
+ return OPVXX2(60, 267, 0) /* xscvdpspn - v2.07 */
+ case AXSCVSPDPN:
+ return OPVXX2(60, 331, 0) /* xscvspdpn - v2.07 */
+
+ case AXVCVDPSP:
+ return OPVXX2(60, 393, 0) /* xvcvdpsp - v2.06 */
+ case AXVCVSPDP:
+ return OPVXX2(60, 457, 0) /* xvcvspdp - v2.06 */
+
+ case AXSCVDPSXDS:
+ return OPVXX2(60, 344, 0) /* xscvdpsxds - v2.06 */
+ case AXSCVDPSXWS:
+ return OPVXX2(60, 88, 0) /* xscvdpsxws - v2.06 */
+ case AXSCVDPUXDS:
+ return OPVXX2(60, 328, 0) /* xscvdpuxds - v2.06 */
+ case AXSCVDPUXWS:
+ return OPVXX2(60, 72, 0) /* xscvdpuxws - v2.06 */
+
+ case AXSCVSXDDP:
+ return OPVXX2(60, 376, 0) /* xscvsxddp - v2.06 */
+ case AXSCVUXDDP:
+ return OPVXX2(60, 360, 0) /* xscvuxddp - v2.06 */
+ case AXSCVSXDSP:
+ return OPVXX2(60, 312, 0) /* xscvsxdsp - v2.06 */
+ case AXSCVUXDSP:
+ return OPVXX2(60, 296, 0) /* xscvuxdsp - v2.06 */
+
+ case AXVCVDPSXDS:
+ return OPVXX2(60, 472, 0) /* xvcvdpsxds - v2.06 */
+ case AXVCVDPSXWS:
+ return OPVXX2(60, 216, 0) /* xvcvdpsxws - v2.06 */
+ case AXVCVDPUXDS:
+ return OPVXX2(60, 456, 0) /* xvcvdpuxds - v2.06 */
+ case AXVCVDPUXWS:
+ return OPVXX2(60, 200, 0) /* xvcvdpuxws - v2.06 */
+ case AXVCVSPSXDS:
+ return OPVXX2(60, 408, 0) /* xvcvspsxds - v2.07 */
+ case AXVCVSPSXWS:
+ return OPVXX2(60, 152, 0) /* xvcvspsxws - v2.07 */
+ case AXVCVSPUXDS:
+ return OPVXX2(60, 392, 0) /* xvcvspuxds - v2.07 */
+ case AXVCVSPUXWS:
+ return OPVXX2(60, 136, 0) /* xvcvspuxws - v2.07 */
+
+ case AXVCVSXDDP:
+ return OPVXX2(60, 504, 0) /* xvcvsxddp - v2.06 */
+ case AXVCVSXWDP:
+ return OPVXX2(60, 248, 0) /* xvcvsxwdp - v2.06 */
+ case AXVCVUXDDP:
+ return OPVXX2(60, 488, 0) /* xvcvuxddp - v2.06 */
+ case AXVCVUXWDP:
+ return OPVXX2(60, 232, 0) /* xvcvuxwdp - v2.06 */
+ case AXVCVSXDSP:
+ return OPVXX2(60, 440, 0) /* xvcvsxdsp - v2.06 */
+ case AXVCVSXWSP:
+ return OPVXX2(60, 184, 0) /* xvcvsxwsp - v2.06 */
+ case AXVCVUXDSP:
+ return OPVXX2(60, 424, 0) /* xvcvuxdsp - v2.06 */
+ case AXVCVUXWSP:
+ return OPVXX2(60, 168, 0) /* xvcvuxwsp - v2.06 */
+ /* End of VSX instructions */
+
case AXOR:
return OPVCC(31, 316, 0, 0)
case AXORCC:
return OPVCC(31, 316, 0, 1)
}
- ctxt.Diag("bad r/r opcode %v", obj.Aconv(a))
+ 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 {
+ switch a {
+ /* Vector (VMX/Altivec) instructions */
+ /* ISA 2.03 enables these for PPC970. For POWERx processors, these */
+ /* are enabled starting at POWER6 (ISA 2.05). */
+ case AVSLDOI:
+ return OPVX(4, 44, 0, 0) /* vsldoi - v2.03 */
+ }
+
+ ctxt.Diag("bad i/r/r/r opcode %v", a)
+ return 0
+}
+
+func opiirr(ctxt *obj.Link, a obj.As) uint32 {
+ switch a {
+ /* Vector (VMX/Altivec) instructions */
+ /* ISA 2.07 enables these for POWER8 and beyond. */
+ case AVSHASIGMAW:
+ return OPVX(4, 1666, 0, 0) /* vshasigmaw - v2.07 */
+ case AVSHASIGMAD:
+ return OPVX(4, 1730, 0, 0) /* vshasigmad - v2.07 */
+ }
+
+ ctxt.Diag("bad i/i/r/r opcode %v", a)
return 0
}
@@ -3084,9 +4169,9 @@ func opirr(ctxt *obj.Link, a obj.As) uint32 {
case ABNE:
return AOP_RRR(16<<26, 4, 2, 0)
case ABVC:
- return AOP_RRR(16<<26, 4, 3, 0)
+ return AOP_RRR(16<<26, 4, 3, 0) // apparently unordered-clear
case ABVS:
- return AOP_RRR(16<<26, 12, 3, 0)
+ return AOP_RRR(16<<26, 12, 3, 0) // apparently unordered-set
case ACMP:
return OPVCC(11, 0, 0, 0) | 1<<21 /* L=1 */
@@ -3115,7 +4200,10 @@ func opirr(ctxt *obj.Link, a obj.As) uint32 {
return OPVCC(30, 0, 0, 0) | 3<<2 /* rldimi */
case ARLDMICC:
return OPVCC(30, 0, 0, 1) | 3<<2
-
+ case ARLDIMI:
+ return OPVCC(30, 0, 0, 0) | 3<<2 /* rldimi */
+ case ARLDIMICC:
+ return OPVCC(30, 0, 0, 1) | 3<<2
case ARLWNM:
return OPVCC(21, 0, 0, 0) /* rlwinm */
case ARLWNMCC:
@@ -3154,13 +4242,31 @@ func opirr(ctxt *obj.Link, a obj.As) uint32 {
case ATD:
return OPVCC(2, 0, 0, 0)
+ /* Vector (VMX/Altivec) instructions */
+ /* ISA 2.03 enables these for PPC970. For POWERx processors, these */
+ /* are enabled starting at POWER6 (ISA 2.05). */
+ case AVSPLTB:
+ return OPVX(4, 524, 0, 0) /* vspltb - v2.03 */
+ case AVSPLTH:
+ return OPVX(4, 588, 0, 0) /* vsplth - v2.03 */
+ case AVSPLTW:
+ return OPVX(4, 652, 0, 0) /* vspltw - v2.03 */
+
+ case AVSPLTISB:
+ return OPVX(4, 780, 0, 0) /* vspltisb - v2.03 */
+ case AVSPLTISH:
+ return OPVX(4, 844, 0, 0) /* vspltish - v2.03 */
+ case AVSPLTISW:
+ return OPVX(4, 908, 0, 0) /* vspltisw - v2.03 */
+ /* End of vector instructions */
+
case AXOR:
return OPVCC(26, 0, 0, 0) /* XORIL */
case -AXOR:
return OPVCC(27, 0, 0, 0) /* XORIU */
}
- ctxt.Diag("bad opcode i/r %v", obj.Aconv(a))
+ ctxt.Diag("bad opcode i/r or i/r/r %v", a)
return 0
}
@@ -3207,7 +4313,7 @@ func opload(ctxt *obj.Link, a obj.As) uint32 {
return OPVCC(46, 0, 0, 0) /* lmw */
}
- ctxt.Diag("bad load opcode %v", obj.Aconv(a))
+ ctxt.Diag("bad load opcode %v", a)
return 0
}
@@ -3238,6 +4344,10 @@ func oploadx(ctxt *obj.Link, a obj.As) uint32 {
return OPVCC(31, 535, 0, 0) /* lfsx */
case AFMOVSU:
return OPVCC(31, 567, 0, 0) /* lfsux */
+ case AFMOVSX:
+ return OPVCC(31, 855, 0, 0) /* lfiwax - power6, isa 2.05 */
+ case AFMOVSZ:
+ return OPVCC(31, 887, 0, 0) /* lfiwzx - power7, isa 2.06 */
case AMOVH:
return OPVCC(31, 343, 0, 0) /* lhax */
case AMOVHU:
@@ -3246,6 +4356,8 @@ func oploadx(ctxt *obj.Link, a obj.As) uint32 {
return OPVCC(31, 790, 0, 0) /* lhbrx */
case AMOVWBR:
return OPVCC(31, 534, 0, 0) /* lwbrx */
+ case AMOVDBR:
+ return OPVCC(31, 532, 0, 0) /* ldbrx */
case AMOVHZ:
return OPVCC(31, 279, 0, 0) /* lhzx */
case AMOVHZU:
@@ -3264,9 +4376,47 @@ func oploadx(ctxt *obj.Link, a obj.As) uint32 {
return OPVCC(31, 21, 0, 0) /* ldx */
case AMOVDU:
return OPVCC(31, 53, 0, 0) /* ldux */
+
+ /* Vector (VMX/Altivec) instructions */
+ /* ISA 2.03 enables these for PPC970. For POWERx processors, these */
+ /* are enabled starting at POWER6 (ISA 2.05). */
+ case ALVEBX:
+ return OPVCC(31, 7, 0, 0) /* lvebx - v2.03 */
+ case ALVEHX:
+ return OPVCC(31, 39, 0, 0) /* lvehx - v2.03 */
+ case ALVEWX:
+ return OPVCC(31, 71, 0, 0) /* lvewx - v2.03 */
+ case ALVX:
+ return OPVCC(31, 103, 0, 0) /* lvx - v2.03 */
+ case ALVXL:
+ return OPVCC(31, 359, 0, 0) /* lvxl - v2.03 */
+ case ALVSL:
+ return OPVCC(31, 6, 0, 0) /* lvsl - v2.03 */
+ case ALVSR:
+ return OPVCC(31, 38, 0, 0) /* lvsr - v2.03 */
+ /* End of vector instructions */
+
+ /* Vector scalar (VSX) instructions */
+ /* ISA 2.06 enables these for POWER7. */
+ case ALXVD2X:
+ return OPVXX1(31, 844, 0) /* lxvd2x - v2.06 */
+ case ALXVDSX:
+ return OPVXX1(31, 332, 0) /* lxvdsx - v2.06 */
+ case ALXVW4X:
+ return OPVXX1(31, 780, 0) /* lxvw4x - v2.06 */
+
+ case ALXSDX:
+ return OPVXX1(31, 588, 0) /* lxsdx - v2.06 */
+
+ case ALXSIWAX:
+ return OPVXX1(31, 76, 0) /* lxsiwax - v2.07 */
+ case ALXSIWZX:
+ return OPVXX1(31, 12, 0) /* lxsiwzx - v2.07 */
+ /* End of vector scalar instructions */
+
}
- ctxt.Diag("bad loadx opcode %v", obj.Aconv(a))
+ ctxt.Diag("bad loadx opcode %v", a)
return 0
}
@@ -3310,7 +4460,7 @@ func opstore(ctxt *obj.Link, a obj.As) uint32 {
return OPVCC(62, 0, 0, 1) /* stdu */
}
- ctxt.Diag("unknown store opcode %v", obj.Aconv(a))
+ ctxt.Diag("unknown store opcode %v", a)
return 0
}
@@ -3332,6 +4482,8 @@ func opstorex(ctxt *obj.Link, a obj.As) uint32 {
return OPVCC(31, 663, 0, 0) /* stfsx */
case AFMOVSU:
return OPVCC(31, 695, 0, 0) /* stfsux */
+ case AFMOVSX:
+ return OPVCC(31, 983, 0, 0) /* stfiwx */
case AMOVHZ, AMOVH:
return OPVCC(31, 407, 0, 0) /* sthx */
@@ -3362,8 +4514,38 @@ func opstorex(ctxt *obj.Link, a obj.As) uint32 {
return OPVCC(31, 149, 0, 0) /* stdx */
case AMOVDU:
return OPVCC(31, 181, 0, 0) /* stdux */
+
+ /* Vector (VMX/Altivec) instructions */
+ /* ISA 2.03 enables these for PPC970. For POWERx processors, these */
+ /* are enabled starting at POWER6 (ISA 2.05). */
+ case ASTVEBX:
+ return OPVCC(31, 135, 0, 0) /* stvebx - v2.03 */
+ case ASTVEHX:
+ return OPVCC(31, 167, 0, 0) /* stvehx - v2.03 */
+ case ASTVEWX:
+ return OPVCC(31, 199, 0, 0) /* stvewx - v2.03 */
+ case ASTVX:
+ return OPVCC(31, 231, 0, 0) /* stvx - v2.03 */
+ case ASTVXL:
+ return OPVCC(31, 487, 0, 0) /* stvxl - v2.03 */
+ /* End of vector instructions */
+
+ /* Vector scalar (VSX) instructions */
+ /* ISA 2.06 enables these for POWER7. */
+ case ASTXVD2X:
+ return OPVXX1(31, 972, 0) /* stxvd2x - v2.06 */
+ case ASTXVW4X:
+ return OPVXX1(31, 908, 0) /* stxvw4x - v2.06 */
+
+ case ASTXSDX:
+ return OPVXX1(31, 716, 0) /* stxsdx - v2.06 */
+
+ case ASTXSIWX:
+ return OPVXX1(31, 140, 0) /* stxsiwx - v2.07 */
+ /* End of vector scalar instructions */
+
}
- ctxt.Diag("unknown storex opcode %v", obj.Aconv(a))
+ 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 d46297a..dfc4896 100644
--- a/src/cmd/internal/obj/ppc64/list9.go
+++ b/src/cmd/internal/obj/ppc64/list9.go
@@ -53,6 +53,12 @@ func Rconv(r int) string {
if REG_F0 <= r && r <= REG_F31 {
return fmt.Sprintf("F%d", r-REG_F0)
}
+ if REG_V0 <= r && r <= REG_V31 {
+ return fmt.Sprintf("V%d", r-REG_V0)
+ }
+ if REG_VS0 <= r && r <= REG_VS63 {
+ return fmt.Sprintf("VS%d", r-REG_VS0)
+ }
if REG_CR0 <= r && r <= REG_CR7 {
return fmt.Sprintf("CR%d", r-REG_CR0)
}
diff --git a/src/cmd/internal/obj/ppc64/obj9.go b/src/cmd/internal/obj/ppc64/obj9.go
index 5f88307..68211ee 100644
--- a/src/cmd/internal/obj/ppc64/obj9.go
+++ b/src/cmd/internal/obj/ppc64/obj9.go
@@ -63,7 +63,7 @@ func progedit(ctxt *obj.Link, p *obj.Prog) {
s.Size = 4
p.From.Type = obj.TYPE_MEM
p.From.Sym = s
- p.From.Sym.Local = true
+ p.From.Sym.Set(obj.AttrLocal, true)
p.From.Name = obj.NAME_EXTERN
p.From.Offset = 0
}
@@ -76,7 +76,7 @@ func progedit(ctxt *obj.Link, p *obj.Prog) {
s.Size = 8
p.From.Type = obj.TYPE_MEM
p.From.Sym = s
- p.From.Sym.Local = true
+ p.From.Sym.Set(obj.AttrLocal, true)
p.From.Name = obj.NAME_EXTERN
p.From.Offset = 0
}
@@ -89,7 +89,7 @@ func progedit(ctxt *obj.Link, p *obj.Prog) {
s.Size = 8
p.From.Type = obj.TYPE_MEM
p.From.Sym = s
- p.From.Sym.Local = true
+ p.From.Sym.Set(obj.AttrLocal, true)
p.From.Name = obj.NAME_EXTERN
p.From.Offset = 0
}
@@ -168,7 +168,7 @@ func rewriteToUseGot(ctxt *obj.Link, p *obj.Prog) {
// We only care about global data: NAME_EXTERN means a global
// symbol in the Go sense, and p.Sym.Local is true for a few
// internally defined symbols.
- if p.From.Type == obj.TYPE_ADDR && p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local {
+ if p.From.Type == obj.TYPE_ADDR && p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local() {
// MOVD $sym, Rx becomes MOVD sym at GOT, Rx
// MOVD $sym+<off>, Rx becomes MOVD sym at GOT, Rx; ADD <off>, Rx
if p.As != AMOVD {
@@ -195,12 +195,12 @@ func rewriteToUseGot(ctxt *obj.Link, p *obj.Prog) {
// MOVx sym, Ry becomes MOVD sym at GOT, REGTMP; MOVx (REGTMP), Ry
// MOVx Ry, sym becomes MOVD sym at GOT, REGTMP; MOVx Ry, (REGTMP)
// An addition may be inserted between the two MOVs if there is an offset.
- if p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local {
- if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local {
+ if p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local() {
+ if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local() {
ctxt.Diag("cannot handle NAME_EXTERN on both sides in %v with -dynlink", p)
}
source = &p.From
- } else if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local {
+ } else if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local() {
source = &p.To
} else {
return
@@ -275,9 +275,8 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
* expand BECOME pseudo
*/
if ctxt.Debugvlog != 0 {
- fmt.Fprintf(ctxt.Bso, "%5.2f noops\n", obj.Cputime())
+ ctxt.Logf("%5.2f noops\n", obj.Cputime())
}
- ctxt.Bso.Flush()
var q *obj.Prog
var q1 *obj.Prog
@@ -446,19 +445,15 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
}
autosize := int32(0)
- var aoffset int
- var mov obj.As
var p1 *obj.Prog
var p2 *obj.Prog
for p := cursym.Text; p != nil; p = p.Link {
o := p.As
switch o {
case obj.ATEXT:
- mov = AMOVD
- aoffset = 0
autosize = int32(textstksiz)
- if p.Mark&LEAF != 0 && autosize == 0 && p.From3.Offset&obj.NOFRAME == 0 {
+ if p.Mark&LEAF != 0 && autosize == 0 {
// A leaf function with no locals has no frame.
p.From3.Offset |= obj.NOFRAME
}
@@ -469,6 +464,12 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
autosize += int32(ctxt.FixedFrameSize())
}
+ if p.Mark&LEAF != 0 && autosize < obj.StackSmall {
+ // A leaf function with a small stack can be marked
+ // NOSPLIT, avoiding a stack check.
+ p.From3.Offset |= obj.NOSPLIT
+ }
+
p.To.Offset = int64(autosize)
q = p
@@ -515,11 +516,49 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
}
if autosize != 0 {
- /* use MOVDU to adjust R1 when saving R31, if autosize is small */
+ // 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 {
- mov = AMOVDU
- aoffset = int(-autosize)
+ // Use MOVDU to adjust R1 when saving R31, if autosize is small.
+ q = obj.Appendp(ctxt, q)
+ q.As = AMOVD
+ q.Lineno = p.Lineno
+ q.From.Type = obj.TYPE_REG
+ q.From.Reg = REG_LR
+ q.To.Type = obj.TYPE_REG
+ q.To.Reg = REGTMP
+
+ q = obj.Appendp(ctxt, q)
+ q.As = AMOVDU
+ q.Lineno = p.Lineno
+ q.From.Type = obj.TYPE_REG
+ q.From.Reg = REGTMP
+ q.To.Type = obj.TYPE_MEM
+ q.To.Offset = int64(-autosize)
+ q.To.Reg = REGSP
+ q.Spadj = int32(autosize)
} else {
+ // Frame size is too large for a MOVDU 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.As = AMOVD
+ q.Lineno = p.Lineno
+ q.From.Type = obj.TYPE_REG
+ q.From.Reg = REG_LR
+ q.To.Type = obj.TYPE_REG
+ q.To.Reg = REG_R29 // REGTMP may be used to synthesize large offset in the next instruction
+
+ q = obj.Appendp(ctxt, q)
+ q.As = AMOVD
+ q.Lineno = p.Lineno
+ 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.As = AADD
q.Lineno = p.Lineno
@@ -537,30 +576,10 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
}
if cursym.Text.Mark&LEAF != 0 {
- cursym.Leaf = true
+ cursym.Set(obj.AttrLeaf, true)
break
}
- q = obj.Appendp(ctxt, q)
- q.As = AMOVD
- q.Lineno = p.Lineno
- q.From.Type = obj.TYPE_REG
- q.From.Reg = REG_LR
- q.To.Type = obj.TYPE_REG
- q.To.Reg = REGTMP
-
- q = obj.Appendp(ctxt, q)
- q.As = mov
- q.Lineno = p.Lineno
- q.From.Type = obj.TYPE_REG
- q.From.Reg = REGTMP
- q.To.Type = obj.TYPE_MEM
- q.To.Offset = int64(aoffset)
- q.To.Reg = REGSP
- if q.As == AMOVDU {
- q.Spadj = int32(-aoffset)
- }
-
if ctxt.Flag_shared {
q = obj.Appendp(ctxt, q)
q.As = AMOVD
@@ -824,6 +843,8 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
}
*/
func stacksplit(ctxt *obj.Link, 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)
@@ -831,7 +852,7 @@ func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32) *obj.Prog {
p.From.Type = obj.TYPE_MEM
p.From.Reg = REGG
p.From.Offset = 2 * int64(ctxt.Arch.PtrSize) // G.stackguard0
- if ctxt.Cursym.Cfunc {
+ if ctxt.Cursym.CFunc() {
p.From.Offset = 3 * int64(ctxt.Arch.PtrSize) // G.stackguard1
}
p.To.Type = obj.TYPE_REG
@@ -946,7 +967,7 @@ func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32) *obj.Prog {
}
var morestacksym *obj.LSym
- if ctxt.Cursym.Cfunc {
+ 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)
@@ -954,6 +975,24 @@ func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32) *obj.Prog {
morestacksym = obj.Linklookup(ctxt, "runtime.morestack", 0)
}
+ if 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.
+ // Fortunately, in shared mode, 8(SP) and 16(SP) are reserved in
+ // the caller's frame, but not used (0(SP) is caller's saved LR,
+ // 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.As = AMOVD
+ p.From.Type = obj.TYPE_REG
+ p.From.Reg = REG_R2
+ p.To.Type = obj.TYPE_MEM
+ p.To.Reg = REGSP
+ p.To.Offset = 8
+ }
+
if 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,
@@ -1001,12 +1040,23 @@ func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32) *obj.Prog {
p.To.Type = obj.TYPE_BRANCH
p.To.Sym = morestacksym
}
+
+ if ctxt.Flag_shared {
+ // MOVD 8(SP), R2
+ p = obj.Appendp(ctxt, p)
+ p.As = AMOVD
+ p.From.Type = obj.TYPE_MEM
+ p.From.Reg = REGSP
+ p.From.Offset = 8
+ p.To.Type = obj.TYPE_REG
+ p.To.Reg = REG_R2
+ }
+
// BR start
p = obj.Appendp(ctxt, p)
-
p.As = ABR
p.To.Type = obj.TYPE_BRANCH
- p.Pcond = ctxt.Cursym.Text.Link
+ p.Pcond = p0.Link
// placeholder for q1's jump target
p = obj.Appendp(ctxt, p)
diff --git a/src/cmd/internal/obj/reloctype_string.go b/src/cmd/internal/obj/reloctype_string.go
new file mode 100644
index 0000000..6de617c
--- /dev/null
+++ b/src/cmd/internal/obj/reloctype_string.go
@@ -0,0 +1,17 @@
+// Code generated by "stringer -type=RelocType"; DO NOT EDIT
+
+package obj
+
+import "fmt"
+
+const _RelocType_name = "R_ADDRR_ADDRPOWERR_ADDRARM64R_ADDRMIPSR_ADDROFFR_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, 53, 59, 68, 79, 88, 99, 109, 116, 123, 131, 139, 147, 153, 159, 165, 175, 184, 195, 206, 216, 225, 235, 249, 263, 279, 293, 307, 318, 332, 347, 364, 382, 403, 413, 424, 437}
+
+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 490695c..87ee971 100644
--- a/src/cmd/internal/obj/s390x/a.out.go
+++ b/src/cmd/internal/obj/s390x/a.out.go
@@ -209,24 +209,27 @@ const (
// integer arithmetic
AADD = obj.ABaseS390X + obj.A_ARCHSPECIFIC + iota
AADDC
- AADDME
AADDE
- AADDZE
+ AADDW
ADIVW
ADIVWU
ADIVD
ADIVDU
+ AMODW
+ AMODWU
+ AMODD
+ AMODDU
AMULLW
AMULLD
AMULHD
AMULHDU
ASUB
ASUBC
- ASUBME
ASUBV
ASUBE
- ASUBZE
+ ASUBW
ANEG
+ ANEGW
// integer moves
AMOVWBR
@@ -240,14 +243,24 @@ const (
AMOVD
AMOVDBR
+ // conditional moves
+ AMOVDEQ
+ AMOVDGE
+ AMOVDGT
+ AMOVDLE
+ AMOVDLT
+ AMOVDNE
+
+ // find leftmost one
+ AFLOGR
+
// integer bitwise
AAND
- AANDN
- ANAND
- ANOR
+ AANDW
AOR
- AORN
+ AORW
AXOR
+ AXORW
ASLW
ASLD
ASRW
@@ -276,6 +289,7 @@ const (
AFMULS
AFNABS
AFNEG
+ AFNEGS
AFNMADD
AFNMADDS
AFNMSUB
@@ -286,6 +300,8 @@ const (
AFSUBS
AFSQRT
AFSQRTS
+ AFIEBR
+ AFIDBR
// convert from int32/int64 to float/float64
ACEFBRA
@@ -332,6 +348,8 @@ const (
ABGT
ABLE
ABLT
+ ABLEU
+ ABLTU
ABNE
ABVC
ABVS
@@ -364,6 +382,18 @@ const (
ALA
ALAY
+ // interlocked load and op
+ ALAA
+ ALAAG
+ ALAAL
+ ALAALG
+ ALAN
+ ALANG
+ ALAX
+ ALAXG
+ ALAO
+ ALAOG
+
// load/store multiple
ALMY
ALMG
diff --git a/src/cmd/internal/obj/s390x/anames.go b/src/cmd/internal/obj/s390x/anames.go
index 62dd181..51b9ffc 100644
--- a/src/cmd/internal/obj/s390x/anames.go
+++ b/src/cmd/internal/obj/s390x/anames.go
@@ -8,24 +8,27 @@ import "cmd/internal/obj"
var Anames = []string{
obj.A_ARCHSPECIFIC: "ADD",
"ADDC",
- "ADDME",
"ADDE",
- "ADDZE",
+ "ADDW",
"DIVW",
"DIVWU",
"DIVD",
"DIVDU",
+ "MODW",
+ "MODWU",
+ "MODD",
+ "MODDU",
"MULLW",
"MULLD",
"MULHD",
"MULHDU",
"SUB",
"SUBC",
- "SUBME",
"SUBV",
"SUBE",
- "SUBZE",
+ "SUBW",
"NEG",
+ "NEGW",
"MOVWBR",
"MOVB",
"MOVBZ",
@@ -36,13 +39,19 @@ var Anames = []string{
"MOVWZ",
"MOVD",
"MOVDBR",
+ "MOVDEQ",
+ "MOVDGE",
+ "MOVDGT",
+ "MOVDLE",
+ "MOVDLT",
+ "MOVDNE",
+ "FLOGR",
"AND",
- "ANDN",
- "NAND",
- "NOR",
+ "ANDW",
"OR",
- "ORN",
+ "ORW",
"XOR",
+ "XORW",
"SLW",
"SLD",
"SRW",
@@ -69,6 +78,7 @@ var Anames = []string{
"FMULS",
"FNABS",
"FNEG",
+ "FNEGS",
"FNMADD",
"FNMADDS",
"FNMSUB",
@@ -79,6 +89,8 @@ var Anames = []string{
"FSUBS",
"FSQRT",
"FSQRTS",
+ "FIEBR",
+ "FIDBR",
"CEFBRA",
"CDFBRA",
"CEGBRA",
@@ -109,6 +121,8 @@ var Anames = []string{
"BGT",
"BLE",
"BLT",
+ "BLEU",
+ "BLTU",
"BNE",
"BVC",
"BVS",
@@ -134,6 +148,16 @@ var Anames = []string{
"LARL",
"LA",
"LAY",
+ "LAA",
+ "LAAG",
+ "LAAL",
+ "LAALG",
+ "LAN",
+ "LANG",
+ "LAX",
+ "LAXG",
+ "LAO",
+ "LAOG",
"LMY",
"LMG",
"STMY",
diff --git a/src/cmd/internal/obj/s390x/asmz.go b/src/cmd/internal/obj/s390x/asmz.go
index 2a99bbe..cc039bd 100644
--- a/src/cmd/internal/obj/s390x/asmz.go
+++ b/src/cmd/internal/obj/s390x/asmz.go
@@ -38,7 +38,7 @@ import (
// instruction layout.
const (
- FuncAlign = 16
+ funcAlign = 16
)
type Optab struct {
@@ -76,19 +76,16 @@ var optab = []Optab{
Optab{AMOVBZ, C_DCON, C_NONE, C_NONE, C_REG, 3, 0},
// store constant
- Optab{AMOVD, C_SYMADDR, C_NONE, C_NONE, C_ADDR, 73, 0},
Optab{AMOVD, C_LCON, C_NONE, C_NONE, C_ADDR, 73, 0},
Optab{AMOVW, C_LCON, C_NONE, C_NONE, C_ADDR, 73, 0},
Optab{AMOVWZ, C_LCON, C_NONE, C_NONE, C_ADDR, 73, 0},
Optab{AMOVBZ, C_LCON, C_NONE, C_NONE, C_ADDR, 73, 0},
Optab{AMOVB, C_LCON, C_NONE, C_NONE, C_ADDR, 73, 0},
- Optab{AMOVD, C_SYMADDR, C_NONE, C_NONE, C_LAUTO, 72, REGSP},
Optab{AMOVD, C_LCON, C_NONE, C_NONE, C_LAUTO, 72, REGSP},
Optab{AMOVW, C_LCON, C_NONE, C_NONE, C_LAUTO, 72, REGSP},
Optab{AMOVWZ, C_LCON, C_NONE, C_NONE, C_LAUTO, 72, REGSP},
Optab{AMOVB, C_LCON, C_NONE, C_NONE, C_LAUTO, 72, REGSP},
Optab{AMOVBZ, C_LCON, C_NONE, C_NONE, C_LAUTO, 72, REGSP},
- Optab{AMOVD, C_SYMADDR, C_NONE, C_NONE, C_LOREG, 72, 0},
Optab{AMOVD, C_LCON, C_NONE, C_NONE, C_LOREG, 72, 0},
Optab{AMOVW, C_LCON, C_NONE, C_NONE, C_LOREG, 72, 0},
Optab{AMOVWZ, C_LCON, C_NONE, C_NONE, C_LOREG, 72, 0},
@@ -137,20 +134,26 @@ var optab = []Optab{
Optab{AMOVBZ, C_ADDR, C_NONE, C_NONE, C_REG, 75, 0},
Optab{AMOVB, C_ADDR, C_NONE, C_NONE, C_REG, 75, 0},
+ // interlocked load and op
+ Optab{ALAAG, C_REG, C_REG, C_NONE, C_LOREG, 99, 0},
+
// integer arithmetic
Optab{AADD, C_REG, C_REG, C_NONE, C_REG, 2, 0},
Optab{AADD, C_REG, C_NONE, C_NONE, C_REG, 2, 0},
Optab{AADD, C_LCON, C_REG, C_NONE, C_REG, 22, 0},
Optab{AADD, C_LCON, C_NONE, C_NONE, C_REG, 22, 0},
+ Optab{AADD, C_LOREG, C_NONE, C_NONE, C_REG, 12, 0},
+ Optab{AADD, C_LAUTO, C_NONE, C_NONE, C_REG, 12, REGSP},
+ Optab{ASUB, C_LCON, C_REG, C_NONE, C_REG, 21, 0},
+ Optab{ASUB, C_LCON, C_NONE, C_NONE, C_REG, 21, 0},
+ Optab{ASUB, C_LOREG, C_NONE, C_NONE, C_REG, 12, 0},
+ Optab{ASUB, C_LAUTO, C_NONE, C_NONE, C_REG, 12, REGSP},
Optab{AMULHD, C_REG, C_NONE, C_NONE, C_REG, 4, 0},
Optab{AMULHD, C_REG, C_REG, C_NONE, C_REG, 4, 0},
- Optab{ASUBC, C_REG, C_REG, C_NONE, C_REG, 10, 0},
- Optab{ASUBC, C_REG, C_NONE, C_NONE, C_REG, 10, 0},
Optab{ADIVW, C_REG, C_REG, C_NONE, C_REG, 2, 0},
Optab{ADIVW, C_REG, C_NONE, C_NONE, C_REG, 2, 0},
Optab{ASUB, C_REG, C_REG, C_NONE, C_REG, 10, 0},
Optab{ASUB, C_REG, C_NONE, C_NONE, C_REG, 10, 0},
- Optab{AADDME, C_REG, C_NONE, C_NONE, C_REG, 47, 0},
Optab{ANEG, C_REG, C_NONE, C_NONE, C_REG, 47, 0},
Optab{ANEG, C_NONE, C_NONE, C_NONE, C_REG, 47, 0},
@@ -158,11 +161,13 @@ var optab = []Optab{
Optab{AAND, C_REG, C_REG, C_NONE, C_REG, 6, 0},
Optab{AAND, C_REG, C_NONE, C_NONE, C_REG, 6, 0},
Optab{AAND, C_LCON, C_NONE, C_NONE, C_REG, 23, 0},
- Optab{AAND, C_LCON, C_REG, C_NONE, C_REG, 23, 0},
- Optab{AOR, C_REG, C_REG, C_NONE, C_REG, 6, 0},
- Optab{AOR, C_REG, C_NONE, C_NONE, C_REG, 6, 0},
- Optab{AOR, C_LCON, C_NONE, C_NONE, C_REG, 23, 0},
- Optab{AOR, C_LCON, C_REG, C_NONE, C_REG, 23, 0},
+ Optab{AAND, C_LOREG, C_NONE, C_NONE, C_REG, 12, 0},
+ Optab{AAND, C_LAUTO, C_NONE, C_NONE, C_REG, 12, REGSP},
+ Optab{AANDW, C_REG, C_REG, C_NONE, C_REG, 6, 0},
+ Optab{AANDW, C_REG, C_NONE, C_NONE, C_REG, 6, 0},
+ Optab{AANDW, C_LCON, C_NONE, C_NONE, C_REG, 24, 0},
+ Optab{AANDW, C_LOREG, C_NONE, C_NONE, C_REG, 12, 0},
+ Optab{AANDW, C_LAUTO, C_NONE, C_NONE, C_REG, 12, REGSP},
Optab{ASLD, C_REG, C_NONE, C_NONE, C_REG, 7, 0},
Optab{ASLD, C_REG, C_REG, C_NONE, C_REG, 7, 0},
Optab{ASLD, C_SCON, C_REG, C_NONE, C_REG, 7, 0},
@@ -188,6 +193,7 @@ var optab = []Optab{
Optab{AFMOVD, C_ZCON, C_NONE, C_NONE, C_FREG, 67, 0},
Optab{ACEFBRA, C_REG, C_NONE, C_NONE, C_FREG, 82, 0},
Optab{ACFEBRA, C_FREG, C_NONE, C_NONE, C_REG, 83, 0},
+ Optab{AFIEBR, C_SCON, C_FREG, C_NONE, C_FREG, 48, 0},
// load symbol address (plus offset)
Optab{AMOVD, C_SYMADDR, C_NONE, C_NONE, C_REG, 19, 0},
@@ -213,6 +219,12 @@ var optab = []Optab{
Optab{ACMPUBEQ, C_REG, C_REG, C_NONE, C_SBRA, 89, 0},
Optab{ACMPUBEQ, C_REG, C_NONE, C_ANDCON, C_SBRA, 90, 0},
+ // move on condition
+ Optab{AMOVDEQ, C_REG, C_NONE, C_NONE, C_REG, 17, 0},
+
+ // find leftmost one
+ Optab{AFLOGR, C_REG, C_NONE, C_NONE, C_REG, 8, 0},
+
// compare
Optab{ACMP, C_REG, C_NONE, C_NONE, C_REG, 70, 0},
Optab{ACMP, C_REG, C_NONE, C_NONE, C_LCON, 71, 0},
@@ -383,7 +395,7 @@ func spanz(ctxt *obj.Link, cursym *obj.LSym) {
ctxt.Cursym = cursym
ctxt.Autosize = int32(p.To.Offset)
- if oprange[AANDN&obj.AMask] == nil {
+ if oprange[AORW&obj.AMask] == nil {
buildop(ctxt)
}
@@ -420,8 +432,8 @@ func spanz(ctxt *obj.Link, cursym *obj.LSym) {
}
cursym.Size = int64(len(buffer))
- if cursym.Size%FuncAlign != 0 {
- cursym.Size += FuncAlign - (cursym.Size % FuncAlign)
+ if cursym.Size%funcAlign != 0 {
+ cursym.Size += funcAlign - (cursym.Size % funcAlign)
}
cursym.Grow(cursym.Size)
copy(cursym.P, buffer)
@@ -651,7 +663,7 @@ func oplook(ctxt *obj.Link, p *obj.Prog) *Optab {
}
// cannot find a case; abort
- ctxt.Diag("illegal combination %v %v %v %v %v\n", obj.Aconv(p.As), DRconv(a1), DRconv(a2), DRconv(a3), DRconv(a4))
+ ctxt.Diag("illegal combination %v %v %v %v %v\n", p.As, DRconv(a1), DRconv(a2), DRconv(a3), DRconv(a4))
ctxt.Diag("prog: %v\n", p)
return nil
}
@@ -786,6 +798,7 @@ func buildop(ctxt *obj.Link) {
switch r {
case AADD:
opset(AADDC, r)
+ opset(AADDW, r)
opset(AMULLD, r)
opset(AMULLW, r)
case ADIVW:
@@ -793,6 +806,10 @@ func buildop(ctxt *obj.Link) {
opset(ADIVD, r)
opset(ADIVDU, r)
opset(ADIVWU, r)
+ opset(AMODD, r)
+ opset(AMODDU, r)
+ opset(AMODW, r)
+ opset(AMODWU, r)
case AMULHD:
opset(AMULHDU, r)
case AMOVBZ:
@@ -809,19 +826,20 @@ func buildop(ctxt *obj.Link) {
opset(ASTCKC, r)
opset(ASTCKE, r)
opset(ASTCKF, r)
+ case ALAAG:
+ opset(ALAA, r)
+ opset(ALAAL, r)
+ opset(ALAALG, r)
+ opset(ALAN, r)
+ opset(ALANG, r)
+ opset(ALAX, r)
+ opset(ALAXG, r)
+ opset(ALAO, r)
+ opset(ALAOG, r)
case ASTMG:
opset(ASTMY, r)
case ALMG:
opset(ALMY, r)
- case AAND:
- opset(AANDN, r)
- opset(ANAND, r)
- opset(ANOR, r)
- opset(AORN, r)
- case AADDME:
- opset(AADDZE, r)
- opset(ASUBME, r)
- opset(ASUBZE, r)
case ABEQ:
opset(ABGE, r)
opset(ABGT, r)
@@ -830,6 +848,8 @@ func buildop(ctxt *obj.Link) {
opset(ABNE, r)
opset(ABVC, r)
opset(ABVS, r)
+ opset(ABLEU, r)
+ opset(ABLTU, r)
case ABR:
opset(ABL, r)
case ABC:
@@ -837,6 +857,7 @@ func buildop(ctxt *obj.Link) {
case AFABS:
opset(AFNABS, r)
opset(AFNEG, r)
+ opset(AFNEGS, r)
opset(ALEDBR, r)
opset(ALDEBR, r)
opset(AFSQRT, r)
@@ -860,8 +881,12 @@ func buildop(ctxt *obj.Link) {
case AFCMPO:
opset(AFCMPU, r)
opset(ACEBR, r)
- case AOR:
+ case AAND:
+ opset(AOR, r)
opset(AXOR, r)
+ case AANDW:
+ opset(AORW, r)
+ opset(AXORW, r)
case ASLD:
opset(ASRD, r)
opset(ASLW, r)
@@ -875,6 +900,9 @@ func buildop(ctxt *obj.Link) {
case ASUB:
opset(ASUBC, r)
opset(ASUBE, r)
+ opset(ASUBW, r)
+ case ANEG:
+ opset(ANEGW, r)
case AFMOVD:
opset(AFMOVS, r)
case AMOVDBR:
@@ -899,6 +927,8 @@ func buildop(ctxt *obj.Link) {
opset(ACLFDBR, r)
opset(ACLGEBR, r)
opset(ACLGDBR, r)
+ case AFIEBR:
+ opset(AFIDBR, r)
case ACMPBEQ:
opset(ACMPBGE, r)
opset(ACMPBGT, r)
@@ -911,6 +941,12 @@ func buildop(ctxt *obj.Link) {
opset(ACMPUBLE, r)
opset(ACMPUBLT, r)
opset(ACMPUBNE, r)
+ case AMOVDEQ:
+ opset(AMOVDGE, r)
+ opset(AMOVDGT, r)
+ opset(AMOVDLE, r)
+ opset(AMOVDLT, r)
+ opset(AMOVDNE, r)
case AVL:
opset(AVLLEZB, r)
opset(AVLLEZH, r)
@@ -2494,22 +2530,26 @@ func addcallreloc(ctxt *obj.Link, sym *obj.LSym, add int64) *obj.Reloc {
func branchMask(ctxt *obj.Link, p *obj.Prog) uint32 {
switch p.As {
- case ABEQ, ACMPBEQ, ACMPUBEQ:
+ case ABEQ, ACMPBEQ, ACMPUBEQ, AMOVDEQ:
return 0x8
- case ABGE, ACMPBGE, ACMPUBGE:
+ case ABGE, ACMPBGE, ACMPUBGE, AMOVDGE:
return 0xA
- case ABGT, ACMPBGT, ACMPUBGT:
+ case ABGT, ACMPBGT, ACMPUBGT, AMOVDGT:
return 0x2
- case ABLE, ACMPBLE, ACMPUBLE:
+ case ABLE, ACMPBLE, ACMPUBLE, AMOVDLE:
return 0xC
- case ABLT, ACMPBLT, ACMPUBLT:
+ case ABLT, ACMPBLT, ACMPUBLT, AMOVDLT:
return 0x4
- case ABNE, ACMPBNE, ACMPUBNE:
+ case ABNE, ACMPBNE, ACMPUBNE, AMOVDNE:
return 0x7
+ case ABLEU: // LE or unordered
+ return 0xD
+ case ABLTU: // LT or unordered
+ return 0x5
case ABVC:
- return 0x0 //needs extra instruction
+ return 0x0 // needs extra instruction
case ABVS:
- return 0x1
+ return 0x1 // unordered
}
ctxt.Diag("unknown conditional branch %v", p.As)
return 0xF
@@ -2558,9 +2598,9 @@ func asmout(ctxt *obj.Link, asm *[]byte) {
}
case 2: // arithmetic op reg [reg] reg
- r := int(p.Reg)
+ r := p.Reg
if r == 0 {
- r = int(p.To.Reg)
+ r = p.To.Reg
}
var opcode uint32
@@ -2574,17 +2614,19 @@ func asmout(ctxt *obj.Link, asm *[]byte) {
opcode = op_ALGRK
case AADDE:
opcode = op_ALCGR
+ case AADDW:
+ opcode = op_ARK
case AMULLW:
opcode = op_MSGFR
case AMULLD:
opcode = op_MSGR
- case ADIVW:
+ case ADIVW, AMODW:
opcode = op_DSGFR
- case ADIVWU:
+ case ADIVWU, AMODWU:
opcode = op_DLR
- case ADIVD:
+ case ADIVD, AMODD:
opcode = op_DSGR
- case ADIVDU:
+ case ADIVDU, AMODDU:
opcode = op_DLGR
case AFADD:
opcode = op_ADBR
@@ -2603,11 +2645,15 @@ func asmout(ctxt *obj.Link, asm *[]byte) {
switch p.As {
default:
- case AADD, AADDC:
- zRRF(opcode, uint32(p.From.Reg), 0, uint32(p.To.Reg), uint32(r), asm)
+ case AADD, AADDC, AADDW:
+ if p.As == AADDW && r == p.To.Reg {
+ zRR(op_AR, uint32(p.To.Reg), uint32(p.From.Reg), asm)
+ } else {
+ zRRF(opcode, uint32(p.From.Reg), 0, uint32(p.To.Reg), uint32(r), asm)
+ }
case AADDE, AMULLW, AMULLD:
- if r == int(p.To.Reg) {
+ 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)
@@ -2618,14 +2664,22 @@ func asmout(ctxt *obj.Link, asm *[]byte) {
case ADIVW, ADIVWU, ADIVD, ADIVDU:
if p.As == ADIVWU || p.As == ADIVDU {
- zRRE(op_LGR, REGTMP, REGZERO, asm)
+ zRI(op_LGHI, REGTMP, 0, asm)
}
zRRE(op_LGR, REGTMP2, uint32(r), asm)
zRRE(opcode, REGTMP, uint32(p.From.Reg), asm)
zRRE(op_LGR, uint32(p.To.Reg), REGTMP2, asm)
+ case AMODW, AMODWU, AMODD, AMODDU:
+ if p.As == AMODWU || p.As == AMODDU {
+ zRI(op_LGHI, REGTMP, 0, asm)
+ }
+ zRRE(op_LGR, REGTMP2, uint32(r), asm)
+ zRRE(opcode, REGTMP, uint32(p.From.Reg), asm)
+ zRRE(op_LGR, uint32(p.To.Reg), REGTMP, asm)
+
case AFADD, AFADDS:
- if r == int(p.To.Reg) {
+ 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)
@@ -2635,7 +2689,7 @@ func asmout(ctxt *obj.Link, asm *[]byte) {
}
case AFSUB, AFSUBS, AFDIV, AFDIVS:
- if r == int(p.To.Reg) {
+ 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)
@@ -2665,16 +2719,14 @@ func asmout(ctxt *obj.Link, asm *[]byte) {
case AMOVW:
v = int64(int32(v))
}
- if v&0xffff == v {
- zRI(op_LLILL, uint32(p.To.Reg), uint32(v), asm)
+ if int64(int16(v)) == v {
+ zRI(op_LGHI, uint32(p.To.Reg), uint32(v), asm)
} else if v&0xffff0000 == v {
zRI(op_LLILH, uint32(p.To.Reg), uint32(v>>16), asm)
} else if v&0xffff00000000 == v {
zRI(op_LLIHL, uint32(p.To.Reg), uint32(v>>32), asm)
} else if uint64(v)&0xffff000000000000 == uint64(v) {
zRI(op_LLIHH, uint32(p.To.Reg), uint32(v>>48), asm)
- } else if int64(int16(v)) == v {
- zRI(op_LGHI, uint32(p.To.Reg), uint32(v), asm)
} else if int64(int32(v)) == v {
zRIL(_a, op_LGFI, uint32(p.To.Reg), uint32(v), asm)
} else if int64(uint32(v)) == v {
@@ -2712,74 +2764,35 @@ func asmout(ctxt *obj.Link, asm *[]byte) {
zI(op_SVC, 0, asm)
case 6: // logical op reg [reg] reg
- if p.To.Reg == 0 {
- ctxt.Diag("literal operation on R0\n%v", p)
- }
-
+ var oprr, oprre, oprrf uint32
switch p.As {
- case AAND, AOR, AXOR:
- var opcode1, opcode2 uint32
- switch p.As {
- default:
- case AAND:
- opcode1 = op_NGR
- opcode2 = op_NGRK
- case AOR:
- opcode1 = op_OGR
- opcode2 = op_OGRK
- case AXOR:
- opcode1 = op_XGR
- opcode2 = op_XGRK
- }
-
- r := int(p.Reg)
- if r == 0 {
- zRRE(opcode1, uint32(p.To.Reg), uint32(p.From.Reg), asm)
- } else {
- zRRF(opcode2, uint32(r), 0, uint32(p.To.Reg), uint32(p.From.Reg), asm)
- }
-
- case AANDN, AORN:
- var opcode1, opcode2 uint32
- switch p.As {
- default:
- case AANDN:
- opcode1 = op_NGR
- opcode2 = op_NGRK
- case AORN:
- opcode1 = op_OGR
- opcode2 = op_OGRK
- }
-
- r := int(p.Reg)
- if r == 0 {
- zRRE(op_LCGR, uint32(p.To.Reg), uint32(p.To.Reg), asm)
- zRRE(opcode1, uint32(p.To.Reg), uint32(p.From.Reg), asm)
- } else {
- zRRE(op_LCGR, REGTMP, uint32(r), asm)
- zRRF(opcode2, REGTMP, 0, uint32(p.To.Reg), uint32(p.From.Reg), asm)
- }
-
- case ANAND, ANOR:
- var opcode1, opcode2 uint32
- switch p.As {
- default:
- case ANAND:
- opcode1 = op_NGR
- opcode2 = op_NGRK
- case ANOR:
- opcode1 = op_OGR
- opcode2 = op_OGRK
- }
-
- r := int(p.Reg)
- if r == 0 {
- zRRE(opcode1, uint32(p.To.Reg), uint32(p.From.Reg), asm)
+ case AAND:
+ oprre = op_NGR
+ oprrf = op_NGRK
+ case AANDW:
+ oprr = op_NR
+ oprrf = op_NRK
+ case AOR:
+ oprre = op_OGR
+ oprrf = op_OGRK
+ case AORW:
+ oprr = op_OR
+ oprrf = op_ORK
+ case AXOR:
+ oprre = op_XGR
+ oprrf = op_XGRK
+ case AXORW:
+ oprr = op_XR
+ oprrf = op_XRK
+ }
+ if p.Reg == 0 {
+ if oprr != 0 {
+ zRR(oprr, uint32(p.To.Reg), uint32(p.From.Reg), asm)
} else {
- zRRF(opcode2, uint32(r), 0, uint32(p.To.Reg), uint32(p.From.Reg), asm)
+ zRRE(oprre, uint32(p.To.Reg), uint32(p.From.Reg), asm)
}
-
- zRRE(op_LCGR, uint32(p.To.Reg), uint32(p.To.Reg), asm)
+ } else {
+ zRRF(oprrf, uint32(p.Reg), 0, uint32(p.To.Reg), uint32(p.From.Reg), asm)
}
case 7: // shift/rotate reg [reg] reg
@@ -2812,6 +2825,13 @@ func asmout(ctxt *obj.Link, asm *[]byte) {
}
zRSY(opcode, uint32(r1), uint32(r3), uint32(b2), uint32(d2), asm)
+ case 8: // find leftmost one
+ if p.To.Reg&1 != 0 {
+ 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)
+
case 10: // subtract reg [reg] reg
r := int(p.Reg)
@@ -2829,7 +2849,6 @@ func asmout(ctxt *obj.Link, asm *[]byte) {
} else {
zRRF(op_SLGRK, uint32(p.From.Reg), 0, uint32(p.To.Reg), uint32(r), asm)
}
-
case ASUBE:
if r == 0 {
r = int(p.To.Reg)
@@ -2844,6 +2863,12 @@ func asmout(ctxt *obj.Link, asm *[]byte) {
zRRE(op_LGR, uint32(p.To.Reg), uint32(r), asm)
zRRE(op_SLBGR, uint32(p.To.Reg), uint32(p.From.Reg), asm)
}
+ case ASUBW:
+ if r == 0 {
+ zRR(op_SR, uint32(p.To.Reg), uint32(p.From.Reg), asm)
+ } else {
+ zRRF(op_SRK, uint32(p.From.Reg), 0, uint32(p.To.Reg), uint32(r), asm)
+ }
}
case 11: // br/bl
@@ -2866,6 +2891,67 @@ func asmout(ctxt *obj.Link, asm *[]byte) {
}
}
+ case 12:
+ r1 := p.To.Reg
+ d2 := vregoff(ctxt, &p.From)
+ b2 := p.From.Reg
+ if b2 == 0 {
+ b2 = o.param
+ }
+ x2 := p.From.Index
+ if -DISP20/2 > d2 || d2 >= DISP20/2 {
+ zRIL(_a, op_LGFI, REGTMP, uint32(d2), asm)
+ if x2 != 0 {
+ zRX(op_LA, REGTMP, REGTMP, uint32(x2), 0, asm)
+ }
+ x2 = REGTMP
+ d2 = 0
+ }
+ var opx, opxy uint32
+ switch p.As {
+ case AADD:
+ opxy = op_AG
+ case AADDC:
+ opxy = op_ALG
+ case AADDW:
+ opx = op_A
+ opxy = op_AY
+ case AMULLW:
+ opx = op_MS
+ opxy = op_MSY
+ case AMULLD:
+ opxy = op_MSG
+ case ASUB:
+ opxy = op_SG
+ case ASUBC:
+ opxy = op_SLG
+ case ASUBE:
+ opxy = op_SLBG
+ case ASUBW:
+ opx = op_S
+ opxy = op_SY
+ case AAND:
+ opxy = op_NG
+ case AANDW:
+ opx = op_N
+ opxy = op_NY
+ case AOR:
+ opxy = op_OG
+ case AORW:
+ opx = op_O
+ opxy = op_OY
+ case AXOR:
+ opxy = op_XG
+ case AXORW:
+ opx = op_X
+ opxy = op_XY
+ }
+ if opx != 0 && 0 <= d2 && d2 < DISP12 {
+ zRX(opx, uint32(r1), uint32(x2), uint32(b2), uint32(d2), asm)
+ } else {
+ zRXY(opxy, uint32(r1), uint32(x2), uint32(b2), uint32(d2), asm)
+ }
+
case 15: // br/bl (reg)
r := p.To.Reg
if p.As == ABCL || p.As == ABL {
@@ -2889,6 +2975,10 @@ func asmout(ctxt *obj.Link, asm *[]byte) {
addrilreloc(ctxt, p.To.Sym, p.To.Offset)
}
+ case 17: // move on condition
+ m3 := branchMask(ctxt, p)
+ zRRF(op_LOCGR, m3, 0, uint32(p.To.Reg), uint32(p.From.Reg), asm)
+
case 18: // br/bl reg
if p.As == ABL {
zRR(op_BASR, uint32(REG_LR), uint32(p.To.Reg), asm)
@@ -2905,107 +2995,143 @@ func asmout(ctxt *obj.Link, asm *[]byte) {
}
addrilreloc(ctxt, p.From.Sym, d)
- case 22: // arithmetic op $constant [reg] reg
- if p.From.Sym != nil {
- ctxt.Diag("%v is not supported", p)
- }
+ case 21: // subtract $constant [reg] reg
v := vregoff(ctxt, &p.From)
r := p.Reg
if r == 0 {
r = p.To.Reg
}
switch p.As {
- default:
- case AADD:
- if r == p.To.Reg {
- zRIL(_a, op_AGFI, uint32(p.To.Reg), uint32(v), asm)
- } else if int64(int16(v)) == v {
- zRIE(_d, op_AGHIK, uint32(p.To.Reg), uint32(r), uint32(v), 0, 0, 0, 0, asm)
- } else {
- zRRE(op_LGR, uint32(p.To.Reg), uint32(r), asm)
- zRIL(_a, op_AGFI, uint32(p.To.Reg), uint32(v), asm)
- }
- case AADDC:
+ case ASUB:
+ zRIL(_a, op_LGFI, uint32(REGTMP), uint32(v), asm)
+ zRRF(op_SLGRK, uint32(REGTMP), 0, uint32(p.To.Reg), uint32(r), asm)
+ case ASUBC:
if r != p.To.Reg {
zRRE(op_LGR, uint32(p.To.Reg), uint32(r), asm)
}
- zRIL(_a, op_ALGFI, uint32(p.To.Reg), uint32(v), asm)
- case AMULLW, AMULLD:
+ zRIL(_a, op_SLGFI, uint32(p.To.Reg), uint32(v), asm)
+ case ASUBW:
if r != p.To.Reg {
- zRRE(op_LGR, uint32(p.To.Reg), uint32(r), asm)
- }
- if int64(int16(v)) == v {
- zRI(op_MGHI, uint32(p.To.Reg), uint32(v), asm)
- } else {
- zRIL(_a, op_MSGFI, uint32(p.To.Reg), uint32(v), asm)
+ zRR(op_LR, uint32(p.To.Reg), uint32(r), asm)
}
+ zRIL(_a, op_SLFI, uint32(p.To.Reg), uint32(v), asm)
}
- case 23: // logical op $constant [reg] reg
+ case 22: // add/multiply $constant [reg] reg
v := vregoff(ctxt, &p.From)
- var opcode uint32
r := p.Reg
if r == 0 {
r = p.To.Reg
}
- if r == p.To.Reg {
+ var opri, opril, oprie uint32
+ switch p.As {
+ case AADD:
+ opri = op_AGHI
+ opril = op_AGFI
+ oprie = op_AGHIK
+ case AADDC:
+ opril = op_ALGFI
+ oprie = op_ALGHSIK
+ case AADDW:
+ opri = op_AHI
+ opril = op_AFI
+ oprie = op_AHIK
+ case AMULLW:
+ opri = op_MHI
+ opril = op_MSFI
+ case AMULLD:
+ opri = op_MGHI
+ opril = op_MSGFI
+ }
+ if r != p.To.Reg && (oprie == 0 || int64(int16(v)) != v) {
switch p.As {
- default:
- ctxt.Diag("%v is not supported", p)
- case AAND:
- if v >= 0 { // needs zero extend
- zRIL(_a, op_LGFI, REGTMP, uint32(v), asm)
- zRRE(op_NGR, uint32(p.To.Reg), REGTMP, asm)
- } else if int64(int16(v)) == v {
- zRI(op_NILL, uint32(p.To.Reg), uint32(v), asm)
- } else { // r.To.Reg & 0xffffffff00000000 & uint32(v)
- zRIL(_a, op_NILF, uint32(p.To.Reg), uint32(v), asm)
- }
- case AOR:
- if int64(uint32(v)) != v { // needs sign extend
- zRIL(_a, op_LGFI, REGTMP, uint32(v), asm)
- zRRE(op_OGR, uint32(p.To.Reg), REGTMP, asm)
- } else if int64(uint16(v)) == v {
- zRI(op_OILL, uint32(p.To.Reg), uint32(v), asm)
- } else {
- zRIL(_a, op_OILF, uint32(p.To.Reg), uint32(v), asm)
- }
- case AXOR:
- if int64(uint32(v)) != v { // needs sign extend
- zRIL(_a, op_LGFI, REGTMP, uint32(v), asm)
- zRRE(op_XGR, uint32(p.To.Reg), REGTMP, asm)
- } else {
- zRIL(_a, op_XILF, uint32(p.To.Reg), uint32(v), asm)
- }
+ case AADD, AADDC, AMULLD:
+ zRRE(op_LGR, uint32(p.To.Reg), uint32(r), asm)
+ case AADDW, AMULLW:
+ zRR(op_LR, uint32(p.To.Reg), uint32(r), asm)
+ }
+ r = p.To.Reg
+ }
+ if r == p.To.Reg {
+ if opri != 0 && int64(int16(v)) == v {
+ zRI(opri, uint32(p.To.Reg), uint32(v), asm)
+ } else {
+ zRIL(_a, opril, uint32(p.To.Reg), uint32(v), asm)
}
} else {
- switch p.As {
- default:
- ctxt.Diag("%v is not supported", p)
- case AAND:
- opcode = op_NGRK
- case AOR:
- opcode = op_OGRK
- case AXOR:
- opcode = op_XGRK
+ zRIE(_d, oprie, uint32(p.To.Reg), uint32(r), uint32(v), 0, 0, 0, 0, asm)
+ }
+
+ case 23: // 64-bit logical op $constant reg
+ // TODO(mundaym): merge with case 24.
+ v := vregoff(ctxt, &p.From)
+ switch p.As {
+ default:
+ ctxt.Diag("%v is not supported", p)
+ case AAND:
+ if v >= 0 { // needs zero extend
+ zRIL(_a, op_LGFI, REGTMP, uint32(v), asm)
+ zRRE(op_NGR, uint32(p.To.Reg), REGTMP, asm)
+ } else if int64(int16(v)) == v {
+ zRI(op_NILL, uint32(p.To.Reg), uint32(v), asm)
+ } else { // r.To.Reg & 0xffffffff00000000 & uint32(v)
+ zRIL(_a, op_NILF, uint32(p.To.Reg), uint32(v), asm)
+ }
+ case AOR:
+ if int64(uint32(v)) != v { // needs sign extend
+ zRIL(_a, op_LGFI, REGTMP, uint32(v), asm)
+ zRRE(op_OGR, uint32(p.To.Reg), REGTMP, asm)
+ } else if int64(uint16(v)) == v {
+ zRI(op_OILL, uint32(p.To.Reg), uint32(v), asm)
+ } else {
+ zRIL(_a, op_OILF, uint32(p.To.Reg), uint32(v), asm)
+ }
+ case AXOR:
+ if int64(uint32(v)) != v { // needs sign extend
+ zRIL(_a, op_LGFI, REGTMP, uint32(v), asm)
+ zRRE(op_XGR, uint32(p.To.Reg), REGTMP, asm)
+ } else {
+ zRIL(_a, op_XILF, uint32(p.To.Reg), uint32(v), asm)
}
- zRIL(_a, op_LGFI, REGTMP, uint32(v), asm)
- zRRF(opcode, uint32(r), 0, uint32(p.To.Reg), REGTMP, asm)
}
- case 26: // mov $addr/sym reg
+ case 24: // 32-bit logical op $constant reg
+ v := vregoff(ctxt, &p.From)
+ switch p.As {
+ case AANDW:
+ if uint32(v&0xffff0000) == 0xffff0000 {
+ zRI(op_NILL, uint32(p.To.Reg), uint32(v), asm)
+ } else if uint32(v&0x0000ffff) == 0x0000ffff {
+ zRI(op_NILH, uint32(p.To.Reg), uint32(v)>>16, asm)
+ } else {
+ zRIL(_a, op_NILF, uint32(p.To.Reg), uint32(v), asm)
+ }
+ case AORW:
+ if uint32(v&0xffff0000) == 0 {
+ zRI(op_OILL, uint32(p.To.Reg), uint32(v), asm)
+ } else if uint32(v&0x0000ffff) == 0 {
+ zRI(op_OILH, uint32(p.To.Reg), uint32(v)>>16, asm)
+ } else {
+ zRIL(_a, op_OILF, uint32(p.To.Reg), uint32(v), asm)
+ }
+ case AXORW:
+ zRIL(_a, op_XILF, uint32(p.To.Reg), uint32(v), asm)
+ }
+
+ case 26: // MOVD $offset(base)(index), reg
v := regoff(ctxt, &p.From)
r := p.From.Reg
if r == 0 {
r = o.param
}
+ i := p.From.Index
if v >= 0 && v < DISP12 {
- zRX(op_LA, uint32(p.To.Reg), uint32(r), 0, uint32(v), asm)
+ zRX(op_LA, uint32(p.To.Reg), uint32(r), uint32(i), uint32(v), asm)
} else if v >= -DISP20/2 && v < DISP20/2 {
- zRXY(op_LAY, uint32(p.To.Reg), uint32(r), 0, uint32(v), asm)
+ zRXY(op_LAY, uint32(p.To.Reg), uint32(r), uint32(i), uint32(v), asm)
} else {
zRIL(_a, op_LGFI, REGTMP, uint32(v), asm)
- zRX(op_LA, uint32(p.To.Reg), uint32(r), REGTMP, 0, asm)
+ zRX(op_LA, uint32(p.To.Reg), uint32(r), REGTMP, uint32(i), asm)
}
case 31: // dword
@@ -3060,6 +3186,8 @@ func asmout(ctxt *obj.Link, asm *[]byte) {
opcode = op_LNDBR
case AFNEG:
opcode = op_LCDFR
+ case AFNEGS:
+ opcode = op_LCEBR
case ALEDBR:
opcode = op_LEDBR
case ALDEBR:
@@ -3144,54 +3272,32 @@ func asmout(ctxt *obj.Link, asm *[]byte) {
*asm = append(*asm, uint8(wd))
}
- case 47: // arithmetic op (carry) reg [reg] reg
+ case 47: // negate [reg] reg
+ r := p.From.Reg
+ if r == 0 {
+ r = p.To.Reg
+ }
switch p.As {
- default:
-
- case AADDME:
- r := int(p.From.Reg)
- if p.To.Reg == p.From.Reg {
- zRRE(op_LGR, REGTMP, uint32(p.From.Reg), asm)
- r = REGTMP
- }
- zRIL(_a, op_LGFI, uint32(p.To.Reg), 0xffffffff, asm) // p.To.Reg <- -1
- zRRE(op_ALCGR, uint32(p.To.Reg), uint32(r), asm)
-
- case AADDZE:
- r := int(p.From.Reg)
- if p.To.Reg == p.From.Reg {
- zRRE(op_LGR, REGTMP, uint32(p.From.Reg), asm)
- r = REGTMP
- }
- zRRE(op_LGR, uint32(p.To.Reg), REGZERO, asm) // p.To.Reg <- 0
- zRRE(op_ALCGR, uint32(p.To.Reg), uint32(r), asm)
-
- case ASUBME:
- r := int(p.From.Reg)
- if p.To.Reg == p.From.Reg {
- zRRE(op_LGR, REGTMP, uint32(p.From.Reg), asm)
- r = REGTMP
- }
- zRIL(_a, op_LGFI, uint32(p.To.Reg), 0xffffffff, asm) // p.To.Reg <- -1
- zRRE(op_SLBGR, uint32(p.To.Reg), uint32(r), asm)
-
- case ASUBZE:
- r := int(p.From.Reg)
- if p.To.Reg == p.From.Reg {
- zRRE(op_LGR, REGTMP, uint32(p.From.Reg), asm)
- r = REGTMP
- }
- zRRE(op_LGR, uint32(p.To.Reg), REGZERO, asm) // p.To.Reg <- 0
- zRRE(op_SLBGR, uint32(p.To.Reg), uint32(r), asm)
-
case ANEG:
- r := int(p.From.Reg)
- if r == 0 {
- r = int(p.To.Reg)
- }
zRRE(op_LCGR, uint32(p.To.Reg), uint32(r), asm)
+ case ANEGW:
+ zRRE(op_LCGFR, uint32(p.To.Reg), uint32(r), asm)
}
+ case 48: // floating-point round to integer
+ m3 := vregoff(ctxt, &p.From)
+ if 0 > m3 || m3 > 7 {
+ ctxt.Diag("mask (%v) must be in the range [0, 7]", m3)
+ }
+ var opcode uint32
+ switch p.As {
+ case AFIEBR:
+ opcode = op_FIEBR
+ case AFIDBR:
+ opcode = op_FIDBR
+ }
+ zRRF(opcode, uint32(m3), 0, uint32(p.To.Reg), uint32(p.Reg), asm)
+
case 67: // fmov $0 freg
var opcode uint32
switch p.As {
@@ -3227,9 +3333,15 @@ func asmout(ctxt *obj.Link, asm *[]byte) {
ctxt.Diag("%v overflows a uint32", v)
}
}
- zRIL(_a, zopril(ctxt, p.As), uint32(p.From.Reg), uint32(regoff(ctxt, &p.To)), asm)
+ if p.As == ACMP && int64(int16(v)) == v {
+ zRI(op_CGHI, uint32(p.From.Reg), uint32(v), asm)
+ } 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)
+ }
- case 72: // mov $constant/$addr mem
+ case 72: // mov $constant mem
v := regoff(ctxt, &p.From)
d := regoff(ctxt, &p.To)
r := p.To.Reg
@@ -3237,23 +3349,7 @@ func asmout(ctxt *obj.Link, asm *[]byte) {
if r == 0 {
r = o.param
}
- if p.From.Sym != nil {
- zRIL(_b, op_LARL, REGTMP, 0, asm)
- if v&0x1 != 0 {
- v -= 1
- zRX(op_LA, REGTMP, REGTMP, 0, 1, asm)
- }
- addrilreloc(ctxt, p.From.Sym, int64(v))
- if d < -DISP20/2 || d >= DISP20/2 {
- zRIL(_a, op_LGFI, REGTMP2, uint32(d), asm)
- if x != 0 {
- zRRE(op_AGR, REGTMP2, uint32(x), asm)
- }
- d = 0
- x = REGTMP2
- }
- zRXY(zopstore(ctxt, p.As), REGTMP, uint32(x), uint32(r), uint32(d), asm)
- } else if int32(int16(v)) == v && x == 0 {
+ if 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)
@@ -3307,16 +3403,7 @@ func asmout(ctxt *obj.Link, asm *[]byte) {
}
zRIL(_b, op_LARL, REGTMP, uint32(d), asm)
addrilreloc(ctxt, p.To.Sym, int64(d))
- if p.From.Sym != nil {
- zRIL(_b, op_LARL, REGTMP2, 0, asm)
- a := uint32(0)
- if v&0x1 != 0 {
- v -= 1
- zRX(op_LA, REGTMP2, REGTMP2, 0, 1, asm)
- }
- addrilrelocoffset(ctxt, p.From.Sym, int64(v), sizeRIL)
- zRXY(zopstore(ctxt, p.As), REGTMP2, 0, REGTMP, a, asm)
- } else if int32(int16(v)) == v {
+ if int32(int16(v)) == v {
var opcode uint32
switch p.As {
case AMOVD:
@@ -3800,6 +3887,39 @@ func asmout(ctxt *obj.Link, asm *[]byte) {
zRSY(op_LMG, uint32(rstart), uint32(rend), uint32(reg), uint32(offset), asm)
}
+ case 99: // interlocked load and op
+ if p.To.Index != 0 {
+ ctxt.Diag("cannot use indexed address")
+ }
+ offset := regoff(ctxt, &p.To)
+ if offset < -DISP20/2 || offset >= DISP20/2 {
+ ctxt.Diag("%v does not fit into 20-bit signed integer", offset)
+ }
+ var opcode uint32
+ switch p.As {
+ case ALAA:
+ opcode = op_LAA
+ case ALAAG:
+ opcode = op_LAAG
+ case ALAAL:
+ opcode = op_LAAL
+ case ALAALG:
+ opcode = op_LAALG
+ case ALAN:
+ opcode = op_LAN
+ case ALANG:
+ opcode = op_LANG
+ case ALAX:
+ opcode = op_LAX
+ case ALAXG:
+ opcode = op_LAXG
+ case ALAO:
+ opcode = op_LAO
+ case ALAOG:
+ opcode = op_LAOG
+ }
+ zRSY(opcode, uint32(p.Reg), uint32(p.From.Reg), uint32(p.To.Reg), uint32(offset), asm)
+
case 100: // VRX STORE
op, m3, _ := vop(p.As)
if p.From3 != nil {
@@ -3980,7 +4100,7 @@ func asmout(ctxt *obj.Link, asm *[]byte) {
v2 := uint32(p.From3.Reg)
v3 := uint32(p.From.Reg)
v4 := uint32(p.Reg)
- zVRRe(op, v1, v2, v3, m5, m6, v4, asm)
+ zVRRe(op, v1, v2, v3, m6, m5, v4, asm)
case 122: // VRR-f LOAD VRS FROM GRS DISJOINT
op, _, _ := vop(p.As)
@@ -4039,7 +4159,7 @@ func zopload(ctxt *obj.Link, a obj.As) uint32 {
return op_LRVH
}
- ctxt.Diag("unknown store opcode %v", obj.Aconv(a))
+ ctxt.Diag("unknown store opcode %v", a)
return 0
}
@@ -4071,7 +4191,7 @@ func zopstore(ctxt *obj.Link, a obj.As) uint32 {
return op_STRVH
}
- ctxt.Diag("unknown store opcode %v", obj.Aconv(a))
+ ctxt.Diag("unknown store opcode %v", a)
return 0
}
@@ -4089,7 +4209,7 @@ func zoprre(ctxt *obj.Link, a obj.As) uint32 {
case ACEBR:
return op_CEBR
}
- ctxt.Diag("unknown rre opcode %v", obj.Aconv(a))
+ ctxt.Diag("unknown rre opcode %v", a)
return 0
}
@@ -4101,7 +4221,7 @@ func zoprr(ctxt *obj.Link, a obj.As) uint32 {
case ACMPWU:
return op_CLR
}
- ctxt.Diag("unknown rr opcode %v", obj.Aconv(a))
+ ctxt.Diag("unknown rr opcode %v", a)
return 0
}
@@ -4117,7 +4237,7 @@ func zopril(ctxt *obj.Link, a obj.As) uint32 {
case ACMPWU:
return op_CLFI
}
- ctxt.Diag("unknown ril opcode %v", obj.Aconv(a))
+ ctxt.Diag("unknown ril opcode %v", a)
return 0
}
diff --git a/src/cmd/internal/obj/s390x/objz.go b/src/cmd/internal/obj/s390x/objz.go
index 0526a35..fca8f85 100644
--- a/src/cmd/internal/obj/s390x/objz.go
+++ b/src/cmd/internal/obj/s390x/objz.go
@@ -66,7 +66,7 @@ func progedit(ctxt *obj.Link, p *obj.Prog) {
s.Size = 4
p.From.Type = obj.TYPE_MEM
p.From.Sym = s
- p.From.Sym.Local = true
+ p.From.Sym.Set(obj.AttrLocal, true)
p.From.Name = obj.NAME_EXTERN
p.From.Offset = 0
}
@@ -82,7 +82,7 @@ func progedit(ctxt *obj.Link, p *obj.Prog) {
s.Size = 8
p.From.Type = obj.TYPE_MEM
p.From.Sym = s
- p.From.Sym.Local = true
+ p.From.Sym.Set(obj.AttrLocal, true)
p.From.Name = obj.NAME_EXTERN
p.From.Offset = 0
}
@@ -99,7 +99,7 @@ func progedit(ctxt *obj.Link, p *obj.Prog) {
s.Size = 8
p.From.Type = obj.TYPE_MEM
p.From.Sym = s
- p.From.Sym.Local = true
+ p.From.Sym.Set(obj.AttrLocal, true)
p.From.Name = obj.NAME_EXTERN
p.From.Offset = 0
}
@@ -109,13 +109,13 @@ func progedit(ctxt *obj.Link, p *obj.Prog) {
// Rewrite SUB constants into ADD.
switch p.As {
case ASUBC:
- if p.From.Type == obj.TYPE_CONST {
+ if p.From.Type == obj.TYPE_CONST && isint32(-p.From.Offset) {
p.From.Offset = -p.From.Offset
p.As = AADDC
}
case ASUB:
- if p.From.Type == obj.TYPE_CONST {
+ if p.From.Type == obj.TYPE_CONST && isint32(-p.From.Offset) {
p.From.Offset = -p.From.Offset
p.As = AADD
}
@@ -137,7 +137,7 @@ func rewriteToUseGot(ctxt *obj.Link, p *obj.Prog) {
// We only care about global data: NAME_EXTERN means a global
// symbol in the Go sense, and p.Sym.Local is true for a few
// internally defined symbols.
- if p.From.Type == obj.TYPE_ADDR && p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local {
+ if p.From.Type == obj.TYPE_ADDR && p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local() {
// MOVD $sym, Rx becomes MOVD sym at GOT, Rx
// MOVD $sym+<off>, Rx becomes MOVD sym at GOT, Rx; ADD <off>, Rx
if p.To.Type != obj.TYPE_REG || p.As != AMOVD {
@@ -162,12 +162,12 @@ func rewriteToUseGot(ctxt *obj.Link, p *obj.Prog) {
// MOVD sym, Ry becomes MOVD sym at GOT, REGTMP; MOVD (REGTMP), Ry
// MOVD Ry, sym becomes MOVD sym at GOT, REGTMP; MOVD Ry, (REGTMP)
// An addition may be inserted between the two MOVs if there is an offset.
- if p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local {
- if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local {
+ if p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local() {
+ if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local() {
ctxt.Diag("cannot handle NAME_EXTERN on both sides in %v with -dynlink", p)
}
source = &p.From
- } else if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local {
+ } else if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local() {
source = &p.To
} else {
return
@@ -242,9 +242,8 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
* expand BECOME pseudo
*/
if ctxt.Debugvlog != 0 {
- fmt.Fprintf(ctxt.Bso, "%5.2f noops\n", obj.Cputime())
+ ctxt.Logf("%5.2f noops\n", obj.Cputime())
}
- ctxt.Bso.Flush()
var q *obj.Prog
var q1 *obj.Prog
@@ -259,14 +258,6 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
p.Link.Mark |= LABEL
}
- case ANOR:
- q = p
- if p.To.Type == obj.TYPE_REG {
- if p.To.Reg == REGZERO {
- p.Mark |= LABEL | SYNC
- }
- }
-
case ASYNC,
AWORD:
q = p
@@ -313,6 +304,8 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
ABGT,
ABLE,
ABLT,
+ ABLEU,
+ ABLTU,
ABNE,
ABR,
ABVC,
@@ -387,7 +380,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
case obj.ATEXT:
autosize = int32(textstksiz)
- if p.Mark&LEAF != 0 && autosize == 0 && p.From3.Offset&obj.NOFRAME == 0 {
+ if p.Mark&LEAF != 0 && autosize == 0 {
// A leaf function with no locals has no frame.
p.From3.Offset |= obj.NOFRAME
}
@@ -398,6 +391,12 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
autosize += int32(ctxt.FixedFrameSize())
}
+ if p.Mark&LEAF != 0 && autosize < obj.StackSmall {
+ // A leaf function with a small stack can be marked
+ // NOSPLIT, avoiding a stack check.
+ p.From3.Offset |= obj.NOSPLIT
+ }
+
p.To.Offset = int64(autosize)
q = p
@@ -409,8 +408,21 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
}
if autosize != 0 {
+ // Make sure to save link register for non-empty frame, even if
+ // it is a leaf function, so that traceback works.
+ // 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.As = AMOVD
+ q.From.Type = obj.TYPE_REG
+ q.From.Reg = REG_LR
+ q.To.Type = obj.TYPE_MEM
+ q.To.Reg = REGSP
+ q.To.Offset = int64(-autosize)
+
+ q = obj.Appendp(ctxt, q)
+ q.As = AMOVD
q.From.Type = obj.TYPE_ADDR
q.From.Offset = int64(-autosize)
q.From.Reg = REGSP // not actually needed - REGSP is assumed if no reg is provided
@@ -425,23 +437,15 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
}
if cursym.Text.Mark&LEAF != 0 {
- cursym.Leaf = true
+ cursym.Set(obj.AttrLeaf, true)
break
}
- q = obj.Appendp(ctxt, q)
- q.As = AMOVD
- q.From.Type = obj.TYPE_REG
- q.From.Reg = REG_LR
- q.To.Type = obj.TYPE_MEM
- q.To.Reg = REGSP
- q.To.Offset = 0
-
if cursym.Text.From3.Offset&obj.WRAPPER != 0 {
// if(g->panic != nil && g->panic->argp == FP) g->panic->argp = bottom-of-frame
//
// MOVD g_panic(g), R3
- // CMP R0, R3
+ // CMP R3, $0
// BEQ end
// MOVD panic_argp(R3), R4
// ADD $(autosize+8), R1, R5
@@ -467,9 +471,9 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
q = obj.Appendp(ctxt, q)
q.As = ACMP
q.From.Type = obj.TYPE_REG
- q.From.Reg = REG_R0
- q.To.Type = obj.TYPE_REG
- q.To.Reg = REG_R3
+ q.From.Reg = REG_R3
+ q.To.Type = obj.TYPE_CONST
+ q.To.Offset = 0
q = obj.Appendp(ctxt, q)
q.As = ABEQ
@@ -606,7 +610,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
}
}
if wasSplit {
- pLast = stacksplitPost(ctxt, pLast, pPre, pPreempt) // emit post part of split check
+ pLast = stacksplitPost(ctxt, pLast, pPre, pPreempt, autosize) // emit post part of split check
}
}
@@ -665,7 +669,7 @@ func stacksplitPre(ctxt *obj.Link, p *obj.Prog, framesize int32) (*obj.Prog, *ob
p.From.Type = obj.TYPE_MEM
p.From.Reg = REGG
p.From.Offset = 2 * int64(ctxt.Arch.PtrSize) // G.stackguard0
- if ctxt.Cursym.Cfunc {
+ if ctxt.Cursym.CFunc() {
p.From.Offset = 3 * int64(ctxt.Arch.PtrSize) // G.stackguard1
}
p.To.Type = obj.TYPE_REG
@@ -782,10 +786,25 @@ 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) *obj.Prog {
+func stacksplitPost(ctxt *obj.Link, 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.As = obj.ANOP
+ spfix.Spadj = -framesize
+
+ pcdata := obj.Appendp(ctxt, spfix)
+ pcdata.Lineno = ctxt.Cursym.Text.Lineno
+ pcdata.Mode = ctxt.Cursym.Text.Mode
+ pcdata.As = obj.APCDATA
+ pcdata.From.Type = obj.TYPE_CONST
+ pcdata.From.Offset = obj.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, p)
+ p = obj.Appendp(ctxt, pcdata)
pPre.Pcond = p
p.As = AMOVD
p.From.Type = obj.TYPE_REG
@@ -801,7 +820,7 @@ func stacksplitPost(ctxt *obj.Link, p *obj.Prog, pPre *obj.Prog, pPreempt *obj.P
p.As = ABL
p.To.Type = obj.TYPE_BRANCH
- if ctxt.Cursym.Cfunc {
+ 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)
@@ -994,6 +1013,7 @@ var unaryDst = map[obj.As]bool{
ASTCKE: true,
ASTCKF: true,
ANEG: true,
+ ANEGW: true,
AVONE: true,
AVZERO: true,
}
diff --git a/src/cmd/internal/obj/sizeof_test.go b/src/cmd/internal/obj/sizeof_test.go
index f7173d3..b8a3c54 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{}, 52, 80},
- {LSym{}, 80, 136},
- {Prog{}, 196, 288},
+ {Addr{}, 40, 64},
+ {LSym{}, 76, 128},
+ {Prog{}, 144, 224},
}
for _, tt := range tests {
diff --git a/src/cmd/internal/obj/stack.go b/src/cmd/internal/obj/stack.go
index 712a10f..687adf2 100644
--- a/src/cmd/internal/obj/stack.go
+++ b/src/cmd/internal/obj/stack.go
@@ -11,7 +11,7 @@ const (
STACKSYSTEM = 0
StackSystem = STACKSYSTEM
StackBig = 4096
- StackGuard = 720*stackGuardMultiplier + StackSystem
+ StackGuard = 880*stackGuardMultiplier + StackSystem
StackSmall = 128
StackLimit = StackGuard - StackSystem - StackSmall
)
diff --git a/src/cmd/internal/obj/sym.go b/src/cmd/internal/obj/sym.go
index e974ca8..84de5b6 100644
--- a/src/cmd/internal/obj/sym.go
+++ b/src/cmd/internal/obj/sym.go
@@ -1,6 +1,6 @@
// Derived from Inferno utils/6l/obj.c and utils/6l/span.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6l/obj.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6l/span.c
+// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/obj.c
+// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/span.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth at terzarima.net)
@@ -32,56 +32,16 @@
package obj
import (
- "cmd/internal/sys"
"log"
"os"
"path/filepath"
- "strconv"
)
-var headers = []struct {
- name string
- val int
-}{
- {"darwin", Hdarwin},
- {"dragonfly", Hdragonfly},
- {"freebsd", Hfreebsd},
- {"linux", Hlinux},
- {"android", Hlinux}, // must be after "linux" entry or else headstr(Hlinux) == "android"
- {"nacl", Hnacl},
- {"netbsd", Hnetbsd},
- {"openbsd", Hopenbsd},
- {"plan9", Hplan9},
- {"solaris", Hsolaris},
- {"windows", Hwindows},
- {"windowsgui", Hwindows},
-}
-
-func headtype(name string) int {
- for i := 0; i < len(headers); i++ {
- if name == headers[i].name {
- return headers[i].val
- }
- }
- return -1
-}
-
-func Headstr(v int) string {
- for i := 0; i < len(headers); i++ {
- if v == headers[i].val {
- return headers[i].name
- }
- }
- return strconv.Itoa(v)
-}
-
func Linknew(arch *LinkArch) *Link {
ctxt := new(Link)
ctxt.Hash = make(map[SymVer]*LSym)
ctxt.Arch = arch
ctxt.Version = HistVersion
- ctxt.Goroot = Getgoroot()
- ctxt.Goroot_final = os.Getenv("GOROOT_FINAL")
var buf string
buf, _ = os.Getwd()
@@ -91,22 +51,16 @@ func Linknew(arch *LinkArch) *Link {
buf = filepath.ToSlash(buf)
ctxt.Pathname = buf
- ctxt.LineHist.GOROOT = ctxt.Goroot
- ctxt.LineHist.GOROOT_FINAL = ctxt.Goroot_final
+ ctxt.LineHist.GOROOT = GOROOT
ctxt.LineHist.Dir = ctxt.Pathname
- ctxt.Headtype = headtype(Getgoos())
+ ctxt.Headtype.Set(GOOS)
if ctxt.Headtype < 0 {
- log.Fatalf("unknown goos %s", Getgoos())
- }
-
- // On arm, record goarm.
- if ctxt.Arch.Family == sys.ARM {
- ctxt.Goarm = Getgoarm()
+ log.Fatalf("unknown goos %s", GOOS)
}
ctxt.Flag_optimize = true
- ctxt.Framepointer_enabled = Framepointer_enabled(Getgoos(), arch.Name)
+ ctxt.Framepointer_enabled = Framepointer_enabled(GOOS, arch.Name)
return ctxt
}
diff --git a/src/cmd/internal/obj/symkind_string.go b/src/cmd/internal/obj/symkind_string.go
new file mode 100644
index 0000000..fef8c35
--- /dev/null
+++ b/src/cmd/internal/obj/symkind_string.go
@@ -0,0 +1,16 @@
+// 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/util.go b/src/cmd/internal/obj/util.go
index 18813c3..bc5d1c5 100644
--- a/src/cmd/internal/obj/util.go
+++ b/src/cmd/internal/obj/util.go
@@ -31,19 +31,16 @@ func envOr(key, value string) string {
return value
}
-func Getgoroot() string {
- return envOr("GOROOT", defaultGOROOT)
-}
-
-func Getgoarch() string {
- return envOr("GOARCH", defaultGOARCH)
-}
-
-func Getgoos() string {
- return envOr("GOOS", defaultGOOS)
-}
+var (
+ GOROOT = envOr("GOROOT", defaultGOROOT)
+ GOARCH = envOr("GOARCH", defaultGOARCH)
+ GOOS = envOr("GOOS", defaultGOOS)
+ GO386 = envOr("GO386", defaultGO386)
+ GOARM = goarm()
+ Version = version
+)
-func Getgoarm() int32 {
+func goarm() int {
switch v := envOr("GOARM", defaultGOARM); v {
case "5":
return 5
@@ -57,19 +54,10 @@ func Getgoarm() int32 {
panic("unreachable")
}
-func Getgo386() string {
- // Validated by cmd/compile.
- return envOr("GO386", defaultGO386)
-}
-
func Getgoextlinkenabled() string {
return envOr("GO_EXTLINK_ENABLED", defaultGO_EXTLINK_ENABLED)
}
-func Getgoversion() string {
- return version
-}
-
func (p *Prog) Line() string {
return p.Ctxt.LineHist.LineString(int(p.Lineno))
}
@@ -138,7 +126,7 @@ func (p *Prog) String() string {
var buf bytes.Buffer
- fmt.Fprintf(&buf, "%.5d (%v)\t%v%s", p.Pc, p.Line(), Aconv(p.As), sc)
+ fmt.Fprintf(&buf, "%.5d (%v)\t%v%s", p.Pc, p.Line(), p.As, sc)
sep := "\t"
quadOpAmd64 := p.RegTo2 == -1
if quadOpAmd64 {
@@ -155,7 +143,7 @@ func (p *Prog) String() string {
sep = ", "
}
if p.From3Type() != TYPE_NONE {
- if p.From3.Type == TYPE_CONST && (p.As == ATEXT || p.As == AGLOBL) {
+ if p.From3.Type == TYPE_CONST && p.As == ATEXT {
// Special case - omit $.
fmt.Fprintf(&buf, "%s%d", sep, p.From3.Offset)
} else if quadOpAmd64 {
@@ -252,9 +240,6 @@ func Dconv(p *Prog, a *Addr) string {
if a.Index != REG_NONE {
str += fmt.Sprintf("(%v*%d)", Rconv(int(a.Index)), int(a.Scale))
}
- if p != nil && p.As == ATYPE && a.Gotype != nil {
- str += fmt.Sprintf("%s", a.Gotype.Name)
- }
case TYPE_CONST:
if a.Reg != 0 {
@@ -286,14 +271,23 @@ func Dconv(p *Prog, a *Addr) string {
case TYPE_SHIFT:
v := int(a.Offset)
- op := "<<>>->@>"[((v>>5)&3)<<1:]
- if v&(1<<4) != 0 {
- str = fmt.Sprintf("R%d%c%cR%d", v&15, op[0], op[1], (v>>8)&15)
- } else {
- str = fmt.Sprintf("R%d%c%c%d", v&15, op[0], op[1], (v>>7)&31)
- }
- if a.Reg != 0 {
- str += fmt.Sprintf("(%v)", Rconv(int(a.Reg)))
+ ops := "<<>>->@>"
+ switch GOARCH {
+ case "arm":
+ op := ops[((v>>5)&3)<<1:]
+ if v&(1<<4) != 0 {
+ str = fmt.Sprintf("R%d%c%cR%d", v&15, op[0], op[1], (v>>8)&15)
+ } else {
+ str = fmt.Sprintf("R%d%c%c%d", v&15, op[0], op[1], (v>>7)&31)
+ }
+ if a.Reg != 0 {
+ str += fmt.Sprintf("(%v)", Rconv(int(a.Reg)))
+ }
+ case "arm64":
+ 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)
}
case TYPE_REGREG:
@@ -390,13 +384,13 @@ var regSpace []regSet
const (
// Because of masking operations in the encodings, each register
// space should start at 0 modulo some power of 2.
- RBase386 = 1 * 1024
- RBaseAMD64 = 2 * 1024
- RBaseARM = 3 * 1024
- RBasePPC64 = 4 * 1024 // range [4k, 8k)
- RBaseARM64 = 8 * 1024 // range [8k, 13k)
- RBaseMIPS64 = 13 * 1024 // range [13k, 14k)
- RBaseS390X = 14 * 1024 // range [14k, 15k)
+ RBase386 = 1 * 1024
+ RBaseAMD64 = 2 * 1024
+ RBaseARM = 3 * 1024
+ RBasePPC64 = 4 * 1024 // range [4k, 8k)
+ RBaseARM64 = 8 * 1024 // range [8k, 13k)
+ RBaseMIPS = 13 * 1024 // range [13k, 14k)
+ RBaseS390X = 14 * 1024 // range [14k, 15k)
)
// RegisterRegister binds a pretty-printer (Rconv) for register
@@ -453,10 +447,13 @@ var aSpace []opSet
// RegisterOpcode binds a list of instruction names
// to a given instruction number range.
func RegisterOpcode(lo As, Anames []string) {
+ if len(Anames) > AllowedOpCodes {
+ panic(fmt.Sprintf("too many instructions, have %d max %d", len(Anames), AllowedOpCodes))
+ }
aSpace = append(aSpace, opSet{lo, Anames})
}
-func Aconv(a As) string {
+func (a As) String() string {
if 0 <= a && int(a) < len(Anames) {
return Anames[a]
}
@@ -472,12 +469,10 @@ func Aconv(a As) string {
var Anames = []string{
"XXX",
"CALL",
- "CHECKNIL",
"DUFFCOPY",
"DUFFZERO",
"END",
"FUNCDATA",
- "GLOBL",
"JMP",
"NOP",
"PCDATA",
@@ -492,8 +487,13 @@ var Anames = []string{
}
func Bool2int(b bool) int {
+ // The compiler currently only optimizes this form.
+ // See issue 6011.
+ var i int
if b {
- return 1
+ i = 1
+ } else {
+ i = 0
}
- return 0
+ return i
}
diff --git a/src/cmd/internal/obj/x86/a.out.go b/src/cmd/internal/obj/x86/a.out.go
index ab1dabc..02f92ed 100644
--- a/src/cmd/internal/obj/x86/a.out.go
+++ b/src/cmd/internal/obj/x86/a.out.go
@@ -1,5 +1,5 @@
// Inferno utils/6c/6.out.h
-// http://code.google.com/p/inferno-os/source/browse/utils/6c/6.out.h
+// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6c/6.out.h
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth at terzarima.net)
@@ -771,6 +771,9 @@ const (
AROUNDSS
AROUNDPD
AROUNDSD
+ AMOVDDUP
+ AMOVSHDUP
+ AMOVSLDUP
APSHUFD
APCLMULQDQ
@@ -803,6 +806,11 @@ const (
AVPERM2I128
ARORXL
ARORXQ
+ AVBROADCASTSS
+ AVBROADCASTSD
+ AVMOVDDUP
+ AVMOVSHDUP
+ AVMOVSLDUP
// from 386
AJCXZW
diff --git a/src/cmd/internal/obj/x86/anames.go b/src/cmd/internal/obj/x86/anames.go
index 3b30154..8c5be80 100644
--- a/src/cmd/internal/obj/x86/anames.go
+++ b/src/cmd/internal/obj/x86/anames.go
@@ -708,6 +708,9 @@ var Anames = []string{
"ROUNDSS",
"ROUNDPD",
"ROUNDSD",
+ "MOVDDUP",
+ "MOVSHDUP",
+ "MOVSLDUP",
"PSHUFD",
"PCLMULQDQ",
"VZEROUPPER",
@@ -738,6 +741,11 @@ var Anames = []string{
"VPERM2I128",
"RORXL",
"RORXQ",
+ "VBROADCASTSS",
+ "VBROADCASTSD",
+ "VMOVDDUP",
+ "VMOVSHDUP",
+ "VMOVSLDUP",
"JCXZW",
"FCMOVCC",
"FCMOVCS",
diff --git a/src/cmd/internal/obj/x86/asm6.go b/src/cmd/internal/obj/x86/asm6.go
index 676da40..bf67822 100644
--- a/src/cmd/internal/obj/x86/asm6.go
+++ b/src/cmd/internal/obj/x86/asm6.go
@@ -1,5 +1,5 @@
// Inferno utils/6l/span.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6l/span.c
+// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/span.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth at terzarima.net)
@@ -56,7 +56,7 @@ const (
//
LoopAlign = 16
MaxLoopPad = 0
- FuncAlign = 16
+ funcAlign = 16
)
type Optab struct {
@@ -352,14 +352,6 @@ var yxorb = []ytab{
{Ymb, Ynone, Yrb, Zm_r, 1},
}
-var yxorl = []ytab{
- {Yi8, Ynone, Yml, Zibo_m, 2},
- {Yi32, Ynone, Yax, Zil_, 1},
- {Yi32, Ynone, Yml, Zilo_m, 2},
- {Yrl, Ynone, Yml, Zr_m, 1},
- {Yml, Ynone, Yrl, Zm_r, 1},
-}
-
var yaddl = []ytab{
{Yi8, Ynone, Yml, Zibo_m, 2},
{Yi32, Ynone, Yax, Zil_, 1},
@@ -368,14 +360,6 @@ var yaddl = []ytab{
{Yml, Ynone, Yrl, Zm_r, 1},
}
-var yincb = []ytab{
- {Ynone, Ynone, Ymb, Zo_m, 2},
-}
-
-var yincw = []ytab{
- {Ynone, Ynone, Yml, Zo_m, 2},
-}
-
var yincl = []ytab{
{Ynone, Ynone, Yrl, Z_rp, 1},
{Ynone, Ynone, Yml, Zo_m, 2},
@@ -413,13 +397,6 @@ var yshl = []ytab{
{Ycx, Ynone, Yml, Zo_m, 2},
}
-var ytestb = []ytab{
- {Yi32, Ynone, Yal, Zib_, 1},
- {Yi32, Ynone, Ymb, Zibo_m, 2},
- {Yrb, Ynone, Ymb, Zr_m, 1},
- {Ymb, Ynone, Yrb, Zm_r, 1},
-}
-
var ytestl = []ytab{
{Yi32, Ynone, Yax, Zil_, 1},
{Yi32, Ynone, Yml, Zilo_m, 2},
@@ -434,10 +411,6 @@ var ymovb = []ytab{
{Yi32, Ynone, Ymb, Zibo_m, 2},
}
-var ymbs = []ytab{
- {Ymb, Ynone, Ynone, Zm_o, 2},
-}
-
var ybtl = []ytab{
{Yi8, Ynone, Yml, Zibo_m, 2},
{Yrl, Ynone, Yml, Zr_m, 1},
@@ -643,10 +616,6 @@ var yfadd = []ytab{
{Yf0, Ynone, Yrf, Zo_m, 2},
}
-var yfaddp = []ytab{
- {Yf0, Ynone, Yrf, Zo_m, 2},
-}
-
var yfxch = []ytab{
{Yf0, Ynone, Yrf, Zo_m, 2},
{Yrf, Ynone, Yf0, Zm_o, 2},
@@ -661,11 +630,6 @@ var ystsw = []ytab{
{Ynone, Ynone, Yax, Zlit, 1},
}
-var ystcw = []ytab{
- {Ynone, Ynone, Ym, Zo_m, 2},
- {Ym, Ynone, Ynone, Zm_o, 2},
-}
-
var ysvrs = []ytab{
{Ynone, Ynone, Ym, Zo_m, 2},
{Ym, Ynone, Ynone, Zm_o, 2},
@@ -694,12 +658,6 @@ var yxcvm2 = []ytab{
{Ymm, Ynone, Yxr, Zm_r_xm, 2},
}
-/*
-var yxmq = []ytab{
- {Yxm, Ynone, Yxr, Zm_r_xm, 2},
-}
-*/
-
var yxr = []ytab{
{Yxr, Ynone, Yxr, Zm_r_xm, 1},
}
@@ -716,10 +674,6 @@ var ymr_ml = []ytab{
{Ymr, Ynone, Yml, Zr_m_xm, 1},
}
-var yxcmp = []ytab{
- {Yxm, Ynone, Yxr, Zm_r_xm, 1},
-}
-
var yxcmpi = []ytab{
{Yxm, Yxr, Yi8, Zm_r_i_xm, 2},
}
@@ -810,10 +764,6 @@ var yaes = []ytab{
{Yxm, Ynone, Yxr, Zlitm_r, 2},
}
-var yaes2 = []ytab{
- {Yu8, Yxm, Yxr, Zibm_r, 2},
-}
-
var yxbegin = []ytab{
{Ynone, Ynone, Ybr, Zjmp, 1},
}
@@ -855,6 +805,8 @@ var yvex_ri3 = []ytab{
}
var yvex_xyi3 = []ytab{
+ {Yu8, Yxm, Yxr, Zvex_i_rm_r, 2},
+ {Yu8, Yym, Yyr, Zvex_i_rm_r, 2},
{Yi8, Yxm, Yxr, Zvex_i_rm_r, 2},
{Yi8, Yym, Yyr, Zvex_i_rm_r, 2},
}
@@ -881,12 +833,10 @@ var yvex_shift_dq = []ytab{
var yvex_r3 = []ytab{
{Yml, Yrl, Yrl, Zvex_rm_v_r, 2},
- {Yml, Yrl, Yrl, Zvex_rm_v_r, 2},
}
var yvex_vmr3 = []ytab{
{Yrl, Yml, Yrl, Zvex_v_rm_r, 2},
- {Yrl, Yml, Yrl, Zvex_v_rm_r, 2},
}
var yvex_xy2 = []ytab{
@@ -916,6 +866,10 @@ var yvex_vpbroadcast = []ytab{
{Yxm, Ynone, Yyr, Zvex_rm_v_r, 2},
}
+var yvex_vpbroadcast_sd = []ytab{
+ {Yxm, Ynone, Yyr, Zvex_rm_v_r, 2},
+}
+
var ymmxmm0f38 = []ytab{
{Ymm, Ynone, Ymr, Zlitm_r, 3},
{Yxm, Ynone, Yxr, Zlitm_r, 5},
@@ -988,9 +942,9 @@ var optab =
{AAAM, ynone, P32, [23]uint8{0xd4, 0x0a}},
{AAAS, ynone, P32, [23]uint8{0x3f}},
{AADCB, yxorb, Pb, [23]uint8{0x14, 0x80, 02, 0x10, 0x10}},
- {AADCL, yxorl, Px, [23]uint8{0x83, 02, 0x15, 0x81, 02, 0x11, 0x13}},
- {AADCQ, yxorl, Pw, [23]uint8{0x83, 02, 0x15, 0x81, 02, 0x11, 0x13}},
- {AADCW, yxorl, Pe, [23]uint8{0x83, 02, 0x15, 0x81, 02, 0x11, 0x13}},
+ {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}},
{AADDB, yxorb, Pb, [23]uint8{0x04, 0x80, 00, 0x00, 0x02}},
{AADDL, yaddl, Px, [23]uint8{0x83, 00, 0x05, 0x81, 00, 0x01, 0x03}},
{AADDPD, yxm, Pq, [23]uint8{0x58}},
@@ -1001,13 +955,13 @@ var optab =
{AADDW, yaddl, Pe, [23]uint8{0x83, 00, 0x05, 0x81, 00, 0x01, 0x03}},
{AADJSP, nil, 0, [23]uint8{}},
{AANDB, yxorb, Pb, [23]uint8{0x24, 0x80, 04, 0x20, 0x22}},
- {AANDL, yxorl, Px, [23]uint8{0x83, 04, 0x25, 0x81, 04, 0x21, 0x23}},
+ {AANDL, yaddl, Px, [23]uint8{0x83, 04, 0x25, 0x81, 04, 0x21, 0x23}},
{AANDNPD, yxm, Pq, [23]uint8{0x55}},
{AANDNPS, yxm, Pm, [23]uint8{0x55}},
{AANDPD, yxm, Pq, [23]uint8{0x54}},
{AANDPS, yxm, Pq, [23]uint8{0x54}},
- {AANDQ, yxorl, Pw, [23]uint8{0x83, 04, 0x25, 0x81, 04, 0x21, 0x23}},
- {AANDW, yxorl, Pe, [23]uint8{0x83, 04, 0x25, 0x81, 04, 0x21, 0x23}},
+ {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}},
{ABOUNDL, yrl_m, P32, [23]uint8{0x62}},
{ABOUNDW, yrl_m, Pe, [23]uint8{0x62}},
@@ -1099,8 +1053,8 @@ var optab =
{ACMPSS, yxcmpi, Px, [23]uint8{Pf3, 0xc2}},
{ACMPSW, ynone, Pe, [23]uint8{0xa7}},
{ACMPW, ycmpl, Pe, [23]uint8{0x83, 07, 0x3d, 0x81, 07, 0x39, 0x3b}},
- {ACOMISD, yxcmp, Pe, [23]uint8{0x2f}},
- {ACOMISS, yxcmp, Pm, [23]uint8{0x2f}},
+ {ACOMISD, yxm, Pe, [23]uint8{0x2f}},
+ {ACOMISS, yxm, Pm, [23]uint8{0x2f}},
{ACPUID, ynone, Pm, [23]uint8{0xa2}},
{ACVTPL2PD, yxcvm2, Px, [23]uint8{Pf3, 0xe6, Pe, 0x2a}},
{ACVTPL2PS, yxcvm2, Pm, [23]uint8{0x5b, 0, 0x2a, 0}},
@@ -1128,10 +1082,10 @@ var optab =
{ACQO, ynone, Pw, [23]uint8{0x99}},
{ADAA, ynone, P32, [23]uint8{0x27}},
{ADAS, ynone, P32, [23]uint8{0x2f}},
- {ADECB, yincb, Pb, [23]uint8{0xfe, 01}},
+ {ADECB, yscond, Pb, [23]uint8{0xfe, 01}},
{ADECL, yincl, Px1, [23]uint8{0x48, 0xff, 01}},
{ADECQ, yincq, Pw, [23]uint8{0xff, 01}},
- {ADECW, yincw, Pe, [23]uint8{0xff, 01}},
+ {ADECW, yincq, Pe, [23]uint8{0xff, 01}},
{ADIVB, ydivb, Pb, [23]uint8{0xf6, 06}},
{ADIVL, ydivl, Px, [23]uint8{0xf7, 06}},
{ADIVPD, yxm, Pe, [23]uint8{0x5e}},
@@ -1146,7 +1100,6 @@ var optab =
{AFXSAVE, ysvrs, Pm, [23]uint8{0xae, 00, 0xae, 00}},
{AFXRSTOR64, ysvrs, Pw, [23]uint8{0x0f, 0xae, 01, 0x0f, 0xae, 01}},
{AFXSAVE64, ysvrs, Pw, [23]uint8{0x0f, 0xae, 00, 0x0f, 0xae, 00}},
- {obj.AGLOBL, nil, 0, [23]uint8{}},
{AHLT, ynone, Px, [23]uint8{0xf4}},
{AIDIVB, ydivb, Pb, [23]uint8{0xf6, 07}},
{AIDIVL, ydivl, Px, [23]uint8{0xf7, 07}},
@@ -1158,10 +1111,10 @@ var optab =
{AIMULW, yimul, Pe, [23]uint8{0xf7, 05, 0x6b, 0x69, Pm, 0xaf}},
{AIMUL3Q, yimul3, Pw, [23]uint8{0x6b, 00}},
{AINB, yin, Pb, [23]uint8{0xe4, 0xec}},
- {AINCB, yincb, Pb, [23]uint8{0xfe, 00}},
+ {AINCB, yscond, Pb, [23]uint8{0xfe, 00}},
{AINCL, yincl, Px1, [23]uint8{0x40, 0xff, 00}},
{AINCQ, yincq, Pw, [23]uint8{0xff, 00}},
- {AINCW, yincw, Pe, [23]uint8{0xff, 00}},
+ {AINCW, yincq, Pe, [23]uint8{0xff, 00}},
{AINL, yin, Px, [23]uint8{0xe5, 0xed}},
{AINSB, ynone, Pb, [23]uint8{0x6c}},
{AINSL, ynone, Px, [23]uint8{0x6d}},
@@ -1287,11 +1240,11 @@ var optab =
{ANOTQ, yscond, Pw, [23]uint8{0xf7, 02}},
{ANOTW, yscond, Pe, [23]uint8{0xf7, 02}},
{AORB, yxorb, Pb, [23]uint8{0x0c, 0x80, 01, 0x08, 0x0a}},
- {AORL, yxorl, Px, [23]uint8{0x83, 01, 0x0d, 0x81, 01, 0x09, 0x0b}},
+ {AORL, yaddl, Px, [23]uint8{0x83, 01, 0x0d, 0x81, 01, 0x09, 0x0b}},
{AORPD, yxm, Pq, [23]uint8{0x56}},
{AORPS, yxm, Pm, [23]uint8{0x56}},
- {AORQ, yxorl, Pw, [23]uint8{0x83, 01, 0x0d, 0x81, 01, 0x09, 0x0b}},
- {AORW, yxorl, Pe, [23]uint8{0x83, 01, 0x0d, 0x81, 01, 0x09, 0x0b}},
+ {AORQ, yaddl, Pw, [23]uint8{0x83, 01, 0x0d, 0x81, 01, 0x09, 0x0b}},
+ {AORW, yaddl, Pe, [23]uint8{0x83, 01, 0x0d, 0x81, 01, 0x09, 0x0b}},
{AOUTB, yin, Pb, [23]uint8{0xe6, 0xee}},
{AOUTL, yin, Px, [23]uint8{0xe7, 0xef}},
{AOUTSB, ynone, Pb, [23]uint8{0x6e}},
@@ -1449,9 +1402,9 @@ var optab =
{ASARQ, yshl, Pw, [23]uint8{0xd1, 07, 0xc1, 07, 0xd3, 07, 0xd3, 07}},
{ASARW, yshl, Pe, [23]uint8{0xd1, 07, 0xc1, 07, 0xd3, 07, 0xd3, 07}},
{ASBBB, yxorb, Pb, [23]uint8{0x1c, 0x80, 03, 0x18, 0x1a}},
- {ASBBL, yxorl, Px, [23]uint8{0x83, 03, 0x1d, 0x81, 03, 0x19, 0x1b}},
- {ASBBQ, yxorl, Pw, [23]uint8{0x83, 03, 0x1d, 0x81, 03, 0x19, 0x1b}},
- {ASBBW, yxorl, Pe, [23]uint8{0x83, 03, 0x1d, 0x81, 03, 0x19, 0x1b}},
+ {ASBBL, yaddl, Px, [23]uint8{0x83, 03, 0x1d, 0x81, 03, 0x19, 0x1b}},
+ {ASBBQ, yaddl, Pw, [23]uint8{0x83, 03, 0x1d, 0x81, 03, 0x19, 0x1b}},
+ {ASBBW, yaddl, Pe, [23]uint8{0x83, 03, 0x1d, 0x81, 03, 0x19, 0x1b}},
{ASCASB, ynone, Pb, [23]uint8{0xae}},
{ASCASL, ynone, Px, [23]uint8{0xaf}},
{ASCASQ, ynone, Pw, [23]uint8{0xaf}},
@@ -1504,13 +1457,13 @@ var optab =
{ASUBW, yaddl, Pe, [23]uint8{0x83, 05, 0x2d, 0x81, 05, 0x29, 0x2b}},
{ASWAPGS, ynone, Pm, [23]uint8{0x01, 0xf8}},
{ASYSCALL, ynone, Px, [23]uint8{0x0f, 0x05}}, /* fast syscall */
- {ATESTB, ytestb, Pb, [23]uint8{0xa8, 0xf6, 00, 0x84, 0x84}},
+ {ATESTB, yxorb, Pb, [23]uint8{0xa8, 0xf6, 00, 0x84, 0x84}},
{ATESTL, ytestl, Px, [23]uint8{0xa9, 0xf7, 00, 0x85, 0x85}},
{ATESTQ, ytestl, Pw, [23]uint8{0xa9, 0xf7, 00, 0x85, 0x85}},
{ATESTW, ytestl, Pe, [23]uint8{0xa9, 0xf7, 00, 0x85, 0x85}},
{obj.ATEXT, ytext, Px, [23]uint8{}},
- {AUCOMISD, yxcmp, Pe, [23]uint8{0x2e}},
- {AUCOMISS, yxcmp, Pm, [23]uint8{0x2e}},
+ {AUCOMISD, yxm, Pe, [23]uint8{0x2e}},
+ {AUCOMISS, yxm, Pm, [23]uint8{0x2e}},
{AUNPCKHPD, yxm, Pe, [23]uint8{0x15}},
{AUNPCKHPS, yxm, Pm, [23]uint8{0x15}},
{AUNPCKLPD, yxm, Pe, [23]uint8{0x14}},
@@ -1525,11 +1478,11 @@ var optab =
{AXCHGW, yxchg, Pe, [23]uint8{0x90, 0x90, 0x87, 0x87}},
{AXLAT, ynone, Px, [23]uint8{0xd7}},
{AXORB, yxorb, Pb, [23]uint8{0x34, 0x80, 06, 0x30, 0x32}},
- {AXORL, yxorl, Px, [23]uint8{0x83, 06, 0x35, 0x81, 06, 0x31, 0x33}},
+ {AXORL, yaddl, Px, [23]uint8{0x83, 06, 0x35, 0x81, 06, 0x31, 0x33}},
{AXORPD, yxm, Pe, [23]uint8{0x57}},
{AXORPS, yxm, Pm, [23]uint8{0x57}},
- {AXORQ, yxorl, Pw, [23]uint8{0x83, 06, 0x35, 0x81, 06, 0x31, 0x33}},
- {AXORW, yxorl, Pe, [23]uint8{0x83, 06, 0x35, 0x81, 06, 0x31, 0x33}},
+ {AXORQ, yaddl, Pw, [23]uint8{0x83, 06, 0x35, 0x81, 06, 0x31, 0x33}},
+ {AXORW, yaddl, Pe, [23]uint8{0x83, 06, 0x35, 0x81, 06, 0x31, 0x33}},
{AFMOVB, yfmvx, Px, [23]uint8{0xdf, 04}},
{AFMOVBP, yfmvp, Px, [23]uint8{0xdf, 06}},
{AFMOVD, yfmvd, Px, [23]uint8{0xdd, 00, 0xdd, 02, 0xd9, 00, 0xdd, 02}},
@@ -1568,44 +1521,44 @@ var optab =
{AFUCOMIP, ycompp, Px, [23]uint8{0xdf, 05}},
{AFUCOMP, ycompp, Px, [23]uint8{0xdd, 05}},
{AFUCOMPP, ycompp, Px, [23]uint8{0xda, 13}},
- {AFADDDP, yfaddp, Px, [23]uint8{0xde, 00}},
+ {AFADDDP, ycompp, Px, [23]uint8{0xde, 00}},
{AFADDW, yfmvx, Px, [23]uint8{0xde, 00}},
{AFADDL, yfmvx, Px, [23]uint8{0xda, 00}},
{AFADDF, yfmvx, Px, [23]uint8{0xd8, 00}},
{AFADDD, yfadd, Px, [23]uint8{0xdc, 00, 0xd8, 00, 0xdc, 00}},
- {AFMULDP, yfaddp, Px, [23]uint8{0xde, 01}},
+ {AFMULDP, ycompp, Px, [23]uint8{0xde, 01}},
{AFMULW, yfmvx, Px, [23]uint8{0xde, 01}},
{AFMULL, yfmvx, Px, [23]uint8{0xda, 01}},
{AFMULF, yfmvx, Px, [23]uint8{0xd8, 01}},
{AFMULD, yfadd, Px, [23]uint8{0xdc, 01, 0xd8, 01, 0xdc, 01}},
- {AFSUBDP, yfaddp, Px, [23]uint8{0xde, 05}},
+ {AFSUBDP, ycompp, Px, [23]uint8{0xde, 05}},
{AFSUBW, yfmvx, Px, [23]uint8{0xde, 04}},
{AFSUBL, yfmvx, Px, [23]uint8{0xda, 04}},
{AFSUBF, yfmvx, Px, [23]uint8{0xd8, 04}},
{AFSUBD, yfadd, Px, [23]uint8{0xdc, 04, 0xd8, 04, 0xdc, 05}},
- {AFSUBRDP, yfaddp, Px, [23]uint8{0xde, 04}},
+ {AFSUBRDP, ycompp, Px, [23]uint8{0xde, 04}},
{AFSUBRW, yfmvx, Px, [23]uint8{0xde, 05}},
{AFSUBRL, yfmvx, Px, [23]uint8{0xda, 05}},
{AFSUBRF, yfmvx, Px, [23]uint8{0xd8, 05}},
{AFSUBRD, yfadd, Px, [23]uint8{0xdc, 05, 0xd8, 05, 0xdc, 04}},
- {AFDIVDP, yfaddp, Px, [23]uint8{0xde, 07}},
+ {AFDIVDP, ycompp, Px, [23]uint8{0xde, 07}},
{AFDIVW, yfmvx, Px, [23]uint8{0xde, 06}},
{AFDIVL, yfmvx, Px, [23]uint8{0xda, 06}},
{AFDIVF, yfmvx, Px, [23]uint8{0xd8, 06}},
{AFDIVD, yfadd, Px, [23]uint8{0xdc, 06, 0xd8, 06, 0xdc, 07}},
- {AFDIVRDP, yfaddp, Px, [23]uint8{0xde, 06}},
+ {AFDIVRDP, ycompp, Px, [23]uint8{0xde, 06}},
{AFDIVRW, yfmvx, Px, [23]uint8{0xde, 07}},
{AFDIVRL, yfmvx, Px, [23]uint8{0xda, 07}},
{AFDIVRF, yfmvx, Px, [23]uint8{0xd8, 07}},
{AFDIVRD, yfadd, Px, [23]uint8{0xdc, 07, 0xd8, 07, 0xdc, 06}},
{AFXCHD, yfxch, Px, [23]uint8{0xd9, 01, 0xd9, 01}},
{AFFREE, nil, 0, [23]uint8{}},
- {AFLDCW, ystcw, Px, [23]uint8{0xd9, 05, 0xd9, 05}},
- {AFLDENV, ystcw, Px, [23]uint8{0xd9, 04, 0xd9, 04}},
+ {AFLDCW, ysvrs, Px, [23]uint8{0xd9, 05, 0xd9, 05}},
+ {AFLDENV, ysvrs, Px, [23]uint8{0xd9, 04, 0xd9, 04}},
{AFRSTOR, ysvrs, Px, [23]uint8{0xdd, 04, 0xdd, 04}},
{AFSAVE, ysvrs, Px, [23]uint8{0xdd, 06, 0xdd, 06}},
- {AFSTCW, ystcw, Px, [23]uint8{0xd9, 07, 0xd9, 07}},
- {AFSTENV, ystcw, Px, [23]uint8{0xd9, 06, 0xd9, 06}},
+ {AFSTCW, ysvrs, Px, [23]uint8{0xd9, 07, 0xd9, 07}},
+ {AFSTENV, ysvrs, Px, [23]uint8{0xd9, 06, 0xd9, 06}},
{AFSTSW, ystsw, Px, [23]uint8{0xdd, 07, 0xdf, 0xe0}},
{AF2XM1, ynone, Px, [23]uint8{0xd9, 0xf0}},
{AFABS, ynone, Px, [23]uint8{0xd9, 0xe1}},
@@ -1643,7 +1596,7 @@ var optab =
{ACMPXCHGQ, yrl_ml, Pw, [23]uint8{0x0f, 0xb1}},
{ACMPXCHG8B, yscond, Pm, [23]uint8{0xc7, 01}},
{AINVD, ynone, Pm, [23]uint8{0x08}},
- {AINVLPG, ymbs, Pm, [23]uint8{0x01, 07}},
+ {AINVLPG, ydivb, Pm, [23]uint8{0x01, 07}},
{ALFENCE, ynone, Pm, [23]uint8{0xae, 0xe8}},
{AMFENCE, ynone, Pm, [23]uint8{0xae, 0xf0}},
{AMOVNTIL, yrl_ml, Pm, [23]uint8{0xc3}},
@@ -1673,14 +1626,17 @@ var optab =
{AAESDEC, yaes, Pq, [23]uint8{0x38, 0xde, 0}},
{AAESDECLAST, yaes, Pq, [23]uint8{0x38, 0xdf, 0}},
{AAESIMC, yaes, Pq, [23]uint8{0x38, 0xdb, 0}},
- {AAESKEYGENASSIST, yaes2, Pq, [23]uint8{0x3a, 0xdf, 0}},
- {AROUNDPD, yaes2, Pq, [23]uint8{0x3a, 0x09, 0}},
- {AROUNDPS, yaes2, Pq, [23]uint8{0x3a, 0x08, 0}},
- {AROUNDSD, yaes2, Pq, [23]uint8{0x3a, 0x0b, 0}},
- {AROUNDSS, yaes2, Pq, [23]uint8{0x3a, 0x0a, 0}},
+ {AAESKEYGENASSIST, yxshuf, Pq, [23]uint8{0x3a, 0xdf, 0}},
+ {AROUNDPD, yxshuf, Pq, [23]uint8{0x3a, 0x09, 0}},
+ {AROUNDPS, yxshuf, Pq, [23]uint8{0x3a, 0x08, 0}},
+ {AROUNDSD, yxshuf, Pq, [23]uint8{0x3a, 0x0b, 0}},
+ {AROUNDSS, yxshuf, Pq, [23]uint8{0x3a, 0x0a, 0}},
{APSHUFD, yxshuf, Pq, [23]uint8{0x70, 0}},
{APCLMULQDQ, yxshuf, Pq, [23]uint8{0x3a, 0x44, 0}},
{APCMPESTRI, yxshuf, Pq, [23]uint8{0x3a, 0x61, 0}},
+ {AMOVDDUP, yxm, Pf2, [23]uint8{0x12}},
+ {AMOVSHDUP, yxm, Pf3, [23]uint8{0x16}},
+ {AMOVSLDUP, yxm, Pf3, [23]uint8{0x12}},
{AANDNL, yvex_r3, Pvex, [23]uint8{VEX_LZ_0F38_W0, 0xF2}},
{AANDNQ, yvex_r3, Pvex, [23]uint8{VEX_LZ_0F38_W1, 0xF2}},
@@ -1712,7 +1668,7 @@ var optab =
{AVPBROADCASTB, yvex_vpbroadcast, Pvex, [23]uint8{VEX_128_66_0F38_W0, 0x78, VEX_256_66_0F38_W0, 0x78}},
{AVPTEST, yvex_xy2, Pvex, [23]uint8{VEX_128_66_0F38_WIG, 0x17, VEX_256_66_0F38_WIG, 0x17}},
{AVPSHUFB, yvex_xy3, Pvex, [23]uint8{VEX_128_66_0F38_WIG, 0x00, VEX_256_66_0F38_WIG, 0x00}},
- {AVPSHUFD, yvex_xyi3, Pvex, [23]uint8{VEX_128_66_0F_WIG, 0x70, VEX_256_66_0F_WIG, 0x70}},
+ {AVPSHUFD, yvex_xyi3, Pvex, [23]uint8{VEX_128_66_0F_WIG, 0x70, VEX_256_66_0F_WIG, 0x70, VEX_128_66_0F_WIG, 0x70, VEX_256_66_0F_WIG, 0x70}},
{AVPOR, yvex_xy3, Pvex, [23]uint8{VEX_128_66_0F_WIG, 0xeb, VEX_256_66_0F_WIG, 0xeb}},
{AVPADDQ, yvex_xy3, Pvex, [23]uint8{VEX_128_66_0F_WIG, 0xd4, VEX_256_66_0F_WIG, 0xd4}},
{AVPADDD, yvex_xy3, Pvex, [23]uint8{VEX_128_66_0F_WIG, 0xfe, VEX_256_66_0F_WIG, 0xfe}},
@@ -1729,6 +1685,11 @@ var optab =
{AVPERM2I128, yvex_yyi4, Pvex, [23]uint8{VEX_256_66_0F3A_WIG, 0x46}},
{ARORXL, yvex_ri3, Pvex, [23]uint8{VEX_LZ_F2_0F3A_W0, 0xf0}},
{ARORXQ, yvex_ri3, Pvex, [23]uint8{VEX_LZ_F2_0F3A_W1, 0xf0}},
+ {AVBROADCASTSD, yvex_vpbroadcast_sd, Pvex, [23]uint8{VEX_256_66_0F38_W0, 0x19}},
+ {AVBROADCASTSS, yvex_vpbroadcast, Pvex, [23]uint8{VEX_128_66_0F38_W0, 0x18, VEX_256_66_0F38_W0, 0x18}},
+ {AVMOVDDUP, yvex_xy2, Pvex, [23]uint8{VEX_128_F2_0F_WIG, 0x12, VEX_256_F2_0F_WIG, 0x12}},
+ {AVMOVSHDUP, yvex_xy2, Pvex, [23]uint8{VEX_128_F3_0F_WIG, 0x16, VEX_256_F3_0F_WIG, 0x16}},
+ {AVMOVSLDUP, yvex_xy2, Pvex, [23]uint8{VEX_128_F3_0F_WIG, 0x12, VEX_256_F3_0F_WIG, 0x12}},
{AXACQUIRE, ynone, Px, [23]uint8{0xf2}},
{AXRELEASE, ynone, Px, [23]uint8{0xf3}},
@@ -1741,7 +1702,6 @@ var optab =
{obj.ATYPE, nil, 0, [23]uint8{}},
{obj.AFUNCDATA, yfuncdata, Px, [23]uint8{0, 0}},
{obj.APCDATA, ypcdata, Px, [23]uint8{0, 0}},
- {obj.ACHECKNIL, nil, 0, [23]uint8{}},
{obj.AVARDEF, nil, 0, [23]uint8{}},
{obj.AVARKILL, nil, 0, [23]uint8{}},
{obj.ADUFFCOPY, yduff, Px, [23]uint8{0xe8}},
@@ -2013,7 +1973,7 @@ func instinit() {
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, obj.Aconv(c))
+ log.Fatalf("phase error in optab: %d (%v)", i, c)
}
opindex[c&obj.AMask] = &optab[i]
}
@@ -2150,7 +2110,7 @@ func instinit() {
}
}
-var isAndroid = (obj.Getgoos() == "android")
+var isAndroid = (obj.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
@@ -2186,7 +2146,7 @@ func prefixof(ctxt *obj.Link, p *obj.Prog, a *obj.Addr) int {
if isAndroid {
return 0x65 // GS
}
- log.Fatalf("unknown TLS base register for %s", obj.Headstr(ctxt.Headtype))
+ log.Fatalf("unknown TLS base register for %v", ctxt.Headtype)
case obj.Hdarwin,
obj.Hdragonfly,
@@ -2199,7 +2159,7 @@ func prefixof(ctxt *obj.Link, p *obj.Prog, a *obj.Addr) int {
switch ctxt.Headtype {
default:
- log.Fatalf("unknown TLS base register for %s", obj.Headstr(ctxt.Headtype))
+ log.Fatalf("unknown TLS base register for %v", ctxt.Headtype)
case obj.Hlinux:
if isAndroid {
@@ -2769,7 +2729,7 @@ func vaddr(ctxt *obj.Link, p *obj.Prog, a *obj.Addr, r *obj.Reloc) int64 {
log.Fatalf("reloc")
}
- if !ctxt.Flag_shared || isAndroid {
+ if !ctxt.Flag_shared || isAndroid || ctxt.Headtype == obj.Hdarwin {
r.Type = obj.R_TLS_LE
r.Siz = 4
r.Off = -1 // caller must fill in
@@ -2835,7 +2795,9 @@ func asmandsz(ctxt *obj.Link, p *obj.Prog, a *obj.Addr, r int, rex int, m64 int)
goto bad
}
if p.Mode == 32 && ctxt.Flag_shared {
- base = REG_CX
+ // The base register has already been set. It holds the PC
+ // of this instruction returned by a PC-reading thunk.
+ // See obj6.go:rewriteToPcrel.
} else {
base = REG_NONE
}
@@ -2880,7 +2842,9 @@ func asmandsz(ctxt *obj.Link, p *obj.Prog, a *obj.Addr, r int, rex int, m64 int)
ctxt.Diag("bad addr: %v", p)
}
if p.Mode == 32 && ctxt.Flag_shared {
- base = REG_CX
+ // The base register has already been set. It holds the PC
+ // of this instruction returned by a PC-reading thunk.
+ // See obj6.go:rewriteToPcrel.
} else {
base = REG_NONE
}
@@ -3427,7 +3391,8 @@ func doasm(ctxt *obj.Link, p *obj.Prog) {
log.Fatalf("asmins bad table %v", p)
}
op = int(o.op[z])
- if op == 0x0f {
+ // In vex case 0x0f is actually VEX_256_F2_0F_WIG
+ if op == 0x0f && o.prefix != Pvex {
ctxt.AsmBuf.Put1(byte(op))
z++
op = int(o.op[z])
@@ -3739,7 +3704,11 @@ func doasm(ctxt *obj.Link, p *obj.Prog) {
ctxt.AsmBuf.Put2(byte(op), o.op[z+1])
r = obj.Addrel(ctxt.Cursym)
r.Off = int32(p.Pc + int64(ctxt.AsmBuf.Len()))
- r.Type = obj.R_ADDR
+ if p.Mode == 64 {
+ r.Type = obj.R_PCREL
+ } else {
+ r.Type = obj.R_ADDR
+ }
r.Siz = 4
r.Add = p.To.Offset
r.Sym = p.To.Sym
@@ -4010,31 +3979,32 @@ func doasm(ctxt *obj.Link, p *obj.Prog) {
// are handled in prefixof above and should not be listed here.
switch ctxt.Headtype {
default:
- log.Fatalf("unknown TLS base location for %s", obj.Headstr(ctxt.Headtype))
+ log.Fatalf("unknown TLS base location for %v", ctxt.Headtype)
case obj.Hlinux,
obj.Hnacl:
if ctxt.Flag_shared {
// Note that this is not generating the same insns as the other cases.
- // MOV TLS, R_to
+ // MOV TLS, dst
// becomes
- // call __x86.get_pc_thunk.cx
- // movl (gotpc + g at gotntpoff)(%ecx),$R_To
+ // call __x86.get_pc_thunk.dst
+ // movl (gotpc + g at gotntpoff)(dst), dst
// which is encoded as
- // call __x86.get_pc_thunk.cx
- // movq 0(%ecx), R_to
+ // call __x86.get_pc_thunk.dst
+ // movq 0(dst), dst
// and R_CALL & R_TLS_IE relocs. This all assumes the only tls variable we access
// is g, which we can't check here, but will when we assemble the second
// instruction.
+ 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
r.Siz = 4
- r.Sym = obj.Linklookup(ctxt, "__x86.get_pc_thunk.cx", 0)
+ r.Sym = obj.Linklookup(ctxt, "__x86.get_pc_thunk."+strings.ToLower(Rconv(int(dst))), 0)
ctxt.AsmBuf.PutInt32(0)
- ctxt.AsmBuf.Put2(0x8B, byte(2<<6|reg[REG_CX]|(reg[p.To.Reg]<<3)))
+ 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
@@ -4067,7 +4037,7 @@ func doasm(ctxt *obj.Link, p *obj.Prog) {
ctxt.AsmBuf.Put1(0x8B)
asmand(ctxt, p, &pp.From, &p.To)
- case obj.Hwindows:
+ case obj.Hwindows, obj.Hwindowsgui:
// Windows TLS base is always 0x14(FS).
pp.From = p.From
@@ -4085,7 +4055,7 @@ func doasm(ctxt *obj.Link, p *obj.Prog) {
switch ctxt.Headtype {
default:
- log.Fatalf("unknown TLS base location for %s", obj.Headstr(ctxt.Headtype))
+ log.Fatalf("unknown TLS base location for %v", ctxt.Headtype)
case obj.Hlinux:
if !ctxt.Flag_shared {
@@ -4139,7 +4109,7 @@ func doasm(ctxt *obj.Link, p *obj.Prog) {
0x8B)
asmand(ctxt, p, &pp.From, &p.To)
- case obj.Hwindows:
+ case obj.Hwindows, obj.Hwindowsgui:
// Windows TLS base is always 0x28(GS).
pp.From = p.From
diff --git a/src/cmd/internal/obj/x86/list6.go b/src/cmd/internal/obj/x86/list6.go
index fa9ddca..a1a49ed 100644
--- a/src/cmd/internal/obj/x86/list6.go
+++ b/src/cmd/internal/obj/x86/list6.go
@@ -1,5 +1,5 @@
// Inferno utils/6c/list.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6c/list.c
+// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6c/list.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth at terzarima.net)
diff --git a/src/cmd/internal/obj/x86/obj6.go b/src/cmd/internal/obj/x86/obj6.go
index 75638a0..102d8c3 100644
--- a/src/cmd/internal/obj/x86/obj6.go
+++ b/src/cmd/internal/obj/x86/obj6.go
@@ -1,5 +1,5 @@
// Inferno utils/6l/pass.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6l/pass.c
+// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/pass.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth at terzarima.net)
@@ -36,6 +36,7 @@ import (
"fmt"
"log"
"math"
+ "strings"
)
func CanUse1InsnTLS(ctxt *obj.Link) bool {
@@ -54,7 +55,8 @@ func CanUse1InsnTLS(ctxt *obj.Link) bool {
case obj.Hlinux,
obj.Hnacl,
obj.Hplan9,
- obj.Hwindows:
+ obj.Hwindows,
+ obj.Hwindowsgui:
return false
}
@@ -62,8 +64,7 @@ func CanUse1InsnTLS(ctxt *obj.Link) bool {
}
switch ctxt.Headtype {
- case obj.Hplan9,
- obj.Hwindows:
+ case obj.Hplan9, obj.Hwindows, obj.Hwindowsgui:
return false
case obj.Hlinux:
return !ctxt.Flag_shared
@@ -180,7 +181,7 @@ func progedit(ctxt *obj.Link, p *obj.Prog) {
}
// TODO: Remove.
- if ctxt.Headtype == obj.Hwindows && p.Mode == 64 || ctxt.Headtype == obj.Hplan9 {
+ if (ctxt.Headtype == obj.Hwindows || ctxt.Headtype == obj.Hwindowsgui) && p.Mode == 64 || ctxt.Headtype == obj.Hplan9 {
if p.From.Scale == 1 && p.From.Index == REG_TLS {
p.From.Scale = 2
}
@@ -265,7 +266,7 @@ func progedit(ctxt *obj.Link, p *obj.Prog) {
p.From.Type = obj.TYPE_MEM
p.From.Name = obj.NAME_EXTERN
p.From.Sym = s
- p.From.Sym.Local = true
+ p.From.Sym.Set(obj.AttrLocal, true)
p.From.Offset = 0
}
@@ -305,7 +306,7 @@ func progedit(ctxt *obj.Link, p *obj.Prog) {
p.From.Type = obj.TYPE_MEM
p.From.Name = obj.NAME_EXTERN
p.From.Sym = s
- p.From.Sym.Local = true
+ p.From.Sym.Set(obj.AttrLocal, true)
p.From.Offset = 0
}
}
@@ -333,6 +334,13 @@ func rewriteToUseGot(ctxt *obj.Link, p *obj.Prog) {
lea = ALEAL
mov = AMOVL
reg = REG_CX
+ if p.As == ALEAL && p.To.Reg != p.From.Reg && p.To.Reg != p.From.Index {
+ // Special case: clobber the destination register with
+ // the PC so we don't have to clobber CX.
+ // The SSA backend depends on CX not being clobbered across LEAL.
+ // See cmd/compile/internal/ssa/gen/386.rules (search for Flag_shared).
+ reg = p.To.Reg
+ }
}
if p.As == obj.ADUFFCOPY || p.As == obj.ADUFFZERO {
@@ -371,12 +379,12 @@ func rewriteToUseGot(ctxt *obj.Link, p *obj.Prog) {
// We only care about global data: NAME_EXTERN means a global
// symbol in the Go sense, and p.Sym.Local is true for a few
// internally defined symbols.
- if p.As == lea && p.From.Type == obj.TYPE_MEM && p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local {
+ if p.As == lea && p.From.Type == obj.TYPE_MEM && p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local() {
// $LEA sym, Rx becomes $MOV $sym, Rx which will be rewritten below
p.As = mov
p.From.Type = obj.TYPE_ADDR
}
- if p.From.Type == obj.TYPE_ADDR && p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local {
+ if p.From.Type == obj.TYPE_ADDR && p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local() {
// $MOV $sym, Rx becomes $MOV sym at GOT, Rx
// $MOV $sym+<off>, Rx becomes $MOV sym at GOT, Rx; $LEA <off>(Rx), Rx
// On 386 only, more complicated things like PUSHL $sym become $MOV sym at GOT, CX; PUSHL CX
@@ -391,7 +399,7 @@ func rewriteToUseGot(ctxt *obj.Link, p *obj.Prog) {
dest = p.To
p.As = mov
p.To.Type = obj.TYPE_REG
- p.To.Reg = REG_CX
+ p.To.Reg = reg
p.To.Sym = nil
p.To.Name = obj.NAME_NONE
}
@@ -412,7 +420,7 @@ func rewriteToUseGot(ctxt *obj.Link, p *obj.Prog) {
q.As = pAs
q.To = dest
q.From.Type = obj.TYPE_REG
- q.From.Reg = REG_CX
+ q.From.Reg = reg
}
}
if p.From3 != nil && p.From3.Name == obj.NAME_EXTERN {
@@ -422,12 +430,12 @@ func rewriteToUseGot(ctxt *obj.Link, p *obj.Prog) {
// MOVx sym, Ry becomes $MOV sym at GOT, R15; MOVx (R15), Ry
// MOVx Ry, sym becomes $MOV sym at GOT, R15; MOVx Ry, (R15)
// 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 {
+ if p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local() {
+ if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local() {
ctxt.Diag("cannot handle NAME_EXTERN on both sides in %v with -dynlink", p)
}
source = &p.From
- } else if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local {
+ } else if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local() {
source = &p.To
} else {
return
@@ -437,7 +445,7 @@ 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 p.Mode == 64 || (p.To.Sym != nil && p.To.Sym.Local()) || p.RegTo2 != 0 {
return
}
p1 := obj.Appendp(ctxt, p)
@@ -509,7 +517,7 @@ func rewriteToPcrel(ctxt *obj.Link, p *obj.Prog) {
return
}
// Any Prog (aside from the above special cases) with an Addr with Name ==
- // NAME_EXTERN, NAME_STATIC or NAME_GOTREF has a CALL __x86.get_pc_thunk.cx
+ // NAME_EXTERN, NAME_STATIC or NAME_GOTREF has a CALL __x86.get_pc_thunk.XX
// inserted before it.
isName := func(a *obj.Addr) bool {
if a.Sym == nil || (a.Type != obj.TYPE_MEM && a.Type != obj.TYPE_ADDR) || a.Reg != 0 {
@@ -542,21 +550,36 @@ func rewriteToPcrel(ctxt *obj.Link, p *obj.Prog) {
if !isName(&p.From) && !isName(&p.To) && (p.From3 == nil || !isName(p.From3)) {
return
}
+ var dst int16 = REG_CX
+ if (p.As == ALEAL || p.As == AMOVL) && p.To.Reg != p.From.Reg && p.To.Reg != p.From.Index {
+ dst = p.To.Reg
+ // Why? See the comment near the top of rewriteToUseGot above.
+ // AMOVLs might be introduced by the GOT rewrites.
+ }
q := obj.Appendp(ctxt, p)
q.RegTo2 = 1
r := obj.Appendp(ctxt, q)
r.RegTo2 = 1
q.As = obj.ACALL
- q.To.Sym = obj.Linklookup(ctxt, "__x86.get_pc_thunk.cx", 0)
+ q.To.Sym = obj.Linklookup(ctxt, "__x86.get_pc_thunk."+strings.ToLower(Rconv(int(dst))), 0)
q.To.Type = obj.TYPE_MEM
q.To.Name = obj.NAME_EXTERN
- q.To.Sym.Local = true
+ q.To.Sym.Set(obj.AttrLocal, true)
r.As = p.As
r.Scond = p.Scond
r.From = p.From
r.From3 = p.From3
r.Reg = p.Reg
r.To = p.To
+ if isName(&p.From) {
+ r.From.Reg = dst
+ }
+ if isName(&p.To) {
+ r.To.Reg = dst
+ }
+ if p.From3 != nil && isName(p.From3) {
+ r.From3.Reg = dst
+ }
obj.Nopout(p)
}
@@ -632,17 +655,29 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
// TODO(rsc): Remove 'p.Mode == 64 &&'.
if p.Mode == 64 && autoffset < obj.StackSmall && p.From3Offset()&obj.NOSPLIT == 0 {
+ leaf := true
+ LeafSearch:
for q := p; q != nil; q = q.Link {
- if q.As == obj.ACALL {
- goto noleaf
- }
- if (q.As == obj.ADUFFCOPY || q.As == obj.ADUFFZERO) && autoffset >= obj.StackSmall-8 {
- goto noleaf
+ switch q.As {
+ case obj.ACALL:
+ // Treat common runtime calls that take no arguments
+ // the same as duffcopy and duffzero.
+ if !isZeroArgRuntimeCall(q.To.Sym) {
+ leaf = false
+ break LeafSearch
+ }
+ fallthrough
+ case obj.ADUFFCOPY, obj.ADUFFZERO:
+ if autoffset >= obj.StackSmall-8 {
+ leaf = false
+ break LeafSearch
+ }
}
}
- p.From3.Offset |= obj.NOSPLIT
- noleaf:
+ if leaf {
+ p.From3.Offset |= obj.NOSPLIT
+ }
}
if p.From3Offset()&obj.NOSPLIT == 0 || p.From3Offset()&obj.WRAPPER != 0 {
@@ -663,17 +698,6 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
p.From.Type = obj.TYPE_CONST
p.From.Offset = int64(autoffset)
p.Spadj = autoffset
- } else {
- // zero-byte stack adjustment.
- // Insert a fake non-zero adjustment so that stkcheck can
- // recognize the end of the stack-splitting prolog.
- p = obj.Appendp(ctxt, p)
-
- p.As = obj.ANOP
- p.Spadj = int32(-ctxt.Arch.PtrSize)
- p = obj.Appendp(ctxt, p)
- p.As = obj.ANOP
- p.Spadj = int32(ctxt.Arch.PtrSize)
}
deltasp := autoffset
@@ -810,31 +834,26 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
p2.Pcond = p
}
- var a int
- var pcsize int
for ; p != nil; p = p.Link {
- pcsize = int(p.Mode) / 8
- a = int(p.From.Name)
- if a == obj.NAME_AUTO {
+ pcsize := int(p.Mode) / 8
+ switch p.From.Name {
+ case obj.NAME_AUTO:
p.From.Offset += int64(deltasp) - int64(bpsize)
- }
- if a == obj.NAME_PARAM {
+ case obj.NAME_PARAM:
p.From.Offset += int64(deltasp) + int64(pcsize)
}
if p.From3 != nil {
- a = int(p.From3.Name)
- if a == obj.NAME_AUTO {
+ switch p.From3.Name {
+ case obj.NAME_AUTO:
p.From3.Offset += int64(deltasp) - int64(bpsize)
- }
- if a == obj.NAME_PARAM {
+ case obj.NAME_PARAM:
p.From3.Offset += int64(deltasp) + int64(pcsize)
}
}
- a = int(p.To.Name)
- if a == obj.NAME_AUTO {
+ switch p.To.Name {
+ case obj.NAME_AUTO:
p.To.Offset += int64(deltasp) - int64(bpsize)
- }
- if a == obj.NAME_PARAM {
+ case obj.NAME_PARAM:
p.To.Offset += int64(deltasp) + int64(pcsize)
}
@@ -873,7 +892,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
continue
case obj.ARET:
- break
+ // do nothing
}
if autoffset != deltasp {
@@ -914,6 +933,17 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
}
}
+func isZeroArgRuntimeCall(s *obj.LSym) bool {
+ if s == nil {
+ return false
+ }
+ switch s.Name {
+ case "runtime.panicindex", "runtime.panicslice", "runtime.panicdivide":
+ return true
+ }
+ return false
+}
+
func indir_cx(ctxt *obj.Link, p *obj.Prog, a *obj.Addr) {
if ctxt.Headtype == obj.Hnacl && p.Mode == 64 {
a.Type = obj.TYPE_MEM
@@ -984,7 +1014,7 @@ func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32, textarg int32) *ob
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 ctxt.Cursym.CFunc() {
p.To.Offset = 3 * int64(ctxt.Arch.PtrSize) // G.stackguard1
}
} else if framesize <= obj.StackBig {
@@ -1006,7 +1036,7 @@ func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32, textarg int32) *ob
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 ctxt.Cursym.CFunc() {
p.To.Offset = 3 * int64(ctxt.Arch.PtrSize) // G.stackguard1
}
} else {
@@ -1030,7 +1060,7 @@ func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32, textarg int32) *ob
p.As = mov
indir_cx(ctxt, p, &p.From)
p.From.Offset = 2 * int64(ctxt.Arch.PtrSize) // G.stackguard0
- if ctxt.Cursym.Cfunc {
+ if ctxt.Cursym.CFunc() {
p.From.Offset = 3 * int64(ctxt.Arch.PtrSize) // G.stackguard1
}
p.To.Type = obj.TYPE_REG
@@ -1083,11 +1113,23 @@ func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32, textarg int32) *ob
for last = ctxt.Cursym.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.As = obj.ANOP
spfix.Spadj = -framesize
- call := obj.Appendp(ctxt, spfix)
+ pcdata := obj.Appendp(ctxt, spfix)
+ pcdata.Lineno = ctxt.Cursym.Text.Lineno
+ pcdata.Mode = ctxt.Cursym.Text.Mode
+ pcdata.As = obj.APCDATA
+ pcdata.From.Type = obj.TYPE_CONST
+ pcdata.From.Offset = obj.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.As = obj.ACALL
@@ -1095,7 +1137,7 @@ func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32, textarg int32) *ob
call.To.Name = obj.NAME_EXTERN
morestack := "runtime.morestack"
switch {
- case ctxt.Cursym.Cfunc:
+ case ctxt.Cursym.CFunc():
morestack = "runtime.morestackc"
case ctxt.Cursym.Text.From3Offset()&obj.NEEDCTXT == 0:
morestack = "runtime.morestack_noctxt"
@@ -1208,7 +1250,7 @@ func relinv(a obj.As) obj.As {
return AJOS
}
- log.Fatalf("unknown relation: %s", obj.Aconv(a))
+ log.Fatalf("unknown relation: %s", a)
return 0
}
diff --git a/src/cmd/internal/obj/x86/obj6_test.go b/src/cmd/internal/obj/x86/obj6_test.go
index fe1f95c..e311c62 100644
--- a/src/cmd/internal/obj/x86/obj6_test.go
+++ b/src/cmd/internal/obj/x86/obj6_test.go
@@ -4,7 +4,6 @@ import (
"bufio"
"bytes"
"fmt"
- "go/build"
"internal/testenv"
"io/ioutil"
"os"
@@ -96,13 +95,8 @@ func asmOutput(t *testing.T, s string) []byte {
if err != nil {
t.Fatal(err)
}
- gofolder := filepath.Join(build.Default.GOROOT, "bin")
- if gobin := os.Getenv("GOBIN"); len(gobin) != 0 {
- gofolder = gobin
- }
-
cmd := exec.Command(
- filepath.Join(gofolder, "go"), "tool", "asm", "-S", "-dynlink",
+ testenv.GoToolPath(t), "tool", "asm", "-S", "-dynlink",
"-o", filepath.Join(tmpdir, "output.6"), tmpfile.Name())
var env []string
diff --git a/src/cmd/internal/objfile/disasm.go b/src/cmd/internal/objfile/disasm.go
index 25c3301..8af0c8f 100644
--- a/src/cmd/internal/objfile/disasm.go
+++ b/src/cmd/internal/objfile/disasm.go
@@ -16,13 +16,14 @@ import (
"text/tabwriter"
"golang.org/x/arch/arm/armasm"
+ "golang.org/x/arch/ppc64/ppc64asm"
"golang.org/x/arch/x86/x86asm"
)
// Disasm is a disassembler for a given File.
type Disasm struct {
syms []Sym //symbols in file, sorted by address
- pcln *gosym.Table // pcln table
+ pcln Liner // pcln table
text []byte // bytes of text segment (actual instructions)
textStart uint64 // start PC of text
textEnd uint64 // end PC of text
@@ -116,6 +117,7 @@ func (d *Disasm) Print(w io.Writer, filter *regexp.Regexp, start, end uint64) {
for _, sym := range d.syms {
symStart := sym.Addr
symEnd := sym.Addr + uint64(sym.Size)
+ relocs := sym.Relocs
if sym.Code != 'T' && sym.Code != 't' ||
symStart < d.textStart ||
symEnd <= start || end <= symStart ||
@@ -135,7 +137,7 @@ func (d *Disasm) Print(w io.Writer, filter *regexp.Regexp, start, end uint64) {
symEnd = end
}
code := d.text[:end-d.textStart]
- d.Decode(symStart, symEnd, func(pc, size uint64, file string, line int, text string) {
+ 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 size%4 != 0 || d.goarch == "386" || d.goarch == "amd64" {
@@ -158,7 +160,7 @@ func (d *Disasm) Print(w io.Writer, filter *regexp.Regexp, start, end uint64) {
}
// Decode disassembles the text segment range [start, end), calling f for each instruction.
-func (d *Disasm) Decode(start, end uint64, f func(pc, size uint64, file string, line int, text string)) {
+func (d *Disasm) Decode(start, end uint64, relocs []Reloc, f func(pc, size uint64, file string, line int, text string)) {
if start < d.textStart {
start = d.textStart
}
@@ -169,21 +171,32 @@ func (d *Disasm) Decode(start, end uint64, f func(pc, size uint64, file string,
lookup := d.lookup
for pc := start; pc < end; {
i := pc - d.textStart
- text, size := d.disasm(code[i:], pc, lookup)
+ text, size := d.disasm(code[i:], pc, lookup, d.byteOrder)
file, line, _ := d.pcln.PCToLine(pc)
+ text += "\t"
+ first := true
+ for len(relocs) > 0 && relocs[0].Addr < i+uint64(size) {
+ if first {
+ first = false
+ } else {
+ text += " "
+ }
+ text += relocs[0].Stringer.String(pc - start)
+ relocs = relocs[1:]
+ }
f(pc, uint64(size), file, line, text)
pc += uint64(size)
}
}
type lookupFunc func(addr uint64) (sym string, base uint64)
-type disasmFunc func(code []byte, pc uint64, lookup lookupFunc) (text string, size int)
+type disasmFunc func(code []byte, pc uint64, lookup lookupFunc, ord binary.ByteOrder) (text string, size int)
-func disasm_386(code []byte, pc uint64, lookup lookupFunc) (string, int) {
+func disasm_386(code []byte, pc uint64, lookup lookupFunc, _ binary.ByteOrder) (string, int) {
return disasm_x86(code, pc, lookup, 32)
}
-func disasm_amd64(code []byte, pc uint64, lookup lookupFunc) (string, int) {
+func disasm_amd64(code []byte, pc uint64, lookup lookupFunc, _ binary.ByteOrder) (string, int) {
return disasm_x86(code, pc, lookup, 64)
}
@@ -220,7 +233,7 @@ func (r textReader) ReadAt(data []byte, off int64) (n int, err error) {
return
}
-func disasm_arm(code []byte, pc uint64, lookup lookupFunc) (string, int) {
+func disasm_arm(code []byte, pc uint64, lookup lookupFunc, _ binary.ByteOrder) (string, int) {
inst, err := armasm.Decode(code, armasm.ModeARM)
var text string
size := inst.Len
@@ -233,10 +246,25 @@ func disasm_arm(code []byte, pc uint64, lookup lookupFunc) (string, int) {
return text, size
}
+func disasm_ppc64(code []byte, pc uint64, lookup lookupFunc, byteOrder binary.ByteOrder) (string, int) {
+ inst, err := ppc64asm.Decode(code, byteOrder)
+ var text string
+ size := inst.Len
+ if err != nil || size == 0 || inst.Op == 0 {
+ size = 4
+ text = "?"
+ } else {
+ text = ppc64asm.GoSyntax(inst, pc, lookup)
+ }
+ return text, size
+}
+
var disasms = map[string]disasmFunc{
- "386": disasm_386,
- "amd64": disasm_amd64,
- "arm": disasm_arm,
+ "386": disasm_386,
+ "amd64": disasm_amd64,
+ "arm": disasm_arm,
+ "ppc64": disasm_ppc64,
+ "ppc64le": disasm_ppc64,
}
var byteOrders = map[string]binary.ByteOrder{
@@ -247,3 +275,9 @@ var byteOrders = map[string]binary.ByteOrder{
"ppc64le": binary.LittleEndian,
"s390x": binary.BigEndian,
}
+
+type Liner interface {
+ // Given a pc, returns the corresponding file, line, and function data.
+ // If unknown, returns "",0,nil.
+ PCToLine(uint64) (string, int, *gosym.Func)
+}
diff --git a/src/cmd/internal/objfile/elf.go b/src/cmd/internal/objfile/elf.go
index c811460..4ab7e6d 100644
--- a/src/cmd/internal/objfile/elf.go
+++ b/src/cmd/internal/objfile/elf.go
@@ -9,6 +9,7 @@ package objfile
import (
"debug/dwarf"
"debug/elf"
+ "encoding/binary"
"fmt"
"os"
)
@@ -99,6 +100,9 @@ func (f *elfFile) goarch() string {
case elf.EM_ARM:
return "arm"
case elf.EM_PPC64:
+ if f.elf.ByteOrder == binary.LittleEndian {
+ return "ppc64le"
+ }
return "ppc64"
case elf.EM_S390:
return "s390x"
diff --git a/src/cmd/internal/objfile/goobj.go b/src/cmd/internal/objfile/goobj.go
index 43435ef..230137e 100644
--- a/src/cmd/internal/objfile/goobj.go
+++ b/src/cmd/internal/objfile/goobj.go
@@ -8,7 +8,9 @@ package objfile
import (
"cmd/internal/goobj"
+ "cmd/internal/sys"
"debug/dwarf"
+ "debug/gosym"
"errors"
"fmt"
"os"
@@ -16,6 +18,7 @@ import (
type goobjFile struct {
goobj *goobj.Package
+ f *os.File // the underlying .o or .a file
}
func openGoobj(r *os.File) (rawFile, error) {
@@ -23,7 +26,7 @@ func openGoobj(r *os.File) (rawFile, error) {
if err != nil {
return nil, err
}
- return &goobjFile{f}, nil
+ return &goobjFile{goobj: f, f: r}, nil
}
func goobjName(id goobj.SymID) string {
@@ -55,6 +58,9 @@ func (f *goobjFile) symbols() ([]Sym, error) {
if s.Version != 0 {
sym.Code += 'a' - 'A'
}
+ for i, r := range s.Reloc {
+ sym.Relocs = append(sym.Relocs, Reloc{Addr: uint64(s.Data.Offset) + uint64(r.Offset), Size: uint64(r.Size), Stringer: &s.Reloc[i]})
+ }
syms = append(syms, sym)
}
@@ -75,23 +81,68 @@ func (f *goobjFile) symbols() ([]Sym, error) {
return syms, nil
}
-// pcln does not make sense for Go object files, because each
-// symbol has its own individual pcln table, so there is no global
-// space of addresses to map.
func (f *goobjFile) pcln() (textStart uint64, symtab, pclntab []byte, err error) {
+ // Should never be called. We implement Liner below, callers
+ // should use that instead.
return 0, nil, nil, fmt.Errorf("pcln not available in go object file")
}
-// text does not make sense for Go object files, because
-// each function has a separate section.
+// Find returns the file name, line, and function data for the given pc.
+// Returns "",0,nil if unknown.
+// This function implements the Liner interface in preference to pcln() above.
+func (f *goobjFile) PCToLine(pc uint64) (string, int, *gosym.Func) {
+ // TODO: this is really inefficient. Binary search? Memoize last result?
+ var arch *sys.Arch
+ for _, a := range sys.Archs {
+ if a.Name == f.goobj.Arch {
+ arch = a
+ break
+ }
+ }
+ if arch == nil {
+ return "", 0, nil
+ }
+ for _, s := range f.goobj.Syms {
+ if pc < uint64(s.Data.Offset) || pc >= uint64(s.Data.Offset+s.Data.Size) {
+ continue
+ }
+ if s.Func == nil {
+ return "", 0, nil
+ }
+ pcfile := make([]byte, s.Func.PCFile.Size)
+ _, err := f.f.ReadAt(pcfile, s.Func.PCFile.Offset)
+ if err != nil {
+ return "", 0, nil
+ }
+ fileID := gosym.PCValue(pcfile, pc-uint64(s.Data.Offset), arch.MinLC)
+ fileName := s.Func.File[fileID]
+ pcline := make([]byte, s.Func.PCLine.Size)
+ _, err = f.f.ReadAt(pcline, s.Func.PCLine.Offset)
+ if err != nil {
+ return "", 0, nil
+ }
+ line := gosym.PCValue(pcline, pc-uint64(s.Data.Offset), arch.MinLC)
+ // Note: we provide only the name in the Func structure.
+ // We could provide more if needed.
+ return fileName, line, &gosym.Func{Sym: &gosym.Sym{Name: s.Name}}
+ }
+ return "", 0, nil
+}
+
+// We treat the whole object file as the text section.
func (f *goobjFile) text() (textStart uint64, text []byte, err error) {
- return 0, nil, fmt.Errorf("text not available in go object file")
+ var info os.FileInfo
+ info, err = f.f.Stat()
+ if err != nil {
+ return
+ }
+ text = make([]byte, info.Size())
+ _, err = f.f.ReadAt(text, 0)
+ return
}
-// goarch makes sense but is not exposed in debug/goobj's API,
-// and we don't need it yet for any users of internal/objfile.
func (f *goobjFile) goarch() string {
- return "GOARCH unimplemented for debug/goobj files"
+ return f.goobj.Arch
}
func (f *goobjFile) loadAddress() (uint64, error) {
diff --git a/src/cmd/internal/objfile/objfile.go b/src/cmd/internal/objfile/objfile.go
index e5d99f0..2bf6363 100644
--- a/src/cmd/internal/objfile/objfile.go
+++ b/src/cmd/internal/objfile/objfile.go
@@ -30,11 +30,24 @@ type File struct {
// A Sym is a symbol defined in an executable file.
type Sym struct {
- Name string // symbol name
- Addr uint64 // virtual address of symbol
- Size int64 // size in bytes
- Code rune // nm code (T for text, D for data, and so on)
- Type string // XXX?
+ Name string // symbol name
+ Addr uint64 // virtual address of symbol
+ Size int64 // size in bytes
+ Code rune // nm code (T for text, D for data, and so on)
+ Type string // XXX?
+ Relocs []Reloc // in increasing Addr order
+}
+
+type Reloc struct {
+ Addr uint64 // Address of first byte that reloc applies to.
+ Size uint64 // Number of bytes
+ Stringer RelocStringer
+}
+
+type RelocStringer interface {
+ // insnOffset is the offset of the instruction containing the relocation
+ // from the start of the symbol containing the relocation.
+ String(insnOffset uint64) string
}
var openers = []func(*os.File) (rawFile, error){
@@ -80,7 +93,13 @@ func (x byAddr) Less(i, j int) bool { return x[i].Addr < x[j].Addr }
func (x byAddr) Len() int { return len(x) }
func (x byAddr) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
-func (f *File) PCLineTable() (*gosym.Table, error) {
+func (f *File) PCLineTable() (Liner, error) {
+ // If the raw file implements Liner directly, use that.
+ // Currently, only Go intermediate objects and archives (goobj) use this path.
+ if pcln, ok := f.raw.(Liner); ok {
+ return pcln, nil
+ }
+ // Otherwise, read the pcln tables and build a Liner out of that.
textStart, symtab, pclntab, err := f.raw.pcln()
if err != nil {
return nil, err
diff --git a/src/cmd/internal/pprof/commands/commands.go b/src/cmd/internal/pprof/commands/commands.go
deleted file mode 100644
index 5dfbbd4..0000000
--- a/src/cmd/internal/pprof/commands/commands.go
+++ /dev/null
@@ -1,244 +0,0 @@
-// Copyright 2014 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// Package commands defines and manages the basic pprof commands
-package commands
-
-import (
- "bytes"
- "fmt"
- "io"
- "io/ioutil"
- "os"
- "os/exec"
- "runtime"
- "strings"
- "time"
-
- "cmd/internal/pprof/plugin"
- "cmd/internal/pprof/report"
- "cmd/internal/pprof/svg"
- "cmd/internal/pprof/tempfile"
-)
-
-// Commands describes the commands accepted by pprof.
-type Commands map[string]*Command
-
-// Command describes the actions for a pprof command. Includes a
-// function for command-line completion, the report format to use
-// during report generation, any postprocessing functions, and whether
-// the command expects a regexp parameter (typically a function name).
-type Command struct {
- Complete Completer // autocomplete for interactive mode
- Format int // report format to generate
- PostProcess PostProcessor // postprocessing to run on report
- HasParam bool // Collect a parameter from the CLI
- Usage string // Help text
-}
-
-// Completer is a function for command-line autocompletion
-type Completer func(prefix string) string
-
-// PostProcessor is a function that applies post-processing to the report output
-type PostProcessor func(input *bytes.Buffer, output io.Writer, ui plugin.UI) error
-
-// PProf returns the basic pprof report-generation commands
-func PProf(c Completer, interactive **bool) Commands {
- return Commands{
- // Commands that require no post-processing.
- "tags": {nil, report.Tags, nil, false, "Outputs all tags in the profile"},
- "raw": {c, report.Raw, nil, false, "Outputs a text representation of the raw profile"},
- "dot": {c, report.Dot, nil, false, "Outputs a graph in DOT format"},
- "top": {c, report.Text, nil, false, "Outputs top entries in text form"},
- "tree": {c, report.Tree, nil, false, "Outputs a text rendering of call graph"},
- "text": {c, report.Text, nil, false, "Outputs top entries in text form"},
- "disasm": {c, report.Dis, nil, true, "Output annotated assembly for functions matching regexp or address"},
- "list": {c, report.List, nil, true, "Output annotated source for functions matching regexp"},
- "peek": {c, report.Tree, nil, true, "Output callers/callees of functions matching regexp"},
-
- // Save binary formats to a file
- "callgrind": {c, report.Callgrind, awayFromTTY("callgraph.out"), false, "Outputs a graph in callgrind format"},
- "proto": {c, report.Proto, awayFromTTY("pb.gz"), false, "Outputs the profile in compressed protobuf format"},
-
- // Generate report in DOT format and postprocess with dot
- "gif": {c, report.Dot, invokeDot("gif"), false, "Outputs a graph image in GIF format"},
- "pdf": {c, report.Dot, invokeDot("pdf"), false, "Outputs a graph in PDF format"},
- "png": {c, report.Dot, invokeDot("png"), false, "Outputs a graph image in PNG format"},
- "ps": {c, report.Dot, invokeDot("ps"), false, "Outputs a graph in PS format"},
-
- // Save SVG output into a file after including svgpan library
- "svg": {c, report.Dot, saveSVGToFile(), false, "Outputs a graph in SVG format"},
-
- // Visualize postprocessed dot output
- "eog": {c, report.Dot, invokeVisualizer(interactive, invokeDot("svg"), "svg", []string{"eog"}), false, "Visualize graph through eog"},
- "evince": {c, report.Dot, invokeVisualizer(interactive, invokeDot("pdf"), "pdf", []string{"evince"}), false, "Visualize graph through evince"},
- "gv": {c, report.Dot, invokeVisualizer(interactive, invokeDot("ps"), "ps", []string{"gv --noantialias"}), false, "Visualize graph through gv"},
- "web": {c, report.Dot, invokeVisualizer(interactive, saveSVGToFile(), "svg", browsers()), false, "Visualize graph through web browser"},
-
- // Visualize HTML directly generated by report.
- "weblist": {c, report.WebList, invokeVisualizer(interactive, awayFromTTY("html"), "html", browsers()), true, "Output annotated source in HTML for functions matching regexp or address"},
- }
-}
-
-// browsers returns a list of commands to attempt for web visualization
-// on the current platform
-func browsers() []string {
- var cmds []string
- if exe := os.Getenv("BROWSER"); exe != "" {
- cmds = append(cmds, exe)
- }
- switch runtime.GOOS {
- case "darwin":
- cmds = append(cmds, "/usr/bin/open")
- case "windows":
- cmds = append(cmds, "cmd /c start")
- default:
- cmds = append(cmds, "xdg-open")
- }
- cmds = append(cmds, "chrome", "google-chrome", "firefox")
- return cmds
-}
-
-// NewCompleter creates an autocompletion function for a set of commands.
-func NewCompleter(cs Commands) Completer {
- return func(line string) string {
- switch tokens := strings.Fields(line); len(tokens) {
- case 0:
- // Nothing to complete
- case 1:
- // Single token -- complete command name
- found := ""
- for c := range cs {
- if strings.HasPrefix(c, tokens[0]) {
- if found != "" {
- return line
- }
- found = c
- }
- }
- if found != "" {
- return found
- }
- default:
- // Multiple tokens -- complete using command completer
- if c, ok := cs[tokens[0]]; ok {
- if c.Complete != nil {
- lastTokenIdx := len(tokens) - 1
- lastToken := tokens[lastTokenIdx]
- if strings.HasPrefix(lastToken, "-") {
- lastToken = "-" + c.Complete(lastToken[1:])
- } else {
- lastToken = c.Complete(lastToken)
- }
- return strings.Join(append(tokens[:lastTokenIdx], lastToken), " ")
- }
- }
- }
- return line
- }
-}
-
-// awayFromTTY saves the output in a file if it would otherwise go to
-// the terminal screen. This is used to avoid dumping binary data on
-// the screen.
-func awayFromTTY(format string) PostProcessor {
- return func(input *bytes.Buffer, output io.Writer, ui plugin.UI) error {
- if output == os.Stdout && ui.IsTerminal() {
- tempFile, err := tempfile.New("", "profile", "."+format)
- if err != nil {
- return err
- }
- ui.PrintErr("Generating report in ", tempFile.Name())
- _, err = fmt.Fprint(tempFile, input)
- return err
- }
- _, err := fmt.Fprint(output, input)
- return err
- }
-}
-
-func invokeDot(format string) PostProcessor {
- divert := awayFromTTY(format)
- return func(input *bytes.Buffer, output io.Writer, ui plugin.UI) error {
- if _, err := exec.LookPath("dot"); err != nil {
- ui.PrintErr("Cannot find dot, have you installed Graphviz?")
- return err
- }
- cmd := exec.Command("dot", "-T"+format)
- var buf bytes.Buffer
- cmd.Stdin, cmd.Stdout, cmd.Stderr = input, &buf, os.Stderr
- if err := cmd.Run(); err != nil {
- return err
- }
- return divert(&buf, output, ui)
- }
-}
-
-func saveSVGToFile() PostProcessor {
- generateSVG := invokeDot("svg")
- divert := awayFromTTY("svg")
- return func(input *bytes.Buffer, output io.Writer, ui plugin.UI) error {
- baseSVG := &bytes.Buffer{}
- generateSVG(input, baseSVG, ui)
- massaged := &bytes.Buffer{}
- fmt.Fprint(massaged, svg.Massage(*baseSVG))
- return divert(massaged, output, ui)
- }
-}
-
-var vizTmpDir string
-
-func makeVizTmpDir() error {
- if vizTmpDir != "" {
- return nil
- }
- name, err := ioutil.TempDir("", "pprof-")
- if err != nil {
- return err
- }
- tempfile.DeferDelete(name)
- vizTmpDir = name
- return nil
-}
-
-func invokeVisualizer(interactive **bool, format PostProcessor, suffix string, visualizers []string) PostProcessor {
- return func(input *bytes.Buffer, output io.Writer, ui plugin.UI) error {
- if err := makeVizTmpDir(); err != nil {
- return err
- }
- tempFile, err := tempfile.New(vizTmpDir, "pprof", "."+suffix)
- if err != nil {
- return err
- }
- tempfile.DeferDelete(tempFile.Name())
- if err = format(input, tempFile, ui); err != nil {
- return err
- }
- tempFile.Close() // on windows, if the file is Open, start cannot access it.
- // Try visualizers until one is successful
- for _, v := range visualizers {
- // Separate command and arguments for exec.Command.
- args := strings.Split(v, " ")
- if len(args) == 0 {
- continue
- }
- viewer := exec.Command(args[0], append(args[1:], tempFile.Name())...)
- viewer.Stderr = os.Stderr
- if err = viewer.Start(); err == nil {
- // The viewer might just send a message to another program
- // to open the file. Give that program a little time to open the
- // file before we remove it.
- time.Sleep(1 * time.Second)
-
- if !**interactive {
- // In command-line mode, wait for the viewer to be closed
- // before proceeding
- return viewer.Wait()
- }
- return nil
- }
- }
- return err
- }
-}
diff --git a/src/cmd/internal/pprof/driver/driver.go b/src/cmd/internal/pprof/driver/driver.go
deleted file mode 100644
index 782acfd..0000000
--- a/src/cmd/internal/pprof/driver/driver.go
+++ /dev/null
@@ -1,1041 +0,0 @@
-// Copyright 2014 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// Package driver implements the core pprof functionality. It can be
-// parameterized with a flag implementation, fetch and symbolize
-// mechanisms.
-package driver
-
-import (
- "bytes"
- "fmt"
- "io"
- "net/url"
- "os"
- "path/filepath"
- "regexp"
- "sort"
- "strconv"
- "strings"
- "sync"
- "time"
-
- "cmd/internal/pprof/commands"
- "cmd/internal/pprof/plugin"
- "cmd/internal/pprof/profile"
- "cmd/internal/pprof/report"
- "cmd/internal/pprof/tempfile"
-)
-
-// PProf acquires a profile, and symbolizes it using a profile
-// manager. Then it generates a report formatted according to the
-// options selected through the flags package.
-func PProf(flagset plugin.FlagSet, fetch plugin.Fetcher, sym plugin.Symbolizer, obj plugin.ObjTool, ui plugin.UI, overrides commands.Commands) error {
- // Remove any temporary files created during pprof processing.
- defer tempfile.Cleanup()
-
- f, err := getFlags(flagset, overrides, ui)
- if err != nil {
- return err
- }
-
- obj.SetConfig(*f.flagTools)
-
- sources := f.profileSource
- if len(sources) > 1 {
- source := sources[0]
- // If the first argument is a supported object file, treat as executable.
- if file, err := obj.Open(source, 0); err == nil {
- file.Close()
- f.profileExecName = source
- sources = sources[1:]
- } else if *f.flagBuildID == "" && isBuildID(source) {
- f.flagBuildID = &source
- sources = sources[1:]
- }
- }
-
- // errMu protects concurrent accesses to errset and err. errset is set if an
- // error is encountered by one of the goroutines grabbing a profile.
- errMu, errset := sync.Mutex{}, false
-
- // Fetch profiles.
- wg := sync.WaitGroup{}
- profs := make([]*profile.Profile, len(sources))
- for i, source := range sources {
- wg.Add(1)
- go func(i int, src string) {
- defer wg.Done()
- p, grabErr := grabProfile(src, f.profileExecName, *f.flagBuildID, fetch, sym, obj, ui, f)
- if grabErr != nil {
- errMu.Lock()
- defer errMu.Unlock()
- errset, err = true, grabErr
- return
- }
- profs[i] = p
- }(i, source)
- }
- wg.Wait()
- if errset {
- return err
- }
-
- // Merge profiles.
- prof := profs[0]
- for _, p := range profs[1:] {
- if err = prof.Merge(p, 1); err != nil {
- return err
- }
- }
-
- if *f.flagBase != "" {
- // Fetch base profile and subtract from current profile.
- base, err := grabProfile(*f.flagBase, f.profileExecName, *f.flagBuildID, fetch, sym, obj, ui, f)
- if err != nil {
- return err
- }
-
- if err = prof.Merge(base, -1); err != nil {
- return err
- }
- }
-
- if err := processFlags(prof, ui, f); err != nil {
- return err
- }
-
- if !*f.flagRuntime {
- prof.RemoveUninteresting()
- }
-
- if *f.flagInteractive {
- return interactive(prof, obj, ui, f)
- }
-
- return generate(false, prof, obj, ui, f)
-}
-
-// isBuildID determines if the profile may contain a build ID, by
-// checking that it is a string of hex digits.
-func isBuildID(id string) bool {
- return strings.Trim(id, "0123456789abcdefABCDEF") == ""
-}
-
-// adjustURL updates the profile source URL based on heuristics. It
-// will append ?seconds=sec for CPU profiles if not already
-// specified. Returns the hostname if the profile is remote.
-func adjustURL(source string, sec int, ui plugin.UI) (adjusted, host string, duration time.Duration) {
- // If there is a local file with this name, just use it.
- if _, err := os.Stat(source); err == nil {
- return source, "", 0
- }
-
- url, err := url.Parse(source)
-
- // Automatically add http:// to URLs of the form hostname:port/path.
- // url.Parse treats "hostname" as the Scheme.
- if err != nil || (url.Host == "" && url.Scheme != "" && url.Scheme != "file") {
- url, err = url.Parse("http://" + source)
- if err != nil {
- return source, "", 0
- }
- }
- if scheme := strings.ToLower(url.Scheme); scheme == "" || scheme == "file" {
- url.Scheme = ""
- return url.String(), "", 0
- }
-
- values := url.Query()
- if urlSeconds := values.Get("seconds"); urlSeconds != "" {
- if us, err := strconv.ParseInt(urlSeconds, 10, 32); err == nil {
- if sec >= 0 {
- ui.PrintErr("Overriding -seconds for URL ", source)
- }
- sec = int(us)
- }
- }
-
- switch strings.ToLower(url.Path) {
- case "", "/":
- // Apply default /profilez.
- url.Path = "/profilez"
- case "/protoz":
- // Rewrite to /profilez?type=proto
- url.Path = "/profilez"
- values.Set("type", "proto")
- }
-
- if hasDuration(url.Path) {
- if sec > 0 {
- duration = time.Duration(sec) * time.Second
- values.Set("seconds", fmt.Sprintf("%d", sec))
- } else {
- // Assume default duration: 30 seconds
- duration = 30 * time.Second
- }
- }
- url.RawQuery = values.Encode()
- return url.String(), url.Host, duration
-}
-
-func hasDuration(path string) bool {
- for _, trigger := range []string{"profilez", "wallz", "/profile"} {
- if strings.Contains(path, trigger) {
- return true
- }
- }
- return false
-}
-
-// preprocess does filtering and aggregation of a profile based on the
-// requested options.
-func preprocess(prof *profile.Profile, ui plugin.UI, f *flags) error {
- if *f.flagFocus != "" || *f.flagIgnore != "" || *f.flagHide != "" {
- focus, ignore, hide, err := compileFocusIgnore(*f.flagFocus, *f.flagIgnore, *f.flagHide)
- if err != nil {
- return err
- }
- fm, im, hm := prof.FilterSamplesByName(focus, ignore, hide)
-
- warnNoMatches(fm, *f.flagFocus, "Focus", ui)
- warnNoMatches(im, *f.flagIgnore, "Ignore", ui)
- warnNoMatches(hm, *f.flagHide, "Hide", ui)
- }
-
- if *f.flagTagFocus != "" || *f.flagTagIgnore != "" {
- focus, err := compileTagFilter(*f.flagTagFocus, ui)
- if err != nil {
- return err
- }
- ignore, err := compileTagFilter(*f.flagTagIgnore, ui)
- if err != nil {
- return err
- }
- fm, im := prof.FilterSamplesByTag(focus, ignore)
-
- warnNoMatches(fm, *f.flagTagFocus, "TagFocus", ui)
- warnNoMatches(im, *f.flagTagIgnore, "TagIgnore", ui)
- }
-
- return aggregate(prof, f)
-}
-
-func compileFocusIgnore(focus, ignore, hide string) (f, i, h *regexp.Regexp, err error) {
- if focus != "" {
- if f, err = regexp.Compile(focus); err != nil {
- return nil, nil, nil, fmt.Errorf("parsing focus regexp: %v", err)
- }
- }
-
- if ignore != "" {
- if i, err = regexp.Compile(ignore); err != nil {
- return nil, nil, nil, fmt.Errorf("parsing ignore regexp: %v", err)
- }
- }
-
- if hide != "" {
- if h, err = regexp.Compile(hide); err != nil {
- return nil, nil, nil, fmt.Errorf("parsing hide regexp: %v", err)
- }
- }
- return
-}
-
-func compileTagFilter(filter string, ui plugin.UI) (f func(string, string, int64) bool, err error) {
- if filter == "" {
- return nil, nil
- }
- if numFilter := parseTagFilterRange(filter); numFilter != nil {
- ui.PrintErr("Interpreted '", filter, "' as range, not regexp")
- return func(key, val string, num int64) bool {
- if val != "" {
- return false
- }
- return numFilter(num, key)
- }, nil
- }
- fx, err := regexp.Compile(filter)
- if err != nil {
- return nil, err
- }
-
- return func(key, val string, num int64) bool {
- if val == "" {
- return false
- }
- return fx.MatchString(key + ":" + val)
- }, nil
-}
-
-var tagFilterRangeRx = regexp.MustCompile("([[:digit:]]+)([[:alpha:]]+)")
-
-// parseTagFilterRange returns a function to checks if a value is
-// contained on the range described by a string. It can recognize
-// strings of the form:
-// "32kb" -- matches values == 32kb
-// ":64kb" -- matches values <= 64kb
-// "4mb:" -- matches values >= 4mb
-// "12kb:64mb" -- matches values between 12kb and 64mb (both included).
-func parseTagFilterRange(filter string) func(int64, string) bool {
- ranges := tagFilterRangeRx.FindAllStringSubmatch(filter, 2)
- if len(ranges) == 0 {
- return nil // No ranges were identified
- }
- v, err := strconv.ParseInt(ranges[0][1], 10, 64)
- if err != nil {
- panic(fmt.Errorf("Failed to parse int %s: %v", ranges[0][1], err))
- }
- value, unit := report.ScaleValue(v, ranges[0][2], ranges[0][2])
- if len(ranges) == 1 {
- switch match := ranges[0][0]; filter {
- case match:
- return func(v int64, u string) bool {
- sv, su := report.ScaleValue(v, u, unit)
- return su == unit && sv == value
- }
- case match + ":":
- return func(v int64, u string) bool {
- sv, su := report.ScaleValue(v, u, unit)
- return su == unit && sv >= value
- }
- case ":" + match:
- return func(v int64, u string) bool {
- sv, su := report.ScaleValue(v, u, unit)
- return su == unit && sv <= value
- }
- }
- return nil
- }
- if filter != ranges[0][0]+":"+ranges[1][0] {
- return nil
- }
- if v, err = strconv.ParseInt(ranges[1][1], 10, 64); err != nil {
- panic(fmt.Errorf("Failed to parse int %s: %v", ranges[1][1], err))
- }
- value2, unit2 := report.ScaleValue(v, ranges[1][2], unit)
- if unit != unit2 {
- return nil
- }
- return func(v int64, u string) bool {
- sv, su := report.ScaleValue(v, u, unit)
- return su == unit && sv >= value && sv <= value2
- }
-}
-
-func warnNoMatches(match bool, rx, option string, ui plugin.UI) {
- if !match && rx != "" && rx != "." {
- ui.PrintErr(option + " expression matched no samples: " + rx)
- }
-}
-
-// grabProfile fetches and symbolizes a profile.
-func grabProfile(source, exec, buildid string, fetch plugin.Fetcher, sym plugin.Symbolizer, obj plugin.ObjTool, ui plugin.UI, f *flags) (*profile.Profile, error) {
- source, host, duration := adjustURL(source, *f.flagSeconds, ui)
- remote := host != ""
-
- if remote {
- ui.Print("Fetching profile from ", source)
- if duration != 0 {
- ui.Print("Please wait... (" + duration.String() + ")")
- }
- }
-
- now := time.Now()
- // Fetch profile from source.
- // Give 50% slack on the timeout.
- p, err := fetch(source, duration+duration/2, ui)
- if err != nil {
- return nil, err
- }
-
- // Update the time/duration if the profile source doesn't include it.
- // TODO(rsilvera): Remove this when we remove support for legacy profiles.
- if remote {
- if p.TimeNanos == 0 {
- p.TimeNanos = now.UnixNano()
- }
- if duration != 0 && p.DurationNanos == 0 {
- p.DurationNanos = int64(duration)
- }
- }
-
- // Replace executable/buildID with the options provided in the
- // command line. Assume the executable is the first Mapping entry.
- if exec != "" || buildid != "" {
- if len(p.Mapping) == 0 {
- // Create a fake mapping to hold the user option, and associate
- // all samples to it.
- m := &profile.Mapping{
- ID: 1,
- }
- for _, l := range p.Location {
- l.Mapping = m
- }
- p.Mapping = []*profile.Mapping{m}
- }
- if exec != "" {
- p.Mapping[0].File = exec
- }
- if buildid != "" {
- p.Mapping[0].BuildID = buildid
- }
- }
-
- if err := sym(*f.flagSymbolize, source, p, obj, ui); err != nil {
- return nil, err
- }
-
- // Save a copy of any remote profiles, unless the user is explicitly
- // saving it.
- if remote && !f.isFormat("proto") {
- prefix := "pprof."
- if len(p.Mapping) > 0 && p.Mapping[0].File != "" {
- prefix = prefix + filepath.Base(p.Mapping[0].File) + "."
- }
- if !strings.ContainsRune(host, os.PathSeparator) {
- prefix = prefix + host + "."
- }
- for _, s := range p.SampleType {
- prefix = prefix + s.Type + "."
- }
-
- dir := os.Getenv("PPROF_TMPDIR")
- tempFile, err := tempfile.New(dir, prefix, ".pb.gz")
- if err == nil {
- if err = p.Write(tempFile); err == nil {
- ui.PrintErr("Saved profile in ", tempFile.Name())
- }
- }
- if err != nil {
- ui.PrintErr("Could not save profile: ", err)
- }
- }
-
- if err := p.Demangle(obj.Demangle); err != nil {
- ui.PrintErr("Failed to demangle profile: ", err)
- }
-
- if err := p.CheckValid(); err != nil {
- return nil, fmt.Errorf("Grab %s: %v", source, err)
- }
-
- return p, nil
-}
-
-type flags struct {
- flagInteractive *bool // Accept commands interactively
- flagCommands map[string]*bool // pprof commands without parameters
- flagParamCommands map[string]*string // pprof commands with parameters
-
- flagOutput *string // Output file name
-
- flagCum *bool // Sort by cumulative data
- flagCallTree *bool // generate a context-sensitive call tree
-
- flagAddresses *bool // Report at address level
- flagLines *bool // Report at source line level
- flagFiles *bool // Report at file level
- flagFunctions *bool // Report at function level [default]
-
- flagSymbolize *string // Symbolization options (=none to disable)
- flagBuildID *string // Override build if for first mapping
-
- flagNodeCount *int // Max number of nodes to show
- flagNodeFraction *float64 // Hide nodes below <f>*total
- flagEdgeFraction *float64 // Hide edges below <f>*total
- flagTrim *bool // Set to false to ignore NodeCount/*Fraction
- flagRuntime *bool // Show runtime call frames in memory profiles
- flagFocus *string // Restricts to paths going through a node matching regexp
- flagIgnore *string // Skips paths going through any nodes matching regexp
- flagHide *string // Skips sample locations matching regexp
- flagTagFocus *string // Restrict to samples tagged with key:value matching regexp
- flagTagIgnore *string // Discard samples tagged with key:value matching regexp
- flagDropNegative *bool // Skip negative values
-
- flagBase *string // Source for base profile to user for comparison
-
- flagSeconds *int // Length of time for dynamic profiles
-
- flagTotalDelay *bool // Display total delay at each region
- flagContentions *bool // Display number of delays at each region
- flagMeanDelay *bool // Display mean delay at each region
-
- flagInUseSpace *bool // Display in-use memory size
- flagInUseObjects *bool // Display in-use object counts
- flagAllocSpace *bool // Display allocated memory size
- flagAllocObjects *bool // Display allocated object counts
- flagDisplayUnit *string // Measurement unit to use on reports
- flagDivideBy *float64 // Ratio to divide sample values
-
- flagSampleIndex *int // Sample value to use in reports.
- flagMean *bool // Use mean of sample_index over count
-
- flagTools *string
- profileSource []string
- profileExecName string
-
- extraUsage string
- commands commands.Commands
-}
-
-func (f *flags) isFormat(format string) bool {
- if fl := f.flagCommands[format]; fl != nil {
- return *fl
- }
- if fl := f.flagParamCommands[format]; fl != nil {
- return *fl != ""
- }
- return false
-}
-
-// String provides a printable representation for the current set of flags.
-func (f *flags) String(p *profile.Profile) string {
- var ret string
-
- if ix := *f.flagSampleIndex; ix != -1 {
- ret += fmt.Sprintf(" %-25s : %d (%s)\n", "sample_index", ix, p.SampleType[ix].Type)
- }
- if ix := *f.flagMean; ix {
- ret += boolFlagString("mean")
- }
- if *f.flagDisplayUnit != "minimum" {
- ret += stringFlagString("unit", *f.flagDisplayUnit)
- }
-
- switch {
- case *f.flagInteractive:
- ret += boolFlagString("interactive")
- }
- for name, fl := range f.flagCommands {
- if *fl {
- ret += boolFlagString(name)
- }
- }
-
- if *f.flagCum {
- ret += boolFlagString("cum")
- }
- if *f.flagCallTree {
- ret += boolFlagString("call_tree")
- }
-
- switch {
- case *f.flagAddresses:
- ret += boolFlagString("addresses")
- case *f.flagLines:
- ret += boolFlagString("lines")
- case *f.flagFiles:
- ret += boolFlagString("files")
- case *f.flagFunctions:
- ret += boolFlagString("functions")
- }
-
- if *f.flagNodeCount != -1 {
- ret += intFlagString("nodecount", *f.flagNodeCount)
- }
-
- ret += floatFlagString("nodefraction", *f.flagNodeFraction)
- ret += floatFlagString("edgefraction", *f.flagEdgeFraction)
-
- if *f.flagFocus != "" {
- ret += stringFlagString("focus", *f.flagFocus)
- }
- if *f.flagIgnore != "" {
- ret += stringFlagString("ignore", *f.flagIgnore)
- }
- if *f.flagHide != "" {
- ret += stringFlagString("hide", *f.flagHide)
- }
-
- if *f.flagTagFocus != "" {
- ret += stringFlagString("tagfocus", *f.flagTagFocus)
- }
- if *f.flagTagIgnore != "" {
- ret += stringFlagString("tagignore", *f.flagTagIgnore)
- }
-
- return ret
-}
-
-func boolFlagString(label string) string {
- return fmt.Sprintf(" %-25s : true\n", label)
-}
-
-func stringFlagString(label, value string) string {
- return fmt.Sprintf(" %-25s : %s\n", label, value)
-}
-
-func intFlagString(label string, value int) string {
- return fmt.Sprintf(" %-25s : %d\n", label, value)
-}
-
-func floatFlagString(label string, value float64) string {
- return fmt.Sprintf(" %-25s : %f\n", label, value)
-}
-
-// Utility routines to set flag values.
-func newBool(b bool) *bool {
- return &b
-}
-
-func newString(s string) *string {
- return &s
-}
-
-func newFloat64(fl float64) *float64 {
- return &fl
-}
-
-func newInt(i int) *int {
- return &i
-}
-
-func (f *flags) usage(ui plugin.UI) {
- var commandMsg []string
- for name, cmd := range f.commands {
- if cmd.HasParam {
- name = name + "=p"
- }
- commandMsg = append(commandMsg,
- fmt.Sprintf(" -%-16s %s", name, cmd.Usage))
- }
-
- sort.Strings(commandMsg)
-
- text := usageMsgHdr + strings.Join(commandMsg, "\n") + "\n" + usageMsg + "\n"
- if f.extraUsage != "" {
- text += f.extraUsage + "\n"
- }
- text += usageMsgVars
- ui.Print(text)
-}
-
-func getFlags(flag plugin.FlagSet, overrides commands.Commands, ui plugin.UI) (*flags, error) {
- f := &flags{
- flagInteractive: flag.Bool("interactive", false, "Accepts commands interactively"),
- flagCommands: make(map[string]*bool),
- flagParamCommands: make(map[string]*string),
-
- // Filename for file-based output formats, stdout by default.
- flagOutput: flag.String("output", "", "Output filename for file-based outputs "),
- // Comparisons.
- flagBase: flag.String("base", "", "Source for base profile for comparison"),
- flagDropNegative: flag.Bool("drop_negative", false, "Ignore negative differences"),
-
- // Data sorting criteria.
- flagCum: flag.Bool("cum", false, "Sort by cumulative data"),
- // Graph handling options.
- flagCallTree: flag.Bool("call_tree", false, "Create a context-sensitive call tree"),
- // Granularity of output resolution.
- flagAddresses: flag.Bool("addresses", false, "Report at address level"),
- flagLines: flag.Bool("lines", false, "Report at source line level"),
- flagFiles: flag.Bool("files", false, "Report at source file level"),
- flagFunctions: flag.Bool("functions", false, "Report at function level [default]"),
- // Internal options.
- flagSymbolize: flag.String("symbolize", "", "Options for profile symbolization"),
- flagBuildID: flag.String("buildid", "", "Override build id for first mapping"),
- // Filtering options
- flagNodeCount: flag.Int("nodecount", -1, "Max number of nodes to show"),
- flagNodeFraction: flag.Float64("nodefraction", 0.005, "Hide nodes below <f>*total"),
- flagEdgeFraction: flag.Float64("edgefraction", 0.001, "Hide edges below <f>*total"),
- flagTrim: flag.Bool("trim", true, "Honor nodefraction/edgefraction/nodecount defaults"),
- flagRuntime: flag.Bool("runtime", false, "Show runtime call frames in memory profiles"),
- flagFocus: flag.String("focus", "", "Restricts to paths going through a node matching regexp"),
- flagIgnore: flag.String("ignore", "", "Skips paths going through any nodes matching regexp"),
- flagHide: flag.String("hide", "", "Skips nodes matching regexp"),
- flagTagFocus: flag.String("tagfocus", "", "Restrict to samples with tags in range or matched by regexp"),
- flagTagIgnore: flag.String("tagignore", "", "Discard samples with tags in range or matched by regexp"),
- // CPU profile options
- flagSeconds: flag.Int("seconds", -1, "Length of time for dynamic profiles"),
- // Heap profile options
- flagInUseSpace: flag.Bool("inuse_space", false, "Display in-use memory size"),
- flagInUseObjects: flag.Bool("inuse_objects", false, "Display in-use object counts"),
- flagAllocSpace: flag.Bool("alloc_space", false, "Display allocated memory size"),
- flagAllocObjects: flag.Bool("alloc_objects", false, "Display allocated object counts"),
- flagDisplayUnit: flag.String("unit", "minimum", "Measurement units to display"),
- flagDivideBy: flag.Float64("divide_by", 1.0, "Ratio to divide all samples before visualization"),
- flagSampleIndex: flag.Int("sample_index", -1, "Index of sample value to report"),
- flagMean: flag.Bool("mean", false, "Average sample value over first value (count)"),
- // Contention profile options
- flagTotalDelay: flag.Bool("total_delay", false, "Display total delay at each region"),
- flagContentions: flag.Bool("contentions", false, "Display number of delays at each region"),
- flagMeanDelay: flag.Bool("mean_delay", false, "Display mean delay at each region"),
- flagTools: flag.String("tools", os.Getenv("PPROF_TOOLS"), "Path for object tool pathnames"),
- extraUsage: flag.ExtraUsage(),
- }
-
- // Flags used during command processing
- interactive := &f.flagInteractive
- f.commands = commands.PProf(functionCompleter, interactive)
-
- // Override commands
- for name, cmd := range overrides {
- f.commands[name] = cmd
- }
-
- for name, cmd := range f.commands {
- if cmd.HasParam {
- f.flagParamCommands[name] = flag.String(name, "", "Generate a report in "+name+" format, matching regexp")
- } else {
- f.flagCommands[name] = flag.Bool(name, false, "Generate a report in "+name+" format")
- }
- }
-
- args := flag.Parse(func() { f.usage(ui) })
- if len(args) == 0 {
- return nil, fmt.Errorf("no profile source specified")
- }
-
- f.profileSource = args
-
- // Instruct legacy heapz parsers to grab historical allocation data,
- // instead of the default in-use data. Not available with tcmalloc.
- if *f.flagAllocSpace || *f.flagAllocObjects {
- profile.LegacyHeapAllocated = true
- }
-
- if profileDir := os.Getenv("PPROF_TMPDIR"); profileDir == "" {
- profileDir = os.Getenv("HOME") + "/pprof"
- os.Setenv("PPROF_TMPDIR", profileDir)
- if err := os.MkdirAll(profileDir, 0755); err != nil {
- return nil, fmt.Errorf("failed to access temp dir %s: %v", profileDir, err)
- }
- }
-
- return f, nil
-}
-
-func processFlags(p *profile.Profile, ui plugin.UI, f *flags) error {
- flagDis := f.isFormat("disasm")
- flagPeek := f.isFormat("peek")
- flagWebList := f.isFormat("weblist")
- flagList := f.isFormat("list")
-
- if flagDis || flagWebList {
- // Collect all samples at address granularity for assembly
- // listing.
- f.flagNodeCount = newInt(0)
- f.flagAddresses = newBool(true)
- f.flagLines = newBool(false)
- f.flagFiles = newBool(false)
- f.flagFunctions = newBool(false)
- }
-
- if flagPeek {
- // Collect all samples at function granularity for peek command
- f.flagNodeCount = newInt(0)
- f.flagAddresses = newBool(false)
- f.flagLines = newBool(false)
- f.flagFiles = newBool(false)
- f.flagFunctions = newBool(true)
- }
-
- if flagList {
- // Collect all samples at fileline granularity for source
- // listing.
- f.flagNodeCount = newInt(0)
- f.flagAddresses = newBool(false)
- f.flagLines = newBool(true)
- f.flagFiles = newBool(false)
- f.flagFunctions = newBool(false)
- }
-
- if !*f.flagTrim {
- f.flagNodeCount = newInt(0)
- f.flagNodeFraction = newFloat64(0)
- f.flagEdgeFraction = newFloat64(0)
- }
-
- if oc := countFlagMap(f.flagCommands, f.flagParamCommands); oc == 0 {
- f.flagInteractive = newBool(true)
- } else if oc > 1 {
- f.usage(ui)
- return fmt.Errorf("must set at most one output format")
- }
-
- // Apply nodecount defaults for non-interactive mode. The
- // interactive shell will apply defaults for the interactive mode.
- if *f.flagNodeCount < 0 && !*f.flagInteractive {
- switch {
- default:
- f.flagNodeCount = newInt(80)
- case f.isFormat("text"):
- f.flagNodeCount = newInt(0)
- }
- }
-
- // Apply legacy options and diagnose conflicts.
- if rc := countFlags([]*bool{f.flagAddresses, f.flagLines, f.flagFiles, f.flagFunctions}); rc == 0 {
- f.flagFunctions = newBool(true)
- } else if rc > 1 {
- f.usage(ui)
- return fmt.Errorf("must set at most one granularity option")
- }
-
- var err error
- si, sm := *f.flagSampleIndex, *f.flagMean || *f.flagMeanDelay
- si, err = sampleIndex(p, &f.flagTotalDelay, si, 1, "delay", "-total_delay", err)
- si, err = sampleIndex(p, &f.flagMeanDelay, si, 1, "delay", "-mean_delay", err)
- si, err = sampleIndex(p, &f.flagContentions, si, 0, "contentions", "-contentions", err)
-
- si, err = sampleIndex(p, &f.flagInUseSpace, si, 1, "inuse_space", "-inuse_space", err)
- si, err = sampleIndex(p, &f.flagInUseObjects, si, 0, "inuse_objects", "-inuse_objects", err)
- si, err = sampleIndex(p, &f.flagAllocSpace, si, 1, "alloc_space", "-alloc_space", err)
- si, err = sampleIndex(p, &f.flagAllocObjects, si, 0, "alloc_objects", "-alloc_objects", err)
-
- if si == -1 {
- // Use last value if none is requested.
- si = len(p.SampleType) - 1
- } else if si < 0 || si >= len(p.SampleType) {
- err = fmt.Errorf("sample_index value %d out of range [0..%d]", si, len(p.SampleType)-1)
- }
-
- if err != nil {
- f.usage(ui)
- return err
- }
- f.flagSampleIndex, f.flagMean = newInt(si), newBool(sm)
- return nil
-}
-
-func sampleIndex(p *profile.Profile, flag **bool,
- sampleIndex int,
- newSampleIndex int,
- sampleType, option string,
- err error) (int, error) {
- if err != nil || !**flag {
- return sampleIndex, err
- }
- *flag = newBool(false)
- if sampleIndex != -1 {
- return 0, fmt.Errorf("set at most one sample value selection option")
- }
- if newSampleIndex >= len(p.SampleType) ||
- p.SampleType[newSampleIndex].Type != sampleType {
- return 0, fmt.Errorf("option %s not valid for this profile", option)
- }
- return newSampleIndex, nil
-}
-
-func countFlags(bs []*bool) int {
- var c int
- for _, b := range bs {
- if *b {
- c++
- }
- }
- return c
-}
-
-func countFlagMap(bms map[string]*bool, bmrxs map[string]*string) int {
- var c int
- for _, b := range bms {
- if *b {
- c++
- }
- }
- for _, s := range bmrxs {
- if *s != "" {
- c++
- }
- }
- return c
-}
-
-var usageMsgHdr = "usage: pprof [options] [binary] <profile source> ...\n" +
- "Output format (only set one):\n"
-
-var usageMsg = "Output file parameters (for file-based output formats):\n" +
- " -output=f Generate output on file f (stdout by default)\n" +
- "Output granularity (only set one):\n" +
- " -functions Report at function level [default]\n" +
- " -files Report at source file level\n" +
- " -lines Report at source line level\n" +
- " -addresses Report at address level\n" +
- "Comparison options:\n" +
- " -base <profile> Show delta from this profile\n" +
- " -drop_negative Ignore negative differences\n" +
- "Sorting options:\n" +
- " -cum Sort by cumulative data\n\n" +
- "Dynamic profile options:\n" +
- " -seconds=N Length of time for dynamic profiles\n" +
- "Profile trimming options:\n" +
- " -nodecount=N Max number of nodes to show\n" +
- " -nodefraction=f Hide nodes below <f>*total\n" +
- " -edgefraction=f Hide edges below <f>*total\n" +
- "Sample value selection option (by index):\n" +
- " -sample_index Index of sample value to display\n" +
- " -mean Average sample value over first value\n" +
- "Sample value selection option (for heap profiles):\n" +
- " -inuse_space Display in-use memory size\n" +
- " -inuse_objects Display in-use object counts\n" +
- " -alloc_space Display allocated memory size\n" +
- " -alloc_objects Display allocated object counts\n" +
- "Sample value selection option (for contention profiles):\n" +
- " -total_delay Display total delay at each region\n" +
- " -contentions Display number of delays at each region\n" +
- " -mean_delay Display mean delay at each region\n" +
- "Filtering options:\n" +
- " -runtime Show runtime call frames in memory profiles\n" +
- " -focus=r Restricts to paths going through a node matching regexp\n" +
- " -ignore=r Skips paths going through any nodes matching regexp\n" +
- " -tagfocus=r Restrict to samples tagged with key:value matching regexp\n" +
- " Restrict to samples with numeric tags in range (eg \"32kb:1mb\")\n" +
- " -tagignore=r Discard samples tagged with key:value matching regexp\n" +
- " Avoid samples with numeric tags in range (eg \"1mb:\")\n" +
- "Miscellaneous:\n" +
- " -call_tree Generate a context-sensitive call tree\n" +
- " -unit=u Convert all samples to unit u for display\n" +
- " -divide_by=f Scale all samples by dividing them by f\n" +
- " -buildid=id Override build id for main binary in profile\n" +
- " -tools=path Search path for object-level tools\n" +
- " -help This message"
-
-var usageMsgVars = "Environment Variables:\n" +
- " PPROF_TMPDIR Location for saved profiles (default $HOME/pprof)\n" +
- " PPROF_TOOLS Search path for object-level tools\n" +
- " PPROF_BINARY_PATH Search path for local binary files\n" +
- " default: $HOME/pprof/binaries\n" +
- " finds binaries by $name and $buildid/$name"
-
-func aggregate(prof *profile.Profile, f *flags) error {
- switch {
- case f.isFormat("proto"), f.isFormat("raw"):
- // No aggregation for raw profiles.
- case f.isFormat("callgrind"):
- // Aggregate to file/line for callgrind.
- fallthrough
- case *f.flagLines:
- return prof.Aggregate(true, true, true, true, false)
- case *f.flagFiles:
- return prof.Aggregate(true, false, true, false, false)
- case *f.flagFunctions:
- return prof.Aggregate(true, true, false, false, false)
- case f.isFormat("weblist"), f.isFormat("disasm"):
- return prof.Aggregate(false, true, true, true, true)
- }
- return nil
-}
-
-// parseOptions parses the options into report.Options
-// Returns a function to postprocess the report after generation.
-func parseOptions(f *flags) (o *report.Options, p commands.PostProcessor, err error) {
-
- if *f.flagDivideBy == 0 {
- return nil, nil, fmt.Errorf("zero divisor specified")
- }
-
- o = &report.Options{
- CumSort: *f.flagCum,
- CallTree: *f.flagCallTree,
- PrintAddresses: *f.flagAddresses,
- DropNegative: *f.flagDropNegative,
- Ratio: 1 / *f.flagDivideBy,
-
- NodeCount: *f.flagNodeCount,
- NodeFraction: *f.flagNodeFraction,
- EdgeFraction: *f.flagEdgeFraction,
- OutputUnit: *f.flagDisplayUnit,
- }
-
- for cmd, b := range f.flagCommands {
- if *b {
- pcmd := f.commands[cmd]
- o.OutputFormat = pcmd.Format
- return o, pcmd.PostProcess, nil
- }
- }
-
- for cmd, rx := range f.flagParamCommands {
- if *rx != "" {
- pcmd := f.commands[cmd]
- if o.Symbol, err = regexp.Compile(*rx); err != nil {
- return nil, nil, fmt.Errorf("parsing -%s regexp: %v", cmd, err)
- }
- o.OutputFormat = pcmd.Format
- return o, pcmd.PostProcess, nil
- }
- }
-
- return nil, nil, fmt.Errorf("no output format selected")
-}
-
-type sampleValueFunc func(*profile.Sample) int64
-
-// sampleFormat returns a function to extract values out of a profile.Sample,
-// and the type/units of those values.
-func sampleFormat(p *profile.Profile, f *flags) (sampleValueFunc, string, string) {
- valueIndex := *f.flagSampleIndex
-
- if *f.flagMean {
- return meanExtractor(valueIndex), "mean_" + p.SampleType[valueIndex].Type, p.SampleType[valueIndex].Unit
- }
-
- return valueExtractor(valueIndex), p.SampleType[valueIndex].Type, p.SampleType[valueIndex].Unit
-}
-
-func valueExtractor(ix int) sampleValueFunc {
- return func(s *profile.Sample) int64 {
- return s.Value[ix]
- }
-}
-
-func meanExtractor(ix int) sampleValueFunc {
- return func(s *profile.Sample) int64 {
- if s.Value[0] == 0 {
- return 0
- }
- return s.Value[ix] / s.Value[0]
- }
-}
-
-func generate(interactive bool, prof *profile.Profile, obj plugin.ObjTool, ui plugin.UI, f *flags) error {
- o, postProcess, err := parseOptions(f)
- if err != nil {
- return err
- }
-
- var w io.Writer
- if *f.flagOutput == "" {
- w = os.Stdout
- } else {
- ui.PrintErr("Generating report in ", *f.flagOutput)
- outputFile, err := os.Create(*f.flagOutput)
- if err != nil {
- return err
- }
- defer outputFile.Close()
- w = outputFile
- }
-
- if prof.Empty() {
- return fmt.Errorf("profile is empty")
- }
-
- value, stype, unit := sampleFormat(prof, f)
- o.SampleType = stype
- rpt := report.New(prof, *o, value, unit)
-
- // Do not apply filters if we're just generating a proto, so we
- // still have all the data.
- if o.OutputFormat != report.Proto {
- // Delay applying focus/ignore until after creating the report so
- // the report reflects the total number of samples.
- if err := preprocess(prof, ui, f); err != nil {
- return err
- }
- }
-
- if postProcess == nil {
- return report.Generate(w, rpt, obj)
- }
-
- var dot bytes.Buffer
- if err = report.Generate(&dot, rpt, obj); err != nil {
- return err
- }
-
- return postProcess(&dot, w, ui)
-}
diff --git a/src/cmd/internal/pprof/driver/interactive.go b/src/cmd/internal/pprof/driver/interactive.go
deleted file mode 100644
index 1b08226..0000000
--- a/src/cmd/internal/pprof/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/internal/pprof/commands"
- "cmd/internal/pprof/plugin"
- "cmd/internal/pprof/profile"
-)
-
-var profileFunctionNames = []string{}
-
-// functionCompleter replaces provided substring with a function
-// name retrieved from a profile if a single match exists. Otherwise,
-// it returns unchanged substring. It defaults to no-op if the profile
-// is not specified.
-func functionCompleter(substring string) string {
- found := ""
- for _, fName := range profileFunctionNames {
- if strings.Contains(fName, substring) {
- if found != "" {
- return substring
- }
- found = fName
- }
- }
- if found != "" {
- return found
- }
- return substring
-}
-
-// updateAutoComplete enhances autocompletion with information that can be
-// retrieved from the profile
-func updateAutoComplete(p *profile.Profile) {
- profileFunctionNames = nil // remove function names retrieved previously
- for _, fn := range p.Function {
- profileFunctionNames = append(profileFunctionNames, fn.Name)
- }
-}
-
-// splitCommand splits the command line input into tokens separated by
-// spaces. Takes care to separate commands of the form 'top10' into
-// two tokens: 'top' and '10'
-func splitCommand(input string) []string {
- fields := strings.Fields(input)
- if num := strings.IndexAny(fields[0], "0123456789"); num != -1 {
- inputNumber := fields[0][num:]
- fields[0] = fields[0][:num]
- fields = append([]string{fields[0], inputNumber}, fields[1:]...)
- }
- return fields
-}
-
-// interactive displays a prompt and reads commands for profile
-// manipulation/visualization.
-func interactive(p *profile.Profile, obj plugin.ObjTool, ui plugin.UI, f *flags) error {
- updateAutoComplete(p)
-
- // Enter command processing loop.
- ui.Print("Entering interactive mode (type \"help\" for commands)")
- ui.SetAutoComplete(commands.NewCompleter(f.commands))
-
- for {
- input, err := readCommand(p, ui, f)
- if err != nil {
- if err != io.EOF {
- return err
- }
- if input == "" {
- return nil
- }
- }
- // Process simple commands.
- switch input {
- case "":
- continue
- case ":":
- f.flagFocus = newString("")
- f.flagIgnore = newString("")
- f.flagTagFocus = newString("")
- f.flagTagIgnore = newString("")
- f.flagHide = newString("")
- continue
- }
-
- fields := splitCommand(input)
- // Process report generation commands.
- if _, ok := f.commands[fields[0]]; ok {
- if err := generateReport(p, fields, obj, ui, f); err != nil {
- if err == io.EOF {
- return nil
- }
- ui.PrintErr(err)
- }
- continue
- }
-
- switch cmd := fields[0]; cmd {
- case "help":
- commandHelp(fields, ui, f)
- continue
- case "exit", "quit":
- return nil
- }
-
- // Process option settings.
- if of, err := optFlags(p, input, f); err == nil {
- f = of
- } else {
- ui.PrintErr("Error: ", err.Error())
- }
- }
-}
-
-func generateReport(p *profile.Profile, cmd []string, obj plugin.ObjTool, ui plugin.UI, f *flags) error {
- prof := p.Copy()
-
- cf, err := cmdFlags(prof, cmd, ui, f)
- if err != nil {
- return err
- }
-
- return generate(true, prof, obj, ui, cf)
-}
-
-// validateRegex checks if a string is a valid regular expression.
-func validateRegex(v string) error {
- _, err := regexp.Compile(v)
- return err
-}
-
-// readCommand prompts for and reads the next command.
-func readCommand(p *profile.Profile, ui plugin.UI, f *flags) (string, error) {
- //ui.Print("Options:\n", f.String(p))
- s, err := ui.ReadLine()
- return strings.TrimSpace(s), err
-}
-
-func commandHelp(_ []string, ui plugin.UI, f *flags) error {
- help := `
- Commands:
- cmd [n] [--cum] [focus_regex]* [-ignore_regex]*
- Produce a text report with the top n entries.
- Include samples matching focus_regex, and exclude ignore_regex.
- Add --cum to sort using cumulative data.
- Available commands:
-`
- var commands []string
- for name, cmd := range f.commands {
- commands = append(commands, fmt.Sprintf(" %-12s %s", name, cmd.Usage))
- }
- sort.Strings(commands)
-
- help = help + strings.Join(commands, "\n") + `
- peek func_regex
- Display callers and callees of functions matching func_regex.
-
- dot [n] [focus_regex]* [-ignore_regex]* [>file]
- Produce an annotated callgraph with the top n entries.
- Include samples matching focus_regex, and exclude ignore_regex.
- For other outputs, replace dot with:
- - Graphic formats: dot, svg, pdf, ps, gif, png (use > to name output file)
- - Graph viewer: gv, web, evince, eog
-
- callgrind [n] [focus_regex]* [-ignore_regex]* [>file]
- Produce a file in callgrind-compatible format.
- Include samples matching focus_regex, and exclude ignore_regex.
-
- weblist func_regex [-ignore_regex]*
- Show annotated source with interspersed assembly in a web browser.
-
- list func_regex [-ignore_regex]*
- Print source for routines matching func_regex, and exclude ignore_regex.
-
- disasm func_regex [-ignore_regex]*
- Disassemble routines matching func_regex, and exclude ignore_regex.
-
- tags tag_regex [-ignore_regex]*
- List tags with key:value matching tag_regex and exclude ignore_regex.
-
- quit/exit/^D
- Exit pprof.
-
- option=value
- The following options can be set individually:
- cum/flat: Sort entries based on cumulative or flat data
- call_tree: Build context-sensitive call trees
- nodecount: Max number of entries to display
- nodefraction: Min frequency ratio of nodes to display
- edgefraction: Min frequency ratio of edges to display
- focus/ignore: Regexp to include/exclude samples by name/file
- tagfocus/tagignore: Regexp or value range to filter samples by tag
- eg "1mb", "1mb:2mb", ":64kb"
-
- functions: Level of aggregation for sample data
- files:
- lines:
- addresses:
-
- unit: Measurement unit to use on reports
-
- Sample value selection by index:
- sample_index: Index of sample value to display
- mean: Average sample value over first value
-
- Sample value selection by name:
- alloc_space for heap profiles
- alloc_objects
- inuse_space
- inuse_objects
-
- total_delay for contention profiles
- mean_delay
- contentions
-
- : Clear focus/ignore/hide/tagfocus/tagignore`
-
- ui.Print(help)
- return nil
-}
-
-// cmdFlags parses the options of an interactive command and returns
-// an updated flags object.
-func cmdFlags(prof *profile.Profile, input []string, ui plugin.UI, f *flags) (*flags, error) {
- cf := *f
-
- var focus, ignore string
- output := *cf.flagOutput
- nodeCount := *cf.flagNodeCount
- cmd := input[0]
-
- // Update output flags based on parameters.
- tokens := input[1:]
- for p := 0; p < len(tokens); p++ {
- t := tokens[p]
- if t == "" {
- continue
- }
- if c, err := strconv.ParseInt(t, 10, 32); err == nil {
- nodeCount = int(c)
- continue
- }
- switch t[0] {
- case '>':
- if len(t) > 1 {
- output = t[1:]
- continue
- }
- // find next token
- for p++; p < len(tokens); p++ {
- if tokens[p] != "" {
- output = tokens[p]
- break
- }
- }
- case '-':
- if t == "--cum" || t == "-cum" {
- cf.flagCum = newBool(true)
- continue
- }
- ignore = catRegex(ignore, t[1:])
- default:
- focus = catRegex(focus, t)
- }
- }
-
- pcmd, ok := f.commands[cmd]
- if !ok {
- return nil, fmt.Errorf("Unexpected parse failure: %v", input)
- }
- // Reset flags
- cf.flagCommands = make(map[string]*bool)
- cf.flagParamCommands = make(map[string]*string)
-
- if !pcmd.HasParam {
- cf.flagCommands[cmd] = newBool(true)
-
- switch cmd {
- case "tags":
- cf.flagTagFocus = newString(focus)
- cf.flagTagIgnore = newString(ignore)
- default:
- cf.flagFocus = newString(catRegex(*cf.flagFocus, focus))
- cf.flagIgnore = newString(catRegex(*cf.flagIgnore, ignore))
- }
- } else {
- if focus == "" {
- focus = "."
- }
- cf.flagParamCommands[cmd] = newString(focus)
- cf.flagIgnore = newString(catRegex(*cf.flagIgnore, ignore))
- }
-
- if nodeCount < 0 {
- switch cmd {
- case "text", "top":
- // Default text/top to 10 nodes on interactive mode
- nodeCount = 10
- default:
- nodeCount = 80
- }
- }
-
- cf.flagNodeCount = newInt(nodeCount)
- cf.flagOutput = newString(output)
-
- // Do regular flags processing
- if err := processFlags(prof, ui, &cf); err != nil {
- cf.usage(ui)
- return nil, err
- }
-
- return &cf, nil
-}
-
-func catRegex(a, b string) string {
- if a == "" {
- return b
- }
- if b == "" {
- return a
- }
- return a + "|" + b
-}
-
-// optFlags parses an interactive option setting and returns
-// an updated flags object.
-func optFlags(p *profile.Profile, input string, f *flags) (*flags, error) {
- inputs := strings.SplitN(input, "=", 2)
- option := strings.ToLower(strings.TrimSpace(inputs[0]))
- var value string
- if len(inputs) == 2 {
- value = strings.TrimSpace(inputs[1])
- }
-
- of := *f
-
- var err error
- var bv bool
- var uv uint64
- var fv float64
-
- switch option {
- case "cum":
- if bv, err = parseBool(value); err != nil {
- return nil, err
- }
- of.flagCum = newBool(bv)
- case "flat":
- if bv, err = parseBool(value); err != nil {
- return nil, err
- }
- of.flagCum = newBool(!bv)
- case "call_tree":
- if bv, err = parseBool(value); err != nil {
- return nil, err
- }
- of.flagCallTree = newBool(bv)
- case "unit":
- of.flagDisplayUnit = newString(value)
- case "sample_index":
- if uv, err = strconv.ParseUint(value, 10, 32); err != nil {
- return nil, err
- }
- if ix := int(uv); ix < 0 || ix >= len(p.SampleType) {
- return nil, fmt.Errorf("sample_index out of range [0..%d]", len(p.SampleType)-1)
- }
- of.flagSampleIndex = newInt(int(uv))
- case "mean":
- if bv, err = parseBool(value); err != nil {
- return nil, err
- }
- of.flagMean = newBool(bv)
- case "nodecount":
- if uv, err = strconv.ParseUint(value, 10, 32); err != nil {
- return nil, err
- }
- of.flagNodeCount = newInt(int(uv))
- case "nodefraction":
- if fv, err = strconv.ParseFloat(value, 64); err != nil {
- return nil, err
- }
- of.flagNodeFraction = newFloat64(fv)
- case "edgefraction":
- if fv, err = strconv.ParseFloat(value, 64); err != nil {
- return nil, err
- }
- of.flagEdgeFraction = newFloat64(fv)
- case "focus":
- if err = validateRegex(value); err != nil {
- return nil, err
- }
- of.flagFocus = newString(value)
- case "ignore":
- if err = validateRegex(value); err != nil {
- return nil, err
- }
- of.flagIgnore = newString(value)
- case "tagfocus":
- if err = validateRegex(value); err != nil {
- return nil, err
- }
- of.flagTagFocus = newString(value)
- case "tagignore":
- if err = validateRegex(value); err != nil {
- return nil, err
- }
- of.flagTagIgnore = newString(value)
- case "hide":
- if err = validateRegex(value); err != nil {
- return nil, err
- }
- of.flagHide = newString(value)
- case "addresses", "files", "lines", "functions":
- if bv, err = parseBool(value); err != nil {
- return nil, err
- }
- if !bv {
- return nil, fmt.Errorf("select one of addresses/files/lines/functions")
- }
- setGranularityToggle(option, &of)
- default:
- if ix := findSampleIndex(p, "", option); ix >= 0 {
- of.flagSampleIndex = newInt(ix)
- } else if ix := findSampleIndex(p, "total_", option); ix >= 0 {
- of.flagSampleIndex = newInt(ix)
- of.flagMean = newBool(false)
- } else if ix := findSampleIndex(p, "mean_", option); ix >= 1 {
- of.flagSampleIndex = newInt(ix)
- of.flagMean = newBool(true)
- } else {
- return nil, fmt.Errorf("unrecognized command: %s", input)
- }
- }
- return &of, nil
-}
-
-// parseBool parses a string as a boolean value.
-func parseBool(v string) (bool, error) {
- switch strings.ToLower(v) {
- case "true", "t", "yes", "y", "1", "":
- return true, nil
- case "false", "f", "no", "n", "0":
- return false, nil
- }
- return false, fmt.Errorf(`illegal input "%s" for bool value`, v)
-}
-
-func findSampleIndex(p *profile.Profile, prefix, sampleType string) int {
- if !strings.HasPrefix(sampleType, prefix) {
- return -1
- }
- sampleType = strings.TrimPrefix(sampleType, prefix)
- for i, r := range p.SampleType {
- if r.Type == sampleType {
- return i
- }
- }
- return -1
-}
-
-// setGranularityToggle manages the set of granularity options. These
-// operate as a toggle; turning one on turns the others off.
-func setGranularityToggle(o string, fl *flags) {
- t, f := newBool(true), newBool(false)
- fl.flagFunctions = f
- fl.flagFiles = f
- fl.flagLines = f
- fl.flagAddresses = f
- switch o {
- case "functions":
- fl.flagFunctions = t
- case "files":
- fl.flagFiles = t
- case "lines":
- fl.flagLines = t
- case "addresses":
- fl.flagAddresses = t
- default:
- panic(fmt.Errorf("unexpected option %s", o))
- }
-}
diff --git a/src/cmd/internal/pprof/fetch/fetch.go b/src/cmd/internal/pprof/fetch/fetch.go
deleted file mode 100644
index ffd282e..0000000
--- a/src/cmd/internal/pprof/fetch/fetch.go
+++ /dev/null
@@ -1,82 +0,0 @@
-// Copyright 2014 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// Package fetch provides an extensible mechanism to fetch a profile
-// from a data source.
-package fetch
-
-import (
- "fmt"
- "io"
- "io/ioutil"
- "net/http"
- "net/url"
- "os"
- "strings"
- "time"
-
- "cmd/internal/pprof/plugin"
- "cmd/internal/pprof/profile"
-)
-
-// FetchProfile reads from a data source (network, file) and generates a
-// profile.
-func FetchProfile(source string, timeout time.Duration) (*profile.Profile, error) {
- return Fetcher(source, timeout, plugin.StandardUI())
-}
-
-// Fetcher is the plugin.Fetcher version of FetchProfile.
-func Fetcher(source string, timeout time.Duration, ui plugin.UI) (*profile.Profile, error) {
- var f io.ReadCloser
- var err error
-
- url, err := url.Parse(source)
- if err == nil && url.Host != "" {
- f, err = FetchURL(source, timeout)
- } else {
- f, err = os.Open(source)
- }
- if err != nil {
- return nil, err
- }
- defer f.Close()
- return profile.Parse(f)
-}
-
-// FetchURL fetches a profile from a URL using HTTP.
-func FetchURL(source string, timeout time.Duration) (io.ReadCloser, error) {
- resp, err := httpGet(source, timeout)
- if err != nil {
- return nil, fmt.Errorf("http fetch %s: %v", source, err)
- }
- if resp.StatusCode != http.StatusOK {
- return nil, fmt.Errorf("server response: %s", resp.Status)
- }
-
- return resp.Body, nil
-}
-
-// PostURL issues a POST to a URL over HTTP.
-func PostURL(source, post string) ([]byte, error) {
- resp, err := http.Post(source, "application/octet-stream", strings.NewReader(post))
- if err != nil {
- return nil, fmt.Errorf("http post %s: %v", source, err)
- }
- if resp.StatusCode != http.StatusOK {
- return nil, fmt.Errorf("server response: %s", resp.Status)
- }
- defer resp.Body.Close()
- return ioutil.ReadAll(resp.Body)
-}
-
-// httpGet is a wrapper around http.Get; it is defined as a variable
-// so it can be redefined during for testing.
-var httpGet = func(url string, timeout time.Duration) (*http.Response, error) {
- client := &http.Client{
- Transport: &http.Transport{
- ResponseHeaderTimeout: timeout + 5*time.Second,
- },
- }
- return client.Get(url)
-}
diff --git a/src/cmd/internal/pprof/plugin/plugin.go b/src/cmd/internal/pprof/plugin/plugin.go
deleted file mode 100644
index d5025d5..0000000
--- a/src/cmd/internal/pprof/plugin/plugin.go
+++ /dev/null
@@ -1,213 +0,0 @@
-// Copyright 2014 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// Package plugin defines the plugin implementations that the main pprof driver requires.
-package plugin
-
-import (
- "bufio"
- "fmt"
- "os"
- "regexp"
- "strings"
- "time"
-
- "cmd/internal/pprof/profile"
-)
-
-// A FlagSet creates and parses command-line flags.
-// It is similar to the standard flag.FlagSet.
-type FlagSet interface {
- // Bool, Int, Float64, and String define new flags,
- // like the functions of the same name in package flag.
- Bool(name string, def bool, usage string) *bool
- Int(name string, def int, usage string) *int
- Float64(name string, def float64, usage string) *float64
- String(name string, def string, usage string) *string
-
- // ExtraUsage returns any additional text that should be
- // printed after the standard usage message.
- // The typical use of ExtraUsage is to show any custom flags
- // defined by the specific pprof plugins being used.
- ExtraUsage() string
-
- // Parse initializes the flags with their values for this run
- // and returns the non-flag command line arguments.
- // If an unknown flag is encountered or there are no arguments,
- // Parse should call usage and return nil.
- Parse(usage func()) []string
-}
-
-// An ObjTool inspects shared libraries and executable files.
-type ObjTool interface {
- // Open opens the named object file.
- // If the object is a shared library, start is the address where
- // it is mapped into memory in the address space being inspected.
- Open(file string, start uint64) (ObjFile, error)
-
- // Demangle translates a batch of symbol names from mangled
- // form to human-readable form.
- Demangle(names []string) (map[string]string, error)
-
- // Disasm disassembles the named object file, starting at
- // the start address and stopping at (before) the end address.
- Disasm(file string, start, end uint64) ([]Inst, error)
-
- // SetConfig configures the tool.
- // The implementation defines the meaning of the string
- // and can ignore it entirely.
- SetConfig(config string)
-}
-
-// NoObjTool returns a trivial implementation of the ObjTool interface.
-// Open returns an error indicating that the requested file does not exist.
-// Demangle returns an empty map and a nil error.
-// Disasm returns an error.
-// SetConfig is a no-op.
-func NoObjTool() ObjTool {
- return noObjTool{}
-}
-
-type noObjTool struct{}
-
-func (noObjTool) Open(file string, start uint64) (ObjFile, error) {
- return nil, &os.PathError{Op: "open", Path: file, Err: os.ErrNotExist}
-}
-
-func (noObjTool) Demangle(name []string) (map[string]string, error) {
- return make(map[string]string), nil
-}
-
-func (noObjTool) Disasm(file string, start, end uint64) ([]Inst, error) {
- return nil, fmt.Errorf("disassembly not supported")
-}
-
-func (noObjTool) SetConfig(config string) {
-}
-
-// An ObjFile is a single object file: a shared library or executable.
-type ObjFile interface {
- // Name returns the underlyinf file name, if available
- Name() string
-
- // Base returns the base address to use when looking up symbols in the file.
- Base() uint64
-
- // BuildID returns the GNU build ID of the file, or an empty string.
- BuildID() string
-
- // SourceLine reports the source line information for a given
- // address in the file. Due to inlining, the source line information
- // is in general a list of positions representing a call stack,
- // with the leaf function first.
- SourceLine(addr uint64) ([]Frame, error)
-
- // Symbols returns a list of symbols in the object file.
- // If r is not nil, Symbols restricts the list to symbols
- // with names matching the regular expression.
- // If addr is not zero, Symbols restricts the list to symbols
- // containing that address.
- Symbols(r *regexp.Regexp, addr uint64) ([]*Sym, error)
-
- // Close closes the file, releasing associated resources.
- Close() error
-}
-
-// A Frame describes a single line in a source file.
-type Frame struct {
- Func string // name of function
- File string // source file name
- Line int // line in file
-}
-
-// A Sym describes a single symbol in an object file.
-type Sym struct {
- Name []string // names of symbol (many if symbol was dedup'ed)
- File string // object file containing symbol
- Start uint64 // start virtual address
- End uint64 // virtual address of last byte in sym (Start+size-1)
-}
-
-// An Inst is a single instruction in an assembly listing.
-type Inst struct {
- Addr uint64 // virtual address of instruction
- Text string // instruction text
- File string // source file
- Line int // source line
-}
-
-// A UI manages user interactions.
-type UI interface {
- // Read returns a line of text (a command) read from the user.
- ReadLine() (string, error)
-
- // Print shows a message to the user.
- // It formats the text as fmt.Print would and adds a final \n if not already present.
- // For line-based UI, Print writes to standard error.
- // (Standard output is reserved for report data.)
- Print(...interface{})
-
- // PrintErr shows an error message to the user.
- // It formats the text as fmt.Print would and adds a final \n if not already present.
- // For line-based UI, PrintErr writes to standard error.
- PrintErr(...interface{})
-
- // IsTerminal returns whether the UI is known to be tied to an
- // interactive terminal (as opposed to being redirected to a file).
- IsTerminal() bool
-
- // SetAutoComplete instructs the UI to call complete(cmd) to obtain
- // the auto-completion of cmd, if the UI supports auto-completion at all.
- SetAutoComplete(complete func(string) string)
-}
-
-// StandardUI returns a UI that reads from standard input,
-// prints messages to standard output,
-// prints errors to standard error, and doesn't use auto-completion.
-func StandardUI() UI {
- return &stdUI{r: bufio.NewReader(os.Stdin)}
-}
-
-type stdUI struct {
- r *bufio.Reader
-}
-
-func (ui *stdUI) ReadLine() (string, error) {
- os.Stdout.WriteString("(pprof) ")
- return ui.r.ReadString('\n')
-}
-
-func (ui *stdUI) Print(args ...interface{}) {
- ui.fprint(os.Stderr, args)
-}
-
-func (ui *stdUI) PrintErr(args ...interface{}) {
- ui.fprint(os.Stderr, args)
-}
-
-func (ui *stdUI) IsTerminal() bool {
- return false
-}
-
-func (ui *stdUI) SetAutoComplete(func(string) string) {
-}
-
-func (ui *stdUI) fprint(f *os.File, args []interface{}) {
- text := fmt.Sprint(args...)
- if !strings.HasSuffix(text, "\n") {
- text += "\n"
- }
- f.WriteString(text)
-}
-
-// A Fetcher reads and returns the profile named by src.
-// It gives up after the given timeout, unless src contains a timeout override
-// (as defined by the implementation).
-// It can print messages to ui.
-type Fetcher func(src string, timeout time.Duration, ui UI) (*profile.Profile, error)
-
-// A Symbolizer annotates a profile with symbol information.
-// The profile was fetch from src.
-// The meaning of mode is defined by the implementation.
-type Symbolizer func(mode, src string, prof *profile.Profile, obj ObjTool, ui UI) error
diff --git a/src/cmd/internal/pprof/profile/legacy_profile.go b/src/cmd/internal/pprof/profile/legacy_profile.go
deleted file mode 100644
index 8ccfe45..0000000
--- a/src/cmd/internal/pprof/profile/legacy_profile.go
+++ /dev/null
@@ -1,1236 +0,0 @@
-// Copyright 2014 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// This file implements parsers to convert legacy profiles into the
-// profile.proto format.
-
-package profile
-
-import (
- "bufio"
- "bytes"
- "fmt"
- "io"
- "math"
- "regexp"
- "strconv"
- "strings"
-)
-
-var (
- countStartRE = regexp.MustCompile(`\A(\w+) profile: total \d+\n\z`)
- countRE = regexp.MustCompile(`\A(\d+) @(( 0x[0-9a-f]+)+)\n\z`)
-
- heapHeaderRE = regexp.MustCompile(`heap profile: *(\d+): *(\d+) *\[ *(\d+): *(\d+) *\] *@ *(heap[_a-z0-9]*)/?(\d*)`)
- heapSampleRE = regexp.MustCompile(`(-?\d+): *(-?\d+) *\[ *(\d+): *(\d+) *] @([ x0-9a-f]*)`)
-
- contentionSampleRE = regexp.MustCompile(`(\d+) *(\d+) @([ x0-9a-f]*)`)
-
- hexNumberRE = regexp.MustCompile(`0x[0-9a-f]+`)
-
- growthHeaderRE = regexp.MustCompile(`heap profile: *(\d+): *(\d+) *\[ *(\d+): *(\d+) *\] @ growthz`)
-
- fragmentationHeaderRE = regexp.MustCompile(`heap profile: *(\d+): *(\d+) *\[ *(\d+): *(\d+) *\] @ fragmentationz`)
-
- threadzStartRE = regexp.MustCompile(`--- threadz \d+ ---`)
- threadStartRE = regexp.MustCompile(`--- Thread ([[:xdigit:]]+) \(name: (.*)/(\d+)\) stack: ---`)
-
- procMapsRE = regexp.MustCompile(`([[:xdigit:]]+)-([[:xdigit:]]+)\s+([-rwxp]+)\s+([[:xdigit:]]+)\s+([[:xdigit:]]+):([[:xdigit:]]+)\s+([[:digit:]]+)\s*(\S+)?`)
-
- briefMapsRE = regexp.MustCompile(`\s*([[:xdigit:]]+)-([[:xdigit:]]+):\s*(\S+)(\s.*@)?([[:xdigit:]]+)?`)
-
- // LegacyHeapAllocated instructs the heapz parsers to use the
- // allocated memory stats instead of the default in-use memory. Note
- // that tcmalloc doesn't provide all allocated memory, only in-use
- // stats.
- LegacyHeapAllocated bool
-)
-
-func isSpaceOrComment(line string) bool {
- trimmed := strings.TrimSpace(line)
- return len(trimmed) == 0 || trimmed[0] == '#'
-}
-
-// parseGoCount parses a Go count profile (e.g., threadcreate or
-// goroutine) and returns a new Profile.
-func parseGoCount(b []byte) (*Profile, error) {
- r := bytes.NewBuffer(b)
-
- var line string
- var err error
- for {
- // Skip past comments and empty lines seeking a real header.
- line, err = r.ReadString('\n')
- if err != nil {
- return nil, err
- }
- if !isSpaceOrComment(line) {
- break
- }
- }
-
- m := countStartRE.FindStringSubmatch(line)
- if m == nil {
- return nil, errUnrecognized
- }
- profileType := m[1]
- p := &Profile{
- PeriodType: &ValueType{Type: profileType, Unit: "count"},
- Period: 1,
- SampleType: []*ValueType{{Type: profileType, Unit: "count"}},
- }
- locations := make(map[uint64]*Location)
- for {
- line, err = r.ReadString('\n')
- if err != nil {
- if err == io.EOF {
- break
- }
- return nil, err
- }
- if isSpaceOrComment(line) {
- continue
- }
- if strings.HasPrefix(line, "---") {
- break
- }
- m := countRE.FindStringSubmatch(line)
- if m == nil {
- return nil, errMalformed
- }
- n, err := strconv.ParseInt(m[1], 0, 64)
- if err != nil {
- return nil, errMalformed
- }
- fields := strings.Fields(m[2])
- locs := make([]*Location, 0, len(fields))
- for _, stk := range fields {
- addr, err := strconv.ParseUint(stk, 0, 64)
- if err != nil {
- return nil, errMalformed
- }
- // Adjust all frames by -1 to land on the call instruction.
- addr--
- loc := locations[addr]
- if loc == nil {
- loc = &Location{
- Address: addr,
- }
- locations[addr] = loc
- p.Location = append(p.Location, loc)
- }
- locs = append(locs, loc)
- }
- p.Sample = append(p.Sample, &Sample{
- Location: locs,
- Value: []int64{n},
- })
- }
-
- if err = parseAdditionalSections(strings.TrimSpace(line), r, p); err != nil {
- return nil, err
- }
- return p, nil
-}
-
-// remapLocationIDs ensures there is a location for each address
-// referenced by a sample, and remaps the samples to point to the new
-// location ids.
-func (p *Profile) remapLocationIDs() {
- seen := make(map[*Location]bool, len(p.Location))
- var locs []*Location
-
- for _, s := range p.Sample {
- for _, l := range s.Location {
- if seen[l] {
- continue
- }
- l.ID = uint64(len(locs) + 1)
- locs = append(locs, l)
- seen[l] = true
- }
- }
- p.Location = locs
-}
-
-func (p *Profile) remapFunctionIDs() {
- seen := make(map[*Function]bool, len(p.Function))
- var fns []*Function
-
- for _, l := range p.Location {
- for _, ln := range l.Line {
- fn := ln.Function
- if fn == nil || seen[fn] {
- continue
- }
- fn.ID = uint64(len(fns) + 1)
- fns = append(fns, fn)
- seen[fn] = true
- }
- }
- p.Function = fns
-}
-
-// remapMappingIDs matches location addresses with existing mappings
-// and updates them appropriately. This is O(N*M), if this ever shows
-// up as a bottleneck, evaluate sorting the mappings and doing a
-// binary search, which would make it O(N*log(M)).
-func (p *Profile) remapMappingIDs() {
- if len(p.Mapping) == 0 {
- return
- }
-
- // Some profile handlers will incorrectly set regions for the main
- // executable if its section is remapped. Fix them through heuristics.
-
- // Remove the initial mapping if named '/anon_hugepage' and has a
- // consecutive adjacent mapping.
- if m := p.Mapping[0]; strings.HasPrefix(m.File, "/anon_hugepage") {
- if len(p.Mapping) > 1 && m.Limit == p.Mapping[1].Start {
- p.Mapping = p.Mapping[1:]
- }
- }
-
- // Subtract the offset from the start of the main mapping if it
- // ends up at a recognizable start address.
- const expectedStart = 0x400000
- if m := p.Mapping[0]; m.Start-m.Offset == expectedStart {
- m.Start = expectedStart
- m.Offset = 0
- }
-
- for _, l := range p.Location {
- if a := l.Address; a != 0 {
- for _, m := range p.Mapping {
- if m.Start <= a && a < m.Limit {
- l.Mapping = m
- break
- }
- }
- }
- }
-
- // Reset all mapping IDs.
- for i, m := range p.Mapping {
- m.ID = uint64(i + 1)
- }
-}
-
-var cpuInts = []func([]byte) (uint64, []byte){
- get32l,
- get32b,
- get64l,
- get64b,
-}
-
-func get32l(b []byte) (uint64, []byte) {
- if len(b) < 4 {
- return 0, nil
- }
- return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24, b[4:]
-}
-
-func get32b(b []byte) (uint64, []byte) {
- if len(b) < 4 {
- return 0, nil
- }
- return uint64(b[3]) | uint64(b[2])<<8 | uint64(b[1])<<16 | uint64(b[0])<<24, b[4:]
-}
-
-func get64l(b []byte) (uint64, []byte) {
- if len(b) < 8 {
- return 0, nil
- }
- return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 | uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56, b[8:]
-}
-
-func get64b(b []byte) (uint64, []byte) {
- if len(b) < 8 {
- return 0, nil
- }
- return uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 | uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56, b[8:]
-}
-
-// ParseTracebacks parses a set of tracebacks and returns a newly
-// populated profile. It will accept any text file and generate a
-// Profile out of it with any hex addresses it can identify, including
-// a process map if it can recognize one. Each sample will include a
-// tag "source" with the addresses recognized in string format.
-func ParseTracebacks(b []byte) (*Profile, error) {
- r := bytes.NewBuffer(b)
-
- p := &Profile{
- PeriodType: &ValueType{Type: "trace", Unit: "count"},
- Period: 1,
- SampleType: []*ValueType{
- {Type: "trace", Unit: "count"},
- },
- }
-
- var sources []string
- var sloc []*Location
-
- locs := make(map[uint64]*Location)
- for {
- l, err := r.ReadString('\n')
- if err != nil {
- if err != io.EOF {
- return nil, err
- }
- if l == "" {
- break
- }
- }
- if sectionTrigger(l) == memoryMapSection {
- break
- }
- if s, addrs := extractHexAddresses(l); len(s) > 0 {
- for _, addr := range addrs {
- // Addresses from stack traces point to the next instruction after
- // each call. Adjust by -1 to land somewhere on the actual call.
- addr--
- loc := locs[addr]
- if locs[addr] == nil {
- loc = &Location{
- Address: addr,
- }
- p.Location = append(p.Location, loc)
- locs[addr] = loc
- }
- sloc = append(sloc, loc)
- }
-
- sources = append(sources, s...)
- } else {
- if len(sources) > 0 || len(sloc) > 0 {
- addTracebackSample(sloc, sources, p)
- sloc, sources = nil, nil
- }
- }
- }
-
- // Add final sample to save any leftover data.
- if len(sources) > 0 || len(sloc) > 0 {
- addTracebackSample(sloc, sources, p)
- }
-
- if err := p.ParseMemoryMap(r); err != nil {
- return nil, err
- }
- return p, nil
-}
-
-func addTracebackSample(l []*Location, s []string, p *Profile) {
- p.Sample = append(p.Sample,
- &Sample{
- Value: []int64{1},
- Location: l,
- Label: map[string][]string{"source": s},
- })
-}
-
-// parseCPU parses a profilez legacy profile and returns a newly
-// populated Profile.
-//
-// The general format for profilez samples is a sequence of words in
-// binary format. The first words are a header with the following data:
-// 1st word -- 0
-// 2nd word -- 3
-// 3rd word -- 0 if a c++ application, 1 if a java application.
-// 4th word -- Sampling period (in microseconds).
-// 5th word -- Padding.
-func parseCPU(b []byte) (*Profile, error) {
- var parse func([]byte) (uint64, []byte)
- var n1, n2, n3, n4, n5 uint64
- for _, parse = range cpuInts {
- var tmp []byte
- n1, tmp = parse(b)
- n2, tmp = parse(tmp)
- n3, tmp = parse(tmp)
- n4, tmp = parse(tmp)
- n5, tmp = parse(tmp)
-
- if tmp != nil && n1 == 0 && n2 == 3 && n3 == 0 && n4 > 0 && n5 == 0 {
- b = tmp
- return cpuProfile(b, int64(n4), parse)
- }
- }
- return nil, errUnrecognized
-}
-
-// cpuProfile returns a new Profile from C++ profilez data.
-// b is the profile bytes after the header, period is the profiling
-// period, and parse is a function to parse 8-byte chunks from the
-// profile in its native endianness.
-func cpuProfile(b []byte, period int64, parse func(b []byte) (uint64, []byte)) (*Profile, error) {
- p := &Profile{
- Period: period * 1000,
- PeriodType: &ValueType{Type: "cpu", Unit: "nanoseconds"},
- SampleType: []*ValueType{
- {Type: "samples", Unit: "count"},
- {Type: "cpu", Unit: "nanoseconds"},
- },
- }
- var err error
- if b, _, err = parseCPUSamples(b, parse, true, p); err != nil {
- return nil, err
- }
-
- // If all samples have the same second-to-the-bottom frame, it
- // strongly suggests that it is an uninteresting artifact of
- // measurement -- a stack frame pushed by the signal handler. The
- // bottom frame is always correct as it is picked up from the signal
- // structure, not the stack. Check if this is the case and if so,
- // remove.
- if len(p.Sample) > 1 && len(p.Sample[0].Location) > 1 {
- allSame := true
- id1 := p.Sample[0].Location[1].Address
- for _, s := range p.Sample {
- if len(s.Location) < 2 || id1 != s.Location[1].Address {
- allSame = false
- break
- }
- }
- if allSame {
- for _, s := range p.Sample {
- s.Location = append(s.Location[:1], s.Location[2:]...)
- }
- }
- }
-
- if err := p.ParseMemoryMap(bytes.NewBuffer(b)); err != nil {
- return nil, err
- }
- return p, nil
-}
-
-// parseCPUSamples parses a collection of profilez samples from a
-// profile.
-//
-// profilez samples are a repeated sequence of stack frames of the
-// form:
-// 1st word -- The number of times this stack was encountered.
-// 2nd word -- The size of the stack (StackSize).
-// 3rd word -- The first address on the stack.
-// ...
-// StackSize + 2 -- The last address on the stack
-// The last stack trace is of the form:
-// 1st word -- 0
-// 2nd word -- 1
-// 3rd word -- 0
-//
-// Addresses from stack traces may point to the next instruction after
-// each call. Optionally adjust by -1 to land somewhere on the actual
-// call (except for the leaf, which is not a call).
-func parseCPUSamples(b []byte, parse func(b []byte) (uint64, []byte), adjust bool, p *Profile) ([]byte, map[uint64]*Location, error) {
- locs := make(map[uint64]*Location)
- for len(b) > 0 {
- var count, nstk uint64
- count, b = parse(b)
- nstk, b = parse(b)
- if b == nil || nstk > uint64(len(b)/4) {
- return nil, nil, errUnrecognized
- }
- var sloc []*Location
- addrs := make([]uint64, nstk)
- for i := 0; i < int(nstk); i++ {
- addrs[i], b = parse(b)
- }
-
- if count == 0 && nstk == 1 && addrs[0] == 0 {
- // End of data marker
- break
- }
- for i, addr := range addrs {
- if adjust && i > 0 {
- addr--
- }
- loc := locs[addr]
- if loc == nil {
- loc = &Location{
- Address: addr,
- }
- locs[addr] = loc
- p.Location = append(p.Location, loc)
- }
- sloc = append(sloc, loc)
- }
- p.Sample = append(p.Sample,
- &Sample{
- Value: []int64{int64(count), int64(count) * p.Period},
- Location: sloc,
- })
- }
- // Reached the end without finding the EOD marker.
- return b, locs, nil
-}
-
-// parseHeap parses a heapz legacy or a growthz profile and
-// returns a newly populated Profile.
-func parseHeap(b []byte) (p *Profile, err error) {
- r := bytes.NewBuffer(b)
- l, err := r.ReadString('\n')
- if err != nil {
- return nil, errUnrecognized
- }
-
- sampling := ""
-
- if header := heapHeaderRE.FindStringSubmatch(l); header != nil {
- p = &Profile{
- SampleType: []*ValueType{
- {Type: "objects", Unit: "count"},
- {Type: "space", Unit: "bytes"},
- },
- PeriodType: &ValueType{Type: "objects", Unit: "bytes"},
- }
-
- var period int64
- if len(header[6]) > 0 {
- if period, err = strconv.ParseInt(header[6], 10, 64); err != nil {
- return nil, errUnrecognized
- }
- }
-
- switch header[5] {
- case "heapz_v2", "heap_v2":
- sampling, p.Period = "v2", period
- case "heapprofile":
- sampling, p.Period = "", 1
- case "heap":
- sampling, p.Period = "v2", period/2
- default:
- return nil, errUnrecognized
- }
- } else if header = growthHeaderRE.FindStringSubmatch(l); header != nil {
- p = &Profile{
- SampleType: []*ValueType{
- {Type: "objects", Unit: "count"},
- {Type: "space", Unit: "bytes"},
- },
- PeriodType: &ValueType{Type: "heapgrowth", Unit: "count"},
- Period: 1,
- }
- } else if header = fragmentationHeaderRE.FindStringSubmatch(l); header != nil {
- p = &Profile{
- SampleType: []*ValueType{
- {Type: "objects", Unit: "count"},
- {Type: "space", Unit: "bytes"},
- },
- PeriodType: &ValueType{Type: "allocations", Unit: "count"},
- Period: 1,
- }
- } else {
- return nil, errUnrecognized
- }
-
- if LegacyHeapAllocated {
- for _, st := range p.SampleType {
- st.Type = "alloc_" + st.Type
- }
- } else {
- for _, st := range p.SampleType {
- st.Type = "inuse_" + st.Type
- }
- }
-
- locs := make(map[uint64]*Location)
- for {
- l, err = r.ReadString('\n')
- if err != nil {
- if err != io.EOF {
- return nil, err
- }
-
- if l == "" {
- break
- }
- }
-
- if isSpaceOrComment(l) {
- continue
- }
- l = strings.TrimSpace(l)
-
- if sectionTrigger(l) != unrecognizedSection {
- break
- }
-
- value, blocksize, addrs, err := parseHeapSample(l, p.Period, sampling)
- if err != nil {
- return nil, err
- }
- var sloc []*Location
- for _, addr := range addrs {
- // Addresses from stack traces point to the next instruction after
- // each call. Adjust by -1 to land somewhere on the actual call.
- addr--
- loc := locs[addr]
- if locs[addr] == nil {
- loc = &Location{
- Address: addr,
- }
- p.Location = append(p.Location, loc)
- locs[addr] = loc
- }
- sloc = append(sloc, loc)
- }
-
- p.Sample = append(p.Sample, &Sample{
- Value: value,
- Location: sloc,
- NumLabel: map[string][]int64{"bytes": {blocksize}},
- })
- }
-
- if err = parseAdditionalSections(l, r, p); err != nil {
- return nil, err
- }
- return p, nil
-}
-
-// parseHeapSample parses a single row from a heap profile into a new Sample.
-func parseHeapSample(line string, rate int64, sampling string) (value []int64, blocksize int64, addrs []uint64, err error) {
- sampleData := heapSampleRE.FindStringSubmatch(line)
- if len(sampleData) != 6 {
- return value, blocksize, addrs, fmt.Errorf("unexpected number of sample values: got %d, want 6", len(sampleData))
- }
-
- // Use first two values by default; tcmalloc sampling generates the
- // same value for both, only the older heap-profile collect separate
- // stats for in-use and allocated objects.
- valueIndex := 1
- if LegacyHeapAllocated {
- valueIndex = 3
- }
-
- var v1, v2 int64
- if v1, err = strconv.ParseInt(sampleData[valueIndex], 10, 64); err != nil {
- return value, blocksize, addrs, fmt.Errorf("malformed sample: %s: %v", line, err)
- }
- if v2, err = strconv.ParseInt(sampleData[valueIndex+1], 10, 64); err != nil {
- return value, blocksize, addrs, fmt.Errorf("malformed sample: %s: %v", line, err)
- }
-
- if v1 == 0 {
- if v2 != 0 {
- return value, blocksize, addrs, fmt.Errorf("allocation count was 0 but allocation bytes was %d", v2)
- }
- } else {
- blocksize = v2 / v1
- if sampling == "v2" {
- v1, v2 = scaleHeapSample(v1, v2, rate)
- }
- }
-
- value = []int64{v1, v2}
- addrs = parseHexAddresses(sampleData[5])
-
- return value, blocksize, addrs, nil
-}
-
-// extractHexAddresses extracts hex numbers from a string and returns
-// them, together with their numeric value, in a slice.
-func extractHexAddresses(s string) ([]string, []uint64) {
- hexStrings := hexNumberRE.FindAllString(s, -1)
- var ids []uint64
- for _, s := range hexStrings {
- if id, err := strconv.ParseUint(s, 0, 64); err == nil {
- ids = append(ids, id)
- } else {
- // Do not expect any parsing failures due to the regexp matching.
- panic("failed to parse hex value:" + s)
- }
- }
- return hexStrings, ids
-}
-
-// parseHexAddresses parses hex numbers from a string and returns them
-// in a slice.
-func parseHexAddresses(s string) []uint64 {
- _, ids := extractHexAddresses(s)
- return ids
-}
-
-// scaleHeapSample adjusts the data from a heapz Sample to
-// account for its probability of appearing in the collected
-// data. heapz profiles are a sampling of the memory allocations
-// requests in a program. We estimate the unsampled value by dividing
-// each collected sample by its probability of appearing in the
-// profile. heapz v2 profiles rely on a poisson process to determine
-// which samples to collect, based on the desired average collection
-// rate R. The probability of a sample of size S to appear in that
-// profile is 1-exp(-S/R).
-func scaleHeapSample(count, size, rate int64) (int64, int64) {
- if count == 0 || size == 0 {
- return 0, 0
- }
-
- if rate <= 1 {
- // if rate==1 all samples were collected so no adjustment is needed.
- // if rate<1 treat as unknown and skip scaling.
- return count, size
- }
-
- avgSize := float64(size) / float64(count)
- scale := 1 / (1 - math.Exp(-avgSize/float64(rate)))
-
- return int64(float64(count) * scale), int64(float64(size) * scale)
-}
-
-// parseContention parses a contentionz profile and returns a newly
-// populated Profile.
-func parseContention(b []byte) (p *Profile, err error) {
- r := bytes.NewBuffer(b)
- l, err := r.ReadString('\n')
- if err != nil {
- return nil, errUnrecognized
- }
-
- if !strings.HasPrefix(l, "--- contention") {
- return nil, errUnrecognized
- }
-
- p = &Profile{
- PeriodType: &ValueType{Type: "contentions", Unit: "count"},
- Period: 1,
- SampleType: []*ValueType{
- {Type: "contentions", Unit: "count"},
- {Type: "delay", Unit: "nanoseconds"},
- },
- }
-
- var cpuHz int64
- // Parse text of the form "attribute = value" before the samples.
- const delimiter = "="
- for {
- l, err = r.ReadString('\n')
- if err != nil {
- if err != io.EOF {
- return nil, err
- }
-
- if l == "" {
- break
- }
- }
-
- if l = strings.TrimSpace(l); l == "" {
- continue
- }
-
- if strings.HasPrefix(l, "---") {
- break
- }
-
- attr := strings.SplitN(l, delimiter, 2)
- if len(attr) != 2 {
- break
- }
- key, val := strings.TrimSpace(attr[0]), strings.TrimSpace(attr[1])
- var err error
- switch key {
- case "cycles/second":
- if cpuHz, err = strconv.ParseInt(val, 0, 64); err != nil {
- return nil, errUnrecognized
- }
- case "sampling period":
- if p.Period, err = strconv.ParseInt(val, 0, 64); err != nil {
- return nil, errUnrecognized
- }
- case "ms since reset":
- ms, err := strconv.ParseInt(val, 0, 64)
- if err != nil {
- return nil, errUnrecognized
- }
- p.DurationNanos = ms * 1000 * 1000
- case "format":
- // CPP contentionz profiles don't have format.
- return nil, errUnrecognized
- case "resolution":
- // CPP contentionz profiles don't have resolution.
- return nil, errUnrecognized
- case "discarded samples":
- default:
- return nil, errUnrecognized
- }
- }
-
- locs := make(map[uint64]*Location)
- for {
- if l = strings.TrimSpace(l); strings.HasPrefix(l, "---") {
- break
- }
- value, addrs, err := parseContentionSample(l, p.Period, cpuHz)
- if err != nil {
- return nil, err
- }
- var sloc []*Location
- for _, addr := range addrs {
- // Addresses from stack traces point to the next instruction after
- // each call. Adjust by -1 to land somewhere on the actual call.
- addr--
- loc := locs[addr]
- if locs[addr] == nil {
- loc = &Location{
- Address: addr,
- }
- p.Location = append(p.Location, loc)
- locs[addr] = loc
- }
- sloc = append(sloc, loc)
- }
- p.Sample = append(p.Sample, &Sample{
- Value: value,
- Location: sloc,
- })
-
- if l, err = r.ReadString('\n'); err != nil {
- if err != io.EOF {
- return nil, err
- }
- if l == "" {
- break
- }
- }
- }
-
- if err = parseAdditionalSections(l, r, p); err != nil {
- return nil, err
- }
-
- return p, nil
-}
-
-// parseContentionSample parses a single row from a contention profile
-// into a new Sample.
-func parseContentionSample(line string, period, cpuHz int64) (value []int64, addrs []uint64, err error) {
- sampleData := contentionSampleRE.FindStringSubmatch(line)
- if sampleData == nil {
- return value, addrs, errUnrecognized
- }
-
- v1, err := strconv.ParseInt(sampleData[1], 10, 64)
- if err != nil {
- return value, addrs, fmt.Errorf("malformed sample: %s: %v", line, err)
- }
- v2, err := strconv.ParseInt(sampleData[2], 10, 64)
- if err != nil {
- return value, addrs, fmt.Errorf("malformed sample: %s: %v", line, err)
- }
-
- // Unsample values if period and cpuHz are available.
- // - Delays are scaled to cycles and then to nanoseconds.
- // - Contentions are scaled to cycles.
- if period > 0 {
- if cpuHz > 0 {
- cpuGHz := float64(cpuHz) / 1e9
- v1 = int64(float64(v1) * float64(period) / cpuGHz)
- }
- v2 = v2 * period
- }
-
- value = []int64{v2, v1}
- addrs = parseHexAddresses(sampleData[3])
-
- return value, addrs, nil
-}
-
-// parseThread parses a Threadz profile and returns a new Profile.
-func parseThread(b []byte) (*Profile, error) {
- r := bytes.NewBuffer(b)
-
- var line string
- var err error
- for {
- // Skip past comments and empty lines seeking a real header.
- line, err = r.ReadString('\n')
- if err != nil {
- return nil, err
- }
- if !isSpaceOrComment(line) {
- break
- }
- }
-
- if m := threadzStartRE.FindStringSubmatch(line); m != nil {
- // Advance over initial comments until first stack trace.
- for {
- line, err = r.ReadString('\n')
- if err != nil {
- if err != io.EOF {
- return nil, err
- }
-
- if line == "" {
- break
- }
- }
- if sectionTrigger(line) != unrecognizedSection || line[0] == '-' {
- break
- }
- }
- } else if t := threadStartRE.FindStringSubmatch(line); len(t) != 4 {
- return nil, errUnrecognized
- }
-
- p := &Profile{
- SampleType: []*ValueType{{Type: "thread", Unit: "count"}},
- PeriodType: &ValueType{Type: "thread", Unit: "count"},
- Period: 1,
- }
-
- locs := make(map[uint64]*Location)
- // Recognize each thread and populate profile samples.
- for sectionTrigger(line) == unrecognizedSection {
- if strings.HasPrefix(line, "---- no stack trace for") {
- line = ""
- break
- }
- if t := threadStartRE.FindStringSubmatch(line); len(t) != 4 {
- return nil, errUnrecognized
- }
-
- var addrs []uint64
- line, addrs, err = parseThreadSample(r)
- if err != nil {
- return nil, errUnrecognized
- }
- if len(addrs) == 0 {
- // We got a --same as previous threads--. Bump counters.
- if len(p.Sample) > 0 {
- s := p.Sample[len(p.Sample)-1]
- s.Value[0]++
- }
- continue
- }
-
- var sloc []*Location
- for _, addr := range addrs {
- // Addresses from stack traces point to the next instruction after
- // each call. Adjust by -1 to land somewhere on the actual call.
- addr--
- loc := locs[addr]
- if locs[addr] == nil {
- loc = &Location{
- Address: addr,
- }
- p.Location = append(p.Location, loc)
- locs[addr] = loc
- }
- sloc = append(sloc, loc)
- }
-
- p.Sample = append(p.Sample, &Sample{
- Value: []int64{1},
- Location: sloc,
- })
- }
-
- if err = parseAdditionalSections(line, r, p); err != nil {
- return nil, err
- }
-
- return p, nil
-}
-
-// parseThreadSample parses a symbolized or unsymbolized stack trace.
-// Returns the first line after the traceback, the sample (or nil if
-// it hits a 'same-as-previous' marker) and an error.
-func parseThreadSample(b *bytes.Buffer) (nextl string, addrs []uint64, err error) {
- var l string
- sameAsPrevious := false
- for {
- if l, err = b.ReadString('\n'); err != nil {
- if err != io.EOF {
- return "", nil, err
- }
- if l == "" {
- break
- }
- }
- if l = strings.TrimSpace(l); l == "" {
- continue
- }
-
- if strings.HasPrefix(l, "---") {
- break
- }
- if strings.Contains(l, "same as previous thread") {
- sameAsPrevious = true
- continue
- }
-
- addrs = append(addrs, parseHexAddresses(l)...)
- }
-
- if sameAsPrevious {
- return l, nil, nil
- }
- return l, addrs, nil
-}
-
-// parseAdditionalSections parses any additional sections in the
-// profile, ignoring any unrecognized sections.
-func parseAdditionalSections(l string, b *bytes.Buffer, p *Profile) (err error) {
- for {
- if sectionTrigger(l) == memoryMapSection {
- break
- }
- // Ignore any unrecognized sections.
- if l, err := b.ReadString('\n'); err != nil {
- if err != io.EOF {
- return err
- }
- if l == "" {
- break
- }
- }
- }
- return p.ParseMemoryMap(b)
-}
-
-// ParseMemoryMap parses a memory map in the format of
-// /proc/self/maps, and overrides the mappings in the current profile.
-// It renumbers the samples and locations in the profile correspondingly.
-func (p *Profile) ParseMemoryMap(rd io.Reader) error {
- b := bufio.NewReader(rd)
-
- var attrs []string
- var r *strings.Replacer
- const delimiter = "="
- for {
- l, err := b.ReadString('\n')
- if err != nil {
- if err != io.EOF {
- return err
- }
- if l == "" {
- break
- }
- }
- if l = strings.TrimSpace(l); l == "" {
- continue
- }
-
- if r != nil {
- l = r.Replace(l)
- }
- m, err := parseMappingEntry(l)
- if err != nil {
- if err == errUnrecognized {
- // Recognize assignments of the form: attr=value, and replace
- // $attr with value on subsequent mappings.
- if attr := strings.SplitN(l, delimiter, 2); len(attr) == 2 {
- attrs = append(attrs, "$"+strings.TrimSpace(attr[0]), strings.TrimSpace(attr[1]))
- r = strings.NewReplacer(attrs...)
- }
- // Ignore any unrecognized entries
- continue
- }
- return err
- }
- if m == nil || (m.File == "" && len(p.Mapping) != 0) {
- // In some cases the first entry may include the address range
- // but not the name of the file. It should be followed by
- // another entry with the name.
- continue
- }
- if len(p.Mapping) == 1 && p.Mapping[0].File == "" {
- // Update the name if this is the entry following that empty one.
- p.Mapping[0].File = m.File
- continue
- }
- p.Mapping = append(p.Mapping, m)
- }
- p.remapLocationIDs()
- p.remapFunctionIDs()
- p.remapMappingIDs()
- return nil
-}
-
-func parseMappingEntry(l string) (*Mapping, error) {
- mapping := &Mapping{}
- var err error
- if me := procMapsRE.FindStringSubmatch(l); len(me) == 9 {
- if !strings.Contains(me[3], "x") {
- // Skip non-executable entries.
- return nil, nil
- }
- if mapping.Start, err = strconv.ParseUint(me[1], 16, 64); err != nil {
- return nil, errUnrecognized
- }
- if mapping.Limit, err = strconv.ParseUint(me[2], 16, 64); err != nil {
- return nil, errUnrecognized
- }
- if me[4] != "" {
- if mapping.Offset, err = strconv.ParseUint(me[4], 16, 64); err != nil {
- return nil, errUnrecognized
- }
- }
- mapping.File = me[8]
- return mapping, nil
- }
-
- if me := briefMapsRE.FindStringSubmatch(l); len(me) == 6 {
- if mapping.Start, err = strconv.ParseUint(me[1], 16, 64); err != nil {
- return nil, errUnrecognized
- }
- if mapping.Limit, err = strconv.ParseUint(me[2], 16, 64); err != nil {
- return nil, errUnrecognized
- }
- mapping.File = me[3]
- if me[5] != "" {
- if mapping.Offset, err = strconv.ParseUint(me[5], 16, 64); err != nil {
- return nil, errUnrecognized
- }
- }
- return mapping, nil
- }
-
- return nil, errUnrecognized
-}
-
-type sectionType int
-
-const (
- unrecognizedSection sectionType = iota
- memoryMapSection
-)
-
-var memoryMapTriggers = []string{
- "--- Memory map: ---",
- "MAPPED_LIBRARIES:",
-}
-
-func sectionTrigger(line string) sectionType {
- for _, trigger := range memoryMapTriggers {
- if strings.Contains(line, trigger) {
- return memoryMapSection
- }
- }
- return unrecognizedSection
-}
-
-func (p *Profile) addLegacyFrameInfo() {
- switch {
- case isProfileType(p, heapzSampleTypes) ||
- isProfileType(p, heapzInUseSampleTypes) ||
- isProfileType(p, heapzAllocSampleTypes):
- p.DropFrames, p.KeepFrames = allocRxStr, allocSkipRxStr
- case isProfileType(p, contentionzSampleTypes):
- p.DropFrames, p.KeepFrames = lockRxStr, ""
- default:
- p.DropFrames, p.KeepFrames = cpuProfilerRxStr, ""
- }
-}
-
-var heapzSampleTypes = []string{"allocations", "size"} // early Go pprof profiles
-var heapzInUseSampleTypes = []string{"inuse_objects", "inuse_space"}
-var heapzAllocSampleTypes = []string{"alloc_objects", "alloc_space"}
-var contentionzSampleTypes = []string{"contentions", "delay"}
-
-func isProfileType(p *Profile, t []string) bool {
- st := p.SampleType
- if len(st) != len(t) {
- return false
- }
-
- for i := range st {
- if st[i].Type != t[i] {
- return false
- }
- }
- return true
-}
-
-var allocRxStr = strings.Join([]string{
- // POSIX entry points.
- `calloc`,
- `cfree`,
- `malloc`,
- `free`,
- `memalign`,
- `do_memalign`,
- `(__)?posix_memalign`,
- `pvalloc`,
- `valloc`,
- `realloc`,
-
- // TC malloc.
- `tcmalloc::.*`,
- `tc_calloc`,
- `tc_cfree`,
- `tc_malloc`,
- `tc_free`,
- `tc_memalign`,
- `tc_posix_memalign`,
- `tc_pvalloc`,
- `tc_valloc`,
- `tc_realloc`,
- `tc_new`,
- `tc_delete`,
- `tc_newarray`,
- `tc_deletearray`,
- `tc_new_nothrow`,
- `tc_newarray_nothrow`,
-
- // Memory-allocation routines on OS X.
- `malloc_zone_malloc`,
- `malloc_zone_calloc`,
- `malloc_zone_valloc`,
- `malloc_zone_realloc`,
- `malloc_zone_memalign`,
- `malloc_zone_free`,
-
- // Go runtime
- `runtime\..*`,
-
- // Other misc. memory allocation routines
- `BaseArena::.*`,
- `(::)?do_malloc_no_errno`,
- `(::)?do_malloc_pages`,
- `(::)?do_malloc`,
- `DoSampledAllocation`,
- `MallocedMemBlock::MallocedMemBlock`,
- `_M_allocate`,
- `__builtin_(vec_)?delete`,
- `__builtin_(vec_)?new`,
- `__gnu_cxx::new_allocator::allocate`,
- `__libc_malloc`,
- `__malloc_alloc_template::allocate`,
- `allocate`,
- `cpp_alloc`,
- `operator new(\[\])?`,
- `simple_alloc::allocate`,
-}, `|`)
-
-var allocSkipRxStr = strings.Join([]string{
- // Preserve Go runtime frames that appear in the middle/bottom of
- // the stack.
- `runtime\.panic`,
-}, `|`)
-
-var cpuProfilerRxStr = strings.Join([]string{
- `ProfileData::Add`,
- `ProfileData::prof_handler`,
- `CpuProfiler::prof_handler`,
- `__pthread_sighandler`,
- `__restore`,
-}, `|`)
-
-var lockRxStr = strings.Join([]string{
- `RecordLockProfileData`,
- `(base::)?RecordLockProfileData.*`,
- `(base::)?SubmitMutexProfileData.*`,
- `(base::)?SubmitSpinLockProfileData.*`,
- `(Mutex::)?AwaitCommon.*`,
- `(Mutex::)?Unlock.*`,
- `(Mutex::)?UnlockSlow.*`,
- `(Mutex::)?ReaderUnlock.*`,
- `(MutexLock::)?~MutexLock.*`,
- `(SpinLock::)?Unlock.*`,
- `(SpinLock::)?SlowUnlock.*`,
- `(SpinLockHolder::)?~SpinLockHolder.*`,
-}, `|`)
diff --git a/src/cmd/internal/pprof/profile/profile_test.go b/src/cmd/internal/pprof/profile/profile_test.go
deleted file mode 100644
index 09b11a4..0000000
--- a/src/cmd/internal/pprof/profile/profile_test.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.
-
-package profile
-
-import (
- "bytes"
- "testing"
-)
-
-func TestEmptyProfile(t *testing.T) {
- var buf bytes.Buffer
- p, err := Parse(&buf)
- if err != nil {
- t.Error("Want no error, got", err)
- }
- if p == nil {
- t.Fatal("Want a valid profile, got <nil>")
- }
- if !p.Empty() {
- t.Errorf("Profile should be empty, got %#v", p)
- }
-}
diff --git a/src/cmd/internal/pprof/report/report.go b/src/cmd/internal/pprof/report/report.go
deleted file mode 100644
index b11ad2a..0000000
--- a/src/cmd/internal/pprof/report/report.go
+++ /dev/null
@@ -1,1684 +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/internal/pprof/plugin"
- "cmd/internal/pprof/profile"
-)
-
-// Generate generates a report as directed by the Report.
-func Generate(w io.Writer, rpt *Report, obj plugin.ObjTool) error {
- o := rpt.options
-
- switch o.OutputFormat {
- case Dot:
- return printDOT(w, rpt)
- case Tree:
- return printTree(w, rpt)
- case Text:
- return printText(w, rpt)
- case Raw:
- fmt.Fprint(w, rpt.prof.String())
- return nil
- case Tags:
- return printTags(w, rpt)
- case Proto:
- return rpt.prof.Write(w)
- case Dis:
- return printAssembly(w, rpt, obj)
- case List:
- return printSource(w, rpt)
- case WebList:
- return printWebSource(w, rpt, obj)
- case Callgrind:
- return printCallgrind(w, rpt)
- }
- return fmt.Errorf("unexpected output format")
-}
-
-// printAssembly prints an annotated assembly listing.
-func printAssembly(w io.Writer, rpt *Report, obj plugin.ObjTool) error {
- g, err := newGraph(rpt)
- if err != nil {
- return err
- }
-
- o := rpt.options
- prof := rpt.prof
-
- // If the regexp source can be parsed as an address, also match
- // functions that land on that address.
- var address *uint64
- if hex, err := strconv.ParseUint(o.Symbol.String(), 0, 64); err == nil {
- address = &hex
- }
-
- fmt.Fprintln(w, "Total:", rpt.formatValue(rpt.total))
- symbols := symbolsFromBinaries(prof, g, o.Symbol, address, obj)
- symNodes := nodesPerSymbol(g.ns, symbols)
- // Sort function names for printing.
- var syms objSymbols
- for s := range symNodes {
- syms = append(syms, s)
- }
- sort.Sort(syms)
-
- // Correlate the symbols from the binary with the profile samples.
- for _, s := range syms {
- sns := symNodes[s]
-
- // Gather samples for this symbol.
- flatSum, cumSum := sumNodes(sns)
-
- // Get the function assembly.
- insns, err := obj.Disasm(s.sym.File, s.sym.Start, s.sym.End)
- if err != nil {
- return err
- }
-
- ns := annotateAssembly(insns, sns, s.base)
-
- fmt.Fprintf(w, "ROUTINE ======================== %s\n", s.sym.Name[0])
- for _, name := range s.sym.Name[1:] {
- fmt.Fprintf(w, " AKA ======================== %s\n", name)
- }
- fmt.Fprintf(w, "%10s %10s (flat, cum) %s of Total\n",
- rpt.formatValue(flatSum), rpt.formatValue(cumSum),
- percentage(cumSum, rpt.total))
-
- for _, n := range ns {
- fmt.Fprintf(w, "%10s %10s %10x: %s\n", valueOrDot(n.flat, rpt), valueOrDot(n.cum, rpt), n.info.address, n.info.name)
- }
- }
- return nil
-}
-
-// symbolsFromBinaries examines the binaries listed on the profile
-// that have associated samples, and identifies symbols matching rx.
-func symbolsFromBinaries(prof *profile.Profile, g graph, rx *regexp.Regexp, address *uint64, obj plugin.ObjTool) []*objSymbol {
- hasSamples := make(map[string]bool)
- // Only examine mappings that have samples that match the
- // regexp. This is an optimization to speed up pprof.
- for _, n := range g.ns {
- if name := n.info.prettyName(); rx.MatchString(name) && n.info.objfile != "" {
- hasSamples[n.info.objfile] = true
- }
- }
-
- // Walk all mappings looking for matching functions with samples.
- var objSyms []*objSymbol
- for _, m := range prof.Mapping {
- if !hasSamples[filepath.Base(m.File)] {
- if address == nil || !(m.Start <= *address && *address <= m.Limit) {
- continue
- }
- }
-
- f, err := obj.Open(m.File, m.Start)
- if err != nil {
- fmt.Printf("%v\n", err)
- continue
- }
-
- // Find symbols in this binary matching the user regexp.
- var addr uint64
- if address != nil {
- addr = *address
- }
- msyms, err := f.Symbols(rx, addr)
- base := f.Base()
- f.Close()
- if err != nil {
- continue
- }
- for _, ms := range msyms {
- objSyms = append(objSyms,
- &objSymbol{
- sym: ms,
- base: base,
- },
- )
- }
- }
-
- return objSyms
-}
-
-// objSym represents a symbol identified from a binary. It includes
-// the SymbolInfo from the disasm package and the base that must be
-// added to correspond to sample addresses
-type objSymbol struct {
- sym *plugin.Sym
- base uint64
-}
-
-// objSymbols is a wrapper type to enable sorting of []*objSymbol.
-type objSymbols []*objSymbol
-
-func (o objSymbols) Len() int {
- return len(o)
-}
-
-func (o objSymbols) Less(i, j int) bool {
- if namei, namej := o[i].sym.Name[0], o[j].sym.Name[0]; namei != namej {
- return namei < namej
- }
- return o[i].sym.Start < o[j].sym.Start
-}
-
-func (o objSymbols) Swap(i, j int) {
- o[i], o[j] = o[j], o[i]
-}
-
-// nodesPerSymbol classifies nodes into a group of symbols.
-func nodesPerSymbol(ns nodes, symbols []*objSymbol) map[*objSymbol]nodes {
- symNodes := make(map[*objSymbol]nodes)
- for _, s := range symbols {
- // Gather samples for this symbol.
- for _, n := range ns {
- address := n.info.address - s.base
- if address >= s.sym.Start && address < s.sym.End {
- symNodes[s] = append(symNodes[s], n)
- }
- }
- }
- return symNodes
-}
-
-// annotateAssembly annotates a set of assembly instructions with a
-// set of samples. It returns a set of nodes to display. base is an
-// offset to adjust the sample addresses.
-func annotateAssembly(insns []plugin.Inst, samples nodes, base uint64) nodes {
- // Add end marker to simplify printing loop.
- insns = append(insns, plugin.Inst{
- Addr: ^uint64(0),
- })
-
- // Ensure samples are sorted by address.
- samples.sort(addressOrder)
-
- var s int
- var asm nodes
- for ix, in := range insns[:len(insns)-1] {
- n := node{
- info: nodeInfo{
- address: in.Addr,
- name: in.Text,
- file: trimPath(in.File),
- lineno: in.Line,
- },
- }
-
- // Sum all the samples until the next instruction (to account
- // for samples attributed to the middle of an instruction).
- for next := insns[ix+1].Addr; s < len(samples) && samples[s].info.address-base < next; s++ {
- n.flat += samples[s].flat
- n.cum += samples[s].cum
- if samples[s].info.file != "" {
- n.info.file = trimPath(samples[s].info.file)
- n.info.lineno = samples[s].info.lineno
- }
- }
- asm = append(asm, &n)
- }
-
- return asm
-}
-
-// valueOrDot formats a value according to a report, intercepting zero
-// values.
-func valueOrDot(value int64, rpt *Report) string {
- if value == 0 {
- return "."
- }
- return rpt.formatValue(value)
-}
-
-// printTags collects all tags referenced in the profile and prints
-// them in a sorted table.
-func printTags(w io.Writer, rpt *Report) error {
- p := rpt.prof
-
- // Hashtable to keep accumulate tags as key,value,count.
- tagMap := make(map[string]map[string]int64)
- for _, s := range p.Sample {
- for key, vals := range s.Label {
- for _, val := range vals {
- if valueMap, ok := tagMap[key]; ok {
- valueMap[val] = valueMap[val] + s.Value[0]
- continue
- }
- valueMap := make(map[string]int64)
- valueMap[val] = s.Value[0]
- tagMap[key] = valueMap
- }
- }
- for key, vals := range s.NumLabel {
- for _, nval := range vals {
- val := scaledValueLabel(nval, key, "auto")
- if valueMap, ok := tagMap[key]; ok {
- valueMap[val] = valueMap[val] + s.Value[0]
- continue
- }
- valueMap := make(map[string]int64)
- valueMap[val] = s.Value[0]
- tagMap[key] = valueMap
- }
- }
- }
-
- tagKeys := make(tags, 0, len(tagMap))
- for key := range tagMap {
- tagKeys = append(tagKeys, &tag{name: key})
- }
- sort.Sort(tagKeys)
-
- for _, tagKey := range tagKeys {
- var total int64
- key := tagKey.name
- tags := make(tags, 0, len(tagMap[key]))
- for t, c := range tagMap[key] {
- total += c
- tags = append(tags, &tag{name: t, weight: c})
- }
-
- sort.Sort(tags)
- fmt.Fprintf(w, "%s: Total %d\n", key, total)
- for _, t := range tags {
- if total > 0 {
- fmt.Fprintf(w, " %8d (%s): %s\n", t.weight,
- percentage(t.weight, total), t.name)
- } else {
- fmt.Fprintf(w, " %8d: %s\n", t.weight, t.name)
- }
- }
- fmt.Fprintln(w)
- }
- return nil
-}
-
-// printText prints a flat text report for a profile.
-func printText(w io.Writer, rpt *Report) error {
- g, err := newGraph(rpt)
- if err != nil {
- return err
- }
-
- origCount, droppedNodes, _ := g.preprocess(rpt)
- fmt.Fprintln(w, strings.Join(legendDetailLabels(rpt, g, origCount, droppedNodes, 0), "\n"))
-
- fmt.Fprintf(w, "%10s %5s%% %5s%% %10s %5s%%\n",
- "flat", "flat", "sum", "cum", "cum")
-
- var flatSum int64
- for _, n := range g.ns {
- name, flat, cum := n.info.prettyName(), n.flat, n.cum
-
- flatSum += flat
- fmt.Fprintf(w, "%10s %s %s %10s %s %s\n",
- rpt.formatValue(flat),
- percentage(flat, rpt.total),
- percentage(flatSum, rpt.total),
- rpt.formatValue(cum),
- percentage(cum, rpt.total),
- name)
- }
- return nil
-}
-
-// printCallgrind prints a graph for a profile on callgrind format.
-func printCallgrind(w io.Writer, rpt *Report) error {
- g, err := newGraph(rpt)
- if err != nil {
- return err
- }
-
- o := rpt.options
- rpt.options.NodeFraction = 0
- rpt.options.EdgeFraction = 0
- rpt.options.NodeCount = 0
-
- g.preprocess(rpt)
-
- fmt.Fprintln(w, "events:", o.SampleType+"("+o.OutputUnit+")")
-
- files := make(map[string]int)
- names := make(map[string]int)
- for _, n := range g.ns {
- fmt.Fprintln(w, "fl="+callgrindName(files, n.info.file))
- fmt.Fprintln(w, "fn="+callgrindName(names, n.info.name))
- sv, _ := ScaleValue(n.flat, o.SampleUnit, o.OutputUnit)
- fmt.Fprintf(w, "%d %d\n", n.info.lineno, int(sv))
-
- // Print outgoing edges.
- for _, out := range sortedEdges(n.out) {
- c, _ := ScaleValue(out.weight, o.SampleUnit, o.OutputUnit)
- count := fmt.Sprintf("%d", int(c))
- callee := out.dest
- fmt.Fprintln(w, "cfl="+callgrindName(files, callee.info.file))
- fmt.Fprintln(w, "cfn="+callgrindName(names, callee.info.name))
- fmt.Fprintln(w, "calls="+count, callee.info.lineno)
- fmt.Fprintln(w, n.info.lineno, count)
- }
- fmt.Fprintln(w)
- }
-
- return nil
-}
-
-// callgrindName implements the callgrind naming compression scheme.
-// For names not previously seen returns "(N) name", where N is a
-// unique index. For names previously seen returns "(N)" where N is
-// the index returned the first time.
-func callgrindName(names map[string]int, name string) string {
- if name == "" {
- return ""
- }
- if id, ok := names[name]; ok {
- return fmt.Sprintf("(%d)", id)
- }
- id := len(names) + 1
- names[name] = id
- return fmt.Sprintf("(%d) %s", id, name)
-}
-
-// printTree prints a tree-based report in text form.
-func printTree(w io.Writer, rpt *Report) error {
- const separator = "----------------------------------------------------------+-------------"
- const legend = " flat flat% sum% cum cum% calls calls% + context "
-
- g, err := newGraph(rpt)
- if err != nil {
- return err
- }
-
- origCount, droppedNodes, _ := g.preprocess(rpt)
- fmt.Fprintln(w, strings.Join(legendDetailLabels(rpt, g, origCount, droppedNodes, 0), "\n"))
-
- fmt.Fprintln(w, separator)
- fmt.Fprintln(w, legend)
- var flatSum int64
-
- rx := rpt.options.Symbol
- for _, n := range g.ns {
- name, flat, cum := n.info.prettyName(), n.flat, n.cum
-
- // Skip any entries that do not match the regexp (for the "peek" command).
- if rx != nil && !rx.MatchString(name) {
- continue
- }
-
- fmt.Fprintln(w, separator)
- // Print incoming edges.
- inEdges := sortedEdges(n.in)
- inSum := inEdges.sum()
- for _, in := range inEdges {
- fmt.Fprintf(w, "%50s %s | %s\n", rpt.formatValue(in.weight),
- percentage(in.weight, inSum), in.src.info.prettyName())
- }
-
- // Print current node.
- flatSum += flat
- fmt.Fprintf(w, "%10s %s %s %10s %s | %s\n",
- rpt.formatValue(flat),
- percentage(flat, rpt.total),
- percentage(flatSum, rpt.total),
- rpt.formatValue(cum),
- percentage(cum, rpt.total),
- name)
-
- // Print outgoing edges.
- outEdges := sortedEdges(n.out)
- outSum := outEdges.sum()
- for _, out := range outEdges {
- fmt.Fprintf(w, "%50s %s | %s\n", rpt.formatValue(out.weight),
- percentage(out.weight, outSum), out.dest.info.prettyName())
- }
- }
- if len(g.ns) > 0 {
- fmt.Fprintln(w, separator)
- }
- return nil
-}
-
-// printDOT prints an annotated callgraph in DOT format.
-func printDOT(w io.Writer, rpt *Report) error {
- g, err := newGraph(rpt)
- if err != nil {
- return err
- }
-
- origCount, droppedNodes, droppedEdges := g.preprocess(rpt)
-
- prof := rpt.prof
- graphname := "unnamed"
- if len(prof.Mapping) > 0 {
- graphname = filepath.Base(prof.Mapping[0].File)
- }
- fmt.Fprintln(w, `digraph "`+graphname+`" {`)
- fmt.Fprintln(w, `node [style=filled fillcolor="#f8f8f8"]`)
- fmt.Fprintln(w, dotLegend(rpt, g, origCount, droppedNodes, droppedEdges))
-
- if len(g.ns) == 0 {
- fmt.Fprintln(w, "}")
- return nil
- }
-
- // Make sure nodes have a unique consistent id.
- nodeIndex := make(map[*node]int)
- maxFlat := float64(g.ns[0].flat)
- for i, n := range g.ns {
- nodeIndex[n] = i + 1
- if float64(n.flat) > maxFlat {
- maxFlat = float64(n.flat)
- }
- }
- var edges edgeList
- for _, n := range g.ns {
- node := dotNode(rpt, maxFlat, nodeIndex[n], n)
- fmt.Fprintln(w, node)
- if nodelets := dotNodelets(rpt, nodeIndex[n], n); nodelets != "" {
- fmt.Fprint(w, nodelets)
- }
-
- // Collect outgoing edges.
- for _, e := range n.out {
- edges = append(edges, e)
- }
- }
- // Sort edges by frequency as a hint to the graph layout engine.
- sort.Sort(edges)
- for _, e := range edges {
- fmt.Fprintln(w, dotEdge(rpt, nodeIndex[e.src], nodeIndex[e.dest], e))
- }
- fmt.Fprintln(w, "}")
- return nil
-}
-
-// percentage computes the percentage of total of a value, and encodes
-// it as a string. At least two digits of precision are printed.
-func percentage(value, total int64) string {
- var ratio float64
- if total != 0 {
- ratio = float64(value) / float64(total) * 100
- }
- switch {
- case ratio >= 99.95:
- return " 100%"
- case ratio >= 1.0:
- return fmt.Sprintf("%5.2f%%", ratio)
- default:
- return fmt.Sprintf("%5.2g%%", ratio)
- }
-}
-
-// dotLegend generates the overall graph label for a report in DOT format.
-func dotLegend(rpt *Report, g graph, origCount, droppedNodes, droppedEdges int) string {
- label := legendLabels(rpt)
- label = append(label, legendDetailLabels(rpt, g, origCount, droppedNodes, droppedEdges)...)
- return fmt.Sprintf(`subgraph cluster_L { L [shape=box fontsize=32 label="%s\l"] }`, strings.Join(label, `\l`))
-}
-
-// legendLabels generates labels exclusive to graph visualization.
-func legendLabels(rpt *Report) []string {
- prof := rpt.prof
- o := rpt.options
- var label []string
- if len(prof.Mapping) > 0 {
- if prof.Mapping[0].File != "" {
- label = append(label, "File: "+filepath.Base(prof.Mapping[0].File))
- }
- if prof.Mapping[0].BuildID != "" {
- label = append(label, "Build ID: "+prof.Mapping[0].BuildID)
- }
- }
- if o.SampleType != "" {
- label = append(label, "Type: "+o.SampleType)
- }
- if prof.TimeNanos != 0 {
- const layout = "Jan 2, 2006 at 3:04pm (MST)"
- label = append(label, "Time: "+time.Unix(0, prof.TimeNanos).Format(layout))
- }
- if prof.DurationNanos != 0 {
- label = append(label, fmt.Sprintf("Duration: %v", time.Duration(prof.DurationNanos)))
- }
- return label
-}
-
-// legendDetailLabels generates labels common to graph and text visualization.
-func legendDetailLabels(rpt *Report, g graph, origCount, droppedNodes, droppedEdges int) []string {
- nodeFraction := rpt.options.NodeFraction
- edgeFraction := rpt.options.EdgeFraction
- nodeCount := rpt.options.NodeCount
-
- label := []string{}
-
- var flatSum int64
- for _, n := range g.ns {
- flatSum = flatSum + n.flat
- }
-
- label = append(label, fmt.Sprintf("%s of %s total (%s)", rpt.formatValue(flatSum), rpt.formatValue(rpt.total), percentage(flatSum, rpt.total)))
-
- if rpt.total > 0 {
- if droppedNodes > 0 {
- label = append(label, genLabel(droppedNodes, "node", "cum",
- rpt.formatValue(int64(float64(rpt.total)*nodeFraction))))
- }
- if droppedEdges > 0 {
- label = append(label, genLabel(droppedEdges, "edge", "freq",
- rpt.formatValue(int64(float64(rpt.total)*edgeFraction))))
- }
- if nodeCount > 0 && nodeCount < origCount {
- label = append(label, fmt.Sprintf("Showing top %d nodes out of %d (cum >= %s)",
- nodeCount, origCount,
- rpt.formatValue(g.ns[len(g.ns)-1].cum)))
- }
- }
- return label
-}
-
-func genLabel(d int, n, l, f string) string {
- if d > 1 {
- n = n + "s"
- }
- return fmt.Sprintf("Dropped %d %s (%s <= %s)", d, n, l, f)
-}
-
-// dotNode generates a graph node in DOT format.
-func dotNode(rpt *Report, maxFlat float64, rIndex int, n *node) string {
- flat, cum := n.flat, n.cum
-
- labels := strings.Split(n.info.prettyName(), "::")
- label := strings.Join(labels, `\n`) + `\n`
-
- flatValue := rpt.formatValue(flat)
- if flat > 0 {
- label = label + fmt.Sprintf(`%s(%s)`,
- flatValue,
- strings.TrimSpace(percentage(flat, rpt.total)))
- } else {
- label = label + "0"
- }
- cumValue := flatValue
- if cum != flat {
- if flat > 0 {
- label = label + `\n`
- } else {
- label = label + " "
- }
- cumValue = rpt.formatValue(cum)
- label = label + fmt.Sprintf(`of %s(%s)`,
- cumValue,
- strings.TrimSpace(percentage(cum, rpt.total)))
- }
-
- // Scale font sizes from 8 to 24 based on percentage of flat frequency.
- // Use non linear growth to emphasize the size difference.
- baseFontSize, maxFontGrowth := 8, 16.0
- fontSize := baseFontSize
- if maxFlat > 0 && flat > 0 && float64(flat) <= maxFlat {
- fontSize += int(math.Ceil(maxFontGrowth * math.Sqrt(float64(flat)/maxFlat)))
- }
- return fmt.Sprintf(`N%d [label="%s" fontsize=%d shape=box tooltip="%s (%s)"]`,
- rIndex,
- label,
- fontSize, n.info.prettyName(), cumValue)
-}
-
-// dotEdge generates a graph edge in DOT format.
-func dotEdge(rpt *Report, from, to int, e *edgeInfo) string {
- w := rpt.formatValue(e.weight)
- attr := fmt.Sprintf(`label=" %s"`, w)
- if rpt.total > 0 {
- if weight := 1 + int(e.weight*100/rpt.total); weight > 1 {
- attr = fmt.Sprintf(`%s weight=%d`, attr, weight)
- }
- if width := 1 + int(e.weight*5/rpt.total); width > 1 {
- attr = fmt.Sprintf(`%s penwidth=%d`, attr, width)
- }
- }
- arrow := "->"
- if e.residual {
- arrow = "..."
- }
- tooltip := fmt.Sprintf(`"%s %s %s (%s)"`,
- e.src.info.prettyName(), arrow, e.dest.info.prettyName(), w)
- attr = fmt.Sprintf(`%s tooltip=%s labeltooltip=%s`,
- attr, tooltip, tooltip)
-
- if e.residual {
- attr = attr + ` style="dotted"`
- }
-
- if len(e.src.tags) > 0 {
- // Separate children further if source has tags.
- attr = attr + " minlen=2"
- }
- return fmt.Sprintf("N%d -> N%d [%s]", from, to, attr)
-}
-
-// dotNodelets generates the DOT boxes for the node tags.
-func dotNodelets(rpt *Report, rIndex int, n *node) (dot string) {
- const maxNodelets = 4 // Number of nodelets for alphanumeric labels
- const maxNumNodelets = 4 // Number of nodelets for numeric labels
-
- var ts, nts tags
- for _, t := range n.tags {
- if t.unit == "" {
- ts = append(ts, t)
- } else {
- nts = append(nts, t)
- }
- }
-
- // Select the top maxNodelets alphanumeric labels by weight
- sort.Sort(ts)
- if len(ts) > maxNodelets {
- ts = ts[:maxNodelets]
- }
- for i, t := range ts {
- weight := rpt.formatValue(t.weight)
- dot += fmt.Sprintf(`N%d_%d [label = "%s" fontsize=8 shape=box3d tooltip="%s"]`+"\n", rIndex, i, t.name, weight)
- dot += fmt.Sprintf(`N%d -> N%d_%d [label=" %s" weight=100 tooltip="\L" labeltooltip="\L"]`+"\n", rIndex, rIndex, i, weight)
- }
-
- // Collapse numeric labels into maxNumNodelets buckets, of the form:
- // 1MB..2MB, 3MB..5MB, ...
- nts = collapseTags(nts, maxNumNodelets)
- sort.Sort(nts)
- for i, t := range nts {
- weight := rpt.formatValue(t.weight)
- dot += fmt.Sprintf(`NN%d_%d [label = "%s" fontsize=8 shape=box3d tooltip="%s"]`+"\n", rIndex, i, t.name, weight)
- dot += fmt.Sprintf(`N%d -> NN%d_%d [label=" %s" weight=100 tooltip="\L" labeltooltip="\L"]`+"\n", rIndex, rIndex, i, weight)
- }
-
- return dot
-}
-
-// graph summarizes a performance profile into a format that is
-// suitable for visualization.
-type graph struct {
- ns nodes
-}
-
-// nodes is an ordered collection of graph nodes.
-type nodes []*node
-
-// tags represent sample annotations
-type tags []*tag
-type tagMap map[string]*tag
-
-type tag struct {
- name string
- unit string // Describe the value, "" for non-numeric tags
- value int64
- weight int64
-}
-
-func (t tags) Len() int { return len(t) }
-func (t tags) Swap(i, j int) { t[i], t[j] = t[j], t[i] }
-func (t tags) Less(i, j int) bool {
- if t[i].weight == t[j].weight {
- return t[i].name < t[j].name
- }
- return t[i].weight > t[j].weight
-}
-
-// node is an entry on a profiling report. It represents a unique
-// program location. It can include multiple names to represent
-// inlined functions.
-type node struct {
- info nodeInfo // Information associated to this entry.
-
- // values associated to this node.
- // flat is exclusive to this node, cum includes all descendents.
- flat, cum int64
-
- // in and out contains the nodes immediately reaching or reached by this nodes.
- in, out edgeMap
-
- // tags provide additional information about subsets of a sample.
- tags tagMap
-}
-
-type nodeInfo struct {
- name string
- origName string
- address uint64
- file string
- startLine, lineno int
- inline bool
- lowPriority bool
- objfile string
- parent *node // Used only if creating a calltree
-}
-
-func (n *node) addTags(s *profile.Sample, weight int64) {
- // Add a tag with all string labels
- var labels []string
- for key, vals := range s.Label {
- for _, v := range vals {
- labels = append(labels, key+":"+v)
- }
- }
- if len(labels) > 0 {
- sort.Strings(labels)
- l := n.tags.findOrAddTag(strings.Join(labels, `\n`), "", 0)
- l.weight += weight
- }
-
- for key, nvals := range s.NumLabel {
- for _, v := range nvals {
- label := scaledValueLabel(v, key, "auto")
- l := n.tags.findOrAddTag(label, key, v)
- l.weight += weight
- }
- }
-}
-
-func (m tagMap) findOrAddTag(label, unit string, value int64) *tag {
- if l := m[label]; l != nil {
- return l
- }
- l := &tag{
- name: label,
- unit: unit,
- value: value,
- }
- m[label] = l
- return l
-}
-
-// collapseTags reduces the number of entries in a tagMap by merging
-// adjacent nodes into ranges. It uses a greedy approach to merge
-// starting with the entries with the lowest weight.
-func collapseTags(ts tags, count int) tags {
- if len(ts) <= count {
- return ts
- }
-
- sort.Sort(ts)
- tagGroups := make([]tags, count)
- for i, t := range ts[:count] {
- tagGroups[i] = tags{t}
- }
- for _, t := range ts[count:] {
- g, d := 0, tagDistance(t, tagGroups[0][0])
- for i := 1; i < count; i++ {
- if nd := tagDistance(t, tagGroups[i][0]); nd < d {
- g, d = i, nd
- }
- }
- tagGroups[g] = append(tagGroups[g], t)
- }
-
- var nts tags
- for _, g := range tagGroups {
- l, w := tagGroupLabel(g)
- nts = append(nts, &tag{
- name: l,
- weight: w,
- })
- }
- return nts
-}
-
-func tagDistance(t, u *tag) float64 {
- v, _ := ScaleValue(u.value, u.unit, t.unit)
- if v < float64(t.value) {
- return float64(t.value) - v
- }
- return v - float64(t.value)
-}
-
-func tagGroupLabel(g tags) (string, int64) {
- if len(g) == 1 {
- t := g[0]
- return scaledValueLabel(t.value, t.unit, "auto"), t.weight
- }
- min := g[0]
- max := g[0]
- w := min.weight
- for _, t := range g[1:] {
- if v, _ := ScaleValue(t.value, t.unit, min.unit); int64(v) < min.value {
- min = t
- }
- if v, _ := ScaleValue(t.value, t.unit, max.unit); int64(v) > max.value {
- max = t
- }
- w += t.weight
- }
- return scaledValueLabel(min.value, min.unit, "auto") + ".." +
- scaledValueLabel(max.value, max.unit, "auto"), w
-}
-
-// sumNodes adds the flat and sum values on a report.
-func sumNodes(ns nodes) (flat int64, cum int64) {
- for _, n := range ns {
- flat += n.flat
- cum += n.cum
- }
- return
-}
-
-type edgeMap map[*node]*edgeInfo
-
-// edgeInfo contains any attributes to be represented about edges in a graph/
-type edgeInfo struct {
- src, dest *node
- // The summary weight of the edge
- weight int64
- // residual edges connect nodes that were connected through a
- // separate node, which has been removed from the report.
- residual bool
-}
-
-// bumpWeight increases the weight of an edge. If there isn't such an
-// edge in the map one is created.
-func bumpWeight(from, to *node, w int64, residual bool) {
- if from.out[to] != to.in[from] {
- panic(fmt.Errorf("asymmetric edges %v %v", *from, *to))
- }
-
- if n := from.out[to]; n != nil {
- n.weight += w
- if n.residual && !residual {
- n.residual = false
- }
- return
- }
-
- info := &edgeInfo{src: from, dest: to, weight: w, residual: residual}
- from.out[to] = info
- to.in[from] = info
-}
-
-// Output formats.
-const (
- Proto = iota
- Dot
- Tags
- Tree
- Text
- Raw
- Dis
- List
- WebList
- Callgrind
-)
-
-// Options are the formatting and filtering options used to generate a
-// profile.
-type Options struct {
- OutputFormat int
-
- CumSort bool
- CallTree bool
- PrintAddresses bool
- DropNegative bool
- Ratio float64
-
- NodeCount int
- NodeFraction float64
- EdgeFraction float64
-
- SampleType string
- SampleUnit string // Unit for the sample data from the profile.
- OutputUnit string // Units for data formatting in report.
-
- Symbol *regexp.Regexp // Symbols to include on disassembly report.
-}
-
-// newGraph summarizes performance data from a profile into a graph.
-func newGraph(rpt *Report) (g graph, err error) {
- prof := rpt.prof
- o := rpt.options
-
- // Generate a tree for graphical output if requested.
- buildTree := o.CallTree && o.OutputFormat == Dot
-
- locations := make(map[uint64][]nodeInfo)
- for _, l := range prof.Location {
- locations[l.ID] = newLocInfo(l)
- }
-
- nm := make(nodeMap)
- for _, sample := range prof.Sample {
- if sample.Location == nil {
- continue
- }
-
- // Construct list of node names for sample.
- var stack []nodeInfo
- for _, loc := range sample.Location {
- id := loc.ID
- stack = append(stack, locations[id]...)
- }
-
- // Upfront pass to update the parent chains, to prevent the
- // merging of nodes with different parents.
- if buildTree {
- var nn *node
- for i := len(stack); i > 0; i-- {
- n := &stack[i-1]
- n.parent = nn
- nn = nm.findOrInsertNode(*n)
- }
- }
-
- leaf := nm.findOrInsertNode(stack[0])
- weight := rpt.sampleValue(sample)
- leaf.addTags(sample, weight)
-
- // Aggregate counter data.
- leaf.flat += weight
- seen := make(map[*node]bool)
- var nn *node
- for _, s := range stack {
- n := nm.findOrInsertNode(s)
- if !seen[n] {
- seen[n] = true
- n.cum += weight
-
- if nn != nil {
- bumpWeight(n, nn, weight, false)
- }
- }
- nn = n
- }
- }
-
- // Collect new nodes into a report.
- ns := make(nodes, 0, len(nm))
- for _, n := range nm {
- if rpt.options.DropNegative && n.flat < 0 {
- continue
- }
- ns = append(ns, n)
- }
-
- return graph{ns}, nil
-}
-
-// Create a slice of formatted names for a location.
-func newLocInfo(l *profile.Location) []nodeInfo {
- var objfile string
-
- if m := l.Mapping; m != nil {
- objfile = filepath.Base(m.File)
- }
-
- if len(l.Line) == 0 {
- return []nodeInfo{
- {
- address: l.Address,
- objfile: objfile,
- },
- }
- }
- var info []nodeInfo
- numInlineFrames := len(l.Line) - 1
- for li, line := range l.Line {
- ni := nodeInfo{
- address: l.Address,
- lineno: int(line.Line),
- inline: li < numInlineFrames,
- objfile: objfile,
- }
-
- if line.Function != nil {
- ni.name = line.Function.Name
- ni.origName = line.Function.SystemName
- ni.file = line.Function.Filename
- ni.startLine = int(line.Function.StartLine)
- }
-
- info = append(info, ni)
- }
- return info
-}
-
-// nodeMap maps from a node info struct to a node. It is used to merge
-// report entries with the same info.
-type nodeMap map[nodeInfo]*node
-
-func (m nodeMap) findOrInsertNode(info nodeInfo) *node {
- rr := m[info]
- if rr == nil {
- rr = &node{
- info: info,
- in: make(edgeMap),
- out: make(edgeMap),
- tags: make(map[string]*tag),
- }
- m[info] = rr
- }
- return rr
-}
-
-// preprocess does any required filtering/sorting according to the
-// report options. Returns the mapping from each node to any nodes
-// removed by path compression and statistics on the nodes/edges removed.
-func (g *graph) preprocess(rpt *Report) (origCount, droppedNodes, droppedEdges int) {
- o := rpt.options
-
- // Compute total weight of current set of nodes.
- // This is <= rpt.total because of node filtering.
- var totalValue int64
- for _, n := range g.ns {
- totalValue += n.flat
- }
-
- // Remove nodes with value <= total*nodeFraction
- if nodeFraction := o.NodeFraction; nodeFraction > 0 {
- var removed nodes
- minValue := int64(float64(totalValue) * nodeFraction)
- kept := make(nodes, 0, len(g.ns))
- for _, n := range g.ns {
- if n.cum < minValue {
- removed = append(removed, n)
- } else {
- kept = append(kept, n)
- tagsKept := make(map[string]*tag)
- for s, t := range n.tags {
- if t.weight >= minValue {
- tagsKept[s] = t
- }
- }
- n.tags = tagsKept
- }
- }
- droppedNodes = len(removed)
- removeNodes(removed, false, false)
- g.ns = kept
- }
-
- // Remove edges below minimum frequency.
- if edgeFraction := o.EdgeFraction; edgeFraction > 0 {
- minEdge := int64(float64(totalValue) * edgeFraction)
- for _, n := range g.ns {
- for src, e := range n.in {
- if e.weight < minEdge {
- delete(n.in, src)
- delete(src.out, n)
- droppedEdges++
- }
- }
- }
- }
-
- sortOrder := flatName
- if o.CumSort {
- // Force cum sorting for graph output, to preserve connectivity.
- sortOrder = cumName
- }
-
- // Nodes that have flat==0 and a single in/out do not provide much
- // information. Give them first chance to be removed. Do not consider edges
- // from/to nodes that are expected to be removed.
- maxNodes := o.NodeCount
- if o.OutputFormat == Dot {
- if maxNodes > 0 && maxNodes < len(g.ns) {
- sortOrder = cumName
- g.ns.sort(cumName)
- cumCutoff := g.ns[maxNodes].cum
- for _, n := range g.ns {
- if n.flat == 0 {
- if count := countEdges(n.out, cumCutoff); count > 1 {
- continue
- }
- if count := countEdges(n.in, cumCutoff); count != 1 {
- continue
- }
- n.info.lowPriority = true
- }
- }
- }
- }
-
- g.ns.sort(sortOrder)
- if maxNodes > 0 {
- origCount = len(g.ns)
- for index, nodes := 0, 0; index < len(g.ns); index++ {
- nodes++
- // For DOT output, count the tags as nodes since we will draw
- // boxes for them.
- if o.OutputFormat == Dot {
- nodes += len(g.ns[index].tags)
- }
- if nodes > maxNodes {
- // Trim to the top n nodes. Create dotted edges to bridge any
- // broken connections.
- removeNodes(g.ns[index:], true, true)
- g.ns = g.ns[:index]
- break
- }
- }
- }
- removeRedundantEdges(g.ns)
-
- // Select best unit for profile output.
- // Find the appropriate units for the smallest non-zero sample
- if o.OutputUnit == "minimum" && len(g.ns) > 0 {
- var maxValue, minValue int64
-
- for _, n := range g.ns {
- if n.flat > 0 && (minValue == 0 || n.flat < minValue) {
- minValue = n.flat
- }
- if n.cum > maxValue {
- maxValue = n.cum
- }
- }
- if r := o.Ratio; r > 0 && r != 1 {
- minValue = int64(float64(minValue) * r)
- maxValue = int64(float64(maxValue) * r)
- }
-
- _, minUnit := ScaleValue(minValue, o.SampleUnit, "minimum")
- _, maxUnit := ScaleValue(maxValue, o.SampleUnit, "minimum")
-
- unit := minUnit
- if minUnit != maxUnit && minValue*100 < maxValue && o.OutputFormat != Callgrind {
- // Minimum and maximum values have different units. Scale
- // minimum by 100 to use larger units, allowing minimum value to
- // be scaled down to 0.01, except for callgrind reports since
- // they can only represent integer values.
- _, unit = ScaleValue(100*minValue, o.SampleUnit, "minimum")
- }
-
- if unit != "" {
- o.OutputUnit = unit
- } else {
- o.OutputUnit = o.SampleUnit
- }
- }
- return
-}
-
-// countEdges counts the number of edges below the specified cutoff.
-func countEdges(el edgeMap, cutoff int64) int {
- count := 0
- for _, e := range el {
- if e.weight > cutoff {
- count++
- }
- }
- return count
-}
-
-// removeNodes removes nodes from a report, optionally bridging
-// connections between in/out edges and spreading out their weights
-// proportionally. residual marks new bridge edges as residual
-// (dotted).
-func removeNodes(toRemove nodes, bridge, residual bool) {
- for _, n := range toRemove {
- for ei := range n.in {
- delete(ei.out, n)
- }
- if bridge {
- for ei, wi := range n.in {
- for eo, wo := range n.out {
- var weight int64
- if n.cum != 0 {
- weight = int64(float64(wo.weight) * (float64(wi.weight) / float64(n.cum)))
- }
- bumpWeight(ei, eo, weight, residual)
- }
- }
- }
- for eo := range n.out {
- delete(eo.in, n)
- }
- }
-}
-
-// removeRedundantEdges removes residual edges if the destination can
-// be reached through another path. This is done to simplify the graph
-// while preserving connectivity.
-func removeRedundantEdges(ns nodes) {
- // Walk the nodes and outgoing edges in reverse order to prefer
- // removing edges with the lowest weight.
- for i := len(ns); i > 0; i-- {
- n := ns[i-1]
- in := sortedEdges(n.in)
- for j := len(in); j > 0; j-- {
- if e := in[j-1]; e.residual && isRedundant(e) {
- delete(e.src.out, e.dest)
- delete(e.dest.in, e.src)
- }
- }
- }
-}
-
-// isRedundant determines if an edge can be removed without impacting
-// connectivity of the whole graph. This is implemented by checking if the
-// nodes have a common ancestor after removing the edge.
-func isRedundant(e *edgeInfo) bool {
- destPred := predecessors(e, e.dest)
- if len(destPred) == 1 {
- return false
- }
- srcPred := predecessors(e, e.src)
-
- for n := range srcPred {
- if destPred[n] && n != e.dest {
- return true
- }
- }
- return false
-}
-
-// predecessors collects all the predecessors to node n, excluding edge e.
-func predecessors(e *edgeInfo, n *node) map[*node]bool {
- seen := map[*node]bool{n: true}
- queue := []*node{n}
- for len(queue) > 0 {
- n := queue[0]
- queue = queue[1:]
- for _, ie := range n.in {
- if e == ie || seen[ie.src] {
- continue
- }
- seen[ie.src] = true
- queue = append(queue, ie.src)
- }
- }
- return seen
-}
-
-// nodeSorter is a mechanism used to allow a report to be sorted
-// in different ways.
-type nodeSorter struct {
- rs nodes
- less func(i, j int) bool
-}
-
-func (s nodeSorter) Len() int { return len(s.rs) }
-func (s nodeSorter) Swap(i, j int) { s.rs[i], s.rs[j] = s.rs[j], s.rs[i] }
-func (s nodeSorter) Less(i, j int) bool { return s.less(i, j) }
-
-type nodeOrder int
-
-const (
- flatName nodeOrder = iota
- flatCumName
- cumName
- nameOrder
- fileOrder
- addressOrder
-)
-
-// sort reorders the entries in a report based on the specified
-// ordering criteria. The result is sorted in decreasing order for
-// numeric quantities, alphabetically for text, and increasing for
-// addresses.
-func (ns nodes) sort(o nodeOrder) error {
- var s nodeSorter
-
- switch o {
- case flatName:
- s = nodeSorter{ns,
- func(i, j int) bool {
- if iv, jv := ns[i].flat, ns[j].flat; iv != jv {
- return iv > jv
- }
- if ns[i].info.prettyName() != ns[j].info.prettyName() {
- return ns[i].info.prettyName() < ns[j].info.prettyName()
- }
- iv, jv := ns[i].cum, ns[j].cum
- return iv > jv
- },
- }
- case flatCumName:
- s = nodeSorter{ns,
- func(i, j int) bool {
- if iv, jv := ns[i].flat, ns[j].flat; iv != jv {
- return iv > jv
- }
- if iv, jv := ns[i].cum, ns[j].cum; iv != jv {
- return iv > jv
- }
- return ns[i].info.prettyName() < ns[j].info.prettyName()
- },
- }
- case cumName:
- s = nodeSorter{ns,
- func(i, j int) bool {
- if ns[i].info.lowPriority != ns[j].info.lowPriority {
- return ns[j].info.lowPriority
- }
- if iv, jv := ns[i].cum, ns[j].cum; iv != jv {
- return iv > jv
- }
- if ns[i].info.prettyName() != ns[j].info.prettyName() {
- return ns[i].info.prettyName() < ns[j].info.prettyName()
- }
- iv, jv := ns[i].flat, ns[j].flat
- return iv > jv
- },
- }
- case nameOrder:
- s = nodeSorter{ns,
- func(i, j int) bool {
- return ns[i].info.name < ns[j].info.name
- },
- }
- case fileOrder:
- s = nodeSorter{ns,
- func(i, j int) bool {
- return ns[i].info.file < ns[j].info.file
- },
- }
- case addressOrder:
- s = nodeSorter{ns,
- func(i, j int) bool {
- return ns[i].info.address < ns[j].info.address
- },
- }
- default:
- return fmt.Errorf("report: unrecognized sort ordering: %d", o)
- }
- sort.Sort(s)
- return nil
-}
-
-type edgeList []*edgeInfo
-
-// sortedEdges return a slice of the edges in the map, sorted for
-// visualization. The sort order is first based on the edge weight
-// (higher-to-lower) and then by the node names to avoid flakiness.
-func sortedEdges(edges map[*node]*edgeInfo) edgeList {
- el := make(edgeList, 0, len(edges))
- for _, w := range edges {
- el = append(el, w)
- }
-
- sort.Sort(el)
- return el
-}
-
-func (el edgeList) Len() int {
- return len(el)
-}
-
-func (el edgeList) Less(i, j int) bool {
- if el[i].weight != el[j].weight {
- return el[i].weight > el[j].weight
- }
-
- from1 := el[i].src.info.prettyName()
- from2 := el[j].src.info.prettyName()
- if from1 != from2 {
- return from1 < from2
- }
-
- to1 := el[i].dest.info.prettyName()
- to2 := el[j].dest.info.prettyName()
-
- return to1 < to2
-}
-
-func (el edgeList) Swap(i, j int) {
- el[i], el[j] = el[j], el[i]
-}
-
-func (el edgeList) sum() int64 {
- var ret int64
- for _, e := range el {
- ret += e.weight
- }
- return ret
-}
-
-// ScaleValue reformats a value from a unit to a different unit.
-func ScaleValue(value int64, fromUnit, toUnit string) (sv float64, su string) {
- // Avoid infinite recursion on overflow.
- if value < 0 && -value > 0 {
- v, u := ScaleValue(-value, fromUnit, toUnit)
- return -v, u
- }
- if m, u, ok := memoryLabel(value, fromUnit, toUnit); ok {
- return m, u
- }
- if t, u, ok := timeLabel(value, fromUnit, toUnit); ok {
- return t, u
- }
- // Skip non-interesting units.
- switch toUnit {
- case "count", "sample", "unit", "minimum":
- return float64(value), ""
- default:
- return float64(value), toUnit
- }
-}
-
-func scaledValueLabel(value int64, fromUnit, toUnit string) string {
- v, u := ScaleValue(value, fromUnit, toUnit)
-
- sv := strings.TrimSuffix(fmt.Sprintf("%.2f", v), ".00")
- if sv == "0" || sv == "-0" {
- return "0"
- }
- return sv + u
-}
-
-func memoryLabel(value int64, fromUnit, toUnit string) (v float64, u string, ok bool) {
- fromUnit = strings.TrimSuffix(strings.ToLower(fromUnit), "s")
- toUnit = strings.TrimSuffix(strings.ToLower(toUnit), "s")
-
- switch fromUnit {
- case "byte", "b":
- case "kilobyte", "kb":
- value *= 1024
- case "megabyte", "mb":
- value *= 1024 * 1024
- case "gigabyte", "gb":
- value *= 1024 * 1024 * 1024
- default:
- return 0, "", false
- }
-
- if toUnit == "minimum" || toUnit == "auto" {
- switch {
- case value < 1024:
- toUnit = "b"
- case value < 1024*1024:
- toUnit = "kb"
- case value < 1024*1024*1024:
- toUnit = "mb"
- default:
- toUnit = "gb"
- }
- }
-
- var output float64
- switch toUnit {
- default:
- output, toUnit = float64(value), "B"
- case "kb", "kbyte", "kilobyte":
- output, toUnit = float64(value)/1024, "kB"
- case "mb", "mbyte", "megabyte":
- output, toUnit = float64(value)/(1024*1024), "MB"
- case "gb", "gbyte", "gigabyte":
- output, toUnit = float64(value)/(1024*1024*1024), "GB"
- }
- return output, toUnit, true
-}
-
-func timeLabel(value int64, fromUnit, toUnit string) (v float64, u string, ok bool) {
- fromUnit = strings.ToLower(fromUnit)
- if len(fromUnit) > 2 {
- fromUnit = strings.TrimSuffix(fromUnit, "s")
- }
-
- toUnit = strings.ToLower(toUnit)
- if len(toUnit) > 2 {
- toUnit = strings.TrimSuffix(toUnit, "s")
- }
-
- var d time.Duration
- switch fromUnit {
- case "nanosecond", "ns":
- d = time.Duration(value) * time.Nanosecond
- case "microsecond":
- d = time.Duration(value) * time.Microsecond
- case "millisecond", "ms":
- d = time.Duration(value) * time.Millisecond
- case "second", "sec":
- d = time.Duration(value) * time.Second
- case "cycle":
- return float64(value), "", true
- default:
- return 0, "", false
- }
-
- if toUnit == "minimum" || toUnit == "auto" {
- switch {
- case d < 1*time.Microsecond:
- toUnit = "ns"
- case d < 1*time.Millisecond:
- toUnit = "us"
- case d < 1*time.Second:
- toUnit = "ms"
- case d < 1*time.Minute:
- toUnit = "sec"
- case d < 1*time.Hour:
- toUnit = "min"
- case d < 24*time.Hour:
- toUnit = "hour"
- case d < 15*24*time.Hour:
- toUnit = "day"
- case d < 120*24*time.Hour:
- toUnit = "week"
- default:
- toUnit = "year"
- }
- }
-
- var output float64
- dd := float64(d)
- switch toUnit {
- case "ns", "nanosecond":
- output, toUnit = dd/float64(time.Nanosecond), "ns"
- case "us", "microsecond":
- output, toUnit = dd/float64(time.Microsecond), "us"
- case "ms", "millisecond":
- output, toUnit = dd/float64(time.Millisecond), "ms"
- case "min", "minute":
- output, toUnit = dd/float64(time.Minute), "mins"
- case "hour", "hr":
- output, toUnit = dd/float64(time.Hour), "hrs"
- case "day":
- output, toUnit = dd/float64(24*time.Hour), "days"
- case "week", "wk":
- output, toUnit = dd/float64(7*24*time.Hour), "wks"
- case "year", "yr":
- output, toUnit = dd/float64(365*7*24*time.Hour), "yrs"
- default:
- fallthrough
- case "sec", "second", "s":
- output, toUnit = dd/float64(time.Second), "s"
- }
- return output, toUnit, true
-}
-
-// prettyName determines the printable name to be used for a node.
-func (info *nodeInfo) prettyName() string {
- var name string
- if info.address != 0 {
- name = fmt.Sprintf("%016x", info.address)
- }
-
- if info.name != "" {
- name = name + " " + info.name
- }
-
- if info.file != "" {
- name += " " + trimPath(info.file)
- if info.lineno != 0 {
- name += fmt.Sprintf(":%d", info.lineno)
- }
- }
-
- if info.inline {
- name = name + " (inline)"
- }
-
- if name = strings.TrimSpace(name); name == "" && info.objfile != "" {
- name = "[" + info.objfile + "]"
- }
- return name
-}
-
-// New builds a new report indexing the sample values interpreting the
-// samples with the provided function.
-func New(prof *profile.Profile, options Options, value func(s *profile.Sample) int64, unit string) *Report {
- o := &options
- if o.SampleUnit == "" {
- o.SampleUnit = unit
- }
- format := func(v int64) string {
- if r := o.Ratio; r > 0 && r != 1 {
- fv := float64(v) * r
- v = int64(fv)
- }
- return scaledValueLabel(v, o.SampleUnit, o.OutputUnit)
- }
- return &Report{prof, computeTotal(prof, value), o, value, format}
-}
-
-// NewDefault builds a new report indexing the sample values with the
-// last value available.
-func NewDefault(prof *profile.Profile, options Options) *Report {
- index := len(prof.SampleType) - 1
- o := &options
- if o.SampleUnit == "" {
- o.SampleUnit = strings.ToLower(prof.SampleType[index].Unit)
- }
- value := func(s *profile.Sample) int64 {
- return s.Value[index]
- }
- format := func(v int64) string {
- if r := o.Ratio; r > 0 && r != 1 {
- fv := float64(v) * r
- v = int64(fv)
- }
- return scaledValueLabel(v, o.SampleUnit, o.OutputUnit)
- }
- return &Report{prof, computeTotal(prof, value), o, value, format}
-}
-
-func computeTotal(prof *profile.Profile, value func(s *profile.Sample) int64) int64 {
- var ret int64
- for _, sample := range prof.Sample {
- ret += value(sample)
- }
- return ret
-}
-
-// Report contains the data and associated routines to extract a
-// report from a profile.
-type Report struct {
- prof *profile.Profile
- total int64
- options *Options
- sampleValue func(*profile.Sample) int64
- formatValue func(int64) string
-}
diff --git a/src/cmd/internal/pprof/report/source.go b/src/cmd/internal/pprof/report/source.go
deleted file mode 100644
index 608e4d5..0000000
--- a/src/cmd/internal/pprof/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/internal/pprof/plugin"
-)
-
-// printSource prints an annotated source listing, include all
-// functions with samples that match the regexp rpt.options.symbol.
-// The sources are sorted by function name and then by filename to
-// eliminate potential nondeterminism.
-func printSource(w io.Writer, rpt *Report) error {
- o := rpt.options
- g, err := newGraph(rpt)
- if err != nil {
- return err
- }
-
- // Identify all the functions that match the regexp provided.
- // Group nodes for each matching function.
- var functions nodes
- functionNodes := make(map[string]nodes)
- for _, n := range g.ns {
- if !o.Symbol.MatchString(n.info.name) {
- continue
- }
- if functionNodes[n.info.name] == nil {
- functions = append(functions, n)
- }
- functionNodes[n.info.name] = append(functionNodes[n.info.name], n)
- }
- functions.sort(nameOrder)
-
- fmt.Fprintf(w, "Total: %s\n", rpt.formatValue(rpt.total))
- for _, fn := range functions {
- name := fn.info.name
-
- // Identify all the source files associated to this function.
- // Group nodes for each source file.
- var sourceFiles nodes
- fileNodes := make(map[string]nodes)
- for _, n := range functionNodes[name] {
- if n.info.file == "" {
- continue
- }
- if fileNodes[n.info.file] == nil {
- sourceFiles = append(sourceFiles, n)
- }
- fileNodes[n.info.file] = append(fileNodes[n.info.file], n)
- }
-
- if len(sourceFiles) == 0 {
- fmt.Printf("No source information for %s\n", name)
- continue
- }
-
- sourceFiles.sort(fileOrder)
-
- // Print each file associated with this function.
- for _, fl := range sourceFiles {
- filename := fl.info.file
- fns := fileNodes[filename]
- flatSum, cumSum := sumNodes(fns)
-
- fnodes, path, err := getFunctionSource(name, filename, fns, 0, 0)
- fmt.Fprintf(w, "ROUTINE ======================== %s in %s\n", name, path)
- fmt.Fprintf(w, "%10s %10s (flat, cum) %s of Total\n",
- rpt.formatValue(flatSum), rpt.formatValue(cumSum),
- percentage(cumSum, rpt.total))
-
- if err != nil {
- fmt.Fprintf(w, " Error: %v\n", err)
- continue
- }
-
- for _, fn := range fnodes {
- fmt.Fprintf(w, "%10s %10s %6d:%s\n", valueOrDot(fn.flat, rpt), valueOrDot(fn.cum, rpt), fn.info.lineno, fn.info.name)
- }
- }
- }
- return nil
-}
-
-// printWebSource prints an annotated source listing, include all
-// functions with samples that match the regexp rpt.options.symbol.
-func printWebSource(w io.Writer, rpt *Report, obj plugin.ObjTool) error {
- o := rpt.options
- g, err := newGraph(rpt)
- if err != nil {
- return err
- }
-
- // If the regexp source can be parsed as an address, also match
- // functions that land on that address.
- var address *uint64
- if hex, err := strconv.ParseUint(o.Symbol.String(), 0, 64); err == nil {
- address = &hex
- }
-
- // Extract interesting symbols from binary files in the profile and
- // classify samples per symbol.
- symbols := symbolsFromBinaries(rpt.prof, g, o.Symbol, address, obj)
- symNodes := nodesPerSymbol(g.ns, symbols)
-
- // Sort symbols for printing.
- var syms objSymbols
- for s := range symNodes {
- syms = append(syms, s)
- }
- sort.Sort(syms)
-
- if len(syms) == 0 {
- return fmt.Errorf("no samples found on routines matching: %s", o.Symbol.String())
- }
-
- printHeader(w, rpt)
- for _, s := range syms {
- name := s.sym.Name[0]
- // Identify sources associated to a symbol by examining
- // symbol samples. Classify samples per source file.
- var sourceFiles nodes
- fileNodes := make(map[string]nodes)
- for _, n := range symNodes[s] {
- if n.info.file == "" {
- continue
- }
- if fileNodes[n.info.file] == nil {
- sourceFiles = append(sourceFiles, n)
- }
- fileNodes[n.info.file] = append(fileNodes[n.info.file], n)
- }
-
- if len(sourceFiles) == 0 {
- fmt.Printf("No source information for %s\n", name)
- continue
- }
-
- sourceFiles.sort(fileOrder)
-
- // Print each file associated with this function.
- for _, fl := range sourceFiles {
- filename := fl.info.file
- fns := fileNodes[filename]
-
- asm := assemblyPerSourceLine(symbols, fns, filename, obj)
- start, end := sourceCoordinates(asm)
-
- fnodes, path, err := getFunctionSource(name, filename, fns, start, end)
- if err != nil {
- fnodes, path = getMissingFunctionSource(filename, asm, start, end)
- }
-
- flatSum, cumSum := sumNodes(fnodes)
- printFunctionHeader(w, name, path, flatSum, cumSum, rpt)
- for _, fn := range fnodes {
- printFunctionSourceLine(w, fn, asm[fn.info.lineno], rpt)
- }
- printFunctionClosing(w)
- }
- }
- printPageClosing(w)
- return nil
-}
-
-// sourceCoordinates returns the lowest and highest line numbers from
-// a set of assembly statements.
-func sourceCoordinates(asm map[int]nodes) (start, end int) {
- for l := range asm {
- if start == 0 || l < start {
- start = l
- }
- if end == 0 || l > end {
- end = l
- }
- }
- return start, end
-}
-
-// assemblyPerSourceLine disassembles the binary containing a symbol
-// and classifies the assembly instructions according to its
-// corresponding source line, annotating them with a set of samples.
-func assemblyPerSourceLine(objSyms []*objSymbol, rs nodes, src string, obj plugin.ObjTool) map[int]nodes {
- assembly := make(map[int]nodes)
- // Identify symbol to use for this collection of samples.
- o := findMatchingSymbol(objSyms, rs)
- if o == nil {
- return assembly
- }
-
- // Extract assembly for matched symbol
- insns, err := obj.Disasm(o.sym.File, o.sym.Start, o.sym.End)
- if err != nil {
- return assembly
- }
-
- srcBase := filepath.Base(src)
- anodes := annotateAssembly(insns, rs, o.base)
- var lineno = 0
- for _, an := range anodes {
- if filepath.Base(an.info.file) == srcBase {
- lineno = an.info.lineno
- }
- if lineno != 0 {
- assembly[lineno] = append(assembly[lineno], an)
- }
- }
-
- return assembly
-}
-
-// findMatchingSymbol looks for the symbol that corresponds to a set
-// of samples, by comparing their addresses.
-func findMatchingSymbol(objSyms []*objSymbol, ns nodes) *objSymbol {
- for _, n := range ns {
- for _, o := range objSyms {
- if filepath.Base(o.sym.File) == n.info.objfile &&
- o.sym.Start <= n.info.address-o.base &&
- n.info.address-o.base <= o.sym.End {
- return o
- }
- }
- }
- return nil
-}
-
-// printHeader prints the page header for a weblist report.
-func printHeader(w io.Writer, rpt *Report) {
- fmt.Fprintln(w, weblistPageHeader)
-
- var labels []string
- for _, l := range legendLabels(rpt) {
- labels = append(labels, template.HTMLEscapeString(l))
- }
-
- fmt.Fprintf(w, `<div class="legend">%s<br>Total: %s</div>`,
- strings.Join(labels, "<br>\n"),
- rpt.formatValue(rpt.total),
- )
-}
-
-// printFunctionHeader prints a function header for a weblist report.
-func printFunctionHeader(w io.Writer, name, path string, flatSum, cumSum int64, rpt *Report) {
- fmt.Fprintf(w, `<h1>%s</h1>%s
-<pre onClick="pprof_toggle_asm(event)">
- Total: %10s %10s (flat, cum) %s
-`,
- template.HTMLEscapeString(name), template.HTMLEscapeString(path),
- rpt.formatValue(flatSum), rpt.formatValue(cumSum),
- percentage(cumSum, rpt.total))
-}
-
-// printFunctionSourceLine prints a source line and the corresponding assembly.
-func printFunctionSourceLine(w io.Writer, fn *node, assembly nodes, rpt *Report) {
- if len(assembly) == 0 {
- fmt.Fprintf(w,
- "<span class=line> %6d</span> <span class=nop> %10s %10s %s </span>\n",
- fn.info.lineno,
- valueOrDot(fn.flat, rpt), valueOrDot(fn.cum, rpt),
- template.HTMLEscapeString(fn.info.name))
- return
- }
-
- fmt.Fprintf(w,
- "<span class=line> %6d</span> <span class=deadsrc> %10s %10s %s </span>",
- fn.info.lineno,
- valueOrDot(fn.flat, rpt), valueOrDot(fn.cum, rpt),
- template.HTMLEscapeString(fn.info.name))
- fmt.Fprint(w, "<span class=asm>")
- for _, an := range assembly {
- var fileline string
- class := "disasmloc"
- if an.info.file != "" {
- fileline = fmt.Sprintf("%s:%d", template.HTMLEscapeString(an.info.file), an.info.lineno)
- if an.info.lineno != fn.info.lineno {
- class = "unimportant"
- }
- }
- fmt.Fprintf(w, " %8s %10s %10s %8x: %-48s <span class=%s>%s</span>\n", "",
- valueOrDot(an.flat, rpt), valueOrDot(an.cum, rpt),
- an.info.address,
- template.HTMLEscapeString(an.info.name),
- class,
- template.HTMLEscapeString(fileline))
- }
- fmt.Fprintln(w, "</span>")
-}
-
-// printFunctionClosing prints the end of a function in a weblist report.
-func printFunctionClosing(w io.Writer) {
- fmt.Fprintln(w, "</pre>")
-}
-
-// printPageClosing prints the end of the page in a weblist report.
-func printPageClosing(w io.Writer) {
- fmt.Fprintln(w, weblistPageClosing)
-}
-
-// getFunctionSource collects the sources of a function from a source
-// file and annotates it with the samples in fns. Returns the sources
-// as nodes, using the info.name field to hold the source code.
-func getFunctionSource(fun, file string, fns nodes, start, end int) (nodes, string, error) {
- f, file, err := adjustSourcePath(file)
- if err != nil {
- return nil, file, err
- }
-
- lineNodes := make(map[int]nodes)
-
- // Collect source coordinates from profile.
- const margin = 5 // Lines before first/after last sample.
- if start == 0 {
- if fns[0].info.startLine != 0 {
- start = fns[0].info.startLine
- } else {
- start = fns[0].info.lineno - margin
- }
- } else {
- start -= margin
- }
- if end == 0 {
- end = fns[0].info.lineno
- }
- end += margin
- for _, n := range fns {
- lineno := n.info.lineno
- nodeStart := n.info.startLine
- if nodeStart == 0 {
- nodeStart = lineno - margin
- }
- nodeEnd := lineno + margin
- if nodeStart < start {
- start = nodeStart
- } else if nodeEnd > end {
- end = nodeEnd
- }
- lineNodes[lineno] = append(lineNodes[lineno], n)
- }
-
- var src nodes
- buf := bufio.NewReader(f)
- lineno := 1
- for {
- line, err := buf.ReadString('\n')
- if err != nil {
- if err != io.EOF {
- return nil, file, err
- }
- if line == "" {
- // end was at or past EOF; that's okay
- break
- }
- }
- if lineno >= start {
- flat, cum := sumNodes(lineNodes[lineno])
-
- src = append(src, &node{
- info: nodeInfo{
- name: strings.TrimRight(line, "\n"),
- lineno: lineno,
- },
- flat: flat,
- cum: cum,
- })
- }
- lineno++
- if lineno > end {
- break
- }
- }
- return src, file, nil
-}
-
-// getMissingFunctionSource creates a dummy function body to point to
-// the source file and annotates it with the samples in asm.
-func getMissingFunctionSource(filename string, asm map[int]nodes, start, end int) (nodes, string) {
- var fnodes nodes
- for i := start; i <= end; i++ {
- lrs := asm[i]
- if len(lrs) == 0 {
- continue
- }
- flat, cum := sumNodes(lrs)
- fnodes = append(fnodes, &node{
- info: nodeInfo{
- name: "???",
- lineno: i,
- },
- flat: flat,
- cum: cum,
- })
- }
- return fnodes, filename
-}
-
-// adjustSourcePath adjusts the path for a source file by trimming
-// known prefixes and searching for the file on all parents of the
-// current working dir.
-func adjustSourcePath(path string) (*os.File, string, error) {
- path = trimPath(path)
- f, err := os.Open(path)
- if err == nil {
- return f, path, nil
- }
-
- if dir, wderr := os.Getwd(); wderr == nil {
- for {
- parent := filepath.Dir(dir)
- if parent == dir {
- break
- }
- if f, err := os.Open(filepath.Join(parent, path)); err == nil {
- return f, filepath.Join(parent, path), nil
- }
-
- dir = parent
- }
- }
-
- return nil, path, err
-}
-
-// trimPath cleans up a path by removing prefixes that are commonly
-// found on profiles.
-func trimPath(path string) string {
- basePaths := []string{
- "/proc/self/cwd/./",
- "/proc/self/cwd/",
- }
-
- sPath := filepath.ToSlash(path)
-
- for _, base := range basePaths {
- if strings.HasPrefix(sPath, base) {
- return filepath.FromSlash(sPath[len(base):])
- }
- }
- return path
-}
diff --git a/src/cmd/internal/pprof/symbolizer/symbolizer.go b/src/cmd/internal/pprof/symbolizer/symbolizer.go
deleted file mode 100644
index bc22800..0000000
--- a/src/cmd/internal/pprof/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/internal/pprof/plugin"
- "cmd/internal/pprof/profile"
-)
-
-// Symbolize adds symbol and line number information to all locations
-// in a profile. mode enables some options to control
-// symbolization. Currently only recognizes "force", which causes it
-// to overwrite any existing data.
-func Symbolize(mode string, prof *profile.Profile, obj plugin.ObjTool, ui plugin.UI) error {
- force := false
- // Disable some mechanisms based on mode string.
- for _, o := range strings.Split(strings.ToLower(mode), ":") {
- switch o {
- case "force":
- force = true
- default:
- }
- }
-
- if len(prof.Mapping) == 0 {
- return fmt.Errorf("no known mappings")
- }
-
- mt, err := newMapping(prof, obj, ui, force)
- if err != nil {
- return err
- }
- defer mt.close()
-
- functions := make(map[profile.Function]*profile.Function)
- for _, l := range mt.prof.Location {
- m := l.Mapping
- segment := mt.segments[m]
- if segment == nil {
- // Nothing to do
- continue
- }
-
- stack, err := segment.SourceLine(l.Address)
- if err != nil || len(stack) == 0 {
- // No answers from addr2line
- continue
- }
-
- l.Line = make([]profile.Line, len(stack))
- for i, frame := range stack {
- if frame.Func != "" {
- m.HasFunctions = true
- }
- if frame.File != "" {
- m.HasFilenames = true
- }
- if frame.Line != 0 {
- m.HasLineNumbers = true
- }
- f := &profile.Function{
- Name: frame.Func,
- SystemName: frame.Func,
- Filename: frame.File,
- }
- if fp := functions[*f]; fp != nil {
- f = fp
- } else {
- functions[*f] = f
- f.ID = uint64(len(mt.prof.Function)) + 1
- mt.prof.Function = append(mt.prof.Function, f)
- }
- l.Line[i] = profile.Line{
- Function: f,
- Line: int64(frame.Line),
- }
- }
-
- if len(stack) > 0 {
- m.HasInlineFrames = true
- }
- }
- return nil
-}
-
-// newMapping creates a mappingTable for a profile.
-func newMapping(prof *profile.Profile, obj plugin.ObjTool, ui plugin.UI, force bool) (*mappingTable, error) {
- mt := &mappingTable{
- prof: prof,
- segments: make(map[*profile.Mapping]plugin.ObjFile),
- }
-
- // Identify used mappings
- mappings := make(map[*profile.Mapping]bool)
- for _, l := range prof.Location {
- mappings[l.Mapping] = true
- }
-
- for _, m := range prof.Mapping {
- if !mappings[m] {
- continue
- }
- // Do not attempt to re-symbolize a mapping that has already been symbolized.
- if !force && (m.HasFunctions || m.HasFilenames || m.HasLineNumbers) {
- continue
- }
-
- f, err := locateFile(obj, m.File, m.BuildID, m.Start)
- if err != nil {
- ui.PrintErr("Local symbolization failed for ", filepath.Base(m.File), ": ", err)
- // Move on to other mappings
- continue
- }
-
- if fid := f.BuildID(); m.BuildID != "" && fid != "" && fid != m.BuildID {
- // Build ID mismatch - ignore.
- f.Close()
- continue
- }
-
- mt.segments[m] = f
- }
-
- return mt, nil
-}
-
-// locateFile opens a local file for symbolization on the search path
-// at $PPROF_BINARY_PATH. Looks inside these directories for files
-// named $BUILDID/$BASENAME and $BASENAME (if build id is available).
-func locateFile(obj plugin.ObjTool, file, buildID string, start uint64) (plugin.ObjFile, error) {
- // Construct search path to examine
- searchPath := os.Getenv("PPROF_BINARY_PATH")
- if searchPath == "" {
- // Use $HOME/pprof/binaries as default directory for local symbolization binaries
- searchPath = filepath.Join(os.Getenv("HOME"), "pprof", "binaries")
- }
-
- // Collect names to search: {buildid/basename, basename}
- var fileNames []string
- if baseName := filepath.Base(file); buildID != "" {
- fileNames = []string{filepath.Join(buildID, baseName), baseName}
- } else {
- fileNames = []string{baseName}
- }
- for _, path := range filepath.SplitList(searchPath) {
- for nameIndex, name := range fileNames {
- file := filepath.Join(path, name)
- if f, err := obj.Open(file, start); err == nil {
- fileBuildID := f.BuildID()
- if buildID == "" || buildID == fileBuildID {
- return f, nil
- }
- f.Close()
- if nameIndex == 0 {
- // If this is the first name, the path includes the build id. Report inconsistency.
- return nil, fmt.Errorf("found file %s with inconsistent build id %s", file, fileBuildID)
- }
- }
- }
- }
- // Try original file name
- f, err := obj.Open(file, start)
- if err == nil && buildID != "" {
- if fileBuildID := f.BuildID(); fileBuildID != "" && fileBuildID != buildID {
- // Mismatched build IDs, ignore
- f.Close()
- return nil, fmt.Errorf("mismatched build ids %s != %s", fileBuildID, buildID)
- }
- }
- return f, err
-}
-
-// mappingTable contains the mechanisms for symbolization of a
-// profile.
-type mappingTable struct {
- prof *profile.Profile
- segments map[*profile.Mapping]plugin.ObjFile
-}
-
-// Close releases any external processes being used for the mapping.
-func (mt *mappingTable) close() {
- for _, segment := range mt.segments {
- segment.Close()
- }
-}
diff --git a/src/cmd/internal/pprof/symbolz/symbolz.go b/src/cmd/internal/pprof/symbolz/symbolz.go
deleted file mode 100644
index 2f2850a..0000000
--- a/src/cmd/internal/pprof/symbolz/symbolz.go
+++ /dev/null
@@ -1,111 +0,0 @@
-// Copyright 2014 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// Package symbolz symbolizes a profile using the output from the symbolz
-// service.
-package symbolz
-
-import (
- "bytes"
- "fmt"
- "io"
- "net/url"
- "regexp"
- "strconv"
- "strings"
-
- "cmd/internal/pprof/profile"
-)
-
-var (
- symbolzRE = regexp.MustCompile(`(0x[[:xdigit:]]+)\s+(.*)`)
-)
-
-// Symbolize symbolizes profile p by parsing data returned by a
-// symbolz handler. syms receives the symbolz query (hex addresses
-// separated by '+') and returns the symbolz output in a string. It
-// symbolizes all locations based on their addresses, regardless of
-// mapping.
-func Symbolize(source string, syms func(string, string) ([]byte, error), p *profile.Profile) error {
- if source = symbolz(source, p); source == "" {
- // If the source is not a recognizable URL, do nothing.
- return nil
- }
-
- // Construct query of addresses to symbolize.
- var a []string
- for _, l := range p.Location {
- if l.Address != 0 && len(l.Line) == 0 {
- a = append(a, fmt.Sprintf("%#x", l.Address))
- }
- }
-
- if len(a) == 0 {
- // No addresses to symbolize.
- return nil
- }
- lines := make(map[uint64]profile.Line)
- functions := make(map[string]*profile.Function)
- if b, err := syms(source, strings.Join(a, "+")); err == nil {
- buf := bytes.NewBuffer(b)
- for {
- l, err := buf.ReadString('\n')
-
- if err != nil {
- if err == io.EOF {
- break
- }
- return err
- }
-
- if symbol := symbolzRE.FindStringSubmatch(l); len(symbol) == 3 {
- addr, err := strconv.ParseUint(symbol[1], 0, 64)
- if err != nil {
- return fmt.Errorf("unexpected parse failure %s: %v", symbol[1], err)
- }
-
- name := symbol[2]
- fn := functions[name]
- if fn == nil {
- fn = &profile.Function{
- ID: uint64(len(p.Function) + 1),
- Name: name,
- SystemName: name,
- }
- functions[name] = fn
- p.Function = append(p.Function, fn)
- }
-
- lines[addr] = profile.Line{Function: fn}
- }
- }
- }
-
- for _, l := range p.Location {
- if line, ok := lines[l.Address]; ok {
- l.Line = []profile.Line{line}
- if l.Mapping != nil {
- l.Mapping.HasFunctions = true
- }
- }
- }
-
- return nil
-}
-
-// symbolz returns the corresponding symbolz source for a profile URL.
-func symbolz(source string, p *profile.Profile) string {
- if url, err := url.Parse(source); err == nil && url.Host != "" {
- if last := strings.LastIndex(url.Path, "/"); last != -1 {
- if strings.HasSuffix(url.Path[:last], "pprof") {
- url.Path = url.Path[:last] + "/symbol"
- } else {
- url.Path = url.Path[:last] + "/symbolz"
- }
- return url.String()
- }
- }
-
- return ""
-}
diff --git a/src/cmd/internal/sys/arch.go b/src/cmd/internal/sys/arch.go
index 18accde..22c8c32 100644
--- a/src/cmd/internal/sys/arch.go
+++ b/src/cmd/internal/sys/arch.go
@@ -16,6 +16,7 @@ const (
ARM
ARM64
I386
+ MIPS
MIPS64
PPC64
S390X
@@ -97,6 +98,26 @@ var ArchARM64 = &Arch{
MinLC: 4,
}
+var ArchMIPS = &Arch{
+ Name: "mips",
+ Family: MIPS,
+ ByteOrder: binary.BigEndian,
+ IntSize: 4,
+ PtrSize: 4,
+ RegSize: 4,
+ MinLC: 4,
+}
+
+var ArchMIPSLE = &Arch{
+ Name: "mipsle",
+ Family: MIPS,
+ ByteOrder: binary.LittleEndian,
+ IntSize: 4,
+ PtrSize: 4,
+ RegSize: 4,
+ MinLC: 4,
+}
+
var ArchMIPS64 = &Arch{
Name: "mips64",
Family: MIPS64,
@@ -146,3 +167,18 @@ var ArchS390X = &Arch{
RegSize: 8,
MinLC: 2,
}
+
+var Archs = [...]*Arch{
+ Arch386,
+ ArchAMD64,
+ ArchAMD64P32,
+ ArchARM,
+ ArchARM64,
+ ArchMIPS,
+ ArchMIPSLE,
+ ArchMIPS64,
+ ArchMIPS64LE,
+ ArchPPC64,
+ ArchPPC64LE,
+ ArchS390X,
+}
diff --git a/src/cmd/link/doc.go b/src/cmd/link/doc.go
index ffaead7..16fddf2 100644
--- a/src/cmd/link/doc.go
+++ b/src/cmd/link/doc.go
@@ -85,6 +85,8 @@ Flags:
Link with C/C++ memory sanitizer support.
-o file
Write output to file (default a.out, or a.out.exe on Windows).
+ -pluginpath path
+ The path name used to prefix exported plugin symbols.
-r dir1:dir2:...
Set the ELF dynamic linker search path.
-race
diff --git a/src/cmd/link/internal/amd64/asm.go b/src/cmd/link/internal/amd64/asm.go
index eff9a22..60bd45c 100644
--- a/src/cmd/link/internal/amd64/asm.go
+++ b/src/cmd/link/internal/amd64/asm.go
@@ -1,5 +1,5 @@
// Inferno utils/6l/asm.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6l/asm.c
+// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/asm.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth at terzarima.net)
@@ -34,7 +34,6 @@ import (
"cmd/internal/obj"
"cmd/link/internal/ld"
"debug/elf"
- "fmt"
"log"
)
@@ -42,11 +41,11 @@ func PADDR(x uint32) uint32 {
return x &^ 0x80000000
}
-func Addcall(ctxt *ld.Link, s *ld.LSym, t *ld.LSym) int64 {
+func Addcall(ctxt *ld.Link, s *ld.Symbol, t *ld.Symbol) int64 {
s.Attr |= ld.AttrReachable
i := s.Size
s.Size += 4
- ld.Symgrow(ctxt, s, s.Size)
+ ld.Symgrow(s, s.Size)
r := ld.Addrel(s)
r.Sym = t
r.Off = int32(i)
@@ -55,78 +54,80 @@ func Addcall(ctxt *ld.Link, s *ld.LSym, t *ld.LSym) int64 {
return i + int64(r.Siz)
}
-func gentext() {
- if !ld.DynlinkingGo() {
+func gentext(ctxt *ld.Link) {
+ if !ctxt.DynlinkingGo() {
return
}
- addmoduledata := ld.Linklookup(ld.Ctxt, "runtime.addmoduledata", 0)
- if addmoduledata.Type == obj.STEXT {
+ addmoduledata := ctxt.Syms.Lookup("runtime.addmoduledata", 0)
+ if addmoduledata.Type == obj.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 := ld.Linklookup(ld.Ctxt, "go.link.addmoduledata", 0)
+ initfunc := ctxt.Syms.Lookup("go.link.addmoduledata", 0)
initfunc.Type = obj.STEXT
initfunc.Attr |= ld.AttrLocal
initfunc.Attr |= ld.AttrReachable
o := func(op ...uint8) {
for _, op1 := range op {
- ld.Adduint8(ld.Ctxt, initfunc, op1)
+ ld.Adduint8(ctxt, initfunc, op1)
}
}
// 0000000000000000 <local.dso_init>:
// 0: 48 8d 3d 00 00 00 00 lea 0x0(%rip),%rdi # 7 <local.dso_init+0x7>
// 3: R_X86_64_PC32 runtime.firstmoduledata-0x4
o(0x48, 0x8d, 0x3d)
- ld.Addpcrelplus(ld.Ctxt, initfunc, ld.Ctxt.Moduledata, 0)
+ ld.Addpcrelplus(ctxt, initfunc, ctxt.Moduledata, 0)
// 7: e8 00 00 00 00 callq c <local.dso_init+0xc>
// 8: R_X86_64_PLT32 runtime.addmoduledata-0x4
o(0xe8)
- Addcall(ld.Ctxt, initfunc, addmoduledata)
+ Addcall(ctxt, initfunc, addmoduledata)
// c: c3 retq
o(0xc3)
- ld.Ctxt.Textp = append(ld.Ctxt.Textp, initfunc)
- initarray_entry := ld.Linklookup(ld.Ctxt, "go.link.addmoduledatainit", 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.AttrReachable
initarray_entry.Attr |= ld.AttrLocal
initarray_entry.Type = obj.SINITARR
- ld.Addaddr(ld.Ctxt, initarray_entry, initfunc)
+ ld.Addaddr(ctxt, initarray_entry, initfunc)
}
-func adddynrel(s *ld.LSym, r *ld.Reloc) {
+func adddynrel(ctxt *ld.Link, s *ld.Symbol, r *ld.Reloc) bool {
targ := r.Sym
- ld.Ctxt.Cursym = s
switch r.Type {
default:
if r.Type >= 256 {
- ld.Diag("unexpected relocation type %d", r.Type)
- return
+ ld.Errorf(s, "unexpected relocation type %d", r.Type)
+ return false
}
// Handle relocations found in ELF object files.
case 256 + ld.R_X86_64_PC32:
if targ.Type == obj.SDYNIMPORT {
- ld.Diag("unexpected R_X86_64_PC32 relocation for dynamic symbol %s", targ.Name)
+ ld.Errorf(s, "unexpected R_X86_64_PC32 relocation for dynamic symbol %s", targ.Name)
}
if targ.Type == 0 || targ.Type == obj.SXREF {
- ld.Diag("unknown symbol %s in pcrel", targ.Name)
+ ld.Errorf(s, "unknown symbol %s in pcrel", targ.Name)
}
r.Type = obj.R_PCREL
r.Add += 4
- return
+ return true
case 256 + ld.R_X86_64_PLT32:
r.Type = obj.R_PCREL
r.Add += 4
if targ.Type == obj.SDYNIMPORT {
- addpltsym(targ)
- r.Sym = ld.Linklookup(ld.Ctxt, ".plt", 0)
+ addpltsym(ctxt, targ)
+ r.Sym = ctxt.Syms.Lookup(".plt", 0)
r.Add += int64(targ.Plt)
}
- return
+ 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 {
@@ -137,26 +138,26 @@ func adddynrel(s *ld.LSym, r *ld.Reloc) {
r.Type = obj.R_PCREL
r.Add += 4
- return
+ return true
}
}
// fall back to using GOT and hope for the best (CMOV*)
// TODO: just needs relocation, no need to put in .dynsym
- addgotsym(targ)
+ addgotsym(ctxt, targ)
r.Type = obj.R_PCREL
- r.Sym = ld.Linklookup(ld.Ctxt, ".got", 0)
+ r.Sym = ctxt.Syms.Lookup(".got", 0)
r.Add += 4
r.Add += int64(targ.Got)
- return
+ return true
case 256 + ld.R_X86_64_64:
if targ.Type == obj.SDYNIMPORT {
- ld.Diag("unexpected R_X86_64_64 relocation for dynamic symbol %s", targ.Name)
+ ld.Errorf(s, "unexpected R_X86_64_64 relocation for dynamic symbol %s", targ.Name)
}
r.Type = obj.R_ADDR
- return
+ return true
// Handle relocations found in Mach-O object files.
case 512 + ld.MACHO_X86_64_RELOC_UNSIGNED*2 + 0,
@@ -166,17 +167,17 @@ func adddynrel(s *ld.LSym, r *ld.Reloc) {
r.Type = obj.R_ADDR
if targ.Type == obj.SDYNIMPORT {
- ld.Diag("unexpected reloc for dynamic symbol %s", targ.Name)
+ ld.Errorf(s, "unexpected reloc for dynamic symbol %s", targ.Name)
}
- return
+ return true
case 512 + ld.MACHO_X86_64_RELOC_BRANCH*2 + 1:
if targ.Type == obj.SDYNIMPORT {
- addpltsym(targ)
- r.Sym = ld.Linklookup(ld.Ctxt, ".plt", 0)
+ addpltsym(ctxt, targ)
+ r.Sym = ctxt.Syms.Lookup(".plt", 0)
r.Add = int64(targ.Plt)
r.Type = obj.R_PCREL
- return
+ return true
}
fallthrough
@@ -189,92 +190,134 @@ func adddynrel(s *ld.LSym, r *ld.Reloc) {
r.Type = obj.R_PCREL
if targ.Type == obj.SDYNIMPORT {
- ld.Diag("unexpected pc-relative reloc for dynamic symbol %s", targ.Name)
+ ld.Errorf(s, "unexpected pc-relative reloc for dynamic symbol %s", targ.Name)
}
- return
+ return true
case 512 + ld.MACHO_X86_64_RELOC_GOT_LOAD*2 + 1:
if targ.Type != obj.SDYNIMPORT {
// have symbol
// turn MOVQ of GOT entry into LEAQ of symbol itself
if r.Off < 2 || s.P[r.Off-2] != 0x8b {
- ld.Diag("unexpected GOT_LOAD reloc for non-dynamic symbol %s", targ.Name)
- return
+ ld.Errorf(s, "unexpected GOT_LOAD reloc for non-dynamic symbol %s", targ.Name)
+ return false
}
s.P[r.Off-2] = 0x8d
r.Type = obj.R_PCREL
- return
+ return true
}
fallthrough
// fall through
case 512 + ld.MACHO_X86_64_RELOC_GOT*2 + 1:
if targ.Type != obj.SDYNIMPORT {
- ld.Diag("unexpected GOT reloc for non-dynamic symbol %s", targ.Name)
+ ld.Errorf(s, "unexpected GOT reloc for non-dynamic symbol %s", targ.Name)
}
- addgotsym(targ)
+ addgotsym(ctxt, targ)
r.Type = obj.R_PCREL
- r.Sym = ld.Linklookup(ld.Ctxt, ".got", 0)
+ r.Sym = ctxt.Syms.Lookup(".got", 0)
r.Add += int64(targ.Got)
- return
- }
-
- // Handle references to ELF symbols from our own object files.
- if targ.Type != obj.SDYNIMPORT {
- return
+ return true
}
switch r.Type {
case obj.R_CALL,
obj.R_PCREL:
- if ld.HEADTYPE == obj.Hwindows {
+ if targ.Type != obj.SDYNIMPORT {
+ // nothing to do, the relocation will be laid out in reloc
+ return true
+ }
+ if ld.Headtype == obj.Hwindows || ld.Headtype == obj.Hwindowsgui {
// nothing to do, the relocation will be laid out in pereloc1
- return
+ return true
} else {
// for both ELF and Mach-O
- addpltsym(targ)
- r.Sym = ld.Linklookup(ld.Ctxt, ".plt", 0)
+ addpltsym(ctxt, targ)
+ r.Sym = ctxt.Syms.Lookup(".plt", 0)
r.Add = int64(targ.Plt)
- return
+ return true
}
case obj.R_ADDR:
if s.Type == obj.STEXT && ld.Iself {
- if ld.HEADTYPE == obj.Hsolaris {
- addpltsym(targ)
- r.Sym = ld.Linklookup(ld.Ctxt, ".plt", 0)
+ if ld.Headtype == obj.Hsolaris {
+ addpltsym(ctxt, targ)
+ r.Sym = ctxt.Syms.Lookup(".plt", 0)
r.Add += int64(targ.Plt)
- return
+ return true
}
// The code is asking for the address of an external
// function. We provide it with the address of the
// correspondent GOT symbol.
- addgotsym(targ)
+ addgotsym(ctxt, targ)
- r.Sym = ld.Linklookup(ld.Ctxt, ".got", 0)
+ r.Sym = ctxt.Syms.Lookup(".got", 0)
r.Add += int64(targ.Got)
- return
+ return true
+ }
+
+ // Process dynamic relocations for the data sections.
+ if ld.Buildmode == ld.BuildmodePIE && ld.Linkmode == ld.LinkInternal {
+ // When internally linking, generate dynamic relocations
+ // for all typical R_ADDR relocations. The exception
+ // are those R_ADDR that are created as part of generating
+ // the dynamic relocations and must be resolved statically.
+ //
+ // There are three phases relevant to understanding this:
+ //
+ // dodata() // we are here
+ // address() // symbol address assignment
+ // reloc() // resolution of static R_ADDR relocs
+ //
+ // At this point symbol addresses have not been
+ // assigned yet (as the final size of the .rela section
+ // will affect the addresses), and so we cannot write
+ // the Elf64_Rela.r_offset now. Instead we delay it
+ // until after the 'address' phase of the linker is
+ // complete. We do this via Addaddrplus, which creates
+ // a new R_ADDR relocation which will be resolved in
+ // the 'reloc' phase.
+ //
+ // These synthetic static R_ADDR relocs must be skipped
+ // now, or else we will be caught in an infinite loop
+ // of generating synthetic relocs for our synthetic
+ // relocs.
+ switch s.Name {
+ case ".dynsym", ".rela", ".got.plt", ".dynamic":
+ return false
+ }
+ } else {
+ // Either internally linking a static executable,
+ // in which case we can resolve these relocations
+ // statically in the 'reloc' phase, or externally
+ // 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 {
+ break
+ }
}
- if s.Type != obj.SDATA {
- break
- }
if ld.Iself {
- ld.Adddynsym(ld.Ctxt, targ)
- rela := ld.Linklookup(ld.Ctxt, ".rela", 0)
- ld.Addaddrplus(ld.Ctxt, rela, s, int64(r.Off))
+ // TODO: We generate a R_X86_64_64 relocation for every R_ADDR, even
+ // though it would be more efficient (for the dynamic linker) if we
+ // generated R_X86_RELATIVE instead.
+ ld.Adddynsym(ctxt, targ)
+ rela := ctxt.Syms.Lookup(".rela", 0)
+ ld.Addaddrplus(ctxt, rela, s, int64(r.Off))
if r.Siz == 8 {
- ld.Adduint64(ld.Ctxt, rela, ld.ELF64_R_INFO(uint32(targ.Dynid), ld.R_X86_64_64))
+ ld.Adduint64(ctxt, rela, ld.ELF64_R_INFO(uint32(targ.Dynid), ld.R_X86_64_64))
} else {
- ld.Adduint64(ld.Ctxt, rela, ld.ELF64_R_INFO(uint32(targ.Dynid), ld.R_X86_64_32))
+ // TODO: never happens, remove.
+ ld.Adduint64(ctxt, rela, ld.ELF64_R_INFO(uint32(targ.Dynid), ld.R_X86_64_32))
}
- ld.Adduint64(ld.Ctxt, rela, uint64(r.Add))
+ ld.Adduint64(ctxt, rela, uint64(r.Add))
r.Type = 256 // ignore during relocsym
- return
+ return true
}
- if ld.HEADTYPE == obj.Hdarwin && s.Size == int64(ld.SysArch.PtrSize) && r.Off == 0 {
+ if ld.Headtype == obj.Hdarwin && s.Size == int64(ld.SysArch.PtrSize) && r.Off == 0 {
// Mach-O relocations are a royal pain to lay out.
// They use a compact stateful bytecode representation
// that is too much bother to deal with.
@@ -285,31 +328,30 @@ func adddynrel(s *ld.LSym, r *ld.Reloc) {
// just in case the C code assigns to the variable,
// and of course it only works for single pointers,
// but we only need to support cgo and that's all it needs.
- ld.Adddynsym(ld.Ctxt, targ)
+ ld.Adddynsym(ctxt, targ)
- got := ld.Linklookup(ld.Ctxt, ".got", 0)
+ got := ctxt.Syms.Lookup(".got", 0)
s.Type = got.Type | obj.SSUB
s.Outer = got
s.Sub = got.Sub
got.Sub = s
s.Value = got.Size
- ld.Adduint64(ld.Ctxt, got, 0)
- ld.Adduint32(ld.Ctxt, ld.Linklookup(ld.Ctxt, ".linkedit.got", 0), uint32(targ.Dynid))
+ ld.Adduint64(ctxt, got, 0)
+ ld.Adduint32(ctxt, ctxt.Syms.Lookup(".linkedit.got", 0), uint32(targ.Dynid))
r.Type = 256 // ignore during relocsym
- return
+ return true
}
- if ld.HEADTYPE == obj.Hwindows {
+ if ld.Headtype == obj.Hwindows || ld.Headtype == obj.Hwindowsgui {
// nothing to do, the relocation will be laid out in pereloc1
- return
+ return true
}
}
- ld.Ctxt.Cursym = s
- ld.Diag("unsupported relocation for dynamic symbol %s (type=%d stype=%d)", targ.Name, r.Type, targ.Type)
+ return false
}
-func elfreloc1(r *ld.Reloc, sectoff int64) int {
+func elfreloc1(ctxt *ld.Link, r *ld.Reloc, sectoff int64) int {
ld.Thearch.Vput(uint64(sectoff))
elfsym := r.Xsym.ElfsymForReloc()
@@ -343,7 +385,7 @@ func elfreloc1(r *ld.Reloc, sectoff int64) int {
case obj.R_CALL:
if r.Siz == 4 {
if r.Xsym.Type == obj.SDYNIMPORT {
- if ld.DynlinkingGo() {
+ if ctxt.DynlinkingGo() {
ld.Thearch.Vput(ld.R_X86_64_PLT32 | uint64(elfsym)<<32)
} else {
ld.Thearch.Vput(ld.R_X86_64_GOTPCREL | uint64(elfsym)<<32)
@@ -378,14 +420,14 @@ func elfreloc1(r *ld.Reloc, sectoff int64) int {
return 0
}
-func machoreloc1(r *ld.Reloc, sectoff int64) int {
+func machoreloc1(s *ld.Symbol, r *ld.Reloc, sectoff int64) int {
var v uint32
rs := r.Xsym
- if rs.Type == obj.SHOSTOBJ || r.Type == obj.R_PCREL {
+ if rs.Type == obj.SHOSTOBJ || r.Type == obj.R_PCREL || r.Type == obj.R_GOTPCREL {
if rs.Dynid < 0 {
- ld.Diag("reloc %d to non-macho symbol %s type=%d", r.Type, rs.Name, rs.Type)
+ ld.Errorf(s, "reloc %d to non-macho symbol %s type=%d", r.Type, rs.Name, rs.Type)
return -1
}
@@ -394,7 +436,7 @@ func machoreloc1(r *ld.Reloc, sectoff int64) int {
} else {
v = uint32(rs.Sect.Extnum)
if v == 0 {
- ld.Diag("reloc %d to symbol %s in non-macho section %s type=%d", r.Type, rs.Name, rs.Sect.Name, rs.Type)
+ ld.Errorf(s, "reloc %d to symbol %s in non-macho section %s type=%d", r.Type, rs.Name, rs.Sect.Name, rs.Type)
return -1
}
}
@@ -414,6 +456,9 @@ func machoreloc1(r *ld.Reloc, sectoff int64) int {
case obj.R_PCREL:
v |= 1 << 24 // pc-relative bit
v |= ld.MACHO_X86_64_RELOC_SIGNED << 28
+ case obj.R_GOTPCREL:
+ v |= 1 << 24 // pc-relative bit
+ v |= ld.MACHO_X86_64_RELOC_GOT_LOAD << 28
}
switch r.Siz {
@@ -438,13 +483,13 @@ func machoreloc1(r *ld.Reloc, sectoff int64) int {
return 0
}
-func pereloc1(r *ld.Reloc, sectoff int64) bool {
+func pereloc1(s *ld.Symbol, r *ld.Reloc, sectoff int64) bool {
var v uint32
rs := r.Xsym
if rs.Dynid < 0 {
- ld.Diag("reloc %d to non-coff symbol %s type=%d", r.Type, rs.Name, rs.Type)
+ ld.Errorf(s, "reloc %d to non-coff symbol %s type=%d", r.Type, rs.Name, rs.Type)
return false
}
@@ -472,84 +517,84 @@ func pereloc1(r *ld.Reloc, sectoff int64) bool {
return true
}
-func archreloc(r *ld.Reloc, s *ld.LSym, val *int64) int {
+func archreloc(ctxt *ld.Link, r *ld.Reloc, s *ld.Symbol, val *int64) int {
return -1
}
-func archrelocvariant(r *ld.Reloc, s *ld.LSym, t int64) int64 {
+func archrelocvariant(ctxt *ld.Link, r *ld.Reloc, s *ld.Symbol, t int64) int64 {
log.Fatalf("unexpected relocation variant")
return t
}
-func elfsetupplt() {
- plt := ld.Linklookup(ld.Ctxt, ".plt", 0)
- got := ld.Linklookup(ld.Ctxt, ".got.plt", 0)
+func elfsetupplt(ctxt *ld.Link) {
+ plt := ctxt.Syms.Lookup(".plt", 0)
+ got := ctxt.Syms.Lookup(".got.plt", 0)
if plt.Size == 0 {
// pushq got+8(IP)
- ld.Adduint8(ld.Ctxt, plt, 0xff)
+ ld.Adduint8(ctxt, plt, 0xff)
- ld.Adduint8(ld.Ctxt, plt, 0x35)
- ld.Addpcrelplus(ld.Ctxt, plt, got, 8)
+ ld.Adduint8(ctxt, plt, 0x35)
+ ld.Addpcrelplus(ctxt, plt, got, 8)
// jmpq got+16(IP)
- ld.Adduint8(ld.Ctxt, plt, 0xff)
+ ld.Adduint8(ctxt, plt, 0xff)
- ld.Adduint8(ld.Ctxt, plt, 0x25)
- ld.Addpcrelplus(ld.Ctxt, plt, got, 16)
+ ld.Adduint8(ctxt, plt, 0x25)
+ ld.Addpcrelplus(ctxt, plt, got, 16)
// nopl 0(AX)
- ld.Adduint32(ld.Ctxt, plt, 0x00401f0f)
+ ld.Adduint32(ctxt, plt, 0x00401f0f)
// assume got->size == 0 too
- ld.Addaddrplus(ld.Ctxt, got, ld.Linklookup(ld.Ctxt, ".dynamic", 0), 0)
+ ld.Addaddrplus(ctxt, got, ctxt.Syms.Lookup(".dynamic", 0), 0)
- ld.Adduint64(ld.Ctxt, got, 0)
- ld.Adduint64(ld.Ctxt, got, 0)
+ ld.Adduint64(ctxt, got, 0)
+ ld.Adduint64(ctxt, got, 0)
}
}
-func addpltsym(s *ld.LSym) {
+func addpltsym(ctxt *ld.Link, s *ld.Symbol) {
if s.Plt >= 0 {
return
}
- ld.Adddynsym(ld.Ctxt, s)
+ ld.Adddynsym(ctxt, s)
if ld.Iself {
- plt := ld.Linklookup(ld.Ctxt, ".plt", 0)
- got := ld.Linklookup(ld.Ctxt, ".got.plt", 0)
- rela := ld.Linklookup(ld.Ctxt, ".rela.plt", 0)
+ plt := ctxt.Syms.Lookup(".plt", 0)
+ got := ctxt.Syms.Lookup(".got.plt", 0)
+ rela := ctxt.Syms.Lookup(".rela.plt", 0)
if plt.Size == 0 {
- elfsetupplt()
+ elfsetupplt(ctxt)
}
// jmpq *got+size(IP)
- ld.Adduint8(ld.Ctxt, plt, 0xff)
+ ld.Adduint8(ctxt, plt, 0xff)
- ld.Adduint8(ld.Ctxt, plt, 0x25)
- ld.Addpcrelplus(ld.Ctxt, plt, got, got.Size)
+ ld.Adduint8(ctxt, plt, 0x25)
+ ld.Addpcrelplus(ctxt, plt, got, got.Size)
// add to got: pointer to current pos in plt
- ld.Addaddrplus(ld.Ctxt, got, plt, plt.Size)
+ ld.Addaddrplus(ctxt, got, plt, plt.Size)
// pushq $x
- ld.Adduint8(ld.Ctxt, plt, 0x68)
+ ld.Adduint8(ctxt, plt, 0x68)
- ld.Adduint32(ld.Ctxt, plt, uint32((got.Size-24-8)/8))
+ ld.Adduint32(ctxt, plt, uint32((got.Size-24-8)/8))
// jmpq .plt
- ld.Adduint8(ld.Ctxt, plt, 0xe9)
+ ld.Adduint8(ctxt, plt, 0xe9)
- ld.Adduint32(ld.Ctxt, plt, uint32(-(plt.Size + 4)))
+ ld.Adduint32(ctxt, plt, uint32(-(plt.Size + 4)))
// rela
- ld.Addaddrplus(ld.Ctxt, rela, got, got.Size-8)
+ ld.Addaddrplus(ctxt, rela, got, got.Size-8)
- ld.Adduint64(ld.Ctxt, rela, ld.ELF64_R_INFO(uint32(s.Dynid), ld.R_X86_64_JMP_SLOT))
- ld.Adduint64(ld.Ctxt, rela, 0)
+ ld.Adduint64(ctxt, rela, ld.ELF64_R_INFO(uint32(s.Dynid), ld.R_X86_64_JMP_SLOT))
+ ld.Adduint64(ctxt, rela, 0)
s.Plt = int32(plt.Size - 16)
- } else if ld.HEADTYPE == obj.Hdarwin {
+ } else if ld.Headtype == obj.Hdarwin {
// To do lazy symbol lookup right, we're supposed
// to tell the dynamic loader which library each
// symbol comes from and format the link info
@@ -560,54 +605,52 @@ func addpltsym(s *ld.LSym) {
// http://networkpx.blogspot.com/2009/09/about-lcdyldinfoonly-command.html
// has details about what we're avoiding.
- addgotsym(s)
- plt := ld.Linklookup(ld.Ctxt, ".plt", 0)
+ addgotsym(ctxt, s)
+ plt := ctxt.Syms.Lookup(".plt", 0)
- ld.Adduint32(ld.Ctxt, ld.Linklookup(ld.Ctxt, ".linkedit.plt", 0), uint32(s.Dynid))
+ ld.Adduint32(ctxt, ctxt.Syms.Lookup(".linkedit.plt", 0), uint32(s.Dynid))
// jmpq *got+size(IP)
s.Plt = int32(plt.Size)
- ld.Adduint8(ld.Ctxt, plt, 0xff)
- ld.Adduint8(ld.Ctxt, plt, 0x25)
- ld.Addpcrelplus(ld.Ctxt, plt, ld.Linklookup(ld.Ctxt, ".got", 0), int64(s.Got))
+ ld.Adduint8(ctxt, plt, 0xff)
+ ld.Adduint8(ctxt, plt, 0x25)
+ ld.Addpcrelplus(ctxt, plt, ctxt.Syms.Lookup(".got", 0), int64(s.Got))
} else {
- ld.Diag("addpltsym: unsupported binary format")
+ ld.Errorf(s, "addpltsym: unsupported binary format")
}
}
-func addgotsym(s *ld.LSym) {
+func addgotsym(ctxt *ld.Link, s *ld.Symbol) {
if s.Got >= 0 {
return
}
- ld.Adddynsym(ld.Ctxt, s)
- got := ld.Linklookup(ld.Ctxt, ".got", 0)
+ ld.Adddynsym(ctxt, s)
+ got := ctxt.Syms.Lookup(".got", 0)
s.Got = int32(got.Size)
- ld.Adduint64(ld.Ctxt, got, 0)
+ ld.Adduint64(ctxt, got, 0)
if ld.Iself {
- rela := ld.Linklookup(ld.Ctxt, ".rela", 0)
- ld.Addaddrplus(ld.Ctxt, rela, got, int64(s.Got))
- ld.Adduint64(ld.Ctxt, rela, ld.ELF64_R_INFO(uint32(s.Dynid), ld.R_X86_64_GLOB_DAT))
- ld.Adduint64(ld.Ctxt, rela, 0)
- } else if ld.HEADTYPE == obj.Hdarwin {
- ld.Adduint32(ld.Ctxt, ld.Linklookup(ld.Ctxt, ".linkedit.got", 0), uint32(s.Dynid))
+ rela := ctxt.Syms.Lookup(".rela", 0)
+ 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 {
+ ld.Adduint32(ctxt, ctxt.Syms.Lookup(".linkedit.got", 0), uint32(s.Dynid))
} else {
- ld.Diag("addgotsym: unsupported binary format")
+ ld.Errorf(s, "addgotsym: unsupported binary format")
}
}
-func asmb() {
- if ld.Debug['v'] != 0 {
- fmt.Fprintf(ld.Bso, "%5.2f asmb\n", obj.Cputime())
+func asmb(ctxt *ld.Link) {
+ if ctxt.Debugvlog != 0 {
+ ctxt.Logf("%5.2f asmb\n", obj.Cputime())
}
- ld.Bso.Flush()
- if ld.Debug['v'] != 0 {
- fmt.Fprintf(ld.Bso, "%5.2f codeblk\n", obj.Cputime())
+ if ctxt.Debugvlog != 0 {
+ ctxt.Logf("%5.2f codeblk\n", obj.Cputime())
}
- ld.Bso.Flush()
if ld.Iself {
ld.Asmbelfsetup()
@@ -616,48 +659,52 @@ func asmb() {
sect := ld.Segtext.Sect
ld.Cseek(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
// 0xCC is INT $3 - breakpoint instruction
- ld.CodeblkPad(int64(sect.Vaddr), int64(sect.Length), []byte{0xCC})
+ ld.CodeblkPad(ctxt, int64(sect.Vaddr), int64(sect.Length), []byte{0xCC})
for sect = sect.Next; sect != nil; sect = sect.Next {
ld.Cseek(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
- ld.Datblk(int64(sect.Vaddr), int64(sect.Length))
+ ld.Datblk(ctxt, int64(sect.Vaddr), int64(sect.Length))
}
if ld.Segrodata.Filelen > 0 {
- if ld.Debug['v'] != 0 {
- fmt.Fprintf(ld.Bso, "%5.2f rodatblk\n", obj.Cputime())
+ if ctxt.Debugvlog != 0 {
+ ctxt.Logf("%5.2f rodatblk\n", obj.Cputime())
}
- ld.Bso.Flush()
-
ld.Cseek(int64(ld.Segrodata.Fileoff))
- ld.Datblk(int64(ld.Segrodata.Vaddr), int64(ld.Segrodata.Filelen))
+ 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())
+ }
+ ld.Cseek(int64(ld.Segrelrodata.Fileoff))
+ ld.Datblk(ctxt, int64(ld.Segrelrodata.Vaddr), int64(ld.Segrelrodata.Filelen))
}
- if ld.Debug['v'] != 0 {
- fmt.Fprintf(ld.Bso, "%5.2f datblk\n", obj.Cputime())
+ if ctxt.Debugvlog != 0 {
+ ctxt.Logf("%5.2f datblk\n", obj.Cputime())
}
- ld.Bso.Flush()
ld.Cseek(int64(ld.Segdata.Fileoff))
- ld.Datblk(int64(ld.Segdata.Vaddr), int64(ld.Segdata.Filelen))
+ ld.Datblk(ctxt, int64(ld.Segdata.Vaddr), int64(ld.Segdata.Filelen))
ld.Cseek(int64(ld.Segdwarf.Fileoff))
- ld.Dwarfblk(int64(ld.Segdwarf.Vaddr), int64(ld.Segdwarf.Filelen))
+ ld.Dwarfblk(ctxt, int64(ld.Segdwarf.Vaddr), int64(ld.Segdwarf.Filelen))
machlink := int64(0)
- if ld.HEADTYPE == obj.Hdarwin {
- machlink = ld.Domacholink()
+ if ld.Headtype == obj.Hdarwin {
+ machlink = ld.Domacholink(ctxt)
}
- switch ld.HEADTYPE {
+ switch ld.Headtype {
default:
- ld.Diag("unknown header type %d", ld.HEADTYPE)
+ ld.Errorf(nil, "unknown header type %v", ld.Headtype)
fallthrough
case obj.Hplan9:
break
case obj.Hdarwin:
- ld.Debug['8'] = 1 /* 64-bit addresses */
+ ld.Flag8 = true /* 64-bit addresses */
case obj.Hlinux,
obj.Hfreebsd,
@@ -665,10 +712,11 @@ func asmb() {
obj.Hopenbsd,
obj.Hdragonfly,
obj.Hsolaris:
- ld.Debug['8'] = 1 /* 64-bit addresses */
+ ld.Flag8 = true /* 64-bit addresses */
case obj.Hnacl,
- obj.Hwindows:
+ obj.Hwindows,
+ obj.Hwindowsgui:
break
}
@@ -676,19 +724,18 @@ func asmb() {
ld.Spsize = 0
ld.Lcsize = 0
symo := int64(0)
- if ld.Debug['s'] == 0 {
- if ld.Debug['v'] != 0 {
- fmt.Fprintf(ld.Bso, "%5.2f sym\n", obj.Cputime())
+ if !*ld.FlagS {
+ if ctxt.Debugvlog != 0 {
+ ctxt.Logf("%5.2f sym\n", obj.Cputime())
}
- ld.Bso.Flush()
- switch ld.HEADTYPE {
+ switch ld.Headtype {
default:
case obj.Hplan9:
- ld.Debug['s'] = 1
+ *ld.FlagS = true
symo = int64(ld.Segdata.Fileoff + ld.Segdata.Filelen)
case obj.Hdarwin:
- symo = int64(ld.Segdwarf.Fileoff + uint64(ld.Rnd(int64(ld.Segdwarf.Filelen), int64(ld.INITRND))) + uint64(machlink))
+ symo = int64(ld.Segdwarf.Fileoff + uint64(ld.Rnd(int64(ld.Segdwarf.Filelen), int64(*ld.FlagRound))) + uint64(machlink))
case obj.Hlinux,
obj.Hfreebsd,
@@ -698,36 +745,37 @@ func asmb() {
obj.Hsolaris,
obj.Hnacl:
symo = int64(ld.Segdwarf.Fileoff + ld.Segdwarf.Filelen)
- symo = ld.Rnd(symo, int64(ld.INITRND))
+ symo = ld.Rnd(symo, int64(*ld.FlagRound))
- case obj.Hwindows:
+ case obj.Hwindows,
+ obj.Hwindowsgui:
symo = int64(ld.Segdwarf.Fileoff + ld.Segdwarf.Filelen)
symo = ld.Rnd(symo, ld.PEFILEALIGN)
}
ld.Cseek(symo)
- switch ld.HEADTYPE {
+ switch ld.Headtype {
default:
if ld.Iself {
ld.Cseek(symo)
- ld.Asmelfsym()
+ ld.Asmelfsym(ctxt)
ld.Cflush()
ld.Cwrite(ld.Elfstrdat)
- if ld.Debug['v'] != 0 {
- fmt.Fprintf(ld.Bso, "%5.2f dwarf\n", obj.Cputime())
+ if ctxt.Debugvlog != 0 {
+ ctxt.Logf("%5.2f dwarf\n", obj.Cputime())
}
if ld.Linkmode == ld.LinkExternal {
- ld.Elfemitreloc()
+ ld.Elfemitreloc(ctxt)
}
}
case obj.Hplan9:
- ld.Asmplan9sym()
+ ld.Asmplan9sym(ctxt)
ld.Cflush()
- sym := ld.Linklookup(ld.Ctxt, "pclntab", 0)
+ sym := ctxt.Syms.Lookup("pclntab", 0)
if sym != nil {
ld.Lcsize = int32(len(sym.P))
for i := 0; int32(i) < ld.Lcsize; i++ {
@@ -737,24 +785,23 @@ func asmb() {
ld.Cflush()
}
- case obj.Hwindows:
- if ld.Debug['v'] != 0 {
- fmt.Fprintf(ld.Bso, "%5.2f dwarf\n", obj.Cputime())
+ case obj.Hwindows, obj.Hwindowsgui:
+ if ctxt.Debugvlog != 0 {
+ ctxt.Logf("%5.2f dwarf\n", obj.Cputime())
}
case obj.Hdarwin:
if ld.Linkmode == ld.LinkExternal {
- ld.Machoemitreloc()
+ ld.Machoemitreloc(ctxt)
}
}
}
- if ld.Debug['v'] != 0 {
- fmt.Fprintf(ld.Bso, "%5.2f headr\n", obj.Cputime())
+ if ctxt.Debugvlog != 0 {
+ ctxt.Logf("%5.2f headr\n", obj.Cputime())
}
- ld.Bso.Flush()
ld.Cseek(0)
- switch ld.HEADTYPE {
+ switch ld.Headtype {
default:
case obj.Hplan9: /* plan9 */
magic := int32(4*26*26 + 7)
@@ -765,14 +812,14 @@ func asmb() {
ld.Lputb(uint32(ld.Segdata.Filelen))
ld.Lputb(uint32(ld.Segdata.Length - ld.Segdata.Filelen))
ld.Lputb(uint32(ld.Symsize)) /* nsyms */
- vl := ld.Entryvalue()
+ vl := ld.Entryvalue(ctxt)
ld.Lputb(PADDR(uint32(vl))) /* va of entry */
ld.Lputb(uint32(ld.Spsize)) /* sp offsets */
ld.Lputb(uint32(ld.Lcsize)) /* line offsets */
ld.Vputb(uint64(vl)) /* va of entry */
case obj.Hdarwin:
- ld.Asmbmacho()
+ ld.Asmbmacho(ctxt)
case obj.Hlinux,
obj.Hfreebsd,
@@ -781,11 +828,48 @@ func asmb() {
obj.Hdragonfly,
obj.Hsolaris,
obj.Hnacl:
- ld.Asmbelf(symo)
+ ld.Asmbelf(ctxt, symo)
- case obj.Hwindows:
- ld.Asmbpe()
+ case obj.Hwindows,
+ obj.Hwindowsgui:
+ ld.Asmbpe(ctxt)
}
ld.Cflush()
}
+
+func tlsIEtoLE(s *ld.Symbol, off, size int) {
+ // Transform the PC-relative instruction into a constant load.
+ // That is,
+ //
+ // MOVQ X(IP), REG -> MOVQ $Y, REG
+ //
+ // To determine the instruction and register, we study the op codes.
+ // Consult an AMD64 instruction encoding guide to decipher this.
+ if off < 3 {
+ log.Fatal("R_X86_64_GOTTPOFF reloc not preceded by MOVQ or ADDQ instruction")
+ }
+ op := s.P[off-3 : off]
+ reg := op[2] >> 3
+
+ if op[1] == 0x8b || reg == 4 {
+ // MOVQ
+ if op[0] == 0x4c {
+ op[0] = 0x49
+ } else if size == 4 && op[0] == 0x44 {
+ op[0] = 0x41
+ }
+ if op[1] == 0x8b {
+ op[1] = 0xc7
+ } else {
+ op[1] = 0x81 // special case for SP
+ }
+ op[2] = 0xc0 | reg
+ } else {
+ // An alternate op is ADDQ. This is handled by GNU gold,
+ // but right now is not generated by the Go compiler:
+ // ADDQ X(IP), REG -> ADDQ $Y, REG
+ // Consider adding support for it here.
+ log.Fatalf("expected TLS IE op to be MOVQ, got %v", op)
+ }
+}
diff --git a/src/cmd/link/internal/amd64/l.go b/src/cmd/link/internal/amd64/l.go
index 05f7fa3..393da6b 100644
--- a/src/cmd/link/internal/amd64/l.go
+++ b/src/cmd/link/internal/amd64/l.go
@@ -1,5 +1,5 @@
// Inferno utils/6l/l.h
-// http://code.google.com/p/inferno-os/source/browse/utils/6l/l.h
+// 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)
@@ -31,13 +31,13 @@
package amd64
const (
- MaxAlign = 32 // max data alignment
- MinAlign = 1 // min data alignment
- FuncAlign = 16
+ maxAlign = 32 // max data alignment
+ minAlign = 1 // min data alignment
+ funcAlign = 16
)
/* Used by ../internal/ld/dwarf.go */
const (
- DWARFREGSP = 7
- DWARFREGLR = 16
+ dwarfRegSP = 7
+ dwarfRegLR = 16
)
diff --git a/src/cmd/link/internal/amd64/obj.go b/src/cmd/link/internal/amd64/obj.go
index f62f237..9646b60 100644
--- a/src/cmd/link/internal/amd64/obj.go
+++ b/src/cmd/link/internal/amd64/obj.go
@@ -1,5 +1,5 @@
// Inferno utils/6l/obj.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6l/obj.c
+// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/obj.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth at terzarima.net)
@@ -35,27 +35,19 @@ import (
"cmd/internal/sys"
"cmd/link/internal/ld"
"fmt"
- "log"
)
-// Reading object files.
-
-func Main() {
- linkarchinit()
- ld.Ldmain()
-}
-
-func linkarchinit() {
+func Init() {
ld.SysArch = sys.ArchAMD64
- if obj.Getgoarch() == "amd64p32" {
+ if obj.GOARCH == "amd64p32" {
ld.SysArch = sys.ArchAMD64P32
}
- ld.Thearch.Funcalign = FuncAlign
- ld.Thearch.Maxalign = MaxAlign
- ld.Thearch.Minalign = MinAlign
- ld.Thearch.Dwarfregsp = DWARFREGSP
- ld.Thearch.Dwarfreglr = DWARFREGLR
+ ld.Thearch.Funcalign = funcAlign
+ ld.Thearch.Maxalign = maxAlign
+ ld.Thearch.Minalign = minAlign
+ ld.Thearch.Dwarfregsp = dwarfRegSP
+ ld.Thearch.Dwarfreglr = dwarfRegLR
ld.Thearch.Adddynrel = adddynrel
ld.Thearch.Archinit = archinit
@@ -73,6 +65,7 @@ func linkarchinit() {
ld.Thearch.Append16 = ld.Append16l
ld.Thearch.Append32 = ld.Append32l
ld.Thearch.Append64 = ld.Append64l
+ ld.Thearch.TLSIEtoLE = tlsIEtoLE
ld.Thearch.Linuxdynld = "/lib64/ld-linux-x86-64.so.2"
ld.Thearch.Freebsddynld = "/libexec/ld-elf.so.1"
@@ -82,67 +75,36 @@ func linkarchinit() {
ld.Thearch.Solarisdynld = "/lib/amd64/ld.so.1"
}
-func archinit() {
- // getgoextlinkenabled is based on GO_EXTLINK_ENABLED when
- // Go was built; see ../../make.bash.
- if ld.Linkmode == ld.LinkAuto && obj.Getgoextlinkenabled() == "0" {
- ld.Linkmode = ld.LinkInternal
- }
-
- if ld.Buildmode == ld.BuildmodeCArchive || ld.Buildmode == ld.BuildmodeCShared || ld.DynlinkingGo() {
- ld.Linkmode = ld.LinkExternal
- }
-
- switch ld.HEADTYPE {
- default:
- if ld.Linkmode == ld.LinkAuto {
- ld.Linkmode = ld.LinkInternal
- }
- if ld.Linkmode == ld.LinkExternal && obj.Getgoextlinkenabled() != "1" {
- log.Fatalf("cannot use -linkmode=external with -H %s", ld.Headstr(int(ld.HEADTYPE)))
- }
-
- case obj.Hdarwin,
- obj.Hdragonfly,
- obj.Hfreebsd,
- obj.Hlinux,
- obj.Hnacl,
- obj.Hnetbsd,
- obj.Hopenbsd,
- obj.Hsolaris,
- obj.Hwindows:
- break
- }
-
- switch ld.HEADTYPE {
+func archinit(ctxt *ld.Link) {
+ switch ld.Headtype {
default:
- ld.Exitf("unknown -H option: %v", ld.HEADTYPE)
+ ld.Exitf("unknown -H option: %v", ld.Headtype)
case obj.Hplan9: /* plan 9 */
ld.HEADR = 32 + 8
- if ld.INITTEXT == -1 {
- ld.INITTEXT = 0x200000 + int64(ld.HEADR)
+ if *ld.FlagTextAddr == -1 {
+ *ld.FlagTextAddr = 0x200000 + int64(ld.HEADR)
}
- if ld.INITDAT == -1 {
- ld.INITDAT = 0
+ if *ld.FlagDataAddr == -1 {
+ *ld.FlagDataAddr = 0
}
- if ld.INITRND == -1 {
- ld.INITRND = 0x200000
+ if *ld.FlagRound == -1 {
+ *ld.FlagRound = 0x200000
}
case obj.Hdarwin: /* apple MACH */
ld.Machoinit()
ld.HEADR = ld.INITIAL_MACHO_HEADR
- if ld.INITRND == -1 {
- ld.INITRND = 4096
+ if *ld.FlagRound == -1 {
+ *ld.FlagRound = 4096
}
- if ld.INITTEXT == -1 {
- ld.INITTEXT = 4096 + int64(ld.HEADR)
+ if *ld.FlagTextAddr == -1 {
+ *ld.FlagTextAddr = 0x1000000 + int64(ld.HEADR)
}
- if ld.INITDAT == -1 {
- ld.INITDAT = 0
+ if *ld.FlagDataAddr == -1 {
+ *ld.FlagDataAddr = 0
}
case obj.Hlinux, /* elf64 executable */
@@ -151,50 +113,50 @@ func archinit() {
obj.Hopenbsd, /* openbsd */
obj.Hdragonfly, /* dragonfly */
obj.Hsolaris: /* solaris */
- ld.Elfinit()
+ ld.Elfinit(ctxt)
ld.HEADR = ld.ELFRESERVE
- if ld.INITTEXT == -1 {
- ld.INITTEXT = (1 << 22) + int64(ld.HEADR)
+ if *ld.FlagTextAddr == -1 {
+ *ld.FlagTextAddr = (1 << 22) + int64(ld.HEADR)
}
- if ld.INITDAT == -1 {
- ld.INITDAT = 0
+ if *ld.FlagDataAddr == -1 {
+ *ld.FlagDataAddr = 0
}
- if ld.INITRND == -1 {
- ld.INITRND = 4096
+ if *ld.FlagRound == -1 {
+ *ld.FlagRound = 4096
}
case obj.Hnacl:
- ld.Elfinit()
- ld.Debug['w']++ // disable dwarf, which gets confused and is useless anyway
+ ld.Elfinit(ctxt)
+ *ld.FlagW = true // disable dwarf, which gets confused and is useless anyway
ld.HEADR = 0x10000
ld.Funcalign = 32
- if ld.INITTEXT == -1 {
- ld.INITTEXT = 0x20000
+ if *ld.FlagTextAddr == -1 {
+ *ld.FlagTextAddr = 0x20000
}
- if ld.INITDAT == -1 {
- ld.INITDAT = 0
+ if *ld.FlagDataAddr == -1 {
+ *ld.FlagDataAddr = 0
}
- if ld.INITRND == -1 {
- ld.INITRND = 0x10000
+ if *ld.FlagRound == -1 {
+ *ld.FlagRound = 0x10000
}
- case obj.Hwindows: /* PE executable */
- ld.Peinit()
+ case obj.Hwindows, obj.Hwindowsgui: /* PE executable */
+ ld.Peinit(ctxt)
ld.HEADR = ld.PEFILEHEADR
- if ld.INITTEXT == -1 {
- ld.INITTEXT = ld.PEBASE + int64(ld.PESECTHEADR)
+ if *ld.FlagTextAddr == -1 {
+ *ld.FlagTextAddr = ld.PEBASE + int64(ld.PESECTHEADR)
}
- if ld.INITDAT == -1 {
- ld.INITDAT = 0
+ if *ld.FlagDataAddr == -1 {
+ *ld.FlagDataAddr = 0
}
- if ld.INITRND == -1 {
- ld.INITRND = ld.PESECTALIGN
+ if *ld.FlagRound == -1 {
+ *ld.FlagRound = ld.PESECTALIGN
}
}
- if ld.INITDAT != 0 && ld.INITRND != 0 {
- fmt.Printf("warning: -D0x%x is ignored because of -R0x%x\n", uint64(ld.INITDAT), uint32(ld.INITRND))
+ if *ld.FlagDataAddr != 0 && *ld.FlagRound != 0 {
+ fmt.Printf("warning: -D0x%x is ignored because of -R0x%x\n", uint64(*ld.FlagDataAddr), uint32(*ld.FlagRound))
}
}
diff --git a/src/cmd/link/internal/arm/asm.go b/src/cmd/link/internal/arm/asm.go
index 0c3e957..ee57df1 100644
--- a/src/cmd/link/internal/arm/asm.go
+++ b/src/cmd/link/internal/arm/asm.go
@@ -1,5 +1,5 @@
// Inferno utils/5l/asm.c
-// http://code.google.com/p/inferno-os/source/browse/utils/5l/asm.c
+// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5l/asm.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth at terzarima.net)
@@ -58,23 +58,23 @@ import (
// c: 00000004 .word 0x00000004
// c: R_ARM_GOT_PREL local.moduledata
-func gentext() {
- if !ld.DynlinkingGo() {
+func gentext(ctxt *ld.Link) {
+ if !ctxt.DynlinkingGo() {
return
}
- addmoduledata := ld.Linklookup(ld.Ctxt, "runtime.addmoduledata", 0)
- if addmoduledata.Type == obj.STEXT {
+ addmoduledata := ctxt.Syms.Lookup("runtime.addmoduledata", 0)
+ if addmoduledata.Type == obj.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 := ld.Linklookup(ld.Ctxt, "go.link.addmoduledata", 0)
+ initfunc := ctxt.Syms.Lookup("go.link.addmoduledata", 0)
initfunc.Type = obj.STEXT
initfunc.Attr |= ld.AttrLocal
initfunc.Attr |= ld.AttrReachable
o := func(op uint32) {
- ld.Adduint32(ld.Ctxt, initfunc, op)
+ ld.Adduint32(ctxt, initfunc, op)
}
o(0xe59f0004)
o(0xe08f0000)
@@ -83,7 +83,7 @@ func gentext() {
rel := ld.Addrel(initfunc)
rel.Off = 8
rel.Siz = 4
- rel.Sym = ld.Linklookup(ld.Ctxt, "runtime.addmoduledata", 0)
+ rel.Sym = ctxt.Syms.Lookup("runtime.addmoduledata", 0)
rel.Type = obj.R_CALLARM
rel.Add = 0xeafffffe // vomit
@@ -91,16 +91,19 @@ func gentext() {
rel = ld.Addrel(initfunc)
rel.Off = 12
rel.Siz = 4
- rel.Sym = ld.Ctxt.Moduledata
+ rel.Sym = ctxt.Moduledata
rel.Type = obj.R_PCREL
rel.Add = 4
- ld.Ctxt.Textp = append(ld.Ctxt.Textp, initfunc)
- initarray_entry := ld.Linklookup(ld.Ctxt, "go.link.addmoduledatainit", 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.AttrReachable
initarray_entry.Attr |= ld.AttrLocal
initarray_entry.Type = obj.SINITARR
- ld.Addaddr(ld.Ctxt, initarray_entry, initfunc)
+ ld.Addaddr(ctxt, initarray_entry, initfunc)
}
// Preserve highest 8 bits of a, and do addition to lower 24-bit
@@ -109,15 +112,14 @@ func braddoff(a int32, b int32) int32 {
return int32((uint32(a))&0xff000000 | 0x00ffffff&uint32(a+b))
}
-func adddynrel(s *ld.LSym, r *ld.Reloc) {
+func adddynrel(ctxt *ld.Link, s *ld.Symbol, r *ld.Reloc) bool {
targ := r.Sym
- ld.Ctxt.Cursym = s
switch r.Type {
default:
if r.Type >= 256 {
- ld.Diag("unexpected relocation type %d", r.Type)
- return
+ ld.Errorf(s, "unexpected relocation type %d", r.Type)
+ return false
}
// Handle relocations found in ELF object files.
@@ -125,75 +127,75 @@ func adddynrel(s *ld.LSym, r *ld.Reloc) {
r.Type = obj.R_CALLARM
if targ.Type == obj.SDYNIMPORT {
- addpltsym(ld.Ctxt, targ)
- r.Sym = ld.Linklookup(ld.Ctxt, ".plt", 0)
+ addpltsym(ctxt, targ)
+ r.Sym = ctxt.Syms.Lookup(".plt", 0)
r.Add = int64(braddoff(int32(r.Add), targ.Plt/4))
}
- return
+ return true
case 256 + ld.R_ARM_THM_PC22: // R_ARM_THM_CALL
ld.Exitf("R_ARM_THM_CALL, are you using -marm?")
- return
+ return false
case 256 + ld.R_ARM_GOT32: // R_ARM_GOT_BREL
if targ.Type != obj.SDYNIMPORT {
- addgotsyminternal(ld.Ctxt, targ)
+ addgotsyminternal(ctxt, targ)
} else {
- addgotsym(ld.Ctxt, targ)
+ addgotsym(ctxt, targ)
}
r.Type = obj.R_CONST // write r->add during relocsym
r.Sym = nil
r.Add += int64(targ.Got)
- return
+ return true
case 256 + ld.R_ARM_GOT_PREL: // GOT(nil) + A - nil
if targ.Type != obj.SDYNIMPORT {
- addgotsyminternal(ld.Ctxt, targ)
+ addgotsyminternal(ctxt, targ)
} else {
- addgotsym(ld.Ctxt, targ)
+ addgotsym(ctxt, targ)
}
r.Type = obj.R_PCREL
- r.Sym = ld.Linklookup(ld.Ctxt, ".got", 0)
+ r.Sym = ctxt.Syms.Lookup(".got", 0)
r.Add += int64(targ.Got) + 4
- return
+ return true
case 256 + ld.R_ARM_GOTOFF: // R_ARM_GOTOFF32
r.Type = obj.R_GOTOFF
- return
+ return true
case 256 + ld.R_ARM_GOTPC: // R_ARM_BASE_PREL
r.Type = obj.R_PCREL
- r.Sym = ld.Linklookup(ld.Ctxt, ".got", 0)
+ r.Sym = ctxt.Syms.Lookup(".got", 0)
r.Add += 4
- return
+ return true
case 256 + ld.R_ARM_CALL:
r.Type = obj.R_CALLARM
if targ.Type == obj.SDYNIMPORT {
- addpltsym(ld.Ctxt, targ)
- r.Sym = ld.Linklookup(ld.Ctxt, ".plt", 0)
+ addpltsym(ctxt, targ)
+ r.Sym = ctxt.Syms.Lookup(".plt", 0)
r.Add = int64(braddoff(int32(r.Add), targ.Plt/4))
}
- return
+ return true
case 256 + ld.R_ARM_REL32: // R_ARM_REL32
r.Type = obj.R_PCREL
r.Add += 4
- return
+ return true
case 256 + ld.R_ARM_ABS32:
if targ.Type == obj.SDYNIMPORT {
- ld.Diag("unexpected R_ARM_ABS32 relocation for dynamic symbol %s", targ.Name)
+ ld.Errorf(s, "unexpected R_ARM_ABS32 relocation for dynamic symbol %s", targ.Name)
}
r.Type = obj.R_ADDR
- return
+ return true
// we can just ignore this, because we are targeting ARM V5+ anyway
case 256 + ld.R_ARM_V4BX:
@@ -203,52 +205,51 @@ func adddynrel(s *ld.LSym, r *ld.Reloc) {
}
r.Sym = nil
- return
+ return true
case 256 + ld.R_ARM_PC24,
256 + ld.R_ARM_JUMP24:
r.Type = obj.R_CALLARM
if targ.Type == obj.SDYNIMPORT {
- addpltsym(ld.Ctxt, targ)
- r.Sym = ld.Linklookup(ld.Ctxt, ".plt", 0)
+ addpltsym(ctxt, targ)
+ r.Sym = ctxt.Syms.Lookup(".plt", 0)
r.Add = int64(braddoff(int32(r.Add), targ.Plt/4))
}
- return
+ return true
}
// Handle references to ELF symbols from our own object files.
if targ.Type != obj.SDYNIMPORT {
- return
+ return true
}
switch r.Type {
case obj.R_CALLARM:
- addpltsym(ld.Ctxt, targ)
- r.Sym = ld.Linklookup(ld.Ctxt, ".plt", 0)
+ addpltsym(ctxt, targ)
+ r.Sym = ctxt.Syms.Lookup(".plt", 0)
r.Add = int64(targ.Plt)
- return
+ return true
case obj.R_ADDR:
if s.Type != obj.SDATA {
break
}
if ld.Iself {
- ld.Adddynsym(ld.Ctxt, targ)
- rel := ld.Linklookup(ld.Ctxt, ".rel", 0)
- ld.Addaddrplus(ld.Ctxt, rel, s, int64(r.Off))
- ld.Adduint32(ld.Ctxt, rel, ld.ELF32_R_INFO(uint32(targ.Dynid), ld.R_ARM_GLOB_DAT)) // we need a nil + A dynamic reloc
- r.Type = obj.R_CONST // write r->add during relocsym
+ ld.Adddynsym(ctxt, targ)
+ 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.Sym = nil
- return
+ return true
}
}
- ld.Ctxt.Cursym = s
- ld.Diag("unsupported relocation for dynamic symbol %s (type=%d stype=%d)", targ.Name, r.Type, targ.Type)
+ return false
}
-func elfreloc1(r *ld.Reloc, sectoff int64) int {
+func elfreloc1(ctxt *ld.Link, r *ld.Reloc, sectoff int64) int {
ld.Thearch.Lput(uint32(sectoff))
elfsym := r.Xsym.ElfsymForReloc()
@@ -298,41 +299,41 @@ func elfreloc1(r *ld.Reloc, sectoff int64) int {
return 0
}
-func elfsetupplt() {
- plt := ld.Linklookup(ld.Ctxt, ".plt", 0)
- got := ld.Linklookup(ld.Ctxt, ".got.plt", 0)
+func elfsetupplt(ctxt *ld.Link) {
+ plt := ctxt.Syms.Lookup(".plt", 0)
+ got := ctxt.Syms.Lookup(".got.plt", 0)
if plt.Size == 0 {
// str lr, [sp, #-4]!
- ld.Adduint32(ld.Ctxt, plt, 0xe52de004)
+ ld.Adduint32(ctxt, plt, 0xe52de004)
// ldr lr, [pc, #4]
- ld.Adduint32(ld.Ctxt, plt, 0xe59fe004)
+ ld.Adduint32(ctxt, plt, 0xe59fe004)
// add lr, pc, lr
- ld.Adduint32(ld.Ctxt, plt, 0xe08fe00e)
+ ld.Adduint32(ctxt, plt, 0xe08fe00e)
// ldr pc, [lr, #8]!
- ld.Adduint32(ld.Ctxt, plt, 0xe5bef008)
+ ld.Adduint32(ctxt, plt, 0xe5bef008)
// .word &GLOBAL_OFFSET_TABLE[0] - .
- ld.Addpcrelplus(ld.Ctxt, plt, got, 4)
+ ld.Addpcrelplus(ctxt, plt, got, 4)
// the first .plt entry requires 3 .plt.got entries
- ld.Adduint32(ld.Ctxt, got, 0)
+ ld.Adduint32(ctxt, got, 0)
- ld.Adduint32(ld.Ctxt, got, 0)
- ld.Adduint32(ld.Ctxt, got, 0)
+ ld.Adduint32(ctxt, got, 0)
+ ld.Adduint32(ctxt, got, 0)
}
}
-func machoreloc1(r *ld.Reloc, sectoff int64) int {
+func machoreloc1(s *ld.Symbol, r *ld.Reloc, sectoff int64) int {
var v uint32
rs := r.Xsym
if r.Type == obj.R_PCREL {
if rs.Type == obj.SHOSTOBJ {
- ld.Diag("pc-relative relocation of external symbol is not supported")
+ ld.Errorf(s, "pc-relative relocation of external symbol is not supported")
return -1
}
if r.Siz != 4 {
@@ -356,13 +357,13 @@ func machoreloc1(r *ld.Reloc, sectoff int64) int {
ld.Thearch.Lput(o1)
ld.Thearch.Lput(uint32(ld.Symaddr(rs)))
ld.Thearch.Lput(o2)
- ld.Thearch.Lput(uint32(ld.Ctxt.Cursym.Value + int64(r.Off)))
+ ld.Thearch.Lput(uint32(s.Value + int64(r.Off)))
return 0
}
if rs.Type == obj.SHOSTOBJ || r.Type == obj.R_CALLARM {
if rs.Dynid < 0 {
- ld.Diag("reloc %d to non-macho symbol %s type=%d", r.Type, rs.Name, rs.Type)
+ ld.Errorf(s, "reloc %d to non-macho symbol %s type=%d", r.Type, rs.Name, rs.Type)
return -1
}
@@ -371,7 +372,7 @@ func machoreloc1(r *ld.Reloc, sectoff int64) int {
} else {
v = uint32(rs.Sect.Extnum)
if v == 0 {
- ld.Diag("reloc %d to symbol %s in non-macho section %s type=%d", r.Type, rs.Name, rs.Sect.Name, rs.Type)
+ ld.Errorf(s, "reloc %d to symbol %s in non-macho section %s type=%d", r.Type, rs.Name, rs.Sect.Name, rs.Type)
return -1
}
}
@@ -410,7 +411,164 @@ func machoreloc1(r *ld.Reloc, sectoff int64) int {
return 0
}
-func archreloc(r *ld.Reloc, s *ld.LSym, val *int64) int {
+// sign extend a 24-bit integer
+func signext24(x int64) int32 {
+ return (int32(x) << 8) >> 8
+}
+
+// encode an immediate in ARM's imm12 format. copied from ../../../internal/obj/arm/asm5.go
+func immrot(v uint32) uint32 {
+ for i := 0; i < 16; i++ {
+ if v&^0xff == 0 {
+ return uint32(i<<8) | v | 1<<25
+ }
+ v = v<<2 | v>>30
+ }
+ return 0
+}
+
+// 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:
+ // 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
+ if t > 0x7fffff || t < -0x800000 || (*ld.FlagDebugTramp > 1 && s.File != r.Sym.File) {
+ // direct call too far, need to insert trampoline.
+ // look up existing trampolines first. if we found one within the range
+ // of direct call, we can reuse it. otherwise create a new one.
+ offset := (signext24(r.Add&0xffffff) + 2) * 4
+ var tramp *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 {
+ // don't reuse trampoline defined in other module
+ continue
+ }
+ if tramp.Value == 0 {
+ // either the trampoline does not exist -- we need to create one,
+ // or found one the address which is not assigned -- this will be
+ // laid down immediately after the current function. use this one.
+ break
+ }
+
+ t = (ld.Symaddr(tramp) - 8 - (s.Value + int64(r.Off))) / 4
+ if t >= -0x800000 && t < 0x7fffff {
+ // found an existing trampoline that is not too far
+ // we can just use it
+ break
+ }
+ }
+ if tramp.Type == 0 {
+ // trampoline does not exist, create one
+ ctxt.AddTramp(tramp)
+ if ctxt.DynlinkingGo() {
+ if immrot(uint32(offset)) == 0 {
+ ld.Errorf(s, "odd offset in dynlink direct call: %v+%d", r.Sym, offset)
+ }
+ gentrampdyn(tramp, r.Sym, int64(offset))
+ } else if ld.Buildmode == ld.BuildmodeCArchive || ld.Buildmode == ld.BuildmodeCShared || ld.Buildmode == ld.BuildmodePIE {
+ gentramppic(tramp, r.Sym, int64(offset))
+ } else {
+ gentramp(tramp, r.Sym, int64(offset))
+ }
+ }
+ // modify reloc to point to tramp, which will be resolved later
+ r.Sym = tramp
+ r.Add = r.Add&0xff000000 | 0xfffffe // clear the offset embedded in the instruction
+ r.Done = 0
+ }
+ default:
+ ld.Errorf(s, "trampoline called with non-jump reloc: %v", r.Type)
+ }
+}
+
+// generate a trampoline to target+offset
+func gentramp(tramp, target *ld.Symbol, offset int64) {
+ tramp.Size = 12 // 3 instructions
+ tramp.P = make([]byte, tramp.Size)
+ t := ld.Symaddr(target) + int64(offset)
+ o1 := uint32(0xe5900000 | 11<<12 | 15<<16) // MOVW (R15), R11 // R15 is actual pc + 8
+ o2 := uint32(0xe12fff10 | 11) // JMP (R11)
+ o3 := uint32(t) // WORD $target
+ ld.SysArch.ByteOrder.PutUint32(tramp.P, o1)
+ ld.SysArch.ByteOrder.PutUint32(tramp.P[4:], o2)
+ ld.SysArch.ByteOrder.PutUint32(tramp.P[8:], o3)
+
+ if ld.Linkmode == ld.LinkExternal {
+ r := ld.Addrel(tramp)
+ r.Off = 8
+ r.Type = obj.R_ADDR
+ r.Siz = 4
+ r.Sym = target
+ r.Add = offset
+ }
+}
+
+// generate a trampoline to target+offset in position independent code
+func gentramppic(tramp, target *ld.Symbol, offset int64) {
+ tramp.Size = 16 // 4 instructions
+ tramp.P = make([]byte, tramp.Size)
+ o1 := uint32(0xe5900000 | 11<<12 | 15<<16 | 4) // MOVW 4(R15), R11 // R15 is actual pc + 8
+ o2 := uint32(0xe0800000 | 11<<12 | 15<<16 | 11) // ADD R15, R11, R11
+ o3 := uint32(0xe12fff10 | 11) // JMP (R11)
+ o4 := uint32(0) // WORD $(target-pc) // filled in with relocation
+ 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)
+
+ r := ld.Addrel(tramp)
+ r.Off = 12
+ r.Type = obj.R_PCREL
+ r.Siz = 4
+ r.Sym = target
+ r.Add = offset + 4
+}
+
+// generate a trampoline to target+offset in dynlink mode (using GOT)
+func gentrampdyn(tramp, target *ld.Symbol, offset int64) {
+ tramp.Size = 20 // 5 instructions
+ o1 := uint32(0xe5900000 | 11<<12 | 15<<16 | 8) // MOVW 8(R15), R11 // R15 is actual pc + 8
+ o2 := uint32(0xe0800000 | 11<<12 | 15<<16 | 11) // ADD R15, R11, R11
+ o3 := uint32(0xe5900000 | 11<<12 | 11<<16) // MOVW (R11), R11
+ o4 := uint32(0xe12fff10 | 11) // JMP (R11)
+ o5 := uint32(0) // WORD $target at GOT // filled in with relocation
+ o6 := uint32(0)
+ if offset != 0 {
+ // insert an instruction to add offset
+ tramp.Size = 24 // 6 instructions
+ o6 = o5
+ o5 = o4
+ o4 = uint32(0xe2800000 | 11<<12 | 11<<16 | immrot(uint32(offset))) // ADD $offset, R11, R11
+ o1 = uint32(0xe5900000 | 11<<12 | 15<<16 | 12) // MOVW 12(R15), R11
+ }
+ tramp.P = make([]byte, tramp.Size)
+ 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)
+ ld.SysArch.ByteOrder.PutUint32(tramp.P[16:], o5)
+ if offset != 0 {
+ ld.SysArch.ByteOrder.PutUint32(tramp.P[20:], o6)
+ }
+
+ r := ld.Addrel(tramp)
+ r.Off = 16
+ r.Type = obj.R_GOTPCREL
+ r.Siz = 4
+ r.Sym = target
+ r.Add = 8
+ if offset != 0 {
+ // increase reloc offset by 4 as we inserted an ADD instruction
+ r.Off = 20
+ r.Add = 12
+ }
+}
+
+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:
@@ -419,10 +577,7 @@ func archreloc(r *ld.Reloc, s *ld.LSym, val *int64) int {
// set up addend for eventual relocation via outer symbol.
rs := r.Sym
- r.Xadd = r.Add
- if r.Xadd&0x800000 != 0 {
- r.Xadd |= ^0xffffff
- }
+ r.Xadd = int64(signext24(r.Add & 0xffffff))
r.Xadd *= 4
for rs.Outer != nil {
r.Xadd += ld.Symaddr(rs) - ld.Symaddr(rs.Outer)
@@ -430,7 +585,7 @@ func archreloc(r *ld.Reloc, s *ld.LSym, val *int64) int {
}
if rs.Type != obj.SHOSTOBJ && rs.Type != obj.SDYNIMPORT && rs.Sect == nil {
- ld.Diag("missing section for %s", rs.Name)
+ ld.Errorf(s, "missing section for %s", rs.Name)
}
r.Xsym = rs
@@ -439,10 +594,14 @@ func archreloc(r *ld.Reloc, s *ld.LSym, 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 == obj.Hdarwin {
r.Xadd -= ld.Symaddr(s) + int64(r.Off)
}
+ if r.Xadd/4 > 0x7fffff || r.Xadd/4 < -0x800000 {
+ ld.Errorf(s, "direct call too far %d", r.Xadd/4)
+ }
+
*val = int64(braddoff(int32(0xff000000&uint32(r.Add)), int32(0xffffff&uint32(r.Xadd/4))))
return 0
}
@@ -456,30 +615,36 @@ func archreloc(r *ld.Reloc, s *ld.LSym, val *int64) int {
return 0
case obj.R_GOTOFF:
- *val = ld.Symaddr(r.Sym) + r.Add - ld.Symaddr(ld.Linklookup(ld.Ctxt, ".got", 0))
+ *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
+ // The following three arch specific relocations are only for generation of
// Linux/ARM ELF's PLT entry (3 assembler instruction)
case obj.R_PLT0: // add ip, pc, #0xXX00000
- if ld.Symaddr(ld.Linklookup(ld.Ctxt, ".got.plt", 0)) < ld.Symaddr(ld.Linklookup(ld.Ctxt, ".plt", 0)) {
- ld.Diag(".got.plt should be placed after .plt section.")
+ 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(ld.Linklookup(ld.Ctxt, ".plt", 0))+int64(r.Off))+r.Add)) >> 20))
+ *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
- *val = 0xe28cca00 + (0xff & (int64(uint32(ld.Symaddr(r.Sym)-(ld.Symaddr(ld.Linklookup(ld.Ctxt, ".plt", 0))+int64(r.Off))+r.Add+4)) >> 12))
+ *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]!
- *val = 0xe5bcf000 + (0xfff & int64(uint32(ld.Symaddr(r.Sym)-(ld.Symaddr(ld.Linklookup(ld.Ctxt, ".plt", 0))+int64(r.Off))+r.Add+8)))
+ *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
- *val = int64(braddoff(int32(0xff000000&uint32(r.Add)), int32(0xffffff&uint32((ld.Symaddr(r.Sym)+int64((uint32(r.Add))*4)-(s.Value+int64(r.Off)))/4))))
+ // 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
+ if t > 0x7fffff || t < -0x800000 {
+ ld.Errorf(s, "direct call too far: %s %x", r.Sym.Name, t)
+ }
+ *val = int64(braddoff(int32(0xff000000&uint32(r.Add)), int32(0xffffff&t)))
return 0
}
@@ -487,27 +652,27 @@ func archreloc(r *ld.Reloc, s *ld.LSym, val *int64) int {
return -1
}
-func archrelocvariant(r *ld.Reloc, s *ld.LSym, t int64) int64 {
+func archrelocvariant(ctxt *ld.Link, r *ld.Reloc, s *ld.Symbol, t int64) int64 {
log.Fatalf("unexpected relocation variant")
return t
}
-func addpltreloc(ctxt *ld.Link, plt *ld.LSym, got *ld.LSym, sym *ld.LSym, typ int) *ld.Reloc {
+func addpltreloc(ctxt *ld.Link, plt *ld.Symbol, got *ld.Symbol, sym *ld.Symbol, typ obj.RelocType) *ld.Reloc {
r := ld.Addrel(plt)
r.Sym = got
r.Off = int32(plt.Size)
r.Siz = 4
- r.Type = int32(typ)
+ r.Type = typ
r.Add = int64(sym.Got) - 8
plt.Attr |= ld.AttrReachable
plt.Size += 4
- ld.Symgrow(ctxt, plt, plt.Size)
+ ld.Symgrow(plt, plt.Size)
return r
}
-func addpltsym(ctxt *ld.Link, s *ld.LSym) {
+func addpltsym(ctxt *ld.Link, s *ld.Symbol) {
if s.Plt >= 0 {
return
}
@@ -515,11 +680,11 @@ func addpltsym(ctxt *ld.Link, s *ld.LSym) {
ld.Adddynsym(ctxt, s)
if ld.Iself {
- plt := ld.Linklookup(ctxt, ".plt", 0)
- got := ld.Linklookup(ctxt, ".got.plt", 0)
- rel := ld.Linklookup(ctxt, ".rel.plt", 0)
+ plt := ctxt.Syms.Lookup(".plt", 0)
+ got := ctxt.Syms.Lookup(".got.plt", 0)
+ rel := ctxt.Syms.Lookup(".rel.plt", 0)
if plt.Size == 0 {
- elfsetupplt()
+ elfsetupplt(ctxt)
}
// .got entry
@@ -542,50 +707,49 @@ func addpltsym(ctxt *ld.Link, s *ld.LSym) {
ld.Adduint32(ctxt, rel, ld.ELF32_R_INFO(uint32(s.Dynid), ld.R_ARM_JUMP_SLOT))
} else {
- ld.Diag("addpltsym: unsupported binary format")
+ ld.Errorf(s, "addpltsym: unsupported binary format")
}
}
-func addgotsyminternal(ctxt *ld.Link, s *ld.LSym) {
+func addgotsyminternal(ctxt *ld.Link, s *ld.Symbol) {
if s.Got >= 0 {
return
}
- got := ld.Linklookup(ctxt, ".got", 0)
+ got := ctxt.Syms.Lookup(".got", 0)
s.Got = int32(got.Size)
ld.Addaddrplus(ctxt, got, s, 0)
if ld.Iself {
} else {
- ld.Diag("addgotsyminternal: unsupported binary format")
+ ld.Errorf(s, "addgotsyminternal: unsupported binary format")
}
}
-func addgotsym(ctxt *ld.Link, s *ld.LSym) {
+func addgotsym(ctxt *ld.Link, s *ld.Symbol) {
if s.Got >= 0 {
return
}
ld.Adddynsym(ctxt, s)
- got := ld.Linklookup(ctxt, ".got", 0)
+ got := ctxt.Syms.Lookup(".got", 0)
s.Got = int32(got.Size)
ld.Adduint32(ctxt, got, 0)
if ld.Iself {
- rel := ld.Linklookup(ctxt, ".rel", 0)
+ 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_ARM_GLOB_DAT))
} else {
- ld.Diag("addgotsym: unsupported binary format")
+ ld.Errorf(s, "addgotsym: unsupported binary format")
}
}
-func asmb() {
- if ld.Debug['v'] != 0 {
- fmt.Fprintf(ld.Bso, "%5.2f asmb\n", obj.Cputime())
+func asmb(ctxt *ld.Link) {
+ if ctxt.Debugvlog != 0 {
+ ctxt.Logf("%5.2f asmb\n", obj.Cputime())
}
- ld.Bso.Flush()
if ld.Iself {
ld.Asmbelfsetup()
@@ -593,36 +757,40 @@ func asmb() {
sect := ld.Segtext.Sect
ld.Cseek(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
- ld.Codeblk(int64(sect.Vaddr), int64(sect.Length))
+ ld.Codeblk(ctxt, int64(sect.Vaddr), int64(sect.Length))
for sect = sect.Next; sect != nil; sect = sect.Next {
ld.Cseek(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
- ld.Datblk(int64(sect.Vaddr), int64(sect.Length))
+ ld.Datblk(ctxt, int64(sect.Vaddr), int64(sect.Length))
}
if ld.Segrodata.Filelen > 0 {
- if ld.Debug['v'] != 0 {
- fmt.Fprintf(ld.Bso, "%5.2f rodatblk\n", obj.Cputime())
+ if ctxt.Debugvlog != 0 {
+ ctxt.Logf("%5.2f rodatblk\n", obj.Cputime())
}
- ld.Bso.Flush()
-
ld.Cseek(int64(ld.Segrodata.Fileoff))
- ld.Datblk(int64(ld.Segrodata.Vaddr), int64(ld.Segrodata.Filelen))
+ 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())
+ }
+ ld.Cseek(int64(ld.Segrelrodata.Fileoff))
+ ld.Datblk(ctxt, int64(ld.Segrelrodata.Vaddr), int64(ld.Segrelrodata.Filelen))
}
- if ld.Debug['v'] != 0 {
- fmt.Fprintf(ld.Bso, "%5.2f datblk\n", obj.Cputime())
+ if ctxt.Debugvlog != 0 {
+ ctxt.Logf("%5.2f datblk\n", obj.Cputime())
}
- ld.Bso.Flush()
ld.Cseek(int64(ld.Segdata.Fileoff))
- ld.Datblk(int64(ld.Segdata.Vaddr), int64(ld.Segdata.Filelen))
+ ld.Datblk(ctxt, int64(ld.Segdata.Vaddr), int64(ld.Segdata.Filelen))
ld.Cseek(int64(ld.Segdwarf.Fileoff))
- ld.Dwarfblk(int64(ld.Segdwarf.Vaddr), int64(ld.Segdwarf.Filelen))
+ ld.Dwarfblk(ctxt, int64(ld.Segdwarf.Vaddr), int64(ld.Segdwarf.Filelen))
machlink := uint32(0)
- if ld.HEADTYPE == obj.Hdarwin {
- machlink = uint32(ld.Domacholink())
+ if ld.Headtype == obj.Hdarwin {
+ machlink = uint32(ld.Domacholink(ctxt))
}
/* output symbol table */
@@ -630,47 +798,46 @@ func asmb() {
ld.Lcsize = 0
symo := uint32(0)
- if ld.Debug['s'] == 0 {
+ if !*ld.FlagS {
// TODO: rationalize
- if ld.Debug['v'] != 0 {
- fmt.Fprintf(ld.Bso, "%5.2f sym\n", obj.Cputime())
+ if ctxt.Debugvlog != 0 {
+ ctxt.Logf("%5.2f sym\n", obj.Cputime())
}
- ld.Bso.Flush()
- switch ld.HEADTYPE {
+ switch ld.Headtype {
default:
if ld.Iself {
symo = uint32(ld.Segdwarf.Fileoff + ld.Segdwarf.Filelen)
- symo = uint32(ld.Rnd(int64(symo), int64(ld.INITRND)))
+ symo = uint32(ld.Rnd(int64(symo), int64(*ld.FlagRound)))
}
case obj.Hplan9:
symo = uint32(ld.Segdata.Fileoff + ld.Segdata.Filelen)
case obj.Hdarwin:
- symo = uint32(ld.Segdwarf.Fileoff + uint64(ld.Rnd(int64(ld.Segdwarf.Filelen), int64(ld.INITRND))) + uint64(machlink))
+ symo = uint32(ld.Segdwarf.Fileoff + uint64(ld.Rnd(int64(ld.Segdwarf.Filelen), int64(*ld.FlagRound))) + uint64(machlink))
}
ld.Cseek(int64(symo))
- switch ld.HEADTYPE {
+ switch ld.Headtype {
default:
if ld.Iself {
- if ld.Debug['v'] != 0 {
- fmt.Fprintf(ld.Bso, "%5.2f elfsym\n", obj.Cputime())
+ if ctxt.Debugvlog != 0 {
+ ctxt.Logf("%5.2f elfsym\n", obj.Cputime())
}
- ld.Asmelfsym()
+ ld.Asmelfsym(ctxt)
ld.Cflush()
ld.Cwrite(ld.Elfstrdat)
if ld.Linkmode == ld.LinkExternal {
- ld.Elfemitreloc()
+ ld.Elfemitreloc(ctxt)
}
}
case obj.Hplan9:
- ld.Asmplan9sym()
+ ld.Asmplan9sym(ctxt)
ld.Cflush()
- sym := ld.Linklookup(ld.Ctxt, "pclntab", 0)
+ sym := ctxt.Syms.Lookup("pclntab", 0)
if sym != nil {
ld.Lcsize = int32(len(sym.P))
for i := 0; int32(i) < ld.Lcsize; i++ {
@@ -682,26 +849,24 @@ func asmb() {
case obj.Hdarwin:
if ld.Linkmode == ld.LinkExternal {
- ld.Machoemitreloc()
+ ld.Machoemitreloc(ctxt)
}
}
}
- ld.Ctxt.Cursym = nil
- if ld.Debug['v'] != 0 {
- fmt.Fprintf(ld.Bso, "%5.2f header\n", obj.Cputime())
+ if ctxt.Debugvlog != 0 {
+ ctxt.Logf("%5.2f header\n", obj.Cputime())
}
- ld.Bso.Flush()
ld.Cseek(0)
- switch ld.HEADTYPE {
+ switch ld.Headtype {
default:
case obj.Hplan9: /* plan 9 */
ld.Lputb(0x647) /* magic */
ld.Lputb(uint32(ld.Segtext.Filelen)) /* sizes */
ld.Lputb(uint32(ld.Segdata.Filelen))
ld.Lputb(uint32(ld.Segdata.Length - ld.Segdata.Filelen))
- ld.Lputb(uint32(ld.Symsize)) /* nsyms */
- ld.Lputb(uint32(ld.Entryvalue())) /* va of entry */
+ ld.Lputb(uint32(ld.Symsize)) /* nsyms */
+ ld.Lputb(uint32(ld.Entryvalue(ctxt))) /* va of entry */
ld.Lputb(0)
ld.Lputb(uint32(ld.Lcsize))
@@ -710,14 +875,14 @@ func asmb() {
obj.Hnetbsd,
obj.Hopenbsd,
obj.Hnacl:
- ld.Asmbelf(int64(symo))
+ ld.Asmbelf(ctxt, int64(symo))
case obj.Hdarwin:
- ld.Asmbmacho()
+ ld.Asmbmacho(ctxt)
}
ld.Cflush()
- if ld.Debug['c'] != 0 {
+ if *ld.FlagC {
fmt.Printf("textsize=%d\n", ld.Segtext.Filelen)
fmt.Printf("datsize=%d\n", ld.Segdata.Filelen)
fmt.Printf("bsssize=%d\n", ld.Segdata.Length-ld.Segdata.Filelen)
diff --git a/src/cmd/link/internal/arm/l.go b/src/cmd/link/internal/arm/l.go
index 63b1165..a83d26b 100644
--- a/src/cmd/link/internal/arm/l.go
+++ b/src/cmd/link/internal/arm/l.go
@@ -1,5 +1,5 @@
// Inferno utils/5l/asm.c
-// http://code.google.com/p/inferno-os/source/browse/utils/5l/asm.c
+// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5l/asm.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth at terzarima.net)
@@ -33,7 +33,7 @@ package arm
// Writing object files.
// Inferno utils/5l/l.h
-// http://code.google.com/p/inferno-os/source/browse/utils/5l/l.h
+// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5l/l.h
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth at terzarima.net)
@@ -63,13 +63,13 @@ package arm
// THE SOFTWARE.
const (
- MaxAlign = 8 // max data alignment
- MinAlign = 1 // min data alignment
- FuncAlign = 4 // single-instruction alignment
+ maxAlign = 8 // max data alignment
+ minAlign = 1 // min data alignment
+ funcAlign = 4 // single-instruction alignment
)
/* Used by ../internal/ld/dwarf.go */
const (
- DWARFREGSP = 13
- DWARFREGLR = 14
+ dwarfRegSP = 13
+ dwarfRegLR = 14
)
diff --git a/src/cmd/link/internal/arm/obj.go b/src/cmd/link/internal/arm/obj.go
index 9ea9771..4feaa09 100644
--- a/src/cmd/link/internal/arm/obj.go
+++ b/src/cmd/link/internal/arm/obj.go
@@ -1,5 +1,5 @@
// Inferno utils/5l/obj.c
-// http://code.google.com/p/inferno-os/source/browse/utils/5l/obj.c
+// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5l/obj.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth at terzarima.net)
@@ -35,29 +35,22 @@ import (
"cmd/internal/sys"
"cmd/link/internal/ld"
"fmt"
- "log"
)
-// Reading object files.
-
-func Main() {
- linkarchinit()
- ld.Ldmain()
-}
-
-func linkarchinit() {
+func Init() {
ld.SysArch = sys.ArchARM
- ld.Thearch.Funcalign = FuncAlign
- ld.Thearch.Maxalign = MaxAlign
- ld.Thearch.Minalign = MinAlign
- ld.Thearch.Dwarfregsp = DWARFREGSP
- ld.Thearch.Dwarfreglr = DWARFREGLR
+ ld.Thearch.Funcalign = funcAlign
+ ld.Thearch.Maxalign = maxAlign
+ ld.Thearch.Minalign = minAlign
+ ld.Thearch.Dwarfregsp = dwarfRegSP
+ ld.Thearch.Dwarfreglr = dwarfRegLR
ld.Thearch.Adddynrel = adddynrel
ld.Thearch.Archinit = archinit
ld.Thearch.Archreloc = archreloc
ld.Thearch.Archrelocvariant = archrelocvariant
+ ld.Thearch.Trampoline = trampoline
ld.Thearch.Asmb = asmb
ld.Thearch.Elfreloc1 = elfreloc1
ld.Thearch.Elfsetupplt = elfsetupplt
@@ -78,98 +71,72 @@ func linkarchinit() {
ld.Thearch.Solarisdynld = "XXX"
}
-func archinit() {
- // getgoextlinkenabled is based on GO_EXTLINK_ENABLED when
- // Go was built; see ../../make.bash.
- if ld.Linkmode == ld.LinkAuto && obj.Getgoextlinkenabled() == "0" {
- ld.Linkmode = ld.LinkInternal
- }
-
- if ld.Buildmode == ld.BuildmodeCArchive || ld.Buildmode == ld.BuildmodeCShared || ld.DynlinkingGo() {
- ld.Linkmode = ld.LinkExternal
- }
-
- switch ld.HEADTYPE {
- default:
- if ld.Linkmode == ld.LinkAuto {
- ld.Linkmode = ld.LinkInternal
- }
- if ld.Linkmode == ld.LinkExternal && obj.Getgoextlinkenabled() != "1" {
- log.Fatalf("cannot use -linkmode=external with -H %s", ld.Headstr(int(ld.HEADTYPE)))
- }
-
- case obj.Hlinux,
- obj.Hfreebsd,
- obj.Hnacl,
- obj.Hdarwin:
- break
- }
-
- switch ld.HEADTYPE {
+func archinit(ctxt *ld.Link) {
+ switch ld.Headtype {
default:
- ld.Exitf("unknown -H option: %v", ld.HEADTYPE)
+ ld.Exitf("unknown -H option: %v", ld.Headtype)
case obj.Hplan9: /* plan 9 */
ld.HEADR = 32
- if ld.INITTEXT == -1 {
- ld.INITTEXT = 4128
+ if *ld.FlagTextAddr == -1 {
+ *ld.FlagTextAddr = 4128
}
- if ld.INITDAT == -1 {
- ld.INITDAT = 0
+ if *ld.FlagDataAddr == -1 {
+ *ld.FlagDataAddr = 0
}
- if ld.INITRND == -1 {
- ld.INITRND = 4096
+ if *ld.FlagRound == -1 {
+ *ld.FlagRound = 4096
}
case obj.Hlinux, /* arm elf */
obj.Hfreebsd,
obj.Hnetbsd,
obj.Hopenbsd:
- ld.Debug['d'] = 0
+ *ld.FlagD = false
// with dynamic linking
- ld.Elfinit()
+ ld.Elfinit(ctxt)
ld.HEADR = ld.ELFRESERVE
- if ld.INITTEXT == -1 {
- ld.INITTEXT = 0x10000 + int64(ld.HEADR)
+ if *ld.FlagTextAddr == -1 {
+ *ld.FlagTextAddr = 0x10000 + int64(ld.HEADR)
}
- if ld.INITDAT == -1 {
- ld.INITDAT = 0
+ if *ld.FlagDataAddr == -1 {
+ *ld.FlagDataAddr = 0
}
- if ld.INITRND == -1 {
- ld.INITRND = 4096
+ if *ld.FlagRound == -1 {
+ *ld.FlagRound = 4096
}
case obj.Hnacl:
- ld.Elfinit()
+ ld.Elfinit(ctxt)
ld.HEADR = 0x10000
ld.Funcalign = 16
- if ld.INITTEXT == -1 {
- ld.INITTEXT = 0x20000
+ if *ld.FlagTextAddr == -1 {
+ *ld.FlagTextAddr = 0x20000
}
- if ld.INITDAT == -1 {
- ld.INITDAT = 0
+ if *ld.FlagDataAddr == -1 {
+ *ld.FlagDataAddr = 0
}
- if ld.INITRND == -1 {
- ld.INITRND = 0x10000
+ if *ld.FlagRound == -1 {
+ *ld.FlagRound = 0x10000
}
case obj.Hdarwin: /* apple MACH */
- ld.Debug['w'] = 1 // disable DWARF generation
+ *ld.FlagW = true // disable DWARF generation
ld.Machoinit()
ld.HEADR = ld.INITIAL_MACHO_HEADR
- if ld.INITTEXT == -1 {
- ld.INITTEXT = 4096 + int64(ld.HEADR)
+ if *ld.FlagTextAddr == -1 {
+ *ld.FlagTextAddr = 4096 + int64(ld.HEADR)
}
- if ld.INITDAT == -1 {
- ld.INITDAT = 0
+ if *ld.FlagDataAddr == -1 {
+ *ld.FlagDataAddr = 0
}
- if ld.INITRND == -1 {
- ld.INITRND = 4096
+ if *ld.FlagRound == -1 {
+ *ld.FlagRound = 4096
}
}
- if ld.INITDAT != 0 && ld.INITRND != 0 {
- fmt.Printf("warning: -D0x%x is ignored because of -R0x%x\n", uint64(ld.INITDAT), uint32(ld.INITRND))
+ if *ld.FlagDataAddr != 0 && *ld.FlagRound != 0 {
+ fmt.Printf("warning: -D0x%x is ignored because of -R0x%x\n", uint64(*ld.FlagDataAddr), uint32(*ld.FlagRound))
}
}
diff --git a/src/cmd/link/internal/arm64/asm.go b/src/cmd/link/internal/arm64/asm.go
index 7832e91..118a575 100644
--- a/src/cmd/link/internal/arm64/asm.go
+++ b/src/cmd/link/internal/arm64/asm.go
@@ -1,5 +1,5 @@
// Inferno utils/5l/asm.c
-// http://code.google.com/p/inferno-os/source/browse/utils/5l/asm.c
+// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5l/asm.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth at terzarima.net)
@@ -38,23 +38,23 @@ import (
"log"
)
-func gentext() {
- if !ld.DynlinkingGo() {
+func gentext(ctxt *ld.Link) {
+ if !ctxt.DynlinkingGo() {
return
}
- addmoduledata := ld.Linklookup(ld.Ctxt, "runtime.addmoduledata", 0)
+ addmoduledata := ctxt.Syms.Lookup("runtime.addmoduledata", 0)
if addmoduledata.Type == obj.STEXT {
// we're linking a module containing the runtime -> no need for
// an init function
return
}
addmoduledata.Attr |= ld.AttrReachable
- initfunc := ld.Linklookup(ld.Ctxt, "go.link.addmoduledata", 0)
+ initfunc := ctxt.Syms.Lookup("go.link.addmoduledata", 0)
initfunc.Type = obj.STEXT
initfunc.Attr |= ld.AttrLocal
initfunc.Attr |= ld.AttrReachable
o := func(op uint32) {
- ld.Adduint32(ld.Ctxt, initfunc, op)
+ ld.Adduint32(ctxt, initfunc, op)
}
// 0000000000000000 <local.dso_init>:
// 0: 90000000 adrp x0, 0 <runtime.firstmoduledata>
@@ -66,7 +66,7 @@ func gentext() {
rel := ld.Addrel(initfunc)
rel.Off = 0
rel.Siz = 8
- rel.Sym = ld.Ctxt.Moduledata
+ rel.Sym = ctxt.Moduledata
rel.Type = obj.R_ADDRARM64
// 8: 14000000 bl 0 <runtime.addmoduledata>
@@ -75,22 +75,23 @@ func gentext() {
rel = ld.Addrel(initfunc)
rel.Off = 8
rel.Siz = 4
- rel.Sym = ld.Linklookup(ld.Ctxt, "runtime.addmoduledata", 0)
+ 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
- ld.Ctxt.Textp = append(ld.Ctxt.Textp, initfunc)
- initarray_entry := ld.Linklookup(ld.Ctxt, "go.link.addmoduledatainit", 0)
+ 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
- ld.Addaddr(ld.Ctxt, initarray_entry, initfunc)
+ ld.Addaddr(ctxt, initarray_entry, initfunc)
}
-func adddynrel(s *ld.LSym, r *ld.Reloc) {
+func adddynrel(ctxt *ld.Link, s *ld.Symbol, r *ld.Reloc) bool {
log.Fatalf("adddynrel not implemented")
+ return false
}
-func elfreloc1(r *ld.Reloc, sectoff int64) int {
+func elfreloc1(ctxt *ld.Link, r *ld.Reloc, sectoff int64) int {
ld.Thearch.Vput(uint64(sectoff))
elfsym := r.Xsym.ElfsymForReloc()
@@ -142,12 +143,12 @@ func elfreloc1(r *ld.Reloc, sectoff int64) int {
return 0
}
-func elfsetupplt() {
+func elfsetupplt(ctxt *ld.Link) {
// TODO(aram)
return
}
-func machoreloc1(r *ld.Reloc, sectoff int64) int {
+func machoreloc1(s *ld.Symbol, r *ld.Reloc, sectoff int64) int {
var v uint32
rs := r.Xsym
@@ -157,7 +158,7 @@ func machoreloc1(r *ld.Reloc, sectoff int64) int {
// UNSIGNED relocation at all.
if rs.Type == obj.SHOSTOBJ || r.Type == obj.R_CALLARM64 || r.Type == obj.R_ADDRARM64 || r.Type == obj.R_ADDR {
if rs.Dynid < 0 {
- ld.Diag("reloc %d to non-macho symbol %s type=%d", r.Type, rs.Name, rs.Type)
+ ld.Errorf(s, "reloc %d to non-macho symbol %s type=%d", r.Type, rs.Name, rs.Type)
return -1
}
@@ -166,7 +167,7 @@ func machoreloc1(r *ld.Reloc, sectoff int64) int {
} else {
v = uint32(rs.Sect.Extnum)
if v == 0 {
- ld.Diag("reloc %d to symbol %s in non-macho section %s type=%d", r.Type, rs.Name, rs.Sect.Name, rs.Type)
+ ld.Errorf(s, "reloc %d to symbol %s in non-macho section %s type=%d", r.Type, rs.Name, rs.Sect.Name, rs.Type)
return -1
}
}
@@ -180,7 +181,7 @@ func machoreloc1(r *ld.Reloc, sectoff int64) int {
case obj.R_CALLARM64:
if r.Xadd != 0 {
- ld.Diag("ld64 doesn't allow BR26 reloc with non-zero addend: %s+%d", rs.Name, r.Xadd)
+ ld.Errorf(s, "ld64 doesn't allow BR26 reloc with non-zero addend: %s+%d", rs.Name, r.Xadd)
}
v |= 1 << 24 // pc-relative bit
@@ -226,7 +227,7 @@ func machoreloc1(r *ld.Reloc, sectoff int64) int {
return 0
}
-func archreloc(r *ld.Reloc, s *ld.LSym, val *int64) int {
+func archreloc(ctxt *ld.Link, r *ld.Reloc, s *ld.Symbol, val *int64) int {
if ld.Linkmode == ld.LinkExternal {
switch r.Type {
default:
@@ -234,7 +235,7 @@ func archreloc(r *ld.Reloc, s *ld.LSym, val *int64) int {
case obj.R_ARM64_GOTPCREL:
var o1, o2 uint32
- if ld.Ctxt.Arch.ByteOrder == binary.BigEndian {
+ if ctxt.Arch.ByteOrder == binary.BigEndian {
o1 = uint32(*val >> 32)
o2 = uint32(*val)
} else {
@@ -249,14 +250,14 @@ func archreloc(r *ld.Reloc, s *ld.LSym, val *int64) int {
// (https://sourceware.org/bugzilla/show_bug.cgi?id=18270). So
// we convert the adrp; ld64 + R_ARM64_GOTPCREL into adrp;
// add + R_ADDRARM64.
- if !(r.Sym.Version != 0 || (r.Sym.Type&obj.SHIDDEN != 0) || r.Sym.Attr.Local()) && r.Sym.Type == obj.STEXT && ld.DynlinkingGo() {
+ if !(r.Sym.Version != 0 || (r.Sym.Type&obj.SHIDDEN != 0) || r.Sym.Attr.Local()) && r.Sym.Type == obj.STEXT && ctxt.DynlinkingGo() {
if o2&0xffc00000 != 0xf9400000 {
- ld.Ctxt.Diag("R_ARM64_GOTPCREL against unexpected instruction %x", o2)
+ ld.Errorf(s, "R_ARM64_GOTPCREL against unexpected instruction %x", o2)
}
o2 = 0x91000000 | (o2 & 0x000003ff)
r.Type = obj.R_ADDRARM64
}
- if ld.Ctxt.Arch.ByteOrder == binary.BigEndian {
+ if ctxt.Arch.ByteOrder == binary.BigEndian {
*val = int64(o1)<<32 | int64(o2)
} else {
*val = int64(o2)<<32 | int64(o1)
@@ -275,7 +276,7 @@ func archreloc(r *ld.Reloc, s *ld.LSym, val *int64) int {
}
if rs.Type != obj.SHOSTOBJ && rs.Type != obj.SDYNIMPORT && rs.Sect == nil {
- ld.Diag("missing section for %s", rs.Name)
+ ld.Errorf(s, "missing section for %s", rs.Name)
}
r.Xsym = rs
@@ -284,10 +285,10 @@ func archreloc(r *ld.Reloc, s *ld.LSym, 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 == obj.Hdarwin {
var o0, o1 uint32
- if ld.Ctxt.Arch.ByteOrder == binary.BigEndian {
+ if ctxt.Arch.ByteOrder == binary.BigEndian {
o0 = uint32(*val >> 32)
o1 = uint32(*val)
} else {
@@ -304,7 +305,7 @@ func archreloc(r *ld.Reloc, s *ld.LSym, val *int64) int {
r.Xadd = 0
// when laid out, the instruction order must always be o1, o2.
- if ld.Ctxt.Arch.ByteOrder == binary.BigEndian {
+ if ctxt.Arch.ByteOrder == binary.BigEndian {
*val = int64(o0)<<32 | int64(o1)
} else {
*val = int64(o1)<<32 | int64(o0)
@@ -329,18 +330,18 @@ func archreloc(r *ld.Reloc, s *ld.LSym, val *int64) int {
return 0
case obj.R_GOTOFF:
- *val = ld.Symaddr(r.Sym) + r.Add - ld.Symaddr(ld.Linklookup(ld.Ctxt, ".got", 0))
+ *val = ld.Symaddr(r.Sym) + r.Add - ld.Symaddr(ctxt.Syms.Lookup(".got", 0))
return 0
case obj.R_ADDRARM64:
t := ld.Symaddr(r.Sym) + r.Add - ((s.Value + int64(r.Off)) &^ 0xfff)
if t >= 1<<32 || t < -1<<32 {
- ld.Diag("program too large, address relocation distance = %d", t)
+ ld.Errorf(s, "program too large, address relocation distance = %d", t)
}
var o0, o1 uint32
- if ld.Ctxt.Arch.ByteOrder == binary.BigEndian {
+ if ctxt.Arch.ByteOrder == binary.BigEndian {
o0 = uint32(*val >> 32)
o1 = uint32(*val)
} else {
@@ -352,7 +353,7 @@ func archreloc(r *ld.Reloc, s *ld.LSym, val *int64) int {
o1 |= uint32(t&0xfff) << 10
// when laid out, the instruction order must always be o1, o2.
- if ld.Ctxt.Arch.ByteOrder == binary.BigEndian {
+ if ctxt.Arch.ByteOrder == binary.BigEndian {
*val = int64(o0)<<32 | int64(o1)
} else {
*val = int64(o1)<<32 | int64(o0)
@@ -361,14 +362,14 @@ func archreloc(r *ld.Reloc, s *ld.LSym, val *int64) int {
case obj.R_ARM64_TLS_LE:
r.Done = 0
- if ld.HEADTYPE != obj.Hlinux {
- ld.Diag("TLS reloc on unsupported OS %s", ld.Headstr(int(ld.HEADTYPE)))
+ if ld.Headtype != obj.Hlinux {
+ ld.Errorf(s, "TLS reloc on unsupported OS %v", ld.Headtype)
}
// The TCB is two pointers. This is not documented anywhere, but is
// de facto part of the ABI.
v := r.Sym.Value + int64(2*ld.SysArch.PtrSize)
if v < 0 || v >= 32678 {
- ld.Diag("TLS offset out of range %d", v)
+ ld.Errorf(s, "TLS offset out of range %d", v)
}
*val |= v << 5
return 0
@@ -376,7 +377,7 @@ func archreloc(r *ld.Reloc, s *ld.LSym, val *int64) int {
case obj.R_CALLARM64:
t := (ld.Symaddr(r.Sym) + r.Add) - (s.Value + int64(r.Off))
if t >= 1<<27 || t < -1<<27 {
- ld.Diag("program too large, call relocation distance = %d", t)
+ ld.Errorf(s, "program too large, call relocation distance = %d", t)
}
*val |= (t >> 2) & 0x03ffffff
return 0
@@ -385,16 +386,15 @@ func archreloc(r *ld.Reloc, s *ld.LSym, val *int64) int {
return -1
}
-func archrelocvariant(r *ld.Reloc, s *ld.LSym, t int64) int64 {
+func archrelocvariant(ctxt *ld.Link, r *ld.Reloc, s *ld.Symbol, t int64) int64 {
log.Fatalf("unexpected relocation variant")
return -1
}
-func asmb() {
- if ld.Debug['v'] != 0 {
- fmt.Fprintf(ld.Bso, "%5.2f asmb\n", obj.Cputime())
+func asmb(ctxt *ld.Link) {
+ if ctxt.Debugvlog != 0 {
+ ctxt.Logf("%5.2f asmb\n", obj.Cputime())
}
- ld.Bso.Flush()
if ld.Iself {
ld.Asmbelfsetup()
@@ -402,36 +402,40 @@ func asmb() {
sect := ld.Segtext.Sect
ld.Cseek(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
- ld.Codeblk(int64(sect.Vaddr), int64(sect.Length))
+ ld.Codeblk(ctxt, int64(sect.Vaddr), int64(sect.Length))
for sect = sect.Next; sect != nil; sect = sect.Next {
ld.Cseek(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
- ld.Datblk(int64(sect.Vaddr), int64(sect.Length))
+ ld.Datblk(ctxt, int64(sect.Vaddr), int64(sect.Length))
}
if ld.Segrodata.Filelen > 0 {
- if ld.Debug['v'] != 0 {
- fmt.Fprintf(ld.Bso, "%5.2f rodatblk\n", obj.Cputime())
+ if ctxt.Debugvlog != 0 {
+ ctxt.Logf("%5.2f rodatblk\n", obj.Cputime())
}
- ld.Bso.Flush()
-
ld.Cseek(int64(ld.Segrodata.Fileoff))
- ld.Datblk(int64(ld.Segrodata.Vaddr), int64(ld.Segrodata.Filelen))
+ 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())
+ }
+ ld.Cseek(int64(ld.Segrelrodata.Fileoff))
+ ld.Datblk(ctxt, int64(ld.Segrelrodata.Vaddr), int64(ld.Segrelrodata.Filelen))
}
- if ld.Debug['v'] != 0 {
- fmt.Fprintf(ld.Bso, "%5.2f datblk\n", obj.Cputime())
+ if ctxt.Debugvlog != 0 {
+ ctxt.Logf("%5.2f datblk\n", obj.Cputime())
}
- ld.Bso.Flush()
ld.Cseek(int64(ld.Segdata.Fileoff))
- ld.Datblk(int64(ld.Segdata.Vaddr), int64(ld.Segdata.Filelen))
+ ld.Datblk(ctxt, int64(ld.Segdata.Vaddr), int64(ld.Segdata.Filelen))
ld.Cseek(int64(ld.Segdwarf.Fileoff))
- ld.Dwarfblk(int64(ld.Segdwarf.Vaddr), int64(ld.Segdwarf.Filelen))
+ ld.Dwarfblk(ctxt, int64(ld.Segdwarf.Vaddr), int64(ld.Segdwarf.Filelen))
machlink := uint32(0)
- if ld.HEADTYPE == obj.Hdarwin {
- machlink = uint32(ld.Domacholink())
+ if ld.Headtype == obj.Hdarwin {
+ machlink = uint32(ld.Domacholink(ctxt))
}
/* output symbol table */
@@ -439,47 +443,46 @@ func asmb() {
ld.Lcsize = 0
symo := uint32(0)
- if ld.Debug['s'] == 0 {
+ if !*ld.FlagS {
// TODO: rationalize
- if ld.Debug['v'] != 0 {
- fmt.Fprintf(ld.Bso, "%5.2f sym\n", obj.Cputime())
+ if ctxt.Debugvlog != 0 {
+ ctxt.Logf("%5.2f sym\n", obj.Cputime())
}
- ld.Bso.Flush()
- switch ld.HEADTYPE {
+ switch ld.Headtype {
default:
if ld.Iself {
symo = uint32(ld.Segdwarf.Fileoff + ld.Segdwarf.Filelen)
- symo = uint32(ld.Rnd(int64(symo), int64(ld.INITRND)))
+ symo = uint32(ld.Rnd(int64(symo), int64(*ld.FlagRound)))
}
case obj.Hplan9:
symo = uint32(ld.Segdata.Fileoff + ld.Segdata.Filelen)
case obj.Hdarwin:
- symo = uint32(ld.Segdwarf.Fileoff + uint64(ld.Rnd(int64(ld.Segdwarf.Filelen), int64(ld.INITRND))) + uint64(machlink))
+ symo = uint32(ld.Segdwarf.Fileoff + uint64(ld.Rnd(int64(ld.Segdwarf.Filelen), int64(*ld.FlagRound))) + uint64(machlink))
}
ld.Cseek(int64(symo))
- switch ld.HEADTYPE {
+ switch ld.Headtype {
default:
if ld.Iself {
- if ld.Debug['v'] != 0 {
- fmt.Fprintf(ld.Bso, "%5.2f elfsym\n", obj.Cputime())
+ if ctxt.Debugvlog != 0 {
+ ctxt.Logf("%5.2f elfsym\n", obj.Cputime())
}
- ld.Asmelfsym()
+ ld.Asmelfsym(ctxt)
ld.Cflush()
ld.Cwrite(ld.Elfstrdat)
if ld.Linkmode == ld.LinkExternal {
- ld.Elfemitreloc()
+ ld.Elfemitreloc(ctxt)
}
}
case obj.Hplan9:
- ld.Asmplan9sym()
+ ld.Asmplan9sym(ctxt)
ld.Cflush()
- sym := ld.Linklookup(ld.Ctxt, "pclntab", 0)
+ sym := ctxt.Syms.Lookup("pclntab", 0)
if sym != nil {
ld.Lcsize = int32(len(sym.P))
for i := 0; int32(i) < ld.Lcsize; i++ {
@@ -491,26 +494,24 @@ func asmb() {
case obj.Hdarwin:
if ld.Linkmode == ld.LinkExternal {
- ld.Machoemitreloc()
+ ld.Machoemitreloc(ctxt)
}
}
}
- ld.Ctxt.Cursym = nil
- if ld.Debug['v'] != 0 {
- fmt.Fprintf(ld.Bso, "%5.2f header\n", obj.Cputime())
+ if ctxt.Debugvlog != 0 {
+ ctxt.Logf("%5.2f header\n", obj.Cputime())
}
- ld.Bso.Flush()
ld.Cseek(0)
- switch ld.HEADTYPE {
+ switch ld.Headtype {
default:
case obj.Hplan9: /* plan 9 */
ld.Thearch.Lput(0x647) /* magic */
ld.Thearch.Lput(uint32(ld.Segtext.Filelen)) /* sizes */
ld.Thearch.Lput(uint32(ld.Segdata.Filelen))
ld.Thearch.Lput(uint32(ld.Segdata.Length - ld.Segdata.Filelen))
- ld.Thearch.Lput(uint32(ld.Symsize)) /* nsyms */
- ld.Thearch.Lput(uint32(ld.Entryvalue())) /* va of entry */
+ ld.Thearch.Lput(uint32(ld.Symsize)) /* nsyms */
+ ld.Thearch.Lput(uint32(ld.Entryvalue(ctxt))) /* va of entry */
ld.Thearch.Lput(0)
ld.Thearch.Lput(uint32(ld.Lcsize))
@@ -519,14 +520,14 @@ func asmb() {
obj.Hnetbsd,
obj.Hopenbsd,
obj.Hnacl:
- ld.Asmbelf(int64(symo))
+ ld.Asmbelf(ctxt, int64(symo))
case obj.Hdarwin:
- ld.Asmbmacho()
+ ld.Asmbmacho(ctxt)
}
ld.Cflush()
- if ld.Debug['c'] != 0 {
+ if *ld.FlagC {
fmt.Printf("textsize=%d\n", ld.Segtext.Filelen)
fmt.Printf("datsize=%d\n", ld.Segdata.Filelen)
fmt.Printf("bsssize=%d\n", ld.Segdata.Length-ld.Segdata.Filelen)
diff --git a/src/cmd/link/internal/arm64/l.go b/src/cmd/link/internal/arm64/l.go
index cbee2a3..50b88e4 100644
--- a/src/cmd/link/internal/arm64/l.go
+++ b/src/cmd/link/internal/arm64/l.go
@@ -1,5 +1,5 @@
// Inferno utils/5l/asm.c
-// http://code.google.com/p/inferno-os/source/browse/utils/5l/asm.c
+// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5l/asm.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth at terzarima.net)
@@ -62,13 +62,13 @@ package arm64
// THE SOFTWARE.
const (
- MaxAlign = 32 // max data alignment
- MinAlign = 1 // min data alignment
- FuncAlign = 8
+ maxAlign = 32 // max data alignment
+ minAlign = 1 // min data alignment
+ funcAlign = 8
)
/* Used by ../internal/ld/dwarf.go */
const (
- DWARFREGSP = 31
- DWARFREGLR = 30
+ dwarfRegSP = 31
+ dwarfRegLR = 30
)
diff --git a/src/cmd/link/internal/arm64/obj.go b/src/cmd/link/internal/arm64/obj.go
index 86f9ff7..7d49163 100644
--- a/src/cmd/link/internal/arm64/obj.go
+++ b/src/cmd/link/internal/arm64/obj.go
@@ -1,5 +1,5 @@
// Inferno utils/5l/obj.c
-// http://code.google.com/p/inferno-os/source/browse/utils/5l/obj.c
+// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5l/obj.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth at terzarima.net)
@@ -35,24 +35,16 @@ import (
"cmd/internal/sys"
"cmd/link/internal/ld"
"fmt"
- "log"
)
-// Reading object files.
-
-func Main() {
- linkarchinit()
- ld.Ldmain()
-}
-
-func linkarchinit() {
+func Init() {
ld.SysArch = sys.ArchARM64
- ld.Thearch.Funcalign = FuncAlign
- ld.Thearch.Maxalign = MaxAlign
- ld.Thearch.Minalign = MinAlign
- ld.Thearch.Dwarfregsp = DWARFREGSP
- ld.Thearch.Dwarfreglr = DWARFREGLR
+ ld.Thearch.Funcalign = funcAlign
+ ld.Thearch.Maxalign = maxAlign
+ ld.Thearch.Minalign = minAlign
+ ld.Thearch.Dwarfregsp = dwarfRegSP
+ ld.Thearch.Dwarfreglr = dwarfRegLR
ld.Thearch.Adddynrel = adddynrel
ld.Thearch.Archinit = archinit
@@ -79,94 +71,67 @@ func linkarchinit() {
ld.Thearch.Solarisdynld = "XXX"
}
-func archinit() {
- // getgoextlinkenabled is based on GO_EXTLINK_ENABLED when
- // Go was built; see ../../make.bash.
- if ld.Linkmode == ld.LinkAuto && obj.Getgoextlinkenabled() == "0" {
- ld.Linkmode = ld.LinkInternal
- }
-
- // Darwin/arm64 only supports external linking
- if ld.HEADTYPE == obj.Hdarwin {
- ld.Linkmode = ld.LinkExternal
- }
-
- switch ld.HEADTYPE {
- default:
- if ld.Linkmode == ld.LinkAuto {
- ld.Linkmode = ld.LinkInternal
- }
- if ld.Linkmode == ld.LinkExternal && obj.Getgoextlinkenabled() != "1" {
- log.Fatalf("cannot use -linkmode=external with -H %s", ld.Headstr(int(ld.HEADTYPE)))
- }
- case obj.Hlinux, obj.Hdarwin:
- break
- }
-
- if ld.Buildmode == ld.BuildmodeCShared || ld.DynlinkingGo() {
- ld.Linkmode = ld.LinkExternal
- }
-
- switch ld.HEADTYPE {
+func archinit(ctxt *ld.Link) {
+ switch ld.Headtype {
default:
- ld.Exitf("unknown -H option: %v", ld.HEADTYPE)
+ ld.Exitf("unknown -H option: %v", ld.Headtype)
case obj.Hplan9: /* plan 9 */
ld.HEADR = 32
- if ld.INITTEXT == -1 {
- ld.INITTEXT = 4128
+ if *ld.FlagTextAddr == -1 {
+ *ld.FlagTextAddr = 4096 + int64(ld.HEADR)
}
- if ld.INITDAT == -1 {
- ld.INITDAT = 0
+ if *ld.FlagDataAddr == -1 {
+ *ld.FlagDataAddr = 0
}
- if ld.INITRND == -1 {
- ld.INITRND = 4096
+ if *ld.FlagRound == -1 {
+ *ld.FlagRound = 4096
}
case obj.Hlinux: /* arm64 elf */
- ld.Elfinit()
+ ld.Elfinit(ctxt)
ld.HEADR = ld.ELFRESERVE
- if ld.INITTEXT == -1 {
- ld.INITTEXT = 0x10000 + int64(ld.HEADR)
+ if *ld.FlagTextAddr == -1 {
+ *ld.FlagTextAddr = 0x10000 + int64(ld.HEADR)
}
- if ld.INITDAT == -1 {
- ld.INITDAT = 0
+ if *ld.FlagDataAddr == -1 {
+ *ld.FlagDataAddr = 0
}
- if ld.INITRND == -1 {
- ld.INITRND = 0x10000
+ if *ld.FlagRound == -1 {
+ *ld.FlagRound = 0x10000
}
case obj.Hdarwin: /* apple MACH */
- ld.Debug['w'] = 1 // disable DWARF generation
+ *ld.FlagW = true // disable DWARF generation
ld.Machoinit()
ld.HEADR = ld.INITIAL_MACHO_HEADR
- if ld.INITTEXT == -1 {
- ld.INITTEXT = 4096 + int64(ld.HEADR)
+ if *ld.FlagTextAddr == -1 {
+ *ld.FlagTextAddr = 4096 + int64(ld.HEADR)
}
- if ld.INITDAT == -1 {
- ld.INITDAT = 0
+ if *ld.FlagDataAddr == -1 {
+ *ld.FlagDataAddr = 0
}
- if ld.INITRND == -1 {
- ld.INITRND = 4096
+ if *ld.FlagRound == -1 {
+ *ld.FlagRound = 4096
}
case obj.Hnacl:
- ld.Elfinit()
+ ld.Elfinit(ctxt)
ld.HEADR = 0x10000
ld.Funcalign = 16
- if ld.INITTEXT == -1 {
- ld.INITTEXT = 0x20000
+ if *ld.FlagTextAddr == -1 {
+ *ld.FlagTextAddr = 0x20000
}
- if ld.INITDAT == -1 {
- ld.INITDAT = 0
+ if *ld.FlagDataAddr == -1 {
+ *ld.FlagDataAddr = 0
}
- if ld.INITRND == -1 {
- ld.INITRND = 0x10000
+ if *ld.FlagRound == -1 {
+ *ld.FlagRound = 0x10000
}
}
- if ld.INITDAT != 0 && ld.INITRND != 0 {
- fmt.Printf("warning: -D0x%x is ignored because of -R0x%x\n", uint64(ld.INITDAT), uint32(ld.INITRND))
+ if *ld.FlagDataAddr != 0 && *ld.FlagRound != 0 {
+ fmt.Printf("warning: -D0x%x is ignored because of -R0x%x\n", uint64(*ld.FlagDataAddr), uint32(*ld.FlagRound))
}
}
diff --git a/src/cmd/link/internal/ld/ar.go b/src/cmd/link/internal/ld/ar.go
index 80c33ce..6db672f 100644
--- a/src/cmd/link/internal/ld/ar.go
+++ b/src/cmd/link/internal/ld/ar.go
@@ -1,5 +1,5 @@
// Inferno utils/include/ar.h
-// http://code.google.com/p/inferno-os/source/browse/utils/include/ar.h
+// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/include/ar.h
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth at terzarima.net)
@@ -63,13 +63,13 @@ type ArHdr struct {
// file, but it has an armap listing symbols and the objects that
// define them. This is used for the compiler support library
// libgcc.a.
-func hostArchive(name string) {
+func hostArchive(ctxt *Link, name string) {
f, err := bio.Open(name)
if err != nil {
if os.IsNotExist(err) {
// It's OK if we don't have a libgcc file at all.
- if Debug['v'] != 0 {
- fmt.Fprintf(Bso, "skipping libgcc file: %v\n", err)
+ if ctxt.Debugvlog != 0 {
+ ctxt.Logf("skipping libgcc file: %v\n", err)
}
return
}
@@ -99,7 +99,7 @@ func hostArchive(name string) {
any := true
for any {
var load []uint64
- for _, s := range Ctxt.Allsym {
+ for _, s := range ctxt.Syms.Allsym {
for _, r := range s.R {
if r.Sym != nil && r.Sym.Type&obj.SMASK == obj.SXREF {
if off := armap[r.Sym.Name]; off != 0 && !loaded[off] {
@@ -118,9 +118,10 @@ func hostArchive(name string) {
pname := fmt.Sprintf("%s(%s)", name, arhdr.name)
l = atolwhex(arhdr.size)
- h := ldobj(f, "libgcc", l, pname, name, ArchiveObj)
+ libgcc := Library{Pkg: "libgcc"}
+ h := ldobj(ctxt, f, &libgcc, l, pname, name, ArchiveObj)
f.Seek(h.off, 0)
- h.ld(f, h.pkg, h.length, h.pn)
+ h.ld(ctxt, f, h.pkg, h.length, h.pn)
}
any = len(load) > 0
@@ -165,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 goos == "darwin" || (goos == "windows" && goarch == "386") {
+ if obj.GOOS == "darwin" || (obj.GOOS == "windows" && obj.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
new file mode 100644
index 0000000..c9ee884
--- /dev/null
+++ b/src/cmd/link/internal/ld/config.go
@@ -0,0 +1,250 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ld
+
+import (
+ "cmd/internal/obj"
+ "cmd/internal/sys"
+ "fmt"
+ "log"
+)
+
+var (
+ Linkmode LinkMode
+ Buildmode BuildMode
+)
+
+// A BuildMode indicates the sort of object we are building.
+//
+// Possible build modes are the same as those for the -buildmode flag
+// in cmd/go, and are documented in 'go help buildmode'.
+type BuildMode uint8
+
+const (
+ BuildmodeUnset BuildMode = iota
+ BuildmodeExe
+ BuildmodePIE
+ BuildmodeCArchive
+ BuildmodeCShared
+ BuildmodeShared
+ BuildmodePlugin
+)
+
+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)
+ }
+ switch s {
+ default:
+ return fmt.Errorf("invalid buildmode: %q", s)
+ case "exe":
+ *mode = BuildmodeExe
+ case "pie":
+ switch obj.GOOS {
+ case "android", "linux":
+ default:
+ return badmode()
+ }
+ *mode = BuildmodePIE
+ case "c-archive":
+ switch obj.GOOS {
+ case "darwin", "linux":
+ case "windows":
+ switch obj.GOARCH {
+ case "amd64", "386":
+ default:
+ return badmode()
+ }
+ default:
+ return badmode()
+ }
+ *mode = BuildmodeCArchive
+ case "c-shared":
+ switch obj.GOARCH {
+ case "386", "amd64", "arm", "arm64":
+ default:
+ return badmode()
+ }
+ *mode = BuildmodeCShared
+ case "shared":
+ switch obj.GOOS {
+ case "linux":
+ switch obj.GOARCH {
+ case "386", "amd64", "arm", "arm64", "ppc64le", "s390x":
+ default:
+ return badmode()
+ }
+ default:
+ return badmode()
+ }
+ *mode = BuildmodeShared
+ case "plugin":
+ switch obj.GOOS {
+ case "linux":
+ switch obj.GOARCH {
+ case "386", "amd64", "arm", "arm64":
+ default:
+ return badmode()
+ }
+ case "darwin":
+ switch obj.GOARCH {
+ case "amd64":
+ default:
+ return badmode()
+ }
+ default:
+ return badmode()
+ }
+ *mode = BuildmodePlugin
+ }
+ return nil
+}
+
+func (mode *BuildMode) String() string {
+ switch *mode {
+ case BuildmodeUnset:
+ return "" // avoid showing a default in usage message
+ case BuildmodeExe:
+ return "exe"
+ case BuildmodePIE:
+ return "pie"
+ case BuildmodeCArchive:
+ return "c-archive"
+ case BuildmodeCShared:
+ return "c-shared"
+ case BuildmodeShared:
+ return "shared"
+ case BuildmodePlugin:
+ return "plugin"
+ }
+ return fmt.Sprintf("BuildMode(%d)", uint8(*mode))
+}
+
+// LinkMode indicates whether an external linker is used for the final link.
+type LinkMode uint8
+
+const (
+ LinkAuto LinkMode = iota
+ LinkInternal
+ LinkExternal
+)
+
+func (mode *LinkMode) Set(s string) error {
+ switch s {
+ default:
+ return fmt.Errorf("invalid linkmode: %q", s)
+ case "auto":
+ *mode = LinkAuto
+ case "internal":
+ *mode = LinkInternal
+ case "external":
+ *mode = LinkExternal
+ }
+ return nil
+}
+
+func (mode *LinkMode) String() string {
+ switch *mode {
+ case LinkAuto:
+ return "auto"
+ case LinkInternal:
+ return "internal"
+ case LinkExternal:
+ return "external"
+ }
+ return fmt.Sprintf("LinkMode(%d)", uint8(*mode))
+}
+
+// mustLinkExternal reports whether the program being linked requires
+// the external linker be used to complete the link.
+func mustLinkExternal(ctxt *Link) (res bool, reason string) {
+ if ctxt.Debugvlog > 1 {
+ defer func() {
+ if res {
+ log.Printf("external linking is forced by: %s\n", reason)
+ }
+ }()
+ }
+
+ switch obj.GOOS {
+ case "android":
+ return true, "android"
+ case "darwin":
+ if SysArch.InFamily(sys.ARM, sys.ARM64) {
+ return true, "iOS"
+ }
+ }
+
+ if *flagMsan {
+ return true, "msan"
+ }
+
+ // Internally linking cgo is incomplete on some architectures.
+ // https://golang.org/issue/10373
+ // https://golang.org/issue/14449
+ if iscgo && SysArch.InFamily(sys.ARM64, sys.MIPS64) {
+ return true, obj.GOARCH + " does not support internal cgo"
+ }
+
+ // Some build modes require work the internal linker cannot do (yet).
+ switch Buildmode {
+ case BuildmodeCArchive:
+ return true, "buildmode=c-archive"
+ case BuildmodeCShared:
+ return true, "buildmode=c-shared"
+ case BuildmodePIE:
+ switch obj.GOOS + "/" + obj.GOARCH {
+ case "linux/amd64":
+ default:
+ // Internal linking does not support TLS_IE.
+ return true, "buildmode=pie"
+ }
+ case BuildmodePlugin:
+ return true, "buildmode=plugin"
+ case BuildmodeShared:
+ return true, "buildmode=shared"
+ }
+ if *FlagLinkshared {
+ return true, "dynamically linking with a shared library"
+ }
+
+ return false, ""
+}
+
+// determineLinkMode sets Linkmode.
+//
+// It is called after flags are processed and inputs are processed,
+// so the Linkmode variable has an initial value from the -linkmode
+// flag and the iscgo externalobj variables are set.
+func determineLinkMode(ctxt *Link) {
+ switch Linkmode {
+ case LinkAuto:
+ // The environment variable GO_EXTLINK_ENABLED controls the
+ // 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() {
+ case "0":
+ if needed, reason := mustLinkExternal(ctxt); needed {
+ Exitf("internal linking requested via GO_EXTLINK_ENABLED, but external linking required: %s", reason)
+ }
+ Linkmode = LinkInternal
+ case "1":
+ Linkmode = LinkExternal
+ default:
+ if needed, _ := mustLinkExternal(ctxt); needed {
+ Linkmode = LinkExternal
+ } else if iscgo && externalobj {
+ Linkmode = LinkExternal
+ } else {
+ Linkmode = LinkInternal
+ }
+ }
+ case LinkInternal:
+ if needed, reason := mustLinkExternal(ctxt); needed {
+ Exitf("internal linking requested 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 57a0dad..eaf6aa2 100644
--- a/src/cmd/link/internal/ld/data.go
+++ b/src/cmd/link/internal/ld/data.go
@@ -1,6 +1,6 @@
// Derived from Inferno utils/6l/obj.c and utils/6l/span.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6l/obj.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6l/span.c
+// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/obj.c
+// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/span.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth at terzarima.net)
@@ -44,7 +44,7 @@ import (
"sync"
)
-func Symgrow(ctxt *Link, s *LSym, siz int64) {
+func Symgrow(s *Symbol, siz int64) {
if int64(int(siz)) != siz {
log.Fatalf("symgrow size %d too long", siz)
}
@@ -58,19 +58,19 @@ func Symgrow(ctxt *Link, s *LSym, siz int64) {
s.P = s.P[:siz]
}
-func Addrel(s *LSym) *Reloc {
+func Addrel(s *Symbol) *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 {
+func setuintxx(ctxt *Link, s *Symbol, off int64, v uint64, wid int64) int64 {
if s.Type == 0 {
s.Type = obj.SDATA
}
s.Attr |= AttrReachable
if s.Size < off+wid {
s.Size = off + wid
- Symgrow(ctxt, s, s.Size)
+ Symgrow(s, s.Size)
}
switch wid {
@@ -87,7 +87,7 @@ func setuintxx(ctxt *Link, s *LSym, off int64, v uint64, wid int64) int64 {
return off + wid
}
-func Addbytes(ctxt *Link, s *LSym, bytes []byte) int64 {
+func Addbytes(s *Symbol, bytes []byte) int64 {
if s.Type == 0 {
s.Type = obj.SDATA
}
@@ -98,13 +98,13 @@ func Addbytes(ctxt *Link, s *LSym, bytes []byte) int64 {
return s.Size
}
-func adduintxx(ctxt *Link, s *LSym, v uint64, wid int) int64 {
+func adduintxx(ctxt *Link, s *Symbol, v uint64, wid int) int64 {
off := s.Size
setuintxx(ctxt, s, off, v, int64(wid))
return off
}
-func Adduint8(ctxt *Link, s *LSym, v uint8) int64 {
+func Adduint8(ctxt *Link, s *Symbol, v uint8) int64 {
off := s.Size
if s.Type == 0 {
s.Type = obj.SDATA
@@ -116,38 +116,38 @@ func Adduint8(ctxt *Link, s *LSym, v uint8) int64 {
return off
}
-func Adduint16(ctxt *Link, s *LSym, v uint16) int64 {
+func Adduint16(ctxt *Link, s *Symbol, v uint16) int64 {
return adduintxx(ctxt, s, uint64(v), 2)
}
-func Adduint32(ctxt *Link, s *LSym, v uint32) int64 {
+func Adduint32(ctxt *Link, s *Symbol, v uint32) int64 {
return adduintxx(ctxt, s, uint64(v), 4)
}
-func Adduint64(ctxt *Link, s *LSym, v uint64) int64 {
+func Adduint64(ctxt *Link, s *Symbol, v uint64) int64 {
return adduintxx(ctxt, s, v, 8)
}
-func adduint(ctxt *Link, s *LSym, v uint64) int64 {
+func adduint(ctxt *Link, s *Symbol, v uint64) int64 {
return adduintxx(ctxt, s, v, SysArch.IntSize)
}
-func setuint8(ctxt *Link, s *LSym, r int64, v uint8) int64 {
+func setuint8(ctxt *Link, s *Symbol, r int64, v uint8) int64 {
return setuintxx(ctxt, s, r, uint64(v), 1)
}
-func setuint32(ctxt *Link, s *LSym, r int64, v uint32) int64 {
+func setuint32(ctxt *Link, s *Symbol, r int64, v uint32) int64 {
return setuintxx(ctxt, s, r, uint64(v), 4)
}
-func Addaddrplus(ctxt *Link, s *LSym, t *LSym, add int64) int64 {
+func Addaddrplus(ctxt *Link, s *Symbol, t *Symbol, add int64) int64 {
if s.Type == 0 {
s.Type = obj.SDATA
}
s.Attr |= AttrReachable
i := s.Size
s.Size += int64(ctxt.Arch.PtrSize)
- Symgrow(ctxt, s, s.Size)
+ Symgrow(s, s.Size)
r := Addrel(s)
r.Sym = t
r.Off = int32(i)
@@ -157,14 +157,14 @@ func Addaddrplus(ctxt *Link, s *LSym, t *LSym, add int64) int64 {
return i + int64(r.Siz)
}
-func Addpcrelplus(ctxt *Link, s *LSym, t *LSym, add int64) int64 {
+func Addpcrelplus(ctxt *Link, s *Symbol, t *Symbol, add int64) int64 {
if s.Type == 0 {
s.Type = obj.SDATA
}
s.Attr |= AttrReachable
i := s.Size
s.Size += 4
- Symgrow(ctxt, s, s.Size)
+ Symgrow(s, s.Size)
r := Addrel(s)
r.Sym = t
r.Off = int32(i)
@@ -177,18 +177,18 @@ func Addpcrelplus(ctxt *Link, s *LSym, t *LSym, add int64) int64 {
return i + int64(r.Siz)
}
-func Addaddr(ctxt *Link, s *LSym, t *LSym) int64 {
+func Addaddr(ctxt *Link, s *Symbol, t *Symbol) int64 {
return Addaddrplus(ctxt, s, t, 0)
}
-func setaddrplus(ctxt *Link, s *LSym, off int64, t *LSym, add int64) int64 {
+func setaddrplus(ctxt *Link, s *Symbol, off int64, t *Symbol, add int64) int64 {
if s.Type == 0 {
s.Type = obj.SDATA
}
s.Attr |= AttrReachable
if off+int64(ctxt.Arch.PtrSize) > s.Size {
s.Size = off + int64(ctxt.Arch.PtrSize)
- Symgrow(ctxt, s, s.Size)
+ Symgrow(s, s.Size)
}
r := Addrel(s)
@@ -200,18 +200,18 @@ func setaddrplus(ctxt *Link, s *LSym, off int64, t *LSym, add int64) int64 {
return off + int64(r.Siz)
}
-func setaddr(ctxt *Link, s *LSym, off int64, t *LSym) int64 {
+func setaddr(ctxt *Link, s *Symbol, off int64, t *Symbol) int64 {
return setaddrplus(ctxt, s, off, t, 0)
}
-func addsize(ctxt *Link, s *LSym, t *LSym) int64 {
+func addsize(ctxt *Link, s *Symbol, t *Symbol) int64 {
if s.Type == 0 {
s.Type = obj.SDATA
}
s.Attr |= AttrReachable
i := s.Size
s.Size += int64(ctxt.Arch.PtrSize)
- Symgrow(ctxt, s, s.Size)
+ Symgrow(s, s.Size)
r := Addrel(s)
r.Sym = t
r.Off = int32(i)
@@ -220,14 +220,14 @@ func addsize(ctxt *Link, s *LSym, t *LSym) int64 {
return i + int64(r.Siz)
}
-func addaddrplus4(ctxt *Link, s *LSym, t *LSym, add int64) int64 {
+func addaddrplus4(ctxt *Link, s *Symbol, t *Symbol, add int64) int64 {
if s.Type == 0 {
s.Type = obj.SDATA
}
s.Attr |= AttrReachable
i := s.Size
s.Size += 4
- Symgrow(ctxt, s, s.Size)
+ Symgrow(s, s.Size)
r := Addrel(s)
r.Sym = t
r.Off = int32(i)
@@ -238,46 +238,41 @@ func addaddrplus4(ctxt *Link, s *LSym, t *LSym, add int64) int64 {
}
/*
- * divide-and-conquer list-link
- * sort of LSym* structures.
- * Used for the data block.
+ * divide-and-conquer list-link (by Sub) sort of Symbol* by Value.
+ * Used for sub-symbols when loading host objects (see e.g. ldelf.go).
*/
-func listsubp(s *LSym) **LSym {
- return &s.Sub
-}
-
-func listsort(l *LSym, cmp func(*LSym, *LSym) int, nextp func(*LSym) **LSym) *LSym {
- if l == nil || *nextp(l) == nil {
+func listsort(l *Symbol) *Symbol {
+ if l == nil || l.Sub == nil {
return l
}
l1 := l
l2 := l
for {
- l2 = *nextp(l2)
+ l2 = l2.Sub
if l2 == nil {
break
}
- l2 = *nextp(l2)
+ l2 = l2.Sub
if l2 == nil {
break
}
- l1 = *nextp(l1)
+ l1 = l1.Sub
}
- l2 = *nextp(l1)
- *nextp(l1) = nil
- l1 = listsort(l, cmp, nextp)
- l2 = listsort(l2, cmp, nextp)
+ l2 = l1.Sub
+ l1.Sub = nil
+ l1 = listsort(l)
+ l2 = listsort(l2)
/* set up lead element */
- if cmp(l1, l2) < 0 {
+ if l1.Value < l2.Value {
l = l1
- l1 = *nextp(l1)
+ l1 = l1.Sub
} else {
l = l2
- l2 = *nextp(l2)
+ l2 = l2.Sub
}
le := l
@@ -285,67 +280,121 @@ func listsort(l *LSym, cmp func(*LSym, *LSym) int, nextp func(*LSym) **LSym) *LS
for {
if l1 == nil {
for l2 != nil {
- *nextp(le) = l2
+ le.Sub = l2
le = l2
- l2 = *nextp(l2)
+ l2 = l2.Sub
}
- *nextp(le) = nil
+ le.Sub = nil
break
}
if l2 == nil {
for l1 != nil {
- *nextp(le) = l1
+ le.Sub = l1
le = l1
- l1 = *nextp(l1)
+ l1 = l1.Sub
}
break
}
- if cmp(l1, l2) < 0 {
- *nextp(le) = l1
+ if l1.Value < l2.Value {
+ le.Sub = l1
le = l1
- l1 = *nextp(l1)
+ l1 = l1.Sub
} else {
- *nextp(le) = l2
+ le.Sub = l2
le = l2
- l2 = *nextp(l2)
+ l2 = l2.Sub
}
}
- *nextp(le) = nil
+ le.Sub = nil
return l
}
-func relocsym(s *LSym) {
+// isRuntimeDepPkg returns whether pkg is the runtime package or its dependency
+func isRuntimeDepPkg(pkg string) bool {
+ switch pkg {
+ case "runtime",
+ "sync/atomic": // runtime may call to sync/atomic, due to go:linkname
+ return true
+ }
+ return strings.HasPrefix(pkg, "runtime/internal/") && !strings.HasSuffix(pkg, "_test")
+}
+
+// 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
+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 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)
+ }
+ // runtime and its dependent packages may call to each other.
+ // they are fine, as they will be laid down together.
+ }
+ continue
+ }
+
+ Thearch.Trampoline(ctxt, r, s)
+ }
+
+}
+
+// resolve relocations in s.
+func relocsym(ctxt *Link, s *Symbol) {
var r *Reloc
- var rs *LSym
+ var rs *Symbol
var i16 int16
var off int32
var siz int32
var fl int32
var o int64
- Ctxt.Cursym = s
for ri := int32(0); ri < int32(len(s.R)); ri++ {
r = &s.R[ri]
+
r.Done = 1
off = r.Off
siz = int32(r.Siz)
if off < 0 || off+siz > int32(len(s.P)) {
- Diag("%s: invalid relocation %d+%d not in [%d,%d)", s.Name, off, siz, 0, len(s.P))
+ rname := ""
+ if r.Sym != nil {
+ rname = r.Sym.Name
+ }
+ Errorf(s, "invalid relocation %s: %d+%d not in [%d,%d)", rname, off, siz, 0, len(s.P))
continue
}
if r.Sym != nil && (r.Sym.Type&(obj.SMASK|obj.SHIDDEN) == 0 || r.Sym.Type&obj.SMASK == obj.SXREF) {
// When putting the runtime but not main into a shared library
// these symbols are undefined and that's OK.
- if Buildmode == BuildmodeShared && (r.Sym.Name == "main.main" || r.Sym.Name == "main.init") {
- r.Sym.Type = obj.SDYNIMPORT
+ if Buildmode == BuildmodeShared {
+ if r.Sym.Name == "main.main" || r.Sym.Name == "main.init" {
+ r.Sym.Type = obj.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.
+ continue
+ }
} else {
- Diag("%s: not defined", r.Sym.Name)
+ Errorf(s, "relocation target %s not defined", r.Sym.Name)
continue
}
}
@@ -359,13 +408,13 @@ func relocsym(s *LSym) {
// We need to be able to reference dynimport symbols when linking against
// shared libraries, and Solaris needs it always
- if HEADTYPE != obj.Hsolaris && r.Sym != nil && r.Sym.Type == obj.SDYNIMPORT && !DynlinkingGo() {
+ if Headtype != obj.Hsolaris && r.Sym != nil && r.Sym.Type == obj.SDYNIMPORT && !ctxt.DynlinkingGo() {
if !(SysArch.Family == sys.PPC64 && Linkmode == LinkExternal && r.Sym.Name == ".TOC.") {
- Diag("unhandled relocation for %s (type %d rtype %d)", r.Sym.Name, r.Sym.Type, r.Type)
+ 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.Sym.Attr.Reachable() {
- Diag("unreachable sym in relocation: %s %s", s.Name, r.Sym.Name)
+ if r.Sym != nil && r.Sym.Type != obj.STLSBSS && r.Type != obj.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.
@@ -383,27 +432,27 @@ func relocsym(s *LSym) {
default:
switch siz {
default:
- Diag("bad reloc size %#x for %s", uint32(siz), r.Sym.Name)
+ Errorf(s, "bad reloc size %#x for %s", uint32(siz), r.Sym.Name)
case 1:
o = int64(s.P[off])
case 2:
- o = int64(Ctxt.Arch.ByteOrder.Uint16(s.P[off:]))
+ o = int64(ctxt.Arch.ByteOrder.Uint16(s.P[off:]))
case 4:
- o = int64(Ctxt.Arch.ByteOrder.Uint32(s.P[off:]))
+ o = int64(ctxt.Arch.ByteOrder.Uint32(s.P[off:]))
case 8:
- o = int64(Ctxt.Arch.ByteOrder.Uint64(s.P[off:]))
+ o = int64(ctxt.Arch.ByteOrder.Uint64(s.P[off:]))
}
- if Thearch.Archreloc(r, s, &o) < 0 {
- Diag("unknown reloc %d", r.Type)
+ if Thearch.Archreloc(ctxt, r, s, &o) < 0 {
+ Errorf(s, "unknown reloc to %v: %v", r.Sym.Name, r.Type)
}
case obj.R_TLS_LE:
- isAndroidX86 := goos == "android" && (SysArch.InFamily(sys.AMD64, sys.I386))
+ isAndroidX86 := obj.GOOS == "android" && (SysArch.InFamily(sys.AMD64, sys.I386))
- if Linkmode == LinkExternal && Iself && HEADTYPE != obj.Hopenbsd && !isAndroidX86 {
+ if Linkmode == LinkExternal && Iself && Headtype != obj.Hopenbsd && !isAndroidX86 {
r.Done = 0
if r.Sym == nil {
- r.Sym = Ctxt.Tlsg
+ r.Sym = ctxt.Tlsg
}
r.Xsym = r.Sym
r.Xadd = r.Add
@@ -423,21 +472,21 @@ func relocsym(s *LSym) {
// related to the fact that our own TLS storage happens
// to take up 8 bytes.
o = 8 + r.Sym.Value
- } else if Iself || Ctxt.Headtype == obj.Hplan9 || Ctxt.Headtype == obj.Hdarwin || isAndroidX86 {
- o = int64(Ctxt.Tlsoffset) + r.Add
- } else if Ctxt.Headtype == obj.Hwindows {
+ } else if Iself || Headtype == obj.Hplan9 || Headtype == obj.Hdarwin || isAndroidX86 {
+ o = int64(ctxt.Tlsoffset) + r.Add
+ } else if Headtype == obj.Hwindows || Headtype == obj.Hwindowsgui {
o = r.Add
} else {
- log.Fatalf("unexpected R_TLS_LE relocation for %s", Headstr(Ctxt.Headtype))
+ log.Fatalf("unexpected R_TLS_LE relocation for %v", Headtype)
}
case obj.R_TLS_IE:
- isAndroidX86 := goos == "android" && (SysArch.InFamily(sys.AMD64, sys.I386))
+ isAndroidX86 := obj.GOOS == "android" && (SysArch.InFamily(sys.AMD64, sys.I386))
- if Linkmode == LinkExternal && Iself && HEADTYPE != obj.Hopenbsd && !isAndroidX86 {
+ if Linkmode == LinkExternal && Iself && Headtype != obj.Hopenbsd && !isAndroidX86 {
r.Done = 0
if r.Sym == nil {
- r.Sym = Ctxt.Tlsg
+ r.Sym = ctxt.Tlsg
}
r.Xsym = r.Sym
r.Xadd = r.Add
@@ -447,7 +496,20 @@ func relocsym(s *LSym) {
}
break
}
- log.Fatalf("cannot handle R_TLS_IE when linking internally")
+ if Buildmode == BuildmodePIE && Iself {
+ // We are linking the final executable, so we
+ // can optimize any TLS IE relocation to LE.
+ if Thearch.TLSIEtoLE == nil {
+ log.Fatalf("internal linking of TLS IE not supported on %v", SysArch.Family)
+ }
+ Thearch.TLSIEtoLE(s, int(off), int(r.Siz))
+ o = int64(ctxt.Tlsoffset)
+ // TODO: o += r.Add when SysArch.Family != sys.AMD64?
+ // Why do we treat r.Add differently on AMD64?
+ // Is the external linker using Xadd at all?
+ } else {
+ 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 {
@@ -463,7 +525,7 @@ func relocsym(s *LSym) {
}
if rs.Type != obj.SHOSTOBJ && rs.Type != obj.SDYNIMPORT && rs.Sect == nil {
- Diag("missing section for %s", rs.Name)
+ Errorf(s, "missing section for relocation target %s", rs.Name)
}
r.Xsym = rs
@@ -472,7 +534,7 @@ func relocsym(s *LSym) {
if SysArch.Family == sys.AMD64 {
o = 0
}
- } else if HEADTYPE == obj.Hdarwin {
+ } else if Headtype == obj.Hdarwin {
// ld64 for arm64 has a bug where if the address pointed to by o exists in the
// symbol table (dynid >= 0), or is inside a symbol that exists in the symbol
// table, then it will add o twice into the relocated value.
@@ -480,16 +542,16 @@ func relocsym(s *LSym) {
// extern relocation by requiring rs->dynid >= 0.
if rs.Type != obj.SHOSTOBJ {
if SysArch.Family == sys.ARM64 && rs.Dynid < 0 {
- Diag("R_ADDR reloc to %s+%d is not supported on darwin/arm64", rs.Name, o)
+ Errorf(s, "R_ADDR reloc to %s+%d is not supported on darwin/arm64", rs.Name, o)
}
if SysArch.Family != sys.ARM64 {
o += Symaddr(rs)
}
}
- } else if HEADTYPE == obj.Hwindows {
+ } else if Headtype == obj.Hwindows || Headtype == obj.Hwindowsgui {
// nothing to do
} else {
- Diag("unhandled pcrel relocation for %s", headstring)
+ Errorf(s, "unhandled pcrel relocation to %s on %v", rs.Name, Headtype)
}
break
@@ -503,19 +565,19 @@ func relocsym(s *LSym) {
// Instead of special casing only amd64, we treat this as an error on all
// 64-bit architectures so as to be future-proof.
if int32(o) < 0 && SysArch.PtrSize > 4 && siz == 4 {
- Diag("non-pc-relative relocation address is too big: %#x (%#x + %#x)", uint64(o), Symaddr(r.Sym), r.Add)
+ Errorf(s, "non-pc-relative relocation address for %s is too big: %#x (%#x + %#x)", r.Sym.Name, uint64(o), Symaddr(r.Sym), r.Add)
errorexit()
}
case obj.R_DWARFREF:
if r.Sym.Sect == nil {
- Diag("missing DWARF section: %s from %s", r.Sym.Name, s.Name)
+ Errorf(s, "missing DWARF section for relocation target %s", r.Sym.Name)
}
if Linkmode == LinkExternal {
r.Done = 0
r.Type = obj.R_ADDR
- r.Xsym = Linkrlookup(Ctxt, r.Sym.Sect.Name, 0)
+ 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
@@ -526,12 +588,36 @@ func relocsym(s *LSym) {
}
o = Symaddr(r.Sym) + r.Add - int64(r.Sym.Sect.Vaddr)
+ case obj.R_WEAKADDROFF:
+ if !r.Sym.Attr.Reachable() {
+ continue
+ }
+ fallthrough
case obj.R_ADDROFF:
- o = Symaddr(r.Sym) - int64(r.Sym.Sect.Vaddr) + r.Add
+ // 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
+ } 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_CALL, obj.R_GOTPCREL, obj.R_PCREL:
- if Linkmode == LinkExternal && r.Sym != nil && r.Sym.Type != obj.SCONST && (r.Sym.Sect != Ctxt.Cursym.Sect || r.Type == obj.R_GOTPCREL) {
+ case obj.R_GOTPCREL:
+ if ctxt.DynlinkingGo() && Headtype == obj.Hdarwin && r.Sym != nil && r.Sym.Type != obj.SCONST {
+ r.Done = 0
+ r.Xadd = r.Add
+ r.Xadd -= int64(r.Siz) // relative to address after the relocated chunk
+ r.Xsym = r.Sym
+
+ o = r.Xadd
+ o += int64(r.Siz)
+ 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) {
r.Done = 0
// set up addend for eventual relocation via outer symbol.
@@ -545,7 +631,7 @@ func relocsym(s *LSym) {
r.Xadd -= int64(r.Siz) // relative to address after the relocated chunk
if rs.Type != obj.SHOSTOBJ && rs.Type != obj.SDYNIMPORT && rs.Sect == nil {
- Diag("missing section for %s", rs.Name)
+ Errorf(s, "missing section for relocation target %s", rs.Name)
}
r.Xsym = rs
@@ -554,7 +640,7 @@ func relocsym(s *LSym) {
if SysArch.Family == sys.AMD64 {
o = 0
}
- } else if HEADTYPE == obj.Hdarwin {
+ } else if Headtype == obj.Hdarwin {
if r.Type == obj.R_CALL {
if rs.Type != obj.SHOSTOBJ {
o += int64(uint64(Symaddr(rs)) - rs.Sect.Vaddr)
@@ -562,11 +648,11 @@ func relocsym(s *LSym) {
o -= int64(r.Off) // relative to section offset, not symbol
} else if SysArch.Family == sys.ARM {
// see ../arm/asm.go:/machoreloc1
- o += Symaddr(rs) - int64(Ctxt.Cursym.Value) - int64(r.Off)
+ o += Symaddr(rs) - int64(s.Value) - int64(r.Off)
} else {
o += int64(r.Siz)
}
- } else if HEADTYPE == obj.Hwindows && SysArch.Family == sys.AMD64 { // only amd64 needs PCREL
+ } else if (Headtype == obj.Hwindows || Headtype == obj.Hwindowsgui) && 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)
@@ -574,7 +660,7 @@ func relocsym(s *LSym) {
// relocated address, compensate that.
o -= int64(s.Sect.Vaddr - PEBASE)
} else {
- Diag("unhandled pcrel relocation for %s", headstring)
+ Errorf(s, "unhandled pcrel relocation to %s on %v", rs.Name, Headtype)
}
break
@@ -585,20 +671,14 @@ func relocsym(s *LSym) {
o += Symaddr(r.Sym)
}
- // NOTE: The (int32) cast on the next line works around a bug in Plan 9's 8c
- // compiler. The expression s->value + r->off + r->siz is int32 + int32 +
- // uchar, and Plan 9 8c incorrectly treats the expression as type uint32
- // instead of int32, causing incorrect values when sign extended for adding
- // to o. The bug only occurs on Plan 9, because this C program is compiled by
- // the standard host compiler (gcc on most other systems).
- o += r.Add - (s.Value + int64(r.Off) + int64(int32(r.Siz)))
+ o += r.Add - (s.Value + int64(r.Off) + int64(r.Siz))
case obj.R_SIZE:
o = r.Sym.Size + r.Add
}
if r.Variant != RV_NONE {
- o = Thearch.Archrelocvariant(r, s, o)
+ o = Thearch.Archrelocvariant(ctxt, r, s, o)
}
if false {
@@ -610,8 +690,7 @@ func relocsym(s *LSym) {
}
switch siz {
default:
- Ctxt.Cursym = s
- Diag("bad reloc size %#x for %s", uint32(siz), r.Sym.Name)
+ Errorf(s, "bad reloc size %#x for %s", uint32(siz), r.Sym.Name)
fallthrough
// TODO(rsc): Remove.
@@ -620,51 +699,50 @@ func relocsym(s *LSym) {
case 2:
if o != int64(int16(o)) {
- Diag("relocation address is too big: %#x", o)
+ Errorf(s, "relocation address for %s is too big: %#x", r.Sym.Name, o)
}
i16 = int16(o)
- Ctxt.Arch.ByteOrder.PutUint16(s.P[off:], uint16(i16))
+ ctxt.Arch.ByteOrder.PutUint16(s.P[off:], uint16(i16))
case 4:
if r.Type == obj.R_PCREL || r.Type == obj.R_CALL {
if o != int64(int32(o)) {
- Diag("pc-relative relocation address is too big: %#x", o)
+ Errorf(s, "pc-relative relocation address for %s is too big: %#x", r.Sym.Name, o)
}
} else {
if o != int64(int32(o)) && o != int64(uint32(o)) {
- Diag("non-pc-relative relocation address is too big: %#x", uint64(o))
+ Errorf(s, "non-pc-relative relocation address for %s is too big: %#x", r.Sym.Name, uint64(o))
}
}
fl = int32(o)
- Ctxt.Arch.ByteOrder.PutUint32(s.P[off:], uint32(fl))
+ ctxt.Arch.ByteOrder.PutUint32(s.P[off:], uint32(fl))
case 8:
- Ctxt.Arch.ByteOrder.PutUint64(s.P[off:], uint64(o))
+ ctxt.Arch.ByteOrder.PutUint64(s.P[off:], uint64(o))
}
}
}
-func reloc() {
- if Debug['v'] != 0 {
- fmt.Fprintf(Bso, "%5.2f reloc\n", obj.Cputime())
+func (ctxt *Link) reloc() {
+ if ctxt.Debugvlog != 0 {
+ ctxt.Logf("%5.2f reloc\n", obj.Cputime())
}
- Bso.Flush()
- for _, s := range Ctxt.Textp {
- relocsym(s)
+ for _, s := range ctxt.Textp {
+ relocsym(ctxt, s)
}
for _, sym := range datap {
- relocsym(sym)
+ relocsym(ctxt, sym)
}
- for s := dwarfp; s != nil; s = s.Next {
- relocsym(s)
+ for _, s := range dwarfp {
+ relocsym(ctxt, s)
}
}
-func dynrelocsym(s *LSym) {
- if HEADTYPE == obj.Hwindows && Linkmode != LinkExternal {
- rel := Linklookup(Ctxt, ".rel", 0)
+func dynrelocsym(ctxt *Link, s *Symbol) {
+ if (Headtype == obj.Hwindows || Headtype == obj.Hwindowsgui) && Linkmode != LinkExternal {
+ rel := ctxt.Syms.Lookup(".rel", 0)
if s == rel {
return
}
@@ -675,7 +753,10 @@ func dynrelocsym(s *LSym) {
continue
}
if !targ.Attr.Reachable() {
- Diag("internal inconsistency: dynamic symbol %s is not reachable.", targ.Name)
+ if r.Type == obj.R_WEAKADDROFF {
+ continue
+ }
+ Errorf(s, "dynamic relocation to unreachable symbol %s", targ.Name)
}
if r.Sym.Plt == -2 && r.Sym.Got != -2 { // make dynimport JMP table for PE object files.
targ.Plt = int32(rel.Size)
@@ -684,17 +765,17 @@ func dynrelocsym(s *LSym) {
// jmp *addr
if SysArch.Family == sys.I386 {
- Adduint8(Ctxt, rel, 0xff)
- Adduint8(Ctxt, rel, 0x25)
- Addaddr(Ctxt, rel, targ)
- Adduint8(Ctxt, rel, 0x90)
- Adduint8(Ctxt, rel, 0x90)
+ Adduint8(ctxt, rel, 0xff)
+ Adduint8(ctxt, rel, 0x25)
+ Addaddr(ctxt, rel, targ)
+ Adduint8(ctxt, rel, 0x90)
+ Adduint8(ctxt, rel, 0x90)
} else {
- Adduint8(Ctxt, rel, 0xff)
- Adduint8(Ctxt, rel, 0x24)
- Adduint8(Ctxt, rel, 0x25)
- addaddrplus4(Ctxt, rel, targ, 0)
- Adduint8(Ctxt, rel, 0x90)
+ Adduint8(ctxt, rel, 0xff)
+ Adduint8(ctxt, rel, 0x24)
+ Adduint8(ctxt, rel, 0x25)
+ addaddrplus4(ctxt, rel, targ, 0)
+ Adduint8(ctxt, rel, 0x90)
}
} else if r.Sym.Plt >= 0 {
r.Sym = rel
@@ -707,104 +788,63 @@ func dynrelocsym(s *LSym) {
for ri := 0; ri < len(s.R); ri++ {
r := &s.R[ri]
+ if Buildmode == BuildmodePIE && Linkmode == LinkInternal {
+ // It's expected that some relocations will be done
+ // later by relocsym (R_TLS_LE, R_ADDROFF), so
+ // don't worry if Adddynrel returns false.
+ Thearch.Adddynrel(ctxt, s, r)
+ continue
+ }
if r.Sym != nil && r.Sym.Type == obj.SDYNIMPORT || r.Type >= 256 {
if r.Sym != nil && !r.Sym.Attr.Reachable() {
- Diag("internal inconsistency: dynamic symbol %s is not reachable.", r.Sym.Name)
+ Errorf(s, "dynamic relocation to unreachable symbol %s", r.Sym.Name)
+ }
+ if !Thearch.Adddynrel(ctxt, s, r) {
+ Errorf(s, "unsupported dynamic relocation for symbol %s (type=%d stype=%d)", r.Sym.Name, r.Type, r.Sym.Type)
}
- Thearch.Adddynrel(s, r)
}
}
}
-func dynreloc(data *[obj.SXREF][]*LSym) {
+func dynreloc(ctxt *Link, data *[obj.SXREF][]*Symbol) {
// -d suppresses dynamic loader format, so we may as well not
// compute these sections or mark their symbols as reachable.
- if Debug['d'] != 0 && HEADTYPE != obj.Hwindows {
+ if *FlagD && Headtype != obj.Hwindows && Headtype != obj.Hwindowsgui {
return
}
- if Debug['v'] != 0 {
- fmt.Fprintf(Bso, "%5.2f reloc\n", obj.Cputime())
+ if ctxt.Debugvlog != 0 {
+ ctxt.Logf("%5.2f reloc\n", obj.Cputime())
}
- Bso.Flush()
- for _, s := range Ctxt.Textp {
- dynrelocsym(s)
+ for _, s := range ctxt.Textp {
+ dynrelocsym(ctxt, s)
}
for _, syms := range data {
for _, sym := range syms {
- dynrelocsym(sym)
+ dynrelocsym(ctxt, sym)
}
}
if Iself {
- elfdynhash()
- }
-}
-
-func blk(start *LSym, addr int64, size int64) {
- var sym *LSym
-
- for sym = start; sym != nil; sym = sym.Next {
- if sym.Type&obj.SSUB == 0 && sym.Value >= addr {
- break
- }
- }
-
- eaddr := addr + size
- for ; sym != nil; sym = sym.Next {
- if sym.Type&obj.SSUB != 0 {
- continue
- }
- if sym.Value >= eaddr {
- break
- }
- Ctxt.Cursym = sym
- if sym.Value < addr {
- Diag("phase error: addr=%#x but sym=%#x type=%d", addr, sym.Value, sym.Type)
- errorexit()
- }
-
- if addr < sym.Value {
- strnput("", int(sym.Value-addr))
- addr = sym.Value
- }
- Cwrite(sym.P)
- addr += int64(len(sym.P))
- if addr < sym.Value+sym.Size {
- strnput("", int(sym.Value+sym.Size-addr))
- addr = sym.Value + sym.Size
- }
- if addr != sym.Value+sym.Size {
- Diag("phase error: addr=%#x value+size=%#x", addr, sym.Value+sym.Size)
- errorexit()
- }
-
- if sym.Value+sym.Size >= eaddr {
- break
- }
- }
-
- if addr < eaddr {
- strnput("", int(eaddr-addr))
+ elfdynhash(ctxt)
}
- Cflush()
}
-func Codeblk(addr int64, size int64) {
- CodeblkPad(addr, size, zeros[:])
+func Codeblk(ctxt *Link, addr int64, size int64) {
+ CodeblkPad(ctxt, addr, size, zeros[:])
}
-func CodeblkPad(addr int64, size int64, pad []byte) {
- if Debug['a'] != 0 {
- fmt.Fprintf(Bso, "codeblk [%#x,%#x) at offset %#x\n", addr, addr+size, Cpos())
+func CodeblkPad(ctxt *Link, addr int64, size int64, pad []byte) {
+ if *flagA {
+ ctxt.Logf("codeblk [%#x,%#x) at offset %#x\n", addr, addr+size, coutbuf.Offset())
}
- blkSlice(Ctxt.Textp, addr, size, pad)
+ blk(ctxt, ctxt.Textp, addr, size, pad)
/* again for printing */
- if Debug['a'] == 0 {
+ if !*flagA {
return
}
- syms := Ctxt.Textp
+ syms := ctxt.Textp
for i, sym := range syms {
if !sym.Attr.Reachable() {
continue
@@ -826,42 +866,37 @@ func CodeblkPad(addr int64, size int64, pad []byte) {
}
if addr < sym.Value {
- fmt.Fprintf(Bso, "%-20s %.8x|", "_", uint64(addr))
+ ctxt.Logf("%-20s %.8x|", "_", uint64(addr))
for ; addr < sym.Value; addr++ {
- fmt.Fprintf(Bso, " %.2x", 0)
+ ctxt.Logf(" %.2x", 0)
}
- fmt.Fprintf(Bso, "\n")
+ ctxt.Logf("\n")
}
- fmt.Fprintf(Bso, "%.6x\t%-20s\n", uint64(addr), sym.Name)
+ ctxt.Logf("%.6x\t%-20s\n", uint64(addr), sym.Name)
q = sym.P
for len(q) >= 16 {
- fmt.Fprintf(Bso, "%.6x\t% x\n", uint64(addr), q[:16])
+ ctxt.Logf("%.6x\t% x\n", uint64(addr), q[:16])
addr += 16
q = q[16:]
}
if len(q) > 0 {
- fmt.Fprintf(Bso, "%.6x\t% x\n", uint64(addr), q)
+ ctxt.Logf("%.6x\t% x\n", uint64(addr), q)
addr += int64(len(q))
}
}
if addr < eaddr {
- fmt.Fprintf(Bso, "%-20s %.8x|", "_", uint64(addr))
+ ctxt.Logf("%-20s %.8x|", "_", uint64(addr))
for ; addr < eaddr; addr++ {
- fmt.Fprintf(Bso, " %.2x", 0)
+ ctxt.Logf(" %.2x", 0)
}
}
-
- Bso.Flush()
}
-// blkSlice is a variant of blk that processes slices.
-// After text symbols are converted from a linked list to a slice,
-// delete blk and give this function its name.
-func blkSlice(syms []*LSym, addr, size int64, pad []byte) {
+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 {
syms = syms[i:]
@@ -877,9 +912,8 @@ func blkSlice(syms []*LSym, addr, size int64, pad []byte) {
if s.Value >= eaddr {
break
}
- Ctxt.Cursym = s
if s.Value < addr {
- Diag("phase error: addr=%#x but sym=%#x type=%d", addr, s.Value, s.Type)
+ Errorf(s, "phase error: addr=%#x but sym=%#x type=%d", addr, s.Value, s.Type)
errorexit()
}
if addr < s.Value {
@@ -893,7 +927,7 @@ func blkSlice(syms []*LSym, addr, size int64, pad []byte) {
addr = s.Value + s.Size
}
if addr != s.Value+s.Size {
- Diag("phase error: addr=%#x value+size=%#x", addr, s.Value+s.Size)
+ Errorf(s, "phase error: addr=%#x value+size=%#x", addr, s.Value+s.Size)
errorexit()
}
if s.Value+s.Size >= eaddr {
@@ -907,15 +941,15 @@ func blkSlice(syms []*LSym, addr, size int64, pad []byte) {
Cflush()
}
-func Datblk(addr int64, size int64) {
- if Debug['a'] != 0 {
- fmt.Fprintf(Bso, "datblk [%#x,%#x) at offset %#x\n", addr, addr+size, Cpos())
+func Datblk(ctxt *Link, addr int64, size int64) {
+ if *flagA {
+ ctxt.Logf("datblk [%#x,%#x) at offset %#x\n", addr, addr+size, coutbuf.Offset())
}
- blkSlice(datap, addr, size, zeros[:])
+ blk(ctxt, datap, addr, size, zeros[:])
/* again for printing */
- if Debug['a'] == 0 {
+ if !*flagA {
return
}
@@ -933,23 +967,23 @@ func Datblk(addr int64, size int64) {
break
}
if addr < sym.Value {
- fmt.Fprintf(Bso, "\t%.8x| 00 ...\n", uint64(addr))
+ ctxt.Logf("\t%.8x| 00 ...\n", uint64(addr))
addr = sym.Value
}
- fmt.Fprintf(Bso, "%s\n\t%.8x|", sym.Name, uint64(addr))
+ ctxt.Logf("%s\n\t%.8x|", sym.Name, uint64(addr))
for i, b := range sym.P {
if i > 0 && i%16 == 0 {
- fmt.Fprintf(Bso, "\n\t%.8x|", uint64(addr)+uint64(i))
+ ctxt.Logf("\n\t%.8x|", uint64(addr)+uint64(i))
}
- fmt.Fprintf(Bso, " %.2x", b)
+ ctxt.Logf(" %.2x", b)
}
addr += int64(len(sym.P))
for ; addr < sym.Value+sym.Size; addr++ {
- fmt.Fprintf(Bso, " %.2x", 0)
+ ctxt.Logf(" %.2x", 0)
}
- fmt.Fprintf(Bso, "\n")
+ ctxt.Logf("\n")
if Linkmode != LinkExternal {
continue
@@ -968,22 +1002,22 @@ func Datblk(addr int64, size int64) {
case obj.R_CALL:
typ = "call"
}
- fmt.Fprintf(Bso, "\treloc %.8x/%d %s %s+%#x [%#x]\n", uint(sym.Value+int64(r.Off)), r.Siz, typ, rsname, r.Add, r.Sym.Value+r.Add)
+ 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)
}
}
if addr < eaddr {
- fmt.Fprintf(Bso, "\t%.8x| 00 ...\n", uint(addr))
+ ctxt.Logf("\t%.8x| 00 ...\n", uint(addr))
}
- fmt.Fprintf(Bso, "\t%.8x|\n", uint(eaddr))
+ ctxt.Logf("\t%.8x|\n", uint(eaddr))
}
-func Dwarfblk(addr int64, size int64) {
- if Debug['a'] != 0 {
- fmt.Fprintf(Bso, "dwarfblk [%#x,%#x) at offset %#x\n", addr, addr+size, Cpos())
+func Dwarfblk(ctxt *Link, addr int64, size int64) {
+ if *flagA {
+ ctxt.Logf("dwarfblk [%#x,%#x) at offset %#x\n", addr, addr+size, coutbuf.Offset())
}
- blk(dwarfp, addr, size)
+ blk(ctxt, dwarfp, addr, size, zeros[:])
}
var zeros [512]byte
@@ -1013,29 +1047,30 @@ func strnputPad(s string, n int, pad []byte) {
}
}
-var strdata []*LSym
+var strdata []*Symbol
-func addstrdata1(arg string) {
- i := strings.Index(arg, "=")
- if i < 0 {
+func addstrdata1(ctxt *Link, arg string) {
+ eq := strings.Index(arg, "=")
+ dot := strings.LastIndex(arg[:eq+1], ".")
+ if eq < 0 || dot < 0 {
Exitf("-X flag requires argument of the form importpath.name=value")
}
- addstrdata(arg[:i], arg[i+1:])
+ addstrdata(ctxt, pathtoprefix(arg[:dot])+arg[dot:eq], arg[eq+1:])
}
-func addstrdata(name string, value string) {
+func addstrdata(ctxt *Link, name string, value string) {
p := fmt.Sprintf("%s.str", name)
- sp := Linklookup(Ctxt, p, 0)
+ sp := ctxt.Syms.Lookup(p, 0)
Addstring(sp, value)
sp.Type = obj.SRODATA
- s := Linklookup(Ctxt, name, 0)
+ s := ctxt.Syms.Lookup(name, 0)
s.Size = 0
s.Attr |= AttrDuplicateOK
reachable := s.Attr.Reachable()
- Addaddr(Ctxt, s, sp)
- adduintxx(Ctxt, s, uint64(len(value)), SysArch.PtrSize)
+ Addaddr(ctxt, s, sp)
+ adduintxx(ctxt, s, uint64(len(value)), SysArch.PtrSize)
// addstring, addaddr, etc., mark the symbols as reachable.
// In this case that is not necessarily true, so stick to what
@@ -1047,24 +1082,24 @@ func addstrdata(name string, value string) {
sp.Attr.Set(AttrReachable, reachable)
}
-func checkstrdata() {
+func (ctxt *Link) checkstrdata() {
for _, s := range strdata {
if s.Type == obj.STEXT {
- Diag("cannot use -X with text symbol %s", s.Name)
+ Errorf(s, "cannot use -X with text symbol")
} else if s.Gotype != nil && s.Gotype.Name != "type.string" {
- Diag("cannot use -X with non-string symbol %s", s.Name)
+ Errorf(s, "cannot use -X with non-string symbol")
}
}
}
-func Addstring(s *LSym, str string) int64 {
+func Addstring(s *Symbol, str string) int64 {
if s.Type == 0 {
s.Type = obj.SNOPTRDATA
}
s.Attr |= AttrReachable
r := s.Size
if s.Name == ".shstrtab" {
- elfsetstring(str, int(r))
+ elfsetstring(s, str, int(r))
}
s.P = append(s.P, str...)
s.P = append(s.P, 0)
@@ -1074,31 +1109,31 @@ func Addstring(s *LSym, str string) int64 {
// addgostring adds str, as a Go string value, to s. symname is the name of the
// symbol used to define the string data and must be unique per linked object.
-func addgostring(s *LSym, symname, str string) {
- sym := Linklookup(Ctxt, symname, 0)
+func addgostring(ctxt *Link, s *Symbol, symname, str string) {
+ sym := ctxt.Syms.Lookup(symname, 0)
if sym.Type != obj.Sxxx {
- Diag("duplicate symname in addgostring: %s", symname)
+ Errorf(s, "duplicate symname in addgostring: %s", symname)
}
sym.Attr |= AttrReachable
sym.Attr |= AttrLocal
sym.Type = obj.SRODATA
sym.Size = int64(len(str))
sym.P = []byte(str)
- Addaddr(Ctxt, s, sym)
- adduint(Ctxt, s, uint64(len(str)))
+ Addaddr(ctxt, s, sym)
+ adduint(ctxt, s, uint64(len(str)))
}
-func addinitarrdata(s *LSym) {
+func addinitarrdata(ctxt *Link, s *Symbol) {
p := s.Name + ".ptr"
- sp := Linklookup(Ctxt, p, 0)
+ sp := ctxt.Syms.Lookup(p, 0)
sp.Type = obj.SINITARR
sp.Size = 0
sp.Attr |= AttrDuplicateOK
- Addaddr(Ctxt, sp, s)
+ Addaddr(ctxt, sp, s)
}
-func dosymtype() {
- for _, s := range Ctxt.Allsym {
+func dosymtype(ctxt *Link) {
+ for _, s := range ctxt.Syms.Allsym {
if len(s.P) > 0 {
if s.Type == obj.SBSS {
s.Type = obj.SDATA
@@ -1111,22 +1146,22 @@ func dosymtype() {
// library initializer function.
switch Buildmode {
case BuildmodeCArchive, BuildmodeCShared:
- if s.Name == INITENTRY {
- addinitarrdata(s)
+ if s.Name == *flagEntrySymbol {
+ addinitarrdata(ctxt, s)
}
}
}
}
// symalign returns the required alignment for the given symbol s.
-func symalign(s *LSym) int32 {
+func symalign(s *Symbol) int32 {
min := int32(Thearch.Minalign)
if s.Align >= min {
return s.Align
} else if s.Align != 0 {
return min
}
- if (strings.HasPrefix(s.Name, "go.string.") && !strings.HasPrefix(s.Name, "go.string.hdr.")) || strings.HasPrefix(s.Name, "type..namedata.") {
+ if strings.HasPrefix(s.Name, "go.string.") || strings.HasPrefix(s.Name, "type..namedata.") {
// String data is just bytes.
// If we align it, we waste a lot of space to padding.
return min
@@ -1138,28 +1173,32 @@ func symalign(s *LSym) int32 {
return align
}
-func aligndatsize(datsize int64, s *LSym) int64 {
+func aligndatsize(datsize int64, s *Symbol) int64 {
return Rnd(datsize, int64(symalign(s)))
}
const debugGCProg = false
type GCProg struct {
- sym *LSym
- w gcprog.Writer
+ ctxt *Link
+ sym *Symbol
+ w gcprog.Writer
}
-func (p *GCProg) Init(name string) {
- p.sym = Linklookup(Ctxt, name, 0)
- p.w.Init(p.writeByte)
+func (p *GCProg) Init(ctxt *Link, name string) {
+ p.ctxt = ctxt
+ p.sym = ctxt.Syms.Lookup(name, 0)
+ p.w.Init(p.writeByte(ctxt))
if debugGCProg {
fmt.Fprintf(os.Stderr, "ld: start GCProg %s\n", name)
p.w.Debug(os.Stderr)
}
}
-func (p *GCProg) writeByte(x byte) {
- Adduint8(Ctxt, p.sym, x)
+func (p *GCProg) writeByte(ctxt *Link) func(x byte) {
+ return func(x byte) {
+ Adduint8(ctxt, p.sym, x)
+ }
}
func (p *GCProg) End(size int64) {
@@ -1170,25 +1209,32 @@ func (p *GCProg) End(size int64) {
}
}
-func (p *GCProg) AddSym(s *LSym) {
+func (p *GCProg) AddSym(s *Symbol) {
typ := s.Gotype
// Things without pointers should be in SNOPTRDATA or SNOPTRBSS;
// everything we see should have pointers and should therefore have a type.
if typ == nil {
- Diag("missing Go type information for global symbol: %s size %d", s.Name, int(s.Size))
+ switch s.Name {
+ case "runtime.data", "runtime.edata", "runtime.bss", "runtime.ebss":
+ // Ignore special symbols that are sometimes laid out
+ // as real symbols. See comment about dyld on darwin in
+ // the address function.
+ return
+ }
+ Errorf(s, "missing Go type information for global symbol: size %d", s.Size)
return
}
ptrsize := int64(SysArch.PtrSize)
- nptr := decodetype_ptrdata(typ) / ptrsize
+ nptr := decodetypePtrdata(p.ctxt.Arch, typ) / ptrsize
if debugGCProg {
fmt.Fprintf(os.Stderr, "gcprog sym: %s at %d (ptr=%d+%d)\n", s.Name, s.Value, s.Value/ptrsize, nptr)
}
- if decodetype_usegcprog(typ) == 0 {
+ if decodetypeUsegcprog(typ) == 0 {
// Copy pointers from mask into program.
- mask := decodetype_gcmask(typ)
+ mask := decodetypeGcmask(p.ctxt, typ)
for i := int64(0); i < nptr; i++ {
if (mask[i/8]>>uint(i%8))&1 != 0 {
p.w.Ptr(s.Value/ptrsize + i)
@@ -1198,17 +1244,17 @@ func (p *GCProg) AddSym(s *LSym) {
}
// Copy program.
- prog := decodetype_gcprog(typ)
+ prog := decodetypeGcprog(p.ctxt, typ)
p.w.ZeroUntil(s.Value / ptrsize)
p.w.Append(prog[4:], nptr)
}
-// dataSortKey is used to sort a slice of data symbol *LSym pointers.
+// dataSortKey is used to sort a slice of data symbol *Symbol pointers.
// The sort keys are kept inline to improve cache behaviour while sorting.
type dataSortKey struct {
size int64
name string
- lsym *LSym
+ sym *Symbol
}
type bySizeAndName []dataSortKey
@@ -1225,33 +1271,64 @@ 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(datsize int64, symn int) {
+func checkdatsize(ctxt *Link, datsize int64, symn obj.SymKind) {
if datsize > cutoff {
- Diag("too much data in section %v (over %d bytes)", symn, cutoff)
+ Errorf(nil, "too much data in section %v (over %d bytes)", symn, cutoff)
}
}
-func list2slice(s *LSym) []*LSym {
- var syms []*LSym
- for ; s != nil; s = s.Next {
- syms = append(syms, s)
- }
- return syms
-}
-
// datap is a collection of reachable data symbols in address order.
// Generated by dodata.
-var datap []*LSym
-
-func dodata() {
- if Debug['v'] != 0 {
- fmt.Fprintf(Bso, "%5.2f dodata\n", obj.Cputime())
+var datap []*Symbol
+
+func (ctxt *Link) dodata() {
+ if ctxt.Debugvlog != 0 {
+ ctxt.Logf("%5.2f dodata\n", obj.Cputime())
+ }
+
+ if ctxt.DynlinkingGo() && Headtype == obj.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
+ // out with their matching section.
+ //
+ // However on darwin, dyld will find the special symbol
+ // in the first loaded module, even though it is local.
+ //
+ // (An hypothesis, formed without looking in the dyld sources:
+ // these special symbols have no size, so their address
+ // matches a real symbol. The dynamic linker assumes we
+ // want the normal symbol with the same address and finds
+ // it in the other module.)
+ //
+ // To work around this we lay out the symbls whose
+ // addresses are vital for multi-module programs to work
+ // as normal symbols, and give them a little size.
+ bss := ctxt.Syms.Lookup("runtime.bss", 0)
+ bss.Size = 8
+ bss.Attr.Set(AttrSpecial, false)
+
+ ctxt.Syms.Lookup("runtime.ebss", 0).Attr.Set(AttrSpecial, false)
+
+ data := ctxt.Syms.Lookup("runtime.data", 0)
+ data.Size = 8
+ data.Attr.Set(AttrSpecial, false)
+
+ ctxt.Syms.Lookup("runtime.edata", 0).Attr.Set(AttrSpecial, false)
+
+ types := ctxt.Syms.Lookup("runtime.types", 0)
+ types.Type = obj.STYPE
+ types.Size = 8
+ types.Attr.Set(AttrSpecial, false)
+
+ etypes := ctxt.Syms.Lookup("runtime.etypes", 0)
+ etypes.Type = obj.SFUNCTAB
+ etypes.Attr.Set(AttrSpecial, false)
}
- Bso.Flush()
// Collect data symbols by type into data.
- var data [obj.SXREF][]*LSym
- for _, s := range Ctxt.Allsym {
+ var data [obj.SXREF][]*Symbol
+ for _, s := range ctxt.Syms.Allsym {
if !s.Attr.Reachable() || s.Attr.Special() {
continue
}
@@ -1267,25 +1344,25 @@ func dodata() {
// symbol, which is itself data.
//
// On darwin, we need the symbol table numbers for dynreloc.
- if HEADTYPE == obj.Hdarwin {
- machosymorder()
+ if Headtype == obj.Hdarwin {
+ machosymorder(ctxt)
}
- dynreloc(&data)
+ dynreloc(ctxt, &data)
if UseRelro() {
// "read only" data with relocations needs to go in its own section
// when building a shared library. We do this by boosting objects of
// type SXXX with relocations to type SXXXRELRO.
- for symnro := int16(obj.STYPE); symnro < obj.STYPERELRO; symnro++ {
- symnrelro := symnro + obj.STYPERELRO - obj.STYPE
+ for _, symnro := range obj.ReadOnly {
+ symnrelro := obj.RelROMap[symnro]
- ro := []*LSym{}
+ ro := []*Symbol{}
relro := data[symnrelro]
for _, s := range data[symnro] {
isRelro := len(s.R) > 0
switch s.Type {
- case obj.STYPE, obj.SGOSTRINGHDR, obj.STYPERELRO, obj.SGOSTRINGHDRRELRO:
+ case obj.STYPE, obj.STYPERELRO, obj.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.
@@ -1308,8 +1385,8 @@ func dodata() {
// symbol and the outer end up in the same section).
for _, s := range relro {
if s.Outer != nil && s.Outer.Type != s.Type {
- Diag("inconsistent types for %s and its Outer %s (%d != %d)",
- s.Name, s.Outer.Name, s.Type, s.Outer.Type)
+ Errorf(s, "inconsistent types for symbol and its Outer %s (%v != %v)",
+ s.Outer.Name, s.Type, s.Outer.Type)
}
}
@@ -1322,10 +1399,10 @@ func dodata() {
var dataMaxAlign [obj.SXREF]int32
var wg sync.WaitGroup
for symn := range data {
- symn := symn
+ symn := obj.SymKind(symn)
wg.Add(1)
go func() {
- data[symn], dataMaxAlign[symn] = dodataSect(symn, data[symn])
+ data[symn], dataMaxAlign[symn] = dodataSect(ctxt, symn, data[symn])
wg.Done()
}()
}
@@ -1337,14 +1414,14 @@ func dodata() {
// to generate garbage collection information.
datsize := int64(0)
- // Writable sections.
- writableSects := []int{
+ // Writable data sections that do not need any specialized handling.
+ writable := []obj.SymKind{
obj.SELFSECT,
obj.SMACHO,
obj.SMACHOGOT,
obj.SWINDOWS,
}
- for _, symn := range writableSects {
+ for _, symn := range writable {
for _, s := range data[symn] {
sect := addsection(&Segdata, s.Name, 06)
sect.Align = symalign(s)
@@ -1356,7 +1433,7 @@ func dodata() {
datsize += s.Size
sect.Length = uint64(datsize) - sect.Vaddr
}
- checkdatsize(datsize, symn)
+ checkdatsize(ctxt, datsize, symn)
}
// .got (and .toc on ppc64)
@@ -1365,7 +1442,7 @@ func dodata() {
sect.Align = dataMaxAlign[obj.SELFGOT]
datsize = Rnd(datsize, int64(sect.Align))
sect.Vaddr = uint64(datsize)
- var toc *LSym
+ var toc *Symbol
for _, s := range data[obj.SELFGOT] {
datsize = aligndatsize(datsize, s)
s.Sect = sect
@@ -1373,7 +1450,7 @@ func dodata() {
s.Value = int64(uint64(datsize) - sect.Vaddr)
// Resolve .TOC. symbol for this object file (ppc64)
- toc = Linkrlookup(Ctxt, ".TOC.", int(s.Version))
+ toc = ctxt.Syms.ROLookup(".TOC.", int(s.Version))
if toc != nil {
toc.Sect = sect
toc.Outer = s
@@ -1385,7 +1462,7 @@ func dodata() {
datsize += s.Size
}
- checkdatsize(datsize, obj.SELFGOT)
+ checkdatsize(ctxt, datsize, obj.SELFGOT)
sect.Length = uint64(datsize) - sect.Vaddr
}
@@ -1394,8 +1471,8 @@ func dodata() {
sect.Align = dataMaxAlign[obj.SNOPTRDATA]
datsize = Rnd(datsize, int64(sect.Align))
sect.Vaddr = uint64(datsize)
- Linklookup(Ctxt, "runtime.noptrdata", 0).Sect = sect
- Linklookup(Ctxt, "runtime.enoptrdata", 0).Sect = sect
+ ctxt.Syms.Lookup("runtime.noptrdata", 0).Sect = sect
+ ctxt.Syms.Lookup("runtime.enoptrdata", 0).Sect = sect
for _, s := range data[obj.SNOPTRDATA] {
datsize = aligndatsize(datsize, s)
s.Sect = sect
@@ -1403,14 +1480,14 @@ func dodata() {
s.Value = int64(uint64(datsize) - sect.Vaddr)
datsize += s.Size
}
- checkdatsize(datsize, obj.SNOPTRDATA)
+ checkdatsize(ctxt, datsize, obj.SNOPTRDATA)
sect.Length = uint64(datsize) - sect.Vaddr
- hasinitarr := Linkshared
+ hasinitarr := *FlagLinkshared
/* shared library initializer */
switch Buildmode {
- case BuildmodeCArchive, BuildmodeCShared, BuildmodeShared:
+ case BuildmodeCArchive, BuildmodeCShared, BuildmodeShared, BuildmodePlugin:
hasinitarr = true
}
if hasinitarr {
@@ -1425,7 +1502,7 @@ func dodata() {
datsize += s.Size
}
sect.Length = uint64(datsize) - sect.Vaddr
- checkdatsize(datsize, obj.SINITARR)
+ checkdatsize(ctxt, datsize, obj.SINITARR)
}
/* data */
@@ -1433,10 +1510,10 @@ func dodata() {
sect.Align = dataMaxAlign[obj.SDATA]
datsize = Rnd(datsize, int64(sect.Align))
sect.Vaddr = uint64(datsize)
- Linklookup(Ctxt, "runtime.data", 0).Sect = sect
- Linklookup(Ctxt, "runtime.edata", 0).Sect = sect
+ ctxt.Syms.Lookup("runtime.data", 0).Sect = sect
+ ctxt.Syms.Lookup("runtime.edata", 0).Sect = sect
var gc GCProg
- gc.Init("runtime.gcdata")
+ gc.Init(ctxt, "runtime.gcdata")
for _, s := range data[obj.SDATA] {
s.Sect = sect
s.Type = obj.SDATA
@@ -1445,7 +1522,7 @@ func dodata() {
gc.AddSym(s)
datsize += s.Size
}
- checkdatsize(datsize, obj.SDATA)
+ checkdatsize(ctxt, datsize, obj.SDATA)
sect.Length = uint64(datsize) - sect.Vaddr
gc.End(int64(sect.Length))
@@ -1454,10 +1531,10 @@ func dodata() {
sect.Align = dataMaxAlign[obj.SBSS]
datsize = Rnd(datsize, int64(sect.Align))
sect.Vaddr = uint64(datsize)
- Linklookup(Ctxt, "runtime.bss", 0).Sect = sect
- Linklookup(Ctxt, "runtime.ebss", 0).Sect = sect
+ ctxt.Syms.Lookup("runtime.bss", 0).Sect = sect
+ ctxt.Syms.Lookup("runtime.ebss", 0).Sect = sect
gc = GCProg{}
- gc.Init("runtime.gcbss")
+ gc.Init(ctxt, "runtime.gcbss")
for _, s := range data[obj.SBSS] {
s.Sect = sect
datsize = aligndatsize(datsize, s)
@@ -1465,7 +1542,7 @@ func dodata() {
gc.AddSym(s)
datsize += s.Size
}
- checkdatsize(datsize, obj.SBSS)
+ checkdatsize(ctxt, datsize, obj.SBSS)
sect.Length = uint64(datsize) - sect.Vaddr
gc.End(int64(sect.Length))
@@ -1474,8 +1551,8 @@ func dodata() {
sect.Align = dataMaxAlign[obj.SNOPTRBSS]
datsize = Rnd(datsize, int64(sect.Align))
sect.Vaddr = uint64(datsize)
- Linklookup(Ctxt, "runtime.noptrbss", 0).Sect = sect
- Linklookup(Ctxt, "runtime.enoptrbss", 0).Sect = sect
+ ctxt.Syms.Lookup("runtime.noptrbss", 0).Sect = sect
+ ctxt.Syms.Lookup("runtime.enoptrbss", 0).Sect = sect
for _, s := range data[obj.SNOPTRBSS] {
datsize = aligndatsize(datsize, s)
s.Sect = sect
@@ -1484,12 +1561,12 @@ func dodata() {
}
sect.Length = uint64(datsize) - sect.Vaddr
- Linklookup(Ctxt, "runtime.end", 0).Sect = sect
- checkdatsize(datsize, obj.SNOPTRBSS)
+ ctxt.Syms.Lookup("runtime.end", 0).Sect = sect
+ checkdatsize(ctxt, datsize, obj.SNOPTRBSS)
if len(data[obj.STLSBSS]) > 0 {
var sect *Section
- if Iself && (Linkmode == LinkExternal || Debug['d'] == 0) && HEADTYPE != obj.Hopenbsd {
+ if Iself && (Linkmode == LinkExternal || !*FlagD) && Headtype != obj.Hopenbsd {
sect = addsection(&Segdata, ".tbss", 06)
sect.Align = int32(SysArch.PtrSize)
sect.Vaddr = 0
@@ -1502,7 +1579,7 @@ func dodata() {
s.Value = datsize
datsize += s.Size
}
- checkdatsize(datsize, obj.STLSBSS)
+ checkdatsize(ctxt, datsize, obj.STLSBSS)
if sect != nil {
sect.Length = uint64(datsize)
@@ -1530,7 +1607,7 @@ func dodata() {
/* read-only executable ELF, Mach-O sections */
if len(data[obj.STEXT]) != 0 {
- Diag("dodata found an STEXT symbol: %s", data[obj.STEXT][0].Name)
+ Errorf(nil, "dodata found an STEXT symbol: %s", data[obj.STEXT][0].Name)
}
for _, s := range data[obj.SELFRXSECT] {
sect := addsection(&Segtext, s.Name, 04)
@@ -1542,37 +1619,27 @@ func dodata() {
s.Value = int64(uint64(datsize) - sect.Vaddr)
datsize += s.Size
sect.Length = uint64(datsize) - sect.Vaddr
- checkdatsize(datsize, obj.SELFRXSECT)
+ checkdatsize(ctxt, datsize, obj.SELFRXSECT)
}
/* read-only data */
sect = addsection(segro, ".rodata", 04)
sect.Vaddr = 0
- Linklookup(Ctxt, "runtime.rodata", 0).Sect = sect
- Linklookup(Ctxt, "runtime.erodata", 0).Sect = sect
+ ctxt.Syms.Lookup("runtime.rodata", 0).Sect = sect
+ ctxt.Syms.Lookup("runtime.erodata", 0).Sect = sect
if !UseRelro() {
- Linklookup(Ctxt, "runtime.types", 0).Sect = sect
- Linklookup(Ctxt, "runtime.etypes", 0).Sect = sect
- }
- roSects := []int{
- obj.STYPE,
- obj.SSTRING,
- obj.SGOSTRING,
- obj.SGOSTRINGHDR,
- obj.SGOFUNC,
- obj.SGCBITS,
- obj.SRODATA,
- obj.SFUNCTAB,
- }
- for _, symn := range roSects {
+ ctxt.Syms.Lookup("runtime.types", 0).Sect = sect
+ ctxt.Syms.Lookup("runtime.etypes", 0).Sect = sect
+ }
+ for _, symn := range obj.ReadOnly {
align := dataMaxAlign[symn]
if sect.Align < align {
sect.Align = align
}
}
datsize = Rnd(datsize, int64(sect.Align))
- for _, symn := range roSects {
+ for _, symn := range obj.ReadOnly {
for _, s := range data[symn] {
datsize = aligndatsize(datsize, s)
s.Sect = sect
@@ -1580,10 +1647,37 @@ func dodata() {
s.Value = int64(uint64(datsize) - sect.Vaddr)
datsize += s.Size
}
- checkdatsize(datsize, symn)
+ checkdatsize(ctxt, datsize, symn)
}
sect.Length = uint64(datsize) - sect.Vaddr
+ /* read-only ELF, Mach-O sections */
+ for _, s := range data[obj.SELFROSECT] {
+ sect = addsection(segro, s.Name, 04)
+ sect.Align = symalign(s)
+ datsize = Rnd(datsize, int64(sect.Align))
+ sect.Vaddr = uint64(datsize)
+ s.Sect = sect
+ s.Type = obj.SRODATA
+ s.Value = int64(uint64(datsize) - sect.Vaddr)
+ datsize += s.Size
+ sect.Length = uint64(datsize) - sect.Vaddr
+ }
+ checkdatsize(ctxt, datsize, obj.SELFROSECT)
+
+ for _, s := range data[obj.SMACHOPLT] {
+ sect = addsection(segro, s.Name, 04)
+ sect.Align = symalign(s)
+ datsize = Rnd(datsize, int64(sect.Align))
+ sect.Vaddr = uint64(datsize)
+ s.Sect = sect
+ s.Type = obj.SRODATA
+ s.Value = int64(uint64(datsize) - sect.Vaddr)
+ datsize += s.Size
+ sect.Length = uint64(datsize) - sect.Vaddr
+ }
+ checkdatsize(ctxt, datsize, obj.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
// mprotect sections after relocations are applied by giving them write
@@ -1594,77 +1688,75 @@ func dodata() {
// situation.
// TODO(mwhudson): It would make sense to do this more widely, but it makes
// the system linker segfault on darwin.
- relro_perms := 04
- relro_prefix := ""
+ addrelrosection := func(suffix string) *Section {
+ return addsection(segro, suffix, 04)
+ }
if UseRelro() {
- relro_perms = 06
- relro_prefix = ".data.rel.ro"
+ addrelrosection = func(suffix string) *Section {
+ seg := &Segrelrodata
+ if Linkmode == LinkExternal {
+ // Using a separate segment with an external
+ // linker results in some programs moving
+ // their data sections unexpectedly, which
+ // corrupts the moduledata. So we use the
+ // rodata segment and let the external linker
+ // sort out a rel.ro segment.
+ seg = &Segrodata
+ }
+ return addsection(seg, ".data.rel.ro"+suffix, 06)
+ }
/* data only written by relocations */
- sect = addsection(segro, ".data.rel.ro", 06)
+ sect = addrelrosection("")
sect.Vaddr = 0
- Linklookup(Ctxt, "runtime.types", 0).Sect = sect
- Linklookup(Ctxt, "runtime.etypes", 0).Sect = sect
- relroSects := []int{
- obj.STYPERELRO,
- obj.SSTRINGRELRO,
- obj.SGOSTRINGRELRO,
- obj.SGOSTRINGHDRRELRO,
- obj.SGOFUNCRELRO,
- obj.SGCBITSRELRO,
- obj.SRODATARELRO,
- obj.SFUNCTABRELRO,
- }
- for _, symn := range relroSects {
+ 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]
align := dataMaxAlign[symn]
if sect.Align < align {
sect.Align = align
}
}
datsize = Rnd(datsize, int64(sect.Align))
- for _, symn := range relroSects {
+ for _, symnro := range obj.ReadOnly {
+ symn := obj.RelROMap[symnro]
for _, s := range data[symn] {
datsize = aligndatsize(datsize, s)
if s.Outer != nil && s.Outer.Sect != nil && s.Outer.Sect != sect {
- Diag("s.Outer (%s) in different section from s (%s)", s.Outer.Name, s.Name)
+ 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.Value = int64(uint64(datsize) - sect.Vaddr)
datsize += s.Size
}
- checkdatsize(datsize, symn)
+ checkdatsize(ctxt, datsize, symn)
}
sect.Length = uint64(datsize) - sect.Vaddr
-
}
/* typelink */
- sect = addsection(segro, relro_prefix+".typelink", relro_perms)
+ sect = addrelrosection(".typelink")
sect.Align = dataMaxAlign[obj.STYPELINK]
datsize = Rnd(datsize, int64(sect.Align))
sect.Vaddr = uint64(datsize)
- Linklookup(Ctxt, "runtime.typelink", 0).Sect = sect
- Linklookup(Ctxt, "runtime.etypelink", 0).Sect = sect
- for _, s := range data[obj.STYPELINK] {
- datsize = aligndatsize(datsize, s)
- s.Sect = sect
- s.Type = obj.SRODATA
- s.Value = int64(uint64(datsize) - sect.Vaddr)
- datsize += s.Size
- }
- checkdatsize(datsize, obj.STYPELINK)
+ typelink := ctxt.Syms.Lookup("runtime.typelink", 0)
+ typelink.Sect = sect
+ typelink.Type = obj.RODATA
+ datsize += typelink.Size
+ checkdatsize(ctxt, datsize, obj.STYPELINK)
sect.Length = uint64(datsize) - sect.Vaddr
/* itablink */
- sect = addsection(segro, relro_prefix+".itablink", relro_perms)
+ sect = addrelrosection(".itablink")
sect.Align = dataMaxAlign[obj.SITABLINK]
datsize = Rnd(datsize, int64(sect.Align))
sect.Vaddr = uint64(datsize)
- Linklookup(Ctxt, "runtime.itablink", 0).Sect = sect
- Linklookup(Ctxt, "runtime.eitablink", 0).Sect = sect
+ ctxt.Syms.Lookup("runtime.itablink", 0).Sect = sect
+ ctxt.Syms.Lookup("runtime.eitablink", 0).Sect = sect
for _, s := range data[obj.SITABLINK] {
datsize = aligndatsize(datsize, s)
s.Sect = sect
@@ -1672,16 +1764,16 @@ func dodata() {
s.Value = int64(uint64(datsize) - sect.Vaddr)
datsize += s.Size
}
- checkdatsize(datsize, obj.SITABLINK)
+ checkdatsize(ctxt, datsize, obj.SITABLINK)
sect.Length = uint64(datsize) - sect.Vaddr
/* gosymtab */
- sect = addsection(segro, relro_prefix+".gosymtab", relro_perms)
+ sect = addrelrosection(".gosymtab")
sect.Align = dataMaxAlign[obj.SSYMTAB]
datsize = Rnd(datsize, int64(sect.Align))
sect.Vaddr = uint64(datsize)
- Linklookup(Ctxt, "runtime.symtab", 0).Sect = sect
- Linklookup(Ctxt, "runtime.esymtab", 0).Sect = sect
+ ctxt.Syms.Lookup("runtime.symtab", 0).Sect = sect
+ ctxt.Syms.Lookup("runtime.esymtab", 0).Sect = sect
for _, s := range data[obj.SSYMTAB] {
datsize = aligndatsize(datsize, s)
s.Sect = sect
@@ -1689,16 +1781,16 @@ func dodata() {
s.Value = int64(uint64(datsize) - sect.Vaddr)
datsize += s.Size
}
- checkdatsize(datsize, obj.SSYMTAB)
+ checkdatsize(ctxt, datsize, obj.SSYMTAB)
sect.Length = uint64(datsize) - sect.Vaddr
/* gopclntab */
- sect = addsection(segro, relro_prefix+".gopclntab", relro_perms)
+ sect = addrelrosection(".gopclntab")
sect.Align = dataMaxAlign[obj.SPCLNTAB]
datsize = Rnd(datsize, int64(sect.Align))
sect.Vaddr = uint64(datsize)
- Linklookup(Ctxt, "runtime.pclntab", 0).Sect = sect
- Linklookup(Ctxt, "runtime.epclntab", 0).Sect = sect
+ ctxt.Syms.Lookup("runtime.pclntab", 0).Sect = sect
+ ctxt.Syms.Lookup("runtime.epclntab", 0).Sect = sect
for _, s := range data[obj.SPCLNTAB] {
datsize = aligndatsize(datsize, s)
s.Sect = sect
@@ -1706,49 +1798,26 @@ func dodata() {
s.Value = int64(uint64(datsize) - sect.Vaddr)
datsize += s.Size
}
- checkdatsize(datsize, obj.SRODATA)
+ checkdatsize(ctxt, datsize, obj.SRODATA)
sect.Length = uint64(datsize) - sect.Vaddr
- /* read-only ELF, Mach-O sections */
- for _, s := range data[obj.SELFROSECT] {
- sect = addsection(segro, s.Name, 04)
- sect.Align = symalign(s)
- datsize = Rnd(datsize, int64(sect.Align))
- sect.Vaddr = uint64(datsize)
- s.Sect = sect
- s.Type = obj.SRODATA
- s.Value = int64(uint64(datsize) - sect.Vaddr)
- datsize += s.Size
- sect.Length = uint64(datsize) - sect.Vaddr
- }
- checkdatsize(datsize, obj.SELFROSECT)
-
- for _, s := range data[obj.SMACHOPLT] {
- sect = addsection(segro, s.Name, 04)
- sect.Align = symalign(s)
- datsize = Rnd(datsize, int64(sect.Align))
- sect.Vaddr = uint64(datsize)
- s.Sect = sect
- s.Type = obj.SRODATA
- s.Value = int64(uint64(datsize) - sect.Vaddr)
- datsize += s.Size
- sect.Length = uint64(datsize) - sect.Vaddr
- }
- checkdatsize(datsize, obj.SMACHOPLT)
-
// 6g uses 4-byte relocation offsets, so the entire segment must fit in 32 bits.
if datsize != int64(uint32(datsize)) {
- Diag("read-only data segment too large")
+ Errorf(nil, "read-only data segment too large: %d", datsize)
}
for symn := obj.SELFRXSECT; symn < obj.SXREF; symn++ {
datap = append(datap, data[symn]...)
}
- dwarfgeneratedebugsyms()
+ dwarfgeneratedebugsyms(ctxt)
- var s *LSym
- for s = dwarfp; s != nil && s.Type == obj.SDWARFSECT; s = s.Next {
+ var s *Symbol
+ var i int
+ for i, s = range dwarfp {
+ if s.Type != obj.SDWARFSECT {
+ break
+ }
sect = addsection(&Segdwarf, s.Name, 04)
sect.Align = 1
datsize = Rnd(datsize, int64(sect.Align))
@@ -1759,14 +1828,17 @@ func dodata() {
datsize += s.Size
sect.Length = uint64(datsize) - sect.Vaddr
}
- checkdatsize(datsize, obj.SDWARFSECT)
+ checkdatsize(ctxt, datsize, obj.SDWARFSECT)
- if s != nil {
+ if i < len(dwarfp) {
sect = addsection(&Segdwarf, ".debug_info", 04)
sect.Align = 1
datsize = Rnd(datsize, int64(sect.Align))
sect.Vaddr = uint64(datsize)
- for ; s != nil && s.Type == obj.SDWARFINFO; s = s.Next {
+ for _, s := range dwarfp[i:] {
+ if s.Type != obj.SDWARFINFO {
+ break
+ }
s.Sect = sect
s.Type = obj.SRODATA
s.Value = int64(uint64(datsize) - sect.Vaddr)
@@ -1774,7 +1846,7 @@ func dodata() {
datsize += s.Size
}
sect.Length = uint64(datsize) - sect.Vaddr
- checkdatsize(datsize, obj.SDWARFINFO)
+ checkdatsize(ctxt, datsize, obj.SDWARFINFO)
}
/* number the sections */
@@ -1788,6 +1860,10 @@ func dodata() {
sect.Extnum = int16(n)
n++
}
+ for sect := Segrelrodata.Sect; sect != nil; sect = sect.Next {
+ sect.Extnum = int16(n)
+ n++
+ }
for sect := Segdata.Sect; sect != nil; sect = sect.Next {
sect.Extnum = int16(n)
n++
@@ -1798,38 +1874,53 @@ func dodata() {
}
}
-func dodataSect(symn int, syms []*LSym) (result []*LSym, maxAlign int32) {
- if HEADTYPE == obj.Hdarwin {
+func dodataSect(ctxt *Link, symn obj.SymKind, syms []*Symbol) (result []*Symbol, maxAlign int32) {
+ if Headtype == obj.Hdarwin {
// Some symbols may no longer belong in syms
// due to movement in machosymorder.
- newSyms := make([]*LSym, 0, len(syms))
+ newSyms := make([]*Symbol, 0, len(syms))
for _, s := range syms {
- if int(s.Type) == symn {
+ if s.Type == symn {
newSyms = append(newSyms, s)
}
}
syms = newSyms
}
- symsSort := make([]dataSortKey, len(syms))
- for i, s := range syms {
+ var head, tail *Symbol
+ symsSort := make([]dataSortKey, 0, len(syms))
+ for _, s := range syms {
if s.Attr.OnList() {
log.Fatalf("symbol %s listed multiple times", s.Name)
}
s.Attr |= AttrOnList
switch {
case s.Size < int64(len(s.P)):
- Diag("%s: initialize bounds (%d < %d)", s.Name, s.Size, len(s.P))
+ Errorf(s, "initialize bounds (%d < %d)", s.Size, len(s.P))
case s.Size < 0:
- Diag("%s: negative size (%d bytes)", s.Name, s.Size)
+ Errorf(s, "negative size (%d bytes)", s.Size)
case s.Size > cutoff:
- Diag("%s: symbol too large (%d bytes)", s.Name, s.Size)
+ Errorf(s, "symbol too large (%d bytes)", s.Size)
}
- symsSort[i] = dataSortKey{
+ // 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 {
+ switch s.Name {
+ case "runtime.text", "runtime.bss", "runtime.data", "runtime.types":
+ head = s
+ continue
+ case "runtime.etext", "runtime.ebss", "runtime.edata", "runtime.etypes":
+ tail = s
+ continue
+ }
+ }
+
+ key := dataSortKey{
size: s.Size,
name: s.Name,
- lsym: s,
+ sym: s,
}
switch s.Type {
@@ -1838,23 +1929,29 @@ func dodataSect(symn int, syms []*LSym) (result []*LSym, maxAlign int32) {
// from input files. Both are type SELFGOT, so in that case
// we skip size comparison and fall through to the name
// comparison (conveniently, .got sorts before .toc).
- symsSort[i].size = 0
- case obj.STYPELINK:
- // Sort typelinks by the rtype.string field so the reflect
- // package can binary search type links.
- symsSort[i].name = string(decodetype_str(s.R[0].Sym))
+ key.size = 0
}
+
+ symsSort = append(symsSort, key)
}
sort.Sort(bySizeAndName(symsSort))
+ off := 0
+ if head != nil {
+ syms[0] = head
+ off++
+ }
for i, symSort := range symsSort {
- syms[i] = symSort.lsym
- align := symalign(symSort.lsym)
+ syms[i+off] = symSort.sym
+ align := symalign(symSort.sym)
if maxAlign < align {
maxAlign = align
}
}
+ if tail != nil {
+ syms[len(syms)-1] = tail
+ }
if Iself && symn == obj.SELFROSECT {
// Make .rela and .rela.plt contiguous, the ELF ABI requires this
@@ -1890,27 +1987,27 @@ func dodataSect(symn int, syms []*LSym) (result []*LSym, maxAlign int32) {
// give us a place to put the Go build ID. On those systems, we put it
// at the very beginning of the text segment.
// This ``header'' is read by cmd/go.
-func textbuildid() {
- if Iself || buildid == "" {
+func (ctxt *Link) textbuildid() {
+ if Iself || Buildmode == BuildmodePlugin || *flagBuildid == "" {
return
}
- sym := Linklookup(Ctxt, "go.buildid", 0)
+ sym := ctxt.Syms.Lookup("go.buildid", 0)
sym.Attr |= AttrReachable
// The \xff is invalid UTF-8, meant to make it less likely
// to find one of these accidentally.
- data := "\xff Go build ID: " + strconv.Quote(buildid) + "\n \xff"
+ data := "\xff Go build ID: " + strconv.Quote(*flagBuildid) + "\n \xff"
sym.Type = obj.STEXT
sym.P = []byte(data)
sym.Size = int64(len(sym.P))
- Ctxt.Textp = append(Ctxt.Textp, nil)
- copy(Ctxt.Textp[1:], Ctxt.Textp)
- Ctxt.Textp[0] = sym
+ ctxt.Textp = append(ctxt.Textp, nil)
+ copy(ctxt.Textp[1:], ctxt.Textp)
+ ctxt.Textp[0] = sym
}
// assign addresses to text
-func textaddress() {
+func (ctxt *Link) textaddress() {
addsection(&Segtext, ".text", 05)
// Assign PCs in text segment.
@@ -1919,43 +2016,110 @@ func textaddress() {
sect := Segtext.Sect
sect.Align = int32(Funcalign)
- Linklookup(Ctxt, "runtime.text", 0).Sect = sect
- Linklookup(Ctxt, "runtime.etext", 0).Sect = sect
- if HEADTYPE == obj.Hwindows {
- Linklookup(Ctxt, ".text", 0).Sect = sect
+
+ text := ctxt.Syms.Lookup("runtime.text", 0)
+ text.Sect = sect
+
+ if ctxt.DynlinkingGo() && Headtype == obj.Hdarwin {
+ etext := ctxt.Syms.Lookup("runtime.etext", 0)
+ etext.Sect = sect
+
+ ctxt.Textp = append(ctxt.Textp, etext, nil)
+ copy(ctxt.Textp[1:], ctxt.Textp)
+ ctxt.Textp[0] = text
+ }
+
+ if Headtype == obj.Hwindows || Headtype == obj.Hwindowsgui {
+ ctxt.Syms.Lookup(".text", 0).Sect = sect
}
- va := uint64(INITTEXT)
+ va := uint64(*FlagTextAddr)
+ n := 1
sect.Vaddr = va
- for _, sym := range Ctxt.Textp {
- sym.Sect = sect
- if sym.Type&obj.SSUB != 0 {
- continue
- }
- if sym.Align != 0 {
- va = uint64(Rnd(int64(va), int64(sym.Align)))
- } else {
- va = uint64(Rnd(int64(va), int64(Funcalign)))
- }
- sym.Value = 0
- for sub := sym; sub != nil; sub = sub.Sub {
- sub.Value += int64(va)
- }
- if sym.Size == 0 && sym.Sub != nil {
- Ctxt.Cursym = sym
- }
- if sym.Size < MINFUNC {
- va += MINFUNC // spacing required for findfunctab
- } else {
- va += uint64(sym.Size)
+ ntramps := 0
+ for _, sym := range ctxt.Textp {
+ sect, n, va = assignAddress(ctxt, sect, n, sym, va)
+
+ 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.Length = va - sect.Vaddr
+ ctxt.Syms.Lookup("runtime.etext", 0).Sect = sect
+
+ // merge tramps into Textp, keeping Textp in address order
+ if ntramps != 0 {
+ newtextp := make([]*Symbol, 0, len(ctxt.Textp)+ntramps)
+ i := 0
+ for _, sym := range ctxt.Textp {
+ for ; i < ntramps && ctxt.tramps[i].Value < sym.Value; i++ {
+ newtextp = append(newtextp, ctxt.tramps[i])
+ }
+ newtextp = append(newtextp, sym)
+ }
+ newtextp = append(newtextp, ctxt.tramps[i:ntramps]...)
+
+ ctxt.Textp = newtextp
+ }
+}
+
+// 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) {
+ sym.Sect = sect
+ if sym.Type&obj.SSUB != 0 {
+ return sect, n, va
+ }
+ if sym.Align != 0 {
+ va = uint64(Rnd(int64(va), int64(sym.Align)))
+ } else {
+ va = uint64(Rnd(int64(va), int64(Funcalign)))
+ }
+ sym.Value = 0
+ for sub := sym; sub != nil; sub = sub.Sub {
+ sub.Value += int64(va)
+ }
+
+ funcsize := uint64(MINFUNC) // spacing required for findfunctab
+ if sym.Size > MINFUNC {
+ funcsize = uint64(sym.Size)
+ }
+
+ // On ppc64x a text section should not be larger than 2^26 bytes due to the size of
+ // call target offset field in the bl instruction. Splitting into smaller text
+ // sections smaller than this limit allows the GNU linker to modify the long calls
+ // appropriately. The limit allows for the space needed for tables inserted by the linker.
+
+ // If this function doesn't fit in the current text section, then create a new one.
+
+ // Only break at outermost syms.
+
+ if SysArch.InFamily(sys.PPC64) && sym.Outer == nil && Iself && Linkmode == LinkExternal && va-sect.Vaddr+funcsize > 0x1c00000 {
+
+ // Set the length for the previous text section
+ sect.Length = va - sect.Vaddr
+
+ // Create new section, set the starting Vaddr
+ sect = addsection(&Segtext, ".text", 05)
+ sect.Vaddr = va
+
+ // Create a symbol for the start of the secondary text sections
+ ctxt.Syms.Lookup(fmt.Sprintf("runtime.text.%d", n), 0).Sect = sect
+ n++
+ }
+ va += funcsize
+
+ return sect, n, va
}
// assign addresses
-func address() {
- va := uint64(INITTEXT)
+func (ctxt *Link) address() {
+ va := uint64(*FlagTextAddr)
Segtext.Rwx = 05
Segtext.Vaddr = va
Segtext.Fileoff = uint64(HEADR)
@@ -1965,16 +2129,27 @@ func address() {
va += s.Length
}
- Segtext.Length = va - uint64(INITTEXT)
+ Segtext.Length = va - uint64(*FlagTextAddr)
Segtext.Filelen = Segtext.Length
- if HEADTYPE == obj.Hnacl {
+ if Headtype == obj.Hnacl {
va += 32 // room for the "halt sled"
}
if Segrodata.Sect != nil {
// align to page boundary so as not to mix
// rodata and executable text.
- va = uint64(Rnd(int64(va), int64(INITRND)))
+ //
+ // Note: gold or GNU ld will reduce the size of the executable
+ // file by arranging for the relro segment to end at a page
+ // boundary, and overlap the end of the text segment with the
+ // start of the relro segment in the file. The PT_LOAD segments
+ // will be such that the last page of the text segment will be
+ // mapped twice, once r-x and once starting out rw- and, after
+ // relocation processing, changed to r--.
+ //
+ // Ideally the last page of the text segment would not be
+ // writable even for this short period.
+ va = uint64(Rnd(int64(va), int64(*FlagRound)))
Segrodata.Rwx = 04
Segrodata.Vaddr = va
@@ -1989,16 +2164,34 @@ func address() {
Segrodata.Length = va - Segrodata.Vaddr
Segrodata.Filelen = Segrodata.Length
}
+ if Segrelrodata.Sect != nil {
+ // align to page boundary so as not to mix
+ // rodata, rel-ro data, and executable text.
+ va = uint64(Rnd(int64(va), int64(*FlagRound)))
+
+ Segrelrodata.Rwx = 06
+ Segrelrodata.Vaddr = va
+ Segrelrodata.Fileoff = va - Segrodata.Vaddr + Segrodata.Fileoff
+ Segrelrodata.Filelen = 0
+ for s := Segrelrodata.Sect; s != nil; s = s.Next {
+ va = uint64(Rnd(int64(va), int64(s.Align)))
+ s.Vaddr = va
+ va += s.Length
+ }
+
+ Segrelrodata.Length = va - Segrelrodata.Vaddr
+ Segrelrodata.Filelen = Segrelrodata.Length
+ }
- va = uint64(Rnd(int64(va), int64(INITRND)))
+ va = uint64(Rnd(int64(va), int64(*FlagRound)))
Segdata.Rwx = 06
Segdata.Vaddr = va
Segdata.Fileoff = va - Segtext.Vaddr + Segtext.Fileoff
Segdata.Filelen = 0
- if HEADTYPE == obj.Hwindows {
+ if Headtype == obj.Hwindows || Headtype == obj.Hwindowsgui {
Segdata.Fileoff = Segtext.Fileoff + uint64(Rnd(int64(Segtext.Length), PEFILEALIGN))
}
- if HEADTYPE == obj.Hplan9 {
+ if Headtype == obj.Hplan9 {
Segdata.Fileoff = Segtext.Fileoff + Segtext.Filelen
}
var data *Section
@@ -2033,12 +2226,12 @@ func address() {
Segdata.Filelen = bss.Vaddr - Segdata.Vaddr
- va = uint64(Rnd(int64(va), int64(INITRND)))
+ va = uint64(Rnd(int64(va), int64(*FlagRound)))
Segdwarf.Rwx = 06
Segdwarf.Vaddr = va
- Segdwarf.Fileoff = Segdata.Fileoff + uint64(Rnd(int64(Segdata.Filelen), int64(INITRND)))
+ Segdwarf.Fileoff = Segdata.Fileoff + uint64(Rnd(int64(Segdata.Filelen), int64(*FlagRound)))
Segdwarf.Filelen = 0
- if HEADTYPE == obj.Hwindows {
+ if Headtype == obj.Hwindows || Headtype == obj.Hwindowsgui {
Segdwarf.Fileoff = Segdata.Fileoff + uint64(Rnd(int64(Segdata.Filelen), int64(PEFILEALIGN)))
}
for s := Segdwarf.Sect; s != nil; s = s.Next {
@@ -2048,7 +2241,7 @@ func address() {
}
s.Vaddr = va
va += uint64(vlen)
- if HEADTYPE == obj.Hwindows {
+ if Headtype == obj.Hwindows || Headtype == obj.Hwindowsgui {
va = uint64(Rnd(int64(va), PEFILEALIGN))
}
Segdwarf.Length = va - Segdwarf.Vaddr
@@ -2056,27 +2249,21 @@ func address() {
Segdwarf.Filelen = va - Segdwarf.Vaddr
- text := Segtext.Sect
- var rodata *Section
- if Segrodata.Sect != nil {
- rodata = Segrodata.Sect
- } else {
- rodata = text.Next
- }
- var relrodata *Section
- typelink := rodata.Next
- if UseRelro() {
- // There is another section (.data.rel.ro) when building a shared
- // object on elf systems.
- relrodata = typelink
- typelink = typelink.Next
+ var (
+ text = Segtext.Sect
+ rodata = ctxt.Syms.Lookup("runtime.rodata", 0).Sect
+ itablink = ctxt.Syms.Lookup("runtime.itablink", 0).Sect
+ symtab = ctxt.Syms.Lookup("runtime.symtab", 0).Sect
+ pclntab = ctxt.Syms.Lookup("runtime.pclntab", 0).Sect
+ types = ctxt.Syms.Lookup("runtime.types", 0).Sect
+ )
+ lasttext := text
+ // Could be multiple .text sections
+ for sect := text.Next; sect != nil && sect.Name == ".text"; sect = sect.Next {
+ lasttext = sect
}
- itablink := typelink.Next
- symtab := itablink.Next
- pclntab := symtab.Next
for _, s := range datap {
- Ctxt.Cursym = s
if s.Sect != nil {
s.Value += int64(s.Sect.Vaddr)
}
@@ -2085,8 +2272,7 @@ func address() {
}
}
- for sym := dwarfp; sym != nil; sym = sym.Next {
- Ctxt.Cursym = sym
+ for _, sym := range dwarfp {
if sym.Sect != nil {
sym.Value += int64(sym.Sect.Vaddr)
}
@@ -2096,52 +2282,66 @@ func address() {
}
if Buildmode == BuildmodeShared {
- s := Linklookup(Ctxt, "go.link.abihashbytes", 0)
- sectSym := Linklookup(Ctxt, ".note.go.abihash", 0)
+ s := ctxt.Syms.Lookup("go.link.abihashbytes", 0)
+ sectSym := ctxt.Syms.Lookup(".note.go.abihash", 0)
s.Sect = sectSym.Sect
s.Value = int64(sectSym.Sect.Vaddr + 16)
}
- types := relrodata
- if types == nil {
- types = rodata
+ 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))
}
- xdefine("runtime.text", obj.STEXT, int64(text.Vaddr))
- xdefine("runtime.etext", obj.STEXT, int64(text.Vaddr+text.Length))
- if HEADTYPE == obj.Hwindows {
- xdefine(".text", obj.STEXT, int64(text.Vaddr))
+ // 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++
}
- xdefine("runtime.rodata", obj.SRODATA, int64(rodata.Vaddr))
- xdefine("runtime.erodata", obj.SRODATA, int64(rodata.Vaddr+rodata.Length))
- xdefine("runtime.types", obj.SRODATA, int64(types.Vaddr))
- xdefine("runtime.etypes", obj.SRODATA, int64(types.Vaddr+types.Length))
- xdefine("runtime.typelink", obj.SRODATA, int64(typelink.Vaddr))
- xdefine("runtime.etypelink", obj.SRODATA, int64(typelink.Vaddr+typelink.Length))
- xdefine("runtime.itablink", obj.SRODATA, int64(itablink.Vaddr))
- xdefine("runtime.eitablink", obj.SRODATA, int64(itablink.Vaddr+itablink.Length))
- sym := Linklookup(Ctxt, "runtime.gcdata", 0)
+ 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))
+
+ sym := ctxt.Syms.Lookup("runtime.gcdata", 0)
sym.Attr |= AttrLocal
- xdefine("runtime.egcdata", obj.SRODATA, Symaddr(sym)+sym.Size)
- Linklookup(Ctxt, "runtime.egcdata", 0).Sect = sym.Sect
+ ctxt.xdefine("runtime.egcdata", obj.SRODATA, Symaddr(sym)+sym.Size)
+ ctxt.Syms.Lookup("runtime.egcdata", 0).Sect = sym.Sect
- sym = Linklookup(Ctxt, "runtime.gcbss", 0)
+ sym = ctxt.Syms.Lookup("runtime.gcbss", 0)
sym.Attr |= AttrLocal
- xdefine("runtime.egcbss", obj.SRODATA, Symaddr(sym)+sym.Size)
- Linklookup(Ctxt, "runtime.egcbss", 0).Sect = sym.Sect
-
- xdefine("runtime.symtab", obj.SRODATA, int64(symtab.Vaddr))
- xdefine("runtime.esymtab", obj.SRODATA, int64(symtab.Vaddr+symtab.Length))
- xdefine("runtime.pclntab", obj.SRODATA, int64(pclntab.Vaddr))
- xdefine("runtime.epclntab", obj.SRODATA, int64(pclntab.Vaddr+pclntab.Length))
- xdefine("runtime.noptrdata", obj.SNOPTRDATA, int64(noptr.Vaddr))
- xdefine("runtime.enoptrdata", obj.SNOPTRDATA, int64(noptr.Vaddr+noptr.Length))
- xdefine("runtime.bss", obj.SBSS, int64(bss.Vaddr))
- xdefine("runtime.ebss", obj.SBSS, int64(bss.Vaddr+bss.Length))
- xdefine("runtime.data", obj.SDATA, int64(data.Vaddr))
- xdefine("runtime.edata", obj.SDATA, int64(data.Vaddr+data.Length))
- xdefine("runtime.noptrbss", obj.SNOPTRBSS, int64(noptrbss.Vaddr))
- xdefine("runtime.enoptrbss", obj.SNOPTRBSS, int64(noptrbss.Vaddr+noptrbss.Length))
- xdefine("runtime.end", obj.SBSS, int64(Segdata.Vaddr+Segdata.Length))
+ ctxt.xdefine("runtime.egcbss", obj.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))
+}
+
+// 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.Attr |= AttrReachable
+ s.Attr |= AttrOnList
+ ctxt.tramps = append(ctxt.tramps, s)
+ if *FlagDebugTramp > 0 && ctxt.Debugvlog > 0 {
+ ctxt.Logf("trampoline %s inserted\n", s)
+ }
}
diff --git a/src/cmd/link/internal/ld/deadcode.go b/src/cmd/link/internal/ld/deadcode.go
index aaed6cd..ae51681 100644
--- a/src/cmd/link/internal/ld/deadcode.go
+++ b/src/cmd/link/internal/ld/deadcode.go
@@ -15,7 +15,7 @@ import (
// deadcode marks all reachable symbols.
//
// The basis of the dead code elimination is a flood fill of symbols,
-// following their relocations, beginning at INITENTRY.
+// following their relocations, beginning at *flagEntrySymbol.
//
// This flood fill is wrapped in logic for pruning unused methods.
// All methods are mentioned by relocations on their receiver's *rtype.
@@ -45,8 +45,8 @@ import (
//
// Any unreached text symbols are removed from ctxt.Textp.
func deadcode(ctxt *Link) {
- if Debug['v'] != 0 {
- fmt.Fprintf(ctxt.Bso, "%5.2f deadcode\n", obj.Cputime())
+ if ctxt.Debugvlog != 0 {
+ ctxt.Logf("%5.2f deadcode\n", obj.Cputime())
}
d := &deadcodepass{
@@ -55,15 +55,15 @@ func deadcode(ctxt *Link) {
}
// First, flood fill any symbols directly reachable in the call
- // graph from INITENTRY. Ignore all methods not directly called.
+ // graph from *flagEntrySymbol. Ignore all methods not directly called.
d.init()
d.flood()
- callSym := Linkrlookup(ctxt, "reflect.Value.Call", 0)
- methSym := Linkrlookup(ctxt, "reflect.Value.Method", 0)
+ callSym := ctxt.Syms.ROLookup("reflect.Value.Call", 0)
+ methSym := ctxt.Syms.ROLookup("reflect.Value.Method", 0)
reflectSeen := false
- if DynlinkingGo() {
+ if ctxt.DynlinkingGo() {
// Exported methods may satisfy interfaces we don't know
// about yet when dynamically linking.
reflectSeen = true
@@ -108,18 +108,17 @@ func deadcode(ctxt *Link) {
}
if Buildmode != BuildmodeShared {
- // Keep a typelink or itablink if the symbol it points at is being kept.
- // (When BuildmodeShared, always keep typelinks and itablinks.)
- for _, s := range ctxt.Allsym {
- if strings.HasPrefix(s.Name, "go.typelink.") ||
- strings.HasPrefix(s.Name, "go.itablink.") {
+ // Keep a itablink if the symbol it points at is being kept.
+ // (When BuildmodeShared, always keep itablinks.)
+ for _, s := range ctxt.Syms.Allsym {
+ if strings.HasPrefix(s.Name, "go.itablink.") {
s.Attr.Set(AttrReachable, len(s.R) == 1 && s.R[0].Sym.Attr.Reachable())
}
}
}
// Remove dead text but keep file information (z symbols).
- textp := make([]*LSym, 0, len(ctxt.Textp))
+ textp := make([]*Symbol, 0, len(ctxt.Textp))
for _, s := range ctxt.Textp {
if s.Attr.Reachable() {
textp = append(textp, s)
@@ -154,11 +153,11 @@ var markextra = []string{
// the reflect.method struct: mtyp, ifn, and tfn.
type methodref struct {
m methodsig
- src *LSym // receiver type symbol
+ src *Symbol // receiver type symbol
r [3]*Reloc // R_METHODOFF relocations to fields of runtime.method
}
-func (m methodref) ifn() *LSym { return m.r[1].Sym }
+func (m methodref) ifn() *Symbol { return m.r[1].Sym }
func (m methodref) isExported() bool {
for _, r := range m.m {
@@ -170,7 +169,7 @@ func (m methodref) isExported() bool {
// deadcodepass holds state for the deadcode flood fill.
type deadcodepass struct {
ctxt *Link
- markQueue []*LSym // symbols to flood fill in next pass
+ markQueue []*Symbol // symbols to flood fill in next pass
ifaceMethod map[methodsig]bool // methods declared in reached interfaces
markableMethods []methodref // methods of reached types
reflectMethod bool
@@ -180,8 +179,8 @@ func (d *deadcodepass) cleanupReloc(r *Reloc) {
if r.Sym.Attr.Reachable() {
r.Type = obj.R_ADDROFF
} else {
- if Debug['v'] > 1 {
- fmt.Fprintf(d.ctxt.Bso, "removing method %s\n", r.Sym.Name)
+ if d.ctxt.Debugvlog > 1 {
+ d.ctxt.Logf("removing method %s\n", r.Sym.Name)
}
r.Sym = nil
r.Siz = 0
@@ -189,14 +188,14 @@ func (d *deadcodepass) cleanupReloc(r *Reloc) {
}
// mark appends a symbol to the mark queue for flood filling.
-func (d *deadcodepass) mark(s, parent *LSym) {
+func (d *deadcodepass) mark(s, parent *Symbol) {
if s == nil || s.Attr.Reachable() {
return
}
if s.Attr.ReflectMethod() {
d.reflectMethod = true
}
- if flag_dumpdep {
+ if *flagDumpDep {
p := "_"
if parent != nil {
p = parent.Name
@@ -217,13 +216,13 @@ func (d *deadcodepass) markMethod(m methodref) {
}
// init marks all initial symbols as reachable.
-// In a typical binary, this is INITENTRY.
+// In a typical binary, this is *flagEntrySymbol.
func (d *deadcodepass) init() {
var names []string
if SysArch.Family == sys.ARM {
// mark some functions that are only referenced after linker code editing
- if d.ctxt.Goarm == 5 {
+ if obj.GOARM == 5 {
names = append(names, "_sfloat")
}
names = append(names, "runtime.read_tls_fallback")
@@ -232,7 +231,7 @@ func (d *deadcodepass) init() {
if Buildmode == BuildmodeShared {
// Mark all symbols defined in this library as reachable when
// building a shared library.
- for _, s := range d.ctxt.Allsym {
+ for _, s := range d.ctxt.Syms.Allsym {
if s.Type != 0 && s.Type != obj.SDYNIMPORT {
d.mark(s, nil)
}
@@ -240,9 +239,20 @@ func (d *deadcodepass) init() {
} else {
// In a normal binary, start at main.main and the init
// functions and mark what is reachable from there.
- names = append(names, INITENTRY)
- if Linkshared && Buildmode == BuildmodeExe {
+ names = append(names, *flagEntrySymbol)
+ if *FlagLinkshared && (Buildmode == BuildmodeExe || Buildmode == BuildmodePIE) {
names = append(names, "main.main", "main.init")
+ } else if Buildmode == BuildmodePlugin {
+ names = append(names, *flagPluginPath+".init", *flagPluginPath+".main", "go.plugin.tabs")
+
+ // We don't keep the go.plugin.exports symbol,
+ // but we do keep the symbols it refers to.
+ exports := d.ctxt.Syms.ROLookup("go.plugin.exports", 0)
+ if exports != nil {
+ for _, r := range exports.R {
+ d.mark(r.Sym, nil)
+ }
+ }
}
for _, name := range markextra {
names = append(names, name)
@@ -253,7 +263,7 @@ func (d *deadcodepass) init() {
}
for _, name := range names {
- d.mark(Linkrlookup(d.ctxt, name, 0), nil)
+ d.mark(d.ctxt.Syms.ROLookup(name, 0), nil)
}
}
@@ -264,8 +274,8 @@ func (d *deadcodepass) flood() {
s := d.markQueue[0]
d.markQueue = d.markQueue[1:]
if s.Type == obj.STEXT {
- if Debug['v'] > 1 {
- fmt.Fprintf(d.ctxt.Bso, "marktext %s\n", s.Name)
+ if d.ctxt.Debugvlog > 1 {
+ d.ctxt.Logf("marktext %s\n", s.Name)
}
if s.FuncInfo != nil {
for _, a := range s.FuncInfo.Autom {
@@ -276,10 +286,15 @@ func (d *deadcodepass) flood() {
}
if strings.HasPrefix(s.Name, "type.") && s.Name[5] != '.' {
- if decodetype_kind(s)&kindMask == kindInterface {
- for _, sig := range decodetype_ifacemethods(s) {
- if Debug['v'] > 1 {
- fmt.Fprintf(d.ctxt.Bso, "reached iface method: %s\n", sig)
+ if len(s.P) == 0 {
+ // Probably a bug. The undefined symbol check
+ // later will give a better error than deadcode.
+ continue
+ }
+ if decodetypeKind(s)&kindMask == kindInterface {
+ for _, sig := range decodeIfaceMethods(d.ctxt.Arch, s) {
+ if d.ctxt.Debugvlog > 1 {
+ d.ctxt.Logf("reached iface method: %s\n", sig)
}
d.ifaceMethod[sig] = true
}
@@ -293,6 +308,12 @@ func (d *deadcodepass) flood() {
if r.Sym == nil {
continue
}
+ if r.Type == obj.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 {
d.mark(r.Sym, s)
continue
@@ -315,7 +336,7 @@ func (d *deadcodepass) flood() {
// Decode runtime type information for type methods
// to help work out which methods can be called
// dynamically via interfaces.
- methodsigs := decodetype_methods(s)
+ methodsigs := decodetypeMethods(d.ctxt.Arch, s)
if len(methods) != len(methodsigs) {
panic(fmt.Sprintf("%q has %d method relocations for %d methods", s.Name, len(methods), len(methodsigs)))
}
diff --git a/src/cmd/link/internal/ld/decodesym.go b/src/cmd/link/internal/ld/decodesym.go
index a1eef03..d111b00 100644
--- a/src/cmd/link/internal/ld/decodesym.go
+++ b/src/cmd/link/internal/ld/decodesym.go
@@ -28,7 +28,7 @@ const (
tflagExtraStar = 1 << 1
)
-func decode_reloc(s *LSym, off int32) *Reloc {
+func decodeReloc(s *Symbol, off int32) *Reloc {
for i := range s.R {
if s.R[i].Off == off {
return &s.R[i]
@@ -37,22 +37,22 @@ func decode_reloc(s *LSym, off int32) *Reloc {
return nil
}
-func decode_reloc_sym(s *LSym, off int32) *LSym {
- r := decode_reloc(s, off)
+func decodeRelocSym(s *Symbol, off int32) *Symbol {
+ r := decodeReloc(s, off)
if r == nil {
return nil
}
return r.Sym
}
-func decode_inuxi(p []byte, sz int) uint64 {
+func decodeInuxi(arch *sys.Arch, p []byte, sz int) uint64 {
switch sz {
case 2:
- return uint64(Ctxt.Arch.ByteOrder.Uint16(p))
+ return uint64(arch.ByteOrder.Uint16(p))
case 4:
- return uint64(Ctxt.Arch.ByteOrder.Uint32(p))
+ return uint64(arch.ByteOrder.Uint32(p))
case 8:
- return Ctxt.Arch.ByteOrder.Uint64(p)
+ return arch.ByteOrder.Uint64(p)
default:
Exitf("dwarf: decode inuxi %d", sz)
panic("unreachable")
@@ -64,33 +64,33 @@ func structfieldSize() int { return 3 * SysArch.PtrSize } // runtime.struc
func uncommonSize() int { return 4 + 2 + 2 + 4 + 4 } // runtime.uncommontype
// Type.commonType.kind
-func decodetype_kind(s *LSym) uint8 {
+func decodetypeKind(s *Symbol) uint8 {
return s.P[2*SysArch.PtrSize+7] & obj.KindMask // 0x13 / 0x1f
}
// Type.commonType.kind
-func decodetype_usegcprog(s *LSym) uint8 {
+func decodetypeUsegcprog(s *Symbol) uint8 {
return s.P[2*SysArch.PtrSize+7] & obj.KindGCProg // 0x13 / 0x1f
}
// Type.commonType.size
-func decodetype_size(s *LSym) int64 {
- return int64(decode_inuxi(s.P, SysArch.PtrSize)) // 0x8 / 0x10
+func decodetypeSize(arch *sys.Arch, s *Symbol) int64 {
+ return int64(decodeInuxi(arch, s.P, SysArch.PtrSize)) // 0x8 / 0x10
}
// Type.commonType.ptrdata
-func decodetype_ptrdata(s *LSym) int64 {
- return int64(decode_inuxi(s.P[SysArch.PtrSize:], SysArch.PtrSize)) // 0x8 / 0x10
+func decodetypePtrdata(arch *sys.Arch, s *Symbol) int64 {
+ return int64(decodeInuxi(arch, s.P[SysArch.PtrSize:], SysArch.PtrSize)) // 0x8 / 0x10
}
// Type.commonType.tflag
-func decodetype_hasUncommon(s *LSym) bool {
+func decodetypeHasUncommon(s *Symbol) bool {
return s.P[2*SysArch.PtrSize+4]&tflagUncommon != 0
}
// Find the elf.Section of a given shared library that contains a given address.
-func findShlibSection(path string, addr uint64) *elf.Section {
- for _, shlib := range Ctxt.Shlibs {
+func findShlibSection(ctxt *Link, path string, addr uint64) *elf.Section {
+ for _, shlib := range ctxt.Shlibs {
if shlib.Path == path {
for _, sect := range shlib.File.Sections {
if sect.Addr <= addr && addr <= sect.Addr+sect.Size {
@@ -103,42 +103,42 @@ func findShlibSection(path string, addr uint64) *elf.Section {
}
// Type.commonType.gc
-func decodetype_gcprog(s *LSym) []byte {
+func decodetypeGcprog(ctxt *Link, s *Symbol) []byte {
if s.Type == obj.SDYNIMPORT {
- addr := decodetype_gcprog_shlib(s)
- sect := findShlibSection(s.File, addr)
+ addr := decodetypeGcprogShlib(ctxt, s)
+ sect := findShlibSection(ctxt, s.File, addr)
if sect != nil {
// A gcprog is a 4-byte uint32 indicating length, followed by
// the actual program.
progsize := make([]byte, 4)
sect.ReadAt(progsize, int64(addr-sect.Addr))
- progbytes := make([]byte, Ctxt.Arch.ByteOrder.Uint32(progsize))
+ progbytes := make([]byte, ctxt.Arch.ByteOrder.Uint32(progsize))
sect.ReadAt(progbytes, int64(addr-sect.Addr+4))
return append(progsize, progbytes...)
}
Exitf("cannot find gcprog for %s", s.Name)
return nil
}
- return decode_reloc_sym(s, 2*int32(SysArch.PtrSize)+8+1*int32(SysArch.PtrSize)).P
+ return decodeRelocSym(s, 2*int32(SysArch.PtrSize)+8+1*int32(SysArch.PtrSize)).P
}
-func decodetype_gcprog_shlib(s *LSym) uint64 {
+func decodetypeGcprogShlib(ctxt *Link, s *Symbol) uint64 {
if SysArch.Family == sys.ARM64 {
- for _, shlib := range Ctxt.Shlibs {
+ for _, shlib := range ctxt.Shlibs {
if shlib.Path == s.File {
- return shlib.gcdata_addresses[s]
+ return shlib.gcdataAddresses[s]
}
}
return 0
}
- return decode_inuxi(s.P[2*int32(SysArch.PtrSize)+8+1*int32(SysArch.PtrSize):], SysArch.PtrSize)
+ return decodeInuxi(ctxt.Arch, s.P[2*int32(SysArch.PtrSize)+8+1*int32(SysArch.PtrSize):], SysArch.PtrSize)
}
-func decodetype_gcmask(s *LSym) []byte {
+func decodetypeGcmask(ctxt *Link, s *Symbol) []byte {
if s.Type == obj.SDYNIMPORT {
- addr := decodetype_gcprog_shlib(s)
- ptrdata := decodetype_ptrdata(s)
- sect := findShlibSection(s.File, addr)
+ addr := decodetypeGcprogShlib(ctxt, s)
+ ptrdata := decodetypePtrdata(ctxt.Arch, s)
+ sect := findShlibSection(ctxt, s.File, addr)
if sect != nil {
r := make([]byte, ptrdata/int64(SysArch.PtrSize))
sect.ReadAt(r, int64(addr-sect.Addr))
@@ -147,93 +147,93 @@ func decodetype_gcmask(s *LSym) []byte {
Exitf("cannot find gcmask for %s", s.Name)
return nil
}
- mask := decode_reloc_sym(s, 2*int32(SysArch.PtrSize)+8+1*int32(SysArch.PtrSize))
+ mask := decodeRelocSym(s, 2*int32(SysArch.PtrSize)+8+1*int32(SysArch.PtrSize))
return mask.P
}
// Type.ArrayType.elem and Type.SliceType.Elem
-func decodetype_arrayelem(s *LSym) *LSym {
- return decode_reloc_sym(s, int32(commonsize())) // 0x1c / 0x30
+func decodetypeArrayElem(s *Symbol) *Symbol {
+ return decodeRelocSym(s, int32(commonsize())) // 0x1c / 0x30
}
-func decodetype_arraylen(s *LSym) int64 {
- return int64(decode_inuxi(s.P[commonsize()+2*SysArch.PtrSize:], SysArch.PtrSize))
+func decodetypeArrayLen(arch *sys.Arch, s *Symbol) int64 {
+ return int64(decodeInuxi(arch, s.P[commonsize()+2*SysArch.PtrSize:], SysArch.PtrSize))
}
// Type.PtrType.elem
-func decodetype_ptrelem(s *LSym) *LSym {
- return decode_reloc_sym(s, int32(commonsize())) // 0x1c / 0x30
+func decodetypePtrElem(s *Symbol) *Symbol {
+ return decodeRelocSym(s, int32(commonsize())) // 0x1c / 0x30
}
// Type.MapType.key, elem
-func decodetype_mapkey(s *LSym) *LSym {
- return decode_reloc_sym(s, int32(commonsize())) // 0x1c / 0x30
+func decodetypeMapKey(s *Symbol) *Symbol {
+ return decodeRelocSym(s, int32(commonsize())) // 0x1c / 0x30
}
-func decodetype_mapvalue(s *LSym) *LSym {
- return decode_reloc_sym(s, int32(commonsize())+int32(SysArch.PtrSize)) // 0x20 / 0x38
+func decodetypeMapValue(s *Symbol) *Symbol {
+ return decodeRelocSym(s, int32(commonsize())+int32(SysArch.PtrSize)) // 0x20 / 0x38
}
// Type.ChanType.elem
-func decodetype_chanelem(s *LSym) *LSym {
- return decode_reloc_sym(s, int32(commonsize())) // 0x1c / 0x30
+func decodetypeChanElem(s *Symbol) *Symbol {
+ return decodeRelocSym(s, int32(commonsize())) // 0x1c / 0x30
}
// Type.FuncType.dotdotdot
-func decodetype_funcdotdotdot(s *LSym) bool {
- return uint16(decode_inuxi(s.P[commonsize()+2:], 2))&(1<<15) != 0
+func decodetypeFuncDotdotdot(arch *sys.Arch, s *Symbol) bool {
+ return uint16(decodeInuxi(arch, s.P[commonsize()+2:], 2))&(1<<15) != 0
}
// Type.FuncType.inCount
-func decodetype_funcincount(s *LSym) int {
- return int(decode_inuxi(s.P[commonsize():], 2))
+func decodetypeFuncInCount(arch *sys.Arch, s *Symbol) int {
+ return int(decodeInuxi(arch, s.P[commonsize():], 2))
}
-func decodetype_funcoutcount(s *LSym) int {
- return int(uint16(decode_inuxi(s.P[commonsize()+2:], 2)) & (1<<15 - 1))
+func decodetypeFuncOutCount(arch *sys.Arch, s *Symbol) int {
+ return int(uint16(decodeInuxi(arch, s.P[commonsize()+2:], 2)) & (1<<15 - 1))
}
-func decodetype_funcintype(s *LSym, i int) *LSym {
+func decodetypeFuncInType(s *Symbol, i int) *Symbol {
uadd := commonsize() + 4
if SysArch.PtrSize == 8 {
uadd += 4
}
- if decodetype_hasUncommon(s) {
+ if decodetypeHasUncommon(s) {
uadd += uncommonSize()
}
- return decode_reloc_sym(s, int32(uadd+i*SysArch.PtrSize))
+ return decodeRelocSym(s, int32(uadd+i*SysArch.PtrSize))
}
-func decodetype_funcouttype(s *LSym, i int) *LSym {
- return decodetype_funcintype(s, i+decodetype_funcincount(s))
+func decodetypeFuncOutType(arch *sys.Arch, s *Symbol, i int) *Symbol {
+ return decodetypeFuncInType(s, i+decodetypeFuncInCount(arch, s))
}
// Type.StructType.fields.Slice::length
-func decodetype_structfieldcount(s *LSym) int {
- return int(decode_inuxi(s.P[commonsize()+2*SysArch.PtrSize:], SysArch.IntSize))
+func decodetypeStructFieldCount(arch *sys.Arch, s *Symbol) int {
+ return int(decodeInuxi(arch, s.P[commonsize()+2*SysArch.PtrSize:], SysArch.IntSize))
}
-func decodetype_structfieldarrayoff(s *LSym, i int) int {
+func decodetypeStructFieldArrayOff(s *Symbol, i int) int {
off := commonsize() + 2*SysArch.PtrSize + 2*SysArch.IntSize
- if decodetype_hasUncommon(s) {
+ if decodetypeHasUncommon(s) {
off += uncommonSize()
}
off += i * structfieldSize()
return off
}
-// decodetype_str returns the contents of an rtype's str field (a nameOff).
-func decodetype_str(s *LSym) string {
- str := decodetype_name(s, 4*SysArch.PtrSize+8)
+// decodetypeStr returns the contents of an rtype's str field (a nameOff).
+func decodetypeStr(s *Symbol) string {
+ str := decodetypeName(s, 4*SysArch.PtrSize+8)
if s.P[2*SysArch.PtrSize+4]&tflagExtraStar != 0 {
return str[1:]
}
return str
}
-// decodetype_name decodes the name from a reflect.name.
-func decodetype_name(s *LSym, off int) string {
- r := decode_reloc(s, int32(off))
+// decodetypeName decodes the name from a reflect.name.
+func decodetypeName(s *Symbol, off int) string {
+ r := decodeReloc(s, int32(off))
if r == nil {
return ""
}
@@ -243,24 +243,24 @@ func decodetype_name(s *LSym, off int) string {
return string(data[3 : 3+namelen])
}
-func decodetype_structfieldname(s *LSym, i int) string {
- off := decodetype_structfieldarrayoff(s, i)
- return decodetype_name(s, off)
+func decodetypeStructFieldName(s *Symbol, i int) string {
+ off := decodetypeStructFieldArrayOff(s, i)
+ return decodetypeName(s, off)
}
-func decodetype_structfieldtype(s *LSym, i int) *LSym {
- off := decodetype_structfieldarrayoff(s, i)
- return decode_reloc_sym(s, int32(off+SysArch.PtrSize))
+func decodetypeStructFieldType(s *Symbol, i int) *Symbol {
+ off := decodetypeStructFieldArrayOff(s, i)
+ return decodeRelocSym(s, int32(off+SysArch.PtrSize))
}
-func decodetype_structfieldoffs(s *LSym, i int) int64 {
- off := decodetype_structfieldarrayoff(s, i)
- return int64(decode_inuxi(s.P[off+2*SysArch.PtrSize:], SysArch.IntSize))
+func decodetypeStructFieldOffs(arch *sys.Arch, s *Symbol, i int) int64 {
+ off := decodetypeStructFieldArrayOff(s, i)
+ return int64(decodeInuxi(arch, s.P[off+2*SysArch.PtrSize:], SysArch.IntSize))
}
// InterfaceType.methods.length
-func decodetype_ifacemethodcount(s *LSym) int64 {
- return int64(decode_inuxi(s.P[commonsize()+2*SysArch.PtrSize:], SysArch.IntSize))
+func decodetypeIfaceMethodCount(arch *sys.Arch, s *Symbol) int64 {
+ return int64(decodeInuxi(arch, s.P[commonsize()+2*SysArch.PtrSize:], SysArch.IntSize))
}
// methodsig is a fully qualified typed method signature, like
@@ -280,34 +280,34 @@ const (
kindMask = (1 << 5) - 1
)
-// decode_methodsig decodes an array of method signature information.
+// decodeMethodSig decodes an array of method signature information.
// Each element of the array is size bytes. The first 4 bytes is a
// nameOff for the method name, and the next 4 bytes is a typeOff for
// the function type.
//
// Conveniently this is the layout of both runtime.method and runtime.imethod.
-func decode_methodsig(s *LSym, off, size, count int) []methodsig {
+func decodeMethodSig(arch *sys.Arch, s *Symbol, off, size, count int) []methodsig {
var buf bytes.Buffer
var methods []methodsig
for i := 0; i < count; i++ {
- buf.WriteString(decodetype_name(s, off))
- mtypSym := decode_reloc_sym(s, int32(off+4))
+ buf.WriteString(decodetypeName(s, off))
+ mtypSym := decodeRelocSym(s, int32(off+4))
buf.WriteRune('(')
- inCount := decodetype_funcincount(mtypSym)
+ inCount := decodetypeFuncInCount(arch, mtypSym)
for i := 0; i < inCount; i++ {
if i > 0 {
buf.WriteString(", ")
}
- buf.WriteString(decodetype_funcintype(mtypSym, i).Name)
+ buf.WriteString(decodetypeFuncInType(mtypSym, i).Name)
}
buf.WriteString(") (")
- outCount := decodetype_funcoutcount(mtypSym)
+ outCount := decodetypeFuncOutCount(arch, mtypSym)
for i := 0; i < outCount; i++ {
if i > 0 {
buf.WriteString(", ")
}
- buf.WriteString(decodetype_funcouttype(mtypSym, i).Name)
+ buf.WriteString(decodetypeFuncOutType(arch, mtypSym, i).Name)
}
buf.WriteRune(')')
@@ -318,11 +318,11 @@ func decode_methodsig(s *LSym, off, size, count int) []methodsig {
return methods
}
-func decodetype_ifacemethods(s *LSym) []methodsig {
- if decodetype_kind(s)&kindMask != kindInterface {
+func decodeIfaceMethods(arch *sys.Arch, s *Symbol) []methodsig {
+ if decodetypeKind(s)&kindMask != kindInterface {
panic(fmt.Sprintf("symbol %q is not an interface", s.Name))
}
- r := decode_reloc(s, int32(commonsize()+SysArch.PtrSize))
+ r := decodeReloc(s, int32(commonsize()+SysArch.PtrSize))
if r == nil {
return nil
}
@@ -330,17 +330,17 @@ func decodetype_ifacemethods(s *LSym) []methodsig {
panic(fmt.Sprintf("imethod slice pointer in %q leads to a different symbol", s.Name))
}
off := int(r.Add) // array of reflect.imethod values
- numMethods := int(decodetype_ifacemethodcount(s))
+ numMethods := int(decodetypeIfaceMethodCount(arch, s))
sizeofIMethod := 4 + 4
- return decode_methodsig(s, off, sizeofIMethod, numMethods)
+ return decodeMethodSig(arch, s, off, sizeofIMethod, numMethods)
}
-func decodetype_methods(s *LSym) []methodsig {
- if !decodetype_hasUncommon(s) {
+func decodetypeMethods(arch *sys.Arch, s *Symbol) []methodsig {
+ if !decodetypeHasUncommon(s) {
panic(fmt.Sprintf("no methods on %q", s.Name))
}
off := commonsize() // reflect.rtype
- switch decodetype_kind(s) & kindMask {
+ switch decodetypeKind(s) & kindMask {
case kindStruct: // reflect.structType
off += 2*SysArch.PtrSize + 2*SysArch.IntSize
case kindPtr: // reflect.ptrType
@@ -361,9 +361,9 @@ func decodetype_methods(s *LSym) []methodsig {
// just Sizeof(rtype)
}
- mcount := int(decode_inuxi(s.P[off+4:], 2))
- moff := int(decode_inuxi(s.P[off+4+2+2:], 4))
+ mcount := int(decodeInuxi(arch, s.P[off+4:], 2))
+ moff := int(decodeInuxi(arch, s.P[off+4+2+2:], 4))
off += moff // offset to array of reflect.method values
const sizeofMethod = 4 * 4 // sizeof reflect.method in program
- return decode_methodsig(s, off, sizeofMethod, mcount)
+ return decodeMethodSig(arch, s, off, sizeofMethod, mcount)
}
diff --git a/src/cmd/link/internal/ld/dwarf.go b/src/cmd/link/internal/ld/dwarf.go
index fa7105f..61d3e4f 100644
--- a/src/cmd/link/internal/ld/dwarf.go
+++ b/src/cmd/link/internal/ld/dwarf.go
@@ -15,6 +15,7 @@
package ld
import (
+ "cmd/internal/dwarf"
"cmd/internal/obj"
"fmt"
"log"
@@ -22,505 +23,148 @@ import (
"strings"
)
-const infoprefix = "go.dwarf.info."
-
-/*
- * Offsets and sizes of the debug_* sections in the cout file.
- */
-var abbrevsym *LSym
-var arangessec *LSym
-var framesec *LSym
-var infosec *LSym
-var linesec *LSym
-
-var gdbscript string
-
-/*
- * Basic I/O
- */
-func addrput(s *LSym, addr int64) {
- switch SysArch.PtrSize {
- case 4:
- Adduint32(Ctxt, s, uint32(addr))
-
- case 8:
- Adduint64(Ctxt, s, uint64(addr))
- }
+type dwctxt struct {
+ linkctxt *Link
}
-func appendUleb128(b []byte, v uint64) []byte {
- for {
- c := uint8(v & 0x7f)
- v >>= 7
- if v != 0 {
- c |= 0x80
- }
- b = append(b, c)
- if c&0x80 == 0 {
- break
- }
- }
- return b
-}
-
-func appendSleb128(b []byte, v int64) []byte {
- for {
- c := uint8(v & 0x7f)
- s := uint8(v & 0x40)
- v >>= 7
- if (v != -1 || s == 0) && (v != 0 || s != 0) {
- c |= 0x80
- }
- b = append(b, c)
- if c&0x80 == 0 {
- break
- }
- }
- return b
+func (c dwctxt) PtrSize() int {
+ return SysArch.PtrSize
}
-
-var encbuf [10]byte
-
-func uleb128put(s *LSym, v int64) {
- b := appendUleb128(encbuf[:0], uint64(v))
- Addbytes(Ctxt, s, b)
+func (c dwctxt) AddInt(s dwarf.Sym, size int, i int64) {
+ ls := s.(*Symbol)
+ adduintxx(c.linkctxt, ls, uint64(i), size)
}
-
-func sleb128put(s *LSym, v int64) {
- b := appendSleb128(encbuf[:0], v)
- Addbytes(Ctxt, s, b)
+func (c dwctxt) AddBytes(s dwarf.Sym, b []byte) {
+ ls := s.(*Symbol)
+ Addbytes(ls, b)
}
-
-/*
- * Defining Abbrevs. This is hardcoded, and there will be
- * only a handful of them. The DWARF spec places no restriction on
- * the ordering of attributes in the Abbrevs and DIEs, and we will
- * always write them out in the order of declaration in the abbrev.
- */
-type DWAttrForm struct {
- attr uint16
- form uint8
+func (c dwctxt) AddString(s dwarf.Sym, v string) {
+ Addstring(s.(*Symbol), v)
}
-
-// Go-specific type attributes.
-const (
- DW_AT_go_kind = 0x2900
- DW_AT_go_key = 0x2901
- DW_AT_go_elem = 0x2902
-
- DW_AT_internal_location = 253 // params and locals; not emitted
-)
-
-// Index into the abbrevs table below.
-// Keep in sync with ispubname() and ispubtype() below.
-// ispubtype considers >= NULLTYPE public
-const (
- DW_ABRV_NULL = iota
- DW_ABRV_COMPUNIT
- DW_ABRV_FUNCTION
- DW_ABRV_VARIABLE
- DW_ABRV_AUTO
- DW_ABRV_PARAM
- DW_ABRV_STRUCTFIELD
- DW_ABRV_FUNCTYPEPARAM
- DW_ABRV_DOTDOTDOT
- DW_ABRV_ARRAYRANGE
- DW_ABRV_NULLTYPE
- DW_ABRV_BASETYPE
- DW_ABRV_ARRAYTYPE
- DW_ABRV_CHANTYPE
- DW_ABRV_FUNCTYPE
- DW_ABRV_IFACETYPE
- DW_ABRV_MAPTYPE
- DW_ABRV_PTRTYPE
- DW_ABRV_BARE_PTRTYPE // only for void*, no DW_AT_type attr to please gdb 6.
- DW_ABRV_SLICETYPE
- DW_ABRV_STRINGTYPE
- DW_ABRV_STRUCTTYPE
- DW_ABRV_TYPEDECL
- DW_NABRV
-)
-
-type DWAbbrev struct {
- tag uint8
- children uint8
- attr []DWAttrForm
+func (c dwctxt) SymValue(s dwarf.Sym) int64 {
+ return s.(*Symbol).Value
}
-var abbrevs = [DW_NABRV]DWAbbrev{
- /* The mandatory DW_ABRV_NULL entry. */
- {0, 0, []DWAttrForm{}},
-
- /* COMPUNIT */
- {
- DW_TAG_compile_unit,
- DW_CHILDREN_yes,
- []DWAttrForm{
- {DW_AT_name, DW_FORM_string},
- {DW_AT_language, DW_FORM_data1},
- {DW_AT_low_pc, DW_FORM_addr},
- {DW_AT_high_pc, DW_FORM_addr},
- {DW_AT_stmt_list, DW_FORM_data4},
- {DW_AT_comp_dir, DW_FORM_string},
- },
- },
-
- /* FUNCTION */
- {
- DW_TAG_subprogram,
- DW_CHILDREN_yes,
- []DWAttrForm{
- {DW_AT_name, DW_FORM_string},
- {DW_AT_low_pc, DW_FORM_addr},
- {DW_AT_high_pc, DW_FORM_addr},
- {DW_AT_external, DW_FORM_flag},
- },
- },
-
- /* VARIABLE */
- {
- DW_TAG_variable,
- DW_CHILDREN_no,
- []DWAttrForm{
- {DW_AT_name, DW_FORM_string},
- {DW_AT_location, DW_FORM_block1},
- {DW_AT_type, DW_FORM_ref_addr},
- {DW_AT_external, DW_FORM_flag},
- },
- },
-
- /* AUTO */
- {
- DW_TAG_variable,
- DW_CHILDREN_no,
- []DWAttrForm{
- {DW_AT_name, DW_FORM_string},
- {DW_AT_location, DW_FORM_block1},
- {DW_AT_type, DW_FORM_ref_addr},
- },
- },
-
- /* PARAM */
- {
- DW_TAG_formal_parameter,
- DW_CHILDREN_no,
- []DWAttrForm{
- {DW_AT_name, DW_FORM_string},
- {DW_AT_location, DW_FORM_block1},
- {DW_AT_type, DW_FORM_ref_addr},
- },
- },
-
- /* STRUCTFIELD */
- {
- DW_TAG_member,
- DW_CHILDREN_no,
- []DWAttrForm{
- {DW_AT_name, DW_FORM_string},
- {DW_AT_data_member_location, DW_FORM_block1},
- {DW_AT_type, DW_FORM_ref_addr},
- },
- },
-
- /* FUNCTYPEPARAM */
- {
- DW_TAG_formal_parameter,
- DW_CHILDREN_no,
-
- // No name!
- []DWAttrForm{
- {DW_AT_type, DW_FORM_ref_addr},
- },
- },
-
- /* DOTDOTDOT */
- {
- DW_TAG_unspecified_parameters,
- DW_CHILDREN_no,
- []DWAttrForm{},
- },
-
- /* ARRAYRANGE */
- {
- DW_TAG_subrange_type,
- DW_CHILDREN_no,
-
- // No name!
- []DWAttrForm{
- {DW_AT_type, DW_FORM_ref_addr},
- {DW_AT_count, DW_FORM_udata},
- },
- },
-
- // Below here are the types considered public by ispubtype
- /* NULLTYPE */
- {
- DW_TAG_unspecified_type,
- DW_CHILDREN_no,
- []DWAttrForm{
- {DW_AT_name, DW_FORM_string},
- },
- },
-
- /* BASETYPE */
- {
- DW_TAG_base_type,
- DW_CHILDREN_no,
- []DWAttrForm{
- {DW_AT_name, DW_FORM_string},
- {DW_AT_encoding, DW_FORM_data1},
- {DW_AT_byte_size, DW_FORM_data1},
- {DW_AT_go_kind, DW_FORM_data1},
- },
- },
-
- /* ARRAYTYPE */
- // child is subrange with upper bound
- {
- DW_TAG_array_type,
- DW_CHILDREN_yes,
- []DWAttrForm{
- {DW_AT_name, DW_FORM_string},
- {DW_AT_type, DW_FORM_ref_addr},
- {DW_AT_byte_size, DW_FORM_udata},
- {DW_AT_go_kind, DW_FORM_data1},
- },
- },
-
- /* CHANTYPE */
- {
- DW_TAG_typedef,
- DW_CHILDREN_no,
- []DWAttrForm{
- {DW_AT_name, DW_FORM_string},
- {DW_AT_type, DW_FORM_ref_addr},
- {DW_AT_go_kind, DW_FORM_data1},
- {DW_AT_go_elem, DW_FORM_ref_addr},
- },
- },
-
- /* FUNCTYPE */
- {
- DW_TAG_subroutine_type,
- DW_CHILDREN_yes,
- []DWAttrForm{
- {DW_AT_name, DW_FORM_string},
- // {DW_AT_type, DW_FORM_ref_addr},
- {DW_AT_go_kind, DW_FORM_data1},
- },
- },
-
- /* IFACETYPE */
- {
- DW_TAG_typedef,
- DW_CHILDREN_yes,
- []DWAttrForm{
- {DW_AT_name, DW_FORM_string},
- {DW_AT_type, DW_FORM_ref_addr},
- {DW_AT_go_kind, DW_FORM_data1},
- },
- },
-
- /* MAPTYPE */
- {
- DW_TAG_typedef,
- DW_CHILDREN_no,
- []DWAttrForm{
- {DW_AT_name, DW_FORM_string},
- {DW_AT_type, DW_FORM_ref_addr},
- {DW_AT_go_kind, DW_FORM_data1},
- {DW_AT_go_key, DW_FORM_ref_addr},
- {DW_AT_go_elem, DW_FORM_ref_addr},
- },
- },
-
- /* PTRTYPE */
- {
- DW_TAG_pointer_type,
- DW_CHILDREN_no,
- []DWAttrForm{
- {DW_AT_name, DW_FORM_string},
- {DW_AT_type, DW_FORM_ref_addr},
- {DW_AT_go_kind, DW_FORM_data1},
- },
- },
-
- /* BARE_PTRTYPE */
- {
- DW_TAG_pointer_type,
- DW_CHILDREN_no,
- []DWAttrForm{
- {DW_AT_name, DW_FORM_string},
- },
- },
-
- /* SLICETYPE */
- {
- DW_TAG_structure_type,
- DW_CHILDREN_yes,
- []DWAttrForm{
- {DW_AT_name, DW_FORM_string},
- {DW_AT_byte_size, DW_FORM_udata},
- {DW_AT_go_kind, DW_FORM_data1},
- {DW_AT_go_elem, DW_FORM_ref_addr},
- },
- },
-
- /* STRINGTYPE */
- {
- DW_TAG_structure_type,
- DW_CHILDREN_yes,
- []DWAttrForm{
- {DW_AT_name, DW_FORM_string},
- {DW_AT_byte_size, DW_FORM_udata},
- {DW_AT_go_kind, DW_FORM_data1},
- },
- },
-
- /* STRUCTTYPE */
- {
- DW_TAG_structure_type,
- DW_CHILDREN_yes,
- []DWAttrForm{
- {DW_AT_name, DW_FORM_string},
- {DW_AT_byte_size, DW_FORM_udata},
- {DW_AT_go_kind, DW_FORM_data1},
- },
- },
-
- /* TYPEDECL */
- {
- DW_TAG_typedef,
- DW_CHILDREN_no,
- []DWAttrForm{
- {DW_AT_name, DW_FORM_string},
- {DW_AT_type, DW_FORM_ref_addr},
- },
- },
+func (c dwctxt) AddAddress(s dwarf.Sym, data interface{}, value int64) {
+ if value != 0 {
+ value -= (data.(*Symbol)).Value
+ }
+ Addaddrplus(c.linkctxt, s.(*Symbol), data.(*Symbol), value)
}
-var dwarfp *LSym
-
-func writeabbrev() *LSym {
- s := Linklookup(Ctxt, ".debug_abbrev", 0)
- s.Type = obj.SDWARFSECT
- abbrevsym = s
-
- for i := 1; i < DW_NABRV; i++ {
- // See section 7.5.3
- uleb128put(s, int64(i))
-
- uleb128put(s, int64(abbrevs[i].tag))
- Adduint8(Ctxt, s, abbrevs[i].children)
- for _, f := range abbrevs[i].attr {
- uleb128put(s, int64(f.attr))
- uleb128put(s, int64(f.form))
- }
- uleb128put(s, 0)
- uleb128put(s, 0)
+func (c dwctxt) AddSectionOffset(s dwarf.Sym, size int, t interface{}, ofs int64) {
+ ls := s.(*Symbol)
+ switch size {
+ default:
+ Errorf(ls, "invalid size %d in adddwarfref\n", size)
+ fallthrough
+ case SysArch.PtrSize:
+ Addaddr(c.linkctxt, ls, t.(*Symbol))
+ case 4:
+ addaddrplus4(c.linkctxt, ls, t.(*Symbol), 0)
}
-
- Adduint8(Ctxt, s, 0)
- return s
+ r := &ls.R[len(ls.R)-1]
+ r.Type = obj.R_DWARFREF
+ r.Add = ofs
}
/*
- * Debugging Information Entries and their attributes.
+ * Offsets and sizes of the debug_* sections in the cout file.
*/
+var abbrevsym *Symbol
+var arangessec *Symbol
+var framesec *Symbol
+var infosec *Symbol
+var linesec *Symbol
-// For DW_CLS_string and _block, value should contain the length, and
-// data the data, for _reference, value is 0 and data is a DWDie* to
-// the referenced instance, for all others, value is the whole thing
-// and data is null.
-
-type DWAttr struct {
- link *DWAttr
- atr uint16 // DW_AT_
- cls uint8 // DW_CLS_
- value int64
- data interface{}
-}
+var gdbscript string
+
+var dwarfp []*Symbol
-type DWDie struct {
- abbrev int
- link *DWDie
- child *DWDie
- attr *DWAttr
- sym *LSym
+func writeabbrev(ctxt *Link, syms []*Symbol) []*Symbol {
+ s := ctxt.Syms.Lookup(".debug_abbrev", 0)
+ s.Type = obj.SDWARFSECT
+ abbrevsym = s
+ Addbytes(s, dwarf.GetAbbrev())
+ return append(syms, s)
}
/*
* Root DIEs for compilation units, types and global variables.
*/
-var dwroot DWDie
+var dwroot dwarf.DWDie
-var dwtypes DWDie
+var dwtypes dwarf.DWDie
-var dwglobals DWDie
+var dwglobals dwarf.DWDie
-func newattr(die *DWDie, attr uint16, cls int, value int64, data interface{}) *DWAttr {
- a := new(DWAttr)
- a.link = die.attr
- die.attr = a
- a.atr = attr
- a.cls = uint8(cls)
- a.value = value
- a.data = data
+func newattr(die *dwarf.DWDie, attr uint16, cls int, value int64, data interface{}) *dwarf.DWAttr {
+ a := new(dwarf.DWAttr)
+ a.Link = die.Attr
+ die.Attr = a
+ a.Atr = attr
+ a.Cls = uint8(cls)
+ a.Value = value
+ a.Data = data
return a
}
// Each DIE (except the root ones) has at least 1 attribute: its
// name. getattr moves the desired one to the front so
// frequently searched ones are found faster.
-func getattr(die *DWDie, attr uint16) *DWAttr {
- if die.attr.atr == attr {
- return die.attr
+func getattr(die *dwarf.DWDie, attr uint16) *dwarf.DWAttr {
+ if die.Attr.Atr == attr {
+ return die.Attr
}
- a := die.attr
- b := a.link
+ a := die.Attr
+ b := a.Link
for b != nil {
- if b.atr == attr {
- a.link = b.link
- b.link = die.attr
- die.attr = b
+ if b.Atr == attr {
+ a.Link = b.Link
+ b.Link = die.Attr
+ die.Attr = b
return b
}
a = b
- b = b.link
+ b = b.Link
}
return nil
}
-// Every DIE has at least a DW_AT_name attribute (but it will only be
+// Every DIE has at least a AT_name attribute (but it will only be
// written out if it is listed in the abbrev).
-func newdie(parent *DWDie, abbrev int, name string, version int) *DWDie {
- die := new(DWDie)
- die.abbrev = abbrev
- die.link = parent.child
- parent.child = die
-
- newattr(die, DW_AT_name, DW_CLS_STRING, int64(len(name)), name)
-
- if name != "" && (abbrev <= DW_ABRV_VARIABLE || abbrev >= DW_ABRV_NULLTYPE) {
- if abbrev != DW_ABRV_VARIABLE || version == 0 {
- die.sym = Linklookup(Ctxt, infoprefix+name, version)
- die.sym.Attr |= AttrHidden
- die.sym.Type = obj.SDWARFINFO
+func newdie(ctxt *Link, parent *dwarf.DWDie, abbrev int, name string, version int) *dwarf.DWDie {
+ die := new(dwarf.DWDie)
+ die.Abbrev = abbrev
+ die.Link = parent.Child
+ parent.Child = die
+
+ newattr(die, dwarf.DW_AT_name, dwarf.DW_CLS_STRING, int64(len(name)), name)
+
+ 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
+ die.Sym = sym
}
}
return die
}
-func walktypedef(die *DWDie) *DWDie {
+func walktypedef(die *dwarf.DWDie) *dwarf.DWDie {
+ if die == nil {
+ return nil
+ }
// Resolve typedef if present.
- if die.abbrev == DW_ABRV_TYPEDECL {
- for attr := die.attr; attr != nil; attr = attr.link {
- if attr.atr == DW_AT_type && attr.cls == DW_CLS_REFERENCE && attr.data != nil {
- return attr.data.(*DWDie)
+ if die.Abbrev == dwarf.DW_ABRV_TYPEDECL {
+ for attr := die.Attr; attr != nil; attr = attr.Link {
+ if attr.Atr == dwarf.DW_AT_type && attr.Cls == dwarf.DW_CLS_REFERENCE && attr.Data != nil {
+ return attr.Data.(*dwarf.DWDie)
}
}
}
@@ -528,8 +172,8 @@ func walktypedef(die *DWDie) *DWDie {
return die
}
-func walksymtypedef(s *LSym) *LSym {
- if t := Linkrlookup(Ctxt, s.Name+"..def", int(s.Version)); t != nil {
+func walksymtypedef(ctxt *Link, s *Symbol) *Symbol {
+ if t := ctxt.Syms.ROLookup(s.Name+"..def", int(s.Version)); t != nil {
return t
}
return s
@@ -537,11 +181,11 @@ func walksymtypedef(s *LSym) *LSym {
// Find child by AT_name using hashtable if available or linear scan
// if not.
-func findchild(die *DWDie, name string) *DWDie {
- var prev *DWDie
+func findchild(die *dwarf.DWDie, name string) *dwarf.DWDie {
+ var prev *dwarf.DWDie
for ; die != prev; prev, die = die, walktypedef(die) {
- for a := die.child; a != nil; a = a.link {
- if name == getattr(a, DW_AT_name).data {
+ for a := die.Child; a != nil; a = a.Link {
+ if name == getattr(a, dwarf.DW_AT_name).Data {
return a
}
}
@@ -551,29 +195,32 @@ func findchild(die *DWDie, name string) *DWDie {
}
// Used to avoid string allocation when looking up dwarf symbols
-var prefixBuf = []byte(infoprefix)
+var prefixBuf = []byte(dwarf.InfoPrefix)
-func find(name string) *LSym {
+func find(ctxt *Link, name string) *Symbol {
n := append(prefixBuf, name...)
// The string allocation below is optimized away because it is only used in a map lookup.
- s := Linkrlookup(Ctxt, string(n), 0)
- prefixBuf = n[:len(infoprefix)]
- return s
+ s := ctxt.Syms.ROLookup(string(n), 0)
+ prefixBuf = n[:len(dwarf.InfoPrefix)]
+ if s != nil && s.Type == obj.SDWARFINFO {
+ return s
+ }
+ return nil
}
-func mustFind(name string) *LSym {
- r := find(name)
+func mustFind(ctxt *Link, name string) *Symbol {
+ r := find(ctxt, name)
if r == nil {
Exitf("dwarf find: cannot find %s", name)
}
return r
}
-func adddwarfref(ctxt *Link, s *LSym, t *LSym, size int) int64 {
+func adddwarfref(ctxt *Link, s *Symbol, t *Symbol, size int) int64 {
var result int64
switch size {
default:
- Diag("invalid size %d in adddwarfref\n", size)
+ Errorf(s, "invalid size %d in adddwarfref\n", size)
fallthrough
case SysArch.PtrSize:
result = Addaddr(ctxt, s, t)
@@ -585,182 +232,54 @@ func adddwarfref(ctxt *Link, s *LSym, t *LSym, size int) int64 {
return result
}
-func newrefattr(die *DWDie, attr uint16, ref *LSym) *DWAttr {
+func newrefattr(die *dwarf.DWDie, attr uint16, ref *Symbol) *dwarf.DWAttr {
if ref == nil {
return nil
}
- return newattr(die, attr, DW_CLS_REFERENCE, 0, ref)
+ return newattr(die, attr, dwarf.DW_CLS_REFERENCE, 0, ref)
}
-func putattr(s *LSym, abbrev int, form int, cls int, value int64, data interface{}) {
- switch form {
- case DW_FORM_addr: // address
- if Linkmode == LinkExternal {
- value -= (data.(*LSym)).Value
- Addaddrplus(Ctxt, s, data.(*LSym), value)
- break
- }
-
- addrput(s, value)
-
- case DW_FORM_block1: // block
- if cls == DW_CLS_ADDRESS {
- Adduint8(Ctxt, s, uint8(1+SysArch.PtrSize))
- Adduint8(Ctxt, s, DW_OP_addr)
- Addaddr(Ctxt, s, data.(*LSym))
- break
- }
-
- value &= 0xff
- Adduint8(Ctxt, s, uint8(value))
- p := data.([]byte)
- for i := 0; int64(i) < value; i++ {
- Adduint8(Ctxt, s, p[i])
- }
-
- case DW_FORM_block2: // block
- value &= 0xffff
-
- Adduint16(Ctxt, s, uint16(value))
- p := data.([]byte)
- for i := 0; int64(i) < value; i++ {
- Adduint8(Ctxt, s, p[i])
- }
-
- case DW_FORM_block4: // block
- value &= 0xffffffff
-
- Adduint32(Ctxt, s, uint32(value))
- p := data.([]byte)
- for i := 0; int64(i) < value; i++ {
- Adduint8(Ctxt, s, p[i])
- }
-
- case DW_FORM_block: // block
- uleb128put(s, value)
-
- p := data.([]byte)
- for i := 0; int64(i) < value; i++ {
- Adduint8(Ctxt, s, p[i])
- }
-
- case DW_FORM_data1: // constant
- Adduint8(Ctxt, s, uint8(value))
-
- case DW_FORM_data2: // constant
- Adduint16(Ctxt, s, uint16(value))
-
- case DW_FORM_data4: // constant, {line,loclist,mac,rangelist}ptr
- if Linkmode == LinkExternal && cls == DW_CLS_PTR {
- adddwarfref(Ctxt, s, linesec, 4)
- break
- }
-
- Adduint32(Ctxt, s, uint32(value))
-
- case DW_FORM_data8: // constant, {line,loclist,mac,rangelist}ptr
- Adduint64(Ctxt, s, uint64(value))
-
- case DW_FORM_sdata: // constant
- sleb128put(s, value)
-
- case DW_FORM_udata: // constant
- uleb128put(s, value)
-
- case DW_FORM_string: // string
- str := data.(string)
- Addstring(s, str)
- for i := int64(len(str)); i < value; i++ {
- Adduint8(Ctxt, s, 0)
- }
-
- case DW_FORM_flag: // flag
- if value != 0 {
- Adduint8(Ctxt, s, 1)
- } else {
- Adduint8(Ctxt, s, 0)
- }
-
- // In DWARF 2 (which is what we claim to generate),
- // the ref_addr is the same size as a normal address.
- // In DWARF 3 it is always 32 bits, unless emitting a large
- // (> 4 GB of debug info aka "64-bit") unit, which we don't implement.
- case DW_FORM_ref_addr: // reference to a DIE in the .info section
- if data == nil {
- Diag("dwarf: null reference in %d", abbrev)
- if SysArch.PtrSize == 8 {
- Adduint64(Ctxt, s, 0) // invalid dwarf, gdb will complain.
- } else {
- Adduint32(Ctxt, s, 0) // invalid dwarf, gdb will complain.
- }
- } else {
- dsym := data.(*LSym)
- adddwarfref(Ctxt, s, dsym, SysArch.PtrSize)
- }
-
- case DW_FORM_ref1, // reference within the compilation unit
- DW_FORM_ref2, // reference
- DW_FORM_ref4, // reference
- DW_FORM_ref8, // reference
- DW_FORM_ref_udata, // reference
-
- DW_FORM_strp, // string
- DW_FORM_indirect: // (see Section 7.5.3)
- fallthrough
- default:
- Exitf("dwarf: unsupported attribute form %d / class %d", form, cls)
+func putdies(linkctxt *Link, ctxt dwarf.Context, syms []*Symbol, die *dwarf.DWDie) []*Symbol {
+ for ; die != nil; die = die.Link {
+ syms = putdie(linkctxt, ctxt, syms, die)
}
-}
-
-// Note that we can (and do) add arbitrary attributes to a DIE, but
-// only the ones actually listed in the Abbrev will be written out.
-func putattrs(s *LSym, abbrev int, attr *DWAttr) {
-Outer:
- for _, f := range abbrevs[abbrev].attr {
- for ap := attr; ap != nil; ap = ap.link {
- if ap.atr == f.attr {
- putattr(s, abbrev, int(f.form), int(ap.cls), ap.value, ap.data)
- continue Outer
- }
- }
+ Adduint8(linkctxt, syms[len(syms)-1], 0)
- putattr(s, abbrev, int(f.form), 0, 0, nil)
- }
+ return syms
}
-func putdies(prev *LSym, die *DWDie) *LSym {
- for ; die != nil; die = die.link {
- prev = putdie(prev, die)
+func dtolsym(s dwarf.Sym) *Symbol {
+ if s == nil {
+ return nil
}
- Adduint8(Ctxt, prev, 0)
- return prev
+ return s.(*Symbol)
}
-func putdie(prev *LSym, die *DWDie) *LSym {
- s := die.sym
+func putdie(linkctxt *Link, ctxt dwarf.Context, syms []*Symbol, die *dwarf.DWDie) []*Symbol {
+ s := dtolsym(die.Sym)
if s == nil {
- s = prev
+ s = syms[len(syms)-1]
} else {
if s.Attr.OnList() {
log.Fatalf("symbol %s listed multiple times", s.Name)
}
s.Attr |= AttrOnList
- prev.Next = s
+ syms = append(syms, s)
}
- uleb128put(s, int64(die.abbrev))
- putattrs(s, die.abbrev, die.attr)
- if abbrevs[die.abbrev].children != 0 {
- return putdies(s, die.child)
+ dwarf.Uleb128put(ctxt, s, int64(die.Abbrev))
+ dwarf.PutAttrs(ctxt, s, die.Abbrev, die.Attr)
+ if dwarf.HasChildren(die) {
+ return putdies(linkctxt, ctxt, syms, die.Child)
}
- return s
+ return syms
}
-func reverselist(list **DWDie) {
+func reverselist(list **dwarf.DWDie) {
curr := *list
- var prev *DWDie
+ var prev *dwarf.DWDie
for curr != nil {
- var next *DWDie = curr.link
- curr.link = prev
+ var next *dwarf.DWDie = curr.Link
+ curr.Link = prev
prev = curr
curr = next
}
@@ -768,32 +287,32 @@ func reverselist(list **DWDie) {
*list = prev
}
-func reversetree(list **DWDie) {
+func reversetree(list **dwarf.DWDie) {
reverselist(list)
- for die := *list; die != nil; die = die.link {
- if abbrevs[die.abbrev].children != 0 {
- reversetree(&die.child)
+ for die := *list; die != nil; die = die.Link {
+ if dwarf.HasChildren(die) {
+ reversetree(&die.Child)
}
}
}
-func newmemberoffsetattr(die *DWDie, offs int32) {
+func newmemberoffsetattr(die *dwarf.DWDie, offs int32) {
var block [20]byte
- b := append(block[:0], DW_OP_plus_uconst)
- b = appendUleb128(b, uint64(offs))
- newattr(die, DW_AT_data_member_location, DW_CLS_BLOCK, int64(len(b)), b)
+ b := append(block[:0], dwarf.DW_OP_plus_uconst)
+ b = dwarf.AppendUleb128(b, uint64(offs))
+ newattr(die, dwarf.DW_AT_data_member_location, dwarf.DW_CLS_BLOCK, int64(len(b)), b)
}
-// GDB doesn't like DW_FORM_addr for DW_AT_location, so emit a
+// GDB doesn't like FORM_addr for AT_location, so emit a
// location expression that evals to a const.
-func newabslocexprattr(die *DWDie, addr int64, sym *LSym) {
- newattr(die, DW_AT_location, DW_CLS_ADDRESS, addr, sym)
+func newabslocexprattr(die *dwarf.DWDie, addr int64, sym *Symbol) {
+ newattr(die, dwarf.DW_AT_location, dwarf.DW_CLS_ADDRESS, addr, sym)
// below
}
// Lookup predefined types
-func lookup_or_diag(n string) *LSym {
- s := Linkrlookup(Ctxt, n, 0)
+func lookupOrDiag(ctxt *Link, n string) *Symbol {
+ s := ctxt.Syms.ROLookup(n, 0)
if s == nil || s.Size == 0 {
Exitf("dwarf: missing type: %s", n)
}
@@ -801,7 +320,7 @@ func lookup_or_diag(n string) *LSym {
return s
}
-func dotypedef(parent *DWDie, name string, def *DWDie) {
+func dotypedef(ctxt *Link, parent *dwarf.DWDie, name string, def *dwarf.DWDie) {
// Only emit typedefs for real names.
if strings.HasPrefix(name, "map[") {
return
@@ -816,64 +335,65 @@ func dotypedef(parent *DWDie, name string, def *DWDie) {
return
}
if def == nil {
- Diag("dwarf: bad def in dotypedef")
+ Errorf(nil, "dwarf: bad def in dotypedef")
}
- def.sym = Linklookup(Ctxt, def.sym.Name+"..def", 0)
- def.sym.Attr |= AttrHidden
- def.sym.Type = obj.SDWARFINFO
+ sym := ctxt.Syms.Lookup(dtolsym(def.Sym).Name+"..def", 0)
+ sym.Attr |= AttrHidden
+ sym.Type = obj.SDWARFINFO
+ def.Sym = sym
// The typedef entry must be created after the def,
// so that future lookups will find the typedef instead
// of the real definition. This hooks the typedef into any
// circular definition loops, so that gdb can understand them.
- die := newdie(parent, DW_ABRV_TYPEDECL, name, 0)
+ die := newdie(ctxt, parent, dwarf.DW_ABRV_TYPEDECL, name, 0)
- newrefattr(die, DW_AT_type, def.sym)
+ newrefattr(die, dwarf.DW_AT_type, sym)
}
// Define gotype, for composite ones recurse into constituents.
-func defgotype(gotype *LSym) *LSym {
+func defgotype(ctxt *Link, gotype *Symbol) *Symbol {
if gotype == nil {
- return mustFind("<unspecified>")
+ return mustFind(ctxt, "<unspecified>")
}
if !strings.HasPrefix(gotype.Name, "type.") {
- Diag("dwarf: type name doesn't start with \"type.\": %s", gotype.Name)
- return mustFind("<unspecified>")
+ Errorf(gotype, "dwarf: type name doesn't start with \"type.\"")
+ return mustFind(ctxt, "<unspecified>")
}
name := gotype.Name[5:] // could also decode from Type.string
- sdie := find(name)
+ sdie := find(ctxt, name)
if sdie != nil {
return sdie
}
- return newtype(gotype).sym
+ return newtype(ctxt, gotype).Sym.(*Symbol)
}
-func newtype(gotype *LSym) *DWDie {
+func newtype(ctxt *Link, gotype *Symbol) *dwarf.DWDie {
name := gotype.Name[5:] // could also decode from Type.string
- kind := decodetype_kind(gotype)
- bytesize := decodetype_size(gotype)
+ kind := decodetypeKind(gotype)
+ bytesize := decodetypeSize(ctxt.Arch, gotype)
- var die *DWDie
+ var die *dwarf.DWDie
switch kind {
case obj.KindBool:
- die = newdie(&dwtypes, DW_ABRV_BASETYPE, name, 0)
- newattr(die, DW_AT_encoding, DW_CLS_CONSTANT, DW_ATE_boolean, 0)
- newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0)
+ 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:
- die = newdie(&dwtypes, DW_ABRV_BASETYPE, name, 0)
- newattr(die, DW_AT_encoding, DW_CLS_CONSTANT, DW_ATE_signed, 0)
- newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0)
+ 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,
@@ -881,137 +401,137 @@ func newtype(gotype *LSym) *DWDie {
obj.KindUint32,
obj.KindUint64,
obj.KindUintptr:
- die = newdie(&dwtypes, DW_ABRV_BASETYPE, name, 0)
- newattr(die, DW_AT_encoding, DW_CLS_CONSTANT, DW_ATE_unsigned, 0)
- newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0)
+ 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:
- die = newdie(&dwtypes, DW_ABRV_BASETYPE, name, 0)
- newattr(die, DW_AT_encoding, DW_CLS_CONSTANT, DW_ATE_float, 0)
- newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0)
+ 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:
- die = newdie(&dwtypes, DW_ABRV_BASETYPE, name, 0)
- newattr(die, DW_AT_encoding, DW_CLS_CONSTANT, DW_ATE_complex_float, 0)
- newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0)
+ 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:
- die = newdie(&dwtypes, DW_ABRV_ARRAYTYPE, name, 0)
- dotypedef(&dwtypes, name, die)
- newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0)
- s := decodetype_arrayelem(gotype)
- newrefattr(die, DW_AT_type, defgotype(s))
- fld := newdie(die, DW_ABRV_ARRAYRANGE, "range", 0)
+ 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)
+ s := decodetypeArrayElem(gotype)
+ newrefattr(die, dwarf.DW_AT_type, defgotype(ctxt, s))
+ fld := newdie(ctxt, die, dwarf.DW_ABRV_ARRAYRANGE, "range", 0)
// use actual length not upper bound; correct for 0-length arrays.
- newattr(fld, DW_AT_count, DW_CLS_CONSTANT, decodetype_arraylen(gotype), 0)
+ newattr(fld, dwarf.DW_AT_count, dwarf.DW_CLS_CONSTANT, decodetypeArrayLen(ctxt.Arch, gotype), 0)
- newrefattr(fld, DW_AT_type, mustFind("uintptr"))
+ newrefattr(fld, dwarf.DW_AT_type, mustFind(ctxt, "uintptr"))
case obj.KindChan:
- die = newdie(&dwtypes, DW_ABRV_CHANTYPE, name, 0)
- newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0)
- s := decodetype_chanelem(gotype)
- newrefattr(die, DW_AT_go_elem, defgotype(s))
+ 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)
+ newrefattr(die, dwarf.DW_AT_go_elem, defgotype(ctxt, s))
// Save elem type for synthesizechantypes. We could synthesize here
// but that would change the order of DIEs we output.
- newrefattr(die, DW_AT_type, s)
+ newrefattr(die, dwarf.DW_AT_type, s)
case obj.KindFunc:
- die = newdie(&dwtypes, DW_ABRV_FUNCTYPE, name, 0)
- dotypedef(&dwtypes, name, die)
- newrefattr(die, DW_AT_type, mustFind("void"))
- nfields := decodetype_funcincount(gotype)
- var fld *DWDie
- var s *LSym
+ die = newdie(ctxt, &dwtypes, dwarf.DW_ABRV_FUNCTYPE, name, 0)
+ dotypedef(ctxt, &dwtypes, name, die)
+ newrefattr(die, dwarf.DW_AT_type, mustFind(ctxt, "void"))
+ nfields := decodetypeFuncInCount(ctxt.Arch, gotype)
+ var fld *dwarf.DWDie
+ var s *Symbol
for i := 0; i < nfields; i++ {
- s = decodetype_funcintype(gotype, i)
- fld = newdie(die, DW_ABRV_FUNCTYPEPARAM, s.Name[5:], 0)
- newrefattr(fld, DW_AT_type, defgotype(s))
+ s = decodetypeFuncInType(gotype, i)
+ fld = newdie(ctxt, die, dwarf.DW_ABRV_FUNCTYPEPARAM, s.Name[5:], 0)
+ newrefattr(fld, dwarf.DW_AT_type, defgotype(ctxt, s))
}
- if decodetype_funcdotdotdot(gotype) {
- newdie(die, DW_ABRV_DOTDOTDOT, "...", 0)
+ if decodetypeFuncDotdotdot(ctxt.Arch, gotype) {
+ newdie(ctxt, die, dwarf.DW_ABRV_DOTDOTDOT, "...", 0)
}
- nfields = decodetype_funcoutcount(gotype)
+ nfields = decodetypeFuncOutCount(ctxt.Arch, gotype)
for i := 0; i < nfields; i++ {
- s = decodetype_funcouttype(gotype, i)
- fld = newdie(die, DW_ABRV_FUNCTYPEPARAM, s.Name[5:], 0)
- newrefattr(fld, DW_AT_type, defptrto(defgotype(s)))
+ s = decodetypeFuncOutType(ctxt.Arch, gotype, i)
+ fld = newdie(ctxt, die, dwarf.DW_ABRV_FUNCTYPEPARAM, s.Name[5:], 0)
+ newrefattr(fld, dwarf.DW_AT_type, defptrto(ctxt, defgotype(ctxt, s)))
}
case obj.KindInterface:
- die = newdie(&dwtypes, DW_ABRV_IFACETYPE, name, 0)
- dotypedef(&dwtypes, name, die)
- newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0)
- nfields := int(decodetype_ifacemethodcount(gotype))
- var s *LSym
+ 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)
+ nfields := int(decodetypeIfaceMethodCount(ctxt.Arch, gotype))
+ var s *Symbol
if nfields == 0 {
- s = lookup_or_diag("type.runtime.eface")
+ s = lookupOrDiag(ctxt, "type.runtime.eface")
} else {
- s = lookup_or_diag("type.runtime.iface")
+ s = lookupOrDiag(ctxt, "type.runtime.iface")
}
- newrefattr(die, DW_AT_type, defgotype(s))
+ newrefattr(die, dwarf.DW_AT_type, defgotype(ctxt, s))
case obj.KindMap:
- die = newdie(&dwtypes, DW_ABRV_MAPTYPE, name, 0)
- s := decodetype_mapkey(gotype)
- newrefattr(die, DW_AT_go_key, defgotype(s))
- s = decodetype_mapvalue(gotype)
- newrefattr(die, DW_AT_go_elem, defgotype(s))
+ die = newdie(ctxt, &dwtypes, dwarf.DW_ABRV_MAPTYPE, name, 0)
+ s := decodetypeMapKey(gotype)
+ newrefattr(die, dwarf.DW_AT_go_key, defgotype(ctxt, s))
+ s = decodetypeMapValue(gotype)
+ newrefattr(die, dwarf.DW_AT_go_elem, defgotype(ctxt, s))
// Save gotype for use in synthesizemaptypes. We could synthesize here,
// but that would change the order of the DIEs.
- newrefattr(die, DW_AT_type, gotype)
+ newrefattr(die, dwarf.DW_AT_type, gotype)
case obj.KindPtr:
- die = newdie(&dwtypes, DW_ABRV_PTRTYPE, name, 0)
- dotypedef(&dwtypes, name, die)
- s := decodetype_ptrelem(gotype)
- newrefattr(die, DW_AT_type, defgotype(s))
+ 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:
- die = newdie(&dwtypes, DW_ABRV_SLICETYPE, name, 0)
- dotypedef(&dwtypes, name, die)
- newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0)
- s := decodetype_arrayelem(gotype)
- elem := defgotype(s)
- newrefattr(die, DW_AT_go_elem, elem)
+ 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)
+ s := decodetypeArrayElem(gotype)
+ elem := defgotype(ctxt, s)
+ newrefattr(die, dwarf.DW_AT_go_elem, elem)
case obj.KindString:
- die = newdie(&dwtypes, DW_ABRV_STRINGTYPE, name, 0)
- newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0)
+ 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:
- die = newdie(&dwtypes, DW_ABRV_STRUCTTYPE, name, 0)
- dotypedef(&dwtypes, name, die)
- newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0)
- nfields := decodetype_structfieldcount(gotype)
+ 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 *DWDie
- var s *LSym
+ var fld *dwarf.DWDie
+ var s *Symbol
for i := 0; i < nfields; i++ {
- f = decodetype_structfieldname(gotype, i)
- s = decodetype_structfieldtype(gotype, i)
+ f = decodetypeStructFieldName(gotype, i)
+ s = decodetypeStructFieldType(gotype, i)
if f == "" {
f = s.Name[5:] // skip "type."
}
- fld = newdie(die, DW_ABRV_STRUCTFIELD, f, 0)
- newrefattr(fld, DW_AT_type, defgotype(s))
- newmemberoffsetattr(fld, int32(decodetype_structfieldoffs(gotype, i)))
+ 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)))
}
case obj.KindUnsafePointer:
- die = newdie(&dwtypes, DW_ABRV_BARE_PTRTYPE, name, 0)
+ die = newdie(ctxt, &dwtypes, dwarf.DW_ABRV_BARE_PTRTYPE, name, 0)
default:
- Diag("dwarf: definition of unknown kind %d: %s", kind, gotype.Name)
- die = newdie(&dwtypes, DW_ABRV_TYPEDECL, name, 0)
- newrefattr(die, DW_AT_type, mustFind("<unspecified>"))
+ Errorf(gotype, "dwarf: definition of unknown kind %d", kind)
+ die = newdie(ctxt, &dwtypes, dwarf.DW_ABRV_TYPEDECL, name, 0)
+ newrefattr(die, dwarf.DW_AT_type, mustFind(ctxt, "<unspecified>"))
}
- newattr(die, DW_AT_go_kind, DW_CLS_CONSTANT, int64(kind), 0)
+ newattr(die, dwarf.DW_AT_go_kind, dwarf.DW_CLS_CONSTANT, int64(kind), 0)
if _, ok := prototypedies[gotype.Name]; ok {
prototypedies[gotype.Name] = die
@@ -1020,18 +540,18 @@ func newtype(gotype *LSym) *DWDie {
return die
}
-func nameFromDIESym(dwtype *LSym) string {
- return strings.TrimSuffix(dwtype.Name[len(infoprefix):], "..def")
+func nameFromDIESym(dwtype *Symbol) string {
+ return strings.TrimSuffix(dwtype.Name[len(dwarf.InfoPrefix):], "..def")
}
// Find or construct *T given T.
-func defptrto(dwtype *LSym) *LSym {
+func defptrto(ctxt *Link, dwtype *Symbol) *Symbol {
ptrname := "*" + nameFromDIESym(dwtype)
- die := find(ptrname)
+ die := find(ctxt, ptrname)
if die == nil {
- pdie := newdie(&dwtypes, DW_ABRV_PTRTYPE, ptrname, 0)
- newrefattr(pdie, DW_AT_type, dwtype)
- return pdie.sym
+ pdie := newdie(ctxt, &dwtypes, dwarf.DW_ABRV_PTRTYPE, ptrname, 0)
+ newrefattr(pdie, dwarf.DW_AT_type, dwtype)
+ return dtolsym(pdie.Sym)
}
return die
@@ -1040,79 +560,79 @@ func defptrto(dwtype *LSym) *LSym {
// Copies src's children into dst. Copies attributes by value.
// DWAttr.data is copied as pointer only. If except is one of
// the top-level children, it will not be copied.
-func copychildrenexcept(dst *DWDie, src *DWDie, except *DWDie) {
- for src = src.child; src != nil; src = src.link {
+func copychildrenexcept(ctxt *Link, dst *dwarf.DWDie, src *dwarf.DWDie, except *dwarf.DWDie) {
+ for src = src.Child; src != nil; src = src.Link {
if src == except {
continue
}
- c := newdie(dst, src.abbrev, getattr(src, DW_AT_name).data.(string), 0)
- for a := src.attr; a != nil; a = a.link {
- newattr(c, a.atr, int(a.cls), a.value, a.data)
+ c := newdie(ctxt, dst, src.Abbrev, getattr(src, dwarf.DW_AT_name).Data.(string), 0)
+ for a := src.Attr; a != nil; a = a.Link {
+ newattr(c, a.Atr, int(a.Cls), a.Value, a.Data)
}
- copychildrenexcept(c, src, nil)
+ copychildrenexcept(ctxt, c, src, nil)
}
- reverselist(&dst.child)
+ reverselist(&dst.Child)
}
-func copychildren(dst *DWDie, src *DWDie) {
- copychildrenexcept(dst, src, nil)
+func copychildren(ctxt *Link, dst *dwarf.DWDie, src *dwarf.DWDie) {
+ copychildrenexcept(ctxt, dst, src, nil)
}
-// Search children (assumed to have DW_TAG_member) for the one named
-// field and set its DW_AT_type to dwtype
-func substitutetype(structdie *DWDie, field string, dwtype *LSym) {
+// Search children (assumed to have TAG_member) for the one named
+// field and set its AT_type to dwtype
+func substitutetype(structdie *dwarf.DWDie, field string, dwtype *Symbol) {
child := findchild(structdie, field)
if child == nil {
Exitf("dwarf substitutetype: %s does not have member %s",
- getattr(structdie, DW_AT_name).data, field)
+ getattr(structdie, dwarf.DW_AT_name).Data, field)
return
}
- a := getattr(child, DW_AT_type)
+ a := getattr(child, dwarf.DW_AT_type)
if a != nil {
- a.data = dwtype
+ a.Data = dwtype
} else {
- newrefattr(child, DW_AT_type, dwtype)
+ newrefattr(child, dwarf.DW_AT_type, dwtype)
}
}
-func findprotodie(name string) *DWDie {
+func findprotodie(ctxt *Link, name string) *dwarf.DWDie {
die, ok := prototypedies[name]
if ok && die == nil {
- defgotype(lookup_or_diag(name))
+ defgotype(ctxt, lookupOrDiag(ctxt, name))
die = prototypedies[name]
}
return die
}
-func synthesizestringtypes(die *DWDie) {
- prototype := walktypedef(findprotodie("type.runtime.stringStructDWARF"))
+func synthesizestringtypes(ctxt *Link, die *dwarf.DWDie) {
+ prototype := walktypedef(findprotodie(ctxt, "type.runtime.stringStructDWARF"))
if prototype == nil {
return
}
- for ; die != nil; die = die.link {
- if die.abbrev != DW_ABRV_STRINGTYPE {
+ for ; die != nil; die = die.Link {
+ if die.Abbrev != dwarf.DW_ABRV_STRINGTYPE {
continue
}
- copychildren(die, prototype)
+ copychildren(ctxt, die, prototype)
}
}
-func synthesizeslicetypes(die *DWDie) {
- prototype := walktypedef(findprotodie("type.runtime.slice"))
+func synthesizeslicetypes(ctxt *Link, die *dwarf.DWDie) {
+ prototype := walktypedef(findprotodie(ctxt, "type.runtime.slice"))
if prototype == nil {
return
}
- for ; die != nil; die = die.link {
- if die.abbrev != DW_ABRV_SLICETYPE {
+ for ; die != nil; die = die.Link {
+ if die.Abbrev != dwarf.DW_ABRV_SLICETYPE {
continue
}
- copychildren(die, prototype)
- elem := getattr(die, DW_AT_go_elem).data.(*LSym)
- substitutetype(die, "array", defptrto(elem))
+ copychildren(ctxt, die, prototype)
+ elem := getattr(die, dwarf.DW_AT_go_elem).Data.(*Symbol)
+ substitutetype(die, "array", defptrto(ctxt, elem))
}
}
@@ -1135,166 +655,166 @@ const (
BucketSize = 8
)
-func mkinternaltype(abbrev int, typename, keyname, valname string, f func(*DWDie)) *LSym {
+func mkinternaltype(ctxt *Link, abbrev int, typename, keyname, valname string, f func(*dwarf.DWDie)) *Symbol {
name := mkinternaltypename(typename, keyname, valname)
- symname := infoprefix + name
- s := Linkrlookup(Ctxt, symname, 0)
- if s != nil {
+ symname := dwarf.InfoPrefix + name
+ s := ctxt.Syms.ROLookup(symname, 0)
+ if s != nil && s.Type == obj.SDWARFINFO {
return s
}
- die := newdie(&dwtypes, abbrev, name, 0)
+ die := newdie(ctxt, &dwtypes, abbrev, name, 0)
f(die)
- return die.sym
+ return dtolsym(die.Sym)
}
-func synthesizemaptypes(die *DWDie) {
- hash := walktypedef(findprotodie("type.runtime.hmap"))
- bucket := walktypedef(findprotodie("type.runtime.bmap"))
+func synthesizemaptypes(ctxt *Link, die *dwarf.DWDie) {
+ hash := walktypedef(findprotodie(ctxt, "type.runtime.hmap"))
+ bucket := walktypedef(findprotodie(ctxt, "type.runtime.bmap"))
if hash == nil {
return
}
- for ; die != nil; die = die.link {
- if die.abbrev != DW_ABRV_MAPTYPE {
+ for ; die != nil; die = die.Link {
+ if die.Abbrev != dwarf.DW_ABRV_MAPTYPE {
continue
}
- gotype := getattr(die, DW_AT_type).data.(*LSym)
- keytype := decodetype_mapkey(gotype)
- valtype := decodetype_mapvalue(gotype)
- keysize, valsize := decodetype_size(keytype), decodetype_size(valtype)
- keytype, valtype = walksymtypedef(defgotype(keytype)), walksymtypedef(defgotype(valtype))
+ gotype := getattr(die, dwarf.DW_AT_type).Data.(*Symbol)
+ keytype := decodetypeMapKey(gotype)
+ valtype := decodetypeMapValue(gotype)
+ keysize, valsize := decodetypeSize(ctxt.Arch, keytype), decodetypeSize(ctxt.Arch, valtype)
+ keytype, valtype = walksymtypedef(ctxt, defgotype(ctxt, keytype)), walksymtypedef(ctxt, defgotype(ctxt, valtype))
// compute size info like hashmap.c does.
- indirect_key, indirect_val := false, false
+ indirectKey, indirectVal := false, false
if keysize > MaxKeySize {
keysize = int64(SysArch.PtrSize)
- indirect_key = true
+ indirectKey = true
}
if valsize > MaxValSize {
valsize = int64(SysArch.PtrSize)
- indirect_val = true
+ indirectVal = true
}
// Construct type to represent an array of BucketSize keys
keyname := nameFromDIESym(keytype)
- dwhks := mkinternaltype(DW_ABRV_ARRAYTYPE, "[]key", keyname, "", func(dwhk *DWDie) {
- newattr(dwhk, DW_AT_byte_size, DW_CLS_CONSTANT, BucketSize*keysize, 0)
+ dwhks := mkinternaltype(ctxt, dwarf.DW_ABRV_ARRAYTYPE, "[]key", keyname, "", func(dwhk *dwarf.DWDie) {
+ newattr(dwhk, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, BucketSize*keysize, 0)
t := keytype
- if indirect_key {
- t = defptrto(keytype)
+ if indirectKey {
+ t = defptrto(ctxt, keytype)
}
- newrefattr(dwhk, DW_AT_type, t)
- fld := newdie(dwhk, DW_ABRV_ARRAYRANGE, "size", 0)
- newattr(fld, DW_AT_count, DW_CLS_CONSTANT, BucketSize, 0)
- newrefattr(fld, DW_AT_type, mustFind("uintptr"))
+ newrefattr(dwhk, dwarf.DW_AT_type, t)
+ fld := newdie(ctxt, dwhk, dwarf.DW_ABRV_ARRAYRANGE, "size", 0)
+ newattr(fld, dwarf.DW_AT_count, dwarf.DW_CLS_CONSTANT, BucketSize, 0)
+ newrefattr(fld, dwarf.DW_AT_type, mustFind(ctxt, "uintptr"))
})
// Construct type to represent an array of BucketSize values
valname := nameFromDIESym(valtype)
- dwhvs := mkinternaltype(DW_ABRV_ARRAYTYPE, "[]val", valname, "", func(dwhv *DWDie) {
- newattr(dwhv, DW_AT_byte_size, DW_CLS_CONSTANT, BucketSize*valsize, 0)
+ dwhvs := mkinternaltype(ctxt, dwarf.DW_ABRV_ARRAYTYPE, "[]val", valname, "", func(dwhv *dwarf.DWDie) {
+ newattr(dwhv, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, BucketSize*valsize, 0)
t := valtype
- if indirect_val {
- t = defptrto(valtype)
+ if indirectVal {
+ t = defptrto(ctxt, valtype)
}
- newrefattr(dwhv, DW_AT_type, t)
- fld := newdie(dwhv, DW_ABRV_ARRAYRANGE, "size", 0)
- newattr(fld, DW_AT_count, DW_CLS_CONSTANT, BucketSize, 0)
- newrefattr(fld, DW_AT_type, mustFind("uintptr"))
+ newrefattr(dwhv, dwarf.DW_AT_type, t)
+ fld := newdie(ctxt, dwhv, dwarf.DW_ABRV_ARRAYRANGE, "size", 0)
+ newattr(fld, dwarf.DW_AT_count, dwarf.DW_CLS_CONSTANT, BucketSize, 0)
+ newrefattr(fld, dwarf.DW_AT_type, mustFind(ctxt, "uintptr"))
})
// Construct bucket<K,V>
- dwhbs := mkinternaltype(DW_ABRV_STRUCTTYPE, "bucket", keyname, valname, func(dwhb *DWDie) {
+ dwhbs := mkinternaltype(ctxt, dwarf.DW_ABRV_STRUCTTYPE, "bucket", keyname, valname, func(dwhb *dwarf.DWDie) {
// Copy over all fields except the field "data" from the generic
// bucket. "data" will be replaced with keys/values below.
- copychildrenexcept(dwhb, bucket, findchild(bucket, "data"))
+ copychildrenexcept(ctxt, dwhb, bucket, findchild(bucket, "data"))
- fld := newdie(dwhb, DW_ABRV_STRUCTFIELD, "keys", 0)
- newrefattr(fld, DW_AT_type, dwhks)
+ fld := newdie(ctxt, dwhb, dwarf.DW_ABRV_STRUCTFIELD, "keys", 0)
+ newrefattr(fld, dwarf.DW_AT_type, dwhks)
newmemberoffsetattr(fld, BucketSize)
- fld = newdie(dwhb, DW_ABRV_STRUCTFIELD, "values", 0)
- newrefattr(fld, DW_AT_type, dwhvs)
+ fld = newdie(ctxt, dwhb, dwarf.DW_ABRV_STRUCTFIELD, "values", 0)
+ newrefattr(fld, dwarf.DW_AT_type, dwhvs)
newmemberoffsetattr(fld, BucketSize+BucketSize*int32(keysize))
- fld = newdie(dwhb, DW_ABRV_STRUCTFIELD, "overflow", 0)
- newrefattr(fld, DW_AT_type, defptrto(dwhb.sym))
+ fld = newdie(ctxt, dwhb, dwarf.DW_ABRV_STRUCTFIELD, "overflow", 0)
+ newrefattr(fld, dwarf.DW_AT_type, defptrto(ctxt, dtolsym(dwhb.Sym)))
newmemberoffsetattr(fld, BucketSize+BucketSize*(int32(keysize)+int32(valsize)))
if SysArch.RegSize > SysArch.PtrSize {
- fld = newdie(dwhb, DW_ABRV_STRUCTFIELD, "pad", 0)
- newrefattr(fld, DW_AT_type, mustFind("uintptr"))
+ fld = newdie(ctxt, dwhb, dwarf.DW_ABRV_STRUCTFIELD, "pad", 0)
+ newrefattr(fld, dwarf.DW_AT_type, mustFind(ctxt, "uintptr"))
newmemberoffsetattr(fld, BucketSize+BucketSize*(int32(keysize)+int32(valsize))+int32(SysArch.PtrSize))
}
- newattr(dwhb, DW_AT_byte_size, DW_CLS_CONSTANT, BucketSize+BucketSize*keysize+BucketSize*valsize+int64(SysArch.RegSize), 0)
+ newattr(dwhb, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, BucketSize+BucketSize*keysize+BucketSize*valsize+int64(SysArch.RegSize), 0)
})
// Construct hash<K,V>
- dwhs := mkinternaltype(DW_ABRV_STRUCTTYPE, "hash", keyname, valname, func(dwh *DWDie) {
- copychildren(dwh, hash)
- substitutetype(dwh, "buckets", defptrto(dwhbs))
- substitutetype(dwh, "oldbuckets", defptrto(dwhbs))
- newattr(dwh, DW_AT_byte_size, DW_CLS_CONSTANT, getattr(hash, DW_AT_byte_size).value, nil)
+ dwhs := mkinternaltype(ctxt, dwarf.DW_ABRV_STRUCTTYPE, "hash", keyname, valname, func(dwh *dwarf.DWDie) {
+ copychildren(ctxt, dwh, hash)
+ substitutetype(dwh, "buckets", defptrto(ctxt, dwhbs))
+ substitutetype(dwh, "oldbuckets", defptrto(ctxt, dwhbs))
+ newattr(dwh, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, getattr(hash, dwarf.DW_AT_byte_size).Value, nil)
})
// make map type a pointer to hash<K,V>
- newrefattr(die, DW_AT_type, defptrto(dwhs))
+ newrefattr(die, dwarf.DW_AT_type, defptrto(ctxt, dwhs))
}
}
-func synthesizechantypes(die *DWDie) {
- sudog := walktypedef(findprotodie("type.runtime.sudog"))
- waitq := walktypedef(findprotodie("type.runtime.waitq"))
- hchan := walktypedef(findprotodie("type.runtime.hchan"))
+func synthesizechantypes(ctxt *Link, die *dwarf.DWDie) {
+ sudog := walktypedef(findprotodie(ctxt, "type.runtime.sudog"))
+ waitq := walktypedef(findprotodie(ctxt, "type.runtime.waitq"))
+ hchan := walktypedef(findprotodie(ctxt, "type.runtime.hchan"))
if sudog == nil || waitq == nil || hchan == nil {
return
}
- sudogsize := int(getattr(sudog, DW_AT_byte_size).value)
+ sudogsize := int(getattr(sudog, dwarf.DW_AT_byte_size).Value)
- for ; die != nil; die = die.link {
- if die.abbrev != DW_ABRV_CHANTYPE {
+ for ; die != nil; die = die.Link {
+ if die.Abbrev != dwarf.DW_ABRV_CHANTYPE {
continue
}
- elemgotype := getattr(die, DW_AT_type).data.(*LSym)
- elemsize := decodetype_size(elemgotype)
+ elemgotype := getattr(die, dwarf.DW_AT_type).Data.(*Symbol)
+ elemsize := decodetypeSize(ctxt.Arch, elemgotype)
elemname := elemgotype.Name[5:]
- elemtype := walksymtypedef(defgotype(elemgotype))
+ elemtype := walksymtypedef(ctxt, defgotype(ctxt, elemgotype))
// sudog<T>
- dwss := mkinternaltype(DW_ABRV_STRUCTTYPE, "sudog", elemname, "", func(dws *DWDie) {
- copychildren(dws, sudog)
+ dwss := mkinternaltype(ctxt, dwarf.DW_ABRV_STRUCTTYPE, "sudog", elemname, "", func(dws *dwarf.DWDie) {
+ copychildren(ctxt, dws, sudog)
substitutetype(dws, "elem", elemtype)
if elemsize > 8 {
elemsize -= 8
} else {
elemsize = 0
}
- newattr(dws, DW_AT_byte_size, DW_CLS_CONSTANT, int64(sudogsize)+elemsize, nil)
+ newattr(dws, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, int64(sudogsize)+elemsize, nil)
})
// waitq<T>
- dwws := mkinternaltype(DW_ABRV_STRUCTTYPE, "waitq", elemname, "", func(dww *DWDie) {
+ dwws := mkinternaltype(ctxt, dwarf.DW_ABRV_STRUCTTYPE, "waitq", elemname, "", func(dww *dwarf.DWDie) {
- copychildren(dww, waitq)
- substitutetype(dww, "first", defptrto(dwss))
- substitutetype(dww, "last", defptrto(dwss))
- newattr(dww, DW_AT_byte_size, DW_CLS_CONSTANT, getattr(waitq, DW_AT_byte_size).value, nil)
+ copychildren(ctxt, dww, waitq)
+ substitutetype(dww, "first", defptrto(ctxt, dwss))
+ substitutetype(dww, "last", defptrto(ctxt, dwss))
+ newattr(dww, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, getattr(waitq, dwarf.DW_AT_byte_size).Value, nil)
})
// hchan<T>
- dwhs := mkinternaltype(DW_ABRV_STRUCTTYPE, "hchan", elemname, "", func(dwh *DWDie) {
- copychildren(dwh, hchan)
+ dwhs := mkinternaltype(ctxt, dwarf.DW_ABRV_STRUCTTYPE, "hchan", elemname, "", func(dwh *dwarf.DWDie) {
+ copychildren(ctxt, dwh, hchan)
substitutetype(dwh, "recvq", dwws)
substitutetype(dwh, "sendq", dwws)
- newattr(dwh, DW_AT_byte_size, DW_CLS_CONSTANT, getattr(hchan, DW_AT_byte_size).value, nil)
+ newattr(dwh, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, getattr(hchan, dwarf.DW_AT_byte_size).Value, nil)
})
- newrefattr(die, DW_AT_type, defptrto(dwhs))
+ newrefattr(die, dwarf.DW_AT_type, defptrto(ctxt, dwhs))
}
}
// For use with pass.c::genasmsym
-func defdwsymb(sym *LSym, s string, t int, v int64, size int64, ver int, gotype *LSym) {
+func defdwsymb(ctxt *Link, sym *Symbol, s string, t SymbolType, v int64, gotype *Symbol) {
if strings.HasPrefix(s, "go.string.") {
return
}
@@ -1303,44 +823,48 @@ func defdwsymb(sym *LSym, s string, t int, v int64, size int64, ver int, gotype
}
if strings.HasPrefix(s, "type.") && s != "type.*" && !strings.HasPrefix(s, "type..") {
- defgotype(sym)
+ defgotype(ctxt, sym)
return
}
- var dv *DWDie
+ var dv *dwarf.DWDie
- var dt *LSym
+ var dt *Symbol
switch t {
default:
return
- case 'd', 'b', 'D', 'B':
- dv = newdie(&dwglobals, DW_ABRV_VARIABLE, s, ver)
+ case DataSym, BSSSym:
+ dv = newdie(ctxt, &dwglobals, dwarf.DW_ABRV_VARIABLE, s, int(sym.Version))
newabslocexprattr(dv, v, sym)
- if ver == 0 {
- newattr(dv, DW_AT_external, DW_CLS_FLAG, 1, 0)
+ if sym.Version == 0 {
+ newattr(dv, dwarf.DW_AT_external, dwarf.DW_CLS_FLAG, 1, 0)
}
fallthrough
- case 'a', 'p':
- dt = defgotype(gotype)
+ case AutoSym, ParamSym:
+ dt = defgotype(ctxt, gotype)
}
if dv != nil {
- newrefattr(dv, DW_AT_type, dt)
+ newrefattr(dv, dwarf.DW_AT_type, dt)
}
}
-func movetomodule(parent *DWDie) {
- die := dwroot.child.child
- for die.link != nil {
- die = die.link
+func movetomodule(parent *dwarf.DWDie) {
+ die := dwroot.Child.Child
+ if die == nil {
+ dwroot.Child.Child = parent.Child
+ return
+ }
+ for die.Link != nil {
+ die = die.Link
}
- die.link = parent.child
+ die.Link = parent.Child
}
// If the pcln table contains runtime/runtime.go, use that to set gdbscript path.
-func finddebugruntimepath(s *LSym) {
+func finddebugruntimepath(s *Symbol) {
if gdbscript != "" {
return
}
@@ -1355,51 +879,104 @@ func finddebugruntimepath(s *LSym) {
}
/*
- * Generate short opcodes when possible, long ones when necessary.
+ * Generate a sequence of opcodes that is as short as possible.
* See section 6.2.5
*/
const (
- LINE_BASE = -1
- LINE_RANGE = 4
+ LINE_BASE = -4
+ LINE_RANGE = 10
+ PC_RANGE = (255 - OPCODE_BASE) / LINE_RANGE
OPCODE_BASE = 10
)
-func putpclcdelta(s *LSym, delta_pc int64, delta_lc int64) {
- if LINE_BASE <= delta_lc && delta_lc < LINE_BASE+LINE_RANGE {
- var opcode int64 = OPCODE_BASE + (delta_lc - LINE_BASE) + (LINE_RANGE * delta_pc)
- if OPCODE_BASE <= opcode && opcode < 256 {
- Adduint8(Ctxt, s, uint8(opcode))
- return
+func putpclcdelta(linkctxt *Link, ctxt dwarf.Context, s *Symbol, deltaPC uint64, deltaLC int64) {
+ // Choose a special opcode that minimizes the number of bytes needed to
+ // encode the remaining PC delta and LC delta.
+ var opcode int64
+ if deltaLC < LINE_BASE {
+ if deltaPC >= PC_RANGE {
+ opcode = OPCODE_BASE + (LINE_RANGE * PC_RANGE)
+ } else {
+ opcode = OPCODE_BASE + (LINE_RANGE * int64(deltaPC))
+ }
+ } else if deltaLC < LINE_BASE+LINE_RANGE {
+ if deltaPC >= PC_RANGE {
+ opcode = OPCODE_BASE + (deltaLC - LINE_BASE) + (LINE_RANGE * PC_RANGE)
+ if opcode > 255 {
+ opcode -= LINE_RANGE
+ }
+ } else {
+ opcode = OPCODE_BASE + (deltaLC - LINE_BASE) + (LINE_RANGE * int64(deltaPC))
+ }
+ } else {
+ if deltaPC <= PC_RANGE {
+ opcode = OPCODE_BASE + (LINE_RANGE - 1) + (LINE_RANGE * int64(deltaPC))
+ if opcode > 255 {
+ opcode = 255
+ }
+ } else {
+ // Use opcode 249 (pc+=23, lc+=5) or 255 (pc+=24, lc+=1).
+ //
+ // Let x=deltaPC-PC_RANGE. If we use opcode 255, x will be the remaining
+ // deltaPC that we need to encode separately before emitting 255. If we
+ // use opcode 249, we will need to encode x+1. If x+1 takes one more
+ // byte to encode than x, then we use opcode 255.
+ //
+ // In all other cases x and x+1 take the same number of bytes to encode,
+ // so we use opcode 249, which may save us a byte in encoding deltaLC,
+ // for similar reasons.
+ switch deltaPC - PC_RANGE {
+ // PC_RANGE is the largest deltaPC we can encode in one byte, using
+ // DW_LNS_const_add_pc.
+ //
+ // (1<<16)-1 is the largest deltaPC we can encode in three bytes, using
+ // DW_LNS_fixed_advance_pc.
+ //
+ // (1<<(7n))-1 is the largest deltaPC we can encode in n+1 bytes for
+ // n=1,3,4,5,..., using DW_LNS_advance_pc.
+ case PC_RANGE, (1 << 7) - 1, (1 << 16) - 1, (1 << 21) - 1, (1 << 28) - 1,
+ (1 << 35) - 1, (1 << 42) - 1, (1 << 49) - 1, (1 << 56) - 1, (1 << 63) - 1:
+ opcode = 255
+ default:
+ opcode = OPCODE_BASE + LINE_RANGE*PC_RANGE - 1 // 249
+ }
}
}
-
- if delta_pc != 0 {
- Adduint8(Ctxt, s, DW_LNS_advance_pc)
- sleb128put(s, delta_pc)
+ if opcode < OPCODE_BASE || opcode > 255 {
+ panic(fmt.Sprintf("produced invalid special opcode %d", opcode))
}
- Adduint8(Ctxt, s, DW_LNS_advance_line)
- sleb128put(s, delta_lc)
- Adduint8(Ctxt, s, DW_LNS_copy)
-}
-
-func newcfaoffsetattr(die *DWDie, offs int32) {
- var block [20]byte
- b := append(block[:0], DW_OP_call_frame_cfa)
+ // Subtract from deltaPC and deltaLC the amounts that the opcode will add.
+ deltaPC -= uint64((opcode - OPCODE_BASE) / LINE_RANGE)
+ deltaLC -= int64((opcode-OPCODE_BASE)%LINE_RANGE + LINE_BASE)
- if offs != 0 {
- b = append(b, DW_OP_consts)
- b = appendSleb128(b, int64(offs))
- b = append(b, DW_OP_plus)
+ // Encode deltaPC.
+ if deltaPC != 0 {
+ if deltaPC <= PC_RANGE {
+ // Adjust the opcode so that we can use the 1-byte DW_LNS_const_add_pc
+ // instruction.
+ opcode -= LINE_RANGE * int64(PC_RANGE-deltaPC)
+ if opcode < OPCODE_BASE {
+ panic(fmt.Sprintf("produced invalid special opcode %d", opcode))
+ }
+ Adduint8(linkctxt, s, dwarf.DW_LNS_const_add_pc)
+ } else if (1<<14) <= deltaPC && deltaPC < (1<<16) {
+ Adduint8(linkctxt, s, dwarf.DW_LNS_fixed_advance_pc)
+ Adduint16(linkctxt, s, uint16(deltaPC))
+ } else {
+ Adduint8(linkctxt, s, dwarf.DW_LNS_advance_pc)
+ dwarf.Uleb128put(ctxt, s, int64(deltaPC))
+ }
}
- newattr(die, DW_AT_location, DW_CLS_BLOCK, int64(len(b)), b)
-}
+ // Encode deltaLC.
+ if deltaLC != 0 {
+ Adduint8(linkctxt, s, dwarf.DW_LNS_advance_line)
+ dwarf.Sleb128put(ctxt, s, deltaLC)
+ }
-func mkvarname(name string, da int) string {
- buf := fmt.Sprintf("%s#%d", name, da)
- n := buf
- return n
+ // Output the special opcode.
+ Adduint8(linkctxt, s, uint8(opcode))
}
/*
@@ -1413,100 +990,109 @@ func getCompilationDir() string {
return "/"
}
-func writelines(prev *LSym) *LSym {
+func writelines(ctxt *Link, syms []*Symbol) ([]*Symbol, []*Symbol) {
+ var dwarfctxt dwarf.Context = dwctxt{ctxt}
if linesec == nil {
- linesec = Linklookup(Ctxt, ".debug_line", 0)
+ linesec = ctxt.Syms.Lookup(".debug_line", 0)
}
linesec.Type = obj.SDWARFSECT
linesec.R = linesec.R[:0]
ls := linesec
- prev.Next = ls
+ syms = append(syms, ls)
+ var funcs []*Symbol
unitstart := int64(-1)
headerstart := int64(-1)
headerend := int64(-1)
epc := int64(0)
- var epcs *LSym
- var dwinfo *DWDie
+ var epcs *Symbol
+ var dwinfo *dwarf.DWDie
- lang := DW_LANG_Go
+ lang := dwarf.DW_LANG_Go
- s := Ctxt.Textp[0]
+ s := ctxt.Textp[0]
+ if ctxt.DynlinkingGo() && Headtype == obj.Hdarwin {
+ s = ctxt.Textp[1] // skip runtime.text
+ }
- dwinfo = newdie(&dwroot, DW_ABRV_COMPUNIT, "go", 0)
- newattr(dwinfo, DW_AT_language, DW_CLS_CONSTANT, int64(lang), 0)
- newattr(dwinfo, DW_AT_stmt_list, DW_CLS_PTR, 0, 0)
- newattr(dwinfo, DW_AT_low_pc, DW_CLS_ADDRESS, s.Value, s)
+ dwinfo = newdie(ctxt, &dwroot, dwarf.DW_ABRV_COMPUNIT, "go", 0)
+ newattr(dwinfo, dwarf.DW_AT_language, dwarf.DW_CLS_CONSTANT, int64(lang), 0)
+ newattr(dwinfo, dwarf.DW_AT_stmt_list, dwarf.DW_CLS_PTR, 0, linesec)
+ newattr(dwinfo, dwarf.DW_AT_low_pc, dwarf.DW_CLS_ADDRESS, s.Value, s)
// OS X linker requires compilation dir or absolute path in comp unit name to output debug info.
compDir := getCompilationDir()
- newattr(dwinfo, DW_AT_comp_dir, DW_CLS_STRING, int64(len(compDir)), compDir)
+ newattr(dwinfo, dwarf.DW_AT_comp_dir, dwarf.DW_CLS_STRING, int64(len(compDir)), compDir)
// Write .debug_line Line Number Program Header (sec 6.2.4)
// Fields marked with (*) must be changed for 64-bit dwarf
- unit_length_offset := ls.Size
- Adduint32(Ctxt, ls, 0) // unit_length (*), filled in at end.
+ unitLengthOffset := ls.Size
+ Adduint32(ctxt, ls, 0) // unit_length (*), filled in at end.
unitstart = ls.Size
- Adduint16(Ctxt, ls, 2) // dwarf version (appendix F)
- header_length_offset := ls.Size
- Adduint32(Ctxt, ls, 0) // header_length (*), filled in at end.
+ Adduint16(ctxt, ls, 2) // dwarf version (appendix F)
+ headerLengthOffset := ls.Size
+ Adduint32(ctxt, ls, 0) // header_length (*), filled in at end.
headerstart = ls.Size
// cpos == unitstart + 4 + 2 + 4
- Adduint8(Ctxt, ls, 1) // minimum_instruction_length
- Adduint8(Ctxt, ls, 1) // default_is_stmt
- Adduint8(Ctxt, ls, LINE_BASE&0xFF) // line_base
- Adduint8(Ctxt, ls, LINE_RANGE) // line_range
- Adduint8(Ctxt, ls, OPCODE_BASE) // opcode_base
- Adduint8(Ctxt, ls, 0) // standard_opcode_lengths[1]
- Adduint8(Ctxt, ls, 1) // standard_opcode_lengths[2]
- Adduint8(Ctxt, ls, 1) // standard_opcode_lengths[3]
- Adduint8(Ctxt, ls, 1) // standard_opcode_lengths[4]
- Adduint8(Ctxt, ls, 1) // standard_opcode_lengths[5]
- Adduint8(Ctxt, ls, 0) // standard_opcode_lengths[6]
- Adduint8(Ctxt, ls, 0) // standard_opcode_lengths[7]
- Adduint8(Ctxt, ls, 0) // standard_opcode_lengths[8]
- Adduint8(Ctxt, ls, 1) // standard_opcode_lengths[9]
- Adduint8(Ctxt, ls, 0) // include_directories (empty)
-
- for _, f := range Ctxt.Filesyms {
+ Adduint8(ctxt, ls, 1) // minimum_instruction_length
+ Adduint8(ctxt, ls, 1) // default_is_stmt
+ Adduint8(ctxt, ls, LINE_BASE&0xFF) // line_base
+ Adduint8(ctxt, ls, LINE_RANGE) // line_range
+ Adduint8(ctxt, ls, OPCODE_BASE) // opcode_base
+ Adduint8(ctxt, ls, 0) // standard_opcode_lengths[1]
+ Adduint8(ctxt, ls, 1) // standard_opcode_lengths[2]
+ Adduint8(ctxt, ls, 1) // standard_opcode_lengths[3]
+ Adduint8(ctxt, ls, 1) // standard_opcode_lengths[4]
+ Adduint8(ctxt, ls, 1) // standard_opcode_lengths[5]
+ Adduint8(ctxt, ls, 0) // standard_opcode_lengths[6]
+ Adduint8(ctxt, ls, 0) // standard_opcode_lengths[7]
+ Adduint8(ctxt, ls, 0) // standard_opcode_lengths[8]
+ Adduint8(ctxt, ls, 1) // standard_opcode_lengths[9]
+ Adduint8(ctxt, ls, 0) // include_directories (empty)
+
+ for _, f := range ctxt.Filesyms {
Addstring(ls, f.Name)
- Adduint8(Ctxt, ls, 0)
- Adduint8(Ctxt, ls, 0)
- Adduint8(Ctxt, ls, 0)
+ Adduint8(ctxt, ls, 0)
+ Adduint8(ctxt, ls, 0)
+ Adduint8(ctxt, ls, 0)
}
// 4 zeros: the string termination + 3 fields.
- Adduint8(Ctxt, ls, 0)
+ Adduint8(ctxt, ls, 0)
// terminate file_names.
headerend = ls.Size
- Adduint8(Ctxt, ls, 0) // start extended opcode
- uleb128put(ls, 1+int64(SysArch.PtrSize))
- Adduint8(Ctxt, ls, DW_LNE_set_address)
+ Adduint8(ctxt, ls, 0) // start extended opcode
+ dwarf.Uleb128put(dwarfctxt, ls, 1+int64(SysArch.PtrSize))
+ Adduint8(ctxt, ls, dwarf.DW_LNE_set_address)
pc := s.Value
line := 1
file := 1
- if Linkmode == LinkExternal {
- Addaddr(Ctxt, ls, s)
- } else {
- addrput(ls, pc)
- }
+ Addaddr(ctxt, ls, s)
var pcfile Pciter
var pcline Pciter
- for _, Ctxt.Cursym = range Ctxt.Textp {
- s := Ctxt.Cursym
+ for _, s := range ctxt.Textp {
- dwfunc := newdie(dwinfo, DW_ABRV_FUNCTION, s.Name, int(s.Version))
- newattr(dwfunc, DW_AT_low_pc, DW_CLS_ADDRESS, s.Value, s)
epc = s.Value + s.Size
epcs = s
- newattr(dwfunc, DW_AT_high_pc, DW_CLS_ADDRESS, epc, s)
- if s.Version == 0 {
- newattr(dwfunc, DW_AT_external, DW_CLS_FLAG, 1, 0)
+
+ dsym := ctxt.Syms.Lookup(dwarf.InfoPrefix+s.Name, int(s.Version))
+ dsym.Attr |= AttrHidden
+ dsym.Type = obj.SDWARFINFO
+ for _, r := range dsym.R {
+ if r.Type == obj.R_DWARFREF && r.Sym.Size == 0 {
+ if Buildmode == BuildmodeShared {
+ // These type symbols may not be present in BuildmodeShared. Skip.
+ continue
+ }
+ n := nameFromDIESym(r.Sym)
+ defgotype(ctxt, ctxt.Syms.Lookup("type."+n, 0))
+ }
}
+ funcs = append(funcs, dsym)
if s.FuncInfo == nil {
continue
@@ -1514,8 +1100,8 @@ func writelines(prev *LSym) *LSym {
finddebugruntimepath(s)
- pciterinit(Ctxt, &pcfile, &s.FuncInfo.Pcfile)
- pciterinit(Ctxt, &pcline, &s.FuncInfo.Pcline)
+ pciterinit(ctxt, &pcfile, &s.FuncInfo.Pcfile)
+ pciterinit(ctxt, &pcline, &s.FuncInfo.Pcline)
epc = pc
for pcfile.done == 0 && pcline.done == 0 {
if epc-s.Value >= int64(pcfile.nextpc) {
@@ -1529,12 +1115,12 @@ func writelines(prev *LSym) *LSym {
}
if int32(file) != pcfile.value {
- Adduint8(Ctxt, ls, DW_LNS_set_file)
- uleb128put(ls, int64(pcfile.value))
+ Adduint8(ctxt, ls, dwarf.DW_LNS_set_file)
+ dwarf.Uleb128put(dwarfctxt, ls, int64(pcfile.value))
file = int(pcfile.value)
}
- putpclcdelta(ls, s.Value+int64(pcline.pc)-pc, int64(pcline.value)-int64(line))
+ putpclcdelta(ctxt, dwarfctxt, ls, uint64(s.Value+int64(pcline.pc)-pc), int64(pcline.value)-int64(line))
pc = s.Value + int64(pcline.pc)
line = int(pcline.value)
@@ -1545,80 +1131,18 @@ func writelines(prev *LSym) *LSym {
}
epc += s.Value
}
-
- var (
- dt, da int
- offs int64
- )
- for _, a := range s.FuncInfo.Autom {
- switch a.Name {
- case obj.A_AUTO:
- dt = DW_ABRV_AUTO
- offs = int64(a.Aoffset)
- if !haslinkregister() {
- offs -= int64(SysArch.PtrSize)
- }
- if obj.Framepointer_enabled(obj.Getgoos(), obj.Getgoarch()) {
- // The frame pointer is saved
- // between the CFA and the
- // autos.
- offs -= int64(SysArch.PtrSize)
- }
-
- case obj.A_PARAM:
- dt = DW_ABRV_PARAM
- offs = int64(a.Aoffset) + Ctxt.FixedFrameSize()
-
- default:
- continue
- }
-
- if strings.Contains(a.Asym.Name, ".autotmp_") {
- continue
- }
- var n string
- if findchild(dwfunc, a.Asym.Name) != nil {
- n = mkvarname(a.Asym.Name, da)
- } else {
- n = a.Asym.Name
- }
-
- // Drop the package prefix from locals and arguments.
- if i := strings.LastIndex(n, "."); i >= 0 {
- n = n[i+1:]
- }
-
- dwvar := newdie(dwfunc, dt, n, 0)
- newcfaoffsetattr(dwvar, int32(offs))
- newrefattr(dwvar, DW_AT_type, defgotype(a.Gotype))
-
- // push dwvar down dwfunc->child to preserve order
- newattr(dwvar, DW_AT_internal_location, DW_CLS_CONSTANT, offs, nil)
-
- dwfunc.child = dwvar.link // take dwvar out from the top of the list
- dws := &dwfunc.child
- for ; *dws != nil; dws = &(*dws).link {
- if offs > getattr(*dws, DW_AT_internal_location).value {
- break
- }
- }
- dwvar.link = *dws
- *dws = dwvar
-
- da++
- }
}
- Adduint8(Ctxt, ls, 0) // start extended opcode
- uleb128put(ls, 1)
- Adduint8(Ctxt, ls, DW_LNE_end_sequence)
+ Adduint8(ctxt, ls, 0) // start extended opcode
+ dwarf.Uleb128put(dwarfctxt, ls, 1)
+ Adduint8(ctxt, ls, dwarf.DW_LNE_end_sequence)
- newattr(dwinfo, DW_AT_high_pc, DW_CLS_ADDRESS, epc+1, epcs)
+ newattr(dwinfo, dwarf.DW_AT_high_pc, dwarf.DW_CLS_ADDRESS, epc+1, epcs)
- setuint32(Ctxt, ls, unit_length_offset, uint32(ls.Size-unitstart))
- setuint32(Ctxt, ls, header_length_offset, uint32(headerend-headerstart))
+ setuint32(ctxt, ls, unitLengthOffset, uint32(ls.Size-unitstart))
+ setuint32(ctxt, ls, headerLengthOffset, uint32(headerend-headerstart))
- return ls
+ return syms, funcs
}
/*
@@ -1630,64 +1154,65 @@ const (
// appendPCDeltaCFA appends per-PC CFA deltas to b and returns the final slice.
func appendPCDeltaCFA(b []byte, deltapc, cfa int64) []byte {
- b = append(b, DW_CFA_def_cfa_offset_sf)
- b = appendSleb128(b, cfa/dataAlignmentFactor)
+ b = append(b, dwarf.DW_CFA_def_cfa_offset_sf)
+ b = dwarf.AppendSleb128(b, cfa/dataAlignmentFactor)
switch {
case deltapc < 0x40:
- b = append(b, uint8(DW_CFA_advance_loc+deltapc))
+ b = append(b, uint8(dwarf.DW_CFA_advance_loc+deltapc))
case deltapc < 0x100:
- b = append(b, DW_CFA_advance_loc1)
+ b = append(b, dwarf.DW_CFA_advance_loc1)
b = append(b, uint8(deltapc))
case deltapc < 0x10000:
- b = append(b, DW_CFA_advance_loc2)
+ b = append(b, dwarf.DW_CFA_advance_loc2)
b = Thearch.Append16(b, uint16(deltapc))
default:
- b = append(b, DW_CFA_advance_loc4)
+ b = append(b, dwarf.DW_CFA_advance_loc4)
b = Thearch.Append32(b, uint32(deltapc))
}
return b
}
-func writeframes(prev *LSym) *LSym {
+func writeframes(ctxt *Link, syms []*Symbol) []*Symbol {
+ var dwarfctxt dwarf.Context = dwctxt{ctxt}
if framesec == nil {
- framesec = Linklookup(Ctxt, ".debug_frame", 0)
+ framesec = ctxt.Syms.Lookup(".debug_frame", 0)
}
framesec.Type = obj.SDWARFSECT
framesec.R = framesec.R[:0]
fs := framesec
- prev.Next = fs
+ syms = append(syms, fs)
// Emit the CIE, Section 6.4.1
cieReserve := uint32(16)
- if haslinkregister() {
+ if haslinkregister(ctxt) {
cieReserve = 32
}
- Adduint32(Ctxt, fs, cieReserve) // initial length, must be multiple of pointer size
- Adduint32(Ctxt, fs, 0xffffffff) // cid.
- Adduint8(Ctxt, fs, 3) // dwarf version (appendix F)
- Adduint8(Ctxt, fs, 0) // augmentation ""
- uleb128put(fs, 1) // code_alignment_factor
- sleb128put(fs, dataAlignmentFactor) // all CFI offset calculations include multiplication with this factor
- uleb128put(fs, int64(Thearch.Dwarfreglr)) // return_address_register
-
- Adduint8(Ctxt, fs, DW_CFA_def_cfa) // Set the current frame address..
- uleb128put(fs, int64(Thearch.Dwarfregsp)) // ...to use the value in the platform's SP register (defined in l.go)...
- if haslinkregister() {
- uleb128put(fs, int64(0)) // ...plus a 0 offset.
-
- Adduint8(Ctxt, fs, DW_CFA_same_value) // The platform's link register is unchanged during the prologue.
- uleb128put(fs, int64(Thearch.Dwarfreglr))
-
- Adduint8(Ctxt, fs, DW_CFA_val_offset) // The previous value...
- uleb128put(fs, int64(Thearch.Dwarfregsp)) // ...of the platform's SP register...
- uleb128put(fs, int64(0)) // ...is CFA+0.
+ Adduint32(ctxt, fs, cieReserve) // initial length, must be multiple of thearch.ptrsize
+ Adduint32(ctxt, fs, 0xffffffff) // cid.
+ Adduint8(ctxt, fs, 3) // dwarf version (appendix F)
+ Adduint8(ctxt, fs, 0) // augmentation ""
+ dwarf.Uleb128put(dwarfctxt, fs, 1) // code_alignment_factor
+ dwarf.Sleb128put(dwarfctxt, fs, dataAlignmentFactor) // all CFI offset calculations include multiplication with this factor
+ dwarf.Uleb128put(dwarfctxt, fs, int64(Thearch.Dwarfreglr)) // return_address_register
+
+ Adduint8(ctxt, fs, dwarf.DW_CFA_def_cfa) // Set the current frame address..
+ dwarf.Uleb128put(dwarfctxt, fs, int64(Thearch.Dwarfregsp)) // ...to use the value in the platform's SP register (defined in l.go)...
+ if haslinkregister(ctxt) {
+ dwarf.Uleb128put(dwarfctxt, fs, int64(0)) // ...plus a 0 offset.
+
+ Adduint8(ctxt, fs, dwarf.DW_CFA_same_value) // The platform's link register is unchanged during the prologue.
+ dwarf.Uleb128put(dwarfctxt, fs, int64(Thearch.Dwarfreglr))
+
+ Adduint8(ctxt, fs, dwarf.DW_CFA_val_offset) // The previous value...
+ dwarf.Uleb128put(dwarfctxt, fs, int64(Thearch.Dwarfregsp)) // ...of the platform's SP register...
+ dwarf.Uleb128put(dwarfctxt, fs, int64(0)) // ...is CFA+0.
} else {
- uleb128put(fs, int64(SysArch.PtrSize)) // ...plus the word size (because the call instruction implicitly adds one word to the frame).
+ dwarf.Uleb128put(dwarfctxt, fs, int64(SysArch.PtrSize)) // ...plus the word size (because the call instruction implicitly adds one word to the frame).
- Adduint8(Ctxt, fs, DW_CFA_offset_extended) // The previous value...
- uleb128put(fs, int64(Thearch.Dwarfreglr)) // ...of the return address...
- uleb128put(fs, int64(-SysArch.PtrSize)/dataAlignmentFactor) // ...is saved at [CFA - (PtrSize/4)].
+ Adduint8(ctxt, fs, dwarf.DW_CFA_offset_extended) // The previous value...
+ dwarf.Uleb128put(dwarfctxt, fs, int64(Thearch.Dwarfreglr)) // ...of the return address...
+ dwarf.Uleb128put(dwarfctxt, fs, int64(-SysArch.PtrSize)/dataAlignmentFactor) // ...is saved at [CFA - (PtrSize/4)].
}
// 4 is to exclude the length field.
@@ -1697,12 +1222,11 @@ func writeframes(prev *LSym) *LSym {
Exitf("dwarf: cieReserve too small by %d bytes.", -pad)
}
- Addbytes(Ctxt, fs, zeros[:pad])
+ Addbytes(fs, zeros[:pad])
var deltaBuf []byte
var pcsp Pciter
- for _, Ctxt.Cursym = range Ctxt.Textp {
- s := Ctxt.Cursym
+ for _, s := range ctxt.Textp {
if s.FuncInfo == nil {
continue
}
@@ -1710,7 +1234,7 @@ func writeframes(prev *LSym) *LSym {
// Emit a FDE, Section 6.4.1.
// First build the section contents into a byte buffer.
deltaBuf = deltaBuf[:0]
- for pciterinit(Ctxt, &pcsp, &s.FuncInfo.Pcsp); pcsp.done == 0; pciternext(&pcsp) {
+ for pciterinit(ctxt, &pcsp, &s.FuncInfo.Pcsp); pcsp.done == 0; pciternext(&pcsp) {
nextpc := pcsp.nextpc
// pciterinit goes up to the end of the function,
@@ -1722,21 +1246,21 @@ func writeframes(prev *LSym) *LSym {
}
}
- if haslinkregister() {
+ if haslinkregister(ctxt) {
// TODO(bryanpkc): This is imprecise. In general, the instruction
// that stores the return address to the stack frame is not the
// same one that allocates the frame.
if pcsp.value > 0 {
// The return address is preserved at (CFA-frame_size)
// after a stack frame has been allocated.
- deltaBuf = append(deltaBuf, DW_CFA_offset_extended_sf)
- deltaBuf = appendUleb128(deltaBuf, uint64(Thearch.Dwarfreglr))
- deltaBuf = appendSleb128(deltaBuf, -int64(pcsp.value)/dataAlignmentFactor)
+ deltaBuf = append(deltaBuf, dwarf.DW_CFA_offset_extended_sf)
+ deltaBuf = dwarf.AppendUleb128(deltaBuf, uint64(Thearch.Dwarfreglr))
+ deltaBuf = dwarf.AppendSleb128(deltaBuf, -int64(pcsp.value)/dataAlignmentFactor)
} else {
// The return address is restored into the link register
// when a stack frame has been de-allocated.
- deltaBuf = append(deltaBuf, DW_CFA_same_value)
- deltaBuf = appendUleb128(deltaBuf, uint64(Thearch.Dwarfreglr))
+ deltaBuf = append(deltaBuf, dwarf.DW_CFA_same_value)
+ deltaBuf = dwarf.AppendUleb128(deltaBuf, uint64(Thearch.Dwarfreglr))
}
deltaBuf = appendPCDeltaCFA(deltaBuf, int64(nextpc)-int64(pcsp.pc), int64(pcsp.value))
} else {
@@ -1751,17 +1275,17 @@ func writeframes(prev *LSym) *LSym {
// 4 bytes: Pointer to the CIE above, at offset 0
// ptrsize: initial location
// ptrsize: address range
- Adduint32(Ctxt, fs, uint32(4+2*SysArch.PtrSize+len(deltaBuf))) // length (excludes itself)
+ Adduint32(ctxt, fs, uint32(4+2*SysArch.PtrSize+len(deltaBuf))) // length (excludes itself)
if Linkmode == LinkExternal {
- adddwarfref(Ctxt, fs, framesec, 4)
+ adddwarfref(ctxt, fs, framesec, 4)
} else {
- Adduint32(Ctxt, fs, 0) // CIE offset
+ Adduint32(ctxt, fs, 0) // CIE offset
}
- Addaddr(Ctxt, fs, s)
- addrput(fs, s.Size) // address range
- Addbytes(Ctxt, fs, deltaBuf)
+ Addaddr(ctxt, fs, s)
+ adduintxx(ctxt, fs, uint64(s.Size), SysArch.PtrSize) // address range
+ Addbytes(fs, deltaBuf)
}
- return fs
+ return syms
}
/*
@@ -1771,163 +1295,171 @@ const (
COMPUNITHEADERSIZE = 4 + 2 + 4 + 1
)
-func writeinfo(prev *LSym) *LSym {
+func writeinfo(ctxt *Link, syms []*Symbol, funcs []*Symbol) []*Symbol {
if infosec == nil {
- infosec = Linklookup(Ctxt, ".debug_info", 0)
+ infosec = ctxt.Syms.Lookup(".debug_info", 0)
}
infosec.R = infosec.R[:0]
infosec.Type = obj.SDWARFINFO
infosec.Attr |= AttrReachable
- prev.Next, prev = infosec, infosec
+ syms = append(syms, infosec)
if arangessec == nil {
- arangessec = Linklookup(Ctxt, ".dwarfaranges", 0)
+ arangessec = ctxt.Syms.Lookup(".dwarfaranges", 0)
}
arangessec.R = arangessec.R[:0]
- for compunit := dwroot.child; compunit != nil; compunit = compunit.link {
- s := compunit.sym
- prev.Next, prev = s, s
+ var dwarfctxt dwarf.Context = dwctxt{ctxt}
+
+ for compunit := dwroot.Child; compunit != nil; compunit = compunit.Link {
+ s := dtolsym(compunit.Sym)
// Write .debug_info Compilation Unit Header (sec 7.5.1)
// Fields marked with (*) must be changed for 64-bit dwarf
// This must match COMPUNITHEADERSIZE above.
- Adduint32(Ctxt, s, 0) // unit_length (*), will be filled in later.
- Adduint16(Ctxt, s, 2) // dwarf version (appendix F)
+ Adduint32(ctxt, s, 0) // unit_length (*), will be filled in later.
+ Adduint16(ctxt, s, 2) // dwarf version (appendix F)
// debug_abbrev_offset (*)
- adddwarfref(Ctxt, s, abbrevsym, 4)
+ adddwarfref(ctxt, s, abbrevsym, 4)
- Adduint8(Ctxt, s, uint8(SysArch.PtrSize)) // address_size
+ Adduint8(ctxt, s, uint8(SysArch.PtrSize)) // address_size
- prev = putdie(prev, compunit)
- cusize := s.Size - 4 // exclude the length field.
- for child := s.Next; child != nil; child = child.Next {
+ dwarf.Uleb128put(dwarfctxt, s, int64(compunit.Abbrev))
+ dwarf.PutAttrs(dwarfctxt, s, compunit.Abbrev, compunit.Attr)
+
+ cu := []*Symbol{s}
+ if funcs != nil {
+ cu = append(cu, funcs...)
+ funcs = nil
+ }
+ cu = putdies(ctxt, dwarfctxt, cu, compunit.Child)
+ var cusize int64
+ for _, child := range cu {
cusize += child.Size
}
-
- setuint32(Ctxt, s, 0, uint32(cusize))
- newattr(compunit, DW_AT_byte_size, DW_CLS_CONSTANT, cusize, 0)
+ cusize -= 4 // exclude the length field.
+ setuint32(ctxt, s, 0, uint32(cusize))
+ newattr(compunit, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, cusize, 0)
+ syms = append(syms, cu...)
}
- return prev
+ return syms
}
/*
* Emit .debug_pubnames/_types. _info must have been written before,
* because we need die->offs and infoo/infosize;
*/
-func ispubname(die *DWDie) bool {
- switch die.abbrev {
- case DW_ABRV_FUNCTION, DW_ABRV_VARIABLE:
- a := getattr(die, DW_AT_external)
- return a != nil && a.value != 0
+func ispubname(die *dwarf.DWDie) bool {
+ switch die.Abbrev {
+ case dwarf.DW_ABRV_FUNCTION, dwarf.DW_ABRV_VARIABLE:
+ a := getattr(die, dwarf.DW_AT_external)
+ return a != nil && a.Value != 0
}
return false
}
-func ispubtype(die *DWDie) bool {
- return die.abbrev >= DW_ABRV_NULLTYPE
+func ispubtype(die *dwarf.DWDie) bool {
+ return die.Abbrev >= dwarf.DW_ABRV_NULLTYPE
}
-func writepub(sname string, ispub func(*DWDie) bool, prev *LSym) *LSym {
- s := Linklookup(Ctxt, sname, 0)
+func writepub(ctxt *Link, sname string, ispub func(*dwarf.DWDie) bool, syms []*Symbol) []*Symbol {
+ s := ctxt.Syms.Lookup(sname, 0)
s.Type = obj.SDWARFSECT
- prev.Next = s
+ syms = append(syms, s)
- for compunit := dwroot.child; compunit != nil; compunit = compunit.link {
+ for compunit := dwroot.Child; compunit != nil; compunit = compunit.Link {
sectionstart := s.Size
- culength := uint32(getattr(compunit, DW_AT_byte_size).value) + 4
+ culength := uint32(getattr(compunit, dwarf.DW_AT_byte_size).Value) + 4
// Write .debug_pubnames/types Header (sec 6.1.1)
- Adduint32(Ctxt, s, 0) // unit_length (*), will be filled in later.
- Adduint16(Ctxt, s, 2) // dwarf version (appendix F)
- adddwarfref(Ctxt, s, compunit.sym, 4) // debug_info_offset (of the Comp unit Header)
- Adduint32(Ctxt, s, culength) // debug_info_length
+ Adduint32(ctxt, s, 0) // unit_length (*), will be filled in later.
+ Adduint16(ctxt, s, 2) // dwarf version (appendix F)
+ adddwarfref(ctxt, s, dtolsym(compunit.Sym), 4) // debug_info_offset (of the Comp unit Header)
+ Adduint32(ctxt, s, culength) // debug_info_length
- for die := compunit.child; die != nil; die = die.link {
+ for die := compunit.Child; die != nil; die = die.Link {
if !ispub(die) {
continue
}
- dwa := getattr(die, DW_AT_name)
- name := dwa.data.(string)
- if die.sym == nil {
+ dwa := getattr(die, dwarf.DW_AT_name)
+ name := dwa.Data.(string)
+ if die.Sym == nil {
fmt.Println("Missing sym for ", name)
}
- adddwarfref(Ctxt, s, die.sym, 4)
+ adddwarfref(ctxt, s, dtolsym(die.Sym), 4)
Addstring(s, name)
}
- Adduint32(Ctxt, s, 0)
+ Adduint32(ctxt, s, 0)
- setuint32(Ctxt, s, sectionstart, uint32(s.Size-sectionstart)-4) // exclude the length field.
+ setuint32(ctxt, s, sectionstart, uint32(s.Size-sectionstart)-4) // exclude the length field.
}
- return s
+ return syms
}
/*
* emit .debug_aranges. _info must have been written before,
- * because we need die->offs of dw_globals.
+ * because we need die->offs of dwarf.DW_globals.
*/
-func writearanges(prev *LSym) *LSym {
- s := Linklookup(Ctxt, ".debug_aranges", 0)
+func writearanges(ctxt *Link, syms []*Symbol) []*Symbol {
+ s := ctxt.Syms.Lookup(".debug_aranges", 0)
s.Type = obj.SDWARFSECT
// The first tuple is aligned to a multiple of the size of a single tuple
// (twice the size of an address)
headersize := int(Rnd(4+2+4+1+1, int64(SysArch.PtrSize*2))) // don't count unit_length field itself
- for compunit := dwroot.child; compunit != nil; compunit = compunit.link {
- b := getattr(compunit, DW_AT_low_pc)
+ for compunit := dwroot.Child; compunit != nil; compunit = compunit.Link {
+ b := getattr(compunit, dwarf.DW_AT_low_pc)
if b == nil {
continue
}
- e := getattr(compunit, DW_AT_high_pc)
+ e := getattr(compunit, dwarf.DW_AT_high_pc)
if e == nil {
continue
}
// Write .debug_aranges Header + entry (sec 6.1.2)
unitlength := uint32(headersize) + 4*uint32(SysArch.PtrSize) - 4
- Adduint32(Ctxt, s, unitlength) // unit_length (*)
- Adduint16(Ctxt, s, 2) // dwarf version (appendix F)
+ Adduint32(ctxt, s, unitlength) // unit_length (*)
+ Adduint16(ctxt, s, 2) // dwarf version (appendix F)
- adddwarfref(Ctxt, s, compunit.sym, 4)
+ adddwarfref(ctxt, s, dtolsym(compunit.Sym), 4)
- Adduint8(Ctxt, s, uint8(SysArch.PtrSize)) // address_size
- Adduint8(Ctxt, s, 0) // segment_size
+ Adduint8(ctxt, s, uint8(SysArch.PtrSize)) // address_size
+ Adduint8(ctxt, s, 0) // segment_size
padding := headersize - (4 + 2 + 4 + 1 + 1)
for i := 0; i < padding; i++ {
- Adduint8(Ctxt, s, 0)
+ Adduint8(ctxt, s, 0)
}
- Addaddrplus(Ctxt, s, b.data.(*LSym), b.value-(b.data.(*LSym)).Value)
- addrput(s, e.value-b.value)
- addrput(s, 0)
- addrput(s, 0)
+ Addaddrplus(ctxt, s, b.Data.(*Symbol), b.Value-(b.Data.(*Symbol)).Value)
+ adduintxx(ctxt, s, uint64(e.Value-b.Value), SysArch.PtrSize)
+ adduintxx(ctxt, s, 0, SysArch.PtrSize)
+ adduintxx(ctxt, s, 0, SysArch.PtrSize)
}
if s.Size > 0 {
- prev.Next = s
- prev = s
+ syms = append(syms, s)
}
- return prev
+ return syms
}
-func writegdbscript(prev *LSym) *LSym {
+func writegdbscript(ctxt *Link, syms []*Symbol) []*Symbol {
if gdbscript != "" {
- s := Linklookup(Ctxt, ".debug_gdb_scripts", 0)
+ s := ctxt.Syms.Lookup(".debug_gdb_scripts", 0)
s.Type = obj.SDWARFSECT
- prev.Next = s
- prev = s
- Adduint8(Ctxt, s, 1) // magic 1 byte?
+ syms = append(syms, s)
+ Adduint8(ctxt, s, 1) // magic 1 byte?
Addstring(s, gdbscript)
}
- return prev
+ return syms
}
-var prototypedies map[string]*DWDie
+var prototypedies map[string]*dwarf.DWDie
/*
* This is the main entry point for generating dwarf. After emitting
@@ -1938,43 +1470,43 @@ var prototypedies map[string]*DWDie
* passes.
*
*/
-func dwarfgeneratedebugsyms() {
- if Debug['w'] != 0 { // disable dwarf
+func dwarfgeneratedebugsyms(ctxt *Link) {
+ if *FlagW { // disable dwarf
return
}
- if Debug['s'] != 0 && HEADTYPE != obj.Hdarwin {
+ if *FlagS && Headtype != obj.Hdarwin {
return
}
- if HEADTYPE == obj.Hplan9 {
+ if Headtype == obj.Hplan9 {
return
}
if Linkmode == LinkExternal {
- if !Iself && HEADTYPE != obj.Hdarwin {
+ if !Iself && Headtype != obj.Hdarwin {
return
}
}
- if Debug['v'] != 0 {
- fmt.Fprintf(Bso, "%5.2f dwarf\n", obj.Cputime())
+ if ctxt.Debugvlog != 0 {
+ ctxt.Logf("%5.2f dwarf\n", obj.Cputime())
}
- // For diagnostic messages.
- newattr(&dwtypes, DW_AT_name, DW_CLS_STRING, int64(len("dwtypes")), "dwtypes")
+ // Forctxt.Diagnostic messages.
+ newattr(&dwtypes, dwarf.DW_AT_name, dwarf.DW_CLS_STRING, int64(len("dwtypes")), "dwtypes")
// Some types that must exist to define other ones.
- newdie(&dwtypes, DW_ABRV_NULLTYPE, "<unspecified>", 0)
+ newdie(ctxt, &dwtypes, dwarf.DW_ABRV_NULLTYPE, "<unspecified>", 0)
- newdie(&dwtypes, DW_ABRV_NULLTYPE, "void", 0)
- newdie(&dwtypes, DW_ABRV_BARE_PTRTYPE, "unsafe.Pointer", 0)
+ newdie(ctxt, &dwtypes, dwarf.DW_ABRV_NULLTYPE, "void", 0)
+ newdie(ctxt, &dwtypes, dwarf.DW_ABRV_BARE_PTRTYPE, "unsafe.Pointer", 0)
- die := newdie(&dwtypes, DW_ABRV_BASETYPE, "uintptr", 0) // needed for array size
- newattr(die, DW_AT_encoding, DW_CLS_CONSTANT, DW_ATE_unsigned, 0)
- newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, int64(SysArch.PtrSize), 0)
- newattr(die, DW_AT_go_kind, DW_CLS_CONSTANT, obj.KindUintptr, 0)
+ 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)
// Prototypes needed for type synthesis.
- prototypedies = map[string]*DWDie{
+ prototypedies = map[string]*dwarf.DWDie{
"type.runtime.stringStructDWARF": nil,
"type.runtime.slice": nil,
"type.runtime.hmap": nil,
@@ -1985,47 +1517,46 @@ func dwarfgeneratedebugsyms() {
}
// Needed by the prettyprinter code for interface inspection.
- defgotype(lookup_or_diag("type.runtime._type"))
+ defgotype(ctxt, lookupOrDiag(ctxt, "type.runtime._type"))
- defgotype(lookup_or_diag("type.runtime.interfacetype"))
- defgotype(lookup_or_diag("type.runtime.itab"))
+ defgotype(ctxt, lookupOrDiag(ctxt, "type.runtime.interfacetype"))
+ defgotype(ctxt, lookupOrDiag(ctxt, "type.runtime.itab"))
- genasmsym(defdwsymb)
+ genasmsym(ctxt, defdwsymb)
- dwarfp = writeabbrev()
- last := dwarfp
- last = writelines(last)
- last = writeframes(last)
+ syms := writeabbrev(ctxt, nil)
+ syms, funcs := writelines(ctxt, syms)
+ syms = writeframes(ctxt, syms)
- synthesizestringtypes(dwtypes.child)
- synthesizeslicetypes(dwtypes.child)
- synthesizemaptypes(dwtypes.child)
- synthesizechantypes(dwtypes.child)
+ synthesizestringtypes(ctxt, dwtypes.Child)
+ synthesizeslicetypes(ctxt, dwtypes.Child)
+ synthesizemaptypes(ctxt, dwtypes.Child)
+ synthesizechantypes(ctxt, dwtypes.Child)
- reversetree(&dwroot.child)
- reversetree(&dwtypes.child)
- reversetree(&dwglobals.child)
+ reversetree(&dwroot.Child)
+ reversetree(&dwtypes.Child)
+ reversetree(&dwglobals.Child)
movetomodule(&dwtypes)
movetomodule(&dwglobals)
// Need to reorder symbols so SDWARFINFO is after all SDWARFSECT
// (but we need to generate dies before writepub)
- writeinfo(last)
- infosyms := last.Next
-
- last = writepub(".debug_pubnames", ispubname, last)
- last = writepub(".debug_pubtypes", ispubtype, last)
- last = writearanges(last)
- last = writegdbscript(last)
- last.Next = infosyms
+ infosyms := writeinfo(ctxt, nil, funcs)
+
+ syms = writepub(ctxt, ".debug_pubnames", ispubname, syms)
+ syms = writepub(ctxt, ".debug_pubtypes", ispubtype, syms)
+ syms = writearanges(ctxt, syms)
+ syms = writegdbscript(ctxt, syms)
+ syms = append(syms, infosyms...)
+ dwarfp = syms
}
/*
* Elf.
*/
-func dwarfaddshstrings(shstrtab *LSym) {
- if Debug['w'] != 0 { // disable dwarf
+func dwarfaddshstrings(ctxt *Link, shstrtab *Symbol) {
+ if *FlagW { // disable dwarf
return
}
@@ -2049,36 +1580,35 @@ func dwarfaddshstrings(shstrtab *LSym) {
// Add section symbols for DWARF debug info. This is called before
// dwarfaddelfheaders.
-func dwarfaddelfsectionsyms() {
- if Debug['w'] != 0 { // disable dwarf
+func dwarfaddelfsectionsyms(ctxt *Link) {
+ if *FlagW { // disable dwarf
return
}
if Linkmode != LinkExternal {
return
}
- sym := Linklookup(Ctxt, ".debug_info", 0)
+ sym := ctxt.Syms.Lookup(".debug_info", 0)
putelfsectionsym(sym, sym.Sect.Elfsect.shnum)
- sym = Linklookup(Ctxt, ".debug_abbrev", 0)
+ sym = ctxt.Syms.Lookup(".debug_abbrev", 0)
putelfsectionsym(sym, sym.Sect.Elfsect.shnum)
- sym = Linklookup(Ctxt, ".debug_line", 0)
+ sym = ctxt.Syms.Lookup(".debug_line", 0)
putelfsectionsym(sym, sym.Sect.Elfsect.shnum)
- sym = Linklookup(Ctxt, ".debug_frame", 0)
+ sym = ctxt.Syms.Lookup(".debug_frame", 0)
putelfsectionsym(sym, sym.Sect.Elfsect.shnum)
}
/*
* Windows PE
*/
-func dwarfaddpeheaders() {
- if Debug['w'] != 0 { // disable dwarf
+func dwarfaddpeheaders(ctxt *Link) {
+ if *FlagW { // disable dwarf
return
}
for sect := Segdwarf.Sect; sect != nil; sect = sect.Next {
- h := newPEDWARFSection(sect.Name, int64(sect.Length))
+ h := newPEDWARFSection(ctxt, sect.Name, int64(sect.Length))
fileoff := sect.Vaddr - Segdwarf.Vaddr + Segdwarf.Fileoff
if uint64(h.PointerToRawData) != fileoff {
- Diag("%s.PointerToRawData = %#x, want %#x", sect.Name, h.PointerToRawData, fileoff)
- errorexit()
+ Exitf("%s.PointerToRawData = %#x, want %#x", sect.Name, h.PointerToRawData, fileoff)
}
}
}
diff --git a/src/cmd/link/internal/ld/dwarf_defs.go b/src/cmd/link/internal/ld/dwarf_defs.go
deleted file mode 100644
index c52879c..0000000
--- a/src/cmd/link/internal/ld/dwarf_defs.go
+++ /dev/null
@@ -1,516 +0,0 @@
-// Copyright 2010 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package ld
-
-// TODO/NICETOHAVE:
-// - eliminate DW_CLS_ if not used
-// - package info in compilation units
-// - assign global variables and types to their packages
-// - gdb uses c syntax, meaning clumsy quoting is needed for go identifiers. eg
-// ptype struct '[]uint8' and qualifiers need to be quoted away
-// - lexical scoping is lost, so gdb gets confused as to which 'obj.i' you mean.
-// - file:line info for variables
-// - make strings a typedef so prettyprinters can see the underlying string type
-//
-// Copyright 2010 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-/*
- * Emit debug_abbrevs, debug_info and debug_line sections to current
- * offset in cout.
- */
-
-/*
- * Add the dwarf section names to the ELF
- * s[ection]h[eader]str[ing]tab. Prerequisite for
- * dwarfaddelfheaders().
- */
-
-/*
- * Add section headers pointing to the sections emitted in
- * dwarfemitdebugsections.
- */
-// Copyright 2010 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// Cut, pasted, tr-and-awk'ed from tables in
-// http://dwarfstd.org/doc/Dwarf3.pdf
-
-// Table 18
-const (
- DW_TAG_array_type = 0x01
- DW_TAG_class_type = 0x02
- DW_TAG_entry_point = 0x03
- DW_TAG_enumeration_type = 0x04
- DW_TAG_formal_parameter = 0x05
- DW_TAG_imported_declaration = 0x08
- DW_TAG_label = 0x0a
- DW_TAG_lexical_block = 0x0b
- DW_TAG_member = 0x0d
- DW_TAG_pointer_type = 0x0f
- DW_TAG_reference_type = 0x10
- DW_TAG_compile_unit = 0x11
- DW_TAG_string_type = 0x12
- DW_TAG_structure_type = 0x13
- DW_TAG_subroutine_type = 0x15
- DW_TAG_typedef = 0x16
- DW_TAG_union_type = 0x17
- DW_TAG_unspecified_parameters = 0x18
- DW_TAG_variant = 0x19
- DW_TAG_common_block = 0x1a
- DW_TAG_common_inclusion = 0x1b
- DW_TAG_inheritance = 0x1c
- DW_TAG_inlined_subroutine = 0x1d
- DW_TAG_module = 0x1e
- DW_TAG_ptr_to_member_type = 0x1f
- DW_TAG_set_type = 0x20
- DW_TAG_subrange_type = 0x21
- DW_TAG_with_stmt = 0x22
- DW_TAG_access_declaration = 0x23
- DW_TAG_base_type = 0x24
- DW_TAG_catch_block = 0x25
- DW_TAG_const_type = 0x26
- DW_TAG_constant = 0x27
- DW_TAG_enumerator = 0x28
- DW_TAG_file_type = 0x29
- DW_TAG_friend = 0x2a
- DW_TAG_namelist = 0x2b
- DW_TAG_namelist_item = 0x2c
- DW_TAG_packed_type = 0x2d
- DW_TAG_subprogram = 0x2e
- DW_TAG_template_type_parameter = 0x2f
- DW_TAG_template_value_parameter = 0x30
- DW_TAG_thrown_type = 0x31
- DW_TAG_try_block = 0x32
- DW_TAG_variant_part = 0x33
- DW_TAG_variable = 0x34
- DW_TAG_volatile_type = 0x35
- // Dwarf3
- DW_TAG_dwarf_procedure = 0x36
- DW_TAG_restrict_type = 0x37
- DW_TAG_interface_type = 0x38
- DW_TAG_namespace = 0x39
- DW_TAG_imported_module = 0x3a
- DW_TAG_unspecified_type = 0x3b
- DW_TAG_partial_unit = 0x3c
- DW_TAG_imported_unit = 0x3d
- DW_TAG_condition = 0x3f
- DW_TAG_shared_type = 0x40
- // Dwarf4
- DW_TAG_type_unit = 0x41
- DW_TAG_rvalue_reference_type = 0x42
- DW_TAG_template_alias = 0x43
-
- // User defined
- DW_TAG_lo_user = 0x4080
- DW_TAG_hi_user = 0xffff
-)
-
-// Table 19
-const (
- DW_CHILDREN_no = 0x00
- DW_CHILDREN_yes = 0x01
-)
-
-// Not from the spec, but logically belongs here
-const (
- DW_CLS_ADDRESS = 0x01 + iota
- DW_CLS_BLOCK
- DW_CLS_CONSTANT
- DW_CLS_FLAG
- DW_CLS_PTR // lineptr, loclistptr, macptr, rangelistptr
- DW_CLS_REFERENCE
- DW_CLS_ADDRLOC
- DW_CLS_STRING
-)
-
-// Table 20
-const (
- DW_AT_sibling = 0x01 // reference
- DW_AT_location = 0x02 // block, loclistptr
- DW_AT_name = 0x03 // string
- DW_AT_ordering = 0x09 // constant
- DW_AT_byte_size = 0x0b // block, constant, reference
- DW_AT_bit_offset = 0x0c // block, constant, reference
- DW_AT_bit_size = 0x0d // block, constant, reference
- DW_AT_stmt_list = 0x10 // lineptr
- DW_AT_low_pc = 0x11 // address
- DW_AT_high_pc = 0x12 // address
- DW_AT_language = 0x13 // constant
- DW_AT_discr = 0x15 // reference
- DW_AT_discr_value = 0x16 // constant
- DW_AT_visibility = 0x17 // constant
- DW_AT_import = 0x18 // reference
- DW_AT_string_length = 0x19 // block, loclistptr
- DW_AT_common_reference = 0x1a // reference
- DW_AT_comp_dir = 0x1b // string
- DW_AT_const_value = 0x1c // block, constant, string
- DW_AT_containing_type = 0x1d // reference
- DW_AT_default_value = 0x1e // reference
- DW_AT_inline = 0x20 // constant
- DW_AT_is_optional = 0x21 // flag
- DW_AT_lower_bound = 0x22 // block, constant, reference
- DW_AT_producer = 0x25 // string
- DW_AT_prototyped = 0x27 // flag
- DW_AT_return_addr = 0x2a // block, loclistptr
- DW_AT_start_scope = 0x2c // constant
- DW_AT_bit_stride = 0x2e // constant
- DW_AT_upper_bound = 0x2f // block, constant, reference
- DW_AT_abstract_origin = 0x31 // reference
- DW_AT_accessibility = 0x32 // constant
- DW_AT_address_class = 0x33 // constant
- DW_AT_artificial = 0x34 // flag
- DW_AT_base_types = 0x35 // reference
- DW_AT_calling_convention = 0x36 // constant
- DW_AT_count = 0x37 // block, constant, reference
- DW_AT_data_member_location = 0x38 // block, constant, loclistptr
- DW_AT_decl_column = 0x39 // constant
- DW_AT_decl_file = 0x3a // constant
- DW_AT_decl_line = 0x3b // constant
- DW_AT_declaration = 0x3c // flag
- DW_AT_discr_list = 0x3d // block
- DW_AT_encoding = 0x3e // constant
- DW_AT_external = 0x3f // flag
- DW_AT_frame_base = 0x40 // block, loclistptr
- DW_AT_friend = 0x41 // reference
- DW_AT_identifier_case = 0x42 // constant
- DW_AT_macro_info = 0x43 // macptr
- DW_AT_namelist_item = 0x44 // block
- DW_AT_priority = 0x45 // reference
- DW_AT_segment = 0x46 // block, loclistptr
- DW_AT_specification = 0x47 // reference
- DW_AT_static_link = 0x48 // block, loclistptr
- DW_AT_type = 0x49 // reference
- DW_AT_use_location = 0x4a // block, loclistptr
- DW_AT_variable_parameter = 0x4b // flag
- DW_AT_virtuality = 0x4c // constant
- DW_AT_vtable_elem_location = 0x4d // block, loclistptr
- // Dwarf3
- DW_AT_allocated = 0x4e // block, constant, reference
- DW_AT_associated = 0x4f // block, constant, reference
- DW_AT_data_location = 0x50 // block
- DW_AT_byte_stride = 0x51 // block, constant, reference
- DW_AT_entry_pc = 0x52 // address
- DW_AT_use_UTF8 = 0x53 // flag
- DW_AT_extension = 0x54 // reference
- DW_AT_ranges = 0x55 // rangelistptr
- DW_AT_trampoline = 0x56 // address, flag, reference, string
- DW_AT_call_column = 0x57 // constant
- DW_AT_call_file = 0x58 // constant
- DW_AT_call_line = 0x59 // constant
- DW_AT_description = 0x5a // string
- DW_AT_binary_scale = 0x5b // constant
- DW_AT_decimal_scale = 0x5c // constant
- DW_AT_small = 0x5d // reference
- DW_AT_decimal_sign = 0x5e // constant
- DW_AT_digit_count = 0x5f // constant
- DW_AT_picture_string = 0x60 // string
- DW_AT_mutable = 0x61 // flag
- DW_AT_threads_scaled = 0x62 // flag
- DW_AT_explicit = 0x63 // flag
- DW_AT_object_pointer = 0x64 // reference
- DW_AT_endianity = 0x65 // constant
- DW_AT_elemental = 0x66 // flag
- DW_AT_pure = 0x67 // flag
- DW_AT_recursive = 0x68 // flag
-
- DW_AT_lo_user = 0x2000 // ---
- DW_AT_hi_user = 0x3fff // ---
-)
-
-// Table 21
-const (
- DW_FORM_addr = 0x01 // address
- DW_FORM_block2 = 0x03 // block
- DW_FORM_block4 = 0x04 // block
- DW_FORM_data2 = 0x05 // constant
- DW_FORM_data4 = 0x06 // constant, lineptr, loclistptr, macptr, rangelistptr
- DW_FORM_data8 = 0x07 // constant, lineptr, loclistptr, macptr, rangelistptr
- DW_FORM_string = 0x08 // string
- DW_FORM_block = 0x09 // block
- DW_FORM_block1 = 0x0a // block
- DW_FORM_data1 = 0x0b // constant
- DW_FORM_flag = 0x0c // flag
- DW_FORM_sdata = 0x0d // constant
- DW_FORM_strp = 0x0e // string
- DW_FORM_udata = 0x0f // constant
- DW_FORM_ref_addr = 0x10 // reference
- DW_FORM_ref1 = 0x11 // reference
- DW_FORM_ref2 = 0x12 // reference
- DW_FORM_ref4 = 0x13 // reference
- DW_FORM_ref8 = 0x14 // reference
- DW_FORM_ref_udata = 0x15 // reference
- DW_FORM_indirect = 0x16 // (see Section 7.5.3)
-)
-
-// Table 24 (#operands, notes)
-const (
- DW_OP_addr = 0x03 // 1 constant address (size target specific)
- DW_OP_deref = 0x06 // 0
- DW_OP_const1u = 0x08 // 1 1-byte constant
- DW_OP_const1s = 0x09 // 1 1-byte constant
- DW_OP_const2u = 0x0a // 1 2-byte constant
- DW_OP_const2s = 0x0b // 1 2-byte constant
- DW_OP_const4u = 0x0c // 1 4-byte constant
- DW_OP_const4s = 0x0d // 1 4-byte constant
- DW_OP_const8u = 0x0e // 1 8-byte constant
- DW_OP_const8s = 0x0f // 1 8-byte constant
- DW_OP_constu = 0x10 // 1 ULEB128 constant
- DW_OP_consts = 0x11 // 1 SLEB128 constant
- DW_OP_dup = 0x12 // 0
- DW_OP_drop = 0x13 // 0
- DW_OP_over = 0x14 // 0
- DW_OP_pick = 0x15 // 1 1-byte stack index
- DW_OP_swap = 0x16 // 0
- DW_OP_rot = 0x17 // 0
- DW_OP_xderef = 0x18 // 0
- DW_OP_abs = 0x19 // 0
- DW_OP_and = 0x1a // 0
- DW_OP_div = 0x1b // 0
- DW_OP_minus = 0x1c // 0
- DW_OP_mod = 0x1d // 0
- DW_OP_mul = 0x1e // 0
- DW_OP_neg = 0x1f // 0
- DW_OP_not = 0x20 // 0
- DW_OP_or = 0x21 // 0
- DW_OP_plus = 0x22 // 0
- DW_OP_plus_uconst = 0x23 // 1 ULEB128 addend
- DW_OP_shl = 0x24 // 0
- DW_OP_shr = 0x25 // 0
- DW_OP_shra = 0x26 // 0
- DW_OP_xor = 0x27 // 0
- DW_OP_skip = 0x2f // 1 signed 2-byte constant
- DW_OP_bra = 0x28 // 1 signed 2-byte constant
- DW_OP_eq = 0x29 // 0
- DW_OP_ge = 0x2a // 0
- DW_OP_gt = 0x2b // 0
- DW_OP_le = 0x2c // 0
- DW_OP_lt = 0x2d // 0
- DW_OP_ne = 0x2e // 0
- DW_OP_lit0 = 0x30 // 0 ...
- DW_OP_lit31 = 0x4f // 0 literals 0..31 = (DW_OP_lit0 + literal)
- DW_OP_reg0 = 0x50 // 0 ..
- DW_OP_reg31 = 0x6f // 0 reg 0..31 = (DW_OP_reg0 + regnum)
- DW_OP_breg0 = 0x70 // 1 ...
- DW_OP_breg31 = 0x8f // 1 SLEB128 offset base register 0..31 = (DW_OP_breg0 + regnum)
- DW_OP_regx = 0x90 // 1 ULEB128 register
- DW_OP_fbreg = 0x91 // 1 SLEB128 offset
- DW_OP_bregx = 0x92 // 2 ULEB128 register followed by SLEB128 offset
- DW_OP_piece = 0x93 // 1 ULEB128 size of piece addressed
- DW_OP_deref_size = 0x94 // 1 1-byte size of data retrieved
- DW_OP_xderef_size = 0x95 // 1 1-byte size of data retrieved
- DW_OP_nop = 0x96 // 0
- DW_OP_push_object_address = 0x97 // 0
- DW_OP_call2 = 0x98 // 1 2-byte offset of DIE
- DW_OP_call4 = 0x99 // 1 4-byte offset of DIE
- DW_OP_call_ref = 0x9a // 1 4- or 8-byte offset of DIE
- DW_OP_form_tls_address = 0x9b // 0
- DW_OP_call_frame_cfa = 0x9c // 0
- DW_OP_bit_piece = 0x9d // 2
- DW_OP_lo_user = 0xe0
- DW_OP_hi_user = 0xff
-)
-
-// Table 25
-const (
- DW_ATE_address = 0x01
- DW_ATE_boolean = 0x02
- DW_ATE_complex_float = 0x03
- DW_ATE_float = 0x04
- DW_ATE_signed = 0x05
- DW_ATE_signed_char = 0x06
- DW_ATE_unsigned = 0x07
- DW_ATE_unsigned_char = 0x08
- DW_ATE_imaginary_float = 0x09
- DW_ATE_packed_decimal = 0x0a
- DW_ATE_numeric_string = 0x0b
- DW_ATE_edited = 0x0c
- DW_ATE_signed_fixed = 0x0d
- DW_ATE_unsigned_fixed = 0x0e
- DW_ATE_decimal_float = 0x0f
- DW_ATE_lo_user = 0x80
- DW_ATE_hi_user = 0xff
-)
-
-// Table 26
-const (
- DW_DS_unsigned = 0x01
- DW_DS_leading_overpunch = 0x02
- DW_DS_trailing_overpunch = 0x03
- DW_DS_leading_separate = 0x04
- DW_DS_trailing_separate = 0x05
-)
-
-// Table 27
-const (
- DW_END_default = 0x00
- DW_END_big = 0x01
- DW_END_little = 0x02
- DW_END_lo_user = 0x40
- DW_END_hi_user = 0xff
-)
-
-// Table 28
-const (
- DW_ACCESS_public = 0x01
- DW_ACCESS_protected = 0x02
- DW_ACCESS_private = 0x03
-)
-
-// Table 29
-const (
- DW_VIS_local = 0x01
- DW_VIS_exported = 0x02
- DW_VIS_qualified = 0x03
-)
-
-// Table 30
-const (
- DW_VIRTUALITY_none = 0x00
- DW_VIRTUALITY_virtual = 0x01
- DW_VIRTUALITY_pure_virtual = 0x02
-)
-
-// Table 31
-const (
- DW_LANG_C89 = 0x0001
- DW_LANG_C = 0x0002
- DW_LANG_Ada83 = 0x0003
- DW_LANG_C_plus_plus = 0x0004
- DW_LANG_Cobol74 = 0x0005
- DW_LANG_Cobol85 = 0x0006
- DW_LANG_Fortran77 = 0x0007
- DW_LANG_Fortran90 = 0x0008
- DW_LANG_Pascal83 = 0x0009
- DW_LANG_Modula2 = 0x000a
- // Dwarf3
- DW_LANG_Java = 0x000b
- DW_LANG_C99 = 0x000c
- DW_LANG_Ada95 = 0x000d
- DW_LANG_Fortran95 = 0x000e
- DW_LANG_PLI = 0x000f
- DW_LANG_ObjC = 0x0010
- DW_LANG_ObjC_plus_plus = 0x0011
- DW_LANG_UPC = 0x0012
- DW_LANG_D = 0x0013
- // Dwarf4
- DW_LANG_Python = 0x0014
- // Dwarf5
- DW_LANG_Go = 0x0016
-
- DW_LANG_lo_user = 0x8000
- DW_LANG_hi_user = 0xffff
-)
-
-// Table 32
-const (
- DW_ID_case_sensitive = 0x00
- DW_ID_up_case = 0x01
- DW_ID_down_case = 0x02
- DW_ID_case_insensitive = 0x03
-)
-
-// Table 33
-const (
- DW_CC_normal = 0x01
- DW_CC_program = 0x02
- DW_CC_nocall = 0x03
- DW_CC_lo_user = 0x40
- DW_CC_hi_user = 0xff
-)
-
-// Table 34
-const (
- DW_INL_not_inlined = 0x00
- DW_INL_inlined = 0x01
- DW_INL_declared_not_inlined = 0x02
- DW_INL_declared_inlined = 0x03
-)
-
-// Table 35
-const (
- DW_ORD_row_major = 0x00
- DW_ORD_col_major = 0x01
-)
-
-// Table 36
-const (
- DW_DSC_label = 0x00
- DW_DSC_range = 0x01
-)
-
-// Table 37
-const (
- DW_LNS_copy = 0x01
- DW_LNS_advance_pc = 0x02
- DW_LNS_advance_line = 0x03
- DW_LNS_set_file = 0x04
- DW_LNS_set_column = 0x05
- DW_LNS_negate_stmt = 0x06
- DW_LNS_set_basic_block = 0x07
- DW_LNS_const_add_pc = 0x08
- DW_LNS_fixed_advance_pc = 0x09
- // Dwarf3
- DW_LNS_set_prologue_end = 0x0a
- DW_LNS_set_epilogue_begin = 0x0b
- DW_LNS_set_isa = 0x0c
-)
-
-// Table 38
-const (
- DW_LNE_end_sequence = 0x01
- DW_LNE_set_address = 0x02
- DW_LNE_define_file = 0x03
- DW_LNE_lo_user = 0x80
- DW_LNE_hi_user = 0xff
-)
-
-// Table 39
-const (
- DW_MACINFO_define = 0x01
- DW_MACINFO_undef = 0x02
- DW_MACINFO_start_file = 0x03
- DW_MACINFO_end_file = 0x04
- DW_MACINFO_vendor_ext = 0xff
-)
-
-// Table 40.
-const (
- // operand,...
- DW_CFA_nop = 0x00
- DW_CFA_set_loc = 0x01 // address
- DW_CFA_advance_loc1 = 0x02 // 1-byte delta
- DW_CFA_advance_loc2 = 0x03 // 2-byte delta
- DW_CFA_advance_loc4 = 0x04 // 4-byte delta
- DW_CFA_offset_extended = 0x05 // ULEB128 register, ULEB128 offset
- DW_CFA_restore_extended = 0x06 // ULEB128 register
- DW_CFA_undefined = 0x07 // ULEB128 register
- DW_CFA_same_value = 0x08 // ULEB128 register
- DW_CFA_register = 0x09 // ULEB128 register, ULEB128 register
- DW_CFA_remember_state = 0x0a
- DW_CFA_restore_state = 0x0b
-
- DW_CFA_def_cfa = 0x0c // ULEB128 register, ULEB128 offset
- DW_CFA_def_cfa_register = 0x0d // ULEB128 register
- DW_CFA_def_cfa_offset = 0x0e // ULEB128 offset
- DW_CFA_def_cfa_expression = 0x0f // BLOCK
- DW_CFA_expression = 0x10 // ULEB128 register, BLOCK
- DW_CFA_offset_extended_sf = 0x11 // ULEB128 register, SLEB128 offset
- DW_CFA_def_cfa_sf = 0x12 // ULEB128 register, SLEB128 offset
- DW_CFA_def_cfa_offset_sf = 0x13 // SLEB128 offset
- DW_CFA_val_offset = 0x14 // ULEB128, ULEB128
- DW_CFA_val_offset_sf = 0x15 // ULEB128, SLEB128
- DW_CFA_val_expression = 0x16 // ULEB128, BLOCK
-
- DW_CFA_lo_user = 0x1c
- DW_CFA_hi_user = 0x3f
-
- // Opcodes that take an addend operand.
- DW_CFA_advance_loc = 0x1 << 6 // +delta
- DW_CFA_offset = 0x2 << 6 // +register (ULEB128 offset)
- DW_CFA_restore = 0x3 << 6 // +register
-)
diff --git a/src/cmd/link/internal/ld/elf.go b/src/cmd/link/internal/ld/elf.go
index 39d3609..b4d5aae 100644
--- a/src/cmd/link/internal/ld/elf.go
+++ b/src/cmd/link/internal/ld/elf.go
@@ -66,10 +66,10 @@ import (
* padded to a word boundary. The values of n_namesz and n_descsz do
* not include the padding.
*/
-type Elf_Note struct {
- n_namesz uint32
- n_descsz uint32
- n_type uint32
+type elfNote struct {
+ nNamesz uint32
+ nDescsz uint32
+ nType uint32
}
const (
@@ -236,7 +236,9 @@ const (
PT_LOPROC = 0x70000000
PT_HIPROC = 0x7fffffff
PT_GNU_STACK = 0x6474e551
+ PT_GNU_RELRO = 0x6474e552
PT_PAX_FLAGS = 0x65041580
+ PT_SUNWSTACK = 0x6ffffffb
PF_X = 0x1
PF_W = 0x2
PF_R = 0x4
@@ -806,7 +808,7 @@ type ElfShdr struct {
addralign uint64
entsize uint64
shnum int
- secsym *LSym
+ secsym *Symbol
}
/*
@@ -878,7 +880,7 @@ const (
* written in the 32-bit format on the 32-bit machines.
*/
const (
- NSECT = 48
+ NSECT = 400
)
var (
@@ -913,7 +915,7 @@ var buildinfo []byte
Initialize the global variable that describes the ELF header. It will be updated as
we write section and prog headers.
*/
-func Elfinit() {
+func Elfinit(ctxt *Link) {
Iself = true
if SysArch.InFamily(sys.AMD64, sys.ARM64, sys.MIPS64, sys.PPC64, sys.S390X) {
@@ -925,7 +927,7 @@ func Elfinit() {
switch SysArch.Family {
// 64-bit architectures
case sys.PPC64, sys.S390X:
- if Ctxt.Arch.ByteOrder == binary.BigEndian {
+ if ctxt.Arch.ByteOrder == binary.BigEndian {
ehdr.flags = 1 /* Version 1 ABI */
} else {
ehdr.flags = 2 /* Version 2 ABI */
@@ -943,20 +945,23 @@ func Elfinit() {
ehdr.phentsize = ELF64PHDRSIZE /* Must be ELF64PHDRSIZE */
ehdr.shentsize = ELF64SHDRSIZE /* Must be ELF64SHDRSIZE */
- // we use EABI on both linux/arm and freebsd/arm.
// 32-bit architectures
- case sys.ARM:
- // we use EABI on both linux/arm and freebsd/arm.
- if HEADTYPE == obj.Hlinux || HEADTYPE == obj.Hfreebsd {
- // We set a value here that makes no indication of which
- // float ABI the object uses, because this is information
- // used by the dynamic linker to compare executables and
- // shared libraries -- so it only matters for cgo calls, and
- // the information properly comes from the object files
- // produced by the host C compiler. parseArmAttributes in
- // ldelf.go reads that information and updates this field as
- // appropriate.
- ehdr.flags = 0x5000002 // has entry point, Version5 EABI
+ 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 {
+ // 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
+ // shared libraries -- so it only matters for cgo calls, and
+ // the information properly comes from the object files
+ // produced by the host C compiler. parseArmAttributes in
+ // ldelf.go reads that information and updates this field as
+ // appropriate.
+ ehdr.flags = 0x5000002 // has entry point, Version5 EABI
+ }
+ } else if SysArch.Family == sys.MIPS {
+ ehdr.flags = 0x50000000 /* MIPS 32 */
}
fallthrough
default:
@@ -1054,13 +1059,13 @@ func elfwriteshdrs() uint32 {
return uint32(ehdr.shnum) * ELF32SHDRSIZE
}
-func elfsetstring(s string, off int) {
+func elfsetstring(s *Symbol, str string, off int) {
if nelfstr >= len(elfstr) {
- Diag("too many elf strings")
+ Errorf(s, "too many elf strings")
errorexit()
}
- elfstr[nelfstr].s = s
+ elfstr[nelfstr].s = str
elfstr[nelfstr].off = off
nelfstr++
}
@@ -1082,7 +1087,7 @@ func elfwritephdrs() uint32 {
func newElfPhdr() *ElfPhdr {
e := new(ElfPhdr)
if ehdr.phnum >= NSECT {
- Diag("too many phdrs")
+ Errorf(nil, "too many phdrs")
} else {
phdr[ehdr.phnum] = e
ehdr.phnum++
@@ -1100,7 +1105,7 @@ func newElfShdr(name int64) *ElfShdr {
e.name = uint32(name)
e.shnum = int(ehdr.shnum)
if ehdr.shnum >= NSECT {
- Diag("too many shdrs")
+ Errorf(nil, "too many shdrs")
} else {
shdr[ehdr.shnum] = e
ehdr.shnum++
@@ -1173,36 +1178,36 @@ func elfhash(name string) uint32 {
return h
}
-func Elfwritedynent(s *LSym, tag int, val uint64) {
+func Elfwritedynent(ctxt *Link, s *Symbol, tag int, val uint64) {
if elf64 {
- Adduint64(Ctxt, s, uint64(tag))
- Adduint64(Ctxt, s, val)
+ Adduint64(ctxt, s, uint64(tag))
+ Adduint64(ctxt, s, val)
} else {
- Adduint32(Ctxt, s, uint32(tag))
- Adduint32(Ctxt, s, uint32(val))
+ Adduint32(ctxt, s, uint32(tag))
+ Adduint32(ctxt, s, uint32(val))
}
}
-func elfwritedynentsym(s *LSym, tag int, t *LSym) {
- Elfwritedynentsymplus(s, tag, t, 0)
+func elfwritedynentsym(ctxt *Link, s *Symbol, tag int, t *Symbol) {
+ Elfwritedynentsymplus(ctxt, s, tag, t, 0)
}
-func Elfwritedynentsymplus(s *LSym, tag int, t *LSym, add int64) {
+func Elfwritedynentsymplus(ctxt *Link, s *Symbol, tag int, t *Symbol, add int64) {
if elf64 {
- Adduint64(Ctxt, s, uint64(tag))
+ Adduint64(ctxt, s, uint64(tag))
} else {
- Adduint32(Ctxt, s, uint32(tag))
+ Adduint32(ctxt, s, uint32(tag))
}
- Addaddrplus(Ctxt, s, t, add)
+ Addaddrplus(ctxt, s, t, add)
}
-func elfwritedynentsymsize(s *LSym, tag int, t *LSym) {
+func elfwritedynentsymsize(ctxt *Link, s *Symbol, tag int, t *Symbol) {
if elf64 {
- Adduint64(Ctxt, s, uint64(tag))
+ Adduint64(ctxt, s, uint64(tag))
} else {
- Adduint32(Ctxt, s, uint32(tag))
+ Adduint32(ctxt, s, uint32(tag))
}
- addsize(Ctxt, s, t)
+ addsize(ctxt, s, t)
}
func elfinterp(sh *ElfShdr, startva uint64, resoff uint64, p string) int {
@@ -1355,7 +1360,7 @@ func elfbuildinfo(sh *ElfShdr, startva uint64, resoff uint64) int {
}
func elfgobuildid(sh *ElfShdr, startva uint64, resoff uint64) int {
- n := len(ELF_NOTE_GO_NAME) + int(Rnd(int64(len(buildid)), 4))
+ n := len(ELF_NOTE_GO_NAME) + int(Rnd(int64(len(*flagBuildid)), 4))
return elfnote(sh, startva, resoff, n, true)
}
@@ -1374,15 +1379,15 @@ func elfwritebuildinfo() int {
}
func elfwritegobuildid() int {
- sh := elfwritenotehdr(".note.go.buildid", uint32(len(ELF_NOTE_GO_NAME)), uint32(len(buildid)), ELF_NOTE_GOBUILDID_TAG)
+ sh := elfwritenotehdr(".note.go.buildid", uint32(len(ELF_NOTE_GO_NAME)), uint32(len(*flagBuildid)), ELF_NOTE_GOBUILDID_TAG)
if sh == nil {
return 0
}
Cwrite(ELF_NOTE_GO_NAME)
- Cwrite([]byte(buildid))
+ Cwrite([]byte(*flagBuildid))
var zero = make([]byte, 4)
- Cwrite(zero[:int(Rnd(int64(len(buildid)), 4)-int64(len(buildid)))])
+ Cwrite(zero[:int(Rnd(int64(len(*flagBuildid)), 4)-int64(len(*flagBuildid)))])
return int(sh.size)
}
@@ -1438,13 +1443,13 @@ havelib:
return aux
}
-func elfdynhash() {
+func elfdynhash(ctxt *Link) {
if !Iself {
return
}
nsym := Nelfsym
- s := Linklookup(Ctxt, ".hash", 0)
+ s := ctxt.Syms.Lookup(".hash", 0)
s.Type = obj.SELFROSECT
s.Attr |= AttrReachable
@@ -1461,7 +1466,7 @@ func elfdynhash() {
buckets := make([]uint32, nbucket)
var b int
- for _, sy := range Ctxt.Allsym {
+ for _, sy := range ctxt.Syms.Allsym {
if sy.Dynid <= 0 {
continue
}
@@ -1480,29 +1485,29 @@ func elfdynhash() {
// s390x (ELF64) hash table entries are 8 bytes
if SysArch.Family == sys.S390X {
- Adduint64(Ctxt, s, uint64(nbucket))
- Adduint64(Ctxt, s, uint64(nsym))
+ Adduint64(ctxt, s, uint64(nbucket))
+ Adduint64(ctxt, s, uint64(nsym))
for i := 0; i < nbucket; i++ {
- Adduint64(Ctxt, s, uint64(buckets[i]))
+ Adduint64(ctxt, s, uint64(buckets[i]))
}
for i := 0; i < nsym; i++ {
- Adduint64(Ctxt, s, uint64(chain[i]))
+ Adduint64(ctxt, s, uint64(chain[i]))
}
} else {
- Adduint32(Ctxt, s, uint32(nbucket))
- Adduint32(Ctxt, s, uint32(nsym))
+ Adduint32(ctxt, s, uint32(nbucket))
+ Adduint32(ctxt, s, uint32(nsym))
for i := 0; i < nbucket; i++ {
- Adduint32(Ctxt, s, buckets[i])
+ Adduint32(ctxt, s, buckets[i])
}
for i := 0; i < nsym; i++ {
- Adduint32(Ctxt, s, chain[i])
+ Adduint32(ctxt, s, chain[i])
}
}
// version symbols
- dynstr := Linklookup(Ctxt, ".dynstr", 0)
+ dynstr := ctxt.Syms.Lookup(".dynstr", 0)
- s = Linklookup(Ctxt, ".gnu.version_r", 0)
+ s = ctxt.Syms.Lookup(".gnu.version_r", 0)
i = 2
nfile := 0
var j int
@@ -1511,18 +1516,18 @@ func elfdynhash() {
nfile++
// header
- Adduint16(Ctxt, s, 1) // table version
+ Adduint16(ctxt, s, 1) // table version
j = 0
for x = l.aux; x != nil; x = x.next {
j++
}
- Adduint16(Ctxt, s, uint16(j)) // aux count
- Adduint32(Ctxt, s, uint32(Addstring(dynstr, l.file))) // file string offset
- Adduint32(Ctxt, s, 16) // offset from header to first aux
+ Adduint16(ctxt, s, uint16(j)) // aux count
+ Adduint32(ctxt, s, uint32(Addstring(dynstr, l.file))) // file string offset
+ Adduint32(ctxt, s, 16) // offset from header to first aux
if l.next != nil {
- Adduint32(Ctxt, s, 16+uint32(j)*16) // offset from this header to next
+ Adduint32(ctxt, s, 16+uint32(j)*16) // offset from this header to next
} else {
- Adduint32(Ctxt, s, 0)
+ Adduint32(ctxt, s, 0)
}
for x = l.aux; x != nil; x = x.next {
@@ -1530,51 +1535,51 @@ func elfdynhash() {
i++
// aux struct
- Adduint32(Ctxt, s, elfhash(x.vers)) // hash
- Adduint16(Ctxt, s, 0) // flags
- Adduint16(Ctxt, s, uint16(x.num)) // other - index we refer to this by
- Adduint32(Ctxt, s, uint32(Addstring(dynstr, x.vers))) // version string offset
+ Adduint32(ctxt, s, elfhash(x.vers)) // hash
+ Adduint16(ctxt, s, 0) // flags
+ Adduint16(ctxt, s, uint16(x.num)) // other - index we refer to this by
+ Adduint32(ctxt, s, uint32(Addstring(dynstr, x.vers))) // version string offset
if x.next != nil {
- Adduint32(Ctxt, s, 16) // offset from this aux to next
+ Adduint32(ctxt, s, 16) // offset from this aux to next
} else {
- Adduint32(Ctxt, s, 0)
+ Adduint32(ctxt, s, 0)
}
}
}
// version references
- s = Linklookup(Ctxt, ".gnu.version", 0)
+ s = ctxt.Syms.Lookup(".gnu.version", 0)
for i := 0; i < nsym; i++ {
if i == 0 {
- Adduint16(Ctxt, s, 0) // first entry - no symbol
+ Adduint16(ctxt, s, 0) // first entry - no symbol
} else if need[i] == nil {
- Adduint16(Ctxt, s, 1) // global
+ Adduint16(ctxt, s, 1) // global
} else {
- Adduint16(Ctxt, s, uint16(need[i].num))
+ Adduint16(ctxt, s, uint16(need[i].num))
}
}
- s = Linklookup(Ctxt, ".dynamic", 0)
+ s = ctxt.Syms.Lookup(".dynamic", 0)
elfverneed = nfile
if elfverneed != 0 {
- elfwritedynentsym(s, DT_VERNEED, Linklookup(Ctxt, ".gnu.version_r", 0))
- Elfwritedynent(s, DT_VERNEEDNUM, uint64(nfile))
- elfwritedynentsym(s, DT_VERSYM, Linklookup(Ctxt, ".gnu.version", 0))
+ elfwritedynentsym(ctxt, s, DT_VERNEED, ctxt.Syms.Lookup(".gnu.version_r", 0))
+ Elfwritedynent(ctxt, s, DT_VERNEEDNUM, uint64(nfile))
+ elfwritedynentsym(ctxt, s, DT_VERSYM, ctxt.Syms.Lookup(".gnu.version", 0))
}
- sy := Linklookup(Ctxt, elfRelType+".plt", 0)
+ sy := ctxt.Syms.Lookup(elfRelType+".plt", 0)
if sy.Size > 0 {
if elfRelType == ".rela" {
- Elfwritedynent(s, DT_PLTREL, DT_RELA)
+ Elfwritedynent(ctxt, s, DT_PLTREL, DT_RELA)
} else {
- Elfwritedynent(s, DT_PLTREL, DT_REL)
+ Elfwritedynent(ctxt, s, DT_PLTREL, DT_REL)
}
- elfwritedynentsymsize(s, DT_PLTRELSZ, sy)
- elfwritedynentsym(s, DT_JMPREL, sy)
+ elfwritedynentsymsize(ctxt, s, DT_PLTRELSZ, sy)
+ elfwritedynentsym(ctxt, s, DT_JMPREL, sy)
}
- Elfwritedynent(s, DT_NULL, 0)
+ Elfwritedynent(ctxt, s, DT_NULL, 0)
}
func elfphload(seg *Segment) *ElfPhdr {
@@ -1594,11 +1599,22 @@ func elfphload(seg *Segment) *ElfPhdr {
ph.memsz = seg.Length
ph.off = seg.Fileoff
ph.filesz = seg.Filelen
- ph.align = uint64(INITRND)
+ ph.align = uint64(*FlagRound)
return ph
}
+func elfphrelro(seg *Segment) {
+ ph := newElfPhdr()
+ ph.type_ = PT_GNU_RELRO
+ ph.vaddr = seg.Vaddr
+ ph.paddr = seg.Vaddr
+ ph.memsz = seg.Length
+ ph.off = seg.Fileoff
+ ph.filesz = seg.Filelen
+ ph.align = uint64(*FlagRound)
+}
+
func elfshname(name string) *ElfShdr {
var off int
var sh *ElfShdr
@@ -1618,7 +1634,25 @@ func elfshname(name string) *ElfShdr {
}
}
- Diag("cannot find elf name %s", name)
+ Exitf("cannot find elf name %s", name)
+ return nil
+}
+
+// Create an ElfShdr for the section with name.
+// Create a duplicate if one already exists with that name
+func elfshnamedup(name string) *ElfShdr {
+ var off int
+ var sh *ElfShdr
+
+ for i := 0; i < nelfstr; i++ {
+ if name == elfstr[i].s {
+ off = elfstr[i].off
+ sh = newElfShdr(int64(off))
+ return sh
+ }
+ }
+
+ Errorf(nil, "cannot find elf name %s", name)
errorexit()
return nil
}
@@ -1630,7 +1664,17 @@ func elfshalloc(sect *Section) *ElfShdr {
}
func elfshbits(sect *Section) *ElfShdr {
- sh := elfshalloc(sect)
+ var sh *ElfShdr
+
+ if sect.Name == ".text" {
+ if sect.Elfsect == nil {
+ sect.Elfsect = elfshnamedup(sect.Name)
+ }
+ sh = sect.Elfsect
+ } else {
+ sh = elfshalloc(sect)
+ }
+
// If this section has already been set up as a note, we assume type_ and
// flags are already correct, but the other fields still need filling in.
if sh.type_ == SHT_NOTE {
@@ -1640,9 +1684,9 @@ func elfshbits(sect *Section) *ElfShdr {
// in a loadable segment (e.g. the abihash note) but not for
// notes that we do not want to be mapped (e.g. the package
// list note). The real fix is probably to define new values
- // for LSym.Type corresponding to mapped and unmapped notes
+ // for Symbol.Type corresponding to mapped and unmapped notes
// and handle them in dodata().
- Diag("sh.type_ == SHT_NOTE in elfshbits when linking internally")
+ Errorf(nil, "sh.type_ == SHT_NOTE in elfshbits when linking internally")
}
sh.addralign = uint64(sect.Align)
sh.size = sect.Length
@@ -1706,6 +1750,15 @@ func elfshreloc(sect *Section) *ElfShdr {
}
sh := elfshname(elfRelType + sect.Name)
+ // There could be multiple text sections but each needs
+ // its own .rela.text.
+
+ if sect.Name == ".text" {
+ if sh.info != 0 && sh.info != uint32(sect.Elfsect.shnum) {
+ sh = elfshnamedup(elfRelType + sect.Name)
+ }
+ }
+
sh.type_ = uint32(typ)
sh.entsize = uint64(SysArch.RegSize) * 2
if typ == SHT_RELA {
@@ -1719,7 +1772,7 @@ func elfshreloc(sect *Section) *ElfShdr {
return sh
}
-func elfrelocsect(sect *Section, syms []*LSym) {
+func elfrelocsect(ctxt *Link, sect *Section, syms []*Symbol) {
// If main section is SHT_NOBITS, nothing to relocate.
// Also nothing to relocate in .shstrtab.
if sect.Vaddr >= sect.Seg.Vaddr+sect.Seg.Filelen {
@@ -1729,7 +1782,7 @@ func elfrelocsect(sect *Section, syms []*LSym) {
return
}
- sect.Reloff = uint64(Cpos())
+ sect.Reloff = uint64(coutbuf.Offset())
for i, s := range syms {
if !s.Attr.Reachable() {
continue
@@ -1748,59 +1801,67 @@ func elfrelocsect(sect *Section, syms []*LSym) {
if sym.Value >= int64(eaddr) {
break
}
- Ctxt.Cursym = sym
-
for ri := 0; ri < len(sym.R); ri++ {
r := &sym.R[ri]
if r.Done != 0 {
continue
}
if r.Xsym == nil {
- Diag("missing xsym in relocation")
+ Errorf(sym, "missing xsym in relocation")
continue
}
if r.Xsym.ElfsymForReloc() == 0 {
- Diag("reloc %d to non-elf symbol %s (outer=%s) %d", r.Type, r.Sym.Name, r.Xsym.Name, r.Sym.Type)
+ Errorf(sym, "reloc %d to non-elf symbol %s (outer=%s) %d", r.Type, r.Sym.Name, r.Xsym.Name, r.Sym.Type)
}
- if Thearch.Elfreloc1(r, int64(uint64(sym.Value+int64(r.Off))-sect.Vaddr)) < 0 {
- Diag("unsupported obj reloc %d/%d to %s", r.Type, r.Siz, r.Sym.Name)
+ if !r.Xsym.Attr.Reachable() {
+ Errorf(sym, "unreachable reloc %v target %v", r.Type, r.Xsym.Name)
+ }
+ if Thearch.Elfreloc1(ctxt, r, int64(uint64(sym.Value+int64(r.Off))-sect.Vaddr)) < 0 {
+ Errorf(sym, "unsupported obj reloc %d/%d to %s", r.Type, r.Siz, r.Sym.Name)
}
}
}
- sect.Rellen = uint64(Cpos()) - sect.Reloff
+ sect.Rellen = uint64(coutbuf.Offset()) - sect.Reloff
}
-func Elfemitreloc() {
- for Cpos()&7 != 0 {
+func Elfemitreloc(ctxt *Link) {
+ for coutbuf.Offset()&7 != 0 {
Cput(0)
}
- elfrelocsect(Segtext.Sect, Ctxt.Textp)
- for sect := Segtext.Sect.Next; sect != nil; sect = sect.Next {
- elfrelocsect(sect, datap)
+ for sect := Segtext.Sect; sect != nil; sect = sect.Next {
+ if sect.Name == ".text" {
+ elfrelocsect(ctxt, sect, ctxt.Textp)
+ } else {
+ elfrelocsect(ctxt, sect, datap)
+ }
}
+
for sect := Segrodata.Sect; sect != nil; sect = sect.Next {
- elfrelocsect(sect, datap)
+ elfrelocsect(ctxt, sect, datap)
+ }
+ for sect := Segrelrodata.Sect; sect != nil; sect = sect.Next {
+ elfrelocsect(ctxt, sect, datap)
}
for sect := Segdata.Sect; sect != nil; sect = sect.Next {
- elfrelocsect(sect, datap)
+ elfrelocsect(ctxt, sect, datap)
}
for sect := Segdwarf.Sect; sect != nil; sect = sect.Next {
- elfrelocsect(sect, list2slice(dwarfp))
+ elfrelocsect(ctxt, sect, dwarfp)
}
}
-func addgonote(sectionName string, tag uint32, desc []byte) {
- s := Linklookup(Ctxt, sectionName, 0)
+func addgonote(ctxt *Link, sectionName string, tag uint32, desc []byte) {
+ s := ctxt.Syms.Lookup(sectionName, 0)
s.Attr |= AttrReachable
s.Type = obj.SELFROSECT
// namesz
- Adduint32(Ctxt, s, uint32(len(ELF_NOTE_GO_NAME)))
+ Adduint32(ctxt, s, uint32(len(ELF_NOTE_GO_NAME)))
// descsz
- Adduint32(Ctxt, s, uint32(len(desc)))
+ Adduint32(ctxt, s, uint32(len(desc)))
// tag
- Adduint32(Ctxt, s, tag)
+ Adduint32(ctxt, s, tag)
// name + padding
s.P = append(s.P, ELF_NOTE_GO_NAME...)
for len(s.P)%4 != 0 {
@@ -1814,13 +1875,13 @@ func addgonote(sectionName string, tag uint32, desc []byte) {
s.Size = int64(len(s.P))
}
-func doelf() {
+func (ctxt *Link) doelf() {
if !Iself {
return
}
/* predefine strings we need for section headers */
- shstrtab := Linklookup(Ctxt, ".shstrtab", 0)
+ shstrtab := ctxt.Syms.Lookup(".shstrtab", 0)
shstrtab.Type = obj.SELFROSECT
shstrtab.Attr |= AttrReachable
@@ -1836,21 +1897,21 @@ func doelf() {
// for dynamic internal linker or external linking, so that various
// binutils could correctly calculate PT_TLS size.
// see https://golang.org/issue/5200.
- if HEADTYPE != obj.Hopenbsd {
- if Debug['d'] == 0 || Linkmode == LinkExternal {
+ if Headtype != obj.Hopenbsd {
+ if !*FlagD || Linkmode == LinkExternal {
Addstring(shstrtab, ".tbss")
}
}
- if HEADTYPE == obj.Hnetbsd {
+ if Headtype == obj.Hnetbsd {
Addstring(shstrtab, ".note.netbsd.ident")
}
- if HEADTYPE == obj.Hopenbsd {
+ if Headtype == obj.Hopenbsd {
Addstring(shstrtab, ".note.openbsd.ident")
}
if len(buildinfo) > 0 {
Addstring(shstrtab, ".note.gnu.build-id")
}
- if buildid != "" {
+ if *flagBuildid != "" {
Addstring(shstrtab, ".note.go.buildid")
}
Addstring(shstrtab, ".elfdata")
@@ -1867,7 +1928,7 @@ func doelf() {
Addstring(shstrtab, relro_prefix+".gopclntab")
if Linkmode == LinkExternal {
- Debug['d'] = 1
+ *FlagD = true
Addstring(shstrtab, elfRelType+".text")
Addstring(shstrtab, elfRelType+".rodata")
@@ -1891,11 +1952,11 @@ func doelf() {
}
}
- hasinitarr := Linkshared
+ hasinitarr := *FlagLinkshared
/* shared library initializer */
switch Buildmode {
- case BuildmodeCArchive, BuildmodeCShared, BuildmodeShared:
+ case BuildmodeCArchive, BuildmodeCShared, BuildmodeShared, BuildmodePlugin:
hasinitarr = true
}
@@ -1904,15 +1965,15 @@ func doelf() {
Addstring(shstrtab, elfRelType+".init_array")
}
- if Debug['s'] == 0 {
+ if !*FlagS {
Addstring(shstrtab, ".symtab")
Addstring(shstrtab, ".strtab")
- dwarfaddshstrings(shstrtab)
+ dwarfaddshstrings(ctxt, shstrtab)
}
Addstring(shstrtab, ".shstrtab")
- if Debug['d'] == 0 { /* -d suppresses dynamic loader format */
+ if !*FlagD { /* -d suppresses dynamic loader format */
Addstring(shstrtab, ".interp")
Addstring(shstrtab, ".hash")
Addstring(shstrtab, ".got")
@@ -1931,7 +1992,7 @@ func doelf() {
Addstring(shstrtab, ".gnu.version_r")
/* dynamic symbol table - first entry all zeros */
- s := Linklookup(Ctxt, ".dynsym", 0)
+ s := ctxt.Syms.Lookup(".dynsym", 0)
s.Type = obj.SELFROSECT
s.Attr |= AttrReachable
@@ -1942,7 +2003,7 @@ func doelf() {
}
/* dynamic string table */
- s = Linklookup(Ctxt, ".dynstr", 0)
+ s = ctxt.Syms.Lookup(".dynstr", 0)
s.Type = obj.SELFROSECT
s.Attr |= AttrReachable
@@ -1952,34 +2013,34 @@ func doelf() {
dynstr := s
/* relocation table */
- s = Linklookup(Ctxt, elfRelType, 0)
+ s = ctxt.Syms.Lookup(elfRelType, 0)
s.Attr |= AttrReachable
s.Type = obj.SELFROSECT
/* global offset table */
- s = Linklookup(Ctxt, ".got", 0)
+ s = ctxt.Syms.Lookup(".got", 0)
s.Attr |= AttrReachable
s.Type = obj.SELFGOT // writable
/* ppc64 glink resolver */
if SysArch.Family == sys.PPC64 {
- s := Linklookup(Ctxt, ".glink", 0)
+ s := ctxt.Syms.Lookup(".glink", 0)
s.Attr |= AttrReachable
s.Type = obj.SELFRXSECT
}
/* hash */
- s = Linklookup(Ctxt, ".hash", 0)
+ s = ctxt.Syms.Lookup(".hash", 0)
s.Attr |= AttrReachable
s.Type = obj.SELFROSECT
- s = Linklookup(Ctxt, ".got.plt", 0)
+ s = ctxt.Syms.Lookup(".got.plt", 0)
s.Attr |= AttrReachable
s.Type = obj.SELFSECT // writable
- s = Linklookup(Ctxt, ".plt", 0)
+ s = ctxt.Syms.Lookup(".plt", 0)
s.Attr |= AttrReachable
if SysArch.Family == sys.PPC64 {
@@ -1990,22 +2051,22 @@ func doelf() {
s.Type = obj.SELFRXSECT
}
- Thearch.Elfsetupplt()
+ Thearch.Elfsetupplt(ctxt)
- s = Linklookup(Ctxt, elfRelType+".plt", 0)
+ s = ctxt.Syms.Lookup(elfRelType+".plt", 0)
s.Attr |= AttrReachable
s.Type = obj.SELFROSECT
- s = Linklookup(Ctxt, ".gnu.version", 0)
+ s = ctxt.Syms.Lookup(".gnu.version", 0)
s.Attr |= AttrReachable
s.Type = obj.SELFROSECT
- s = Linklookup(Ctxt, ".gnu.version_r", 0)
+ s = ctxt.Syms.Lookup(".gnu.version_r", 0)
s.Attr |= AttrReachable
s.Type = obj.SELFROSECT
/* define dynamic elf table */
- s = Linklookup(Ctxt, ".dynamic", 0)
+ s = ctxt.Syms.Lookup(".dynamic", 0)
s.Attr |= AttrReachable
s.Type = obj.SELFSECT // writable
@@ -2013,85 +2074,85 @@ func doelf() {
/*
* .dynamic table
*/
- elfwritedynentsym(s, DT_HASH, Linklookup(Ctxt, ".hash", 0))
+ elfwritedynentsym(ctxt, s, DT_HASH, ctxt.Syms.Lookup(".hash", 0))
- elfwritedynentsym(s, DT_SYMTAB, Linklookup(Ctxt, ".dynsym", 0))
+ elfwritedynentsym(ctxt, s, DT_SYMTAB, ctxt.Syms.Lookup(".dynsym", 0))
if elf64 {
- Elfwritedynent(s, DT_SYMENT, ELF64SYMSIZE)
+ Elfwritedynent(ctxt, s, DT_SYMENT, ELF64SYMSIZE)
} else {
- Elfwritedynent(s, DT_SYMENT, ELF32SYMSIZE)
+ Elfwritedynent(ctxt, s, DT_SYMENT, ELF32SYMSIZE)
}
- elfwritedynentsym(s, DT_STRTAB, Linklookup(Ctxt, ".dynstr", 0))
- elfwritedynentsymsize(s, DT_STRSZ, Linklookup(Ctxt, ".dynstr", 0))
+ elfwritedynentsym(ctxt, s, DT_STRTAB, ctxt.Syms.Lookup(".dynstr", 0))
+ elfwritedynentsymsize(ctxt, s, DT_STRSZ, ctxt.Syms.Lookup(".dynstr", 0))
if elfRelType == ".rela" {
- elfwritedynentsym(s, DT_RELA, Linklookup(Ctxt, ".rela", 0))
- elfwritedynentsymsize(s, DT_RELASZ, Linklookup(Ctxt, ".rela", 0))
- Elfwritedynent(s, DT_RELAENT, ELF64RELASIZE)
+ elfwritedynentsym(ctxt, s, DT_RELA, ctxt.Syms.Lookup(".rela", 0))
+ elfwritedynentsymsize(ctxt, s, DT_RELASZ, ctxt.Syms.Lookup(".rela", 0))
+ Elfwritedynent(ctxt, s, DT_RELAENT, ELF64RELASIZE)
} else {
- elfwritedynentsym(s, DT_REL, Linklookup(Ctxt, ".rel", 0))
- elfwritedynentsymsize(s, DT_RELSZ, Linklookup(Ctxt, ".rel", 0))
- Elfwritedynent(s, DT_RELENT, ELF32RELSIZE)
+ elfwritedynentsym(ctxt, s, DT_REL, ctxt.Syms.Lookup(".rel", 0))
+ elfwritedynentsymsize(ctxt, s, DT_RELSZ, ctxt.Syms.Lookup(".rel", 0))
+ Elfwritedynent(ctxt, s, DT_RELENT, ELF32RELSIZE)
}
if rpath.val != "" {
- Elfwritedynent(s, DT_RUNPATH, uint64(Addstring(dynstr, rpath.val)))
+ Elfwritedynent(ctxt, s, DT_RUNPATH, uint64(Addstring(dynstr, rpath.val)))
}
if SysArch.Family == sys.PPC64 {
- elfwritedynentsym(s, DT_PLTGOT, Linklookup(Ctxt, ".plt", 0))
+ elfwritedynentsym(ctxt, s, DT_PLTGOT, ctxt.Syms.Lookup(".plt", 0))
} else if SysArch.Family == sys.S390X {
- elfwritedynentsym(s, DT_PLTGOT, Linklookup(Ctxt, ".got", 0))
+ elfwritedynentsym(ctxt, s, DT_PLTGOT, ctxt.Syms.Lookup(".got", 0))
} else {
- elfwritedynentsym(s, DT_PLTGOT, Linklookup(Ctxt, ".got.plt", 0))
+ elfwritedynentsym(ctxt, s, DT_PLTGOT, ctxt.Syms.Lookup(".got.plt", 0))
}
if SysArch.Family == sys.PPC64 {
- Elfwritedynent(s, DT_PPC64_OPT, 0)
+ Elfwritedynent(ctxt, s, DT_PPC64_OPT, 0)
}
// Solaris dynamic linker can't handle an empty .rela.plt if
// DT_JMPREL is emitted so we have to defer generation of DT_PLTREL,
// DT_PLTRELSZ, and DT_JMPREL dynamic entries until after we know the
// size of .rel(a).plt section.
- Elfwritedynent(s, DT_DEBUG, 0)
+ Elfwritedynent(ctxt, s, DT_DEBUG, 0)
}
if Buildmode == BuildmodeShared {
// The go.link.abihashbytes symbol will be pointed at the appropriate
// part of the .note.go.abihash section in data.go:func address().
- s := Linklookup(Ctxt, "go.link.abihashbytes", 0)
+ s := ctxt.Syms.Lookup("go.link.abihashbytes", 0)
s.Attr |= AttrLocal
s.Type = obj.SRODATA
s.Attr |= AttrSpecial
s.Attr |= AttrReachable
s.Size = int64(sha1.Size)
- sort.Sort(byPkg(Ctxt.Library))
+ sort.Sort(byPkg(ctxt.Library))
h := sha1.New()
- for _, l := range Ctxt.Library {
+ for _, l := range ctxt.Library {
h.Write(l.hash)
}
- addgonote(".note.go.abihash", ELF_NOTE_GOABIHASH_TAG, h.Sum([]byte{}))
- addgonote(".note.go.pkg-list", ELF_NOTE_GOPKGLIST_TAG, pkglistfornote)
+ addgonote(ctxt, ".note.go.abihash", ELF_NOTE_GOABIHASH_TAG, h.Sum([]byte{}))
+ addgonote(ctxt, ".note.go.pkg-list", ELF_NOTE_GOPKGLIST_TAG, pkglistfornote)
var deplist []string
- for _, shlib := range Ctxt.Shlibs {
+ for _, shlib := range ctxt.Shlibs {
deplist = append(deplist, filepath.Base(shlib.Path))
}
- addgonote(".note.go.deps", ELF_NOTE_GODEPS_TAG, []byte(strings.Join(deplist, "\n")))
+ addgonote(ctxt, ".note.go.deps", ELF_NOTE_GODEPS_TAG, []byte(strings.Join(deplist, "\n")))
}
- if Linkmode == LinkExternal && buildid != "" {
- addgonote(".note.go.buildid", ELF_NOTE_GOBUILDID_TAG, []byte(buildid))
+ if Linkmode == LinkExternal && *flagBuildid != "" {
+ addgonote(ctxt, ".note.go.buildid", ELF_NOTE_GOBUILDID_TAG, []byte(*flagBuildid))
}
}
// Do not write DT_NULL. elfdynhash will finish it.
-func shsym(sh *ElfShdr, s *LSym) {
+func shsym(sh *ElfShdr, s *Symbol) {
addr := Symaddr(s)
if sh.flags&SHF_ALLOC != 0 {
sh.addr = uint64(addr)
}
- sh.off = uint64(datoff(addr))
+ sh.off = uint64(datoff(s, addr))
sh.size = uint64(s.Size)
}
@@ -2109,11 +2170,22 @@ func Asmbelfsetup() {
elfshname("")
for sect := Segtext.Sect; sect != nil; sect = sect.Next {
- elfshalloc(sect)
+ // 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" {
+ if sect.Elfsect == nil {
+ sect.Elfsect = elfshnamedup(sect.Name)
+ }
+ } else {
+ elfshalloc(sect)
+ }
}
for sect := Segrodata.Sect; sect != nil; sect = sect.Next {
elfshalloc(sect)
}
+ for sect := Segrelrodata.Sect; sect != nil; sect = sect.Next {
+ elfshalloc(sect)
+ }
for sect := Segdata.Sect; sect != nil; sect = sect.Next {
elfshalloc(sect)
}
@@ -2122,12 +2194,12 @@ func Asmbelfsetup() {
}
}
-func Asmbelf(symo int64) {
+func Asmbelf(ctxt *Link, symo int64) {
eh := getElfEhdr()
switch SysArch.Family {
default:
Exitf("unknown architecture in asmbelf: %v", SysArch.Family)
- case sys.MIPS64:
+ case sys.MIPS, sys.MIPS64:
eh.machine = EM_MIPS
case sys.ARM:
eh.machine = EM_ARM
@@ -2144,7 +2216,24 @@ func Asmbelf(symo int64) {
}
elfreserve := int64(ELFRESERVE)
- startva := INITTEXT - int64(HEADR)
+
+ numtext := int64(0)
+ for sect := Segtext.Sect; sect != nil; sect = sect.Next {
+ if sect.Name == ".text" {
+ numtext++
+ }
+ }
+
+ // If there are multiple text sections, extra space is needed
+ // in the elfreserve for the additional .text and .rela.text
+ // section headers. It can handle 4 extra now. Headers are
+ // 64 bytes.
+
+ if numtext > 4 {
+ elfreserve += elfreserve + numtext*64*2
+ }
+
+ startva := *FlagTextAddr - int64(HEADR)
resoff := elfreserve
var pph *ElfPhdr
@@ -2165,7 +2254,7 @@ func Asmbelf(symo int64) {
sh.type_ = SHT_NOTE
}
- if buildid != "" {
+ if *flagBuildid != "" {
sh := elfshname(".note.go.buildid")
sh.type_ = SHT_NOTE
sh.flags = SHF_ALLOC
@@ -2180,16 +2269,16 @@ func Asmbelf(symo int64) {
pph.type_ = PT_PHDR
pph.flags = PF_R
pph.off = uint64(eh.ehsize)
- pph.vaddr = uint64(INITTEXT) - uint64(HEADR) + pph.off
- pph.paddr = uint64(INITTEXT) - uint64(HEADR) + pph.off
- pph.align = uint64(INITRND)
+ pph.vaddr = uint64(*FlagTextAddr) - uint64(HEADR) + pph.off
+ pph.paddr = uint64(*FlagTextAddr) - uint64(HEADR) + pph.off
+ pph.align = uint64(*FlagRound)
/*
* PHDR must be in a loaded segment. Adjust the text
* segment boundaries downwards to include it.
* Except on NaCl where it must not be loaded.
*/
- if HEADTYPE != obj.Hnacl {
+ if Headtype != obj.Hnacl {
o := int64(Segtext.Vaddr - pph.vaddr)
Segtext.Vaddr -= uint64(o)
Segtext.Length += uint64(o)
@@ -2198,7 +2287,7 @@ func Asmbelf(symo int64) {
Segtext.Filelen += uint64(o)
}
- if Debug['d'] == 0 { /* -d suppresses dynamic loader format */
+ if !*FlagD { /* -d suppresses dynamic loader format */
/* interpreter */
sh := elfshname(".interp")
@@ -2206,7 +2295,7 @@ func Asmbelf(symo int64) {
sh.flags = SHF_ALLOC
sh.addralign = 1
if interpreter == "" {
- switch HEADTYPE {
+ switch Headtype {
case obj.Hlinux:
interpreter = Thearch.Linuxdynld
@@ -2236,9 +2325,9 @@ func Asmbelf(symo int64) {
}
pnote = nil
- if HEADTYPE == obj.Hnetbsd || HEADTYPE == obj.Hopenbsd {
+ if Headtype == obj.Hnetbsd || Headtype == obj.Hopenbsd {
var sh *ElfShdr
- switch HEADTYPE {
+ switch Headtype {
case obj.Hnetbsd:
sh = elfshname(".note.netbsd.ident")
resoff -= int64(elfnetbsdsig(sh, uint64(startva), uint64(resoff)))
@@ -2267,7 +2356,7 @@ func Asmbelf(symo int64) {
phsh(pnote, sh)
}
- if buildid != "" {
+ if *flagBuildid != "" {
sh := elfshname(".note.go.buildid")
resoff -= int64(elfgobuildid(sh, uint64(startva), uint64(resoff)))
@@ -2283,10 +2372,14 @@ func Asmbelf(symo int64) {
if Segrodata.Sect != nil {
elfphload(&Segrodata)
}
+ if Segrelrodata.Sect != nil {
+ elfphload(&Segrelrodata)
+ elfphrelro(&Segrelrodata)
+ }
elfphload(&Segdata)
/* Dynamic linking sections */
- if Debug['d'] == 0 {
+ if !*FlagD {
sh := elfshname(".dynsym")
sh.type_ = SHT_DYNSYM
sh.flags = SHF_ALLOC
@@ -2299,13 +2392,13 @@ func Asmbelf(symo int64) {
sh.link = uint32(elfshname(".dynstr").shnum)
// sh->info = index of first non-local symbol (number of local symbols)
- shsym(sh, Linklookup(Ctxt, ".dynsym", 0))
+ shsym(sh, ctxt.Syms.Lookup(".dynsym", 0))
sh = elfshname(".dynstr")
sh.type_ = SHT_STRTAB
sh.flags = SHF_ALLOC
sh.addralign = 1
- shsym(sh, Linklookup(Ctxt, ".dynstr", 0))
+ shsym(sh, ctxt.Syms.Lookup(".dynstr", 0))
if elfverneed != 0 {
sh := elfshname(".gnu.version")
@@ -2314,7 +2407,7 @@ func Asmbelf(symo int64) {
sh.addralign = 2
sh.link = uint32(elfshname(".dynsym").shnum)
sh.entsize = 2
- shsym(sh, Linklookup(Ctxt, ".gnu.version", 0))
+ shsym(sh, ctxt.Syms.Lookup(".gnu.version", 0))
sh = elfshname(".gnu.version_r")
sh.type_ = SHT_GNU_VERNEED
@@ -2322,7 +2415,7 @@ func Asmbelf(symo int64) {
sh.addralign = uint64(SysArch.RegSize)
sh.info = uint32(elfverneed)
sh.link = uint32(elfshname(".dynstr").shnum)
- shsym(sh, Linklookup(Ctxt, ".gnu.version_r", 0))
+ shsym(sh, ctxt.Syms.Lookup(".gnu.version_r", 0))
}
if elfRelType == ".rela" {
@@ -2333,7 +2426,7 @@ func Asmbelf(symo int64) {
sh.addralign = uint64(SysArch.RegSize)
sh.link = uint32(elfshname(".dynsym").shnum)
sh.info = uint32(elfshname(".plt").shnum)
- shsym(sh, Linklookup(Ctxt, ".rela.plt", 0))
+ shsym(sh, ctxt.Syms.Lookup(".rela.plt", 0))
sh = elfshname(".rela")
sh.type_ = SHT_RELA
@@ -2341,7 +2434,7 @@ func Asmbelf(symo int64) {
sh.entsize = ELF64RELASIZE
sh.addralign = 8
sh.link = uint32(elfshname(".dynsym").shnum)
- shsym(sh, Linklookup(Ctxt, ".rela", 0))
+ shsym(sh, ctxt.Syms.Lookup(".rela", 0))
} else {
sh := elfshname(".rel.plt")
sh.type_ = SHT_REL
@@ -2349,7 +2442,7 @@ func Asmbelf(symo int64) {
sh.entsize = ELF32RELSIZE
sh.addralign = 4
sh.link = uint32(elfshname(".dynsym").shnum)
- shsym(sh, Linklookup(Ctxt, ".rel.plt", 0))
+ shsym(sh, ctxt.Syms.Lookup(".rel.plt", 0))
sh = elfshname(".rel")
sh.type_ = SHT_REL
@@ -2357,7 +2450,7 @@ func Asmbelf(symo int64) {
sh.entsize = ELF32RELSIZE
sh.addralign = 4
sh.link = uint32(elfshname(".dynsym").shnum)
- shsym(sh, Linklookup(Ctxt, ".rel", 0))
+ shsym(sh, ctxt.Syms.Lookup(".rel", 0))
}
if eh.machine == EM_PPC64 {
@@ -2365,7 +2458,7 @@ func Asmbelf(symo int64) {
sh.type_ = SHT_PROGBITS
sh.flags = SHF_ALLOC + SHF_EXECINSTR
sh.addralign = 4
- shsym(sh, Linklookup(Ctxt, ".glink", 0))
+ shsym(sh, ctxt.Syms.Lookup(".glink", 0))
}
sh = elfshname(".plt")
@@ -2386,7 +2479,7 @@ func Asmbelf(symo int64) {
sh.entsize = 4
}
sh.addralign = sh.entsize
- shsym(sh, Linklookup(Ctxt, ".plt", 0))
+ shsym(sh, ctxt.Syms.Lookup(".plt", 0))
// On ppc64, .got comes from the input files, so don't
// create it here, and .got.plt is not used.
@@ -2396,14 +2489,14 @@ func Asmbelf(symo int64) {
sh.flags = SHF_ALLOC + SHF_WRITE
sh.entsize = uint64(SysArch.RegSize)
sh.addralign = uint64(SysArch.RegSize)
- shsym(sh, Linklookup(Ctxt, ".got", 0))
+ shsym(sh, ctxt.Syms.Lookup(".got", 0))
sh = elfshname(".got.plt")
sh.type_ = SHT_PROGBITS
sh.flags = SHF_ALLOC + SHF_WRITE
sh.entsize = uint64(SysArch.RegSize)
sh.addralign = uint64(SysArch.RegSize)
- shsym(sh, Linklookup(Ctxt, ".got.plt", 0))
+ shsym(sh, ctxt.Syms.Lookup(".got.plt", 0))
}
sh = elfshname(".hash")
@@ -2412,7 +2505,7 @@ func Asmbelf(symo int64) {
sh.entsize = 4
sh.addralign = uint64(SysArch.RegSize)
sh.link = uint32(elfshname(".dynsym").shnum)
- shsym(sh, Linklookup(Ctxt, ".hash", 0))
+ shsym(sh, ctxt.Syms.Lookup(".hash", 0))
/* sh and PT_DYNAMIC for .dynamic section */
sh = elfshname(".dynamic")
@@ -2422,7 +2515,7 @@ func Asmbelf(symo int64) {
sh.entsize = 2 * uint64(SysArch.RegSize)
sh.addralign = uint64(SysArch.RegSize)
sh.link = uint32(elfshname(".dynstr").shnum)
- shsym(sh, Linklookup(Ctxt, ".dynamic", 0))
+ shsym(sh, ctxt.Syms.Lookup(".dynamic", 0))
ph := newElfPhdr()
ph.type_ = PT_DYNAMIC
ph.flags = PF_R + PF_W
@@ -2434,7 +2527,7 @@ func Asmbelf(symo int64) {
// 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 {
+ if Headtype != obj.Hopenbsd {
tlssize := uint64(0)
for sect := Segdata.Sect; sect != nil; sect = sect.Next {
if sect.Name == ".tbss" {
@@ -2451,7 +2544,7 @@ func Asmbelf(symo int64) {
}
}
- if HEADTYPE == obj.Hlinux {
+ if Headtype == obj.Hlinux {
ph := newElfPhdr()
ph.type_ = PT_GNU_STACK
ph.flags = PF_W + PF_R
@@ -2461,17 +2554,21 @@ func Asmbelf(symo int64) {
ph.type_ = PT_PAX_FLAGS
ph.flags = 0x2a00 // mprotect, randexec, emutramp disabled
ph.align = uint64(SysArch.RegSize)
+ } else if Headtype == obj.Hsolaris {
+ ph := newElfPhdr()
+ ph.type_ = PT_SUNWSTACK
+ ph.flags = PF_W + PF_R
}
elfobj:
sh := elfshname(".shstrtab")
sh.type_ = SHT_STRTAB
sh.addralign = 1
- shsym(sh, Linklookup(Ctxt, ".shstrtab", 0))
+ shsym(sh, ctxt.Syms.Lookup(".shstrtab", 0))
eh.shstrndx = uint16(sh.shnum)
// put these sections early in the list
- if Debug['s'] == 0 {
+ if !*FlagS {
elfshname(".symtab")
elfshname(".strtab")
}
@@ -2482,6 +2579,9 @@ elfobj:
for sect := Segrodata.Sect; sect != nil; sect = sect.Next {
elfshbits(sect)
}
+ for sect := Segrelrodata.Sect; sect != nil; sect = sect.Next {
+ elfshbits(sect)
+ }
for sect := Segdata.Sect; sect != nil; sect = sect.Next {
elfshbits(sect)
}
@@ -2496,10 +2596,13 @@ elfobj:
for sect := Segrodata.Sect; sect != nil; sect = sect.Next {
elfshreloc(sect)
}
+ for sect := Segrelrodata.Sect; sect != nil; sect = sect.Next {
+ elfshreloc(sect)
+ }
for sect := Segdata.Sect; sect != nil; sect = sect.Next {
elfshreloc(sect)
}
- for s := dwarfp; s != nil; s = s.Next {
+ for _, s := range dwarfp {
if len(s.R) > 0 || s.Type == obj.SDWARFINFO {
elfshreloc(s.Sect)
}
@@ -2515,7 +2618,7 @@ elfobj:
sh.flags = 0
}
- if Debug['s'] == 0 {
+ if !*FlagS {
sh := elfshname(".symtab")
sh.type_ = SHT_SYMTAB
sh.off = uint64(symo)
@@ -2538,13 +2641,13 @@ elfobj:
eh.ident[EI_MAG1] = 'E'
eh.ident[EI_MAG2] = 'L'
eh.ident[EI_MAG3] = 'F'
- if HEADTYPE == obj.Hfreebsd {
+ if Headtype == obj.Hfreebsd {
eh.ident[EI_OSABI] = ELFOSABI_FREEBSD
- } else if HEADTYPE == obj.Hnetbsd {
+ } else if Headtype == obj.Hnetbsd {
eh.ident[EI_OSABI] = ELFOSABI_NETBSD
- } else if HEADTYPE == obj.Hopenbsd {
+ } else if Headtype == obj.Hopenbsd {
eh.ident[EI_OSABI] = ELFOSABI_OPENBSD
- } else if HEADTYPE == obj.Hdragonfly {
+ } else if Headtype == obj.Hdragonfly {
eh.ident[EI_OSABI] = ELFOSABI_NONE
}
if elf64 {
@@ -2552,7 +2655,7 @@ elfobj:
} else {
eh.ident[EI_CLASS] = ELFCLASS32
}
- if Ctxt.Arch.ByteOrder == binary.BigEndian {
+ if ctxt.Arch.ByteOrder == binary.BigEndian {
eh.ident[EI_DATA] = ELFDATA2MSB
} else {
eh.ident[EI_DATA] = ELFDATA2LSB
@@ -2561,12 +2664,14 @@ elfobj:
if Linkmode == LinkExternal {
eh.type_ = ET_REL
+ } else if Buildmode == BuildmodePIE {
+ eh.type_ = ET_DYN
} else {
eh.type_ = ET_EXEC
}
if Linkmode != LinkExternal {
- eh.entry = uint64(Entryvalue())
+ eh.entry = uint64(Entryvalue(ctxt))
}
eh.version = EV_CURRENT
@@ -2581,38 +2686,38 @@ elfobj:
a += int64(elfwritehdr())
a += int64(elfwritephdrs())
a += int64(elfwriteshdrs())
- if Debug['d'] == 0 {
+ if !*FlagD {
a += int64(elfwriteinterp())
}
if Linkmode != LinkExternal {
- if HEADTYPE == obj.Hnetbsd {
+ if Headtype == obj.Hnetbsd {
a += int64(elfwritenetbsdsig())
}
- if HEADTYPE == obj.Hopenbsd {
+ if Headtype == obj.Hopenbsd {
a += int64(elfwriteopenbsdsig())
}
if len(buildinfo) > 0 {
a += int64(elfwritebuildinfo())
}
- if buildid != "" {
+ if *flagBuildid != "" {
a += int64(elfwritegobuildid())
}
}
if a > elfreserve {
- Diag("ELFRESERVE too small: %d > %d", a, elfreserve)
+ Errorf(nil, "ELFRESERVE too small: %d > %d with %d text sections", a, elfreserve, numtext)
}
}
-func Elfadddynsym(ctxt *Link, s *LSym) {
+func Elfadddynsym(ctxt *Link, s *Symbol) {
if elf64 {
s.Dynid = int32(Nelfsym)
Nelfsym++
- d := Linklookup(ctxt, ".dynsym", 0)
+ d := ctxt.Syms.Lookup(".dynsym", 0)
name := s.Extname
- Adduint32(ctxt, d, uint32(Addstring(Linklookup(ctxt, ".dynstr", 0), name)))
+ Adduint32(ctxt, d, uint32(Addstring(ctxt.Syms.Lookup(".dynstr", 0), name)))
/* type */
t := STB_GLOBAL << 4
@@ -2645,18 +2750,18 @@ func Elfadddynsym(ctxt *Link, s *LSym) {
Adduint64(ctxt, d, uint64(s.Size))
if SysArch.Family == sys.AMD64 && !s.Attr.CgoExportDynamic() && s.Dynimplib != "" && !seenlib[s.Dynimplib] {
- Elfwritedynent(Linklookup(ctxt, ".dynamic", 0), DT_NEEDED, uint64(Addstring(Linklookup(ctxt, ".dynstr", 0), s.Dynimplib)))
+ Elfwritedynent(ctxt, ctxt.Syms.Lookup(".dynamic", 0), DT_NEEDED, uint64(Addstring(ctxt.Syms.Lookup(".dynstr", 0), s.Dynimplib)))
}
} else {
s.Dynid = int32(Nelfsym)
Nelfsym++
- d := Linklookup(ctxt, ".dynsym", 0)
+ d := ctxt.Syms.Lookup(".dynsym", 0)
/* name */
name := s.Extname
- Adduint32(ctxt, d, uint32(Addstring(Linklookup(ctxt, ".dynstr", 0), name)))
+ Adduint32(ctxt, d, uint32(Addstring(ctxt.Syms.Lookup(".dynstr", 0), name)))
/* value */
if s.Type == obj.SDYNIMPORT {
diff --git a/src/cmd/link/internal/ld/go.go b/src/cmd/link/internal/ld/go.go
index 79cdae0..5b84c3d 100644
--- a/src/cmd/link/internal/ld/go.go
+++ b/src/cmd/link/internal/ld/go.go
@@ -28,16 +28,16 @@ func expandpkg(t0 string, pkg string) string {
// once the dust settles, try to move some code to
// libmach, so that other linkers and ar can share.
-func ldpkg(f *bio.Reader, pkg string, length int64, filename string, whence int) {
+func ldpkg(ctxt *Link, f *bio.Reader, pkg string, length int64, filename string, whence int) {
var p0, p1 int
- if Debug['g'] != 0 {
+ if *flagG {
return
}
if int64(int(length)) != length {
fmt.Fprintf(os.Stderr, "%s: too much pkg data in %s\n", os.Args[0], filename)
- if Debug['u'] != 0 {
+ if *flagU {
errorexit()
}
return
@@ -52,7 +52,7 @@ func ldpkg(f *bio.Reader, pkg string, length int64, filename string, whence int)
bdata := make([]byte, length)
if _, err := io.ReadFull(f, bdata); err != nil {
fmt.Fprintf(os.Stderr, "%s: short pkg read %s\n", os.Args[0], filename)
- if Debug['u'] != 0 {
+ if *flagU {
errorexit()
}
return
@@ -84,7 +84,7 @@ func ldpkg(f *bio.Reader, pkg string, length int64, filename string, whence int)
if pkg == "main" && !isMain {
Exitf("%s: not package main", filename)
}
- if Debug['u'] != 0 && whence != ArchiveObj && !isSafe {
+ if *flagU && whence != ArchiveObj && !isSafe {
Exitf("load of unsafe package %s", filename)
}
}
@@ -101,7 +101,7 @@ func ldpkg(f *bio.Reader, pkg string, length int64, filename string, whence int)
i := strings.IndexByte(data[p0+1:], '\n')
if i < 0 {
fmt.Fprintf(os.Stderr, "%s: found $$ // cgo but no newline in %s\n", os.Args[0], filename)
- if Debug['u'] != 0 {
+ if *flagU {
errorexit()
}
return
@@ -114,25 +114,25 @@ func ldpkg(f *bio.Reader, pkg string, length int64, filename string, whence int)
}
if p1 < 0 {
fmt.Fprintf(os.Stderr, "%s: cannot find end of // cgo section in %s\n", os.Args[0], filename)
- if Debug['u'] != 0 {
+ if *flagU {
errorexit()
}
return
}
p1 += p0
- loadcgo(filename, pkg, data[p0:p1])
+ loadcgo(ctxt, filename, pkg, data[p0:p1])
}
}
-func loadcgo(file string, pkg string, p string) {
+func loadcgo(ctxt *Link, file string, pkg string, p string) {
var next string
var q string
var f []string
var local string
var remote string
var lib string
- var s *LSym
+ var s *Symbol
p0 := ""
for ; p != ""; p = next {
@@ -163,7 +163,7 @@ func loadcgo(file string, pkg string, p string) {
lib = f[3]
}
- if Debug['d'] != 0 {
+ if *FlagD {
fmt.Fprintf(os.Stderr, "%s: %s: cannot use dynamic imports with -d flag\n", os.Args[0], file)
nerrors++
return
@@ -174,7 +174,7 @@ func loadcgo(file string, pkg string, p string) {
// to force a link of foo.so.
havedynamic = 1
- if HEADTYPE == obj.Hdarwin {
+ if Headtype == obj.Hdarwin {
Machoadddynlib(lib)
} else {
dynlib = append(dynlib, lib)
@@ -187,7 +187,7 @@ func loadcgo(file string, pkg string, p string) {
if i := strings.Index(remote, "#"); i >= 0 {
remote, q = remote[:i], remote[i+1:]
}
- s = Linklookup(Ctxt, local, 0)
+ s = ctxt.Syms.Lookup(local, 0)
if local != f[1] {
}
if s.Type == 0 || s.Type == obj.SXREF || s.Type == obj.SHOSTOBJ {
@@ -208,7 +208,7 @@ func loadcgo(file string, pkg string, p string) {
goto err
}
local = f[1]
- s = Linklookup(Ctxt, local, 0)
+ s = ctxt.Syms.Lookup(local, 0)
s.Type = obj.SHOSTOBJ
s.Size = 0
continue
@@ -225,11 +225,11 @@ func loadcgo(file string, pkg string, p string) {
remote = local
}
local = expandpkg(local, pkg)
- s = Linklookup(Ctxt, local, 0)
+ s = ctxt.Syms.Lookup(local, 0)
switch Buildmode {
- case BuildmodeCShared, BuildmodeCArchive:
- if s == Linklookup(Ctxt, "main", 0) {
+ case BuildmodeCShared, BuildmodeCArchive, BuildmodePlugin:
+ if s == ctxt.Syms.Lookup("main", 0) {
continue
}
}
@@ -267,7 +267,7 @@ func loadcgo(file string, pkg string, p string) {
goto err
}
- if Debug['I'] == 0 {
+ if *flagInterpreter == "" {
if interpreter != "" && interpreter != f[1] {
fmt.Fprintf(os.Stderr, "%s: conflict dynlinker: %s and %s\n", os.Args[0], interpreter, f[1])
nerrors++
@@ -298,43 +298,43 @@ err:
var seenlib = make(map[string]bool)
-func adddynlib(lib string) {
+func adddynlib(ctxt *Link, lib string) {
if seenlib[lib] || Linkmode == LinkExternal {
return
}
seenlib[lib] = true
if Iself {
- s := Linklookup(Ctxt, ".dynstr", 0)
+ s := ctxt.Syms.Lookup(".dynstr", 0)
if s.Size == 0 {
Addstring(s, "")
}
- Elfwritedynent(Linklookup(Ctxt, ".dynamic", 0), DT_NEEDED, uint64(Addstring(s, lib)))
+ Elfwritedynent(ctxt, ctxt.Syms.Lookup(".dynamic", 0), DT_NEEDED, uint64(Addstring(s, lib)))
} else {
- Diag("adddynlib: unsupported binary format")
+ Errorf(nil, "adddynlib: unsupported binary format")
}
}
-func Adddynsym(ctxt *Link, s *LSym) {
+func Adddynsym(ctxt *Link, s *Symbol) {
if s.Dynid >= 0 || Linkmode == LinkExternal {
return
}
if Iself {
Elfadddynsym(ctxt, s)
- } else if HEADTYPE == obj.Hdarwin {
- Diag("adddynsym: missed symbol %s (%s)", s.Name, s.Extname)
- } else if HEADTYPE == obj.Hwindows {
+ } else if Headtype == obj.Hdarwin {
+ Errorf(s, "adddynsym: missed symbol (Extname=%s)", s.Extname)
+ } else if Headtype == obj.Hwindows {
// already taken care of
} else {
- Diag("adddynsym: unsupported binary format")
+ Errorf(s, "adddynsym: unsupported binary format")
}
}
func fieldtrack(ctxt *Link) {
// record field tracking references
var buf bytes.Buffer
- for _, s := range ctxt.Allsym {
+ 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
@@ -352,26 +352,26 @@ func fieldtrack(ctxt *Link) {
}
}
- if tracksym == "" {
+ if *flagFieldTrack == "" {
return
}
- s := Linklookup(ctxt, tracksym, 0)
+ s := ctxt.Syms.Lookup(*flagFieldTrack, 0)
if !s.Attr.Reachable() {
return
}
- addstrdata(tracksym, buf.String())
+ addstrdata(ctxt, *flagFieldTrack, buf.String())
}
-func addexport() {
- if HEADTYPE == obj.Hdarwin {
+func (ctxt *Link) addexport() {
+ if Headtype == obj.Hdarwin {
return
}
for _, exp := range dynexp {
- Adddynsym(Ctxt, exp)
+ Adddynsym(ctxt, exp)
}
for _, lib := range dynlib {
- adddynlib(lib)
+ adddynlib(ctxt, lib)
}
}
@@ -419,15 +419,3 @@ func importcycles() {
p.cycle()
}
}
-
-func setlinkmode(arg string) {
- if arg == "internal" {
- Linkmode = LinkInternal
- } else if arg == "external" {
- Linkmode = LinkExternal
- } else if arg == "auto" {
- Linkmode = LinkAuto
- } else {
- Exitf("unknown link mode -linkmode %s", arg)
- }
-}
diff --git a/src/cmd/link/internal/ld/ld.go b/src/cmd/link/internal/ld/ld.go
index bbbfd3e..4750e82 100644
--- a/src/cmd/link/internal/ld/ld.go
+++ b/src/cmd/link/internal/ld/ld.go
@@ -1,6 +1,6 @@
// Derived from Inferno utils/6l/obj.c and utils/6l/span.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6l/obj.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6l/span.c
+// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/obj.c
+// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/span.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth at terzarima.net)
@@ -33,15 +33,15 @@ package ld
import (
"cmd/internal/obj"
- "fmt"
"io/ioutil"
"os"
"path"
+ "path/filepath"
"strconv"
"strings"
)
-func addlib(ctxt *Link, src string, obj string, pathname string) {
+func addlib(ctxt *Link, src string, obj string, pathname string) *Library {
name := path.Clean(pathname)
// runtime.a -> runtime, runtime.6 -> runtime
@@ -53,18 +53,18 @@ func addlib(ctxt *Link, src string, obj string, pathname string) {
// already loaded?
for i := 0; i < len(ctxt.Library); i++ {
if ctxt.Library[i].Pkg == pkg {
- return
+ return ctxt.Library[i]
}
}
var pname string
isshlib := false
- if (ctxt.Windows == 0 && strings.HasPrefix(name, "/")) || (ctxt.Windows != 0 && len(name) >= 2 && name[1] == ':') {
+ if filepath.IsAbs(name) {
pname = name
} else {
// try dot, -L "libdir", and then goroot.
for _, dir := range ctxt.Libdir {
- if Linkshared {
+ if *FlagLinkshared {
pname = dir + "/" + pkg + ".shlibname"
if _, err := os.Stat(pname); err == nil {
isshlib = true
@@ -80,33 +80,32 @@ func addlib(ctxt *Link, src string, obj string, pathname string) {
pname = path.Clean(pname)
- if ctxt.Debugvlog > 1 && ctxt.Bso != nil {
- fmt.Fprintf(ctxt.Bso, "%5.2f addlib: %s %s pulls in %s isshlib %v\n", elapsed(), obj, src, pname, isshlib)
+ if ctxt.Debugvlog > 1 {
+ ctxt.Logf("%5.2f addlib: %s %s pulls in %s isshlib %v\n", elapsed(), obj, src, pname, isshlib)
}
if isshlib {
- addlibpath(ctxt, src, obj, "", pkg, pname)
- } else {
- addlibpath(ctxt, src, obj, pname, pkg, "")
+ return addlibpath(ctxt, src, obj, "", pkg, pname)
}
+ return addlibpath(ctxt, src, obj, pname, pkg, "")
}
/*
- * add library to library list.
+ * add library to library list, return added library.
* srcref: src file referring to package
* objref: object file referring to package
* file: object file, e.g., /home/rsc/go/pkg/container/vector.a
* pkg: package import path, e.g. container/vector
*/
-func addlibpath(ctxt *Link, srcref string, objref string, file string, pkg string, shlibnamefile string) {
+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
+ return ctxt.Library[i]
}
}
- if ctxt.Debugvlog > 1 && ctxt.Bso != nil {
- fmt.Fprintf(ctxt.Bso, "%5.2f addlibpath: srcref: %s objref: %s file: %s pkg: %s shlibnamefile: %s\n", obj.Cputime(), srcref, objref, file, pkg, shlibnamefile)
+ 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.Library = append(ctxt.Library, &Library{})
@@ -118,10 +117,11 @@ func addlibpath(ctxt *Link, srcref string, objref string, file string, pkg strin
if shlibnamefile != "" {
shlibbytes, err := ioutil.ReadFile(shlibnamefile)
if err != nil {
- Diag("cannot read %s: %v", shlibnamefile, err)
+ Errorf(nil, "cannot read %s: %v", shlibnamefile, err)
}
l.Shlib = strings.TrimSpace(string(shlibbytes))
}
+ return l
}
func atolwhex(s string) int64 {
diff --git a/src/cmd/link/internal/ld/ldelf.go b/src/cmd/link/internal/ld/ldelf.go
index af60a5c..00e8f37 100644
--- a/src/cmd/link/internal/ld/ldelf.go
+++ b/src/cmd/link/internal/ld/ldelf.go
@@ -137,6 +137,8 @@ const (
ElfSymTypeFunc = 2
ElfSymTypeSection = 3
ElfSymTypeFile = 4
+ ElfSymTypeCommon = 5
+ ElfSymTypeTLS = 6
)
const (
@@ -264,7 +266,7 @@ type ElfSect struct {
align uint64
entsize uint64
base []byte
- sym *LSym
+ sym *Symbol
}
type ElfObj struct {
@@ -303,29 +305,19 @@ type ElfSym struct {
type_ uint8
other uint8
shndx uint16
- sym *LSym
+ sym *Symbol
}
var ElfMagic = [4]uint8{0x7F, 'E', 'L', 'F'}
-func valuecmp(a *LSym, b *LSym) int {
- if a.Value < b.Value {
- return -1
- }
- if a.Value > b.Value {
- return +1
- }
- return 0
-}
-
const (
- Tag_file = 1
- Tag_CPU_name = 4
- Tag_CPU_raw_name = 5
- Tag_compatibility = 32
- Tag_nodefaults = 64
- Tag_also_compatible_with = 65
- Tag_ABI_VFP_args = 28
+ TagFile = 1
+ TagCPUName = 4
+ TagCPURawName = 5
+ TagCompatibility = 32
+ TagNoDefaults = 64
+ TagAlsoCompatibleWith = 65
+ TagABIVFPArgs = 28
)
type elfAttribute struct {
@@ -366,7 +358,7 @@ func (a *elfAttributeList) uleb128() uint64 {
func (a *elfAttributeList) armAttr() elfAttribute {
attr := elfAttribute{tag: a.uleb128()}
switch {
- case attr.tag == Tag_compatibility:
+ case attr.tag == TagCompatibility:
attr.ival = a.uleb128()
attr.sval = a.string()
@@ -377,7 +369,7 @@ func (a *elfAttributeList) armAttr() elfAttribute {
attr.sval = a.string()
// Tag with string argument
- case attr.tag == Tag_CPU_name || attr.tag == Tag_CPU_raw_name || (attr.tag >= 32 && attr.tag&1 != 0):
+ case attr.tag == TagCPUName || attr.tag == TagCPURawName || (attr.tag >= 32 && attr.tag&1 != 0):
attr.sval = a.string()
default: // Tag with integer argument
@@ -399,13 +391,14 @@ func (a *elfAttributeList) done() bool {
// find the one we are looking for. This format is slightly documented in "ELF
// for the ARM Architecture" but mostly this is derived from reading the source
// to gold and readelf.
-func parseArmAttributes(e binary.ByteOrder, data []byte) {
+func parseArmAttributes(ctxt *Link, e binary.ByteOrder, data []byte) {
// We assume the soft-float ABI unless we see a tag indicating otherwise.
if ehdr.flags == 0x5000002 {
ehdr.flags = 0x5000202
}
if data[0] != 'A' {
- fmt.Fprintf(Bso, ".ARM.attributes has unexpected format %c\n", data[0])
+ // TODO(dfc) should this be ctxt.Diag ?
+ ctxt.Logf(".ARM.attributes has unexpected format %c\n", data[0])
return
}
data = data[1:]
@@ -416,7 +409,8 @@ func parseArmAttributes(e binary.ByteOrder, data []byte) {
nulIndex := bytes.IndexByte(sectiondata, 0)
if nulIndex < 0 {
- fmt.Fprintf(Bso, "corrupt .ARM.attributes (section name not NUL-terminated)\n")
+ // TODO(dfc) should this be ctxt.Diag ?
+ ctxt.Logf("corrupt .ARM.attributes (section name not NUL-terminated)\n")
return
}
name := string(sectiondata[:nulIndex])
@@ -431,28 +425,29 @@ func parseArmAttributes(e binary.ByteOrder, data []byte) {
subsectiondata := sectiondata[sz+4 : subsectionsize]
sectiondata = sectiondata[subsectionsize:]
- if subsectiontag == Tag_file {
+ if subsectiontag == TagFile {
attrList := elfAttributeList{data: subsectiondata}
for !attrList.done() {
attr := attrList.armAttr()
- if attr.tag == Tag_ABI_VFP_args && attr.ival == 1 {
+ if attr.tag == TagABIVFPArgs && attr.ival == 1 {
ehdr.flags = 0x5000402 // has entry point, Version5 EABI, hard-float ABI
}
}
if attrList.err != nil {
- fmt.Fprintf(Bso, "could not parse .ARM.attributes\n")
+ // TODO(dfc) should this be ctxt.Diag ?
+ ctxt.Logf("could not parse .ARM.attributes\n")
}
}
}
}
}
-func ldelf(f *bio.Reader, pkg string, length int64, pn string) {
- if Debug['v'] != 0 {
- fmt.Fprintf(Bso, "%5.2f ldelf %s\n", obj.Cputime(), pn)
+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.IncVersion()
+ localSymVersion := ctxt.Syms.IncVersion()
base := f.Offset()
var add uint64
@@ -472,10 +467,10 @@ func ldelf(f *bio.Reader, pkg string, length int64, pn string) {
var rela int
var rp *Reloc
var rsect *ElfSect
- var s *LSym
+ var s *Symbol
var sect *ElfSect
var sym ElfSym
- var symbols []*LSym
+ var symbols []*Symbol
if _, err := io.ReadFull(f, hdrbuf[:]); err != nil {
goto bad
}
@@ -544,54 +539,60 @@ func ldelf(f *bio.Reader, pkg string, length int64, pn string) {
}
if e.Uint16(hdr.Type[:]) != ElfTypeRelocatable {
- Diag("%s: elf but not elf relocatable object", pn)
+ Errorf(nil, "%s: elf but not elf relocatable object", pn)
return
}
switch SysArch.Family {
default:
- Diag("%s: elf %s unimplemented", pn, SysArch.Name)
+ Errorf(nil, "%s: elf %s unimplemented", pn, SysArch.Name)
return
+ case sys.MIPS:
+ if elfobj.machine != ElfMachMips || hdr.Ident[4] != ElfClass32 {
+ Errorf(nil, "%s: elf object but not mips", pn)
+ return
+ }
+
case sys.MIPS64:
if elfobj.machine != ElfMachMips || hdr.Ident[4] != ElfClass64 {
- Diag("%s: elf object but not mips64", pn)
+ Errorf(nil, "%s: elf object but not mips64", pn)
return
}
case sys.ARM:
if e != binary.LittleEndian || elfobj.machine != ElfMachArm || hdr.Ident[4] != ElfClass32 {
- Diag("%s: elf object but not arm", pn)
+ Errorf(nil, "%s: elf object but not arm", pn)
return
}
case sys.AMD64:
if e != binary.LittleEndian || elfobj.machine != ElfMachAmd64 || hdr.Ident[4] != ElfClass64 {
- Diag("%s: elf object but not amd64", pn)
+ Errorf(nil, "%s: elf object but not amd64", pn)
return
}
case sys.ARM64:
if e != binary.LittleEndian || elfobj.machine != ElfMachArm64 || hdr.Ident[4] != ElfClass64 {
- Diag("%s: elf object but not arm64", pn)
+ Errorf(nil, "%s: elf object but not arm64", pn)
return
}
case sys.I386:
if e != binary.LittleEndian || elfobj.machine != ElfMach386 || hdr.Ident[4] != ElfClass32 {
- Diag("%s: elf object but not 386", pn)
+ Errorf(nil, "%s: elf object but not 386", pn)
return
}
case sys.PPC64:
if elfobj.machine != ElfMachPower64 || hdr.Ident[4] != ElfClass64 {
- Diag("%s: elf object but not ppc64", pn)
+ Errorf(nil, "%s: elf object but not ppc64", pn)
return
}
case sys.S390X:
if elfobj.machine != ElfMachS390 || hdr.Ident[4] != ElfClass64 {
- Diag("%s: elf object but not s390x", pn)
+ Errorf(nil, "%s: elf object but not s390x", pn)
return
}
}
@@ -667,7 +668,7 @@ func ldelf(f *bio.Reader, pkg string, length int64, pn string) {
}
if elfobj.symtab.link <= 0 || elfobj.symtab.link >= uint32(elfobj.nsect) {
- Diag("%s: elf object has symbol table with invalid string table link", pn)
+ Errorf(nil, "%s: elf object has symbol table with invalid string table link", pn)
return
}
@@ -697,7 +698,7 @@ func ldelf(f *bio.Reader, pkg string, length int64, pn string) {
if err = elfmap(elfobj, sect); err != nil {
goto bad
}
- parseArmAttributes(e, sect.base[:sect.size])
+ parseArmAttributes(ctxt, e, sect.base[:sect.size])
}
if (sect.type_ != ElfSectProgbits && sect.type_ != ElfSectNobits) || sect.flags&ElfSectFlagAlloc == 0 {
continue
@@ -709,7 +710,7 @@ func ldelf(f *bio.Reader, pkg string, length int64, pn string) {
}
name = fmt.Sprintf("%s(%s)", pkg, sect.name)
- s = Linklookup(Ctxt, name, Ctxt.Version)
+ s = ctxt.Syms.Lookup(name, localSymVersion)
switch int(sect.flags) & (ElfSectFlagAlloc | ElfSectFlagWrite | ElfSectFlagExec) {
default:
@@ -745,17 +746,17 @@ func ldelf(f *bio.Reader, pkg string, length int64, pn string) {
// enter sub-symbols into symbol table.
// symbol 0 is the null symbol.
- symbols = make([]*LSym, elfobj.nsymtab)
+ symbols = make([]*Symbol, elfobj.nsymtab)
for i := 1; i < elfobj.nsymtab; i++ {
- if err = readelfsym(elfobj, i, &sym, 1); err != nil {
+ if err = readelfsym(ctxt, elfobj, i, &sym, 1, localSymVersion); err != nil {
goto bad
}
symbols[i] = sym.sym
- if sym.type_ != ElfSymTypeFunc && sym.type_ != ElfSymTypeObject && sym.type_ != ElfSymTypeNone {
+ if sym.type_ != ElfSymTypeFunc && sym.type_ != ElfSymTypeObject && sym.type_ != ElfSymTypeNone && sym.type_ != ElfSymTypeCommon {
continue
}
- if sym.shndx == ElfSymShnCommon {
+ if sym.shndx == ElfSymShnCommon || sym.type_ == ElfSymTypeCommon {
s = sym.sym
if uint64(s.Size) < sym.size {
s.Size = int64(sym.size)
@@ -789,7 +790,7 @@ func ldelf(f *bio.Reader, pkg string, length int64, pn string) {
if strings.HasPrefix(sym.name, ".LASF") { // gcc on s390x does this
continue
}
- Diag("%s: sym#%d: ignoring %s in section %d (type %d)", pn, i, sym.name, sym.shndx, sym.type_)
+ Errorf(sym.sym, "%s: sym#%d: ignoring symbol in section %d (type %d)", pn, i, sym.shndx, sym.type_)
continue
}
@@ -812,7 +813,7 @@ func ldelf(f *bio.Reader, pkg string, length int64, pn string) {
s.Outer = sect.sym
if sect.sym.Type == obj.STEXT {
if s.Attr.External() && !s.Attr.DuplicateOK() {
- Diag("%s: duplicate definition of %s", pn, s.Name)
+ Errorf(s, "%s: duplicate symbol definition", pn)
}
s.Attr |= AttrExternal
}
@@ -822,7 +823,7 @@ func ldelf(f *bio.Reader, pkg string, length int64, pn string) {
if 2 <= flag && flag <= 6 {
s.Localentry = 1 << uint(flag-2)
} else if flag == 7 {
- Diag("%s: invalid sym.other 0x%x for %s", pn, sym.other, s.Name)
+ Errorf(s, "%s: invalid sym.other 0x%x", pn, sym.other)
}
}
}
@@ -835,20 +836,20 @@ func ldelf(f *bio.Reader, pkg string, length int64, pn string) {
continue
}
if s.Sub != nil {
- s.Sub = listsort(s.Sub, valuecmp, listsubp)
+ s.Sub = listsort(s.Sub)
}
if s.Type == obj.STEXT {
if s.Attr.OnList() {
log.Fatalf("symbol %s listed multiple times", s.Name)
}
s.Attr |= AttrOnList
- Ctxt.Textp = append(Ctxt.Textp, s)
+ ctxt.Textp = append(ctxt.Textp, s)
for s = s.Sub; s != nil; s = s.Sub {
if s.Attr.OnList() {
log.Fatalf("symbol %s listed multiple times", s.Name)
}
s.Attr |= AttrOnList
- Ctxt.Textp = append(Ctxt.Textp, s)
+ ctxt.Textp = append(ctxt.Textp, s)
}
}
}
@@ -910,7 +911,7 @@ func ldelf(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(elfobj, int(info>>32), &sym, 0); err != nil {
+ if err = readelfsym(ctxt, elfobj, int(info>>32), &sym, 0, 0); err != nil {
goto bad
}
sym.sym = symbols[info>>32]
@@ -922,8 +923,8 @@ func ldelf(f *bio.Reader, pkg string, length int64, pn string) {
rp.Sym = sym.sym
}
- rp.Type = 256 + int32(info)
- rp.Siz = relSize(pn, uint32(info))
+ rp.Type = 256 + obj.RelocType(info)
+ rp.Siz = relSize(ctxt, pn, uint32(info))
if rela != 0 {
rp.Add = int64(add)
} else {
@@ -933,7 +934,7 @@ func ldelf(f *bio.Reader, pkg string, length int64, pn string) {
} else if rp.Siz == 8 {
rp.Add = int64(e.Uint64(sect.base[rp.Off:]))
} else {
- Diag("invalid rela size %d", rp.Siz)
+ Errorf(nil, "invalid rela size %d", rp.Siz)
}
}
@@ -957,7 +958,7 @@ func ldelf(f *bio.Reader, pkg string, length int64, pn string) {
return
bad:
- Diag("%s: malformed elf file: %v", pn, err)
+ Errorf(nil, "%s: malformed elf file: %v", pn, err)
}
func section(elfobj *ElfObj, name string) *ElfSect {
@@ -990,14 +991,14 @@ func elfmap(elfobj *ElfObj, sect *ElfSect) (err error) {
return nil
}
-func readelfsym(elfobj *ElfObj, i int, sym *ElfSym, needSym int) (err error) {
+func readelfsym(ctxt *Link, elfobj *ElfObj, i int, sym *ElfSym, needSym int, localSymVersion int) (err error) {
if i >= elfobj.nsymtab || i < 0 {
err = fmt.Errorf("invalid elf symbol index")
return err
}
if i == 0 {
- Diag("readym: read null symbol!")
+ Errorf(nil, "readym: read null symbol!")
}
if elfobj.is64 != 0 {
@@ -1022,7 +1023,7 @@ func readelfsym(elfobj *ElfObj, i int, sym *ElfSym, needSym int) (err error) {
sym.other = b.Other
}
- var s *LSym
+ var s *Symbol
if sym.name == "_GLOBAL_OFFSET_TABLE_" {
sym.name = ".got"
}
@@ -1036,11 +1037,11 @@ func readelfsym(elfobj *ElfObj, i int, sym *ElfSym, needSym int) (err error) {
case ElfSymTypeSection:
s = elfobj.sect[sym.shndx].sym
- case ElfSymTypeObject, ElfSymTypeFunc, ElfSymTypeNone:
+ case ElfSymTypeObject, ElfSymTypeFunc, ElfSymTypeNone, ElfSymTypeCommon:
switch sym.bind {
case ElfSymBindGlobal:
if needSym != 0 {
- s = Linklookup(Ctxt, sym.name, 0)
+ s = ctxt.Syms.Lookup(sym.name, 0)
// for global scoped hidden symbols we should insert it into
// symbol hash table, but mark them as hidden.
@@ -1066,7 +1067,7 @@ func readelfsym(elfobj *ElfObj, i int, sym *ElfSym, needSym int) (err error) {
// We need to be able to look this up,
// so put it in the hash table.
if needSym != 0 {
- s = Linklookup(Ctxt, sym.name, Ctxt.Version)
+ s = ctxt.Syms.Lookup(sym.name, localSymVersion)
s.Type |= obj.SHIDDEN
}
@@ -1077,14 +1078,14 @@ func readelfsym(elfobj *ElfObj, i int, sym *ElfSym, needSym int) (err error) {
// local names and hidden global names are unique
// and should only be referenced by their index, not name, so we
// don't bother to add them into the hash table
- s = linknewsym(Ctxt, sym.name, Ctxt.Version)
+ s = ctxt.Syms.newsym(sym.name, localSymVersion)
s.Type |= obj.SHIDDEN
}
case ElfSymBindWeak:
if needSym != 0 {
- s = Linklookup(Ctxt, sym.name, 0)
+ s = ctxt.Syms.Lookup(sym.name, 0)
if sym.other == 2 {
s.Type |= obj.SHIDDEN
}
@@ -1126,7 +1127,7 @@ func (x rbyoff) Less(i, j int) bool {
return false
}
-func relSize(pn string, elftype uint32) uint8 {
+func relSize(ctxt *Link, pn string, elftype uint32) uint8 {
// TODO(mdempsky): Replace this with a struct-valued switch statement
// once golang.org/issue/15164 is fixed or found to not impair cmd/link
// performance.
@@ -1141,7 +1142,7 @@ func relSize(pn string, elftype uint32) uint8 {
switch uint32(SysArch.Family) | elftype<<24 {
default:
- Diag("%s: unknown relocation type %d; compiled without -fpic?", pn, elftype)
+ Errorf(nil, "%s: unknown relocation type %d; compiled without -fpic?", pn, elftype)
fallthrough
case S390X | R_390_8<<24:
diff --git a/src/cmd/link/internal/ld/ldmacho.go b/src/cmd/link/internal/ld/ldmacho.go
index a101249..54812b1 100644
--- a/src/cmd/link/internal/ld/ldmacho.go
+++ b/src/cmd/link/internal/ld/ldmacho.go
@@ -43,7 +43,7 @@ const (
N_STAB = 0xe0
)
-type LdMachoObj struct {
+type ldMachoObj struct {
f *bio.Reader
base int64 // off in f where Mach-O begins
length int64 // length of Mach-O
@@ -54,20 +54,20 @@ type LdMachoObj struct {
subcputype uint
filetype uint32
flags uint32
- cmd []LdMachoCmd
+ cmd []ldMachoCmd
ncmd uint
}
-type LdMachoCmd struct {
+type ldMachoCmd struct {
type_ int
off uint32
size uint32
- seg LdMachoSeg
- sym LdMachoSymtab
- dsym LdMachoDysymtab
+ seg ldMachoSeg
+ sym ldMachoSymtab
+ dsym ldMachoDysymtab
}
-type LdMachoSeg struct {
+type ldMachoSeg struct {
name string
vmaddr uint64
vmsize uint64
@@ -77,10 +77,10 @@ type LdMachoSeg struct {
initprot uint32
nsect uint32
flags uint32
- sect []LdMachoSect
+ sect []ldMachoSect
}
-type LdMachoSect struct {
+type ldMachoSect struct {
name string
segname string
addr uint64
@@ -92,11 +92,11 @@ type LdMachoSect struct {
flags uint32
res1 uint32
res2 uint32
- sym *LSym
- rel []LdMachoRel
+ sym *Symbol
+ rel []ldMachoRel
}
-type LdMachoRel struct {
+type ldMachoRel struct {
addr uint32
symnum uint32
pcrel uint8
@@ -107,26 +107,26 @@ type LdMachoRel struct {
value uint32
}
-type LdMachoSymtab struct {
+type ldMachoSymtab struct {
symoff uint32
nsym uint32
stroff uint32
strsize uint32
str []byte
- sym []LdMachoSym
+ sym []ldMachoSym
}
-type LdMachoSym struct {
+type ldMachoSym struct {
name string
type_ uint8
sectnum uint8
desc uint16
kind int8
value uint64
- sym *LSym
+ sym *Symbol
}
-type LdMachoDysymtab struct {
+type ldMachoDysymtab struct {
ilocalsym uint32
nlocalsym uint32
iextdefsym uint32
@@ -175,7 +175,7 @@ const (
LdMachoFilePreload = 5
)
-func unpackcmd(p []byte, m *LdMachoObj, c *LdMachoCmd, type_ uint, sz uint) int {
+func unpackcmd(p []byte, m *ldMachoObj, c *ldMachoCmd, type_ uint, sz uint) int {
e4 := m.e.Uint32
e8 := m.e.Uint64
@@ -198,12 +198,12 @@ func unpackcmd(p []byte, m *LdMachoObj, c *LdMachoCmd, type_ uint, sz uint) int
c.seg.initprot = e4(p[44:])
c.seg.nsect = e4(p[48:])
c.seg.flags = e4(p[52:])
- c.seg.sect = make([]LdMachoSect, c.seg.nsect)
+ c.seg.sect = make([]ldMachoSect, c.seg.nsect)
if uint32(sz) < 56+c.seg.nsect*68 {
return -1
}
p = p[56:]
- var s *LdMachoSect
+ var s *ldMachoSect
for i := 0; uint32(i) < c.seg.nsect; i++ {
s = &c.seg.sect[i]
s.name = cstring(p[0:16])
@@ -233,12 +233,12 @@ func unpackcmd(p []byte, m *LdMachoObj, c *LdMachoCmd, type_ uint, sz uint) int
c.seg.initprot = e4(p[60:])
c.seg.nsect = e4(p[64:])
c.seg.flags = e4(p[68:])
- c.seg.sect = make([]LdMachoSect, c.seg.nsect)
+ c.seg.sect = make([]ldMachoSect, c.seg.nsect)
if uint32(sz) < 72+c.seg.nsect*80 {
return -1
}
p = p[72:]
- var s *LdMachoSect
+ var s *ldMachoSect
for i := 0; uint32(i) < c.seg.nsect; i++ {
s = &c.seg.sect[i]
s.name = cstring(p[0:16])
@@ -293,11 +293,11 @@ func unpackcmd(p []byte, m *LdMachoObj, c *LdMachoCmd, type_ uint, sz uint) int
return 0
}
-func macholoadrel(m *LdMachoObj, sect *LdMachoSect) int {
+func macholoadrel(m *ldMachoObj, sect *ldMachoSect) int {
if sect.rel != nil || sect.nreloc == 0 {
return 0
}
- rel := make([]LdMachoRel, sect.nreloc)
+ rel := make([]ldMachoRel, sect.nreloc)
n := int(sect.nreloc * 8)
buf := make([]byte, n)
if m.f.Seek(m.base+int64(sect.reloff), 0) < 0 {
@@ -307,7 +307,7 @@ func macholoadrel(m *LdMachoObj, sect *LdMachoSect) int {
return -1
}
var p []byte
- var r *LdMachoRel
+ var r *ldMachoRel
var v uint32
for i := 0; uint32(i) < sect.nreloc; i++ {
r = &rel[i]
@@ -345,7 +345,7 @@ func macholoadrel(m *LdMachoObj, sect *LdMachoSect) int {
return 0
}
-func macholoaddsym(m *LdMachoObj, d *LdMachoDysymtab) int {
+func macholoaddsym(m *ldMachoObj, d *ldMachoDysymtab) int {
n := int(d.nindirectsyms)
p := make([]byte, n*4)
@@ -363,7 +363,7 @@ func macholoaddsym(m *LdMachoObj, d *LdMachoDysymtab) int {
return 0
}
-func macholoadsym(m *LdMachoObj, symtab *LdMachoSymtab) int {
+func macholoadsym(m *ldMachoObj, symtab *ldMachoSymtab) int {
if symtab.sym != nil {
return 0
}
@@ -388,9 +388,9 @@ func macholoadsym(m *LdMachoObj, symtab *LdMachoSymtab) int {
if _, err := io.ReadFull(m.f, symbuf); err != nil {
return -1
}
- sym := make([]LdMachoSym, symtab.nsym)
+ sym := make([]ldMachoSym, symtab.nsym)
p := symbuf
- var s *LdMachoSym
+ var s *ldMachoSym
var v uint32
for i := 0; uint32(i) < symtab.nsym; i++ {
s = &sym[i]
@@ -415,7 +415,7 @@ func macholoadsym(m *LdMachoObj, symtab *LdMachoSymtab) int {
return 0
}
-func ldmacho(f *bio.Reader, pkg string, length int64, pn string) {
+func ldmacho(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
var err error
var j int
var is64 bool
@@ -428,23 +428,23 @@ func ldmacho(f *bio.Reader, pkg string, length int64, pn string) {
var ty uint32
var sz uint32
var off uint32
- var m *LdMachoObj
+ var m *ldMachoObj
var e binary.ByteOrder
- var sect *LdMachoSect
- var rel *LdMachoRel
+ var sect *ldMachoSect
+ var rel *ldMachoRel
var rpi int
- var s *LSym
- var s1 *LSym
- var outer *LSym
- var c *LdMachoCmd
- var symtab *LdMachoSymtab
- var dsymtab *LdMachoDysymtab
- var sym *LdMachoSym
+ var s *Symbol
+ var s1 *Symbol
+ var outer *Symbol
+ var c *ldMachoCmd
+ var symtab *ldMachoSymtab
+ var dsymtab *ldMachoDysymtab
+ var sym *ldMachoSym
var r []Reloc
var rp *Reloc
var name string
- Ctxt.IncVersion()
+ localSymVersion := ctxt.Syms.IncVersion()
base := f.Offset()
if _, err := io.ReadFull(f, hdr[:]); err != nil {
goto bad
@@ -471,7 +471,7 @@ func ldmacho(f *bio.Reader, pkg string, length int64, pn string) {
f.Seek(4, 1) // skip reserved word in header
}
- m = new(LdMachoObj)
+ m = new(ldMachoObj)
m.f = f
m.e = e
@@ -487,23 +487,23 @@ func ldmacho(f *bio.Reader, pkg string, length int64, pn string) {
switch SysArch.Family {
default:
- Diag("%s: mach-o %s unimplemented", pn, SysArch.Name)
+ Errorf(nil, "%s: mach-o %s unimplemented", pn, SysArch.Name)
return
case sys.AMD64:
if e != binary.LittleEndian || m.cputype != LdMachoCpuAmd64 {
- Diag("%s: mach-o object but not amd64", pn)
+ Errorf(nil, "%s: mach-o object but not amd64", pn)
return
}
case sys.I386:
if e != binary.LittleEndian || m.cputype != LdMachoCpu386 {
- Diag("%s: mach-o object but not 386", pn)
+ Errorf(nil, "%s: mach-o object but not 386", pn)
return
}
}
- m.cmd = make([]LdMachoCmd, ncmd)
+ m.cmd = make([]ldMachoCmd, ncmd)
off = uint32(len(hdr))
cmdp = make([]byte, cmdsz)
if _, err2 := io.ReadFull(f, cmdp); err2 != nil {
@@ -587,7 +587,7 @@ func ldmacho(f *bio.Reader, pkg string, length int64, pn string) {
continue
}
name = fmt.Sprintf("%s(%s/%s)", pkg, sect.segname, sect.name)
- s = Linklookup(Ctxt, name, Ctxt.Version)
+ s = ctxt.Syms.Lookup(name, localSymVersion)
if s.Type != 0 {
err = fmt.Errorf("duplicate %s/%s", sect.segname, sect.name)
goto bad
@@ -634,9 +634,9 @@ func ldmacho(f *bio.Reader, pkg string, length int64, pn string) {
}
v := 0
if sym.type_&N_EXT == 0 {
- v = Ctxt.Version
+ v = localSymVersion
}
- s = Linklookup(Ctxt, name, v)
+ s = ctxt.Syms.Lookup(name, v)
if sym.type_&N_EXT == 0 {
s.Attr |= AttrDuplicateOK
}
@@ -673,7 +673,7 @@ func ldmacho(f *bio.Reader, pkg string, length int64, pn string) {
}
if outer.Type == obj.STEXT {
if s.Attr.External() && !s.Attr.DuplicateOK() {
- Diag("%s: duplicate definition of %s", pn, s.Name)
+ Errorf(s, "%s: duplicate symbol definition", pn)
}
s.Attr |= AttrExternal
}
@@ -690,7 +690,7 @@ func ldmacho(f *bio.Reader, pkg string, length int64, pn string) {
continue
}
if s.Sub != nil {
- s.Sub = listsort(s.Sub, valuecmp, listsubp)
+ s.Sub = listsort(s.Sub)
// assign sizes, now that we know symbols in sorted order.
for s1 = s.Sub; s1 != nil; s1 = s1.Sub {
@@ -707,13 +707,13 @@ func ldmacho(f *bio.Reader, pkg string, length int64, pn string) {
log.Fatalf("symbol %s listed multiple times", s.Name)
}
s.Attr |= AttrOnList
- Ctxt.Textp = append(Ctxt.Textp, s)
+ ctxt.Textp = append(ctxt.Textp, s)
for s1 = s.Sub; s1 != nil; s1 = s1.Sub {
if s1.Attr.OnList() {
log.Fatalf("symbol %s listed multiple times", s1.Name)
}
s1.Attr |= AttrOnList
- Ctxt.Textp = append(Ctxt.Textp, s1)
+ ctxt.Textp = append(ctxt.Textp, s1)
}
}
}
@@ -738,7 +738,7 @@ func ldmacho(f *bio.Reader, pkg string, length int64, pn string) {
if rel.scattered != 0 {
if SysArch.Family != sys.I386 {
// mach-o only uses scattered relocation on 32-bit platforms
- Diag("unexpected scattered relocation")
+ Errorf(s, "unexpected scattered relocation")
continue
}
@@ -778,7 +778,7 @@ func ldmacho(f *bio.Reader, pkg string, length int64, pn string) {
// now consider the desired symbol.
// find the section where it lives.
- var ks *LdMachoSect
+ var ks *ldMachoSect
for k := 0; uint32(k) < c.seg.nsect; k++ {
ks = &c.seg.sect[k]
if ks.addr <= uint64(rel.value) && uint64(rel.value) < ks.addr+ks.size {
@@ -828,7 +828,7 @@ func ldmacho(f *bio.Reader, pkg string, length int64, pn string) {
}
rp.Siz = rel.length
- rp.Type = 512 + (int32(rel.type_) << 1) + int32(rel.pcrel)
+ rp.Type = 512 + (obj.RelocType(rel.type_) << 1) + obj.RelocType(rel.pcrel)
rp.Off = int32(rel.addr)
// Handle X86_64_RELOC_SIGNED referencing a section (rel->extrn == 0).
@@ -900,5 +900,5 @@ func ldmacho(f *bio.Reader, pkg string, length int64, pn string) {
return
bad:
- Diag("%s: malformed mach-o file: %v", pn, err)
+ Errorf(nil, "%s: malformed mach-o file: %v", pn, err)
}
diff --git a/src/cmd/link/internal/ld/ldpe.go b/src/cmd/link/internal/ld/ldpe.go
index 7eb26bc..f9c49d0 100644
--- a/src/cmd/link/internal/ld/ldpe.go
+++ b/src/cmd/link/internal/ld/ldpe.go
@@ -8,12 +8,12 @@ import (
"cmd/internal/bio"
"cmd/internal/obj"
"cmd/internal/sys"
- "encoding/binary"
+ "debug/pe"
+ "errors"
"fmt"
"io"
"log"
"sort"
- "strconv"
"strings"
)
@@ -100,155 +100,77 @@ const (
IMAGE_REL_AMD64_SSPAN32 = 0x0010
)
-type PeSym struct {
- name string
- value uint32
- sectnum uint16
- type_ uint16
- sclass uint8
- aux uint8
- sym *LSym
-}
-
-type PeSect struct {
- name string
- base []byte
- size uint64
- sym *LSym
- sh IMAGE_SECTION_HEADER
-}
-
-type PeObj struct {
- f *bio.Reader
- name string
- base uint32
- sect []PeSect
- nsect uint
- pesym []PeSym
- npesym uint
- fh IMAGE_FILE_HEADER
- snames []byte
-}
-
-func ldpe(f *bio.Reader, pkg string, length int64, pn string) {
- if Debug['v'] != 0 {
- fmt.Fprintf(Bso, "%5.2f ldpe %s\n", obj.Cputime(), pn)
- }
+// TODO(brainman): maybe just add ReadAt method to bio.Reader instead of creating peBiobuf
- var sect *PeSect
- Ctxt.IncVersion()
- base := f.Offset()
+// peBiobuf makes bio.Reader look like io.ReaderAt.
+type peBiobuf bio.Reader
- peobj := new(PeObj)
- peobj.f = f
- peobj.base = uint32(base)
- peobj.name = pn
-
- // read header
- var err error
- var j int
- var l uint32
- var name string
- var numaux int
- var r []Reloc
- var rp *Reloc
- var rsect *PeSect
- var s *LSym
- var sym *PeSym
- var symbuf [18]uint8
- if err = binary.Read(f, binary.LittleEndian, &peobj.fh); err != nil {
- goto bad
+func (f *peBiobuf) ReadAt(p []byte, off int64) (int, error) {
+ ret := ((*bio.Reader)(f)).Seek(off, 0)
+ if ret < 0 {
+ return 0, errors.New("fail to seek")
}
-
- // load section list
- peobj.sect = make([]PeSect, peobj.fh.NumberOfSections)
-
- peobj.nsect = uint(peobj.fh.NumberOfSections)
- for i := 0; i < int(peobj.fh.NumberOfSections); i++ {
- if err = binary.Read(f, binary.LittleEndian, &peobj.sect[i].sh); err != nil {
- goto bad
- }
- peobj.sect[i].size = uint64(peobj.sect[i].sh.SizeOfRawData)
- peobj.sect[i].name = cstring(peobj.sect[i].sh.Name[:])
+ n, err := f.Read(p)
+ if err != nil {
+ return 0, err
}
+ return n, nil
+}
- // TODO return error if found .cormeta
-
- // load string table
- f.Seek(base+int64(peobj.fh.PointerToSymbolTable)+int64(len(symbuf))*int64(peobj.fh.NumberOfSymbols), 0)
-
- if _, err := io.ReadFull(f, symbuf[:4]); err != nil {
- goto bad
- }
- l = Le32(symbuf[:])
- peobj.snames = make([]byte, l)
- f.Seek(base+int64(peobj.fh.PointerToSymbolTable)+int64(len(symbuf))*int64(peobj.fh.NumberOfSymbols), 0)
- if _, err := io.ReadFull(f, peobj.snames); err != nil {
- goto bad
+func ldpe(ctxt *Link, input *bio.Reader, pkg string, length int64, pn string) {
+ err := ldpeError(ctxt, input, pkg, length, pn)
+ if err != nil {
+ Errorf(nil, "%s: malformed pe file: %v", pn, err)
}
+}
- // rewrite section names if they start with /
- for i := 0; i < int(peobj.fh.NumberOfSections); i++ {
- if peobj.sect[i].name == "" {
- continue
- }
- if peobj.sect[i].name[0] != '/' {
- continue
- }
- n, _ := strconv.Atoi(peobj.sect[i].name[1:])
- peobj.sect[i].name = cstring(peobj.snames[n:])
+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)
}
- // read symbols
- peobj.pesym = make([]PeSym, peobj.fh.NumberOfSymbols)
+ localSymVersion := ctxt.Syms.IncVersion()
- peobj.npesym = uint(peobj.fh.NumberOfSymbols)
- f.Seek(base+int64(peobj.fh.PointerToSymbolTable), 0)
- for i := 0; uint32(i) < peobj.fh.NumberOfSymbols; i += numaux + 1 {
- f.Seek(base+int64(peobj.fh.PointerToSymbolTable)+int64(len(symbuf))*int64(i), 0)
- if _, err := io.ReadFull(f, symbuf[:]); err != nil {
- goto bad
- }
+ sectsyms := make(map[*pe.Section]*Symbol)
+ sectdata := make(map[*pe.Section][]byte)
- if (symbuf[0] == 0) && (symbuf[1] == 0) && (symbuf[2] == 0) && (symbuf[3] == 0) {
- l = Le32(symbuf[4:])
- peobj.pesym[i].name = cstring(peobj.snames[l:]) // sym name length <= 8
- } else {
- peobj.pesym[i].name = cstring(symbuf[:8])
- }
+ // Some input files are archives containing multiple of
+ // object files, and pe.NewFile seeks to the start of
+ // input file and get confused. Create section reader
+ // to stop pe.NewFile looking before current position.
+ sr := io.NewSectionReader((*peBiobuf)(input), input.Offset(), 1<<63-1)
- peobj.pesym[i].value = Le32(symbuf[8:])
- peobj.pesym[i].sectnum = Le16(symbuf[12:])
- peobj.pesym[i].sclass = symbuf[16]
- peobj.pesym[i].aux = symbuf[17]
- peobj.pesym[i].type_ = Le16(symbuf[14:])
- numaux = int(peobj.pesym[i].aux)
- if numaux < 0 {
- numaux = 0
- }
+ // TODO: replace pe.NewFile with pe.Load (grep for "add Load function" in debug/pe for details)
+ f, err := pe.NewFile(sr)
+ if err != nil {
+ return err
}
+ defer f.Close()
+
+ // TODO return error if found .cormeta
// create symbols for mapped sections
- for i := 0; uint(i) < peobj.nsect; i++ {
- sect = &peobj.sect[i]
- if sect.sh.Characteristics&IMAGE_SCN_MEM_DISCARDABLE != 0 {
+ for _, sect := range f.Sections {
+ if sect.Characteristics&IMAGE_SCN_MEM_DISCARDABLE != 0 {
continue
}
- if sect.sh.Characteristics&(IMAGE_SCN_CNT_CODE|IMAGE_SCN_CNT_INITIALIZED_DATA|IMAGE_SCN_CNT_UNINITIALIZED_DATA) == 0 {
+ if sect.Characteristics&(IMAGE_SCN_CNT_CODE|IMAGE_SCN_CNT_INITIALIZED_DATA|IMAGE_SCN_CNT_UNINITIALIZED_DATA) == 0 {
// This has been seen for .idata sections, which we
// want to ignore. See issues 5106 and 5273.
continue
}
- if pemap(peobj, sect) < 0 {
- goto bad
+ data, err := sect.Data()
+ if err != nil {
+ return err
}
+ sectdata[sect] = data
- name = fmt.Sprintf("%s(%s)", pkg, sect.name)
- s = Linklookup(Ctxt, name, Ctxt.Version)
+ name := fmt.Sprintf("%s(%s)", pkg, sect.Name)
+ s := ctxt.Syms.Lookup(name, localSymVersion)
- switch sect.sh.Characteristics & (IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE) {
+ 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
@@ -262,58 +184,59 @@ func ldpe(f *bio.Reader, pkg string, length int64, pn string) {
s.Type = obj.STEXT
default:
- err = fmt.Errorf("unexpected flags %#06x for PE section %s", sect.sh.Characteristics, sect.name)
- goto bad
+ return fmt.Errorf("unexpected flags %#06x for PE section %s", sect.Characteristics, sect.Name)
}
- s.P = sect.base
- s.P = s.P[:sect.size]
- s.Size = int64(sect.size)
- sect.sym = s
- if sect.name == ".rsrc" {
- setpersrc(sect.sym)
+ s.P = data
+ s.Size = int64(len(data))
+ sectsyms[sect] = s
+ if sect.Name == ".rsrc" {
+ setpersrc(ctxt, s)
}
}
// load relocations
- for i := 0; uint(i) < peobj.nsect; i++ {
- rsect = &peobj.sect[i]
- if rsect.sym == nil || rsect.sh.NumberOfRelocations == 0 {
+ for _, rsect := range f.Sections {
+ if _, found := sectsyms[rsect]; !found {
+ continue
+ }
+ if rsect.NumberOfRelocations == 0 {
continue
}
- if rsect.sh.Characteristics&IMAGE_SCN_MEM_DISCARDABLE != 0 {
+ if rsect.Characteristics&IMAGE_SCN_MEM_DISCARDABLE != 0 {
continue
}
- if sect.sh.Characteristics&(IMAGE_SCN_CNT_CODE|IMAGE_SCN_CNT_INITIALIZED_DATA|IMAGE_SCN_CNT_UNINITIALIZED_DATA) == 0 {
+ if rsect.Characteristics&(IMAGE_SCN_CNT_CODE|IMAGE_SCN_CNT_INITIALIZED_DATA|IMAGE_SCN_CNT_UNINITIALIZED_DATA) == 0 {
// This has been seen for .idata sections, which we
// want to ignore. See issues 5106 and 5273.
continue
}
- r = make([]Reloc, rsect.sh.NumberOfRelocations)
- f.Seek(int64(peobj.base)+int64(rsect.sh.PointerToRelocations), 0)
- for j = 0; j < int(rsect.sh.NumberOfRelocations); j++ {
- rp = &r[j]
- if _, err := io.ReadFull(f, symbuf[:10]); err != nil {
- goto bad
+ rs := make([]Reloc, rsect.NumberOfRelocations)
+ for j, r := range rsect.Relocs {
+ rp := &rs[j]
+ if int(r.SymbolTableIndex) >= len(f.COFFSymbols) {
+ return fmt.Errorf("relocation number %d symbol index idx=%d cannot be large then number of symbols %d", j, r.SymbolTableIndex, len(f.COFFSymbols))
}
- rva := Le32(symbuf[0:])
- symindex := Le32(symbuf[4:])
- type_ := Le16(symbuf[8:])
- if err = readpesym(peobj, int(symindex), &sym); err != nil {
- goto bad
+ pesym := &f.COFFSymbols[r.SymbolTableIndex]
+ gosym, err := readpesym(ctxt, f, pesym, sectsyms, localSymVersion)
+ if err != nil {
+ return err
}
- if sym.sym == nil {
- err = fmt.Errorf("reloc of invalid sym %s idx=%d type=%d", sym.name, symindex, sym.type_)
- goto bad
+ if gosym == nil {
+ name, err := pesym.FullName(f.StringTable)
+ if err != nil {
+ name = string(pesym.Name[:])
+ }
+ return fmt.Errorf("reloc of invalid sym %s idx=%d type=%d", name, r.SymbolTableIndex, pesym.Type)
}
- rp.Sym = sym.sym
+ rp.Sym = gosym
rp.Siz = 4
- rp.Off = int32(rva)
- switch type_ {
+ rp.Off = int32(r.VirtualAddress)
+ switch r.Type {
default:
- Diag("%s: unknown relocation type %d;", pn, type_)
+ Errorf(sectsyms[rsect], "%s: unknown relocation type %d;", pn, r.Type)
fallthrough
case IMAGE_REL_I386_REL32, IMAGE_REL_AMD64_REL32,
@@ -321,13 +244,13 @@ func ldpe(f *bio.Reader, pkg string, length int64, pn string) {
IMAGE_REL_AMD64_ADDR32NB:
rp.Type = obj.R_PCREL
- rp.Add = int64(int32(Le32(rsect.base[rp.Off:])))
+ rp.Add = int64(int32(Le32(sectdata[rsect][rp.Off:])))
case IMAGE_REL_I386_DIR32NB, IMAGE_REL_I386_DIR32:
rp.Type = obj.R_ADDR
// load addend from image
- rp.Add = int64(int32(Le32(rsect.base[rp.Off:])))
+ rp.Add = int64(int32(Le32(sectdata[rsect][rp.Off:])))
case IMAGE_REL_AMD64_ADDR64: // R_X86_64_64
rp.Siz = 8
@@ -335,86 +258,99 @@ func ldpe(f *bio.Reader, pkg string, length int64, pn string) {
rp.Type = obj.R_ADDR
// load addend from image
- rp.Add = int64(Le64(rsect.base[rp.Off:]))
+ rp.Add = int64(Le64(sectdata[rsect][rp.Off:]))
}
// ld -r could generate multiple section symbols for the
// same section but with different values, we have to take
// that into account
- if issect(&peobj.pesym[symindex]) {
- rp.Add += int64(peobj.pesym[symindex].value)
+ if issect(pesym) {
+ rp.Add += int64(pesym.Value)
}
}
- sort.Sort(rbyoff(r[:rsect.sh.NumberOfRelocations]))
+ sort.Sort(rbyoff(rs[:rsect.NumberOfRelocations]))
- s = rsect.sym
- s.R = r
- s.R = s.R[:rsect.sh.NumberOfRelocations]
+ s := sectsyms[rsect]
+ s.R = rs
+ s.R = s.R[:rsect.NumberOfRelocations]
}
// enter sub-symbols into symbol table.
- for i := 0; uint(i) < peobj.npesym; i++ {
- if peobj.pesym[i].name == "" {
+ for i, numaux := 0, 0; i < len(f.COFFSymbols); i += numaux + 1 {
+ pesym := &f.COFFSymbols[i]
+
+ numaux = int(pesym.NumberOfAuxSymbols)
+
+ name, err := pesym.FullName(f.StringTable)
+ if err != nil {
+ return err
+ }
+ if name == "" {
+ continue
+ }
+ if issect(pesym) {
continue
}
- if issect(&peobj.pesym[i]) {
+ if int(pesym.SectionNumber) > len(f.Sections) {
continue
}
- if uint(peobj.pesym[i].sectnum) > peobj.nsect {
+ if pesym.SectionNumber == IMAGE_SYM_DEBUG {
continue
}
- if peobj.pesym[i].sectnum > 0 {
- sect = &peobj.sect[peobj.pesym[i].sectnum-1]
- if sect.sym == nil {
+ var sect *pe.Section
+ if pesym.SectionNumber > 0 {
+ sect = f.Sections[pesym.SectionNumber-1]
+ if _, found := sectsyms[sect]; !found {
continue
}
}
- if err = readpesym(peobj, i, &sym); err != nil {
- goto bad
+ s, err := readpesym(ctxt, f, pesym, sectsyms, localSymVersion)
+ if err != nil {
+ return err
}
- s = sym.sym
- if sym.sectnum == 0 { // extern
+ if pesym.SectionNumber == 0 { // extern
if s.Type == obj.SDYNIMPORT {
s.Plt = -2 // flag for dynimport in PE object files.
}
- if s.Type == obj.SXREF && sym.value > 0 { // global data
+ if s.Type == obj.SXREF && pesym.Value > 0 { // global data
s.Type = obj.SNOPTRDATA
- s.Size = int64(sym.value)
+ s.Size = int64(pesym.Value)
}
continue
- } else if sym.sectnum > 0 && uint(sym.sectnum) <= peobj.nsect {
- sect = &peobj.sect[sym.sectnum-1]
- if sect.sym == nil {
- Diag("%s: %s sym == 0!", pn, s.Name)
+ } else if pesym.SectionNumber > 0 && int(pesym.SectionNumber) <= len(f.Sections) {
+ sect = f.Sections[pesym.SectionNumber-1]
+ if _, found := sectsyms[sect]; !found {
+ Errorf(s, "%s: missing sect.sym", pn)
}
} else {
- Diag("%s: %s sectnum < 0!", pn, s.Name)
+ Errorf(s, "%s: sectnum < 0!", pn)
}
if sect == nil {
- return
+ return nil
}
if s.Outer != nil {
if s.Attr.DuplicateOK() {
continue
}
- Exitf("%s: duplicate symbol reference: %s in both %s and %s", pn, s.Name, s.Outer.Name, sect.sym.Name)
+ Exitf("%s: duplicate symbol reference: %s in both %s and %s", pn, s.Name, s.Outer.Name, sectsyms[sect].Name)
}
- s.Sub = sect.sym.Sub
- sect.sym.Sub = s
- s.Type = sect.sym.Type | obj.SSUB
- s.Value = int64(sym.value)
+ sectsym := sectsyms[sect]
+ s.Sub = sectsym.Sub
+ sectsym.Sub = s
+ s.Type = sectsym.Type | obj.SSUB
+ s.Value = int64(pesym.Value)
s.Size = 4
- s.Outer = sect.sym
- if sect.sym.Type == obj.STEXT {
+ s.Outer = sectsym
+ if sectsym.Type == obj.STEXT {
if s.Attr.External() && !s.Attr.DuplicateOK() {
- Diag("%s: duplicate definition of %s", pn, s.Name)
+ Errorf(s, "%s: duplicate symbol definition", pn)
}
s.Attr |= AttrExternal
}
@@ -422,73 +358,47 @@ func ldpe(f *bio.Reader, pkg string, length int64, pn string) {
// Sort outer lists by address, adding to textp.
// This keeps textp in increasing address order.
- for i := 0; uint(i) < peobj.nsect; i++ {
- s = peobj.sect[i].sym
+ for _, sect := range f.Sections {
+ s := sectsyms[sect]
if s == nil {
continue
}
if s.Sub != nil {
- s.Sub = listsort(s.Sub, valuecmp, listsubp)
+ s.Sub = listsort(s.Sub)
}
if s.Type == obj.STEXT {
if s.Attr.OnList() {
log.Fatalf("symbol %s listed multiple times", s.Name)
}
s.Attr |= AttrOnList
- Ctxt.Textp = append(Ctxt.Textp, s)
+ ctxt.Textp = append(ctxt.Textp, s)
for s = s.Sub; s != nil; s = s.Sub {
if s.Attr.OnList() {
log.Fatalf("symbol %s listed multiple times", s.Name)
}
s.Attr |= AttrOnList
- Ctxt.Textp = append(Ctxt.Textp, s)
+ ctxt.Textp = append(ctxt.Textp, s)
}
}
}
- return
-
-bad:
- Diag("%s: malformed pe file: %v", pn, err)
-}
-
-func pemap(peobj *PeObj, sect *PeSect) int {
- if sect.base != nil {
- return 0
- }
-
- sect.base = make([]byte, sect.sh.SizeOfRawData)
- if sect.sh.PointerToRawData == 0 { // .bss doesn't have data in object file
- return 0
- }
- if peobj.f.Seek(int64(peobj.base)+int64(sect.sh.PointerToRawData), 0) < 0 {
- return -1
- }
- if _, err := io.ReadFull(peobj.f, sect.base); err != nil {
- return -1
- }
-
- return 0
+ return nil
}
-func issect(s *PeSym) bool {
- return s.sclass == IMAGE_SYM_CLASS_STATIC && s.type_ == 0 && s.name[0] == '.'
+func issect(s *pe.COFFSymbol) bool {
+ return s.StorageClass == IMAGE_SYM_CLASS_STATIC && s.Type == 0 && s.Name[0] == '.'
}
-func readpesym(peobj *PeObj, i int, y **PeSym) (err error) {
- if uint(i) >= peobj.npesym || i < 0 {
- err = fmt.Errorf("invalid pe symbol index")
- return err
+func readpesym(ctxt *Link, f *pe.File, sym *pe.COFFSymbol, sectsyms map[*pe.Section]*Symbol, localSymVersion int) (*Symbol, error) {
+ symname, err := sym.FullName(f.StringTable)
+ if err != nil {
+ return nil, err
}
-
- sym := &peobj.pesym[i]
- *y = sym
-
var name string
if issect(sym) {
- name = peobj.sect[sym.sectnum-1].sym.Name
+ name = sectsyms[f.Sections[sym.SectionNumber-1]].Name
} else {
- name = sym.name
+ name = symname
if strings.HasPrefix(name, "__imp_") {
name = name[6:] // __imp_Name => Name
}
@@ -502,34 +412,31 @@ func readpesym(peobj *PeObj, i int, y **PeSym) (err error) {
name = name[:i]
}
- var s *LSym
- switch sym.type_ {
+ var s *Symbol
+ switch sym.Type {
default:
- err = fmt.Errorf("%s: invalid symbol type %d", sym.name, sym.type_)
- return err
+ return nil, fmt.Errorf("%s: invalid symbol type %d", symname, sym.Type)
case IMAGE_SYM_DTYPE_FUNCTION, IMAGE_SYM_DTYPE_NULL:
- switch sym.sclass {
+ switch sym.StorageClass {
case IMAGE_SYM_CLASS_EXTERNAL: //global
- s = Linklookup(Ctxt, name, 0)
+ s = ctxt.Syms.Lookup(name, 0)
case IMAGE_SYM_CLASS_NULL, IMAGE_SYM_CLASS_STATIC, IMAGE_SYM_CLASS_LABEL:
- s = Linklookup(Ctxt, name, Ctxt.Version)
+ s = ctxt.Syms.Lookup(name, localSymVersion)
s.Attr |= AttrDuplicateOK
default:
- err = fmt.Errorf("%s: invalid symbol binding %d", sym.name, sym.sclass)
- return err
+ return nil, fmt.Errorf("%s: invalid symbol binding %d", symname, sym.StorageClass)
}
}
- if s != nil && s.Type == 0 && (sym.sclass != IMAGE_SYM_CLASS_STATIC || sym.value != 0) {
+ if s != nil && s.Type == 0 && (sym.StorageClass != IMAGE_SYM_CLASS_STATIC || sym.Value != 0) {
s.Type = obj.SXREF
}
- if strings.HasPrefix(sym.name, "__imp_") {
+ if strings.HasPrefix(symname, "__imp_") {
s.Got = -2 // flag for __imp_
}
- sym.sym = s
- return nil
+ return s, nil
}
diff --git a/src/cmd/link/internal/ld/lib.go b/src/cmd/link/internal/ld/lib.go
index 14f4fa9..fb32190 100644
--- a/src/cmd/link/internal/ld/lib.go
+++ b/src/cmd/link/internal/ld/lib.go
@@ -1,5 +1,5 @@
// Inferno utils/8l/asm.c
-// http://code.google.com/p/inferno-os/source/browse/utils/8l/asm.c
+// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/8l/asm.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth at terzarima.net)
@@ -54,7 +54,7 @@ import (
// Data layout and relocation.
// Derived from Inferno utils/6l/l.h
-// http://code.google.com/p/inferno-os/source/browse/utils/6l/l.h
+// 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)
@@ -95,42 +95,35 @@ type Arch struct {
Openbsddynld string
Dragonflydynld string
Solarisdynld string
- Adddynrel func(*LSym, *Reloc)
- Archinit func()
- Archreloc func(*Reloc, *LSym, *int64) int
- Archrelocvariant func(*Reloc, *LSym, int64) int64
- Asmb func()
- Elfreloc1 func(*Reloc, int64) int
- Elfsetupplt func()
- Gentext func()
- Machoreloc1 func(*Reloc, int64) int
- PEreloc1 func(*Reloc, int64) bool
+ Adddynrel func(*Link, *Symbol, *Reloc) bool
+ Archinit func(*Link)
+ Archreloc func(*Link, *Reloc, *Symbol, *int64) int
+ Archrelocvariant func(*Link, *Reloc, *Symbol, int64) int64
+ Trampoline func(*Link, *Reloc, *Symbol)
+ Asmb func(*Link)
+ Elfreloc1 func(*Link, *Reloc, int64) int
+ Elfsetupplt func(*Link)
+ Gentext func(*Link)
+ Machoreloc1 func(*Symbol, *Reloc, int64) int
+ PEreloc1 func(*Symbol, *Reloc, int64) bool
Wput func(uint16)
Lput func(uint32)
Vput func(uint64)
Append16 func(b []byte, v uint16) []byte
Append32 func(b []byte, v uint32) []byte
Append64 func(b []byte, v uint64) []byte
-}
-
-type Rpath struct {
- set bool
- val string
-}
-
-func (r *Rpath) Set(val string) error {
- r.set = true
- r.val = val
- return nil
-}
-func (r *Rpath) String() string {
- return r.val
+ // TLSIEtoLE converts a TLS Initial Executable relocation to
+ // a TLS Local Executable relocation.
+ //
+ // This is possible when a TLS IE relocation refers to a local
+ // symbol in an executable, which is typical when internally
+ // linking PIE binaries.
+ TLSIEtoLE func(s *Symbol, off, size int)
}
var (
Thearch Arch
- Debug [128]int
Lcsize int32
rpath Rpath
Spsize int32
@@ -171,66 +164,52 @@ type Section struct {
// DynlinkingGo returns whether we are producing Go code that can live
// in separate shared libraries linked together at runtime.
-func DynlinkingGo() bool {
- return Buildmode == BuildmodeShared || Linkshared
+func (ctxt *Link) DynlinkingGo() bool {
+ if !ctxt.Loaded {
+ panic("DynlinkingGo called before all symbols loaded")
+ }
+ canUsePlugins := ctxt.Syms.ROLookup("plugin.Open", 0) != nil
+ return Buildmode == BuildmodeShared || *FlagLinkshared || Buildmode == BuildmodePlugin || canUsePlugins
}
// UseRelro returns whether to make use of "read only relocations" aka
// relro.
func UseRelro() bool {
switch Buildmode {
- case BuildmodeCShared, BuildmodeShared, BuildmodePIE:
+ case BuildmodeCArchive, BuildmodeCShared, BuildmodeShared, BuildmodePIE, BuildmodePlugin:
return Iself
default:
- return Linkshared
+ return *FlagLinkshared
}
}
var (
- SysArch *sys.Arch
- outfile string
- dynexp []*LSym
- dynlib []string
- ldflag []string
- havedynamic int
- Funcalign int
- iscgo bool
- elfglobalsymndx int
- flag_dumpdep bool
- flag_installsuffix string
- flag_race int
- flag_msan int
- Buildmode BuildMode
- Linkshared bool
- tracksym string
- interpreter string
- tmpdir string
- extld string
- extldflags string
- extar string
- libgccfile string
- debug_s int // backup old value of debug['s']
- Ctxt *Link
- HEADR int32
- HEADTYPE int32
- INITRND int32
- INITTEXT int64
- INITDAT int64
- INITENTRY string /* entry point */
- nerrors int
- Linkmode int
- liveness int64
+ SysArch *sys.Arch
+ dynexp []*Symbol
+ dynlib []string
+ ldflag []string
+ havedynamic int
+ Funcalign int
+ iscgo bool
+ elfglobalsymndx int
+ interpreter string
+
+ debug_s bool // backup old value of debug['s']
+ HEADR int32
+ Headtype obj.HeadType
+
+ nerrors int
+ liveness int64
)
var (
- Segtext Segment
- Segrodata Segment
- Segdata Segment
- Segdwarf Segment
+ Segtext Segment
+ Segrodata Segment
+ Segrelrodata Segment
+ Segdata Segment
+ Segdwarf Segment
)
-/* set by call to mywhatsys() */
-
/* whence for ldpkg */
const (
FileObj = 0 + iota
@@ -238,12 +217,6 @@ const (
Pkgdef
)
-var (
- headstring string
- // buffered output
- Bso *bufio.Writer
-)
-
// TODO(dfc) outBuf duplicates bio.Writer
type outBuf struct {
w *bufio.Writer
@@ -263,6 +236,10 @@ func (w *outBuf) WriteString(s string) (n int, err error) {
return n, err
}
+func (w *outBuf) Offset() int64 {
+ return w.off
+}
+
var coutbuf outBuf
const pkgname = "__.PKGDEF"
@@ -271,105 +248,11 @@ var (
// Set if we see an object compiled by the host compiler that is not
// from a package that is known to support internal linking mode.
externalobj = false
- goroot string
- goarch string
- goos string
theline string
)
-func Lflag(arg string) {
- Ctxt.Libdir = append(Ctxt.Libdir, arg)
-}
-
-// A BuildMode indicates the sort of object we are building:
-// "exe": build a main package and everything it imports into an executable.
-// "c-shared": build a main package, plus all packages that it imports, into a
-// single C shared library. The only callable symbols will be those functions
-// marked as exported.
-// "shared": combine all packages passed on the command line, and their
-// dependencies, into a single shared library that will be used when
-// building with the -linkshared option.
-type BuildMode uint8
-
-const (
- BuildmodeUnset BuildMode = iota
- BuildmodeExe
- BuildmodePIE
- BuildmodeCArchive
- BuildmodeCShared
- BuildmodeShared
-)
-
-func (mode *BuildMode) Set(s string) error {
- goos := obj.Getgoos()
- goarch := obj.Getgoarch()
- badmode := func() error {
- return fmt.Errorf("buildmode %s not supported on %s/%s", s, goos, goarch)
- }
- switch s {
- default:
- return fmt.Errorf("invalid buildmode: %q", s)
- case "exe":
- *mode = BuildmodeExe
- case "pie":
- switch goos {
- case "android", "linux":
- default:
- return badmode()
- }
- *mode = BuildmodePIE
- case "c-archive":
- switch goos {
- case "darwin", "linux":
- case "windows":
- switch goarch {
- case "amd64", "386":
- default:
- return badmode()
- }
- default:
- return badmode()
- }
- *mode = BuildmodeCArchive
- case "c-shared":
- switch goarch {
- case "386", "amd64", "arm", "arm64":
- default:
- return badmode()
- }
- *mode = BuildmodeCShared
- case "shared":
- switch goos {
- case "linux":
- switch goarch {
- case "386", "amd64", "arm", "arm64", "ppc64le", "s390x":
- default:
- return badmode()
- }
- default:
- return badmode()
- }
- *mode = BuildmodeShared
- }
- return nil
-}
-
-func (mode *BuildMode) String() string {
- switch *mode {
- case BuildmodeUnset:
- return "" // avoid showing a default in usage message
- case BuildmodeExe:
- return "exe"
- case BuildmodePIE:
- return "pie"
- case BuildmodeCArchive:
- return "c-archive"
- case BuildmodeCShared:
- return "c-shared"
- case BuildmodeShared:
- return "shared"
- }
- return fmt.Sprintf("BuildMode(%d)", uint8(*mode))
+func Lflag(ctxt *Link, arg string) {
+ ctxt.Libdir = append(ctxt.Libdir, arg)
}
/*
@@ -379,67 +262,53 @@ func (mode *BuildMode) String() string {
* S_ISREG() does not exist on Plan 9.
*/
func mayberemoveoutfile() {
- if fi, err := os.Lstat(outfile); err == nil && !fi.Mode().IsRegular() {
+ if fi, err := os.Lstat(*flagOutfile); err == nil && !fi.Mode().IsRegular() {
return
}
- os.Remove(outfile)
+ os.Remove(*flagOutfile)
}
-func libinit() {
+func libinit(ctxt *Link) {
Funcalign = Thearch.Funcalign
- mywhatsys() // get goroot, goarch, goos
// add goroot to the end of the libdir list.
suffix := ""
suffixsep := ""
- if flag_installsuffix != "" {
+ if *flagInstallSuffix != "" {
suffixsep = "_"
- suffix = flag_installsuffix
- } else if flag_race != 0 {
+ suffix = *flagInstallSuffix
+ } else if *flagRace {
suffixsep = "_"
suffix = "race"
- } else if flag_msan != 0 {
+ } else if *flagMsan {
suffixsep = "_"
suffix = "msan"
}
- Lflag(filepath.Join(goroot, "pkg", fmt.Sprintf("%s_%s%s%s", goos, goarch, suffixsep, suffix)))
+ Lflag(ctxt, filepath.Join(obj.GOROOT, "pkg", fmt.Sprintf("%s_%s%s%s", obj.GOOS, obj.GOARCH, suffixsep, suffix)))
mayberemoveoutfile()
- f, err := os.OpenFile(outfile, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0775)
+ f, err := os.OpenFile(*flagOutfile, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0775)
if err != nil {
- Exitf("cannot create %s: %v", outfile, err)
+ Exitf("cannot create %s: %v", *flagOutfile, err)
}
coutbuf.w = bufio.NewWriter(f)
coutbuf.f = f
- if INITENTRY == "" {
+ if *flagEntrySymbol == "" {
switch Buildmode {
case BuildmodeCShared, BuildmodeCArchive:
- INITENTRY = fmt.Sprintf("_rt0_%s_%s_lib", goarch, goos)
+ *flagEntrySymbol = fmt.Sprintf("_rt0_%s_%s_lib", obj.GOARCH, obj.GOOS)
case BuildmodeExe, BuildmodePIE:
- INITENTRY = fmt.Sprintf("_rt0_%s_%s", goarch, goos)
- case BuildmodeShared:
- // No INITENTRY for -buildmode=shared
+ *flagEntrySymbol = fmt.Sprintf("_rt0_%s_%s", obj.GOARCH, obj.GOOS)
+ case BuildmodeShared, BuildmodePlugin:
+ // No *flagEntrySymbol for -buildmode=shared and plugin
default:
- Diag("unknown INITENTRY for buildmode %v", Buildmode)
+ Errorf(nil, "unknown *flagEntrySymbol for buildmode %v", Buildmode)
}
}
-
- if !DynlinkingGo() {
- Linklookup(Ctxt, INITENTRY, 0).Type = obj.SXREF
- }
-}
-
-func Exitf(format string, a ...interface{}) {
- fmt.Fprintf(os.Stderr, os.Args[0]+": "+format+"\n", a...)
- if coutbuf.f != nil {
- coutbuf.f.Close()
- mayberemoveoutfile()
- }
- Exit(2)
}
func errorexit() {
@@ -463,117 +332,106 @@ func errorexit() {
Exit(0)
}
-func loadinternal(name string) {
- found := 0
- for i := 0; i < len(Ctxt.Libdir); i++ {
- if Linkshared {
- shlibname := filepath.Join(Ctxt.Libdir[i], name+".shlibname")
- if Debug['v'] != 0 {
- fmt.Fprintf(Bso, "searching for %s.a in %s\n", name, shlibname)
+func loadinternal(ctxt *Link, name string) *Library {
+ for i := 0; i < len(ctxt.Libdir); i++ {
+ if *FlagLinkshared {
+ shlibname := filepath.Join(ctxt.Libdir[i], name+".shlibname")
+ if ctxt.Debugvlog != 0 {
+ ctxt.Logf("searching for %s.a in %s\n", name, shlibname)
}
if _, err := os.Stat(shlibname); err == nil {
- addlibpath(Ctxt, "internal", "internal", "", name, shlibname)
- found = 1
- break
+ return addlibpath(ctxt, "internal", "internal", "", name, shlibname)
}
}
- pname := filepath.Join(Ctxt.Libdir[i], name+".a")
- if Debug['v'] != 0 {
- fmt.Fprintf(Bso, "searching for %s.a in %s\n", name, pname)
+ pname := filepath.Join(ctxt.Libdir[i], name+".a")
+ if ctxt.Debugvlog != 0 {
+ ctxt.Logf("searching for %s.a in %s\n", name, pname)
}
if _, err := os.Stat(pname); err == nil {
- addlibpath(Ctxt, "internal", "internal", pname, name, "")
- found = 1
- break
+ return addlibpath(ctxt, "internal", "internal", pname, name, "")
}
}
- if found == 0 {
- fmt.Fprintf(Bso, "warning: unable to find %s.a\n", name)
+ ctxt.Logf("warning: unable to find %s.a\n", name)
+ return nil
+}
+
+// findLibPathCmd uses cmd command to find gcc library libname.
+// It returns library full path if found, or "none" if not found.
+func (ctxt *Link) findLibPathCmd(cmd, libname string) string {
+ if *flagExtld == "" {
+ *flagExtld = "gcc"
+ }
+ args := hostlinkArchArgs()
+ args = append(args, cmd)
+ if ctxt.Debugvlog != 0 {
+ ctxt.Logf("%s %v\n", *flagExtld, args)
+ }
+ out, err := exec.Command(*flagExtld, args...).Output()
+ if err != nil {
+ if ctxt.Debugvlog != 0 {
+ ctxt.Logf("not using a %s file because compiler failed\n%v\n%s\n", libname, err, out)
+ }
+ return "none"
}
+ return strings.TrimSpace(string(out))
+}
+
+// findLibPath searches for library libname.
+// It returns library full path if found, or "none" if not found.
+func (ctxt *Link) findLibPath(libname string) string {
+ return ctxt.findLibPathCmd("--print-file-name="+libname, libname)
}
-func loadlib() {
+func (ctxt *Link) loadlib() {
switch Buildmode {
- case BuildmodeCShared:
- s := Linklookup(Ctxt, "runtime.islibrary", 0)
+ case BuildmodeCShared, BuildmodePlugin:
+ s := ctxt.Syms.Lookup("runtime.islibrary", 0)
s.Attr |= AttrDuplicateOK
- Adduint8(Ctxt, s, 1)
+ Adduint8(ctxt, s, 1)
case BuildmodeCArchive:
- s := Linklookup(Ctxt, "runtime.isarchive", 0)
+ s := ctxt.Syms.Lookup("runtime.isarchive", 0)
s.Attr |= AttrDuplicateOK
- Adduint8(Ctxt, s, 1)
+ Adduint8(ctxt, s, 1)
}
- loadinternal("runtime")
+ loadinternal(ctxt, "runtime")
if SysArch.Family == sys.ARM {
- loadinternal("math")
+ loadinternal(ctxt, "math")
}
- if flag_race != 0 {
- loadinternal("runtime/race")
+ if *flagRace {
+ loadinternal(ctxt, "runtime/race")
}
- if flag_msan != 0 {
- loadinternal("runtime/msan")
+ if *flagMsan {
+ loadinternal(ctxt, "runtime/msan")
}
var i int
- for i = 0; i < len(Ctxt.Library); i++ {
- iscgo = iscgo || Ctxt.Library[i].Pkg == "runtime/cgo"
- if Ctxt.Library[i].Shlib == "" {
- if Debug['v'] > 1 {
- fmt.Fprintf(Bso, "%5.2f autolib: %s (from %s)\n", obj.Cputime(), Ctxt.Library[i].File, Ctxt.Library[i].Objref)
+ for i = 0; i < len(ctxt.Library); i++ {
+ 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)
}
- objfile(Ctxt.Library[i])
+ objfile(ctxt, ctxt.Library[i])
}
}
- for i = 0; i < len(Ctxt.Library); i++ {
- if Ctxt.Library[i].Shlib != "" {
- if Debug['v'] > 1 {
- fmt.Fprintf(Bso, "%5.2f autolib: %s (from %s)\n", obj.Cputime(), Ctxt.Library[i].Shlib, Ctxt.Library[i].Objref)
+ 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)
}
- ldshlibsyms(Ctxt.Library[i].Shlib)
+ ldshlibsyms(ctxt, ctxt.Library[i].Shlib)
}
}
- if Linkmode == LinkAuto {
- if iscgo && externalobj {
- Linkmode = LinkExternal
- } else {
- Linkmode = LinkInternal
- }
-
- // Force external linking for android.
- if goos == "android" {
- Linkmode = LinkExternal
- }
-
- // Force external linking for PIE executables, as
- // internal linking does not support TLS_IE.
- if Buildmode == BuildmodePIE {
- Linkmode = LinkExternal
- }
-
- // cgo on Darwin must use external linking
- // we can always use external linking, but then there will be circular
- // dependency problems when compiling natively (external linking requires
- // runtime/cgo, runtime/cgo requires cmd/cgo, but cmd/cgo needs to be
- // compiled using external linking.)
- if SysArch.InFamily(sys.ARM, sys.ARM64) && HEADTYPE == obj.Hdarwin && iscgo {
- Linkmode = LinkExternal
- }
-
- // Force external linking for msan.
- if flag_msan != 0 {
- Linkmode = LinkExternal
- }
- }
+ // We now have enough information to determine the link mode.
+ determineLinkMode(ctxt)
- // cmd/7l doesn't support cgo internal linking
- // This is https://golang.org/issue/10373.
- // mips64x doesn't support cgo internal linking either (golang.org/issue/14449)
- if iscgo && (goarch == "arm64" || goarch == "mips64" || goarch == "mips64le") {
- Linkmode = LinkExternal
+ if Linkmode == LinkExternal && SysArch.Family == sys.PPC64 {
+ toc := ctxt.Syms.Lookup(".TOC.", 0)
+ toc.Type = obj.SDYNIMPORT
}
if Linkmode == LinkExternal && !iscgo {
@@ -581,16 +439,16 @@ func loadlib() {
// The startup code uses an import of runtime/cgo to decide
// whether to initialize the TLS. So give it one. This could
// be handled differently but it's an unusual case.
- loadinternal("runtime/cgo")
+ loadinternal(ctxt, "runtime/cgo")
- if i < len(Ctxt.Library) {
- if Ctxt.Library[i].Shlib != "" {
- ldshlibsyms(Ctxt.Library[i].Shlib)
+ if i < len(ctxt.Library) {
+ if ctxt.Library[i].Shlib != "" {
+ ldshlibsyms(ctxt, ctxt.Library[i].Shlib)
} else {
- if DynlinkingGo() {
+ if Buildmode == BuildmodeShared || *FlagLinkshared {
Exitf("cannot implicitly include runtime/cgo in a shared library")
}
- objfile(Ctxt.Library[i])
+ objfile(ctxt, ctxt.Library[i])
}
}
}
@@ -598,7 +456,7 @@ func loadlib() {
if Linkmode == LinkInternal {
// Drop all the cgo_import_static declarations.
// Turns out we won't be needing them.
- for _, s := range Ctxt.Allsym {
+ for _, s := range ctxt.Syms.Allsym {
if s.Type == obj.SHOSTOBJ {
// If a symbol was marked both
// cgo_import_static and cgo_import_dynamic,
@@ -613,7 +471,7 @@ func loadlib() {
}
}
- tlsg := Linklookup(Ctxt, "runtime.tlsg", 0)
+ tlsg := ctxt.Syms.Lookup("runtime.tlsg", 0)
// runtime.tlsg is used for external linking on platforms that do not define
// a variable to hold g in assembly (currently only intel).
@@ -621,12 +479,18 @@ func loadlib() {
tlsg.Type = obj.STLSBSS
tlsg.Size = int64(SysArch.PtrSize)
} else if tlsg.Type != obj.SDYNIMPORT {
- Diag("internal error: runtime declared tlsg variable %d", tlsg.Type)
+ Errorf(nil, "runtime declared tlsg variable %v", tlsg.Type)
}
tlsg.Attr |= AttrReachable
- Ctxt.Tlsg = tlsg
+ ctxt.Tlsg = tlsg
- moduledata := Linklookup(Ctxt, "runtime.firstmoduledata", 0)
+ var moduledata *Symbol
+ if Buildmode == BuildmodePlugin {
+ moduledata = ctxt.Syms.Lookup("local.pluginmoduledata", 0)
+ moduledata.Attr |= AttrLocal
+ } else {
+ moduledata = ctxt.Syms.Lookup("runtime.firstmoduledata", 0)
+ }
if moduledata.Type != 0 && moduledata.Type != obj.SDYNIMPORT {
// If the module (toolchain-speak for "executable or shared
// library") we are linking contains the runtime package, it
@@ -638,29 +502,29 @@ func loadlib() {
// In addition, on ARM, the runtime depends on the linker
// recording the value of GOARM.
if SysArch.Family == sys.ARM {
- s := Linklookup(Ctxt, "runtime.goarm", 0)
+ s := ctxt.Syms.Lookup("runtime.goarm", 0)
s.Type = obj.SRODATA
s.Size = 0
- Adduint8(Ctxt, s, uint8(Ctxt.Goarm))
+ Adduint8(ctxt, s, uint8(obj.GOARM))
}
- if obj.Framepointer_enabled(obj.Getgoos(), obj.Getgoarch()) {
- s := Linklookup(Ctxt, "runtime.framepointer_enabled", 0)
+ if obj.Framepointer_enabled(obj.GOOS, obj.GOARCH) {
+ s := ctxt.Syms.Lookup("runtime.framepointer_enabled", 0)
s.Type = obj.SRODATA
s.Size = 0
- Adduint8(Ctxt, s, 1)
+ Adduint8(ctxt, s, 1)
}
} else {
// If OTOH the module does not contain the runtime package,
// create a local symbol for the moduledata.
- moduledata = Linklookup(Ctxt, "local.moduledata", 0)
+ moduledata = ctxt.Syms.Lookup("local.moduledata", 0)
moduledata.Attr |= AttrLocal
}
// In all cases way we mark the moduledata as noptrdata to hide it from
// the GC.
moduledata.Type = obj.SNOPTRDATA
moduledata.Attr |= AttrReachable
- Ctxt.Moduledata = moduledata
+ ctxt.Moduledata = moduledata
// Now that we know the link mode, trim the dynexp list.
x := AttrCgoExportDynamic
@@ -679,12 +543,12 @@ func loadlib() {
// In internal link mode, read the host object files.
if Linkmode == LinkInternal {
- hostobjs()
+ hostobjs(ctxt)
// If we have any undefined symbols in external
// objects, try to read them from the libgcc file.
any := false
- for _, s := range Ctxt.Allsym {
+ 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" {
any = true
@@ -693,29 +557,27 @@ func loadlib() {
}
}
if any {
- if libgccfile == "" {
- if extld == "" {
- extld = "gcc"
- }
- args := hostlinkArchArgs()
- args = append(args, "--print-libgcc-file-name")
- if Debug['v'] != 0 {
- fmt.Fprintf(Bso, "%s %v\n", extld, args)
+ if *flagLibGCC == "" {
+ *flagLibGCC = ctxt.findLibPathCmd("--print-libgcc-file-name", "libgcc")
+ }
+ if *flagLibGCC != "none" {
+ hostArchive(ctxt, *flagLibGCC)
+ }
+ if Headtype == obj.Hwindows || Headtype == obj.Hwindowsgui {
+ if p := ctxt.findLibPath("libmingwex.a"); p != "none" {
+ hostArchive(ctxt, p)
}
- out, err := exec.Command(extld, args...).Output()
- if err != nil {
- if Debug['v'] != 0 {
- fmt.Fprintln(Bso, "not using a libgcc file because compiler failed")
- fmt.Fprintf(Bso, "%v\n%s\n", err, out)
- }
- libgccfile = "none"
- } else {
- libgccfile = strings.TrimSpace(string(out))
+ if p := ctxt.findLibPath("libmingw32.a"); p != "none" {
+ hostArchive(ctxt, p)
}
- }
-
- if libgccfile != "none" {
- hostArchive(libgccfile)
+ // TODO: maybe do something similar to peimporteddlls to collect all lib names
+ // and try link them all to final exe just like libmingwex.a and libmingw32.a:
+ /*
+ for:
+ #cgo windows LDFLAGS: -lmsvcrt -lm
+ import:
+ libmsvcrt.a libm.a
+ */
}
}
} else {
@@ -723,6 +585,8 @@ func loadlib() {
}
// We've loaded all the code now.
+ ctxt.Loaded = true
+
// If there are no dynamic libraries needed, gcc disables dynamic linking.
// Because of this, glibc's dynamic ELF loader occasionally (like in version 2.13)
// assumes that a dynamic binary always refers to at least one dynamic library.
@@ -733,14 +597,53 @@ func loadlib() {
// binaries, so leave it enabled on OS X (Mach-O) binaries.
// Also leave it enabled on Solaris which doesn't support
// statically linked binaries.
- switch Buildmode {
- case BuildmodeExe, BuildmodePIE:
- if havedynamic == 0 && HEADTYPE != obj.Hdarwin && HEADTYPE != obj.Hsolaris {
- Debug['d'] = 1
+ if Buildmode == BuildmodeExe {
+ if havedynamic == 0 && Headtype != obj.Hdarwin && Headtype != obj.Hsolaris {
+ *FlagD = true
+ }
+ }
+
+ 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.Attr |= AttrReachable
}
}
importcycles()
+
+ // put symbols into Textp
+ // do it in postorder so that packages are laid down in dependency order
+ // internal first, then everything else
+ ctxt.Library = postorder(ctxt.Library)
+ for _, doInternal := range [2]bool{true, false} {
+ for _, lib := range ctxt.Library {
+ if isRuntimeDepPkg(lib.Pkg) != doInternal {
+ continue
+ }
+ ctxt.Textp = append(ctxt.Textp, lib.textp...)
+ for _, s := range lib.dupTextSyms {
+ if !s.Attr.OnList() {
+ ctxt.Textp = append(ctxt.Textp, s)
+ s.Attr |= AttrOnList
+ }
+ }
+ }
+ }
+
+ if len(ctxt.Shlibs) > 0 {
+ // We might have overwritten some functions above (this tends to happen for the
+ // autogenerated type equality/hashing functions) and we don't want to generated
+ // pcln table entries for these any more so remove them from Textp.
+ textp := make([]*Symbol, 0, len(ctxt.Textp))
+ for _, s := range ctxt.Textp {
+ if s.Type != obj.SDYNIMPORT {
+ textp = append(textp, s)
+ }
+ }
+ ctxt.Textp = textp
+ }
}
/*
@@ -775,13 +678,12 @@ func nextar(bp *bio.Reader, off int64, a *ArHdr) int64 {
return arsize + SAR_HDR
}
-func objfile(lib *Library) {
+func objfile(ctxt *Link, lib *Library) {
pkg := pathtoprefix(lib.Pkg)
- if Debug['v'] > 1 {
- fmt.Fprintf(Bso, "%5.2f ldobj: %s (%s)\n", obj.Cputime(), lib.File, pkg)
+ if ctxt.Debugvlog > 1 {
+ ctxt.Logf("%5.2f ldobj: %s (%s)\n", obj.Cputime(), lib.File, pkg)
}
- Bso.Flush()
f, err := bio.Open(lib.File)
if err != nil {
Exitf("cannot open file %s: %v", lib.File, err)
@@ -796,7 +698,7 @@ func objfile(lib *Library) {
l := f.Seek(0, 2)
f.Seek(0, 0)
- ldobj(f, pkg, l, lib.File, lib.File, FileObj)
+ ldobj(ctxt, f, lib, l, lib.File, lib.File, FileObj)
f.Close()
return
@@ -809,20 +711,20 @@ func objfile(lib *Library) {
l := nextar(f, off, &arhdr)
var pname string
if l <= 0 {
- Diag("%s: short read on archive file symbol header", lib.File)
+ Errorf(nil, "%s: short read on archive file symbol header", lib.File)
goto out
}
if !strings.HasPrefix(arhdr.name, pkgname) {
- Diag("%s: cannot find package header", lib.File)
+ Errorf(nil, "%s: cannot find package header", lib.File)
goto out
}
- if Buildmode == BuildmodeShared {
+ if Buildmode == BuildmodeShared || Buildmode == BuildmodePlugin || ctxt.Syms.ROLookup("plugin.Open", 0) != nil {
before := f.Offset()
pkgdefBytes := make([]byte, atolwhex(arhdr.size))
if _, err := io.ReadFull(f, pkgdefBytes); err != nil {
- Diag("%s: short read on archive file symbol header: %v", lib.File, err)
+ Errorf(nil, "%s: short read on archive file symbol header: %v", lib.File, err)
}
hash := sha1.Sum(pkgdefBytes)
lib.hash = hash[:]
@@ -831,7 +733,7 @@ func objfile(lib *Library) {
off += l
- ldpkg(f, pkg, atolwhex(arhdr.size), lib.File, Pkgdef)
+ ldpkg(ctxt, f, pkg, atolwhex(arhdr.size), lib.File, Pkgdef)
/*
* load all the object files from the archive now.
@@ -858,7 +760,7 @@ func objfile(lib *Library) {
pname = fmt.Sprintf("%s(%s)", lib.File, arhdr.name)
l = atolwhex(arhdr.size)
- ldobj(f, pkg, l, pname, lib.File, ArchiveObj)
+ ldobj(ctxt, f, lib, l, pname, lib.File, ArchiveObj)
}
out:
@@ -866,7 +768,7 @@ out:
}
type Hostobj struct {
- ld func(*bio.Reader, string, int64, string)
+ ld func(*Link, *bio.Reader, string, int64, string)
pkg string
pn string
file string
@@ -887,7 +789,7 @@ var internalpkg = []string{
"runtime/msan",
}
-func ldhostobj(ld func(*bio.Reader, string, int64, string), f *bio.Reader, pkg string, length int64, pn string, file string) *Hostobj {
+func ldhostobj(ld func(*Link, *bio.Reader, string, int64, string), f *bio.Reader, pkg string, length int64, pn string, file string) *Hostobj {
isinternal := false
for i := 0; i < len(internalpkg); i++ {
if pkg == internalpkg[i] {
@@ -902,7 +804,7 @@ func ldhostobj(ld func(*bio.Reader, string, int64, string), f *bio.Reader, pkg s
// 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 == obj.Hdragonfly {
if pkg == "net" || pkg == "os/user" {
isinternal = false
}
@@ -923,7 +825,7 @@ func ldhostobj(ld func(*bio.Reader, string, int64, string), f *bio.Reader, pkg s
return h
}
-func hostobjs() {
+func hostobjs(ctxt *Link) {
var h *Hostobj
for i := 0; i < len(hostobj); i++ {
@@ -934,7 +836,7 @@ func hostobjs() {
}
f.Seek(h.off, 0)
- h.ld(f, h.pkg, h.length, h.pn)
+ h.ld(ctxt, f, h.pkg, h.length, h.pn)
f.Close()
}
}
@@ -942,7 +844,7 @@ func hostobjs() {
// provided by lib9
func rmtemp() {
- os.RemoveAll(tmpdir)
+ os.RemoveAll(*flagTmpdir)
}
func hostlinksetup() {
@@ -953,16 +855,16 @@ func hostlinksetup() {
// For external link, record that we need to tell the external linker -s,
// and turn off -s internally: the external linker needs the symbol
// information for its final link.
- debug_s = Debug['s']
- Debug['s'] = 0
+ debug_s = *FlagS
+ *FlagS = false
// create temporary directory and arrange cleanup
- if tmpdir == "" {
+ if *flagTmpdir == "" {
dir, err := ioutil.TempDir("", "go-link-")
if err != nil {
log.Fatal(err)
}
- tmpdir = dir
+ *flagTmpdir = dir
AtExit(rmtemp)
}
@@ -970,7 +872,7 @@ func hostlinksetup() {
coutbuf.f.Close()
mayberemoveoutfile()
- p := filepath.Join(tmpdir, "go.o")
+ p := filepath.Join(*flagTmpdir, "go.o")
var err error
f, err := os.OpenFile(p, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0775)
if err != nil {
@@ -988,7 +890,7 @@ func hostobjCopy() (paths []string) {
sema := make(chan struct{}, runtime.NumCPU()) // limit open file descriptors
for i, h := range hostobj {
h := h
- dst := filepath.Join(tmpdir, fmt.Sprintf("%06d.o", i))
+ dst := filepath.Join(*flagTmpdir, fmt.Sprintf("%06d.o", i))
paths = append(paths, dst)
wg.Add(1)
@@ -1023,13 +925,13 @@ func hostobjCopy() (paths []string) {
}
// archive builds a .a archive from the hostobj object files.
-func archive() {
+func (ctxt *Link) archive() {
if Buildmode != BuildmodeCArchive {
return
}
- if extar == "" {
- extar = "ar"
+ if *flagExtar == "" {
+ *flagExtar = "ar"
}
mayberemoveoutfile()
@@ -1042,13 +944,12 @@ func archive() {
}
coutbuf.f = nil
- argv := []string{extar, "-q", "-c", "-s", outfile}
- argv = append(argv, filepath.Join(tmpdir, "go.o"))
+ argv := []string{*flagExtar, "-q", "-c", "-s", *flagOutfile}
+ argv = append(argv, filepath.Join(*flagTmpdir, "go.o"))
argv = append(argv, hostobjCopy()...)
- if Debug['v'] != 0 {
- fmt.Fprintf(Bso, "archive: %s\n", strings.Join(argv, " "))
- Bso.Flush()
+ if ctxt.Debugvlog != 0 {
+ ctxt.Logf("archive: %s\n", strings.Join(argv, " "))
}
if out, err := exec.Command(argv[0], argv[1:]...).CombinedOutput(); err != nil {
@@ -1056,7 +957,7 @@ func archive() {
}
}
-func hostlink() {
+func (l *Link) hostlink() {
if Linkmode != LinkExternal || nerrors > 0 {
return
}
@@ -1064,37 +965,39 @@ func hostlink() {
return
}
- if extld == "" {
- extld = "gcc"
+ if *flagExtld == "" {
+ *flagExtld = "gcc"
}
var argv []string
- argv = append(argv, extld)
+ argv = append(argv, *flagExtld)
argv = append(argv, hostlinkArchArgs()...)
- if Debug['s'] == 0 && debug_s == 0 {
+ if !*FlagS && !debug_s {
argv = append(argv, "-gdwarf-2")
} else {
argv = append(argv, "-s")
}
- if HEADTYPE == obj.Hdarwin {
- argv = append(argv, "-Wl,-no_pie,-headerpad,1144")
- }
- if HEADTYPE == obj.Hopenbsd {
- argv = append(argv, "-Wl,-nopie")
- }
- if HEADTYPE == obj.Hwindows {
- if headstring == "windowsgui" {
- argv = append(argv, "-mwindows")
+ switch Headtype {
+ case obj.Hdarwin:
+ argv = append(argv, "-Wl,-headerpad,1144")
+ if l.DynlinkingGo() {
+ argv = append(argv, "-Wl,-flat_namespace")
} else {
- argv = append(argv, "-mconsole")
+ argv = append(argv, "-Wl,-no_pie")
}
+ case obj.Hopenbsd:
+ argv = append(argv, "-Wl,-nopie")
+ case obj.Hwindows:
+ argv = append(argv, "-mconsole")
+ case obj.Hwindowsgui:
+ argv = append(argv, "-mwindows")
}
switch Buildmode {
case BuildmodeExe:
- if HEADTYPE == obj.Hdarwin {
+ if Headtype == obj.Hdarwin {
argv = append(argv, "-Wl,-pagezero_size,4000000")
}
case BuildmodePIE:
@@ -1103,7 +1006,7 @@ func hostlink() {
}
argv = append(argv, "-pie")
case BuildmodeCShared:
- if HEADTYPE == obj.Hdarwin {
+ if Headtype == obj.Hdarwin {
argv = append(argv, "-dynamiclib", "-Wl,-read_only_relocs,suppress")
} else {
// ELF.
@@ -1120,9 +1023,18 @@ func hostlink() {
argv = append(argv, "-Wl,-z,relro")
}
argv = append(argv, "-shared")
+ case BuildmodePlugin:
+ if Headtype == obj.Hdarwin {
+ argv = append(argv, "-dynamiclib")
+ } else {
+ if UseRelro() {
+ argv = append(argv, "-Wl,-z,relro")
+ }
+ argv = append(argv, "-shared")
+ }
}
- if Iself && DynlinkingGo() {
+ if Iself && l.DynlinkingGo() {
// We force all symbol resolution to be done at program startup
// because lazy PLT resolution can use large amounts of stack at
// times we cannot allow it to do so.
@@ -1147,7 +1059,7 @@ func hostlink() {
// If gold is not installed, gcc will silently switch
// back to ld.bfd. So we parse the version information
// and provide a useful error if gold is missing.
- cmd := exec.Command(extld, "-fuse-ld=gold", "-Wl,--version")
+ cmd := exec.Command(*flagExtld, "-fuse-ld=gold", "-Wl,--version")
if out, err := cmd.CombinedOutput(); err == nil {
if !bytes.Contains(out, []byte("GNU gold")) {
log.Fatalf("ARM external linker must be gold (issue #15696), but is not: %s", out)
@@ -1166,8 +1078,8 @@ func hostlink() {
// will decide that the file already has an extension. We
// only want to do this when producing a Windows output file
// on a Windows host.
- outopt := outfile
- if goos == "windows" && runtime.GOOS == "windows" && filepath.Ext(outopt) == "" {
+ outopt := *flagOutfile
+ if obj.GOOS == "windows" && runtime.GOOS == "windows" && filepath.Ext(outopt) == "" {
outopt += "."
}
argv = append(argv, "-o")
@@ -1186,10 +1098,10 @@ func hostlink() {
argv = append(argv, "-Qunused-arguments")
}
- argv = append(argv, filepath.Join(tmpdir, "go.o"))
+ argv = append(argv, filepath.Join(*flagTmpdir, "go.o"))
argv = append(argv, hostobjCopy()...)
- if Linkshared {
+ if *FlagLinkshared {
seenDirs := make(map[string]bool)
seenLibs := make(map[string]bool)
addshlib := func(path string) {
@@ -1208,13 +1120,13 @@ func hostlink() {
seenLibs[base] = true
}
}
- for _, shlib := range Ctxt.Shlibs {
+ for _, shlib := range l.Shlibs {
addshlib(shlib.Path)
for _, dep := range shlib.Deps {
if dep == "" {
continue
}
- libpath := findshlib(dep)
+ libpath := findshlib(l, dep)
if libpath != "" {
addshlib(libpath)
}
@@ -1222,27 +1134,22 @@ func hostlink() {
}
}
- sanitizers := flag_race != 0
-
- for _, flag := range ldflag {
- if strings.HasPrefix(flag, "-fsanitize=") {
- sanitizers = true
- }
- }
-
argv = append(argv, ldflag...)
- if sanitizers {
- // On a system where the toolchain creates position independent
- // executables by default, tsan/msan/asan/etc initialization can
- // fail. So we pass -no-pie here, but support for that flag is quite
- // new and we test for its support first.
- src := filepath.Join(tmpdir, "trivial.c")
+ // When building a program with the default -buildmode=exe the
+ // gc compiler generates code requires DT_TEXTREL in a
+ // position independent executable (PIE). On systems where the
+ // toolchain creates PIEs by default, and where DT_TEXTREL
+ // does not work, the resulting programs will not run. See
+ // issue #17847. To avoid this problem pass -no-pie to the
+ // toolchain if it is supported.
+ if Buildmode == BuildmodeExe {
+ src := filepath.Join(*flagTmpdir, "trivial.c")
if err := ioutil.WriteFile(src, []byte{}, 0666); err != nil {
- Ctxt.Diag("WriteFile trivial.c failed: %v", err)
+ Errorf(nil, "WriteFile trivial.c failed: %v", err)
}
cmd := exec.Command(argv[0], "-c", "-no-pie", "trivial.c")
- cmd.Dir = tmpdir
+ cmd.Dir = *flagTmpdir
cmd.Env = append([]string{"LC_ALL=C"}, os.Environ()...)
out, err := cmd.CombinedOutput()
supported := err == nil && !bytes.Contains(out, []byte("unrecognized"))
@@ -1251,14 +1158,14 @@ func hostlink() {
}
}
- for _, p := range strings.Fields(extldflags) {
+ for _, p := range strings.Fields(*flagExtldflags) {
argv = append(argv, p)
// clang, unlike GCC, passes -rdynamic to the linker
// even when linking with -static, causing a linker
// error when using GNU ld. So take out -rdynamic if
// we added it. We do it in this order, rather than
- // only adding -rdynamic later, so that -extldflags
+ // only adding -rdynamic later, so that -*extldflags
// can override -rdynamic without using -static.
if Iself && p == "-static" {
for i := range argv {
@@ -1268,32 +1175,32 @@ func hostlink() {
}
}
}
- if HEADTYPE == obj.Hwindows {
+ if Headtype == obj.Hwindows || Headtype == obj.Hwindowsgui {
+ // libmingw32 and libmingwex have some inter-dependencies,
+ // so must use linker groups.
+ argv = append(argv, "-Wl,--start-group", "-lmingwex", "-lmingw32", "-Wl,--end-group")
argv = append(argv, peimporteddlls()...)
}
- if Debug['v'] != 0 {
- fmt.Fprintf(Bso, "host link:")
+ if l.Debugvlog != 0 {
+ l.Logf("%5.2f host link:", obj.Cputime())
for _, v := range argv {
- fmt.Fprintf(Bso, " %q", v)
+ l.Logf(" %q", v)
}
- fmt.Fprintf(Bso, "\n")
- Bso.Flush()
+ l.Logf("\n")
}
if out, err := exec.Command(argv[0], argv[1:]...).CombinedOutput(); err != nil {
Exitf("running %s failed: %v\n%s", argv[0], err, out)
- } else if Debug['v'] != 0 && len(out) > 0 {
- fmt.Fprintf(Bso, "%s", out)
- Bso.Flush()
+ } else if l.Debugvlog != 0 && len(out) > 0 {
+ l.Logf("%s", out)
}
- if Debug['s'] == 0 && debug_s == 0 && HEADTYPE == obj.Hdarwin {
+ if !*FlagS && !debug_s && Headtype == obj.Hdarwin {
// Skip combining dwarf on arm.
if !SysArch.InFamily(sys.ARM, sys.ARM64) {
- dsym := filepath.Join(tmpdir, "go.dwarf")
- if out, err := exec.Command("dsymutil", "-f", outfile, "-o", dsym).CombinedOutput(); err != nil {
- Ctxt.Cursym = nil
+ dsym := filepath.Join(*flagTmpdir, "go.dwarf")
+ if out, err := exec.Command("dsymutil", "-f", *flagOutfile, "-o", dsym).CombinedOutput(); err != nil {
Exitf("%s: running dsymutil failed: %v\n%s", os.Args[0], err, out)
}
// Skip combining if `dsymutil` didn't generate a file. See #11994.
@@ -1301,14 +1208,12 @@ func hostlink() {
return
}
// For os.Rename to work reliably, must be in same directory as outfile.
- combinedOutput := outfile + "~"
- if err := machoCombineDwarf(outfile, dsym, combinedOutput); err != nil {
- Ctxt.Cursym = nil
+ combinedOutput := *flagOutfile + "~"
+ if err := machoCombineDwarf(*flagOutfile, dsym, combinedOutput); err != nil {
Exitf("%s: combining dwarf failed: %v", os.Args[0], err)
}
- os.Remove(outfile)
- if err := os.Rename(combinedOutput, outfile); err != nil {
- Ctxt.Cursym = nil
+ os.Remove(*flagOutfile)
+ if err := os.Rename(combinedOutput, *flagOutfile); err != nil {
Exitf("%s: %v", os.Args[0], err)
}
}
@@ -1336,9 +1241,10 @@ func hostlinkArchArgs() []string {
// ldobj loads an input object. If it is a host object (an object
// compiled by a non-Go compiler) it returns the Hostobj pointer. If
// it is a Go object, it returns nil.
-func ldobj(f *bio.Reader, pkg string, length int64, pn string, file string, whence int) *Hostobj {
- eof := f.Offset() + length
+func ldobj(ctxt *Link, f *bio.Reader, lib *Library, length int64, pn string, file string, whence int) *Hostobj {
+ pkg := pathtoprefix(lib.Pkg)
+ eof := f.Offset() + length
start := f.Offset()
c1 := bgetc(f)
c2 := bgetc(f)
@@ -1362,7 +1268,7 @@ func ldobj(f *bio.Reader, pkg string, length int64, pn string, file string, when
/* check the header */
line, err := f.ReadString('\n')
if err != nil {
- Diag("truncated object file: %s: %v", pn, err)
+ Errorf(nil, "truncated object file: %s: %v", pn, err)
return nil
}
@@ -1374,20 +1280,20 @@ func ldobj(f *bio.Reader, pkg string, length int64, pn string, file string, when
if line == SysArch.Name {
// old header format: just $GOOS
- Diag("%s: stale object file", pn)
+ Errorf(nil, "%s: stale object file", pn)
return nil
}
- Diag("%s: not an object file", pn)
+ Errorf(nil, "%s: not an object file", pn)
return nil
}
- // First, check that the basic goos, goarch, and version match.
- t := fmt.Sprintf("%s %s %s ", goos, obj.Getgoarch(), obj.Getgoversion())
+ // First, check that the basic GOOS, GOARCH, and Version match.
+ t := fmt.Sprintf("%s %s %s ", obj.GOOS, obj.GOARCH, obj.Version)
line = strings.TrimRight(line, "\n")
- if !strings.HasPrefix(line[10:]+" ", t) && Debug['f'] == 0 {
- Diag("%s: object is [%s] expected [%s]", pn, line[10:], t)
+ if !strings.HasPrefix(line[10:]+" ", t) && !*flagF {
+ Errorf(nil, "%s: object is [%s] expected [%s]", pn, line[10:], t)
return nil
}
@@ -1398,7 +1304,7 @@ func ldobj(f *bio.Reader, pkg string, length int64, pn string, file string, when
if theline == "" {
theline = line[10:]
} else if theline != line[10:] {
- Diag("%s: object is [%s] expected [%s]", pn, line[10:], theline)
+ Errorf(nil, "%s: object is [%s] expected [%s]", pn, line[10:], theline)
return nil
}
}
@@ -1414,7 +1320,7 @@ func ldobj(f *bio.Reader, pkg string, length int64, pn string, file string, when
c2 = c3
c3 = bgetc(f)
if c3 == -1 {
- Diag("truncated object file: %s", pn)
+ Errorf(nil, "truncated object file: %s", pn)
return nil
}
}
@@ -1422,22 +1328,22 @@ func ldobj(f *bio.Reader, pkg string, length int64, pn string, file string, when
import1 := f.Offset()
f.Seek(import0, 0)
- ldpkg(f, pkg, import1-import0-2, pn, whence) // -2 for !\n
+ ldpkg(ctxt, f, pkg, import1-import0-2, pn, whence) // -2 for !\n
f.Seek(import1, 0)
- LoadObjFile(Ctxt, f, pkg, eof-f.Offset(), pn)
+ LoadObjFile(ctxt, f, lib, eof-f.Offset(), pn)
return nil
}
-func readelfsymboldata(f *elf.File, sym *elf.Symbol) []byte {
+func readelfsymboldata(ctxt *Link, f *elf.File, sym *elf.Symbol) []byte {
data := make([]byte, sym.Size)
sect := f.Sections[sym.Section]
if sect.Type != elf.SHT_PROGBITS && sect.Type != elf.SHT_NOTE {
- Diag("reading %s from non-data section", sym.Name)
+ Errorf(nil, "reading %s from non-data section", sym.Name)
}
n, err := sect.ReadAt(data, int64(sym.Value-sect.Addr))
if uint64(n) != sym.Size {
- Diag("reading contents of %s: %v", sym.Name, err)
+ Errorf(nil, "reading contents of %s: %v", sym.Name, err)
}
return data
}
@@ -1491,62 +1397,61 @@ func readnote(f *elf.File, name []byte, typ int32) ([]byte, error) {
return nil, nil
}
-func findshlib(shlib string) string {
- for _, libdir := range Ctxt.Libdir {
+func findshlib(ctxt *Link, shlib string) string {
+ for _, libdir := range ctxt.Libdir {
libpath := filepath.Join(libdir, shlib)
if _, err := os.Stat(libpath); err == nil {
return libpath
}
}
- Diag("cannot find shared library: %s", shlib)
+ Errorf(nil, "cannot find shared library: %s", shlib)
return ""
}
-func ldshlibsyms(shlib string) {
- libpath := findshlib(shlib)
+func ldshlibsyms(ctxt *Link, shlib string) {
+ libpath := findshlib(ctxt, shlib)
if libpath == "" {
return
}
- for _, processedlib := range Ctxt.Shlibs {
+ for _, processedlib := range ctxt.Shlibs {
if processedlib.Path == libpath {
return
}
}
- if Ctxt.Debugvlog > 1 && Ctxt.Bso != nil {
- fmt.Fprintf(Ctxt.Bso, "%5.2f ldshlibsyms: found library with name %s at %s\n", obj.Cputime(), shlib, libpath)
- Ctxt.Bso.Flush()
+ if ctxt.Debugvlog > 1 {
+ ctxt.Logf("%5.2f ldshlibsyms: found library with name %s at %s\n", obj.Cputime(), shlib, libpath)
}
f, err := elf.Open(libpath)
if err != nil {
- Diag("cannot open shared library: %s", libpath)
+ Errorf(nil, "cannot open shared library: %s", libpath)
return
}
hash, err := readnote(f, ELF_NOTE_GO_NAME, ELF_NOTE_GOABIHASH_TAG)
if err != nil {
- Diag("cannot read ABI hash from shared library %s: %v", libpath, err)
+ Errorf(nil, "cannot read ABI hash from shared library %s: %v", libpath, err)
return
}
depsbytes, err := readnote(f, ELF_NOTE_GO_NAME, ELF_NOTE_GODEPS_TAG)
if err != nil {
- Diag("cannot read dep list from shared library %s: %v", libpath, err)
+ Errorf(nil, "cannot read dep list from shared library %s: %v", libpath, err)
return
}
deps := strings.Split(string(depsbytes), "\n")
syms, err := f.DynamicSymbols()
if err != nil {
- Diag("cannot read symbols from shared library: %s", libpath)
+ Errorf(nil, "cannot read symbols from shared library: %s", libpath)
return
}
- gcdata_locations := make(map[uint64]*LSym)
+ gcdataLocations := make(map[uint64]*Symbol)
for _, elfsym := range syms {
if elf.ST_TYPE(elfsym.Info) == elf.STT_NOTYPE || elf.ST_TYPE(elfsym.Info) == elf.STT_SECTION {
continue
}
- lsym := Linklookup(Ctxt, elfsym.Name, 0)
+ lsym := ctxt.Syms.Lookup(elfsym.Name, 0)
// Because loadlib above loads all .a files before loading any shared
// libraries, any non-dynimport symbols we find that duplicate symbols
// already loaded should be ignored (the symbols from the .a files
@@ -1563,12 +1468,12 @@ func ldshlibsyms(shlib string) {
// The decodetype_* functions in decodetype.go need access to
// the type data.
if strings.HasPrefix(lsym.Name, "type.") && !strings.HasPrefix(lsym.Name, "type..") {
- lsym.P = readelfsymboldata(f, &elfsym)
- gcdata_locations[elfsym.Value+2*uint64(SysArch.PtrSize)+8+1*uint64(SysArch.PtrSize)] = lsym
+ lsym.P = readelfsymboldata(ctxt, f, &elfsym)
+ gcdataLocations[elfsym.Value+2*uint64(SysArch.PtrSize)+8+1*uint64(SysArch.PtrSize)] = lsym
}
}
}
- gcdata_addresses := make(map[*LSym]uint64)
+ gcdataAddresses := make(map[*Symbol]uint64)
if SysArch.Family == sys.ARM64 {
for _, sect := range f.Sections {
if sect.Type == elf.SHT_RELA {
@@ -1579,39 +1484,22 @@ func ldshlibsyms(shlib string) {
if err == io.EOF {
break
} else if err != nil {
- Diag("reading relocation failed %v", err)
+ Errorf(nil, "reading relocation failed %v", err)
return
}
t := elf.R_AARCH64(rela.Info & 0xffff)
if t != elf.R_AARCH64_RELATIVE {
continue
}
- if lsym, ok := gcdata_locations[rela.Off]; ok {
- gcdata_addresses[lsym] = uint64(rela.Addend)
+ if lsym, ok := gcdataLocations[rela.Off]; ok {
+ gcdataAddresses[lsym] = uint64(rela.Addend)
}
}
}
}
}
- // We might have overwritten some functions above (this tends to happen for the
- // autogenerated type equality/hashing functions) and we don't want to generated
- // pcln table entries for these any more so remove them from Textp.
- textp := make([]*LSym, 0, len(Ctxt.Textp))
- for _, s := range Ctxt.Textp {
- if s.Type != obj.SDYNIMPORT {
- textp = append(textp, s)
- }
- }
- Ctxt.Textp = textp
-
- Ctxt.Shlibs = append(Ctxt.Shlibs, Shlib{Path: libpath, Hash: hash, Deps: deps, File: f, gcdata_addresses: gcdata_addresses})
-}
-
-func mywhatsys() {
- goroot = obj.Getgoroot()
- goos = obj.Getgoos()
- goarch = obj.Getgoarch()
+ 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.
@@ -1677,32 +1565,32 @@ func Be32(b []byte) uint32 {
return uint32(b[0])<<24 | uint32(b[1])<<16 | uint32(b[2])<<8 | uint32(b[3])
}
-type Chain struct {
- sym *LSym
- up *Chain
+type chain struct {
+ sym *Symbol
+ up *chain
limit int // limit on entry to sym
}
-var morestack *LSym
+var morestack *Symbol
// TODO: Record enough information in new object files to
// allow stack checks here.
-func haslinkregister() bool {
- return Ctxt.FixedFrameSize() != 0
+func haslinkregister(ctxt *Link) bool {
+ return ctxt.FixedFrameSize() != 0
}
-func callsize() int {
- if haslinkregister() {
+func callsize(ctxt *Link) int {
+ if haslinkregister(ctxt) {
return 0
}
return SysArch.RegSize
}
-func dostkcheck() {
- var ch Chain
+func (ctxt *Link) dostkcheck() {
+ var ch chain
- morestack = Linklookup(Ctxt, "runtime.morestack", 0)
+ morestack = ctxt.Syms.Lookup("runtime.morestack", 0)
// Every splitting function ensures that there are at least StackLimit
// bytes available below SP when the splitting prologue finishes.
@@ -1713,11 +1601,11 @@ func dostkcheck() {
// of non-splitting functions.
ch.up = nil
- ch.limit = obj.StackLimit - callsize()
+ ch.limit = obj.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.
- for _, s := range Ctxt.Textp {
+ for _, s := range ctxt.Textp {
// runtime.racesymbolizethunk is called from gcc-compiled C
// code running on the operating system thread stack.
// It uses more than the usual amount of stack but that's okay.
@@ -1726,28 +1614,26 @@ func dostkcheck() {
}
if s.Attr.NoSplit() {
- Ctxt.Cursym = s
ch.sym = s
- stkcheck(&ch, 0)
+ stkcheck(ctxt, &ch, 0)
}
}
- for _, s := range Ctxt.Textp {
+ for _, s := range ctxt.Textp {
if !s.Attr.NoSplit() {
- Ctxt.Cursym = s
ch.sym = s
- stkcheck(&ch, 0)
+ stkcheck(ctxt, &ch, 0)
}
}
}
-func stkcheck(up *Chain, depth int) int {
+func stkcheck(ctxt *Link, up *chain, depth int) int {
limit := up.limit
s := up.sym
// Don't duplicate work: only need to consider each
// function at top of safe zone once.
- top := limit == obj.StackLimit-callsize()
+ top := limit == obj.StackLimit-callsize(ctxt)
if top {
if s.Attr.StackCheck() {
return 0
@@ -1756,25 +1642,26 @@ func stkcheck(up *Chain, depth int) int {
}
if depth > 100 {
- Diag("nosplit stack check too deep")
- stkbroke(up, 0)
+ Errorf(s, "nosplit stack check too deep")
+ stkbroke(ctxt, up, 0)
return -1
}
if s.Attr.External() || s.FuncInfo == nil {
// external function.
// should never be called directly.
- // only diagnose the direct caller.
+ // onlyctxt.Diagnose the direct caller.
// TODO(mwhudson): actually think about this.
- if depth == 1 && s.Type != obj.SXREF && !DynlinkingGo() &&
- Buildmode != BuildmodePIE && Buildmode != BuildmodeCShared {
- Diag("call to external function %s", s.Name)
+ if depth == 1 && s.Type != obj.SXREF && !ctxt.DynlinkingGo() &&
+ Buildmode != BuildmodeCArchive && Buildmode != BuildmodePIE && Buildmode != BuildmodeCShared && Buildmode != BuildmodePlugin {
+
+ Errorf(s, "call to external function")
}
return -1
}
if limit < 0 {
- stkbroke(up, limit)
+ stkbroke(ctxt, up, limit)
return -1
}
@@ -1784,14 +1671,14 @@ func stkcheck(up *Chain, depth int) int {
return 0
}
- var ch Chain
+ var ch chain
ch.up = up
if !s.Attr.NoSplit() {
// Ensure we have enough stack to call morestack.
- ch.limit = limit - callsize()
+ ch.limit = limit - callsize(ctxt)
ch.sym = morestack
- if stkcheck(&ch, depth+1) < 0 {
+ if stkcheck(ctxt, &ch, depth+1) < 0 {
return -1
}
if !top {
@@ -1802,22 +1689,22 @@ func stkcheck(up *Chain, depth int) int {
if s.FuncInfo != nil {
locals = s.FuncInfo.Locals
}
- limit = int(obj.StackLimit+locals) + int(Ctxt.FixedFrameSize())
+ limit = int(obj.StackLimit+locals) + int(ctxt.FixedFrameSize())
}
// Walk through sp adjustments in function, consuming relocs.
ri := 0
endr := len(s.R)
- var ch1 Chain
+ var ch1 chain
var pcsp Pciter
var r *Reloc
- for pciterinit(Ctxt, &pcsp, &s.FuncInfo.Pcsp); pcsp.done == 0; pciternext(&pcsp) {
+ for pciterinit(ctxt, &pcsp, &s.FuncInfo.Pcsp); pcsp.done == 0; pciternext(&pcsp) {
// pcsp.value is in effect for [pcsp.pc, pcsp.nextpc).
// Check stack size in effect for this span.
if int32(limit)-pcsp.value < 0 {
- stkbroke(up, int(int32(limit)-pcsp.value))
+ stkbroke(ctxt, up, int(int32(limit)-pcsp.value))
return -1
}
@@ -1827,9 +1714,9 @@ func stkcheck(up *Chain, depth int) int {
switch r.Type {
// Direct call.
case obj.R_CALL, obj.R_CALLARM, obj.R_CALLARM64, obj.R_CALLPOWER, obj.R_CALLMIPS:
- ch.limit = int(int32(limit) - pcsp.value - int32(callsize()))
+ ch.limit = int(int32(limit) - pcsp.value - int32(callsize(ctxt)))
ch.sym = r.Sym
- if stkcheck(&ch, depth+1) < 0 {
+ if stkcheck(ctxt, &ch, depth+1) < 0 {
return -1
}
@@ -1838,13 +1725,13 @@ func stkcheck(up *Chain, depth int) int {
// Arrange the data structures to report both calls, so that
// if there is an error, stkprint shows all the steps involved.
case obj.R_CALLIND:
- ch.limit = int(int32(limit) - pcsp.value - int32(callsize()))
+ ch.limit = int(int32(limit) - pcsp.value - int32(callsize(ctxt)))
ch.sym = nil
- ch1.limit = ch.limit - callsize() // for morestack in called prologue
+ ch1.limit = ch.limit - callsize(ctxt) // for morestack in called prologue
ch1.up = &ch
ch1.sym = morestack
- if stkcheck(&ch1, depth+2) < 0 {
+ if stkcheck(ctxt, &ch1, depth+2) < 0 {
return -1
}
}
@@ -1854,12 +1741,12 @@ func stkcheck(up *Chain, depth int) int {
return 0
}
-func stkbroke(ch *Chain, limit int) {
- Diag("nosplit stack overflow")
- stkprint(ch, limit)
+func stkbroke(ctxt *Link, ch *chain, limit int) {
+ Errorf(ch.sym, "nosplit stack overflow")
+ stkprint(ctxt, ch, limit)
}
-func stkprint(ch *Chain, limit int) {
+func stkprint(ctxt *Link, ch *chain, limit int) {
var name string
if ch.sym != nil {
@@ -1879,8 +1766,8 @@ func stkprint(ch *Chain, limit int) {
fmt.Printf("\t%d\tguaranteed after split check in %s\n", ch.limit, name)
}
} else {
- stkprint(ch.up, ch.limit+callsize())
- if !haslinkregister() {
+ stkprint(ctxt, ch.up, ch.limit+callsize(ctxt))
+ if !haslinkregister(ctxt) {
fmt.Printf("\t%d\ton entry to %s\n", ch.limit, name)
}
}
@@ -1896,10 +1783,6 @@ func Cflush() {
}
}
-func Cpos() int64 {
- return coutbuf.off
-}
-
func Cseek(p int64) {
if p == coutbuf.off {
return
@@ -1930,38 +1813,59 @@ func usage() {
Exit(2)
}
-func setheadtype(s string) {
- h := headtype(s)
- if h < 0 {
- Exitf("unknown header type -H %s", s)
- }
-
- headstring = s
- HEADTYPE = int32(headtype(s))
+func doversion() {
+ Exitf("version %s", obj.Version)
}
-func setinterp(s string) {
- Debug['I'] = 1 // denote cmdline interpreter override
- interpreter = s
-}
+type SymbolType int8
-func doversion() {
- Exitf("version %s", obj.Getgoversion())
-}
+const (
+ TextSym SymbolType = 'T'
+ DataSym = 'D'
+ BSSSym = 'B'
+ UndefinedSym = 'U'
+ TLSSym = 't'
+ FileSym = 'f'
+ FrameSym = 'm'
+ ParamSym = 'p'
+ AutoSym = 'a'
+)
-func genasmsym(put func(*LSym, string, int, int64, int64, int, *LSym)) {
+func genasmsym(ctxt *Link, put func(*Link, *Symbol, string, SymbolType, int64, *Symbol)) {
// These symbols won't show up in the first loop below because we
// skip STEXT symbols. Normal STEXT symbols are emitted by walking textp.
- s := Linklookup(Ctxt, "runtime.text", 0)
+ s := ctxt.Syms.Lookup("runtime.text", 0)
if s.Type == obj.STEXT {
- put(s, s.Name, 'T', s.Value, s.Size, int(s.Version), nil)
+ 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 {
+ if n == 0 {
+ n++
+ continue
+ }
+ if sect.Name != ".text" {
+ break
+ }
+ s = ctxt.Syms.ROLookup(fmt.Sprintf("runtime.text.%d", n), 0)
+ if s == nil {
+ break
+ }
+ if s.Type == obj.STEXT {
+ put(ctxt, s, s.Name, TextSym, s.Value, nil)
+ }
+ n++
}
- s = Linklookup(Ctxt, "runtime.etext", 0)
+
+ s = ctxt.Syms.Lookup("runtime.etext", 0)
if s.Type == obj.STEXT {
- put(s, s.Name, 'T', s.Value, s.Size, int(s.Version), nil)
+ put(ctxt, s, s.Name, TextSym, s.Value, nil)
}
- for _, s := range Ctxt.Allsym {
+ for _, s := range ctxt.Syms.Allsym {
if s.Attr.Hidden() {
continue
}
@@ -1981,13 +1885,11 @@ func genasmsym(put func(*LSym, string, int, int64, int64, int, *LSym)) {
obj.STYPE,
obj.SSTRING,
obj.SGOSTRING,
- obj.SGOSTRINGHDR,
obj.SGOFUNC,
obj.SGCBITS,
obj.STYPERELRO,
obj.SSTRINGRELRO,
obj.SGOSTRINGRELRO,
- obj.SGOSTRINGHDRRELRO,
obj.SGOFUNCRELRO,
obj.SGCBITSRELRO,
obj.SRODATARELRO,
@@ -1997,48 +1899,48 @@ func genasmsym(put func(*LSym, string, int, int64, int64, int, *LSym)) {
if !s.Attr.Reachable() {
continue
}
- put(s, s.Name, 'D', Symaddr(s), s.Size, int(s.Version), s.Gotype)
+ put(ctxt, s, s.Name, DataSym, Symaddr(s), s.Gotype)
case obj.SBSS, obj.SNOPTRBSS:
if !s.Attr.Reachable() {
continue
}
if len(s.P) > 0 {
- Diag("%s should not be bss (size=%d type=%d special=%v)", s.Name, len(s.P), s.Type, s.Attr.Special())
+ Errorf(s, "should not be bss (size=%d type=%d special=%v)", len(s.P), s.Type, s.Attr.Special())
}
- put(s, s.Name, 'B', Symaddr(s), s.Size, int(s.Version), s.Gotype)
+ put(ctxt, s, s.Name, BSSSym, Symaddr(s), s.Gotype)
case obj.SFILE:
- put(nil, s.Name, 'f', s.Value, 0, int(s.Version), nil)
+ put(ctxt, nil, s.Name, FileSym, s.Value, nil)
case obj.SHOSTOBJ:
- if HEADTYPE == obj.Hwindows || Iself {
- put(s, s.Name, 'U', s.Value, 0, int(s.Version), nil)
+ if Headtype == obj.Hwindows || Headtype == obj.Hwindowsgui || Iself {
+ put(ctxt, s, s.Name, UndefinedSym, s.Value, nil)
}
case obj.SDYNIMPORT:
if !s.Attr.Reachable() {
continue
}
- put(s, s.Extname, 'U', 0, 0, int(s.Version), nil)
+ put(ctxt, s, s.Extname, UndefinedSym, 0, nil)
case obj.STLSBSS:
- if Linkmode == LinkExternal && HEADTYPE != obj.Hopenbsd {
- put(s, s.Name, 't', Symaddr(s), s.Size, int(s.Version), s.Gotype)
+ if Linkmode == LinkExternal && Headtype != obj.Hopenbsd {
+ put(ctxt, s, s.Name, TLSSym, Symaddr(s), s.Gotype)
}
}
}
var off int32
- for _, s := range Ctxt.Textp {
- put(s, s.Name, 'T', s.Value, s.Size, int(s.Version), s.Gotype)
+ for _, s := range ctxt.Textp {
+ put(ctxt, s, s.Name, TextSym, s.Value, s.Gotype)
locals := int32(0)
if s.FuncInfo != nil {
locals = s.FuncInfo.Locals
}
// NOTE(ality): acid can't produce a stack trace without .frame symbols
- put(nil, ".frame", 'm', int64(locals)+int64(SysArch.PtrSize), 0, 0, nil)
+ put(ctxt, nil, ".frame", FrameSym, int64(locals)+int64(SysArch.PtrSize), nil)
if s.FuncInfo == nil {
continue
@@ -2059,135 +1961,116 @@ func genasmsym(put func(*LSym, string, int, int64, int64, int, *LSym)) {
// FP
if off >= 0 {
- put(nil, a.Asym.Name, 'p', int64(off), 0, 0, a.Gotype)
+ put(ctxt, nil, a.Asym.Name, ParamSym, int64(off), a.Gotype)
continue
}
// SP
if off <= int32(-SysArch.PtrSize) {
- put(nil, a.Asym.Name, 'a', -(int64(off) + int64(SysArch.PtrSize)), 0, 0, a.Gotype)
+ put(ctxt, nil, a.Asym.Name, AutoSym, -(int64(off) + int64(SysArch.PtrSize)), a.Gotype)
continue
}
+ // Otherwise, off is addressing the saved program counter.
+ // Something underhanded is going on. Say nothing.
}
}
- // Otherwise, off is addressing the saved program counter.
- // Something underhanded is going on. Say nothing.
- if Debug['v'] != 0 || Debug['n'] != 0 {
- fmt.Fprintf(Bso, "%5.2f symsize = %d\n", obj.Cputime(), uint32(Symsize))
+ if ctxt.Debugvlog != 0 || *flagN {
+ ctxt.Logf("%5.2f symsize = %d\n", obj.Cputime(), uint32(Symsize))
}
- Bso.Flush()
}
-func Symaddr(s *LSym) int64 {
+func Symaddr(s *Symbol) int64 {
if !s.Attr.Reachable() {
- Diag("unreachable symbol in symaddr - %s", s.Name)
+ Errorf(s, "unreachable symbol in symaddr")
}
return s.Value
}
-func xdefine(p string, t int, v int64) {
- s := Linklookup(Ctxt, p, 0)
- s.Type = int16(t)
+func (ctxt *Link) xdefine(p string, t obj.SymKind, v int64) {
+ s := ctxt.Syms.Lookup(p, 0)
+ s.Type = t
s.Value = v
s.Attr |= AttrReachable
s.Attr |= AttrSpecial
s.Attr |= AttrLocal
}
-func datoff(addr int64) int64 {
+func datoff(s *Symbol, addr int64) int64 {
if uint64(addr) >= Segdata.Vaddr {
return int64(uint64(addr) - Segdata.Vaddr + Segdata.Fileoff)
}
if uint64(addr) >= Segtext.Vaddr {
return int64(uint64(addr) - Segtext.Vaddr + Segtext.Fileoff)
}
- Diag("datoff %#x", addr)
+ Errorf(s, "invalid datoff %#x", addr)
return 0
}
-func Entryvalue() int64 {
- a := INITENTRY
+func Entryvalue(ctxt *Link) int64 {
+ a := *flagEntrySymbol
if a[0] >= '0' && a[0] <= '9' {
return atolwhex(a)
}
- s := Linklookup(Ctxt, a, 0)
+ s := ctxt.Syms.Lookup(a, 0)
if s.Type == 0 {
- return INITTEXT
+ return *FlagTextAddr
}
if s.Type != obj.STEXT {
- Diag("entry not text: %s", s.Name)
+ Errorf(s, "entry not text")
}
return s.Value
}
-func undefsym(s *LSym) {
+func undefsym(ctxt *Link, s *Symbol) {
var r *Reloc
- Ctxt.Cursym = s
for i := 0; i < len(s.R); i++ {
r = &s.R[i]
if r.Sym == nil { // happens for some external ARM relocs
continue
}
if r.Sym.Type == obj.Sxxx || r.Sym.Type == obj.SXREF {
- Diag("undefined: %s", r.Sym.Name)
+ Errorf(s, "undefined: %q", r.Sym.Name)
}
- if !r.Sym.Attr.Reachable() {
- Diag("use of unreachable symbol: %s", r.Sym.Name)
+ if !r.Sym.Attr.Reachable() && r.Type != obj.R_WEAKADDROFF {
+ Errorf(s, "relocation target %q", r.Sym.Name)
}
}
}
-func undef() {
- for _, s := range Ctxt.Textp {
- undefsym(s)
+func (ctxt *Link) undef() {
+ for _, s := range ctxt.Textp {
+ undefsym(ctxt, s)
}
for _, s := range datap {
- undefsym(s)
+ undefsym(ctxt, s)
}
if nerrors > 0 {
errorexit()
}
}
-func callgraph() {
- if Debug['c'] == 0 {
+func (ctxt *Link) callgraph() {
+ if !*FlagC {
return
}
var i int
var r *Reloc
- for _, s := range Ctxt.Textp {
+ for _, s := range ctxt.Textp {
for i = 0; i < len(s.R); i++ {
r = &s.R[i]
if r.Sym == nil {
continue
}
if (r.Type == obj.R_CALL || r.Type == obj.R_CALLARM || r.Type == obj.R_CALLPOWER || r.Type == obj.R_CALLMIPS) && r.Sym.Type == obj.STEXT {
- fmt.Fprintf(Bso, "%s calls %s\n", s.Name, r.Sym.Name)
+ ctxt.Logf("%s calls %s\n", s.Name, r.Sym.Name)
}
}
}
}
-func Diag(format string, args ...interface{}) {
- tn := ""
- sep := ""
- if Ctxt.Cursym != nil {
- tn = Ctxt.Cursym.Name
- sep = ": "
- }
- fmt.Printf("%s%s%s\n", tn, sep, fmt.Sprintf(format, args...))
- nerrors++
- if Debug['h'] != 0 {
- panic("error")
- }
- if nerrors > 20 {
- Exitf("too many errors")
- }
-}
-
func Rnd(v int64, r int64) int64 {
if r <= 0 {
return v
@@ -2211,3 +2094,34 @@ func bgetc(r *bio.Reader) int {
}
return int(c)
}
+
+type markKind uint8 // for postorder traversal
+const (
+ unvisited markKind = iota
+ visiting
+ visited
+)
+
+func postorder(libs []*Library) []*Library {
+ order := make([]*Library, 0, len(libs)) // hold the result
+ mark := make(map[*Library]markKind, len(libs))
+ for _, lib := range libs {
+ dfs(lib, mark, &order)
+ }
+ return order
+}
+
+func dfs(lib *Library, mark map[*Library]markKind, order *[]*Library) {
+ if mark[lib] == visited {
+ return
+ }
+ if mark[lib] == visiting {
+ panic("found import cycle while visiting " + lib.Pkg)
+ }
+ mark[lib] = visiting
+ for _, i := range lib.imports {
+ dfs(i, mark, order)
+ }
+ mark[lib] = visited
+ *order = append(*order, lib)
+}
diff --git a/src/cmd/link/internal/ld/link.go b/src/cmd/link/internal/ld/link.go
index 9bab68b..ab7e49b 100644
--- a/src/cmd/link/internal/ld/link.go
+++ b/src/cmd/link/internal/ld/link.go
@@ -1,5 +1,5 @@
// Derived from Inferno utils/6l/l.h and related files.
-// http://code.google.com/p/inferno-os/source/browse/utils/6l/l.h
+// 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)
@@ -32,15 +32,17 @@ package ld
import (
"bufio"
+ "cmd/internal/obj"
"cmd/internal/sys"
"debug/elf"
"fmt"
)
-type LSym struct {
+// Symbol is an entry in the symbol table.
+type Symbol struct {
Name string
Extname string
- Type int16
+ Type obj.SymKind
Version int16
Attr Attribute
Localentry uint8
@@ -56,28 +58,28 @@ type LSym struct {
// is not set for symbols defined by the packages being linked or by symbols
// read by ldelf (and so is left as elf.STT_NOTYPE).
ElfType elf.SymType
- Next *LSym
- Sub *LSym
- Outer *LSym
- Gotype *LSym
- Reachparent *LSym
+ Sub *Symbol
+ Outer *Symbol
+ Gotype *Symbol
+ Reachparent *Symbol
File string
Dynimplib string
Dynimpvers string
Sect *Section
FuncInfo *FuncInfo
- P []byte
- R []Reloc
+ // P contains the raw symbol data.
+ P []byte
+ R []Reloc
}
-func (s *LSym) String() string {
+func (s *Symbol) String() string {
if s.Version == 0 {
return s.Name
}
return fmt.Sprintf("%s<%d>", s.Name, s.Version)
}
-func (s *LSym) ElfsymForReloc() int32 {
+func (s *Symbol) ElfsymForReloc() int32 {
// If putelfsym created a local version of this symbol, use that in all
// relocations.
if s.LocalElfsym != 0 {
@@ -103,6 +105,7 @@ const (
AttrOnList
AttrLocal
AttrReflectMethod
+ AttrMakeTypelink
)
func (a Attribute) DuplicateOK() bool { return a&AttrDuplicateOK != 0 }
@@ -117,6 +120,7 @@ func (a Attribute) Hidden() bool { return a&AttrHidden != 0 }
func (a Attribute) OnList() bool { return a&AttrOnList != 0 }
func (a Attribute) Local() bool { return a&AttrLocal != 0 }
func (a Attribute) ReflectMethod() bool { return a&AttrReflectMethod != 0 }
+func (a Attribute) MakeTypelink() bool { return a&AttrMakeTypelink != 0 }
func (a Attribute) CgoExport() bool {
return a.CgoExportDynamic() || a.CgoExportStatic()
@@ -130,58 +134,65 @@ func (a *Attribute) Set(flag Attribute, value bool) {
}
}
+// Reloc is a relocation.
+//
+// The typical Reloc rewrites part of a symbol at offset Off to address Sym.
+// A Reloc is stored in a slice on the Symbol it rewrites.
+//
+// Relocations are generated by the compiler as the type
+// cmd/internal/obj.Reloc, which is encoded into the object file wire
+// format and decoded by the linker into this type. A separate type is
+// used to hold linker-specific state about the relocation.
+//
+// Some relocations are created by cmd/link.
type Reloc struct {
- Off int32
- Siz uint8
- Done uint8
- Type int32
- Variant int32
- Add int64
- Xadd int64
- Sym *LSym
- Xsym *LSym
+ 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
}
type Auto struct {
- Asym *LSym
- Gotype *LSym
+ Asym *Symbol
+ Gotype *Symbol
Aoffset int32
Name int16
}
type Shlib struct {
- Path string
- Hash []byte
- Deps []string
- File *elf.File
- gcdata_addresses map[*LSym]uint64
+ Path string
+ Hash []byte
+ Deps []string
+ File *elf.File
+ gcdataAddresses map[*Symbol]uint64
}
+// Link holds the context for writing object code from a compiler
+// or for reading that input into the linker.
type Link struct {
- Goarm int32
- Headtype int
+ Syms *Symbols
+
Arch *sys.Arch
- Debugvlog int32
+ Debugvlog int
Bso *bufio.Writer
- Windows int32
- Goroot string
- // Symbol lookup based on name and indexed by version.
- Hash []map[string]*LSym
+ Loaded bool // set after all inputs have been loaded as symbols
- Allsym []*LSym
- Tlsg *LSym
+ Tlsg *Symbol
Libdir []string
Library []*Library
Shlibs []Shlib
Tlsoffset int
- Diag func(string, ...interface{})
- Cursym *LSym
- Version int
- Textp []*LSym
- Filesyms []*LSym
- Moduledata *LSym
- LSymBatch []LSym
+ Textp []*Symbol
+ Filesyms []*Symbol
+ Moduledata *Symbol
+
+ tramps []*Symbol // trampolines
}
// The smallest possible offset from the hardware stack pointer to a local
@@ -201,18 +212,25 @@ func (ctxt *Link) FixedFrameSize() int64 {
}
}
-func (l *Link) IncVersion() {
- l.Version++
- l.Hash = append(l.Hash, make(map[string]*LSym))
+func (l *Link) Logf(format string, args ...interface{}) {
+ fmt.Fprintf(l.Bso, format, args...)
+ l.Bso.Flush()
}
type Library struct {
- Objref string
- Srcref string
- File string
- Pkg string
- Shlib string
- hash []byte
+ Objref string
+ Srcref string
+ File string
+ Pkg string
+ Shlib string
+ hash []byte
+ imports []*Library
+ textp []*Symbol // text symbols defined in this library
+ dupTextSyms []*Symbol // dupok text symbols defined in this library
+}
+
+func (l Library) String() string {
+ return l.Pkg
}
type FuncInfo struct {
@@ -223,9 +241,9 @@ type FuncInfo struct {
Pcfile Pcdata
Pcline Pcdata
Pcdata []Pcdata
- Funcdata []*LSym
+ Funcdata []*Symbol
Funcdataoff []int64
- File []*LSym
+ File []*Symbol
}
type Pcdata struct {
@@ -243,9 +261,11 @@ type Pciter struct {
done int
}
-// Reloc.variant
+// RelocVariant is a linker-internal variation on a relocation.
+type RelocVariant uint8
+
const (
- RV_NONE = iota
+ RV_NONE RelocVariant = iota
RV_POWER_LO
RV_POWER_HI
RV_POWER_HA
@@ -256,20 +276,6 @@ const (
// divided by 2.
RV_390_DBL
- RV_CHECK_OVERFLOW = 1 << 8
- RV_TYPE_MASK = RV_CHECK_OVERFLOW - 1
-)
-
-// Pcdata iterator.
-// for(pciterinit(ctxt, &it, &pcd); !it.done; pciternext(&it)) { it.value holds in [it.pc, it.nextpc) }
-
-// Link holds the context for writing object code from a compiler
-// to be linker input or for reading that input into the linker.
-
-// LinkArch is the definition of a single architecture.
-
-const (
- LinkAuto = 0 + iota
- LinkInternal
- LinkExternal
+ RV_CHECK_OVERFLOW RelocVariant = 1 << 7
+ RV_TYPE_MASK RelocVariant = RV_CHECK_OVERFLOW - 1
)
diff --git a/src/cmd/link/internal/ld/macho.go b/src/cmd/link/internal/ld/macho.go
index 53cc962..c88af64 100644
--- a/src/cmd/link/internal/ld/macho.go
+++ b/src/cmd/link/internal/ld/macho.go
@@ -121,7 +121,7 @@ const (
var nkind [NumSymKind]int
-var sortsym []*LSym
+var sortsym []*Symbol
var nsortsym int
@@ -131,7 +131,7 @@ var nsortsym int
// "big enough" header size. The initial header is
// one page, the non-dynamic library stuff takes
// up about 1300 bytes; we overestimate that as 2k.
-var load_budget int = INITIAL_MACHO_HEADR - 2*1024
+var loadBudget int = INITIAL_MACHO_HEADR - 2*1024
func Machoinit() {
macho64 = SysArch.RegSize == 8
@@ -186,7 +186,7 @@ var dylib []string
var linkoff int64
func machowrite() int {
- o1 := Cpos()
+ o1 := coutbuf.Offset()
loadsize := 4 * 4 * ndebug
for i := 0; i < len(load); i++ {
@@ -291,41 +291,41 @@ func machowrite() int {
}
}
- return int(Cpos() - o1)
+ return int(coutbuf.Offset() - o1)
}
-func domacho() {
- if Debug['d'] != 0 {
+func (ctxt *Link) domacho() {
+ if *FlagD {
return
}
// empirically, string table must begin with " \x00".
- s := Linklookup(Ctxt, ".machosymstr", 0)
+ s := ctxt.Syms.Lookup(".machosymstr", 0)
s.Type = obj.SMACHOSYMSTR
s.Attr |= AttrReachable
- Adduint8(Ctxt, s, ' ')
- Adduint8(Ctxt, s, '\x00')
+ Adduint8(ctxt, s, ' ')
+ Adduint8(ctxt, s, '\x00')
- s = Linklookup(Ctxt, ".machosymtab", 0)
+ s = ctxt.Syms.Lookup(".machosymtab", 0)
s.Type = obj.SMACHOSYMTAB
s.Attr |= AttrReachable
if Linkmode != LinkExternal {
- s := Linklookup(Ctxt, ".plt", 0) // will be __symbol_stub
+ s := ctxt.Syms.Lookup(".plt", 0) // will be __symbol_stub
s.Type = obj.SMACHOPLT
s.Attr |= AttrReachable
- s = Linklookup(Ctxt, ".got", 0) // will be __nl_symbol_ptr
+ s = ctxt.Syms.Lookup(".got", 0) // will be __nl_symbol_ptr
s.Type = obj.SMACHOGOT
s.Attr |= AttrReachable
s.Align = 4
- s = Linklookup(Ctxt, ".linkedit.plt", 0) // indirect table for .plt
+ s = ctxt.Syms.Lookup(".linkedit.plt", 0) // indirect table for .plt
s.Type = obj.SMACHOINDIRECTPLT
s.Attr |= AttrReachable
- s = Linklookup(Ctxt, ".linkedit.got", 0) // indirect table for .got
+ s = ctxt.Syms.Lookup(".linkedit.got", 0) // indirect table for .got
s.Type = obj.SMACHOINDIRECTGOT
s.Attr |= AttrReachable
}
@@ -336,24 +336,24 @@ func Machoadddynlib(lib string) {
// and 24 bytes of header metadata. If not enough
// space, grab another page of initial space at the
// beginning of the output file.
- load_budget -= (len(lib)+7)/8*8 + 24
+ loadBudget -= (len(lib)+7)/8*8 + 24
- if load_budget < 0 {
+ if loadBudget < 0 {
HEADR += 4096
- INITTEXT += 4096
- load_budget += 4096
+ *FlagTextAddr += 4096
+ loadBudget += 4096
}
dylib = append(dylib, lib)
}
-func machoshbits(mseg *MachoSeg, sect *Section, segname string) {
+func machoshbits(ctxt *Link, mseg *MachoSeg, sect *Section, segname string) {
buf := "__" + strings.Replace(sect.Name[1:], ".", "_", -1)
var msect *MachoSect
if sect.Rwx&1 == 0 && segname != "__DWARF" && (SysArch.Family == sys.ARM64 ||
- (SysArch.Family == sys.AMD64 && (Buildmode == BuildmodeCShared || Buildmode == BuildmodeCArchive)) ||
- (SysArch.Family == sys.ARM && (Buildmode == BuildmodeCShared || Buildmode == BuildmodeCArchive))) {
+ (SysArch.Family == sys.AMD64 && (Buildmode == BuildmodeCShared || Buildmode == BuildmodeCArchive || Buildmode == BuildmodePlugin)) ||
+ (SysArch.Family == sys.ARM && (Buildmode == BuildmodeCShared || Buildmode == BuildmodeCArchive || Buildmode == BuildmodePlugin))) {
// Darwin external linker on arm64 and on amd64 and arm in c-shared/c-archive buildmode
// complains about absolute relocs in __TEXT, so if the section is not
// executable, put it in __DATA segment.
@@ -376,7 +376,7 @@ func machoshbits(mseg *MachoSeg, sect *Section, segname string) {
if sect.Vaddr < sect.Seg.Vaddr+sect.Seg.Filelen {
// data in file
if sect.Length > sect.Seg.Vaddr+sect.Seg.Filelen-sect.Vaddr {
- Diag("macho cannot represent section %s crossing data and bss", sect.Name)
+ Errorf(nil, "macho cannot represent section %s crossing data and bss", sect.Name)
}
msect.off = uint32(sect.Seg.Fileoff + sect.Vaddr - sect.Seg.Vaddr)
} else {
@@ -400,7 +400,7 @@ func machoshbits(mseg *MachoSeg, sect *Section, segname string) {
if sect.Name == ".got" {
msect.name = "__nl_symbol_ptr"
msect.flag = 6 /* section with nonlazy symbol pointers */
- msect.res1 = uint32(Linklookup(Ctxt, ".linkedit.plt", 0).Size / 4) /* offset into indirect symbol table */
+ msect.res1 = uint32(ctxt.Syms.Lookup(".linkedit.plt", 0).Size / 4) /* offset into indirect symbol table */
}
if sect.Name == ".init_array" {
@@ -413,9 +413,9 @@ func machoshbits(mseg *MachoSeg, sect *Section, segname string) {
}
}
-func Asmbmacho() {
+func Asmbmacho(ctxt *Link) {
/* apple MACH */
- va := INITTEXT - int64(HEADR)
+ va := *FlagTextAddr - int64(HEADR)
mh := getMachoHdr()
switch SysArch.Family {
@@ -460,7 +460,7 @@ func Asmbmacho() {
}
/* text */
- v := Rnd(int64(uint64(HEADR)+Segtext.Length), int64(INITRND))
+ v := Rnd(int64(uint64(HEADR)+Segtext.Length), int64(*FlagRound))
if Linkmode != LinkExternal {
ms = newMachoSeg("__TEXT", 20)
@@ -473,7 +473,7 @@ func Asmbmacho() {
}
for sect := Segtext.Sect; sect != nil; sect = sect.Next {
- machoshbits(ms, sect, "__TEXT")
+ machoshbits(ctxt, ms, sect, "__TEXT")
}
/* data */
@@ -489,11 +489,11 @@ func Asmbmacho() {
}
for sect := Segdata.Sect; sect != nil; sect = sect.Next {
- machoshbits(ms, sect, "__DATA")
+ machoshbits(ctxt, ms, sect, "__DATA")
}
/* dwarf */
- if Debug['w'] == 0 {
+ if !*FlagW {
if Linkmode != LinkExternal {
ms = newMachoSeg("__DWARF", 20)
ms.vaddr = Segdwarf.Vaddr
@@ -502,7 +502,7 @@ func Asmbmacho() {
ms.filesize = Segdwarf.Filelen
}
for sect := Segdwarf.Sect; sect != nil; sect = sect.Next {
- machoshbits(ms, sect, "__DWARF")
+ machoshbits(ctxt, ms, sect, "__DWARF")
}
}
@@ -512,43 +512,43 @@ func Asmbmacho() {
Exitf("unknown macho architecture: %v", SysArch.Family)
case sys.ARM:
- ml := newMachoLoad(5, 17+2) /* unix thread */
- ml.data[0] = 1 /* thread type */
- ml.data[1] = 17 /* word count */
- ml.data[2+15] = uint32(Entryvalue()) /* start pc */
+ ml := newMachoLoad(5, 17+2) /* unix thread */
+ ml.data[0] = 1 /* thread type */
+ ml.data[1] = 17 /* word count */
+ ml.data[2+15] = uint32(Entryvalue(ctxt)) /* start pc */
case sys.AMD64:
- ml := newMachoLoad(5, 42+2) /* unix thread */
- ml.data[0] = 4 /* thread type */
- ml.data[1] = 42 /* word count */
- ml.data[2+32] = uint32(Entryvalue()) /* start pc */
- ml.data[2+32+1] = uint32(Entryvalue() >> 32)
+ ml := newMachoLoad(5, 42+2) /* unix thread */
+ ml.data[0] = 4 /* thread type */
+ ml.data[1] = 42 /* word count */
+ ml.data[2+32] = uint32(Entryvalue(ctxt)) /* start pc */
+ ml.data[2+32+1] = uint32(Entryvalue(ctxt) >> 32)
case sys.ARM64:
- ml := newMachoLoad(5, 68+2) /* unix thread */
- ml.data[0] = 6 /* thread type */
- ml.data[1] = 68 /* word count */
- ml.data[2+64] = uint32(Entryvalue()) /* start pc */
- ml.data[2+64+1] = uint32(Entryvalue() >> 32)
+ ml := newMachoLoad(5, 68+2) /* unix thread */
+ ml.data[0] = 6 /* thread type */
+ ml.data[1] = 68 /* word count */
+ ml.data[2+64] = uint32(Entryvalue(ctxt)) /* start pc */
+ ml.data[2+64+1] = uint32(Entryvalue(ctxt) >> 32)
case sys.I386:
- ml := newMachoLoad(5, 16+2) /* unix thread */
- ml.data[0] = 1 /* thread type */
- ml.data[1] = 16 /* word count */
- ml.data[2+10] = uint32(Entryvalue()) /* start pc */
+ ml := newMachoLoad(5, 16+2) /* unix thread */
+ ml.data[0] = 1 /* thread type */
+ ml.data[1] = 16 /* word count */
+ ml.data[2+10] = uint32(Entryvalue(ctxt)) /* start pc */
}
}
- if Debug['d'] == 0 {
+ if !*FlagD {
// must match domacholink below
- s1 := Linklookup(Ctxt, ".machosymtab", 0)
- s2 := Linklookup(Ctxt, ".linkedit.plt", 0)
- s3 := Linklookup(Ctxt, ".linkedit.got", 0)
- s4 := Linklookup(Ctxt, ".machosymstr", 0)
+ s1 := ctxt.Syms.Lookup(".machosymtab", 0)
+ s2 := ctxt.Syms.Lookup(".linkedit.plt", 0)
+ s3 := ctxt.Syms.Lookup(".linkedit.got", 0)
+ s4 := ctxt.Syms.Lookup(".machosymstr", 0)
if Linkmode != LinkExternal {
ms := newMachoSeg("__LINKEDIT", 0)
- ms.vaddr = uint64(va) + uint64(v) + uint64(Rnd(int64(Segdata.Length), int64(INITRND)))
+ ms.vaddr = uint64(va) + uint64(v) + uint64(Rnd(int64(Segdata.Length), int64(*FlagRound)))
ms.vsize = uint64(s1.Size) + uint64(s2.Size) + uint64(s3.Size) + uint64(s4.Size)
ms.fileoffset = uint64(linkoff)
ms.filesize = ms.vsize
@@ -562,7 +562,7 @@ func Asmbmacho() {
ml.data[2] = uint32(linkoff + s1.Size + s2.Size + s3.Size) /* stroff */
ml.data[3] = uint32(s4.Size) /* strsize */
- machodysymtab()
+ machodysymtab(ctxt)
if Linkmode != LinkExternal {
ml := newMachoLoad(14, 6) /* LC_LOAD_DYLINKER */
@@ -602,7 +602,7 @@ func Asmbmacho() {
}
}
-func symkind(s *LSym) int {
+func symkind(s *Symbol) int {
if s.Type == obj.SDYNIMPORT {
return SymKindUndef
}
@@ -612,7 +612,7 @@ func symkind(s *LSym) int {
return SymKindLocal
}
-func addsym(s *LSym, name string, type_ int, addr int64, size int64, ver int, gotype *LSym) {
+func addsym(ctxt *Link, s *Symbol, name string, type_ SymbolType, addr int64, gotype *Symbol) {
if s == nil {
return
}
@@ -621,7 +621,7 @@ func addsym(s *LSym, name string, type_ int, addr int64, size int64, ver int, go
default:
return
- case 'D', 'B', 'T':
+ case DataSym, BSSSym, TextSym:
break
}
@@ -633,7 +633,7 @@ func addsym(s *LSym, name string, type_ int, addr int64, size int64, ver int, go
nsortsym++
}
-type machoscmp []*LSym
+type machoscmp []*Symbol
func (x machoscmp) Len() int {
return len(x)
@@ -656,78 +656,83 @@ func (x machoscmp) Less(i, j int) bool {
return s1.Extname < s2.Extname
}
-func machogenasmsym(put func(*LSym, string, int, int64, int64, int, *LSym)) {
- genasmsym(put)
- for _, s := range Ctxt.Allsym {
+func machogenasmsym(ctxt *Link) {
+ genasmsym(ctxt, addsym)
+ for _, s := range ctxt.Syms.Allsym {
if s.Type == obj.SDYNIMPORT || s.Type == obj.SHOSTOBJ {
if s.Attr.Reachable() {
- put(s, "", 'D', 0, 0, 0, nil)
+ addsym(ctxt, s, "", DataSym, 0, nil)
}
}
}
}
-func machosymorder() {
+func machosymorder(ctxt *Link) {
// On Mac OS X Mountain Lion, we must sort exported symbols
// So we sort them here and pre-allocate dynid for them
// See https://golang.org/issue/4029
for i := 0; i < len(dynexp); i++ {
dynexp[i].Attr |= AttrReachable
}
- machogenasmsym(addsym)
- sortsym = make([]*LSym, nsortsym)
+ machogenasmsym(ctxt)
+ sortsym = make([]*Symbol, nsortsym)
nsortsym = 0
- machogenasmsym(addsym)
+ machogenasmsym(ctxt)
sort.Sort(machoscmp(sortsym[:nsortsym]))
for i := 0; i < nsortsym; i++ {
sortsym[i].Dynid = int32(i)
}
}
-func machosymtab() {
- symtab := Linklookup(Ctxt, ".machosymtab", 0)
- symstr := Linklookup(Ctxt, ".machosymstr", 0)
+func machosymtab(ctxt *Link) {
+ symtab := ctxt.Syms.Lookup(".machosymtab", 0)
+ symstr := ctxt.Syms.Lookup(".machosymstr", 0)
for i := 0; i < nsortsym; i++ {
s := sortsym[i]
- Adduint32(Ctxt, symtab, uint32(symstr.Size))
+ Adduint32(ctxt, symtab, uint32(symstr.Size))
- // Only add _ to C symbols. Go symbols have dot in the name.
- if !strings.Contains(s.Extname, ".") {
- Adduint8(Ctxt, symstr, '_')
+ // In normal buildmodes, only add _ to C symbols, as
+ // Go symbols have dot in the name.
+ //
+ // When dynamically linking, prefix all non-local
+ // symbols with _ as dlsym on darwin requires it to
+ // resolve any symbol.
+ if !strings.Contains(s.Extname, ".") || (ctxt.DynlinkingGo() && !s.Attr.Local()) {
+ Adduint8(ctxt, symstr, '_')
}
// replace "·" as ".", because DTrace cannot handle it.
Addstring(symstr, strings.Replace(s.Extname, "·", ".", -1))
if s.Type == obj.SDYNIMPORT || s.Type == obj.SHOSTOBJ {
- Adduint8(Ctxt, symtab, 0x01) // type N_EXT, external symbol
- Adduint8(Ctxt, symtab, 0) // no section
- Adduint16(Ctxt, symtab, 0) // desc
- adduintxx(Ctxt, symtab, 0, SysArch.PtrSize) // no value
+ Adduint8(ctxt, symtab, 0x01) // type N_EXT, external symbol
+ Adduint8(ctxt, symtab, 0) // no section
+ Adduint16(ctxt, symtab, 0) // desc
+ adduintxx(ctxt, symtab, 0, SysArch.PtrSize) // no value
} else {
- if s.Attr.CgoExport() {
- Adduint8(Ctxt, symtab, 0x0f)
+ if s.Attr.CgoExport() || (ctxt.DynlinkingGo() && !s.Attr.Local()) {
+ Adduint8(ctxt, symtab, 0x0f)
} else {
- Adduint8(Ctxt, symtab, 0x0e)
+ Adduint8(ctxt, symtab, 0x0e)
}
o := s
for o.Outer != nil {
o = o.Outer
}
if o.Sect == nil {
- Diag("missing section for %s", s.Name)
- Adduint8(Ctxt, symtab, 0)
+ Errorf(s, "missing section for symbol")
+ Adduint8(ctxt, symtab, 0)
} else {
- Adduint8(Ctxt, symtab, uint8(o.Sect.Extnum))
+ Adduint8(ctxt, symtab, uint8(o.Sect.Extnum))
}
- Adduint16(Ctxt, symtab, 0) // desc
- adduintxx(Ctxt, symtab, uint64(Symaddr(s)), SysArch.PtrSize)
+ Adduint16(ctxt, symtab, 0) // desc
+ adduintxx(ctxt, symtab, uint64(Symaddr(s)), SysArch.PtrSize)
}
}
}
-func machodysymtab() {
+func machodysymtab(ctxt *Link) {
ml := newMachoLoad(11, 18) /* LC_DYSYMTAB */
n := 0
@@ -750,10 +755,10 @@ func machodysymtab() {
ml.data[11] = 0 /* nextrefsyms */
// must match domacholink below
- s1 := Linklookup(Ctxt, ".machosymtab", 0)
+ s1 := ctxt.Syms.Lookup(".machosymtab", 0)
- s2 := Linklookup(Ctxt, ".linkedit.plt", 0)
- s3 := Linklookup(Ctxt, ".linkedit.got", 0)
+ s2 := ctxt.Syms.Lookup(".linkedit.plt", 0)
+ s3 := ctxt.Syms.Lookup(".linkedit.got", 0)
ml.data[12] = uint32(linkoff + s1.Size) /* indirectsymoff */
ml.data[13] = uint32((s2.Size + s3.Size) / 4) /* nindirectsyms */
@@ -763,15 +768,15 @@ func machodysymtab() {
ml.data[17] = 0 /* nlocrel */
}
-func Domacholink() int64 {
- machosymtab()
+func Domacholink(ctxt *Link) int64 {
+ machosymtab(ctxt)
// write data that will be linkedit section
- s1 := Linklookup(Ctxt, ".machosymtab", 0)
+ s1 := ctxt.Syms.Lookup(".machosymtab", 0)
- s2 := Linklookup(Ctxt, ".linkedit.plt", 0)
- s3 := Linklookup(Ctxt, ".linkedit.got", 0)
- s4 := Linklookup(Ctxt, ".machosymstr", 0)
+ s2 := ctxt.Syms.Lookup(".linkedit.plt", 0)
+ s3 := ctxt.Syms.Lookup(".linkedit.got", 0)
+ s4 := ctxt.Syms.Lookup(".machosymstr", 0)
// Force the linkedit section to end on a 16-byte
// boundary. This allows pure (non-cgo) Go binaries
@@ -791,13 +796,13 @@ func Domacholink() int64 {
// any alignment padding itself, working around the
// issue.
for s4.Size%16 != 0 {
- Adduint8(Ctxt, s4, 0)
+ Adduint8(ctxt, s4, 0)
}
size := int(s1.Size + s2.Size + s3.Size + s4.Size)
if size > 0 {
- linkoff = Rnd(int64(uint64(HEADR)+Segtext.Length), int64(INITRND)) + Rnd(int64(Segdata.Filelen), int64(INITRND)) + Rnd(int64(Segdwarf.Filelen), int64(INITRND))
+ linkoff = Rnd(int64(uint64(HEADR)+Segtext.Length), int64(*FlagRound)) + Rnd(int64(Segdata.Filelen), int64(*FlagRound)) + Rnd(int64(Segdwarf.Filelen), int64(*FlagRound))
Cseek(linkoff)
Cwrite(s1.P[:s1.Size])
@@ -806,16 +811,16 @@ func Domacholink() int64 {
Cwrite(s4.P[:s4.Size])
}
- return Rnd(int64(size), int64(INITRND))
+ return Rnd(int64(size), int64(*FlagRound))
}
-func machorelocsect(sect *Section, syms []*LSym) {
+func machorelocsect(ctxt *Link, sect *Section, syms []*Symbol) {
// If main section has no bits, nothing to relocate.
if sect.Vaddr >= sect.Seg.Vaddr+sect.Seg.Filelen {
return
}
- sect.Reloff = uint64(Cpos())
+ sect.Reloff = uint64(coutbuf.Offset())
for i, s := range syms {
if !s.Attr.Reachable() {
continue
@@ -834,35 +839,40 @@ func machorelocsect(sect *Section, syms []*LSym) {
if sym.Value >= int64(eaddr) {
break
}
- Ctxt.Cursym = sym
-
for ri := 0; ri < len(sym.R); ri++ {
r := &sym.R[ri]
if r.Done != 0 {
continue
}
- if Thearch.Machoreloc1(r, int64(uint64(sym.Value+int64(r.Off))-sect.Vaddr)) < 0 {
- Diag("unsupported obj reloc %d/%d to %s", r.Type, r.Siz, r.Sym.Name)
+ if r.Xsym == nil {
+ Errorf(sym, "missing xsym in relocation")
+ continue
+ }
+ if !r.Xsym.Attr.Reachable() {
+ Errorf(sym, "unreachable reloc %v target %v", r.Type, r.Xsym.Name)
+ }
+ if Thearch.Machoreloc1(sym, r, int64(uint64(sym.Value+int64(r.Off))-sect.Vaddr)) < 0 {
+ Errorf(sym, "unsupported obj reloc %v/%d to %s", r.Type, r.Siz, r.Sym.Name)
}
}
}
- sect.Rellen = uint64(Cpos()) - sect.Reloff
+ sect.Rellen = uint64(coutbuf.Offset()) - sect.Reloff
}
-func Machoemitreloc() {
- for Cpos()&7 != 0 {
+func Machoemitreloc(ctxt *Link) {
+ for coutbuf.Offset()&7 != 0 {
Cput(0)
}
- machorelocsect(Segtext.Sect, Ctxt.Textp)
+ machorelocsect(ctxt, Segtext.Sect, ctxt.Textp)
for sect := Segtext.Sect.Next; sect != nil; sect = sect.Next {
- machorelocsect(sect, datap)
+ machorelocsect(ctxt, sect, datap)
}
for sect := Segdata.Sect; sect != nil; sect = sect.Next {
- machorelocsect(sect, datap)
+ machorelocsect(ctxt, sect, datap)
}
for sect := Segdwarf.Sect; sect != nil; sect = sect.Next {
- machorelocsect(sect, list2slice(dwarfp))
+ machorelocsect(ctxt, sect, dwarfp)
}
}
diff --git a/src/cmd/link/internal/ld/main.go b/src/cmd/link/internal/ld/main.go
new file mode 100644
index 0000000..2fd92f6
--- /dev/null
+++ b/src/cmd/link/internal/ld/main.go
@@ -0,0 +1,264 @@
+// Inferno utils/6l/obj.c
+// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/obj.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth at terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth at terzarima.net)
+// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+// Portions Copyright © 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+package ld
+
+import (
+ "bufio"
+ "cmd/internal/obj"
+ "cmd/internal/sys"
+ "flag"
+ "log"
+ "os"
+ "runtime"
+ "runtime/pprof"
+ "strings"
+)
+
+var (
+ pkglistfornote []byte
+)
+
+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:...")
+}
+
+// Flags used by the linker. The exported flags are used by the architecture-specific packages.
+var (
+ flagBuildid = flag.String("buildid", "", "record `id` as Go toolchain build id")
+
+ flagOutfile = flag.String("o", "", "write output to `file`")
+ flagPluginPath = flag.String("pluginpath", "", "full path name for plugin")
+ FlagLinkshared = flag.Bool("linkshared", false, "link against installed Go shared libraries")
+
+ flagInstallSuffix = flag.String("installsuffix", "", "set package directory `suffix`")
+ flagDumpDep = flag.Bool("dumpdep", false, "dump symbol dependency graph")
+ flagRace = flag.Bool("race", false, "enable race detector")
+ flagMsan = flag.Bool("msan", false, "enable MSan interface")
+
+ flagFieldTrack = flag.String("k", "", "set field tracking `symbol`")
+ flagLibGCC = flag.String("libgcc", "", "compiler support lib for internal linking; use \"none\" to disable")
+ flagTmpdir = flag.String("tmpdir", "", "use `directory` for temporary files")
+
+ flagExtld = flag.String("extld", "", "use `linker` when linking in external mode")
+ flagExtldflags = flag.String("extldflags", "", "pass `flags` to external linker")
+ flagExtar = flag.String("extar", "", "archive program for buildmode=c-archive")
+
+ flagA = flag.Bool("a", false, "disassemble output")
+ FlagC = flag.Bool("c", false, "dump call graph")
+ FlagD = flag.Bool("d", false, "disable dynamic executable")
+ flagF = flag.Bool("f", false, "ignore version mismatch")
+ flagG = flag.Bool("g", false, "disable go package data checks")
+ flagH = flag.Bool("h", false, "halt on error")
+ flagN = flag.Bool("n", false, "dump symbol table")
+ FlagS = flag.Bool("s", false, "disable symbol table")
+ flagU = flag.Bool("u", false, "reject unsafe packages")
+ FlagW = flag.Bool("w", false, "disable DWARF generation")
+ Flag8 bool // use 64-bit addresses in symbol table
+ flagInterpreter = flag.String("I", "", "use `linker` as ELF dynamic linker")
+ FlagDebugTramp = flag.Int("debugtramp", 0, "debug trampolines")
+
+ 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`")
+ flagEntrySymbol = flag.String("E", "", "set `entry` symbol name")
+
+ cpuprofile = flag.String("cpuprofile", "", "write cpu profile to `file`")
+ memprofile = flag.String("memprofile", "", "write memory profile to `file`")
+ memprofilerate = flag.Int64("memprofilerate", 0, "set runtime.MemProfileRate to `rate`")
+)
+
+// Main is the main entry point for the linker code.
+func Main() {
+ ctxt := linknew(SysArch)
+ ctxt.Bso = bufio.NewWriter(os.Stdout)
+
+ // For testing behavior of go command when tools crash silently.
+ // Undocumented, not in standard flag parser to avoid
+ // exposing in usage message.
+ for _, arg := range os.Args {
+ if arg == "-crash_for_testing" {
+ os.Exit(2)
+ }
+ }
+
+ // TODO(matloob): define these above and then check flag values here
+ if SysArch.Family == sys.AMD64 && obj.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)
+
+ startProfile()
+ if Buildmode == BuildmodeUnset {
+ Buildmode = BuildmodeExe
+ }
+
+ if Buildmode != BuildmodeShared && flag.NArg() != 1 {
+ usage()
+ }
+
+ if *flagOutfile == "" {
+ *flagOutfile = "a.out"
+ if Headtype == obj.Hwindows || Headtype == obj.Hwindowsgui {
+ *flagOutfile += ".exe"
+ }
+ }
+
+ interpreter = *flagInterpreter
+
+ libinit(ctxt) // creates outfile
+
+ if Headtype == obj.Hunknown {
+ Headtype.Set(obj.GOOS)
+ }
+
+ ctxt.computeTLSOffset()
+ Thearch.Archinit(ctxt)
+
+ if *FlagLinkshared && !Iself {
+ Exitf("-linkshared can only be used on elf systems")
+ }
+
+ if ctxt.Debugvlog != 0 {
+ ctxt.Logf("HEADER = -H%d -T0x%x -D0x%x -R0x%x\n", Headtype, uint64(*FlagTextAddr), uint64(*FlagDataAddr), uint32(*FlagRound))
+ }
+
+ switch Buildmode {
+ case BuildmodeShared:
+ for i := 0; i < flag.NArg(); i++ {
+ arg := flag.Arg(i)
+ parts := strings.SplitN(arg, "=", 2)
+ var pkgpath, file string
+ if len(parts) == 1 {
+ pkgpath, file = "main", arg
+ } else {
+ pkgpath, file = parts[0], parts[1]
+ }
+ pkglistfornote = append(pkglistfornote, pkgpath...)
+ pkglistfornote = append(pkglistfornote, '\n')
+ addlibpath(ctxt, "command line", "command line", file, pkgpath, "")
+ }
+ case BuildmodePlugin:
+ addlibpath(ctxt, "command line", "command line", flag.Arg(0), *flagPluginPath, "")
+ default:
+ addlibpath(ctxt, "command line", "command line", flag.Arg(0), "main", "")
+ }
+ ctxt.loadlib()
+
+ ctxt.checkstrdata()
+ deadcode(ctxt)
+ fieldtrack(ctxt)
+ ctxt.callgraph()
+
+ ctxt.doelf()
+ if Headtype == obj.Hdarwin {
+ ctxt.domacho()
+ }
+ ctxt.dostkcheck()
+ if Headtype == obj.Hwindows || Headtype == obj.Hwindowsgui {
+ ctxt.dope()
+ }
+ ctxt.addexport()
+ Thearch.Gentext(ctxt) // trampolines, call stubs, etc.
+ ctxt.textbuildid()
+ ctxt.textaddress()
+ ctxt.pclntab()
+ ctxt.findfunctab()
+ ctxt.typelink()
+ ctxt.symtab()
+ ctxt.dodata()
+ ctxt.address()
+ ctxt.reloc()
+ Thearch.Asmb(ctxt)
+ ctxt.undef()
+ ctxt.hostlink()
+ ctxt.archive()
+ if ctxt.Debugvlog != 0 {
+ ctxt.Logf("%5.2f cpu time\n", obj.Cputime())
+ ctxt.Logf("%d symbols\n", len(ctxt.Syms.Allsym))
+ ctxt.Logf("%d liveness data\n", liveness)
+ }
+
+ ctxt.Bso.Flush()
+
+ errorexit()
+}
+
+type Rpath struct {
+ set bool
+ val string
+}
+
+func (r *Rpath) Set(val string) error {
+ r.set = true
+ r.val = val
+ return nil
+}
+
+func (r *Rpath) String() string {
+ return r.val
+}
+
+func startProfile() {
+ if *cpuprofile != "" {
+ f, err := os.Create(*cpuprofile)
+ if err != nil {
+ log.Fatalf("%v", err)
+ }
+ if err := pprof.StartCPUProfile(f); err != nil {
+ log.Fatalf("%v", err)
+ }
+ AtExit(pprof.StopCPUProfile)
+ }
+ if *memprofile != "" {
+ if *memprofilerate != 0 {
+ runtime.MemProfileRate = int(*memprofilerate)
+ }
+ f, err := os.Create(*memprofile)
+ if err != nil {
+ log.Fatalf("%v", err)
+ }
+ AtExit(func() {
+ runtime.GC() // profile all outstanding allocations
+ if err := pprof.WriteHeapProfile(f); err != nil {
+ log.Fatalf("%v", err)
+ }
+ })
+ }
+}
diff --git a/src/cmd/link/internal/ld/objfile.go b/src/cmd/link/internal/ld/objfile.go
index be9832d..7626a4f 100644
--- a/src/cmd/link/internal/ld/objfile.go
+++ b/src/cmd/link/internal/ld/objfile.go
@@ -44,17 +44,19 @@ package ld
// 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.
+// 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 LSym*):
+// 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 dupok
+// 1<<0 dupok
+// 1<<1 local
+// 1<<2 add to typelink table
// - size [int]
// - gotype [symref index]
// - p [data block]
@@ -111,6 +113,7 @@ import (
"bufio"
"bytes"
"cmd/internal/bio"
+ "cmd/internal/dwarf"
"cmd/internal/obj"
"crypto/sha1"
"encoding/base64"
@@ -129,34 +132,37 @@ var emptyPkg = []byte(`"".`)
// objReader reads Go object files.
type objReader struct {
- rd *bufio.Reader
- ctxt *Link
- pkg string
- pn string
- // List of symbol references for the file being read.
- dupSym *LSym
+ rd *bufio.Reader
+ ctxt *Link
+ lib *Library
+ pn string
+ dupSym *Symbol
+ localSymVersion int
// rdBuf is used by readString and readSymName as scratch for reading strings.
rdBuf []byte
- refs []*LSym
+ // List of symbol references for the file being read.
+ refs []*Symbol
data []byte
reloc []Reloc
pcdata []Pcdata
autom []Auto
- funcdata []*LSym
+ funcdata []*Symbol
funcdataoff []int64
- file []*LSym
+ file []*Symbol
}
-func LoadObjFile(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
+func LoadObjFile(ctxt *Link, f *bio.Reader, lib *Library, length int64, pn string) {
+
start := f.Offset()
r := &objReader{
- rd: f.Reader,
- pkg: pkg,
- ctxt: ctxt,
- pn: pn,
- dupSym: &LSym{Name: ".dup"},
+ rd: f.Reader,
+ lib: lib,
+ ctxt: ctxt,
+ pn: pn,
+ dupSym: &Symbol{Name: ".dup"},
+ localSymVersion: ctxt.Syms.IncVersion(),
}
r.loadObjFile()
if f.Offset() != start+length {
@@ -165,8 +171,7 @@ func LoadObjFile(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string)
}
func (r *objReader) loadObjFile() {
- // Increment context version, versions are used to differentiate static files in different packages
- r.ctxt.IncVersion()
+ pkg := pathtoprefix(r.lib.Pkg)
// Magic header
var buf [8]uint8
@@ -187,11 +192,14 @@ func (r *objReader) loadObjFile() {
if lib == "" {
break
}
- addlib(r.ctxt, r.pkg, r.pn, lib)
+ l := addlib(r.ctxt, pkg, r.pn, lib)
+ if l != nil {
+ r.lib.imports = append(r.lib.imports, l)
+ }
}
// Symbol references
- r.refs = []*LSym{nil} // zeroth ref is nil
+ r.refs = []*Symbol{nil} // zeroth ref is nil
for {
c, err := r.rd.Peek(1)
if err != nil {
@@ -240,10 +248,10 @@ func (r *objReader) readSlices() {
n = r.readInt()
r.autom = make([]Auto, n)
n = r.readInt()
- r.funcdata = make([]*LSym, n)
+ r.funcdata = make([]*Symbol, n)
r.funcdataoff = make([]int64, n)
n = r.readInt()
- r.file = make([]*LSym, n)
+ r.file = make([]*Symbol, n)
}
// Symbols are prefixed so their content doesn't get confused with the magic footer.
@@ -253,18 +261,20 @@ func (r *objReader) readSym() {
if c, err := r.rd.ReadByte(); c != symPrefix || err != nil {
log.Fatalln("readSym out of sync")
}
- t := r.readInt()
+ t := obj.SymKind(r.readInt())
s := r.readSymIndex()
flags := r.readInt()
dupok := flags&1 != 0
local := flags&2 != 0
+ makeTypelink := flags&4 != 0
size := r.readInt()
typ := r.readSymIndex()
data := r.readData()
nreloc := r.readInt()
+ pkg := pathtoprefix(r.lib.Pkg)
isdup := false
- var dup *LSym
+ 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.Size < int64(size) {
@@ -290,7 +300,7 @@ func (r *objReader) readSym() {
}
overwrite:
- s.File = r.pkg
+ s.File = pkg
if dupok {
s.Attr |= AttrDuplicateOK
}
@@ -301,13 +311,14 @@ overwrite:
log.Fatalf("missing type for %s in %s", s.Name, r.pn)
}
if t == obj.SBSS && (s.Type == obj.SRODATA || s.Type == obj.SNOPTRBSS) {
- t = int(s.Type)
+ t = s.Type
}
- s.Type = int16(t)
+ s.Type = t
if s.Size < int64(size) {
s.Size = int64(size)
}
s.Attr.Set(AttrLocal, local)
+ s.Attr.Set(AttrMakeTypelink, makeTypelink)
if typ != nil {
s.Gotype = typ
}
@@ -325,7 +336,7 @@ overwrite:
s.R[i] = Reloc{
Off: r.readInt32(),
Siz: r.readUint8(),
- Type: r.readInt32(),
+ Type: obj.RelocType(r.readInt32()),
Add: r.readInt64(),
Sym: r.readSymIndex(),
}
@@ -393,12 +404,51 @@ overwrite:
pc.File[i] = r.readSymIndex()
}
- if !isdup {
+ if !dupok {
if s.Attr.OnList() {
log.Fatalf("symbol %s listed multiple times", s.Name)
}
s.Attr |= AttrOnList
- r.ctxt.Textp = append(r.ctxt.Textp, s)
+ r.lib.textp = append(r.lib.textp, s)
+ } else {
+ // there may ba a dup in another package
+ // put into a temp list and add to text later
+ if !isdup {
+ r.lib.dupTextSyms = append(r.lib.dupTextSyms, s)
+ } else {
+ r.lib.dupTextSyms = append(r.lib.dupTextSyms, dup)
+ }
+ }
+ }
+ if s.Type == obj.SDWARFINFO {
+ r.patchDWARFName(s)
+ }
+}
+
+func (r *objReader) patchDWARFName(s *Symbol) {
+ // This is kind of ugly. Really the package name should not
+ // even be included here.
+ if s.Size < 1 || s.P[0] != dwarf.DW_ABRV_FUNCTION {
+ return
+ }
+ e := bytes.IndexByte(s.P, 0)
+ if e == -1 {
+ return
+ }
+ p := bytes.Index(s.P[:e], emptyPkg)
+ if p == -1 {
+ return
+ }
+ pkgprefix := []byte(pathtoprefix(r.lib.Pkg) + ".")
+ patched := bytes.Replace(s.P[:e], emptyPkg, pkgprefix, -1)
+
+ s.P = append(patched, s.P[e:]...)
+ delta := int64(len(s.P)) - s.Size
+ s.Size = int64(len(s.P))
+ for i := range s.R {
+ r := &s.R[i]
+ if r.Off > int32(e) {
+ r.Off += int32(delta)
}
}
}
@@ -420,9 +470,9 @@ func (r *objReader) readRef() {
log.Fatalf("invalid symbol version %d", v)
}
if v == 1 {
- v = r.ctxt.Version
+ v = r.localSymVersion
}
- s := Linklookup(r.ctxt, name, v)
+ s := r.ctxt.Syms.Lookup(name, v)
r.refs = append(r.refs, s)
if s == nil || v != 0 {
@@ -522,7 +572,7 @@ func (r *objReader) readData() []byte {
// readSymName reads a symbol name, replacing all "". with pkg.
func (r *objReader) readSymName() string {
- pkg := r.pkg
+ pkg := pathtoprefix(r.lib.Pkg)
n := r.readInt()
if n == 0 {
r.readInt64()
@@ -553,7 +603,7 @@ func (r *objReader) readSymName() string {
}
r.rdBuf = adjName[:0] // in case 2*n wasn't enough
- if DynlinkingGo() {
+ if Buildmode == BuildmodeShared || *FlagLinkshared {
// These types are included in the symbol
// table when dynamically linking. To keep
// binary size down, we replace the names
@@ -564,8 +614,10 @@ func (r *objReader) readSymName() string {
// the symbol is not decodable.
//
// Leave type.runtime. symbols alone, because
- // other parts of the linker manipulates them.
- if strings.HasPrefix(s, "type.") && !strings.HasPrefix(s, "type.runtime.") {
+ // other parts of the linker manipulates them,
+ // and also symbols whose names would not be
+ // shortened by this process.
+ if len(s) > 14 && strings.HasPrefix(s, "type.") && !strings.HasPrefix(s, "type.runtime.") {
hash := sha1.Sum([]byte(s))
prefix := "type."
if s[5] == '.' {
@@ -584,7 +636,7 @@ func (r *objReader) readSymName() string {
}
// Reads the index of a symbol reference and resolves it to a symbol
-func (r *objReader) readSymIndex() *LSym {
+func (r *objReader) readSymIndex() *Symbol {
i := r.readInt()
return r.refs[i]
}
diff --git a/src/cmd/link/internal/ld/pcln.go b/src/cmd/link/internal/ld/pcln.go
index 991b9ef..5a6c425 100644
--- a/src/cmd/link/internal/ld/pcln.go
+++ b/src/cmd/link/internal/ld/pcln.go
@@ -6,39 +6,11 @@ package ld
import (
"cmd/internal/obj"
- "fmt"
"log"
"os"
"path/filepath"
)
-// funcpctab writes to dst a pc-value table mapping the code in func to the values
-// returned by valfunc parameterized by arg. The invocation of valfunc to update the
-// current value is, for each p,
-//
-// val = valfunc(func, val, p, 0, arg);
-// record val as value at p->pc;
-// val = valfunc(func, val, p, 1, arg);
-//
-// where func is the function, val is the current value, p is the instruction being
-// considered, and arg can be used to further parameterize valfunc.
-
-// pctofileline computes either the file number (arg == 0)
-// or the line number (arg == 1) to use at p.
-// Because p->lineno applies to p, phase == 0 (before p)
-// takes care of the update.
-
-// pctospadj computes the sp adjustment in effect.
-// It is oldval plus any adjustment made by p itself.
-// The adjustment by p takes effect only after p, so we
-// apply the change during phase == 1.
-
-// pctopcdata computes the pcdata value in effect at p.
-// A PCDATA instruction sets the value in effect at future
-// non-PCDATA instructions.
-// Since PCDATA instructions have no width in the final code,
-// it does not matter which phase we use for the update.
-
// iteration over encoded pcdata tables.
func getvarint(pp *[]byte) uint32 {
@@ -97,10 +69,6 @@ func pciterinit(ctxt *Link, it *Pciter, d *Pcdata) {
pciternext(it)
}
-// Copyright 2013 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
func addvarint(d *Pcdata, val uint32) {
n := int32(0)
for v := val; v >= 0x80; v >>= 7 {
@@ -123,25 +91,25 @@ func addvarint(d *Pcdata, val uint32) {
p[0] = byte(v)
}
-func addpctab(ftab *LSym, off int32, d *Pcdata) int32 {
+func addpctab(ctxt *Link, ftab *Symbol, off int32, d *Pcdata) int32 {
var start int32
if len(d.P) > 0 {
start = int32(len(ftab.P))
- Addbytes(Ctxt, ftab, d.P)
+ Addbytes(ftab, d.P)
}
- return int32(setuint32(Ctxt, ftab, int64(off), uint32(start)))
+ return int32(setuint32(ctxt, ftab, int64(off), uint32(start)))
}
-func ftabaddstring(ftab *LSym, s string) int32 {
+func ftabaddstring(ctxt *Link, ftab *Symbol, s string) int32 {
n := int32(len(s)) + 1
start := int32(len(ftab.P))
- Symgrow(Ctxt, ftab, int64(start)+int64(n)+1)
+ Symgrow(ftab, int64(start)+int64(n)+1)
copy(ftab.P[start:], s)
return start
}
-func renumberfiles(ctxt *Link, files []*LSym, d *Pcdata) {
- var f *LSym
+func renumberfiles(ctxt *Link, files []*Symbol, d *Pcdata) {
+ var f *Symbol
// Give files numbers.
for i := 0; i < len(files); i++ {
@@ -186,7 +154,7 @@ func renumberfiles(ctxt *Link, files []*LSym, d *Pcdata) {
*d = out
}
-func container(s *LSym) int {
+func container(s *Symbol) int {
// We want to generate func table entries only for the "lowest level" symbols,
// not containers of subsymbols.
if s != nil && s.Type&obj.SCONTAINER != 0 {
@@ -198,18 +166,18 @@ func container(s *LSym) int {
// pclntab initializes the pclntab symbol with
// runtime function and file name information.
-var pclntab_zpcln FuncInfo
+var pclntabZpcln FuncInfo
// These variables are used to initialize runtime.firstmoduledata, see symtab.go:symtab.
var pclntabNfunc int32
var pclntabFiletabOffset int32
var pclntabPclntabOffset int32
-var pclntabFirstFunc *LSym
-var pclntabLastFunc *LSym
+var pclntabFirstFunc *Symbol
+var pclntabLastFunc *Symbol
-func pclntab() {
- funcdata_bytes := int64(0)
- ftab := Linklookup(Ctxt, "runtime.pclntab", 0)
+func (ctxt *Link) pclntab() {
+ funcdataBytes := int64(0)
+ ftab := ctxt.Syms.Lookup("runtime.pclntab", 0)
ftab.Type = obj.SPCLNTAB
ftab.Attr |= AttrReachable
@@ -222,47 +190,47 @@ func pclntab() {
nfunc := int32(0)
// Find container symbols, mark them with SCONTAINER
- for _, s := range Ctxt.Textp {
+ for _, s := range ctxt.Textp {
if s.Outer != nil {
s.Outer.Type |= obj.SCONTAINER
}
}
- for _, s := range Ctxt.Textp {
+ for _, s := range ctxt.Textp {
if container(s) == 0 {
nfunc++
}
}
pclntabNfunc = nfunc
- Symgrow(Ctxt, ftab, 8+int64(SysArch.PtrSize)+int64(nfunc)*2*int64(SysArch.PtrSize)+int64(SysArch.PtrSize)+4)
- setuint32(Ctxt, ftab, 0, 0xfffffffb)
- setuint8(Ctxt, ftab, 6, uint8(SysArch.MinLC))
- setuint8(Ctxt, ftab, 7, uint8(SysArch.PtrSize))
- setuintxx(Ctxt, ftab, 8, uint64(nfunc), int64(SysArch.PtrSize))
+ Symgrow(ftab, 8+int64(SysArch.PtrSize)+int64(nfunc)*2*int64(SysArch.PtrSize)+int64(SysArch.PtrSize)+4)
+ setuint32(ctxt, ftab, 0, 0xfffffffb)
+ setuint8(ctxt, ftab, 6, uint8(SysArch.MinLC))
+ setuint8(ctxt, ftab, 7, uint8(SysArch.PtrSize))
+ setuintxx(ctxt, ftab, 8, uint64(nfunc), int64(SysArch.PtrSize))
pclntabPclntabOffset = int32(8 + SysArch.PtrSize)
nfunc = 0
- var last *LSym
- for _, Ctxt.Cursym = range Ctxt.Textp {
- last = Ctxt.Cursym
- if container(Ctxt.Cursym) != 0 {
+ var last *Symbol
+ for _, s := range ctxt.Textp {
+ last = s
+ if container(s) != 0 {
continue
}
- pcln := Ctxt.Cursym.FuncInfo
+ pcln := s.FuncInfo
if pcln == nil {
- pcln = &pclntab_zpcln
+ pcln = &pclntabZpcln
}
if pclntabFirstFunc == nil {
- pclntabFirstFunc = Ctxt.Cursym
+ pclntabFirstFunc = s
}
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), Ctxt.Cursym)
- setuintxx(Ctxt, ftab, 8+int64(SysArch.PtrSize)+int64(nfunc)*2*int64(SysArch.PtrSize)+int64(SysArch.PtrSize), uint64(funcstart), int64(SysArch.PtrSize))
+ 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))
// fixed size of struct, checked below
off := funcstart
@@ -271,37 +239,37 @@ func pclntab() {
if len(pcln.Funcdata) > 0 && (end&int32(SysArch.PtrSize-1) != 0) {
end += 4
}
- Symgrow(Ctxt, ftab, int64(end))
+ Symgrow(ftab, int64(end))
// entry uintptr
- off = int32(setaddr(Ctxt, ftab, int64(off), Ctxt.Cursym))
+ off = int32(setaddr(ctxt, ftab, int64(off), s))
// name int32
- off = int32(setuint32(Ctxt, ftab, int64(off), uint32(ftabaddstring(ftab, Ctxt.Cursym.Name))))
+ off = int32(setuint32(ctxt, ftab, int64(off), uint32(ftabaddstring(ctxt, ftab, s.Name))))
// args int32
// TODO: Move into funcinfo.
args := uint32(0)
- if Ctxt.Cursym.FuncInfo != nil {
- args = uint32(Ctxt.Cursym.FuncInfo.Args)
+ if s.FuncInfo != nil {
+ args = uint32(s.FuncInfo.Args)
}
- off = int32(setuint32(Ctxt, ftab, int64(off), args))
+ off = int32(setuint32(ctxt, ftab, int64(off), args))
// frame int32
// This has been removed (it was never set quite correctly anyway).
// Nothing should use it.
// Leave an obviously incorrect value.
// TODO: Remove entirely.
- off = int32(setuint32(Ctxt, ftab, int64(off), 0x1234567))
+ off = int32(setuint32(ctxt, ftab, int64(off), 0x1234567))
- if pcln != &pclntab_zpcln {
- renumberfiles(Ctxt, pcln.File, &pcln.Pcfile)
+ if pcln != &pclntabZpcln {
+ renumberfiles(ctxt, pcln.File, &pcln.Pcfile)
if false {
// Sanity check the new numbering
var it Pciter
- for pciterinit(Ctxt, &it, &pcln.Pcfile); it.done == 0; pciternext(&it) {
- if it.value < 1 || it.value > int32(len(Ctxt.Filesyms)) {
- Diag("bad file number in pcfile: %d not in range [1, %d]\n", it.value, len(Ctxt.Filesyms))
+ for pciterinit(ctxt, &it, &pcln.Pcfile); it.done == 0; pciternext(&it) {
+ if it.value < 1 || it.value > int32(len(ctxt.Filesyms)) {
+ Errorf(s, "bad file number in pcfile: %d not in range [1, %d]\n", it.value, len(ctxt.Filesyms))
errorexit()
}
}
@@ -309,14 +277,14 @@ func pclntab() {
}
// pcdata
- off = addpctab(ftab, off, &pcln.Pcsp)
+ off = addpctab(ctxt, ftab, off, &pcln.Pcsp)
- off = addpctab(ftab, off, &pcln.Pcfile)
- off = addpctab(ftab, off, &pcln.Pcline)
- off = int32(setuint32(Ctxt, ftab, int64(off), uint32(len(pcln.Pcdata))))
- off = int32(setuint32(Ctxt, ftab, int64(off), uint32(len(pcln.Funcdata))))
+ off = addpctab(ctxt, ftab, off, &pcln.Pcfile)
+ off = addpctab(ctxt, ftab, off, &pcln.Pcline)
+ off = int32(setuint32(ctxt, ftab, int64(off), uint32(len(pcln.Pcdata))))
+ off = int32(setuint32(ctxt, ftab, int64(off), uint32(len(pcln.Funcdata))))
for i := 0; i < len(pcln.Pcdata); i++ {
- off = addpctab(ftab, off, &pcln.Pcdata[i])
+ off = addpctab(ctxt, ftab, off, &pcln.Pcdata[i])
}
// funcdata, must be pointer-aligned and we're only int32-aligned.
@@ -327,12 +295,12 @@ func 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))
+ setuintxx(ctxt, ftab, int64(off)+int64(SysArch.PtrSize)*int64(i), uint64(pcln.Funcdataoff[i]), int64(SysArch.PtrSize))
} else {
// TODO: Dedup.
- funcdata_bytes += pcln.Funcdata[i].Size
+ funcdataBytes += pcln.Funcdata[i].Size
- setaddrplus(Ctxt, ftab, int64(off)+int64(SysArch.PtrSize)*int64(i), pcln.Funcdata[i], pcln.Funcdataoff[i])
+ setaddrplus(ctxt, ftab, int64(off)+int64(SysArch.PtrSize)*int64(i), pcln.Funcdata[i], pcln.Funcdataoff[i])
}
}
@@ -340,7 +308,7 @@ func pclntab() {
}
if off != end {
- Diag("bad math in functab: funcstart=%d off=%d but end=%d (npcdata=%d nfuncdata=%d ptrsize=%d)", funcstart, off, end, len(pcln.Pcdata), len(pcln.Funcdata), SysArch.PtrSize)
+ Errorf(s, "bad math in functab: funcstart=%d off=%d but end=%d (npcdata=%d nfuncdata=%d ptrsize=%d)", funcstart, off, end, len(pcln.Pcdata), len(pcln.Funcdata), SysArch.PtrSize)
errorexit()
}
@@ -349,33 +317,33 @@ func pclntab() {
pclntabLastFunc = last
// Final entry of table is just end pc.
- setaddrplus(Ctxt, ftab, 8+int64(SysArch.PtrSize)+int64(nfunc)*2*int64(SysArch.PtrSize), last, last.Size)
+ setaddrplus(ctxt, ftab, 8+int64(SysArch.PtrSize)+int64(nfunc)*2*int64(SysArch.PtrSize), last, last.Size)
// Start file table.
start := int32(len(ftab.P))
start += int32(-len(ftab.P)) & (int32(SysArch.PtrSize) - 1)
pclntabFiletabOffset = start
- setuint32(Ctxt, ftab, 8+int64(SysArch.PtrSize)+int64(nfunc)*2*int64(SysArch.PtrSize)+int64(SysArch.PtrSize), uint32(start))
+ setuint32(ctxt, ftab, 8+int64(SysArch.PtrSize)+int64(nfunc)*2*int64(SysArch.PtrSize)+int64(SysArch.PtrSize), uint32(start))
- Symgrow(Ctxt, ftab, int64(start)+(int64(len(Ctxt.Filesyms))+1)*4)
- setuint32(Ctxt, ftab, int64(start), uint32(len(Ctxt.Filesyms)))
- for i := len(Ctxt.Filesyms) - 1; i >= 0; i-- {
- s := Ctxt.Filesyms[i]
- setuint32(Ctxt, ftab, int64(start)+s.Value*4, uint32(ftabaddstring(ftab, s.Name)))
+ Symgrow(ftab, int64(start)+(int64(len(ctxt.Filesyms))+1)*4)
+ setuint32(ctxt, ftab, int64(start), uint32(len(ctxt.Filesyms)+1))
+ for i := len(ctxt.Filesyms) - 1; i >= 0; i-- {
+ s := ctxt.Filesyms[i]
+ setuint32(ctxt, ftab, int64(start)+s.Value*4, uint32(ftabaddstring(ctxt, ftab, s.Name)))
}
ftab.Size = int64(len(ftab.P))
- if Debug['v'] != 0 {
- fmt.Fprintf(Bso, "%5.2f pclntab=%d bytes, funcdata total %d bytes\n", obj.Cputime(), ftab.Size, funcdata_bytes)
+ if ctxt.Debugvlog != 0 {
+ ctxt.Logf("%5.2f pclntab=%d bytes, funcdata total %d bytes\n", obj.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 := goroot
+ root := obj.GOROOT
if final := os.Getenv("GOROOT_FINAL"); final != "" {
root = final
}
@@ -393,16 +361,16 @@ const (
// findfunctab generates a lookup table to quickly find the containing
// function for a pc. See src/runtime/symtab.go:findfunc for details.
-func findfunctab() {
- t := Linklookup(Ctxt, "runtime.findfunctab", 0)
+func (ctxt *Link) findfunctab() {
+ t := ctxt.Syms.Lookup("runtime.findfunctab", 0)
t.Type = obj.SRODATA
t.Attr |= AttrReachable
t.Attr |= AttrLocal
// find min and max address
- min := Ctxt.Textp[0].Value
+ min := ctxt.Textp[0].Value
max := int64(0)
- for _, s := range Ctxt.Textp {
+ for _, s := range ctxt.Textp {
max = s.Value + s.Size
}
@@ -415,18 +383,18 @@ func findfunctab() {
indexes[i] = NOIDX
}
idx := int32(0)
- for i, s := range Ctxt.Textp {
+ for i, s := range ctxt.Textp {
if container(s) != 0 {
continue
}
p := s.Value
- var e *LSym
+ var e *Symbol
i++
- if i < len(Ctxt.Textp) {
- e = Ctxt.Textp[i]
+ if i < len(ctxt.Textp) {
+ e = ctxt.Textp[i]
}
- for container(e) != 0 && i < len(Ctxt.Textp) {
- e = Ctxt.Textp[i]
+ for container(e) != 0 && i < len(ctxt.Textp) {
+ e = ctxt.Textp[i]
i++
}
q := max
@@ -452,25 +420,25 @@ func findfunctab() {
// allocate table
nbuckets := int32((max - min + BUCKETSIZE - 1) / BUCKETSIZE)
- Symgrow(Ctxt, t, 4*int64(nbuckets)+int64(n))
+ Symgrow(t, 4*int64(nbuckets)+int64(n))
// fill in table
for i := int32(0); i < nbuckets; i++ {
base := indexes[i*SUBBUCKETS]
if base == NOIDX {
- Diag("hole in findfunctab")
+ Errorf(nil, "hole in findfunctab")
}
- setuint32(Ctxt, t, int64(i)*(4+SUBBUCKETS), uint32(base))
+ setuint32(ctxt, t, int64(i)*(4+SUBBUCKETS), uint32(base))
for j := int32(0); j < SUBBUCKETS && i*SUBBUCKETS+j < n; j++ {
idx = indexes[i*SUBBUCKETS+j]
if idx == NOIDX {
- Diag("hole in findfunctab")
+ Errorf(nil, "hole in findfunctab")
}
if idx-base >= 256 {
- Diag("too many functions in a findfunc bucket! %d/%d %d %d", i, nbuckets, j, idx-base)
+ Errorf(nil, "too many functions in a findfunc bucket! %d/%d %d %d", i, nbuckets, j, idx-base)
}
- setuint8(Ctxt, t, int64(i)*(4+SUBBUCKETS)+4+int64(j), uint8(idx-base))
+ setuint8(ctxt, t, int64(i)*(4+SUBBUCKETS)+4+int64(j), uint8(idx-base))
}
}
}
diff --git a/src/cmd/link/internal/ld/pe.go b/src/cmd/link/internal/ld/pe.go
index 839aa6c..517ed6c 100644
--- a/src/cmd/link/internal/ld/pe.go
+++ b/src/cmd/link/internal/ld/pe.go
@@ -324,7 +324,7 @@ var dosstub = []uint8{
0x00,
}
-var rsrcsym *LSym
+var rsrcsym *Symbol
var strtbl []byte
@@ -357,7 +357,7 @@ var sh [16]IMAGE_SECTION_HEADER
var dd []IMAGE_DATA_DIRECTORY
type Imp struct {
- s *LSym
+ s *Symbol
off uint64
next *Imp
argsize int
@@ -373,13 +373,13 @@ type Dll struct {
var dr *Dll
-var dexport [1024]*LSym
+var dexport [1024]*Symbol
var nexport int
-func addpesection(name string, sectsize int, filesize int) *IMAGE_SECTION_HEADER {
+func addpesection(ctxt *Link, name string, sectsize int, filesize int) *IMAGE_SECTION_HEADER {
if pensect == 16 {
- Diag("too many sections")
+ Errorf(nil, "too many sections")
errorexit()
}
@@ -398,26 +398,26 @@ func addpesection(name string, sectsize int, filesize int) *IMAGE_SECTION_HEADER
return h
}
-func chksectoff(h *IMAGE_SECTION_HEADER, off int64) {
+func chksectoff(ctxt *Link, h *IMAGE_SECTION_HEADER, off int64) {
if off != int64(h.PointerToRawData) {
- Diag("%s.PointerToRawData = %#x, want %#x", cstring(h.Name[:]), uint64(int64(h.PointerToRawData)), uint64(off))
+ Errorf(nil, "%s.PointerToRawData = %#x, want %#x", cstring(h.Name[:]), uint64(int64(h.PointerToRawData)), uint64(off))
errorexit()
}
}
-func chksectseg(h *IMAGE_SECTION_HEADER, s *Segment) {
+func chksectseg(ctxt *Link, h *IMAGE_SECTION_HEADER, s *Segment) {
if s.Vaddr-PEBASE != uint64(h.VirtualAddress) {
- Diag("%s.VirtualAddress = %#x, want %#x", cstring(h.Name[:]), uint64(int64(h.VirtualAddress)), uint64(int64(s.Vaddr-PEBASE)))
+ Errorf(nil, "%s.VirtualAddress = %#x, want %#x", cstring(h.Name[:]), uint64(int64(h.VirtualAddress)), uint64(int64(s.Vaddr-PEBASE)))
errorexit()
}
if s.Fileoff != uint64(h.PointerToRawData) {
- Diag("%s.PointerToRawData = %#x, want %#x", cstring(h.Name[:]), uint64(int64(h.PointerToRawData)), uint64(int64(s.Fileoff)))
+ Errorf(nil, "%s.PointerToRawData = %#x, want %#x", cstring(h.Name[:]), uint64(int64(h.PointerToRawData)), uint64(int64(s.Fileoff)))
errorexit()
}
}
-func Peinit() {
+func Peinit(ctxt *Link) {
var l int
switch SysArch.Family {
@@ -441,9 +441,9 @@ func Peinit() {
nextfileoff = int(PEFILEHEADR)
// some mingw libs depend on this symbol, for example, FindPESectionByName
- xdefine("__image_base__", obj.SDATA, PEBASE)
+ ctxt.xdefine("__image_base__", obj.SDATA, PEBASE)
- xdefine("_image_base__", obj.SDATA, PEBASE)
+ ctxt.xdefine("_image_base__", obj.SDATA, PEBASE)
}
func pewrite() {
@@ -472,12 +472,12 @@ func strput(s string) {
}
}
-func initdynimport() *Dll {
+func initdynimport(ctxt *Link) *Dll {
var d *Dll
dr = nil
var m *Imp
- for _, s := range Ctxt.Allsym {
+ for _, s := range ctxt.Syms.Allsym {
if !s.Attr.Reachable() || s.Type != obj.SDYNIMPORT {
continue
}
@@ -505,7 +505,7 @@ func initdynimport() *Dll {
var err error
m.argsize, err = strconv.Atoi(s.Extname[i+1:])
if err != nil {
- Diag("failed to parse stdcall decoration: %v", err)
+ Errorf(s, "failed to parse stdcall decoration: %v", err)
}
m.argsize *= SysArch.PtrSize
s.Extname = s.Extname[:i]
@@ -521,13 +521,13 @@ func initdynimport() *Dll {
for d := dr; d != nil; d = d.next {
for m = d.ms; m != nil; m = m.next {
m.s.Type = obj.SDATA
- Symgrow(Ctxt, m.s, int64(SysArch.PtrSize))
+ Symgrow(m.s, int64(SysArch.PtrSize))
dynName := m.s.Extname
// only windows/386 requires stdcall decoration
if SysArch.Family == sys.I386 && m.argsize >= 0 {
dynName += fmt.Sprintf("@%d", m.argsize)
}
- dynSym := Linklookup(Ctxt, dynName, 0)
+ dynSym := ctxt.Syms.Lookup(dynName, 0)
dynSym.Attr |= AttrReachable
dynSym.Type = obj.SHOSTOBJ
r := Addrel(m.s)
@@ -538,7 +538,7 @@ func initdynimport() *Dll {
}
}
} else {
- dynamic := Linklookup(Ctxt, ".windynamic", 0)
+ dynamic := ctxt.Syms.Lookup(".windynamic", 0)
dynamic.Attr |= AttrReachable
dynamic.Type = obj.SWINDOWS
for d := dr; d != nil; d = d.next {
@@ -569,9 +569,9 @@ func peimporteddlls() []string {
return dlls
}
-func addimports(datsect *IMAGE_SECTION_HEADER) {
- startoff := Cpos()
- dynamic := Linklookup(Ctxt, ".windynamic", 0)
+func addimports(ctxt *Link, datsect *IMAGE_SECTION_HEADER) {
+ startoff := coutbuf.Offset()
+ dynamic := ctxt.Syms.Lookup(".windynamic", 0)
// skip import descriptor table (will write it later)
n := uint64(0)
@@ -583,7 +583,7 @@ func addimports(datsect *IMAGE_SECTION_HEADER) {
// write dll names
for d := dr; d != nil; d = d.next {
- d.nameoff = uint64(Cpos()) - uint64(startoff)
+ d.nameoff = uint64(coutbuf.Offset()) - uint64(startoff)
strput(d.name)
}
@@ -591,18 +591,18 @@ func addimports(datsect *IMAGE_SECTION_HEADER) {
var m *Imp
for d := dr; d != nil; d = d.next {
for m = d.ms; m != nil; m = m.next {
- m.off = uint64(nextsectoff) + uint64(Cpos()) - uint64(startoff)
+ m.off = uint64(nextsectoff) + uint64(coutbuf.Offset()) - uint64(startoff)
Wputl(0) // hint
strput(m.s.Extname)
}
}
// write OriginalFirstThunks
- oftbase := uint64(Cpos()) - uint64(startoff)
+ oftbase := uint64(coutbuf.Offset()) - uint64(startoff)
- n = uint64(Cpos())
+ n = uint64(coutbuf.Offset())
for d := dr; d != nil; d = d.next {
- d.thunkoff = uint64(Cpos()) - n
+ d.thunkoff = uint64(coutbuf.Offset()) - n
for m = d.ms; m != nil; m = m.next {
if pe64 != 0 {
Vputl(m.off)
@@ -619,13 +619,13 @@ func addimports(datsect *IMAGE_SECTION_HEADER) {
}
// add pe section and pad it at the end
- n = uint64(Cpos()) - uint64(startoff)
+ n = uint64(coutbuf.Offset()) - uint64(startoff)
- isect := addpesection(".idata", int(n), int(n))
+ isect := addpesection(ctxt, ".idata", int(n), int(n))
isect.Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE
- chksectoff(isect, startoff)
+ chksectoff(ctxt, isect, startoff)
strnput("", int(uint64(isect.SizeOfRawData)-n))
- endoff := Cpos()
+ endoff := coutbuf.Offset()
// write FirstThunks (allocated in .data section)
ftbase := uint64(dynamic.Value) - uint64(datsect.VirtualAddress) - PEBASE
@@ -666,7 +666,6 @@ func addimports(datsect *IMAGE_SECTION_HEADER) {
// update data directory
dd[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = isect.VirtualAddress
-
dd[IMAGE_DIRECTORY_ENTRY_IMPORT].Size = isect.VirtualSize
dd[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress = uint32(dynamic.Value - PEBASE)
dd[IMAGE_DIRECTORY_ENTRY_IAT].Size = uint32(dynamic.Size)
@@ -674,20 +673,20 @@ func addimports(datsect *IMAGE_SECTION_HEADER) {
Cseek(endoff)
}
-type byExtname []*LSym
+type byExtname []*Symbol
func (s byExtname) Len() int { return len(s) }
func (s byExtname) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
func (s byExtname) Less(i, j int) bool { return s[i].Extname < s[j].Extname }
-func initdynexport() {
+func initdynexport(ctxt *Link) {
nexport = 0
- for _, s := range Ctxt.Allsym {
+ for _, s := range ctxt.Syms.Allsym {
if !s.Attr.Reachable() || !s.Attr.CgoExportDynamic() {
continue
}
if nexport+1 > len(dexport) {
- Diag("pe dynexport table is full")
+ Errorf(s, "pe dynexport table is full")
errorexit()
}
@@ -698,10 +697,10 @@ func initdynexport() {
sort.Sort(byExtname(dexport[:nexport]))
}
-func addexports() {
+func addexports(ctxt *Link) {
var e IMAGE_EXPORT_DIRECTORY
- size := binary.Size(&e) + 10*nexport + len(outfile) + 1
+ size := binary.Size(&e) + 10*nexport + len(*flagOutfile) + 1
for i := 0; i < nexport; i++ {
size += len(dexport[i].Extname) + 1
}
@@ -710,16 +709,16 @@ func addexports() {
return
}
- sect := addpesection(".edata", size, size)
+ sect := addpesection(ctxt, ".edata", size, size)
sect.Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ
- chksectoff(sect, Cpos())
+ chksectoff(ctxt, sect, coutbuf.Offset())
va := int(sect.VirtualAddress)
dd[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress = uint32(va)
dd[IMAGE_DIRECTORY_ENTRY_EXPORT].Size = sect.VirtualSize
- va_name := va + binary.Size(&e) + nexport*4
- va_addr := va + binary.Size(&e)
- va_na := va + binary.Size(&e) + nexport*8
+ vaName := va + binary.Size(&e) + nexport*4
+ vaAddr := va + binary.Size(&e)
+ vaNa := va + binary.Size(&e) + nexport*8
e.Characteristics = 0
e.MajorVersion = 0
@@ -728,9 +727,9 @@ func addexports() {
e.NumberOfNames = uint32(nexport)
e.Name = uint32(va+binary.Size(&e)) + uint32(nexport)*10 // Program names.
e.Base = 1
- e.AddressOfFunctions = uint32(va_addr)
- e.AddressOfNames = uint32(va_name)
- e.AddressOfNameOrdinals = uint32(va_na)
+ e.AddressOfFunctions = uint32(vaAddr)
+ e.AddressOfNames = uint32(vaName)
+ e.AddressOfNameOrdinals = uint32(vaNa)
// put IMAGE_EXPORT_DIRECTORY
binary.Write(&coutbuf, binary.LittleEndian, &e)
@@ -741,7 +740,7 @@ func addexports() {
}
// put EXPORT Name Pointer Table
- v := int(e.Name + uint32(len(outfile)) + 1)
+ v := int(e.Name + uint32(len(*flagOutfile)) + 1)
for i := 0; i < nexport; i++ {
Lputl(uint32(v))
@@ -754,7 +753,7 @@ func addexports() {
}
// put Names
- strnput(outfile, len(outfile)+1)
+ strnput(*flagOutfile, len(*flagOutfile)+1)
for i := 0; i < nexport; i++ {
strnput(dexport[i].Extname, len(dexport[i].Extname)+1)
@@ -764,7 +763,7 @@ func addexports() {
// perelocsect relocates symbols from first in section sect, and returns
// the total number of relocations emitted.
-func perelocsect(sect *Section, syms []*LSym) int {
+func perelocsect(ctxt *Link, sect *Section, syms []*Symbol) int {
// If main section has no bits, nothing to relocate.
if sect.Vaddr >= sect.Seg.Vaddr+sect.Seg.Filelen {
return 0
@@ -772,7 +771,7 @@ func perelocsect(sect *Section, syms []*LSym) int {
relocs := 0
- sect.Reloff = uint64(Cpos())
+ sect.Reloff = uint64(coutbuf.Offset())
for i, s := range syms {
if !s.Attr.Reachable() {
continue
@@ -791,52 +790,50 @@ func perelocsect(sect *Section, syms []*LSym) int {
if sym.Value >= int64(eaddr) {
break
}
- Ctxt.Cursym = sym
-
for ri := 0; ri < len(sym.R); ri++ {
r := &sym.R[ri]
if r.Done != 0 {
continue
}
if r.Xsym == nil {
- Diag("missing xsym in relocation")
+ Errorf(sym, "missing xsym in relocation")
continue
}
if r.Xsym.Dynid < 0 {
- Diag("reloc %d to non-coff symbol %s (outer=%s) %d", r.Type, r.Sym.Name, r.Xsym.Name, r.Sym.Type)
+ 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(r, int64(uint64(sym.Value+int64(r.Off))-PEBASE)) {
- Diag("unsupported obj reloc %d/%d to %s", r.Type, r.Siz, r.Sym.Name)
+ if !Thearch.PEreloc1(sym, r, int64(uint64(sym.Value+int64(r.Off))-PEBASE)) {
+ Errorf(sym, "unsupported obj reloc %d/%d to %s", r.Type, r.Siz, r.Sym.Name)
}
relocs++
}
}
- sect.Rellen = uint64(Cpos()) - sect.Reloff
+ sect.Rellen = uint64(coutbuf.Offset()) - sect.Reloff
return relocs
}
// peemitreloc emits relocation entries for go.o in external linking.
-func peemitreloc(text, data, ctors *IMAGE_SECTION_HEADER) {
- for Cpos()&7 != 0 {
+func peemitreloc(ctxt *Link, text, data, ctors *IMAGE_SECTION_HEADER) {
+ for coutbuf.Offset()&7 != 0 {
Cput(0)
}
- text.PointerToRelocations = uint32(Cpos())
+ text.PointerToRelocations = uint32(coutbuf.Offset())
// first entry: extended relocs
Lputl(0) // placeholder for number of relocation + 1
Lputl(0)
Wputl(0)
- n := perelocsect(Segtext.Sect, Ctxt.Textp) + 1
+ n := perelocsect(ctxt, Segtext.Sect, ctxt.Textp) + 1
for sect := Segtext.Sect.Next; sect != nil; sect = sect.Next {
- n += perelocsect(sect, datap)
+ n += perelocsect(ctxt, sect, datap)
}
- cpos := Cpos()
+ cpos := coutbuf.Offset()
Cseek(int64(text.PointerToRelocations))
Lputl(uint32(n))
Cseek(cpos)
@@ -856,10 +853,10 @@ func peemitreloc(text, data, ctors *IMAGE_SECTION_HEADER) {
n = 1
for sect := Segdata.Sect; sect != nil; sect = sect.Next {
- n += perelocsect(sect, datap)
+ n += perelocsect(ctxt, sect, datap)
}
- cpos = Cpos()
+ cpos = coutbuf.Offset()
Cseek(int64(data.PointerToRelocations))
Lputl(uint32(n))
Cseek(cpos)
@@ -871,15 +868,15 @@ func peemitreloc(text, data, ctors *IMAGE_SECTION_HEADER) {
}
data.NumberOfRelocations = uint16(n - 1)
- dottext := Linklookup(Ctxt, ".text", 0)
+ dottext := ctxt.Syms.Lookup(".text", 0)
ctors.NumberOfRelocations = 1
- ctors.PointerToRelocations = uint32(Cpos())
+ ctors.PointerToRelocations = uint32(coutbuf.Offset())
sectoff := ctors.VirtualAddress
Lputl(sectoff)
Lputl(uint32(dottext.Dynid))
- switch obj.Getgoarch() {
+ switch obj.GOARCH {
default:
- fmt.Fprintf(os.Stderr, "link: unknown architecture for PE: %q\n", obj.Getgoarch())
+ fmt.Fprintf(os.Stderr, "link: unknown architecture for PE: %q\n", obj.GOARCH)
os.Exit(2)
case "386":
Wputl(IMAGE_REL_I386_DIR32)
@@ -888,15 +885,15 @@ func peemitreloc(text, data, ctors *IMAGE_SECTION_HEADER) {
}
}
-func dope() {
+func (ctxt *Link) dope() {
/* relocation table */
- rel := Linklookup(Ctxt, ".rel", 0)
+ rel := ctxt.Syms.Lookup(".rel", 0)
rel.Attr |= AttrReachable
rel.Type = obj.SELFROSECT
- initdynimport()
- initdynexport()
+ initdynimport(ctxt)
+ initdynexport(ctxt)
}
func strtbladd(name string) int {
@@ -913,14 +910,14 @@ func strtbladd(name string) int {
* reference: pecoff_v8.docx Page 24.
* <http://www.microsoft.com/whdc/system/platform/firmware/PECOFFdwn.mspx>
*/
-func newPEDWARFSection(name string, size int64) *IMAGE_SECTION_HEADER {
+func newPEDWARFSection(ctxt *Link, name string, size int64) *IMAGE_SECTION_HEADER {
if size == 0 {
return nil
}
off := strtbladd(name)
s := fmt.Sprintf("/%d", off)
- h := addpesection(s, int(size), int(size))
+ h := addpesection(ctxt, s, int(size), int(size))
h.Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_DISCARDABLE
return h
@@ -928,20 +925,20 @@ func newPEDWARFSection(name string, size int64) *IMAGE_SECTION_HEADER {
// writePESymTableRecords writes all COFF symbol table records.
// It returns number of records written.
-func writePESymTableRecords() int {
+func writePESymTableRecords(ctxt *Link) int {
var symcnt int
- put := func(s *LSym, name string, type_ int, addr int64, size int64, ver int, gotype *LSym) {
+ put := func(ctxt *Link, s *Symbol, name string, type_ SymbolType, addr int64, gotype *Symbol) {
if s == nil {
return
}
- if s.Sect == nil && type_ != 'U' {
+ if s.Sect == nil && type_ != UndefinedSym {
return
}
switch type_ {
default:
return
- case 'D', 'B', 'T', 'U':
+ case DataSym, BSSSym, TextSym, UndefinedSym:
}
// only windows/386 requires underscore prefix on external symbols
@@ -967,10 +964,10 @@ func writePESymTableRecords() int {
} else if uint64(s.Value) >= Segtext.Vaddr {
value = int64(uint64(s.Value) - Segtext.Vaddr)
sect = textsect
- } else if type_ == 'U' {
+ } else if type_ == UndefinedSym {
typ = IMAGE_SYM_DTYPE_FUNCTION
} else {
- Diag("addpesym %#x", addr)
+ Errorf(s, "addpesym %#x", addr)
}
// write COFF symbol table record
@@ -1001,28 +998,28 @@ func writePESymTableRecords() int {
for d := dr; d != nil; d = d.next {
for m := d.ms; m != nil; m = m.next {
s := m.s.R[0].Xsym
- put(s, s.Name, 'U', 0, int64(SysArch.PtrSize), 0, nil)
+ put(ctxt, s, s.Name, UndefinedSym, 0, nil)
}
}
- s := Linklookup(Ctxt, ".text", 0)
+ s := ctxt.Syms.Lookup(".text", 0)
if s.Type == obj.STEXT {
- put(s, s.Name, 'T', s.Value, s.Size, int(s.Version), nil)
+ put(ctxt, s, s.Name, TextSym, s.Value, nil)
}
}
- genasmsym(put)
+ genasmsym(ctxt, put)
return symcnt
}
-func addpesymtable() {
- symtabStartPos := Cpos()
+func addpesymtable(ctxt *Link) {
+ symtabStartPos := coutbuf.Offset()
// write COFF symbol table
var symcnt int
- if Debug['s'] == 0 || Linkmode == LinkExternal {
- symcnt = writePESymTableRecords()
+ if !*FlagS || Linkmode == LinkExternal {
+ symcnt = writePESymTableRecords(ctxt)
}
// update COFF file header and section table
@@ -1031,9 +1028,9 @@ func addpesymtable() {
if Linkmode != LinkExternal {
// We do not really need .symtab for go.o, and if we have one, ld
// will also include it in the exe, and that will confuse windows.
- h = addpesection(".symtab", size, size)
+ h = addpesection(ctxt, ".symtab", size, size)
h.Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_DISCARDABLE
- chksectoff(h, symtabStartPos)
+ chksectoff(ctxt, h, symtabStartPos)
}
fh.PointerToSymbolTable = uint32(symtabStartPos)
fh.NumberOfSymbols = uint32(symcnt)
@@ -1048,22 +1045,22 @@ func addpesymtable() {
}
}
-func setpersrc(sym *LSym) {
+func setpersrc(ctxt *Link, sym *Symbol) {
if rsrcsym != nil {
- Diag("too many .rsrc sections")
+ Errorf(sym, "too many .rsrc sections")
}
rsrcsym = sym
}
-func addpersrc() {
+func addpersrc(ctxt *Link) {
if rsrcsym == nil {
return
}
- h := addpesection(".rsrc", int(rsrcsym.Size), int(rsrcsym.Size))
+ h := addpesection(ctxt, ".rsrc", int(rsrcsym.Size), int(rsrcsym.Size))
h.Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_CNT_INITIALIZED_DATA
- chksectoff(h, Cpos())
+ chksectoff(ctxt, h, coutbuf.Offset())
// relocation
var p []byte
@@ -1091,16 +1088,16 @@ func addpersrc() {
dd[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size = h.VirtualSize
}
-func addinitarray() (c *IMAGE_SECTION_HEADER) {
+func addinitarray(ctxt *Link) (c *IMAGE_SECTION_HEADER) {
// The size below was determined by the specification for array relocations,
// and by observing what GCC writes here. If the initarray section grows to
// contain more than one constructor entry, the size will need to be 8 * constructor_count.
// However, the entire Go runtime is initialized from just one function, so it is unlikely
// that this will need to grow in the future.
var size int
- switch obj.Getgoarch() {
+ switch obj.GOARCH {
default:
- fmt.Fprintf(os.Stderr, "link: unknown architecture for PE: %q\n", obj.Getgoarch())
+ fmt.Fprintf(os.Stderr, "link: unknown architecture for PE: %q\n", obj.GOARCH)
os.Exit(2)
case "386":
size = 4
@@ -1108,16 +1105,16 @@ func addinitarray() (c *IMAGE_SECTION_HEADER) {
size = 8
}
- c = addpesection(".ctors", size, size)
+ c = addpesection(ctxt, ".ctors", size, size)
c.Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ
c.SizeOfRawData = uint32(size)
Cseek(int64(c.PointerToRawData))
- chksectoff(c, Cpos())
- init_entry := Linklookup(Ctxt, INITENTRY, 0)
+ chksectoff(ctxt, c, coutbuf.Offset())
+ init_entry := ctxt.Syms.Lookup(*flagEntrySymbol, 0)
addr := uint64(init_entry.Value) - init_entry.Sect.Vaddr
- switch obj.Getgoarch() {
+ switch obj.GOARCH {
case "386":
Lputl(uint32(addr))
case "amd64":
@@ -1127,7 +1124,7 @@ func addinitarray() (c *IMAGE_SECTION_HEADER) {
return c
}
-func Asmbpe() {
+func Asmbpe(ctxt *Link) {
switch SysArch.Family {
default:
Exitf("unknown PE architecture: %v", SysArch.Family)
@@ -1137,50 +1134,50 @@ func Asmbpe() {
fh.Machine = IMAGE_FILE_MACHINE_I386
}
- t := addpesection(".text", int(Segtext.Length), int(Segtext.Length))
+ t := addpesection(ctxt, ".text", int(Segtext.Length), int(Segtext.Length))
t.Characteristics = IMAGE_SCN_CNT_CODE | IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ
if Linkmode == LinkExternal {
// some data symbols (e.g. masks) end up in the .text section, and they normally
// expect larger alignment requirement than the default text section alignment.
t.Characteristics |= IMAGE_SCN_ALIGN_32BYTES
}
- chksectseg(t, &Segtext)
+ chksectseg(ctxt, t, &Segtext)
textsect = pensect
var d *IMAGE_SECTION_HEADER
var c *IMAGE_SECTION_HEADER
if Linkmode != LinkExternal {
- d = addpesection(".data", int(Segdata.Length), int(Segdata.Filelen))
+ d = addpesection(ctxt, ".data", int(Segdata.Length), int(Segdata.Filelen))
d.Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE
- chksectseg(d, &Segdata)
+ chksectseg(ctxt, d, &Segdata)
datasect = pensect
} else {
- d = addpesection(".data", int(Segdata.Filelen), int(Segdata.Filelen))
+ d = addpesection(ctxt, ".data", int(Segdata.Filelen), int(Segdata.Filelen))
d.Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_ALIGN_32BYTES
- chksectseg(d, &Segdata)
+ chksectseg(ctxt, d, &Segdata)
datasect = pensect
- b := addpesection(".bss", int(Segdata.Length-Segdata.Filelen), 0)
+ b := addpesection(ctxt, ".bss", int(Segdata.Length-Segdata.Filelen), 0)
b.Characteristics = IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_ALIGN_32BYTES
b.PointerToRawData = 0
bsssect = pensect
- c = addinitarray()
+ c = addinitarray(ctxt)
}
- if Debug['s'] == 0 {
- dwarfaddpeheaders()
+ if !*FlagS {
+ dwarfaddpeheaders(ctxt)
}
Cseek(int64(nextfileoff))
if Linkmode != LinkExternal {
- addimports(d)
- addexports()
+ addimports(ctxt, d)
+ addexports(ctxt)
}
- addpesymtable()
- addpersrc()
+ addpesymtable(ctxt)
+ addpersrc(ctxt)
if Linkmode == LinkExternal {
- peemitreloc(t, d, c)
+ peemitreloc(ctxt, t, d, c)
}
fh.NumberOfSections = uint16(pensect)
@@ -1218,8 +1215,8 @@ func Asmbpe() {
oh64.SizeOfUninitializedData = 0
oh.SizeOfUninitializedData = 0
if Linkmode != LinkExternal {
- oh64.AddressOfEntryPoint = uint32(Entryvalue() - PEBASE)
- oh.AddressOfEntryPoint = uint32(Entryvalue() - PEBASE)
+ oh64.AddressOfEntryPoint = uint32(Entryvalue(ctxt) - PEBASE)
+ oh.AddressOfEntryPoint = uint32(Entryvalue(ctxt) - PEBASE)
}
oh64.BaseOfCode = t.VirtualAddress
oh.BaseOfCode = t.VirtualAddress
@@ -1245,7 +1242,7 @@ func Asmbpe() {
oh.SizeOfImage = uint32(nextsectoff)
oh64.SizeOfHeaders = uint32(PEFILEHEADR)
oh.SizeOfHeaders = uint32(PEFILEHEADR)
- if headstring == "windowsgui" {
+ if Headtype == obj.Hwindowsgui {
oh64.Subsystem = IMAGE_SUBSYSTEM_WINDOWS_GUI
oh.Subsystem = IMAGE_SUBSYSTEM_WINDOWS_GUI
} else {
diff --git a/src/cmd/link/internal/ld/pobj.go b/src/cmd/link/internal/ld/pobj.go
deleted file mode 100644
index 7a4555f..0000000
--- a/src/cmd/link/internal/ld/pobj.go
+++ /dev/null
@@ -1,227 +0,0 @@
-// Inferno utils/6l/obj.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6l/obj.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth at terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth at terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// Portions Copyright © 2009 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-package ld
-
-import (
- "bufio"
- "cmd/internal/obj"
- "cmd/internal/sys"
- "flag"
- "fmt"
- "os"
- "strings"
-)
-
-var (
- pkglistfornote []byte
- buildid string
-)
-
-func Ldmain() {
- Bso = bufio.NewWriter(os.Stdout)
-
- Ctxt = linknew(SysArch)
- Ctxt.Diag = Diag
- Ctxt.Bso = Bso
-
- Debug = [128]int{}
- nerrors = 0
- outfile = ""
- HEADTYPE = -1
- INITTEXT = -1
- INITDAT = -1
- INITRND = -1
- INITENTRY = ""
- Linkmode = LinkAuto
-
- // For testing behavior of go command when tools crash silently.
- // Undocumented, not in standard flag parser to avoid
- // exposing in usage message.
- for _, arg := range os.Args {
- if arg == "-crash_for_testing" {
- os.Exit(2)
- }
- }
-
- if SysArch.Family == sys.AMD64 && obj.Getgoos() == "plan9" {
- obj.Flagcount("8", "use 64-bit addresses in symbol table", &Debug['8'])
- }
- obj.Flagfn1("B", "add an ELF NT_GNU_BUILD_ID `note` when using ELF", addbuildinfo)
- obj.Flagcount("C", "check Go calls to C code", &Debug['C'])
- obj.Flagint64("D", "set data segment `address`", &INITDAT)
- obj.Flagstr("E", "set `entry` symbol name", &INITENTRY)
- obj.Flagfn1("I", "use `linker` as ELF dynamic linker", setinterp)
- obj.Flagfn1("L", "add specified `directory` to library path", Lflag)
- obj.Flagfn1("H", "set header `type`", setheadtype)
- obj.Flagint32("R", "set address rounding `quantum`", &INITRND)
- obj.Flagint64("T", "set text segment `address`", &INITTEXT)
- obj.Flagfn0("V", "print version and exit", doversion)
- obj.Flagfn1("X", "add string value `definition` of the form importpath.name=value", addstrdata1)
- obj.Flagcount("a", "disassemble output", &Debug['a'])
- obj.Flagstr("buildid", "record `id` as Go toolchain build id", &buildid)
- flag.Var(&Buildmode, "buildmode", "set build `mode`")
- obj.Flagcount("c", "dump call graph", &Debug['c'])
- obj.Flagcount("d", "disable dynamic executable", &Debug['d'])
- flag.BoolVar(&flag_dumpdep, "dumpdep", false, "dump symbol dependency graph")
- obj.Flagstr("extar", "archive program for buildmode=c-archive", &extar)
- obj.Flagstr("extld", "use `linker` when linking in external mode", &extld)
- obj.Flagstr("extldflags", "pass `flags` to external linker", &extldflags)
- obj.Flagcount("f", "ignore version mismatch", &Debug['f'])
- obj.Flagcount("g", "disable go package data checks", &Debug['g'])
- obj.Flagcount("h", "halt on error", &Debug['h'])
- obj.Flagstr("installsuffix", "set package directory `suffix`", &flag_installsuffix)
- obj.Flagstr("k", "set field tracking `symbol`", &tracksym)
- obj.Flagstr("libgcc", "compiler support lib for internal linking; use \"none\" to disable", &libgccfile)
- obj.Flagfn1("linkmode", "set link `mode` (internal, external, auto)", setlinkmode)
- flag.BoolVar(&Linkshared, "linkshared", false, "link against installed Go shared libraries")
- obj.Flagcount("msan", "enable MSan interface", &flag_msan)
- obj.Flagcount("n", "dump symbol table", &Debug['n'])
- obj.Flagstr("o", "write output to `file`", &outfile)
- flag.Var(&rpath, "r", "set the ELF dynamic linker search `path` to dir1:dir2:...")
- obj.Flagcount("race", "enable race detector", &flag_race)
- obj.Flagcount("s", "disable symbol table", &Debug['s'])
- var flagShared int
- if SysArch.InFamily(sys.ARM, sys.AMD64) {
- obj.Flagcount("shared", "generate shared object (implies -linkmode external)", &flagShared)
- }
- obj.Flagstr("tmpdir", "use `directory` for temporary files", &tmpdir)
- obj.Flagcount("u", "reject unsafe packages", &Debug['u'])
- obj.Flagcount("v", "print link trace", &Debug['v'])
- obj.Flagcount("w", "disable DWARF generation", &Debug['w'])
-
- obj.Flagstr("cpuprofile", "write cpu profile to `file`", &cpuprofile)
- obj.Flagstr("memprofile", "write memory profile to `file`", &memprofile)
- obj.Flagint64("memprofilerate", "set runtime.MemProfileRate to `rate`", &memprofilerate)
-
- obj.Flagparse(usage)
-
- startProfile()
- Ctxt.Bso = Bso
- Ctxt.Debugvlog = int32(Debug['v'])
- if flagShared != 0 {
- if Buildmode == BuildmodeUnset {
- Buildmode = BuildmodeCShared
- } else if Buildmode != BuildmodeCShared {
- Exitf("-shared and -buildmode=%s are incompatible", Buildmode.String())
- }
- }
- if Buildmode == BuildmodeUnset {
- Buildmode = BuildmodeExe
- }
-
- if Buildmode != BuildmodeShared && flag.NArg() != 1 {
- usage()
- }
-
- if outfile == "" {
- outfile = "a.out"
- if HEADTYPE == obj.Hwindows {
- outfile += ".exe"
- }
- }
-
- libinit() // creates outfile
-
- if HEADTYPE == -1 {
- HEADTYPE = int32(headtype(goos))
- }
- Ctxt.Headtype = int(HEADTYPE)
- if headstring == "" {
- headstring = Headstr(int(HEADTYPE))
- }
-
- Thearch.Archinit()
-
- if Linkshared && !Iself {
- Exitf("-linkshared can only be used on elf systems")
- }
-
- if Debug['v'] != 0 {
- fmt.Fprintf(Bso, "HEADER = -H%d -T0x%x -D0x%x -R0x%x\n", HEADTYPE, uint64(INITTEXT), uint64(INITDAT), uint32(INITRND))
- }
- Bso.Flush()
-
- if Buildmode == BuildmodeShared {
- for i := 0; i < flag.NArg(); i++ {
- arg := flag.Arg(i)
- parts := strings.SplitN(arg, "=", 2)
- var pkgpath, file string
- if len(parts) == 1 {
- pkgpath, file = "main", arg
- } else {
- pkgpath, file = parts[0], parts[1]
- }
- pkglistfornote = append(pkglistfornote, pkgpath...)
- pkglistfornote = append(pkglistfornote, '\n')
- addlibpath(Ctxt, "command line", "command line", file, pkgpath, "")
- }
- } else {
- addlibpath(Ctxt, "command line", "command line", flag.Arg(0), "main", "")
- }
- loadlib()
-
- checkstrdata()
- deadcode(Ctxt)
- fieldtrack(Ctxt)
- callgraph()
-
- doelf()
- if HEADTYPE == obj.Hdarwin {
- domacho()
- }
- dostkcheck()
- if HEADTYPE == obj.Hwindows {
- dope()
- }
- addexport()
- Thearch.Gentext() // trampolines, call stubs, etc.
- textbuildid()
- textaddress()
- pclntab()
- findfunctab()
- symtab()
- dodata()
- address()
- reloc()
- Thearch.Asmb()
- undef()
- hostlink()
- archive()
- if Debug['v'] != 0 {
- fmt.Fprintf(Bso, "%5.2f cpu time\n", obj.Cputime())
- fmt.Fprintf(Bso, "%d symbols\n", len(Ctxt.Allsym))
- fmt.Fprintf(Bso, "%d liveness data\n", liveness)
- }
-
- Bso.Flush()
-
- errorexit()
-}
diff --git a/src/cmd/link/internal/ld/sym.go b/src/cmd/link/internal/ld/sym.go
index a44c8de..4908e34 100644
--- a/src/cmd/link/internal/ld/sym.go
+++ b/src/cmd/link/internal/ld/sym.go
@@ -1,6 +1,6 @@
// Derived from Inferno utils/6l/obj.c and utils/6l/span.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6l/obj.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6l/span.c
+// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/obj.c
+// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/span.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth at terzarima.net)
@@ -35,56 +35,35 @@ import (
"cmd/internal/obj"
"cmd/internal/sys"
"log"
- "strconv"
)
-var headers = []struct {
- name string
- val int
-}{
- {"darwin", obj.Hdarwin},
- {"dragonfly", obj.Hdragonfly},
- {"freebsd", obj.Hfreebsd},
- {"linux", obj.Hlinux},
- {"android", obj.Hlinux}, // must be after "linux" entry or else headstr(Hlinux) == "android"
- {"nacl", obj.Hnacl},
- {"netbsd", obj.Hnetbsd},
- {"openbsd", obj.Hopenbsd},
- {"plan9", obj.Hplan9},
- {"solaris", obj.Hsolaris},
- {"windows", obj.Hwindows},
- {"windowsgui", obj.Hwindows},
-}
-
func linknew(arch *sys.Arch) *Link {
ctxt := &Link{
- Hash: []map[string]*LSym{
- // preallocate about 2mb for hash of
- // non static symbols
- make(map[string]*LSym, 100000),
+ Syms: &Symbols{
+ hash: []map[string]*Symbol{
+ // preallocate about 2mb for hash of
+ // non static symbols
+ make(map[string]*Symbol, 100000),
+ },
+ Allsym: make([]*Symbol, 0, 100000),
},
- Allsym: make([]*LSym, 0, 100000),
- Arch: arch,
- Goroot: obj.Getgoroot(),
+ Arch: arch,
}
- p := obj.Getgoarch()
- if p != arch.Name {
- log.Fatalf("invalid goarch %s (want %s)", p, arch.Name)
+ if obj.GOARCH != arch.Name {
+ log.Fatalf("invalid obj.GOARCH %s (want %s)", obj.GOARCH, arch.Name)
}
- ctxt.Headtype = headtype(obj.Getgoos())
- if ctxt.Headtype < 0 {
- log.Fatalf("unknown goos %s", obj.Getgoos())
- }
+ return ctxt
+}
- // Record thread-local storage offset.
- // TODO(rsc): Move tlsoffset back into the linker.
- switch ctxt.Headtype {
+// computeTLSOffset records the thread-local storage offset.
+func (ctxt *Link) computeTLSOffset() {
+ switch Headtype {
default:
- log.Fatalf("unknown thread-local storage offset for %s", Headstr(ctxt.Headtype))
+ log.Fatalf("unknown thread-local storage offset for %v", Headtype)
- case obj.Hplan9, obj.Hwindows:
+ case obj.Hplan9, obj.Hwindows, obj.Hwindowsgui:
break
/*
@@ -98,7 +77,7 @@ func linknew(arch *sys.Arch) *Link {
obj.Hopenbsd,
obj.Hdragonfly,
obj.Hsolaris:
- if obj.Getgoos() == "android" {
+ if obj.GOOS == "android" {
switch ctxt.Arch.Family {
case sys.AMD64:
// Android/amd64 constant - offset from 0(FS) to our TLS slot.
@@ -152,63 +131,4 @@ func linknew(arch *sys.Arch) *Link {
}
}
- // On arm, record goarm.
- if ctxt.Arch.Family == sys.ARM {
- ctxt.Goarm = obj.Getgoarm()
- }
-
- return ctxt
-}
-
-func linknewsym(ctxt *Link, name string, v int) *LSym {
- batch := ctxt.LSymBatch
- if len(batch) == 0 {
- batch = make([]LSym, 1000)
- }
- s := &batch[0]
- ctxt.LSymBatch = batch[1:]
-
- s.Dynid = -1
- s.Plt = -1
- s.Got = -1
- s.Name = name
- s.Version = int16(v)
- ctxt.Allsym = append(ctxt.Allsym, s)
-
- return s
-}
-
-func Linklookup(ctxt *Link, name string, v int) *LSym {
- m := ctxt.Hash[v]
- s := m[name]
- if s != nil {
- return s
- }
- s = linknewsym(ctxt, name, v)
- s.Extname = s.Name
- m[name] = s
- return s
-}
-
-// read-only lookup
-func Linkrlookup(ctxt *Link, name string, v int) *LSym {
- return ctxt.Hash[v][name]
-}
-
-func Headstr(v int) string {
- for i := 0; i < len(headers); i++ {
- if v == headers[i].val {
- return headers[i].name
- }
- }
- return strconv.Itoa(v)
-}
-
-func headtype(name string) int {
- for i := 0; i < len(headers); i++ {
- if name == headers[i].name {
- return headers[i].val
- }
- }
- return -1
}
diff --git a/src/cmd/link/internal/ld/symbols.go b/src/cmd/link/internal/ld/symbols.go
new file mode 100644
index 0000000..154507d
--- /dev/null
+++ b/src/cmd/link/internal/ld/symbols.go
@@ -0,0 +1,84 @@
+// 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
+
+type Symbols struct {
+ symbolBatch []Symbol
+
+ // Symbol lookup based on name and indexed by version.
+ hash []map[string]*Symbol
+
+ Allsym []*Symbol
+}
+
+func (syms *Symbols) newsym(name string, v int) *Symbol {
+ batch := syms.symbolBatch
+ if len(batch) == 0 {
+ batch = make([]Symbol, 1000)
+ }
+ s := &batch[0]
+ syms.symbolBatch = batch[1:]
+
+ s.Dynid = -1
+ s.Plt = -1
+ s.Got = -1
+ s.Name = name
+ s.Version = int16(v)
+ syms.Allsym = append(syms.Allsym, s)
+
+ return s
+}
+
+// Look up the symbol with the given name and version, creating the
+// symbol if it is not found.
+func (syms *Symbols) Lookup(name string, v int) *Symbol {
+ m := syms.hash[v]
+ s := m[name]
+ if s != nil {
+ return s
+ }
+ s = syms.newsym(name, v)
+ s.Extname = s.Name
+ m[name] = s
+ return s
+}
+
+// Look up the symbol with the given name and version, returning nil
+// if it is not found.
+func (syms *Symbols) ROLookup(name string, v int) *Symbol {
+ return syms.hash[v][name]
+}
+
+// Allocate a new version (i.e. symbol namespace).
+func (syms *Symbols) IncVersion() int {
+ syms.hash = append(syms.hash, make(map[string]*Symbol))
+ return len(syms.hash) - 1
+}
diff --git a/src/cmd/link/internal/ld/symtab.go b/src/cmd/link/internal/ld/symtab.go
index 06d7792..98ce3ad 100644
--- a/src/cmd/link/internal/ld/symtab.go
+++ b/src/cmd/link/internal/ld/symtab.go
@@ -1,5 +1,5 @@
// Inferno utils/6l/span.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6l/span.c
+// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/span.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth at terzarima.net)
@@ -46,14 +46,6 @@ func putelfstr(s string) int {
putelfstr("")
}
- // When dynamically linking, we create LSym's by reading the names from
- // the symbol tables of the shared libraries and so the names need to
- // match exactly. Tools like DTrace will have to wait for now.
- if !DynlinkingGo() {
- // Rewrite · to . for ASCII-only tools like DTrace (sigh)
- s = strings.Replace(s, "·", ".", -1)
- }
-
off := len(Elfstrdat)
Elfstrdat = append(Elfstrdat, s...)
Elfstrdat = append(Elfstrdat, 0)
@@ -84,29 +76,31 @@ var numelfsym int = 1 // 0 is reserved
var elfbind int
-func putelfsym(x *LSym, s string, t int, addr int64, size int64, ver int, go_ *LSym) {
- var type_ int
+func putelfsym(ctxt *Link, x *Symbol, s string, t SymbolType, addr int64, go_ *Symbol) {
+ var typ int
switch t {
default:
return
- case 'T':
- type_ = STT_FUNC
+ case TextSym:
+ typ = STT_FUNC
- case 'D':
- type_ = STT_OBJECT
+ case DataSym, BSSSym:
+ typ = STT_OBJECT
- case 'B':
- type_ = STT_OBJECT
-
- case 'U':
+ case UndefinedSym:
// ElfType is only set for symbols read from Go shared libraries, but
// for other symbols it is left as STT_NOTYPE which is fine.
- type_ = int(x.ElfType)
+ typ = int(x.ElfType)
+
+ case TLSSym:
+ typ = STT_TLS
+ }
- case 't':
- type_ = STT_TLS
+ size := x.Size
+ if t == UndefinedSym {
+ size = 0
}
xo := x
@@ -119,13 +113,11 @@ func putelfsym(x *LSym, s string, t int, addr int64, size int64, ver int, go_ *L
elfshnum = SHN_UNDEF
} else {
if xo.Sect == nil {
- Ctxt.Cursym = x
- Diag("missing section in putelfsym")
+ Errorf(x, "missing section in putelfsym")
return
}
if xo.Sect.Elfsect == nil {
- Ctxt.Cursym = x
- Diag("missing ELF section in putelfsym")
+ Errorf(x, "missing ELF section in putelfsym")
return
}
elfshnum = xo.Sect.Elfsect.shnum
@@ -135,7 +127,7 @@ func putelfsym(x *LSym, s string, t int, addr int64, size int64, ver int, go_ *L
// maybe one day STB_WEAK.
bind := STB_GLOBAL
- if ver != 0 || (x.Type&obj.SHIDDEN != 0) || x.Attr.Local() {
+ if x.Version != 0 || (x.Type&obj.SHIDDEN != 0) || x.Attr.Local() {
bind = STB_LOCAL
}
@@ -144,7 +136,7 @@ func putelfsym(x *LSym, s string, t int, addr int64, size int64, ver int, go_ *L
// To avoid filling the dynamic table with lots of unnecessary symbols,
// mark all Go symbols local (not global) in the final executable.
// But when we're dynamically linking, we need all those global symbols.
- if !DynlinkingGo() && Linkmode == LinkExternal && !x.Attr.CgoExportStatic() && elfshnum != SHN_UNDEF {
+ if !ctxt.DynlinkingGo() && Linkmode == LinkExternal && !x.Attr.CgoExportStatic() && elfshnum != SHN_UNDEF {
bind = STB_LOCAL
}
@@ -155,23 +147,31 @@ func putelfsym(x *LSym, s string, t int, addr int64, size int64, ver int, go_ *L
if x.Type&obj.SHIDDEN != 0 {
other = STV_HIDDEN
}
- if (Buildmode == BuildmodePIE || DynlinkingGo()) && SysArch.Family == sys.PPC64 && type_ == STT_FUNC && x.Name != "runtime.duffzero" && x.Name != "runtime.duffcopy" {
+ if (Buildmode == BuildmodeCArchive || Buildmode == BuildmodePIE || ctxt.DynlinkingGo()) && SysArch.Family == sys.PPC64 && typ == STT_FUNC && x.Name != "runtime.duffzero" && x.Name != "runtime.duffcopy" {
// On ppc64 the top three bits of the st_other field indicate how
// many instructions separate the global and local entry points. In
// our case it is two instructions, indicated by the value 3.
other |= 3 << 5
}
- if DynlinkingGo() && bind == STB_GLOBAL && elfbind == STB_LOCAL && x.Type == obj.STEXT {
+ // When dynamically linking, we create Symbols by reading the names from
+ // the symbol tables of the shared libraries and so the names need to
+ // match exactly. Tools like DTrace will have to wait for now.
+ if !ctxt.DynlinkingGo() {
+ // Rewrite · to . for ASCII-only tools like DTrace (sigh)
+ s = strings.Replace(s, "·", ".", -1)
+ }
+
+ if ctxt.DynlinkingGo() && bind == STB_GLOBAL && elfbind == STB_LOCAL && x.Type == obj.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
// global function symbol and making all relocations against the
// global symbol refer to this local symbol instead (see
- // (*LSym).ElfsymForReloc). This is approximately equivalent to the
+ // (*Symbol).ElfsymForReloc). This is approximately equivalent to the
// ELF linker -Bsymbolic-functions option, but that is buggy on
// several platforms.
- putelfsyment(putelfstr("local."+s), addr, size, STB_LOCAL<<4|type_&0xf, elfshnum, other)
+ putelfsyment(putelfstr("local."+s), addr, size, STB_LOCAL<<4|typ&0xf, elfshnum, other)
x.LocalElfsym = int32(numelfsym)
numelfsym++
return
@@ -179,22 +179,22 @@ func putelfsym(x *LSym, s string, t int, addr int64, size int64, ver int, go_ *L
return
}
- putelfsyment(putelfstr(s), addr, size, bind<<4|type_&0xf, elfshnum, other)
+ putelfsyment(putelfstr(s), addr, size, bind<<4|typ&0xf, elfshnum, other)
x.Elfsym = int32(numelfsym)
numelfsym++
}
-func putelfsectionsym(s *LSym, shndx int) {
+func putelfsectionsym(s *Symbol, shndx int) {
putelfsyment(0, 0, 0, STB_LOCAL<<4|STT_SECTION, shndx, 0)
s.Elfsym = int32(numelfsym)
numelfsym++
}
-func Asmelfsym() {
+func Asmelfsym(ctxt *Link) {
// the first symbol entry is reserved
putelfsyment(0, 0, 0, STB_LOCAL<<4|STT_NOTYPE, 0, 0)
- dwarfaddelfsectionsyms()
+ dwarfaddelfsectionsyms(ctxt)
// Some linkers will add a FILE sym if one is not present.
// Avoid having the working directory inserted into the symbol table.
@@ -204,29 +204,25 @@ func Asmelfsym() {
numelfsym++
elfbind = STB_LOCAL
- genasmsym(putelfsym)
+ genasmsym(ctxt, putelfsym)
elfbind = STB_GLOBAL
elfglobalsymndx = numelfsym
- genasmsym(putelfsym)
+ genasmsym(ctxt, putelfsym)
}
-func putplan9sym(x *LSym, s string, t int, addr int64, size int64, ver int, go_ *LSym) {
- switch t {
- case 'T', 'L', 'D', 'B':
- if ver != 0 {
+func putplan9sym(ctxt *Link, x *Symbol, s string, typ SymbolType, addr int64, go_ *Symbol) {
+ t := int(typ)
+ switch typ {
+ case TextSym, DataSym, BSSSym:
+ if x.Version != 0 {
t += 'a' - 'A'
}
fallthrough
- case 'a',
- 'p',
- 'f',
- 'z',
- 'Z',
- 'm':
+ case AutoSym, ParamSym, FileSym, FrameSym:
l := 4
- if HEADTYPE == obj.Hplan9 && SysArch.Family == sys.AMD64 && Debug['8'] == 0 {
+ if Headtype == obj.Hplan9 && SysArch.Family == sys.AMD64 && !Flag8 {
Lputb(uint32(addr >> 32))
l = 8
}
@@ -235,26 +231,15 @@ func putplan9sym(x *LSym, s string, t int, addr int64, size int64, ver int, go_
Cput(uint8(t + 0x80)) /* 0x80 is variable length */
var i int
- if t == 'z' || t == 'Z' {
- Cput(s[0])
- for i = 1; s[i] != 0 || s[i+1] != 0; i += 2 {
- Cput(s[i])
- Cput(s[i+1])
- }
- Cput(0)
- Cput(0)
- i++
- } else {
- /* skip the '<' in filenames */
- if t == 'f' {
- s = s[1:]
- }
- for i = 0; i < len(s); i++ {
- Cput(s[i])
- }
- Cput(0)
+ /* skip the '<' in filenames */
+ if t == FileSym {
+ s = s[1:]
}
+ for i = 0; i < len(s); i++ {
+ Cput(s[i])
+ }
+ Cput(0)
Symsize += int32(l) + 1 + int32(i) + 1
@@ -263,11 +248,13 @@ func putplan9sym(x *LSym, s string, t int, addr int64, size int64, ver int, go_
}
}
-func Asmplan9sym() {
- genasmsym(putplan9sym)
+func Asmplan9sym(ctxt *Link) {
+ genasmsym(ctxt, putplan9sym)
}
-var symt *LSym
+var symt *Symbol
+
+var encbuf [10]byte
func Wputb(w uint16) { Cwrite(Append16b(encbuf[:0], w)) }
func Lputb(l uint32) { Cwrite(Append32b(encbuf[:0], l)) }
@@ -315,67 +302,121 @@ func (libs byPkg) Swap(a, b int) {
libs[a], libs[b] = libs[b], libs[a]
}
-func symtab() {
- dosymtype()
+// Create a table with information on the text sections.
+
+func textsectionmap(ctxt *Link) uint32 {
+
+ t := ctxt.Syms.Lookup("runtime.textsectionmap", 0)
+ t.Type = obj.SRODATA
+ t.Attr |= AttrReachable
+ nsections := int64(0)
+
+ for sect := Segtext.Sect; sect != nil; sect = sect.Next {
+ if sect.Name == ".text" {
+ nsections++
+ } else {
+ break
+ }
+ }
+ Symgrow(t, nsections*(2*int64(SysArch.IntSize)+int64(SysArch.PtrSize)))
+
+ off := int64(0)
+ n := 0
+
+ // The vaddr for each text section is the difference between the section's
+ // Vaddr and the Vaddr for the first text section as determined at compile
+ // time.
+
+ // The symbol for the first text section is named runtime.text as before.
+ // Additional text sections are named runtime.text.n where n is the
+ // 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 {
+ 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))
+ if n == 0 {
+ s := ctxt.Syms.ROLookup("runtime.text", 0)
+ if s == nil {
+ Errorf(nil, "Unable to find symbol runtime.text\n")
+ }
+ off = setaddr(ctxt, t, off, s)
+
+ } else {
+ s := ctxt.Syms.Lookup(fmt.Sprintf("runtime.text.%d", n), 0)
+ if s == nil {
+ Errorf(nil, "Unable to find symbol runtime.text.%d\n", n)
+ }
+ off = setaddr(ctxt, t, off, s)
+ }
+ n++
+ }
+ return uint32(n)
+}
+
+func (ctxt *Link) symtab() {
+ dosymtype(ctxt)
// Define these so that they'll get put into the symbol table.
// data.c:/^address will provide the actual values.
- xdefine("runtime.text", obj.STEXT, 0)
-
- xdefine("runtime.etext", obj.STEXT, 0)
- xdefine("runtime.typelink", obj.SRODATA, 0)
- xdefine("runtime.etypelink", obj.SRODATA, 0)
- xdefine("runtime.itablink", obj.SRODATA, 0)
- xdefine("runtime.eitablink", obj.SRODATA, 0)
- xdefine("runtime.rodata", obj.SRODATA, 0)
- xdefine("runtime.erodata", obj.SRODATA, 0)
- xdefine("runtime.types", obj.SRODATA, 0)
- xdefine("runtime.etypes", obj.SRODATA, 0)
- xdefine("runtime.noptrdata", obj.SNOPTRDATA, 0)
- xdefine("runtime.enoptrdata", obj.SNOPTRDATA, 0)
- xdefine("runtime.data", obj.SDATA, 0)
- xdefine("runtime.edata", obj.SDATA, 0)
- xdefine("runtime.bss", obj.SBSS, 0)
- xdefine("runtime.ebss", obj.SBSS, 0)
- xdefine("runtime.noptrbss", obj.SNOPTRBSS, 0)
- xdefine("runtime.enoptrbss", obj.SNOPTRBSS, 0)
- xdefine("runtime.end", obj.SBSS, 0)
- xdefine("runtime.epclntab", obj.SRODATA, 0)
- xdefine("runtime.esymtab", obj.SRODATA, 0)
+ 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)
// garbage collection symbols
- s := Linklookup(Ctxt, "runtime.gcdata", 0)
+ s := ctxt.Syms.Lookup("runtime.gcdata", 0)
s.Type = obj.SRODATA
s.Size = 0
s.Attr |= AttrReachable
- xdefine("runtime.egcdata", obj.SRODATA, 0)
+ ctxt.xdefine("runtime.egcdata", obj.SRODATA, 0)
- s = Linklookup(Ctxt, "runtime.gcbss", 0)
+ s = ctxt.Syms.Lookup("runtime.gcbss", 0)
s.Type = obj.SRODATA
s.Size = 0
s.Attr |= AttrReachable
- xdefine("runtime.egcbss", obj.SRODATA, 0)
+ ctxt.xdefine("runtime.egcbss", obj.SRODATA, 0)
// pseudo-symbols to mark locations of type, string, and go string data.
- var symtype *LSym
- var symtyperel *LSym
- if UseRelro() && (Buildmode == BuildmodeCShared || Buildmode == BuildmodePIE) {
- s = Linklookup(Ctxt, "type.*", 0)
+ var symtype *Symbol
+ var symtyperel *Symbol
+ if UseRelro() && (Buildmode == BuildmodeCArchive || Buildmode == BuildmodeCShared || Buildmode == BuildmodePIE) {
+ s = ctxt.Syms.Lookup("type.*", 0)
s.Type = obj.STYPE
s.Size = 0
s.Attr |= AttrReachable
symtype = s
- s = Linklookup(Ctxt, "typerel.*", 0)
+ s = ctxt.Syms.Lookup("typerel.*", 0)
s.Type = obj.STYPERELRO
s.Size = 0
s.Attr |= AttrReachable
symtyperel = s
- } else if !DynlinkingGo() {
- s = Linklookup(Ctxt, "type.*", 0)
+ } else if !ctxt.DynlinkingGo() {
+ s = ctxt.Syms.Lookup("type.*", 0)
s.Type = obj.STYPE
s.Size = 0
@@ -384,47 +425,51 @@ func symtab() {
symtyperel = s
}
- groupSym := func(name string, t int16) *LSym {
- s := Linklookup(Ctxt, name, 0)
+ groupSym := func(name string, t obj.SymKind) *Symbol {
+ s := ctxt.Syms.Lookup(name, 0)
s.Type = t
s.Size = 0
s.Attr |= AttrLocal | AttrReachable
return s
}
var (
- symgostring = groupSym("go.string.*", obj.SGOSTRING)
- symgostringhdr = groupSym("go.string.hdr.*", obj.SGOSTRINGHDR)
- symgofunc = groupSym("go.func.*", obj.SGOFUNC)
- symgcbits = groupSym("runtime.gcbits.*", obj.SGCBITS)
+ symgostring = groupSym("go.string.*", obj.SGOSTRING)
+ symgofunc = groupSym("go.func.*", obj.SGOFUNC)
+ symgcbits = groupSym("runtime.gcbits.*", obj.SGCBITS)
)
- symtypelink := Linklookup(Ctxt, "runtime.typelink", 0)
- symtypelink.Type = obj.STYPELINK
+ var symgofuncrel *Symbol
+ if !ctxt.DynlinkingGo() {
+ if UseRelro() {
+ symgofuncrel = groupSym("go.funcrel.*", obj.SGOFUNCRELRO)
+ } else {
+ symgofuncrel = symgofunc
+ }
+ }
- symitablink := Linklookup(Ctxt, "runtime.itablink", 0)
+ symitablink := ctxt.Syms.Lookup("runtime.itablink", 0)
symitablink.Type = obj.SITABLINK
- symt = Linklookup(Ctxt, "runtime.symtab", 0)
+ symt = ctxt.Syms.Lookup("runtime.symtab", 0)
symt.Attr |= AttrLocal
symt.Type = obj.SSYMTAB
symt.Size = 0
symt.Attr |= AttrReachable
- ntypelinks := 0
nitablinks := 0
// assign specific types so that they sort together.
// within a type they sort by size, so the .* symbols
// just defined above will be first.
// hide the specific symbols.
- for _, s := range Ctxt.Allsym {
+ for _, s := range ctxt.Syms.Allsym {
if !s.Attr.Reachable() || s.Attr.Special() || s.Type != obj.SRODATA {
continue
}
switch {
case strings.HasPrefix(s.Name, "type."):
- if !DynlinkingGo() {
+ if !ctxt.DynlinkingGo() {
s.Attr |= AttrHidden
}
if UseRelro() {
@@ -440,12 +485,6 @@ func symtab() {
// names, as they can be referred to by a section offset.
s.Type = obj.STYPERELRO
- case strings.HasPrefix(s.Name, "go.typelink."):
- ntypelinks++
- s.Type = obj.STYPELINK
- s.Attr |= AttrHidden
- s.Outer = symtypelink
-
case strings.HasPrefix(s.Name, "go.itablink."):
nitablinks++
s.Type = obj.SITABLINK
@@ -456,20 +495,23 @@ func symtab() {
s.Type = obj.SGOSTRING
s.Attr |= AttrHidden
s.Outer = symgostring
- if strings.HasPrefix(s.Name, "go.string.hdr.") {
- s.Type = obj.SGOSTRINGHDR
- s.Outer = symgostringhdr
- }
case strings.HasPrefix(s.Name, "runtime.gcbits."):
s.Type = obj.SGCBITS
s.Attr |= AttrHidden
s.Outer = symgcbits
- case strings.HasPrefix(s.Name, "go.func."):
- s.Type = obj.SGOFUNC
- s.Attr |= AttrHidden
- s.Outer = symgofunc
+ case strings.HasSuffix(s.Name, "·f"):
+ if !ctxt.DynlinkingGo() {
+ s.Attr |= AttrHidden
+ }
+ if UseRelro() {
+ s.Type = obj.SGOFUNCRELRO
+ s.Outer = symgofuncrel
+ } else {
+ s.Type = obj.SGOFUNC
+ s.Outer = symgofunc
+ }
case strings.HasPrefix(s.Name, "gcargs."), strings.HasPrefix(s.Name, "gclocals."), strings.HasPrefix(s.Name, "gclocals·"):
s.Type = obj.SGOFUNC
@@ -481,106 +523,172 @@ func symtab() {
}
if Buildmode == BuildmodeShared {
- abihashgostr := Linklookup(Ctxt, "go.link.abihash."+filepath.Base(outfile), 0)
+ abihashgostr := ctxt.Syms.Lookup("go.link.abihash."+filepath.Base(*flagOutfile), 0)
abihashgostr.Attr |= AttrReachable
abihashgostr.Type = obj.SRODATA
- hashsym := Linklookup(Ctxt, "go.link.abihashbytes", 0)
- Addaddr(Ctxt, abihashgostr, hashsym)
- adduint(Ctxt, abihashgostr, uint64(hashsym.Size))
+ hashsym := ctxt.Syms.Lookup("go.link.abihashbytes", 0)
+ Addaddr(ctxt, abihashgostr, hashsym)
+ adduint(ctxt, abihashgostr, uint64(hashsym.Size))
+ }
+ if Buildmode == BuildmodePlugin || ctxt.Syms.ROLookup("plugin.Open", 0) != nil {
+ for _, l := range ctxt.Library {
+ s := ctxt.Syms.Lookup("go.link.pkghashbytes."+l.Pkg, 0)
+ s.Attr |= AttrReachable
+ s.Type = obj.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
+ Addaddr(ctxt, str, s)
+ adduint(ctxt, str, uint64(len(l.hash)))
+ }
}
+ nsections := textsectionmap(ctxt)
+
// Information about the layout of the executable image for the
// runtime to use. Any changes here must be matched by changes to
// the definition of moduledata in runtime/symtab.go.
// This code uses several global variables that are set by pcln.go:pclntab.
- moduledata := Ctxt.Moduledata
+ moduledata := ctxt.Moduledata
// The pclntab slice
- Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.pclntab", 0))
- adduint(Ctxt, moduledata, uint64(Linklookup(Ctxt, "runtime.pclntab", 0).Size))
- adduint(Ctxt, moduledata, uint64(Linklookup(Ctxt, "runtime.pclntab", 0).Size))
+ Addaddr(ctxt, moduledata, ctxt.Syms.Lookup("runtime.pclntab", 0))
+ adduint(ctxt, moduledata, uint64(ctxt.Syms.Lookup("runtime.pclntab", 0).Size))
+ adduint(ctxt, moduledata, uint64(ctxt.Syms.Lookup("runtime.pclntab", 0).Size))
// The ftab slice
- Addaddrplus(Ctxt, moduledata, Linklookup(Ctxt, "runtime.pclntab", 0), int64(pclntabPclntabOffset))
- adduint(Ctxt, moduledata, uint64(pclntabNfunc+1))
- adduint(Ctxt, moduledata, uint64(pclntabNfunc+1))
+ Addaddrplus(ctxt, moduledata, ctxt.Syms.Lookup("runtime.pclntab", 0), int64(pclntabPclntabOffset))
+ adduint(ctxt, moduledata, uint64(pclntabNfunc+1))
+ adduint(ctxt, moduledata, uint64(pclntabNfunc+1))
// The filetab slice
- Addaddrplus(Ctxt, moduledata, Linklookup(Ctxt, "runtime.pclntab", 0), int64(pclntabFiletabOffset))
- adduint(Ctxt, moduledata, uint64(len(Ctxt.Filesyms))+1)
- adduint(Ctxt, moduledata, uint64(len(Ctxt.Filesyms))+1)
+ Addaddrplus(ctxt, moduledata, ctxt.Syms.Lookup("runtime.pclntab", 0), int64(pclntabFiletabOffset))
+ adduint(ctxt, moduledata, uint64(len(ctxt.Filesyms))+1)
+ adduint(ctxt, moduledata, uint64(len(ctxt.Filesyms))+1)
// findfunctab
- Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.findfunctab", 0))
+ Addaddr(ctxt, moduledata, ctxt.Syms.Lookup("runtime.findfunctab", 0))
// minpc, maxpc
- Addaddr(Ctxt, moduledata, pclntabFirstFunc)
- Addaddrplus(Ctxt, moduledata, pclntabLastFunc, pclntabLastFunc.Size)
+ Addaddr(ctxt, moduledata, pclntabFirstFunc)
+ Addaddrplus(ctxt, moduledata, pclntabLastFunc, pclntabLastFunc.Size)
// pointers to specific parts of the module
- Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.text", 0))
- Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.etext", 0))
- Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.noptrdata", 0))
- Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.enoptrdata", 0))
- Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.data", 0))
- Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.edata", 0))
- Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.bss", 0))
- Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.ebss", 0))
- Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.noptrbss", 0))
- Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.enoptrbss", 0))
- Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.end", 0))
- Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.gcdata", 0))
- Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.gcbss", 0))
- Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.types", 0))
- Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.etypes", 0))
+ Addaddr(ctxt, moduledata, ctxt.Syms.Lookup("runtime.text", 0))
+ Addaddr(ctxt, moduledata, ctxt.Syms.Lookup("runtime.etext", 0))
+ Addaddr(ctxt, moduledata, ctxt.Syms.Lookup("runtime.noptrdata", 0))
+ Addaddr(ctxt, moduledata, ctxt.Syms.Lookup("runtime.enoptrdata", 0))
+ Addaddr(ctxt, moduledata, ctxt.Syms.Lookup("runtime.data", 0))
+ Addaddr(ctxt, moduledata, ctxt.Syms.Lookup("runtime.edata", 0))
+ Addaddr(ctxt, moduledata, ctxt.Syms.Lookup("runtime.bss", 0))
+ Addaddr(ctxt, moduledata, ctxt.Syms.Lookup("runtime.ebss", 0))
+ Addaddr(ctxt, moduledata, ctxt.Syms.Lookup("runtime.noptrbss", 0))
+ Addaddr(ctxt, moduledata, ctxt.Syms.Lookup("runtime.enoptrbss", 0))
+ Addaddr(ctxt, moduledata, ctxt.Syms.Lookup("runtime.end", 0))
+ Addaddr(ctxt, moduledata, ctxt.Syms.Lookup("runtime.gcdata", 0))
+ Addaddr(ctxt, moduledata, ctxt.Syms.Lookup("runtime.gcbss", 0))
+ Addaddr(ctxt, moduledata, ctxt.Syms.Lookup("runtime.types", 0))
+ Addaddr(ctxt, moduledata, ctxt.Syms.Lookup("runtime.etypes", 0))
+
+ // text section information
+ Addaddr(ctxt, moduledata, ctxt.Syms.Lookup("runtime.textsectionmap", 0))
+ adduint(ctxt, moduledata, uint64(nsections))
+ adduint(ctxt, moduledata, uint64(nsections))
+
// The typelinks slice
- Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.typelink", 0))
- adduint(Ctxt, moduledata, uint64(ntypelinks))
- adduint(Ctxt, moduledata, uint64(ntypelinks))
+ typelinkSym := ctxt.Syms.Lookup("runtime.typelink", 0)
+ ntypelinks := uint64(typelinkSym.Size) / 4
+ Addaddr(ctxt, moduledata, typelinkSym)
+ adduint(ctxt, moduledata, ntypelinks)
+ adduint(ctxt, moduledata, ntypelinks)
// The itablinks slice
- Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.itablink", 0))
- adduint(Ctxt, moduledata, uint64(nitablinks))
- adduint(Ctxt, moduledata, uint64(nitablinks))
- if len(Ctxt.Shlibs) > 0 {
- thismodulename := filepath.Base(outfile)
+ Addaddr(ctxt, moduledata, ctxt.Syms.Lookup("runtime.itablink", 0))
+ adduint(ctxt, moduledata, uint64(nitablinks))
+ adduint(ctxt, moduledata, uint64(nitablinks))
+ // The ptab slice
+ if ptab := ctxt.Syms.ROLookup("go.plugin.tabs", 0); ptab != nil {
+ ptab.Attr |= AttrReachable
+ ptab.Attr |= AttrLocal
+ ptab.Type = obj.SRODATA
+
+ nentries := uint64(len(ptab.P) / 8) // sizeof(nameOff) + sizeof(typeOff)
+ Addaddr(ctxt, moduledata, ptab)
+ adduint(ctxt, moduledata, nentries)
+ adduint(ctxt, moduledata, nentries)
+ } else {
+ adduint(ctxt, moduledata, 0)
+ adduint(ctxt, moduledata, 0)
+ adduint(ctxt, moduledata, 0)
+ }
+ if Buildmode == BuildmodePlugin {
+ addgostring(ctxt, moduledata, "go.link.thispluginpath", *flagPluginPath)
+
+ pkghashes := ctxt.Syms.Lookup("go.link.pkghashes", 0)
+ pkghashes.Attr |= AttrReachable
+ pkghashes.Attr |= AttrLocal
+ pkghashes.Type = obj.SRODATA
+
+ for i, l := range ctxt.Library {
+ // pkghashes[i].name
+ addgostring(ctxt, pkghashes, fmt.Sprintf("go.link.pkgname.%d", i), l.Pkg)
+ // pkghashes[i].linktimehash
+ addgostring(ctxt, pkghashes, fmt.Sprintf("go.link.pkglinkhash.%d", i), string(l.hash))
+ // pkghashes[i].runtimehash
+ hash := ctxt.Syms.ROLookup("go.link.pkghash."+l.Pkg, 0)
+ Addaddr(ctxt, pkghashes, hash)
+ }
+ Addaddr(ctxt, moduledata, pkghashes)
+ adduint(ctxt, moduledata, uint64(len(ctxt.Library)))
+ adduint(ctxt, moduledata, uint64(len(ctxt.Library)))
+ } else {
+ adduint(ctxt, moduledata, 0) // pluginpath
+ adduint(ctxt, moduledata, 0)
+ adduint(ctxt, moduledata, 0) // pkghashes slice
+ adduint(ctxt, moduledata, 0)
+ adduint(ctxt, moduledata, 0)
+ }
+ if len(ctxt.Shlibs) > 0 {
+ thismodulename := filepath.Base(*flagOutfile)
switch Buildmode {
case BuildmodeExe, BuildmodePIE:
// When linking an executable, outfile is just "a.out". Make
// it something slightly more comprehensible.
thismodulename = "the executable"
}
- addgostring(moduledata, "go.link.thismodulename", thismodulename)
+ addgostring(ctxt, moduledata, "go.link.thismodulename", thismodulename)
- modulehashes := Linklookup(Ctxt, "go.link.abihashes", 0)
+ modulehashes := ctxt.Syms.Lookup("go.link.abihashes", 0)
modulehashes.Attr |= AttrReachable
modulehashes.Attr |= AttrLocal
modulehashes.Type = obj.SRODATA
- for i, shlib := range Ctxt.Shlibs {
+ for i, shlib := range ctxt.Shlibs {
// modulehashes[i].modulename
modulename := filepath.Base(shlib.Path)
- addgostring(modulehashes, fmt.Sprintf("go.link.libname.%d", i), modulename)
+ addgostring(ctxt, modulehashes, fmt.Sprintf("go.link.libname.%d", i), modulename)
// modulehashes[i].linktimehash
- addgostring(modulehashes, fmt.Sprintf("go.link.linkhash.%d", i), string(shlib.Hash))
+ addgostring(ctxt, modulehashes, fmt.Sprintf("go.link.linkhash.%d", i), string(shlib.Hash))
// modulehashes[i].runtimehash
- abihash := Linklookup(Ctxt, "go.link.abihash."+modulename, 0)
+ abihash := ctxt.Syms.Lookup("go.link.abihash."+modulename, 0)
abihash.Attr |= AttrReachable
- Addaddr(Ctxt, modulehashes, abihash)
+ Addaddr(ctxt, modulehashes, abihash)
}
- Addaddr(Ctxt, moduledata, modulehashes)
- adduint(Ctxt, moduledata, uint64(len(Ctxt.Shlibs)))
- adduint(Ctxt, moduledata, uint64(len(Ctxt.Shlibs)))
+ Addaddr(ctxt, moduledata, modulehashes)
+ adduint(ctxt, moduledata, uint64(len(ctxt.Shlibs)))
+ adduint(ctxt, moduledata, uint64(len(ctxt.Shlibs)))
}
// The rest of moduledata is zero initialized.
// When linking an object that does not contain the runtime we are
// creating the moduledata from scratch and it does not have a
// compiler-provided size, so read it from the type data.
- moduledatatype := Linkrlookup(Ctxt, "type.runtime.moduledata", 0)
- moduledata.Size = decodetype_size(moduledatatype)
- Symgrow(Ctxt, moduledata, moduledata.Size)
+ moduledatatype := ctxt.Syms.ROLookup("type.runtime.moduledata", 0)
+ moduledata.Size = decodetypeSize(ctxt.Arch, moduledatatype)
+ Symgrow(moduledata, moduledata.Size)
- lastmoduledatap := Linklookup(Ctxt, "runtime.lastmoduledatap", 0)
+ lastmoduledatap := ctxt.Syms.Lookup("runtime.lastmoduledatap", 0)
if lastmoduledatap.Type != obj.SDYNIMPORT {
lastmoduledatap.Type = obj.SNOPTRDATA
lastmoduledatap.Size = 0 // overwrite existing value
- Addaddr(Ctxt, lastmoduledatap, moduledata)
+ Addaddr(ctxt, lastmoduledatap, moduledata)
}
}
diff --git a/src/cmd/link/internal/ld/typelink.go b/src/cmd/link/internal/ld/typelink.go
new file mode 100644
index 0000000..48a1104
--- /dev/null
+++ b/src/cmd/link/internal/ld/typelink.go
@@ -0,0 +1,49 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ld
+
+import (
+ "sort"
+
+ "cmd/internal/obj"
+)
+
+type byTypeStr []typelinkSortKey
+
+type typelinkSortKey struct {
+ TypeStr string
+ Type *Symbol
+}
+
+func (s byTypeStr) Less(i, j int) bool { return s[i].TypeStr < s[j].TypeStr }
+func (s byTypeStr) Len() int { return len(s) }
+func (s byTypeStr) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
+
+// typelink generates the typelink table which is used by reflect.typelinks().
+// Types that should be added to the typelinks table are marked with the
+// MakeTypelink attribute by the compiler.
+func (ctxt *Link) typelink() {
+ typelinks := byTypeStr{}
+ for _, s := range ctxt.Syms.Allsym {
+ if s.Attr.Reachable() && s.Attr.MakeTypelink() {
+ typelinks = append(typelinks, typelinkSortKey{decodetypeStr(s), s})
+ }
+ }
+ sort.Sort(typelinks)
+
+ tl := ctxt.Syms.Lookup("runtime.typelink", 0)
+ tl.Type = obj.STYPELINK
+ tl.Attr |= AttrReachable | AttrLocal
+ tl.Size = int64(4 * len(typelinks))
+ tl.P = make([]byte, tl.Size)
+ tl.R = make([]Reloc, len(typelinks))
+ for i, s := range typelinks {
+ r := &tl.R[i]
+ r.Sym = s.Type
+ r.Off = int32(i * 4)
+ r.Siz = 4
+ r.Type = obj.R_ADDROFF
+ }
+}
diff --git a/src/cmd/link/internal/ld/util.go b/src/cmd/link/internal/ld/util.go
index 19b3688..925aab6 100644
--- a/src/cmd/link/internal/ld/util.go
+++ b/src/cmd/link/internal/ld/util.go
@@ -7,10 +7,8 @@ package ld
import (
"bytes"
"encoding/binary"
- "log"
+ "fmt"
"os"
- "runtime"
- "runtime/pprof"
"strings"
"time"
)
@@ -73,46 +71,42 @@ func AtExit(f func()) {
atExitFuncs = append(atExitFuncs, f)
}
+// Exit exits with code after executing all atExitFuncs.
func Exit(code int) {
for i := len(atExitFuncs) - 1; i >= 0; i-- {
- f := atExitFuncs[i]
- atExitFuncs = atExitFuncs[:i]
- f()
+ atExitFuncs[i]()
}
os.Exit(code)
}
-var (
- cpuprofile string
- memprofile string
- memprofilerate int64
-)
+// Exitf logs an error message then calls Exit(2).
+func Exitf(format string, a ...interface{}) {
+ fmt.Fprintf(os.Stderr, os.Args[0]+": "+format+"\n", a...)
+ if coutbuf.f != nil {
+ coutbuf.f.Close()
+ mayberemoveoutfile()
+ }
+ Exit(2)
+}
-func startProfile() {
- if cpuprofile != "" {
- f, err := os.Create(cpuprofile)
- if err != nil {
- log.Fatalf("%v", err)
- }
- if err := pprof.StartCPUProfile(f); err != nil {
- log.Fatalf("%v", err)
- }
- AtExit(pprof.StopCPUProfile)
+// Errorf logs an error message.
+//
+// If more than 20 errors have been printed, exit with an error.
+//
+// Logging an error means that on exit cmd/link will delete any
+// output file and return a non-zero error code.
+func Errorf(s *Symbol, format string, args ...interface{}) {
+ if s != nil {
+ format = s.Name + ": " + format
}
- if memprofile != "" {
- if memprofilerate != 0 {
- runtime.MemProfileRate = int(memprofilerate)
- }
- f, err := os.Create(memprofile)
- if err != nil {
- log.Fatalf("%v", err)
- }
- AtExit(func() {
- runtime.GC() // profile all outstanding allocations
- if err := pprof.WriteHeapProfile(f); err != nil {
- log.Fatalf("%v", err)
- }
- })
+ format += "\n"
+ fmt.Fprintf(os.Stderr, format, args...)
+ nerrors++
+ if *flagH {
+ panic("error")
+ }
+ if nerrors > 20 {
+ Exitf("too many errors")
}
}
diff --git a/src/cmd/link/internal/mips/asm.go b/src/cmd/link/internal/mips/asm.go
new file mode 100644
index 0000000..b2c7289
--- /dev/null
+++ b/src/cmd/link/internal/mips/asm.go
@@ -0,0 +1,191 @@
+// Inferno utils/5l/asm.c
+// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5l/asm.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth at terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth at terzarima.net)
+// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+// Portions Copyright © 2016 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION 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 mips
+
+import (
+ "cmd/internal/obj"
+ "cmd/link/internal/ld"
+ "fmt"
+ "log"
+)
+
+func gentext(ctxt *ld.Link) {
+ return
+}
+
+func adddynrel(ctxt *ld.Link, s *ld.Symbol, r *ld.Reloc) bool {
+ log.Fatalf("adddynrel not implemented")
+ return false
+}
+
+func elfreloc1(ctxt *ld.Link, r *ld.Reloc, sectoff int64) int {
+ return -1
+}
+
+func elfsetupplt(ctxt *ld.Link) {
+ return
+}
+
+func machoreloc1(s *ld.Symbol, r *ld.Reloc, sectoff int64) int {
+ return -1
+}
+
+func archreloc(ctxt *ld.Link, r *ld.Reloc, s *ld.Symbol, val *int64) int {
+ if ld.Linkmode == ld.LinkExternal {
+ return -1
+ }
+
+ switch r.Type {
+ case obj.R_CONST:
+ *val = r.Add
+ return 0
+
+ case obj.R_GOTOFF:
+ *val = ld.Symaddr(r.Sym) + r.Add - ld.Symaddr(ctxt.Syms.Lookup(".got", 0))
+ return 0
+
+ case obj.R_ADDRMIPS,
+ obj.R_ADDRMIPSU:
+ t := ld.Symaddr(r.Sym) + r.Add
+ o1 := ld.SysArch.ByteOrder.Uint32(s.P[r.Off:])
+ if r.Type == obj.R_ADDRMIPS {
+ *val = int64(o1&0xffff0000 | uint32(t)&0xffff)
+ } else {
+ *val = int64(o1&0xffff0000 | uint32((t+1<<15)>>16)&0xffff)
+ }
+ return 0
+
+ case obj.R_CALLMIPS,
+ obj.R_JMPMIPS:
+ // Low 26 bits = (S + A) >> 2
+ t := ld.Symaddr(r.Sym) + r.Add
+ o1 := ld.SysArch.ByteOrder.Uint32(s.P[r.Off:])
+ *val = int64(o1&0xfc000000 | uint32(t>>2)&^0xfc000000)
+ return 0
+ }
+
+ return -1
+}
+
+func archrelocvariant(ctxt *ld.Link, r *ld.Reloc, s *ld.Symbol, t int64) int64 {
+ return -1
+}
+
+func asmb(ctxt *ld.Link) {
+ if ctxt.Debugvlog != 0 {
+ ctxt.Logf("%5.2f asmb\n", obj.Cputime())
+ }
+
+ if ld.Iself {
+ ld.Asmbelfsetup()
+ }
+
+ sect := ld.Segtext.Sect
+ 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 {
+ 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())
+ }
+
+ ld.Cseek(int64(ld.Segrodata.Fileoff))
+ ld.Datblk(ctxt, int64(ld.Segrodata.Vaddr), int64(ld.Segrodata.Filelen))
+ }
+
+ if ctxt.Debugvlog != 0 {
+ ctxt.Logf("%5.2f datblk\n", obj.Cputime())
+ }
+
+ ld.Cseek(int64(ld.Segdata.Fileoff))
+ ld.Datblk(ctxt, int64(ld.Segdata.Vaddr), int64(ld.Segdata.Filelen))
+
+ ld.Cseek(int64(ld.Segdwarf.Fileoff))
+ ld.Dwarfblk(ctxt, int64(ld.Segdwarf.Vaddr), int64(ld.Segdwarf.Filelen))
+
+ /* output symbol table */
+ ld.Symsize = 0
+
+ ld.Lcsize = 0
+ symo := uint32(0)
+ if !*ld.FlagS {
+ if !ld.Iself {
+ ld.Errorf(nil, "unsupported executable format")
+ }
+ if ctxt.Debugvlog != 0 {
+ ctxt.Logf("%5.2f sym\n", obj.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())
+ }
+ ld.Asmelfsym(ctxt)
+ ld.Cflush()
+ ld.Cwrite(ld.Elfstrdat)
+
+ if ctxt.Debugvlog != 0 {
+ ctxt.Logf("%5.2f dwarf\n", obj.Cputime())
+ }
+
+ if ld.Linkmode == ld.LinkExternal {
+ ld.Elfemitreloc(ctxt)
+ }
+ }
+
+ if ctxt.Debugvlog != 0 {
+ ctxt.Logf("%5.2f header\n", obj.Cputime())
+ }
+
+ ld.Cseek(0)
+ switch ld.Headtype {
+ default:
+ ld.Errorf(nil, "unsupported operating system")
+ case obj.Hlinux:
+ ld.Asmbelf(ctxt, int64(symo))
+ }
+
+ ld.Cflush()
+ if *ld.FlagC {
+ fmt.Printf("textsize=%d\n", ld.Segtext.Filelen)
+ fmt.Printf("datsize=%d\n", ld.Segdata.Filelen)
+ fmt.Printf("bsssize=%d\n", ld.Segdata.Length-ld.Segdata.Filelen)
+ fmt.Printf("symsize=%d\n", ld.Symsize)
+ fmt.Printf("lcsize=%d\n", ld.Lcsize)
+ fmt.Printf("total=%d\n", ld.Segtext.Filelen+ld.Segdata.Length+uint64(ld.Symsize)+uint64(ld.Lcsize))
+ }
+}
diff --git a/src/cmd/link/internal/mips/l.go b/src/cmd/link/internal/mips/l.go
new file mode 100644
index 0000000..adbde40
--- /dev/null
+++ b/src/cmd/link/internal/mips/l.go
@@ -0,0 +1,74 @@
+// Inferno utils/5l/asm.c
+// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5l/asm.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth at terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth at terzarima.net)
+// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+// Portions Copyright © 2016 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION 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 mips
+
+// Writing object files.
+
+// cmd/9l/l.h from Vita Nuova.
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth at terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2008 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth at terzarima.net)
+// Revisions Copyright © 2000-2008 Lucent Technologies Inc. and others
+// Portions Copyright © 2016 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+const (
+ MaxAlign = 32 // max data alignment
+ MinAlign = 1 // min data alignment
+ FuncAlign = 4
+)
+
+/* Used by ../internal/ld/dwarf.go */
+const (
+ DWARFREGSP = 29
+ DWARFREGLR = 31
+)
diff --git a/src/cmd/link/internal/mips/obj.go b/src/cmd/link/internal/mips/obj.go
new file mode 100644
index 0000000..a333876
--- /dev/null
+++ b/src/cmd/link/internal/mips/obj.go
@@ -0,0 +1,110 @@
+// Inferno utils/5l/obj.c
+// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5l/obj.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth at terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth at terzarima.net)
+// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+// Portions Copyright © 2016 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION 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 mips
+
+import (
+ "cmd/internal/obj"
+ "cmd/internal/sys"
+ "cmd/link/internal/ld"
+ "fmt"
+)
+
+// Reading object files.
+
+func Init() {
+ if obj.GOARCH == "mipsle" {
+ ld.SysArch = sys.ArchMIPSLE
+ } else {
+ ld.SysArch = sys.ArchMIPS
+ }
+
+ ld.Thearch.Funcalign = FuncAlign
+ ld.Thearch.Maxalign = MaxAlign
+ ld.Thearch.Minalign = MinAlign
+ ld.Thearch.Dwarfregsp = DWARFREGSP
+ ld.Thearch.Dwarfreglr = DWARFREGLR
+
+ ld.Thearch.Adddynrel = adddynrel
+ ld.Thearch.Archinit = archinit
+ ld.Thearch.Archreloc = archreloc
+ ld.Thearch.Archrelocvariant = archrelocvariant
+ ld.Thearch.Asmb = asmb
+ ld.Thearch.Elfreloc1 = elfreloc1
+ ld.Thearch.Elfsetupplt = elfsetupplt
+ ld.Thearch.Gentext = gentext
+ ld.Thearch.Machoreloc1 = machoreloc1
+ if ld.SysArch == sys.ArchMIPSLE {
+ ld.Thearch.Lput = ld.Lputl
+ ld.Thearch.Wput = ld.Wputl
+ ld.Thearch.Vput = ld.Vputl
+ ld.Thearch.Append16 = ld.Append16l
+ ld.Thearch.Append32 = ld.Append32l
+ ld.Thearch.Append64 = ld.Append64l
+ } else {
+ ld.Thearch.Lput = ld.Lputb
+ ld.Thearch.Wput = ld.Wputb
+ ld.Thearch.Vput = ld.Vputb
+ ld.Thearch.Append16 = ld.Append16b
+ ld.Thearch.Append32 = ld.Append32b
+ ld.Thearch.Append64 = ld.Append64b
+ }
+
+ ld.Thearch.Linuxdynld = "/lib/ld.so.1"
+
+ ld.Thearch.Freebsddynld = "XXX"
+ ld.Thearch.Openbsddynld = "XXX"
+ ld.Thearch.Netbsddynld = "XXX"
+ ld.Thearch.Dragonflydynld = "XXX"
+ ld.Thearch.Solarisdynld = "XXX"
+}
+
+func archinit(ctxt *ld.Link) {
+ switch ld.Headtype {
+ default:
+ ld.Exitf("unknown -H option: %v", ld.Headtype)
+ case obj.Hlinux: /* mips elf */
+ ld.Elfinit(ctxt)
+ ld.HEADR = ld.ELFRESERVE
+ if *ld.FlagTextAddr == -1 {
+ *ld.FlagTextAddr = 0x10000 + int64(ld.HEADR)
+ }
+ if *ld.FlagDataAddr == -1 {
+ *ld.FlagDataAddr = 0
+ }
+ if *ld.FlagRound == -1 {
+ *ld.FlagRound = 0x10000
+ }
+ }
+
+ if *ld.FlagDataAddr != 0 && *ld.FlagRound != 0 {
+ fmt.Printf("warning: -D0x%x is ignored because of -R0x%x\n", uint64(*ld.FlagDataAddr), uint32(*ld.FlagRound))
+ }
+}
diff --git a/src/cmd/link/internal/mips64/asm.go b/src/cmd/link/internal/mips64/asm.go
index 32d9f23..1c3216f 100644
--- a/src/cmd/link/internal/mips64/asm.go
+++ b/src/cmd/link/internal/mips64/asm.go
@@ -1,5 +1,5 @@
// Inferno utils/5l/asm.c
-// http://code.google.com/p/inferno-os/source/browse/utils/5l/asm.c
+// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5l/asm.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth at terzarima.net)
@@ -38,13 +38,14 @@ import (
"log"
)
-func gentext() {}
+func gentext(ctxt *ld.Link) {}
-func adddynrel(s *ld.LSym, r *ld.Reloc) {
+func adddynrel(ctxt *ld.Link, s *ld.Symbol, r *ld.Reloc) bool {
log.Fatalf("adddynrel not implemented")
+ return false
}
-func elfreloc1(r *ld.Reloc, sectoff int64) int {
+func elfreloc1(ctxt *ld.Link, r *ld.Reloc, sectoff int64) int {
// mips64 ELF relocation (endian neutral)
// offset uint64
// sym uint32
@@ -93,15 +94,15 @@ func elfreloc1(r *ld.Reloc, sectoff int64) int {
return 0
}
-func elfsetupplt() {
+func elfsetupplt(ctxt *ld.Link) {
return
}
-func machoreloc1(r *ld.Reloc, sectoff int64) int {
+func machoreloc1(s *ld.Symbol, r *ld.Reloc, sectoff int64) int {
return -1
}
-func archreloc(r *ld.Reloc, s *ld.LSym, val *int64) int {
+func archreloc(ctxt *ld.Link, r *ld.Reloc, s *ld.Symbol, val *int64) int {
if ld.Linkmode == ld.LinkExternal {
switch r.Type {
default:
@@ -120,7 +121,7 @@ func archreloc(r *ld.Reloc, s *ld.LSym, val *int64) int {
}
if rs.Type != obj.SHOSTOBJ && rs.Type != obj.SDYNIMPORT && rs.Sect == nil {
- ld.Diag("missing section for %s", rs.Name)
+ ld.Errorf(s, "missing section for %s", rs.Name)
}
r.Xsym = rs
@@ -142,7 +143,7 @@ func archreloc(r *ld.Reloc, s *ld.LSym, val *int64) int {
return 0
case obj.R_GOTOFF:
- *val = ld.Symaddr(r.Sym) + r.Add - ld.Symaddr(ld.Linklookup(ld.Ctxt, ".got", 0))
+ *val = ld.Symaddr(r.Sym) + r.Add - ld.Symaddr(ctxt.Syms.Lookup(".got", 0))
return 0
case obj.R_ADDRMIPS,
@@ -160,7 +161,7 @@ func archreloc(r *ld.Reloc, s *ld.LSym, val *int64) int {
// thread pointer is at 0x7000 offset from the start of TLS data area
t := ld.Symaddr(r.Sym) + r.Add - 0x7000
if t < -32768 || t >= 32678 {
- ld.Diag("TLS offset out of range %d", t)
+ ld.Errorf(s, "TLS offset out of range %d", t)
}
o1 := ld.SysArch.ByteOrder.Uint32(s.P[r.Off:])
*val = int64(o1&0xffff0000 | uint32(t)&0xffff)
@@ -178,15 +179,14 @@ func archreloc(r *ld.Reloc, s *ld.LSym, val *int64) int {
return -1
}
-func archrelocvariant(r *ld.Reloc, s *ld.LSym, t int64) int64 {
+func archrelocvariant(ctxt *ld.Link, r *ld.Reloc, s *ld.Symbol, t int64) int64 {
return -1
}
-func asmb() {
- if ld.Debug['v'] != 0 {
- fmt.Fprintf(ld.Bso, "%5.2f asmb\n", obj.Cputime())
+func asmb(ctxt *ld.Link) {
+ if ctxt.Debugvlog != 0 {
+ ctxt.Logf("%5.2f asmb\n", obj.Cputime())
}
- ld.Bso.Flush()
if ld.Iself {
ld.Asmbelfsetup()
@@ -194,49 +194,52 @@ func asmb() {
sect := ld.Segtext.Sect
ld.Cseek(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
- ld.Codeblk(int64(sect.Vaddr), int64(sect.Length))
+ ld.Codeblk(ctxt, int64(sect.Vaddr), int64(sect.Length))
for sect = sect.Next; sect != nil; sect = sect.Next {
ld.Cseek(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
- ld.Datblk(int64(sect.Vaddr), int64(sect.Length))
+ ld.Datblk(ctxt, int64(sect.Vaddr), int64(sect.Length))
}
if ld.Segrodata.Filelen > 0 {
- if ld.Debug['v'] != 0 {
- fmt.Fprintf(ld.Bso, "%5.2f rodatblk\n", obj.Cputime())
+ if ctxt.Debugvlog != 0 {
+ ctxt.Logf("%5.2f rodatblk\n", obj.Cputime())
}
- ld.Bso.Flush()
-
ld.Cseek(int64(ld.Segrodata.Fileoff))
- ld.Datblk(int64(ld.Segrodata.Vaddr), int64(ld.Segrodata.Filelen))
+ 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())
+ }
+ ld.Cseek(int64(ld.Segrelrodata.Fileoff))
+ ld.Datblk(ctxt, int64(ld.Segrelrodata.Vaddr), int64(ld.Segrelrodata.Filelen))
}
- if ld.Debug['v'] != 0 {
- fmt.Fprintf(ld.Bso, "%5.2f datblk\n", obj.Cputime())
+ if ctxt.Debugvlog != 0 {
+ ctxt.Logf("%5.2f datblk\n", obj.Cputime())
}
- ld.Bso.Flush()
ld.Cseek(int64(ld.Segdata.Fileoff))
- ld.Datblk(int64(ld.Segdata.Vaddr), int64(ld.Segdata.Filelen))
+ ld.Datblk(ctxt, int64(ld.Segdata.Vaddr), int64(ld.Segdata.Filelen))
ld.Cseek(int64(ld.Segdwarf.Fileoff))
- ld.Dwarfblk(int64(ld.Segdwarf.Vaddr), int64(ld.Segdwarf.Filelen))
+ ld.Dwarfblk(ctxt, int64(ld.Segdwarf.Vaddr), int64(ld.Segdwarf.Filelen))
/* output symbol table */
ld.Symsize = 0
ld.Lcsize = 0
symo := uint32(0)
- if ld.Debug['s'] == 0 {
+ if !*ld.FlagS {
// TODO: rationalize
- if ld.Debug['v'] != 0 {
- fmt.Fprintf(ld.Bso, "%5.2f sym\n", obj.Cputime())
+ if ctxt.Debugvlog != 0 {
+ ctxt.Logf("%5.2f sym\n", obj.Cputime())
}
- ld.Bso.Flush()
- switch ld.HEADTYPE {
+ switch ld.Headtype {
default:
if ld.Iself {
symo = uint32(ld.Segdwarf.Fileoff + ld.Segdwarf.Filelen)
- symo = uint32(ld.Rnd(int64(symo), int64(ld.INITRND)))
+ symo = uint32(ld.Rnd(int64(symo), int64(*ld.FlagRound)))
}
case obj.Hplan9:
@@ -244,26 +247,26 @@ func asmb() {
}
ld.Cseek(int64(symo))
- switch ld.HEADTYPE {
+ switch ld.Headtype {
default:
if ld.Iself {
- if ld.Debug['v'] != 0 {
- fmt.Fprintf(ld.Bso, "%5.2f elfsym\n", obj.Cputime())
+ if ctxt.Debugvlog != 0 {
+ ctxt.Logf("%5.2f elfsym\n", obj.Cputime())
}
- ld.Asmelfsym()
+ ld.Asmelfsym(ctxt)
ld.Cflush()
ld.Cwrite(ld.Elfstrdat)
if ld.Linkmode == ld.LinkExternal {
- ld.Elfemitreloc()
+ ld.Elfemitreloc(ctxt)
}
}
case obj.Hplan9:
- ld.Asmplan9sym()
+ ld.Asmplan9sym(ctxt)
ld.Cflush()
- sym := ld.Linklookup(ld.Ctxt, "pclntab", 0)
+ sym := ctxt.Syms.Lookup("pclntab", 0)
if sym != nil {
ld.Lcsize = int32(len(sym.P))
for i := 0; int32(i) < ld.Lcsize; i++ {
@@ -275,13 +278,11 @@ func asmb() {
}
}
- ld.Ctxt.Cursym = nil
- if ld.Debug['v'] != 0 {
- fmt.Fprintf(ld.Bso, "%5.2f header\n", obj.Cputime())
+ if ctxt.Debugvlog != 0 {
+ ctxt.Logf("%5.2f header\n", obj.Cputime())
}
- ld.Bso.Flush()
ld.Cseek(0)
- switch ld.HEADTYPE {
+ switch ld.Headtype {
default:
case obj.Hplan9: /* plan 9 */
magic := uint32(4*18*18 + 7)
@@ -292,8 +293,8 @@ func asmb() {
ld.Thearch.Lput(uint32(ld.Segtext.Filelen)) /* sizes */
ld.Thearch.Lput(uint32(ld.Segdata.Filelen))
ld.Thearch.Lput(uint32(ld.Segdata.Length - ld.Segdata.Filelen))
- ld.Thearch.Lput(uint32(ld.Symsize)) /* nsyms */
- ld.Thearch.Lput(uint32(ld.Entryvalue())) /* va of entry */
+ ld.Thearch.Lput(uint32(ld.Symsize)) /* nsyms */
+ ld.Thearch.Lput(uint32(ld.Entryvalue(ctxt))) /* va of entry */
ld.Thearch.Lput(0)
ld.Thearch.Lput(uint32(ld.Lcsize))
@@ -302,11 +303,11 @@ func asmb() {
obj.Hnetbsd,
obj.Hopenbsd,
obj.Hnacl:
- ld.Asmbelf(int64(symo))
+ ld.Asmbelf(ctxt, int64(symo))
}
ld.Cflush()
- if ld.Debug['c'] != 0 {
+ if *ld.FlagC {
fmt.Printf("textsize=%d\n", ld.Segtext.Filelen)
fmt.Printf("datsize=%d\n", ld.Segdata.Filelen)
fmt.Printf("bsssize=%d\n", ld.Segdata.Length-ld.Segdata.Filelen)
diff --git a/src/cmd/link/internal/mips64/l.go b/src/cmd/link/internal/mips64/l.go
index e3f4fb3..d794122 100644
--- a/src/cmd/link/internal/mips64/l.go
+++ b/src/cmd/link/internal/mips64/l.go
@@ -1,5 +1,5 @@
// Inferno utils/5l/asm.c
-// http://code.google.com/p/inferno-os/source/browse/utils/5l/asm.c
+// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5l/asm.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth at terzarima.net)
@@ -62,13 +62,13 @@ package mips64
// THE SOFTWARE.
const (
- MaxAlign = 32 // max data alignment
- MinAlign = 1 // min data alignment
- FuncAlign = 8
+ maxAlign = 32 // max data alignment
+ minAlign = 1 // min data alignment
+ funcAlign = 8
)
/* Used by ../internal/ld/dwarf.go */
const (
- DWARFREGSP = 29
- DWARFREGLR = 31
+ dwarfRegSP = 29
+ dwarfRegLR = 31
)
diff --git a/src/cmd/link/internal/mips64/obj.go b/src/cmd/link/internal/mips64/obj.go
index ae9a280..b79cd9d 100644
--- a/src/cmd/link/internal/mips64/obj.go
+++ b/src/cmd/link/internal/mips64/obj.go
@@ -1,5 +1,5 @@
// Inferno utils/5l/obj.c
-// http://code.google.com/p/inferno-os/source/browse/utils/5l/obj.c
+// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5l/obj.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth at terzarima.net)
@@ -35,28 +35,20 @@ import (
"cmd/internal/sys"
"cmd/link/internal/ld"
"fmt"
- "log"
)
-// Reading object files.
-
-func Main() {
- linkarchinit()
- ld.Ldmain()
-}
-
-func linkarchinit() {
- if obj.Getgoarch() == "mips64le" {
+func Init() {
+ if obj.GOARCH == "mips64le" {
ld.SysArch = sys.ArchMIPS64LE
} else {
ld.SysArch = sys.ArchMIPS64
}
- ld.Thearch.Funcalign = FuncAlign
- ld.Thearch.Maxalign = MaxAlign
- ld.Thearch.Minalign = MinAlign
- ld.Thearch.Dwarfregsp = DWARFREGSP
- ld.Thearch.Dwarfreglr = DWARFREGLR
+ ld.Thearch.Funcalign = funcAlign
+ ld.Thearch.Maxalign = maxAlign
+ ld.Thearch.Minalign = minAlign
+ ld.Thearch.Dwarfregsp = dwarfRegSP
+ ld.Thearch.Dwarfreglr = dwarfRegLR
ld.Thearch.Adddynrel = adddynrel
ld.Thearch.Archinit = archinit
@@ -92,72 +84,53 @@ func linkarchinit() {
ld.Thearch.Solarisdynld = "XXX"
}
-func archinit() {
- // getgoextlinkenabled is based on GO_EXTLINK_ENABLED when
- // Go was built; see ../../make.bash.
- if ld.Linkmode == ld.LinkAuto && obj.Getgoextlinkenabled() == "0" {
- ld.Linkmode = ld.LinkInternal
- }
-
- switch ld.HEADTYPE {
- default:
- if ld.Linkmode == ld.LinkAuto {
- ld.Linkmode = ld.LinkInternal
- }
- if ld.Linkmode == ld.LinkExternal && obj.Getgoextlinkenabled() != "1" {
- log.Fatalf("cannot use -linkmode=external with -H %s", ld.Headstr(int(ld.HEADTYPE)))
- }
-
- case obj.Hlinux:
- break
- }
-
- switch ld.HEADTYPE {
+func archinit(ctxt *ld.Link) {
+ switch ld.Headtype {
default:
- ld.Exitf("unknown -H option: %v", ld.HEADTYPE)
+ ld.Exitf("unknown -H option: %v", ld.Headtype)
case obj.Hplan9: /* plan 9 */
ld.HEADR = 32
- if ld.INITTEXT == -1 {
- ld.INITTEXT = 16*1024 + int64(ld.HEADR)
+ if *ld.FlagTextAddr == -1 {
+ *ld.FlagTextAddr = 16*1024 + int64(ld.HEADR)
}
- if ld.INITDAT == -1 {
- ld.INITDAT = 0
+ if *ld.FlagDataAddr == -1 {
+ *ld.FlagDataAddr = 0
}
- if ld.INITRND == -1 {
- ld.INITRND = 16 * 1024
+ if *ld.FlagRound == -1 {
+ *ld.FlagRound = 16 * 1024
}
case obj.Hlinux: /* mips64 elf */
- ld.Elfinit()
+ ld.Elfinit(ctxt)
ld.HEADR = ld.ELFRESERVE
- if ld.INITTEXT == -1 {
- ld.INITTEXT = 0x10000 + int64(ld.HEADR)
+ if *ld.FlagTextAddr == -1 {
+ *ld.FlagTextAddr = 0x10000 + int64(ld.HEADR)
}
- if ld.INITDAT == -1 {
- ld.INITDAT = 0
+ if *ld.FlagDataAddr == -1 {
+ *ld.FlagDataAddr = 0
}
- if ld.INITRND == -1 {
- ld.INITRND = 0x10000
+ if *ld.FlagRound == -1 {
+ *ld.FlagRound = 0x10000
}
case obj.Hnacl:
- ld.Elfinit()
+ ld.Elfinit(ctxt)
ld.HEADR = 0x10000
ld.Funcalign = 16
- if ld.INITTEXT == -1 {
- ld.INITTEXT = 0x20000
+ if *ld.FlagTextAddr == -1 {
+ *ld.FlagTextAddr = 0x20000
}
- if ld.INITDAT == -1 {
- ld.INITDAT = 0
+ if *ld.FlagDataAddr == -1 {
+ *ld.FlagDataAddr = 0
}
- if ld.INITRND == -1 {
- ld.INITRND = 0x10000
+ if *ld.FlagRound == -1 {
+ *ld.FlagRound = 0x10000
}
}
- if ld.INITDAT != 0 && ld.INITRND != 0 {
- fmt.Printf("warning: -D0x%x is ignored because of -R0x%x\n", uint64(ld.INITDAT), uint32(ld.INITRND))
+ if *ld.FlagDataAddr != 0 && *ld.FlagRound != 0 {
+ fmt.Printf("warning: -D0x%x is ignored because of -R0x%x\n", uint64(*ld.FlagDataAddr), uint32(*ld.FlagRound))
}
}
diff --git a/src/cmd/link/internal/ppc64/asm.go b/src/cmd/link/internal/ppc64/asm.go
index bd2e23f..97107b9 100644
--- a/src/cmd/link/internal/ppc64/asm.go
+++ b/src/cmd/link/internal/ppc64/asm.go
@@ -1,5 +1,5 @@
// Inferno utils/5l/asm.c
-// http://code.google.com/p/inferno-os/source/browse/utils/5l/asm.c
+// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5l/asm.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth at terzarima.net)
@@ -38,7 +38,7 @@ import (
"log"
)
-func genplt() {
+func genplt(ctxt *ld.Link) {
// The ppc64 ABI PLT has similar concepts to other
// architectures, but is laid out quite differently. When we
// see an R_PPC64_REL24 relocation to a dynamic symbol
@@ -87,7 +87,7 @@ func genplt() {
//
// This assumes "case 1" from the ABI, where the caller needs
// us to save and restore the TOC pointer.
- for _, s := range ld.Ctxt.Textp {
+ 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 {
@@ -96,20 +96,20 @@ func genplt() {
// Reserve PLT entry and generate symbol
// resolver
- addpltsym(ld.Ctxt, r.Sym)
+ addpltsym(ctxt, r.Sym)
// Generate call stub
n := fmt.Sprintf("%s.%s", s.Name, r.Sym.Name)
- stub := ld.Linklookup(ld.Ctxt, n, 0)
+ stub := ctxt.Syms.Lookup(n, 0)
if s.Attr.Reachable() {
stub.Attr |= ld.AttrReachable
}
if stub.Size == 0 {
// Need outer to resolve .TOC.
stub.Outer = s
- ld.Ctxt.Textp = append(ld.Ctxt.Textp, stub)
- gencallstub(1, stub, r.Sym)
+ ctxt.Textp = append(ctxt.Textp, stub)
+ gencallstub(ctxt, 1, stub, r.Sym)
}
// Update the relocation to use the call stub
@@ -118,29 +118,29 @@ func genplt() {
// Restore TOC after bl. The compiler put a
// nop here for us to overwrite.
const o1 = 0xe8410018 // ld r2,24(r1)
- ld.Ctxt.Arch.ByteOrder.PutUint32(s.P[r.Off+4:], o1)
+ ctxt.Arch.ByteOrder.PutUint32(s.P[r.Off+4:], o1)
}
}
}
-func genaddmoduledata() {
- addmoduledata := ld.Linkrlookup(ld.Ctxt, "runtime.addmoduledata", 0)
+func genaddmoduledata(ctxt *ld.Link) {
+ addmoduledata := ctxt.Syms.ROLookup("runtime.addmoduledata", 0)
if addmoduledata.Type == obj.STEXT {
return
}
addmoduledata.Attr |= ld.AttrReachable
- initfunc := ld.Linklookup(ld.Ctxt, "go.link.addmoduledata", 0)
+ initfunc := ctxt.Syms.Lookup("go.link.addmoduledata", 0)
initfunc.Type = obj.STEXT
initfunc.Attr |= ld.AttrLocal
initfunc.Attr |= ld.AttrReachable
o := func(op uint32) {
- ld.Adduint32(ld.Ctxt, initfunc, op)
+ ld.Adduint32(ctxt, initfunc, op)
}
// addis r2, r12, .TOC.-func at ha
rel := ld.Addrel(initfunc)
rel.Off = int32(initfunc.Size)
rel.Siz = 8
- rel.Sym = ld.Linklookup(ld.Ctxt, ".TOC.", 0)
+ rel.Sym = ctxt.Syms.Lookup(".TOC.", 0)
rel.Type = obj.R_ADDRPOWER_PCREL
o(0x3c4c0000)
// addi r2, r2, .TOC.-func at l
@@ -153,7 +153,7 @@ func genaddmoduledata() {
rel = ld.Addrel(initfunc)
rel.Off = int32(initfunc.Size)
rel.Siz = 8
- rel.Sym = ld.Linklookup(ld.Ctxt, "local.moduledata", 0)
+ rel.Sym = ctxt.Syms.Lookup("local.moduledata", 0)
rel.Type = obj.R_ADDRPOWER_GOT
o(0x3c620000)
// ld r3, local.moduledata at got@l(r3)
@@ -176,39 +176,39 @@ func genaddmoduledata() {
// blr
o(0x4e800020)
- ld.Ctxt.Textp = append(ld.Ctxt.Textp, initfunc)
- initarray_entry := ld.Linklookup(ld.Ctxt, "go.link.addmoduledatainit", 0)
+ initarray_entry := ctxt.Syms.Lookup("go.link.addmoduledatainit", 0)
+ ctxt.Textp = append(ctxt.Textp, initfunc)
initarray_entry.Attr |= ld.AttrReachable
initarray_entry.Attr |= ld.AttrLocal
initarray_entry.Type = obj.SINITARR
- ld.Addaddr(ld.Ctxt, initarray_entry, initfunc)
+ ld.Addaddr(ctxt, initarray_entry, initfunc)
}
-func gentext() {
- if ld.DynlinkingGo() {
- genaddmoduledata()
+func gentext(ctxt *ld.Link) {
+ if ctxt.DynlinkingGo() {
+ genaddmoduledata(ctxt)
}
if ld.Linkmode == ld.LinkInternal {
- genplt()
+ genplt(ctxt)
}
}
// Construct a call stub in stub that calls symbol targ via its PLT
// entry.
-func gencallstub(abicase int, stub *ld.LSym, targ *ld.LSym) {
+func gencallstub(ctxt *ld.Link, abicase int, stub *ld.Symbol, targ *ld.Symbol) {
if abicase != 1 {
// If we see R_PPC64_TOCSAVE or R_PPC64_REL24_NOTOC
// relocations, we'll need to implement cases 2 and 3.
log.Fatalf("gencallstub only implements case 1 calls")
}
- plt := ld.Linklookup(ld.Ctxt, ".plt", 0)
+ plt := ctxt.Syms.Lookup(".plt", 0)
stub.Type = obj.STEXT
// Save TOC pointer in TOC save slot
- ld.Adduint32(ld.Ctxt, stub, 0xf8410018) // std r2,24(r1)
+ ld.Adduint32(ctxt, stub, 0xf8410018) // std r2,24(r1)
// Load the function pointer from the PLT.
r := ld.Addrel(stub)
@@ -217,38 +217,37 @@ func gencallstub(abicase int, stub *ld.LSym, targ *ld.LSym) {
r.Sym = plt
r.Add = int64(targ.Plt)
r.Siz = 2
- if ld.Ctxt.Arch.ByteOrder == binary.BigEndian {
+ if ctxt.Arch.ByteOrder == binary.BigEndian {
r.Off += int32(r.Siz)
}
r.Type = obj.R_POWER_TOC
r.Variant = ld.RV_POWER_HA
- ld.Adduint32(ld.Ctxt, stub, 0x3d820000) // addis r12,r2,targ at plt@toc at ha
+ ld.Adduint32(ctxt, stub, 0x3d820000) // addis r12,r2,targ at plt@toc at ha
r = ld.Addrel(stub)
r.Off = int32(stub.Size)
r.Sym = plt
r.Add = int64(targ.Plt)
r.Siz = 2
- if ld.Ctxt.Arch.ByteOrder == binary.BigEndian {
+ if ctxt.Arch.ByteOrder == binary.BigEndian {
r.Off += int32(r.Siz)
}
r.Type = obj.R_POWER_TOC
r.Variant = ld.RV_POWER_LO
- ld.Adduint32(ld.Ctxt, stub, 0xe98c0000) // ld r12,targ at plt@toc at l(r12)
+ ld.Adduint32(ctxt, stub, 0xe98c0000) // ld r12,targ at plt@toc at l(r12)
// Jump to the loaded pointer
- ld.Adduint32(ld.Ctxt, stub, 0x7d8903a6) // mtctr r12
- ld.Adduint32(ld.Ctxt, stub, 0x4e800420) // bctr
+ ld.Adduint32(ctxt, stub, 0x7d8903a6) // mtctr r12
+ ld.Adduint32(ctxt, stub, 0x4e800420) // bctr
}
-func adddynrel(s *ld.LSym, r *ld.Reloc) {
+func adddynrel(ctxt *ld.Link, s *ld.Symbol, r *ld.Reloc) bool {
targ := r.Sym
- ld.Ctxt.Cursym = s
switch r.Type {
default:
if r.Type >= 256 {
- ld.Diag("unexpected relocation type %d", r.Type)
- return
+ ld.Errorf(s, "unexpected relocation type %d", r.Type)
+ return false
}
// Handle relocations found in ELF object files.
@@ -264,96 +263,96 @@ func adddynrel(s *ld.LSym, r *ld.Reloc) {
if targ.Type == obj.SDYNIMPORT {
// Should have been handled in elfsetupplt
- ld.Diag("unexpected R_PPC64_REL24 for dyn import")
+ ld.Errorf(s, "unexpected R_PPC64_REL24 for dyn import")
}
- return
+ return true
case 256 + ld.R_PPC_REL32:
r.Type = obj.R_PCREL
r.Add += 4
if targ.Type == obj.SDYNIMPORT {
- ld.Diag("unexpected R_PPC_REL32 for dyn import")
+ ld.Errorf(s, "unexpected R_PPC_REL32 for dyn import")
}
- return
+ return true
case 256 + ld.R_PPC64_ADDR64:
r.Type = obj.R_ADDR
if targ.Type == obj.SDYNIMPORT {
// These happen in .toc sections
- ld.Adddynsym(ld.Ctxt, targ)
+ ld.Adddynsym(ctxt, targ)
- rela := ld.Linklookup(ld.Ctxt, ".rela", 0)
- ld.Addaddrplus(ld.Ctxt, rela, s, int64(r.Off))
- ld.Adduint64(ld.Ctxt, rela, ld.ELF64_R_INFO(uint32(targ.Dynid), ld.R_PPC64_ADDR64))
- ld.Adduint64(ld.Ctxt, rela, uint64(r.Add))
+ rela := ctxt.Syms.Lookup(".rela", 0)
+ ld.Addaddrplus(ctxt, rela, s, int64(r.Off))
+ ld.Adduint64(ctxt, rela, ld.ELF64_R_INFO(uint32(targ.Dynid), ld.R_PPC64_ADDR64))
+ ld.Adduint64(ctxt, rela, uint64(r.Add))
r.Type = 256 // ignore during relocsym
}
- return
+ return true
case 256 + ld.R_PPC64_TOC16:
r.Type = obj.R_POWER_TOC
r.Variant = ld.RV_POWER_LO | ld.RV_CHECK_OVERFLOW
- return
+ return true
case 256 + ld.R_PPC64_TOC16_LO:
r.Type = obj.R_POWER_TOC
r.Variant = ld.RV_POWER_LO
- return
+ return true
case 256 + ld.R_PPC64_TOC16_HA:
r.Type = obj.R_POWER_TOC
r.Variant = ld.RV_POWER_HA | ld.RV_CHECK_OVERFLOW
- return
+ return true
case 256 + ld.R_PPC64_TOC16_HI:
r.Type = obj.R_POWER_TOC
r.Variant = ld.RV_POWER_HI | ld.RV_CHECK_OVERFLOW
- return
+ return true
case 256 + ld.R_PPC64_TOC16_DS:
r.Type = obj.R_POWER_TOC
r.Variant = ld.RV_POWER_DS | ld.RV_CHECK_OVERFLOW
- return
+ return true
case 256 + ld.R_PPC64_TOC16_LO_DS:
r.Type = obj.R_POWER_TOC
r.Variant = ld.RV_POWER_DS
- return
+ return true
case 256 + ld.R_PPC64_REL16_LO:
r.Type = obj.R_PCREL
r.Variant = ld.RV_POWER_LO
r.Add += 2 // Compensate for relocation size of 2
- return
+ return true
case 256 + ld.R_PPC64_REL16_HI:
r.Type = obj.R_PCREL
r.Variant = ld.RV_POWER_HI | ld.RV_CHECK_OVERFLOW
r.Add += 2
- return
+ return true
case 256 + ld.R_PPC64_REL16_HA:
r.Type = obj.R_PCREL
r.Variant = ld.RV_POWER_HA | ld.RV_CHECK_OVERFLOW
r.Add += 2
- return
+ return true
}
// Handle references to ELF symbols from our own object files.
if targ.Type != obj.SDYNIMPORT {
- return
+ return true
}
// TODO(austin): Translate our relocations to ELF
- ld.Diag("unsupported relocation for dynamic symbol %s (type=%d stype=%d)", targ.Name, r.Type, targ.Type)
+ return false
}
-func elfreloc1(r *ld.Reloc, sectoff int64) int {
+func elfreloc1(ctxt *ld.Link, r *ld.Reloc, sectoff int64) int {
ld.Thearch.Vput(uint64(sectoff))
elfsym := r.Xsym.ElfsymForReloc()
@@ -432,8 +431,8 @@ func elfreloc1(r *ld.Reloc, sectoff int64) int {
return 0
}
-func elfsetupplt() {
- plt := ld.Linklookup(ld.Ctxt, ".plt", 0)
+func elfsetupplt(ctxt *ld.Link) {
+ plt := ctxt.Syms.Lookup(".plt", 0)
if plt.Size == 0 {
// The dynamic linker stores the address of the
// dynamic resolver and the DSO identifier in the two
@@ -443,31 +442,31 @@ func elfsetupplt() {
}
}
-func machoreloc1(r *ld.Reloc, sectoff int64) int {
+func machoreloc1(s *ld.Symbol, r *ld.Reloc, sectoff int64) int {
return -1
}
// Return the value of .TOC. for symbol s
-func symtoc(s *ld.LSym) int64 {
- var toc *ld.LSym
+func symtoc(ctxt *ld.Link, s *ld.Symbol) int64 {
+ var toc *ld.Symbol
if s.Outer != nil {
- toc = ld.Linkrlookup(ld.Ctxt, ".TOC.", int(s.Outer.Version))
+ toc = ctxt.Syms.ROLookup(".TOC.", int(s.Outer.Version))
} else {
- toc = ld.Linkrlookup(ld.Ctxt, ".TOC.", int(s.Version))
+ toc = ctxt.Syms.ROLookup(".TOC.", int(s.Version))
}
if toc == nil {
- ld.Diag("TOC-relative relocation in object without .TOC.")
+ ld.Errorf(s, "TOC-relative relocation in object without .TOC.")
return 0
}
return toc.Value
}
-func archrelocaddr(r *ld.Reloc, s *ld.LSym, val *int64) int {
+func archrelocaddr(ctxt *ld.Link, r *ld.Reloc, s *ld.Symbol, val *int64) int {
var o1, o2 uint32
- if ld.Ctxt.Arch.ByteOrder == binary.BigEndian {
+ if ctxt.Arch.ByteOrder == binary.BigEndian {
o1 = uint32(*val >> 32)
o2 = uint32(*val)
} else {
@@ -484,7 +483,7 @@ func archrelocaddr(r *ld.Reloc, s *ld.LSym, val *int64) int {
t := ld.Symaddr(r.Sym) + r.Add
if t < 0 || t >= 1<<31 {
- ld.Ctxt.Diag("relocation for %s is too big (>=2G): %d", s.Name, ld.Symaddr(r.Sym))
+ ld.Errorf(s, "relocation for %s is too big (>=2G): %d", s.Name, ld.Symaddr(r.Sym))
}
if t&0x8000 != 0 {
t += 0x10000
@@ -498,7 +497,7 @@ func archrelocaddr(r *ld.Reloc, s *ld.LSym, val *int64) int {
case obj.R_ADDRPOWER_DS:
o1 |= (uint32(t) >> 16) & 0xffff
if t&3 != 0 {
- ld.Ctxt.Diag("bad DS reloc for %s: %d", s.Name, ld.Symaddr(r.Sym))
+ ld.Errorf(s, "bad DS reloc for %s: %d", s.Name, ld.Symaddr(r.Sym))
}
o2 |= uint32(t) & 0xfffc
@@ -506,7 +505,7 @@ func archrelocaddr(r *ld.Reloc, s *ld.LSym, val *int64) int {
return -1
}
- if ld.Ctxt.Arch.ByteOrder == binary.BigEndian {
+ if ctxt.Arch.ByteOrder == binary.BigEndian {
*val = int64(o1)<<32 | int64(o2)
} else {
*val = int64(o2)<<32 | int64(o1)
@@ -514,7 +513,70 @@ func archrelocaddr(r *ld.Reloc, s *ld.LSym, val *int64) int {
return 0
}
-func archreloc(r *ld.Reloc, s *ld.LSym, 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) {
+
+ t := ld.Symaddr(r.Sym) + r.Add - (s.Value + int64(r.Off))
+ switch r.Type {
+ case obj.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) {
+ var tramp *ld.Symbol
+ for i := 0; ; i++ {
+
+ // Using r.Add as part of the name is significant in functions like duffzero where the call
+ // target is at some offset within the function. Calls to duff+8 and duff+256 must appear as
+ // distinct trampolines.
+
+ name := r.Sym.Name
+ if r.Add == 0 {
+ name = name + fmt.Sprintf("-tramp%d", i)
+ } else {
+ name = name + fmt.Sprintf("%+x-tramp%d", r.Add, i)
+ }
+
+ // Look up the trampoline in case it already exists
+
+ tramp = ctxt.Syms.Lookup(name, int(r.Sym.Version))
+ if tramp.Value == 0 {
+ break
+ }
+
+ 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 {
+ 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)
+ }
+ r.Sym = tramp
+ r.Add = 0 // This was folded into the trampoline target address
+ r.Done = 0
+ }
+ default:
+ ld.Errorf(s, "trampoline called with non-jump reloc: %v", r.Type)
+ }
+}
+
+func archreloc(ctxt *ld.Link, r *ld.Reloc, s *ld.Symbol, val *int64) int {
if ld.Linkmode == ld.LinkExternal {
switch r.Type {
default:
@@ -544,7 +606,7 @@ func archreloc(r *ld.Reloc, s *ld.LSym, val *int64) int {
}
if rs.Type != obj.SHOSTOBJ && rs.Type != obj.SDYNIMPORT && rs.Sect == nil {
- ld.Diag("missing section for %s", rs.Name)
+ ld.Errorf(s, "missing section for %s", rs.Name)
}
r.Xsym = rs
@@ -564,30 +626,30 @@ func archreloc(r *ld.Reloc, s *ld.LSym, val *int64) int {
return 0
case obj.R_GOTOFF:
- *val = ld.Symaddr(r.Sym) + r.Add - ld.Symaddr(ld.Linklookup(ld.Ctxt, ".got", 0))
+ *val = ld.Symaddr(r.Sym) + r.Add - ld.Symaddr(ctxt.Syms.Lookup(".got", 0))
return 0
case obj.R_ADDRPOWER, obj.R_ADDRPOWER_DS:
- return archrelocaddr(r, s, val)
+ return archrelocaddr(ctxt, r, s, val)
case obj.R_CALLPOWER:
// Bits 6 through 29 = (S + A - P) >> 2
t := ld.Symaddr(r.Sym) + r.Add - (s.Value + int64(r.Off))
+
if t&3 != 0 {
- ld.Ctxt.Diag("relocation for %s+%d is not aligned: %d", r.Sym.Name, r.Off, t)
+ ld.Errorf(s, "relocation for %s+%d is not aligned: %d", r.Sym.Name, r.Off, t)
}
+ // If branch offset is too far then create a trampoline.
+
if int64(int32(t<<6)>>6) != t {
- // TODO(austin) This can happen if text > 32M.
- // Add a call trampoline to .text in that case.
- ld.Ctxt.Diag("relocation for %s+%d is too big: %d", r.Sym.Name, r.Off, t)
+ ld.Errorf(s, "direct call too far: %s %x", r.Sym.Name, t)
}
-
*val |= int64(uint32(t) &^ 0xfc000003)
return 0
case obj.R_POWER_TOC: // S + A - .TOC.
- *val = ld.Symaddr(r.Sym) + r.Add - symtoc(s)
+ *val = ld.Symaddr(r.Sym) + r.Add - symtoc(ctxt, s)
return 0
@@ -598,7 +660,7 @@ func archreloc(r *ld.Reloc, s *ld.LSym, val *int64) int {
// Specification".
v := r.Sym.Value - 0x7000
if int64(int16(v)) != v {
- ld.Diag("TLS offset out of range %d", v)
+ ld.Errorf(s, "TLS offset out of range %d", v)
}
*val = (*val &^ 0xffff) | (v & 0xffff)
return 0
@@ -607,10 +669,10 @@ func archreloc(r *ld.Reloc, s *ld.LSym, val *int64) int {
return -1
}
-func archrelocvariant(r *ld.Reloc, s *ld.LSym, t int64) int64 {
+func archrelocvariant(ctxt *ld.Link, r *ld.Reloc, s *ld.Symbol, t int64) int64 {
switch r.Variant & ld.RV_TYPE_MASK {
default:
- ld.Diag("unexpected relocation variant %d", r.Variant)
+ ld.Errorf(s, "unexpected relocation variant %d", r.Variant)
fallthrough
case ld.RV_NONE:
@@ -621,7 +683,7 @@ func archrelocvariant(r *ld.Reloc, s *ld.LSym, t int64) int64 {
// Whether to check for signed or unsigned
// overflow depends on the instruction
var o1 uint32
- if ld.Ctxt.Arch.ByteOrder == binary.BigEndian {
+ if ctxt.Arch.ByteOrder == binary.BigEndian {
o1 = ld.Be32(s.P[r.Off-2:])
} else {
o1 = ld.Le32(s.P[r.Off:])
@@ -655,7 +717,7 @@ func archrelocvariant(r *ld.Reloc, s *ld.LSym, t int64) int64 {
// Whether to check for signed or unsigned
// overflow depends on the instruction
var o1 uint32
- if ld.Ctxt.Arch.ByteOrder == binary.BigEndian {
+ if ctxt.Arch.ByteOrder == binary.BigEndian {
o1 = ld.Be32(s.P[r.Off-2:])
} else {
o1 = ld.Le32(s.P[r.Off:])
@@ -679,13 +741,13 @@ func archrelocvariant(r *ld.Reloc, s *ld.LSym, t int64) int64 {
case ld.RV_POWER_DS:
var o1 uint32
- if ld.Ctxt.Arch.ByteOrder == binary.BigEndian {
+ if ctxt.Arch.ByteOrder == binary.BigEndian {
o1 = uint32(ld.Be16(s.P[r.Off:]))
} else {
o1 = uint32(ld.Le16(s.P[r.Off:]))
}
if t&3 != 0 {
- ld.Diag("relocation for %s+%d is not aligned: %d", r.Sym.Name, r.Off, t)
+ ld.Errorf(s, "relocation for %s+%d is not aligned: %d", r.Sym.Name, r.Off, t)
}
if (r.Variant&ld.RV_CHECK_OVERFLOW != 0) && int64(int16(t)) != t {
goto overflow
@@ -694,11 +756,11 @@ func archrelocvariant(r *ld.Reloc, s *ld.LSym, t int64) int64 {
}
overflow:
- ld.Diag("relocation for %s+%d is too big: %d", r.Sym.Name, r.Off, t)
+ ld.Errorf(s, "relocation for %s+%d is too big: %d", r.Sym.Name, r.Off, t)
return t
}
-func addpltsym(ctxt *ld.Link, s *ld.LSym) {
+func addpltsym(ctxt *ld.Link, s *ld.Symbol) {
if s.Plt >= 0 {
return
}
@@ -706,14 +768,14 @@ func addpltsym(ctxt *ld.Link, s *ld.LSym) {
ld.Adddynsym(ctxt, s)
if ld.Iself {
- plt := ld.Linklookup(ctxt, ".plt", 0)
- rela := ld.Linklookup(ctxt, ".rela.plt", 0)
+ plt := ctxt.Syms.Lookup(".plt", 0)
+ rela := ctxt.Syms.Lookup(".rela.plt", 0)
if plt.Size == 0 {
- elfsetupplt()
+ elfsetupplt(ctxt)
}
// Create the glink resolver if necessary
- glink := ensureglinkresolver()
+ glink := ensureglinkresolver(ctxt)
// Write symbol resolver stub (just a branch to the
// glink resolver stub)
@@ -739,13 +801,13 @@ func addpltsym(ctxt *ld.Link, s *ld.LSym) {
ld.Adduint64(ctxt, rela, ld.ELF64_R_INFO(uint32(s.Dynid), ld.R_PPC64_JMP_SLOT))
ld.Adduint64(ctxt, rela, 0)
} else {
- ld.Diag("addpltsym: unsupported binary format")
+ ld.Errorf(s, "addpltsym: unsupported binary format")
}
}
// Generate the glink resolver stub if necessary and return the .glink section
-func ensureglinkresolver() *ld.LSym {
- glink := ld.Linklookup(ld.Ctxt, ".glink", 0)
+func ensureglinkresolver(ctxt *ld.Link) *ld.Symbol {
+ glink := ctxt.Syms.Lookup(".glink", 0)
if glink.Size != 0 {
return glink
}
@@ -757,107 +819,111 @@ func ensureglinkresolver() *ld.LSym {
//
// This stub is PIC, so first get the PC of label 1 into r11.
// Other things will be relative to this.
- ld.Adduint32(ld.Ctxt, glink, 0x7c0802a6) // mflr r0
- ld.Adduint32(ld.Ctxt, glink, 0x429f0005) // bcl 20,31,1f
- ld.Adduint32(ld.Ctxt, glink, 0x7d6802a6) // 1: mflr r11
- ld.Adduint32(ld.Ctxt, glink, 0x7c0803a6) // mtlf r0
+ ld.Adduint32(ctxt, glink, 0x7c0802a6) // mflr r0
+ ld.Adduint32(ctxt, glink, 0x429f0005) // bcl 20,31,1f
+ ld.Adduint32(ctxt, glink, 0x7d6802a6) // 1: mflr r11
+ ld.Adduint32(ctxt, glink, 0x7c0803a6) // mtlf r0
// Compute the .plt array index from the entry point address.
// Because this is PIC, everything is relative to label 1b (in
// r11):
// r0 = ((r12 - r11) - (res_0 - r11)) / 4 = (r12 - res_0) / 4
- ld.Adduint32(ld.Ctxt, glink, 0x3800ffd0) // li r0,-(res_0-1b)=-48
- ld.Adduint32(ld.Ctxt, glink, 0x7c006214) // add r0,r0,r12
- ld.Adduint32(ld.Ctxt, glink, 0x7c0b0050) // sub r0,r0,r11
- ld.Adduint32(ld.Ctxt, glink, 0x7800f082) // srdi r0,r0,2
+ ld.Adduint32(ctxt, glink, 0x3800ffd0) // li r0,-(res_0-1b)=-48
+ ld.Adduint32(ctxt, glink, 0x7c006214) // add r0,r0,r12
+ ld.Adduint32(ctxt, glink, 0x7c0b0050) // sub r0,r0,r11
+ ld.Adduint32(ctxt, glink, 0x7800f082) // srdi r0,r0,2
// r11 = address of the first byte of the PLT
r := ld.Addrel(glink)
r.Off = int32(glink.Size)
- r.Sym = ld.Linklookup(ld.Ctxt, ".plt", 0)
+ r.Sym = ctxt.Syms.Lookup(".plt", 0)
r.Siz = 8
r.Type = obj.R_ADDRPOWER
- ld.Adduint32(ld.Ctxt, glink, 0x3d600000) // addis r11,0,.plt at ha
- ld.Adduint32(ld.Ctxt, glink, 0x396b0000) // addi r11,r11,.plt at l
+ ld.Adduint32(ctxt, glink, 0x3d600000) // addis r11,0,.plt at ha
+ ld.Adduint32(ctxt, glink, 0x396b0000) // addi r11,r11,.plt at l
// Load r12 = dynamic resolver address and r11 = DSO
// identifier from the first two doublewords of the PLT.
- ld.Adduint32(ld.Ctxt, glink, 0xe98b0000) // ld r12,0(r11)
- ld.Adduint32(ld.Ctxt, glink, 0xe96b0008) // ld r11,8(r11)
+ ld.Adduint32(ctxt, glink, 0xe98b0000) // ld r12,0(r11)
+ ld.Adduint32(ctxt, glink, 0xe96b0008) // ld r11,8(r11)
// Jump to the dynamic resolver
- ld.Adduint32(ld.Ctxt, glink, 0x7d8903a6) // mtctr r12
- ld.Adduint32(ld.Ctxt, glink, 0x4e800420) // bctr
+ ld.Adduint32(ctxt, glink, 0x7d8903a6) // mtctr r12
+ ld.Adduint32(ctxt, glink, 0x4e800420) // bctr
// The symbol resolvers must immediately follow.
// res_0:
// Add DT_PPC64_GLINK .dynamic entry, which points to 32 bytes
// before the first symbol resolver stub.
- s := ld.Linklookup(ld.Ctxt, ".dynamic", 0)
+ s := ctxt.Syms.Lookup(".dynamic", 0)
- ld.Elfwritedynentsymplus(s, ld.DT_PPC64_GLINK, glink, glink.Size-32)
+ ld.Elfwritedynentsymplus(ctxt, s, ld.DT_PPC64_GLINK, glink, glink.Size-32)
return glink
}
-func asmb() {
- if ld.Debug['v'] != 0 {
- fmt.Fprintf(ld.Bso, "%5.2f asmb\n", obj.Cputime())
+func asmb(ctxt *ld.Link) {
+ if ctxt.Debugvlog != 0 {
+ ctxt.Logf("%5.2f asmb\n", obj.Cputime())
}
- ld.Bso.Flush()
if ld.Iself {
ld.Asmbelfsetup()
}
- sect := ld.Segtext.Sect
- ld.Cseek(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
- ld.Codeblk(int64(sect.Vaddr), int64(sect.Length))
- for sect = sect.Next; sect != nil; sect = sect.Next {
+ for sect := ld.Segtext.Sect; sect != nil; sect = sect.Next {
ld.Cseek(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
- ld.Datblk(int64(sect.Vaddr), int64(sect.Length))
+ // Handle additional text sections with Codeblk
+ if sect.Name == ".text" {
+ ld.Codeblk(ctxt, int64(sect.Vaddr), int64(sect.Length))
+ } else {
+ ld.Datblk(ctxt, int64(sect.Vaddr), int64(sect.Length))
+ }
}
if ld.Segrodata.Filelen > 0 {
- if ld.Debug['v'] != 0 {
- fmt.Fprintf(ld.Bso, "%5.2f rodatblk\n", obj.Cputime())
+ if ctxt.Debugvlog != 0 {
+ ctxt.Logf("%5.2f rodatblk\n", obj.Cputime())
}
- ld.Bso.Flush()
-
ld.Cseek(int64(ld.Segrodata.Fileoff))
- ld.Datblk(int64(ld.Segrodata.Vaddr), int64(ld.Segrodata.Filelen))
+ 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())
+ }
+ ld.Cseek(int64(ld.Segrelrodata.Fileoff))
+ ld.Datblk(ctxt, int64(ld.Segrelrodata.Vaddr), int64(ld.Segrelrodata.Filelen))
}
- if ld.Debug['v'] != 0 {
- fmt.Fprintf(ld.Bso, "%5.2f datblk\n", obj.Cputime())
+ if ctxt.Debugvlog != 0 {
+ ctxt.Logf("%5.2f datblk\n", obj.Cputime())
}
- ld.Bso.Flush()
ld.Cseek(int64(ld.Segdata.Fileoff))
- ld.Datblk(int64(ld.Segdata.Vaddr), int64(ld.Segdata.Filelen))
+ ld.Datblk(ctxt, int64(ld.Segdata.Vaddr), int64(ld.Segdata.Filelen))
ld.Cseek(int64(ld.Segdwarf.Fileoff))
- ld.Dwarfblk(int64(ld.Segdwarf.Vaddr), int64(ld.Segdwarf.Filelen))
+ ld.Dwarfblk(ctxt, int64(ld.Segdwarf.Vaddr), int64(ld.Segdwarf.Filelen))
/* output symbol table */
ld.Symsize = 0
ld.Lcsize = 0
symo := uint32(0)
- if ld.Debug['s'] == 0 {
+ if !*ld.FlagS {
// TODO: rationalize
- if ld.Debug['v'] != 0 {
- fmt.Fprintf(ld.Bso, "%5.2f sym\n", obj.Cputime())
+ if ctxt.Debugvlog != 0 {
+ ctxt.Logf("%5.2f sym\n", obj.Cputime())
}
- ld.Bso.Flush()
- switch ld.HEADTYPE {
+ switch ld.Headtype {
default:
if ld.Iself {
symo = uint32(ld.Segdwarf.Fileoff + ld.Segdwarf.Filelen)
- symo = uint32(ld.Rnd(int64(symo), int64(ld.INITRND)))
+ symo = uint32(ld.Rnd(int64(symo), int64(*ld.FlagRound)))
}
case obj.Hplan9:
@@ -865,26 +931,26 @@ func asmb() {
}
ld.Cseek(int64(symo))
- switch ld.HEADTYPE {
+ switch ld.Headtype {
default:
if ld.Iself {
- if ld.Debug['v'] != 0 {
- fmt.Fprintf(ld.Bso, "%5.2f elfsym\n", obj.Cputime())
+ if ctxt.Debugvlog != 0 {
+ ctxt.Logf("%5.2f elfsym\n", obj.Cputime())
}
- ld.Asmelfsym()
+ ld.Asmelfsym(ctxt)
ld.Cflush()
ld.Cwrite(ld.Elfstrdat)
if ld.Linkmode == ld.LinkExternal {
- ld.Elfemitreloc()
+ ld.Elfemitreloc(ctxt)
}
}
case obj.Hplan9:
- ld.Asmplan9sym()
+ ld.Asmplan9sym(ctxt)
ld.Cflush()
- sym := ld.Linklookup(ld.Ctxt, "pclntab", 0)
+ sym := ctxt.Syms.Lookup("pclntab", 0)
if sym != nil {
ld.Lcsize = int32(len(sym.P))
for i := 0; int32(i) < ld.Lcsize; i++ {
@@ -896,21 +962,19 @@ func asmb() {
}
}
- ld.Ctxt.Cursym = nil
- if ld.Debug['v'] != 0 {
- fmt.Fprintf(ld.Bso, "%5.2f header\n", obj.Cputime())
+ if ctxt.Debugvlog != 0 {
+ ctxt.Logf("%5.2f header\n", obj.Cputime())
}
- ld.Bso.Flush()
ld.Cseek(0)
- switch ld.HEADTYPE {
+ switch ld.Headtype {
default:
case obj.Hplan9: /* plan 9 */
ld.Thearch.Lput(0x647) /* magic */
ld.Thearch.Lput(uint32(ld.Segtext.Filelen)) /* sizes */
ld.Thearch.Lput(uint32(ld.Segdata.Filelen))
ld.Thearch.Lput(uint32(ld.Segdata.Length - ld.Segdata.Filelen))
- ld.Thearch.Lput(uint32(ld.Symsize)) /* nsyms */
- ld.Thearch.Lput(uint32(ld.Entryvalue())) /* va of entry */
+ ld.Thearch.Lput(uint32(ld.Symsize)) /* nsyms */
+ ld.Thearch.Lput(uint32(ld.Entryvalue(ctxt))) /* va of entry */
ld.Thearch.Lput(0)
ld.Thearch.Lput(uint32(ld.Lcsize))
@@ -919,11 +983,11 @@ func asmb() {
obj.Hnetbsd,
obj.Hopenbsd,
obj.Hnacl:
- ld.Asmbelf(int64(symo))
+ ld.Asmbelf(ctxt, int64(symo))
}
ld.Cflush()
- if ld.Debug['c'] != 0 {
+ if *ld.FlagC {
fmt.Printf("textsize=%d\n", ld.Segtext.Filelen)
fmt.Printf("datsize=%d\n", ld.Segdata.Filelen)
fmt.Printf("bsssize=%d\n", ld.Segdata.Length-ld.Segdata.Filelen)
diff --git a/src/cmd/link/internal/ppc64/l.go b/src/cmd/link/internal/ppc64/l.go
index 2e5c235..f7ae33d 100644
--- a/src/cmd/link/internal/ppc64/l.go
+++ b/src/cmd/link/internal/ppc64/l.go
@@ -1,5 +1,5 @@
// Inferno utils/5l/asm.c
-// http://code.google.com/p/inferno-os/source/browse/utils/5l/asm.c
+// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5l/asm.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth at terzarima.net)
@@ -62,13 +62,13 @@ package ppc64
// THE SOFTWARE.
const (
- MaxAlign = 32 // max data alignment
- MinAlign = 1 // min data alignment
- FuncAlign = 8
+ maxAlign = 32 // max data alignment
+ minAlign = 1 // min data alignment
+ funcAlign = 8
)
/* Used by ../internal/ld/dwarf.go */
const (
- DWARFREGSP = 1
- DWARFREGLR = 65
+ dwarfRegSP = 1
+ dwarfRegLR = 65
)
diff --git a/src/cmd/link/internal/ppc64/obj.go b/src/cmd/link/internal/ppc64/obj.go
index b619eb9..6eff2f4 100644
--- a/src/cmd/link/internal/ppc64/obj.go
+++ b/src/cmd/link/internal/ppc64/obj.go
@@ -1,5 +1,5 @@
// Inferno utils/5l/obj.c
-// http://code.google.com/p/inferno-os/source/browse/utils/5l/obj.c
+// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5l/obj.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth at terzarima.net)
@@ -35,28 +35,20 @@ import (
"cmd/internal/sys"
"cmd/link/internal/ld"
"fmt"
- "log"
)
-// Reading object files.
-
-func Main() {
- linkarchinit()
- ld.Ldmain()
-}
-
-func linkarchinit() {
- if obj.Getgoarch() == "ppc64le" {
+func Init() {
+ if obj.GOARCH == "ppc64le" {
ld.SysArch = sys.ArchPPC64LE
} else {
ld.SysArch = sys.ArchPPC64
}
- ld.Thearch.Funcalign = FuncAlign
- ld.Thearch.Maxalign = MaxAlign
- ld.Thearch.Minalign = MinAlign
- ld.Thearch.Dwarfregsp = DWARFREGSP
- ld.Thearch.Dwarfreglr = DWARFREGLR
+ ld.Thearch.Funcalign = funcAlign
+ ld.Thearch.Maxalign = maxAlign
+ ld.Thearch.Minalign = minAlign
+ ld.Thearch.Dwarfregsp = dwarfRegSP
+ ld.Thearch.Dwarfreglr = dwarfRegLR
ld.Thearch.Adddynrel = adddynrel
ld.Thearch.Archinit = archinit
@@ -66,6 +58,7 @@ func linkarchinit() {
ld.Thearch.Elfreloc1 = elfreloc1
ld.Thearch.Elfsetupplt = elfsetupplt
ld.Thearch.Gentext = gentext
+ ld.Thearch.Trampoline = trampoline
ld.Thearch.Machoreloc1 = machoreloc1
if ld.SysArch == sys.ArchPPC64LE {
ld.Thearch.Lput = ld.Lputl
@@ -93,89 +86,56 @@ func linkarchinit() {
ld.Thearch.Solarisdynld = "XXX"
}
-func archinit() {
- // getgoextlinkenabled is based on GO_EXTLINK_ENABLED when
- // Go was built; see ../../make.bash.
- if ld.Linkmode == ld.LinkAuto && obj.Getgoextlinkenabled() == "0" {
- ld.Linkmode = ld.LinkInternal
- }
-
- switch ld.Buildmode {
- case ld.BuildmodePIE, ld.BuildmodeShared:
- ld.Linkmode = ld.LinkExternal
- }
-
- if ld.Linkshared {
- ld.Linkmode = ld.LinkExternal
- }
-
- if ld.Linkmode == ld.LinkExternal {
- toc := ld.Linklookup(ld.Ctxt, ".TOC.", 0)
- toc.Type = obj.SDYNIMPORT
- }
-
- switch ld.HEADTYPE {
- default:
- if ld.Linkmode == ld.LinkAuto {
- ld.Linkmode = ld.LinkInternal
- }
- if ld.Linkmode == ld.LinkExternal && obj.Getgoextlinkenabled() != "1" {
- log.Fatalf("cannot use -linkmode=external with -H %s", ld.Headstr(int(ld.HEADTYPE)))
- }
-
- case obj.Hlinux:
- break
- }
-
- switch ld.HEADTYPE {
+func archinit(ctxt *ld.Link) {
+ switch ld.Headtype {
default:
- ld.Exitf("unknown -H option: %v", ld.HEADTYPE)
+ ld.Exitf("unknown -H option: %v", ld.Headtype)
case obj.Hplan9: /* plan 9 */
ld.HEADR = 32
- if ld.INITTEXT == -1 {
- ld.INITTEXT = 4128
+ if *ld.FlagTextAddr == -1 {
+ *ld.FlagTextAddr = 4128
}
- if ld.INITDAT == -1 {
- ld.INITDAT = 0
+ if *ld.FlagDataAddr == -1 {
+ *ld.FlagDataAddr = 0
}
- if ld.INITRND == -1 {
- ld.INITRND = 4096
+ if *ld.FlagRound == -1 {
+ *ld.FlagRound = 4096
}
case obj.Hlinux: /* ppc64 elf */
if ld.SysArch == sys.ArchPPC64 {
- ld.Debug['d'] = 1 // TODO(austin): ELF ABI v1 not supported yet
+ *ld.FlagD = true // TODO(austin): ELF ABI v1 not supported yet
}
- ld.Elfinit()
+ ld.Elfinit(ctxt)
ld.HEADR = ld.ELFRESERVE
- if ld.INITTEXT == -1 {
- ld.INITTEXT = 0x10000 + int64(ld.HEADR)
+ if *ld.FlagTextAddr == -1 {
+ *ld.FlagTextAddr = 0x10000 + int64(ld.HEADR)
}
- if ld.INITDAT == -1 {
- ld.INITDAT = 0
+ if *ld.FlagDataAddr == -1 {
+ *ld.FlagDataAddr = 0
}
- if ld.INITRND == -1 {
- ld.INITRND = 0x10000
+ if *ld.FlagRound == -1 {
+ *ld.FlagRound = 0x10000
}
case obj.Hnacl:
- ld.Elfinit()
+ ld.Elfinit(ctxt)
ld.HEADR = 0x10000
ld.Funcalign = 16
- if ld.INITTEXT == -1 {
- ld.INITTEXT = 0x20000
+ if *ld.FlagTextAddr == -1 {
+ *ld.FlagTextAddr = 0x20000
}
- if ld.INITDAT == -1 {
- ld.INITDAT = 0
+ if *ld.FlagDataAddr == -1 {
+ *ld.FlagDataAddr = 0
}
- if ld.INITRND == -1 {
- ld.INITRND = 0x10000
+ if *ld.FlagRound == -1 {
+ *ld.FlagRound = 0x10000
}
}
- if ld.INITDAT != 0 && ld.INITRND != 0 {
- fmt.Printf("warning: -D0x%x is ignored because of -R0x%x\n", uint64(ld.INITDAT), uint32(ld.INITRND))
+ if *ld.FlagDataAddr != 0 && *ld.FlagRound != 0 {
+ fmt.Printf("warning: -D0x%x is ignored because of -R0x%x\n", uint64(*ld.FlagDataAddr), uint32(*ld.FlagRound))
}
}
diff --git a/src/cmd/link/internal/s390x/asm.go b/src/cmd/link/internal/s390x/asm.go
index 9864749..4a5f48c 100644
--- a/src/cmd/link/internal/s390x/asm.go
+++ b/src/cmd/link/internal/s390x/asm.go
@@ -1,5 +1,5 @@
// Inferno utils/5l/asm.c
-// http://code.google.com/p/inferno-os/source/browse/utils/5l/asm.c
+// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5l/asm.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth at terzarima.net)
@@ -47,102 +47,101 @@ import (
// undef
//
// The job of appending the moduledata is delegated to runtime.addmoduledata.
-func gentext() {
- if !ld.DynlinkingGo() {
+func gentext(ctxt *ld.Link) {
+ if !ctxt.DynlinkingGo() {
return
}
- addmoduledata := ld.Linklookup(ld.Ctxt, "runtime.addmoduledata", 0)
+ addmoduledata := ctxt.Syms.Lookup("runtime.addmoduledata", 0)
if addmoduledata.Type == obj.STEXT {
// we're linking a module containing the runtime -> no need for
// an init function
return
}
addmoduledata.Attr |= ld.AttrReachable
- initfunc := ld.Linklookup(ld.Ctxt, "go.link.addmoduledata", 0)
+ initfunc := ctxt.Syms.Lookup("go.link.addmoduledata", 0)
initfunc.Type = obj.STEXT
initfunc.Attr |= ld.AttrLocal
initfunc.Attr |= ld.AttrReachable
// larl %r2, <local.moduledata>
- ld.Adduint8(ld.Ctxt, initfunc, 0xc0)
- ld.Adduint8(ld.Ctxt, initfunc, 0x20)
+ ld.Adduint8(ctxt, initfunc, 0xc0)
+ ld.Adduint8(ctxt, initfunc, 0x20)
lmd := ld.Addrel(initfunc)
lmd.Off = int32(initfunc.Size)
lmd.Siz = 4
- lmd.Sym = ld.Ctxt.Moduledata
+ lmd.Sym = ctxt.Moduledata
lmd.Type = obj.R_PCREL
lmd.Variant = ld.RV_390_DBL
lmd.Add = 2 + int64(lmd.Siz)
- ld.Adduint32(ld.Ctxt, initfunc, 0)
+ ld.Adduint32(ctxt, initfunc, 0)
// jg <runtime.addmoduledata[@plt]>
- ld.Adduint8(ld.Ctxt, initfunc, 0xc0)
- ld.Adduint8(ld.Ctxt, initfunc, 0xf4)
+ ld.Adduint8(ctxt, initfunc, 0xc0)
+ ld.Adduint8(ctxt, initfunc, 0xf4)
rel := ld.Addrel(initfunc)
rel.Off = int32(initfunc.Size)
rel.Siz = 4
- rel.Sym = ld.Linklookup(ld.Ctxt, "runtime.addmoduledata", 0)
+ rel.Sym = ctxt.Syms.Lookup("runtime.addmoduledata", 0)
rel.Type = obj.R_CALL
rel.Variant = ld.RV_390_DBL
rel.Add = 2 + int64(rel.Siz)
- ld.Adduint32(ld.Ctxt, initfunc, 0)
+ ld.Adduint32(ctxt, initfunc, 0)
// undef (for debugging)
- ld.Adduint32(ld.Ctxt, initfunc, 0)
+ ld.Adduint32(ctxt, initfunc, 0)
- ld.Ctxt.Textp = append(ld.Ctxt.Textp, initfunc)
- initarray_entry := ld.Linklookup(ld.Ctxt, "go.link.addmoduledatainit", 0)
+ 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
- ld.Addaddr(ld.Ctxt, initarray_entry, initfunc)
+ ld.Addaddr(ctxt, initarray_entry, initfunc)
}
-func adddynrel(s *ld.LSym, r *ld.Reloc) {
+func adddynrel(ctxt *ld.Link, s *ld.Symbol, r *ld.Reloc) bool {
targ := r.Sym
- ld.Ctxt.Cursym = s
switch r.Type {
default:
if r.Type >= 256 {
- ld.Diag("unexpected relocation type %d", r.Type)
- return
+ ld.Errorf(s, "unexpected relocation type %d", r.Type)
+ return false
}
// Handle relocations found in ELF object files.
case 256 + ld.R_390_12,
256 + ld.R_390_GOT12:
- ld.Diag("s390x 12-bit relocations have not been implemented (relocation type %d)", r.Type-256)
- return
+ ld.Errorf(s, "s390x 12-bit relocations have not been implemented (relocation type %d)", r.Type-256)
+ return false
case 256 + ld.R_390_8,
256 + ld.R_390_16,
256 + ld.R_390_32,
256 + ld.R_390_64:
if targ.Type == obj.SDYNIMPORT {
- ld.Diag("unexpected R_390_nn relocation for dynamic symbol %s", targ.Name)
+ ld.Errorf(s, "unexpected R_390_nn relocation for dynamic symbol %s", targ.Name)
}
r.Type = obj.R_ADDR
- return
+ return true
case 256 + ld.R_390_PC16,
256 + ld.R_390_PC32,
256 + ld.R_390_PC64:
if targ.Type == obj.SDYNIMPORT {
- ld.Diag("unexpected R_390_PCnn relocation for dynamic symbol %s", targ.Name)
+ ld.Errorf(s, "unexpected R_390_PCnn relocation for dynamic symbol %s", targ.Name)
}
if targ.Type == 0 || targ.Type == obj.SXREF {
- ld.Diag("unknown symbol %s in pcrel", targ.Name)
+ ld.Errorf(s, "unknown symbol %s in pcrel", targ.Name)
}
r.Type = obj.R_PCREL
r.Add += int64(r.Siz)
- return
+ return true
case 256 + ld.R_390_GOT16,
256 + ld.R_390_GOT32,
256 + ld.R_390_GOT64:
- ld.Diag("unimplemented S390x relocation: %v", r.Type-256)
- return
+ ld.Errorf(s, "unimplemented S390x relocation: %v", r.Type-256)
+ return true
case 256 + ld.R_390_PLT16DBL,
256 + ld.R_390_PLT32DBL:
@@ -150,47 +149,51 @@ func adddynrel(s *ld.LSym, r *ld.Reloc) {
r.Variant = ld.RV_390_DBL
r.Add += int64(r.Siz)
if targ.Type == obj.SDYNIMPORT {
- addpltsym(ld.Ctxt, targ)
- r.Sym = ld.Linklookup(ld.Ctxt, ".plt", 0)
+ addpltsym(ctxt, targ)
+ r.Sym = ctxt.Syms.Lookup(".plt", 0)
r.Add += int64(targ.Plt)
}
- return
+ return true
case 256 + ld.R_390_PLT32,
256 + ld.R_390_PLT64:
r.Type = obj.R_PCREL
r.Add += int64(r.Siz)
if targ.Type == obj.SDYNIMPORT {
- addpltsym(ld.Ctxt, targ)
- r.Sym = ld.Linklookup(ld.Ctxt, ".plt", 0)
+ addpltsym(ctxt, targ)
+ r.Sym = ctxt.Syms.Lookup(".plt", 0)
r.Add += int64(targ.Plt)
}
- return
+ return true
case 256 + ld.R_390_COPY:
- ld.Diag("unimplemented S390x relocation: %v", r.Type-256)
+ ld.Errorf(s, "unimplemented S390x relocation: %v", r.Type-256)
+ return false
case 256 + ld.R_390_GLOB_DAT:
- ld.Diag("unimplemented S390x relocation: %v", r.Type-256)
+ ld.Errorf(s, "unimplemented S390x relocation: %v", r.Type-256)
+ return false
case 256 + ld.R_390_JMP_SLOT:
- ld.Diag("unimplemented S390x relocation: %v", r.Type-256)
+ ld.Errorf(s, "unimplemented S390x relocation: %v", r.Type-256)
+ return false
case 256 + ld.R_390_RELATIVE:
- ld.Diag("unimplemented S390x relocation: %v", r.Type-256)
+ ld.Errorf(s, "unimplemented S390x relocation: %v", r.Type-256)
+ return false
case 256 + ld.R_390_GOTOFF:
if targ.Type == obj.SDYNIMPORT {
- ld.Diag("unexpected R_390_GOTOFF relocation for dynamic symbol %s", targ.Name)
+ ld.Errorf(s, "unexpected R_390_GOTOFF relocation for dynamic symbol %s", targ.Name)
}
r.Type = obj.R_GOTOFF
- return
+ return true
case 256 + ld.R_390_GOTPC:
r.Type = obj.R_PCREL
- r.Sym = ld.Linklookup(ld.Ctxt, ".got", 0)
+ r.Sym = ctxt.Syms.Lookup(".got", 0)
r.Add += int64(r.Siz)
- return
+ return true
case 256 + ld.R_390_PC16DBL,
256 + ld.R_390_PC32DBL:
@@ -198,36 +201,36 @@ func adddynrel(s *ld.LSym, r *ld.Reloc) {
r.Variant = ld.RV_390_DBL
r.Add += int64(r.Siz)
if targ.Type == obj.SDYNIMPORT {
- ld.Diag("unexpected R_390_PCnnDBL relocation for dynamic symbol %s", targ.Name)
+ ld.Errorf(s, "unexpected R_390_PCnnDBL relocation for dynamic symbol %s", targ.Name)
}
- return
+ return true
case 256 + ld.R_390_GOTPCDBL:
r.Type = obj.R_PCREL
r.Variant = ld.RV_390_DBL
- r.Sym = ld.Linklookup(ld.Ctxt, ".got", 0)
+ r.Sym = ctxt.Syms.Lookup(".got", 0)
r.Add += int64(r.Siz)
- return
+ return true
case 256 + ld.R_390_GOTENT:
- addgotsym(targ)
+ addgotsym(ctxt, targ)
r.Type = obj.R_PCREL
r.Variant = ld.RV_390_DBL
- r.Sym = ld.Linklookup(ld.Ctxt, ".got", 0)
+ r.Sym = ctxt.Syms.Lookup(".got", 0)
r.Add += int64(targ.Got)
r.Add += int64(r.Siz)
- return
+ return true
}
// Handle references to ELF symbols from our own object files.
if targ.Type != obj.SDYNIMPORT {
- return
+ return true
}
- ld.Diag("unsupported relocation for dynamic symbol %s (type=%d stype=%d)", targ.Name, r.Type, targ.Type)
+ return false
}
-func elfreloc1(r *ld.Reloc, sectoff int64) int {
+func elfreloc1(ctxt *ld.Link, r *ld.Reloc, sectoff int64) int {
ld.Thearch.Vput(uint64(sectoff))
elfsym := r.Xsym.ElfsymForReloc()
@@ -326,61 +329,61 @@ func elfreloc1(r *ld.Reloc, sectoff int64) int {
return 0
}
-func elfsetupplt() {
- plt := ld.Linklookup(ld.Ctxt, ".plt", 0)
- got := ld.Linklookup(ld.Ctxt, ".got", 0)
+func elfsetupplt(ctxt *ld.Link) {
+ plt := ctxt.Syms.Lookup(".plt", 0)
+ got := ctxt.Syms.Lookup(".got", 0)
if plt.Size == 0 {
// stg %r1,56(%r15)
- ld.Adduint8(ld.Ctxt, plt, 0xe3)
- ld.Adduint8(ld.Ctxt, plt, 0x10)
- ld.Adduint8(ld.Ctxt, plt, 0xf0)
- ld.Adduint8(ld.Ctxt, plt, 0x38)
- ld.Adduint8(ld.Ctxt, plt, 0x00)
- ld.Adduint8(ld.Ctxt, plt, 0x24)
+ ld.Adduint8(ctxt, plt, 0xe3)
+ ld.Adduint8(ctxt, plt, 0x10)
+ ld.Adduint8(ctxt, plt, 0xf0)
+ ld.Adduint8(ctxt, plt, 0x38)
+ ld.Adduint8(ctxt, plt, 0x00)
+ ld.Adduint8(ctxt, plt, 0x24)
// larl %r1,_GLOBAL_OFFSET_TABLE_
- ld.Adduint8(ld.Ctxt, plt, 0xc0)
- ld.Adduint8(ld.Ctxt, plt, 0x10)
- ld.Addpcrelplus(ld.Ctxt, plt, got, 6)
+ ld.Adduint8(ctxt, plt, 0xc0)
+ ld.Adduint8(ctxt, plt, 0x10)
+ ld.Addpcrelplus(ctxt, plt, got, 6)
// mvc 48(8,%r15),8(%r1)
- ld.Adduint8(ld.Ctxt, plt, 0xd2)
- ld.Adduint8(ld.Ctxt, plt, 0x07)
- ld.Adduint8(ld.Ctxt, plt, 0xf0)
- ld.Adduint8(ld.Ctxt, plt, 0x30)
- ld.Adduint8(ld.Ctxt, plt, 0x10)
- ld.Adduint8(ld.Ctxt, plt, 0x08)
+ ld.Adduint8(ctxt, plt, 0xd2)
+ ld.Adduint8(ctxt, plt, 0x07)
+ ld.Adduint8(ctxt, plt, 0xf0)
+ ld.Adduint8(ctxt, plt, 0x30)
+ ld.Adduint8(ctxt, plt, 0x10)
+ ld.Adduint8(ctxt, plt, 0x08)
// lg %r1,16(%r1)
- ld.Adduint8(ld.Ctxt, plt, 0xe3)
- ld.Adduint8(ld.Ctxt, plt, 0x10)
- ld.Adduint8(ld.Ctxt, plt, 0x10)
- ld.Adduint8(ld.Ctxt, plt, 0x10)
- ld.Adduint8(ld.Ctxt, plt, 0x00)
- ld.Adduint8(ld.Ctxt, plt, 0x04)
+ ld.Adduint8(ctxt, plt, 0xe3)
+ ld.Adduint8(ctxt, plt, 0x10)
+ ld.Adduint8(ctxt, plt, 0x10)
+ ld.Adduint8(ctxt, plt, 0x10)
+ ld.Adduint8(ctxt, plt, 0x00)
+ ld.Adduint8(ctxt, plt, 0x04)
// br %r1
- ld.Adduint8(ld.Ctxt, plt, 0x07)
- ld.Adduint8(ld.Ctxt, plt, 0xf1)
+ ld.Adduint8(ctxt, plt, 0x07)
+ ld.Adduint8(ctxt, plt, 0xf1)
// nopr %r0
- ld.Adduint8(ld.Ctxt, plt, 0x07)
- ld.Adduint8(ld.Ctxt, plt, 0x00)
+ ld.Adduint8(ctxt, plt, 0x07)
+ ld.Adduint8(ctxt, plt, 0x00)
// nopr %r0
- ld.Adduint8(ld.Ctxt, plt, 0x07)
- ld.Adduint8(ld.Ctxt, plt, 0x00)
+ ld.Adduint8(ctxt, plt, 0x07)
+ ld.Adduint8(ctxt, plt, 0x00)
// nopr %r0
- ld.Adduint8(ld.Ctxt, plt, 0x07)
- ld.Adduint8(ld.Ctxt, plt, 0x00)
+ ld.Adduint8(ctxt, plt, 0x07)
+ ld.Adduint8(ctxt, plt, 0x00)
// assume got->size == 0 too
- ld.Addaddrplus(ld.Ctxt, got, ld.Linklookup(ld.Ctxt, ".dynamic", 0), 0)
+ ld.Addaddrplus(ctxt, got, ctxt.Syms.Lookup(".dynamic", 0), 0)
- ld.Adduint64(ld.Ctxt, got, 0)
- ld.Adduint64(ld.Ctxt, got, 0)
+ ld.Adduint64(ctxt, got, 0)
+ ld.Adduint64(ctxt, got, 0)
}
}
-func machoreloc1(r *ld.Reloc, sectoff int64) int {
+func machoreloc1(s *ld.Symbol, r *ld.Reloc, sectoff int64) int {
return -1
}
-func archreloc(r *ld.Reloc, s *ld.LSym, val *int64) int {
+func archreloc(ctxt *ld.Link, r *ld.Reloc, s *ld.Symbol, val *int64) int {
if ld.Linkmode == ld.LinkExternal {
return -1
}
@@ -391,17 +394,17 @@ func archreloc(r *ld.Reloc, s *ld.LSym, val *int64) int {
return 0
case obj.R_GOTOFF:
- *val = ld.Symaddr(r.Sym) + r.Add - ld.Symaddr(ld.Linklookup(ld.Ctxt, ".got", 0))
+ *val = ld.Symaddr(r.Sym) + r.Add - ld.Symaddr(ctxt.Syms.Lookup(".got", 0))
return 0
}
return -1
}
-func archrelocvariant(r *ld.Reloc, s *ld.LSym, t int64) int64 {
+func archrelocvariant(ctxt *ld.Link, r *ld.Reloc, s *ld.Symbol, t int64) int64 {
switch r.Variant & ld.RV_TYPE_MASK {
default:
- ld.Diag("unexpected relocation variant %d", r.Variant)
+ ld.Errorf(s, "unexpected relocation variant %d", r.Variant)
return t
case ld.RV_NONE:
@@ -409,13 +412,13 @@ func archrelocvariant(r *ld.Reloc, s *ld.LSym, t int64) int64 {
case ld.RV_390_DBL:
if (t & 1) != 0 {
- ld.Diag("%s+%v is not 2-byte aligned", r.Sym.Name, r.Sym.Value)
+ ld.Errorf(s, "%s+%v is not 2-byte aligned", r.Sym.Name, r.Sym.Value)
}
return t >> 1
}
}
-func addpltsym(ctxt *ld.Link, s *ld.LSym) {
+func addpltsym(ctxt *ld.Link, s *ld.Symbol) {
if s.Plt >= 0 {
return
}
@@ -423,11 +426,11 @@ func addpltsym(ctxt *ld.Link, s *ld.LSym) {
ld.Adddynsym(ctxt, s)
if ld.Iself {
- plt := ld.Linklookup(ctxt, ".plt", 0)
- got := ld.Linklookup(ctxt, ".got", 0)
- rela := ld.Linklookup(ctxt, ".rela.plt", 0)
+ plt := ctxt.Syms.Lookup(".plt", 0)
+ got := ctxt.Syms.Lookup(".got", 0)
+ rela := ctxt.Syms.Lookup(".rela.plt", 0)
if plt.Size == 0 {
- elfsetupplt()
+ elfsetupplt(ctxt)
}
// larl %r1,_GLOBAL_OFFSET_TABLE_+index
@@ -474,35 +477,34 @@ func addpltsym(ctxt *ld.Link, s *ld.LSym) {
s.Plt = int32(plt.Size - 32)
} else {
- ld.Diag("addpltsym: unsupported binary format")
+ ld.Errorf(s, "addpltsym: unsupported binary format")
}
}
-func addgotsym(s *ld.LSym) {
+func addgotsym(ctxt *ld.Link, s *ld.Symbol) {
if s.Got >= 0 {
return
}
- ld.Adddynsym(ld.Ctxt, s)
- got := ld.Linklookup(ld.Ctxt, ".got", 0)
+ ld.Adddynsym(ctxt, s)
+ got := ctxt.Syms.Lookup(".got", 0)
s.Got = int32(got.Size)
- ld.Adduint64(ld.Ctxt, got, 0)
+ ld.Adduint64(ctxt, got, 0)
if ld.Iself {
- rela := ld.Linklookup(ld.Ctxt, ".rela", 0)
- ld.Addaddrplus(ld.Ctxt, rela, got, int64(s.Got))
- ld.Adduint64(ld.Ctxt, rela, ld.ELF64_R_INFO(uint32(s.Dynid), ld.R_390_GLOB_DAT))
- ld.Adduint64(ld.Ctxt, rela, 0)
+ rela := ctxt.Syms.Lookup(".rela", 0)
+ ld.Addaddrplus(ctxt, rela, got, int64(s.Got))
+ ld.Adduint64(ctxt, rela, ld.ELF64_R_INFO(uint32(s.Dynid), ld.R_390_GLOB_DAT))
+ ld.Adduint64(ctxt, rela, 0)
} else {
- ld.Diag("addgotsym: unsupported binary format")
+ ld.Errorf(s, "addgotsym: unsupported binary format")
}
}
-func asmb() {
- if ld.Debug['v'] != 0 {
- fmt.Fprintf(ld.Bso, "%5.2f asmb\n", obj.Cputime())
+func asmb(ctxt *ld.Link) {
+ if ctxt.Debugvlog != 0 {
+ ctxt.Logf("%5.2f asmb\n", obj.Cputime())
}
- ld.Bso.Flush()
if ld.Iself {
ld.Asmbelfsetup()
@@ -510,81 +512,82 @@ func asmb() {
sect := ld.Segtext.Sect
ld.Cseek(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
- ld.Codeblk(int64(sect.Vaddr), int64(sect.Length))
+ ld.Codeblk(ctxt, int64(sect.Vaddr), int64(sect.Length))
for sect = sect.Next; sect != nil; sect = sect.Next {
ld.Cseek(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
- ld.Datblk(int64(sect.Vaddr), int64(sect.Length))
+ ld.Datblk(ctxt, int64(sect.Vaddr), int64(sect.Length))
}
if ld.Segrodata.Filelen > 0 {
- if ld.Debug['v'] != 0 {
- fmt.Fprintf(ld.Bso, "%5.2f rodatblk\n", obj.Cputime())
+ if ctxt.Debugvlog != 0 {
+ ctxt.Logf("%5.2f rodatblk\n", obj.Cputime())
}
- ld.Bso.Flush()
-
ld.Cseek(int64(ld.Segrodata.Fileoff))
- ld.Datblk(int64(ld.Segrodata.Vaddr), int64(ld.Segrodata.Filelen))
+ 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())
+ }
+ ld.Cseek(int64(ld.Segrelrodata.Fileoff))
+ ld.Datblk(ctxt, int64(ld.Segrelrodata.Vaddr), int64(ld.Segrelrodata.Filelen))
}
- if ld.Debug['v'] != 0 {
- fmt.Fprintf(ld.Bso, "%5.2f datblk\n", obj.Cputime())
+ if ctxt.Debugvlog != 0 {
+ ctxt.Logf("%5.2f datblk\n", obj.Cputime())
}
- ld.Bso.Flush()
ld.Cseek(int64(ld.Segdata.Fileoff))
- ld.Datblk(int64(ld.Segdata.Vaddr), int64(ld.Segdata.Filelen))
+ ld.Datblk(ctxt, int64(ld.Segdata.Vaddr), int64(ld.Segdata.Filelen))
ld.Cseek(int64(ld.Segdwarf.Fileoff))
- ld.Dwarfblk(int64(ld.Segdwarf.Vaddr), int64(ld.Segdwarf.Filelen))
+ ld.Dwarfblk(ctxt, int64(ld.Segdwarf.Vaddr), int64(ld.Segdwarf.Filelen))
/* output symbol table */
ld.Symsize = 0
ld.Lcsize = 0
symo := uint32(0)
- if ld.Debug['s'] == 0 {
+ if !*ld.FlagS {
if !ld.Iself {
- ld.Diag("unsupported executable format")
+ ld.Errorf(nil, "unsupported executable format")
}
- if ld.Debug['v'] != 0 {
- fmt.Fprintf(ld.Bso, "%5.2f sym\n", obj.Cputime())
+ if ctxt.Debugvlog != 0 {
+ ctxt.Logf("%5.2f sym\n", obj.Cputime())
}
- ld.Bso.Flush()
symo = uint32(ld.Segdwarf.Fileoff + ld.Segdwarf.Filelen)
- symo = uint32(ld.Rnd(int64(symo), int64(ld.INITRND)))
+ symo = uint32(ld.Rnd(int64(symo), int64(*ld.FlagRound)))
ld.Cseek(int64(symo))
- if ld.Debug['v'] != 0 {
- fmt.Fprintf(ld.Bso, "%5.2f elfsym\n", obj.Cputime())
+ if ctxt.Debugvlog != 0 {
+ ctxt.Logf("%5.2f elfsym\n", obj.Cputime())
}
- ld.Asmelfsym()
+ ld.Asmelfsym(ctxt)
ld.Cflush()
ld.Cwrite(ld.Elfstrdat)
- if ld.Debug['v'] != 0 {
- fmt.Fprintf(ld.Bso, "%5.2f dwarf\n", obj.Cputime())
+ if ctxt.Debugvlog != 0 {
+ ctxt.Logf("%5.2f dwarf\n", obj.Cputime())
}
if ld.Linkmode == ld.LinkExternal {
- ld.Elfemitreloc()
+ ld.Elfemitreloc(ctxt)
}
}
- ld.Ctxt.Cursym = nil
- if ld.Debug['v'] != 0 {
- fmt.Fprintf(ld.Bso, "%5.2f header\n", obj.Cputime())
+ if ctxt.Debugvlog != 0 {
+ ctxt.Logf("%5.2f header\n", obj.Cputime())
}
- ld.Bso.Flush()
ld.Cseek(0)
- switch ld.HEADTYPE {
+ switch ld.Headtype {
default:
- ld.Diag("unsupported operating system")
+ ld.Errorf(nil, "unsupported operating system")
case obj.Hlinux:
- ld.Asmbelf(int64(symo))
+ ld.Asmbelf(ctxt, int64(symo))
}
ld.Cflush()
- if ld.Debug['c'] != 0 {
+ if *ld.FlagC {
fmt.Printf("textsize=%d\n", ld.Segtext.Filelen)
fmt.Printf("datsize=%d\n", ld.Segdata.Filelen)
fmt.Printf("bsssize=%d\n", ld.Segdata.Length-ld.Segdata.Filelen)
diff --git a/src/cmd/link/internal/s390x/l.go b/src/cmd/link/internal/s390x/l.go
index 7c92bdb..87d10ee 100644
--- a/src/cmd/link/internal/s390x/l.go
+++ b/src/cmd/link/internal/s390x/l.go
@@ -1,5 +1,5 @@
// Inferno utils/5l/asm.c
-// http://code.google.com/p/inferno-os/source/browse/utils/5l/asm.c
+// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5l/asm.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth at terzarima.net)
@@ -62,13 +62,13 @@ package s390x
// THE SOFTWARE.
const (
- MaxAlign = 32 // max data alignment
- MinAlign = 2 // min data alignment
- FuncAlign = 16
+ maxAlign = 32 // max data alignment
+ minAlign = 2 // min data alignment
+ funcAlign = 16
)
/* Used by ../internal/ld/dwarf.go */
const (
- DWARFREGSP = 15
- DWARFREGLR = 14
+ dwarfRegSP = 15
+ dwarfRegLR = 14
)
diff --git a/src/cmd/link/internal/s390x/obj.go b/src/cmd/link/internal/s390x/obj.go
index b77f57d..eea8978 100644
--- a/src/cmd/link/internal/s390x/obj.go
+++ b/src/cmd/link/internal/s390x/obj.go
@@ -1,5 +1,5 @@
// Inferno utils/5l/obj.c
-// http://code.google.com/p/inferno-os/source/browse/utils/5l/obj.c
+// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5l/obj.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth at terzarima.net)
@@ -37,21 +37,14 @@ import (
"fmt"
)
-// Reading object files.
-
-func Main() {
- linkarchinit()
- ld.Ldmain()
-}
-
-func linkarchinit() {
+func Init() {
ld.SysArch = sys.ArchS390X
- ld.Thearch.Funcalign = FuncAlign
- ld.Thearch.Maxalign = MaxAlign
- ld.Thearch.Minalign = MinAlign
- ld.Thearch.Dwarfregsp = DWARFREGSP
- ld.Thearch.Dwarfreglr = DWARFREGLR
+ ld.Thearch.Funcalign = funcAlign
+ ld.Thearch.Maxalign = maxAlign
+ ld.Thearch.Minalign = minAlign
+ ld.Thearch.Dwarfregsp = dwarfRegSP
+ ld.Thearch.Dwarfreglr = dwarfRegLR
ld.Thearch.Adddynrel = adddynrel
ld.Thearch.Archinit = archinit
@@ -79,36 +72,26 @@ func linkarchinit() {
ld.Thearch.Solarisdynld = "XXX"
}
-func archinit() {
- // getgoextlinkenabled is based on GO_EXTLINK_ENABLED when
- // Go was built; see ../../make.bash.
- if ld.Linkmode == ld.LinkAuto && obj.Getgoextlinkenabled() == "0" {
- ld.Linkmode = ld.LinkInternal
- }
-
- if ld.Buildmode == ld.BuildmodeCArchive || ld.Buildmode == ld.BuildmodeCShared || ld.DynlinkingGo() {
- ld.Linkmode = ld.LinkExternal
- }
-
- switch ld.HEADTYPE {
+func archinit(ctxt *ld.Link) {
+ switch ld.Headtype {
default:
- ld.Exitf("unknown -H option: %v", ld.HEADTYPE)
+ ld.Exitf("unknown -H option: %v", ld.Headtype)
case obj.Hlinux: // s390x ELF
- ld.Elfinit()
+ ld.Elfinit(ctxt)
ld.HEADR = ld.ELFRESERVE
- if ld.INITTEXT == -1 {
- ld.INITTEXT = 0x10000 + int64(ld.HEADR)
+ if *ld.FlagTextAddr == -1 {
+ *ld.FlagTextAddr = 0x10000 + int64(ld.HEADR)
}
- if ld.INITDAT == -1 {
- ld.INITDAT = 0
+ if *ld.FlagDataAddr == -1 {
+ *ld.FlagDataAddr = 0
}
- if ld.INITRND == -1 {
- ld.INITRND = 0x10000
+ if *ld.FlagRound == -1 {
+ *ld.FlagRound = 0x10000
}
}
- if ld.INITDAT != 0 && ld.INITRND != 0 {
- fmt.Printf("warning: -D0x%x is ignored because of -R0x%x\n", uint64(ld.INITDAT), uint32(ld.INITRND))
+ if *ld.FlagDataAddr != 0 && *ld.FlagRound != 0 {
+ fmt.Printf("warning: -D0x%x is ignored because of -R0x%x\n", uint64(*ld.FlagDataAddr), uint32(*ld.FlagRound))
}
}
diff --git a/src/cmd/link/internal/x86/asm.go b/src/cmd/link/internal/x86/asm.go
index cc8f96f..af702c2 100644
--- a/src/cmd/link/internal/x86/asm.go
+++ b/src/cmd/link/internal/x86/asm.go
@@ -1,5 +1,5 @@
// Inferno utils/8l/asm.c
-// http://code.google.com/p/inferno-os/source/browse/utils/8l/asm.c
+// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/8l/asm.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth at terzarima.net)
@@ -33,16 +33,15 @@ package x86
import (
"cmd/internal/obj"
"cmd/link/internal/ld"
- "fmt"
"log"
)
// Append 4 bytes to s and create a R_CALL relocation targeting t to fill them in.
-func addcall(ctxt *ld.Link, s *ld.LSym, t *ld.LSym) {
+func addcall(ctxt *ld.Link, s *ld.Symbol, t *ld.Symbol) {
s.Attr |= ld.AttrReachable
i := s.Size
s.Size += 4
- ld.Symgrow(ctxt, s, s.Size)
+ ld.Symgrow(s, s.Size)
r := ld.Addrel(s)
r.Sym = t
r.Off = int32(i)
@@ -50,29 +49,58 @@ func addcall(ctxt *ld.Link, s *ld.LSym, t *ld.LSym) {
r.Siz = 4
}
-func gentext() {
- if !ld.DynlinkingGo() && ld.Buildmode != ld.BuildmodePIE && ld.Buildmode != ld.BuildmodeCShared {
- return
+func gentext(ctxt *ld.Link) {
+ if ctxt.DynlinkingGo() {
+ // We need get_pc_thunk.
+ } else {
+ switch ld.Buildmode {
+ case ld.BuildmodeCArchive:
+ if !ld.Iself {
+ return
+ }
+ case ld.BuildmodePIE, ld.BuildmodeCShared, ld.BuildmodePlugin:
+ // We need get_pc_thunk.
+ default:
+ return
+ }
}
- thunkfunc := ld.Linklookup(ld.Ctxt, "__x86.get_pc_thunk.cx", 0)
- thunkfunc.Type = obj.STEXT
- thunkfunc.Attr |= ld.AttrLocal
- thunkfunc.Attr |= ld.AttrReachable
- o := func(op ...uint8) {
- for _, op1 := range op {
- ld.Adduint8(ld.Ctxt, thunkfunc, op1)
+ // Generate little thunks that load the PC of the next instruction into a register.
+ thunks := make([]*ld.Symbol, 0, 7+len(ctxt.Textp))
+ for _, r := range [...]struct {
+ name string
+ num uint8
+ }{
+ {"ax", 0},
+ {"cx", 1},
+ {"dx", 2},
+ {"bx", 3},
+ // sp
+ {"bp", 5},
+ {"si", 6},
+ {"di", 7},
+ } {
+ thunkfunc := ctxt.Syms.Lookup("__x86.get_pc_thunk."+r.name, 0)
+ thunkfunc.Type = obj.STEXT
+ thunkfunc.Attr |= ld.AttrLocal
+ thunkfunc.Attr |= ld.AttrReachable //TODO: remove?
+ o := func(op ...uint8) {
+ for _, op1 := range op {
+ ld.Adduint8(ctxt, thunkfunc, op1)
+ }
}
- }
- // 8b 0c 24 mov (%esp),%ecx
- o(0x8b, 0x0c, 0x24)
- // c3 ret
- o(0xc3)
+ // 8b 04 24 mov (%esp),%eax
+ // Destination register is in bits 3-5 of the middle byte, so add that in.
+ o(0x8b, 0x04+r.num<<3, 0x24)
+ // c3 ret
+ o(0xc3)
- ld.Ctxt.Textp = append(ld.Ctxt.Textp, thunkfunc)
+ thunks = append(thunks, thunkfunc)
+ }
+ ctxt.Textp = append(thunks, ctxt.Textp...) // keep Textp in dependency order
- addmoduledata := ld.Linklookup(ld.Ctxt, "runtime.addmoduledata", 0)
- if addmoduledata.Type == obj.STEXT {
+ addmoduledata := ctxt.Syms.Lookup("runtime.addmoduledata", 0)
+ if addmoduledata.Type == obj.STEXT && ld.Buildmode != ld.BuildmodePlugin {
// we're linking a module containing the runtime -> no need for
// an init function
return
@@ -80,20 +108,20 @@ func gentext() {
addmoduledata.Attr |= ld.AttrReachable
- initfunc := ld.Linklookup(ld.Ctxt, "go.link.addmoduledata", 0)
+ initfunc := ctxt.Syms.Lookup("go.link.addmoduledata", 0)
initfunc.Type = obj.STEXT
initfunc.Attr |= ld.AttrLocal
initfunc.Attr |= ld.AttrReachable
- o = func(op ...uint8) {
+ o := func(op ...uint8) {
for _, op1 := range op {
- ld.Adduint8(ld.Ctxt, initfunc, op1)
+ ld.Adduint8(ctxt, initfunc, op1)
}
}
// go.link.addmoduledata:
// 53 push %ebx
// e8 00 00 00 00 call __x86.get_pc_thunk.cx + R_CALL __x86.get_pc_thunk.cx
- // 8d 81 00 00 00 00 lea 0x0(%ecx), %eax + R_PCREL ld.Ctxt.Moduledata
+ // 8d 81 00 00 00 00 lea 0x0(%ecx), %eax + R_PCREL ctxt.Moduledata
// 8d 99 00 00 00 00 lea 0x0(%ecx), %ebx + R_GOTPC _GLOBAL_OFFSET_TABLE_
// e8 00 00 00 00 call runtime.addmoduledata at plt + R_CALL runtime.addmoduledata
// 5b pop %ebx
@@ -102,70 +130,72 @@ func gentext() {
o(0x53)
o(0xe8)
- addcall(ld.Ctxt, initfunc, ld.Linklookup(ld.Ctxt, "__x86.get_pc_thunk.cx", 0))
+ addcall(ctxt, initfunc, ctxt.Syms.Lookup("__x86.get_pc_thunk.cx", 0))
o(0x8d, 0x81)
- ld.Addpcrelplus(ld.Ctxt, initfunc, ld.Ctxt.Moduledata, 6)
+ ld.Addpcrelplus(ctxt, initfunc, ctxt.Moduledata, 6)
o(0x8d, 0x99)
i := initfunc.Size
initfunc.Size += 4
- ld.Symgrow(ld.Ctxt, initfunc, initfunc.Size)
+ ld.Symgrow(initfunc, initfunc.Size)
r := ld.Addrel(initfunc)
- r.Sym = ld.Linklookup(ld.Ctxt, "_GLOBAL_OFFSET_TABLE_", 0)
+ r.Sym = ctxt.Syms.Lookup("_GLOBAL_OFFSET_TABLE_", 0)
r.Off = int32(i)
r.Type = obj.R_PCREL
r.Add = 12
r.Siz = 4
o(0xe8)
- addcall(ld.Ctxt, initfunc, addmoduledata)
+ addcall(ctxt, initfunc, addmoduledata)
o(0x5b)
o(0xc3)
- ld.Ctxt.Textp = append(ld.Ctxt.Textp, initfunc)
- initarray_entry := ld.Linklookup(ld.Ctxt, "go.link.addmoduledatainit", 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.AttrReachable
initarray_entry.Attr |= ld.AttrLocal
initarray_entry.Type = obj.SINITARR
- ld.Addaddr(ld.Ctxt, initarray_entry, initfunc)
+ ld.Addaddr(ctxt, initarray_entry, initfunc)
}
-func adddynrel(s *ld.LSym, r *ld.Reloc) {
+func adddynrel(ctxt *ld.Link, s *ld.Symbol, r *ld.Reloc) bool {
targ := r.Sym
- ld.Ctxt.Cursym = s
switch r.Type {
default:
if r.Type >= 256 {
- ld.Diag("unexpected relocation type %d", r.Type)
- return
+ ld.Errorf(s, "unexpected relocation type %d", r.Type)
+ return false
}
// Handle relocations found in ELF object files.
case 256 + ld.R_386_PC32:
if targ.Type == obj.SDYNIMPORT {
- ld.Diag("unexpected R_386_PC32 relocation for dynamic symbol %s", targ.Name)
+ ld.Errorf(s, "unexpected R_386_PC32 relocation for dynamic symbol %s", targ.Name)
}
if targ.Type == 0 || targ.Type == obj.SXREF {
- ld.Diag("unknown symbol %s in pcrel", targ.Name)
+ ld.Errorf(s, "unknown symbol %s in pcrel", targ.Name)
}
r.Type = obj.R_PCREL
r.Add += 4
- return
+ return true
case 256 + ld.R_386_PLT32:
r.Type = obj.R_PCREL
r.Add += 4
if targ.Type == obj.SDYNIMPORT {
- addpltsym(ld.Ctxt, targ)
- r.Sym = ld.Linklookup(ld.Ctxt, ".plt", 0)
+ addpltsym(ctxt, targ)
+ r.Sym = ctxt.Syms.Lookup(".plt", 0)
r.Add += int64(targ.Plt)
}
- return
+ return true
case 256 + ld.R_386_GOT32, 256 + ld.R_386_GOT32X:
if targ.Type != obj.SDYNIMPORT {
@@ -175,7 +205,7 @@ func adddynrel(s *ld.LSym, r *ld.Reloc) {
s.P[r.Off-2] = 0x8d
r.Type = obj.R_GOTOFF
- return
+ return true
}
if r.Off >= 2 && s.P[r.Off-2] == 0xff && s.P[r.Off-1] == 0xb3 {
@@ -185,104 +215,103 @@ func adddynrel(s *ld.LSym, r *ld.Reloc) {
s.P[r.Off-1] = 0x68
r.Type = obj.R_ADDR
- return
+ return true
}
- ld.Diag("unexpected GOT reloc for non-dynamic symbol %s", targ.Name)
- return
+ ld.Errorf(s, "unexpected GOT reloc for non-dynamic symbol %s", targ.Name)
+ return false
}
- addgotsym(ld.Ctxt, targ)
+ addgotsym(ctxt, targ)
r.Type = obj.R_CONST // write r->add during relocsym
r.Sym = nil
r.Add += int64(targ.Got)
- return
+ return true
case 256 + ld.R_386_GOTOFF:
r.Type = obj.R_GOTOFF
- return
+ return true
case 256 + ld.R_386_GOTPC:
r.Type = obj.R_PCREL
- r.Sym = ld.Linklookup(ld.Ctxt, ".got", 0)
+ r.Sym = ctxt.Syms.Lookup(".got", 0)
r.Add += 4
- return
+ return true
case 256 + ld.R_386_32:
if targ.Type == obj.SDYNIMPORT {
- ld.Diag("unexpected R_386_32 relocation for dynamic symbol %s", targ.Name)
+ ld.Errorf(s, "unexpected R_386_32 relocation for dynamic symbol %s", targ.Name)
}
r.Type = obj.R_ADDR
- return
+ return true
case 512 + ld.MACHO_GENERIC_RELOC_VANILLA*2 + 0:
r.Type = obj.R_ADDR
if targ.Type == obj.SDYNIMPORT {
- ld.Diag("unexpected reloc for dynamic symbol %s", targ.Name)
+ ld.Errorf(s, "unexpected reloc for dynamic symbol %s", targ.Name)
}
- return
+ return true
case 512 + ld.MACHO_GENERIC_RELOC_VANILLA*2 + 1:
if targ.Type == obj.SDYNIMPORT {
- addpltsym(ld.Ctxt, targ)
- r.Sym = ld.Linklookup(ld.Ctxt, ".plt", 0)
+ addpltsym(ctxt, targ)
+ r.Sym = ctxt.Syms.Lookup(".plt", 0)
r.Add = int64(targ.Plt)
r.Type = obj.R_PCREL
- return
+ return true
}
r.Type = obj.R_PCREL
- return
+ return true
case 512 + ld.MACHO_FAKE_GOTPCREL:
if targ.Type != obj.SDYNIMPORT {
// have symbol
// turn MOVL of GOT entry into LEAL of symbol itself
if r.Off < 2 || s.P[r.Off-2] != 0x8b {
- ld.Diag("unexpected GOT reloc for non-dynamic symbol %s", targ.Name)
- return
+ ld.Errorf(s, "unexpected GOT reloc for non-dynamic symbol %s", targ.Name)
+ return false
}
s.P[r.Off-2] = 0x8d
r.Type = obj.R_PCREL
- return
+ return true
}
- addgotsym(ld.Ctxt, targ)
- r.Sym = ld.Linklookup(ld.Ctxt, ".got", 0)
+ addgotsym(ctxt, targ)
+ r.Sym = ctxt.Syms.Lookup(".got", 0)
r.Add += int64(targ.Got)
r.Type = obj.R_PCREL
- return
+ return true
}
// Handle references to ELF symbols from our own object files.
if targ.Type != obj.SDYNIMPORT {
- return
+ return true
}
-
switch r.Type {
case obj.R_CALL,
obj.R_PCREL:
- addpltsym(ld.Ctxt, targ)
- r.Sym = ld.Linklookup(ld.Ctxt, ".plt", 0)
+ addpltsym(ctxt, targ)
+ r.Sym = ctxt.Syms.Lookup(".plt", 0)
r.Add = int64(targ.Plt)
- return
+ return true
case obj.R_ADDR:
if s.Type != obj.SDATA {
break
}
if ld.Iself {
- ld.Adddynsym(ld.Ctxt, targ)
- rel := ld.Linklookup(ld.Ctxt, ".rel", 0)
- ld.Addaddrplus(ld.Ctxt, rel, s, int64(r.Off))
- ld.Adduint32(ld.Ctxt, rel, ld.ELF32_R_INFO(uint32(targ.Dynid), ld.R_386_32))
+ ld.Adddynsym(ctxt, targ)
+ 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.Sym = nil
- return
+ return true
}
- if ld.HEADTYPE == obj.Hdarwin && s.Size == int64(ld.SysArch.PtrSize) && r.Off == 0 {
+ if ld.Headtype == obj.Hdarwin && s.Size == int64(ld.SysArch.PtrSize) && r.Off == 0 {
// Mach-O relocations are a royal pain to lay out.
// They use a compact stateful bytecode representation
// that is too much bother to deal with.
@@ -293,31 +322,30 @@ func adddynrel(s *ld.LSym, r *ld.Reloc) {
// just in case the C code assigns to the variable,
// and of course it only works for single pointers,
// but we only need to support cgo and that's all it needs.
- ld.Adddynsym(ld.Ctxt, targ)
+ ld.Adddynsym(ctxt, targ)
- got := ld.Linklookup(ld.Ctxt, ".got", 0)
+ got := ctxt.Syms.Lookup(".got", 0)
s.Type = got.Type | obj.SSUB
s.Outer = got
s.Sub = got.Sub
got.Sub = s
s.Value = got.Size
- ld.Adduint32(ld.Ctxt, got, 0)
- ld.Adduint32(ld.Ctxt, ld.Linklookup(ld.Ctxt, ".linkedit.got", 0), uint32(targ.Dynid))
+ ld.Adduint32(ctxt, got, 0)
+ ld.Adduint32(ctxt, ctxt.Syms.Lookup(".linkedit.got", 0), uint32(targ.Dynid))
r.Type = 256 // ignore during relocsym
- return
+ return true
}
- if ld.HEADTYPE == obj.Hwindows && s.Size == int64(ld.SysArch.PtrSize) {
+ if (ld.Headtype == obj.Hwindows || ld.Headtype == obj.Hwindowsgui) && s.Size == int64(ld.SysArch.PtrSize) {
// nothing to do, the relocation will be laid out in pereloc1
- return
+ return true
}
}
- ld.Ctxt.Cursym = s
- ld.Diag("unsupported relocation for dynamic symbol %s (type=%d stype=%d)", targ.Name, r.Type, targ.Type)
+ return false
}
-func elfreloc1(r *ld.Reloc, sectoff int64) int {
+func elfreloc1(ctxt *ld.Link, r *ld.Reloc, sectoff int64) int {
ld.Thearch.Lput(uint32(sectoff))
elfsym := r.Xsym.ElfsymForReloc()
@@ -381,14 +409,14 @@ func elfreloc1(r *ld.Reloc, sectoff int64) int {
return 0
}
-func machoreloc1(r *ld.Reloc, sectoff int64) int {
+func machoreloc1(s *ld.Symbol, r *ld.Reloc, sectoff int64) int {
var v uint32
rs := r.Xsym
if rs.Type == obj.SHOSTOBJ {
if rs.Dynid < 0 {
- ld.Diag("reloc %d to non-macho symbol %s type=%d", r.Type, rs.Name, rs.Type)
+ ld.Errorf(s, "reloc %d to non-macho symbol %s type=%d", r.Type, rs.Name, rs.Type)
return -1
}
@@ -397,7 +425,7 @@ func machoreloc1(r *ld.Reloc, sectoff int64) int {
} else {
v = uint32(rs.Sect.Extnum)
if v == 0 {
- ld.Diag("reloc %d to symbol %s in non-macho section %s type=%d", r.Type, rs.Name, rs.Sect.Name, rs.Type)
+ ld.Errorf(s, "reloc %d to symbol %s in non-macho section %s type=%d", r.Type, rs.Name, rs.Sect.Name, rs.Type)
return -1
}
}
@@ -437,13 +465,13 @@ func machoreloc1(r *ld.Reloc, sectoff int64) int {
return 0
}
-func pereloc1(r *ld.Reloc, sectoff int64) bool {
+func pereloc1(s *ld.Symbol, r *ld.Reloc, sectoff int64) bool {
var v uint32
rs := r.Xsym
if rs.Dynid < 0 {
- ld.Diag("reloc %d to non-coff symbol %s type=%d", r.Type, rs.Name, rs.Type)
+ ld.Errorf(s, "reloc %d to non-coff symbol %s type=%d", r.Type, rs.Name, rs.Type)
return false
}
@@ -467,7 +495,7 @@ func pereloc1(r *ld.Reloc, sectoff int64) bool {
return true
}
-func archreloc(r *ld.Reloc, s *ld.LSym, val *int64) int {
+func archreloc(ctxt *ld.Link, r *ld.Reloc, s *ld.Symbol, val *int64) int {
if ld.Linkmode == ld.LinkExternal {
return -1
}
@@ -477,46 +505,46 @@ func archreloc(r *ld.Reloc, s *ld.LSym, val *int64) int {
return 0
case obj.R_GOTOFF:
- *val = ld.Symaddr(r.Sym) + r.Add - ld.Symaddr(ld.Linklookup(ld.Ctxt, ".got", 0))
+ *val = ld.Symaddr(r.Sym) + r.Add - ld.Symaddr(ctxt.Syms.Lookup(".got", 0))
return 0
}
return -1
}
-func archrelocvariant(r *ld.Reloc, s *ld.LSym, t int64) int64 {
+func archrelocvariant(ctxt *ld.Link, r *ld.Reloc, s *ld.Symbol, t int64) int64 {
log.Fatalf("unexpected relocation variant")
return t
}
-func elfsetupplt() {
- plt := ld.Linklookup(ld.Ctxt, ".plt", 0)
- got := ld.Linklookup(ld.Ctxt, ".got.plt", 0)
+func elfsetupplt(ctxt *ld.Link) {
+ plt := ctxt.Syms.Lookup(".plt", 0)
+ got := ctxt.Syms.Lookup(".got.plt", 0)
if plt.Size == 0 {
// pushl got+4
- ld.Adduint8(ld.Ctxt, plt, 0xff)
+ ld.Adduint8(ctxt, plt, 0xff)
- ld.Adduint8(ld.Ctxt, plt, 0x35)
- ld.Addaddrplus(ld.Ctxt, plt, got, 4)
+ ld.Adduint8(ctxt, plt, 0x35)
+ ld.Addaddrplus(ctxt, plt, got, 4)
// jmp *got+8
- ld.Adduint8(ld.Ctxt, plt, 0xff)
+ ld.Adduint8(ctxt, plt, 0xff)
- ld.Adduint8(ld.Ctxt, plt, 0x25)
- ld.Addaddrplus(ld.Ctxt, plt, got, 8)
+ ld.Adduint8(ctxt, plt, 0x25)
+ ld.Addaddrplus(ctxt, plt, got, 8)
// zero pad
- ld.Adduint32(ld.Ctxt, plt, 0)
+ ld.Adduint32(ctxt, plt, 0)
// assume got->size == 0 too
- ld.Addaddrplus(ld.Ctxt, got, ld.Linklookup(ld.Ctxt, ".dynamic", 0), 0)
+ ld.Addaddrplus(ctxt, got, ctxt.Syms.Lookup(".dynamic", 0), 0)
- ld.Adduint32(ld.Ctxt, got, 0)
- ld.Adduint32(ld.Ctxt, got, 0)
+ ld.Adduint32(ctxt, got, 0)
+ ld.Adduint32(ctxt, got, 0)
}
}
-func addpltsym(ctxt *ld.Link, s *ld.LSym) {
+func addpltsym(ctxt *ld.Link, s *ld.Symbol) {
if s.Plt >= 0 {
return
}
@@ -524,11 +552,11 @@ func addpltsym(ctxt *ld.Link, s *ld.LSym) {
ld.Adddynsym(ctxt, s)
if ld.Iself {
- plt := ld.Linklookup(ctxt, ".plt", 0)
- got := ld.Linklookup(ctxt, ".got.plt", 0)
- rel := ld.Linklookup(ctxt, ".rel.plt", 0)
+ plt := ctxt.Syms.Lookup(".plt", 0)
+ got := ctxt.Syms.Lookup(".got.plt", 0)
+ rel := ctxt.Syms.Lookup(".rel.plt", 0)
if plt.Size == 0 {
- elfsetupplt()
+ elfsetupplt(ctxt)
}
// jmpq *got+size
@@ -556,52 +584,51 @@ func addpltsym(ctxt *ld.Link, s *ld.LSym) {
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 == obj.Hdarwin {
// Same laziness as in 6l.
- plt := ld.Linklookup(ctxt, ".plt", 0)
+ plt := ctxt.Syms.Lookup(".plt", 0)
addgotsym(ctxt, s)
- ld.Adduint32(ctxt, ld.Linklookup(ctxt, ".linkedit.plt", 0), uint32(s.Dynid))
+ ld.Adduint32(ctxt, ctxt.Syms.Lookup(".linkedit.plt", 0), uint32(s.Dynid))
// jmpq *got+size(IP)
s.Plt = int32(plt.Size)
ld.Adduint8(ctxt, plt, 0xff)
ld.Adduint8(ctxt, plt, 0x25)
- ld.Addaddrplus(ctxt, plt, ld.Linklookup(ctxt, ".got", 0), int64(s.Got))
+ ld.Addaddrplus(ctxt, plt, ctxt.Syms.Lookup(".got", 0), int64(s.Got))
} else {
- ld.Diag("addpltsym: unsupported binary format")
+ ld.Errorf(s, "addpltsym: unsupported binary format")
}
}
-func addgotsym(ctxt *ld.Link, s *ld.LSym) {
+func addgotsym(ctxt *ld.Link, s *ld.Symbol) {
if s.Got >= 0 {
return
}
ld.Adddynsym(ctxt, s)
- got := ld.Linklookup(ctxt, ".got", 0)
+ got := ctxt.Syms.Lookup(".got", 0)
s.Got = int32(got.Size)
ld.Adduint32(ctxt, got, 0)
if ld.Iself {
- rel := ld.Linklookup(ctxt, ".rel", 0)
+ 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 {
- ld.Adduint32(ctxt, ld.Linklookup(ctxt, ".linkedit.got", 0), uint32(s.Dynid))
+ } else if ld.Headtype == obj.Hdarwin {
+ ld.Adduint32(ctxt, ctxt.Syms.Lookup(".linkedit.got", 0), uint32(s.Dynid))
} else {
- ld.Diag("addgotsym: unsupported binary format")
+ ld.Errorf(s, "addgotsym: unsupported binary format")
}
}
-func asmb() {
- if ld.Debug['v'] != 0 {
- fmt.Fprintf(ld.Bso, "%5.2f asmb\n", obj.Cputime())
+func asmb(ctxt *ld.Link) {
+ if ctxt.Debugvlog != 0 {
+ ctxt.Logf("%5.2f asmb\n", obj.Cputime())
}
- ld.Bso.Flush()
if ld.Iself {
ld.Asmbelfsetup()
@@ -610,87 +637,91 @@ func asmb() {
sect := ld.Segtext.Sect
ld.Cseek(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
// 0xCC is INT $3 - breakpoint instruction
- ld.CodeblkPad(int64(sect.Vaddr), int64(sect.Length), []byte{0xCC})
+ ld.CodeblkPad(ctxt, int64(sect.Vaddr), int64(sect.Length), []byte{0xCC})
for sect = sect.Next; sect != nil; sect = sect.Next {
ld.Cseek(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
- ld.Datblk(int64(sect.Vaddr), int64(sect.Length))
+ ld.Datblk(ctxt, int64(sect.Vaddr), int64(sect.Length))
}
if ld.Segrodata.Filelen > 0 {
- if ld.Debug['v'] != 0 {
- fmt.Fprintf(ld.Bso, "%5.2f rodatblk\n", obj.Cputime())
+ if ctxt.Debugvlog != 0 {
+ ctxt.Logf("%5.2f rodatblk\n", obj.Cputime())
}
- ld.Bso.Flush()
ld.Cseek(int64(ld.Segrodata.Fileoff))
- ld.Datblk(int64(ld.Segrodata.Vaddr), int64(ld.Segrodata.Filelen))
+ 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())
+ }
+ ld.Cseek(int64(ld.Segrelrodata.Fileoff))
+ ld.Datblk(ctxt, int64(ld.Segrelrodata.Vaddr), int64(ld.Segrelrodata.Filelen))
}
- if ld.Debug['v'] != 0 {
- fmt.Fprintf(ld.Bso, "%5.2f datblk\n", obj.Cputime())
+ if ctxt.Debugvlog != 0 {
+ ctxt.Logf("%5.2f datblk\n", obj.Cputime())
}
- ld.Bso.Flush()
ld.Cseek(int64(ld.Segdata.Fileoff))
- ld.Datblk(int64(ld.Segdata.Vaddr), int64(ld.Segdata.Filelen))
+ ld.Datblk(ctxt, int64(ld.Segdata.Vaddr), int64(ld.Segdata.Filelen))
ld.Cseek(int64(ld.Segdwarf.Fileoff))
- ld.Dwarfblk(int64(ld.Segdwarf.Vaddr), int64(ld.Segdwarf.Filelen))
+ ld.Dwarfblk(ctxt, int64(ld.Segdwarf.Vaddr), int64(ld.Segdwarf.Filelen))
machlink := uint32(0)
- if ld.HEADTYPE == obj.Hdarwin {
- machlink = uint32(ld.Domacholink())
+ if ld.Headtype == obj.Hdarwin {
+ machlink = uint32(ld.Domacholink(ctxt))
}
ld.Symsize = 0
ld.Spsize = 0
ld.Lcsize = 0
symo := uint32(0)
- if ld.Debug['s'] == 0 {
+ if !*ld.FlagS {
// TODO: rationalize
- if ld.Debug['v'] != 0 {
- fmt.Fprintf(ld.Bso, "%5.2f sym\n", obj.Cputime())
+ if ctxt.Debugvlog != 0 {
+ ctxt.Logf("%5.2f sym\n", obj.Cputime())
}
- ld.Bso.Flush()
- switch ld.HEADTYPE {
+ switch ld.Headtype {
default:
if ld.Iself {
symo = uint32(ld.Segdwarf.Fileoff + ld.Segdwarf.Filelen)
- symo = uint32(ld.Rnd(int64(symo), int64(ld.INITRND)))
+ symo = uint32(ld.Rnd(int64(symo), int64(*ld.FlagRound)))
}
case obj.Hplan9:
symo = uint32(ld.Segdata.Fileoff + ld.Segdata.Filelen)
case obj.Hdarwin:
- symo = uint32(ld.Segdwarf.Fileoff + uint64(ld.Rnd(int64(ld.Segdwarf.Filelen), int64(ld.INITRND))) + uint64(machlink))
+ symo = uint32(ld.Segdwarf.Fileoff + uint64(ld.Rnd(int64(ld.Segdwarf.Filelen), int64(*ld.FlagRound))) + uint64(machlink))
- case obj.Hwindows:
+ case obj.Hwindows, obj.Hwindowsgui:
symo = uint32(ld.Segdwarf.Fileoff + ld.Segdwarf.Filelen)
symo = uint32(ld.Rnd(int64(symo), ld.PEFILEALIGN))
}
ld.Cseek(int64(symo))
- switch ld.HEADTYPE {
+ switch ld.Headtype {
default:
if ld.Iself {
- if ld.Debug['v'] != 0 {
- fmt.Fprintf(ld.Bso, "%5.2f elfsym\n", obj.Cputime())
+ if ctxt.Debugvlog != 0 {
+ ctxt.Logf("%5.2f elfsym\n", obj.Cputime())
}
- ld.Asmelfsym()
+ ld.Asmelfsym(ctxt)
ld.Cflush()
ld.Cwrite(ld.Elfstrdat)
if ld.Linkmode == ld.LinkExternal {
- ld.Elfemitreloc()
+ ld.Elfemitreloc(ctxt)
}
}
case obj.Hplan9:
- ld.Asmplan9sym()
+ ld.Asmplan9sym(ctxt)
ld.Cflush()
- sym := ld.Linklookup(ld.Ctxt, "pclntab", 0)
+ sym := ctxt.Syms.Lookup("pclntab", 0)
if sym != nil {
ld.Lcsize = int32(len(sym.P))
for i := 0; int32(i) < ld.Lcsize; i++ {
@@ -700,24 +731,23 @@ func asmb() {
ld.Cflush()
}
- case obj.Hwindows:
- if ld.Debug['v'] != 0 {
- fmt.Fprintf(ld.Bso, "%5.2f dwarf\n", obj.Cputime())
+ case obj.Hwindows, obj.Hwindowsgui:
+ if ctxt.Debugvlog != 0 {
+ ctxt.Logf("%5.2f dwarf\n", obj.Cputime())
}
case obj.Hdarwin:
if ld.Linkmode == ld.LinkExternal {
- ld.Machoemitreloc()
+ ld.Machoemitreloc(ctxt)
}
}
}
- if ld.Debug['v'] != 0 {
- fmt.Fprintf(ld.Bso, "%5.2f headr\n", obj.Cputime())
+ if ctxt.Debugvlog != 0 {
+ ctxt.Logf("%5.2f headr\n", obj.Cputime())
}
- ld.Bso.Flush()
ld.Cseek(0)
- switch ld.HEADTYPE {
+ switch ld.Headtype {
default:
case obj.Hplan9: /* plan9 */
magic := int32(4*11*11 + 7)
@@ -726,23 +756,23 @@ func asmb() {
ld.Lputb(uint32(ld.Segtext.Filelen)) /* sizes */
ld.Lputb(uint32(ld.Segdata.Filelen))
ld.Lputb(uint32(ld.Segdata.Length - ld.Segdata.Filelen))
- ld.Lputb(uint32(ld.Symsize)) /* nsyms */
- ld.Lputb(uint32(ld.Entryvalue())) /* va of entry */
- ld.Lputb(uint32(ld.Spsize)) /* sp offsets */
- ld.Lputb(uint32(ld.Lcsize)) /* line offsets */
+ ld.Lputb(uint32(ld.Symsize)) /* nsyms */
+ ld.Lputb(uint32(ld.Entryvalue(ctxt))) /* va of entry */
+ ld.Lputb(uint32(ld.Spsize)) /* sp offsets */
+ ld.Lputb(uint32(ld.Lcsize)) /* line offsets */
case obj.Hdarwin:
- ld.Asmbmacho()
+ ld.Asmbmacho(ctxt)
case obj.Hlinux,
obj.Hfreebsd,
obj.Hnetbsd,
obj.Hopenbsd,
obj.Hnacl:
- ld.Asmbelf(int64(symo))
+ ld.Asmbelf(ctxt, int64(symo))
- case obj.Hwindows:
- ld.Asmbpe()
+ case obj.Hwindows, obj.Hwindowsgui:
+ ld.Asmbpe(ctxt)
}
ld.Cflush()
diff --git a/src/cmd/link/internal/x86/l.go b/src/cmd/link/internal/x86/l.go
index 065508e..0f104ea 100644
--- a/src/cmd/link/internal/x86/l.go
+++ b/src/cmd/link/internal/x86/l.go
@@ -1,5 +1,5 @@
// Inferno utils/8l/l.h
-// http://code.google.com/p/inferno-os/source/browse/utils/8l/l.h
+// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/8l/l.h
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth at terzarima.net)
@@ -31,13 +31,13 @@
package x86
const (
- MaxAlign = 32 // max data alignment
- MinAlign = 1 // min data alignment
- FuncAlign = 16
+ maxAlign = 32 // max data alignment
+ minAlign = 1 // min data alignment
+ funcAlign = 16
)
/* Used by ../internal/ld/dwarf.go */
const (
- DWARFREGSP = 4
- DWARFREGLR = 8
+ dwarfRegSP = 4
+ dwarfRegLR = 8
)
diff --git a/src/cmd/link/internal/x86/obj.go b/src/cmd/link/internal/x86/obj.go
index a4d8f50..ea213be 100644
--- a/src/cmd/link/internal/x86/obj.go
+++ b/src/cmd/link/internal/x86/obj.go
@@ -1,5 +1,5 @@
// Inferno utils/8l/obj.c
-// http://code.google.com/p/inferno-os/source/browse/utils/8l/obj.c
+// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/8l/obj.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth at terzarima.net)
@@ -35,24 +35,16 @@ import (
"cmd/internal/sys"
"cmd/link/internal/ld"
"fmt"
- "log"
)
-// Reading object files.
-
-func Main() {
- linkarchinit()
- ld.Ldmain()
-}
-
-func linkarchinit() {
+func Init() {
ld.SysArch = sys.Arch386
- ld.Thearch.Funcalign = FuncAlign
- ld.Thearch.Maxalign = MaxAlign
- ld.Thearch.Minalign = MinAlign
- ld.Thearch.Dwarfregsp = DWARFREGSP
- ld.Thearch.Dwarfreglr = DWARFREGLR
+ ld.Thearch.Funcalign = funcAlign
+ ld.Thearch.Maxalign = maxAlign
+ ld.Thearch.Minalign = minAlign
+ ld.Thearch.Dwarfregsp = dwarfRegSP
+ ld.Thearch.Dwarfreglr = dwarfRegLR
ld.Thearch.Adddynrel = adddynrel
ld.Thearch.Archinit = archinit
@@ -78,116 +70,85 @@ func linkarchinit() {
ld.Thearch.Solarisdynld = "/lib/ld.so.1"
}
-func archinit() {
- // getgoextlinkenabled is based on GO_EXTLINK_ENABLED when
- // Go was built; see ../../make.bash.
- if ld.Linkmode == ld.LinkAuto && obj.Getgoextlinkenabled() == "0" {
- ld.Linkmode = ld.LinkInternal
- }
-
- if ld.Buildmode == ld.BuildmodeCShared || ld.Buildmode == ld.BuildmodePIE || ld.DynlinkingGo() {
- ld.Linkmode = ld.LinkExternal
- got := ld.Linklookup(ld.Ctxt, "_GLOBAL_OFFSET_TABLE_", 0)
- got.Type = obj.SDYNIMPORT
- got.Attr |= ld.AttrReachable
- }
-
- switch ld.HEADTYPE {
- default:
- if ld.Linkmode == ld.LinkAuto {
- ld.Linkmode = ld.LinkInternal
- }
- if ld.Linkmode == ld.LinkExternal && obj.Getgoextlinkenabled() != "1" {
- log.Fatalf("cannot use -linkmode=external with -H %s", ld.Headstr(int(ld.HEADTYPE)))
- }
-
- case obj.Hdarwin,
- obj.Hfreebsd,
- obj.Hlinux,
- obj.Hnetbsd,
- obj.Hopenbsd,
- obj.Hwindows:
- break
- }
-
- switch ld.HEADTYPE {
+func archinit(ctxt *ld.Link) {
+ switch ld.Headtype {
default:
- ld.Exitf("unknown -H option: %v", ld.HEADTYPE)
+ ld.Exitf("unknown -H option: %v", ld.Headtype)
case obj.Hplan9: /* plan 9 */
ld.HEADR = 32
- if ld.INITTEXT == -1 {
- ld.INITTEXT = 4096 + 32
+ if *ld.FlagTextAddr == -1 {
+ *ld.FlagTextAddr = 4096 + int64(ld.HEADR)
}
- if ld.INITDAT == -1 {
- ld.INITDAT = 0
+ if *ld.FlagDataAddr == -1 {
+ *ld.FlagDataAddr = 0
}
- if ld.INITRND == -1 {
- ld.INITRND = 4096
+ if *ld.FlagRound == -1 {
+ *ld.FlagRound = 4096
}
case obj.Hdarwin: /* apple MACH */
ld.Machoinit()
ld.HEADR = ld.INITIAL_MACHO_HEADR
- if ld.INITTEXT == -1 {
- ld.INITTEXT = 4096 + int64(ld.HEADR)
+ if *ld.FlagTextAddr == -1 {
+ *ld.FlagTextAddr = 4096 + int64(ld.HEADR)
}
- if ld.INITDAT == -1 {
- ld.INITDAT = 0
+ if *ld.FlagDataAddr == -1 {
+ *ld.FlagDataAddr = 0
}
- if ld.INITRND == -1 {
- ld.INITRND = 4096
+ if *ld.FlagRound == -1 {
+ *ld.FlagRound = 4096
}
case obj.Hlinux, /* elf32 executable */
obj.Hfreebsd,
obj.Hnetbsd,
obj.Hopenbsd:
- ld.Elfinit()
+ ld.Elfinit(ctxt)
ld.HEADR = ld.ELFRESERVE
- if ld.INITTEXT == -1 {
- ld.INITTEXT = 0x08048000 + int64(ld.HEADR)
+ if *ld.FlagTextAddr == -1 {
+ *ld.FlagTextAddr = 0x08048000 + int64(ld.HEADR)
}
- if ld.INITDAT == -1 {
- ld.INITDAT = 0
+ if *ld.FlagDataAddr == -1 {
+ *ld.FlagDataAddr = 0
}
- if ld.INITRND == -1 {
- ld.INITRND = 4096
+ if *ld.FlagRound == -1 {
+ *ld.FlagRound = 4096
}
case obj.Hnacl:
- ld.Elfinit()
+ ld.Elfinit(ctxt)
ld.HEADR = 0x10000
ld.Funcalign = 32
- if ld.INITTEXT == -1 {
- ld.INITTEXT = 0x20000
+ if *ld.FlagTextAddr == -1 {
+ *ld.FlagTextAddr = 0x20000
}
- if ld.INITDAT == -1 {
- ld.INITDAT = 0
+ if *ld.FlagDataAddr == -1 {
+ *ld.FlagDataAddr = 0
}
- if ld.INITRND == -1 {
- ld.INITRND = 0x10000
+ if *ld.FlagRound == -1 {
+ *ld.FlagRound = 0x10000
}
- case obj.Hwindows: /* PE executable */
- ld.Peinit()
+ case obj.Hwindows, obj.Hwindowsgui: /* PE executable */
+ ld.Peinit(ctxt)
ld.HEADR = ld.PEFILEHEADR
- if ld.INITTEXT == -1 {
- ld.INITTEXT = ld.PEBASE + int64(ld.PESECTHEADR)
+ if *ld.FlagTextAddr == -1 {
+ *ld.FlagTextAddr = ld.PEBASE + int64(ld.PESECTHEADR)
}
- if ld.INITDAT == -1 {
- ld.INITDAT = 0
+ if *ld.FlagDataAddr == -1 {
+ *ld.FlagDataAddr = 0
}
- if ld.INITRND == -1 {
- ld.INITRND = ld.PESECTALIGN
+ if *ld.FlagRound == -1 {
+ *ld.FlagRound = ld.PESECTALIGN
}
}
- if ld.INITDAT != 0 && ld.INITRND != 0 {
- fmt.Printf("warning: -D0x%x is ignored because of -R0x%x\n", uint64(ld.INITDAT), uint32(ld.INITRND))
+ if *ld.FlagDataAddr != 0 && *ld.FlagRound != 0 {
+ fmt.Printf("warning: -D0x%x is ignored because of -R0x%x\n", uint64(*ld.FlagDataAddr), uint32(*ld.FlagRound))
}
}
diff --git a/src/cmd/link/linkbig_test.go b/src/cmd/link/linkbig_test.go
new file mode 100644
index 0000000..d793c2f
--- /dev/null
+++ b/src/cmd/link/linkbig_test.go
@@ -0,0 +1,109 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This program generates a test to verify that a program can be
+// successfully linked even when there are very large text
+// sections present.
+
+package main
+
+import (
+ "bytes"
+ "cmd/internal/obj"
+ "fmt"
+ "internal/testenv"
+ "io/ioutil"
+ "os"
+ "os/exec"
+ "testing"
+)
+
+func TestLargeText(t *testing.T) {
+ if testing.Short() || (obj.GOARCH != "ppc64le" && obj.GOARCH != "ppc64" && obj.GOARCH != "arm") {
+ t.Skip("Skipping large text section test in short mode or on %s", obj.GOARCH)
+ }
+ testenv.MustHaveGoBuild(t)
+
+ var w bytes.Buffer
+ const FN = 4
+ tmpdir, err := ioutil.TempDir("", "bigtext")
+
+ defer os.RemoveAll(tmpdir)
+
+ // Generate the scenario where the total amount of text exceeds the
+ // limit for the jmp/call instruction, on RISC architectures like ppc64le,
+ // which is 2^26. When that happens the call requires special trampolines or
+ // long branches inserted by the linker where supported.
+ // Multiple .s files are generated instead of one.
+ instOnArch := map[string]string{
+ "ppc64": "\tMOVD\tR0,R3\n",
+ "ppc64le": "\tMOVD\tR0,R3\n",
+ "arm": "\tMOVW\tR0,R1\n",
+ }
+ inst := instOnArch[obj.GOARCH]
+ for j := 0; j < FN; j++ {
+ testname := fmt.Sprintf("bigfn%d", j)
+ fmt.Fprintf(&w, "TEXT ·%s(SB),$0\n", testname)
+ for i := 0; i < 2200000; i++ {
+ fmt.Fprintf(&w, inst)
+ }
+ fmt.Fprintf(&w, "\tRET\n")
+ err := ioutil.WriteFile(tmpdir+"/"+testname+".s", w.Bytes(), 0666)
+ if err != nil {
+ t.Fatalf("can't write output: %v\n", err)
+ }
+ w.Reset()
+ }
+ fmt.Fprintf(&w, "package main\n")
+ fmt.Fprintf(&w, "\nimport (\n")
+ fmt.Fprintf(&w, "\t\"os\"\n")
+ fmt.Fprintf(&w, "\t\"fmt\"\n")
+ fmt.Fprintf(&w, ")\n\n")
+
+ for i := 0; i < FN; i++ {
+ fmt.Fprintf(&w, "func bigfn%d()\n", i)
+ }
+ fmt.Fprintf(&w, "\nfunc main() {\n")
+
+ // There are lots of dummy code generated in the .s files just to generate a lot
+ // of text. Link them in but guard their call so their code is not executed but
+ // the main part of the program can be run.
+ fmt.Fprintf(&w, "\tif os.Getenv(\"LINKTESTARG\") != \"\" {\n")
+ for i := 0; i < FN; i++ {
+ fmt.Fprintf(&w, "\t\tbigfn%d()\n", i)
+ }
+ fmt.Fprintf(&w, "\t}\n")
+ fmt.Fprintf(&w, "\tfmt.Printf(\"PASS\\n\")\n")
+ fmt.Fprintf(&w, "}")
+ err = ioutil.WriteFile(tmpdir+"/bigfn.go", w.Bytes(), 0666)
+ if err != nil {
+ t.Fatalf("can't write output: %v\n", err)
+ }
+
+ // Build and run with internal linking.
+ os.Chdir(tmpdir)
+ cmd := exec.Command(testenv.GoToolPath(t), "build", "-o", "bigtext")
+ out, err := cmd.CombinedOutput()
+ if err != nil {
+ t.Fatalf("Build failed for big text program with internal linking: %v, output: %s", err, out)
+ }
+ cmd = exec.Command(tmpdir + "/bigtext")
+ out, err = cmd.CombinedOutput()
+ if err != nil {
+ t.Fatalf("Program built with internal linking failed to run with err %v, output: %s", err, out)
+ }
+
+ // Build and run with external linking
+ os.Chdir(tmpdir)
+ cmd = exec.Command(testenv.GoToolPath(t), "build", "-o", "bigtext", "-ldflags", "'-linkmode=external'")
+ out, err = cmd.CombinedOutput()
+ if err != nil {
+ t.Fatalf("Build failed for big text program with external linking: %v, output: %s", err, out)
+ }
+ cmd = exec.Command(tmpdir + "/bigtext")
+ out, err = cmd.CombinedOutput()
+ if err != nil {
+ t.Fatalf("Program built with external linking failed to run with err %v, output: %s", err, out)
+ }
+}
diff --git a/src/cmd/link/main.go b/src/cmd/link/main.go
index f92e02e..a9aeb1e 100644
--- a/src/cmd/link/main.go
+++ b/src/cmd/link/main.go
@@ -9,6 +9,8 @@ import (
"cmd/link/internal/amd64"
"cmd/link/internal/arm"
"cmd/link/internal/arm64"
+ "cmd/link/internal/ld"
+ "cmd/link/internal/mips"
"cmd/link/internal/mips64"
"cmd/link/internal/ppc64"
"cmd/link/internal/s390x"
@@ -17,24 +19,41 @@ import (
"os"
)
+// The bulk of the linker implementation lives in cmd/link/internal/ld.
+// Architecture-specific code lives in cmd/link/internal/GOARCH.
+//
+// Program initialization:
+//
+// Before any argument parsing is done, the Init function of relevant
+// architecture package is called. The only job done in Init is
+// configuration of the ld.Thearch and ld.SysArch variables.
+//
+// Then control flow passes to ld.Main, which parses flags, makes
+// some configuration decisions, and then gives the architecture
+// packages a second chance to modify the linker's configuration
+// via the ld.Thearch.Archinit function.
+
func main() {
- switch obj.Getgoarch() {
+ switch obj.GOARCH {
default:
- fmt.Fprintf(os.Stderr, "link: unknown architecture %q\n", obj.Getgoarch())
+ fmt.Fprintf(os.Stderr, "link: unknown architecture %q\n", obj.GOARCH)
os.Exit(2)
case "386":
- x86.Main()
+ x86.Init()
case "amd64", "amd64p32":
- amd64.Main()
+ amd64.Init()
case "arm":
- arm.Main()
+ arm.Init()
case "arm64":
- arm64.Main()
+ arm64.Init()
+ case "mips", "mipsle":
+ mips.Init()
case "mips64", "mips64le":
- mips64.Main()
+ mips64.Init()
case "ppc64", "ppc64le":
- ppc64.Main()
+ ppc64.Init()
case "s390x":
- s390x.Main()
+ s390x.Init()
}
+ ld.Main()
}
diff --git a/src/cmd/nm/nm.go b/src/cmd/nm/nm.go
index 462c4c5..4384af8 100644
--- a/src/cmd/nm/nm.go
+++ b/src/cmd/nm/nm.go
@@ -103,11 +103,11 @@ func nm(file string) {
switch *sortOrder {
case "address":
- sort.Sort(byAddr(syms))
+ sort.Slice(syms, func(i, j int) bool { return syms[i].Addr < syms[j].Addr })
case "name":
- sort.Sort(byName(syms))
+ sort.Slice(syms, func(i, j int) bool { return syms[i].Name < syms[j].Name })
case "size":
- sort.Sort(bySize(syms))
+ sort.Slice(syms, func(i, j int) bool { return syms[i].Size > syms[j].Size })
}
w := bufio.NewWriter(os.Stdout)
@@ -131,21 +131,3 @@ func nm(file string) {
}
w.Flush()
}
-
-type byAddr []objfile.Sym
-
-func (x byAddr) Len() int { return len(x) }
-func (x byAddr) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
-func (x byAddr) Less(i, j int) bool { return x[i].Addr < x[j].Addr }
-
-type byName []objfile.Sym
-
-func (x byName) Len() int { return len(x) }
-func (x byName) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
-func (x byName) Less(i, j int) bool { return x[i].Name < x[j].Name }
-
-type bySize []objfile.Sym
-
-func (x bySize) Len() int { return len(x) }
-func (x bySize) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
-func (x bySize) Less(i, j int) bool { return x[i].Size > x[j].Size }
diff --git a/src/cmd/nm/nm_test.go b/src/cmd/nm/nm_test.go
index 602a288..ed1ad0d 100644
--- a/src/cmd/nm/nm_test.go
+++ b/src/cmd/nm/nm_test.go
@@ -65,7 +65,7 @@ func TestNM(t *testing.T) {
defer os.RemoveAll(tmpDir)
testnmpath := filepath.Join(tmpDir, "testnm.exe")
- out, err := exec.Command("go", "build", "-o", testnmpath, "cmd/nm").CombinedOutput()
+ out, err := exec.Command(testenv.GoToolPath(t), "build", "-o", testnmpath, "cmd/nm").CombinedOutput()
if err != nil {
t.Fatalf("go build -o %v cmd/nm: %v\n%s", testnmpath, err, string(out))
}
diff --git a/src/cmd/objdump/objdump_test.go b/src/cmd/objdump/objdump_test.go
index 899db06..30b964d 100644
--- a/src/cmd/objdump/objdump_test.go
+++ b/src/cmd/objdump/objdump_test.go
@@ -5,6 +5,8 @@
package main
import (
+ "flag"
+ "fmt"
"go/build"
"internal/testenv"
"io/ioutil"
@@ -16,21 +18,42 @@ import (
"testing"
)
-func buildObjdump(t *testing.T) (tmp, exe string) {
- testenv.MustHaveGoBuild(t)
+var tmp, exe string // populated by buildObjdump
- tmp, err := ioutil.TempDir("", "TestObjDump")
+func TestMain(m *testing.M) {
+ if !testenv.HasGoBuild() {
+ return
+ }
+ var exitcode int
+ if err := buildObjdump(); err == nil {
+ exitcode = m.Run()
+ } else {
+ fmt.Println(err)
+ exitcode = 1
+ }
+ os.RemoveAll(tmp)
+ os.Exit(exitcode)
+}
+
+func buildObjdump() error {
+ var err error
+ tmp, err = ioutil.TempDir("", "TestObjDump")
if err != nil {
- t.Fatal("TempDir failed: ", err)
+ return fmt.Errorf("TempDir failed: %v", err)
}
exe = filepath.Join(tmp, "testobjdump.exe")
- out, err := exec.Command("go", "build", "-o", exe, "cmd/objdump").CombinedOutput()
+ gotool, err := testenv.GoTool()
+ if err != nil {
+ return err
+ }
+ out, err := exec.Command(gotool, "build", "-o", exe, "cmd/objdump").CombinedOutput()
if err != nil {
os.RemoveAll(tmp)
- t.Fatalf("go build -o %v cmd/objdump: %v\n%s", exe, err, string(out))
+ return fmt.Errorf("go build -o %v cmd/objdump: %v\n%s", exe, err, string(out))
}
- return
+
+ return nil
}
var x86Need = []string{
@@ -49,6 +72,16 @@ var armNeed = []string{
"RET",
}
+var ppcNeed = []string{
+ "fmthello.go:6",
+ "TEXT main.main(SB)",
+ "BR main.main(SB)",
+ "CALL fmt.Println(SB)",
+ "RET",
+}
+
+var target = flag.String("target", "", "test disassembly of `goos/goarch` binary")
+
// objdump is fully cross platform: it can handle binaries
// from any known operating system and architecture.
// We could in principle add binaries to testdata and check
@@ -59,14 +92,24 @@ var armNeed = []string{
// can handle that one.
func testDisasm(t *testing.T, flags ...string) {
- tmp, exe := buildObjdump(t)
- defer os.RemoveAll(tmp)
+ goarch := runtime.GOARCH
+ if *target != "" {
+ f := strings.Split(*target, "/")
+ if len(f) != 2 {
+ t.Fatalf("-target argument must be goos/goarch")
+ }
+ defer os.Setenv("GOOS", os.Getenv("GOOS"))
+ defer os.Setenv("GOARCH", os.Getenv("GOARCH"))
+ os.Setenv("GOOS", f[0])
+ os.Setenv("GOARCH", f[1])
+ goarch = f[1]
+ }
hello := filepath.Join(tmp, "hello.exe")
args := []string{"build", "-o", hello}
args = append(args, flags...)
args = append(args, "testdata/fmthello.go")
- out, err := exec.Command("go", args...).CombinedOutput()
+ out, err := exec.Command(testenv.GoToolPath(t), args...).CombinedOutput()
if err != nil {
t.Fatalf("go build fmthello.go: %v\n%s", err, out)
}
@@ -74,11 +117,13 @@ func testDisasm(t *testing.T, flags ...string) {
"fmthello.go:6",
"TEXT main.main(SB)",
}
- switch runtime.GOARCH {
+ switch goarch {
case "amd64", "386":
need = append(need, x86Need...)
case "arm":
need = append(need, armNeed...)
+ case "ppc64", "ppc64le":
+ need = append(need, ppcNeed...)
}
out, err = exec.Command(exe, "-s", "main.main", hello).CombinedOutput()
@@ -101,11 +146,9 @@ func testDisasm(t *testing.T, flags ...string) {
func TestDisasm(t *testing.T) {
switch runtime.GOARCH {
- case "ppc64", "ppc64le":
- t.Skipf("skipping on %s, issue 9039", runtime.GOARCH)
case "arm64":
t.Skipf("skipping on %s, issue 10106", runtime.GOARCH)
- case "mips64", "mips64le":
+ 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)
@@ -119,7 +162,7 @@ func TestDisasmExtld(t *testing.T) {
t.Skipf("skipping on %s", runtime.GOOS)
}
switch runtime.GOARCH {
- case "ppc64", "ppc64le":
+ case "ppc64":
t.Skipf("skipping on %s, no support for external linking, issue 9038", runtime.GOARCH)
case "arm64":
t.Skipf("skipping on %s, issue 10106", runtime.GOARCH)
diff --git a/src/cmd/pack/pack_test.go b/src/cmd/pack/pack_test.go
index c305a87..79d9cde 100644
--- a/src/cmd/pack/pack_test.go
+++ b/src/cmd/pack/pack_test.go
@@ -218,10 +218,11 @@ func TestHello(t *testing.T) {
return doRun(t, dir, args...)
}
- run("go", "build", "cmd/pack") // writes pack binary to dir
- run("go", "tool", "compile", "hello.go")
+ goBin := testenv.GoToolPath(t)
+ run(goBin, "build", "cmd/pack") // writes pack binary to dir
+ run(goBin, "tool", "compile", "hello.go")
run("./pack", "grc", "hello.a", "hello.o")
- run("go", "tool", "link", "-o", "a.out", "hello.a")
+ run(goBin, "tool", "link", "-o", "a.out", "hello.a")
out := run("./a.out")
if out != "hello world\n" {
t.Fatalf("incorrect output: %q, want %q", out, "hello world\n")
@@ -282,11 +283,12 @@ func TestLargeDefs(t *testing.T) {
return doRun(t, dir, args...)
}
- run("go", "build", "cmd/pack") // writes pack binary to dir
- run("go", "tool", "compile", "large.go")
+ goBin := testenv.GoToolPath(t)
+ run(goBin, "build", "cmd/pack") // writes pack binary to dir
+ run(goBin, "tool", "compile", "large.go")
run("./pack", "grc", "large.a", "large.o")
- run("go", "tool", "compile", "-I", ".", "main.go")
- run("go", "tool", "link", "-L", ".", "-o", "a.out", "main.o")
+ run(goBin, "tool", "compile", "-I", ".", "main.go")
+ run(goBin, "tool", "link", "-L", ".", "-o", "a.out", "main.o")
out := run("./a.out")
if out != "ok\n" {
t.Fatalf("incorrect output: %q, want %q", out, "ok\n")
diff --git a/src/cmd/pprof/internal/commands/commands.go b/src/cmd/pprof/internal/commands/commands.go
new file mode 100644
index 0000000..9669cb9
--- /dev/null
+++ b/src/cmd/pprof/internal/commands/commands.go
@@ -0,0 +1,235 @@
+// Copyright 2014 The Go Authors. 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
new file mode 100644
index 0000000..931985a
--- /dev/null
+++ b/src/cmd/pprof/internal/driver/driver.go
@@ -0,0 +1,1042 @@
+// Copyright 2014 The Go Authors. 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, 1, "delay", "-total_delay", err)
+ si, err = sampleIndex(p, &f.flagMeanDelay, si, 1, "delay", "-mean_delay", err)
+ si, err = sampleIndex(p, &f.flagContentions, si, 0, "contentions", "-contentions", err)
+
+ si, err = sampleIndex(p, &f.flagInUseSpace, si, 1, "inuse_space", "-inuse_space", err)
+ si, err = sampleIndex(p, &f.flagInUseObjects, si, 0, "inuse_objects", "-inuse_objects", err)
+ si, err = sampleIndex(p, &f.flagAllocSpace, si, 1, "alloc_space", "-alloc_space", err)
+ si, err = sampleIndex(p, &f.flagAllocObjects, si, 0, "alloc_objects", "-alloc_objects", err)
+
+ if si == -1 {
+ // Use last value if none is requested.
+ si = len(p.SampleType) - 1
+ } else if si < 0 || si >= len(p.SampleType) {
+ err = fmt.Errorf("sample_index value %d out of range [0..%d]", si, len(p.SampleType)-1)
+ }
+
+ if err != nil {
+ f.usage(ui)
+ return err
+ }
+ f.flagSampleIndex, f.flagMean = newInt(si), newBool(sm)
+ return nil
+}
+
+func sampleIndex(p *profile.Profile, flag **bool,
+ sampleIndex int,
+ newSampleIndex int,
+ sampleType, option string,
+ err error) (int, error) {
+ if err != nil || !**flag {
+ return sampleIndex, err
+ }
+ *flag = newBool(false)
+ if sampleIndex != -1 {
+ return 0, fmt.Errorf("set at most one sample value selection option")
+ }
+ if newSampleIndex >= len(p.SampleType) ||
+ p.SampleType[newSampleIndex].Type != sampleType {
+ return 0, fmt.Errorf("option %s not valid for this profile", option)
+ }
+ return newSampleIndex, nil
+}
+
+func countFlags(bs []*bool) int {
+ var c int
+ for _, b := range bs {
+ if *b {
+ c++
+ }
+ }
+ return c
+}
+
+func countFlagMap(bms map[string]*bool, bmrxs map[string]*string) int {
+ var c int
+ for _, b := range bms {
+ if *b {
+ c++
+ }
+ }
+ for _, s := range bmrxs {
+ if *s != "" {
+ c++
+ }
+ }
+ return c
+}
+
+var usageMsgHdr = "usage: pprof [options] [binary] <profile source> ...\n" +
+ "Output format (only set one):\n"
+
+var usageMsg = "Output file parameters (for file-based output formats):\n" +
+ " -output=f Generate output on file f (stdout by default)\n" +
+ "Output granularity (only set one):\n" +
+ " -functions Report at function level [default]\n" +
+ " -files Report at source file level\n" +
+ " -lines Report at source line level\n" +
+ " -addresses Report at address level\n" +
+ "Comparison options:\n" +
+ " -base <profile> Show delta from this profile\n" +
+ " -drop_negative Ignore negative differences\n" +
+ "Sorting options:\n" +
+ " -cum Sort by cumulative data\n\n" +
+ "Dynamic profile options:\n" +
+ " -seconds=N Length of time for dynamic profiles\n" +
+ "Profile trimming options:\n" +
+ " -nodecount=N Max number of nodes to show\n" +
+ " -nodefraction=f Hide nodes below <f>*total\n" +
+ " -edgefraction=f Hide edges below <f>*total\n" +
+ "Sample value selection option (by index):\n" +
+ " -sample_index Index of sample value to display\n" +
+ " -mean Average sample value over first value\n" +
+ "Sample value selection option (for heap profiles):\n" +
+ " -inuse_space Display in-use memory size\n" +
+ " -inuse_objects Display in-use object counts\n" +
+ " -alloc_space Display allocated memory size\n" +
+ " -alloc_objects Display allocated object counts\n" +
+ "Sample value selection option (for contention profiles):\n" +
+ " -total_delay Display total delay at each region\n" +
+ " -contentions Display number of delays at each region\n" +
+ " -mean_delay Display mean delay at each region\n" +
+ "Filtering options:\n" +
+ " -runtime Show runtime call frames in memory profiles\n" +
+ " -focus=r Restricts to paths going through a node matching regexp\n" +
+ " -ignore=r Skips paths going through any nodes matching regexp\n" +
+ " -tagfocus=r Restrict to samples tagged with key:value matching regexp\n" +
+ " Restrict to samples with numeric tags in range (eg \"32kb:1mb\")\n" +
+ " -tagignore=r Discard samples tagged with key:value matching regexp\n" +
+ " Avoid samples with numeric tags in range (eg \"1mb:\")\n" +
+ "Miscellaneous:\n" +
+ " -call_tree Generate a context-sensitive call tree\n" +
+ " -unit=u Convert all samples to unit u for display\n" +
+ " -divide_by=f Scale all samples by dividing them by f\n" +
+ " -buildid=id Override build id for main binary in profile\n" +
+ " -tools=path Search path for object-level tools\n" +
+ " -help This message"
+
+var usageMsgVars = "Environment Variables:\n" +
+ " PPROF_TMPDIR Location for saved profiles (default $HOME/pprof)\n" +
+ " PPROF_TOOLS Search path for object-level tools\n" +
+ " PPROF_BINARY_PATH Search path for local binary files\n" +
+ " default: $HOME/pprof/binaries\n" +
+ " finds binaries by $name and $buildid/$name"
+
+func aggregate(prof *profile.Profile, f *flags) error {
+ switch {
+ case f.isFormat("proto"), f.isFormat("raw"):
+ // No aggregation for raw profiles.
+ case *f.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
new file mode 100644
index 0000000..1fa07a2
--- /dev/null
+++ b/src/cmd/pprof/internal/driver/interactive.go
@@ -0,0 +1,492 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package driver
+
+import (
+ "fmt"
+ "io"
+ "regexp"
+ "sort"
+ "strconv"
+ "strings"
+
+ "cmd/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
new file mode 100644
index 0000000..d3ccb65
--- /dev/null
+++ b/src/cmd/pprof/internal/fetch/fetch.go
@@ -0,0 +1,98 @@
+// Copyright 2014 The Go Authors. 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
new file mode 100644
index 0000000..ff1e8ad
--- /dev/null
+++ b/src/cmd/pprof/internal/plugin/plugin.go
@@ -0,0 +1,213 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package plugin defines the plugin implementations that the main pprof driver requires.
+package plugin
+
+import (
+ "bufio"
+ "fmt"
+ "os"
+ "regexp"
+ "strings"
+ "time"
+
+ "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
new file mode 100644
index 0000000..14875c1
--- /dev/null
+++ b/src/cmd/pprof/internal/report/report.go
@@ -0,0 +1,1726 @@
+// Copyright 2014 The Go Authors. 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[filepath.Base(m.File)] {
+ if address == nil || !(m.Start <= *address && *address <= m.Limit) {
+ continue
+ }
+ }
+
+ f, err := obj.Open(m.File, m.Start)
+ if err != nil {
+ fmt.Printf("%v\n", err)
+ continue
+ }
+
+ // Find symbols in this binary matching the user regexp.
+ var addr uint64
+ if address != nil {
+ addr = *address
+ }
+ msyms, err := f.Symbols(rx, addr)
+ base := f.Base()
+ f.Close()
+ if err != nil {
+ continue
+ }
+ for _, ms := range msyms {
+ objSyms = append(objSyms,
+ &objSymbol{
+ sym: ms,
+ base: base,
+ },
+ )
+ }
+ }
+
+ return objSyms
+}
+
+// objSym represents a symbol identified from a binary. It includes
+// the SymbolInfo from the disasm package and the base that must be
+// added to correspond to sample addresses
+type objSymbol struct {
+ sym *plugin.Sym
+ base uint64
+}
+
+// objSymbols is a wrapper type to enable sorting of []*objSymbol.
+type objSymbols []*objSymbol
+
+func (o objSymbols) Len() int {
+ return len(o)
+}
+
+func (o objSymbols) Less(i, j int) bool {
+ if namei, namej := o[i].sym.Name[0], o[j].sym.Name[0]; namei != namej {
+ return namei < namej
+ }
+ return o[i].sym.Start < o[j].sym.Start
+}
+
+func (o objSymbols) Swap(i, j int) {
+ o[i], o[j] = o[j], o[i]
+}
+
+// nodesPerSymbol classifies nodes into a group of symbols.
+func nodesPerSymbol(ns nodes, symbols []*objSymbol) map[*objSymbol]nodes {
+ symNodes := make(map[*objSymbol]nodes)
+ for _, s := range symbols {
+ // Gather samples for this symbol.
+ for _, n := range ns {
+ address := n.info.address - s.base
+ if address >= s.sym.Start && address < s.sym.End {
+ symNodes[s] = append(symNodes[s], n)
+ }
+ }
+ }
+ return symNodes
+}
+
+// annotateAssembly annotates a set of assembly instructions with a
+// set of samples. It returns a set of nodes to display. base is an
+// offset to adjust the sample addresses.
+func annotateAssembly(insns []plugin.Inst, samples nodes, base uint64) nodes {
+ // Add end marker to simplify printing loop.
+ insns = append(insns, plugin.Inst{
+ Addr: ^uint64(0),
+ })
+
+ // Ensure samples are sorted by address.
+ samples.sort(addressOrder)
+
+ var s int
+ var asm nodes
+ for ix, in := range insns[:len(insns)-1] {
+ n := node{
+ info: nodeInfo{
+ address: in.Addr,
+ name: in.Text,
+ file: trimPath(in.File),
+ lineno: in.Line,
+ },
+ }
+
+ // Sum all the samples until the next instruction (to account
+ // for samples attributed to the middle of an instruction).
+ for next := insns[ix+1].Addr; s < len(samples) && samples[s].info.address-base < next; s++ {
+ n.flat += samples[s].flat
+ n.cum += samples[s].cum
+ if samples[s].info.file != "" {
+ n.info.file = trimPath(samples[s].info.file)
+ n.info.lineno = samples[s].info.lineno
+ }
+ }
+ asm = append(asm, &n)
+ }
+
+ return asm
+}
+
+// valueOrDot formats a value according to a report, intercepting zero
+// values.
+func valueOrDot(value int64, rpt *Report) string {
+ if value == 0 {
+ return "."
+ }
+ return rpt.formatValue(value)
+}
+
+// printTags collects all tags referenced in the profile and prints
+// them in a sorted table.
+func printTags(w io.Writer, rpt *Report) error {
+ p := rpt.prof
+
+ // Hashtable to keep accumulate tags as key,value,count.
+ tagMap := make(map[string]map[string]int64)
+ for _, s := range p.Sample {
+ for key, vals := range s.Label {
+ for _, val := range vals {
+ if valueMap, ok := tagMap[key]; ok {
+ valueMap[val] = valueMap[val] + s.Value[0]
+ continue
+ }
+ valueMap := make(map[string]int64)
+ valueMap[val] = s.Value[0]
+ tagMap[key] = valueMap
+ }
+ }
+ for key, vals := range s.NumLabel {
+ for _, nval := range vals {
+ val := scaledValueLabel(nval, key, "auto")
+ if valueMap, ok := tagMap[key]; ok {
+ valueMap[val] = valueMap[val] + s.Value[0]
+ continue
+ }
+ valueMap := make(map[string]int64)
+ valueMap[val] = s.Value[0]
+ tagMap[key] = valueMap
+ }
+ }
+ }
+
+ tagKeys := make(tags, 0, len(tagMap))
+ for key := range tagMap {
+ tagKeys = append(tagKeys, &tag{name: key})
+ }
+ sort.Sort(tagKeys)
+
+ for _, tagKey := range tagKeys {
+ var total int64
+ key := tagKey.name
+ tags := make(tags, 0, len(tagMap[key]))
+ for t, c := range tagMap[key] {
+ total += c
+ tags = append(tags, &tag{name: t, weight: c})
+ }
+
+ sort.Sort(tags)
+ fmt.Fprintf(w, "%s: Total %d\n", key, total)
+ for _, t := range tags {
+ if total > 0 {
+ fmt.Fprintf(w, " %8d (%s): %s\n", t.weight,
+ percentage(t.weight, total), t.name)
+ } else {
+ fmt.Fprintf(w, " %8d: %s\n", t.weight, t.name)
+ }
+ }
+ fmt.Fprintln(w)
+ }
+ return nil
+}
+
+// printText prints a flat text report for a profile.
+func printText(w io.Writer, rpt *Report) error {
+ g, err := newGraph(rpt)
+ if err != nil {
+ return err
+ }
+
+ origCount, droppedNodes, _ := g.preprocess(rpt)
+ fmt.Fprintln(w, strings.Join(legendDetailLabels(rpt, g, origCount, droppedNodes, 0), "\n"))
+
+ fmt.Fprintf(w, "%10s %5s%% %5s%% %10s %5s%%\n",
+ "flat", "flat", "sum", "cum", "cum")
+
+ var flatSum int64
+ for _, n := range g.ns {
+ name, flat, cum := n.info.prettyName(), n.flat, n.cum
+
+ flatSum += flat
+ fmt.Fprintf(w, "%10s %s %s %10s %s %s\n",
+ rpt.formatValue(flat),
+ percentage(flat, rpt.total),
+ percentage(flatSum, rpt.total),
+ rpt.formatValue(cum),
+ percentage(cum, rpt.total),
+ name)
+ }
+ return nil
+}
+
+// printCallgrind prints a graph for a profile on callgrind format.
+func printCallgrind(w io.Writer, rpt *Report) error {
+ g, err := newGraph(rpt)
+ if err != nil {
+ return err
+ }
+
+ o := rpt.options
+ rpt.options.NodeFraction = 0
+ rpt.options.EdgeFraction = 0
+ rpt.options.NodeCount = 0
+
+ g.preprocess(rpt)
+
+ fmt.Fprintln(w, "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
new file mode 100644
index 0000000..7ab7e38
--- /dev/null
+++ b/src/cmd/pprof/internal/report/source.go
@@ -0,0 +1,454 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package report
+
+// This file contains routines related to the generation of annotated
+// source listings.
+
+import (
+ "bufio"
+ "fmt"
+ "html/template"
+ "io"
+ "os"
+ "path/filepath"
+ "sort"
+ "strconv"
+ "strings"
+
+ "cmd/pprof/internal/plugin"
+)
+
+// printSource prints an annotated source listing, include all
+// functions with samples that match the regexp rpt.options.symbol.
+// The sources are sorted by function name and then by filename to
+// eliminate potential nondeterminism.
+func printSource(w io.Writer, rpt *Report) error {
+ o := rpt.options
+ g, err := newGraph(rpt)
+ if err != nil {
+ return err
+ }
+
+ // Identify all the functions that match the regexp provided.
+ // Group nodes for each matching function.
+ var functions nodes
+ functionNodes := make(map[string]nodes)
+ for _, n := range g.ns {
+ if !o.Symbol.MatchString(n.info.name) {
+ continue
+ }
+ if functionNodes[n.info.name] == nil {
+ functions = append(functions, n)
+ }
+ functionNodes[n.info.name] = append(functionNodes[n.info.name], n)
+ }
+ functions.sort(nameOrder)
+
+ fmt.Fprintf(w, "Total: %s\n", rpt.formatValue(rpt.total))
+ for _, fn := range functions {
+ name := fn.info.name
+
+ // Identify all the source files associated to this function.
+ // Group nodes for each source file.
+ var sourceFiles nodes
+ fileNodes := make(map[string]nodes)
+ for _, n := range functionNodes[name] {
+ if n.info.file == "" {
+ continue
+ }
+ if fileNodes[n.info.file] == nil {
+ sourceFiles = append(sourceFiles, n)
+ }
+ fileNodes[n.info.file] = append(fileNodes[n.info.file], n)
+ }
+
+ if len(sourceFiles) == 0 {
+ fmt.Printf("No source information for %s\n", name)
+ continue
+ }
+
+ sourceFiles.sort(fileOrder)
+
+ // Print each file associated with this function.
+ for _, fl := range sourceFiles {
+ filename := fl.info.file
+ fns := fileNodes[filename]
+ flatSum, cumSum := sumNodes(fns)
+
+ fnodes, path, err := getFunctionSource(name, filename, fns, 0, 0)
+ fmt.Fprintf(w, "ROUTINE ======================== %s in %s\n", name, path)
+ fmt.Fprintf(w, "%10s %10s (flat, cum) %s of Total\n",
+ rpt.formatValue(flatSum), rpt.formatValue(cumSum),
+ percentage(cumSum, rpt.total))
+
+ if err != nil {
+ fmt.Fprintf(w, " Error: %v\n", err)
+ continue
+ }
+
+ for _, fn := range fnodes {
+ fmt.Fprintf(w, "%10s %10s %6d:%s\n", valueOrDot(fn.flat, rpt), valueOrDot(fn.cum, rpt), fn.info.lineno, fn.info.name)
+ }
+ }
+ }
+ return nil
+}
+
+// printWebSource prints an annotated source listing, include all
+// functions with samples that match the regexp rpt.options.symbol.
+func printWebSource(w io.Writer, rpt *Report, obj plugin.ObjTool) error {
+ o := rpt.options
+ g, err := newGraph(rpt)
+ if err != nil {
+ return err
+ }
+
+ // If the regexp source can be parsed as an address, also match
+ // functions that land on that address.
+ var address *uint64
+ if hex, err := strconv.ParseUint(o.Symbol.String(), 0, 64); err == nil {
+ address = &hex
+ }
+
+ // Extract interesting symbols from binary files in the profile and
+ // classify samples per symbol.
+ symbols := symbolsFromBinaries(rpt.prof, g, o.Symbol, address, obj)
+ symNodes := nodesPerSymbol(g.ns, symbols)
+
+ // Sort symbols for printing.
+ var syms objSymbols
+ for s := range symNodes {
+ syms = append(syms, s)
+ }
+ sort.Sort(syms)
+
+ if len(syms) == 0 {
+ return fmt.Errorf("no samples found on routines matching: %s", o.Symbol.String())
+ }
+
+ printHeader(w, rpt)
+ for _, s := range syms {
+ name := s.sym.Name[0]
+ // Identify sources associated to a symbol by examining
+ // symbol samples. Classify samples per source file.
+ var sourceFiles nodes
+ fileNodes := make(map[string]nodes)
+ for _, n := range symNodes[s] {
+ if n.info.file == "" {
+ continue
+ }
+ if fileNodes[n.info.file] == nil {
+ sourceFiles = append(sourceFiles, n)
+ }
+ fileNodes[n.info.file] = append(fileNodes[n.info.file], n)
+ }
+
+ if len(sourceFiles) == 0 {
+ fmt.Printf("No source information for %s\n", name)
+ continue
+ }
+
+ sourceFiles.sort(fileOrder)
+
+ // Print each file associated with this function.
+ for _, fl := range sourceFiles {
+ filename := fl.info.file
+ fns := fileNodes[filename]
+
+ asm := assemblyPerSourceLine(symbols, fns, filename, obj)
+ start, end := sourceCoordinates(asm)
+
+ fnodes, path, err := getFunctionSource(name, filename, fns, start, end)
+ if err != nil {
+ fnodes, path = getMissingFunctionSource(filename, asm, start, end)
+ }
+
+ flatSum, cumSum := sumNodes(fnodes)
+ printFunctionHeader(w, name, path, flatSum, cumSum, rpt)
+ for _, fn := range fnodes {
+ printFunctionSourceLine(w, fn, asm[fn.info.lineno], rpt)
+ }
+ printFunctionClosing(w)
+ }
+ }
+ printPageClosing(w)
+ return nil
+}
+
+// sourceCoordinates returns the lowest and highest line numbers from
+// a set of assembly statements.
+func sourceCoordinates(asm map[int]nodes) (start, end int) {
+ for l := range asm {
+ if start == 0 || l < start {
+ start = l
+ }
+ if end == 0 || l > end {
+ end = l
+ }
+ }
+ return start, end
+}
+
+// assemblyPerSourceLine disassembles the binary containing a symbol
+// and classifies the assembly instructions according to its
+// corresponding source line, annotating them with a set of samples.
+func assemblyPerSourceLine(objSyms []*objSymbol, rs nodes, src string, obj plugin.ObjTool) map[int]nodes {
+ assembly := make(map[int]nodes)
+ // Identify symbol to use for this collection of samples.
+ o := findMatchingSymbol(objSyms, rs)
+ if o == nil {
+ return assembly
+ }
+
+ // Extract assembly for matched symbol
+ insns, err := obj.Disasm(o.sym.File, o.sym.Start, o.sym.End)
+ if err != nil {
+ return assembly
+ }
+
+ srcBase := filepath.Base(src)
+ anodes := annotateAssembly(insns, rs, o.base)
+ var lineno = 0
+ for _, an := range anodes {
+ if filepath.Base(an.info.file) == srcBase {
+ lineno = an.info.lineno
+ }
+ if lineno != 0 {
+ assembly[lineno] = append(assembly[lineno], an)
+ }
+ }
+
+ return assembly
+}
+
+// findMatchingSymbol looks for the symbol that corresponds to a set
+// of samples, by comparing their addresses.
+func findMatchingSymbol(objSyms []*objSymbol, ns nodes) *objSymbol {
+ for _, n := range ns {
+ for _, o := range objSyms {
+ if filepath.Base(o.sym.File) == n.info.objfile &&
+ o.sym.Start <= n.info.address-o.base &&
+ n.info.address-o.base <= o.sym.End {
+ return o
+ }
+ }
+ }
+ return nil
+}
+
+// printHeader prints the page header for a weblist report.
+func printHeader(w io.Writer, rpt *Report) {
+ fmt.Fprintln(w, weblistPageHeader)
+
+ var labels []string
+ for _, l := range legendLabels(rpt) {
+ labels = append(labels, template.HTMLEscapeString(l))
+ }
+
+ fmt.Fprintf(w, `<div class="legend">%s<br>Total: %s</div>`,
+ strings.Join(labels, "<br>\n"),
+ rpt.formatValue(rpt.total),
+ )
+}
+
+// printFunctionHeader prints a function header for a weblist report.
+func printFunctionHeader(w io.Writer, name, path string, flatSum, cumSum int64, rpt *Report) {
+ fmt.Fprintf(w, `<h1>%s</h1>%s
+<pre onClick="pprof_toggle_asm(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/internal/pprof/report/source_html.go b/src/cmd/pprof/internal/report/source_html.go
similarity index 100%
rename from src/cmd/internal/pprof/report/source_html.go
rename to src/cmd/pprof/internal/report/source_html.go
diff --git a/src/cmd/internal/pprof/svg/svg.go b/src/cmd/pprof/internal/svg/svg.go
similarity index 100%
rename from src/cmd/internal/pprof/svg/svg.go
rename to src/cmd/pprof/internal/svg/svg.go
diff --git a/src/cmd/internal/pprof/svg/svgpan.go b/src/cmd/pprof/internal/svg/svgpan.go
similarity index 100%
rename from src/cmd/internal/pprof/svg/svgpan.go
rename to src/cmd/pprof/internal/svg/svgpan.go
diff --git a/src/cmd/pprof/internal/symbolizer/symbolizer.go b/src/cmd/pprof/internal/symbolizer/symbolizer.go
new file mode 100644
index 0000000..06a3976
--- /dev/null
+++ b/src/cmd/pprof/internal/symbolizer/symbolizer.go
@@ -0,0 +1,195 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package symbolizer provides a routine to populate a profile with
+// symbol, file and line number information. It relies on the
+// addr2liner and demangler packages to do the actual work.
+package symbolizer
+
+import (
+ "fmt"
+ "os"
+ "path/filepath"
+ "strings"
+
+ "cmd/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
new file mode 100644
index 0000000..6e58001
--- /dev/null
+++ b/src/cmd/pprof/internal/symbolz/symbolz.go
@@ -0,0 +1,111 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package symbolz symbolizes a profile using the output from the symbolz
+// service.
+package symbolz
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+ "net/url"
+ "regexp"
+ "strconv"
+ "strings"
+
+ "internal/pprof/profile"
+)
+
+var (
+ symbolzRE = regexp.MustCompile(`(0x[[:xdigit:]]+)\s+(.*)`)
+)
+
+// Symbolize symbolizes profile p by parsing data returned by a
+// symbolz handler. syms receives the symbolz query (hex addresses
+// separated by '+') and returns the symbolz output in a string. It
+// symbolizes all locations based on their addresses, regardless of
+// mapping.
+func Symbolize(source string, syms func(string, string) ([]byte, error), p *profile.Profile) error {
+ if source = symbolz(source, p); source == "" {
+ // If the source is not a recognizable URL, do nothing.
+ return nil
+ }
+
+ // Construct query of addresses to symbolize.
+ var a []string
+ for _, l := range p.Location {
+ if l.Address != 0 && len(l.Line) == 0 {
+ a = append(a, fmt.Sprintf("%#x", l.Address))
+ }
+ }
+
+ if len(a) == 0 {
+ // No addresses to symbolize.
+ return nil
+ }
+ lines := make(map[uint64]profile.Line)
+ functions := make(map[string]*profile.Function)
+ if b, err := syms(source, strings.Join(a, "+")); err == nil {
+ buf := bytes.NewBuffer(b)
+ for {
+ l, err := buf.ReadString('\n')
+
+ if err != nil {
+ if err == io.EOF {
+ break
+ }
+ return err
+ }
+
+ if symbol := symbolzRE.FindStringSubmatch(l); len(symbol) == 3 {
+ addr, err := strconv.ParseUint(symbol[1], 0, 64)
+ if err != nil {
+ return fmt.Errorf("unexpected parse failure %s: %v", symbol[1], err)
+ }
+
+ name := symbol[2]
+ fn := functions[name]
+ if fn == nil {
+ fn = &profile.Function{
+ ID: uint64(len(p.Function) + 1),
+ Name: name,
+ SystemName: name,
+ }
+ functions[name] = fn
+ p.Function = append(p.Function, fn)
+ }
+
+ lines[addr] = profile.Line{Function: fn}
+ }
+ }
+ }
+
+ for _, l := range p.Location {
+ if line, ok := lines[l.Address]; ok {
+ l.Line = []profile.Line{line}
+ if l.Mapping != nil {
+ l.Mapping.HasFunctions = true
+ }
+ }
+ }
+
+ return nil
+}
+
+// symbolz returns the corresponding symbolz source for a profile URL.
+func symbolz(source string, p *profile.Profile) string {
+ if url, err := url.Parse(source); err == nil && url.Host != "" {
+ if last := strings.LastIndex(url.Path, "/"); last != -1 {
+ if strings.HasSuffix(url.Path[:last], "pprof") {
+ url.Path = url.Path[:last] + "/symbol"
+ } else {
+ url.Path = url.Path[:last] + "/symbolz"
+ }
+ return url.String()
+ }
+ }
+
+ return ""
+}
diff --git a/src/cmd/internal/pprof/tempfile/tempfile.go b/src/cmd/pprof/internal/tempfile/tempfile.go
similarity index 100%
rename from src/cmd/internal/pprof/tempfile/tempfile.go
rename to src/cmd/pprof/internal/tempfile/tempfile.go
diff --git a/src/cmd/pprof/pprof.go b/src/cmd/pprof/pprof.go
index 5ee8a11..18479b4 100644
--- a/src/cmd/pprof/pprof.go
+++ b/src/cmd/pprof/pprof.go
@@ -6,7 +6,6 @@ package main
import (
"debug/dwarf"
- "debug/gosym"
"flag"
"fmt"
"net/url"
@@ -16,13 +15,13 @@ import (
"sync"
"cmd/internal/objfile"
- "cmd/internal/pprof/commands"
- "cmd/internal/pprof/driver"
- "cmd/internal/pprof/fetch"
- "cmd/internal/pprof/plugin"
- "cmd/internal/pprof/profile"
- "cmd/internal/pprof/symbolizer"
- "cmd/internal/pprof/symbolz"
+ "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"
)
func main() {
@@ -161,7 +160,7 @@ func (t *objTool) Disasm(file string, start, end uint64) ([]plugin.Inst, error)
return nil, err
}
var asm []plugin.Inst
- d.Decode(start, end, func(pc, size uint64, file string, line int, text string) {
+ 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})
})
return asm, nil
@@ -203,7 +202,7 @@ type file struct {
offset uint64
sym []objfile.Sym
file *objfile.File
- pcln *gosym.Table
+ pcln objfile.Liner
triedDwarf bool
dwarf *dwarf.Data
diff --git a/src/cmd/trace/main.go b/src/cmd/trace/main.go
index 893719e..c7bf75e 100644
--- a/src/cmd/trace/main.go
+++ b/src/cmd/trace/main.go
@@ -15,21 +15,29 @@ 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 (
"bufio"
+ "cmd/internal/browser"
"flag"
"fmt"
"html/template"
"internal/trace"
+ "io"
"log"
"net"
"net/http"
"os"
- "os/exec"
- "runtime"
"sync"
)
@@ -40,15 +48,27 @@ Given a trace file produced by 'go test':
Open a web browser displaying trace:
go tool trace [flags] [pkg.test] trace.out
+
+Generate a pprof-like profile from the trace:
+ go tool trace -pprof=TYPE [pkg.test] trace.out
+
[pkg.test] argument is required for traces produced by Go 1.6 and below.
Go 1.7 does not require the binary argument.
+Supported profile types are:
+ - net: network blocking profile
+ - sync: synchronization blocking profile
+ - syscall: syscall blocking profile
+ - sched: scheduler latency profile
+
Flags:
-http=addr: HTTP service address (e.g., ':6060')
+ -pprof=type: print a pprof-like profile instead
`
var (
- httpFlag = flag.String("http", "localhost:0", "HTTP service address (e.g., ':6060')")
+ httpFlag = flag.String("http", "localhost:0", "HTTP service address (e.g., ':6060')")
+ pprofFlag = flag.String("pprof", "", "print a pprof-like profile instead")
// The binary file name, left here for serveSVGProfile.
programBinary string
@@ -74,6 +94,27 @@ func main() {
flag.Usage()
}
+ var pprofFunc func(io.Writer) error
+ switch *pprofFlag {
+ case "net":
+ pprofFunc = pprofIO
+ case "sync":
+ pprofFunc = pprofBlock
+ case "syscall":
+ pprofFunc = pprofSyscall
+ case "sched":
+ pprofFunc = pprofSched
+ }
+ if pprofFunc != nil {
+ if err := pprofFunc(os.Stdout); err != nil {
+ dief("failed to generate pprof: %v\n", err)
+ }
+ os.Exit(0)
+ }
+ if *pprofFlag != "" {
+ dief("unknown pprof type %s\n", *pprofFlag)
+ }
+
ln, err := net.Listen("tcp", *httpFlag)
if err != nil {
dief("failed to create server socket: %v\n", err)
@@ -90,13 +131,16 @@ func main() {
events: events,
endTime: int64(1<<63 - 1),
}
- data := generateTrace(params)
+ data, err := generateTrace(params)
+ if err != nil {
+ dief("%v\n", err)
+ }
log.Printf("Splitting trace...")
ranges = splitTrace(data)
log.Printf("Opening browser")
- if !startBrowser("http://" + ln.Addr().String()) {
+ if !browser.Open("http://" + ln.Addr().String()) {
fmt.Fprintf(os.Stderr, "Trace viewer is listening on http://%s\n", ln.Addr().String())
}
@@ -162,24 +206,6 @@ var templMain = template.Must(template.New("").Parse(`
</html>
`))
-// startBrowser tries to open the URL in a browser
-// and reports whether it succeeds.
-// Note: copied from x/tools/cmd/cover/html.go
-func startBrowser(url string) bool {
- // try to start the browser
- var args []string
- switch runtime.GOOS {
- case "darwin":
- args = []string{"open"}
- case "windows":
- args = []string{"cmd", "/c", "start"}
- default:
- args = []string{"xdg-open"}
- }
- cmd := exec.Command(args[0], append(args[1:], url)...)
- return cmd.Start() == nil
-}
-
func dief(msg string, args ...interface{}) {
fmt.Fprintf(os.Stderr, msg, args...)
os.Exit(1)
diff --git a/src/cmd/trace/pprof.go b/src/cmd/trace/pprof.go
index fdda6d8..dea3a74 100644
--- a/src/cmd/trace/pprof.go
+++ b/src/cmd/trace/pprof.go
@@ -8,9 +8,10 @@ package main
import (
"bufio"
- "cmd/internal/pprof/profile"
"fmt"
+ "internal/pprof/profile"
"internal/trace"
+ "io"
"io/ioutil"
"net/http"
"os"
@@ -18,10 +19,10 @@ import (
)
func init() {
- http.HandleFunc("/io", httpIO)
- http.HandleFunc("/block", httpBlock)
- http.HandleFunc("/syscall", httpSyscall)
- http.HandleFunc("/sched", httpSched)
+ http.HandleFunc("/io", serveSVGProfile(pprofIO))
+ http.HandleFunc("/block", serveSVGProfile(pprofBlock))
+ http.HandleFunc("/syscall", serveSVGProfile(pprofSyscall))
+ http.HandleFunc("/sched", serveSVGProfile(pprofSched))
}
// Record represents one entry in pprof-like profiles.
@@ -31,12 +32,11 @@ type Record struct {
time int64
}
-// httpIO serves IO pprof-like profile (time spent in IO wait).
-func httpIO(w http.ResponseWriter, r *http.Request) {
+// pprofIO generates IO pprof-like profile (time spent in IO wait).
+func pprofIO(w io.Writer) error {
events, err := parseEvents()
if err != nil {
- http.Error(w, err.Error(), http.StatusInternalServerError)
- return
+ return err
}
prof := make(map[uint64]Record)
for _, ev := range events {
@@ -49,21 +49,20 @@ func httpIO(w http.ResponseWriter, r *http.Request) {
rec.time += ev.Link.Ts - ev.Ts
prof[ev.StkID] = rec
}
- serveSVGProfile(w, r, prof)
+ return buildProfile(prof).Write(w)
}
-// httpBlock serves blocking pprof-like profile (time spent blocked on synchronization primitives).
-func httpBlock(w http.ResponseWriter, r *http.Request) {
+// pprofBlock generates blocking pprof-like profile (time spent blocked on synchronization primitives).
+func pprofBlock(w io.Writer) error {
events, err := parseEvents()
if err != nil {
- http.Error(w, err.Error(), http.StatusInternalServerError)
- return
+ return err
}
prof := make(map[uint64]Record)
for _, ev := range events {
switch ev.Type {
case trace.EvGoBlockSend, trace.EvGoBlockRecv, trace.EvGoBlockSelect,
- trace.EvGoBlockSync, trace.EvGoBlockCond:
+ trace.EvGoBlockSync, trace.EvGoBlockCond, trace.EvGoBlockGC:
default:
continue
}
@@ -76,15 +75,14 @@ func httpBlock(w http.ResponseWriter, r *http.Request) {
rec.time += ev.Link.Ts - ev.Ts
prof[ev.StkID] = rec
}
- serveSVGProfile(w, r, prof)
+ return buildProfile(prof).Write(w)
}
-// httpSyscall serves syscall pprof-like profile (time spent blocked in syscalls).
-func httpSyscall(w http.ResponseWriter, r *http.Request) {
+// pprofSyscall generates syscall pprof-like profile (time spent blocked in syscalls).
+func pprofSyscall(w io.Writer) error {
events, err := parseEvents()
if err != nil {
- http.Error(w, err.Error(), http.StatusInternalServerError)
- return
+ return err
}
prof := make(map[uint64]Record)
for _, ev := range events {
@@ -97,16 +95,15 @@ func httpSyscall(w http.ResponseWriter, r *http.Request) {
rec.time += ev.Link.Ts - ev.Ts
prof[ev.StkID] = rec
}
- serveSVGProfile(w, r, prof)
+ return buildProfile(prof).Write(w)
}
-// httpSched serves scheduler latency pprof-like profile
+// pprofSched generates scheduler latency pprof-like profile
// (time between a goroutine become runnable and actually scheduled for execution).
-func httpSched(w http.ResponseWriter, r *http.Request) {
+func pprofSched(w io.Writer) error {
events, err := parseEvents()
if err != nil {
- http.Error(w, err.Error(), http.StatusInternalServerError)
- return
+ return err
}
prof := make(map[uint64]Record)
for _, ev := range events {
@@ -120,45 +117,43 @@ func httpSched(w http.ResponseWriter, r *http.Request) {
rec.time += ev.Link.Ts - ev.Ts
prof[ev.StkID] = rec
}
- serveSVGProfile(w, r, prof)
+ return buildProfile(prof).Write(w)
}
-// generateSVGProfile generates pprof-like profile stored in prof and writes in to w.
-func serveSVGProfile(w http.ResponseWriter, r *http.Request, prof map[uint64]Record) {
- if len(prof) == 0 {
- http.Error(w, "The profile is empty", http.StatusNotFound)
- return
- }
- blockf, err := ioutil.TempFile("", "block")
- if err != nil {
- http.Error(w, fmt.Sprintf("failed to create temp file: %v", err), http.StatusInternalServerError)
- return
- }
- defer func() {
- blockf.Close()
- os.Remove(blockf.Name())
- }()
- blockb := bufio.NewWriter(blockf)
- if err := buildProfile(prof).Write(blockb); err != nil {
- http.Error(w, fmt.Sprintf("failed to write profile: %v", err), http.StatusInternalServerError)
- return
- }
- if err := blockb.Flush(); err != nil {
- http.Error(w, fmt.Sprintf("failed to flush temp file: %v", err), http.StatusInternalServerError)
- return
- }
- if err := blockf.Close(); err != nil {
- http.Error(w, fmt.Sprintf("failed to close temp file: %v", err), http.StatusInternalServerError)
- return
- }
- svgFilename := blockf.Name() + ".svg"
- if output, err := exec.Command("go", "tool", "pprof", "-svg", "-output", svgFilename, blockf.Name()).CombinedOutput(); err != nil {
- http.Error(w, fmt.Sprintf("failed to execute go tool pprof: %v\n%s", err, output), http.StatusInternalServerError)
- return
+// serveSVGProfile serves pprof-like profile generated by prof as svg.
+func serveSVGProfile(prof func(w io.Writer) error) http.HandlerFunc {
+ return func(w http.ResponseWriter, r *http.Request) {
+ blockf, err := ioutil.TempFile("", "block")
+ if err != nil {
+ http.Error(w, fmt.Sprintf("failed to create temp file: %v", err), http.StatusInternalServerError)
+ return
+ }
+ defer func() {
+ blockf.Close()
+ os.Remove(blockf.Name())
+ }()
+ blockb := bufio.NewWriter(blockf)
+ if err := prof(blockb); err != nil {
+ http.Error(w, fmt.Sprintf("failed to generate profile: %v", err), http.StatusInternalServerError)
+ return
+ }
+ if err := blockb.Flush(); err != nil {
+ http.Error(w, fmt.Sprintf("failed to flush temp file: %v", err), http.StatusInternalServerError)
+ return
+ }
+ if err := blockf.Close(); err != nil {
+ http.Error(w, fmt.Sprintf("failed to close temp file: %v", err), http.StatusInternalServerError)
+ return
+ }
+ svgFilename := blockf.Name() + ".svg"
+ if output, err := exec.Command("go", "tool", "pprof", "-svg", "-output", svgFilename, blockf.Name()).CombinedOutput(); err != nil {
+ http.Error(w, fmt.Sprintf("failed to execute go tool pprof: %v\n%s", err, output), http.StatusInternalServerError)
+ return
+ }
+ defer os.Remove(svgFilename)
+ w.Header().Set("Content-Type", "image/svg+xml")
+ http.ServeFile(w, r, svgFilename)
}
- defer os.Remove(svgFilename)
- w.Header().Set("Content-Type", "image/svg+xml")
- http.ServeFile(w, r, svgFilename)
}
func buildProfile(prof map[uint64]Record) *profile.Profile {
diff --git a/src/cmd/trace/trace.go b/src/cmd/trace/trace.go
index 2b6a37b..f5a2df4 100644
--- a/src/cmd/trace/trace.go
+++ b/src/cmd/trace/trace.go
@@ -160,7 +160,11 @@ func httpJsonTrace(w http.ResponseWriter, r *http.Request) {
params.gs = trace.RelatedGoroutines(events, goid)
}
- data := generateTrace(params)
+ data, err := generateTrace(params)
+ if err != nil {
+ log.Printf("failed to generate trace: %v", err)
+ return
+ }
if startStr, endStr := r.FormValue("start"), r.FormValue("end"); startStr != "" && endStr != "" {
// If start/end arguments are present, we are rendering a range of the trace.
@@ -250,11 +254,19 @@ type traceContext struct {
frameTree frameNode
frameSeq int
arrowSeq uint64
+ gcount uint64
+
+ heapStats, prevHeapStats heapStats
+ threadStats, prevThreadStats threadStats
+ gstates, prevGstates [gStateCount]uint64
+}
+
+type heapStats struct {
heapAlloc uint64
nextGC uint64
- gcount uint64
- grunnable uint64
- grunning uint64
+}
+
+type threadStats struct {
insyscall uint64
prunning uint64
}
@@ -264,6 +276,18 @@ type frameNode struct {
children map[uint64]frameNode
}
+type gState int
+
+const (
+ gDead gState = iota
+ gRunnable
+ gRunning
+ gWaiting
+ gWaitingGC
+
+ gStateCount
+)
+
type ViewerData struct {
Events []*ViewerEvent `json:"traceEvents"`
Frames map[string]ViewerFrame `json:"stackFrames"`
@@ -307,17 +331,34 @@ type SortIndexArg struct {
// If gtrace=true, generate trace for goroutine goid, otherwise whole trace.
// startTime, endTime determine part of the trace that we are interested in.
// gset restricts goroutines that are included in the resulting trace.
-func generateTrace(params *traceParams) ViewerData {
+func generateTrace(params *traceParams) (ViewerData, error) {
ctx := &traceContext{traceParams: params}
ctx.frameTree.children = make(map[uint64]frameNode)
ctx.data.Frames = make(map[string]ViewerFrame)
ctx.data.TimeUnit = "ns"
maxProc := 0
gnames := make(map[uint64]string)
+ gstates := make(map[uint64]gState)
+ // 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 {
+ // For checking, gWaiting counts as any gWaiting*.
+ oldState = gstates[g]
+ }
+ if gstates[g] != 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[newState]++
+ gstates[g] = newState
+ }
for _, ev := range ctx.events {
- // Handle trace.EvGoStart separately, because we need the goroutine name
- // even if ignore the event otherwise.
- if ev.Type == trace.EvGoStart {
+ // 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 {
if len(ev.Stk) > 0 {
gnames[ev.G] = fmt.Sprintf("G%v %s", ev.G, ev.Stk[0].Fn)
@@ -325,6 +366,48 @@ func generateTrace(params *traceParams) ViewerData {
gnames[ev.G] = fmt.Sprintf("G%v", ev.G)
}
}
+ case trace.EvProcStart:
+ ctx.threadStats.prunning++
+ case trace.EvProcStop:
+ ctx.threadStats.prunning--
+ case trace.EvGoCreate:
+ ctx.gcount++
+ setGState(ev, ev.Args[0], gDead, gRunnable)
+ case trace.EvGoEnd:
+ ctx.gcount--
+ setGState(ev, ev.G, gRunning, gDead)
+ case trace.EvGoUnblock:
+ setGState(ev, ev.Args[0], gWaiting, gRunnable)
+ case trace.EvGoSysExit:
+ setGState(ev, ev.G, gWaiting, gRunnable)
+ ctx.threadStats.insyscall--
+ case trace.EvGoSysBlock:
+ setGState(ev, ev.G, gRunning, gWaiting)
+ ctx.threadStats.insyscall++
+ case trace.EvGoSched, trace.EvGoPreempt:
+ setGState(ev, ev.G, gRunning, gRunnable)
+ case trace.EvGoStop,
+ trace.EvGoSleep, trace.EvGoBlock, trace.EvGoBlockSend, trace.EvGoBlockRecv,
+ trace.EvGoBlockSelect, trace.EvGoBlockSync, trace.EvGoBlockCond, trace.EvGoBlockNet:
+ setGState(ev, ev.G, gRunning, gWaiting)
+ case trace.EvGoBlockGC:
+ setGState(ev, ev.G, gRunning, gWaitingGC)
+ case trace.EvGoWaiting:
+ setGState(ev, ev.G, gRunnable, gWaiting)
+ case trace.EvGoInSyscall:
+ // Cancel out the effect of EvGoCreate at the beginning.
+ setGState(ev, ev.G, gRunnable, gWaiting)
+ ctx.threadStats.insyscall++
+ case trace.EvHeapAlloc:
+ ctx.heapStats.heapAlloc = ev.Args[0]
+ case trace.EvNextGC:
+ ctx.heapStats.nextGC = ev.Args[0]
+ }
+ if setGStateErr != nil {
+ return ctx.data, setGStateErr
+ }
+ if ctx.gstates[gRunnable] < 0 || ctx.gstates[gRunning] < 0 || ctx.threadStats.insyscall < 0 {
+ return ctx.data, fmt.Errorf("invalid state after processing %v: runnable=%d running=%d insyscall=%d", ev, ctx.gstates[gRunnable], ctx.gstates[gRunning], ctx.threadStats.insyscall)
}
// Ignore events that are from uninteresting goroutines
@@ -340,20 +423,17 @@ func generateTrace(params *traceParams) ViewerData {
maxProc = ev.P
}
+ // Emit trace objects.
switch ev.Type {
case trace.EvProcStart:
if ctx.gtrace {
continue
}
- ctx.prunning++
- ctx.emitThreadCounters(ev)
ctx.emitInstant(ev, "proc start")
case trace.EvProcStop:
if ctx.gtrace {
continue
}
- ctx.prunning--
- ctx.emitThreadCounters(ev)
ctx.emitInstant(ev, "proc stop")
case trace.EvGCStart:
ctx.emitSlice(ev, "GC")
@@ -362,64 +442,28 @@ func generateTrace(params *traceParams) ViewerData {
if ctx.gtrace {
continue
}
- ctx.emitSlice(ev, "MARK")
+ ctx.emitSlice(ev, "MARK TERMINATION")
case trace.EvGCScanDone:
case trace.EvGCSweepStart:
ctx.emitSlice(ev, "SWEEP")
case trace.EvGCSweepDone:
case trace.EvGoStart:
- ctx.grunnable--
- ctx.grunning++
- ctx.emitGoroutineCounters(ev)
ctx.emitSlice(ev, gnames[ev.G])
+ case trace.EvGoStartLabel:
+ ctx.emitSlice(ev, ev.SArgs[0])
case trace.EvGoCreate:
- ctx.gcount++
- ctx.grunnable++
- ctx.emitGoroutineCounters(ev)
ctx.emitArrow(ev, "go")
- case trace.EvGoEnd:
- ctx.gcount--
- ctx.grunning--
- ctx.emitGoroutineCounters(ev)
case trace.EvGoUnblock:
- ctx.grunnable++
- ctx.emitGoroutineCounters(ev)
ctx.emitArrow(ev, "unblock")
case trace.EvGoSysCall:
ctx.emitInstant(ev, "syscall")
case trace.EvGoSysExit:
- ctx.grunnable++
- ctx.emitGoroutineCounters(ev)
- ctx.insyscall--
- ctx.emitThreadCounters(ev)
ctx.emitArrow(ev, "sysexit")
- case trace.EvGoSysBlock:
- ctx.grunning--
- ctx.emitGoroutineCounters(ev)
- ctx.insyscall++
- ctx.emitThreadCounters(ev)
- case trace.EvGoSched, trace.EvGoPreempt:
- ctx.grunnable++
- ctx.grunning--
- ctx.emitGoroutineCounters(ev)
- case trace.EvGoStop,
- trace.EvGoSleep, trace.EvGoBlock, trace.EvGoBlockSend, trace.EvGoBlockRecv,
- trace.EvGoBlockSelect, trace.EvGoBlockSync, trace.EvGoBlockCond, trace.EvGoBlockNet:
- ctx.grunning--
- ctx.emitGoroutineCounters(ev)
- case trace.EvGoWaiting:
- ctx.grunnable--
- ctx.emitGoroutineCounters(ev)
- case trace.EvGoInSyscall:
- ctx.insyscall++
- ctx.emitThreadCounters(ev)
- case trace.EvHeapAlloc:
- ctx.heapAlloc = ev.Args[0]
- ctx.emitHeapCounters(ev)
- case trace.EvNextGC:
- ctx.nextGC = ev.Args[0]
- ctx.emitHeapCounters(ev)
}
+ // Emit any counter updates.
+ ctx.emitThreadCounters(ev)
+ ctx.emitHeapCounters(ev)
+ ctx.emitGoroutineCounters(ev)
}
ctx.data.footer = len(ctx.data.Events)
@@ -429,6 +473,9 @@ func generateTrace(params *traceParams) ViewerData {
ctx.emit(&ViewerEvent{Name: "process_name", Phase: "M", Pid: 1, Arg: &NameArg{"STATS"}})
ctx.emit(&ViewerEvent{Name: "process_sort_index", Phase: "M", Pid: 1, Arg: &SortIndexArg{0}})
+ ctx.emit(&ViewerEvent{Name: "thread_name", Phase: "M", Pid: 0, Tid: trace.GCP, Arg: &NameArg{"GC"}})
+ ctx.emit(&ViewerEvent{Name: "thread_sort_index", Phase: "M", Pid: 0, Tid: trace.GCP, Arg: &SortIndexArg{-6}})
+
ctx.emit(&ViewerEvent{Name: "thread_name", Phase: "M", Pid: 0, Tid: trace.NetpollP, Arg: &NameArg{"Network"}})
ctx.emit(&ViewerEvent{Name: "thread_sort_index", Phase: "M", Pid: 0, Tid: trace.NetpollP, Arg: &SortIndexArg{-5}})
@@ -456,7 +503,7 @@ func generateTrace(params *traceParams) ViewerData {
ctx.emit(&ViewerEvent{Name: "thread_sort_index", Phase: "M", Pid: 0, Tid: 0, Arg: &SortIndexArg{-1}})
}
- return ctx.data
+ return ctx.data, nil
}
func (ctx *traceContext) emit(e *ViewerEvent) {
@@ -488,41 +535,57 @@ func (ctx *traceContext) emitSlice(ev *trace.Event, name string) {
})
}
+type heapCountersArg struct {
+ Allocated uint64
+ NextGC uint64
+}
+
func (ctx *traceContext) emitHeapCounters(ev *trace.Event) {
- type Arg struct {
- Allocated uint64
- NextGC uint64
- }
if ctx.gtrace {
return
}
+ if ctx.prevHeapStats == ctx.heapStats {
+ return
+ }
diff := uint64(0)
- if ctx.nextGC > ctx.heapAlloc {
- diff = ctx.nextGC - ctx.heapAlloc
+ if ctx.heapStats.nextGC > ctx.heapStats.heapAlloc {
+ diff = ctx.heapStats.nextGC - ctx.heapStats.heapAlloc
}
- ctx.emit(&ViewerEvent{Name: "Heap", Phase: "C", Time: ctx.time(ev), Pid: 1, Arg: &Arg{ctx.heapAlloc, diff}})
+ ctx.emit(&ViewerEvent{Name: "Heap", Phase: "C", Time: ctx.time(ev), Pid: 1, Arg: &heapCountersArg{ctx.heapStats.heapAlloc, diff}})
+ ctx.prevHeapStats = ctx.heapStats
+}
+
+type goroutineCountersArg struct {
+ Running uint64
+ Runnable uint64
+ GCWaiting uint64
}
func (ctx *traceContext) emitGoroutineCounters(ev *trace.Event) {
- type Arg struct {
- Running uint64
- Runnable uint64
- }
if ctx.gtrace {
return
}
- ctx.emit(&ViewerEvent{Name: "Goroutines", Phase: "C", Time: ctx.time(ev), Pid: 1, Arg: &Arg{ctx.grunning, ctx.grunnable}})
+ if ctx.prevGstates == ctx.gstates {
+ return
+ }
+ ctx.emit(&ViewerEvent{Name: "Goroutines", Phase: "C", Time: ctx.time(ev), Pid: 1, Arg: &goroutineCountersArg{ctx.gstates[gRunning], ctx.gstates[gRunnable], ctx.gstates[gWaitingGC]}})
+ ctx.prevGstates = ctx.gstates
+}
+
+type threadCountersArg struct {
+ Running uint64
+ InSyscall uint64
}
func (ctx *traceContext) emitThreadCounters(ev *trace.Event) {
- type Arg struct {
- Running uint64
- InSyscall uint64
- }
if ctx.gtrace {
return
}
- ctx.emit(&ViewerEvent{Name: "Threads", Phase: "C", Time: ctx.time(ev), Pid: 1, Arg: &Arg{ctx.prunning, ctx.insyscall}})
+ if ctx.prevThreadStats == ctx.threadStats {
+ return
+ }
+ ctx.emit(&ViewerEvent{Name: "Threads", Phase: "C", Time: ctx.time(ev), Pid: 1, Arg: &threadCountersArg{ctx.threadStats.prunning, ctx.threadStats.insyscall}})
+ ctx.prevThreadStats = ctx.threadStats
}
func (ctx *traceContext) emitInstant(ev *trace.Event, name string) {
diff --git a/src/cmd/trace/trace_test.go b/src/cmd/trace/trace_test.go
new file mode 100644
index 0000000..d14239c
--- /dev/null
+++ b/src/cmd/trace/trace_test.go
@@ -0,0 +1,101 @@
+package main
+
+import (
+ "internal/trace"
+ "testing"
+)
+
+// TestGoroutineCount tests runnable/running goroutine counts computed by generateTrace
+// remain in the valid range.
+// - the counts must not be negative. generateTrace will return an error.
+// - the counts must not include goroutines blocked waiting on channels or in syscall.
+func TestGoroutineCount(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]
+
+ // In this test, we assume a valid trace contains EvGoWaiting or EvGoInSyscall
+ // event for every blocked goroutine.
+
+ // goroutine 10: blocked
+ w.Emit(trace.EvGoCreate, 1, 10, 1, 1) // [timestamp, new goroutine id, new stack id, stack id]
+ w.Emit(trace.EvGoWaiting, 1, 10) // [timestamp, goroutine id]
+
+ // goroutine 20: in syscall
+ w.Emit(trace.EvGoCreate, 1, 20, 2, 1)
+ w.Emit(trace.EvGoInSyscall, 1, 20) // [timestamp, goroutine id]
+
+ // goroutine 30: runnable
+ w.Emit(trace.EvGoCreate, 1, 30, 5, 1)
+
+ w.Emit(trace.EvProcStart, 2, 0) // [timestamp, thread id]
+
+ // goroutine 40: runnable->running->runnable
+ w.Emit(trace.EvGoCreate, 1, 40, 7, 1)
+ w.Emit(trace.EvGoStartLocal, 1, 40) // [timestamp, goroutine id]
+ w.Emit(trace.EvGoSched, 1, 8) // [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),
+ }
+
+ // If the counts drop below 0, generateTrace will return an error.
+ viewerData, err := generateTrace(params)
+ if err != nil {
+ t.Fatalf("generateTrace failed: %v", err)
+ }
+ for _, ev := range viewerData.Events {
+ if ev.Name == "Goroutines" {
+ cnt := ev.Arg.(*goroutineCountersArg)
+ if cnt.Runnable+cnt.Running > 2 {
+ t.Errorf("goroutine count=%+v; want no more than 2 goroutines in runnable/running state", cnt)
+ }
+ t.Logf("read %+v %+v", ev, cnt)
+ }
+ }
+}
+
+func TestGoroutineFilter(t *testing.T) {
+ // Test that we handle state changes to selected goroutines
+ // caused by events on goroutines that are not selected.
+
+ 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 10: blocked
+ w.Emit(trace.EvGoCreate, 1, 10, 1, 1) // [timestamp, new goroutine id, new stack id, stack id]
+ w.Emit(trace.EvGoWaiting, 1, 10) // [timestamp, goroutine id]
+
+ // goroutine 20: runnable->running->unblock 10
+ w.Emit(trace.EvGoCreate, 1, 20, 7, 1)
+ w.Emit(trace.EvGoStartLocal, 1, 20) // [timestamp, goroutine id]
+ w.Emit(trace.EvGoUnblockLocal, 1, 10, 8) // [timestamp, goroutine id, stack]
+ w.Emit(trace.EvGoEnd, 1) // [timestamp]
+
+ // goroutine 10: runnable->running->block
+ w.Emit(trace.EvGoStartLocal, 1, 10) // [timestamp, goroutine id]
+ w.Emit(trace.EvGoBlock, 1, 9) // [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),
+ gs: map[uint64]bool{10: true},
+ }
+
+ _, err = generateTrace(params)
+ if err != nil {
+ t.Fatalf("generateTrace failed: %v", err)
+ }
+}
diff --git a/src/cmd/vendor/golang.org/x/arch/ppc64/ppc64asm/decode.go b/src/cmd/vendor/golang.org/x/arch/ppc64/ppc64asm/decode.go
new file mode 100644
index 0000000..e1518d5
--- /dev/null
+++ b/src/cmd/vendor/golang.org/x/arch/ppc64/ppc64asm/decode.go
@@ -0,0 +1,179 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ppc64asm
+
+import (
+ "encoding/binary"
+ "fmt"
+ "log"
+)
+
+const debugDecode = false
+
+// instFormat is a decoding rule for one specific instruction form.
+// a uint32 instruction ins matches the rule if ins&Mask == Value
+// DontCare bits should be zero, but the machine might not reject
+// ones in those bits, they are mainly reserved for future expansion
+// of the instruction set.
+// The Args are stored in the same order as the instruction manual.
+type instFormat struct {
+ Op Op
+ Mask uint32
+ Value uint32
+ DontCare uint32
+ Args [5]*argField
+}
+
+// argField indicate how to decode an argument to an instruction.
+// First parse the value from the BitFields, shift it left by Shift
+// bits to get the actual numerical value.
+type argField struct {
+ Type ArgType
+ Shift uint8
+ BitFields
+}
+
+// Parse parses the Arg out from the given binary instruction i.
+func (a argField) Parse(i uint32) Arg {
+ switch a.Type {
+ default:
+ return nil
+ case TypeUnknown:
+ return nil
+ case TypeReg:
+ return R0 + Reg(a.BitFields.Parse(i))
+ case TypeCondRegBit:
+ return Cond0LT + CondReg(a.BitFields.Parse(i))
+ case TypeCondRegField:
+ return CR0 + CondReg(a.BitFields.Parse(i))
+ case TypeFPReg:
+ return F0 + Reg(a.BitFields.Parse(i))
+ case TypeVecReg:
+ return V0 + Reg(a.BitFields.Parse(i))
+ case TypeVecSReg:
+ return VS0 + Reg(a.BitFields.Parse(i))
+ case TypeSpReg:
+ return SpReg(a.BitFields.Parse(i))
+ case TypeImmSigned:
+ return Imm(a.BitFields.ParseSigned(i) << a.Shift)
+ case TypeImmUnsigned:
+ return Imm(a.BitFields.Parse(i) << a.Shift)
+ case TypePCRel:
+ return PCRel(a.BitFields.ParseSigned(i) << a.Shift)
+ case TypeLabel:
+ return Label(a.BitFields.ParseSigned(i) << a.Shift)
+ case TypeOffset:
+ return Offset(a.BitFields.ParseSigned(i) << a.Shift)
+ }
+}
+
+type ArgType int8
+
+const (
+ TypeUnknown ArgType = iota
+ TypePCRel // PC-relative address
+ TypeLabel // absolute address
+ TypeReg // integer register
+ TypeCondRegBit // conditional register bit (0-31)
+ TypeCondRegField // conditional register field (0-7)
+ TypeFPReg // floating point register
+ TypeVecReg // vector register
+ TypeVecSReg // VSX register
+ TypeSpReg // special register (depends on Op)
+ TypeImmSigned // signed immediate
+ TypeImmUnsigned // unsigned immediate/flag/mask, this is the catch-all type
+ TypeOffset // signed offset in load/store
+ TypeLast // must be the last one
+)
+
+func (t ArgType) String() string {
+ switch t {
+ default:
+ return fmt.Sprintf("ArgType(%d)", int(t))
+ case TypeUnknown:
+ return "Unknown"
+ case TypeReg:
+ return "Reg"
+ case TypeCondRegBit:
+ return "CondRegBit"
+ case TypeCondRegField:
+ return "CondRegField"
+ case TypeFPReg:
+ return "FPReg"
+ case TypeVecReg:
+ return "VecReg"
+ case TypeVecSReg:
+ return "VecSReg"
+ case TypeSpReg:
+ return "SpReg"
+ case TypeImmSigned:
+ return "ImmSigned"
+ case TypeImmUnsigned:
+ return "ImmUnsigned"
+ case TypePCRel:
+ return "PCRel"
+ case TypeLabel:
+ return "Label"
+ case TypeOffset:
+ return "Offset"
+ }
+}
+
+func (t ArgType) GoString() string {
+ s := t.String()
+ if t > 0 && t < TypeLast {
+ return "Type" + s
+ }
+ return s
+}
+
+var (
+ // Errors
+ errShort = fmt.Errorf("truncated instruction")
+ errUnknown = fmt.Errorf("unknown instruction")
+)
+
+var decoderCover []bool
+
+// Decode decodes the leading bytes in src as a single instruction using
+// byte order ord.
+func Decode(src []byte, ord binary.ByteOrder) (inst Inst, err error) {
+ if len(src) < 4 {
+ return inst, errShort
+ }
+ if decoderCover == nil {
+ decoderCover = make([]bool, len(instFormats))
+ }
+ inst.Len = 4 // only 4-byte instructions are supported
+ ui := ord.Uint32(src[:inst.Len])
+ inst.Enc = ui
+ for i, iform := range instFormats {
+ if ui&iform.Mask != iform.Value {
+ continue
+ }
+ if ui&iform.DontCare != 0 {
+ if debugDecode {
+ log.Printf("Decode(%#x): unused bit is 1 for Op %s", ui, iform.Op)
+ }
+ // to match GNU objdump (libopcodes), we ignore don't care bits
+ }
+ for i, argfield := range iform.Args {
+ if argfield == nil {
+ break
+ }
+ inst.Args[i] = argfield.Parse(ui)
+ }
+ inst.Op = iform.Op
+ if debugDecode {
+ log.Printf("%#x: search entry %d", ui, i)
+ continue
+ }
+ break
+ }
+ if inst.Op == 0 {
+ return inst, errUnknown
+ }
+ return inst, nil
+}
diff --git a/src/cmd/vendor/golang.org/x/arch/ppc64/ppc64asm/decode_test.go b/src/cmd/vendor/golang.org/x/arch/ppc64/ppc64asm/decode_test.go
new file mode 100644
index 0000000..71f64d6
--- /dev/null
+++ b/src/cmd/vendor/golang.org/x/arch/ppc64/ppc64asm/decode_test.go
@@ -0,0 +1,64 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ppc64asm
+
+import (
+ "encoding/binary"
+ "encoding/hex"
+ "io/ioutil"
+ "strings"
+ "testing"
+)
+
+func TestDecode(t *testing.T) {
+ data, err := ioutil.ReadFile("testdata/decode.txt")
+ if err != nil {
+ t.Fatal(err)
+ }
+ all := string(data)
+ for strings.Contains(all, "\t\t") {
+ all = strings.Replace(all, "\t\t", "\t", -1)
+ }
+ for _, line := range strings.Split(all, "\n") {
+ line = strings.TrimSpace(line)
+ if line == "" || strings.HasPrefix(line, "#") {
+ continue
+ }
+ f := strings.SplitN(line, "\t", 3)
+ i := strings.Index(f[0], "|")
+ if i < 0 {
+ t.Errorf("parsing %q: missing | separator", f[0])
+ continue
+ }
+ if i%2 != 0 {
+ t.Errorf("parsing %q: misaligned | separator", f[0])
+ }
+ size := i / 2
+ code, err := hex.DecodeString(f[0][:i] + f[0][i+1:])
+ if err != nil {
+ t.Errorf("parsing %q: %v", f[0], err)
+ continue
+ }
+ syntax, asm := f[1], f[2]
+ inst, err := Decode(code, binary.BigEndian)
+ var out string
+ if err != nil {
+ out = "error: " + err.Error()
+ } else {
+ switch syntax {
+ case "gnu":
+ out = GNUSyntax(inst)
+ //case "plan9":
+ // out = GoSyntax(inst, 0, nil, nil)
+ default:
+ t.Errorf("unknown syntax %q", syntax)
+ continue
+ }
+ }
+ if out != asm || inst.Len != size {
+ t.Errorf("Decode(%s) [%s] = %s want %s", f[0], syntax, out, asm)
+ }
+ }
+}
diff --git a/src/cmd/vendor/golang.org/x/arch/ppc64/ppc64asm/doc.go b/src/cmd/vendor/golang.org/x/arch/ppc64/ppc64asm/doc.go
new file mode 100644
index 0000000..5f4ef7d
--- /dev/null
+++ b/src/cmd/vendor/golang.org/x/arch/ppc64/ppc64asm/doc.go
@@ -0,0 +1,6 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package ppc64asm implements decoding of 64-bit PowerPC machine code.
+package ppc64asm
diff --git a/src/cmd/vendor/golang.org/x/arch/ppc64/ppc64asm/ext_test.go b/src/cmd/vendor/golang.org/x/arch/ppc64/ppc64asm/ext_test.go
new file mode 100644
index 0000000..b553984
--- /dev/null
+++ b/src/cmd/vendor/golang.org/x/arch/ppc64/ppc64asm/ext_test.go
@@ -0,0 +1,535 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Support for testing against external disassembler program.
+// Copied and simplified from rsc.io/arm/armasm/ext_test.go.
+
+package ppc64asm
+
+import (
+ "bufio"
+ "bytes"
+ "encoding/binary"
+ "encoding/hex"
+ "flag"
+ "fmt"
+ "io/ioutil"
+ "log"
+ "math/rand"
+ "os"
+ "os/exec"
+ "regexp"
+ "runtime"
+ "strings"
+ "testing"
+ "time"
+)
+
+var (
+ printTests = flag.Bool("printtests", false, "print test cases that exercise new code paths")
+ dumpTest = flag.Bool("dump", false, "dump all encodings")
+ mismatch = flag.Bool("mismatch", false, "log allowed mismatches")
+ longTest = flag.Bool("long", false, "long test")
+ keep = flag.Bool("keep", false, "keep object files around")
+ debug = false
+)
+
+// A ExtInst represents a single decoded instruction parsed
+// from an external disassembler's output.
+type ExtInst struct {
+ addr uint32
+ enc [4]byte
+ nenc int
+ text string
+}
+
+func (r ExtInst) String() string {
+ return fmt.Sprintf("%#x: % x: %s", r.addr, r.enc, r.text)
+}
+
+// An ExtDis is a connection between an external disassembler and a test.
+type ExtDis struct {
+ Dec chan ExtInst
+ File *os.File
+ Size int
+ KeepFile bool
+ Cmd *exec.Cmd
+}
+
+// Run runs the given command - the external disassembler - and returns
+// a buffered reader of its standard output.
+func (ext *ExtDis) Run(cmd ...string) (*bufio.Reader, error) {
+ if *keep {
+ log.Printf("%s\n", strings.Join(cmd, " "))
+ }
+ ext.Cmd = exec.Command(cmd[0], cmd[1:]...)
+ out, err := ext.Cmd.StdoutPipe()
+ if err != nil {
+ return nil, fmt.Errorf("stdoutpipe: %v", err)
+ }
+ if err := ext.Cmd.Start(); err != nil {
+ return nil, fmt.Errorf("exec: %v", err)
+ }
+
+ b := bufio.NewReaderSize(out, 1<<20)
+ return b, nil
+}
+
+// Wait waits for the command started with Run to exit.
+func (ext *ExtDis) Wait() error {
+ return ext.Cmd.Wait()
+}
+
+// testExtDis tests a set of byte sequences against an external disassembler.
+// The disassembler is expected to produce the given syntax and be run
+// in the given architecture mode (16, 32, or 64-bit).
+// The extdis function must start the external disassembler
+// and then parse its output, sending the parsed instructions on ext.Dec.
+// The generate function calls its argument f once for each byte sequence
+// to be tested. The generate function itself will be called twice, and it must
+// make the same sequence of calls to f each time.
+// When a disassembly does not match the internal decoding,
+// allowedMismatch determines whether this mismatch should be
+// allowed, or else considered an error.
+func testExtDis(
+ t *testing.T,
+ syntax string,
+ extdis func(ext *ExtDis) error,
+ generate func(f func([]byte)),
+ allowedMismatch func(text string, size int, inst *Inst, dec ExtInst) bool,
+) {
+ start := time.Now()
+ ext := &ExtDis{
+ Dec: make(chan ExtInst),
+ }
+ errc := make(chan error)
+
+ // First pass: write instructions to input file for external disassembler.
+ file, f, size, err := writeInst(generate)
+ if err != nil {
+ t.Fatal(err)
+ }
+ ext.Size = size
+ ext.File = f
+ defer func() {
+ f.Close()
+ if !*keep {
+ os.Remove(file)
+ }
+ }()
+
+ // Second pass: compare disassembly against our decodings.
+ var (
+ totalTests = 0
+ totalSkips = 0
+ totalErrors = 0
+
+ errors = make([]string, 0, 100) // sampled errors, at most cap
+ )
+ go func() {
+ errc <- extdis(ext)
+ }()
+ generate(func(enc []byte) {
+ dec, ok := <-ext.Dec
+ if !ok {
+ t.Errorf("decoding stream ended early")
+ return
+ }
+ inst, text := disasm(syntax, pad(enc))
+ totalTests++
+ if *dumpTest {
+ fmt.Printf("%x -> %s [%d]\n", enc[:len(enc)], dec.text, dec.nenc)
+ }
+ if text != dec.text || inst.Len != dec.nenc {
+ suffix := ""
+ if allowedMismatch(text, size, &inst, dec) {
+ totalSkips++
+ if !*mismatch {
+ return
+ }
+ suffix += " (allowed mismatch)"
+ }
+ totalErrors++
+ if len(errors) >= cap(errors) {
+ j := rand.Intn(totalErrors)
+ if j >= cap(errors) {
+ return
+ }
+ errors = append(errors[:j], errors[j+1:]...)
+ }
+ errors = append(errors, fmt.Sprintf("decode(%x) = %q, %d, want %q, %d%s", enc, text, inst.Len, dec.text, dec.nenc, suffix))
+ }
+ })
+
+ if *mismatch {
+ totalErrors -= totalSkips
+ }
+
+ for _, b := range errors {
+ t.Log(b)
+ }
+
+ if totalErrors > 0 {
+ t.Fail()
+ }
+ t.Logf("%d test cases, %d expected mismatches, %d failures; %.0f cases/second", totalTests, totalSkips, totalErrors, float64(totalTests)/time.Since(start).Seconds())
+
+ if err := <-errc; err != nil {
+ t.Fatalf("external disassembler: %v", err)
+ }
+
+}
+
+const start = 0x8000 // start address of text
+
+// writeInst writes the generated byte sequences to a new file
+// starting at offset start. That file is intended to be the input to
+// the external disassembler.
+func writeInst(generate func(func([]byte))) (file string, f *os.File, size int, err error) {
+ f, err = ioutil.TempFile("", "ppc64asm")
+ if err != nil {
+ return
+ }
+
+ file = f.Name()
+
+ f.Seek(start, 0)
+ w := bufio.NewWriter(f)
+ defer w.Flush()
+ size = 0
+ generate(func(x []byte) {
+ if len(x) > 4 {
+ x = x[:4]
+ }
+ if debug {
+ fmt.Printf("%#x: %x%x\n", start+size, x, zeros[len(x):])
+ }
+ w.Write(x)
+ w.Write(zeros[len(x):])
+ size += len(zeros)
+ })
+ return file, f, size, nil
+}
+
+var zeros = []byte{0, 0, 0, 0}
+
+// pad pads the code sequence with pops.
+func pad(enc []byte) []byte {
+ if len(enc) < 4 {
+ enc = append(enc[:len(enc):len(enc)], zeros[:4-len(enc)]...)
+ }
+ return enc
+}
+
+// disasm returns the decoded instruction and text
+// for the given source bytes, using the given syntax and mode.
+func disasm(syntax string, src []byte) (inst Inst, text string) {
+ // If printTests is set, we record the coverage value
+ // before and after, and we write out the inputs for which
+ // coverage went up, in the format expected in testdata/decode.text.
+ // This produces a fairly small set of test cases that exercise nearly
+ // all the code.
+ var cover float64
+ if *printTests {
+ cover -= coverage()
+ }
+
+ inst, err := Decode(src, binary.BigEndian)
+ if err != nil {
+ text = "error: " + err.Error()
+ } else {
+ text = inst.String()
+ switch syntax {
+ //case "arm":
+ // text = ARMSyntax(inst)
+ case "gnu":
+ text = GNUSyntax(inst)
+ //case "plan9":
+ // text = GoSyntax(inst, 0, nil)
+ default:
+ text = "error: unknown syntax " + syntax
+ }
+ }
+
+ if *printTests {
+ cover += coverage()
+ if cover > 0 {
+ max := len(src)
+ if max > 4 && inst.Len <= 4 {
+ max = 4
+ }
+ fmt.Printf("%x|%x\t%s\t%s\n", src[:inst.Len], src[inst.Len:max], syntax, text)
+ }
+ }
+
+ return
+}
+
+// coverage returns a floating point number denoting the
+// test coverage until now. The number increases when new code paths are exercised,
+// both in the Go program and in the decoder byte code.
+func coverage() float64 {
+ var f float64
+ f += testing.Coverage()
+ f += decodeCoverage()
+ return f
+}
+
+func decodeCoverage() float64 {
+ n := 0
+ for _, t := range decoderCover {
+ if t {
+ n++
+ }
+ }
+ return float64(1+n) / float64(1+len(decoderCover))
+}
+
+// Helpers for writing disassembler output parsers.
+
+// hasPrefix reports whether any of the space-separated words in the text s
+// begins with any of the given prefixes.
+func hasPrefix(s string, prefixes ...string) bool {
+ for _, prefix := range prefixes {
+ for s := s; s != ""; {
+ if strings.HasPrefix(s, prefix) {
+ return true
+ }
+ i := strings.Index(s, " ")
+ if i < 0 {
+ break
+ }
+ s = s[i+1:]
+ }
+ }
+ return false
+}
+
+// contains reports whether the text s contains any of the given substrings.
+func contains(s string, substrings ...string) bool {
+ for _, sub := range substrings {
+ if strings.Contains(s, sub) {
+ return true
+ }
+ }
+ return false
+}
+
+// isHex reports whether b is a hexadecimal character (0-9A-Fa-f).
+func isHex(b byte) bool { return b == '0' || unhex[b] > 0 }
+
+// parseHex parses the hexadecimal byte dump in hex,
+// appending the parsed bytes to raw and returning the updated slice.
+// The returned bool signals whether any invalid hex was found.
+// Spaces and tabs between bytes are okay but any other non-hex is not.
+func parseHex(hex []byte, raw []byte) ([]byte, bool) {
+ hex = trimSpace(hex)
+ for j := 0; j < len(hex); {
+ for hex[j] == ' ' || hex[j] == '\t' {
+ j++
+ }
+ if j >= len(hex) {
+ break
+ }
+ if j+2 > len(hex) || !isHex(hex[j]) || !isHex(hex[j+1]) {
+ return nil, false
+ }
+ raw = append(raw, unhex[hex[j]]<<4|unhex[hex[j+1]])
+ j += 2
+ }
+ return raw, true
+}
+
+var unhex = [256]byte{
+ '0': 0,
+ '1': 1,
+ '2': 2,
+ '3': 3,
+ '4': 4,
+ '5': 5,
+ '6': 6,
+ '7': 7,
+ '8': 8,
+ '9': 9,
+ 'A': 10,
+ 'B': 11,
+ 'C': 12,
+ 'D': 13,
+ 'E': 14,
+ 'F': 15,
+ 'a': 10,
+ 'b': 11,
+ 'c': 12,
+ 'd': 13,
+ 'e': 14,
+ 'f': 15,
+}
+
+// index is like bytes.Index(s, []byte(t)) but avoids the allocation.
+func index(s []byte, t string) int {
+ i := 0
+ for {
+ j := bytes.IndexByte(s[i:], t[0])
+ if j < 0 {
+ return -1
+ }
+ i = i + j
+ if i+len(t) > len(s) {
+ return -1
+ }
+ for k := 1; k < len(t); k++ {
+ if s[i+k] != t[k] {
+ goto nomatch
+ }
+ }
+ return i
+ nomatch:
+ i++
+ }
+}
+
+// fixSpace rewrites runs of spaces, tabs, and newline characters into single spaces in s.
+// If s must be rewritten, it is rewritten in place.
+func fixSpace(s []byte) []byte {
+ s = trimSpace(s)
+ for i := 0; i < len(s); i++ {
+ if s[i] == '\t' || s[i] == '\n' || i > 0 && s[i] == ' ' && s[i-1] == ' ' {
+ goto Fix
+ }
+ }
+ return s
+
+Fix:
+ b := s
+ w := 0
+ for i := 0; i < len(s); i++ {
+ c := s[i]
+ if c == '\t' || c == '\n' {
+ c = ' '
+ }
+ if c == ' ' && w > 0 && b[w-1] == ' ' {
+ continue
+ }
+ b[w] = c
+ w++
+ }
+ if w > 0 && b[w-1] == ' ' {
+ w--
+ }
+ return b[:w]
+}
+
+// trimSpace trims leading and trailing space from s, returning a subslice of s.
+func trimSpace(s []byte) []byte {
+ j := len(s)
+ for j > 0 && (s[j-1] == ' ' || s[j-1] == '\t' || s[j-1] == '\n') {
+ j--
+ }
+ i := 0
+ for i < j && (s[i] == ' ' || s[i] == '\t') {
+ i++
+ }
+ return s[i:j]
+}
+
+// pcrel matches instructions using relative addressing mode.
+var (
+ pcrel = regexp.MustCompile(`^((?:.* )?(?:b|bc)[^ac ]* (?:(?:[0-9]{1,2},)|(?:[0-7]\*)|\+|lt|gt|eq|so|cr[0-7]|,)*)0x([0-9a-f]+)$`)
+)
+
+// Generators.
+//
+// The test cases are described as functions that invoke a callback repeatedly,
+// with a new input sequence each time. These helpers make writing those
+// a little easier.
+
+// randomCases generates random instructions.
+func randomCases(t *testing.T) func(func([]byte)) {
+ return func(try func([]byte)) {
+ // All the strides are relatively prime to 2 and therefore to 2²⁸,
+ // so we will not repeat any instructions until we have tried all 2²⁸.
+ // Using a stride other than 1 is meant to visit the instructions in a
+ // pseudorandom order, which gives better variety in the set of
+ // test cases chosen by -printtests.
+ stride := uint32(10007)
+ n := 1 << 28 / 7
+ if testing.Short() {
+ stride = 100003
+ n = 1 << 28 / 1001
+ } else if *longTest {
+ stride = 2000033
+ n = 1 << 29
+ }
+ x := uint32(0)
+ for i := 0; i < n; i++ {
+ enc := (x%15)<<28 | x&(1<<28-1)
+ try([]byte{byte(enc), byte(enc >> 8), byte(enc >> 16), byte(enc >> 24)})
+ x += stride
+ }
+ }
+}
+
+// hexCases generates the cases written in hexadecimal in the encoded string.
+// Spaces in 'encoded' separate entire test cases, not individual bytes.
+func hexCases(t *testing.T, encoded string) func(func([]byte)) {
+ return func(try func([]byte)) {
+ for _, x := range strings.Fields(encoded) {
+ src, err := hex.DecodeString(x)
+ if err != nil {
+ t.Errorf("parsing %q: %v", x, err)
+ }
+ try(src)
+ }
+ }
+}
+
+// testdataCases generates the test cases recorded in testdata/decode.txt.
+// It only uses the inputs; it ignores the answers recorded in that file.
+func testdataCases(t *testing.T) func(func([]byte)) {
+ var codes [][]byte
+ data, err := ioutil.ReadFile("testdata/decode.txt")
+ if err != nil {
+ t.Fatal(err)
+ }
+ for _, line := range strings.Split(string(data), "\n") {
+ line = strings.TrimSpace(line)
+ if line == "" || strings.HasPrefix(line, "#") {
+ continue
+ }
+ f := strings.Fields(line)[0]
+ i := strings.Index(f, "|")
+ if i < 0 {
+ t.Errorf("parsing %q: missing | separator", f)
+ continue
+ }
+ if i%2 != 0 {
+ t.Errorf("parsing %q: misaligned | separator", f)
+ }
+ code, err := hex.DecodeString(f[:i] + f[i+1:])
+ if err != nil {
+ t.Errorf("parsing %q: %v", f, err)
+ continue
+ }
+ codes = append(codes, code)
+ }
+
+ return func(try func([]byte)) {
+ for _, code := range codes {
+ try(code)
+ }
+ }
+}
+
+func caller(skip int) string {
+ pc, _, _, _ := runtime.Caller(skip)
+ f := runtime.FuncForPC(pc)
+ name := "?"
+ if f != nil {
+ name = f.Name()
+ if i := strings.LastIndex(name, "."); i >= 0 {
+ name = name[i+1:]
+ }
+ }
+ return name
+}
diff --git a/src/cmd/vendor/golang.org/x/arch/ppc64/ppc64asm/field.go b/src/cmd/vendor/golang.org/x/arch/ppc64/ppc64asm/field.go
new file mode 100644
index 0000000..26a4fdf
--- /dev/null
+++ b/src/cmd/vendor/golang.org/x/arch/ppc64/ppc64asm/field.go
@@ -0,0 +1,84 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ppc64asm
+
+import (
+ "fmt"
+ "strings"
+)
+
+// A BitField is a bit-field in a 32-bit word.
+// Bits are counted from 0 from the MSB to 31 as the LSB.
+type BitField struct {
+ Offs uint8 // the offset of the left-most bit.
+ Bits uint8 // length in bits.
+}
+
+func (b BitField) String() string {
+ if b.Bits > 1 {
+ return fmt.Sprintf("[%d:%d]", b.Offs, int(b.Offs+b.Bits)-1)
+ } else if b.Bits == 1 {
+ return fmt.Sprintf("[%d]", b.Offs)
+ } else {
+ return fmt.Sprintf("[%d, len=0]", b.Offs)
+ }
+}
+
+// Parse extracts the bitfield b from i, and return it as an unsigned integer.
+// Parse will panic if b is invalid.
+func (b BitField) Parse(i uint32) uint32 {
+ if b.Bits > 32 || b.Bits == 0 || b.Offs > 31 || b.Offs+b.Bits > 32 {
+ panic(fmt.Sprintf("invalid bitfiled %v", b))
+ }
+ return (i >> (32 - b.Offs - b.Bits)) & ((1 << b.Bits) - 1)
+}
+
+// ParseSigned extracts the bitfield b from i, and return it as a signed integer.
+// ParseSigned will panic if b is invalid.
+func (b BitField) ParseSigned(i uint32) int32 {
+ u := int32(b.Parse(i))
+ return u << (32 - b.Bits) >> (32 - b.Bits)
+}
+
+// BitFields is a series of BitFields representing a single number.
+type BitFields []BitField
+
+func (bs BitFields) String() string {
+ ss := make([]string, len(bs))
+ for i, bf := range bs {
+ ss[i] = bf.String()
+ }
+ return fmt.Sprintf("<%s>", strings.Join(ss, "|"))
+}
+
+func (bs *BitFields) Append(b BitField) {
+ *bs = append(*bs, b)
+}
+
+// parse extracts the bitfields from i, concatenate them and return the result
+// as an unsigned integer and the total length of all the bitfields.
+// parse will panic if any bitfield in b is invalid, but it doesn't check if
+// the sequence of bitfields is reasonable.
+func (bs BitFields) parse(i uint32) (u uint32, Bits uint8) {
+ for _, b := range bs {
+ u = (u << b.Bits) | b.Parse(i)
+ Bits += b.Bits
+ }
+ return u, Bits
+}
+
+// Parse extracts the bitfields from i, concatenate them and return the result
+// as an unsigned integer. Parse will panic if any bitfield in b is invalid.
+func (bs BitFields) Parse(i uint32) uint32 {
+ u, _ := bs.parse(i)
+ return u
+}
+
+// Parse extracts the bitfields from i, concatenate them and return the result
+// as a signed integer. Parse will panic if any bitfield in b is invalid.
+func (bs BitFields) ParseSigned(i uint32) int32 {
+ u, l := bs.parse(i)
+ return int32(u) << (32 - l) >> (32 - l)
+}
diff --git a/src/cmd/vendor/golang.org/x/arch/ppc64/ppc64asm/field_test.go b/src/cmd/vendor/golang.org/x/arch/ppc64/ppc64asm/field_test.go
new file mode 100644
index 0000000..14eb2f8
--- /dev/null
+++ b/src/cmd/vendor/golang.org/x/arch/ppc64/ppc64asm/field_test.go
@@ -0,0 +1,60 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ppc64asm
+
+import (
+ "testing"
+)
+
+func panicOrNot(f func()) (panicked bool) {
+ defer func() {
+ if err := recover(); err != nil {
+ panicked = true
+ }
+ }()
+ f()
+ return false
+}
+
+func TestBitField(t *testing.T) {
+ var tests = []struct {
+ b BitField
+ i uint32 // input
+ u uint32 // unsigned output
+ s int32 // signed output
+ fail bool // if the check should panic
+ }{
+ {BitField{0, 0}, 0, 0, 0, true},
+ {BitField{31, 2}, 0, 0, 0, true},
+ {BitField{31, 1}, 1, 1, -1, false},
+ {BitField{29, 2}, 0 << 1, 0, 0, false},
+ {BitField{29, 2}, 1 << 1, 1, 1, false},
+ {BitField{29, 2}, 2 << 1, 2, -2, false},
+ {BitField{29, 2}, 3 << 1, 3, -1, false},
+ {BitField{0, 32}, 1<<32 - 1, 1<<32 - 1, -1, false},
+ {BitField{16, 3}, 1 << 15, 4, -4, false},
+ }
+ for i, tst := range tests {
+ var (
+ ou uint32
+ os int32
+ )
+ failed := panicOrNot(func() {
+ ou = tst.b.Parse(tst.i)
+ os = tst.b.ParseSigned(tst.i)
+ })
+ if failed != tst.fail {
+ t.Errorf("case %d: %v: fail test failed, got %v, expected %v", i, tst.b, failed, tst.fail)
+ continue
+ }
+ if ou != tst.u {
+ t.Errorf("case %d: %v.Parse(%d) returned %d, expected %d", i, tst.b, tst.i, ou, tst.u)
+ continue
+ }
+ if os != tst.s {
+ t.Errorf("case %d: %v.ParseSigned(%d) returned %d, expected %d", i, tst.b, tst.i, os, tst.s)
+ }
+ }
+}
diff --git a/src/cmd/vendor/golang.org/x/arch/ppc64/ppc64asm/gnu.go b/src/cmd/vendor/golang.org/x/arch/ppc64/ppc64asm/gnu.go
new file mode 100644
index 0000000..63be379
--- /dev/null
+++ b/src/cmd/vendor/golang.org/x/arch/ppc64/ppc64asm/gnu.go
@@ -0,0 +1,125 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ppc64asm
+
+import (
+ "bytes"
+ "fmt"
+ "strings"
+)
+
+// GNUSyntax returns the GNU assembler syntax for the instruction, as defined by GNU binutils.
+// This form typically matches the syntax defined in the Power ISA Reference Manual.
+func GNUSyntax(inst Inst) string {
+ var buf bytes.Buffer
+ if inst.Op == 0 {
+ return "error: unkown instruction"
+ }
+ buf.WriteString(inst.Op.String())
+ sep := " "
+ for i, arg := range inst.Args[:] {
+ if arg == nil {
+ break
+ }
+ text := gnuArg(&inst, i, arg)
+ if text == "" {
+ continue
+ }
+ buf.WriteString(sep)
+ sep = ","
+ buf.WriteString(text)
+ }
+ return buf.String()
+}
+
+// gnuArg formats arg (which is the argIndex's arg in inst) according to GNU rules.
+// NOTE: because GNUSyntax is the only caller of this func, and it receives a copy
+// of inst, it's ok to modify inst.Args here.
+func gnuArg(inst *Inst, argIndex int, arg Arg) string {
+ // special cases for load/store instructions
+ if _, ok := arg.(Offset); ok {
+ if argIndex+1 == len(inst.Args) || inst.Args[argIndex+1] == nil {
+ panic(fmt.Errorf("wrong table: offset not followed by register"))
+ }
+ }
+ switch arg := arg.(type) {
+ case Reg:
+ if isLoadStoreOp(inst.Op) && argIndex == 1 && arg == R0 {
+ return "0"
+ }
+ return arg.String()
+ case CondReg:
+ if arg == CR0 && strings.HasPrefix(inst.Op.String(), "cmp") {
+ return "" // don't show cr0 for cmp instructions
+ } else if arg >= CR0 {
+ return fmt.Sprintf("cr%d", int(arg-CR0))
+ }
+ bit := [4]string{"lt", "gt", "eq", "so"}[(arg-Cond0LT)%4]
+ if arg <= Cond0SO {
+ return bit
+ }
+ return fmt.Sprintf("4*cr%d+%s", int(arg-Cond0LT)/4, bit)
+ case Imm:
+ return fmt.Sprintf("%d", arg)
+ case SpReg:
+ return fmt.Sprintf("%d", int(arg))
+ case PCRel:
+ return fmt.Sprintf(".%+#x", int(arg))
+ case Label:
+ return fmt.Sprintf("%#x", uint32(arg))
+ case Offset:
+ reg := inst.Args[argIndex+1].(Reg)
+ removeArg(inst, argIndex+1)
+ if reg == R0 {
+ return fmt.Sprintf("%d(0)", int(arg))
+ }
+ return fmt.Sprintf("%d(r%d)", int(arg), reg-R0)
+ }
+ return fmt.Sprintf("???(%v)", arg)
+}
+
+// removeArg removes the arg in inst.Args[index].
+func removeArg(inst *Inst, index int) {
+ for i := index; i < len(inst.Args); i++ {
+ if i+1 < len(inst.Args) {
+ inst.Args[i] = inst.Args[i+1]
+ } else {
+ inst.Args[i] = nil
+ }
+ }
+}
+
+// isLoadStoreOp returns true if op is a load or store instruction
+func isLoadStoreOp(op Op) bool {
+ switch op {
+ case LBZ, LBZU, LBZX, LBZUX:
+ return true
+ case LHZ, LHZU, LHZX, LHZUX:
+ return true
+ case LHA, LHAU, LHAX, LHAUX:
+ return true
+ case LWZ, LWZU, LWZX, LWZUX:
+ return true
+ case LWA, LWAX, LWAUX:
+ return true
+ case LD, LDU, LDX, LDUX:
+ return true
+ case LQ:
+ return true
+ case STB, STBU, STBX, STBUX:
+ return true
+ case STH, STHU, STHX, STHUX:
+ return true
+ case STW, STWU, STWX, STWUX:
+ return true
+ case STD, STDU, STDX, STDUX:
+ return true
+ case STQ:
+ return true
+ case LHBRX, LWBRX, STHBRX, STWBRX:
+ return true
+ }
+ return false
+}
diff --git a/src/cmd/vendor/golang.org/x/arch/ppc64/ppc64asm/inst.go b/src/cmd/vendor/golang.org/x/arch/ppc64/ppc64asm/inst.go
new file mode 100644
index 0000000..bd86b92
--- /dev/null
+++ b/src/cmd/vendor/golang.org/x/arch/ppc64/ppc64asm/inst.go
@@ -0,0 +1,344 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ppc64asm
+
+import (
+ "bytes"
+ "fmt"
+)
+
+type Inst struct {
+ Op Op // Opcode mnemonic
+ Enc uint32 // Raw encoding bits
+ Len int // Length of encoding in bytes.
+ Args Args // Instruction arguments, in Power ISA manual order.
+}
+
+func (i Inst) String() string {
+ var buf bytes.Buffer
+ buf.WriteString(i.Op.String())
+ for j, arg := range i.Args {
+ if arg == nil {
+ break
+ }
+ if j == 0 {
+ buf.WriteString(" ")
+ } else {
+ buf.WriteString(", ")
+ }
+ buf.WriteString(arg.String())
+ }
+ return buf.String()
+}
+
+// An Op is an instruction operation.
+type Op uint16
+
+func (o Op) String() string {
+ if int(o) >= len(opstr) || opstr[o] == "" {
+ return fmt.Sprintf("Op(%d)", int(o))
+ }
+ return opstr[o]
+}
+
+// An Arg is a single instruction argument, one of these types: Reg, CondReg, SpReg, Imm, PCRel, Label, or Offset.
+type Arg interface {
+ IsArg()
+ String() string
+}
+
+// An Args holds the instruction arguments.
+// If an instruction has fewer than 4 arguments,
+// the final elements in the array are nil.
+type Args [5]Arg
+
+// A Reg is a single register. The zero value means R0, not the absence of a register.
+// It also includes special registers.
+type Reg uint16
+
+const (
+ _ Reg = iota
+ R0
+ R1
+ R2
+ R3
+ R4
+ R5
+ R6
+ R7
+ R8
+ R9
+ R10
+ R11
+ R12
+ R13
+ R14
+ R15
+ R16
+ R17
+ R18
+ R19
+ R20
+ R21
+ R22
+ R23
+ R24
+ R25
+ R26
+ R27
+ R28
+ R29
+ R30
+ R31
+ F0
+ F1
+ F2
+ F3
+ F4
+ F5
+ F6
+ F7
+ F8
+ F9
+ F10
+ F11
+ F12
+ F13
+ F14
+ F15
+ F16
+ F17
+ F18
+ F19
+ F20
+ F21
+ F22
+ F23
+ F24
+ F25
+ F26
+ F27
+ F28
+ F29
+ F30
+ F31
+ V0 // VSX extension, F0 is V0[0:63].
+ V1
+ V2
+ V3
+ V4
+ V5
+ V6
+ V7
+ V8
+ V9
+ V10
+ V11
+ V12
+ V13
+ V14
+ V15
+ V16
+ V17
+ V18
+ V19
+ V20
+ V21
+ V22
+ V23
+ V24
+ V25
+ V26
+ V27
+ V28
+ V29
+ V30
+ V31
+ VS0
+ VS1
+ VS2
+ VS3
+ VS4
+ VS5
+ VS6
+ VS7
+ VS8
+ VS9
+ VS10
+ VS11
+ VS12
+ VS13
+ VS14
+ VS15
+ VS16
+ VS17
+ VS18
+ VS19
+ VS20
+ VS21
+ VS22
+ VS23
+ VS24
+ VS25
+ VS26
+ VS27
+ VS28
+ VS29
+ VS30
+ VS31
+ VS32
+ VS33
+ VS34
+ VS35
+ VS36
+ VS37
+ VS38
+ VS39
+ VS40
+ VS41
+ VS42
+ VS43
+ VS44
+ VS45
+ VS46
+ VS47
+ VS48
+ VS49
+ VS50
+ VS51
+ VS52
+ VS53
+ VS54
+ VS55
+ VS56
+ VS57
+ VS58
+ VS59
+ VS60
+ VS61
+ VS62
+ VS63
+)
+
+func (Reg) IsArg() {}
+func (r Reg) String() string {
+ switch {
+ case R0 <= r && r <= R31:
+ return fmt.Sprintf("r%d", int(r-R0))
+ case F0 <= r && r <= F31:
+ return fmt.Sprintf("f%d", int(r-F0))
+ case V0 <= r && r <= V31:
+ return fmt.Sprintf("v%d", int(r-V0))
+ case VS0 <= r && r <= VS63:
+ return fmt.Sprintf("vs%d", int(r-VS0))
+ default:
+ return fmt.Sprintf("Reg(%d)", int(r))
+ }
+}
+
+// CondReg is a bit or field in the conditon register.
+type CondReg int8
+
+const (
+ _ CondReg = iota
+ // Condition Regster bits
+ Cond0LT
+ Cond0GT
+ Cond0EQ
+ Cond0SO
+ Cond1LT
+ Cond1GT
+ Cond1EQ
+ Cond1SO
+ Cond2LT
+ Cond2GT
+ Cond2EQ
+ Cond2SO
+ Cond3LT
+ Cond3GT
+ Cond3EQ
+ Cond3SO
+ Cond4LT
+ Cond4GT
+ Cond4EQ
+ Cond4SO
+ Cond5LT
+ Cond5GT
+ Cond5EQ
+ Cond5SO
+ Cond6LT
+ Cond6GT
+ Cond6EQ
+ Cond6SO
+ Cond7LT
+ Cond7GT
+ Cond7EQ
+ Cond7SO
+ // Condition Register Fields
+ CR0
+ CR1
+ CR2
+ CR3
+ CR4
+ CR5
+ CR6
+ CR7
+)
+
+func (CondReg) IsArg() {}
+func (c CondReg) String() string {
+ switch {
+ default:
+ return fmt.Sprintf("CondReg(%d)", int(c))
+ case c >= CR0:
+ return fmt.Sprintf("CR%d", int(c-CR0))
+ case c >= Cond0LT && c < CR0:
+ return fmt.Sprintf("Cond%d%s", int((c-Cond0LT)/4), [4]string{"LT", "GT", "EQ", "SO"}[(c-Cond0LT)%4])
+ }
+}
+
+// SpReg is a special register, its meaning depends on Op.
+type SpReg uint16
+
+const (
+ SpRegZero SpReg = 0
+)
+
+func (SpReg) IsArg() {}
+func (s SpReg) String() string {
+ return fmt.Sprintf("SpReg(%d)", int(s))
+}
+
+// PCRel is a PC-relative offset, used only in branch instructions.
+type PCRel int32
+
+func (PCRel) IsArg() {}
+func (r PCRel) String() string {
+ return fmt.Sprintf("PC%+#x", int32(r))
+}
+
+// A Label is a code (text) address, used only in absolute branch instructions.
+type Label uint32
+
+func (Label) IsArg() {}
+func (l Label) String() string {
+ return fmt.Sprintf("%#x", uint32(l))
+}
+
+// Imm represents an immediate number.
+type Imm int32
+
+func (Imm) IsArg() {}
+func (i Imm) String() string {
+ return fmt.Sprintf("%d", int32(i))
+}
+
+// Offset represents a memory offset immediate.
+type Offset int32
+
+func (Offset) IsArg() {}
+func (o Offset) String() string {
+ return fmt.Sprintf("%+d", int32(o))
+}
diff --git a/src/cmd/vendor/golang.org/x/arch/ppc64/ppc64asm/objdump_test.go b/src/cmd/vendor/golang.org/x/arch/ppc64/ppc64asm/objdump_test.go
new file mode 100644
index 0000000..ae825fd
--- /dev/null
+++ b/src/cmd/vendor/golang.org/x/arch/ppc64/ppc64asm/objdump_test.go
@@ -0,0 +1,133 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ppc64asm
+
+import (
+ "encoding/binary"
+ "strings"
+ "testing"
+)
+
+func TestObjdumpPowerTestdata(t *testing.T) { testObjdump(t, testdataCases(t)) }
+func TestObjdumpPowerManual(t *testing.T) { testObjdump(t, hexCases(t, objdumpManualTests)) }
+
+// Disable this for now since generating all possible bit combinations within a word
+// generates lots of ppc64x instructions not possible with golang so not worth supporting..
+//func TestObjdumpPowerRandom(t *testing.T) { testObjdump(t, randomCases(t)) }
+
+// objdumpManualTests holds test cases that will be run by TestObjdumpARMManual.
+// If you are debugging a few cases that turned up in a longer run, it can be useful
+// to list them here and then use -run=Manual, particularly with tracing enabled.
+// Note that these are byte sequences, so they must be reversed from the usual
+// word presentation.
+var objdumpManualTests = `
+6d746162
+4c040000
+88000017
+`
+
+// allowedMismatchObjdump reports whether the mismatch between text and dec
+// should be allowed by the test.
+func allowedMismatchObjdump(text string, size int, inst *Inst, dec ExtInst) bool {
+ if hasPrefix(dec.text, deleted...) {
+ return true
+ }
+
+ // we support more instructions than binutils
+ if strings.Contains(dec.text, ".long") {
+ return true
+ }
+
+ if hasPrefix(text, "error:") {
+ if hasPrefix(dec.text, unsupported...) {
+ return true
+ }
+ }
+
+ switch inst.Op {
+ case BC, BCA, BL, BLA, BCL, BCLA, TDI, TWI, TW, TD:
+ return true // TODO(minux): we lack the support for extended opcodes here
+ case RLWNM, RLWNM_, RLDICL, RLDICL_, RLWINM, RLWINM_, RLDCL, RLDCL_:
+ return true // TODO(minux): we lack the support for extended opcodes here
+ case DCBTST, DCBT:
+ return true // objdump uses the embedded argument order, we use the server argument order
+ case MTFSF, MTFSF_: // objdump doesn't show the last two arguments
+ return true
+ case VSPLTB, VSPLTH, VSPLTW: // objdump generates unreasonable result "vspltw v6,v19,4" for 10c49a8c, the last 4 should be 0.
+ return true
+ }
+ if hasPrefix(text, "evm", "evl", "efs") { // objdump will disassemble them wrong (e.g. evmhoumia as vsldoi)
+ return true
+ }
+
+ if len(dec.enc) >= 4 {
+ _ = binary.BigEndian.Uint32(dec.enc[:4])
+ }
+
+ return false
+}
+
+// Instructions known to libopcodes (or xed) but not to us.
+// TODO(minux): those single precision instructions are missing from ppc64.csv
+// those data cache instructions are deprecated, but must be treated as no-ops, see 4.3.2.1 pg. 774.
+var unsupported = strings.Fields(`
+fmsubs
+fmsubs.
+fnmadds
+fnmadds.
+fnmsubs
+fnmsubs.
+fmuls
+fmuls.
+fdivs
+fdivs.
+fadds
+fadds.
+fsubs
+fsubs.
+dst
+dstst
+dssall
+`)
+
+// Instructions explicitly dropped in Power ISA that were in POWER architecture.
+// See A.30 Deleted Instructions and A.31 Discontiued Opcodes
+var deleted = strings.Fields(`
+abs
+clcs
+clf
+cli
+dclst
+div
+divs
+doz
+dozi
+lscbx
+maskg
+maskir
+mfsri
+mul
+nabs
+rac
+rfi
+rfsvc
+rlmi
+rrib
+sle
+sleq
+sliq
+slliq
+sllq
+slq
+sraiq
+sraq
+sre
+srea
+sreq
+sriq
+srliq
+srlq
+srq
+maskg`)
diff --git a/src/cmd/vendor/golang.org/x/arch/ppc64/ppc64asm/objdumpext_test.go b/src/cmd/vendor/golang.org/x/arch/ppc64/ppc64asm/objdumpext_test.go
new file mode 100644
index 0000000..7483543
--- /dev/null
+++ b/src/cmd/vendor/golang.org/x/arch/ppc64/ppc64asm/objdumpext_test.go
@@ -0,0 +1,255 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Copied and simplified from rsc.io/arm/armasm/objdumpext_test.go.
+
+package ppc64asm
+
+import (
+ "bytes"
+ "debug/elf"
+ "encoding/binary"
+ "fmt"
+ "io"
+ "log"
+ "os"
+ "runtime"
+ "strconv"
+ "strings"
+ "testing"
+)
+
+const objdumpPath = "/usr/bin/objdump"
+
+func testObjdump(t *testing.T, generate func(func([]byte))) {
+ if testing.Short() {
+ t.Skip("skipping objdump test in short mode")
+ }
+ if runtime.GOARCH != "ppc64le" && runtime.GOARCH != "ppc64" {
+ t.Skip("skipping; test requires host tool objdump for ppc64 or ppc64le")
+ }
+ if _, err := os.Stat(objdumpPath); err != nil {
+ t.Skip(err)
+ }
+
+ testExtDis(t, "gnu", objdump, generate, allowedMismatchObjdump)
+}
+
+func objdump(ext *ExtDis) error {
+ // File already written with instructions; add ELF header.
+ if err := writeELF64(ext.File, ext.Size); err != nil {
+ return err
+ }
+
+ b, err := ext.Run(objdumpPath, "-d", "-z", ext.File.Name())
+ if err != nil {
+ return err
+ }
+
+ var (
+ nmatch int
+ reading bool
+ next uint32 = start
+ addr uint32
+ encbuf [4]byte
+ enc []byte
+ text string
+ )
+ flush := func() {
+ if addr == next {
+ if m := pcrel.FindStringSubmatch(text); m != nil {
+ targ, _ := strconv.ParseUint(m[2], 16, 64)
+ text = fmt.Sprintf("%s.%+#x", m[1], int32(uint32(targ)-addr))
+ }
+ if strings.HasPrefix(text, "stmia") {
+ text = "stm" + text[5:]
+ }
+ if strings.HasPrefix(text, "stmfd") {
+ text = "stmdb" + text[5:]
+ }
+ if strings.HasPrefix(text, "ldmfd") {
+ text = "ldm" + text[5:]
+ }
+ text = strings.Replace(text, "#0.0", "#0", -1)
+ if text == "undefined" && len(enc) == 4 {
+ text = "error: unknown instruction"
+ enc = nil
+ }
+ if len(enc) == 4 {
+ // prints as word but we want to record bytes
+ enc[0], enc[3] = enc[3], enc[0]
+ enc[1], enc[2] = enc[2], enc[1]
+ }
+ ext.Dec <- ExtInst{addr, encbuf, len(enc), text}
+ encbuf = [4]byte{}
+ enc = nil
+ next += 4
+ }
+ }
+ var textangle = []byte("<.text>:")
+ for {
+ line, err := b.ReadSlice('\n')
+ if err != nil {
+ if err == io.EOF {
+ break
+ }
+ return fmt.Errorf("reading objdump output: %v", err)
+ }
+ if bytes.Contains(line, textangle) {
+ reading = true
+ continue
+ }
+ if !reading {
+ continue
+ }
+ if debug {
+ os.Stdout.Write(line)
+ }
+ if enc1 := parseContinuation(line, encbuf[:len(enc)]); enc1 != nil {
+ enc = enc1
+ continue
+ }
+ flush()
+ nmatch++
+ addr, enc, text = parseLine(line, encbuf[:0])
+ if addr > next {
+ return fmt.Errorf("address out of sync expected <= %#x at %q in:\n%s", next, line, line)
+ }
+ }
+ flush()
+ if next != start+uint32(ext.Size) {
+ return fmt.Errorf("not enough results found [%d %d]", next, start+ext.Size)
+ }
+ if err := ext.Wait(); err != nil {
+ return fmt.Errorf("exec: %v", err)
+ }
+
+ return nil
+}
+
+var (
+ undefined = []byte("<UNDEFINED>")
+ unpredictable = []byte("<UNPREDICTABLE>")
+ illegalShifter = []byte("<illegal shifter operand>")
+)
+
+func parseLine(line []byte, encstart []byte) (addr uint32, enc []byte, text string) {
+ oline := line
+ i := index(line, ":\t")
+ if i < 0 {
+ log.Fatalf("cannot parse disassembly: %q", oline)
+ }
+ x, err := strconv.ParseUint(string(trimSpace(line[:i])), 16, 32)
+ if err != nil {
+ log.Fatalf("cannot parse disassembly: %q", oline)
+ }
+ addr = uint32(x)
+ line = line[i+2:]
+ i = bytes.IndexByte(line, '\t')
+ if i < 0 {
+ log.Fatalf("cannot parse disassembly: %q", oline)
+ }
+ enc, ok := parseHex(line[:i], encstart)
+ if !ok {
+ log.Fatalf("cannot parse disassembly: %q", oline)
+ }
+ line = trimSpace(line[i:])
+ if bytes.Contains(line, undefined) {
+ text = "undefined"
+ return
+ }
+ if bytes.Contains(line, illegalShifter) {
+ text = "undefined"
+ return
+ }
+ if false && bytes.Contains(line, unpredictable) {
+ text = "unpredictable"
+ return
+ }
+ if i := bytes.IndexByte(line, ';'); i >= 0 {
+ line = trimSpace(line[:i])
+ }
+ text = string(fixSpace(line))
+ return
+}
+
+func parseContinuation(line []byte, enc []byte) []byte {
+ i := index(line, ":\t")
+ if i < 0 {
+ return nil
+ }
+ line = line[i+1:]
+ enc, _ = parseHex(line, enc)
+ return enc
+}
+
+// writeELF64 writes an ELF64 header to the file,
+// describing a text segment that starts at start
+// and extends for size bytes.
+func writeELF64(f *os.File, size int) error {
+ f.Seek(0, 0)
+ var hdr elf.Header64
+ var prog elf.Prog64
+ var sect elf.Section64
+ var buf bytes.Buffer
+ binary.Write(&buf, binary.BigEndian, &hdr)
+ off1 := buf.Len()
+ binary.Write(&buf, binary.BigEndian, &prog)
+ off2 := buf.Len()
+ binary.Write(&buf, binary.BigEndian, §)
+ off3 := buf.Len()
+ buf.Reset()
+ data := byte(elf.ELFDATA2MSB)
+ hdr = elf.Header64{
+ Ident: [16]byte{0x7F, 'E', 'L', 'F', 2, data, 1},
+ Type: 2,
+ Machine: uint16(elf.EM_PPC64),
+ Version: 1,
+ Entry: start,
+ Phoff: uint64(off1),
+ Shoff: uint64(off2),
+ Flags: 0x05000002,
+ Ehsize: uint16(off1),
+ Phentsize: uint16(off2 - off1),
+ Phnum: 1,
+ Shentsize: uint16(off3 - off2),
+ Shnum: 3,
+ Shstrndx: 2,
+ }
+ binary.Write(&buf, binary.BigEndian, &hdr)
+ prog = elf.Prog64{
+ Type: 1,
+ Off: start,
+ Vaddr: start,
+ Paddr: start,
+ Filesz: uint64(size),
+ Memsz: uint64(size),
+ Flags: 5,
+ Align: start,
+ }
+ binary.Write(&buf, binary.BigEndian, &prog)
+ binary.Write(&buf, binary.BigEndian, §) // NULL section
+ sect = elf.Section64{
+ Name: 1,
+ Type: uint32(elf.SHT_PROGBITS),
+ Addr: start,
+ Off: start,
+ Size: uint64(size),
+ Flags: uint64(elf.SHF_ALLOC | elf.SHF_EXECINSTR),
+ Addralign: 4,
+ }
+ binary.Write(&buf, binary.BigEndian, §) // .text
+ sect = elf.Section64{
+ Name: uint32(len("\x00.text\x00")),
+ Type: uint32(elf.SHT_STRTAB),
+ Addr: 0,
+ Off: uint64(off2 + (off3-off2)*3),
+ Size: uint64(len("\x00.text\x00.shstrtab\x00")),
+ Addralign: 1,
+ }
+ binary.Write(&buf, binary.BigEndian, §)
+ buf.WriteString("\x00.text\x00.shstrtab\x00")
+ f.Write(buf.Bytes())
+ return nil
+}
diff --git a/src/cmd/vendor/golang.org/x/arch/ppc64/ppc64asm/plan9.go b/src/cmd/vendor/golang.org/x/arch/ppc64/ppc64asm/plan9.go
new file mode 100644
index 0000000..57a761e
--- /dev/null
+++ b/src/cmd/vendor/golang.org/x/arch/ppc64/ppc64asm/plan9.go
@@ -0,0 +1,172 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ppc64asm
+
+import (
+ "fmt"
+ "strings"
+)
+
+// GoSyntax returns the Go assembler syntax for the instruction.
+// The pc is the program counter of the first instruction, used for expanding
+// PC-relative addresses into absolute ones.
+// The symname function queries the symbol table for the program
+// being disassembled. It returns the name and base address of the symbol
+// containing the target, if any; otherwise it returns "", 0.
+func GoSyntax(inst Inst, pc uint64, symname func(uint64) (string, uint64)) string {
+ if symname == nil {
+ symname = func(uint64) (string, uint64) { return "", 0 }
+ }
+ if inst.Op == 0 {
+ return "?"
+ }
+ var args []string
+ for i, a := range inst.Args[:] {
+ if a == nil {
+ break
+ }
+ if s := plan9Arg(&inst, i, pc, a, symname); s != "" {
+ args = append(args, s)
+ }
+ }
+ var op string
+ op = plan9OpMap[inst.Op]
+ if op == "" {
+ op = strings.ToUpper(inst.Op.String())
+ }
+ // laid out the instruction
+ switch inst.Op {
+ default: // dst, sA, sB, ...
+ if len(args) == 0 {
+ return op
+ } else if len(args) == 1 {
+ return fmt.Sprintf("%s %s", op, args[0])
+ }
+ args = append(args, args[0])
+ return op + " " + strings.Join(args[1:], ", ")
+ // store instructions always have the memory operand at the end, no need to reorder
+ case STB, STBU, STBX, STBUX,
+ STH, STHU, STHX, STHUX,
+ STW, STWU, STWX, STWUX,
+ STD, STDU, STDX, STDUX,
+ STQ,
+ STHBRX, STWBRX:
+ return op + " " + strings.Join(args, ", ")
+ // branch instructions needs additional handling
+ case BCLR:
+ if int(inst.Args[0].(Imm))&20 == 20 { // unconditional
+ return "RET"
+ }
+ return op + " " + strings.Join(args, ", ")
+ case BC:
+ if int(inst.Args[0].(Imm))&0x1c == 12 { // jump on cond bit set
+ return fmt.Sprintf("B%s %s", args[1], args[2])
+ } else if int(inst.Args[0].(Imm))&0x1c == 4 && revCondMap[args[1]] != "" { // jump on cond bit not set
+ return fmt.Sprintf("B%s %s", revCondMap[args[1]], args[2])
+ }
+ return op + " " + strings.Join(args, ", ")
+ case BCCTR:
+ if int(inst.Args[0].(Imm))&20 == 20 { // unconditional
+ return "BR (CTR)"
+ }
+ return op + " " + strings.Join(args, ", ")
+ case BCCTRL:
+ if int(inst.Args[0].(Imm))&20 == 20 { // unconditional
+ return "BL (CTR)"
+ }
+ return op + " " + strings.Join(args, ", ")
+ case BCA, BCL, BCLA, BCLRL, BCTAR, BCTARL:
+ return op + " " + strings.Join(args, ", ")
+ }
+}
+
+// plan9Arg formats arg (which is the argIndex's arg in inst) according to Plan 9 rules.
+// NOTE: because Plan9Syntax is the only caller of this func, and it receives a copy
+// of inst, it's ok to modify inst.Args here.
+func plan9Arg(inst *Inst, argIndex int, pc uint64, arg Arg, symname func(uint64) (string, uint64)) string {
+ // special cases for load/store instructions
+ if _, ok := arg.(Offset); ok {
+ if argIndex+1 == len(inst.Args) || inst.Args[argIndex+1] == nil {
+ panic(fmt.Errorf("wrong table: offset not followed by register"))
+ }
+ }
+ switch arg := arg.(type) {
+ case Reg:
+ if isLoadStoreOp(inst.Op) && argIndex == 1 && arg == R0 {
+ return "0"
+ }
+ if arg == R30 {
+ return "g"
+ }
+ return strings.ToUpper(arg.String())
+ case CondReg:
+ if arg == CR0 && strings.HasPrefix(inst.Op.String(), "cmp") {
+ return "" // don't show cr0 for cmp instructions
+ } else if arg >= CR0 {
+ return fmt.Sprintf("CR%d", int(arg-CR0))
+ }
+ bit := [4]string{"LT", "GT", "EQ", "SO"}[(arg-Cond0LT)%4]
+ if arg <= Cond0SO {
+ return bit
+ }
+ return fmt.Sprintf("4*CR%d+%s", int(arg-Cond0LT)/4, bit)
+ case Imm:
+ return fmt.Sprintf("$%d", arg)
+ case SpReg:
+ switch arg {
+ case 8:
+ return "LR"
+ case 9:
+ return "CTR"
+ }
+ return fmt.Sprintf("SPR(%d)", int(arg))
+ case PCRel:
+ addr := pc + uint64(int64(arg))
+ if s, base := symname(addr); s != "" && base == addr {
+ return fmt.Sprintf("%s(SB)", s)
+ }
+ return fmt.Sprintf("%#x", addr)
+ case Label:
+ return fmt.Sprintf("%#x", int(arg))
+ case Offset:
+ reg := inst.Args[argIndex+1].(Reg)
+ removeArg(inst, argIndex+1)
+ if reg == R0 {
+ return fmt.Sprintf("%d(0)", int(arg))
+ }
+ return fmt.Sprintf("%d(R%d)", int(arg), reg-R0)
+ }
+ return fmt.Sprintf("???(%v)", arg)
+}
+
+// revCondMap maps a conditional register bit to its inverse, if possible.
+var revCondMap = map[string]string{
+ "LT": "GE", "GT": "LE", "EQ": "NE",
+}
+
+// plan9OpMap maps an Op to its Plan 9 mnemonics, if different than its GNU mnemonics.
+var plan9OpMap = map[Op]string{
+ LWARX: "LWAR", STWCX_: "STWCCC",
+ LDARX: "LDAR", STDCX_: "STDCCC",
+ LHARX: "LHAR", STHCX_: "STHCCC",
+ LBARX: "LBAR", STBCX_: "STBCCC",
+ ADDI: "ADD",
+ ADD_: "ADDCC",
+ LBZ: "MOVBZ", STB: "MOVB",
+ LBZU: "MOVBZU", STBU: "MOVBU", // TODO(minux): indexed forms are not handled
+ LHZ: "MOVHZ", LHA: "MOVH", STH: "MOVH",
+ LHZU: "MOVHZU", STHU: "MOVHU",
+ LI: "MOVD",
+ LIS: "ADDIS",
+ LWZ: "MOVWZ", LWA: "MOVW", STW: "MOVW",
+ LWZU: "MOVWZU", STWU: "MOVWU",
+ LD: "MOVD", STD: "MOVD",
+ LDU: "MOVDU", STDU: "MOVDU",
+ MTSPR: "MOVD", MFSPR: "MOVD", // the width is ambiguous for SPRs
+ B: "BR",
+ BL: "CALL",
+ CMPLD: "CMPU", CMPLW: "CMPWU",
+ CMPD: "CMP", CMPW: "CMPW",
+}
diff --git a/src/cmd/vendor/golang.org/x/arch/ppc64/ppc64asm/tables.go b/src/cmd/vendor/golang.org/x/arch/ppc64/ppc64asm/tables.go
new file mode 100644
index 0000000..24c745c
--- /dev/null
+++ b/src/cmd/vendor/golang.org/x/arch/ppc64/ppc64asm/tables.go
@@ -0,0 +1,5421 @@
+// DO NOT EDIT
+// generated by: ppc64map -fmt=decoder ../pp64.csv
+
+package ppc64asm
+
+const (
+ _ Op = iota
+ CNTLZW
+ CNTLZW_
+ B
+ BA
+ BL
+ BLA
+ BC
+ BCA
+ BCL
+ BCLA
+ BCLR
+ BCLRL
+ BCCTR
+ BCCTRL
+ BCTAR
+ BCTARL
+ CRAND
+ CROR
+ CRNAND
+ CRXOR
+ CRNOR
+ CRANDC
+ MCRF
+ CREQV
+ CRORC
+ SC
+ CLRBHRB
+ MFBHRBE
+ LBZ
+ LBZU
+ LBZX
+ LBZUX
+ LHZ
+ LHZU
+ LHZX
+ LHZUX
+ LHA
+ LHAU
+ LHAX
+ LHAUX
+ LWZ
+ LWZU
+ LWZX
+ LWZUX
+ LWA
+ LWAX
+ LWAUX
+ LD
+ LDU
+ LDX
+ LDUX
+ STB
+ STBU
+ STBX
+ STBUX
+ STH
+ STHU
+ STHX
+ STHUX
+ STW
+ STWU
+ STWX
+ STWUX
+ STD
+ STDU
+ STDX
+ STDUX
+ LQ
+ STQ
+ LHBRX
+ LWBRX
+ STHBRX
+ STWBRX
+ LDBRX
+ STDBRX
+ LMW
+ STMW
+ LSWI
+ LSWX
+ STSWI
+ STSWX
+ LI
+ ADDI
+ LIS
+ ADDIS
+ ADD
+ ADD_
+ ADDO
+ ADDO_
+ ADDIC
+ SUBF
+ SUBF_
+ SUBFO
+ SUBFO_
+ ADDIC_
+ SUBFIC
+ ADDC
+ ADDC_
+ ADDCO
+ ADDCO_
+ SUBFC
+ SUBFC_
+ SUBFCO
+ SUBFCO_
+ ADDE
+ ADDE_
+ ADDEO
+ ADDEO_
+ ADDME
+ ADDME_
+ ADDMEO
+ ADDMEO_
+ SUBFE
+ SUBFE_
+ SUBFEO
+ SUBFEO_
+ SUBFME
+ SUBFME_
+ SUBFMEO
+ SUBFMEO_
+ ADDZE
+ ADDZE_
+ ADDZEO
+ ADDZEO_
+ SUBFZE
+ SUBFZE_
+ SUBFZEO
+ SUBFZEO_
+ NEG
+ NEG_
+ NEGO
+ NEGO_
+ MULLI
+ MULLW
+ MULLW_
+ MULLWO
+ MULLWO_
+ MULHW
+ MULHW_
+ MULHWU
+ MULHWU_
+ DIVW
+ DIVW_
+ DIVWO
+ DIVWO_
+ DIVWU
+ DIVWU_
+ DIVWUO
+ DIVWUO_
+ DIVWE
+ DIVWE_
+ DIVWEO
+ DIVWEO_
+ DIVWEU
+ DIVWEU_
+ DIVWEUO
+ DIVWEUO_
+ MULLD
+ MULLD_
+ MULLDO
+ MULLDO_
+ MULHDU
+ MULHDU_
+ MULHD
+ MULHD_
+ DIVD
+ DIVD_
+ DIVDO
+ DIVDO_
+ DIVDU
+ DIVDU_
+ DIVDUO
+ DIVDUO_
+ DIVDE
+ DIVDE_
+ DIVDEO
+ DIVDEO_
+ DIVDEU
+ DIVDEU_
+ DIVDEUO
+ DIVDEUO_
+ CMPWI
+ CMPDI
+ CMPW
+ CMPD
+ CMPLWI
+ CMPLDI
+ CMPLW
+ CMPLD
+ TWI
+ TW
+ TDI
+ ISEL
+ TD
+ ANDI_
+ ANDIS_
+ ORI
+ ORIS
+ XORI
+ XORIS
+ AND
+ AND_
+ XOR
+ XOR_
+ NAND
+ NAND_
+ OR
+ OR_
+ NOR
+ NOR_
+ ANDC
+ ANDC_
+ EXTSB
+ EXTSB_
+ EQV
+ EQV_
+ ORC
+ ORC_
+ EXTSH
+ EXTSH_
+ CMPB
+ POPCNTB
+ POPCNTW
+ PRTYD
+ PRTYW
+ EXTSW
+ EXTSW_
+ CNTLZD
+ CNTLZD_
+ POPCNTD
+ BPERMD
+ RLWINM
+ RLWINM_
+ RLWNM
+ RLWNM_
+ RLWIMI
+ RLWIMI_
+ RLDICL
+ RLDICL_
+ RLDICR
+ RLDICR_
+ RLDIC
+ RLDIC_
+ RLDCL
+ RLDCL_
+ RLDCR
+ RLDCR_
+ RLDIMI
+ RLDIMI_
+ SLW
+ SLW_
+ SRW
+ SRW_
+ SRAWI
+ SRAWI_
+ SRAW
+ SRAW_
+ SLD
+ SLD_
+ SRD
+ SRD_
+ SRADI
+ SRADI_
+ SRAD
+ SRAD_
+ CDTBCD
+ CBCDTD
+ ADDG6S
+ MTSPR
+ MFSPR
+ MTCRF
+ MFCR
+ MTSLE
+ MFVSRD
+ MFVSRWZ
+ MTVSRD
+ MTVSRWA
+ MTVSRWZ
+ MTOCRF
+ MFOCRF
+ MCRXR
+ MTDCRUX
+ MFDCRUX
+ LFS
+ LFSU
+ LFSX
+ LFSUX
+ LFD
+ LFDU
+ LFDX
+ LFDUX
+ LFIWAX
+ LFIWZX
+ STFS
+ STFSU
+ STFSX
+ STFSUX
+ STFD
+ STFDU
+ STFDX
+ STFDUX
+ STFIWX
+ LFDP
+ LFDPX
+ STFDP
+ STFDPX
+ FMR
+ FMR_
+ FABS
+ FABS_
+ FNABS
+ FNABS_
+ FNEG
+ FNEG_
+ FCPSGN
+ FCPSGN_
+ FMRGEW
+ FMRGOW
+ FADD
+ FADD_
+ FADDS
+ FADDS_
+ FSUB
+ FSUB_
+ FSUBS
+ FSUBS_
+ FMUL
+ FMUL_
+ FMULS
+ FMULS_
+ FDIV
+ FDIV_
+ FDIVS
+ FDIVS_
+ FSQRT
+ FSQRT_
+ FSQRTS
+ FSQRTS_
+ FRE
+ FRE_
+ FRES
+ FRES_
+ FRSQRTE
+ FRSQRTE_
+ FRSQRTES
+ FRSQRTES_
+ FTDIV
+ FTSQRT
+ FMADD
+ FMADD_
+ FMADDS
+ FMADDS_
+ FMSUB
+ FMSUB_
+ FMSUBS
+ FMSUBS_
+ FNMADD
+ FNMADD_
+ FNMADDS
+ FNMADDS_
+ FNMSUB
+ FNMSUB_
+ FNMSUBS
+ FNMSUBS_
+ FRSP
+ FRSP_
+ FCTID
+ FCTID_
+ FCTIDZ
+ FCTIDZ_
+ FCTIDU
+ FCTIDU_
+ FCTIDUZ
+ FCTIDUZ_
+ FCTIW
+ FCTIW_
+ FCTIWZ
+ FCTIWZ_
+ FCTIWU
+ FCTIWU_
+ FCTIWUZ
+ FCTIWUZ_
+ FCFID
+ FCFID_
+ FCFIDU
+ FCFIDU_
+ FCFIDS
+ FCFIDS_
+ FCFIDUS
+ FCFIDUS_
+ FRIN
+ FRIN_
+ FRIZ
+ FRIZ_
+ FRIP
+ FRIP_
+ FRIM
+ FRIM_
+ FCMPU
+ FCMPO
+ FSEL
+ FSEL_
+ MFFS
+ MFFS_
+ MCRFS
+ MTFSFI
+ MTFSFI_
+ MTFSF
+ MTFSF_
+ MTFSB0
+ MTFSB0_
+ MTFSB1
+ MTFSB1_
+ LVEBX
+ LVEHX
+ LVEWX
+ LVX
+ LVXL
+ STVEBX
+ STVEHX
+ STVEWX
+ STVX
+ STVXL
+ LVSL
+ LVSR
+ VPKPX
+ VPKSDSS
+ VPKSDUS
+ VPKSHSS
+ VPKSHUS
+ VPKSWSS
+ VPKSWUS
+ VPKUDUM
+ VPKUDUS
+ VPKUHUM
+ VPKUHUS
+ VPKUWUM
+ VPKUWUS
+ VUPKHPX
+ VUPKLPX
+ VUPKHSB
+ VUPKHSH
+ VUPKHSW
+ VUPKLSB
+ VUPKLSH
+ VUPKLSW
+ VMRGHB
+ VMRGHH
+ VMRGLB
+ VMRGLH
+ VMRGHW
+ VMRGLW
+ VMRGEW
+ VMRGOW
+ VSPLTB
+ VSPLTH
+ VSPLTW
+ VSPLTISB
+ VSPLTISH
+ VSPLTISW
+ VPERM
+ VSEL
+ VSL
+ VSLDOI
+ VSLO
+ VSR
+ VSRO
+ VADDCUW
+ VADDSBS
+ VADDSHS
+ VADDSWS
+ VADDUBM
+ VADDUDM
+ VADDUHM
+ VADDUWM
+ VADDUBS
+ VADDUHS
+ VADDUWS
+ VADDUQM
+ VADDEUQM
+ VADDCUQ
+ VADDECUQ
+ VSUBCUW
+ VSUBSBS
+ VSUBSHS
+ VSUBSWS
+ VSUBUBM
+ VSUBUDM
+ VSUBUHM
+ VSUBUWM
+ VSUBUBS
+ VSUBUHS
+ VSUBUWS
+ VSUBUQM
+ VSUBEUQM
+ VSUBCUQ
+ VSUBECUQ
+ VMULESB
+ VMULEUB
+ VMULOSB
+ VMULOUB
+ VMULESH
+ VMULEUH
+ VMULOSH
+ VMULOUH
+ VMULESW
+ VMULEUW
+ VMULOSW
+ VMULOUW
+ VMULUWM
+ VMHADDSHS
+ VMHRADDSHS
+ VMLADDUHM
+ VMSUMUBM
+ VMSUMMBM
+ VMSUMSHM
+ VMSUMSHS
+ VMSUMUHM
+ VMSUMUHS
+ VSUMSWS
+ VSUM2SWS
+ VSUM4SBS
+ VSUM4SHS
+ VSUM4UBS
+ VAVGSB
+ VAVGSH
+ VAVGSW
+ VAVGUB
+ VAVGUW
+ VAVGUH
+ VMAXSB
+ VMAXSD
+ VMAXUB
+ VMAXUD
+ VMAXSH
+ VMAXSW
+ VMAXUH
+ VMAXUW
+ VMINSB
+ VMINSD
+ VMINUB
+ VMINUD
+ VMINSH
+ VMINSW
+ VMINUH
+ VMINUW
+ VCMPEQUB
+ VCMPEQUB_
+ VCMPEQUH
+ VCMPEQUH_
+ VCMPEQUW
+ VCMPEQUW_
+ VCMPEQUD
+ VCMPEQUD_
+ VCMPGTSB
+ VCMPGTSB_
+ VCMPGTSD
+ VCMPGTSD_
+ VCMPGTSH
+ VCMPGTSH_
+ VCMPGTSW
+ VCMPGTSW_
+ VCMPGTUB
+ VCMPGTUB_
+ VCMPGTUD
+ VCMPGTUD_
+ VCMPGTUH
+ VCMPGTUH_
+ VCMPGTUW
+ VCMPGTUW_
+ VAND
+ VANDC
+ VEQV
+ VNAND
+ VORC
+ VNOR
+ VOR
+ VXOR
+ VRLB
+ VRLH
+ VRLW
+ VRLD
+ VSLB
+ VSLH
+ VSLW
+ VSLD
+ VSRB
+ VSRH
+ VSRW
+ VSRD
+ VSRAB
+ VSRAH
+ VSRAW
+ VSRAD
+ VADDFP
+ VSUBFP
+ VMADDFP
+ VNMSUBFP
+ VMAXFP
+ VMINFP
+ VCTSXS
+ VCTUXS
+ VCFSX
+ VCFUX
+ VRFIM
+ VRFIN
+ VRFIP
+ VRFIZ
+ VCMPBFP
+ VCMPBFP_
+ VCMPEQFP
+ VCMPEQFP_
+ VCMPGEFP
+ VCMPGEFP_
+ VCMPGTFP
+ VCMPGTFP_
+ VEXPTEFP
+ VLOGEFP
+ VREFP
+ VRSQRTEFP
+ VCIPHER
+ VCIPHERLAST
+ VNCIPHER
+ VNCIPHERLAST
+ VSBOX
+ VSHASIGMAD
+ VSHASIGMAW
+ VPMSUMB
+ VPMSUMD
+ VPMSUMH
+ VPMSUMW
+ VPERMXOR
+ VGBBD
+ VCLZB
+ VCLZH
+ VCLZW
+ VCLZD
+ VPOPCNTB
+ VPOPCNTD
+ VPOPCNTH
+ VPOPCNTW
+ VBPERMQ
+ BCDADD_
+ BCDSUB_
+ MTVSCR
+ MFVSCR
+ DADD
+ DADD_
+ DSUB
+ DSUB_
+ DMUL
+ DMUL_
+ DDIV
+ DDIV_
+ DCMPU
+ DCMPO
+ DTSTDC
+ DTSTDG
+ DTSTEX
+ DTSTSF
+ DQUAI
+ DQUAI_
+ DQUA
+ DQUA_
+ DRRND
+ DRRND_
+ DRINTX
+ DRINTX_
+ DRINTN
+ DRINTN_
+ DCTDP
+ DCTDP_
+ DCTQPQ
+ DCTQPQ_
+ DRSP
+ DRSP_
+ DRDPQ
+ DRDPQ_
+ DCFFIX
+ DCFFIX_
+ DCFFIXQ
+ DCFFIXQ_
+ DCTFIX
+ DCTFIX_
+ DDEDPD
+ DDEDPD_
+ DENBCD
+ DENBCD_
+ DXEX
+ DXEX_
+ DIEX
+ DIEX_
+ DSCLI
+ DSCLI_
+ DSCRI
+ DSCRI_
+ LXSDX
+ LXSIWAX
+ LXSIWZX
+ LXSSPX
+ LXVD2X
+ LXVDSX
+ LXVW4X
+ STXSDX
+ STXSIWX
+ STXSSPX
+ STXVD2X
+ STXVW4X
+ XSABSDP
+ XSADDDP
+ XSADDSP
+ XSCMPODP
+ XSCMPUDP
+ XSCPSGNDP
+ XSCVDPSP
+ XSCVDPSPN
+ XSCVDPSXDS
+ XSCVDPSXWS
+ XSCVDPUXDS
+ XSCVDPUXWS
+ XSCVSPDP
+ XSCVSPDPN
+ XSCVSXDDP
+ XSCVSXDSP
+ XSCVUXDDP
+ XSCVUXDSP
+ XSDIVDP
+ XSDIVSP
+ XSMADDADP
+ XSMADDASP
+ XSMAXDP
+ XSMINDP
+ XSMSUBADP
+ XSMSUBASP
+ XSMULDP
+ XSMULSP
+ XSNABSDP
+ XSNEGDP
+ XSNMADDADP
+ XSNMADDASP
+ XSNMSUBADP
+ XSNMSUBASP
+ XSRDPI
+ XSRDPIC
+ XSRDPIM
+ XSRDPIP
+ XSRDPIZ
+ XSREDP
+ XSRESP
+ XSRSP
+ XSRSQRTEDP
+ XSRSQRTESP
+ XSSQRTDP
+ XSSQRTSP
+ XSSUBDP
+ XSSUBSP
+ XSTDIVDP
+ XSTSQRTDP
+ XVABSDP
+ XVABSSP
+ XVADDDP
+ XVADDSP
+ XVCMPEQDP
+ XVCMPEQDP_
+ XVCMPEQSP
+ XVCMPEQSP_
+ XVCMPGEDP
+ XVCMPGEDP_
+ XVCMPGESP
+ XVCMPGESP_
+ XVCMPGTDP
+ XVCMPGTDP_
+ XVCMPGTSP
+ XVCMPGTSP_
+ XVCPSGNDP
+ XVCPSGNSP
+ XVCVDPSP
+ XVCVDPSXDS
+ XVCVDPSXWS
+ XVCVDPUXDS
+ XVCVDPUXWS
+ XVCVSPDP
+ XVCVSPSXDS
+ XVCVSPSXWS
+ XVCVSPUXDS
+ XVCVSPUXWS
+ XVCVSXDDP
+ XVCVSXDSP
+ XVCVSXWDP
+ XVCVSXWSP
+ XVCVUXDDP
+ XVCVUXDSP
+ XVCVUXWDP
+ XVCVUXWSP
+ XVDIVDP
+ XVDIVSP
+ XVMADDADP
+ XVMADDASP
+ XVMAXDP
+ XVMAXSP
+ XVMINDP
+ XVMINSP
+ XVMSUBADP
+ XVMSUBASP
+ XVMULDP
+ XVMULSP
+ XVNABSDP
+ XVNABSSP
+ XVNEGDP
+ XVNEGSP
+ XVNMADDADP
+ XVNMADDASP
+ XVNMSUBADP
+ XVNMSUBASP
+ XVRDPI
+ XVRDPIC
+ XVRDPIM
+ XVRDPIP
+ XVRDPIZ
+ XVREDP
+ XVRESP
+ XVRSPI
+ XVRSPIC
+ XVRSPIM
+ XVRSPIP
+ XVRSPIZ
+ XVRSQRTEDP
+ XVRSQRTESP
+ XVSQRTDP
+ XVSQRTSP
+ XVSUBDP
+ XVSUBSP
+ XVTDIVDP
+ XVTDIVSP
+ XVTSQRTDP
+ XVTSQRTSP
+ XXLAND
+ XXLANDC
+ XXLEQV
+ XXLNAND
+ XXLORC
+ XXLNOR
+ XXLOR
+ XXLXOR
+ XXMRGHW
+ XXMRGLW
+ XXPERMDI
+ XXSEL
+ XXSLDWI
+ XXSPLTW
+ BRINC
+ EVABS
+ EVADDIW
+ EVADDSMIAAW
+ EVADDSSIAAW
+ EVADDUMIAAW
+ EVADDUSIAAW
+ EVADDW
+ EVAND
+ EVCMPEQ
+ EVANDC
+ EVCMPGTS
+ EVCMPGTU
+ EVCMPLTU
+ EVCMPLTS
+ EVCNTLSW
+ EVCNTLZW
+ EVDIVWS
+ EVDIVWU
+ EVEQV
+ EVEXTSB
+ EVEXTSH
+ EVLDD
+ EVLDH
+ EVLDDX
+ EVLDHX
+ EVLDW
+ EVLHHESPLAT
+ EVLDWX
+ EVLHHESPLATX
+ EVLHHOSSPLAT
+ EVLHHOUSPLAT
+ EVLHHOSSPLATX
+ EVLHHOUSPLATX
+ EVLWHE
+ EVLWHOS
+ EVLWHEX
+ EVLWHOSX
+ EVLWHOU
+ EVLWHSPLAT
+ EVLWHOUX
+ EVLWHSPLATX
+ EVLWWSPLAT
+ EVMERGEHI
+ EVLWWSPLATX
+ EVMERGELO
+ EVMERGEHILO
+ EVMHEGSMFAA
+ EVMERGELOHI
+ EVMHEGSMFAN
+ EVMHEGSMIAA
+ EVMHEGUMIAA
+ EVMHEGSMIAN
+ EVMHEGUMIAN
+ EVMHESMF
+ EVMHESMFAAW
+ EVMHESMFA
+ EVMHESMFANW
+ EVMHESMI
+ EVMHESMIAAW
+ EVMHESMIA
+ EVMHESMIANW
+ EVMHESSF
+ EVMHESSFA
+ EVMHESSFAAW
+ EVMHESSFANW
+ EVMHESSIAAW
+ EVMHESSIANW
+ EVMHEUMI
+ EVMHEUMIAAW
+ EVMHEUMIA
+ EVMHEUMIANW
+ EVMHEUSIAAW
+ EVMHEUSIANW
+ EVMHOGSMFAA
+ EVMHOGSMIAA
+ EVMHOGSMFAN
+ EVMHOGSMIAN
+ EVMHOGUMIAA
+ EVMHOSMF
+ EVMHOGUMIAN
+ EVMHOSMFA
+ EVMHOSMFAAW
+ EVMHOSMI
+ EVMHOSMFANW
+ EVMHOSMIA
+ EVMHOSMIAAW
+ EVMHOSMIANW
+ EVMHOSSF
+ EVMHOSSFA
+ EVMHOSSFAAW
+ EVMHOSSFANW
+ EVMHOSSIAAW
+ EVMHOUMI
+ EVMHOSSIANW
+ EVMHOUMIA
+ EVMHOUMIAAW
+ EVMHOUSIAAW
+ EVMHOUMIANW
+ EVMHOUSIANW
+ EVMRA
+ EVMWHSMF
+ EVMWHSMI
+ EVMWHSMFA
+ EVMWHSMIA
+ EVMWHSSF
+ EVMWHUMI
+ EVMWHSSFA
+ EVMWHUMIA
+ EVMWLSMIAAW
+ EVMWLSSIAAW
+ EVMWLSMIANW
+ EVMWLSSIANW
+ EVMWLUMI
+ EVMWLUMIAAW
+ EVMWLUMIA
+ EVMWLUMIANW
+ EVMWLUSIAAW
+ EVMWSMF
+ EVMWLUSIANW
+ EVMWSMFA
+ EVMWSMFAA
+ EVMWSMI
+ EVMWSMIAA
+ EVMWSMFAN
+ EVMWSMIA
+ EVMWSMIAN
+ EVMWSSF
+ EVMWSSFA
+ EVMWSSFAA
+ EVMWUMI
+ EVMWSSFAN
+ EVMWUMIA
+ EVMWUMIAA
+ EVNAND
+ EVMWUMIAN
+ EVNEG
+ EVNOR
+ EVORC
+ EVOR
+ EVRLW
+ EVRLWI
+ EVSEL
+ EVRNDW
+ EVSLW
+ EVSPLATFI
+ EVSRWIS
+ EVSLWI
+ EVSPLATI
+ EVSRWIU
+ EVSRWS
+ EVSTDD
+ EVSRWU
+ EVSTDDX
+ EVSTDH
+ EVSTDW
+ EVSTDHX
+ EVSTDWX
+ EVSTWHE
+ EVSTWHO
+ EVSTWWE
+ EVSTWHEX
+ EVSTWHOX
+ EVSTWWEX
+ EVSTWWO
+ EVSUBFSMIAAW
+ EVSTWWOX
+ EVSUBFSSIAAW
+ EVSUBFUMIAAW
+ EVSUBFUSIAAW
+ EVSUBFW
+ EVSUBIFW
+ EVXOR
+ EVFSABS
+ EVFSNABS
+ EVFSNEG
+ EVFSADD
+ EVFSMUL
+ EVFSSUB
+ EVFSDIV
+ EVFSCMPGT
+ EVFSCMPLT
+ EVFSCMPEQ
+ EVFSTSTGT
+ EVFSTSTLT
+ EVFSTSTEQ
+ EVFSCFSI
+ EVFSCFSF
+ EVFSCFUI
+ EVFSCFUF
+ EVFSCTSI
+ EVFSCTUI
+ EVFSCTSIZ
+ EVFSCTUIZ
+ EVFSCTSF
+ EVFSCTUF
+ EFSABS
+ EFSNEG
+ EFSNABS
+ EFSADD
+ EFSMUL
+ EFSSUB
+ EFSDIV
+ EFSCMPGT
+ EFSCMPLT
+ EFSCMPEQ
+ EFSTSTGT
+ EFSTSTLT
+ EFSTSTEQ
+ EFSCFSI
+ EFSCFSF
+ EFSCTSI
+ EFSCFUI
+ EFSCFUF
+ EFSCTUI
+ EFSCTSIZ
+ EFSCTSF
+ EFSCTUIZ
+ EFSCTUF
+ EFDABS
+ EFDNEG
+ EFDNABS
+ EFDADD
+ EFDMUL
+ EFDSUB
+ EFDDIV
+ EFDCMPGT
+ EFDCMPEQ
+ EFDCMPLT
+ EFDTSTGT
+ EFDTSTLT
+ EFDCFSI
+ EFDTSTEQ
+ EFDCFUI
+ EFDCFSID
+ EFDCFSF
+ EFDCFUF
+ EFDCFUID
+ EFDCTSI
+ EFDCTUI
+ EFDCTSIDZ
+ EFDCTUIDZ
+ EFDCTSIZ
+ EFDCTSF
+ EFDCTUF
+ EFDCTUIZ
+ EFDCFS
+ EFSCFD
+ DLMZB
+ DLMZB_
+ MACCHW
+ MACCHW_
+ MACCHWO
+ MACCHWO_
+ MACCHWS
+ MACCHWS_
+ MACCHWSO
+ MACCHWSO_
+ MACCHWU
+ MACCHWU_
+ MACCHWUO
+ MACCHWUO_
+ MACCHWSU
+ MACCHWSU_
+ MACCHWSUO
+ MACCHWSUO_
+ MACHHW
+ MACHHW_
+ MACHHWO
+ MACHHWO_
+ MACHHWS
+ MACHHWS_
+ MACHHWSO
+ MACHHWSO_
+ MACHHWU
+ MACHHWU_
+ MACHHWUO
+ MACHHWUO_
+ MACHHWSU
+ MACHHWSU_
+ MACHHWSUO
+ MACHHWSUO_
+ MACLHW
+ MACLHW_
+ MACLHWO
+ MACLHWO_
+ MACLHWS
+ MACLHWS_
+ MACLHWSO
+ MACLHWSO_
+ MACLHWU
+ MACLHWU_
+ MACLHWUO
+ MACLHWUO_
+ MULCHW
+ MULCHW_
+ MACLHWSU
+ MACLHWSU_
+ MACLHWSUO
+ MACLHWSUO_
+ MULCHWU
+ MULCHWU_
+ MULHHW
+ MULHHW_
+ MULLHW
+ MULLHW_
+ MULHHWU
+ MULHHWU_
+ MULLHWU
+ MULLHWU_
+ NMACCHW
+ NMACCHW_
+ NMACCHWO
+ NMACCHWO_
+ NMACCHWS
+ NMACCHWS_
+ NMACCHWSO
+ NMACCHWSO_
+ NMACHHW
+ NMACHHW_
+ NMACHHWO
+ NMACHHWO_
+ NMACHHWS
+ NMACHHWS_
+ NMACHHWSO
+ NMACHHWSO_
+ NMACLHW
+ NMACLHW_
+ NMACLHWO
+ NMACLHWO_
+ NMACLHWS
+ NMACLHWS_
+ NMACLHWSO
+ NMACLHWSO_
+ ICBI
+ ICBT
+ DCBA
+ DCBT
+ DCBTST
+ DCBZ
+ DCBST
+ DCBF
+ ISYNC
+ LBARX
+ LHARX
+ LWARX
+ STBCX_
+ STHCX_
+ STWCX_
+ LDARX
+ STDCX_
+ LQARX
+ STQCX_
+ SYNC
+ EIEIO
+ MBAR
+ WAIT
+ TBEGIN_
+ TEND_
+ TABORT_
+ TABORTWC_
+ TABORTWCI_
+ TABORTDC_
+ TABORTDCI_
+ TSR_
+ TCHECK
+ MFTB
+ RFEBB
+ LBDX
+ LHDX
+ LWDX
+ LDDX
+ LFDDX
+ STBDX
+ STHDX
+ STWDX
+ STDDX
+ STFDDX
+ DSN
+ ECIWX
+ ECOWX
+ RFID
+ HRFID
+ DOZE
+ NAP
+ SLEEP
+ RVWINKLE
+ LBZCIX
+ LWZCIX
+ LHZCIX
+ LDCIX
+ STBCIX
+ STWCIX
+ STHCIX
+ STDCIX
+ TRECLAIM_
+ TRECHKPT_
+ MTMSR
+ MTMSRD
+ MFMSR
+ SLBIE
+ SLBIA
+ SLBMTE
+ SLBMFEV
+ SLBMFEE
+ SLBFEE_
+ MTSR
+ MTSRIN
+ MFSR
+ MFSRIN
+ TLBIE
+ TLBIEL
+ TLBIA
+ TLBSYNC
+ MSGSND
+ MSGCLR
+ MSGSNDP
+ MSGCLRP
+ MTTMR
+ RFI
+ RFCI
+ RFDI
+ RFMCI
+ RFGI
+ EHPRIV
+ MTDCR
+ MTDCRX
+ MFDCR
+ MFDCRX
+ WRTEE
+ WRTEEI
+ LBEPX
+ LHEPX
+ LWEPX
+ LDEPX
+ STBEPX
+ STHEPX
+ STWEPX
+ STDEPX
+ DCBSTEP
+ DCBTEP
+ DCBFEP
+ DCBTSTEP
+ ICBIEP
+ DCBZEP
+ LFDEPX
+ STFDEPX
+ EVLDDEPX
+ EVSTDDEPX
+ LVEPX
+ LVEPXL
+ STVEPX
+ STVEPXL
+ DCBI
+ DCBLQ_
+ ICBLQ_
+ DCBTLS
+ DCBTSTLS
+ ICBTLS
+ ICBLC
+ DCBLC
+ TLBIVAX
+ TLBILX
+ TLBSX
+ TLBSRX_
+ TLBRE
+ TLBWE
+ DNH
+ DCI
+ ICI
+ DCREAD
+ ICREAD
+ MFPMR
+ MTPMR
+)
+
+var opstr = [...]string{
+ CNTLZW: "cntlzw",
+ CNTLZW_: "cntlzw.",
+ B: "b",
+ BA: "ba",
+ BL: "bl",
+ BLA: "bla",
+ BC: "bc",
+ BCA: "bca",
+ BCL: "bcl",
+ BCLA: "bcla",
+ BCLR: "bclr",
+ BCLRL: "bclrl",
+ BCCTR: "bcctr",
+ BCCTRL: "bcctrl",
+ BCTAR: "bctar",
+ BCTARL: "bctarl",
+ CRAND: "crand",
+ CROR: "cror",
+ CRNAND: "crnand",
+ CRXOR: "crxor",
+ CRNOR: "crnor",
+ CRANDC: "crandc",
+ MCRF: "mcrf",
+ CREQV: "creqv",
+ CRORC: "crorc",
+ SC: "sc",
+ CLRBHRB: "clrbhrb",
+ MFBHRBE: "mfbhrbe",
+ LBZ: "lbz",
+ LBZU: "lbzu",
+ LBZX: "lbzx",
+ LBZUX: "lbzux",
+ LHZ: "lhz",
+ LHZU: "lhzu",
+ LHZX: "lhzx",
+ LHZUX: "lhzux",
+ LHA: "lha",
+ LHAU: "lhau",
+ LHAX: "lhax",
+ LHAUX: "lhaux",
+ LWZ: "lwz",
+ LWZU: "lwzu",
+ LWZX: "lwzx",
+ LWZUX: "lwzux",
+ LWA: "lwa",
+ LWAX: "lwax",
+ LWAUX: "lwaux",
+ LD: "ld",
+ LDU: "ldu",
+ LDX: "ldx",
+ LDUX: "ldux",
+ STB: "stb",
+ STBU: "stbu",
+ STBX: "stbx",
+ STBUX: "stbux",
+ STH: "sth",
+ STHU: "sthu",
+ STHX: "sthx",
+ STHUX: "sthux",
+ STW: "stw",
+ STWU: "stwu",
+ STWX: "stwx",
+ STWUX: "stwux",
+ STD: "std",
+ STDU: "stdu",
+ STDX: "stdx",
+ STDUX: "stdux",
+ LQ: "lq",
+ STQ: "stq",
+ LHBRX: "lhbrx",
+ LWBRX: "lwbrx",
+ STHBRX: "sthbrx",
+ STWBRX: "stwbrx",
+ LDBRX: "ldbrx",
+ STDBRX: "stdbrx",
+ LMW: "lmw",
+ STMW: "stmw",
+ LSWI: "lswi",
+ LSWX: "lswx",
+ STSWI: "stswi",
+ STSWX: "stswx",
+ LI: "li",
+ ADDI: "addi",
+ LIS: "lis",
+ ADDIS: "addis",
+ ADD: "add",
+ ADD_: "add.",
+ ADDO: "addo",
+ ADDO_: "addo.",
+ ADDIC: "addic",
+ SUBF: "subf",
+ SUBF_: "subf.",
+ SUBFO: "subfo",
+ SUBFO_: "subfo.",
+ ADDIC_: "addic.",
+ SUBFIC: "subfic",
+ ADDC: "addc",
+ ADDC_: "addc.",
+ ADDCO: "addco",
+ ADDCO_: "addco.",
+ SUBFC: "subfc",
+ SUBFC_: "subfc.",
+ SUBFCO: "subfco",
+ SUBFCO_: "subfco.",
+ ADDE: "adde",
+ ADDE_: "adde.",
+ ADDEO: "addeo",
+ ADDEO_: "addeo.",
+ ADDME: "addme",
+ ADDME_: "addme.",
+ ADDMEO: "addmeo",
+ ADDMEO_: "addmeo.",
+ SUBFE: "subfe",
+ SUBFE_: "subfe.",
+ SUBFEO: "subfeo",
+ SUBFEO_: "subfeo.",
+ SUBFME: "subfme",
+ SUBFME_: "subfme.",
+ SUBFMEO: "subfmeo",
+ SUBFMEO_: "subfmeo.",
+ ADDZE: "addze",
+ ADDZE_: "addze.",
+ ADDZEO: "addzeo",
+ ADDZEO_: "addzeo.",
+ SUBFZE: "subfze",
+ SUBFZE_: "subfze.",
+ SUBFZEO: "subfzeo",
+ SUBFZEO_: "subfzeo.",
+ NEG: "neg",
+ NEG_: "neg.",
+ NEGO: "nego",
+ NEGO_: "nego.",
+ MULLI: "mulli",
+ MULLW: "mullw",
+ MULLW_: "mullw.",
+ MULLWO: "mullwo",
+ MULLWO_: "mullwo.",
+ MULHW: "mulhw",
+ MULHW_: "mulhw.",
+ MULHWU: "mulhwu",
+ MULHWU_: "mulhwu.",
+ DIVW: "divw",
+ DIVW_: "divw.",
+ DIVWO: "divwo",
+ DIVWO_: "divwo.",
+ DIVWU: "divwu",
+ DIVWU_: "divwu.",
+ DIVWUO: "divwuo",
+ DIVWUO_: "divwuo.",
+ DIVWE: "divwe",
+ DIVWE_: "divwe.",
+ DIVWEO: "divweo",
+ DIVWEO_: "divweo.",
+ DIVWEU: "divweu",
+ DIVWEU_: "divweu.",
+ DIVWEUO: "divweuo",
+ DIVWEUO_: "divweuo.",
+ MULLD: "mulld",
+ MULLD_: "mulld.",
+ MULLDO: "mulldo",
+ MULLDO_: "mulldo.",
+ MULHDU: "mulhdu",
+ MULHDU_: "mulhdu.",
+ MULHD: "mulhd",
+ MULHD_: "mulhd.",
+ DIVD: "divd",
+ DIVD_: "divd.",
+ DIVDO: "divdo",
+ DIVDO_: "divdo.",
+ DIVDU: "divdu",
+ DIVDU_: "divdu.",
+ DIVDUO: "divduo",
+ DIVDUO_: "divduo.",
+ DIVDE: "divde",
+ DIVDE_: "divde.",
+ DIVDEO: "divdeo",
+ DIVDEO_: "divdeo.",
+ DIVDEU: "divdeu",
+ DIVDEU_: "divdeu.",
+ DIVDEUO: "divdeuo",
+ DIVDEUO_: "divdeuo.",
+ CMPWI: "cmpwi",
+ CMPDI: "cmpdi",
+ CMPW: "cmpw",
+ CMPD: "cmpd",
+ CMPLWI: "cmplwi",
+ CMPLDI: "cmpldi",
+ CMPLW: "cmplw",
+ CMPLD: "cmpld",
+ TWI: "twi",
+ TW: "tw",
+ TDI: "tdi",
+ ISEL: "isel",
+ TD: "td",
+ ANDI_: "andi.",
+ ANDIS_: "andis.",
+ ORI: "ori",
+ ORIS: "oris",
+ XORI: "xori",
+ XORIS: "xoris",
+ AND: "and",
+ AND_: "and.",
+ XOR: "xor",
+ XOR_: "xor.",
+ NAND: "nand",
+ NAND_: "nand.",
+ OR: "or",
+ OR_: "or.",
+ NOR: "nor",
+ NOR_: "nor.",
+ ANDC: "andc",
+ ANDC_: "andc.",
+ EXTSB: "extsb",
+ EXTSB_: "extsb.",
+ EQV: "eqv",
+ EQV_: "eqv.",
+ ORC: "orc",
+ ORC_: "orc.",
+ EXTSH: "extsh",
+ EXTSH_: "extsh.",
+ CMPB: "cmpb",
+ POPCNTB: "popcntb",
+ POPCNTW: "popcntw",
+ PRTYD: "prtyd",
+ PRTYW: "prtyw",
+ EXTSW: "extsw",
+ EXTSW_: "extsw.",
+ CNTLZD: "cntlzd",
+ CNTLZD_: "cntlzd.",
+ POPCNTD: "popcntd",
+ BPERMD: "bpermd",
+ RLWINM: "rlwinm",
+ RLWINM_: "rlwinm.",
+ RLWNM: "rlwnm",
+ RLWNM_: "rlwnm.",
+ RLWIMI: "rlwimi",
+ RLWIMI_: "rlwimi.",
+ RLDICL: "rldicl",
+ RLDICL_: "rldicl.",
+ RLDICR: "rldicr",
+ RLDICR_: "rldicr.",
+ RLDIC: "rldic",
+ RLDIC_: "rldic.",
+ RLDCL: "rldcl",
+ RLDCL_: "rldcl.",
+ RLDCR: "rldcr",
+ RLDCR_: "rldcr.",
+ RLDIMI: "rldimi",
+ RLDIMI_: "rldimi.",
+ SLW: "slw",
+ SLW_: "slw.",
+ SRW: "srw",
+ SRW_: "srw.",
+ SRAWI: "srawi",
+ SRAWI_: "srawi.",
+ SRAW: "sraw",
+ SRAW_: "sraw.",
+ SLD: "sld",
+ SLD_: "sld.",
+ SRD: "srd",
+ SRD_: "srd.",
+ SRADI: "sradi",
+ SRADI_: "sradi.",
+ SRAD: "srad",
+ SRAD_: "srad.",
+ CDTBCD: "cdtbcd",
+ CBCDTD: "cbcdtd",
+ ADDG6S: "addg6s",
+ MTSPR: "mtspr",
+ MFSPR: "mfspr",
+ MTCRF: "mtcrf",
+ MFCR: "mfcr",
+ MTSLE: "mtsle",
+ MFVSRD: "mfvsrd",
+ MFVSRWZ: "mfvsrwz",
+ MTVSRD: "mtvsrd",
+ MTVSRWA: "mtvsrwa",
+ MTVSRWZ: "mtvsrwz",
+ MTOCRF: "mtocrf",
+ MFOCRF: "mfocrf",
+ MCRXR: "mcrxr",
+ MTDCRUX: "mtdcrux",
+ MFDCRUX: "mfdcrux",
+ LFS: "lfs",
+ LFSU: "lfsu",
+ LFSX: "lfsx",
+ LFSUX: "lfsux",
+ LFD: "lfd",
+ LFDU: "lfdu",
+ LFDX: "lfdx",
+ LFDUX: "lfdux",
+ LFIWAX: "lfiwax",
+ LFIWZX: "lfiwzx",
+ STFS: "stfs",
+ STFSU: "stfsu",
+ STFSX: "stfsx",
+ STFSUX: "stfsux",
+ STFD: "stfd",
+ STFDU: "stfdu",
+ STFDX: "stfdx",
+ STFDUX: "stfdux",
+ STFIWX: "stfiwx",
+ LFDP: "lfdp",
+ LFDPX: "lfdpx",
+ STFDP: "stfdp",
+ STFDPX: "stfdpx",
+ FMR: "fmr",
+ FMR_: "fmr.",
+ FABS: "fabs",
+ FABS_: "fabs.",
+ FNABS: "fnabs",
+ FNABS_: "fnabs.",
+ FNEG: "fneg",
+ FNEG_: "fneg.",
+ FCPSGN: "fcpsgn",
+ FCPSGN_: "fcpsgn.",
+ FMRGEW: "fmrgew",
+ FMRGOW: "fmrgow",
+ FADD: "fadd",
+ FADD_: "fadd.",
+ FADDS: "fadds",
+ FADDS_: "fadds.",
+ FSUB: "fsub",
+ FSUB_: "fsub.",
+ FSUBS: "fsubs",
+ FSUBS_: "fsubs.",
+ FMUL: "fmul",
+ FMUL_: "fmul.",
+ FMULS: "fmuls",
+ FMULS_: "fmuls.",
+ FDIV: "fdiv",
+ FDIV_: "fdiv.",
+ FDIVS: "fdivs",
+ FDIVS_: "fdivs.",
+ FSQRT: "fsqrt",
+ FSQRT_: "fsqrt.",
+ FSQRTS: "fsqrts",
+ FSQRTS_: "fsqrts.",
+ FRE: "fre",
+ FRE_: "fre.",
+ FRES: "fres",
+ FRES_: "fres.",
+ FRSQRTE: "frsqrte",
+ FRSQRTE_: "frsqrte.",
+ FRSQRTES: "frsqrtes",
+ FRSQRTES_: "frsqrtes.",
+ FTDIV: "ftdiv",
+ FTSQRT: "ftsqrt",
+ FMADD: "fmadd",
+ FMADD_: "fmadd.",
+ FMADDS: "fmadds",
+ FMADDS_: "fmadds.",
+ FMSUB: "fmsub",
+ FMSUB_: "fmsub.",
+ FMSUBS: "fmsubs",
+ FMSUBS_: "fmsubs.",
+ FNMADD: "fnmadd",
+ FNMADD_: "fnmadd.",
+ FNMADDS: "fnmadds",
+ FNMADDS_: "fnmadds.",
+ FNMSUB: "fnmsub",
+ FNMSUB_: "fnmsub.",
+ FNMSUBS: "fnmsubs",
+ FNMSUBS_: "fnmsubs.",
+ FRSP: "frsp",
+ FRSP_: "frsp.",
+ FCTID: "fctid",
+ FCTID_: "fctid.",
+ FCTIDZ: "fctidz",
+ FCTIDZ_: "fctidz.",
+ FCTIDU: "fctidu",
+ FCTIDU_: "fctidu.",
+ FCTIDUZ: "fctiduz",
+ FCTIDUZ_: "fctiduz.",
+ FCTIW: "fctiw",
+ FCTIW_: "fctiw.",
+ FCTIWZ: "fctiwz",
+ FCTIWZ_: "fctiwz.",
+ FCTIWU: "fctiwu",
+ FCTIWU_: "fctiwu.",
+ FCTIWUZ: "fctiwuz",
+ FCTIWUZ_: "fctiwuz.",
+ FCFID: "fcfid",
+ FCFID_: "fcfid.",
+ FCFIDU: "fcfidu",
+ FCFIDU_: "fcfidu.",
+ FCFIDS: "fcfids",
+ FCFIDS_: "fcfids.",
+ FCFIDUS: "fcfidus",
+ FCFIDUS_: "fcfidus.",
+ FRIN: "frin",
+ FRIN_: "frin.",
+ FRIZ: "friz",
+ FRIZ_: "friz.",
+ FRIP: "frip",
+ FRIP_: "frip.",
+ FRIM: "frim",
+ FRIM_: "frim.",
+ FCMPU: "fcmpu",
+ FCMPO: "fcmpo",
+ FSEL: "fsel",
+ FSEL_: "fsel.",
+ MFFS: "mffs",
+ MFFS_: "mffs.",
+ MCRFS: "mcrfs",
+ MTFSFI: "mtfsfi",
+ MTFSFI_: "mtfsfi.",
+ MTFSF: "mtfsf",
+ MTFSF_: "mtfsf.",
+ MTFSB0: "mtfsb0",
+ MTFSB0_: "mtfsb0.",
+ MTFSB1: "mtfsb1",
+ MTFSB1_: "mtfsb1.",
+ LVEBX: "lvebx",
+ LVEHX: "lvehx",
+ LVEWX: "lvewx",
+ LVX: "lvx",
+ LVXL: "lvxl",
+ STVEBX: "stvebx",
+ STVEHX: "stvehx",
+ STVEWX: "stvewx",
+ STVX: "stvx",
+ STVXL: "stvxl",
+ LVSL: "lvsl",
+ LVSR: "lvsr",
+ VPKPX: "vpkpx",
+ VPKSDSS: "vpksdss",
+ VPKSDUS: "vpksdus",
+ VPKSHSS: "vpkshss",
+ VPKSHUS: "vpkshus",
+ VPKSWSS: "vpkswss",
+ VPKSWUS: "vpkswus",
+ VPKUDUM: "vpkudum",
+ VPKUDUS: "vpkudus",
+ VPKUHUM: "vpkuhum",
+ VPKUHUS: "vpkuhus",
+ VPKUWUM: "vpkuwum",
+ VPKUWUS: "vpkuwus",
+ VUPKHPX: "vupkhpx",
+ VUPKLPX: "vupklpx",
+ VUPKHSB: "vupkhsb",
+ VUPKHSH: "vupkhsh",
+ VUPKHSW: "vupkhsw",
+ VUPKLSB: "vupklsb",
+ VUPKLSH: "vupklsh",
+ VUPKLSW: "vupklsw",
+ VMRGHB: "vmrghb",
+ VMRGHH: "vmrghh",
+ VMRGLB: "vmrglb",
+ VMRGLH: "vmrglh",
+ VMRGHW: "vmrghw",
+ VMRGLW: "vmrglw",
+ VMRGEW: "vmrgew",
+ VMRGOW: "vmrgow",
+ VSPLTB: "vspltb",
+ VSPLTH: "vsplth",
+ VSPLTW: "vspltw",
+ VSPLTISB: "vspltisb",
+ VSPLTISH: "vspltish",
+ VSPLTISW: "vspltisw",
+ VPERM: "vperm",
+ VSEL: "vsel",
+ VSL: "vsl",
+ VSLDOI: "vsldoi",
+ VSLO: "vslo",
+ VSR: "vsr",
+ VSRO: "vsro",
+ VADDCUW: "vaddcuw",
+ VADDSBS: "vaddsbs",
+ VADDSHS: "vaddshs",
+ VADDSWS: "vaddsws",
+ VADDUBM: "vaddubm",
+ VADDUDM: "vaddudm",
+ VADDUHM: "vadduhm",
+ VADDUWM: "vadduwm",
+ VADDUBS: "vaddubs",
+ VADDUHS: "vadduhs",
+ VADDUWS: "vadduws",
+ VADDUQM: "vadduqm",
+ VADDEUQM: "vaddeuqm",
+ VADDCUQ: "vaddcuq",
+ VADDECUQ: "vaddecuq",
+ VSUBCUW: "vsubcuw",
+ VSUBSBS: "vsubsbs",
+ VSUBSHS: "vsubshs",
+ VSUBSWS: "vsubsws",
+ VSUBUBM: "vsububm",
+ VSUBUDM: "vsubudm",
+ VSUBUHM: "vsubuhm",
+ VSUBUWM: "vsubuwm",
+ VSUBUBS: "vsububs",
+ VSUBUHS: "vsubuhs",
+ VSUBUWS: "vsubuws",
+ VSUBUQM: "vsubuqm",
+ VSUBEUQM: "vsubeuqm",
+ VSUBCUQ: "vsubcuq",
+ VSUBECUQ: "vsubecuq",
+ VMULESB: "vmulesb",
+ VMULEUB: "vmuleub",
+ VMULOSB: "vmulosb",
+ VMULOUB: "vmuloub",
+ VMULESH: "vmulesh",
+ VMULEUH: "vmuleuh",
+ VMULOSH: "vmulosh",
+ VMULOUH: "vmulouh",
+ VMULESW: "vmulesw",
+ VMULEUW: "vmuleuw",
+ VMULOSW: "vmulosw",
+ VMULOUW: "vmulouw",
+ VMULUWM: "vmuluwm",
+ VMHADDSHS: "vmhaddshs",
+ VMHRADDSHS: "vmhraddshs",
+ VMLADDUHM: "vmladduhm",
+ VMSUMUBM: "vmsumubm",
+ VMSUMMBM: "vmsummbm",
+ VMSUMSHM: "vmsumshm",
+ VMSUMSHS: "vmsumshs",
+ VMSUMUHM: "vmsumuhm",
+ VMSUMUHS: "vmsumuhs",
+ VSUMSWS: "vsumsws",
+ VSUM2SWS: "vsum2sws",
+ VSUM4SBS: "vsum4sbs",
+ VSUM4SHS: "vsum4shs",
+ VSUM4UBS: "vsum4ubs",
+ VAVGSB: "vavgsb",
+ VAVGSH: "vavgsh",
+ VAVGSW: "vavgsw",
+ VAVGUB: "vavgub",
+ VAVGUW: "vavguw",
+ VAVGUH: "vavguh",
+ VMAXSB: "vmaxsb",
+ VMAXSD: "vmaxsd",
+ VMAXUB: "vmaxub",
+ VMAXUD: "vmaxud",
+ VMAXSH: "vmaxsh",
+ VMAXSW: "vmaxsw",
+ VMAXUH: "vmaxuh",
+ VMAXUW: "vmaxuw",
+ VMINSB: "vminsb",
+ VMINSD: "vminsd",
+ VMINUB: "vminub",
+ VMINUD: "vminud",
+ VMINSH: "vminsh",
+ VMINSW: "vminsw",
+ VMINUH: "vminuh",
+ VMINUW: "vminuw",
+ VCMPEQUB: "vcmpequb",
+ VCMPEQUB_: "vcmpequb.",
+ VCMPEQUH: "vcmpequh",
+ VCMPEQUH_: "vcmpequh.",
+ VCMPEQUW: "vcmpequw",
+ VCMPEQUW_: "vcmpequw.",
+ VCMPEQUD: "vcmpequd",
+ VCMPEQUD_: "vcmpequd.",
+ VCMPGTSB: "vcmpgtsb",
+ VCMPGTSB_: "vcmpgtsb.",
+ VCMPGTSD: "vcmpgtsd",
+ VCMPGTSD_: "vcmpgtsd.",
+ VCMPGTSH: "vcmpgtsh",
+ VCMPGTSH_: "vcmpgtsh.",
+ VCMPGTSW: "vcmpgtsw",
+ VCMPGTSW_: "vcmpgtsw.",
+ VCMPGTUB: "vcmpgtub",
+ VCMPGTUB_: "vcmpgtub.",
+ VCMPGTUD: "vcmpgtud",
+ VCMPGTUD_: "vcmpgtud.",
+ VCMPGTUH: "vcmpgtuh",
+ VCMPGTUH_: "vcmpgtuh.",
+ VCMPGTUW: "vcmpgtuw",
+ VCMPGTUW_: "vcmpgtuw.",
+ VAND: "vand",
+ VANDC: "vandc",
+ VEQV: "veqv",
+ VNAND: "vnand",
+ VORC: "vorc",
+ VNOR: "vnor",
+ VOR: "vor",
+ VXOR: "vxor",
+ VRLB: "vrlb",
+ VRLH: "vrlh",
+ VRLW: "vrlw",
+ VRLD: "vrld",
+ VSLB: "vslb",
+ VSLH: "vslh",
+ VSLW: "vslw",
+ VSLD: "vsld",
+ VSRB: "vsrb",
+ VSRH: "vsrh",
+ VSRW: "vsrw",
+ VSRD: "vsrd",
+ VSRAB: "vsrab",
+ VSRAH: "vsrah",
+ VSRAW: "vsraw",
+ VSRAD: "vsrad",
+ VADDFP: "vaddfp",
+ VSUBFP: "vsubfp",
+ VMADDFP: "vmaddfp",
+ VNMSUBFP: "vnmsubfp",
+ VMAXFP: "vmaxfp",
+ VMINFP: "vminfp",
+ VCTSXS: "vctsxs",
+ VCTUXS: "vctuxs",
+ VCFSX: "vcfsx",
+ VCFUX: "vcfux",
+ VRFIM: "vrfim",
+ VRFIN: "vrfin",
+ VRFIP: "vrfip",
+ VRFIZ: "vrfiz",
+ VCMPBFP: "vcmpbfp",
+ VCMPBFP_: "vcmpbfp.",
+ VCMPEQFP: "vcmpeqfp",
+ VCMPEQFP_: "vcmpeqfp.",
+ VCMPGEFP: "vcmpgefp",
+ VCMPGEFP_: "vcmpgefp.",
+ VCMPGTFP: "vcmpgtfp",
+ VCMPGTFP_: "vcmpgtfp.",
+ VEXPTEFP: "vexptefp",
+ VLOGEFP: "vlogefp",
+ VREFP: "vrefp",
+ VRSQRTEFP: "vrsqrtefp",
+ VCIPHER: "vcipher",
+ VCIPHERLAST: "vcipherlast",
+ VNCIPHER: "vncipher",
+ VNCIPHERLAST: "vncipherlast",
+ VSBOX: "vsbox",
+ VSHASIGMAD: "vshasigmad",
+ VSHASIGMAW: "vshasigmaw",
+ VPMSUMB: "vpmsumb",
+ VPMSUMD: "vpmsumd",
+ VPMSUMH: "vpmsumh",
+ VPMSUMW: "vpmsumw",
+ VPERMXOR: "vpermxor",
+ VGBBD: "vgbbd",
+ VCLZB: "vclzb",
+ VCLZH: "vclzh",
+ VCLZW: "vclzw",
+ VCLZD: "vclzd",
+ VPOPCNTB: "vpopcntb",
+ VPOPCNTD: "vpopcntd",
+ VPOPCNTH: "vpopcnth",
+ VPOPCNTW: "vpopcntw",
+ VBPERMQ: "vbpermq",
+ BCDADD_: "bcdadd.",
+ BCDSUB_: "bcdsub.",
+ MTVSCR: "mtvscr",
+ MFVSCR: "mfvscr",
+ DADD: "dadd",
+ DADD_: "dadd.",
+ DSUB: "dsub",
+ DSUB_: "dsub.",
+ DMUL: "dmul",
+ DMUL_: "dmul.",
+ DDIV: "ddiv",
+ DDIV_: "ddiv.",
+ DCMPU: "dcmpu",
+ DCMPO: "dcmpo",
+ DTSTDC: "dtstdc",
+ DTSTDG: "dtstdg",
+ DTSTEX: "dtstex",
+ DTSTSF: "dtstsf",
+ DQUAI: "dquai",
+ DQUAI_: "dquai.",
+ DQUA: "dqua",
+ DQUA_: "dqua.",
+ DRRND: "drrnd",
+ DRRND_: "drrnd.",
+ DRINTX: "drintx",
+ DRINTX_: "drintx.",
+ DRINTN: "drintn",
+ DRINTN_: "drintn.",
+ DCTDP: "dctdp",
+ DCTDP_: "dctdp.",
+ DCTQPQ: "dctqpq",
+ DCTQPQ_: "dctqpq.",
+ DRSP: "drsp",
+ DRSP_: "drsp.",
+ DRDPQ: "drdpq",
+ DRDPQ_: "drdpq.",
+ DCFFIX: "dcffix",
+ DCFFIX_: "dcffix.",
+ DCFFIXQ: "dcffixq",
+ DCFFIXQ_: "dcffixq.",
+ DCTFIX: "dctfix",
+ DCTFIX_: "dctfix.",
+ DDEDPD: "ddedpd",
+ DDEDPD_: "ddedpd.",
+ DENBCD: "denbcd",
+ DENBCD_: "denbcd.",
+ DXEX: "dxex",
+ DXEX_: "dxex.",
+ DIEX: "diex",
+ DIEX_: "diex.",
+ DSCLI: "dscli",
+ DSCLI_: "dscli.",
+ DSCRI: "dscri",
+ DSCRI_: "dscri.",
+ LXSDX: "lxsdx",
+ LXSIWAX: "lxsiwax",
+ LXSIWZX: "lxsiwzx",
+ LXSSPX: "lxsspx",
+ LXVD2X: "lxvd2x",
+ LXVDSX: "lxvdsx",
+ LXVW4X: "lxvw4x",
+ STXSDX: "stxsdx",
+ STXSIWX: "stxsiwx",
+ STXSSPX: "stxsspx",
+ STXVD2X: "stxvd2x",
+ STXVW4X: "stxvw4x",
+ XSABSDP: "xsabsdp",
+ XSADDDP: "xsadddp",
+ XSADDSP: "xsaddsp",
+ XSCMPODP: "xscmpodp",
+ XSCMPUDP: "xscmpudp",
+ XSCPSGNDP: "xscpsgndp",
+ XSCVDPSP: "xscvdpsp",
+ XSCVDPSPN: "xscvdpspn",
+ XSCVDPSXDS: "xscvdpsxds",
+ XSCVDPSXWS: "xscvdpsxws",
+ XSCVDPUXDS: "xscvdpuxds",
+ XSCVDPUXWS: "xscvdpuxws",
+ XSCVSPDP: "xscvspdp",
+ XSCVSPDPN: "xscvspdpn",
+ XSCVSXDDP: "xscvsxddp",
+ XSCVSXDSP: "xscvsxdsp",
+ XSCVUXDDP: "xscvuxddp",
+ XSCVUXDSP: "xscvuxdsp",
+ XSDIVDP: "xsdivdp",
+ XSDIVSP: "xsdivsp",
+ XSMADDADP: "xsmaddadp",
+ XSMADDASP: "xsmaddasp",
+ XSMAXDP: "xsmaxdp",
+ XSMINDP: "xsmindp",
+ XSMSUBADP: "xsmsubadp",
+ XSMSUBASP: "xsmsubasp",
+ XSMULDP: "xsmuldp",
+ XSMULSP: "xsmulsp",
+ XSNABSDP: "xsnabsdp",
+ XSNEGDP: "xsnegdp",
+ XSNMADDADP: "xsnmaddadp",
+ XSNMADDASP: "xsnmaddasp",
+ XSNMSUBADP: "xsnmsubadp",
+ XSNMSUBASP: "xsnmsubasp",
+ XSRDPI: "xsrdpi",
+ XSRDPIC: "xsrdpic",
+ XSRDPIM: "xsrdpim",
+ XSRDPIP: "xsrdpip",
+ XSRDPIZ: "xsrdpiz",
+ XSREDP: "xsredp",
+ XSRESP: "xsresp",
+ XSRSP: "xsrsp",
+ XSRSQRTEDP: "xsrsqrtedp",
+ XSRSQRTESP: "xsrsqrtesp",
+ XSSQRTDP: "xssqrtdp",
+ XSSQRTSP: "xssqrtsp",
+ XSSUBDP: "xssubdp",
+ XSSUBSP: "xssubsp",
+ XSTDIVDP: "xstdivdp",
+ XSTSQRTDP: "xstsqrtdp",
+ XVABSDP: "xvabsdp",
+ XVABSSP: "xvabssp",
+ XVADDDP: "xvadddp",
+ XVADDSP: "xvaddsp",
+ XVCMPEQDP: "xvcmpeqdp",
+ XVCMPEQDP_: "xvcmpeqdp.",
+ XVCMPEQSP: "xvcmpeqsp",
+ XVCMPEQSP_: "xvcmpeqsp.",
+ XVCMPGEDP: "xvcmpgedp",
+ XVCMPGEDP_: "xvcmpgedp.",
+ XVCMPGESP: "xvcmpgesp",
+ XVCMPGESP_: "xvcmpgesp.",
+ XVCMPGTDP: "xvcmpgtdp",
+ XVCMPGTDP_: "xvcmpgtdp.",
+ XVCMPGTSP: "xvcmpgtsp",
+ XVCMPGTSP_: "xvcmpgtsp.",
+ XVCPSGNDP: "xvcpsgndp",
+ XVCPSGNSP: "xvcpsgnsp",
+ XVCVDPSP: "xvcvdpsp",
+ XVCVDPSXDS: "xvcvdpsxds",
+ XVCVDPSXWS: "xvcvdpsxws",
+ XVCVDPUXDS: "xvcvdpuxds",
+ XVCVDPUXWS: "xvcvdpuxws",
+ XVCVSPDP: "xvcvspdp",
+ XVCVSPSXDS: "xvcvspsxds",
+ XVCVSPSXWS: "xvcvspsxws",
+ XVCVSPUXDS: "xvcvspuxds",
+ XVCVSPUXWS: "xvcvspuxws",
+ XVCVSXDDP: "xvcvsxddp",
+ XVCVSXDSP: "xvcvsxdsp",
+ XVCVSXWDP: "xvcvsxwdp",
+ XVCVSXWSP: "xvcvsxwsp",
+ XVCVUXDDP: "xvcvuxddp",
+ XVCVUXDSP: "xvcvuxdsp",
+ XVCVUXWDP: "xvcvuxwdp",
+ XVCVUXWSP: "xvcvuxwsp",
+ XVDIVDP: "xvdivdp",
+ XVDIVSP: "xvdivsp",
+ XVMADDADP: "xvmaddadp",
+ XVMADDASP: "xvmaddasp",
+ XVMAXDP: "xvmaxdp",
+ XVMAXSP: "xvmaxsp",
+ XVMINDP: "xvmindp",
+ XVMINSP: "xvminsp",
+ XVMSUBADP: "xvmsubadp",
+ XVMSUBASP: "xvmsubasp",
+ XVMULDP: "xvmuldp",
+ XVMULSP: "xvmulsp",
+ XVNABSDP: "xvnabsdp",
+ XVNABSSP: "xvnabssp",
+ XVNEGDP: "xvnegdp",
+ XVNEGSP: "xvnegsp",
+ XVNMADDADP: "xvnmaddadp",
+ XVNMADDASP: "xvnmaddasp",
+ XVNMSUBADP: "xvnmsubadp",
+ XVNMSUBASP: "xvnmsubasp",
+ XVRDPI: "xvrdpi",
+ XVRDPIC: "xvrdpic",
+ XVRDPIM: "xvrdpim",
+ XVRDPIP: "xvrdpip",
+ XVRDPIZ: "xvrdpiz",
+ XVREDP: "xvredp",
+ XVRESP: "xvresp",
+ XVRSPI: "xvrspi",
+ XVRSPIC: "xvrspic",
+ XVRSPIM: "xvrspim",
+ XVRSPIP: "xvrspip",
+ XVRSPIZ: "xvrspiz",
+ XVRSQRTEDP: "xvrsqrtedp",
+ XVRSQRTESP: "xvrsqrtesp",
+ XVSQRTDP: "xvsqrtdp",
+ XVSQRTSP: "xvsqrtsp",
+ XVSUBDP: "xvsubdp",
+ XVSUBSP: "xvsubsp",
+ XVTDIVDP: "xvtdivdp",
+ XVTDIVSP: "xvtdivsp",
+ XVTSQRTDP: "xvtsqrtdp",
+ XVTSQRTSP: "xvtsqrtsp",
+ XXLAND: "xxland",
+ XXLANDC: "xxlandc",
+ XXLEQV: "xxleqv",
+ XXLNAND: "xxlnand",
+ XXLORC: "xxlorc",
+ XXLNOR: "xxlnor",
+ XXLOR: "xxlor",
+ XXLXOR: "xxlxor",
+ XXMRGHW: "xxmrghw",
+ XXMRGLW: "xxmrglw",
+ XXPERMDI: "xxpermdi",
+ XXSEL: "xxsel",
+ XXSLDWI: "xxsldwi",
+ XXSPLTW: "xxspltw",
+ BRINC: "brinc",
+ EVABS: "evabs",
+ EVADDIW: "evaddiw",
+ EVADDSMIAAW: "evaddsmiaaw",
+ EVADDSSIAAW: "evaddssiaaw",
+ EVADDUMIAAW: "evaddumiaaw",
+ EVADDUSIAAW: "evaddusiaaw",
+ EVADDW: "evaddw",
+ EVAND: "evand",
+ EVCMPEQ: "evcmpeq",
+ EVANDC: "evandc",
+ EVCMPGTS: "evcmpgts",
+ EVCMPGTU: "evcmpgtu",
+ EVCMPLTU: "evcmpltu",
+ EVCMPLTS: "evcmplts",
+ EVCNTLSW: "evcntlsw",
+ EVCNTLZW: "evcntlzw",
+ EVDIVWS: "evdivws",
+ EVDIVWU: "evdivwu",
+ EVEQV: "eveqv",
+ EVEXTSB: "evextsb",
+ EVEXTSH: "evextsh",
+ EVLDD: "evldd",
+ EVLDH: "evldh",
+ EVLDDX: "evlddx",
+ EVLDHX: "evldhx",
+ EVLDW: "evldw",
+ EVLHHESPLAT: "evlhhesplat",
+ EVLDWX: "evldwx",
+ EVLHHESPLATX: "evlhhesplatx",
+ EVLHHOSSPLAT: "evlhhossplat",
+ EVLHHOUSPLAT: "evlhhousplat",
+ EVLHHOSSPLATX: "evlhhossplatx",
+ EVLHHOUSPLATX: "evlhhousplatx",
+ EVLWHE: "evlwhe",
+ EVLWHOS: "evlwhos",
+ EVLWHEX: "evlwhex",
+ EVLWHOSX: "evlwhosx",
+ EVLWHOU: "evlwhou",
+ EVLWHSPLAT: "evlwhsplat",
+ EVLWHOUX: "evlwhoux",
+ EVLWHSPLATX: "evlwhsplatx",
+ EVLWWSPLAT: "evlwwsplat",
+ EVMERGEHI: "evmergehi",
+ EVLWWSPLATX: "evlwwsplatx",
+ EVMERGELO: "evmergelo",
+ EVMERGEHILO: "evmergehilo",
+ EVMHEGSMFAA: "evmhegsmfaa",
+ EVMERGELOHI: "evmergelohi",
+ EVMHEGSMFAN: "evmhegsmfan",
+ EVMHEGSMIAA: "evmhegsmiaa",
+ EVMHEGUMIAA: "evmhegumiaa",
+ EVMHEGSMIAN: "evmhegsmian",
+ EVMHEGUMIAN: "evmhegumian",
+ EVMHESMF: "evmhesmf",
+ EVMHESMFAAW: "evmhesmfaaw",
+ EVMHESMFA: "evmhesmfa",
+ EVMHESMFANW: "evmhesmfanw",
+ EVMHESMI: "evmhesmi",
+ EVMHESMIAAW: "evmhesmiaaw",
+ EVMHESMIA: "evmhesmia",
+ EVMHESMIANW: "evmhesmianw",
+ EVMHESSF: "evmhessf",
+ EVMHESSFA: "evmhessfa",
+ EVMHESSFAAW: "evmhessfaaw",
+ EVMHESSFANW: "evmhessfanw",
+ EVMHESSIAAW: "evmhessiaaw",
+ EVMHESSIANW: "evmhessianw",
+ EVMHEUMI: "evmheumi",
+ EVMHEUMIAAW: "evmheumiaaw",
+ EVMHEUMIA: "evmheumia",
+ EVMHEUMIANW: "evmheumianw",
+ EVMHEUSIAAW: "evmheusiaaw",
+ EVMHEUSIANW: "evmheusianw",
+ EVMHOGSMFAA: "evmhogsmfaa",
+ EVMHOGSMIAA: "evmhogsmiaa",
+ EVMHOGSMFAN: "evmhogsmfan",
+ EVMHOGSMIAN: "evmhogsmian",
+ EVMHOGUMIAA: "evmhogumiaa",
+ EVMHOSMF: "evmhosmf",
+ EVMHOGUMIAN: "evmhogumian",
+ EVMHOSMFA: "evmhosmfa",
+ EVMHOSMFAAW: "evmhosmfaaw",
+ EVMHOSMI: "evmhosmi",
+ EVMHOSMFANW: "evmhosmfanw",
+ EVMHOSMIA: "evmhosmia",
+ EVMHOSMIAAW: "evmhosmiaaw",
+ EVMHOSMIANW: "evmhosmianw",
+ EVMHOSSF: "evmhossf",
+ EVMHOSSFA: "evmhossfa",
+ EVMHOSSFAAW: "evmhossfaaw",
+ EVMHOSSFANW: "evmhossfanw",
+ EVMHOSSIAAW: "evmhossiaaw",
+ EVMHOUMI: "evmhoumi",
+ EVMHOSSIANW: "evmhossianw",
+ EVMHOUMIA: "evmhoumia",
+ EVMHOUMIAAW: "evmhoumiaaw",
+ EVMHOUSIAAW: "evmhousiaaw",
+ EVMHOUMIANW: "evmhoumianw",
+ EVMHOUSIANW: "evmhousianw",
+ EVMRA: "evmra",
+ EVMWHSMF: "evmwhsmf",
+ EVMWHSMI: "evmwhsmi",
+ EVMWHSMFA: "evmwhsmfa",
+ EVMWHSMIA: "evmwhsmia",
+ EVMWHSSF: "evmwhssf",
+ EVMWHUMI: "evmwhumi",
+ EVMWHSSFA: "evmwhssfa",
+ EVMWHUMIA: "evmwhumia",
+ EVMWLSMIAAW: "evmwlsmiaaw",
+ EVMWLSSIAAW: "evmwlssiaaw",
+ EVMWLSMIANW: "evmwlsmianw",
+ EVMWLSSIANW: "evmwlssianw",
+ EVMWLUMI: "evmwlumi",
+ EVMWLUMIAAW: "evmwlumiaaw",
+ EVMWLUMIA: "evmwlumia",
+ EVMWLUMIANW: "evmwlumianw",
+ EVMWLUSIAAW: "evmwlusiaaw",
+ EVMWSMF: "evmwsmf",
+ EVMWLUSIANW: "evmwlusianw",
+ EVMWSMFA: "evmwsmfa",
+ EVMWSMFAA: "evmwsmfaa",
+ EVMWSMI: "evmwsmi",
+ EVMWSMIAA: "evmwsmiaa",
+ EVMWSMFAN: "evmwsmfan",
+ EVMWSMIA: "evmwsmia",
+ EVMWSMIAN: "evmwsmian",
+ EVMWSSF: "evmwssf",
+ EVMWSSFA: "evmwssfa",
+ EVMWSSFAA: "evmwssfaa",
+ EVMWUMI: "evmwumi",
+ EVMWSSFAN: "evmwssfan",
+ EVMWUMIA: "evmwumia",
+ EVMWUMIAA: "evmwumiaa",
+ EVNAND: "evnand",
+ EVMWUMIAN: "evmwumian",
+ EVNEG: "evneg",
+ EVNOR: "evnor",
+ EVORC: "evorc",
+ EVOR: "evor",
+ EVRLW: "evrlw",
+ EVRLWI: "evrlwi",
+ EVSEL: "evsel",
+ EVRNDW: "evrndw",
+ EVSLW: "evslw",
+ EVSPLATFI: "evsplatfi",
+ EVSRWIS: "evsrwis",
+ EVSLWI: "evslwi",
+ EVSPLATI: "evsplati",
+ EVSRWIU: "evsrwiu",
+ EVSRWS: "evsrws",
+ EVSTDD: "evstdd",
+ EVSRWU: "evsrwu",
+ EVSTDDX: "evstddx",
+ EVSTDH: "evstdh",
+ EVSTDW: "evstdw",
+ EVSTDHX: "evstdhx",
+ EVSTDWX: "evstdwx",
+ EVSTWHE: "evstwhe",
+ EVSTWHO: "evstwho",
+ EVSTWWE: "evstwwe",
+ EVSTWHEX: "evstwhex",
+ EVSTWHOX: "evstwhox",
+ EVSTWWEX: "evstwwex",
+ EVSTWWO: "evstwwo",
+ EVSUBFSMIAAW: "evsubfsmiaaw",
+ EVSTWWOX: "evstwwox",
+ EVSUBFSSIAAW: "evsubfssiaaw",
+ EVSUBFUMIAAW: "evsubfumiaaw",
+ EVSUBFUSIAAW: "evsubfusiaaw",
+ EVSUBFW: "evsubfw",
+ EVSUBIFW: "evsubifw",
+ EVXOR: "evxor",
+ EVFSABS: "evfsabs",
+ EVFSNABS: "evfsnabs",
+ EVFSNEG: "evfsneg",
+ EVFSADD: "evfsadd",
+ EVFSMUL: "evfsmul",
+ EVFSSUB: "evfssub",
+ EVFSDIV: "evfsdiv",
+ EVFSCMPGT: "evfscmpgt",
+ EVFSCMPLT: "evfscmplt",
+ EVFSCMPEQ: "evfscmpeq",
+ EVFSTSTGT: "evfststgt",
+ EVFSTSTLT: "evfststlt",
+ EVFSTSTEQ: "evfststeq",
+ EVFSCFSI: "evfscfsi",
+ EVFSCFSF: "evfscfsf",
+ EVFSCFUI: "evfscfui",
+ EVFSCFUF: "evfscfuf",
+ EVFSCTSI: "evfsctsi",
+ EVFSCTUI: "evfsctui",
+ EVFSCTSIZ: "evfsctsiz",
+ EVFSCTUIZ: "evfsctuiz",
+ EVFSCTSF: "evfsctsf",
+ EVFSCTUF: "evfsctuf",
+ EFSABS: "efsabs",
+ EFSNEG: "efsneg",
+ EFSNABS: "efsnabs",
+ EFSADD: "efsadd",
+ EFSMUL: "efsmul",
+ EFSSUB: "efssub",
+ EFSDIV: "efsdiv",
+ EFSCMPGT: "efscmpgt",
+ EFSCMPLT: "efscmplt",
+ EFSCMPEQ: "efscmpeq",
+ EFSTSTGT: "efststgt",
+ EFSTSTLT: "efststlt",
+ EFSTSTEQ: "efststeq",
+ EFSCFSI: "efscfsi",
+ EFSCFSF: "efscfsf",
+ EFSCTSI: "efsctsi",
+ EFSCFUI: "efscfui",
+ EFSCFUF: "efscfuf",
+ EFSCTUI: "efsctui",
+ EFSCTSIZ: "efsctsiz",
+ EFSCTSF: "efsctsf",
+ EFSCTUIZ: "efsctuiz",
+ EFSCTUF: "efsctuf",
+ EFDABS: "efdabs",
+ EFDNEG: "efdneg",
+ EFDNABS: "efdnabs",
+ EFDADD: "efdadd",
+ EFDMUL: "efdmul",
+ EFDSUB: "efdsub",
+ EFDDIV: "efddiv",
+ EFDCMPGT: "efdcmpgt",
+ EFDCMPEQ: "efdcmpeq",
+ EFDCMPLT: "efdcmplt",
+ EFDTSTGT: "efdtstgt",
+ EFDTSTLT: "efdtstlt",
+ EFDCFSI: "efdcfsi",
+ EFDTSTEQ: "efdtsteq",
+ EFDCFUI: "efdcfui",
+ EFDCFSID: "efdcfsid",
+ EFDCFSF: "efdcfsf",
+ EFDCFUF: "efdcfuf",
+ EFDCFUID: "efdcfuid",
+ EFDCTSI: "efdctsi",
+ EFDCTUI: "efdctui",
+ EFDCTSIDZ: "efdctsidz",
+ EFDCTUIDZ: "efdctuidz",
+ EFDCTSIZ: "efdctsiz",
+ EFDCTSF: "efdctsf",
+ EFDCTUF: "efdctuf",
+ EFDCTUIZ: "efdctuiz",
+ EFDCFS: "efdcfs",
+ EFSCFD: "efscfd",
+ DLMZB: "dlmzb",
+ DLMZB_: "dlmzb.",
+ MACCHW: "macchw",
+ MACCHW_: "macchw.",
+ MACCHWO: "macchwo",
+ MACCHWO_: "macchwo.",
+ MACCHWS: "macchws",
+ MACCHWS_: "macchws.",
+ MACCHWSO: "macchwso",
+ MACCHWSO_: "macchwso.",
+ MACCHWU: "macchwu",
+ MACCHWU_: "macchwu.",
+ MACCHWUO: "macchwuo",
+ MACCHWUO_: "macchwuo.",
+ MACCHWSU: "macchwsu",
+ MACCHWSU_: "macchwsu.",
+ MACCHWSUO: "macchwsuo",
+ MACCHWSUO_: "macchwsuo.",
+ MACHHW: "machhw",
+ MACHHW_: "machhw.",
+ MACHHWO: "machhwo",
+ MACHHWO_: "machhwo.",
+ MACHHWS: "machhws",
+ MACHHWS_: "machhws.",
+ MACHHWSO: "machhwso",
+ MACHHWSO_: "machhwso.",
+ MACHHWU: "machhwu",
+ MACHHWU_: "machhwu.",
+ MACHHWUO: "machhwuo",
+ MACHHWUO_: "machhwuo.",
+ MACHHWSU: "machhwsu",
+ MACHHWSU_: "machhwsu.",
+ MACHHWSUO: "machhwsuo",
+ MACHHWSUO_: "machhwsuo.",
+ MACLHW: "maclhw",
+ MACLHW_: "maclhw.",
+ MACLHWO: "maclhwo",
+ MACLHWO_: "maclhwo.",
+ MACLHWS: "maclhws",
+ MACLHWS_: "maclhws.",
+ MACLHWSO: "maclhwso",
+ MACLHWSO_: "maclhwso.",
+ MACLHWU: "maclhwu",
+ MACLHWU_: "maclhwu.",
+ MACLHWUO: "maclhwuo",
+ MACLHWUO_: "maclhwuo.",
+ MULCHW: "mulchw",
+ MULCHW_: "mulchw.",
+ MACLHWSU: "maclhwsu",
+ MACLHWSU_: "maclhwsu.",
+ MACLHWSUO: "maclhwsuo",
+ MACLHWSUO_: "maclhwsuo.",
+ MULCHWU: "mulchwu",
+ MULCHWU_: "mulchwu.",
+ MULHHW: "mulhhw",
+ MULHHW_: "mulhhw.",
+ MULLHW: "mullhw",
+ MULLHW_: "mullhw.",
+ MULHHWU: "mulhhwu",
+ MULHHWU_: "mulhhwu.",
+ MULLHWU: "mullhwu",
+ MULLHWU_: "mullhwu.",
+ NMACCHW: "nmacchw",
+ NMACCHW_: "nmacchw.",
+ NMACCHWO: "nmacchwo",
+ NMACCHWO_: "nmacchwo.",
+ NMACCHWS: "nmacchws",
+ NMACCHWS_: "nmacchws.",
+ NMACCHWSO: "nmacchwso",
+ NMACCHWSO_: "nmacchwso.",
+ NMACHHW: "nmachhw",
+ NMACHHW_: "nmachhw.",
+ NMACHHWO: "nmachhwo",
+ NMACHHWO_: "nmachhwo.",
+ NMACHHWS: "nmachhws",
+ NMACHHWS_: "nmachhws.",
+ NMACHHWSO: "nmachhwso",
+ NMACHHWSO_: "nmachhwso.",
+ NMACLHW: "nmaclhw",
+ NMACLHW_: "nmaclhw.",
+ NMACLHWO: "nmaclhwo",
+ NMACLHWO_: "nmaclhwo.",
+ NMACLHWS: "nmaclhws",
+ NMACLHWS_: "nmaclhws.",
+ NMACLHWSO: "nmaclhwso",
+ NMACLHWSO_: "nmaclhwso.",
+ ICBI: "icbi",
+ ICBT: "icbt",
+ DCBA: "dcba",
+ DCBT: "dcbt",
+ DCBTST: "dcbtst",
+ DCBZ: "dcbz",
+ DCBST: "dcbst",
+ DCBF: "dcbf",
+ ISYNC: "isync",
+ LBARX: "lbarx",
+ LHARX: "lharx",
+ LWARX: "lwarx",
+ STBCX_: "stbcx.",
+ STHCX_: "sthcx.",
+ STWCX_: "stwcx.",
+ LDARX: "ldarx",
+ STDCX_: "stdcx.",
+ LQARX: "lqarx",
+ STQCX_: "stqcx.",
+ SYNC: "sync",
+ EIEIO: "eieio",
+ MBAR: "mbar",
+ WAIT: "wait",
+ TBEGIN_: "tbegin.",
+ TEND_: "tend.",
+ TABORT_: "tabort.",
+ TABORTWC_: "tabortwc.",
+ TABORTWCI_: "tabortwci.",
+ TABORTDC_: "tabortdc.",
+ TABORTDCI_: "tabortdci.",
+ TSR_: "tsr.",
+ TCHECK: "tcheck",
+ MFTB: "mftb",
+ RFEBB: "rfebb",
+ LBDX: "lbdx",
+ LHDX: "lhdx",
+ LWDX: "lwdx",
+ LDDX: "lddx",
+ LFDDX: "lfddx",
+ STBDX: "stbdx",
+ STHDX: "sthdx",
+ STWDX: "stwdx",
+ STDDX: "stddx",
+ STFDDX: "stfddx",
+ DSN: "dsn",
+ ECIWX: "eciwx",
+ ECOWX: "ecowx",
+ RFID: "rfid",
+ HRFID: "hrfid",
+ DOZE: "doze",
+ NAP: "nap",
+ SLEEP: "sleep",
+ RVWINKLE: "rvwinkle",
+ LBZCIX: "lbzcix",
+ LWZCIX: "lwzcix",
+ LHZCIX: "lhzcix",
+ LDCIX: "ldcix",
+ STBCIX: "stbcix",
+ STWCIX: "stwcix",
+ STHCIX: "sthcix",
+ STDCIX: "stdcix",
+ TRECLAIM_: "treclaim.",
+ TRECHKPT_: "trechkpt.",
+ MTMSR: "mtmsr",
+ MTMSRD: "mtmsrd",
+ MFMSR: "mfmsr",
+ SLBIE: "slbie",
+ SLBIA: "slbia",
+ SLBMTE: "slbmte",
+ SLBMFEV: "slbmfev",
+ SLBMFEE: "slbmfee",
+ SLBFEE_: "slbfee.",
+ MTSR: "mtsr",
+ MTSRIN: "mtsrin",
+ MFSR: "mfsr",
+ MFSRIN: "mfsrin",
+ TLBIE: "tlbie",
+ TLBIEL: "tlbiel",
+ TLBIA: "tlbia",
+ TLBSYNC: "tlbsync",
+ MSGSND: "msgsnd",
+ MSGCLR: "msgclr",
+ MSGSNDP: "msgsndp",
+ MSGCLRP: "msgclrp",
+ MTTMR: "mttmr",
+ RFI: "rfi",
+ RFCI: "rfci",
+ RFDI: "rfdi",
+ RFMCI: "rfmci",
+ RFGI: "rfgi",
+ EHPRIV: "ehpriv",
+ MTDCR: "mtdcr",
+ MTDCRX: "mtdcrx",
+ MFDCR: "mfdcr",
+ MFDCRX: "mfdcrx",
+ WRTEE: "wrtee",
+ WRTEEI: "wrteei",
+ LBEPX: "lbepx",
+ LHEPX: "lhepx",
+ LWEPX: "lwepx",
+ LDEPX: "ldepx",
+ STBEPX: "stbepx",
+ STHEPX: "sthepx",
+ STWEPX: "stwepx",
+ STDEPX: "stdepx",
+ DCBSTEP: "dcbstep",
+ DCBTEP: "dcbtep",
+ DCBFEP: "dcbfep",
+ DCBTSTEP: "dcbtstep",
+ ICBIEP: "icbiep",
+ DCBZEP: "dcbzep",
+ LFDEPX: "lfdepx",
+ STFDEPX: "stfdepx",
+ EVLDDEPX: "evlddepx",
+ EVSTDDEPX: "evstddepx",
+ LVEPX: "lvepx",
+ LVEPXL: "lvepxl",
+ STVEPX: "stvepx",
+ STVEPXL: "stvepxl",
+ DCBI: "dcbi",
+ DCBLQ_: "dcblq.",
+ ICBLQ_: "icblq.",
+ DCBTLS: "dcbtls",
+ DCBTSTLS: "dcbtstls",
+ ICBTLS: "icbtls",
+ ICBLC: "icblc",
+ DCBLC: "dcblc",
+ TLBIVAX: "tlbivax",
+ TLBILX: "tlbilx",
+ TLBSX: "tlbsx",
+ TLBSRX_: "tlbsrx.",
+ TLBRE: "tlbre",
+ TLBWE: "tlbwe",
+ DNH: "dnh",
+ DCI: "dci",
+ ICI: "ici",
+ DCREAD: "dcread",
+ ICREAD: "icread",
+ MFPMR: "mfpmr",
+ MTPMR: "mtpmr",
+}
+
+var (
+ ap_Reg_11_15 = &argField{Type: TypeReg, Shift: 0, BitFields: BitFields{{11, 5}}}
+ ap_Reg_6_10 = &argField{Type: TypeReg, Shift: 0, BitFields: BitFields{{6, 5}}}
+ ap_PCRel_6_29_shift2 = &argField{Type: TypePCRel, Shift: 2, BitFields: BitFields{{6, 24}}}
+ ap_Label_6_29_shift2 = &argField{Type: TypeLabel, Shift: 2, BitFields: BitFields{{6, 24}}}
+ ap_ImmUnsigned_6_10 = &argField{Type: TypeImmUnsigned, Shift: 0, BitFields: BitFields{{6, 5}}}
+ ap_CondRegBit_11_15 = &argField{Type: TypeCondRegBit, Shift: 0, BitFields: BitFields{{11, 5}}}
+ ap_PCRel_16_29_shift2 = &argField{Type: TypePCRel, Shift: 2, BitFields: BitFields{{16, 14}}}
+ ap_Label_16_29_shift2 = &argField{Type: TypeLabel, Shift: 2, BitFields: BitFields{{16, 14}}}
+ ap_ImmUnsigned_19_20 = &argField{Type: TypeImmUnsigned, Shift: 0, BitFields: BitFields{{19, 2}}}
+ ap_CondRegBit_6_10 = &argField{Type: TypeCondRegBit, Shift: 0, BitFields: BitFields{{6, 5}}}
+ ap_CondRegBit_16_20 = &argField{Type: TypeCondRegBit, Shift: 0, BitFields: BitFields{{16, 5}}}
+ ap_CondRegField_6_8 = &argField{Type: TypeCondRegField, Shift: 0, BitFields: BitFields{{6, 3}}}
+ ap_CondRegField_11_13 = &argField{Type: TypeCondRegField, Shift: 0, BitFields: BitFields{{11, 3}}}
+ ap_ImmUnsigned_20_26 = &argField{Type: TypeImmUnsigned, Shift: 0, BitFields: BitFields{{20, 7}}}
+ ap_SpReg_11_20 = &argField{Type: TypeSpReg, Shift: 0, BitFields: BitFields{{11, 10}}}
+ ap_Offset_16_31 = &argField{Type: TypeOffset, Shift: 0, BitFields: BitFields{{16, 16}}}
+ ap_Reg_16_20 = &argField{Type: TypeReg, Shift: 0, BitFields: BitFields{{16, 5}}}
+ ap_Offset_16_29_shift2 = &argField{Type: TypeOffset, Shift: 2, BitFields: BitFields{{16, 14}}}
+ ap_Offset_16_27_shift4 = &argField{Type: TypeOffset, Shift: 4, BitFields: BitFields{{16, 12}}}
+ ap_ImmUnsigned_16_20 = &argField{Type: TypeImmUnsigned, Shift: 0, BitFields: BitFields{{16, 5}}}
+ ap_ImmSigned_16_31 = &argField{Type: TypeImmSigned, Shift: 0, BitFields: BitFields{{16, 16}}}
+ ap_ImmUnsigned_16_31 = &argField{Type: TypeImmUnsigned, Shift: 0, BitFields: BitFields{{16, 16}}}
+ ap_CondRegBit_21_25 = &argField{Type: TypeCondRegBit, Shift: 0, BitFields: BitFields{{21, 5}}}
+ ap_ImmUnsigned_21_25 = &argField{Type: TypeImmUnsigned, Shift: 0, BitFields: BitFields{{21, 5}}}
+ ap_ImmUnsigned_26_30 = &argField{Type: TypeImmUnsigned, Shift: 0, BitFields: BitFields{{26, 5}}}
+ ap_ImmUnsigned_30_30_16_20 = &argField{Type: TypeImmUnsigned, Shift: 0, BitFields: BitFields{{30, 1}, {16, 5}}}
+ ap_ImmUnsigned_26_26_21_25 = &argField{Type: TypeImmUnsigned, Shift: 0, BitFields: BitFields{{26, 1}, {21, 5}}}
+ ap_SpReg_16_20_11_15 = &argField{Type: TypeSpReg, Shift: 0, BitFields: BitFields{{16, 5}, {11, 5}}}
+ ap_ImmUnsigned_12_19 = &argField{Type: TypeImmUnsigned, Shift: 0, BitFields: BitFields{{12, 8}}}
+ ap_ImmUnsigned_10_10 = &argField{Type: TypeImmUnsigned, Shift: 0, BitFields: BitFields{{10, 1}}}
+ ap_VecSReg_31_31_6_10 = &argField{Type: TypeVecSReg, Shift: 0, BitFields: BitFields{{31, 1}, {6, 5}}}
+ ap_FPReg_6_10 = &argField{Type: TypeFPReg, Shift: 0, BitFields: BitFields{{6, 5}}}
+ ap_FPReg_16_20 = &argField{Type: TypeFPReg, Shift: 0, BitFields: BitFields{{16, 5}}}
+ ap_FPReg_11_15 = &argField{Type: TypeFPReg, Shift: 0, BitFields: BitFields{{11, 5}}}
+ ap_FPReg_21_25 = &argField{Type: TypeFPReg, Shift: 0, BitFields: BitFields{{21, 5}}}
+ ap_ImmUnsigned_16_19 = &argField{Type: TypeImmUnsigned, Shift: 0, BitFields: BitFields{{16, 4}}}
+ ap_ImmUnsigned_15_15 = &argField{Type: TypeImmUnsigned, Shift: 0, BitFields: BitFields{{15, 1}}}
+ ap_ImmUnsigned_7_14 = &argField{Type: TypeImmUnsigned, Shift: 0, BitFields: BitFields{{7, 8}}}
+ ap_ImmUnsigned_6_6 = &argField{Type: TypeImmUnsigned, Shift: 0, BitFields: BitFields{{6, 1}}}
+ ap_VecReg_6_10 = &argField{Type: TypeVecReg, Shift: 0, BitFields: BitFields{{6, 5}}}
+ ap_VecReg_11_15 = &argField{Type: TypeVecReg, Shift: 0, BitFields: BitFields{{11, 5}}}
+ ap_VecReg_16_20 = &argField{Type: TypeVecReg, Shift: 0, BitFields: BitFields{{16, 5}}}
+ ap_ImmUnsigned_12_15 = &argField{Type: TypeImmUnsigned, Shift: 0, BitFields: BitFields{{12, 4}}}
+ ap_ImmUnsigned_13_15 = &argField{Type: TypeImmUnsigned, Shift: 0, BitFields: BitFields{{13, 3}}}
+ ap_ImmUnsigned_14_15 = &argField{Type: TypeImmUnsigned, Shift: 0, BitFields: BitFields{{14, 2}}}
+ ap_ImmSigned_11_15 = &argField{Type: TypeImmSigned, Shift: 0, BitFields: BitFields{{11, 5}}}
+ ap_VecReg_21_25 = &argField{Type: TypeVecReg, Shift: 0, BitFields: BitFields{{21, 5}}}
+ ap_ImmUnsigned_22_25 = &argField{Type: TypeImmUnsigned, Shift: 0, BitFields: BitFields{{22, 4}}}
+ ap_ImmUnsigned_11_15 = &argField{Type: TypeImmUnsigned, Shift: 0, BitFields: BitFields{{11, 5}}}
+ ap_ImmUnsigned_16_16 = &argField{Type: TypeImmUnsigned, Shift: 0, BitFields: BitFields{{16, 1}}}
+ ap_ImmUnsigned_17_20 = &argField{Type: TypeImmUnsigned, Shift: 0, BitFields: BitFields{{17, 4}}}
+ ap_ImmUnsigned_22_22 = &argField{Type: TypeImmUnsigned, Shift: 0, BitFields: BitFields{{22, 1}}}
+ ap_ImmUnsigned_16_21 = &argField{Type: TypeImmUnsigned, Shift: 0, BitFields: BitFields{{16, 6}}}
+ ap_ImmUnsigned_21_22 = &argField{Type: TypeImmUnsigned, Shift: 0, BitFields: BitFields{{21, 2}}}
+ ap_ImmUnsigned_11_12 = &argField{Type: TypeImmUnsigned, Shift: 0, BitFields: BitFields{{11, 2}}}
+ ap_ImmUnsigned_11_11 = &argField{Type: TypeImmUnsigned, Shift: 0, BitFields: BitFields{{11, 1}}}
+ ap_VecSReg_30_30_16_20 = &argField{Type: TypeVecSReg, Shift: 0, BitFields: BitFields{{30, 1}, {16, 5}}}
+ ap_VecSReg_29_29_11_15 = &argField{Type: TypeVecSReg, Shift: 0, BitFields: BitFields{{29, 1}, {11, 5}}}
+ ap_ImmUnsigned_22_23 = &argField{Type: TypeImmUnsigned, Shift: 0, BitFields: BitFields{{22, 2}}}
+ ap_VecSReg_28_28_21_25 = &argField{Type: TypeVecSReg, Shift: 0, BitFields: BitFields{{28, 1}, {21, 5}}}
+ ap_CondRegField_29_31 = &argField{Type: TypeCondRegField, Shift: 0, BitFields: BitFields{{29, 3}}}
+ ap_ImmUnsigned_7_10 = &argField{Type: TypeImmUnsigned, Shift: 0, BitFields: BitFields{{7, 4}}}
+ ap_ImmUnsigned_9_10 = &argField{Type: TypeImmUnsigned, Shift: 0, BitFields: BitFields{{9, 2}}}
+ ap_ImmUnsigned_31_31 = &argField{Type: TypeImmUnsigned, Shift: 0, BitFields: BitFields{{31, 1}}}
+ ap_ImmSigned_16_20 = &argField{Type: TypeImmSigned, Shift: 0, BitFields: BitFields{{16, 5}}}
+ ap_ImmUnsigned_20_20 = &argField{Type: TypeImmUnsigned, Shift: 0, BitFields: BitFields{{20, 1}}}
+ ap_ImmUnsigned_8_10 = &argField{Type: TypeImmUnsigned, Shift: 0, BitFields: BitFields{{8, 3}}}
+ ap_SpReg_12_15 = &argField{Type: TypeSpReg, Shift: 0, BitFields: BitFields{{12, 4}}}
+ ap_ImmUnsigned_6_20 = &argField{Type: TypeImmUnsigned, Shift: 0, BitFields: BitFields{{6, 15}}}
+ ap_ImmUnsigned_11_20 = &argField{Type: TypeImmUnsigned, Shift: 0, BitFields: BitFields{{11, 10}}}
+)
+
+var instFormats = [...]instFormat{
+ {CNTLZW, 0xfc0007ff, 0x7c000034, 0xf800, // Count Leading Zeros Word X-form (cntlzw RA, RS)
+ [5]*argField{ap_Reg_11_15, ap_Reg_6_10}},
+ {CNTLZW_, 0xfc0007ff, 0x7c000035, 0xf800, // Count Leading Zeros Word X-form (cntlzw. RA, RS)
+ [5]*argField{ap_Reg_11_15, ap_Reg_6_10}},
+ {B, 0xfc000003, 0x48000000, 0x0, // Branch I-form (b target_addr)
+ [5]*argField{ap_PCRel_6_29_shift2}},
+ {BA, 0xfc000003, 0x48000002, 0x0, // Branch I-form (ba target_addr)
+ [5]*argField{ap_Label_6_29_shift2}},
+ {BL, 0xfc000003, 0x48000001, 0x0, // Branch I-form (bl target_addr)
+ [5]*argField{ap_PCRel_6_29_shift2}},
+ {BLA, 0xfc000003, 0x48000003, 0x0, // Branch I-form (bla target_addr)
+ [5]*argField{ap_Label_6_29_shift2}},
+ {BC, 0xfc000003, 0x40000000, 0x0, // Branch Conditional B-form (bc BO,BI,target_addr)
+ [5]*argField{ap_ImmUnsigned_6_10, ap_CondRegBit_11_15, ap_PCRel_16_29_shift2}},
+ {BCA, 0xfc000003, 0x40000002, 0x0, // Branch Conditional B-form (bca BO,BI,target_addr)
+ [5]*argField{ap_ImmUnsigned_6_10, ap_CondRegBit_11_15, ap_Label_16_29_shift2}},
+ {BCL, 0xfc000003, 0x40000001, 0x0, // Branch Conditional B-form (bcl BO,BI,target_addr)
+ [5]*argField{ap_ImmUnsigned_6_10, ap_CondRegBit_11_15, ap_PCRel_16_29_shift2}},
+ {BCLA, 0xfc000003, 0x40000003, 0x0, // Branch Conditional B-form (bcla BO,BI,target_addr)
+ [5]*argField{ap_ImmUnsigned_6_10, ap_CondRegBit_11_15, ap_Label_16_29_shift2}},
+ {BCLR, 0xfc0007ff, 0x4c000020, 0xe000, // Branch Conditional to Link Register XL-form (bclr BO,BI,BH)
+ [5]*argField{ap_ImmUnsigned_6_10, ap_CondRegBit_11_15, ap_ImmUnsigned_19_20}},
+ {BCLRL, 0xfc0007ff, 0x4c000021, 0xe000, // Branch Conditional to Link Register XL-form (bclrl BO,BI,BH)
+ [5]*argField{ap_ImmUnsigned_6_10, ap_CondRegBit_11_15, ap_ImmUnsigned_19_20}},
+ {BCCTR, 0xfc0007ff, 0x4c000420, 0xe000, // Branch Conditional to Count Register XL-form (bcctr BO,BI,BH)
+ [5]*argField{ap_ImmUnsigned_6_10, ap_CondRegBit_11_15, ap_ImmUnsigned_19_20}},
+ {BCCTRL, 0xfc0007ff, 0x4c000421, 0xe000, // Branch Conditional to Count Register XL-form (bcctrl BO,BI,BH)
+ [5]*argField{ap_ImmUnsigned_6_10, ap_CondRegBit_11_15, ap_ImmUnsigned_19_20}},
+ {BCTAR, 0xfc0007ff, 0x4c000460, 0xe000, // Branch Conditional to Branch Target Address Register XL-form (bctar BO,BI,BH)
+ [5]*argField{ap_ImmUnsigned_6_10, ap_CondRegBit_11_15, ap_ImmUnsigned_19_20}},
+ {BCTARL, 0xfc0007ff, 0x4c000461, 0xe000, // Branch Conditional to Branch Target Address Register XL-form (bctarl BO,BI,BH)
+ [5]*argField{ap_ImmUnsigned_6_10, ap_CondRegBit_11_15, ap_ImmUnsigned_19_20}},
+ {CRAND, 0xfc0007fe, 0x4c000202, 0x1, // Condition Register AND XL-form (crand BT,BA,BB)
+ [5]*argField{ap_CondRegBit_6_10, ap_CondRegBit_11_15, ap_CondRegBit_16_20}},
+ {CROR, 0xfc0007fe, 0x4c000382, 0x1, // Condition Register OR XL-form (cror BT,BA,BB)
+ [5]*argField{ap_CondRegBit_6_10, ap_CondRegBit_11_15, ap_CondRegBit_16_20}},
+ {CRNAND, 0xfc0007fe, 0x4c0001c2, 0x1, // Condition Register NAND XL-form (crnand BT,BA,BB)
+ [5]*argField{ap_CondRegBit_6_10, ap_CondRegBit_11_15, ap_CondRegBit_16_20}},
+ {CRXOR, 0xfc0007fe, 0x4c000182, 0x1, // Condition Register XOR XL-form (crxor BT,BA,BB)
+ [5]*argField{ap_CondRegBit_6_10, ap_CondRegBit_11_15, ap_CondRegBit_16_20}},
+ {CRNOR, 0xfc0007fe, 0x4c000042, 0x1, // Condition Register NOR XL-form (crnor BT,BA,BB)
+ [5]*argField{ap_CondRegBit_6_10, ap_CondRegBit_11_15, ap_CondRegBit_16_20}},
+ {CRANDC, 0xfc0007fe, 0x4c000102, 0x1, // Condition Register AND with Complement XL-form (crandc BT,BA,BB)
+ [5]*argField{ap_CondRegBit_6_10, ap_CondRegBit_11_15, ap_CondRegBit_16_20}},
+ {MCRF, 0xfc0007fe, 0x4c000000, 0x63f801, // Move Condition Register Field XL-form (mcrf BF,BFA)
+ [5]*argField{ap_CondRegField_6_8, ap_CondRegField_11_13}},
+ {CREQV, 0xfc0007fe, 0x4c000242, 0x1, // Condition Register Equivalent XL-form (creqv BT,BA,BB)
+ [5]*argField{ap_CondRegBit_6_10, ap_CondRegBit_11_15, ap_CondRegBit_16_20}},
+ {CRORC, 0xfc0007fe, 0x4c000342, 0x1, // Condition Register OR with Complement XL-form (crorc BT,BA,BB)
+ [5]*argField{ap_CondRegBit_6_10, ap_CondRegBit_11_15, ap_CondRegBit_16_20}},
+ {SC, 0xfc000002, 0x44000002, 0x3fff01d, // System Call SC-form (sc LEV)
+ [5]*argField{ap_ImmUnsigned_20_26}},
+ {CLRBHRB, 0xfc0007fe, 0x7c00035c, 0x3fff801, // Clear BHRB X-form (clrbhrb)
+ [5]*argField{}},
+ {MFBHRBE, 0xfc0007fe, 0x7c00025c, 0x1, // Move From Branch History Rolling Buffer XFX-form (mfbhrbe RT,BHRBE)
+ [5]*argField{ap_Reg_6_10, ap_SpReg_11_20}},
+ {LBZ, 0xfc000000, 0x88000000, 0x0, // Load Byte and Zero D-form (lbz RT,D(RA))
+ [5]*argField{ap_Reg_6_10, ap_Offset_16_31, ap_Reg_11_15}},
+ {LBZU, 0xfc000000, 0x8c000000, 0x0, // Load Byte and Zero with Update D-form (lbzu RT,D(RA))
+ [5]*argField{ap_Reg_6_10, ap_Offset_16_31, ap_Reg_11_15}},
+ {LBZX, 0xfc0007fe, 0x7c0000ae, 0x1, // Load Byte and Zero Indexed X-form (lbzx RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {LBZUX, 0xfc0007fe, 0x7c0000ee, 0x1, // Load Byte and Zero with Update Indexed X-form (lbzux RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {LHZ, 0xfc000000, 0xa0000000, 0x0, // Load Halfword and Zero D-form (lhz RT,D(RA))
+ [5]*argField{ap_Reg_6_10, ap_Offset_16_31, ap_Reg_11_15}},
+ {LHZU, 0xfc000000, 0xa4000000, 0x0, // Load Halfword and Zero with Update D-form (lhzu RT,D(RA))
+ [5]*argField{ap_Reg_6_10, ap_Offset_16_31, ap_Reg_11_15}},
+ {LHZX, 0xfc0007fe, 0x7c00022e, 0x1, // Load Halfword and Zero Indexed X-form (lhzx RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {LHZUX, 0xfc0007fe, 0x7c00026e, 0x1, // Load Halfword and Zero with Update Indexed X-form (lhzux RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {LHA, 0xfc000000, 0xa8000000, 0x0, // Load Halfword Algebraic D-form (lha RT,D(RA))
+ [5]*argField{ap_Reg_6_10, ap_Offset_16_31, ap_Reg_11_15}},
+ {LHAU, 0xfc000000, 0xac000000, 0x0, // Load Halfword Algebraic with Update D-form (lhau RT,D(RA))
+ [5]*argField{ap_Reg_6_10, ap_Offset_16_31, ap_Reg_11_15}},
+ {LHAX, 0xfc0007fe, 0x7c0002ae, 0x1, // Load Halfword Algebraic Indexed X-form (lhax RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {LHAUX, 0xfc0007fe, 0x7c0002ee, 0x1, // Load Halfword Algebraic with Update Indexed X-form (lhaux RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {LWZ, 0xfc000000, 0x80000000, 0x0, // Load Word and Zero D-form (lwz RT,D(RA))
+ [5]*argField{ap_Reg_6_10, ap_Offset_16_31, ap_Reg_11_15}},
+ {LWZU, 0xfc000000, 0x84000000, 0x0, // Load Word and Zero with Update D-form (lwzu RT,D(RA))
+ [5]*argField{ap_Reg_6_10, ap_Offset_16_31, ap_Reg_11_15}},
+ {LWZX, 0xfc0007fe, 0x7c00002e, 0x1, // Load Word and Zero Indexed X-form (lwzx RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {LWZUX, 0xfc0007fe, 0x7c00006e, 0x1, // Load Word and Zero with Update Indexed X-form (lwzux RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {LWA, 0xfc000003, 0xe8000002, 0x0, // Load Word Algebraic DS-form (lwa RT,DS(RA))
+ [5]*argField{ap_Reg_6_10, ap_Offset_16_29_shift2, ap_Reg_11_15}},
+ {LWAX, 0xfc0007fe, 0x7c0002aa, 0x1, // Load Word Algebraic Indexed X-form (lwax RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {LWAUX, 0xfc0007fe, 0x7c0002ea, 0x1, // Load Word Algebraic with Update Indexed X-form (lwaux RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {LD, 0xfc000003, 0xe8000000, 0x0, // Load Doubleword DS-form (ld RT,DS(RA))
+ [5]*argField{ap_Reg_6_10, ap_Offset_16_29_shift2, ap_Reg_11_15}},
+ {LDU, 0xfc000003, 0xe8000001, 0x0, // Load Doubleword with Update DS-form (ldu RT,DS(RA))
+ [5]*argField{ap_Reg_6_10, ap_Offset_16_29_shift2, ap_Reg_11_15}},
+ {LDX, 0xfc0007fe, 0x7c00002a, 0x1, // Load Doubleword Indexed X-form (ldx RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {LDUX, 0xfc0007fe, 0x7c00006a, 0x1, // Load Doubleword with Update Indexed X-form (ldux RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {STB, 0xfc000000, 0x98000000, 0x0, // Store Byte D-form (stb RS,D(RA))
+ [5]*argField{ap_Reg_6_10, ap_Offset_16_31, ap_Reg_11_15}},
+ {STBU, 0xfc000000, 0x9c000000, 0x0, // Store Byte with Update D-form (stbu RS,D(RA))
+ [5]*argField{ap_Reg_6_10, ap_Offset_16_31, ap_Reg_11_15}},
+ {STBX, 0xfc0007fe, 0x7c0001ae, 0x1, // Store Byte Indexed X-form (stbx RS,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {STBUX, 0xfc0007fe, 0x7c0001ee, 0x1, // Store Byte with Update Indexed X-form (stbux RS,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {STH, 0xfc000000, 0xb0000000, 0x0, // Store Halfword D-form (sth RS,D(RA))
+ [5]*argField{ap_Reg_6_10, ap_Offset_16_31, ap_Reg_11_15}},
+ {STHU, 0xfc000000, 0xb4000000, 0x0, // Store Halfword with Update D-form (sthu RS,D(RA))
+ [5]*argField{ap_Reg_6_10, ap_Offset_16_31, ap_Reg_11_15}},
+ {STHX, 0xfc0007fe, 0x7c00032e, 0x1, // Store Halfword Indexed X-form (sthx RS,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {STHUX, 0xfc0007fe, 0x7c00036e, 0x1, // Store Halfword with Update Indexed X-form (sthux RS,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {STW, 0xfc000000, 0x90000000, 0x0, // Store Word D-form (stw RS,D(RA))
+ [5]*argField{ap_Reg_6_10, ap_Offset_16_31, ap_Reg_11_15}},
+ {STWU, 0xfc000000, 0x94000000, 0x0, // Store Word with Update D-form (stwu RS,D(RA))
+ [5]*argField{ap_Reg_6_10, ap_Offset_16_31, ap_Reg_11_15}},
+ {STWX, 0xfc0007fe, 0x7c00012e, 0x1, // Store Word Indexed X-form (stwx RS,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {STWUX, 0xfc0007fe, 0x7c00016e, 0x1, // Store Word with Update Indexed X-form (stwux RS,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {STD, 0xfc000003, 0xf8000000, 0x0, // Store Doubleword DS-form (std RS,DS(RA))
+ [5]*argField{ap_Reg_6_10, ap_Offset_16_29_shift2, ap_Reg_11_15}},
+ {STDU, 0xfc000003, 0xf8000001, 0x0, // Store Doubleword with Update DS-form (stdu RS,DS(RA))
+ [5]*argField{ap_Reg_6_10, ap_Offset_16_29_shift2, ap_Reg_11_15}},
+ {STDX, 0xfc0007fe, 0x7c00012a, 0x1, // Store Doubleword Indexed X-form (stdx RS,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {STDUX, 0xfc0007fe, 0x7c00016a, 0x1, // Store Doubleword with Update Indexed X-form (stdux RS,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {LQ, 0xfc000000, 0xe0000000, 0xf, // Load Quadword DQ-form (lq RTp,DQ(RA))
+ [5]*argField{ap_Reg_6_10, ap_Offset_16_27_shift4, ap_Reg_11_15}},
+ {STQ, 0xfc000003, 0xf8000002, 0x0, // Store Quadword DS-form (stq RSp,DS(RA))
+ [5]*argField{ap_Reg_6_10, ap_Offset_16_29_shift2, ap_Reg_11_15}},
+ {LHBRX, 0xfc0007fe, 0x7c00062c, 0x1, // Load Halfword Byte-Reverse Indexed X-form (lhbrx RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {LWBRX, 0xfc0007fe, 0x7c00042c, 0x1, // Load Word Byte-Reverse Indexed X-form (lwbrx RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {STHBRX, 0xfc0007fe, 0x7c00072c, 0x1, // Store Halfword Byte-Reverse Indexed X-form (sthbrx RS,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {STWBRX, 0xfc0007fe, 0x7c00052c, 0x1, // Store Word Byte-Reverse Indexed X-form (stwbrx RS,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {LDBRX, 0xfc0007fe, 0x7c000428, 0x1, // Load Doubleword Byte-Reverse Indexed X-form (ldbrx RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {STDBRX, 0xfc0007fe, 0x7c000528, 0x1, // Store Doubleword Byte-Reverse Indexed X-form (stdbrx RS,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {LMW, 0xfc000000, 0xb8000000, 0x0, // Load Multiple Word D-form (lmw RT,D(RA))
+ [5]*argField{ap_Reg_6_10, ap_Offset_16_31, ap_Reg_11_15}},
+ {STMW, 0xfc000000, 0xbc000000, 0x0, // Store Multiple Word D-form (stmw RS,D(RA))
+ [5]*argField{ap_Reg_6_10, ap_Offset_16_31, ap_Reg_11_15}},
+ {LSWI, 0xfc0007fe, 0x7c0004aa, 0x1, // Load String Word Immediate X-form (lswi RT,RA,NB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_ImmUnsigned_16_20}},
+ {LSWX, 0xfc0007fe, 0x7c00042a, 0x1, // Load String Word Indexed X-form (lswx RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {STSWI, 0xfc0007fe, 0x7c0005aa, 0x1, // Store String Word Immediate X-form (stswi RS,RA,NB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_ImmUnsigned_16_20}},
+ {STSWX, 0xfc0007fe, 0x7c00052a, 0x1, // Store String Word Indexed X-form (stswx RS,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {LI, 0xfc1f0000, 0x38000000, 0x0, // Add Immediate D-form (li RT,SI)
+ [5]*argField{ap_Reg_6_10, ap_ImmSigned_16_31}},
+ {ADDI, 0xfc000000, 0x38000000, 0x0, // Add Immediate D-form (addi RT,RA,SI)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_ImmSigned_16_31}},
+ {LIS, 0xfc1f0000, 0x3c000000, 0x0, // Add Immediate Shifted D-form (lis RT, SI)
+ [5]*argField{ap_Reg_6_10, ap_ImmSigned_16_31}},
+ {ADDIS, 0xfc000000, 0x3c000000, 0x0, // Add Immediate Shifted D-form (addis RT,RA,SI)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_ImmSigned_16_31}},
+ {ADD, 0xfc0007ff, 0x7c000214, 0x0, // Add XO-form (add RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {ADD_, 0xfc0007ff, 0x7c000215, 0x0, // Add XO-form (add. RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {ADDO, 0xfc0007ff, 0x7c000614, 0x0, // Add XO-form (addo RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {ADDO_, 0xfc0007ff, 0x7c000615, 0x0, // Add XO-form (addo. RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {ADDIC, 0xfc000000, 0x30000000, 0x0, // Add Immediate Carrying D-form (addic RT,RA,SI)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_ImmSigned_16_31}},
+ {SUBF, 0xfc0007ff, 0x7c000050, 0x0, // Subtract From XO-form (subf RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {SUBF_, 0xfc0007ff, 0x7c000051, 0x0, // Subtract From XO-form (subf. RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {SUBFO, 0xfc0007ff, 0x7c000450, 0x0, // Subtract From XO-form (subfo RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {SUBFO_, 0xfc0007ff, 0x7c000451, 0x0, // Subtract From XO-form (subfo. RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {ADDIC_, 0xfc000000, 0x34000000, 0x0, // Add Immediate Carrying and Record D-form (addic. RT,RA,SI)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_ImmSigned_16_31}},
+ {SUBFIC, 0xfc000000, 0x20000000, 0x0, // Subtract From Immediate Carrying D-form (subfic RT,RA,SI)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_ImmSigned_16_31}},
+ {ADDC, 0xfc0007ff, 0x7c000014, 0x0, // Add Carrying XO-form (addc RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {ADDC_, 0xfc0007ff, 0x7c000015, 0x0, // Add Carrying XO-form (addc. RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {ADDCO, 0xfc0007ff, 0x7c000414, 0x0, // Add Carrying XO-form (addco RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {ADDCO_, 0xfc0007ff, 0x7c000415, 0x0, // Add Carrying XO-form (addco. RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {SUBFC, 0xfc0007ff, 0x7c000010, 0x0, // Subtract From Carrying XO-form (subfc RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {SUBFC_, 0xfc0007ff, 0x7c000011, 0x0, // Subtract From Carrying XO-form (subfc. RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {SUBFCO, 0xfc0007ff, 0x7c000410, 0x0, // Subtract From Carrying XO-form (subfco RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {SUBFCO_, 0xfc0007ff, 0x7c000411, 0x0, // Subtract From Carrying XO-form (subfco. RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {ADDE, 0xfc0007ff, 0x7c000114, 0x0, // Add Extended XO-form (adde RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {ADDE_, 0xfc0007ff, 0x7c000115, 0x0, // Add Extended XO-form (adde. RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {ADDEO, 0xfc0007ff, 0x7c000514, 0x0, // Add Extended XO-form (addeo RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {ADDEO_, 0xfc0007ff, 0x7c000515, 0x0, // Add Extended XO-form (addeo. RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {ADDME, 0xfc0007ff, 0x7c0001d4, 0xf800, // Add to Minus One Extended XO-form (addme RT,RA)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15}},
+ {ADDME_, 0xfc0007ff, 0x7c0001d5, 0xf800, // Add to Minus One Extended XO-form (addme. RT,RA)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15}},
+ {ADDMEO, 0xfc0007ff, 0x7c0005d4, 0xf800, // Add to Minus One Extended XO-form (addmeo RT,RA)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15}},
+ {ADDMEO_, 0xfc0007ff, 0x7c0005d5, 0xf800, // Add to Minus One Extended XO-form (addmeo. RT,RA)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15}},
+ {SUBFE, 0xfc0007ff, 0x7c000110, 0x0, // Subtract From Extended XO-form (subfe RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {SUBFE_, 0xfc0007ff, 0x7c000111, 0x0, // Subtract From Extended XO-form (subfe. RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {SUBFEO, 0xfc0007ff, 0x7c000510, 0x0, // Subtract From Extended XO-form (subfeo RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {SUBFEO_, 0xfc0007ff, 0x7c000511, 0x0, // Subtract From Extended XO-form (subfeo. RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {SUBFME, 0xfc0007ff, 0x7c0001d0, 0xf800, // Subtract From Minus One Extended XO-form (subfme RT,RA)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15}},
+ {SUBFME_, 0xfc0007ff, 0x7c0001d1, 0xf800, // Subtract From Minus One Extended XO-form (subfme. RT,RA)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15}},
+ {SUBFMEO, 0xfc0007ff, 0x7c0005d0, 0xf800, // Subtract From Minus One Extended XO-form (subfmeo RT,RA)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15}},
+ {SUBFMEO_, 0xfc0007ff, 0x7c0005d1, 0xf800, // Subtract From Minus One Extended XO-form (subfmeo. RT,RA)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15}},
+ {ADDZE, 0xfc0007ff, 0x7c000194, 0xf800, // Add to Zero Extended XO-form (addze RT,RA)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15}},
+ {ADDZE_, 0xfc0007ff, 0x7c000195, 0xf800, // Add to Zero Extended XO-form (addze. RT,RA)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15}},
+ {ADDZEO, 0xfc0007ff, 0x7c000594, 0xf800, // Add to Zero Extended XO-form (addzeo RT,RA)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15}},
+ {ADDZEO_, 0xfc0007ff, 0x7c000595, 0xf800, // Add to Zero Extended XO-form (addzeo. RT,RA)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15}},
+ {SUBFZE, 0xfc0007ff, 0x7c000190, 0xf800, // Subtract From Zero Extended XO-form (subfze RT,RA)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15}},
+ {SUBFZE_, 0xfc0007ff, 0x7c000191, 0xf800, // Subtract From Zero Extended XO-form (subfze. RT,RA)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15}},
+ {SUBFZEO, 0xfc0007ff, 0x7c000590, 0xf800, // Subtract From Zero Extended XO-form (subfzeo RT,RA)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15}},
+ {SUBFZEO_, 0xfc0007ff, 0x7c000591, 0xf800, // Subtract From Zero Extended XO-form (subfzeo. RT,RA)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15}},
+ {NEG, 0xfc0007ff, 0x7c0000d0, 0xf800, // Negate XO-form (neg RT,RA)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15}},
+ {NEG_, 0xfc0007ff, 0x7c0000d1, 0xf800, // Negate XO-form (neg. RT,RA)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15}},
+ {NEGO, 0xfc0007ff, 0x7c0004d0, 0xf800, // Negate XO-form (nego RT,RA)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15}},
+ {NEGO_, 0xfc0007ff, 0x7c0004d1, 0xf800, // Negate XO-form (nego. RT,RA)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15}},
+ {MULLI, 0xfc000000, 0x1c000000, 0x0, // Multiply Low Immediate D-form (mulli RT,RA,SI)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_ImmSigned_16_31}},
+ {MULLW, 0xfc0007ff, 0x7c0001d6, 0x0, // Multiply Low Word XO-form (mullw RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {MULLW_, 0xfc0007ff, 0x7c0001d7, 0x0, // Multiply Low Word XO-form (mullw. RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {MULLWO, 0xfc0007ff, 0x7c0005d6, 0x0, // Multiply Low Word XO-form (mullwo RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {MULLWO_, 0xfc0007ff, 0x7c0005d7, 0x0, // Multiply Low Word XO-form (mullwo. RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {MULHW, 0xfc0003ff, 0x7c000096, 0x400, // Multiply High Word XO-form (mulhw RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {MULHW_, 0xfc0003ff, 0x7c000097, 0x400, // Multiply High Word XO-form (mulhw. RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {MULHWU, 0xfc0003ff, 0x7c000016, 0x400, // Multiply High Word Unsigned XO-form (mulhwu RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {MULHWU_, 0xfc0003ff, 0x7c000017, 0x400, // Multiply High Word Unsigned XO-form (mulhwu. RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {DIVW, 0xfc0007ff, 0x7c0003d6, 0x0, // Divide Word XO-form (divw RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {DIVW_, 0xfc0007ff, 0x7c0003d7, 0x0, // Divide Word XO-form (divw. RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {DIVWO, 0xfc0007ff, 0x7c0007d6, 0x0, // Divide Word XO-form (divwo RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {DIVWO_, 0xfc0007ff, 0x7c0007d7, 0x0, // Divide Word XO-form (divwo. RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {DIVWU, 0xfc0007ff, 0x7c000396, 0x0, // Divide Word Unsigned XO-form (divwu RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {DIVWU_, 0xfc0007ff, 0x7c000397, 0x0, // Divide Word Unsigned XO-form (divwu. RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {DIVWUO, 0xfc0007ff, 0x7c000796, 0x0, // Divide Word Unsigned XO-form (divwuo RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {DIVWUO_, 0xfc0007ff, 0x7c000797, 0x0, // Divide Word Unsigned XO-form (divwuo. RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {DIVWE, 0xfc0007ff, 0x7c000356, 0x0, // Divide Word Extended XO-form (divwe RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {DIVWE_, 0xfc0007ff, 0x7c000357, 0x0, // Divide Word Extended XO-form (divwe. RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {DIVWEO, 0xfc0007ff, 0x7c000756, 0x0, // Divide Word Extended XO-form (divweo RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {DIVWEO_, 0xfc0007ff, 0x7c000757, 0x0, // Divide Word Extended XO-form (divweo. RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {DIVWEU, 0xfc0007ff, 0x7c000316, 0x0, // Divide Word Extended Unsigned XO-form (divweu RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {DIVWEU_, 0xfc0007ff, 0x7c000317, 0x0, // Divide Word Extended Unsigned XO-form (divweu. RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {DIVWEUO, 0xfc0007ff, 0x7c000716, 0x0, // Divide Word Extended Unsigned XO-form (divweuo RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {DIVWEUO_, 0xfc0007ff, 0x7c000717, 0x0, // Divide Word Extended Unsigned XO-form (divweuo. RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {MULLD, 0xfc0007ff, 0x7c0001d2, 0x0, // Multiply Low Doubleword XO-form (mulld RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {MULLD_, 0xfc0007ff, 0x7c0001d3, 0x0, // Multiply Low Doubleword XO-form (mulld. RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {MULLDO, 0xfc0007ff, 0x7c0005d2, 0x0, // Multiply Low Doubleword XO-form (mulldo RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {MULLDO_, 0xfc0007ff, 0x7c0005d3, 0x0, // Multiply Low Doubleword XO-form (mulldo. RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {MULHDU, 0xfc0003ff, 0x7c000012, 0x400, // Multiply High Doubleword Unsigned XO-form (mulhdu RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {MULHDU_, 0xfc0003ff, 0x7c000013, 0x400, // Multiply High Doubleword Unsigned XO-form (mulhdu. RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {MULHD, 0xfc0003ff, 0x7c000092, 0x400, // Multiply High Doubleword XO-form (mulhd RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {MULHD_, 0xfc0003ff, 0x7c000093, 0x400, // Multiply High Doubleword XO-form (mulhd. RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {DIVD, 0xfc0007ff, 0x7c0003d2, 0x0, // Divide Doubleword XO-form (divd RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {DIVD_, 0xfc0007ff, 0x7c0003d3, 0x0, // Divide Doubleword XO-form (divd. RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {DIVDO, 0xfc0007ff, 0x7c0007d2, 0x0, // Divide Doubleword XO-form (divdo RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {DIVDO_, 0xfc0007ff, 0x7c0007d3, 0x0, // Divide Doubleword XO-form (divdo. RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {DIVDU, 0xfc0007ff, 0x7c000392, 0x0, // Divide Doubleword Unsigned XO-form (divdu RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {DIVDU_, 0xfc0007ff, 0x7c000393, 0x0, // Divide Doubleword Unsigned XO-form (divdu. RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {DIVDUO, 0xfc0007ff, 0x7c000792, 0x0, // Divide Doubleword Unsigned XO-form (divduo RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {DIVDUO_, 0xfc0007ff, 0x7c000793, 0x0, // Divide Doubleword Unsigned XO-form (divduo. RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {DIVDE, 0xfc0007ff, 0x7c000352, 0x0, // Divide Doubleword Extended XO-form (divde RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {DIVDE_, 0xfc0007ff, 0x7c000353, 0x0, // Divide Doubleword Extended XO-form (divde. RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {DIVDEO, 0xfc0007ff, 0x7c000752, 0x0, // Divide Doubleword Extended XO-form (divdeo RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {DIVDEO_, 0xfc0007ff, 0x7c000753, 0x0, // Divide Doubleword Extended XO-form (divdeo. RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {DIVDEU, 0xfc0007ff, 0x7c000312, 0x0, // Divide Doubleword Extended Unsigned XO-form (divdeu RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {DIVDEU_, 0xfc0007ff, 0x7c000313, 0x0, // Divide Doubleword Extended Unsigned XO-form (divdeu. RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {DIVDEUO, 0xfc0007ff, 0x7c000712, 0x0, // Divide Doubleword Extended Unsigned XO-form (divdeuo RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {DIVDEUO_, 0xfc0007ff, 0x7c000713, 0x0, // Divide Doubleword Extended Unsigned XO-form (divdeuo. RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {CMPWI, 0xfc200000, 0x2c000000, 0x400000, // Compare Immediate D-form (cmpwi BF,RA,SI)
+ [5]*argField{ap_CondRegField_6_8, ap_Reg_11_15, ap_ImmSigned_16_31}},
+ {CMPDI, 0xfc200000, 0x2c200000, 0x400000, // Compare Immediate D-form (cmpdi BF,RA,SI)
+ [5]*argField{ap_CondRegField_6_8, ap_Reg_11_15, ap_ImmSigned_16_31}},
+ {CMPW, 0xfc2007fe, 0x7c000000, 0x400001, // Compare X-form (cmpw BF,RA,RB)
+ [5]*argField{ap_CondRegField_6_8, ap_Reg_11_15, ap_Reg_16_20}},
+ {CMPD, 0xfc2007fe, 0x7c200000, 0x400001, // Compare X-form (cmpd BF,RA,RB)
+ [5]*argField{ap_CondRegField_6_8, ap_Reg_11_15, ap_Reg_16_20}},
+ {CMPLWI, 0xfc200000, 0x28000000, 0x400000, // Compare Logical Immediate D-form (cmplwi BF,RA,UI)
+ [5]*argField{ap_CondRegField_6_8, ap_Reg_11_15, ap_ImmUnsigned_16_31}},
+ {CMPLDI, 0xfc200000, 0x28200000, 0x400000, // Compare Logical Immediate D-form (cmpldi BF,RA,UI)
+ [5]*argField{ap_CondRegField_6_8, ap_Reg_11_15, ap_ImmUnsigned_16_31}},
+ {CMPLW, 0xfc2007fe, 0x7c000040, 0x400001, // Compare Logical X-form (cmplw BF,RA,RB)
+ [5]*argField{ap_CondRegField_6_8, ap_Reg_11_15, ap_Reg_16_20}},
+ {CMPLD, 0xfc2007fe, 0x7c200040, 0x400001, // Compare Logical X-form (cmpld BF,RA,RB)
+ [5]*argField{ap_CondRegField_6_8, ap_Reg_11_15, ap_Reg_16_20}},
+ {TWI, 0xfc000000, 0xc000000, 0x0, // Trap Word Immediate D-form (twi TO,RA,SI)
+ [5]*argField{ap_ImmUnsigned_6_10, ap_Reg_11_15, ap_ImmSigned_16_31}},
+ {TW, 0xfc0007fe, 0x7c000008, 0x1, // Trap Word X-form (tw TO,RA,RB)
+ [5]*argField{ap_ImmUnsigned_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {TDI, 0xfc000000, 0x8000000, 0x0, // Trap Doubleword Immediate D-form (tdi TO,RA,SI)
+ [5]*argField{ap_ImmUnsigned_6_10, ap_Reg_11_15, ap_ImmSigned_16_31}},
+ {ISEL, 0xfc00003e, 0x7c00001e, 0x1, // Integer Select A-form (isel RT,RA,RB,BC)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20, ap_CondRegBit_21_25}},
+ {TD, 0xfc0007fe, 0x7c000088, 0x1, // Trap Doubleword X-form (td TO,RA,RB)
+ [5]*argField{ap_ImmUnsigned_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {ANDI_, 0xfc000000, 0x70000000, 0x0, // AND Immediate D-form (andi. RA,RS,UI)
+ [5]*argField{ap_Reg_11_15, ap_Reg_6_10, ap_ImmUnsigned_16_31}},
+ {ANDIS_, 0xfc000000, 0x74000000, 0x0, // AND Immediate Shifted D-form (andis. RA,RS,UI)
+ [5]*argField{ap_Reg_11_15, ap_Reg_6_10, ap_ImmUnsigned_16_31}},
+ {ORI, 0xfc000000, 0x60000000, 0x0, // OR Immediate D-form (ori RA,RS,UI)
+ [5]*argField{ap_Reg_11_15, ap_Reg_6_10, ap_ImmUnsigned_16_31}},
+ {ORIS, 0xfc000000, 0x64000000, 0x0, // OR Immediate Shifted D-form (oris RA,RS,UI)
+ [5]*argField{ap_Reg_11_15, ap_Reg_6_10, ap_ImmUnsigned_16_31}},
+ {XORI, 0xfc000000, 0x68000000, 0x0, // XOR Immediate D-form (xori RA,RS,UI)
+ [5]*argField{ap_Reg_11_15, ap_Reg_6_10, ap_ImmUnsigned_16_31}},
+ {XORIS, 0xfc000000, 0x6c000000, 0x0, // XOR Immediate Shifted D-form (xoris RA,RS,UI)
+ [5]*argField{ap_Reg_11_15, ap_Reg_6_10, ap_ImmUnsigned_16_31}},
+ {AND, 0xfc0007ff, 0x7c000038, 0x0, // AND X-form (and RA,RS,RB)
+ [5]*argField{ap_Reg_11_15, ap_Reg_6_10, ap_Reg_16_20}},
+ {AND_, 0xfc0007ff, 0x7c000039, 0x0, // AND X-form (and. RA,RS,RB)
+ [5]*argField{ap_Reg_11_15, ap_Reg_6_10, ap_Reg_16_20}},
+ {XOR, 0xfc0007ff, 0x7c000278, 0x0, // XOR X-form (xor RA,RS,RB)
+ [5]*argField{ap_Reg_11_15, ap_Reg_6_10, ap_Reg_16_20}},
+ {XOR_, 0xfc0007ff, 0x7c000279, 0x0, // XOR X-form (xor. RA,RS,RB)
+ [5]*argField{ap_Reg_11_15, ap_Reg_6_10, ap_Reg_16_20}},
+ {NAND, 0xfc0007ff, 0x7c0003b8, 0x0, // NAND X-form (nand RA,RS,RB)
+ [5]*argField{ap_Reg_11_15, ap_Reg_6_10, ap_Reg_16_20}},
+ {NAND_, 0xfc0007ff, 0x7c0003b9, 0x0, // NAND X-form (nand. RA,RS,RB)
+ [5]*argField{ap_Reg_11_15, ap_Reg_6_10, ap_Reg_16_20}},
+ {OR, 0xfc0007ff, 0x7c000378, 0x0, // OR X-form (or RA,RS,RB)
+ [5]*argField{ap_Reg_11_15, ap_Reg_6_10, ap_Reg_16_20}},
+ {OR_, 0xfc0007ff, 0x7c000379, 0x0, // OR X-form (or. RA,RS,RB)
+ [5]*argField{ap_Reg_11_15, ap_Reg_6_10, ap_Reg_16_20}},
+ {NOR, 0xfc0007ff, 0x7c0000f8, 0x0, // NOR X-form (nor RA,RS,RB)
+ [5]*argField{ap_Reg_11_15, ap_Reg_6_10, ap_Reg_16_20}},
+ {NOR_, 0xfc0007ff, 0x7c0000f9, 0x0, // NOR X-form (nor. RA,RS,RB)
+ [5]*argField{ap_Reg_11_15, ap_Reg_6_10, ap_Reg_16_20}},
+ {ANDC, 0xfc0007ff, 0x7c000078, 0x0, // AND with Complement X-form (andc RA,RS,RB)
+ [5]*argField{ap_Reg_11_15, ap_Reg_6_10, ap_Reg_16_20}},
+ {ANDC_, 0xfc0007ff, 0x7c000079, 0x0, // AND with Complement X-form (andc. RA,RS,RB)
+ [5]*argField{ap_Reg_11_15, ap_Reg_6_10, ap_Reg_16_20}},
+ {EXTSB, 0xfc0007ff, 0x7c000774, 0xf800, // Extend Sign Byte X-form (extsb RA,RS)
+ [5]*argField{ap_Reg_11_15, ap_Reg_6_10}},
+ {EXTSB_, 0xfc0007ff, 0x7c000775, 0xf800, // Extend Sign Byte X-form (extsb. RA,RS)
+ [5]*argField{ap_Reg_11_15, ap_Reg_6_10}},
+ {EQV, 0xfc0007ff, 0x7c000238, 0x0, // Equivalent X-form (eqv RA,RS,RB)
+ [5]*argField{ap_Reg_11_15, ap_Reg_6_10, ap_Reg_16_20}},
+ {EQV_, 0xfc0007ff, 0x7c000239, 0x0, // Equivalent X-form (eqv. RA,RS,RB)
+ [5]*argField{ap_Reg_11_15, ap_Reg_6_10, ap_Reg_16_20}},
+ {ORC, 0xfc0007ff, 0x7c000338, 0x0, // OR with Complement X-form (orc RA,RS,RB)
+ [5]*argField{ap_Reg_11_15, ap_Reg_6_10, ap_Reg_16_20}},
+ {ORC_, 0xfc0007ff, 0x7c000339, 0x0, // OR with Complement X-form (orc. RA,RS,RB)
+ [5]*argField{ap_Reg_11_15, ap_Reg_6_10, ap_Reg_16_20}},
+ {EXTSH, 0xfc0007ff, 0x7c000734, 0xf800, // Extend Sign Halfword X-form (extsh RA,RS)
+ [5]*argField{ap_Reg_11_15, ap_Reg_6_10}},
+ {EXTSH_, 0xfc0007ff, 0x7c000735, 0xf800, // Extend Sign Halfword X-form (extsh. RA,RS)
+ [5]*argField{ap_Reg_11_15, ap_Reg_6_10}},
+ {CMPB, 0xfc0007fe, 0x7c0003f8, 0x1, // Compare Bytes X-form (cmpb RA,RS,RB)
+ [5]*argField{ap_Reg_11_15, ap_Reg_6_10, ap_Reg_16_20}},
+ {POPCNTB, 0xfc0007fe, 0x7c0000f4, 0xf801, // Population Count Bytes X-form (popcntb RA, RS)
+ [5]*argField{ap_Reg_11_15, ap_Reg_6_10}},
+ {POPCNTW, 0xfc0007fe, 0x7c0002f4, 0xf801, // Population Count Words X-form (popcntw RA, RS)
+ [5]*argField{ap_Reg_11_15, ap_Reg_6_10}},
+ {PRTYD, 0xfc0007fe, 0x7c000174, 0xf801, // Parity Doubleword X-form (prtyd RA,RS)
+ [5]*argField{ap_Reg_11_15, ap_Reg_6_10}},
+ {PRTYW, 0xfc0007fe, 0x7c000134, 0xf801, // Parity Word X-form (prtyw RA,RS)
+ [5]*argField{ap_Reg_11_15, ap_Reg_6_10}},
+ {EXTSW, 0xfc0007ff, 0x7c0007b4, 0xf800, // Extend Sign Word X-form (extsw RA,RS)
+ [5]*argField{ap_Reg_11_15, ap_Reg_6_10}},
+ {EXTSW_, 0xfc0007ff, 0x7c0007b5, 0xf800, // Extend Sign Word X-form (extsw. RA,RS)
+ [5]*argField{ap_Reg_11_15, ap_Reg_6_10}},
+ {CNTLZD, 0xfc0007ff, 0x7c000074, 0xf800, // Count Leading Zeros Doubleword X-form (cntlzd RA,RS)
+ [5]*argField{ap_Reg_11_15, ap_Reg_6_10}},
+ {CNTLZD_, 0xfc0007ff, 0x7c000075, 0xf800, // Count Leading Zeros Doubleword X-form (cntlzd. RA,RS)
+ [5]*argField{ap_Reg_11_15, ap_Reg_6_10}},
+ {POPCNTD, 0xfc0007fe, 0x7c0003f4, 0xf801, // Population Count Doubleword X-form (popcntd RA, RS)
+ [5]*argField{ap_Reg_11_15, ap_Reg_6_10}},
+ {BPERMD, 0xfc0007fe, 0x7c0001f8, 0x1, // Bit Permute Doubleword X-form (bpermd RA,RS,RB)
+ [5]*argField{ap_Reg_11_15, ap_Reg_6_10, ap_Reg_16_20}},
+ {RLWINM, 0xfc000001, 0x54000000, 0x0, // Rotate Left Word Immediate then AND with Mask M-form (rlwinm RA,RS,SH,MB,ME)
+ [5]*argField{ap_Reg_11_15, ap_Reg_6_10, ap_ImmUnsigned_16_20, ap_ImmUnsigned_21_25, ap_ImmUnsigned_26_30}},
+ {RLWINM_, 0xfc000001, 0x54000001, 0x0, // Rotate Left Word Immediate then AND with Mask M-form (rlwinm. RA,RS,SH,MB,ME)
+ [5]*argField{ap_Reg_11_15, ap_Reg_6_10, ap_ImmUnsigned_16_20, ap_ImmUnsigned_21_25, ap_ImmUnsigned_26_30}},
+ {RLWNM, 0xfc000001, 0x5c000000, 0x0, // Rotate Left Word then AND with Mask M-form (rlwnm RA,RS,RB,MB,ME)
+ [5]*argField{ap_Reg_11_15, ap_Reg_6_10, ap_Reg_16_20, ap_ImmUnsigned_21_25, ap_ImmUnsigned_26_30}},
+ {RLWNM_, 0xfc000001, 0x5c000001, 0x0, // Rotate Left Word then AND with Mask M-form (rlwnm. RA,RS,RB,MB,ME)
+ [5]*argField{ap_Reg_11_15, ap_Reg_6_10, ap_Reg_16_20, ap_ImmUnsigned_21_25, ap_ImmUnsigned_26_30}},
+ {RLWIMI, 0xfc000001, 0x50000000, 0x0, // Rotate Left Word Immediate then Mask Insert M-form (rlwimi RA,RS,SH,MB,ME)
+ [5]*argField{ap_Reg_11_15, ap_Reg_6_10, ap_ImmUnsigned_16_20, ap_ImmUnsigned_21_25, ap_ImmUnsigned_26_30}},
+ {RLWIMI_, 0xfc000001, 0x50000001, 0x0, // Rotate Left Word Immediate then Mask Insert M-form (rlwimi. RA,RS,SH,MB,ME)
+ [5]*argField{ap_Reg_11_15, ap_Reg_6_10, ap_ImmUnsigned_16_20, ap_ImmUnsigned_21_25, ap_ImmUnsigned_26_30}},
+ {RLDICL, 0xfc00001d, 0x78000000, 0x0, // Rotate Left Doubleword Immediate then Clear Left MD-form (rldicl RA,RS,SH,MB)
+ [5]*argField{ap_Reg_11_15, ap_Reg_6_10, ap_ImmUnsigned_30_30_16_20, ap_ImmUnsigned_26_26_21_25}},
+ {RLDICL_, 0xfc00001d, 0x78000001, 0x0, // Rotate Left Doubleword Immediate then Clear Left MD-form (rldicl. RA,RS,SH,MB)
+ [5]*argField{ap_Reg_11_15, ap_Reg_6_10, ap_ImmUnsigned_30_30_16_20, ap_ImmUnsigned_26_26_21_25}},
+ {RLDICR, 0xfc00001d, 0x78000004, 0x0, // Rotate Left Doubleword Immediate then Clear Right MD-form (rldicr RA,RS,SH,ME)
+ [5]*argField{ap_Reg_11_15, ap_Reg_6_10, ap_ImmUnsigned_30_30_16_20, ap_ImmUnsigned_26_26_21_25}},
+ {RLDICR_, 0xfc00001d, 0x78000005, 0x0, // Rotate Left Doubleword Immediate then Clear Right MD-form (rldicr. RA,RS,SH,ME)
+ [5]*argField{ap_Reg_11_15, ap_Reg_6_10, ap_ImmUnsigned_30_30_16_20, ap_ImmUnsigned_26_26_21_25}},
+ {RLDIC, 0xfc00001d, 0x78000008, 0x0, // Rotate Left Doubleword Immediate then Clear MD-form (rldic RA,RS,SH,MB)
+ [5]*argField{ap_Reg_11_15, ap_Reg_6_10, ap_ImmUnsigned_30_30_16_20, ap_ImmUnsigned_26_26_21_25}},
+ {RLDIC_, 0xfc00001d, 0x78000009, 0x0, // Rotate Left Doubleword Immediate then Clear MD-form (rldic. RA,RS,SH,MB)
+ [5]*argField{ap_Reg_11_15, ap_Reg_6_10, ap_ImmUnsigned_30_30_16_20, ap_ImmUnsigned_26_26_21_25}},
+ {RLDCL, 0xfc00001f, 0x78000010, 0x0, // Rotate Left Doubleword then Clear Left MDS-form (rldcl RA,RS,RB,MB)
+ [5]*argField{ap_Reg_11_15, ap_Reg_6_10, ap_Reg_16_20, ap_ImmUnsigned_26_26_21_25}},
+ {RLDCL_, 0xfc00001f, 0x78000011, 0x0, // Rotate Left Doubleword then Clear Left MDS-form (rldcl. RA,RS,RB,MB)
+ [5]*argField{ap_Reg_11_15, ap_Reg_6_10, ap_Reg_16_20, ap_ImmUnsigned_26_26_21_25}},
+ {RLDCR, 0xfc00001f, 0x78000012, 0x0, // Rotate Left Doubleword then Clear Right MDS-form (rldcr RA,RS,RB,ME)
+ [5]*argField{ap_Reg_11_15, ap_Reg_6_10, ap_Reg_16_20, ap_ImmUnsigned_26_26_21_25}},
+ {RLDCR_, 0xfc00001f, 0x78000013, 0x0, // Rotate Left Doubleword then Clear Right MDS-form (rldcr. RA,RS,RB,ME)
+ [5]*argField{ap_Reg_11_15, ap_Reg_6_10, ap_Reg_16_20, ap_ImmUnsigned_26_26_21_25}},
+ {RLDIMI, 0xfc00001d, 0x7800000c, 0x0, // Rotate Left Doubleword Immediate then Mask Insert MD-form (rldimi RA,RS,SH,MB)
+ [5]*argField{ap_Reg_11_15, ap_Reg_6_10, ap_ImmUnsigned_30_30_16_20, ap_ImmUnsigned_26_26_21_25}},
+ {RLDIMI_, 0xfc00001d, 0x7800000d, 0x0, // Rotate Left Doubleword Immediate then Mask Insert MD-form (rldimi. RA,RS,SH,MB)
+ [5]*argField{ap_Reg_11_15, ap_Reg_6_10, ap_ImmUnsigned_30_30_16_20, ap_ImmUnsigned_26_26_21_25}},
+ {SLW, 0xfc0007ff, 0x7c000030, 0x0, // Shift Left Word X-form (slw RA,RS,RB)
+ [5]*argField{ap_Reg_11_15, ap_Reg_6_10, ap_Reg_16_20}},
+ {SLW_, 0xfc0007ff, 0x7c000031, 0x0, // Shift Left Word X-form (slw. RA,RS,RB)
+ [5]*argField{ap_Reg_11_15, ap_Reg_6_10, ap_Reg_16_20}},
+ {SRW, 0xfc0007ff, 0x7c000430, 0x0, // Shift Right Word X-form (srw RA,RS,RB)
+ [5]*argField{ap_Reg_11_15, ap_Reg_6_10, ap_Reg_16_20}},
+ {SRW_, 0xfc0007ff, 0x7c000431, 0x0, // Shift Right Word X-form (srw. RA,RS,RB)
+ [5]*argField{ap_Reg_11_15, ap_Reg_6_10, ap_Reg_16_20}},
+ {SRAWI, 0xfc0007ff, 0x7c000670, 0x0, // Shift Right Algebraic Word Immediate X-form (srawi RA,RS,SH)
+ [5]*argField{ap_Reg_11_15, ap_Reg_6_10, ap_ImmUnsigned_16_20}},
+ {SRAWI_, 0xfc0007ff, 0x7c000671, 0x0, // Shift Right Algebraic Word Immediate X-form (srawi. RA,RS,SH)
+ [5]*argField{ap_Reg_11_15, ap_Reg_6_10, ap_ImmUnsigned_16_20}},
+ {SRAW, 0xfc0007ff, 0x7c000630, 0x0, // Shift Right Algebraic Word X-form (sraw RA,RS,RB)
+ [5]*argField{ap_Reg_11_15, ap_Reg_6_10, ap_Reg_16_20}},
+ {SRAW_, 0xfc0007ff, 0x7c000631, 0x0, // Shift Right Algebraic Word X-form (sraw. RA,RS,RB)
+ [5]*argField{ap_Reg_11_15, ap_Reg_6_10, ap_Reg_16_20}},
+ {SLD, 0xfc0007ff, 0x7c000036, 0x0, // Shift Left Doubleword X-form (sld RA,RS,RB)
+ [5]*argField{ap_Reg_11_15, ap_Reg_6_10, ap_Reg_16_20}},
+ {SLD_, 0xfc0007ff, 0x7c000037, 0x0, // Shift Left Doubleword X-form (sld. RA,RS,RB)
+ [5]*argField{ap_Reg_11_15, ap_Reg_6_10, ap_Reg_16_20}},
+ {SRD, 0xfc0007ff, 0x7c000436, 0x0, // Shift Right Doubleword X-form (srd RA,RS,RB)
+ [5]*argField{ap_Reg_11_15, ap_Reg_6_10, ap_Reg_16_20}},
+ {SRD_, 0xfc0007ff, 0x7c000437, 0x0, // Shift Right Doubleword X-form (srd. RA,RS,RB)
+ [5]*argField{ap_Reg_11_15, ap_Reg_6_10, ap_Reg_16_20}},
+ {SRADI, 0xfc0007fd, 0x7c000674, 0x0, // Shift Right Algebraic Doubleword Immediate XS-form (sradi RA,RS,SH)
+ [5]*argField{ap_Reg_11_15, ap_Reg_6_10, ap_ImmUnsigned_30_30_16_20}},
+ {SRADI_, 0xfc0007fd, 0x7c000675, 0x0, // Shift Right Algebraic Doubleword Immediate XS-form (sradi. RA,RS,SH)
+ [5]*argField{ap_Reg_11_15, ap_Reg_6_10, ap_ImmUnsigned_30_30_16_20}},
+ {SRAD, 0xfc0007ff, 0x7c000634, 0x0, // Shift Right Algebraic Doubleword X-form (srad RA,RS,RB)
+ [5]*argField{ap_Reg_11_15, ap_Reg_6_10, ap_Reg_16_20}},
+ {SRAD_, 0xfc0007ff, 0x7c000635, 0x0, // Shift Right Algebraic Doubleword X-form (srad. RA,RS,RB)
+ [5]*argField{ap_Reg_11_15, ap_Reg_6_10, ap_Reg_16_20}},
+ {CDTBCD, 0xfc0007fe, 0x7c000234, 0xf801, // Convert Declets To Binary Coded Decimal X-form (cdtbcd RA, RS)
+ [5]*argField{ap_Reg_11_15, ap_Reg_6_10}},
+ {CBCDTD, 0xfc0007fe, 0x7c000274, 0xf801, // Convert Binary Coded Decimal To Declets X-form (cbcdtd RA, RS)
+ [5]*argField{ap_Reg_11_15, ap_Reg_6_10}},
+ {ADDG6S, 0xfc0003fe, 0x7c000094, 0x401, // Add and Generate Sixes XO-form (addg6s RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {MTSPR, 0xfc0007fe, 0x7c0003a6, 0x1, // Move To Special Purpose Register XFX-form (mtspr SPR,RS)
+ [5]*argField{ap_SpReg_16_20_11_15, ap_Reg_6_10}},
+ {MFSPR, 0xfc0007fe, 0x7c0002a6, 0x1, // Move From Special Purpose Register XFX-form (mfspr RT,SPR)
+ [5]*argField{ap_Reg_6_10, ap_SpReg_16_20_11_15}},
+ {MTCRF, 0xfc1007fe, 0x7c000120, 0x801, // Move To Condition Register Fields XFX-form (mtcrf FXM,RS)
+ [5]*argField{ap_ImmUnsigned_12_19, ap_Reg_6_10}},
+ {MFCR, 0xfc1007fe, 0x7c000026, 0xff801, // Move From Condition Register XFX-form (mfcr RT)
+ [5]*argField{ap_Reg_6_10}},
+ {MTSLE, 0xfc0007fe, 0x7c000126, 0x3dff801, // Move To Split Little Endian X-form (mtsle L)
+ [5]*argField{ap_ImmUnsigned_10_10}},
+ {MFVSRD, 0xfc0007fe, 0x7c000066, 0xf800, // Move From VSR Doubleword XX1-form (mfvsrd RA,XS)
+ [5]*argField{ap_Reg_11_15, ap_VecSReg_31_31_6_10}},
+ {MFVSRWZ, 0xfc0007fe, 0x7c0000e6, 0xf800, // Move From VSR Word and Zero XX1-form (mfvsrwz RA,XS)
+ [5]*argField{ap_Reg_11_15, ap_VecSReg_31_31_6_10}},
+ {MTVSRD, 0xfc0007fe, 0x7c000166, 0xf800, // Move To VSR Doubleword XX1-form (mtvsrd XT,RA)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_Reg_11_15}},
+ {MTVSRWA, 0xfc0007fe, 0x7c0001a6, 0xf800, // Move To VSR Word Algebraic XX1-form (mtvsrwa XT,RA)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_Reg_11_15}},
+ {MTVSRWZ, 0xfc0007fe, 0x7c0001e6, 0xf800, // Move To VSR Word and Zero XX1-form (mtvsrwz XT,RA)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_Reg_11_15}},
+ {MTOCRF, 0xfc1007fe, 0x7c100120, 0x801, // Move To One Condition Register Field XFX-form (mtocrf FXM,RS)
+ [5]*argField{ap_ImmUnsigned_12_19, ap_Reg_6_10}},
+ {MFOCRF, 0xfc1007fe, 0x7c100026, 0x801, // Move From One Condition Register Field XFX-form (mfocrf RT,FXM)
+ [5]*argField{ap_Reg_6_10, ap_ImmUnsigned_12_19}},
+ {MCRXR, 0xfc0007fe, 0x7c000400, 0x7ff801, // Move to Condition Register from XER X-form (mcrxr BF)
+ [5]*argField{ap_CondRegField_6_8}},
+ {MTDCRUX, 0xfc0007fe, 0x7c000346, 0xf801, // Move To Device Control Register User-mode Indexed X-form (mtdcrux RS,RA)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15}},
+ {MFDCRUX, 0xfc0007fe, 0x7c000246, 0xf801, // Move From Device Control Register User-mode Indexed X-form (mfdcrux RT,RA)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15}},
+ {LFS, 0xfc000000, 0xc0000000, 0x0, // Load Floating-Point Single D-form (lfs FRT,D(RA))
+ [5]*argField{ap_FPReg_6_10, ap_Offset_16_31, ap_Reg_11_15}},
+ {LFSU, 0xfc000000, 0xc4000000, 0x0, // Load Floating-Point Single with Update D-form (lfsu FRT,D(RA))
+ [5]*argField{ap_FPReg_6_10, ap_Offset_16_31, ap_Reg_11_15}},
+ {LFSX, 0xfc0007fe, 0x7c00042e, 0x1, // Load Floating-Point Single Indexed X-form (lfsx FRT,RA,RB)
+ [5]*argField{ap_FPReg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {LFSUX, 0xfc0007fe, 0x7c00046e, 0x1, // Load Floating-Point Single with Update Indexed X-form (lfsux FRT,RA,RB)
+ [5]*argField{ap_FPReg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {LFD, 0xfc000000, 0xc8000000, 0x0, // Load Floating-Point Double D-form (lfd FRT,D(RA))
+ [5]*argField{ap_FPReg_6_10, ap_Offset_16_31, ap_Reg_11_15}},
+ {LFDU, 0xfc000000, 0xcc000000, 0x0, // Load Floating-Point Double with Update D-form (lfdu FRT,D(RA))
+ [5]*argField{ap_FPReg_6_10, ap_Offset_16_31, ap_Reg_11_15}},
+ {LFDX, 0xfc0007fe, 0x7c0004ae, 0x1, // Load Floating-Point Double Indexed X-form (lfdx FRT,RA,RB)
+ [5]*argField{ap_FPReg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {LFDUX, 0xfc0007fe, 0x7c0004ee, 0x1, // Load Floating-Point Double with Update Indexed X-form (lfdux FRT,RA,RB)
+ [5]*argField{ap_FPReg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {LFIWAX, 0xfc0007fe, 0x7c0006ae, 0x1, // Load Floating-Point as Integer Word Algebraic Indexed X-form (lfiwax FRT,RA,RB)
+ [5]*argField{ap_FPReg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {LFIWZX, 0xfc0007fe, 0x7c0006ee, 0x1, // Load Floating-Point as Integer Word and Zero Indexed X-form (lfiwzx FRT,RA,RB)
+ [5]*argField{ap_FPReg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {STFS, 0xfc000000, 0xd0000000, 0x0, // Store Floating-Point Single D-form (stfs FRS,D(RA))
+ [5]*argField{ap_FPReg_6_10, ap_Offset_16_31, ap_Reg_11_15}},
+ {STFSU, 0xfc000000, 0xd4000000, 0x0, // Store Floating-Point Single with Update D-form (stfsu FRS,D(RA))
+ [5]*argField{ap_FPReg_6_10, ap_Offset_16_31, ap_Reg_11_15}},
+ {STFSX, 0xfc0007fe, 0x7c00052e, 0x1, // Store Floating-Point Single Indexed X-form (stfsx FRS,RA,RB)
+ [5]*argField{ap_FPReg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {STFSUX, 0xfc0007fe, 0x7c00056e, 0x1, // Store Floating-Point Single with Update Indexed X-form (stfsux FRS,RA,RB)
+ [5]*argField{ap_FPReg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {STFD, 0xfc000000, 0xd8000000, 0x0, // Store Floating-Point Double D-form (stfd FRS,D(RA))
+ [5]*argField{ap_FPReg_6_10, ap_Offset_16_31, ap_Reg_11_15}},
+ {STFDU, 0xfc000000, 0xdc000000, 0x0, // Store Floating-Point Double with Update D-form (stfdu FRS,D(RA))
+ [5]*argField{ap_FPReg_6_10, ap_Offset_16_31, ap_Reg_11_15}},
+ {STFDX, 0xfc0007fe, 0x7c0005ae, 0x1, // Store Floating-Point Double Indexed X-form (stfdx FRS,RA,RB)
+ [5]*argField{ap_FPReg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {STFDUX, 0xfc0007fe, 0x7c0005ee, 0x1, // Store Floating-Point Double with Update Indexed X-form (stfdux FRS,RA,RB)
+ [5]*argField{ap_FPReg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {STFIWX, 0xfc0007fe, 0x7c0007ae, 0x1, // Store Floating-Point as Integer Word Indexed X-form (stfiwx FRS,RA,RB)
+ [5]*argField{ap_FPReg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {LFDP, 0xfc000003, 0xe4000000, 0x0, // Load Floating-Point Double Pair DS-form (lfdp FRTp,DS(RA))
+ [5]*argField{ap_FPReg_6_10, ap_Offset_16_29_shift2, ap_Reg_11_15}},
+ {LFDPX, 0xfc0007fe, 0x7c00062e, 0x1, // Load Floating-Point Double Pair Indexed X-form (lfdpx FRTp,RA,RB)
+ [5]*argField{ap_FPReg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {STFDP, 0xfc000003, 0xf4000000, 0x0, // Store Floating-Point Double Pair DS-form (stfdp FRSp,DS(RA))
+ [5]*argField{ap_FPReg_6_10, ap_Offset_16_29_shift2, ap_Reg_11_15}},
+ {STFDPX, 0xfc0007fe, 0x7c00072e, 0x1, // Store Floating-Point Double Pair Indexed X-form (stfdpx FRSp,RA,RB)
+ [5]*argField{ap_FPReg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {FMR, 0xfc0007ff, 0xfc000090, 0x1f0000, // Floating Move Register X-form (fmr FRT,FRB)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_16_20}},
+ {FMR_, 0xfc0007ff, 0xfc000091, 0x1f0000, // Floating Move Register X-form (fmr. FRT,FRB)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_16_20}},
+ {FABS, 0xfc0007ff, 0xfc000210, 0x1f0000, // Floating Absolute Value X-form (fabs FRT,FRB)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_16_20}},
+ {FABS_, 0xfc0007ff, 0xfc000211, 0x1f0000, // Floating Absolute Value X-form (fabs. FRT,FRB)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_16_20}},
+ {FNABS, 0xfc0007ff, 0xfc000110, 0x1f0000, // Floating Negative Absolute Value X-form (fnabs FRT,FRB)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_16_20}},
+ {FNABS_, 0xfc0007ff, 0xfc000111, 0x1f0000, // Floating Negative Absolute Value X-form (fnabs. FRT,FRB)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_16_20}},
+ {FNEG, 0xfc0007ff, 0xfc000050, 0x1f0000, // Floating Negate X-form (fneg FRT,FRB)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_16_20}},
+ {FNEG_, 0xfc0007ff, 0xfc000051, 0x1f0000, // Floating Negate X-form (fneg. FRT,FRB)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_16_20}},
+ {FCPSGN, 0xfc0007ff, 0xfc000010, 0x0, // Floating Copy Sign X-form (fcpsgn FRT, FRA, FRB)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_11_15, ap_FPReg_16_20}},
+ {FCPSGN_, 0xfc0007ff, 0xfc000011, 0x0, // Floating Copy Sign X-form (fcpsgn. FRT, FRA, FRB)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_11_15, ap_FPReg_16_20}},
+ {FMRGEW, 0xfc0007fe, 0xfc00078c, 0x1, // Floating Merge Even Word X-form (fmrgew FRT,FRA,FRB)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_11_15, ap_FPReg_16_20}},
+ {FMRGOW, 0xfc0007fe, 0xfc00068c, 0x1, // Floating Merge Odd Word X-form (fmrgow FRT,FRA,FRB)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_11_15, ap_FPReg_16_20}},
+ {FADD, 0xfc00003f, 0xfc00002a, 0x7c0, // Floating Add [Single] A-form (fadd FRT,FRA,FRB)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_11_15, ap_FPReg_16_20}},
+ {FADD_, 0xfc00003f, 0xfc00002b, 0x7c0, // Floating Add [Single] A-form (fadd. FRT,FRA,FRB)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_11_15, ap_FPReg_16_20}},
+ {FADDS, 0xfc00003f, 0xec00002a, 0x7c0, // Floating Add [Single] A-form (fadds FRT,FRA,FRB)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_11_15, ap_FPReg_16_20}},
+ {FADDS_, 0xfc00003f, 0xec00002b, 0x7c0, // Floating Add [Single] A-form (fadds. FRT,FRA,FRB)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_11_15, ap_FPReg_16_20}},
+ {FSUB, 0xfc00003f, 0xfc000028, 0x7c0, // Floating Subtract [Single] A-form (fsub FRT,FRA,FRB)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_11_15, ap_FPReg_16_20}},
+ {FSUB_, 0xfc00003f, 0xfc000029, 0x7c0, // Floating Subtract [Single] A-form (fsub. FRT,FRA,FRB)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_11_15, ap_FPReg_16_20}},
+ {FSUBS, 0xfc00003f, 0xec000028, 0x7c0, // Floating Subtract [Single] A-form (fsubs FRT,FRA,FRB)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_11_15, ap_FPReg_16_20}},
+ {FSUBS_, 0xfc00003f, 0xec000029, 0x7c0, // Floating Subtract [Single] A-form (fsubs. FRT,FRA,FRB)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_11_15, ap_FPReg_16_20}},
+ {FMUL, 0xfc00003f, 0xfc000032, 0xf800, // Floating Multiply [Single] A-form (fmul FRT,FRA,FRC)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_11_15, ap_FPReg_21_25}},
+ {FMUL_, 0xfc00003f, 0xfc000033, 0xf800, // Floating Multiply [Single] A-form (fmul. FRT,FRA,FRC)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_11_15, ap_FPReg_21_25}},
+ {FMULS, 0xfc00003f, 0xec000032, 0xf800, // Floating Multiply [Single] A-form (fmuls FRT,FRA,FRC)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_11_15, ap_FPReg_21_25}},
+ {FMULS_, 0xfc00003f, 0xec000033, 0xf800, // Floating Multiply [Single] A-form (fmuls. FRT,FRA,FRC)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_11_15, ap_FPReg_21_25}},
+ {FDIV, 0xfc00003f, 0xfc000024, 0x7c0, // Floating Divide [Single] A-form (fdiv FRT,FRA,FRB)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_11_15, ap_FPReg_16_20}},
+ {FDIV_, 0xfc00003f, 0xfc000025, 0x7c0, // Floating Divide [Single] A-form (fdiv. FRT,FRA,FRB)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_11_15, ap_FPReg_16_20}},
+ {FDIVS, 0xfc00003f, 0xec000024, 0x7c0, // Floating Divide [Single] A-form (fdivs FRT,FRA,FRB)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_11_15, ap_FPReg_16_20}},
+ {FDIVS_, 0xfc00003f, 0xec000025, 0x7c0, // Floating Divide [Single] A-form (fdivs. FRT,FRA,FRB)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_11_15, ap_FPReg_16_20}},
+ {FSQRT, 0xfc00003f, 0xfc00002c, 0x1f07c0, // Floating Square Root [Single] A-form (fsqrt FRT,FRB)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_16_20}},
+ {FSQRT_, 0xfc00003f, 0xfc00002d, 0x1f07c0, // Floating Square Root [Single] A-form (fsqrt. FRT,FRB)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_16_20}},
+ {FSQRTS, 0xfc00003f, 0xec00002c, 0x1f07c0, // Floating Square Root [Single] A-form (fsqrts FRT,FRB)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_16_20}},
+ {FSQRTS_, 0xfc00003f, 0xec00002d, 0x1f07c0, // Floating Square Root [Single] A-form (fsqrts. FRT,FRB)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_16_20}},
+ {FRE, 0xfc00003f, 0xfc000030, 0x1f07c0, // Floating Reciprocal Estimate [Single] A-form (fre FRT,FRB)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_16_20}},
+ {FRE_, 0xfc00003f, 0xfc000031, 0x1f07c0, // Floating Reciprocal Estimate [Single] A-form (fre. FRT,FRB)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_16_20}},
+ {FRES, 0xfc00003f, 0xec000030, 0x1f07c0, // Floating Reciprocal Estimate [Single] A-form (fres FRT,FRB)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_16_20}},
+ {FRES_, 0xfc00003f, 0xec000031, 0x1f07c0, // Floating Reciprocal Estimate [Single] A-form (fres. FRT,FRB)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_16_20}},
+ {FRSQRTE, 0xfc00003f, 0xfc000034, 0x1f07c0, // Floating Reciprocal Square Root Estimate [Single] A-form (frsqrte FRT,FRB)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_16_20}},
+ {FRSQRTE_, 0xfc00003f, 0xfc000035, 0x1f07c0, // Floating Reciprocal Square Root Estimate [Single] A-form (frsqrte. FRT,FRB)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_16_20}},
+ {FRSQRTES, 0xfc00003f, 0xec000034, 0x1f07c0, // Floating Reciprocal Square Root Estimate [Single] A-form (frsqrtes FRT,FRB)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_16_20}},
+ {FRSQRTES_, 0xfc00003f, 0xec000035, 0x1f07c0, // Floating Reciprocal Square Root Estimate [Single] A-form (frsqrtes. FRT,FRB)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_16_20}},
+ {FTDIV, 0xfc0007fe, 0xfc000100, 0x600001, // Floating Test for software Divide X-form (ftdiv BF,FRA,FRB)
+ [5]*argField{ap_CondRegField_6_8, ap_FPReg_11_15, ap_FPReg_16_20}},
+ {FTSQRT, 0xfc0007fe, 0xfc000140, 0x7f0001, // Floating Test for software Square Root X-form (ftsqrt BF,FRB)
+ [5]*argField{ap_CondRegField_6_8, ap_FPReg_16_20}},
+ {FMADD, 0xfc00003f, 0xfc00003a, 0x0, // Floating Multiply-Add [Single] A-form (fmadd FRT,FRA,FRC,FRB)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_11_15, ap_FPReg_21_25, ap_FPReg_16_20}},
+ {FMADD_, 0xfc00003f, 0xfc00003b, 0x0, // Floating Multiply-Add [Single] A-form (fmadd. FRT,FRA,FRC,FRB)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_11_15, ap_FPReg_21_25, ap_FPReg_16_20}},
+ {FMADDS, 0xfc00003f, 0xec00003a, 0x0, // Floating Multiply-Add [Single] A-form (fmadds FRT,FRA,FRC,FRB)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_11_15, ap_FPReg_21_25, ap_FPReg_16_20}},
+ {FMADDS_, 0xfc00003f, 0xec00003b, 0x0, // Floating Multiply-Add [Single] A-form (fmadds. FRT,FRA,FRC,FRB)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_11_15, ap_FPReg_21_25, ap_FPReg_16_20}},
+ {FMSUB, 0xfc00003f, 0xfc000038, 0x0, // Floating Multiply-Subtract [Single] A-form (fmsub FRT,FRA,FRC,FRB)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_11_15, ap_FPReg_21_25, ap_FPReg_16_20}},
+ {FMSUB_, 0xfc00003f, 0xfc000039, 0x0, // Floating Multiply-Subtract [Single] A-form (fmsub. FRT,FRA,FRC,FRB)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_11_15, ap_FPReg_21_25, ap_FPReg_16_20}},
+ {FMSUBS, 0xfc00003f, 0xec000038, 0x0, // Floating Multiply-Subtract [Single] A-form (fmsubs FRT,FRA,FRC,FRB)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_11_15, ap_FPReg_21_25, ap_FPReg_16_20}},
+ {FMSUBS_, 0xfc00003f, 0xec000039, 0x0, // Floating Multiply-Subtract [Single] A-form (fmsubs. FRT,FRA,FRC,FRB)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_11_15, ap_FPReg_21_25, ap_FPReg_16_20}},
+ {FNMADD, 0xfc00003f, 0xfc00003e, 0x0, // Floating Negative Multiply-Add [Single] A-form (fnmadd FRT,FRA,FRC,FRB)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_11_15, ap_FPReg_21_25, ap_FPReg_16_20}},
+ {FNMADD_, 0xfc00003f, 0xfc00003f, 0x0, // Floating Negative Multiply-Add [Single] A-form (fnmadd. FRT,FRA,FRC,FRB)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_11_15, ap_FPReg_21_25, ap_FPReg_16_20}},
+ {FNMADDS, 0xfc00003f, 0xec00003e, 0x0, // Floating Negative Multiply-Add [Single] A-form (fnmadds FRT,FRA,FRC,FRB)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_11_15, ap_FPReg_21_25, ap_FPReg_16_20}},
+ {FNMADDS_, 0xfc00003f, 0xec00003f, 0x0, // Floating Negative Multiply-Add [Single] A-form (fnmadds. FRT,FRA,FRC,FRB)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_11_15, ap_FPReg_21_25, ap_FPReg_16_20}},
+ {FNMSUB, 0xfc00003f, 0xfc00003c, 0x0, // Floating Negative Multiply-Subtract [Single] A-form (fnmsub FRT,FRA,FRC,FRB)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_11_15, ap_FPReg_21_25, ap_FPReg_16_20}},
+ {FNMSUB_, 0xfc00003f, 0xfc00003d, 0x0, // Floating Negative Multiply-Subtract [Single] A-form (fnmsub. FRT,FRA,FRC,FRB)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_11_15, ap_FPReg_21_25, ap_FPReg_16_20}},
+ {FNMSUBS, 0xfc00003f, 0xec00003c, 0x0, // Floating Negative Multiply-Subtract [Single] A-form (fnmsubs FRT,FRA,FRC,FRB)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_11_15, ap_FPReg_21_25, ap_FPReg_16_20}},
+ {FNMSUBS_, 0xfc00003f, 0xec00003d, 0x0, // Floating Negative Multiply-Subtract [Single] A-form (fnmsubs. FRT,FRA,FRC,FRB)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_11_15, ap_FPReg_21_25, ap_FPReg_16_20}},
+ {FRSP, 0xfc0007ff, 0xfc000018, 0x1f0000, // Floating Round to Single-Precision X-form (frsp FRT,FRB)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_16_20}},
+ {FRSP_, 0xfc0007ff, 0xfc000019, 0x1f0000, // Floating Round to Single-Precision X-form (frsp. FRT,FRB)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_16_20}},
+ {FCTID, 0xfc0007ff, 0xfc00065c, 0x1f0000, // Floating Convert To Integer Doubleword X-form (fctid FRT,FRB)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_16_20}},
+ {FCTID_, 0xfc0007ff, 0xfc00065d, 0x1f0000, // Floating Convert To Integer Doubleword X-form (fctid. FRT,FRB)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_16_20}},
+ {FCTIDZ, 0xfc0007ff, 0xfc00065e, 0x1f0000, // Floating Convert To Integer Doubleword with round toward Zero X-form (fctidz FRT,FRB)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_16_20}},
+ {FCTIDZ_, 0xfc0007ff, 0xfc00065f, 0x1f0000, // Floating Convert To Integer Doubleword with round toward Zero X-form (fctidz. FRT,FRB)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_16_20}},
+ {FCTIDU, 0xfc0007ff, 0xfc00075c, 0x1f0000, // Floating Convert To Integer Doubleword Unsigned X-form (fctidu FRT,FRB)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_16_20}},
+ {FCTIDU_, 0xfc0007ff, 0xfc00075d, 0x1f0000, // Floating Convert To Integer Doubleword Unsigned X-form (fctidu. FRT,FRB)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_16_20}},
+ {FCTIDUZ, 0xfc0007ff, 0xfc00075e, 0x1f0000, // Floating Convert To Integer Doubleword Unsigned with round toward Zero X-form (fctiduz FRT,FRB)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_16_20}},
+ {FCTIDUZ_, 0xfc0007ff, 0xfc00075f, 0x1f0000, // Floating Convert To Integer Doubleword Unsigned with round toward Zero X-form (fctiduz. FRT,FRB)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_16_20}},
+ {FCTIW, 0xfc0007ff, 0xfc00001c, 0x1f0000, // Floating Convert To Integer Word X-form (fctiw FRT,FRB)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_16_20}},
+ {FCTIW_, 0xfc0007ff, 0xfc00001d, 0x1f0000, // Floating Convert To Integer Word X-form (fctiw. FRT,FRB)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_16_20}},
+ {FCTIWZ, 0xfc0007ff, 0xfc00001e, 0x1f0000, // Floating Convert To Integer Word with round toward Zero X-form (fctiwz FRT,FRB)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_16_20}},
+ {FCTIWZ_, 0xfc0007ff, 0xfc00001f, 0x1f0000, // Floating Convert To Integer Word with round toward Zero X-form (fctiwz. FRT,FRB)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_16_20}},
+ {FCTIWU, 0xfc0007ff, 0xfc00011c, 0x1f0000, // Floating Convert To Integer Word Unsigned X-form (fctiwu FRT,FRB)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_16_20}},
+ {FCTIWU_, 0xfc0007ff, 0xfc00011d, 0x1f0000, // Floating Convert To Integer Word Unsigned X-form (fctiwu. FRT,FRB)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_16_20}},
+ {FCTIWUZ, 0xfc0007ff, 0xfc00011e, 0x1f0000, // Floating Convert To Integer Word Unsigned with round toward Zero X-form (fctiwuz FRT,FRB)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_16_20}},
+ {FCTIWUZ_, 0xfc0007ff, 0xfc00011f, 0x1f0000, // Floating Convert To Integer Word Unsigned with round toward Zero X-form (fctiwuz. FRT,FRB)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_16_20}},
+ {FCFID, 0xfc0007ff, 0xfc00069c, 0x1f0000, // Floating Convert From Integer Doubleword X-form (fcfid FRT,FRB)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_16_20}},
+ {FCFID_, 0xfc0007ff, 0xfc00069d, 0x1f0000, // Floating Convert From Integer Doubleword X-form (fcfid. FRT,FRB)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_16_20}},
+ {FCFIDU, 0xfc0007ff, 0xfc00079c, 0x1f0000, // Floating Convert From Integer Doubleword Unsigned X-form (fcfidu FRT,FRB)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_16_20}},
+ {FCFIDU_, 0xfc0007ff, 0xfc00079d, 0x1f0000, // Floating Convert From Integer Doubleword Unsigned X-form (fcfidu. FRT,FRB)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_16_20}},
+ {FCFIDS, 0xfc0007ff, 0xec00069c, 0x1f0000, // Floating Convert From Integer Doubleword Single X-form (fcfids FRT,FRB)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_16_20}},
+ {FCFIDS_, 0xfc0007ff, 0xec00069d, 0x1f0000, // Floating Convert From Integer Doubleword Single X-form (fcfids. FRT,FRB)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_16_20}},
+ {FCFIDUS, 0xfc0007ff, 0xec00079c, 0x1f0000, // Floating Convert From Integer Doubleword Unsigned Single X-form (fcfidus FRT,FRB)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_16_20}},
+ {FCFIDUS_, 0xfc0007ff, 0xec00079d, 0x1f0000, // Floating Convert From Integer Doubleword Unsigned Single X-form (fcfidus. FRT,FRB)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_16_20}},
+ {FRIN, 0xfc0007ff, 0xfc000310, 0x1f0000, // Floating Round to Integer Nearest X-form (frin FRT,FRB)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_16_20}},
+ {FRIN_, 0xfc0007ff, 0xfc000311, 0x1f0000, // Floating Round to Integer Nearest X-form (frin. FRT,FRB)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_16_20}},
+ {FRIZ, 0xfc0007ff, 0xfc000350, 0x1f0000, // Floating Round to Integer Toward Zero X-form (friz FRT,FRB)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_16_20}},
+ {FRIZ_, 0xfc0007ff, 0xfc000351, 0x1f0000, // Floating Round to Integer Toward Zero X-form (friz. FRT,FRB)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_16_20}},
+ {FRIP, 0xfc0007ff, 0xfc000390, 0x1f0000, // Floating Round to Integer Plus X-form (frip FRT,FRB)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_16_20}},
+ {FRIP_, 0xfc0007ff, 0xfc000391, 0x1f0000, // Floating Round to Integer Plus X-form (frip. FRT,FRB)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_16_20}},
+ {FRIM, 0xfc0007ff, 0xfc0003d0, 0x1f0000, // Floating Round to Integer Minus X-form (frim FRT,FRB)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_16_20}},
+ {FRIM_, 0xfc0007ff, 0xfc0003d1, 0x1f0000, // Floating Round to Integer Minus X-form (frim. FRT,FRB)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_16_20}},
+ {FCMPU, 0xfc0007fe, 0xfc000000, 0x600001, // Floating Compare Unordered X-form (fcmpu BF,FRA,FRB)
+ [5]*argField{ap_CondRegField_6_8, ap_FPReg_11_15, ap_FPReg_16_20}},
+ {FCMPO, 0xfc0007fe, 0xfc000040, 0x600001, // Floating Compare Ordered X-form (fcmpo BF,FRA,FRB)
+ [5]*argField{ap_CondRegField_6_8, ap_FPReg_11_15, ap_FPReg_16_20}},
+ {FSEL, 0xfc00003f, 0xfc00002e, 0x0, // Floating Select A-form (fsel FRT,FRA,FRC,FRB)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_11_15, ap_FPReg_21_25, ap_FPReg_16_20}},
+ {FSEL_, 0xfc00003f, 0xfc00002f, 0x0, // Floating Select A-form (fsel. FRT,FRA,FRC,FRB)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_11_15, ap_FPReg_21_25, ap_FPReg_16_20}},
+ {MFFS, 0xfc0007ff, 0xfc00048e, 0x1ff800, // Move From FPSCR X-form (mffs FRT)
+ [5]*argField{ap_FPReg_6_10}},
+ {MFFS_, 0xfc0007ff, 0xfc00048f, 0x1ff800, // Move From FPSCR X-form (mffs. FRT)
+ [5]*argField{ap_FPReg_6_10}},
+ {MCRFS, 0xfc0007fe, 0xfc000080, 0x63f801, // Move to Condition Register from FPSCR X-form (mcrfs BF,BFA)
+ [5]*argField{ap_CondRegField_6_8, ap_CondRegField_11_13}},
+ {MTFSFI, 0xfc0007ff, 0xfc00010c, 0x7e0800, // Move To FPSCR Field Immediate X-form (mtfsfi BF,U,W)
+ [5]*argField{ap_CondRegField_6_8, ap_ImmUnsigned_16_19, ap_ImmUnsigned_15_15}},
+ {MTFSFI_, 0xfc0007ff, 0xfc00010d, 0x7e0800, // Move To FPSCR Field Immediate X-form (mtfsfi. BF,U,W)
+ [5]*argField{ap_CondRegField_6_8, ap_ImmUnsigned_16_19, ap_ImmUnsigned_15_15}},
+ {MTFSF, 0xfc0007ff, 0xfc00058e, 0x0, // Move To FPSCR Fields XFL-form (mtfsf FLM,FRB,L,W)
+ [5]*argField{ap_ImmUnsigned_7_14, ap_FPReg_16_20, ap_ImmUnsigned_6_6, ap_ImmUnsigned_15_15}},
+ {MTFSF_, 0xfc0007ff, 0xfc00058f, 0x0, // Move To FPSCR Fields XFL-form (mtfsf. FLM,FRB,L,W)
+ [5]*argField{ap_ImmUnsigned_7_14, ap_FPReg_16_20, ap_ImmUnsigned_6_6, ap_ImmUnsigned_15_15}},
+ {MTFSB0, 0xfc0007ff, 0xfc00008c, 0x1ff800, // Move To FPSCR Bit 0 X-form (mtfsb0 BT)
+ [5]*argField{ap_CondRegBit_6_10}},
+ {MTFSB0_, 0xfc0007ff, 0xfc00008d, 0x1ff800, // Move To FPSCR Bit 0 X-form (mtfsb0. BT)
+ [5]*argField{ap_CondRegBit_6_10}},
+ {MTFSB1, 0xfc0007ff, 0xfc00004c, 0x1ff800, // Move To FPSCR Bit 1 X-form (mtfsb1 BT)
+ [5]*argField{ap_CondRegBit_6_10}},
+ {MTFSB1_, 0xfc0007ff, 0xfc00004d, 0x1ff800, // Move To FPSCR Bit 1 X-form (mtfsb1. BT)
+ [5]*argField{ap_CondRegBit_6_10}},
+ {LVEBX, 0xfc0007fe, 0x7c00000e, 0x1, // Load Vector Element Byte Indexed X-form (lvebx VRT,RA,RB)
+ [5]*argField{ap_VecReg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {LVEHX, 0xfc0007fe, 0x7c00004e, 0x1, // Load Vector Element Halfword Indexed X-form (lvehx VRT,RA,RB)
+ [5]*argField{ap_VecReg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {LVEWX, 0xfc0007fe, 0x7c00008e, 0x1, // Load Vector Element Word Indexed X-form (lvewx VRT,RA,RB)
+ [5]*argField{ap_VecReg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {LVX, 0xfc0007fe, 0x7c0000ce, 0x1, // Load Vector Indexed X-form (lvx VRT,RA,RB)
+ [5]*argField{ap_VecReg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {LVXL, 0xfc0007fe, 0x7c0002ce, 0x1, // Load Vector Indexed LRU X-form (lvxl VRT,RA,RB)
+ [5]*argField{ap_VecReg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {STVEBX, 0xfc0007fe, 0x7c00010e, 0x1, // Store Vector Element Byte Indexed X-form (stvebx VRS,RA,RB)
+ [5]*argField{ap_VecReg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {STVEHX, 0xfc0007fe, 0x7c00014e, 0x1, // Store Vector Element Halfword Indexed X-form (stvehx VRS,RA,RB)
+ [5]*argField{ap_VecReg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {STVEWX, 0xfc0007fe, 0x7c00018e, 0x1, // Store Vector Element Word Indexed X-form (stvewx VRS,RA,RB)
+ [5]*argField{ap_VecReg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {STVX, 0xfc0007fe, 0x7c0001ce, 0x1, // Store Vector Indexed X-form (stvx VRS,RA,RB)
+ [5]*argField{ap_VecReg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {STVXL, 0xfc0007fe, 0x7c0003ce, 0x1, // Store Vector Indexed LRU X-form (stvxl VRS,RA,RB)
+ [5]*argField{ap_VecReg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {LVSL, 0xfc0007fe, 0x7c00000c, 0x1, // Load Vector for Shift Left Indexed X-form (lvsl VRT,RA,RB)
+ [5]*argField{ap_VecReg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {LVSR, 0xfc0007fe, 0x7c00004c, 0x1, // Load Vector for Shift Right Indexed X-form (lvsr VRT,RA,RB)
+ [5]*argField{ap_VecReg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {VPKPX, 0xfc0007ff, 0x1000030e, 0x0, // Vector Pack Pixel VX-form (vpkpx VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VPKSDSS, 0xfc0007ff, 0x100005ce, 0x0, // Vector Pack Signed Doubleword Signed Saturate VX-form (vpksdss VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VPKSDUS, 0xfc0007ff, 0x1000054e, 0x0, // Vector Pack Signed Doubleword Unsigned Saturate VX-form (vpksdus VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VPKSHSS, 0xfc0007ff, 0x1000018e, 0x0, // Vector Pack Signed Halfword Signed Saturate VX-form (vpkshss VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VPKSHUS, 0xfc0007ff, 0x1000010e, 0x0, // Vector Pack Signed Halfword Unsigned Saturate VX-form (vpkshus VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VPKSWSS, 0xfc0007ff, 0x100001ce, 0x0, // Vector Pack Signed Word Signed Saturate VX-form (vpkswss VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VPKSWUS, 0xfc0007ff, 0x1000014e, 0x0, // Vector Pack Signed Word Unsigned Saturate VX-form (vpkswus VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VPKUDUM, 0xfc0007ff, 0x1000044e, 0x0, // Vector Pack Unsigned Doubleword Unsigned Modulo VX-form (vpkudum VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VPKUDUS, 0xfc0007ff, 0x100004ce, 0x0, // Vector Pack Unsigned Doubleword Unsigned Saturate VX-form (vpkudus VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VPKUHUM, 0xfc0007ff, 0x1000000e, 0x0, // Vector Pack Unsigned Halfword Unsigned Modulo VX-form (vpkuhum VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VPKUHUS, 0xfc0007ff, 0x1000008e, 0x0, // Vector Pack Unsigned Halfword Unsigned Saturate VX-form (vpkuhus VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VPKUWUM, 0xfc0007ff, 0x1000004e, 0x0, // Vector Pack Unsigned Word Unsigned Modulo VX-form (vpkuwum VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VPKUWUS, 0xfc0007ff, 0x100000ce, 0x0, // Vector Pack Unsigned Word Unsigned Saturate VX-form (vpkuwus VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VUPKHPX, 0xfc0007ff, 0x1000034e, 0x1f0000, // Vector Unpack High Pixel VX-form (vupkhpx VRT,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_16_20}},
+ {VUPKLPX, 0xfc0007ff, 0x100003ce, 0x1f0000, // Vector Unpack Low Pixel VX-form (vupklpx VRT,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_16_20}},
+ {VUPKHSB, 0xfc0007ff, 0x1000020e, 0x1f0000, // Vector Unpack High Signed Byte VX-form (vupkhsb VRT,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_16_20}},
+ {VUPKHSH, 0xfc0007ff, 0x1000024e, 0x1f0000, // Vector Unpack High Signed Halfword VX-form (vupkhsh VRT,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_16_20}},
+ {VUPKHSW, 0xfc0007ff, 0x1000064e, 0x1f0000, // Vector Unpack High Signed Word VX-form (vupkhsw VRT,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_16_20}},
+ {VUPKLSB, 0xfc0007ff, 0x1000028e, 0x1f0000, // Vector Unpack Low Signed Byte VX-form (vupklsb VRT,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_16_20}},
+ {VUPKLSH, 0xfc0007ff, 0x100002ce, 0x1f0000, // Vector Unpack Low Signed Halfword VX-form (vupklsh VRT,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_16_20}},
+ {VUPKLSW, 0xfc0007ff, 0x100006ce, 0x1f0000, // Vector Unpack Low Signed Word VX-form (vupklsw VRT,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_16_20}},
+ {VMRGHB, 0xfc0007ff, 0x1000000c, 0x0, // Vector Merge High Byte VX-form (vmrghb VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VMRGHH, 0xfc0007ff, 0x1000004c, 0x0, // Vector Merge High Halfword VX-form (vmrghh VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VMRGLB, 0xfc0007ff, 0x1000010c, 0x0, // Vector Merge Low Byte VX-form (vmrglb VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VMRGLH, 0xfc0007ff, 0x1000014c, 0x0, // Vector Merge Low Halfword VX-form (vmrglh VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VMRGHW, 0xfc0007ff, 0x1000008c, 0x0, // Vector Merge High Word VX-form (vmrghw VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VMRGLW, 0xfc0007ff, 0x1000018c, 0x0, // Vector Merge Low Word VX-form (vmrglw VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VMRGEW, 0xfc0007ff, 0x1000078c, 0x0, // Vector Merge Even Word VX-form (vmrgew VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VMRGOW, 0xfc0007ff, 0x1000068c, 0x0, // Vector Merge Odd Word VX-form (vmrgow VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VSPLTB, 0xfc0007ff, 0x1000020c, 0x100000, // Vector Splat Byte VX-form (vspltb VRT,VRB,UIM)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_16_20, ap_ImmUnsigned_12_15}},
+ {VSPLTH, 0xfc0007ff, 0x1000024c, 0x180000, // Vector Splat Halfword VX-form (vsplth VRT,VRB,UIM)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_16_20, ap_ImmUnsigned_13_15}},
+ {VSPLTW, 0xfc0007ff, 0x1000028c, 0x1c0000, // Vector Splat Word VX-form (vspltw VRT,VRB,UIM)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_16_20, ap_ImmUnsigned_14_15}},
+ {VSPLTISB, 0xfc0007ff, 0x1000030c, 0xf800, // Vector Splat Immediate Signed Byte VX-form (vspltisb VRT,SIM)
+ [5]*argField{ap_VecReg_6_10, ap_ImmSigned_11_15}},
+ {VSPLTISH, 0xfc0007ff, 0x1000034c, 0xf800, // Vector Splat Immediate Signed Halfword VX-form (vspltish VRT,SIM)
+ [5]*argField{ap_VecReg_6_10, ap_ImmSigned_11_15}},
+ {VSPLTISW, 0xfc0007ff, 0x1000038c, 0xf800, // Vector Splat Immediate Signed Word VX-form (vspltisw VRT,SIM)
+ [5]*argField{ap_VecReg_6_10, ap_ImmSigned_11_15}},
+ {VPERM, 0xfc00003f, 0x1000002b, 0x0, // Vector Permute VA-form (vperm VRT,VRA,VRB,VRC)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20, ap_VecReg_21_25}},
+ {VSEL, 0xfc00003f, 0x1000002a, 0x0, // Vector Select VA-form (vsel VRT,VRA,VRB,VRC)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20, ap_VecReg_21_25}},
+ {VSL, 0xfc0007ff, 0x100001c4, 0x0, // Vector Shift Left VX-form (vsl VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VSLDOI, 0xfc00003f, 0x1000002c, 0x400, // Vector Shift Left Double by Octet Immediate VA-form (vsldoi VRT,VRA,VRB,SHB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20, ap_ImmUnsigned_22_25}},
+ {VSLO, 0xfc0007ff, 0x1000040c, 0x0, // Vector Shift Left by Octet VX-form (vslo VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VSR, 0xfc0007ff, 0x100002c4, 0x0, // Vector Shift Right VX-form (vsr VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VSRO, 0xfc0007ff, 0x1000044c, 0x0, // Vector Shift Right by Octet VX-form (vsro VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VADDCUW, 0xfc0007ff, 0x10000180, 0x0, // Vector Add and Write Carry-Out Unsigned Word VX-form (vaddcuw VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VADDSBS, 0xfc0007ff, 0x10000300, 0x0, // Vector Add Signed Byte Saturate VX-form (vaddsbs VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VADDSHS, 0xfc0007ff, 0x10000340, 0x0, // Vector Add Signed Halfword Saturate VX-form (vaddshs VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VADDSWS, 0xfc0007ff, 0x10000380, 0x0, // Vector Add Signed Word Saturate VX-form (vaddsws VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VADDUBM, 0xfc0007ff, 0x10000000, 0x0, // Vector Add Unsigned Byte Modulo VX-form (vaddubm VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VADDUDM, 0xfc0007ff, 0x100000c0, 0x0, // Vector Add Unsigned Doubleword Modulo VX-form (vaddudm VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VADDUHM, 0xfc0007ff, 0x10000040, 0x0, // Vector Add Unsigned Halfword Modulo VX-form (vadduhm VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VADDUWM, 0xfc0007ff, 0x10000080, 0x0, // Vector Add Unsigned Word Modulo VX-form (vadduwm VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VADDUBS, 0xfc0007ff, 0x10000200, 0x0, // Vector Add Unsigned Byte Saturate VX-form (vaddubs VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VADDUHS, 0xfc0007ff, 0x10000240, 0x0, // Vector Add Unsigned Halfword Saturate VX-form (vadduhs VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VADDUWS, 0xfc0007ff, 0x10000280, 0x0, // Vector Add Unsigned Word Saturate VX-form (vadduws VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VADDUQM, 0xfc0007ff, 0x10000100, 0x0, // Vector Add Unsigned Quadword Modulo VX-form (vadduqm VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VADDEUQM, 0xfc00003f, 0x1000003c, 0x0, // Vector Add Extended Unsigned Quadword Modulo VA-form (vaddeuqm VRT,VRA,VRB,VRC)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20, ap_VecReg_21_25}},
+ {VADDCUQ, 0xfc0007ff, 0x10000140, 0x0, // Vector Add & write Carry Unsigned Quadword VX-form (vaddcuq VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VADDECUQ, 0xfc00003f, 0x1000003d, 0x0, // Vector Add Extended & write Carry Unsigned Quadword VA-form (vaddecuq VRT,VRA,VRB,VRC)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20, ap_VecReg_21_25}},
+ {VSUBCUW, 0xfc0007ff, 0x10000580, 0x0, // Vector Subtract and Write Carry-Out Unsigned Word VX-form (vsubcuw VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VSUBSBS, 0xfc0007ff, 0x10000700, 0x0, // Vector Subtract Signed Byte Saturate VX-form (vsubsbs VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VSUBSHS, 0xfc0007ff, 0x10000740, 0x0, // Vector Subtract Signed Halfword Saturate VX-form (vsubshs VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VSUBSWS, 0xfc0007ff, 0x10000780, 0x0, // Vector Subtract Signed Word Saturate VX-form (vsubsws VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VSUBUBM, 0xfc0007ff, 0x10000400, 0x0, // Vector Subtract Unsigned Byte Modulo VX-form (vsububm VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VSUBUDM, 0xfc0007ff, 0x100004c0, 0x0, // Vector Subtract Unsigned Doubleword Modulo VX-form (vsubudm VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VSUBUHM, 0xfc0007ff, 0x10000440, 0x0, // Vector Subtract Unsigned Halfword Modulo VX-form (vsubuhm VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VSUBUWM, 0xfc0007ff, 0x10000480, 0x0, // Vector Subtract Unsigned Word Modulo VX-form (vsubuwm VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VSUBUBS, 0xfc0007ff, 0x10000600, 0x0, // Vector Subtract Unsigned Byte Saturate VX-form (vsububs VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VSUBUHS, 0xfc0007ff, 0x10000640, 0x0, // Vector Subtract Unsigned Halfword Saturate VX-form (vsubuhs VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VSUBUWS, 0xfc0007ff, 0x10000680, 0x0, // Vector Subtract Unsigned Word Saturate VX-form (vsubuws VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VSUBUQM, 0xfc0007ff, 0x10000500, 0x0, // Vector Subtract Unsigned Quadword Modulo VX-form (vsubuqm VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VSUBEUQM, 0xfc00003f, 0x1000003e, 0x0, // Vector Subtract Extended Unsigned Quadword Modulo VA-form (vsubeuqm VRT,VRA,VRB,VRC)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20, ap_VecReg_21_25}},
+ {VSUBCUQ, 0xfc0007ff, 0x10000540, 0x0, // Vector Subtract & write Carry Unsigned Quadword VX-form (vsubcuq VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VSUBECUQ, 0xfc00003f, 0x1000003f, 0x0, // Vector Subtract Extended & write Carry Unsigned Quadword VA-form (vsubecuq VRT,VRA,VRB,VRC)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20, ap_VecReg_21_25}},
+ {VMULESB, 0xfc0007ff, 0x10000308, 0x0, // Vector Multiply Even Signed Byte VX-form (vmulesb VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VMULEUB, 0xfc0007ff, 0x10000208, 0x0, // Vector Multiply Even Unsigned Byte VX-form (vmuleub VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VMULOSB, 0xfc0007ff, 0x10000108, 0x0, // Vector Multiply Odd Signed Byte VX-form (vmulosb VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VMULOUB, 0xfc0007ff, 0x10000008, 0x0, // Vector Multiply Odd Unsigned Byte VX-form (vmuloub VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VMULESH, 0xfc0007ff, 0x10000348, 0x0, // Vector Multiply Even Signed Halfword VX-form (vmulesh VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VMULEUH, 0xfc0007ff, 0x10000248, 0x0, // Vector Multiply Even Unsigned Halfword VX-form (vmuleuh VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VMULOSH, 0xfc0007ff, 0x10000148, 0x0, // Vector Multiply Odd Signed Halfword VX-form (vmulosh VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VMULOUH, 0xfc0007ff, 0x10000048, 0x0, // Vector Multiply Odd Unsigned Halfword VX-form (vmulouh VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VMULESW, 0xfc0007ff, 0x10000388, 0x0, // Vector Multiply Even Signed Word VX-form (vmulesw VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VMULEUW, 0xfc0007ff, 0x10000288, 0x0, // Vector Multiply Even Unsigned Word VX-form (vmuleuw VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VMULOSW, 0xfc0007ff, 0x10000188, 0x0, // Vector Multiply Odd Signed Word VX-form (vmulosw VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VMULOUW, 0xfc0007ff, 0x10000088, 0x0, // Vector Multiply Odd Unsigned Word VX-form (vmulouw VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VMULUWM, 0xfc0007ff, 0x10000089, 0x0, // Vector Multiply Unsigned Word Modulo VX-form (vmuluwm VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VMHADDSHS, 0xfc00003f, 0x10000020, 0x0, // Vector Multiply-High-Add Signed Halfword Saturate VA-form (vmhaddshs VRT,VRA,VRB,VRC)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20, ap_VecReg_21_25}},
+ {VMHRADDSHS, 0xfc00003f, 0x10000021, 0x0, // Vector Multiply-High-Round-Add Signed Halfword Saturate VA-form (vmhraddshs VRT,VRA,VRB,VRC)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20, ap_VecReg_21_25}},
+ {VMLADDUHM, 0xfc00003f, 0x10000022, 0x0, // Vector Multiply-Low-Add Unsigned Halfword Modulo VA-form (vmladduhm VRT,VRA,VRB,VRC)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20, ap_VecReg_21_25}},
+ {VMSUMUBM, 0xfc00003f, 0x10000024, 0x0, // Vector Multiply-Sum Unsigned Byte Modulo VA-form (vmsumubm VRT,VRA,VRB,VRC)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20, ap_VecReg_21_25}},
+ {VMSUMMBM, 0xfc00003f, 0x10000025, 0x0, // Vector Multiply-Sum Mixed Byte Modulo VA-form (vmsummbm VRT,VRA,VRB,VRC)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20, ap_VecReg_21_25}},
+ {VMSUMSHM, 0xfc00003f, 0x10000028, 0x0, // Vector Multiply-Sum Signed Halfword Modulo VA-form (vmsumshm VRT,VRA,VRB,VRC)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20, ap_VecReg_21_25}},
+ {VMSUMSHS, 0xfc00003f, 0x10000029, 0x0, // Vector Multiply-Sum Signed Halfword Saturate VA-form (vmsumshs VRT,VRA,VRB,VRC)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20, ap_VecReg_21_25}},
+ {VMSUMUHM, 0xfc00003f, 0x10000026, 0x0, // Vector Multiply-Sum Unsigned Halfword Modulo VA-form (vmsumuhm VRT,VRA,VRB,VRC)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20, ap_VecReg_21_25}},
+ {VMSUMUHS, 0xfc00003f, 0x10000027, 0x0, // Vector Multiply-Sum Unsigned Halfword Saturate VA-form (vmsumuhs VRT,VRA,VRB,VRC)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20, ap_VecReg_21_25}},
+ {VSUMSWS, 0xfc0007ff, 0x10000788, 0x0, // Vector Sum across Signed Word Saturate VX-form (vsumsws VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VSUM2SWS, 0xfc0007ff, 0x10000688, 0x0, // Vector Sum across Half Signed Word Saturate VX-form (vsum2sws VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VSUM4SBS, 0xfc0007ff, 0x10000708, 0x0, // Vector Sum across Quarter Signed Byte Saturate VX-form (vsum4sbs VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VSUM4SHS, 0xfc0007ff, 0x10000648, 0x0, // Vector Sum across Quarter Signed Halfword Saturate VX-form (vsum4shs VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VSUM4UBS, 0xfc0007ff, 0x10000608, 0x0, // Vector Sum across Quarter Unsigned Byte Saturate VX-form (vsum4ubs VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VAVGSB, 0xfc0007ff, 0x10000502, 0x0, // Vector Average Signed Byte VX-form (vavgsb VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VAVGSH, 0xfc0007ff, 0x10000542, 0x0, // Vector Average Signed Halfword VX-form (vavgsh VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VAVGSW, 0xfc0007ff, 0x10000582, 0x0, // Vector Average Signed Word VX-form (vavgsw VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VAVGUB, 0xfc0007ff, 0x10000402, 0x0, // Vector Average Unsigned Byte VX-form (vavgub VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VAVGUW, 0xfc0007ff, 0x10000482, 0x0, // Vector Average Unsigned Word VX-form (vavguw VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VAVGUH, 0xfc0007ff, 0x10000442, 0x0, // Vector Average Unsigned Halfword VX-form (vavguh VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VMAXSB, 0xfc0007ff, 0x10000102, 0x0, // Vector Maximum Signed Byte VX-form (vmaxsb VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VMAXSD, 0xfc0007ff, 0x100001c2, 0x0, // Vector Maximum Signed Doubleword VX-form (vmaxsd VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VMAXUB, 0xfc0007ff, 0x10000002, 0x0, // Vector Maximum Unsigned Byte VX-form (vmaxub VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VMAXUD, 0xfc0007ff, 0x100000c2, 0x0, // Vector Maximum Unsigned Doubleword VX-form (vmaxud VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VMAXSH, 0xfc0007ff, 0x10000142, 0x0, // Vector Maximum Signed Halfword VX-form (vmaxsh VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VMAXSW, 0xfc0007ff, 0x10000182, 0x0, // Vector Maximum Signed Word VX-form (vmaxsw VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VMAXUH, 0xfc0007ff, 0x10000042, 0x0, // Vector Maximum Unsigned Halfword VX-form (vmaxuh VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VMAXUW, 0xfc0007ff, 0x10000082, 0x0, // Vector Maximum Unsigned Word VX-form (vmaxuw VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VMINSB, 0xfc0007ff, 0x10000302, 0x0, // Vector Minimum Signed Byte VX-form (vminsb VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VMINSD, 0xfc0007ff, 0x100003c2, 0x0, // Vector Minimum Signed Doubleword VX-form (vminsd VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VMINUB, 0xfc0007ff, 0x10000202, 0x0, // Vector Minimum Unsigned Byte VX-form (vminub VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VMINUD, 0xfc0007ff, 0x100002c2, 0x0, // Vector Minimum Unsigned Doubleword VX-form (vminud VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VMINSH, 0xfc0007ff, 0x10000342, 0x0, // Vector Minimum Signed Halfword VX-form (vminsh VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VMINSW, 0xfc0007ff, 0x10000382, 0x0, // Vector Minimum Signed Word VX-form (vminsw VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VMINUH, 0xfc0007ff, 0x10000242, 0x0, // Vector Minimum Unsigned Halfword VX-form (vminuh VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VMINUW, 0xfc0007ff, 0x10000282, 0x0, // Vector Minimum Unsigned Word VX-form (vminuw VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VCMPEQUB, 0xfc0007ff, 0x10000006, 0x0, // Vector Compare Equal To Unsigned Byte VC-form (vcmpequb VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VCMPEQUB_, 0xfc0007ff, 0x10000406, 0x0, // Vector Compare Equal To Unsigned Byte VC-form (vcmpequb. VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VCMPEQUH, 0xfc0007ff, 0x10000046, 0x0, // Vector Compare Equal To Unsigned Halfword VC-form (vcmpequh VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VCMPEQUH_, 0xfc0007ff, 0x10000446, 0x0, // Vector Compare Equal To Unsigned Halfword VC-form (vcmpequh. VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VCMPEQUW, 0xfc0007ff, 0x10000086, 0x0, // Vector Compare Equal To Unsigned Word VC-form (vcmpequw VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VCMPEQUW_, 0xfc0007ff, 0x10000486, 0x0, // Vector Compare Equal To Unsigned Word VC-form (vcmpequw. VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VCMPEQUD, 0xfc0007ff, 0x100000c7, 0x0, // Vector Compare Equal To Unsigned Doubleword VX-form (vcmpequd VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VCMPEQUD_, 0xfc0007ff, 0x100004c7, 0x0, // Vector Compare Equal To Unsigned Doubleword VX-form (vcmpequd. VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VCMPGTSB, 0xfc0007ff, 0x10000306, 0x0, // Vector Compare Greater Than Signed Byte VC-form (vcmpgtsb VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VCMPGTSB_, 0xfc0007ff, 0x10000706, 0x0, // Vector Compare Greater Than Signed Byte VC-form (vcmpgtsb. VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VCMPGTSD, 0xfc0007ff, 0x100003c7, 0x0, // Vector Compare Greater Than Signed Doubleword VX-form (vcmpgtsd VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VCMPGTSD_, 0xfc0007ff, 0x100007c7, 0x0, // Vector Compare Greater Than Signed Doubleword VX-form (vcmpgtsd. VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VCMPGTSH, 0xfc0007ff, 0x10000346, 0x0, // Vector Compare Greater Than Signed Halfword VC-form (vcmpgtsh VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VCMPGTSH_, 0xfc0007ff, 0x10000746, 0x0, // Vector Compare Greater Than Signed Halfword VC-form (vcmpgtsh. VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VCMPGTSW, 0xfc0007ff, 0x10000386, 0x0, // Vector Compare Greater Than Signed Word VC-form (vcmpgtsw VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VCMPGTSW_, 0xfc0007ff, 0x10000786, 0x0, // Vector Compare Greater Than Signed Word VC-form (vcmpgtsw. VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VCMPGTUB, 0xfc0007ff, 0x10000206, 0x0, // Vector Compare Greater Than Unsigned Byte VC-form (vcmpgtub VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VCMPGTUB_, 0xfc0007ff, 0x10000606, 0x0, // Vector Compare Greater Than Unsigned Byte VC-form (vcmpgtub. VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VCMPGTUD, 0xfc0007ff, 0x100002c7, 0x0, // Vector Compare Greater Than Unsigned Doubleword VX-form (vcmpgtud VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VCMPGTUD_, 0xfc0007ff, 0x100006c7, 0x0, // Vector Compare Greater Than Unsigned Doubleword VX-form (vcmpgtud. VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VCMPGTUH, 0xfc0007ff, 0x10000246, 0x0, // Vector Compare Greater Than Unsigned Halfword VC-form (vcmpgtuh VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VCMPGTUH_, 0xfc0007ff, 0x10000646, 0x0, // Vector Compare Greater Than Unsigned Halfword VC-form (vcmpgtuh. VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VCMPGTUW, 0xfc0007ff, 0x10000286, 0x0, // Vector Compare Greater Than Unsigned Word VC-form (vcmpgtuw VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VCMPGTUW_, 0xfc0007ff, 0x10000686, 0x0, // Vector Compare Greater Than Unsigned Word VC-form (vcmpgtuw. VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VAND, 0xfc0007ff, 0x10000404, 0x0, // Vector Logical AND VX-form (vand VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VANDC, 0xfc0007ff, 0x10000444, 0x0, // Vector Logical AND with Complement VX-form (vandc VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VEQV, 0xfc0007ff, 0x10000684, 0x0, // Vector Logical Equivalent VX-form (veqv VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VNAND, 0xfc0007ff, 0x10000584, 0x0, // Vector Logical NAND VX-form (vnand VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VORC, 0xfc0007ff, 0x10000544, 0x0, // Vector Logical OR with Complement VX-form (vorc VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VNOR, 0xfc0007ff, 0x10000504, 0x0, // Vector Logical NOR VX-form (vnor VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VOR, 0xfc0007ff, 0x10000484, 0x0, // Vector Logical OR VX-form (vor VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VXOR, 0xfc0007ff, 0x100004c4, 0x0, // Vector Logical XOR VX-form (vxor VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VRLB, 0xfc0007ff, 0x10000004, 0x0, // Vector Rotate Left Byte VX-form (vrlb VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VRLH, 0xfc0007ff, 0x10000044, 0x0, // Vector Rotate Left Halfword VX-form (vrlh VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VRLW, 0xfc0007ff, 0x10000084, 0x0, // Vector Rotate Left Word VX-form (vrlw VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VRLD, 0xfc0007ff, 0x100000c4, 0x0, // Vector Rotate Left Doubleword VX-form (vrld VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VSLB, 0xfc0007ff, 0x10000104, 0x0, // Vector Shift Left Byte VX-form (vslb VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VSLH, 0xfc0007ff, 0x10000144, 0x0, // Vector Shift Left Halfword VX-form (vslh VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VSLW, 0xfc0007ff, 0x10000184, 0x0, // Vector Shift Left Word VX-form (vslw VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VSLD, 0xfc0007ff, 0x100005c4, 0x0, // Vector Shift Left Doubleword VX-form (vsld VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VSRB, 0xfc0007ff, 0x10000204, 0x0, // Vector Shift Right Byte VX-form (vsrb VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VSRH, 0xfc0007ff, 0x10000244, 0x0, // Vector Shift Right Halfword VX-form (vsrh VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VSRW, 0xfc0007ff, 0x10000284, 0x0, // Vector Shift Right Word VX-form (vsrw VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VSRD, 0xfc0007ff, 0x100006c4, 0x0, // Vector Shift Right Doubleword VX-form (vsrd VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VSRAB, 0xfc0007ff, 0x10000304, 0x0, // Vector Shift Right Algebraic Byte VX-form (vsrab VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VSRAH, 0xfc0007ff, 0x10000344, 0x0, // Vector Shift Right Algebraic Halfword VX-form (vsrah VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VSRAW, 0xfc0007ff, 0x10000384, 0x0, // Vector Shift Right Algebraic Word VX-form (vsraw VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VSRAD, 0xfc0007ff, 0x100003c4, 0x0, // Vector Shift Right Algebraic Doubleword VX-form (vsrad VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VADDFP, 0xfc0007ff, 0x1000000a, 0x0, // Vector Add Single-Precision VX-form (vaddfp VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VSUBFP, 0xfc0007ff, 0x1000004a, 0x0, // Vector Subtract Single-Precision VX-form (vsubfp VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VMADDFP, 0xfc00003f, 0x1000002e, 0x0, // Vector Multiply-Add Single-Precision VA-form (vmaddfp VRT,VRA,VRC,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_21_25, ap_VecReg_16_20}},
+ {VNMSUBFP, 0xfc00003f, 0x1000002f, 0x0, // Vector Negative Multiply-Subtract Single-Precision VA-form (vnmsubfp VRT,VRA,VRC,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_21_25, ap_VecReg_16_20}},
+ {VMAXFP, 0xfc0007ff, 0x1000040a, 0x0, // Vector Maximum Single-Precision VX-form (vmaxfp VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VMINFP, 0xfc0007ff, 0x1000044a, 0x0, // Vector Minimum Single-Precision VX-form (vminfp VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VCTSXS, 0xfc0007ff, 0x100003ca, 0x0, // Vector Convert To Signed Fixed-Point Word Saturate VX-form (vctsxs VRT,VRB,UIM)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_16_20, ap_ImmUnsigned_11_15}},
+ {VCTUXS, 0xfc0007ff, 0x1000038a, 0x0, // Vector Convert To Unsigned Fixed-Point Word Saturate VX-form (vctuxs VRT,VRB,UIM)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_16_20, ap_ImmUnsigned_11_15}},
+ {VCFSX, 0xfc0007ff, 0x1000034a, 0x0, // Vector Convert From Signed Fixed-Point Word VX-form (vcfsx VRT,VRB,UIM)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_16_20, ap_ImmUnsigned_11_15}},
+ {VCFUX, 0xfc0007ff, 0x1000030a, 0x0, // Vector Convert From Unsigned Fixed-Point Word VX-form (vcfux VRT,VRB,UIM)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_16_20, ap_ImmUnsigned_11_15}},
+ {VRFIM, 0xfc0007ff, 0x100002ca, 0x1f0000, // Vector Round to Single-Precision Integer toward -Infinity VX-form (vrfim VRT,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_16_20}},
+ {VRFIN, 0xfc0007ff, 0x1000020a, 0x1f0000, // Vector Round to Single-Precision Integer Nearest VX-form (vrfin VRT,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_16_20}},
+ {VRFIP, 0xfc0007ff, 0x1000028a, 0x1f0000, // Vector Round to Single-Precision Integer toward +Infinity VX-form (vrfip VRT,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_16_20}},
+ {VRFIZ, 0xfc0007ff, 0x1000024a, 0x1f0000, // Vector Round to Single-Precision Integer toward Zero VX-form (vrfiz VRT,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_16_20}},
+ {VCMPBFP, 0xfc0007ff, 0x100003c6, 0x0, // Vector Compare Bounds Single-Precision VC-form (vcmpbfp VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VCMPBFP_, 0xfc0007ff, 0x100007c6, 0x0, // Vector Compare Bounds Single-Precision VC-form (vcmpbfp. VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VCMPEQFP, 0xfc0007ff, 0x100000c6, 0x0, // Vector Compare Equal To Single-Precision VC-form (vcmpeqfp VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VCMPEQFP_, 0xfc0007ff, 0x100004c6, 0x0, // Vector Compare Equal To Single-Precision VC-form (vcmpeqfp. VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VCMPGEFP, 0xfc0007ff, 0x100001c6, 0x0, // Vector Compare Greater Than or Equal To Single-Precision VC-form (vcmpgefp VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VCMPGEFP_, 0xfc0007ff, 0x100005c6, 0x0, // Vector Compare Greater Than or Equal To Single-Precision VC-form (vcmpgefp. VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VCMPGTFP, 0xfc0007ff, 0x100002c6, 0x0, // Vector Compare Greater Than Single-Precision VC-form (vcmpgtfp VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VCMPGTFP_, 0xfc0007ff, 0x100006c6, 0x0, // Vector Compare Greater Than Single-Precision VC-form (vcmpgtfp. VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VEXPTEFP, 0xfc0007ff, 0x1000018a, 0x1f0000, // Vector 2 Raised to the Exponent Estimate Floating-Point VX-form (vexptefp VRT,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_16_20}},
+ {VLOGEFP, 0xfc0007ff, 0x100001ca, 0x1f0000, // Vector Log Base 2 Estimate Floating-Point VX-form (vlogefp VRT,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_16_20}},
+ {VREFP, 0xfc0007ff, 0x1000010a, 0x1f0000, // Vector Reciprocal Estimate Single-Precision VX-form (vrefp VRT,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_16_20}},
+ {VRSQRTEFP, 0xfc0007ff, 0x1000014a, 0x1f0000, // Vector Reciprocal Square Root Estimate Single-Precision VX-form (vrsqrtefp VRT,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_16_20}},
+ {VCIPHER, 0xfc0007ff, 0x10000508, 0x0, // Vector AES Cipher VX-form (vcipher VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VCIPHERLAST, 0xfc0007ff, 0x10000509, 0x0, // Vector AES Cipher Last VX-form (vcipherlast VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VNCIPHER, 0xfc0007ff, 0x10000548, 0x0, // Vector AES Inverse Cipher VX-form (vncipher VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VNCIPHERLAST, 0xfc0007ff, 0x10000549, 0x0, // Vector AES Inverse Cipher Last VX-form (vncipherlast VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VSBOX, 0xfc0007ff, 0x100005c8, 0xf800, // Vector AES SubBytes VX-form (vsbox VRT,VRA)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15}},
+ {VSHASIGMAD, 0xfc0007ff, 0x100006c2, 0x0, // Vector SHA-512 Sigma Doubleword VX-form (vshasigmad VRT,VRA,ST,SIX)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_ImmUnsigned_16_16, ap_ImmUnsigned_17_20}},
+ {VSHASIGMAW, 0xfc0007ff, 0x10000682, 0x0, // Vector SHA-256 Sigma Word VX-form (vshasigmaw VRT,VRA,ST,SIX)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_ImmUnsigned_16_16, ap_ImmUnsigned_17_20}},
+ {VPMSUMB, 0xfc0007ff, 0x10000408, 0x0, // Vector Polynomial Multiply-Sum Byte VX-form (vpmsumb VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VPMSUMD, 0xfc0007ff, 0x100004c8, 0x0, // Vector Polynomial Multiply-Sum Doubleword VX-form (vpmsumd VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VPMSUMH, 0xfc0007ff, 0x10000448, 0x0, // Vector Polynomial Multiply-Sum Halfword VX-form (vpmsumh VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VPMSUMW, 0xfc0007ff, 0x10000488, 0x0, // Vector Polynomial Multiply-Sum Word VX-form (vpmsumw VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VPERMXOR, 0xfc00003f, 0x1000002d, 0x0, // Vector Permute and Exclusive-OR VA-form (vpermxor VRT,VRA,VRB,VRC)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20, ap_VecReg_21_25}},
+ {VGBBD, 0xfc0007ff, 0x1000050c, 0x1f0000, // Vector Gather Bits by Bytes by Doubleword VX-form (vgbbd VRT,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_16_20}},
+ {VCLZB, 0xfc0007ff, 0x10000702, 0x1f0000, // Vector Count Leading Zeros Byte VX-form (vclzb VRT,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_16_20}},
+ {VCLZH, 0xfc0007ff, 0x10000742, 0x1f0000, // Vector Count Leading Zeros Halfword VX-form (vclzh VRT,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_16_20}},
+ {VCLZW, 0xfc0007ff, 0x10000782, 0x1f0000, // Vector Count Leading Zeros Word VX-form (vclzw VRT,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_16_20}},
+ {VCLZD, 0xfc0007ff, 0x100007c2, 0x1f0000, // Vector Count Leading Zeros Doubleword (vclzd VRT,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_16_20}},
+ {VPOPCNTB, 0xfc0007ff, 0x10000703, 0x1f0000, // Vector Population Count Byte (vpopcntb VRT,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_16_20}},
+ {VPOPCNTD, 0xfc0007ff, 0x100007c3, 0x1f0000, // Vector Population Count Doubleword (vpopcntd VRT,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_16_20}},
+ {VPOPCNTH, 0xfc0007ff, 0x10000743, 0x1f0000, // Vector Population Count Halfword (vpopcnth VRT,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_16_20}},
+ {VPOPCNTW, 0xfc0007ff, 0x10000783, 0x1f0000, // Vector Population Count Word (vpopcntw VRT,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_16_20}},
+ {VBPERMQ, 0xfc0007ff, 0x1000054c, 0x0, // Vector Bit Permute Quadword VX-form (vbpermq VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {BCDADD_, 0xfc0005ff, 0x10000401, 0x0, // Decimal Add Modulo VX-form (bcdadd. VRT,VRA,VRB,PS)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20, ap_ImmUnsigned_22_22}},
+ {BCDSUB_, 0xfc0005ff, 0x10000441, 0x0, // Decimal Subtract Modulo VX-form (bcdsub. VRT,VRA,VRB,PS)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20, ap_ImmUnsigned_22_22}},
+ {MTVSCR, 0xfc0007ff, 0x10000644, 0x3ff0000, // Move To Vector Status and Control Register VX-form (mtvscr VRB)
+ [5]*argField{ap_VecReg_16_20}},
+ {MFVSCR, 0xfc0007ff, 0x10000604, 0x1ff800, // Move From Vector Status and Control Register VX-form (mfvscr VRT)
+ [5]*argField{ap_VecReg_6_10}},
+ {DADD, 0xfc0007ff, 0xec000004, 0x0, // DFP Add [Quad] X-form (dadd FRT,FRA,FRB)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_11_15, ap_FPReg_16_20}},
+ {DADD_, 0xfc0007ff, 0xec000005, 0x0, // DFP Add [Quad] X-form (dadd. FRT,FRA,FRB)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_11_15, ap_FPReg_16_20}},
+ {DSUB, 0xfc0007ff, 0xec000404, 0x0, // DFP Subtract [Quad] X-form (dsub FRT,FRA,FRB)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_11_15, ap_FPReg_16_20}},
+ {DSUB_, 0xfc0007ff, 0xec000405, 0x0, // DFP Subtract [Quad] X-form (dsub. FRT,FRA,FRB)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_11_15, ap_FPReg_16_20}},
+ {DMUL, 0xfc0007ff, 0xec000044, 0x0, // DFP Multiply [Quad] X-form (dmul FRT,FRA,FRB)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_11_15, ap_FPReg_16_20}},
+ {DMUL_, 0xfc0007ff, 0xec000045, 0x0, // DFP Multiply [Quad] X-form (dmul. FRT,FRA,FRB)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_11_15, ap_FPReg_16_20}},
+ {DDIV, 0xfc0007ff, 0xec000444, 0x0, // DFP Divide [Quad] X-form (ddiv FRT,FRA,FRB)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_11_15, ap_FPReg_16_20}},
+ {DDIV_, 0xfc0007ff, 0xec000445, 0x0, // DFP Divide [Quad] X-form (ddiv. FRT,FRA,FRB)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_11_15, ap_FPReg_16_20}},
+ {DCMPU, 0xfc0007fe, 0xec000504, 0x600001, // DFP Compare Unordered [Quad] X-form (dcmpu BF,FRA,FRB)
+ [5]*argField{ap_CondRegField_6_8, ap_FPReg_11_15, ap_FPReg_16_20}},
+ {DCMPO, 0xfc0007fe, 0xec000104, 0x600001, // DFP Compare Ordered [Quad] X-form (dcmpo BF,FRA,FRB)
+ [5]*argField{ap_CondRegField_6_8, ap_FPReg_11_15, ap_FPReg_16_20}},
+ {DTSTDC, 0xfc0003fe, 0xec000184, 0x600001, // DFP Test Data Class [Quad] Z22-form (dtstdc BF,FRA,DCM)
+ [5]*argField{ap_CondRegField_6_8, ap_FPReg_11_15, ap_ImmUnsigned_16_21}},
+ {DTSTDG, 0xfc0003fe, 0xec0001c4, 0x600001, // DFP Test Data Group [Quad] Z22-form (dtstdg BF,FRA,DGM)
+ [5]*argField{ap_CondRegField_6_8, ap_FPReg_11_15, ap_ImmUnsigned_16_21}},
+ {DTSTEX, 0xfc0007fe, 0xec000144, 0x600001, // DFP Test Exponent [Quad] X-form (dtstex BF,FRA,FRB)
+ [5]*argField{ap_CondRegField_6_8, ap_FPReg_11_15, ap_FPReg_16_20}},
+ {DTSTSF, 0xfc0007fe, 0xec000544, 0x600001, // DFP Test Significance [Quad] X-form (dtstsf BF,FRA,FRB)
+ [5]*argField{ap_CondRegField_6_8, ap_FPReg_11_15, ap_FPReg_16_20}},
+ {DQUAI, 0xfc0001ff, 0xec000086, 0x0, // DFP Quantize Immediate [Quad] Z23-form (dquai TE,FRT,FRB,RMC)
+ [5]*argField{ap_ImmSigned_11_15, ap_FPReg_6_10, ap_FPReg_16_20, ap_ImmUnsigned_21_22}},
+ {DQUAI_, 0xfc0001ff, 0xec000087, 0x0, // DFP Quantize Immediate [Quad] Z23-form (dquai. TE,FRT,FRB,RMC)
+ [5]*argField{ap_ImmSigned_11_15, ap_FPReg_6_10, ap_FPReg_16_20, ap_ImmUnsigned_21_22}},
+ {DQUA, 0xfc0001ff, 0xec000006, 0x0, // DFP Quantize [Quad] Z23-form (dqua FRT,FRA,FRB,RMC)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_11_15, ap_FPReg_16_20, ap_ImmUnsigned_21_22}},
+ {DQUA_, 0xfc0001ff, 0xec000007, 0x0, // DFP Quantize [Quad] Z23-form (dqua. FRT,FRA,FRB,RMC)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_11_15, ap_FPReg_16_20, ap_ImmUnsigned_21_22}},
+ {DRRND, 0xfc0001ff, 0xec000046, 0x0, // DFP Reround [Quad] Z23-form (drrnd FRT,FRA,FRB,RMC)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_11_15, ap_FPReg_16_20, ap_ImmUnsigned_21_22}},
+ {DRRND_, 0xfc0001ff, 0xec000047, 0x0, // DFP Reround [Quad] Z23-form (drrnd. FRT,FRA,FRB,RMC)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_11_15, ap_FPReg_16_20, ap_ImmUnsigned_21_22}},
+ {DRINTX, 0xfc0001ff, 0xec0000c6, 0x1e0000, // DFP Round To FP Integer With Inexact [Quad] Z23-form (drintx R,FRT,FRB,RMC)
+ [5]*argField{ap_ImmUnsigned_15_15, ap_FPReg_6_10, ap_FPReg_16_20, ap_ImmUnsigned_21_22}},
+ {DRINTX_, 0xfc0001ff, 0xec0000c7, 0x1e0000, // DFP Round To FP Integer With Inexact [Quad] Z23-form (drintx. R,FRT,FRB,RMC)
+ [5]*argField{ap_ImmUnsigned_15_15, ap_FPReg_6_10, ap_FPReg_16_20, ap_ImmUnsigned_21_22}},
+ {DRINTN, 0xfc0001ff, 0xec0001c6, 0x1e0000, // DFP Round To FP Integer Without Inexact [Quad] Z23-form (drintn R,FRT,FRB,RMC)
+ [5]*argField{ap_ImmUnsigned_15_15, ap_FPReg_6_10, ap_FPReg_16_20, ap_ImmUnsigned_21_22}},
+ {DRINTN_, 0xfc0001ff, 0xec0001c7, 0x1e0000, // DFP Round To FP Integer Without Inexact [Quad] Z23-form (drintn. R,FRT,FRB,RMC)
+ [5]*argField{ap_ImmUnsigned_15_15, ap_FPReg_6_10, ap_FPReg_16_20, ap_ImmUnsigned_21_22}},
+ {DCTDP, 0xfc0007ff, 0xec000204, 0x1f0000, // DFP Convert To DFP Long X-form (dctdp FRT,FRB)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_16_20}},
+ {DCTDP_, 0xfc0007ff, 0xec000205, 0x1f0000, // DFP Convert To DFP Long X-form (dctdp. FRT,FRB)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_16_20}},
+ {DCTQPQ, 0xfc0007ff, 0xfc000204, 0x1f0000, // DFP Convert To DFP Extended X-form (dctqpq FRTp,FRB)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_16_20}},
+ {DCTQPQ_, 0xfc0007ff, 0xfc000205, 0x1f0000, // DFP Convert To DFP Extended X-form (dctqpq. FRTp,FRB)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_16_20}},
+ {DRSP, 0xfc0007ff, 0xec000604, 0x1f0000, // DFP Round To DFP Short X-form (drsp FRT,FRB)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_16_20}},
+ {DRSP_, 0xfc0007ff, 0xec000605, 0x1f0000, // DFP Round To DFP Short X-form (drsp. FRT,FRB)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_16_20}},
+ {DRDPQ, 0xfc0007ff, 0xfc000604, 0x1f0000, // DFP Round To DFP Long X-form (drdpq FRTp,FRBp)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_16_20}},
+ {DRDPQ_, 0xfc0007ff, 0xfc000605, 0x1f0000, // DFP Round To DFP Long X-form (drdpq. FRTp,FRBp)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_16_20}},
+ {DCFFIX, 0xfc0007ff, 0xec000644, 0x1f0000, // DFP Convert From Fixed X-form (dcffix FRT,FRB)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_16_20}},
+ {DCFFIX_, 0xfc0007ff, 0xec000645, 0x1f0000, // DFP Convert From Fixed X-form (dcffix. FRT,FRB)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_16_20}},
+ {DCFFIXQ, 0xfc0007ff, 0xfc000644, 0x1f0000, // DFP Convert From Fixed Quad X-form (dcffixq FRTp,FRB)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_16_20}},
+ {DCFFIXQ_, 0xfc0007ff, 0xfc000645, 0x1f0000, // DFP Convert From Fixed Quad X-form (dcffixq. FRTp,FRB)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_16_20}},
+ {DCTFIX, 0xfc0007ff, 0xec000244, 0x1f0000, // DFP Convert To Fixed [Quad] X-form (dctfix FRT,FRB)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_16_20}},
+ {DCTFIX_, 0xfc0007ff, 0xec000245, 0x1f0000, // DFP Convert To Fixed [Quad] X-form (dctfix. FRT,FRB)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_16_20}},
+ {DDEDPD, 0xfc0007ff, 0xec000284, 0x70000, // DFP Decode DPD To BCD [Quad] X-form (ddedpd SP,FRT,FRB)
+ [5]*argField{ap_ImmUnsigned_11_12, ap_FPReg_6_10, ap_FPReg_16_20}},
+ {DDEDPD_, 0xfc0007ff, 0xec000285, 0x70000, // DFP Decode DPD To BCD [Quad] X-form (ddedpd. SP,FRT,FRB)
+ [5]*argField{ap_ImmUnsigned_11_12, ap_FPReg_6_10, ap_FPReg_16_20}},
+ {DENBCD, 0xfc0007ff, 0xec000684, 0xf0000, // DFP Encode BCD To DPD [Quad] X-form (denbcd S,FRT,FRB)
+ [5]*argField{ap_ImmUnsigned_11_11, ap_FPReg_6_10, ap_FPReg_16_20}},
+ {DENBCD_, 0xfc0007ff, 0xec000685, 0xf0000, // DFP Encode BCD To DPD [Quad] X-form (denbcd. S,FRT,FRB)
+ [5]*argField{ap_ImmUnsigned_11_11, ap_FPReg_6_10, ap_FPReg_16_20}},
+ {DXEX, 0xfc0007ff, 0xec0002c4, 0x1f0000, // DFP Extract Biased Exponent [Quad] X-form (dxex FRT,FRB)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_16_20}},
+ {DXEX_, 0xfc0007ff, 0xec0002c5, 0x1f0000, // DFP Extract Biased Exponent [Quad] X-form (dxex. FRT,FRB)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_16_20}},
+ {DIEX, 0xfc0007ff, 0xec0006c4, 0x0, // DFP Insert Biased Exponent [Quad] X-form (diex FRT,FRA,FRB)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_11_15, ap_FPReg_16_20}},
+ {DIEX_, 0xfc0007ff, 0xec0006c5, 0x0, // DFP Insert Biased Exponent [Quad] X-form (diex. FRT,FRA,FRB)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_11_15, ap_FPReg_16_20}},
+ {DSCLI, 0xfc0003ff, 0xec000084, 0x0, // DFP Shift Significand Left Immediate [Quad] Z22-form (dscli FRT,FRA,SH)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_11_15, ap_ImmUnsigned_16_21}},
+ {DSCLI_, 0xfc0003ff, 0xec000085, 0x0, // DFP Shift Significand Left Immediate [Quad] Z22-form (dscli. FRT,FRA,SH)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_11_15, ap_ImmUnsigned_16_21}},
+ {DSCRI, 0xfc0003ff, 0xec0000c4, 0x0, // DFP Shift Significand Right Immediate [Quad] Z22-form (dscri FRT,FRA,SH)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_11_15, ap_ImmUnsigned_16_21}},
+ {DSCRI_, 0xfc0003ff, 0xec0000c5, 0x0, // DFP Shift Significand Right Immediate [Quad] Z22-form (dscri. FRT,FRA,SH)
+ [5]*argField{ap_FPReg_6_10, ap_FPReg_11_15, ap_ImmUnsigned_16_21}},
+ {LXSDX, 0xfc0007fe, 0x7c000498, 0x0, // Load VSX Scalar Doubleword Indexed XX1-form (lxsdx XT,RA,RB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {LXSIWAX, 0xfc0007fe, 0x7c000098, 0x0, // Load VSX Scalar as Integer Word Algebraic Indexed XX1-form (lxsiwax XT,RA,RB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {LXSIWZX, 0xfc0007fe, 0x7c000018, 0x0, // Load VSX Scalar as Integer Word and Zero Indexed XX1-form (lxsiwzx XT,RA,RB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {LXSSPX, 0xfc0007fe, 0x7c000418, 0x0, // Load VSX Scalar Single-Precision Indexed XX1-form (lxsspx XT,RA,RB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {LXVD2X, 0xfc0007fe, 0x7c000698, 0x0, // Load VSX Vector Doubleword*2 Indexed XX1-form (lxvd2x XT,RA,RB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {LXVDSX, 0xfc0007fe, 0x7c000298, 0x0, // Load VSX Vector Doubleword & Splat Indexed XX1-form (lxvdsx XT,RA,RB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {LXVW4X, 0xfc0007fe, 0x7c000618, 0x0, // Load VSX Vector Word*4 Indexed XX1-form (lxvw4x XT,RA,RB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {STXSDX, 0xfc0007fe, 0x7c000598, 0x0, // Store VSX Scalar Doubleword Indexed XX1-form (stxsdx XS,RA,RB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {STXSIWX, 0xfc0007fe, 0x7c000118, 0x0, // Store VSX Scalar as Integer Word Indexed XX1-form (stxsiwx XS,RA,RB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {STXSSPX, 0xfc0007fe, 0x7c000518, 0x0, // Store VSX Scalar Single-Precision Indexed XX1-form (stxsspx XS,RA,RB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {STXVD2X, 0xfc0007fe, 0x7c000798, 0x0, // Store VSX Vector Doubleword*2 Indexed XX1-form (stxvd2x XS,RA,RB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {STXVW4X, 0xfc0007fe, 0x7c000718, 0x0, // Store VSX Vector Word*4 Indexed XX1-form (stxvw4x XS,RA,RB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {XSABSDP, 0xfc0007fc, 0xf0000564, 0x1f0000, // VSX Scalar Absolute Value Double-Precision XX2-form (xsabsdp XT,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_30_30_16_20}},
+ {XSADDDP, 0xfc0007f8, 0xf0000100, 0x0, // VSX Scalar Add Double-Precision XX3-form (xsadddp XT,XA,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_29_29_11_15, ap_VecSReg_30_30_16_20}},
+ {XSADDSP, 0xfc0007f8, 0xf0000000, 0x0, // VSX Scalar Add Single-Precision XX3-form (xsaddsp XT,XA,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_29_29_11_15, ap_VecSReg_30_30_16_20}},
+ {XSCMPODP, 0xfc0007f8, 0xf0000158, 0x600001, // VSX Scalar Compare Ordered Double-Precision XX3-form (xscmpodp BF,XA,XB)
+ [5]*argField{ap_CondRegField_6_8, ap_VecSReg_29_29_11_15, ap_VecSReg_30_30_16_20}},
+ {XSCMPUDP, 0xfc0007f8, 0xf0000118, 0x600001, // VSX Scalar Compare Unordered Double-Precision XX3-form (xscmpudp BF,XA,XB)
+ [5]*argField{ap_CondRegField_6_8, ap_VecSReg_29_29_11_15, ap_VecSReg_30_30_16_20}},
+ {XSCPSGNDP, 0xfc0007f8, 0xf0000580, 0x0, // VSX Scalar Copy Sign Double-Precision XX3-form (xscpsgndp XT,XA,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_29_29_11_15, ap_VecSReg_30_30_16_20}},
+ {XSCVDPSP, 0xfc0007fc, 0xf0000424, 0x1f0000, // VSX Scalar round Double-Precision to single-precision and Convert to Single-Precision format XX2-form (xscvdpsp XT,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_30_30_16_20}},
+ {XSCVDPSPN, 0xfc0007fc, 0xf000042c, 0x1f0000, // VSX Scalar Convert Scalar Single-Precision to Vector Single-Precision format Non-signalling XX2-form (xscvdpspn XT,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_30_30_16_20}},
+ {XSCVDPSXDS, 0xfc0007fc, 0xf0000560, 0x1f0000, // VSX Scalar truncate Double-Precision to integer and Convert to Signed Integer Doubleword format with Saturate XX2-form (xscvdpsxds XT,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_30_30_16_20}},
+ {XSCVDPSXWS, 0xfc0007fc, 0xf0000160, 0x1f0000, // VSX Scalar truncate Double-Precision to integer and Convert to Signed Integer Word format with Saturate XX2-form (xscvdpsxws XT,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_30_30_16_20}},
+ {XSCVDPUXDS, 0xfc0007fc, 0xf0000520, 0x1f0000, // VSX Scalar truncate Double-Precision integer and Convert to Unsigned Integer Doubleword format with Saturate XX2-form (xscvdpuxds XT,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_30_30_16_20}},
+ {XSCVDPUXWS, 0xfc0007fc, 0xf0000120, 0x1f0000, // VSX Scalar truncate Double-Precision to integer and Convert to Unsigned Integer Word format with Saturate XX2-form (xscvdpuxws XT,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_30_30_16_20}},
+ {XSCVSPDP, 0xfc0007fc, 0xf0000524, 0x1f0000, // VSX Scalar Convert Single-Precision to Double-Precision format XX2-form (xscvspdp XT,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_30_30_16_20}},
+ {XSCVSPDPN, 0xfc0007fc, 0xf000052c, 0x1f0000, // VSX Scalar Convert Single-Precision to Double-Precision format Non-signalling XX2-form (xscvspdpn XT,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_30_30_16_20}},
+ {XSCVSXDDP, 0xfc0007fc, 0xf00005e0, 0x1f0000, // VSX Scalar Convert Signed Integer Doubleword to floating-point format and round to Double-Precision format XX2-form (xscvsxddp XT,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_30_30_16_20}},
+ {XSCVSXDSP, 0xfc0007fc, 0xf00004e0, 0x1f0000, // VSX Scalar Convert Signed Integer Doubleword to floating-point format and round to Single-Precision XX2-form (xscvsxdsp XT,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_30_30_16_20}},
+ {XSCVUXDDP, 0xfc0007fc, 0xf00005a0, 0x1f0000, // VSX Scalar Convert Unsigned Integer Doubleword to floating-point format and round to Double-Precision format XX2-form (xscvuxddp XT,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_30_30_16_20}},
+ {XSCVUXDSP, 0xfc0007fc, 0xf00004a0, 0x1f0000, // VSX Scalar Convert Unsigned Integer Doubleword to floating-point format and round to Single-Precision XX2-form (xscvuxdsp XT,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_30_30_16_20}},
+ {XSDIVDP, 0xfc0007f8, 0xf00001c0, 0x0, // VSX Scalar Divide Double-Precision XX3-form (xsdivdp XT,XA,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_29_29_11_15, ap_VecSReg_30_30_16_20}},
+ {XSDIVSP, 0xfc0007f8, 0xf00000c0, 0x0, // VSX Scalar Divide Single-Precision XX3-form (xsdivsp XT,XA,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_29_29_11_15, ap_VecSReg_30_30_16_20}},
+ {XSMADDADP, 0xfc0007f8, 0xf0000108, 0x0, // VSX Scalar Multiply-Add Double-Precision XX3-form (xsmaddadp XT,XA,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_29_29_11_15, ap_VecSReg_30_30_16_20}},
+ {XSMADDASP, 0xfc0007f8, 0xf0000008, 0x0, // VSX Scalar Multiply-Add Single-Precision XX3-form (xsmaddasp XT,XA,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_29_29_11_15, ap_VecSReg_30_30_16_20}},
+ {XSMAXDP, 0xfc0007f8, 0xf0000500, 0x0, // VSX Scalar Maximum Double-Precision XX3-form (xsmaxdp XT,XA,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_29_29_11_15, ap_VecSReg_30_30_16_20}},
+ {XSMINDP, 0xfc0007f8, 0xf0000540, 0x0, // VSX Scalar Minimum Double-Precision XX3-form (xsmindp XT,XA,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_29_29_11_15, ap_VecSReg_30_30_16_20}},
+ {XSMSUBADP, 0xfc0007f8, 0xf0000188, 0x0, // VSX Scalar Multiply-Subtract Double-Precision XX3-form (xsmsubadp XT,XA,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_29_29_11_15, ap_VecSReg_30_30_16_20}},
+ {XSMSUBASP, 0xfc0007f8, 0xf0000088, 0x0, // VSX Scalar Multiply-Subtract Single-Precision XX3-form (xsmsubasp XT,XA,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_29_29_11_15, ap_VecSReg_30_30_16_20}},
+ {XSMULDP, 0xfc0007f8, 0xf0000180, 0x0, // VSX Scalar Multiply Double-Precision XX3-form (xsmuldp XT,XA,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_29_29_11_15, ap_VecSReg_30_30_16_20}},
+ {XSMULSP, 0xfc0007f8, 0xf0000080, 0x0, // VSX Scalar Multiply Single-Precision XX3-form (xsmulsp XT,XA,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_29_29_11_15, ap_VecSReg_30_30_16_20}},
+ {XSNABSDP, 0xfc0007fc, 0xf00005a4, 0x1f0000, // VSX Scalar Negative Absolute Value Double-Precision XX2-form (xsnabsdp XT,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_30_30_16_20}},
+ {XSNEGDP, 0xfc0007fc, 0xf00005e4, 0x1f0000, // VSX Scalar Negate Double-Precision XX2-form (xsnegdp XT,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_30_30_16_20}},
+ {XSNMADDADP, 0xfc0007f8, 0xf0000508, 0x0, // VSX Scalar Negative Multiply-Add Double-Precision XX3-form (xsnmaddadp XT,XA,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_29_29_11_15, ap_VecSReg_30_30_16_20}},
+ {XSNMADDASP, 0xfc0007f8, 0xf0000408, 0x0, // VSX Scalar Negative Multiply-Add Single-Precision XX3-form (xsnmaddasp XT,XA,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_29_29_11_15, ap_VecSReg_30_30_16_20}},
+ {XSNMSUBADP, 0xfc0007f8, 0xf0000588, 0x0, // VSX Scalar Negative Multiply-Subtract Double-Precision XX3-form (xsnmsubadp XT,XA,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_29_29_11_15, ap_VecSReg_30_30_16_20}},
+ {XSNMSUBASP, 0xfc0007f8, 0xf0000488, 0x0, // VSX Scalar Negative Multiply-Subtract Single-Precision XX3-form (xsnmsubasp XT,XA,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_29_29_11_15, ap_VecSReg_30_30_16_20}},
+ {XSRDPI, 0xfc0007fc, 0xf0000124, 0x1f0000, // VSX Scalar Round to Double-Precision Integer using round to Nearest Away XX2-form (xsrdpi XT,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_30_30_16_20}},
+ {XSRDPIC, 0xfc0007fc, 0xf00001ac, 0x1f0000, // VSX Scalar Round to Double-Precision Integer exact using Current rounding mode XX2-form (xsrdpic XT,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_30_30_16_20}},
+ {XSRDPIM, 0xfc0007fc, 0xf00001e4, 0x1f0000, // VSX Scalar Round to Double-Precision Integer using round toward -Infinity XX2-form (xsrdpim XT,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_30_30_16_20}},
+ {XSRDPIP, 0xfc0007fc, 0xf00001a4, 0x1f0000, // VSX Scalar Round to Double-Precision Integer using round toward +Infinity XX2-form (xsrdpip XT,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_30_30_16_20}},
+ {XSRDPIZ, 0xfc0007fc, 0xf0000164, 0x1f0000, // VSX Scalar Round to Double-Precision Integer using round toward Zero XX2-form (xsrdpiz XT,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_30_30_16_20}},
+ {XSREDP, 0xfc0007fc, 0xf0000168, 0x1f0000, // VSX Scalar Reciprocal Estimate Double-Precision XX2-form (xsredp XT,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_30_30_16_20}},
+ {XSRESP, 0xfc0007fc, 0xf0000068, 0x1f0000, // VSX Scalar Reciprocal Estimate Single-Precision XX2-form (xsresp XT,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_30_30_16_20}},
+ {XSRSP, 0xfc0007fc, 0xf0000464, 0x1f0000, // VSX Scalar Round to Single-Precision XX2-form (xsrsp XT,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_30_30_16_20}},
+ {XSRSQRTEDP, 0xfc0007fc, 0xf0000128, 0x1f0000, // VSX Scalar Reciprocal Square Root Estimate Double-Precision XX2-form (xsrsqrtedp XT,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_30_30_16_20}},
+ {XSRSQRTESP, 0xfc0007fc, 0xf0000028, 0x1f0000, // VSX Scalar Reciprocal Square Root Estimate Single-Precision XX2-form (xsrsqrtesp XT,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_30_30_16_20}},
+ {XSSQRTDP, 0xfc0007fc, 0xf000012c, 0x1f0000, // VSX Scalar Square Root Double-Precision XX2-form (xssqrtdp XT,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_30_30_16_20}},
+ {XSSQRTSP, 0xfc0007fc, 0xf000002c, 0x1f0000, // VSX Scalar Square Root Single-Precision XX-form (xssqrtsp XT,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_30_30_16_20}},
+ {XSSUBDP, 0xfc0007f8, 0xf0000140, 0x0, // VSX Scalar Subtract Double-Precision XX3-form (xssubdp XT,XA,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_29_29_11_15, ap_VecSReg_30_30_16_20}},
+ {XSSUBSP, 0xfc0007f8, 0xf0000040, 0x0, // VSX Scalar Subtract Single-Precision XX3-form (xssubsp XT,XA,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_29_29_11_15, ap_VecSReg_30_30_16_20}},
+ {XSTDIVDP, 0xfc0007f8, 0xf00001e8, 0x600001, // VSX Scalar Test for software Divide Double-Precision XX3-form (xstdivdp BF,XA,XB)
+ [5]*argField{ap_CondRegField_6_8, ap_VecSReg_29_29_11_15, ap_VecSReg_30_30_16_20}},
+ {XSTSQRTDP, 0xfc0007fc, 0xf00001a8, 0x7f0001, // VSX Scalar Test for software Square Root Double-Precision XX2-form (xstsqrtdp BF,XB)
+ [5]*argField{ap_CondRegField_6_8, ap_VecSReg_30_30_16_20}},
+ {XVABSDP, 0xfc0007fc, 0xf0000764, 0x1f0000, // VSX Vector Absolute Value Double-Precision XX2-form (xvabsdp XT,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_30_30_16_20}},
+ {XVABSSP, 0xfc0007fc, 0xf0000664, 0x1f0000, // VSX Vector Absolute Value Single-Precision XX2-form (xvabssp XT,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_30_30_16_20}},
+ {XVADDDP, 0xfc0007f8, 0xf0000300, 0x0, // VSX Vector Add Double-Precision XX3-form (xvadddp XT,XA,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_29_29_11_15, ap_VecSReg_30_30_16_20}},
+ {XVADDSP, 0xfc0007f8, 0xf0000200, 0x0, // VSX Vector Add Single-Precision XX3-form (xvaddsp XT,XA,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_29_29_11_15, ap_VecSReg_30_30_16_20}},
+ {XVCMPEQDP, 0xfc0007f8, 0xf0000318, 0x0, // VSX Vector Compare Equal To Double-Precision [ & Record ] XX3-form (xvcmpeqdp XT,XA,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_29_29_11_15, ap_VecSReg_30_30_16_20}},
+ {XVCMPEQDP_, 0xfc0007f8, 0xf0000718, 0x0, // VSX Vector Compare Equal To Double-Precision [ & Record ] XX3-form (xvcmpeqdp. XT,XA,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_29_29_11_15, ap_VecSReg_30_30_16_20}},
+ {XVCMPEQSP, 0xfc0007f8, 0xf0000218, 0x0, // VSX Vector Compare Equal To Single-Precision [ & Record ] XX3-form (xvcmpeqsp XT,XA,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_29_29_11_15, ap_VecSReg_30_30_16_20}},
+ {XVCMPEQSP_, 0xfc0007f8, 0xf0000618, 0x0, // VSX Vector Compare Equal To Single-Precision [ & Record ] XX3-form (xvcmpeqsp. XT,XA,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_29_29_11_15, ap_VecSReg_30_30_16_20}},
+ {XVCMPGEDP, 0xfc0007f8, 0xf0000398, 0x0, // VSX Vector Compare Greater Than or Equal To Double-Precision [ & Record ] XX3-form (xvcmpgedp XT,XA,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_29_29_11_15, ap_VecSReg_30_30_16_20}},
+ {XVCMPGEDP_, 0xfc0007f8, 0xf0000798, 0x0, // VSX Vector Compare Greater Than or Equal To Double-Precision [ & Record ] XX3-form (xvcmpgedp. XT,XA,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_29_29_11_15, ap_VecSReg_30_30_16_20}},
+ {XVCMPGESP, 0xfc0007f8, 0xf0000298, 0x0, // VSX Vector Compare Greater Than or Equal To Single-Precision [ & record CR6 ] XX3-form (xvcmpgesp XT,XA,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_29_29_11_15, ap_VecSReg_30_30_16_20}},
+ {XVCMPGESP_, 0xfc0007f8, 0xf0000698, 0x0, // VSX Vector Compare Greater Than or Equal To Single-Precision [ & record CR6 ] XX3-form (xvcmpgesp. XT,XA,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_29_29_11_15, ap_VecSReg_30_30_16_20}},
+ {XVCMPGTDP, 0xfc0007f8, 0xf0000358, 0x0, // VSX Vector Compare Greater Than Double-Precision [ & record CR6 ] XX3-form (xvcmpgtdp XT,XA,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_29_29_11_15, ap_VecSReg_30_30_16_20}},
+ {XVCMPGTDP_, 0xfc0007f8, 0xf0000758, 0x0, // VSX Vector Compare Greater Than Double-Precision [ & record CR6 ] XX3-form (xvcmpgtdp. XT,XA,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_29_29_11_15, ap_VecSReg_30_30_16_20}},
+ {XVCMPGTSP, 0xfc0007f8, 0xf0000258, 0x0, // VSX Vector Compare Greater Than Single-Precision [ & record CR6 ] XX3-form (xvcmpgtsp XT,XA,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_29_29_11_15, ap_VecSReg_30_30_16_20}},
+ {XVCMPGTSP_, 0xfc0007f8, 0xf0000658, 0x0, // VSX Vector Compare Greater Than Single-Precision [ & record CR6 ] XX3-form (xvcmpgtsp. XT,XA,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_29_29_11_15, ap_VecSReg_30_30_16_20}},
+ {XVCPSGNDP, 0xfc0007f8, 0xf0000780, 0x0, // VSX Vector Copy Sign Double-Precision XX3-form (xvcpsgndp XT,XA,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_29_29_11_15, ap_VecSReg_30_30_16_20}},
+ {XVCPSGNSP, 0xfc0007f8, 0xf0000680, 0x0, // VSX Vector Copy Sign Single-Precision XX3-form (xvcpsgnsp XT,XA,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_29_29_11_15, ap_VecSReg_30_30_16_20}},
+ {XVCVDPSP, 0xfc0007fc, 0xf0000624, 0x1f0000, // VSX Vector round Double-Precision to single-precision and Convert to Single-Precision format XX2-form (xvcvdpsp XT,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_30_30_16_20}},
+ {XVCVDPSXDS, 0xfc0007fc, 0xf0000760, 0x1f0000, // VSX Vector truncate Double-Precision to integer and Convert to Signed Integer Doubleword format with Saturate XX2-form (xvcvdpsxds XT,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_30_30_16_20}},
+ {XVCVDPSXWS, 0xfc0007fc, 0xf0000360, 0x1f0000, // VSX Vector truncate Double-Precision to integer and Convert to Signed Integer Word format with Saturate XX2-form (xvcvdpsxws XT,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_30_30_16_20}},
+ {XVCVDPUXDS, 0xfc0007fc, 0xf0000720, 0x1f0000, // VSX Vector truncate Double-Precision to integer and Convert to Unsigned Integer Doubleword format with Saturate XX2-form (xvcvdpuxds XT,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_30_30_16_20}},
+ {XVCVDPUXWS, 0xfc0007fc, 0xf0000320, 0x1f0000, // VSX Vector truncate Double-Precision to integer and Convert to Unsigned Integer Word format with Saturate XX2-form (xvcvdpuxws XT,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_30_30_16_20}},
+ {XVCVSPDP, 0xfc0007fc, 0xf0000724, 0x1f0000, // VSX Vector Convert Single-Precision to Double-Precision format XX2-form (xvcvspdp XT,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_30_30_16_20}},
+ {XVCVSPSXDS, 0xfc0007fc, 0xf0000660, 0x1f0000, // VSX Vector truncate Single-Precision to integer and Convert to Signed Integer Doubleword format with Saturate XX2-form (xvcvspsxds XT,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_30_30_16_20}},
+ {XVCVSPSXWS, 0xfc0007fc, 0xf0000260, 0x1f0000, // VSX Vector truncate Single-Precision to integer and Convert to Signed Integer Word format with Saturate XX2-form (xvcvspsxws XT,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_30_30_16_20}},
+ {XVCVSPUXDS, 0xfc0007fc, 0xf0000620, 0x1f0000, // VSX Vector truncate Single-Precision to integer and Convert to Unsigned Integer Doubleword format with Saturate XX2-form (xvcvspuxds XT,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_30_30_16_20}},
+ {XVCVSPUXWS, 0xfc0007fc, 0xf0000220, 0x1f0000, // VSX Vector truncate Single-Precision to integer and Convert to Unsigned Integer Word format with Saturate XX2-form (xvcvspuxws XT,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_30_30_16_20}},
+ {XVCVSXDDP, 0xfc0007fc, 0xf00007e0, 0x1f0000, // VSX Vector Convert and round Signed Integer Doubleword to Double-Precision format XX2-form (xvcvsxddp XT,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_30_30_16_20}},
+ {XVCVSXDSP, 0xfc0007fc, 0xf00006e0, 0x1f0000, // VSX Vector Convert and round Signed Integer Doubleword to Single-Precision format XX2-form (xvcvsxdsp XT,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_30_30_16_20}},
+ {XVCVSXWDP, 0xfc0007fc, 0xf00003e0, 0x1f0000, // VSX Vector Convert Signed Integer Word to Double-Precision format XX2-form (xvcvsxwdp XT,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_30_30_16_20}},
+ {XVCVSXWSP, 0xfc0007fc, 0xf00002e0, 0x1f0000, // VSX Vector Convert and round Signed Integer Word to Single-Precision format XX2-form (xvcvsxwsp XT,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_30_30_16_20}},
+ {XVCVUXDDP, 0xfc0007fc, 0xf00007a0, 0x1f0000, // VSX Vector Convert and round Unsigned Integer Doubleword to Double-Precision format XX2-form (xvcvuxddp XT,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_30_30_16_20}},
+ {XVCVUXDSP, 0xfc0007fc, 0xf00006a0, 0x1f0000, // VSX Vector Convert and round Unsigned Integer Doubleword to Single-Precision format XX2-form (xvcvuxdsp XT,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_30_30_16_20}},
+ {XVCVUXWDP, 0xfc0007fc, 0xf00003a0, 0x1f0000, // VSX Vector Convert and round Unsigned Integer Word to Double-Precision format XX2-form (xvcvuxwdp XT,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_30_30_16_20}},
+ {XVCVUXWSP, 0xfc0007fc, 0xf00002a0, 0x1f0000, // VSX Vector Convert and round Unsigned Integer Word to Single-Precision format XX2-form (xvcvuxwsp XT,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_30_30_16_20}},
+ {XVDIVDP, 0xfc0007f8, 0xf00003c0, 0x0, // VSX Vector Divide Double-Precision XX3-form (xvdivdp XT,XA,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_29_29_11_15, ap_VecSReg_30_30_16_20}},
+ {XVDIVSP, 0xfc0007f8, 0xf00002c0, 0x0, // VSX Vector Divide Single-Precision XX3-form (xvdivsp XT,XA,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_29_29_11_15, ap_VecSReg_30_30_16_20}},
+ {XVMADDADP, 0xfc0007f8, 0xf0000308, 0x0, // VSX Vector Multiply-Add Double-Precision XX3-form (xvmaddadp XT,XA,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_29_29_11_15, ap_VecSReg_30_30_16_20}},
+ {XVMADDASP, 0xfc0007f8, 0xf0000208, 0x0, // VSX Vector Multiply-Add Single-Precision XX3-form (xvmaddasp XT,XA,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_29_29_11_15, ap_VecSReg_30_30_16_20}},
+ {XVMAXDP, 0xfc0007f8, 0xf0000700, 0x0, // VSX Vector Maximum Double-Precision XX3-form (xvmaxdp XT,XA,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_29_29_11_15, ap_VecSReg_30_30_16_20}},
+ {XVMAXSP, 0xfc0007f8, 0xf0000600, 0x0, // VSX Vector Maximum Single-Precision XX3-form (xvmaxsp XT,XA,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_29_29_11_15, ap_VecSReg_30_30_16_20}},
+ {XVMINDP, 0xfc0007f8, 0xf0000740, 0x0, // VSX Vector Minimum Double-Precision XX3-form (xvmindp XT,XA,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_29_29_11_15, ap_VecSReg_30_30_16_20}},
+ {XVMINSP, 0xfc0007f8, 0xf0000640, 0x0, // VSX Vector Minimum Single-Precision XX3-form (xvminsp XT,XA,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_29_29_11_15, ap_VecSReg_30_30_16_20}},
+ {XVMSUBADP, 0xfc0007f8, 0xf0000388, 0x0, // VSX Vector Multiply-Subtract Double-Precision XX3-form (xvmsubadp XT,XA,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_29_29_11_15, ap_VecSReg_30_30_16_20}},
+ {XVMSUBASP, 0xfc0007f8, 0xf0000288, 0x0, // VSX Vector Multiply-Subtract Single-Precision XX3-form (xvmsubasp XT,XA,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_29_29_11_15, ap_VecSReg_30_30_16_20}},
+ {XVMULDP, 0xfc0007f8, 0xf0000380, 0x0, // VSX Vector Multiply Double-Precision XX3-form (xvmuldp XT,XA,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_29_29_11_15, ap_VecSReg_30_30_16_20}},
+ {XVMULSP, 0xfc0007f8, 0xf0000280, 0x0, // VSX Vector Multiply Single-Precision XX3-form (xvmulsp XT,XA,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_29_29_11_15, ap_VecSReg_30_30_16_20}},
+ {XVNABSDP, 0xfc0007fc, 0xf00007a4, 0x1f0000, // VSX Vector Negative Absolute Value Double-Precision XX2-form (xvnabsdp XT,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_30_30_16_20}},
+ {XVNABSSP, 0xfc0007fc, 0xf00006a4, 0x1f0000, // VSX Vector Negative Absolute Value Single-Precision XX2-form (xvnabssp XT,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_30_30_16_20}},
+ {XVNEGDP, 0xfc0007fc, 0xf00007e4, 0x1f0000, // VSX Vector Negate Double-Precision XX2-form (xvnegdp XT,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_30_30_16_20}},
+ {XVNEGSP, 0xfc0007fc, 0xf00006e4, 0x1f0000, // VSX Vector Negate Single-Precision XX2-form (xvnegsp XT,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_30_30_16_20}},
+ {XVNMADDADP, 0xfc0007f8, 0xf0000708, 0x0, // VSX Vector Negative Multiply-Add Double-Precision XX3-form (xvnmaddadp XT,XA,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_29_29_11_15, ap_VecSReg_30_30_16_20}},
+ {XVNMADDASP, 0xfc0007f8, 0xf0000608, 0x0, // VSX Vector Negative Multiply-Add Single-Precision XX3-form (xvnmaddasp XT,XA,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_29_29_11_15, ap_VecSReg_30_30_16_20}},
+ {XVNMSUBADP, 0xfc0007f8, 0xf0000788, 0x0, // VSX Vector Negative Multiply-Subtract Double-Precision XX3-form (xvnmsubadp XT,XA,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_29_29_11_15, ap_VecSReg_30_30_16_20}},
+ {XVNMSUBASP, 0xfc0007f8, 0xf0000688, 0x0, // VSX Vector Negative Multiply-Subtract Single-Precision XX3-form (xvnmsubasp XT,XA,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_29_29_11_15, ap_VecSReg_30_30_16_20}},
+ {XVRDPI, 0xfc0007fc, 0xf0000324, 0x1f0000, // VSX Vector Round to Double-Precision Integer using round to Nearest Away XX2-form (xvrdpi XT,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_30_30_16_20}},
+ {XVRDPIC, 0xfc0007fc, 0xf00003ac, 0x1f0000, // VSX Vector Round to Double-Precision Integer Exact using Current rounding mode XX2-form (xvrdpic XT,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_30_30_16_20}},
+ {XVRDPIM, 0xfc0007fc, 0xf00003e4, 0x1f0000, // VSX Vector Round to Double-Precision Integer using round toward -Infinity XX2-form (xvrdpim XT,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_30_30_16_20}},
+ {XVRDPIP, 0xfc0007fc, 0xf00003a4, 0x1f0000, // VSX Vector Round to Double-Precision Integer using round toward +Infinity XX2-form (xvrdpip XT,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_30_30_16_20}},
+ {XVRDPIZ, 0xfc0007fc, 0xf0000364, 0x1f0000, // VSX Vector Round to Double-Precision Integer using round toward Zero XX2-form (xvrdpiz XT,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_30_30_16_20}},
+ {XVREDP, 0xfc0007fc, 0xf0000368, 0x1f0000, // VSX Vector Reciprocal Estimate Double-Precision XX2-form (xvredp XT,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_30_30_16_20}},
+ {XVRESP, 0xfc0007fc, 0xf0000268, 0x1f0000, // VSX Vector Reciprocal Estimate Single-Precision XX2-form (xvresp XT,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_30_30_16_20}},
+ {XVRSPI, 0xfc0007fc, 0xf0000224, 0x1f0000, // VSX Vector Round to Single-Precision Integer using round to Nearest Away XX2-form (xvrspi XT,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_30_30_16_20}},
+ {XVRSPIC, 0xfc0007fc, 0xf00002ac, 0x1f0000, // VSX Vector Round to Single-Precision Integer Exact using Current rounding mode XX2-form (xvrspic XT,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_30_30_16_20}},
+ {XVRSPIM, 0xfc0007fc, 0xf00002e4, 0x1f0000, // VSX Vector Round to Single-Precision Integer using round toward -Infinity XX2-form (xvrspim XT,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_30_30_16_20}},
+ {XVRSPIP, 0xfc0007fc, 0xf00002a4, 0x1f0000, // VSX Vector Round to Single-Precision Integer using round toward +Infinity XX2-form (xvrspip XT,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_30_30_16_20}},
+ {XVRSPIZ, 0xfc0007fc, 0xf0000264, 0x1f0000, // VSX Vector Round to Single-Precision Integer using round toward Zero XX2-form (xvrspiz XT,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_30_30_16_20}},
+ {XVRSQRTEDP, 0xfc0007fc, 0xf0000328, 0x1f0000, // VSX Vector Reciprocal Square Root Estimate Double-Precision XX2-form (xvrsqrtedp XT,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_30_30_16_20}},
+ {XVRSQRTESP, 0xfc0007fc, 0xf0000228, 0x1f0000, // VSX Vector Reciprocal Square Root Estimate Single-Precision XX2-form (xvrsqrtesp XT,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_30_30_16_20}},
+ {XVSQRTDP, 0xfc0007fc, 0xf000032c, 0x1f0000, // VSX Vector Square Root Double-Precision XX2-form (xvsqrtdp XT,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_30_30_16_20}},
+ {XVSQRTSP, 0xfc0007fc, 0xf000022c, 0x1f0000, // VSX Vector Square Root Single-Precision XX2-form (xvsqrtsp XT,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_30_30_16_20}},
+ {XVSUBDP, 0xfc0007f8, 0xf0000340, 0x0, // VSX Vector Subtract Double-Precision XX3-form (xvsubdp XT,XA,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_29_29_11_15, ap_VecSReg_30_30_16_20}},
+ {XVSUBSP, 0xfc0007f8, 0xf0000240, 0x0, // VSX Vector Subtract Single-Precision XX3-form (xvsubsp XT,XA,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_29_29_11_15, ap_VecSReg_30_30_16_20}},
+ {XVTDIVDP, 0xfc0007f8, 0xf00003e8, 0x600001, // VSX Vector Test for software Divide Double-Precision XX3-form (xvtdivdp BF,XA,XB)
+ [5]*argField{ap_CondRegField_6_8, ap_VecSReg_29_29_11_15, ap_VecSReg_30_30_16_20}},
+ {XVTDIVSP, 0xfc0007f8, 0xf00002e8, 0x600001, // VSX Vector Test for software Divide Single-Precision XX3-form (xvtdivsp BF,XA,XB)
+ [5]*argField{ap_CondRegField_6_8, ap_VecSReg_29_29_11_15, ap_VecSReg_30_30_16_20}},
+ {XVTSQRTDP, 0xfc0007fc, 0xf00003a8, 0x7f0001, // VSX Vector Test for software Square Root Double-Precision XX2-form (xvtsqrtdp BF,XB)
+ [5]*argField{ap_CondRegField_6_8, ap_VecSReg_30_30_16_20}},
+ {XVTSQRTSP, 0xfc0007fc, 0xf00002a8, 0x7f0001, // VSX Vector Test for software Square Root Single-Precision XX2-form (xvtsqrtsp BF,XB)
+ [5]*argField{ap_CondRegField_6_8, ap_VecSReg_30_30_16_20}},
+ {XXLAND, 0xfc0007f8, 0xf0000410, 0x0, // VSX Logical AND XX3-form (xxland XT,XA,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_29_29_11_15, ap_VecSReg_30_30_16_20}},
+ {XXLANDC, 0xfc0007f8, 0xf0000450, 0x0, // VSX Logical AND with Complement XX3-form (xxlandc XT,XA,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_29_29_11_15, ap_VecSReg_30_30_16_20}},
+ {XXLEQV, 0xfc0007f8, 0xf00005d0, 0x0, // VSX Logical Equivalence XX3-form (xxleqv XT,XA,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_29_29_11_15, ap_VecSReg_30_30_16_20}},
+ {XXLNAND, 0xfc0007f8, 0xf0000590, 0x0, // VSX Logical NAND XX3-form (xxlnand XT,XA,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_29_29_11_15, ap_VecSReg_30_30_16_20}},
+ {XXLORC, 0xfc0007f8, 0xf0000550, 0x0, // VSX Logical OR with Complement XX3-form (xxlorc XT,XA,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_29_29_11_15, ap_VecSReg_30_30_16_20}},
+ {XXLNOR, 0xfc0007f8, 0xf0000510, 0x0, // VSX Logical NOR XX3-form (xxlnor XT,XA,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_29_29_11_15, ap_VecSReg_30_30_16_20}},
+ {XXLOR, 0xfc0007f8, 0xf0000490, 0x0, // VSX Logical OR XX3-form (xxlor XT,XA,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_29_29_11_15, ap_VecSReg_30_30_16_20}},
+ {XXLXOR, 0xfc0007f8, 0xf00004d0, 0x0, // VSX Logical XOR XX3-form (xxlxor XT,XA,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_29_29_11_15, ap_VecSReg_30_30_16_20}},
+ {XXMRGHW, 0xfc0007f8, 0xf0000090, 0x0, // VSX Merge High Word XX3-form (xxmrghw XT,XA,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_29_29_11_15, ap_VecSReg_30_30_16_20}},
+ {XXMRGLW, 0xfc0007f8, 0xf0000190, 0x0, // VSX Merge Low Word XX3-form (xxmrglw XT,XA,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_29_29_11_15, ap_VecSReg_30_30_16_20}},
+ {XXPERMDI, 0xfc0004f8, 0xf0000050, 0x0, // VSX Permute Doubleword Immediate XX3-form (xxpermdi XT,XA,XB,DM)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_29_29_11_15, ap_VecSReg_30_30_16_20, ap_ImmUnsigned_22_23}},
+ {XXSEL, 0xfc000030, 0xf0000030, 0x0, // VSX Select XX4-form (xxsel XT,XA,XB,XC)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_29_29_11_15, ap_VecSReg_30_30_16_20, ap_VecSReg_28_28_21_25}},
+ {XXSLDWI, 0xfc0004f8, 0xf0000010, 0x0, // VSX Shift Left Double by Word Immediate XX3-form (xxsldwi XT,XA,XB,SHW)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_29_29_11_15, ap_VecSReg_30_30_16_20, ap_ImmUnsigned_22_23}},
+ {XXSPLTW, 0xfc0007fc, 0xf0000290, 0x1c0000, // VSX Splat Word XX2-form (xxspltw XT,XB,UIM)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_30_30_16_20, ap_ImmUnsigned_14_15}},
+ {BRINC, 0xfc0007ff, 0x1000020f, 0x0, // Bit Reversed Increment EVX-form (brinc RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVABS, 0xfc0007ff, 0x10000208, 0xf800, // Vector Absolute Value EVX-form (evabs RT,RA)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15}},
+ {EVADDIW, 0xfc0007ff, 0x10000202, 0x0, // Vector Add Immediate Word EVX-form (evaddiw RT,RB,UI)
+ [5]*argField{ap_Reg_6_10, ap_Reg_16_20, ap_ImmUnsigned_11_15}},
+ {EVADDSMIAAW, 0xfc0007ff, 0x100004c9, 0xf800, // Vector Add Signed, Modulo, Integer to Accumulator Word EVX-form (evaddsmiaaw RT,RA)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15}},
+ {EVADDSSIAAW, 0xfc0007ff, 0x100004c1, 0xf800, // Vector Add Signed, Saturate, Integer to Accumulator Word EVX-form (evaddssiaaw RT,RA)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15}},
+ {EVADDUMIAAW, 0xfc0007ff, 0x100004c8, 0xf800, // Vector Add Unsigned, Modulo, Integer to Accumulator Word EVX-form (evaddumiaaw RT,RA)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15}},
+ {EVADDUSIAAW, 0xfc0007ff, 0x100004c0, 0xf800, // Vector Add Unsigned, Saturate, Integer to Accumulator Word EVX-form (evaddusiaaw RT,RA)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15}},
+ {EVADDW, 0xfc0007ff, 0x10000200, 0x0, // Vector Add Word EVX-form (evaddw RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVAND, 0xfc0007ff, 0x10000211, 0x0, // Vector AND EVX-form (evand RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVCMPEQ, 0xfc0007ff, 0x10000234, 0x600000, // Vector Compare Equal EVX-form (evcmpeq BF,RA,RB)
+ [5]*argField{ap_CondRegField_6_8, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVANDC, 0xfc0007ff, 0x10000212, 0x0, // Vector AND with Complement EVX-form (evandc RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVCMPGTS, 0xfc0007ff, 0x10000231, 0x600000, // Vector Compare Greater Than Signed EVX-form (evcmpgts BF,RA,RB)
+ [5]*argField{ap_CondRegField_6_8, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVCMPGTU, 0xfc0007ff, 0x10000230, 0x600000, // Vector Compare Greater Than Unsigned EVX-form (evcmpgtu BF,RA,RB)
+ [5]*argField{ap_CondRegField_6_8, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVCMPLTU, 0xfc0007ff, 0x10000232, 0x600000, // Vector Compare Less Than Unsigned EVX-form (evcmpltu BF,RA,RB)
+ [5]*argField{ap_CondRegField_6_8, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVCMPLTS, 0xfc0007ff, 0x10000233, 0x600000, // Vector Compare Less Than Signed EVX-form (evcmplts BF,RA,RB)
+ [5]*argField{ap_CondRegField_6_8, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVCNTLSW, 0xfc0007ff, 0x1000020e, 0xf800, // Vector Count Leading Signed Bits Word EVX-form (evcntlsw RT,RA)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15}},
+ {EVCNTLZW, 0xfc0007ff, 0x1000020d, 0xf800, // Vector Count Leading Zeros Word EVX-form (evcntlzw RT,RA)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15}},
+ {EVDIVWS, 0xfc0007ff, 0x100004c6, 0x0, // Vector Divide Word Signed EVX-form (evdivws RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVDIVWU, 0xfc0007ff, 0x100004c7, 0x0, // Vector Divide Word Unsigned EVX-form (evdivwu RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVEQV, 0xfc0007ff, 0x10000219, 0x0, // Vector Equivalent EVX-form (eveqv RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVEXTSB, 0xfc0007ff, 0x1000020a, 0xf800, // Vector Extend Sign Byte EVX-form (evextsb RT,RA)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15}},
+ {EVEXTSH, 0xfc0007ff, 0x1000020b, 0xf800, // Vector Extend Sign Halfword EVX-form (evextsh RT,RA)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15}},
+ {EVLDD, 0xfc0007ff, 0x10000301, 0x0, // Vector Load Double Word into Double Word EVX-form (evldd RT,D(RA))
+ [5]*argField{ap_Reg_6_10, ap_ImmUnsigned_16_20, ap_Reg_11_15}},
+ {EVLDH, 0xfc0007ff, 0x10000305, 0x0, // Vector Load Double into Four Halfwords EVX-form (evldh RT,D(RA))
+ [5]*argField{ap_Reg_6_10, ap_ImmUnsigned_16_20, ap_Reg_11_15}},
+ {EVLDDX, 0xfc0007ff, 0x10000300, 0x0, // Vector Load Double Word into Double Word Indexed EVX-form (evlddx RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVLDHX, 0xfc0007ff, 0x10000304, 0x0, // Vector Load Double into Four Halfwords Indexed EVX-form (evldhx RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVLDW, 0xfc0007ff, 0x10000303, 0x0, // Vector Load Double into Two Words EVX-form (evldw RT,D(RA))
+ [5]*argField{ap_Reg_6_10, ap_ImmUnsigned_16_20, ap_Reg_11_15}},
+ {EVLHHESPLAT, 0xfc0007ff, 0x10000309, 0x0, // Vector Load Halfword into Halfwords Even and Splat EVX-form (evlhhesplat RT,D(RA))
+ [5]*argField{ap_Reg_6_10, ap_ImmUnsigned_16_20, ap_Reg_11_15}},
+ {EVLDWX, 0xfc0007ff, 0x10000302, 0x0, // Vector Load Double into Two Words Indexed EVX-form (evldwx RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVLHHESPLATX, 0xfc0007ff, 0x10000308, 0x0, // Vector Load Halfword into Halfwords Even and Splat Indexed EVX-form (evlhhesplatx RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVLHHOSSPLAT, 0xfc0007ff, 0x1000030f, 0x0, // Vector Load Halfword into Halfword Odd Signed and Splat EVX-form (evlhhossplat RT,D(RA))
+ [5]*argField{ap_Reg_6_10, ap_ImmUnsigned_16_20, ap_Reg_11_15}},
+ {EVLHHOUSPLAT, 0xfc0007ff, 0x1000030d, 0x0, // Vector Load Halfword into Halfword Odd Unsigned and Splat EVX-form (evlhhousplat RT,D(RA))
+ [5]*argField{ap_Reg_6_10, ap_ImmUnsigned_16_20, ap_Reg_11_15}},
+ {EVLHHOSSPLATX, 0xfc0007ff, 0x1000030e, 0x0, // Vector Load Halfword into Halfword Odd Signed and Splat Indexed EVX-form (evlhhossplatx RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVLHHOUSPLATX, 0xfc0007ff, 0x1000030c, 0x0, // Vector Load Halfword into Halfword Odd Unsigned and Splat Indexed EVX-form (evlhhousplatx RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVLWHE, 0xfc0007ff, 0x10000311, 0x0, // Vector Load Word into Two Halfwords Even EVX-form (evlwhe RT,D(RA))
+ [5]*argField{ap_Reg_6_10, ap_ImmUnsigned_16_20, ap_Reg_11_15}},
+ {EVLWHOS, 0xfc0007ff, 0x10000317, 0x0, // Vector Load Word into Two Halfwords Odd Signed (with sign extension) EVX-form (evlwhos RT,D(RA))
+ [5]*argField{ap_Reg_6_10, ap_ImmUnsigned_16_20, ap_Reg_11_15}},
+ {EVLWHEX, 0xfc0007ff, 0x10000310, 0x0, // Vector Load Word into Two Halfwords Even Indexed EVX-form (evlwhex RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVLWHOSX, 0xfc0007ff, 0x10000316, 0x0, // Vector Load Word into Two Halfwords Odd Signed Indexed (with sign extension) EVX-form (evlwhosx RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVLWHOU, 0xfc0007ff, 0x10000315, 0x0, // Vector Load Word into Two Halfwords Odd Unsigned (zero-extended) EVX-form (evlwhou RT,D(RA))
+ [5]*argField{ap_Reg_6_10, ap_ImmUnsigned_16_20, ap_Reg_11_15}},
+ {EVLWHSPLAT, 0xfc0007ff, 0x1000031d, 0x0, // Vector Load Word into Two Halfwords and Splat EVX-form (evlwhsplat RT,D(RA))
+ [5]*argField{ap_Reg_6_10, ap_ImmUnsigned_16_20, ap_Reg_11_15}},
+ {EVLWHOUX, 0xfc0007ff, 0x10000314, 0x0, // Vector Load Word into Two Halfwords Odd Unsigned Indexed (zero-extended) EVX-form (evlwhoux RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVLWHSPLATX, 0xfc0007ff, 0x1000031c, 0x0, // Vector Load Word into Two Halfwords and Splat Indexed EVX-form (evlwhsplatx RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVLWWSPLAT, 0xfc0007ff, 0x10000319, 0x0, // Vector Load Word into Word and Splat EVX-form (evlwwsplat RT,D(RA))
+ [5]*argField{ap_Reg_6_10, ap_ImmUnsigned_16_20, ap_Reg_11_15}},
+ {EVMERGEHI, 0xfc0007ff, 0x1000022c, 0x0, // Vector Merge High EVX-form (evmergehi RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVLWWSPLATX, 0xfc0007ff, 0x10000318, 0x0, // Vector Load Word into Word and Splat Indexed EVX-form (evlwwsplatx RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVMERGELO, 0xfc0007ff, 0x1000022d, 0x0, // Vector Merge Low EVX-form (evmergelo RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVMERGEHILO, 0xfc0007ff, 0x1000022e, 0x0, // Vector Merge High/Low EVX-form (evmergehilo RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVMHEGSMFAA, 0xfc0007ff, 0x1000052b, 0x0, // Vector Multiply Halfwords, Even, Guarded, Signed, Modulo, Fractional and Accumulate EVX-form (evmhegsmfaa RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVMERGELOHI, 0xfc0007ff, 0x1000022f, 0x0, // Vector Merge Low/High EVX-form (evmergelohi RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVMHEGSMFAN, 0xfc0007ff, 0x100005ab, 0x0, // Vector Multiply Halfwords, Even, Guarded, Signed, Modulo, Fractional and Accumulate Negative EVX-form (evmhegsmfan RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVMHEGSMIAA, 0xfc0007ff, 0x10000529, 0x0, // Vector Multiply Halfwords, Even, Guarded, Signed, Modulo, Integer and Accumulate EVX-form (evmhegsmiaa RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVMHEGUMIAA, 0xfc0007ff, 0x10000528, 0x0, // Vector Multiply Halfwords, Even, Guarded, Unsigned, Modulo, Integer and Accumulate EVX-form (evmhegumiaa RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVMHEGSMIAN, 0xfc0007ff, 0x100005a9, 0x0, // Vector Multiply Halfwords, Even, Guarded, Signed, Modulo, Integer and Accumulate Negative EVX-form (evmhegsmian RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVMHEGUMIAN, 0xfc0007ff, 0x100005a8, 0x0, // Vector Multiply Halfwords, Even, Guarded, Unsigned, Modulo, Integer and Accumulate Negative EVX-form (evmhegumian RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVMHESMF, 0xfc0007ff, 0x1000040b, 0x0, // Vector Multiply Halfwords, Even, Signed, Modulo, Fractional EVX-form (evmhesmf RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVMHESMFAAW, 0xfc0007ff, 0x1000050b, 0x0, // Vector Multiply Halfwords, Even, Signed, Modulo, Fractional and Accumulate into Words EVX-form (evmhesmfaaw RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVMHESMFA, 0xfc0007ff, 0x1000042b, 0x0, // Vector Multiply Halfwords, Even, Signed, Modulo, Fractional to Accumulator EVX-form (evmhesmfa RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVMHESMFANW, 0xfc0007ff, 0x1000058b, 0x0, // Vector Multiply Halfwords, Even, Signed, Modulo, Fractional and Accumulate Negative into Words EVX-form (evmhesmfanw RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVMHESMI, 0xfc0007ff, 0x10000409, 0x0, // Vector Multiply Halfwords, Even, Signed, Modulo, Integer EVX-form (evmhesmi RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVMHESMIAAW, 0xfc0007ff, 0x10000509, 0x0, // Vector Multiply Halfwords, Even, Signed, Modulo, Integer and Accumulate into Words EVX-form (evmhesmiaaw RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVMHESMIA, 0xfc0007ff, 0x10000429, 0x0, // Vector Multiply Halfwords, Even, Signed, Modulo, Integer to Accumulator EVX-form (evmhesmia RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVMHESMIANW, 0xfc0007ff, 0x10000589, 0x0, // Vector Multiply Halfwords, Even, Signed, Modulo, Integer and Accumulate Negative into Words EVX-form (evmhesmianw RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVMHESSF, 0xfc0007ff, 0x10000403, 0x0, // Vector Multiply Halfwords, Even, Signed, Saturate, Fractional EVX-form (evmhessf RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVMHESSFA, 0xfc0007ff, 0x10000423, 0x0, // Vector Multiply Halfwords, Even, Signed, Saturate, Fractional to Accumulator EVX-form (evmhessfa RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVMHESSFAAW, 0xfc0007ff, 0x10000503, 0x0, // Vector Multiply Halfwords, Even, Signed, Saturate, Fractional and Accumulate into Words EVX-form (evmhessfaaw RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVMHESSFANW, 0xfc0007ff, 0x10000583, 0x0, // Vector Multiply Halfwords, Even, Signed, Saturate, Fractional and Accumulate Negative into Words EVX-form (evmhessfanw RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVMHESSIAAW, 0xfc0007ff, 0x10000501, 0x0, // Vector Multiply Halfwords, Even, Signed, Saturate, Integer and Accumulate into Words EVX-form (evmhessiaaw RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVMHESSIANW, 0xfc0007ff, 0x10000581, 0x0, // Vector Multiply Halfwords, Even, Signed, Saturate, Integer and Accumulate Negative into Words EVX-form (evmhessianw RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVMHEUMI, 0xfc0007ff, 0x10000408, 0x0, // Vector Multiply Halfwords, Even, Unsigned, Modulo, Integer EVX-form (evmheumi RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVMHEUMIAAW, 0xfc0007ff, 0x10000508, 0x0, // Vector Multiply Halfwords, Even, Unsigned, Modulo, Integer and Accumulate into Words EVX-form (evmheumiaaw RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVMHEUMIA, 0xfc0007ff, 0x10000428, 0x0, // Vector Multiply Halfwords, Even, Unsigned, Modulo, Integer to Accumulator EVX-form (evmheumia RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVMHEUMIANW, 0xfc0007ff, 0x10000588, 0x0, // Vector Multiply Halfwords, Even, Unsigned, Modulo, Integer and Accumulate Negative into Words EVX-form (evmheumianw RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVMHEUSIAAW, 0xfc0007ff, 0x10000500, 0x0, // Vector Multiply Halfwords, Even, Unsigned, Saturate, Integer and Accumulate into Words EVX-form (evmheusiaaw RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVMHEUSIANW, 0xfc0007ff, 0x10000580, 0x0, // Vector Multiply Halfwords, Even, Unsigned, Saturate, Integer and Accumulate Negative into Words EVX-form (evmheusianw RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVMHOGSMFAA, 0xfc0007ff, 0x1000052f, 0x0, // Vector Multiply Halfwords, Odd, Guarded, Signed, Modulo, Fractional and Accumulate EVX-form (evmhogsmfaa RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVMHOGSMIAA, 0xfc0007ff, 0x1000052d, 0x0, // Vector Multiply Halfwords, Odd, Guarded, Signed, Modulo, Integer and Accumulate EVX-form (evmhogsmiaa RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVMHOGSMFAN, 0xfc0007ff, 0x100005af, 0x0, // Vector Multiply Halfwords, Odd, Guarded, Signed, Modulo, Fractional and Accumulate Negative EVX-form (evmhogsmfan RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVMHOGSMIAN, 0xfc0007ff, 0x100005ad, 0x0, // Vector Multiply Halfwords, Odd, Guarded, Signed, Modulo, Integer and Accumulate Negative EVX-form (evmhogsmian RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVMHOGUMIAA, 0xfc0007ff, 0x1000052c, 0x0, // Vector Multiply Halfwords, Odd, Guarded, Unsigned, Modulo, Integer and Accumulate EVX-form (evmhogumiaa RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVMHOSMF, 0xfc0007ff, 0x1000040f, 0x0, // Vector Multiply Halfwords, Odd, Signed, Modulo, Fractional EVX-form (evmhosmf RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVMHOGUMIAN, 0xfc0007ff, 0x100005ac, 0x0, // Vector Multiply Halfwords, Odd, Guarded, Unsigned, Modulo, Integer and Accumulate Negative EVX-form (evmhogumian RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVMHOSMFA, 0xfc0007ff, 0x1000042f, 0x0, // Vector Multiply Halfwords, Odd, Signed, Modulo, Fractional to Accumulator EVX-form (evmhosmfa RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVMHOSMFAAW, 0xfc0007ff, 0x1000050f, 0x0, // Vector Multiply Halfwords, Odd, Signed, Modulo, Fractional and Accumulate into Words EVX-form (evmhosmfaaw RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVMHOSMI, 0xfc0007ff, 0x1000040d, 0x0, // Vector Multiply Halfwords, Odd, Signed, Modulo, Integer EVX-form (evmhosmi RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVMHOSMFANW, 0xfc0007ff, 0x1000058f, 0x0, // Vector Multiply Halfwords, Odd, Signed, Modulo, Fractional and Accumulate Negative into Words EVX-form (evmhosmfanw RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVMHOSMIA, 0xfc0007ff, 0x1000042d, 0x0, // Vector Multiply Halfwords, Odd, Signed, Modulo, Integer to Accumulator EVX-form (evmhosmia RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVMHOSMIAAW, 0xfc0007ff, 0x1000050d, 0x0, // Vector Multiply Halfwords, Odd, Signed, Modulo, Integer and Accumulate into Words EVX-form (evmhosmiaaw RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVMHOSMIANW, 0xfc0007ff, 0x1000058d, 0x0, // Vector Multiply Halfwords, Odd, Signed, Modulo, Integer and Accumulate Negative into Words EVX-form (evmhosmianw RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVMHOSSF, 0xfc0007ff, 0x10000407, 0x0, // Vector Multiply Halfwords, Odd, Signed, Saturate, Fractional EVX-form (evmhossf RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVMHOSSFA, 0xfc0007ff, 0x10000427, 0x0, // Vector Multiply Halfwords, Odd, Signed, Saturate, Fractional to Accumulator EVX-form (evmhossfa RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVMHOSSFAAW, 0xfc0007ff, 0x10000507, 0x0, // Vector Multiply Halfwords, Odd, Signed, Saturate, Fractional and Accumulate into Words EVX-form (evmhossfaaw RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVMHOSSFANW, 0xfc0007ff, 0x10000587, 0x0, // Vector Multiply Halfwords, Odd, Signed, Saturate, Fractional and Accumulate Negative into Words EVX-form (evmhossfanw RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVMHOSSIAAW, 0xfc0007ff, 0x10000505, 0x0, // Vector Multiply Halfwords, Odd, Signed, Saturate, Integer and Accumulate into Words EVX-form (evmhossiaaw RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVMHOUMI, 0xfc0007ff, 0x1000040c, 0x0, // Vector Multiply Halfwords, Odd, Unsigned, Modulo, Integer EVX-form (evmhoumi RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVMHOSSIANW, 0xfc0007ff, 0x10000585, 0x0, // Vector Multiply Halfwords, Odd, Signed, Saturate, Integer and Accumulate Negative into Words EVX-form (evmhossianw RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVMHOUMIA, 0xfc0007ff, 0x1000042c, 0x0, // Vector Multiply Halfwords, Odd, Unsigned, Modulo, Integer to Accumulator EVX-form (evmhoumia RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVMHOUMIAAW, 0xfc0007ff, 0x1000050c, 0x0, // Vector Multiply Halfwords, Odd, Unsigned, Modulo, Integer and Accumulate into Words EVX-form (evmhoumiaaw RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVMHOUSIAAW, 0xfc0007ff, 0x10000504, 0x0, // Vector Multiply Halfwords, Odd, Unsigned, Saturate, Integer and Accumulate into Words EVX-form (evmhousiaaw RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVMHOUMIANW, 0xfc0007ff, 0x1000058c, 0x0, // Vector Multiply Halfwords, Odd, Unsigned, Modulo, Integer and Accumulate Negative into Words EVX-form (evmhoumianw RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVMHOUSIANW, 0xfc0007ff, 0x10000584, 0x0, // Vector Multiply Halfwords, Odd, Unsigned, Saturate, Integer and Accumulate Negative into Words EVX-form (evmhousianw RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVMRA, 0xfc0007ff, 0x100004c4, 0xf800, // Initialize Accumulator EVX-form (evmra RT,RA)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15}},
+ {EVMWHSMF, 0xfc0007ff, 0x1000044f, 0x0, // Vector Multiply Word High Signed, Modulo, Fractional EVX-form (evmwhsmf RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVMWHSMI, 0xfc0007ff, 0x1000044d, 0x0, // Vector Multiply Word High Signed, Modulo, Integer EVX-form (evmwhsmi RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVMWHSMFA, 0xfc0007ff, 0x1000046f, 0x0, // Vector Multiply Word High Signed, Modulo, Fractional to Accumulator EVX-form (evmwhsmfa RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVMWHSMIA, 0xfc0007ff, 0x1000046d, 0x0, // Vector Multiply Word High Signed, Modulo, Integer to Accumulator EVX-form (evmwhsmia RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVMWHSSF, 0xfc0007ff, 0x10000447, 0x0, // Vector Multiply Word High Signed, Saturate, Fractional EVX-form (evmwhssf RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVMWHUMI, 0xfc0007ff, 0x1000044c, 0x0, // Vector Multiply Word High Unsigned, Modulo, Integer EVX-form (evmwhumi RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVMWHSSFA, 0xfc0007ff, 0x10000467, 0x0, // Vector Multiply Word High Signed, Saturate, Fractional to Accumulator EVX-form (evmwhssfa RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVMWHUMIA, 0xfc0007ff, 0x1000046c, 0x0, // Vector Multiply Word High Unsigned, Modulo, Integer to Accumulator EVX-form (evmwhumia RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVMWLSMIAAW, 0xfc0007ff, 0x10000549, 0x0, // Vector Multiply Word Low Signed, Modulo, Integer and Accumulate into Words EVX-form (evmwlsmiaaw RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVMWLSSIAAW, 0xfc0007ff, 0x10000541, 0x0, // Vector Multiply Word Low Signed, Saturate, Integer and Accumulate into Words EVX-form (evmwlssiaaw RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVMWLSMIANW, 0xfc0007ff, 0x100005c9, 0x0, // Vector Multiply Word Low Signed, Modulo, Integer and Accumulate Negative in Words EVX-form (evmwlsmianw RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVMWLSSIANW, 0xfc0007ff, 0x100005c1, 0x0, // Vector Multiply Word Low Signed, Saturate, Integer and Accumulate Negative in Words EVX-form (evmwlssianw RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVMWLUMI, 0xfc0007ff, 0x10000448, 0x0, // Vector Multiply Word Low Unsigned, Modulo, Integer EVX-form (evmwlumi RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVMWLUMIAAW, 0xfc0007ff, 0x10000548, 0x0, // Vector Multiply Word Low Unsigned, Modulo, Integer and Accumulate into Words EVX-form (evmwlumiaaw RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVMWLUMIA, 0xfc0007ff, 0x10000468, 0x0, // Vector Multiply Word Low Unsigned, Modulo, Integer to Accumulator EVX-form (evmwlumia RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVMWLUMIANW, 0xfc0007ff, 0x100005c8, 0x0, // Vector Multiply Word Low Unsigned, Modulo, Integer and Accumulate Negative in Words EVX-form (evmwlumianw RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVMWLUSIAAW, 0xfc0007ff, 0x10000540, 0x0, // Vector Multiply Word Low Unsigned, Saturate, Integer and Accumulate into Words EVX-form (evmwlusiaaw RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVMWSMF, 0xfc0007ff, 0x1000045b, 0x0, // Vector Multiply Word Signed, Modulo, Fractional EVX-form (evmwsmf RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVMWLUSIANW, 0xfc0007ff, 0x100005c0, 0x0, // Vector Multiply Word Low Unsigned, Saturate, Integer and Accumulate Negative in Words EVX-form (evmwlusianw RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVMWSMFA, 0xfc0007ff, 0x1000047b, 0x0, // Vector Multiply Word Signed, Modulo, Fractional to Accumulator EVX-form (evmwsmfa RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVMWSMFAA, 0xfc0007ff, 0x1000055b, 0x0, // Vector Multiply Word Signed, Modulo, Fractional and Accumulate EVX-form (evmwsmfaa RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVMWSMI, 0xfc0007ff, 0x10000459, 0x0, // Vector Multiply Word Signed, Modulo, Integer EVX-form (evmwsmi RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVMWSMIAA, 0xfc0007ff, 0x10000559, 0x0, // Vector Multiply Word Signed, Modulo, Integer and Accumulate EVX-form (evmwsmiaa RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVMWSMFAN, 0xfc0007ff, 0x100005db, 0x0, // Vector Multiply Word Signed, Modulo, Fractional and Accumulate Negative EVX-form (evmwsmfan RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVMWSMIA, 0xfc0007ff, 0x10000479, 0x0, // Vector Multiply Word Signed, Modulo, Integer to Accumulator EVX-form (evmwsmia RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVMWSMIAN, 0xfc0007ff, 0x100005d9, 0x0, // Vector Multiply Word Signed, Modulo, Integer and Accumulate Negative EVX-form (evmwsmian RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVMWSSF, 0xfc0007ff, 0x10000453, 0x0, // Vector Multiply Word Signed, Saturate, Fractional EVX-form (evmwssf RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVMWSSFA, 0xfc0007ff, 0x10000473, 0x0, // Vector Multiply Word Signed, Saturate, Fractional to Accumulator EVX-form (evmwssfa RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVMWSSFAA, 0xfc0007ff, 0x10000553, 0x0, // Vector Multiply Word Signed, Saturate, Fractional and Accumulate EVX-form (evmwssfaa RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVMWUMI, 0xfc0007ff, 0x10000458, 0x0, // Vector Multiply Word Unsigned, Modulo, Integer EVX-form (evmwumi RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVMWSSFAN, 0xfc0007ff, 0x100005d3, 0x0, // Vector Multiply Word Signed, Saturate, Fractional and Accumulate Negative EVX-form (evmwssfan RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVMWUMIA, 0xfc0007ff, 0x10000478, 0x0, // Vector Multiply Word Unsigned, Modulo, Integer to Accumulator EVX-form (evmwumia RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVMWUMIAA, 0xfc0007ff, 0x10000558, 0x0, // Vector Multiply Word Unsigned, Modulo, Integer and Accumulate EVX-form (evmwumiaa RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVNAND, 0xfc0007ff, 0x1000021e, 0x0, // Vector NAND EVX-form (evnand RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVMWUMIAN, 0xfc0007ff, 0x100005d8, 0x0, // Vector Multiply Word Unsigned, Modulo, Integer and Accumulate Negative EVX-form (evmwumian RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVNEG, 0xfc0007ff, 0x10000209, 0xf800, // Vector Negate EVX-form (evneg RT,RA)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15}},
+ {EVNOR, 0xfc0007ff, 0x10000218, 0x0, // Vector NOR EVX-form (evnor RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVORC, 0xfc0007ff, 0x1000021b, 0x0, // Vector OR with Complement EVX-form (evorc RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVOR, 0xfc0007ff, 0x10000217, 0x0, // Vector OR EVX-form (evor RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVRLW, 0xfc0007ff, 0x10000228, 0x0, // Vector Rotate Left Word EVX-form (evrlw RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVRLWI, 0xfc0007ff, 0x1000022a, 0x0, // Vector Rotate Left Word Immediate EVX-form (evrlwi RT,RA,UI)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_ImmUnsigned_16_20}},
+ {EVSEL, 0xfc0007f8, 0x10000278, 0x0, // Vector Select EVS-form (evsel RT,RA,RB,BFA)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20, ap_CondRegField_29_31}},
+ {EVRNDW, 0xfc0007ff, 0x1000020c, 0xf800, // Vector Round Word EVX-form (evrndw RT,RA)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15}},
+ {EVSLW, 0xfc0007ff, 0x10000224, 0x0, // Vector Shift Left Word EVX-form (evslw RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVSPLATFI, 0xfc0007ff, 0x1000022b, 0xf800, // Vector Splat Fractional Immediate EVX-form (evsplatfi RT,SI)
+ [5]*argField{ap_Reg_6_10, ap_ImmSigned_11_15}},
+ {EVSRWIS, 0xfc0007ff, 0x10000223, 0x0, // Vector Shift Right Word Immediate Signed EVX-form (evsrwis RT,RA,UI)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_ImmUnsigned_16_20}},
+ {EVSLWI, 0xfc0007ff, 0x10000226, 0x0, // Vector Shift Left Word Immediate EVX-form (evslwi RT,RA,UI)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_ImmUnsigned_16_20}},
+ {EVSPLATI, 0xfc0007ff, 0x10000229, 0xf800, // Vector Splat Immediate EVX-form (evsplati RT,SI)
+ [5]*argField{ap_Reg_6_10, ap_ImmSigned_11_15}},
+ {EVSRWIU, 0xfc0007ff, 0x10000222, 0x0, // Vector Shift Right Word Immediate Unsigned EVX-form (evsrwiu RT,RA,UI)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_ImmUnsigned_16_20}},
+ {EVSRWS, 0xfc0007ff, 0x10000221, 0x0, // Vector Shift Right Word Signed EVX-form (evsrws RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVSTDD, 0xfc0007ff, 0x10000321, 0x0, // Vector Store Double of Double EVX-form (evstdd RS,D(RA))
+ [5]*argField{ap_Reg_6_10, ap_ImmUnsigned_16_20, ap_Reg_11_15}},
+ {EVSRWU, 0xfc0007ff, 0x10000220, 0x0, // Vector Shift Right Word Unsigned EVX-form (evsrwu RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVSTDDX, 0xfc0007ff, 0x10000320, 0x0, // Vector Store Double of Double Indexed EVX-form (evstddx RS,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVSTDH, 0xfc0007ff, 0x10000325, 0x0, // Vector Store Double of Four Halfwords EVX-form (evstdh RS,D(RA))
+ [5]*argField{ap_Reg_6_10, ap_ImmUnsigned_16_20, ap_Reg_11_15}},
+ {EVSTDW, 0xfc0007ff, 0x10000323, 0x0, // Vector Store Double of Two Words EVX-form (evstdw RS,D(RA))
+ [5]*argField{ap_Reg_6_10, ap_ImmUnsigned_16_20, ap_Reg_11_15}},
+ {EVSTDHX, 0xfc0007ff, 0x10000324, 0x0, // Vector Store Double of Four Halfwords Indexed EVX-form (evstdhx RS,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVSTDWX, 0xfc0007ff, 0x10000322, 0x0, // Vector Store Double of Two Words Indexed EVX-form (evstdwx RS,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVSTWHE, 0xfc0007ff, 0x10000331, 0x0, // Vector Store Word of Two Halfwords from Even EVX-form (evstwhe RS,D(RA))
+ [5]*argField{ap_Reg_6_10, ap_ImmUnsigned_16_20, ap_Reg_11_15}},
+ {EVSTWHO, 0xfc0007ff, 0x10000335, 0x0, // Vector Store Word of Two Halfwords from Odd EVX-form (evstwho RS,D(RA))
+ [5]*argField{ap_Reg_6_10, ap_ImmUnsigned_16_20, ap_Reg_11_15}},
+ {EVSTWWE, 0xfc0007ff, 0x10000339, 0x0, // Vector Store Word of Word from Even EVX-form (evstwwe RS,D(RA))
+ [5]*argField{ap_Reg_6_10, ap_ImmUnsigned_16_20, ap_Reg_11_15}},
+ {EVSTWHEX, 0xfc0007ff, 0x10000330, 0x0, // Vector Store Word of Two Halfwords from Even Indexed EVX-form (evstwhex RS,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVSTWHOX, 0xfc0007ff, 0x10000334, 0x0, // Vector Store Word of Two Halfwords from Odd Indexed EVX-form (evstwhox RS,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVSTWWEX, 0xfc0007ff, 0x10000338, 0x0, // Vector Store Word of Word from Even Indexed EVX-form (evstwwex RS,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVSTWWO, 0xfc0007ff, 0x1000033d, 0x0, // Vector Store Word of Word from Odd EVX-form (evstwwo RS,D(RA))
+ [5]*argField{ap_Reg_6_10, ap_ImmUnsigned_16_20, ap_Reg_11_15}},
+ {EVSUBFSMIAAW, 0xfc0007ff, 0x100004cb, 0xf800, // Vector Subtract Signed, Modulo, Integer to Accumulator Word EVX-form (evsubfsmiaaw RT,RA)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15}},
+ {EVSTWWOX, 0xfc0007ff, 0x1000033c, 0x0, // Vector Store Word of Word from Odd Indexed EVX-form (evstwwox RS,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVSUBFSSIAAW, 0xfc0007ff, 0x100004c3, 0xf800, // Vector Subtract Signed, Saturate, Integer to Accumulator Word EVX-form (evsubfssiaaw RT,RA)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15}},
+ {EVSUBFUMIAAW, 0xfc0007ff, 0x100004ca, 0xf800, // Vector Subtract Unsigned, Modulo, Integer to Accumulator Word EVX-form (evsubfumiaaw RT,RA)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15}},
+ {EVSUBFUSIAAW, 0xfc0007ff, 0x100004c2, 0xf800, // Vector Subtract Unsigned, Saturate, Integer to Accumulator Word EVX-form (evsubfusiaaw RT,RA)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15}},
+ {EVSUBFW, 0xfc0007ff, 0x10000204, 0x0, // Vector Subtract from Word EVX-form (evsubfw RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVSUBIFW, 0xfc0007ff, 0x10000206, 0x0, // Vector Subtract Immediate from Word EVX-form (evsubifw RT,UI,RB)
+ [5]*argField{ap_Reg_6_10, ap_ImmUnsigned_11_15, ap_Reg_16_20}},
+ {EVXOR, 0xfc0007ff, 0x10000216, 0x0, // Vector XOR EVX-form (evxor RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVFSABS, 0xfc0007ff, 0x10000284, 0xf800, // Vector Floating-Point Single-Precision Absolute Value EVX-form (evfsabs RT,RA)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15}},
+ {EVFSNABS, 0xfc0007ff, 0x10000285, 0xf800, // Vector Floating-Point Single-Precision Negative Absolute Value EVX-form (evfsnabs RT,RA)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15}},
+ {EVFSNEG, 0xfc0007ff, 0x10000286, 0xf800, // Vector Floating-Point Single-Precision Negate EVX-form (evfsneg RT,RA)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15}},
+ {EVFSADD, 0xfc0007ff, 0x10000280, 0x0, // Vector Floating-Point Single-Precision Add EVX-form (evfsadd RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVFSMUL, 0xfc0007ff, 0x10000288, 0x0, // Vector Floating-Point Single-Precision Multiply EVX-form (evfsmul RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVFSSUB, 0xfc0007ff, 0x10000281, 0x0, // Vector Floating-Point Single-Precision Subtract EVX-form (evfssub RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVFSDIV, 0xfc0007ff, 0x10000289, 0x0, // Vector Floating-Point Single-Precision Divide EVX-form (evfsdiv RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVFSCMPGT, 0xfc0007ff, 0x1000028c, 0x600000, // Vector Floating-Point Single-Precision Compare Greater Than EVX-form (evfscmpgt BF,RA,RB)
+ [5]*argField{ap_CondRegField_6_8, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVFSCMPLT, 0xfc0007ff, 0x1000028d, 0x600000, // Vector Floating-Point Single-Precision Compare Less Than EVX-form (evfscmplt BF,RA,RB)
+ [5]*argField{ap_CondRegField_6_8, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVFSCMPEQ, 0xfc0007ff, 0x1000028e, 0x600000, // Vector Floating-Point Single-Precision Compare Equal EVX-form (evfscmpeq BF,RA,RB)
+ [5]*argField{ap_CondRegField_6_8, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVFSTSTGT, 0xfc0007ff, 0x1000029c, 0x600000, // Vector Floating-Point Single-Precision Test Greater Than EVX-form (evfststgt BF,RA,RB)
+ [5]*argField{ap_CondRegField_6_8, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVFSTSTLT, 0xfc0007ff, 0x1000029d, 0x600000, // Vector Floating-Point Single-Precision Test Less Than EVX-form (evfststlt BF,RA,RB)
+ [5]*argField{ap_CondRegField_6_8, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVFSTSTEQ, 0xfc0007ff, 0x1000029e, 0x600000, // Vector Floating-Point Single-Precision Test Equal EVX-form (evfststeq BF,RA,RB)
+ [5]*argField{ap_CondRegField_6_8, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVFSCFSI, 0xfc0007ff, 0x10000291, 0x1f0000, // Vector Convert Floating-Point Single-Precision from Signed Integer EVX-form (evfscfsi RT,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_16_20}},
+ {EVFSCFSF, 0xfc0007ff, 0x10000293, 0x1f0000, // Vector Convert Floating-Point Single-Precision from Signed Fraction EVX-form (evfscfsf RT,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_16_20}},
+ {EVFSCFUI, 0xfc0007ff, 0x10000290, 0x1f0000, // Vector Convert Floating-Point Single-Precision from Unsigned Integer EVX-form (evfscfui RT,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_16_20}},
+ {EVFSCFUF, 0xfc0007ff, 0x10000292, 0x1f0000, // Vector Convert Floating-Point Single-Precision from Unsigned Fraction EVX-form (evfscfuf RT,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_16_20}},
+ {EVFSCTSI, 0xfc0007ff, 0x10000295, 0x1f0000, // Vector Convert Floating-Point Single-Precision to Signed Integer EVX-form (evfsctsi RT,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_16_20}},
+ {EVFSCTUI, 0xfc0007ff, 0x10000294, 0x1f0000, // Vector Convert Floating-Point Single-Precision to Unsigned Integer EVX-form (evfsctui RT,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_16_20}},
+ {EVFSCTSIZ, 0xfc0007ff, 0x1000029a, 0x1f0000, // Vector Convert Floating-Point Single-Precision to Signed Integer with Round toward Zero EVX-form (evfsctsiz RT,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_16_20}},
+ {EVFSCTUIZ, 0xfc0007ff, 0x10000298, 0x1f0000, // Vector Convert Floating-Point Single-Precision to Unsigned Integer with Round toward Zero EVX-form (evfsctuiz RT,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_16_20}},
+ {EVFSCTSF, 0xfc0007ff, 0x10000297, 0x1f0000, // Vector Convert Floating-Point Single-Precision to Signed Fraction EVX-form (evfsctsf RT,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_16_20}},
+ {EVFSCTUF, 0xfc0007ff, 0x10000296, 0x1f0000, // Vector Convert Floating-Point Single-Precision to Unsigned Fraction EVX-form (evfsctuf RT,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_16_20}},
+ {EFSABS, 0xfc0007ff, 0x100002c4, 0xf800, // Floating-Point Single-Precision Absolute Value EVX-form (efsabs RT,RA)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15}},
+ {EFSNEG, 0xfc0007ff, 0x100002c6, 0xf800, // Floating-Point Single-Precision Negate EVX-form (efsneg RT,RA)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15}},
+ {EFSNABS, 0xfc0007ff, 0x100002c5, 0xf800, // Floating-Point Single-Precision Negative Absolute Value EVX-form (efsnabs RT,RA)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15}},
+ {EFSADD, 0xfc0007ff, 0x100002c0, 0x0, // Floating-Point Single-Precision Add EVX-form (efsadd RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EFSMUL, 0xfc0007ff, 0x100002c8, 0x0, // Floating-Point Single-Precision Multiply EVX-form (efsmul RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EFSSUB, 0xfc0007ff, 0x100002c1, 0x0, // Floating-Point Single-Precision Subtract EVX-form (efssub RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EFSDIV, 0xfc0007ff, 0x100002c9, 0x0, // Floating-Point Single-Precision Divide EVX-form (efsdiv RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EFSCMPGT, 0xfc0007ff, 0x100002cc, 0x600000, // Floating-Point Single-Precision Compare Greater Than EVX-form (efscmpgt BF,RA,RB)
+ [5]*argField{ap_CondRegField_6_8, ap_Reg_11_15, ap_Reg_16_20}},
+ {EFSCMPLT, 0xfc0007ff, 0x100002cd, 0x600000, // Floating-Point Single-Precision Compare Less Than EVX-form (efscmplt BF,RA,RB)
+ [5]*argField{ap_CondRegField_6_8, ap_Reg_11_15, ap_Reg_16_20}},
+ {EFSCMPEQ, 0xfc0007ff, 0x100002ce, 0x600000, // Floating-Point Single-Precision Compare Equal EVX-form (efscmpeq BF,RA,RB)
+ [5]*argField{ap_CondRegField_6_8, ap_Reg_11_15, ap_Reg_16_20}},
+ {EFSTSTGT, 0xfc0007ff, 0x100002dc, 0x600000, // Floating-Point Single-Precision Test Greater Than EVX-form (efststgt BF,RA,RB)
+ [5]*argField{ap_CondRegField_6_8, ap_Reg_11_15, ap_Reg_16_20}},
+ {EFSTSTLT, 0xfc0007ff, 0x100002dd, 0x600000, // Floating-Point Single-Precision Test Less Than EVX-form (efststlt BF,RA,RB)
+ [5]*argField{ap_CondRegField_6_8, ap_Reg_11_15, ap_Reg_16_20}},
+ {EFSTSTEQ, 0xfc0007ff, 0x100002de, 0x600000, // Floating-Point Single-Precision Test Equal EVX-form (efststeq BF,RA,RB)
+ [5]*argField{ap_CondRegField_6_8, ap_Reg_11_15, ap_Reg_16_20}},
+ {EFSCFSI, 0xfc0007ff, 0x100002d1, 0x1f0000, // Convert Floating-Point Single-Precision from Signed Integer EVX-form (efscfsi RT,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_16_20}},
+ {EFSCFSF, 0xfc0007ff, 0x100002d3, 0x1f0000, // Convert Floating-Point Single-Precision from Signed Fraction EVX-form (efscfsf RT,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_16_20}},
+ {EFSCTSI, 0xfc0007ff, 0x100002d5, 0x1f0000, // Convert Floating-Point Single-Precision to Signed Integer EVX-form (efsctsi RT,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_16_20}},
+ {EFSCFUI, 0xfc0007ff, 0x100002d0, 0x1f0000, // Convert Floating-Point Single-Precision from Unsigned Integer EVX-form (efscfui RT,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_16_20}},
+ {EFSCFUF, 0xfc0007ff, 0x100002d2, 0x1f0000, // Convert Floating-Point Single-Precision from Unsigned Fraction EVX-form (efscfuf RT,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_16_20}},
+ {EFSCTUI, 0xfc0007ff, 0x100002d4, 0x1f0000, // Convert Floating-Point Single-Precision to Unsigned Integer EVX-form (efsctui RT,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_16_20}},
+ {EFSCTSIZ, 0xfc0007ff, 0x100002da, 0x1f0000, // Convert Floating-Point Single-Precision to Signed Integer with Round toward Zero EVX-form (efsctsiz RT,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_16_20}},
+ {EFSCTSF, 0xfc0007ff, 0x100002d7, 0x1f0000, // Convert Floating-Point Single-Precision to Signed Fraction EVX-form (efsctsf RT,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_16_20}},
+ {EFSCTUIZ, 0xfc0007ff, 0x100002d8, 0x1f0000, // Convert Floating-Point Single-Precision to Unsigned Integer with Round toward Zero EVX-form (efsctuiz RT,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_16_20}},
+ {EFSCTUF, 0xfc0007ff, 0x100002d6, 0x1f0000, // Convert Floating-Point Single-Precision to Unsigned Fraction EVX-form (efsctuf RT,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_16_20}},
+ {EFDABS, 0xfc0007ff, 0x100002e4, 0xf800, // Floating-Point Double-Precision Absolute Value EVX-form (efdabs RT,RA)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15}},
+ {EFDNEG, 0xfc0007ff, 0x100002e6, 0xf800, // Floating-Point Double-Precision Negate EVX-form (efdneg RT,RA)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15}},
+ {EFDNABS, 0xfc0007ff, 0x100002e5, 0xf800, // Floating-Point Double-Precision Negative Absolute Value EVX-form (efdnabs RT,RA)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15}},
+ {EFDADD, 0xfc0007ff, 0x100002e0, 0x0, // Floating-Point Double-Precision Add EVX-form (efdadd RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EFDMUL, 0xfc0007ff, 0x100002e8, 0x0, // Floating-Point Double-Precision Multiply EVX-form (efdmul RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EFDSUB, 0xfc0007ff, 0x100002e1, 0x0, // Floating-Point Double-Precision Subtract EVX-form (efdsub RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EFDDIV, 0xfc0007ff, 0x100002e9, 0x0, // Floating-Point Double-Precision Divide EVX-form (efddiv RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EFDCMPGT, 0xfc0007ff, 0x100002ec, 0x600000, // Floating-Point Double-Precision Compare Greater Than EVX-form (efdcmpgt BF,RA,RB)
+ [5]*argField{ap_CondRegField_6_8, ap_Reg_11_15, ap_Reg_16_20}},
+ {EFDCMPEQ, 0xfc0007ff, 0x100002ee, 0x600000, // Floating-Point Double-Precision Compare Equal EVX-form (efdcmpeq BF,RA,RB)
+ [5]*argField{ap_CondRegField_6_8, ap_Reg_11_15, ap_Reg_16_20}},
+ {EFDCMPLT, 0xfc0007ff, 0x100002ed, 0x600000, // Floating-Point Double-Precision Compare Less Than EVX-form (efdcmplt BF,RA,RB)
+ [5]*argField{ap_CondRegField_6_8, ap_Reg_11_15, ap_Reg_16_20}},
+ {EFDTSTGT, 0xfc0007ff, 0x100002fc, 0x600000, // Floating-Point Double-Precision Test Greater Than EVX-form (efdtstgt BF,RA,RB)
+ [5]*argField{ap_CondRegField_6_8, ap_Reg_11_15, ap_Reg_16_20}},
+ {EFDTSTLT, 0xfc0007ff, 0x100002fd, 0x600000, // Floating-Point Double-Precision Test Less Than EVX-form (efdtstlt BF,RA,RB)
+ [5]*argField{ap_CondRegField_6_8, ap_Reg_11_15, ap_Reg_16_20}},
+ {EFDCFSI, 0xfc0007ff, 0x100002f1, 0x1f0000, // Convert Floating-Point Double-Precision from Signed Integer EVX-form (efdcfsi RT,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_16_20}},
+ {EFDTSTEQ, 0xfc0007ff, 0x100002fe, 0x600000, // Floating-Point Double-Precision Test Equal EVX-form (efdtsteq BF,RA,RB)
+ [5]*argField{ap_CondRegField_6_8, ap_Reg_11_15, ap_Reg_16_20}},
+ {EFDCFUI, 0xfc0007ff, 0x100002f0, 0x1f0000, // Convert Floating-Point Double-Precision from Unsigned Integer EVX-form (efdcfui RT,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_16_20}},
+ {EFDCFSID, 0xfc0007ff, 0x100002e3, 0x1f0000, // Convert Floating-Point Double-Precision from Signed Integer Doubleword EVX-form (efdcfsid RT,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_16_20}},
+ {EFDCFSF, 0xfc0007ff, 0x100002f3, 0x1f0000, // Convert Floating-Point Double-Precision from Signed Fraction EVX-form (efdcfsf RT,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_16_20}},
+ {EFDCFUF, 0xfc0007ff, 0x100002f2, 0x1f0000, // Convert Floating-Point Double-Precision from Unsigned Fraction EVX-form (efdcfuf RT,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_16_20}},
+ {EFDCFUID, 0xfc0007ff, 0x100002e2, 0x1f0000, // Convert Floating-Point Double-Precision from Unsigned Integer Doubleword EVX-form (efdcfuid RT,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_16_20}},
+ {EFDCTSI, 0xfc0007ff, 0x100002f5, 0x1f0000, // Convert Floating-Point Double-Precision to Signed Integer EVX-form (efdctsi RT,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_16_20}},
+ {EFDCTUI, 0xfc0007ff, 0x100002f4, 0x1f0000, // Convert Floating-Point Double-Precision to Unsigned Integer EVX-form (efdctui RT,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_16_20}},
+ {EFDCTSIDZ, 0xfc0007ff, 0x100002eb, 0x1f0000, // Convert Floating-Point Double-Precision to Signed Integer Doubleword with Round toward Zero EVX-form (efdctsidz RT,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_16_20}},
+ {EFDCTUIDZ, 0xfc0007ff, 0x100002ea, 0x1f0000, // Convert Floating-Point Double-Precision to Unsigned Integer Doubleword with Round toward Zero EVX-form (efdctuidz RT,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_16_20}},
+ {EFDCTSIZ, 0xfc0007ff, 0x100002fa, 0x1f0000, // Convert Floating-Point Double-Precision to Signed Integer with Round toward Zero EVX-form (efdctsiz RT,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_16_20}},
+ {EFDCTSF, 0xfc0007ff, 0x100002f7, 0x1f0000, // Convert Floating-Point Double-Precision to Signed Fraction EVX-form (efdctsf RT,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_16_20}},
+ {EFDCTUF, 0xfc0007ff, 0x100002f6, 0x1f0000, // Convert Floating-Point Double-Precision to Unsigned Fraction EVX-form (efdctuf RT,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_16_20}},
+ {EFDCTUIZ, 0xfc0007ff, 0x100002f8, 0x1f0000, // Convert Floating-Point Double-Precision to Unsigned Integer with Round toward Zero EVX-form (efdctuiz RT,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_16_20}},
+ {EFDCFS, 0xfc0007ff, 0x100002ef, 0x1f0000, // Floating-Point Double-Precision Convert from Single-Precision EVX-form (efdcfs RT,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_16_20}},
+ {EFSCFD, 0xfc0007ff, 0x100002cf, 0x1f0000, // Floating-Point Single-Precision Convert from Double-Precision EVX-form (efscfd RT,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_16_20}},
+ {DLMZB, 0xfc0007ff, 0x7c00009c, 0x0, // Determine Leftmost Zero Byte X-form (dlmzb RA,RS,RB)
+ [5]*argField{ap_Reg_11_15, ap_Reg_6_10, ap_Reg_16_20}},
+ {DLMZB_, 0xfc0007ff, 0x7c00009d, 0x0, // Determine Leftmost Zero Byte X-form (dlmzb. RA,RS,RB)
+ [5]*argField{ap_Reg_11_15, ap_Reg_6_10, ap_Reg_16_20}},
+ {MACCHW, 0xfc0007ff, 0x10000158, 0x0, // Multiply Accumulate Cross Halfword to Word Modulo Signed XO-form (macchw RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {MACCHW_, 0xfc0007ff, 0x10000159, 0x0, // Multiply Accumulate Cross Halfword to Word Modulo Signed XO-form (macchw. RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {MACCHWO, 0xfc0007ff, 0x10000558, 0x0, // Multiply Accumulate Cross Halfword to Word Modulo Signed XO-form (macchwo RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {MACCHWO_, 0xfc0007ff, 0x10000559, 0x0, // Multiply Accumulate Cross Halfword to Word Modulo Signed XO-form (macchwo. RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {MACCHWS, 0xfc0007ff, 0x100001d8, 0x0, // Multiply Accumulate Cross Halfword to Word Saturate Signed XO-form (macchws RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {MACCHWS_, 0xfc0007ff, 0x100001d9, 0x0, // Multiply Accumulate Cross Halfword to Word Saturate Signed XO-form (macchws. RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {MACCHWSO, 0xfc0007ff, 0x100005d8, 0x0, // Multiply Accumulate Cross Halfword to Word Saturate Signed XO-form (macchwso RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {MACCHWSO_, 0xfc0007ff, 0x100005d9, 0x0, // Multiply Accumulate Cross Halfword to Word Saturate Signed XO-form (macchwso. RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {MACCHWU, 0xfc0007ff, 0x10000118, 0x0, // Multiply Accumulate Cross Halfword to Word Modulo Unsigned XO-form (macchwu RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {MACCHWU_, 0xfc0007ff, 0x10000119, 0x0, // Multiply Accumulate Cross Halfword to Word Modulo Unsigned XO-form (macchwu. RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {MACCHWUO, 0xfc0007ff, 0x10000518, 0x0, // Multiply Accumulate Cross Halfword to Word Modulo Unsigned XO-form (macchwuo RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {MACCHWUO_, 0xfc0007ff, 0x10000519, 0x0, // Multiply Accumulate Cross Halfword to Word Modulo Unsigned XO-form (macchwuo. RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {MACCHWSU, 0xfc0007ff, 0x10000198, 0x0, // Multiply Accumulate Cross Halfword to Word Saturate Unsigned XO-form (macchwsu RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {MACCHWSU_, 0xfc0007ff, 0x10000199, 0x0, // Multiply Accumulate Cross Halfword to Word Saturate Unsigned XO-form (macchwsu. RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {MACCHWSUO, 0xfc0007ff, 0x10000598, 0x0, // Multiply Accumulate Cross Halfword to Word Saturate Unsigned XO-form (macchwsuo RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {MACCHWSUO_, 0xfc0007ff, 0x10000599, 0x0, // Multiply Accumulate Cross Halfword to Word Saturate Unsigned XO-form (macchwsuo. RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {MACHHW, 0xfc0007ff, 0x10000058, 0x0, // Multiply Accumulate High Halfword to Word Modulo Signed XO-form (machhw RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {MACHHW_, 0xfc0007ff, 0x10000059, 0x0, // Multiply Accumulate High Halfword to Word Modulo Signed XO-form (machhw. RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {MACHHWO, 0xfc0007ff, 0x10000458, 0x0, // Multiply Accumulate High Halfword to Word Modulo Signed XO-form (machhwo RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {MACHHWO_, 0xfc0007ff, 0x10000459, 0x0, // Multiply Accumulate High Halfword to Word Modulo Signed XO-form (machhwo. RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {MACHHWS, 0xfc0007ff, 0x100000d8, 0x0, // Multiply Accumulate High Halfword to Word Saturate Signed XO-form (machhws RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {MACHHWS_, 0xfc0007ff, 0x100000d9, 0x0, // Multiply Accumulate High Halfword to Word Saturate Signed XO-form (machhws. RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {MACHHWSO, 0xfc0007ff, 0x100004d8, 0x0, // Multiply Accumulate High Halfword to Word Saturate Signed XO-form (machhwso RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {MACHHWSO_, 0xfc0007ff, 0x100004d9, 0x0, // Multiply Accumulate High Halfword to Word Saturate Signed XO-form (machhwso. RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {MACHHWU, 0xfc0007ff, 0x10000018, 0x0, // Multiply Accumulate High Halfword to Word Modulo Unsigned XO-form (machhwu RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {MACHHWU_, 0xfc0007ff, 0x10000019, 0x0, // Multiply Accumulate High Halfword to Word Modulo Unsigned XO-form (machhwu. RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {MACHHWUO, 0xfc0007ff, 0x10000418, 0x0, // Multiply Accumulate High Halfword to Word Modulo Unsigned XO-form (machhwuo RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {MACHHWUO_, 0xfc0007ff, 0x10000419, 0x0, // Multiply Accumulate High Halfword to Word Modulo Unsigned XO-form (machhwuo. RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {MACHHWSU, 0xfc0007ff, 0x10000098, 0x0, // Multiply Accumulate High Halfword to Word Saturate Unsigned XO-form (machhwsu RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {MACHHWSU_, 0xfc0007ff, 0x10000099, 0x0, // Multiply Accumulate High Halfword to Word Saturate Unsigned XO-form (machhwsu. RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {MACHHWSUO, 0xfc0007ff, 0x10000498, 0x0, // Multiply Accumulate High Halfword to Word Saturate Unsigned XO-form (machhwsuo RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {MACHHWSUO_, 0xfc0007ff, 0x10000499, 0x0, // Multiply Accumulate High Halfword to Word Saturate Unsigned XO-form (machhwsuo. RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {MACLHW, 0xfc0007ff, 0x10000358, 0x0, // Multiply Accumulate Low Halfword to Word Modulo Signed XO-form (maclhw RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {MACLHW_, 0xfc0007ff, 0x10000359, 0x0, // Multiply Accumulate Low Halfword to Word Modulo Signed XO-form (maclhw. RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {MACLHWO, 0xfc0007ff, 0x10000758, 0x0, // Multiply Accumulate Low Halfword to Word Modulo Signed XO-form (maclhwo RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {MACLHWO_, 0xfc0007ff, 0x10000759, 0x0, // Multiply Accumulate Low Halfword to Word Modulo Signed XO-form (maclhwo. RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {MACLHWS, 0xfc0007ff, 0x100003d8, 0x0, // Multiply Accumulate Low Halfword to Word Saturate Signed XO-form (maclhws RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {MACLHWS_, 0xfc0007ff, 0x100003d9, 0x0, // Multiply Accumulate Low Halfword to Word Saturate Signed XO-form (maclhws. RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {MACLHWSO, 0xfc0007ff, 0x100007d8, 0x0, // Multiply Accumulate Low Halfword to Word Saturate Signed XO-form (maclhwso RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {MACLHWSO_, 0xfc0007ff, 0x100007d9, 0x0, // Multiply Accumulate Low Halfword to Word Saturate Signed XO-form (maclhwso. RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {MACLHWU, 0xfc0007ff, 0x10000318, 0x0, // Multiply Accumulate Low Halfword to Word Modulo Unsigned XO-form (maclhwu RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {MACLHWU_, 0xfc0007ff, 0x10000319, 0x0, // Multiply Accumulate Low Halfword to Word Modulo Unsigned XO-form (maclhwu. RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {MACLHWUO, 0xfc0007ff, 0x10000718, 0x0, // Multiply Accumulate Low Halfword to Word Modulo Unsigned XO-form (maclhwuo RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {MACLHWUO_, 0xfc0007ff, 0x10000719, 0x0, // Multiply Accumulate Low Halfword to Word Modulo Unsigned XO-form (maclhwuo. RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {MULCHW, 0xfc0007ff, 0x10000150, 0x0, // Multiply Cross Halfword to Word Signed X-form (mulchw RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {MULCHW_, 0xfc0007ff, 0x10000151, 0x0, // Multiply Cross Halfword to Word Signed X-form (mulchw. RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {MACLHWSU, 0xfc0007ff, 0x10000398, 0x0, // Multiply Accumulate Low Halfword to Word Saturate Unsigned XO-form (maclhwsu RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {MACLHWSU_, 0xfc0007ff, 0x10000399, 0x0, // Multiply Accumulate Low Halfword to Word Saturate Unsigned XO-form (maclhwsu. RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {MACLHWSUO, 0xfc0007ff, 0x10000798, 0x0, // Multiply Accumulate Low Halfword to Word Saturate Unsigned XO-form (maclhwsuo RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {MACLHWSUO_, 0xfc0007ff, 0x10000799, 0x0, // Multiply Accumulate Low Halfword to Word Saturate Unsigned XO-form (maclhwsuo. RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {MULCHWU, 0xfc0007ff, 0x10000110, 0x0, // Multiply Cross Halfword to Word Unsigned X-form (mulchwu RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {MULCHWU_, 0xfc0007ff, 0x10000111, 0x0, // Multiply Cross Halfword to Word Unsigned X-form (mulchwu. RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {MULHHW, 0xfc0007ff, 0x10000050, 0x0, // Multiply High Halfword to Word Signed X-form (mulhhw RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {MULHHW_, 0xfc0007ff, 0x10000051, 0x0, // Multiply High Halfword to Word Signed X-form (mulhhw. RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {MULLHW, 0xfc0007ff, 0x10000350, 0x0, // Multiply Low Halfword to Word Signed X-form (mullhw RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {MULLHW_, 0xfc0007ff, 0x10000351, 0x0, // Multiply Low Halfword to Word Signed X-form (mullhw. RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {MULHHWU, 0xfc0007ff, 0x10000010, 0x0, // Multiply High Halfword to Word Unsigned X-form (mulhhwu RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {MULHHWU_, 0xfc0007ff, 0x10000011, 0x0, // Multiply High Halfword to Word Unsigned X-form (mulhhwu. RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {MULLHWU, 0xfc0007ff, 0x10000310, 0x0, // Multiply Low Halfword to Word Unsigned X-form (mullhwu RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {MULLHWU_, 0xfc0007ff, 0x10000311, 0x0, // Multiply Low Halfword to Word Unsigned X-form (mullhwu. RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {NMACCHW, 0xfc0007ff, 0x1000015c, 0x0, // Negative Multiply Accumulate Cross Halfword to Word Modulo Signed XO-form (nmacchw RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {NMACCHW_, 0xfc0007ff, 0x1000015d, 0x0, // Negative Multiply Accumulate Cross Halfword to Word Modulo Signed XO-form (nmacchw. RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {NMACCHWO, 0xfc0007ff, 0x1000055c, 0x0, // Negative Multiply Accumulate Cross Halfword to Word Modulo Signed XO-form (nmacchwo RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {NMACCHWO_, 0xfc0007ff, 0x1000055d, 0x0, // Negative Multiply Accumulate Cross Halfword to Word Modulo Signed XO-form (nmacchwo. RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {NMACCHWS, 0xfc0007ff, 0x100001dc, 0x0, // Negative Multiply Accumulate Cross Halfword to Word Saturate Signed XO-form (nmacchws RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {NMACCHWS_, 0xfc0007ff, 0x100001dd, 0x0, // Negative Multiply Accumulate Cross Halfword to Word Saturate Signed XO-form (nmacchws. RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {NMACCHWSO, 0xfc0007ff, 0x100005dc, 0x0, // Negative Multiply Accumulate Cross Halfword to Word Saturate Signed XO-form (nmacchwso RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {NMACCHWSO_, 0xfc0007ff, 0x100005dd, 0x0, // Negative Multiply Accumulate Cross Halfword to Word Saturate Signed XO-form (nmacchwso. RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {NMACHHW, 0xfc0007ff, 0x1000005c, 0x0, // Negative Multiply Accumulate High Halfword to Word Modulo Signed XO-form (nmachhw RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {NMACHHW_, 0xfc0007ff, 0x1000005d, 0x0, // Negative Multiply Accumulate High Halfword to Word Modulo Signed XO-form (nmachhw. RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {NMACHHWO, 0xfc0007ff, 0x1000045c, 0x0, // Negative Multiply Accumulate High Halfword to Word Modulo Signed XO-form (nmachhwo RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {NMACHHWO_, 0xfc0007ff, 0x1000045d, 0x0, // Negative Multiply Accumulate High Halfword to Word Modulo Signed XO-form (nmachhwo. RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {NMACHHWS, 0xfc0007ff, 0x100000dc, 0x0, // Negative Multiply Accumulate High Halfword to Word Saturate Signed XO-form (nmachhws RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {NMACHHWS_, 0xfc0007ff, 0x100000dd, 0x0, // Negative Multiply Accumulate High Halfword to Word Saturate Signed XO-form (nmachhws. RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {NMACHHWSO, 0xfc0007ff, 0x100004dc, 0x0, // Negative Multiply Accumulate High Halfword to Word Saturate Signed XO-form (nmachhwso RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {NMACHHWSO_, 0xfc0007ff, 0x100004dd, 0x0, // Negative Multiply Accumulate High Halfword to Word Saturate Signed XO-form (nmachhwso. RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {NMACLHW, 0xfc0007ff, 0x1000035c, 0x0, // Negative Multiply Accumulate Low Halfword to Word Modulo Signed XO-form (nmaclhw RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {NMACLHW_, 0xfc0007ff, 0x1000035d, 0x0, // Negative Multiply Accumulate Low Halfword to Word Modulo Signed XO-form (nmaclhw. RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {NMACLHWO, 0xfc0007ff, 0x1000075c, 0x0, // Negative Multiply Accumulate Low Halfword to Word Modulo Signed XO-form (nmaclhwo RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {NMACLHWO_, 0xfc0007ff, 0x1000075d, 0x0, // Negative Multiply Accumulate Low Halfword to Word Modulo Signed XO-form (nmaclhwo. RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {NMACLHWS, 0xfc0007ff, 0x100003dc, 0x0, // Negative Multiply Accumulate Low Halfword to Word Saturate Signed XO-form (nmaclhws RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {NMACLHWS_, 0xfc0007ff, 0x100003dd, 0x0, // Negative Multiply Accumulate Low Halfword to Word Saturate Signed XO-form (nmaclhws. RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {NMACLHWSO, 0xfc0007ff, 0x100007dc, 0x0, // Negative Multiply Accumulate Low Halfword to Word Saturate Signed XO-form (nmaclhwso RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {NMACLHWSO_, 0xfc0007ff, 0x100007dd, 0x0, // Negative Multiply Accumulate Low Halfword to Word Saturate Signed XO-form (nmaclhwso. RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {ICBI, 0xfc0007fe, 0x7c0007ac, 0x3e00001, // Instruction Cache Block Invalidate X-form (icbi RA,RB)
+ [5]*argField{ap_Reg_11_15, ap_Reg_16_20}},
+ {ICBT, 0xfc0007fe, 0x7c00002c, 0x2000001, // Instruction Cache Block Touch X-form (icbt CT, RA, RB)
+ [5]*argField{ap_ImmUnsigned_7_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {DCBA, 0xfc0007fe, 0x7c0005ec, 0x3e00001, // Data Cache Block Allocate X-form (dcba RA,RB)
+ [5]*argField{ap_Reg_11_15, ap_Reg_16_20}},
+ {DCBT, 0xfc0007fe, 0x7c00022c, 0x1, // Data Cache Block Touch X-form (dcbt RA,RB,TH)
+ [5]*argField{ap_Reg_11_15, ap_Reg_16_20, ap_ImmUnsigned_6_10}},
+ {DCBT, 0xfc0007fe, 0x7c00022c, 0x1, // Data Cache Block Touch X-form (dcbt TH,RA,RB)
+ [5]*argField{ap_ImmUnsigned_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {DCBTST, 0xfc0007fe, 0x7c0001ec, 0x1, // Data Cache Block Touch for Store X-form (dcbtst RA,RB,TH)
+ [5]*argField{ap_Reg_11_15, ap_Reg_16_20, ap_ImmUnsigned_6_10}},
+ {DCBTST, 0xfc0007fe, 0x7c0001ec, 0x1, // Data Cache Block Touch for Store X-form (dcbtst TH,RA,RB)
+ [5]*argField{ap_ImmUnsigned_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {DCBZ, 0xfc0007fe, 0x7c0007ec, 0x3e00001, // Data Cache Block set to Zero X-form (dcbz RA,RB)
+ [5]*argField{ap_Reg_11_15, ap_Reg_16_20}},
+ {DCBST, 0xfc0007fe, 0x7c00006c, 0x3e00001, // Data Cache Block Store X-form (dcbst RA,RB)
+ [5]*argField{ap_Reg_11_15, ap_Reg_16_20}},
+ {DCBF, 0xfc0007fe, 0x7c0000ac, 0x3800001, // Data Cache Block Flush X-form (dcbf RA,RB,L)
+ [5]*argField{ap_Reg_11_15, ap_Reg_16_20, ap_ImmUnsigned_9_10}},
+ {ISYNC, 0xfc0007fe, 0x4c00012c, 0x3fff801, // Instruction Synchronize XL-form (isync)
+ [5]*argField{}},
+ {LBARX, 0xfc0007ff, 0x7c000068, 0x0, // Load Byte And Reserve Indexed X-form [Category: Phased-In] (lbarx RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {LBARX, 0xfc0007fe, 0x7c000068, 0x0, // Load Byte And Reserve Indexed X-form [Category: Phased-In] (lbarx RT,RA,RB,EH)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20, ap_ImmUnsigned_31_31}},
+ {LHARX, 0xfc0007ff, 0x7c0000e8, 0x0, // Load Halfword And Reserve Indexed X-form [Category: Phased-In] (lharx RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {LHARX, 0xfc0007fe, 0x7c0000e8, 0x0, // Load Halfword And Reserve Indexed X-form [Category: Phased-In] (lharx RT,RA,RB,EH)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20, ap_ImmUnsigned_31_31}},
+ {LWARX, 0xfc0007ff, 0x7c000028, 0x0, // Load Word And Reserve Indexed X-form (lwarx RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {LWARX, 0xfc0007ff, 0x7c000028, 0x0, // Load Word And Reserve Indexed X-form (lwarx RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {LWARX, 0xfc0007fe, 0x7c000028, 0x0, // Load Word And Reserve Indexed X-form (lwarx RT,RA,RB,EH)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20, ap_ImmUnsigned_31_31}},
+ {STBCX_, 0xfc0007ff, 0x7c00056d, 0x0, // Store Byte Conditional Indexed X-form [Category: Phased-In] (stbcx. RS,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {STHCX_, 0xfc0007ff, 0x7c0005ad, 0x0, // Store Halfword Conditional Indexed X-form [Category: Phased-In] (sthcx. RS,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {STWCX_, 0xfc0007ff, 0x7c00012d, 0x0, // Store Word Conditional Indexed X-form (stwcx. RS,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {LDARX, 0xfc0007ff, 0x7c0000a8, 0x0, // Load Doubleword And Reserve Indexed X-form (ldarx RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {LDARX, 0xfc0007fe, 0x7c0000a8, 0x0, // Load Doubleword And Reserve Indexed X-form (ldarx RT,RA,RB,EH)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20, ap_ImmUnsigned_31_31}},
+ {STDCX_, 0xfc0007ff, 0x7c0001ad, 0x0, // Store Doubleword Conditional Indexed X-form (stdcx. RS,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {LQARX, 0xfc0007ff, 0x7c000228, 0x0, // Load Quadword And Reserve Indexed X-form (lqarx RTp,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {LQARX, 0xfc0007fe, 0x7c000228, 0x0, // Load Quadword And Reserve Indexed X-form (lqarx RTp,RA,RB,EH)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20, ap_ImmUnsigned_31_31}},
+ {STQCX_, 0xfc0007ff, 0x7c00016d, 0x0, // Store Quadword Conditional Indexed X-form (stqcx. RSp,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {SYNC, 0xfc0007fe, 0x7c0004ac, 0x390f801, // Synchronize X-form (sync L, E)
+ [5]*argField{ap_ImmUnsigned_9_10, ap_ImmUnsigned_12_15}},
+ {EIEIO, 0xfc0007fe, 0x7c0006ac, 0x3fff801, // Enforce In-order Execution of I/O X-form (eieio)
+ [5]*argField{}},
+ {MBAR, 0xfc0007fe, 0x7c0006ac, 0x1ff801, // Memory Barrier X-form (mbar MO)
+ [5]*argField{ap_ImmUnsigned_6_10}},
+ {WAIT, 0xfc0007fe, 0x7c00007c, 0x39ff801, // Wait X-form (wait WC)
+ [5]*argField{ap_ImmUnsigned_9_10}},
+ {TBEGIN_, 0xfc0007ff, 0x7c00051d, 0x1dff800, // Transaction Begin X-form (tbegin. R)
+ [5]*argField{ap_ImmUnsigned_10_10}},
+ {TEND_, 0xfc0007ff, 0x7c00055d, 0x1fff800, // Transaction End X-form (tend. A)
+ [5]*argField{ap_ImmUnsigned_6_6}},
+ {TABORT_, 0xfc0007ff, 0x7c00071d, 0x3e0f800, // Transaction Abort X-form (tabort. RA)
+ [5]*argField{ap_Reg_11_15}},
+ {TABORTWC_, 0xfc0007ff, 0x7c00061d, 0x0, // Transaction Abort Word Conditional X-form (tabortwc. TO,RA,RB)
+ [5]*argField{ap_ImmUnsigned_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {TABORTWCI_, 0xfc0007ff, 0x7c00069d, 0x0, // Transaction Abort Word Conditional Immediate X-form (tabortwci. TO,RA,SI)
+ [5]*argField{ap_ImmUnsigned_6_10, ap_Reg_11_15, ap_ImmSigned_16_20}},
+ {TABORTDC_, 0xfc0007ff, 0x7c00065d, 0x0, // Transaction Abort Doubleword Conditional X-form (tabortdc. TO,RA,RB)
+ [5]*argField{ap_ImmUnsigned_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {TABORTDCI_, 0xfc0007ff, 0x7c0006dd, 0x0, // Transaction Abort Doubleword Conditional Immediate X-form (tabortdci. TO,RA, SI)
+ [5]*argField{ap_ImmUnsigned_6_10, ap_Reg_11_15, ap_ImmSigned_16_20}},
+ {TSR_, 0xfc0007ff, 0x7c0005dd, 0x3dff800, // Transaction Suspend or Resume X-form (tsr. L)
+ [5]*argField{ap_ImmUnsigned_10_10}},
+ {TCHECK, 0xfc0007fe, 0x7c00059c, 0x7ff801, // Transaction Check X-form (tcheck BF)
+ [5]*argField{ap_CondRegField_6_8}},
+ {MFTB, 0xfc0007fe, 0x7c0002e6, 0x1, // Move From Time Base XFX-form (mftb RT,TBR)
+ [5]*argField{ap_Reg_6_10, ap_SpReg_16_20_11_15}},
+ {RFEBB, 0xfc0007fe, 0x4c000124, 0x3fff001, // Return from Event-Based Branch XL-form (rfebb S)
+ [5]*argField{ap_ImmUnsigned_20_20}},
+ {LBDX, 0xfc0007fe, 0x7c000406, 0x1, // Load Byte with Decoration Indexed X-form (lbdx RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {LHDX, 0xfc0007fe, 0x7c000446, 0x1, // Load Halfword with Decoration Indexed X-form (lhdx RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {LWDX, 0xfc0007fe, 0x7c000486, 0x1, // Load Word with Decoration Indexed X-form (lwdx RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {LDDX, 0xfc0007fe, 0x7c0004c6, 0x1, // Load Doubleword with Decoration Indexed X-form (lddx RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {LFDDX, 0xfc0007fe, 0x7c000646, 0x1, // Load Floating Doubleword with Decoration Indexed X-form (lfddx FRT,RA,RB)
+ [5]*argField{ap_FPReg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {STBDX, 0xfc0007fe, 0x7c000506, 0x1, // Store Byte with Decoration Indexed X-form (stbdx RS,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {STHDX, 0xfc0007fe, 0x7c000546, 0x1, // Store Halfword with Decoration Indexed X-form (sthdx RS,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {STWDX, 0xfc0007fe, 0x7c000586, 0x1, // Store Word with Decoration Indexed X-form (stwdx RS,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {STDDX, 0xfc0007fe, 0x7c0005c6, 0x1, // Store Doubleword with Decoration Indexed X-form (stddx RS,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {STFDDX, 0xfc0007fe, 0x7c000746, 0x1, // Store Floating Doubleword with Decoration Indexed X-form (stfddx FRS,RA,RB)
+ [5]*argField{ap_FPReg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {DSN, 0xfc0007fe, 0x7c0003c6, 0x3e00001, // Decorated Storage Notify X-form (dsn RA,RB)
+ [5]*argField{ap_Reg_11_15, ap_Reg_16_20}},
+ {ECIWX, 0xfc0007fe, 0x7c00026c, 0x1, // External Control In Word Indexed X-form (eciwx RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {ECOWX, 0xfc0007fe, 0x7c00036c, 0x1, // External Control Out Word Indexed X-form (ecowx RS,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {SC, 0xfc000002, 0x44000002, 0x3fff01d, // System Call SC-form (sc LEV)
+ [5]*argField{ap_ImmUnsigned_20_26}},
+ {RFID, 0xfc0007fe, 0x4c000024, 0x3fff801, // Return From Interrupt Doubleword XL-form (rfid)
+ [5]*argField{}},
+ {HRFID, 0xfc0007fe, 0x4c000224, 0x3fff801, // Hypervisor Return From Interrupt Doubleword XL-form (hrfid)
+ [5]*argField{}},
+ {DOZE, 0xfc0007fe, 0x4c000324, 0x3fff801, // Doze XL-form (doze)
+ [5]*argField{}},
+ {NAP, 0xfc0007fe, 0x4c000364, 0x3fff801, // Nap XL-form (nap)
+ [5]*argField{}},
+ {SLEEP, 0xfc0007fe, 0x4c0003a4, 0x3fff801, // Sleep XL-form (sleep)
+ [5]*argField{}},
+ {RVWINKLE, 0xfc0007fe, 0x4c0003e4, 0x3fff801, // Rip Van Winkle XL-form (rvwinkle)
+ [5]*argField{}},
+ {LBZCIX, 0xfc0007fe, 0x7c0006aa, 0x1, // Load Byte and Zero Caching Inhibited Indexed X-form (lbzcix RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {LWZCIX, 0xfc0007fe, 0x7c00062a, 0x1, // Load Word and Zero Caching Inhibited Indexed X-form (lwzcix RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {LHZCIX, 0xfc0007fe, 0x7c00066a, 0x1, // Load Halfword and Zero Caching Inhibited Indexed X-form (lhzcix RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {LDCIX, 0xfc0007fe, 0x7c0006ea, 0x1, // Load Doubleword Caching Inhibited Indexed X-form (ldcix RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {STBCIX, 0xfc0007fe, 0x7c0007aa, 0x1, // Store Byte Caching Inhibited Indexed X-form (stbcix RS,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {STWCIX, 0xfc0007fe, 0x7c00072a, 0x1, // Store Word Caching Inhibited Indexed X-form (stwcix RS,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {STHCIX, 0xfc0007fe, 0x7c00076a, 0x1, // Store Halfword Caching Inhibited Indexed X-form (sthcix RS,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {STDCIX, 0xfc0007fe, 0x7c0007ea, 0x1, // Store Doubleword Caching Inhibited Indexed X-form (stdcix RS,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {TRECLAIM_, 0xfc0007ff, 0x7c00075d, 0x3e0f800, // Transaction Reclaim X-form (treclaim. RA)
+ [5]*argField{ap_Reg_11_15}},
+ {TRECHKPT_, 0xfc0007ff, 0x7c0007dd, 0x3fff800, // Transaction Recheckpoint X-form (trechkpt.)
+ [5]*argField{}},
+ {MTSPR, 0xfc0007fe, 0x7c0003a6, 0x1, // Move To Special Purpose Register XFX-form (mtspr SPR,RS)
+ [5]*argField{ap_SpReg_16_20_11_15, ap_Reg_6_10}},
+ {MFSPR, 0xfc0007fe, 0x7c0002a6, 0x1, // Move From Special Purpose Register XFX-form (mfspr RT,SPR)
+ [5]*argField{ap_Reg_6_10, ap_SpReg_16_20_11_15}},
+ {MTMSR, 0xfc0007fe, 0x7c000124, 0x1ef801, // Move To Machine State Register X-form (mtmsr RS,L)
+ [5]*argField{ap_Reg_6_10, ap_ImmUnsigned_15_15}},
+ {MTMSRD, 0xfc0007fe, 0x7c000164, 0x1ef801, // Move To Machine State Register Doubleword X-form (mtmsrd RS,L)
+ [5]*argField{ap_Reg_6_10, ap_ImmUnsigned_15_15}},
+ {MFMSR, 0xfc0007fe, 0x7c0000a6, 0x1ff801, // Move From Machine State Register X-form (mfmsr RT)
+ [5]*argField{ap_Reg_6_10}},
+ {SLBIE, 0xfc0007fe, 0x7c000364, 0x3ff0001, // SLB Invalidate Entry X-form (slbie RB)
+ [5]*argField{ap_Reg_16_20}},
+ {SLBIA, 0xfc0007fe, 0x7c0003e4, 0x31ff801, // SLB Invalidate All X-form (slbia IH)
+ [5]*argField{ap_ImmUnsigned_8_10}},
+ {SLBMTE, 0xfc0007fe, 0x7c000324, 0x1f0001, // SLB Move To Entry X-form (slbmte RS,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_16_20}},
+ {SLBMFEV, 0xfc0007fe, 0x7c0006a6, 0x1f0001, // SLB Move From Entry VSID X-form (slbmfev RT,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_16_20}},
+ {SLBMFEE, 0xfc0007fe, 0x7c000726, 0x1f0001, // SLB Move From Entry ESID X-form (slbmfee RT,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_16_20}},
+ {SLBFEE_, 0xfc0007ff, 0x7c0007a7, 0x1f0000, // SLB Find Entry ESID X-form (slbfee. RT,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_16_20}},
+ {MTSR, 0xfc0007fe, 0x7c0001a4, 0x10f801, // Move To Segment Register X-form (mtsr SR,RS)
+ [5]*argField{ap_SpReg_12_15, ap_Reg_6_10}},
+ {MTSRIN, 0xfc0007fe, 0x7c0001e4, 0x1f0001, // Move To Segment Register Indirect X-form (mtsrin RS,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_16_20}},
+ {MFSR, 0xfc0007fe, 0x7c0004a6, 0x10f801, // Move From Segment Register X-form (mfsr RT,SR)
+ [5]*argField{ap_Reg_6_10, ap_SpReg_12_15}},
+ {MFSRIN, 0xfc0007fe, 0x7c000526, 0x1f0001, // Move From Segment Register Indirect X-form (mfsrin RT,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_16_20}},
+ {TLBIE, 0xfc0007fe, 0x7c000264, 0x1f0001, // TLB Invalidate Entry X-form (tlbie RB,RS)
+ [5]*argField{ap_Reg_16_20, ap_Reg_6_10}},
+ {TLBIEL, 0xfc0007fe, 0x7c000224, 0x3ff0001, // TLB Invalidate Entry Local X-form (tlbiel RB)
+ [5]*argField{ap_Reg_16_20}},
+ {TLBIA, 0xfc0007fe, 0x7c0002e4, 0x3fff801, // TLB Invalidate All X-form (tlbia)
+ [5]*argField{}},
+ {TLBSYNC, 0xfc0007fe, 0x7c00046c, 0x3fff801, // TLB Synchronize X-form (tlbsync)
+ [5]*argField{}},
+ {MSGSND, 0xfc0007fe, 0x7c00019c, 0x3ff0001, // Message Send X-form (msgsnd RB)
+ [5]*argField{ap_Reg_16_20}},
+ {MSGCLR, 0xfc0007fe, 0x7c0001dc, 0x3ff0001, // Message Clear X-form (msgclr RB)
+ [5]*argField{ap_Reg_16_20}},
+ {MSGSNDP, 0xfc0007fe, 0x7c00011c, 0x3ff0001, // Message Send Privileged X-form (msgsndp RB)
+ [5]*argField{ap_Reg_16_20}},
+ {MSGCLRP, 0xfc0007fe, 0x7c00015c, 0x3ff0001, // Message Clear Privileged X-form (msgclrp RB)
+ [5]*argField{ap_Reg_16_20}},
+ {MTTMR, 0xfc0007fe, 0x7c0003dc, 0x1, // Move To Thread Management Register XFX-form (mttmr TMR,RS)
+ [5]*argField{ap_SpReg_16_20_11_15, ap_Reg_6_10}},
+ {SC, 0xfc000002, 0x44000002, 0x3fffffd, // System Call SC-form (sc)
+ [5]*argField{}},
+ {RFI, 0xfc0007fe, 0x4c000064, 0x3fff801, // Return From Interrupt XL-form (rfi)
+ [5]*argField{}},
+ {RFCI, 0xfc0007fe, 0x4c000066, 0x3fff801, // Return From Critical Interrupt XL-form (rfci)
+ [5]*argField{}},
+ {RFDI, 0xfc0007fe, 0x4c00004e, 0x3fff801, // Return From Debug Interrupt X-form (rfdi)
+ [5]*argField{}},
+ {RFMCI, 0xfc0007fe, 0x4c00004c, 0x3fff801, // Return From Machine Check Interrupt XL-form (rfmci)
+ [5]*argField{}},
+ {RFGI, 0xfc0007fe, 0x4c0000cc, 0x3fff801, // Return From Guest Interrupt XL-form (rfgi)
+ [5]*argField{}},
+ {EHPRIV, 0xfc0007fe, 0x7c00021c, 0x1, // Embedded Hypervisor Privilege XL-form (ehpriv OC)
+ [5]*argField{ap_ImmUnsigned_6_20}},
+ {MTSPR, 0xfc0007fe, 0x7c0003a6, 0x1, // Move To Special Purpose Register XFX-form (mtspr SPR,RS)
+ [5]*argField{ap_SpReg_16_20_11_15, ap_Reg_6_10}},
+ {MFSPR, 0xfc0007fe, 0x7c0002a6, 0x1, // Move From Special Purpose Register XFX-form (mfspr RT,SPR)
+ [5]*argField{ap_Reg_6_10, ap_SpReg_16_20_11_15}},
+ {MTDCR, 0xfc0007fe, 0x7c000386, 0x1, // Move To Device Control Register XFX-form (mtdcr DCRN,RS)
+ [5]*argField{ap_SpReg_16_20_11_15, ap_Reg_6_10}},
+ {MTDCRX, 0xfc0007fe, 0x7c000306, 0xf801, // Move To Device Control Register Indexed X-form (mtdcrx RA,RS)
+ [5]*argField{ap_Reg_11_15, ap_Reg_6_10}},
+ {MFDCR, 0xfc0007fe, 0x7c000286, 0x1, // Move From Device Control Register XFX-form (mfdcr RT,DCRN)
+ [5]*argField{ap_Reg_6_10, ap_SpReg_16_20_11_15}},
+ {MFDCRX, 0xfc0007fe, 0x7c000206, 0xf801, // Move From Device Control Register Indexed X-form (mfdcrx RT,RA)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15}},
+ {MTMSR, 0xfc0007fe, 0x7c000124, 0x1ff801, // Move To Machine State Register X-form (mtmsr RS)
+ [5]*argField{ap_Reg_6_10}},
+ {MFMSR, 0xfc0007fe, 0x7c0000a6, 0x1ff801, // Move From Machine State Register X-form (mfmsr RT)
+ [5]*argField{ap_Reg_6_10}},
+ {WRTEE, 0xfc0007fe, 0x7c000106, 0x1ff801, // Write MSR External Enable X-form (wrtee RS)
+ [5]*argField{ap_Reg_6_10}},
+ {WRTEEI, 0xfc0007fe, 0x7c000146, 0x3ff7801, // Write MSR External Enable Immediate X-form (wrteei E)
+ [5]*argField{ap_ImmUnsigned_16_16}},
+ {LBEPX, 0xfc0007fe, 0x7c0000be, 0x1, // Load Byte by External Process ID Indexed X-form (lbepx RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {LHEPX, 0xfc0007fe, 0x7c00023e, 0x1, // Load Halfword by External Process ID Indexed X-form (lhepx RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {LWEPX, 0xfc0007fe, 0x7c00003e, 0x1, // Load Word by External Process ID Indexed X-form (lwepx RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {LDEPX, 0xfc0007fe, 0x7c00003a, 0x1, // Load Doubleword by External Process ID Indexed X-form (ldepx RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {STBEPX, 0xfc0007fe, 0x7c0001be, 0x1, // Store Byte by External Process ID Indexed X-form (stbepx RS,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {STHEPX, 0xfc0007fe, 0x7c00033e, 0x1, // Store Halfword by External Process ID Indexed X-form (sthepx RS,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {STWEPX, 0xfc0007fe, 0x7c00013e, 0x1, // Store Word by External Process ID Indexed X-form (stwepx RS,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {STDEPX, 0xfc0007fe, 0x7c00013a, 0x1, // Store Doubleword by External Process ID Indexed X-form (stdepx RS,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {DCBSTEP, 0xfc0007fe, 0x7c00007e, 0x3e00001, // Data Cache Block Store by External PID X-form (dcbstep RA,RB)
+ [5]*argField{ap_Reg_11_15, ap_Reg_16_20}},
+ {DCBTEP, 0xfc0007fe, 0x7c00027e, 0x1, // Data Cache Block Touch by External PID X-form (dcbtep TH,RA,RB)
+ [5]*argField{ap_ImmUnsigned_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {DCBFEP, 0xfc0007fe, 0x7c0000fe, 0x3800001, // Data Cache Block Flush by External PID X-form (dcbfep RA,RB,L)
+ [5]*argField{ap_Reg_11_15, ap_Reg_16_20, ap_ImmUnsigned_9_10}},
+ {DCBTSTEP, 0xfc0007fe, 0x7c0001fe, 0x1, // Data Cache Block Touch for Store by External PID X-form (dcbtstep TH,RA,RB)
+ [5]*argField{ap_ImmUnsigned_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {ICBIEP, 0xfc0007fe, 0x7c0007be, 0x3e00001, // Instruction Cache Block Invalidate by External PID X-form (icbiep RA,RB)
+ [5]*argField{ap_Reg_11_15, ap_Reg_16_20}},
+ {DCBZEP, 0xfc0007fe, 0x7c0007fe, 0x3e00001, // Data Cache Block set to Zero by External PID X-form (dcbzep RA,RB)
+ [5]*argField{ap_Reg_11_15, ap_Reg_16_20}},
+ {LFDEPX, 0xfc0007fe, 0x7c0004be, 0x1, // Load Floating-Point Double by External Process ID Indexed X-form (lfdepx FRT,RA,RB)
+ [5]*argField{ap_FPReg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {STFDEPX, 0xfc0007fe, 0x7c0005be, 0x1, // Store Floating-Point Double by External Process ID Indexed X-form (stfdepx FRS,RA,RB)
+ [5]*argField{ap_FPReg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVLDDEPX, 0xfc0007fe, 0x7c00063e, 0x1, // Vector Load Doubleword into Doubleword by External Process ID Indexed EVX-form (evlddepx RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {EVSTDDEPX, 0xfc0007fe, 0x7c00073e, 0x1, // Vector Store Doubleword into Doubleword by External Process ID Indexed EVX-form (evstddepx RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {LVEPX, 0xfc0007fe, 0x7c00024e, 0x1, // Load Vector by External Process ID Indexed X-form (lvepx VRT,RA,RB)
+ [5]*argField{ap_VecReg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {LVEPXL, 0xfc0007fe, 0x7c00020e, 0x1, // Load Vector by External Process ID Indexed LRU X-form (lvepxl VRT,RA,RB)
+ [5]*argField{ap_VecReg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {STVEPX, 0xfc0007fe, 0x7c00064e, 0x1, // Store Vector by External Process ID Indexed X-form (stvepx VRS,RA,RB)
+ [5]*argField{ap_VecReg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {STVEPXL, 0xfc0007fe, 0x7c00060e, 0x1, // Store Vector by External Process ID Indexed LRU X-form (stvepxl VRS,RA,RB)
+ [5]*argField{ap_VecReg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {DCBI, 0xfc0007fe, 0x7c0003ac, 0x3e00001, // Data Cache Block Invalidate X-form (dcbi RA,RB)
+ [5]*argField{ap_Reg_11_15, ap_Reg_16_20}},
+ {DCBLQ_, 0xfc0007ff, 0x7c00034d, 0x2000000, // Data Cache Block Lock Query X-form (dcblq. CT,RA,RB)
+ [5]*argField{ap_ImmUnsigned_7_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {ICBLQ_, 0xfc0007ff, 0x7c00018d, 0x2000000, // Instruction Cache Block Lock Query X-form (icblq. CT,RA,RB)
+ [5]*argField{ap_ImmUnsigned_7_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {DCBTLS, 0xfc0007fe, 0x7c00014c, 0x2000001, // Data Cache Block Touch and Lock Set X-form (dcbtls CT,RA,RB)
+ [5]*argField{ap_ImmUnsigned_7_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {DCBTSTLS, 0xfc0007fe, 0x7c00010c, 0x2000001, // Data Cache Block Touch for Store and Lock Set X-form (dcbtstls CT,RA,RB)
+ [5]*argField{ap_ImmUnsigned_7_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {ICBTLS, 0xfc0007fe, 0x7c0003cc, 0x2000001, // Instruction Cache Block Touch and Lock Set X-form (icbtls CT,RA,RB)
+ [5]*argField{ap_ImmUnsigned_7_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {ICBLC, 0xfc0007fe, 0x7c0001cc, 0x2000001, // Instruction Cache Block Lock Clear X-form (icblc CT,RA,RB)
+ [5]*argField{ap_ImmUnsigned_7_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {DCBLC, 0xfc0007fe, 0x7c00030c, 0x2000001, // Data Cache Block Lock Clear X-form (dcblc CT,RA,RB)
+ [5]*argField{ap_ImmUnsigned_7_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {TLBIVAX, 0xfc0007fe, 0x7c000624, 0x3e00001, // TLB Invalidate Virtual Address Indexed X-form (tlbivax RA,RB)
+ [5]*argField{ap_Reg_11_15, ap_Reg_16_20}},
+ {TLBILX, 0xfc0007fe, 0x7c000024, 0x3800001, // TLB Invalidate Local Indexed X-form (tlbilx RA,RB])
+ [5]*argField{ap_Reg_11_15, ap_Reg_16_20}},
+ {TLBSX, 0xfc0007fe, 0x7c000724, 0x3e00001, // TLB Search Indexed X-form (tlbsx RA,RB)
+ [5]*argField{ap_Reg_11_15, ap_Reg_16_20}},
+ {TLBSRX_, 0xfc0007ff, 0x7c0006a5, 0x3e00000, // TLB Search and Reserve Indexed X-form (tlbsrx. RA,RB)
+ [5]*argField{ap_Reg_11_15, ap_Reg_16_20}},
+ {TLBRE, 0xfc0007fe, 0x7c000764, 0x3fff801, // TLB Read Entry X-form (tlbre)
+ [5]*argField{}},
+ {TLBSYNC, 0xfc0007fe, 0x7c00046c, 0x3fff801, // TLB Synchronize X-form (tlbsync)
+ [5]*argField{}},
+ {TLBWE, 0xfc0007fe, 0x7c0007a4, 0x3fff801, // TLB Write Entry X-form (tlbwe)
+ [5]*argField{}},
+ {DNH, 0xfc0007fe, 0x4c00018c, 0x1, // Debugger Notify Halt XFX-form (dnh DUI,DUIS)
+ [5]*argField{ap_ImmUnsigned_6_10, ap_ImmUnsigned_11_20}},
+ {MSGSND, 0xfc0007fe, 0x7c00019c, 0x3ff0001, // Message Send X-form (msgsnd RB)
+ [5]*argField{ap_Reg_16_20}},
+ {MSGCLR, 0xfc0007fe, 0x7c0001dc, 0x3ff0001, // Message Clear X-form (msgclr RB)
+ [5]*argField{ap_Reg_16_20}},
+ {DCI, 0xfc0007fe, 0x7c00038c, 0x21ff801, // Data Cache Invalidate X-form (dci CT)
+ [5]*argField{ap_ImmUnsigned_7_10}},
+ {ICI, 0xfc0007fe, 0x7c00078c, 0x21ff801, // Instruction Cache Invalidate X-form (ici CT)
+ [5]*argField{ap_ImmUnsigned_7_10}},
+ {DCREAD, 0xfc0007fe, 0x7c0003cc, 0x1, // Data Cache Read X-form (dcread RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {ICREAD, 0xfc0007fe, 0x7c0007cc, 0x3e00001, // Instruction Cache Read X-form (icread RA,RB)
+ [5]*argField{ap_Reg_11_15, ap_Reg_16_20}},
+ {MFPMR, 0xfc0007fe, 0x7c00029c, 0x1, // Move From Performance Monitor Register XFX-form (mfpmr RT,PMRN)
+ [5]*argField{ap_Reg_6_10, ap_SpReg_11_20}},
+ {MTPMR, 0xfc0007fe, 0x7c00039c, 0x1, // Move To Performance Monitor Register XFX-form (mtpmr PMRN,RS)
+ [5]*argField{ap_SpReg_11_20, ap_Reg_6_10}},
+}
diff --git a/src/cmd/vendor/golang.org/x/arch/ppc64/ppc64asm/testdata/decode.txt b/src/cmd/vendor/golang.org/x/arch/ppc64/ppc64asm/testdata/decode.txt
new file mode 100644
index 0000000..b4e5db2
--- /dev/null
+++ b/src/cmd/vendor/golang.org/x/arch/ppc64/ppc64asm/testdata/decode.txt
@@ -0,0 +1,25 @@
+6d746162| gnu xoris r20,r11,24930
+4c040000| gnu mcrf cr0,cr1
+88000017| gnu lbz r0,23(0)
+4abaa88a| gnu ba 0xfebaa888
+7d8fc2a6| gnu mfspr r12,783
+00000000| gnu error: unknown instruction
+a1841e80| gnu lhz r12,7808(r4)
+42093d10| gnu bc 16,4*cr2+gt,.+0x3d10
+e38d5b90| gnu lq r28,23440(r13)
+84127a20| gnu lwzu r0,31264(r18)
+c61bb730| gnu lfsu f16,-18640(r27)
+0825f440| gnu tdi 1,r5,-3008
+a9a912c1| gnu lha r13,4801(r9)
+ebb24fd1| gnu ldu r29,20432(r18)
+b1ce0612| gnu sth r14,1554(r14)
+f3c04322| gnu xvcvdpuxws vs30,vs40
+945c62a2| gnu stwu r2,25250(r28)
+9c8156e3| gnu stbu r4,22243(r1)
+f91b9c7a| gnu stq r8,-25480(r27)
+2c1c81b4| gnu cmpwi r28,-32332
+f87b904d| gnu stdu r3,-28596(r27)
+eab3c832| gnu lwa r21,-14288(r19)
+4320336b| gnu bcla 25,lt,0x3368
+7e40092e| gnu stwx r18,0,r1
+7c103c2c| gnu lwbrx r0,r16,r7
diff --git a/src/cmd/vendor/vendor.json b/src/cmd/vendor/vendor.json
index 565498f..8fc8897 100644
--- a/src/cmd/vendor/vendor.json
+++ b/src/cmd/vendor/vendor.json
@@ -11,6 +11,12 @@
"local": "golang.org/x/arch/arm/armasm",
"revision": "ad6a463afcf9bd5b38c81fa9ba612dae11859d40",
"revisionTime": "2015-08-28T15:42:14Z"
+ },
+ {
+ "canonical": "golang.org/x/arch/ppc64/ppc64asm",
+ "local": "golang.org/x/arch/ppc64/ppc64asm",
+ "revision": "4831b0a617f7a819d4bf3c877d8e827d0283542c",
+ "revisionTime": "2016-10-12T18:28:04Z"
}
]
}
diff --git a/src/cmd/vet/all/main.go b/src/cmd/vet/all/main.go
new file mode 100644
index 0000000..f4ee8fe
--- /dev/null
+++ b/src/cmd/vet/all/main.go
@@ -0,0 +1,332 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build ignore
+
+// The vet/all command runs go vet on the standard library and commands.
+// It compares the output against a set of whitelists
+// maintained in the whitelist directory.
+package main
+
+import (
+ "bufio"
+ "bytes"
+ "flag"
+ "fmt"
+ "go/build"
+ "internal/testenv"
+ "log"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "runtime"
+ "strconv"
+ "strings"
+ "sync"
+)
+
+var (
+ flagPlatforms = flag.String("p", "", "platform(s) to use e.g. linux/amd64,darwin/386")
+ flagAll = flag.Bool("all", false, "run all platforms")
+ flagNoLines = flag.Bool("n", false, "don't print line numbers")
+)
+
+var cmdGoPath string
+
+func main() {
+ log.SetPrefix("vet/all: ")
+ log.SetFlags(0)
+
+ var err error
+ cmdGoPath, err = testenv.GoTool()
+ if err != nil {
+ log.Print("could not find cmd/go; skipping")
+ // We're on a platform that can't run cmd/go.
+ // We want this script to be able to run as part of all.bash,
+ // so return cleanly rather than with exit code 1.
+ return
+ }
+
+ flag.Parse()
+ switch {
+ case *flagAll && *flagPlatforms != "":
+ log.Print("-all and -p flags are incompatible")
+ flag.Usage()
+ os.Exit(2)
+ case *flagPlatforms != "":
+ vetPlatforms(parseFlagPlatforms())
+ case *flagAll:
+ vetPlatforms(allPlatforms())
+ default:
+ host := platform{os: build.Default.GOOS, arch: build.Default.GOARCH}
+ host.vet(runtime.GOMAXPROCS(-1))
+ }
+}
+
+func allPlatforms() []platform {
+ var pp []platform
+ cmd := exec.Command(cmdGoPath, "tool", "dist", "list")
+ out, err := cmd.Output()
+ if err != nil {
+ log.Fatal(err)
+ }
+ lines := bytes.Split(out, []byte{'\n'})
+ for _, line := range lines {
+ if len(line) == 0 {
+ continue
+ }
+ pp = append(pp, parsePlatform(string(line)))
+ }
+ return pp
+}
+
+func parseFlagPlatforms() []platform {
+ var pp []platform
+ components := strings.Split(*flagPlatforms, ",")
+ for _, c := range components {
+ pp = append(pp, parsePlatform(c))
+ }
+ return pp
+}
+
+func parsePlatform(s string) platform {
+ vv := strings.Split(s, "/")
+ if len(vv) != 2 {
+ log.Fatalf("could not parse platform %s, must be of form goos/goarch", s)
+ }
+ return platform{os: vv[0], arch: vv[1]}
+}
+
+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)
+ }
+
+ // Look up whether goarch has a shared arch suffix,
+ // such as mips64x for mips64 and mips64le.
+ archsuff := goarch
+ if x, ok := archAsmX[goarch]; ok {
+ archsuff = x
+ }
+
+ // Load whitelists.
+ filenames := []string{
+ "all.txt",
+ goos + ".txt",
+ goarch + ".txt",
+ goos + "_" + goarch + ".txt",
+ fmt.Sprintf("%dbit.txt", archbits),
+ }
+ if goarch != archsuff {
+ filenames = append(filenames,
+ archsuff+".txt",
+ goos+"_"+archsuff+".txt",
+ )
+ }
+
+ // We allow error message templates using GOOS and GOARCH.
+ if goos == "android" {
+ goos = "linux" // so many special cases :(
+ }
+
+ // Read whitelists and do template substitution.
+ replace := strings.NewReplacer("GOOS", goos, "GOARCH", goarch, "ARCHSUFF", archsuff)
+
+ for _, filename := range filenames {
+ path := filepath.Join("whitelist", filename)
+ f, err := os.Open(path)
+ if err != nil {
+ // Allow not-exist errors; not all combinations have whitelists.
+ if os.IsNotExist(err) {
+ continue
+ }
+ log.Fatal(err)
+ }
+ scan := bufio.NewScanner(f)
+ for scan.Scan() {
+ line := scan.Text()
+ if len(line) == 0 || strings.HasPrefix(line, "//") {
+ continue
+ }
+ w[replace.Replace(line)]++
+ }
+ if err := scan.Err(); err != nil {
+ log.Fatal(err)
+ }
+ }
+}
+
+type platform struct {
+ os string
+ arch string
+}
+
+func (p platform) String() string {
+ return p.os + "/" + p.arch
+}
+
+// ignorePathPrefixes are file path prefixes that should be ignored wholesale.
+var ignorePathPrefixes = [...]string{
+ // These testdata dirs have lots of intentionally broken/bad code for tests.
+ "cmd/go/testdata/",
+ "cmd/vet/testdata/",
+ "go/printer/testdata/",
+}
+
+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()
+ }()
+ }
+ wg.Wait()
+}
+
+func (p platform) vet(ncpus int) {
+ var buf bytes.Buffer
+ fmt.Fprintf(&buf, "go run main.go -p %s\n", p)
+
+ // Load whitelist(s).
+ 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.Dir = filepath.Join(runtime.GOROOT(), "src")
+ cmd.Env = env
+ stderr, err := cmd.StderrPipe()
+ if err != nil {
+ log.Fatal(err)
+ }
+ if err := cmd.Start(); err != nil {
+ log.Fatal(err)
+ }
+
+ // Process vet output.
+ scan := bufio.NewScanner(stderr)
+NextLine:
+ for scan.Scan() {
+ line := scan.Text()
+ if strings.HasPrefix(line, "vet: ") {
+ // Typecheck failure: Malformed syntax or multiple packages or the like.
+ // This will yield nicer error messages elsewhere, so ignore them here.
+ continue
+ }
+
+ fields := strings.SplitN(line, ":", 3)
+ var file, lineno, msg string
+ switch len(fields) {
+ case 2:
+ // vet message with no line number
+ file, msg = fields[0], fields[1]
+ case 3:
+ file, lineno, msg = fields[0], fields[1], fields[2]
+ default:
+ log.Fatalf("could not parse vet output line:\n%s", line)
+ }
+ msg = strings.TrimSpace(msg)
+
+ for _, ignore := range ignorePathPrefixes {
+ if strings.HasPrefix(file, filepath.FromSlash(ignore)) {
+ continue NextLine
+ }
+ }
+
+ key := file + ": " + msg
+ if w[key] == 0 {
+ // Vet error with no match in the whitelist. Print it.
+ if *flagNoLines {
+ fmt.Fprintf(&buf, "%s: %s\n", file, msg)
+ } else {
+ fmt.Fprintf(&buf, "%s:%s: %s\n", file, lineno, msg)
+ }
+ continue
+ }
+ w[key]--
+ }
+ if scan.Err() != nil {
+ log.Fatalf("failed to scan vet output: %v", scan.Err())
+ }
+ err = cmd.Wait()
+ // We expect vet to fail.
+ // Make sure it has failed appropriately, though (for example, not a PathError).
+ if _, ok := err.(*exec.ExitError); !ok {
+ log.Fatalf("unexpected go vet execution failure: %v", err)
+ }
+ printedHeader := false
+ if len(w) > 0 {
+ for k, v := range w {
+ if v != 0 {
+ if !printedHeader {
+ fmt.Fprintln(&buf, "unmatched whitelist entries:")
+ printedHeader = true
+ }
+ for i := 0; i < v; i++ {
+ fmt.Fprintln(&buf, k)
+ }
+ }
+ }
+ }
+
+ 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",
+ "ppc64": "ppc64x",
+ "ppc64le": "ppc64x",
+}
diff --git a/src/cmd/vet/all/whitelist/386.txt b/src/cmd/vet/all/whitelist/386.txt
new file mode 100644
index 0000000..33b63e1
--- /dev/null
+++ b/src/cmd/vet/all/whitelist/386.txt
@@ -0,0 +1,29 @@
+// 386-specific vet whitelist. See readme.txt for details.
+
+runtime/asm_ARCHSUFF.s: [GOARCH] cannot check cross-package assembly function: Compare is in package bytes
+
+// reflect trampolines intentionally omit arg size. Same for morestack.
+reflect/asm_386.s: [386] makeFuncStub: use of 4(SP) points beyond argument frame
+reflect/asm_386.s: [386] methodValueCall: use of 4(SP) points beyond argument frame
+runtime/asm_386.s: [386] morestack: use of 4(SP) points beyond argument frame
+runtime/asm_386.s: [386] morestack: use of 8(SP) points beyond argument frame
+runtime/asm_386.s: [386] morestack: use of 4(SP) points beyond argument frame
+
+// Intentionally missing declarations. These are special assembly routines.
+runtime/asm_386.s: [386] ldt0setup: function ldt0setup missing Go declaration
+runtime/asm_386.s: [386] emptyfunc: function emptyfunc missing Go declaration
+runtime/asm_386.s: [386] aeshashbody: function aeshashbody missing Go declaration
+runtime/asm_386.s: [386] memeqbody: function memeqbody missing Go declaration
+runtime/asm_386.s: [386] cmpbody: function cmpbody missing Go declaration
+runtime/asm_386.s: [386] addmoduledata: function addmoduledata missing Go declaration
+runtime/duff_386.s: [386] duffzero: function duffzero missing Go declaration
+runtime/duff_386.s: [386] duffcopy: function duffcopy missing Go declaration
+
+runtime/asm_386.s: [386] uint32tofloat64: function uint32tofloat64 missing Go declaration
+runtime/asm_386.s: [386] float64touint32: function float64touint32 missing Go declaration
+
+runtime/asm_386.s: [386] stackcheck: function stackcheck missing Go declaration
+
+// Clearer using FP than SP, but that requires named offsets.
+runtime/asm_386.s: [386] rt0_go: unknown variable argc
+runtime/asm_386.s: [386] rt0_go: unknown variable argv
diff --git a/src/cmd/vet/all/whitelist/64bit.txt b/src/cmd/vet/all/whitelist/64bit.txt
new file mode 100644
index 0000000..35b9eb3
--- /dev/null
+++ b/src/cmd/vet/all/whitelist/64bit.txt
@@ -0,0 +1,13 @@
+// 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
new file mode 100644
index 0000000..7250de1
--- /dev/null
+++ b/src/cmd/vet/all/whitelist/all.txt
@@ -0,0 +1,92 @@
+// Non-platform-specific vet whitelist. See readme.txt for details.
+
+// Issue 17580 (remove when fixed)
+cmd/go/go_test.go: +build comment must appear before package clause and be followed by a blank line
+
+
+// Real problems that we can't fix.
+
+// This is a bad WriteTo signature. Errors are being ignored!
+// However, we can't change it due to the Go 1 compatibility promise.
+go/types/scope.go: method WriteTo(w io.Writer, n int, recurse bool) should have signature WriteTo(io.Writer) (int64, error)
+
+
+// False positives.
+
+// 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
+runtime/testdata/testprog/deadlock.go: unreachable code
+runtime/testdata/testprog/deadlock.go: unreachable code
+sync/cond_test.go: assignment copies lock value to c2: sync.Cond contains sync.noCopy
+
+// Non-standard method signatures.
+// These cases are basically ok.
+// Errors are handled reasonably and there's no clear need for interface satisfaction.
+// 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)
+
+// These encoding/xml methods have the correct signature.
+// vet doesn't know it because they are *in* the encoding/xml package.
+// It's not worth teaching vet about the distinction, so whitelist them.
+encoding/gob/encode.go: method WriteByte(c byte) should have signature WriteByte(byte) error
+encoding/xml/marshal.go: method MarshalXML(e *Encoder, start StartElement) error should have signature MarshalXML(*xml.Encoder, xml.StartElement) error
+encoding/xml/marshal_test.go: method MarshalXML(e *Encoder, start StartElement) error should have signature MarshalXML(*xml.Encoder, xml.StartElement) error
+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 [...]
+cmd/link/link_test.go: struct field tag "\n\tJarndyce and Jarndyce drones on. This scarecrow of a suit has, over the course of time, become so complicated, that no man alive knows what it means. The parties to it understand it least; but it has been observed that no two Chancery lawyers can talk about it for five minutes, without coming to a total disagreement as to all the premises. Innumerable children have been born into the cause; innumerable young people have married into it; innume [...]
+cmd/link/link_test.go: struct field tag "\n\tThe one great principle of the English law is, to make business for itself. There is no other principle distinctly, certainly, and consistently maintained through all its narrow turnings. Viewed by this light it becomes a coherent scheme, and not the monstrous maze the laity are apt to think it. Let them but once clearly perceive that its grand principle is to make business for itself at their expense, and surely they will cease to grumble." n [...]
diff --git a/src/cmd/vet/all/whitelist/amd64.txt b/src/cmd/vet/all/whitelist/amd64.txt
new file mode 100644
index 0000000..df4ec84
--- /dev/null
+++ b/src/cmd/vet/all/whitelist/amd64.txt
@@ -0,0 +1,35 @@
+// amd64-specific vet whitelist. See readme.txt for details.
+
+
+// False positives.
+
+
+// reflect trampolines intentionally omit arg size. Same for morestack.
+reflect/asm_amd64.s: [amd64] makeFuncStub: use of 8(SP) points beyond argument frame
+reflect/asm_amd64.s: [amd64] methodValueCall: use of 8(SP) points beyond argument frame
+runtime/asm_amd64.s: [amd64] morestack: use of 8(SP) points beyond argument frame
+runtime/asm_amd64.s: [amd64] morestack: use of 16(SP) points beyond argument frame
+runtime/asm_amd64.s: [amd64] morestack: use of 8(SP) points beyond argument frame
+
+// Nothing much to do about cross-package assembly. Unfortunate.
+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
+
+// Intentionally missing declarations. These are special assembly routines.
+// Some are jumped into from other routines, with values in specific registers.
+// duff* have direct calls from the compiler.
+// Others use the platform ABI.
+// There is no sensible corresponding Go prototype.
+runtime/asm_amd64.s: [amd64] aeshashbody: function aeshashbody missing Go declaration
+runtime/asm_amd64.s: [amd64] memeqbody: function memeqbody missing Go declaration
+runtime/asm_amd64.s: [amd64] cmpbody: function cmpbody missing Go declaration
+runtime/asm_amd64.s: [amd64] indexbytebody: function indexbytebody missing Go declaration
+runtime/asm_amd64.s: [amd64] addmoduledata: function addmoduledata missing Go declaration
+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
+
diff --git a/src/cmd/vet/all/whitelist/android_386.txt b/src/cmd/vet/all/whitelist/android_386.txt
new file mode 100644
index 0000000..5095f2f
--- /dev/null
+++ b/src/cmd/vet/all/whitelist/android_386.txt
@@ -0,0 +1,8 @@
+// android/386-specific vet whitelist. See readme.txt for details.
+
+runtime/sys_linux_386.s: [386] setldt: function setldt missing Go declaration
+
+// These SP references occur after a stack-altering call. They're fine.
+runtime/sys_linux_386.s: [386] clone: 12(SP) should be mp+8(FP)
+runtime/sys_linux_386.s: [386] clone: 4(SP) should be flags+0(FP)
+runtime/sys_linux_386.s: [386] clone: 8(SP) should be stk+4(FP)
diff --git a/src/cmd/vet/all/whitelist/android_amd64.txt b/src/cmd/vet/all/whitelist/android_amd64.txt
new file mode 100644
index 0000000..90dabb0
--- /dev/null
+++ b/src/cmd/vet/all/whitelist/android_amd64.txt
@@ -0,0 +1,3 @@
+// android/amd64-specific vet whitelist. See readme.txt for details.
+
+runtime/sys_linux_amd64.s: [amd64] settls: function settls missing Go declaration
diff --git a/src/cmd/vet/all/whitelist/android_arm.txt b/src/cmd/vet/all/whitelist/android_arm.txt
new file mode 100644
index 0000000..fbd569e
--- /dev/null
+++ b/src/cmd/vet/all/whitelist/android_arm.txt
@@ -0,0 +1,5 @@
+// android/arm-specific vet whitelist. See readme.txt for details.
+
+runtime/sys_linux_arm.s: [arm] clone: 12(R13) should be stk+4(FP)
+runtime/sys_linux_arm.s: [arm] clone: 8(R13) should be flags+0(FP)
+runtime/sys_linux_arm.s: [arm] read_tls_fallback: function read_tls_fallback missing Go declaration
diff --git a/src/cmd/vet/all/whitelist/arm.txt b/src/cmd/vet/all/whitelist/arm.txt
new file mode 100644
index 0000000..c0ab9de
--- /dev/null
+++ b/src/cmd/vet/all/whitelist/arm.txt
@@ -0,0 +1,26 @@
+// arm-specific vet whitelist. See readme.txt for details.
+
+runtime/asm_ARCHSUFF.s: [GOARCH] cannot check cross-package assembly function: Compare is in package bytes
+
+// reflect trampolines intentionally omit arg size. Same for morestack.
+reflect/asm_arm.s: [arm] makeFuncStub: use of 8(R13) points beyond argument frame
+reflect/asm_arm.s: [arm] methodValueCall: use of 8(R13) points beyond argument frame
+runtime/asm_arm.s: [arm] morestack: use of 4(R13) points beyond argument frame
+
+// Intentionally missing declarations.
+runtime/asm_arm.s: [arm] emptyfunc: function emptyfunc missing Go declaration
+runtime/asm_arm.s: [arm] abort: function abort missing Go declaration
+runtime/asm_arm.s: [arm] armPublicationBarrier: function armPublicationBarrier missing Go declaration
+runtime/asm_arm.s: [arm] cmpbody: function cmpbody missing Go declaration
+runtime/asm_arm.s: [arm] usplitR0: function usplitR0 missing Go declaration
+runtime/asm_arm.s: [arm] addmoduledata: function addmoduledata missing Go declaration
+runtime/duff_arm.s: [arm] duffzero: function duffzero missing Go declaration
+runtime/duff_arm.s: [arm] duffcopy: function duffcopy missing Go declaration
+runtime/tls_arm.s: [arm] save_g: function save_g missing Go declaration
+runtime/tls_arm.s: [arm] load_g: function load_g missing Go declaration
+runtime/tls_arm.s: [arm] _initcgo: function _initcgo missing Go declaration
+
+// Clearer using FP than SP, but that requires named offsets.
+runtime/asm_arm.s: [arm] rt0_go: use of 4(R13) points beyond argument frame
+
+runtime/internal/atomic/asm_arm.s: [arm] cas: function cas missing Go declaration
diff --git a/src/cmd/vet/all/whitelist/arm64.txt b/src/cmd/vet/all/whitelist/arm64.txt
new file mode 100644
index 0000000..8a3c891
--- /dev/null
+++ b/src/cmd/vet/all/whitelist/arm64.txt
@@ -0,0 +1,17 @@
+// arm64-specific vet whitelist. See readme.txt for details.
+
+runtime/asm_ARCHSUFF.s: [GOARCH] cannot check cross-package assembly function: Compare is in package bytes
+
+// False positives.
+
+// reflect trampolines intentionally omit arg size. Same for morestack.
+reflect/asm_arm64.s: [arm64] makeFuncStub: use of 16(RSP) points beyond argument frame
+reflect/asm_arm64.s: [arm64] methodValueCall: use of 16(RSP) points beyond argument frame
+
+// Intentionally missing declarations.
+runtime/asm_arm64.s: [arm64] abort: function abort missing Go declaration
+runtime/asm_arm64.s: [arm64] addmoduledata: function addmoduledata missing Go declaration
+runtime/duff_arm64.s: [arm64] duffzero: function duffzero missing Go declaration
+runtime/duff_arm64.s: [arm64] duffcopy: function duffcopy missing Go declaration
+runtime/tls_arm64.s: [arm64] load_g: function load_g missing Go declaration
+runtime/tls_arm64.s: [arm64] save_g: function save_g missing Go declaration
diff --git a/src/cmd/vet/all/whitelist/darwin_386.txt b/src/cmd/vet/all/whitelist/darwin_386.txt
new file mode 100644
index 0000000..c5c51d0
--- /dev/null
+++ b/src/cmd/vet/all/whitelist/darwin_386.txt
@@ -0,0 +1,8 @@
+// darwin/386-specific vet whitelist. See readme.txt for details.
+
+// Ok
+
+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
diff --git a/src/cmd/vet/all/whitelist/darwin_amd64.txt b/src/cmd/vet/all/whitelist/darwin_amd64.txt
new file mode 100644
index 0000000..277abd7
--- /dev/null
+++ b/src/cmd/vet/all/whitelist/darwin_amd64.txt
@@ -0,0 +1,4 @@
+// darwin/amd64-specific vet whitelist. See readme.txt for details.
+
+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
diff --git a/src/cmd/vet/all/whitelist/darwin_arm.txt b/src/cmd/vet/all/whitelist/darwin_arm.txt
new file mode 100644
index 0000000..0e619be
--- /dev/null
+++ b/src/cmd/vet/all/whitelist/darwin_arm.txt
@@ -0,0 +1,12 @@
+// darwin/arm-specific vet whitelist. See readme.txt for details.
+
+// False positives due to comments in assembly.
+// To be removed. See CL 27154.
+
+runtime/sys_darwin_arm.s: [arm] sigfwd: use of unnamed argument 0(FP); offset 0 is fn+0(FP)
+
+
+// Ok.
+
+runtime/sys_darwin_arm.s: [arm] bsdthread_start: function bsdthread_start missing Go declaration
+runtime/asm_arm.s: [arm] sigreturn: function sigreturn missing Go declaration
diff --git a/src/cmd/vet/all/whitelist/darwin_arm64.txt b/src/cmd/vet/all/whitelist/darwin_arm64.txt
new file mode 100644
index 0000000..080a4ca
--- /dev/null
+++ b/src/cmd/vet/all/whitelist/darwin_arm64.txt
@@ -0,0 +1,14 @@
+// darwin/arm64-specific vet whitelist. See readme.txt for details.
+
+runtime/sys_darwin_arm64.s: [arm64] sigtramp: 24(RSP) should be infostyle+8(FP)
+runtime/sys_darwin_arm64.s: [arm64] sigtramp: 24(RSP) should be infostyle+8(FP)
+runtime/sys_darwin_arm64.s: [arm64] bsdthread_create: RET without writing to 4-byte ret+24(FP)
+runtime/sys_darwin_arm64.s: [arm64] bsdthread_start: function bsdthread_start missing Go declaration
+runtime/sys_darwin_arm64.s: [arm64] bsdthread_register: RET without writing to 4-byte ret+0(FP)
+runtime/cgo/signal_darwin_arm64.s: [arm64] panicmem: use of 8(RSP) points beyond argument frame
+runtime/cgo/signal_darwin_arm64.s: [arm64] panicmem: use of 8(RSP) points beyond argument frame
+runtime/cgo/signal_darwin_arm64.s: [arm64] panicmem: use of 16(RSP) points beyond argument frame
+runtime/cgo/signal_darwin_arm64.s: [arm64] panicmem: use of 8(RSP) points beyond argument frame
+runtime/cgo/signal_darwin_arm64.s: [arm64] panicmem: use of 16(RSP) points beyond argument frame
+runtime/cgo/signal_darwin_arm64.s: [arm64] panicmem: use of 16(RSP) points beyond argument frame
+runtime/asm_arm64.s: [arm64] sigreturn: function sigreturn missing Go declaration
diff --git a/src/cmd/vet/all/whitelist/dragonfly_amd64.txt b/src/cmd/vet/all/whitelist/dragonfly_amd64.txt
new file mode 100644
index 0000000..6c44159
--- /dev/null
+++ b/src/cmd/vet/all/whitelist/dragonfly_amd64.txt
@@ -0,0 +1,7 @@
+// dragonfly/amd64-specific vet whitelist. See readme.txt for details.
+
+runtime/sys_dragonfly_amd64.s: [amd64] settls: function settls missing Go declaration
+
+syscall/asm9_unix2_amd64.s: [amd64] Syscall9: 8(SP) should be num+0(FP)
+syscall/asm9_unix2_amd64.s: [amd64] Syscall9: 16(SP) should be a1+8(FP)
+syscall/asm9_unix2_amd64.s: [amd64] Syscall9: 24(SP) should be a2+16(FP)
diff --git a/src/cmd/vet/all/whitelist/freebsd_386.txt b/src/cmd/vet/all/whitelist/freebsd_386.txt
new file mode 100644
index 0000000..d37132c
--- /dev/null
+++ b/src/cmd/vet/all/whitelist/freebsd_386.txt
@@ -0,0 +1,19 @@
+// freebsd/386-specific vet whitelist. See readme.txt for details.
+
+runtime/sys_freebsd_386.s: [386] thr_start: unknown variable mm
+runtime/sys_freebsd_386.s: [386] sigtramp: unknown variable signo
+runtime/sys_freebsd_386.s: [386] sigtramp: unknown variable info
+runtime/sys_freebsd_386.s: [386] sigtramp: unknown variable context
+runtime/sys_freebsd_386.s: [386] sigtramp: unknown variable context
+runtime/sys_freebsd_386.s: [386] setldt: function setldt missing Go declaration
+runtime/sys_freebsd_386.s: [386] i386_set_ldt: function i386_set_ldt missing Go declaration
+syscall/asm_unix_386.s: [386] Syscall: 8(SP) should be a1+4(FP)
+syscall/asm_unix_386.s: [386] Syscall: 4(SP) should be trap+0(FP)
+syscall/asm_unix_386.s: [386] Syscall6: 8(SP) should be a1+4(FP)
+syscall/asm_unix_386.s: [386] Syscall6: 4(SP) should be trap+0(FP)
+syscall/asm_unix_386.s: [386] Syscall9: 8(SP) should be a1+4(FP)
+syscall/asm_unix_386.s: [386] Syscall9: 4(SP) should be num+0(FP)
+syscall/asm_unix_386.s: [386] RawSyscall: 8(SP) should be a1+4(FP)
+syscall/asm_unix_386.s: [386] RawSyscall: 4(SP) should be trap+0(FP)
+syscall/asm_unix_386.s: [386] RawSyscall6: 8(SP) should be a1+4(FP)
+syscall/asm_unix_386.s: [386] RawSyscall6: 4(SP) should be trap+0(FP)
diff --git a/src/cmd/vet/all/whitelist/freebsd_amd64.txt b/src/cmd/vet/all/whitelist/freebsd_amd64.txt
new file mode 100644
index 0000000..a910f48
--- /dev/null
+++ b/src/cmd/vet/all/whitelist/freebsd_amd64.txt
@@ -0,0 +1,6 @@
+// freebsd/amd64-specific vet whitelist. See readme.txt for details.
+
+runtime/sys_freebsd_amd64.s: [amd64] settls: function settls missing Go declaration
+syscall/asm9_unix2_amd64.s: [amd64] Syscall9: 8(SP) should be num+0(FP)
+syscall/asm9_unix2_amd64.s: [amd64] Syscall9: 16(SP) should be a1+8(FP)
+syscall/asm9_unix2_amd64.s: [amd64] Syscall9: 24(SP) should be a2+16(FP)
diff --git a/src/cmd/vet/all/whitelist/freebsd_arm.txt b/src/cmd/vet/all/whitelist/freebsd_arm.txt
new file mode 100644
index 0000000..11e5c42
--- /dev/null
+++ b/src/cmd/vet/all/whitelist/freebsd_arm.txt
@@ -0,0 +1,4 @@
+// freebsd/arm-specific vet whitelist. See readme.txt for details.
+
+runtime/asm_arm.s: [arm] sigreturn: function sigreturn missing Go declaration
+runtime/sys_freebsd_arm.s: [arm] read_tls_fallback: function read_tls_fallback missing Go declaration
diff --git a/src/cmd/vet/all/whitelist/linux_386.txt b/src/cmd/vet/all/whitelist/linux_386.txt
new file mode 100644
index 0000000..a5111ca
--- /dev/null
+++ b/src/cmd/vet/all/whitelist/linux_386.txt
@@ -0,0 +1,13 @@
+// linux/386-specific vet whitelist. See readme.txt for details.
+
+runtime/sys_linux_386.s: [386] setldt: function setldt missing Go declaration
+
+// These SP references occur after a stack-altering call. They're fine.
+runtime/sys_linux_386.s: [386] clone: 12(SP) should be mp+8(FP)
+runtime/sys_linux_386.s: [386] clone: 4(SP) should be flags+0(FP)
+runtime/sys_linux_386.s: [386] clone: 8(SP) should be stk+4(FP)
+
+// Android-specific; stubs missing on other linux platforms.
+runtime/sys_linux_386.s: [386] access: function access missing Go declaration
+runtime/sys_linux_386.s: [386] connect: function connect missing Go declaration
+runtime/sys_linux_386.s: [386] socket: function socket missing Go declaration
diff --git a/src/cmd/vet/all/whitelist/linux_amd64.txt b/src/cmd/vet/all/whitelist/linux_amd64.txt
new file mode 100644
index 0000000..69ba65d
--- /dev/null
+++ b/src/cmd/vet/all/whitelist/linux_amd64.txt
@@ -0,0 +1,8 @@
+// linux/amd64-specific vet whitelist. See readme.txt for details.
+
+runtime/sys_linux_amd64.s: [amd64] settls: function settls missing Go declaration
+
+// Android-specific; stubs missing on other linux platforms.
+runtime/sys_linux_amd64.s: [amd64] access: function access missing Go declaration
+runtime/sys_linux_amd64.s: [amd64] connect: function connect missing Go declaration
+runtime/sys_linux_amd64.s: [amd64] socket: function socket missing Go declaration
diff --git a/src/cmd/vet/all/whitelist/linux_arm.txt b/src/cmd/vet/all/whitelist/linux_arm.txt
new file mode 100644
index 0000000..fbf0e27
--- /dev/null
+++ b/src/cmd/vet/all/whitelist/linux_arm.txt
@@ -0,0 +1,12 @@
+// linux/arm-specific vet whitelist. See readme.txt for details.
+
+
+// These SP references occur after a stack-altering call. They're fine.
+runtime/sys_linux_arm.s: [arm] clone: 12(R13) should be stk+4(FP)
+runtime/sys_linux_arm.s: [arm] clone: 8(R13) should be flags+0(FP)
+
+// Special functions.
+runtime/sys_linux_arm.s: [arm] read_tls_fallback: function read_tls_fallback missing Go declaration
+runtime/sys_linux_arm.s: [arm] access: function access missing Go declaration
+runtime/sys_linux_arm.s: [arm] connect: function connect missing Go declaration
+runtime/sys_linux_arm.s: [arm] socket: function socket missing Go declaration
diff --git a/src/cmd/vet/all/whitelist/linux_arm64.txt b/src/cmd/vet/all/whitelist/linux_arm64.txt
new file mode 100644
index 0000000..67280b7
--- /dev/null
+++ b/src/cmd/vet/all/whitelist/linux_arm64.txt
@@ -0,0 +1,5 @@
+// linux/arm64-specific vet whitelist. See readme.txt for details.
+
+runtime/sys_linux_arm64.s: [arm64] access: function access missing Go declaration
+runtime/sys_linux_arm64.s: [arm64] connect: function connect missing Go declaration
+runtime/sys_linux_arm64.s: [arm64] socket: function socket missing Go declaration
diff --git a/src/cmd/vet/all/whitelist/linux_ppc64x.txt b/src/cmd/vet/all/whitelist/linux_ppc64x.txt
new file mode 100644
index 0000000..21e87e3
--- /dev/null
+++ b/src/cmd/vet/all/whitelist/linux_ppc64x.txt
@@ -0,0 +1,5 @@
+// linux/ppc64-specific vet whitelist. See readme.txt for details.
+
+runtime/sys_linux_ppc64x.s: [GOARCH] _sigtramp: function _sigtramp missing Go declaration
+runtime/sys_linux_ppc64x.s: [GOARCH] _cgoSigtramp: function _cgoSigtramp missing Go declaration
+runtime/asm_ppc64x.s: [GOARCH] procyield: use of 24(R1) points beyond argument frame
diff --git a/src/cmd/vet/all/whitelist/mips64x.txt b/src/cmd/vet/all/whitelist/mips64x.txt
new file mode 100644
index 0000000..b29cf3e
--- /dev/null
+++ b/src/cmd/vet/all/whitelist/mips64x.txt
@@ -0,0 +1,8 @@
+// mips64-specific vet whitelist. See readme.txt for details.
+
+reflect/asm_mips64x.s: [GOARCH] makeFuncStub: use of 16(R29) points beyond argument frame
+reflect/asm_mips64x.s: [GOARCH] methodValueCall: use of 16(R29) points beyond argument frame
+runtime/asm_mips64x.s: [GOARCH] abort: function abort missing Go declaration
+runtime/duff_mips64x.s: [GOARCH] duffzero: function duffzero missing Go declaration
+runtime/tls_mips64x.s: [GOARCH] save_g: function save_g missing Go declaration
+runtime/tls_mips64x.s: [GOARCH] load_g: function load_g missing Go declaration
diff --git a/src/cmd/vet/all/whitelist/nacl_386.txt b/src/cmd/vet/all/whitelist/nacl_386.txt
new file mode 100644
index 0000000..68bba51
--- /dev/null
+++ b/src/cmd/vet/all/whitelist/nacl_386.txt
@@ -0,0 +1,13 @@
+// nacl/386-specific vet whitelist. See readme.txt for details.
+
+runtime/sys_nacl_386.s: [386] cannot check cross-package assembly function: naclWrite is in package syscall
+runtime/sys_nacl_386.s: [386] cannot check cross-package assembly function: now is in package syscall
+runtime/sys_nacl_386.s: [386] nacl_clock_gettime: function nacl_clock_gettime missing Go declaration
+runtime/sys_nacl_386.s: [386] setldt: function setldt missing Go declaration
+runtime/sys_nacl_386.s: [386] sigtramp: use of 20(SP) points beyond argument frame
+runtime/sys_nacl_386.s: [386] sigtramp: use of 4(SP) points beyond argument frame
+runtime/sys_nacl_386.s: [386] sigtramp: unknown variable ctxt
+runtime/sys_nacl_386.s: [386] sigtramp: use of 8(SP) points beyond argument frame
+runtime/sys_nacl_386.s: [386] sigtramp: use of 12(SP) points beyond argument frame
+runtime/sys_nacl_386.s: [386] sigtramp: use of 20(SP) points beyond argument frame
+runtime/sys_nacl_386.s: [386] sigtramp: unknown variable ctxt
diff --git a/src/cmd/vet/all/whitelist/nacl_amd64p32.txt b/src/cmd/vet/all/whitelist/nacl_amd64p32.txt
new file mode 100644
index 0000000..83bcfe9
--- /dev/null
+++ b/src/cmd/vet/all/whitelist/nacl_amd64p32.txt
@@ -0,0 +1,31 @@
+// nacl/amd64p32-specific vet whitelist. See readme.txt for details.
+
+// reflect trampolines intentionally omit arg size. Same for morestack.
+reflect/asm_amd64p32.s: [amd64p32] makeFuncStub: use of 4(SP) points beyond argument frame
+reflect/asm_amd64p32.s: [amd64p32] methodValueCall: use of 4(SP) points beyond argument frame
+runtime/asm_amd64p32.s: [amd64p32] morestack: use of 8(SP) points beyond argument frame
+runtime/asm_amd64p32.s: [amd64p32] morestack: use of 16(SP) points beyond argument frame
+runtime/asm_amd64p32.s: [amd64p32] morestack: use of 8(SP) points beyond argument frame
+
+runtime/sys_nacl_amd64p32.s: [amd64p32] sigtramp: unknown variable ctxt
+runtime/sys_nacl_amd64p32.s: [amd64p32] sigtramp: unknown variable ctxt
+runtime/sys_nacl_amd64p32.s: [amd64p32] sigtramp: unknown variable ctxt
+runtime/sys_nacl_amd64p32.s: [amd64p32] sigtramp: unknown variable ctxt
+runtime/sys_nacl_amd64p32.s: [amd64p32] sigtramp: unknown variable ctxt
+runtime/sys_nacl_amd64p32.s: [amd64p32] nacl_sysinfo: function nacl_sysinfo missing Go declaration
+runtime/sys_nacl_amd64p32.s: [amd64p32] cannot check cross-package assembly function: naclWrite is in package syscall
+runtime/sys_nacl_amd64p32.s: [amd64p32] cannot check cross-package assembly function: now is in package syscall
+runtime/sys_nacl_amd64p32.s: [amd64p32] nacl_clock_gettime: function nacl_clock_gettime missing Go declaration
+runtime/sys_nacl_amd64p32.s: [amd64p32] settls: function settls missing Go declaration
+
+// Clearer using FP than SP, but that requires named offsets.
+runtime/asm_amd64p32.s: [amd64p32] rt0_go: unknown variable argc
+runtime/asm_amd64p32.s: [amd64p32] rt0_go: unknown variable argv
+
+runtime/asm_amd64p32.s: [amd64p32] memeqbody: function memeqbody missing Go declaration
+runtime/asm_amd64p32.s: [amd64p32] cannot check cross-package assembly function: Compare is in package bytes
+runtime/asm_amd64p32.s: [amd64p32] cmpbody: function cmpbody missing Go declaration
+runtime/asm_amd64p32.s: [amd64p32] indexbytebody: function indexbytebody missing Go declaration
+runtime/asm_amd64p32.s: [amd64p32] asmcgocall: RET without writing to 4-byte ret+8(FP)
+
+runtime/asm_amd64p32.s: [amd64p32] stackcheck: function stackcheck missing Go declaration
diff --git a/src/cmd/vet/all/whitelist/nacl_arm.txt b/src/cmd/vet/all/whitelist/nacl_arm.txt
new file mode 100644
index 0000000..cc0fcba
--- /dev/null
+++ b/src/cmd/vet/all/whitelist/nacl_arm.txt
@@ -0,0 +1,8 @@
+// nacl/arm-specific vet whitelist. See readme.txt for details.
+
+runtime/asm_arm.s: [arm] sigreturn: function sigreturn missing Go declaration
+runtime/sys_nacl_arm.s: [arm] cannot check cross-package assembly function: naclWrite is in package syscall
+runtime/sys_nacl_arm.s: [arm] cannot check cross-package assembly function: now is in package syscall
+runtime/sys_nacl_arm.s: [arm] nacl_clock_gettime: function nacl_clock_gettime missing Go declaration
+runtime/sys_nacl_arm.s: [arm] nacl_sysinfo: function nacl_sysinfo missing Go declaration
+runtime/sys_nacl_arm.s: [arm] read_tls_fallback: function read_tls_fallback missing Go declaration
diff --git a/src/cmd/vet/all/whitelist/netbsd.txt b/src/cmd/vet/all/whitelist/netbsd.txt
new file mode 100644
index 0000000..48bfde5
--- /dev/null
+++ b/src/cmd/vet/all/whitelist/netbsd.txt
@@ -0,0 +1,3 @@
+// netbsd-specific vet whitelist. See readme.txt for details.
+
+runtime/sys_netbsd_ARCHSUFF.s: [GOARCH] sigreturn_tramp: function sigreturn_tramp missing Go declaration
diff --git a/src/cmd/vet/all/whitelist/netbsd_386.txt b/src/cmd/vet/all/whitelist/netbsd_386.txt
new file mode 100644
index 0000000..1d1f323
--- /dev/null
+++ b/src/cmd/vet/all/whitelist/netbsd_386.txt
@@ -0,0 +1,23 @@
+// netbsd/386-specific vet whitelist. See readme.txt for details.
+
+runtime/sys_netbsd_ARCHSUFF.s: [GOARCH] settls: function settls missing Go declaration
+
+runtime/sys_netbsd_386.s: [386] sigreturn_tramp: use of 140(SP) points beyond argument frame
+runtime/sys_netbsd_386.s: [386] sigreturn_tramp: use of 4(SP) points beyond argument frame
+runtime/sys_netbsd_386.s: [386] sigreturn_tramp: use of 4(SP) points beyond argument frame
+runtime/sys_netbsd_386.s: [386] sigtramp: unknown variable signo
+runtime/sys_netbsd_386.s: [386] sigtramp: unknown variable info
+runtime/sys_netbsd_386.s: [386] sigtramp: unknown variable context
+runtime/sys_netbsd_386.s: [386] setldt: function setldt missing Go declaration
+runtime/sys_netbsd_386.s: [386] setldt: use of 16(SP) points beyond argument frame
+
+syscall/asm_unix_386.s: [386] Syscall: 8(SP) should be a1+4(FP)
+syscall/asm_unix_386.s: [386] Syscall: 4(SP) should be trap+0(FP)
+syscall/asm_unix_386.s: [386] Syscall6: 8(SP) should be a1+4(FP)
+syscall/asm_unix_386.s: [386] Syscall6: 4(SP) should be trap+0(FP)
+syscall/asm_unix_386.s: [386] Syscall9: 8(SP) should be a1+4(FP)
+syscall/asm_unix_386.s: [386] Syscall9: 4(SP) should be num+0(FP)
+syscall/asm_unix_386.s: [386] RawSyscall: 8(SP) should be a1+4(FP)
+syscall/asm_unix_386.s: [386] RawSyscall: 4(SP) should be trap+0(FP)
+syscall/asm_unix_386.s: [386] RawSyscall6: 8(SP) should be a1+4(FP)
+syscall/asm_unix_386.s: [386] RawSyscall6: 4(SP) should be trap+0(FP)
diff --git a/src/cmd/vet/all/whitelist/netbsd_amd64.txt b/src/cmd/vet/all/whitelist/netbsd_amd64.txt
new file mode 100644
index 0000000..8b14dc5
--- /dev/null
+++ b/src/cmd/vet/all/whitelist/netbsd_amd64.txt
@@ -0,0 +1,3 @@
+// netbsd/amd64-specific vet whitelist. See readme.txt for details.
+
+runtime/sys_netbsd_amd64.s: [amd64] settls: function settls missing Go declaration
diff --git a/src/cmd/vet/all/whitelist/netbsd_arm.txt b/src/cmd/vet/all/whitelist/netbsd_arm.txt
new file mode 100644
index 0000000..c0a0aa2
--- /dev/null
+++ b/src/cmd/vet/all/whitelist/netbsd_arm.txt
@@ -0,0 +1,5 @@
+// netbsd/arm-specific vet whitelist. See readme.txt for details.
+
+runtime/asm_arm.s: [arm] sigreturn: function sigreturn missing Go declaration
+runtime/sys_netbsd_arm.s: [arm] read_tls_fallback: function read_tls_fallback missing Go declaration
+syscall/asm_netbsd_arm.s: [arm] Syscall9: unknown variable trap; offset 0 is num+0(FP)
diff --git a/src/cmd/vet/all/whitelist/openbsd_386.txt b/src/cmd/vet/all/whitelist/openbsd_386.txt
new file mode 100644
index 0000000..b5c0a73
--- /dev/null
+++ b/src/cmd/vet/all/whitelist/openbsd_386.txt
@@ -0,0 +1,17 @@
+// openbsd/386-specific vet whitelist. See readme.txt for details.
+
+runtime/sys_openbsd_386.s: [386] sigtramp: unknown variable signo
+runtime/sys_openbsd_386.s: [386] sigtramp: unknown variable info
+runtime/sys_openbsd_386.s: [386] sigtramp: unknown variable context
+runtime/sys_openbsd_386.s: [386] setldt: function setldt missing Go declaration
+runtime/sys_openbsd_386.s: [386] settls: function settls missing Go declaration
+syscall/asm_unix_386.s: [386] Syscall: 8(SP) should be a1+4(FP)
+syscall/asm_unix_386.s: [386] Syscall: 4(SP) should be trap+0(FP)
+syscall/asm_unix_386.s: [386] Syscall6: 8(SP) should be a1+4(FP)
+syscall/asm_unix_386.s: [386] Syscall6: 4(SP) should be trap+0(FP)
+syscall/asm_unix_386.s: [386] Syscall9: 8(SP) should be a1+4(FP)
+syscall/asm_unix_386.s: [386] Syscall9: 4(SP) should be num+0(FP)
+syscall/asm_unix_386.s: [386] RawSyscall: 8(SP) should be a1+4(FP)
+syscall/asm_unix_386.s: [386] RawSyscall: 4(SP) should be trap+0(FP)
+syscall/asm_unix_386.s: [386] RawSyscall6: 8(SP) should be a1+4(FP)
+syscall/asm_unix_386.s: [386] RawSyscall6: 4(SP) should be trap+0(FP)
diff --git a/src/cmd/vet/all/whitelist/openbsd_amd64.txt b/src/cmd/vet/all/whitelist/openbsd_amd64.txt
new file mode 100644
index 0000000..433f62c
--- /dev/null
+++ b/src/cmd/vet/all/whitelist/openbsd_amd64.txt
@@ -0,0 +1,3 @@
+// openbsd/amd64-specific vet whitelist. See readme.txt for details.
+
+runtime/sys_openbsd_amd64.s: [amd64] settls: function settls missing Go declaration
diff --git a/src/cmd/vet/all/whitelist/openbsd_arm.txt b/src/cmd/vet/all/whitelist/openbsd_arm.txt
new file mode 100644
index 0000000..16bf26c
--- /dev/null
+++ b/src/cmd/vet/all/whitelist/openbsd_arm.txt
@@ -0,0 +1,4 @@
+// openbsd/arm-specific vet whitelist. See readme.txt for details.
+
+runtime/asm_arm.s: [arm] sigreturn: function sigreturn missing Go declaration
+runtime/sys_openbsd_arm.s: [arm] read_tls_fallback: function read_tls_fallback missing Go declaration
diff --git a/src/cmd/vet/all/whitelist/plan9_386.txt b/src/cmd/vet/all/whitelist/plan9_386.txt
new file mode 100644
index 0000000..1531161
--- /dev/null
+++ b/src/cmd/vet/all/whitelist/plan9_386.txt
@@ -0,0 +1,3 @@
+// plan9/386-specific vet whitelist. See readme.txt for details.
+
+runtime/sys_plan9_386.s: [386] setldt: function setldt missing Go declaration
diff --git a/src/cmd/vet/all/whitelist/plan9_amd64.txt b/src/cmd/vet/all/whitelist/plan9_amd64.txt
new file mode 100644
index 0000000..39fc8e2
--- /dev/null
+++ b/src/cmd/vet/all/whitelist/plan9_amd64.txt
@@ -0,0 +1,4 @@
+// plan9/amd64-specific vet whitelist. See readme.txt for details.
+
+runtime/sys_plan9_amd64.s: [amd64] setldt: function setldt missing Go declaration
+runtime/sys_plan9_amd64.s: [amd64] settls: function settls missing Go declaration
diff --git a/src/cmd/vet/all/whitelist/plan9_arm.txt b/src/cmd/vet/all/whitelist/plan9_arm.txt
new file mode 100644
index 0000000..5af3271
--- /dev/null
+++ b/src/cmd/vet/all/whitelist/plan9_arm.txt
@@ -0,0 +1,4 @@
+// plan9/arm-specific vet whitelist. See readme.txt for details.
+
+runtime/asm_arm.s: [arm] sigreturn: function sigreturn missing Go declaration
+runtime/sys_plan9_arm.s: [arm] read_tls_fallback: function read_tls_fallback missing Go declaration
diff --git a/src/cmd/vet/all/whitelist/ppc64x.txt b/src/cmd/vet/all/whitelist/ppc64x.txt
new file mode 100644
index 0000000..4f6444e
--- /dev/null
+++ b/src/cmd/vet/all/whitelist/ppc64x.txt
@@ -0,0 +1,12 @@
+// ppc64-specific vet whitelist. See readme.txt for details.
+
+runtime/asm_ARCHSUFF.s: [GOARCH] cannot check cross-package assembly function: Compare is in package bytes
+
+runtime/asm_ppc64x.s: [GOARCH] reginit: function reginit missing Go declaration
+runtime/asm_ppc64x.s: [GOARCH] abort: function abort missing Go declaration
+runtime/asm_ppc64x.s: [GOARCH] memeqbody: function memeqbody missing Go declaration
+runtime/asm_ppc64x.s: [GOARCH] goexit: use of 24(R1) points beyond argument frame
+runtime/asm_ppc64x.s: [GOARCH] addmoduledata: function addmoduledata missing Go declaration
+runtime/duff_ppc64x.s: [GOARCH] duffzero: function duffzero missing Go declaration
+runtime/tls_ppc64x.s: [GOARCH] save_g: function save_g missing Go declaration
+runtime/tls_ppc64x.s: [GOARCH] load_g: function load_g missing Go declaration
diff --git a/src/cmd/vet/all/whitelist/readme.txt b/src/cmd/vet/all/whitelist/readme.txt
new file mode 100644
index 0000000..4f83757
--- /dev/null
+++ b/src/cmd/vet/all/whitelist/readme.txt
@@ -0,0 +1,4 @@
+This directory contains whitelists for vet complaints about the standard library and commands.
+They are line-based and unordered, although counts of duplicated lines matter.
+Each line matches vet's output, except that line numbers are removed to avoid churn.
+There are also os-, arch-, and bitwidth-specific whitelists.
diff --git a/src/cmd/vet/all/whitelist/s390x.txt b/src/cmd/vet/all/whitelist/s390x.txt
new file mode 100644
index 0000000..875835e
--- /dev/null
+++ b/src/cmd/vet/all/whitelist/s390x.txt
@@ -0,0 +1,19 @@
+reflect/asm_s390x.s: [s390x] makeFuncStub: use of 16(R15) points beyond argument frame
+reflect/asm_s390x.s: [s390x] methodValueCall: use of 16(R15) points beyond argument frame
+runtime/asm_s390x.s: [s390x] abort: function abort missing Go declaration
+runtime/asm_s390x.s: [s390x] memeqbody: function memeqbody missing Go declaration
+runtime/asm_s390x.s: [s390x] memeqbodyclc: function memeqbodyclc missing Go declaration
+runtime/asm_s390x.s: [s390x] indexbytebody: function indexbytebody missing Go declaration
+runtime/asm_s390x.s: [s390x] cannot check cross-package assembly function: Compare is in package bytes
+runtime/asm_s390x.s: [s390x] cmpbody: function cmpbody missing Go declaration
+runtime/asm_s390x.s: [s390x] cmpbodyclc: function cmpbodyclc missing Go declaration
+runtime/asm_s390x.s: [s390x] cannot check cross-package assembly function: supportsVX is in package strings
+runtime/asm_s390x.s: [s390x] cannot check cross-package assembly function: supportsVX is in package bytes
+runtime/asm_s390x.s: [s390x] cannot check cross-package assembly function: indexShortStr is in package strings
+runtime/asm_s390x.s: [s390x] cannot check cross-package assembly function: indexShortStr is in package bytes
+runtime/asm_s390x.s: [s390x] indexShortStr: function indexShortStr missing Go declaration
+runtime/asm_s390x.s: [s390x] addmoduledata: function addmoduledata missing Go declaration
+runtime/memclr_s390x.s: [s390x] memclr_s390x_exrl_xc: function memclr_s390x_exrl_xc missing Go declaration
+runtime/memmove_s390x.s: [s390x] memmove_s390x_exrl_mvc: function memmove_s390x_exrl_mvc missing Go declaration
+runtime/tls_s390x.s: [s390x] save_g: function save_g missing Go declaration
+runtime/tls_s390x.s: [s390x] load_g: function load_g missing Go declaration
diff --git a/src/cmd/vet/all/whitelist/solaris_amd64.txt b/src/cmd/vet/all/whitelist/solaris_amd64.txt
new file mode 100644
index 0000000..26a9da4
--- /dev/null
+++ b/src/cmd/vet/all/whitelist/solaris_amd64.txt
@@ -0,0 +1,6 @@
+// solaris/amd64-specific vet whitelist. See readme.txt for details.
+
+runtime/sys_solaris_amd64.s: [amd64] settls: function settls missing Go declaration
+runtime/sys_solaris_amd64.s: [amd64] pipe1: function pipe1 missing Go declaration
+runtime/sys_solaris_amd64.s: [amd64] asmsysvicall6: function asmsysvicall6 missing Go declaration
+runtime/sys_solaris_amd64.s: [amd64] usleep2: function usleep2 missing Go declaration
diff --git a/src/cmd/vet/all/whitelist/windows.txt b/src/cmd/vet/all/whitelist/windows.txt
new file mode 100644
index 0000000..e80a92f
--- /dev/null
+++ b/src/cmd/vet/all/whitelist/windows.txt
@@ -0,0 +1,5 @@
+// windows-specific vet whitelist. See readme.txt for details.
+
+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
new file mode 100644
index 0000000..7a6d23f
--- /dev/null
+++ b/src/cmd/vet/all/whitelist/windows_386.txt
@@ -0,0 +1,9 @@
+// windows/386-specific vet whitelist. See readme.txt for details.
+
+runtime/sys_windows_386.s: [386] profileloop: use of 4(SP) points beyond argument frame
+runtime/sys_windows_386.s: [386] ctrlhandler: 4(SP) should be _type+0(FP)
+runtime/sys_windows_386.s: [386] setldt: function setldt missing Go declaration
+runtime/zcallback_windows.s: [386] callbackasm: function callbackasm missing Go declaration
+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)
diff --git a/src/cmd/vet/all/whitelist/windows_amd64.txt b/src/cmd/vet/all/whitelist/windows_amd64.txt
new file mode 100644
index 0000000..a2e1844
--- /dev/null
+++ b/src/cmd/vet/all/whitelist/windows_amd64.txt
@@ -0,0 +1,8 @@
+// windows/amd64-specific vet whitelist. See readme.txt for details.
+
+runtime/sys_windows_amd64.s: [amd64] ctrlhandler: 16(SP) should be _type+0(FP)
+runtime/sys_windows_amd64.s: [amd64] ctrlhandler: RET without writing to 4-byte ret+8(FP)
+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/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 d543b2e..a516cc4 100644
--- a/src/cmd/vet/asmdecl.go
+++ b/src/cmd/vet/asmdecl.go
@@ -10,7 +10,9 @@ import (
"bytes"
"fmt"
"go/ast"
+ "go/build"
"go/token"
+ "go/types"
"regexp"
"strconv"
"strings"
@@ -24,16 +26,17 @@ type asmKind int
const (
asmString asmKind = 100 + iota
asmSlice
+ asmArray
asmInterface
asmEmptyInterface
+ asmStruct
+ asmComplex
)
// An asmArch describes assembly parameters for an architecture
type asmArch struct {
name string
- ptrSize int
- intSize int
- maxAlign int
+ sizes *types.StdSizes
bigEndian bool
stack string
lr bool
@@ -57,16 +60,26 @@ type asmVar struct {
inner []*asmVar
}
+// Common architecture word sizes and alignments.
var (
- asmArch386 = asmArch{"386", 4, 4, 4, false, "SP", false}
- asmArchArm = asmArch{"arm", 4, 4, 4, false, "R13", true}
- asmArchArm64 = asmArch{"arm64", 8, 8, 8, false, "RSP", true}
- asmArchAmd64 = asmArch{"amd64", 8, 8, 8, false, "SP", false}
- asmArchAmd64p32 = asmArch{"amd64p32", 4, 4, 8, false, "SP", false}
- asmArchMips64 = asmArch{"mips64", 8, 8, 8, true, "R29", true}
- asmArchMips64LE = asmArch{"mips64", 8, 8, 8, false, "R29", true}
- asmArchPpc64 = asmArch{"ppc64", 8, 8, 8, true, "R1", true}
- asmArchPpc64LE = asmArch{"ppc64le", 8, 8, 8, false, "R1", true}
+ 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}
arches = []*asmArch{
&asmArch386,
@@ -74,17 +87,24 @@ var (
&asmArchArm64,
&asmArchAmd64,
&asmArchAmd64p32,
+ &asmArchMips,
+ &asmArchMipsLE,
&asmArchMips64,
&asmArchMips64LE,
&asmArchPpc64,
&asmArchPpc64LE,
+ &asmArchS390X,
}
)
+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) }
+
var (
re = regexp.MustCompile
asmPlusBuild = re(`//\s+\+build\s+([^\n]+)`)
- asmTEXT = re(`\bTEXT\b.*·([^\(]+)\(SB\)(?:\s*,\s*([0-9A-Z|+]+))?(?:\s*,\s*\$(-?[0-9]+)(?:-([0-9]+))?)?`)
+ asmTEXT = re(`\bTEXT\b(.*)·([^\(]+)\(SB\)(?:\s*,\s*([0-9A-Z|+]+))?(?:\s*,\s*\$(-?[0-9]+)(?:-([0-9]+))?)?`)
asmDATA = re(`\b(DATA|GLOBL)\b`)
asmNamedFP = re(`([a-zA-Z0-9_\xFF-\x{10FFFF}]+)(?:\+([0-9]+))\(FP\)`)
asmUnnamedFP = re(`[^+\-0-9](([0-9]+)\(FP\))`)
@@ -163,40 +183,73 @@ Files:
if arch == "" {
// Determine architecture from +build line if possible.
if m := asmPlusBuild.FindStringSubmatch(line); m != nil {
- Fields:
+ // There can be multiple architectures in a single +build line,
+ // so accumulate them all and then prefer the one that
+ // matches build.Default.GOARCH.
+ var archCandidates []*asmArch
for _, fld := range strings.Fields(m[1]) {
for _, a := range arches {
if a.name == fld {
- arch = a.name
- archDef = a
- break Fields
+ archCandidates = append(archCandidates, a)
}
}
}
+ for _, a := range archCandidates {
+ if a.name == build.Default.GOARCH {
+ archCandidates = []*asmArch{a}
+ break
+ }
+ }
+ if len(archCandidates) > 0 {
+ arch = archCandidates[0].name
+ archDef = archCandidates[0]
+ }
}
}
if m := asmTEXT.FindStringSubmatch(line); m != nil {
flushRet()
if arch == "" {
- f.Warnf(token.NoPos, "%s: cannot determine architecture for assembly file", f.name)
- continue Files
+ // Arch not specified by filename or build tags.
+ // Fall back to build.Default.GOARCH.
+ for _, a := range arches {
+ if a.name == build.Default.GOARCH {
+ arch = a.name
+ archDef = a
+ break
+ }
+ }
+ if arch == "" {
+ f.Warnf(token.NoPos, "%s: cannot determine architecture for assembly file", f.name)
+ continue Files
+ }
+ }
+ fnName = m[2]
+ if pkgName := strings.TrimSpace(m[1]); pkgName != "" {
+ pathParts := strings.Split(pkgName, "∕")
+ pkgName = pathParts[len(pathParts)-1]
+ if pkgName != f.pkg.path {
+ f.Warnf(token.NoPos, "%s:%d: [%s] cannot check cross-package assembly function: %s is in package %s", f.name, lineno, arch, fnName, pkgName)
+ fn = nil
+ fnName = ""
+ continue
+ }
}
- fnName = m[1]
- fn = knownFunc[m[1]][arch]
+ fn = knownFunc[fnName][arch]
if fn != nil {
- size, _ := strconv.Atoi(m[4])
- if size != fn.size && (m[2] != "7" && !strings.Contains(m[2], "NOSPLIT") || size != 0) {
+ size, _ := strconv.Atoi(m[5])
+ flag := m[3]
+ if size != fn.size && (flag != "7" && !strings.Contains(flag, "NOSPLIT") || size != 0) {
badf("wrong argument size %d; expected $...-%d", size, fn.size)
}
}
- localSize, _ = strconv.Atoi(m[3])
- localSize += archDef.intSize
+ localSize, _ = strconv.Atoi(m[4])
+ localSize += archDef.intSize()
if archDef.lr {
// Account for caller's saved LR
- localSize += archDef.intSize
+ localSize += archDef.intSize()
}
- argSize, _ = strconv.Atoi(m[4])
+ argSize, _ = strconv.Atoi(m[5])
if fn == nil && !strings.Contains(fnName, "<>") {
badf("function %s missing Go declaration", fnName)
}
@@ -300,199 +353,179 @@ Files:
}
}
+func asmKindForType(t types.Type, size int) asmKind {
+ switch t := t.Underlying().(type) {
+ case *types.Basic:
+ switch t.Kind() {
+ case types.String:
+ return asmString
+ case types.Complex64, types.Complex128:
+ return asmComplex
+ }
+ return asmKind(size)
+ case *types.Pointer, *types.Chan, *types.Map, *types.Signature:
+ return asmKind(size)
+ case *types.Struct:
+ return asmStruct
+ case *types.Interface:
+ if t.Empty() {
+ return asmEmptyInterface
+ }
+ return asmInterface
+ case *types.Array:
+ return asmArray
+ case *types.Slice:
+ return asmSlice
+ }
+ panic("unreachable")
+}
+
+// A component is an assembly-addressable component of a composite type,
+// or a composite type itself.
+type component struct {
+ size int
+ offset int
+ kind asmKind
+ typ string
+ suffix string // Such as _base for string base, _0_lo for lo half of first element of [1]uint64 on 32 bit machine.
+ outer string // The suffix for immediately containing composite type.
+}
+
+func newComponent(suffix string, kind asmKind, typ string, offset, size int, outer string) component {
+ return component{suffix: suffix, kind: kind, typ: typ, offset: offset, size: size, outer: outer}
+}
+
+// componentsOfType generates a list of components of type t.
+// For example, given string, the components are the string itself, the base, and the length.
+func componentsOfType(arch *asmArch, t types.Type) []component {
+ return appendComponentsRecursive(arch, t, nil, "", 0)
+}
+
+// appendComponentsRecursive implements componentsOfType.
+// Recursion is required to correct handle structs and arrays,
+// which can contain arbitrary other types.
+func appendComponentsRecursive(arch *asmArch, t types.Type, cc []component, suffix string, off int) []component {
+ s := t.String()
+ size := int(arch.sizes.Sizeof(t))
+ kind := asmKindForType(t, size)
+ cc = append(cc, newComponent(suffix, kind, s, off, size, suffix))
+
+ switch kind {
+ case 8:
+ if arch.ptrSize() == 4 {
+ w1, w2 := "lo", "hi"
+ if arch.bigEndian {
+ w1, w2 = w2, w1
+ }
+ cc = append(cc, newComponent(suffix+"_"+w1, 4, "half "+s, off, 4, suffix))
+ cc = append(cc, newComponent(suffix+"_"+w2, 4, "half "+s, off+4, 4, suffix))
+ }
+
+ 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))
+
+ 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))
+
+ 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))
+
+ 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))
+
+ case asmComplex:
+ fsize := size / 2
+ cc = append(cc, newComponent(suffix+"_real", asmKind(fsize), fmt.Sprintf("real(complex%d)", size*8), off, fsize, suffix))
+ cc = append(cc, newComponent(suffix+"_imag", asmKind(fsize), fmt.Sprintf("imag(complex%d)", size*8), off+fsize, fsize, suffix))
+
+ case asmStruct:
+ tu := t.Underlying().(*types.Struct)
+ fields := make([]*types.Var, tu.NumFields())
+ for i := 0; i < tu.NumFields(); i++ {
+ fields[i] = tu.Field(i)
+ }
+ offsets := arch.sizes.Offsetsof(fields)
+ for i, f := range fields {
+ cc = appendComponentsRecursive(arch, f.Type(), cc, suffix+"_"+f.Name(), off+int(offsets[i]))
+ }
+
+ case asmArray:
+ tu := t.Underlying().(*types.Array)
+ elem := tu.Elem()
+ // Calculate offset of each element array.
+ fields := []*types.Var{
+ types.NewVar(token.NoPos, nil, "fake0", elem),
+ types.NewVar(token.NoPos, nil, "fake1", elem),
+ }
+ offsets := arch.sizes.Offsetsof(fields)
+ elemoff := int(offsets[1])
+ for i := 0; i < int(tu.Len()); i++ {
+ cc = appendComponentsRecursive(arch, elem, cc, suffix+"_"+strconv.Itoa(i), i*elemoff)
+ }
+ }
+
+ return cc
+}
+
// asmParseDecl parses a function decl for expected assembly variables.
func (f *File) asmParseDecl(decl *ast.FuncDecl) map[string]*asmFunc {
var (
arch *asmArch
fn *asmFunc
offset int
- failed bool
)
- addVar := func(outer string, v asmVar) {
- if vo := fn.vars[outer]; vo != nil {
- vo.inner = append(vo.inner, &v)
- }
- fn.vars[v.name] = &v
- for i := 0; i < v.size; i++ {
- fn.varByOffset[v.off+i] = &v
- }
- }
-
- addParams := func(list []*ast.Field) {
- for i, fld := range list {
- // Determine alignment, size, and kind of type in declaration.
- var align, size int
- var kind asmKind
- names := fld.Names
- typ := f.gofmt(fld.Type)
- switch t := fld.Type.(type) {
- default:
- switch typ {
- default:
- f.Warnf(fld.Type.Pos(), "unknown assembly argument type %s", typ)
- failed = true
- return
- case "int8", "uint8", "byte", "bool":
- size = 1
- case "int16", "uint16":
- size = 2
- case "int32", "uint32", "float32":
- size = 4
- case "int64", "uint64", "float64":
- align = arch.maxAlign
- size = 8
- case "int", "uint":
- size = arch.intSize
- case "uintptr", "iword", "Word", "Errno", "unsafe.Pointer":
- size = arch.ptrSize
- case "string", "ErrorString":
- size = arch.ptrSize * 2
- align = arch.ptrSize
- kind = asmString
- }
- case *ast.ChanType, *ast.FuncType, *ast.MapType, *ast.StarExpr:
- size = arch.ptrSize
- case *ast.InterfaceType:
- align = arch.ptrSize
- size = 2 * arch.ptrSize
- if len(t.Methods.List) > 0 {
- kind = asmInterface
- } else {
- kind = asmEmptyInterface
- }
- case *ast.ArrayType:
- if t.Len == nil {
- size = arch.ptrSize + 2*arch.intSize
- align = arch.ptrSize
- kind = asmSlice
- break
- }
- f.Warnf(fld.Type.Pos(), "unsupported assembly argument type %s", typ)
- failed = true
- case *ast.StructType:
- f.Warnf(fld.Type.Pos(), "unsupported assembly argument type %s", typ)
- failed = true
- }
- if align == 0 {
- align = size
- }
- if kind == 0 {
- kind = asmKind(size)
- }
+ // addParams adds asmVars for each of the parameters in list.
+ // isret indicates whether the list are the arguments or the return values.
+ addParams := func(list []*ast.Field, isret bool) {
+ argnum := 0
+ for _, fld := range list {
+ t := f.pkg.types[fld.Type].Type
+ align := int(arch.sizes.Alignof(t))
+ size := int(arch.sizes.Sizeof(t))
offset += -offset & (align - 1)
+ cc := componentsOfType(arch, t)
- // Create variable for each name being declared with this type.
+ // names is the list of names with this type.
+ names := fld.Names
if len(names) == 0 {
- name := "unnamed"
- if decl.Type.Results != nil && len(decl.Type.Results.List) > 0 && &list[0] == &decl.Type.Results.List[0] && i == 0 {
- // Assume assembly will refer to single unnamed result as r.
+ // Anonymous args will be called arg, arg1, arg2, ...
+ // Similarly so for return values: ret, ret1, ret2, ...
+ name := "arg"
+ if isret {
name = "ret"
}
- names = []*ast.Ident{{Name: name}}
+ if argnum > 0 {
+ name += strconv.Itoa(argnum)
+ }
+ names = []*ast.Ident{ast.NewIdent(name)}
}
+ argnum += len(names)
+
+ // Create variable for each name.
for _, id := range names {
name := id.Name
- addVar("", asmVar{
- name: name,
- kind: kind,
- typ: typ,
- off: offset,
- size: size,
- })
- switch kind {
- case 8:
- if arch.ptrSize == 4 {
- w1, w2 := "lo", "hi"
- if arch.bigEndian {
- w1, w2 = w2, w1
- }
- addVar(name, asmVar{
- name: name + "_" + w1,
- kind: 4,
- typ: "half " + typ,
- off: offset,
- size: 4,
- })
- addVar(name, asmVar{
- name: name + "_" + w2,
- kind: 4,
- typ: "half " + typ,
- off: offset + 4,
- size: 4,
- })
+ for _, c := range cc {
+ outer := name + c.outer
+ v := asmVar{
+ name: name + c.suffix,
+ kind: c.kind,
+ typ: c.typ,
+ off: offset + c.offset,
+ size: c.size,
+ }
+ if vo := fn.vars[outer]; vo != nil {
+ vo.inner = append(vo.inner, &v)
+ }
+ fn.vars[v.name] = &v
+ for i := 0; i < v.size; i++ {
+ fn.varByOffset[v.off+i] = &v
}
-
- case asmEmptyInterface:
- addVar(name, asmVar{
- name: name + "_type",
- kind: asmKind(arch.ptrSize),
- typ: "interface type",
- off: offset,
- size: arch.ptrSize,
- })
- addVar(name, asmVar{
- name: name + "_data",
- kind: asmKind(arch.ptrSize),
- typ: "interface data",
- off: offset + arch.ptrSize,
- size: arch.ptrSize,
- })
-
- case asmInterface:
- addVar(name, asmVar{
- name: name + "_itable",
- kind: asmKind(arch.ptrSize),
- typ: "interface itable",
- off: offset,
- size: arch.ptrSize,
- })
- addVar(name, asmVar{
- name: name + "_data",
- kind: asmKind(arch.ptrSize),
- typ: "interface data",
- off: offset + arch.ptrSize,
- size: arch.ptrSize,
- })
-
- case asmSlice:
- addVar(name, asmVar{
- name: name + "_base",
- kind: asmKind(arch.ptrSize),
- typ: "slice base",
- off: offset,
- size: arch.ptrSize,
- })
- addVar(name, asmVar{
- name: name + "_len",
- kind: asmKind(arch.intSize),
- typ: "slice len",
- off: offset + arch.ptrSize,
- size: arch.intSize,
- })
- addVar(name, asmVar{
- name: name + "_cap",
- kind: asmKind(arch.intSize),
- typ: "slice cap",
- off: offset + arch.ptrSize + arch.intSize,
- size: arch.intSize,
- })
-
- case asmString:
- addVar(name, asmVar{
- name: name + "_base",
- kind: asmKind(arch.ptrSize),
- typ: "string base",
- off: offset,
- size: arch.ptrSize,
- })
- addVar(name, asmVar{
- name: name + "_len",
- kind: asmKind(arch.intSize),
- typ: "string len",
- off: offset + arch.ptrSize,
- size: arch.intSize,
- })
}
offset += size
}
@@ -507,18 +540,15 @@ func (f *File) asmParseDecl(decl *ast.FuncDecl) map[string]*asmFunc {
varByOffset: make(map[int]*asmVar),
}
offset = 0
- addParams(decl.Type.Params.List)
+ addParams(decl.Type.Params.List, false)
if decl.Type.Results != nil && len(decl.Type.Results.List) > 0 {
- offset += -offset & (arch.maxAlign - 1)
- addParams(decl.Type.Results.List)
+ offset += -offset & (arch.maxAlign() - 1)
+ addParams(decl.Type.Results.List, true)
}
fn.size = offset
m[arch.name] = fn
}
- if failed {
- return nil
- }
return m
}
@@ -613,7 +643,7 @@ func asmCheckVar(badf func(string, ...interface{}), fn *asmFunc, line, expr stri
src = 8
}
}
- case "mips64", "mips64le":
+ case "mips", "mipsle", "mips64", "mips64le":
switch op {
case "MOVB", "MOVBU":
src = 1
@@ -624,6 +654,17 @@ func asmCheckVar(badf func(string, ...interface{}), fn *asmFunc, line, expr stri
case "MOVV", "MOVD":
src = 8
}
+ case "s390x":
+ switch op {
+ case "MOVB", "MOVBZ":
+ src = 1
+ case "MOVH", "MOVHZ":
+ src = 2
+ case "MOVW", "MOVWZ", "FMOVS":
+ src = 4
+ case "MOVD", "FMOVD":
+ src = 8
+ }
}
}
if dst == 0 {
@@ -639,11 +680,13 @@ func asmCheckVar(badf func(string, ...interface{}), fn *asmFunc, line, expr stri
}
vk := v.kind
+ vs := v.size
vt := v.typ
switch vk {
case asmInterface, asmEmptyInterface, asmString, asmSlice:
// allow reference to first word (pointer)
vk = v.inner[0].kind
+ vs = v.inner[0].size
vt = v.inner[0].typ
}
@@ -677,6 +720,6 @@ func asmCheckVar(badf func(string, ...interface{}), fn *asmFunc, line, expr stri
fmt.Fprintf(&inner, "%s+%d(FP)", vi.name, vi.off)
}
}
- badf("invalid %s of %s; %s is %d-byte value%s", op, expr, vt, vk, inner.String())
+ badf("invalid %s of %s; %s is %d-byte value%s", op, expr, vt, vs, inner.String())
}
}
diff --git a/src/cmd/vet/cgo.go b/src/cmd/vet/cgo.go
index b896862..d233e9a 100644
--- a/src/cmd/vet/cgo.go
+++ b/src/cmd/vet/cgo.go
@@ -38,6 +38,11 @@ func checkCgoCall(f *File, node ast.Node) {
return
}
+ // A call to C.CBytes passes a pointer but is always safe.
+ if sel.Sel.Name == "CBytes" {
+ return
+ }
+
for _, arg := range x.Args {
if !typeOKForCgoCall(cgoBaseType(f, arg)) {
f.Badf(arg.Pos(), "possibly passing Go type with embedded pointer to C")
diff --git a/src/cmd/vet/copylock.go b/src/cmd/vet/copylock.go
index 6533768..31c1257 100644
--- a/src/cmd/vet/copylock.go
+++ b/src/cmd/vet/copylock.go
@@ -210,6 +210,14 @@ func lockPath(tpkg *types.Package, typ types.Type) typePath {
return nil
}
+ for {
+ atyp, ok := typ.Underlying().(*types.Array)
+ if !ok {
+ break
+ }
+ typ = atyp.Elem()
+ }
+
// We're only interested in the case in which the underlying
// type is a struct. (Interfaces and pointers are safe to copy.)
styp, ok := typ.Underlying().(*types.Struct)
diff --git a/src/cmd/vet/doc.go b/src/cmd/vet/doc.go
index 69d5f9c..5cbe116 100644
--- a/src/cmd/vet/doc.go
+++ b/src/cmd/vet/doc.go
@@ -84,14 +84,14 @@ Flag: -copylocks
Locks that are erroneously passed by value.
-Tests, benchmarks and documentation examples
+HTTP responses used incorrectly
-Flag: -tests
+Flag: -httpresponse
-Mistakes involving tests including functions with incorrect names or signatures
-and example tests that document identifiers not in the package.
+Mistakes deferring a function call on an HTTP response before
+checking whether the error returned with the response was nil.
-Failure to call the cancelation function returned by context.WithCancel.
+Failure to call the cancelation function returned by WithCancel
Flag: -lostcancel
@@ -137,8 +137,6 @@ complains about arguments that look like format descriptor strings.
It also checks for errors such as using a Writer as the first argument of
Printf.
-Struct tags
-
Range loop variables
Flag: -rangeloops
@@ -157,11 +155,20 @@ Flag: -shift
Shifts equal to or longer than the variable's length.
+Struct tags
+
Flag: -structtags
Struct tags that do not follow the format understood by reflect.StructTag.Get.
Well-known encoding struct tags (json, xml) used with unexported fields.
+Tests and documentation examples
+
+Flag: -tests
+
+Mistakes involving tests including functions with incorrect names or signatures
+and example tests that document identifiers not in the package.
+
Unreachable code
Flag: -unreachable
diff --git a/src/cmd/vet/httpresponse.go b/src/cmd/vet/httpresponse.go
new file mode 100644
index 0000000..f667edb
--- /dev/null
+++ b/src/cmd/vet/httpresponse.go
@@ -0,0 +1,153 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file contains the check for http.Response values being used before
+// checking for errors.
+
+package main
+
+import (
+ "go/ast"
+ "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) {
+ call := node.(*ast.CallExpr)
+ if !isHTTPFuncOrMethodOnClient(f, call) {
+ return // the function call is not related to this check.
+ }
+
+ finder := &blockStmtFinder{node: call}
+ ast.Walk(finder, f.file)
+ stmts := finder.stmts()
+ if len(stmts) < 2 {
+ return // the call to the http function is the last statement of the block.
+ }
+
+ asg, ok := stmts[0].(*ast.AssignStmt)
+ if !ok {
+ return // the first statement is not assignment.
+ }
+ resp := rootIdent(asg.Lhs[0])
+ if resp == nil {
+ return // could not find the http.Response in the assignment.
+ }
+
+ def, ok := stmts[1].(*ast.DeferStmt)
+ if !ok {
+ return // the following statement is not a defer.
+ }
+ root := rootIdent(def.Call.Fun)
+ if root == nil {
+ return // could not find the receiver of the defer call.
+ }
+
+ if resp.Obj == root.Obj {
+ f.Badf(root.Pos(), "using %s before checking for errors", resp.Name)
+ }
+}
+
+// isHTTPFuncOrMethodOnClient checks whether the given call expression is on
+// either a function of the net/http package or a method of http.Client that
+// returns (*http.Response, error).
+func isHTTPFuncOrMethodOnClient(f *File, expr *ast.CallExpr) bool {
+ fun, _ := expr.Fun.(*ast.SelectorExpr)
+ sig, _ := f.pkg.types[fun].Type.(*types.Signature)
+ if sig == nil {
+ return false // the call is not on of the form x.f()
+ }
+
+ res := sig.Results()
+ if res.Len() != 2 {
+ return false // the function called does not return two values.
+ }
+ if ptr, ok := res.At(0).Type().(*types.Pointer); !ok || !types.Identical(ptr.Elem(), httpResponseType) {
+ return false // the first return type is not *http.Response.
+ }
+ if !types.Identical(res.At(1).Type().Underlying(), errorType) {
+ return false // the second return type is not error
+ }
+
+ typ := f.pkg.types[fun.X].Type
+ if typ == nil {
+ id, ok := fun.X.(*ast.Ident)
+ return ok && id.Name == "http" // function in net/http package.
+ }
+
+ if types.Identical(typ, httpClientType) {
+ return true // method on http.Client.
+ }
+ ptr, ok := typ.(*types.Pointer)
+ return ok && types.Identical(ptr.Elem(), httpClientType) // method on *http.Client.
+}
+
+// blockStmtFinder is an ast.Visitor that given any ast node can find the
+// statement containing it and its succeeding statements in the same block.
+type blockStmtFinder struct {
+ node ast.Node // target of search
+ stmt ast.Stmt // innermost statement enclosing argument to Visit
+ block *ast.BlockStmt // innermost block enclosing argument to Visit.
+}
+
+// Visit finds f.node performing a search down the ast tree.
+// It keeps the last block statement and statement seen for later use.
+func (f *blockStmtFinder) Visit(node ast.Node) ast.Visitor {
+ if node == nil || f.node.Pos() < node.Pos() || f.node.End() > node.End() {
+ return nil // not here
+ }
+ switch n := node.(type) {
+ case *ast.BlockStmt:
+ f.block = n
+ case ast.Stmt:
+ f.stmt = n
+ }
+ if f.node.Pos() == node.Pos() && f.node.End() == node.End() {
+ return nil // found
+ }
+ return f // keep looking
+}
+
+// stmts returns the statements of f.block starting from the one including f.node.
+func (f *blockStmtFinder) stmts() []ast.Stmt {
+ for i, v := range f.block.List {
+ if f.stmt == v {
+ return f.block.List[i:]
+ }
+ }
+ return nil
+}
+
+// rootIdent finds the root identifier x in a chain of selections x.y.z, or nil if not found.
+func rootIdent(n ast.Node) *ast.Ident {
+ switch n := n.(type) {
+ case *ast.SelectorExpr:
+ return rootIdent(n.X)
+ case *ast.Ident:
+ return n
+ default:
+ return nil
+ }
+}
diff --git a/src/cmd/vet/main.go b/src/cmd/vet/main.go
index 4f3cca8..3da0b3c 100644
--- a/src/cmd/vet/main.go
+++ b/src/cmd/vet/main.go
@@ -25,7 +25,7 @@ import (
var (
verbose = flag.Bool("v", false, "verbose")
- tags = flag.String("tags", "", "comma-separated list of build tags to apply when parsing")
+ tags = flag.String("tags", "", "space-separated list of build tags to apply when parsing")
tagList = []string{} // exploded version of tags flag; set in main
)
@@ -133,13 +133,13 @@ var (
callExpr *ast.CallExpr
compositeLit *ast.CompositeLit
exprStmt *ast.ExprStmt
- field *ast.Field
funcDecl *ast.FuncDecl
funcLit *ast.FuncLit
genDecl *ast.GenDecl
interfaceType *ast.InterfaceType
rangeStmt *ast.RangeStmt
returnStmt *ast.ReturnStmt
+ structType *ast.StructType
// checkers is a two-level map.
// The outer level is keyed by a nil pointer, one of the AST vars above.
@@ -161,7 +161,7 @@ func register(name, usage string, fn func(*File, ast.Node), types ...ast.Node) {
// Usage is a replacement usage function for the flags package.
func Usage() {
- fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
+ fmt.Fprintf(os.Stderr, "Usage of vet:\n")
fmt.Fprintf(os.Stderr, "\tvet [flags] directory...\n")
fmt.Fprintf(os.Stderr, "\tvet [flags] files... # Must be a single package\n")
fmt.Fprintf(os.Stderr, "By default, -all is set and all non-experimental checks are run.\n")
@@ -208,7 +208,10 @@ func main() {
}
}
- tagList = strings.Split(*tags, ",")
+ // Accept space-separated tags because that matches
+ // the go command's other subcommands.
+ // Accept commas because go tool vet traditionally has.
+ tagList = strings.Fields(strings.Replace(*tags, ",", " ", -1))
initPrintFlags()
initUnusedFlags()
@@ -440,14 +443,22 @@ func (f *File) loc(pos token.Pos) string {
return fmt.Sprintf("%s:%d", posn.Filename, posn.Line)
}
+// locPrefix returns a formatted representation of the position for use as a line prefix.
+func (f *File) locPrefix(pos token.Pos) string {
+ if pos == token.NoPos {
+ return ""
+ }
+ return fmt.Sprintf("%s: ", f.loc(pos))
+}
+
// Warn reports an error but does not set the exit code.
func (f *File) Warn(pos token.Pos, args ...interface{}) {
- fmt.Fprintf(os.Stderr, "%s: %s", f.loc(pos), fmt.Sprintln(args...))
+ fmt.Fprintf(os.Stderr, "%s%s", f.locPrefix(pos), fmt.Sprintln(args...))
}
// Warnf reports a formatted error but does not set the exit code.
func (f *File) Warnf(pos token.Pos, format string, args ...interface{}) {
- fmt.Fprintf(os.Stderr, "%s: %s\n", f.loc(pos), fmt.Sprintf(format, args...))
+ fmt.Fprintf(os.Stderr, "%s%s\n", f.locPrefix(pos), fmt.Sprintf(format, args...))
}
// walkFile walks the file's tree.
@@ -470,8 +481,6 @@ func (f *File) Visit(node ast.Node) ast.Visitor {
key = compositeLit
case *ast.ExprStmt:
key = exprStmt
- case *ast.Field:
- key = field
case *ast.FuncDecl:
key = funcDecl
case *ast.FuncLit:
@@ -484,6 +493,8 @@ func (f *File) Visit(node ast.Node) ast.Visitor {
key = rangeStmt
case *ast.ReturnStmt:
key = returnStmt
+ case *ast.StructType:
+ key = structType
}
for _, fn := range f.checkers[key] {
fn(f, node)
diff --git a/src/cmd/vet/print.go b/src/cmd/vet/print.go
index f4b985c..9998dda 100644
--- a/src/cmd/vet/print.go
+++ b/src/cmd/vet/print.go
@@ -94,7 +94,7 @@ func formatString(f *File, call *ast.CallExpr) (string, int) {
if typ != nil {
if sig, ok := typ.(*types.Signature); ok {
if !sig.Variadic() {
- // Skip checking non-variadic functions
+ // Skip checking non-variadic functions.
return "", -1
}
idx := sig.Params().Len() - 2
@@ -103,30 +103,36 @@ func formatString(f *File, call *ast.CallExpr) (string, int) {
// fixed arguments.
return "", -1
}
- s, ok := stringLiteralArg(f, call, idx)
+ s, ok := stringConstantArg(f, call, idx)
if !ok {
- // The last argument before variadic args isn't a string
+ // The last argument before variadic args isn't a string.
return "", -1
}
return s, idx
}
}
- // Cannot determine call's signature. Fallback to scanning for the first
- // string argument in the call
+ // Cannot determine call's signature. Fall back to scanning for the first
+ // string constant in the call.
for idx := range call.Args {
- if s, ok := stringLiteralArg(f, call, idx); ok {
+ if s, ok := stringConstantArg(f, call, idx); ok {
return s, idx
}
+ if f.pkg.types[call.Args[idx]].Type == types.Typ[types.String] {
+ // Skip checking a call with a non-constant format
+ // string argument, since its contents are unavailable
+ // for validation.
+ return "", -1
+ }
}
return "", -1
}
-// stringLiteralArg returns call's string constant argument at the index idx.
+// stringConstantArg returns call's string constant argument at the index idx.
//
// ("", false) is returned if call's argument at the index idx isn't a string
-// literal.
-func stringLiteralArg(f *File, call *ast.CallExpr, idx int) (string, bool) {
+// constant.
+func stringConstantArg(f *File, call *ast.CallExpr, idx int) (string, bool) {
if idx >= len(call.Args) {
return "", false
}
@@ -186,6 +192,12 @@ func isStringer(f *File, d *ast.FuncDecl) bool {
f.pkg.types[d.Type.Results.List[0].Type].Type == types.Typ[types.String]
}
+// isFormatter reports whether t satisfies fmt.Formatter.
+// Unlike fmt.Stringer, it's impossible to satisfy fmt.Formatter without importing fmt.
+func (f *File) isFormatter(t types.Type) bool {
+ return formatterType != nil && types.Implements(t, formatterType)
+}
+
// formatState holds the parsed representation of a printf directive such as "%3.*[4]d".
// It is constructed by parsePrintfVerb.
type formatState struct {
@@ -194,7 +206,6 @@ type formatState struct {
name string // Printf, Sprintf etc.
flags []byte // the list of # + etc.
argNums []int // the successive argument numbers that are consumed, adjusted to refer to actual arg in call
- indexed bool // whether an indexing expression appears: %[1]d.
firstArg int // Index of first argument after the format in the Printf call.
// Used only during parse.
file *File
@@ -223,7 +234,7 @@ func (f *File) checkPrintf(call *ast.CallExpr, name string) {
}
// Hard part: check formats against args.
argNum := firstArg
- indexed := false
+ maxArgNum := firstArg
for i, w := 0, 0; i < len(format); i += w {
w = 1
if format[i] == '%' {
@@ -232,9 +243,6 @@ func (f *File) checkPrintf(call *ast.CallExpr, name string) {
return
}
w = len(state.format)
- if state.indexed {
- indexed = true
- }
if !f.okPrintfArg(call, state) { // One error per format is enough.
return
}
@@ -242,16 +250,20 @@ func (f *File) checkPrintf(call *ast.CallExpr, name string) {
// Continue with the next sequential argument.
argNum = state.argNums[len(state.argNums)-1] + 1
}
+ for _, n := range state.argNums {
+ if n >= maxArgNum {
+ maxArgNum = n + 1
+ }
+ }
}
}
// Dotdotdot is hard.
- if call.Ellipsis.IsValid() && argNum >= len(call.Args)-1 {
+ if call.Ellipsis.IsValid() && maxArgNum >= len(call.Args)-1 {
return
}
- // If the arguments were direct indexed, we assume the programmer knows what's up.
- // Otherwise, there should be no leftover arguments.
- if !indexed && argNum != len(call.Args) {
- expect := argNum - firstArg
+ // There should be no leftover arguments.
+ if maxArgNum != len(call.Args) {
+ expect := maxArgNum - firstArg
numArgs := len(call.Args) - firstArg
f.Badf(call.Pos(), "wrong number of args for format in %s call: %d needed but %d args", name, expect, numArgs)
}
@@ -286,17 +298,20 @@ func (s *formatState) parseIndex() bool {
return true
}
// Argument index present.
- s.indexed = true
s.nbytes++ // skip '['
start := s.nbytes
s.scanNum()
if s.nbytes == len(s.format) || s.nbytes == start || s.format[s.nbytes] != ']' {
- s.file.Badf(s.call.Pos(), "illegal syntax for printf argument index")
+ end := strings.Index(s.format, "]")
+ if end < 0 {
+ end = len(s.format)
+ }
+ s.file.Badf(s.call.Pos(), "bad syntax for printf argument index: [%s]", s.format[start:end])
return false
}
arg32, err := strconv.ParseInt(s.format[start:s.nbytes], 10, 32)
if err != nil {
- s.file.Badf(s.call.Pos(), "illegal syntax for printf argument index: %s", err)
+ s.file.Badf(s.call.Pos(), "bad syntax for printf argument index: %s", err)
return false
}
s.nbytes++ // skip ']'
@@ -349,14 +364,12 @@ func (f *File) parsePrintfVerb(call *ast.CallExpr, name, format string, firstArg
argNum: argNum,
argNums: make([]int, 0, 1),
nbytes: 1, // There's guaranteed to be a percent sign.
- indexed: false,
firstArg: firstArg,
file: f,
call: call,
}
// There may be flags.
state.parseFlags()
- indexPending := false
// There may be an index.
if !state.parseIndex() {
return nil
@@ -370,7 +383,7 @@ func (f *File) parsePrintfVerb(call *ast.CallExpr, name, format string, firstArg
return nil
}
// Now a verb, possibly prefixed by an index (which we may already have).
- if !indexPending && !state.parseIndex() {
+ if !state.indexPending && !state.parseIndex() {
return nil
}
if state.nbytes == len(state.format) {
@@ -416,8 +429,6 @@ const (
)
// printVerbs identifies which flags are known to printf for each verb.
-// TODO: A type that implements Formatter may do what it wants, and vet
-// will complain incorrectly.
var printVerbs = []printVerb{
// '-' is a width modifier, always valid.
// '.' is a precision for float, max width for strings.
@@ -459,7 +470,16 @@ func (f *File) okPrintfArg(call *ast.CallExpr, state *formatState) (ok bool) {
break
}
}
- if !found {
+
+ // Does current arg implement fmt.Formatter?
+ formatter := false
+ if state.argNum < len(call.Args) {
+ if tv, ok := f.pkg.types[call.Args[state.argNum]]; ok {
+ formatter = f.isFormatter(tv.Type)
+ }
+ }
+
+ if !found && !formatter {
f.Badf(call.Pos(), "unrecognized printf verb %q", state.verb)
return false
}
@@ -487,7 +507,7 @@ func (f *File) okPrintfArg(call *ast.CallExpr, state *formatState) (ok bool) {
return false
}
}
- if state.verb == '%' {
+ if state.verb == '%' || formatter {
return true
}
argNum := state.argNums[len(state.argNums)-1]
@@ -626,7 +646,10 @@ func (f *File) checkPrint(call *ast.CallExpr, name string) {
}
arg := args[0]
if lit, ok := arg.(*ast.BasicLit); ok && lit.Kind == token.STRING {
- if strings.Contains(lit.Value, "%") {
+ // Ignore trailing % character in lit.Value.
+ // The % in "abc 0.0%" couldn't be a formatting directive.
+ s := strings.TrimSuffix(lit.Value, `%"`)
+ if strings.Contains(s, "%") {
f.Badf(call.Pos(), "possible formatting directive in %s call", name)
}
}
diff --git a/src/cmd/vet/shift.go b/src/cmd/vet/shift.go
index 8c038b4..55f3ea3 100644
--- a/src/cmd/vet/shift.go
+++ b/src/cmd/vet/shift.go
@@ -41,6 +41,12 @@ func checkShift(f *File, node ast.Node) {
// checkLongShift checks if shift or shift-assign operations shift by more than
// the length of the underlying variable.
func checkLongShift(f *File, node ast.Node, x, y ast.Expr) {
+ if f.pkg.types[x].Value != nil {
+ // Ignore shifts of constants.
+ // These are frequently used for bit-twiddling tricks
+ // like ^uint(0) >> 63 for 32/64 bit detection and compatibility.
+ return
+ }
v := f.pkg.types[y].Value
if v == nil {
return
diff --git a/src/cmd/vet/structtag.go b/src/cmd/vet/structtag.go
index abff14f..814bbda 100644
--- a/src/cmd/vet/structtag.go
+++ b/src/cmd/vet/structtag.go
@@ -9,20 +9,31 @@ package main
import (
"errors"
"go/ast"
+ "go/token"
"reflect"
"strconv"
+ "strings"
)
func init() {
register("structtags",
"check that struct field tags have canonical format and apply to exported fields as needed",
- checkCanonicalFieldTag,
- field)
+ checkStructFieldTags,
+ structType)
}
-// checkCanonicalFieldTag checks a struct field tag.
-func checkCanonicalFieldTag(f *File, node ast.Node) {
- field := node.(*ast.Field)
+// checkStructFieldTags checks all the field tags of a struct, including checking for duplicates.
+func checkStructFieldTags(f *File, node ast.Node) {
+ var seen map[[2]string]token.Pos
+ for _, field := range node.(*ast.StructType).Fields.List {
+ checkCanonicalFieldTag(f, field, &seen)
+ }
+}
+
+var checkTagDups = []string{"json", "xml"}
+
+// checkCanonicalFieldTag checks a single struct field tag.
+func checkCanonicalFieldTag(f *File, field *ast.Field, seen *map[[2]string]token.Pos) {
if field.Tag == nil {
return
}
@@ -34,7 +45,26 @@ func checkCanonicalFieldTag(f *File, node ast.Node) {
}
if err := validateStructTag(tag); err != nil {
- f.Badf(field.Pos(), "struct field tag %s not compatible with reflect.StructTag.Get: %s", field.Tag.Value, err)
+ raw, _ := strconv.Unquote(field.Tag.Value) // field.Tag.Value is known to be a quoted string
+ f.Badf(field.Pos(), "struct field tag %#q not compatible with reflect.StructTag.Get: %s", raw, err)
+ }
+
+ for _, key := range checkTagDups {
+ val := reflect.StructTag(tag).Get(key)
+ if val == "" || val == "-" || val[0] == ',' {
+ continue
+ }
+ if i := strings.Index(val, ","); i >= 0 {
+ val = val[:i]
+ }
+ if *seen == nil {
+ *seen = map[[2]string]token.Pos{}
+ }
+ if pos, ok := (*seen)[[2]string{key, val}]; ok {
+ f.Badf(field.Pos(), "struct field %s repeats %s tag %q also at %s", field.Names[0].Name, key, val, f.loc(pos))
+ } else {
+ (*seen)[[2]string{key, val}] = field.Pos()
+ }
}
// Check for use of json or xml tags with unexported fields.
@@ -49,9 +79,8 @@ func checkCanonicalFieldTag(f *File, node ast.Node) {
return
}
- st := reflect.StructTag(tag)
for _, enc := range [...]string{"json", "xml"} {
- if st.Get(enc) != "" {
+ if reflect.StructTag(tag).Get(enc) != "" {
f.Badf(field.Pos(), "struct field %s has %s tag but is not exported", field.Names[0].Name, enc)
return
}
@@ -62,6 +91,7 @@ var (
errTagSyntax = errors.New("bad syntax for struct tag pair")
errTagKeySyntax = errors.New("bad syntax for struct tag key")
errTagValueSyntax = errors.New("bad syntax for struct tag value")
+ errTagSpace = errors.New("key:\"value\" pairs not separated by spaces")
)
// validateStructTag parses the struct tag and returns an error if it is not
@@ -70,7 +100,13 @@ var (
func validateStructTag(tag string) error {
// This code is based on the StructTag.Get code in package reflect.
- for tag != "" {
+ n := 0
+ for ; tag != ""; n++ {
+ if n > 0 && tag != "" && tag[0] != ' ' {
+ // More restrictive than reflect, but catches likely mistakes
+ // like `x:"foo",y:"bar"`, which parses as `x:"foo" ,y:"bar"` with second key ",y".
+ return errTagSpace
+ }
// Skip leading space.
i := 0
for i < len(tag) && tag[i] == ' ' {
diff --git a/src/cmd/vet/testdata/asm.go b/src/cmd/vet/testdata/asm.go
deleted file mode 100644
index 8194710..0000000
--- a/src/cmd/vet/testdata/asm.go
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright 2010 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build ignore
-
-// This file contains declarations to test the assembly in test_asm.s.
-
-package testdata
-
-func arg1(x int8, y uint8)
-func arg2(x int16, y uint16)
-func arg4(x int32, y uint32)
-func arg8(x int64, y uint64)
-func argint(x int, y uint)
-func argptr(x *byte, y *byte, c chan int, m map[int]int, f func())
-func argstring(x, y string)
-func argslice(x, y []string)
-func argiface(x interface{}, y interface {
- m()
-})
-func returnint() int
-func returnbyte(x int) byte
-func returnnamed(x byte) (r1 int, r2 int16, r3 string, r4 byte)
-func returnintmissing() int
-func leaf(x, y int) int
-
-func noprof(x int)
-func dupok(x int)
-func nosplit(x int)
-func rodata(x int)
-func noptr(x int)
-func wrapper(x int)
-
-func f15271() (x uint32)
diff --git a/src/cmd/vet/testdata/asm/asm.go b/src/cmd/vet/testdata/asm/asm.go
new file mode 100644
index 0000000..e6d6d03
--- /dev/null
+++ b/src/cmd/vet/testdata/asm/asm.go
@@ -0,0 +1,45 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build ignore
+
+// This file contains declarations to test the assembly in test_asm.s.
+
+package testdata
+
+type S struct {
+ i int32
+ b bool
+ s string
+}
+
+func arg1(x int8, y uint8)
+func arg2(x int16, y uint16)
+func arg4(x int32, y uint32)
+func arg8(x int64, y uint64)
+func argint(x int, y uint)
+func argptr(x *byte, y *byte, c chan int, m map[int]int, f func())
+func argstring(x, y string)
+func argslice(x, y []string)
+func argiface(x interface{}, y interface {
+ m()
+})
+func argcomplex(x complex64, y complex128)
+func argstruct(x S, y struct{})
+func argarray(x [2]S)
+func returnint() int
+func returnbyte(x int) byte
+func returnnamed(x byte) (r1 int, r2 int16, r3 string, r4 byte)
+func returnintmissing() int
+func leaf(x, y int) int
+
+func noprof(x int)
+func dupok(x int)
+func nosplit(x int)
+func rodata(x int)
+func noptr(x int)
+func wrapper(x int)
+
+func f15271() (x uint32)
+func f17584(x float32, y complex64)
diff --git a/src/cmd/vet/testdata/asm/asm1.s b/src/cmd/vet/testdata/asm/asm1.s
new file mode 100644
index 0000000..cac6ed2
--- /dev/null
+++ b/src/cmd/vet/testdata/asm/asm1.s
@@ -0,0 +1,315 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build amd64
+// +build vet_test
+
+TEXT ·arg1(SB),0,$0-2
+ MOVB x+0(FP), AX
+ // MOVB x+0(FP), AX // commented out instructions used to panic
+ MOVB y+1(FP), BX
+ MOVW x+0(FP), AX // ERROR "\[amd64\] arg1: invalid MOVW of x\+0\(FP\); int8 is 1-byte value"
+ MOVW y+1(FP), AX // ERROR "invalid MOVW of y\+1\(FP\); uint8 is 1-byte value"
+ MOVL x+0(FP), AX // ERROR "invalid MOVL of x\+0\(FP\); int8 is 1-byte value"
+ MOVL y+1(FP), AX // ERROR "invalid MOVL of y\+1\(FP\); uint8 is 1-byte value"
+ MOVQ x+0(FP), AX // ERROR "invalid MOVQ of x\+0\(FP\); int8 is 1-byte value"
+ MOVQ y+1(FP), AX // ERROR "invalid MOVQ of y\+1\(FP\); uint8 is 1-byte value"
+ MOVB x+1(FP), AX // ERROR "invalid offset x\+1\(FP\); expected x\+0\(FP\)"
+ MOVB y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+1\(FP\)"
+ TESTB x+0(FP), AX
+ TESTB y+1(FP), BX
+ TESTW x+0(FP), AX // ERROR "invalid TESTW of x\+0\(FP\); int8 is 1-byte value"
+ TESTW y+1(FP), AX // ERROR "invalid TESTW of y\+1\(FP\); uint8 is 1-byte value"
+ TESTL x+0(FP), AX // ERROR "invalid TESTL of x\+0\(FP\); int8 is 1-byte value"
+ TESTL y+1(FP), AX // ERROR "invalid TESTL of y\+1\(FP\); uint8 is 1-byte value"
+ TESTQ x+0(FP), AX // ERROR "invalid TESTQ of x\+0\(FP\); int8 is 1-byte value"
+ TESTQ y+1(FP), AX // ERROR "invalid TESTQ of y\+1\(FP\); uint8 is 1-byte value"
+ TESTB x+1(FP), AX // ERROR "invalid offset x\+1\(FP\); expected x\+0\(FP\)"
+ TESTB y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+1\(FP\)"
+ MOVB 8(SP), AX // ERROR "8\(SP\) should be x\+0\(FP\)"
+ MOVB 9(SP), AX // ERROR "9\(SP\) should be y\+1\(FP\)"
+ MOVB 10(SP), AX // ERROR "use of 10\(SP\) points beyond argument frame"
+ RET
+
+TEXT ·arg2(SB),0,$0-4
+ MOVB x+0(FP), AX // ERROR "arg2: invalid MOVB of x\+0\(FP\); int16 is 2-byte value"
+ MOVB y+2(FP), AX // ERROR "invalid MOVB of y\+2\(FP\); uint16 is 2-byte value"
+ MOVW x+0(FP), AX
+ MOVW y+2(FP), BX
+ MOVL x+0(FP), AX // ERROR "invalid MOVL of x\+0\(FP\); int16 is 2-byte value"
+ MOVL y+2(FP), AX // ERROR "invalid MOVL of y\+2\(FP\); uint16 is 2-byte value"
+ MOVQ x+0(FP), AX // ERROR "invalid MOVQ of x\+0\(FP\); int16 is 2-byte value"
+ MOVQ y+2(FP), AX // ERROR "invalid MOVQ of y\+2\(FP\); uint16 is 2-byte value"
+ MOVW x+2(FP), AX // ERROR "invalid offset x\+2\(FP\); expected x\+0\(FP\)"
+ MOVW y+0(FP), AX // ERROR "invalid offset y\+0\(FP\); expected y\+2\(FP\)"
+ TESTB x+0(FP), AX // ERROR "invalid TESTB of x\+0\(FP\); int16 is 2-byte value"
+ TESTB y+2(FP), AX // ERROR "invalid TESTB of y\+2\(FP\); uint16 is 2-byte value"
+ TESTW x+0(FP), AX
+ TESTW y+2(FP), BX
+ TESTL x+0(FP), AX // ERROR "invalid TESTL of x\+0\(FP\); int16 is 2-byte value"
+ TESTL y+2(FP), AX // ERROR "invalid TESTL of y\+2\(FP\); uint16 is 2-byte value"
+ TESTQ x+0(FP), AX // ERROR "invalid TESTQ of x\+0\(FP\); int16 is 2-byte value"
+ TESTQ y+2(FP), AX // ERROR "invalid TESTQ of y\+2\(FP\); uint16 is 2-byte value"
+ TESTW x+2(FP), AX // ERROR "invalid offset x\+2\(FP\); expected x\+0\(FP\)"
+ TESTW y+0(FP), AX // ERROR "invalid offset y\+0\(FP\); expected y\+2\(FP\)"
+ RET
+
+TEXT ·arg4(SB),0,$0-2 // ERROR "arg4: wrong argument size 2; expected \$\.\.\.-8"
+ MOVB x+0(FP), AX // ERROR "invalid MOVB of x\+0\(FP\); int32 is 4-byte value"
+ MOVB y+4(FP), BX // ERROR "invalid MOVB of y\+4\(FP\); uint32 is 4-byte value"
+ MOVW x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); int32 is 4-byte value"
+ MOVW y+4(FP), AX // ERROR "invalid MOVW of y\+4\(FP\); uint32 is 4-byte value"
+ MOVL x+0(FP), AX
+ MOVL y+4(FP), AX
+ MOVQ x+0(FP), AX // ERROR "invalid MOVQ of x\+0\(FP\); int32 is 4-byte value"
+ MOVQ y+4(FP), AX // ERROR "invalid MOVQ of y\+4\(FP\); uint32 is 4-byte value"
+ MOVL x+4(FP), AX // ERROR "invalid offset x\+4\(FP\); expected x\+0\(FP\)"
+ MOVL y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+4\(FP\)"
+ TESTB x+0(FP), AX // ERROR "invalid TESTB of x\+0\(FP\); int32 is 4-byte value"
+ TESTB y+4(FP), BX // ERROR "invalid TESTB of y\+4\(FP\); uint32 is 4-byte value"
+ TESTW x+0(FP), AX // ERROR "invalid TESTW of x\+0\(FP\); int32 is 4-byte value"
+ TESTW y+4(FP), AX // ERROR "invalid TESTW of y\+4\(FP\); uint32 is 4-byte value"
+ TESTL x+0(FP), AX
+ TESTL y+4(FP), AX
+ TESTQ x+0(FP), AX // ERROR "invalid TESTQ of x\+0\(FP\); int32 is 4-byte value"
+ TESTQ y+4(FP), AX // ERROR "invalid TESTQ of y\+4\(FP\); uint32 is 4-byte value"
+ TESTL x+4(FP), AX // ERROR "invalid offset x\+4\(FP\); expected x\+0\(FP\)"
+ TESTL y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+4\(FP\)"
+ RET
+
+TEXT ·arg8(SB),7,$0-2 // ERROR "wrong argument size 2; expected \$\.\.\.-16"
+ MOVB x+0(FP), AX // ERROR "invalid MOVB of x\+0\(FP\); int64 is 8-byte value"
+ MOVB y+8(FP), BX // ERROR "invalid MOVB of y\+8\(FP\); uint64 is 8-byte value"
+ MOVW x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); int64 is 8-byte value"
+ MOVW y+8(FP), AX // ERROR "invalid MOVW of y\+8\(FP\); uint64 is 8-byte value"
+ MOVL x+0(FP), AX // ERROR "invalid MOVL of x\+0\(FP\); int64 is 8-byte value"
+ MOVL y+8(FP), AX // ERROR "invalid MOVL of y\+8\(FP\); uint64 is 8-byte value"
+ MOVQ x+0(FP), AX
+ MOVQ y+8(FP), AX
+ MOVQ x+8(FP), AX // ERROR "invalid offset x\+8\(FP\); expected x\+0\(FP\)"
+ MOVQ y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+8\(FP\)"
+ TESTB x+0(FP), AX // ERROR "invalid TESTB of x\+0\(FP\); int64 is 8-byte value"
+ TESTB y+8(FP), BX // ERROR "invalid TESTB of y\+8\(FP\); uint64 is 8-byte value"
+ TESTW x+0(FP), AX // ERROR "invalid TESTW of x\+0\(FP\); int64 is 8-byte value"
+ TESTW y+8(FP), AX // ERROR "invalid TESTW of y\+8\(FP\); uint64 is 8-byte value"
+ TESTL x+0(FP), AX // ERROR "invalid TESTL of x\+0\(FP\); int64 is 8-byte value"
+ TESTL y+8(FP), AX // ERROR "invalid TESTL of y\+8\(FP\); uint64 is 8-byte value"
+ TESTQ x+0(FP), AX
+ TESTQ y+8(FP), AX
+ TESTQ x+8(FP), AX // ERROR "invalid offset x\+8\(FP\); expected x\+0\(FP\)"
+ TESTQ y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+8\(FP\)"
+ RET
+
+TEXT ·argint(SB),0,$0-2 // ERROR "wrong argument size 2; expected \$\.\.\.-16"
+ MOVB x+0(FP), AX // ERROR "invalid MOVB of x\+0\(FP\); int is 8-byte value"
+ MOVB y+8(FP), BX // ERROR "invalid MOVB of y\+8\(FP\); uint is 8-byte value"
+ MOVW x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); int is 8-byte value"
+ MOVW y+8(FP), AX // ERROR "invalid MOVW of y\+8\(FP\); uint is 8-byte value"
+ MOVL x+0(FP), AX // ERROR "invalid MOVL of x\+0\(FP\); int is 8-byte value"
+ MOVL y+8(FP), AX // ERROR "invalid MOVL of y\+8\(FP\); uint is 8-byte value"
+ MOVQ x+0(FP), AX
+ MOVQ y+8(FP), AX
+ MOVQ x+8(FP), AX // ERROR "invalid offset x\+8\(FP\); expected x\+0\(FP\)"
+ MOVQ y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+8\(FP\)"
+ TESTB x+0(FP), AX // ERROR "invalid TESTB of x\+0\(FP\); int is 8-byte value"
+ TESTB y+8(FP), BX // ERROR "invalid TESTB of y\+8\(FP\); uint is 8-byte value"
+ TESTW x+0(FP), AX // ERROR "invalid TESTW of x\+0\(FP\); int is 8-byte value"
+ TESTW y+8(FP), AX // ERROR "invalid TESTW of y\+8\(FP\); uint is 8-byte value"
+ TESTL x+0(FP), AX // ERROR "invalid TESTL of x\+0\(FP\); int is 8-byte value"
+ TESTL y+8(FP), AX // ERROR "invalid TESTL of y\+8\(FP\); uint is 8-byte value"
+ TESTQ x+0(FP), AX
+ TESTQ y+8(FP), AX
+ TESTQ x+8(FP), AX // ERROR "invalid offset x\+8\(FP\); expected x\+0\(FP\)"
+ TESTQ y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+8\(FP\)"
+ RET
+
+TEXT ·argptr(SB),7,$0-2 // ERROR "wrong argument size 2; expected \$\.\.\.-40"
+ MOVB x+0(FP), AX // ERROR "invalid MOVB of x\+0\(FP\); \*byte is 8-byte value"
+ MOVB y+8(FP), BX // ERROR "invalid MOVB of y\+8\(FP\); \*byte is 8-byte value"
+ MOVW x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); \*byte is 8-byte value"
+ MOVW y+8(FP), AX // ERROR "invalid MOVW of y\+8\(FP\); \*byte is 8-byte value"
+ MOVL x+0(FP), AX // ERROR "invalid MOVL of x\+0\(FP\); \*byte is 8-byte value"
+ MOVL y+8(FP), AX // ERROR "invalid MOVL of y\+8\(FP\); \*byte is 8-byte value"
+ MOVQ x+0(FP), AX
+ MOVQ y+8(FP), AX
+ MOVQ x+8(FP), AX // ERROR "invalid offset x\+8\(FP\); expected x\+0\(FP\)"
+ MOVQ y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+8\(FP\)"
+ TESTB x+0(FP), AX // ERROR "invalid TESTB of x\+0\(FP\); \*byte is 8-byte value"
+ TESTB y+8(FP), BX // ERROR "invalid TESTB of y\+8\(FP\); \*byte is 8-byte value"
+ TESTW x+0(FP), AX // ERROR "invalid TESTW of x\+0\(FP\); \*byte is 8-byte value"
+ TESTW y+8(FP), AX // ERROR "invalid TESTW of y\+8\(FP\); \*byte is 8-byte value"
+ TESTL x+0(FP), AX // ERROR "invalid TESTL of x\+0\(FP\); \*byte is 8-byte value"
+ TESTL y+8(FP), AX // ERROR "invalid TESTL of y\+8\(FP\); \*byte is 8-byte value"
+ TESTQ x+0(FP), AX
+ TESTQ y+8(FP), AX
+ TESTQ x+8(FP), AX // ERROR "invalid offset x\+8\(FP\); expected x\+0\(FP\)"
+ TESTQ y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+8\(FP\)"
+ MOVL c+16(FP), AX // ERROR "invalid MOVL of c\+16\(FP\); chan int is 8-byte value"
+ MOVL m+24(FP), AX // ERROR "invalid MOVL of m\+24\(FP\); map\[int\]int is 8-byte value"
+ MOVL f+32(FP), AX // ERROR "invalid MOVL of f\+32\(FP\); func\(\) is 8-byte value"
+ RET
+
+TEXT ·argstring(SB),0,$32 // ERROR "wrong argument size 0; expected \$\.\.\.-32"
+ MOVW x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); string base is 8-byte value"
+ MOVL x+0(FP), AX // ERROR "invalid MOVL of x\+0\(FP\); string base is 8-byte value"
+ MOVQ x+0(FP), AX
+ MOVW x_base+0(FP), AX // ERROR "invalid MOVW of x_base\+0\(FP\); string base is 8-byte value"
+ MOVL x_base+0(FP), AX // ERROR "invalid MOVL of x_base\+0\(FP\); string base is 8-byte value"
+ MOVQ x_base+0(FP), AX
+ MOVW x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)"
+ MOVL x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)"
+ MOVQ x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)"
+ MOVW x_len+8(FP), AX // ERROR "invalid MOVW of x_len\+8\(FP\); string len is 8-byte value"
+ MOVL x_len+8(FP), AX // ERROR "invalid MOVL of x_len\+8\(FP\); string len is 8-byte value"
+ MOVQ x_len+8(FP), AX
+ MOVQ y+0(FP), AX // ERROR "invalid offset y\+0\(FP\); expected y\+16\(FP\)"
+ MOVQ y_len+8(FP), AX // ERROR "invalid offset y_len\+8\(FP\); expected y_len\+24\(FP\)"
+ RET
+
+TEXT ·argslice(SB),0,$48 // ERROR "wrong argument size 0; expected \$\.\.\.-48"
+ MOVW x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); slice base is 8-byte value"
+ MOVL x+0(FP), AX // ERROR "invalid MOVL of x\+0\(FP\); slice base is 8-byte value"
+ MOVQ x+0(FP), AX
+ MOVW x_base+0(FP), AX // ERROR "invalid MOVW of x_base\+0\(FP\); slice base is 8-byte value"
+ MOVL x_base+0(FP), AX // ERROR "invalid MOVL of x_base\+0\(FP\); slice base is 8-byte value"
+ MOVQ x_base+0(FP), AX
+ MOVW x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)"
+ MOVL x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)"
+ MOVQ x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)"
+ MOVW x_len+8(FP), AX // ERROR "invalid MOVW of x_len\+8\(FP\); slice len is 8-byte value"
+ MOVL x_len+8(FP), AX // ERROR "invalid MOVL of x_len\+8\(FP\); slice len is 8-byte value"
+ MOVQ x_len+8(FP), AX
+ MOVW x_cap+0(FP), AX // ERROR "invalid offset x_cap\+0\(FP\); expected x_cap\+16\(FP\)"
+ MOVL x_cap+0(FP), AX // ERROR "invalid offset x_cap\+0\(FP\); expected x_cap\+16\(FP\)"
+ MOVQ x_cap+0(FP), AX // ERROR "invalid offset x_cap\+0\(FP\); expected x_cap\+16\(FP\)"
+ MOVW x_cap+16(FP), AX // ERROR "invalid MOVW of x_cap\+16\(FP\); slice cap is 8-byte value"
+ MOVL x_cap+16(FP), AX // ERROR "invalid MOVL of x_cap\+16\(FP\); slice cap is 8-byte value"
+ MOVQ x_cap+16(FP), AX
+ MOVQ y+0(FP), AX // ERROR "invalid offset y\+0\(FP\); expected y\+24\(FP\)"
+ MOVQ y_len+8(FP), AX // ERROR "invalid offset y_len\+8\(FP\); expected y_len\+32\(FP\)"
+ MOVQ y_cap+16(FP), AX // ERROR "invalid offset y_cap\+16\(FP\); expected y_cap\+40\(FP\)"
+ RET
+
+TEXT ·argiface(SB),0,$0-32
+ MOVW x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); interface type is 8-byte value"
+ MOVL x+0(FP), AX // ERROR "invalid MOVL of x\+0\(FP\); interface type is 8-byte value"
+ MOVQ x+0(FP), AX
+ MOVW x_type+0(FP), AX // ERROR "invalid MOVW of x_type\+0\(FP\); interface type is 8-byte value"
+ MOVL x_type+0(FP), AX // ERROR "invalid MOVL of x_type\+0\(FP\); interface type is 8-byte value"
+ MOVQ x_type+0(FP), AX
+ MOVQ x_itable+0(FP), AX // ERROR "unknown variable x_itable; offset 0 is x_type\+0\(FP\)"
+ MOVQ x_itable+1(FP), AX // ERROR "unknown variable x_itable; offset 1 is x_type\+0\(FP\)"
+ MOVW x_data+0(FP), AX // ERROR "invalid offset x_data\+0\(FP\); expected x_data\+8\(FP\)"
+ MOVL x_data+0(FP), AX // ERROR "invalid offset x_data\+0\(FP\); expected x_data\+8\(FP\)"
+ MOVQ x_data+0(FP), AX // ERROR "invalid offset x_data\+0\(FP\); expected x_data\+8\(FP\)"
+ MOVW x_data+8(FP), AX // ERROR "invalid MOVW of x_data\+8\(FP\); interface data is 8-byte value"
+ MOVL x_data+8(FP), AX // ERROR "invalid MOVL of x_data\+8\(FP\); interface data is 8-byte value"
+ MOVQ x_data+8(FP), AX
+ MOVW y+16(FP), AX // ERROR "invalid MOVW of y\+16\(FP\); interface itable is 8-byte value"
+ MOVL y+16(FP), AX // ERROR "invalid MOVL of y\+16\(FP\); interface itable is 8-byte value"
+ MOVQ y+16(FP), AX
+ MOVW y_itable+16(FP), AX // ERROR "invalid MOVW of y_itable\+16\(FP\); interface itable is 8-byte value"
+ MOVL y_itable+16(FP), AX // ERROR "invalid MOVL of y_itable\+16\(FP\); interface itable is 8-byte value"
+ MOVQ y_itable+16(FP), AX
+ MOVQ y_type+16(FP), AX // ERROR "unknown variable y_type; offset 16 is y_itable\+16\(FP\)"
+ MOVW y_data+16(FP), AX // ERROR "invalid offset y_data\+16\(FP\); expected y_data\+24\(FP\)"
+ MOVL y_data+16(FP), AX // ERROR "invalid offset y_data\+16\(FP\); expected y_data\+24\(FP\)"
+ MOVQ y_data+16(FP), AX // ERROR "invalid offset y_data\+16\(FP\); expected y_data\+24\(FP\)"
+ MOVW y_data+24(FP), AX // ERROR "invalid MOVW of y_data\+24\(FP\); interface data is 8-byte value"
+ MOVL y_data+24(FP), AX // ERROR "invalid MOVL of y_data\+24\(FP\); interface data is 8-byte value"
+ MOVQ y_data+24(FP), AX
+ RET
+
+TEXT ·argcomplex(SB),0,$24 // ERROR "wrong argument size 0; expected \$\.\.\.-24"
+ MOVSS x+0(FP), X0 // ERROR "invalid MOVSS of x\+0\(FP\); complex64 is 8-byte value containing x_real\+0\(FP\) and x_imag\+4\(FP\)"
+ MOVSD x+0(FP), X0 // ERROR "invalid MOVSD of x\+0\(FP\); complex64 is 8-byte value containing x_real\+0\(FP\) and x_imag\+4\(FP\)"
+ MOVSS x_real+0(FP), X0
+ MOVSD x_real+0(FP), X0 // ERROR "invalid MOVSD of x_real\+0\(FP\); real\(complex64\) is 4-byte value"
+ MOVSS x_real+4(FP), X0 // ERROR "invalid offset x_real\+4\(FP\); expected x_real\+0\(FP\)"
+ MOVSS x_imag+4(FP), X0
+ MOVSD x_imag+4(FP), X0 // ERROR "invalid MOVSD of x_imag\+4\(FP\); imag\(complex64\) is 4-byte value"
+ MOVSS x_imag+8(FP), X0 // ERROR "invalid offset x_imag\+8\(FP\); expected x_imag\+4\(FP\)"
+ MOVSD y+8(FP), X0 // ERROR "invalid MOVSD of y\+8\(FP\); complex128 is 16-byte value containing y_real\+8\(FP\) and y_imag\+16\(FP\)"
+ MOVSS y_real+8(FP), X0 // ERROR "invalid MOVSS of y_real\+8\(FP\); real\(complex128\) is 8-byte value"
+ MOVSD y_real+8(FP), X0
+ MOVSS y_real+16(FP), X0 // ERROR "invalid offset y_real\+16\(FP\); expected y_real\+8\(FP\)"
+ MOVSS y_imag+16(FP), X0 // ERROR "invalid MOVSS of y_imag\+16\(FP\); imag\(complex128\) is 8-byte value"
+ MOVSD y_imag+16(FP), X0
+ MOVSS y_imag+24(FP), X0 // ERROR "invalid offset y_imag\+24\(FP\); expected y_imag\+16\(FP\)"
+ RET
+
+TEXT ·argstruct(SB),0,$64 // ERROR "wrong argument size 0; expected \$\.\.\.-24"
+ MOVQ x+0(FP), AX // ERROR "invalid MOVQ of x\+0\(FP\); testdata.S is 24-byte value"
+ MOVQ x_i+0(FP), AX // ERROR "invalid MOVQ of x_i\+0\(FP\); int32 is 4-byte value"
+ MOVQ x_b+0(FP), AX // ERROR "invalid offset x_b\+0\(FP\); expected x_b\+4\(FP\)"
+ MOVQ x_s+8(FP), AX
+ MOVQ x_s_base+8(FP), AX
+ MOVQ x_s+16(FP), AX // ERROR "invalid offset x_s\+16\(FP\); expected x_s\+8\(FP\), x_s_base\+8\(FP\), or x_s_len\+16\(FP\)"
+ MOVQ x_s_len+16(FP), AX
+ RET
+
+TEXT ·argarray(SB),0,$64 // ERROR "wrong argument size 0; expected \$\.\.\.-48"
+ MOVQ x+0(FP), AX // ERROR "invalid MOVQ of x\+0\(FP\); \[2\]testdata.S is 48-byte value"
+ MOVQ x_0_i+0(FP), AX // ERROR "invalid MOVQ of x_0_i\+0\(FP\); int32 is 4-byte value"
+ MOVQ x_0_b+0(FP), AX // ERROR "invalid offset x_0_b\+0\(FP\); expected x_0_b\+4\(FP\)"
+ MOVQ x_0_s+8(FP), AX
+ MOVQ x_0_s_base+8(FP), AX
+ MOVQ x_0_s+16(FP), AX // ERROR "invalid offset x_0_s\+16\(FP\); expected x_0_s\+8\(FP\), x_0_s_base\+8\(FP\), or x_0_s_len\+16\(FP\)"
+ MOVQ x_0_s_len+16(FP), AX
+ MOVB foo+25(FP), AX // ERROR "unknown variable foo; offset 25 is x_1_i\+24\(FP\)"
+ MOVQ x_1_s+32(FP), AX
+ MOVQ x_1_s_base+32(FP), AX
+ MOVQ x_1_s+40(FP), AX // ERROR "invalid offset x_1_s\+40\(FP\); expected x_1_s\+32\(FP\), x_1_s_base\+32\(FP\), or x_1_s_len\+40\(FP\)"
+ MOVQ x_1_s_len+40(FP), AX
+ RET
+
+TEXT ·returnint(SB),0,$0-8
+ MOVB AX, ret+0(FP) // ERROR "invalid MOVB of ret\+0\(FP\); int is 8-byte value"
+ MOVW AX, ret+0(FP) // ERROR "invalid MOVW of ret\+0\(FP\); int is 8-byte value"
+ MOVL AX, ret+0(FP) // ERROR "invalid MOVL of ret\+0\(FP\); int is 8-byte value"
+ MOVQ AX, ret+0(FP)
+ MOVQ AX, ret+1(FP) // ERROR "invalid offset ret\+1\(FP\); expected ret\+0\(FP\)"
+ MOVQ AX, r+0(FP) // ERROR "unknown variable r; offset 0 is ret\+0\(FP\)"
+ RET
+
+TEXT ·returnbyte(SB),0,$0-9
+ MOVQ x+0(FP), AX
+ MOVB AX, ret+8(FP)
+ MOVW AX, ret+8(FP) // ERROR "invalid MOVW of ret\+8\(FP\); byte is 1-byte value"
+ MOVL AX, ret+8(FP) // ERROR "invalid MOVL of ret\+8\(FP\); byte is 1-byte value"
+ MOVQ AX, ret+8(FP) // ERROR "invalid MOVQ of ret\+8\(FP\); byte is 1-byte value"
+ MOVB AX, ret+7(FP) // ERROR "invalid offset ret\+7\(FP\); expected ret\+8\(FP\)"
+ RET
+
+TEXT ·returnnamed(SB),0,$0-41
+ MOVB x+0(FP), AX
+ MOVQ AX, r1+8(FP)
+ MOVW AX, r2+16(FP)
+ MOVQ AX, r3+24(FP)
+ MOVQ AX, r3_base+24(FP)
+ MOVQ AX, r3_len+32(FP)
+ MOVB AX, r4+40(FP)
+ MOVL AX, r1+8(FP) // ERROR "invalid MOVL of r1\+8\(FP\); int is 8-byte value"
+ RET
+
+TEXT ·returnintmissing(SB),0,$0-8
+ RET // ERROR "RET without writing to 8-byte ret\+0\(FP\)"
+
+
+// issue 15271
+TEXT ·f15271(SB), NOSPLIT, $0-4
+ // Stick 123 into the low 32 bits of X0.
+ MOVQ $123, AX
+ PINSRD $0, AX, X0
+
+ // Return them.
+ PEXTRD $0, X0, x+0(FP)
+ RET
+
+// issue 17584
+TEXT ·f17584(SB), NOSPLIT, $12
+ MOVSS x+0(FP), X0
+ MOVSS y_real+4(FP), X0
+ MOVSS y_imag+8(FP), X0
+ RET
diff --git a/src/cmd/vet/testdata/asm2.s b/src/cmd/vet/testdata/asm/asm2.s
similarity index 100%
rename from src/cmd/vet/testdata/asm2.s
rename to src/cmd/vet/testdata/asm/asm2.s
diff --git a/src/cmd/vet/testdata/asm3.s b/src/cmd/vet/testdata/asm/asm3.s
similarity index 100%
rename from src/cmd/vet/testdata/asm3.s
rename to src/cmd/vet/testdata/asm/asm3.s
diff --git a/src/cmd/vet/testdata/asm4.s b/src/cmd/vet/testdata/asm/asm4.s
similarity index 100%
rename from src/cmd/vet/testdata/asm4.s
rename to src/cmd/vet/testdata/asm/asm4.s
diff --git a/src/cmd/vet/testdata/asm5.s b/src/cmd/vet/testdata/asm/asm5.s
similarity index 100%
rename from src/cmd/vet/testdata/asm5.s
rename to src/cmd/vet/testdata/asm/asm5.s
diff --git a/src/cmd/vet/testdata/asm/asm6.s b/src/cmd/vet/testdata/asm/asm6.s
new file mode 100644
index 0000000..4e85ab3
--- /dev/null
+++ b/src/cmd/vet/testdata/asm/asm6.s
@@ -0,0 +1,193 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build s390x
+// +build vet_test
+
+TEXT ·arg1(SB),0,$0-2
+ MOVB x+0(FP), R1
+ MOVBZ y+1(FP), R2
+ MOVH x+0(FP), R1 // ERROR "\[s390x\] arg1: invalid MOVH of x\+0\(FP\); int8 is 1-byte value"
+ MOVHZ y+1(FP), R1 // ERROR "invalid MOVHZ of y\+1\(FP\); uint8 is 1-byte value"
+ MOVW x+0(FP), R1 // ERROR "invalid MOVW of x\+0\(FP\); int8 is 1-byte value"
+ MOVWZ y+1(FP), R1 // ERROR "invalid MOVWZ of y\+1\(FP\); uint8 is 1-byte value"
+ MOVD x+0(FP), R1 // ERROR "invalid MOVD of x\+0\(FP\); int8 is 1-byte value"
+ MOVD y+1(FP), R1 // ERROR "invalid MOVD of y\+1\(FP\); uint8 is 1-byte value"
+ MOVB x+1(FP), R1 // ERROR "invalid offset x\+1\(FP\); expected x\+0\(FP\)"
+ MOVBZ y+2(FP), R1 // ERROR "invalid offset y\+2\(FP\); expected y\+1\(FP\)"
+ MOVB 16(R15), R1 // ERROR "16\(R15\) should be x\+0\(FP\)"
+ MOVB 17(R15), R1 // ERROR "17\(R15\) should be y\+1\(FP\)"
+ MOVB 18(R15), R1 // ERROR "use of 18\(R15\) points beyond argument frame"
+ RET
+
+TEXT ·arg2(SB),0,$0-4
+ MOVBZ x+0(FP), R1 // ERROR "arg2: invalid MOVBZ of x\+0\(FP\); int16 is 2-byte value"
+ MOVB y+2(FP), R1 // ERROR "invalid MOVB of y\+2\(FP\); uint16 is 2-byte value"
+ MOVHZ x+0(FP), R1
+ MOVH y+2(FP), R2
+ MOVWZ x+0(FP), R1 // ERROR "invalid MOVWZ of x\+0\(FP\); int16 is 2-byte value"
+ MOVW y+2(FP), R1 // ERROR "invalid MOVW of y\+2\(FP\); uint16 is 2-byte value"
+ MOVD x+0(FP), R1 // ERROR "invalid MOVD of x\+0\(FP\); int16 is 2-byte value"
+ MOVD y+2(FP), R1 // ERROR "invalid MOVD of y\+2\(FP\); uint16 is 2-byte value"
+ MOVHZ x+2(FP), R1 // ERROR "invalid offset x\+2\(FP\); expected x\+0\(FP\)"
+ MOVH y+0(FP), R1 // ERROR "invalid offset y\+0\(FP\); expected y\+2\(FP\)"
+ RET
+
+TEXT ·arg4(SB),0,$0-2 // ERROR "arg4: wrong argument size 2; expected \$\.\.\.-8"
+ MOVB x+0(FP), R1 // ERROR "invalid MOVB of x\+0\(FP\); int32 is 4-byte value"
+ MOVB y+4(FP), R2 // ERROR "invalid MOVB of y\+4\(FP\); uint32 is 4-byte value"
+ MOVH x+0(FP), R1 // ERROR "invalid MOVH of x\+0\(FP\); int32 is 4-byte value"
+ MOVH y+4(FP), R1 // ERROR "invalid MOVH of y\+4\(FP\); uint32 is 4-byte value"
+ MOVW x+0(FP), R1
+ MOVW y+4(FP), R1
+ MOVD x+0(FP), R1 // ERROR "invalid MOVD of x\+0\(FP\); int32 is 4-byte value"
+ MOVD y+4(FP), R1 // ERROR "invalid MOVD of y\+4\(FP\); uint32 is 4-byte value"
+ MOVW x+4(FP), R1 // ERROR "invalid offset x\+4\(FP\); expected x\+0\(FP\)"
+ MOVW y+2(FP), R1 // ERROR "invalid offset y\+2\(FP\); expected y\+4\(FP\)"
+ RET
+
+TEXT ·arg8(SB),7,$0-2 // ERROR "wrong argument size 2; expected \$\.\.\.-16"
+ MOVB x+0(FP), R1 // ERROR "invalid MOVB of x\+0\(FP\); int64 is 8-byte value"
+ MOVB y+8(FP), R2 // ERROR "invalid MOVB of y\+8\(FP\); uint64 is 8-byte value"
+ MOVH x+0(FP), R1 // ERROR "invalid MOVH of x\+0\(FP\); int64 is 8-byte value"
+ MOVH y+8(FP), R1 // ERROR "invalid MOVH of y\+8\(FP\); uint64 is 8-byte value"
+ MOVW x+0(FP), R1 // ERROR "invalid MOVW of x\+0\(FP\); int64 is 8-byte value"
+ MOVW y+8(FP), R1 // ERROR "invalid MOVW of y\+8\(FP\); uint64 is 8-byte value"
+ MOVD x+0(FP), R1
+ MOVD y+8(FP), R1
+ MOVD x+8(FP), R1 // ERROR "invalid offset x\+8\(FP\); expected x\+0\(FP\)"
+ MOVD y+2(FP), R1 // ERROR "invalid offset y\+2\(FP\); expected y\+8\(FP\)"
+ RET
+
+TEXT ·argint(SB),0,$0-2 // ERROR "wrong argument size 2; expected \$\.\.\.-16"
+ MOVB x+0(FP), R1 // ERROR "invalid MOVB of x\+0\(FP\); int is 8-byte value"
+ MOVB y+8(FP), R2 // ERROR "invalid MOVB of y\+8\(FP\); uint is 8-byte value"
+ MOVH x+0(FP), R1 // ERROR "invalid MOVH of x\+0\(FP\); int is 8-byte value"
+ MOVH y+8(FP), R1 // ERROR "invalid MOVH of y\+8\(FP\); uint is 8-byte value"
+ MOVW x+0(FP), R1 // ERROR "invalid MOVW of x\+0\(FP\); int is 8-byte value"
+ MOVW y+8(FP), R1 // ERROR "invalid MOVW of y\+8\(FP\); uint is 8-byte value"
+ MOVD x+0(FP), R1
+ MOVD y+8(FP), R1
+ MOVD x+8(FP), R1 // ERROR "invalid offset x\+8\(FP\); expected x\+0\(FP\)"
+ MOVD y+2(FP), R1 // ERROR "invalid offset y\+2\(FP\); expected y\+8\(FP\)"
+ RET
+
+TEXT ·argptr(SB),7,$0-2 // ERROR "wrong argument size 2; expected \$\.\.\.-40"
+ MOVB x+0(FP), R1 // ERROR "invalid MOVB of x\+0\(FP\); \*byte is 8-byte value"
+ MOVB y+8(FP), R2 // ERROR "invalid MOVB of y\+8\(FP\); \*byte is 8-byte value"
+ MOVH x+0(FP), R1 // ERROR "invalid MOVH of x\+0\(FP\); \*byte is 8-byte value"
+ MOVH y+8(FP), R1 // ERROR "invalid MOVH of y\+8\(FP\); \*byte is 8-byte value"
+ MOVW x+0(FP), R1 // ERROR "invalid MOVW of x\+0\(FP\); \*byte is 8-byte value"
+ MOVW y+8(FP), R1 // ERROR "invalid MOVW of y\+8\(FP\); \*byte is 8-byte value"
+ MOVD x+0(FP), R1
+ MOVD y+8(FP), R1
+ MOVD x+8(FP), R1 // ERROR "invalid offset x\+8\(FP\); expected x\+0\(FP\)"
+ MOVD y+2(FP), R1 // ERROR "invalid offset y\+2\(FP\); expected y\+8\(FP\)"
+ MOVW c+16(FP), R1 // ERROR "invalid MOVW of c\+16\(FP\); chan int is 8-byte value"
+ MOVW m+24(FP), R1 // ERROR "invalid MOVW of m\+24\(FP\); map\[int\]int is 8-byte value"
+ MOVW f+32(FP), R1 // ERROR "invalid MOVW of f\+32\(FP\); func\(\) is 8-byte value"
+ RET
+
+TEXT ·argstring(SB),0,$32 // ERROR "wrong argument size 0; expected \$\.\.\.-32"
+ MOVH x+0(FP), R1 // ERROR "invalid MOVH of x\+0\(FP\); string base is 8-byte value"
+ MOVW x+0(FP), R1 // ERROR "invalid MOVW of x\+0\(FP\); string base is 8-byte value"
+ MOVD x+0(FP), R1
+ MOVH x_base+0(FP), R1 // ERROR "invalid MOVH of x_base\+0\(FP\); string base is 8-byte value"
+ MOVW x_base+0(FP), R1 // ERROR "invalid MOVW of x_base\+0\(FP\); string base is 8-byte value"
+ MOVD x_base+0(FP), R1
+ MOVH x_len+0(FP), R1 // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)"
+ MOVW x_len+0(FP), R1 // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)"
+ MOVD x_len+0(FP), R1 // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)"
+ MOVH x_len+8(FP), R1 // ERROR "invalid MOVH of x_len\+8\(FP\); string len is 8-byte value"
+ MOVW x_len+8(FP), R1 // ERROR "invalid MOVW of x_len\+8\(FP\); string len is 8-byte value"
+ MOVD x_len+8(FP), R1
+ MOVD y+0(FP), R1 // ERROR "invalid offset y\+0\(FP\); expected y\+16\(FP\)"
+ MOVD y_len+8(FP), R1 // ERROR "invalid offset y_len\+8\(FP\); expected y_len\+24\(FP\)"
+ RET
+
+TEXT ·argslice(SB),0,$48 // ERROR "wrong argument size 0; expected \$\.\.\.-48"
+ MOVH x+0(FP), R1 // ERROR "invalid MOVH of x\+0\(FP\); slice base is 8-byte value"
+ MOVW x+0(FP), R1 // ERROR "invalid MOVW of x\+0\(FP\); slice base is 8-byte value"
+ MOVD x+0(FP), R1
+ MOVH x_base+0(FP), R1 // ERROR "invalid MOVH of x_base\+0\(FP\); slice base is 8-byte value"
+ MOVW x_base+0(FP), R1 // ERROR "invalid MOVW of x_base\+0\(FP\); slice base is 8-byte value"
+ MOVD x_base+0(FP), R1
+ MOVH x_len+0(FP), R1 // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)"
+ MOVW x_len+0(FP), R1 // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)"
+ MOVD x_len+0(FP), R1 // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)"
+ MOVH x_len+8(FP), R1 // ERROR "invalid MOVH of x_len\+8\(FP\); slice len is 8-byte value"
+ MOVW x_len+8(FP), R1 // ERROR "invalid MOVW of x_len\+8\(FP\); slice len is 8-byte value"
+ MOVD x_len+8(FP), R1
+ MOVH x_cap+0(FP), R1 // ERROR "invalid offset x_cap\+0\(FP\); expected x_cap\+16\(FP\)"
+ MOVW x_cap+0(FP), R1 // ERROR "invalid offset x_cap\+0\(FP\); expected x_cap\+16\(FP\)"
+ MOVD x_cap+0(FP), R1 // ERROR "invalid offset x_cap\+0\(FP\); expected x_cap\+16\(FP\)"
+ MOVH x_cap+16(FP), R1 // ERROR "invalid MOVH of x_cap\+16\(FP\); slice cap is 8-byte value"
+ MOVW x_cap+16(FP), R1 // ERROR "invalid MOVW of x_cap\+16\(FP\); slice cap is 8-byte value"
+ MOVD x_cap+16(FP), R1
+ MOVD y+0(FP), R1 // ERROR "invalid offset y\+0\(FP\); expected y\+24\(FP\)"
+ MOVD y_len+8(FP), R1 // ERROR "invalid offset y_len\+8\(FP\); expected y_len\+32\(FP\)"
+ MOVD y_cap+16(FP), R1 // ERROR "invalid offset y_cap\+16\(FP\); expected y_cap\+40\(FP\)"
+ RET
+
+TEXT ·argiface(SB),0,$0-32
+ MOVH x+0(FP), R1 // ERROR "invalid MOVH of x\+0\(FP\); interface type is 8-byte value"
+ MOVW x+0(FP), R1 // ERROR "invalid MOVW of x\+0\(FP\); interface type is 8-byte value"
+ MOVD x+0(FP), R1
+ MOVH x_type+0(FP), R1 // ERROR "invalid MOVH of x_type\+0\(FP\); interface type is 8-byte value"
+ MOVW x_type+0(FP), R1 // ERROR "invalid MOVW of x_type\+0\(FP\); interface type is 8-byte value"
+ MOVD x_type+0(FP), R1
+ MOVD x_itable+0(FP), R1 // ERROR "unknown variable x_itable; offset 0 is x_type\+0\(FP\)"
+ MOVD x_itable+1(FP), R1 // ERROR "unknown variable x_itable; offset 1 is x_type\+0\(FP\)"
+ MOVH x_data+0(FP), R1 // ERROR "invalid offset x_data\+0\(FP\); expected x_data\+8\(FP\)"
+ MOVW x_data+0(FP), R1 // ERROR "invalid offset x_data\+0\(FP\); expected x_data\+8\(FP\)"
+ MOVD x_data+0(FP), R1 // ERROR "invalid offset x_data\+0\(FP\); expected x_data\+8\(FP\)"
+ MOVH x_data+8(FP), R1 // ERROR "invalid MOVH of x_data\+8\(FP\); interface data is 8-byte value"
+ MOVW x_data+8(FP), R1 // ERROR "invalid MOVW of x_data\+8\(FP\); interface data is 8-byte value"
+ MOVD x_data+8(FP), R1
+ MOVH y+16(FP), R1 // ERROR "invalid MOVH of y\+16\(FP\); interface itable is 8-byte value"
+ MOVW y+16(FP), R1 // ERROR "invalid MOVW of y\+16\(FP\); interface itable is 8-byte value"
+ MOVD y+16(FP), R1
+ MOVH y_itable+16(FP), R1 // ERROR "invalid MOVH of y_itable\+16\(FP\); interface itable is 8-byte value"
+ MOVW y_itable+16(FP), R1 // ERROR "invalid MOVW of y_itable\+16\(FP\); interface itable is 8-byte value"
+ MOVD y_itable+16(FP), R1
+ MOVD y_type+16(FP), R1 // ERROR "unknown variable y_type; offset 16 is y_itable\+16\(FP\)"
+ MOVH y_data+16(FP), R1 // ERROR "invalid offset y_data\+16\(FP\); expected y_data\+24\(FP\)"
+ MOVW y_data+16(FP), R1 // ERROR "invalid offset y_data\+16\(FP\); expected y_data\+24\(FP\)"
+ MOVD y_data+16(FP), R1 // ERROR "invalid offset y_data\+16\(FP\); expected y_data\+24\(FP\)"
+ MOVH y_data+24(FP), R1 // ERROR "invalid MOVH of y_data\+24\(FP\); interface data is 8-byte value"
+ MOVW y_data+24(FP), R1 // ERROR "invalid MOVW of y_data\+24\(FP\); interface data is 8-byte value"
+ MOVD y_data+24(FP), R1
+ RET
+
+TEXT ·returnint(SB),0,$0-8
+ MOVB R1, ret+0(FP) // ERROR "invalid MOVB of ret\+0\(FP\); int is 8-byte value"
+ MOVH R1, ret+0(FP) // ERROR "invalid MOVH of ret\+0\(FP\); int is 8-byte value"
+ MOVW R1, ret+0(FP) // ERROR "invalid MOVW of ret\+0\(FP\); int is 8-byte value"
+ MOVD R1, ret+0(FP)
+ MOVD R1, ret+1(FP) // ERROR "invalid offset ret\+1\(FP\); expected ret\+0\(FP\)"
+ MOVD R1, r+0(FP) // ERROR "unknown variable r; offset 0 is ret\+0\(FP\)"
+ RET
+
+TEXT ·returnbyte(SB),0,$0-9
+ MOVD x+0(FP), R1
+ MOVB R1, ret+8(FP)
+ MOVH R1, ret+8(FP) // ERROR "invalid MOVH of ret\+8\(FP\); byte is 1-byte value"
+ MOVW R1, ret+8(FP) // ERROR "invalid MOVW of ret\+8\(FP\); byte is 1-byte value"
+ MOVD R1, ret+8(FP) // ERROR "invalid MOVD of ret\+8\(FP\); byte is 1-byte value"
+ MOVB R1, ret+7(FP) // ERROR "invalid offset ret\+7\(FP\); expected ret\+8\(FP\)"
+ RET
+
+TEXT ·returnnamed(SB),0,$0-41
+ MOVB x+0(FP), R1
+ MOVD R1, r1+8(FP)
+ MOVH R1, r2+16(FP)
+ MOVD R1, r3+24(FP)
+ MOVD R1, r3_base+24(FP)
+ MOVD R1, r3_len+32(FP)
+ MOVB R1, r4+40(FP)
+ MOVW R1, r1+8(FP) // ERROR "invalid MOVW of r1\+8\(FP\); int is 8-byte value"
+ RET
+
+TEXT ·returnintmissing(SB),0,$0-8
+ RET // ERROR "RET without writing to 8-byte ret\+0\(FP\)"
diff --git a/src/cmd/vet/testdata/asm/asm7.s b/src/cmd/vet/testdata/asm/asm7.s
new file mode 100644
index 0000000..d5ff546
--- /dev/null
+++ b/src/cmd/vet/testdata/asm/asm7.s
@@ -0,0 +1,193 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build ppc64 ppc64le
+// +build vet_test
+
+TEXT ·arg1(SB),0,$0-2
+ MOVB x+0(FP), R3
+ MOVBZ y+1(FP), R4
+ MOVH x+0(FP), R3 // ERROR "\[(ppc64|ppc64le)\] arg1: invalid MOVH of x\+0\(FP\); int8 is 1-byte value"
+ MOVHZ y+1(FP), R3 // ERROR "invalid MOVHZ of y\+1\(FP\); uint8 is 1-byte value"
+ MOVW x+0(FP), R3 // ERROR "invalid MOVW of x\+0\(FP\); int8 is 1-byte value"
+ MOVWZ y+1(FP), R3 // ERROR "invalid MOVWZ of y\+1\(FP\); uint8 is 1-byte value"
+ MOVD x+0(FP), R3 // ERROR "invalid MOVD of x\+0\(FP\); int8 is 1-byte value"
+ MOVD y+1(FP), R3 // ERROR "invalid MOVD of y\+1\(FP\); uint8 is 1-byte value"
+ MOVB x+1(FP), R3 // ERROR "invalid offset x\+1\(FP\); expected x\+0\(FP\)"
+ MOVBZ y+2(FP), R3 // ERROR "invalid offset y\+2\(FP\); expected y\+1\(FP\)"
+ MOVB 16(R1), R3 // ERROR "16\(R1\) should be x\+0\(FP\)"
+ MOVB 17(R1), R3 // ERROR "17\(R1\) should be y\+1\(FP\)"
+ MOVB 18(R1), R3 // ERROR "use of 18\(R1\) points beyond argument frame"
+ RET
+
+TEXT ·arg2(SB),0,$0-4
+ MOVBZ x+0(FP), R3 // ERROR "arg2: invalid MOVBZ of x\+0\(FP\); int16 is 2-byte value"
+ MOVB y+2(FP), R3 // ERROR "invalid MOVB of y\+2\(FP\); uint16 is 2-byte value"
+ MOVHZ x+0(FP), R3
+ MOVH y+2(FP), R4
+ MOVWZ x+0(FP), R3 // ERROR "invalid MOVWZ of x\+0\(FP\); int16 is 2-byte value"
+ MOVW y+2(FP), R3 // ERROR "invalid MOVW of y\+2\(FP\); uint16 is 2-byte value"
+ MOVD x+0(FP), R3 // ERROR "invalid MOVD of x\+0\(FP\); int16 is 2-byte value"
+ MOVD y+2(FP), R3 // ERROR "invalid MOVD of y\+2\(FP\); uint16 is 2-byte value"
+ MOVHZ x+2(FP), R3 // ERROR "invalid offset x\+2\(FP\); expected x\+0\(FP\)"
+ MOVH y+0(FP), R3 // ERROR "invalid offset y\+0\(FP\); expected y\+2\(FP\)"
+ RET
+
+TEXT ·arg4(SB),0,$0-2 // ERROR "arg4: wrong argument size 2; expected \$\.\.\.-8"
+ MOVB x+0(FP), R3 // ERROR "invalid MOVB of x\+0\(FP\); int32 is 4-byte value"
+ MOVB y+4(FP), R4 // ERROR "invalid MOVB of y\+4\(FP\); uint32 is 4-byte value"
+ MOVH x+0(FP), R3 // ERROR "invalid MOVH of x\+0\(FP\); int32 is 4-byte value"
+ MOVH y+4(FP), R3 // ERROR "invalid MOVH of y\+4\(FP\); uint32 is 4-byte value"
+ MOVW x+0(FP), R3
+ MOVW y+4(FP), R3
+ MOVD x+0(FP), R3 // ERROR "invalid MOVD of x\+0\(FP\); int32 is 4-byte value"
+ MOVD y+4(FP), R3 // ERROR "invalid MOVD of y\+4\(FP\); uint32 is 4-byte value"
+ MOVW x+4(FP), R3 // ERROR "invalid offset x\+4\(FP\); expected x\+0\(FP\)"
+ MOVW y+2(FP), R3 // ERROR "invalid offset y\+2\(FP\); expected y\+4\(FP\)"
+ RET
+
+TEXT ·arg8(SB),7,$0-2 // ERROR "wrong argument size 2; expected \$\.\.\.-16"
+ MOVB x+0(FP), R3 // ERROR "invalid MOVB of x\+0\(FP\); int64 is 8-byte value"
+ MOVB y+8(FP), R4 // ERROR "invalid MOVB of y\+8\(FP\); uint64 is 8-byte value"
+ MOVH x+0(FP), R3 // ERROR "invalid MOVH of x\+0\(FP\); int64 is 8-byte value"
+ MOVH y+8(FP), R3 // ERROR "invalid MOVH of y\+8\(FP\); uint64 is 8-byte value"
+ MOVW x+0(FP), R3 // ERROR "invalid MOVW of x\+0\(FP\); int64 is 8-byte value"
+ MOVW y+8(FP), R3 // ERROR "invalid MOVW of y\+8\(FP\); uint64 is 8-byte value"
+ MOVD x+0(FP), R3
+ MOVD y+8(FP), R3
+ MOVD x+8(FP), R3 // ERROR "invalid offset x\+8\(FP\); expected x\+0\(FP\)"
+ MOVD y+2(FP), R3 // ERROR "invalid offset y\+2\(FP\); expected y\+8\(FP\)"
+ RET
+
+TEXT ·argint(SB),0,$0-2 // ERROR "wrong argument size 2; expected \$\.\.\.-16"
+ MOVB x+0(FP), R3 // ERROR "invalid MOVB of x\+0\(FP\); int is 8-byte value"
+ MOVB y+8(FP), R4 // ERROR "invalid MOVB of y\+8\(FP\); uint is 8-byte value"
+ MOVH x+0(FP), R3 // ERROR "invalid MOVH of x\+0\(FP\); int is 8-byte value"
+ MOVH y+8(FP), R3 // ERROR "invalid MOVH of y\+8\(FP\); uint is 8-byte value"
+ MOVW x+0(FP), R3 // ERROR "invalid MOVW of x\+0\(FP\); int is 8-byte value"
+ MOVW y+8(FP), R3 // ERROR "invalid MOVW of y\+8\(FP\); uint is 8-byte value"
+ MOVD x+0(FP), R3
+ MOVD y+8(FP), R3
+ MOVD x+8(FP), R3 // ERROR "invalid offset x\+8\(FP\); expected x\+0\(FP\)"
+ MOVD y+2(FP), R3 // ERROR "invalid offset y\+2\(FP\); expected y\+8\(FP\)"
+ RET
+
+TEXT ·argptr(SB),7,$0-2 // ERROR "wrong argument size 2; expected \$\.\.\.-40"
+ MOVB x+0(FP), R3 // ERROR "invalid MOVB of x\+0\(FP\); \*byte is 8-byte value"
+ MOVB y+8(FP), R4 // ERROR "invalid MOVB of y\+8\(FP\); \*byte is 8-byte value"
+ MOVH x+0(FP), R3 // ERROR "invalid MOVH of x\+0\(FP\); \*byte is 8-byte value"
+ MOVH y+8(FP), R3 // ERROR "invalid MOVH of y\+8\(FP\); \*byte is 8-byte value"
+ MOVW x+0(FP), R3 // ERROR "invalid MOVW of x\+0\(FP\); \*byte is 8-byte value"
+ MOVW y+8(FP), R3 // ERROR "invalid MOVW of y\+8\(FP\); \*byte is 8-byte value"
+ MOVD x+0(FP), R3
+ MOVD y+8(FP), R3
+ MOVD x+8(FP), R3 // ERROR "invalid offset x\+8\(FP\); expected x\+0\(FP\)"
+ MOVD y+2(FP), R3 // ERROR "invalid offset y\+2\(FP\); expected y\+8\(FP\)"
+ MOVW c+16(FP), R3 // ERROR "invalid MOVW of c\+16\(FP\); chan int is 8-byte value"
+ MOVW m+24(FP), R3 // ERROR "invalid MOVW of m\+24\(FP\); map\[int\]int is 8-byte value"
+ MOVW f+32(FP), R3 // ERROR "invalid MOVW of f\+32\(FP\); func\(\) is 8-byte value"
+ RET
+
+TEXT ·argstring(SB),0,$32 // ERROR "wrong argument size 0; expected \$\.\.\.-32"
+ MOVH x+0(FP), R3 // ERROR "invalid MOVH of x\+0\(FP\); string base is 8-byte value"
+ MOVW x+0(FP), R3 // ERROR "invalid MOVW of x\+0\(FP\); string base is 8-byte value"
+ MOVD x+0(FP), R3
+ MOVH x_base+0(FP), R3 // ERROR "invalid MOVH of x_base\+0\(FP\); string base is 8-byte value"
+ MOVW x_base+0(FP), R3 // ERROR "invalid MOVW of x_base\+0\(FP\); string base is 8-byte value"
+ MOVD x_base+0(FP), R3
+ MOVH x_len+0(FP), R3 // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)"
+ MOVW x_len+0(FP), R3 // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)"
+ MOVD x_len+0(FP), R3 // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)"
+ MOVH x_len+8(FP), R3 // ERROR "invalid MOVH of x_len\+8\(FP\); string len is 8-byte value"
+ MOVW x_len+8(FP), R3 // ERROR "invalid MOVW of x_len\+8\(FP\); string len is 8-byte value"
+ MOVD x_len+8(FP), R3
+ MOVD y+0(FP), R3 // ERROR "invalid offset y\+0\(FP\); expected y\+16\(FP\)"
+ MOVD y_len+8(FP), R3 // ERROR "invalid offset y_len\+8\(FP\); expected y_len\+24\(FP\)"
+ RET
+
+TEXT ·argslice(SB),0,$48 // ERROR "wrong argument size 0; expected \$\.\.\.-48"
+ MOVH x+0(FP), R3 // ERROR "invalid MOVH of x\+0\(FP\); slice base is 8-byte value"
+ MOVW x+0(FP), R3 // ERROR "invalid MOVW of x\+0\(FP\); slice base is 8-byte value"
+ MOVD x+0(FP), R3
+ MOVH x_base+0(FP), R3 // ERROR "invalid MOVH of x_base\+0\(FP\); slice base is 8-byte value"
+ MOVW x_base+0(FP), R3 // ERROR "invalid MOVW of x_base\+0\(FP\); slice base is 8-byte value"
+ MOVD x_base+0(FP), R3
+ MOVH x_len+0(FP), R3 // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)"
+ MOVW x_len+0(FP), R3 // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)"
+ MOVD x_len+0(FP), R3 // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)"
+ MOVH x_len+8(FP), R3 // ERROR "invalid MOVH of x_len\+8\(FP\); slice len is 8-byte value"
+ MOVW x_len+8(FP), R3 // ERROR "invalid MOVW of x_len\+8\(FP\); slice len is 8-byte value"
+ MOVD x_len+8(FP), R3
+ MOVH x_cap+0(FP), R3 // ERROR "invalid offset x_cap\+0\(FP\); expected x_cap\+16\(FP\)"
+ MOVW x_cap+0(FP), R3 // ERROR "invalid offset x_cap\+0\(FP\); expected x_cap\+16\(FP\)"
+ MOVD x_cap+0(FP), R3 // ERROR "invalid offset x_cap\+0\(FP\); expected x_cap\+16\(FP\)"
+ MOVH x_cap+16(FP), R3 // ERROR "invalid MOVH of x_cap\+16\(FP\); slice cap is 8-byte value"
+ MOVW x_cap+16(FP), R3 // ERROR "invalid MOVW of x_cap\+16\(FP\); slice cap is 8-byte value"
+ MOVD x_cap+16(FP), R3
+ MOVD y+0(FP), R3 // ERROR "invalid offset y\+0\(FP\); expected y\+24\(FP\)"
+ MOVD y_len+8(FP), R3 // ERROR "invalid offset y_len\+8\(FP\); expected y_len\+32\(FP\)"
+ MOVD y_cap+16(FP), R3 // ERROR "invalid offset y_cap\+16\(FP\); expected y_cap\+40\(FP\)"
+ RET
+
+TEXT ·argiface(SB),0,$0-32
+ MOVH x+0(FP), R3 // ERROR "invalid MOVH of x\+0\(FP\); interface type is 8-byte value"
+ MOVW x+0(FP), R3 // ERROR "invalid MOVW of x\+0\(FP\); interface type is 8-byte value"
+ MOVD x+0(FP), R3
+ MOVH x_type+0(FP), R3 // ERROR "invalid MOVH of x_type\+0\(FP\); interface type is 8-byte value"
+ MOVW x_type+0(FP), R3 // ERROR "invalid MOVW of x_type\+0\(FP\); interface type is 8-byte value"
+ MOVD x_type+0(FP), R3
+ MOVD x_itable+0(FP), R3 // ERROR "unknown variable x_itable; offset 0 is x_type\+0\(FP\)"
+ MOVD x_itable+1(FP), R3 // ERROR "unknown variable x_itable; offset 1 is x_type\+0\(FP\)"
+ MOVH x_data+0(FP), R3 // ERROR "invalid offset x_data\+0\(FP\); expected x_data\+8\(FP\)"
+ MOVW x_data+0(FP), R3 // ERROR "invalid offset x_data\+0\(FP\); expected x_data\+8\(FP\)"
+ MOVD x_data+0(FP), R3 // ERROR "invalid offset x_data\+0\(FP\); expected x_data\+8\(FP\)"
+ MOVH x_data+8(FP), R3 // ERROR "invalid MOVH of x_data\+8\(FP\); interface data is 8-byte value"
+ MOVW x_data+8(FP), R3 // ERROR "invalid MOVW of x_data\+8\(FP\); interface data is 8-byte value"
+ MOVD x_data+8(FP), R3
+ MOVH y+16(FP), R3 // ERROR "invalid MOVH of y\+16\(FP\); interface itable is 8-byte value"
+ MOVW y+16(FP), R3 // ERROR "invalid MOVW of y\+16\(FP\); interface itable is 8-byte value"
+ MOVD y+16(FP), R3
+ MOVH y_itable+16(FP), R3 // ERROR "invalid MOVH of y_itable\+16\(FP\); interface itable is 8-byte value"
+ MOVW y_itable+16(FP), R3 // ERROR "invalid MOVW of y_itable\+16\(FP\); interface itable is 8-byte value"
+ MOVD y_itable+16(FP), R3
+ MOVD y_type+16(FP), R3 // ERROR "unknown variable y_type; offset 16 is y_itable\+16\(FP\)"
+ MOVH y_data+16(FP), R3 // ERROR "invalid offset y_data\+16\(FP\); expected y_data\+24\(FP\)"
+ MOVW y_data+16(FP), R3 // ERROR "invalid offset y_data\+16\(FP\); expected y_data\+24\(FP\)"
+ MOVD y_data+16(FP), R3 // ERROR "invalid offset y_data\+16\(FP\); expected y_data\+24\(FP\)"
+ MOVH y_data+24(FP), R3 // ERROR "invalid MOVH of y_data\+24\(FP\); interface data is 8-byte value"
+ MOVW y_data+24(FP), R3 // ERROR "invalid MOVW of y_data\+24\(FP\); interface data is 8-byte value"
+ MOVD y_data+24(FP), R3
+ RET
+
+TEXT ·returnint(SB),0,$0-8
+ MOVB R3, ret+0(FP) // ERROR "invalid MOVB of ret\+0\(FP\); int is 8-byte value"
+ MOVH R3, ret+0(FP) // ERROR "invalid MOVH of ret\+0\(FP\); int is 8-byte value"
+ MOVW R3, ret+0(FP) // ERROR "invalid MOVW of ret\+0\(FP\); int is 8-byte value"
+ MOVD R3, ret+0(FP)
+ MOVD R3, ret+1(FP) // ERROR "invalid offset ret\+1\(FP\); expected ret\+0\(FP\)"
+ MOVD R3, r+0(FP) // ERROR "unknown variable r; offset 0 is ret\+0\(FP\)"
+ RET
+
+TEXT ·returnbyte(SB),0,$0-9
+ MOVD x+0(FP), R3
+ MOVB R3, ret+8(FP)
+ MOVH R3, ret+8(FP) // ERROR "invalid MOVH of ret\+8\(FP\); byte is 1-byte value"
+ MOVW R3, ret+8(FP) // ERROR "invalid MOVW of ret\+8\(FP\); byte is 1-byte value"
+ MOVD R3, ret+8(FP) // ERROR "invalid MOVD of ret\+8\(FP\); byte is 1-byte value"
+ MOVB R3, ret+7(FP) // ERROR "invalid offset ret\+7\(FP\); expected ret\+8\(FP\)"
+ RET
+
+TEXT ·returnnamed(SB),0,$0-41
+ MOVB x+0(FP), R3
+ MOVD R3, r1+8(FP)
+ MOVH R3, r2+16(FP)
+ MOVD R3, r3+24(FP)
+ MOVD R3, r3_base+24(FP)
+ MOVD R3, r3_len+32(FP)
+ MOVB R3, r4+40(FP)
+ MOVW R3, r1+8(FP) // ERROR "invalid MOVW of r1\+8\(FP\); int is 8-byte value"
+ RET
+
+TEXT ·returnintmissing(SB),0,$0-8
+ RET // ERROR "RET without writing to 8-byte ret\+0\(FP\)"
diff --git a/src/cmd/vet/testdata/asm1.s b/src/cmd/vet/testdata/asm1.s
deleted file mode 100644
index 2c6f13b..0000000
--- a/src/cmd/vet/testdata/asm1.s
+++ /dev/null
@@ -1,265 +0,0 @@
-// Copyright 2013 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build amd64
-// +build vet_test
-
-TEXT ·arg1(SB),0,$0-2
- MOVB x+0(FP), AX
- // MOVB x+0(FP), AX // commented out instructions used to panic
- MOVB y+1(FP), BX
- MOVW x+0(FP), AX // ERROR "\[amd64\] arg1: invalid MOVW of x\+0\(FP\); int8 is 1-byte value"
- MOVW y+1(FP), AX // ERROR "invalid MOVW of y\+1\(FP\); uint8 is 1-byte value"
- MOVL x+0(FP), AX // ERROR "invalid MOVL of x\+0\(FP\); int8 is 1-byte value"
- MOVL y+1(FP), AX // ERROR "invalid MOVL of y\+1\(FP\); uint8 is 1-byte value"
- MOVQ x+0(FP), AX // ERROR "invalid MOVQ of x\+0\(FP\); int8 is 1-byte value"
- MOVQ y+1(FP), AX // ERROR "invalid MOVQ of y\+1\(FP\); uint8 is 1-byte value"
- MOVB x+1(FP), AX // ERROR "invalid offset x\+1\(FP\); expected x\+0\(FP\)"
- MOVB y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+1\(FP\)"
- TESTB x+0(FP), AX
- TESTB y+1(FP), BX
- TESTW x+0(FP), AX // ERROR "invalid TESTW of x\+0\(FP\); int8 is 1-byte value"
- TESTW y+1(FP), AX // ERROR "invalid TESTW of y\+1\(FP\); uint8 is 1-byte value"
- TESTL x+0(FP), AX // ERROR "invalid TESTL of x\+0\(FP\); int8 is 1-byte value"
- TESTL y+1(FP), AX // ERROR "invalid TESTL of y\+1\(FP\); uint8 is 1-byte value"
- TESTQ x+0(FP), AX // ERROR "invalid TESTQ of x\+0\(FP\); int8 is 1-byte value"
- TESTQ y+1(FP), AX // ERROR "invalid TESTQ of y\+1\(FP\); uint8 is 1-byte value"
- TESTB x+1(FP), AX // ERROR "invalid offset x\+1\(FP\); expected x\+0\(FP\)"
- TESTB y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+1\(FP\)"
- MOVB 8(SP), AX // ERROR "8\(SP\) should be x\+0\(FP\)"
- MOVB 9(SP), AX // ERROR "9\(SP\) should be y\+1\(FP\)"
- MOVB 10(SP), AX // ERROR "use of 10\(SP\) points beyond argument frame"
- RET
-
-TEXT ·arg2(SB),0,$0-4
- MOVB x+0(FP), AX // ERROR "arg2: invalid MOVB of x\+0\(FP\); int16 is 2-byte value"
- MOVB y+2(FP), AX // ERROR "invalid MOVB of y\+2\(FP\); uint16 is 2-byte value"
- MOVW x+0(FP), AX
- MOVW y+2(FP), BX
- MOVL x+0(FP), AX // ERROR "invalid MOVL of x\+0\(FP\); int16 is 2-byte value"
- MOVL y+2(FP), AX // ERROR "invalid MOVL of y\+2\(FP\); uint16 is 2-byte value"
- MOVQ x+0(FP), AX // ERROR "invalid MOVQ of x\+0\(FP\); int16 is 2-byte value"
- MOVQ y+2(FP), AX // ERROR "invalid MOVQ of y\+2\(FP\); uint16 is 2-byte value"
- MOVW x+2(FP), AX // ERROR "invalid offset x\+2\(FP\); expected x\+0\(FP\)"
- MOVW y+0(FP), AX // ERROR "invalid offset y\+0\(FP\); expected y\+2\(FP\)"
- TESTB x+0(FP), AX // ERROR "invalid TESTB of x\+0\(FP\); int16 is 2-byte value"
- TESTB y+2(FP), AX // ERROR "invalid TESTB of y\+2\(FP\); uint16 is 2-byte value"
- TESTW x+0(FP), AX
- TESTW y+2(FP), BX
- TESTL x+0(FP), AX // ERROR "invalid TESTL of x\+0\(FP\); int16 is 2-byte value"
- TESTL y+2(FP), AX // ERROR "invalid TESTL of y\+2\(FP\); uint16 is 2-byte value"
- TESTQ x+0(FP), AX // ERROR "invalid TESTQ of x\+0\(FP\); int16 is 2-byte value"
- TESTQ y+2(FP), AX // ERROR "invalid TESTQ of y\+2\(FP\); uint16 is 2-byte value"
- TESTW x+2(FP), AX // ERROR "invalid offset x\+2\(FP\); expected x\+0\(FP\)"
- TESTW y+0(FP), AX // ERROR "invalid offset y\+0\(FP\); expected y\+2\(FP\)"
- RET
-
-TEXT ·arg4(SB),0,$0-2 // ERROR "arg4: wrong argument size 2; expected \$\.\.\.-8"
- MOVB x+0(FP), AX // ERROR "invalid MOVB of x\+0\(FP\); int32 is 4-byte value"
- MOVB y+4(FP), BX // ERROR "invalid MOVB of y\+4\(FP\); uint32 is 4-byte value"
- MOVW x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); int32 is 4-byte value"
- MOVW y+4(FP), AX // ERROR "invalid MOVW of y\+4\(FP\); uint32 is 4-byte value"
- MOVL x+0(FP), AX
- MOVL y+4(FP), AX
- MOVQ x+0(FP), AX // ERROR "invalid MOVQ of x\+0\(FP\); int32 is 4-byte value"
- MOVQ y+4(FP), AX // ERROR "invalid MOVQ of y\+4\(FP\); uint32 is 4-byte value"
- MOVL x+4(FP), AX // ERROR "invalid offset x\+4\(FP\); expected x\+0\(FP\)"
- MOVL y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+4\(FP\)"
- TESTB x+0(FP), AX // ERROR "invalid TESTB of x\+0\(FP\); int32 is 4-byte value"
- TESTB y+4(FP), BX // ERROR "invalid TESTB of y\+4\(FP\); uint32 is 4-byte value"
- TESTW x+0(FP), AX // ERROR "invalid TESTW of x\+0\(FP\); int32 is 4-byte value"
- TESTW y+4(FP), AX // ERROR "invalid TESTW of y\+4\(FP\); uint32 is 4-byte value"
- TESTL x+0(FP), AX
- TESTL y+4(FP), AX
- TESTQ x+0(FP), AX // ERROR "invalid TESTQ of x\+0\(FP\); int32 is 4-byte value"
- TESTQ y+4(FP), AX // ERROR "invalid TESTQ of y\+4\(FP\); uint32 is 4-byte value"
- TESTL x+4(FP), AX // ERROR "invalid offset x\+4\(FP\); expected x\+0\(FP\)"
- TESTL y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+4\(FP\)"
- RET
-
-TEXT ·arg8(SB),7,$0-2 // ERROR "wrong argument size 2; expected \$\.\.\.-16"
- MOVB x+0(FP), AX // ERROR "invalid MOVB of x\+0\(FP\); int64 is 8-byte value"
- MOVB y+8(FP), BX // ERROR "invalid MOVB of y\+8\(FP\); uint64 is 8-byte value"
- MOVW x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); int64 is 8-byte value"
- MOVW y+8(FP), AX // ERROR "invalid MOVW of y\+8\(FP\); uint64 is 8-byte value"
- MOVL x+0(FP), AX // ERROR "invalid MOVL of x\+0\(FP\); int64 is 8-byte value"
- MOVL y+8(FP), AX // ERROR "invalid MOVL of y\+8\(FP\); uint64 is 8-byte value"
- MOVQ x+0(FP), AX
- MOVQ y+8(FP), AX
- MOVQ x+8(FP), AX // ERROR "invalid offset x\+8\(FP\); expected x\+0\(FP\)"
- MOVQ y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+8\(FP\)"
- TESTB x+0(FP), AX // ERROR "invalid TESTB of x\+0\(FP\); int64 is 8-byte value"
- TESTB y+8(FP), BX // ERROR "invalid TESTB of y\+8\(FP\); uint64 is 8-byte value"
- TESTW x+0(FP), AX // ERROR "invalid TESTW of x\+0\(FP\); int64 is 8-byte value"
- TESTW y+8(FP), AX // ERROR "invalid TESTW of y\+8\(FP\); uint64 is 8-byte value"
- TESTL x+0(FP), AX // ERROR "invalid TESTL of x\+0\(FP\); int64 is 8-byte value"
- TESTL y+8(FP), AX // ERROR "invalid TESTL of y\+8\(FP\); uint64 is 8-byte value"
- TESTQ x+0(FP), AX
- TESTQ y+8(FP), AX
- TESTQ x+8(FP), AX // ERROR "invalid offset x\+8\(FP\); expected x\+0\(FP\)"
- TESTQ y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+8\(FP\)"
- RET
-
-TEXT ·argint(SB),0,$0-2 // ERROR "wrong argument size 2; expected \$\.\.\.-16"
- MOVB x+0(FP), AX // ERROR "invalid MOVB of x\+0\(FP\); int is 8-byte value"
- MOVB y+8(FP), BX // ERROR "invalid MOVB of y\+8\(FP\); uint is 8-byte value"
- MOVW x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); int is 8-byte value"
- MOVW y+8(FP), AX // ERROR "invalid MOVW of y\+8\(FP\); uint is 8-byte value"
- MOVL x+0(FP), AX // ERROR "invalid MOVL of x\+0\(FP\); int is 8-byte value"
- MOVL y+8(FP), AX // ERROR "invalid MOVL of y\+8\(FP\); uint is 8-byte value"
- MOVQ x+0(FP), AX
- MOVQ y+8(FP), AX
- MOVQ x+8(FP), AX // ERROR "invalid offset x\+8\(FP\); expected x\+0\(FP\)"
- MOVQ y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+8\(FP\)"
- TESTB x+0(FP), AX // ERROR "invalid TESTB of x\+0\(FP\); int is 8-byte value"
- TESTB y+8(FP), BX // ERROR "invalid TESTB of y\+8\(FP\); uint is 8-byte value"
- TESTW x+0(FP), AX // ERROR "invalid TESTW of x\+0\(FP\); int is 8-byte value"
- TESTW y+8(FP), AX // ERROR "invalid TESTW of y\+8\(FP\); uint is 8-byte value"
- TESTL x+0(FP), AX // ERROR "invalid TESTL of x\+0\(FP\); int is 8-byte value"
- TESTL y+8(FP), AX // ERROR "invalid TESTL of y\+8\(FP\); uint is 8-byte value"
- TESTQ x+0(FP), AX
- TESTQ y+8(FP), AX
- TESTQ x+8(FP), AX // ERROR "invalid offset x\+8\(FP\); expected x\+0\(FP\)"
- TESTQ y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+8\(FP\)"
- RET
-
-TEXT ·argptr(SB),7,$0-2 // ERROR "wrong argument size 2; expected \$\.\.\.-40"
- MOVB x+0(FP), AX // ERROR "invalid MOVB of x\+0\(FP\); \*byte is 8-byte value"
- MOVB y+8(FP), BX // ERROR "invalid MOVB of y\+8\(FP\); \*byte is 8-byte value"
- MOVW x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); \*byte is 8-byte value"
- MOVW y+8(FP), AX // ERROR "invalid MOVW of y\+8\(FP\); \*byte is 8-byte value"
- MOVL x+0(FP), AX // ERROR "invalid MOVL of x\+0\(FP\); \*byte is 8-byte value"
- MOVL y+8(FP), AX // ERROR "invalid MOVL of y\+8\(FP\); \*byte is 8-byte value"
- MOVQ x+0(FP), AX
- MOVQ y+8(FP), AX
- MOVQ x+8(FP), AX // ERROR "invalid offset x\+8\(FP\); expected x\+0\(FP\)"
- MOVQ y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+8\(FP\)"
- TESTB x+0(FP), AX // ERROR "invalid TESTB of x\+0\(FP\); \*byte is 8-byte value"
- TESTB y+8(FP), BX // ERROR "invalid TESTB of y\+8\(FP\); \*byte is 8-byte value"
- TESTW x+0(FP), AX // ERROR "invalid TESTW of x\+0\(FP\); \*byte is 8-byte value"
- TESTW y+8(FP), AX // ERROR "invalid TESTW of y\+8\(FP\); \*byte is 8-byte value"
- TESTL x+0(FP), AX // ERROR "invalid TESTL of x\+0\(FP\); \*byte is 8-byte value"
- TESTL y+8(FP), AX // ERROR "invalid TESTL of y\+8\(FP\); \*byte is 8-byte value"
- TESTQ x+0(FP), AX
- TESTQ y+8(FP), AX
- TESTQ x+8(FP), AX // ERROR "invalid offset x\+8\(FP\); expected x\+0\(FP\)"
- TESTQ y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+8\(FP\)"
- MOVL c+16(FP), AX // ERROR "invalid MOVL of c\+16\(FP\); chan int is 8-byte value"
- MOVL m+24(FP), AX // ERROR "invalid MOVL of m\+24\(FP\); map\[int\]int is 8-byte value"
- MOVL f+32(FP), AX // ERROR "invalid MOVL of f\+32\(FP\); func\(\) is 8-byte value"
- RET
-
-TEXT ·argstring(SB),0,$32 // ERROR "wrong argument size 0; expected \$\.\.\.-32"
- MOVW x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); string base is 8-byte value"
- MOVL x+0(FP), AX // ERROR "invalid MOVL of x\+0\(FP\); string base is 8-byte value"
- MOVQ x+0(FP), AX
- MOVW x_base+0(FP), AX // ERROR "invalid MOVW of x_base\+0\(FP\); string base is 8-byte value"
- MOVL x_base+0(FP), AX // ERROR "invalid MOVL of x_base\+0\(FP\); string base is 8-byte value"
- MOVQ x_base+0(FP), AX
- MOVW x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)"
- MOVL x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)"
- MOVQ x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)"
- MOVW x_len+8(FP), AX // ERROR "invalid MOVW of x_len\+8\(FP\); string len is 8-byte value"
- MOVL x_len+8(FP), AX // ERROR "invalid MOVL of x_len\+8\(FP\); string len is 8-byte value"
- MOVQ x_len+8(FP), AX
- MOVQ y+0(FP), AX // ERROR "invalid offset y\+0\(FP\); expected y\+16\(FP\)"
- MOVQ y_len+8(FP), AX // ERROR "invalid offset y_len\+8\(FP\); expected y_len\+24\(FP\)"
- RET
-
-TEXT ·argslice(SB),0,$48 // ERROR "wrong argument size 0; expected \$\.\.\.-48"
- MOVW x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); slice base is 8-byte value"
- MOVL x+0(FP), AX // ERROR "invalid MOVL of x\+0\(FP\); slice base is 8-byte value"
- MOVQ x+0(FP), AX
- MOVW x_base+0(FP), AX // ERROR "invalid MOVW of x_base\+0\(FP\); slice base is 8-byte value"
- MOVL x_base+0(FP), AX // ERROR "invalid MOVL of x_base\+0\(FP\); slice base is 8-byte value"
- MOVQ x_base+0(FP), AX
- MOVW x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)"
- MOVL x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)"
- MOVQ x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)"
- MOVW x_len+8(FP), AX // ERROR "invalid MOVW of x_len\+8\(FP\); slice len is 8-byte value"
- MOVL x_len+8(FP), AX // ERROR "invalid MOVL of x_len\+8\(FP\); slice len is 8-byte value"
- MOVQ x_len+8(FP), AX
- MOVW x_cap+0(FP), AX // ERROR "invalid offset x_cap\+0\(FP\); expected x_cap\+16\(FP\)"
- MOVL x_cap+0(FP), AX // ERROR "invalid offset x_cap\+0\(FP\); expected x_cap\+16\(FP\)"
- MOVQ x_cap+0(FP), AX // ERROR "invalid offset x_cap\+0\(FP\); expected x_cap\+16\(FP\)"
- MOVW x_cap+16(FP), AX // ERROR "invalid MOVW of x_cap\+16\(FP\); slice cap is 8-byte value"
- MOVL x_cap+16(FP), AX // ERROR "invalid MOVL of x_cap\+16\(FP\); slice cap is 8-byte value"
- MOVQ x_cap+16(FP), AX
- MOVQ y+0(FP), AX // ERROR "invalid offset y\+0\(FP\); expected y\+24\(FP\)"
- MOVQ y_len+8(FP), AX // ERROR "invalid offset y_len\+8\(FP\); expected y_len\+32\(FP\)"
- MOVQ y_cap+16(FP), AX // ERROR "invalid offset y_cap\+16\(FP\); expected y_cap\+40\(FP\)"
- RET
-
-TEXT ·argiface(SB),0,$0-32
- MOVW x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); interface type is 8-byte value"
- MOVL x+0(FP), AX // ERROR "invalid MOVL of x\+0\(FP\); interface type is 8-byte value"
- MOVQ x+0(FP), AX
- MOVW x_type+0(FP), AX // ERROR "invalid MOVW of x_type\+0\(FP\); interface type is 8-byte value"
- MOVL x_type+0(FP), AX // ERROR "invalid MOVL of x_type\+0\(FP\); interface type is 8-byte value"
- MOVQ x_type+0(FP), AX
- MOVQ x_itable+0(FP), AX // ERROR "unknown variable x_itable; offset 0 is x_type\+0\(FP\)"
- MOVQ x_itable+1(FP), AX // ERROR "unknown variable x_itable; offset 1 is x_type\+0\(FP\)"
- MOVW x_data+0(FP), AX // ERROR "invalid offset x_data\+0\(FP\); expected x_data\+8\(FP\)"
- MOVL x_data+0(FP), AX // ERROR "invalid offset x_data\+0\(FP\); expected x_data\+8\(FP\)"
- MOVQ x_data+0(FP), AX // ERROR "invalid offset x_data\+0\(FP\); expected x_data\+8\(FP\)"
- MOVW x_data+8(FP), AX // ERROR "invalid MOVW of x_data\+8\(FP\); interface data is 8-byte value"
- MOVL x_data+8(FP), AX // ERROR "invalid MOVL of x_data\+8\(FP\); interface data is 8-byte value"
- MOVQ x_data+8(FP), AX
- MOVW y+16(FP), AX // ERROR "invalid MOVW of y\+16\(FP\); interface itable is 8-byte value"
- MOVL y+16(FP), AX // ERROR "invalid MOVL of y\+16\(FP\); interface itable is 8-byte value"
- MOVQ y+16(FP), AX
- MOVW y_itable+16(FP), AX // ERROR "invalid MOVW of y_itable\+16\(FP\); interface itable is 8-byte value"
- MOVL y_itable+16(FP), AX // ERROR "invalid MOVL of y_itable\+16\(FP\); interface itable is 8-byte value"
- MOVQ y_itable+16(FP), AX
- MOVQ y_type+16(FP), AX // ERROR "unknown variable y_type; offset 16 is y_itable\+16\(FP\)"
- MOVW y_data+16(FP), AX // ERROR "invalid offset y_data\+16\(FP\); expected y_data\+24\(FP\)"
- MOVL y_data+16(FP), AX // ERROR "invalid offset y_data\+16\(FP\); expected y_data\+24\(FP\)"
- MOVQ y_data+16(FP), AX // ERROR "invalid offset y_data\+16\(FP\); expected y_data\+24\(FP\)"
- MOVW y_data+24(FP), AX // ERROR "invalid MOVW of y_data\+24\(FP\); interface data is 8-byte value"
- MOVL y_data+24(FP), AX // ERROR "invalid MOVL of y_data\+24\(FP\); interface data is 8-byte value"
- MOVQ y_data+24(FP), AX
- RET
-
-TEXT ·returnint(SB),0,$0-8
- MOVB AX, ret+0(FP) // ERROR "invalid MOVB of ret\+0\(FP\); int is 8-byte value"
- MOVW AX, ret+0(FP) // ERROR "invalid MOVW of ret\+0\(FP\); int is 8-byte value"
- MOVL AX, ret+0(FP) // ERROR "invalid MOVL of ret\+0\(FP\); int is 8-byte value"
- MOVQ AX, ret+0(FP)
- MOVQ AX, ret+1(FP) // ERROR "invalid offset ret\+1\(FP\); expected ret\+0\(FP\)"
- MOVQ AX, r+0(FP) // ERROR "unknown variable r; offset 0 is ret\+0\(FP\)"
- RET
-
-TEXT ·returnbyte(SB),0,$0-9
- MOVQ x+0(FP), AX
- MOVB AX, ret+8(FP)
- MOVW AX, ret+8(FP) // ERROR "invalid MOVW of ret\+8\(FP\); byte is 1-byte value"
- MOVL AX, ret+8(FP) // ERROR "invalid MOVL of ret\+8\(FP\); byte is 1-byte value"
- MOVQ AX, ret+8(FP) // ERROR "invalid MOVQ of ret\+8\(FP\); byte is 1-byte value"
- MOVB AX, ret+7(FP) // ERROR "invalid offset ret\+7\(FP\); expected ret\+8\(FP\)"
- RET
-
-TEXT ·returnnamed(SB),0,$0-41
- MOVB x+0(FP), AX
- MOVQ AX, r1+8(FP)
- MOVW AX, r2+16(FP)
- MOVQ AX, r3+24(FP)
- MOVQ AX, r3_base+24(FP)
- MOVQ AX, r3_len+32(FP)
- MOVB AX, r4+40(FP)
- MOVL AX, r1+8(FP) // ERROR "invalid MOVL of r1\+8\(FP\); int is 8-byte value"
- RET
-
-TEXT ·returnintmissing(SB),0,$0-8
- RET // ERROR "RET without writing to 8-byte ret\+0\(FP\)"
-
-
-// issue 15271
-TEXT ·f15271(SB), NOSPLIT, $0-4
- // Stick 123 into the low 32 bits of X0.
- MOVQ $123, AX
- PINSRD $0, AX, X0
-
- // Return them.
- PEXTRD $0, X0, x+0(FP)
- RET
diff --git a/src/cmd/vet/testdata/asm8.s b/src/cmd/vet/testdata/asm8.s
new file mode 100644
index 0000000..550d92a
--- /dev/null
+++ b/src/cmd/vet/testdata/asm8.s
@@ -0,0 +1,165 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build mipsle
+// +build vet_test
+
+TEXT ·arg1(SB),0,$0-2
+ MOVB x+0(FP), R1
+ MOVBU y+1(FP), R2
+ MOVH x+0(FP), R1 // ERROR "\[mipsle\] arg1: invalid MOVH of x\+0\(FP\); int8 is 1-byte value"
+ MOVHU y+1(FP), R1 // ERROR "invalid MOVHU of y\+1\(FP\); uint8 is 1-byte value"
+ MOVW x+0(FP), R1 // ERROR "invalid MOVW of x\+0\(FP\); int8 is 1-byte value"
+ MOVWU y+1(FP), R1 // ERROR "invalid MOVWU of y\+1\(FP\); uint8 is 1-byte value"
+ MOVW y+1(FP), R1 // ERROR "invalid MOVW of y\+1\(FP\); uint8 is 1-byte value"
+ MOVB x+1(FP), R1 // ERROR "invalid offset x\+1\(FP\); expected x\+0\(FP\)"
+ MOVBU y+2(FP), R1 // ERROR "invalid offset y\+2\(FP\); expected y\+1\(FP\)"
+ MOVB 8(R29), R1 // ERROR "8\(R29\) should be x\+0\(FP\)"
+ MOVB 9(R29), R1 // ERROR "9\(R29\) should be y\+1\(FP\)"
+ MOVB 10(R29), R1 // ERROR "use of 10\(R29\) points beyond argument frame"
+ RET
+
+TEXT ·arg2(SB),0,$0-4
+ MOVBU x+0(FP), R1 // ERROR "arg2: invalid MOVBU of x\+0\(FP\); int16 is 2-byte value"
+ MOVB y+2(FP), R1 // ERROR "invalid MOVB of y\+2\(FP\); uint16 is 2-byte value"
+ MOVHU x+0(FP), R1
+ MOVH y+2(FP), R2
+ MOVWU x+0(FP), R1 // ERROR "invalid MOVWU of x\+0\(FP\); int16 is 2-byte value"
+ MOVW y+2(FP), R1 // ERROR "invalid MOVW of y\+2\(FP\); uint16 is 2-byte value"
+ MOVHU x+2(FP), R1 // ERROR "invalid offset x\+2\(FP\); expected x\+0\(FP\)"
+ MOVH y+0(FP), R1 // ERROR "invalid offset y\+0\(FP\); expected y\+2\(FP\)"
+ RET
+
+TEXT ·arg4(SB),0,$0-2 // ERROR "arg4: wrong argument size 2; expected \$\.\.\.-8"
+ MOVB x+0(FP), R1 // ERROR "invalid MOVB of x\+0\(FP\); int32 is 4-byte value"
+ MOVB y+4(FP), R2 // ERROR "invalid MOVB of y\+4\(FP\); uint32 is 4-byte value"
+ MOVH x+0(FP), R1 // ERROR "invalid MOVH of x\+0\(FP\); int32 is 4-byte value"
+ MOVH y+4(FP), R1 // ERROR "invalid MOVH of y\+4\(FP\); uint32 is 4-byte value"
+ MOVW x+0(FP), R1
+ MOVW y+4(FP), R1
+ MOVW x+4(FP), R1 // ERROR "invalid offset x\+4\(FP\); expected x\+0\(FP\)"
+ MOVW y+2(FP), R1 // ERROR "invalid offset y\+2\(FP\); expected y\+4\(FP\)"
+ RET
+
+TEXT ·arg8(SB),7,$0-2 // ERROR "wrong argument size 2; expected \$\.\.\.-16"
+ MOVB x+0(FP), R1 // ERROR "invalid MOVB of x\+0\(FP\); int64 is 8-byte value"
+ MOVB y+8(FP), R2 // ERROR "invalid MOVB of y\+8\(FP\); uint64 is 8-byte value"
+ MOVH x+0(FP), R1 // ERROR "invalid MOVH of x\+0\(FP\); int64 is 8-byte value"
+ MOVH y+8(FP), R1 // ERROR "invalid MOVH of y\+8\(FP\); uint64 is 8-byte value"
+ MOVW x+0(FP), R1 // ERROR "invalid MOVW of x\+0\(FP\); int64 is 8-byte value containing x_lo\+0\(FP\) and x_hi\+4\(FP\)"
+ MOVW x_lo+0(FP), R1
+ MOVW x_hi+4(FP), R1
+ MOVW y+8(FP), R1 // ERROR "invalid MOVW of y\+8\(FP\); uint64 is 8-byte value containing y_lo\+8\(FP\) and y_hi\+12\(FP\)"
+ MOVW y_lo+8(FP), R1
+ MOVW y_hi+12(FP), R1
+ RET
+
+TEXT ·argint(SB),0,$0-2 // ERROR "wrong argument size 2; expected \$\.\.\.-8"
+ MOVB x+0(FP), R1 // ERROR "invalid MOVB of x\+0\(FP\); int is 4-byte value"
+ MOVB y+4(FP), R2 // ERROR "invalid MOVB of y\+4\(FP\); uint is 4-byte value"
+ MOVH x+0(FP), R1 // ERROR "invalid MOVH of x\+0\(FP\); int is 4-byte value"
+ MOVH y+4(FP), R1 // ERROR "invalid MOVH of y\+4\(FP\); uint is 4-byte value"
+ MOVW x+0(FP), R1
+ MOVW y+4(FP), R1
+ MOVW x+4(FP), R1 // ERROR "invalid offset x\+4\(FP\); expected x\+0\(FP\)"
+ MOVW y+2(FP), R1 // ERROR "invalid offset y\+2\(FP\); expected y\+4\(FP\)"
+ RET
+
+TEXT ·argptr(SB),7,$0-2 // ERROR "wrong argument size 2; expected \$\.\.\.-20"
+ MOVB x+0(FP), R1 // ERROR "invalid MOVB of x\+0\(FP\); \*byte is 4-byte value"
+ MOVB y+4(FP), R2 // ERROR "invalid MOVB of y\+4\(FP\); \*byte is 4-byte value"
+ MOVH x+0(FP), R1 // ERROR "invalid MOVH of x\+0\(FP\); \*byte is 4-byte value"
+ MOVH y+4(FP), R1 // ERROR "invalid MOVH of y\+4\(FP\); \*byte is 4-byte value"
+ MOVW x+0(FP), R1
+ MOVW y+4(FP), R1
+ MOVW x+4(FP), R1 // ERROR "invalid offset x\+4\(FP\); expected x\+0\(FP\)"
+ MOVW y+2(FP), R1 // ERROR "invalid offset y\+2\(FP\); expected y\+4\(FP\)"
+ MOVH c+8(FP), R1 // ERROR "invalid MOVH of c\+8\(FP\); chan int is 4-byte value"
+ MOVH m+12(FP), R1 // ERROR "invalid MOVH of m\+12\(FP\); map\[int\]int is 4-byte value"
+ MOVH f+16(FP), R1 // ERROR "invalid MOVH of f\+16\(FP\); func\(\) is 4-byte value"
+ RET
+
+TEXT ·argstring(SB),0,$16 // ERROR "wrong argument size 0; expected \$\.\.\.-16"
+ MOVH x+0(FP), R1 // ERROR "invalid MOVH of x\+0\(FP\); string base is 4-byte value"
+ MOVW x+0(FP), R1
+ MOVH x_base+0(FP), R1 // ERROR "invalid MOVH of x_base\+0\(FP\); string base is 4-byte value"
+ MOVW x_base+0(FP), R1
+ MOVH x_len+0(FP), R1 // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+4\(FP\)"
+ MOVW x_len+0(FP), R1 // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+4\(FP\)"
+ MOVH x_len+4(FP), R1 // ERROR "invalid MOVH of x_len\+4\(FP\); string len is 4-byte value"
+ MOVW x_len+4(FP), R1
+ MOVW y+0(FP), R1 // ERROR "invalid offset y\+0\(FP\); expected y\+8\(FP\)"
+ MOVW y_len+4(FP), R1 // ERROR "invalid offset y_len\+4\(FP\); expected y_len\+12\(FP\)"
+ RET
+
+TEXT ·argslice(SB),0,$24 // ERROR "wrong argument size 0; expected \$\.\.\.-24"
+ MOVH x+0(FP), R1 // ERROR "invalid MOVH of x\+0\(FP\); slice base is 4-byte value"
+ MOVW x+0(FP), R1
+ MOVH x_base+0(FP), R1 // ERROR "invalid MOVH of x_base\+0\(FP\); slice base is 4-byte value"
+ MOVW x_base+0(FP), R1
+ MOVH x_len+0(FP), R1 // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+4\(FP\)"
+ MOVW x_len+0(FP), R1 // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+4\(FP\)"
+ MOVH x_len+4(FP), R1 // ERROR "invalid MOVH of x_len\+4\(FP\); slice len is 4-byte value"
+ MOVW x_len+4(FP), R1
+ MOVH x_cap+0(FP), R1 // ERROR "invalid offset x_cap\+0\(FP\); expected x_cap\+8\(FP\)"
+ MOVW x_cap+0(FP), R1 // ERROR "invalid offset x_cap\+0\(FP\); expected x_cap\+8\(FP\)"
+ MOVH x_cap+8(FP), R1 // ERROR "invalid MOVH of x_cap\+8\(FP\); slice cap is 4-byte value"
+ MOVW x_cap+8(FP), R1
+ MOVW y+0(FP), R1 // ERROR "invalid offset y\+0\(FP\); expected y\+12\(FP\)"
+ MOVW y_len+4(FP), R1 // ERROR "invalid offset y_len\+4\(FP\); expected y_len\+16\(FP\)"
+ MOVW y_cap+8(FP), R1 // ERROR "invalid offset y_cap\+8\(FP\); expected y_cap\+20\(FP\)"
+ RET
+
+TEXT ·argiface(SB),0,$0-16
+ MOVH x+0(FP), R1 // ERROR "invalid MOVH of x\+0\(FP\); interface type is 4-byte value"
+ MOVW x+0(FP), R1
+ MOVH x_type+0(FP), R1 // ERROR "invalid MOVH of x_type\+0\(FP\); interface type is 4-byte value"
+ MOVW x_type+0(FP), R1
+ MOVQ x_itable+0(FP), R1 // ERROR "unknown variable x_itable; offset 0 is x_type\+0\(FP\)"
+ MOVQ x_itable+1(FP), R1 // ERROR "unknown variable x_itable; offset 1 is x_type\+0\(FP\)"
+ MOVH x_data+0(FP), R1 // ERROR "invalid offset x_data\+0\(FP\); expected x_data\+4\(FP\)"
+ MOVW x_data+0(FP), R1 // ERROR "invalid offset x_data\+0\(FP\); expected x_data\+4\(FP\)"
+ MOVQ x_data+0(FP), R1 // ERROR "invalid offset x_data\+0\(FP\); expected x_data\+4\(FP\)"
+ MOVH x_data+4(FP), R1 // ERROR "invalid MOVH of x_data\+4\(FP\); interface data is 4-byte value"
+ MOVW x_data+4(FP), R1
+ MOVH y+8(FP), R1 // ERROR "invalid MOVH of y\+8\(FP\); interface itable is 4-byte value"
+ MOVW y+8(FP), R1
+ MOVH y_itable+8(FP), R1 // ERROR "invalid MOVH of y_itable\+8\(FP\); interface itable is 4-byte value"
+ MOVW y_itable+8(FP), R1
+ MOVW y_type+8(FP), AX // ERROR "unknown variable y_type; offset 8 is y_itable\+8\(FP\)"
+ MOVH y_data+8(FP), AX // ERROR "invalid offset y_data\+8\(FP\); expected y_data\+12\(FP\)"
+ MOVW y_data+8(FP), AX // ERROR "invalid offset y_data\+8\(FP\); expected y_data\+12\(FP\)"
+ MOVH y_data+12(FP), AX // ERROR "invalid MOVH of y_data\+12\(FP\); interface data is 4-byte value"
+ MOVW y_data+12(FP), AX
+ RET
+
+TEXT ·returnbyte(SB),0,$0-5
+ MOVW x+0(FP), R1
+ MOVB R1, ret+4(FP)
+ MOVH R1, ret+4(FP) // ERROR "invalid MOVH of ret\+4\(FP\); byte is 1-byte value"
+ MOVW R1, ret+4(FP) // ERROR "invalid MOVW of ret\+4\(FP\); byte is 1-byte value"
+ MOVB R1, ret+3(FP) // ERROR "invalid offset ret\+3\(FP\); expected ret\+4\(FP\)"
+ RET
+
+TEXT ·returnbyte(SB),0,$0-5
+ MOVW x+0(FP), R1
+ MOVB R1, ret+4(FP)
+ MOVH R1, ret+4(FP) // ERROR "invalid MOVH of ret\+4\(FP\); byte is 1-byte value"
+ MOVW R1, ret+4(FP) // ERROR "invalid MOVW of ret\+4\(FP\); byte is 1-byte value"
+ MOVB R1, ret+3(FP) // ERROR "invalid offset ret\+3\(FP\); expected ret\+4\(FP\)"
+ RET
+
+TEXT ·returnnamed(SB),0,$0-21
+ MOVB x+0(FP), AX
+ MOVW R1, r1+4(FP)
+ MOVH R1, r2+8(FP)
+ MOVW R1, r3+12(FP)
+ MOVW R1, r3_base+12(FP)
+ MOVW R1, r3_len+16(FP)
+ MOVB R1, r4+20(FP)
+ MOVB R1, r1+4(FP) // ERROR "invalid MOVB of r1\+4\(FP\); int is 4-byte value"
+ RET
+
+TEXT ·returnintmissing(SB),0,$0-4
+ RET // ERROR "RET without writing to 4-byte ret\+0\(FP\)"
diff --git a/src/cmd/vet/testdata/buildtag.go b/src/cmd/vet/testdata/buildtag/buildtag.go
similarity index 100%
rename from src/cmd/vet/testdata/buildtag.go
rename to src/cmd/vet/testdata/buildtag/buildtag.go
diff --git a/src/cmd/vet/testdata/buildtag_bad.go b/src/cmd/vet/testdata/buildtag/buildtag_bad.go
similarity index 100%
rename from src/cmd/vet/testdata/buildtag_bad.go
rename to src/cmd/vet/testdata/buildtag/buildtag_bad.go
diff --git a/src/cmd/vet/testdata/cgo.go b/src/cmd/vet/testdata/cgo.go
deleted file mode 100644
index 5ce6007..0000000
--- a/src/cmd/vet/testdata/cgo.go
+++ /dev/null
@@ -1,54 +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 contains tests for the cgo checker.
-
-package testdata
-
-// void f(void *);
-import "C"
-
-import "unsafe"
-
-func CgoTests() {
- var c chan bool
- C.f(*(*unsafe.Pointer)(unsafe.Pointer(&c))) // ERROR "embedded pointer"
- C.f(unsafe.Pointer(&c)) // ERROR "embedded pointer"
-
- var m map[string]string
- C.f(*(*unsafe.Pointer)(unsafe.Pointer(&m))) // ERROR "embedded pointer"
- C.f(unsafe.Pointer(&m)) // ERROR "embedded pointer"
-
- var f func()
- C.f(*(*unsafe.Pointer)(unsafe.Pointer(&f))) // ERROR "embedded pointer"
- C.f(unsafe.Pointer(&f)) // ERROR "embedded pointer"
-
- var s []int
- C.f(*(*unsafe.Pointer)(unsafe.Pointer(&s))) // ERROR "embedded pointer"
- C.f(unsafe.Pointer(&s)) // ERROR "embedded pointer"
-
- var a [1][]int
- C.f(*(*unsafe.Pointer)(unsafe.Pointer(&a))) // ERROR "embedded pointer"
- C.f(unsafe.Pointer(&a)) // ERROR "embedded pointer"
-
- var st struct{ f []int }
- C.f(*(*unsafe.Pointer)(unsafe.Pointer(&st))) // ERROR "embedded pointer"
- C.f(unsafe.Pointer(&st)) // ERROR "embedded pointer"
-
- // The following cases are OK.
- var i int
- C.f(*(*unsafe.Pointer)(unsafe.Pointer(&i)))
- C.f(unsafe.Pointer(&i))
-
- C.f(*(*unsafe.Pointer)(unsafe.Pointer(&s[0])))
- C.f(unsafe.Pointer(&s[0]))
-
- var a2 [1]int
- C.f(*(*unsafe.Pointer)(unsafe.Pointer(&a2)))
- C.f(unsafe.Pointer(&a2))
-
- var st2 struct{ i int }
- C.f(*(*unsafe.Pointer)(unsafe.Pointer(&st2)))
- C.f(unsafe.Pointer(&st2))
-}
diff --git a/src/cmd/vet/testdata/cgo/cgo.go b/src/cmd/vet/testdata/cgo/cgo.go
new file mode 100644
index 0000000..25d395b
--- /dev/null
+++ b/src/cmd/vet/testdata/cgo/cgo.go
@@ -0,0 +1,56 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file contains tests for the cgo checker.
+
+package testdata
+
+// void f(void *);
+import "C"
+
+import "unsafe"
+
+func CgoTests() {
+ var c chan bool
+ C.f(*(*unsafe.Pointer)(unsafe.Pointer(&c))) // ERROR "embedded pointer"
+ C.f(unsafe.Pointer(&c)) // ERROR "embedded pointer"
+
+ var m map[string]string
+ C.f(*(*unsafe.Pointer)(unsafe.Pointer(&m))) // ERROR "embedded pointer"
+ C.f(unsafe.Pointer(&m)) // ERROR "embedded pointer"
+
+ var f func()
+ C.f(*(*unsafe.Pointer)(unsafe.Pointer(&f))) // ERROR "embedded pointer"
+ C.f(unsafe.Pointer(&f)) // ERROR "embedded pointer"
+
+ var s []int
+ C.f(*(*unsafe.Pointer)(unsafe.Pointer(&s))) // ERROR "embedded pointer"
+ C.f(unsafe.Pointer(&s)) // ERROR "embedded pointer"
+
+ var a [1][]int
+ C.f(*(*unsafe.Pointer)(unsafe.Pointer(&a))) // ERROR "embedded pointer"
+ C.f(unsafe.Pointer(&a)) // ERROR "embedded pointer"
+
+ var st struct{ f []int }
+ C.f(*(*unsafe.Pointer)(unsafe.Pointer(&st))) // ERROR "embedded pointer"
+ C.f(unsafe.Pointer(&st)) // ERROR "embedded pointer"
+
+ // The following cases are OK.
+ var i int
+ C.f(*(*unsafe.Pointer)(unsafe.Pointer(&i)))
+ C.f(unsafe.Pointer(&i))
+
+ C.f(*(*unsafe.Pointer)(unsafe.Pointer(&s[0])))
+ C.f(unsafe.Pointer(&s[0]))
+
+ var a2 [1]int
+ C.f(*(*unsafe.Pointer)(unsafe.Pointer(&a2)))
+ C.f(unsafe.Pointer(&a2))
+
+ var st2 struct{ i int }
+ C.f(*(*unsafe.Pointer)(unsafe.Pointer(&st2)))
+ C.f(unsafe.Pointer(&st2))
+
+ C.CBytes([]byte("hello"))
+}
diff --git a/src/cmd/vet/testdata/cgo2.go b/src/cmd/vet/testdata/cgo/cgo2.go
similarity index 100%
rename from src/cmd/vet/testdata/cgo2.go
rename to src/cmd/vet/testdata/cgo/cgo2.go
diff --git a/src/cmd/vet/testdata/copylock.go b/src/cmd/vet/testdata/copylock.go
index d49f468..35ed766 100644
--- a/src/cmd/vet/testdata/copylock.go
+++ b/src/cmd/vet/testdata/copylock.go
@@ -68,6 +68,24 @@ func BadFunc() {
// override 'new' keyword
new := func(interface{}) {}
new(t) // ERROR "function call copies lock value: testdata.Tlock contains sync.Once contains sync.Mutex"
+
+ // copy of array of locks
+ var muA [5]sync.Mutex
+ muB := muA // ERROR "assignment copies lock value to muB: sync.Mutex"
+ muA = muB // ERROR "assignment copies lock value to muA: sync.Mutex"
+ muSlice := muA[:] // OK
+
+ // multidimensional array
+ var mmuA [5][5]sync.Mutex
+ mmuB := mmuA // ERROR "assignment copies lock value to mmuB: sync.Mutex"
+ mmuA = mmuB // ERROR "assignment copies lock value to mmuA: sync.Mutex"
+ mmuSlice := mmuA[:] // OK
+
+ // slice copy is ok
+ var fmuA [5][][5]sync.Mutex
+ fmuB := fmuA // OK
+ fmuA = fmuB // OK
+ fmuSlice := fmuA[:] // OK
}
// SyncTypesCheck checks copying of sync.* types except sync.Mutex
diff --git a/src/cmd/vet/testdata/httpresponse.go b/src/cmd/vet/testdata/httpresponse.go
new file mode 100644
index 0000000..7302a64
--- /dev/null
+++ b/src/cmd/vet/testdata/httpresponse.go
@@ -0,0 +1,85 @@
+package testdata
+
+import (
+ "log"
+ "net/http"
+)
+
+func goodHTTPGet() {
+ res, err := http.Get("http://foo.com")
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer res.Body.Close()
+}
+
+func badHTTPGet() {
+ res, err := http.Get("http://foo.com")
+ defer res.Body.Close() // ERROR "using res before checking for errors"
+ if err != nil {
+ log.Fatal(err)
+ }
+}
+
+func badHTTPHead() {
+ res, err := http.Head("http://foo.com")
+ defer res.Body.Close() // ERROR "using res before checking for errors"
+ if err != nil {
+ log.Fatal(err)
+ }
+}
+
+func goodClientGet() {
+ client := http.DefaultClient
+ res, err := client.Get("http://foo.com")
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer res.Body.Close()
+}
+
+func badClientPtrGet() {
+ client := http.DefaultClient
+ resp, err := client.Get("http://foo.com")
+ defer resp.Body.Close() // ERROR "using resp before checking for errors"
+ if err != nil {
+ log.Fatal(err)
+ }
+}
+
+func badClientGet() {
+ client := http.Client{}
+ resp, err := client.Get("http://foo.com")
+ defer resp.Body.Close() // ERROR "using resp before checking for errors"
+ if err != nil {
+ log.Fatal(err)
+ }
+}
+
+func badClientPtrDo() {
+ client := http.DefaultClient
+ req, err := http.NewRequest("GET", "http://foo.com", nil)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ resp, err := client.Do(req)
+ defer resp.Body.Close() // ERROR "using resp before checking for errors"
+ if err != nil {
+ log.Fatal(err)
+ }
+}
+
+func badClientDo() {
+ var client http.Client
+ req, err := http.NewRequest("GET", "http://foo.com", nil)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ resp, err := client.Do(req)
+ defer resp.Body.Close() // ERROR "using resp before checking for errors"
+ if err != nil {
+ log.Fatal(err)
+ }
+}
diff --git a/src/cmd/vet/testdata/print.go b/src/cmd/vet/testdata/print.go
index ab97256..b5c59eb 100644
--- a/src/cmd/vet/testdata/print.go
+++ b/src/cmd/vet/testdata/print.go
@@ -128,11 +128,14 @@ func PrintfTests() {
fmt.Printf("%t", stringerarrayv) // ERROR "arg stringerarrayv for printf verb %t of wrong type"
fmt.Printf("%t", notstringerarrayv) // ERROR "arg notstringerarrayv for printf verb %t of wrong type"
fmt.Printf("%q", notstringerarrayv) // ERROR "arg notstringerarrayv for printf verb %q of wrong type"
- fmt.Printf("%d", Formatter(true)) // correct (the type is responsible for formatting)
- fmt.Printf("%s", nonemptyinterface) // correct (the dynamic type of nonemptyinterface may be a stringer)
+ fmt.Printf("%d", Formatter(true)) // ERROR "arg Formatter\(true\) for printf verb %d of wrong type: testdata.Formatter"
+ fmt.Printf("%z", FormatterVal(true)) // correct (the type is responsible for formatting)
+ fmt.Printf("%d", FormatterVal(true)) // correct (the type is responsible for formatting)
+ fmt.Printf("%s", nonemptyinterface) // correct (the type is responsible for formatting)
fmt.Printf("%.*s %d %g", 3, "hi", 23, 'x') // ERROR "arg 'x' for printf verb %g of wrong type"
fmt.Println() // not an error
fmt.Println("%s", "hi") // ERROR "possible formatting directive in Println call"
+ fmt.Println("0.0%") // correct (trailing % couldn't be a formatting directive)
fmt.Printf("%s", "hi", 3) // ERROR "wrong number of args for format in Printf call"
_ = fmt.Sprintf("%"+("s"), "hi", 3) // ERROR "wrong number of args for format in Sprintf call"
fmt.Printf("%s%%%d", "hi", 3) // correct
@@ -173,8 +176,8 @@ func PrintfTests() {
Printf("%[2]*.[1]*[3]d", 2, 3, 4)
fmt.Fprintf(os.Stderr, "%[2]*.[1]*[3]d", 2, 3, 4) // Use Fprintf to make sure we count arguments correctly.
// Bad argument reorderings.
- Printf("%[xd", 3) // ERROR "illegal syntax for printf argument index"
- Printf("%[x]d", 3) // ERROR "illegal syntax for printf argument index"
+ Printf("%[xd", 3) // ERROR "bad syntax for printf argument index: \[xd\]"
+ Printf("%[x]d", 3) // ERROR "bad syntax for printf argument index: \[x\]"
Printf("%[3]*s", "hi", 2) // ERROR "missing argument for Printf.* reads arg 3, have only 2"
_ = fmt.Sprintf("%[3]d", 2) // ERROR "missing argument for Sprintf.* reads arg 3, have only 1"
Printf("%[2]*.[1]*[3]d", 2, "hi", 4) // ERROR "arg .hi. for \* in printf format not of type int"
@@ -199,6 +202,11 @@ func PrintfTests() {
et4.Error() // ok, not an error method.
var et5 errorTest5
et5.error() // ok, not an error method.
+ // Interfaces can be used with any verb.
+ var iface interface {
+ ToTheMadness() bool // Method ToTheMadness usually returns false
+ }
+ fmt.Printf("%f", iface) // ok: fmt treats interfaces as transparent and iface may well have a float concrete type
// Can't print a function.
Printf("%d", someFunction) // ERROR "arg someFunction in printf call is a function value, not a function call"
Printf("%v", someFunction) // ERROR "arg someFunction in printf call is a function value, not a function call"
@@ -232,6 +240,9 @@ func PrintfTests() {
externalprintf.Logf(level, "%d", 42) // OK
externalprintf.Errorf(level, level, "foo %q bar", "foobar") // OK
externalprintf.Logf(level, "%d") // ERROR "format reads arg 1, have only 0 args"
+ var formatStr = "%s %s"
+ externalprintf.Sprintf(formatStr, "a", "b") // OK
+ externalprintf.Logf(level, formatStr, "a", "b") // OK
// user-defined Println-like functions
ss := &someStruct{}
@@ -243,6 +254,15 @@ func PrintfTests() {
ss.log(someFunction) // OK
ss.log(someFunction, "bar", 1.33) // OK
ss.log(someFunction, someFunction) // ERROR "arg someFunction in log call is a function value, not a function call"
+
+ // indexed arguments
+ Printf("%d %[3]d %d %[2]d", 1, 2, 3, 4) // OK
+ Printf("%d %[0]d %d %[2]d", 1, 2, 3, 4) // ERROR "indexes start at 1"
+ Printf("%d %[3]d %d %[-2]d", 1, 2, 3, 4) // ERROR "bad syntax for printf argument index: \[-2\]"
+ Printf("%d %[3]d %d %[2234234234234]d", 1, 2, 3, 4) // ERROR "bad syntax for printf argument index: .+ value out of range"
+ Printf("%d %[3]d %d %[2]d", 1, 2, 3) // ERROR "format reads arg 4, have only 3 args"
+ Printf("%d %[3]d %d %[2]d", 1, 2, 3, 4, 5) // ERROR "wrong number of args for format in Printf call: 4 needed but 5 args"
+ Printf("%[1][3]d", 1, 2) // ERROR "unrecognized printf verb '\['"
}
type someStruct struct{}
@@ -398,6 +418,12 @@ type Formatter bool
func (*Formatter) Format(fmt.State, rune) {
}
+// Formatter with value receiver
+type FormatterVal bool
+
+func (FormatterVal) Format(fmt.State, rune) {
+}
+
type RecursiveSlice []RecursiveSlice
var recursiveSliceV = &RecursiveSlice{}
diff --git a/src/cmd/vet/testdata/shift.go b/src/cmd/vet/testdata/shift.go
index 6624f09..99acaad 100644
--- a/src/cmd/vet/testdata/shift.go
+++ b/src/cmd/vet/testdata/shift.go
@@ -75,4 +75,6 @@ func ShiftTest() {
_ = 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 oneIf64Bit = ^uint(0) >> 63 // allow large shifts of constants; they are used for 32/64 bit compatibility tricks
}
diff --git a/src/cmd/vet/testdata/structtag.go b/src/cmd/vet/testdata/structtag.go
index 6878f56..cba990f 100644
--- a/src/cmd/vet/testdata/structtag.go
+++ b/src/cmd/vet/testdata/structtag.go
@@ -15,6 +15,8 @@ type StructTagTest struct {
F int `:"emptykey"` // ERROR "not compatible with reflect.StructTag.Get: bad syntax for struct tag key"
G int `x:"noEndQuote` // ERROR "not compatible with reflect.StructTag.Get: bad syntax for struct tag value"
H int `x:"trunc\x0"` // ERROR "not compatible with reflect.StructTag.Get: bad syntax for struct tag value"
+ I int `x:"foo",y:"bar"` // ERROR "not compatible with reflect.StructTag.Get: key:.value. pairs not separated by spaces"
+ J int `x:"foo"y:"bar"` // ERROR "not compatible with reflect.StructTag.Get: key:.value. pairs not separated by spaces"
OK0 int `x:"y" u:"v" w:""`
OK1 int `x:"y:z" u:"v" w:""` // note multiple colons.
OK2 int "k0:\"values contain spaces\" k1:\"literal\ttabs\" k2:\"and\\tescaped\\tabs\""
@@ -34,3 +36,31 @@ type JSONEmbeddedField struct {
UnexportedEncodingTagTest `is:"embedded"`
unexp `is:"embedded,notexported" json:"unexp"` // OK for now, see issue 7363
}
+
+type DuplicateJSONFields struct {
+ JSON int `json:"a"`
+ DuplicateJSON int `json:"a"` // ERROR "struct field DuplicateJSON repeats json tag .a. also at testdata/structtag.go:41"
+ IgnoredJSON int `json:"-"`
+ OtherIgnoredJSON int `json:"-"`
+ OmitJSON int `json:",omitempty"`
+ OtherOmitJSON int `json:",omitempty"`
+ DuplicateOmitJSON int `json:"a,omitempty"` // ERROR "struct field DuplicateOmitJSON repeats json tag .a. also at testdata/structtag.go:41"
+ NonJSON int `foo:"a"`
+ DuplicateNonJSON int `foo:"a"`
+ Embedded struct {
+ DuplicateJSON int `json:"a"` // OK because its not in the same struct type
+ }
+
+ XML int `xml:"a"`
+ DuplicateXML int `xml:"a"` // ERROR "struct field DuplicateXML repeats xml tag .a. also at testdata/structtag.go:54"
+ IgnoredXML int `xml:"-"`
+ OtherIgnoredXML int `xml:"-"`
+ OmitXML int `xml:",omitempty"`
+ OtherOmitXML int `xml:",omitempty"`
+ DuplicateOmitXML int `xml:"a,omitempty"` // ERROR "struct field DuplicateOmitXML repeats xml tag .a. also at testdata/structtag.go:54"
+ NonXML int `foo:"a"`
+ DuplicateNonXML int `foo:"a"`
+ Embedded struct {
+ DuplicateXML int `xml:"a"` // OK because its not in the same struct type
+ }
+}
diff --git a/src/cmd/vet/testdata/testingpkg/tests.go b/src/cmd/vet/testdata/testingpkg/tests.go
new file mode 100644
index 0000000..69d29d3
--- /dev/null
+++ b/src/cmd/vet/testdata/testingpkg/tests.go
@@ -0,0 +1 @@
+package testdata
diff --git a/src/cmd/vet/testdata/tests_test.go b/src/cmd/vet/testdata/testingpkg/tests_test.go
similarity index 100%
rename from src/cmd/vet/testdata/tests_test.go
rename to src/cmd/vet/testdata/testingpkg/tests_test.go
diff --git a/src/cmd/vet/testdata/unsafeptr.go b/src/cmd/vet/testdata/unsafeptr.go
index e04856e..ce85200 100644
--- a/src/cmd/vet/testdata/unsafeptr.go
+++ b/src/cmd/vet/testdata/unsafeptr.go
@@ -15,13 +15,15 @@ func f() {
x = unsafe.Pointer(y) // ERROR "possible misuse of unsafe.Pointer"
y = uintptr(x)
- // only allowed pointer arithmetic is ptr +/- num.
+ // only allowed pointer arithmetic is ptr +/-/&^ num.
// num+ptr is technically okay but still flagged: write ptr+num instead.
x = unsafe.Pointer(uintptr(x) + 1)
x = unsafe.Pointer(1 + uintptr(x)) // ERROR "possible misuse of unsafe.Pointer"
x = unsafe.Pointer(uintptr(x) + uintptr(x)) // ERROR "possible misuse of unsafe.Pointer"
x = unsafe.Pointer(uintptr(x) - 1)
x = unsafe.Pointer(1 - uintptr(x)) // ERROR "possible misuse of unsafe.Pointer"
+ x = unsafe.Pointer(uintptr(x) &^ 3)
+ x = unsafe.Pointer(1 &^ uintptr(x)) // ERROR "possible misuse of unsafe.Pointer"
// certain uses of reflect are okay
var v reflect.Value
diff --git a/src/cmd/vet/types.go b/src/cmd/vet/types.go
index 4d0e615..8357d3c 100644
--- a/src/cmd/vet/types.go
+++ b/src/cmd/vet/types.go
@@ -113,8 +113,7 @@ func (f *File) matchArgTypeInternal(t printfArgType, typ types.Type, arg ast.Exp
}
}
// If the type implements fmt.Formatter, we have nothing to check.
- // formatterTyp may be nil - be conservative and check for Format method in that case.
- if formatterType != nil && types.Implements(typ, formatterType) || f.hasMethod(typ, "Format") {
+ if f.isFormatter(typ) {
return true
}
// If we can use a string, might arg (dynamically) implement the Stringer or Error interface?
@@ -185,13 +184,10 @@ func (f *File) matchArgTypeInternal(t printfArgType, typ types.Type, arg ast.Exp
return f.matchStructArgType(t, typ, arg, inProgress)
case *types.Interface:
- // If the static type of the argument is empty interface, there's little we can do.
- // Example:
- // func f(x interface{}) { fmt.Printf("%s", x) }
- // Whether x is valid for %s depends on the type of the argument to f. One day
- // we will be able to do better. For now, we assume that empty interface is OK
- // but non-empty interfaces, with Stringer and Error handled above, are errors.
- return typ.NumMethods() == 0
+ // There's little we can do.
+ // Whether any particular verb is valid depends on the argument.
+ // The user may have reasonable prior knowledge of the contents of the interface.
+ return true
case *types.Basic:
switch typ.Kind() {
diff --git a/src/cmd/vet/unsafeptr.go b/src/cmd/vet/unsafeptr.go
index a143e4d..cb2cc81 100644
--- a/src/cmd/vet/unsafeptr.go
+++ b/src/cmd/vet/unsafeptr.go
@@ -89,7 +89,7 @@ func (f *File) isSafeUintptr(x ast.Expr) bool {
case *ast.BinaryExpr:
switch x.Op {
- case token.ADD, token.SUB:
+ case token.ADD, token.SUB, token.AND_NOT:
return f.isSafeUintptr(x.X) && !f.isSafeUintptr(x.Y)
}
}
diff --git a/src/cmd/vet/vet_test.go b/src/cmd/vet/vet_test.go
index 31d4b90..725f013 100644
--- a/src/cmd/vet/vet_test.go
+++ b/src/cmd/vet/vet_test.go
@@ -6,13 +6,13 @@ package main_test
import (
"bytes"
- "flag"
"fmt"
"internal/testenv"
"os"
"os/exec"
"path/filepath"
"runtime"
+ "sync"
"testing"
)
@@ -23,7 +23,6 @@ const (
// We implement TestMain so remove the test binary when all is done.
func TestMain(m *testing.M) {
- flag.Parse()
result := m.Run()
os.Remove(binary)
os.Exit(result)
@@ -40,20 +39,23 @@ func MustHavePerl(t *testing.T) {
}
var (
- built = false // We have built the binary.
- failed = false // We have failed to build the binary, don't try again.
+ buildMu sync.Mutex // guards following
+ built = false // We have built the binary.
+ failed = false // We have failed to build the binary, don't try again.
)
func Build(t *testing.T) {
- testenv.MustHaveGoBuild(t)
- MustHavePerl(t)
+ buildMu.Lock()
+ defer buildMu.Unlock()
if built {
return
}
if failed {
t.Skip("cannot run on this environment")
}
- cmd := exec.Command("go", "build", "-o", binary)
+ testenv.MustHaveGoBuild(t)
+ MustHavePerl(t)
+ cmd := exec.Command(testenv.GoToolPath(t), "build", "-o", binary)
output, err := cmd.CombinedOutput()
if err != nil {
failed = true
@@ -83,66 +85,122 @@ func Vet(t *testing.T, files []string) {
// rm testvet
//
+// TestVet tests self-contained files in testdata/*.go.
+//
+// If a file contains assembly or has inter-dependencies, it should be
+// in its own test, like TestVetAsm, TestDivergentPackagesExamples,
+// etc below.
func TestVet(t *testing.T) {
Build(t)
+ t.Parallel()
// errchk ./testvet
gos, err := filepath.Glob(filepath.Join(dataDir, "*.go"))
if err != nil {
t.Fatal(err)
}
- asms, err := filepath.Glob(filepath.Join(dataDir, "*.s"))
- if err != nil {
- t.Fatal(err)
+ wide := runtime.GOMAXPROCS(0)
+ if wide > len(gos) {
+ wide = len(gos)
+ }
+ batch := make([][]string, wide)
+ for i, file := range gos {
+ batch[i%wide] = append(batch[i%wide], file)
+ }
+ for i, files := range batch {
+ files := files
+ t.Run(fmt.Sprint(i), func(t *testing.T) {
+ t.Parallel()
+ t.Logf("files: %q", files)
+ Vet(t, files)
+ })
}
- files := append(gos, asms...)
- Vet(t, files)
}
-func TestDivergentPackagesExamples(t *testing.T) {
+func TestVetAsm(t *testing.T) {
Build(t)
+
+ asmDir := filepath.Join(dataDir, "asm")
+ gos, err := filepath.Glob(filepath.Join(asmDir, "*.go"))
+ if err != nil {
+ t.Fatal(err)
+ }
+ asms, err := filepath.Glob(filepath.Join(asmDir, "*.s"))
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ t.Parallel()
// errchk ./testvet
- Vet(t, []string{"testdata/divergent"})
+ Vet(t, append(gos, asms...))
}
-func TestIncompleteExamples(t *testing.T) {
+func TestVetDirs(t *testing.T) {
+ t.Parallel()
Build(t)
- // errchk ./testvet
- Vet(t, []string{"testdata/incomplete/examples_test.go"})
+ for _, dir := range []string{
+ "testingpkg",
+ "divergent",
+ "buildtag",
+ "incomplete", // incomplete examples
+ } {
+ dir := dir
+ t.Run(dir, func(t *testing.T) {
+ t.Parallel()
+ gos, err := filepath.Glob(filepath.Join("testdata", dir, "*.go"))
+ if err != nil {
+ t.Fatal(err)
+ }
+ Vet(t, gos)
+ })
+ }
}
func run(c *exec.Cmd, t *testing.T) bool {
output, err := c.CombinedOutput()
- os.Stderr.Write(output)
if err != nil {
+ t.Logf("vet output:\n%s", output)
t.Fatal(err)
}
// Errchk delights by not returning non-zero status if it finds errors, so we look at the output.
// It prints "BUG" if there is a failure.
if !c.ProcessState.Success() {
+ t.Logf("vet output:\n%s", output)
return false
}
- return !bytes.Contains(output, []byte("BUG"))
+ ok := !bytes.Contains(output, []byte("BUG"))
+ if !ok {
+ t.Logf("vet output:\n%s", output)
+ }
+ return ok
}
// TestTags verifies that the -tags argument controls which files to check.
func TestTags(t *testing.T) {
+ t.Parallel()
Build(t)
- args := []string{
- "-tags=testtag",
- "-v", // We're going to look at the files it examines.
- "testdata/tagtest",
- }
- cmd := exec.Command("./"+binary, args...)
- output, err := cmd.CombinedOutput()
- if err != nil {
- t.Fatal(err)
- }
- // file1 has testtag and file2 has !testtag.
- if !bytes.Contains(output, []byte(filepath.Join("tagtest", "file1.go"))) {
- t.Error("file1 was excluded, should be included")
- }
- if bytes.Contains(output, []byte(filepath.Join("tagtest", "file2.go"))) {
- t.Error("file2 was included, should be excluded")
+ for _, tag := range []string{"testtag", "x testtag y", "x,testtag,y"} {
+ tag := tag
+ t.Run(tag, func(t *testing.T) {
+ t.Parallel()
+ t.Logf("-tags=%s", tag)
+ args := []string{
+ "-tags=" + tag,
+ "-v", // We're going to look at the files it examines.
+ "testdata/tagtest",
+ }
+ cmd := exec.Command("./"+binary, args...)
+ output, err := cmd.CombinedOutput()
+ if err != nil {
+ t.Fatal(err)
+ }
+ // file1 has testtag and file2 has !testtag.
+ if !bytes.Contains(output, []byte(filepath.Join("tagtest", "file1.go"))) {
+ t.Error("file1 was excluded, should be included")
+ }
+ if bytes.Contains(output, []byte(filepath.Join("tagtest", "file2.go"))) {
+ t.Error("file2 was included, should be excluded")
+ }
+ })
}
}
diff --git a/src/cmd/yacc/doc.go b/src/cmd/yacc/doc.go
deleted file mode 100644
index c9bb573..0000000
--- a/src/cmd/yacc/doc.go
+++ /dev/null
@@ -1,69 +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.
-
-/*
-
-Yacc is a version of yacc for Go.
-It is written in Go and generates parsers written in Go.
-
-Usage:
-
- go tool yacc args...
-
-It is largely transliterated from the Inferno version written in Limbo
-which in turn was largely transliterated from the Plan 9 version
-written in C and documented at
-
- https://9p.io/magic/man2html/1/yacc
-
-Adepts of the original yacc will have no trouble adapting to this
-form of the tool.
-
-The directory $GOROOT/src/cmd/yacc/testdata/expr is a yacc program
-for a very simple expression parser. See expr.y and main.go in that
-directory for examples of how to write and build yacc programs.
-
-The generated parser is reentrant. The parsing function yyParse expects
-to be given an argument that conforms to the following interface:
-
- type yyLexer interface {
- Lex(lval *yySymType) int
- Error(e string)
- }
-
-Lex should return the token identifier, and place other token
-information in lval (which replaces the usual yylval).
-Error is equivalent to yyerror in the original yacc.
-
-Code inside the grammar actions may refer to the variable yylex,
-which holds the yyLexer passed to yyParse.
-
-Clients that need to understand more about the parser state can
-create the parser separately from invoking it. The function yyNewParser
-returns a yyParser conforming to the following interface:
-
- type yyParser interface {
- Parse(yyLex) int
- Lookahead() int
- }
-
-Parse runs the parser; the top-level call yyParse(yylex) is equivalent
-to yyNewParser().Parse(yylex).
-
-Lookahead can be called during grammar actions to read (but not consume)
-the value of the current lookahead token, as returned by yylex.Lex.
-If there is no current lookahead token (because the parser has not called Lex
-or has consumed the token returned by the most recent call to Lex),
-Lookahead returns -1. Calling Lookahead is equivalent to reading
-yychar from within in a grammar action.
-
-Multiple grammars compiled into a single program should be placed in
-distinct packages. If that is impossible, the "-p prefix" flag to
-yacc sets the prefix, by default yy, that begins the names of
-symbols, including types, the parser, and the lexer, generated and
-referenced by yacc's generated code. Setting it to distinct values
-allows multiple grammars to be placed in a single package.
-
-*/
-package main
diff --git a/src/cmd/yacc/testdata/expr/README b/src/cmd/yacc/testdata/expr/README
deleted file mode 100644
index 302ef57..0000000
--- a/src/cmd/yacc/testdata/expr/README
+++ /dev/null
@@ -1,20 +0,0 @@
-This directory contains a simple program demonstrating how to use
-the Go version of yacc.
-
-To build it:
-
- $ go generate
- $ go build
-
-or
-
- $ go generate
- $ go run expr.go
-
-The file main.go contains the "go generate" command to run yacc to
-create expr.go from expr.y. It also has the package doc comment,
-as godoc will not scan the .y file.
-
-The actual implementation is in expr.y.
-
-The program is not installed in the binary distributions of Go.
diff --git a/src/cmd/yacc/testdata/expr/expr.y b/src/cmd/yacc/testdata/expr/expr.y
deleted file mode 100644
index c39f919..0000000
--- a/src/cmd/yacc/testdata/expr/expr.y
+++ /dev/null
@@ -1,202 +0,0 @@
-// Copyright 2013 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// This is an example of a goyacc program.
-// To build it:
-// go tool yacc -p "expr" expr.y (produces y.go)
-// go build -o expr y.go
-// expr
-// > <type an expression>
-
-%{
-
-package main
-
-import (
- "bufio"
- "bytes"
- "fmt"
- "io"
- "log"
- "math/big"
- "os"
- "unicode/utf8"
-)
-
-%}
-
-%union {
- num *big.Rat
-}
-
-%type <num> expr expr1 expr2 expr3
-
-%token '+' '-' '*' '/' '(' ')'
-
-%token <num> NUM
-
-%%
-
-top:
- expr
- {
- if $1.IsInt() {
- fmt.Println($1.Num().String())
- } else {
- fmt.Println($1.String())
- }
- }
-
-expr:
- expr1
-| '+' expr
- {
- $$ = $2
- }
-| '-' expr
- {
- $$ = $2.Neg($2)
- }
-
-expr1:
- expr2
-| expr1 '+' expr2
- {
- $$ = $1.Add($1, $3)
- }
-| expr1 '-' expr2
- {
- $$ = $1.Sub($1, $3)
- }
-
-expr2:
- expr3
-| expr2 '*' expr3
- {
- $$ = $1.Mul($1, $3)
- }
-| expr2 '/' expr3
- {
- $$ = $1.Quo($1, $3)
- }
-
-expr3:
- NUM
-| '(' expr ')'
- {
- $$ = $2
- }
-
-
-%%
-
-// The parser expects the lexer to return 0 on EOF. Give it a name
-// for clarity.
-const eof = 0
-
-// The parser uses the type <prefix>Lex as a lexer. It must provide
-// the methods Lex(*<prefix>SymType) int and Error(string).
-type exprLex struct {
- line []byte
- peek rune
-}
-
-// The parser calls this method to get each new token. This
-// implementation returns operators and NUM.
-func (x *exprLex) Lex(yylval *exprSymType) int {
- for {
- c := x.next()
- switch c {
- case eof:
- return eof
- case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
- return x.num(c, yylval)
- case '+', '-', '*', '/', '(', ')':
- return int(c)
-
- // Recognize Unicode multiplication and division
- // symbols, returning what the parser expects.
- case '×':
- return '*'
- case '÷':
- return '/'
-
- case ' ', '\t', '\n', '\r':
- default:
- log.Printf("unrecognized character %q", c)
- }
- }
-}
-
-// Lex a number.
-func (x *exprLex) num(c rune, yylval *exprSymType) int {
- add := func(b *bytes.Buffer, c rune) {
- if _, err := b.WriteRune(c); err != nil {
- log.Fatalf("WriteRune: %s", err)
- }
- }
- var b bytes.Buffer
- add(&b, c)
- L: for {
- c = x.next()
- switch c {
- case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '.', 'e', 'E':
- add(&b, c)
- default:
- break L
- }
- }
- if c != eof {
- x.peek = c
- }
- yylval.num = &big.Rat{}
- _, ok := yylval.num.SetString(b.String())
- if !ok {
- log.Printf("bad number %q", b.String())
- return eof
- }
- return NUM
-}
-
-// Return the next rune for the lexer.
-func (x *exprLex) next() rune {
- if x.peek != eof {
- r := x.peek
- x.peek = eof
- return r
- }
- if len(x.line) == 0 {
- return eof
- }
- c, size := utf8.DecodeRune(x.line)
- x.line = x.line[size:]
- if c == utf8.RuneError && size == 1 {
- log.Print("invalid utf8")
- return x.next()
- }
- return c
-}
-
-// The parser calls this method on a parse error.
-func (x *exprLex) Error(s string) {
- log.Printf("parse error: %s", s)
-}
-
-func main() {
- in := bufio.NewReader(os.Stdin)
- for {
- if _, err := os.Stdout.WriteString("> "); err != nil {
- log.Fatalf("WriteString: %s", err)
- }
- line, err := in.ReadBytes('\n')
- if err == io.EOF {
- return
- }
- if err != nil {
- log.Fatalf("ReadBytes: %s", err)
- }
-
- exprParse(&exprLex{line: line})
- }
-}
diff --git a/src/cmd/yacc/testdata/expr/main.go b/src/cmd/yacc/testdata/expr/main.go
deleted file mode 100644
index 37f0023..0000000
--- a/src/cmd/yacc/testdata/expr/main.go
+++ /dev/null
@@ -1,15 +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 holds the go generate command to run yacc on the grammar in expr.y.
-// To build expr:
-// % go generate
-// % go build
-
-//go:generate -command yacc go tool yacc
-//go:generate yacc -o expr.go -p "expr" expr.y
-
-// Expr is a simple expression evaluator that serves as a working example of
-// how to use Go's yacc implementation.
-package main
diff --git a/src/cmd/yacc/yacc.go b/src/cmd/yacc/yacc.go
deleted file mode 100644
index 8a5df05..0000000
--- a/src/cmd/yacc/yacc.go
+++ /dev/null
@@ -1,3641 +0,0 @@
-/*
-Derived from Inferno's utils/iyacc/yacc.c
-http://code.google.com/p/inferno-os/source/browse/utils/iyacc/yacc.c
-
-This copyright NOTICE applies to all files in this directory and
-subdirectories, unless another copyright notice appears in a given
-file or subdirectory. If you take substantial code from this software to use in
-other programs, you must somehow include with it an appropriate
-copyright notice that includes the copyright notice and the other
-notices below. It is fine (and often tidier) to do that in a separate
-file such as NOTICE, LICENCE or COPYING.
-
- 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 main
-
-// yacc
-// major difference is lack of stem ("y" variable)
-//
-
-import (
- "bufio"
- "bytes"
- "flag"
- "fmt"
- "go/format"
- "io/ioutil"
- "os"
- "strconv"
- "strings"
- "unicode"
-)
-
-// the following are adjustable
-// according to memory size
-const (
- ACTSIZE = 30000
- NSTATES = 2000
- TEMPSIZE = 2000
-
- SYMINC = 50 // increase for non-term or term
- RULEINC = 50 // increase for max rule length prodptr[i]
- PRODINC = 100 // increase for productions prodptr
- WSETINC = 50 // increase for working sets wsets
- STATEINC = 200 // increase for states statemem
-
- NAMESIZE = 50
- NTYPES = 63
- ISIZE = 400
-
- PRIVATE = 0xE000 // unicode private use
-
- // relationships which must hold:
- // TEMPSIZE >= NTERMS + NNONTERM + 1;
- // TEMPSIZE >= NSTATES;
- //
-
- NTBASE = 010000
- ERRCODE = 8190
- ACCEPTCODE = 8191
- YYLEXUNK = 3
- TOKSTART = 4 //index of first defined token
-)
-
-// no, left, right, binary assoc.
-const (
- NOASC = iota
- LASC
- RASC
- BASC
-)
-
-// flags for state generation
-const (
- DONE = iota
- MUSTDO
- MUSTLOOKAHEAD
-)
-
-// flags for a rule having an action, and being reduced
-const (
- ACTFLAG = 1 << (iota + 2)
- REDFLAG
-)
-
-// output parser flags
-const yyFlag = -1000
-
-// parse tokens
-const (
- IDENTIFIER = PRIVATE + iota
- MARK
- TERM
- LEFT
- RIGHT
- BINARY
- PREC
- LCURLY
- IDENTCOLON
- NUMBER
- START
- TYPEDEF
- TYPENAME
- UNION
- ERROR
-)
-
-const ENDFILE = 0
-const EMPTY = 1
-const WHOKNOWS = 0
-const OK = 1
-const NOMORE = -1000
-
-// macros for getting associativity and precedence levels
-func ASSOC(i int) int { return i & 3 }
-
-func PLEVEL(i int) int { return (i >> 4) & 077 }
-
-func TYPE(i int) int { return (i >> 10) & 077 }
-
-// macros for setting associativity and precedence levels
-func SETASC(i, j int) int { return i | j }
-
-func SETPLEV(i, j int) int { return i | (j << 4) }
-
-func SETTYPE(i, j int) int { return i | (j << 10) }
-
-// I/O descriptors
-var finput *bufio.Reader // input file
-var stderr *bufio.Writer
-var ftable *bufio.Writer // y.go file
-var fcode = &bytes.Buffer{} // saved code
-var foutput *bufio.Writer // y.output file
-
-var fmtImported bool // output file has recorded an import of "fmt"
-
-var oflag string // -o [y.go] - y.go file
-var vflag string // -v [y.output] - y.output file
-var lflag bool // -l - disable line directives
-var prefix string // name prefix for identifiers, default yy
-
-func init() {
- flag.StringVar(&oflag, "o", "y.go", "parser output")
- flag.StringVar(&prefix, "p", "yy", "name prefix to use in generated code")
- flag.StringVar(&vflag, "v", "y.output", "create parsing tables")
- flag.BoolVar(&lflag, "l", false, "disable line directives")
-}
-
-var initialstacksize = 16
-
-// communication variables between various I/O routines
-var infile string // input file name
-var numbval int // value of an input number
-var tokname string // input token name, slop for runes and 0
-var tokflag = false
-
-// structure declarations
-type Lkset []int
-
-type Pitem struct {
- prod []int
- off int // offset within the production
- first int // first term or non-term in item
- prodno int // production number for sorting
-}
-
-type Item struct {
- pitem Pitem
- look Lkset
-}
-
-type Symb struct {
- name string
- noconst bool
- value int
-}
-
-type Wset struct {
- pitem Pitem
- flag int
- ws Lkset
-}
-
-// storage of types
-var ntypes int // number of types defined
-var typeset [NTYPES]string // pointers to type tags
-
-// token information
-
-var ntokens = 0 // number of tokens
-var tokset []Symb
-var toklev []int // vector with the precedence of the terminals
-
-// nonterminal information
-
-var nnonter = -1 // the number of nonterminals
-var nontrst []Symb
-var start int // start symbol
-
-// state information
-
-var nstate = 0 // number of states
-var pstate = make([]int, NSTATES+2) // index into statemem to the descriptions of the states
-var statemem []Item
-var tystate = make([]int, NSTATES) // contains type information about the states
-var tstates []int // states generated by terminal gotos
-var ntstates []int // states generated by nonterminal gotos
-var mstates = make([]int, NSTATES) // chain of overflows of term/nonterm generation lists
-var lastred int // number of last reduction of a state
-var defact = make([]int, NSTATES) // default actions of states
-
-// lookahead set information
-
-var nolook = 0 // flag to turn off lookahead computations
-var tbitset = 0 // size of lookahead sets
-var clset Lkset // temporary storage for lookahead computations
-
-// working set information
-
-var wsets []Wset
-var cwp int
-
-// storage for action table
-
-var amem []int // action table storage
-var memp int // next free action table position
-var indgo = make([]int, NSTATES) // index to the stored goto table
-
-// temporary vector, indexable by states, terms, or ntokens
-
-var temp1 = make([]int, TEMPSIZE) // temporary storage, indexed by terms + ntokens or states
-var lineno = 1 // current input line number
-var fatfl = 1 // if on, error is fatal
-var nerrors = 0 // number of errors
-
-// assigned token type values
-
-var extval = 0
-
-// grammar rule information
-
-var nprod = 1 // number of productions
-var prdptr [][]int // pointers to descriptions of productions
-var levprd []int // precedence levels for the productions
-var rlines []int // line number for this rule
-
-// statistics collection variables
-
-var zzgoent = 0
-var zzgobest = 0
-var zzacent = 0
-var zzexcp = 0
-var zzclose = 0
-var zzrrconf = 0
-var zzsrconf = 0
-var zzstate = 0
-
-// optimizer arrays
-
-var yypgo [][]int
-var optst [][]int
-var ggreed []int
-var pgo []int
-
-var maxspr int // maximum spread of any entry
-var maxoff int // maximum offset into a array
-var maxa int
-
-// storage for information about the nonterminals
-
-var pres [][][]int // vector of pointers to productions yielding each nonterminal
-var pfirst []Lkset
-var pempty []int // vector of nonterminals nontrivially deriving e
-
-// random stuff picked out from between functions
-
-var indebug = 0 // debugging flag for cpfir
-var pidebug = 0 // debugging flag for putitem
-var gsdebug = 0 // debugging flag for stagen
-var cldebug = 0 // debugging flag for closure
-var pkdebug = 0 // debugging flag for apack
-var g2debug = 0 // debugging for go2gen
-var adb = 0 // debugging for callopt
-
-type Resrv struct {
- name string
- value int
-}
-
-var resrv = []Resrv{
- {"binary", BINARY},
- {"left", LEFT},
- {"nonassoc", BINARY},
- {"prec", PREC},
- {"right", RIGHT},
- {"start", START},
- {"term", TERM},
- {"token", TERM},
- {"type", TYPEDEF},
- {"union", UNION},
- {"struct", UNION},
- {"error", ERROR},
-}
-
-type Error struct {
- lineno int
- tokens []string
- msg string
-}
-
-var errors []Error
-
-type Row struct {
- actions []int
- defaultAction int
-}
-
-var stateTable []Row
-
-var zznewstate = 0
-
-const EOF = -1
-
-func main() {
-
- setup() // initialize and read productions
-
- tbitset = (ntokens + 32) / 32
- cpres() // make table of which productions yield a given nonterminal
- cempty() // make a table of which nonterminals can match the empty string
- cpfir() // make a table of firsts of nonterminals
-
- stagen() // generate the states
-
- yypgo = make([][]int, nnonter+1)
- optst = make([][]int, nstate)
- output() // write the states and the tables
- go2out()
-
- hideprod()
- summary()
-
- callopt()
-
- others()
-
- exit(0)
-}
-
-func setup() {
- var j, ty int
-
- stderr = bufio.NewWriter(os.Stderr)
- foutput = nil
-
- flag.Parse()
- if flag.NArg() != 1 {
- usage()
- }
- if initialstacksize < 1 {
- // never set so cannot happen
- fmt.Fprintf(stderr, "yacc: stack size too small\n")
- usage()
- }
- yaccpar = strings.Replace(yaccpartext, "$$", prefix, -1)
- openup()
-
- defin(0, "$end")
- extval = PRIVATE // tokens start in unicode 'private use'
- defin(0, "error")
- defin(1, "$accept")
- defin(0, "$unk")
- i := 0
-
- t := gettok()
-
-outer:
- for {
- switch t {
- default:
- errorf("syntax error tok=%v", t-PRIVATE)
-
- case MARK, ENDFILE:
- break outer
-
- case ';':
-
- case START:
- t = gettok()
- if t != IDENTIFIER {
- errorf("bad %%start construction")
- }
- start = chfind(1, tokname)
-
- case ERROR:
- lno := lineno
- var tokens []string
- for {
- t := gettok()
- if t == ':' {
- break
- }
- if t != IDENTIFIER && t != IDENTCOLON {
- errorf("bad syntax in %%error")
- }
- tokens = append(tokens, tokname)
- if t == IDENTCOLON {
- break
- }
- }
- if gettok() != IDENTIFIER {
- errorf("bad syntax in %%error")
- }
- errors = append(errors, Error{lno, tokens, tokname})
-
- case TYPEDEF:
- t = gettok()
- if t != TYPENAME {
- errorf("bad syntax in %%type")
- }
- ty = numbval
- for {
- t = gettok()
- switch t {
- case IDENTIFIER:
- t = chfind(1, tokname)
- if t < NTBASE {
- j = TYPE(toklev[t])
- if j != 0 && j != ty {
- errorf("type redeclaration of token %s",
- tokset[t].name)
- } else {
- toklev[t] = SETTYPE(toklev[t], ty)
- }
- } else {
- j = nontrst[t-NTBASE].value
- if j != 0 && j != ty {
- errorf("type redeclaration of nonterminal %v",
- nontrst[t-NTBASE].name)
- } else {
- nontrst[t-NTBASE].value = ty
- }
- }
- continue
-
- case ',':
- continue
- }
- break
- }
- continue
-
- case UNION:
- cpyunion()
-
- case LEFT, BINARY, RIGHT, TERM:
- // nonzero means new prec. and assoc.
- lev := t - TERM
- if lev != 0 {
- i++
- }
- ty = 0
-
- // get identifiers so defined
- t = gettok()
-
- // there is a type defined
- if t == TYPENAME {
- ty = numbval
- t = gettok()
- }
- for {
- switch t {
- case ',':
- t = gettok()
- continue
-
- case ';':
- break
-
- case IDENTIFIER:
- j = chfind(0, tokname)
- if j >= NTBASE {
- errorf("%v defined earlier as nonterminal", tokname)
- }
- if lev != 0 {
- if ASSOC(toklev[j]) != 0 {
- errorf("redeclaration of precedence of %v", tokname)
- }
- toklev[j] = SETASC(toklev[j], lev)
- toklev[j] = SETPLEV(toklev[j], i)
- }
- if ty != 0 {
- if TYPE(toklev[j]) != 0 {
- errorf("redeclaration of type of %v", tokname)
- }
- toklev[j] = SETTYPE(toklev[j], ty)
- }
- t = gettok()
- if t == NUMBER {
- tokset[j].value = numbval
- t = gettok()
- }
-
- continue
- }
- break
- }
- continue
-
- case LCURLY:
- cpycode()
- }
- t = gettok()
- }
-
- if t == ENDFILE {
- errorf("unexpected EOF before %%")
- }
-
- fmt.Fprintf(fcode, "switch %snt {\n", prefix)
-
- moreprod()
- prdptr[0] = []int{NTBASE, start, 1, 0}
-
- nprod = 1
- curprod := make([]int, RULEINC)
- t = gettok()
- if t != IDENTCOLON {
- errorf("bad syntax on first rule")
- }
-
- if start == 0 {
- prdptr[0][1] = chfind(1, tokname)
- }
-
- // read rules
- // put into prdptr array in the format
- // target
- // followed by id's of terminals and non-terminals
- // followed by -nprod
-
- for t != MARK && t != ENDFILE {
- mem := 0
-
- // process a rule
- rlines[nprod] = lineno
- ruleline := lineno
- if t == '|' {
- curprod[mem] = prdptr[nprod-1][0]
- mem++
- } else if t == IDENTCOLON {
- curprod[mem] = chfind(1, tokname)
- if curprod[mem] < NTBASE {
- lerrorf(ruleline, "token illegal on LHS of grammar rule")
- }
- mem++
- } else {
- lerrorf(ruleline, "illegal rule: missing semicolon or | ?")
- }
-
- // read rule body
- t = gettok()
- for {
- for t == IDENTIFIER {
- curprod[mem] = chfind(1, tokname)
- if curprod[mem] < NTBASE {
- levprd[nprod] = toklev[curprod[mem]]
- }
- mem++
- if mem >= len(curprod) {
- ncurprod := make([]int, mem+RULEINC)
- copy(ncurprod, curprod)
- curprod = ncurprod
- }
- t = gettok()
- }
- if t == PREC {
- if gettok() != IDENTIFIER {
- lerrorf(ruleline, "illegal %%prec syntax")
- }
- j = chfind(2, tokname)
- if j >= NTBASE {
- lerrorf(ruleline, "nonterminal "+nontrst[j-NTBASE].name+" illegal after %%prec")
- }
- levprd[nprod] = toklev[j]
- t = gettok()
- }
- if t != '=' {
- break
- }
- levprd[nprod] |= ACTFLAG
- fmt.Fprintf(fcode, "\n\tcase %v:", nprod)
- fmt.Fprintf(fcode, "\n\t\t%sDollar = %sS[%spt-%v:%spt+1]", prefix, prefix, prefix, mem-1, prefix)
- cpyact(curprod, mem)
-
- // action within rule...
- t = gettok()
- if t == IDENTIFIER {
- // make it a nonterminal
- j = chfind(1, fmt.Sprintf("$$%v", nprod))
-
- //
- // the current rule will become rule number nprod+1
- // enter null production for action
- //
- prdptr[nprod] = make([]int, 2)
- prdptr[nprod][0] = j
- prdptr[nprod][1] = -nprod
-
- // update the production information
- nprod++
- moreprod()
- levprd[nprod] = levprd[nprod-1] & ^ACTFLAG
- levprd[nprod-1] = ACTFLAG
- rlines[nprod] = lineno
-
- // make the action appear in the original rule
- curprod[mem] = j
- mem++
- if mem >= len(curprod) {
- ncurprod := make([]int, mem+RULEINC)
- copy(ncurprod, curprod)
- curprod = ncurprod
- }
- }
- }
-
- for t == ';' {
- t = gettok()
- }
- curprod[mem] = -nprod
- mem++
-
- // check that default action is reasonable
- if ntypes != 0 && (levprd[nprod]&ACTFLAG) == 0 &&
- nontrst[curprod[0]-NTBASE].value != 0 {
- // no explicit action, LHS has value
- tempty := curprod[1]
- if tempty < 0 {
- lerrorf(ruleline, "must return a value, since LHS has a type")
- }
- if tempty >= NTBASE {
- tempty = nontrst[tempty-NTBASE].value
- } else {
- tempty = TYPE(toklev[tempty])
- }
- if tempty != nontrst[curprod[0]-NTBASE].value {
- lerrorf(ruleline, "default action causes potential type clash")
- }
- }
- moreprod()
- prdptr[nprod] = make([]int, mem)
- copy(prdptr[nprod], curprod)
- nprod++
- moreprod()
- levprd[nprod] = 0
- }
-
- if TEMPSIZE < ntokens+nnonter+1 {
- errorf("too many tokens (%d) or non-terminals (%d)", ntokens, nnonter)
- }
-
- //
- // end of all rules
- // dump out the prefix code
- //
-
- fmt.Fprintf(fcode, "\n\t}")
-
- // put out non-literal terminals
- for i := TOKSTART; i <= ntokens; i++ {
- // non-literals
- if !tokset[i].noconst {
- fmt.Fprintf(ftable, "const %v = %v\n", tokset[i].name, tokset[i].value)
- }
- }
-
- // put out names of tokens
- ftable.WriteRune('\n')
- fmt.Fprintf(ftable, "var %sToknames = [...]string{\n", prefix)
- for i := 1; i <= ntokens; i++ {
- fmt.Fprintf(ftable, "\t%q,\n", tokset[i].name)
- }
- fmt.Fprintf(ftable, "}\n")
-
- // put out names of states.
- // commented out to avoid a huge table just for debugging.
- // re-enable to have the names in the binary.
- fmt.Fprintf(ftable, "var %sStatenames = [...]string{", prefix)
- // for i:=TOKSTART; i<=ntokens; i++ {
- // fmt.Fprintf(ftable, "\t%q,\n", tokset[i].name);
- // }
- fmt.Fprintf(ftable, "}\n")
-
- ftable.WriteRune('\n')
- fmt.Fprintf(ftable, "const %sEofCode = 1\n", prefix)
- fmt.Fprintf(ftable, "const %sErrCode = 2\n", prefix)
- fmt.Fprintf(ftable, "const %sInitialStackSize = %v\n", prefix, initialstacksize)
-
- //
- // copy any postfix code
- //
- if t == MARK {
- if !lflag {
- fmt.Fprintf(ftable, "\n//line %v:%v\n", infile, lineno)
- }
- for {
- c := getrune(finput)
- if c == EOF {
- break
- }
- ftable.WriteRune(c)
- }
- }
-}
-
-//
-// allocate enough room to hold another production
-//
-func moreprod() {
- n := len(prdptr)
- if nprod >= n {
- nn := n + PRODINC
- aprod := make([][]int, nn)
- alevprd := make([]int, nn)
- arlines := make([]int, nn)
-
- copy(aprod, prdptr)
- copy(alevprd, levprd)
- copy(arlines, rlines)
-
- prdptr = aprod
- levprd = alevprd
- rlines = arlines
- }
-}
-
-//
-// define s to be a terminal if nt==0
-// or a nonterminal if nt==1
-//
-func defin(nt int, s string) int {
- val := 0
- if nt != 0 {
- nnonter++
- if nnonter >= len(nontrst) {
- anontrst := make([]Symb, nnonter+SYMINC)
- copy(anontrst, nontrst)
- nontrst = anontrst
- }
- nontrst[nnonter] = Symb{name: s}
- return NTBASE + nnonter
- }
-
- // must be a token
- ntokens++
- if ntokens >= len(tokset) {
- nn := ntokens + SYMINC
- atokset := make([]Symb, nn)
- atoklev := make([]int, nn)
-
- copy(atoklev, toklev)
- copy(atokset, tokset)
-
- tokset = atokset
- toklev = atoklev
- }
- tokset[ntokens].name = s
- toklev[ntokens] = 0
-
- // establish value for token
- // single character literal
- if s[0] == '\'' || s[0] == '"' {
- q, err := strconv.Unquote(s)
- if err != nil {
- errorf("invalid token: %s", err)
- }
- rq := []rune(q)
- if len(rq) != 1 {
- errorf("character token too long: %s", s)
- }
- val = int(rq[0])
- if val == 0 {
- errorf("token value 0 is illegal")
- }
- tokset[ntokens].noconst = true
- } else {
- val = extval
- extval++
- if s[0] == '$' {
- tokset[ntokens].noconst = true
- }
- }
-
- tokset[ntokens].value = val
- return ntokens
-}
-
-var peekline = 0
-
-func gettok() int {
- var i int
- var match, c rune
-
- tokname = ""
- for {
- lineno += peekline
- peekline = 0
- c = getrune(finput)
- for c == ' ' || c == '\n' || c == '\t' || c == '\v' || c == '\r' {
- if c == '\n' {
- lineno++
- }
- c = getrune(finput)
- }
-
- // skip comment -- fix
- if c != '/' {
- break
- }
- lineno += skipcom()
- }
-
- switch c {
- case EOF:
- if tokflag {
- fmt.Printf(">>> ENDFILE %v\n", lineno)
- }
- return ENDFILE
-
- case '{':
- ungetrune(finput, c)
- if tokflag {
- fmt.Printf(">>> ={ %v\n", lineno)
- }
- return '='
-
- case '<':
- // get, and look up, a type name (union member name)
- c = getrune(finput)
- for c != '>' && c != EOF && c != '\n' {
- tokname += string(c)
- c = getrune(finput)
- }
-
- if c != '>' {
- errorf("unterminated < ... > clause")
- }
-
- for i = 1; i <= ntypes; i++ {
- if typeset[i] == tokname {
- numbval = i
- if tokflag {
- fmt.Printf(">>> TYPENAME old <%v> %v\n", tokname, lineno)
- }
- return TYPENAME
- }
- }
- ntypes++
- numbval = ntypes
- typeset[numbval] = tokname
- if tokflag {
- fmt.Printf(">>> TYPENAME new <%v> %v\n", tokname, lineno)
- }
- return TYPENAME
-
- case '"', '\'':
- match = c
- tokname = string(c)
- for {
- c = getrune(finput)
- if c == '\n' || c == EOF {
- errorf("illegal or missing ' or \"")
- }
- if c == '\\' {
- tokname += string('\\')
- c = getrune(finput)
- } else if c == match {
- if tokflag {
- fmt.Printf(">>> IDENTIFIER \"%v\" %v\n", tokname, lineno)
- }
- tokname += string(c)
- return IDENTIFIER
- }
- tokname += string(c)
- }
-
- case '%':
- c = getrune(finput)
- switch c {
- case '%':
- if tokflag {
- fmt.Printf(">>> MARK %%%% %v\n", lineno)
- }
- return MARK
- case '=':
- if tokflag {
- fmt.Printf(">>> PREC %%= %v\n", lineno)
- }
- return PREC
- case '{':
- if tokflag {
- fmt.Printf(">>> LCURLY %%{ %v\n", lineno)
- }
- return LCURLY
- }
-
- getword(c)
- // find a reserved word
- for i := range resrv {
- if tokname == resrv[i].name {
- if tokflag {
- fmt.Printf(">>> %%%v %v %v\n", tokname,
- resrv[i].value-PRIVATE, lineno)
- }
- return resrv[i].value
- }
- }
- errorf("invalid escape, or illegal reserved word: %v", tokname)
-
- case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
- numbval = int(c - '0')
- for {
- c = getrune(finput)
- if !isdigit(c) {
- break
- }
- numbval = numbval*10 + int(c-'0')
- }
- ungetrune(finput, c)
- if tokflag {
- fmt.Printf(">>> NUMBER %v %v\n", numbval, lineno)
- }
- return NUMBER
-
- default:
- if isword(c) || c == '.' || c == '$' {
- getword(c)
- break
- }
- if tokflag {
- fmt.Printf(">>> OPERATOR %v %v\n", string(c), lineno)
- }
- return int(c)
- }
-
- // look ahead to distinguish IDENTIFIER from IDENTCOLON
- c = getrune(finput)
- for c == ' ' || c == '\t' || c == '\n' || c == '\v' || c == '\r' || c == '/' {
- if c == '\n' {
- peekline++
- }
- // look for comments
- if c == '/' {
- peekline += skipcom()
- }
- c = getrune(finput)
- }
- if c == ':' {
- if tokflag {
- fmt.Printf(">>> IDENTCOLON %v: %v\n", tokname, lineno)
- }
- return IDENTCOLON
- }
-
- ungetrune(finput, c)
- if tokflag {
- fmt.Printf(">>> IDENTIFIER %v %v\n", tokname, lineno)
- }
- return IDENTIFIER
-}
-
-func getword(c rune) {
- tokname = ""
- for isword(c) || isdigit(c) || c == '.' || c == '$' {
- tokname += string(c)
- c = getrune(finput)
- }
- ungetrune(finput, c)
-}
-
-//
-// determine the type of a symbol
-//
-func fdtype(t int) int {
- var v int
- var s string
-
- if t >= NTBASE {
- v = nontrst[t-NTBASE].value
- s = nontrst[t-NTBASE].name
- } else {
- v = TYPE(toklev[t])
- s = tokset[t].name
- }
- if v <= 0 {
- errorf("must specify type for %v", s)
- }
- return v
-}
-
-func chfind(t int, s string) int {
- if s[0] == '"' || s[0] == '\'' {
- t = 0
- }
- for i := 0; i <= ntokens; i++ {
- if s == tokset[i].name {
- return i
- }
- }
- for i := 0; i <= nnonter; i++ {
- if s == nontrst[i].name {
- return NTBASE + i
- }
- }
-
- // cannot find name
- if t > 1 {
- errorf("%v should have been defined earlier", s)
- }
- return defin(t, s)
-}
-
-//
-// copy the union declaration to the output, and the define file if present
-//
-func cpyunion() {
-
- if !lflag {
- fmt.Fprintf(ftable, "\n//line %v:%v\n", infile, lineno)
- }
- fmt.Fprintf(ftable, "type %sSymType struct", prefix)
-
- level := 0
-
-out:
- for {
- c := getrune(finput)
- if c == EOF {
- errorf("EOF encountered while processing %%union")
- }
- ftable.WriteRune(c)
- switch c {
- case '\n':
- lineno++
- case '{':
- if level == 0 {
- fmt.Fprintf(ftable, "\n\tyys int")
- }
- level++
- case '}':
- level--
- if level == 0 {
- break out
- }
- }
- }
- fmt.Fprintf(ftable, "\n\n")
-}
-
-//
-// saves code between %{ and %}
-// adds an import for __fmt__ the first time
-//
-func cpycode() {
- lno := lineno
-
- c := getrune(finput)
- if c == '\n' {
- c = getrune(finput)
- lineno++
- }
- if !lflag {
- fmt.Fprintf(ftable, "\n//line %v:%v\n", infile, lineno)
- }
- // accumulate until %}
- code := make([]rune, 0, 1024)
- for c != EOF {
- if c == '%' {
- c = getrune(finput)
- if c == '}' {
- emitcode(code, lno+1)
- return
- }
- code = append(code, '%')
- }
- code = append(code, c)
- if c == '\n' {
- lineno++
- }
- c = getrune(finput)
- }
- lineno = lno
- errorf("eof before %%}")
-}
-
-//
-// emits code saved up from between %{ and %}
-// called by cpycode
-// adds an import for __yyfmt__ after the package clause
-//
-func emitcode(code []rune, lineno int) {
- for i, line := range lines(code) {
- writecode(line)
- if !fmtImported && isPackageClause(line) {
- fmt.Fprintln(ftable, `import __yyfmt__ "fmt"`)
- if !lflag {
- fmt.Fprintf(ftable, "//line %v:%v\n\t\t", infile, lineno+i)
- }
- fmtImported = true
- }
- }
-}
-
-//
-// does this line look like a package clause? not perfect: might be confused by early comments.
-//
-func isPackageClause(line []rune) bool {
- line = skipspace(line)
-
- // must be big enough.
- if len(line) < len("package X\n") {
- return false
- }
-
- // must start with "package"
- for i, r := range []rune("package") {
- if line[i] != r {
- return false
- }
- }
- line = skipspace(line[len("package"):])
-
- // must have another identifier.
- if len(line) == 0 || (!unicode.IsLetter(line[0]) && line[0] != '_') {
- return false
- }
- for len(line) > 0 {
- if !unicode.IsLetter(line[0]) && !unicode.IsDigit(line[0]) && line[0] != '_' {
- break
- }
- line = line[1:]
- }
- line = skipspace(line)
-
- // eol, newline, or comment must follow
- if len(line) == 0 {
- return true
- }
- if line[0] == '\r' || line[0] == '\n' {
- return true
- }
- if len(line) >= 2 {
- return line[0] == '/' && (line[1] == '/' || line[1] == '*')
- }
- return false
-}
-
-//
-// skip initial spaces
-//
-func skipspace(line []rune) []rune {
- for len(line) > 0 {
- if line[0] != ' ' && line[0] != '\t' {
- break
- }
- line = line[1:]
- }
- return line
-}
-
-//
-// break code into lines
-//
-func lines(code []rune) [][]rune {
- l := make([][]rune, 0, 100)
- for len(code) > 0 {
- // one line per loop
- var i int
- for i = range code {
- if code[i] == '\n' {
- break
- }
- }
- l = append(l, code[:i+1])
- code = code[i+1:]
- }
- return l
-}
-
-//
-// writes code to ftable
-//
-func writecode(code []rune) {
- for _, r := range code {
- ftable.WriteRune(r)
- }
-}
-
-//
-// skip over comments
-// skipcom is called after reading a '/'
-//
-func skipcom() int {
- var c rune
-
- c = getrune(finput)
- if c == '/' {
- for c != EOF {
- if c == '\n' {
- return 1
- }
- c = getrune(finput)
- }
- errorf("EOF inside comment")
- return 0
- }
- if c != '*' {
- errorf("illegal comment")
- }
-
- nl := 0 // lines skipped
- c = getrune(finput)
-
-l1:
- switch c {
- case '*':
- c = getrune(finput)
- if c == '/' {
- break
- }
- goto l1
-
- case '\n':
- nl++
- fallthrough
-
- default:
- c = getrune(finput)
- goto l1
- }
- return nl
-}
-
-func dumpprod(curprod []int, max int) {
- fmt.Printf("\n")
- for i := 0; i < max; i++ {
- p := curprod[i]
- if p < 0 {
- fmt.Printf("[%v] %v\n", i, p)
- } else {
- fmt.Printf("[%v] %v\n", i, symnam(p))
- }
- }
-}
-
-//
-// copy action to the next ; or closing }
-//
-func cpyact(curprod []int, max int) {
-
- if !lflag {
- fmt.Fprintf(fcode, "\n\t\t//line %v:%v", infile, lineno)
- }
- fmt.Fprint(fcode, "\n\t\t")
-
- lno := lineno
- brac := 0
-
-loop:
- for {
- c := getrune(finput)
-
- swt:
- switch c {
- case ';':
- if brac == 0 {
- fcode.WriteRune(c)
- return
- }
-
- case '{':
- if brac == 0 {
- }
- brac++
-
- case '$':
- s := 1
- tok := -1
- c = getrune(finput)
-
- // type description
- if c == '<' {
- ungetrune(finput, c)
- if gettok() != TYPENAME {
- errorf("bad syntax on $<ident> clause")
- }
- tok = numbval
- c = getrune(finput)
- }
- if c == '$' {
- fmt.Fprintf(fcode, "%sVAL", prefix)
-
- // put out the proper tag...
- if ntypes != 0 {
- if tok < 0 {
- tok = fdtype(curprod[0])
- }
- fmt.Fprintf(fcode, ".%v", typeset[tok])
- }
- continue loop
- }
- if c == '-' {
- s = -s
- c = getrune(finput)
- }
- j := 0
- if isdigit(c) {
- for isdigit(c) {
- j = j*10 + int(c-'0')
- c = getrune(finput)
- }
- ungetrune(finput, c)
- j = j * s
- if j >= max {
- errorf("Illegal use of $%v", j)
- }
- } else if isword(c) || c == '.' {
- // look for $name
- ungetrune(finput, c)
- if gettok() != IDENTIFIER {
- errorf("$ must be followed by an identifier")
- }
- tokn := chfind(2, tokname)
- fnd := -1
- c = getrune(finput)
- if c != '@' {
- ungetrune(finput, c)
- } else if gettok() != NUMBER {
- errorf("@ must be followed by number")
- } else {
- fnd = numbval
- }
- for j = 1; j < max; j++ {
- if tokn == curprod[j] {
- fnd--
- if fnd <= 0 {
- break
- }
- }
- }
- if j >= max {
- errorf("$name or $name at number not found")
- }
- } else {
- fcode.WriteRune('$')
- if s < 0 {
- fcode.WriteRune('-')
- }
- ungetrune(finput, c)
- continue loop
- }
- fmt.Fprintf(fcode, "%sDollar[%v]", prefix, j)
-
- // put out the proper tag
- if ntypes != 0 {
- if j <= 0 && tok < 0 {
- errorf("must specify type of $%v", j)
- }
- if tok < 0 {
- tok = fdtype(curprod[j])
- }
- fmt.Fprintf(fcode, ".%v", typeset[tok])
- }
- continue loop
-
- case '}':
- brac--
- if brac != 0 {
- break
- }
- fcode.WriteRune(c)
- return
-
- case '/':
- nc := getrune(finput)
- if nc != '/' && nc != '*' {
- ungetrune(finput, nc)
- break
- }
- // a comment
- fcode.WriteRune(c)
- fcode.WriteRune(nc)
- c = getrune(finput)
- for c != EOF {
- switch {
- case c == '\n':
- lineno++
- if nc == '/' { // end of // comment
- break swt
- }
- case c == '*' && nc == '*': // end of /* comment?
- nnc := getrune(finput)
- if nnc == '/' {
- fcode.WriteRune('*')
- fcode.WriteRune('/')
- c = getrune(finput)
- break swt
- }
- ungetrune(finput, nnc)
- }
- fcode.WriteRune(c)
- c = getrune(finput)
- }
- errorf("EOF inside comment")
-
- case '\'', '"':
- // character string or constant
- match := c
- fcode.WriteRune(c)
- c = getrune(finput)
- for c != EOF {
- if c == '\\' {
- fcode.WriteRune(c)
- c = getrune(finput)
- if c == '\n' {
- lineno++
- }
- } else if c == match {
- break swt
- }
- if c == '\n' {
- errorf("newline in string or char const")
- }
- fcode.WriteRune(c)
- c = getrune(finput)
- }
- errorf("EOF in string or character constant")
-
- case EOF:
- lineno = lno
- errorf("action does not terminate")
-
- case '\n':
- fmt.Fprint(fcode, "\n\t")
- lineno++
- continue loop
- }
-
- fcode.WriteRune(c)
- }
-}
-
-func openup() {
- infile = flag.Arg(0)
- finput = open(infile)
- if finput == nil {
- errorf("cannot open %v", infile)
- }
-
- foutput = nil
- if vflag != "" {
- foutput = create(vflag)
- if foutput == nil {
- errorf("can't create file %v", vflag)
- }
- }
-
- ftable = nil
- if oflag == "" {
- oflag = "y.go"
- }
- ftable = create(oflag)
- if ftable == nil {
- errorf("can't create file %v", oflag)
- }
-
-}
-
-//
-// return a pointer to the name of symbol i
-//
-func symnam(i int) string {
- var s string
-
- if i >= NTBASE {
- s = nontrst[i-NTBASE].name
- } else {
- s = tokset[i].name
- }
- return s
-}
-
-//
-// set elements 0 through n-1 to c
-//
-func aryfil(v []int, n, c int) {
- for i := 0; i < n; i++ {
- v[i] = c
- }
-}
-
-//
-// compute an array with the beginnings of productions yielding given nonterminals
-// The array pres points to these lists
-// the array pyield has the lists: the total size is only NPROD+1
-//
-func cpres() {
- pres = make([][][]int, nnonter+1)
- curres := make([][]int, nprod)
-
- if false {
- for j := 0; j <= nnonter; j++ {
- fmt.Printf("nnonter[%v] = %v\n", j, nontrst[j].name)
- }
- for j := 0; j < nprod; j++ {
- fmt.Printf("prdptr[%v][0] = %v+NTBASE\n", j, prdptr[j][0]-NTBASE)
- }
- }
-
- fatfl = 0 // make undefined symbols nonfatal
- for i := 0; i <= nnonter; i++ {
- n := 0
- c := i + NTBASE
- for j := 0; j < nprod; j++ {
- if prdptr[j][0] == c {
- curres[n] = prdptr[j][1:]
- n++
- }
- }
- if n == 0 {
- errorf("nonterminal %v not defined", nontrst[i].name)
- continue
- }
- pres[i] = make([][]int, n)
- copy(pres[i], curres)
- }
- fatfl = 1
- if nerrors != 0 {
- summary()
- exit(1)
- }
-}
-
-func dumppres() {
- for i := 0; i <= nnonter; i++ {
- fmt.Printf("nonterm %d\n", i)
- curres := pres[i]
- for j := 0; j < len(curres); j++ {
- fmt.Printf("\tproduction %d:", j)
- prd := curres[j]
- for k := 0; k < len(prd); k++ {
- fmt.Printf(" %d", prd[k])
- }
- fmt.Print("\n")
- }
- }
-}
-
-//
-// mark nonterminals which derive the empty string
-// also, look for nonterminals which don't derive any token strings
-//
-func cempty() {
- var i, p, np int
- var prd []int
-
- pempty = make([]int, nnonter+1)
-
- // first, use the array pempty to detect productions that can never be reduced
- // set pempty to WHONOWS
- aryfil(pempty, nnonter+1, WHOKNOWS)
-
- // now, look at productions, marking nonterminals which derive something
-more:
- for {
- for i = 0; i < nprod; i++ {
- prd = prdptr[i]
- if pempty[prd[0]-NTBASE] != 0 {
- continue
- }
- np = len(prd) - 1
- for p = 1; p < np; p++ {
- if prd[p] >= NTBASE && pempty[prd[p]-NTBASE] == WHOKNOWS {
- break
- }
- }
- // production can be derived
- if p == np {
- pempty[prd[0]-NTBASE] = OK
- continue more
- }
- }
- break
- }
-
- // now, look at the nonterminals, to see if they are all OK
- for i = 0; i <= nnonter; i++ {
- // the added production rises or falls as the start symbol ...
- if i == 0 {
- continue
- }
- if pempty[i] != OK {
- fatfl = 0
- errorf("nonterminal " + nontrst[i].name + " never derives any token string")
- }
- }
-
- if nerrors != 0 {
- summary()
- exit(1)
- }
-
- // now, compute the pempty array, to see which nonterminals derive the empty string
- // set pempty to WHOKNOWS
- aryfil(pempty, nnonter+1, WHOKNOWS)
-
- // loop as long as we keep finding empty nonterminals
-
-again:
- for {
- next:
- for i = 1; i < nprod; i++ {
- // not known to be empty
- prd = prdptr[i]
- if pempty[prd[0]-NTBASE] != WHOKNOWS {
- continue
- }
- np = len(prd) - 1
- for p = 1; p < np; p++ {
- if prd[p] < NTBASE || pempty[prd[p]-NTBASE] != EMPTY {
- continue next
- }
- }
-
- // we have a nontrivially empty nonterminal
- pempty[prd[0]-NTBASE] = EMPTY
-
- // got one ... try for another
- continue again
- }
- return
- }
-}
-
-func dumpempty() {
- for i := 0; i <= nnonter; i++ {
- if pempty[i] == EMPTY {
- fmt.Printf("non-term %d %s matches empty\n", i, symnam(i+NTBASE))
- }
- }
-}
-
-//
-// compute an array with the first of nonterminals
-//
-func cpfir() {
- var s, n, p, np, ch, i int
- var curres [][]int
- var prd []int
-
- wsets = make([]Wset, nnonter+WSETINC)
- pfirst = make([]Lkset, nnonter+1)
- for i = 0; i <= nnonter; i++ {
- wsets[i].ws = mkset()
- pfirst[i] = mkset()
- curres = pres[i]
- n = len(curres)
-
- // initially fill the sets
- for s = 0; s < n; s++ {
- prd = curres[s]
- np = len(prd) - 1
- for p = 0; p < np; p++ {
- ch = prd[p]
- if ch < NTBASE {
- setbit(pfirst[i], ch)
- break
- }
- if pempty[ch-NTBASE] == 0 {
- break
- }
- }
- }
- }
-
- // now, reflect transitivity
- changes := 1
- for changes != 0 {
- changes = 0
- for i = 0; i <= nnonter; i++ {
- curres = pres[i]
- n = len(curres)
- for s = 0; s < n; s++ {
- prd = curres[s]
- np = len(prd) - 1
- for p = 0; p < np; p++ {
- ch = prd[p] - NTBASE
- if ch < 0 {
- break
- }
- changes |= setunion(pfirst[i], pfirst[ch])
- if pempty[ch] == 0 {
- break
- }
- }
- }
- }
- }
-
- if indebug == 0 {
- return
- }
- if foutput != nil {
- for i = 0; i <= nnonter; i++ {
- fmt.Fprintf(foutput, "\n%v: %v %v\n",
- nontrst[i].name, pfirst[i], pempty[i])
- }
- }
-}
-
-//
-// generate the states
-//
-func stagen() {
- // initialize
- nstate = 0
- tstates = make([]int, ntokens+1) // states generated by terminal gotos
- ntstates = make([]int, nnonter+1) // states generated by nonterminal gotos
- amem = make([]int, ACTSIZE)
- memp = 0
-
- clset = mkset()
- pstate[0] = 0
- pstate[1] = 0
- aryfil(clset, tbitset, 0)
- putitem(Pitem{prdptr[0], 0, 0, 0}, clset)
- tystate[0] = MUSTDO
- nstate = 1
- pstate[2] = pstate[1]
-
- //
- // now, the main state generation loop
- // first pass generates all of the states
- // later passes fix up lookahead
- // could be sped up a lot by remembering
- // results of the first pass rather than recomputing
- //
- first := 1
- for more := 1; more != 0; first = 0 {
- more = 0
- for i := 0; i < nstate; i++ {
- if tystate[i] != MUSTDO {
- continue
- }
-
- tystate[i] = DONE
- aryfil(temp1, nnonter+1, 0)
-
- // take state i, close it, and do gotos
- closure(i)
-
- // generate goto's
- for p := 0; p < cwp; p++ {
- pi := wsets[p]
- if pi.flag != 0 {
- continue
- }
- wsets[p].flag = 1
- c := pi.pitem.first
- if c <= 1 {
- if pstate[i+1]-pstate[i] <= p {
- tystate[i] = MUSTLOOKAHEAD
- }
- continue
- }
-
- // do a goto on c
- putitem(wsets[p].pitem, wsets[p].ws)
- for q := p + 1; q < cwp; q++ {
- // this item contributes to the goto
- if c == wsets[q].pitem.first {
- putitem(wsets[q].pitem, wsets[q].ws)
- wsets[q].flag = 1
- }
- }
-
- if c < NTBASE {
- state(c) // register new state
- } else {
- temp1[c-NTBASE] = state(c)
- }
- }
-
- if gsdebug != 0 && foutput != nil {
- fmt.Fprintf(foutput, "%v: ", i)
- for j := 0; j <= nnonter; j++ {
- if temp1[j] != 0 {
- fmt.Fprintf(foutput, "%v %v,", nontrst[j].name, temp1[j])
- }
- }
- fmt.Fprintf(foutput, "\n")
- }
-
- if first != 0 {
- indgo[i] = apack(temp1[1:], nnonter-1) - 1
- }
-
- more++
- }
- }
-}
-
-//
-// generate the closure of state i
-//
-func closure(i int) {
- zzclose++
-
- // first, copy kernel of state i to wsets
- cwp = 0
- q := pstate[i+1]
- for p := pstate[i]; p < q; p++ {
- wsets[cwp].pitem = statemem[p].pitem
- wsets[cwp].flag = 1 // this item must get closed
- copy(wsets[cwp].ws, statemem[p].look)
- cwp++
- }
-
- // now, go through the loop, closing each item
- work := 1
- for work != 0 {
- work = 0
- for u := 0; u < cwp; u++ {
- if wsets[u].flag == 0 {
- continue
- }
-
- // dot is before c
- c := wsets[u].pitem.first
- if c < NTBASE {
- wsets[u].flag = 0
- // only interesting case is where . is before nonterminal
- continue
- }
-
- // compute the lookahead
- aryfil(clset, tbitset, 0)
-
- // find items involving c
- for v := u; v < cwp; v++ {
- if wsets[v].flag != 1 || wsets[v].pitem.first != c {
- continue
- }
- pi := wsets[v].pitem.prod
- ipi := wsets[v].pitem.off + 1
-
- wsets[v].flag = 0
- if nolook != 0 {
- continue
- }
-
- ch := pi[ipi]
- ipi++
- for ch > 0 {
- // terminal symbol
- if ch < NTBASE {
- setbit(clset, ch)
- break
- }
-
- // nonterminal symbol
- setunion(clset, pfirst[ch-NTBASE])
- if pempty[ch-NTBASE] == 0 {
- break
- }
- ch = pi[ipi]
- ipi++
- }
- if ch <= 0 {
- setunion(clset, wsets[v].ws)
- }
- }
-
- //
- // now loop over productions derived from c
- //
- curres := pres[c-NTBASE]
- n := len(curres)
-
- nexts:
- // initially fill the sets
- for s := 0; s < n; s++ {
- prd := curres[s]
-
- //
- // put these items into the closure
- // is the item there
- //
- for v := 0; v < cwp; v++ {
- // yes, it is there
- if wsets[v].pitem.off == 0 &&
- aryeq(wsets[v].pitem.prod, prd) != 0 {
- if nolook == 0 &&
- setunion(wsets[v].ws, clset) != 0 {
- wsets[v].flag = 1
- work = 1
- }
- continue nexts
- }
- }
-
- // not there; make a new entry
- if cwp >= len(wsets) {
- awsets := make([]Wset, cwp+WSETINC)
- copy(awsets, wsets)
- wsets = awsets
- }
- wsets[cwp].pitem = Pitem{prd, 0, prd[0], -prd[len(prd)-1]}
- wsets[cwp].flag = 1
- wsets[cwp].ws = mkset()
- if nolook == 0 {
- work = 1
- copy(wsets[cwp].ws, clset)
- }
- cwp++
- }
- }
- }
-
- // have computed closure; flags are reset; return
- if cldebug != 0 && foutput != nil {
- fmt.Fprintf(foutput, "\nState %v, nolook = %v\n", i, nolook)
- for u := 0; u < cwp; u++ {
- if wsets[u].flag != 0 {
- fmt.Fprintf(foutput, "flag set\n")
- }
- wsets[u].flag = 0
- fmt.Fprintf(foutput, "\t%v", writem(wsets[u].pitem))
- prlook(wsets[u].ws)
- fmt.Fprintf(foutput, "\n")
- }
- }
-}
-
-//
-// sorts last state,and sees if it equals earlier ones. returns state number
-//
-func state(c int) int {
- zzstate++
- p1 := pstate[nstate]
- p2 := pstate[nstate+1]
- if p1 == p2 {
- return 0 // null state
- }
-
- // sort the items
- var k, l int
- for k = p1 + 1; k < p2; k++ { // make k the biggest
- for l = k; l > p1; l-- {
- if statemem[l].pitem.prodno < statemem[l-1].pitem.prodno ||
- statemem[l].pitem.prodno == statemem[l-1].pitem.prodno &&
- statemem[l].pitem.off < statemem[l-1].pitem.off {
- s := statemem[l]
- statemem[l] = statemem[l-1]
- statemem[l-1] = s
- } else {
- break
- }
- }
- }
-
- size1 := p2 - p1 // size of state
-
- var i int
- if c >= NTBASE {
- i = ntstates[c-NTBASE]
- } else {
- i = tstates[c]
- }
-
-look:
- for ; i != 0; i = mstates[i] {
- // get ith state
- q1 := pstate[i]
- q2 := pstate[i+1]
- size2 := q2 - q1
- if size1 != size2 {
- continue
- }
- k = p1
- for l = q1; l < q2; l++ {
- if aryeq(statemem[l].pitem.prod, statemem[k].pitem.prod) == 0 ||
- statemem[l].pitem.off != statemem[k].pitem.off {
- continue look
- }
- k++
- }
-
- // found it
- pstate[nstate+1] = pstate[nstate] // delete last state
-
- // fix up lookaheads
- if nolook != 0 {
- return i
- }
- k = p1
- for l = q1; l < q2; l++ {
- if setunion(statemem[l].look, statemem[k].look) != 0 {
- tystate[i] = MUSTDO
- }
- k++
- }
- return i
- }
-
- // state is new
- zznewstate++
- if nolook != 0 {
- errorf("yacc state/nolook error")
- }
- pstate[nstate+2] = p2
- if nstate+1 >= NSTATES {
- errorf("too many states")
- }
- if c >= NTBASE {
- mstates[nstate] = ntstates[c-NTBASE]
- ntstates[c-NTBASE] = nstate
- } else {
- mstates[nstate] = tstates[c]
- tstates[c] = nstate
- }
- tystate[nstate] = MUSTDO
- nstate++
- return nstate - 1
-}
-
-func putitem(p Pitem, set Lkset) {
- p.off++
- p.first = p.prod[p.off]
-
- if pidebug != 0 && foutput != nil {
- fmt.Fprintf(foutput, "putitem(%v), state %v\n", writem(p), nstate)
- }
- j := pstate[nstate+1]
- if j >= len(statemem) {
- asm := make([]Item, j+STATEINC)
- copy(asm, statemem)
- statemem = asm
- }
- statemem[j].pitem = p
- if nolook == 0 {
- s := mkset()
- copy(s, set)
- statemem[j].look = s
- }
- j++
- pstate[nstate+1] = j
-}
-
-//
-// creates output string for item pointed to by pp
-//
-func writem(pp Pitem) string {
- var i int
-
- p := pp.prod
- q := chcopy(nontrst[prdptr[pp.prodno][0]-NTBASE].name) + ": "
- npi := pp.off
-
- pi := aryeq(p, prdptr[pp.prodno])
-
- for {
- c := ' '
- if pi == npi {
- c = '.'
- }
- q += string(c)
-
- i = p[pi]
- pi++
- if i <= 0 {
- break
- }
- q += chcopy(symnam(i))
- }
-
- // an item calling for a reduction
- i = p[npi]
- if i < 0 {
- q += fmt.Sprintf(" (%v)", -i)
- }
-
- return q
-}
-
-//
-// pack state i from temp1 into amem
-//
-func apack(p []int, n int) int {
- //
- // we don't need to worry about checking because
- // we will only look at entries known to be there...
- // eliminate leading and trailing 0's
- //
- off := 0
- pp := 0
- for ; pp <= n && p[pp] == 0; pp++ {
- off--
- }
-
- // no actions
- if pp > n {
- return 0
- }
- for ; n > pp && p[n] == 0; n-- {
- }
- p = p[pp : n+1]
-
- // now, find a place for the elements from p to q, inclusive
- r := len(amem) - len(p)
-
-nextk:
- for rr := 0; rr <= r; rr++ {
- qq := rr
- for pp = 0; pp < len(p); pp++ {
- if p[pp] != 0 {
- if p[pp] != amem[qq] && amem[qq] != 0 {
- continue nextk
- }
- }
- qq++
- }
-
- // we have found an acceptable k
- if pkdebug != 0 && foutput != nil {
- fmt.Fprintf(foutput, "off = %v, k = %v\n", off+rr, rr)
- }
- qq = rr
- for pp = 0; pp < len(p); pp++ {
- if p[pp] != 0 {
- if qq > memp {
- memp = qq
- }
- amem[qq] = p[pp]
- }
- qq++
- }
- if pkdebug != 0 && foutput != nil {
- for pp = 0; pp <= memp; pp += 10 {
- fmt.Fprintf(foutput, "\n")
- for qq = pp; qq <= pp+9; qq++ {
- fmt.Fprintf(foutput, "%v ", amem[qq])
- }
- fmt.Fprintf(foutput, "\n")
- }
- }
- return off + rr
- }
- errorf("no space in action table")
- return 0
-}
-
-//
-// print the output for the states
-//
-func output() {
- var c, u, v int
-
- if !lflag {
- fmt.Fprintf(ftable, "\n//line yacctab:1")
- }
- fmt.Fprintf(ftable, "\nvar %sExca = [...]int{\n", prefix)
-
- if len(errors) > 0 {
- stateTable = make([]Row, nstate)
- }
-
- noset := mkset()
-
- // output the stuff for state i
- for i := 0; i < nstate; i++ {
- nolook = 0
- if tystate[i] != MUSTLOOKAHEAD {
- nolook = 1
- }
- closure(i)
-
- // output actions
- nolook = 1
- aryfil(temp1, ntokens+nnonter+1, 0)
- for u = 0; u < cwp; u++ {
- c = wsets[u].pitem.first
- if c > 1 && c < NTBASE && temp1[c] == 0 {
- for v = u; v < cwp; v++ {
- if c == wsets[v].pitem.first {
- putitem(wsets[v].pitem, noset)
- }
- }
- temp1[c] = state(c)
- } else if c > NTBASE {
- c -= NTBASE
- if temp1[c+ntokens] == 0 {
- temp1[c+ntokens] = amem[indgo[i]+c]
- }
- }
- }
- if i == 1 {
- temp1[1] = ACCEPTCODE
- }
-
- // now, we have the shifts; look at the reductions
- lastred = 0
- for u = 0; u < cwp; u++ {
- c = wsets[u].pitem.first
-
- // reduction
- if c > 0 {
- continue
- }
- lastred = -c
- us := wsets[u].ws
- for k := 0; k <= ntokens; k++ {
- if bitset(us, k) == 0 {
- continue
- }
- if temp1[k] == 0 {
- temp1[k] = c
- } else if temp1[k] < 0 { // reduce/reduce conflict
- if foutput != nil {
- fmt.Fprintf(foutput,
- "\n %v: reduce/reduce conflict (red'ns "+
- "%v and %v) on %v",
- i, -temp1[k], lastred, symnam(k))
- }
- if -temp1[k] > lastred {
- temp1[k] = -lastred
- }
- zzrrconf++
- } else {
- // potential shift/reduce conflict
- precftn(lastred, k, i)
- }
- }
- }
- wract(i)
- }
-
- fmt.Fprintf(ftable, "}\n")
- ftable.WriteRune('\n')
- fmt.Fprintf(ftable, "const %sNprod = %v\n", prefix, nprod)
- fmt.Fprintf(ftable, "const %sPrivate = %v\n", prefix, PRIVATE)
- ftable.WriteRune('\n')
- fmt.Fprintf(ftable, "var %sTokenNames []string\n", prefix)
- fmt.Fprintf(ftable, "var %sStates []string\n", prefix)
-}
-
-//
-// decide a shift/reduce conflict by precedence.
-// r is a rule number, t a token number
-// the conflict is in state s
-// temp1[t] is changed to reflect the action
-//
-func precftn(r, t, s int) {
- var action int
-
- lp := levprd[r]
- lt := toklev[t]
- if PLEVEL(lt) == 0 || PLEVEL(lp) == 0 {
- // conflict
- if foutput != nil {
- fmt.Fprintf(foutput,
- "\n%v: shift/reduce conflict (shift %v(%v), red'n %v(%v)) on %v",
- s, temp1[t], PLEVEL(lt), r, PLEVEL(lp), symnam(t))
- }
- zzsrconf++
- return
- }
- if PLEVEL(lt) == PLEVEL(lp) {
- action = ASSOC(lt)
- } else if PLEVEL(lt) > PLEVEL(lp) {
- action = RASC // shift
- } else {
- action = LASC
- } // reduce
- switch action {
- case BASC: // error action
- temp1[t] = ERRCODE
- case LASC: // reduce
- temp1[t] = -r
- }
-}
-
-//
-// output state i
-// temp1 has the actions, lastred the default
-//
-func wract(i int) {
- var p, p1 int
-
- // find the best choice for lastred
- lastred = 0
- ntimes := 0
- for j := 0; j <= ntokens; j++ {
- if temp1[j] >= 0 {
- continue
- }
- if temp1[j]+lastred == 0 {
- continue
- }
- // count the number of appearances of temp1[j]
- count := 0
- tred := -temp1[j]
- levprd[tred] |= REDFLAG
- for p = 0; p <= ntokens; p++ {
- if temp1[p]+tred == 0 {
- count++
- }
- }
- if count > ntimes {
- lastred = tred
- ntimes = count
- }
- }
-
- //
- // for error recovery, arrange that, if there is a shift on the
- // error recovery token, `error', that the default be the error action
- //
- if temp1[2] > 0 {
- lastred = 0
- }
-
- // clear out entries in temp1 which equal lastred
- // count entries in optst table
- n := 0
- for p = 0; p <= ntokens; p++ {
- p1 = temp1[p]
- if p1+lastred == 0 {
- temp1[p] = 0
- p1 = 0
- }
- if p1 > 0 && p1 != ACCEPTCODE && p1 != ERRCODE {
- n++
- }
- }
-
- wrstate(i)
- defact[i] = lastred
- flag := 0
- os := make([]int, n*2)
- n = 0
- for p = 0; p <= ntokens; p++ {
- p1 = temp1[p]
- if p1 != 0 {
- if p1 < 0 {
- p1 = -p1
- } else if p1 == ACCEPTCODE {
- p1 = -1
- } else if p1 == ERRCODE {
- p1 = 0
- } else {
- os[n] = p
- n++
- os[n] = p1
- n++
- zzacent++
- continue
- }
- if flag == 0 {
- fmt.Fprintf(ftable, "\t-1, %v,\n", i)
- }
- flag++
- fmt.Fprintf(ftable, "\t%v, %v,\n", p, p1)
- zzexcp++
- }
- }
- if flag != 0 {
- defact[i] = -2
- fmt.Fprintf(ftable, "\t-2, %v,\n", lastred)
- }
- optst[i] = os
-}
-
-//
-// writes state i
-//
-func wrstate(i int) {
- var j0, j1, u int
- var pp, qq int
-
- if len(errors) > 0 {
- actions := append([]int(nil), temp1...)
- defaultAction := ERRCODE
- if lastred != 0 {
- defaultAction = -lastred
- }
- stateTable[i] = Row{actions, defaultAction}
- }
-
- if foutput == nil {
- return
- }
- fmt.Fprintf(foutput, "\nstate %v\n", i)
- qq = pstate[i+1]
- for pp = pstate[i]; pp < qq; pp++ {
- fmt.Fprintf(foutput, "\t%v\n", writem(statemem[pp].pitem))
- }
- if tystate[i] == MUSTLOOKAHEAD {
- // print out empty productions in closure
- for u = pstate[i+1] - pstate[i]; u < cwp; u++ {
- if wsets[u].pitem.first < 0 {
- fmt.Fprintf(foutput, "\t%v\n", writem(wsets[u].pitem))
- }
- }
- }
-
- // check for state equal to another
- for j0 = 0; j0 <= ntokens; j0++ {
- j1 = temp1[j0]
- if j1 != 0 {
- fmt.Fprintf(foutput, "\n\t%v ", symnam(j0))
-
- // shift, error, or accept
- if j1 > 0 {
- if j1 == ACCEPTCODE {
- fmt.Fprintf(foutput, "accept")
- } else if j1 == ERRCODE {
- fmt.Fprintf(foutput, "error")
- } else {
- fmt.Fprintf(foutput, "shift %v", j1)
- }
- } else {
- fmt.Fprintf(foutput, "reduce %v (src line %v)", -j1, rlines[-j1])
- }
- }
- }
-
- // output the final production
- if lastred != 0 {
- fmt.Fprintf(foutput, "\n\t. reduce %v (src line %v)\n\n",
- lastred, rlines[lastred])
- } else {
- fmt.Fprintf(foutput, "\n\t. error\n\n")
- }
-
- // now, output nonterminal actions
- j1 = ntokens
- for j0 = 1; j0 <= nnonter; j0++ {
- j1++
- if temp1[j1] != 0 {
- fmt.Fprintf(foutput, "\t%v goto %v\n", symnam(j0+NTBASE), temp1[j1])
- }
- }
-}
-
-//
-// output the gotos for the nontermninals
-//
-func go2out() {
- for i := 1; i <= nnonter; i++ {
- go2gen(i)
-
- // find the best one to make default
- best := -1
- times := 0
-
- // is j the most frequent
- for j := 0; j < nstate; j++ {
- if tystate[j] == 0 {
- continue
- }
- if tystate[j] == best {
- continue
- }
-
- // is tystate[j] the most frequent
- count := 0
- cbest := tystate[j]
- for k := j; k < nstate; k++ {
- if tystate[k] == cbest {
- count++
- }
- }
- if count > times {
- best = cbest
- times = count
- }
- }
-
- // best is now the default entry
- zzgobest += times - 1
- n := 0
- for j := 0; j < nstate; j++ {
- if tystate[j] != 0 && tystate[j] != best {
- n++
- }
- }
- goent := make([]int, 2*n+1)
- n = 0
- for j := 0; j < nstate; j++ {
- if tystate[j] != 0 && tystate[j] != best {
- goent[n] = j
- n++
- goent[n] = tystate[j]
- n++
- zzgoent++
- }
- }
-
- // now, the default
- if best == -1 {
- best = 0
- }
-
- zzgoent++
- goent[n] = best
- yypgo[i] = goent
- }
-}
-
-//
-// output the gotos for nonterminal c
-//
-func go2gen(c int) {
- var i, cc, p, q int
-
- // first, find nonterminals with gotos on c
- aryfil(temp1, nnonter+1, 0)
- temp1[c] = 1
- work := 1
- for work != 0 {
- work = 0
- for i = 0; i < nprod; i++ {
- // cc is a nonterminal with a goto on c
- cc = prdptr[i][1] - NTBASE
- if cc >= 0 && temp1[cc] != 0 {
- // thus, the left side of production i does too
- cc = prdptr[i][0] - NTBASE
- if temp1[cc] == 0 {
- work = 1
- temp1[cc] = 1
- }
- }
- }
- }
-
- // now, we have temp1[c] = 1 if a goto on c in closure of cc
- if g2debug != 0 && foutput != nil {
- fmt.Fprintf(foutput, "%v: gotos on ", nontrst[c].name)
- for i = 0; i <= nnonter; i++ {
- if temp1[i] != 0 {
- fmt.Fprintf(foutput, "%v ", nontrst[i].name)
- }
- }
- fmt.Fprintf(foutput, "\n")
- }
-
- // now, go through and put gotos into tystate
- aryfil(tystate, nstate, 0)
- for i = 0; i < nstate; i++ {
- q = pstate[i+1]
- for p = pstate[i]; p < q; p++ {
- cc = statemem[p].pitem.first
- if cc >= NTBASE {
- // goto on c is possible
- if temp1[cc-NTBASE] != 0 {
- tystate[i] = amem[indgo[i]+c]
- break
- }
- }
- }
- }
-}
-
-//
-// in order to free up the mem and amem arrays for the optimizer,
-// and still be able to output yyr1, etc., after the sizes of
-// the action array is known, we hide the nonterminals
-// derived by productions in levprd.
-//
-func hideprod() {
- nred := 0
- levprd[0] = 0
- for i := 1; i < nprod; i++ {
- if (levprd[i] & REDFLAG) == 0 {
- if foutput != nil {
- fmt.Fprintf(foutput, "Rule not reduced: %v\n",
- writem(Pitem{prdptr[i], 0, 0, i}))
- }
- fmt.Printf("rule %v never reduced\n", writem(Pitem{prdptr[i], 0, 0, i}))
- nred++
- }
- levprd[i] = prdptr[i][0] - NTBASE
- }
- if nred != 0 {
- fmt.Printf("%v rules never reduced\n", nred)
- }
-}
-
-func callopt() {
- var j, k, p, q, i int
- var v []int
-
- pgo = make([]int, nnonter+1)
- pgo[0] = 0
- maxoff = 0
- maxspr = 0
- for i = 0; i < nstate; i++ {
- k = 32000
- j = 0
- v = optst[i]
- q = len(v)
- for p = 0; p < q; p += 2 {
- if v[p] > j {
- j = v[p]
- }
- if v[p] < k {
- k = v[p]
- }
- }
-
- // nontrivial situation
- if k <= j {
- // j is now the range
- // j -= k; // call scj
- if k > maxoff {
- maxoff = k
- }
- }
- tystate[i] = q + 2*j
- if j > maxspr {
- maxspr = j
- }
- }
-
- // initialize ggreed table
- ggreed = make([]int, nnonter+1)
- for i = 1; i <= nnonter; i++ {
- ggreed[i] = 1
- j = 0
-
- // minimum entry index is always 0
- v = yypgo[i]
- q = len(v) - 1
- for p = 0; p < q; p += 2 {
- ggreed[i] += 2
- if v[p] > j {
- j = v[p]
- }
- }
- ggreed[i] = ggreed[i] + 2*j
- if j > maxoff {
- maxoff = j
- }
- }
-
- // now, prepare to put the shift actions into the amem array
- for i = 0; i < ACTSIZE; i++ {
- amem[i] = 0
- }
- maxa = 0
- for i = 0; i < nstate; i++ {
- if tystate[i] == 0 && adb > 1 {
- fmt.Fprintf(ftable, "State %v: null\n", i)
- }
- indgo[i] = yyFlag
- }
-
- i = nxti()
- for i != NOMORE {
- if i >= 0 {
- stin(i)
- } else {
- gin(-i)
- }
- i = nxti()
- }
-
- // print amem array
- if adb > 2 {
- for p = 0; p <= maxa; p += 10 {
- fmt.Fprintf(ftable, "%v ", p)
- for i = 0; i < 10; i++ {
- fmt.Fprintf(ftable, "%v ", amem[p+i])
- }
- ftable.WriteRune('\n')
- }
- }
-
- aoutput()
- osummary()
-}
-
-//
-// finds the next i
-//
-func nxti() int {
- max := 0
- maxi := 0
- for i := 1; i <= nnonter; i++ {
- if ggreed[i] >= max {
- max = ggreed[i]
- maxi = -i
- }
- }
- for i := 0; i < nstate; i++ {
- if tystate[i] >= max {
- max = tystate[i]
- maxi = i
- }
- }
- if max == 0 {
- return NOMORE
- }
- return maxi
-}
-
-func gin(i int) {
- var s int
-
- // enter gotos on nonterminal i into array amem
- ggreed[i] = 0
-
- q := yypgo[i]
- nq := len(q) - 1
-
- // now, find amem place for it
-nextgp:
- for p := 0; p < ACTSIZE; p++ {
- if amem[p] != 0 {
- continue
- }
- for r := 0; r < nq; r += 2 {
- s = p + q[r] + 1
- if s > maxa {
- maxa = s
- if maxa >= ACTSIZE {
- errorf("a array overflow")
- }
- }
- if amem[s] != 0 {
- continue nextgp
- }
- }
-
- // we have found amem spot
- amem[p] = q[nq]
- if p > maxa {
- maxa = p
- }
- for r := 0; r < nq; r += 2 {
- s = p + q[r] + 1
- amem[s] = q[r+1]
- }
- pgo[i] = p
- if adb > 1 {
- fmt.Fprintf(ftable, "Nonterminal %v, entry at %v\n", i, pgo[i])
- }
- return
- }
- errorf("cannot place goto %v\n", i)
-}
-
-func stin(i int) {
- var s int
-
- tystate[i] = 0
-
- // enter state i into the amem array
- q := optst[i]
- nq := len(q)
-
-nextn:
- // find an acceptable place
- for n := -maxoff; n < ACTSIZE; n++ {
- flag := 0
- for r := 0; r < nq; r += 2 {
- s = q[r] + n
- if s < 0 || s > ACTSIZE {
- continue nextn
- }
- if amem[s] == 0 {
- flag++
- } else if amem[s] != q[r+1] {
- continue nextn
- }
- }
-
- // check the position equals another only if the states are identical
- for j := 0; j < nstate; j++ {
- if indgo[j] == n {
-
- // we have some disagreement
- if flag != 0 {
- continue nextn
- }
- if nq == len(optst[j]) {
-
- // states are equal
- indgo[i] = n
- if adb > 1 {
- fmt.Fprintf(ftable, "State %v: entry at"+
- "%v equals state %v\n",
- i, n, j)
- }
- return
- }
-
- // we have some disagreement
- continue nextn
- }
- }
-
- for r := 0; r < nq; r += 2 {
- s = q[r] + n
- if s > maxa {
- maxa = s
- }
- if amem[s] != 0 && amem[s] != q[r+1] {
- errorf("clobber of a array, pos'n %v, by %v", s, q[r+1])
- }
- amem[s] = q[r+1]
- }
- indgo[i] = n
- if adb > 1 {
- fmt.Fprintf(ftable, "State %v: entry at %v\n", i, indgo[i])
- }
- return
- }
- errorf("Error; failure to place state %v", i)
-}
-
-//
-// this version is for limbo
-// write out the optimized parser
-//
-func aoutput() {
- ftable.WriteRune('\n')
- fmt.Fprintf(ftable, "const %sLast = %v\n\n", prefix, maxa+1)
- arout("Act", amem, maxa+1)
- arout("Pact", indgo, nstate)
- arout("Pgo", pgo, nnonter+1)
-}
-
-//
-// put out other arrays, copy the parsers
-//
-func others() {
- var i, j int
-
- arout("R1", levprd, nprod)
- aryfil(temp1, nprod, 0)
-
- //
- //yyr2 is the number of rules for each production
- //
- for i = 1; i < nprod; i++ {
- temp1[i] = len(prdptr[i]) - 2
- }
- arout("R2", temp1, nprod)
-
- aryfil(temp1, nstate, -1000)
- for i = 0; i <= ntokens; i++ {
- for j := tstates[i]; j != 0; j = mstates[j] {
- temp1[j] = i
- }
- }
- for i = 0; i <= nnonter; i++ {
- for j = ntstates[i]; j != 0; j = mstates[j] {
- temp1[j] = -i
- }
- }
- arout("Chk", temp1, nstate)
- arout("Def", defact, nstate)
-
- // put out token translation tables
- // table 1 has 0-256
- aryfil(temp1, 256, 0)
- c := 0
- for i = 1; i <= ntokens; i++ {
- j = tokset[i].value
- if j >= 0 && j < 256 {
- if temp1[j] != 0 {
- fmt.Print("yacc bug -- cannot have 2 different Ts with same value\n")
- fmt.Printf(" %s and %s\n", tokset[i].name, tokset[temp1[j]].name)
- nerrors++
- }
- temp1[j] = i
- if j > c {
- c = j
- }
- }
- }
- for i = 0; i <= c; i++ {
- if temp1[i] == 0 {
- temp1[i] = YYLEXUNK
- }
- }
- arout("Tok1", temp1, c+1)
-
- // table 2 has PRIVATE-PRIVATE+256
- aryfil(temp1, 256, 0)
- c = 0
- for i = 1; i <= ntokens; i++ {
- j = tokset[i].value - PRIVATE
- if j >= 0 && j < 256 {
- if temp1[j] != 0 {
- fmt.Print("yacc bug -- cannot have 2 different Ts with same value\n")
- fmt.Printf(" %s and %s\n", tokset[i].name, tokset[temp1[j]].name)
- nerrors++
- }
- temp1[j] = i
- if j > c {
- c = j
- }
- }
- }
- arout("Tok2", temp1, c+1)
-
- // table 3 has everything else
- fmt.Fprintf(ftable, "var %sTok3 = [...]int{\n\t", prefix)
- c = 0
- for i = 1; i <= ntokens; i++ {
- j = tokset[i].value
- if j >= 0 && j < 256 {
- continue
- }
- if j >= PRIVATE && j < 256+PRIVATE {
- continue
- }
-
- if c%5 != 0 {
- ftable.WriteRune(' ')
- }
- fmt.Fprintf(ftable, "%d, %d,", j, i)
- c++
- if c%5 == 0 {
- fmt.Fprint(ftable, "\n\t")
- }
- }
- if c%5 != 0 {
- ftable.WriteRune(' ')
- }
- fmt.Fprintf(ftable, "%d,\n}\n", 0)
-
- // Custom error messages.
- fmt.Fprintf(ftable, "\n")
- fmt.Fprintf(ftable, "var %sErrorMessages = [...]struct {\n", prefix)
- fmt.Fprintf(ftable, "\tstate int\n")
- fmt.Fprintf(ftable, "\ttoken int\n")
- fmt.Fprintf(ftable, "\tmsg string\n")
- fmt.Fprintf(ftable, "}{\n")
- for _, error := range errors {
- lineno = error.lineno
- state, token := runMachine(error.tokens)
- fmt.Fprintf(ftable, "\t{%v, %v, %s},\n", state, token, error.msg)
- }
- fmt.Fprintf(ftable, "}\n")
-
- // copy parser text
- ch := getrune(finput)
- for ch != EOF {
- ftable.WriteRune(ch)
- ch = getrune(finput)
- }
-
- // copy yaccpar
- if !lflag {
- fmt.Fprintf(ftable, "\n//line yaccpar:1\n")
- }
-
- parts := strings.SplitN(yaccpar, prefix+"run()", 2)
- fmt.Fprintf(ftable, "%v", parts[0])
- ftable.Write(fcode.Bytes())
- fmt.Fprintf(ftable, "%v", parts[1])
-}
-
-func runMachine(tokens []string) (state, token int) {
- var stack []int
- i := 0
- token = -1
-
-Loop:
- if token < 0 {
- token = chfind(2, tokens[i])
- i++
- }
-
- row := stateTable[state]
-
- c := token
- if token >= NTBASE {
- c = token - NTBASE + ntokens
- }
- action := row.actions[c]
- if action == 0 {
- action = row.defaultAction
- }
-
- switch {
- case action == ACCEPTCODE:
- errorf("tokens are accepted")
- return
- case action == ERRCODE:
- if token >= NTBASE {
- errorf("error at non-terminal token %s", symnam(token))
- }
- return
- case action > 0:
- // Shift to state action.
- stack = append(stack, state)
- state = action
- token = -1
- goto Loop
- default:
- // Reduce by production -action.
- prod := prdptr[-action]
- if rhsLen := len(prod) - 2; rhsLen > 0 {
- n := len(stack) - rhsLen
- state = stack[n]
- stack = stack[:n]
- }
- if token >= 0 {
- i--
- }
- token = prod[0]
- goto Loop
- }
-}
-
-func arout(s string, v []int, n int) {
- s = prefix + s
- fmt.Fprintf(ftable, "var %v = [...]int{\n", s)
- for i := 0; i < n; i++ {
- if i%10 == 0 {
- fmt.Fprintf(ftable, "\n\t")
- } else {
- ftable.WriteRune(' ')
- }
- fmt.Fprintf(ftable, "%d,", v[i])
- }
- fmt.Fprintf(ftable, "\n}\n")
-}
-
-//
-// output the summary on y.output
-//
-func summary() {
- if foutput != nil {
- fmt.Fprintf(foutput, "\n%v terminals, %v nonterminals\n", ntokens, nnonter+1)
- fmt.Fprintf(foutput, "%v grammar rules, %v/%v states\n", nprod, nstate, NSTATES)
- fmt.Fprintf(foutput, "%v shift/reduce, %v reduce/reduce conflicts reported\n", zzsrconf, zzrrconf)
- fmt.Fprintf(foutput, "%v working sets used\n", len(wsets))
- fmt.Fprintf(foutput, "memory: parser %v/%v\n", memp, ACTSIZE)
- fmt.Fprintf(foutput, "%v extra closures\n", zzclose-2*nstate)
- fmt.Fprintf(foutput, "%v shift entries, %v exceptions\n", zzacent, zzexcp)
- fmt.Fprintf(foutput, "%v goto entries\n", zzgoent)
- fmt.Fprintf(foutput, "%v entries saved by goto default\n", zzgobest)
- }
- if zzsrconf != 0 || zzrrconf != 0 {
- fmt.Printf("\nconflicts: ")
- if zzsrconf != 0 {
- fmt.Printf("%v shift/reduce", zzsrconf)
- }
- if zzsrconf != 0 && zzrrconf != 0 {
- fmt.Printf(", ")
- }
- if zzrrconf != 0 {
- fmt.Printf("%v reduce/reduce", zzrrconf)
- }
- fmt.Printf("\n")
- }
-}
-
-//
-// write optimizer summary
-//
-func osummary() {
- if foutput == nil {
- return
- }
- i := 0
- for p := maxa; p >= 0; p-- {
- if amem[p] == 0 {
- i++
- }
- }
-
- fmt.Fprintf(foutput, "Optimizer space used: output %v/%v\n", maxa+1, ACTSIZE)
- fmt.Fprintf(foutput, "%v table entries, %v zero\n", maxa+1, i)
- fmt.Fprintf(foutput, "maximum spread: %v, maximum offset: %v\n", maxspr, maxoff)
-}
-
-//
-// copies and protects "'s in q
-//
-func chcopy(q string) string {
- s := ""
- i := 0
- j := 0
- for i = 0; i < len(q); i++ {
- if q[i] == '"' {
- s += q[j:i] + "\\"
- j = i
- }
- }
- return s + q[j:i]
-}
-
-func usage() {
- fmt.Fprintf(stderr, "usage: yacc [-o output] [-v parsetable] input\n")
- exit(1)
-}
-
-func bitset(set Lkset, bit int) int { return set[bit>>5] & (1 << uint(bit&31)) }
-
-func setbit(set Lkset, bit int) { set[bit>>5] |= (1 << uint(bit&31)) }
-
-func mkset() Lkset { return make([]int, tbitset) }
-
-//
-// set a to the union of a and b
-// return 1 if b is not a subset of a, 0 otherwise
-//
-func setunion(a, b []int) int {
- sub := 0
- for i := 0; i < tbitset; i++ {
- x := a[i]
- y := x | b[i]
- a[i] = y
- if y != x {
- sub = 1
- }
- }
- return sub
-}
-
-func prlook(p Lkset) {
- if p == nil {
- fmt.Fprintf(foutput, "\tNULL")
- return
- }
- fmt.Fprintf(foutput, " { ")
- for j := 0; j <= ntokens; j++ {
- if bitset(p, j) != 0 {
- fmt.Fprintf(foutput, "%v ", symnam(j))
- }
- }
- fmt.Fprintf(foutput, "}")
-}
-
-//
-// utility routines
-//
-var peekrune rune
-
-func isdigit(c rune) bool { return c >= '0' && c <= '9' }
-
-func isword(c rune) bool {
- return c >= 0xa0 || c == '_' || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')
-}
-
-//
-// return 1 if 2 arrays are equal
-// return 0 if not equal
-//
-func aryeq(a []int, b []int) int {
- n := len(a)
- if len(b) != n {
- return 0
- }
- for ll := 0; ll < n; ll++ {
- if a[ll] != b[ll] {
- return 0
- }
- }
- return 1
-}
-
-func getrune(f *bufio.Reader) rune {
- var r rune
-
- if peekrune != 0 {
- if peekrune == EOF {
- return EOF
- }
- r = peekrune
- peekrune = 0
- return r
- }
-
- c, n, err := f.ReadRune()
- if n == 0 {
- return EOF
- }
- if err != nil {
- errorf("read error: %v", err)
- }
- //fmt.Printf("rune = %v n=%v\n", string(c), n);
- return c
-}
-
-func ungetrune(f *bufio.Reader, c rune) {
- if f != finput {
- panic("ungetc - not finput")
- }
- if peekrune != 0 {
- panic("ungetc - 2nd unget")
- }
- peekrune = c
-}
-
-func write(f *bufio.Writer, b []byte, n int) int {
- panic("write")
-}
-
-func open(s string) *bufio.Reader {
- fi, err := os.Open(s)
- if err != nil {
- errorf("error opening %v: %v", s, err)
- }
- //fmt.Printf("open %v\n", s);
- return bufio.NewReader(fi)
-}
-
-func create(s string) *bufio.Writer {
- fo, err := os.Create(s)
- if err != nil {
- errorf("error creating %v: %v", s, err)
- }
- //fmt.Printf("create %v mode %v\n", s);
- return bufio.NewWriter(fo)
-}
-
-//
-// write out error comment
-//
-func lerrorf(lineno int, s string, v ...interface{}) {
- nerrors++
- fmt.Fprintf(stderr, s, v...)
- fmt.Fprintf(stderr, ": %v:%v\n", infile, lineno)
- if fatfl != 0 {
- summary()
- exit(1)
- }
-}
-
-func errorf(s string, v ...interface{}) {
- lerrorf(lineno, s, v...)
-}
-
-func exit(status int) {
- if ftable != nil {
- ftable.Flush()
- ftable = nil
- gofmt()
- }
- if foutput != nil {
- foutput.Flush()
- foutput = nil
- }
- if stderr != nil {
- stderr.Flush()
- stderr = nil
- }
- os.Exit(status)
-}
-
-func gofmt() {
- src, err := ioutil.ReadFile(oflag)
- if err != nil {
- return
- }
- src, err = format.Source(src)
- if err != nil {
- return
- }
- ioutil.WriteFile(oflag, src, 0666)
-}
-
-var yaccpar string // will be processed version of yaccpartext: s/$$/prefix/g
-var yaccpartext = `
-/* parser for yacc output */
-
-var (
- $$Debug = 0
- $$ErrorVerbose = false
-)
-
-type $$Lexer interface {
- Lex(lval *$$SymType) int
- Error(s string)
-}
-
-type $$Parser interface {
- Parse($$Lexer) int
- Lookahead() int
-}
-
-type $$ParserImpl struct {
- lval $$SymType
- stack [$$InitialStackSize]$$SymType
- char int
-}
-
-func (p *$$ParserImpl) Lookahead() int {
- return p.char
-}
-
-func $$NewParser() $$Parser {
- return &$$ParserImpl{}
-}
-
-const $$Flag = -1000
-
-func $$Tokname(c int) string {
- if c >= 1 && c-1 < len($$Toknames) {
- if $$Toknames[c-1] != "" {
- return $$Toknames[c-1]
- }
- }
- return __yyfmt__.Sprintf("tok-%v", c)
-}
-
-func $$Statname(s int) string {
- if s >= 0 && s < len($$Statenames) {
- if $$Statenames[s] != "" {
- return $$Statenames[s]
- }
- }
- return __yyfmt__.Sprintf("state-%v", s)
-}
-
-func $$ErrorMessage(state, lookAhead int) string {
- const TOKSTART = 4
-
- if !$$ErrorVerbose {
- return "syntax error"
- }
-
- for _, e := range $$ErrorMessages {
- if e.state == state && e.token == lookAhead {
- return "syntax error: " + e.msg
- }
- }
-
- res := "syntax error: unexpected " + $$Tokname(lookAhead)
-
- // To match Bison, suggest at most four expected tokens.
- expected := make([]int, 0, 4)
-
- // Look for shiftable tokens.
- base := $$Pact[state]
- for tok := TOKSTART; tok-1 < len($$Toknames); tok++ {
- if n := base + tok; n >= 0 && n < $$Last && $$Chk[$$Act[n]] == tok {
- if len(expected) == cap(expected) {
- return res
- }
- expected = append(expected, tok)
- }
- }
-
- if $$Def[state] == -2 {
- i := 0
- for $$Exca[i] != -1 || $$Exca[i+1] != state {
- i += 2
- }
-
- // Look for tokens that we accept or reduce.
- for i += 2; $$Exca[i] >= 0; i += 2 {
- tok := $$Exca[i]
- if tok < TOKSTART || $$Exca[i+1] == 0 {
- continue
- }
- if len(expected) == cap(expected) {
- return res
- }
- expected = append(expected, tok)
- }
-
- // If the default action is to accept or reduce, give up.
- if $$Exca[i+1] != 0 {
- return res
- }
- }
-
- for i, tok := range expected {
- if i == 0 {
- res += ", expecting "
- } else {
- res += " or "
- }
- res += $$Tokname(tok)
- }
- return res
-}
-
-func $$lex1(lex $$Lexer, lval *$$SymType) (char, token int) {
- token = 0
- char = lex.Lex(lval)
- if char <= 0 {
- token = $$Tok1[0]
- goto out
- }
- if char < len($$Tok1) {
- token = $$Tok1[char]
- goto out
- }
- if char >= $$Private {
- if char < $$Private+len($$Tok2) {
- token = $$Tok2[char-$$Private]
- goto out
- }
- }
- for i := 0; i < len($$Tok3); i += 2 {
- token = $$Tok3[i+0]
- if token == char {
- token = $$Tok3[i+1]
- goto out
- }
- }
-
-out:
- if token == 0 {
- token = $$Tok2[1] /* unknown char */
- }
- if $$Debug >= 3 {
- __yyfmt__.Printf("lex %s(%d)\n", $$Tokname(token), uint(char))
- }
- return char, token
-}
-
-func $$Parse($$lex $$Lexer) int {
- return $$NewParser().Parse($$lex)
-}
-
-func ($$rcvr *$$ParserImpl) Parse($$lex $$Lexer) int {
- var $$n int
- var $$VAL $$SymType
- var $$Dollar []$$SymType
- _ = $$Dollar // silence set and not used
- $$S := $$rcvr.stack[:]
-
- Nerrs := 0 /* number of errors */
- Errflag := 0 /* error recovery flag */
- $$state := 0
- $$rcvr.char = -1
- $$token := -1 // $$rcvr.char translated into internal numbering
- defer func() {
- // Make sure we report no lookahead when not parsing.
- $$state = -1
- $$rcvr.char = -1
- $$token = -1
- }()
- $$p := -1
- goto $$stack
-
-ret0:
- return 0
-
-ret1:
- return 1
-
-$$stack:
- /* put a state and value onto the stack */
- if $$Debug >= 4 {
- __yyfmt__.Printf("char %v in %v\n", $$Tokname($$token), $$Statname($$state))
- }
-
- $$p++
- if $$p >= len($$S) {
- nyys := make([]$$SymType, len($$S)*2)
- copy(nyys, $$S)
- $$S = nyys
- }
- $$S[$$p] = $$VAL
- $$S[$$p].yys = $$state
-
-$$newstate:
- $$n = $$Pact[$$state]
- if $$n <= $$Flag {
- goto $$default /* simple state */
- }
- if $$rcvr.char < 0 {
- $$rcvr.char, $$token = $$lex1($$lex, &$$rcvr.lval)
- }
- $$n += $$token
- if $$n < 0 || $$n >= $$Last {
- goto $$default
- }
- $$n = $$Act[$$n]
- if $$Chk[$$n] == $$token { /* valid shift */
- $$rcvr.char = -1
- $$token = -1
- $$VAL = $$rcvr.lval
- $$state = $$n
- if Errflag > 0 {
- Errflag--
- }
- goto $$stack
- }
-
-$$default:
- /* default state action */
- $$n = $$Def[$$state]
- if $$n == -2 {
- if $$rcvr.char < 0 {
- $$rcvr.char, $$token = $$lex1($$lex, &$$rcvr.lval)
- }
-
- /* look through exception table */
- xi := 0
- for {
- if $$Exca[xi+0] == -1 && $$Exca[xi+1] == $$state {
- break
- }
- xi += 2
- }
- for xi += 2; ; xi += 2 {
- $$n = $$Exca[xi+0]
- if $$n < 0 || $$n == $$token {
- break
- }
- }
- $$n = $$Exca[xi+1]
- if $$n < 0 {
- goto ret0
- }
- }
- if $$n == 0 {
- /* error ... attempt to resume parsing */
- switch Errflag {
- case 0: /* brand new error */
- $$lex.Error($$ErrorMessage($$state, $$token))
- Nerrs++
- if $$Debug >= 1 {
- __yyfmt__.Printf("%s", $$Statname($$state))
- __yyfmt__.Printf(" saw %s\n", $$Tokname($$token))
- }
- fallthrough
-
- case 1, 2: /* incompletely recovered error ... try again */
- Errflag = 3
-
- /* find a state where "error" is a legal shift action */
- for $$p >= 0 {
- $$n = $$Pact[$$S[$$p].yys] + $$ErrCode
- if $$n >= 0 && $$n < $$Last {
- $$state = $$Act[$$n] /* simulate a shift of "error" */
- if $$Chk[$$state] == $$ErrCode {
- goto $$stack
- }
- }
-
- /* the current p has no shift on "error", pop stack */
- if $$Debug >= 2 {
- __yyfmt__.Printf("error recovery pops state %d\n", $$S[$$p].yys)
- }
- $$p--
- }
- /* there is no state on the stack with an error shift ... abort */
- goto ret1
-
- case 3: /* no shift yet; clobber input char */
- if $$Debug >= 2 {
- __yyfmt__.Printf("error recovery discards %s\n", $$Tokname($$token))
- }
- if $$token == $$EofCode {
- goto ret1
- }
- $$rcvr.char = -1
- $$token = -1
- goto $$newstate /* try again in the same state */
- }
- }
-
- /* reduction by production $$n */
- if $$Debug >= 2 {
- __yyfmt__.Printf("reduce %v in:\n\t%v\n", $$n, $$Statname($$state))
- }
-
- $$nt := $$n
- $$pt := $$p
- _ = $$pt // guard against "declared and not used"
-
- $$p -= $$R2[$$n]
- // $$p is now the index of $0. Perform the default action. Iff the
- // reduced production is ε, $1 is possibly out of range.
- if $$p+1 >= len($$S) {
- nyys := make([]$$SymType, len($$S)*2)
- copy(nyys, $$S)
- $$S = nyys
- }
- $$VAL = $$S[$$p+1]
-
- /* consult goto table to find next state */
- $$n = $$R1[$$n]
- $$g := $$Pgo[$$n]
- $$j := $$g + $$S[$$p].yys + 1
-
- if $$j >= $$Last {
- $$state = $$Act[$$g]
- } else {
- $$state = $$Act[$$j]
- if $$Chk[$$state] != -$$n {
- $$state = $$Act[$$g]
- }
- }
- // dummy call; replaced with literal code
- $$run()
- goto $$stack /* stack new state and value */
-}
-`
diff --git a/src/cmp.bash b/src/cmp.bash
index 68086c3..dac9ca0 100644
--- a/src/cmp.bash
+++ b/src/cmp.bash
@@ -1,6 +1,6 @@
#!/usr/bin/env bash
-# Copyright 2016 The Go Authors. All rights reserved.
+# Copyright 2016 The Go Authors. All rights reserved.
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
diff --git a/src/compress/flate/deflate.go b/src/compress/flate/deflate.go
index 9f53d51..97265b3 100644
--- a/src/compress/flate/deflate.go
+++ b/src/compress/flate/deflate.go
@@ -84,9 +84,10 @@ type compressor struct {
bulkHasher func([]byte, []uint32)
// compression algorithm
- fill func(*compressor, []byte) int // copy data to window
- step func(*compressor) // process window
- sync bool // requesting flush
+ fill func(*compressor, []byte) int // copy data to window
+ step func(*compressor) // process window
+ sync bool // requesting flush
+ bestSpeed *deflateFast // Encoder for BestSpeed
// Input hash chains
// hashHead[hashValue] contains the largest inputIndex with the specified hash value
@@ -346,12 +347,13 @@ func (d *compressor) encSpeed() {
d.err = d.w.err
}
d.windowEnd = 0
+ d.bestSpeed.reset()
return
}
}
// Encode the block.
- d.tokens = encodeBestSpeed(d.tokens[:0], d.window[:d.windowEnd])
+ d.tokens = d.bestSpeed.encode(d.tokens[:0], d.window[:d.windowEnd])
// If we removed less than 1/16th, Huffman compress the block.
if len(d.tokens) > d.windowEnd-(d.windowEnd>>4) {
@@ -519,10 +521,10 @@ func (d *compressor) fillStore(b []byte) int {
}
func (d *compressor) store() {
- if d.windowEnd > 0 {
+ if d.windowEnd > 0 && (d.windowEnd == maxStoreBlockSize || d.sync) {
d.err = d.writeStoredBlock(d.window[:d.windowEnd])
+ d.windowEnd = 0
}
- d.windowEnd = 0
}
// storeHuff compresses and stores the currently added data
@@ -584,6 +586,7 @@ func (d *compressor) init(w io.Writer, level int) (err error) {
d.window = make([]byte, maxStoreBlockSize)
d.fill = (*compressor).fillStore
d.step = (*compressor).encSpeed
+ d.bestSpeed = newDeflateFast()
d.tokens = make([]token, maxStoreBlockSize)
case level == DefaultCompression:
level = 6
@@ -609,6 +612,7 @@ func (d *compressor) reset(w io.Writer) {
case BestSpeed:
d.windowEnd = 0
d.tokens = d.tokens[:0]
+ d.bestSpeed.reset()
default:
d.chainHead = -1
for i := range d.hashHead {
@@ -702,10 +706,12 @@ func (w *Writer) Write(data []byte) (n int, err error) {
return w.d.write(data)
}
-// Flush flushes any pending compressed data to the underlying writer.
+// Flush flushes any pending data to the underlying writer.
// It is useful mainly in compressed network protocols, to ensure that
// a remote reader has enough data to reconstruct a packet.
// Flush does not return until the data has been written.
+// Calling Flush when there is no pending data still causes the Writer
+// to emit a sync marker of at least 4 bytes.
// If the underlying writer returns an error, Flush returns that error.
//
// In the terminology of the zlib library, Flush is equivalent to Z_SYNC_FLUSH.
diff --git a/src/compress/flate/deflate_test.go b/src/compress/flate/deflate_test.go
index 3322c40..521a260 100644
--- a/src/compress/flate/deflate_test.go
+++ b/src/compress/flate/deflate_test.go
@@ -342,6 +342,7 @@ func testToFromWithLimit(t *testing.T, input []byte, name string, limit [11]int)
}
func TestDeflateInflate(t *testing.T) {
+ t.Parallel()
for i, h := range deflateInflateTests {
testToFromWithLimit(t, h.in, fmt.Sprintf("#%d", i), [11]int{})
}
@@ -376,6 +377,7 @@ var deflateInflateStringTests = []deflateInflateStringTest{
}
func TestDeflateInflateString(t *testing.T) {
+ t.Parallel()
if testing.Short() && testenv.Builder() == "" {
t.Skip("skipping in short mode")
}
@@ -463,6 +465,7 @@ func TestRegression2508(t *testing.T) {
}
func TestWriterReset(t *testing.T) {
+ t.Parallel()
for level := 0; level <= 9; level++ {
if testing.Short() && level > 1 {
break
@@ -490,6 +493,7 @@ func TestWriterReset(t *testing.T) {
w.d.fill, wref.d.fill = nil, nil
w.d.step, wref.d.step = nil, nil
w.d.bulkHasher, wref.d.bulkHasher = nil, nil
+ w.d.bestSpeed, wref.d.bestSpeed = nil, nil
// hashMatch is always overwritten when used.
copy(w.d.hashMatch[:], wref.d.hashMatch[:])
if len(w.d.tokens) != 0 {
@@ -558,6 +562,7 @@ func testResetOutput(t *testing.T, newWriter func(w io.Writer) (*Writer, error))
// compressor.encSpeed method (0, 16, 128), as well as near maxStoreBlockSize
// (65535).
func TestBestSpeed(t *testing.T) {
+ t.Parallel()
abc := make([]byte, 128)
for i := range abc {
abc[i] = byte(i)
@@ -647,6 +652,7 @@ func (w *failWriter) Write(b []byte) (int, error) {
}
func TestWriterPersistentError(t *testing.T) {
+ t.Parallel()
d, err := ioutil.ReadFile("../testdata/Mark.Twain-Tom.Sawyer.txt")
if err != nil {
t.Fatalf("ReadFile: %v", err)
@@ -681,3 +687,180 @@ func TestWriterPersistentError(t *testing.T) {
}
}
}
+
+func TestBestSpeedMatch(t *testing.T) {
+ t.Parallel()
+ cases := []struct {
+ previous, current []byte
+ t, s, want int32
+ }{{
+ previous: []byte{0, 0, 0, 1, 2},
+ current: []byte{3, 4, 5, 0, 1, 2, 3, 4, 5},
+ t: -3,
+ s: 3,
+ want: 6,
+ }, {
+ previous: []byte{0, 0, 0, 1, 2},
+ current: []byte{2, 4, 5, 0, 1, 2, 3, 4, 5},
+ t: -3,
+ s: 3,
+ want: 3,
+ }, {
+ previous: []byte{0, 0, 0, 1, 1},
+ current: []byte{3, 4, 5, 0, 1, 2, 3, 4, 5},
+ t: -3,
+ s: 3,
+ want: 2,
+ }, {
+ previous: []byte{0, 0, 0, 1, 2},
+ current: []byte{2, 2, 2, 2, 1, 2, 3, 4, 5},
+ t: -1,
+ s: 0,
+ want: 4,
+ }, {
+ previous: []byte{0, 0, 0, 1, 2, 3, 4, 5, 2, 2},
+ current: []byte{2, 2, 2, 2, 1, 2, 3, 4, 5},
+ t: -7,
+ s: 4,
+ want: 5,
+ }, {
+ previous: []byte{9, 9, 9, 9, 9},
+ current: []byte{2, 2, 2, 2, 1, 2, 3, 4, 5},
+ t: -1,
+ s: 0,
+ want: 0,
+ }, {
+ previous: []byte{9, 9, 9, 9, 9},
+ current: []byte{9, 2, 2, 2, 1, 2, 3, 4, 5},
+ t: 0,
+ s: 1,
+ want: 0,
+ }, {
+ previous: []byte{},
+ current: []byte{9, 2, 2, 2, 1, 2, 3, 4, 5},
+ t: -5,
+ s: 1,
+ want: 0,
+ }, {
+ previous: []byte{},
+ current: []byte{9, 2, 2, 2, 1, 2, 3, 4, 5},
+ t: -1,
+ s: 1,
+ want: 0,
+ }, {
+ previous: []byte{},
+ current: []byte{2, 2, 2, 2, 1, 2, 3, 4, 5},
+ t: 0,
+ s: 1,
+ want: 3,
+ }, {
+ previous: []byte{3, 4, 5},
+ current: []byte{3, 4, 5},
+ t: -3,
+ s: 0,
+ want: 3,
+ }, {
+ previous: make([]byte, 1000),
+ current: make([]byte, 1000),
+ t: -1000,
+ s: 0,
+ want: maxMatchLength - 4,
+ }, {
+ previous: make([]byte, 200),
+ current: make([]byte, 500),
+ t: -200,
+ s: 0,
+ want: maxMatchLength - 4,
+ }, {
+ previous: make([]byte, 200),
+ current: make([]byte, 500),
+ t: 0,
+ s: 1,
+ want: maxMatchLength - 4,
+ }, {
+ previous: make([]byte, maxMatchLength-4),
+ current: make([]byte, 500),
+ t: -(maxMatchLength - 4),
+ s: 0,
+ want: maxMatchLength - 4,
+ }, {
+ previous: make([]byte, 200),
+ current: make([]byte, 500),
+ t: -200,
+ s: 400,
+ want: 100,
+ }, {
+ previous: make([]byte, 10),
+ current: make([]byte, 500),
+ t: 200,
+ s: 400,
+ want: 100,
+ }}
+ for i, c := range cases {
+ e := deflateFast{prev: c.previous}
+ got := e.matchLen(c.s, c.t, c.current)
+ if got != c.want {
+ t.Errorf("Test %d: match length, want %d, got %d", i, c.want, got)
+ }
+ }
+}
+
+func TestBestSpeedMaxMatchOffset(t *testing.T) {
+ t.Parallel()
+ const abc, xyz = "abcdefgh", "stuvwxyz"
+ for _, matchBefore := range []bool{false, true} {
+ for _, extra := range []int{0, inputMargin - 1, inputMargin, inputMargin + 1, 2 * inputMargin} {
+ for offsetAdj := -5; offsetAdj <= +5; offsetAdj++ {
+ report := func(desc string, err error) {
+ t.Errorf("matchBefore=%t, extra=%d, offsetAdj=%d: %s%v",
+ matchBefore, extra, offsetAdj, desc, err)
+ }
+
+ offset := maxMatchOffset + offsetAdj
+
+ // Make src to be a []byte of the form
+ // "%s%s%s%s%s" % (abc, zeros0, xyzMaybe, abc, zeros1)
+ // where:
+ // zeros0 is approximately maxMatchOffset zeros.
+ // xyzMaybe is either xyz or the empty string.
+ // zeros1 is between 0 and 30 zeros.
+ // The difference between the two abc's will be offset, which
+ // is maxMatchOffset plus or minus a small adjustment.
+ src := make([]byte, offset+len(abc)+extra)
+ copy(src, abc)
+ if !matchBefore {
+ copy(src[offset-len(xyz):], xyz)
+ }
+ copy(src[offset:], abc)
+
+ buf := new(bytes.Buffer)
+ w, err := NewWriter(buf, BestSpeed)
+ if err != nil {
+ report("NewWriter: ", err)
+ continue
+ }
+ if _, err := w.Write(src); err != nil {
+ report("Write: ", err)
+ continue
+ }
+ if err := w.Close(); err != nil {
+ report("Writer.Close: ", err)
+ continue
+ }
+
+ r := NewReader(buf)
+ dst, err := ioutil.ReadAll(r)
+ r.Close()
+ if err != nil {
+ report("ReadAll: ", err)
+ continue
+ }
+
+ if !bytes.Equal(dst, src) {
+ report("", fmt.Errorf("bytes differ after round-tripping"))
+ continue
+ }
+ }
+ }
+ }
+}
diff --git a/src/compress/flate/deflatefast.go b/src/compress/flate/deflatefast.go
index 6b881a4..a1636a3 100644
--- a/src/compress/flate/deflatefast.go
+++ b/src/compress/flate/deflatefast.go
@@ -14,12 +14,12 @@ const (
tableShift = 32 - tableBits // Right-shift to get the tableBits most significant bits of a uint32.
)
-func load32(b []byte, i int) uint32 {
+func load32(b []byte, i int32) uint32 {
b = b[i : i+4 : len(b)] // Help the compiler eliminate bounds checks on the next line.
return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24
}
-func load64(b []byte, i int) uint64 {
+func load64(b []byte, i int32) uint64 {
b = b[i : i+8 : len(b)] // Help the compiler eliminate bounds checks on the next line.
return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 |
uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56
@@ -38,31 +38,49 @@ const (
minNonLiteralBlockSize = 1 + 1 + inputMargin
)
-func encodeBestSpeed(dst []token, src []byte) []token {
+type tableEntry struct {
+ val uint32 // Value at destination
+ offset int32
+}
+
+// deflateFast maintains the table for matches,
+// and the previous byte block for cross block matching.
+type deflateFast struct {
+ table [tableSize]tableEntry
+ prev []byte // Previous block, zero length if unknown.
+ cur int32 // Current match offset.
+}
+
+func newDeflateFast() *deflateFast {
+ return &deflateFast{cur: maxStoreBlockSize, prev: make([]byte, 0, maxStoreBlockSize)}
+}
+
+// encode encodes a block given in src and appends tokens
+// to dst and returns the result.
+func (e *deflateFast) encode(dst []token, src []byte) []token {
+ // Ensure that e.cur doesn't wrap.
+ if e.cur > 1<<30 {
+ *e = deflateFast{cur: maxStoreBlockSize, prev: e.prev[:0]}
+ }
+
// This check isn't in the Snappy implementation, but there, the caller
// instead of the callee handles this case.
if len(src) < minNonLiteralBlockSize {
+ e.cur += maxStoreBlockSize
+ e.prev = e.prev[:0]
return emitLiteral(dst, src)
}
- // Initialize the hash table.
- //
- // The table element type is uint16, as s < sLimit and sLimit < len(src)
- // and len(src) <= maxStoreBlockSize and maxStoreBlockSize == 65535.
- var table [tableSize]uint16
-
// sLimit is when to stop looking for offset/length copies. The inputMargin
// lets us use a fast path for emitLiteral in the main loop, while we are
// looking for copies.
- sLimit := len(src) - inputMargin
+ sLimit := int32(len(src) - inputMargin)
// nextEmit is where in src the next emitLiteral should start from.
- nextEmit := 0
-
- // The encoded form must start with a literal, as there are no previous
- // bytes to copy, so we start looking for hash matches at s == 1.
- s := 1
- nextHash := hash(load32(src, s))
+ nextEmit := int32(0)
+ s := int32(0)
+ cv := load32(src, s)
+ nextHash := hash(cv)
for {
// Copied from the C++ snappy implementation:
@@ -80,10 +98,10 @@ func encodeBestSpeed(dst []token, src []byte) []token {
// The "skip" variable keeps track of how many bytes there are since
// the last match; dividing it by 32 (ie. right-shifting by five) gives
// the number of bytes to move ahead for each iteration.
- skip := 32
+ skip := int32(32)
nextS := s
- candidate := 0
+ var candidate tableEntry
for {
s = nextS
bytesBetweenHashLookups := skip >> 5
@@ -92,13 +110,18 @@ func encodeBestSpeed(dst []token, src []byte) []token {
if nextS > sLimit {
goto emitRemainder
}
- candidate = int(table[nextHash&tableMask])
- table[nextHash&tableMask] = uint16(s)
- nextHash = hash(load32(src, nextS))
- // TODO: < should be <=, and add a test for that.
- if s-candidate < maxMatchOffset && load32(src, s) == load32(src, candidate) {
- break
+ candidate = e.table[nextHash&tableMask]
+ now := load32(src, nextS)
+ e.table[nextHash&tableMask] = tableEntry{offset: s + e.cur, val: cv}
+ nextHash = hash(now)
+
+ offset := s - (candidate.offset - e.cur)
+ if offset > maxMatchOffset || cv != candidate.val {
+ // Out of range or not matched.
+ cv = now
+ continue
}
+ break
}
// A 4-byte match has been found. We'll later see if more than 4 bytes
@@ -117,22 +140,16 @@ func encodeBestSpeed(dst []token, src []byte) []token {
for {
// Invariant: we have a 4-byte match at s, and no need to emit any
// literal bytes prior to s.
- base := s
// Extend the 4-byte match as long as possible.
//
- // This is an inlined version of Snappy's:
- // s = extendMatch(src, candidate+4, s+4)
s += 4
- s1 := base + maxMatchLength
- if s1 > len(src) {
- s1 = len(src)
- }
- for i := candidate + 4; s < s1 && src[i] == src[s]; i, s = i+1, s+1 {
- }
+ t := candidate.offset - e.cur + 4
+ l := e.matchLen(s, t, src)
- // matchToken is flate's equivalent of Snappy's emitCopy.
- dst = append(dst, matchToken(uint32(s-base-baseMatchLength), uint32(base-candidate-baseMatchOffset)))
+ // matchToken is flate's equivalent of Snappy's emitCopy. (length,offset)
+ dst = append(dst, matchToken(uint32(l+4-baseMatchLength), uint32(s-t-baseMatchOffset)))
+ s += l
nextEmit = s
if s >= sLimit {
goto emitRemainder
@@ -145,14 +162,17 @@ func encodeBestSpeed(dst []token, src []byte) []token {
// are faster as one load64 call (with some shifts) instead of
// three load32 calls.
x := load64(src, s-1)
- prevHash := hash(uint32(x >> 0))
- table[prevHash&tableMask] = uint16(s - 1)
- currHash := hash(uint32(x >> 8))
- candidate = int(table[currHash&tableMask])
- table[currHash&tableMask] = uint16(s)
- // TODO: >= should be >, and add a test for that.
- if s-candidate >= maxMatchOffset || uint32(x>>8) != load32(src, candidate) {
- nextHash = hash(uint32(x >> 16))
+ prevHash := hash(uint32(x))
+ e.table[prevHash&tableMask] = tableEntry{offset: e.cur + s - 1, val: uint32(x)}
+ x >>= 8
+ currHash := hash(uint32(x))
+ candidate = e.table[currHash&tableMask]
+ e.table[currHash&tableMask] = tableEntry{offset: e.cur + s, val: uint32(x)}
+
+ offset := s - (candidate.offset - e.cur)
+ if offset > maxMatchOffset || uint32(x) != candidate.val {
+ cv = uint32(x >> 8)
+ nextHash = hash(cv)
s++
break
}
@@ -160,15 +180,91 @@ func encodeBestSpeed(dst []token, src []byte) []token {
}
emitRemainder:
- if nextEmit < len(src) {
+ if int(nextEmit) < len(src) {
dst = emitLiteral(dst, src[nextEmit:])
}
+ e.cur += int32(len(src))
+ e.prev = e.prev[:len(src)]
+ copy(e.prev, src)
return dst
}
func emitLiteral(dst []token, lit []byte) []token {
for _, v := range lit {
- dst = append(dst, token(v))
+ dst = append(dst, literalToken(uint32(v)))
}
return dst
}
+
+// matchLen returns the match length between src[s:] and src[t:].
+// t can be negative to indicate the match is starting in e.prev.
+// We assume that src[s-4:s] and src[t-4:t] already match.
+func (e *deflateFast) matchLen(s, t int32, src []byte) int32 {
+ s1 := int(s) + maxMatchLength - 4
+ if s1 > len(src) {
+ s1 = len(src)
+ }
+
+ // If we are inside the current block
+ if t >= 0 {
+ b := src[t:]
+ a := src[s:s1]
+ b = b[:len(a)]
+ // Extend the match to be as long as possible.
+ for i := range a {
+ if a[i] != b[i] {
+ return int32(i)
+ }
+ }
+ return int32(len(a))
+ }
+
+ // We found a match in the previous block.
+ tp := int32(len(e.prev)) + t
+ if tp < 0 {
+ return 0
+ }
+
+ // Extend the match to be as long as possible.
+ a := src[s:s1]
+ b := e.prev[tp:]
+ if len(b) > len(a) {
+ b = b[:len(a)]
+ }
+ a = a[:len(b)]
+ for i := range b {
+ if a[i] != b[i] {
+ return int32(i)
+ }
+ }
+
+ // If we reached our limit, we matched everything we are
+ // allowed to in the previous block and we return.
+ n := int32(len(b))
+ if int(s+n) == s1 {
+ return n
+ }
+
+ // Continue looking for more matches in the current block.
+ a = src[s+n : s1]
+ b = src[:len(a)]
+ for i := range a {
+ if a[i] != b[i] {
+ return int32(i) + n
+ }
+ }
+ return int32(len(a)) + n
+}
+
+// Reset resets the encoding history.
+// This ensures that no matches are made to the previous block.
+func (e *deflateFast) reset() {
+ e.prev = e.prev[:0]
+ // Bump the offset, so all matches will fail distance check.
+ e.cur += maxMatchOffset
+
+ // Protect against e.cur wraparound.
+ if e.cur > 1<<30 {
+ *e = deflateFast{cur: maxStoreBlockSize, prev: e.prev[:0]}
+ }
+}
diff --git a/src/compress/flate/example_test.go b/src/compress/flate/example_test.go
new file mode 100644
index 0000000..5780092
--- /dev/null
+++ b/src/compress/flate/example_test.go
@@ -0,0 +1,243 @@
+// Copyright 2016 The Go Authors. 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_test
+
+import (
+ "bytes"
+ "compress/flate"
+ "fmt"
+ "io"
+ "log"
+ "os"
+ "strings"
+ "sync"
+)
+
+// In performance critical applications, Reset can be used to discard the
+// current compressor or decompressor state and reinitialize them quickly
+// by taking advantage of previously allocated memory.
+func Example_reset() {
+ proverbs := []string{
+ "Don't communicate by sharing memory, share memory by communicating.\n",
+ "Concurrency is not parallelism.\n",
+ "The bigger the interface, the weaker the abstraction.\n",
+ "Documentation is for users.\n",
+ }
+
+ var r strings.Reader
+ var b bytes.Buffer
+ buf := make([]byte, 32<<10)
+
+ zw, err := flate.NewWriter(nil, flate.DefaultCompression)
+ if err != nil {
+ log.Fatal(err)
+ }
+ zr := flate.NewReader(nil)
+
+ for _, s := range proverbs {
+ r.Reset(s)
+ b.Reset()
+
+ // Reset the compressor and encode from some input stream.
+ zw.Reset(&b)
+ if _, err := io.CopyBuffer(zw, &r, buf); err != nil {
+ log.Fatal(err)
+ }
+ if err := zw.Close(); err != nil {
+ log.Fatal(err)
+ }
+
+ // Reset the decompressor and decode to some output stream.
+ if err := zr.(flate.Resetter).Reset(&b, nil); err != nil {
+ log.Fatal(err)
+ }
+ if _, err := io.CopyBuffer(os.Stdout, zr, buf); err != nil {
+ log.Fatal(err)
+ }
+ if err := zr.Close(); err != nil {
+ log.Fatal(err)
+ }
+ }
+
+ // Output:
+ // Don't communicate by sharing memory, share memory by communicating.
+ // Concurrency is not parallelism.
+ // The bigger the interface, the weaker the abstraction.
+ // Documentation is for users.
+}
+
+// A preset dictionary can be used to improve the compression ratio.
+// The downside to using a dictionary is that the compressor and decompressor
+// must agree in advance what dictionary to use.
+func Example_dictionary() {
+ // The dictionary is a string of bytes. When compressing some input data,
+ // the compressor will attempt to substitute substrings with matches found
+ // in the dictionary. As such, the dictionary should only contain substrings
+ // that are expected to be found in the actual data stream.
+ const dict = `<?xml version="1.0"?>` + `<book>` + `<data>` + `<meta name="` + `" content="`
+
+ // The data to compress should (but is not required to) contain frequent
+ // substrings that match those in the dictionary.
+ const data = `<?xml version="1.0"?>
+<book>
+ <meta name="title" content="The Go Programming Language"/>
+ <meta name="authors" content="Alan Donovan and Brian Kernighan"/>
+ <meta name="published" content="2015-10-26"/>
+ <meta name="isbn" content="978-0134190440"/>
+ <data>...</data>
+</book>
+`
+
+ var b bytes.Buffer
+
+ // Compress the data using the specially crafted dictionary.
+ zw, err := flate.NewWriterDict(&b, flate.DefaultCompression, []byte(dict))
+ if err != nil {
+ log.Fatal(err)
+ }
+ if _, err := io.Copy(zw, strings.NewReader(data)); err != nil {
+ log.Fatal(err)
+ }
+ if err := zw.Close(); err != nil {
+ log.Fatal(err)
+ }
+
+ // The decompressor must use the same dictionary as the compressor.
+ // Otherwise, the input may appear as corrupted.
+ fmt.Println("Decompressed output using the dictionary:")
+ zr := flate.NewReaderDict(bytes.NewReader(b.Bytes()), []byte(dict))
+ if _, err := io.Copy(os.Stdout, zr); err != nil {
+ log.Fatal(err)
+ }
+ if err := zr.Close(); err != nil {
+ log.Fatal(err)
+ }
+
+ fmt.Println()
+
+ // Substitute all of the bytes in the dictionary with a '#' to visually
+ // demonstrate the approximate effectiveness of using a preset dictionary.
+ fmt.Println("Substrings matched by the dictionary are marked with #:")
+ hashDict := []byte(dict)
+ for i := range hashDict {
+ hashDict[i] = '#'
+ }
+ zr = flate.NewReaderDict(&b, hashDict)
+ if _, err := io.Copy(os.Stdout, zr); err != nil {
+ log.Fatal(err)
+ }
+ if err := zr.Close(); err != nil {
+ log.Fatal(err)
+ }
+
+ // Output:
+ // Decompressed output using the dictionary:
+ // <?xml version="1.0"?>
+ // <book>
+ // <meta name="title" content="The Go Programming Language"/>
+ // <meta name="authors" content="Alan Donovan and Brian Kernighan"/>
+ // <meta name="published" content="2015-10-26"/>
+ // <meta name="isbn" content="978-0134190440"/>
+ // <data>...</data>
+ // </book>
+ //
+ // Substrings matched by the dictionary are marked with #:
+ // #####################
+ // ######
+ // ############title###########The Go Programming Language"/#
+ // ############authors###########Alan Donovan and Brian Kernighan"/#
+ // ############published###########2015-10-26"/#
+ // ############isbn###########978-0134190440"/#
+ // ######...</#####
+ // </#####
+}
+
+// DEFLATE is suitable for transmitting compressed data across the network.
+func Example_synchronization() {
+ var wg sync.WaitGroup
+ defer wg.Wait()
+
+ // Use io.Pipe to simulate a network connection.
+ // A real network application should take care to properly close the
+ // underlying connection.
+ rp, wp := io.Pipe()
+
+ // Start a goroutine to act as the transmitter.
+ wg.Add(1)
+ go func() {
+ defer wg.Done()
+
+ zw, err := flate.NewWriter(wp, flate.BestSpeed)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ b := make([]byte, 256)
+ for _, m := range strings.Fields("A long time ago in a galaxy far, far away...") {
+ // We use a simple framing format where the first byte is the
+ // message length, followed the message itself.
+ b[0] = uint8(copy(b[1:], m))
+
+ if _, err := zw.Write(b[:1+len(m)]); err != nil {
+ log.Fatal(err)
+ }
+
+ // Flush ensures that the receiver can read all data sent so far.
+ if err := zw.Flush(); err != nil {
+ log.Fatal(err)
+ }
+ }
+
+ if err := zw.Close(); err != nil {
+ log.Fatal(err)
+ }
+ }()
+
+ // Start a goroutine to act as the receiver.
+ wg.Add(1)
+ go func() {
+ defer wg.Done()
+
+ zr := flate.NewReader(rp)
+
+ b := make([]byte, 256)
+ for {
+ // Read the message length.
+ // This is guaranteed to return for every corresponding
+ // Flush and Close on the transmitter side.
+ if _, err := io.ReadFull(zr, b[:1]); err != nil {
+ if err == io.EOF {
+ break // The transmitter closed the stream
+ }
+ log.Fatal(err)
+ }
+
+ // Read the message content.
+ n := int(b[0])
+ if _, err := io.ReadFull(zr, b[:n]); err != nil {
+ log.Fatal(err)
+ }
+
+ fmt.Printf("Received %d bytes: %s\n", n, b[:n])
+ }
+ fmt.Println()
+
+ if err := zr.Close(); err != nil {
+ log.Fatal(err)
+ }
+ }()
+
+ // Output:
+ // Received 1 bytes: A
+ // Received 4 bytes: long
+ // Received 4 bytes: time
+ // Received 3 bytes: ago
+ // Received 2 bytes: in
+ // Received 1 bytes: a
+ // Received 6 bytes: galaxy
+ // Received 4 bytes: far,
+ // Received 3 bytes: far
+ // Received 7 bytes: away...
+}
diff --git a/src/compress/flate/flate_test.go b/src/compress/flate/flate_test.go
index 83c2049..1e45077 100644
--- a/src/compress/flate/flate_test.go
+++ b/src/compress/flate/flate_test.go
@@ -281,6 +281,7 @@ func TestTruncatedStreams(t *testing.T) {
//
// See https://github.com/google/go-github/pull/317 for background.
func TestReaderEarlyEOF(t *testing.T) {
+ t.Parallel()
testSizes := []int{
1, 2, 3, 4, 5, 6, 7, 8,
100, 1000, 10000, 100000,
diff --git a/src/compress/flate/huffman_bit_writer.go b/src/compress/flate/huffman_bit_writer.go
index d8b5a3e..6cd6281 100644
--- a/src/compress/flate/huffman_bit_writer.go
+++ b/src/compress/flate/huffman_bit_writer.go
@@ -520,7 +520,7 @@ func (w *huffmanBitWriter) writeBlockDynamic(tokens []token, eof bool, input []b
// the literalEncoding and the offsetEncoding.
w.generateCodegen(numLiterals, numOffsets, w.literalEncoding, w.offsetEncoding)
w.codegenEncoding.generate(w.codegenFreq[:], 7)
- size, numCodegens := w.dynamicSize(w.literalEncoding, huffOffset, 0)
+ size, numCodegens := w.dynamicSize(w.literalEncoding, w.offsetEncoding, 0)
// Store bytes, if we don't get a reasonable improvement.
if ssize, storable := w.storedSize(input); storable && ssize < (size+size>>4) {
diff --git a/src/compress/flate/inflate.go b/src/compress/flate/inflate.go
index 68cc232..9a8c4fc 100644
--- a/src/compress/flate/inflate.go
+++ b/src/compress/flate/inflate.go
@@ -344,6 +344,9 @@ func (f *decompressor) Read(b []byte) (int, error) {
return 0, f.err
}
f.step(f)
+ if f.err != nil && len(f.toRead) == 0 {
+ f.toRead = f.dict.readFlush() // Flush what's left in case of error
+ }
}
}
diff --git a/src/compress/flate/inflate_test.go b/src/compress/flate/inflate_test.go
index e0bce71..951decd 100644
--- a/src/compress/flate/inflate_test.go
+++ b/src/compress/flate/inflate_test.go
@@ -7,6 +7,8 @@ package flate
import (
"bytes"
"io"
+ "io/ioutil"
+ "strings"
"testing"
)
@@ -38,6 +40,33 @@ func TestReset(t *testing.T) {
}
}
+func TestReaderTruncated(t *testing.T) {
+ vectors := []struct{ input, output string }{
+ {"\x00", ""},
+ {"\x00\f", ""},
+ {"\x00\f\x00", ""},
+ {"\x00\f\x00\xf3\xff", ""},
+ {"\x00\f\x00\xf3\xffhello", "hello"},
+ {"\x00\f\x00\xf3\xffhello, world", "hello, world"},
+ {"\x02", ""},
+ {"\xf2H\xcd", "He"},
+ {"\xf2H͙0a\u0084\t", "Hel\x90\x90\x90\x90\x90"},
+ {"\xf2H͙0a\u0084\t\x00", "Hel\x90\x90\x90\x90\x90"},
+ }
+
+ for i, v := range vectors {
+ r := strings.NewReader(v.input)
+ zr := NewReader(r)
+ b, err := ioutil.ReadAll(zr)
+ if err != io.ErrUnexpectedEOF {
+ t.Errorf("test %d, error mismatch: got %v, want io.ErrUnexpectedEOF", i, err)
+ }
+ if string(b) != v.output {
+ t.Errorf("test %d, output mismatch: got %q, want %q", i, b, v.output)
+ }
+ }
+}
+
func TestResetDict(t *testing.T) {
dict := []byte("the lorem fox")
ss := []string{
diff --git a/src/compress/flate/writer_test.go b/src/compress/flate/writer_test.go
index 21cd0b2..c4d36aa 100644
--- a/src/compress/flate/writer_test.go
+++ b/src/compress/flate/writer_test.go
@@ -56,6 +56,7 @@ func (e *errorWriter) Write(b []byte) (int, error) {
// Test if errors from the underlying writer is passed upwards.
func TestWriteError(t *testing.T) {
+ t.Parallel()
buf := new(bytes.Buffer)
n := 65536
if !testing.Short() {
@@ -75,7 +76,7 @@ func TestWriteError(t *testing.T) {
if err != nil {
t.Fatalf("NewWriter: level %d: %v", l, err)
}
- n, err := io.CopyBuffer(w, bytes.NewBuffer(in), copyBuffer)
+ n, err := io.CopyBuffer(w, struct{ io.Reader }{bytes.NewBuffer(in)}, copyBuffer)
if err == nil {
t.Fatalf("Level %d: Expected an error, writer was %#v", l, ew)
}
@@ -113,6 +114,7 @@ func TestWriteError(t *testing.T) {
// Test if two runs produce identical results
// even when writing different sizes to the Writer.
func TestDeterministic(t *testing.T) {
+ t.Parallel()
for i := 0; i <= 9; i++ {
t.Run(fmt.Sprint("L", i), func(t *testing.T) { testDeterministic(i, t) })
}
@@ -120,6 +122,7 @@ func TestDeterministic(t *testing.T) {
}
func testDeterministic(i int, t *testing.T) {
+ t.Parallel()
// Test so much we cross a good number of block boundaries.
var length = maxStoreBlockSize*30 + 500
if testing.Short() {
@@ -142,7 +145,7 @@ func testDeterministic(i int, t *testing.T) {
}
// Use a very small prime sized buffer.
cbuf := make([]byte, 787)
- _, err = io.CopyBuffer(w, br, cbuf)
+ _, err = io.CopyBuffer(w, struct{ io.Reader }{br}, cbuf)
if err != nil {
t.Fatal(err)
}
@@ -157,7 +160,7 @@ func testDeterministic(i int, t *testing.T) {
if err != nil {
t.Fatal(err)
}
- _, err = io.CopyBuffer(w2, br2, cbuf)
+ _, err = io.CopyBuffer(w2, struct{ io.Reader }{br2}, cbuf)
if err != nil {
t.Fatal(err)
}
diff --git a/src/compress/gzip/example_test.go b/src/compress/gzip/example_test.go
new file mode 100644
index 0000000..ce29e9b
--- /dev/null
+++ b/src/compress/gzip/example_test.go
@@ -0,0 +1,128 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gzip_test
+
+import (
+ "bytes"
+ "compress/gzip"
+ "fmt"
+ "io"
+ "log"
+ "os"
+ "time"
+)
+
+func Example_writerReader() {
+ var buf bytes.Buffer
+ zw := gzip.NewWriter(&buf)
+
+ // Setting the Header fields is optional.
+ zw.Name = "a-new-hope.txt"
+ zw.Comment = "an epic space opera by George Lucas"
+ zw.ModTime = time.Date(1977, time.May, 25, 0, 0, 0, 0, time.UTC)
+
+ _, err := zw.Write([]byte("A long time ago in a galaxy far, far away..."))
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ if err := zw.Close(); err != nil {
+ log.Fatal(err)
+ }
+
+ zr, err := gzip.NewReader(&buf)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ fmt.Printf("Name: %s\nComment: %s\nModTime: %s\n\n", zr.Name, zr.Comment, zr.ModTime.UTC())
+
+ if _, err := io.Copy(os.Stdout, zr); err != nil {
+ log.Fatal(err)
+ }
+
+ if err := zr.Close(); err != nil {
+ log.Fatal(err)
+ }
+
+ // Output:
+ // Name: a-new-hope.txt
+ // Comment: an epic space opera by George Lucas
+ // ModTime: 1977-05-25 00:00:00 +0000 UTC
+ //
+ // A long time ago in a galaxy far, far away...
+}
+
+func ExampleReader_Multistream() {
+ var buf bytes.Buffer
+ zw := gzip.NewWriter(&buf)
+
+ var files = []struct {
+ name string
+ comment string
+ modTime time.Time
+ data string
+ }{
+ {"file-1.txt", "file-header-1", time.Date(2006, time.February, 1, 3, 4, 5, 0, time.UTC), "Hello Gophers - 1"},
+ {"file-2.txt", "file-header-2", time.Date(2007, time.March, 2, 4, 5, 6, 1, time.UTC), "Hello Gophers - 2"},
+ }
+
+ for _, file := range files {
+ zw.Name = file.name
+ zw.Comment = file.comment
+ zw.ModTime = file.modTime
+
+ if _, err := zw.Write([]byte(file.data)); err != nil {
+ log.Fatal(err)
+ }
+
+ if err := zw.Close(); err != nil {
+ log.Fatal(err)
+ }
+
+ zw.Reset(&buf)
+ }
+
+ zr, err := gzip.NewReader(&buf)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ for {
+ zr.Multistream(false)
+ fmt.Printf("Name: %s\nComment: %s\nModTime: %s\n\n", zr.Name, zr.Comment, zr.ModTime.UTC())
+
+ if _, err := io.Copy(os.Stdout, zr); err != nil {
+ log.Fatal(err)
+ }
+
+ fmt.Print("\n\n")
+
+ err = zr.Reset(&buf)
+ if err == io.EOF {
+ break
+ }
+ if err != nil {
+ log.Fatal(err)
+ }
+ }
+
+ if err := zr.Close(); err != nil {
+ log.Fatal(err)
+ }
+
+ // Output:
+ // Name: file-1.txt
+ // Comment: file-header-1
+ // ModTime: 2006-02-01 03:04:05 +0000 UTC
+ //
+ // Hello Gophers - 1
+ //
+ // Name: file-2.txt
+ // Comment: file-header-2
+ // ModTime: 2007-03-02 04:05:06 +0000 UTC
+ //
+ // Hello Gophers - 2
+}
diff --git a/src/compress/gzip/gunzip.go b/src/compress/gzip/gunzip.go
index 7e64069..8bd750b 100644
--- a/src/compress/gzip/gunzip.go
+++ b/src/compress/gzip/gunzip.go
@@ -186,7 +186,11 @@ func (z *Reader) readHeader() (hdr Header, err error) {
return hdr, ErrHeader
}
flg := z.buf[3]
- hdr.ModTime = time.Unix(int64(le.Uint32(z.buf[4:8])), 0)
+ if t := int64(le.Uint32(z.buf[4:8])); t > 0 {
+ // Section 2.3.1, the zero value for MTIME means that the
+ // modified time is not set.
+ hdr.ModTime = time.Unix(t, 0)
+ }
// z.buf[8] is XFL and is currently ignored.
hdr.OS = z.buf[9]
z.digest = crc32.ChecksumIEEE(z.buf[:10])
@@ -238,6 +242,7 @@ func (z *Reader) readHeader() (hdr Header, err error) {
return hdr, nil
}
+// Read implements io.Reader, reading uncompressed bytes from its underlying Reader.
func (z *Reader) Read(p []byte) (n int, err error) {
if z.err != nil {
return 0, z.err
diff --git a/src/compress/gzip/gunzip_test.go b/src/compress/gzip/gunzip_test.go
index fdce919..fdea0c5 100644
--- a/src/compress/gzip/gunzip_test.go
+++ b/src/compress/gzip/gunzip_test.go
@@ -339,6 +339,26 @@ var gunzipTests = []gunzipTest{
},
nil,
},
+ {
+ "",
+ "truncated gzip file amid raw-block",
+ "hello",
+ []byte{
+ 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0x00, 0x0c, 0x00, 0xf3, 0xff, 0x68, 0x65, 0x6c, 0x6c, 0x6f,
+ },
+ io.ErrUnexpectedEOF,
+ },
+ {
+ "",
+ "truncated gzip file amid fixed-block",
+ "He",
+ []byte{
+ 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xf2, 0x48, 0xcd,
+ },
+ io.ErrUnexpectedEOF,
+ },
}
func TestDecompressor(t *testing.T) {
diff --git a/src/compress/gzip/gzip.go b/src/compress/gzip/gzip.go
index c702c49..aafb442 100644
--- a/src/compress/gzip/gzip.go
+++ b/src/compress/gzip/gzip.go
@@ -10,6 +10,7 @@ import (
"fmt"
"hash/crc32"
"io"
+ "time"
)
// These constants are copied from the flate package, so that code that imports
@@ -19,6 +20,7 @@ const (
BestSpeed = flate.BestSpeed
BestCompression = flate.BestCompression
DefaultCompression = flate.DefaultCompression
+ HuffmanOnly = flate.HuffmanOnly
)
// A Writer is an io.WriteCloser.
@@ -52,11 +54,11 @@ func NewWriter(w io.Writer) *Writer {
// NewWriterLevel is like NewWriter but specifies the compression level instead
// of assuming DefaultCompression.
//
-// The compression level can be DefaultCompression, NoCompression, or any
-// integer value between BestSpeed and BestCompression inclusive. The error
-// returned will be nil if the level is valid.
+// The compression level can be DefaultCompression, NoCompression, HuffmanOnly
+// or any integer value between BestSpeed and BestCompression inclusive.
+// The error returned will be nil if the level is valid.
func NewWriterLevel(w io.Writer, level int) (*Writer, error) {
- if level < DefaultCompression || level > BestCompression {
+ if level < HuffmanOnly || level > BestCompression {
return nil, fmt.Errorf("gzip: invalid compression level: %d", level)
}
z := new(Writer)
@@ -142,10 +144,7 @@ func (z *Writer) Write(p []byte) (int, error) {
// Write the GZIP header lazily.
if !z.wroteHeader {
z.wroteHeader = true
- z.buf[0] = gzipID1
- z.buf[1] = gzipID2
- z.buf[2] = gzipDeflate
- z.buf[3] = 0
+ z.buf = [10]byte{0: gzipID1, 1: gzipID2, 2: gzipDeflate}
if z.Extra != nil {
z.buf[3] |= 0x04
}
@@ -155,13 +154,15 @@ func (z *Writer) Write(p []byte) (int, error) {
if z.Comment != "" {
z.buf[3] |= 0x10
}
- le.PutUint32(z.buf[4:8], uint32(z.ModTime.Unix()))
+ if z.ModTime.After(time.Unix(0, 0)) {
+ // Section 2.3.1, the zero value for MTIME means that the
+ // modified time is not set.
+ le.PutUint32(z.buf[4:8], uint32(z.ModTime.Unix()))
+ }
if z.level == BestCompression {
z.buf[8] = 2
} else if z.level == BestSpeed {
z.buf[8] = 4
- } else {
- z.buf[8] = 0
}
z.buf[9] = z.OS
n, z.err = z.w.Write(z.buf[:10])
diff --git a/src/compress/gzip/gzip_test.go b/src/compress/gzip/gzip_test.go
index 09271b2..865c529 100644
--- a/src/compress/gzip/gzip_test.go
+++ b/src/compress/gzip/gzip_test.go
@@ -8,6 +8,7 @@ import (
"bufio"
"bytes"
"io/ioutil"
+ "reflect"
"testing"
"time"
)
@@ -24,6 +25,9 @@ func TestEmpty(t *testing.T) {
if err != nil {
t.Fatalf("NewReader: %v", err)
}
+ if want := (Header{OS: 255}); !reflect.DeepEqual(r.Header, want) {
+ t.Errorf("Header mismatch:\ngot %#v\nwant %#v", r.Header, want)
+ }
b, err := ioutil.ReadAll(r)
if err != nil {
t.Fatalf("ReadAll: %v", err)
diff --git a/src/compress/gzip/issue14937_test.go b/src/compress/gzip/issue14937_test.go
index 432ad16..e76d47c 100644
--- a/src/compress/gzip/issue14937_test.go
+++ b/src/compress/gzip/issue14937_test.go
@@ -7,7 +7,6 @@ import (
"runtime"
"strings"
"testing"
- "time"
)
// Per golang.org/issue/14937, check that every .gz file
@@ -16,8 +15,12 @@ func TestGZIPFilesHaveZeroMTimes(t *testing.T) {
if testing.Short() && testenv.Builder() == "" {
t.Skip("skipping in short mode")
}
+ goroot, err := filepath.EvalSymlinks(runtime.GOROOT())
+ if err != nil {
+ t.Fatal("error evaluating GOROOT: ", err)
+ }
var files []string
- err := filepath.Walk(runtime.GOROOT(), func(path string, info os.FileInfo, err error) error {
+ err = filepath.Walk(goroot, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
@@ -53,7 +56,7 @@ func checkZeroMTime(t *testing.T, path string) {
return
}
defer gz.Close()
- if !gz.ModTime.Equal(time.Unix(0, 0)) {
+ if !gz.ModTime.IsZero() {
t.Errorf("gzip file %s has non-zero mtime (%s)", path, gz.ModTime)
}
}
diff --git a/src/compress/zlib/reader_test.go b/src/compress/zlib/reader_test.go
index f74bff1..7e27aec 100644
--- a/src/compress/zlib/reader_test.go
+++ b/src/compress/zlib/reader_test.go
@@ -121,6 +121,24 @@ var zlibTests = []zlibTest{
},
ErrDictionary,
},
+ {
+ "truncated zlib stream amid raw-block",
+ "hello",
+ []byte{
+ 0x78, 0x9c, 0x00, 0x0c, 0x00, 0xf3, 0xff, 0x68, 0x65, 0x6c, 0x6c, 0x6f,
+ },
+ nil,
+ io.ErrUnexpectedEOF,
+ },
+ {
+ "truncated zlib stream amid fixed-block",
+ "He",
+ []byte{
+ 0x78, 0x9c, 0xf2, 0x48, 0xcd,
+ },
+ nil,
+ io.ErrUnexpectedEOF,
+ },
}
func TestDecompressor(t *testing.T) {
diff --git a/src/compress/zlib/writer.go b/src/compress/zlib/writer.go
index 3b4313a..1620c00 100644
--- a/src/compress/zlib/writer.go
+++ b/src/compress/zlib/writer.go
@@ -19,6 +19,7 @@ const (
BestSpeed = flate.BestSpeed
BestCompression = flate.BestCompression
DefaultCompression = flate.DefaultCompression
+ HuffmanOnly = flate.HuffmanOnly
)
// A Writer takes data written to it and writes the compressed
@@ -47,9 +48,9 @@ func NewWriter(w io.Writer) *Writer {
// NewWriterLevel is like NewWriter but specifies the compression level instead
// of assuming DefaultCompression.
//
-// The compression level can be DefaultCompression, NoCompression, or any
-// integer value between BestSpeed and BestCompression inclusive. The error
-// returned will be nil if the level is valid.
+// The compression level can be DefaultCompression, NoCompression, HuffmanOnly
+// or any integer value between BestSpeed and BestCompression inclusive.
+// The error returned will be nil if the level is valid.
func NewWriterLevel(w io.Writer, level int) (*Writer, error) {
return NewWriterLevelDict(w, level, nil)
}
@@ -60,7 +61,7 @@ func NewWriterLevel(w io.Writer, level int) (*Writer, error) {
// The dictionary may be nil. If not, its contents should not be modified until
// the Writer is closed.
func NewWriterLevelDict(w io.Writer, level int, dict []byte) (*Writer, error) {
- if level < DefaultCompression || level > BestCompression {
+ if level < HuffmanOnly || level > BestCompression {
return nil, fmt.Errorf("zlib: invalid compression level: %d", level)
}
return &Writer{
@@ -99,7 +100,7 @@ func (z *Writer) writeHeader() (err error) {
// The next bit, FDICT, is set if a dictionary is given.
// The final five FCHECK bits form a mod-31 checksum.
switch z.level {
- case 0, 1:
+ case -2, 0, 1:
z.scratch[1] = 0 << 6
case 2, 3, 4, 5:
z.scratch[1] = 1 << 6
diff --git a/src/compress/zlib/writer_test.go b/src/compress/zlib/writer_test.go
index dd94165..d501974 100644
--- a/src/compress/zlib/writer_test.go
+++ b/src/compress/zlib/writer_test.go
@@ -147,6 +147,7 @@ func TestWriter(t *testing.T) {
tag := fmt.Sprintf("#%d", i)
testLevelDict(t, tag, b, DefaultCompression, "")
testLevelDict(t, tag, b, NoCompression, "")
+ testLevelDict(t, tag, b, HuffmanOnly, "")
for level := BestSpeed; level <= BestCompression; level++ {
testLevelDict(t, tag, b, level, "")
}
@@ -157,6 +158,7 @@ func TestWriterBig(t *testing.T) {
for i, fn := range filenames {
testFileLevelDict(t, fn, DefaultCompression, "")
testFileLevelDict(t, fn, NoCompression, "")
+ testFileLevelDict(t, fn, HuffmanOnly, "")
for level := BestSpeed; level <= BestCompression; level++ {
testFileLevelDict(t, fn, level, "")
if level >= 1 && testing.Short() && testenv.Builder() == "" {
@@ -174,6 +176,7 @@ func TestWriterDict(t *testing.T) {
for i, fn := range filenames {
testFileLevelDict(t, fn, DefaultCompression, dictionary)
testFileLevelDict(t, fn, NoCompression, dictionary)
+ testFileLevelDict(t, fn, HuffmanOnly, dictionary)
for level := BestSpeed; level <= BestCompression; level++ {
testFileLevelDict(t, fn, level, dictionary)
if level >= 1 && testing.Short() && testenv.Builder() == "" {
@@ -191,8 +194,10 @@ func TestWriterReset(t *testing.T) {
for _, fn := range filenames {
testFileLevelDictReset(t, fn, NoCompression, nil)
testFileLevelDictReset(t, fn, DefaultCompression, nil)
+ testFileLevelDictReset(t, fn, HuffmanOnly, nil)
testFileLevelDictReset(t, fn, NoCompression, []byte(dictionary))
testFileLevelDictReset(t, fn, DefaultCompression, []byte(dictionary))
+ testFileLevelDictReset(t, fn, HuffmanOnly, []byte(dictionary))
if testing.Short() {
break
}
diff --git a/src/container/heap/heap.go b/src/container/heap/heap.go
index 5fe23b9..7110c51 100644
--- a/src/container/heap/heap.go
+++ b/src/container/heap/heap.go
@@ -83,8 +83,9 @@ func Remove(h Interface, i int) interface{} {
// but less expensive than, calling Remove(h, i) followed by a Push of the new value.
// The complexity is O(log(n)) where n = h.Len().
func Fix(h Interface, i int) {
- down(h, i, h.Len())
- up(h, i)
+ if !down(h, i, h.Len()) {
+ up(h, i)
+ }
}
func up(h Interface, j int) {
@@ -98,7 +99,8 @@ func up(h Interface, j int) {
}
}
-func down(h Interface, i, n int) {
+func down(h Interface, i0, n int) bool {
+ i := i0
for {
j1 := 2*i + 1
if j1 >= n || j1 < 0 { // j1 < 0 after int overflow
@@ -114,4 +116,5 @@ func down(h Interface, i, n int) {
h.Swap(i, j)
i = j
}
+ return i > i0
}
diff --git a/src/container/list/list_test.go b/src/container/list/list_test.go
index e3bfe53..99e006f 100644
--- a/src/container/list/list_test.go
+++ b/src/container/list/list_test.go
@@ -271,7 +271,7 @@ func TestMove(t *testing.T) {
l.MoveBefore(e2, e4)
checkListPointers(t, l, []*Element{e1, e3, e2, e4})
- e1, e2, e3, e4 = e1, e3, e2, e4
+ e2, e3 = e3, e2
l.MoveBefore(e4, e1)
checkListPointers(t, l, []*Element{e4, e1, e2, e3})
@@ -279,11 +279,11 @@ func TestMove(t *testing.T) {
l.MoveAfter(e4, e1)
checkListPointers(t, l, []*Element{e1, e4, e2, e3})
- e1, e2, e3, e4 = e1, e4, e2, e3
+ e2, e3, e4 = e4, e2, e3
l.MoveAfter(e2, e3)
checkListPointers(t, l, []*Element{e1, e3, e2, e4})
- e1, e2, e3, e4 = e1, e3, e2, e4
+ e2, e3 = e3, e2
}
// Test PushFront, PushBack, PushFrontList, PushBackList with uninitialized List
diff --git a/src/context/benchmark_test.go b/src/context/benchmark_test.go
new file mode 100644
index 0000000..b792327
--- /dev/null
+++ b/src/context/benchmark_test.go
@@ -0,0 +1,44 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package context_test
+
+import (
+ . "context"
+ "fmt"
+ "testing"
+)
+
+func BenchmarkContextCancelTree(b *testing.B) {
+ depths := []int{1, 10, 100, 1000}
+ for _, d := range depths {
+ b.Run(fmt.Sprintf("depth=%d", d), func(b *testing.B) {
+ b.Run("Root=Background", func(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ buildContextTree(Background(), d)
+ }
+ })
+ b.Run("Root=OpenCanceler", func(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ ctx, cancel := WithCancel(Background())
+ buildContextTree(ctx, d)
+ cancel()
+ }
+ })
+ b.Run("Root=ClosedCanceler", func(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ ctx, cancel := WithCancel(Background())
+ cancel()
+ buildContextTree(ctx, d)
+ }
+ })
+ })
+ }
+}
+
+func buildContextTree(root Context, depth int) {
+ for d := 0; d < depth; d++ {
+ root, _ = WithCancel(root)
+ }
+}
diff --git a/src/context/context.go b/src/context/context.go
index f8ce9cc..0aa7c24 100644
--- a/src/context/context.go
+++ b/src/context/context.go
@@ -159,9 +159,9 @@ var DeadlineExceeded error = deadlineExceededError{}
type deadlineExceededError struct{}
-func (deadlineExceededError) Error() string { return "context deadline exceeded" }
-
-func (deadlineExceededError) Timeout() bool { return true }
+func (deadlineExceededError) Error() string { return "context deadline exceeded" }
+func (deadlineExceededError) Timeout() bool { return true }
+func (deadlineExceededError) Temporary() bool { return true }
// An emptyCtx is never canceled, has no values, and has no deadline. It is not
// struct{}, since vars of this type must have distinct addresses.
@@ -252,9 +252,9 @@ func propagateCancel(parent Context, child canceler) {
child.cancel(false, p.err)
} else {
if p.children == nil {
- p.children = make(map[canceler]bool)
+ p.children = make(map[canceler]struct{})
}
- p.children[child] = true
+ p.children[child] = struct{}{}
}
p.mu.Unlock()
} else {
@@ -314,8 +314,8 @@ type cancelCtx struct {
done chan struct{} // closed by the first cancel call.
mu sync.Mutex
- children map[canceler]bool // set to nil by the first cancel call
- err error // set to non-nil by the first cancel call
+ 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{} {
@@ -376,7 +376,7 @@ func WithDeadline(parent Context, deadline time.Time) (Context, CancelFunc) {
deadline: deadline,
}
propagateCancel(parent, c)
- d := deadline.Sub(time.Now())
+ d := time.Until(deadline)
if d <= 0 {
c.cancel(true, DeadlineExceeded) // deadline has already passed
return c, func() { c.cancel(true, Canceled) }
@@ -406,7 +406,7 @@ func (c *timerCtx) Deadline() (deadline time.Time, ok bool) {
}
func (c *timerCtx) String() string {
- return fmt.Sprintf("%v.WithDeadline(%s [%s])", c.cancelCtx.Context, c.deadline, c.deadline.Sub(time.Now()))
+ return fmt.Sprintf("%v.WithDeadline(%s [%s])", c.cancelCtx.Context, c.deadline, time.Until(c.deadline))
}
func (c *timerCtx) cancel(removeFromParent bool, err error) {
@@ -443,7 +443,13 @@ func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc) {
// Use context Values only for request-scoped data that transits processes and
// APIs, not for passing optional parameters to functions.
//
-// The provided key must be comparable.
+// The provided key must be comparable and should not be of type
+// string or any other built-in type to avoid collisions between
+// packages using context. Users of WithValue should define their own
+// types for keys. To avoid allocating when assigning to an
+// interface{}, context keys often have concrete type
+// struct{}. Alternatively, exported context key variables' static
+// type should be a pointer or interface.
func WithValue(parent Context, key, val interface{}) Context {
if key == nil {
panic("nil key")
diff --git a/src/context/context_test.go b/src/context/context_test.go
index cf18211..2d604a0 100644
--- a/src/context/context_test.go
+++ b/src/context/context_test.go
@@ -10,10 +10,26 @@ import (
"runtime"
"strings"
"sync"
- "testing"
"time"
)
+type testingT interface {
+ Error(args ...interface{})
+ Errorf(format string, args ...interface{})
+ Fail()
+ FailNow()
+ Failed() bool
+ Fatal(args ...interface{})
+ Fatalf(format string, args ...interface{})
+ Log(args ...interface{})
+ Logf(format string, args ...interface{})
+ Name() string
+ Skip(args ...interface{})
+ SkipNow()
+ Skipf(format string, args ...interface{})
+ Skipped() bool
+}
+
// otherContext is a Context that's not one of the types defined in context.go.
// This lets us test code paths that differ based on the underlying type of the
// Context.
@@ -21,7 +37,7 @@ type otherContext struct {
Context
}
-func TestBackground(t *testing.T) {
+func XTestBackground(t testingT) {
c := Background()
if c == nil {
t.Fatalf("Background returned nil")
@@ -36,7 +52,7 @@ func TestBackground(t *testing.T) {
}
}
-func TestTODO(t *testing.T) {
+func XTestTODO(t testingT) {
c := TODO()
if c == nil {
t.Fatalf("TODO returned nil")
@@ -51,7 +67,7 @@ func TestTODO(t *testing.T) {
}
}
-func TestWithCancel(t *testing.T) {
+func XTestWithCancel(t testingT) {
c1, cancel := WithCancel(Background())
if got, want := fmt.Sprint(c1), "context.Background.WithCancel"; got != want {
@@ -92,7 +108,12 @@ func TestWithCancel(t *testing.T) {
}
}
-func TestParentFinishesChild(t *testing.T) {
+func contains(m map[canceler]struct{}, key canceler) bool {
+ _, ret := m[key]
+ return ret
+}
+
+func XTestParentFinishesChild(t testingT) {
// Context tree:
// parent -> cancelChild
// parent -> valueChild -> timerChild
@@ -120,7 +141,7 @@ func TestParentFinishesChild(t *testing.T) {
cc := cancelChild.(*cancelCtx)
tc := timerChild.(*timerCtx)
pc.mu.Lock()
- if len(pc.children) != 2 || !pc.children[cc] || !pc.children[tc] {
+ if len(pc.children) != 2 || !contains(pc.children, cc) || !contains(pc.children, tc) {
t.Errorf("bad linkage: pc.children = %v, want %v and %v",
pc.children, cc, tc)
}
@@ -169,7 +190,7 @@ func TestParentFinishesChild(t *testing.T) {
}
}
-func TestChildFinishesFirst(t *testing.T) {
+func XTestChildFinishesFirst(t testingT) {
cancelable, stop := WithCancel(Background())
defer stop()
for _, parent := range []Context{Background(), cancelable} {
@@ -191,7 +212,7 @@ func TestChildFinishesFirst(t *testing.T) {
if pcok {
pc.mu.Lock()
- if len(pc.children) != 1 || !pc.children[cc] {
+ if len(pc.children) != 1 || !contains(pc.children, cc) {
t.Errorf("bad linkage: pc.children = %v, cc = %v", pc.children, cc)
}
pc.mu.Unlock()
@@ -229,7 +250,7 @@ func TestChildFinishesFirst(t *testing.T) {
}
}
-func testDeadline(c Context, name string, failAfter time.Duration, t *testing.T) {
+func testDeadline(c Context, name string, failAfter time.Duration, t testingT) {
select {
case <-time.After(failAfter):
t.Fatalf("%s: context should have timed out", name)
@@ -240,7 +261,7 @@ func testDeadline(c Context, name string, failAfter time.Duration, t *testing.T)
}
}
-func TestDeadline(t *testing.T) {
+func XTestDeadline(t testingT) {
c, _ := WithDeadline(Background(), time.Now().Add(50*time.Millisecond))
if got, prefix := fmt.Sprint(c), "context.Background.WithDeadline("; !strings.HasPrefix(got, prefix) {
t.Errorf("c.String() = %q want prefix %q", got, prefix)
@@ -263,7 +284,7 @@ func TestDeadline(t *testing.T) {
testDeadline(c, "WithDeadline+now", time.Second, t)
}
-func TestTimeout(t *testing.T) {
+func XTestTimeout(t testingT) {
c, _ := WithTimeout(Background(), 50*time.Millisecond)
if got, prefix := fmt.Sprint(c), "context.Background.WithDeadline("; !strings.HasPrefix(got, prefix) {
t.Errorf("c.String() = %q want prefix %q", got, prefix)
@@ -280,7 +301,7 @@ func TestTimeout(t *testing.T) {
testDeadline(c, "WithTimeout+otherContext+WithTimeout", 2*time.Second, t)
}
-func TestCanceledTimeout(t *testing.T) {
+func XTestCanceledTimeout(t testingT) {
c, _ := WithTimeout(Background(), time.Second)
o := otherContext{c}
c, cancel := WithTimeout(o, 2*time.Second)
@@ -303,7 +324,7 @@ var k1 = key1(1)
var k2 = key2(1) // same int as k1, different type
var k3 = key2(3) // same type as k2, different int
-func TestValues(t *testing.T) {
+func XTestValues(t testingT) {
check := func(c Context, nm, v1, v2, v3 string) {
if v, ok := c.Value(k1).(string); ok == (len(v1) == 0) || v != v1 {
t.Errorf(`%s.Value(k1).(string) = %q, %t want %q, %t`, nm, v, ok, v1, len(v1) != 0)
@@ -351,7 +372,7 @@ func TestValues(t *testing.T) {
check(o4, "o4", "", "c2k2", "")
}
-func TestAllocs(t *testing.T) {
+func XTestAllocs(t testingT, testingShort func() bool, testingAllocsPerRun func(int, func()) float64) {
bg := Background()
for _, test := range []struct {
desc string
@@ -411,16 +432,16 @@ func TestAllocs(t *testing.T) {
limit = test.gccgoLimit
}
numRuns := 100
- if testing.Short() {
+ if testingShort() {
numRuns = 10
}
- if n := testing.AllocsPerRun(numRuns, test.f); n > limit {
+ if n := testingAllocsPerRun(numRuns, test.f); n > limit {
t.Errorf("%s allocs = %f want %d", test.desc, n, int(limit))
}
}
}
-func TestSimultaneousCancels(t *testing.T) {
+func XTestSimultaneousCancels(t testingT) {
root, cancel := WithCancel(Background())
m := map[Context]CancelFunc{root: cancel}
q := []Context{root}
@@ -468,7 +489,7 @@ func TestSimultaneousCancels(t *testing.T) {
}
}
-func TestInterlockedCancels(t *testing.T) {
+func XTestInterlockedCancels(t testingT) {
parent, cancelParent := WithCancel(Background())
child, cancelChild := WithCancel(parent)
go func() {
@@ -485,15 +506,15 @@ func TestInterlockedCancels(t *testing.T) {
}
}
-func TestLayersCancel(t *testing.T) {
+func XTestLayersCancel(t testingT) {
testLayers(t, time.Now().UnixNano(), false)
}
-func TestLayersTimeout(t *testing.T) {
+func XTestLayersTimeout(t testingT) {
testLayers(t, time.Now().UnixNano(), true)
}
-func testLayers(t *testing.T, seed int64, testTimeout bool) {
+func testLayers(t testingT, seed int64, testTimeout bool) {
rand.Seed(seed)
errorf := func(format string, a ...interface{}) {
t.Errorf(fmt.Sprintf("seed=%d: %s", seed, format), a...)
@@ -562,7 +583,7 @@ func testLayers(t *testing.T, seed int64, testTimeout bool) {
}
}
-func TestCancelRemoves(t *testing.T) {
+func XTestCancelRemoves(t testingT) {
checkChildren := func(when string, ctx Context, want int) {
if got := len(ctx.(*cancelCtx).children); got != want {
t.Errorf("%s: context has %d children, want %d", when, got, want)
@@ -584,7 +605,22 @@ func TestCancelRemoves(t *testing.T) {
checkChildren("after cancelling WithTimeout child", ctx, 0)
}
-func TestWithValueChecksKey(t *testing.T) {
+func XTestWithCancelCanceledParent(t testingT) {
+ parent, pcancel := WithCancel(Background())
+ pcancel()
+
+ c, _ := WithCancel(parent)
+ select {
+ case <-c.Done():
+ case <-time.After(5 * time.Second):
+ t.Fatal("timeout waiting for Done")
+ }
+ if got, want := c.Err(), Canceled; got != want {
+ t.Errorf("child not cancelled; got = %v, want = %v", got, want)
+ }
+}
+
+func XTestWithValueChecksKey(t testingT) {
panicVal := recoveredValue(func() { WithValue(Background(), []byte("foo"), "bar") })
if panicVal == nil {
t.Error("expected panic")
@@ -601,7 +637,7 @@ func recoveredValue(fn func()) (v interface{}) {
return
}
-func TestDeadlineExceededSupportsTimeout(t *testing.T) {
+func XTestDeadlineExceededSupportsTimeout(t testingT) {
i, ok := DeadlineExceeded.(interface {
Timeout() bool
})
diff --git a/src/context/example_test.go b/src/context/example_test.go
new file mode 100644
index 0000000..2d48d4e
--- /dev/null
+++ b/src/context/example_test.go
@@ -0,0 +1,116 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package context_test
+
+import (
+ "context"
+ "fmt"
+ "time"
+)
+
+// This example demonstrates the use of a cancelable context to prevent a
+// goroutine leak. By the end of the example function, the goroutine started
+// by gen will return without leaking.
+func ExampleWithCancel() {
+ // gen generates integers in a separate goroutine and
+ // sends them to the returned channel.
+ // The callers of gen need to cancel the context once
+ // they are done consuming generated integers not to leak
+ // the internal goroutine started by gen.
+ gen := func(ctx context.Context) <-chan int {
+ dst := make(chan int)
+ n := 1
+ go func() {
+ for {
+ select {
+ case <-ctx.Done():
+ return // returning not to leak the goroutine
+ case dst <- n:
+ n++
+ }
+ }
+ }()
+ return dst
+ }
+
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel() // cancel when we are finished consuming integers
+
+ for n := range gen(ctx) {
+ fmt.Println(n)
+ if n == 5 {
+ break
+ }
+ }
+ // Output:
+ // 1
+ // 2
+ // 3
+ // 4
+ // 5
+}
+
+// This example passes a context with a arbitrary deadline to tell a blocking
+// function that it should abandon its work as soon as it gets to it.
+func ExampleWithDeadline() {
+ d := time.Now().Add(50 * time.Millisecond)
+ ctx, cancel := context.WithDeadline(context.Background(), d)
+
+ // Even though ctx will be expired, it is good practice to call its
+ // cancelation function in any case. Failure to do so may keep the
+ // context and its parent alive longer than necessary.
+ defer cancel()
+
+ select {
+ case <-time.After(1 * time.Second):
+ fmt.Println("overslept")
+ case <-ctx.Done():
+ fmt.Println(ctx.Err())
+ }
+
+ // Output:
+ // context deadline exceeded
+}
+
+// This example passes a context with a timeout to tell a blocking function that
+// it should abandon its work after the timeout elapses.
+func ExampleWithTimeout() {
+ // Pass a context with a timeout to tell a blocking function that it
+ // should abandon its work after the timeout elapses.
+ ctx, cancel := context.WithTimeout(context.Background(), 50*time.Millisecond)
+ defer cancel()
+
+ select {
+ case <-time.After(1 * time.Second):
+ fmt.Println("overslept")
+ case <-ctx.Done():
+ fmt.Println(ctx.Err()) // prints "context deadline exceeded"
+ }
+
+ // Output:
+ // context deadline exceeded
+}
+
+func ExampleWithValue() {
+ type favContextKey string
+
+ f := func(ctx context.Context, k favContextKey) {
+ if v := ctx.Value(k); v != nil {
+ fmt.Println("found value:", v)
+ return
+ }
+ fmt.Println("key not found:", k)
+ }
+
+ k := favContextKey("language")
+ ctx := context.WithValue(context.Background(), k, "Go")
+
+ f(ctx, k)
+ f(ctx, favContextKey("color"))
+
+ // Output:
+ // found value: Go
+ // key not found: color
+}
diff --git a/src/context/net_test.go b/src/context/net_test.go
new file mode 100644
index 0000000..a007689
--- /dev/null
+++ b/src/context/net_test.go
@@ -0,0 +1,21 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package context_test
+
+import (
+ "context"
+ "net"
+ "testing"
+)
+
+func TestDeadlineExceededIsNetError(t *testing.T) {
+ err, ok := context.DeadlineExceeded.(net.Error)
+ if !ok {
+ t.Fatal("DeadlineExceeded does not implement net.Error")
+ }
+ if !err.Timeout() || !err.Temporary() {
+ t.Fatalf("Timeout() = %v, Temporary() = %v, want true, true", err.Timeout(), err.Temporary())
+ }
+}
diff --git a/src/context/withtimeout_test.go b/src/context/withtimeout_test.go
deleted file mode 100644
index a3e8979..0000000
--- a/src/context/withtimeout_test.go
+++ /dev/null
@@ -1,33 +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 context_test
-
-import (
- "context"
- "fmt"
- "time"
-)
-
-func ExampleWithTimeout() {
- // Pass a context with a timeout to tell a blocking function that it
- // should abandon its work after the timeout elapses.
- ctx, cancel := context.WithTimeout(context.Background(), 50*time.Millisecond)
-
- select {
- case <-time.After(1 * time.Second):
- fmt.Println("overslept")
- case <-ctx.Done():
- fmt.Println(ctx.Err()) // prints "context deadline exceeded"
- }
-
- // Even though ctx should have expired already, it is good
- // practice to call its cancelation function in any case.
- // Failure to do so may keep the context and its parent alive
- // longer than necessary.
- cancel()
-
- // Output:
- // context deadline exceeded
-}
diff --git a/src/context/x_test.go b/src/context/x_test.go
new file mode 100644
index 0000000..d14b6f1
--- /dev/null
+++ b/src/context/x_test.go
@@ -0,0 +1,29 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package context_test
+
+import (
+ . "context"
+ "testing"
+)
+
+func TestBackground(t *testing.T) { XTestBackground(t) }
+func TestTODO(t *testing.T) { XTestTODO(t) }
+func TestWithCancel(t *testing.T) { XTestWithCancel(t) }
+func TestParentFinishesChild(t *testing.T) { XTestParentFinishesChild(t) }
+func TestChildFinishesFirst(t *testing.T) { XTestChildFinishesFirst(t) }
+func TestDeadline(t *testing.T) { XTestDeadline(t) }
+func TestTimeout(t *testing.T) { XTestTimeout(t) }
+func TestCanceledTimeout(t *testing.T) { XTestCanceledTimeout(t) }
+func TestValues(t *testing.T) { XTestValues(t) }
+func TestAllocs(t *testing.T) { XTestAllocs(t, testing.Short, testing.AllocsPerRun) }
+func TestSimultaneousCancels(t *testing.T) { XTestSimultaneousCancels(t) }
+func TestInterlockedCancels(t *testing.T) { XTestInterlockedCancels(t) }
+func TestLayersCancel(t *testing.T) { XTestLayersCancel(t) }
+func TestLayersTimeout(t *testing.T) { XTestLayersTimeout(t) }
+func TestCancelRemoves(t *testing.T) { XTestCancelRemoves(t) }
+func TestWithCancelCanceledParent(t *testing.T) { XTestWithCancelCanceledParent(t) }
+func TestWithValueChecksKey(t *testing.T) { XTestWithValueChecksKey(t) }
+func TestDeadlineExceededSupportsTimeout(t *testing.T) { XTestDeadlineExceededSupportsTimeout(t) }
diff --git a/src/crypto/aes/aes_gcm.go b/src/crypto/aes/aes_gcm.go
index a894a68..5e2de02 100644
--- a/src/crypto/aes/aes_gcm.go
+++ b/src/crypto/aes/aes_gcm.go
@@ -99,6 +99,9 @@ func (g *gcmAsm) Seal(dst, nonce, plaintext, data []byte) []byte {
if len(nonce) != g.nonceSize {
panic("cipher: incorrect nonce length given to GCM")
}
+ if uint64(len(plaintext)) > ((1<<32)-2)*BlockSize {
+ panic("cipher: message too large for GCM")
+ }
var counter, tagMask [gcmBlockSize]byte
@@ -137,6 +140,10 @@ func (g *gcmAsm) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) {
if len(ciphertext) < gcmTagSize {
return nil, errOpen
}
+ if uint64(len(ciphertext)) > ((1<<32)-2)*BlockSize+gcmTagSize {
+ return nil, errOpen
+ }
+
tag := ciphertext[len(ciphertext)-gcmTagSize:]
ciphertext = ciphertext[:len(ciphertext)-gcmTagSize]
diff --git a/src/crypto/aes/asm_amd64.s b/src/crypto/aes/asm_amd64.s
index b257998..ad871ec 100644
--- a/src/crypto/aes/asm_amd64.s
+++ b/src/crypto/aes/asm_amd64.s
@@ -4,17 +4,6 @@
#include "textflag.h"
-// func hasAsm() bool
-// returns whether AES-NI is supported
-TEXT ·hasAsm(SB),NOSPLIT,$0
- XORQ AX, AX
- INCL AX
- CPUID
- SHRQ $25, CX
- ANDQ $1, CX
- MOVB CX, ret+0(FP)
- RET
-
// func encryptBlockAsm(nr int, xk *uint32, dst, src *byte)
TEXT ·encryptBlockAsm(SB),NOSPLIT,$0
MOVQ nr+0(FP), CX
diff --git a/src/crypto/aes/asm_s390x.s b/src/crypto/aes/asm_s390x.s
index e31415a..2cf3ddd 100644
--- a/src/crypto/aes/asm_s390x.s
+++ b/src/crypto/aes/asm_s390x.s
@@ -4,44 +4,20 @@
#include "textflag.h"
-// func hasAsm() bool
-TEXT ·hasAsm(SB),NOSPLIT,$16-1
- XOR R0, R0 // set function code to 0 (query)
- LA mask-16(SP), R1 // 16-byte stack variable for mask
- MOVD $(0x38<<40), R3 // mask for bits 18-20 (big endian)
-
- // check for KM AES functions
- WORD $0xB92E0024 // cipher message (KM)
- MOVD mask-16(SP), R2
- AND R3, R2
- CMPBNE R2, R3, notfound
-
- // check for KMC AES functions
- WORD $0xB92F0024 // cipher message with chaining (KMC)
- MOVD mask-16(SP), R2
- AND R3, R2
- CMPBNE R2, R3, notfound
-
- MOVB $1, ret+0(FP)
- RET
-notfound:
- MOVB $0, ret+0(FP)
- RET
-
-// func cryptBlocks(function code, key, dst, src *byte, length int)
+// func cryptBlocks(c code, key, dst, src *byte, length int)
TEXT ·cryptBlocks(SB),NOSPLIT,$0-40
MOVD key+8(FP), R1
MOVD dst+16(FP), R2
MOVD src+24(FP), R4
MOVD length+32(FP), R5
- MOVD function+0(FP), R0
+ MOVD c+0(FP), R0
loop:
WORD $0xB92E0024 // cipher message (KM)
BVS loop // branch back if interrupted
XOR R0, R0
RET
-// func cryptBlocksChain(function code, iv, key, dst, src *byte, length int)
+// func cryptBlocksChain(c code, iv, key, dst, src *byte, length int)
TEXT ·cryptBlocksChain(SB),NOSPLIT,$48-48
LA params-48(SP), R1
MOVD iv+8(FP), R8
@@ -51,7 +27,7 @@ TEXT ·cryptBlocksChain(SB),NOSPLIT,$48-48
MOVD dst+24(FP), R2
MOVD src+32(FP), R4
MOVD length+40(FP), R5
- MOVD function+0(FP), R0
+ MOVD c+0(FP), R0
loop:
WORD $0xB92F0024 // cipher message with chaining (KMC)
BVS loop // branch back if interrupted
@@ -91,3 +67,86 @@ tail:
BR tail
done:
RET
+
+// func cryptBlocksGCM(fn code, key, dst, src, buf []byte, cnt *[16]byte)
+TEXT ·cryptBlocksGCM(SB),NOSPLIT,$0-112
+ MOVD src_len+64(FP), R0
+ MOVD buf_base+80(FP), R1
+ MOVD cnt+104(FP), R12
+ LMG (R12), R2, R3
+
+ // Check that the src size is less than or equal to the buffer size.
+ MOVD buf_len+88(FP), R4
+ CMP R0, R4
+ BGT crash
+
+ // Check that the src size is a multiple of 16-bytes.
+ MOVD R0, R4
+ AND $0xf, R4
+ BLT crash // non-zero
+
+ // Check that the src size is less than or equal to the dst size.
+ MOVD dst_len+40(FP), R4
+ CMP R0, R4
+ BGT crash
+
+ MOVD R2, R4
+ MOVD R2, R6
+ MOVD R2, R8
+ MOVD R3, R5
+ MOVD R3, R7
+ MOVD R3, R9
+ ADDW $1, R5
+ ADDW $2, R7
+ ADDW $3, R9
+incr:
+ CMP R0, $64
+ BLT tail
+ STMG R2, R9, (R1)
+ ADDW $4, R3
+ ADDW $4, R5
+ ADDW $4, R7
+ ADDW $4, R9
+ MOVD $64(R1), R1
+ SUB $64, R0
+ BR incr
+tail:
+ CMP R0, $0
+ BEQ crypt
+ STMG R2, R3, (R1)
+ ADDW $1, R3
+ MOVD $16(R1), R1
+ SUB $16, R0
+ BR tail
+crypt:
+ STMG R2, R3, (R12) // update next counter value
+ MOVD fn+0(FP), R0 // function code (encryption)
+ MOVD key_base+8(FP), R1 // key
+ MOVD buf_base+80(FP), R2 // counter values
+ MOVD dst_base+32(FP), R4 // dst
+ MOVD src_base+56(FP), R6 // src
+ MOVD src_len+64(FP), R7 // len
+loop:
+ WORD $0xB92D2046 // cipher message with counter (KMCTR)
+ BVS loop // branch back if interrupted
+ RET
+crash:
+ MOVD $0, (R0)
+ RET
+
+// func ghash(key *gcmHashKey, hash *[16]byte, data []byte)
+TEXT ·ghash(SB),NOSPLIT,$32-40
+ MOVD $65, R0 // GHASH function code
+ MOVD key+0(FP), R2
+ LMG (R2), R6, R7
+ MOVD hash+8(FP), R8
+ LMG (R8), R4, R5
+ MOVD $params-32(SP), R1
+ STMG R4, R7, (R1)
+ LMG data+16(FP), R2, R3 // R2=base, R3=len
+loop:
+ WORD $0xB93E0002 // compute intermediate message digest (KIMD)
+ BVS loop // branch back if interrupted
+ MVC $16, (R1), (R8)
+ MOVD $0, R0
+ RET
diff --git a/src/crypto/aes/cipher_amd64.go b/src/crypto/aes/cipher_amd64.go
index b33c8ff..43de3bd 100644
--- a/src/crypto/aes/cipher_amd64.go
+++ b/src/crypto/aes/cipher_amd64.go
@@ -6,10 +6,10 @@ package aes
import (
"crypto/cipher"
+ "crypto/internal/cipherhw"
)
// defined in asm_amd64.s
-func hasAsm() bool
func encryptBlockAsm(nr int, xk *uint32, dst, src *byte)
func decryptBlockAsm(nr int, xk *uint32, dst, src *byte)
func expandKeyAsm(nr int, key *byte, enc *uint32, dec *uint32)
@@ -18,7 +18,7 @@ type aesCipherAsm struct {
aesCipher
}
-var useAsm = hasAsm()
+var useAsm = cipherhw.AESGCMSupport()
func newCipher(key []byte) (cipher.Block, error) {
if !useAsm {
diff --git a/src/crypto/aes/cipher_s390x.go b/src/crypto/aes/cipher_s390x.go
index bec5933..6030c25 100644
--- a/src/crypto/aes/cipher_s390x.go
+++ b/src/crypto/aes/cipher_s390x.go
@@ -6,6 +6,7 @@ package aes
import (
"crypto/cipher"
+ "crypto/internal/cipherhw"
)
type code int
@@ -23,18 +24,13 @@ type aesCipherAsm struct {
storage [256]byte // array backing key slice
}
-// hasAsm reports whether the AES-128, AES-192 and AES-256
-// cipher message (KM) function codes are supported.
-// Note: this function call is expensive.
-func hasAsm() bool
-
// cryptBlocks invokes the cipher message (KM) instruction with
// the given function code. This is equivalent to AES in ECB
// mode. The length must be a multiple of BlockSize (16).
//go:noesape
func cryptBlocks(c code, key, dst, src *byte, length int)
-var useAsm = hasAsm()
+var useAsm = cipherhw.AESGCMSupport()
func newCipher(key []byte) (cipher.Block, error) {
if !useAsm {
diff --git a/src/crypto/aes/gcm_s390x.go b/src/crypto/aes/gcm_s390x.go
new file mode 100644
index 0000000..9eaaf7c
--- /dev/null
+++ b/src/crypto/aes/gcm_s390x.go
@@ -0,0 +1,270 @@
+// Copyright 2016 The Go Authors. 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"
+ "crypto/subtle"
+ "errors"
+)
+
+// gcmCount represents a 16-byte big-endian count value.
+type gcmCount [16]byte
+
+// inc increments the rightmost 32-bits of the count value by 1.
+func (x *gcmCount) inc() {
+ // The compiler should optimize this to a 32-bit addition.
+ n := uint32(x[15]) | uint32(x[14])<<8 | uint32(x[13])<<16 | uint32(x[12])<<24
+ n += 1
+ x[12] = byte(n >> 24)
+ x[13] = byte(n >> 16)
+ x[14] = byte(n >> 8)
+ x[15] = byte(n)
+}
+
+// gcmLengths writes len0 || len1 as big-endian values to a 16-byte array.
+func gcmLengths(len0, len1 uint64) [16]byte {
+ return [16]byte{
+ byte(len0 >> 56),
+ byte(len0 >> 48),
+ byte(len0 >> 40),
+ byte(len0 >> 32),
+ byte(len0 >> 24),
+ byte(len0 >> 16),
+ byte(len0 >> 8),
+ byte(len0),
+ byte(len1 >> 56),
+ byte(len1 >> 48),
+ byte(len1 >> 40),
+ byte(len1 >> 32),
+ byte(len1 >> 24),
+ byte(len1 >> 16),
+ byte(len1 >> 8),
+ byte(len1),
+ }
+}
+
+// gcmHashKey represents the 16-byte hash key required by the GHASH algorithm.
+type gcmHashKey [16]byte
+
+type gcmAsm struct {
+ block *aesCipherAsm
+ hashKey gcmHashKey
+ nonceSize int
+}
+
+const (
+ gcmBlockSize = 16
+ gcmTagSize = 16
+ gcmStandardNonceSize = 12
+)
+
+var errOpen = errors.New("cipher: message authentication failed")
+
+// Assert that aesCipherAsm implements the gcmAble interface.
+var _ gcmAble = (*aesCipherAsm)(nil)
+
+// NewGCM returns the AES cipher wrapped in Galois Counter Mode. This is only
+// called by crypto/cipher.NewGCM via the gcmAble interface.
+func (c *aesCipherAsm) NewGCM(nonceSize int) (cipher.AEAD, error) {
+ var hk gcmHashKey
+ c.Encrypt(hk[:], hk[:])
+ g := &gcmAsm{
+ block: c,
+ hashKey: hk,
+ nonceSize: nonceSize,
+ }
+ return g, nil
+}
+
+func (g *gcmAsm) NonceSize() int {
+ return g.nonceSize
+}
+
+func (*gcmAsm) Overhead() int {
+ return gcmTagSize
+}
+
+// sliceForAppend takes a slice and a requested number of bytes. It returns a
+// slice with the contents of the given slice followed by that many bytes and a
+// second slice that aliases into it and contains only the extra bytes. If the
+// original slice has sufficient capacity then no allocation is performed.
+func sliceForAppend(in []byte, n int) (head, tail []byte) {
+ if total := len(in) + n; cap(in) >= total {
+ head = in[:total]
+ } else {
+ head = make([]byte, total)
+ copy(head, in)
+ }
+ tail = head[len(in):]
+ return
+}
+
+// ghash uses the GHASH algorithm to hash data with the given key. The initial
+// hash value is given by hash which will be updated with the new hash value.
+// The length of data must be a multiple of 16-bytes.
+//go:noescape
+func ghash(key *gcmHashKey, hash *[16]byte, data []byte)
+
+// paddedGHASH pads data with zeroes until its length is a multiple of
+// 16-bytes. It then calculates a new value for hash using the GHASH algorithm.
+func (g *gcmAsm) paddedGHASH(hash *[16]byte, data []byte) {
+ siz := len(data) &^ 0xf // align size to 16-bytes
+ if siz > 0 {
+ ghash(&g.hashKey, hash, data[:siz])
+ data = data[siz:]
+ }
+ if len(data) > 0 {
+ var s [16]byte
+ copy(s[:], data)
+ ghash(&g.hashKey, hash, s[:])
+ }
+}
+
+// cryptBlocksGCM encrypts src using AES in counter mode using the given
+// function code and key. The rightmost 32-bits of the counter are incremented
+// between each block as required by the GCM spec. The initial counter value
+// is given by cnt, which is updated with the value of the next counter value
+// to use.
+//
+// The lengths of both dst and buf must be greater than or equal to the length
+// of src. buf may be partially or completely overwritten during the execution
+// of the function.
+//go:noescape
+func cryptBlocksGCM(fn code, key, dst, src, buf []byte, cnt *gcmCount)
+
+// counterCrypt encrypts src using AES in counter mode and places the result
+// into dst. cnt is the initial count value and will be updated with the next
+// count value. The length of dst must be greater than or equal to the length
+// of src.
+func (g *gcmAsm) counterCrypt(dst, src []byte, cnt *gcmCount) {
+ // Copying src into a buffer improves performance on some models when
+ // src and dst point to the same underlying array. We also need a
+ // buffer for counter values.
+ var ctrbuf, srcbuf [2048]byte
+ for len(src) >= 16 {
+ siz := len(src)
+ if len(src) > len(ctrbuf) {
+ siz = len(ctrbuf)
+ }
+ siz &^= 0xf // align siz to 16-bytes
+ copy(srcbuf[:], src[:siz])
+ cryptBlocksGCM(g.block.function, g.block.key, dst[:siz], srcbuf[:siz], ctrbuf[:], cnt)
+ src = src[siz:]
+ dst = dst[siz:]
+ }
+ if len(src) > 0 {
+ var x [16]byte
+ g.block.Encrypt(x[:], cnt[:])
+ for i := range src {
+ dst[i] = src[i] ^ x[i]
+ }
+ cnt.inc()
+ }
+}
+
+// deriveCounter computes the initial GCM counter state from the given nonce.
+// See NIST SP 800-38D, section 7.1.
+func (g *gcmAsm) deriveCounter(nonce []byte) gcmCount {
+ // GCM has two modes of operation with respect to the initial counter
+ // state: a "fast path" for 96-bit (12-byte) nonces, and a "slow path"
+ // for nonces of other lengths. For a 96-bit nonce, the nonce, along
+ // with a four-byte big-endian counter starting at one, is used
+ // directly as the starting counter. For other nonce sizes, the counter
+ // is computed by passing it through the GHASH function.
+ var counter gcmCount
+ if len(nonce) == gcmStandardNonceSize {
+ copy(counter[:], nonce)
+ counter[gcmBlockSize-1] = 1
+ } else {
+ var hash [16]byte
+ g.paddedGHASH(&hash, nonce)
+ lens := gcmLengths(0, uint64(len(nonce))*8)
+ g.paddedGHASH(&hash, lens[:])
+ copy(counter[:], hash[:])
+ }
+ return counter
+}
+
+// auth calculates GHASH(ciphertext, additionalData), masks the result with
+// tagMask and writes the result to out.
+func (g *gcmAsm) auth(out, ciphertext, additionalData []byte, tagMask *[gcmTagSize]byte) {
+ var hash [16]byte
+ g.paddedGHASH(&hash, additionalData)
+ g.paddedGHASH(&hash, ciphertext)
+ lens := gcmLengths(uint64(len(additionalData))*8, uint64(len(ciphertext))*8)
+ g.paddedGHASH(&hash, lens[:])
+
+ copy(out, hash[:])
+ for i := range out {
+ out[i] ^= tagMask[i]
+ }
+}
+
+// Seal encrypts and authenticates plaintext. See the cipher.AEAD interface for
+// details.
+func (g *gcmAsm) Seal(dst, nonce, plaintext, data []byte) []byte {
+ if len(nonce) != g.nonceSize {
+ panic("cipher: incorrect nonce length given to GCM")
+ }
+ if uint64(len(plaintext)) > ((1<<32)-2)*BlockSize {
+ panic("cipher: message too large for GCM")
+ }
+
+ ret, out := sliceForAppend(dst, len(plaintext)+gcmTagSize)
+
+ counter := g.deriveCounter(nonce)
+
+ var tagMask [gcmBlockSize]byte
+ g.block.Encrypt(tagMask[:], counter[:])
+ counter.inc()
+
+ g.counterCrypt(out, plaintext, &counter)
+ g.auth(out[len(plaintext):], out[:len(plaintext)], data, &tagMask)
+
+ return ret
+}
+
+// Open authenticates and decrypts ciphertext. See the cipher.AEAD interface
+// for details.
+func (g *gcmAsm) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) {
+ if len(nonce) != g.nonceSize {
+ panic("cipher: incorrect nonce length given to GCM")
+ }
+ if len(ciphertext) < gcmTagSize {
+ return nil, errOpen
+ }
+ if uint64(len(ciphertext)) > ((1<<32)-2)*BlockSize+gcmTagSize {
+ return nil, errOpen
+ }
+
+ tag := ciphertext[len(ciphertext)-gcmTagSize:]
+ ciphertext = ciphertext[:len(ciphertext)-gcmTagSize]
+
+ counter := g.deriveCounter(nonce)
+
+ var tagMask [gcmBlockSize]byte
+ g.block.Encrypt(tagMask[:], counter[:])
+ counter.inc()
+
+ var expectedTag [gcmTagSize]byte
+ g.auth(expectedTag[:], ciphertext, data, &tagMask)
+
+ ret, out := sliceForAppend(dst, len(ciphertext))
+
+ if subtle.ConstantTimeCompare(expectedTag[:], tag) != 1 {
+ // The AESNI code decrypts and authenticates concurrently, and
+ // so overwrites dst in the event of a tag mismatch. That
+ // behaviour is mimicked here in order to be consistent across
+ // platforms.
+ for i := range out {
+ out[i] = 0
+ }
+ return nil, errOpen
+ }
+
+ g.counterCrypt(out, ciphertext, &counter)
+ return ret, nil
+}
diff --git a/src/crypto/cipher/example_test.go b/src/crypto/cipher/example_test.go
index 9abe782..956cc2e 100644
--- a/src/crypto/cipher/example_test.go
+++ b/src/crypto/cipher/example_test.go
@@ -14,7 +14,7 @@ import (
"os"
)
-func ExampleNewGCMEncrypter() {
+func ExampleNewGCM_encrypt() {
// The key argument should be the AES key, either 16 or 32 bytes
// to select AES-128 or AES-256.
key := []byte("AES256Key-32Characters1234567890")
@@ -40,7 +40,7 @@ func ExampleNewGCMEncrypter() {
fmt.Printf("%x\n", ciphertext)
}
-func ExampleNewGCMDecrypter() {
+func ExampleNewGCM_decrypt() {
// The key argument should be the AES key, either 16 or 32 bytes
// to select AES-128 or AES-256.
key := []byte("AES256Key-32Characters1234567890")
diff --git a/src/crypto/cipher/gcm.go b/src/crypto/cipher/gcm.go
index 3868d71..cfc5769 100644
--- a/src/crypto/cipher/gcm.go
+++ b/src/crypto/cipher/gcm.go
@@ -135,6 +135,10 @@ func (g *gcm) Seal(dst, nonce, plaintext, data []byte) []byte {
if len(nonce) != g.nonceSize {
panic("cipher: incorrect nonce length given to GCM")
}
+ if uint64(len(plaintext)) > ((1<<32)-2)*uint64(g.cipher.BlockSize()) {
+ panic("cipher: message too large for GCM")
+ }
+
ret, out := sliceForAppend(dst, len(plaintext)+gcmTagSize)
var counter, tagMask [gcmBlockSize]byte
@@ -159,6 +163,10 @@ func (g *gcm) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) {
if len(ciphertext) < gcmTagSize {
return nil, errOpen
}
+ if uint64(len(ciphertext)) > ((1<<32)-2)*uint64(g.cipher.BlockSize())+gcmTagSize {
+ return nil, errOpen
+ }
+
tag := ciphertext[len(ciphertext)-gcmTagSize:]
ciphertext = ciphertext[:len(ciphertext)-gcmTagSize]
diff --git a/src/crypto/cipher/gcm_test.go b/src/crypto/cipher/gcm_test.go
index bb1ab3c..6878b4c 100644
--- a/src/crypto/cipher/gcm_test.go
+++ b/src/crypto/cipher/gcm_test.go
@@ -8,7 +8,11 @@ import (
"bytes"
"crypto/aes"
"crypto/cipher"
+ "crypto/rand"
"encoding/hex"
+ "errors"
+ "io"
+ "reflect"
"testing"
)
@@ -274,3 +278,157 @@ func TestTagFailureOverwrite(t *testing.T) {
}
}
}
+
+func TestGCMCounterWrap(t *testing.T) {
+ // Test that the last 32-bits of the counter wrap correctly.
+ tests := []struct {
+ nonce, tag string
+ }{
+ {"0fa72e25", "37e1948cdfff09fbde0c40ad99fee4a7"}, // counter: 7eb59e4d961dad0dfdd75aaffffffff0
+ {"afe05cc1", "438f3aa9fee5e54903b1927bca26bbdf"}, // counter: 75d492a7e6e6bfc979ad3a8ffffffff4
+ {"9ffecbef", "7b88ca424df9703e9e8611071ec7e16e"}, // counter: c8bb108b0ecdc71747b9d57ffffffff5
+ {"ffc3e5b3", "38d49c86e0abe853ac250e66da54c01a"}, // counter: 706414d2de9b36ab3b900a9ffffffff6
+ {"cfdd729d", "e08402eaac36a1a402e09b1bd56500e8"}, // counter: cd0b96fe36b04e750584e56ffffffff7
+ {"010ae3d486", "5405bb490b1f95d01e2ba735687154bc"}, // counter: e36c18e69406c49722808104fffffff8
+ {"01b1107a9d", "939a585f342e01e17844627492d44dbf"}, // counter: e6d56eaf9127912b6d62c6dcffffffff
+ }
+ key, err := aes.NewCipher(make([]byte, 16))
+ if err != nil {
+ t.Fatal(err)
+ }
+ plaintext := make([]byte, 16*17+1)
+ for i, test := range tests {
+ nonce, _ := hex.DecodeString(test.nonce)
+ want, _ := hex.DecodeString(test.tag)
+ aead, err := cipher.NewGCMWithNonceSize(key, len(nonce))
+ if err != nil {
+ t.Fatal(err)
+ }
+ got := aead.Seal(nil, nonce, plaintext, nil)
+ if !bytes.Equal(got[len(plaintext):], want) {
+ t.Errorf("test[%v]: got: %x, want: %x", i, got[len(plaintext):], want)
+ }
+ _, err = aead.Open(nil, nonce, got, nil)
+ if err != nil {
+ t.Errorf("test[%v]: authentication failed", i)
+ }
+ }
+}
+
+var _ cipher.Block = (*wrapper)(nil)
+
+type wrapper struct {
+ block cipher.Block
+}
+
+func (w *wrapper) BlockSize() int { return w.block.BlockSize() }
+func (w *wrapper) Encrypt(dst, src []byte) { w.block.Encrypt(dst, src) }
+func (w *wrapper) Decrypt(dst, src []byte) { w.block.Decrypt(dst, src) }
+
+// wrap wraps the Block interface so that it does not fulfill
+// any optimizing interfaces such as gcmAble.
+func wrap(b cipher.Block) cipher.Block {
+ return &wrapper{b}
+}
+
+func TestGCMAsm(t *testing.T) {
+ // Create a new pair of AEADs, one using the assembly implementation
+ // and one using the generic Go implementation.
+ newAESGCM := func(key []byte) (asm, generic cipher.AEAD, err error) {
+ block, err := aes.NewCipher(key[:])
+ if err != nil {
+ return nil, nil, err
+ }
+ asm, err = cipher.NewGCM(block)
+ if err != nil {
+ return nil, nil, err
+ }
+ generic, err = cipher.NewGCM(wrap(block))
+ if err != nil {
+ return nil, nil, err
+ }
+ return asm, generic, nil
+ }
+
+ // check for assembly implementation
+ var key [16]byte
+ asm, generic, err := newAESGCM(key[:])
+ if err != nil {
+ t.Fatal(err)
+ }
+ if reflect.TypeOf(asm) == reflect.TypeOf(generic) {
+ t.Skipf("no assembly implementation of GCM")
+ }
+
+ // generate permutations
+ type pair struct{ align, length int }
+ lengths := []int{0, 8192, 8193, 8208}
+ keySizes := []int{16, 24, 32}
+ alignments := []int{0, 1, 2, 3}
+ if testing.Short() {
+ keySizes = []int{16}
+ alignments = []int{1}
+ }
+ perms := make([]pair, 0)
+ for _, l := range lengths {
+ for _, a := range alignments {
+ if a != 0 && l == 0 {
+ continue
+ }
+ perms = append(perms, pair{align: a, length: l})
+ }
+ }
+
+ // run test for all permutations
+ test := func(ks int, pt, ad []byte) error {
+ key := make([]byte, ks)
+ if _, err := io.ReadFull(rand.Reader, key); err != nil {
+ return err
+ }
+ asm, generic, err := newAESGCM(key)
+ if err != nil {
+ return err
+ }
+ if _, err := io.ReadFull(rand.Reader, pt); err != nil {
+ return err
+ }
+ if _, err := io.ReadFull(rand.Reader, ad); err != nil {
+ return err
+ }
+ nonce := make([]byte, 12)
+ if _, err := io.ReadFull(rand.Reader, nonce); err != nil {
+ return err
+ }
+ want := generic.Seal(nil, nonce, pt, ad)
+ got := asm.Seal(nil, nonce, pt, ad)
+ if !bytes.Equal(want, got) {
+ return errors.New("incorrect Seal output")
+ }
+ got, err = asm.Open(nil, nonce, want, ad)
+ if err != nil {
+ return errors.New("authentication failed")
+ }
+ if !bytes.Equal(pt, got) {
+ return errors.New("incorrect Open output")
+ }
+ return nil
+ }
+ for _, a := range perms {
+ ad := make([]byte, a.align+a.length)
+ ad = ad[a.align:]
+ for _, p := range perms {
+ pt := make([]byte, p.align+p.length)
+ pt = pt[p.align:]
+ for _, ks := range keySizes {
+ if err := test(ks, pt, ad); err != nil {
+ t.Error(err)
+ t.Errorf(" key size: %v", ks)
+ t.Errorf(" plaintext alignment: %v", p.align)
+ t.Errorf(" plaintext length: %v", p.length)
+ t.Errorf(" additionalData alignment: %v", a.align)
+ t.Fatalf(" additionalData length: %v", a.length)
+ }
+ }
+ }
+ }
+}
diff --git a/src/crypto/ecdsa/ecdsa.go b/src/crypto/ecdsa/ecdsa.go
index 72fb499..02848fd 100644
--- a/src/crypto/ecdsa/ecdsa.go
+++ b/src/crypto/ecdsa/ecdsa.go
@@ -149,7 +149,7 @@ var errZeroParam = errors.New("zero parameter")
// returns the signature as a pair of integers. The security of the private key
// depends on the entropy of rand.
func Sign(rand io.Reader, priv *PrivateKey, hash []byte) (r, s *big.Int, err error) {
- // Get max(log2(q) / 2, 256) bits of entropy from rand.
+ // Get min(log2(q) / 2, 256) bits of entropy from rand.
entropylen := (priv.Curve.Params().BitSize + 7) / 16
if entropylen > 32 {
entropylen = 32
diff --git a/src/crypto/ecdsa/ecdsa_test.go b/src/crypto/ecdsa/ecdsa_test.go
index fc25fd7..9546f67 100644
--- a/src/crypto/ecdsa/ecdsa_test.go
+++ b/src/crypto/ecdsa/ecdsa_test.go
@@ -54,6 +54,18 @@ func BenchmarkSignP256(b *testing.B) {
}
}
+func BenchmarkSignP384(b *testing.B) {
+ b.ResetTimer()
+ p384 := elliptic.P384()
+ hashed := []byte("testing")
+ priv, _ := GenerateKey(p384, rand.Reader)
+
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ _, _, _ = Sign(rand.Reader, priv, hashed)
+ }
+}
+
func BenchmarkVerifyP256(b *testing.B) {
b.ResetTimer()
p256 := elliptic.P256()
diff --git a/src/crypto/elliptic/elliptic_test.go b/src/crypto/elliptic/elliptic_test.go
index 7f3f1a2..902c414 100644
--- a/src/crypto/elliptic/elliptic_test.go
+++ b/src/crypto/elliptic/elliptic_test.go
@@ -28,7 +28,7 @@ func TestOffCurve(t *testing.T) {
b := Marshal(p224, x, y)
x1, y1 := Unmarshal(p224, b)
if x1 != nil || y1 != nil {
- t.Errorf("FAIL: unmarshalling a point not on the curve succeeded")
+ t.Errorf("FAIL: unmarshaling a point not on the curve succeeded")
}
}
diff --git a/src/crypto/elliptic/p256.go b/src/crypto/elliptic/p256.go
index 05a3311..bbf0087 100644
--- a/src/crypto/elliptic/p256.go
+++ b/src/crypto/elliptic/p256.go
@@ -17,7 +17,8 @@ type p256Curve struct {
}
var (
- p256 p256Curve
+ p256Params *CurveParams
+
// RInverse contains 1/R mod p - the inverse of the Montgomery constant
// (2**257).
p256RInverse *big.Int
@@ -25,15 +26,18 @@ var (
func initP256() {
// See FIPS 186-3, section D.2.3
- p256.CurveParams = &CurveParams{Name: "P-256"}
- p256.P, _ = new(big.Int).SetString("115792089210356248762697446949407573530086143415290314195533631308867097853951", 10)
- p256.N, _ = new(big.Int).SetString("115792089210356248762697446949407573529996955224135760342422259061068512044369", 10)
- p256.B, _ = new(big.Int).SetString("5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b", 16)
- p256.Gx, _ = new(big.Int).SetString("6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296", 16)
- p256.Gy, _ = new(big.Int).SetString("4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5", 16)
- p256.BitSize = 256
+ p256Params = &CurveParams{Name: "P-256"}
+ p256Params.P, _ = new(big.Int).SetString("115792089210356248762697446949407573530086143415290314195533631308867097853951", 10)
+ p256Params.N, _ = new(big.Int).SetString("115792089210356248762697446949407573529996955224135760342422259061068512044369", 10)
+ p256Params.B, _ = new(big.Int).SetString("5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b", 16)
+ p256Params.Gx, _ = new(big.Int).SetString("6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296", 16)
+ p256Params.Gy, _ = new(big.Int).SetString("4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5", 16)
+ p256Params.BitSize = 256
p256RInverse, _ = new(big.Int).SetString("7fffffff00000001fffffffe8000000100000000ffffffff0000000180000000", 16)
+
+ // Arch-specific initialization, i.e. let a platform dynamically pick a P256 implementation
+ initP256Arch()
}
func (curve p256Curve) Params() *CurveParams {
@@ -47,8 +51,8 @@ func p256GetScalar(out *[32]byte, in []byte) {
n := new(big.Int).SetBytes(in)
var scalarBytes []byte
- if n.Cmp(p256.N) >= 0 {
- n.Mod(n, p256.N)
+ if n.Cmp(p256Params.N) >= 0 {
+ n.Mod(n, p256Params.N)
scalarBytes = n.Bytes()
} else {
scalarBytes = in
@@ -1143,7 +1147,7 @@ func p256ScalarMult(xOut, yOut, zOut, x, y *[p256Limbs]uint32, scalar *[32]uint8
// p256FromBig sets out = R*in.
func p256FromBig(out *[p256Limbs]uint32, in *big.Int) {
tmp := new(big.Int).Lsh(in, 257)
- tmp.Mod(tmp, p256.P)
+ tmp.Mod(tmp, p256Params.P)
for i := 0; i < p256Limbs; i++ {
if bits := tmp.Bits(); len(bits) > 0 {
@@ -1183,6 +1187,6 @@ func p256ToBig(in *[p256Limbs]uint32) *big.Int {
}
result.Mul(result, p256RInverse)
- result.Mod(result, p256.P)
+ result.Mod(result, p256Params.P)
return result
}
diff --git a/src/crypto/elliptic/p256_asm_s390x.s b/src/crypto/elliptic/p256_asm_s390x.s
new file mode 100644
index 0000000..96b59be
--- /dev/null
+++ b/src/crypto/elliptic/p256_asm_s390x.s
@@ -0,0 +1,2201 @@
+// Copyright 2016 The Go 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"
+
+DATA p256ordK0<>+0x00(SB)/4, $0xee00bc4f
+DATA p256ord<>+0x00(SB)/8, $0xffffffff00000000
+DATA p256ord<>+0x08(SB)/8, $0xffffffffffffffff
+DATA p256ord<>+0x10(SB)/8, $0xbce6faada7179e84
+DATA p256ord<>+0x18(SB)/8, $0xf3b9cac2fc632551
+DATA p256<>+0x00(SB)/8, $0xffffffff00000001 // P256
+DATA p256<>+0x08(SB)/8, $0x0000000000000000 // P256
+DATA p256<>+0x10(SB)/8, $0x00000000ffffffff // P256
+DATA p256<>+0x18(SB)/8, $0xffffffffffffffff // P256
+DATA p256<>+0x20(SB)/8, $0x0c0d0e0f1c1d1e1f // SEL d1 d0 d1 d0
+DATA p256<>+0x28(SB)/8, $0x0c0d0e0f1c1d1e1f // SEL d1 d0 d1 d0
+DATA p256<>+0x30(SB)/8, $0x0000000010111213 // SEL 0 d1 d0 0
+DATA p256<>+0x38(SB)/8, $0x1415161700000000 // SEL 0 d1 d0 0
+DATA p256<>+0x40(SB)/8, $0x18191a1b1c1d1e1f // SEL d1 d0 d1 d0
+DATA p256<>+0x48(SB)/8, $0x18191a1b1c1d1e1f // SEL d1 d0 d1 d0
+DATA p256mul<>+0x00(SB)/8, $0xffffffff00000001 // P256
+DATA p256mul<>+0x08(SB)/8, $0x0000000000000000 // P256
+DATA p256mul<>+0x10(SB)/8, $0x00000000ffffffff // P256
+DATA p256mul<>+0x18(SB)/8, $0xffffffffffffffff // P256
+DATA p256mul<>+0x20(SB)/8, $0x1c1d1e1f00000000 // SEL d0 0 0 d0
+DATA p256mul<>+0x28(SB)/8, $0x000000001c1d1e1f // SEL d0 0 0 d0
+DATA p256mul<>+0x30(SB)/8, $0x0001020304050607 // SEL d0 0 d1 d0
+DATA p256mul<>+0x38(SB)/8, $0x1c1d1e1f0c0d0e0f // SEL d0 0 d1 d0
+DATA p256mul<>+0x40(SB)/8, $0x040506071c1d1e1f // SEL 0 d1 d0 d1
+DATA p256mul<>+0x48(SB)/8, $0x0c0d0e0f1c1d1e1f // SEL 0 d1 d0 d1
+DATA p256mul<>+0x50(SB)/8, $0x0405060704050607 // SEL 0 0 d1 d0
+DATA p256mul<>+0x58(SB)/8, $0x1c1d1e1f0c0d0e0f // SEL 0 0 d1 d0
+DATA p256mul<>+0x60(SB)/8, $0x0c0d0e0f1c1d1e1f // SEL d1 d0 d1 d0
+DATA p256mul<>+0x68(SB)/8, $0x0c0d0e0f1c1d1e1f // SEL d1 d0 d1 d0
+DATA p256mul<>+0x70(SB)/8, $0x141516170c0d0e0f // SEL 0 d1 d0 0
+DATA p256mul<>+0x78(SB)/8, $0x1c1d1e1f14151617 // SEL 0 d1 d0 0
+DATA p256mul<>+0x80(SB)/8, $0x00000000fffffffe // (1*2^256)%P256
+DATA p256mul<>+0x88(SB)/8, $0xffffffffffffffff // (1*2^256)%P256
+DATA p256mul<>+0x90(SB)/8, $0xffffffff00000000 // (1*2^256)%P256
+DATA p256mul<>+0x98(SB)/8, $0x0000000000000001 // (1*2^256)%P256
+GLOBL p256ordK0<>(SB), 8, $4
+GLOBL p256ord<>(SB), 8, $32
+GLOBL p256<>(SB), 8, $80
+GLOBL p256mul<>(SB), 8, $160
+
+// func hasVectorFacility() bool
+TEXT ·hasVectorFacility(SB), NOSPLIT, $24-1
+ MOVD $x-24(SP), R1
+ XC $24, 0(R1), 0(R1) // clear the storage
+ MOVD $2, R0 // R0 is the number of double words stored -1
+ WORD $0xB2B01000 // STFLE 0(R1)
+ XOR R0, R0 // reset the value of R0
+ MOVBZ z-8(SP), R1
+ AND $0x40, R1
+ BEQ novector
+
+vectorinstalled:
+ // check if the vector instruction has been enabled
+ VLEIB $0, $0xF, V16
+ VLGVB $0, V16, R1
+ CMPBNE R1, $0xF, novector
+ MOVB $1, ret+0(FP) // have vx
+ RET
+
+novector:
+ MOVB $0, ret+0(FP) // no vx
+ RET
+
+// ---------------------------------------
+// iff cond == 1 val <- -val
+// func p256NegCond(val *p256Point, cond int)
+#define P1ptr R1
+#define CPOOL R4
+
+#define Y1L V0
+#define Y1H V1
+#define T1L V2
+#define T1H V3
+
+#define PL V30
+#define PH V31
+
+#define ZER V4
+#define SEL1 V5
+#define CAR1 V6
+TEXT ·p256NegCond(SB), NOSPLIT, $0
+ MOVD val+0(FP), P1ptr
+
+ MOVD $p256mul<>+0x00(SB), CPOOL
+ VL 16(CPOOL), PL
+ VL 0(CPOOL), PH
+
+ VL 32(P1ptr), Y1H
+ VL 48(P1ptr), Y1L
+
+ VLREPG cond+8(FP), SEL1
+ VZERO ZER
+ VCEQG SEL1, ZER, SEL1
+
+ VSCBIQ Y1L, PL, CAR1
+ VSQ Y1L, PL, T1L
+ VSBIQ PH, Y1H, CAR1, T1H
+
+ VSEL Y1L, T1L, SEL1, Y1L
+ VSEL Y1H, T1H, SEL1, Y1H
+
+ VST Y1H, 32(P1ptr)
+ VST Y1L, 48(P1ptr)
+ RET
+
+#undef P1ptr
+#undef CPOOL
+#undef Y1L
+#undef Y1H
+#undef T1L
+#undef T1H
+#undef PL
+#undef PH
+#undef ZER
+#undef SEL1
+#undef CAR1
+
+// ---------------------------------------
+// if cond == 0 res <- b; else res <- a
+// func p256MovCond(res, a, b *p256Point, cond int)
+#define P3ptr R1
+#define P1ptr R2
+#define P2ptr R3
+
+#define X1L V0
+#define X1H V1
+#define Y1L V2
+#define Y1H V3
+#define Z1L V4
+#define Z1H V5
+#define X2L V6
+#define X2H V7
+#define Y2L V8
+#define Y2H V9
+#define Z2L V10
+#define Z2H V11
+
+#define ZER V18
+#define SEL1 V19
+TEXT ·p256MovCond(SB), NOSPLIT, $0
+ MOVD res+0(FP), P3ptr
+ MOVD a+8(FP), P1ptr
+ MOVD b+16(FP), P2ptr
+ VLREPG cond+24(FP), SEL1
+ VZERO ZER
+ VCEQG SEL1, ZER, SEL1
+
+ VL 0(P1ptr), X1H
+ VL 16(P1ptr), X1L
+ VL 32(P1ptr), Y1H
+ VL 48(P1ptr), Y1L
+ VL 64(P1ptr), Z1H
+ VL 80(P1ptr), Z1L
+
+ VL 0(P2ptr), X2H
+ VL 16(P2ptr), X2L
+ VL 32(P2ptr), Y2H
+ VL 48(P2ptr), Y2L
+ VL 64(P2ptr), Z2H
+ VL 80(P2ptr), Z2L
+
+ VSEL X2L, X1L, SEL1, X1L
+ VSEL X2H, X1H, SEL1, X1H
+ VSEL Y2L, Y1L, SEL1, Y1L
+ VSEL Y2H, Y1H, SEL1, Y1H
+ VSEL Z2L, Z1L, SEL1, Z1L
+ VSEL Z2H, Z1H, SEL1, Z1H
+
+ VST X1H, 0(P3ptr)
+ VST X1L, 16(P3ptr)
+ VST Y1H, 32(P3ptr)
+ VST Y1L, 48(P3ptr)
+ VST Z1H, 64(P3ptr)
+ VST Z1L, 80(P3ptr)
+
+ RET
+
+#undef P3ptr
+#undef P1ptr
+#undef P2ptr
+#undef X1L
+#undef X1H
+#undef Y1L
+#undef Y1H
+#undef Z1L
+#undef Z1H
+#undef X2L
+#undef X2H
+#undef Y2L
+#undef Y2H
+#undef Z2L
+#undef Z2H
+#undef ZER
+#undef SEL1
+
+// ---------------------------------------
+// Constant time table access
+// Indexed from 1 to 15, with -1 offset
+// (index 0 is implicitly point at infinity)
+// func p256Select(point *p256Point, table []p256Point, idx int)
+#define P3ptr R1
+#define P1ptr R2
+#define COUNT R4
+
+#define X1L V0
+#define X1H V1
+#define Y1L V2
+#define Y1H V3
+#define Z1L V4
+#define Z1H V5
+#define X2L V6
+#define X2H V7
+#define Y2L V8
+#define Y2H V9
+#define Z2L V10
+#define Z2H V11
+
+#define ONE V18
+#define IDX V19
+#define SEL1 V20
+#define SEL2 V21
+TEXT ·p256Select(SB), NOSPLIT, $0
+ MOVD point+0(FP), P3ptr
+ MOVD table+8(FP), P1ptr
+ VLREPB idx+(32+7)(FP), IDX
+ VREPIB $1, ONE
+ VREPIB $1, SEL2
+ MOVD $1, COUNT
+
+ VZERO X1H
+ VZERO X1L
+ VZERO Y1H
+ VZERO Y1L
+ VZERO Z1H
+ VZERO Z1L
+
+loop_select:
+ VL 0(P1ptr), X2H
+ VL 16(P1ptr), X2L
+ VL 32(P1ptr), Y2H
+ VL 48(P1ptr), Y2L
+ VL 64(P1ptr), Z2H
+ VL 80(P1ptr), Z2L
+
+ VCEQG SEL2, IDX, SEL1
+
+ VSEL X2L, X1L, SEL1, X1L
+ VSEL X2H, X1H, SEL1, X1H
+ VSEL Y2L, Y1L, SEL1, Y1L
+ VSEL Y2H, Y1H, SEL1, Y1H
+ VSEL Z2L, Z1L, SEL1, Z1L
+ VSEL Z2H, Z1H, SEL1, Z1H
+
+ VAB SEL2, ONE, SEL2
+ ADDW $1, COUNT
+ ADD $96, P1ptr
+ CMPW COUNT, $17
+ BLT loop_select
+
+ VST X1H, 0(P3ptr)
+ VST X1L, 16(P3ptr)
+ VST Y1H, 32(P3ptr)
+ VST Y1L, 48(P3ptr)
+ VST Z1H, 64(P3ptr)
+ VST Z1L, 80(P3ptr)
+ RET
+
+#undef P3ptr
+#undef P1ptr
+#undef COUNT
+#undef X1L
+#undef X1H
+#undef Y1L
+#undef Y1H
+#undef Z1L
+#undef Z1H
+#undef X2L
+#undef X2H
+#undef Y2L
+#undef Y2H
+#undef Z2L
+#undef Z2H
+#undef ONE
+#undef IDX
+#undef SEL1
+#undef SEL2
+
+// ---------------------------------------
+// Constant time table access
+// Indexed from 1 to 15, with -1 offset
+// (index 0 is implicitly point at infinity)
+// func p256SelectBase(point *p256Point, table []p256Point, idx int)
+#define P3ptr R1
+#define P1ptr R2
+#define COUNT R4
+
+#define X1L V0
+#define X1H V1
+#define Y1L V2
+#define Y1H V3
+#define Z1L V4
+#define Z1H V5
+#define X2L V6
+#define X2H V7
+#define Y2L V8
+#define Y2H V9
+#define Z2L V10
+#define Z2H V11
+
+#define ONE V18
+#define IDX V19
+#define SEL1 V20
+#define SEL2 V21
+TEXT ·p256SelectBase(SB), NOSPLIT, $0
+ MOVD point+0(FP), P3ptr
+ MOVD table+8(FP), P1ptr
+ VLREPB idx+(32+7)(FP), IDX
+ VREPIB $1, ONE
+ VREPIB $1, SEL2
+ MOVD $1, COUNT
+
+ VZERO X1H
+ VZERO X1L
+ VZERO Y1H
+ VZERO Y1L
+ VZERO Z1H
+ VZERO Z1L
+
+loop_select:
+ VL 0(P1ptr), X2H
+ VL 16(P1ptr), X2L
+ VL 32(P1ptr), Y2H
+ VL 48(P1ptr), Y2L
+ VL 64(P1ptr), Z2H
+ VL 80(P1ptr), Z2L
+
+ VCEQG SEL2, IDX, SEL1
+
+ VSEL X2L, X1L, SEL1, X1L
+ VSEL X2H, X1H, SEL1, X1H
+ VSEL Y2L, Y1L, SEL1, Y1L
+ VSEL Y2H, Y1H, SEL1, Y1H
+ VSEL Z2L, Z1L, SEL1, Z1L
+ VSEL Z2H, Z1H, SEL1, Z1H
+
+ VAB SEL2, ONE, SEL2
+ ADDW $1, COUNT
+ ADD $96, P1ptr
+ CMPW COUNT, $65
+ BLT loop_select
+
+ VST X1H, 0(P3ptr)
+ VST X1L, 16(P3ptr)
+ VST Y1H, 32(P3ptr)
+ VST Y1L, 48(P3ptr)
+ VST Z1H, 64(P3ptr)
+ VST Z1L, 80(P3ptr)
+ RET
+
+#undef P3ptr
+#undef P1ptr
+#undef COUNT
+#undef X1L
+#undef X1H
+#undef Y1L
+#undef Y1H
+#undef Z1L
+#undef Z1H
+#undef X2L
+#undef X2H
+#undef Y2L
+#undef Y2H
+#undef Z2L
+#undef Z2H
+#undef ONE
+#undef IDX
+#undef SEL1
+#undef SEL2
+
+// ---------------------------------------
+// func p256FromMont(res, in []byte)
+#define res_ptr R1
+#define x_ptr R2
+#define CPOOL R4
+
+#define T0 V0
+#define T1 V1
+#define T2 V2
+#define TT0 V3
+#define TT1 V4
+
+#define ZER V6
+#define SEL1 V7
+#define SEL2 V8
+#define CAR1 V9
+#define CAR2 V10
+#define RED1 V11
+#define RED2 V12
+#define PL V13
+#define PH V14
+
+TEXT ·p256FromMont(SB), NOSPLIT, $0
+ MOVD res+0(FP), res_ptr
+ MOVD in+24(FP), x_ptr
+
+ VZERO T2
+ VZERO ZER
+ MOVD $p256<>+0x00(SB), CPOOL
+ VL 16(CPOOL), PL
+ VL 0(CPOOL), PH
+ VL 48(CPOOL), SEL2
+ VL 64(CPOOL), SEL1
+
+ VL (1*16)(x_ptr), T0
+ VL (0*16)(x_ptr), T1
+
+ // First round
+ VPERM T1, T0, SEL1, RED2 // d1 d0 d1 d0
+ VPERM ZER, RED2, SEL2, RED1 // 0 d1 d0 0
+ VSQ RED1, RED2, RED2 // Guaranteed not to underflow
+
+ VSLDB $8, T1, T0, T0
+ VSLDB $8, T2, T1, T1
+
+ VACCQ T0, RED1, CAR1
+ VAQ T0, RED1, T0
+ VACCCQ T1, RED2, CAR1, CAR2
+ VACQ T1, RED2, CAR1, T1
+ VAQ T2, CAR2, T2
+
+ // Second round
+ VPERM T1, T0, SEL1, RED2 // d1 d0 d1 d0
+ VPERM ZER, RED2, SEL2, RED1 // 0 d1 d0 0
+ VSQ RED1, RED2, RED2 // Guaranteed not to underflow
+
+ VSLDB $8, T1, T0, T0
+ VSLDB $8, T2, T1, T1
+
+ VACCQ T0, RED1, CAR1
+ VAQ T0, RED1, T0
+ VACCCQ T1, RED2, CAR1, CAR2
+ VACQ T1, RED2, CAR1, T1
+ VAQ T2, CAR2, T2
+
+ // Third round
+ VPERM T1, T0, SEL1, RED2 // d1 d0 d1 d0
+ VPERM ZER, RED2, SEL2, RED1 // 0 d1 d0 0
+ VSQ RED1, RED2, RED2 // Guaranteed not to underflow
+
+ VSLDB $8, T1, T0, T0
+ VSLDB $8, T2, T1, T1
+
+ VACCQ T0, RED1, CAR1
+ VAQ T0, RED1, T0
+ VACCCQ T1, RED2, CAR1, CAR2
+ VACQ T1, RED2, CAR1, T1
+ VAQ T2, CAR2, T2
+
+ // Last round
+ VPERM T1, T0, SEL1, RED2 // d1 d0 d1 d0
+ VPERM ZER, RED2, SEL2, RED1 // 0 d1 d0 0
+ VSQ RED1, RED2, RED2 // Guaranteed not to underflow
+
+ VSLDB $8, T1, T0, T0
+ VSLDB $8, T2, T1, T1
+
+ VACCQ T0, RED1, CAR1
+ VAQ T0, RED1, T0
+ VACCCQ T1, RED2, CAR1, CAR2
+ VACQ T1, RED2, CAR1, T1
+ VAQ T2, CAR2, T2
+
+ // ---------------------------------------------------
+
+ VSCBIQ PL, T0, CAR1
+ VSQ PL, T0, TT0
+ VSBCBIQ T1, PH, CAR1, CAR2
+ VSBIQ T1, PH, CAR1, TT1
+ VSBIQ T2, ZER, CAR2, T2
+
+ // what output to use, TT1||TT0 or T1||T0?
+ VSEL T0, TT0, T2, T0
+ VSEL T1, TT1, T2, T1
+
+ VST T0, (1*16)(res_ptr)
+ VST T1, (0*16)(res_ptr)
+ RET
+
+#undef res_ptr
+#undef x_ptr
+#undef CPOOL
+#undef T0
+#undef T1
+#undef T2
+#undef TT0
+#undef TT1
+#undef ZER
+#undef SEL1
+#undef SEL2
+#undef CAR1
+#undef CAR2
+#undef RED1
+#undef RED2
+#undef PL
+#undef PH
+
+// ---------------------------------------
+// func p256OrdMul(res, in1, in2 []byte)
+#define res_ptr R1
+#define x_ptr R2
+#define y_ptr R3
+#define X0 V0
+#define X1 V1
+#define Y0 V2
+#define Y1 V3
+#define M0 V4
+#define M1 V5
+#define T0 V6
+#define T1 V7
+#define T2 V8
+#define YDIG V9
+
+#define ADD1 V16
+#define ADD1H V17
+#define ADD2 V18
+#define ADD2H V19
+#define RED1 V20
+#define RED1H V21
+#define RED2 V22
+#define RED2H V23
+#define CAR1 V24
+#define CAR1M V25
+
+#define MK0 V30
+#define K0 V31
+TEXT ·p256OrdMul(SB), NOSPLIT, $0
+ MOVD res+0(FP), res_ptr
+ MOVD in1+24(FP), x_ptr
+ MOVD in2+48(FP), y_ptr
+
+ VZERO T2
+ MOVD $p256ordK0<>+0x00(SB), R4
+
+ // VLEF $3, 0(R4), K0
+ WORD $0xE7F40000
+ BYTE $0x38
+ BYTE $0x03
+ MOVD $p256ord<>+0x00(SB), R4
+ VL 16(R4), M0
+ VL 0(R4), M1
+
+ VL (1*16)(x_ptr), X0
+ VL (0*16)(x_ptr), X1
+ VL (1*16)(y_ptr), Y0
+ VL (0*16)(y_ptr), Y1
+
+ // ---------------------------------------------------------------------------/
+ VREPF $3, Y0, YDIG
+ VMLF X0, YDIG, ADD1
+ VMLF ADD1, K0, MK0
+ VREPF $3, MK0, MK0
+
+ VMLF X1, YDIG, ADD2
+ VMLHF X0, YDIG, ADD1H
+ VMLHF X1, YDIG, ADD2H
+
+ VMALF M0, MK0, ADD1, RED1
+ VMALHF M0, MK0, ADD1, RED1H
+ VMALF M1, MK0, ADD2, RED2
+ VMALHF M1, MK0, ADD2, RED2H
+
+ VSLDB $12, RED2, RED1, RED1
+ VSLDB $12, T2, RED2, RED2
+
+ VACCQ RED1, ADD1H, CAR1
+ VAQ RED1, ADD1H, T0
+ VACCQ RED1H, T0, CAR1M
+ VAQ RED1H, T0, T0
+
+ // << ready for next MK0
+
+ VACQ RED2, ADD2H, CAR1, T1
+ VACCCQ RED2, ADD2H, CAR1, CAR1
+ VACCCQ RED2H, T1, CAR1M, T2
+ VACQ RED2H, T1, CAR1M, T1
+ VAQ CAR1, T2, T2
+
+ // ---------------------------------------------------
+/* *
+ * ---+--------+--------+
+ * T2| T1 | T0 |
+ * ---+--------+--------+
+ * *(add)*
+ * +--------+--------+
+ * | X1 | X0 |
+ * +--------+--------+
+ * *(mul)*
+ * +--------+--------+
+ * | YDIG | YDIG |
+ * +--------+--------+
+ * *(add)*
+ * +--------+--------+
+ * | M1 | M0 |
+ * +--------+--------+
+ * *(mul)*
+ * +--------+--------+
+ * | MK0 | MK0 |
+ * +--------+--------+
+ *
+ * ---------------------
+ *
+ * +--------+--------+
+ * | ADD2 | ADD1 |
+ * +--------+--------+
+ * +--------+--------+
+ * | ADD2H | ADD1H |
+ * +--------+--------+
+ * +--------+--------+
+ * | RED2 | RED1 |
+ * +--------+--------+
+ * +--------+--------+
+ * | RED2H | RED1H |
+ * +--------+--------+
+ */
+ VREPF $2, Y0, YDIG
+ VMALF X0, YDIG, T0, ADD1
+ VMLF ADD1, K0, MK0
+ VREPF $3, MK0, MK0
+
+ VMALF X1, YDIG, T1, ADD2
+ VMALHF X0, YDIG, T0, ADD1H
+ VMALHF X1, YDIG, T1, ADD2H
+
+ VMALF M0, MK0, ADD1, RED1
+ VMALHF M0, MK0, ADD1, RED1H
+ VMALF M1, MK0, ADD2, RED2
+ VMALHF M1, MK0, ADD2, RED2H
+
+ VSLDB $12, RED2, RED1, RED1
+ VSLDB $12, T2, RED2, RED2
+
+ VACCQ RED1, ADD1H, CAR1
+ VAQ RED1, ADD1H, T0
+ VACCQ RED1H, T0, CAR1M
+ VAQ RED1H, T0, T0
+
+ // << ready for next MK0
+
+ VACQ RED2, ADD2H, CAR1, T1
+ VACCCQ RED2, ADD2H, CAR1, CAR1
+ VACCCQ RED2H, T1, CAR1M, T2
+ VACQ RED2H, T1, CAR1M, T1
+ VAQ CAR1, T2, T2
+
+ // ---------------------------------------------------
+ VREPF $1, Y0, YDIG
+ VMALF X0, YDIG, T0, ADD1
+ VMLF ADD1, K0, MK0
+ VREPF $3, MK0, MK0
+
+ VMALF X1, YDIG, T1, ADD2
+ VMALHF X0, YDIG, T0, ADD1H
+ VMALHF X1, YDIG, T1, ADD2H
+
+ VMALF M0, MK0, ADD1, RED1
+ VMALHF M0, MK0, ADD1, RED1H
+ VMALF M1, MK0, ADD2, RED2
+ VMALHF M1, MK0, ADD2, RED2H
+
+ VSLDB $12, RED2, RED1, RED1
+ VSLDB $12, T2, RED2, RED2
+
+ VACCQ RED1, ADD1H, CAR1
+ VAQ RED1, ADD1H, T0
+ VACCQ RED1H, T0, CAR1M
+ VAQ RED1H, T0, T0
+
+ // << ready for next MK0
+
+ VACQ RED2, ADD2H, CAR1, T1
+ VACCCQ RED2, ADD2H, CAR1, CAR1
+ VACCCQ RED2H, T1, CAR1M, T2
+ VACQ RED2H, T1, CAR1M, T1
+ VAQ CAR1, T2, T2
+
+ // ---------------------------------------------------
+ VREPF $0, Y0, YDIG
+ VMALF X0, YDIG, T0, ADD1
+ VMLF ADD1, K0, MK0
+ VREPF $3, MK0, MK0
+
+ VMALF X1, YDIG, T1, ADD2
+ VMALHF X0, YDIG, T0, ADD1H
+ VMALHF X1, YDIG, T1, ADD2H
+
+ VMALF M0, MK0, ADD1, RED1
+ VMALHF M0, MK0, ADD1, RED1H
+ VMALF M1, MK0, ADD2, RED2
+ VMALHF M1, MK0, ADD2, RED2H
+
+ VSLDB $12, RED2, RED1, RED1
+ VSLDB $12, T2, RED2, RED2
+
+ VACCQ RED1, ADD1H, CAR1
+ VAQ RED1, ADD1H, T0
+ VACCQ RED1H, T0, CAR1M
+ VAQ RED1H, T0, T0
+
+ // << ready for next MK0
+
+ VACQ RED2, ADD2H, CAR1, T1
+ VACCCQ RED2, ADD2H, CAR1, CAR1
+ VACCCQ RED2H, T1, CAR1M, T2
+ VACQ RED2H, T1, CAR1M, T1
+ VAQ CAR1, T2, T2
+
+ // ---------------------------------------------------
+ VREPF $3, Y1, YDIG
+ VMALF X0, YDIG, T0, ADD1
+ VMLF ADD1, K0, MK0
+ VREPF $3, MK0, MK0
+
+ VMALF X1, YDIG, T1, ADD2
+ VMALHF X0, YDIG, T0, ADD1H
+ VMALHF X1, YDIG, T1, ADD2H
+
+ VMALF M0, MK0, ADD1, RED1
+ VMALHF M0, MK0, ADD1, RED1H
+ VMALF M1, MK0, ADD2, RED2
+ VMALHF M1, MK0, ADD2, RED2H
+
+ VSLDB $12, RED2, RED1, RED1
+ VSLDB $12, T2, RED2, RED2
+
+ VACCQ RED1, ADD1H, CAR1
+ VAQ RED1, ADD1H, T0
+ VACCQ RED1H, T0, CAR1M
+ VAQ RED1H, T0, T0
+
+ // << ready for next MK0
+
+ VACQ RED2, ADD2H, CAR1, T1
+ VACCCQ RED2, ADD2H, CAR1, CAR1
+ VACCCQ RED2H, T1, CAR1M, T2
+ VACQ RED2H, T1, CAR1M, T1
+ VAQ CAR1, T2, T2
+
+ // ---------------------------------------------------
+ VREPF $2, Y1, YDIG
+ VMALF X0, YDIG, T0, ADD1
+ VMLF ADD1, K0, MK0
+ VREPF $3, MK0, MK0
+
+ VMALF X1, YDIG, T1, ADD2
+ VMALHF X0, YDIG, T0, ADD1H
+ VMALHF X1, YDIG, T1, ADD2H
+
+ VMALF M0, MK0, ADD1, RED1
+ VMALHF M0, MK0, ADD1, RED1H
+ VMALF M1, MK0, ADD2, RED2
+ VMALHF M1, MK0, ADD2, RED2H
+
+ VSLDB $12, RED2, RED1, RED1
+ VSLDB $12, T2, RED2, RED2
+
+ VACCQ RED1, ADD1H, CAR1
+ VAQ RED1, ADD1H, T0
+ VACCQ RED1H, T0, CAR1M
+ VAQ RED1H, T0, T0
+
+ // << ready for next MK0
+
+ VACQ RED2, ADD2H, CAR1, T1
+ VACCCQ RED2, ADD2H, CAR1, CAR1
+ VACCCQ RED2H, T1, CAR1M, T2
+ VACQ RED2H, T1, CAR1M, T1
+ VAQ CAR1, T2, T2
+
+ // ---------------------------------------------------
+ VREPF $1, Y1, YDIG
+ VMALF X0, YDIG, T0, ADD1
+ VMLF ADD1, K0, MK0
+ VREPF $3, MK0, MK0
+
+ VMALF X1, YDIG, T1, ADD2
+ VMALHF X0, YDIG, T0, ADD1H
+ VMALHF X1, YDIG, T1, ADD2H
+
+ VMALF M0, MK0, ADD1, RED1
+ VMALHF M0, MK0, ADD1, RED1H
+ VMALF M1, MK0, ADD2, RED2
+ VMALHF M1, MK0, ADD2, RED2H
+
+ VSLDB $12, RED2, RED1, RED1
+ VSLDB $12, T2, RED2, RED2
+
+ VACCQ RED1, ADD1H, CAR1
+ VAQ RED1, ADD1H, T0
+ VACCQ RED1H, T0, CAR1M
+ VAQ RED1H, T0, T0
+
+ // << ready for next MK0
+
+ VACQ RED2, ADD2H, CAR1, T1
+ VACCCQ RED2, ADD2H, CAR1, CAR1
+ VACCCQ RED2H, T1, CAR1M, T2
+ VACQ RED2H, T1, CAR1M, T1
+ VAQ CAR1, T2, T2
+
+ // ---------------------------------------------------
+ VREPF $0, Y1, YDIG
+ VMALF X0, YDIG, T0, ADD1
+ VMLF ADD1, K0, MK0
+ VREPF $3, MK0, MK0
+
+ VMALF X1, YDIG, T1, ADD2
+ VMALHF X0, YDIG, T0, ADD1H
+ VMALHF X1, YDIG, T1, ADD2H
+
+ VMALF M0, MK0, ADD1, RED1
+ VMALHF M0, MK0, ADD1, RED1H
+ VMALF M1, MK0, ADD2, RED2
+ VMALHF M1, MK0, ADD2, RED2H
+
+ VSLDB $12, RED2, RED1, RED1
+ VSLDB $12, T2, RED2, RED2
+
+ VACCQ RED1, ADD1H, CAR1
+ VAQ RED1, ADD1H, T0
+ VACCQ RED1H, T0, CAR1M
+ VAQ RED1H, T0, T0
+
+ // << ready for next MK0
+
+ VACQ RED2, ADD2H, CAR1, T1
+ VACCCQ RED2, ADD2H, CAR1, CAR1
+ VACCCQ RED2H, T1, CAR1M, T2
+ VACQ RED2H, T1, CAR1M, T1
+ VAQ CAR1, T2, T2
+
+ // ---------------------------------------------------
+
+ VZERO RED1
+ VSCBIQ M0, T0, CAR1
+ VSQ M0, T0, ADD1
+ VSBCBIQ T1, M1, CAR1, CAR1M
+ VSBIQ T1, M1, CAR1, ADD2
+ VSBIQ T2, RED1, CAR1M, T2
+
+ // what output to use, ADD2||ADD1 or T1||T0?
+ VSEL T0, ADD1, T2, T0
+ VSEL T1, ADD2, T2, T1
+
+ VST T0, (1*16)(res_ptr)
+ VST T1, (0*16)(res_ptr)
+ RET
+
+#undef res_ptr
+#undef x_ptr
+#undef y_ptr
+#undef X0
+#undef X1
+#undef Y0
+#undef Y1
+#undef M0
+#undef M1
+#undef T0
+#undef T1
+#undef T2
+#undef YDIG
+
+#undef ADD1
+#undef ADD1H
+#undef ADD2
+#undef ADD2H
+#undef RED1
+#undef RED1H
+#undef RED2
+#undef RED2H
+#undef CAR1
+#undef CAR1M
+
+#undef MK0
+#undef K0
+
+// ---------------------------------------
+// p256MulInternal
+// V0-V3,V30,V31 - Not Modified
+// V4-V15 - Volatile
+
+#define CPOOL R4
+
+// Parameters
+#define X0 V0 // Not modified
+#define X1 V1 // Not modified
+#define Y0 V2 // Not modified
+#define Y1 V3 // Not modified
+#define T0 V4
+#define T1 V5
+#define P0 V30 // Not modified
+#define P1 V31 // Not modified
+
+// Temporaries
+#define YDIG V6 // Overloaded with CAR2, ZER
+#define ADD1H V7 // Overloaded with ADD3H
+#define ADD2H V8 // Overloaded with ADD4H
+#define ADD3 V9 // Overloaded with SEL2,SEL5
+#define ADD4 V10 // Overloaded with SEL3,SEL6
+#define RED1 V11 // Overloaded with CAR2
+#define RED2 V12
+#define RED3 V13 // Overloaded with SEL1
+#define T2 V14
+// Overloaded temporaries
+#define ADD1 V4 // Overloaded with T0
+#define ADD2 V5 // Overloaded with T1
+#define ADD3H V7 // Overloaded with ADD1H
+#define ADD4H V8 // Overloaded with ADD2H
+#define ZER V6 // Overloaded with YDIG, CAR2
+#define CAR1 V6 // Overloaded with YDIG, ZER
+#define CAR2 V11 // Overloaded with RED1
+// Constant Selects
+#define SEL1 V13 // Overloaded with RED3
+#define SEL2 V9 // Overloaded with ADD3,SEL5
+#define SEL3 V10 // Overloaded with ADD4,SEL6
+#define SEL4 V6 // Overloaded with YDIG,CAR2,ZER
+#define SEL5 V9 // Overloaded with ADD3,SEL2
+#define SEL6 V10 // Overloaded with ADD4,SEL3
+
+/* *
+ * To follow the flow of bits, for your own sanity a stiff drink, need you shall.
+ * Of a single round, a 'helpful' picture, here is. Meaning, column position has.
+ * With you, SIMD be...
+ *
+ * +--------+--------+
+ * +--------| RED2 | RED1 |
+ * | +--------+--------+
+ * | ---+--------+--------+
+ * | +---- T2| T1 | T0 |--+
+ * | | ---+--------+--------+ |
+ * | | |
+ * | | ======================= |
+ * | | |
+ * | | +--------+--------+<-+
+ * | +-------| ADD2 | ADD1 |--|-----+
+ * | | +--------+--------+ | |
+ * | | +--------+--------+<---+ |
+ * | | | ADD2H | ADD1H |--+ |
+ * | | +--------+--------+ | |
+ * | | +--------+--------+<-+ |
+ * | | | ADD4 | ADD3 |--|-+ |
+ * | | +--------+--------+ | | |
+ * | | +--------+--------+<---+ | |
+ * | | | ADD4H | ADD3H |------|-+ |(+vzero)
+ * | | +--------+--------+ | | V
+ * | | ------------------------ | | +--------+
+ * | | | | | RED3 | [d0 0 0 d0]
+ * | | | | +--------+
+ * | +---->+--------+--------+ | | |
+ * (T2[1w]||ADD2[4w]||ADD1[3w]) +--------| T1 | T0 | | | |
+ * | +--------+--------+ | | |
+ * +---->---+--------+--------+ | | |
+ * T2| T1 | T0 |----+ | |
+ * ---+--------+--------+ | | |
+ * ---+--------+--------+<---+ | |
+ * +--- T2| T1 | T0 |----------+
+ * | ---+--------+--------+ | |
+ * | +--------+--------+<-------------+
+ * | | RED2 | RED1 |-----+ | | [0 d1 d0 d1] [d0 0 d1 d0]
+ * | +--------+--------+ | | |
+ * | +--------+<----------------------+
+ * | | RED3 |--------------+ | [0 0 d1 d0]
+ * | +--------+ | |
+ * +--->+--------+--------+ | |
+ * | T1 | T0 |--------+
+ * +--------+--------+ | |
+ * --------------------------- | |
+ * | |
+ * +--------+--------+<----+ |
+ * | RED2 | RED1 | |
+ * +--------+--------+ |
+ * ---+--------+--------+<-------+
+ * T2| T1 | T0 | (H1P-H1P-H00RRAY!)
+ * ---+--------+--------+
+ *
+ * *Mi obra de arte de siglo XXI @vpaprots
+ *
+ *
+ * First group is special, doesnt get the two inputs:
+ * +--------+--------+<-+
+ * +-------| ADD2 | ADD1 |--|-----+
+ * | +--------+--------+ | |
+ * | +--------+--------+<---+ |
+ * | | ADD2H | ADD1H |--+ |
+ * | +--------+--------+ | |
+ * | +--------+--------+<-+ |
+ * | | ADD4 | ADD3 |--|-+ |
+ * | +--------+--------+ | | |
+ * | +--------+--------+<---+ | |
+ * | | ADD4H | ADD3H |------|-+ |(+vzero)
+ * | +--------+--------+ | | V
+ * | ------------------------ | | +--------+
+ * | | | | RED3 | [d0 0 0 d0]
+ * | | | +--------+
+ * +---->+--------+--------+ | | |
+ * (T2[1w]||ADD2[4w]||ADD1[3w]) | T1 | T0 |----+ | |
+ * +--------+--------+ | | |
+ * ---+--------+--------+<---+ | |
+ * +--- T2| T1 | T0 |----------+
+ * | ---+--------+--------+ | |
+ * | +--------+--------+<-------------+
+ * | | RED2 | RED1 |-----+ | | [0 d1 d0 d1] [d0 0 d1 d0]
+ * | +--------+--------+ | | |
+ * | +--------+<----------------------+
+ * | | RED3 |--------------+ | [0 0 d1 d0]
+ * | +--------+ | |
+ * +--->+--------+--------+ | |
+ * | T1 | T0 |--------+
+ * +--------+--------+ | |
+ * --------------------------- | |
+ * | |
+ * +--------+--------+<----+ |
+ * | RED2 | RED1 | |
+ * +--------+--------+ |
+ * ---+--------+--------+<-------+
+ * T2| T1 | T0 | (H1P-H1P-H00RRAY!)
+ * ---+--------+--------+
+ *
+ * Last 'group' needs to RED2||RED1 shifted less
+ */
+TEXT p256MulInternal<>(SB), NOSPLIT, $0-0
+ VL 32(CPOOL), SEL1
+ VL 48(CPOOL), SEL2
+ VL 64(CPOOL), SEL3
+ VL 80(CPOOL), SEL4
+
+ // ---------------------------------------------------
+
+ VREPF $3, Y0, YDIG
+ VMLHF X0, YDIG, ADD1H
+ VMLHF X1, YDIG, ADD2H
+ VMLF X0, YDIG, ADD1
+ VMLF X1, YDIG, ADD2
+
+ VREPF $2, Y0, YDIG
+ VMALF X0, YDIG, ADD1H, ADD3
+ VMALF X1, YDIG, ADD2H, ADD4
+ VMALHF X0, YDIG, ADD1H, ADD3H // ADD1H Free
+ VMALHF X1, YDIG, ADD2H, ADD4H // ADD2H Free
+
+ VZERO ZER
+ VL 32(CPOOL), SEL1
+ VPERM ZER, ADD1, SEL1, RED3 // [d0 0 0 d0]
+
+ VSLDB $12, ADD2, ADD1, T0 // ADD1 Free
+ VSLDB $12, ZER, ADD2, T1 // ADD2 Free
+
+ VACCQ T0, ADD3, CAR1
+ VAQ T0, ADD3, T0 // ADD3 Free
+ VACCCQ T1, ADD4, CAR1, T2
+ VACQ T1, ADD4, CAR1, T1 // ADD4 Free
+
+ VL 48(CPOOL), SEL2
+ VL 64(CPOOL), SEL3
+ VL 80(CPOOL), SEL4
+ VPERM RED3, T0, SEL2, RED1 // [d0 0 d1 d0]
+ VPERM RED3, T0, SEL3, RED2 // [ 0 d1 d0 d1]
+ VPERM RED3, T0, SEL4, RED3 // [ 0 0 d1 d0]
+ VSQ RED3, RED2, RED2 // Guaranteed not to underflow
+
+ VSLDB $12, T1, T0, T0
+ VSLDB $12, T2, T1, T1
+
+ VACCQ T0, ADD3H, CAR1
+ VAQ T0, ADD3H, T0
+ VACCCQ T1, ADD4H, CAR1, T2
+ VACQ T1, ADD4H, CAR1, T1
+
+ // ---------------------------------------------------
+
+ VREPF $1, Y0, YDIG
+ VMALHF X0, YDIG, T0, ADD1H
+ VMALHF X1, YDIG, T1, ADD2H
+ VMALF X0, YDIG, T0, ADD1 // T0 Free->ADD1
+ VMALF X1, YDIG, T1, ADD2 // T1 Free->ADD2
+
+ VREPF $0, Y0, YDIG
+ VMALF X0, YDIG, ADD1H, ADD3
+ VMALF X1, YDIG, ADD2H, ADD4
+ VMALHF X0, YDIG, ADD1H, ADD3H // ADD1H Free->ADD3H
+ VMALHF X1, YDIG, ADD2H, ADD4H // ADD2H Free->ADD4H , YDIG Free->ZER
+
+ VZERO ZER
+ VL 32(CPOOL), SEL1
+ VPERM ZER, ADD1, SEL1, RED3 // [d0 0 0 d0]
+
+ VSLDB $12, ADD2, ADD1, T0 // ADD1 Free->T0
+ VSLDB $12, T2, ADD2, T1 // ADD2 Free->T1, T2 Free
+
+ VACCQ T0, RED1, CAR1
+ VAQ T0, RED1, T0
+ VACCCQ T1, RED2, CAR1, T2
+ VACQ T1, RED2, CAR1, T1
+
+ VACCQ T0, ADD3, CAR1
+ VAQ T0, ADD3, T0
+ VACCCQ T1, ADD4, CAR1, CAR2
+ VACQ T1, ADD4, CAR1, T1
+ VAQ T2, CAR2, T2
+
+ VL 48(CPOOL), SEL2
+ VL 64(CPOOL), SEL3
+ VL 80(CPOOL), SEL4
+ VPERM RED3, T0, SEL2, RED1 // [d0 0 d1 d0]
+ VPERM RED3, T0, SEL3, RED2 // [ 0 d1 d0 d1]
+ VPERM RED3, T0, SEL4, RED3 // [ 0 0 d1 d0]
+ VSQ RED3, RED2, RED2 // Guaranteed not to underflow
+
+ VSLDB $12, T1, T0, T0
+ VSLDB $12, T2, T1, T1
+
+ VACCQ T0, ADD3H, CAR1
+ VAQ T0, ADD3H, T0
+ VACCCQ T1, ADD4H, CAR1, T2
+ VACQ T1, ADD4H, CAR1, T1
+
+ // ---------------------------------------------------
+
+ VREPF $3, Y1, YDIG
+ VMALHF X0, YDIG, T0, ADD1H
+ VMALHF X1, YDIG, T1, ADD2H
+ VMALF X0, YDIG, T0, ADD1
+ VMALF X1, YDIG, T1, ADD2
+
+ VREPF $2, Y1, YDIG
+ VMALF X0, YDIG, ADD1H, ADD3
+ VMALF X1, YDIG, ADD2H, ADD4
+ VMALHF X0, YDIG, ADD1H, ADD3H // ADD1H Free
+ VMALHF X1, YDIG, ADD2H, ADD4H // ADD2H Free
+
+ VZERO ZER
+ VL 32(CPOOL), SEL1
+ VPERM ZER, ADD1, SEL1, RED3 // [d0 0 0 d0]
+
+ VSLDB $12, ADD2, ADD1, T0 // ADD1 Free
+ VSLDB $12, T2, ADD2, T1 // ADD2 Free
+
+ VACCQ T0, RED1, CAR1
+ VAQ T0, RED1, T0
+ VACCCQ T1, RED2, CAR1, T2
+ VACQ T1, RED2, CAR1, T1
+
+ VACCQ T0, ADD3, CAR1
+ VAQ T0, ADD3, T0
+ VACCCQ T1, ADD4, CAR1, CAR2
+ VACQ T1, ADD4, CAR1, T1
+ VAQ T2, CAR2, T2
+
+ VL 48(CPOOL), SEL2
+ VL 64(CPOOL), SEL3
+ VL 80(CPOOL), SEL4
+ VPERM RED3, T0, SEL2, RED1 // [d0 0 d1 d0]
+ VPERM RED3, T0, SEL3, RED2 // [ 0 d1 d0 d1]
+ VPERM RED3, T0, SEL4, RED3 // [ 0 0 d1 d0]
+ VSQ RED3, RED2, RED2 // Guaranteed not to underflow
+
+ VSLDB $12, T1, T0, T0
+ VSLDB $12, T2, T1, T1
+
+ VACCQ T0, ADD3H, CAR1
+ VAQ T0, ADD3H, T0
+ VACCCQ T1, ADD4H, CAR1, T2
+ VACQ T1, ADD4H, CAR1, T1
+
+ // ---------------------------------------------------
+
+ VREPF $1, Y1, YDIG
+ VMALHF X0, YDIG, T0, ADD1H
+ VMALHF X1, YDIG, T1, ADD2H
+ VMALF X0, YDIG, T0, ADD1
+ VMALF X1, YDIG, T1, ADD2
+
+ VREPF $0, Y1, YDIG
+ VMALF X0, YDIG, ADD1H, ADD3
+ VMALF X1, YDIG, ADD2H, ADD4
+ VMALHF X0, YDIG, ADD1H, ADD3H
+ VMALHF X1, YDIG, ADD2H, ADD4H
+
+ VZERO ZER
+ VL 32(CPOOL), SEL1
+ VPERM ZER, ADD1, SEL1, RED3 // [d0 0 0 d0]
+
+ VSLDB $12, ADD2, ADD1, T0
+ VSLDB $12, T2, ADD2, T1
+
+ VACCQ T0, RED1, CAR1
+ VAQ T0, RED1, T0
+ VACCCQ T1, RED2, CAR1, T2
+ VACQ T1, RED2, CAR1, T1
+
+ VACCQ T0, ADD3, CAR1
+ VAQ T0, ADD3, T0
+ VACCCQ T1, ADD4, CAR1, CAR2
+ VACQ T1, ADD4, CAR1, T1
+ VAQ T2, CAR2, T2
+
+ VL 96(CPOOL), SEL5
+ VL 112(CPOOL), SEL6
+ VPERM T0, RED3, SEL5, RED2 // [d1 d0 d1 d0]
+ VPERM T0, RED3, SEL6, RED1 // [ 0 d1 d0 0]
+ VSQ RED1, RED2, RED2 // Guaranteed not to underflow
+
+ VSLDB $12, T1, T0, T0
+ VSLDB $12, T2, T1, T1
+
+ VACCQ T0, ADD3H, CAR1
+ VAQ T0, ADD3H, T0
+ VACCCQ T1, ADD4H, CAR1, T2
+ VACQ T1, ADD4H, CAR1, T1
+
+ VACCQ T0, RED1, CAR1
+ VAQ T0, RED1, T0
+ VACCCQ T1, RED2, CAR1, CAR2
+ VACQ T1, RED2, CAR1, T1
+ VAQ T2, CAR2, T2
+
+ // ---------------------------------------------------
+
+ VZERO RED3
+ VSCBIQ P0, T0, CAR1
+ VSQ P0, T0, ADD1H
+ VSBCBIQ T1, P1, CAR1, CAR2
+ VSBIQ T1, P1, CAR1, ADD2H
+ VSBIQ T2, RED3, CAR2, T2
+
+ // what output to use, ADD2H||ADD1H or T1||T0?
+ VSEL T0, ADD1H, T2, T0
+ VSEL T1, ADD2H, T2, T1
+ RET
+
+#undef CPOOL
+
+#undef X0
+#undef X1
+#undef Y0
+#undef Y1
+#undef T0
+#undef T1
+#undef P0
+#undef P1
+
+#undef SEL1
+#undef SEL2
+#undef SEL3
+#undef SEL4
+#undef SEL5
+#undef SEL6
+
+#undef YDIG
+#undef ADD1H
+#undef ADD2H
+#undef ADD3
+#undef ADD4
+#undef RED1
+#undef RED2
+#undef RED3
+#undef T2
+#undef ADD1
+#undef ADD2
+#undef ADD3H
+#undef ADD4H
+#undef ZER
+#undef CAR1
+#undef CAR2
+
+#define p256SubInternal(T1, T0, X1, X0, Y1, Y0) \
+ VZERO ZER \
+ VSCBIQ Y0, X0, CAR1 \
+ VSQ Y0, X0, T0 \
+ VSBCBIQ X1, Y1, CAR1, SEL1 \
+ VSBIQ X1, Y1, CAR1, T1 \
+ VSQ SEL1, ZER, SEL1 \
+ \
+ VACCQ T0, PL, CAR1 \
+ VAQ T0, PL, TT0 \
+ VACQ T1, PH, CAR1, TT1 \
+ \
+ VSEL T0, TT0, SEL1, T0 \
+ VSEL T1, TT1, SEL1, T1 \
+
+#define p256AddInternal(T1, T0, X1, X0, Y1, Y0) \
+ VACCQ X0, Y0, CAR1 \
+ VAQ X0, Y0, T0 \
+ VACCCQ X1, Y1, CAR1, T2 \
+ VACQ X1, Y1, CAR1, T1 \
+ \
+ VZERO ZER \
+ VSCBIQ PL, T0, CAR1 \
+ VSQ PL, T0, TT0 \
+ VSBCBIQ T1, PH, CAR1, CAR2 \
+ VSBIQ T1, PH, CAR1, TT1 \
+ VSBIQ T2, ZER, CAR2, SEL1 \
+ \
+ VSEL T0, TT0, SEL1, T0 \
+ VSEL T1, TT1, SEL1, T1
+
+#define p256HalfInternal(T1, T0, X1, X0) \
+ VZERO ZER \
+ VSBIQ ZER, ZER, X0, SEL1 \
+ \
+ VACCQ X0, PL, CAR1 \
+ VAQ X0, PL, T0 \
+ VACCCQ X1, PH, CAR1, T2 \
+ VACQ X1, PH, CAR1, T1 \
+ \
+ VSEL X0, T0, SEL1, T0 \
+ VSEL X1, T1, SEL1, T1 \
+ VSEL ZER, T2, SEL1, T2 \
+ \
+ VSLDB $15, T2, ZER, TT1 \
+ VSLDB $15, T1, ZER, TT0 \
+ VREPIB $1, SEL1 \
+ VSRL SEL1, T0, T0 \
+ VSRL SEL1, T1, T1 \
+ VREPIB $7, SEL1 \
+ VSL SEL1, TT0, TT0 \
+ VSL SEL1, TT1, TT1 \
+ VO T0, TT0, T0 \
+ VO T1, TT1, T1
+
+// ---------------------------------------
+// func p256MulAsm(res, in1, in2 []byte)
+#define res_ptr R1
+#define x_ptr R2
+#define y_ptr R3
+#define CPOOL R4
+
+// Parameters
+#define X0 V0
+#define X1 V1
+#define Y0 V2
+#define Y1 V3
+#define T0 V4
+#define T1 V5
+
+// Constants
+#define P0 V30
+#define P1 V31
+TEXT ·p256MulAsm(SB), NOSPLIT, $0
+ MOVD res+0(FP), res_ptr
+ MOVD in1+24(FP), x_ptr
+ MOVD in2+48(FP), y_ptr
+
+ VL (1*16)(x_ptr), X0
+ VL (0*16)(x_ptr), X1
+ VL (1*16)(y_ptr), Y0
+ VL (0*16)(y_ptr), Y1
+
+ MOVD $p256mul<>+0x00(SB), CPOOL
+ VL 16(CPOOL), P0
+ VL 0(CPOOL), P1
+
+ CALL p256MulInternal<>(SB)
+
+ VST T0, (1*16)(res_ptr)
+ VST T1, (0*16)(res_ptr)
+ RET
+
+#undef res_ptr
+#undef x_ptr
+#undef y_ptr
+#undef CPOOL
+
+#undef X0
+#undef X1
+#undef Y0
+#undef Y1
+#undef T0
+#undef T1
+#undef P0
+#undef P1
+
+// Point add with P2 being affine point
+// If sign == 1 -> P2 = -P2
+// If sel == 0 -> P3 = P1
+// if zero == 0 -> P3 = P2
+// p256PointAddAffineAsm(P3, P1, P2 *p256Point, sign, sel, zero int)
+#define P3ptr R1
+#define P1ptr R2
+#define P2ptr R3
+#define CPOOL R4
+
+// Temporaries in REGs
+#define Y2L V15
+#define Y2H V16
+#define T1L V17
+#define T1H V18
+#define T2L V19
+#define T2H V20
+#define T3L V21
+#define T3H V22
+#define T4L V23
+#define T4H V24
+
+// Temps for Sub and Add
+#define TT0 V11
+#define TT1 V12
+#define T2 V13
+
+// p256MulAsm Parameters
+#define X0 V0
+#define X1 V1
+#define Y0 V2
+#define Y1 V3
+#define T0 V4
+#define T1 V5
+
+#define PL V30
+#define PH V31
+
+// Names for zero/sel selects
+#define X1L V0
+#define X1H V1
+#define Y1L V2 // p256MulAsmParmY
+#define Y1H V3 // p256MulAsmParmY
+#define Z1L V4
+#define Z1H V5
+#define X2L V0
+#define X2H V1
+#define Z2L V4
+#define Z2H V5
+#define X3L V17 // T1L
+#define X3H V18 // T1H
+#define Y3L V21 // T3L
+#define Y3H V22 // T3H
+#define Z3L V28
+#define Z3H V29
+
+#define ZER V6
+#define SEL1 V7
+#define CAR1 V8
+#define CAR2 V9
+/* *
+ * Three operand formula:
+ * Source: 2004 Hankerson–Menezes–Vanstone, page 91.
+ * T1 = Z1²
+ * T2 = T1*Z1
+ * T1 = T1*X2
+ * T2 = T2*Y2
+ * T1 = T1-X1
+ * T2 = T2-Y1
+ * Z3 = Z1*T1
+ * T3 = T1²
+ * T4 = T3*T1
+ * T3 = T3*X1
+ * T1 = 2*T3
+ * X3 = T2²
+ * X3 = X3-T1
+ * X3 = X3-T4
+ * T3 = T3-X3
+ * T3 = T3*T2
+ * T4 = T4*Y1
+ * Y3 = T3-T4
+
+ * Three operand formulas, but with MulInternal X,Y used to store temps
+X=Z1; Y=Z1; MUL;T- // T1 = Z1² T1
+X=T ; Y- ; MUL;T2=T // T2 = T1*Z1 T1 T2
+X- ; Y=X2; MUL;T1=T // T1 = T1*X2 T1 T2
+X=T2; Y=Y2; MUL;T- // T2 = T2*Y2 T1 T2
+SUB(T2<T-Y1) // T2 = T2-Y1 T1 T2
+SUB(Y<T1-X1) // T1 = T1-X1 T1 T2
+X=Z1; Y- ; MUL;Z3:=T// Z3 = Z1*T1 T2
+X=Y; Y- ; MUL;X=T // T3 = T1*T1 T2
+X- ; Y- ; MUL;T4=T // T4 = T3*T1 T2 T4
+X- ; Y=X1; MUL;T3=T // T3 = T3*X1 T2 T3 T4
+ADD(T1<T+T) // T1 = T3+T3 T1 T2 T3 T4
+X=T2; Y=T2; MUL;T- // X3 = T2*T2 T1 T2 T3 T4
+SUB(T<T-T1) // X3 = X3-T1 T1 T2 T3 T4
+SUB(T<T-T4) X3:=T // X3 = X3-T4 T2 T3 T4
+SUB(X<T3-T) // T3 = T3-X3 T2 T3 T4
+X- ; Y- ; MUL;T3=T // T3 = T3*T2 T2 T3 T4
+X=T4; Y=Y1; MUL;T- // T4 = T4*Y1 T3 T4
+SUB(T<T3-T) Y3:=T // Y3 = T3-T4 T3 T4
+
+ */
+TEXT ·p256PointAddAffineAsm(SB), NOSPLIT, $0
+ MOVD P3+0(FP), P3ptr
+ MOVD P1+8(FP), P1ptr
+ MOVD P2+16(FP), P2ptr
+
+ MOVD $p256mul<>+0x00(SB), CPOOL
+ VL 16(CPOOL), PL
+ VL 0(CPOOL), PH
+
+ // if (sign == 1) {
+ // Y2 = fromBig(new(big.Int).Mod(new(big.Int).Sub(p256.P, new(big.Int).SetBytes(Y2)), p256.P)) // Y2 = P-Y2
+ // }
+
+ VL 32(P2ptr), Y2H
+ VL 48(P2ptr), Y2L
+
+ VLREPG sign+24(FP), SEL1
+ VZERO ZER
+ VCEQG SEL1, ZER, SEL1
+
+ VSCBIQ Y2L, PL, CAR1
+ VSQ Y2L, PL, T1L
+ VSBIQ PH, Y2H, CAR1, T1H
+
+ VSEL Y2L, T1L, SEL1, Y2L
+ VSEL Y2H, T1H, SEL1, Y2H
+
+/* *
+ * Three operand formula:
+ * Source: 2004 Hankerson–Menezes–Vanstone, page 91.
+ */
+ // X=Z1; Y=Z1; MUL; T- // T1 = Z1² T1
+ VL 64(P1ptr), X1 // Z1H
+ VL 80(P1ptr), X0 // Z1L
+ VLR X0, Y0
+ VLR X1, Y1
+ CALL p256MulInternal<>(SB)
+
+ // X=T ; Y- ; MUL; T2=T // T2 = T1*Z1 T1 T2
+ VLR T0, X0
+ VLR T1, X1
+ CALL p256MulInternal<>(SB)
+ VLR T0, T2L
+ VLR T1, T2H
+
+ // X- ; Y=X2; MUL; T1=T // T1 = T1*X2 T1 T2
+ VL 0(P2ptr), Y1 // X2H
+ VL 16(P2ptr), Y0 // X2L
+ CALL p256MulInternal<>(SB)
+ VLR T0, T1L
+ VLR T1, T1H
+
+ // X=T2; Y=Y2; MUL; T- // T2 = T2*Y2 T1 T2
+ VLR T2L, X0
+ VLR T2H, X1
+ VLR Y2L, Y0
+ VLR Y2H, Y1
+ CALL p256MulInternal<>(SB)
+
+ // SUB(T2<T-Y1) // T2 = T2-Y1 T1 T2
+ VL 32(P1ptr), Y1H
+ VL 48(P1ptr), Y1L
+ p256SubInternal(T2H,T2L,T1,T0,Y1H,Y1L)
+
+ // SUB(Y<T1-X1) // T1 = T1-X1 T1 T2
+ VL 0(P1ptr), X1H
+ VL 16(P1ptr), X1L
+ p256SubInternal(Y1,Y0,T1H,T1L,X1H,X1L)
+
+ // X=Z1; Y- ; MUL; Z3:=T// Z3 = Z1*T1 T2
+ VL 64(P1ptr), X1 // Z1H
+ VL 80(P1ptr), X0 // Z1L
+ CALL p256MulInternal<>(SB)
+
+ // VST T1, 64(P3ptr)
+ // VST T0, 80(P3ptr)
+ VLR T0, Z3L
+ VLR T1, Z3H
+
+ // X=Y; Y- ; MUL; X=T // T3 = T1*T1 T2
+ VLR Y0, X0
+ VLR Y1, X1
+ CALL p256MulInternal<>(SB)
+ VLR T0, X0
+ VLR T1, X1
+
+ // X- ; Y- ; MUL; T4=T // T4 = T3*T1 T2 T4
+ CALL p256MulInternal<>(SB)
+ VLR T0, T4L
+ VLR T1, T4H
+
+ // X- ; Y=X1; MUL; T3=T // T3 = T3*X1 T2 T3 T4
+ VL 0(P1ptr), Y1 // X1H
+ VL 16(P1ptr), Y0 // X1L
+ CALL p256MulInternal<>(SB)
+ VLR T0, T3L
+ VLR T1, T3H
+
+ // ADD(T1<T+T) // T1 = T3+T3 T1 T2 T3 T4
+ p256AddInternal(T1H,T1L, T1,T0,T1,T0)
+
+ // X=T2; Y=T2; MUL; T- // X3 = T2*T2 T1 T2 T3 T4
+ VLR T2L, X0
+ VLR T2H, X1
+ VLR T2L, Y0
+ VLR T2H, Y1
+ CALL p256MulInternal<>(SB)
+
+ // SUB(T<T-T1) // X3 = X3-T1 T1 T2 T3 T4 (T1 = X3)
+ p256SubInternal(T1,T0,T1,T0,T1H,T1L)
+
+ // SUB(T<T-T4) X3:=T // X3 = X3-T4 T2 T3 T4
+ p256SubInternal(T1,T0,T1,T0,T4H,T4L)
+ VLR T0, X3L
+ VLR T1, X3H
+
+ // SUB(X<T3-T) // T3 = T3-X3 T2 T3 T4
+ p256SubInternal(X1,X0,T3H,T3L,T1,T0)
+
+ // X- ; Y- ; MUL; T3=T // T3 = T3*T2 T2 T3 T4
+ CALL p256MulInternal<>(SB)
+ VLR T0, T3L
+ VLR T1, T3H
+
+ // X=T4; Y=Y1; MUL; T- // T4 = T4*Y1 T3 T4
+ VLR T4L, X0
+ VLR T4H, X1
+ VL 32(P1ptr), Y1 // Y1H
+ VL 48(P1ptr), Y0 // Y1L
+ CALL p256MulInternal<>(SB)
+
+ // SUB(T<T3-T) Y3:=T // Y3 = T3-T4 T3 T4 (T3 = Y3)
+ p256SubInternal(Y3H,Y3L,T3H,T3L,T1,T0)
+
+ // if (sel == 0) {
+ // copy(P3.x[:], X1)
+ // copy(P3.y[:], Y1)
+ // copy(P3.z[:], Z1)
+ // }
+
+ VL 0(P1ptr), X1H
+ VL 16(P1ptr), X1L
+
+ // Y1 already loaded, left over from addition
+ VL 64(P1ptr), Z1H
+ VL 80(P1ptr), Z1L
+
+ VLREPG sel+32(FP), SEL1
+ VZERO ZER
+ VCEQG SEL1, ZER, SEL1
+
+ VSEL X1L, X3L, SEL1, X3L
+ VSEL X1H, X3H, SEL1, X3H
+ VSEL Y1L, Y3L, SEL1, Y3L
+ VSEL Y1H, Y3H, SEL1, Y3H
+ VSEL Z1L, Z3L, SEL1, Z3L
+ VSEL Z1H, Z3H, SEL1, Z3H
+
+ // if (zero == 0) {
+ // copy(P3.x[:], X2)
+ // copy(P3.y[:], Y2)
+ // copy(P3.z[:], []byte{0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ // 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}) //(p256.z*2^256)%p
+ // }
+ VL 0(P2ptr), X2H
+ VL 16(P2ptr), X2L
+
+ // Y2 already loaded
+ VL 128(CPOOL), Z2H
+ VL 144(CPOOL), Z2L
+
+ VLREPG zero+40(FP), SEL1
+ VZERO ZER
+ VCEQG SEL1, ZER, SEL1
+
+ VSEL X2L, X3L, SEL1, X3L
+ VSEL X2H, X3H, SEL1, X3H
+ VSEL Y2L, Y3L, SEL1, Y3L
+ VSEL Y2H, Y3H, SEL1, Y3H
+ VSEL Z2L, Z3L, SEL1, Z3L
+ VSEL Z2H, Z3H, SEL1, Z3H
+
+ // All done, store out the result!!!
+ VST X3H, 0(P3ptr)
+ VST X3L, 16(P3ptr)
+ VST Y3H, 32(P3ptr)
+ VST Y3L, 48(P3ptr)
+ VST Z3H, 64(P3ptr)
+ VST Z3L, 80(P3ptr)
+
+ RET
+
+#undef P3ptr
+#undef P1ptr
+#undef P2ptr
+#undef CPOOL
+
+#undef Y2L
+#undef Y2H
+#undef T1L
+#undef T1H
+#undef T2L
+#undef T2H
+#undef T3L
+#undef T3H
+#undef T4L
+#undef T4H
+
+#undef TT0
+#undef TT1
+#undef T2
+
+#undef X0
+#undef X1
+#undef Y0
+#undef Y1
+#undef T0
+#undef T1
+
+#undef PL
+#undef PH
+
+#undef X1L
+#undef X1H
+#undef Y1L
+#undef Y1H
+#undef Z1L
+#undef Z1H
+#undef X2L
+#undef X2H
+#undef Z2L
+#undef Z2H
+#undef X3L
+#undef X3H
+#undef Y3L
+#undef Y3H
+#undef Z3L
+#undef Z3H
+
+#undef ZER
+#undef SEL1
+#undef CAR1
+#undef CAR2
+
+// p256PointDoubleAsm(P3, P1 *p256Point)
+// http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian.html#doubling-dbl-2007-bl
+// http://www.hyperelliptic.org/EFD/g1p/auto-shortw.html
+// http://www.hyperelliptic.org/EFD/g1p/auto-shortw-projective-3.html
+#define P3ptr R1
+#define P1ptr R2
+#define CPOOL R4
+
+// Temporaries in REGs
+#define X3L V15
+#define X3H V16
+#define Y3L V17
+#define Y3H V18
+#define T1L V19
+#define T1H V20
+#define T2L V21
+#define T2H V22
+#define T3L V23
+#define T3H V24
+
+#define X1L V6
+#define X1H V7
+#define Y1L V8
+#define Y1H V9
+#define Z1L V10
+#define Z1H V11
+
+// Temps for Sub and Add
+#define TT0 V11
+#define TT1 V12
+#define T2 V13
+
+// p256MulAsm Parameters
+#define X0 V0
+#define X1 V1
+#define Y0 V2
+#define Y1 V3
+#define T0 V4
+#define T1 V5
+
+#define PL V30
+#define PH V31
+
+#define Z3L V23
+#define Z3H V24
+
+#define ZER V26
+#define SEL1 V27
+#define CAR1 V28
+#define CAR2 V29
+/*
+ * http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2004-hmv
+ * Cost: 4M + 4S + 1*half + 5add + 2*2 + 1*3.
+ * Source: 2004 Hankerson–Menezes–Vanstone, page 91.
+ * A = 3(X₁-Z₁²)×(X₁+Z₁²)
+ * B = 2Y₁
+ * Z₃ = B×Z₁
+ * C = B²
+ * D = C×X₁
+ * X₃ = A²-2D
+ * Y₃ = (D-X₃)×A-C²/2
+ *
+ * Three-operand formula:
+ * T1 = Z1²
+ * T2 = X1-T1
+ * T1 = X1+T1
+ * T2 = T2*T1
+ * T2 = 3*T2
+ * Y3 = 2*Y1
+ * Z3 = Y3*Z1
+ * Y3 = Y3²
+ * T3 = Y3*X1
+ * Y3 = Y3²
+ * Y3 = half*Y3
+ * X3 = T2²
+ * T1 = 2*T3
+ * X3 = X3-T1
+ * T1 = T3-X3
+ * T1 = T1*T2
+ * Y3 = T1-Y3
+ */
+
+TEXT ·p256PointDoubleAsm(SB), NOSPLIT, $0
+ MOVD P3+0(FP), P3ptr
+ MOVD P1+8(FP), P1ptr
+
+ MOVD $p256mul<>+0x00(SB), CPOOL
+ VL 16(CPOOL), PL
+ VL 0(CPOOL), PH
+
+ // X=Z1; Y=Z1; MUL; T- // T1 = Z1²
+ VL 64(P1ptr), X1 // Z1H
+ VL 80(P1ptr), X0 // Z1L
+ VLR X0, Y0
+ VLR X1, Y1
+ CALL p256MulInternal<>(SB)
+
+ // SUB(X<X1-T) // T2 = X1-T1
+ VL 0(P1ptr), X1H
+ VL 16(P1ptr), X1L
+ p256SubInternal(X1,X0,X1H,X1L,T1,T0)
+
+ // ADD(Y<X1+T) // T1 = X1+T1
+ p256AddInternal(Y1,Y0,X1H,X1L,T1,T0)
+
+ // X- ; Y- ; MUL; T- // T2 = T2*T1
+ CALL p256MulInternal<>(SB)
+
+ // ADD(T2<T+T); ADD(T2<T2+T) // T2 = 3*T2
+ p256AddInternal(T2H,T2L,T1,T0,T1,T0)
+ p256AddInternal(T2H,T2L,T2H,T2L,T1,T0)
+
+ // ADD(X<Y1+Y1) // Y3 = 2*Y1
+ VL 32(P1ptr), Y1H
+ VL 48(P1ptr), Y1L
+ p256AddInternal(X1,X0,Y1H,Y1L,Y1H,Y1L)
+
+ // X- ; Y=Z1; MUL; Z3:=T // Z3 = Y3*Z1
+ VL 64(P1ptr), Y1 // Z1H
+ VL 80(P1ptr), Y0 // Z1L
+ CALL p256MulInternal<>(SB)
+ VST T1, 64(P3ptr)
+ VST T0, 80(P3ptr)
+
+ // X- ; Y=X ; MUL; T- // Y3 = Y3²
+ VLR X0, Y0
+ VLR X1, Y1
+ CALL p256MulInternal<>(SB)
+
+ // X=T ; Y=X1; MUL; T3=T // T3 = Y3*X1
+ VLR T0, X0
+ VLR T1, X1
+ VL 0(P1ptr), Y1
+ VL 16(P1ptr), Y0
+ CALL p256MulInternal<>(SB)
+ VLR T0, T3L
+ VLR T1, T3H
+
+ // X- ; Y=X ; MUL; T- // Y3 = Y3²
+ VLR X0, Y0
+ VLR X1, Y1
+ CALL p256MulInternal<>(SB)
+
+ // HAL(Y3<T) // Y3 = half*Y3
+ p256HalfInternal(Y3H,Y3L, T1,T0)
+
+ // X=T2; Y=T2; MUL; T- // X3 = T2²
+ VLR T2L, X0
+ VLR T2H, X1
+ VLR T2L, Y0
+ VLR T2H, Y1
+ CALL p256MulInternal<>(SB)
+
+ // ADD(T1<T3+T3) // T1 = 2*T3
+ p256AddInternal(T1H,T1L,T3H,T3L,T3H,T3L)
+
+ // SUB(X3<T-T1) X3:=X3 // X3 = X3-T1
+ p256SubInternal(X3H,X3L,T1,T0,T1H,T1L)
+ VST X3H, 0(P3ptr)
+ VST X3L, 16(P3ptr)
+
+ // SUB(X<T3-X3) // T1 = T3-X3
+ p256SubInternal(X1,X0,T3H,T3L,X3H,X3L)
+
+ // X- ; Y- ; MUL; T- // T1 = T1*T2
+ CALL p256MulInternal<>(SB)
+
+ // SUB(Y3<T-Y3) // Y3 = T1-Y3
+ p256SubInternal(Y3H,Y3L,T1,T0,Y3H,Y3L)
+
+ VST Y3H, 32(P3ptr)
+ VST Y3L, 48(P3ptr)
+ RET
+
+#undef P3ptr
+#undef P1ptr
+#undef CPOOL
+#undef X3L
+#undef X3H
+#undef Y3L
+#undef Y3H
+#undef T1L
+#undef T1H
+#undef T2L
+#undef T2H
+#undef T3L
+#undef T3H
+#undef X1L
+#undef X1H
+#undef Y1L
+#undef Y1H
+#undef Z1L
+#undef Z1H
+#undef TT0
+#undef TT1
+#undef T2
+#undef X0
+#undef X1
+#undef Y0
+#undef Y1
+#undef T0
+#undef T1
+#undef PL
+#undef PH
+#undef Z3L
+#undef Z3H
+#undef ZER
+#undef SEL1
+#undef CAR1
+#undef CAR2
+
+// p256PointAddAsm(P3, P1, P2 *p256Point)
+#define P3ptr R1
+#define P1ptr R2
+#define P2ptr R3
+#define CPOOL R4
+
+// Temporaries in REGs
+#define T1L V16
+#define T1H V17
+#define T2L V18
+#define T2H V19
+#define U1L V20
+#define U1H V21
+#define S1L V22
+#define S1H V23
+#define HL V24
+#define HH V25
+#define RL V26
+#define RH V27
+
+// Temps for Sub and Add
+#define ZER V6
+#define SEL1 V7
+#define CAR1 V8
+#define CAR2 V9
+#define TT0 V11
+#define TT1 V12
+#define T2 V13
+
+// p256MulAsm Parameters
+#define X0 V0
+#define X1 V1
+#define Y0 V2
+#define Y1 V3
+#define T0 V4
+#define T1 V5
+
+#define PL V30
+#define PH V31
+/*
+ * https://choucroutage.com/Papers/SideChannelAttacks/ctrsa-2011-brown.pdf "Software Implementation of the NIST Elliptic Curves Over Prime Fields"
+ *
+ * A = X₁×Z₂²
+ * B = Y₁×Z₂³
+ * C = X₂×Z₁²-A
+ * D = Y₂×Z₁³-B
+ * X₃ = D² - 2A×C² - C³
+ * Y₃ = D×(A×C² - X₃) - B×C³
+ * Z₃ = Z₁×Z₂×C
+ *
+ * Three-operand formula (adopted): http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-add-1998-cmo-2
+ * Temp storage: T1,T2,U1,H,Z3=X3=Y3,S1,R
+ *
+ * T1 = Z1*Z1
+ * T2 = Z2*Z2
+ * U1 = X1*T2
+ * H = X2*T1
+ * H = H-U1
+ * Z3 = Z1*Z2
+ * Z3 = Z3*H << store-out Z3 result reg.. could override Z1, if slices have same backing array
+ *
+ * S1 = Z2*T2
+ * S1 = Y1*S1
+ * R = Z1*T1
+ * R = Y2*R
+ * R = R-S1
+ *
+ * T1 = H*H
+ * T2 = H*T1
+ * U1 = U1*T1
+ *
+ * X3 = R*R
+ * X3 = X3-T2
+ * T1 = 2*U1
+ * X3 = X3-T1 << store-out X3 result reg
+ *
+ * T2 = S1*T2
+ * Y3 = U1-X3
+ * Y3 = R*Y3
+ * Y3 = Y3-T2 << store-out Y3 result reg
+
+ // X=Z1; Y=Z1; MUL; T- // T1 = Z1*Z1
+ // X- ; Y=T ; MUL; R=T // R = Z1*T1
+ // X=X2; Y- ; MUL; H=T // H = X2*T1
+ // X=Z2; Y=Z2; MUL; T- // T2 = Z2*Z2
+ // X- ; Y=T ; MUL; S1=T // S1 = Z2*T2
+ // X=X1; Y- ; MUL; U1=T // U1 = X1*T2
+ // SUB(H<H-T) // H = H-U1
+ // X=Z1; Y=Z2; MUL; T- // Z3 = Z1*Z2
+ // X=T ; Y=H ; MUL; Z3:=T// Z3 = Z3*H << store-out Z3 result reg.. could override Z1, if slices have same backing array
+ // X=Y1; Y=S1; MUL; S1=T // S1 = Y1*S1
+ // X=Y2; Y=R ; MUL; T- // R = Y2*R
+ // SUB(R<T-S1) // R = R-S1
+ // X=H ; Y=H ; MUL; T- // T1 = H*H
+ // X- ; Y=T ; MUL; T2=T // T2 = H*T1
+ // X=U1; Y- ; MUL; U1=T // U1 = U1*T1
+ // X=R ; Y=R ; MUL; T- // X3 = R*R
+ // SUB(T<T-T2) // X3 = X3-T2
+ // ADD(X<U1+U1) // T1 = 2*U1
+ // SUB(T<T-X) X3:=T // X3 = X3-T1 << store-out X3 result reg
+ // SUB(Y<U1-T) // Y3 = U1-X3
+ // X=R ; Y- ; MUL; U1=T // Y3 = R*Y3
+ // X=S1; Y=T2; MUL; T- // T2 = S1*T2
+ // SUB(T<U1-T); Y3:=T // Y3 = Y3-T2 << store-out Y3 result reg
+ */
+TEXT ·p256PointAddAsm(SB), NOSPLIT, $0
+ MOVD P3+0(FP), P3ptr
+ MOVD P1+8(FP), P1ptr
+ MOVD P2+16(FP), P2ptr
+
+ MOVD $p256mul<>+0x00(SB), CPOOL
+ VL 16(CPOOL), PL
+ VL 0(CPOOL), PH
+
+ // X=Z1; Y=Z1; MUL; T- // T1 = Z1*Z1
+ VL 64(P1ptr), X1 // Z1H
+ VL 80(P1ptr), X0 // Z1L
+ VLR X0, Y0
+ VLR X1, Y1
+ CALL p256MulInternal<>(SB)
+
+ // X- ; Y=T ; MUL; R=T // R = Z1*T1
+ VLR T0, Y0
+ VLR T1, Y1
+ CALL p256MulInternal<>(SB)
+ VLR T0, RL
+ VLR T1, RH
+
+ // X=X2; Y- ; MUL; H=T // H = X2*T1
+ VL 0(P2ptr), X1 // X2H
+ VL 16(P2ptr), X0 // X2L
+ CALL p256MulInternal<>(SB)
+ VLR T0, HL
+ VLR T1, HH
+
+ // X=Z2; Y=Z2; MUL; T- // T2 = Z2*Z2
+ VL 64(P2ptr), X1 // Z2H
+ VL 80(P2ptr), X0 // Z2L
+ VLR X0, Y0
+ VLR X1, Y1
+ CALL p256MulInternal<>(SB)
+
+ // X- ; Y=T ; MUL; S1=T // S1 = Z2*T2
+ VLR T0, Y0
+ VLR T1, Y1
+ CALL p256MulInternal<>(SB)
+ VLR T0, S1L
+ VLR T1, S1H
+
+ // X=X1; Y- ; MUL; U1=T // U1 = X1*T2
+ VL 0(P1ptr), X1 // X1H
+ VL 16(P1ptr), X0 // X1L
+ CALL p256MulInternal<>(SB)
+ VLR T0, U1L
+ VLR T1, U1H
+
+ // SUB(H<H-T) // H = H-U1
+ p256SubInternal(HH,HL,HH,HL,T1,T0)
+
+ // X=Z1; Y=Z2; MUL; T- // Z3 = Z1*Z2
+ VL 64(P1ptr), X1 // Z1H
+ VL 80(P1ptr), X0 // Z1L
+ VL 64(P2ptr), Y1 // Z2H
+ VL 80(P2ptr), Y0 // Z2L
+ CALL p256MulInternal<>(SB)
+
+ // X=T ; Y=H ; MUL; Z3:=T// Z3 = Z3*H
+ VLR T0, X0
+ VLR T1, X1
+ VLR HL, Y0
+ VLR HH, Y1
+ CALL p256MulInternal<>(SB)
+ VST T1, 64(P3ptr)
+ VST T0, 80(P3ptr)
+
+ // X=Y1; Y=S1; MUL; S1=T // S1 = Y1*S1
+ VL 32(P1ptr), X1
+ VL 48(P1ptr), X0
+ VLR S1L, Y0
+ VLR S1H, Y1
+ CALL p256MulInternal<>(SB)
+ VLR T0, S1L
+ VLR T1, S1H
+
+ // X=Y2; Y=R ; MUL; T- // R = Y2*R
+ VL 32(P2ptr), X1
+ VL 48(P2ptr), X0
+ VLR RL, Y0
+ VLR RH, Y1
+ CALL p256MulInternal<>(SB)
+
+ // SUB(R<T-S1) // R = T-S1
+ p256SubInternal(RH,RL,T1,T0,S1H,S1L)
+
+ // X=H ; Y=H ; MUL; T- // T1 = H*H
+ VLR HL, X0
+ VLR HH, X1
+ VLR HL, Y0
+ VLR HH, Y1
+ CALL p256MulInternal<>(SB)
+
+ // X- ; Y=T ; MUL; T2=T // T2 = H*T1
+ VLR T0, Y0
+ VLR T1, Y1
+ CALL p256MulInternal<>(SB)
+ VLR T0, T2L
+ VLR T1, T2H
+
+ // X=U1; Y- ; MUL; U1=T // U1 = U1*T1
+ VLR U1L, X0
+ VLR U1H, X1
+ CALL p256MulInternal<>(SB)
+ VLR T0, U1L
+ VLR T1, U1H
+
+ // X=R ; Y=R ; MUL; T- // X3 = R*R
+ VLR RL, X0
+ VLR RH, X1
+ VLR RL, Y0
+ VLR RH, Y1
+ CALL p256MulInternal<>(SB)
+
+ // SUB(T<T-T2) // X3 = X3-T2
+ p256SubInternal(T1,T0,T1,T0,T2H,T2L)
+
+ // ADD(X<U1+U1) // T1 = 2*U1
+ p256AddInternal(X1,X0,U1H,U1L,U1H,U1L)
+
+ // SUB(T<T-X) X3:=T // X3 = X3-T1 << store-out X3 result reg
+ p256SubInternal(T1,T0,T1,T0,X1,X0)
+ VST T1, 0(P3ptr)
+ VST T0, 16(P3ptr)
+
+ // SUB(Y<U1-T) // Y3 = U1-X3
+ p256SubInternal(Y1,Y0,U1H,U1L,T1,T0)
+
+ // X=R ; Y- ; MUL; U1=T // Y3 = R*Y3
+ VLR RL, X0
+ VLR RH, X1
+ CALL p256MulInternal<>(SB)
+ VLR T0, U1L
+ VLR T1, U1H
+
+ // X=S1; Y=T2; MUL; T- // T2 = S1*T2
+ VLR S1L, X0
+ VLR S1H, X1
+ VLR T2L, Y0
+ VLR T2H, Y1
+ CALL p256MulInternal<>(SB)
+
+ // SUB(T<U1-T); Y3:=T // Y3 = Y3-T2 << store-out Y3 result reg
+ p256SubInternal(T1,T0,U1H,U1L,T1,T0)
+ VST T1, 32(P3ptr)
+ VST T0, 48(P3ptr)
+
+ RET
diff --git a/src/crypto/elliptic/p256_generic.go b/src/crypto/elliptic/p256_generic.go
new file mode 100644
index 0000000..9963fca
--- /dev/null
+++ b/src/crypto/elliptic/p256_generic.go
@@ -0,0 +1,16 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !amd64,!s390x
+
+package elliptic
+
+var (
+ p256 p256Curve
+)
+
+func initP256Arch() {
+ // Use pure Go implementation.
+ p256 = p256Curve{p256Params}
+}
diff --git a/src/crypto/elliptic/p256_s390x.go b/src/crypto/elliptic/p256_s390x.go
new file mode 100644
index 0000000..2ed4c0b
--- /dev/null
+++ b/src/crypto/elliptic/p256_s390x.go
@@ -0,0 +1,513 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build s390x
+
+package elliptic
+
+import (
+ "math/big"
+)
+
+type p256CurveFast struct {
+ *CurveParams
+}
+
+type p256Point struct {
+ x [32]byte
+ y [32]byte
+ z [32]byte
+}
+
+var (
+ p256 Curve
+ p256PreFast *[37][64]p256Point
+)
+
+// hasVectorFacility reports whether the machine has the z/Architecture
+// vector facility installed and enabled.
+func hasVectorFacility() bool
+
+var hasVX = hasVectorFacility()
+
+func initP256Arch() {
+ if hasVX {
+ p256 = p256CurveFast{p256Params}
+ initTable()
+ return
+ }
+
+ // No vector support, use pure Go implementation.
+ p256 = p256Curve{p256Params}
+ return
+}
+
+func (curve p256CurveFast) Params() *CurveParams {
+ return curve.CurveParams
+}
+
+// Functions implemented in p256_asm_s390x.s
+// Montgomery multiplication modulo P256
+func p256MulAsm(res, in1, in2 []byte)
+
+// Montgomery square modulo P256
+func p256Sqr(res, in []byte) {
+ p256MulAsm(res, in, in)
+}
+
+// Montgomery multiplication by 1
+func p256FromMont(res, in []byte)
+
+// iff cond == 1 val <- -val
+func p256NegCond(val *p256Point, cond int)
+
+// if cond == 0 res <- b; else res <- a
+func p256MovCond(res, a, b *p256Point, cond int)
+
+// Constant time table access
+func p256Select(point *p256Point, table []p256Point, idx int)
+func p256SelectBase(point *p256Point, table []p256Point, idx int)
+
+// Montgomery multiplication modulo Ord(G)
+func p256OrdMul(res, in1, in2 []byte)
+
+// Montgomery square modulo Ord(G), repeated n times
+func p256OrdSqr(res, in []byte, n int) {
+ copy(res, in)
+ for i := 0; i < n; i += 1 {
+ p256OrdMul(res, res, res)
+ }
+}
+
+// Point add with P2 being affine point
+// If sign == 1 -> P2 = -P2
+// If sel == 0 -> P3 = P1
+// if zero == 0 -> P3 = P2
+func p256PointAddAffineAsm(P3, P1, P2 *p256Point, sign, sel, zero int)
+
+// Point add
+func p256PointAddAsm(P3, P1, P2 *p256Point)
+func p256PointDoubleAsm(P3, P1 *p256Point)
+
+func (curve p256CurveFast) Inverse(k *big.Int) *big.Int {
+ if k.Cmp(p256Params.N) >= 0 {
+ // This should never happen.
+ reducedK := new(big.Int).Mod(k, p256Params.N)
+ k = reducedK
+ }
+
+ // table will store precomputed powers of x. The 32 bytes at index
+ // i store x^(i+1).
+ var table [15][32]byte
+
+ x := fromBig(k)
+ // This code operates in the Montgomery domain where R = 2^256 mod n
+ // and n is the order of the scalar field. (See initP256 for the
+ // value.) Elements in the Montgomery domain take the form a×R and
+ // multiplication of x and y in the calculates (x × y × R^-1) mod n. RR
+ // is R×R mod n thus the Montgomery multiplication x and RR gives x×R,
+ // i.e. converts x into the Montgomery domain. Stored in BigEndian form
+ RR := []byte{0x66, 0xe1, 0x2d, 0x94, 0xf3, 0xd9, 0x56, 0x20, 0x28, 0x45, 0xb2, 0x39, 0x2b, 0x6b, 0xec, 0x59,
+ 0x46, 0x99, 0x79, 0x9c, 0x49, 0xbd, 0x6f, 0xa6, 0x83, 0x24, 0x4c, 0x95, 0xbe, 0x79, 0xee, 0xa2}
+
+ p256OrdMul(table[0][:], x, RR)
+
+ // Prepare the table, no need in constant time access, because the
+ // power is not a secret. (Entry 0 is never used.)
+ for i := 2; i < 16; i += 2 {
+ p256OrdSqr(table[i-1][:], table[(i/2)-1][:], 1)
+ p256OrdMul(table[i][:], table[i-1][:], table[0][:])
+ }
+
+ copy(x, table[14][:]) // f
+
+ p256OrdSqr(x[0:32], x[0:32], 4)
+ p256OrdMul(x[0:32], x[0:32], table[14][:]) // ff
+ t := make([]byte, 32)
+ copy(t, x)
+
+ p256OrdSqr(x, x, 8)
+ p256OrdMul(x, x, t) // ffff
+ copy(t, x)
+
+ p256OrdSqr(x, x, 16)
+ p256OrdMul(x, x, t) // ffffffff
+ copy(t, x)
+
+ p256OrdSqr(x, x, 64) // ffffffff0000000000000000
+ p256OrdMul(x, x, t) // ffffffff00000000ffffffff
+ p256OrdSqr(x, x, 32) // ffffffff00000000ffffffff00000000
+ p256OrdMul(x, x, t) // ffffffff00000000ffffffffffffffff
+
+ // Remaining 32 windows
+ expLo := [32]byte{0xb, 0xc, 0xe, 0x6, 0xf, 0xa, 0xa, 0xd, 0xa, 0x7, 0x1, 0x7, 0x9, 0xe, 0x8, 0x4,
+ 0xf, 0x3, 0xb, 0x9, 0xc, 0xa, 0xc, 0x2, 0xf, 0xc, 0x6, 0x3, 0x2, 0x5, 0x4, 0xf}
+ for i := 0; i < 32; i++ {
+ p256OrdSqr(x, x, 4)
+ p256OrdMul(x, x, table[expLo[i]-1][:])
+ }
+
+ // Multiplying by one in the Montgomery domain converts a Montgomery
+ // value out of the domain.
+ one := []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}
+ p256OrdMul(x, x, one)
+
+ return new(big.Int).SetBytes(x)
+}
+
+// fromBig converts a *big.Int into a format used by this code.
+func fromBig(big *big.Int) []byte {
+ // This could be done a lot more efficiently...
+ res := big.Bytes()
+ if 32 == len(res) {
+ return res
+ }
+ t := make([]byte, 32)
+ offset := 32 - len(res)
+ for i := len(res) - 1; i >= 0; i-- {
+ t[i+offset] = res[i]
+ }
+ return t
+}
+
+// p256GetMultiplier makes sure byte array will have 32 byte elements, If the scalar
+// is equal or greater than the order of the group, it's reduced modulo that order.
+func p256GetMultiplier(in []byte) []byte {
+ n := new(big.Int).SetBytes(in)
+
+ if n.Cmp(p256Params.N) >= 0 {
+ n.Mod(n, p256Params.N)
+ }
+ return fromBig(n)
+}
+
+// p256MulAsm operates in a Montgomery domain with R = 2^256 mod p, where p is the
+// underlying field of the curve. (See initP256 for the value.) Thus rr here is
+// R×R mod p. See comment in Inverse about how this is used.
+var rr = []byte{0x00, 0x00, 0x00, 0x04, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe,
+ 0xff, 0xff, 0xff, 0xfb, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03}
+
+// (This is one, in the Montgomery domain.)
+var one = []byte{0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}
+
+func maybeReduceModP(in *big.Int) *big.Int {
+ if in.Cmp(p256Params.P) < 0 {
+ return in
+ }
+ return new(big.Int).Mod(in, p256Params.P)
+}
+
+func (curve p256CurveFast) CombinedMult(bigX, bigY *big.Int, baseScalar, scalar []byte) (x, y *big.Int) {
+ var r1, r2 p256Point
+ r1.p256BaseMult(p256GetMultiplier(baseScalar))
+
+ copy(r2.x[:], fromBig(maybeReduceModP(bigX)))
+ copy(r2.y[:], fromBig(maybeReduceModP(bigY)))
+ copy(r2.z[:], one)
+ p256MulAsm(r2.x[:], r2.x[:], rr[:])
+ p256MulAsm(r2.y[:], r2.y[:], rr[:])
+
+ r2.p256ScalarMult(p256GetMultiplier(scalar))
+ p256PointAddAsm(&r1, &r1, &r2)
+ return r1.p256PointToAffine()
+}
+
+func (curve p256CurveFast) ScalarBaseMult(scalar []byte) (x, y *big.Int) {
+ var r p256Point
+ r.p256BaseMult(p256GetMultiplier(scalar))
+ return r.p256PointToAffine()
+}
+
+func (curve p256CurveFast) ScalarMult(bigX, bigY *big.Int, scalar []byte) (x, y *big.Int) {
+ var r p256Point
+ copy(r.x[:], fromBig(maybeReduceModP(bigX)))
+ copy(r.y[:], fromBig(maybeReduceModP(bigY)))
+ copy(r.z[:], one)
+ p256MulAsm(r.x[:], r.x[:], rr[:])
+ p256MulAsm(r.y[:], r.y[:], rr[:])
+ r.p256ScalarMult(p256GetMultiplier(scalar))
+ return r.p256PointToAffine()
+}
+
+func (p *p256Point) p256PointToAffine() (x, y *big.Int) {
+ zInv := make([]byte, 32)
+ zInvSq := make([]byte, 32)
+
+ p256Inverse(zInv, p.z[:])
+ p256Sqr(zInvSq, zInv)
+ p256MulAsm(zInv, zInv, zInvSq)
+
+ p256MulAsm(zInvSq, p.x[:], zInvSq)
+ p256MulAsm(zInv, p.y[:], zInv)
+
+ p256FromMont(zInvSq, zInvSq)
+ p256FromMont(zInv, zInv)
+
+ return new(big.Int).SetBytes(zInvSq), new(big.Int).SetBytes(zInv)
+}
+
+// p256Inverse sets out to in^-1 mod p.
+func p256Inverse(out, in []byte) {
+ var stack [6 * 32]byte
+ p2 := stack[32*0 : 32*0+32]
+ p4 := stack[32*1 : 32*1+32]
+ p8 := stack[32*2 : 32*2+32]
+ p16 := stack[32*3 : 32*3+32]
+ p32 := stack[32*4 : 32*4+32]
+
+ p256Sqr(out, in)
+ p256MulAsm(p2, out, in) // 3*p
+
+ p256Sqr(out, p2)
+ p256Sqr(out, out)
+ p256MulAsm(p4, out, p2) // f*p
+
+ p256Sqr(out, p4)
+ p256Sqr(out, out)
+ p256Sqr(out, out)
+ p256Sqr(out, out)
+ p256MulAsm(p8, out, p4) // ff*p
+
+ p256Sqr(out, p8)
+
+ for i := 0; i < 7; i++ {
+ p256Sqr(out, out)
+ }
+ p256MulAsm(p16, out, p8) // ffff*p
+
+ p256Sqr(out, p16)
+ for i := 0; i < 15; i++ {
+ p256Sqr(out, out)
+ }
+ p256MulAsm(p32, out, p16) // ffffffff*p
+
+ p256Sqr(out, p32)
+
+ for i := 0; i < 31; i++ {
+ p256Sqr(out, out)
+ }
+ p256MulAsm(out, out, in)
+
+ for i := 0; i < 32*4; i++ {
+ p256Sqr(out, out)
+ }
+ p256MulAsm(out, out, p32)
+
+ for i := 0; i < 32; i++ {
+ p256Sqr(out, out)
+ }
+ p256MulAsm(out, out, p32)
+
+ for i := 0; i < 16; i++ {
+ p256Sqr(out, out)
+ }
+ p256MulAsm(out, out, p16)
+
+ for i := 0; i < 8; i++ {
+ p256Sqr(out, out)
+ }
+ p256MulAsm(out, out, p8)
+
+ p256Sqr(out, out)
+ p256Sqr(out, out)
+ p256Sqr(out, out)
+ p256Sqr(out, out)
+ p256MulAsm(out, out, p4)
+
+ p256Sqr(out, out)
+ p256Sqr(out, out)
+ p256MulAsm(out, out, p2)
+
+ p256Sqr(out, out)
+ p256Sqr(out, out)
+ p256MulAsm(out, out, in)
+}
+
+func boothW5(in uint) (int, int) {
+ var s uint = ^((in >> 5) - 1)
+ var d uint = (1 << 6) - in - 1
+ d = (d & s) | (in & (^s))
+ d = (d >> 1) + (d & 1)
+ return int(d), int(s & 1)
+}
+
+func boothW7(in uint) (int, int) {
+ var s uint = ^((in >> 7) - 1)
+ var d uint = (1 << 8) - in - 1
+ d = (d & s) | (in & (^s))
+ d = (d >> 1) + (d & 1)
+ return int(d), int(s & 1)
+}
+
+func initTable() {
+ p256PreFast = new([37][64]p256Point) //z coordinate not used
+ basePoint := p256Point{
+ x: [32]byte{0x18, 0x90, 0x5f, 0x76, 0xa5, 0x37, 0x55, 0xc6, 0x79, 0xfb, 0x73, 0x2b, 0x77, 0x62, 0x25, 0x10,
+ 0x75, 0xba, 0x95, 0xfc, 0x5f, 0xed, 0xb6, 0x01, 0x79, 0xe7, 0x30, 0xd4, 0x18, 0xa9, 0x14, 0x3c}, //(p256.x*2^256)%p
+ y: [32]byte{0x85, 0x71, 0xff, 0x18, 0x25, 0x88, 0x5d, 0x85, 0xd2, 0xe8, 0x86, 0x88, 0xdd, 0x21, 0xf3, 0x25,
+ 0x8b, 0x4a, 0xb8, 0xe4, 0xba, 0x19, 0xe4, 0x5c, 0xdd, 0xf2, 0x53, 0x57, 0xce, 0x95, 0x56, 0x0a}, //(p256.y*2^256)%p
+ z: [32]byte{0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, //(p256.z*2^256)%p
+ }
+
+ t1 := new(p256Point)
+ t2 := new(p256Point)
+ *t2 = basePoint
+
+ zInv := make([]byte, 32)
+ zInvSq := make([]byte, 32)
+ for j := 0; j < 64; j++ {
+ *t1 = *t2
+ for i := 0; i < 37; i++ {
+ // The window size is 7 so we need to double 7 times.
+ if i != 0 {
+ for k := 0; k < 7; k++ {
+ p256PointDoubleAsm(t1, t1)
+ }
+ }
+ // Convert the point to affine form. (Its values are
+ // still in Montgomery form however.)
+ p256Inverse(zInv, t1.z[:])
+ p256Sqr(zInvSq, zInv)
+ p256MulAsm(zInv, zInv, zInvSq)
+
+ p256MulAsm(t1.x[:], t1.x[:], zInvSq)
+ p256MulAsm(t1.y[:], t1.y[:], zInv)
+
+ copy(t1.z[:], basePoint.z[:])
+ // Update the table entry
+ copy(p256PreFast[i][j].x[:], t1.x[:])
+ copy(p256PreFast[i][j].y[:], t1.y[:])
+ }
+ if j == 0 {
+ p256PointDoubleAsm(t2, &basePoint)
+ } else {
+ p256PointAddAsm(t2, t2, &basePoint)
+ }
+ }
+}
+
+func (p *p256Point) p256BaseMult(scalar []byte) {
+ wvalue := (uint(scalar[31]) << 1) & 0xff
+ sel, sign := boothW7(uint(wvalue))
+ p256SelectBase(p, p256PreFast[0][:], sel)
+ p256NegCond(p, sign)
+
+ copy(p.z[:], one[:])
+ var t0 p256Point
+
+ copy(t0.z[:], one[:])
+
+ index := uint(6)
+ zero := sel
+
+ for i := 1; i < 37; i++ {
+ if index < 247 {
+ wvalue = ((uint(scalar[31-index/8]) >> (index % 8)) + (uint(scalar[31-index/8-1]) << (8 - (index % 8)))) & 0xff
+ } else {
+ wvalue = (uint(scalar[31-index/8]) >> (index % 8)) & 0xff
+ }
+ index += 7
+ sel, sign = boothW7(uint(wvalue))
+ p256SelectBase(&t0, p256PreFast[i][:], sel)
+ p256PointAddAffineAsm(p, p, &t0, sign, sel, zero)
+ zero |= sel
+ }
+}
+
+func (p *p256Point) p256ScalarMult(scalar []byte) {
+ // precomp is a table of precomputed points that stores powers of p
+ // from p^1 to p^16.
+ var precomp [16]p256Point
+ var t0, t1, t2, t3 p256Point
+
+ // Prepare the table
+ *&precomp[0] = *p
+
+ p256PointDoubleAsm(&t0, p)
+ p256PointDoubleAsm(&t1, &t0)
+ p256PointDoubleAsm(&t2, &t1)
+ p256PointDoubleAsm(&t3, &t2)
+ *&precomp[1] = t0 // 2
+ *&precomp[3] = t1 // 4
+ *&precomp[7] = t2 // 8
+ *&precomp[15] = t3 // 16
+
+ p256PointAddAsm(&t0, &t0, p)
+ p256PointAddAsm(&t1, &t1, p)
+ p256PointAddAsm(&t2, &t2, p)
+ *&precomp[2] = t0 // 3
+ *&precomp[4] = t1 // 5
+ *&precomp[8] = t2 // 9
+
+ p256PointDoubleAsm(&t0, &t0)
+ p256PointDoubleAsm(&t1, &t1)
+ *&precomp[5] = t0 // 6
+ *&precomp[9] = t1 // 10
+
+ p256PointAddAsm(&t2, &t0, p)
+ p256PointAddAsm(&t1, &t1, p)
+ *&precomp[6] = t2 // 7
+ *&precomp[10] = t1 // 11
+
+ p256PointDoubleAsm(&t0, &t0)
+ p256PointDoubleAsm(&t2, &t2)
+ *&precomp[11] = t0 // 12
+ *&precomp[13] = t2 // 14
+
+ p256PointAddAsm(&t0, &t0, p)
+ p256PointAddAsm(&t2, &t2, p)
+ *&precomp[12] = t0 // 13
+ *&precomp[14] = t2 // 15
+
+ // Start scanning the window from top bit
+ index := uint(254)
+ var sel, sign int
+
+ wvalue := (uint(scalar[31-index/8]) >> (index % 8)) & 0x3f
+ sel, _ = boothW5(uint(wvalue))
+ p256Select(p, precomp[:], sel)
+ zero := sel
+
+ for index > 4 {
+ index -= 5
+ p256PointDoubleAsm(p, p)
+ p256PointDoubleAsm(p, p)
+ p256PointDoubleAsm(p, p)
+ p256PointDoubleAsm(p, p)
+ p256PointDoubleAsm(p, p)
+
+ if index < 247 {
+ wvalue = ((uint(scalar[31-index/8]) >> (index % 8)) + (uint(scalar[31-index/8-1]) << (8 - (index % 8)))) & 0x3f
+ } else {
+ wvalue = (uint(scalar[31-index/8]) >> (index % 8)) & 0x3f
+ }
+
+ sel, sign = boothW5(uint(wvalue))
+
+ p256Select(&t0, precomp[:], sel)
+ p256NegCond(&t0, sign)
+ p256PointAddAsm(&t1, p, &t0)
+ p256MovCond(&t1, &t1, p, sel)
+ p256MovCond(p, &t1, &t0, zero)
+ zero |= sel
+ }
+
+ p256PointDoubleAsm(p, p)
+ p256PointDoubleAsm(p, p)
+ p256PointDoubleAsm(p, p)
+ p256PointDoubleAsm(p, p)
+ p256PointDoubleAsm(p, p)
+
+ wvalue = (uint(scalar[31]) << 1) & 0x3f
+ sel, sign = boothW5(uint(wvalue))
+
+ p256Select(&t0, precomp[:], sel)
+ p256NegCond(&t0, sign)
+ p256PointAddAsm(&t1, p, &t0)
+ p256MovCond(&t1, &t1, p, sel)
+ p256MovCond(p, &t1, &t0, zero)
+}
diff --git a/src/crypto/hmac/hmac.go b/src/crypto/hmac/hmac.go
index a748107..9ef9c44 100644
--- a/src/crypto/hmac/hmac.go
+++ b/src/crypto/hmac/hmac.go
@@ -94,5 +94,5 @@ func Equal(mac1, mac2 []byte) bool {
// We don't have to be constant time if the lengths of the MACs are
// different as that suggests that a completely different hash function
// was used.
- return len(mac1) == len(mac2) && subtle.ConstantTimeCompare(mac1, mac2) == 1
+ return subtle.ConstantTimeCompare(mac1, mac2) == 1
}
diff --git a/src/crypto/internal/cipherhw/asm_amd64.s b/src/crypto/internal/cipherhw/asm_amd64.s
new file mode 100644
index 0000000..dd1afd4
--- /dev/null
+++ b/src/crypto/internal/cipherhw/asm_amd64.s
@@ -0,0 +1,17 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build amd64,!gccgo,!appengine
+
+#include "textflag.h"
+
+// func hasAESNI() bool
+TEXT ·hasAESNI(SB),NOSPLIT,$0
+ XORQ AX, AX
+ INCL AX
+ CPUID
+ SHRQ $25, CX
+ ANDQ $1, CX
+ MOVB CX, ret+0(FP)
+ RET
diff --git a/src/crypto/internal/cipherhw/asm_s390x.s b/src/crypto/internal/cipherhw/asm_s390x.s
new file mode 100644
index 0000000..51dc1c6
--- /dev/null
+++ b/src/crypto/internal/cipherhw/asm_s390x.s
@@ -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.
+
+// +build s390x,!gccgo,!appengine
+
+#include "textflag.h"
+
+// func hasHWSupport() bool
+TEXT ·hasHWSupport(SB),NOSPLIT,$16-1
+ XOR R0, R0 // set function code to 0 (query)
+ LA mask-16(SP), R1 // 16-byte stack variable for mask
+ MOVD $(0x38<<40), R3 // mask for bits 18-20 (big endian)
+
+ // check for KM AES functions
+ WORD $0xB92E0024 // cipher message (KM)
+ MOVD mask-16(SP), R2
+ AND R3, R2
+ CMPBNE R2, R3, notfound
+
+ // check for KMC AES functions
+ WORD $0xB92F0024 // cipher message with chaining (KMC)
+ MOVD mask-16(SP), R2
+ AND R3, R2
+ CMPBNE R2, R3, notfound
+
+ // check for KMCTR AES functions
+ WORD $0xB92D4024 // cipher message with counter (KMCTR)
+ MOVD mask-16(SP), R2
+ AND R3, R2
+ CMPBNE R2, R3, notfound
+
+ // check for KIMD GHASH function
+ WORD $0xB93E0024 // compute intermediate message digest (KIMD)
+ MOVD mask-8(SP), R2 // bits 64-127
+ MOVD $(1<<62), R5
+ AND R5, R2
+ CMPBNE R2, R5, notfound
+
+ MOVB $1, ret+0(FP)
+ RET
+notfound:
+ MOVB $0, ret+0(FP)
+ RET
diff --git a/src/crypto/internal/cipherhw/cipherhw_amd64.go b/src/crypto/internal/cipherhw/cipherhw_amd64.go
new file mode 100644
index 0000000..be0d490
--- /dev/null
+++ b/src/crypto/internal/cipherhw/cipherhw_amd64.go
@@ -0,0 +1,16 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build amd64,!gccgo,!appengine
+
+package cipherhw
+
+// defined in asm_amd64.s
+func hasAESNI() bool
+
+// AESGCMSupport returns true if the Go standard library supports AES-GCM in
+// hardware.
+func AESGCMSupport() bool {
+ return hasAESNI()
+}
diff --git a/src/crypto/internal/cipherhw/cipherhw_s390x.go b/src/crypto/internal/cipherhw/cipherhw_s390x.go
new file mode 100644
index 0000000..9cd7679
--- /dev/null
+++ b/src/crypto/internal/cipherhw/cipherhw_s390x.go
@@ -0,0 +1,18 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build s390x,!gccgo,!appengine
+
+package cipherhw
+
+// hasHWSupport reports whether the AES-128, AES-192 and AES-256 cipher message
+// (KM) function codes are supported. Note that this function is expensive.
+// defined in asm_s390x.s
+func hasHWSupport() bool
+
+var hwSupport = hasHWSupport()
+
+func AESGCMSupport() bool {
+ return hwSupport
+}
diff --git a/src/crypto/internal/cipherhw/doc.go b/src/crypto/internal/cipherhw/doc.go
new file mode 100644
index 0000000..a75fcf6
--- /dev/null
+++ b/src/crypto/internal/cipherhw/doc.go
@@ -0,0 +1,7 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package cipherhw exposes common functions for detecting whether hardware
+// support for certain ciphers and authenticators is present.
+package cipherhw
diff --git a/src/crypto/internal/cipherhw/generic.go b/src/crypto/internal/cipherhw/generic.go
new file mode 100644
index 0000000..64d90d3
--- /dev/null
+++ b/src/crypto/internal/cipherhw/generic.go
@@ -0,0 +1,11 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !amd64,!s390x gccgo appengine
+
+package cipherhw
+
+func AESGCMSupport() bool {
+ return false
+}
diff --git a/src/crypto/md5/example_test.go b/src/crypto/md5/example_test.go
index d47bb45..af8c1bf 100644
--- a/src/crypto/md5/example_test.go
+++ b/src/crypto/md5/example_test.go
@@ -8,6 +8,8 @@ import (
"crypto/md5"
"fmt"
"io"
+ "log"
+ "os"
)
func ExampleNew() {
@@ -23,3 +25,18 @@ func ExampleSum() {
fmt.Printf("%x", md5.Sum(data))
// Output: b0804ec967f48520697662a204f5fe72
}
+
+func ExampleNew_file() {
+ f, err := os.Open("file.txt")
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer f.Close()
+
+ h := md5.New()
+ if _, err := io.Copy(h, f); err != nil {
+ log.Fatal(err)
+ }
+
+ fmt.Printf("%x", h.Sum(nil))
+}
diff --git a/src/crypto/md5/md5block_amd64p32.s b/src/crypto/md5/md5block_amd64p32.s
index d918a67..ee05f86 100644
--- a/src/crypto/md5/md5block_amd64p32.s
+++ b/src/crypto/md5/md5block_amd64p32.s
@@ -17,7 +17,7 @@
// Licence: I hereby disclaim the copyright on this code and place it
// in the public domain.
-TEXT ·block(SB),NOSPLIT,$0-32
+TEXT ·block(SB),NOSPLIT,$0-16
MOVL dig+0(FP), R11
MOVL p+4(FP), SI
MOVL p_len+8(FP), DX
diff --git a/src/crypto/rand/util_test.go b/src/crypto/rand/util_test.go
index 7b07689..48a2c3f 100644
--- a/src/crypto/rand/util_test.go
+++ b/src/crypto/rand/util_test.go
@@ -7,7 +7,9 @@ package rand_test
import (
"crypto/rand"
"math/big"
+ mathrand "math/rand"
"testing"
+ "time"
)
// https://golang.org/issue/6849.
@@ -63,3 +65,10 @@ func TestIntNegativeMaxPanics(t *testing.T) {
b := new(big.Int).SetInt64(int64(-1))
testIntPanics(t, b)
}
+
+func BenchmarkPrime(b *testing.B) {
+ r := mathrand.New(mathrand.NewSource(time.Now().UnixNano()))
+ for i := 0; i < b.N; i++ {
+ rand.Prime(r, 1024)
+ }
+}
diff --git a/src/crypto/rc4/rc4_arm.s b/src/crypto/rc4/rc4_arm.s
index 05e94cb..c726d6d 100644
--- a/src/crypto/rc4/rc4_arm.s
+++ b/src/crypto/rc4/rc4_arm.s
@@ -25,8 +25,8 @@ TEXT ·xorKeyStream(SB),NOSPLIT,$0
MOVW src+4(FP), Rsrc
MOVW n+8(FP), Rn
MOVW state+12(FP), Rstate
- MOVW pi+16(FP), Rpi
- MOVW pj+20(FP), Rpj
+ MOVW i+16(FP), Rpi
+ MOVW j+20(FP), Rpj
MOVBU (Rpi), Ri
MOVBU (Rpj), Rj
MOVW $0, Rk
diff --git a/src/crypto/rsa/rsa.go b/src/crypto/rsa/rsa.go
index 5943056..f809a9b 100644
--- a/src/crypto/rsa/rsa.go
+++ b/src/crypto/rsa/rsa.go
@@ -27,6 +27,7 @@ import (
"errors"
"hash"
"io"
+ "math"
"math/big"
)
@@ -214,6 +215,21 @@ func GenerateMultiPrimeKey(random io.Reader, nprimes int, bits int) (*PrivateKey
return nil, errors.New("crypto/rsa: GenerateMultiPrimeKey: nprimes must be >= 2")
}
+ if bits < 64 {
+ primeLimit := float64(uint64(1) << uint(bits/nprimes))
+ // pi approximates the number of primes less than primeLimit
+ pi := primeLimit / (math.Log(primeLimit) - 1)
+ // Generated primes start with 11 (in binary) so we can only
+ // use a quarter of them.
+ pi /= 4
+ // Use a factor of two to ensure that key generation terminates
+ // in a reasonable amount of time.
+ pi /= 2
+ if pi <= float64(nprimes) {
+ return nil, errors.New("crypto/rsa: too few primes of given length to generate an RSA key")
+ }
+ }
+
primes := make([]*big.Int, nprimes)
NextSetOfPrimes:
@@ -268,9 +284,8 @@ NextSetOfPrimes:
g := new(big.Int)
priv.D = new(big.Int)
- y := new(big.Int)
e := big.NewInt(int64(priv.E))
- g.GCD(priv.D, y, e, totient)
+ g.GCD(priv.D, nil, e, totient)
if g.Cmp(bigOne) == 0 {
if priv.D.Sign() < 0 {
@@ -347,8 +362,8 @@ func encrypt(c *big.Int, pub *PublicKey, m *big.Int) *big.Int {
// values could be used to ensure that a ciphertext for one purpose cannot be
// used for another by an attacker. If not required it can be empty.
//
-// The message must be no longer than the length of the public modulus less
-// twice the hash length plus 2.
+// The message must be no longer than the length of the public modulus minus
+// twice the hash length, minus a further 2.
func EncryptOAEP(hash hash.Hash, random io.Reader, pub *PublicKey, msg []byte, label []byte) ([]byte, error) {
if err := checkPub(pub); err != nil {
return nil, err
diff --git a/src/crypto/rsa/rsa_test.go b/src/crypto/rsa/rsa_test.go
index 6902f9a..84b1674 100644
--- a/src/crypto/rsa/rsa_test.go
+++ b/src/crypto/rsa/rsa_test.go
@@ -73,6 +73,17 @@ func TestNPrimeKeyGeneration(t *testing.T) {
}
}
+func TestImpossibleKeyGeneration(t *testing.T) {
+ // This test ensures that trying to generate toy RSA keys doesn't enter
+ // an infinite loop.
+ for i := 0; i < 32; i++ {
+ GenerateKey(rand.Reader, i)
+ GenerateMultiPrimeKey(rand.Reader, 3, i)
+ GenerateMultiPrimeKey(rand.Reader, 4, i)
+ GenerateMultiPrimeKey(rand.Reader, 5, i)
+ }
+}
+
func TestGnuTLSKey(t *testing.T) {
// This is a key generated by `certtool --generate-privkey --bits 128`.
// It's such that de ≢ 1 mod φ(n), but is congruent mod the order of
diff --git a/src/crypto/sha1/example_test.go b/src/crypto/sha1/example_test.go
index 42aec8a..499055c 100644
--- a/src/crypto/sha1/example_test.go
+++ b/src/crypto/sha1/example_test.go
@@ -8,6 +8,8 @@ import (
"crypto/sha1"
"fmt"
"io"
+ "log"
+ "os"
)
func ExampleNew() {
@@ -23,3 +25,18 @@ func ExampleSum() {
fmt.Printf("% x", sha1.Sum(data))
// Output: af 06 49 23 bb f2 30 15 96 aa c4 c2 73 ba 32 17 8e bc 4a 96
}
+
+func ExampleNew_file() {
+ f, err := os.Open("file.txt")
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer f.Close()
+
+ h := sha1.New()
+ if _, err := io.Copy(h, f); err != nil {
+ log.Fatal(err)
+ }
+
+ fmt.Printf("% x", h.Sum(nil))
+}
diff --git a/src/crypto/sha1/sha1.go b/src/crypto/sha1/sha1.go
index ac593b1..fbb2f94 100644
--- a/src/crypto/sha1/sha1.go
+++ b/src/crypto/sha1/sha1.go
@@ -90,7 +90,7 @@ func (d0 *digest) Sum(in []byte) []byte {
func (d *digest) checkSum() [Size]byte {
len := d.len
- // Padding. Add a 1 bit and 0 bits until 56 bytes mod 64.
+ // Padding. Add a 1 bit and 0 bits until 56 bytes mod 64.
var tmp [64]byte
tmp[0] = 0x80
if len%64 < 56 {
@@ -121,6 +121,74 @@ func (d *digest) checkSum() [Size]byte {
return digest
}
+// ConstantTimeSum computes the same result of Sum() but in constant time
+func (d0 *digest) ConstantTimeSum(in []byte) []byte {
+ d := *d0
+ hash := d.constSum()
+ return append(in, hash[:]...)
+}
+
+func (d *digest) constSum() [Size]byte {
+ var length [8]byte
+ l := d.len << 3
+ for i := uint(0); i < 8; i++ {
+ length[i] = byte(l >> (56 - 8*i))
+ }
+
+ nx := byte(d.nx)
+ t := nx - 56 // if nx < 56 then the MSB of t is one
+ mask1b := byte(int8(t) >> 7) // mask1b is 0xFF iff one block is enough
+
+ separator := byte(0x80) // gets reset to 0x00 once used
+ for i := byte(0); i < chunk; i++ {
+ mask := byte(int8(i-nx) >> 7) // 0x00 after the end of data
+
+ // if we reached the end of the data, replace with 0x80 or 0x00
+ d.x[i] = (^mask & separator) | (mask & d.x[i])
+
+ // zero the separator once used
+ separator &= mask
+
+ if i >= 56 {
+ // we might have to write the length here if all fit in one block
+ d.x[i] |= mask1b & length[i-56]
+ }
+ }
+
+ // compress, and only keep the digest if all fit in one block
+ block(d, d.x[:])
+
+ var digest [Size]byte
+ for i, s := range d.h {
+ digest[i*4] = mask1b & byte(s>>24)
+ digest[i*4+1] = mask1b & byte(s>>16)
+ digest[i*4+2] = mask1b & byte(s>>8)
+ digest[i*4+3] = mask1b & byte(s)
+ }
+
+ for i := byte(0); i < chunk; i++ {
+ // second block, it's always past the end of data, might start with 0x80
+ if i < 56 {
+ d.x[i] = separator
+ separator = 0
+ } else {
+ d.x[i] = length[i-56]
+ }
+ }
+
+ // compress, and only keep the digest if we actually needed the second block
+ block(d, d.x[:])
+
+ for i, s := range d.h {
+ digest[i*4] |= ^mask1b & byte(s>>24)
+ digest[i*4+1] |= ^mask1b & byte(s>>16)
+ digest[i*4+2] |= ^mask1b & byte(s>>8)
+ digest[i*4+3] |= ^mask1b & byte(s)
+ }
+
+ return digest
+}
+
// Sum returns the SHA1 checksum of the data.
func Sum(data []byte) [Size]byte {
var d digest
diff --git a/src/crypto/sha1/sha1_test.go b/src/crypto/sha1/sha1_test.go
index 214afc5..3e59a5d 100644
--- a/src/crypto/sha1/sha1_test.go
+++ b/src/crypto/sha1/sha1_test.go
@@ -61,15 +61,24 @@ func TestGolden(t *testing.T) {
t.Fatalf("Sum function: sha1(%s) = %s want %s", g.in, s, g.out)
}
c := New()
- for j := 0; j < 3; j++ {
- if j < 2 {
+ for j := 0; j < 4; j++ {
+ var sum []byte
+ switch j {
+ case 0, 1:
io.WriteString(c, g.in)
- } else {
+ sum = c.Sum(nil)
+ case 2:
io.WriteString(c, g.in[0:len(g.in)/2])
c.Sum(nil)
io.WriteString(c, g.in[len(g.in)/2:])
+ sum = c.Sum(nil)
+ case 3:
+ io.WriteString(c, g.in[0:len(g.in)/2])
+ c.(*digest).ConstantTimeSum(nil)
+ io.WriteString(c, g.in[len(g.in)/2:])
+ sum = c.(*digest).ConstantTimeSum(nil)
}
- s := fmt.Sprintf("%x", c.Sum(nil))
+ s := fmt.Sprintf("%x", sum)
if s != g.out {
t.Fatalf("sha1[%d](%s) = %s want %s", j, g.in, s, g.out)
}
diff --git a/src/crypto/sha1/sha1block_amd64.go b/src/crypto/sha1/sha1block_amd64.go
index fd85a42..0320e41 100644
--- a/src/crypto/sha1/sha1block_amd64.go
+++ b/src/crypto/sha1/sha1block_amd64.go
@@ -1,4 +1,4 @@
-// Copyright 2016 The Go Authors. All rights reserved.
+// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
diff --git a/src/crypto/sha1/sha1block_amd64p32.s b/src/crypto/sha1/sha1block_amd64p32.s
index efebbf0..0159d23 100644
--- a/src/crypto/sha1/sha1block_amd64p32.s
+++ b/src/crypto/sha1/sha1block_amd64p32.s
@@ -91,7 +91,7 @@
FUNC4(a, b, c, d, e); \
MIX(a, b, c, d, e, 0xCA62C1D6)
-TEXT ·block(SB),NOSPLIT,$64-32
+TEXT ·block(SB),NOSPLIT,$64-16
MOVL dig+0(FP), R14
MOVL p_base+4(FP), SI
MOVL p_len+8(FP), DX
diff --git a/src/crypto/sha256/example_test.go b/src/crypto/sha256/example_test.go
new file mode 100644
index 0000000..7d73120
--- /dev/null
+++ b/src/crypto/sha256/example_test.go
@@ -0,0 +1,41 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package sha256_test
+
+import (
+ "crypto/sha256"
+ "fmt"
+ "io"
+ "log"
+ "os"
+)
+
+func ExampleSum256() {
+ sum := sha256.Sum256([]byte("hello world\n"))
+ fmt.Printf("%x", sum)
+ // Output: a948904f2f0f479b8f8197694b30184b0d2ed1c1cd2a1ec0fb85d299a192a447
+}
+
+func ExampleNew() {
+ h := sha256.New()
+ h.Write([]byte("hello world\n"))
+ fmt.Printf("%x", h.Sum(nil))
+ // Output: a948904f2f0f479b8f8197694b30184b0d2ed1c1cd2a1ec0fb85d299a192a447
+}
+
+func ExampleNew_file() {
+ f, err := os.Open("file.txt")
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer f.Close()
+
+ h := sha256.New()
+ if _, err := io.Copy(h, f); err != nil {
+ log.Fatal(err)
+ }
+
+ fmt.Printf("%x", h.Sum(nil))
+}
diff --git a/src/crypto/sha256/sha256block_386.s b/src/crypto/sha256/sha256block_386.s
index e0353c3..33ed027 100644
--- a/src/crypto/sha256/sha256block_386.s
+++ b/src/crypto/sha256/sha256block_386.s
@@ -141,7 +141,7 @@
MSGSCHEDULE1(index); \
SHA256ROUND(index, const, a, b, c, d, e, f, g, h)
-TEXT ·block(SB),0,$296-12
+TEXT ·block(SB),0,$296-16
MOVL p_base+4(FP), SI
MOVL p_len+8(FP), DX
SHRL $6, DX
diff --git a/src/crypto/sha256/sha256block_amd64.s b/src/crypto/sha256/sha256block_amd64.s
index 6ab3b52..edf7ad1 100644
--- a/src/crypto/sha256/sha256block_amd64.s
+++ b/src/crypto/sha256/sha256block_amd64.s
@@ -1,4 +1,4 @@
-// Copyright 2013 The Go Authors. All rights reserved.
+// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
@@ -302,7 +302,7 @@
ADDL y0, y2; \ // y2 = S1 + CH // --
; \
VPXOR XTMP4, XTMP3, XTMP1; \ // XTMP1 = s0
- VPSHUFD $-6, XDWORD3, XTMP2; \ // XTMP2 = W[-2] {BBAA}
+ VPSHUFD $0xFA, XDWORD3, XTMP2; \ // XTMP2 = W[-2] {BBAA}
ORL T1, y3; \ // y3 = MAJ = (a|c)&b)|(a&c) // MAJ
ADDL y1, h; \ // h = k + w + h + S0 // --
; \
diff --git a/src/crypto/sha256/sha256block_decl.go b/src/crypto/sha256/sha256block_decl.go
index e6caff9..fe07e53 100644
--- a/src/crypto/sha256/sha256block_decl.go
+++ b/src/crypto/sha256/sha256block_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 386 amd64 s390x
+// +build 386 amd64 s390x ppc64le
package sha256
diff --git a/src/crypto/sha256/sha256block_generic.go b/src/crypto/sha256/sha256block_generic.go
index 1a01969..a182a5e 100644
--- a/src/crypto/sha256/sha256block_generic.go
+++ b/src/crypto/sha256/sha256block_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,!386,!s390x
+// +build !amd64,!386,!s390x,!ppc64le
package sha256
diff --git a/src/crypto/sha256/sha256block_ppc64le.s b/src/crypto/sha256/sha256block_ppc64le.s
new file mode 100644
index 0000000..7ac5000
--- /dev/null
+++ b/src/crypto/sha256/sha256block_ppc64le.s
@@ -0,0 +1,269 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "textflag.h"
+
+// SHA256 block routine. See sha256block.go for Go equivalent.
+//
+// The algorithm is detailed in FIPS 180-4:
+//
+// http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf
+//
+// Wt = Mt; for 0 <= t <= 15
+// Wt = SIGMA1(Wt-2) + SIGMA0(Wt-15) + Wt-16; for 16 <= t <= 63
+//
+// a = H0
+// b = H1
+// c = H2
+// d = H3
+// e = H4
+// f = H5
+// g = H6
+// h = H7
+//
+// for t = 0 to 63 {
+// T1 = h + BIGSIGMA1(e) + Ch(e,f,g) + Kt + Wt
+// T2 = BIGSIGMA0(a) + Maj(a,b,c)
+// h = g
+// g = f
+// f = e
+// e = d + T1
+// d = c
+// c = b
+// b = a
+// a = T1 + T2
+// }
+//
+// H0 = a + H0
+// H1 = b + H1
+// H2 = c + H2
+// H3 = d + H3
+// H4 = e + H4
+// H5 = f + H5
+// 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)
+
+// 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
+
+ ADD R26, R29, R28
+
+ MOVD R28, 256(R1)
+ CMP R26, R28
+ 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
+
+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
+ BLT loop
+
+end:
+ RET
diff --git a/src/crypto/sha512/sha512block_decl.go b/src/crypto/sha512/sha512block_decl.go
index 47d656a..8194506 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
+// +build amd64 s390x ppc64le
package sha512
diff --git a/src/crypto/sha512/sha512block_generic.go b/src/crypto/sha512/sha512block_generic.go
index 2c691ba..08f2e07 100644
--- a/src/crypto/sha512/sha512block_generic.go
+++ b/src/crypto/sha512/sha512block_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 sha512
diff --git a/src/crypto/sha512/sha512block_ppc64le.s b/src/crypto/sha512/sha512block_ppc64le.s
new file mode 100644
index 0000000..7b338d8
--- /dev/null
+++ b/src/crypto/sha512/sha512block_ppc64le.s
@@ -0,0 +1,293 @@
+// Copyright 2016 The Go 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"
+
+// SHA512 block routine. See sha512block.go for Go equivalent.
+//
+// The algorithm is detailed in FIPS 180-4:
+//
+// http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf
+//
+// Wt = Mt; for 0 <= t <= 15
+// Wt = SIGMA1(Wt-2) + SIGMA0(Wt-15) + Wt-16; for 16 <= t <= 79
+//
+// a = H0
+// b = H1
+// c = H2
+// d = H3
+// e = H4
+// f = H5
+// g = H6
+// h = H7
+//
+// for t = 0 to 79 {
+// T1 = h + BIGSIGMA1(e) + Ch(e,f,g) + Kt + Wt
+// T2 = BIGSIGMA0(a) + Maj(a,b,c)
+// h = g
+// g = f
+// f = e
+// e = d + T1
+// d = c
+// c = b
+// b = a
+// a = T1 + T2
+// }
+//
+// H0 = a + H0
+// H1 = b + H1
+// H2 = c + H2
+// H3 = d + H3
+// H4 = e + H4
+// H5 = f + H5
+// 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)
+
+// 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
+
+// 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
+
+// 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
+
+#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 SHA512ROUND1(index, const, a, b, c, d, e, f, g, h) \
+ MSGSCHEDULE1(index); \
+ SHA512ROUND(index, const, a, b, c, d, e, f, g, h)
+
+// 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
+
+ ADD R6, R7, R8
+ MOVD R8, 640(R1)
+ CMP R6, R8
+ 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
+
+loop:
+ MOVD R1, R9 // R9: message schedule
+
+ 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)
+
+ 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)
+
+ 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)
+
+ ADD $128, R6
+ MOVD 640(R1), R21
+ CMPU R6, R21
+ BLT loop
+
+end:
+ RET
diff --git a/src/crypto/tls/alert.go b/src/crypto/tls/alert.go
index 9cf9922..4929868 100644
--- a/src/crypto/tls/alert.go
+++ b/src/crypto/tls/alert.go
@@ -38,6 +38,7 @@ const (
alertInappropriateFallback alert = 86
alertUserCanceled alert = 90
alertNoRenegotiation alert = 100
+ alertNoApplicationProtocol alert = 120
)
var alertText = map[alert]string{
@@ -64,6 +65,7 @@ var alertText = map[alert]string{
alertInappropriateFallback: "inappropriate fallback",
alertUserCanceled: "user canceled",
alertNoRenegotiation: "no renegotiation",
+ alertNoApplicationProtocol: "no application protocol",
}
func (e alert) String() string {
diff --git a/src/crypto/tls/cipher_suites.go b/src/crypto/tls/cipher_suites.go
index e69f5f9..0514674 100644
--- a/src/crypto/tls/cipher_suites.go
+++ b/src/crypto/tls/cipher_suites.go
@@ -11,8 +11,11 @@ import (
"crypto/hmac"
"crypto/rc4"
"crypto/sha1"
+ "crypto/sha256"
"crypto/x509"
"hash"
+
+ "golang_org/x/crypto/chacha20poly1305"
)
// a keyAgreement implements the client and server side of a TLS key agreement
@@ -73,25 +76,32 @@ type cipherSuite struct {
}
var cipherSuites = []*cipherSuite{
- // Ciphersuite order is chosen so that ECDHE comes before plain RSA
- // and RC4 comes before AES-CBC (because of the Lucky13 attack).
+ // Ciphersuite order is chosen so that ECDHE comes before plain RSA and
+ // AEADs are the top preference.
+ {TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305, 32, 0, 12, ecdheRSAKA, suiteECDHE | suiteTLS12, nil, nil, aeadChaCha20Poly1305},
+ {TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305, 32, 0, 12, ecdheECDSAKA, suiteECDHE | suiteECDSA | suiteTLS12, nil, nil, aeadChaCha20Poly1305},
{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, 16, 0, 4, ecdheRSAKA, suiteECDHE | suiteTLS12, nil, nil, aeadAESGCM},
{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, 16, 0, 4, ecdheECDSAKA, suiteECDHE | suiteECDSA | suiteTLS12, nil, nil, aeadAESGCM},
{TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, 32, 0, 4, ecdheRSAKA, suiteECDHE | suiteTLS12 | suiteSHA384, nil, nil, aeadAESGCM},
{TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, 32, 0, 4, ecdheECDSAKA, suiteECDHE | suiteECDSA | suiteTLS12 | suiteSHA384, nil, nil, aeadAESGCM},
- {TLS_ECDHE_RSA_WITH_RC4_128_SHA, 16, 20, 0, ecdheRSAKA, suiteECDHE | suiteDefaultOff, cipherRC4, macSHA1, nil},
- {TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, 16, 20, 0, ecdheECDSAKA, suiteECDHE | suiteECDSA | suiteDefaultOff, cipherRC4, macSHA1, nil},
+ {TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, 16, 32, 16, ecdheRSAKA, suiteECDHE | suiteTLS12, cipherAES, macSHA256, nil},
{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, 16, 20, 16, ecdheRSAKA, suiteECDHE, cipherAES, macSHA1, nil},
+ {TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, 16, 32, 16, ecdheECDSAKA, suiteECDHE | suiteECDSA | suiteTLS12, cipherAES, macSHA256, nil},
{TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, 16, 20, 16, ecdheECDSAKA, suiteECDHE | suiteECDSA, cipherAES, macSHA1, nil},
{TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, 32, 20, 16, ecdheRSAKA, suiteECDHE, cipherAES, macSHA1, nil},
{TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, 32, 20, 16, ecdheECDSAKA, suiteECDHE | suiteECDSA, cipherAES, macSHA1, nil},
{TLS_RSA_WITH_AES_128_GCM_SHA256, 16, 0, 4, rsaKA, suiteTLS12, nil, nil, aeadAESGCM},
{TLS_RSA_WITH_AES_256_GCM_SHA384, 32, 0, 4, rsaKA, suiteTLS12 | suiteSHA384, nil, nil, aeadAESGCM},
- {TLS_RSA_WITH_RC4_128_SHA, 16, 20, 0, rsaKA, suiteDefaultOff, cipherRC4, macSHA1, nil},
+ {TLS_RSA_WITH_AES_128_CBC_SHA256, 16, 32, 16, rsaKA, suiteTLS12, cipherAES, macSHA256, nil},
{TLS_RSA_WITH_AES_128_CBC_SHA, 16, 20, 16, rsaKA, 0, cipherAES, macSHA1, nil},
{TLS_RSA_WITH_AES_256_CBC_SHA, 32, 20, 16, rsaKA, 0, cipherAES, macSHA1, nil},
{TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, 24, 20, 8, ecdheRSAKA, suiteECDHE, cipher3DES, macSHA1, nil},
{TLS_RSA_WITH_3DES_EDE_CBC_SHA, 24, 20, 8, rsaKA, 0, cipher3DES, macSHA1, nil},
+
+ // RC4-based cipher suites are disabled by default.
+ {TLS_RSA_WITH_RC4_128_SHA, 16, 20, 0, rsaKA, suiteDefaultOff, cipherRC4, macSHA1, nil},
+ {TLS_ECDHE_RSA_WITH_RC4_128_SHA, 16, 20, 0, ecdheRSAKA, suiteECDHE | suiteDefaultOff, cipherRC4, macSHA1, nil},
+ {TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, 16, 20, 0, ecdheECDSAKA, suiteECDHE | suiteECDSA | suiteDefaultOff, cipherRC4, macSHA1, nil},
}
func cipherRC4(key, iv []byte, isRead bool) interface{} {
@@ -125,35 +135,84 @@ func macSHA1(version uint16, key []byte) macFunction {
copy(mac.key, key)
return mac
}
- return tls10MAC{hmac.New(sha1.New, key)}
+ return tls10MAC{hmac.New(newConstantTimeHash(sha1.New), key)}
+}
+
+// macSHA256 returns a SHA-256 based MAC. These are only supported in TLS 1.2
+// so the given version is ignored.
+func macSHA256(version uint16, key []byte) macFunction {
+ return tls10MAC{hmac.New(sha256.New, key)}
}
type macFunction interface {
Size() int
- MAC(digestBuf, seq, header, data []byte) []byte
+ MAC(digestBuf, seq, header, data, extra []byte) []byte
+}
+
+type aead interface {
+ cipher.AEAD
+
+ // explicitIVLen returns the number of bytes used by the explicit nonce
+ // that is included in the record. This is eight for older AEADs and
+ // zero for modern ones.
+ explicitNonceLen() int
}
// fixedNonceAEAD wraps an AEAD and prefixes a fixed portion of the nonce to
// each call.
type fixedNonceAEAD struct {
- // sealNonce and openNonce are buffers where the larger nonce will be
- // constructed. Since a seal and open operation may be running
- // concurrently, there is a separate buffer for each.
- sealNonce, openNonce []byte
- aead cipher.AEAD
+ // nonce contains the fixed part of the nonce in the first four bytes.
+ nonce [12]byte
+ aead cipher.AEAD
}
-func (f *fixedNonceAEAD) NonceSize() int { return 8 }
-func (f *fixedNonceAEAD) Overhead() int { return f.aead.Overhead() }
+func (f *fixedNonceAEAD) NonceSize() int { return 8 }
+func (f *fixedNonceAEAD) Overhead() int { return f.aead.Overhead() }
+func (f *fixedNonceAEAD) explicitNonceLen() int { return 8 }
func (f *fixedNonceAEAD) Seal(out, nonce, plaintext, additionalData []byte) []byte {
- copy(f.sealNonce[len(f.sealNonce)-8:], nonce)
- return f.aead.Seal(out, f.sealNonce, plaintext, additionalData)
+ copy(f.nonce[4:], nonce)
+ return f.aead.Seal(out, f.nonce[:], plaintext, additionalData)
}
func (f *fixedNonceAEAD) Open(out, nonce, plaintext, additionalData []byte) ([]byte, error) {
- copy(f.openNonce[len(f.openNonce)-8:], nonce)
- return f.aead.Open(out, f.openNonce, plaintext, additionalData)
+ copy(f.nonce[4:], nonce)
+ return f.aead.Open(out, f.nonce[:], plaintext, additionalData)
+}
+
+// xoredNonceAEAD wraps an AEAD by XORing in a fixed pattern to the nonce
+// before each call.
+type xorNonceAEAD struct {
+ nonceMask [12]byte
+ aead cipher.AEAD
+}
+
+func (f *xorNonceAEAD) NonceSize() int { return 8 }
+func (f *xorNonceAEAD) Overhead() int { return f.aead.Overhead() }
+func (f *xorNonceAEAD) explicitNonceLen() int { return 0 }
+
+func (f *xorNonceAEAD) Seal(out, nonce, plaintext, additionalData []byte) []byte {
+ for i, b := range nonce {
+ f.nonceMask[4+i] ^= b
+ }
+ result := f.aead.Seal(out, f.nonceMask[:], plaintext, additionalData)
+ for i, b := range nonce {
+ f.nonceMask[4+i] ^= b
+ }
+
+ return result
+}
+
+func (f *xorNonceAEAD) Open(out, nonce, plaintext, additionalData []byte) ([]byte, error) {
+ for i, b := range nonce {
+ f.nonceMask[4+i] ^= b
+ }
+ result, err := f.aead.Open(out, f.nonceMask[:], plaintext, additionalData)
+ for i, b := range nonce {
+ f.nonceMask[4+i] ^= b
+ }
+
+ return result, err
}
func aeadAESGCM(key, fixedNonce []byte) cipher.AEAD {
@@ -166,11 +225,20 @@ func aeadAESGCM(key, fixedNonce []byte) cipher.AEAD {
panic(err)
}
- nonce1, nonce2 := make([]byte, 12), make([]byte, 12)
- copy(nonce1, fixedNonce)
- copy(nonce2, fixedNonce)
+ ret := &fixedNonceAEAD{aead: aead}
+ copy(ret.nonce[:], fixedNonce)
+ return ret
+}
+
+func aeadChaCha20Poly1305(key, fixedNonce []byte) cipher.AEAD {
+ aead, err := chacha20poly1305.New(key)
+ if err != nil {
+ panic(err)
+ }
- return &fixedNonceAEAD{nonce1, nonce2, aead}
+ ret := &xorNonceAEAD{aead: aead}
+ copy(ret.nonceMask[:], fixedNonce)
+ return ret
}
// ssl30MAC implements the SSLv3 MAC function, as defined in
@@ -188,7 +256,9 @@ var ssl30Pad1 = [48]byte{0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0
var ssl30Pad2 = [48]byte{0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c}
-func (s ssl30MAC) MAC(digestBuf, seq, header, data []byte) []byte {
+// MAC does not offer constant timing guarantees for SSL v3.0, since it's deemed
+// useless considering the similar, protocol-level POODLE vulnerability.
+func (s ssl30MAC) MAC(digestBuf, seq, header, data, extra []byte) []byte {
padLength := 48
if s.h.Size() == 20 {
padLength = 40
@@ -210,6 +280,29 @@ func (s ssl30MAC) MAC(digestBuf, seq, header, data []byte) []byte {
return s.h.Sum(digestBuf[:0])
}
+type constantTimeHash interface {
+ hash.Hash
+ ConstantTimeSum(b []byte) []byte
+}
+
+// cthWrapper wraps any hash.Hash that implements ConstantTimeSum, and replaces
+// with that all calls to Sum. It's used to obtain a ConstantTimeSum-based HMAC.
+type cthWrapper struct {
+ h constantTimeHash
+}
+
+func (c *cthWrapper) Size() int { return c.h.Size() }
+func (c *cthWrapper) BlockSize() int { return c.h.BlockSize() }
+func (c *cthWrapper) Reset() { c.h.Reset() }
+func (c *cthWrapper) Write(p []byte) (int, error) { return c.h.Write(p) }
+func (c *cthWrapper) Sum(b []byte) []byte { return c.h.ConstantTimeSum(b) }
+
+func newConstantTimeHash(h func() hash.Hash) func() hash.Hash {
+ return func() hash.Hash {
+ return &cthWrapper{h().(constantTimeHash)}
+ }
+}
+
// tls10MAC implements the TLS 1.0 MAC function. RFC 2246, section 6.2.3.
type tls10MAC struct {
h hash.Hash
@@ -219,12 +312,19 @@ func (s tls10MAC) Size() int {
return s.h.Size()
}
-func (s tls10MAC) MAC(digestBuf, seq, header, data []byte) []byte {
+// MAC is guaranteed to take constant time, as long as
+// len(seq)+len(header)+len(data)+len(extra) is constant. extra is not fed into
+// the MAC, but is only provided to make the timing profile constant.
+func (s tls10MAC) MAC(digestBuf, seq, header, data, extra []byte) []byte {
s.h.Reset()
s.h.Write(seq)
s.h.Write(header)
s.h.Write(data)
- return s.h.Sum(digestBuf[:0])
+ res := s.h.Sum(digestBuf[:0])
+ if extra != nil {
+ s.h.Write(extra)
+ }
+ return res
}
func rsaKA(version uint16) keyAgreement {
@@ -270,6 +370,7 @@ const (
TLS_RSA_WITH_3DES_EDE_CBC_SHA uint16 = 0x000a
TLS_RSA_WITH_AES_128_CBC_SHA uint16 = 0x002f
TLS_RSA_WITH_AES_256_CBC_SHA uint16 = 0x0035
+ TLS_RSA_WITH_AES_128_CBC_SHA256 uint16 = 0x003c
TLS_RSA_WITH_AES_128_GCM_SHA256 uint16 = 0x009c
TLS_RSA_WITH_AES_256_GCM_SHA384 uint16 = 0x009d
TLS_ECDHE_ECDSA_WITH_RC4_128_SHA uint16 = 0xc007
@@ -279,10 +380,14 @@ const (
TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA uint16 = 0xc012
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA uint16 = 0xc013
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA uint16 = 0xc014
+ TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 uint16 = 0xc023
+ TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 uint16 = 0xc027
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 uint16 = 0xc02f
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 uint16 = 0xc02b
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 uint16 = 0xc030
TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 uint16 = 0xc02c
+ TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305 uint16 = 0xcca8
+ TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305 uint16 = 0xcca9
// TLS_FALLBACK_SCSV isn't a standard cipher suite but an indicator
// that the client is doing version fallback. See
diff --git a/src/crypto/tls/common.go b/src/crypto/tls/common.go
index 9fc7420..276d176 100644
--- a/src/crypto/tls/common.go
+++ b/src/crypto/tls/common.go
@@ -7,6 +7,7 @@ package tls
import (
"container/list"
"crypto"
+ "crypto/internal/cipherhw"
"crypto/rand"
"crypto/sha512"
"crypto/x509"
@@ -14,6 +15,7 @@ import (
"fmt"
"io"
"math/big"
+ "net"
"strings"
"sync"
"time"
@@ -95,6 +97,7 @@ const (
CurveP256 CurveID = 23
CurveP384 CurveID = 24
CurveP521 CurveID = 25
+ X25519 CurveID = 29
)
// TLS Elliptic Curve Point Formats
@@ -213,6 +216,25 @@ type ClientSessionCache interface {
Put(sessionKey string, cs *ClientSessionState)
}
+// SignatureScheme identifies a signature algorithm supported by TLS. See
+// https://tools.ietf.org/html/draft-ietf-tls-tls13-18#section-4.2.3.
+type SignatureScheme uint16
+
+const (
+ PKCS1WithSHA1 SignatureScheme = 0x0201
+ PKCS1WithSHA256 SignatureScheme = 0x0401
+ PKCS1WithSHA384 SignatureScheme = 0x0501
+ PKCS1WithSHA512 SignatureScheme = 0x0601
+
+ PSSWithSHA256 SignatureScheme = 0x0804
+ PSSWithSHA384 SignatureScheme = 0x0805
+ PSSWithSHA512 SignatureScheme = 0x0806
+
+ ECDSAWithP256AndSHA256 SignatureScheme = 0x0403
+ ECDSAWithP384AndSHA384 SignatureScheme = 0x0503
+ ECDSAWithP521AndSHA512 SignatureScheme = 0x0603
+)
+
// ClientHelloInfo contains information from a ClientHello message in order to
// guide certificate selection in the GetCertificate callback.
type ClientHelloInfo struct {
@@ -237,6 +259,47 @@ type ClientHelloInfo struct {
// is being used (see
// http://tools.ietf.org/html/rfc4492#section-5.1.2).
SupportedPoints []uint8
+
+ // SignatureSchemes lists the signature and hash schemes that the client
+ // is willing to verify. SignatureSchemes is set only if the Signature
+ // Algorithms Extension is being used (see
+ // https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1).
+ SignatureSchemes []SignatureScheme
+
+ // SupportedProtos lists the application protocols supported by the client.
+ // SupportedProtos is set only if the Application-Layer Protocol
+ // Negotiation Extension is being used (see
+ // https://tools.ietf.org/html/rfc7301#section-3.1).
+ //
+ // Servers can select a protocol by setting Config.NextProtos in a
+ // GetConfigForClient return value.
+ SupportedProtos []string
+
+ // SupportedVersions lists the TLS versions supported by the client.
+ // For TLS versions less than 1.3, this is extrapolated from the max
+ // version advertised by the client, so values other than the greatest
+ // might be rejected if used.
+ SupportedVersions []uint16
+
+ // Conn is the underlying net.Conn for the connection. Do not read
+ // from, or write to, this connection; that will cause the TLS
+ // connection to fail.
+ Conn net.Conn
+}
+
+// CertificateRequestInfo contains information from a server's
+// CertificateRequest message, which is used to demand a certificate and proof
+// of control from a client.
+type CertificateRequestInfo struct {
+ // AcceptableCAs contains zero or more, DER-encoded, X.501
+ // Distinguished Names. These are the names of root or intermediate CAs
+ // that the server wishes the returned certificate to be signed by. An
+ // empty slice indicates that the server has no preference.
+ AcceptableCAs [][]byte
+
+ // SignatureSchemes lists the signature schemes that the server is
+ // willing to verify.
+ SignatureSchemes []SignatureScheme
}
// RenegotiationSupport enumerates the different levels of support for TLS
@@ -281,10 +344,11 @@ type Config struct {
// If Time is nil, TLS uses time.Now.
Time func() time.Time
- // Certificates contains one or more certificate chains
- // to present to the other side of the connection.
- // Server configurations must include at least one certificate
- // or else set GetCertificate.
+ // Certificates contains one or more certificate chains to present to
+ // the other side of the connection. Server configurations must include
+ // at least one certificate or else set GetCertificate. Clients doing
+ // client-authentication may set either Certificates or
+ // GetClientCertificate.
Certificates []Certificate
// NameToCertificate maps from a certificate name to an element of
@@ -302,7 +366,54 @@ type Config struct {
// If GetCertificate is nil or returns nil, then the certificate is
// retrieved from NameToCertificate. If NameToCertificate is nil, the
// first element of Certificates will be used.
- GetCertificate func(clientHello *ClientHelloInfo) (*Certificate, error)
+ GetCertificate func(*ClientHelloInfo) (*Certificate, error)
+
+ // GetClientCertificate, if not nil, is called when a server requests a
+ // certificate from a client. If set, the contents of Certificates will
+ // be ignored.
+ //
+ // If GetClientCertificate returns an error, the handshake will be
+ // aborted and that error will be returned. Otherwise
+ // GetClientCertificate must return a non-nil Certificate. If
+ // Certificate.Certificate is empty then no certificate will be sent to
+ // the server. If this is unacceptable to the server then it may abort
+ // the handshake.
+ //
+ // GetClientCertificate may be called multiple times for the same
+ // connection if renegotiation occurs or if TLS 1.3 is in use.
+ GetClientCertificate func(*CertificateRequestInfo) (*Certificate, error)
+
+ // GetConfigForClient, if not nil, is called after a ClientHello is
+ // received from a client. It may return a non-nil Config in order to
+ // change the Config that will be used to handle this connection. If
+ // the returned Config is nil, the original Config will be used. The
+ // Config returned by this callback may not be subsequently modified.
+ //
+ // If GetConfigForClient is nil, the Config passed to Server() will be
+ // used for all connections.
+ //
+ // Uniquely for the fields in the returned Config, session ticket keys
+ // will be duplicated from the original Config if not set.
+ // Specifically, if SetSessionTicketKeys was called on the original
+ // config but not on the returned config then the ticket keys from the
+ // original config will be copied into the new config before use.
+ // Otherwise, if SessionTicketKey was set in the original config but
+ // not in the returned config then it will be copied into the returned
+ // config before use. If neither of those cases applies then the key
+ // material from the returned config will be used for session tickets.
+ GetConfigForClient func(*ClientHelloInfo) (*Config, error)
+
+ // VerifyPeerCertificate, if not nil, is called after normal
+ // certificate verification by either a TLS client or server. It
+ // receives the raw ASN.1 certificates provided by the peer and also
+ // any verified chains that normal processing found. If it returns a
+ // non-nil error, the handshake is aborted and that error results.
+ //
+ // If normal verification fails then the handshake will abort before
+ // considering this callback. If normal verification is disabled by
+ // setting InsecureSkipVerify then this callback will be considered but
+ // the verifiedChains argument will always be nil.
+ VerifyPeerCertificate func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error
// RootCAs defines the set of root certificate authorities
// that clients use when verifying server certificates.
@@ -387,15 +498,27 @@ type Config struct {
// The default, none, is correct for the vast majority of applications.
Renegotiation RenegotiationSupport
+ // KeyLogWriter optionally specifies a destination for TLS master secrets
+ // in NSS key log format that can be used to allow external programs
+ // such as Wireshark to decrypt TLS connections.
+ // See https://developer.mozilla.org/en-US/docs/Mozilla/Projects/NSS/Key_Log_Format.
+ // Use of KeyLogWriter compromises security and should only be
+ // used for debugging.
+ KeyLogWriter io.Writer
+
serverInitOnce sync.Once // guards calling (*Config).serverInit
- // mutex protects sessionTicketKeys
+ // mutex protects sessionTicketKeys and originalConfig.
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
@@ -422,14 +545,26 @@ func ticketKeyFromBytes(b [32]byte) (key ticketKey) {
return key
}
-// clone returns a copy of c. Only the exported fields are copied.
-func (c *Config) clone() *Config {
+// Clone returns a shallow clone of c. It is safe to clone a Config that is
+// being used concurrently by a TLS client or server.
+func (c *Config) Clone() *Config {
+ // Running serverInit ensures that it's safe to read
+ // SessionTicketsDisabled.
+ c.serverInitOnce.Do(c.serverInit)
+
+ var sessionTicketKeys []ticketKey
+ c.mutex.RLock()
+ sessionTicketKeys = c.sessionTicketKeys
+ c.mutex.RUnlock()
+
return &Config{
Rand: c.Rand,
Time: c.Time,
Certificates: c.Certificates,
NameToCertificate: c.NameToCertificate,
GetCertificate: c.GetCertificate,
+ GetConfigForClient: c.GetConfigForClient,
+ VerifyPeerCertificate: c.VerifyPeerCertificate,
RootCAs: c.RootCAs,
NextProtos: c.NextProtos,
ServerName: c.ServerName,
@@ -446,14 +581,22 @@ func (c *Config) clone() *Config {
CurvePreferences: c.CurvePreferences,
DynamicRecordSizingDisabled: c.DynamicRecordSizingDisabled,
Renegotiation: c.Renegotiation,
+ KeyLogWriter: c.KeyLogWriter,
+ sessionTicketKeys: sessionTicketKeys,
+ // originalConfig is deliberately not duplicated.
}
}
func (c *Config) serverInit() {
- if c.SessionTicketsDisabled {
+ 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 {
@@ -463,13 +606,21 @@ func (c *Config) serverInit() {
}
if !alreadySet {
- if _, err := io.ReadFull(c.rand(), c.SessionTicketKey[:]); err != nil {
+ if originalConfig != nil {
+ copy(c.SessionTicketKey[:], originalConfig.SessionTicketKey[:])
+ } else if _, err := io.ReadFull(c.rand(), c.SessionTicketKey[:]); err != nil {
c.SessionTicketsDisabled = true
return
}
}
- c.sessionTicketKeys = []ticketKey{ticketKeyFromBytes(c.SessionTicketKey)}
+ if originalConfig != nil {
+ originalConfig.mutex.RLock()
+ c.sessionTicketKeys = originalConfig.sessionTicketKeys
+ originalConfig.mutex.RUnlock()
+ } else {
+ c.sessionTicketKeys = []ticketKey{ticketKeyFromBytes(c.SessionTicketKey)}
+ }
}
func (c *Config) ticketKeys() []ticketKey {
@@ -539,7 +690,7 @@ func (c *Config) maxVersion() uint16 {
return c.MaxVersion
}
-var defaultCurvePreferences = []CurveID{CurveP256, CurveP384, CurveP521}
+var defaultCurvePreferences = []CurveID{X25519, CurveP256, CurveP384, CurveP521}
func (c *Config) curvePreferences() []CurveID {
if c == nil || len(c.CurvePreferences) == 0 {
@@ -627,6 +778,26 @@ func (c *Config) BuildNameToCertificate() {
}
}
+// writeKeyLog logs client random and master secret if logging was enabled by
+// setting c.KeyLogWriter.
+func (c *Config) writeKeyLog(clientRandom, masterSecret []byte) error {
+ if c.KeyLogWriter == nil {
+ return nil
+ }
+
+ logLine := []byte(fmt.Sprintf("CLIENT_RANDOM %x %x\n", clientRandom, masterSecret))
+
+ writerMutex.Lock()
+ _, err := c.KeyLogWriter.Write(logLine)
+ writerMutex.Unlock()
+
+ return err
+}
+
+// writerMutex protects all KeyLogWriters globally. It is rarely enabled,
+// and is only for debugging, so a global mutex saves space.
+var writerMutex sync.Mutex
+
// A Certificate is a chain of one or more certificates, leaf first.
type Certificate struct {
Certificate [][]byte
@@ -749,11 +920,46 @@ func defaultCipherSuites() []uint16 {
}
func initDefaultCipherSuites() {
+ var topCipherSuites []uint16
+ if cipherhw.AESGCMSupport() {
+ // If AES-GCM hardware is provided then prioritise AES-GCM
+ // cipher suites.
+ topCipherSuites = []uint16{
+ TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+ TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
+ TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
+ TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
+ TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
+ TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
+ }
+ } else {
+ // Without AES-GCM hardware, we put the ChaCha20-Poly1305
+ // cipher suites first.
+ topCipherSuites = []uint16{
+ TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
+ TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
+ TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+ TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
+ TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
+ TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
+ }
+ }
+
varDefaultCipherSuites = make([]uint16, 0, len(cipherSuites))
+ for _, topCipher := range topCipherSuites {
+ varDefaultCipherSuites = append(varDefaultCipherSuites, topCipher)
+ }
+
+NextCipherSuite:
for _, suite := range cipherSuites {
if suite.flags&suiteDefaultOff != 0 {
continue
}
+ for _, existing := range varDefaultCipherSuites {
+ if existing == suite.id {
+ continue NextCipherSuite
+ }
+ }
varDefaultCipherSuites = append(varDefaultCipherSuites, suite.id)
}
}
diff --git a/src/crypto/tls/conn.go b/src/crypto/tls/conn.go
index 77fd6d3..4b2702a 100644
--- a/src/crypto/tls/conn.go
+++ b/src/crypto/tls/conn.go
@@ -64,6 +64,13 @@ type Conn struct {
// the first transmitted Finished message is the tls-unique
// channel-binding value.
clientFinishedIsFirst bool
+
+ // closeNotifyErr is any error from sending the alertCloseNotify record.
+ closeNotifyErr error
+ // closeNotifySent is true if the Conn attempted to send an
+ // alertCloseNotify record.
+ closeNotifySent bool
+
// clientFinished and serverFinished contain the Finished message sent
// by the client or server in the most recent handshake. This is
// retained to support the renegotiation extension and tls-unique
@@ -193,18 +200,18 @@ func (hc *halfConn) incSeq() {
panic("TLS: sequence number wraparound")
}
-// removePadding returns an unpadded slice, in constant time, which is a prefix
-// of the input. It also returns a byte which is equal to 255 if the padding
-// was valid and 0 otherwise. See RFC 2246, section 6.2.3.2
-func removePadding(payload []byte) ([]byte, byte) {
+// extractPadding returns, in constant time, the length of the padding to remove
+// from the end of payload. It also returns a byte which is equal to 255 if the
+// padding was valid and 0 otherwise. See RFC 2246, section 6.2.3.2
+func extractPadding(payload []byte) (toRemove int, good byte) {
if len(payload) < 1 {
- return payload, 0
+ return 0, 0
}
paddingLen := payload[len(payload)-1]
t := uint(len(payload)-1) - uint(paddingLen)
// if len(payload) >= (paddingLen - 1) then the MSB of t is zero
- good := byte(int32(^t) >> 31)
+ good = byte(int32(^t) >> 31)
toCheck := 255 // the maximum possible padding length
// The length of the padded data is public, so we can use an if here
@@ -227,24 +234,24 @@ func removePadding(payload []byte) ([]byte, byte) {
good &= good << 1
good = uint8(int8(good) >> 7)
- toRemove := good&paddingLen + 1
- return payload[:len(payload)-int(toRemove)], good
+ toRemove = int(paddingLen) + 1
+ return
}
-// removePaddingSSL30 is a replacement for removePadding in the case that the
+// extractPaddingSSL30 is a replacement for extractPadding in the case that the
// protocol version is SSLv3. In this version, the contents of the padding
// are random and cannot be checked.
-func removePaddingSSL30(payload []byte) ([]byte, byte) {
+func extractPaddingSSL30(payload []byte) (toRemove int, good byte) {
if len(payload) < 1 {
- return payload, 0
+ return 0, 0
}
paddingLen := int(payload[len(payload)-1]) + 1
if paddingLen > len(payload) {
- return payload, 0
+ return 0, 0
}
- return payload[:len(payload)-paddingLen], 255
+ return paddingLen, 255
}
func roundUp(a, b int) int {
@@ -270,6 +277,7 @@ func (hc *halfConn) decrypt(b *block) (ok bool, prefixLen int, alertValue alert)
}
paddingGood := byte(255)
+ paddingLen := 0
explicitIVLen := 0
// decrypt
@@ -277,13 +285,17 @@ func (hc *halfConn) decrypt(b *block) (ok bool, prefixLen int, alertValue alert)
switch c := hc.cipher.(type) {
case cipher.Stream:
c.XORKeyStream(payload, payload)
- case cipher.AEAD:
- explicitIVLen = 8
+ case aead:
+ explicitIVLen = c.explicitNonceLen()
if len(payload) < explicitIVLen {
return false, 0, alertBadRecordMAC
}
- nonce := payload[:8]
- payload = payload[8:]
+ nonce := payload[:explicitIVLen]
+ payload = payload[explicitIVLen:]
+
+ if len(nonce) == 0 {
+ nonce = hc.seq[:]
+ }
copy(hc.additionalData[:], hc.seq[:])
copy(hc.additionalData[8:], b.data[:3])
@@ -312,22 +324,17 @@ func (hc *halfConn) decrypt(b *block) (ok bool, prefixLen int, alertValue alert)
}
c.CryptBlocks(payload, payload)
if hc.version == VersionSSL30 {
- payload, paddingGood = removePaddingSSL30(payload)
+ paddingLen, paddingGood = extractPaddingSSL30(payload)
} else {
- payload, paddingGood = removePadding(payload)
+ paddingLen, paddingGood = extractPadding(payload)
+
+ // To protect against CBC padding oracles like Lucky13, the data
+ // past paddingLen (which is secret) is passed to the MAC
+ // function as extra data, to be fed into the HMAC after
+ // computing the digest. This makes the MAC constant time as
+ // long as the digest computation is constant time and does not
+ // affect the subsequent write.
}
- b.resize(recordHeaderLen + explicitIVLen + len(payload))
-
- // note that we still have a timing side-channel in the
- // MAC check, below. An attacker can align the record
- // so that a correct padding will cause one less hash
- // block to be calculated. Then they can iteratively
- // decrypt a record by breaking each byte. See
- // "Password Interception in a SSL/TLS Channel", Brice
- // Canvel et al.
- //
- // However, our behavior matches OpenSSL, so we leak
- // only as much as they do.
default:
panic("unknown cipher type")
}
@@ -340,17 +347,19 @@ func (hc *halfConn) decrypt(b *block) (ok bool, prefixLen int, alertValue alert)
}
// strip mac off payload, b.data
- n := len(payload) - macSize
+ n := len(payload) - macSize - paddingLen
+ n = subtle.ConstantTimeSelect(int(uint32(n)>>31), 0, n) // if n < 0 { n = 0 }
b.data[3] = byte(n >> 8)
b.data[4] = byte(n)
- b.resize(recordHeaderLen + explicitIVLen + n)
- remoteMAC := payload[n:]
- localMAC := hc.mac.MAC(hc.inDigestBuf, hc.seq[0:], b.data[:recordHeaderLen], payload[:n])
+ remoteMAC := payload[n : n+macSize]
+ localMAC := hc.mac.MAC(hc.inDigestBuf, hc.seq[0:], b.data[:recordHeaderLen], payload[:n], payload[n+macSize:])
if subtle.ConstantTimeCompare(localMAC, remoteMAC) != 1 || paddingGood != 255 {
return false, 0, alertBadRecordMAC
}
hc.inDigestBuf = localMAC
+
+ b.resize(recordHeaderLen + explicitIVLen + n)
}
hc.incSeq()
@@ -378,7 +387,7 @@ func padToBlockSize(payload []byte, blockSize int) (prefix, finalBlock []byte) {
func (hc *halfConn) encrypt(b *block, explicitIVLen int) (bool, alert) {
// mac
if hc.mac != nil {
- mac := hc.mac.MAC(hc.outDigestBuf, hc.seq[0:], b.data[:recordHeaderLen], b.data[recordHeaderLen+explicitIVLen:])
+ mac := hc.mac.MAC(hc.outDigestBuf, hc.seq[0:], b.data[:recordHeaderLen], b.data[recordHeaderLen+explicitIVLen:], nil)
n := len(b.data)
b.resize(n + len(mac))
@@ -393,10 +402,13 @@ func (hc *halfConn) encrypt(b *block, explicitIVLen int) (bool, alert) {
switch c := hc.cipher.(type) {
case cipher.Stream:
c.XORKeyStream(payload, payload)
- case cipher.AEAD:
+ case aead:
payloadLen := len(b.data) - recordHeaderLen - explicitIVLen
b.resize(len(b.data) + c.Overhead())
nonce := b.data[recordHeaderLen : recordHeaderLen+explicitIVLen]
+ if len(nonce) == 0 {
+ nonce = hc.seq[:]
+ }
payload := b.data[recordHeaderLen+explicitIVLen:]
payload = payload[:payloadLen]
@@ -632,9 +644,10 @@ Again:
// Process message.
b, c.rawInput = c.in.splitBlock(b, recordHeaderLen+n)
- ok, off, err := c.in.decrypt(b)
+ ok, off, alertValue := c.in.decrypt(b)
if !ok {
- c.in.setErrorLocked(c.sendAlert(err))
+ c.in.freeBlock(b)
+ return c.in.setErrorLocked(c.sendAlert(alertValue))
}
b.off = off
data := b.data[b.off:]
@@ -853,15 +866,16 @@ func (c *Conn) writeRecordLocked(typ recordType, data []byte) (int, error) {
}
}
if explicitIVLen == 0 {
- if _, ok := c.out.cipher.(cipher.AEAD); ok {
- explicitIVLen = 8
+ if c, ok := c.out.cipher.(aead); ok {
+ explicitIVLen = c.explicitNonceLen()
+
// The AES-GCM construction in TLS has an
// explicit nonce so that the nonce can be
// random. However, the nonce is only 8 bytes
// which is too small for a secure, random
// nonce. Therefore we use the sequence number
// as the nonce.
- explicitIVIsSeq = true
+ explicitIVIsSeq = explicitIVLen > 0
}
}
m := len(data)
@@ -982,7 +996,7 @@ func (c *Conn) readHandshake() (interface{}, error) {
return nil, c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage))
}
- // The handshake message unmarshallers
+ // The handshake message unmarshalers
// expect to be able to keep references to data,
// so pass in a fresh copy that won't be overwritten.
data = append([]byte(nil), data...)
@@ -993,7 +1007,10 @@ func (c *Conn) readHandshake() (interface{}, error) {
return m, nil
}
-var errClosed = errors.New("tls: use of closed connection")
+var (
+ errClosed = errors.New("tls: use of closed connection")
+ errShutdown = errors.New("tls: protocol is shutdown")
+)
// Write writes data to the connection.
func (c *Conn) Write(b []byte) (int, error) {
@@ -1024,6 +1041,10 @@ func (c *Conn) Write(b []byte) (int, error) {
return 0, alertInternalError
}
+ if c.closeNotifySent {
+ return 0, errShutdown
+ }
+
// SSL 3.0 and TLS 1.0 are susceptible to a chosen-plaintext
// attack when using block mode ciphers due to predictable IVs.
// This can be prevented by splitting each Application Data
@@ -1187,7 +1208,7 @@ func (c *Conn) Close() error {
c.handshakeMutex.Lock()
defer c.handshakeMutex.Unlock()
if c.handshakeComplete {
- alertErr = c.sendAlert(alertCloseNotify)
+ alertErr = c.closeNotify()
}
if err := c.conn.Close(); err != nil {
@@ -1196,6 +1217,32 @@ func (c *Conn) Close() error {
return alertErr
}
+var errEarlyCloseWrite = errors.New("tls: CloseWrite called before handshake complete")
+
+// CloseWrite shuts down the writing side of the connection. It should only be
+// called once the handshake has completed and does not call CloseWrite on the
+// underlying connection. Most callers should just use Close.
+func (c *Conn) CloseWrite() error {
+ c.handshakeMutex.Lock()
+ defer c.handshakeMutex.Unlock()
+ if !c.handshakeComplete {
+ return errEarlyCloseWrite
+ }
+
+ return c.closeNotify()
+}
+
+func (c *Conn) closeNotify() error {
+ c.out.Lock()
+ defer c.out.Unlock()
+
+ if !c.closeNotifySent {
+ c.closeNotifyErr = c.sendAlertLocked(alertCloseNotify)
+ c.closeNotifySent = true
+ }
+ return c.closeNotifyErr
+}
+
// Handshake runs the client or server handshake
// protocol if it has not yet been run.
// Most uses of this package need not call Handshake
@@ -1263,6 +1310,10 @@ func (c *Conn) Handshake() error {
}
if c.handshakeErr == nil {
c.handshakes++
+ } else {
+ // If an error occurred during the hadshake try to flush the
+ // alert that might be left in the buffer.
+ c.flush()
}
if c.handshakeErr == nil && !c.handshakeComplete {
@@ -1284,6 +1335,8 @@ func (c *Conn) ConnectionState() ConnectionState {
var state ConnectionState
state.HandshakeComplete = c.handshakeComplete
+ state.ServerName = c.serverName
+
if c.handshakeComplete {
state.Version = c.vers
state.NegotiatedProtocol = c.clientProtocol
@@ -1292,7 +1345,6 @@ func (c *Conn) ConnectionState() ConnectionState {
state.CipherSuite = c.cipherSuite
state.PeerCertificates = c.peerCertificates
state.VerifiedChains = c.verifiedChains
- state.ServerName = c.serverName
state.SignedCertificateTimestamps = c.scts
state.OCSPResponse = c.ocspResponse
if !c.didResume {
diff --git a/src/crypto/tls/conn_test.go b/src/crypto/tls/conn_test.go
index 5cff7e7..5e5c7a2 100644
--- a/src/crypto/tls/conn_test.go
+++ b/src/crypto/tls/conn_test.go
@@ -40,7 +40,7 @@ var paddingTests = []struct {
func TestRemovePadding(t *testing.T) {
for i, test := range paddingTests {
- payload, good := removePadding(test.in)
+ paddingLen, good := extractPadding(test.in)
expectedGood := byte(255)
if !test.good {
expectedGood = 0
@@ -48,19 +48,19 @@ func TestRemovePadding(t *testing.T) {
if good != expectedGood {
t.Errorf("#%d: wrong validity, want:%d got:%d", i, expectedGood, good)
}
- if good == 255 && len(payload) != test.expectedLen {
- t.Errorf("#%d: got %d, want %d", i, len(payload), test.expectedLen)
+ if good == 255 && len(test.in)-paddingLen != test.expectedLen {
+ t.Errorf("#%d: got %d, want %d", i, len(test.in)-paddingLen, test.expectedLen)
}
}
}
-var certExampleCom = `308201403081eda003020102020101300b06092a864886f70d010105301e311c301a060355040a131354657374696e67204365727469666963617465301e170d3131313030313138353835325a170d3132303933303138353835325a301e311c301a060355040a131354657374696e67204365727469666963617465305a300b06092a864886f70d010101034b003048024100bced6e32368599eeddf18796bfd03958a154f87e5b084f96e85136a56b886733592f493f0fc68b0d6b3551781cb95e13c5de458b28d6fb60d20a9129313261410203010001a31a301830160603551d11040f300d820b6578 [...]
+var certExampleCom = `308201713082011ba003020102021005a75ddf21014d5f417083b7a010ba2e300d06092a864886f70d01010b050030123110300e060355040a130741636d6520436f301e170d3136303831373231343135335a170d3137303831373231343135335a30123110300e060355040a130741636d6520436f305c300d06092a864886f70d0101010500034b003048024100b37f0fdd67e715bf532046ac34acbd8fdc4dabe2b598588f3f58b1f12e6219a16cbfe54d2b4b665396013589262360b6721efa27d546854f17cc9aeec6751db10203010001a34d304b300e0603551d0f0101ff0404030205a0301306 [...]
-var certWildcardExampleCom = `308201423081efa003020102020101300b06092a864886f70d010105301e311c301a060355040a131354657374696e67204365727469666963617465301e170d3131313030313139303034365a170d3132303933303139303034365a301e311c301a060355040a131354657374696e67204365727469666963617465305a300b06092a864886f70d010101034b003048024100bced6e32368599eeddf18796bfd03958a154f87e5b084f96e85136a56b886733592f493f0fc68b0d6b3551781cb95e13c5de458b28d6fb60d20a9129313261410203010001a31c301a30180603551d110411300f [...]
+var certWildcardExampleCom = `308201743082011ea003020102021100a7aa6297c9416a4633af8bec2958c607300d06092a864886f70d01010b050030123110300e060355040a130741636d6520436f301e170d3136303831373231343231395a170d3137303831373231343231395a30123110300e060355040a130741636d6520436f305c300d06092a864886f70d0101010500034b003048024100b105afc859a711ee864114e7d2d46c2dcbe392d3506249f6c2285b0eb342cc4bf2d803677c61c0abde443f084745c1a6d62080e5664ef2cc8f50ad8a0ab8870b0203010001a34f304d300e0603551d0f0101ff04040302 [...]
-var certFooExampleCom = `308201443081f1a003020102020101300b06092a864886f70d010105301e311c301a060355040a131354657374696e67204365727469666963617465301e170d3131313030313139303131345a170d3132303933303139303131345a301e311c301a060355040a131354657374696e67204365727469666963617465305a300b06092a864886f70d010101034b003048024100bced6e32368599eeddf18796bfd03958a154f87e5b084f96e85136a56b886733592f493f0fc68b0d6b3551781cb95e13c5de458b28d6fb60d20a9129313261410203010001a31e301c301a0603551d1104133011820f6 [...]
+var certFooExampleCom = `308201753082011fa00302010202101bbdb6070b0aeffc49008cde74deef29300d06092a864886f70d01010b050030123110300e060355040a130741636d6520436f301e170d3136303831373231343234345a170d3137303831373231343234345a30123110300e060355040a130741636d6520436f305c300d06092a864886f70d0101010500034b003048024100f00ac69d8ca2829f26216c7b50f1d4bbabad58d447706476cd89a2f3e1859943748aa42c15eedc93ac7c49e40d3b05ed645cb6b81c4efba60d961f44211a54eb0203010001a351304f300e0603551d0f0101ff0404030205a0301 [...]
-var certDoubleWildcardExampleCom = `308201443081f1a003020102020101300b06092a864886f70d010105301e311c301a060355040a131354657374696e67204365727469666963617465301e170d3131313030313139303134315a170d3132303933303139303134315a301e311c301a060355040a131354657374696e67204365727469666963617465305a300b06092a864886f70d010101034b003048024100bced6e32368599eeddf18796bfd03958a154f87e5b084f96e85136a56b886733592f493f0fc68b0d6b3551781cb95e13c5de458b28d6fb60d20a9129313261410203010001a31e301c301a0603551d1104 [...]
+var certDoubleWildcardExampleCom = `308201753082011fa003020102021039d262d8538db8ffba30d204e02ddeb5300d06092a864886f70d01010b050030123110300e060355040a130741636d6520436f301e170d3136303831373231343331335a170d3137303831373231343331335a30123110300e060355040a130741636d6520436f305c300d06092a864886f70d0101010500034b003048024100abb6bd84b8b9be3fb9415d00f22b4ddcaec7c99855b9d818c09003e084578430e5cfd2e35faa3561f036d496aa43a9ca6e6cf23c72a763c04ae324004f6cbdbb0203010001a351304f300e0603551d0f0101ff0404 [...]
func TestCertificateSelection(t *testing.T) {
config := Config{
@@ -124,7 +124,7 @@ func TestCertificateSelection(t *testing.T) {
func runDynamicRecordSizingTest(t *testing.T, config *Config) {
clientConn, serverConn := net.Pipe()
- serverConfig := config.clone()
+ serverConfig := config.Clone()
serverConfig.DynamicRecordSizingDisabled = false
tlsConn := Server(serverConn, serverConfig)
@@ -225,19 +225,19 @@ func runDynamicRecordSizingTest(t *testing.T, config *Config) {
}
func TestDynamicRecordSizingWithStreamCipher(t *testing.T) {
- config := testConfig.clone()
+ config := testConfig.Clone()
config.CipherSuites = []uint16{TLS_RSA_WITH_RC4_128_SHA}
runDynamicRecordSizingTest(t, config)
}
func TestDynamicRecordSizingWithCBC(t *testing.T) {
- config := testConfig.clone()
+ config := testConfig.Clone()
config.CipherSuites = []uint16{TLS_RSA_WITH_AES_256_CBC_SHA}
runDynamicRecordSizingTest(t, config)
}
func TestDynamicRecordSizingWithAEAD(t *testing.T) {
- config := testConfig.clone()
+ config := testConfig.Clone()
config.CipherSuites = []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}
runDynamicRecordSizingTest(t, config)
}
diff --git a/src/crypto/tls/example_test.go b/src/crypto/tls/example_test.go
index 7628e43..02d0f18 100644
--- a/src/crypto/tls/example_test.go
+++ b/src/crypto/tls/example_test.go
@@ -7,8 +7,23 @@ package tls_test
import (
"crypto/tls"
"crypto/x509"
+ "log"
+ "net/http"
+ "net/http/httptest"
+ "os"
)
+// zeroSource is an io.Reader that returns an unlimited number of zero bytes.
+type zeroSource struct{}
+
+func (zeroSource) Read(b []byte) (n int, err error) {
+ for i := range b {
+ b[i] = 0
+ }
+
+ return len(b), nil
+}
+
func ExampleDial() {
// Connecting with a custom root-certificate set.
@@ -55,3 +70,46 @@ yuGnBXj8ytqU0CwIPX4WecigUCAkVDNx
}
conn.Close()
}
+
+func ExampleConfig_keyLogWriter() {
+ // Debugging TLS applications by decrypting a network traffic capture.
+
+ // WARNING: Use of KeyLogWriter compromises security and should only be
+ // used for debugging.
+
+ // Dummy test HTTP server for the example with insecure random so output is
+ // reproducible.
+ server := httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}))
+ server.TLS = &tls.Config{
+ Rand: zeroSource{}, // for example only; don't do this.
+ }
+ server.StartTLS()
+ defer server.Close()
+
+ // Typically the log would go to an open file:
+ // w, err := os.OpenFile("tls-secrets.txt", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
+ w := os.Stdout
+
+ client := &http.Client{
+ Transport: &http.Transport{
+ TLSClientConfig: &tls.Config{
+ KeyLogWriter: w,
+
+ Rand: zeroSource{}, // for reproducible output; don't do this.
+ InsecureSkipVerify: true, // test server certificate is not trusted.
+ },
+ },
+ }
+ resp, err := client.Get(server.URL)
+ if err != nil {
+ log.Fatalf("Failed to get URL: %v", err)
+ }
+ resp.Body.Close()
+
+ // The resulting file can be used with Wireshark to decrypt the TLS
+ // connection by setting (Pre)-Master-Secret log filename in SSL Protocol
+ // preferences.
+
+ // Output:
+ // CLIENT_RANDOM 0000000000000000000000000000000000000000000000000000000000000000 baca0df460a688e44ce018b025183cc2353ae01f89755ef766eedd3ecc302888ee3b3a22962e45f48c20df15a98c0e80
+}
diff --git a/src/crypto/tls/handshake_client.go b/src/crypto/tls/handshake_client.go
index f789e6f..6eda18d 100644
--- a/src/crypto/tls/handshake_client.go
+++ b/src/crypto/tls/handshake_client.go
@@ -115,7 +115,7 @@ NextCipherSuite:
// Session resumption is not allowed if renegotiating because
// renegotiation is primarily used to allow a client to send a client
- // certificate, which would be skipped if session resumption occured.
+ // certificate, which would be skipped if session resumption occurred.
if sessionCache != nil && c.handshakes == 0 {
// Try to resume a previously negotiated TLS session, if
// available.
@@ -199,7 +199,7 @@ NextCipherSuite:
// Otherwise, in a full handshake, if we don't have any certificates
// configured then we will never send a CertificateVerify message and
// thus no signatures are needed in that case either.
- if isResume || len(c.config.Certificates) == 0 {
+ if isResume || (len(c.config.Certificates) == 0 && c.config.GetClientCertificate == nil) {
hs.finishedHash.discardHandshakeBuffer()
}
@@ -304,6 +304,13 @@ func (hs *clientHandshakeState) doFullHandshake() error {
}
}
+ if c.config.VerifyPeerCertificate != nil {
+ if err := c.config.VerifyPeerCertificate(certMsg.certificates, c.verifiedChains); err != nil {
+ c.sendAlert(alertBadCertificate)
+ return err
+ }
+ }
+
switch certs[0].PublicKey.(type) {
case *rsa.PublicKey, *ecdsa.PublicKey:
break
@@ -370,71 +377,11 @@ func (hs *clientHandshakeState) doFullHandshake() error {
certReq, ok := msg.(*certificateRequestMsg)
if ok {
certRequested = true
-
- // RFC 4346 on the certificateAuthorities field:
- // A list of the distinguished names of acceptable certificate
- // authorities. These distinguished names may specify a desired
- // distinguished name for a root CA or for a subordinate CA;
- // thus, this message can be used to describe both known roots
- // and a desired authorization space. If the
- // certificate_authorities list is empty then the client MAY
- // send any certificate of the appropriate
- // ClientCertificateType, unless there is some external
- // arrangement to the contrary.
-
hs.finishedHash.Write(certReq.marshal())
- var rsaAvail, ecdsaAvail bool
- for _, certType := range certReq.certificateTypes {
- switch certType {
- case certTypeRSASign:
- rsaAvail = true
- case certTypeECDSASign:
- ecdsaAvail = true
- }
- }
-
- // We need to search our list of client certs for one
- // where SignatureAlgorithm is acceptable to the server and the
- // Issuer is in certReq.certificateAuthorities
- findCert:
- for i, chain := range c.config.Certificates {
- if !rsaAvail && !ecdsaAvail {
- continue
- }
-
- for j, cert := range chain.Certificate {
- x509Cert := chain.Leaf
- // parse the certificate if this isn't the leaf
- // node, or if chain.Leaf was nil
- if j != 0 || x509Cert == nil {
- if x509Cert, err = x509.ParseCertificate(cert); err != nil {
- c.sendAlert(alertInternalError)
- return errors.New("tls: failed to parse client certificate #" + strconv.Itoa(i) + ": " + err.Error())
- }
- }
-
- switch {
- case rsaAvail && x509Cert.PublicKeyAlgorithm == x509.RSA:
- case ecdsaAvail && x509Cert.PublicKeyAlgorithm == x509.ECDSA:
- default:
- continue findCert
- }
-
- if len(certReq.certificateAuthorities) == 0 {
- // they gave us an empty list, so just take the
- // first cert from c.config.Certificates
- chainToSend = &chain
- break findCert
- }
-
- for _, ca := range certReq.certificateAuthorities {
- if bytes.Equal(x509Cert.RawIssuer, ca) {
- chainToSend = &chain
- break findCert
- }
- }
- }
+ if chainToSend, err = hs.getCertificate(certReq); err != nil {
+ c.sendAlert(alertInternalError)
+ return err
}
msg, err = c.readHandshake()
@@ -455,9 +402,7 @@ func (hs *clientHandshakeState) doFullHandshake() error {
// certificate to send.
if certRequested {
certMsg = new(certificateMsg)
- if chainToSend != nil {
- certMsg.certificates = chainToSend.Certificate
- }
+ certMsg.certificates = chainToSend.Certificate
hs.finishedHash.Write(certMsg.marshal())
if _, err := c.writeRecord(recordTypeHandshake, certMsg.marshal()); err != nil {
return err
@@ -476,7 +421,7 @@ func (hs *clientHandshakeState) doFullHandshake() error {
}
}
- if chainToSend != nil {
+ if chainToSend != nil && len(chainToSend.Certificate) > 0 {
certVerify := &certificateVerifyMsg{
hasSignatureAndHash: c.vers >= VersionTLS12,
}
@@ -521,6 +466,10 @@ func (hs *clientHandshakeState) doFullHandshake() error {
}
hs.masterSecret = masterFromPreMasterSecret(c.vers, hs.suite, preMasterSecret, hs.hello.random, hs.serverHello.random)
+ if err := c.config.writeKeyLog(hs.hello.random, hs.masterSecret); err != nil {
+ c.sendAlert(alertInternalError)
+ return errors.New("tls: failed to write to key log: " + err.Error())
+ }
hs.finishedHash.discardHandshakeBuffer()
@@ -716,6 +665,117 @@ func (hs *clientHandshakeState) sendFinished(out []byte) error {
return nil
}
+// tls11SignatureSchemes contains the signature schemes that we synthesise for
+// a TLS <= 1.1 connection, based on the supported certificate types.
+var tls11SignatureSchemes = []SignatureScheme{ECDSAWithP256AndSHA256, ECDSAWithP384AndSHA384, ECDSAWithP521AndSHA512, PKCS1WithSHA256, PKCS1WithSHA384, PKCS1WithSHA512, PKCS1WithSHA1}
+
+const (
+ // tls11SignatureSchemesNumECDSA is the number of initial elements of
+ // tls11SignatureSchemes that use ECDSA.
+ tls11SignatureSchemesNumECDSA = 3
+ // tls11SignatureSchemesNumRSA is the number of trailing elements of
+ // tls11SignatureSchemes that use RSA.
+ tls11SignatureSchemesNumRSA = 4
+)
+
+func (hs *clientHandshakeState) getCertificate(certReq *certificateRequestMsg) (*Certificate, error) {
+ c := hs.c
+
+ var rsaAvail, ecdsaAvail bool
+ for _, certType := range certReq.certificateTypes {
+ switch certType {
+ case certTypeRSASign:
+ rsaAvail = true
+ case certTypeECDSASign:
+ ecdsaAvail = true
+ }
+ }
+
+ if c.config.GetClientCertificate != nil {
+ var signatureSchemes []SignatureScheme
+
+ if !certReq.hasSignatureAndHash {
+ // Prior to TLS 1.2, the signature schemes were not
+ // included in the certificate request message. In this
+ // case we use a plausible list based on the acceptable
+ // certificate types.
+ signatureSchemes = tls11SignatureSchemes
+ if !ecdsaAvail {
+ signatureSchemes = signatureSchemes[tls11SignatureSchemesNumECDSA:]
+ }
+ if !rsaAvail {
+ signatureSchemes = signatureSchemes[:len(signatureSchemes)-tls11SignatureSchemesNumRSA]
+ }
+ } else {
+ signatureSchemes = make([]SignatureScheme, 0, len(certReq.signatureAndHashes))
+ for _, sah := range certReq.signatureAndHashes {
+ signatureSchemes = append(signatureSchemes, SignatureScheme(sah.hash)<<8+SignatureScheme(sah.signature))
+ }
+ }
+
+ return c.config.GetClientCertificate(&CertificateRequestInfo{
+ AcceptableCAs: certReq.certificateAuthorities,
+ SignatureSchemes: signatureSchemes,
+ })
+ }
+
+ // RFC 4346 on the certificateAuthorities field: A list of the
+ // distinguished names of acceptable certificate authorities.
+ // These distinguished names may specify a desired
+ // distinguished name for a root CA or for a subordinate CA;
+ // thus, this message can be used to describe both known roots
+ // and a desired authorization space. If the
+ // certificate_authorities list is empty then the client MAY
+ // send any certificate of the appropriate
+ // ClientCertificateType, unless there is some external
+ // arrangement to the contrary.
+
+ // We need to search our list of client certs for one
+ // where SignatureAlgorithm is acceptable to the server and the
+ // Issuer is in certReq.certificateAuthorities
+findCert:
+ for i, chain := range c.config.Certificates {
+ if !rsaAvail && !ecdsaAvail {
+ continue
+ }
+
+ for j, cert := range chain.Certificate {
+ x509Cert := chain.Leaf
+ // parse the certificate if this isn't the leaf
+ // node, or if chain.Leaf was nil
+ if j != 0 || x509Cert == nil {
+ var err error
+ if x509Cert, err = x509.ParseCertificate(cert); err != nil {
+ c.sendAlert(alertInternalError)
+ return nil, errors.New("tls: failed to parse client certificate #" + strconv.Itoa(i) + ": " + err.Error())
+ }
+ }
+
+ switch {
+ case rsaAvail && x509Cert.PublicKeyAlgorithm == x509.RSA:
+ case ecdsaAvail && x509Cert.PublicKeyAlgorithm == x509.ECDSA:
+ default:
+ continue findCert
+ }
+
+ if len(certReq.certificateAuthorities) == 0 {
+ // they gave us an empty list, so just take the
+ // first cert from c.config.Certificates
+ return &chain, nil
+ }
+
+ for _, ca := range certReq.certificateAuthorities {
+ if bytes.Equal(x509Cert.RawIssuer, ca) {
+ return &chain, nil
+ }
+ }
+ }
+ }
+
+ // No acceptable certificate found. Don't send a certificate.
+ return new(Certificate), nil
+}
+
// clientSessionCacheKey returns a key used to cache sessionTickets that could
// be used to resume previously negotiated TLS sessions with a server.
func clientSessionCacheKey(serverAddr net.Addr, config *Config) string {
diff --git a/src/crypto/tls/handshake_client_test.go b/src/crypto/tls/handshake_client_test.go
index 07d31b6..5851f89 100644
--- a/src/crypto/tls/handshake_client_test.go
+++ b/src/crypto/tls/handshake_client_test.go
@@ -15,12 +15,14 @@ import (
"errors"
"fmt"
"io"
+ "math/big"
"net"
"os"
"os/exec"
"path/filepath"
"strconv"
"strings"
+ "sync"
"testing"
"time"
)
@@ -76,7 +78,7 @@ func newOpensslOutputSink() *opensslOutputSink {
// opensslEndOfHandshake is a message that the “openssl s_server” tool will
// print when a handshake completes if run with “-state”.
-const opensslEndOfHandshake = "SSL_accept:SSLv3 write finished A"
+const opensslEndOfHandshake = "SSL_accept:SSLv3/TLS write finished"
func (o *opensslOutputSink) Write(data []byte) (n int, err error) {
o.line = append(o.line, data...)
@@ -275,6 +277,8 @@ func (test *clientTest) loadData() (flows [][]byte, err error) {
}
func (test *clientTest) run(t *testing.T, write bool) {
+ checkOpenSSLVersion(t)
+
var clientConn, serverConn net.Conn
var recordingConn *recordingConn
var childProcess *exec.Cmd
@@ -355,7 +359,7 @@ func (test *clientTest) run(t *testing.T, write bool) {
}
if expected := i + 1; client.handshakes != expected {
- t.Errorf("client should have recorded %d handshakes, but believes that %d have occured", expected, client.handshakes)
+ t.Errorf("client should have recorded %d handshakes, but believes that %d have occurred", expected, client.handshakes)
}
}()
@@ -409,7 +413,7 @@ func (test *clientTest) run(t *testing.T, write bool) {
childProcess.Process.Kill()
childProcess.Wait()
if len(recordingConn.flows) < 3 {
- childProcess.Stdout.(*bytes.Buffer).WriteTo(os.Stdout)
+ os.Stdout.Write(childProcess.Stdout.(*opensslOutputSink).all)
t.Fatalf("Client connection didn't work")
}
recordingConn.WriteTo(out)
@@ -417,7 +421,26 @@ func (test *clientTest) run(t *testing.T, write bool) {
}
}
+var (
+ didParMu sync.Mutex
+ didPar = map[*testing.T]bool{}
+)
+
+// setParallel calls t.Parallel once. If you call it twice, it would
+// panic.
+func setParallel(t *testing.T) {
+ didParMu.Lock()
+ v := didPar[t]
+ didPar[t] = true
+ didParMu.Unlock()
+ if !v {
+ t.Parallel()
+ }
+}
+
func runClientTestForVersion(t *testing.T, template *clientTest, prefix, option string) {
+ setParallel(t)
+
test := *template
test.name = prefix + test.name
if len(test.command) == 0 {
@@ -508,14 +531,81 @@ func TestHandshakeClientAES256GCMSHA384(t *testing.T) {
runClientTestTLS12(t, test)
}
+func TestHandshakeClientAES128CBCSHA256(t *testing.T) {
+ test := &clientTest{
+ name: "AES128-SHA256",
+ command: []string{"openssl", "s_server", "-cipher", "AES128-SHA256"},
+ }
+ runClientTestTLS12(t, test)
+}
+
+func TestHandshakeClientECDHERSAAES128CBCSHA256(t *testing.T) {
+ test := &clientTest{
+ name: "ECDHE-RSA-AES128-SHA256",
+ command: []string{"openssl", "s_server", "-cipher", "ECDHE-RSA-AES128-SHA256"},
+ }
+ runClientTestTLS12(t, test)
+}
+
+func TestHandshakeClientECDHEECDSAAES128CBCSHA256(t *testing.T) {
+ test := &clientTest{
+ name: "ECDHE-ECDSA-AES128-SHA256",
+ command: []string{"openssl", "s_server", "-cipher", "ECDHE-ECDSA-AES128-SHA256"},
+ cert: testECDSACertificate,
+ key: testECDSAPrivateKey,
+ }
+ runClientTestTLS12(t, test)
+}
+
+func TestHandshakeClientX25519(t *testing.T) {
+ config := testConfig.Clone()
+ config.CurvePreferences = []CurveID{X25519}
+
+ test := &clientTest{
+ name: "X25519-ECDHE-RSA-AES-GCM",
+ command: []string{"openssl", "s_server", "-cipher", "ECDHE-RSA-AES128-GCM-SHA256"},
+ config: config,
+ }
+
+ runClientTestTLS12(t, test)
+}
+
+func TestHandshakeClientECDHERSAChaCha20(t *testing.T) {
+ config := testConfig.Clone()
+ config.CipherSuites = []uint16{TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305}
+
+ test := &clientTest{
+ name: "ECDHE-RSA-CHACHA20-POLY1305",
+ command: []string{"openssl", "s_server", "-cipher", "ECDHE-RSA-CHACHA20-POLY1305"},
+ config: config,
+ }
+
+ runClientTestTLS12(t, test)
+}
+
+func TestHandshakeClientECDHEECDSAChaCha20(t *testing.T) {
+ config := testConfig.Clone()
+ config.CipherSuites = []uint16{TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305}
+
+ test := &clientTest{
+ name: "ECDHE-ECDSA-CHACHA20-POLY1305",
+ command: []string{"openssl", "s_server", "-cipher", "ECDHE-ECDSA-CHACHA20-POLY1305"},
+ config: config,
+ cert: testECDSACertificate,
+ key: testECDSAPrivateKey,
+ }
+
+ runClientTestTLS12(t, test)
+}
+
func TestHandshakeClientCertRSA(t *testing.T) {
- config := testConfig.clone()
+ config := testConfig.Clone()
cert, _ := X509KeyPair([]byte(clientCertificatePEM), []byte(clientKeyPEM))
config.Certificates = []Certificate{cert}
test := &clientTest{
name: "ClientCert-RSA-RSA",
- command: []string{"openssl", "s_server", "-cipher", "RC4-SHA", "-verify", "1"},
+ command: []string{"openssl", "s_server", "-cipher", "AES128", "-verify", "1"},
config: config,
}
@@ -545,13 +635,13 @@ func TestHandshakeClientCertRSA(t *testing.T) {
}
func TestHandshakeClientCertECDSA(t *testing.T) {
- config := testConfig.clone()
+ config := testConfig.Clone()
cert, _ := X509KeyPair([]byte(clientECDSACertificatePEM), []byte(clientECDSAKeyPEM))
config.Certificates = []Certificate{cert}
test := &clientTest{
name: "ClientCert-ECDSA-RSA",
- command: []string{"openssl", "s_server", "-cipher", "RC4-SHA", "-verify", "1"},
+ command: []string{"openssl", "s_server", "-cipher", "AES128", "-verify", "1"},
config: config,
}
@@ -622,13 +712,14 @@ func TestClientResumption(t *testing.T) {
t.Fatal("first ticket doesn't match ticket after resumption")
}
- key2 := randomKey()
- serverConfig.SetSessionTicketKeys([][32]byte{key2})
+ key1 := randomKey()
+ serverConfig.SetSessionTicketKeys([][32]byte{key1})
testResumeState("InvalidSessionTicketKey", false)
testResumeState("ResumeAfterInvalidSessionTicketKey", true)
- serverConfig.SetSessionTicketKeys([][32]byte{randomKey(), key2})
+ key2 := randomKey()
+ serverConfig.SetSessionTicketKeys([][32]byte{key2, key1})
ticket = getTicket()
testResumeState("KeyChange", true)
if bytes.Equal(ticket, getTicket()) {
@@ -636,6 +727,16 @@ func TestClientResumption(t *testing.T) {
}
testResumeState("KeyChangeFinish", true)
+ // Reset serverConfig to ensure that calling SetSessionTicketKeys
+ // before the serverConfig is used works.
+ serverConfig = &Config{
+ CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA, TLS_ECDHE_RSA_WITH_RC4_128_SHA},
+ Certificates: testConfig.Certificates,
+ }
+ serverConfig.SetSessionTicketKeys([][32]byte{key2})
+
+ testResumeState("FreshConfig", true)
+
clientConfig.CipherSuites = []uint16{TLS_ECDHE_RSA_WITH_RC4_128_SHA}
testResumeState("DifferentCipherSuite", false)
testResumeState("DifferentCipherSuiteRecovers", true)
@@ -690,8 +791,59 @@ func TestLRUClientSessionCache(t *testing.T) {
}
}
+func TestKeyLog(t *testing.T) {
+ var serverBuf, clientBuf bytes.Buffer
+
+ clientConfig := testConfig.Clone()
+ clientConfig.KeyLogWriter = &clientBuf
+
+ serverConfig := testConfig.Clone()
+ serverConfig.KeyLogWriter = &serverBuf
+
+ c, s := net.Pipe()
+ done := make(chan bool)
+
+ go func() {
+ defer close(done)
+
+ if err := Server(s, serverConfig).Handshake(); err != nil {
+ t.Errorf("server: %s", err)
+ return
+ }
+ s.Close()
+ }()
+
+ if err := Client(c, clientConfig).Handshake(); err != nil {
+ t.Fatalf("client: %s", err)
+ }
+
+ c.Close()
+ <-done
+
+ checkKeylogLine := func(side, loggedLine string) {
+ if len(loggedLine) == 0 {
+ t.Fatalf("%s: no keylog line was produced", side)
+ }
+ const expectedLen = 13 /* "CLIENT_RANDOM" */ +
+ 1 /* space */ +
+ 32*2 /* hex client nonce */ +
+ 1 /* space */ +
+ 48*2 /* hex master secret */ +
+ 1 /* new line */
+ if len(loggedLine) != expectedLen {
+ t.Fatalf("%s: keylog line has incorrect length (want %d, got %d): %q", side, expectedLen, len(loggedLine), loggedLine)
+ }
+ if !strings.HasPrefix(loggedLine, "CLIENT_RANDOM "+strings.Repeat("0", 64)+" ") {
+ t.Fatalf("%s: keylog line has incorrect structure or nonce: %q", side, loggedLine)
+ }
+ }
+
+ checkKeylogLine("client", string(clientBuf.Bytes()))
+ checkKeylogLine("server", string(serverBuf.Bytes()))
+}
+
func TestHandshakeClientALPNMatch(t *testing.T) {
- config := testConfig.clone()
+ config := testConfig.Clone()
config.NextProtos = []string{"proto2", "proto1"}
test := &clientTest{
@@ -711,32 +863,11 @@ func TestHandshakeClientALPNMatch(t *testing.T) {
runClientTestTLS12(t, test)
}
-func TestHandshakeClientALPNNoMatch(t *testing.T) {
- config := testConfig.clone()
- config.NextProtos = []string{"proto3"}
-
- test := &clientTest{
- name: "ALPN-NoMatch",
- // Note that this needs OpenSSL 1.0.2 because that is the first
- // version that supports the -alpn flag.
- command: []string{"openssl", "s_server", "-alpn", "proto1,proto2"},
- config: config,
- validate: func(state ConnectionState) error {
- // There's no overlap so OpenSSL will not select a protocol.
- if state.NegotiatedProtocol != "" {
- return fmt.Errorf("Got protocol %q, wanted ''", state.NegotiatedProtocol)
- }
- return nil
- },
- }
- runClientTestTLS12(t, test)
-}
-
// sctsBase64 contains data from `openssl s_client -serverinfo 18 -connect ritter.vg:443`
const sctsBase64 = "ABIBaQFnAHUApLkJkLQYWBSHuxOizGdwCjw1mAT5G9+443fNDsgN3BAAAAFHl5nuFgAABAMARjBEAiAcS4JdlW5nW9sElUv2zvQyPoZ6ejKrGGB03gjaBZFMLwIgc1Qbbn+hsH0RvObzhS+XZhr3iuQQJY8S9G85D9KeGPAAdgBo9pj4H2SCvjqM7rkoHUz8cVFdZ5PURNEKZ6y7T0/7xAAAAUeX4bVwAAAEAwBHMEUCIDIhFDgG2HIuADBkGuLobU5a4dlCHoJLliWJ1SYT05z6AiEAjxIoZFFPRNWMGGIjskOTMwXzQ1Wh2e7NxXE1kd1J0QsAdgDuS723dc5guuFCaR+r4Z5mow9+X7By2IMAxHuJeqj9ywAAAUhcZIqHAAAEAwBHMEUCICmJ1rBT09LpkbzxtUC+Hi7nXLR0J+2PmwLp+sJMuqK+AiEAr0NkUnEVKVhAkccIFpYDqHOlZaBs [...]
func TestHandshakClientSCTs(t *testing.T) {
- config := testConfig.clone()
+ config := testConfig.Clone()
scts, err := base64.StdEncoding.DecodeString(sctsBase64)
if err != nil {
@@ -771,7 +902,7 @@ func TestHandshakClientSCTs(t *testing.T) {
}
func TestRenegotiationRejected(t *testing.T) {
- config := testConfig.clone()
+ config := testConfig.Clone()
test := &clientTest{
name: "RenegotiationRejected",
command: []string{"openssl", "s_server", "-state"},
@@ -793,7 +924,7 @@ func TestRenegotiationRejected(t *testing.T) {
}
func TestRenegotiateOnce(t *testing.T) {
- config := testConfig.clone()
+ config := testConfig.Clone()
config.Renegotiation = RenegotiateOnceAsClient
test := &clientTest{
@@ -807,7 +938,7 @@ func TestRenegotiateOnce(t *testing.T) {
}
func TestRenegotiateTwice(t *testing.T) {
- config := testConfig.clone()
+ config := testConfig.Clone()
config.Renegotiation = RenegotiateFreelyAsClient
test := &clientTest{
@@ -821,7 +952,7 @@ func TestRenegotiateTwice(t *testing.T) {
}
func TestRenegotiateTwiceRejected(t *testing.T) {
- config := testConfig.clone()
+ config := testConfig.Clone()
config.Renegotiation = RenegotiateOnceAsClient
test := &clientTest{
@@ -956,6 +1087,160 @@ func TestServerSelectingUnconfiguredCipherSuite(t *testing.T) {
}
}
+func TestVerifyPeerCertificate(t *testing.T) {
+ issuer, err := x509.ParseCertificate(testRSACertificateIssuer)
+ if err != nil {
+ panic(err)
+ }
+
+ rootCAs := x509.NewCertPool()
+ rootCAs.AddCert(issuer)
+
+ now := func() time.Time { return time.Unix(1476984729, 0) }
+
+ sentinelErr := errors.New("TestVerifyPeerCertificate")
+
+ verifyCallback := func(called *bool, rawCerts [][]byte, validatedChains [][]*x509.Certificate) error {
+ if l := len(rawCerts); l != 1 {
+ return fmt.Errorf("got len(rawCerts) = %d, wanted 1", l)
+ }
+ if len(validatedChains) == 0 {
+ return errors.New("got len(validatedChains) = 0, wanted non-zero")
+ }
+ *called = true
+ return nil
+ }
+
+ tests := []struct {
+ configureServer func(*Config, *bool)
+ configureClient func(*Config, *bool)
+ validate func(t *testing.T, testNo int, clientCalled, serverCalled bool, clientErr, serverErr error)
+ }{
+ {
+ configureServer: func(config *Config, called *bool) {
+ config.InsecureSkipVerify = false
+ config.VerifyPeerCertificate = func(rawCerts [][]byte, validatedChains [][]*x509.Certificate) error {
+ return verifyCallback(called, rawCerts, validatedChains)
+ }
+ },
+ configureClient: func(config *Config, called *bool) {
+ config.InsecureSkipVerify = false
+ config.VerifyPeerCertificate = func(rawCerts [][]byte, validatedChains [][]*x509.Certificate) error {
+ return verifyCallback(called, rawCerts, validatedChains)
+ }
+ },
+ validate: func(t *testing.T, testNo int, clientCalled, serverCalled bool, clientErr, serverErr error) {
+ if clientErr != nil {
+ t.Errorf("test[%d]: client handshake failed: %v", testNo, clientErr)
+ }
+ if serverErr != nil {
+ t.Errorf("test[%d]: server handshake failed: %v", testNo, serverErr)
+ }
+ if !clientCalled {
+ t.Errorf("test[%d]: client did not call callback", testNo)
+ }
+ if !serverCalled {
+ t.Errorf("test[%d]: server did not call callback", testNo)
+ }
+ },
+ },
+ {
+ configureServer: func(config *Config, called *bool) {
+ config.InsecureSkipVerify = false
+ config.VerifyPeerCertificate = func(rawCerts [][]byte, validatedChains [][]*x509.Certificate) error {
+ return sentinelErr
+ }
+ },
+ configureClient: func(config *Config, called *bool) {
+ config.VerifyPeerCertificate = nil
+ },
+ validate: func(t *testing.T, testNo int, clientCalled, serverCalled bool, clientErr, serverErr error) {
+ if serverErr != sentinelErr {
+ t.Errorf("#%d: got server error %v, wanted sentinelErr", testNo, serverErr)
+ }
+ },
+ },
+ {
+ configureServer: func(config *Config, called *bool) {
+ config.InsecureSkipVerify = false
+ },
+ configureClient: func(config *Config, called *bool) {
+ config.VerifyPeerCertificate = func(rawCerts [][]byte, validatedChains [][]*x509.Certificate) error {
+ return sentinelErr
+ }
+ },
+ validate: func(t *testing.T, testNo int, clientCalled, serverCalled bool, clientErr, serverErr error) {
+ if clientErr != sentinelErr {
+ t.Errorf("#%d: got client error %v, wanted sentinelErr", testNo, clientErr)
+ }
+ },
+ },
+ {
+ configureServer: func(config *Config, called *bool) {
+ config.InsecureSkipVerify = false
+ },
+ configureClient: func(config *Config, called *bool) {
+ config.InsecureSkipVerify = true
+ config.VerifyPeerCertificate = func(rawCerts [][]byte, validatedChains [][]*x509.Certificate) error {
+ if l := len(rawCerts); l != 1 {
+ return fmt.Errorf("got len(rawCerts) = %d, wanted 1", l)
+ }
+ // With InsecureSkipVerify set, this
+ // callback should still be called but
+ // validatedChains must be empty.
+ if l := len(validatedChains); l != 0 {
+ return errors.New("got len(validatedChains) = 0, wanted zero")
+ }
+ *called = true
+ return nil
+ }
+ },
+ validate: func(t *testing.T, testNo int, clientCalled, serverCalled bool, clientErr, serverErr error) {
+ if clientErr != nil {
+ t.Errorf("test[%d]: client handshake failed: %v", testNo, clientErr)
+ }
+ if serverErr != nil {
+ t.Errorf("test[%d]: server handshake failed: %v", testNo, serverErr)
+ }
+ if !clientCalled {
+ t.Errorf("test[%d]: client did not call callback", testNo)
+ }
+ },
+ },
+ }
+
+ for i, test := range tests {
+ c, s := net.Pipe()
+ done := make(chan error)
+
+ var clientCalled, serverCalled bool
+
+ go func() {
+ config := testConfig.Clone()
+ config.ServerName = "example.golang"
+ config.ClientAuth = RequireAndVerifyClientCert
+ config.ClientCAs = rootCAs
+ config.Time = now
+ test.configureServer(config, &serverCalled)
+
+ err = Server(s, config).Handshake()
+ s.Close()
+ done <- err
+ }()
+
+ config := testConfig.Clone()
+ config.ServerName = "example.golang"
+ config.RootCAs = rootCAs
+ config.Time = now
+ test.configureClient(config, &clientCalled)
+ clientErr := Client(c, config).Handshake()
+ c.Close()
+ serverErr := <-done
+
+ test.validate(t, i, clientCalled, serverCalled, clientErr, serverErr)
+ }
+}
+
// brokenConn wraps a net.Conn and causes all Writes after a certain number to
// fail with brokenConnErr.
type brokenConn struct {
@@ -1046,7 +1331,52 @@ func TestBuffering(t *testing.T) {
}
}
+func TestAlertFlushing(t *testing.T) {
+ c, s := net.Pipe()
+ done := make(chan bool)
+
+ clientWCC := &writeCountingConn{Conn: c}
+ serverWCC := &writeCountingConn{Conn: s}
+
+ serverConfig := testConfig.Clone()
+
+ // Cause a signature-time error
+ brokenKey := rsa.PrivateKey{PublicKey: testRSAPrivateKey.PublicKey}
+ brokenKey.D = big.NewInt(42)
+ serverConfig.Certificates = []Certificate{{
+ Certificate: [][]byte{testRSACertificate},
+ PrivateKey: &brokenKey,
+ }}
+
+ go func() {
+ Server(serverWCC, serverConfig).Handshake()
+ serverWCC.Close()
+ done <- true
+ }()
+
+ err := Client(clientWCC, testConfig).Handshake()
+ if err == nil {
+ t.Fatal("client unexpectedly returned no error")
+ }
+
+ const expectedError = "remote error: tls: handshake failure"
+ if e := err.Error(); !strings.Contains(e, expectedError) {
+ t.Fatalf("expected to find %q in error but error was %q", expectedError, e)
+ }
+ clientWCC.Close()
+ <-done
+
+ if n := clientWCC.numWrites; n != 1 {
+ t.Errorf("expected client handshake to complete with one write, but saw %d", n)
+ }
+
+ if n := serverWCC.numWrites; n != 1 {
+ t.Errorf("expected server handshake to complete with one write, but saw %d", n)
+ }
+}
+
func TestHandshakeRace(t *testing.T) {
+ t.Parallel()
// This test races a Read and Write to try and complete a handshake in
// order to provide some evidence that there are no races or deadlocks
// in the handshake locking.
@@ -1099,3 +1429,137 @@ func TestHandshakeRace(t *testing.T) {
<-readDone
}
}
+
+func TestTLS11SignatureSchemes(t *testing.T) {
+ expected := tls11SignatureSchemesNumECDSA + tls11SignatureSchemesNumRSA
+ if expected != len(tls11SignatureSchemes) {
+ t.Errorf("expected to find %d TLS 1.1 signature schemes, but found %d", expected, len(tls11SignatureSchemes))
+ }
+}
+
+var getClientCertificateTests = []struct {
+ setup func(*Config)
+ expectedClientError string
+ verify func(*testing.T, int, *ConnectionState)
+}{
+ {
+ func(clientConfig *Config) {
+ // Returning a Certificate with no certificate data
+ // should result in an empty message being sent to the
+ // server.
+ clientConfig.GetClientCertificate = func(cri *CertificateRequestInfo) (*Certificate, error) {
+ if len(cri.SignatureSchemes) == 0 {
+ panic("empty SignatureSchemes")
+ }
+ return new(Certificate), nil
+ }
+ },
+ "",
+ func(t *testing.T, testNum int, cs *ConnectionState) {
+ if l := len(cs.PeerCertificates); l != 0 {
+ t.Errorf("#%d: expected no certificates but got %d", testNum, l)
+ }
+ },
+ },
+ {
+ func(clientConfig *Config) {
+ // With TLS 1.1, the SignatureSchemes should be
+ // synthesised from the supported certificate types.
+ clientConfig.MaxVersion = VersionTLS11
+ clientConfig.GetClientCertificate = func(cri *CertificateRequestInfo) (*Certificate, error) {
+ if len(cri.SignatureSchemes) == 0 {
+ panic("empty SignatureSchemes")
+ }
+ return new(Certificate), nil
+ }
+ },
+ "",
+ func(t *testing.T, testNum int, cs *ConnectionState) {
+ if l := len(cs.PeerCertificates); l != 0 {
+ t.Errorf("#%d: expected no certificates but got %d", testNum, l)
+ }
+ },
+ },
+ {
+ func(clientConfig *Config) {
+ // Returning an error should abort the handshake with
+ // that error.
+ clientConfig.GetClientCertificate = func(cri *CertificateRequestInfo) (*Certificate, error) {
+ return nil, errors.New("GetClientCertificate")
+ }
+ },
+ "GetClientCertificate",
+ func(t *testing.T, testNum int, cs *ConnectionState) {
+ },
+ },
+ {
+ func(clientConfig *Config) {
+ clientConfig.GetClientCertificate = func(cri *CertificateRequestInfo) (*Certificate, error) {
+ return &testConfig.Certificates[0], nil
+ }
+ },
+ "",
+ func(t *testing.T, testNum int, cs *ConnectionState) {
+ if l := len(cs.VerifiedChains); l != 0 {
+ t.Errorf("#%d: expected some verified chains, but found none", testNum)
+ }
+ },
+ },
+}
+
+func TestGetClientCertificate(t *testing.T) {
+ issuer, err := x509.ParseCertificate(testRSACertificateIssuer)
+ if err != nil {
+ panic(err)
+ }
+
+ for i, test := range getClientCertificateTests {
+ serverConfig := testConfig.Clone()
+ serverConfig.ClientAuth = RequestClientCert
+ serverConfig.RootCAs = x509.NewCertPool()
+ serverConfig.RootCAs.AddCert(issuer)
+
+ clientConfig := testConfig.Clone()
+
+ test.setup(clientConfig)
+
+ type serverResult struct {
+ cs ConnectionState
+ err error
+ }
+
+ c, s := net.Pipe()
+ done := make(chan serverResult)
+
+ go func() {
+ defer s.Close()
+ server := Server(s, serverConfig)
+ err := server.Handshake()
+
+ var cs ConnectionState
+ if err == nil {
+ cs = server.ConnectionState()
+ }
+ done <- serverResult{cs, err}
+ }()
+
+ clientErr := Client(c, clientConfig).Handshake()
+ c.Close()
+
+ result := <-done
+
+ if clientErr != nil {
+ if len(test.expectedClientError) == 0 {
+ t.Errorf("#%d: client error: %v", i, clientErr)
+ } else if got := clientErr.Error(); got != test.expectedClientError {
+ t.Errorf("#%d: expected client error %q, but got %q", i, test.expectedClientError, got)
+ }
+ } else if len(test.expectedClientError) > 0 {
+ t.Errorf("#%d: expected client error %q, but got no error", i, test.expectedClientError)
+ } else if err := result.err; err != nil {
+ t.Errorf("#%d: server error: %v", i, err)
+ } else {
+ test.verify(t, i, &result.cs)
+ }
+ }
+}
diff --git a/src/crypto/tls/handshake_messages.go b/src/crypto/tls/handshake_messages.go
index ab8e60a..694bd91 100644
--- a/src/crypto/tls/handshake_messages.go
+++ b/src/crypto/tls/handshake_messages.go
@@ -802,12 +802,9 @@ func (m *serverHelloMsg) unmarshal(data []byte) bool {
}
l := int(d[0])<<8 | int(d[1])
d = d[2:]
- if len(d) != l {
+ if len(d) != l || l == 0 {
return false
}
- if l == 0 {
- continue
- }
m.scts = make([][]byte, 0, 3)
for len(d) != 0 {
@@ -816,7 +813,7 @@ func (m *serverHelloMsg) unmarshal(data []byte) bool {
}
sctLen := int(d[0])<<8 | int(d[1])
d = d[2:]
- if len(d) < sctLen {
+ if sctLen == 0 || len(d) < sctLen {
return false
}
m.scts = append(m.scts, d[:sctLen])
diff --git a/src/crypto/tls/handshake_messages_test.go b/src/crypto/tls/handshake_messages_test.go
index 95d825b..f1154d4 100644
--- a/src/crypto/tls/handshake_messages_test.go
+++ b/src/crypto/tls/handshake_messages_test.go
@@ -5,6 +5,7 @@
package tls
import (
+ "bytes"
"math/rand"
"reflect"
"testing"
@@ -260,3 +261,65 @@ func (*sessionState) Generate(rand *rand.Rand, size int) reflect.Value {
}
return reflect.ValueOf(s)
}
+
+func TestRejectEmptySCTList(t *testing.T) {
+ // https://tools.ietf.org/html/rfc6962#section-3.3.1 specifies that
+ // empty SCT lists are invalid.
+
+ var random [32]byte
+ sct := []byte{0x42, 0x42, 0x42, 0x42}
+ serverHello := serverHelloMsg{
+ vers: VersionTLS12,
+ random: random[:],
+ scts: [][]byte{sct},
+ }
+ serverHelloBytes := serverHello.marshal()
+
+ var serverHelloCopy serverHelloMsg
+ if !serverHelloCopy.unmarshal(serverHelloBytes) {
+ t.Fatal("Failed to unmarshal initial message")
+ }
+
+ // Change serverHelloBytes so that the SCT list is empty
+ i := bytes.Index(serverHelloBytes, sct)
+ if i < 0 {
+ t.Fatal("Cannot find SCT in ServerHello")
+ }
+
+ var serverHelloEmptySCT []byte
+ serverHelloEmptySCT = append(serverHelloEmptySCT, serverHelloBytes[:i-6]...)
+ // Append the extension length and SCT list length for an empty list.
+ serverHelloEmptySCT = append(serverHelloEmptySCT, []byte{0, 2, 0, 0}...)
+ serverHelloEmptySCT = append(serverHelloEmptySCT, serverHelloBytes[i+4:]...)
+
+ // Update the handshake message length.
+ serverHelloEmptySCT[1] = byte((len(serverHelloEmptySCT) - 4) >> 16)
+ serverHelloEmptySCT[2] = byte((len(serverHelloEmptySCT) - 4) >> 8)
+ serverHelloEmptySCT[3] = byte(len(serverHelloEmptySCT) - 4)
+
+ // Update the extensions length
+ serverHelloEmptySCT[42] = byte((len(serverHelloEmptySCT) - 44) >> 8)
+ serverHelloEmptySCT[43] = byte((len(serverHelloEmptySCT) - 44))
+
+ if serverHelloCopy.unmarshal(serverHelloEmptySCT) {
+ t.Fatal("Unmarshaled ServerHello with empty SCT list")
+ }
+}
+
+func TestRejectEmptySCT(t *testing.T) {
+ // Not only must the SCT list be non-empty, but the SCT elements must
+ // not be zero length.
+
+ var random [32]byte
+ serverHello := serverHelloMsg{
+ vers: VersionTLS12,
+ random: random[:],
+ scts: [][]byte{nil},
+ }
+ serverHelloBytes := serverHello.marshal()
+
+ var serverHelloCopy serverHelloMsg
+ if serverHelloCopy.unmarshal(serverHelloBytes) {
+ t.Fatal("Unmarshaled ServerHello with zero-length SCT")
+ }
+}
diff --git a/src/crypto/tls/handshake_server.go b/src/crypto/tls/handshake_server.go
index 1aac729..b786c30 100644
--- a/src/crypto/tls/handshake_server.go
+++ b/src/crypto/tls/handshake_server.go
@@ -19,29 +19,28 @@ import (
// serverHandshakeState contains details of a server handshake in progress.
// It's discarded once the handshake has completed.
type serverHandshakeState struct {
- c *Conn
- clientHello *clientHelloMsg
- hello *serverHelloMsg
- suite *cipherSuite
- ellipticOk bool
- ecdsaOk bool
- rsaDecryptOk bool
- rsaSignOk bool
- sessionState *sessionState
- finishedHash finishedHash
- masterSecret []byte
- certsFromClient [][]byte
- cert *Certificate
+ c *Conn
+ clientHello *clientHelloMsg
+ hello *serverHelloMsg
+ suite *cipherSuite
+ ellipticOk bool
+ ecdsaOk bool
+ rsaDecryptOk bool
+ rsaSignOk bool
+ sessionState *sessionState
+ finishedHash finishedHash
+ masterSecret []byte
+ certsFromClient [][]byte
+ cert *Certificate
+ cachedClientHelloInfo *ClientHelloInfo
}
// serverHandshake performs a TLS handshake as a server.
// c.out.Mutex <= L; c.handshakeMutex <= L.
func (c *Conn) serverHandshake() error {
- config := c.config
-
// If this is the first server handshake, we generate a random key to
// encrypt the tickets with.
- config.serverInitOnce.Do(config.serverInit)
+ c.config.serverInitOnce.Do(c.config.serverInit)
hs := serverHandshakeState{
c: c,
@@ -112,7 +111,6 @@ func (c *Conn) serverHandshake() error {
// readClientHello reads a ClientHello message from the client and decides
// whether we will perform session resumption.
func (hs *serverHandshakeState) readClientHello() (isResume bool, err error) {
- config := hs.c.config
c := hs.c
msg, err := c.readHandshake()
@@ -125,7 +123,22 @@ func (hs *serverHandshakeState) readClientHello() (isResume bool, err error) {
c.sendAlert(alertUnexpectedMessage)
return false, unexpectedMessageError(hs.clientHello, msg)
}
- c.vers, ok = config.mutualVersion(hs.clientHello.vers)
+
+ if c.config.GetConfigForClient != nil {
+ if newConfig, err := c.config.GetConfigForClient(hs.clientHelloInfo()); err != nil {
+ 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)
+ c.config = newConfig
+ }
+ }
+
+ c.vers, ok = c.config.mutualVersion(hs.clientHello.vers)
if !ok {
c.sendAlert(alertProtocolVersion)
return false, fmt.Errorf("tls: client offered an unsupported, maximum protocol version of %x", hs.clientHello.vers)
@@ -135,7 +148,7 @@ func (hs *serverHandshakeState) readClientHello() (isResume bool, err error) {
hs.hello = new(serverHelloMsg)
supportedCurve := false
- preferredCurves := config.curvePreferences()
+ preferredCurves := c.config.curvePreferences()
Curves:
for _, curve := range hs.clientHello.supportedCurves {
for _, supported := range preferredCurves {
@@ -171,7 +184,7 @@ Curves:
hs.hello.vers = c.vers
hs.hello.random = make([]byte, 32)
- _, err = io.ReadFull(config.rand(), hs.hello.random)
+ _, err = io.ReadFull(c.config.rand(), hs.hello.random)
if err != nil {
c.sendAlert(alertInternalError)
return false, err
@@ -196,20 +209,15 @@ Curves:
} else {
// Although sending an empty NPN extension is reasonable, Firefox has
// had a bug around this. Best to send nothing at all if
- // config.NextProtos is empty. See
+ // c.config.NextProtos is empty. See
// https://golang.org/issue/5445.
- if hs.clientHello.nextProtoNeg && len(config.NextProtos) > 0 {
+ if hs.clientHello.nextProtoNeg && len(c.config.NextProtos) > 0 {
hs.hello.nextProtoNeg = true
- hs.hello.nextProtos = config.NextProtos
+ hs.hello.nextProtos = c.config.NextProtos
}
}
- hs.cert, err = config.getCertificate(&ClientHelloInfo{
- CipherSuites: hs.clientHello.cipherSuites,
- ServerName: hs.clientHello.serverName,
- SupportedCurves: hs.clientHello.supportedCurves,
- SupportedPoints: hs.clientHello.supportedPoints,
- })
+ hs.cert, err = c.config.getCertificate(hs.clientHelloInfo())
if err != nil {
c.sendAlert(alertInternalError)
return false, err
@@ -354,18 +362,17 @@ func (hs *serverHandshakeState) doResumeHandshake() error {
}
func (hs *serverHandshakeState) doFullHandshake() error {
- config := hs.c.config
c := hs.c
if hs.clientHello.ocspStapling && len(hs.cert.OCSPStaple) > 0 {
hs.hello.ocspStapling = true
}
- hs.hello.ticketSupported = hs.clientHello.ticketSupported && !config.SessionTicketsDisabled
+ hs.hello.ticketSupported = hs.clientHello.ticketSupported && !c.config.SessionTicketsDisabled
hs.hello.cipherSuite = hs.suite.id
hs.finishedHash = newFinishedHash(hs.c.vers, hs.suite)
- if config.ClientAuth == NoClientCert {
+ if c.config.ClientAuth == NoClientCert {
// No need to keep a full record of the handshake if client
// certificates won't be used.
hs.finishedHash.discardHandshakeBuffer()
@@ -394,7 +401,7 @@ func (hs *serverHandshakeState) doFullHandshake() error {
}
keyAgreement := hs.suite.ka(c.vers)
- skx, err := keyAgreement.generateServerKeyExchange(config, hs.cert, hs.clientHello, hs.hello)
+ skx, err := keyAgreement.generateServerKeyExchange(c.config, hs.cert, hs.clientHello, hs.hello)
if err != nil {
c.sendAlert(alertHandshakeFailure)
return err
@@ -406,7 +413,7 @@ func (hs *serverHandshakeState) doFullHandshake() error {
}
}
- if config.ClientAuth >= RequestClientCert {
+ if c.config.ClientAuth >= RequestClientCert {
// Request a client certificate
certReq := new(certificateRequestMsg)
certReq.certificateTypes = []byte{
@@ -423,8 +430,8 @@ func (hs *serverHandshakeState) doFullHandshake() error {
// to our request. When we know the CAs we trust, then
// we can send them down, so that the client can choose
// an appropriate certificate to give to us.
- if config.ClientCAs != nil {
- certReq.certificateAuthorities = config.ClientCAs.Subjects()
+ if c.config.ClientCAs != nil {
+ certReq.certificateAuthorities = c.config.ClientCAs.Subjects()
}
hs.finishedHash.Write(certReq.marshal())
if _, err := c.writeRecord(recordTypeHandshake, certReq.marshal()); err != nil {
@@ -452,7 +459,7 @@ func (hs *serverHandshakeState) doFullHandshake() error {
var ok bool
// If we requested a client certificate, then the client must send a
// certificate message, even if it's empty.
- if config.ClientAuth >= RequestClientCert {
+ if c.config.ClientAuth >= RequestClientCert {
if certMsg, ok = msg.(*certificateMsg); !ok {
c.sendAlert(alertUnexpectedMessage)
return unexpectedMessageError(certMsg, msg)
@@ -461,7 +468,7 @@ func (hs *serverHandshakeState) doFullHandshake() error {
if len(certMsg.certificates) == 0 {
// The client didn't actually send a certificate
- switch config.ClientAuth {
+ switch c.config.ClientAuth {
case RequireAnyClientCert, RequireAndVerifyClientCert:
c.sendAlert(alertBadCertificate)
return errors.New("tls: client didn't provide a certificate")
@@ -487,12 +494,16 @@ func (hs *serverHandshakeState) doFullHandshake() error {
}
hs.finishedHash.Write(ckx.marshal())
- preMasterSecret, err := keyAgreement.processClientKeyExchange(config, hs.cert, ckx, c.vers)
+ preMasterSecret, err := keyAgreement.processClientKeyExchange(c.config, hs.cert, ckx, c.vers)
if err != nil {
c.sendAlert(alertHandshakeFailure)
return err
}
hs.masterSecret = masterFromPreMasterSecret(c.vers, hs.suite, preMasterSecret, hs.clientHello.random, hs.hello.random)
+ if err := c.config.writeKeyLog(hs.clientHello.random, hs.masterSecret); err != nil {
+ c.sendAlert(alertInternalError)
+ return err
+ }
// If we received a client cert in response to our certificate request message,
// the client will send us a certificateVerifyMsg immediately after the
@@ -730,6 +741,13 @@ func (hs *serverHandshakeState) processCertsFromClient(certificates [][]byte) (c
c.verifiedChains = chains
}
+ if c.config.VerifyPeerCertificate != nil {
+ if err := c.config.VerifyPeerCertificate(certificates, c.verifiedChains); err != nil {
+ c.sendAlert(alertBadCertificate)
+ return nil, err
+ }
+ }
+
if len(certs) == 0 {
return nil, nil
}
@@ -788,3 +806,37 @@ func (hs *serverHandshakeState) setCipherSuite(id uint16, supportedCipherSuites
}
return false
}
+
+// suppVersArray is the backing array of ClientHelloInfo.SupportedVersions
+var suppVersArray = [...]uint16{VersionTLS12, VersionTLS11, VersionTLS10, VersionSSL30}
+
+func (hs *serverHandshakeState) clientHelloInfo() *ClientHelloInfo {
+ if hs.cachedClientHelloInfo != nil {
+ return hs.cachedClientHelloInfo
+ }
+
+ var supportedVersions []uint16
+ if hs.clientHello.vers > VersionTLS12 {
+ supportedVersions = suppVersArray[:]
+ } else if hs.clientHello.vers >= VersionSSL30 {
+ supportedVersions = suppVersArray[VersionTLS12-hs.clientHello.vers:]
+ }
+
+ signatureSchemes := make([]SignatureScheme, 0, len(hs.clientHello.signatureAndHashes))
+ for _, sah := range hs.clientHello.signatureAndHashes {
+ signatureSchemes = append(signatureSchemes, SignatureScheme(sah.hash)<<8+SignatureScheme(sah.signature))
+ }
+
+ hs.cachedClientHelloInfo = &ClientHelloInfo{
+ CipherSuites: hs.clientHello.cipherSuites,
+ ServerName: hs.clientHello.serverName,
+ SupportedCurves: hs.clientHello.supportedCurves,
+ SupportedPoints: hs.clientHello.supportedPoints,
+ SignatureSchemes: signatureSchemes,
+ SupportedProtos: hs.clientHello.alpnProtocols,
+ SupportedVersions: supportedVersions,
+ Conn: hs.c.conn,
+ }
+
+ return hs.cachedClientHelloInfo
+}
diff --git a/src/crypto/tls/handshake_server_test.go b/src/crypto/tls/handshake_server_test.go
index 9ae5d11..bcd3d43 100644
--- a/src/crypto/tls/handshake_server_test.go
+++ b/src/crypto/tls/handshake_server_test.go
@@ -130,7 +130,7 @@ func TestNoRC4ByDefault(t *testing.T) {
cipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA},
compressionMethods: []uint8{compressionNone},
}
- serverConfig := testConfig.clone()
+ serverConfig := testConfig.Clone()
// Reset the enabled cipher suites to nil in order to test the
// defaults.
serverConfig.CipherSuites = nil
@@ -147,7 +147,7 @@ func TestDontSelectECDSAWithRSAKey(t *testing.T) {
supportedCurves: []CurveID{CurveP256},
supportedPoints: []uint8{pointFormatUncompressed},
}
- serverConfig := testConfig.clone()
+ serverConfig := testConfig.Clone()
serverConfig.CipherSuites = clientHello.cipherSuites
serverConfig.Certificates = make([]Certificate, 1)
serverConfig.Certificates[0].Certificate = [][]byte{testECDSACertificate}
@@ -172,7 +172,7 @@ func TestDontSelectRSAWithECDSAKey(t *testing.T) {
supportedCurves: []CurveID{CurveP256},
supportedPoints: []uint8{pointFormatUncompressed},
}
- serverConfig := testConfig.clone()
+ serverConfig := testConfig.Clone()
serverConfig.CipherSuites = clientHello.cipherSuites
// First test that it *does* work when the server's key is RSA.
testClientHello(t, serverConfig, clientHello)
@@ -206,7 +206,8 @@ func TestRenegotiationExtension(t *testing.T) {
buf = make([]byte, 1024)
n, err := c.Read(buf)
if err != nil {
- t.Fatalf("Server read returned error: %s", err)
+ t.Errorf("Server read returned error: %s", err)
+ return
}
buf = buf[:n]
c.Close()
@@ -265,7 +266,7 @@ func TestTLS12OnlyCipherSuites(t *testing.T) {
reply, clientErr = cli.readHandshake()
c.Close()
}()
- config := testConfig.clone()
+ config := testConfig.Clone()
config.CipherSuites = clientHello.cipherSuites
Server(s, config).Handshake()
s.Close()
@@ -558,6 +559,8 @@ func (test *serverTest) loadData() (flows [][]byte, err error) {
}
func (test *serverTest) run(t *testing.T, write bool) {
+ checkOpenSSLVersion(t)
+
var clientConn, serverConn net.Conn
var recordingConn *recordingConn
var childProcess *exec.Cmd
@@ -658,6 +661,7 @@ func (test *serverTest) run(t *testing.T, write bool) {
}
func runServerTestForVersion(t *testing.T, template *serverTest, prefix, option string) {
+ setParallel(t)
test := *template
test.name = prefix + test.name
if len(test.command) == 0 {
@@ -732,7 +736,7 @@ func TestHandshakeServerAES256GCMSHA384(t *testing.T) {
}
func TestHandshakeServerECDHEECDSAAES(t *testing.T) {
- config := testConfig.clone()
+ config := testConfig.Clone()
config.Certificates = make([]Certificate, 1)
config.Certificates[0].Certificate = [][]byte{testECDSACertificate}
config.Certificates[0].PrivateKey = testECDSAPrivateKey
@@ -747,8 +751,20 @@ func TestHandshakeServerECDHEECDSAAES(t *testing.T) {
runServerTestTLS12(t, test)
}
+func TestHandshakeServerX25519(t *testing.T) {
+ config := testConfig.Clone()
+ config.CurvePreferences = []CurveID{X25519}
+
+ test := &serverTest{
+ name: "X25519-ECDHE-RSA-AES-GCM",
+ command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "ECDHE-RSA-AES128-GCM-SHA256"},
+ config: config,
+ }
+ runServerTestTLS12(t, test)
+}
+
func TestHandshakeServerALPN(t *testing.T) {
- config := testConfig.clone()
+ config := testConfig.Clone()
config.NextProtos = []string{"proto1", "proto2"}
test := &serverTest{
@@ -769,7 +785,7 @@ func TestHandshakeServerALPN(t *testing.T) {
}
func TestHandshakeServerALPNNoMatch(t *testing.T) {
- config := testConfig.clone()
+ config := testConfig.Clone()
config.NextProtos = []string{"proto3"}
test := &serverTest{
@@ -804,7 +820,7 @@ func TestHandshakeServerSNI(t *testing.T) {
// TestHandshakeServerSNICertForName is similar to TestHandshakeServerSNI, but
// tests the dynamic GetCertificate method
func TestHandshakeServerSNIGetCertificate(t *testing.T) {
- config := testConfig.clone()
+ config := testConfig.Clone()
// Replace the NameToCertificate map with a GetCertificate function
nameToCert := config.NameToCertificate
@@ -826,7 +842,7 @@ func TestHandshakeServerSNIGetCertificate(t *testing.T) {
// GetCertificate method doesn't return a cert, we fall back to what's in
// the NameToCertificate map.
func TestHandshakeServerSNIGetCertificateNotFound(t *testing.T) {
- config := testConfig.clone()
+ config := testConfig.Clone()
config.GetCertificate = func(clientHello *ClientHelloInfo) (*Certificate, error) {
return nil, nil
@@ -844,7 +860,7 @@ func TestHandshakeServerSNIGetCertificateNotFound(t *testing.T) {
func TestHandshakeServerSNIGetCertificateError(t *testing.T) {
const errMsg = "TestHandshakeServerSNIGetCertificateError error"
- serverConfig := testConfig.clone()
+ serverConfig := testConfig.Clone()
serverConfig.GetCertificate = func(clientHello *ClientHelloInfo) (*Certificate, error) {
return nil, errors.New(errMsg)
}
@@ -863,7 +879,7 @@ func TestHandshakeServerSNIGetCertificateError(t *testing.T) {
func TestHandshakeServerEmptyCertificates(t *testing.T) {
const errMsg = "TestHandshakeServerEmptyCertificates error"
- serverConfig := testConfig.clone()
+ serverConfig := testConfig.Clone()
serverConfig.GetCertificate = func(clientHello *ClientHelloInfo) (*Certificate, error) {
return nil, errors.New(errMsg)
}
@@ -891,7 +907,7 @@ func TestHandshakeServerEmptyCertificates(t *testing.T) {
// TestCipherSuiteCertPreferance ensures that we select an RSA ciphersuite with
// an RSA certificate and an ECDSA ciphersuite with an ECDSA certificate.
func TestCipherSuiteCertPreferenceECDSA(t *testing.T) {
- config := testConfig.clone()
+ config := testConfig.Clone()
config.CipherSuites = []uint16{TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA}
config.PreferServerCipherSuites = true
@@ -901,7 +917,7 @@ func TestCipherSuiteCertPreferenceECDSA(t *testing.T) {
}
runServerTestTLS12(t, test)
- config = testConfig.clone()
+ config = testConfig.Clone()
config.CipherSuites = []uint16{TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA}
config.Certificates = []Certificate{
{
@@ -925,13 +941,13 @@ func TestResumption(t *testing.T) {
test := &serverTest{
name: "IssueTicket",
- command: []string{"openssl", "s_client", "-cipher", "RC4-SHA", "-sess_out", sessionFilePath},
+ command: []string{"openssl", "s_client", "-cipher", "AES128-SHA", "-sess_out", sessionFilePath},
}
runServerTestTLS12(t, test)
test = &serverTest{
name: "Resume",
- command: []string{"openssl", "s_client", "-cipher", "RC4-SHA", "-sess_in", sessionFilePath},
+ command: []string{"openssl", "s_client", "-cipher", "AES128-SHA", "-sess_in", sessionFilePath},
}
runServerTestTLS12(t, test)
}
@@ -940,11 +956,11 @@ func TestResumptionDisabled(t *testing.T) {
sessionFilePath := tempFile("")
defer os.Remove(sessionFilePath)
- config := testConfig.clone()
+ config := testConfig.Clone()
test := &serverTest{
name: "IssueTicketPreDisable",
- command: []string{"openssl", "s_client", "-cipher", "RC4-SHA", "-sess_out", sessionFilePath},
+ command: []string{"openssl", "s_client", "-cipher", "AES128-SHA", "-sess_out", sessionFilePath},
config: config,
}
runServerTestTLS12(t, test)
@@ -953,7 +969,7 @@ func TestResumptionDisabled(t *testing.T) {
test = &serverTest{
name: "ResumeDisabled",
- command: []string{"openssl", "s_client", "-cipher", "RC4-SHA", "-sess_in", sessionFilePath},
+ command: []string{"openssl", "s_client", "-cipher", "AES128-SHA", "-sess_in", sessionFilePath},
config: config,
}
runServerTestTLS12(t, test)
@@ -976,40 +992,40 @@ func TestFallbackSCSV(t *testing.T) {
runServerTestTLS11(t, test)
}
-// cert.pem and key.pem were generated with generate_cert.go
-// Thus, they have no ExtKeyUsage fields and trigger an error
-// when verification is turned on.
+// clientCertificatePEM and clientKeyPEM were generated with generate_cert.go
+// Thus, they have no ExtKeyUsage fields and trigger an error when verification
+// is turned on.
const clientCertificatePEM = `
-----BEGIN CERTIFICATE-----
-MIIB7TCCAVigAwIBAgIBADALBgkqhkiG9w0BAQUwJjEQMA4GA1UEChMHQWNtZSBD
-bzESMBAGA1UEAxMJMTI3LjAuMC4xMB4XDTExMTIwODA3NTUxMloXDTEyMTIwNzA4
-MDAxMlowJjEQMA4GA1UEChMHQWNtZSBDbzESMBAGA1UEAxMJMTI3LjAuMC4xMIGc
-MAsGCSqGSIb3DQEBAQOBjAAwgYgCgYBO0Hsx44Jk2VnAwoekXh6LczPHY1PfZpIG
-hPZk1Y/kNqcdK+izIDZFI7Xjla7t4PUgnI2V339aEu+H5Fto5OkOdOwEin/ekyfE
-ARl6vfLcPRSr0FTKIQzQTW6HLlzF0rtNS0/Otiz3fojsfNcCkXSmHgwa2uNKWi7e
-E5xMQIhZkwIDAQABozIwMDAOBgNVHQ8BAf8EBAMCAKAwDQYDVR0OBAYEBAECAwQw
-DwYDVR0jBAgwBoAEAQIDBDALBgkqhkiG9w0BAQUDgYEANh+zegx1yW43RmEr1b3A
-p0vMRpqBWHyFeSnIyMZn3TJWRSt1tukkqVCavh9a+hoV2cxVlXIWg7nCto/9iIw4
-hB2rXZIxE0/9gzvGnfERYraL7KtnvshksBFQRlgXa5kc0x38BvEO5ZaoDPl4ILdE
-GFGNEH5PlGffo05wc46QkYU=
+MIIB7zCCAVigAwIBAgIQXBnBiWWDVW/cC8m5k5/pvDANBgkqhkiG9w0BAQsFADAS
+MRAwDgYDVQQKEwdBY21lIENvMB4XDTE2MDgxNzIxNTIzMVoXDTE3MDgxNzIxNTIz
+MVowEjEQMA4GA1UEChMHQWNtZSBDbzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkC
+gYEAum+qhr3Pv5/y71yUYHhv6BPy0ZZvzdkybiI3zkH5yl0prOEn2mGi7oHLEMff
+NFiVhuk9GeZcJ3NgyI14AvQdpJgJoxlwaTwlYmYqqyIjxXuFOE8uCXMyp70+m63K
+hAfmDzr/d8WdQYUAirab7rCkPy1MTOZCPrtRyN1IVPQMjkcCAwEAAaNGMEQwDgYD
+VR0PAQH/BAQDAgWgMBMGA1UdJQQMMAoGCCsGAQUFBwMBMAwGA1UdEwEB/wQCMAAw
+DwYDVR0RBAgwBocEfwAAATANBgkqhkiG9w0BAQsFAAOBgQBGq0Si+yhU+Fpn+GKU
+8ZqyGJ7ysd4dfm92lam6512oFmyc9wnTN+RLKzZ8Aa1B0jLYw9KT+RBrjpW5LBeK
+o0RIvFkTgxYEiKSBXCUNmAysEbEoVr4dzWFihAm/1oDGRY2CLLTYg5vbySK3KhIR
+e/oCO8HJ/+rJnahJ05XX1Q7lNQ==
-----END CERTIFICATE-----`
const clientKeyPEM = `
-----BEGIN RSA PRIVATE KEY-----
-MIICWgIBAAKBgE7QezHjgmTZWcDCh6ReHotzM8djU99mkgaE9mTVj+Q2px0r6LMg
-NkUjteOVru3g9SCcjZXff1oS74fkW2jk6Q507ASKf96TJ8QBGXq98tw9FKvQVMoh
-DNBNbocuXMXSu01LT862LPd+iOx81wKRdKYeDBra40paLt4TnExAiFmTAgMBAAEC
-gYBxvXd8yNteFTns8A/2yomEMC4yeosJJSpp1CsN3BJ7g8/qTnrVPxBy+RU+qr63
-t2WquaOu/cr5P8iEsa6lk20tf8pjKLNXeX0b1RTzK8rJLbS7nGzP3tvOhL096VtQ
-dAo4ROEaro0TzYpHmpciSvxVIeEIAAdFDObDJPKqcJAxyQJBAJizfYgK8Gzx9fsx
-hxp+VteCbVPg2euASH5Yv3K5LukRdKoSzHE2grUVQgN/LafC0eZibRanxHegYSr7
-7qaswKUCQQCEIWor/X4XTMdVj3Oj+vpiw75y/S9gh682+myZL+d/02IEkwnB098P
-RkKVpenBHyrGg0oeN5La7URILWKj7CPXAkBKo6F+d+phNjwIFoN1Xb/RA32w/D1I
-saG9sF+UEhRt9AxUfW/U/tIQ9V0ZHHcSg1XaCM5Nvp934brdKdvTOKnJAkBD5h/3
-Rybatlvg/fzBEaJFyq09zhngkxlZOUtBVTqzl17RVvY2orgH02U4HbCHy4phxOn7
-qTdQRYlHRftgnWK1AkANibn9PRYJ7mJyJ9Dyj2QeNcSkSTzrt0tPvUMf4+meJymN
-1Ntu5+S1DLLzfxlaljWG6ylW6DNxujCyuXIV2rvA
+MIICXQIBAAKBgQC6b6qGvc+/n/LvXJRgeG/oE/LRlm/N2TJuIjfOQfnKXSms4Sfa
+YaLugcsQx980WJWG6T0Z5lwnc2DIjXgC9B2kmAmjGXBpPCViZiqrIiPFe4U4Ty4J
+czKnvT6brcqEB+YPOv93xZ1BhQCKtpvusKQ/LUxM5kI+u1HI3UhU9AyORwIDAQAB
+AoGAEJZ03q4uuMb7b26WSQsOMeDsftdatT747LGgs3pNRkMJvTb/O7/qJjxoG+Mc
+qeSj0TAZXp+PXXc3ikCECAc+R8rVMfWdmp903XgO/qYtmZGCorxAHEmR80SrfMXv
+PJnznLQWc8U9nphQErR+tTESg7xWEzmFcPKwnZd1xg8ERYkCQQDTGtrFczlB2b/Z
+9TjNMqUlMnTLIk/a/rPE2fLLmAYhK5sHnJdvDURaH2mF4nso0EGtENnTsh6LATnY
+dkrxXGm9AkEA4hXHG2q3MnhgK1Z5hjv+Fnqd+8bcbII9WW4flFs15EKoMgS1w/PJ
+zbsySaSy5IVS8XeShmT9+3lrleed4sy+UwJBAJOOAbxhfXP5r4+5R6ql66jES75w
+jUCVJzJA5ORJrn8g64u2eGK28z/LFQbv9wXgCwfc72R468BdawFSLa/m2EECQGbZ
+rWiFla26IVXV0xcD98VWJsTBZMlgPnSOqoMdM1kSEd4fUmlAYI/dFzV1XYSkOmVr
+FhdZnklmpVDeu27P4c0CQQCuCOup0FlJSBpWY1TTfun/KMBkBatMz0VMA3d7FKIU
+csPezl677Yjo8u1r/KzeI6zLg87Z8E6r6ZWNc9wBSZK6
-----END RSA PRIVATE KEY-----`
const clientECDSACertificatePEM = `
@@ -1040,6 +1056,7 @@ FMBexFe01MNvja5oHt1vzobhfm6ySD6B5U7ixohLZNz1MLvT/2XMW/TdtWo+PtAd
-----END EC PRIVATE KEY-----`
func TestClientAuth(t *testing.T) {
+ setParallel(t)
var certPath, keyPath, ecdsaCertPath, ecdsaKeyPath string
if *update {
@@ -1053,19 +1070,19 @@ func TestClientAuth(t *testing.T) {
defer os.Remove(ecdsaKeyPath)
}
- config := testConfig.clone()
+ config := testConfig.Clone()
config.ClientAuth = RequestClientCert
test := &serverTest{
name: "ClientAuthRequestedNotGiven",
- command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "RC4-SHA"},
+ command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "AES128-SHA"},
config: config,
}
runServerTestTLS12(t, test)
test = &serverTest{
name: "ClientAuthRequestedAndGiven",
- command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "RC4-SHA", "-cert", certPath, "-key", keyPath},
+ command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "AES128-SHA", "-cert", certPath, "-key", keyPath},
config: config,
expectedPeerCerts: []string{clientCertificatePEM},
}
@@ -1073,13 +1090,189 @@ func TestClientAuth(t *testing.T) {
test = &serverTest{
name: "ClientAuthRequestedAndECDSAGiven",
- command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "RC4-SHA", "-cert", ecdsaCertPath, "-key", ecdsaKeyPath},
+ command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "AES128-SHA", "-cert", ecdsaCertPath, "-key", ecdsaKeyPath},
config: config,
expectedPeerCerts: []string{clientECDSACertificatePEM},
}
runServerTestTLS12(t, test)
}
+func TestSNIGivenOnFailure(t *testing.T) {
+ const expectedServerName = "test.testing"
+
+ clientHello := &clientHelloMsg{
+ vers: VersionTLS10,
+ cipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA},
+ compressionMethods: []uint8{compressionNone},
+ serverName: expectedServerName,
+ }
+
+ serverConfig := testConfig.Clone()
+ // Erase the server's cipher suites to ensure the handshake fails.
+ serverConfig.CipherSuites = nil
+
+ c, s := net.Pipe()
+ go func() {
+ cli := Client(c, testConfig)
+ cli.vers = clientHello.vers
+ cli.writeRecord(recordTypeHandshake, clientHello.marshal())
+ c.Close()
+ }()
+ hs := serverHandshakeState{
+ c: Server(s, serverConfig),
+ }
+ _, err := hs.readClientHello()
+ defer s.Close()
+
+ if err == nil {
+ t.Error("No error reported from server")
+ }
+
+ cs := hs.c.ConnectionState()
+ if cs.HandshakeComplete {
+ t.Error("Handshake registered as complete")
+ }
+
+ if cs.ServerName != expectedServerName {
+ t.Errorf("Expected ServerName of %q, but got %q", expectedServerName, cs.ServerName)
+ }
+}
+
+var getConfigForClientTests = []struct {
+ setup func(config *Config)
+ callback func(clientHello *ClientHelloInfo) (*Config, error)
+ errorSubstring string
+ verify func(config *Config) error
+}{
+ {
+ nil,
+ func(clientHello *ClientHelloInfo) (*Config, error) {
+ return nil, nil
+ },
+ "",
+ nil,
+ },
+ {
+ nil,
+ func(clientHello *ClientHelloInfo) (*Config, error) {
+ return nil, errors.New("should bubble up")
+ },
+ "should bubble up",
+ nil,
+ },
+ {
+ nil,
+ func(clientHello *ClientHelloInfo) (*Config, error) {
+ config := testConfig.Clone()
+ // Setting a maximum version of TLS 1.1 should cause
+ // the handshake to fail.
+ config.MaxVersion = VersionTLS11
+ return config, nil
+ },
+ "version 301 when expecting version 302",
+ nil,
+ },
+ {
+ func(config *Config) {
+ for i := range config.SessionTicketKey {
+ config.SessionTicketKey[i] = byte(i)
+ }
+ config.sessionTicketKeys = nil
+ },
+ func(clientHello *ClientHelloInfo) (*Config, error) {
+ config := testConfig.Clone()
+ for i := range config.SessionTicketKey {
+ config.SessionTicketKey[i] = 0
+ }
+ config.sessionTicketKeys = nil
+ return config, nil
+ },
+ "",
+ func(config *Config) error {
+ // The value of SessionTicketKey should have been
+ // duplicated into the per-connection Config.
+ for i := range config.SessionTicketKey {
+ if b := config.SessionTicketKey[i]; b != byte(i) {
+ return fmt.Errorf("SessionTicketKey was not duplicated from original Config: byte %d has value %d", i, b)
+ }
+ }
+ return nil
+ },
+ },
+ {
+ func(config *Config) {
+ var dummyKey [32]byte
+ for i := range dummyKey {
+ dummyKey[i] = byte(i)
+ }
+
+ config.SetSessionTicketKeys([][32]byte{dummyKey})
+ },
+ func(clientHello *ClientHelloInfo) (*Config, error) {
+ config := testConfig.Clone()
+ config.sessionTicketKeys = nil
+ return config, nil
+ },
+ "",
+ func(config *Config) error {
+ // The session ticket keys should have been duplicated
+ // into the per-connection Config.
+ if l := len(config.sessionTicketKeys); l != 1 {
+ return fmt.Errorf("got len(sessionTicketKeys) == %d, wanted 1", l)
+ }
+ return nil
+ },
+ },
+}
+
+func TestGetConfigForClient(t *testing.T) {
+ serverConfig := testConfig.Clone()
+ clientConfig := testConfig.Clone()
+ clientConfig.MinVersion = VersionTLS12
+
+ for i, test := range getConfigForClientTests {
+ if test.setup != nil {
+ test.setup(serverConfig)
+ }
+
+ var configReturned *Config
+ serverConfig.GetConfigForClient = func(clientHello *ClientHelloInfo) (*Config, error) {
+ config, err := test.callback(clientHello)
+ configReturned = config
+ return config, err
+ }
+ c, s := net.Pipe()
+ done := make(chan error)
+
+ go func() {
+ defer s.Close()
+ done <- Server(s, serverConfig).Handshake()
+ }()
+
+ clientErr := Client(c, clientConfig).Handshake()
+ c.Close()
+
+ serverErr := <-done
+
+ if len(test.errorSubstring) == 0 {
+ if serverErr != nil || clientErr != nil {
+ t.Errorf("test[%d]: expected no error but got serverErr: %q, clientErr: %q", i, serverErr, clientErr)
+ }
+ if test.verify != nil {
+ if err := test.verify(configReturned); err != nil {
+ t.Errorf("test[%d]: verify returned error: %v", i, err)
+ }
+ }
+ } else {
+ if serverErr == nil {
+ t.Errorf("test[%d]: expected error containing %q but got no error", i, test.errorSubstring)
+ } else if !strings.Contains(serverErr.Error(), test.errorSubstring) {
+ t.Errorf("test[%d]: expected error to contain %q but it was %q", i, test.errorSubstring, serverErr)
+ }
+ }
+ }
+}
+
func bigFromString(s string) *big.Int {
ret := new(big.Int)
ret.SetString(s, 10)
@@ -1091,23 +1284,23 @@ func fromHex(s string) []byte {
return b
}
-var testRSACertificate = fromHex("30820263308201cca003020102020900a273000c8100cbf3300d06092a864886f70d01010b0500302b31173015060355040a130e476f6f676c652054455354494e473110300e06035504031307476f20526f6f74301e170d3135303130313030303030305a170d3235303130313030303030305a302631173015060355040a130e476f6f676c652054455354494e47310b300906035504031302476f30819f300d06092a864886f70d010101050003818d0030818902818100af8788f6201b95656c14ab4405af3b4514e3b76dfd00634d957ffe6a623586c04af9187cf6aa255e7a643166 [...]
+var testRSACertificate = fromHex("3082024b308201b4a003020102020900e8f09d3fe25beaa6300d06092a864886f70d01010b0500301f310b3009060355040a1302476f3110300e06035504031307476f20526f6f74301e170d3136303130313030303030305a170d3235303130313030303030305a301a310b3009060355040a1302476f310b300906035504031302476f30819f300d06092a864886f70d010101050003818d0030818902818100db467d932e12270648bc062821ab7ec4b6a25dfe1e5245887a3647a5080d92425bc281c0be97799840fb4f6d14fd2b138bc2a52e67d8d4099ed62238b74a0b74732bc234 [...]
-var testRSACertificateIssuer = fromHex("3082024d308201b6a003020102020827326bd913b7c43d300d06092a864886f70d01010b0500302b31173015060355040a130e476f6f676c652054455354494e473110300e06035504031307476f20526f6f74301e170d3135303130313030303030305a170d3235303130313030303030305a302b31173015060355040a130e476f6f676c652054455354494e473110300e06035504031307476f20526f6f7430819f300d06092a864886f70d010101050003818d0030818902818100f0429a7b9f66a222c8453800452db355b34c4409fee09af2510a6589bfa35bdb4d453200d1 [...]
+var testRSACertificateIssuer = fromHex("3082021930820182a003020102020900ca5e4e811a965964300d06092a864886f70d01010b0500301f310b3009060355040a1302476f3110300e06035504031307476f20526f6f74301e170d3136303130313030303030305a170d3235303130313030303030305a301f310b3009060355040a1302476f3110300e06035504031307476f20526f6f7430819f300d06092a864886f70d010101050003818d0030818902818100d667b378bb22f34143b6cd2008236abefaf2852adf3ab05e01329e2c14834f5105df3f3073f99dab5442d45ee5f8f57b0111c8cb682fbb719a86944e [...]
var testECDSACertificate = fromHex("3082020030820162020900b8bf2d47a0d2ebf4300906072a8648ce3d04013045310b3009060355040613024155311330110603550408130a536f6d652d53746174653121301f060355040a1318496e7465726e6574205769646769747320507479204c7464301e170d3132313132323135303633325a170d3232313132303135303633325a3045310b3009060355040613024155311330110603550408130a536f6d652d53746174653121301f060355040a1318496e7465726e6574205769646769747320507479204c746430819b301006072a8648ce3d020106052b81040023038186 [...]
-var testSNICertificate = fromHex("308201f23082015da003020102020100300b06092a864886f70d01010530283110300e060355040a130741636d6520436f311430120603550403130b736e69746573742e636f6d301e170d3132303431313137343033355a170d3133303431313137343533355a30283110300e060355040a130741636d6520436f311430120603550403130b736e69746573742e636f6d30819d300b06092a864886f70d01010103818d0030818902818100bb79d6f517b5e5bf4610d0dc69bee62b07435ad0032d8a7a4385b71452e7a5654c2c78b8238cb5b482e5de1f953b7e62a52ca533d6fe125c7a [...]
+var testSNICertificate = fromHex("0441883421114c81480804c430820237308201a0a003020102020900e8f09d3fe25beaa6300d06092a864886f70d01010b0500301f310b3009060355040a1302476f3110300e06035504031307476f20526f6f74301e170d3136303130313030303030305a170d3235303130313030303030305a3023310b3009060355040a1302476f311430120603550403130b736e69746573742e636f6d30819f300d06092a864886f70d010101050003818d0030818902818100db467d932e12270648bc062821ab7ec4b6a25dfe1e5245887a3647a5080d92425bc281c0be97799840fb4f6d14fd2b [...]
var testRSAPrivateKey = &rsa.PrivateKey{
PublicKey: rsa.PublicKey{
- N: bigFromString("123260960069105588390096594560395120585636206567569540256061833976822892593755073841963170165000086278069699238754008398039246547214989242849418349143232951701395321381739566687846006911427966669790845430647688107009232778985142860108863460556510585049041936029324503323373417214453307648498561956908810892027L"),
+ N: bigFromString("153980389784927331788354528594524332344709972855165340650588877572729725338415474372475094155672066328274535240275856844648695200875763869073572078279316458648124537905600131008790701752441155668003033945258023841165089852359980273279085783159654751552359397986180318708491098942831252291841441726305535546071"),
E: 65537,
},
- D: bigFromString("73196363031103823625826315929954946106043759818067219550565550066527203472294428548476778865091068522665312037075674791871635825938217363523103946045078950060973913307430314113074463630778799389010335923241901501086246276485964417618981733827707048660375428006201525399194575538037883519254056917253456403553L"),
+ D: bigFromString("7746362285745539358014631136245887418412633787074173796862711588221766398229333338511838891484974940633857861775630560092874987828057333663969469797013996401149696897591265769095952887917296740109742927689053276850469671231961384712725169432413343763989564437170644270643461665184965150423819594083121075825"),
Primes: []*big.Int{
- bigFromString("11157426355495284553529769521954035649776033703833034489026848970480272318436419662860715175517581249375929775774910501512841707465207184924996975125010787L"),
- bigFromString("11047436580963564307160117670964629323534448585520694947919342920137706075617545637058809770319843170934495909554506529982972972247390145716507031692656521L"),
+ bigFromString("13299275414352936908236095374926261633419699590839189494995965049151460173257838079863316944311313904000258169883815802963543635820059341150014695560313417"),
+ bigFromString("11578103692682951732111718237224894755352163854919244905974423810539077224889290605729035287537520656160688625383765857517518932447378594964220731750802463"),
},
}
diff --git a/src/crypto/tls/handshake_test.go b/src/crypto/tls/handshake_test.go
index f95f274..8e5410a 100644
--- a/src/crypto/tls/handshake_test.go
+++ b/src/crypto/tls/handshake_test.go
@@ -13,9 +13,11 @@ import (
"io"
"io/ioutil"
"net"
+ "os/exec"
"strconv"
"strings"
"sync"
+ "testing"
)
// TLS reference tests run a connection against a reference implementation
@@ -35,7 +37,52 @@ import (
// generate fresh random numbers, large parts of the reference connection will
// always change.
-var update = flag.Bool("update", false, "update golden files on disk")
+var (
+ update = flag.Bool("update", false, "update golden files on disk")
+
+ opensslVersionTestOnce sync.Once
+ opensslVersionTestErr error
+)
+
+func checkOpenSSLVersion(t *testing.T) {
+ opensslVersionTestOnce.Do(testOpenSSLVersion)
+ if opensslVersionTestErr != nil {
+ t.Fatal(opensslVersionTestErr)
+ }
+}
+
+func testOpenSSLVersion() {
+ // This test ensures that the version of OpenSSL looks reasonable
+ // before updating the test data.
+
+ if !*update {
+ return
+ }
+
+ openssl := exec.Command("openssl", "version")
+ output, err := openssl.CombinedOutput()
+ if err != nil {
+ opensslVersionTestErr = err
+ return
+ }
+
+ version := string(output)
+ if strings.HasPrefix(version, "OpenSSL 1.1.0") {
+ return
+ }
+
+ println("***********************************************")
+ println("")
+ println("You need to build OpenSSL 1.1.0 from source in order")
+ println("to update the test data.")
+ println("")
+ println("Configure it with:")
+ println("./Configure enable-weak-ssl-ciphers enable-ssl3 enable-ssl3-method -static linux-x86_64")
+ println("and then add the apps/ directory at the front of your PATH.")
+ println("***********************************************")
+
+ opensslVersionTestErr = errors.New("version of OpenSSL does not appear to be suitable for updating test data")
+}
// recordingConn is a net.Conn that records the traffic that passes through it.
// WriteTo can be used to produce output that can be later be loaded with
@@ -88,21 +135,33 @@ func (r *recordingConn) Write(b []byte) (n int, err error) {
}
// WriteTo writes Go source code to w that contains the recorded traffic.
-func (r *recordingConn) WriteTo(w io.Writer) {
+func (r *recordingConn) WriteTo(w io.Writer) (int64, error) {
// TLS always starts with a client to server flow.
clientToServer := true
-
+ var written int64
for i, flow := range r.flows {
source, dest := "client", "server"
if !clientToServer {
source, dest = dest, source
}
- fmt.Fprintf(w, ">>> Flow %d (%s to %s)\n", i+1, source, dest)
+ n, err := fmt.Fprintf(w, ">>> Flow %d (%s to %s)\n", i+1, source, dest)
+ written += int64(n)
+ if err != nil {
+ return written, err
+ }
dumper := hex.Dumper(w)
- dumper.Write(flow)
- dumper.Close()
+ n, err = dumper.Write(flow)
+ written += int64(n)
+ if err != nil {
+ return written, err
+ }
+ err = dumper.Close()
+ if err != nil {
+ return written, err
+ }
clientToServer = !clientToServer
}
+ return written, nil
}
func parseTestData(r io.Reader) (flows [][]byte, err error) {
diff --git a/src/crypto/tls/key_agreement.go b/src/crypto/tls/key_agreement.go
index 467efb2..1b27c04 100644
--- a/src/crypto/tls/key_agreement.go
+++ b/src/crypto/tls/key_agreement.go
@@ -16,6 +16,8 @@ import (
"errors"
"io"
"math/big"
+
+ "golang_org/x/crypto/curve25519"
)
var errClientKeyExchange = errors.New("tls: invalid ClientKeyExchange message")
@@ -177,52 +179,71 @@ type ecdheKeyAgreement struct {
version uint16
sigType uint8
privateKey []byte
- curve elliptic.Curve
- x, y *big.Int
+ curveid CurveID
+
+ // publicKey is used to store the peer's public value when X25519 is
+ // being used.
+ publicKey []byte
+ // x and y are used to store the peer's public value when one of the
+ // NIST curves is being used.
+ x, y *big.Int
}
func (ka *ecdheKeyAgreement) generateServerKeyExchange(config *Config, cert *Certificate, clientHello *clientHelloMsg, hello *serverHelloMsg) (*serverKeyExchangeMsg, error) {
- var curveid CurveID
preferredCurves := config.curvePreferences()
NextCandidate:
for _, candidate := range preferredCurves {
for _, c := range clientHello.supportedCurves {
if candidate == c {
- curveid = c
+ ka.curveid = c
break NextCandidate
}
}
}
- if curveid == 0 {
+ if ka.curveid == 0 {
return nil, errors.New("tls: no supported elliptic curves offered")
}
- var ok bool
- if ka.curve, ok = curveForCurveID(curveid); !ok {
- return nil, errors.New("tls: preferredCurves includes unsupported curve")
- }
+ var ecdhePublic []byte
- var x, y *big.Int
- var err error
- ka.privateKey, x, y, err = elliptic.GenerateKey(ka.curve, config.rand())
- if err != nil {
- return nil, err
+ if ka.curveid == X25519 {
+ var scalar, public [32]byte
+ if _, err := io.ReadFull(config.rand(), scalar[:]); err != nil {
+ return nil, err
+ }
+
+ curve25519.ScalarBaseMult(&public, &scalar)
+ ka.privateKey = scalar[:]
+ ecdhePublic = public[:]
+ } else {
+ curve, ok := curveForCurveID(ka.curveid)
+ if !ok {
+ return nil, errors.New("tls: preferredCurves includes unsupported curve")
+ }
+
+ var x, y *big.Int
+ var err error
+ ka.privateKey, x, y, err = elliptic.GenerateKey(curve, config.rand())
+ if err != nil {
+ return nil, err
+ }
+ ecdhePublic = elliptic.Marshal(curve, x, y)
}
- ecdhePublic := elliptic.Marshal(ka.curve, x, y)
// http://tools.ietf.org/html/rfc4492#section-5.4
serverECDHParams := make([]byte, 1+2+1+len(ecdhePublic))
serverECDHParams[0] = 3 // named curve
- serverECDHParams[1] = byte(curveid >> 8)
- serverECDHParams[2] = byte(curveid)
+ serverECDHParams[1] = byte(ka.curveid >> 8)
+ serverECDHParams[2] = byte(ka.curveid)
serverECDHParams[3] = byte(len(ecdhePublic))
copy(serverECDHParams[4:], ecdhePublic)
sigAndHash := signatureAndHash{signature: ka.sigType}
if ka.version >= VersionTLS12 {
+ var err error
if sigAndHash.hash, err = pickTLS12HashForSignature(ka.sigType, clientHello.signatureAndHashes); err != nil {
return nil, err
}
@@ -281,15 +302,32 @@ func (ka *ecdheKeyAgreement) processClientKeyExchange(config *Config, cert *Cert
if len(ckx.ciphertext) == 0 || int(ckx.ciphertext[0]) != len(ckx.ciphertext)-1 {
return nil, errClientKeyExchange
}
- x, y := elliptic.Unmarshal(ka.curve, ckx.ciphertext[1:])
+
+ if ka.curveid == X25519 {
+ if len(ckx.ciphertext) != 1+32 {
+ return nil, errClientKeyExchange
+ }
+
+ var theirPublic, sharedKey, scalar [32]byte
+ copy(theirPublic[:], ckx.ciphertext[1:])
+ copy(scalar[:], ka.privateKey)
+ curve25519.ScalarMult(&sharedKey, &scalar, &theirPublic)
+ return sharedKey[:], nil
+ }
+
+ curve, ok := curveForCurveID(ka.curveid)
+ if !ok {
+ panic("internal error")
+ }
+ x, y := elliptic.Unmarshal(curve, ckx.ciphertext[1:])
if x == nil {
return nil, errClientKeyExchange
}
- if !ka.curve.IsOnCurve(x, y) {
+ if !curve.IsOnCurve(x, y) {
return nil, errClientKeyExchange
}
- x, _ = ka.curve.ScalarMult(x, y, ka.privateKey)
- preMasterSecret := make([]byte, (ka.curve.Params().BitSize+7)>>3)
+ x, _ = curve.ScalarMult(x, y, ka.privateKey)
+ preMasterSecret := make([]byte, (curve.Params().BitSize+7)>>3)
xBytes := x.Bytes()
copy(preMasterSecret[len(preMasterSecret)-len(xBytes):], xBytes)
@@ -303,31 +341,40 @@ func (ka *ecdheKeyAgreement) processServerKeyExchange(config *Config, clientHell
if skx.key[0] != 3 { // named curve
return errors.New("tls: server selected unsupported curve")
}
- curveid := CurveID(skx.key[1])<<8 | CurveID(skx.key[2])
-
- var ok bool
- if ka.curve, ok = curveForCurveID(curveid); !ok {
- return errors.New("tls: server selected unsupported curve")
- }
+ ka.curveid = CurveID(skx.key[1])<<8 | CurveID(skx.key[2])
publicLen := int(skx.key[3])
if publicLen+4 > len(skx.key) {
return errServerKeyExchange
}
- ka.x, ka.y = elliptic.Unmarshal(ka.curve, skx.key[4:4+publicLen])
- if ka.x == nil {
- return errServerKeyExchange
- }
- if !ka.curve.IsOnCurve(ka.x, ka.y) {
- return errServerKeyExchange
- }
serverECDHParams := skx.key[:4+publicLen]
+ publicKey := serverECDHParams[4:]
sig := skx.key[4+publicLen:]
if len(sig) < 2 {
return errServerKeyExchange
}
+ if ka.curveid == X25519 {
+ if len(publicKey) != 32 {
+ return errors.New("tls: bad X25519 public value")
+ }
+ ka.publicKey = publicKey
+ } else {
+ curve, ok := curveForCurveID(ka.curveid)
+ if !ok {
+ return errors.New("tls: server selected unsupported curve")
+ }
+
+ ka.x, ka.y = elliptic.Unmarshal(curve, publicKey)
+ if ka.x == nil {
+ return errServerKeyExchange
+ }
+ if !curve.IsOnCurve(ka.x, ka.y) {
+ return errServerKeyExchange
+ }
+ }
+
sigAndHash := signatureAndHash{signature: ka.sigType}
if ka.version >= VersionTLS12 {
// handle SignatureAndHashAlgorithm
@@ -382,19 +429,40 @@ func (ka *ecdheKeyAgreement) processServerKeyExchange(config *Config, clientHell
}
func (ka *ecdheKeyAgreement) generateClientKeyExchange(config *Config, clientHello *clientHelloMsg, cert *x509.Certificate) ([]byte, *clientKeyExchangeMsg, error) {
- if ka.curve == nil {
+ if ka.curveid == 0 {
return nil, nil, errors.New("tls: missing ServerKeyExchange message")
}
- priv, mx, my, err := elliptic.GenerateKey(ka.curve, config.rand())
- if err != nil {
- return nil, nil, err
- }
- x, _ := ka.curve.ScalarMult(ka.x, ka.y, priv)
- preMasterSecret := make([]byte, (ka.curve.Params().BitSize+7)>>3)
- xBytes := x.Bytes()
- copy(preMasterSecret[len(preMasterSecret)-len(xBytes):], xBytes)
- serialized := elliptic.Marshal(ka.curve, mx, my)
+ var serialized, preMasterSecret []byte
+
+ if ka.curveid == X25519 {
+ var ourPublic, theirPublic, sharedKey, scalar [32]byte
+
+ if _, err := io.ReadFull(config.rand(), scalar[:]); err != nil {
+ return nil, nil, err
+ }
+
+ copy(theirPublic[:], ka.publicKey)
+ curve25519.ScalarBaseMult(&ourPublic, &scalar)
+ curve25519.ScalarMult(&sharedKey, &scalar, &theirPublic)
+ serialized = ourPublic[:]
+ preMasterSecret = sharedKey[:]
+ } else {
+ curve, ok := curveForCurveID(ka.curveid)
+ if !ok {
+ panic("internal error")
+ }
+ priv, mx, my, err := elliptic.GenerateKey(curve, config.rand())
+ if err != nil {
+ return nil, nil, err
+ }
+ x, _ := curve.ScalarMult(ka.x, ka.y, priv)
+ preMasterSecret = make([]byte, (curve.Params().BitSize+7)>>3)
+ xBytes := x.Bytes()
+ copy(preMasterSecret[len(preMasterSecret)-len(xBytes):], xBytes)
+
+ serialized = elliptic.Marshal(curve, mx, my)
+ }
ckx := new(clientKeyExchangeMsg)
ckx.ciphertext = make([]byte, 1+len(serialized))
diff --git a/src/crypto/tls/testdata/Client-TLSv10-ClientCert-ECDSA-ECDSA b/src/crypto/tls/testdata/Client-TLSv10-ClientCert-ECDSA-ECDSA
index a62d27d..099cef4 100644
--- a/src/crypto/tls/testdata/Client-TLSv10-ClientCert-ECDSA-ECDSA
+++ b/src/crypto/tls/testdata/Client-TLSv10-ClientCert-ECDSA-ECDSA
@@ -1,19 +1,20 @@
>>> Flow 1 (client to server)
-00000000 16 03 01 00 85 01 00 00 81 03 03 00 00 00 00 00 |................|
+00000000 16 03 01 00 91 01 00 00 8d 03 03 00 00 00 00 00 |................|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
-00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 22 c0 2f |............."./|
-00000030 c0 2b c0 30 c0 2c c0 11 c0 07 c0 13 c0 09 c0 14 |.+.0.,..........|
-00000040 c0 0a 00 9c 00 9d 00 05 00 2f 00 35 c0 12 00 0a |........./.5....|
-00000050 01 00 00 36 00 05 00 05 01 00 00 00 00 00 0a 00 |...6............|
-00000060 08 00 06 00 17 00 18 00 19 00 0b 00 02 01 00 00 |................|
-00000070 0d 00 0e 00 0c 04 01 04 03 05 01 05 03 02 01 02 |................|
-00000080 03 ff 01 00 01 00 00 12 00 00 |..........|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2c cc a8 |.............,..|
+00000030 cc a9 c0 2f c0 2b c0 30 c0 2c c0 27 c0 13 c0 23 |.../.+.0.,.'...#|
+00000040 c0 09 c0 14 c0 0a 00 9c 00 9d 00 3c 00 2f 00 35 |...........<./.5|
+00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 38 00 05 |.............8..|
+00000060 00 05 01 00 00 00 00 00 0a 00 0a 00 08 00 1d 00 |................|
+00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 0e 00 |................|
+00000080 0c 04 01 04 03 05 01 05 03 02 01 02 03 ff 01 00 |................|
+00000090 01 00 00 12 00 00 |......|
>>> Flow 2 (server to client)
-00000000 16 03 01 00 59 02 00 00 55 03 01 38 1a 94 8d 84 |....Y...U..8....|
-00000010 d7 a4 29 89 50 ad 07 97 5b c0 2c 7b 8c a6 75 0e |..).P...[.,{..u.|
-00000020 97 51 62 10 07 87 c5 6f 0a 5f 86 20 1d ac 1d 05 |.Qb....o._. ....|
-00000030 ea 85 48 84 73 d9 07 8d d0 81 56 99 81 10 7b 18 |..H.s.....V...{.|
-00000040 e8 5e da a9 fe cd f9 91 88 31 9b 6e c0 09 00 00 |.^.......1.n....|
+00000000 16 03 01 00 59 02 00 00 55 03 01 4f 5d 09 43 37 |....Y...U..O].C7|
+00000010 70 c6 d9 8b 07 ca 1a f0 fb a7 05 51 53 67 7a 7e |p..........QSgz~|
+00000020 c9 c6 68 10 10 2a 69 bd 47 db 8e 20 f2 13 5b 26 |..h..*i.G.. ..[&|
+00000030 e6 8e 19 b0 bc b5 ee 1f ca 44 5d 32 11 37 b0 78 |.........D]2.7.x|
+00000040 49 16 6e c2 44 86 52 3f 9f 05 15 aa c0 09 00 00 |I.n.D.R?........|
00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................|
00000060 01 02 0e 0b 00 02 0a 00 02 07 00 02 04 30 82 02 |.............0..|
00000070 00 30 82 01 62 02 09 00 b8 bf 2d 47 a0 d2 eb f4 |.0..b.....-G....|
@@ -48,21 +49,20 @@
00000240 13 83 0d 94 06 bb d4 37 7a f6 ec 7a c9 86 2e dd |.......7z..z....|
00000250 d7 11 69 7f 85 7c 56 de fb 31 78 2b e4 c7 78 0d |..i..|V..1x+..x.|
00000260 ae cb be 9e 4e 36 24 31 7b 6a 0f 39 95 12 07 8f |....N6$1{j.9....|
-00000270 2a 16 03 01 00 d5 0c 00 00 d1 03 00 17 41 04 68 |*............A.h|
-00000280 37 18 3d 57 d2 5a 39 75 1e 7f 0a 3a 47 65 36 2e |7.=W.Z9u...:Ge6.|
-00000290 6d cb 8f aa 0f 0d 45 5e 3f 14 82 f5 8c b1 11 0a |m.....E^?.......|
-000002a0 8f e0 bc e4 07 d3 d5 bf 2d f4 82 ba cf c9 1c 88 |........-.......|
-000002b0 33 72 a8 49 39 48 40 74 c6 96 c3 30 72 31 34 00 |3r.I9H at t...0r14.|
-000002c0 8a 30 81 87 02 41 0e 43 2d 29 81 e9 c3 07 fc 5c |.0...A.C-).....\|
-000002d0 ad c0 51 9e 0f cf c5 77 e4 bf 00 b6 66 f9 0e c6 |..Q....w....f...|
-000002e0 40 c6 b5 49 a4 04 05 31 2c 7c 1f 24 38 80 1b 3f |@..I...1,|.$8..?|
-000002f0 16 5f c7 4d a8 7d 98 50 7f 7d 6d ed e9 19 1d 19 |._.M.}.P.}m.....|
-00000300 7b fd ec c5 4d 18 ab 02 42 01 00 db 37 b7 fa 39 |{...M...B...7..9|
-00000310 4b 3f 16 06 eb b8 4a 22 c6 de 00 d8 a7 eb a2 9e |K?....J"........|
-00000320 e1 6f f4 a4 32 e2 ca d0 72 3a e5 f3 14 27 a0 dd |.o..2...r:...'..|
-00000330 c4 26 34 b3 6c a3 d0 03 90 7a 2e 0e bf 0b 63 63 |.&4.l....z....cc|
-00000340 77 66 37 dd 1a 0f 7a 90 3f c8 a9 16 03 01 00 0e |wf7...z.?.......|
-00000350 0d 00 00 06 03 01 02 40 00 00 0e 00 00 00 |....... at ......|
+00000270 2a 16 03 01 00 b5 0c 00 00 b1 03 00 1d 20 56 b4 |*............ V.|
+00000280 39 d4 8f 18 79 87 89 d0 04 ee 12 54 20 2b be c1 |9...y......T +..|
+00000290 94 99 40 a2 73 df 1e 92 66 0b d1 f1 d6 38 00 8b |.. at .s...f....8..|
+000002a0 30 81 88 02 42 01 38 12 59 bd ea 44 59 f4 6f a9 |0...B.8.Y..DY.o.|
+000002b0 8e 9e a0 85 b5 b3 55 3e 76 49 b7 75 98 6e 81 30 |......U>vI.u.n.0|
+000002c0 c4 73 bd 54 78 39 f7 e2 22 49 4c 93 0d c1 26 89 |.s.Tx9.."IL...&.|
+000002d0 08 b9 9c 8b 86 3e 81 2c a5 50 7c e9 88 ec c0 ad |.....>.,.P|.....|
+000002e0 9e e0 40 ac 4e 0a fd 02 42 01 2e 0d 37 73 6a 0d |.. at .N...B...7sj.|
+000002f0 a4 60 08 a0 2b 32 0f 87 8d f8 9b c7 68 cf 50 79 |.`..+2......h.Py|
+00000300 73 f7 cf 93 aa 75 57 20 58 3d 13 c0 f3 66 7d 59 |s....uW X=...f}Y|
+00000310 15 73 d4 29 03 34 df 33 00 c0 b5 71 bc 2a 90 ef |.s.).4.3...q.*..|
+00000320 3c 02 5e ea 9d 29 93 1c 18 db 04 16 03 01 00 0a |<.^..)..........|
+00000330 0d 00 00 06 03 01 02 40 00 00 16 03 01 00 04 0e |....... at ........|
+00000340 00 00 00 |...|
>>> Flow 3 (client to server)
00000000 16 03 01 02 0a 0b 00 02 06 00 02 03 00 02 00 30 |...............0|
00000010 82 01 fc 30 82 01 5e 02 09 00 9a 30 84 6c 26 35 |...0..^....0.l&5|
@@ -97,34 +97,32 @@
000001e0 be e8 91 b3 da 1a f5 5d a3 23 f5 26 8b 45 70 8d |.......].#.&.Ep.|
000001f0 65 62 9b 7e 01 99 3d 18 f6 10 9a 38 61 9b 2e 57 |eb.~..=....8a..W|
00000200 e4 fa cc b1 8a ce e2 23 a0 87 f0 e1 67 51 eb 16 |.......#....gQ..|
-00000210 03 01 00 46 10 00 00 42 41 04 1e 18 37 ef 0d 19 |...F...BA...7...|
-00000220 51 88 35 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd a7 |Q.5uq..T[....g..|
-00000230 24 20 3e b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e f1 |$ >.V...(^.+-O..|
-00000240 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 a6 |..lK[.V.2B.X..I.|
-00000250 b5 68 1a 41 03 56 6b dc 5a 89 16 03 01 00 90 0f |.h.A.Vk.Z.......|
-00000260 00 00 8c 00 8a 30 81 87 02 41 51 c5 53 a8 0f cb |.....0...AQ.S...|
-00000270 18 79 4a 59 53 62 17 bb 29 39 fa cd 56 6c 5c 29 |.yJYSb..)9..Vl\)|
-00000280 1f e3 bc df fb 9a 29 fa 38 1a 73 aa 4c 79 6b 1c |......).8.s.Lyk.|
-00000290 9f 1c 8e 95 c7 11 cc df 5d e9 c7 93 ce a3 9b e6 |........].......|
-000002a0 94 17 24 3a 8e f8 9a a9 46 01 f9 02 42 01 a1 df |..$:....F...B...|
-000002b0 c5 cc fe 8d 5b 34 fb 89 2f f5 b3 3f 75 d7 19 1b |....[4../..?u...|
-000002c0 5e 0f 1a 2e 8f 2d 62 61 73 85 2c 03 3b 22 07 2f |^....-bas.,.;"./|
-000002d0 6b f3 5c fb ba b2 87 54 1c ef d2 f8 82 f3 9e f8 |k.\....T........|
-000002e0 ce 1b fa ce b0 6d d0 85 f8 62 6e d6 ba 93 cc 14 |.....m...bn.....|
-000002f0 03 01 00 01 01 16 03 01 00 30 76 90 a8 a2 8d 25 |.........0v....%|
-00000300 c5 c2 ff ef 2b 76 83 2c 7a 0d 44 37 99 67 02 d3 |....+v.,z.D7.g..|
-00000310 6e 3b 28 83 21 cf f5 6a 71 61 2d 5b 24 57 b2 19 |n;(.!..jqa-[$W..|
-00000320 63 d4 e5 96 0c 0c e1 f3 3a 99 |c.......:.|
+00000210 03 01 00 25 10 00 00 21 20 2f e5 7d a3 47 cd 62 |...%...! /.}.G.b|
+00000220 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af c4 cf |C.(.._.).0......|
+00000230 c2 ed 90 99 5f 58 cb 3b 74 16 03 01 00 91 0f 00 |...._X.;t.......|
+00000240 00 8d 00 8b 30 81 88 02 42 01 53 2c a8 59 57 d2 |....0...B.S,.YW.|
+00000250 fc 0b 12 27 6f 9a f7 4e a0 dd 2c af 1b 4c 81 0b |...'o..N..,..L..|
+00000260 97 79 7e 6f dd a1 cf cb e2 14 4d af 76 99 d8 06 |.y~o......M.v...|
+00000270 4f 8d 4f 86 d3 25 04 ea 80 02 ae 25 10 9d 2d 59 |O.O..%.....%..-Y|
+00000280 11 39 65 6b 83 d0 16 7d bf a8 a4 02 42 01 f2 16 |.9ek...}....B...|
+00000290 6c f1 e6 3b b1 af fb 3f 99 f0 8a e3 c8 62 ba 71 |l..;...?.....b.q|
+000002a0 12 a1 2c 1e 15 74 d5 98 b5 ae 9f 50 a2 15 9b 73 |..,..t.....P...s|
+000002b0 9a 5f 2c 90 d4 9d 20 6f 35 b6 32 3e f4 b7 dd 50 |._,... o5.2>...P|
+000002c0 64 42 e3 4e 51 f3 11 4b b4 9e a3 92 a2 10 59 14 |dB.NQ..K......Y.|
+000002d0 03 01 00 01 01 16 03 01 00 30 78 8c 7c 31 ce 16 |.........0x.|1..|
+000002e0 8f 1f 2a b9 ee cb 72 7f 1e 59 5b ad c2 58 32 77 |..*...r..Y[..X2w|
+000002f0 fa 46 83 b9 67 0c 5f 41 25 6a 38 ec 20 d2 80 e6 |.F..g._A%j8. ...|
+00000300 be 85 ce 94 b1 89 5f 8d 17 9b |......_...|
>>> Flow 4 (server to client)
-00000000 14 03 01 00 01 01 16 03 01 00 30 37 f0 ad 4c 11 |..........07..L.|
-00000010 6d fb 54 90 13 d2 10 93 43 d8 be 3b d0 2b 14 a5 |m.T.....C..;.+..|
-00000020 9d fb a6 5d 38 e0 f5 e9 a6 0a 8e 3d 99 a2 ec 96 |...]8......=....|
-00000030 d8 ff 90 13 03 99 33 d7 15 29 5f |......3..)_|
+00000000 14 03 01 00 01 01 16 03 01 00 30 95 d6 f2 a2 75 |..........0....u|
+00000010 0e f8 c7 7c f9 1d 65 b4 82 08 c9 62 aa 93 24 8f |...|..e....b..$.|
+00000020 4d 11 c7 b0 17 04 f1 0a 8b be 64 06 f9 07 20 0b |M.........d... .|
+00000030 f0 3b 92 db 62 ba 63 91 a1 58 fe |.;..b.c..X.|
>>> Flow 5 (client to server)
-00000000 17 03 01 00 20 f9 59 b0 e2 8b f9 2c dd 30 1b 8f |.... .Y....,.0..|
-00000010 df 85 0f 17 88 23 5e ca c9 d3 ca 5f 52 d4 33 e0 |.....#^...._R.3.|
-00000020 d2 62 54 17 f2 17 03 01 00 20 62 2d 28 d2 55 68 |.bT...... b-(.Uh|
-00000030 77 ab 6e c0 ac d9 cd 31 1c 38 aa 07 b3 e8 0d 89 |w.n....1.8......|
-00000040 7e e4 f3 a0 65 84 f6 b8 c8 91 15 03 01 00 20 b5 |~...e......... .|
-00000050 95 69 90 d7 32 d1 5a a5 e0 e2 6c 0a dc 00 1c 5e |.i..2.Z...l....^|
-00000060 d2 10 2b a2 3e ae a5 b2 63 9f c4 4e 62 56 db |..+.>...c..NbV.|
+00000000 17 03 01 00 20 3e a4 b5 b5 2f 4f c8 e0 08 cf 8a |.... >.../O.....|
+00000010 9c f6 69 94 a9 91 0f 5d c5 06 ee 71 e2 42 11 b4 |..i....]...q.B..|
+00000020 a8 17 54 19 3d 17 03 01 00 20 ce d2 8d 8a 78 e4 |..T.=.... ....x.|
+00000030 15 a4 ab 83 0d 9c fa 47 1c 8f 2d 87 a8 55 65 9d |.......G..-..Ue.|
+00000040 7f 03 75 11 62 83 0b 44 0b f1 15 03 01 00 20 eb |..u.b..D...... .|
+00000050 1a 46 95 1e 1b 10 b7 25 a8 c4 5b db 8b 3c 61 c9 |.F.....%..[..<a.|
+00000060 25 38 27 1e 69 11 18 16 0a 25 44 ad 9f 52 64 |%8'.i....%D..Rd|
diff --git a/src/crypto/tls/testdata/Client-TLSv10-ClientCert-ECDSA-RSA b/src/crypto/tls/testdata/Client-TLSv10-ClientCert-ECDSA-RSA
index 298cbe1..7e9c272 100644
--- a/src/crypto/tls/testdata/Client-TLSv10-ClientCert-ECDSA-RSA
+++ b/src/crypto/tls/testdata/Client-TLSv10-ClientCert-ECDSA-RSA
@@ -1,60 +1,72 @@
>>> Flow 1 (client to server)
-00000000 16 03 01 00 85 01 00 00 81 03 03 00 00 00 00 00 |................|
+00000000 16 03 01 00 91 01 00 00 8d 03 03 00 00 00 00 00 |................|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
-00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 22 c0 2f |............."./|
-00000030 c0 2b c0 30 c0 2c c0 11 c0 07 c0 13 c0 09 c0 14 |.+.0.,..........|
-00000040 c0 0a 00 9c 00 9d 00 05 00 2f 00 35 c0 12 00 0a |........./.5....|
-00000050 01 00 00 36 00 05 00 05 01 00 00 00 00 00 0a 00 |...6............|
-00000060 08 00 06 00 17 00 18 00 19 00 0b 00 02 01 00 00 |................|
-00000070 0d 00 0e 00 0c 04 01 04 03 05 01 05 03 02 01 02 |................|
-00000080 03 ff 01 00 01 00 00 12 00 00 |..........|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2c cc a8 |.............,..|
+00000030 cc a9 c0 2f c0 2b c0 30 c0 2c c0 27 c0 13 c0 23 |.../.+.0.,.'...#|
+00000040 c0 09 c0 14 c0 0a 00 9c 00 9d 00 3c 00 2f 00 35 |...........<./.5|
+00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 38 00 05 |.............8..|
+00000060 00 05 01 00 00 00 00 00 0a 00 0a 00 08 00 1d 00 |................|
+00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 0e 00 |................|
+00000080 0c 04 01 04 03 05 01 05 03 02 01 02 03 ff 01 00 |................|
+00000090 01 00 00 12 00 00 |......|
>>> Flow 2 (server to client)
-00000000 16 03 01 00 51 02 00 00 4d 03 01 4e 15 d3 06 f6 |....Q...M..N....|
-00000010 ec 13 16 c5 fa 59 cf 5e 2f ad 85 b9 38 e7 7f fb |.....Y.^/...8...|
-00000020 85 cb da eb f2 2e 17 51 a2 b0 be 20 61 e4 32 c9 |.......Q... a.2.|
-00000030 66 92 36 89 0c 0c f4 00 15 47 86 d9 e9 90 ab 2d |f.6......G.....-|
-00000040 8f a3 e2 5e f6 44 2c 6a 1d 98 88 5c 00 05 00 00 |...^.D,j...\....|
-00000050 05 ff 01 00 01 00 16 03 01 02 71 0b 00 02 6d 00 |..........q...m.|
-00000060 02 6a 00 02 67 30 82 02 63 30 82 01 cc a0 03 02 |.j..g0..c0......|
-00000070 01 02 02 09 00 a2 73 00 0c 81 00 cb f3 30 0d 06 |......s......0..|
-00000080 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 2b 31 17 |.*.H........0+1.|
-00000090 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 |0...U....Google |
-000000a0 54 45 53 54 49 4e 47 31 10 30 0e 06 03 55 04 03 |TESTING1.0...U..|
-000000b0 13 07 47 6f 20 52 6f 6f 74 30 1e 17 0d 31 35 30 |..Go Root0...150|
-000000c0 31 30 31 30 30 30 30 30 30 5a 17 0d 32 35 30 31 |101000000Z..2501|
-000000d0 30 31 30 30 30 30 30 30 5a 30 26 31 17 30 15 06 |01000000Z0&1.0..|
-000000e0 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 54 45 53 |.U....Google TES|
-000000f0 54 49 4e 47 31 0b 30 09 06 03 55 04 03 13 02 47 |TING1.0...U....G|
-00000100 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....|
-00000110 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 af 87 |.......0........|
-00000120 88 f6 20 1b 95 65 6c 14 ab 44 05 af 3b 45 14 e3 |.. ..el..D..;E..|
-00000130 b7 6d fd 00 63 4d 95 7f fe 6a 62 35 86 c0 4a f9 |.m..cM...jb5..J.|
-00000140 18 7c f6 aa 25 5e 7a 64 31 66 00 ba f4 8e 92 af |.|..%^zd1f......|
-00000150 c7 6b d8 76 d4 f3 5f 41 cb 6e 56 15 97 1b 97 c1 |.k.v.._A.nV.....|
-00000160 3c 12 39 21 66 3d 2b 16 d1 bc db 1c c0 a7 da b7 |<.9!f=+.........|
-00000170 ca ad ba da cb d5 21 50 ec de 8d ab d1 6b 81 4b |......!P.....k.K|
-00000180 89 02 f3 c4 be c1 6c 89 b1 44 84 bd 21 d1 04 7d |......l..D..!..}|
-00000190 9d 16 4d f9 82 15 f6 ef fa d6 09 47 f2 fb 02 03 |..M........G....|
-000001a0 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..|
-000001b0 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%|
-000001c0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........|
-000001d0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...|
-000001e0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....|
-000001f0 10 12 50 8d 89 6f 1b d1 dc 54 4d 6e cb 69 5e 06 |..P..o...TMn.i^.|
-00000200 f4 30 1b 06 03 55 1d 23 04 14 30 12 80 10 bf 3d |.0...U.#..0....=|
-00000210 b6 a9 66 f2 b8 40 cf ea b4 03 78 48 1a 41 30 19 |..f.. at ....xH.A0.|
-00000220 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp|
-00000230 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H|
-00000240 86 f7 0d 01 01 0b 05 00 03 81 81 00 92 7c af 91 |.............|..|
-00000250 55 12 18 96 59 31 a6 48 40 d5 2d d5 ee bb 02 a0 |U...Y1.H at .-.....|
-00000260 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 da 4f 3d c0 fa |...|..0}<.v.O=..|
-00000270 ae 2d 33 24 6b 03 7b 1b 67 59 11 21 b5 11 bc 77 |.-3$k.{.gY.!...w|
-00000280 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f 22 3e 63 10 6b |...n.-.5.d_">c.k|
-00000290 be ff 14 86 6d 0d f0 15 31 a8 14 38 1e 3b 84 87 |....m...1..8.;..|
-000002a0 2c cb 98 ed 51 76 b9 b1 4f dd db 9b 84 04 86 40 |,...Qv..O......@|
-000002b0 fa 51 dd ba b4 8d eb e3 46 de 46 b9 4f 86 c7 f9 |.Q......F.F.O...|
-000002c0 a4 c2 41 34 ac cc f6 ea b0 ab 39 18 16 03 01 00 |..A4......9.....|
-000002d0 0e 0d 00 00 06 03 01 02 40 00 00 0e 00 00 00 |........ at ......|
+00000000 16 03 01 00 59 02 00 00 55 03 01 32 7c 5c ac bd |....Y...U..2|\..|
+00000010 77 70 c2 f8 f0 20 37 e4 e8 45 db be 97 22 e4 f3 |wp... 7..E..."..|
+00000020 24 1c c1 29 8f 02 e1 bc ba 4a 1e 20 81 6f b5 12 |$..).....J. .o..|
+00000030 c0 9d 9e de 2f b6 04 b2 74 34 da 2b 04 55 2c 4f |..../...t4.+.U,O|
+00000040 dd 01 8a 30 d9 67 45 9f f1 31 f1 78 c0 13 00 00 |...0.gE..1.x....|
+00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................|
+00000060 01 02 59 0b 00 02 55 00 02 52 00 02 4f 30 82 02 |..Y...U..R..O0..|
+00000070 4b 30 82 01 b4 a0 03 02 01 02 02 09 00 e8 f0 9d |K0..............|
+00000080 3f e2 5b ea a6 30 0d 06 09 2a 86 48 86 f7 0d 01 |?.[..0...*.H....|
+00000090 01 0b 05 00 30 1f 31 0b 30 09 06 03 55 04 0a 13 |....0.1.0...U...|
+000000a0 02 47 6f 31 10 30 0e 06 03 55 04 03 13 07 47 6f |.Go1.0...U....Go|
+000000b0 20 52 6f 6f 74 30 1e 17 0d 31 36 30 31 30 31 30 | Root0...1601010|
+000000c0 30 30 30 30 30 5a 17 0d 32 35 30 31 30 31 30 30 |00000Z..25010100|
+000000d0 30 30 30 30 5a 30 1a 31 0b 30 09 06 03 55 04 0a |0000Z0.1.0...U..|
+000000e0 13 02 47 6f 31 0b 30 09 06 03 55 04 03 13 02 47 |..Go1.0...U....G|
+000000f0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....|
+00000100 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 db 46 |.......0.......F|
+00000110 7d 93 2e 12 27 06 48 bc 06 28 21 ab 7e c4 b6 a2 |}...'.H..(!.~...|
+00000120 5d fe 1e 52 45 88 7a 36 47 a5 08 0d 92 42 5b c2 |]..RE.z6G....B[.|
+00000130 81 c0 be 97 79 98 40 fb 4f 6d 14 fd 2b 13 8b c2 |....y. at .Om..+...|
+00000140 a5 2e 67 d8 d4 09 9e d6 22 38 b7 4a 0b 74 73 2b |..g....."8.J.ts+|
+00000150 c2 34 f1 d1 93 e5 96 d9 74 7b f3 58 9f 6c 61 3c |.4......t{.X.la<|
+00000160 c0 b0 41 d4 d9 2b 2b 24 23 77 5b 1c 3b bd 75 5d |..A..++$#w[.;.u]|
+00000170 ce 20 54 cf a1 63 87 1d 1e 24 c4 f3 1d 1a 50 8b |. T..c...$....P.|
+00000180 aa b6 14 43 ed 97 a7 75 62 f4 14 c8 52 d7 02 03 |...C...ub...R...|
+00000190 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..|
+000001a0 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%|
+000001b0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........|
+000001c0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...|
+000001d0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....|
+000001e0 10 9f 91 16 1f 43 43 3e 49 a6 de 6d b6 80 d7 9f |.....CC>I..m....|
+000001f0 60 30 1b 06 03 55 1d 23 04 14 30 12 80 10 48 13 |`0...U.#..0...H.|
+00000200 49 4d 13 7e 16 31 bb a3 01 d5 ac ab 6e 7b 30 19 |IM.~.1......n{0.|
+00000210 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp|
+00000220 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H|
+00000230 86 f7 0d 01 01 0b 05 00 03 81 81 00 9d 30 cc 40 |.............0.@|
+00000240 2b 5b 50 a0 61 cb ba e5 53 58 e1 ed 83 28 a9 58 |+[P.a...SX...(.X|
+00000250 1a a9 38 a4 95 a1 ac 31 5a 1a 84 66 3d 43 d3 2d |..8....1Z..f=C.-|
+00000260 d9 0b f2 97 df d3 20 64 38 92 24 3a 00 bc cf 9c |...... d8.$:....|
+00000270 7d b7 40 20 01 5f aa d3 16 61 09 a2 76 fd 13 c3 |}.@ ._...a..v...|
+00000280 cc e1 0c 5c ee b1 87 82 f1 6c 04 ed 73 bb b3 43 |...\.....l..s..C|
+00000290 77 8d 0c 1c f1 0f a1 d8 40 83 61 c9 4c 72 2b 9d |w....... at .a.Lr+.|
+000002a0 ae db 46 06 06 4d f4 c1 b3 3e c0 d1 bd 42 d4 db |..F..M...>...B..|
+000002b0 fe 3d 13 60 84 5c 21 d3 3b e9 fa e7 16 03 01 00 |.=.`.\!.;.......|
+000002c0 aa 0c 00 00 a6 03 00 1d 20 2f f7 3b 44 1a 47 85 |........ /.;D.G.|
+000002d0 d7 db 40 28 4e 6a f1 2f 1e b5 cc b0 58 0d 92 93 |..@(Nj./....X...|
+000002e0 30 41 65 08 05 f7 51 23 57 00 80 87 0d c3 22 ff |0Ae...Q#W.....".|
+000002f0 aa d1 3f 55 09 cf 98 dc 91 f8 d0 63 58 da dc 52 |..?U.......cX..R|
+00000300 03 f0 06 a6 4e 7e 5b 96 a1 3b d7 8e 1e 68 50 ef |....N~[..;...hP.|
+00000310 59 3f 78 06 eb 9a 33 c5 01 3c e0 fb c6 f1 b6 bc |Y?x...3..<......|
+00000320 5a bc 95 e8 43 d9 ab 36 05 26 13 c5 a6 68 9b e2 |Z...C..6.&...h..|
+00000330 b1 42 6e 89 60 5c b3 91 02 c5 8b ab 53 d1 d9 79 |.Bn.`\......S..y|
+00000340 d0 37 b5 5e 2c 16 72 29 f8 9c d0 4a 46 87 46 f4 |.7.^,.r)...JF.F.|
+00000350 01 2b e8 6a 4f 59 d1 2d 3d de 4b 3b 0e c7 cd 42 |.+.jOY.-=.K;...B|
+00000360 ae d2 94 e9 a6 6b 65 ad 3f 77 57 16 03 01 00 0a |.....ke.?wW.....|
+00000370 0d 00 00 06 03 01 02 40 00 00 16 03 01 00 04 0e |....... at ........|
+00000380 00 00 00 |...|
>>> Flow 3 (client to server)
00000000 16 03 01 02 0a 0b 00 02 06 00 02 03 00 02 00 30 |...............0|
00000010 82 01 fc 30 82 01 5e 02 09 00 9a 30 84 6c 26 35 |...0..^....0.l&5|
@@ -89,33 +101,32 @@
000001e0 be e8 91 b3 da 1a f5 5d a3 23 f5 26 8b 45 70 8d |.......].#.&.Ep.|
000001f0 65 62 9b 7e 01 99 3d 18 f6 10 9a 38 61 9b 2e 57 |eb.~..=....8a..W|
00000200 e4 fa cc b1 8a ce e2 23 a0 87 f0 e1 67 51 eb 16 |.......#....gQ..|
-00000210 03 01 00 86 10 00 00 82 00 80 73 bd 73 65 92 86 |..........s.se..|
-00000220 23 41 14 79 7f d5 c1 10 ce 94 4d ad 9c c3 a9 87 |#A.y......M.....|
-00000230 b5 32 52 f8 6b 11 93 2d 9b 98 0b 8b 1d c0 f6 53 |.2R.k..-.......S|
-00000240 17 6d c7 9c 2e ae c9 6f cc 99 23 38 37 1a 10 fe |.m.....o..#87...|
-00000250 05 0b b5 55 0a 14 e9 60 7d 70 26 98 e2 54 d9 65 |...U...`}p&..T.e|
-00000260 cf 2e f4 53 5f 1d aa 3a f6 33 7b eb 4c 0e b3 ff |...S_..:.3{.L...|
-00000270 5a db 36 2a 47 f3 df f9 fc f5 31 78 83 aa 6b 52 |Z.6*G.....1x..kR|
-00000280 b7 ba 1a 96 bc fa c1 a1 a9 bb 2b f5 38 89 00 4d |..........+.8..M|
-00000290 e5 78 13 4e a4 38 46 42 dc 16 16 03 01 00 91 0f |.x.N.8FB........|
-000002a0 00 00 8d 00 8b 30 81 88 02 42 01 45 b9 8f b1 1f |.....0...B.E....|
-000002b0 72 80 2c 4f 2c 65 58 db 40 7e f1 d5 14 0b cc 4c |r.,O,eX.@~.....L|
-000002c0 8b 50 5c ee 93 45 95 3d fe 00 5e 5e ca 13 56 8d |.P\..E.=..^^..V.|
-000002d0 2b b3 1a 22 70 3f d2 41 cf 74 8f c3 0f 37 ba 97 |+.."p?.A.t...7..|
-000002e0 cb 29 16 77 92 df 19 35 f9 8a a0 8e 02 42 01 00 |.).w...5.....B..|
-000002f0 3f 8b ce b1 2a 01 43 e8 2c b5 27 d1 19 bc 04 b3 |?...*.C.,.'.....|
-00000300 c3 ad bf e8 12 37 57 6f c9 01 7c 8e f4 4d 88 39 |.....7Wo..|..M.9|
-00000310 4b 00 f6 ff fd 38 39 f8 3e 7f 49 d4 6a 82 94 6a |K....89.>.I.j..j|
-00000320 d3 f4 17 f2 a9 e0 ef 85 1e 01 85 b6 ca 89 91 ee |................|
-00000330 14 03 01 00 01 01 16 03 01 00 24 8d 82 24 82 55 |..........$..$.U|
-00000340 c4 0e 45 8c f0 f3 e3 29 4e ff 6c ee 43 4b ca 68 |..E....)N.l.CK.h|
-00000350 2e 12 98 cf ce b6 7e fa 73 07 e1 0f aa 7f 80 |......~.s......|
+00000210 03 01 00 25 10 00 00 21 20 2f e5 7d a3 47 cd 62 |...%...! /.}.G.b|
+00000220 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af c4 cf |C.(.._.).0......|
+00000230 c2 ed 90 99 5f 58 cb 3b 74 16 03 01 00 91 0f 00 |...._X.;t.......|
+00000240 00 8d 00 8b 30 81 88 02 42 01 b3 df 59 06 71 e6 |....0...B...Y.q.|
+00000250 74 c9 9d d5 2c b0 a7 f8 1e ac bc f3 5a e2 ed 0b |t...,.......Z...|
+00000260 f2 e9 37 82 c6 fe 7c 23 b9 63 6e 88 1d 63 31 ad |..7...|#.cn..c1.|
+00000270 d3 29 48 eb f3 5d 52 f5 76 ab fc 16 9e 09 4f 49 |.)H..]R.v.....OI|
+00000280 cf b4 03 6a ed db e5 13 ea 67 74 02 42 01 8e 2f |...j.....gt.B../|
+00000290 b8 12 38 c9 a6 8c 77 40 85 89 ef d8 ac 08 00 c0 |..8...w at ........|
+000002a0 ee 70 68 a6 88 1f d1 67 0d 1b 7b 1f be e0 a7 b9 |.ph....g..{.....|
+000002b0 c3 7d ff 6a 39 3c b9 aa f6 78 ac 9a ca 67 55 0c |.}.j9<...x...gU.|
+000002c0 38 23 cc ab 18 c0 b9 ea 9c 84 61 32 0a 0d f3 14 |8#........a2....|
+000002d0 03 01 00 01 01 16 03 01 00 30 73 12 76 94 30 37 |.........0s.v.07|
+000002e0 e5 e3 30 59 88 2f 5f e9 f2 7b 3d 02 88 65 09 14 |..0Y./_..{=..e..|
+000002f0 68 23 02 d0 ae e5 7f 7f 8d 95 3b 1c 75 f5 1f 24 |h#........;.u..$|
+00000300 43 60 29 bb 0e 69 88 36 a9 68 |C`)..i.6.h|
>>> Flow 4 (server to client)
-00000000 14 03 01 00 01 01 16 03 01 00 24 21 a3 eb a6 f5 |..........$!....|
-00000010 d0 17 38 9b 89 ec f3 39 23 33 f6 49 51 41 97 92 |..8....9#3.IQA..|
-00000020 a6 64 bd 60 68 9d 0e 45 06 2f dd ff 79 b6 50 |.d.`h..E./..y.P|
+00000000 14 03 01 00 01 01 16 03 01 00 30 a0 5f 7f 59 e0 |..........0._.Y.|
+00000010 b1 7e ed ad de 6a 47 94 21 e5 1b 77 a7 d0 88 fd |.~...jG.!..w....|
+00000020 9e 4e 48 87 1d cf 40 e4 b9 38 a3 2e e4 00 c3 94 |.NH... at ..8......|
+00000030 95 20 1c 97 d2 a9 3a 11 86 30 5f |. ....:..0_|
>>> Flow 5 (client to server)
-00000000 17 03 01 00 1a d2 72 d5 91 9d fc 6c 22 02 cc 32 |......r....l"..2|
-00000010 58 5c 8a f6 75 11 48 e1 3f e4 e5 81 29 63 62 15 |X\..u.H.?...)cb.|
-00000020 03 01 00 16 b6 9a 1f 43 d4 ae b7 16 25 ce ae b7 |.......C....%...|
-00000030 6c 37 f7 35 0a 26 7d ea 1f 80 |l7.5.&}...|
+00000000 17 03 01 00 20 ca 4c f5 cb 81 66 2f 97 e3 5d 8b |.... .L...f/..].|
+00000010 dd 7d dd fa fe 8c 98 45 3f 3d 16 17 98 4d b5 15 |.}.....E?=...M..|
+00000020 6c 91 8a 79 7a 17 03 01 00 20 96 ec 30 cb d3 78 |l..yz.... ..0..x|
+00000030 b9 0a a1 ab fd 12 25 d5 82 7b 7a 3c 17 56 7b b7 |......%..{z<.V{.|
+00000040 c4 6e ea a2 5b d7 6b b6 22 a9 15 03 01 00 20 ba |.n..[.k."..... .|
+00000050 ff fe 2b 60 83 34 ad 45 75 15 d5 95 b3 27 92 46 |..+`.4.Eu....'.F|
+00000060 47 ae f1 d4 a4 9d 63 ef db d9 b5 37 0f f1 74 |G.....c....7..t|
diff --git a/src/crypto/tls/testdata/Client-TLSv10-ClientCert-RSA-ECDSA b/src/crypto/tls/testdata/Client-TLSv10-ClientCert-RSA-ECDSA
index ba4976d..67772e1 100644
--- a/src/crypto/tls/testdata/Client-TLSv10-ClientCert-RSA-ECDSA
+++ b/src/crypto/tls/testdata/Client-TLSv10-ClientCert-RSA-ECDSA
@@ -1,19 +1,20 @@
>>> Flow 1 (client to server)
-00000000 16 03 01 00 85 01 00 00 81 03 03 00 00 00 00 00 |................|
+00000000 16 03 01 00 91 01 00 00 8d 03 03 00 00 00 00 00 |................|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
-00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 22 c0 2f |............."./|
-00000030 c0 2b c0 30 c0 2c c0 11 c0 07 c0 13 c0 09 c0 14 |.+.0.,..........|
-00000040 c0 0a 00 9c 00 9d 00 05 00 2f 00 35 c0 12 00 0a |........./.5....|
-00000050 01 00 00 36 00 05 00 05 01 00 00 00 00 00 0a 00 |...6............|
-00000060 08 00 06 00 17 00 18 00 19 00 0b 00 02 01 00 00 |................|
-00000070 0d 00 0e 00 0c 04 01 04 03 05 01 05 03 02 01 02 |................|
-00000080 03 ff 01 00 01 00 00 12 00 00 |..........|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2c cc a8 |.............,..|
+00000030 cc a9 c0 2f c0 2b c0 30 c0 2c c0 27 c0 13 c0 23 |.../.+.0.,.'...#|
+00000040 c0 09 c0 14 c0 0a 00 9c 00 9d 00 3c 00 2f 00 35 |...........<./.5|
+00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 38 00 05 |.............8..|
+00000060 00 05 01 00 00 00 00 00 0a 00 0a 00 08 00 1d 00 |................|
+00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 0e 00 |................|
+00000080 0c 04 01 04 03 05 01 05 03 02 01 02 03 ff 01 00 |................|
+00000090 01 00 00 12 00 00 |......|
>>> Flow 2 (server to client)
-00000000 16 03 01 00 59 02 00 00 55 03 01 eb ed 76 6a 07 |....Y...U....vj.|
-00000010 65 02 ec 6f 93 a0 38 21 09 0d d7 bf 11 20 51 eb |e..o..8!..... Q.|
-00000020 cc 00 08 9b 7a 98 c4 c5 02 ff c1 20 f9 1b c7 66 |....z...... ...f|
-00000030 35 40 8c 67 8d 7f d5 c8 28 f0 cb d2 f9 da af 7a |5 at .g....(......z|
-00000040 ea 4e 42 f2 5d 44 1c cc 92 36 b1 10 c0 09 00 00 |.NB.]D...6......|
+00000000 16 03 01 00 59 02 00 00 55 03 01 ed 13 de 15 cc |....Y...U.......|
+00000010 90 4f f3 72 5a d4 7a 01 26 fa 7a ae 38 92 a0 d6 |.O.rZ.z.&.z.8...|
+00000020 70 4a 20 f6 7e 11 f7 ac e6 94 87 20 9f 37 0f 8f |pJ .~...... .7..|
+00000030 55 a6 6a 97 b8 0f 56 aa 2d 69 c5 79 01 d5 c0 01 |U.j...V.-i.y....|
+00000040 2c 2b 0e 16 d8 79 a3 f3 44 99 7c 01 c0 09 00 00 |,+...y..D.|.....|
00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................|
00000060 01 02 0e 0b 00 02 0a 00 02 07 00 02 04 30 82 02 |.............0..|
00000070 00 30 82 01 62 02 09 00 b8 bf 2d 47 a0 d2 eb f4 |.0..b.....-G....|
@@ -48,82 +49,79 @@
00000240 13 83 0d 94 06 bb d4 37 7a f6 ec 7a c9 86 2e dd |.......7z..z....|
00000250 d7 11 69 7f 85 7c 56 de fb 31 78 2b e4 c7 78 0d |..i..|V..1x+..x.|
00000260 ae cb be 9e 4e 36 24 31 7b 6a 0f 39 95 12 07 8f |....N6$1{j.9....|
-00000270 2a 16 03 01 00 d5 0c 00 00 d1 03 00 17 41 04 34 |*............A.4|
-00000280 47 57 64 b3 20 6d eb 17 9c 36 d4 aa 78 8b 20 26 |GWd. m...6..x. &|
-00000290 6f 22 10 79 5f 96 69 62 1d ae 9f c7 40 17 1e 30 |o".y_.ib.... at ..0|
-000002a0 10 db d1 13 51 d8 63 61 ef 8e fb 34 d6 02 95 ac |....Q.ca...4....|
-000002b0 fb 33 72 a9 46 ff 27 b1 15 ca dd 81 8f 5a 58 00 |.3r.F.'......ZX.|
-000002c0 8a 30 81 87 02 41 5c 09 1a 87 40 f3 1a 87 84 31 |.0...A\... at ....1|
-000002d0 62 6c e5 a5 c0 3c cc ba 5d 4a 5e 65 ea e0 60 83 |bl...<..]J^e..`.|
-000002e0 fe fe 99 1d 66 4a bb 6c 0d 5e 25 64 e3 92 ce eb |....fJ.l.^%d....|
-000002f0 15 39 42 a6 b0 98 a1 d3 79 65 c7 fc e7 c7 64 c7 |.9B.....ye....d.|
-00000300 69 9c 2f 7e 00 c1 a3 02 42 01 f2 61 91 ae 8e f6 |i./~....B..a....|
-00000310 88 99 70 55 32 4a fe 08 31 f0 8d d6 e6 1d fa a1 |..pU2J..1.......|
-00000320 76 b6 16 98 58 8e 46 30 b1 00 b6 dd 5d 70 bb e1 |v...X.F0....]p..|
-00000330 81 89 bd aa ac b5 7f 9b d3 c0 8b 4b c3 36 00 87 |...........K.6..|
-00000340 47 0c 34 92 27 c3 aa bd 0d 7c 36 16 03 01 00 0e |G.4.'....|6.....|
-00000350 0d 00 00 06 03 01 02 40 00 00 0e 00 00 00 |....... at ......|
+00000270 2a 16 03 01 00 b4 0c 00 00 b0 03 00 1d 20 ca e8 |*............ ..|
+00000280 ef 79 56 cd aa eb 12 8f e1 89 d1 3c 63 1f c8 54 |.yV........<c..T|
+00000290 5f 4e cf 6b 72 7d 1c bb f6 80 ae 17 33 69 00 8a |_N.kr}......3i..|
+000002a0 30 81 87 02 42 01 d1 45 df fc 46 21 5b 9b 49 f0 |0...B..E..F![.I.|
+000002b0 3c f2 16 65 1e 33 90 d8 be 1d 65 12 2f 46 93 5b |<..e.3....e./F.[|
+000002c0 e2 14 67 b8 67 9b c1 10 31 a1 96 b8 86 c3 8b 26 |..g.g...1......&|
+000002d0 3f da 5e 86 e7 b1 f9 3f f1 04 57 ed e6 6f a5 86 |?.^....?..W..o..|
+000002e0 f7 58 38 6e 0d ae 42 02 41 05 1b 07 9b 4c 4d 39 |.X8n..B.A....LM9|
+000002f0 2d 0c 4e d7 94 d6 86 c9 6c b9 4d 54 a2 56 87 12 |-.N.....l.MT.V..|
+00000300 08 ec 4e f1 a4 19 5e 52 69 ed 9f 6c 59 5f 31 0f |..N...^Ri..lY_1.|
+00000310 8d 33 1f a7 42 e5 56 9d 54 f4 18 9b 33 31 97 b9 |.3..B.V.T...31..|
+00000320 57 55 c9 9f ea 7d f2 9e 24 e0 16 03 01 00 0a 0d |WU...}..$.......|
+00000330 00 00 06 03 01 02 40 00 00 16 03 01 00 04 0e 00 |...... at .........|
+00000340 00 00 |..|
>>> Flow 3 (client to server)
-00000000 16 03 01 01 fb 0b 00 01 f7 00 01 f4 00 01 f1 30 |...............0|
-00000010 82 01 ed 30 82 01 58 a0 03 02 01 02 02 01 00 30 |...0..X........0|
-00000020 0b 06 09 2a 86 48 86 f7 0d 01 01 05 30 26 31 10 |...*.H......0&1.|
-00000030 30 0e 06 03 55 04 0a 13 07 41 63 6d 65 20 43 6f |0...U....Acme Co|
-00000040 31 12 30 10 06 03 55 04 03 13 09 31 32 37 2e 30 |1.0...U....127.0|
-00000050 2e 30 2e 31 30 1e 17 0d 31 31 31 32 30 38 30 37 |.0.10...11120807|
-00000060 35 35 31 32 5a 17 0d 31 32 31 32 30 37 30 38 30 |5512Z..121207080|
-00000070 30 31 32 5a 30 26 31 10 30 0e 06 03 55 04 0a 13 |012Z0&1.0...U...|
-00000080 07 41 63 6d 65 20 43 6f 31 12 30 10 06 03 55 04 |.Acme Co1.0...U.|
-00000090 03 13 09 31 32 37 2e 30 2e 30 2e 31 30 81 9c 30 |...127.0.0.10..0|
-000000a0 0b 06 09 2a 86 48 86 f7 0d 01 01 01 03 81 8c 00 |...*.H..........|
-000000b0 30 81 88 02 81 80 4e d0 7b 31 e3 82 64 d9 59 c0 |0.....N.{1..d.Y.|
-000000c0 c2 87 a4 5e 1e 8b 73 33 c7 63 53 df 66 92 06 84 |...^..s3.cS.f...|
-000000d0 f6 64 d5 8f e4 36 a7 1d 2b e8 b3 20 36 45 23 b5 |.d...6..+.. 6E#.|
-000000e0 e3 95 ae ed e0 f5 20 9c 8d 95 df 7f 5a 12 ef 87 |...... .....Z...|
-000000f0 e4 5b 68 e4 e9 0e 74 ec 04 8a 7f de 93 27 c4 01 |.[h...t......'..|
-00000100 19 7a bd f2 dc 3d 14 ab d0 54 ca 21 0c d0 4d 6e |.z...=...T.!..Mn|
-00000110 87 2e 5c c5 d2 bb 4d 4b 4f ce b6 2c f7 7e 88 ec |..\...MKO..,.~..|
-00000120 7c d7 02 91 74 a6 1e 0c 1a da e3 4a 5a 2e de 13 ||...t......JZ...|
-00000130 9c 4c 40 88 59 93 02 03 01 00 01 a3 32 30 30 30 |.L at .Y.......2000|
-00000140 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 00 a0 30 |...U...........0|
-00000150 0d 06 03 55 1d 0e 04 06 04 04 01 02 03 04 30 0f |...U..........0.|
-00000160 06 03 55 1d 23 04 08 30 06 80 04 01 02 03 04 30 |..U.#..0.......0|
-00000170 0b 06 09 2a 86 48 86 f7 0d 01 01 05 03 81 81 00 |...*.H..........|
-00000180 36 1f b3 7a 0c 75 c9 6e 37 46 61 2b d5 bd c0 a7 |6..z.u.n7Fa+....|
-00000190 4b cc 46 9a 81 58 7c 85 79 29 c8 c8 c6 67 dd 32 |K.F..X|.y)...g.2|
-000001a0 56 45 2b 75 b6 e9 24 a9 50 9a be 1f 5a fa 1a 15 |VE+u..$.P...Z...|
-000001b0 d9 cc 55 95 72 16 83 b9 c2 b6 8f fd 88 8c 38 84 |..U.r.........8.|
-000001c0 1d ab 5d 92 31 13 4f fd 83 3b c6 9d f1 11 62 b6 |..].1.O..;....b.|
-000001d0 8b ec ab 67 be c8 64 b0 11 50 46 58 17 6b 99 1c |...g..d..PFX.k..|
-000001e0 d3 1d fc 06 f1 0e e5 96 a8 0c f9 78 20 b7 44 18 |...........x .D.|
-000001f0 51 8d 10 7e 4f 94 67 df a3 4e 70 73 8e 90 91 85 |Q..~O.g..Nps....|
-00000200 16 03 01 00 46 10 00 00 42 41 04 1e 18 37 ef 0d |....F...BA...7..|
-00000210 19 51 88 35 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd |.Q.5uq..T[....g.|
-00000220 a7 24 20 3e b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e |.$ >.V...(^.+-O.|
-00000230 f1 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 |...lK[.V.2B.X..I|
-00000240 a6 b5 68 1a 41 03 56 6b dc 5a 89 16 03 01 00 86 |..h.A.Vk.Z......|
-00000250 0f 00 00 82 00 80 1e 4d 89 4e e2 82 ca 5d 31 8a |.......M.N...]1.|
-00000260 66 c7 c2 d6 00 4d 2e 1e 94 34 61 6b 86 3d 78 60 |f....M...4ak.=x`|
-00000270 70 e1 71 93 22 df 5d 81 d3 d7 33 10 f5 01 f9 1d |p.q.".]...3.....|
-00000280 e2 4a 91 22 67 ae 5b 2f 4c d9 43 31 35 c6 01 ad |.J."g.[/L.C15...|
-00000290 59 86 03 a1 9b c5 ea a5 2d aa ef 46 5a a8 70 57 |Y.......-..FZ.pW|
-000002a0 50 59 ea 7a 07 32 bb a6 a1 11 33 05 d8 88 2e 42 |PY.z.2....3....B|
-000002b0 d8 7b f7 34 be 5e 5f 42 9f 6a 90 ed d7 4b c4 7e |.{.4.^_B.j...K.~|
-000002c0 f9 5c a5 ff 28 f8 a1 f1 8f 1c e0 7a 37 a0 49 e5 |.\..(......z7.I.|
-000002d0 ce 11 46 ef 5f 06 14 03 01 00 01 01 16 03 01 00 |..F._...........|
-000002e0 30 cb 08 f0 3c d4 21 f2 3a 7d db 59 75 80 48 24 |0...<.!.:}.Yu.H$|
-000002f0 27 6f 2c 26 50 a4 7d 6c 91 d5 5d f7 c9 b4 bd 15 |'o,&P.}l..].....|
-00000300 a8 8a 12 d5 40 8c 9a 0f 56 67 66 89 dd 12 36 d8 |.... at ...Vgf...6.|
-00000310 d3 |.|
+00000000 16 03 01 01 fd 0b 00 01 f9 00 01 f6 00 01 f3 30 |...............0|
+00000010 82 01 ef 30 82 01 58 a0 03 02 01 02 02 10 5c 19 |...0..X.......\.|
+00000020 c1 89 65 83 55 6f dc 0b c9 b9 93 9f e9 bc 30 0d |..e.Uo........0.|
+00000030 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 12 31 |..*.H........0.1|
+00000040 10 30 0e 06 03 55 04 0a 13 07 41 63 6d 65 20 43 |.0...U....Acme C|
+00000050 6f 30 1e 17 0d 31 36 30 38 31 37 32 31 35 32 33 |o0...16081721523|
+00000060 31 5a 17 0d 31 37 30 38 31 37 32 31 35 32 33 31 |1Z..170817215231|
+00000070 5a 30 12 31 10 30 0e 06 03 55 04 0a 13 07 41 63 |Z0.1.0...U....Ac|
+00000080 6d 65 20 43 6f 30 81 9f 30 0d 06 09 2a 86 48 86 |me Co0..0...*.H.|
+00000090 f7 0d 01 01 01 05 00 03 81 8d 00 30 81 89 02 81 |...........0....|
+000000a0 81 00 ba 6f aa 86 bd cf bf 9f f2 ef 5c 94 60 78 |...o........\.`x|
+000000b0 6f e8 13 f2 d1 96 6f cd d9 32 6e 22 37 ce 41 f9 |o.....o..2n"7.A.|
+000000c0 ca 5d 29 ac e1 27 da 61 a2 ee 81 cb 10 c7 df 34 |.])..'.a.......4|
+000000d0 58 95 86 e9 3d 19 e6 5c 27 73 60 c8 8d 78 02 f4 |X...=..\'s`..x..|
+000000e0 1d a4 98 09 a3 19 70 69 3c 25 62 66 2a ab 22 23 |......pi<%bf*."#|
+000000f0 c5 7b 85 38 4f 2e 09 73 32 a7 bd 3e 9b ad ca 84 |.{.8O..s2..>....|
+00000100 07 e6 0f 3a ff 77 c5 9d 41 85 00 8a b6 9b ee b0 |...:.w..A.......|
+00000110 a4 3f 2d 4c 4c e6 42 3e bb 51 c8 dd 48 54 f4 0c |.?-LL.B>.Q..HT..|
+00000120 8e 47 02 03 01 00 01 a3 46 30 44 30 0e 06 03 55 |.G......F0D0...U|
+00000130 1d 0f 01 01 ff 04 04 03 02 05 a0 30 13 06 03 55 |...........0...U|
+00000140 1d 25 04 0c 30 0a 06 08 2b 06 01 05 05 07 03 01 |.%..0...+.......|
+00000150 30 0c 06 03 55 1d 13 01 01 ff 04 02 30 00 30 0f |0...U.......0.0.|
+00000160 06 03 55 1d 11 04 08 30 06 87 04 7f 00 00 01 30 |..U....0.......0|
+00000170 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 03 81 |...*.H..........|
+00000180 81 00 46 ab 44 a2 fb 28 54 f8 5a 67 f8 62 94 f1 |..F.D..(T.Zg.b..|
+00000190 9a b2 18 9e f2 b1 de 1d 7e 6f 76 95 a9 ba e7 5d |........~ov....]|
+000001a0 a8 16 6c 9c f7 09 d3 37 e4 4b 2b 36 7c 01 ad 41 |..l....7.K+6|..A|
+000001b0 d2 32 d8 c3 d2 93 f9 10 6b 8e 95 b9 2c 17 8a a3 |.2......k...,...|
+000001c0 44 48 bc 59 13 83 16 04 88 a4 81 5c 25 0d 98 0c |DH.Y.......\%...|
+000001d0 ac 11 b1 28 56 be 1d cd 61 62 84 09 bf d6 80 c6 |...(V...ab......|
+000001e0 45 8d 82 2c b4 d8 83 9b db c9 22 b7 2a 12 11 7b |E..,......".*..{|
+000001f0 fa 02 3b c1 c9 ff ea c9 9d a8 49 d3 95 d7 d5 0e |..;.......I.....|
+00000200 e5 35 16 03 01 00 25 10 00 00 21 20 2f e5 7d a3 |.5....%...! /.}.|
+00000210 47 cd 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 |G.bC.(.._.).0...|
+00000220 af c4 cf c2 ed 90 99 5f 58 cb 3b 74 16 03 01 00 |......._X.;t....|
+00000230 86 0f 00 00 82 00 80 8f 6f 77 5d d5 99 28 0c 7a |........ow]..(.z|
+00000240 36 f2 50 ec 9a e6 eb 88 ac 45 f7 9b 6f 98 84 ba |6.P......E..o...|
+00000250 fb 3c b8 d6 54 61 b8 87 25 50 3c 31 5a d2 c1 54 |.<..Ta..%P<1Z..T|
+00000260 e8 ed c3 93 cc 98 b1 c3 d4 84 11 d8 a0 c7 ae 67 |...............g|
+00000270 67 35 6a 0f 93 18 bb 18 52 f8 25 88 1f d2 19 4d |g5j.....R.%....M|
+00000280 3b 4c f2 0f f7 06 68 57 cf 45 20 e0 57 75 37 e9 |;L....hW.E .Wu7.|
+00000290 cd 86 1f e5 d2 90 1e cf 3a 18 fd 45 bc a1 84 63 |........:..E...c|
+000002a0 36 d8 ac 6b 09 41 da 0a 87 7f ab ce 8e 49 e6 c8 |6..k.A.......I..|
+000002b0 bf fb 2c 3b 7b e9 ae 14 03 01 00 01 01 16 03 01 |..,;{...........|
+000002c0 00 30 7d 65 9c c1 25 e4 85 d7 39 d4 67 cf eb f1 |.0}e..%...9.g...|
+000002d0 b7 c2 4d e6 5d bd 13 74 55 22 f0 8a 7e a6 a2 eb |..M.]..tU"..~...|
+000002e0 93 cc b7 fa 86 b1 b5 e0 a3 ef ee 56 f0 cd f7 a5 |...........V....|
+000002f0 d8 9e |..|
>>> Flow 4 (server to client)
-00000000 14 03 01 00 01 01 16 03 01 00 30 02 e3 be 9d 2d |..........0....-|
-00000010 6f 2c 9a b7 b4 f1 a5 30 ec 3e ae 05 e6 02 19 2f |o,.....0.>...../|
-00000020 a4 ac d1 6e ac de 75 4e cc 14 e6 78 5a ea 27 7f |...n..uN...xZ.'.|
-00000030 4e 45 c4 9d b2 da a6 ea b7 d2 7e |NE........~|
+00000000 14 03 01 00 01 01 16 03 01 00 30 ff 13 14 c5 ad |..........0.....|
+00000010 88 ec a1 cf cc 0d 3f 7b ec 50 4a 25 69 1f 18 dc |......?{.PJ%i...|
+00000020 b1 99 1f 3b 78 60 e0 83 c0 cd 9a b3 0d 59 0b f8 |...;x`.......Y..|
+00000030 8a b7 7c 2c b4 2c e4 d0 49 82 82 |..|,.,..I..|
>>> Flow 5 (client to server)
-00000000 17 03 01 00 20 e0 71 e9 54 11 6e 48 4b be a2 2a |.... .q.T.nHK..*|
-00000010 b1 70 d2 2c 74 c0 f4 74 05 f1 d3 d6 84 29 58 f7 |.p.,t..t.....)X.|
-00000020 87 90 84 2b c8 17 03 01 00 20 b6 a2 e9 e0 f0 0d |...+..... ......|
-00000030 d5 ef d7 32 6d cb 99 5d a6 37 c2 6e f9 c3 8e 6f |...2m..].7.n...o|
-00000040 76 71 d8 a6 c5 ae 4e 04 77 06 15 03 01 00 20 f2 |vq....N.w..... .|
-00000050 09 ab dc 37 90 78 3a 2a 41 ab 9b a9 c1 78 2a 64 |...7.x:*A....x*d|
-00000060 a8 3f 21 c4 bb af 76 b3 c6 2f e1 20 a3 b1 1e |.?!...v../. ...|
+00000000 17 03 01 00 20 51 91 74 f6 31 07 15 6b 9e 0b 28 |.... Q.t.1..k..(|
+00000010 02 b8 ec 9d c6 e3 15 24 d3 ea 4b 27 d0 fa 9f c2 |.......$..K'....|
+00000020 c4 8d 37 b3 d9 17 03 01 00 20 7d 97 75 fe de 3f |..7...... }.u..?|
+00000030 ae ab e6 a8 1d 76 1c 06 9c 02 61 cc f5 1d fe c8 |.....v....a.....|
+00000040 a2 dc ae 97 7f 1c 05 19 e5 14 15 03 01 00 20 4a |.............. J|
+00000050 bc 45 97 6b 09 8e 47 5f d5 a0 97 78 79 67 09 8d |.E.k..G_...xyg..|
+00000060 d3 80 38 58 5c cc ae 8e d4 67 1d 93 2b 20 79 |..8X\....g..+ y|
diff --git a/src/crypto/tls/testdata/Client-TLSv10-ClientCert-RSA-RSA b/src/crypto/tls/testdata/Client-TLSv10-ClientCert-RSA-RSA
index e007870..e585894 100644
--- a/src/crypto/tls/testdata/Client-TLSv10-ClientCert-RSA-RSA
+++ b/src/crypto/tls/testdata/Client-TLSv10-ClientCert-RSA-RSA
@@ -1,120 +1,131 @@
>>> Flow 1 (client to server)
-00000000 16 03 01 00 85 01 00 00 81 03 03 00 00 00 00 00 |................|
+00000000 16 03 01 00 91 01 00 00 8d 03 03 00 00 00 00 00 |................|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
-00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 22 c0 2f |............."./|
-00000030 c0 2b c0 30 c0 2c c0 11 c0 07 c0 13 c0 09 c0 14 |.+.0.,..........|
-00000040 c0 0a 00 9c 00 9d 00 05 00 2f 00 35 c0 12 00 0a |........./.5....|
-00000050 01 00 00 36 00 05 00 05 01 00 00 00 00 00 0a 00 |...6............|
-00000060 08 00 06 00 17 00 18 00 19 00 0b 00 02 01 00 00 |................|
-00000070 0d 00 0e 00 0c 04 01 04 03 05 01 05 03 02 01 02 |................|
-00000080 03 ff 01 00 01 00 00 12 00 00 |..........|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2c cc a8 |.............,..|
+00000030 cc a9 c0 2f c0 2b c0 30 c0 2c c0 27 c0 13 c0 23 |.../.+.0.,.'...#|
+00000040 c0 09 c0 14 c0 0a 00 9c 00 9d 00 3c 00 2f 00 35 |...........<./.5|
+00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 38 00 05 |.............8..|
+00000060 00 05 01 00 00 00 00 00 0a 00 0a 00 08 00 1d 00 |................|
+00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 0e 00 |................|
+00000080 0c 04 01 04 03 05 01 05 03 02 01 02 03 ff 01 00 |................|
+00000090 01 00 00 12 00 00 |......|
>>> Flow 2 (server to client)
-00000000 16 03 01 00 51 02 00 00 4d 03 01 e5 d7 4b 56 7b |....Q...M....KV{|
-00000010 a8 2c 07 33 fc 66 d7 79 e9 26 91 56 7d 9d 99 1d |.,.3.f.y.&.V}...|
-00000020 b2 24 36 2c f6 78 3a e7 63 15 f6 20 9f e1 d4 07 |.$6,.x:.c.. ....|
-00000030 a9 75 3d b9 3b 8c 46 cb a7 37 36 56 af 4e 99 cf |.u=.;.F..76V.N..|
-00000040 90 49 e1 e9 69 25 81 0f fd 22 48 e6 00 05 00 00 |.I..i%..."H.....|
-00000050 05 ff 01 00 01 00 16 03 01 02 71 0b 00 02 6d 00 |..........q...m.|
-00000060 02 6a 00 02 67 30 82 02 63 30 82 01 cc a0 03 02 |.j..g0..c0......|
-00000070 01 02 02 09 00 a2 73 00 0c 81 00 cb f3 30 0d 06 |......s......0..|
-00000080 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 2b 31 17 |.*.H........0+1.|
-00000090 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 |0...U....Google |
-000000a0 54 45 53 54 49 4e 47 31 10 30 0e 06 03 55 04 03 |TESTING1.0...U..|
-000000b0 13 07 47 6f 20 52 6f 6f 74 30 1e 17 0d 31 35 30 |..Go Root0...150|
-000000c0 31 30 31 30 30 30 30 30 30 5a 17 0d 32 35 30 31 |101000000Z..2501|
-000000d0 30 31 30 30 30 30 30 30 5a 30 26 31 17 30 15 06 |01000000Z0&1.0..|
-000000e0 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 54 45 53 |.U....Google TES|
-000000f0 54 49 4e 47 31 0b 30 09 06 03 55 04 03 13 02 47 |TING1.0...U....G|
-00000100 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....|
-00000110 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 af 87 |.......0........|
-00000120 88 f6 20 1b 95 65 6c 14 ab 44 05 af 3b 45 14 e3 |.. ..el..D..;E..|
-00000130 b7 6d fd 00 63 4d 95 7f fe 6a 62 35 86 c0 4a f9 |.m..cM...jb5..J.|
-00000140 18 7c f6 aa 25 5e 7a 64 31 66 00 ba f4 8e 92 af |.|..%^zd1f......|
-00000150 c7 6b d8 76 d4 f3 5f 41 cb 6e 56 15 97 1b 97 c1 |.k.v.._A.nV.....|
-00000160 3c 12 39 21 66 3d 2b 16 d1 bc db 1c c0 a7 da b7 |<.9!f=+.........|
-00000170 ca ad ba da cb d5 21 50 ec de 8d ab d1 6b 81 4b |......!P.....k.K|
-00000180 89 02 f3 c4 be c1 6c 89 b1 44 84 bd 21 d1 04 7d |......l..D..!..}|
-00000190 9d 16 4d f9 82 15 f6 ef fa d6 09 47 f2 fb 02 03 |..M........G....|
-000001a0 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..|
-000001b0 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%|
-000001c0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........|
-000001d0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...|
-000001e0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....|
-000001f0 10 12 50 8d 89 6f 1b d1 dc 54 4d 6e cb 69 5e 06 |..P..o...TMn.i^.|
-00000200 f4 30 1b 06 03 55 1d 23 04 14 30 12 80 10 bf 3d |.0...U.#..0....=|
-00000210 b6 a9 66 f2 b8 40 cf ea b4 03 78 48 1a 41 30 19 |..f.. at ....xH.A0.|
-00000220 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp|
-00000230 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H|
-00000240 86 f7 0d 01 01 0b 05 00 03 81 81 00 92 7c af 91 |.............|..|
-00000250 55 12 18 96 59 31 a6 48 40 d5 2d d5 ee bb 02 a0 |U...Y1.H at .-.....|
-00000260 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 da 4f 3d c0 fa |...|..0}<.v.O=..|
-00000270 ae 2d 33 24 6b 03 7b 1b 67 59 11 21 b5 11 bc 77 |.-3$k.{.gY.!...w|
-00000280 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f 22 3e 63 10 6b |...n.-.5.d_">c.k|
-00000290 be ff 14 86 6d 0d f0 15 31 a8 14 38 1e 3b 84 87 |....m...1..8.;..|
-000002a0 2c cb 98 ed 51 76 b9 b1 4f dd db 9b 84 04 86 40 |,...Qv..O......@|
-000002b0 fa 51 dd ba b4 8d eb e3 46 de 46 b9 4f 86 c7 f9 |.Q......F.F.O...|
-000002c0 a4 c2 41 34 ac cc f6 ea b0 ab 39 18 16 03 01 00 |..A4......9.....|
-000002d0 0e 0d 00 00 06 03 01 02 40 00 00 0e 00 00 00 |........ at ......|
+00000000 16 03 01 00 59 02 00 00 55 03 01 61 6b 2e 41 7f |....Y...U..ak.A.|
+00000010 af 26 6f a2 8b 63 ee e4 b1 76 19 3a 6d a3 c2 30 |.&o..c...v.:m..0|
+00000020 37 e8 47 c2 90 10 7e e8 c5 b2 eb 20 00 1c 8f 70 |7.G...~.... ...p|
+00000030 0d 15 4a c7 7d ab ca 79 a7 d8 c2 01 62 6e 6f aa |..J.}..y....bno.|
+00000040 df a2 1c 8f 7c 27 d9 e6 fe e9 c8 ab c0 13 00 00 |....|'..........|
+00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................|
+00000060 01 02 59 0b 00 02 55 00 02 52 00 02 4f 30 82 02 |..Y...U..R..O0..|
+00000070 4b 30 82 01 b4 a0 03 02 01 02 02 09 00 e8 f0 9d |K0..............|
+00000080 3f e2 5b ea a6 30 0d 06 09 2a 86 48 86 f7 0d 01 |?.[..0...*.H....|
+00000090 01 0b 05 00 30 1f 31 0b 30 09 06 03 55 04 0a 13 |....0.1.0...U...|
+000000a0 02 47 6f 31 10 30 0e 06 03 55 04 03 13 07 47 6f |.Go1.0...U....Go|
+000000b0 20 52 6f 6f 74 30 1e 17 0d 31 36 30 31 30 31 30 | Root0...1601010|
+000000c0 30 30 30 30 30 5a 17 0d 32 35 30 31 30 31 30 30 |00000Z..25010100|
+000000d0 30 30 30 30 5a 30 1a 31 0b 30 09 06 03 55 04 0a |0000Z0.1.0...U..|
+000000e0 13 02 47 6f 31 0b 30 09 06 03 55 04 03 13 02 47 |..Go1.0...U....G|
+000000f0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....|
+00000100 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 db 46 |.......0.......F|
+00000110 7d 93 2e 12 27 06 48 bc 06 28 21 ab 7e c4 b6 a2 |}...'.H..(!.~...|
+00000120 5d fe 1e 52 45 88 7a 36 47 a5 08 0d 92 42 5b c2 |]..RE.z6G....B[.|
+00000130 81 c0 be 97 79 98 40 fb 4f 6d 14 fd 2b 13 8b c2 |....y. at .Om..+...|
+00000140 a5 2e 67 d8 d4 09 9e d6 22 38 b7 4a 0b 74 73 2b |..g....."8.J.ts+|
+00000150 c2 34 f1 d1 93 e5 96 d9 74 7b f3 58 9f 6c 61 3c |.4......t{.X.la<|
+00000160 c0 b0 41 d4 d9 2b 2b 24 23 77 5b 1c 3b bd 75 5d |..A..++$#w[.;.u]|
+00000170 ce 20 54 cf a1 63 87 1d 1e 24 c4 f3 1d 1a 50 8b |. T..c...$....P.|
+00000180 aa b6 14 43 ed 97 a7 75 62 f4 14 c8 52 d7 02 03 |...C...ub...R...|
+00000190 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..|
+000001a0 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%|
+000001b0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........|
+000001c0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...|
+000001d0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....|
+000001e0 10 9f 91 16 1f 43 43 3e 49 a6 de 6d b6 80 d7 9f |.....CC>I..m....|
+000001f0 60 30 1b 06 03 55 1d 23 04 14 30 12 80 10 48 13 |`0...U.#..0...H.|
+00000200 49 4d 13 7e 16 31 bb a3 01 d5 ac ab 6e 7b 30 19 |IM.~.1......n{0.|
+00000210 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp|
+00000220 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H|
+00000230 86 f7 0d 01 01 0b 05 00 03 81 81 00 9d 30 cc 40 |.............0.@|
+00000240 2b 5b 50 a0 61 cb ba e5 53 58 e1 ed 83 28 a9 58 |+[P.a...SX...(.X|
+00000250 1a a9 38 a4 95 a1 ac 31 5a 1a 84 66 3d 43 d3 2d |..8....1Z..f=C.-|
+00000260 d9 0b f2 97 df d3 20 64 38 92 24 3a 00 bc cf 9c |...... d8.$:....|
+00000270 7d b7 40 20 01 5f aa d3 16 61 09 a2 76 fd 13 c3 |}.@ ._...a..v...|
+00000280 cc e1 0c 5c ee b1 87 82 f1 6c 04 ed 73 bb b3 43 |...\.....l..s..C|
+00000290 77 8d 0c 1c f1 0f a1 d8 40 83 61 c9 4c 72 2b 9d |w....... at .a.Lr+.|
+000002a0 ae db 46 06 06 4d f4 c1 b3 3e c0 d1 bd 42 d4 db |..F..M...>...B..|
+000002b0 fe 3d 13 60 84 5c 21 d3 3b e9 fa e7 16 03 01 00 |.=.`.\!.;.......|
+000002c0 aa 0c 00 00 a6 03 00 1d 20 29 0b ca 37 f3 a1 52 |........ )..7..R|
+000002d0 49 1c 84 9a e4 74 6b 4b 2d 1f e6 e9 83 1d 5d 59 |I....tkK-.....]Y|
+000002e0 5a 2f 09 9f bc a4 30 af 71 00 80 d9 bb 6d 09 a7 |Z/....0.q....m..|
+000002f0 ab 47 6f e8 a6 1a da fb 66 7d a5 f0 c9 c3 24 4c |.Go.....f}....$L|
+00000300 99 56 c6 29 71 27 08 0b c1 60 44 cc 6d 42 1b 5e |.V.)q'...`D.mB.^|
+00000310 cd 9f 82 24 38 23 ec d9 fa 32 49 2f 16 5d d2 9d |...$8#...2I/.]..|
+00000320 e9 13 4e 66 3d f8 bf 30 2e 8c eb 35 4c e8 81 86 |..Nf=..0...5L...|
+00000330 c0 de c7 0d a9 60 7e 7c 4a c4 1d a0 89 70 de 82 |.....`~|J....p..|
+00000340 1b 37 a0 ea 7f 20 a5 fe d4 20 1d 6f 1a 84 dd a4 |.7... ... .o....|
+00000350 13 46 18 c6 31 14 81 4b a4 bb 43 5c c4 49 1c 5a |.F..1..K..C\.I.Z|
+00000360 8d 12 57 e0 1d 9a b6 cd f1 39 ff 16 03 01 00 0a |..W......9......|
+00000370 0d 00 00 06 03 01 02 40 00 00 16 03 01 00 04 0e |....... at ........|
+00000380 00 00 00 |...|
>>> Flow 3 (client to server)
-00000000 16 03 01 01 fb 0b 00 01 f7 00 01 f4 00 01 f1 30 |...............0|
-00000010 82 01 ed 30 82 01 58 a0 03 02 01 02 02 01 00 30 |...0..X........0|
-00000020 0b 06 09 2a 86 48 86 f7 0d 01 01 05 30 26 31 10 |...*.H......0&1.|
-00000030 30 0e 06 03 55 04 0a 13 07 41 63 6d 65 20 43 6f |0...U....Acme Co|
-00000040 31 12 30 10 06 03 55 04 03 13 09 31 32 37 2e 30 |1.0...U....127.0|
-00000050 2e 30 2e 31 30 1e 17 0d 31 31 31 32 30 38 30 37 |.0.10...11120807|
-00000060 35 35 31 32 5a 17 0d 31 32 31 32 30 37 30 38 30 |5512Z..121207080|
-00000070 30 31 32 5a 30 26 31 10 30 0e 06 03 55 04 0a 13 |012Z0&1.0...U...|
-00000080 07 41 63 6d 65 20 43 6f 31 12 30 10 06 03 55 04 |.Acme Co1.0...U.|
-00000090 03 13 09 31 32 37 2e 30 2e 30 2e 31 30 81 9c 30 |...127.0.0.10..0|
-000000a0 0b 06 09 2a 86 48 86 f7 0d 01 01 01 03 81 8c 00 |...*.H..........|
-000000b0 30 81 88 02 81 80 4e d0 7b 31 e3 82 64 d9 59 c0 |0.....N.{1..d.Y.|
-000000c0 c2 87 a4 5e 1e 8b 73 33 c7 63 53 df 66 92 06 84 |...^..s3.cS.f...|
-000000d0 f6 64 d5 8f e4 36 a7 1d 2b e8 b3 20 36 45 23 b5 |.d...6..+.. 6E#.|
-000000e0 e3 95 ae ed e0 f5 20 9c 8d 95 df 7f 5a 12 ef 87 |...... .....Z...|
-000000f0 e4 5b 68 e4 e9 0e 74 ec 04 8a 7f de 93 27 c4 01 |.[h...t......'..|
-00000100 19 7a bd f2 dc 3d 14 ab d0 54 ca 21 0c d0 4d 6e |.z...=...T.!..Mn|
-00000110 87 2e 5c c5 d2 bb 4d 4b 4f ce b6 2c f7 7e 88 ec |..\...MKO..,.~..|
-00000120 7c d7 02 91 74 a6 1e 0c 1a da e3 4a 5a 2e de 13 ||...t......JZ...|
-00000130 9c 4c 40 88 59 93 02 03 01 00 01 a3 32 30 30 30 |.L at .Y.......2000|
-00000140 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 00 a0 30 |...U...........0|
-00000150 0d 06 03 55 1d 0e 04 06 04 04 01 02 03 04 30 0f |...U..........0.|
-00000160 06 03 55 1d 23 04 08 30 06 80 04 01 02 03 04 30 |..U.#..0.......0|
-00000170 0b 06 09 2a 86 48 86 f7 0d 01 01 05 03 81 81 00 |...*.H..........|
-00000180 36 1f b3 7a 0c 75 c9 6e 37 46 61 2b d5 bd c0 a7 |6..z.u.n7Fa+....|
-00000190 4b cc 46 9a 81 58 7c 85 79 29 c8 c8 c6 67 dd 32 |K.F..X|.y)...g.2|
-000001a0 56 45 2b 75 b6 e9 24 a9 50 9a be 1f 5a fa 1a 15 |VE+u..$.P...Z...|
-000001b0 d9 cc 55 95 72 16 83 b9 c2 b6 8f fd 88 8c 38 84 |..U.r.........8.|
-000001c0 1d ab 5d 92 31 13 4f fd 83 3b c6 9d f1 11 62 b6 |..].1.O..;....b.|
-000001d0 8b ec ab 67 be c8 64 b0 11 50 46 58 17 6b 99 1c |...g..d..PFX.k..|
-000001e0 d3 1d fc 06 f1 0e e5 96 a8 0c f9 78 20 b7 44 18 |...........x .D.|
-000001f0 51 8d 10 7e 4f 94 67 df a3 4e 70 73 8e 90 91 85 |Q..~O.g..Nps....|
-00000200 16 03 01 00 86 10 00 00 82 00 80 73 bd 73 65 92 |...........s.se.|
-00000210 86 23 41 14 79 7f d5 c1 10 ce 94 4d ad 9c c3 a9 |.#A.y......M....|
-00000220 87 b5 32 52 f8 6b 11 93 2d 9b 98 0b 8b 1d c0 f6 |..2R.k..-.......|
-00000230 53 17 6d c7 9c 2e ae c9 6f cc 99 23 38 37 1a 10 |S.m.....o..#87..|
-00000240 fe 05 0b b5 55 0a 14 e9 60 7d 70 26 98 e2 54 d9 |....U...`}p&..T.|
-00000250 65 cf 2e f4 53 5f 1d aa 3a f6 33 7b eb 4c 0e b3 |e...S_..:.3{.L..|
-00000260 ff 5a db 36 2a 47 f3 df f9 fc f5 31 78 83 aa 6b |.Z.6*G.....1x..k|
-00000270 52 b7 ba 1a 96 bc fa c1 a1 a9 bb 2b f5 38 89 00 |R..........+.8..|
-00000280 4d e5 78 13 4e a4 38 46 42 dc 16 16 03 01 00 86 |M.x.N.8FB.......|
-00000290 0f 00 00 82 00 80 3d f7 ff c1 72 82 b8 90 42 a3 |......=...r...B.|
-000002a0 10 24 b5 01 44 60 98 39 e4 36 86 56 09 55 e5 73 |.$..D`.9.6.V.U.s|
-000002b0 3a d9 9d 00 ae 05 23 6f 78 4e 49 28 c1 cc 7a ff |:.....#oxNI(..z.|
-000002c0 8f 67 92 cd 94 c0 d2 68 7f 48 ec 10 83 48 9e 02 |.g.....h.H...H..|
-000002d0 b8 10 b2 1b f0 ba 8f 5a c8 85 d9 19 53 c2 8d 37 |.......Z....S..7|
-000002e0 8e 86 4c ca ee 0f c4 97 20 f9 a5 4e 94 b8 c5 c5 |..L..... ..N....|
-000002f0 53 0c c1 b6 e5 a1 4e d6 15 b3 6b 08 c2 25 c3 de |S.....N...k..%..|
-00000300 e7 69 85 85 56 31 16 ad 68 7e 00 8f 1b fc f8 9f |.i..V1..h~......|
-00000310 d7 50 87 08 0d c5 14 03 01 00 01 01 16 03 01 00 |.P..............|
-00000320 24 eb 0c f3 4f 56 04 e3 54 b0 a8 e4 bb af 3a 44 |$...OV..T.....:D|
-00000330 c7 d6 f0 24 2f fc e6 79 93 f4 4e ec c5 1f 5b 99 |...$/..y..N...[.|
-00000340 32 37 c2 f1 ad |27...|
+00000000 16 03 01 01 fd 0b 00 01 f9 00 01 f6 00 01 f3 30 |...............0|
+00000010 82 01 ef 30 82 01 58 a0 03 02 01 02 02 10 5c 19 |...0..X.......\.|
+00000020 c1 89 65 83 55 6f dc 0b c9 b9 93 9f e9 bc 30 0d |..e.Uo........0.|
+00000030 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 12 31 |..*.H........0.1|
+00000040 10 30 0e 06 03 55 04 0a 13 07 41 63 6d 65 20 43 |.0...U....Acme C|
+00000050 6f 30 1e 17 0d 31 36 30 38 31 37 32 31 35 32 33 |o0...16081721523|
+00000060 31 5a 17 0d 31 37 30 38 31 37 32 31 35 32 33 31 |1Z..170817215231|
+00000070 5a 30 12 31 10 30 0e 06 03 55 04 0a 13 07 41 63 |Z0.1.0...U....Ac|
+00000080 6d 65 20 43 6f 30 81 9f 30 0d 06 09 2a 86 48 86 |me Co0..0...*.H.|
+00000090 f7 0d 01 01 01 05 00 03 81 8d 00 30 81 89 02 81 |...........0....|
+000000a0 81 00 ba 6f aa 86 bd cf bf 9f f2 ef 5c 94 60 78 |...o........\.`x|
+000000b0 6f e8 13 f2 d1 96 6f cd d9 32 6e 22 37 ce 41 f9 |o.....o..2n"7.A.|
+000000c0 ca 5d 29 ac e1 27 da 61 a2 ee 81 cb 10 c7 df 34 |.])..'.a.......4|
+000000d0 58 95 86 e9 3d 19 e6 5c 27 73 60 c8 8d 78 02 f4 |X...=..\'s`..x..|
+000000e0 1d a4 98 09 a3 19 70 69 3c 25 62 66 2a ab 22 23 |......pi<%bf*."#|
+000000f0 c5 7b 85 38 4f 2e 09 73 32 a7 bd 3e 9b ad ca 84 |.{.8O..s2..>....|
+00000100 07 e6 0f 3a ff 77 c5 9d 41 85 00 8a b6 9b ee b0 |...:.w..A.......|
+00000110 a4 3f 2d 4c 4c e6 42 3e bb 51 c8 dd 48 54 f4 0c |.?-LL.B>.Q..HT..|
+00000120 8e 47 02 03 01 00 01 a3 46 30 44 30 0e 06 03 55 |.G......F0D0...U|
+00000130 1d 0f 01 01 ff 04 04 03 02 05 a0 30 13 06 03 55 |...........0...U|
+00000140 1d 25 04 0c 30 0a 06 08 2b 06 01 05 05 07 03 01 |.%..0...+.......|
+00000150 30 0c 06 03 55 1d 13 01 01 ff 04 02 30 00 30 0f |0...U.......0.0.|
+00000160 06 03 55 1d 11 04 08 30 06 87 04 7f 00 00 01 30 |..U....0.......0|
+00000170 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 03 81 |...*.H..........|
+00000180 81 00 46 ab 44 a2 fb 28 54 f8 5a 67 f8 62 94 f1 |..F.D..(T.Zg.b..|
+00000190 9a b2 18 9e f2 b1 de 1d 7e 6f 76 95 a9 ba e7 5d |........~ov....]|
+000001a0 a8 16 6c 9c f7 09 d3 37 e4 4b 2b 36 7c 01 ad 41 |..l....7.K+6|..A|
+000001b0 d2 32 d8 c3 d2 93 f9 10 6b 8e 95 b9 2c 17 8a a3 |.2......k...,...|
+000001c0 44 48 bc 59 13 83 16 04 88 a4 81 5c 25 0d 98 0c |DH.Y.......\%...|
+000001d0 ac 11 b1 28 56 be 1d cd 61 62 84 09 bf d6 80 c6 |...(V...ab......|
+000001e0 45 8d 82 2c b4 d8 83 9b db c9 22 b7 2a 12 11 7b |E..,......".*..{|
+000001f0 fa 02 3b c1 c9 ff ea c9 9d a8 49 d3 95 d7 d5 0e |..;.......I.....|
+00000200 e5 35 16 03 01 00 25 10 00 00 21 20 2f e5 7d a3 |.5....%...! /.}.|
+00000210 47 cd 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 |G.bC.(.._.).0...|
+00000220 af c4 cf c2 ed 90 99 5f 58 cb 3b 74 16 03 01 00 |......._X.;t....|
+00000230 86 0f 00 00 82 00 80 12 76 af 25 e4 e7 ff d6 e4 |........v.%.....|
+00000240 27 58 31 0f 6b 1e 84 13 2f d0 60 80 18 c3 f8 c1 |'X1.k.../.`.....|
+00000250 f8 04 39 d4 07 05 d3 96 e2 b2 10 de 1f 68 88 67 |..9..........h.g|
+00000260 1d dd 0a 11 52 9d 16 0e af 07 de cb f1 7c f4 b4 |....R........|..|
+00000270 5d 0f 4f 43 5b 3c 25 07 32 13 f2 ab 9b 2d d0 a8 |].OC[<%.2....-..|
+00000280 28 90 cb 04 48 c3 43 bd 2b b4 ef b9 7b cd bd d5 |(...H.C.+...{...|
+00000290 bc d1 cc 00 17 46 fa 9b 1f 44 58 b7 6c de 1b 7a |.....F...DX.l..z|
+000002a0 e0 d7 12 38 a3 09 f8 7a 9b 26 0b ee 37 bc 79 1b |...8...z.&..7.y.|
+000002b0 51 9f 9a 1f f9 a9 51 14 03 01 00 01 01 16 03 01 |Q.....Q.........|
+000002c0 00 30 97 df fb 79 78 a8 27 fd 2b 68 6b ec 4d 29 |.0...yx.'.+hk.M)|
+000002d0 a1 02 59 ae 18 0b 46 62 af 61 53 2f 95 50 f2 ac |..Y...Fb.aS/.P..|
+000002e0 c8 c3 5e 78 ca b0 e2 5d ff d7 1b 9b 00 30 f6 da |..^x...].....0..|
+000002f0 d7 91 |..|
>>> Flow 4 (server to client)
-00000000 14 03 01 00 01 01 16 03 01 00 24 75 ac 09 a6 28 |..........$u...(|
-00000010 60 ce 7f 81 a2 75 86 af 84 95 dc 3f e1 07 1c 02 |`....u.....?....|
-00000020 bc 3c 90 db 1e 1a 35 06 93 60 22 69 b9 05 bb |.<....5..`"i...|
+00000000 14 03 01 00 01 01 16 03 01 00 30 f9 e9 d7 8c 4a |..........0....J|
+00000010 6b f4 c9 88 d6 98 70 53 13 fc 51 9c 81 14 cf 71 |k.....pS..Q....q|
+00000020 d9 30 7a d9 2c 34 96 00 a4 a0 2b 1e 7d ff d0 f2 |.0z.,4....+.}...|
+00000030 b7 81 ed 86 c5 e1 09 16 82 47 20 |.........G |
>>> Flow 5 (client to server)
-00000000 17 03 01 00 1a f4 67 a7 d8 0a 67 8d 3a 11 53 7e |......g...g.:.S~|
-00000010 49 91 bf 92 85 e0 35 24 25 72 92 26 63 9b 09 15 |I.....5$%r.&c...|
-00000020 03 01 00 16 98 bb a0 ca 40 70 26 6f 2d 73 35 3d |........ at p&o-s5=|
-00000030 90 8c ff 01 e0 b1 50 52 e3 57 |......PR.W|
+00000000 17 03 01 00 20 db b5 66 4e fb b1 47 8a 8e 6b a8 |.... ..fN..G..k.|
+00000010 03 53 1a 51 22 8e 47 a3 3a 74 ed a4 6a aa 79 fd |.S.Q".G.:t..j.y.|
+00000020 55 0f ac 35 a9 17 03 01 00 20 3e 0b 39 f5 5a 03 |U..5..... >.9.Z.|
+00000030 43 d9 e2 7d 1c dc 3b 42 82 2a 2d d4 04 0a 76 97 |C..}..;B.*-...v.|
+00000040 70 ed ee 99 58 15 40 c1 3a d5 15 03 01 00 20 bf |p...X. at .:..... .|
+00000050 ea e8 93 67 a4 91 1a b5 f5 03 a5 94 50 95 41 16 |...g........P.A.|
+00000060 b0 2a 74 d9 32 65 94 35 45 b9 0f 2e 80 87 fd |.*t.2e.5E......|
diff --git a/src/crypto/tls/testdata/Client-TLSv10-ECDHE-ECDSA-AES b/src/crypto/tls/testdata/Client-TLSv10-ECDHE-ECDSA-AES
index 929e1c6..529b7ce 100644
--- a/src/crypto/tls/testdata/Client-TLSv10-ECDHE-ECDSA-AES
+++ b/src/crypto/tls/testdata/Client-TLSv10-ECDHE-ECDSA-AES
@@ -1,19 +1,20 @@
>>> Flow 1 (client to server)
-00000000 16 03 01 00 85 01 00 00 81 03 03 00 00 00 00 00 |................|
+00000000 16 03 01 00 91 01 00 00 8d 03 03 00 00 00 00 00 |................|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
-00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 22 c0 2f |............."./|
-00000030 c0 2b c0 30 c0 2c c0 11 c0 07 c0 13 c0 09 c0 14 |.+.0.,..........|
-00000040 c0 0a 00 9c 00 9d 00 05 00 2f 00 35 c0 12 00 0a |........./.5....|
-00000050 01 00 00 36 00 05 00 05 01 00 00 00 00 00 0a 00 |...6............|
-00000060 08 00 06 00 17 00 18 00 19 00 0b 00 02 01 00 00 |................|
-00000070 0d 00 0e 00 0c 04 01 04 03 05 01 05 03 02 01 02 |................|
-00000080 03 ff 01 00 01 00 00 12 00 00 |..........|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2c cc a8 |.............,..|
+00000030 cc a9 c0 2f c0 2b c0 30 c0 2c c0 27 c0 13 c0 23 |.../.+.0.,.'...#|
+00000040 c0 09 c0 14 c0 0a 00 9c 00 9d 00 3c 00 2f 00 35 |...........<./.5|
+00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 38 00 05 |.............8..|
+00000060 00 05 01 00 00 00 00 00 0a 00 0a 00 08 00 1d 00 |................|
+00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 0e 00 |................|
+00000080 0c 04 01 04 03 05 01 05 03 02 01 02 03 ff 01 00 |................|
+00000090 01 00 00 12 00 00 |......|
>>> Flow 2 (server to client)
-00000000 16 03 01 00 59 02 00 00 55 03 01 78 09 57 86 09 |....Y...U..x.W..|
-00000010 64 7e 35 c7 c7 b9 44 9c 09 ae f0 49 cb 1c 1f 58 |d~5...D....I...X|
-00000020 89 ef 65 16 9e 32 73 cd 4d 1b 8f 20 10 4d 5b cf |..e..2s.M.. .M[.|
-00000030 d0 24 59 dd e8 47 c9 a2 ad 9c 98 b5 eb 16 46 6b |.$Y..G........Fk|
-00000040 7d 33 6e 53 0a 3d 81 71 a1 bc 43 7a c0 09 00 00 |}3nS.=.q..Cz....|
+00000000 16 03 01 00 59 02 00 00 55 03 01 b0 ec 4b 2e 9e |....Y...U....K..|
+00000010 19 7d 7b 7e 7c 52 8a d2 2e 8a 97 05 8a c6 ae aa |.}{~|R..........|
+00000020 c5 62 bd 6f bd 7e fe 6b c6 9f d4 20 74 db 02 b1 |.b.o.~.k... t...|
+00000030 65 88 41 bb 9a 55 22 f3 01 c4 5c ca 39 86 b1 77 |e.A..U"...\.9..w|
+00000040 c4 b3 45 16 eb 55 d8 15 b8 4d ac 12 c0 09 00 00 |..E..U...M......|
00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................|
00000060 01 02 0e 0b 00 02 0a 00 02 07 00 02 04 30 82 02 |.............0..|
00000070 00 30 82 01 62 02 09 00 b8 bf 2d 47 a0 d2 eb f4 |.0..b.....-G....|
@@ -48,41 +49,37 @@
00000240 13 83 0d 94 06 bb d4 37 7a f6 ec 7a c9 86 2e dd |.......7z..z....|
00000250 d7 11 69 7f 85 7c 56 de fb 31 78 2b e4 c7 78 0d |..i..|V..1x+..x.|
00000260 ae cb be 9e 4e 36 24 31 7b 6a 0f 39 95 12 07 8f |....N6$1{j.9....|
-00000270 2a 16 03 01 00 d6 0c 00 00 d2 03 00 17 41 04 51 |*............A.Q|
-00000280 39 70 43 9c 01 de 29 df 3c d0 f8 31 54 70 34 53 |9pC...).<..1Tp4S|
-00000290 0e ab e8 e0 b0 8b 21 66 63 ac a9 68 7c 92 6f f8 |......!fc..h|.o.|
-000002a0 cf a3 ba cb 6d 39 f4 5c f5 2e ff 1d d7 1b b9 e7 |....m9.\........|
-000002b0 08 13 59 f8 64 7e 23 e0 1d 04 cf 37 47 d6 b7 00 |..Y.d~#....7G...|
-000002c0 8b 30 81 88 02 42 01 cd 1d 01 46 68 da 4c b6 0d |.0...B....Fh.L..|
-000002d0 67 05 39 0d aa 6c c5 40 e4 5d bf 4f 2a 92 78 8d |g.9..l. at .].O*.x.|
-000002e0 08 0e c0 07 8c 68 cc 55 4e 54 a9 9d 22 f9 a6 4a |.....h.UNT.."..J|
-000002f0 e4 38 9f 53 4a 60 e8 eb 81 02 50 75 7e 13 31 2a |.8.SJ`....Pu~.1*|
-00000300 ff 3e 17 cd b4 d1 d4 75 02 42 01 95 ba b6 a0 12 |.>.....u.B......|
-00000310 23 59 9f ae 1c c0 60 d2 8f 59 6b 35 ee b3 3f ac |#Y....`..Yk5..?.|
-00000320 e4 42 9a 23 d0 f4 fd a1 3c 36 1b 31 33 76 8d f0 |.B.#....<6.13v..|
-00000330 b6 66 fd 92 9a 2a 27 8b 06 11 72 41 09 bd 27 55 |.f...*'...rA..'U|
-00000340 c7 1b a9 d1 49 5e 8f 85 dc aa 9d be 16 03 01 00 |....I^..........|
-00000350 04 0e 00 00 00 |.....|
+00000270 2a 16 03 01 00 b5 0c 00 00 b1 03 00 1d 20 7d 74 |*............ }t|
+00000280 bf aa a8 b6 c0 1f 78 0c 1a ee c5 b7 56 ff 5c aa |......x.....V.\.|
+00000290 f4 e3 a5 0c f7 64 31 eb 85 8a c9 bd 05 1b 00 8b |.....d1.........|
+000002a0 30 81 88 02 42 00 f8 5d e5 bf 2e 70 79 f4 36 90 |0...B..]...py.6.|
+000002b0 fc 6e 9a cc f1 c4 01 50 8c b9 92 4e bd e0 82 2d |.n.....P...N...-|
+000002c0 1b ab 30 71 d1 db 76 af 50 75 08 fb cb 50 5b 00 |..0q..v.Pu...P[.|
+000002d0 49 72 f5 d7 d9 44 48 94 ac 1d 8d 2e 50 90 ad a3 |Ir...DH.....P...|
+000002e0 42 2b 5f 57 48 5e 9e 02 42 00 bb 0b 9a d7 25 53 |B+_WH^..B.....%S|
+000002f0 04 5c 58 01 07 8e 3d ee f5 4f 0b 80 bd 02 07 3e |.\X...=..O.....>|
+00000300 ff b9 01 ac 7a 49 be 94 fa cf 58 5c 59 91 b5 5d |....zI....X\Y..]|
+00000310 cc 61 b9 e3 2f 53 7d 3c 3f 41 c5 31 1a 90 fc fa |.a../S}<?A.1....|
+00000320 f7 0b eb e9 01 17 ab 23 ab 28 63 16 03 01 00 04 |.......#.(c.....|
+00000330 0e 00 00 00 |....|
>>> Flow 3 (client to server)
-00000000 16 03 01 00 46 10 00 00 42 41 04 1e 18 37 ef 0d |....F...BA...7..|
-00000010 19 51 88 35 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd |.Q.5uq..T[....g.|
-00000020 a7 24 20 3e b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e |.$ >.V...(^.+-O.|
-00000030 f1 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 |...lK[.V.2B.X..I|
-00000040 a6 b5 68 1a 41 03 56 6b dc 5a 89 14 03 01 00 01 |..h.A.Vk.Z......|
-00000050 01 16 03 01 00 30 64 61 7f ea 98 8e e7 c9 0f ea |.....0da........|
-00000060 0a b3 52 ba 3d 01 36 a4 47 24 7b 2d 19 b5 7e 92 |..R.=.6.G${-..~.|
-00000070 04 b7 8c 4f fc 02 5d 79 15 3e 50 72 05 3c df d2 |...O..]y.>Pr.<..|
-00000080 c6 a3 b3 c8 7c 48 |....|H|
+00000000 16 03 01 00 25 10 00 00 21 20 2f e5 7d a3 47 cd |....%...! /.}.G.|
+00000010 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af c4 |bC.(.._.).0.....|
+00000020 cf c2 ed 90 99 5f 58 cb 3b 74 14 03 01 00 01 01 |....._X.;t......|
+00000030 16 03 01 00 30 f5 d0 86 ef 96 7e b9 94 cc 19 62 |....0.....~....b|
+00000040 cc 3a 14 f1 74 a2 0d c8 b9 4c 5d 8a c5 80 60 23 |.:..t....L]...`#|
+00000050 d5 f5 04 06 16 e2 69 ca 4d 99 1b a0 b5 3b 7d 62 |......i.M....;}b|
+00000060 51 62 ee d9 60 |Qb..`|
>>> Flow 4 (server to client)
-00000000 14 03 01 00 01 01 16 03 01 00 30 7d 49 8d e9 da |..........0}I...|
-00000010 87 77 18 4d 10 63 17 ed 1f 34 7a d4 be e3 dd b6 |.w.M.c...4z.....|
-00000020 8b f3 a7 06 bc de 76 8e 04 be 8a 95 5b 24 19 ec |......v.....[$..|
-00000030 66 55 8a 1b e0 df 0b a1 57 cb 67 |fU......W.g|
+00000000 14 03 01 00 01 01 16 03 01 00 30 4d f9 c2 63 4f |..........0M..cO|
+00000010 98 1b 02 ce df ca d1 15 a2 4f 6f 4c 2c b8 1a 88 |.........OoL,...|
+00000020 11 c9 b3 45 e6 1d cf e8 6b dd 8c 89 c6 1d 0b 66 |...E....k......f|
+00000030 82 d5 1d c6 55 14 1c 56 59 3e 69 |....U..VY>i|
>>> Flow 5 (client to server)
-00000000 17 03 01 00 20 2d a3 e5 55 13 3f 73 8e ba 41 79 |.... -..U.?s..Ay|
-00000010 65 e0 83 d5 3a ea cd e9 a8 b4 4b 3c d0 0c bf 06 |e...:.....K<....|
-00000020 75 2a 67 f2 f7 17 03 01 00 20 a0 8d 3c a2 ca b3 |u*g...... ..<...|
-00000030 f3 e5 36 dc 44 a4 3b ad cd 03 be a9 70 a8 75 51 |..6.D.;.....p.uQ|
-00000040 0f 8e 9f 7c a7 3c 03 84 38 88 15 03 01 00 20 75 |...|.<..8..... u|
-00000050 0f db fe 48 b4 7e 04 3b f5 5b 47 5b 0a ab 69 18 |...H.~.;.[G[..i.|
-00000060 37 bb 89 d3 a8 40 ba 53 3b 5f 6d 8b 06 ff ae |7.... at .S;_m....|
+00000000 17 03 01 00 20 12 be 42 b4 31 07 55 8e f9 a1 64 |.... ..B.1.U...d|
+00000010 96 70 46 68 3e fd 4e 4f 9c af b3 11 de fc 80 f1 |.pFh>.NO........|
+00000020 c8 11 84 ba ae 17 03 01 00 20 2f f9 ec dd 50 97 |......... /...P.|
+00000030 1e a4 f1 66 fe 28 e3 c1 51 8d c0 f6 c3 d8 b3 ad |...f.(..Q.......|
+00000040 7d dc a5 98 87 90 34 71 b4 73 15 03 01 00 20 d1 |}.....4q.s.... .|
+00000050 6f 91 91 01 68 c4 11 6a e5 a2 ed 20 3f 3a 3d b7 |o...h..j... ?:=.|
+00000060 d9 7f c3 b3 29 c3 df 3e 17 69 76 9f 04 f8 58 |....)..>.iv...X|
diff --git a/src/crypto/tls/testdata/Client-TLSv10-ECDHE-RSA-AES b/src/crypto/tls/testdata/Client-TLSv10-ECDHE-RSA-AES
index 0b481ea..78947ac 100644
--- a/src/crypto/tls/testdata/Client-TLSv10-ECDHE-RSA-AES
+++ b/src/crypto/tls/testdata/Client-TLSv10-ECDHE-RSA-AES
@@ -1,93 +1,89 @@
>>> Flow 1 (client to server)
-00000000 16 03 01 00 85 01 00 00 81 03 03 00 00 00 00 00 |................|
+00000000 16 03 01 00 91 01 00 00 8d 03 03 00 00 00 00 00 |................|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
-00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 22 c0 2f |............."./|
-00000030 c0 2b c0 30 c0 2c c0 11 c0 07 c0 13 c0 09 c0 14 |.+.0.,..........|
-00000040 c0 0a 00 9c 00 9d 00 05 00 2f 00 35 c0 12 00 0a |........./.5....|
-00000050 01 00 00 36 00 05 00 05 01 00 00 00 00 00 0a 00 |...6............|
-00000060 08 00 06 00 17 00 18 00 19 00 0b 00 02 01 00 00 |................|
-00000070 0d 00 0e 00 0c 04 01 04 03 05 01 05 03 02 01 02 |................|
-00000080 03 ff 01 00 01 00 00 12 00 00 |..........|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2c cc a8 |.............,..|
+00000030 cc a9 c0 2f c0 2b c0 30 c0 2c c0 27 c0 13 c0 23 |.../.+.0.,.'...#|
+00000040 c0 09 c0 14 c0 0a 00 9c 00 9d 00 3c 00 2f 00 35 |...........<./.5|
+00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 38 00 05 |.............8..|
+00000060 00 05 01 00 00 00 00 00 0a 00 0a 00 08 00 1d 00 |................|
+00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 0e 00 |................|
+00000080 0c 04 01 04 03 05 01 05 03 02 01 02 03 ff 01 00 |................|
+00000090 01 00 00 12 00 00 |......|
>>> Flow 2 (server to client)
-00000000 16 03 01 00 59 02 00 00 55 03 01 90 3d f6 98 16 |....Y...U...=...|
-00000010 55 0f 73 94 05 96 4c ab ad f4 98 7a db c5 ca 26 |U.s...L....z...&|
-00000020 1b c8 d9 15 a8 79 8e 2b 10 67 54 20 b2 8e 45 24 |.....y.+.gT ..E$|
-00000030 6d 82 ec f5 30 41 2e 32 10 fa c0 76 3f 84 81 39 |m...0A.2...v?..9|
-00000040 1e 5d 98 c1 33 d9 0d 4f 21 e1 0d 47 c0 13 00 00 |.]..3..O!..G....|
+00000000 16 03 01 00 59 02 00 00 55 03 01 45 04 14 a2 70 |....Y...U..E...p|
+00000010 3e 1e d9 2c d4 bd f3 e8 9c f3 e0 08 d8 0f 7f 82 |>..,............|
+00000020 2b 07 a0 bd 47 56 a0 e1 06 0d 36 20 fc 0f 5b 85 |+...GV....6 ..[.|
+00000030 8e 17 20 f1 f6 1e 80 c3 79 1a e1 86 c3 ed e9 24 |.. .....y......$|
+00000040 6d bb 24 3c 0c 8d 2c 79 f2 03 27 b0 c0 13 00 00 |m.$<..,y..'.....|
00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................|
-00000060 01 02 71 0b 00 02 6d 00 02 6a 00 02 67 30 82 02 |..q...m..j..g0..|
-00000070 63 30 82 01 cc a0 03 02 01 02 02 09 00 a2 73 00 |c0............s.|
-00000080 0c 81 00 cb f3 30 0d 06 09 2a 86 48 86 f7 0d 01 |.....0...*.H....|
-00000090 01 0b 05 00 30 2b 31 17 30 15 06 03 55 04 0a 13 |....0+1.0...U...|
-000000a0 0e 47 6f 6f 67 6c 65 20 54 45 53 54 49 4e 47 31 |.Google TESTING1|
-000000b0 10 30 0e 06 03 55 04 03 13 07 47 6f 20 52 6f 6f |.0...U....Go Roo|
-000000c0 74 30 1e 17 0d 31 35 30 31 30 31 30 30 30 30 30 |t0...15010100000|
-000000d0 30 5a 17 0d 32 35 30 31 30 31 30 30 30 30 30 30 |0Z..250101000000|
-000000e0 5a 30 26 31 17 30 15 06 03 55 04 0a 13 0e 47 6f |Z0&1.0...U....Go|
-000000f0 6f 67 6c 65 20 54 45 53 54 49 4e 47 31 0b 30 09 |ogle TESTING1.0.|
-00000100 06 03 55 04 03 13 02 47 6f 30 81 9f 30 0d 06 09 |..U....Go0..0...|
-00000110 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 30 |*.H............0|
-00000120 81 89 02 81 81 00 af 87 88 f6 20 1b 95 65 6c 14 |.......... ..el.|
-00000130 ab 44 05 af 3b 45 14 e3 b7 6d fd 00 63 4d 95 7f |.D..;E...m..cM..|
-00000140 fe 6a 62 35 86 c0 4a f9 18 7c f6 aa 25 5e 7a 64 |.jb5..J..|..%^zd|
-00000150 31 66 00 ba f4 8e 92 af c7 6b d8 76 d4 f3 5f 41 |1f.......k.v.._A|
-00000160 cb 6e 56 15 97 1b 97 c1 3c 12 39 21 66 3d 2b 16 |.nV.....<.9!f=+.|
-00000170 d1 bc db 1c c0 a7 da b7 ca ad ba da cb d5 21 50 |..............!P|
-00000180 ec de 8d ab d1 6b 81 4b 89 02 f3 c4 be c1 6c 89 |.....k.K......l.|
-00000190 b1 44 84 bd 21 d1 04 7d 9d 16 4d f9 82 15 f6 ef |.D..!..}..M.....|
-000001a0 fa d6 09 47 f2 fb 02 03 01 00 01 a3 81 93 30 81 |...G..........0.|
-000001b0 90 30 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 05 |.0...U..........|
-000001c0 a0 30 1d 06 03 55 1d 25 04 16 30 14 06 08 2b 06 |.0...U.%..0...+.|
-000001d0 01 05 05 07 03 01 06 08 2b 06 01 05 05 07 03 02 |........+.......|
-000001e0 30 0c 06 03 55 1d 13 01 01 ff 04 02 30 00 30 19 |0...U.......0.0.|
-000001f0 06 03 55 1d 0e 04 12 04 10 12 50 8d 89 6f 1b d1 |..U.......P..o..|
-00000200 dc 54 4d 6e cb 69 5e 06 f4 30 1b 06 03 55 1d 23 |.TMn.i^..0...U.#|
-00000210 04 14 30 12 80 10 bf 3d b6 a9 66 f2 b8 40 cf ea |..0....=..f.. at ..|
-00000220 b4 03 78 48 1a 41 30 19 06 03 55 1d 11 04 12 30 |..xH.A0...U....0|
-00000230 10 82 0e 65 78 61 6d 70 6c 65 2e 67 6f 6c 61 6e |...example.golan|
-00000240 67 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 |g0...*.H........|
-00000250 03 81 81 00 92 7c af 91 55 12 18 96 59 31 a6 48 |.....|..U...Y1.H|
-00000260 40 d5 2d d5 ee bb 02 a0 f5 c2 1e 7c 9b b3 30 7d |@.-........|..0}|
-00000270 3c dc 76 da 4f 3d c0 fa ae 2d 33 24 6b 03 7b 1b |<.v.O=...-3$k.{.|
-00000280 67 59 11 21 b5 11 bc 77 b9 d9 e0 6e a8 2d 2e 35 |gY.!...w...n.-.5|
-00000290 fa 64 5f 22 3e 63 10 6b be ff 14 86 6d 0d f0 15 |.d_">c.k....m...|
-000002a0 31 a8 14 38 1e 3b 84 87 2c cb 98 ed 51 76 b9 b1 |1..8.;..,...Qv..|
-000002b0 4f dd db 9b 84 04 86 40 fa 51 dd ba b4 8d eb e3 |O...... at .Q......|
-000002c0 46 de 46 b9 4f 86 c7 f9 a4 c2 41 34 ac cc f6 ea |F.F.O.....A4....|
-000002d0 b0 ab 39 18 16 03 01 00 cb 0c 00 00 c7 03 00 17 |..9.............|
-000002e0 41 04 d9 ae 3f 05 64 d3 77 d9 1d b8 37 8a d4 ac |A...?.d.w...7...|
-000002f0 51 f4 af 65 70 da c0 64 76 00 53 50 a2 d4 6c bc |Q..ep..dv.SP..l.|
-00000300 9c 62 ab 2f 7b 02 48 fe b2 0d 0b bb be 8f 34 55 |.b./{.H.......4U|
-00000310 fb ce ee 93 43 76 d5 ce 3b b5 79 ab 3d 74 6e 19 |....Cv..;.y.=tn.|
-00000320 a9 7d 00 80 05 cf 57 f2 f7 e0 ad 71 f1 75 d0 8b |.}....W....q.u..|
-00000330 f5 9d 83 1a 7e 0a 71 10 d7 9e fe bd 9d 47 62 45 |....~.q......GbE|
-00000340 8d 1b 9c 33 fa 2c 5c aa ce 9e 62 dc ad 56 ac 87 |...3.,\...b..V..|
-00000350 84 54 f5 32 87 d1 bb 8b d9 d7 6d 3c 6c 6d b7 79 |.T.2......m<lm.y|
-00000360 05 4d 55 f1 7c ef b1 fc e7 35 5d 41 66 60 44 4f |.MU.|....5]Af`DO|
-00000370 f3 dd de 25 f4 73 12 c2 b6 cc 61 d5 14 5a ff 88 |...%.s....a..Z..|
-00000380 ae f5 04 62 ac 2d 10 a0 95 c1 8e fa e6 db fe 41 |...b.-.........A|
-00000390 46 98 f1 3d 2e e3 2a 5a ea 87 26 6e 7a 4f 38 6c |F..=..*Z..&nzO8l|
-000003a0 4b 1f 1b 56 16 03 01 00 04 0e 00 00 00 |K..V.........|
+00000060 01 02 59 0b 00 02 55 00 02 52 00 02 4f 30 82 02 |..Y...U..R..O0..|
+00000070 4b 30 82 01 b4 a0 03 02 01 02 02 09 00 e8 f0 9d |K0..............|
+00000080 3f e2 5b ea a6 30 0d 06 09 2a 86 48 86 f7 0d 01 |?.[..0...*.H....|
+00000090 01 0b 05 00 30 1f 31 0b 30 09 06 03 55 04 0a 13 |....0.1.0...U...|
+000000a0 02 47 6f 31 10 30 0e 06 03 55 04 03 13 07 47 6f |.Go1.0...U....Go|
+000000b0 20 52 6f 6f 74 30 1e 17 0d 31 36 30 31 30 31 30 | Root0...1601010|
+000000c0 30 30 30 30 30 5a 17 0d 32 35 30 31 30 31 30 30 |00000Z..25010100|
+000000d0 30 30 30 30 5a 30 1a 31 0b 30 09 06 03 55 04 0a |0000Z0.1.0...U..|
+000000e0 13 02 47 6f 31 0b 30 09 06 03 55 04 03 13 02 47 |..Go1.0...U....G|
+000000f0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....|
+00000100 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 db 46 |.......0.......F|
+00000110 7d 93 2e 12 27 06 48 bc 06 28 21 ab 7e c4 b6 a2 |}...'.H..(!.~...|
+00000120 5d fe 1e 52 45 88 7a 36 47 a5 08 0d 92 42 5b c2 |]..RE.z6G....B[.|
+00000130 81 c0 be 97 79 98 40 fb 4f 6d 14 fd 2b 13 8b c2 |....y. at .Om..+...|
+00000140 a5 2e 67 d8 d4 09 9e d6 22 38 b7 4a 0b 74 73 2b |..g....."8.J.ts+|
+00000150 c2 34 f1 d1 93 e5 96 d9 74 7b f3 58 9f 6c 61 3c |.4......t{.X.la<|
+00000160 c0 b0 41 d4 d9 2b 2b 24 23 77 5b 1c 3b bd 75 5d |..A..++$#w[.;.u]|
+00000170 ce 20 54 cf a1 63 87 1d 1e 24 c4 f3 1d 1a 50 8b |. T..c...$....P.|
+00000180 aa b6 14 43 ed 97 a7 75 62 f4 14 c8 52 d7 02 03 |...C...ub...R...|
+00000190 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..|
+000001a0 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%|
+000001b0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........|
+000001c0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...|
+000001d0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....|
+000001e0 10 9f 91 16 1f 43 43 3e 49 a6 de 6d b6 80 d7 9f |.....CC>I..m....|
+000001f0 60 30 1b 06 03 55 1d 23 04 14 30 12 80 10 48 13 |`0...U.#..0...H.|
+00000200 49 4d 13 7e 16 31 bb a3 01 d5 ac ab 6e 7b 30 19 |IM.~.1......n{0.|
+00000210 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp|
+00000220 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H|
+00000230 86 f7 0d 01 01 0b 05 00 03 81 81 00 9d 30 cc 40 |.............0.@|
+00000240 2b 5b 50 a0 61 cb ba e5 53 58 e1 ed 83 28 a9 58 |+[P.a...SX...(.X|
+00000250 1a a9 38 a4 95 a1 ac 31 5a 1a 84 66 3d 43 d3 2d |..8....1Z..f=C.-|
+00000260 d9 0b f2 97 df d3 20 64 38 92 24 3a 00 bc cf 9c |...... d8.$:....|
+00000270 7d b7 40 20 01 5f aa d3 16 61 09 a2 76 fd 13 c3 |}.@ ._...a..v...|
+00000280 cc e1 0c 5c ee b1 87 82 f1 6c 04 ed 73 bb b3 43 |...\.....l..s..C|
+00000290 77 8d 0c 1c f1 0f a1 d8 40 83 61 c9 4c 72 2b 9d |w....... at .a.Lr+.|
+000002a0 ae db 46 06 06 4d f4 c1 b3 3e c0 d1 bd 42 d4 db |..F..M...>...B..|
+000002b0 fe 3d 13 60 84 5c 21 d3 3b e9 fa e7 16 03 01 00 |.=.`.\!.;.......|
+000002c0 aa 0c 00 00 a6 03 00 1d 20 85 05 5f e3 a2 b2 12 |........ .._....|
+000002d0 c8 82 53 2b c2 38 e1 a8 08 87 a7 d5 b3 98 6f 81 |..S+.8........o.|
+000002e0 ce 81 6b 78 3e 3a b7 1d 71 00 80 43 81 fb 47 5e |..kx>:..q..C..G^|
+000002f0 08 16 39 35 d3 c2 f3 ea bb 2c 7d bc 01 9b 35 5d |..95.....,}...5]|
+00000300 63 7e c3 38 f3 04 96 eb d7 3f d1 df 71 97 ec 22 |c~.8.....?..q.."|
+00000310 1b 4a 89 14 4d e5 44 08 87 52 69 ea 28 f8 6a ea |.J..M.D..Ri.(.j.|
+00000320 3e ff 17 de 4d 20 95 e3 6e 3f af 05 20 9b a3 ac |>...M ..n?.. ...|
+00000330 70 1b 1c bf f9 52 d6 11 6d d9 85 90 08 4d 64 1f |p....R..m....Md.|
+00000340 c5 35 34 37 11 b8 44 a3 ef 93 a6 b6 87 58 0b c4 |.547..D......X..|
+00000350 8e 94 d8 67 4d 09 7a 2a aa 95 db e6 af 29 21 a2 |...gM.z*.....)!.|
+00000360 ee c3 90 ef c6 53 46 12 fb 87 06 16 03 01 00 04 |.....SF.........|
+00000370 0e 00 00 00 |....|
>>> Flow 3 (client to server)
-00000000 16 03 01 00 46 10 00 00 42 41 04 1e 18 37 ef 0d |....F...BA...7..|
-00000010 19 51 88 35 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd |.Q.5uq..T[....g.|
-00000020 a7 24 20 3e b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e |.$ >.V...(^.+-O.|
-00000030 f1 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 |...lK[.V.2B.X..I|
-00000040 a6 b5 68 1a 41 03 56 6b dc 5a 89 14 03 01 00 01 |..h.A.Vk.Z......|
-00000050 01 16 03 01 00 30 73 96 2d 54 e3 9a bc 54 f5 9e |.....0s.-T...T..|
-00000060 e5 c7 46 35 b8 e1 d6 f6 14 95 92 f1 95 81 5a 9d |..F5..........Z.|
-00000070 4b df cc 96 77 f2 39 60 5d 5d da 94 b0 bf a0 80 |K...w.9`]]......|
-00000080 bd 28 55 b1 6a c3 |.(U.j.|
+00000000 16 03 01 00 25 10 00 00 21 20 2f e5 7d a3 47 cd |....%...! /.}.G.|
+00000010 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af c4 |bC.(.._.).0.....|
+00000020 cf c2 ed 90 99 5f 58 cb 3b 74 14 03 01 00 01 01 |....._X.;t......|
+00000030 16 03 01 00 30 50 f5 a9 34 25 ed a2 fb c8 7f 35 |....0P..4%.....5|
+00000040 08 57 59 da 54 c1 8d 92 ec 23 73 af f3 92 8d 19 |.WY.T....#s.....|
+00000050 03 ce ab 5b eb dc 5b 81 3f 51 a1 20 31 3f 33 da |...[..[.?Q. 1?3.|
+00000060 27 c5 c3 9c fd |'....|
>>> Flow 4 (server to client)
-00000000 14 03 01 00 01 01 16 03 01 00 30 c9 46 7a 8b be |..........0.Fz..|
-00000010 cd eb 5c 83 13 9c 9b 9f 70 84 38 3b 48 8c f4 11 |..\.....p.8;H...|
-00000020 b3 ca 10 09 38 d0 8e c8 9f 66 db b9 8a 95 15 6b |....8....f.....k|
-00000030 5e f8 1d 39 25 75 3d f1 b9 32 a3 |^..9%u=..2.|
+00000000 14 03 01 00 01 01 16 03 01 00 30 b1 61 9b 63 4e |..........0.a.cN|
+00000010 43 96 80 49 ac 2d 93 7d b9 f2 bb 81 79 5e 94 bf |C..I.-.}....y^..|
+00000020 06 d0 a6 14 46 91 cd 90 b0 8a 85 ee fe 41 a7 4d |....F........A.M|
+00000030 97 d7 4d 40 5e f4 5b bd d3 0c db |..M@^.[....|
>>> Flow 5 (client to server)
-00000000 17 03 01 00 20 04 69 a9 01 42 f4 1a fd 5a 4e 12 |.... .i..B...ZN.|
-00000010 2b 6d cd 68 6b 94 70 b2 80 07 cf 79 a4 43 69 bf |+m.hk.p....y.Ci.|
-00000020 27 25 b5 ae e7 17 03 01 00 20 bf 1e cd 83 64 af |'%....... ....d.|
-00000030 6f cc 89 21 bf 16 e7 e8 86 29 f3 0a 36 ab a4 e3 |o..!.....)..6...|
-00000040 fa c0 7e 7a 78 ca 29 17 11 9c 15 03 01 00 20 94 |..~zx.)....... .|
-00000050 7a dd 17 eb fd 67 b1 cc 58 c9 c3 ae db b6 b0 a4 |z....g..X.......|
-00000060 68 15 36 ca 33 22 ec 03 fb cf 2f f5 70 d6 9d |h.6.3"..../.p..|
+00000000 17 03 01 00 20 49 21 bc a5 4c 96 41 3f 22 87 0a |.... I!..L.A?"..|
+00000010 c0 4e 0e 54 cb c2 27 8a 4f b0 37 fb b4 1f c1 4e |.N.T..'.O.7....N|
+00000020 77 e1 09 57 23 17 03 01 00 20 f0 f0 3b 78 a8 ae |w..W#.... ..;x..|
+00000030 ef b1 e0 f4 29 0f 90 4a 0f e5 48 34 84 5e 4f d8 |....)..J..H4.^O.|
+00000040 53 46 f8 29 64 2b 8e 87 79 0a 15 03 01 00 20 71 |SF.)d+..y..... q|
+00000050 32 6c 08 2a f7 18 c8 d5 48 a8 c7 d1 68 7a 65 ec |2l.*....H...hze.|
+00000060 3e fa 4b fe ff 76 1a 57 64 22 61 27 a0 5d b6 |>.K..v.Wd"a'.].|
diff --git a/src/crypto/tls/testdata/Client-TLSv10-RSA-RC4 b/src/crypto/tls/testdata/Client-TLSv10-RSA-RC4
index 57eb930..7ecfbde 100644
--- a/src/crypto/tls/testdata/Client-TLSv10-RSA-RC4
+++ b/src/crypto/tls/testdata/Client-TLSv10-RSA-RC4
@@ -1,79 +1,78 @@
>>> Flow 1 (client to server)
-00000000 16 03 01 00 85 01 00 00 81 03 03 00 00 00 00 00 |................|
+00000000 16 03 01 00 91 01 00 00 8d 03 03 00 00 00 00 00 |................|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
-00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 22 c0 2f |............."./|
-00000030 c0 2b c0 30 c0 2c c0 11 c0 07 c0 13 c0 09 c0 14 |.+.0.,..........|
-00000040 c0 0a 00 9c 00 9d 00 05 00 2f 00 35 c0 12 00 0a |........./.5....|
-00000050 01 00 00 36 00 05 00 05 01 00 00 00 00 00 0a 00 |...6............|
-00000060 08 00 06 00 17 00 18 00 19 00 0b 00 02 01 00 00 |................|
-00000070 0d 00 0e 00 0c 04 01 04 03 05 01 05 03 02 01 02 |................|
-00000080 03 ff 01 00 01 00 00 12 00 00 |..........|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2c cc a8 |.............,..|
+00000030 cc a9 c0 2f c0 2b c0 30 c0 2c c0 27 c0 13 c0 23 |.../.+.0.,.'...#|
+00000040 c0 09 c0 14 c0 0a 00 9c 00 9d 00 3c 00 2f 00 35 |...........<./.5|
+00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 38 00 05 |.............8..|
+00000060 00 05 01 00 00 00 00 00 0a 00 0a 00 08 00 1d 00 |................|
+00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 0e 00 |................|
+00000080 0c 04 01 04 03 05 01 05 03 02 01 02 03 ff 01 00 |................|
+00000090 01 00 00 12 00 00 |......|
>>> Flow 2 (server to client)
-00000000 16 03 01 00 51 02 00 00 4d 03 01 1c 0e e9 7a c6 |....Q...M.....z.|
-00000010 91 fe 7e 8c 6f 0b 8e cf 23 f5 07 29 10 de 05 a6 |..~.o...#..)....|
-00000020 20 72 11 65 4f 2b 45 95 96 02 62 20 43 a8 93 34 | r.eO+E...b C..4|
-00000030 e7 c0 29 d5 fb 26 f9 c2 59 37 94 dc e6 b5 c4 ed |..)..&..Y7......|
-00000040 ae 7a d7 94 d1 f4 d8 0b 02 ad 20 1b 00 05 00 00 |.z........ .....|
-00000050 05 ff 01 00 01 00 16 03 01 02 71 0b 00 02 6d 00 |..........q...m.|
-00000060 02 6a 00 02 67 30 82 02 63 30 82 01 cc a0 03 02 |.j..g0..c0......|
-00000070 01 02 02 09 00 a2 73 00 0c 81 00 cb f3 30 0d 06 |......s......0..|
-00000080 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 2b 31 17 |.*.H........0+1.|
-00000090 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 |0...U....Google |
-000000a0 54 45 53 54 49 4e 47 31 10 30 0e 06 03 55 04 03 |TESTING1.0...U..|
-000000b0 13 07 47 6f 20 52 6f 6f 74 30 1e 17 0d 31 35 30 |..Go Root0...150|
-000000c0 31 30 31 30 30 30 30 30 30 5a 17 0d 32 35 30 31 |101000000Z..2501|
-000000d0 30 31 30 30 30 30 30 30 5a 30 26 31 17 30 15 06 |01000000Z0&1.0..|
-000000e0 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 54 45 53 |.U....Google TES|
-000000f0 54 49 4e 47 31 0b 30 09 06 03 55 04 03 13 02 47 |TING1.0...U....G|
-00000100 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....|
-00000110 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 af 87 |.......0........|
-00000120 88 f6 20 1b 95 65 6c 14 ab 44 05 af 3b 45 14 e3 |.. ..el..D..;E..|
-00000130 b7 6d fd 00 63 4d 95 7f fe 6a 62 35 86 c0 4a f9 |.m..cM...jb5..J.|
-00000140 18 7c f6 aa 25 5e 7a 64 31 66 00 ba f4 8e 92 af |.|..%^zd1f......|
-00000150 c7 6b d8 76 d4 f3 5f 41 cb 6e 56 15 97 1b 97 c1 |.k.v.._A.nV.....|
-00000160 3c 12 39 21 66 3d 2b 16 d1 bc db 1c c0 a7 da b7 |<.9!f=+.........|
-00000170 ca ad ba da cb d5 21 50 ec de 8d ab d1 6b 81 4b |......!P.....k.K|
-00000180 89 02 f3 c4 be c1 6c 89 b1 44 84 bd 21 d1 04 7d |......l..D..!..}|
-00000190 9d 16 4d f9 82 15 f6 ef fa d6 09 47 f2 fb 02 03 |..M........G....|
-000001a0 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..|
-000001b0 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%|
-000001c0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........|
-000001d0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...|
-000001e0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....|
-000001f0 10 12 50 8d 89 6f 1b d1 dc 54 4d 6e cb 69 5e 06 |..P..o...TMn.i^.|
-00000200 f4 30 1b 06 03 55 1d 23 04 14 30 12 80 10 bf 3d |.0...U.#..0....=|
-00000210 b6 a9 66 f2 b8 40 cf ea b4 03 78 48 1a 41 30 19 |..f.. at ....xH.A0.|
-00000220 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp|
-00000230 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H|
-00000240 86 f7 0d 01 01 0b 05 00 03 81 81 00 92 7c af 91 |.............|..|
-00000250 55 12 18 96 59 31 a6 48 40 d5 2d d5 ee bb 02 a0 |U...Y1.H at .-.....|
-00000260 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 da 4f 3d c0 fa |...|..0}<.v.O=..|
-00000270 ae 2d 33 24 6b 03 7b 1b 67 59 11 21 b5 11 bc 77 |.-3$k.{.gY.!...w|
-00000280 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f 22 3e 63 10 6b |...n.-.5.d_">c.k|
-00000290 be ff 14 86 6d 0d f0 15 31 a8 14 38 1e 3b 84 87 |....m...1..8.;..|
-000002a0 2c cb 98 ed 51 76 b9 b1 4f dd db 9b 84 04 86 40 |,...Qv..O......@|
-000002b0 fa 51 dd ba b4 8d eb e3 46 de 46 b9 4f 86 c7 f9 |.Q......F.F.O...|
-000002c0 a4 c2 41 34 ac cc f6 ea b0 ab 39 18 16 03 01 00 |..A4......9.....|
-000002d0 04 0e 00 00 00 |.....|
+00000000 16 03 01 00 51 02 00 00 4d 03 01 4c 98 ce a5 80 |....Q...M..L....|
+00000010 84 dc d3 70 de 75 bf 26 5c 15 8b b7 2c 78 30 a7 |...p.u.&\...,x0.|
+00000020 65 1a 0c f7 1a e5 51 91 7c cb ca 20 83 2c 90 3b |e.....Q.|.. .,.;|
+00000030 cf dd 4e 51 8b 27 98 95 aa d9 1d da 4d 3d e1 18 |..NQ.'......M=..|
+00000040 f5 58 fd 85 c5 ed c9 5f 12 2f 4b b3 00 05 00 00 |.X....._./K.....|
+00000050 05 ff 01 00 01 00 16 03 01 02 59 0b 00 02 55 00 |..........Y...U.|
+00000060 02 52 00 02 4f 30 82 02 4b 30 82 01 b4 a0 03 02 |.R..O0..K0......|
+00000070 01 02 02 09 00 e8 f0 9d 3f e2 5b ea a6 30 0d 06 |........?.[..0..|
+00000080 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 1f 31 0b |.*.H........0.1.|
+00000090 30 09 06 03 55 04 0a 13 02 47 6f 31 10 30 0e 06 |0...U....Go1.0..|
+000000a0 03 55 04 03 13 07 47 6f 20 52 6f 6f 74 30 1e 17 |.U....Go Root0..|
+000000b0 0d 31 36 30 31 30 31 30 30 30 30 30 30 5a 17 0d |.160101000000Z..|
+000000c0 32 35 30 31 30 31 30 30 30 30 30 30 5a 30 1a 31 |250101000000Z0.1|
+000000d0 0b 30 09 06 03 55 04 0a 13 02 47 6f 31 0b 30 09 |.0...U....Go1.0.|
+000000e0 06 03 55 04 03 13 02 47 6f 30 81 9f 30 0d 06 09 |..U....Go0..0...|
+000000f0 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 30 |*.H............0|
+00000100 81 89 02 81 81 00 db 46 7d 93 2e 12 27 06 48 bc |.......F}...'.H.|
+00000110 06 28 21 ab 7e c4 b6 a2 5d fe 1e 52 45 88 7a 36 |.(!.~...]..RE.z6|
+00000120 47 a5 08 0d 92 42 5b c2 81 c0 be 97 79 98 40 fb |G....B[.....y. at .|
+00000130 4f 6d 14 fd 2b 13 8b c2 a5 2e 67 d8 d4 09 9e d6 |Om..+.....g.....|
+00000140 22 38 b7 4a 0b 74 73 2b c2 34 f1 d1 93 e5 96 d9 |"8.J.ts+.4......|
+00000150 74 7b f3 58 9f 6c 61 3c c0 b0 41 d4 d9 2b 2b 24 |t{.X.la<..A..++$|
+00000160 23 77 5b 1c 3b bd 75 5d ce 20 54 cf a1 63 87 1d |#w[.;.u]. T..c..|
+00000170 1e 24 c4 f3 1d 1a 50 8b aa b6 14 43 ed 97 a7 75 |.$....P....C...u|
+00000180 62 f4 14 c8 52 d7 02 03 01 00 01 a3 81 93 30 81 |b...R.........0.|
+00000190 90 30 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 05 |.0...U..........|
+000001a0 a0 30 1d 06 03 55 1d 25 04 16 30 14 06 08 2b 06 |.0...U.%..0...+.|
+000001b0 01 05 05 07 03 01 06 08 2b 06 01 05 05 07 03 02 |........+.......|
+000001c0 30 0c 06 03 55 1d 13 01 01 ff 04 02 30 00 30 19 |0...U.......0.0.|
+000001d0 06 03 55 1d 0e 04 12 04 10 9f 91 16 1f 43 43 3e |..U..........CC>|
+000001e0 49 a6 de 6d b6 80 d7 9f 60 30 1b 06 03 55 1d 23 |I..m....`0...U.#|
+000001f0 04 14 30 12 80 10 48 13 49 4d 13 7e 16 31 bb a3 |..0...H.IM.~.1..|
+00000200 01 d5 ac ab 6e 7b 30 19 06 03 55 1d 11 04 12 30 |....n{0...U....0|
+00000210 10 82 0e 65 78 61 6d 70 6c 65 2e 67 6f 6c 61 6e |...example.golan|
+00000220 67 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 |g0...*.H........|
+00000230 03 81 81 00 9d 30 cc 40 2b 5b 50 a0 61 cb ba e5 |.....0. at +[P.a...|
+00000240 53 58 e1 ed 83 28 a9 58 1a a9 38 a4 95 a1 ac 31 |SX...(.X..8....1|
+00000250 5a 1a 84 66 3d 43 d3 2d d9 0b f2 97 df d3 20 64 |Z..f=C.-...... d|
+00000260 38 92 24 3a 00 bc cf 9c 7d b7 40 20 01 5f aa d3 |8.$:....}.@ ._..|
+00000270 16 61 09 a2 76 fd 13 c3 cc e1 0c 5c ee b1 87 82 |.a..v......\....|
+00000280 f1 6c 04 ed 73 bb b3 43 77 8d 0c 1c f1 0f a1 d8 |.l..s..Cw.......|
+00000290 40 83 61 c9 4c 72 2b 9d ae db 46 06 06 4d f4 c1 |@.a.Lr+...F..M..|
+000002a0 b3 3e c0 d1 bd 42 d4 db fe 3d 13 60 84 5c 21 d3 |.>...B...=.`.\!.|
+000002b0 3b e9 fa e7 16 03 01 00 04 0e 00 00 00 |;............|
>>> Flow 3 (client to server)
-00000000 16 03 01 00 86 10 00 00 82 00 80 73 bd 73 65 92 |...........s.se.|
-00000010 86 23 41 14 79 7f d5 c1 10 ce 94 4d ad 9c c3 a9 |.#A.y......M....|
-00000020 87 b5 32 52 f8 6b 11 93 2d 9b 98 0b 8b 1d c0 f6 |..2R.k..-.......|
-00000030 53 17 6d c7 9c 2e ae c9 6f cc 99 23 38 37 1a 10 |S.m.....o..#87..|
-00000040 fe 05 0b b5 55 0a 14 e9 60 7d 70 26 98 e2 54 d9 |....U...`}p&..T.|
-00000050 65 cf 2e f4 53 5f 1d aa 3a f6 33 7b eb 4c 0e b3 |e...S_..:.3{.L..|
-00000060 ff 5a db 36 2a 47 f3 df f9 fc f5 31 78 83 aa 6b |.Z.6*G.....1x..k|
-00000070 52 b7 ba 1a 96 bc fa c1 a1 a9 bb 2b f5 38 89 00 |R..........+.8..|
-00000080 4d e5 78 13 4e a4 38 46 42 dc 16 14 03 01 00 01 |M.x.N.8FB.......|
-00000090 01 16 03 01 00 24 ae a9 da 45 6b 5e 76 57 02 62 |.....$...Ek^vW.b|
-000000a0 63 d4 1f 40 bf c9 47 27 a9 7a 24 c0 f0 e9 c2 c4 |c.. at ..G'.z$.....|
-000000b0 9c 07 84 df ae c7 66 40 d2 b0 |......f at ..|
+00000000 16 03 01 00 86 10 00 00 82 00 80 b9 65 8d bf a7 |............e...|
+00000010 c8 4b 79 ce 6f cb 8b 13 1c ac b9 7d 66 5e e9 ba |.Ky.o......}f^..|
+00000020 1d 71 4e a9 e9 34 ae f6 64 65 90 3b d8 16 52 a2 |.qN..4..de.;..R.|
+00000030 6f f4 cb 8a 13 74 a2 ee b7 27 69 b4 41 c0 90 68 |o....t...'i.A..h|
+00000040 bc 02 69 e1 c6 48 4f 39 36 30 25 ca 4c 17 ce 83 |..i..HO960%.L...|
+00000050 9e 08 56 e3 05 49 93 9e 2e c4 fb e6 c8 01 f1 0f |..V..I..........|
+00000060 c5 70 0f 08 83 48 e9 48 ef 6e 50 8b 05 7e e5 84 |.p...H.H.nP..~..|
+00000070 25 fa 55 c7 ae 31 02 27 00 ef 3f 98 86 20 12 89 |%.U..1.'..?.. ..|
+00000080 91 59 28 b4 f7 d7 af d2 69 61 35 14 03 01 00 01 |.Y(.....ia5.....|
+00000090 01 16 03 01 00 24 0e 4d ff 2c 39 80 ba a5 96 18 |.....$.M.,9.....|
+000000a0 56 15 94 9f e2 1e 7d 13 62 51 d5 e1 05 f8 d8 b3 |V.....}.bQ......|
+000000b0 bd 77 58 38 95 b4 7d 37 66 8a |.wX8..}7f.|
>>> Flow 4 (server to client)
-00000000 14 03 01 00 01 01 16 03 01 00 24 e9 84 92 41 c5 |..........$...A.|
-00000010 31 e1 3c a9 78 18 d1 7b e1 b1 0b 0a ef 18 54 19 |1.<.x..{......T.|
-00000020 7c ba c7 59 ca c8 7b 4d c9 f4 ad d6 7b 77 fb ||..Y..{M....{w.|
+00000000 14 03 01 00 01 01 16 03 01 00 24 dc 6f da 57 0d |..........$.o.W.|
+00000010 f8 b8 aa d5 e5 0a 2e 81 ed 2a b7 f8 0e 2a f1 05 |.........*...*..|
+00000020 76 8d 4f b0 0e db 16 c5 d7 c8 5e f9 fb 9e e0 |v.O.......^....|
>>> Flow 5 (client to server)
-00000000 17 03 01 00 1a 1a dc 95 e2 4f ec f1 f6 68 9d 15 |.........O...h..|
-00000010 56 d5 7b 06 1a f5 be bb b1 ca b2 a6 d3 9e 28 15 |V.{...........(.|
-00000020 03 01 00 16 64 fe 4a 37 d3 32 a8 55 38 9e 0f 76 |....d.J7.2.U8..v|
-00000030 50 de e2 2e aa 77 15 2b e5 21 |P....w.+.!|
+00000000 17 03 01 00 1a 47 97 4d e6 59 d4 2f bb 60 56 69 |.....G.M.Y./.`Vi|
+00000010 d8 bc 8d 91 44 7c cd 85 7e c5 18 5f 57 8e 08 15 |....D|..~.._W...|
+00000020 03 01 00 16 f7 79 56 72 e6 77 8d af 94 55 d7 0e |.....yVr.w...U..|
+00000030 96 c8 3b 35 52 ea f7 e7 b8 d6 |..;5R.....|
diff --git a/src/crypto/tls/testdata/Client-TLSv11-ECDHE-ECDSA-AES b/src/crypto/tls/testdata/Client-TLSv11-ECDHE-ECDSA-AES
index 87fbe3f..5232ad5 100644
--- a/src/crypto/tls/testdata/Client-TLSv11-ECDHE-ECDSA-AES
+++ b/src/crypto/tls/testdata/Client-TLSv11-ECDHE-ECDSA-AES
@@ -1,19 +1,20 @@
>>> Flow 1 (client to server)
-00000000 16 03 01 00 85 01 00 00 81 03 03 00 00 00 00 00 |................|
+00000000 16 03 01 00 91 01 00 00 8d 03 03 00 00 00 00 00 |................|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
-00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 22 c0 2f |............."./|
-00000030 c0 2b c0 30 c0 2c c0 11 c0 07 c0 13 c0 09 c0 14 |.+.0.,..........|
-00000040 c0 0a 00 9c 00 9d 00 05 00 2f 00 35 c0 12 00 0a |........./.5....|
-00000050 01 00 00 36 00 05 00 05 01 00 00 00 00 00 0a 00 |...6............|
-00000060 08 00 06 00 17 00 18 00 19 00 0b 00 02 01 00 00 |................|
-00000070 0d 00 0e 00 0c 04 01 04 03 05 01 05 03 02 01 02 |................|
-00000080 03 ff 01 00 01 00 00 12 00 00 |..........|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2c cc a8 |.............,..|
+00000030 cc a9 c0 2f c0 2b c0 30 c0 2c c0 27 c0 13 c0 23 |.../.+.0.,.'...#|
+00000040 c0 09 c0 14 c0 0a 00 9c 00 9d 00 3c 00 2f 00 35 |...........<./.5|
+00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 38 00 05 |.............8..|
+00000060 00 05 01 00 00 00 00 00 0a 00 0a 00 08 00 1d 00 |................|
+00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 0e 00 |................|
+00000080 0c 04 01 04 03 05 01 05 03 02 01 02 03 ff 01 00 |................|
+00000090 01 00 00 12 00 00 |......|
>>> Flow 2 (server to client)
-00000000 16 03 02 00 59 02 00 00 55 03 02 07 ae a6 e4 1a |....Y...U.......|
-00000010 f7 7a 0c bc ea 21 0e 86 e3 d0 b4 2c fc d9 97 a3 |.z...!.....,....|
-00000020 8b 29 5f 59 3e a9 06 fb ca d9 57 20 cd 45 e7 cd |.)_Y>.....W .E..|
-00000030 6c 4c 56 cd 7c 4c 51 2c 8f 8c 67 a2 05 51 26 f5 |lLV.|LQ,..g..Q&.|
-00000040 17 cc 18 c2 a1 29 94 4b e2 02 cc 1c c0 09 00 00 |.....).K........|
+00000000 16 03 02 00 59 02 00 00 55 03 02 30 f8 f6 b2 af |....Y...U..0....|
+00000010 99 b0 e0 f6 9a eb 47 6f 2f ad 2f 45 18 56 b3 dd |......Go/./E.V..|
+00000020 b6 b9 20 fb af 97 43 1f 0e 51 c0 20 fe 6c 12 64 |.. ...C..Q. .l.d|
+00000030 8e cc a4 24 d6 e6 80 cf f2 9e 74 3f a7 1e 8b da |...$......t?....|
+00000040 0e 3c 58 74 f4 8f be 1f 60 86 57 c6 c0 09 00 00 |.<Xt....`.W.....|
00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................|
00000060 02 02 0e 0b 00 02 0a 00 02 07 00 02 04 30 82 02 |.............0..|
00000070 00 30 82 01 62 02 09 00 b8 bf 2d 47 a0 d2 eb f4 |.0..b.....-G....|
@@ -48,43 +49,39 @@
00000240 13 83 0d 94 06 bb d4 37 7a f6 ec 7a c9 86 2e dd |.......7z..z....|
00000250 d7 11 69 7f 85 7c 56 de fb 31 78 2b e4 c7 78 0d |..i..|V..1x+..x.|
00000260 ae cb be 9e 4e 36 24 31 7b 6a 0f 39 95 12 07 8f |....N6$1{j.9....|
-00000270 2a 16 03 02 00 d6 0c 00 00 d2 03 00 17 41 04 cd |*............A..|
-00000280 9d 30 75 8d 98 17 b5 1b 2f 4e af ea 69 52 a1 c1 |.0u...../N..iR..|
-00000290 86 73 6a 56 54 f8 ed b6 35 e5 4e 34 a0 6f b1 85 |.sjVT...5.N4.o..|
-000002a0 95 8e be 77 c5 1a 56 9a 59 d1 69 79 ea d6 2b c7 |...w..V.Y.iy..+.|
-000002b0 c1 4a fb bc f8 98 c3 49 1c f3 ce 33 ef 98 20 00 |.J.....I...3.. .|
-000002c0 8b 30 81 88 02 42 00 8b 15 7e 3b 4f 73 b0 8e ca |.0...B...~;Os...|
-000002d0 67 e0 7c d8 89 70 f1 b2 6b 9c 19 84 fa aa 6e 15 |g.|..p..k.....n.|
-000002e0 8b 46 95 57 d5 ac 79 f3 e8 2a e5 7a a8 1e c3 d7 |.F.W..y..*.z....|
-000002f0 0a b2 02 cd d6 32 34 2f 37 65 41 c8 61 c6 ed e5 |.....24/7eA.a...|
-00000300 d2 6f 0f e8 1a 49 b6 c7 02 42 00 d1 00 f4 05 65 |.o...I...B.....e|
-00000310 dd 43 42 db 8b 0b 95 9d f5 62 51 e6 58 60 20 9b |.CB......bQ.X` .|
-00000320 46 84 e6 1f 76 4a 92 42 e4 4d 77 5b 76 a5 78 a0 |F...vJ.B.Mw[v.x.|
-00000330 b0 f0 50 7d f9 4f ca 43 9d c2 50 cb 20 1c 40 52 |..P}.O.C..P. . at R|
-00000340 0f a8 c4 43 7a 9d d5 61 de 26 30 b5 16 03 02 00 |...Cz..a.&0.....|
-00000350 04 0e 00 00 00 |.....|
+00000270 2a 16 03 02 00 b3 0c 00 00 af 03 00 1d 20 4b 2d |*............ K-|
+00000280 60 48 54 b4 48 42 10 de e1 98 f0 fb 73 d9 49 16 |`HT.HB......s.I.|
+00000290 3e a2 11 b3 84 50 de 26 00 09 d8 36 34 04 00 89 |>....P.&...64...|
+000002a0 30 81 86 02 41 24 90 6f 3e 1a 2c a5 7f 08 dc b2 |0...A$.o>.,.....|
+000002b0 d3 46 27 5e cb 1f 2a 6d 92 ba 1b fe e3 c5 64 79 |.F'^..*m......dy|
+000002c0 31 50 8c 43 4b b1 ee 0d 6f 53 ad 6f e9 db 86 e7 |1P.CK...oS.o....|
+000002d0 1f e3 77 f1 8d a8 ab 81 2a d6 fa e7 98 d5 bc 0d |..w.....*.......|
+000002e0 ec af ea 84 c4 f8 02 41 6a d2 66 32 e1 d7 46 1a |.......Aj.f2..F.|
+000002f0 95 5a 91 c3 76 82 20 c2 a3 a2 32 f5 fd eb a2 0e |.Z..v. ...2.....|
+00000300 0f d8 a9 31 7a ef a8 05 6c 5d bf 27 d0 2d 94 ca |...1z...l].'.-..|
+00000310 fb d6 62 7a 1c 6a 46 20 fe ed a6 60 a3 db b1 bd |..bz.jF ...`....|
+00000320 11 82 05 c3 db 0c 4a 2d 6c 16 03 02 00 04 0e 00 |......J-l.......|
+00000330 00 00 |..|
>>> Flow 3 (client to server)
-00000000 16 03 02 00 46 10 00 00 42 41 04 1e 18 37 ef 0d |....F...BA...7..|
-00000010 19 51 88 35 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd |.Q.5uq..T[....g.|
-00000020 a7 24 20 3e b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e |.$ >.V...(^.+-O.|
-00000030 f1 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 |...lK[.V.2B.X..I|
-00000040 a6 b5 68 1a 41 03 56 6b dc 5a 89 14 03 02 00 01 |..h.A.Vk.Z......|
-00000050 01 16 03 02 00 40 00 00 00 00 00 00 00 00 00 00 |..... at ..........|
-00000060 00 00 00 00 00 00 c0 81 e7 e8 40 f3 24 45 ed 74 |.......... at .$E.t|
-00000070 86 31 7b 39 d1 3c a2 67 99 28 06 b1 34 b6 3c a6 |.1{9.<.g.(..4.<.|
-00000080 1d ce 39 aa 56 c9 72 0d f1 e0 c1 5a 51 a0 5d f2 |..9.V.r....ZQ.].|
-00000090 44 4d e6 d7 0e 84 |DM....|
+00000000 16 03 02 00 25 10 00 00 21 20 2f e5 7d a3 47 cd |....%...! /.}.G.|
+00000010 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af c4 |bC.(.._.).0.....|
+00000020 cf c2 ed 90 99 5f 58 cb 3b 74 14 03 02 00 01 01 |....._X.;t......|
+00000030 16 03 02 00 40 00 00 00 00 00 00 00 00 00 00 00 |.... at ...........|
+00000040 00 00 00 00 00 22 71 28 3d 07 73 61 5e 84 72 36 |....."q(=.sa^.r6|
+00000050 c0 87 37 4a 5b c2 d9 40 96 a2 01 20 b2 04 23 2f |..7J[.. at ... ..#/|
+00000060 c1 6f 1e 7c a1 77 20 0f 87 46 98 a2 5c aa 35 37 |.o.|.w ..F..\.57|
+00000070 37 87 5a 75 33 |7.Zu3|
>>> Flow 4 (server to client)
-00000000 14 03 02 00 01 01 16 03 02 00 40 82 8d c7 e3 7b |.......... at ....{|
-00000010 f8 9d 33 a1 c2 08 8c 24 d9 af 66 64 6e e8 61 8e |..3....$..fdn.a.|
-00000020 3c 03 65 2d c3 64 a2 26 23 a5 25 3f a2 a4 f9 40 |<.e-.d.&#.%?...@|
-00000030 ec 9f 0e b8 57 b1 5f 84 ea 94 72 1a 3e 60 f1 dd |....W._...r.>`..|
-00000040 af 2e 81 f7 16 de 43 85 21 51 49 |......C.!QI|
+00000000 14 03 02 00 01 01 16 03 02 00 40 21 b5 1f 8d 4b |..........@!...K|
+00000010 1c a7 28 4e 73 3e d7 c5 75 6e eb e4 b3 95 02 4e |..(Ns>..un.....N|
+00000020 a3 47 03 44 97 69 c9 89 f5 ac e2 29 5e 22 e7 2c |.G.D.i.....)^".,|
+00000030 a2 2d e3 ac 64 45 ae 9d 07 9e fe f8 c6 85 47 4d |.-..dE........GM|
+00000040 59 be 72 8d e6 50 da c7 83 91 14 |Y.r..P.....|
>>> Flow 5 (client to server)
00000000 17 03 02 00 30 00 00 00 00 00 00 00 00 00 00 00 |....0...........|
-00000010 00 00 00 00 00 43 8f 88 82 c8 e1 55 37 76 d7 a5 |.....C.....U7v..|
-00000020 83 c6 d2 94 26 fe 30 1f e2 24 ca d7 27 22 33 47 |....&.0..$..'"3G|
-00000030 5f a9 74 9d ad 15 03 02 00 30 00 00 00 00 00 00 |_.t......0......|
-00000040 00 00 00 00 00 00 00 00 00 00 49 8e ee 5c ec 86 |..........I..\..|
-00000050 e7 64 a7 ac 0d 5c c4 43 a6 45 a4 22 b7 3d 21 06 |.d...\.C.E.".=!.|
-00000060 11 67 08 99 9a 08 a1 7c e0 1e |.g.....|..|
+00000010 00 00 00 00 00 57 45 25 4c 1b 90 d3 28 e1 69 43 |.....WE%L...(.iC|
+00000020 c5 28 d9 d5 15 35 cf 41 bb 38 f2 12 c6 18 a5 a2 |.(...5.A.8......|
+00000030 f5 e4 64 1d 59 15 03 02 00 30 00 00 00 00 00 00 |..d.Y....0......|
+00000040 00 00 00 00 00 00 00 00 00 00 35 06 5f e3 ff e7 |..........5._...|
+00000050 f0 f1 0c d5 b1 59 42 80 19 8d 67 1b 18 18 5c 18 |.....YB...g...\.|
+00000060 42 38 67 85 c3 ab e2 dc 60 d4 |B8g.....`.|
diff --git a/src/crypto/tls/testdata/Client-TLSv11-ECDHE-RSA-AES b/src/crypto/tls/testdata/Client-TLSv11-ECDHE-RSA-AES
index 7581642..48ff7bc 100644
--- a/src/crypto/tls/testdata/Client-TLSv11-ECDHE-RSA-AES
+++ b/src/crypto/tls/testdata/Client-TLSv11-ECDHE-RSA-AES
@@ -1,95 +1,91 @@
>>> Flow 1 (client to server)
-00000000 16 03 01 00 85 01 00 00 81 03 03 00 00 00 00 00 |................|
+00000000 16 03 01 00 91 01 00 00 8d 03 03 00 00 00 00 00 |................|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
-00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 22 c0 2f |............."./|
-00000030 c0 2b c0 30 c0 2c c0 11 c0 07 c0 13 c0 09 c0 14 |.+.0.,..........|
-00000040 c0 0a 00 9c 00 9d 00 05 00 2f 00 35 c0 12 00 0a |........./.5....|
-00000050 01 00 00 36 00 05 00 05 01 00 00 00 00 00 0a 00 |...6............|
-00000060 08 00 06 00 17 00 18 00 19 00 0b 00 02 01 00 00 |................|
-00000070 0d 00 0e 00 0c 04 01 04 03 05 01 05 03 02 01 02 |................|
-00000080 03 ff 01 00 01 00 00 12 00 00 |..........|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2c cc a8 |.............,..|
+00000030 cc a9 c0 2f c0 2b c0 30 c0 2c c0 27 c0 13 c0 23 |.../.+.0.,.'...#|
+00000040 c0 09 c0 14 c0 0a 00 9c 00 9d 00 3c 00 2f 00 35 |...........<./.5|
+00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 38 00 05 |.............8..|
+00000060 00 05 01 00 00 00 00 00 0a 00 0a 00 08 00 1d 00 |................|
+00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 0e 00 |................|
+00000080 0c 04 01 04 03 05 01 05 03 02 01 02 03 ff 01 00 |................|
+00000090 01 00 00 12 00 00 |......|
>>> Flow 2 (server to client)
-00000000 16 03 02 00 59 02 00 00 55 03 02 0c 74 28 d1 02 |....Y...U...t(..|
-00000010 15 8f 15 9c ec 8c 4e 34 97 d8 14 ab 0c ed 1b 38 |......N4.......8|
-00000020 af 7f e6 d3 41 db fd ad a0 8d 4f 20 03 71 4a d6 |....A.....O .qJ.|
-00000030 32 23 57 6c e1 55 34 1d 48 6f 9d e0 9a db 15 9d |2#Wl.U4.Ho......|
-00000040 5b 45 a7 3e 4e 98 31 7d f5 d4 b6 36 c0 13 00 00 |[E.>N.1}...6....|
+00000000 16 03 02 00 59 02 00 00 55 03 02 10 ca d9 1b 83 |....Y...U.......|
+00000010 59 c8 a5 a5 6a 89 65 6e 1c 0a 49 98 69 05 49 27 |Y...j.en..I.i.I'|
+00000020 96 72 74 5f 6e 5b 66 26 3b fd f8 20 23 b5 d6 c5 |.rt_n[f&;.. #...|
+00000030 09 f1 66 02 27 5c 5a 15 17 83 c5 11 a4 32 cf d8 |..f.'\Z......2..|
+00000040 1e a0 e7 93 83 35 6e aa 61 ae 97 77 c0 13 00 00 |.....5n.a..w....|
00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................|
-00000060 02 02 71 0b 00 02 6d 00 02 6a 00 02 67 30 82 02 |..q...m..j..g0..|
-00000070 63 30 82 01 cc a0 03 02 01 02 02 09 00 a2 73 00 |c0............s.|
-00000080 0c 81 00 cb f3 30 0d 06 09 2a 86 48 86 f7 0d 01 |.....0...*.H....|
-00000090 01 0b 05 00 30 2b 31 17 30 15 06 03 55 04 0a 13 |....0+1.0...U...|
-000000a0 0e 47 6f 6f 67 6c 65 20 54 45 53 54 49 4e 47 31 |.Google TESTING1|
-000000b0 10 30 0e 06 03 55 04 03 13 07 47 6f 20 52 6f 6f |.0...U....Go Roo|
-000000c0 74 30 1e 17 0d 31 35 30 31 30 31 30 30 30 30 30 |t0...15010100000|
-000000d0 30 5a 17 0d 32 35 30 31 30 31 30 30 30 30 30 30 |0Z..250101000000|
-000000e0 5a 30 26 31 17 30 15 06 03 55 04 0a 13 0e 47 6f |Z0&1.0...U....Go|
-000000f0 6f 67 6c 65 20 54 45 53 54 49 4e 47 31 0b 30 09 |ogle TESTING1.0.|
-00000100 06 03 55 04 03 13 02 47 6f 30 81 9f 30 0d 06 09 |..U....Go0..0...|
-00000110 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 30 |*.H............0|
-00000120 81 89 02 81 81 00 af 87 88 f6 20 1b 95 65 6c 14 |.......... ..el.|
-00000130 ab 44 05 af 3b 45 14 e3 b7 6d fd 00 63 4d 95 7f |.D..;E...m..cM..|
-00000140 fe 6a 62 35 86 c0 4a f9 18 7c f6 aa 25 5e 7a 64 |.jb5..J..|..%^zd|
-00000150 31 66 00 ba f4 8e 92 af c7 6b d8 76 d4 f3 5f 41 |1f.......k.v.._A|
-00000160 cb 6e 56 15 97 1b 97 c1 3c 12 39 21 66 3d 2b 16 |.nV.....<.9!f=+.|
-00000170 d1 bc db 1c c0 a7 da b7 ca ad ba da cb d5 21 50 |..............!P|
-00000180 ec de 8d ab d1 6b 81 4b 89 02 f3 c4 be c1 6c 89 |.....k.K......l.|
-00000190 b1 44 84 bd 21 d1 04 7d 9d 16 4d f9 82 15 f6 ef |.D..!..}..M.....|
-000001a0 fa d6 09 47 f2 fb 02 03 01 00 01 a3 81 93 30 81 |...G..........0.|
-000001b0 90 30 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 05 |.0...U..........|
-000001c0 a0 30 1d 06 03 55 1d 25 04 16 30 14 06 08 2b 06 |.0...U.%..0...+.|
-000001d0 01 05 05 07 03 01 06 08 2b 06 01 05 05 07 03 02 |........+.......|
-000001e0 30 0c 06 03 55 1d 13 01 01 ff 04 02 30 00 30 19 |0...U.......0.0.|
-000001f0 06 03 55 1d 0e 04 12 04 10 12 50 8d 89 6f 1b d1 |..U.......P..o..|
-00000200 dc 54 4d 6e cb 69 5e 06 f4 30 1b 06 03 55 1d 23 |.TMn.i^..0...U.#|
-00000210 04 14 30 12 80 10 bf 3d b6 a9 66 f2 b8 40 cf ea |..0....=..f.. at ..|
-00000220 b4 03 78 48 1a 41 30 19 06 03 55 1d 11 04 12 30 |..xH.A0...U....0|
-00000230 10 82 0e 65 78 61 6d 70 6c 65 2e 67 6f 6c 61 6e |...example.golan|
-00000240 67 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 |g0...*.H........|
-00000250 03 81 81 00 92 7c af 91 55 12 18 96 59 31 a6 48 |.....|..U...Y1.H|
-00000260 40 d5 2d d5 ee bb 02 a0 f5 c2 1e 7c 9b b3 30 7d |@.-........|..0}|
-00000270 3c dc 76 da 4f 3d c0 fa ae 2d 33 24 6b 03 7b 1b |<.v.O=...-3$k.{.|
-00000280 67 59 11 21 b5 11 bc 77 b9 d9 e0 6e a8 2d 2e 35 |gY.!...w...n.-.5|
-00000290 fa 64 5f 22 3e 63 10 6b be ff 14 86 6d 0d f0 15 |.d_">c.k....m...|
-000002a0 31 a8 14 38 1e 3b 84 87 2c cb 98 ed 51 76 b9 b1 |1..8.;..,...Qv..|
-000002b0 4f dd db 9b 84 04 86 40 fa 51 dd ba b4 8d eb e3 |O...... at .Q......|
-000002c0 46 de 46 b9 4f 86 c7 f9 a4 c2 41 34 ac cc f6 ea |F.F.O.....A4....|
-000002d0 b0 ab 39 18 16 03 02 00 cb 0c 00 00 c7 03 00 17 |..9.............|
-000002e0 41 04 2c e8 55 b8 19 d6 cd e5 c7 96 a4 aa 61 af |A.,.U.........a.|
-000002f0 aa b2 f1 fc b3 ac 9a 90 02 d0 0a 86 61 9a c1 2e |............a...|
-00000300 3e fd 42 0b ba 07 95 77 2b 92 a2 5b 1f 44 ad 6b |>.B....w+..[.D.k|
-00000310 78 7a f4 b3 4b 04 d3 d5 2d eb 20 2d 73 02 4c db |xz..K...-. -s.L.|
-00000320 7e ac 00 80 79 b0 c6 b9 a8 50 e4 bf de 97 c6 1f |~...y....P......|
-00000330 ae 5f 89 77 6e e4 23 8c 8d 1a 49 f8 d4 92 cf 0d |._.wn.#...I.....|
-00000340 f0 08 bd 3a 88 9c 55 46 fc be 9e 7c 70 ff 6f 70 |...:..UF...|p.op|
-00000350 7b 94 b3 7b 82 c3 58 53 f7 20 13 3c 83 6e 10 55 |{..{..XS. .<.n.U|
-00000360 9d 51 cb 53 8c 93 dc 0e 02 06 40 d4 df ce 57 e4 |.Q.S...... at ...W.|
-00000370 e0 9a ba e2 b3 9b 01 98 0e 12 ca e9 96 5b 7a f2 |.............[z.|
-00000380 b1 ac 9c 44 e7 6e 2e c6 51 63 99 68 26 93 ca e2 |...D.n..Qc.h&...|
-00000390 40 31 e5 9a 80 ce 83 8f ca 80 90 c4 e8 ab 89 b2 |@1..............|
-000003a0 ca d6 30 a5 16 03 02 00 04 0e 00 00 00 |..0..........|
+00000060 02 02 59 0b 00 02 55 00 02 52 00 02 4f 30 82 02 |..Y...U..R..O0..|
+00000070 4b 30 82 01 b4 a0 03 02 01 02 02 09 00 e8 f0 9d |K0..............|
+00000080 3f e2 5b ea a6 30 0d 06 09 2a 86 48 86 f7 0d 01 |?.[..0...*.H....|
+00000090 01 0b 05 00 30 1f 31 0b 30 09 06 03 55 04 0a 13 |....0.1.0...U...|
+000000a0 02 47 6f 31 10 30 0e 06 03 55 04 03 13 07 47 6f |.Go1.0...U....Go|
+000000b0 20 52 6f 6f 74 30 1e 17 0d 31 36 30 31 30 31 30 | Root0...1601010|
+000000c0 30 30 30 30 30 5a 17 0d 32 35 30 31 30 31 30 30 |00000Z..25010100|
+000000d0 30 30 30 30 5a 30 1a 31 0b 30 09 06 03 55 04 0a |0000Z0.1.0...U..|
+000000e0 13 02 47 6f 31 0b 30 09 06 03 55 04 03 13 02 47 |..Go1.0...U....G|
+000000f0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....|
+00000100 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 db 46 |.......0.......F|
+00000110 7d 93 2e 12 27 06 48 bc 06 28 21 ab 7e c4 b6 a2 |}...'.H..(!.~...|
+00000120 5d fe 1e 52 45 88 7a 36 47 a5 08 0d 92 42 5b c2 |]..RE.z6G....B[.|
+00000130 81 c0 be 97 79 98 40 fb 4f 6d 14 fd 2b 13 8b c2 |....y. at .Om..+...|
+00000140 a5 2e 67 d8 d4 09 9e d6 22 38 b7 4a 0b 74 73 2b |..g....."8.J.ts+|
+00000150 c2 34 f1 d1 93 e5 96 d9 74 7b f3 58 9f 6c 61 3c |.4......t{.X.la<|
+00000160 c0 b0 41 d4 d9 2b 2b 24 23 77 5b 1c 3b bd 75 5d |..A..++$#w[.;.u]|
+00000170 ce 20 54 cf a1 63 87 1d 1e 24 c4 f3 1d 1a 50 8b |. T..c...$....P.|
+00000180 aa b6 14 43 ed 97 a7 75 62 f4 14 c8 52 d7 02 03 |...C...ub...R...|
+00000190 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..|
+000001a0 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%|
+000001b0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........|
+000001c0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...|
+000001d0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....|
+000001e0 10 9f 91 16 1f 43 43 3e 49 a6 de 6d b6 80 d7 9f |.....CC>I..m....|
+000001f0 60 30 1b 06 03 55 1d 23 04 14 30 12 80 10 48 13 |`0...U.#..0...H.|
+00000200 49 4d 13 7e 16 31 bb a3 01 d5 ac ab 6e 7b 30 19 |IM.~.1......n{0.|
+00000210 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp|
+00000220 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H|
+00000230 86 f7 0d 01 01 0b 05 00 03 81 81 00 9d 30 cc 40 |.............0.@|
+00000240 2b 5b 50 a0 61 cb ba e5 53 58 e1 ed 83 28 a9 58 |+[P.a...SX...(.X|
+00000250 1a a9 38 a4 95 a1 ac 31 5a 1a 84 66 3d 43 d3 2d |..8....1Z..f=C.-|
+00000260 d9 0b f2 97 df d3 20 64 38 92 24 3a 00 bc cf 9c |...... d8.$:....|
+00000270 7d b7 40 20 01 5f aa d3 16 61 09 a2 76 fd 13 c3 |}.@ ._...a..v...|
+00000280 cc e1 0c 5c ee b1 87 82 f1 6c 04 ed 73 bb b3 43 |...\.....l..s..C|
+00000290 77 8d 0c 1c f1 0f a1 d8 40 83 61 c9 4c 72 2b 9d |w....... at .a.Lr+.|
+000002a0 ae db 46 06 06 4d f4 c1 b3 3e c0 d1 bd 42 d4 db |..F..M...>...B..|
+000002b0 fe 3d 13 60 84 5c 21 d3 3b e9 fa e7 16 03 02 00 |.=.`.\!.;.......|
+000002c0 aa 0c 00 00 a6 03 00 1d 20 97 a4 91 6b cd ca 44 |........ ...k..D|
+000002d0 7e ac fd a5 b1 c0 ce 88 07 f3 a2 d9 93 2b a8 d9 |~............+..|
+000002e0 0b 65 0b 47 c0 2e 4f 3b 26 00 80 00 18 01 a1 29 |.e.G..O;&......)|
+000002f0 0b 84 c9 09 5e 8c 58 5f 62 b6 22 8b 94 6e 72 26 |....^.X_b."..nr&|
+00000300 44 27 32 b9 22 12 67 58 34 a1 ce 6f 87 19 a0 5c |D'2.".gX4..o...\|
+00000310 5d 58 dc 91 fb c7 e6 31 33 76 6d 1f 8e 4f 46 55 |]X.....13vm..OFU|
+00000320 f1 08 57 9b bb fe 8d c7 6c 0b cd 8b ad b7 51 28 |..W.....l.....Q(|
+00000330 f8 5b 75 97 fe a0 d4 a1 2e 9a d3 d5 45 62 f8 19 |.[u.........Eb..|
+00000340 f6 73 d0 f6 6d e8 43 49 a2 f5 71 66 c5 29 1a 99 |.s..m.CI..qf.)..|
+00000350 e6 c0 cc f9 a5 cd a5 b7 58 08 4d cc 17 46 91 4c |........X.M..F.L|
+00000360 29 99 b4 05 78 af e7 b0 d1 2d 38 16 03 02 00 04 |)...x....-8.....|
+00000370 0e 00 00 00 |....|
>>> Flow 3 (client to server)
-00000000 16 03 02 00 46 10 00 00 42 41 04 1e 18 37 ef 0d |....F...BA...7..|
-00000010 19 51 88 35 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd |.Q.5uq..T[....g.|
-00000020 a7 24 20 3e b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e |.$ >.V...(^.+-O.|
-00000030 f1 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 |...lK[.V.2B.X..I|
-00000040 a6 b5 68 1a 41 03 56 6b dc 5a 89 14 03 02 00 01 |..h.A.Vk.Z......|
-00000050 01 16 03 02 00 40 00 00 00 00 00 00 00 00 00 00 |..... at ..........|
-00000060 00 00 00 00 00 00 7d 87 6f 44 8f b9 92 51 5a b7 |......}.oD...QZ.|
-00000070 d2 6c 22 7f 62 a1 4e 30 61 f8 42 cd b0 05 c0 24 |.l".b.N0a.B....$|
-00000080 1f e0 49 a8 36 ce 8a 68 94 b7 37 c7 e8 d9 d8 05 |..I.6..h..7.....|
-00000090 be fb 5e 48 ba d1 |..^H..|
+00000000 16 03 02 00 25 10 00 00 21 20 2f e5 7d a3 47 cd |....%...! /.}.G.|
+00000010 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af c4 |bC.(.._.).0.....|
+00000020 cf c2 ed 90 99 5f 58 cb 3b 74 14 03 02 00 01 01 |....._X.;t......|
+00000030 16 03 02 00 40 00 00 00 00 00 00 00 00 00 00 00 |.... at ...........|
+00000040 00 00 00 00 00 f2 fb 8f ab ae 46 f2 6a 18 1b 77 |..........F.j..w|
+00000050 f3 ce 0c b6 83 9c d6 34 54 82 76 db 5c 79 5d cf |.......4T.v.\y].|
+00000060 24 f3 26 6d 9d f0 af d3 fc e0 96 69 0a 04 f7 ba |$.&m.......i....|
+00000070 78 54 af 37 a5 |xT.7.|
>>> Flow 4 (server to client)
-00000000 14 03 02 00 01 01 16 03 02 00 40 7d ed 01 b9 5a |..........@}...Z|
-00000010 34 f4 e1 63 70 84 13 86 e6 4d 90 92 da 3c 9b 35 |4..cp....M...<.5|
-00000020 77 92 7f 0a fd 69 09 75 30 5b c3 2c 6e 8e d0 59 |w....i.u0[.,n..Y|
-00000030 08 08 5c c9 eb 53 45 f3 a6 12 16 f2 95 06 27 82 |..\..SE.......'.|
-00000040 6d 9b 9e 6a bb 52 79 65 ca 94 9b |m..j.Rye...|
+00000000 14 03 02 00 01 01 16 03 02 00 40 e7 d9 0e af 0c |.......... at .....|
+00000010 06 55 85 ab b0 0a 5e d9 11 81 7a 53 c0 f6 3f 84 |.U....^...zS..?.|
+00000020 06 7d 9c 20 05 e9 0d 1d df 9b 48 11 d9 df 0c e6 |.}. ......H.....|
+00000030 6b c2 a8 8f f4 d9 e8 8e f6 1a 3e db 7c e5 97 ac |k.........>.|...|
+00000040 5d 63 08 b2 3a 54 91 62 fc 2e a5 |]c..:T.b...|
>>> Flow 5 (client to server)
00000000 17 03 02 00 30 00 00 00 00 00 00 00 00 00 00 00 |....0...........|
-00000010 00 00 00 00 00 bb 2d 28 50 1f a4 8f be 94 b9 99 |......-(P.......|
-00000020 e6 0b dd cf 50 fc 72 92 ec 1d 72 9b 27 9a 36 18 |....P.r...r.'.6.|
-00000030 3e e3 d7 cc 69 15 03 02 00 30 00 00 00 00 00 00 |>...i....0......|
-00000040 00 00 00 00 00 00 00 00 00 00 61 ca 39 3c 7e 9f |..........a.9<~.|
-00000050 1c c8 c2 2a 42 4a d0 c4 f3 80 41 04 b4 35 d0 41 |...*BJ....A..5.A|
-00000060 3d 47 1b 16 2c 71 27 04 7c 81 |=G..,q'.|.|
+00000010 00 00 00 00 00 3f ef e9 bc 10 07 75 99 67 8f 99 |.....?.....u.g..|
+00000020 bb c0 15 94 86 a2 80 cc 15 97 54 f8 4e 1a d1 9a |..........T.N...|
+00000030 33 80 aa da ec 15 03 02 00 30 00 00 00 00 00 00 |3........0......|
+00000040 00 00 00 00 00 00 00 00 00 00 6f 78 7b d2 80 62 |..........ox{..b|
+00000050 5c cf 34 d6 5a 72 d8 63 95 24 c6 ff 69 d0 6d 90 |\.4.Zr.c.$..i.m.|
+00000060 8d a2 9f 37 e8 7b b1 d4 68 04 |...7.{..h.|
diff --git a/src/crypto/tls/testdata/Client-TLSv11-RSA-RC4 b/src/crypto/tls/testdata/Client-TLSv11-RSA-RC4
index e5e315e..2e9c49e 100644
--- a/src/crypto/tls/testdata/Client-TLSv11-RSA-RC4
+++ b/src/crypto/tls/testdata/Client-TLSv11-RSA-RC4
@@ -1,79 +1,78 @@
>>> Flow 1 (client to server)
-00000000 16 03 01 00 85 01 00 00 81 03 03 00 00 00 00 00 |................|
+00000000 16 03 01 00 91 01 00 00 8d 03 03 00 00 00 00 00 |................|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
-00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 22 c0 2f |............."./|
-00000030 c0 2b c0 30 c0 2c c0 11 c0 07 c0 13 c0 09 c0 14 |.+.0.,..........|
-00000040 c0 0a 00 9c 00 9d 00 05 00 2f 00 35 c0 12 00 0a |........./.5....|
-00000050 01 00 00 36 00 05 00 05 01 00 00 00 00 00 0a 00 |...6............|
-00000060 08 00 06 00 17 00 18 00 19 00 0b 00 02 01 00 00 |................|
-00000070 0d 00 0e 00 0c 04 01 04 03 05 01 05 03 02 01 02 |................|
-00000080 03 ff 01 00 01 00 00 12 00 00 |..........|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2c cc a8 |.............,..|
+00000030 cc a9 c0 2f c0 2b c0 30 c0 2c c0 27 c0 13 c0 23 |.../.+.0.,.'...#|
+00000040 c0 09 c0 14 c0 0a 00 9c 00 9d 00 3c 00 2f 00 35 |...........<./.5|
+00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 38 00 05 |.............8..|
+00000060 00 05 01 00 00 00 00 00 0a 00 0a 00 08 00 1d 00 |................|
+00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 0e 00 |................|
+00000080 0c 04 01 04 03 05 01 05 03 02 01 02 03 ff 01 00 |................|
+00000090 01 00 00 12 00 00 |......|
>>> Flow 2 (server to client)
-00000000 16 03 02 00 51 02 00 00 4d 03 02 59 22 be 64 85 |....Q...M..Y".d.|
-00000010 71 af 54 70 5f a8 50 ff 68 52 a0 9e a7 79 4d 90 |q.Tp_.P.hR...yM.|
-00000020 cd bc c7 9c 4f 62 bc 4d a6 b9 0c 20 e1 94 8f 01 |....Ob.M... ....|
-00000030 fa 7f 9e 6f 01 72 82 ef cc 41 ed 4d 7e 76 ee e1 |...o.r...A.M~v..|
-00000040 21 34 f3 5c e0 b4 4b e2 73 37 a8 40 00 05 00 00 |!4.\..K.s7. at ....|
-00000050 05 ff 01 00 01 00 16 03 02 02 71 0b 00 02 6d 00 |..........q...m.|
-00000060 02 6a 00 02 67 30 82 02 63 30 82 01 cc a0 03 02 |.j..g0..c0......|
-00000070 01 02 02 09 00 a2 73 00 0c 81 00 cb f3 30 0d 06 |......s......0..|
-00000080 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 2b 31 17 |.*.H........0+1.|
-00000090 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 |0...U....Google |
-000000a0 54 45 53 54 49 4e 47 31 10 30 0e 06 03 55 04 03 |TESTING1.0...U..|
-000000b0 13 07 47 6f 20 52 6f 6f 74 30 1e 17 0d 31 35 30 |..Go Root0...150|
-000000c0 31 30 31 30 30 30 30 30 30 5a 17 0d 32 35 30 31 |101000000Z..2501|
-000000d0 30 31 30 30 30 30 30 30 5a 30 26 31 17 30 15 06 |01000000Z0&1.0..|
-000000e0 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 54 45 53 |.U....Google TES|
-000000f0 54 49 4e 47 31 0b 30 09 06 03 55 04 03 13 02 47 |TING1.0...U....G|
-00000100 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....|
-00000110 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 af 87 |.......0........|
-00000120 88 f6 20 1b 95 65 6c 14 ab 44 05 af 3b 45 14 e3 |.. ..el..D..;E..|
-00000130 b7 6d fd 00 63 4d 95 7f fe 6a 62 35 86 c0 4a f9 |.m..cM...jb5..J.|
-00000140 18 7c f6 aa 25 5e 7a 64 31 66 00 ba f4 8e 92 af |.|..%^zd1f......|
-00000150 c7 6b d8 76 d4 f3 5f 41 cb 6e 56 15 97 1b 97 c1 |.k.v.._A.nV.....|
-00000160 3c 12 39 21 66 3d 2b 16 d1 bc db 1c c0 a7 da b7 |<.9!f=+.........|
-00000170 ca ad ba da cb d5 21 50 ec de 8d ab d1 6b 81 4b |......!P.....k.K|
-00000180 89 02 f3 c4 be c1 6c 89 b1 44 84 bd 21 d1 04 7d |......l..D..!..}|
-00000190 9d 16 4d f9 82 15 f6 ef fa d6 09 47 f2 fb 02 03 |..M........G....|
-000001a0 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..|
-000001b0 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%|
-000001c0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........|
-000001d0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...|
-000001e0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....|
-000001f0 10 12 50 8d 89 6f 1b d1 dc 54 4d 6e cb 69 5e 06 |..P..o...TMn.i^.|
-00000200 f4 30 1b 06 03 55 1d 23 04 14 30 12 80 10 bf 3d |.0...U.#..0....=|
-00000210 b6 a9 66 f2 b8 40 cf ea b4 03 78 48 1a 41 30 19 |..f.. at ....xH.A0.|
-00000220 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp|
-00000230 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H|
-00000240 86 f7 0d 01 01 0b 05 00 03 81 81 00 92 7c af 91 |.............|..|
-00000250 55 12 18 96 59 31 a6 48 40 d5 2d d5 ee bb 02 a0 |U...Y1.H at .-.....|
-00000260 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 da 4f 3d c0 fa |...|..0}<.v.O=..|
-00000270 ae 2d 33 24 6b 03 7b 1b 67 59 11 21 b5 11 bc 77 |.-3$k.{.gY.!...w|
-00000280 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f 22 3e 63 10 6b |...n.-.5.d_">c.k|
-00000290 be ff 14 86 6d 0d f0 15 31 a8 14 38 1e 3b 84 87 |....m...1..8.;..|
-000002a0 2c cb 98 ed 51 76 b9 b1 4f dd db 9b 84 04 86 40 |,...Qv..O......@|
-000002b0 fa 51 dd ba b4 8d eb e3 46 de 46 b9 4f 86 c7 f9 |.Q......F.F.O...|
-000002c0 a4 c2 41 34 ac cc f6 ea b0 ab 39 18 16 03 02 00 |..A4......9.....|
-000002d0 04 0e 00 00 00 |.....|
+00000000 16 03 02 00 51 02 00 00 4d 03 02 36 8f 18 79 0f |....Q...M..6..y.|
+00000010 99 6b 3d 1d f4 19 aa ff 79 7c 50 15 52 db 9d c5 |.k=.....y|P.R...|
+00000020 62 40 2d 5b de 45 0c 66 b1 cb be 20 9e 00 c3 00 |b at -[.E.f... ....|
+00000030 22 2f b5 c6 79 c1 f7 72 8f 4b 94 f4 ac fe a9 53 |"/..y..r.K.....S|
+00000040 97 4e fb 00 df 34 b6 24 8f ff 89 db 00 05 00 00 |.N...4.$........|
+00000050 05 ff 01 00 01 00 16 03 02 02 59 0b 00 02 55 00 |..........Y...U.|
+00000060 02 52 00 02 4f 30 82 02 4b 30 82 01 b4 a0 03 02 |.R..O0..K0......|
+00000070 01 02 02 09 00 e8 f0 9d 3f e2 5b ea a6 30 0d 06 |........?.[..0..|
+00000080 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 1f 31 0b |.*.H........0.1.|
+00000090 30 09 06 03 55 04 0a 13 02 47 6f 31 10 30 0e 06 |0...U....Go1.0..|
+000000a0 03 55 04 03 13 07 47 6f 20 52 6f 6f 74 30 1e 17 |.U....Go Root0..|
+000000b0 0d 31 36 30 31 30 31 30 30 30 30 30 30 5a 17 0d |.160101000000Z..|
+000000c0 32 35 30 31 30 31 30 30 30 30 30 30 5a 30 1a 31 |250101000000Z0.1|
+000000d0 0b 30 09 06 03 55 04 0a 13 02 47 6f 31 0b 30 09 |.0...U....Go1.0.|
+000000e0 06 03 55 04 03 13 02 47 6f 30 81 9f 30 0d 06 09 |..U....Go0..0...|
+000000f0 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 30 |*.H............0|
+00000100 81 89 02 81 81 00 db 46 7d 93 2e 12 27 06 48 bc |.......F}...'.H.|
+00000110 06 28 21 ab 7e c4 b6 a2 5d fe 1e 52 45 88 7a 36 |.(!.~...]..RE.z6|
+00000120 47 a5 08 0d 92 42 5b c2 81 c0 be 97 79 98 40 fb |G....B[.....y. at .|
+00000130 4f 6d 14 fd 2b 13 8b c2 a5 2e 67 d8 d4 09 9e d6 |Om..+.....g.....|
+00000140 22 38 b7 4a 0b 74 73 2b c2 34 f1 d1 93 e5 96 d9 |"8.J.ts+.4......|
+00000150 74 7b f3 58 9f 6c 61 3c c0 b0 41 d4 d9 2b 2b 24 |t{.X.la<..A..++$|
+00000160 23 77 5b 1c 3b bd 75 5d ce 20 54 cf a1 63 87 1d |#w[.;.u]. T..c..|
+00000170 1e 24 c4 f3 1d 1a 50 8b aa b6 14 43 ed 97 a7 75 |.$....P....C...u|
+00000180 62 f4 14 c8 52 d7 02 03 01 00 01 a3 81 93 30 81 |b...R.........0.|
+00000190 90 30 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 05 |.0...U..........|
+000001a0 a0 30 1d 06 03 55 1d 25 04 16 30 14 06 08 2b 06 |.0...U.%..0...+.|
+000001b0 01 05 05 07 03 01 06 08 2b 06 01 05 05 07 03 02 |........+.......|
+000001c0 30 0c 06 03 55 1d 13 01 01 ff 04 02 30 00 30 19 |0...U.......0.0.|
+000001d0 06 03 55 1d 0e 04 12 04 10 9f 91 16 1f 43 43 3e |..U..........CC>|
+000001e0 49 a6 de 6d b6 80 d7 9f 60 30 1b 06 03 55 1d 23 |I..m....`0...U.#|
+000001f0 04 14 30 12 80 10 48 13 49 4d 13 7e 16 31 bb a3 |..0...H.IM.~.1..|
+00000200 01 d5 ac ab 6e 7b 30 19 06 03 55 1d 11 04 12 30 |....n{0...U....0|
+00000210 10 82 0e 65 78 61 6d 70 6c 65 2e 67 6f 6c 61 6e |...example.golan|
+00000220 67 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 |g0...*.H........|
+00000230 03 81 81 00 9d 30 cc 40 2b 5b 50 a0 61 cb ba e5 |.....0. at +[P.a...|
+00000240 53 58 e1 ed 83 28 a9 58 1a a9 38 a4 95 a1 ac 31 |SX...(.X..8....1|
+00000250 5a 1a 84 66 3d 43 d3 2d d9 0b f2 97 df d3 20 64 |Z..f=C.-...... d|
+00000260 38 92 24 3a 00 bc cf 9c 7d b7 40 20 01 5f aa d3 |8.$:....}.@ ._..|
+00000270 16 61 09 a2 76 fd 13 c3 cc e1 0c 5c ee b1 87 82 |.a..v......\....|
+00000280 f1 6c 04 ed 73 bb b3 43 77 8d 0c 1c f1 0f a1 d8 |.l..s..Cw.......|
+00000290 40 83 61 c9 4c 72 2b 9d ae db 46 06 06 4d f4 c1 |@.a.Lr+...F..M..|
+000002a0 b3 3e c0 d1 bd 42 d4 db fe 3d 13 60 84 5c 21 d3 |.>...B...=.`.\!.|
+000002b0 3b e9 fa e7 16 03 02 00 04 0e 00 00 00 |;............|
>>> Flow 3 (client to server)
-00000000 16 03 02 00 86 10 00 00 82 00 80 73 bd 73 65 92 |...........s.se.|
-00000010 86 23 41 14 79 7f d5 c1 10 ce 94 4d ad 9c c3 a9 |.#A.y......M....|
-00000020 87 b5 32 52 f8 6b 11 93 2d 9b 98 0b 8b 1d c0 f6 |..2R.k..-.......|
-00000030 53 17 6d c7 9c 2e ae c9 6f cc 99 23 38 37 1a 10 |S.m.....o..#87..|
-00000040 fe 05 0b b5 55 0a 14 e9 60 7d 70 26 98 e2 54 d9 |....U...`}p&..T.|
-00000050 65 cf 2e f4 53 5f 1d aa 3a f6 33 7b eb 4c 0e b3 |e...S_..:.3{.L..|
-00000060 ff 5a db 36 2a 47 f3 df f9 fc f5 31 78 83 aa 6b |.Z.6*G.....1x..k|
-00000070 52 b7 ba 1a 96 bc fa c1 a1 a9 bb 2b f5 38 89 00 |R..........+.8..|
-00000080 4d e5 78 13 4e a4 38 46 42 dc 16 14 03 02 00 01 |M.x.N.8FB.......|
-00000090 01 16 03 02 00 24 0b 7b 3e 32 fb 94 95 66 26 a9 |.....$.{>2...f&.|
-000000a0 4c 21 5e 18 59 cb 80 57 1b 9a 89 c8 91 c5 30 1f |L!^.Y..W......0.|
-000000b0 1a e2 80 9a 0f 03 8e 7b 4c 7d |.......{L}|
+00000000 16 03 02 00 86 10 00 00 82 00 80 b9 65 8d bf a7 |............e...|
+00000010 c8 4b 79 ce 6f cb 8b 13 1c ac b9 7d 66 5e e9 ba |.Ky.o......}f^..|
+00000020 1d 71 4e a9 e9 34 ae f6 64 65 90 3b d8 16 52 a2 |.qN..4..de.;..R.|
+00000030 6f f4 cb 8a 13 74 a2 ee b7 27 69 b4 41 c0 90 68 |o....t...'i.A..h|
+00000040 bc 02 69 e1 c6 48 4f 39 36 30 25 ca 4c 17 ce 83 |..i..HO960%.L...|
+00000050 9e 08 56 e3 05 49 93 9e 2e c4 fb e6 c8 01 f1 0f |..V..I..........|
+00000060 c5 70 0f 08 83 48 e9 48 ef 6e 50 8b 05 7e e5 84 |.p...H.H.nP..~..|
+00000070 25 fa 55 c7 ae 31 02 27 00 ef 3f 98 86 20 12 89 |%.U..1.'..?.. ..|
+00000080 91 59 28 b4 f7 d7 af d2 69 61 35 14 03 02 00 01 |.Y(.....ia5.....|
+00000090 01 16 03 02 00 24 92 fa 9a bb 9b a3 39 3f 6b 0c |.....$......9?k.|
+000000a0 70 b5 48 4a fc cf 79 86 c7 90 e8 db ca 6a ff 95 |p.HJ..y......j..|
+000000b0 11 9b 65 b2 07 61 00 a8 dc 14 |..e..a....|
>>> Flow 4 (server to client)
-00000000 14 03 02 00 01 01 16 03 02 00 24 06 7f be 82 45 |..........$....E|
-00000010 79 c6 67 fb d3 1e 3f ca d9 0f 8f 81 36 cc 80 77 |y.g...?.....6..w|
-00000020 b8 48 f3 88 29 fa f1 3a b2 d4 fd 10 e5 8c 43 |.H..)..:......C|
+00000000 14 03 02 00 01 01 16 03 02 00 24 47 d5 78 31 32 |..........$G.x12|
+00000010 db db 2b f4 2f e6 a4 fa fa 04 31 ba c0 bc 86 38 |..+./.....1....8|
+00000020 29 70 53 c6 8c 28 e5 75 90 ed 0f 4f 3e cb 06 |)pS..(.u...O>..|
>>> Flow 5 (client to server)
-00000000 17 03 02 00 1a 29 4d a2 80 38 2c 9e 96 bb 29 8b |.....)M..8,...).|
-00000010 22 69 ea 85 3e d8 a9 66 39 b8 58 12 ae 67 db 15 |"i..>..f9.X..g..|
-00000020 03 02 00 16 8c b2 f4 c1 35 5d 28 dc 5c bc 30 95 |........5](.\.0.|
-00000030 99 3e f6 c6 ff 4f 5c f4 85 1a |.>...O\...|
+00000000 17 03 02 00 1a f3 e7 6c 01 c5 70 c6 69 dd 4f 40 |.......l..p.i.O@|
+00000010 38 c1 b2 d2 28 69 2f 99 b1 bd 71 d0 c2 00 08 15 |8...(i/...q.....|
+00000020 03 02 00 16 4c 44 14 02 8e 46 f8 84 40 f1 3d 6d |....LD...F.. at .=m|
+00000030 f2 01 f6 9d 7a 0b 18 ee 9d 41 |....z....A|
diff --git a/src/crypto/tls/testdata/Client-TLSv12-AES128-GCM-SHA256 b/src/crypto/tls/testdata/Client-TLSv12-AES128-GCM-SHA256
index 9e41089..c20dcc6 100644
--- a/src/crypto/tls/testdata/Client-TLSv12-AES128-GCM-SHA256
+++ b/src/crypto/tls/testdata/Client-TLSv12-AES128-GCM-SHA256
@@ -1,81 +1,80 @@
>>> Flow 1 (client to server)
-00000000 16 03 01 00 85 01 00 00 81 03 03 00 00 00 00 00 |................|
+00000000 16 03 01 00 91 01 00 00 8d 03 03 00 00 00 00 00 |................|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
-00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 22 c0 2f |............."./|
-00000030 c0 2b c0 30 c0 2c c0 11 c0 07 c0 13 c0 09 c0 14 |.+.0.,..........|
-00000040 c0 0a 00 9c 00 9d 00 05 00 2f 00 35 c0 12 00 0a |........./.5....|
-00000050 01 00 00 36 00 05 00 05 01 00 00 00 00 00 0a 00 |...6............|
-00000060 08 00 06 00 17 00 18 00 19 00 0b 00 02 01 00 00 |................|
-00000070 0d 00 0e 00 0c 04 01 04 03 05 01 05 03 02 01 02 |................|
-00000080 03 ff 01 00 01 00 00 12 00 00 |..........|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2c cc a8 |.............,..|
+00000030 cc a9 c0 2f c0 2b c0 30 c0 2c c0 27 c0 13 c0 23 |.../.+.0.,.'...#|
+00000040 c0 09 c0 14 c0 0a 00 9c 00 9d 00 3c 00 2f 00 35 |...........<./.5|
+00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 38 00 05 |.............8..|
+00000060 00 05 01 00 00 00 00 00 0a 00 0a 00 08 00 1d 00 |................|
+00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 0e 00 |................|
+00000080 0c 04 01 04 03 05 01 05 03 02 01 02 03 ff 01 00 |................|
+00000090 01 00 00 12 00 00 |......|
>>> Flow 2 (server to client)
-00000000 16 03 03 00 51 02 00 00 4d 03 03 e7 18 39 61 14 |....Q...M....9a.|
-00000010 47 69 40 34 ae 4e 58 4b 32 2d ed 2a 52 09 c5 2f |Gi at 4.NXK2-.*R../|
-00000020 07 f6 44 0b 2b 9c 43 4b bb 79 b6 20 48 f4 ff f1 |..D.+.CK.y. H...|
-00000030 c6 72 77 e5 3a e0 8d 08 b9 cd 8b bf e3 9b ec 41 |.rw.:..........A|
-00000040 1d d9 86 1b 35 7b 8c 04 e0 83 0d d3 00 9c 00 00 |....5{..........|
-00000050 05 ff 01 00 01 00 16 03 03 02 71 0b 00 02 6d 00 |..........q...m.|
-00000060 02 6a 00 02 67 30 82 02 63 30 82 01 cc a0 03 02 |.j..g0..c0......|
-00000070 01 02 02 09 00 a2 73 00 0c 81 00 cb f3 30 0d 06 |......s......0..|
-00000080 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 2b 31 17 |.*.H........0+1.|
-00000090 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 |0...U....Google |
-000000a0 54 45 53 54 49 4e 47 31 10 30 0e 06 03 55 04 03 |TESTING1.0...U..|
-000000b0 13 07 47 6f 20 52 6f 6f 74 30 1e 17 0d 31 35 30 |..Go Root0...150|
-000000c0 31 30 31 30 30 30 30 30 30 5a 17 0d 32 35 30 31 |101000000Z..2501|
-000000d0 30 31 30 30 30 30 30 30 5a 30 26 31 17 30 15 06 |01000000Z0&1.0..|
-000000e0 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 54 45 53 |.U....Google TES|
-000000f0 54 49 4e 47 31 0b 30 09 06 03 55 04 03 13 02 47 |TING1.0...U....G|
-00000100 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....|
-00000110 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 af 87 |.......0........|
-00000120 88 f6 20 1b 95 65 6c 14 ab 44 05 af 3b 45 14 e3 |.. ..el..D..;E..|
-00000130 b7 6d fd 00 63 4d 95 7f fe 6a 62 35 86 c0 4a f9 |.m..cM...jb5..J.|
-00000140 18 7c f6 aa 25 5e 7a 64 31 66 00 ba f4 8e 92 af |.|..%^zd1f......|
-00000150 c7 6b d8 76 d4 f3 5f 41 cb 6e 56 15 97 1b 97 c1 |.k.v.._A.nV.....|
-00000160 3c 12 39 21 66 3d 2b 16 d1 bc db 1c c0 a7 da b7 |<.9!f=+.........|
-00000170 ca ad ba da cb d5 21 50 ec de 8d ab d1 6b 81 4b |......!P.....k.K|
-00000180 89 02 f3 c4 be c1 6c 89 b1 44 84 bd 21 d1 04 7d |......l..D..!..}|
-00000190 9d 16 4d f9 82 15 f6 ef fa d6 09 47 f2 fb 02 03 |..M........G....|
-000001a0 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..|
-000001b0 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%|
-000001c0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........|
-000001d0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...|
-000001e0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....|
-000001f0 10 12 50 8d 89 6f 1b d1 dc 54 4d 6e cb 69 5e 06 |..P..o...TMn.i^.|
-00000200 f4 30 1b 06 03 55 1d 23 04 14 30 12 80 10 bf 3d |.0...U.#..0....=|
-00000210 b6 a9 66 f2 b8 40 cf ea b4 03 78 48 1a 41 30 19 |..f.. at ....xH.A0.|
-00000220 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp|
-00000230 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H|
-00000240 86 f7 0d 01 01 0b 05 00 03 81 81 00 92 7c af 91 |.............|..|
-00000250 55 12 18 96 59 31 a6 48 40 d5 2d d5 ee bb 02 a0 |U...Y1.H at .-.....|
-00000260 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 da 4f 3d c0 fa |...|..0}<.v.O=..|
-00000270 ae 2d 33 24 6b 03 7b 1b 67 59 11 21 b5 11 bc 77 |.-3$k.{.gY.!...w|
-00000280 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f 22 3e 63 10 6b |...n.-.5.d_">c.k|
-00000290 be ff 14 86 6d 0d f0 15 31 a8 14 38 1e 3b 84 87 |....m...1..8.;..|
-000002a0 2c cb 98 ed 51 76 b9 b1 4f dd db 9b 84 04 86 40 |,...Qv..O......@|
-000002b0 fa 51 dd ba b4 8d eb e3 46 de 46 b9 4f 86 c7 f9 |.Q......F.F.O...|
-000002c0 a4 c2 41 34 ac cc f6 ea b0 ab 39 18 16 03 03 00 |..A4......9.....|
-000002d0 04 0e 00 00 00 |.....|
+00000000 16 03 03 00 51 02 00 00 4d 03 03 65 9c b1 7a 5c |....Q...M..e..z\|
+00000010 84 e5 a5 12 ba 54 1f 4c ec 95 0b 8f ea 5c cc 3b |.....T.L.....\.;|
+00000020 de b8 18 23 8e c4 95 59 d7 7f 8f 20 36 fe ec 27 |...#...Y... 6..'|
+00000030 10 85 43 fb 9c 68 3f 69 d0 08 a6 57 10 a6 29 a4 |..C..h?i...W..).|
+00000040 f6 0c 2e 05 6e 0d e5 44 61 e1 2e 07 00 9c 00 00 |....n..Da.......|
+00000050 05 ff 01 00 01 00 16 03 03 02 59 0b 00 02 55 00 |..........Y...U.|
+00000060 02 52 00 02 4f 30 82 02 4b 30 82 01 b4 a0 03 02 |.R..O0..K0......|
+00000070 01 02 02 09 00 e8 f0 9d 3f e2 5b ea a6 30 0d 06 |........?.[..0..|
+00000080 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 1f 31 0b |.*.H........0.1.|
+00000090 30 09 06 03 55 04 0a 13 02 47 6f 31 10 30 0e 06 |0...U....Go1.0..|
+000000a0 03 55 04 03 13 07 47 6f 20 52 6f 6f 74 30 1e 17 |.U....Go Root0..|
+000000b0 0d 31 36 30 31 30 31 30 30 30 30 30 30 5a 17 0d |.160101000000Z..|
+000000c0 32 35 30 31 30 31 30 30 30 30 30 30 5a 30 1a 31 |250101000000Z0.1|
+000000d0 0b 30 09 06 03 55 04 0a 13 02 47 6f 31 0b 30 09 |.0...U....Go1.0.|
+000000e0 06 03 55 04 03 13 02 47 6f 30 81 9f 30 0d 06 09 |..U....Go0..0...|
+000000f0 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 30 |*.H............0|
+00000100 81 89 02 81 81 00 db 46 7d 93 2e 12 27 06 48 bc |.......F}...'.H.|
+00000110 06 28 21 ab 7e c4 b6 a2 5d fe 1e 52 45 88 7a 36 |.(!.~...]..RE.z6|
+00000120 47 a5 08 0d 92 42 5b c2 81 c0 be 97 79 98 40 fb |G....B[.....y. at .|
+00000130 4f 6d 14 fd 2b 13 8b c2 a5 2e 67 d8 d4 09 9e d6 |Om..+.....g.....|
+00000140 22 38 b7 4a 0b 74 73 2b c2 34 f1 d1 93 e5 96 d9 |"8.J.ts+.4......|
+00000150 74 7b f3 58 9f 6c 61 3c c0 b0 41 d4 d9 2b 2b 24 |t{.X.la<..A..++$|
+00000160 23 77 5b 1c 3b bd 75 5d ce 20 54 cf a1 63 87 1d |#w[.;.u]. T..c..|
+00000170 1e 24 c4 f3 1d 1a 50 8b aa b6 14 43 ed 97 a7 75 |.$....P....C...u|
+00000180 62 f4 14 c8 52 d7 02 03 01 00 01 a3 81 93 30 81 |b...R.........0.|
+00000190 90 30 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 05 |.0...U..........|
+000001a0 a0 30 1d 06 03 55 1d 25 04 16 30 14 06 08 2b 06 |.0...U.%..0...+.|
+000001b0 01 05 05 07 03 01 06 08 2b 06 01 05 05 07 03 02 |........+.......|
+000001c0 30 0c 06 03 55 1d 13 01 01 ff 04 02 30 00 30 19 |0...U.......0.0.|
+000001d0 06 03 55 1d 0e 04 12 04 10 9f 91 16 1f 43 43 3e |..U..........CC>|
+000001e0 49 a6 de 6d b6 80 d7 9f 60 30 1b 06 03 55 1d 23 |I..m....`0...U.#|
+000001f0 04 14 30 12 80 10 48 13 49 4d 13 7e 16 31 bb a3 |..0...H.IM.~.1..|
+00000200 01 d5 ac ab 6e 7b 30 19 06 03 55 1d 11 04 12 30 |....n{0...U....0|
+00000210 10 82 0e 65 78 61 6d 70 6c 65 2e 67 6f 6c 61 6e |...example.golan|
+00000220 67 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 |g0...*.H........|
+00000230 03 81 81 00 9d 30 cc 40 2b 5b 50 a0 61 cb ba e5 |.....0. at +[P.a...|
+00000240 53 58 e1 ed 83 28 a9 58 1a a9 38 a4 95 a1 ac 31 |SX...(.X..8....1|
+00000250 5a 1a 84 66 3d 43 d3 2d d9 0b f2 97 df d3 20 64 |Z..f=C.-...... d|
+00000260 38 92 24 3a 00 bc cf 9c 7d b7 40 20 01 5f aa d3 |8.$:....}.@ ._..|
+00000270 16 61 09 a2 76 fd 13 c3 cc e1 0c 5c ee b1 87 82 |.a..v......\....|
+00000280 f1 6c 04 ed 73 bb b3 43 77 8d 0c 1c f1 0f a1 d8 |.l..s..Cw.......|
+00000290 40 83 61 c9 4c 72 2b 9d ae db 46 06 06 4d f4 c1 |@.a.Lr+...F..M..|
+000002a0 b3 3e c0 d1 bd 42 d4 db fe 3d 13 60 84 5c 21 d3 |.>...B...=.`.\!.|
+000002b0 3b e9 fa e7 16 03 03 00 04 0e 00 00 00 |;............|
>>> Flow 3 (client to server)
-00000000 16 03 03 00 86 10 00 00 82 00 80 73 bd 73 65 92 |...........s.se.|
-00000010 86 23 41 14 79 7f d5 c1 10 ce 94 4d ad 9c c3 a9 |.#A.y......M....|
-00000020 87 b5 32 52 f8 6b 11 93 2d 9b 98 0b 8b 1d c0 f6 |..2R.k..-.......|
-00000030 53 17 6d c7 9c 2e ae c9 6f cc 99 23 38 37 1a 10 |S.m.....o..#87..|
-00000040 fe 05 0b b5 55 0a 14 e9 60 7d 70 26 98 e2 54 d9 |....U...`}p&..T.|
-00000050 65 cf 2e f4 53 5f 1d aa 3a f6 33 7b eb 4c 0e b3 |e...S_..:.3{.L..|
-00000060 ff 5a db 36 2a 47 f3 df f9 fc f5 31 78 83 aa 6b |.Z.6*G.....1x..k|
-00000070 52 b7 ba 1a 96 bc fa c1 a1 a9 bb 2b f5 38 89 00 |R..........+.8..|
-00000080 4d e5 78 13 4e a4 38 46 42 dc 16 14 03 03 00 01 |M.x.N.8FB.......|
-00000090 01 16 03 03 00 28 00 00 00 00 00 00 00 00 8a 9b |.....(..........|
-000000a0 29 1d 64 2e ee 0d 39 d9 c5 86 b9 02 9d c3 bd 74 |).d...9........t|
-000000b0 39 9d 53 9f 1a ee 84 64 82 82 41 81 f8 2f |9.S....d..A../|
+00000000 16 03 03 00 86 10 00 00 82 00 80 b9 65 8d bf a7 |............e...|
+00000010 c8 4b 79 ce 6f cb 8b 13 1c ac b9 7d 66 5e e9 ba |.Ky.o......}f^..|
+00000020 1d 71 4e a9 e9 34 ae f6 64 65 90 3b d8 16 52 a2 |.qN..4..de.;..R.|
+00000030 6f f4 cb 8a 13 74 a2 ee b7 27 69 b4 41 c0 90 68 |o....t...'i.A..h|
+00000040 bc 02 69 e1 c6 48 4f 39 36 30 25 ca 4c 17 ce 83 |..i..HO960%.L...|
+00000050 9e 08 56 e3 05 49 93 9e 2e c4 fb e6 c8 01 f1 0f |..V..I..........|
+00000060 c5 70 0f 08 83 48 e9 48 ef 6e 50 8b 05 7e e5 84 |.p...H.H.nP..~..|
+00000070 25 fa 55 c7 ae 31 02 27 00 ef 3f 98 86 20 12 89 |%.U..1.'..?.. ..|
+00000080 91 59 28 b4 f7 d7 af d2 69 61 35 14 03 03 00 01 |.Y(.....ia5.....|
+00000090 01 16 03 03 00 28 00 00 00 00 00 00 00 00 97 f1 |.....(..........|
+000000a0 fe 34 f7 de 76 9b 56 27 e6 9f 36 48 30 a6 de 78 |.4..v.V'..6H0..x|
+000000b0 10 6a ef bf 92 8a 6e 99 21 2f 1b 7b 48 80 |.j....n.!/.{H.|
>>> Flow 4 (server to client)
-00000000 14 03 03 00 01 01 16 03 03 00 28 60 71 25 f9 f9 |..........(`q%..|
-00000010 89 cd f8 6f 00 a6 0e 92 f8 3e 84 08 79 6f 91 cd |...o.....>..yo..|
-00000020 e2 62 d5 da 96 79 c3 0d f4 34 26 bd 47 9c 30 aa |.b...y...4&.G.0.|
-00000030 1b 5f 24 |._$|
+00000000 14 03 03 00 01 01 16 03 03 00 28 23 9d a2 ae a1 |..........(#....|
+00000010 7d dd 92 1f 42 18 68 f6 fb 31 56 7b e4 58 a4 e9 |}...B.h..1V{.X..|
+00000020 c2 1c e7 67 1b 40 b1 b9 63 9d 05 fb c7 44 9e f6 |...g. at ..c....D..|
+00000030 7a 14 bb |z..|
>>> Flow 5 (client to server)
-00000000 17 03 03 00 1e 00 00 00 00 00 00 00 01 44 05 c9 |.............D..|
-00000010 2b 82 55 26 ab 4b 65 b1 94 e5 8a 81 bf 44 a5 cb |+.U&.Ke......D..|
-00000020 22 f0 0a 15 03 03 00 1a 00 00 00 00 00 00 00 02 |"...............|
-00000030 59 8d 6f 5d 30 47 4d 3e ed aa 87 5f ca 39 44 a4 |Y.o]0GM>..._.9D.|
-00000040 9b fc |..|
+00000000 17 03 03 00 1e 00 00 00 00 00 00 00 01 d7 31 70 |..............1p|
+00000010 c8 11 3f bd 83 fc 6e f8 3b e0 ee 45 c5 1a c8 41 |..?...n.;..E...A|
+00000020 80 22 d4 15 03 03 00 1a 00 00 00 00 00 00 00 02 |."..............|
+00000030 7a fe 3a 11 7c c0 26 30 55 24 85 0b 43 cb 7c ac |z.:.|.&0U$..C.|.|
+00000040 ef 2c |.,|
diff --git a/src/crypto/tls/testdata/Client-TLSv12-AES128-SHA256 b/src/crypto/tls/testdata/Client-TLSv12-AES128-SHA256
new file mode 100644
index 0000000..774481e
--- /dev/null
+++ b/src/crypto/tls/testdata/Client-TLSv12-AES128-SHA256
@@ -0,0 +1,89 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 91 01 00 00 8d 03 03 00 00 00 00 00 |................|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2c cc a8 |.............,..|
+00000030 cc a9 c0 2f c0 2b c0 30 c0 2c c0 27 c0 13 c0 23 |.../.+.0.,.'...#|
+00000040 c0 09 c0 14 c0 0a 00 9c 00 9d 00 3c 00 2f 00 35 |...........<./.5|
+00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 38 00 05 |.............8..|
+00000060 00 05 01 00 00 00 00 00 0a 00 0a 00 08 00 1d 00 |................|
+00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 0e 00 |................|
+00000080 0c 04 01 04 03 05 01 05 03 02 01 02 03 ff 01 00 |................|
+00000090 01 00 00 12 00 00 |......|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 51 02 00 00 4d 03 03 26 31 ba 4a 56 |....Q...M..&1.JV|
+00000010 16 83 15 47 b9 c4 7e 10 ca 92 31 4d 77 af cc cd |...G..~...1Mw...|
+00000020 70 f4 cc 82 6e b9 ac 1b 0d 17 25 20 e9 08 ec 95 |p...n.....% ....|
+00000030 ea 84 a4 bd 8f 9d 8e d3 58 a7 5e 72 42 e4 19 8f |........X.^rB...|
+00000040 46 c3 d9 be 16 3c d4 53 5a 02 8f a1 00 3c 00 00 |F....<.SZ....<..|
+00000050 05 ff 01 00 01 00 16 03 03 02 59 0b 00 02 55 00 |..........Y...U.|
+00000060 02 52 00 02 4f 30 82 02 4b 30 82 01 b4 a0 03 02 |.R..O0..K0......|
+00000070 01 02 02 09 00 e8 f0 9d 3f e2 5b ea a6 30 0d 06 |........?.[..0..|
+00000080 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 1f 31 0b |.*.H........0.1.|
+00000090 30 09 06 03 55 04 0a 13 02 47 6f 31 10 30 0e 06 |0...U....Go1.0..|
+000000a0 03 55 04 03 13 07 47 6f 20 52 6f 6f 74 30 1e 17 |.U....Go Root0..|
+000000b0 0d 31 36 30 31 30 31 30 30 30 30 30 30 5a 17 0d |.160101000000Z..|
+000000c0 32 35 30 31 30 31 30 30 30 30 30 30 5a 30 1a 31 |250101000000Z0.1|
+000000d0 0b 30 09 06 03 55 04 0a 13 02 47 6f 31 0b 30 09 |.0...U....Go1.0.|
+000000e0 06 03 55 04 03 13 02 47 6f 30 81 9f 30 0d 06 09 |..U....Go0..0...|
+000000f0 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 30 |*.H............0|
+00000100 81 89 02 81 81 00 db 46 7d 93 2e 12 27 06 48 bc |.......F}...'.H.|
+00000110 06 28 21 ab 7e c4 b6 a2 5d fe 1e 52 45 88 7a 36 |.(!.~...]..RE.z6|
+00000120 47 a5 08 0d 92 42 5b c2 81 c0 be 97 79 98 40 fb |G....B[.....y. at .|
+00000130 4f 6d 14 fd 2b 13 8b c2 a5 2e 67 d8 d4 09 9e d6 |Om..+.....g.....|
+00000140 22 38 b7 4a 0b 74 73 2b c2 34 f1 d1 93 e5 96 d9 |"8.J.ts+.4......|
+00000150 74 7b f3 58 9f 6c 61 3c c0 b0 41 d4 d9 2b 2b 24 |t{.X.la<..A..++$|
+00000160 23 77 5b 1c 3b bd 75 5d ce 20 54 cf a1 63 87 1d |#w[.;.u]. T..c..|
+00000170 1e 24 c4 f3 1d 1a 50 8b aa b6 14 43 ed 97 a7 75 |.$....P....C...u|
+00000180 62 f4 14 c8 52 d7 02 03 01 00 01 a3 81 93 30 81 |b...R.........0.|
+00000190 90 30 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 05 |.0...U..........|
+000001a0 a0 30 1d 06 03 55 1d 25 04 16 30 14 06 08 2b 06 |.0...U.%..0...+.|
+000001b0 01 05 05 07 03 01 06 08 2b 06 01 05 05 07 03 02 |........+.......|
+000001c0 30 0c 06 03 55 1d 13 01 01 ff 04 02 30 00 30 19 |0...U.......0.0.|
+000001d0 06 03 55 1d 0e 04 12 04 10 9f 91 16 1f 43 43 3e |..U..........CC>|
+000001e0 49 a6 de 6d b6 80 d7 9f 60 30 1b 06 03 55 1d 23 |I..m....`0...U.#|
+000001f0 04 14 30 12 80 10 48 13 49 4d 13 7e 16 31 bb a3 |..0...H.IM.~.1..|
+00000200 01 d5 ac ab 6e 7b 30 19 06 03 55 1d 11 04 12 30 |....n{0...U....0|
+00000210 10 82 0e 65 78 61 6d 70 6c 65 2e 67 6f 6c 61 6e |...example.golan|
+00000220 67 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 |g0...*.H........|
+00000230 03 81 81 00 9d 30 cc 40 2b 5b 50 a0 61 cb ba e5 |.....0. at +[P.a...|
+00000240 53 58 e1 ed 83 28 a9 58 1a a9 38 a4 95 a1 ac 31 |SX...(.X..8....1|
+00000250 5a 1a 84 66 3d 43 d3 2d d9 0b f2 97 df d3 20 64 |Z..f=C.-...... d|
+00000260 38 92 24 3a 00 bc cf 9c 7d b7 40 20 01 5f aa d3 |8.$:....}.@ ._..|
+00000270 16 61 09 a2 76 fd 13 c3 cc e1 0c 5c ee b1 87 82 |.a..v......\....|
+00000280 f1 6c 04 ed 73 bb b3 43 77 8d 0c 1c f1 0f a1 d8 |.l..s..Cw.......|
+00000290 40 83 61 c9 4c 72 2b 9d ae db 46 06 06 4d f4 c1 |@.a.Lr+...F..M..|
+000002a0 b3 3e c0 d1 bd 42 d4 db fe 3d 13 60 84 5c 21 d3 |.>...B...=.`.\!.|
+000002b0 3b e9 fa e7 16 03 03 00 04 0e 00 00 00 |;............|
+>>> Flow 3 (client to server)
+00000000 16 03 03 00 86 10 00 00 82 00 80 b9 65 8d bf a7 |............e...|
+00000010 c8 4b 79 ce 6f cb 8b 13 1c ac b9 7d 66 5e e9 ba |.Ky.o......}f^..|
+00000020 1d 71 4e a9 e9 34 ae f6 64 65 90 3b d8 16 52 a2 |.qN..4..de.;..R.|
+00000030 6f f4 cb 8a 13 74 a2 ee b7 27 69 b4 41 c0 90 68 |o....t...'i.A..h|
+00000040 bc 02 69 e1 c6 48 4f 39 36 30 25 ca 4c 17 ce 83 |..i..HO960%.L...|
+00000050 9e 08 56 e3 05 49 93 9e 2e c4 fb e6 c8 01 f1 0f |..V..I..........|
+00000060 c5 70 0f 08 83 48 e9 48 ef 6e 50 8b 05 7e e5 84 |.p...H.H.nP..~..|
+00000070 25 fa 55 c7 ae 31 02 27 00 ef 3f 98 86 20 12 89 |%.U..1.'..?.. ..|
+00000080 91 59 28 b4 f7 d7 af d2 69 61 35 14 03 03 00 01 |.Y(.....ia5.....|
+00000090 01 16 03 03 00 50 00 00 00 00 00 00 00 00 00 00 |.....P..........|
+000000a0 00 00 00 00 00 00 46 91 40 e2 65 40 fe 42 c3 34 |......F. at .e@.B.4|
+000000b0 98 65 89 d0 96 7e 7b 67 8e c4 d5 e6 37 f5 96 04 |.e...~{g....7...|
+000000c0 b7 c8 63 83 76 5c ca 9d 89 18 d4 97 8b 3f f6 75 |..c.v\.......?.u|
+000000d0 1d 51 0b b9 90 1c 85 8f 83 20 9e 9a 21 d9 db 14 |.Q....... ..!...|
+000000e0 1e 02 d4 ab aa c4 |......|
+>>> Flow 4 (server to client)
+00000000 14 03 03 00 01 01 16 03 03 00 50 6d 34 72 de 79 |..........Pm4r.y|
+00000010 ad 96 d0 92 5f d7 01 de 90 f4 5d 0f de 02 ae 19 |...._.....].....|
+00000020 61 a3 ee 29 ab 18 f1 09 2e 5b bc e0 73 9a 68 19 |a..).....[..s.h.|
+00000030 17 dd c8 d9 63 b4 28 c8 da 1a 81 40 ca d3 5a 99 |....c.(.... at ..Z.|
+00000040 17 67 fe e9 dd 1a 52 c4 6e 70 0a 0e cf e8 c0 f8 |.g....R.np......|
+00000050 6c 1f ee d2 70 97 dc ee b8 95 35 |l...p.....5|
+>>> Flow 5 (client to server)
+00000000 17 03 03 00 40 00 00 00 00 00 00 00 00 00 00 00 |.... at ...........|
+00000010 00 00 00 00 00 ee 03 cc 04 97 17 f0 04 85 02 b7 |................|
+00000020 5c 24 ca 9f c2 25 e0 76 f4 72 e5 71 2b ac f4 a5 |\$...%.v.r.q+...|
+00000030 c4 62 08 9a da b7 ab 30 2f 34 b0 70 20 a3 b9 b3 |.b.....0/4.p ...|
+00000040 df 90 9b 01 0b 15 03 03 00 40 00 00 00 00 00 00 |......... at ......|
+00000050 00 00 00 00 00 00 00 00 00 00 3b ca fc 0e 08 f2 |..........;.....|
+00000060 c8 b7 22 61 43 24 b3 54 1b ca 58 c6 bd 27 f3 3d |.."aC$.T..X..'.=|
+00000070 ac a0 d8 fe 0e b5 15 7c 1f 98 32 f0 6b 28 bc 61 |.......|..2.k(.a|
+00000080 6c c7 ba 66 54 19 92 a9 6f 43 |l..fT...oC|
diff --git a/src/crypto/tls/testdata/Client-TLSv12-AES256-GCM-SHA384 b/src/crypto/tls/testdata/Client-TLSv12-AES256-GCM-SHA384
index 33fb708..6d26746 100644
--- a/src/crypto/tls/testdata/Client-TLSv12-AES256-GCM-SHA384
+++ b/src/crypto/tls/testdata/Client-TLSv12-AES256-GCM-SHA384
@@ -1,81 +1,80 @@
>>> Flow 1 (client to server)
-00000000 16 03 01 00 85 01 00 00 81 03 03 00 00 00 00 00 |................|
+00000000 16 03 01 00 91 01 00 00 8d 03 03 00 00 00 00 00 |................|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
-00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 22 c0 2f |............."./|
-00000030 c0 2b c0 30 c0 2c c0 11 c0 07 c0 13 c0 09 c0 14 |.+.0.,..........|
-00000040 c0 0a 00 9c 00 9d 00 05 00 2f 00 35 c0 12 00 0a |........./.5....|
-00000050 01 00 00 36 00 05 00 05 01 00 00 00 00 00 0a 00 |...6............|
-00000060 08 00 06 00 17 00 18 00 19 00 0b 00 02 01 00 00 |................|
-00000070 0d 00 0e 00 0c 04 01 04 03 05 01 05 03 02 01 02 |................|
-00000080 03 ff 01 00 01 00 00 12 00 00 |..........|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2c cc a8 |.............,..|
+00000030 cc a9 c0 2f c0 2b c0 30 c0 2c c0 27 c0 13 c0 23 |.../.+.0.,.'...#|
+00000040 c0 09 c0 14 c0 0a 00 9c 00 9d 00 3c 00 2f 00 35 |...........<./.5|
+00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 38 00 05 |.............8..|
+00000060 00 05 01 00 00 00 00 00 0a 00 0a 00 08 00 1d 00 |................|
+00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 0e 00 |................|
+00000080 0c 04 01 04 03 05 01 05 03 02 01 02 03 ff 01 00 |................|
+00000090 01 00 00 12 00 00 |......|
>>> Flow 2 (server to client)
-00000000 16 03 03 00 51 02 00 00 4d 03 03 08 e2 40 1b 1a |....Q...M.... at ..|
-00000010 54 dc 66 60 e1 e0 8d 94 c6 dd 2c eb 95 e0 e9 2f |T.f`......,..../|
-00000020 fb 49 17 d8 34 d7 a2 7a 1b e1 60 20 26 a3 4b 7c |.I..4..z..` &.K||
-00000030 40 cc df 4b 9c 72 a9 e6 61 89 1e 20 b2 e5 e3 1e |@..K.r..a.. ....|
-00000040 4e a3 b6 32 ce fc 94 0d ab 13 74 f8 00 9d 00 00 |N..2......t.....|
-00000050 05 ff 01 00 01 00 16 03 03 02 71 0b 00 02 6d 00 |..........q...m.|
-00000060 02 6a 00 02 67 30 82 02 63 30 82 01 cc a0 03 02 |.j..g0..c0......|
-00000070 01 02 02 09 00 a2 73 00 0c 81 00 cb f3 30 0d 06 |......s......0..|
-00000080 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 2b 31 17 |.*.H........0+1.|
-00000090 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 |0...U....Google |
-000000a0 54 45 53 54 49 4e 47 31 10 30 0e 06 03 55 04 03 |TESTING1.0...U..|
-000000b0 13 07 47 6f 20 52 6f 6f 74 30 1e 17 0d 31 35 30 |..Go Root0...150|
-000000c0 31 30 31 30 30 30 30 30 30 5a 17 0d 32 35 30 31 |101000000Z..2501|
-000000d0 30 31 30 30 30 30 30 30 5a 30 26 31 17 30 15 06 |01000000Z0&1.0..|
-000000e0 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 54 45 53 |.U....Google TES|
-000000f0 54 49 4e 47 31 0b 30 09 06 03 55 04 03 13 02 47 |TING1.0...U....G|
-00000100 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....|
-00000110 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 af 87 |.......0........|
-00000120 88 f6 20 1b 95 65 6c 14 ab 44 05 af 3b 45 14 e3 |.. ..el..D..;E..|
-00000130 b7 6d fd 00 63 4d 95 7f fe 6a 62 35 86 c0 4a f9 |.m..cM...jb5..J.|
-00000140 18 7c f6 aa 25 5e 7a 64 31 66 00 ba f4 8e 92 af |.|..%^zd1f......|
-00000150 c7 6b d8 76 d4 f3 5f 41 cb 6e 56 15 97 1b 97 c1 |.k.v.._A.nV.....|
-00000160 3c 12 39 21 66 3d 2b 16 d1 bc db 1c c0 a7 da b7 |<.9!f=+.........|
-00000170 ca ad ba da cb d5 21 50 ec de 8d ab d1 6b 81 4b |......!P.....k.K|
-00000180 89 02 f3 c4 be c1 6c 89 b1 44 84 bd 21 d1 04 7d |......l..D..!..}|
-00000190 9d 16 4d f9 82 15 f6 ef fa d6 09 47 f2 fb 02 03 |..M........G....|
-000001a0 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..|
-000001b0 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%|
-000001c0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........|
-000001d0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...|
-000001e0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....|
-000001f0 10 12 50 8d 89 6f 1b d1 dc 54 4d 6e cb 69 5e 06 |..P..o...TMn.i^.|
-00000200 f4 30 1b 06 03 55 1d 23 04 14 30 12 80 10 bf 3d |.0...U.#..0....=|
-00000210 b6 a9 66 f2 b8 40 cf ea b4 03 78 48 1a 41 30 19 |..f.. at ....xH.A0.|
-00000220 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp|
-00000230 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H|
-00000240 86 f7 0d 01 01 0b 05 00 03 81 81 00 92 7c af 91 |.............|..|
-00000250 55 12 18 96 59 31 a6 48 40 d5 2d d5 ee bb 02 a0 |U...Y1.H at .-.....|
-00000260 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 da 4f 3d c0 fa |...|..0}<.v.O=..|
-00000270 ae 2d 33 24 6b 03 7b 1b 67 59 11 21 b5 11 bc 77 |.-3$k.{.gY.!...w|
-00000280 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f 22 3e 63 10 6b |...n.-.5.d_">c.k|
-00000290 be ff 14 86 6d 0d f0 15 31 a8 14 38 1e 3b 84 87 |....m...1..8.;..|
-000002a0 2c cb 98 ed 51 76 b9 b1 4f dd db 9b 84 04 86 40 |,...Qv..O......@|
-000002b0 fa 51 dd ba b4 8d eb e3 46 de 46 b9 4f 86 c7 f9 |.Q......F.F.O...|
-000002c0 a4 c2 41 34 ac cc f6 ea b0 ab 39 18 16 03 03 00 |..A4......9.....|
-000002d0 04 0e 00 00 00 |.....|
+00000000 16 03 03 00 51 02 00 00 4d 03 03 98 b0 4a 9a c8 |....Q...M....J..|
+00000010 8f f9 1f f9 70 03 d9 1a ee 7c 29 30 6a 71 7c 6c |....p....|)0jq|l|
+00000020 ea 2c de 84 f9 ee 4d 2c d7 58 12 20 a4 e2 1b f3 |.,....M,.X. ....|
+00000030 42 b8 9a 0b 71 8c 27 57 61 98 c5 c5 1b 04 01 5b |B...q.'Wa......[|
+00000040 a0 bc 88 64 d9 ce 5a a1 b2 7b 6c 4e 00 9d 00 00 |...d..Z..{lN....|
+00000050 05 ff 01 00 01 00 16 03 03 02 59 0b 00 02 55 00 |..........Y...U.|
+00000060 02 52 00 02 4f 30 82 02 4b 30 82 01 b4 a0 03 02 |.R..O0..K0......|
+00000070 01 02 02 09 00 e8 f0 9d 3f e2 5b ea a6 30 0d 06 |........?.[..0..|
+00000080 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 1f 31 0b |.*.H........0.1.|
+00000090 30 09 06 03 55 04 0a 13 02 47 6f 31 10 30 0e 06 |0...U....Go1.0..|
+000000a0 03 55 04 03 13 07 47 6f 20 52 6f 6f 74 30 1e 17 |.U....Go Root0..|
+000000b0 0d 31 36 30 31 30 31 30 30 30 30 30 30 5a 17 0d |.160101000000Z..|
+000000c0 32 35 30 31 30 31 30 30 30 30 30 30 5a 30 1a 31 |250101000000Z0.1|
+000000d0 0b 30 09 06 03 55 04 0a 13 02 47 6f 31 0b 30 09 |.0...U....Go1.0.|
+000000e0 06 03 55 04 03 13 02 47 6f 30 81 9f 30 0d 06 09 |..U....Go0..0...|
+000000f0 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 30 |*.H............0|
+00000100 81 89 02 81 81 00 db 46 7d 93 2e 12 27 06 48 bc |.......F}...'.H.|
+00000110 06 28 21 ab 7e c4 b6 a2 5d fe 1e 52 45 88 7a 36 |.(!.~...]..RE.z6|
+00000120 47 a5 08 0d 92 42 5b c2 81 c0 be 97 79 98 40 fb |G....B[.....y. at .|
+00000130 4f 6d 14 fd 2b 13 8b c2 a5 2e 67 d8 d4 09 9e d6 |Om..+.....g.....|
+00000140 22 38 b7 4a 0b 74 73 2b c2 34 f1 d1 93 e5 96 d9 |"8.J.ts+.4......|
+00000150 74 7b f3 58 9f 6c 61 3c c0 b0 41 d4 d9 2b 2b 24 |t{.X.la<..A..++$|
+00000160 23 77 5b 1c 3b bd 75 5d ce 20 54 cf a1 63 87 1d |#w[.;.u]. T..c..|
+00000170 1e 24 c4 f3 1d 1a 50 8b aa b6 14 43 ed 97 a7 75 |.$....P....C...u|
+00000180 62 f4 14 c8 52 d7 02 03 01 00 01 a3 81 93 30 81 |b...R.........0.|
+00000190 90 30 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 05 |.0...U..........|
+000001a0 a0 30 1d 06 03 55 1d 25 04 16 30 14 06 08 2b 06 |.0...U.%..0...+.|
+000001b0 01 05 05 07 03 01 06 08 2b 06 01 05 05 07 03 02 |........+.......|
+000001c0 30 0c 06 03 55 1d 13 01 01 ff 04 02 30 00 30 19 |0...U.......0.0.|
+000001d0 06 03 55 1d 0e 04 12 04 10 9f 91 16 1f 43 43 3e |..U..........CC>|
+000001e0 49 a6 de 6d b6 80 d7 9f 60 30 1b 06 03 55 1d 23 |I..m....`0...U.#|
+000001f0 04 14 30 12 80 10 48 13 49 4d 13 7e 16 31 bb a3 |..0...H.IM.~.1..|
+00000200 01 d5 ac ab 6e 7b 30 19 06 03 55 1d 11 04 12 30 |....n{0...U....0|
+00000210 10 82 0e 65 78 61 6d 70 6c 65 2e 67 6f 6c 61 6e |...example.golan|
+00000220 67 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 |g0...*.H........|
+00000230 03 81 81 00 9d 30 cc 40 2b 5b 50 a0 61 cb ba e5 |.....0. at +[P.a...|
+00000240 53 58 e1 ed 83 28 a9 58 1a a9 38 a4 95 a1 ac 31 |SX...(.X..8....1|
+00000250 5a 1a 84 66 3d 43 d3 2d d9 0b f2 97 df d3 20 64 |Z..f=C.-...... d|
+00000260 38 92 24 3a 00 bc cf 9c 7d b7 40 20 01 5f aa d3 |8.$:....}.@ ._..|
+00000270 16 61 09 a2 76 fd 13 c3 cc e1 0c 5c ee b1 87 82 |.a..v......\....|
+00000280 f1 6c 04 ed 73 bb b3 43 77 8d 0c 1c f1 0f a1 d8 |.l..s..Cw.......|
+00000290 40 83 61 c9 4c 72 2b 9d ae db 46 06 06 4d f4 c1 |@.a.Lr+...F..M..|
+000002a0 b3 3e c0 d1 bd 42 d4 db fe 3d 13 60 84 5c 21 d3 |.>...B...=.`.\!.|
+000002b0 3b e9 fa e7 16 03 03 00 04 0e 00 00 00 |;............|
>>> Flow 3 (client to server)
-00000000 16 03 03 00 86 10 00 00 82 00 80 73 bd 73 65 92 |...........s.se.|
-00000010 86 23 41 14 79 7f d5 c1 10 ce 94 4d ad 9c c3 a9 |.#A.y......M....|
-00000020 87 b5 32 52 f8 6b 11 93 2d 9b 98 0b 8b 1d c0 f6 |..2R.k..-.......|
-00000030 53 17 6d c7 9c 2e ae c9 6f cc 99 23 38 37 1a 10 |S.m.....o..#87..|
-00000040 fe 05 0b b5 55 0a 14 e9 60 7d 70 26 98 e2 54 d9 |....U...`}p&..T.|
-00000050 65 cf 2e f4 53 5f 1d aa 3a f6 33 7b eb 4c 0e b3 |e...S_..:.3{.L..|
-00000060 ff 5a db 36 2a 47 f3 df f9 fc f5 31 78 83 aa 6b |.Z.6*G.....1x..k|
-00000070 52 b7 ba 1a 96 bc fa c1 a1 a9 bb 2b f5 38 89 00 |R..........+.8..|
-00000080 4d e5 78 13 4e a4 38 46 42 dc 16 14 03 03 00 01 |M.x.N.8FB.......|
-00000090 01 16 03 03 00 28 00 00 00 00 00 00 00 00 28 9a |.....(........(.|
-000000a0 46 23 21 fa a9 ec 6d 57 d1 27 2f 53 58 a9 00 48 |F#!...mW.'/SX..H|
-000000b0 7e 82 82 b8 23 f3 c4 a8 d3 2c a3 99 76 2e |~...#....,..v.|
+00000000 16 03 03 00 86 10 00 00 82 00 80 b9 65 8d bf a7 |............e...|
+00000010 c8 4b 79 ce 6f cb 8b 13 1c ac b9 7d 66 5e e9 ba |.Ky.o......}f^..|
+00000020 1d 71 4e a9 e9 34 ae f6 64 65 90 3b d8 16 52 a2 |.qN..4..de.;..R.|
+00000030 6f f4 cb 8a 13 74 a2 ee b7 27 69 b4 41 c0 90 68 |o....t...'i.A..h|
+00000040 bc 02 69 e1 c6 48 4f 39 36 30 25 ca 4c 17 ce 83 |..i..HO960%.L...|
+00000050 9e 08 56 e3 05 49 93 9e 2e c4 fb e6 c8 01 f1 0f |..V..I..........|
+00000060 c5 70 0f 08 83 48 e9 48 ef 6e 50 8b 05 7e e5 84 |.p...H.H.nP..~..|
+00000070 25 fa 55 c7 ae 31 02 27 00 ef 3f 98 86 20 12 89 |%.U..1.'..?.. ..|
+00000080 91 59 28 b4 f7 d7 af d2 69 61 35 14 03 03 00 01 |.Y(.....ia5.....|
+00000090 01 16 03 03 00 28 00 00 00 00 00 00 00 00 57 97 |.....(........W.|
+000000a0 64 ef 80 07 b0 31 02 c8 2a a2 b7 1f d6 a3 7c 7a |d....1..*.....|z|
+000000b0 e9 c4 e1 55 9f 0a ef 0d 8f 0a 57 13 f5 a4 |...U......W...|
>>> Flow 4 (server to client)
-00000000 14 03 03 00 01 01 16 03 03 00 28 0c c8 0a e1 b8 |..........(.....|
-00000010 95 b9 84 bc 0f 48 eb d4 4a a5 63 c2 92 58 8a 91 |.....H..J.c..X..|
-00000020 27 30 36 28 23 f5 50 bd d6 a9 e9 61 54 10 f9 72 |'06(#.P....aT..r|
-00000030 98 d1 0e |...|
+00000000 14 03 03 00 01 01 16 03 03 00 28 42 49 9c 67 4f |..........(BI.gO|
+00000010 36 75 b8 34 0e ee 00 98 1a ba 52 d5 96 7b 91 d7 |6u.4......R..{..|
+00000020 ba ec e4 5e 2e 42 e3 72 a0 ea 60 24 31 30 3d a2 |...^.B.r..`$10=.|
+00000030 c5 6c 8f |.l.|
>>> Flow 5 (client to server)
-00000000 17 03 03 00 1e 00 00 00 00 00 00 00 01 b9 55 ce |..............U.|
-00000010 5a ab 7e 7e 58 4f c9 5a bc 0e 93 98 4f 87 86 98 |Z.~~XO.Z....O...|
-00000020 a6 40 7e 15 03 03 00 1a 00 00 00 00 00 00 00 02 |.@~.............|
-00000030 57 0c 6f d9 28 87 d4 a6 de 14 91 a7 79 cc 19 e5 |W.o.(.......y...|
-00000040 28 66 |(f|
+00000000 17 03 03 00 1e 00 00 00 00 00 00 00 01 42 9f da |.............B..|
+00000010 a1 e6 98 48 a8 6c 78 a0 f7 fd e7 0f bc df 97 ef |...H.lx.........|
+00000020 b8 62 4c 15 03 03 00 1a 00 00 00 00 00 00 00 02 |.bL.............|
+00000030 99 ac 35 a4 d9 1f 58 26 51 c6 6a b9 1f 53 ec 19 |..5...X&Q.j..S..|
+00000040 90 78 |.x|
diff --git a/src/crypto/tls/testdata/Client-TLSv12-ALPN b/src/crypto/tls/testdata/Client-TLSv12-ALPN
index d7745dc..9f90ff2 100644
--- a/src/crypto/tls/testdata/Client-TLSv12-ALPN
+++ b/src/crypto/tls/testdata/Client-TLSv12-ALPN
@@ -1,93 +1,86 @@
>>> Flow 1 (client to server)
-00000000 16 03 01 00 9d 01 00 00 99 03 03 00 00 00 00 00 |................|
+00000000 16 03 01 00 a9 01 00 00 a5 03 03 00 00 00 00 00 |................|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
-00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 22 c0 2f |............."./|
-00000030 c0 2b c0 30 c0 2c c0 11 c0 07 c0 13 c0 09 c0 14 |.+.0.,..........|
-00000040 c0 0a 00 9c 00 9d 00 05 00 2f 00 35 c0 12 00 0a |........./.5....|
-00000050 01 00 00 4e 33 74 00 00 00 05 00 05 01 00 00 00 |...N3t..........|
-00000060 00 00 0a 00 08 00 06 00 17 00 18 00 19 00 0b 00 |................|
-00000070 02 01 00 00 0d 00 0e 00 0c 04 01 04 03 05 01 05 |................|
-00000080 03 02 01 02 03 ff 01 00 01 00 00 10 00 10 00 0e |................|
-00000090 06 70 72 6f 74 6f 32 06 70 72 6f 74 6f 31 00 12 |.proto2.proto1..|
-000000a0 00 00 |..|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2c cc a8 |.............,..|
+00000030 cc a9 c0 2f c0 2b c0 30 c0 2c c0 27 c0 13 c0 23 |.../.+.0.,.'...#|
+00000040 c0 09 c0 14 c0 0a 00 9c 00 9d 00 3c 00 2f 00 35 |...........<./.5|
+00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 50 33 74 |.............P3t|
+00000060 00 00 00 05 00 05 01 00 00 00 00 00 0a 00 0a 00 |................|
+00000070 08 00 1d 00 17 00 18 00 19 00 0b 00 02 01 00 00 |................|
+00000080 0d 00 0e 00 0c 04 01 04 03 05 01 05 03 02 01 02 |................|
+00000090 03 ff 01 00 01 00 00 10 00 10 00 0e 06 70 72 6f |.............pro|
+000000a0 74 6f 32 06 70 72 6f 74 6f 31 00 12 00 00 |to2.proto1....|
>>> Flow 2 (server to client)
-00000000 16 03 03 00 66 02 00 00 62 03 03 a2 7d b9 7c f9 |....f...b...}.|.|
-00000010 bf fb cb b2 d5 11 c0 99 19 73 3d b4 eb 6b 39 f8 |.........s=..k9.|
-00000020 1b 7c 1d 6b 17 4d 66 a3 ed 20 5b 20 ee 87 d7 1f |.|.k.Mf.. [ ....|
-00000030 cf 60 6c 75 12 8b de 56 f6 ca da 4a 92 76 49 43 |.`lu...V...J.vIC|
-00000040 70 18 0a e7 7b 2a 0c f3 44 a6 d8 dd c0 2f 00 00 |p...{*..D..../..|
+00000000 16 03 03 00 66 02 00 00 62 03 03 8d 70 c6 03 ad |....f...b...p...|
+00000010 2f 20 b3 c2 ab e0 fc 80 74 c4 23 9e 82 65 61 a1 |/ ......t.#..ea.|
+00000020 26 97 14 a0 9b 9c d5 e0 92 43 ee 20 ec 84 cf 78 |&........C. ...x|
+00000030 44 16 7d f3 ad 94 a9 f8 c3 e0 c6 e1 b6 c5 e3 3d |D.}............=|
+00000040 77 ea 76 1d 58 cc 94 3a ad 1a 1a 6c cc a8 00 00 |w.v.X..:...l....|
00000050 1a ff 01 00 01 00 00 0b 00 04 03 00 01 02 00 10 |................|
-00000060 00 09 00 07 06 70 72 6f 74 6f 31 16 03 03 02 71 |.....proto1....q|
-00000070 0b 00 02 6d 00 02 6a 00 02 67 30 82 02 63 30 82 |...m..j..g0..c0.|
-00000080 01 cc a0 03 02 01 02 02 09 00 a2 73 00 0c 81 00 |...........s....|
-00000090 cb f3 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 |..0...*.H.......|
-000000a0 00 30 2b 31 17 30 15 06 03 55 04 0a 13 0e 47 6f |.0+1.0...U....Go|
-000000b0 6f 67 6c 65 20 54 45 53 54 49 4e 47 31 10 30 0e |ogle TESTING1.0.|
-000000c0 06 03 55 04 03 13 07 47 6f 20 52 6f 6f 74 30 1e |..U....Go Root0.|
-000000d0 17 0d 31 35 30 31 30 31 30 30 30 30 30 30 5a 17 |..150101000000Z.|
-000000e0 0d 32 35 30 31 30 31 30 30 30 30 30 30 5a 30 26 |.250101000000Z0&|
-000000f0 31 17 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c |1.0...U....Googl|
-00000100 65 20 54 45 53 54 49 4e 47 31 0b 30 09 06 03 55 |e TESTING1.0...U|
-00000110 04 03 13 02 47 6f 30 81 9f 30 0d 06 09 2a 86 48 |....Go0..0...*.H|
-00000120 86 f7 0d 01 01 01 05 00 03 81 8d 00 30 81 89 02 |............0...|
-00000130 81 81 00 af 87 88 f6 20 1b 95 65 6c 14 ab 44 05 |....... ..el..D.|
-00000140 af 3b 45 14 e3 b7 6d fd 00 63 4d 95 7f fe 6a 62 |.;E...m..cM...jb|
-00000150 35 86 c0 4a f9 18 7c f6 aa 25 5e 7a 64 31 66 00 |5..J..|..%^zd1f.|
-00000160 ba f4 8e 92 af c7 6b d8 76 d4 f3 5f 41 cb 6e 56 |......k.v.._A.nV|
-00000170 15 97 1b 97 c1 3c 12 39 21 66 3d 2b 16 d1 bc db |.....<.9!f=+....|
-00000180 1c c0 a7 da b7 ca ad ba da cb d5 21 50 ec de 8d |...........!P...|
-00000190 ab d1 6b 81 4b 89 02 f3 c4 be c1 6c 89 b1 44 84 |..k.K......l..D.|
-000001a0 bd 21 d1 04 7d 9d 16 4d f9 82 15 f6 ef fa d6 09 |.!..}..M........|
-000001b0 47 f2 fb 02 03 01 00 01 a3 81 93 30 81 90 30 0e |G..........0..0.|
-000001c0 06 03 55 1d 0f 01 01 ff 04 04 03 02 05 a0 30 1d |..U...........0.|
-000001d0 06 03 55 1d 25 04 16 30 14 06 08 2b 06 01 05 05 |..U.%..0...+....|
-000001e0 07 03 01 06 08 2b 06 01 05 05 07 03 02 30 0c 06 |.....+.......0..|
-000001f0 03 55 1d 13 01 01 ff 04 02 30 00 30 19 06 03 55 |.U.......0.0...U|
-00000200 1d 0e 04 12 04 10 12 50 8d 89 6f 1b d1 dc 54 4d |.......P..o...TM|
-00000210 6e cb 69 5e 06 f4 30 1b 06 03 55 1d 23 04 14 30 |n.i^..0...U.#..0|
-00000220 12 80 10 bf 3d b6 a9 66 f2 b8 40 cf ea b4 03 78 |....=..f.. at ....x|
-00000230 48 1a 41 30 19 06 03 55 1d 11 04 12 30 10 82 0e |H.A0...U....0...|
-00000240 65 78 61 6d 70 6c 65 2e 67 6f 6c 61 6e 67 30 0d |example.golang0.|
-00000250 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 03 81 81 |..*.H...........|
-00000260 00 92 7c af 91 55 12 18 96 59 31 a6 48 40 d5 2d |..|..U...Y1.H at .-|
-00000270 d5 ee bb 02 a0 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 |........|..0}<.v|
-00000280 da 4f 3d c0 fa ae 2d 33 24 6b 03 7b 1b 67 59 11 |.O=...-3$k.{.gY.|
-00000290 21 b5 11 bc 77 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f |!...w...n.-.5.d_|
-000002a0 22 3e 63 10 6b be ff 14 86 6d 0d f0 15 31 a8 14 |">c.k....m...1..|
-000002b0 38 1e 3b 84 87 2c cb 98 ed 51 76 b9 b1 4f dd db |8.;..,...Qv..O..|
-000002c0 9b 84 04 86 40 fa 51 dd ba b4 8d eb e3 46 de 46 |.... at .Q......F.F|
-000002d0 b9 4f 86 c7 f9 a4 c2 41 34 ac cc f6 ea b0 ab 39 |.O.....A4......9|
-000002e0 18 16 03 03 00 cd 0c 00 00 c9 03 00 17 41 04 41 |.............A.A|
-000002f0 a4 1f 6f ea 6d 59 68 72 1a 6d 47 c7 b4 a0 08 01 |..o.mYhr.mG.....|
-00000300 b9 b3 d8 7a 95 75 c0 58 2a d9 29 91 e7 d9 78 b2 |...z.u.X*.)...x.|
-00000310 97 1d 52 72 2d 18 cb ce 83 8a 07 f4 bd dd 7e a1 |..Rr-.........~.|
-00000320 d2 45 51 9d bf f1 bf 01 33 3a 10 94 6c 2b 99 04 |.EQ.....3:..l+..|
-00000330 01 00 80 63 8f 03 6d b4 4d f7 27 d0 1f f2 0f ff |...c..m.M.'.....|
-00000340 af 27 c2 97 21 68 8c 32 8b 14 67 0e b5 75 3a 5b |.'..!h.2..g..u:[|
-00000350 73 08 9a c7 fd ad 8d 50 2a de e7 d6 c5 87 7a b2 |s......P*.....z.|
-00000360 06 29 0a 09 dd d4 81 d5 a7 2b 4d 20 50 72 6f be |.).......+M Pro.|
-00000370 35 9b c6 2d b0 1e 8f a2 cf 10 33 d4 53 0b 33 95 |5..-......3.S.3.|
-00000380 b8 a5 34 38 1b db 1e 45 07 36 3a 86 c7 f1 b1 3a |..48...E.6:....:|
-00000390 2e 5d 82 b2 1d 3e e1 27 8f f2 f4 2c 8c c3 27 e9 |.]...>.'...,..'.|
-000003a0 f0 9a 8f 6d 20 b1 19 8e 23 d5 04 69 e4 eb 0d eb |...m ...#..i....|
-000003b0 97 fb 71 16 03 03 00 04 0e 00 00 00 |..q.........|
+00000060 00 09 00 07 06 70 72 6f 74 6f 31 16 03 03 02 59 |.....proto1....Y|
+00000070 0b 00 02 55 00 02 52 00 02 4f 30 82 02 4b 30 82 |...U..R..O0..K0.|
+00000080 01 b4 a0 03 02 01 02 02 09 00 e8 f0 9d 3f e2 5b |.............?.[|
+00000090 ea a6 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 |..0...*.H.......|
+000000a0 00 30 1f 31 0b 30 09 06 03 55 04 0a 13 02 47 6f |.0.1.0...U....Go|
+000000b0 31 10 30 0e 06 03 55 04 03 13 07 47 6f 20 52 6f |1.0...U....Go Ro|
+000000c0 6f 74 30 1e 17 0d 31 36 30 31 30 31 30 30 30 30 |ot0...1601010000|
+000000d0 30 30 5a 17 0d 32 35 30 31 30 31 30 30 30 30 30 |00Z..25010100000|
+000000e0 30 5a 30 1a 31 0b 30 09 06 03 55 04 0a 13 02 47 |0Z0.1.0...U....G|
+000000f0 6f 31 0b 30 09 06 03 55 04 03 13 02 47 6f 30 81 |o1.0...U....Go0.|
+00000100 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 01 05 00 |.0...*.H........|
+00000110 03 81 8d 00 30 81 89 02 81 81 00 db 46 7d 93 2e |....0.......F}..|
+00000120 12 27 06 48 bc 06 28 21 ab 7e c4 b6 a2 5d fe 1e |.'.H..(!.~...]..|
+00000130 52 45 88 7a 36 47 a5 08 0d 92 42 5b c2 81 c0 be |RE.z6G....B[....|
+00000140 97 79 98 40 fb 4f 6d 14 fd 2b 13 8b c2 a5 2e 67 |.y. at .Om..+.....g|
+00000150 d8 d4 09 9e d6 22 38 b7 4a 0b 74 73 2b c2 34 f1 |....."8.J.ts+.4.|
+00000160 d1 93 e5 96 d9 74 7b f3 58 9f 6c 61 3c c0 b0 41 |.....t{.X.la<..A|
+00000170 d4 d9 2b 2b 24 23 77 5b 1c 3b bd 75 5d ce 20 54 |..++$#w[.;.u]. T|
+00000180 cf a1 63 87 1d 1e 24 c4 f3 1d 1a 50 8b aa b6 14 |..c...$....P....|
+00000190 43 ed 97 a7 75 62 f4 14 c8 52 d7 02 03 01 00 01 |C...ub...R......|
+000001a0 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f 01 01 ff |...0..0...U.....|
+000001b0 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 04 16 30 |......0...U.%..0|
+000001c0 14 06 08 2b 06 01 05 05 07 03 01 06 08 2b 06 01 |...+.........+..|
+000001d0 05 05 07 03 02 30 0c 06 03 55 1d 13 01 01 ff 04 |.....0...U......|
+000001e0 02 30 00 30 19 06 03 55 1d 0e 04 12 04 10 9f 91 |.0.0...U........|
+000001f0 16 1f 43 43 3e 49 a6 de 6d b6 80 d7 9f 60 30 1b |..CC>I..m....`0.|
+00000200 06 03 55 1d 23 04 14 30 12 80 10 48 13 49 4d 13 |..U.#..0...H.IM.|
+00000210 7e 16 31 bb a3 01 d5 ac ab 6e 7b 30 19 06 03 55 |~.1......n{0...U|
+00000220 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 6c 65 2e |....0...example.|
+00000230 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 86 f7 0d |golang0...*.H...|
+00000240 01 01 0b 05 00 03 81 81 00 9d 30 cc 40 2b 5b 50 |..........0. at +[P|
+00000250 a0 61 cb ba e5 53 58 e1 ed 83 28 a9 58 1a a9 38 |.a...SX...(.X..8|
+00000260 a4 95 a1 ac 31 5a 1a 84 66 3d 43 d3 2d d9 0b f2 |....1Z..f=C.-...|
+00000270 97 df d3 20 64 38 92 24 3a 00 bc cf 9c 7d b7 40 |... d8.$:....}.@|
+00000280 20 01 5f aa d3 16 61 09 a2 76 fd 13 c3 cc e1 0c | ._...a..v......|
+00000290 5c ee b1 87 82 f1 6c 04 ed 73 bb b3 43 77 8d 0c |\.....l..s..Cw..|
+000002a0 1c f1 0f a1 d8 40 83 61 c9 4c 72 2b 9d ae db 46 |..... at .a.Lr+...F|
+000002b0 06 06 4d f4 c1 b3 3e c0 d1 bd 42 d4 db fe 3d 13 |..M...>...B...=.|
+000002c0 60 84 5c 21 d3 3b e9 fa e7 16 03 03 00 ac 0c 00 |`.\!.;..........|
+000002d0 00 a8 03 00 1d 20 84 de 31 92 b6 a5 d8 a4 88 a2 |..... ..1.......|
+000002e0 54 67 e6 61 40 f2 5a 87 0f ce 15 b1 d6 af f3 5d |Tg.a at .Z........]|
+000002f0 99 71 d6 04 f5 52 04 01 00 80 a8 1d 8b 8c e9 a3 |.q...R..........|
+00000300 af 2d 31 e4 0f f0 26 74 c2 e5 1b ae ac 47 9c 6e |.-1...&t.....G.n|
+00000310 6c 5f 45 7d b1 b3 2a af 36 68 42 13 95 0d 33 1c |l_E}..*.6hB...3.|
+00000320 8d 6c 72 48 4a 94 f0 fb 82 20 cc 76 21 7f 62 e7 |.lrHJ.... .v!.b.|
+00000330 23 a3 c8 4e 3a ce f1 5c c3 60 73 26 59 4c 94 f3 |#..N:..\.`s&YL..|
+00000340 07 36 f6 a0 b3 60 03 d5 72 1e bf c8 d9 1d 61 01 |.6...`..r.....a.|
+00000350 9a 18 57 a3 b4 de 36 1f e1 7d dc 69 c0 fb c0 71 |..W...6..}.i...q|
+00000360 45 1f 73 0d 50 69 d3 18 97 23 60 1c 5a 9a 93 b4 |E.s.Pi...#`.Z...|
+00000370 67 cc e5 80 3b 25 d0 6c 50 c8 16 03 03 00 04 0e |g...;%.lP.......|
+00000380 00 00 00 |...|
>>> Flow 3 (client to server)
-00000000 16 03 03 00 46 10 00 00 42 41 04 1e 18 37 ef 0d |....F...BA...7..|
-00000010 19 51 88 35 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd |.Q.5uq..T[....g.|
-00000020 a7 24 20 3e b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e |.$ >.V...(^.+-O.|
-00000030 f1 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 |...lK[.V.2B.X..I|
-00000040 a6 b5 68 1a 41 03 56 6b dc 5a 89 14 03 03 00 01 |..h.A.Vk.Z......|
-00000050 01 16 03 03 00 28 00 00 00 00 00 00 00 00 15 94 |.....(..........|
-00000060 6f 5b 35 9d eb 14 c8 be 23 a7 05 8c 14 86 35 a7 |o[5.....#.....5.|
-00000070 5c 91 76 4f 85 b1 09 f8 0f 58 9f ec d2 a9 |\.vO.....X....|
+00000000 16 03 03 00 25 10 00 00 21 20 2f e5 7d a3 47 cd |....%...! /.}.G.|
+00000010 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af c4 |bC.(.._.).0.....|
+00000020 cf c2 ed 90 99 5f 58 cb 3b 74 14 03 03 00 01 01 |....._X.;t......|
+00000030 16 03 03 00 20 5c c5 3e 7a 14 97 1b 55 88 25 08 |.... \.>z...U.%.|
+00000040 ad 86 48 ac f0 43 8c 17 5b 58 93 6c 7a 95 69 a8 |..H..C..[X.lz.i.|
+00000050 ad 0c b3 61 4d |...aM|
>>> Flow 4 (server to client)
-00000000 14 03 03 00 01 01 16 03 03 00 28 e7 7f 99 c9 fa |..........(.....|
-00000010 e0 a3 e3 77 68 74 37 62 26 90 d6 be ec a1 ae 5a |...wht7b&......Z|
-00000020 de af 10 f1 2e a0 42 f0 88 ed 89 54 04 b2 b9 eb |......B....T....|
-00000030 b0 91 b8 |...|
+00000000 14 03 03 00 01 01 16 03 03 00 20 dd 1b 80 da d9 |.......... .....|
+00000010 73 da 7d 15 9b 92 82 01 a7 8f fe 4a 75 97 8f f4 |s.}........Ju...|
+00000020 64 1b bf cf c3 40 78 f2 52 f5 7a |d.... at x.R.z|
>>> Flow 5 (client to server)
-00000000 17 03 03 00 1e 00 00 00 00 00 00 00 01 be e7 77 |...............w|
-00000010 f9 92 ac 51 d0 34 25 34 e6 35 9e ea f0 d3 89 45 |...Q.4%4.5.....E|
-00000020 84 1b 93 15 03 03 00 1a 00 00 00 00 00 00 00 02 |................|
-00000030 1a 27 54 01 c9 7c 86 4b 61 c8 98 1b d3 15 1f 93 |.'T..|.Ka.......|
-00000040 f9 42 |.B|
+00000000 17 03 03 00 16 4e fa 7c 37 80 48 19 a6 03 25 7c |.....N.|7.H...%||
+00000010 65 56 43 af 9a e8 e2 aa e5 79 98 15 03 03 00 12 |eVC......y......|
+00000020 f9 b7 01 e8 2e 85 33 89 60 44 84 93 26 4c ec ac |......3.`D..&L..|
+00000030 2e 6f |.o|
diff --git a/src/crypto/tls/testdata/Client-TLSv12-ALPN-NoMatch b/src/crypto/tls/testdata/Client-TLSv12-ALPN-NoMatch
index 9a34e4a..62e7d11 100644
--- a/src/crypto/tls/testdata/Client-TLSv12-ALPN-NoMatch
+++ b/src/crypto/tls/testdata/Client-TLSv12-ALPN-NoMatch
@@ -1,91 +1,91 @@
>>> Flow 1 (client to server)
-00000000 16 03 01 00 96 01 00 00 92 03 03 00 00 00 00 00 |................|
+00000000 16 03 01 00 9c 01 00 00 98 03 03 00 00 00 00 00 |................|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
-00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 22 c0 2f |............."./|
-00000030 c0 2b c0 30 c0 2c c0 11 c0 07 c0 13 c0 09 c0 14 |.+.0.,..........|
-00000040 c0 0a 00 9c 00 9d 00 05 00 2f 00 35 c0 12 00 0a |........./.5....|
-00000050 01 00 00 47 33 74 00 00 00 05 00 05 01 00 00 00 |...G3t..........|
-00000060 00 00 0a 00 08 00 06 00 17 00 18 00 19 00 0b 00 |................|
-00000070 02 01 00 00 0d 00 0e 00 0c 04 01 04 03 05 01 05 |................|
-00000080 03 02 01 02 03 ff 01 00 01 00 00 10 00 09 00 07 |................|
-00000090 06 70 72 6f 74 6f 33 00 12 00 00 |.proto3....|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 28 c0 2f |.............(./|
+00000030 c0 2b c0 30 c0 2c c0 27 c0 13 c0 23 c0 09 c0 14 |.+.0.,.'...#....|
+00000040 c0 0a 00 9c 00 9d 00 3c 00 2f 00 35 c0 12 00 0a |.......<./.5....|
+00000050 00 05 c0 11 c0 07 01 00 00 47 33 74 00 00 00 05 |.........G3t....|
+00000060 00 05 01 00 00 00 00 00 0a 00 08 00 06 00 17 00 |................|
+00000070 18 00 19 00 0b 00 02 01 00 00 0d 00 0e 00 0c 04 |................|
+00000080 01 04 03 05 01 05 03 02 01 02 03 ff 01 00 01 00 |................|
+00000090 00 10 00 09 00 07 06 70 72 6f 74 6f 33 00 12 00 |.......proto3...|
+000000a0 00 |.|
>>> Flow 2 (server to client)
-00000000 16 03 03 00 59 02 00 00 55 03 03 18 3d 15 59 fb |....Y...U...=.Y.|
-00000010 0a a4 93 d7 43 50 59 7f 6c f9 64 db b5 47 cc 17 |....CPY.l.d..G..|
-00000020 8c cd 91 b5 04 02 3f c0 5d 60 b7 20 75 ed d2 e9 |......?.]`. u...|
-00000030 b6 72 2d f7 66 34 2e 2f d2 b9 80 66 eb c3 36 f6 |.r-.f4./...f..6.|
-00000040 b2 61 77 79 a9 c2 db cd 57 5a b2 6b c0 2f 00 00 |.awy....WZ.k./..|
+00000000 16 03 03 00 59 02 00 00 55 03 03 36 0e 9f 51 42 |....Y...U..6..QB|
+00000010 82 65 fa b5 17 7a 86 d6 40 33 a9 67 d3 3d aa 2f |.e...z.. at 3.g.=./|
+00000020 89 a0 39 82 af 16 30 8e 64 80 d4 20 23 a6 d0 12 |..9...0.d.. #...|
+00000030 ff 8c fc b4 b5 47 ec 10 fe ba 73 fb 0f ab e8 1c |.....G....s.....|
+00000040 15 c1 fb 11 c1 b2 e1 8a f7 5d 5b ad c0 2f 00 00 |.........][../..|
00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................|
-00000060 03 02 71 0b 00 02 6d 00 02 6a 00 02 67 30 82 02 |..q...m..j..g0..|
-00000070 63 30 82 01 cc a0 03 02 01 02 02 09 00 a2 73 00 |c0............s.|
-00000080 0c 81 00 cb f3 30 0d 06 09 2a 86 48 86 f7 0d 01 |.....0...*.H....|
-00000090 01 0b 05 00 30 2b 31 17 30 15 06 03 55 04 0a 13 |....0+1.0...U...|
-000000a0 0e 47 6f 6f 67 6c 65 20 54 45 53 54 49 4e 47 31 |.Google TESTING1|
-000000b0 10 30 0e 06 03 55 04 03 13 07 47 6f 20 52 6f 6f |.0...U....Go Roo|
-000000c0 74 30 1e 17 0d 31 35 30 31 30 31 30 30 30 30 30 |t0...15010100000|
-000000d0 30 5a 17 0d 32 35 30 31 30 31 30 30 30 30 30 30 |0Z..250101000000|
-000000e0 5a 30 26 31 17 30 15 06 03 55 04 0a 13 0e 47 6f |Z0&1.0...U....Go|
-000000f0 6f 67 6c 65 20 54 45 53 54 49 4e 47 31 0b 30 09 |ogle TESTING1.0.|
-00000100 06 03 55 04 03 13 02 47 6f 30 81 9f 30 0d 06 09 |..U....Go0..0...|
-00000110 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 30 |*.H............0|
-00000120 81 89 02 81 81 00 af 87 88 f6 20 1b 95 65 6c 14 |.......... ..el.|
-00000130 ab 44 05 af 3b 45 14 e3 b7 6d fd 00 63 4d 95 7f |.D..;E...m..cM..|
-00000140 fe 6a 62 35 86 c0 4a f9 18 7c f6 aa 25 5e 7a 64 |.jb5..J..|..%^zd|
-00000150 31 66 00 ba f4 8e 92 af c7 6b d8 76 d4 f3 5f 41 |1f.......k.v.._A|
-00000160 cb 6e 56 15 97 1b 97 c1 3c 12 39 21 66 3d 2b 16 |.nV.....<.9!f=+.|
-00000170 d1 bc db 1c c0 a7 da b7 ca ad ba da cb d5 21 50 |..............!P|
-00000180 ec de 8d ab d1 6b 81 4b 89 02 f3 c4 be c1 6c 89 |.....k.K......l.|
-00000190 b1 44 84 bd 21 d1 04 7d 9d 16 4d f9 82 15 f6 ef |.D..!..}..M.....|
-000001a0 fa d6 09 47 f2 fb 02 03 01 00 01 a3 81 93 30 81 |...G..........0.|
-000001b0 90 30 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 05 |.0...U..........|
-000001c0 a0 30 1d 06 03 55 1d 25 04 16 30 14 06 08 2b 06 |.0...U.%..0...+.|
-000001d0 01 05 05 07 03 01 06 08 2b 06 01 05 05 07 03 02 |........+.......|
-000001e0 30 0c 06 03 55 1d 13 01 01 ff 04 02 30 00 30 19 |0...U.......0.0.|
-000001f0 06 03 55 1d 0e 04 12 04 10 12 50 8d 89 6f 1b d1 |..U.......P..o..|
-00000200 dc 54 4d 6e cb 69 5e 06 f4 30 1b 06 03 55 1d 23 |.TMn.i^..0...U.#|
-00000210 04 14 30 12 80 10 bf 3d b6 a9 66 f2 b8 40 cf ea |..0....=..f.. at ..|
-00000220 b4 03 78 48 1a 41 30 19 06 03 55 1d 11 04 12 30 |..xH.A0...U....0|
-00000230 10 82 0e 65 78 61 6d 70 6c 65 2e 67 6f 6c 61 6e |...example.golan|
-00000240 67 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 |g0...*.H........|
-00000250 03 81 81 00 92 7c af 91 55 12 18 96 59 31 a6 48 |.....|..U...Y1.H|
-00000260 40 d5 2d d5 ee bb 02 a0 f5 c2 1e 7c 9b b3 30 7d |@.-........|..0}|
-00000270 3c dc 76 da 4f 3d c0 fa ae 2d 33 24 6b 03 7b 1b |<.v.O=...-3$k.{.|
-00000280 67 59 11 21 b5 11 bc 77 b9 d9 e0 6e a8 2d 2e 35 |gY.!...w...n.-.5|
-00000290 fa 64 5f 22 3e 63 10 6b be ff 14 86 6d 0d f0 15 |.d_">c.k....m...|
-000002a0 31 a8 14 38 1e 3b 84 87 2c cb 98 ed 51 76 b9 b1 |1..8.;..,...Qv..|
-000002b0 4f dd db 9b 84 04 86 40 fa 51 dd ba b4 8d eb e3 |O...... at .Q......|
-000002c0 46 de 46 b9 4f 86 c7 f9 a4 c2 41 34 ac cc f6 ea |F.F.O.....A4....|
-000002d0 b0 ab 39 18 16 03 03 00 cd 0c 00 00 c9 03 00 17 |..9.............|
-000002e0 41 04 62 52 78 76 89 36 e7 b9 a6 cc df 8e f8 c3 |A.bRxv.6........|
-000002f0 52 54 b6 42 9b 68 65 65 27 91 bf 1b 0f 21 ab a9 |RT.B.hee'....!..|
-00000300 f4 00 62 dd 70 25 b8 ec d0 3d 9b 0c 53 16 6e eb |..b.p%...=..S.n.|
-00000310 a8 c3 1a ad a9 de ec 27 64 07 e8 9b b8 bf 5a 6c |.......'d.....Zl|
-00000320 87 f4 04 01 00 80 05 ec 2b f7 2e a4 5e 79 85 6f |........+...^y.o|
-00000330 64 7a b5 fb 9a e9 f1 12 ae 28 93 4b 6d 8e a0 2f |dz.......(.Km../|
-00000340 94 bc 38 26 01 64 ab fb 03 c8 3d 17 bc b4 43 09 |..8&.d....=...C.|
-00000350 19 c8 e9 ac 60 40 67 57 71 e3 72 22 cf b1 a7 38 |....`@gWq.r"...8|
-00000360 ac 86 88 9d 47 6f 70 c9 43 82 75 b6 bf 42 4e 72 |....Gop.C.u..BNr|
-00000370 12 48 d1 2b ce 74 02 5d 30 56 66 6f 71 8f 9b 82 |.H.+.t.]0Vfoq...|
-00000380 70 3b 92 5d fb 37 d3 cf d3 23 27 d2 d5 8d 72 22 |p;.].7...#'...r"|
-00000390 d4 b4 92 6d 64 06 d9 0b e0 bb 34 eb bf 42 ec 6a |...md.....4..B.j|
-000003a0 ea e3 56 68 85 a0 16 03 03 00 04 0e 00 00 00 |..Vh...........|
+00000060 03 02 59 0b 00 02 55 00 02 52 00 02 4f 30 82 02 |..Y...U..R..O0..|
+00000070 4b 30 82 01 b4 a0 03 02 01 02 02 09 00 e8 f0 9d |K0..............|
+00000080 3f e2 5b ea a6 30 0d 06 09 2a 86 48 86 f7 0d 01 |?.[..0...*.H....|
+00000090 01 0b 05 00 30 1f 31 0b 30 09 06 03 55 04 0a 13 |....0.1.0...U...|
+000000a0 02 47 6f 31 10 30 0e 06 03 55 04 03 13 07 47 6f |.Go1.0...U....Go|
+000000b0 20 52 6f 6f 74 30 1e 17 0d 31 36 30 31 30 31 30 | Root0...1601010|
+000000c0 30 30 30 30 30 5a 17 0d 32 35 30 31 30 31 30 30 |00000Z..25010100|
+000000d0 30 30 30 30 5a 30 1a 31 0b 30 09 06 03 55 04 0a |0000Z0.1.0...U..|
+000000e0 13 02 47 6f 31 0b 30 09 06 03 55 04 03 13 02 47 |..Go1.0...U....G|
+000000f0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....|
+00000100 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 db 46 |.......0.......F|
+00000110 7d 93 2e 12 27 06 48 bc 06 28 21 ab 7e c4 b6 a2 |}...'.H..(!.~...|
+00000120 5d fe 1e 52 45 88 7a 36 47 a5 08 0d 92 42 5b c2 |]..RE.z6G....B[.|
+00000130 81 c0 be 97 79 98 40 fb 4f 6d 14 fd 2b 13 8b c2 |....y. at .Om..+...|
+00000140 a5 2e 67 d8 d4 09 9e d6 22 38 b7 4a 0b 74 73 2b |..g....."8.J.ts+|
+00000150 c2 34 f1 d1 93 e5 96 d9 74 7b f3 58 9f 6c 61 3c |.4......t{.X.la<|
+00000160 c0 b0 41 d4 d9 2b 2b 24 23 77 5b 1c 3b bd 75 5d |..A..++$#w[.;.u]|
+00000170 ce 20 54 cf a1 63 87 1d 1e 24 c4 f3 1d 1a 50 8b |. T..c...$....P.|
+00000180 aa b6 14 43 ed 97 a7 75 62 f4 14 c8 52 d7 02 03 |...C...ub...R...|
+00000190 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..|
+000001a0 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%|
+000001b0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........|
+000001c0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...|
+000001d0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....|
+000001e0 10 9f 91 16 1f 43 43 3e 49 a6 de 6d b6 80 d7 9f |.....CC>I..m....|
+000001f0 60 30 1b 06 03 55 1d 23 04 14 30 12 80 10 48 13 |`0...U.#..0...H.|
+00000200 49 4d 13 7e 16 31 bb a3 01 d5 ac ab 6e 7b 30 19 |IM.~.1......n{0.|
+00000210 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp|
+00000220 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H|
+00000230 86 f7 0d 01 01 0b 05 00 03 81 81 00 9d 30 cc 40 |.............0.@|
+00000240 2b 5b 50 a0 61 cb ba e5 53 58 e1 ed 83 28 a9 58 |+[P.a...SX...(.X|
+00000250 1a a9 38 a4 95 a1 ac 31 5a 1a 84 66 3d 43 d3 2d |..8....1Z..f=C.-|
+00000260 d9 0b f2 97 df d3 20 64 38 92 24 3a 00 bc cf 9c |...... d8.$:....|
+00000270 7d b7 40 20 01 5f aa d3 16 61 09 a2 76 fd 13 c3 |}.@ ._...a..v...|
+00000280 cc e1 0c 5c ee b1 87 82 f1 6c 04 ed 73 bb b3 43 |...\.....l..s..C|
+00000290 77 8d 0c 1c f1 0f a1 d8 40 83 61 c9 4c 72 2b 9d |w....... at .a.Lr+.|
+000002a0 ae db 46 06 06 4d f4 c1 b3 3e c0 d1 bd 42 d4 db |..F..M...>...B..|
+000002b0 fe 3d 13 60 84 5c 21 d3 3b e9 fa e7 16 03 03 00 |.=.`.\!.;.......|
+000002c0 cd 0c 00 00 c9 03 00 17 41 04 11 b4 a9 10 7e 5c |........A.....~\|
+000002d0 41 5e 39 12 15 a3 ed 5b 3e 5d 68 c8 ad 48 39 ef |A^9....[>]h..H9.|
+000002e0 09 8b b1 a7 bf db 5f 54 49 cd d5 de 4d b3 47 4c |......_TI...M.GL|
+000002f0 18 02 84 7c ec 75 4e d0 3e 8a d1 6c 80 83 98 64 |...|.uN.>..l...d|
+00000300 4a 81 bc 8f 84 c7 e5 b4 2d fa 04 01 00 80 72 ee |J.......-.....r.|
+00000310 41 38 f2 b8 a1 56 81 d8 04 78 75 05 f4 78 5f f2 |A8...V...xu..x_.|
+00000320 2b 5d a2 46 23 9d 48 c8 63 a9 1d de a8 78 6e 99 |+].F#.H.c....xn.|
+00000330 cd 59 6b 19 20 f5 b1 11 e1 f8 1c 5b 40 c3 b8 cd |.Yk. ......[@...|
+00000340 66 a3 98 37 c5 c2 5c b7 d6 cc 61 b4 5e 97 fa dd |f..7..\...a.^...|
+00000350 b7 85 5d b6 34 8c 39 4a 60 5a 03 20 47 7f e3 65 |..].4.9J`Z. G..e|
+00000360 01 18 00 2c c3 eb be d4 aa 58 57 a9 5e 69 fb 3c |...,.....XW.^i.<|
+00000370 fa c6 28 1a 5c f7 00 d5 21 e5 c1 30 db 84 38 c3 |..(.\...!..0..8.|
+00000380 08 aa 08 5f c9 fd a0 b7 8e d0 66 77 bf 13 16 03 |..._......fw....|
+00000390 03 00 04 0e 00 00 00 |.......|
>>> Flow 3 (client to server)
00000000 16 03 03 00 46 10 00 00 42 41 04 1e 18 37 ef 0d |....F...BA...7..|
00000010 19 51 88 35 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd |.Q.5uq..T[....g.|
00000020 a7 24 20 3e b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e |.$ >.V...(^.+-O.|
00000030 f1 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 |...lK[.V.2B.X..I|
00000040 a6 b5 68 1a 41 03 56 6b dc 5a 89 14 03 03 00 01 |..h.A.Vk.Z......|
-00000050 01 16 03 03 00 28 00 00 00 00 00 00 00 00 97 34 |.....(.........4|
-00000060 d5 c2 64 97 f6 a9 f5 60 bc 17 f3 d3 02 3f 42 a8 |..d....`.....?B.|
-00000070 2f ba eb c6 50 3c ec 9b 8d 3b 22 ed ec 35 |/...P<...;"..5|
+00000050 01 16 03 03 00 28 00 00 00 00 00 00 00 00 4f 7e |.....(........O~|
+00000060 9a 3a cc 74 a4 91 77 01 0b 0e 28 0a c5 bd 55 b7 |.:.t..w...(...U.|
+00000070 9a 4c 40 4e e9 c9 46 d5 5f c5 e1 77 c3 f2 |.L at N..F._..w..|
>>> Flow 4 (server to client)
-00000000 14 03 03 00 01 01 16 03 03 00 28 9a e5 f5 51 5c |..........(...Q\|
-00000010 cb be 5d a1 67 cc 55 aa ba db e7 0a ab 96 3b 33 |..].g.U.......;3|
-00000020 5f 2c 8c 61 20 f1 0d 6e ce 90 d8 39 27 d7 fb 68 |_,.a ..n...9'..h|
-00000030 d9 dd da |...|
+00000000 14 03 03 00 01 01 16 03 03 00 28 62 4b 13 ef 22 |..........(bK.."|
+00000010 f9 a8 8d ec 42 3a 36 80 5d a8 5b e9 60 d1 ba 65 |....B:6.].[.`..e|
+00000020 2b d8 37 64 e5 12 b2 ef 84 75 87 0c 0f 3d 35 6e |+.7d.....u...=5n|
+00000030 59 7c 51 |Y|Q|
>>> Flow 5 (client to server)
-00000000 17 03 03 00 1e 00 00 00 00 00 00 00 01 a8 be 7c |...............||
-00000010 05 48 ea df 62 4a 7a 45 68 e4 dc e6 42 ff 06 f2 |.H..bJzEh...B...|
-00000020 02 33 1a 15 03 03 00 1a 00 00 00 00 00 00 00 02 |.3..............|
-00000030 66 68 f4 de da 69 b4 f9 80 9c 80 c6 46 e5 2b ae |fh...i......F.+.|
-00000040 0e d1 |..|
+00000000 17 03 03 00 1e 00 00 00 00 00 00 00 01 5f cd 4d |............._.M|
+00000010 7b a7 c0 f9 6c 1f 80 93 cf 55 3b 12 c7 21 12 86 |{...l....U;..!..|
+00000020 f6 b1 52 15 03 03 00 1a 00 00 00 00 00 00 00 02 |..R.............|
+00000030 fd 31 a4 4b d1 e9 f0 e0 18 b5 96 28 f7 b4 0c 29 |.1.K.......(...)|
+00000040 8c 0c |..|
diff --git a/src/crypto/tls/testdata/Client-TLSv12-ClientCert-ECDSA-ECDSA b/src/crypto/tls/testdata/Client-TLSv12-ClientCert-ECDSA-ECDSA
index 4b88acf..336e10d 100644
--- a/src/crypto/tls/testdata/Client-TLSv12-ClientCert-ECDSA-ECDSA
+++ b/src/crypto/tls/testdata/Client-TLSv12-ClientCert-ECDSA-ECDSA
@@ -1,19 +1,20 @@
>>> Flow 1 (client to server)
-00000000 16 03 01 00 85 01 00 00 81 03 03 00 00 00 00 00 |................|
+00000000 16 03 01 00 91 01 00 00 8d 03 03 00 00 00 00 00 |................|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
-00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 22 c0 2f |............."./|
-00000030 c0 2b c0 30 c0 2c c0 11 c0 07 c0 13 c0 09 c0 14 |.+.0.,..........|
-00000040 c0 0a 00 9c 00 9d 00 05 00 2f 00 35 c0 12 00 0a |........./.5....|
-00000050 01 00 00 36 00 05 00 05 01 00 00 00 00 00 0a 00 |...6............|
-00000060 08 00 06 00 17 00 18 00 19 00 0b 00 02 01 00 00 |................|
-00000070 0d 00 0e 00 0c 04 01 04 03 05 01 05 03 02 01 02 |................|
-00000080 03 ff 01 00 01 00 00 12 00 00 |..........|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2c cc a8 |.............,..|
+00000030 cc a9 c0 2f c0 2b c0 30 c0 2c c0 27 c0 13 c0 23 |.../.+.0.,.'...#|
+00000040 c0 09 c0 14 c0 0a 00 9c 00 9d 00 3c 00 2f 00 35 |...........<./.5|
+00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 38 00 05 |.............8..|
+00000060 00 05 01 00 00 00 00 00 0a 00 0a 00 08 00 1d 00 |................|
+00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 0e 00 |................|
+00000080 0c 04 01 04 03 05 01 05 03 02 01 02 03 ff 01 00 |................|
+00000090 01 00 00 12 00 00 |......|
>>> Flow 2 (server to client)
-00000000 16 03 03 00 59 02 00 00 55 03 03 f0 5c 85 c8 ff |....Y...U...\...|
-00000010 c5 57 76 99 3d 75 e6 2e db 31 26 c0 0c 81 c5 6b |.Wv.=u...1&....k|
-00000020 30 79 e6 72 86 77 48 01 ec 43 1a 20 f8 fd ad b5 |0y.r.wH..C. ....|
-00000030 a0 7b f3 35 27 df ad 95 f9 56 f9 79 6c a2 6c 23 |.{.5'....V.yl.l#|
-00000040 51 4c ef fc 92 fb fa 59 97 e9 63 27 c0 09 00 00 |QL.....Y..c'....|
+00000000 16 03 03 00 59 02 00 00 55 03 03 cf 28 2c 3e 4f |....Y...U...(,>O|
+00000010 da 6b ae 24 74 a9 91 c3 c5 55 4b ab ec 07 f8 cd |.k.$t....UK.....|
+00000020 65 f8 fe 08 f6 9a 23 da 99 6c 5d 20 af 4a 1e 32 |e.....#..l] .J.2|
+00000030 7b bd 3c 0b b1 14 66 a3 b7 2f a4 2a c3 43 c4 e0 |{.<...f../.*.C..|
+00000040 c2 ad 78 b1 28 ab 51 06 1b 87 d2 75 c0 09 00 00 |..x.(.Q....u....|
00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................|
00000060 03 02 0e 0b 00 02 0a 00 02 07 00 02 04 30 82 02 |.............0..|
00000070 00 30 82 01 62 02 09 00 b8 bf 2d 47 a0 d2 eb f4 |.0..b.....-G....|
@@ -48,24 +49,22 @@
00000240 13 83 0d 94 06 bb d4 37 7a f6 ec 7a c9 86 2e dd |.......7z..z....|
00000250 d7 11 69 7f 85 7c 56 de fb 31 78 2b e4 c7 78 0d |..i..|V..1x+..x.|
00000260 ae cb be 9e 4e 36 24 31 7b 6a 0f 39 95 12 07 8f |....N6$1{j.9....|
-00000270 2a 16 03 03 00 d8 0c 00 00 d4 03 00 17 41 04 51 |*............A.Q|
-00000280 1e 2e 40 c5 a1 13 15 f0 bc 8a 04 e1 9a 57 74 10 |.. at ..........Wt.|
-00000290 7e b3 17 bf 0c c9 85 9b 5f bd 6b 39 c7 a6 c0 50 |~......._.k9...P|
-000002a0 0e 5e 9b b1 8c cc 57 39 e8 0f 94 02 be 28 19 16 |.^....W9.....(..|
-000002b0 94 73 2b c1 3c a7 0f c9 e7 b0 89 ac 13 53 f9 04 |.s+.<........S..|
-000002c0 03 00 8b 30 81 88 02 42 01 1b e0 ab 94 02 aa 27 |...0...B.......'|
-000002d0 fa 7b 99 9c 68 36 d8 2d 2e e0 92 84 c7 7b 37 74 |.{..h6.-.....{7t|
-000002e0 6a ad a8 f5 50 3f 74 d5 e8 8e 5a db 31 43 c8 98 |j...P?t...Z.1C..|
-000002f0 d3 ee 61 43 80 9a 72 eb 2d 2b 21 b8 33 aa 61 0a |..aC..r.-+!.3.a.|
-00000300 cd dc 85 88 29 26 83 ee 3c b2 02 42 00 b6 ea 34 |....)&..<..B...4|
-00000310 30 71 5c 0a 9a 6d a2 25 62 1c 3e 13 90 9c a3 b8 |0q\..m.%b.>.....|
-00000320 0d 97 a8 06 26 9e 31 50 88 9a b9 ff 12 63 a8 14 |....&.1P.....c..|
-00000330 18 f3 c2 b0 af d1 27 25 a9 ec ef 69 85 7a 72 c6 |......'%...i.zr.|
-00000340 b0 88 d2 c1 41 43 f4 69 62 25 13 eb f9 f8 16 03 |....AC.ib%......|
-00000350 03 00 2e 0d 00 00 26 03 01 02 40 00 1e 06 01 06 |......&... at .....|
-00000360 02 06 03 05 01 05 02 05 03 04 01 04 02 04 03 03 |................|
-00000370 01 03 02 03 03 02 01 02 02 02 03 00 00 0e 00 00 |................|
-00000380 00 |.|
+00000270 2a 16 03 03 00 b7 0c 00 00 b3 03 00 1d 20 18 6f |*............ .o|
+00000280 77 a5 2b 27 2c 52 fc 6c 8a 34 41 1c a8 c6 4f 90 |w.+',R.l.4A...O.|
+00000290 a9 4b b7 e0 39 8b b1 f5 a6 15 4b 94 e8 2c 04 03 |.K..9.....K..,..|
+000002a0 00 8b 30 81 88 02 42 00 dc 3a 14 a2 38 32 c1 40 |..0...B..:..82.@|
+000002b0 98 83 17 94 e9 2a 0d 95 c3 59 d6 76 94 c2 3e a0 |.....*...Y.v..>.|
+000002c0 f7 e0 5d 64 47 5a d1 d9 ed d2 1c 6b 13 3e e7 83 |..]dGZ.....k.>..|
+000002d0 6e bb 53 33 03 7d 69 c6 8f 9d 98 d7 96 9c 73 e3 |n.S3.}i.......s.|
+000002e0 12 bd 69 1f b1 d3 f4 25 d7 02 42 01 11 6d c8 53 |..i....%..B..m.S|
+000002f0 9b bf f4 db ff 8a 00 82 93 f7 b5 bf c9 bb cd ec |................|
+00000300 64 f8 d9 6d 36 0d f8 db ce 9d 65 a0 5e 5a e0 13 |d..m6.....e.^Z..|
+00000310 ec 08 73 2c 3f 8c c6 5b 08 cc 0f 4a 7d 6b 5e 89 |..s,?..[...J}k^.|
+00000320 bf 4a 4e db 51 5a 9f 51 3e 9d 9a c5 84 16 03 03 |.JN.QZ.Q>.......|
+00000330 00 2a 0d 00 00 26 03 01 02 40 00 1e 06 01 06 02 |.*...&... at ......|
+00000340 06 03 05 01 05 02 05 03 04 01 04 02 04 03 03 01 |................|
+00000350 03 02 03 03 02 01 02 02 02 03 00 00 16 03 03 00 |................|
+00000360 04 0e 00 00 00 |.....|
>>> Flow 3 (client to server)
00000000 16 03 03 02 0a 0b 00 02 06 00 02 03 00 02 00 30 |...............0|
00000010 82 01 fc 30 82 01 5e 02 09 00 9a 30 84 6c 26 35 |...0..^....0.l&5|
@@ -100,36 +99,34 @@
000001e0 be e8 91 b3 da 1a f5 5d a3 23 f5 26 8b 45 70 8d |.......].#.&.Ep.|
000001f0 65 62 9b 7e 01 99 3d 18 f6 10 9a 38 61 9b 2e 57 |eb.~..=....8a..W|
00000200 e4 fa cc b1 8a ce e2 23 a0 87 f0 e1 67 51 eb 16 |.......#....gQ..|
-00000210 03 03 00 46 10 00 00 42 41 04 1e 18 37 ef 0d 19 |...F...BA...7...|
-00000220 51 88 35 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd a7 |Q.5uq..T[....g..|
-00000230 24 20 3e b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e f1 |$ >.V...(^.+-O..|
-00000240 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 a6 |..lK[.V.2B.X..I.|
-00000250 b5 68 1a 41 03 56 6b dc 5a 89 16 03 03 00 93 0f |.h.A.Vk.Z.......|
-00000260 00 00 8f 05 03 00 8b 30 81 88 02 42 00 8a 82 c2 |.......0...B....|
-00000270 c0 30 8c a1 12 c4 4a ed d1 00 3f 2d ee bd 8e 9c |.0....J...?-....|
-00000280 a5 a0 d9 6f 44 27 49 60 e9 75 01 ee b4 0d 87 25 |...oD'I`.u.....%|
-00000290 2a 8d 67 f1 e3 d9 49 6f a0 34 90 76 93 52 f9 17 |*.g...Io.4.v.R..|
-000002a0 fb 1b cc d0 5a f4 50 37 9c 4c 44 b6 61 5f 02 42 |....Z.P7.LD.a_.B|
-000002b0 01 ad 85 38 e9 3a 69 35 ea 74 76 2c 09 6b ab d4 |...8.:i5.tv,.k..|
-000002c0 e0 dc d1 d5 03 41 22 8e 8b 53 98 b7 f1 b6 e9 29 |.....A"..S.....)|
-000002d0 d2 57 34 dc e0 b6 71 77 79 bd 57 61 7c 30 77 00 |.W4...qwy.Wa|0w.|
-000002e0 7a 42 2d 1f ed e8 14 da 16 33 c6 31 e4 3d 53 3a |zB-......3.1.=S:|
-000002f0 9a 37 14 03 03 00 01 01 16 03 03 00 40 00 00 00 |.7.......... at ...|
-00000300 00 00 00 00 00 00 00 00 00 00 00 00 00 d4 fe c1 |................|
-00000310 a6 fb 21 78 21 80 af 0d da a1 80 68 e2 9c ec 0b |..!x!......h....|
-00000320 57 8c 2a 7e f1 11 3b 52 ea 17 00 d1 d4 14 78 c5 |W.*~..;R......x.|
-00000330 81 39 12 ad 30 98 93 1b 29 77 45 7d 00 |.9..0...)wE}.|
+00000210 03 03 00 25 10 00 00 21 20 2f e5 7d a3 47 cd 62 |...%...! /.}.G.b|
+00000220 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af c4 cf |C.(.._.).0......|
+00000230 c2 ed 90 99 5f 58 cb 3b 74 16 03 03 00 93 0f 00 |...._X.;t.......|
+00000240 00 8f 05 03 00 8b 30 81 88 02 42 01 32 6d 32 38 |......0...B.2m28|
+00000250 d6 bd 1b b6 c5 80 f2 ea 60 b8 bf 3f b6 76 68 1b |........`..?.vh.|
+00000260 66 fb 5d 69 0b 25 09 7f 2d 73 ad 7e cd 98 cb b5 |f.]i.%..-s.~....|
+00000270 93 4e 4f 1c 4e 3f a1 39 cf a0 70 a6 3d 29 36 27 |.NO.N?.9..p.=)6'|
+00000280 51 e0 55 95 11 df 00 88 6c 38 d6 de 36 02 42 01 |Q.U.....l8..6.B.|
+00000290 67 50 81 90 a7 ae b5 e2 34 75 81 41 c2 71 8d 0c |gP......4u.A.q..|
+000002a0 9a 20 e7 33 af 0e 61 48 85 51 a1 f7 90 17 d1 ad |. .3..aH.Q......|
+000002b0 b3 e1 cf 3e 12 fc ce 39 16 a8 78 3b 69 0d 79 76 |...>...9..x;i.yv|
+000002c0 03 17 75 c2 a0 63 5e dc 0a a7 c9 aa 15 2a 83 65 |..u..c^......*.e|
+000002d0 df 14 03 03 00 01 01 16 03 03 00 40 00 00 00 00 |........... at ....|
+000002e0 00 00 00 00 00 00 00 00 00 00 00 00 27 da 48 f6 |............'.H.|
+000002f0 d3 00 98 b9 a6 b7 41 0b eb e6 d1 d7 82 9a 0c 59 |......A........Y|
+00000300 8a 42 1c 99 59 af da a7 5b 88 ab b6 7d 01 bc 0f |.B..Y...[...}...|
+00000310 45 08 c4 05 0d 2a 4a 83 bf eb b1 b6 |E....*J.....|
>>> Flow 4 (server to client)
-00000000 14 03 03 00 01 01 16 03 03 00 40 f7 0a 50 d0 87 |.......... at ..P..|
-00000010 fb f9 be b0 6b 8d 9b a5 8b d2 56 27 67 7d 3c 51 |....k.....V'g}<Q|
-00000020 af 53 8c 7d 61 9f 12 a5 54 5d ec 56 36 31 01 73 |.S.}a...T].V61.s|
-00000030 37 cb 5f ff 36 3c 1c 4a e3 db ec 99 bc 86 15 e4 |7._.6<.J........|
-00000040 cd 5d 87 bd d7 80 c7 b1 fe 42 9f |.].......B.|
+00000000 14 03 03 00 01 01 16 03 03 00 40 73 7c e6 43 b9 |.......... at s|.C.|
+00000010 47 85 1c 50 f1 cb a1 29 79 02 dd 13 85 2a d9 a2 |G..P...)y....*..|
+00000020 07 50 e4 80 c4 7e 66 ee f2 1a 21 1d cd e4 ff 4a |.P...~f...!....J|
+00000030 a4 61 9d b4 a1 26 88 72 20 2b 06 77 c3 8b 3b 21 |.a...&.r +.w..;!|
+00000040 53 33 02 3d a2 06 77 3b a5 a6 0b |S3.=..w;...|
>>> Flow 5 (client to server)
00000000 17 03 03 00 30 00 00 00 00 00 00 00 00 00 00 00 |....0...........|
-00000010 00 00 00 00 00 ef 81 cf 63 f1 b5 6b b2 30 6f 00 |........c..k.0o.|
-00000020 0e c0 0c 5d d4 85 76 d2 30 db 6b 14 06 e4 75 0b |...]..v.0.k...u.|
-00000030 cf fc 72 aa 64 15 03 03 00 30 00 00 00 00 00 00 |..r.d....0......|
-00000040 00 00 00 00 00 00 00 00 00 00 ef 28 8a e7 15 51 |...........(...Q|
-00000050 0d 0d 27 4f 36 35 f6 43 28 d2 16 dc a3 35 33 3e |..'O65.C(....53>|
-00000060 be 80 db 31 a9 89 3d 17 c2 58 |...1..=..X|
+00000010 00 00 00 00 00 1a 45 68 03 9b f0 42 e4 21 5e d8 |......Eh...B.!^.|
+00000020 98 d6 46 67 2b 93 80 92 1f 91 60 a3 05 04 1c a0 |..Fg+.....`.....|
+00000030 1b a9 ce 45 03 15 03 03 00 30 00 00 00 00 00 00 |...E.....0......|
+00000040 00 00 00 00 00 00 00 00 00 00 6b 23 42 c8 5c 29 |..........k#B.\)|
+00000050 f5 1f 7c d5 80 c4 9f 6f 12 77 95 71 8f 82 f9 63 |..|....o.w.q...c|
+00000060 07 2c 6d ed 6d c6 4f 90 50 a3 |.,m.m.O.P.|
diff --git a/src/crypto/tls/testdata/Client-TLSv12-ClientCert-ECDSA-RSA b/src/crypto/tls/testdata/Client-TLSv12-ClientCert-ECDSA-RSA
index 53f2f86..fb6c940 100644
--- a/src/crypto/tls/testdata/Client-TLSv12-ClientCert-ECDSA-RSA
+++ b/src/crypto/tls/testdata/Client-TLSv12-ClientCert-ECDSA-RSA
@@ -1,62 +1,74 @@
>>> Flow 1 (client to server)
-00000000 16 03 01 00 85 01 00 00 81 03 03 00 00 00 00 00 |................|
+00000000 16 03 01 00 91 01 00 00 8d 03 03 00 00 00 00 00 |................|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
-00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 22 c0 2f |............."./|
-00000030 c0 2b c0 30 c0 2c c0 11 c0 07 c0 13 c0 09 c0 14 |.+.0.,..........|
-00000040 c0 0a 00 9c 00 9d 00 05 00 2f 00 35 c0 12 00 0a |........./.5....|
-00000050 01 00 00 36 00 05 00 05 01 00 00 00 00 00 0a 00 |...6............|
-00000060 08 00 06 00 17 00 18 00 19 00 0b 00 02 01 00 00 |................|
-00000070 0d 00 0e 00 0c 04 01 04 03 05 01 05 03 02 01 02 |................|
-00000080 03 ff 01 00 01 00 00 12 00 00 |..........|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2c cc a8 |.............,..|
+00000030 cc a9 c0 2f c0 2b c0 30 c0 2c c0 27 c0 13 c0 23 |.../.+.0.,.'...#|
+00000040 c0 09 c0 14 c0 0a 00 9c 00 9d 00 3c 00 2f 00 35 |...........<./.5|
+00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 38 00 05 |.............8..|
+00000060 00 05 01 00 00 00 00 00 0a 00 0a 00 08 00 1d 00 |................|
+00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 0e 00 |................|
+00000080 0c 04 01 04 03 05 01 05 03 02 01 02 03 ff 01 00 |................|
+00000090 01 00 00 12 00 00 |......|
>>> Flow 2 (server to client)
-00000000 16 03 03 00 51 02 00 00 4d 03 03 e8 b5 19 bd df |....Q...M.......|
-00000010 e5 18 78 4b 01 f1 3f 7f ab 91 05 78 98 77 50 bf |..xK..?....x.wP.|
-00000020 60 f5 a4 76 7b 3c 40 9f 54 56 68 20 a1 99 57 a7 |`..v{<@.TVh ..W.|
-00000030 a8 46 ca 26 22 d8 bb 8d 93 12 48 ff be 8e d3 d4 |.F.&".....H.....|
-00000040 e0 fd cd ce f5 d9 a9 2e fe d4 cd 85 00 05 00 00 |................|
-00000050 05 ff 01 00 01 00 16 03 03 02 71 0b 00 02 6d 00 |..........q...m.|
-00000060 02 6a 00 02 67 30 82 02 63 30 82 01 cc a0 03 02 |.j..g0..c0......|
-00000070 01 02 02 09 00 a2 73 00 0c 81 00 cb f3 30 0d 06 |......s......0..|
-00000080 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 2b 31 17 |.*.H........0+1.|
-00000090 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 |0...U....Google |
-000000a0 54 45 53 54 49 4e 47 31 10 30 0e 06 03 55 04 03 |TESTING1.0...U..|
-000000b0 13 07 47 6f 20 52 6f 6f 74 30 1e 17 0d 31 35 30 |..Go Root0...150|
-000000c0 31 30 31 30 30 30 30 30 30 5a 17 0d 32 35 30 31 |101000000Z..2501|
-000000d0 30 31 30 30 30 30 30 30 5a 30 26 31 17 30 15 06 |01000000Z0&1.0..|
-000000e0 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 54 45 53 |.U....Google TES|
-000000f0 54 49 4e 47 31 0b 30 09 06 03 55 04 03 13 02 47 |TING1.0...U....G|
-00000100 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....|
-00000110 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 af 87 |.......0........|
-00000120 88 f6 20 1b 95 65 6c 14 ab 44 05 af 3b 45 14 e3 |.. ..el..D..;E..|
-00000130 b7 6d fd 00 63 4d 95 7f fe 6a 62 35 86 c0 4a f9 |.m..cM...jb5..J.|
-00000140 18 7c f6 aa 25 5e 7a 64 31 66 00 ba f4 8e 92 af |.|..%^zd1f......|
-00000150 c7 6b d8 76 d4 f3 5f 41 cb 6e 56 15 97 1b 97 c1 |.k.v.._A.nV.....|
-00000160 3c 12 39 21 66 3d 2b 16 d1 bc db 1c c0 a7 da b7 |<.9!f=+.........|
-00000170 ca ad ba da cb d5 21 50 ec de 8d ab d1 6b 81 4b |......!P.....k.K|
-00000180 89 02 f3 c4 be c1 6c 89 b1 44 84 bd 21 d1 04 7d |......l..D..!..}|
-00000190 9d 16 4d f9 82 15 f6 ef fa d6 09 47 f2 fb 02 03 |..M........G....|
-000001a0 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..|
-000001b0 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%|
-000001c0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........|
-000001d0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...|
-000001e0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....|
-000001f0 10 12 50 8d 89 6f 1b d1 dc 54 4d 6e cb 69 5e 06 |..P..o...TMn.i^.|
-00000200 f4 30 1b 06 03 55 1d 23 04 14 30 12 80 10 bf 3d |.0...U.#..0....=|
-00000210 b6 a9 66 f2 b8 40 cf ea b4 03 78 48 1a 41 30 19 |..f.. at ....xH.A0.|
-00000220 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp|
-00000230 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H|
-00000240 86 f7 0d 01 01 0b 05 00 03 81 81 00 92 7c af 91 |.............|..|
-00000250 55 12 18 96 59 31 a6 48 40 d5 2d d5 ee bb 02 a0 |U...Y1.H at .-.....|
-00000260 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 da 4f 3d c0 fa |...|..0}<.v.O=..|
-00000270 ae 2d 33 24 6b 03 7b 1b 67 59 11 21 b5 11 bc 77 |.-3$k.{.gY.!...w|
-00000280 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f 22 3e 63 10 6b |...n.-.5.d_">c.k|
-00000290 be ff 14 86 6d 0d f0 15 31 a8 14 38 1e 3b 84 87 |....m...1..8.;..|
-000002a0 2c cb 98 ed 51 76 b9 b1 4f dd db 9b 84 04 86 40 |,...Qv..O......@|
-000002b0 fa 51 dd ba b4 8d eb e3 46 de 46 b9 4f 86 c7 f9 |.Q......F.F.O...|
-000002c0 a4 c2 41 34 ac cc f6 ea b0 ab 39 18 16 03 03 00 |..A4......9.....|
-000002d0 2e 0d 00 00 26 03 01 02 40 00 1e 06 01 06 02 06 |....&... at .......|
-000002e0 03 05 01 05 02 05 03 04 01 04 02 04 03 03 01 03 |................|
-000002f0 02 03 03 02 01 02 02 02 03 00 00 0e 00 00 00 |...............|
+00000000 16 03 03 00 59 02 00 00 55 03 03 2e d2 1c 3f f8 |....Y...U.....?.|
+00000010 3a dc be 78 0b fa 03 00 e0 9a b9 62 34 45 f8 34 |:..x.......b4E.4|
+00000020 54 21 4c c0 76 a6 e1 5a a1 67 c2 20 1b 98 25 34 |T!L.v..Z.g. ..%4|
+00000030 79 ac 59 b5 39 c8 93 10 a9 ea 9d 25 3d 2c d8 69 |y.Y.9......%=,.i|
+00000040 da d8 33 75 ef 44 4c 76 92 2b 3b b4 c0 2f 00 00 |..3u.DLv.+;../..|
+00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................|
+00000060 03 02 59 0b 00 02 55 00 02 52 00 02 4f 30 82 02 |..Y...U..R..O0..|
+00000070 4b 30 82 01 b4 a0 03 02 01 02 02 09 00 e8 f0 9d |K0..............|
+00000080 3f e2 5b ea a6 30 0d 06 09 2a 86 48 86 f7 0d 01 |?.[..0...*.H....|
+00000090 01 0b 05 00 30 1f 31 0b 30 09 06 03 55 04 0a 13 |....0.1.0...U...|
+000000a0 02 47 6f 31 10 30 0e 06 03 55 04 03 13 07 47 6f |.Go1.0...U....Go|
+000000b0 20 52 6f 6f 74 30 1e 17 0d 31 36 30 31 30 31 30 | Root0...1601010|
+000000c0 30 30 30 30 30 5a 17 0d 32 35 30 31 30 31 30 30 |00000Z..25010100|
+000000d0 30 30 30 30 5a 30 1a 31 0b 30 09 06 03 55 04 0a |0000Z0.1.0...U..|
+000000e0 13 02 47 6f 31 0b 30 09 06 03 55 04 03 13 02 47 |..Go1.0...U....G|
+000000f0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....|
+00000100 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 db 46 |.......0.......F|
+00000110 7d 93 2e 12 27 06 48 bc 06 28 21 ab 7e c4 b6 a2 |}...'.H..(!.~...|
+00000120 5d fe 1e 52 45 88 7a 36 47 a5 08 0d 92 42 5b c2 |]..RE.z6G....B[.|
+00000130 81 c0 be 97 79 98 40 fb 4f 6d 14 fd 2b 13 8b c2 |....y. at .Om..+...|
+00000140 a5 2e 67 d8 d4 09 9e d6 22 38 b7 4a 0b 74 73 2b |..g....."8.J.ts+|
+00000150 c2 34 f1 d1 93 e5 96 d9 74 7b f3 58 9f 6c 61 3c |.4......t{.X.la<|
+00000160 c0 b0 41 d4 d9 2b 2b 24 23 77 5b 1c 3b bd 75 5d |..A..++$#w[.;.u]|
+00000170 ce 20 54 cf a1 63 87 1d 1e 24 c4 f3 1d 1a 50 8b |. T..c...$....P.|
+00000180 aa b6 14 43 ed 97 a7 75 62 f4 14 c8 52 d7 02 03 |...C...ub...R...|
+00000190 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..|
+000001a0 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%|
+000001b0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........|
+000001c0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...|
+000001d0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....|
+000001e0 10 9f 91 16 1f 43 43 3e 49 a6 de 6d b6 80 d7 9f |.....CC>I..m....|
+000001f0 60 30 1b 06 03 55 1d 23 04 14 30 12 80 10 48 13 |`0...U.#..0...H.|
+00000200 49 4d 13 7e 16 31 bb a3 01 d5 ac ab 6e 7b 30 19 |IM.~.1......n{0.|
+00000210 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp|
+00000220 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H|
+00000230 86 f7 0d 01 01 0b 05 00 03 81 81 00 9d 30 cc 40 |.............0.@|
+00000240 2b 5b 50 a0 61 cb ba e5 53 58 e1 ed 83 28 a9 58 |+[P.a...SX...(.X|
+00000250 1a a9 38 a4 95 a1 ac 31 5a 1a 84 66 3d 43 d3 2d |..8....1Z..f=C.-|
+00000260 d9 0b f2 97 df d3 20 64 38 92 24 3a 00 bc cf 9c |...... d8.$:....|
+00000270 7d b7 40 20 01 5f aa d3 16 61 09 a2 76 fd 13 c3 |}.@ ._...a..v...|
+00000280 cc e1 0c 5c ee b1 87 82 f1 6c 04 ed 73 bb b3 43 |...\.....l..s..C|
+00000290 77 8d 0c 1c f1 0f a1 d8 40 83 61 c9 4c 72 2b 9d |w....... at .a.Lr+.|
+000002a0 ae db 46 06 06 4d f4 c1 b3 3e c0 d1 bd 42 d4 db |..F..M...>...B..|
+000002b0 fe 3d 13 60 84 5c 21 d3 3b e9 fa e7 16 03 03 00 |.=.`.\!.;.......|
+000002c0 ac 0c 00 00 a8 03 00 1d 20 06 be 1b 0b d8 95 59 |........ ......Y|
+000002d0 b2 13 1c 4a 06 b8 36 3e 4f 98 3f 81 11 3e 7d 21 |...J..6>O.?..>}!|
+000002e0 fa d9 f0 db 1b 41 4a d0 14 04 01 00 80 ca 57 f5 |.....AJ.......W.|
+000002f0 e7 b6 72 7e 3f b0 67 f2 a2 d0 84 d5 7f 7d 83 ff |..r~?.g......}..|
+00000300 92 73 4f 19 f7 94 b6 d7 95 f4 1b 56 2a fc fa 24 |.sO........V*..$|
+00000310 3e fe 00 65 52 76 c8 30 8a bf ae fe b5 c9 f2 47 |>..eRv.0.......G|
+00000320 0a 71 ad c1 6a 61 8c b5 ab 59 09 12 92 b2 b4 ad |.q..ja...Y......|
+00000330 cb cc ac c4 30 e9 a4 8a 82 4e 2e d6 1d 16 46 dd |....0....N....F.|
+00000340 60 37 50 b8 ae 83 c1 e6 1d ba 8c c7 18 f7 5e d7 |`7P...........^.|
+00000350 23 e5 8a 14 ba e4 8e a1 77 8a b6 41 03 61 8a 25 |#.......w..A.a.%|
+00000360 8a 27 f8 cb 2e 4a e0 07 aa bf 03 32 98 16 03 03 |.'...J.....2....|
+00000370 00 2a 0d 00 00 26 03 01 02 40 00 1e 06 01 06 02 |.*...&... at ......|
+00000380 06 03 05 01 05 02 05 03 04 01 04 02 04 03 03 01 |................|
+00000390 03 02 03 03 02 01 02 02 02 03 00 00 16 03 03 00 |................|
+000003a0 04 0e 00 00 00 |.....|
>>> Flow 3 (client to server)
00000000 16 03 03 02 0a 0b 00 02 06 00 02 03 00 02 00 30 |...............0|
00000010 82 01 fc 30 82 01 5e 02 09 00 9a 30 84 6c 26 35 |...0..^....0.l&5|
@@ -91,33 +103,30 @@
000001e0 be e8 91 b3 da 1a f5 5d a3 23 f5 26 8b 45 70 8d |.......].#.&.Ep.|
000001f0 65 62 9b 7e 01 99 3d 18 f6 10 9a 38 61 9b 2e 57 |eb.~..=....8a..W|
00000200 e4 fa cc b1 8a ce e2 23 a0 87 f0 e1 67 51 eb 16 |.......#....gQ..|
-00000210 03 03 00 86 10 00 00 82 00 80 73 bd 73 65 92 86 |..........s.se..|
-00000220 23 41 14 79 7f d5 c1 10 ce 94 4d ad 9c c3 a9 87 |#A.y......M.....|
-00000230 b5 32 52 f8 6b 11 93 2d 9b 98 0b 8b 1d c0 f6 53 |.2R.k..-.......S|
-00000240 17 6d c7 9c 2e ae c9 6f cc 99 23 38 37 1a 10 fe |.m.....o..#87...|
-00000250 05 0b b5 55 0a 14 e9 60 7d 70 26 98 e2 54 d9 65 |...U...`}p&..T.e|
-00000260 cf 2e f4 53 5f 1d aa 3a f6 33 7b eb 4c 0e b3 ff |...S_..:.3{.L...|
-00000270 5a db 36 2a 47 f3 df f9 fc f5 31 78 83 aa 6b 52 |Z.6*G.....1x..kR|
-00000280 b7 ba 1a 96 bc fa c1 a1 a9 bb 2b f5 38 89 00 4d |..........+.8..M|
-00000290 e5 78 13 4e a4 38 46 42 dc 16 16 03 03 00 92 0f |.x.N.8FB........|
-000002a0 00 00 8e 05 03 00 8a 30 81 87 02 42 01 4c f6 31 |.......0...B.L.1|
-000002b0 4f ec 64 bb ce d0 96 4d 66 f3 8d 64 78 c9 2d 47 |O.d....Mf..dx.-G|
-000002c0 39 02 88 31 49 84 7f cc a8 af c1 17 35 fb 46 b1 |9..1I.......5.F.|
-000002d0 dc 07 58 71 13 6b 8e 71 2b 94 fd 41 7c 26 45 39 |..Xq.k.q+..A|&E9|
-000002e0 28 b1 aa f7 5b 89 04 de 84 d1 b5 d9 9f f3 02 41 |(...[..........A|
-000002f0 4e f6 2a ed 39 ee 63 68 da f5 ae 1b 4d f5 01 0f |N.*.9.ch....M...|
-00000300 bc f7 05 d2 96 42 67 e3 8f ff 27 d5 bf c4 53 bf |.....Bg...'...S.|
-00000310 8a d7 46 58 05 54 94 d8 73 a9 d9 38 40 5f cb 8c |..FX.T..s..8 at _..|
-00000320 c7 d1 94 56 2a e1 61 32 29 f7 c9 c1 e8 95 30 e3 |...V*.a2).....0.|
-00000330 33 14 03 03 00 01 01 16 03 03 00 24 b1 86 d2 50 |3..........$...P|
-00000340 fc ea 68 b1 d9 3d b7 2c fd 2c 87 f0 d4 44 2b 22 |..h..=.,.,...D+"|
-00000350 b8 47 74 77 46 14 6d 18 b3 08 9c 3a d4 a1 ba cb |.GtwF.m....:....|
+00000210 03 03 00 25 10 00 00 21 20 2f e5 7d a3 47 cd 62 |...%...! /.}.G.b|
+00000220 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af c4 cf |C.(.._.).0......|
+00000230 c2 ed 90 99 5f 58 cb 3b 74 16 03 03 00 92 0f 00 |...._X.;t.......|
+00000240 00 8e 05 03 00 8a 30 81 87 02 41 19 c6 1e f0 f4 |......0...A.....|
+00000250 ca 79 d7 8c 36 0f 56 9a 9d 07 55 31 fe 63 f1 ec |.y..6.V...U1.c..|
+00000260 20 80 6f 12 ed 7f bb c0 87 0a 0d 68 81 89 bd 8b | .o........h....|
+00000270 19 04 5e c0 19 8a d2 0f 6d 71 83 59 ee a7 be be |..^.....mq.Y....|
+00000280 1d bb 2f 12 53 9b ca 58 0e a6 8d ae 02 42 00 d0 |../.S..X.....B..|
+00000290 4c 69 75 30 86 d1 da 73 1b 8e 3e e1 82 9b f3 58 |Liu0...s..>....X|
+000002a0 8f 6d 0a 10 86 72 5f 90 17 d1 ac 34 8a b5 60 d0 |.m...r_....4..`.|
+000002b0 b8 54 0f 05 7f cd 6a c0 62 b5 04 d9 3a 98 95 b6 |.T....j.b...:...|
+000002c0 b3 00 1d 94 6e 79 35 57 d2 78 a4 7a 4a 45 89 d1 |....ny5W.x.zJE..|
+000002d0 14 03 03 00 01 01 16 03 03 00 28 00 00 00 00 00 |..........(.....|
+000002e0 00 00 00 cf b5 3c cf 0a b7 6b 51 cb fe 06 4c df |.....<...kQ...L.|
+000002f0 2c 79 a6 5e a8 75 8b 4c 44 7b ae ff 64 d7 67 dc |,y.^.u.LD{..d.g.|
+00000300 af ef 54 |..T|
>>> Flow 4 (server to client)
-00000000 14 03 03 00 01 01 16 03 03 00 24 70 c7 ee d4 d3 |..........$p....|
-00000010 d3 ad dc 5a d1 a3 01 89 4d ae 0f b9 7b 97 91 4a |...Z....M...{..J|
-00000020 c0 5b e2 94 ef 5f 2f e0 90 1a 18 8a e8 50 9d |.[..._/......P.|
+00000000 14 03 03 00 01 01 16 03 03 00 28 1c 12 5e 29 ba |..........(..^).|
+00000010 34 b3 d8 ae f7 2a 83 0d 3e 21 ec 91 c9 fa 7f d1 |4....*..>!......|
+00000020 42 7e 8d d9 e5 ed 4e f9 ae 95 66 27 85 cc 44 2d |B~....N...f'..D-|
+00000030 cd a3 26 |..&|
>>> Flow 5 (client to server)
-00000000 17 03 03 00 1a e8 e8 00 30 71 09 61 65 55 90 c8 |........0q.aeU..|
-00000010 d6 fd 8d 5d a9 fb e6 2b d4 45 a9 8c ea 2f 0b 15 |...]...+.E.../..|
-00000020 03 03 00 16 f2 d3 36 ce 26 42 59 1b d7 15 c5 c4 |......6.&BY.....|
-00000030 8b 0b 06 0a d0 fd 78 62 3d 39 |......xb=9|
+00000000 17 03 03 00 1e 00 00 00 00 00 00 00 01 8b 4c 36 |..............L6|
+00000010 6f b8 69 16 0a 40 67 05 5e a8 e6 48 cc ad 7b 29 |o.i.. at g.^..H..{)|
+00000020 95 3d 02 15 03 03 00 1a 00 00 00 00 00 00 00 02 |.=..............|
+00000030 58 e3 b5 8e 30 e7 5d 02 cd e5 c0 11 95 3a ef a9 |X...0.]......:..|
+00000040 d7 86 |..|
diff --git a/src/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-AES256-GCM-SHA384 b/src/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-AES256-GCM-SHA384
index 9ba51f5..17fc8f8 100644
--- a/src/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-AES256-GCM-SHA384
+++ b/src/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-AES256-GCM-SHA384
@@ -1,134 +1,130 @@
>>> Flow 1 (client to server)
-00000000 16 03 01 00 85 01 00 00 81 03 03 00 00 00 00 00 |................|
+00000000 16 03 01 00 91 01 00 00 8d 03 03 00 00 00 00 00 |................|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
-00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 22 c0 2f |............."./|
-00000030 c0 2b c0 30 c0 2c c0 11 c0 07 c0 13 c0 09 c0 14 |.+.0.,..........|
-00000040 c0 0a 00 9c 00 9d 00 05 00 2f 00 35 c0 12 00 0a |........./.5....|
-00000050 01 00 00 36 00 05 00 05 01 00 00 00 00 00 0a 00 |...6............|
-00000060 08 00 06 00 17 00 18 00 19 00 0b 00 02 01 00 00 |................|
-00000070 0d 00 0e 00 0c 04 01 04 03 05 01 05 03 02 01 02 |................|
-00000080 03 ff 01 00 01 00 00 12 00 00 |..........|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2c cc a8 |.............,..|
+00000030 cc a9 c0 2f c0 2b c0 30 c0 2c c0 27 c0 13 c0 23 |.../.+.0.,.'...#|
+00000040 c0 09 c0 14 c0 0a 00 9c 00 9d 00 3c 00 2f 00 35 |...........<./.5|
+00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 38 00 05 |.............8..|
+00000060 00 05 01 00 00 00 00 00 0a 00 0a 00 08 00 1d 00 |................|
+00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 0e 00 |................|
+00000080 0c 04 01 04 03 05 01 05 03 02 01 02 03 ff 01 00 |................|
+00000090 01 00 00 12 00 00 |......|
>>> Flow 2 (server to client)
-00000000 16 03 03 00 59 02 00 00 55 03 03 f5 6d a6 9a 3d |....Y...U...m..=|
-00000010 b4 32 c7 59 b9 f7 09 bb 56 7e 06 26 02 ac eb dd |.2.Y....V~.&....|
-00000020 78 91 e4 cd f9 f4 e7 98 7f 13 f0 20 6d d5 42 4a |x.......... m.BJ|
-00000030 85 ac 86 9a a6 78 6d 5c d7 ef 9d 16 dc ff 5a 41 |.....xm\......ZA|
-00000040 91 5a 54 ff ba f6 90 f4 2a 4f fd 37 c0 30 00 00 |.ZT.....*O.7.0..|
+00000000 16 03 03 00 59 02 00 00 55 03 03 31 df 35 e4 36 |....Y...U..1.5.6|
+00000010 c5 f1 b4 9f e7 5d fa e1 e0 23 04 54 bd 2b fb ab |.....]...#.T.+..|
+00000020 a2 37 8f 35 eb 79 47 e6 f8 2b cb 20 ba d8 db 26 |.7.5.yG..+. ...&|
+00000030 ce 6b 4a e9 1e 0c 46 9f 4d 85 cb d7 b0 e2 3d 20 |.kJ...F.M.....= |
+00000040 58 43 83 37 e1 53 ac 3b d9 b3 fd 0a c0 30 00 00 |XC.7.S.;.....0..|
00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................|
-00000060 03 02 71 0b 00 02 6d 00 02 6a 00 02 67 30 82 02 |..q...m..j..g0..|
-00000070 63 30 82 01 cc a0 03 02 01 02 02 09 00 a2 73 00 |c0............s.|
-00000080 0c 81 00 cb f3 30 0d 06 09 2a 86 48 86 f7 0d 01 |.....0...*.H....|
-00000090 01 0b 05 00 30 2b 31 17 30 15 06 03 55 04 0a 13 |....0+1.0...U...|
-000000a0 0e 47 6f 6f 67 6c 65 20 54 45 53 54 49 4e 47 31 |.Google TESTING1|
-000000b0 10 30 0e 06 03 55 04 03 13 07 47 6f 20 52 6f 6f |.0...U....Go Roo|
-000000c0 74 30 1e 17 0d 31 35 30 31 30 31 30 30 30 30 30 |t0...15010100000|
-000000d0 30 5a 17 0d 32 35 30 31 30 31 30 30 30 30 30 30 |0Z..250101000000|
-000000e0 5a 30 26 31 17 30 15 06 03 55 04 0a 13 0e 47 6f |Z0&1.0...U....Go|
-000000f0 6f 67 6c 65 20 54 45 53 54 49 4e 47 31 0b 30 09 |ogle TESTING1.0.|
-00000100 06 03 55 04 03 13 02 47 6f 30 81 9f 30 0d 06 09 |..U....Go0..0...|
-00000110 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 30 |*.H............0|
-00000120 81 89 02 81 81 00 af 87 88 f6 20 1b 95 65 6c 14 |.......... ..el.|
-00000130 ab 44 05 af 3b 45 14 e3 b7 6d fd 00 63 4d 95 7f |.D..;E...m..cM..|
-00000140 fe 6a 62 35 86 c0 4a f9 18 7c f6 aa 25 5e 7a 64 |.jb5..J..|..%^zd|
-00000150 31 66 00 ba f4 8e 92 af c7 6b d8 76 d4 f3 5f 41 |1f.......k.v.._A|
-00000160 cb 6e 56 15 97 1b 97 c1 3c 12 39 21 66 3d 2b 16 |.nV.....<.9!f=+.|
-00000170 d1 bc db 1c c0 a7 da b7 ca ad ba da cb d5 21 50 |..............!P|
-00000180 ec de 8d ab d1 6b 81 4b 89 02 f3 c4 be c1 6c 89 |.....k.K......l.|
-00000190 b1 44 84 bd 21 d1 04 7d 9d 16 4d f9 82 15 f6 ef |.D..!..}..M.....|
-000001a0 fa d6 09 47 f2 fb 02 03 01 00 01 a3 81 93 30 81 |...G..........0.|
-000001b0 90 30 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 05 |.0...U..........|
-000001c0 a0 30 1d 06 03 55 1d 25 04 16 30 14 06 08 2b 06 |.0...U.%..0...+.|
-000001d0 01 05 05 07 03 01 06 08 2b 06 01 05 05 07 03 02 |........+.......|
-000001e0 30 0c 06 03 55 1d 13 01 01 ff 04 02 30 00 30 19 |0...U.......0.0.|
-000001f0 06 03 55 1d 0e 04 12 04 10 12 50 8d 89 6f 1b d1 |..U.......P..o..|
-00000200 dc 54 4d 6e cb 69 5e 06 f4 30 1b 06 03 55 1d 23 |.TMn.i^..0...U.#|
-00000210 04 14 30 12 80 10 bf 3d b6 a9 66 f2 b8 40 cf ea |..0....=..f.. at ..|
-00000220 b4 03 78 48 1a 41 30 19 06 03 55 1d 11 04 12 30 |..xH.A0...U....0|
-00000230 10 82 0e 65 78 61 6d 70 6c 65 2e 67 6f 6c 61 6e |...example.golan|
-00000240 67 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 |g0...*.H........|
-00000250 03 81 81 00 92 7c af 91 55 12 18 96 59 31 a6 48 |.....|..U...Y1.H|
-00000260 40 d5 2d d5 ee bb 02 a0 f5 c2 1e 7c 9b b3 30 7d |@.-........|..0}|
-00000270 3c dc 76 da 4f 3d c0 fa ae 2d 33 24 6b 03 7b 1b |<.v.O=...-3$k.{.|
-00000280 67 59 11 21 b5 11 bc 77 b9 d9 e0 6e a8 2d 2e 35 |gY.!...w...n.-.5|
-00000290 fa 64 5f 22 3e 63 10 6b be ff 14 86 6d 0d f0 15 |.d_">c.k....m...|
-000002a0 31 a8 14 38 1e 3b 84 87 2c cb 98 ed 51 76 b9 b1 |1..8.;..,...Qv..|
-000002b0 4f dd db 9b 84 04 86 40 fa 51 dd ba b4 8d eb e3 |O...... at .Q......|
-000002c0 46 de 46 b9 4f 86 c7 f9 a4 c2 41 34 ac cc f6 ea |F.F.O.....A4....|
-000002d0 b0 ab 39 18 16 03 03 00 cd 0c 00 00 c9 03 00 17 |..9.............|
-000002e0 41 04 2a 2a b7 63 a8 8e 34 67 32 18 57 6e fe 2a |A.**.c..4g2.Wn.*|
-000002f0 51 41 41 5f 65 a3 a7 e9 d6 0b 42 7f 77 fb 40 09 |QAA_e.....B.w. at .|
-00000300 c8 7a a2 9b fd 5f 6e 2b ce 85 f6 24 c2 8d e8 bb |.z..._n+...$....|
-00000310 69 3e dc 51 15 6f a8 db a4 fb 11 10 70 04 82 6a |i>.Q.o......p..j|
-00000320 7b 81 04 01 00 80 7a a3 c9 1b e6 02 33 39 55 36 |{.....z.....39U6|
-00000330 dc f9 2d f7 00 5b 8d f4 de 7a f7 3b 1b 4c 9a 27 |..-..[...z.;.L.'|
-00000340 f6 db 3c d1 6b f8 d6 7a 20 53 33 5f 88 9f f6 73 |..<.k..z S3_...s|
-00000350 90 2f 35 9e f6 05 b5 80 96 4f c8 85 e6 72 95 ba |./5......O...r..|
-00000360 3b 42 43 94 c3 0b db 91 ff 6b 24 c6 b1 78 de 18 |;BC......k$..x..|
-00000370 9f d5 3b 33 53 22 45 bf cb b2 d2 77 ce 03 56 7b |..;3S"E....w..V{|
-00000380 b7 56 b6 ec 04 64 62 04 f7 f8 52 1a 47 49 01 71 |.V...db...R.GI.q|
-00000390 29 9e ee 68 1f e9 c6 36 fb 77 4c 9a 14 90 e1 70 |)..h...6.wL....p|
-000003a0 7d 7e 77 92 a6 18 16 03 03 00 2e 0d 00 00 26 03 |}~w...........&.|
-000003b0 01 02 40 00 1e 06 01 06 02 06 03 05 01 05 02 05 |.. at .............|
-000003c0 03 04 01 04 02 04 03 03 01 03 02 03 03 02 01 02 |................|
-000003d0 02 02 03 00 00 0e 00 00 00 |.........|
+00000060 03 02 59 0b 00 02 55 00 02 52 00 02 4f 30 82 02 |..Y...U..R..O0..|
+00000070 4b 30 82 01 b4 a0 03 02 01 02 02 09 00 e8 f0 9d |K0..............|
+00000080 3f e2 5b ea a6 30 0d 06 09 2a 86 48 86 f7 0d 01 |?.[..0...*.H....|
+00000090 01 0b 05 00 30 1f 31 0b 30 09 06 03 55 04 0a 13 |....0.1.0...U...|
+000000a0 02 47 6f 31 10 30 0e 06 03 55 04 03 13 07 47 6f |.Go1.0...U....Go|
+000000b0 20 52 6f 6f 74 30 1e 17 0d 31 36 30 31 30 31 30 | Root0...1601010|
+000000c0 30 30 30 30 30 5a 17 0d 32 35 30 31 30 31 30 30 |00000Z..25010100|
+000000d0 30 30 30 30 5a 30 1a 31 0b 30 09 06 03 55 04 0a |0000Z0.1.0...U..|
+000000e0 13 02 47 6f 31 0b 30 09 06 03 55 04 03 13 02 47 |..Go1.0...U....G|
+000000f0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....|
+00000100 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 db 46 |.......0.......F|
+00000110 7d 93 2e 12 27 06 48 bc 06 28 21 ab 7e c4 b6 a2 |}...'.H..(!.~...|
+00000120 5d fe 1e 52 45 88 7a 36 47 a5 08 0d 92 42 5b c2 |]..RE.z6G....B[.|
+00000130 81 c0 be 97 79 98 40 fb 4f 6d 14 fd 2b 13 8b c2 |....y. at .Om..+...|
+00000140 a5 2e 67 d8 d4 09 9e d6 22 38 b7 4a 0b 74 73 2b |..g....."8.J.ts+|
+00000150 c2 34 f1 d1 93 e5 96 d9 74 7b f3 58 9f 6c 61 3c |.4......t{.X.la<|
+00000160 c0 b0 41 d4 d9 2b 2b 24 23 77 5b 1c 3b bd 75 5d |..A..++$#w[.;.u]|
+00000170 ce 20 54 cf a1 63 87 1d 1e 24 c4 f3 1d 1a 50 8b |. T..c...$....P.|
+00000180 aa b6 14 43 ed 97 a7 75 62 f4 14 c8 52 d7 02 03 |...C...ub...R...|
+00000190 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..|
+000001a0 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%|
+000001b0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........|
+000001c0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...|
+000001d0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....|
+000001e0 10 9f 91 16 1f 43 43 3e 49 a6 de 6d b6 80 d7 9f |.....CC>I..m....|
+000001f0 60 30 1b 06 03 55 1d 23 04 14 30 12 80 10 48 13 |`0...U.#..0...H.|
+00000200 49 4d 13 7e 16 31 bb a3 01 d5 ac ab 6e 7b 30 19 |IM.~.1......n{0.|
+00000210 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp|
+00000220 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H|
+00000230 86 f7 0d 01 01 0b 05 00 03 81 81 00 9d 30 cc 40 |.............0.@|
+00000240 2b 5b 50 a0 61 cb ba e5 53 58 e1 ed 83 28 a9 58 |+[P.a...SX...(.X|
+00000250 1a a9 38 a4 95 a1 ac 31 5a 1a 84 66 3d 43 d3 2d |..8....1Z..f=C.-|
+00000260 d9 0b f2 97 df d3 20 64 38 92 24 3a 00 bc cf 9c |...... d8.$:....|
+00000270 7d b7 40 20 01 5f aa d3 16 61 09 a2 76 fd 13 c3 |}.@ ._...a..v...|
+00000280 cc e1 0c 5c ee b1 87 82 f1 6c 04 ed 73 bb b3 43 |...\.....l..s..C|
+00000290 77 8d 0c 1c f1 0f a1 d8 40 83 61 c9 4c 72 2b 9d |w....... at .a.Lr+.|
+000002a0 ae db 46 06 06 4d f4 c1 b3 3e c0 d1 bd 42 d4 db |..F..M...>...B..|
+000002b0 fe 3d 13 60 84 5c 21 d3 3b e9 fa e7 16 03 03 00 |.=.`.\!.;.......|
+000002c0 ac 0c 00 00 a8 03 00 1d 20 9a 18 f9 2e 33 f7 bb |........ ....3..|
+000002d0 ca 60 0b 51 ad 5c 01 e2 61 82 0b 3f 09 8f 78 9d |.`.Q.\..a..?..x.|
+000002e0 3b 11 8b e0 4a 35 2e d5 54 04 01 00 80 90 94 0e |;...J5..T.......|
+000002f0 bf 3a b7 95 d3 58 cc 65 c3 79 5e 1e bb d9 21 56 |.:...X.e.y^...!V|
+00000300 06 93 6c 2b 6e 26 55 ee 26 c3 02 44 7e db 35 9b |..l+n&U.&..D~.5.|
+00000310 d4 d4 1a a0 65 35 41 a4 6c ce de 1f 94 ff b4 1b |....e5A.l.......|
+00000320 1e 9c 28 0b 4c 8d 55 d0 d8 be f1 df e0 d1 1a b5 |..(.L.U.........|
+00000330 c8 be 2c 5a 2c c3 3f ea 4f e6 d5 b4 6b e1 ff eb |..,Z,.?.O...k...|
+00000340 f3 f3 40 54 d5 62 1f a0 fc b2 34 66 ee c5 27 a6 |.. at T.b....4f..'.|
+00000350 2b 2a b9 5d 3f 36 28 eb 39 99 25 e5 04 d2 18 13 |+*.]?6(.9.%.....|
+00000360 3c 23 93 d0 04 37 85 b0 4d 6e 9b 32 9a 16 03 03 |<#...7..Mn.2....|
+00000370 00 2a 0d 00 00 26 03 01 02 40 00 1e 06 01 06 02 |.*...&... at ......|
+00000380 06 03 05 01 05 02 05 03 04 01 04 02 04 03 03 01 |................|
+00000390 03 02 03 03 02 01 02 02 02 03 00 00 16 03 03 00 |................|
+000003a0 04 0e 00 00 00 |.....|
>>> Flow 3 (client to server)
-00000000 16 03 03 01 fb 0b 00 01 f7 00 01 f4 00 01 f1 30 |...............0|
-00000010 82 01 ed 30 82 01 58 a0 03 02 01 02 02 01 00 30 |...0..X........0|
-00000020 0b 06 09 2a 86 48 86 f7 0d 01 01 05 30 26 31 10 |...*.H......0&1.|
-00000030 30 0e 06 03 55 04 0a 13 07 41 63 6d 65 20 43 6f |0...U....Acme Co|
-00000040 31 12 30 10 06 03 55 04 03 13 09 31 32 37 2e 30 |1.0...U....127.0|
-00000050 2e 30 2e 31 30 1e 17 0d 31 31 31 32 30 38 30 37 |.0.10...11120807|
-00000060 35 35 31 32 5a 17 0d 31 32 31 32 30 37 30 38 30 |5512Z..121207080|
-00000070 30 31 32 5a 30 26 31 10 30 0e 06 03 55 04 0a 13 |012Z0&1.0...U...|
-00000080 07 41 63 6d 65 20 43 6f 31 12 30 10 06 03 55 04 |.Acme Co1.0...U.|
-00000090 03 13 09 31 32 37 2e 30 2e 30 2e 31 30 81 9c 30 |...127.0.0.10..0|
-000000a0 0b 06 09 2a 86 48 86 f7 0d 01 01 01 03 81 8c 00 |...*.H..........|
-000000b0 30 81 88 02 81 80 4e d0 7b 31 e3 82 64 d9 59 c0 |0.....N.{1..d.Y.|
-000000c0 c2 87 a4 5e 1e 8b 73 33 c7 63 53 df 66 92 06 84 |...^..s3.cS.f...|
-000000d0 f6 64 d5 8f e4 36 a7 1d 2b e8 b3 20 36 45 23 b5 |.d...6..+.. 6E#.|
-000000e0 e3 95 ae ed e0 f5 20 9c 8d 95 df 7f 5a 12 ef 87 |...... .....Z...|
-000000f0 e4 5b 68 e4 e9 0e 74 ec 04 8a 7f de 93 27 c4 01 |.[h...t......'..|
-00000100 19 7a bd f2 dc 3d 14 ab d0 54 ca 21 0c d0 4d 6e |.z...=...T.!..Mn|
-00000110 87 2e 5c c5 d2 bb 4d 4b 4f ce b6 2c f7 7e 88 ec |..\...MKO..,.~..|
-00000120 7c d7 02 91 74 a6 1e 0c 1a da e3 4a 5a 2e de 13 ||...t......JZ...|
-00000130 9c 4c 40 88 59 93 02 03 01 00 01 a3 32 30 30 30 |.L at .Y.......2000|
-00000140 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 00 a0 30 |...U...........0|
-00000150 0d 06 03 55 1d 0e 04 06 04 04 01 02 03 04 30 0f |...U..........0.|
-00000160 06 03 55 1d 23 04 08 30 06 80 04 01 02 03 04 30 |..U.#..0.......0|
-00000170 0b 06 09 2a 86 48 86 f7 0d 01 01 05 03 81 81 00 |...*.H..........|
-00000180 36 1f b3 7a 0c 75 c9 6e 37 46 61 2b d5 bd c0 a7 |6..z.u.n7Fa+....|
-00000190 4b cc 46 9a 81 58 7c 85 79 29 c8 c8 c6 67 dd 32 |K.F..X|.y)...g.2|
-000001a0 56 45 2b 75 b6 e9 24 a9 50 9a be 1f 5a fa 1a 15 |VE+u..$.P...Z...|
-000001b0 d9 cc 55 95 72 16 83 b9 c2 b6 8f fd 88 8c 38 84 |..U.r.........8.|
-000001c0 1d ab 5d 92 31 13 4f fd 83 3b c6 9d f1 11 62 b6 |..].1.O..;....b.|
-000001d0 8b ec ab 67 be c8 64 b0 11 50 46 58 17 6b 99 1c |...g..d..PFX.k..|
-000001e0 d3 1d fc 06 f1 0e e5 96 a8 0c f9 78 20 b7 44 18 |...........x .D.|
-000001f0 51 8d 10 7e 4f 94 67 df a3 4e 70 73 8e 90 91 85 |Q..~O.g..Nps....|
-00000200 16 03 03 00 46 10 00 00 42 41 04 1e 18 37 ef 0d |....F...BA...7..|
-00000210 19 51 88 35 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd |.Q.5uq..T[....g.|
-00000220 a7 24 20 3e b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e |.$ >.V...(^.+-O.|
-00000230 f1 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 |...lK[.V.2B.X..I|
-00000240 a6 b5 68 1a 41 03 56 6b dc 5a 89 16 03 03 00 88 |..h.A.Vk.Z......|
-00000250 0f 00 00 84 05 01 00 80 45 11 dc 3c 2a fc 5f aa |........E..<*._.|
-00000260 60 09 59 47 45 cc a7 74 e3 9d 0c c3 a4 08 b0 2a |`.YGE..t.......*|
-00000270 44 47 cd 66 ed 94 54 8f d7 74 fd 47 a3 90 56 69 |DG.f..T..t.G..Vi|
-00000280 5a b6 c5 b0 bd c2 16 a2 1e af 58 37 88 cb d1 4b |Z.........X7...K|
-00000290 5c ee e6 0f 16 9b e0 d7 43 b3 e6 0a b2 90 fa 21 |\.......C......!|
-000002a0 78 95 3e 7f fc c1 b3 df a1 bf fc eb bc e8 37 63 |x.>...........7c|
-000002b0 87 33 3e c3 9a e4 6c 0f 3d 0d 9f e8 db 2d 82 ad |.3>...l.=....-..|
-000002c0 3c 6d f7 4a 5e 81 21 4f 19 0e 60 2d ef c1 40 8d |<m.J^.!O..`-.. at .|
-000002d0 cb 97 4f 08 1c c0 66 e7 14 03 03 00 01 01 16 03 |..O...f.........|
-000002e0 03 00 28 00 00 00 00 00 00 00 00 8c ce 5e 94 90 |..(..........^..|
-000002f0 22 2c 8d 64 be 29 99 62 1f 95 6e 3b 51 22 9c eb |",.d.).b..n;Q"..|
-00000300 f3 0f 24 b8 a5 84 58 70 82 71 a1 |..$...Xp.q.|
+00000000 16 03 03 01 fd 0b 00 01 f9 00 01 f6 00 01 f3 30 |...............0|
+00000010 82 01 ef 30 82 01 58 a0 03 02 01 02 02 10 5c 19 |...0..X.......\.|
+00000020 c1 89 65 83 55 6f dc 0b c9 b9 93 9f e9 bc 30 0d |..e.Uo........0.|
+00000030 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 12 31 |..*.H........0.1|
+00000040 10 30 0e 06 03 55 04 0a 13 07 41 63 6d 65 20 43 |.0...U....Acme C|
+00000050 6f 30 1e 17 0d 31 36 30 38 31 37 32 31 35 32 33 |o0...16081721523|
+00000060 31 5a 17 0d 31 37 30 38 31 37 32 31 35 32 33 31 |1Z..170817215231|
+00000070 5a 30 12 31 10 30 0e 06 03 55 04 0a 13 07 41 63 |Z0.1.0...U....Ac|
+00000080 6d 65 20 43 6f 30 81 9f 30 0d 06 09 2a 86 48 86 |me Co0..0...*.H.|
+00000090 f7 0d 01 01 01 05 00 03 81 8d 00 30 81 89 02 81 |...........0....|
+000000a0 81 00 ba 6f aa 86 bd cf bf 9f f2 ef 5c 94 60 78 |...o........\.`x|
+000000b0 6f e8 13 f2 d1 96 6f cd d9 32 6e 22 37 ce 41 f9 |o.....o..2n"7.A.|
+000000c0 ca 5d 29 ac e1 27 da 61 a2 ee 81 cb 10 c7 df 34 |.])..'.a.......4|
+000000d0 58 95 86 e9 3d 19 e6 5c 27 73 60 c8 8d 78 02 f4 |X...=..\'s`..x..|
+000000e0 1d a4 98 09 a3 19 70 69 3c 25 62 66 2a ab 22 23 |......pi<%bf*."#|
+000000f0 c5 7b 85 38 4f 2e 09 73 32 a7 bd 3e 9b ad ca 84 |.{.8O..s2..>....|
+00000100 07 e6 0f 3a ff 77 c5 9d 41 85 00 8a b6 9b ee b0 |...:.w..A.......|
+00000110 a4 3f 2d 4c 4c e6 42 3e bb 51 c8 dd 48 54 f4 0c |.?-LL.B>.Q..HT..|
+00000120 8e 47 02 03 01 00 01 a3 46 30 44 30 0e 06 03 55 |.G......F0D0...U|
+00000130 1d 0f 01 01 ff 04 04 03 02 05 a0 30 13 06 03 55 |...........0...U|
+00000140 1d 25 04 0c 30 0a 06 08 2b 06 01 05 05 07 03 01 |.%..0...+.......|
+00000150 30 0c 06 03 55 1d 13 01 01 ff 04 02 30 00 30 0f |0...U.......0.0.|
+00000160 06 03 55 1d 11 04 08 30 06 87 04 7f 00 00 01 30 |..U....0.......0|
+00000170 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 03 81 |...*.H..........|
+00000180 81 00 46 ab 44 a2 fb 28 54 f8 5a 67 f8 62 94 f1 |..F.D..(T.Zg.b..|
+00000190 9a b2 18 9e f2 b1 de 1d 7e 6f 76 95 a9 ba e7 5d |........~ov....]|
+000001a0 a8 16 6c 9c f7 09 d3 37 e4 4b 2b 36 7c 01 ad 41 |..l....7.K+6|..A|
+000001b0 d2 32 d8 c3 d2 93 f9 10 6b 8e 95 b9 2c 17 8a a3 |.2......k...,...|
+000001c0 44 48 bc 59 13 83 16 04 88 a4 81 5c 25 0d 98 0c |DH.Y.......\%...|
+000001d0 ac 11 b1 28 56 be 1d cd 61 62 84 09 bf d6 80 c6 |...(V...ab......|
+000001e0 45 8d 82 2c b4 d8 83 9b db c9 22 b7 2a 12 11 7b |E..,......".*..{|
+000001f0 fa 02 3b c1 c9 ff ea c9 9d a8 49 d3 95 d7 d5 0e |..;.......I.....|
+00000200 e5 35 16 03 03 00 25 10 00 00 21 20 2f e5 7d a3 |.5....%...! /.}.|
+00000210 47 cd 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 |G.bC.(.._.).0...|
+00000220 af c4 cf c2 ed 90 99 5f 58 cb 3b 74 16 03 03 00 |......._X.;t....|
+00000230 88 0f 00 00 84 05 01 00 80 ad f7 ff a0 cb d0 6e |...............n|
+00000240 8f 19 0c 40 2a 1f bb dd 11 52 81 84 f1 7b 3f cf |...@*....R...{?.|
+00000250 75 72 83 a4 4c 0a 9c 70 95 98 d5 51 a2 28 0c 8c |ur..L..p...Q.(..|
+00000260 20 08 d7 2a a5 3e 0c cf 6c a2 1d 32 bd cc a1 b4 | ..*.>..l..2....|
+00000270 61 e0 6d 9a 61 16 03 5c 7a b8 fa 15 ea cd e4 de |a.m.a..\z.......|
+00000280 d6 16 93 b2 e0 d2 55 b9 03 e0 67 04 27 64 8c e2 |......U...g.'d..|
+00000290 01 ee 8f f7 59 3e 12 16 51 f2 07 20 fe 03 e2 3e |....Y>..Q.. ...>|
+000002a0 09 1f 96 24 c5 73 0e 69 ac 57 ff 43 2b 6a c6 20 |...$.s.i.W.C+j. |
+000002b0 2f e4 ef 7e bc b3 38 57 06 14 03 03 00 01 01 16 |/..~..8W........|
+000002c0 03 03 00 28 00 00 00 00 00 00 00 00 fd 71 f5 ca |...(.........q..|
+000002d0 91 26 67 54 a5 e6 f3 06 c8 40 24 9d a9 bd b1 9a |.&gT.....@$.....|
+000002e0 63 c4 c2 53 56 ba af c0 16 bc 06 5c |c..SV......\|
>>> Flow 4 (server to client)
-00000000 14 03 03 00 01 01 16 03 03 00 28 b1 23 11 48 69 |..........(.#.Hi|
-00000010 52 44 34 f1 9a 69 2b 79 fb 68 b4 53 d5 d7 08 08 |RD4..i+y.h.S....|
-00000020 34 95 5f 56 b2 57 eb 91 31 6c 32 25 b5 68 8a 8e |4._V.W..1l2%.h..|
-00000030 f1 68 6e |.hn|
+00000000 14 03 03 00 01 01 16 03 03 00 28 92 8f bd c5 97 |..........(.....|
+00000010 94 76 70 f4 0a f9 9a 79 69 31 27 0e c0 c5 0b 3c |.vp....yi1'....<|
+00000020 9f 4f c2 2f cb 6c 56 62 80 3b e5 72 6a 05 9e 4b |.O./.lVb.;.rj..K|
+00000030 34 b9 66 |4.f|
>>> Flow 5 (client to server)
-00000000 17 03 03 00 1e 00 00 00 00 00 00 00 01 03 ab 9e |................|
-00000010 f0 a6 6c f1 ea 23 20 63 42 a3 9d c6 5d 41 96 c1 |..l..# cB...]A..|
-00000020 44 b2 8b 15 03 03 00 1a 00 00 00 00 00 00 00 02 |D...............|
-00000030 e9 73 41 50 28 b0 d3 00 46 81 d6 c9 1a ca ab cd |.sAP(...F.......|
-00000040 44 9b |D.|
+00000000 17 03 03 00 1e 00 00 00 00 00 00 00 01 43 fb 43 |.............C.C|
+00000010 3d 96 63 dd 25 94 9d 7a fb 9e 15 6f 62 5e ed 34 |=.c.%..z...ob^.4|
+00000020 19 89 b8 15 03 03 00 1a 00 00 00 00 00 00 00 02 |................|
+00000030 53 c2 2d 6c b7 91 6c 62 84 09 a2 1c 9b 3d 9e 89 |S.-l..lb.....=..|
+00000040 6a 3d |j=|
diff --git a/src/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-ECDSA b/src/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-ECDSA
index 4fa5e20..1ff9198 100644
--- a/src/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-ECDSA
+++ b/src/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-ECDSA
@@ -1,19 +1,20 @@
>>> Flow 1 (client to server)
-00000000 16 03 01 00 85 01 00 00 81 03 03 00 00 00 00 00 |................|
+00000000 16 03 01 00 91 01 00 00 8d 03 03 00 00 00 00 00 |................|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
-00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 22 c0 2f |............."./|
-00000030 c0 2b c0 30 c0 2c c0 11 c0 07 c0 13 c0 09 c0 14 |.+.0.,..........|
-00000040 c0 0a 00 9c 00 9d 00 05 00 2f 00 35 c0 12 00 0a |........./.5....|
-00000050 01 00 00 36 00 05 00 05 01 00 00 00 00 00 0a 00 |...6............|
-00000060 08 00 06 00 17 00 18 00 19 00 0b 00 02 01 00 00 |................|
-00000070 0d 00 0e 00 0c 04 01 04 03 05 01 05 03 02 01 02 |................|
-00000080 03 ff 01 00 01 00 00 12 00 00 |..........|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2c cc a8 |.............,..|
+00000030 cc a9 c0 2f c0 2b c0 30 c0 2c c0 27 c0 13 c0 23 |.../.+.0.,.'...#|
+00000040 c0 09 c0 14 c0 0a 00 9c 00 9d 00 3c 00 2f 00 35 |...........<./.5|
+00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 38 00 05 |.............8..|
+00000060 00 05 01 00 00 00 00 00 0a 00 0a 00 08 00 1d 00 |................|
+00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 0e 00 |................|
+00000080 0c 04 01 04 03 05 01 05 03 02 01 02 03 ff 01 00 |................|
+00000090 01 00 00 12 00 00 |......|
>>> Flow 2 (server to client)
-00000000 16 03 03 00 59 02 00 00 55 03 03 2a 01 f8 3e d1 |....Y...U..*..>.|
-00000010 52 41 2e 9a 8d 56 ff 52 3d 6a fe 65 ab 91 bb b7 |RA...V.R=j.e....|
-00000020 82 be f1 60 40 3b 80 a1 f8 dc 95 20 48 87 41 46 |...`@;..... H.AF|
-00000030 6a d2 f3 b8 d8 68 20 40 45 b7 fe 19 21 bc 84 00 |j....h @E...!...|
-00000040 5d 40 40 21 58 3e 7d fb a7 e3 30 37 c0 09 00 00 |]@@!X>}...07....|
+00000000 16 03 03 00 59 02 00 00 55 03 03 84 4b ff a4 2a |....Y...U...K..*|
+00000010 a4 76 c0 26 f6 05 72 94 01 15 44 f2 c6 7d b0 4b |.v.&..r...D..}.K|
+00000020 1b fa da 51 54 45 78 66 e6 0a dd 20 17 df d2 0c |...QTExf... ....|
+00000030 2f d6 55 b9 ae 82 ce 2f 2f 07 67 54 5e 02 bd 2f |/.U....//.gT^../|
+00000040 48 f6 fb 3d 9c fa 4f a8 66 15 08 da c0 09 00 00 |H..=..O.f.......|
00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................|
00000060 03 02 0e 0b 00 02 0a 00 02 07 00 02 04 30 82 02 |.............0..|
00000070 00 30 82 01 62 02 09 00 b8 bf 2d 47 a0 d2 eb f4 |.0..b.....-G....|
@@ -48,87 +49,83 @@
00000240 13 83 0d 94 06 bb d4 37 7a f6 ec 7a c9 86 2e dd |.......7z..z....|
00000250 d7 11 69 7f 85 7c 56 de fb 31 78 2b e4 c7 78 0d |..i..|V..1x+..x.|
00000260 ae cb be 9e 4e 36 24 31 7b 6a 0f 39 95 12 07 8f |....N6$1{j.9....|
-00000270 2a 16 03 03 00 d8 0c 00 00 d4 03 00 17 41 04 00 |*............A..|
-00000280 9e 90 3a 3d 00 37 0a c0 43 92 6e bf b4 23 d9 64 |..:=.7..C.n..#.d|
-00000290 99 d2 90 9e eb 88 b6 d6 6f 15 4a 22 72 f0 bf 5e |........o.J"r..^|
-000002a0 72 80 93 90 aa f1 d1 9c 45 c6 6e 3a f8 a9 6f fe |r.......E.n:..o.|
-000002b0 fb 24 dc b1 4d 52 39 91 f5 48 36 06 f6 15 0e 04 |.$..MR9..H6.....|
-000002c0 03 00 8b 30 81 88 02 42 00 a9 54 74 a7 a8 d0 04 |...0...B..Tt....|
-000002d0 ae ef e4 64 38 74 21 e6 18 f0 79 b2 d7 7e 7b 0e |...d8t!...y..~{.|
-000002e0 f6 74 75 52 f0 b8 15 3c 3d 15 52 75 9f 60 03 63 |.tuR...<=.Ru.`.c|
-000002f0 15 b8 1e b8 0e 5c 58 c7 e7 2f 6d 76 c7 c8 42 7a |.....\X../mv..Bz|
-00000300 df 15 26 4b dc 9c 3b 4d b3 b6 02 42 00 a5 fd bf |..&K..;M...B....|
-00000310 a9 5d fc 87 42 24 f9 0b 7a 17 97 7c ee 45 1c 29 |.]..B$..z..|.E.)|
-00000320 3a 07 5f df 4d f2 d3 cb fc a6 fd 84 34 2c 40 84 |:._.M.......4, at .|
-00000330 06 76 bf 43 35 d2 f6 9a 7c d6 1b 5e d8 fd 08 35 |.v.C5...|..^...5|
-00000340 1b 90 0e 24 a7 48 9d 71 ab 4a 11 92 d3 6e 16 03 |...$.H.q.J...n..|
-00000350 03 00 2e 0d 00 00 26 03 01 02 40 00 1e 06 01 06 |......&... at .....|
-00000360 02 06 03 05 01 05 02 05 03 04 01 04 02 04 03 03 |................|
-00000370 01 03 02 03 03 02 01 02 02 02 03 00 00 0e 00 00 |................|
-00000380 00 |.|
+00000270 2a 16 03 03 00 b7 0c 00 00 b3 03 00 1d 20 5d 4e |*............ ]N|
+00000280 0c 9e ad 7b f1 48 0c db 03 96 26 2e 16 87 2c e2 |...{.H....&...,.|
+00000290 ce a2 47 5a 57 30 e8 e1 7e b2 53 5b c6 7b 04 03 |..GZW0..~.S[.{..|
+000002a0 00 8b 30 81 88 02 42 00 e8 8e 68 a8 e3 b5 b4 fe |..0...B...h.....|
+000002b0 b9 91 aa 4f 96 3d 97 8d b2 ef 23 a4 3d 16 db 2b |...O.=....#.=..+|
+000002c0 50 6d 52 cd a5 e7 79 ae 65 10 d6 36 e0 ba c3 6b |PmR...y.e..6...k|
+000002d0 53 61 14 bb 05 47 5a df 26 2f cb 3a 95 c6 6b dc |Sa...GZ.&/.:..k.|
+000002e0 88 fd 2e 22 b5 ef ff 31 0e 02 42 01 be ce 6e 53 |..."...1..B...nS|
+000002f0 42 43 1c 1c d8 83 7f 45 c4 16 ee d2 7b 66 a0 f4 |BC.....E....{f..|
+00000300 f3 14 da 5c 14 e8 fc bc 86 7d 18 43 b9 7b 90 8c |...\.....}.C.{..|
+00000310 af f1 05 95 c6 53 0b 0b 0d 10 a1 e9 bb 89 35 c2 |.....S........5.|
+00000320 b2 e1 d7 dd 99 7c bf 85 19 3c 4e 8e 8f 16 03 03 |.....|...<N.....|
+00000330 00 2a 0d 00 00 26 03 01 02 40 00 1e 06 01 06 02 |.*...&... at ......|
+00000340 06 03 05 01 05 02 05 03 04 01 04 02 04 03 03 01 |................|
+00000350 03 02 03 03 02 01 02 02 02 03 00 00 16 03 03 00 |................|
+00000360 04 0e 00 00 00 |.....|
>>> Flow 3 (client to server)
-00000000 16 03 03 01 fb 0b 00 01 f7 00 01 f4 00 01 f1 30 |...............0|
-00000010 82 01 ed 30 82 01 58 a0 03 02 01 02 02 01 00 30 |...0..X........0|
-00000020 0b 06 09 2a 86 48 86 f7 0d 01 01 05 30 26 31 10 |...*.H......0&1.|
-00000030 30 0e 06 03 55 04 0a 13 07 41 63 6d 65 20 43 6f |0...U....Acme Co|
-00000040 31 12 30 10 06 03 55 04 03 13 09 31 32 37 2e 30 |1.0...U....127.0|
-00000050 2e 30 2e 31 30 1e 17 0d 31 31 31 32 30 38 30 37 |.0.10...11120807|
-00000060 35 35 31 32 5a 17 0d 31 32 31 32 30 37 30 38 30 |5512Z..121207080|
-00000070 30 31 32 5a 30 26 31 10 30 0e 06 03 55 04 0a 13 |012Z0&1.0...U...|
-00000080 07 41 63 6d 65 20 43 6f 31 12 30 10 06 03 55 04 |.Acme Co1.0...U.|
-00000090 03 13 09 31 32 37 2e 30 2e 30 2e 31 30 81 9c 30 |...127.0.0.10..0|
-000000a0 0b 06 09 2a 86 48 86 f7 0d 01 01 01 03 81 8c 00 |...*.H..........|
-000000b0 30 81 88 02 81 80 4e d0 7b 31 e3 82 64 d9 59 c0 |0.....N.{1..d.Y.|
-000000c0 c2 87 a4 5e 1e 8b 73 33 c7 63 53 df 66 92 06 84 |...^..s3.cS.f...|
-000000d0 f6 64 d5 8f e4 36 a7 1d 2b e8 b3 20 36 45 23 b5 |.d...6..+.. 6E#.|
-000000e0 e3 95 ae ed e0 f5 20 9c 8d 95 df 7f 5a 12 ef 87 |...... .....Z...|
-000000f0 e4 5b 68 e4 e9 0e 74 ec 04 8a 7f de 93 27 c4 01 |.[h...t......'..|
-00000100 19 7a bd f2 dc 3d 14 ab d0 54 ca 21 0c d0 4d 6e |.z...=...T.!..Mn|
-00000110 87 2e 5c c5 d2 bb 4d 4b 4f ce b6 2c f7 7e 88 ec |..\...MKO..,.~..|
-00000120 7c d7 02 91 74 a6 1e 0c 1a da e3 4a 5a 2e de 13 ||...t......JZ...|
-00000130 9c 4c 40 88 59 93 02 03 01 00 01 a3 32 30 30 30 |.L at .Y.......2000|
-00000140 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 00 a0 30 |...U...........0|
-00000150 0d 06 03 55 1d 0e 04 06 04 04 01 02 03 04 30 0f |...U..........0.|
-00000160 06 03 55 1d 23 04 08 30 06 80 04 01 02 03 04 30 |..U.#..0.......0|
-00000170 0b 06 09 2a 86 48 86 f7 0d 01 01 05 03 81 81 00 |...*.H..........|
-00000180 36 1f b3 7a 0c 75 c9 6e 37 46 61 2b d5 bd c0 a7 |6..z.u.n7Fa+....|
-00000190 4b cc 46 9a 81 58 7c 85 79 29 c8 c8 c6 67 dd 32 |K.F..X|.y)...g.2|
-000001a0 56 45 2b 75 b6 e9 24 a9 50 9a be 1f 5a fa 1a 15 |VE+u..$.P...Z...|
-000001b0 d9 cc 55 95 72 16 83 b9 c2 b6 8f fd 88 8c 38 84 |..U.r.........8.|
-000001c0 1d ab 5d 92 31 13 4f fd 83 3b c6 9d f1 11 62 b6 |..].1.O..;....b.|
-000001d0 8b ec ab 67 be c8 64 b0 11 50 46 58 17 6b 99 1c |...g..d..PFX.k..|
-000001e0 d3 1d fc 06 f1 0e e5 96 a8 0c f9 78 20 b7 44 18 |...........x .D.|
-000001f0 51 8d 10 7e 4f 94 67 df a3 4e 70 73 8e 90 91 85 |Q..~O.g..Nps....|
-00000200 16 03 03 00 46 10 00 00 42 41 04 1e 18 37 ef 0d |....F...BA...7..|
-00000210 19 51 88 35 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd |.Q.5uq..T[....g.|
-00000220 a7 24 20 3e b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e |.$ >.V...(^.+-O.|
-00000230 f1 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 |...lK[.V.2B.X..I|
-00000240 a6 b5 68 1a 41 03 56 6b dc 5a 89 16 03 03 00 88 |..h.A.Vk.Z......|
-00000250 0f 00 00 84 05 01 00 80 20 ef 4b 1c d7 67 37 6e |........ .K..g7n|
-00000260 24 12 9e e9 59 b1 6d da e5 3e 6b 11 03 f4 96 e4 |$...Y.m..>k.....|
-00000270 2e fb 03 e1 13 af 73 4d 15 11 c1 80 e2 ed 11 c6 |......sM........|
-00000280 73 6a 96 ce d1 26 e4 bc fe 71 c9 48 32 fd d8 70 |sj...&...q.H2..p|
-00000290 01 9d 18 7b ed a3 bd 6a 68 df 45 a0 d5 77 79 d2 |...{...jh.E..wy.|
-000002a0 5b e2 8c 96 68 95 46 8d 7d e6 b6 26 fa e1 c4 05 |[...h.F.}..&....|
-000002b0 4c d1 39 4e 35 e3 0c 1b 26 37 2e 0b 9b 0b cf f7 |L.9N5...&7......|
-000002c0 25 c3 da 27 18 70 83 18 49 ff ee ba e3 f8 70 75 |%..'.p..I.....pu|
-000002d0 e8 9b 2d 89 d7 b2 00 a5 14 03 03 00 01 01 16 03 |..-.............|
-000002e0 03 00 40 00 00 00 00 00 00 00 00 00 00 00 00 00 |.. at .............|
-000002f0 00 00 00 d3 33 79 85 64 14 07 a6 93 74 f8 f8 55 |....3y.d....t..U|
-00000300 0f fb fc 8e 1b 4c 38 21 b6 61 c5 4b b2 d4 17 b2 |.....L8!.a.K....|
-00000310 c4 be a6 4b d6 3f a3 5f 3c ff 5f 1d 93 a2 c4 82 |...K.?._<._.....|
-00000320 96 90 eb |...|
+00000000 16 03 03 01 fd 0b 00 01 f9 00 01 f6 00 01 f3 30 |...............0|
+00000010 82 01 ef 30 82 01 58 a0 03 02 01 02 02 10 5c 19 |...0..X.......\.|
+00000020 c1 89 65 83 55 6f dc 0b c9 b9 93 9f e9 bc 30 0d |..e.Uo........0.|
+00000030 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 12 31 |..*.H........0.1|
+00000040 10 30 0e 06 03 55 04 0a 13 07 41 63 6d 65 20 43 |.0...U....Acme C|
+00000050 6f 30 1e 17 0d 31 36 30 38 31 37 32 31 35 32 33 |o0...16081721523|
+00000060 31 5a 17 0d 31 37 30 38 31 37 32 31 35 32 33 31 |1Z..170817215231|
+00000070 5a 30 12 31 10 30 0e 06 03 55 04 0a 13 07 41 63 |Z0.1.0...U....Ac|
+00000080 6d 65 20 43 6f 30 81 9f 30 0d 06 09 2a 86 48 86 |me Co0..0...*.H.|
+00000090 f7 0d 01 01 01 05 00 03 81 8d 00 30 81 89 02 81 |...........0....|
+000000a0 81 00 ba 6f aa 86 bd cf bf 9f f2 ef 5c 94 60 78 |...o........\.`x|
+000000b0 6f e8 13 f2 d1 96 6f cd d9 32 6e 22 37 ce 41 f9 |o.....o..2n"7.A.|
+000000c0 ca 5d 29 ac e1 27 da 61 a2 ee 81 cb 10 c7 df 34 |.])..'.a.......4|
+000000d0 58 95 86 e9 3d 19 e6 5c 27 73 60 c8 8d 78 02 f4 |X...=..\'s`..x..|
+000000e0 1d a4 98 09 a3 19 70 69 3c 25 62 66 2a ab 22 23 |......pi<%bf*."#|
+000000f0 c5 7b 85 38 4f 2e 09 73 32 a7 bd 3e 9b ad ca 84 |.{.8O..s2..>....|
+00000100 07 e6 0f 3a ff 77 c5 9d 41 85 00 8a b6 9b ee b0 |...:.w..A.......|
+00000110 a4 3f 2d 4c 4c e6 42 3e bb 51 c8 dd 48 54 f4 0c |.?-LL.B>.Q..HT..|
+00000120 8e 47 02 03 01 00 01 a3 46 30 44 30 0e 06 03 55 |.G......F0D0...U|
+00000130 1d 0f 01 01 ff 04 04 03 02 05 a0 30 13 06 03 55 |...........0...U|
+00000140 1d 25 04 0c 30 0a 06 08 2b 06 01 05 05 07 03 01 |.%..0...+.......|
+00000150 30 0c 06 03 55 1d 13 01 01 ff 04 02 30 00 30 0f |0...U.......0.0.|
+00000160 06 03 55 1d 11 04 08 30 06 87 04 7f 00 00 01 30 |..U....0.......0|
+00000170 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 03 81 |...*.H..........|
+00000180 81 00 46 ab 44 a2 fb 28 54 f8 5a 67 f8 62 94 f1 |..F.D..(T.Zg.b..|
+00000190 9a b2 18 9e f2 b1 de 1d 7e 6f 76 95 a9 ba e7 5d |........~ov....]|
+000001a0 a8 16 6c 9c f7 09 d3 37 e4 4b 2b 36 7c 01 ad 41 |..l....7.K+6|..A|
+000001b0 d2 32 d8 c3 d2 93 f9 10 6b 8e 95 b9 2c 17 8a a3 |.2......k...,...|
+000001c0 44 48 bc 59 13 83 16 04 88 a4 81 5c 25 0d 98 0c |DH.Y.......\%...|
+000001d0 ac 11 b1 28 56 be 1d cd 61 62 84 09 bf d6 80 c6 |...(V...ab......|
+000001e0 45 8d 82 2c b4 d8 83 9b db c9 22 b7 2a 12 11 7b |E..,......".*..{|
+000001f0 fa 02 3b c1 c9 ff ea c9 9d a8 49 d3 95 d7 d5 0e |..;.......I.....|
+00000200 e5 35 16 03 03 00 25 10 00 00 21 20 2f e5 7d a3 |.5....%...! /.}.|
+00000210 47 cd 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 |G.bC.(.._.).0...|
+00000220 af c4 cf c2 ed 90 99 5f 58 cb 3b 74 16 03 03 00 |......._X.;t....|
+00000230 88 0f 00 00 84 05 01 00 80 98 58 a8 77 3d db 0b |..........X.w=..|
+00000240 04 36 78 51 8b 23 48 fc 70 2b c9 94 1f ee 32 ae |.6xQ.#H.p+....2.|
+00000250 41 c0 42 20 19 51 67 e7 fa c0 fd 15 a1 5f 55 4f |A.B .Qg......_UO|
+00000260 aa be 29 77 f5 47 71 b9 6c 51 89 18 df 25 98 fd |..)w.Gq.lQ...%..|
+00000270 c8 6e ae e3 fd 99 63 ca 2c d2 fb ca bc 57 b7 7f |.n....c.,....W..|
+00000280 a2 90 a6 6f b7 2e b7 2a 52 29 e6 75 57 86 cc b1 |...o...*R).uW...|
+00000290 d8 6c f3 4e 49 ab 4b 66 0a 72 aa ec c2 f7 6e 57 |.l.NI.Kf.r....nW|
+000002a0 15 26 79 1a a4 24 c2 ba 76 9e dd b9 f9 d4 da 1b |.&y..$..v.......|
+000002b0 c9 29 66 eb 64 1b 68 66 66 14 03 03 00 01 01 16 |.)f.d.hff.......|
+000002c0 03 03 00 40 00 00 00 00 00 00 00 00 00 00 00 00 |... at ............|
+000002d0 00 00 00 00 70 2b 69 27 05 9a 96 e6 e8 52 ea 0f |....p+i'.....R..|
+000002e0 3a d6 40 b5 e2 89 5b bf aa 95 6c c1 7d 53 09 89 |:. at ...[...l.}S..|
+000002f0 23 38 6b 83 85 84 fa f4 2e fb cd b3 57 4e 79 8a |#8k.........WNy.|
+00000300 92 74 03 22 |.t."|
>>> Flow 4 (server to client)
-00000000 14 03 03 00 01 01 16 03 03 00 40 80 b0 df ff b3 |.......... at .....|
-00000010 34 11 03 f5 2d fb c7 c2 38 15 df 41 97 55 0e 1d |4...-...8..A.U..|
-00000020 36 f7 a5 35 5b 63 d7 c5 a6 fd fc a1 91 32 9d cd |6..5[c.......2..|
-00000030 34 66 75 4c 5d 27 ee 89 ed d4 4a ec 67 b0 da e7 |4fuL]'....J.g...|
-00000040 f0 e7 36 eb db b9 22 97 74 30 cd |..6...".t0.|
+00000000 14 03 03 00 01 01 16 03 03 00 40 8f 91 f1 f5 6b |.......... at ....k|
+00000010 cc 52 9d db 35 1f db b4 64 fe 33 a5 83 08 24 2f |.R..5...d.3...$/|
+00000020 57 18 0e 60 4e 18 54 bb 80 31 37 fe 26 14 b8 c8 |W..`N.T..17.&...|
+00000030 dd c4 8c 07 42 0b 80 0b 41 82 40 f6 9b b8 60 4f |....B...A. at ...`O|
+00000040 cb 7b 43 ea 1a 6e 31 8d 9f 82 f7 |.{C..n1....|
>>> Flow 5 (client to server)
00000000 17 03 03 00 30 00 00 00 00 00 00 00 00 00 00 00 |....0...........|
-00000010 00 00 00 00 00 62 24 32 e9 40 38 c8 c3 dd 07 42 |.....b$2. at 8....B|
-00000020 05 c8 7c 3d d1 27 68 00 e4 91 6c 2d 08 c1 a1 b6 |..|=.'h...l-....|
-00000030 8a 89 3d 1d c1 15 03 03 00 30 00 00 00 00 00 00 |..=......0......|
-00000040 00 00 00 00 00 00 00 00 00 00 d1 c8 bc cb cb a5 |................|
-00000050 24 1e ad c5 bf 23 92 4b 81 a6 c0 77 19 e0 46 30 |$....#.K...w..F0|
-00000060 48 51 0c cc 39 cd 4b 8d e5 a7 |HQ..9.K...|
+00000010 00 00 00 00 00 70 e7 c8 03 9c e2 58 73 68 ab 9b |.....p.....Xsh..|
+00000020 5c bf 32 57 f8 f1 13 97 02 59 de 99 d3 3e 16 3d |\.2W.....Y...>.=|
+00000030 87 11 d4 b4 63 15 03 03 00 30 00 00 00 00 00 00 |....c....0......|
+00000040 00 00 00 00 00 00 00 00 00 00 9b 99 45 f3 0d f1 |............E...|
+00000050 c5 36 07 8c 81 94 b7 0a dc 7c ee 0c 22 1b 36 fd |.6.......|..".6.|
+00000060 d4 fc 7d f1 98 8b 87 be 5f c6 |..}....._.|
diff --git a/src/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-RSA b/src/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-RSA
index a0a9640..76f0c25 100644
--- a/src/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-RSA
+++ b/src/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-RSA
@@ -1,122 +1,130 @@
>>> Flow 1 (client to server)
-00000000 16 03 01 00 85 01 00 00 81 03 03 00 00 00 00 00 |................|
+00000000 16 03 01 00 91 01 00 00 8d 03 03 00 00 00 00 00 |................|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
-00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 22 c0 2f |............."./|
-00000030 c0 2b c0 30 c0 2c c0 11 c0 07 c0 13 c0 09 c0 14 |.+.0.,..........|
-00000040 c0 0a 00 9c 00 9d 00 05 00 2f 00 35 c0 12 00 0a |........./.5....|
-00000050 01 00 00 36 00 05 00 05 01 00 00 00 00 00 0a 00 |...6............|
-00000060 08 00 06 00 17 00 18 00 19 00 0b 00 02 01 00 00 |................|
-00000070 0d 00 0e 00 0c 04 01 04 03 05 01 05 03 02 01 02 |................|
-00000080 03 ff 01 00 01 00 00 12 00 00 |..........|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2c cc a8 |.............,..|
+00000030 cc a9 c0 2f c0 2b c0 30 c0 2c c0 27 c0 13 c0 23 |.../.+.0.,.'...#|
+00000040 c0 09 c0 14 c0 0a 00 9c 00 9d 00 3c 00 2f 00 35 |...........<./.5|
+00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 38 00 05 |.............8..|
+00000060 00 05 01 00 00 00 00 00 0a 00 0a 00 08 00 1d 00 |................|
+00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 0e 00 |................|
+00000080 0c 04 01 04 03 05 01 05 03 02 01 02 03 ff 01 00 |................|
+00000090 01 00 00 12 00 00 |......|
>>> Flow 2 (server to client)
-00000000 16 03 03 00 51 02 00 00 4d 03 03 60 8e 1c c9 6d |....Q...M..`...m|
-00000010 de 9d 2a dc 6a a6 82 71 9a 3f 8f 5b 18 52 44 4e |..*.j..q.?.[.RDN|
-00000020 4d 72 0d e7 c8 a1 b0 81 64 8c 1f 20 06 a8 17 35 |Mr......d.. ...5|
-00000030 b8 0b 96 52 30 f7 b3 d4 2a 25 94 c0 ba a8 a2 f7 |...R0...*%......|
-00000040 86 5c 18 18 3c 68 3a 71 0f bc 3f 12 00 05 00 00 |.\..<h:q..?.....|
-00000050 05 ff 01 00 01 00 16 03 03 02 71 0b 00 02 6d 00 |..........q...m.|
-00000060 02 6a 00 02 67 30 82 02 63 30 82 01 cc a0 03 02 |.j..g0..c0......|
-00000070 01 02 02 09 00 a2 73 00 0c 81 00 cb f3 30 0d 06 |......s......0..|
-00000080 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 2b 31 17 |.*.H........0+1.|
-00000090 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 |0...U....Google |
-000000a0 54 45 53 54 49 4e 47 31 10 30 0e 06 03 55 04 03 |TESTING1.0...U..|
-000000b0 13 07 47 6f 20 52 6f 6f 74 30 1e 17 0d 31 35 30 |..Go Root0...150|
-000000c0 31 30 31 30 30 30 30 30 30 5a 17 0d 32 35 30 31 |101000000Z..2501|
-000000d0 30 31 30 30 30 30 30 30 5a 30 26 31 17 30 15 06 |01000000Z0&1.0..|
-000000e0 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 54 45 53 |.U....Google TES|
-000000f0 54 49 4e 47 31 0b 30 09 06 03 55 04 03 13 02 47 |TING1.0...U....G|
-00000100 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....|
-00000110 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 af 87 |.......0........|
-00000120 88 f6 20 1b 95 65 6c 14 ab 44 05 af 3b 45 14 e3 |.. ..el..D..;E..|
-00000130 b7 6d fd 00 63 4d 95 7f fe 6a 62 35 86 c0 4a f9 |.m..cM...jb5..J.|
-00000140 18 7c f6 aa 25 5e 7a 64 31 66 00 ba f4 8e 92 af |.|..%^zd1f......|
-00000150 c7 6b d8 76 d4 f3 5f 41 cb 6e 56 15 97 1b 97 c1 |.k.v.._A.nV.....|
-00000160 3c 12 39 21 66 3d 2b 16 d1 bc db 1c c0 a7 da b7 |<.9!f=+.........|
-00000170 ca ad ba da cb d5 21 50 ec de 8d ab d1 6b 81 4b |......!P.....k.K|
-00000180 89 02 f3 c4 be c1 6c 89 b1 44 84 bd 21 d1 04 7d |......l..D..!..}|
-00000190 9d 16 4d f9 82 15 f6 ef fa d6 09 47 f2 fb 02 03 |..M........G....|
-000001a0 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..|
-000001b0 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%|
-000001c0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........|
-000001d0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...|
-000001e0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....|
-000001f0 10 12 50 8d 89 6f 1b d1 dc 54 4d 6e cb 69 5e 06 |..P..o...TMn.i^.|
-00000200 f4 30 1b 06 03 55 1d 23 04 14 30 12 80 10 bf 3d |.0...U.#..0....=|
-00000210 b6 a9 66 f2 b8 40 cf ea b4 03 78 48 1a 41 30 19 |..f.. at ....xH.A0.|
-00000220 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp|
-00000230 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H|
-00000240 86 f7 0d 01 01 0b 05 00 03 81 81 00 92 7c af 91 |.............|..|
-00000250 55 12 18 96 59 31 a6 48 40 d5 2d d5 ee bb 02 a0 |U...Y1.H at .-.....|
-00000260 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 da 4f 3d c0 fa |...|..0}<.v.O=..|
-00000270 ae 2d 33 24 6b 03 7b 1b 67 59 11 21 b5 11 bc 77 |.-3$k.{.gY.!...w|
-00000280 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f 22 3e 63 10 6b |...n.-.5.d_">c.k|
-00000290 be ff 14 86 6d 0d f0 15 31 a8 14 38 1e 3b 84 87 |....m...1..8.;..|
-000002a0 2c cb 98 ed 51 76 b9 b1 4f dd db 9b 84 04 86 40 |,...Qv..O......@|
-000002b0 fa 51 dd ba b4 8d eb e3 46 de 46 b9 4f 86 c7 f9 |.Q......F.F.O...|
-000002c0 a4 c2 41 34 ac cc f6 ea b0 ab 39 18 16 03 03 00 |..A4......9.....|
-000002d0 2e 0d 00 00 26 03 01 02 40 00 1e 06 01 06 02 06 |....&... at .......|
-000002e0 03 05 01 05 02 05 03 04 01 04 02 04 03 03 01 03 |................|
-000002f0 02 03 03 02 01 02 02 02 03 00 00 0e 00 00 00 |...............|
+00000000 16 03 03 00 59 02 00 00 55 03 03 92 93 45 4c f9 |....Y...U....EL.|
+00000010 93 bf ee 78 58 e0 42 b6 df 32 c2 63 6d ec 89 66 |...xX.B..2.cm..f|
+00000020 5a 11 7c 0d 31 2f b5 90 22 ab 3d 20 65 f3 40 c4 |Z.|.1/..".= e. at .|
+00000030 f8 31 fa 80 f3 fb a7 f6 9e dc 0c 94 67 48 d9 2b |.1..........gH.+|
+00000040 cb 94 82 5f 4e 8b 41 5e c6 63 27 da c0 2f 00 00 |..._N.A^.c'../..|
+00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................|
+00000060 03 02 59 0b 00 02 55 00 02 52 00 02 4f 30 82 02 |..Y...U..R..O0..|
+00000070 4b 30 82 01 b4 a0 03 02 01 02 02 09 00 e8 f0 9d |K0..............|
+00000080 3f e2 5b ea a6 30 0d 06 09 2a 86 48 86 f7 0d 01 |?.[..0...*.H....|
+00000090 01 0b 05 00 30 1f 31 0b 30 09 06 03 55 04 0a 13 |....0.1.0...U...|
+000000a0 02 47 6f 31 10 30 0e 06 03 55 04 03 13 07 47 6f |.Go1.0...U....Go|
+000000b0 20 52 6f 6f 74 30 1e 17 0d 31 36 30 31 30 31 30 | Root0...1601010|
+000000c0 30 30 30 30 30 5a 17 0d 32 35 30 31 30 31 30 30 |00000Z..25010100|
+000000d0 30 30 30 30 5a 30 1a 31 0b 30 09 06 03 55 04 0a |0000Z0.1.0...U..|
+000000e0 13 02 47 6f 31 0b 30 09 06 03 55 04 03 13 02 47 |..Go1.0...U....G|
+000000f0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....|
+00000100 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 db 46 |.......0.......F|
+00000110 7d 93 2e 12 27 06 48 bc 06 28 21 ab 7e c4 b6 a2 |}...'.H..(!.~...|
+00000120 5d fe 1e 52 45 88 7a 36 47 a5 08 0d 92 42 5b c2 |]..RE.z6G....B[.|
+00000130 81 c0 be 97 79 98 40 fb 4f 6d 14 fd 2b 13 8b c2 |....y. at .Om..+...|
+00000140 a5 2e 67 d8 d4 09 9e d6 22 38 b7 4a 0b 74 73 2b |..g....."8.J.ts+|
+00000150 c2 34 f1 d1 93 e5 96 d9 74 7b f3 58 9f 6c 61 3c |.4......t{.X.la<|
+00000160 c0 b0 41 d4 d9 2b 2b 24 23 77 5b 1c 3b bd 75 5d |..A..++$#w[.;.u]|
+00000170 ce 20 54 cf a1 63 87 1d 1e 24 c4 f3 1d 1a 50 8b |. T..c...$....P.|
+00000180 aa b6 14 43 ed 97 a7 75 62 f4 14 c8 52 d7 02 03 |...C...ub...R...|
+00000190 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..|
+000001a0 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%|
+000001b0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........|
+000001c0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...|
+000001d0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....|
+000001e0 10 9f 91 16 1f 43 43 3e 49 a6 de 6d b6 80 d7 9f |.....CC>I..m....|
+000001f0 60 30 1b 06 03 55 1d 23 04 14 30 12 80 10 48 13 |`0...U.#..0...H.|
+00000200 49 4d 13 7e 16 31 bb a3 01 d5 ac ab 6e 7b 30 19 |IM.~.1......n{0.|
+00000210 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp|
+00000220 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H|
+00000230 86 f7 0d 01 01 0b 05 00 03 81 81 00 9d 30 cc 40 |.............0.@|
+00000240 2b 5b 50 a0 61 cb ba e5 53 58 e1 ed 83 28 a9 58 |+[P.a...SX...(.X|
+00000250 1a a9 38 a4 95 a1 ac 31 5a 1a 84 66 3d 43 d3 2d |..8....1Z..f=C.-|
+00000260 d9 0b f2 97 df d3 20 64 38 92 24 3a 00 bc cf 9c |...... d8.$:....|
+00000270 7d b7 40 20 01 5f aa d3 16 61 09 a2 76 fd 13 c3 |}.@ ._...a..v...|
+00000280 cc e1 0c 5c ee b1 87 82 f1 6c 04 ed 73 bb b3 43 |...\.....l..s..C|
+00000290 77 8d 0c 1c f1 0f a1 d8 40 83 61 c9 4c 72 2b 9d |w....... at .a.Lr+.|
+000002a0 ae db 46 06 06 4d f4 c1 b3 3e c0 d1 bd 42 d4 db |..F..M...>...B..|
+000002b0 fe 3d 13 60 84 5c 21 d3 3b e9 fa e7 16 03 03 00 |.=.`.\!.;.......|
+000002c0 ac 0c 00 00 a8 03 00 1d 20 66 49 44 2b 04 fe f5 |........ fID+...|
+000002d0 41 68 60 09 81 0e 24 c4 46 68 33 87 41 dd 48 69 |Ah`...$.Fh3.A.Hi|
+000002e0 4c be c8 22 2d 4e ff 80 20 04 01 00 80 30 85 40 |L.."-N.. ....0.@|
+000002f0 30 56 d5 1d 41 14 9d e8 27 39 a2 18 d5 eb 92 27 |0V..A...'9.....'|
+00000300 63 4b 05 85 1a 9e 5f 60 2c 80 a3 20 9f 9c 57 29 |cK...._`,.. ..W)|
+00000310 ba 5f ac 0a aa 89 98 fc ca 8e 37 6b 44 bc 0f 33 |._........7kD..3|
+00000320 5d 47 91 46 55 d4 f9 4f 76 73 51 c4 f6 a9 90 e4 |]G.FU..OvsQ.....|
+00000330 95 10 92 94 f1 33 11 3d 83 0a eb 5d ff e6 9d 9c |.....3.=...]....|
+00000340 19 ec e1 65 11 ad d7 7b 6a a4 f9 d8 b6 0c 53 8a |...e...{j.....S.|
+00000350 16 d5 1f a7 0b 80 6f c5 d8 6a 57 11 2f b1 84 65 |......o..jW./..e|
+00000360 24 8a 02 de aa 10 40 bd 9b 68 a2 b7 b6 16 03 03 |$..... at ..h......|
+00000370 00 2a 0d 00 00 26 03 01 02 40 00 1e 06 01 06 02 |.*...&... at ......|
+00000380 06 03 05 01 05 02 05 03 04 01 04 02 04 03 03 01 |................|
+00000390 03 02 03 03 02 01 02 02 02 03 00 00 16 03 03 00 |................|
+000003a0 04 0e 00 00 00 |.....|
>>> Flow 3 (client to server)
-00000000 16 03 03 01 fb 0b 00 01 f7 00 01 f4 00 01 f1 30 |...............0|
-00000010 82 01 ed 30 82 01 58 a0 03 02 01 02 02 01 00 30 |...0..X........0|
-00000020 0b 06 09 2a 86 48 86 f7 0d 01 01 05 30 26 31 10 |...*.H......0&1.|
-00000030 30 0e 06 03 55 04 0a 13 07 41 63 6d 65 20 43 6f |0...U....Acme Co|
-00000040 31 12 30 10 06 03 55 04 03 13 09 31 32 37 2e 30 |1.0...U....127.0|
-00000050 2e 30 2e 31 30 1e 17 0d 31 31 31 32 30 38 30 37 |.0.10...11120807|
-00000060 35 35 31 32 5a 17 0d 31 32 31 32 30 37 30 38 30 |5512Z..121207080|
-00000070 30 31 32 5a 30 26 31 10 30 0e 06 03 55 04 0a 13 |012Z0&1.0...U...|
-00000080 07 41 63 6d 65 20 43 6f 31 12 30 10 06 03 55 04 |.Acme Co1.0...U.|
-00000090 03 13 09 31 32 37 2e 30 2e 30 2e 31 30 81 9c 30 |...127.0.0.10..0|
-000000a0 0b 06 09 2a 86 48 86 f7 0d 01 01 01 03 81 8c 00 |...*.H..........|
-000000b0 30 81 88 02 81 80 4e d0 7b 31 e3 82 64 d9 59 c0 |0.....N.{1..d.Y.|
-000000c0 c2 87 a4 5e 1e 8b 73 33 c7 63 53 df 66 92 06 84 |...^..s3.cS.f...|
-000000d0 f6 64 d5 8f e4 36 a7 1d 2b e8 b3 20 36 45 23 b5 |.d...6..+.. 6E#.|
-000000e0 e3 95 ae ed e0 f5 20 9c 8d 95 df 7f 5a 12 ef 87 |...... .....Z...|
-000000f0 e4 5b 68 e4 e9 0e 74 ec 04 8a 7f de 93 27 c4 01 |.[h...t......'..|
-00000100 19 7a bd f2 dc 3d 14 ab d0 54 ca 21 0c d0 4d 6e |.z...=...T.!..Mn|
-00000110 87 2e 5c c5 d2 bb 4d 4b 4f ce b6 2c f7 7e 88 ec |..\...MKO..,.~..|
-00000120 7c d7 02 91 74 a6 1e 0c 1a da e3 4a 5a 2e de 13 ||...t......JZ...|
-00000130 9c 4c 40 88 59 93 02 03 01 00 01 a3 32 30 30 30 |.L at .Y.......2000|
-00000140 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 00 a0 30 |...U...........0|
-00000150 0d 06 03 55 1d 0e 04 06 04 04 01 02 03 04 30 0f |...U..........0.|
-00000160 06 03 55 1d 23 04 08 30 06 80 04 01 02 03 04 30 |..U.#..0.......0|
-00000170 0b 06 09 2a 86 48 86 f7 0d 01 01 05 03 81 81 00 |...*.H..........|
-00000180 36 1f b3 7a 0c 75 c9 6e 37 46 61 2b d5 bd c0 a7 |6..z.u.n7Fa+....|
-00000190 4b cc 46 9a 81 58 7c 85 79 29 c8 c8 c6 67 dd 32 |K.F..X|.y)...g.2|
-000001a0 56 45 2b 75 b6 e9 24 a9 50 9a be 1f 5a fa 1a 15 |VE+u..$.P...Z...|
-000001b0 d9 cc 55 95 72 16 83 b9 c2 b6 8f fd 88 8c 38 84 |..U.r.........8.|
-000001c0 1d ab 5d 92 31 13 4f fd 83 3b c6 9d f1 11 62 b6 |..].1.O..;....b.|
-000001d0 8b ec ab 67 be c8 64 b0 11 50 46 58 17 6b 99 1c |...g..d..PFX.k..|
-000001e0 d3 1d fc 06 f1 0e e5 96 a8 0c f9 78 20 b7 44 18 |...........x .D.|
-000001f0 51 8d 10 7e 4f 94 67 df a3 4e 70 73 8e 90 91 85 |Q..~O.g..Nps....|
-00000200 16 03 03 00 86 10 00 00 82 00 80 73 bd 73 65 92 |...........s.se.|
-00000210 86 23 41 14 79 7f d5 c1 10 ce 94 4d ad 9c c3 a9 |.#A.y......M....|
-00000220 87 b5 32 52 f8 6b 11 93 2d 9b 98 0b 8b 1d c0 f6 |..2R.k..-.......|
-00000230 53 17 6d c7 9c 2e ae c9 6f cc 99 23 38 37 1a 10 |S.m.....o..#87..|
-00000240 fe 05 0b b5 55 0a 14 e9 60 7d 70 26 98 e2 54 d9 |....U...`}p&..T.|
-00000250 65 cf 2e f4 53 5f 1d aa 3a f6 33 7b eb 4c 0e b3 |e...S_..:.3{.L..|
-00000260 ff 5a db 36 2a 47 f3 df f9 fc f5 31 78 83 aa 6b |.Z.6*G.....1x..k|
-00000270 52 b7 ba 1a 96 bc fa c1 a1 a9 bb 2b f5 38 89 00 |R..........+.8..|
-00000280 4d e5 78 13 4e a4 38 46 42 dc 16 16 03 03 00 88 |M.x.N.8FB.......|
-00000290 0f 00 00 84 05 01 00 80 21 58 47 70 c2 2e 1c 4a |........!XGp...J|
-000002a0 fa 97 b2 cf 8d f8 93 f4 b0 8c b3 e0 e7 33 a6 ea |.............3..|
-000002b0 d7 fe 8e 25 e7 f3 f5 a1 8d 09 b7 0b 01 ec a1 15 |...%............|
-000002c0 5b 67 06 53 2a 7d 31 e5 a8 16 bc e3 1d ed 5a 77 |[g.S*}1.......Zw|
-000002d0 0b 78 78 c5 fc c5 62 8e 41 49 d3 ea cd 69 10 3f |.xx...b.AI...i.?|
-000002e0 34 9e 86 df f9 9f f6 02 0c 29 c4 66 a0 45 cf 7b |4........).f.E.{|
-000002f0 ce 51 ec 0a 26 b4 9d 3d 9e 63 5d 40 1a e8 84 4e |.Q..&..=.c]@...N|
-00000300 24 f5 42 48 b5 3e f8 92 c4 f2 e6 5d f4 ad 67 01 |$.BH.>.....]..g.|
-00000310 f8 a7 a7 2b b5 fc be e8 14 03 03 00 01 01 16 03 |...+............|
-00000320 03 00 24 f0 ec 1d f5 39 1c d2 d2 c7 f4 1f 3b 0c |..$....9......;.|
-00000330 cd 25 e4 8e ed c4 bb 02 9d 38 e5 a7 91 e0 ea 00 |.%.......8......|
-00000340 73 a8 9a 63 c9 e7 7d |s..c..}|
+00000000 16 03 03 01 fd 0b 00 01 f9 00 01 f6 00 01 f3 30 |...............0|
+00000010 82 01 ef 30 82 01 58 a0 03 02 01 02 02 10 5c 19 |...0..X.......\.|
+00000020 c1 89 65 83 55 6f dc 0b c9 b9 93 9f e9 bc 30 0d |..e.Uo........0.|
+00000030 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 12 31 |..*.H........0.1|
+00000040 10 30 0e 06 03 55 04 0a 13 07 41 63 6d 65 20 43 |.0...U....Acme C|
+00000050 6f 30 1e 17 0d 31 36 30 38 31 37 32 31 35 32 33 |o0...16081721523|
+00000060 31 5a 17 0d 31 37 30 38 31 37 32 31 35 32 33 31 |1Z..170817215231|
+00000070 5a 30 12 31 10 30 0e 06 03 55 04 0a 13 07 41 63 |Z0.1.0...U....Ac|
+00000080 6d 65 20 43 6f 30 81 9f 30 0d 06 09 2a 86 48 86 |me Co0..0...*.H.|
+00000090 f7 0d 01 01 01 05 00 03 81 8d 00 30 81 89 02 81 |...........0....|
+000000a0 81 00 ba 6f aa 86 bd cf bf 9f f2 ef 5c 94 60 78 |...o........\.`x|
+000000b0 6f e8 13 f2 d1 96 6f cd d9 32 6e 22 37 ce 41 f9 |o.....o..2n"7.A.|
+000000c0 ca 5d 29 ac e1 27 da 61 a2 ee 81 cb 10 c7 df 34 |.])..'.a.......4|
+000000d0 58 95 86 e9 3d 19 e6 5c 27 73 60 c8 8d 78 02 f4 |X...=..\'s`..x..|
+000000e0 1d a4 98 09 a3 19 70 69 3c 25 62 66 2a ab 22 23 |......pi<%bf*."#|
+000000f0 c5 7b 85 38 4f 2e 09 73 32 a7 bd 3e 9b ad ca 84 |.{.8O..s2..>....|
+00000100 07 e6 0f 3a ff 77 c5 9d 41 85 00 8a b6 9b ee b0 |...:.w..A.......|
+00000110 a4 3f 2d 4c 4c e6 42 3e bb 51 c8 dd 48 54 f4 0c |.?-LL.B>.Q..HT..|
+00000120 8e 47 02 03 01 00 01 a3 46 30 44 30 0e 06 03 55 |.G......F0D0...U|
+00000130 1d 0f 01 01 ff 04 04 03 02 05 a0 30 13 06 03 55 |...........0...U|
+00000140 1d 25 04 0c 30 0a 06 08 2b 06 01 05 05 07 03 01 |.%..0...+.......|
+00000150 30 0c 06 03 55 1d 13 01 01 ff 04 02 30 00 30 0f |0...U.......0.0.|
+00000160 06 03 55 1d 11 04 08 30 06 87 04 7f 00 00 01 30 |..U....0.......0|
+00000170 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 03 81 |...*.H..........|
+00000180 81 00 46 ab 44 a2 fb 28 54 f8 5a 67 f8 62 94 f1 |..F.D..(T.Zg.b..|
+00000190 9a b2 18 9e f2 b1 de 1d 7e 6f 76 95 a9 ba e7 5d |........~ov....]|
+000001a0 a8 16 6c 9c f7 09 d3 37 e4 4b 2b 36 7c 01 ad 41 |..l....7.K+6|..A|
+000001b0 d2 32 d8 c3 d2 93 f9 10 6b 8e 95 b9 2c 17 8a a3 |.2......k...,...|
+000001c0 44 48 bc 59 13 83 16 04 88 a4 81 5c 25 0d 98 0c |DH.Y.......\%...|
+000001d0 ac 11 b1 28 56 be 1d cd 61 62 84 09 bf d6 80 c6 |...(V...ab......|
+000001e0 45 8d 82 2c b4 d8 83 9b db c9 22 b7 2a 12 11 7b |E..,......".*..{|
+000001f0 fa 02 3b c1 c9 ff ea c9 9d a8 49 d3 95 d7 d5 0e |..;.......I.....|
+00000200 e5 35 16 03 03 00 25 10 00 00 21 20 2f e5 7d a3 |.5....%...! /.}.|
+00000210 47 cd 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 |G.bC.(.._.).0...|
+00000220 af c4 cf c2 ed 90 99 5f 58 cb 3b 74 16 03 03 00 |......._X.;t....|
+00000230 88 0f 00 00 84 05 01 00 80 05 9b 97 90 30 0b 21 |.............0.!|
+00000240 ed 52 16 19 e0 54 7d 59 42 17 94 81 9b 2c b6 5b |.R...T}YB....,.[|
+00000250 7f 7c 8e a5 bf 27 a9 25 14 74 f0 37 fa 6e 2b 84 |.|...'.%.t.7.n+.|
+00000260 80 a4 cd ae a6 8a 1b 62 2d 5e 03 ff 70 55 d7 99 |.......b-^..pU..|
+00000270 68 3c b3 0e 03 41 ae af c6 3e 09 d4 16 8e 06 71 |h<...A...>.....q|
+00000280 14 f8 90 97 cd f6 eb 7d 90 3c d1 f3 95 db 35 3c |.......}.<....5<|
+00000290 c9 7d dc 30 55 e1 a0 66 8e 26 20 4f 43 89 08 6f |.}.0U..f.& OC..o|
+000002a0 95 58 42 ae e8 6c b6 77 45 c6 8c c7 ad e5 ed ff |.XB..l.wE.......|
+000002b0 09 6f 2e 7e b0 e4 5c f2 db 14 03 03 00 01 01 16 |.o.~..\.........|
+000002c0 03 03 00 28 00 00 00 00 00 00 00 00 c0 2c cc 32 |...(.........,.2|
+000002d0 78 5e 6c 3e e9 a3 83 65 b4 bb 4e 79 b2 04 08 30 |x^l>...e..Ny...0|
+000002e0 09 e9 04 99 70 48 44 95 26 b0 37 c9 |....pHD.&.7.|
>>> Flow 4 (server to client)
-00000000 14 03 03 00 01 01 16 03 03 00 24 0b c5 7d ca a6 |..........$..}..|
-00000010 87 7f 50 7b 88 9c d9 8e ea 78 a0 40 6b 8e 92 0b |..P{.....x. at k...|
-00000020 78 88 97 46 ec 7c 20 5b 1f fc da 49 d8 6a be |x..F.| [...I.j.|
+00000000 14 03 03 00 01 01 16 03 03 00 28 5f 80 e2 f1 78 |..........(_...x|
+00000010 0f cb 58 5c 3c 50 4c 1e 33 8a 1f b7 89 92 37 11 |..X\<PL.3.....7.|
+00000020 a3 8a 76 39 4a 3d b0 1f a3 e9 ba 52 f8 2b e5 a3 |..v9J=.....R.+..|
+00000030 59 7c ac |Y|.|
>>> Flow 5 (client to server)
-00000000 17 03 03 00 1a 16 25 97 df 98 e4 d6 8e d1 2c 0c |......%.......,.|
-00000010 27 74 67 e5 b7 f1 c7 58 41 5f 04 f5 e4 74 dc 15 |'tg....XA_...t..|
-00000020 03 03 00 16 df 55 01 0d 53 5b b4 36 c7 88 8d b0 |.....U..S[.6....|
-00000030 22 53 ec 87 1b 07 c7 9d af 89 |"S........|
+00000000 17 03 03 00 1e 00 00 00 00 00 00 00 01 75 dc 54 |.............u.T|
+00000010 d9 c5 b1 c2 c9 64 9a ea 20 e5 76 61 6c 05 af 33 |.....d.. .val..3|
+00000020 6b bc d7 15 03 03 00 1a 00 00 00 00 00 00 00 02 |k...............|
+00000030 24 6b 03 76 d3 da d0 ee a6 32 c3 58 a1 5e a5 21 |$k.v.....2.X.^.!|
+00000040 b8 3a |.:|
diff --git a/src/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES b/src/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES
index c9b5351..5d795e7 100644
--- a/src/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES
+++ b/src/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES
@@ -1,19 +1,20 @@
>>> Flow 1 (client to server)
-00000000 16 03 01 00 85 01 00 00 81 03 03 00 00 00 00 00 |................|
+00000000 16 03 01 00 91 01 00 00 8d 03 03 00 00 00 00 00 |................|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
-00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 22 c0 2f |............."./|
-00000030 c0 2b c0 30 c0 2c c0 11 c0 07 c0 13 c0 09 c0 14 |.+.0.,..........|
-00000040 c0 0a 00 9c 00 9d 00 05 00 2f 00 35 c0 12 00 0a |........./.5....|
-00000050 01 00 00 36 00 05 00 05 01 00 00 00 00 00 0a 00 |...6............|
-00000060 08 00 06 00 17 00 18 00 19 00 0b 00 02 01 00 00 |................|
-00000070 0d 00 0e 00 0c 04 01 04 03 05 01 05 03 02 01 02 |................|
-00000080 03 ff 01 00 01 00 00 12 00 00 |..........|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2c cc a8 |.............,..|
+00000030 cc a9 c0 2f c0 2b c0 30 c0 2c c0 27 c0 13 c0 23 |.../.+.0.,.'...#|
+00000040 c0 09 c0 14 c0 0a 00 9c 00 9d 00 3c 00 2f 00 35 |...........<./.5|
+00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 38 00 05 |.............8..|
+00000060 00 05 01 00 00 00 00 00 0a 00 0a 00 08 00 1d 00 |................|
+00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 0e 00 |................|
+00000080 0c 04 01 04 03 05 01 05 03 02 01 02 03 ff 01 00 |................|
+00000090 01 00 00 12 00 00 |......|
>>> Flow 2 (server to client)
-00000000 16 03 03 00 59 02 00 00 55 03 03 8a ae 27 5b 39 |....Y...U....'[9|
-00000010 8b c4 a6 d5 fa 9e 67 9e 6c fe 53 ed ab ec e0 04 |......g.l.S.....|
-00000020 8d 7c f8 1f d0 db 2e cb 22 4d a1 20 ee 80 5f fc |.|......"M. .._.|
-00000030 f8 77 8a 23 23 c5 95 81 7f a6 12 f5 e0 19 91 50 |.w.##..........P|
-00000040 da 75 42 c2 eb 45 bf e2 a5 54 ed 6e c0 09 00 00 |.uB..E...T.n....|
+00000000 16 03 03 00 59 02 00 00 55 03 03 c3 2f 08 30 ba |....Y...U.../.0.|
+00000010 5d 9e 55 ef 23 f9 8a 0d 2f b4 25 02 5f c0 d2 c2 |].U.#.../.%._...|
+00000020 50 7c da db a4 ee 7c 18 df af aa 20 f3 a5 02 de |P|....|.... ....|
+00000030 54 9f ce b9 6d 69 66 5d 57 76 ff 18 91 d3 93 ab |T...mif]Wv......|
+00000040 39 13 29 4c b9 a7 3c db 7f 4d 97 fc c0 09 00 00 |9.)L..<..M......|
00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................|
00000060 03 02 0e 0b 00 02 0a 00 02 07 00 02 04 30 82 02 |.............0..|
00000070 00 30 82 01 62 02 09 00 b8 bf 2d 47 a0 d2 eb f4 |.0..b.....-G....|
@@ -48,43 +49,39 @@
00000240 13 83 0d 94 06 bb d4 37 7a f6 ec 7a c9 86 2e dd |.......7z..z....|
00000250 d7 11 69 7f 85 7c 56 de fb 31 78 2b e4 c7 78 0d |..i..|V..1x+..x.|
00000260 ae cb be 9e 4e 36 24 31 7b 6a 0f 39 95 12 07 8f |....N6$1{j.9....|
-00000270 2a 16 03 03 00 d7 0c 00 00 d3 03 00 17 41 04 3e |*............A.>|
-00000280 e3 d6 d6 7b d7 ec 6f 4b 88 50 53 26 5a 2b a6 69 |...{..oK.PS&Z+.i|
-00000290 25 6f 30 a7 c3 a5 39 5c e2 ca b6 35 a5 30 35 9a |%o0...9\...5.05.|
-000002a0 35 8f e3 65 bd 4c 47 30 72 9a 4b 32 c4 6d 01 c9 |5..e.LG0r.K2.m..|
-000002b0 a5 91 d1 cd 0b 79 e2 04 0f a9 9c c2 72 cd 58 04 |.....y......r.X.|
-000002c0 03 00 8a 30 81 87 02 41 70 01 8c dd 0a 32 db e3 |...0...Ap....2..|
-000002d0 0b 04 9c d0 64 a1 08 06 b1 cf e3 66 79 1f c0 c1 |....d......fy...|
-000002e0 14 34 87 a6 e5 52 11 20 12 24 a5 b6 c2 50 63 86 |.4...R. .$...Pc.|
-000002f0 31 6a e3 85 7d 19 2d 3b 68 bf b7 64 20 37 c7 f9 |1j..}.-;h..d 7..|
-00000300 76 38 b5 32 84 0b f9 b6 71 02 42 01 89 e3 93 85 |v8.2....q.B.....|
-00000310 d6 16 8e 44 66 72 d6 9f b3 b1 e9 22 ad 2e f8 49 |...Dfr....."...I|
-00000320 41 8f 80 f9 0e d4 fd de 35 67 cf 09 ba 65 f7 a1 |A.......5g...e..|
-00000330 17 a8 c0 b5 a3 cc c0 17 83 af 68 92 5b 5c a9 ce |..........h.[\..|
-00000340 ce 11 92 93 fe 39 b9 80 19 20 f2 b6 3b 16 03 03 |.....9... ..;...|
-00000350 00 04 0e 00 00 00 |......|
+00000270 2a 16 03 03 00 b6 0c 00 00 b2 03 00 1d 20 46 07 |*............ F.|
+00000280 78 fd 3b 0c e0 2c 96 f8 44 b9 e9 06 e9 66 17 35 |x.;..,..D....f.5|
+00000290 c0 92 87 51 f6 e3 d7 f5 09 50 56 c6 e9 3b 04 03 |...Q.....PV..;..|
+000002a0 00 8a 30 81 87 02 41 5d 88 4b fe eb 45 ee 5e 9f |..0...A].K..E.^.|
+000002b0 ec 20 90 1f 41 aa 47 87 f7 ae 46 71 dc 55 8b 2c |. ..A.G...Fq.U.,|
+000002c0 ce 70 5f ad 3e fa 3c c3 cb 77 d2 69 67 25 27 08 |.p_.>.<..w.ig%'.|
+000002d0 23 de 52 3c 0e 6c ca 8f 86 8f 61 cd 5b cf d8 42 |#.R<.l....a.[..B|
+000002e0 aa 5a 95 aa 4b d4 d9 f3 02 42 01 81 78 53 9c bd |.Z..K....B..xS..|
+000002f0 af 7e d9 be 26 07 24 11 ca 4b 1d dd 2b 49 ec 35 |.~..&.$..K..+I.5|
+00000300 25 8d 58 87 ad 80 4f 90 c7 f8 a4 b9 c2 75 b5 12 |%.X...O......u..|
+00000310 a7 2c 49 82 76 e8 ce c4 a7 23 68 75 fc 88 82 13 |.,I.v....#hu....|
+00000320 27 55 a7 50 3c d6 d0 ae e3 88 94 b4 16 03 03 00 |'U.P<...........|
+00000330 04 0e 00 00 00 |.....|
>>> Flow 3 (client to server)
-00000000 16 03 03 00 46 10 00 00 42 41 04 1e 18 37 ef 0d |....F...BA...7..|
-00000010 19 51 88 35 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd |.Q.5uq..T[....g.|
-00000020 a7 24 20 3e b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e |.$ >.V...(^.+-O.|
-00000030 f1 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 |...lK[.V.2B.X..I|
-00000040 a6 b5 68 1a 41 03 56 6b dc 5a 89 14 03 03 00 01 |..h.A.Vk.Z......|
-00000050 01 16 03 03 00 40 00 00 00 00 00 00 00 00 00 00 |..... at ..........|
-00000060 00 00 00 00 00 00 39 19 e6 fb c7 28 b4 c9 f5 ba |......9....(....|
-00000070 a2 44 0a 74 70 18 86 1f 5f c2 3d 99 f5 d7 17 04 |.D.tp..._.=.....|
-00000080 88 07 a5 06 01 6a 2c 13 55 0b fc 82 75 b5 24 54 |.....j,.U...u.$T|
-00000090 a0 63 9e f0 ce 92 |.c....|
+00000000 16 03 03 00 25 10 00 00 21 20 2f e5 7d a3 47 cd |....%...! /.}.G.|
+00000010 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af c4 |bC.(.._.).0.....|
+00000020 cf c2 ed 90 99 5f 58 cb 3b 74 14 03 03 00 01 01 |....._X.;t......|
+00000030 16 03 03 00 40 00 00 00 00 00 00 00 00 00 00 00 |.... at ...........|
+00000040 00 00 00 00 00 04 f4 cc a8 9f 48 44 ca 19 e6 4c |..........HD...L|
+00000050 3d 51 f2 29 40 0b 70 06 09 f0 69 5c 51 78 51 1e |=Q.)@.p...i\QxQ.|
+00000060 2b d1 47 22 8d d6 fb f5 41 bd e4 fd 3d f4 1b 48 |+.G"....A...=..H|
+00000070 44 96 2d 97 b9 |D.-..|
>>> Flow 4 (server to client)
-00000000 14 03 03 00 01 01 16 03 03 00 40 15 37 89 e6 1f |.......... at .7...|
-00000010 20 f6 91 b9 1f fb 29 e9 3e 07 ab c2 09 96 06 89 | .....).>.......|
-00000020 69 c2 dd 63 e1 24 5d cd af 08 e2 ed df 46 45 6b |i..c.$]......FEk|
-00000030 1e 9f 62 b6 89 27 04 3f fc f2 77 71 23 04 24 37 |..b..'.?..wq#.$7|
-00000040 74 8a 0a 64 a8 10 e3 1c dc 53 64 |t..d.....Sd|
+00000000 14 03 03 00 01 01 16 03 03 00 40 f1 a2 70 ba 50 |.......... at ..p.P|
+00000010 9d 7a 9f 8f c6 fb 7e 83 75 bd 94 cf e6 c1 4a f0 |.z....~.u.....J.|
+00000020 e6 54 e9 2c 30 23 a2 5c c2 09 32 d4 06 f7 54 e7 |.T.,0#.\..2...T.|
+00000030 ab 27 a6 66 ab 86 e6 2c 20 12 cf 61 4d ef 12 20 |.'.f..., ..aM.. |
+00000040 ba b6 42 39 b7 76 b9 1b fc f4 44 |..B9.v....D|
>>> Flow 5 (client to server)
00000000 17 03 03 00 30 00 00 00 00 00 00 00 00 00 00 00 |....0...........|
-00000010 00 00 00 00 00 ae 4e e7 3a 25 9d 8f fa 06 99 49 |......N.:%.....I|
-00000020 2e b8 0f 49 d0 54 2d 06 b4 d7 4c 60 51 f1 13 11 |...I.T-...L`Q...|
-00000030 c1 b3 f5 d0 bc 15 03 03 00 30 00 00 00 00 00 00 |.........0......|
-00000040 00 00 00 00 00 00 00 00 00 00 80 de bf db 10 74 |...............t|
-00000050 da 3f d8 77 ca 37 cc f3 96 bd d3 e1 34 9c f2 0a |.?.w.7......4...|
-00000060 70 60 5e 7c a4 7e c9 bd 89 5f |p`^|.~..._|
+00000010 00 00 00 00 00 0b 5b d0 ab 14 3f ae 1f 4b 12 25 |......[...?..K.%|
+00000020 05 2a 67 11 0c 17 42 1b b6 d2 af 16 40 26 fd 7b |.*g...B.....@&.{|
+00000030 d7 57 10 2a f8 15 03 03 00 30 00 00 00 00 00 00 |.W.*.....0......|
+00000040 00 00 00 00 00 00 00 00 00 00 83 54 64 d6 31 32 |...........Td.12|
+00000050 55 62 32 49 b9 54 7b e3 34 02 1c 75 e3 1b 5a 41 |Ub2I.T{.4..u..ZA|
+00000060 a2 cd 47 26 f0 ed c2 d5 41 34 |..G&....A4|
diff --git a/src/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES-GCM b/src/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES-GCM
index 48d822a..28a9ef7 100644
--- a/src/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES-GCM
+++ b/src/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES-GCM
@@ -1,19 +1,20 @@
>>> Flow 1 (client to server)
-00000000 16 03 01 00 85 01 00 00 81 03 03 00 00 00 00 00 |................|
+00000000 16 03 01 00 91 01 00 00 8d 03 03 00 00 00 00 00 |................|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
-00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 22 c0 2f |............."./|
-00000030 c0 2b c0 30 c0 2c c0 11 c0 07 c0 13 c0 09 c0 14 |.+.0.,..........|
-00000040 c0 0a 00 9c 00 9d 00 05 00 2f 00 35 c0 12 00 0a |........./.5....|
-00000050 01 00 00 36 00 05 00 05 01 00 00 00 00 00 0a 00 |...6............|
-00000060 08 00 06 00 17 00 18 00 19 00 0b 00 02 01 00 00 |................|
-00000070 0d 00 0e 00 0c 04 01 04 03 05 01 05 03 02 01 02 |................|
-00000080 03 ff 01 00 01 00 00 12 00 00 |..........|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2c cc a8 |.............,..|
+00000030 cc a9 c0 2f c0 2b c0 30 c0 2c c0 27 c0 13 c0 23 |.../.+.0.,.'...#|
+00000040 c0 09 c0 14 c0 0a 00 9c 00 9d 00 3c 00 2f 00 35 |...........<./.5|
+00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 38 00 05 |.............8..|
+00000060 00 05 01 00 00 00 00 00 0a 00 0a 00 08 00 1d 00 |................|
+00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 0e 00 |................|
+00000080 0c 04 01 04 03 05 01 05 03 02 01 02 03 ff 01 00 |................|
+00000090 01 00 00 12 00 00 |......|
>>> Flow 2 (server to client)
-00000000 16 03 03 00 59 02 00 00 55 03 03 42 ab c5 81 f5 |....Y...U..B....|
-00000010 c0 5b 73 64 f6 1b e0 59 30 b0 fd c5 e6 b3 57 f2 |.[sd...Y0.....W.|
-00000020 28 3f 5c d2 e8 05 7d a8 29 84 2e 20 8e 18 6b 52 |(?\...}.).. ..kR|
-00000030 1b ee 03 02 64 52 fb 24 44 4f 39 f2 d3 0f e6 9d |....dR.$DO9.....|
-00000040 50 31 31 b3 39 9e c1 3a b3 67 41 a0 c0 2b 00 00 |P11.9..:.gA..+..|
+00000000 16 03 03 00 59 02 00 00 55 03 03 72 81 c3 91 37 |....Y...U..r...7|
+00000010 54 37 fb 0f 2b 16 3b 7b bc a6 d9 2e e2 83 23 83 |T7..+.;{......#.|
+00000020 b3 67 cf 36 dc 65 8d a6 3d cb 72 20 ac b9 b9 48 |.g.6.e..=.r ...H|
+00000030 30 9d fe 67 09 39 f5 47 d2 9a c8 3e 22 02 50 5e |0..g.9.G...>".P^|
+00000040 fd 02 c9 ff c1 84 2e 2e ab 78 ef c6 c0 2b 00 00 |.........x...+..|
00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................|
00000060 03 02 0e 0b 00 02 0a 00 02 07 00 02 04 30 82 02 |.............0..|
00000070 00 30 82 01 62 02 09 00 b8 bf 2d 47 a0 d2 eb f4 |.0..b.....-G....|
@@ -48,38 +49,34 @@
00000240 13 83 0d 94 06 bb d4 37 7a f6 ec 7a c9 86 2e dd |.......7z..z....|
00000250 d7 11 69 7f 85 7c 56 de fb 31 78 2b e4 c7 78 0d |..i..|V..1x+..x.|
00000260 ae cb be 9e 4e 36 24 31 7b 6a 0f 39 95 12 07 8f |....N6$1{j.9....|
-00000270 2a 16 03 03 00 d8 0c 00 00 d4 03 00 17 41 04 7a |*............A.z|
-00000280 01 b4 2c 50 85 34 6e 2c 2c 52 bc fa cf 71 82 e5 |..,P.4n,,R...q..|
-00000290 98 8d b0 f1 65 5f 7d bc c8 1b 7c 84 3e 46 45 c5 |....e_}...|.>FE.|
-000002a0 43 0e 72 e1 90 63 40 26 1c 22 dc 9a 3b b8 12 26 |C.r..c@&."..;..&|
-000002b0 a9 d6 1c e1 44 cf c7 38 db 9e 1b d0 b9 bb 06 04 |....D..8........|
-000002c0 03 00 8b 30 81 88 02 42 01 6b af f8 34 ae 89 50 |...0...B.k..4..P|
-000002d0 df 44 20 16 0b f9 ef a9 99 63 39 48 39 08 69 2d |.D ......c9H9.i-|
-000002e0 2d 9d 8b 3a e8 8a 9c 2f e9 d2 85 f2 d3 54 53 ec |-..:.../.....TS.|
-000002f0 b7 18 5b b0 76 3c 38 02 85 cc 00 20 45 9d e7 ba |..[.v<8.... E...|
-00000300 c0 3f c0 b5 1f df 64 42 fd 34 02 42 00 fa e5 dd |.?....dB.4.B....|
-00000310 04 c4 60 60 ff 9b 95 a2 a4 b4 80 87 9f 59 b4 8e |..``.........Y..|
-00000320 72 bf 53 8e 61 b6 df 99 9d 81 05 c5 71 a2 00 cb |r.S.a.......q...|
-00000330 80 bd e5 2a c3 51 d0 45 2f a3 8b 6d 21 6e 6c 80 |...*.Q.E/..m!nl.|
-00000340 4e f1 28 23 6d 76 df 55 77 69 a1 be 39 05 16 03 |N.(#mv.Uwi..9...|
-00000350 03 00 04 0e 00 00 00 |.......|
+00000270 2a 16 03 03 00 b6 0c 00 00 b2 03 00 1d 20 b7 1c |*............ ..|
+00000280 2f 05 5e c8 ae 68 6b 54 c5 88 19 cf 7c 04 b2 ed |/.^..hkT....|...|
+00000290 8d 5a e9 7e 6b 50 8a ee 12 66 2d 6f e4 7a 04 03 |.Z.~kP...f-o.z..|
+000002a0 00 8a 30 81 87 02 42 01 8d 7e 23 bc d7 a7 ad 73 |..0...B..~#....s|
+000002b0 5f 45 9e 04 da 6e c0 34 a8 09 59 e3 bc ab 80 e1 |_E...n.4..Y.....|
+000002c0 d4 84 79 7d de 90 c1 f2 ea 95 ed fc 7e d3 f0 31 |..y}........~..1|
+000002d0 4c 9b da 82 a0 97 ed e6 c9 f2 b9 2a 0a 1e 0a 2c |L..........*...,|
+000002e0 7f 1d 62 ea 11 a9 77 5e 2f 02 41 09 88 2b eb 84 |..b...w^/.A..+..|
+000002f0 4f 62 9a c9 8a 0b a2 c6 88 0e 3e d9 29 f0 2b ba |Ob........>.).+.|
+00000300 08 40 b0 9c 17 70 d9 84 1e d3 39 ad 70 fc df 63 |. at ...p....9.p..c|
+00000310 a0 f6 69 3c 19 ce 0b a5 95 d2 6a b1 46 b1 e5 ba |..i<......j.F...|
+00000320 fd d2 67 4b 76 e3 eb b9 21 d0 7c 85 16 03 03 00 |..gKv...!.|.....|
+00000330 04 0e 00 00 00 |.....|
>>> Flow 3 (client to server)
-00000000 16 03 03 00 46 10 00 00 42 41 04 1e 18 37 ef 0d |....F...BA...7..|
-00000010 19 51 88 35 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd |.Q.5uq..T[....g.|
-00000020 a7 24 20 3e b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e |.$ >.V...(^.+-O.|
-00000030 f1 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 |...lK[.V.2B.X..I|
-00000040 a6 b5 68 1a 41 03 56 6b dc 5a 89 14 03 03 00 01 |..h.A.Vk.Z......|
-00000050 01 16 03 03 00 28 00 00 00 00 00 00 00 00 94 ba |.....(..........|
-00000060 0a c6 38 6b 65 60 95 5e df fc 42 7e ac 9f 5a 25 |..8ke`.^..B~..Z%|
-00000070 39 0e a9 7a 61 b3 17 80 77 82 e5 80 0a af |9..za...w.....|
+00000000 16 03 03 00 25 10 00 00 21 20 2f e5 7d a3 47 cd |....%...! /.}.G.|
+00000010 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af c4 |bC.(.._.).0.....|
+00000020 cf c2 ed 90 99 5f 58 cb 3b 74 14 03 03 00 01 01 |....._X.;t......|
+00000030 16 03 03 00 28 00 00 00 00 00 00 00 00 32 49 7e |....(........2I~|
+00000040 8f d6 2e 81 d7 03 a6 61 a3 04 98 81 95 84 58 d1 |.......a......X.|
+00000050 a2 33 fe 4a 5d cd 96 76 64 1e 1a 62 03 |.3.J]..vd..b.|
>>> Flow 4 (server to client)
-00000000 14 03 03 00 01 01 16 03 03 00 28 ef 8d ac 17 6f |..........(....o|
-00000010 88 03 88 8f f3 d5 a0 60 28 a9 4d e8 20 ae 0c 21 |.......`(.M. ..!|
-00000020 fd d1 50 9b c3 d1 e9 cd 27 ed d7 8b 92 60 49 47 |..P.....'....`IG|
-00000030 ed 9a 74 |..t|
+00000000 14 03 03 00 01 01 16 03 03 00 28 28 14 2d ae 7c |..........((.-.||
+00000010 b8 7d dc 27 b2 18 39 57 c8 be 5c 3d a3 ab fa 5a |.}.'..9W..\=...Z|
+00000020 3d 55 1b 3d 31 77 95 af 42 86 af 2b e7 5a 98 40 |=U.=1w..B..+.Z.@|
+00000030 18 77 d1 |.w.|
>>> Flow 5 (client to server)
-00000000 17 03 03 00 1e 00 00 00 00 00 00 00 01 1d 4f 3c |..............O<|
-00000010 c5 d1 39 01 46 ab 7d d1 75 59 e7 f5 cd fa 02 0b |..9.F.}.uY......|
-00000020 dd 02 17 15 03 03 00 1a 00 00 00 00 00 00 00 02 |................|
-00000030 e9 a5 d5 0c 05 2a 82 fe a5 6c 03 6e d0 c4 7d cb |.....*...l.n..}.|
-00000040 32 f3 |2.|
+00000000 17 03 03 00 1e 00 00 00 00 00 00 00 01 30 50 2f |.............0P/|
+00000010 36 4a 7c ee e6 f0 b9 b8 bf 4d e3 63 4d 5e 58 08 |6J|......M.cM^X.|
+00000020 ac ac 82 15 03 03 00 1a 00 00 00 00 00 00 00 02 |................|
+00000030 80 e2 42 ca 91 65 04 4e ca a8 6f 81 7c 30 c0 1f |..B..e.N..o.|0..|
+00000040 aa 7b |.{|
diff --git a/src/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES128-SHA256 b/src/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES128-SHA256
new file mode 100644
index 0000000..831fa21
--- /dev/null
+++ b/src/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES128-SHA256
@@ -0,0 +1,91 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 91 01 00 00 8d 03 03 00 00 00 00 00 |................|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2c cc a8 |.............,..|
+00000030 cc a9 c0 2f c0 2b c0 30 c0 2c c0 27 c0 13 c0 23 |.../.+.0.,.'...#|
+00000040 c0 09 c0 14 c0 0a 00 9c 00 9d 00 3c 00 2f 00 35 |...........<./.5|
+00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 38 00 05 |.............8..|
+00000060 00 05 01 00 00 00 00 00 0a 00 0a 00 08 00 1d 00 |................|
+00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 0e 00 |................|
+00000080 0c 04 01 04 03 05 01 05 03 02 01 02 03 ff 01 00 |................|
+00000090 01 00 00 12 00 00 |......|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 59 02 00 00 55 03 03 be c0 b6 d7 fe |....Y...U.......|
+00000010 43 9d 21 1f 89 27 bd db 0a 9a 5a 44 dd 79 d1 f2 |C.!..'....ZD.y..|
+00000020 18 9a 2a 04 8c eb e6 a9 93 ef ee 20 35 48 44 08 |..*........ 5HD.|
+00000030 8c 7a 3e f6 0f d7 5f 33 54 60 0b c9 65 4e 17 8d |.z>..._3T`..eN..|
+00000040 d2 69 b7 20 0b c5 ba 9a d4 b7 40 39 c0 23 00 00 |.i. ...... at 9.#..|
+00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................|
+00000060 03 02 0e 0b 00 02 0a 00 02 07 00 02 04 30 82 02 |.............0..|
+00000070 00 30 82 01 62 02 09 00 b8 bf 2d 47 a0 d2 eb f4 |.0..b.....-G....|
+00000080 30 09 06 07 2a 86 48 ce 3d 04 01 30 45 31 0b 30 |0...*.H.=..0E1.0|
+00000090 09 06 03 55 04 06 13 02 41 55 31 13 30 11 06 03 |...U....AU1.0...|
+000000a0 55 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 65 31 |U....Some-State1|
+000000b0 21 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 72 6e |!0...U....Intern|
+000000c0 65 74 20 57 69 64 67 69 74 73 20 50 74 79 20 4c |et Widgits Pty L|
+000000d0 74 64 30 1e 17 0d 31 32 31 31 32 32 31 35 30 36 |td0...1211221506|
+000000e0 33 32 5a 17 0d 32 32 31 31 32 30 31 35 30 36 33 |32Z..22112015063|
+000000f0 32 5a 30 45 31 0b 30 09 06 03 55 04 06 13 02 41 |2Z0E1.0...U....A|
+00000100 55 31 13 30 11 06 03 55 04 08 13 0a 53 6f 6d 65 |U1.0...U....Some|
+00000110 2d 53 74 61 74 65 31 21 30 1f 06 03 55 04 0a 13 |-State1!0...U...|
+00000120 18 49 6e 74 65 72 6e 65 74 20 57 69 64 67 69 74 |.Internet Widgit|
+00000130 73 20 50 74 79 20 4c 74 64 30 81 9b 30 10 06 07 |s Pty Ltd0..0...|
+00000140 2a 86 48 ce 3d 02 01 06 05 2b 81 04 00 23 03 81 |*.H.=....+...#..|
+00000150 86 00 04 00 c4 a1 ed be 98 f9 0b 48 73 36 7e c3 |...........Hs6~.|
+00000160 16 56 11 22 f2 3d 53 c3 3b 4d 21 3d cd 6b 75 e6 |.V.".=S.;M!=.ku.|
+00000170 f6 b0 dc 9a df 26 c1 bc b2 87 f0 72 32 7c b3 64 |.....&.....r2|.d|
+00000180 2f 1c 90 bc ea 68 23 10 7e fe e3 25 c0 48 3a 69 |/....h#.~..%.H:i|
+00000190 e0 28 6d d3 37 00 ef 04 62 dd 0d a0 9c 70 62 83 |.(m.7...b....pb.|
+000001a0 d8 81 d3 64 31 aa 9e 97 31 bd 96 b0 68 c0 9b 23 |...d1...1...h..#|
+000001b0 de 76 64 3f 1a 5c 7f e9 12 0e 58 58 b6 5f 70 dd |.vd?.\....XX._p.|
+000001c0 9b d8 ea d5 d7 f5 d5 cc b9 b6 9f 30 66 5b 66 9a |...........0f[f.|
+000001d0 20 e2 27 e5 bf fe 3b 30 09 06 07 2a 86 48 ce 3d | .'...;0...*.H.=|
+000001e0 04 01 03 81 8c 00 30 81 88 02 42 01 88 a2 4f eb |......0...B...O.|
+000001f0 e2 45 c5 48 7d 1b ac f5 ed 98 9d ae 47 70 c0 5e |.E.H}.......Gp.^|
+00000200 1b b6 2f bd f1 b6 4d b7 61 40 d3 11 a2 ce ee 0b |../...M.a at ......|
+00000210 7e 92 7e ff 76 9d c3 3b 7e a5 3f ce fa 10 e2 59 |~.~.v..;~.?....Y|
+00000220 ec 47 2d 7c ac da 4e 97 0e 15 a0 6f d0 02 42 01 |.G-|..N....o..B.|
+00000230 4d fc be 67 13 9c 2d 05 0e bd 3f a3 8c 25 c1 33 |M..g..-...?..%.3|
+00000240 13 83 0d 94 06 bb d4 37 7a f6 ec 7a c9 86 2e dd |.......7z..z....|
+00000250 d7 11 69 7f 85 7c 56 de fb 31 78 2b e4 c7 78 0d |..i..|V..1x+..x.|
+00000260 ae cb be 9e 4e 36 24 31 7b 6a 0f 39 95 12 07 8f |....N6$1{j.9....|
+00000270 2a 16 03 03 00 b7 0c 00 00 b3 03 00 1d 20 0e 53 |*............ .S|
+00000280 82 54 1a ba f8 a4 52 1d 6d b8 70 18 41 e8 67 f9 |.T....R.m.p.A.g.|
+00000290 38 1e fb fa b8 89 2d d6 4d 1b ae 67 fe 75 04 03 |8.....-.M..g.u..|
+000002a0 00 8b 30 81 88 02 42 01 68 0e d4 92 a6 1a d9 66 |..0...B.h......f|
+000002b0 ff 0e ca 4c 32 b8 78 d3 52 d1 ad a2 32 83 f0 3c |...L2.x.R...2..<|
+000002c0 43 e0 7e 92 94 e9 c6 99 00 d9 f7 06 c0 2c 72 c0 |C.~..........,r.|
+000002d0 9b f7 c0 ec 1f 23 8f b5 e5 74 9d ff 89 17 12 b4 |.....#...t......|
+000002e0 f1 f5 25 f7 2e 0d 78 f6 1c 02 42 01 fc da dd c8 |..%...x...B.....|
+000002f0 65 30 67 a3 ff 42 e3 37 19 ba 7c 04 6b a1 b3 97 |e0g..B.7..|.k...|
+00000300 b0 ca 8c 2d fc b0 40 1c a1 d8 c9 64 fe df 48 3b |...-.. at ....d..H;|
+00000310 07 57 1f 81 a2 3e a4 84 96 00 fb 55 29 1c 94 9d |.W...>.....U)...|
+00000320 f9 0d a4 71 4f 5f fd c3 22 e2 88 07 21 16 03 03 |...qO_.."...!...|
+00000330 00 04 0e 00 00 00 |......|
+>>> Flow 3 (client to server)
+00000000 16 03 03 00 25 10 00 00 21 20 2f e5 7d a3 47 cd |....%...! /.}.G.|
+00000010 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af c4 |bC.(.._.).0.....|
+00000020 cf c2 ed 90 99 5f 58 cb 3b 74 14 03 03 00 01 01 |....._X.;t......|
+00000030 16 03 03 00 50 00 00 00 00 00 00 00 00 00 00 00 |....P...........|
+00000040 00 00 00 00 00 7c e9 97 4b 98 8a 4c 59 95 3e 31 |.....|..K..LY.>1|
+00000050 c4 b6 e2 79 10 de bc 8e aa 1e 52 07 b2 e1 52 bc |...y......R...R.|
+00000060 3b da 8d 5f 12 6a 18 d1 0a 5d 93 1c ad bb f9 b7 |;.._.j...]......|
+00000070 6b 58 49 39 ea 3a 9e 20 47 69 43 b4 b4 d8 16 d0 |kXI9.:. GiC.....|
+00000080 f0 9d 36 74 04 |..6t.|
+>>> Flow 4 (server to client)
+00000000 14 03 03 00 01 01 16 03 03 00 50 60 d5 ac 39 b6 |..........P`..9.|
+00000010 58 50 03 90 9f c9 78 f1 45 43 b1 34 bd c8 29 65 |XP....x.EC.4..)e|
+00000020 54 38 7a 88 46 15 e8 a4 fb 9d 80 4e d6 45 e1 8d |T8z.F......N.E..|
+00000030 27 d6 09 66 1d ee 46 6d dd 8e 89 34 0f 4a fb fd |'..f..Fm...4.J..|
+00000040 bc 85 08 07 f0 5b 1c 24 e2 11 1b e2 a4 94 f5 80 |.....[.$........|
+00000050 fa 47 f4 62 0e b9 1c 31 cb 7b bf |.G.b...1.{.|
+>>> Flow 5 (client to server)
+00000000 17 03 03 00 40 00 00 00 00 00 00 00 00 00 00 00 |.... at ...........|
+00000010 00 00 00 00 00 37 b7 23 a2 06 97 f3 60 9a f0 7e |.....7.#....`..~|
+00000020 b7 11 6d 0d 66 0e db 38 1a eb cd 72 80 c8 54 ef |..m.f..8...r..T.|
+00000030 cf 90 6d 22 68 41 63 03 46 b9 28 4f 2f d6 fe fa |..m"hAc.F.(O/...|
+00000040 b2 91 07 36 71 15 03 03 00 40 00 00 00 00 00 00 |...6q.... at ......|
+00000050 00 00 00 00 00 00 00 00 00 00 ca 17 d9 fd 1a 0e |................|
+00000060 21 db a4 92 dc 92 e8 89 9d 14 6b 8a d3 ee a7 95 |!.........k.....|
+00000070 c0 91 8d 3c af 5a 48 d5 c6 2f 66 b8 b8 d4 ce f9 |...<.ZH../f.....|
+00000080 59 e5 e0 e2 df e5 7e ea 94 03 |Y.....~...|
diff --git a/src/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES256-GCM-SHA384 b/src/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES256-GCM-SHA384
index 2a16651..c22edd0 100644
--- a/src/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES256-GCM-SHA384
+++ b/src/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES256-GCM-SHA384
@@ -1,19 +1,20 @@
>>> Flow 1 (client to server)
-00000000 16 03 01 00 85 01 00 00 81 03 03 00 00 00 00 00 |................|
+00000000 16 03 01 00 91 01 00 00 8d 03 03 00 00 00 00 00 |................|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
-00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 22 c0 2f |............."./|
-00000030 c0 2b c0 30 c0 2c c0 11 c0 07 c0 13 c0 09 c0 14 |.+.0.,..........|
-00000040 c0 0a 00 9c 00 9d 00 05 00 2f 00 35 c0 12 00 0a |........./.5....|
-00000050 01 00 00 36 00 05 00 05 01 00 00 00 00 00 0a 00 |...6............|
-00000060 08 00 06 00 17 00 18 00 19 00 0b 00 02 01 00 00 |................|
-00000070 0d 00 0e 00 0c 04 01 04 03 05 01 05 03 02 01 02 |................|
-00000080 03 ff 01 00 01 00 00 12 00 00 |..........|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2c cc a8 |.............,..|
+00000030 cc a9 c0 2f c0 2b c0 30 c0 2c c0 27 c0 13 c0 23 |.../.+.0.,.'...#|
+00000040 c0 09 c0 14 c0 0a 00 9c 00 9d 00 3c 00 2f 00 35 |...........<./.5|
+00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 38 00 05 |.............8..|
+00000060 00 05 01 00 00 00 00 00 0a 00 0a 00 08 00 1d 00 |................|
+00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 0e 00 |................|
+00000080 0c 04 01 04 03 05 01 05 03 02 01 02 03 ff 01 00 |................|
+00000090 01 00 00 12 00 00 |......|
>>> Flow 2 (server to client)
-00000000 16 03 03 00 59 02 00 00 55 03 03 ed 6d 5a 1c 89 |....Y...U...mZ..|
-00000010 a4 f3 35 0b e4 74 7e e2 05 a5 36 4d 4a 55 b3 7c |..5..t~...6MJU.||
-00000020 a1 a6 42 a3 fc 35 8c e0 97 5b 4b 20 a1 4a 06 28 |..B..5...[K .J.(|
-00000030 4d 40 0b fc 47 d5 4d 9b d5 43 b0 0d 0d c6 ae 30 |M at ..G.M..C.....0|
-00000040 79 59 00 d4 90 96 98 92 d2 3a 57 07 c0 2c 00 00 |yY.......:W..,..|
+00000000 16 03 03 00 59 02 00 00 55 03 03 e6 0e 27 a7 58 |....Y...U....'.X|
+00000010 1d a3 1d 1d 21 64 31 f6 1e bc 28 b4 46 7e 26 be |....!d1...(.F~&.|
+00000020 de 0a 65 eb f0 18 dc 7f 3e 1b 55 20 fe 66 50 20 |..e.....>.U .fP |
+00000030 f0 f0 48 a8 db 0a ff ee 60 ea 3d 7f 07 5e b9 65 |..H.....`.=..^.e|
+00000040 c3 e4 2a 19 9c bd 57 36 ca e3 a7 2d c0 2c 00 00 |..*...W6...-.,..|
00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................|
00000060 03 02 0e 0b 00 02 0a 00 02 07 00 02 04 30 82 02 |.............0..|
00000070 00 30 82 01 62 02 09 00 b8 bf 2d 47 a0 d2 eb f4 |.0..b.....-G....|
@@ -48,38 +49,34 @@
00000240 13 83 0d 94 06 bb d4 37 7a f6 ec 7a c9 86 2e dd |.......7z..z....|
00000250 d7 11 69 7f 85 7c 56 de fb 31 78 2b e4 c7 78 0d |..i..|V..1x+..x.|
00000260 ae cb be 9e 4e 36 24 31 7b 6a 0f 39 95 12 07 8f |....N6$1{j.9....|
-00000270 2a 16 03 03 00 d7 0c 00 00 d3 03 00 17 41 04 89 |*............A..|
-00000280 e6 6d 6a 56 3e e5 4e 72 df 2b 41 11 de a0 c0 3e |.mjV>.Nr.+A....>|
-00000290 22 04 9a b5 a8 d6 22 30 2a e5 bd 83 1c 7a 8e 6c |"....."0*....z.l|
-000002a0 93 ab 8f d7 64 9e fe 89 c0 da 9a 45 7d 76 91 69 |....d......E}v.i|
-000002b0 0a 11 c5 59 26 49 ec 69 99 b3 91 a5 4b 2b 89 04 |...Y&I.i....K+..|
-000002c0 03 00 8a 30 81 87 02 42 01 17 1d ff 9a 99 76 20 |...0...B......v |
-000002d0 13 8a e1 5a a8 04 8a 1e 84 57 fd b0 95 c1 6c af |...Z.....W....l.|
-000002e0 b2 66 13 b5 75 36 ce 86 69 67 3d dc 82 2f 06 57 |.f..u6..ig=../.W|
-000002f0 19 14 56 54 0e 8e 04 74 0b 73 49 61 92 8e d1 9a |..VT...t.sIa....|
-00000300 b5 60 7f 65 a8 f8 99 eb ac 56 02 41 57 a3 78 57 |.`.e.....V.AW.xW|
-00000310 8a dd fa 9c 3d 24 a0 f2 0a 74 1a 8a 8f 6c 82 55 |....=$...t...l.U|
-00000320 4c cd d8 5d 79 99 87 93 41 e7 78 f4 28 0d ef 63 |L..]y...A.x.(..c|
-00000330 fb da 8e 93 86 31 6e 3e ca 6f 6b 1b fd 7a a3 86 |.....1n>.ok..z..|
-00000340 6e bb 17 35 90 d9 a4 df 12 d0 54 5e 25 16 03 03 |n..5......T^%...|
-00000350 00 04 0e 00 00 00 |......|
+00000270 2a 16 03 03 00 b7 0c 00 00 b3 03 00 1d 20 17 21 |*............ .!|
+00000280 a9 b8 65 8b aa 41 d2 d1 45 45 e5 ce 39 60 54 b6 |..e..A..EE..9`T.|
+00000290 43 9f c4 19 a4 aa ec 71 08 b0 d1 22 f7 46 04 03 |C......q...".F..|
+000002a0 00 8b 30 81 88 02 42 00 8b a5 d9 d3 8f a1 72 48 |..0...B.......rH|
+000002b0 06 42 25 c3 f6 c8 46 8d 88 30 36 7d d8 18 a9 cc |.B%...F..06}....|
+000002c0 de e4 c8 3f e9 d2 f0 88 18 cc c6 fb 14 e0 05 b1 |...?............|
+000002d0 ec 50 3d 57 b4 e9 83 57 55 4b 0d 2c 89 69 ff b1 |.P=W...WUK.,.i..|
+000002e0 58 0b 01 89 48 97 ee 88 7e 02 42 01 e1 6f 9c 36 |X...H...~.B..o.6|
+000002f0 6a 6c 86 24 d6 b3 45 f1 6c 03 d8 fd da d8 cc 52 |jl.$..E.l......R|
+00000300 04 41 7a c5 f9 b5 91 a5 6c d8 5a 03 ad de e3 da |.Az.....l.Z.....|
+00000310 de f8 db b0 bc 75 38 03 ab 84 ac 3f b2 c2 7e 6d |.....u8....?..~m|
+00000320 a7 2e c0 d9 bd 85 e2 7b 36 11 2b 12 14 16 03 03 |.......{6.+.....|
+00000330 00 04 0e 00 00 00 |......|
>>> Flow 3 (client to server)
-00000000 16 03 03 00 46 10 00 00 42 41 04 1e 18 37 ef 0d |....F...BA...7..|
-00000010 19 51 88 35 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd |.Q.5uq..T[....g.|
-00000020 a7 24 20 3e b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e |.$ >.V...(^.+-O.|
-00000030 f1 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 |...lK[.V.2B.X..I|
-00000040 a6 b5 68 1a 41 03 56 6b dc 5a 89 14 03 03 00 01 |..h.A.Vk.Z......|
-00000050 01 16 03 03 00 28 00 00 00 00 00 00 00 00 9d e7 |.....(..........|
-00000060 31 2a 0a 46 84 fd d9 18 c2 b0 b1 31 eb 63 4d 2d |1*.F.......1.cM-|
-00000070 ee 17 59 e6 b4 0f c6 d8 3d 8c e9 57 83 a8 |..Y.....=..W..|
+00000000 16 03 03 00 25 10 00 00 21 20 2f e5 7d a3 47 cd |....%...! /.}.G.|
+00000010 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af c4 |bC.(.._.).0.....|
+00000020 cf c2 ed 90 99 5f 58 cb 3b 74 14 03 03 00 01 01 |....._X.;t......|
+00000030 16 03 03 00 28 00 00 00 00 00 00 00 00 4b a3 cc |....(........K..|
+00000040 a1 5b 04 d4 1e 6c 2c 26 56 23 62 50 bc d6 90 0b |.[...l,&V#bP....|
+00000050 67 41 d9 7c 79 a5 53 54 73 0a 93 e2 73 |gA.|y.STs...s|
>>> Flow 4 (server to client)
-00000000 14 03 03 00 01 01 16 03 03 00 28 e0 85 25 02 b4 |..........(..%..|
-00000010 86 32 57 70 3c 7e 6b e5 75 e0 3a 43 c8 c2 fe f8 |.2Wp<~k.u.:C....|
-00000020 2e 04 fe 73 e4 7b 2c 9a e0 65 2e d6 53 ae f1 19 |...s.{,..e..S...|
-00000030 dd 6f 1a |.o.|
+00000000 14 03 03 00 01 01 16 03 03 00 28 e3 19 7b 8c 8a |..........(..{..|
+00000010 52 35 82 cc 70 50 83 22 88 8b 0a 54 bc eb ff 57 |R5..pP."...T...W|
+00000020 2c df 0d 50 d6 21 2f d2 d9 e8 15 27 b9 d7 01 a3 |,..P.!/....'....|
+00000030 f2 62 0b |.b.|
>>> Flow 5 (client to server)
-00000000 17 03 03 00 1e 00 00 00 00 00 00 00 01 29 b2 e6 |.............)..|
-00000010 c3 2e 72 ba cc ac d9 3b c7 0c 1d 53 b2 30 39 71 |..r....;...S.09q|
-00000020 6e dd 79 15 03 03 00 1a 00 00 00 00 00 00 00 02 |n.y.............|
-00000030 88 c9 92 fe 6c 1f 6c fd bd 7b fb 0a 8a b5 cc c9 |....l.l..{......|
-00000040 94 90 |..|
+00000000 17 03 03 00 1e 00 00 00 00 00 00 00 01 cc cf 92 |................|
+00000010 4d 25 58 96 1d dc df fb d9 1f a5 49 87 45 dd 73 |M%X........I.E.s|
+00000020 1a 17 ae 15 03 03 00 1a 00 00 00 00 00 00 00 02 |................|
+00000030 fb b5 c5 e4 aa ea e7 7e ff dd f7 11 63 c0 e4 a3 |.......~....c...|
+00000040 86 fc |..|
diff --git a/src/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-CHACHA20-POLY1305 b/src/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-CHACHA20-POLY1305
new file mode 100644
index 0000000..61e6657
--- /dev/null
+++ b/src/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-CHACHA20-POLY1305
@@ -0,0 +1,77 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 67 01 00 00 63 03 03 00 00 00 00 00 |....g...c.......|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 02 cc a9 |................|
+00000030 01 00 00 38 00 05 00 05 01 00 00 00 00 00 0a 00 |...8............|
+00000040 0a 00 08 00 1d 00 17 00 18 00 19 00 0b 00 02 01 |................|
+00000050 00 00 0d 00 0e 00 0c 04 01 04 03 05 01 05 03 02 |................|
+00000060 01 02 03 ff 01 00 01 00 00 12 00 00 |............|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 59 02 00 00 55 03 03 d6 47 27 38 fc |....Y...U...G'8.|
+00000010 16 92 2c 1f a6 53 a9 31 85 65 a7 83 0a 8f cb 4d |..,..S.1.e.....M|
+00000020 7d 5b df c1 2e b9 b1 08 e3 b9 96 20 16 0c e5 07 |}[......... ....|
+00000030 27 cc 4f 7d 11 ef 1a 14 c6 42 bf e9 c1 b7 a5 89 |'.O}.....B......|
+00000040 ca 2b 4c 30 4f c7 c8 10 13 b0 b1 6b cc a9 00 00 |.+L0O......k....|
+00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................|
+00000060 03 02 0e 0b 00 02 0a 00 02 07 00 02 04 30 82 02 |.............0..|
+00000070 00 30 82 01 62 02 09 00 b8 bf 2d 47 a0 d2 eb f4 |.0..b.....-G....|
+00000080 30 09 06 07 2a 86 48 ce 3d 04 01 30 45 31 0b 30 |0...*.H.=..0E1.0|
+00000090 09 06 03 55 04 06 13 02 41 55 31 13 30 11 06 03 |...U....AU1.0...|
+000000a0 55 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 65 31 |U....Some-State1|
+000000b0 21 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 72 6e |!0...U....Intern|
+000000c0 65 74 20 57 69 64 67 69 74 73 20 50 74 79 20 4c |et Widgits Pty L|
+000000d0 74 64 30 1e 17 0d 31 32 31 31 32 32 31 35 30 36 |td0...1211221506|
+000000e0 33 32 5a 17 0d 32 32 31 31 32 30 31 35 30 36 33 |32Z..22112015063|
+000000f0 32 5a 30 45 31 0b 30 09 06 03 55 04 06 13 02 41 |2Z0E1.0...U....A|
+00000100 55 31 13 30 11 06 03 55 04 08 13 0a 53 6f 6d 65 |U1.0...U....Some|
+00000110 2d 53 74 61 74 65 31 21 30 1f 06 03 55 04 0a 13 |-State1!0...U...|
+00000120 18 49 6e 74 65 72 6e 65 74 20 57 69 64 67 69 74 |.Internet Widgit|
+00000130 73 20 50 74 79 20 4c 74 64 30 81 9b 30 10 06 07 |s Pty Ltd0..0...|
+00000140 2a 86 48 ce 3d 02 01 06 05 2b 81 04 00 23 03 81 |*.H.=....+...#..|
+00000150 86 00 04 00 c4 a1 ed be 98 f9 0b 48 73 36 7e c3 |...........Hs6~.|
+00000160 16 56 11 22 f2 3d 53 c3 3b 4d 21 3d cd 6b 75 e6 |.V.".=S.;M!=.ku.|
+00000170 f6 b0 dc 9a df 26 c1 bc b2 87 f0 72 32 7c b3 64 |.....&.....r2|.d|
+00000180 2f 1c 90 bc ea 68 23 10 7e fe e3 25 c0 48 3a 69 |/....h#.~..%.H:i|
+00000190 e0 28 6d d3 37 00 ef 04 62 dd 0d a0 9c 70 62 83 |.(m.7...b....pb.|
+000001a0 d8 81 d3 64 31 aa 9e 97 31 bd 96 b0 68 c0 9b 23 |...d1...1...h..#|
+000001b0 de 76 64 3f 1a 5c 7f e9 12 0e 58 58 b6 5f 70 dd |.vd?.\....XX._p.|
+000001c0 9b d8 ea d5 d7 f5 d5 cc b9 b6 9f 30 66 5b 66 9a |...........0f[f.|
+000001d0 20 e2 27 e5 bf fe 3b 30 09 06 07 2a 86 48 ce 3d | .'...;0...*.H.=|
+000001e0 04 01 03 81 8c 00 30 81 88 02 42 01 88 a2 4f eb |......0...B...O.|
+000001f0 e2 45 c5 48 7d 1b ac f5 ed 98 9d ae 47 70 c0 5e |.E.H}.......Gp.^|
+00000200 1b b6 2f bd f1 b6 4d b7 61 40 d3 11 a2 ce ee 0b |../...M.a at ......|
+00000210 7e 92 7e ff 76 9d c3 3b 7e a5 3f ce fa 10 e2 59 |~.~.v..;~.?....Y|
+00000220 ec 47 2d 7c ac da 4e 97 0e 15 a0 6f d0 02 42 01 |.G-|..N....o..B.|
+00000230 4d fc be 67 13 9c 2d 05 0e bd 3f a3 8c 25 c1 33 |M..g..-...?..%.3|
+00000240 13 83 0d 94 06 bb d4 37 7a f6 ec 7a c9 86 2e dd |.......7z..z....|
+00000250 d7 11 69 7f 85 7c 56 de fb 31 78 2b e4 c7 78 0d |..i..|V..1x+..x.|
+00000260 ae cb be 9e 4e 36 24 31 7b 6a 0f 39 95 12 07 8f |....N6$1{j.9....|
+00000270 2a 16 03 03 00 b7 0c 00 00 b3 03 00 1d 20 69 78 |*............ ix|
+00000280 7b e5 14 95 c8 d1 3c 7e c2 d7 38 33 c3 9f 8f dc |{.....<~..83....|
+00000290 25 8d 89 8a 99 a4 e4 8b 40 17 fc 80 43 67 04 03 |%....... at ...Cg..|
+000002a0 00 8b 30 81 88 02 42 01 32 a8 dd d9 ec 11 d2 f2 |..0...B.2.......|
+000002b0 6d 86 da 31 00 8c bf ed 81 1d 8c c8 23 87 98 f7 |m..1........#...|
+000002c0 25 0c 1b 3d 9f 07 80 11 bc 07 b1 15 5f 3a 81 0e |%..=........_:..|
+000002d0 59 04 e8 09 be ea 21 97 34 a9 8a 2f ef 3a 47 ad |Y.....!.4../.:G.|
+000002e0 3b f9 9d f3 b8 b8 9a 93 03 02 42 01 bc 88 6b 99 |;.........B...k.|
+000002f0 d7 7a df de 5a 75 53 b0 3c 4c 1d 8b 15 c5 a7 9d |.z..ZuS.<L......|
+00000300 3d 00 c0 f7 19 47 88 30 00 29 24 80 23 45 88 2e |=....G.0.)$.#E..|
+00000310 11 60 3e 4b 6a 41 ad dc 3d 7d 3f 59 a0 0e fd d6 |.`>KjA..=}?Y....|
+00000320 f7 c7 7f 63 49 2f e4 4e d9 8f 2d e5 98 16 03 03 |...cI/.N..-.....|
+00000330 00 04 0e 00 00 00 |......|
+>>> Flow 3 (client to server)
+00000000 16 03 03 00 25 10 00 00 21 20 2f e5 7d a3 47 cd |....%...! /.}.G.|
+00000010 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af c4 |bC.(.._.).0.....|
+00000020 cf c2 ed 90 99 5f 58 cb 3b 74 14 03 03 00 01 01 |....._X.;t......|
+00000030 16 03 03 00 20 7c 89 36 36 77 8c 09 31 e4 48 01 |.... |.66w..1.H.|
+00000040 6f 08 27 a8 bb 1b 1c a6 0c 09 ec 0b f6 a3 be bd |o.'.............|
+00000050 76 70 fb f8 e5 |vp...|
+>>> Flow 4 (server to client)
+00000000 14 03 03 00 01 01 16 03 03 00 20 a0 db 6c df b1 |.......... ..l..|
+00000010 87 77 78 ad 22 b2 98 77 e8 57 aa 13 a8 98 35 63 |.wx."..w.W....5c|
+00000020 00 c5 13 b9 88 5d ca bf bc c5 c3 |.....].....|
+>>> Flow 5 (client to server)
+00000000 17 03 03 00 16 16 00 c8 c6 25 ae 11 9d a5 10 75 |.........%.....u|
+00000010 e4 4c e3 69 12 2b d9 9e 8e 40 88 15 03 03 00 12 |.L.i.+... at ......|
+00000020 cf ab ac d4 c4 8e 9c 92 c4 2f 1f c6 96 0b 36 c9 |........./....6.|
+00000030 f5 22 |."|
diff --git a/src/crypto/tls/testdata/Client-TLSv12-ECDHE-RSA-AES b/src/crypto/tls/testdata/Client-TLSv12-ECDHE-RSA-AES
index 29767b7..45728cf 100644
--- a/src/crypto/tls/testdata/Client-TLSv12-ECDHE-RSA-AES
+++ b/src/crypto/tls/testdata/Client-TLSv12-ECDHE-RSA-AES
@@ -1,95 +1,91 @@
>>> Flow 1 (client to server)
-00000000 16 03 01 00 85 01 00 00 81 03 03 00 00 00 00 00 |................|
+00000000 16 03 01 00 91 01 00 00 8d 03 03 00 00 00 00 00 |................|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
-00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 22 c0 2f |............."./|
-00000030 c0 2b c0 30 c0 2c c0 11 c0 07 c0 13 c0 09 c0 14 |.+.0.,..........|
-00000040 c0 0a 00 9c 00 9d 00 05 00 2f 00 35 c0 12 00 0a |........./.5....|
-00000050 01 00 00 36 00 05 00 05 01 00 00 00 00 00 0a 00 |...6............|
-00000060 08 00 06 00 17 00 18 00 19 00 0b 00 02 01 00 00 |................|
-00000070 0d 00 0e 00 0c 04 01 04 03 05 01 05 03 02 01 02 |................|
-00000080 03 ff 01 00 01 00 00 12 00 00 |..........|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2c cc a8 |.............,..|
+00000030 cc a9 c0 2f c0 2b c0 30 c0 2c c0 27 c0 13 c0 23 |.../.+.0.,.'...#|
+00000040 c0 09 c0 14 c0 0a 00 9c 00 9d 00 3c 00 2f 00 35 |...........<./.5|
+00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 38 00 05 |.............8..|
+00000060 00 05 01 00 00 00 00 00 0a 00 0a 00 08 00 1d 00 |................|
+00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 0e 00 |................|
+00000080 0c 04 01 04 03 05 01 05 03 02 01 02 03 ff 01 00 |................|
+00000090 01 00 00 12 00 00 |......|
>>> Flow 2 (server to client)
-00000000 16 03 03 00 59 02 00 00 55 03 03 2a 6a a8 b3 97 |....Y...U..*j...|
-00000010 d5 c8 5e b4 22 7e d0 a5 c7 46 af 89 60 44 77 5e |..^."~...F..`Dw^|
-00000020 1a f8 3a 30 08 6d 5f 4c 61 36 c5 20 57 79 91 3e |..:0.m_La6. Wy.>|
-00000030 1f 40 d1 f1 33 d7 a9 fb 93 eb 16 0d e1 39 e3 a3 |. at ..3........9..|
-00000040 80 e3 4f 58 a6 f8 a4 be 19 dd ef ee c0 13 00 00 |..OX............|
+00000000 16 03 03 00 59 02 00 00 55 03 03 2f 51 e0 81 eb |....Y...U../Q...|
+00000010 d2 db 4f 22 fa 11 d2 56 f3 06 d6 a0 97 d2 f3 74 |..O"...V.......t|
+00000020 fc a9 a7 73 ba a8 ee f2 05 89 15 20 0f 96 70 60 |...s....... ..p`|
+00000030 6f 78 aa 56 fa 92 5e e3 bc e7 f0 40 00 48 8b 84 |ox.V..^.... at .H..|
+00000040 57 b8 49 e9 f9 00 99 ff 73 29 f6 e7 c0 13 00 00 |W.I.....s)......|
00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................|
-00000060 03 02 71 0b 00 02 6d 00 02 6a 00 02 67 30 82 02 |..q...m..j..g0..|
-00000070 63 30 82 01 cc a0 03 02 01 02 02 09 00 a2 73 00 |c0............s.|
-00000080 0c 81 00 cb f3 30 0d 06 09 2a 86 48 86 f7 0d 01 |.....0...*.H....|
-00000090 01 0b 05 00 30 2b 31 17 30 15 06 03 55 04 0a 13 |....0+1.0...U...|
-000000a0 0e 47 6f 6f 67 6c 65 20 54 45 53 54 49 4e 47 31 |.Google TESTING1|
-000000b0 10 30 0e 06 03 55 04 03 13 07 47 6f 20 52 6f 6f |.0...U....Go Roo|
-000000c0 74 30 1e 17 0d 31 35 30 31 30 31 30 30 30 30 30 |t0...15010100000|
-000000d0 30 5a 17 0d 32 35 30 31 30 31 30 30 30 30 30 30 |0Z..250101000000|
-000000e0 5a 30 26 31 17 30 15 06 03 55 04 0a 13 0e 47 6f |Z0&1.0...U....Go|
-000000f0 6f 67 6c 65 20 54 45 53 54 49 4e 47 31 0b 30 09 |ogle TESTING1.0.|
-00000100 06 03 55 04 03 13 02 47 6f 30 81 9f 30 0d 06 09 |..U....Go0..0...|
-00000110 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 30 |*.H............0|
-00000120 81 89 02 81 81 00 af 87 88 f6 20 1b 95 65 6c 14 |.......... ..el.|
-00000130 ab 44 05 af 3b 45 14 e3 b7 6d fd 00 63 4d 95 7f |.D..;E...m..cM..|
-00000140 fe 6a 62 35 86 c0 4a f9 18 7c f6 aa 25 5e 7a 64 |.jb5..J..|..%^zd|
-00000150 31 66 00 ba f4 8e 92 af c7 6b d8 76 d4 f3 5f 41 |1f.......k.v.._A|
-00000160 cb 6e 56 15 97 1b 97 c1 3c 12 39 21 66 3d 2b 16 |.nV.....<.9!f=+.|
-00000170 d1 bc db 1c c0 a7 da b7 ca ad ba da cb d5 21 50 |..............!P|
-00000180 ec de 8d ab d1 6b 81 4b 89 02 f3 c4 be c1 6c 89 |.....k.K......l.|
-00000190 b1 44 84 bd 21 d1 04 7d 9d 16 4d f9 82 15 f6 ef |.D..!..}..M.....|
-000001a0 fa d6 09 47 f2 fb 02 03 01 00 01 a3 81 93 30 81 |...G..........0.|
-000001b0 90 30 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 05 |.0...U..........|
-000001c0 a0 30 1d 06 03 55 1d 25 04 16 30 14 06 08 2b 06 |.0...U.%..0...+.|
-000001d0 01 05 05 07 03 01 06 08 2b 06 01 05 05 07 03 02 |........+.......|
-000001e0 30 0c 06 03 55 1d 13 01 01 ff 04 02 30 00 30 19 |0...U.......0.0.|
-000001f0 06 03 55 1d 0e 04 12 04 10 12 50 8d 89 6f 1b d1 |..U.......P..o..|
-00000200 dc 54 4d 6e cb 69 5e 06 f4 30 1b 06 03 55 1d 23 |.TMn.i^..0...U.#|
-00000210 04 14 30 12 80 10 bf 3d b6 a9 66 f2 b8 40 cf ea |..0....=..f.. at ..|
-00000220 b4 03 78 48 1a 41 30 19 06 03 55 1d 11 04 12 30 |..xH.A0...U....0|
-00000230 10 82 0e 65 78 61 6d 70 6c 65 2e 67 6f 6c 61 6e |...example.golan|
-00000240 67 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 |g0...*.H........|
-00000250 03 81 81 00 92 7c af 91 55 12 18 96 59 31 a6 48 |.....|..U...Y1.H|
-00000260 40 d5 2d d5 ee bb 02 a0 f5 c2 1e 7c 9b b3 30 7d |@.-........|..0}|
-00000270 3c dc 76 da 4f 3d c0 fa ae 2d 33 24 6b 03 7b 1b |<.v.O=...-3$k.{.|
-00000280 67 59 11 21 b5 11 bc 77 b9 d9 e0 6e a8 2d 2e 35 |gY.!...w...n.-.5|
-00000290 fa 64 5f 22 3e 63 10 6b be ff 14 86 6d 0d f0 15 |.d_">c.k....m...|
-000002a0 31 a8 14 38 1e 3b 84 87 2c cb 98 ed 51 76 b9 b1 |1..8.;..,...Qv..|
-000002b0 4f dd db 9b 84 04 86 40 fa 51 dd ba b4 8d eb e3 |O...... at .Q......|
-000002c0 46 de 46 b9 4f 86 c7 f9 a4 c2 41 34 ac cc f6 ea |F.F.O.....A4....|
-000002d0 b0 ab 39 18 16 03 03 00 cd 0c 00 00 c9 03 00 17 |..9.............|
-000002e0 41 04 8e c8 e8 42 7c 8a 01 c2 ff 01 cb 0b e1 20 |A....B|........ |
-000002f0 50 42 d4 3a 1b 34 ff 74 59 81 2f a2 0e 29 b2 f9 |PB.:.4.tY./..)..|
-00000300 47 cf 0d 08 97 cf aa 9f fe f0 7f e8 f4 fd 3a fa |G.............:.|
-00000310 a6 b6 47 32 d3 25 78 87 bf 77 cc 12 37 02 6a ad |..G2.%x..w..7.j.|
-00000320 cf 2c 04 01 00 80 13 a1 95 17 7b 21 86 7f f2 02 |.,........{!....|
-00000330 9f ed 88 2d 1f 2c 38 96 bc fa 5a 39 85 4b 9f ff |...-.,8...Z9.K..|
-00000340 5c 7a 02 1e 5f c9 4a 69 51 d3 83 34 9f dc 8c 39 |\z.._.JiQ..4...9|
-00000350 fe 81 76 fc c3 59 ff e2 a8 81 ca 6f f6 52 c9 44 |..v..Y.....o.R.D|
-00000360 a0 3f 5e 5e 92 20 db d9 2e 0b e3 ab 75 e7 79 f6 |.?^^. ......u.y.|
-00000370 b2 73 17 e1 94 1e 12 62 e9 b0 0f 04 e7 5d 83 ac |.s.....b.....]..|
-00000380 71 ca a5 62 40 dd 69 b1 3f cf bb 3d c7 3e 51 6c |q..b at .i.?..=.>Ql|
-00000390 11 f2 cf 39 f1 b5 72 bd 52 d4 3d 3c c0 90 34 c8 |...9..r.R.=<..4.|
-000003a0 4b 22 55 39 1c 2b 16 03 03 00 04 0e 00 00 00 |K"U9.+.........|
+00000060 03 02 59 0b 00 02 55 00 02 52 00 02 4f 30 82 02 |..Y...U..R..O0..|
+00000070 4b 30 82 01 b4 a0 03 02 01 02 02 09 00 e8 f0 9d |K0..............|
+00000080 3f e2 5b ea a6 30 0d 06 09 2a 86 48 86 f7 0d 01 |?.[..0...*.H....|
+00000090 01 0b 05 00 30 1f 31 0b 30 09 06 03 55 04 0a 13 |....0.1.0...U...|
+000000a0 02 47 6f 31 10 30 0e 06 03 55 04 03 13 07 47 6f |.Go1.0...U....Go|
+000000b0 20 52 6f 6f 74 30 1e 17 0d 31 36 30 31 30 31 30 | Root0...1601010|
+000000c0 30 30 30 30 30 5a 17 0d 32 35 30 31 30 31 30 30 |00000Z..25010100|
+000000d0 30 30 30 30 5a 30 1a 31 0b 30 09 06 03 55 04 0a |0000Z0.1.0...U..|
+000000e0 13 02 47 6f 31 0b 30 09 06 03 55 04 03 13 02 47 |..Go1.0...U....G|
+000000f0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....|
+00000100 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 db 46 |.......0.......F|
+00000110 7d 93 2e 12 27 06 48 bc 06 28 21 ab 7e c4 b6 a2 |}...'.H..(!.~...|
+00000120 5d fe 1e 52 45 88 7a 36 47 a5 08 0d 92 42 5b c2 |]..RE.z6G....B[.|
+00000130 81 c0 be 97 79 98 40 fb 4f 6d 14 fd 2b 13 8b c2 |....y. at .Om..+...|
+00000140 a5 2e 67 d8 d4 09 9e d6 22 38 b7 4a 0b 74 73 2b |..g....."8.J.ts+|
+00000150 c2 34 f1 d1 93 e5 96 d9 74 7b f3 58 9f 6c 61 3c |.4......t{.X.la<|
+00000160 c0 b0 41 d4 d9 2b 2b 24 23 77 5b 1c 3b bd 75 5d |..A..++$#w[.;.u]|
+00000170 ce 20 54 cf a1 63 87 1d 1e 24 c4 f3 1d 1a 50 8b |. T..c...$....P.|
+00000180 aa b6 14 43 ed 97 a7 75 62 f4 14 c8 52 d7 02 03 |...C...ub...R...|
+00000190 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..|
+000001a0 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%|
+000001b0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........|
+000001c0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...|
+000001d0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....|
+000001e0 10 9f 91 16 1f 43 43 3e 49 a6 de 6d b6 80 d7 9f |.....CC>I..m....|
+000001f0 60 30 1b 06 03 55 1d 23 04 14 30 12 80 10 48 13 |`0...U.#..0...H.|
+00000200 49 4d 13 7e 16 31 bb a3 01 d5 ac ab 6e 7b 30 19 |IM.~.1......n{0.|
+00000210 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp|
+00000220 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H|
+00000230 86 f7 0d 01 01 0b 05 00 03 81 81 00 9d 30 cc 40 |.............0.@|
+00000240 2b 5b 50 a0 61 cb ba e5 53 58 e1 ed 83 28 a9 58 |+[P.a...SX...(.X|
+00000250 1a a9 38 a4 95 a1 ac 31 5a 1a 84 66 3d 43 d3 2d |..8....1Z..f=C.-|
+00000260 d9 0b f2 97 df d3 20 64 38 92 24 3a 00 bc cf 9c |...... d8.$:....|
+00000270 7d b7 40 20 01 5f aa d3 16 61 09 a2 76 fd 13 c3 |}.@ ._...a..v...|
+00000280 cc e1 0c 5c ee b1 87 82 f1 6c 04 ed 73 bb b3 43 |...\.....l..s..C|
+00000290 77 8d 0c 1c f1 0f a1 d8 40 83 61 c9 4c 72 2b 9d |w....... at .a.Lr+.|
+000002a0 ae db 46 06 06 4d f4 c1 b3 3e c0 d1 bd 42 d4 db |..F..M...>...B..|
+000002b0 fe 3d 13 60 84 5c 21 d3 3b e9 fa e7 16 03 03 00 |.=.`.\!.;.......|
+000002c0 ac 0c 00 00 a8 03 00 1d 20 48 77 87 3e 04 c9 14 |........ Hw.>...|
+000002d0 56 9d 1b 41 4b d0 eb 65 8d 56 56 97 fd 73 97 cd |V..AK..e.VV..s..|
+000002e0 c6 88 8f 8e 79 99 09 65 53 04 01 00 80 98 c2 ff |....y..eS.......|
+000002f0 49 aa 41 ce 0e 7b 03 99 39 c0 b5 ac 72 16 1c 5e |I.A..{..9...r..^|
+00000300 a0 92 f1 07 0c 93 dc f6 25 2b 5c be e3 65 41 a9 |........%+\..eA.|
+00000310 1e 57 6d 9f 28 50 ca 87 2f c7 b0 15 2e 15 d2 cc |.Wm.(P../.......|
+00000320 4d 0e 42 4c 0a 01 4d 1b 9c d1 17 e7 22 9a 6a a9 |M.BL..M.....".j.|
+00000330 27 0b 7a a7 32 e3 c7 5a d1 7f f2 1c 45 61 91 a8 |'.z.2..Z....Ea..|
+00000340 e0 e0 49 de b7 2f a6 89 63 94 ed 0e 63 15 6b 4f |..I../..c...c.kO|
+00000350 fb 62 c4 35 cb 98 89 c2 d1 bc f6 e2 2d 8f 9f 72 |.b.5........-..r|
+00000360 56 79 50 5f cd 73 00 f1 65 bf a4 3f 87 16 03 03 |VyP_.s..e..?....|
+00000370 00 04 0e 00 00 00 |......|
>>> Flow 3 (client to server)
-00000000 16 03 03 00 46 10 00 00 42 41 04 1e 18 37 ef 0d |....F...BA...7..|
-00000010 19 51 88 35 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd |.Q.5uq..T[....g.|
-00000020 a7 24 20 3e b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e |.$ >.V...(^.+-O.|
-00000030 f1 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 |...lK[.V.2B.X..I|
-00000040 a6 b5 68 1a 41 03 56 6b dc 5a 89 14 03 03 00 01 |..h.A.Vk.Z......|
-00000050 01 16 03 03 00 40 00 00 00 00 00 00 00 00 00 00 |..... at ..........|
-00000060 00 00 00 00 00 00 a2 6e de ea 78 0c 4d 20 ad 1f |.......n..x.M ..|
-00000070 1a f5 6b 15 09 f1 50 bb cd 40 0e c7 d9 ed 7f e1 |..k...P.. at ......|
-00000080 4b bc d3 26 5d 89 b7 26 c5 6c 0e 59 6f 84 51 5d |K..&]..&.l.Yo.Q]|
-00000090 2f 75 d8 0f 2e e8 |/u....|
+00000000 16 03 03 00 25 10 00 00 21 20 2f e5 7d a3 47 cd |....%...! /.}.G.|
+00000010 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af c4 |bC.(.._.).0.....|
+00000020 cf c2 ed 90 99 5f 58 cb 3b 74 14 03 03 00 01 01 |....._X.;t......|
+00000030 16 03 03 00 40 00 00 00 00 00 00 00 00 00 00 00 |.... at ...........|
+00000040 00 00 00 00 00 93 4b 37 8d 57 43 52 77 56 d2 af |......K7.WCRwV..|
+00000050 7c 56 d0 bf 1e 7b 29 55 3e b7 d0 1c 02 2e 0d de ||V...{)U>.......|
+00000060 09 66 f2 98 21 57 ab d2 d2 4a 73 c1 c5 fe f1 b8 |.f..!W...Js.....|
+00000070 95 d3 fc 70 ce |...p.|
>>> Flow 4 (server to client)
-00000000 14 03 03 00 01 01 16 03 03 00 40 dd d8 e7 63 89 |.......... at ...c.|
-00000010 8e cc 3e e0 df 6d 5a 42 b3 49 1b 66 e8 79 e9 f0 |..>..mZB.I.f.y..|
-00000020 8a c3 0e 5e d7 01 ac 04 81 6a e1 60 14 60 b9 a6 |...^.....j.`.`..|
-00000030 4c a5 46 43 74 df 30 1e f8 74 77 4c b5 42 e5 25 |L.FCt.0..twL.B.%|
-00000040 81 9d b1 04 bc 02 46 bd b1 55 d0 |......F..U.|
+00000000 14 03 03 00 01 01 16 03 03 00 40 b3 e1 81 3e 0a |.......... at ...>.|
+00000010 f8 f3 c6 05 c1 09 f5 73 01 eb 18 1a 05 fa 2f 9b |.......s....../.|
+00000020 b2 bc c7 44 23 38 ed b9 99 a0 56 7d 8b e4 a5 4b |...D#8....V}...K|
+00000030 f1 89 45 bc 95 ea 06 a8 48 de 07 bf d5 cb 53 bc |..E.....H.....S.|
+00000040 50 fa 25 fb d5 79 17 ec 4d be 3d |P.%..y..M.=|
>>> Flow 5 (client to server)
00000000 17 03 03 00 30 00 00 00 00 00 00 00 00 00 00 00 |....0...........|
-00000010 00 00 00 00 00 35 49 6d a7 3f a1 39 5d 37 8d 2e |.....5Im.?.9]7..|
-00000020 c5 1e 90 3b f9 60 58 d3 47 e3 db 73 8b aa 6c 9e |...;.`X.G..s..l.|
-00000030 b5 82 55 09 62 15 03 03 00 30 00 00 00 00 00 00 |..U.b....0......|
-00000040 00 00 00 00 00 00 00 00 00 00 71 b3 7b c7 d4 27 |..........q.{..'|
-00000050 f9 77 7f d0 80 25 1b 43 d0 0e 92 38 8c f3 2f 50 |.w...%.C...8../P|
-00000060 eb 96 22 fb e6 09 45 ec 7f 16 |.."...E...|
+00000010 00 00 00 00 00 3e 90 61 a4 f1 53 ac 7b b2 9f 4e |.....>.a..S.{..N|
+00000020 2c 16 5a 77 8b da 5d 68 5c 8b a8 6d 44 52 f3 ad |,.Zw..]h\..mDR..|
+00000030 8e ba c8 89 2f 15 03 03 00 30 00 00 00 00 00 00 |..../....0......|
+00000040 00 00 00 00 00 00 00 00 00 00 e5 01 5d ef 4c 0c |............].L.|
+00000050 07 8f 21 99 60 83 ee 36 13 8e 25 15 32 85 a5 96 |..!.`..6..%.2...|
+00000060 36 90 60 49 4f c7 54 99 dd 76 |6.`IO.T..v|
diff --git a/src/crypto/tls/testdata/Client-TLSv12-ECDHE-RSA-AES128-SHA256 b/src/crypto/tls/testdata/Client-TLSv12-ECDHE-RSA-AES128-SHA256
new file mode 100644
index 0000000..6b02249
--- /dev/null
+++ b/src/crypto/tls/testdata/Client-TLSv12-ECDHE-RSA-AES128-SHA256
@@ -0,0 +1,95 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 91 01 00 00 8d 03 03 00 00 00 00 00 |................|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2c cc a8 |.............,..|
+00000030 cc a9 c0 2f c0 2b c0 30 c0 2c c0 27 c0 13 c0 23 |.../.+.0.,.'...#|
+00000040 c0 09 c0 14 c0 0a 00 9c 00 9d 00 3c 00 2f 00 35 |...........<./.5|
+00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 38 00 05 |.............8..|
+00000060 00 05 01 00 00 00 00 00 0a 00 0a 00 08 00 1d 00 |................|
+00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 0e 00 |................|
+00000080 0c 04 01 04 03 05 01 05 03 02 01 02 03 ff 01 00 |................|
+00000090 01 00 00 12 00 00 |......|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 59 02 00 00 55 03 03 ab d3 05 5e d0 |....Y...U.....^.|
+00000010 80 0b 87 e9 43 26 e2 c9 28 04 3f eb 68 05 54 3d |....C&..(.?.h.T=|
+00000020 9b 28 d0 4e d4 d9 25 e5 b0 27 2b 20 89 27 da d5 |.(.N..%..'+ .'..|
+00000030 3d 19 38 63 01 34 f6 43 1b a9 f7 09 12 7d 27 e1 |=.8c.4.C.....}'.|
+00000040 f6 23 b8 39 24 8b 1e c7 a3 2f 07 16 c0 27 00 00 |.#.9$..../...'..|
+00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................|
+00000060 03 02 59 0b 00 02 55 00 02 52 00 02 4f 30 82 02 |..Y...U..R..O0..|
+00000070 4b 30 82 01 b4 a0 03 02 01 02 02 09 00 e8 f0 9d |K0..............|
+00000080 3f e2 5b ea a6 30 0d 06 09 2a 86 48 86 f7 0d 01 |?.[..0...*.H....|
+00000090 01 0b 05 00 30 1f 31 0b 30 09 06 03 55 04 0a 13 |....0.1.0...U...|
+000000a0 02 47 6f 31 10 30 0e 06 03 55 04 03 13 07 47 6f |.Go1.0...U....Go|
+000000b0 20 52 6f 6f 74 30 1e 17 0d 31 36 30 31 30 31 30 | Root0...1601010|
+000000c0 30 30 30 30 30 5a 17 0d 32 35 30 31 30 31 30 30 |00000Z..25010100|
+000000d0 30 30 30 30 5a 30 1a 31 0b 30 09 06 03 55 04 0a |0000Z0.1.0...U..|
+000000e0 13 02 47 6f 31 0b 30 09 06 03 55 04 03 13 02 47 |..Go1.0...U....G|
+000000f0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....|
+00000100 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 db 46 |.......0.......F|
+00000110 7d 93 2e 12 27 06 48 bc 06 28 21 ab 7e c4 b6 a2 |}...'.H..(!.~...|
+00000120 5d fe 1e 52 45 88 7a 36 47 a5 08 0d 92 42 5b c2 |]..RE.z6G....B[.|
+00000130 81 c0 be 97 79 98 40 fb 4f 6d 14 fd 2b 13 8b c2 |....y. at .Om..+...|
+00000140 a5 2e 67 d8 d4 09 9e d6 22 38 b7 4a 0b 74 73 2b |..g....."8.J.ts+|
+00000150 c2 34 f1 d1 93 e5 96 d9 74 7b f3 58 9f 6c 61 3c |.4......t{.X.la<|
+00000160 c0 b0 41 d4 d9 2b 2b 24 23 77 5b 1c 3b bd 75 5d |..A..++$#w[.;.u]|
+00000170 ce 20 54 cf a1 63 87 1d 1e 24 c4 f3 1d 1a 50 8b |. T..c...$....P.|
+00000180 aa b6 14 43 ed 97 a7 75 62 f4 14 c8 52 d7 02 03 |...C...ub...R...|
+00000190 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..|
+000001a0 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%|
+000001b0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........|
+000001c0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...|
+000001d0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....|
+000001e0 10 9f 91 16 1f 43 43 3e 49 a6 de 6d b6 80 d7 9f |.....CC>I..m....|
+000001f0 60 30 1b 06 03 55 1d 23 04 14 30 12 80 10 48 13 |`0...U.#..0...H.|
+00000200 49 4d 13 7e 16 31 bb a3 01 d5 ac ab 6e 7b 30 19 |IM.~.1......n{0.|
+00000210 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp|
+00000220 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H|
+00000230 86 f7 0d 01 01 0b 05 00 03 81 81 00 9d 30 cc 40 |.............0.@|
+00000240 2b 5b 50 a0 61 cb ba e5 53 58 e1 ed 83 28 a9 58 |+[P.a...SX...(.X|
+00000250 1a a9 38 a4 95 a1 ac 31 5a 1a 84 66 3d 43 d3 2d |..8....1Z..f=C.-|
+00000260 d9 0b f2 97 df d3 20 64 38 92 24 3a 00 bc cf 9c |...... d8.$:....|
+00000270 7d b7 40 20 01 5f aa d3 16 61 09 a2 76 fd 13 c3 |}.@ ._...a..v...|
+00000280 cc e1 0c 5c ee b1 87 82 f1 6c 04 ed 73 bb b3 43 |...\.....l..s..C|
+00000290 77 8d 0c 1c f1 0f a1 d8 40 83 61 c9 4c 72 2b 9d |w....... at .a.Lr+.|
+000002a0 ae db 46 06 06 4d f4 c1 b3 3e c0 d1 bd 42 d4 db |..F..M...>...B..|
+000002b0 fe 3d 13 60 84 5c 21 d3 3b e9 fa e7 16 03 03 00 |.=.`.\!.;.......|
+000002c0 ac 0c 00 00 a8 03 00 1d 20 ec 71 cc fb 07 bd 0f |........ .q.....|
+000002d0 6b e0 e1 27 7f 62 59 06 09 3c 09 bc b1 c9 09 93 |k..'.bY..<......|
+000002e0 e9 b0 a4 5b f3 be 14 d1 3c 04 01 00 80 a9 c7 98 |...[....<.......|
+000002f0 ea ac 6a 9b 49 7c 72 45 4d 5c c8 4c d6 56 64 1b |..j.I|rEM\.L.Vd.|
+00000300 44 7f 13 4f 2a ed e9 6b c7 c0 a2 25 3b 7a 99 f4 |D..O*..k...%;z..|
+00000310 93 84 35 78 72 21 ca f6 29 1b 60 d7 f6 bd 31 5b |..5xr!..).`...1[|
+00000320 7a fb 57 20 30 cc e6 90 07 b2 0e 08 82 86 56 a7 |z.W 0.........V.|
+00000330 55 00 fd f4 ce f4 b1 74 27 e9 0a 28 1c bc 56 47 |U......t'..(..VG|
+00000340 f7 18 3e 9e 9c 45 2d 1d 82 a8 66 51 27 25 be ec |..>..E-...fQ'%..|
+00000350 cd 9e 83 89 7e e0 e3 0f 3b 7b 32 f2 26 7b 30 c8 |....~...;{2.&{0.|
+00000360 c1 e3 7b 4c f4 14 d5 51 ea b7 45 7a 59 16 03 03 |..{L...Q..EzY...|
+00000370 00 04 0e 00 00 00 |......|
+>>> Flow 3 (client to server)
+00000000 16 03 03 00 25 10 00 00 21 20 2f e5 7d a3 47 cd |....%...! /.}.G.|
+00000010 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af c4 |bC.(.._.).0.....|
+00000020 cf c2 ed 90 99 5f 58 cb 3b 74 14 03 03 00 01 01 |....._X.;t......|
+00000030 16 03 03 00 50 00 00 00 00 00 00 00 00 00 00 00 |....P...........|
+00000040 00 00 00 00 00 76 d8 c4 58 a1 94 11 ab 19 4c 7b |.....v..X.....L{|
+00000050 7c 34 d1 b6 8b 7f a2 96 41 e6 e9 98 d8 55 62 2b ||4......A....Ub+|
+00000060 56 54 2a 65 25 f0 fa 15 ac cb b7 cc 3b 59 8b 99 |VT*e%.......;Y..|
+00000070 e9 be 9e fe 56 97 07 ae 39 38 a7 f4 f0 d0 e9 f5 |....V...98......|
+00000080 33 de 20 a6 04 |3. ..|
+>>> Flow 4 (server to client)
+00000000 14 03 03 00 01 01 16 03 03 00 50 8c 0f 2a be cd |..........P..*..|
+00000010 30 f7 46 cf 58 5b 38 88 86 5e d1 33 b1 61 d6 95 |0.F.X[8..^.3.a..|
+00000020 13 c7 e7 f2 fb bc 37 e5 a3 db ac a7 74 49 00 89 |......7.....tI..|
+00000030 db 94 25 aa 00 b6 b2 34 0a dd 97 bf fa cf 33 6e |..%....4......3n|
+00000040 6e f7 ab bf 70 a6 85 91 9b 4f f2 86 15 83 60 0d |n...p....O....`.|
+00000050 79 9e 11 51 17 a6 6f 06 2f 98 bc |y..Q..o./..|
+>>> Flow 5 (client to server)
+00000000 17 03 03 00 40 00 00 00 00 00 00 00 00 00 00 00 |.... at ...........|
+00000010 00 00 00 00 00 c3 c9 23 7b bd 57 1a 29 5f ac f6 |.......#{.W.)_..|
+00000020 8d bb 90 bb 48 8a 9a 75 65 3b 5b 52 c0 ee 0e 24 |....H..ue;[R...$|
+00000030 43 f6 62 1f 1e 51 36 4e 3e a3 e4 96 d8 2b d8 a7 |C.b..Q6N>....+..|
+00000040 d0 18 97 d7 1e 15 03 03 00 40 00 00 00 00 00 00 |......... at ......|
+00000050 00 00 00 00 00 00 00 00 00 00 c0 c8 9f 7d df b1 |.............}..|
+00000060 78 72 b5 3d 0d 3e d9 88 38 c2 42 eb 2b 4d e0 b3 |xr.=.>..8.B.+M..|
+00000070 d7 69 19 31 57 16 7c 0a bb 24 5b 9c 9b c2 4b b9 |.i.1W.|..$[...K.|
+00000080 55 ef ad 2c c1 eb 9b 59 06 5a |U..,...Y.Z|
diff --git a/src/crypto/tls/testdata/Client-TLSv12-ECDHE-RSA-CHACHA20-POLY1305 b/src/crypto/tls/testdata/Client-TLSv12-ECDHE-RSA-CHACHA20-POLY1305
new file mode 100644
index 0000000..64f999a
--- /dev/null
+++ b/src/crypto/tls/testdata/Client-TLSv12-ECDHE-RSA-CHACHA20-POLY1305
@@ -0,0 +1,81 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 67 01 00 00 63 03 03 00 00 00 00 00 |....g...c.......|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 02 cc a8 |................|
+00000030 01 00 00 38 00 05 00 05 01 00 00 00 00 00 0a 00 |...8............|
+00000040 0a 00 08 00 1d 00 17 00 18 00 19 00 0b 00 02 01 |................|
+00000050 00 00 0d 00 0e 00 0c 04 01 04 03 05 01 05 03 02 |................|
+00000060 01 02 03 ff 01 00 01 00 00 12 00 00 |............|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 59 02 00 00 55 03 03 45 f5 61 06 a8 |....Y...U..E.a..|
+00000010 4e ce c0 32 d6 af fb 12 5e c8 6c 06 ac c9 d7 e4 |N..2....^.l.....|
+00000020 02 49 09 b9 42 ee ae fa e4 52 18 20 12 3a 53 7d |.I..B....R. .:S}|
+00000030 11 cf 13 13 a3 f8 42 c3 98 bb bc a6 10 3e f4 13 |......B......>..|
+00000040 a5 a2 fd ef aa b3 01 3c cb 8a 3a 2c cc a8 00 00 |.......<..:,....|
+00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................|
+00000060 03 02 59 0b 00 02 55 00 02 52 00 02 4f 30 82 02 |..Y...U..R..O0..|
+00000070 4b 30 82 01 b4 a0 03 02 01 02 02 09 00 e8 f0 9d |K0..............|
+00000080 3f e2 5b ea a6 30 0d 06 09 2a 86 48 86 f7 0d 01 |?.[..0...*.H....|
+00000090 01 0b 05 00 30 1f 31 0b 30 09 06 03 55 04 0a 13 |....0.1.0...U...|
+000000a0 02 47 6f 31 10 30 0e 06 03 55 04 03 13 07 47 6f |.Go1.0...U....Go|
+000000b0 20 52 6f 6f 74 30 1e 17 0d 31 36 30 31 30 31 30 | Root0...1601010|
+000000c0 30 30 30 30 30 5a 17 0d 32 35 30 31 30 31 30 30 |00000Z..25010100|
+000000d0 30 30 30 30 5a 30 1a 31 0b 30 09 06 03 55 04 0a |0000Z0.1.0...U..|
+000000e0 13 02 47 6f 31 0b 30 09 06 03 55 04 03 13 02 47 |..Go1.0...U....G|
+000000f0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....|
+00000100 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 db 46 |.......0.......F|
+00000110 7d 93 2e 12 27 06 48 bc 06 28 21 ab 7e c4 b6 a2 |}...'.H..(!.~...|
+00000120 5d fe 1e 52 45 88 7a 36 47 a5 08 0d 92 42 5b c2 |]..RE.z6G....B[.|
+00000130 81 c0 be 97 79 98 40 fb 4f 6d 14 fd 2b 13 8b c2 |....y. at .Om..+...|
+00000140 a5 2e 67 d8 d4 09 9e d6 22 38 b7 4a 0b 74 73 2b |..g....."8.J.ts+|
+00000150 c2 34 f1 d1 93 e5 96 d9 74 7b f3 58 9f 6c 61 3c |.4......t{.X.la<|
+00000160 c0 b0 41 d4 d9 2b 2b 24 23 77 5b 1c 3b bd 75 5d |..A..++$#w[.;.u]|
+00000170 ce 20 54 cf a1 63 87 1d 1e 24 c4 f3 1d 1a 50 8b |. T..c...$....P.|
+00000180 aa b6 14 43 ed 97 a7 75 62 f4 14 c8 52 d7 02 03 |...C...ub...R...|
+00000190 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..|
+000001a0 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%|
+000001b0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........|
+000001c0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...|
+000001d0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....|
+000001e0 10 9f 91 16 1f 43 43 3e 49 a6 de 6d b6 80 d7 9f |.....CC>I..m....|
+000001f0 60 30 1b 06 03 55 1d 23 04 14 30 12 80 10 48 13 |`0...U.#..0...H.|
+00000200 49 4d 13 7e 16 31 bb a3 01 d5 ac ab 6e 7b 30 19 |IM.~.1......n{0.|
+00000210 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp|
+00000220 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H|
+00000230 86 f7 0d 01 01 0b 05 00 03 81 81 00 9d 30 cc 40 |.............0.@|
+00000240 2b 5b 50 a0 61 cb ba e5 53 58 e1 ed 83 28 a9 58 |+[P.a...SX...(.X|
+00000250 1a a9 38 a4 95 a1 ac 31 5a 1a 84 66 3d 43 d3 2d |..8....1Z..f=C.-|
+00000260 d9 0b f2 97 df d3 20 64 38 92 24 3a 00 bc cf 9c |...... d8.$:....|
+00000270 7d b7 40 20 01 5f aa d3 16 61 09 a2 76 fd 13 c3 |}.@ ._...a..v...|
+00000280 cc e1 0c 5c ee b1 87 82 f1 6c 04 ed 73 bb b3 43 |...\.....l..s..C|
+00000290 77 8d 0c 1c f1 0f a1 d8 40 83 61 c9 4c 72 2b 9d |w....... at .a.Lr+.|
+000002a0 ae db 46 06 06 4d f4 c1 b3 3e c0 d1 bd 42 d4 db |..F..M...>...B..|
+000002b0 fe 3d 13 60 84 5c 21 d3 3b e9 fa e7 16 03 03 00 |.=.`.\!.;.......|
+000002c0 ac 0c 00 00 a8 03 00 1d 20 57 53 06 53 e5 14 06 |........ WS.S...|
+000002d0 df 26 9d 3a 06 dc a9 d5 49 d3 3f 5f 7b c2 ab 77 |.&.:....I.?_{..w|
+000002e0 fd a1 fe 28 dc 54 36 06 22 04 01 00 80 da 23 f5 |...(.T6.".....#.|
+000002f0 19 de e8 d2 a9 79 b8 37 3d c0 8c ae f6 7c d5 d9 |.....y.7=....|..|
+00000300 87 ab 6b 3f 76 7c 5f 94 be 11 55 a3 78 66 1e e3 |..k?v|_...U.xf..|
+00000310 f3 11 3d 1a f7 02 26 a4 a6 cd 7c fe 87 0d 68 a1 |..=...&...|...h.|
+00000320 50 e8 7e 94 41 bd 5b 74 d0 6d 3b 6c ef ee 88 2d |P.~.A.[t.m;l...-|
+00000330 60 0a a9 53 cf 1f f4 03 a3 54 e5 91 36 50 62 54 |`..S.....T..6PbT|
+00000340 5f e6 e5 36 63 58 ba 7b bb 3a 79 59 58 08 a8 f2 |_..6cX.{.:yYX...|
+00000350 f5 1e 35 f8 f5 0f 7f 19 e7 7f 5f 56 e2 50 6d 8c |..5......._V.Pm.|
+00000360 da 45 70 60 0d 58 32 94 e7 a0 f7 da 93 16 03 03 |.Ep`.X2.........|
+00000370 00 04 0e 00 00 00 |......|
+>>> Flow 3 (client to server)
+00000000 16 03 03 00 25 10 00 00 21 20 2f e5 7d a3 47 cd |....%...! /.}.G.|
+00000010 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af c4 |bC.(.._.).0.....|
+00000020 cf c2 ed 90 99 5f 58 cb 3b 74 14 03 03 00 01 01 |....._X.;t......|
+00000030 16 03 03 00 20 9d 2f a6 b7 21 56 ad 38 a8 31 20 |.... ./..!V.8.1 |
+00000040 0b 2e dc 3f 8a 34 64 de 81 0e d3 a5 b1 c1 fc 05 |...?.4d.........|
+00000050 18 d9 3e 77 35 |..>w5|
+>>> Flow 4 (server to client)
+00000000 14 03 03 00 01 01 16 03 03 00 20 a8 82 60 8a ef |.......... ..`..|
+00000010 31 55 42 e9 1d 33 0e d8 a9 b1 43 85 1c 04 7b 20 |1UB..3....C...{ |
+00000020 81 df 03 e9 fd c0 f7 32 b9 b3 31 |.......2..1|
+>>> Flow 5 (client to server)
+00000000 17 03 03 00 16 ef 72 f7 1b 26 1a 47 99 f9 4c e7 |......r..&.G..L.|
+00000010 be 8e ab c5 8e ea 8c c6 60 6c 10 15 03 03 00 12 |........`l......|
+00000020 2c f4 39 e3 3a 74 a4 3c 72 63 77 e8 82 cf a9 e2 |,.9.:t.<rcw.....|
+00000030 2b 04 |+.|
diff --git a/src/crypto/tls/testdata/Client-TLSv12-RSA-RC4 b/src/crypto/tls/testdata/Client-TLSv12-RSA-RC4
index ffdc328..74282d4 100644
--- a/src/crypto/tls/testdata/Client-TLSv12-RSA-RC4
+++ b/src/crypto/tls/testdata/Client-TLSv12-RSA-RC4
@@ -1,79 +1,78 @@
>>> Flow 1 (client to server)
-00000000 16 03 01 00 85 01 00 00 81 03 03 00 00 00 00 00 |................|
+00000000 16 03 01 00 91 01 00 00 8d 03 03 00 00 00 00 00 |................|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
-00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 22 c0 2f |............."./|
-00000030 c0 2b c0 30 c0 2c c0 11 c0 07 c0 13 c0 09 c0 14 |.+.0.,..........|
-00000040 c0 0a 00 9c 00 9d 00 05 00 2f 00 35 c0 12 00 0a |........./.5....|
-00000050 01 00 00 36 00 05 00 05 01 00 00 00 00 00 0a 00 |...6............|
-00000060 08 00 06 00 17 00 18 00 19 00 0b 00 02 01 00 00 |................|
-00000070 0d 00 0e 00 0c 04 01 04 03 05 01 05 03 02 01 02 |................|
-00000080 03 ff 01 00 01 00 00 12 00 00 |..........|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2c cc a8 |.............,..|
+00000030 cc a9 c0 2f c0 2b c0 30 c0 2c c0 27 c0 13 c0 23 |.../.+.0.,.'...#|
+00000040 c0 09 c0 14 c0 0a 00 9c 00 9d 00 3c 00 2f 00 35 |...........<./.5|
+00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 38 00 05 |.............8..|
+00000060 00 05 01 00 00 00 00 00 0a 00 0a 00 08 00 1d 00 |................|
+00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 0e 00 |................|
+00000080 0c 04 01 04 03 05 01 05 03 02 01 02 03 ff 01 00 |................|
+00000090 01 00 00 12 00 00 |......|
>>> Flow 2 (server to client)
-00000000 16 03 03 00 51 02 00 00 4d 03 03 79 8f 56 ac 75 |....Q...M..y.V.u|
-00000010 4f a9 fc 2c b9 53 82 a6 b4 c8 0d 4e 50 9a 9e aa |O..,.S.....NP...|
-00000020 8d ed 21 21 91 5d a2 cc 99 1b 68 20 0c e7 35 50 |..!!.]....h ..5P|
-00000030 67 02 70 2a 45 0d 6c 4c 46 df 75 dc 5f 6e 2f 79 |g.p*E.lLF.u._n/y|
-00000040 03 26 da 45 53 25 50 23 c0 85 3b 8c 00 05 00 00 |.&.ES%P#..;.....|
-00000050 05 ff 01 00 01 00 16 03 03 02 71 0b 00 02 6d 00 |..........q...m.|
-00000060 02 6a 00 02 67 30 82 02 63 30 82 01 cc a0 03 02 |.j..g0..c0......|
-00000070 01 02 02 09 00 a2 73 00 0c 81 00 cb f3 30 0d 06 |......s......0..|
-00000080 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 2b 31 17 |.*.H........0+1.|
-00000090 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 |0...U....Google |
-000000a0 54 45 53 54 49 4e 47 31 10 30 0e 06 03 55 04 03 |TESTING1.0...U..|
-000000b0 13 07 47 6f 20 52 6f 6f 74 30 1e 17 0d 31 35 30 |..Go Root0...150|
-000000c0 31 30 31 30 30 30 30 30 30 5a 17 0d 32 35 30 31 |101000000Z..2501|
-000000d0 30 31 30 30 30 30 30 30 5a 30 26 31 17 30 15 06 |01000000Z0&1.0..|
-000000e0 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 54 45 53 |.U....Google TES|
-000000f0 54 49 4e 47 31 0b 30 09 06 03 55 04 03 13 02 47 |TING1.0...U....G|
-00000100 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....|
-00000110 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 af 87 |.......0........|
-00000120 88 f6 20 1b 95 65 6c 14 ab 44 05 af 3b 45 14 e3 |.. ..el..D..;E..|
-00000130 b7 6d fd 00 63 4d 95 7f fe 6a 62 35 86 c0 4a f9 |.m..cM...jb5..J.|
-00000140 18 7c f6 aa 25 5e 7a 64 31 66 00 ba f4 8e 92 af |.|..%^zd1f......|
-00000150 c7 6b d8 76 d4 f3 5f 41 cb 6e 56 15 97 1b 97 c1 |.k.v.._A.nV.....|
-00000160 3c 12 39 21 66 3d 2b 16 d1 bc db 1c c0 a7 da b7 |<.9!f=+.........|
-00000170 ca ad ba da cb d5 21 50 ec de 8d ab d1 6b 81 4b |......!P.....k.K|
-00000180 89 02 f3 c4 be c1 6c 89 b1 44 84 bd 21 d1 04 7d |......l..D..!..}|
-00000190 9d 16 4d f9 82 15 f6 ef fa d6 09 47 f2 fb 02 03 |..M........G....|
-000001a0 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..|
-000001b0 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%|
-000001c0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........|
-000001d0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...|
-000001e0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....|
-000001f0 10 12 50 8d 89 6f 1b d1 dc 54 4d 6e cb 69 5e 06 |..P..o...TMn.i^.|
-00000200 f4 30 1b 06 03 55 1d 23 04 14 30 12 80 10 bf 3d |.0...U.#..0....=|
-00000210 b6 a9 66 f2 b8 40 cf ea b4 03 78 48 1a 41 30 19 |..f.. at ....xH.A0.|
-00000220 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp|
-00000230 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H|
-00000240 86 f7 0d 01 01 0b 05 00 03 81 81 00 92 7c af 91 |.............|..|
-00000250 55 12 18 96 59 31 a6 48 40 d5 2d d5 ee bb 02 a0 |U...Y1.H at .-.....|
-00000260 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 da 4f 3d c0 fa |...|..0}<.v.O=..|
-00000270 ae 2d 33 24 6b 03 7b 1b 67 59 11 21 b5 11 bc 77 |.-3$k.{.gY.!...w|
-00000280 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f 22 3e 63 10 6b |...n.-.5.d_">c.k|
-00000290 be ff 14 86 6d 0d f0 15 31 a8 14 38 1e 3b 84 87 |....m...1..8.;..|
-000002a0 2c cb 98 ed 51 76 b9 b1 4f dd db 9b 84 04 86 40 |,...Qv..O......@|
-000002b0 fa 51 dd ba b4 8d eb e3 46 de 46 b9 4f 86 c7 f9 |.Q......F.F.O...|
-000002c0 a4 c2 41 34 ac cc f6 ea b0 ab 39 18 16 03 03 00 |..A4......9.....|
-000002d0 04 0e 00 00 00 |.....|
+00000000 16 03 03 00 51 02 00 00 4d 03 03 ac bf 85 b8 5f |....Q...M......_|
+00000010 56 44 a0 c5 3b 20 77 71 af de 34 bc 79 a0 a4 a7 |VD..; wq..4.y...|
+00000020 fa 2e cf b5 ee c5 a7 a2 5e 11 48 20 05 89 5e a6 |........^.H ..^.|
+00000030 cd ad 91 e4 be c3 c3 6c 6a 0e 1d ab 27 03 5e 0f |.......lj...'.^.|
+00000040 05 9d ef b0 63 8d 2d b6 29 08 66 e3 00 05 00 00 |....c.-.).f.....|
+00000050 05 ff 01 00 01 00 16 03 03 02 59 0b 00 02 55 00 |..........Y...U.|
+00000060 02 52 00 02 4f 30 82 02 4b 30 82 01 b4 a0 03 02 |.R..O0..K0......|
+00000070 01 02 02 09 00 e8 f0 9d 3f e2 5b ea a6 30 0d 06 |........?.[..0..|
+00000080 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 1f 31 0b |.*.H........0.1.|
+00000090 30 09 06 03 55 04 0a 13 02 47 6f 31 10 30 0e 06 |0...U....Go1.0..|
+000000a0 03 55 04 03 13 07 47 6f 20 52 6f 6f 74 30 1e 17 |.U....Go Root0..|
+000000b0 0d 31 36 30 31 30 31 30 30 30 30 30 30 5a 17 0d |.160101000000Z..|
+000000c0 32 35 30 31 30 31 30 30 30 30 30 30 5a 30 1a 31 |250101000000Z0.1|
+000000d0 0b 30 09 06 03 55 04 0a 13 02 47 6f 31 0b 30 09 |.0...U....Go1.0.|
+000000e0 06 03 55 04 03 13 02 47 6f 30 81 9f 30 0d 06 09 |..U....Go0..0...|
+000000f0 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 30 |*.H............0|
+00000100 81 89 02 81 81 00 db 46 7d 93 2e 12 27 06 48 bc |.......F}...'.H.|
+00000110 06 28 21 ab 7e c4 b6 a2 5d fe 1e 52 45 88 7a 36 |.(!.~...]..RE.z6|
+00000120 47 a5 08 0d 92 42 5b c2 81 c0 be 97 79 98 40 fb |G....B[.....y. at .|
+00000130 4f 6d 14 fd 2b 13 8b c2 a5 2e 67 d8 d4 09 9e d6 |Om..+.....g.....|
+00000140 22 38 b7 4a 0b 74 73 2b c2 34 f1 d1 93 e5 96 d9 |"8.J.ts+.4......|
+00000150 74 7b f3 58 9f 6c 61 3c c0 b0 41 d4 d9 2b 2b 24 |t{.X.la<..A..++$|
+00000160 23 77 5b 1c 3b bd 75 5d ce 20 54 cf a1 63 87 1d |#w[.;.u]. T..c..|
+00000170 1e 24 c4 f3 1d 1a 50 8b aa b6 14 43 ed 97 a7 75 |.$....P....C...u|
+00000180 62 f4 14 c8 52 d7 02 03 01 00 01 a3 81 93 30 81 |b...R.........0.|
+00000190 90 30 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 05 |.0...U..........|
+000001a0 a0 30 1d 06 03 55 1d 25 04 16 30 14 06 08 2b 06 |.0...U.%..0...+.|
+000001b0 01 05 05 07 03 01 06 08 2b 06 01 05 05 07 03 02 |........+.......|
+000001c0 30 0c 06 03 55 1d 13 01 01 ff 04 02 30 00 30 19 |0...U.......0.0.|
+000001d0 06 03 55 1d 0e 04 12 04 10 9f 91 16 1f 43 43 3e |..U..........CC>|
+000001e0 49 a6 de 6d b6 80 d7 9f 60 30 1b 06 03 55 1d 23 |I..m....`0...U.#|
+000001f0 04 14 30 12 80 10 48 13 49 4d 13 7e 16 31 bb a3 |..0...H.IM.~.1..|
+00000200 01 d5 ac ab 6e 7b 30 19 06 03 55 1d 11 04 12 30 |....n{0...U....0|
+00000210 10 82 0e 65 78 61 6d 70 6c 65 2e 67 6f 6c 61 6e |...example.golan|
+00000220 67 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 |g0...*.H........|
+00000230 03 81 81 00 9d 30 cc 40 2b 5b 50 a0 61 cb ba e5 |.....0. at +[P.a...|
+00000240 53 58 e1 ed 83 28 a9 58 1a a9 38 a4 95 a1 ac 31 |SX...(.X..8....1|
+00000250 5a 1a 84 66 3d 43 d3 2d d9 0b f2 97 df d3 20 64 |Z..f=C.-...... d|
+00000260 38 92 24 3a 00 bc cf 9c 7d b7 40 20 01 5f aa d3 |8.$:....}.@ ._..|
+00000270 16 61 09 a2 76 fd 13 c3 cc e1 0c 5c ee b1 87 82 |.a..v......\....|
+00000280 f1 6c 04 ed 73 bb b3 43 77 8d 0c 1c f1 0f a1 d8 |.l..s..Cw.......|
+00000290 40 83 61 c9 4c 72 2b 9d ae db 46 06 06 4d f4 c1 |@.a.Lr+...F..M..|
+000002a0 b3 3e c0 d1 bd 42 d4 db fe 3d 13 60 84 5c 21 d3 |.>...B...=.`.\!.|
+000002b0 3b e9 fa e7 16 03 03 00 04 0e 00 00 00 |;............|
>>> Flow 3 (client to server)
-00000000 16 03 03 00 86 10 00 00 82 00 80 73 bd 73 65 92 |...........s.se.|
-00000010 86 23 41 14 79 7f d5 c1 10 ce 94 4d ad 9c c3 a9 |.#A.y......M....|
-00000020 87 b5 32 52 f8 6b 11 93 2d 9b 98 0b 8b 1d c0 f6 |..2R.k..-.......|
-00000030 53 17 6d c7 9c 2e ae c9 6f cc 99 23 38 37 1a 10 |S.m.....o..#87..|
-00000040 fe 05 0b b5 55 0a 14 e9 60 7d 70 26 98 e2 54 d9 |....U...`}p&..T.|
-00000050 65 cf 2e f4 53 5f 1d aa 3a f6 33 7b eb 4c 0e b3 |e...S_..:.3{.L..|
-00000060 ff 5a db 36 2a 47 f3 df f9 fc f5 31 78 83 aa 6b |.Z.6*G.....1x..k|
-00000070 52 b7 ba 1a 96 bc fa c1 a1 a9 bb 2b f5 38 89 00 |R..........+.8..|
-00000080 4d e5 78 13 4e a4 38 46 42 dc 16 14 03 03 00 01 |M.x.N.8FB.......|
-00000090 01 16 03 03 00 24 72 bd b1 13 05 73 26 c0 0b ec |.....$r....s&...|
-000000a0 e6 39 08 6a 2d 87 00 51 58 9d e3 8d da be 60 98 |.9.j-..QX.....`.|
-000000b0 0a ee 0c 96 13 f4 e5 30 90 85 |.......0..|
+00000000 16 03 03 00 86 10 00 00 82 00 80 b9 65 8d bf a7 |............e...|
+00000010 c8 4b 79 ce 6f cb 8b 13 1c ac b9 7d 66 5e e9 ba |.Ky.o......}f^..|
+00000020 1d 71 4e a9 e9 34 ae f6 64 65 90 3b d8 16 52 a2 |.qN..4..de.;..R.|
+00000030 6f f4 cb 8a 13 74 a2 ee b7 27 69 b4 41 c0 90 68 |o....t...'i.A..h|
+00000040 bc 02 69 e1 c6 48 4f 39 36 30 25 ca 4c 17 ce 83 |..i..HO960%.L...|
+00000050 9e 08 56 e3 05 49 93 9e 2e c4 fb e6 c8 01 f1 0f |..V..I..........|
+00000060 c5 70 0f 08 83 48 e9 48 ef 6e 50 8b 05 7e e5 84 |.p...H.H.nP..~..|
+00000070 25 fa 55 c7 ae 31 02 27 00 ef 3f 98 86 20 12 89 |%.U..1.'..?.. ..|
+00000080 91 59 28 b4 f7 d7 af d2 69 61 35 14 03 03 00 01 |.Y(.....ia5.....|
+00000090 01 16 03 03 00 24 e1 ef 77 60 cf 7a 44 79 74 59 |.....$..w`.zDytY|
+000000a0 ff 81 72 b9 b5 f5 97 af 60 59 78 f5 01 49 2d bb |..r.....`Yx..I-.|
+000000b0 4a ec 98 1f f5 31 f4 00 a2 f3 |J....1....|
>>> Flow 4 (server to client)
-00000000 14 03 03 00 01 01 16 03 03 00 24 d4 ad ab a0 01 |..........$.....|
-00000010 1b 87 9c aa c4 27 08 b5 8c 4a 7f fc 03 df a6 d6 |.....'...J......|
-00000020 f8 6c d1 61 7c d3 1f 6d 18 c3 8d 88 5c 7b cf |.l.a|..m....\{.|
+00000000 14 03 03 00 01 01 16 03 03 00 24 52 fd a3 51 aa |..........$R..Q.|
+00000010 ee 9d 4d be 8c 08 32 f6 f7 4a a5 26 26 6c b2 5a |..M...2..J.&&l.Z|
+00000020 49 7f 31 7d 44 b1 83 67 19 4a e3 07 7d 59 34 |I.1}D..g.J..}Y4|
>>> Flow 5 (client to server)
-00000000 17 03 03 00 1a 33 a8 7a 61 46 09 7b 64 e6 aa f8 |.....3.zaF.{d...|
-00000010 8a 43 d3 a9 0c e9 2e c0 89 7c 72 fb 75 50 50 15 |.C.......|r.uPP.|
-00000020 03 03 00 16 2b b9 b5 eb f8 bd 53 20 ea 67 bc 47 |....+.....S .g.G|
-00000030 83 cf c5 6e f9 4f 9e 12 f5 1a |...n.O....|
+00000000 17 03 03 00 1a 61 73 4d 86 b2 a1 36 b2 3e b0 1d |.....asM...6.>..|
+00000010 6a b9 8a 8b 00 e0 3a d9 7e 23 c7 83 72 97 28 15 |j.....:.~#..r.(.|
+00000020 03 03 00 16 4a 8a 04 00 0a b2 75 80 20 ad 76 2a |....J.....u. .v*|
+00000030 88 16 56 e6 4a a5 c0 ea c7 0c |..V.J.....|
diff --git a/src/crypto/tls/testdata/Client-TLSv12-RenegotiateOnce b/src/crypto/tls/testdata/Client-TLSv12-RenegotiateOnce
index 00d35f4..8a9ac36 100644
--- a/src/crypto/tls/testdata/Client-TLSv12-RenegotiateOnce
+++ b/src/crypto/tls/testdata/Client-TLSv12-RenegotiateOnce
@@ -1,251 +1,231 @@
>>> Flow 1 (client to server)
-00000000 16 03 01 00 85 01 00 00 81 03 03 00 00 00 00 00 |................|
+00000000 16 03 01 00 91 01 00 00 8d 03 03 00 00 00 00 00 |................|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
-00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 22 c0 2f |............."./|
-00000030 c0 2b c0 30 c0 2c c0 11 c0 07 c0 13 c0 09 c0 14 |.+.0.,..........|
-00000040 c0 0a 00 9c 00 9d 00 05 00 2f 00 35 c0 12 00 0a |........./.5....|
-00000050 01 00 00 36 00 05 00 05 01 00 00 00 00 00 0a 00 |...6............|
-00000060 08 00 06 00 17 00 18 00 19 00 0b 00 02 01 00 00 |................|
-00000070 0d 00 0e 00 0c 04 01 04 03 05 01 05 03 02 01 02 |................|
-00000080 03 ff 01 00 01 00 00 12 00 00 |..........|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2c cc a8 |.............,..|
+00000030 cc a9 c0 2f c0 2b c0 30 c0 2c c0 27 c0 13 c0 23 |.../.+.0.,.'...#|
+00000040 c0 09 c0 14 c0 0a 00 9c 00 9d 00 3c 00 2f 00 35 |...........<./.5|
+00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 38 00 05 |.............8..|
+00000060 00 05 01 00 00 00 00 00 0a 00 0a 00 08 00 1d 00 |................|
+00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 0e 00 |................|
+00000080 0c 04 01 04 03 05 01 05 03 02 01 02 03 ff 01 00 |................|
+00000090 01 00 00 12 00 00 |......|
>>> Flow 2 (server to client)
-00000000 16 03 03 00 59 02 00 00 55 03 03 fa 71 0e 3c 35 |....Y...U...q.<5|
-00000010 33 cc 51 25 19 cf fe c4 ef c8 2d ec 88 75 a9 1c |3.Q%......-..u..|
-00000020 6a e4 f3 b4 3d fd 74 cc e1 71 71 20 de 14 e5 21 |j...=.t..qq ...!|
-00000030 84 17 62 62 4f 44 e7 c2 d6 00 07 d2 63 f8 b0 32 |..bbOD......c..2|
-00000040 e0 12 d3 cb 69 1f d8 ed 5d 43 89 86 c0 2f 00 00 |....i...]C.../..|
+00000000 16 03 03 00 59 02 00 00 55 03 03 16 d2 11 2e d6 |....Y...U.......|
+00000010 62 0c 5e 5c 9b 1f d2 31 87 b3 43 3e cd 47 4f f1 |b.^\...1..C>.GO.|
+00000020 0b a9 d1 4f f1 2a 42 5d 35 e0 ce 20 f2 f3 45 4b |...O.*B]5.. ..EK|
+00000030 98 2f 80 06 49 9a c3 4f 3f 70 0d e5 9a 2a 2e ff |./..I..O?p...*..|
+00000040 34 1b 0e 30 2c 85 52 e1 84 8c 3c dc cc a8 00 00 |4..0,.R...<.....|
00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................|
-00000060 03 02 71 0b 00 02 6d 00 02 6a 00 02 67 30 82 02 |..q...m..j..g0..|
-00000070 63 30 82 01 cc a0 03 02 01 02 02 09 00 a2 73 00 |c0............s.|
-00000080 0c 81 00 cb f3 30 0d 06 09 2a 86 48 86 f7 0d 01 |.....0...*.H....|
-00000090 01 0b 05 00 30 2b 31 17 30 15 06 03 55 04 0a 13 |....0+1.0...U...|
-000000a0 0e 47 6f 6f 67 6c 65 20 54 45 53 54 49 4e 47 31 |.Google TESTING1|
-000000b0 10 30 0e 06 03 55 04 03 13 07 47 6f 20 52 6f 6f |.0...U....Go Roo|
-000000c0 74 30 1e 17 0d 31 35 30 31 30 31 30 30 30 30 30 |t0...15010100000|
-000000d0 30 5a 17 0d 32 35 30 31 30 31 30 30 30 30 30 30 |0Z..250101000000|
-000000e0 5a 30 26 31 17 30 15 06 03 55 04 0a 13 0e 47 6f |Z0&1.0...U....Go|
-000000f0 6f 67 6c 65 20 54 45 53 54 49 4e 47 31 0b 30 09 |ogle TESTING1.0.|
-00000100 06 03 55 04 03 13 02 47 6f 30 81 9f 30 0d 06 09 |..U....Go0..0...|
-00000110 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 30 |*.H............0|
-00000120 81 89 02 81 81 00 af 87 88 f6 20 1b 95 65 6c 14 |.......... ..el.|
-00000130 ab 44 05 af 3b 45 14 e3 b7 6d fd 00 63 4d 95 7f |.D..;E...m..cM..|
-00000140 fe 6a 62 35 86 c0 4a f9 18 7c f6 aa 25 5e 7a 64 |.jb5..J..|..%^zd|
-00000150 31 66 00 ba f4 8e 92 af c7 6b d8 76 d4 f3 5f 41 |1f.......k.v.._A|
-00000160 cb 6e 56 15 97 1b 97 c1 3c 12 39 21 66 3d 2b 16 |.nV.....<.9!f=+.|
-00000170 d1 bc db 1c c0 a7 da b7 ca ad ba da cb d5 21 50 |..............!P|
-00000180 ec de 8d ab d1 6b 81 4b 89 02 f3 c4 be c1 6c 89 |.....k.K......l.|
-00000190 b1 44 84 bd 21 d1 04 7d 9d 16 4d f9 82 15 f6 ef |.D..!..}..M.....|
-000001a0 fa d6 09 47 f2 fb 02 03 01 00 01 a3 81 93 30 81 |...G..........0.|
-000001b0 90 30 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 05 |.0...U..........|
-000001c0 a0 30 1d 06 03 55 1d 25 04 16 30 14 06 08 2b 06 |.0...U.%..0...+.|
-000001d0 01 05 05 07 03 01 06 08 2b 06 01 05 05 07 03 02 |........+.......|
-000001e0 30 0c 06 03 55 1d 13 01 01 ff 04 02 30 00 30 19 |0...U.......0.0.|
-000001f0 06 03 55 1d 0e 04 12 04 10 12 50 8d 89 6f 1b d1 |..U.......P..o..|
-00000200 dc 54 4d 6e cb 69 5e 06 f4 30 1b 06 03 55 1d 23 |.TMn.i^..0...U.#|
-00000210 04 14 30 12 80 10 bf 3d b6 a9 66 f2 b8 40 cf ea |..0....=..f.. at ..|
-00000220 b4 03 78 48 1a 41 30 19 06 03 55 1d 11 04 12 30 |..xH.A0...U....0|
-00000230 10 82 0e 65 78 61 6d 70 6c 65 2e 67 6f 6c 61 6e |...example.golan|
-00000240 67 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 |g0...*.H........|
-00000250 03 81 81 00 92 7c af 91 55 12 18 96 59 31 a6 48 |.....|..U...Y1.H|
-00000260 40 d5 2d d5 ee bb 02 a0 f5 c2 1e 7c 9b b3 30 7d |@.-........|..0}|
-00000270 3c dc 76 da 4f 3d c0 fa ae 2d 33 24 6b 03 7b 1b |<.v.O=...-3$k.{.|
-00000280 67 59 11 21 b5 11 bc 77 b9 d9 e0 6e a8 2d 2e 35 |gY.!...w...n.-.5|
-00000290 fa 64 5f 22 3e 63 10 6b be ff 14 86 6d 0d f0 15 |.d_">c.k....m...|
-000002a0 31 a8 14 38 1e 3b 84 87 2c cb 98 ed 51 76 b9 b1 |1..8.;..,...Qv..|
-000002b0 4f dd db 9b 84 04 86 40 fa 51 dd ba b4 8d eb e3 |O...... at .Q......|
-000002c0 46 de 46 b9 4f 86 c7 f9 a4 c2 41 34 ac cc f6 ea |F.F.O.....A4....|
-000002d0 b0 ab 39 18 16 03 03 00 cd 0c 00 00 c9 03 00 17 |..9.............|
-000002e0 41 04 71 a0 a9 f0 31 52 0b a2 5f 44 b1 48 a6 dc |A.q...1R.._D.H..|
-000002f0 b7 b8 bb a3 59 13 06 46 73 37 b1 9d f6 5a 42 49 |....Y..Fs7...ZBI|
-00000300 a7 e4 3c 26 64 ed 26 41 f9 76 d5 88 ad b5 2f 12 |..<&d.&A.v..../.|
-00000310 ce 02 34 b8 85 36 ee cd a1 dc d9 d7 4b ed d2 81 |..4..6......K...|
-00000320 82 1e 04 01 00 80 86 91 0e 05 48 de 2b 45 0a 9d |..........H.+E..|
-00000330 72 33 44 73 98 f3 0e 0f 4c 0b aa c0 6b 02 34 83 |r3Ds....L...k.4.|
-00000340 0c e1 53 04 89 47 21 22 de 09 5e d0 b3 d9 8b 53 |..S..G!"..^....S|
-00000350 62 b0 bf c6 dd fe d3 ed d6 2e ac a0 64 9d a4 07 |b...........d...|
-00000360 1f a9 d5 89 5f 62 7f e0 b1 9b e2 ef 3e 36 89 70 |...._b......>6.p|
-00000370 3e 7c 0a e7 8c cb c3 a8 e0 91 d9 bd 6e 3d be 0e |>|..........n=..|
-00000380 a2 8c ab 46 1b 07 24 40 da a5 e3 0b b1 6a 9f 28 |...F..$@.....j.(|
-00000390 c7 4f e8 d0 a3 57 e1 5c f2 34 07 aa 77 28 91 a0 |.O...W.\.4..w(..|
-000003a0 7e d6 36 2c c3 1a 16 03 03 00 04 0e 00 00 00 |~.6,...........|
+00000060 03 02 59 0b 00 02 55 00 02 52 00 02 4f 30 82 02 |..Y...U..R..O0..|
+00000070 4b 30 82 01 b4 a0 03 02 01 02 02 09 00 e8 f0 9d |K0..............|
+00000080 3f e2 5b ea a6 30 0d 06 09 2a 86 48 86 f7 0d 01 |?.[..0...*.H....|
+00000090 01 0b 05 00 30 1f 31 0b 30 09 06 03 55 04 0a 13 |....0.1.0...U...|
+000000a0 02 47 6f 31 10 30 0e 06 03 55 04 03 13 07 47 6f |.Go1.0...U....Go|
+000000b0 20 52 6f 6f 74 30 1e 17 0d 31 36 30 31 30 31 30 | Root0...1601010|
+000000c0 30 30 30 30 30 5a 17 0d 32 35 30 31 30 31 30 30 |00000Z..25010100|
+000000d0 30 30 30 30 5a 30 1a 31 0b 30 09 06 03 55 04 0a |0000Z0.1.0...U..|
+000000e0 13 02 47 6f 31 0b 30 09 06 03 55 04 03 13 02 47 |..Go1.0...U....G|
+000000f0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....|
+00000100 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 db 46 |.......0.......F|
+00000110 7d 93 2e 12 27 06 48 bc 06 28 21 ab 7e c4 b6 a2 |}...'.H..(!.~...|
+00000120 5d fe 1e 52 45 88 7a 36 47 a5 08 0d 92 42 5b c2 |]..RE.z6G....B[.|
+00000130 81 c0 be 97 79 98 40 fb 4f 6d 14 fd 2b 13 8b c2 |....y. at .Om..+...|
+00000140 a5 2e 67 d8 d4 09 9e d6 22 38 b7 4a 0b 74 73 2b |..g....."8.J.ts+|
+00000150 c2 34 f1 d1 93 e5 96 d9 74 7b f3 58 9f 6c 61 3c |.4......t{.X.la<|
+00000160 c0 b0 41 d4 d9 2b 2b 24 23 77 5b 1c 3b bd 75 5d |..A..++$#w[.;.u]|
+00000170 ce 20 54 cf a1 63 87 1d 1e 24 c4 f3 1d 1a 50 8b |. T..c...$....P.|
+00000180 aa b6 14 43 ed 97 a7 75 62 f4 14 c8 52 d7 02 03 |...C...ub...R...|
+00000190 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..|
+000001a0 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%|
+000001b0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........|
+000001c0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...|
+000001d0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....|
+000001e0 10 9f 91 16 1f 43 43 3e 49 a6 de 6d b6 80 d7 9f |.....CC>I..m....|
+000001f0 60 30 1b 06 03 55 1d 23 04 14 30 12 80 10 48 13 |`0...U.#..0...H.|
+00000200 49 4d 13 7e 16 31 bb a3 01 d5 ac ab 6e 7b 30 19 |IM.~.1......n{0.|
+00000210 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp|
+00000220 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H|
+00000230 86 f7 0d 01 01 0b 05 00 03 81 81 00 9d 30 cc 40 |.............0.@|
+00000240 2b 5b 50 a0 61 cb ba e5 53 58 e1 ed 83 28 a9 58 |+[P.a...SX...(.X|
+00000250 1a a9 38 a4 95 a1 ac 31 5a 1a 84 66 3d 43 d3 2d |..8....1Z..f=C.-|
+00000260 d9 0b f2 97 df d3 20 64 38 92 24 3a 00 bc cf 9c |...... d8.$:....|
+00000270 7d b7 40 20 01 5f aa d3 16 61 09 a2 76 fd 13 c3 |}.@ ._...a..v...|
+00000280 cc e1 0c 5c ee b1 87 82 f1 6c 04 ed 73 bb b3 43 |...\.....l..s..C|
+00000290 77 8d 0c 1c f1 0f a1 d8 40 83 61 c9 4c 72 2b 9d |w....... at .a.Lr+.|
+000002a0 ae db 46 06 06 4d f4 c1 b3 3e c0 d1 bd 42 d4 db |..F..M...>...B..|
+000002b0 fe 3d 13 60 84 5c 21 d3 3b e9 fa e7 16 03 03 00 |.=.`.\!.;.......|
+000002c0 ac 0c 00 00 a8 03 00 1d 20 63 85 d4 43 2a d6 9f |........ c..C*..|
+000002d0 2f 1f 0c 73 fe dc 96 1e 51 50 a5 0d 5e fd b0 5b |/..s....QP..^..[|
+000002e0 a5 88 2a cd 1e bf c1 ec 4d 04 01 00 80 90 fc 48 |..*.....M......H|
+000002f0 53 eb 1b bc ec 39 be ae 60 4d c9 d1 49 eb 97 cf |S....9..`M..I...|
+00000300 94 53 75 30 84 35 ff 0c f6 ad 9f 24 98 70 2b d3 |.Su0.5.....$.p+.|
+00000310 45 0a 7f 25 ca a3 eb 37 5a a5 97 f1 78 8b b6 02 |E..%...7Z...x...|
+00000320 92 f9 12 9e 90 52 36 0e 40 15 76 de 37 02 c5 22 |.....R6. at .v.7.."|
+00000330 44 8f a4 fc f9 ac 88 88 ad 0c 9b f6 0e d6 9f f3 |D...............|
+00000340 68 cb f1 41 dd 2d c2 71 b6 43 36 12 d2 35 1c 9a |h..A.-.q.C6..5..|
+00000350 a9 72 ea af a9 9e 77 19 16 86 be 3e ec 5f 5a 53 |.r....w....>._ZS|
+00000360 f8 38 27 7f 08 2a ae 68 e0 17 31 df 9b 16 03 03 |.8'..*.h..1.....|
+00000370 00 04 0e 00 00 00 |......|
>>> Flow 3 (client to server)
-00000000 16 03 03 00 46 10 00 00 42 41 04 1e 18 37 ef 0d |....F...BA...7..|
-00000010 19 51 88 35 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd |.Q.5uq..T[....g.|
-00000020 a7 24 20 3e b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e |.$ >.V...(^.+-O.|
-00000030 f1 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 |...lK[.V.2B.X..I|
-00000040 a6 b5 68 1a 41 03 56 6b dc 5a 89 14 03 03 00 01 |..h.A.Vk.Z......|
-00000050 01 16 03 03 00 28 00 00 00 00 00 00 00 00 53 c5 |.....(........S.|
-00000060 60 30 29 1d 8a 38 57 f3 6d d1 f4 e1 ec 3e 79 d1 |`0)..8W.m....>y.|
-00000070 79 d3 b8 7f 4e 71 41 d6 72 fa c0 cd 53 92 |y...NqA.r...S.|
+00000000 16 03 03 00 25 10 00 00 21 20 2f e5 7d a3 47 cd |....%...! /.}.G.|
+00000010 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af c4 |bC.(.._.).0.....|
+00000020 cf c2 ed 90 99 5f 58 cb 3b 74 14 03 03 00 01 01 |....._X.;t......|
+00000030 16 03 03 00 20 b1 f2 9a ca 02 d3 ac 26 f5 32 03 |.... .......&.2.|
+00000040 4c b6 de cb f2 a3 11 19 eb c3 e0 e9 3b 8e 99 7d |L...........;..}|
+00000050 c2 f3 d0 6d 4d |...mM|
>>> Flow 4 (server to client)
-00000000 14 03 03 00 01 01 16 03 03 00 28 86 be df d2 27 |..........(....'|
-00000010 8b 37 77 eb 0b e4 6e 38 5c 27 56 48 bb b5 f2 be |.7w...n8\'VH....|
-00000020 43 e5 f7 32 d2 d3 a1 d7 4e 6a 3c 76 17 94 c1 b0 |C..2....Nj<v....|
-00000030 06 af 67 |..g|
+00000000 14 03 03 00 01 01 16 03 03 00 20 c5 d4 b1 e2 0f |.......... .....|
+00000010 37 ad d5 c1 1a 6c 7f da 5f 25 e3 bd 20 1d 6e 58 |7....l.._%.. .nX|
+00000020 27 7a 07 55 76 11 76 72 1b 28 9e |'z.Uv.vr.(.|
>>> Flow 5 (client to server)
-00000000 17 03 03 00 1e 00 00 00 00 00 00 00 01 17 22 06 |..............".|
-00000010 f7 50 b5 6f 65 e0 dd f9 b6 bc 50 b7 91 c9 54 5c |.P.oe.....P...T\|
-00000020 4e 2f cc |N/.|
+00000000 17 03 03 00 16 3d 89 e4 a6 38 75 31 c2 08 3d 86 |.....=...8u1..=.|
+00000010 45 ed 8d c4 49 c4 da 54 3b 8f e3 |E...I..T;..|
>>> Flow 6 (server to client)
-00000000 16 03 03 00 1c 86 be df d2 27 8b 37 78 c8 e7 d6 |.........'.7x...|
-00000010 4b e4 60 9e 4c b0 28 79 d9 7a 78 58 d8 27 76 18 |K.`.L.(y.zxX.'v.|
-00000020 a3 |.|
+00000000 16 03 03 00 14 aa 85 e4 64 46 2f 8e dc 89 3e ef |........dF/...>.|
+00000010 6d 9e 1a af 53 3b a0 81 c2 |m...S;...|
>>> Flow 7 (client to server)
-00000000 16 03 03 00 a9 00 00 00 00 00 00 00 02 a7 17 56 |...............V|
-00000010 8e ea 2e fc 76 06 40 b2 fa 10 71 62 68 b9 14 e6 |....v. at ...qbh...|
-00000020 09 6d 63 86 d1 6b 87 3a c4 84 15 77 68 f8 85 ec |.mc..k.:...wh...|
-00000030 55 49 3c c5 c1 be 24 85 0c 38 4b 66 a8 5f 33 f9 |UI<...$..8Kf._3.|
-00000040 a3 e5 d1 36 fd 25 ba 9d 54 1f 4c df 66 09 a7 08 |...6.%..T.L.f...|
-00000050 8d 7c a4 7e d4 5d c2 11 77 7b 48 7a 32 f7 88 0a |.|.~.]..w{Hz2...|
-00000060 51 5f 6a 26 e2 11 88 01 5b b6 8e 6a aa 18 79 85 |Q_j&....[..j..y.|
-00000070 6a 0e 31 1f 33 5e 34 fd e9 1c 84 7c ea 6c 78 5d |j.1.3^4....|.lx]|
-00000080 0e d2 df c0 8c 92 3d 48 fc 9e 47 18 2a a7 1e e3 |......=H..G.*...|
-00000090 9b 89 6f 30 d0 fd 0a cd 4c b9 d9 89 b6 72 53 54 |..o0....L....rST|
-000000a0 3e 02 c3 d0 68 b0 4e 40 06 86 cd 8e 87 53 |>...h.N at .....S|
+00000000 16 03 03 00 ad c3 12 d1 1a b2 88 da c1 0b 5a 32 |..............Z2|
+00000010 cf 05 35 53 ce 5d d8 42 cd 99 7e e7 9f 62 b8 35 |..5S.].B..~..b.5|
+00000020 9e f5 b5 a6 15 fd 82 26 9b 6a fe 3b 8e c0 43 27 |.......&.j.;..C'|
+00000030 1c 56 37 d1 6f d9 2c a6 a8 e8 b4 50 64 80 ae 5c |.V7.o.,....Pd..\|
+00000040 ed eb a6 58 58 52 cf 32 de 1d be 80 69 63 38 a6 |...XXR.2....ic8.|
+00000050 12 4e 11 9b 50 aa 4b 10 f7 ad 6f 5b 08 c6 cc bd |.N..P.K...o[....|
+00000060 94 42 64 90 c7 33 58 65 18 c5 a7 66 ce dd 83 8b |.Bd..3Xe...f....|
+00000070 b0 15 8a 61 26 c7 eb 15 4b 6c 0b 15 45 33 2a 01 |...a&...Kl..E3*.|
+00000080 ea 13 5a 20 52 16 15 a0 70 8f 86 dc 28 50 bb e4 |..Z R...p...(P..|
+00000090 9d 01 f4 c9 7f 27 5a 54 3f 42 34 c9 5c 04 3f a3 |.....'ZT?B4.\.?.|
+000000a0 6a 5c a1 3f 03 7c fc 57 94 9b 3e 76 65 bf 78 40 |j\.?.|.W..>ve.x@|
+000000b0 b1 4f |.O|
>>> Flow 8 (server to client)
-00000000 16 03 03 00 89 86 be df d2 27 8b 37 79 29 01 95 |.........'.7y)..|
-00000010 8c 13 0f f0 6e 8b 00 0c 1e 1a 36 73 b6 96 ad e1 |....n.....6s....|
-00000020 40 80 6d 68 f3 41 a9 a1 85 ca 86 81 73 6c fc 49 |@.mh.A......sl.I|
-00000030 b4 61 76 27 0f cd 22 5f 7e a7 c1 e3 13 f6 2e da |.av'.."_~.......|
-00000040 1a 15 57 1a f1 b0 be 6d 55 44 78 95 62 82 ff 6e |..W....mUDx.b..n|
-00000050 bb 70 ea 24 2c bf e2 14 48 3a 07 9a 30 3a a8 88 |.p.$,...H:..0:..|
-00000060 8b d6 b4 62 28 cb 30 94 54 f6 9c 15 34 e9 c4 d2 |...b(.0.T...4...|
-00000070 e3 42 cf 79 1f 96 34 f3 4c 9f f2 df 6e 70 4f cd |.B.y..4.L...npO.|
-00000080 68 ae e2 2c d5 b7 f3 37 86 0a f5 7c af 32 16 03 |h..,...7...|.2..|
-00000090 03 02 89 86 be df d2 27 8b 37 7a 66 a9 20 cf 95 |.......'.7zf. ..|
-000000a0 d1 c9 3c c6 bc 53 16 01 e2 78 7e 2b 4d 45 20 d8 |..<..S...x~+ME .|
-000000b0 be da 93 9f 61 0b 34 25 f8 42 aa 0e b7 c5 a7 7a |....a.4%.B.....z|
-000000c0 99 23 b5 a5 0b 39 37 48 2d 66 21 8a bd 41 11 e5 |.#...97H-f!..A..|
-000000d0 79 5f 5d c1 9b 4f c2 0c fc a4 b9 ad 82 7e 7e 5b |y_]..O.......~~[|
-000000e0 f6 95 46 eb b2 9e 9c 2d 58 7e c7 90 2c c4 7f 1c |..F....-X~..,...|
-000000f0 cf 32 86 37 ec ab 60 71 ee 82 2b a2 95 61 8f 31 |.2.7..`q..+..a.1|
-00000100 99 2d c7 f4 5f 29 e8 b6 c3 f4 81 4f 2c b6 2c 67 |.-.._).....O,.,g|
-00000110 70 e5 cf d1 00 77 34 28 dc 61 cf e1 78 10 5e 64 |p....w4(.a..x.^d|
-00000120 17 f7 2b 3e 74 2c 8f 42 d5 a8 c2 4e 11 48 0f 0a |..+>t,.B...N.H..|
-00000130 3f 8a ea 0f 37 f5 da 8f 7f 7c 61 b3 98 d9 69 80 |?...7....|a...i.|
-00000140 b5 1e c6 5c 01 ff e3 8e 45 a1 7a cb ee ea 12 d3 |...\....E.z.....|
-00000150 d7 56 2e 33 8c 55 a5 94 84 f7 a1 a4 fa f3 71 f4 |.V.3.U........q.|
-00000160 a3 15 f0 7e 44 c7 32 65 86 39 93 b7 df ab 6b 94 |...~D.2e.9....k.|
-00000170 df 6d d8 31 72 ba d9 7b b6 8a 68 b1 c8 da e1 a0 |.m.1r..{..h.....|
-00000180 4f 0f 06 6a 52 78 6e a1 57 2f 2b 6b 10 5b c1 57 |O..jRxn.W/+k.[.W|
-00000190 d0 92 23 bf dc 95 f1 83 66 ce 6f ef c5 22 22 24 |..#.....f.o..""$|
-000001a0 80 bd 2f 38 ff de ec 86 8b ad 81 4e fe 31 65 54 |../8.......N.1eT|
-000001b0 19 94 ce 99 0f 6d 5b 1b 53 ba ad 65 a6 6a f6 27 |.....m[.S..e.j.'|
-000001c0 ba e0 b7 a9 8b 80 18 71 67 f7 6c 35 5f 69 c2 19 |.......qg.l5_i..|
-000001d0 08 27 03 45 5a 58 49 27 cf ec bf 18 e7 60 64 2b |.'.EZXI'.....`d+|
-000001e0 47 9e 07 1a 49 ef 90 20 c7 f7 69 5c 46 92 ae 65 |G...I.. ..i\F..e|
-000001f0 fa 45 9f 3b a3 4e ed cb d9 1f d9 26 18 1e bb 58 |.E.;.N.....&...X|
-00000200 16 cd a5 00 df 65 73 39 82 fd 98 29 de 45 8f 70 |.....es9...).E.p|
-00000210 56 e3 c6 0b 18 71 09 92 0e 69 4e b8 e7 23 4f 70 |V....q...iN..#Op|
-00000220 7a 89 06 c7 78 05 04 31 7f 77 5c 68 74 f0 45 76 |z...x..1.w\ht.Ev|
-00000230 e2 56 b2 de 34 e6 79 64 49 9a a8 3a b7 5b 4a d3 |.V..4.ydI..:.[J.|
-00000240 5e 6d 0b f3 fb 6d 0c 2f 61 d0 71 f4 0d ed 60 2f |^m...m./a.q...`/|
-00000250 61 80 c9 9b b9 e5 89 f2 64 88 52 d6 d3 aa 72 6b |a.......d.R...rk|
-00000260 66 18 ae e9 df 20 40 15 b5 73 ba ac 50 b1 27 99 |f.... @..s..P.'.|
-00000270 b3 17 97 56 0b 7d 25 8a 64 80 42 5c c8 b8 d5 98 |...V.}%.d.B\....|
-00000280 28 16 2b ce 45 65 3d fc d8 c6 91 31 c2 d4 09 a3 |(.+.Ee=....1....|
-00000290 cf 92 85 63 36 cb e2 da a3 66 fb 08 c9 bc 12 23 |...c6....f.....#|
-000002a0 c8 88 7d 46 22 98 40 01 bf fb 58 84 f2 8f ad 83 |..}F". at ...X.....|
-000002b0 ed 79 b4 a8 3d e5 92 b7 b8 e1 d0 50 aa be 22 9c |.y..=......P..".|
-000002c0 9c cb dc bd 65 59 41 3e 6f 53 89 02 30 b1 88 ca |....eYA>oS..0...|
-000002d0 06 6d 8e b2 a6 75 6a d8 5a 19 65 de 27 c3 bf 70 |.m...uj.Z.e.'..p|
-000002e0 49 64 13 2d 19 5d 7a ec 91 a7 f6 82 92 7d e3 7e |Id.-.]z......}.~|
-000002f0 d6 65 5b d4 eb ed 58 d7 cd 41 a2 b9 d3 9e e4 a0 |.e[...X..A......|
-00000300 92 bf 88 4f 0e 59 74 66 86 db 72 11 18 ad 81 24 |...O.Ytf..r....$|
-00000310 6e 43 38 24 23 fb db af 92 d8 1a 2d 16 03 03 00 |nC8$#......-....|
-00000320 e5 86 be df d2 27 8b 37 7b ce 01 b6 78 47 7d 3a |.....'.7{...xG}:|
-00000330 ad 2e 03 8e 78 03 61 da 55 0e d4 fa 87 9d 20 25 |....x.a.U..... %|
-00000340 73 1f 3b 87 7b 02 c1 a3 af ce d5 b9 9e 29 91 1b |s.;.{........)..|
-00000350 58 13 c9 bc 96 95 88 f8 67 43 03 25 a3 be 5e a6 |X.......gC.%..^.|
-00000360 1d ee 6e 70 4c b5 66 48 3d 7d 1a 58 8e 10 c0 68 |..npL.fH=}.X...h|
-00000370 6b d8 f1 dd 83 c5 d3 c8 81 c5 6d 72 68 50 41 6f |k.........mrhPAo|
-00000380 f6 20 13 f8 72 fa 82 9a 25 e4 07 10 df b7 39 90 |. ..r...%.....9.|
-00000390 6a d7 d2 d7 a1 1c 31 4e b6 7c 00 bc 4d b1 a1 ff |j.....1N.|..M...|
-000003a0 d0 ae 42 b1 2d 3e 8b c9 43 f4 fa fc d4 71 8f 74 |..B.->..C....q.t|
-000003b0 37 23 1b bb 34 4e b6 e4 fe f1 1b ea da 08 e4 12 |7#..4N..........|
-000003c0 fd 50 23 f9 8a 2d 92 eb f5 2b fc b4 e1 35 87 74 |.P#..-...+...5.t|
-000003d0 44 79 0b df 6a 14 eb 20 17 ab 5b 12 a7 19 a4 4e |Dy..j.. ..[....N|
-000003e0 94 70 93 57 2d bd c2 54 88 fb 19 b7 82 28 ab db |.p.W-..T.....(..|
-000003f0 ca a9 19 5d 36 1b d6 fc 7d 41 2c 5b 76 ec 90 72 |...]6...}A,[v..r|
-00000400 47 5b c4 ae 59 a6 16 03 03 00 46 86 be df d2 27 |G[..Y.....F....'|
-00000410 8b 37 7c ed db 59 c6 0b 4e 52 c9 bc 7a 81 ed 20 |.7|..Y..NR..z.. |
-00000420 00 55 02 76 15 49 9b 0b f2 81 c2 f7 25 51 61 9d |.U.v.I......%Qa.|
-00000430 48 e3 d2 6f 08 ea 0c 9b 26 cc 3b 52 58 ef a0 1f |H..o....&.;RX...|
-00000440 09 c3 ca e8 c2 6c 13 86 b1 94 04 f1 65 e2 de 4c |.....l......e..L|
-00000450 7c |||
+00000000 16 03 03 00 81 33 ef 78 c8 2d 94 4b e3 b8 ea eb |.....3.x.-.K....|
+00000010 67 1e 6c 10 98 25 5f df ce 46 4c 13 77 ec d1 b1 |g.l..%_..FL.w...|
+00000020 e9 e2 c9 b0 de 9c ce 40 d0 d9 6f a5 fb a6 69 1f |....... at ..o...i.|
+00000030 9f 53 68 6c ab f8 f0 10 4a c9 43 f0 ad 61 59 01 |.Shl....J.C..aY.|
+00000040 b2 90 97 9e cf 62 64 a5 46 b2 27 2f 1e b8 33 24 |.....bd.F.'/..3$|
+00000050 ed 7e 6b 5a dd 45 4d 00 61 a3 7e 22 5e bc 02 af |.~kZ.EM.a.~"^...|
+00000060 5a a0 73 fb c5 1c 0f 11 f6 70 5f cc 9e 1c fa 3c |Z.s......p_....<|
+00000070 13 0d 8b 03 4c 3b d5 5a 02 7b 95 64 ae cb 2f 50 |....L;.Z.{.d../P|
+00000080 e7 e1 32 13 72 96 16 03 03 02 69 f0 60 6a b8 fb |..2.r.....i.`j..|
+00000090 50 6e f9 f2 65 d0 73 90 f7 55 0d bc 3a 66 72 32 |Pn..e.s..U..:fr2|
+000000a0 b7 32 ad 1d de 18 04 90 55 70 2d b8 c9 3f 4b 2f |.2......Up-..?K/|
+000000b0 37 98 1c 4e c1 78 c1 ed 1f e2 bf 50 78 40 04 10 |7..N.x.....Px at ..|
+000000c0 b8 55 48 29 26 b0 a4 4d ea aa 45 65 b4 21 93 ed |.UH)&..M..Ee.!..|
+000000d0 49 4c 1d d9 77 33 38 2e 14 92 b4 e3 06 ce fe 51 |IL..w38........Q|
+000000e0 6a 19 1c aa e9 a6 7d fa 45 86 66 1a 6e bb 01 01 |j.....}.E.f.n...|
+000000f0 82 86 89 86 81 ce 0a 93 1a b2 f1 90 71 7a 43 fa |............qzC.|
+00000100 b1 03 24 75 a1 48 f8 ee a0 b4 c0 18 ff 81 95 2a |..$u.H.........*|
+00000110 aa 74 87 39 da 23 ba ab 33 6b 63 ee df 2b f1 d1 |.t.9.#..3kc..+..|
+00000120 1a 9a 4a 0d ef de 68 13 28 81 49 d5 c6 08 57 a9 |..J...h.(.I...W.|
+00000130 d7 5e 56 a4 ec 81 42 de 28 39 51 7d 3a 66 cf a7 |.^V...B.(9Q}:f..|
+00000140 f7 81 7a b2 a7 09 b3 24 a6 b0 a5 cc 96 24 30 b2 |..z....$.....$0.|
+00000150 5b 94 1b ef 70 dd 7f bc 63 2f 7b bc 80 70 9e 9f |[...p...c/{..p..|
+00000160 01 c9 20 ab 35 53 7c 3b d6 70 d9 1d 9a f6 e8 76 |.. .5S|;.p.....v|
+00000170 f5 46 f8 b1 10 46 a9 eb da 7b 80 cc 74 18 f9 30 |.F...F...{..t..0|
+00000180 56 1a cb 4e 60 2a b3 9f 35 fe a9 b8 b8 76 02 a7 |V..N`*..5....v..|
+00000190 4e f9 43 c9 52 70 6a fd 9c 3e dd c4 3f 28 08 19 |N.C.Rpj..>..?(..|
+000001a0 28 ed f9 44 e3 d1 b9 53 7e b7 cd 1b e9 11 c8 9f |(..D...S~.......|
+000001b0 35 ed ab e3 5e 26 e8 49 7a 13 5c 20 9a b7 a0 95 |5...^&.Iz.\ ....|
+000001c0 60 0f 54 68 5c a8 c9 1d 37 0b 9f f6 61 3b fe 4c |`.Th\...7...a;.L|
+000001d0 dc 4f 11 98 0c 7a b7 32 0b 50 e2 cd a7 59 bf 05 |.O...z.2.P...Y..|
+000001e0 a2 8a 51 33 23 ab 99 49 23 97 42 3b 0f 1c 39 b1 |..Q3#..I#.B;..9.|
+000001f0 43 c4 01 aa f9 f8 54 d7 2c b4 ef 33 f3 05 13 d0 |C.....T.,..3....|
+00000200 8d 81 06 23 d3 38 cb 3a 6b 37 f0 4d 1f be ed 0c |...#.8.:k7.M....|
+00000210 b7 58 00 3a bd 74 02 a4 f4 b4 fc fd b8 fa 89 15 |.X.:.t..........|
+00000220 01 46 49 52 47 f1 4c 94 ee de 00 a1 25 aa b4 9b |.FIRG.L.....%...|
+00000230 f6 b4 23 a1 0d fd 00 5a de 45 38 ee 69 17 6f c3 |..#....Z.E8.i.o.|
+00000240 0b ed c5 3b b1 7d b1 2c a4 8f ed 30 44 9a 0b 51 |...;.}.,...0D..Q|
+00000250 34 12 cc 6a 09 e4 74 ec 11 94 4b ba ce 72 93 64 |4..j..t...K..r.d|
+00000260 07 c8 ff 78 6e 1a bd 5e 26 15 a7 e8 72 90 71 a9 |...xn..^&...r.q.|
+00000270 0a bb cf 25 40 1d 20 a7 d7 b3 46 4b 53 6c c2 50 |...%@. ...FKSl.P|
+00000280 c7 7b 58 e1 3c df 6d db 28 71 15 f9 84 b7 ad b0 |.{X.<.m.(q......|
+00000290 9f e9 7a 08 5d 85 7a dd bc c0 62 2e 6a d0 63 6a |..z.].z...b.j.cj|
+000002a0 e2 46 6b 80 68 cf e5 a7 9e 60 42 8a 17 54 9c ec |.Fk.h....`B..T..|
+000002b0 80 9b 81 80 7e 6f 33 8c d1 be 95 30 f2 a9 19 f8 |....~o3....0....|
+000002c0 36 2c 8e 89 c2 5a b4 04 2e 12 05 21 3b 4f 42 26 |6,...Z.....!;OB&|
+000002d0 d1 98 11 f4 17 c2 a3 06 54 37 31 8e ca 9b 07 62 |........T71....b|
+000002e0 79 95 b8 fd 49 aa 60 5b 03 7d 60 50 b6 2f 3b 0a |y...I.`[.}`P./;.|
+000002f0 5d c2 9f 92 16 03 03 00 bc ba f6 73 85 34 20 c4 |]..........s.4 .|
+00000300 b3 a4 15 01 fe 37 b3 b4 57 a5 b5 26 0c 64 2b 3e |.....7..W..&.d+>|
+00000310 07 d3 e4 59 a8 64 3f fd 15 24 24 70 61 77 9b 96 |...Y.d?..$$paw..|
+00000320 c6 4b 79 2e a8 a7 c4 ac 5e cd 6e 8f 30 e5 3f f8 |.Ky.....^.n.0.?.|
+00000330 08 22 cb de 5f 8c b8 dc 07 4b 79 ec 41 41 20 20 |.".._....Ky.AA |
+00000340 02 f6 4e 98 a3 5e 38 e2 5a d9 4a 2d 2e 3b 29 13 |..N..^8.Z.J-.;).|
+00000350 26 dc 4e eb a5 5e a3 b6 6f 16 75 b3 9e 63 4e 8e |&.N..^..o.u..cN.|
+00000360 00 c1 46 30 fc 25 f9 05 86 ed 00 87 f2 6b 5c 18 |..F0.%.......k\.|
+00000370 69 e5 5c 32 9e 15 d2 47 9e 0e d8 c1 7a 9d 45 7a |i.\2...G....z.Ez|
+00000380 76 4a ef 8d b5 60 7d 4d fa 99 8f c5 58 18 ad a2 |vJ...`}M....X...|
+00000390 93 c1 36 85 39 73 e1 7b 46 be 69 de 88 fa 68 8e |..6.9s.{F.i...h.|
+000003a0 be d1 48 bc 7b 29 2a 21 ba 60 60 58 51 c2 03 66 |..H.{)*!.``XQ..f|
+000003b0 51 9a 4e 70 06 16 03 03 00 3a c5 ed 8d 5d b9 c0 |Q.Np.....:...]..|
+000003c0 a2 07 15 c3 ef 76 ff fb ca f6 b6 4b ab a5 7a 80 |.....v.....K..z.|
+000003d0 a9 2e 43 d0 d2 f1 d9 96 61 ff 43 59 3d d1 82 57 |..C.....a.CY=..W|
+000003e0 68 d7 c8 3a 5f 86 4a 2e 00 8f 3d 0e 73 49 c6 4a |h..:_.J...=.sI.J|
+000003f0 81 4e ec e2 16 03 03 00 14 d5 5f c3 d2 9c 13 36 |.N........_....6|
+00000400 cb 22 23 3d e4 03 5b b9 26 66 cf 79 7c |."#=..[.&f.y||
>>> Flow 9 (client to server)
-00000000 16 03 03 02 89 00 00 00 00 00 00 00 03 3c 0f 09 |.............<..|
-00000010 9e dc 39 b8 be ab ca 53 74 05 93 12 a4 e7 bb 56 |..9....St......V|
-00000020 9f e1 9f 2a 09 7d e1 74 89 ee b3 99 3c 91 c6 38 |...*.}.t....<..8|
-00000030 7e 0c 5e 2d 1f 7d bd cd 1a d1 16 ab af 94 08 c6 |~.^-.}..........|
-00000040 74 e3 16 12 0e 9b bc 91 95 6d 01 fd 10 00 12 c6 |t........m......|
-00000050 03 96 92 08 df 50 89 ba 5c 25 ce 31 d8 b1 84 8a |.....P..\%.1....|
-00000060 7d 6c cf 7f e6 9a e4 08 17 cc b8 f2 c9 8f e8 4b |}l.............K|
-00000070 ab 44 4f e9 63 8c 93 71 b1 70 4a f4 29 5f ef 45 |.DO.c..q.pJ.)_.E|
-00000080 68 e1 0e 31 a0 4c 96 8c 65 03 f3 48 24 48 d4 d7 |h..1.L..e..H$H..|
-00000090 93 d1 17 39 8d 97 e8 d8 59 08 4b 46 82 cf a3 99 |...9....Y.KF....|
-000000a0 55 36 65 a9 d8 df db d5 65 78 52 38 c2 2a 1e ec |U6e.....exR8.*..|
-000000b0 65 6a f5 d5 4c 81 0c f6 e6 77 b2 68 d4 6c 32 05 |ej..L....w.h.l2.|
-000000c0 ef f4 ee 0b e1 83 d0 3a cf a0 06 f2 cc 61 62 5e |.......:.....ab^|
-000000d0 fa b4 19 c7 e2 99 c1 cf 02 a1 01 3d 6a e0 be 9f |...........=j...|
-000000e0 82 cd e5 c8 ac e2 3e 6d 0f 60 a4 e9 9b ca cf c9 |......>m.`......|
-000000f0 c1 fe 2d ef 29 ed f9 c3 11 03 9f 76 66 71 ef 24 |..-.)......vfq.$|
-00000100 5f d3 29 aa 6a e1 0c b1 58 7a f3 df 92 e8 61 e2 |_.).j...Xz....a.|
-00000110 41 43 ad 9d 55 a0 b0 a3 20 8d 2c 8f 34 e6 ab d3 |AC..U... .,.4...|
-00000120 37 80 9e cb 27 91 69 0a ba 33 05 a1 7f 4d 7f 63 |7...'.i..3...M.c|
-00000130 ed 6a c1 72 43 ec 6a 6c ac b7 87 bb 81 6e 06 fa |.j.rC.jl.....n..|
-00000140 68 7a c9 33 28 59 ed 74 87 a1 6a 24 06 02 c0 21 |hz.3(Y.t..j$...!|
-00000150 71 b0 27 f9 6e b3 7e 30 e9 e0 df c2 5d 63 2a dd |q.'.n.~0....]c*.|
-00000160 9d e9 9c 4f 47 66 68 7e e4 8c 87 b7 f0 a8 3d b8 |...OGfh~......=.|
-00000170 36 39 3e 4c 9f 55 e7 bb c7 3e 34 36 54 19 41 33 |69>L.U...>46T.A3|
-00000180 61 e6 9a ae c6 91 1d fa 2d 8c 45 95 5f 95 36 79 |a.......-.E._.6y|
-00000190 e9 59 7e 81 cd 7e 9e 01 fe 85 eb c8 ed 4e 93 c6 |.Y~..~.......N..|
-000001a0 53 76 2d 5c 72 50 22 16 04 15 c2 cf 19 07 e6 73 |Sv-\rP"........s|
-000001b0 74 d0 7b bb 68 c3 29 39 bc ab 1b 4c c9 5a 36 73 |t.{.h.)9...L.Z6s|
-000001c0 55 47 7a c8 4a a7 45 fe f3 a9 94 6e ea ea cc 7d |UGz.J.E....n...}|
-000001d0 d1 de f4 82 4c 14 84 f0 58 09 56 25 83 7a 23 71 |....L...X.V%.z#q|
-000001e0 a1 63 e3 4e 13 78 68 41 a1 9a 55 ec 9e 37 ee c2 |.c.N.xhA..U..7..|
-000001f0 7d 3f 8f 91 00 30 f2 ca 7b 13 b7 e7 fe 85 c5 aa |}?...0..{.......|
-00000200 5e e3 97 2c cb d5 13 1e 83 3d c9 2a b1 21 f1 58 |^..,.....=.*.!.X|
-00000210 7d 09 32 31 d6 fd 89 26 ff 72 3c f7 c4 fe 99 33 |}.21...&.r<....3|
-00000220 41 82 76 05 b9 14 b1 b0 3c 41 02 74 a8 1d dd 80 |A.v.....<A.t....|
-00000230 38 67 25 01 39 f7 36 fa e4 1c 7d 2f c9 7e 21 0a |8g%.9.6...}/.~!.|
-00000240 30 77 1e ff fc 8a 31 ac ee 91 f0 2c b1 9a b7 5e |0w....1....,...^|
-00000250 26 d0 7a 9d b4 9e 53 6b dd a6 5e 7b f0 45 99 9b |&.z...Sk..^{.E..|
-00000260 2b 69 90 d4 dd 1a d0 b5 13 90 11 ac 01 f0 2f 94 |+i............/.|
-00000270 5b 59 7e 7a 40 22 3a b0 d4 24 92 7d 94 bf 34 91 |[Y~z@":..$.}..4.|
-00000280 f6 b9 cc c9 e5 de d3 67 6d 83 97 ee 8f 48 16 03 |.......gm....H..|
-00000290 03 00 5e 00 00 00 00 00 00 00 04 dc 6f 41 98 23 |..^.........oA.#|
-000002a0 d7 70 80 24 74 46 c8 45 e1 2f 43 1d b8 66 4d 0a |.p.$tF.E./C..fM.|
-000002b0 03 0e d6 01 8b 92 f7 76 c1 2c 32 6c 65 60 da ab |.......v.,2le`..|
-000002c0 0b 12 6d 30 1c cf de e7 ec a7 12 f9 df 6c b4 42 |..m0.........l.B|
-000002d0 e7 d9 6e 6e f3 1c 10 ee 39 47 7f ec 7c ec 68 68 |..nn....9G..|.hh|
-000002e0 e8 b2 70 a2 67 61 e0 b3 68 b5 91 9f 1a e0 c5 af |..p.ga..h.......|
-000002f0 e3 16 03 03 00 a0 00 00 00 00 00 00 00 05 6b 56 |..............kV|
-00000300 3d 5e 4e f1 2c 30 e2 91 24 5c b1 5f d3 7d 3e dc |=^N.,0..$\._.}>.|
-00000310 ba 98 e1 9f 72 98 2b 0e 11 07 d1 ea 14 d5 73 25 |....r.+.......s%|
-00000320 d2 cf 8e bc a5 ea 93 a7 32 ab 94 83 1e ea c5 62 |........2......b|
-00000330 06 79 bb ab 4c a0 cf fb 51 3b 7b f0 11 5e ae 50 |.y..L...Q;{..^.P|
-00000340 23 cb ff 86 03 3d a5 66 b9 c4 35 c2 12 f2 98 85 |#....=.f..5.....|
-00000350 77 ba af 3b d5 dd f2 cd 58 09 29 26 08 cd 4a ed |w..;....X.)&..J.|
-00000360 ac af 57 ab 27 1a 40 ef 10 57 d1 ad 06 34 be ed |..W.'. at ..W...4..|
-00000370 fe 88 1d 09 4a 81 8a da e7 ef fa 27 71 ab 2b 3f |....J......'q.+?|
-00000380 21 91 5f 1a dc 50 a4 f0 58 bd aa af 75 4e 25 2a |!._..P..X...uN%*|
-00000390 2c 55 e5 57 c6 ab 14 03 03 00 19 00 00 00 00 00 |,U.W............|
-000003a0 00 00 06 5d 8a 3e 8e 55 e4 9d c0 6a de 91 c6 96 |...].>.U...j....|
-000003b0 6e 17 54 a5 16 03 03 00 28 00 00 00 00 00 00 00 |n.T.....(.......|
-000003c0 00 d5 45 5d 11 af e2 b6 f1 a8 e5 ed 58 80 54 ce |..E]........X.T.|
-000003d0 b3 db dc 97 b3 86 c0 83 f9 3b 7c b5 ad 21 f8 cf |.........;|..!..|
-000003e0 9a |.|
+00000000 16 03 03 02 69 15 0b 29 0e 27 a9 4b 52 4d 0a 77 |....i..).'.KRM.w|
+00000010 b8 3a 40 95 84 a7 7a 8d b1 6b 90 61 94 3a e4 06 |.:@...z..k.a.:..|
+00000020 20 6f 88 40 8a 8c c2 4e dc 3a 01 39 c2 11 5a 9b | o. at ...N.:.9..Z.|
+00000030 28 92 bc 72 04 a3 60 c3 42 c0 b8 dd f3 41 40 be |(..r..`.B....A at .|
+00000040 6d 51 5b b8 db 75 63 3d 4f 2a cf f5 04 3d 53 be |mQ[..uc=O*...=S.|
+00000050 47 f1 ae be 0a 97 5d 2c df 55 5d dd 9a f6 0e 40 |G.....],.U]....@|
+00000060 59 02 91 d8 55 c9 3b e6 84 9c 8d 40 af 29 77 59 |Y...U.;.... at .)wY|
+00000070 15 0c 83 dd ec c7 e2 16 85 d8 6e e7 4e c5 a5 b1 |..........n.N...|
+00000080 8b 4b 46 3e 62 7c ff 27 1b 37 b7 5c 05 32 30 fb |.KF>b|.'.7.\.20.|
+00000090 c1 cc 1d 13 1f 09 db 57 6a 70 2b 9f a7 25 9b 75 |.......Wjp+..%.u|
+000000a0 d3 62 20 45 d1 2f 28 c0 d7 84 d6 2e b3 6d 4a c3 |.b E./(......mJ.|
+000000b0 46 0d 92 32 87 65 dd b8 98 68 1a 52 0a df be b3 |F..2.e...h.R....|
+000000c0 09 bc 63 bb a3 da f7 52 5a 81 53 9a e0 ff bb 06 |..c....RZ.S.....|
+000000d0 7f 81 f8 ea 02 bb 3b 96 7b 0f 84 a5 4d 17 3a 2a |......;.{...M.:*|
+000000e0 20 e9 21 70 b2 ab 8a 55 31 4b 1b 60 52 7f a8 39 | .!p...U1K.`R..9|
+000000f0 5a 0f 0b 00 4e eb 01 0c a6 d8 f0 30 2b a3 6f 7b |Z...N......0+.o{|
+00000100 99 82 90 9e 4c c8 03 1c 0e 85 55 bc 2d 42 28 66 |....L.....U.-B(f|
+00000110 35 c3 1e 08 70 d0 45 05 5b 2e 00 fc 9a f1 44 0e |5...p.E.[.....D.|
+00000120 cb 91 ce b8 0f 2a 9f 5a 18 a8 ca 38 ff 2a ab 11 |.....*.Z...8.*..|
+00000130 57 a5 03 2f 3e 92 21 77 df dc 85 e7 fd d4 7e d0 |W../>.!w......~.|
+00000140 d9 6e ef 99 66 5d a8 f5 9a d3 c3 0f 0c 98 cd fe |.n..f]..........|
+00000150 5a 46 79 77 c9 28 fb 5e 3e c0 d5 b3 db 98 79 9d |ZFyw.(.^>.....y.|
+00000160 d4 20 a5 ad 25 d8 3b 39 35 60 fd 21 e0 eb 86 be |. ..%.;95`.!....|
+00000170 8f 65 72 a2 d3 91 4c 25 70 31 b1 02 29 17 da e0 |.er...L%p1..)...|
+00000180 9f 7d 4e 5f 1a 7b 93 09 4c 84 5b 40 f8 3c 98 36 |.}N_.{..L.[@.<.6|
+00000190 9b 14 43 db 43 11 0a e2 9a 8b 73 96 a3 7b 4d 67 |..C.C.....s..{Mg|
+000001a0 d7 35 a6 85 40 6d 45 0e 9d 47 43 96 b8 64 d4 d7 |.5.. at mE..GC..d..|
+000001b0 d1 28 c8 32 7e ab d5 11 ad b4 a7 9c c9 ab c5 96 |.(.2~...........|
+000001c0 72 69 1a db 42 06 8e 03 d0 70 f9 7a 75 56 53 49 |ri..B....p.zuVSI|
+000001d0 29 e1 60 16 86 99 da 9e d6 c3 95 94 e3 e4 6c 9c |).`...........l.|
+000001e0 4f d0 5d e7 a6 23 e1 49 a5 b8 3d 41 a4 e0 8c a2 |O.]..#.I..=A....|
+000001f0 f8 35 40 4d 12 f1 0b 70 06 f5 b5 29 f8 5d 74 73 |.5 at M...p...).]ts|
+00000200 32 35 11 7f 50 a3 22 5b d6 db a5 a8 9f ca db 47 |25..P."[.......G|
+00000210 b9 a8 c7 fc 16 40 ae 94 6e 6c 40 30 7a d6 9c 89 |..... at ..nl@0z...|
+00000220 d7 e9 1b 6b 26 72 1f d7 c9 bc ce 6f 84 03 3d 65 |...k&r.....o..=e|
+00000230 34 f9 7b 32 54 e4 b4 72 8c e1 31 9e e5 13 50 2f |4.{2T..r..1...P/|
+00000240 ea 16 27 15 cb ec 0f 1b 21 aa dd cb 25 74 b9 4d |..'.....!...%t.M|
+00000250 36 c0 0d fe a4 99 2f 86 50 52 d0 83 e2 3f fa e7 |6...../.PR...?..|
+00000260 2d 24 b6 7a ca 7f 69 3e 7d 0b 61 df 29 3b 16 03 |-$.z..i>}.a.);..|
+00000270 03 00 35 8e 89 3d 7b 39 aa d2 21 01 6a 3d fe 4f |..5..={9..!.j=.O|
+00000280 e2 d9 e6 6d 5d 1e d3 a5 1d 3f f8 8e fb 97 3d 06 |...m]....?....=.|
+00000290 9b 68 67 45 15 3b a1 e8 e8 39 77 1a 41 77 2b c5 |.hgE.;...9w.Aw+.|
+000002a0 8c fe bd 28 7a 85 eb 7a 16 03 03 00 98 f0 ed 3c |...(z..z.......<|
+000002b0 37 3f 34 3b 35 e4 15 a8 f3 b4 b6 76 49 65 e8 26 |7?4;5......vIe.&|
+000002c0 93 4b cc b1 31 7a 4c e7 7d 80 63 60 65 9a ff 11 |.K..1zL.}.c`e...|
+000002d0 a8 c5 c4 4e c2 7a ca 95 cb 08 21 77 42 ce 70 1e |...N.z....!wB.p.|
+000002e0 bf d9 b5 6d de dc 03 67 2e 11 b5 47 c1 c0 74 6b |...m...g...G..tk|
+000002f0 b4 9d c4 de 8c d4 80 e4 99 92 31 68 09 85 00 34 |..........1h...4|
+00000300 43 cc 06 09 bc a8 6e 83 a0 fa df 6e a0 04 e9 37 |C.....n....n...7|
+00000310 b3 05 69 b9 f1 85 7f 48 27 73 d0 64 2c 33 48 1f |..i....H's.d,3H.|
+00000320 f9 7c 0a 21 1f cb 0f 4c c2 28 b0 3b 8c 9b 23 21 |.|.!...L.(.;..#!|
+00000330 f4 8c 69 b2 1d 55 35 20 b9 92 09 36 01 aa e1 e3 |..i..U5 ...6....|
+00000340 ee b7 3d 83 7b 14 03 03 00 11 40 bb bb 2e 3d 48 |..=.{..... at ...=H|
+00000350 9f fa c6 0c d8 4f 45 cb 11 b3 a5 16 03 03 00 20 |.....OE........ |
+00000360 39 b7 46 30 00 68 12 c5 f5 d7 a0 85 7f ce 49 70 |9.F0.h........Ip|
+00000370 05 83 64 26 7a 0c 43 fb a9 4d bb 61 3a c3 8a 91 |..d&z.C..M.a:...|
>>> Flow 10 (server to client)
-00000000 14 03 03 00 19 86 be df d2 27 8b 37 7d 85 70 b7 |.........'.7}.p.|
-00000010 a7 98 89 36 01 b4 a8 6f cb 14 0f dd ac 08 16 03 |...6...o........|
-00000020 03 00 28 75 41 a9 ef 1c 88 59 4e 84 15 29 a4 75 |..(uA....YN..).u|
-00000030 e6 66 01 3f a1 b7 ff 69 04 b6 08 99 c9 5e 57 60 |.f.?...i.....^W`|
-00000040 ea 76 21 94 06 e4 32 95 e1 4c d7 17 03 03 00 21 |.v!...2..L.....!|
-00000050 75 41 a9 ef 1c 88 59 4f c8 5d 4e bd 42 52 ec 50 |uA....YO.]N.BR.P|
-00000060 2f 28 4f 87 da bc f0 df a8 93 14 b7 6f a0 7f a2 |/(O.........o...|
-00000070 c5 |.|
+00000000 14 03 03 00 11 d1 d7 7e 3c 5f 01 cb f8 eb af d5 |.......~<_......|
+00000010 ba 09 32 68 4b cf 16 03 03 00 20 02 f1 23 45 32 |..2hK..... ..#E2|
+00000020 60 9b 49 db 2f 3a cb 5c e4 f3 64 b1 cb ca 09 b0 |`.I./:.\..d.....|
+00000030 b3 34 a3 75 7d a5 a0 80 44 fd b7 17 03 03 00 19 |.4.u}...D.......|
+00000040 d7 c3 c4 33 e6 f2 73 d2 2c 0b 7e 0e 40 d3 8b f6 |...3..s.,.~. at ...|
+00000050 47 57 13 88 be 4b 12 43 57 |GW...K.CW|
>>> Flow 11 (client to server)
-00000000 15 03 03 00 1a 00 00 00 00 00 00 00 01 92 8a f2 |................|
-00000010 9a d1 c9 1e 68 15 2d 6b 9a a7 f8 21 78 87 89 |....h.-k...!x..|
+00000000 15 03 03 00 12 3a 90 85 e8 ce 53 d1 2a 3b d6 9a |.....:....S.*;..|
+00000010 f3 61 c1 72 81 c0 03 |.a.r...|
diff --git a/src/crypto/tls/testdata/Client-TLSv12-RenegotiateTwice b/src/crypto/tls/testdata/Client-TLSv12-RenegotiateTwice
index 185dc65..c2f4e4a 100644
--- a/src/crypto/tls/testdata/Client-TLSv12-RenegotiateTwice
+++ b/src/crypto/tls/testdata/Client-TLSv12-RenegotiateTwice
@@ -1,409 +1,376 @@
>>> Flow 1 (client to server)
-00000000 16 03 01 00 85 01 00 00 81 03 03 00 00 00 00 00 |................|
+00000000 16 03 01 00 91 01 00 00 8d 03 03 00 00 00 00 00 |................|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
-00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 22 c0 2f |............."./|
-00000030 c0 2b c0 30 c0 2c c0 11 c0 07 c0 13 c0 09 c0 14 |.+.0.,..........|
-00000040 c0 0a 00 9c 00 9d 00 05 00 2f 00 35 c0 12 00 0a |........./.5....|
-00000050 01 00 00 36 00 05 00 05 01 00 00 00 00 00 0a 00 |...6............|
-00000060 08 00 06 00 17 00 18 00 19 00 0b 00 02 01 00 00 |................|
-00000070 0d 00 0e 00 0c 04 01 04 03 05 01 05 03 02 01 02 |................|
-00000080 03 ff 01 00 01 00 00 12 00 00 |..........|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2c cc a8 |.............,..|
+00000030 cc a9 c0 2f c0 2b c0 30 c0 2c c0 27 c0 13 c0 23 |.../.+.0.,.'...#|
+00000040 c0 09 c0 14 c0 0a 00 9c 00 9d 00 3c 00 2f 00 35 |...........<./.5|
+00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 38 00 05 |.............8..|
+00000060 00 05 01 00 00 00 00 00 0a 00 0a 00 08 00 1d 00 |................|
+00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 0e 00 |................|
+00000080 0c 04 01 04 03 05 01 05 03 02 01 02 03 ff 01 00 |................|
+00000090 01 00 00 12 00 00 |......|
>>> Flow 2 (server to client)
-00000000 16 03 03 00 59 02 00 00 55 03 03 bb b7 b5 ee 8b |....Y...U.......|
-00000010 b7 92 40 96 01 65 93 09 a0 63 77 b3 35 74 0a 73 |.. at ..e...cw.5t.s|
-00000020 db e8 4a 9c d4 95 4b 2a f9 43 1e 20 d6 5a ed d1 |..J...K*.C. .Z..|
-00000030 05 f0 61 aa 45 ae 0e 92 03 87 1b a6 0a 1a 83 a1 |..a.E...........|
-00000040 bd 4f c3 81 79 e8 56 10 5d 08 7b 6d c0 2f 00 00 |.O..y.V.].{m./..|
+00000000 16 03 03 00 59 02 00 00 55 03 03 30 5b 03 80 cf |....Y...U..0[...|
+00000010 ad 5e 69 9b da 4a de 2f 07 f3 6c 42 d7 50 99 10 |.^i..J./..lB.P..|
+00000020 80 15 dc dd d2 ef 3d 20 b9 eb bd 20 51 63 fd 9d |......= ... Qc..|
+00000030 3d b7 3e ea 4e 18 45 90 40 50 f2 f3 2b b8 00 42 |=.>.N.E. at P..+..B|
+00000040 bf 77 ae d1 ff 29 2d ca d8 c2 4e c7 cc a8 00 00 |.w...)-...N.....|
00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................|
-00000060 03 02 71 0b 00 02 6d 00 02 6a 00 02 67 30 82 02 |..q...m..j..g0..|
-00000070 63 30 82 01 cc a0 03 02 01 02 02 09 00 a2 73 00 |c0............s.|
-00000080 0c 81 00 cb f3 30 0d 06 09 2a 86 48 86 f7 0d 01 |.....0...*.H....|
-00000090 01 0b 05 00 30 2b 31 17 30 15 06 03 55 04 0a 13 |....0+1.0...U...|
-000000a0 0e 47 6f 6f 67 6c 65 20 54 45 53 54 49 4e 47 31 |.Google TESTING1|
-000000b0 10 30 0e 06 03 55 04 03 13 07 47 6f 20 52 6f 6f |.0...U....Go Roo|
-000000c0 74 30 1e 17 0d 31 35 30 31 30 31 30 30 30 30 30 |t0...15010100000|
-000000d0 30 5a 17 0d 32 35 30 31 30 31 30 30 30 30 30 30 |0Z..250101000000|
-000000e0 5a 30 26 31 17 30 15 06 03 55 04 0a 13 0e 47 6f |Z0&1.0...U....Go|
-000000f0 6f 67 6c 65 20 54 45 53 54 49 4e 47 31 0b 30 09 |ogle TESTING1.0.|
-00000100 06 03 55 04 03 13 02 47 6f 30 81 9f 30 0d 06 09 |..U....Go0..0...|
-00000110 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 30 |*.H............0|
-00000120 81 89 02 81 81 00 af 87 88 f6 20 1b 95 65 6c 14 |.......... ..el.|
-00000130 ab 44 05 af 3b 45 14 e3 b7 6d fd 00 63 4d 95 7f |.D..;E...m..cM..|
-00000140 fe 6a 62 35 86 c0 4a f9 18 7c f6 aa 25 5e 7a 64 |.jb5..J..|..%^zd|
-00000150 31 66 00 ba f4 8e 92 af c7 6b d8 76 d4 f3 5f 41 |1f.......k.v.._A|
-00000160 cb 6e 56 15 97 1b 97 c1 3c 12 39 21 66 3d 2b 16 |.nV.....<.9!f=+.|
-00000170 d1 bc db 1c c0 a7 da b7 ca ad ba da cb d5 21 50 |..............!P|
-00000180 ec de 8d ab d1 6b 81 4b 89 02 f3 c4 be c1 6c 89 |.....k.K......l.|
-00000190 b1 44 84 bd 21 d1 04 7d 9d 16 4d f9 82 15 f6 ef |.D..!..}..M.....|
-000001a0 fa d6 09 47 f2 fb 02 03 01 00 01 a3 81 93 30 81 |...G..........0.|
-000001b0 90 30 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 05 |.0...U..........|
-000001c0 a0 30 1d 06 03 55 1d 25 04 16 30 14 06 08 2b 06 |.0...U.%..0...+.|
-000001d0 01 05 05 07 03 01 06 08 2b 06 01 05 05 07 03 02 |........+.......|
-000001e0 30 0c 06 03 55 1d 13 01 01 ff 04 02 30 00 30 19 |0...U.......0.0.|
-000001f0 06 03 55 1d 0e 04 12 04 10 12 50 8d 89 6f 1b d1 |..U.......P..o..|
-00000200 dc 54 4d 6e cb 69 5e 06 f4 30 1b 06 03 55 1d 23 |.TMn.i^..0...U.#|
-00000210 04 14 30 12 80 10 bf 3d b6 a9 66 f2 b8 40 cf ea |..0....=..f.. at ..|
-00000220 b4 03 78 48 1a 41 30 19 06 03 55 1d 11 04 12 30 |..xH.A0...U....0|
-00000230 10 82 0e 65 78 61 6d 70 6c 65 2e 67 6f 6c 61 6e |...example.golan|
-00000240 67 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 |g0...*.H........|
-00000250 03 81 81 00 92 7c af 91 55 12 18 96 59 31 a6 48 |.....|..U...Y1.H|
-00000260 40 d5 2d d5 ee bb 02 a0 f5 c2 1e 7c 9b b3 30 7d |@.-........|..0}|
-00000270 3c dc 76 da 4f 3d c0 fa ae 2d 33 24 6b 03 7b 1b |<.v.O=...-3$k.{.|
-00000280 67 59 11 21 b5 11 bc 77 b9 d9 e0 6e a8 2d 2e 35 |gY.!...w...n.-.5|
-00000290 fa 64 5f 22 3e 63 10 6b be ff 14 86 6d 0d f0 15 |.d_">c.k....m...|
-000002a0 31 a8 14 38 1e 3b 84 87 2c cb 98 ed 51 76 b9 b1 |1..8.;..,...Qv..|
-000002b0 4f dd db 9b 84 04 86 40 fa 51 dd ba b4 8d eb e3 |O...... at .Q......|
-000002c0 46 de 46 b9 4f 86 c7 f9 a4 c2 41 34 ac cc f6 ea |F.F.O.....A4....|
-000002d0 b0 ab 39 18 16 03 03 00 cd 0c 00 00 c9 03 00 17 |..9.............|
-000002e0 41 04 b5 fe 7d 68 cd 5a b7 bf 61 10 81 dc 92 23 |A...}h.Z..a....#|
-000002f0 d0 82 13 fb 71 6f 39 48 f9 87 f8 f7 a0 3a cd 18 |....qo9H.....:..|
-00000300 85 d7 4d 66 88 9d 39 8d 6d 53 a1 a3 0d 00 b0 0f |..Mf..9.mS......|
-00000310 14 64 1b 72 2d 89 5c 93 6f 3c ed c9 82 20 3d 2f |.d.r-.\.o<... =/|
-00000320 d0 7f 04 01 00 80 42 24 14 6e cf 78 ea 30 90 1e |......B$.n.x.0..|
-00000330 4e 99 bf ca 98 9c 2f 24 98 c2 a2 b3 f8 34 49 22 |N...../$.....4I"|
-00000340 35 16 11 03 79 3b a8 10 a3 fa d8 5e 17 9d f9 50 |5...y;.....^...P|
-00000350 0a 3b 0b b5 b2 0f 90 18 c1 f5 6f 89 84 04 e2 f0 |.;........o.....|
-00000360 b0 04 2f 3e 78 d3 de 31 9e 6e 3b b8 c7 f5 cc 4f |../>x..1.n;....O|
-00000370 4e ad fe 76 d2 6d 23 31 94 56 b1 d8 df 0d 9b c5 |N..v.m#1.V......|
-00000380 f7 9e 9c a7 2a 47 e4 c8 20 08 fc 6c d5 29 cd 36 |....*G.. ..l.).6|
-00000390 88 83 c5 59 33 6d 1f 0b f9 98 65 fa cb f7 89 2d |...Y3m....e....-|
-000003a0 90 3a 40 8a 31 7e 16 03 03 00 04 0e 00 00 00 |.:@.1~.........|
+00000060 03 02 59 0b 00 02 55 00 02 52 00 02 4f 30 82 02 |..Y...U..R..O0..|
+00000070 4b 30 82 01 b4 a0 03 02 01 02 02 09 00 e8 f0 9d |K0..............|
+00000080 3f e2 5b ea a6 30 0d 06 09 2a 86 48 86 f7 0d 01 |?.[..0...*.H....|
+00000090 01 0b 05 00 30 1f 31 0b 30 09 06 03 55 04 0a 13 |....0.1.0...U...|
+000000a0 02 47 6f 31 10 30 0e 06 03 55 04 03 13 07 47 6f |.Go1.0...U....Go|
+000000b0 20 52 6f 6f 74 30 1e 17 0d 31 36 30 31 30 31 30 | Root0...1601010|
+000000c0 30 30 30 30 30 5a 17 0d 32 35 30 31 30 31 30 30 |00000Z..25010100|
+000000d0 30 30 30 30 5a 30 1a 31 0b 30 09 06 03 55 04 0a |0000Z0.1.0...U..|
+000000e0 13 02 47 6f 31 0b 30 09 06 03 55 04 03 13 02 47 |..Go1.0...U....G|
+000000f0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....|
+00000100 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 db 46 |.......0.......F|
+00000110 7d 93 2e 12 27 06 48 bc 06 28 21 ab 7e c4 b6 a2 |}...'.H..(!.~...|
+00000120 5d fe 1e 52 45 88 7a 36 47 a5 08 0d 92 42 5b c2 |]..RE.z6G....B[.|
+00000130 81 c0 be 97 79 98 40 fb 4f 6d 14 fd 2b 13 8b c2 |....y. at .Om..+...|
+00000140 a5 2e 67 d8 d4 09 9e d6 22 38 b7 4a 0b 74 73 2b |..g....."8.J.ts+|
+00000150 c2 34 f1 d1 93 e5 96 d9 74 7b f3 58 9f 6c 61 3c |.4......t{.X.la<|
+00000160 c0 b0 41 d4 d9 2b 2b 24 23 77 5b 1c 3b bd 75 5d |..A..++$#w[.;.u]|
+00000170 ce 20 54 cf a1 63 87 1d 1e 24 c4 f3 1d 1a 50 8b |. T..c...$....P.|
+00000180 aa b6 14 43 ed 97 a7 75 62 f4 14 c8 52 d7 02 03 |...C...ub...R...|
+00000190 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..|
+000001a0 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%|
+000001b0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........|
+000001c0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...|
+000001d0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....|
+000001e0 10 9f 91 16 1f 43 43 3e 49 a6 de 6d b6 80 d7 9f |.....CC>I..m....|
+000001f0 60 30 1b 06 03 55 1d 23 04 14 30 12 80 10 48 13 |`0...U.#..0...H.|
+00000200 49 4d 13 7e 16 31 bb a3 01 d5 ac ab 6e 7b 30 19 |IM.~.1......n{0.|
+00000210 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp|
+00000220 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H|
+00000230 86 f7 0d 01 01 0b 05 00 03 81 81 00 9d 30 cc 40 |.............0.@|
+00000240 2b 5b 50 a0 61 cb ba e5 53 58 e1 ed 83 28 a9 58 |+[P.a...SX...(.X|
+00000250 1a a9 38 a4 95 a1 ac 31 5a 1a 84 66 3d 43 d3 2d |..8....1Z..f=C.-|
+00000260 d9 0b f2 97 df d3 20 64 38 92 24 3a 00 bc cf 9c |...... d8.$:....|
+00000270 7d b7 40 20 01 5f aa d3 16 61 09 a2 76 fd 13 c3 |}.@ ._...a..v...|
+00000280 cc e1 0c 5c ee b1 87 82 f1 6c 04 ed 73 bb b3 43 |...\.....l..s..C|
+00000290 77 8d 0c 1c f1 0f a1 d8 40 83 61 c9 4c 72 2b 9d |w....... at .a.Lr+.|
+000002a0 ae db 46 06 06 4d f4 c1 b3 3e c0 d1 bd 42 d4 db |..F..M...>...B..|
+000002b0 fe 3d 13 60 84 5c 21 d3 3b e9 fa e7 16 03 03 00 |.=.`.\!.;.......|
+000002c0 ac 0c 00 00 a8 03 00 1d 20 6b cd 37 6d a7 76 7a |........ k.7m.vz|
+000002d0 04 0e 8c 93 db b0 62 67 14 65 26 5e 91 b3 8d 66 |......bg.e&^...f|
+000002e0 20 40 31 c1 84 3c ef d8 67 04 01 00 80 ce 3a f2 | @1..<..g.....:.|
+000002f0 16 01 b2 8a cd d6 1c b3 c4 46 a5 e8 1f 17 85 d9 |.........F......|
+00000300 5b 97 fb dd 43 65 52 82 e3 49 99 e8 49 d9 09 13 |[...CeR..I..I...|
+00000310 05 73 19 d0 d9 66 54 03 de 4b fa 43 2d f1 f8 98 |.s...fT..K.C-...|
+00000320 79 21 3b fa a9 ea 29 78 fa 87 59 8e 9b 2f f2 99 |y!;...)x..Y../..|
+00000330 14 85 21 9c 7e 59 5b 4b 2f e3 33 c4 7c 2c ac 35 |..!.~Y[K/.3.|,.5|
+00000340 4f 68 c8 a3 0b f5 43 7e 72 9a e6 4f 9c 10 4d 4a |Oh....C~r..O..MJ|
+00000350 d4 b5 84 62 61 4e f4 0f 3f a5 b5 23 89 d9 33 e2 |...baN..?..#..3.|
+00000360 06 22 02 c5 fe db 27 fb 40 87 8c e7 6e 16 03 03 |."....'. at ...n...|
+00000370 00 04 0e 00 00 00 |......|
>>> Flow 3 (client to server)
-00000000 16 03 03 00 46 10 00 00 42 41 04 1e 18 37 ef 0d |....F...BA...7..|
-00000010 19 51 88 35 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd |.Q.5uq..T[....g.|
-00000020 a7 24 20 3e b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e |.$ >.V...(^.+-O.|
-00000030 f1 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 |...lK[.V.2B.X..I|
-00000040 a6 b5 68 1a 41 03 56 6b dc 5a 89 14 03 03 00 01 |..h.A.Vk.Z......|
-00000050 01 16 03 03 00 28 00 00 00 00 00 00 00 00 fa e7 |.....(..........|
-00000060 ff 47 50 7a 68 0d 20 f6 9f 2a b5 bc f4 21 c1 72 |.GPzh. ..*...!.r|
-00000070 07 4c e5 07 2c 07 e5 1e d7 fa 07 01 83 68 |.L..,........h|
+00000000 16 03 03 00 25 10 00 00 21 20 2f e5 7d a3 47 cd |....%...! /.}.G.|
+00000010 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af c4 |bC.(.._.).0.....|
+00000020 cf c2 ed 90 99 5f 58 cb 3b 74 14 03 03 00 01 01 |....._X.;t......|
+00000030 16 03 03 00 20 5a b9 f7 81 81 7f 65 84 c9 87 40 |.... Z.....e...@|
+00000040 a4 66 07 85 38 3b 85 8d ff c4 7e b7 f6 16 1d c1 |.f..8;....~.....|
+00000050 36 4f 53 1a bb |6OS..|
>>> Flow 4 (server to client)
-00000000 14 03 03 00 01 01 16 03 03 00 28 b7 93 18 5b 36 |..........(...[6|
-00000010 18 ce 97 17 75 40 15 17 1f 0e 0d 99 fd 66 fa 89 |....u at .......f..|
-00000020 db b7 97 95 a9 45 90 07 6e 82 0e 67 4f 01 58 ec |.....E..n..gO.X.|
-00000030 94 d7 ad |...|
+00000000 14 03 03 00 01 01 16 03 03 00 20 ff b2 f4 3b af |.......... ...;.|
+00000010 ba 44 66 0b f9 31 09 18 df 9d d0 04 82 38 11 dd |.Df..1.......8..|
+00000020 a7 ee 83 ef 03 51 21 08 f9 c4 8a |.....Q!....|
>>> Flow 5 (client to server)
-00000000 17 03 03 00 1e 00 00 00 00 00 00 00 01 21 2b 7b |.............!+{|
-00000010 62 ac e4 37 d6 77 19 89 77 1c 6a ce 40 c1 9d 71 |b..7.w..w.j. at ..q|
-00000020 5a 23 f0 |Z#.|
+00000000 17 03 03 00 16 b6 45 4e 35 df 21 f4 c7 24 ba e6 |......EN5.!..$..|
+00000010 18 65 1c 75 ba 72 5d 5b 4a fd 78 |.e.u.r][J.x|
>>> Flow 6 (server to client)
-00000000 16 03 03 00 1c b7 93 18 5b 36 18 ce 98 4a 49 69 |........[6...JIi|
-00000010 f4 dd 35 f2 93 3b c6 4e d5 25 51 34 38 23 ea 74 |..5..;.N.%Q48#.t|
-00000020 84 |.|
+00000000 16 03 03 00 14 1a ec 37 ab 36 23 80 76 1c 0b d0 |.......7.6#.v...|
+00000010 54 9a 8f 7e 7a c0 bd 09 9a |T..~z....|
>>> Flow 7 (client to server)
-00000000 16 03 03 00 a9 00 00 00 00 00 00 00 02 65 09 7a |.............e.z|
-00000010 d5 9b 32 0b cd 10 ea 2c b6 d8 be ce db 3f a4 38 |..2....,.....?.8|
-00000020 a7 37 a3 95 ed 05 a7 c1 28 69 7a 13 50 07 ab 19 |.7......(iz.P...|
-00000030 52 d7 29 fe 49 80 f0 ef ea 17 ac 20 f9 62 51 72 |R.).I...... .bQr|
-00000040 8d c0 17 62 03 cf bb 80 f8 6f 1b 74 f1 85 45 96 |...b.....o.t..E.|
-00000050 49 55 56 b0 7a dd 9b 5a f1 3f 1a e7 96 cd 21 ec |IUV.z..Z.?....!.|
-00000060 85 6f b9 9d 0f e3 f6 55 9b b8 a7 e1 77 ad 53 0b |.o.....U....w.S.|
-00000070 98 90 ac 5d cf 31 0f 86 69 04 d8 e9 5e fc ea a8 |...].1..i...^...|
-00000080 a8 b7 a2 d8 0f ea 4f e5 ac f2 b2 c0 59 29 ba 53 |......O.....Y).S|
-00000090 af 1e 81 08 be 02 46 a7 b8 6f 2a b4 86 47 5d 8e |......F..o*..G].|
-000000a0 72 a6 64 84 7e 76 31 9c 31 fb 59 b7 da 15 |r.d.~v1.1.Y...|
+00000000 16 03 03 00 ad 7a d4 bf 4d bf 48 0a 0f 2c d1 38 |.....z..M.H..,.8|
+00000010 9f 20 f7 c7 36 27 82 d9 5e f4 21 44 0e 75 46 ca |. ..6'..^.!D.uF.|
+00000020 67 f8 87 6c 4f 1e c7 1e 5f 8d f2 88 58 1b 92 12 |g..lO..._...X...|
+00000030 e0 f6 d5 5c d7 4b 21 b9 8c 93 a8 bc a4 e6 e5 cb |...\.K!.........|
+00000040 d0 33 eb d5 10 ad 53 50 58 e0 94 f0 b8 52 20 8c |.3....SPX....R .|
+00000050 c2 69 7a c3 43 73 3f 2e 4a 42 2c c1 8d c1 ff 1e |.iz.Cs?.JB,.....|
+00000060 57 ba 7d 99 9c a2 10 99 19 d6 72 38 96 ba 2b ff |W.}.......r8..+.|
+00000070 7b a8 42 c0 c0 c4 d4 50 20 39 39 b8 18 23 a1 d3 |{.B....P 99..#..|
+00000080 38 d3 9d 41 81 c2 4b ba 4c 28 c0 14 22 71 df d9 |8..A..K.L(.."q..|
+00000090 e1 57 fc 9c 4f 0e 28 9a 13 c6 a1 e2 de f0 81 3b |.W..O.(........;|
+000000a0 5f c1 7b 61 f5 fc 74 93 f1 06 7d 9b 67 56 45 a4 |_.{a..t...}.gVE.|
+000000b0 f8 83 |..|
>>> Flow 8 (server to client)
-00000000 16 03 03 00 89 b7 93 18 5b 36 18 ce 99 4a 72 26 |........[6...Jr&|
-00000010 ab cb a4 70 60 0f 7a 02 62 28 f3 10 54 77 a7 33 |...p`.z.b(..Tw.3|
-00000020 32 a6 29 c8 8d 18 48 8f 9d 45 6e 7e 06 07 ca b3 |2.)...H..En~....|
-00000030 b6 45 eb ac f2 41 f1 d9 19 9e 30 1f c0 18 40 1c |.E...A....0... at .|
-00000040 55 09 4d f2 23 75 2f 2f c8 b7 46 63 05 d1 73 c0 |U.M.#u//..Fc..s.|
-00000050 02 71 de 5e 4a 84 92 3d 9a b9 68 62 31 91 7d 23 |.q.^J..=..hb1.}#|
-00000060 43 e3 4b 00 98 2e 01 12 f4 1f fa 4c aa 91 a0 ca |C.K........L....|
-00000070 9c a0 d9 6b 7f 5c b3 f4 8d e2 3a 54 eb e9 82 44 |...k.\....:T...D|
-00000080 21 54 ac 85 86 39 b8 df 23 64 2a 0c 3e 1d 16 03 |!T...9..#d*.>...|
-00000090 03 02 89 b7 93 18 5b 36 18 ce 9a 1c ae 99 12 58 |......[6.......X|
-000000a0 12 fa ef da 77 04 7f b5 42 68 b1 59 64 50 92 2b |....w...Bh.YdP.+|
-000000b0 a0 21 b7 b3 4c f8 c2 cc 75 5a d0 85 50 95 f4 1b |.!..L...uZ..P...|
-000000c0 c9 b2 1f 53 94 4c fd 6d 18 ad 1a 0d 24 9f fb 4c |...S.L.m....$..L|
-000000d0 19 13 5a 74 f2 e2 59 dd 1b d8 67 bc d9 d0 da ab |..Zt..Y...g.....|
-000000e0 a7 7f 8e ca e0 09 28 59 18 8d a1 8a c9 c3 2e 76 |......(Y.......v|
-000000f0 b9 0d 2f 56 5f c4 77 07 17 ac 62 26 a1 91 50 ee |../V_.w...b&..P.|
-00000100 60 45 aa a0 8a d9 1a 13 65 68 c8 cf ca 0c 50 3e |`E......eh....P>|
-00000110 9f 39 62 02 12 ea b4 ed e2 6c 0e 28 32 d7 fb ec |.9b......l.(2...|
-00000120 fc 6d e4 0a 14 1d 88 00 a8 c0 57 1e be 78 fd 18 |.m........W..x..|
-00000130 6e 40 70 37 2e f5 3b 52 59 03 02 bf 27 18 c8 00 |n at p7..;RY...'...|
-00000140 58 8f 5e d8 a8 7c 4c 54 83 4a fe f3 dc f8 19 2a |X.^..|LT.J.....*|
-00000150 00 ed 96 93 0e e4 45 58 8f 41 99 0d 93 f5 6c a4 |......EX.A....l.|
-00000160 4e 62 f2 4b 9a cb 69 30 5a 4b 36 45 f2 d2 c1 62 |Nb.K..i0ZK6E...b|
-00000170 f9 1c c4 c3 b2 94 b3 17 1a ed d8 57 ba b7 79 a1 |...........W..y.|
-00000180 a2 2e 5a 18 79 36 0b 54 ee 2c 2c 3b 62 96 5d e5 |..Z.y6.T.,,;b.].|
-00000190 3c 74 0e be 52 6f 06 7c 93 05 86 0f d6 1d d0 ee |<t..Ro.|........|
-000001a0 f9 ac 67 50 a6 d3 36 f7 5f 0b 3f 44 3b fc 4b 79 |..gP..6._.?D;.Ky|
-000001b0 b7 29 04 6c 37 18 2a 04 bf f4 3e 1a 53 f3 93 e5 |.).l7.*...>.S...|
-000001c0 f2 b7 b1 4b ed 19 5a 2f 40 d1 f2 91 49 0b 8b f6 |...K..Z/@...I...|
-000001d0 21 0b 20 01 ce 0f a8 f1 44 3f 5e b1 89 1a 15 9f |!. .....D?^.....|
-000001e0 4c c5 93 6b 68 93 ab 67 b5 1d 10 fa 22 53 e3 0f |L..kh..g...."S..|
-000001f0 c7 63 d0 32 b7 52 c6 2e b7 47 a4 1a b4 ab 35 a9 |.c.2.R...G....5.|
-00000200 b0 0e cd f6 8c e7 54 6c 77 7b 5c 6c c2 b3 02 89 |......Tlw{\l....|
-00000210 74 f7 b1 61 91 dc 01 3a 68 d9 81 78 21 95 b1 67 |t..a...:h..x!..g|
-00000220 36 2d 2a d6 c4 96 0d 7b e0 44 83 cd 52 e4 05 36 |6-*....{.D..R..6|
-00000230 a4 1d 2a 24 e8 cc 76 d7 66 2f 32 ef 8f 70 ef 26 |..*$..v.f/2..p.&|
-00000240 90 73 2e e6 b4 53 91 13 5b 5e 15 51 15 56 e9 43 |.s...S..[^.Q.V.C|
-00000250 22 9a b6 55 3d 94 00 35 73 41 12 fc 8a 0b fd 89 |"..U=..5sA......|
-00000260 7c 00 14 0d b8 f6 76 d0 ac 33 1d e4 73 49 e9 a2 ||.....v..3..sI..|
-00000270 09 69 e1 f1 a7 92 48 ee 2e fc ef 13 09 7c a7 72 |.i....H......|.r|
-00000280 eb 4c 15 39 17 6e cd 71 c0 e9 48 06 43 09 19 39 |.L.9.n.q..H.C..9|
-00000290 72 b0 9c f8 0e 75 af a8 eb 25 96 36 75 68 16 8f |r....u...%.6uh..|
-000002a0 e8 f6 66 56 66 63 b0 52 47 74 55 af c8 7a 07 dc |..fVfc.RGtU..z..|
-000002b0 d0 8b bf 51 6e bc 77 fa 8a 03 43 0c 5a 47 fb c7 |...Qn.w...C.ZG..|
-000002c0 be b3 ef b5 ad 24 48 40 6c 4b 03 41 dd 7c 3e 6e |.....$H at lK.A.|>n|
-000002d0 25 01 4b 45 ce ad d7 23 3a 6c 33 0b f1 7a 44 07 |%.KE...#:l3..zD.|
-000002e0 7e c8 bd 52 a5 a8 30 91 95 3e 4d 42 07 67 57 fb |~..R..0..>MB.gW.|
-000002f0 c0 4a ed 9f 76 21 8e df fb f6 a4 0a 08 1e 5b c6 |.J..v!........[.|
-00000300 3e a3 8c 47 a4 4d 41 2b e6 8f 42 43 cd ef a8 f1 |>..G.MA+..BC....|
-00000310 88 f2 b3 46 eb 8a 24 a3 98 a2 d7 d2 16 03 03 00 |...F..$.........|
-00000320 e5 b7 93 18 5b 36 18 ce 9b 62 57 ae 22 62 34 88 |....[6...bW."b4.|
-00000330 41 e1 7e 2a 4a 07 b4 b8 aa 80 32 f5 93 4c 58 79 |A.~*J.....2..LXy|
-00000340 82 51 d4 b8 c8 5b d2 99 a3 18 43 aa c2 14 bf 65 |.Q...[....C....e|
-00000350 e8 90 8d 46 69 d5 fa 34 e4 1a 47 06 dc 1a ae e9 |...Fi..4..G.....|
-00000360 40 b2 2e 7e 5e 74 f7 72 4d a9 e2 b7 52 b4 bb dc |@..~^t.rM...R...|
-00000370 06 e6 50 7e ef 42 8f 72 08 63 f9 ec 9e 13 36 0f |..P~.B.r.c....6.|
-00000380 d4 95 72 2b ff a5 6d 4b 1b db d6 b3 25 50 f0 dd |..r+..mK....%P..|
-00000390 e3 89 f5 c1 c0 3f aa 6c f0 a7 30 5d 56 76 77 b6 |.....?.l..0]Vvw.|
-000003a0 24 8f 93 fd 49 8c 73 1e f7 5c 5c 3a f3 0d 5e 89 |$...I.s..\\:..^.|
-000003b0 a4 bb 48 8a 82 ed 01 a6 2d eb b1 fe d2 6e 4e 88 |..H.....-....nN.|
-000003c0 1d 06 b6 f5 d8 41 86 40 fe 45 3e ef 35 9b 88 df |.....A. at .E>.5...|
-000003d0 48 af e0 05 33 4e 13 15 8b b6 5a 8e 5c f8 2a 59 |H...3N....Z.\.*Y|
-000003e0 14 6d 4a 79 75 48 e4 9d 16 4f 6f 65 9c c3 40 1e |.mJyuH...Ooe.. at .|
-000003f0 7c 72 60 ce b9 f8 61 3b ff 34 81 94 01 aa b3 59 ||r`...a;.4.....Y|
-00000400 72 d2 1e 5f fe 7f 16 03 03 00 46 b7 93 18 5b 36 |r.._......F...[6|
-00000410 18 ce 9c c8 c9 b2 10 f1 39 bb f0 80 a9 0b 68 76 |........9.....hv|
-00000420 2b 60 0b c5 f3 eb 16 72 b5 4c c9 42 96 39 bf c1 |+`.....r.L.B.9..|
-00000430 94 87 f0 47 80 34 11 e2 1c 4c fc 26 d6 4b 00 49 |...G.4...L.&.K.I|
-00000440 ef 73 00 4e ab 61 d6 1f 89 2c 7e f2 5c ea 6b 5c |.s.N.a...,~.\.k\|
-00000450 50 |P|
+00000000 16 03 03 00 81 ec 0e 7c 60 5b ed 0f 29 e6 cd 3a |.......|`[..)..:|
+00000010 ca ff f7 68 3e 22 30 cf 43 b2 29 71 ca 3a 06 db |...h>"0.C.)q.:..|
+00000020 e0 df bc 87 51 62 df 37 37 7a 9d b4 2d 35 ab bb |....Qb.77z..-5..|
+00000030 d2 ed d1 50 e7 61 a4 27 18 43 23 74 4b 1d 14 46 |...P.a.'.C#tK..F|
+00000040 80 5c 10 99 10 47 b2 51 92 11 1f aa f1 5a c3 cf |.\...G.Q.....Z..|
+00000050 f5 30 69 96 26 f6 0e 7c e9 e1 7c 4b d5 2f 46 1c |.0i.&..|..|K./F.|
+00000060 7d 18 a5 20 f1 ff 40 9e c7 d5 d4 54 33 c4 99 9c |}.. .. at ....T3...|
+00000070 26 95 d9 ca 82 fc e7 27 37 fc 33 9f f8 c7 cb 0a |&......'7.3.....|
+00000080 9d 4e bc 66 ca fc 16 03 03 02 69 ab be 55 39 99 |.N.f......i..U9.|
+00000090 ac 66 a6 86 03 51 70 d8 fa 7d e7 89 09 fc eb b5 |.f...Qp..}......|
+000000a0 25 f6 95 0c 40 3d b8 ea b6 78 41 db a4 f3 92 83 |%...@=...xA.....|
+000000b0 00 c8 8d 1f 19 0c ec ec e5 60 07 d9 31 2d 3b 91 |.........`..1-;.|
+000000c0 ba ad b3 c1 fb b5 57 52 73 37 43 89 22 e0 45 7c |......WRs7C.".E||
+000000d0 b0 da 1f 69 76 d3 af fc ba f0 98 ec d2 7f be f0 |...iv...........|
+000000e0 a4 76 f0 d9 30 1b 78 22 bb 43 fd 45 64 07 e4 64 |.v..0.x".C.Ed..d|
+000000f0 c5 74 2f ed ba 23 8d 3a 5a ff 7f 35 de 25 53 0d |.t/..#.:Z..5.%S.|
+00000100 ac ae 5b da b1 7d 86 fe da c8 9e 79 58 6c 4c 9c |..[..}.....yXlL.|
+00000110 6d f9 e9 1d 31 ff aa fb 8e 2e 98 f4 3a 67 33 9b |m...1.......:g3.|
+00000120 a3 63 5e fc 74 f5 c5 28 76 30 e6 22 8a 85 79 56 |.c^.t..(v0."..yV|
+00000130 4e cf 94 38 92 61 09 22 00 95 d4 16 b4 e0 80 05 |N..8.a."........|
+00000140 28 35 30 6f 56 7d f8 b9 ed 49 72 b0 9f 47 9f 07 |(50oV}...Ir..G..|
+00000150 7f 1d b9 3b 6d ce c9 09 72 2f 65 b0 88 b4 ec 24 |...;m...r/e....$|
+00000160 29 8d 57 93 a7 51 85 32 26 4c 31 21 24 b1 ab 97 |).W..Q.2&L1!$...|
+00000170 c6 3c 38 44 d4 8f d0 3b ea 62 39 48 90 ca c4 5c |.<8D...;.b9H...\|
+00000180 9c 72 08 a4 3f d0 1e 3e 9f 23 02 0e 94 b4 14 cc |.r..?..>.#......|
+00000190 96 bc 23 22 2f af c5 ed 81 da 49 ca 26 f4 55 6a |..#"/.....I.&.Uj|
+000001a0 b3 24 3f 13 a5 f7 d6 82 70 04 37 63 dc 92 63 0f |.$?.....p.7c..c.|
+000001b0 3d f7 4e 42 7c 5a 42 df 53 17 48 25 cb da 31 e1 |=.NB|ZB.S.H%..1.|
+000001c0 67 a7 22 8c ca db 2d 33 49 86 62 b5 ba 38 53 4c |g."...-3I.b..8SL|
+000001d0 12 f3 c3 f6 b6 01 53 b1 11 43 e1 e8 ba 3f 68 7a |......S..C...?hz|
+000001e0 9c 10 09 82 d1 90 cd 9e 52 2e 29 15 0b 13 c3 e3 |........R.).....|
+000001f0 34 ef 76 8a 0d f9 f6 17 76 57 c2 55 cb 7d 45 e0 |4.v.....vW.U.}E.|
+00000200 d5 e6 53 93 75 57 c2 ab 26 5a 13 02 05 7a 60 2b |..S.uW..&Z...z`+|
+00000210 b6 92 1a 88 0c 34 59 81 40 42 70 d5 4e 7b d3 14 |.....4Y. at Bp.N{..|
+00000220 3c e6 70 81 90 ff 53 79 c5 f3 7c d9 02 6f 35 6b |<.p...Sy..|..o5k|
+00000230 d4 81 ff 32 a2 71 28 a0 4b 22 75 9f 3b 50 c8 03 |...2.q(.K"u.;P..|
+00000240 22 e7 4f 1f c5 c5 99 67 f3 2c 97 5e 43 89 84 39 |".O....g.,.^C..9|
+00000250 04 c9 4c 1e e0 da 39 8f 78 8f 95 3a 64 74 d3 63 |..L...9.x..:dt.c|
+00000260 13 d4 14 9d 98 6c bb 27 81 1e 12 88 8c d4 11 1c |.....l.'........|
+00000270 4a 71 2f 10 dc 5b 9a 8e 70 e6 bf 0b a2 50 4c d1 |Jq/..[..p....PL.|
+00000280 c4 29 b7 85 9e 0f 86 33 7c 38 e4 ae d4 53 5e 81 |.).....3|8...S^.|
+00000290 95 cf 6c 1a 15 7d af 20 53 21 f4 84 5c 46 5f 10 |..l..}. S!..\F_.|
+000002a0 1f 68 7d 9a 20 0d a8 1f 90 2f ae b8 c0 57 e0 4b |.h}. ..../...W.K|
+000002b0 ad ec 9d ae 51 52 78 5d 3f bb de 54 54 d4 18 ff |....QRx]?..TT...|
+000002c0 e6 b4 c9 52 f8 66 63 e3 bf 7a f3 5e c6 3f d9 27 |...R.fc..z.^.?.'|
+000002d0 71 07 e7 69 6d cb 60 24 55 4e f9 34 e7 5f a3 37 |q..im.`$UN.4._.7|
+000002e0 76 90 ec b5 eb ff 49 38 15 71 23 fd 77 30 80 c8 |v.....I8.q#.w0..|
+000002f0 ca 0e 38 3c 16 03 03 00 bc 89 27 c8 13 dd 05 8b |..8<......'.....|
+00000300 46 97 5f 19 76 db 29 8d b1 24 52 fe 7a 2e 2c 4d |F._.v.)..$R.z.,M|
+00000310 e2 f9 59 89 48 82 f5 d7 87 af 99 4b 98 c5 7c 1d |..Y.H......K..|.|
+00000320 1a e1 4d fd 0c 37 d0 d3 d8 e2 f8 0f 04 d5 15 21 |..M..7.........!|
+00000330 60 09 47 0c d6 bf 09 bf 55 c1 ae 33 11 35 94 29 |`.G.....U..3.5.)|
+00000340 80 96 3a 53 ae a8 29 c4 84 37 e2 80 f9 da 79 18 |..:S..)..7....y.|
+00000350 77 50 26 32 bf f6 b2 6d 3a 73 25 e7 cd 34 6d ea |wP&2...m:s%..4m.|
+00000360 a0 92 40 7e f8 eb d0 82 06 b3 a1 f5 1c 8e b2 ef |..@~............|
+00000370 b2 4f 0c bb 04 1b c7 cf bc dd 42 19 00 3e 45 93 |.O........B..>E.|
+00000380 e6 72 57 ed eb d9 1d b3 71 b7 fe 84 03 57 e4 9c |.rW.....q....W..|
+00000390 71 78 35 39 63 b1 cf 36 b9 5a d6 95 13 ee 4d 2f |qx59c..6.Z....M/|
+000003a0 22 ef ed 2e fc 69 7c 12 c2 0e 32 ed 05 17 42 5c |"....i|...2...B\|
+000003b0 a7 62 ab 6b 46 16 03 03 00 3a b9 af 3d 25 e4 6a |.b.kF....:..=%.j|
+000003c0 a9 b5 b4 00 79 21 aa 3c f3 56 50 bd 32 a4 a8 ab |....y!.<.VP.2...|
+000003d0 8a 60 77 5d b7 3e 89 d3 60 a2 b8 5c a8 99 27 bb |.`w].>..`..\..'.|
+000003e0 0e dd 93 af 3e 2b 66 8e 56 19 03 29 44 6a 63 a1 |....>+f.V..)Djc.|
+000003f0 c7 17 f3 1e 16 03 03 00 14 1c bd e4 7b c3 88 d9 |............{...|
+00000400 be ba c3 c3 fb b7 07 9d f1 58 3e b0 61 |.........X>.a|
>>> Flow 9 (client to server)
-00000000 16 03 03 02 89 00 00 00 00 00 00 00 03 c2 d4 9b |................|
-00000010 19 c8 b6 76 fb ef e4 b2 f7 97 c7 80 f5 e2 b4 3c |...v...........<|
-00000020 bd b7 b8 25 da 54 52 a7 f8 38 0d 48 c0 13 19 82 |...%.TR..8.H....|
-00000030 17 3c ff d2 c0 8f bd 76 5d 16 39 db a7 51 3f b1 |.<.....v].9..Q?.|
-00000040 72 b6 59 e4 8c 6c f5 33 de 78 15 8d 64 cf 55 c6 |r.Y..l.3.x..d.U.|
-00000050 47 e3 0b 30 06 e1 6c 2d e1 e0 7a e1 0a da dd 0d |G..0..l-..z.....|
-00000060 60 5b 06 28 a8 94 14 a3 cc 91 96 8d 2b 71 af ff |`[.(........+q..|
-00000070 c2 32 e2 19 77 96 f3 5b 53 3a d3 29 51 c2 54 98 |.2..w..[S:.)Q.T.|
-00000080 f3 00 8e 9a fe ef bb ea 06 27 58 54 3c c8 67 dc |.........'XT<.g.|
-00000090 f3 41 01 77 de 25 b4 54 53 67 64 41 b3 ae 2b c2 |.A.w.%.TSgdA..+.|
-000000a0 57 cd 74 14 3c 46 a7 70 ec a8 bc 0e 05 46 ce fc |W.t.<F.p.....F..|
-000000b0 c8 54 4d 23 25 b9 e0 45 fa 1e 1b 2c f1 d0 da 66 |.TM#%..E...,...f|
-000000c0 3c 00 e5 b3 f5 f9 ff 64 75 82 f9 dd c2 3f 42 46 |<......du....?BF|
-000000d0 27 ca 72 a2 f7 6c 4e bf 98 05 e6 99 b5 7b 60 33 |'.r..lN......{`3|
-000000e0 99 e8 7a 7c 91 41 64 cd 96 60 f2 f6 c8 bd 4f 35 |..z|.Ad..`....O5|
-000000f0 5f 6f 43 11 b0 94 3c 98 bc 58 15 7e 52 01 ba cf |_oC...<..X.~R...|
-00000100 71 f4 0a fb 85 0a 24 13 0c 4a 53 55 77 92 91 cd |q.....$..JSUw...|
-00000110 ce 39 7e 07 2f 4f ba 47 ca bd 67 5b ce 5a 04 03 |.9~./O.G..g[.Z..|
-00000120 ff 86 0a 82 80 b9 42 b8 4c e3 ce 73 b2 4a 5a 4b |......B.L..s.JZK|
-00000130 f5 f2 44 d8 e5 01 30 c8 2e ce 4f 62 2d 34 9c d6 |..D...0...Ob-4..|
-00000140 57 20 db 37 20 66 03 b6 4d a7 0f 75 30 d8 ad 2f |W .7 f..M..u0../|
-00000150 63 f7 4e 24 ec 68 e0 a2 a9 b1 3d 68 e5 c1 8b d8 |c.N$.h....=h....|
-00000160 19 dd 40 33 c6 5c 57 3b 22 5a 9c 24 fe 2f 92 54 |.. at 3.\W;"Z.$./.T|
-00000170 0f e8 85 74 06 72 59 ab 1d b8 5d 31 91 ed 05 51 |...t.rY...]1...Q|
-00000180 61 c6 43 3d 81 f4 47 c3 80 17 4d 1b 08 c4 85 1b |a.C=..G...M.....|
-00000190 b7 37 b0 cf 5c 73 5f 56 0f 5a b5 21 21 46 e3 df |.7..\s_V.Z.!!F..|
-000001a0 e6 cb 9d ac ab 16 c0 b1 b8 2a 4a 5b a7 2d 7a 00 |.........*J[.-z.|
-000001b0 9f 9d 76 57 ab 20 ea 80 8a 7a ca 14 45 d7 4e 1b |..vW. ...z..E.N.|
-000001c0 c8 7c b8 c6 82 fc 40 b2 b4 7d f1 74 7d b5 2a 90 |.|.... at ..}.t}.*.|
-000001d0 01 83 d4 d1 26 63 d7 39 69 b1 33 5f 7e 54 de f7 |....&c.9i.3_~T..|
-000001e0 08 3d 62 3b da 57 0d d4 48 99 9a 3e 99 e5 b0 6b |.=b;.W..H..>...k|
-000001f0 25 45 38 36 aa 7a bb 81 7d 0b dd 1d 50 c4 17 68 |%E86.z..}...P..h|
-00000200 4b a7 f7 2f d8 cd 97 a6 ea 24 9b 34 69 9e 7d ad |K../.....$.4i.}.|
-00000210 6a 17 23 d8 36 61 cf 85 74 47 18 5b fd cd 72 ac |j.#.6a..tG.[..r.|
-00000220 c2 a2 b4 53 e3 5d 25 f7 bb b6 95 99 a0 e5 05 38 |...S.]%........8|
-00000230 0a 52 32 f6 7d a6 30 5c 11 6b 8a 7b af ec a2 9b |.R2.}.0\.k.{....|
-00000240 b8 f1 85 6d a8 b7 79 61 42 60 4a 35 73 fb d5 2c |...m..yaB`J5s..,|
-00000250 1f 84 5c d9 c9 23 10 e8 a4 2c 56 fd f4 22 1a 7a |..\..#...,V..".z|
-00000260 f3 b2 c5 69 8b c9 d1 d5 45 c8 65 59 fc ab d9 d3 |...i....E.eY....|
-00000270 7d ab c3 fe bc da 6d a3 cd 0c 83 32 70 65 c7 7f |}.....m....2pe..|
-00000280 8c 83 c8 97 3e 7f 89 fc 11 7d 1c a5 fd 99 16 03 |....>....}......|
-00000290 03 00 5e 00 00 00 00 00 00 00 04 64 60 91 c0 fd |..^........d`...|
-000002a0 3a 96 5a ac 5a 13 a9 9a 41 eb a0 6d 51 98 ee a8 |:.Z.Z...A..mQ...|
-000002b0 4d ee 90 c9 3e a5 15 ac f3 6a c8 56 f3 20 c3 10 |M...>....j.V. ..|
-000002c0 e3 3a d1 ea b0 7d a7 21 ae 2c b1 fa 5c b8 c1 fa |.:...}.!.,..\...|
-000002d0 d7 97 6e ea fd 09 53 46 db aa e4 39 31 00 c2 bb |..n...SF...91...|
-000002e0 ad 36 10 cd e9 cb 46 31 7b 66 ee ce 0c a8 f9 c2 |.6....F1{f......|
-000002f0 0a 16 03 03 00 a0 00 00 00 00 00 00 00 05 6d a0 |..............m.|
-00000300 03 60 12 bb 06 89 0c 03 ad f7 36 f3 5c e4 c1 65 |.`........6.\..e|
-00000310 b2 26 c9 f5 87 85 f9 8f 2d 05 43 35 32 d7 0a a0 |.&......-.C52...|
-00000320 e5 16 7a 94 62 15 ed cc 8e 9f e3 10 8d e7 83 a2 |..z.b...........|
-00000330 ea e4 07 49 c9 df 1d 2b 6f b8 0f 67 31 22 44 9b |...I...+o..g1"D.|
-00000340 65 77 99 78 f9 3e 14 67 3a 90 e5 5a c2 b5 1b ee |ew.x.>.g:..Z....|
-00000350 db 20 73 8d 85 22 4d 79 6e e9 17 d0 b1 03 58 f3 |. s.."Myn.....X.|
-00000360 cf 1b f5 03 9a 75 1f 7a 3b 49 ee 67 04 da c4 fc |.....u.z;I.g....|
-00000370 7a 62 a9 ff 26 4f 71 b2 7e e9 c7 78 96 74 1e 63 |zb..&Oq.~..x.t.c|
-00000380 eb 2b 2f 18 1f 19 cf 1e 89 73 39 9e f6 02 3d 31 |.+/......s9...=1|
-00000390 50 65 1f 80 19 26 14 03 03 00 19 00 00 00 00 00 |Pe...&..........|
-000003a0 00 00 06 82 62 df fd 51 9e be 21 0b 22 b6 c1 6d |....b..Q..!."..m|
-000003b0 5c 90 ea c5 16 03 03 00 28 00 00 00 00 00 00 00 |\.......(.......|
-000003c0 00 d6 5f a7 05 2b 99 cc 7d fb d7 38 5e e3 31 a7 |.._..+..}..8^.1.|
-000003d0 c9 1c bd 7b c7 89 d0 e5 b5 93 78 d1 63 57 d2 76 |...{......x.cW.v|
-000003e0 38 |8|
+00000000 16 03 03 02 69 d3 b2 83 ca 08 61 36 6f fa 66 de |....i.....a6o.f.|
+00000010 5c 42 5f 35 17 f4 4c b3 5e 17 94 07 c5 2a 89 90 |\B_5..L.^....*..|
+00000020 b8 31 50 af 55 91 b1 28 bc 00 00 da 57 85 cc d5 |.1P.U..(....W...|
+00000030 a5 a7 ec ba 52 d5 1f ab b5 4f a3 53 9c af 59 20 |....R....O.S..Y |
+00000040 be 13 f6 c5 70 b0 cc f7 59 69 d1 db 80 7f 60 29 |....p...Yi....`)|
+00000050 e1 e8 7a 1e 97 a6 e1 a2 11 70 4f b4 7b 53 7c 9a |..z......pO.{S|.|
+00000060 dd fa 58 5d 12 a4 fb 3e 46 dd d3 4d ac e3 b6 73 |..X]...>F..M...s|
+00000070 05 42 03 f3 37 79 a0 10 34 ef 01 6f c6 27 52 4b |.B..7y..4..o.'RK|
+00000080 75 4c b2 86 1b d6 ca 13 b4 31 41 db 93 2f a3 35 |uL.......1A../.5|
+00000090 e1 e9 bc 65 85 c8 1a e2 7b 6e 36 49 e8 ed 04 a9 |...e....{n6I....|
+000000a0 cb a9 70 32 c0 4d e5 f5 94 d8 af 7d 41 b6 dc e5 |..p2.M.....}A...|
+000000b0 fc ff db 9f 91 50 df c6 b2 4a 0c bb 86 4e 50 a5 |.....P...J...NP.|
+000000c0 2a 3b 69 e2 3d fa 10 eb cc 48 21 9d 98 78 02 0b |*;i.=....H!..x..|
+000000d0 e7 4d 83 63 9e e5 ad 2c 7b 46 d1 09 28 35 07 6c |.M.c...,{F..(5.l|
+000000e0 12 c9 ae f0 4c 7c 00 aa 54 ba 7b e8 42 be e0 18 |....L|..T.{.B...|
+000000f0 f4 df a0 9d eb 8f a2 3a d0 00 b6 e0 eb 90 65 38 |.......:......e8|
+00000100 b2 cc 21 87 57 b7 50 07 41 e2 5a 9b c8 2b ae 64 |..!.W.P.A.Z..+.d|
+00000110 55 6a d7 b5 0d 5d f0 ac da 0b f0 80 75 8d 6a 0a |Uj...]......u.j.|
+00000120 5b c5 2a 20 f2 ab 75 76 a3 33 f1 43 24 06 45 75 |[.* ..uv.3.C$.Eu|
+00000130 63 58 60 57 ca 7f d2 8f e8 a5 b8 e3 72 37 39 bd |cX`W........r79.|
+00000140 9c dd 10 b0 f8 b5 e8 46 4a 39 ac 94 69 08 51 29 |.......FJ9..i.Q)|
+00000150 27 2d 28 0f 15 8a 91 00 3b cc 99 77 ea 82 0d e1 |'-(.....;..w....|
+00000160 66 ed 34 da 6e 88 47 e5 f4 1b 28 28 cd 38 9f e5 |f.4.n.G...((.8..|
+00000170 1c 26 67 3d 83 d0 b1 88 a3 08 9c 2e 08 a5 b7 af |.&g=............|
+00000180 15 28 d5 1e aa c9 58 17 48 85 f7 13 17 6f 55 c3 |.(....X.H....oU.|
+00000190 dc 9d 2e 7e 67 45 7a cb 80 a7 e5 77 86 96 36 4d |...~gEz....w..6M|
+000001a0 f7 df 27 7d f4 5d 53 9b be e6 b2 b9 44 b9 86 e9 |..'}.]S.....D...|
+000001b0 8f 33 26 4e 20 97 e4 34 66 58 6d d5 28 be e8 84 |.3&N ..4fXm.(...|
+000001c0 de 2f 19 f2 46 52 80 84 e9 ef 0e 6c 55 5c 43 8c |./..FR.....lU\C.|
+000001d0 51 19 8b 22 30 b7 b3 eb 9f ed 35 a1 fe 09 aa 6a |Q.."0.....5....j|
+000001e0 f8 b6 37 7e 20 4c e5 76 ae 10 4c dd 67 7c 07 e2 |..7~ L.v..L.g|..|
+000001f0 0c dc 78 77 a1 8e c1 d1 aa fa d3 36 8b 9c 74 ed |..xw.......6..t.|
+00000200 e2 fe 84 98 40 95 f2 1a a6 fd 77 cf 47 d3 c3 d6 |.... at .....w.G...|
+00000210 bc 38 45 a9 94 63 13 52 2d 7b 3f 3d 06 1e 0a 31 |.8E..c.R-{?=...1|
+00000220 cb 98 1d 18 fa a7 86 21 65 c7 58 dd 78 13 2d 4d |.......!e.X.x.-M|
+00000230 76 57 9d 65 15 a3 2d be 7f c9 58 78 b7 89 3c d6 |vW.e..-...Xx..<.|
+00000240 dc 7e 5b c5 1b 93 78 04 7b ca ef 61 77 6c 27 6b |.~[...x.{..awl'k|
+00000250 a5 30 67 43 64 a7 30 f0 dd 5c 63 92 76 9a e3 a2 |.0gCd.0..\c.v...|
+00000260 31 12 49 8e c4 7e 80 ce 1e ce 94 66 2f 6f 16 03 |1.I..~.....f/o..|
+00000270 03 00 35 39 86 a0 5a 88 07 66 5f 43 59 ed fb b5 |..59..Z..f_CY...|
+00000280 0c 0b ee ff 76 62 28 ea 62 7e 53 72 3d d9 26 9f |....vb(.b~Sr=.&.|
+00000290 06 64 99 83 a5 3c 59 45 84 4d 79 86 1d b4 21 14 |.d...<YE.My...!.|
+000002a0 29 df f1 99 aa 6a 64 91 16 03 03 00 98 22 32 c2 |)....jd......"2.|
+000002b0 63 2c 82 b9 47 02 65 97 6b 14 fc 35 b8 20 ce 3c |c,..G.e.k..5. .<|
+000002c0 1b 16 fd 51 55 e8 31 b5 58 e6 64 a8 2b b0 f2 ab |...QU.1.X.d.+...|
+000002d0 31 7a cd 3e 32 43 64 eb 08 b0 52 d4 81 56 e3 04 |1z.>2Cd...R..V..|
+000002e0 4e d2 1a b8 f6 ae 64 d2 c0 05 9b 18 84 71 a7 ad |N.....d......q..|
+000002f0 ea 49 f6 b5 ae 91 ad 66 6f cb fa 56 de 1e 40 22 |.I.....fo..V..@"|
+00000300 7f d3 44 c4 a7 bf b1 7b 61 e3 09 1f fe 3b 4b 7b |..D....{a....;K{|
+00000310 5a 3f ae 4e c4 5c a8 ac a4 c2 fc 0e 1f 12 4f 9b |Z?.N.\........O.|
+00000320 f9 e0 a2 89 ab a0 bb e8 f9 97 5a 7c 8d e8 58 87 |..........Z|..X.|
+00000330 3f 4c 1c f3 ff 6e b9 a0 e6 f7 e4 c2 43 cc af 9e |?L...n......C...|
+00000340 06 3a 1c ee ef 14 03 03 00 11 8b 6d c3 12 83 c4 |.:.........m....|
+00000350 2f e7 67 81 db 18 9a 33 e6 fa 82 16 03 03 00 20 |/.g....3....... |
+00000360 ef c9 6f 3f b7 9d 9d 2d a0 05 b6 fd 74 8e ff de |..o?...-....t...|
+00000370 cc 4b ca 4c 5b 4d 61 30 76 b5 f3 7a d1 46 d6 6a |.K.L[Ma0v..z.F.j|
>>> Flow 10 (server to client)
-00000000 14 03 03 00 19 b7 93 18 5b 36 18 ce 9d 68 22 e1 |........[6...h".|
-00000010 d0 06 aa e5 87 f8 49 bc 38 d7 b9 38 85 97 16 03 |......I.8..8....|
-00000020 03 00 28 24 71 bf 67 14 d6 5e 29 1b de e6 f4 e0 |..($q.g..^).....|
-00000030 33 76 dc 66 c6 95 c0 3a 15 49 99 09 2f cf 6b 6b |3v.f...:.I../.kk|
-00000040 a1 8f 1a e4 af 8d 1e 7f 02 b1 87 17 03 03 00 21 |...............!|
-00000050 24 71 bf 67 14 d6 5e 2a 61 7b 98 dd e8 52 b0 1e |$q.g..^*a{...R..|
-00000060 28 46 28 de e2 22 65 6c 66 85 3a 1d bb 9e 76 a2 |(F(.."elf.:...v.|
-00000070 55 16 03 03 00 1c 24 71 bf 67 14 d6 5e 2b bb 84 |U.....$q.g..^+..|
-00000080 6d f0 1c d0 46 89 bb b2 09 96 dd 95 53 bf ac d7 |m...F.......S...|
-00000090 80 f1 |..|
+00000000 14 03 03 00 11 2e d9 0e 1b 6b 4b 9a 60 96 e9 38 |.........kK.`..8|
+00000010 35 a3 72 3d c4 5b 16 03 03 00 20 62 1f 2b 02 e8 |5.r=.[.... b.+..|
+00000020 22 0a 89 a2 f6 60 8a da f2 09 52 5a 92 12 a8 f6 |"....`....RZ....|
+00000030 c3 ee 25 17 6b 91 25 3e 2b 75 ba 17 03 03 00 19 |..%.k.%>+u......|
+00000040 b9 4e 6b c3 74 30 39 f9 3f a2 aa af 80 49 6b 8a |.Nk.t09.?....Ik.|
+00000050 f2 a1 9b f5 c7 34 f7 1b 2f 16 03 03 00 14 2d 25 |.....4../.....-%|
+00000060 74 c2 c7 80 a8 5f 65 ff 65 b0 c2 50 c8 bc fe 8c |t...._e.e..P....|
+00000070 d4 9e |..|
>>> Flow 11 (client to server)
-00000000 16 03 03 00 a9 00 00 00 00 00 00 00 01 61 12 ee |.............a..|
-00000010 0a f2 5e e2 3d 3d 36 4c 14 10 20 aa 4d 8a 91 e4 |..^.==6L.. .M...|
-00000020 c2 b0 63 68 9e f5 71 b7 a4 ee 75 27 20 8c 2e 21 |..ch..q...u' ..!|
-00000030 f5 57 3d e9 9a 05 da 7b a5 af 6a 17 10 8b eb 25 |.W=....{..j....%|
-00000040 8a 79 75 07 dc fe f5 7f a5 e2 63 31 ee 55 ba c0 |.yu.......c1.U..|
-00000050 e6 3d de 03 36 2b 64 19 b1 1a b8 80 09 25 8c dd |.=..6+d......%..|
-00000060 dd 59 c7 1d e7 40 20 ae ca a9 b5 14 a7 57 f0 62 |.Y...@ ......W.b|
-00000070 71 88 a3 2c fc a4 50 dc 8b 85 22 20 38 c5 74 ea |q..,..P..." 8.t.|
-00000080 ac 33 1d a3 c5 5c cc 10 62 fd c5 70 22 fa e3 73 |.3...\..b..p"..s|
-00000090 f3 bf 24 14 0d cb 7c 25 e4 74 6c fe c0 70 5e a0 |..$...|%.tl..p^.|
-000000a0 63 a7 e5 f2 6e d8 71 bd 7d b9 f0 b6 0b 70 |c...n.q.}....p|
+00000000 16 03 03 00 ad d0 25 9a 38 60 d3 94 8e b8 23 45 |......%.8`....#E|
+00000010 44 67 95 20 79 1a 27 5f cf bb dc 72 8c 95 2a 02 |Dg. y.'_...r..*.|
+00000020 1d d9 80 c6 61 12 c2 5c ae d5 62 a9 aa b0 4a d0 |....a..\..b...J.|
+00000030 13 ad 6d ae df c9 63 e2 6b 27 bb ca 88 c3 dc 8b |..m...c.k'......|
+00000040 e9 bc 0b fb 32 d6 0f 99 b6 d1 03 7e c9 8d 72 ee |....2......~..r.|
+00000050 09 7b 82 f1 79 11 a7 23 43 8b 77 b8 a9 bd 9e 67 |.{..y..#C.w....g|
+00000060 43 03 79 88 34 ab c2 6b d1 2a cf c7 c9 b6 14 ee |C.y.4..k.*......|
+00000070 ee 32 01 10 fb 85 dc 5a 04 cf 9a ea 8d 8c fc f8 |.2.....Z........|
+00000080 b3 b2 49 c0 93 37 93 09 24 1c 26 97 43 5f dd 09 |..I..7..$.&.C_..|
+00000090 7a 0d c0 6c bd 17 df 78 37 3d 23 6b 9d 27 d2 f7 |z..l...x7=#k.'..|
+000000a0 1c 2e 82 5c ba 95 1c 0f b3 40 af 9f 2f 5e 42 40 |...\..... at ../^B@|
+000000b0 cc b9 |..|
>>> Flow 12 (server to client)
-00000000 16 03 03 00 89 24 71 bf 67 14 d6 5e 2c 55 62 31 |.....$q.g..^,Ub1|
-00000010 5c a3 53 1a c3 2f 89 47 62 33 7e 24 cd ad a9 5b |\.S../.Gb3~$...[|
-00000020 51 79 d8 08 08 ff 09 3c 41 c7 80 ed ec 5a 7a e4 |Qy.....<A....Zz.|
-00000030 71 e1 17 91 5e c1 80 58 35 c7 27 ca 62 74 cc d8 |q...^..X5.'.bt..|
-00000040 e8 35 86 97 bf 05 73 b9 3f ae 5b af 9a 14 88 4b |.5....s.?.[....K|
-00000050 f9 6f a4 de 3d 45 c8 7b 0a b1 7a 81 3e 7c 02 b5 |.o..=E.{..z.>|..|
-00000060 e9 43 a5 64 88 59 f6 55 20 d1 09 39 cd 01 46 0f |.C.d.Y.U ..9..F.|
-00000070 a2 06 f3 2b 45 14 b2 57 21 2c 2f a0 e5 db 02 99 |...+E..W!,/.....|
-00000080 e4 6b 1e 22 99 c9 ae 93 e4 67 89 d1 c6 6d 16 03 |.k.".....g...m..|
-00000090 03 02 89 24 71 bf 67 14 d6 5e 2d ce 6a 42 6b ce |...$q.g..^-.jBk.|
-000000a0 07 4e ff 40 39 4b 00 c8 14 4c 76 e0 4d 09 41 c3 |.N. at 9K...Lv.M.A.|
-000000b0 41 3a ca ac 28 06 01 80 e4 b8 73 a2 fc ea 8d 92 |A:..(.....s.....|
-000000c0 44 0e 43 3e d8 cb 8a 0c a0 c1 5e 88 6d 6d 80 be |D.C>......^.mm..|
-000000d0 9c 9f cc 20 7c fa 6f e4 1a a1 39 c2 a8 7d 04 85 |... |.o...9..}..|
-000000e0 75 5d c4 d3 6f df d7 3a 9d 83 c3 74 aa 49 df 34 |u]..o..:...t.I.4|
-000000f0 e0 41 ad a3 80 80 c3 29 44 b9 5f a1 7b 67 89 30 |.A.....)D._.{g.0|
-00000100 04 b0 90 78 6b 82 fe ae 0c eb e1 5a 64 e2 6f de |...xk......Zd.o.|
-00000110 de 12 db 4f 1f eb 1d a9 66 a1 62 11 ab 54 1f 5d |...O....f.b..T.]|
-00000120 c2 ce 1e a8 b3 8b 29 08 76 13 a0 67 5b e6 1b 2c |......).v..g[..,|
-00000130 bd 1b 42 80 a5 09 b0 03 28 df 77 6f a7 d5 2f 85 |..B.....(.wo../.|
-00000140 2b b1 69 81 5c a0 16 16 1c eb b4 61 f1 f7 70 55 |+.i.\......a..pU|
-00000150 ee 64 9d 8f 1a 0b af af 18 f5 da e6 32 ab b2 28 |.d..........2..(|
-00000160 0d a0 ea b4 44 3d a9 f7 1a 84 c1 8f 30 09 41 13 |....D=......0.A.|
-00000170 a3 34 79 a7 6f da 76 59 62 9f d6 82 0f 48 21 64 |.4y.o.vYb....H!d|
-00000180 11 49 53 cd 3a 44 5a dc 8b 97 8a 84 d2 f9 12 77 |.IS.:DZ........w|
-00000190 b3 5b b0 37 58 7a a3 5a 47 9d c7 e4 83 f5 0a 32 |.[.7Xz.ZG......2|
-000001a0 10 39 aa d6 7c 8e 44 eb a9 fd 0f c0 6a 80 82 21 |.9..|.D.....j..!|
-000001b0 30 d1 36 31 73 38 c5 bd 16 99 71 b5 49 8e 7f df |0.61s8....q.I...|
-000001c0 f9 64 7f ff 16 3b 68 7c b5 7c 1f 41 19 36 dd ef |.d...;h|.|.A.6..|
-000001d0 65 11 b9 91 c4 d4 40 eb 37 94 69 8b 3b 10 56 45 |e..... at .7.i.;.VE|
-000001e0 ee 56 a8 a7 3d 94 17 5c fe f2 88 c7 fb 78 8e 51 |.V..=..\.....x.Q|
-000001f0 53 a8 bc b3 88 ee 75 42 1d 41 b8 c5 34 d5 9e bc |S.....uB.A..4...|
-00000200 b4 b7 1c 97 8b 83 d6 3d 97 4b 43 7a 40 3d 63 6e |.......=.KCz@=cn|
-00000210 cf 57 9a d3 71 6d 54 fe 38 ec 6f d7 c3 aa 1c a8 |.W..qmT.8.o.....|
-00000220 2b f6 34 96 cb 16 da 3e 2d 74 dd f6 1c 33 3c 4e |+.4....>-t...3<N|
-00000230 25 d9 e3 c5 85 52 c3 ea 22 ea 86 16 84 31 05 a4 |%....R.."....1..|
-00000240 7d 41 00 bd 4a b3 79 93 18 1c a1 e4 78 1c 90 49 |}A..J.y.....x..I|
-00000250 b4 9f bc d3 2d d0 f9 46 da 13 7c f6 88 5e e1 b2 |....-..F..|..^..|
-00000260 5c 41 12 bf 2f 1f b4 c3 13 8c 2f a6 83 c5 86 ba |\A../...../.....|
-00000270 20 42 21 57 e1 78 82 0e 4b 55 32 c1 f2 6e 4c a2 | B!W.x..KU2..nL.|
-00000280 a7 c7 63 b3 b5 30 49 9d 7a 51 5e 67 38 52 89 ee |..c..0I.zQ^g8R..|
-00000290 51 16 34 5c f6 b1 04 30 7b f4 b0 f8 88 6c 9d bc |Q.4\...0{....l..|
-000002a0 32 5d 8b 73 b0 df f6 a2 dd e7 62 94 d7 b7 68 92 |2].s......b...h.|
-000002b0 d6 a6 6a b2 53 75 d8 a7 43 1f 1e a2 c0 4e 6a 84 |..j.Su..C....Nj.|
-000002c0 e7 6d ae 81 82 dc 43 bd 8c 44 6a db ec 37 34 70 |.m....C..Dj..74p|
-000002d0 a0 e3 39 a1 17 d2 b7 53 bc 06 0e 33 3f 91 b3 a6 |..9....S...3?...|
-000002e0 0a d1 43 b0 94 54 bc b9 07 52 40 6e 49 99 ab 09 |..C..T...R at nI...|
-000002f0 3f dc 5d 5f c9 33 59 03 3f cf 7b 47 54 2d 05 4b |?.]_.3Y.?.{GT-.K|
-00000300 c2 e6 81 f5 2f 58 5d 84 ad 9d 72 cc 3b 09 70 50 |..../X]...r.;.pP|
-00000310 75 f8 c8 b7 9a 3f b7 3e aa 6a 75 5d 16 03 03 00 |u....?.>.ju]....|
-00000320 e5 24 71 bf 67 14 d6 5e 2e 0b f5 20 45 e5 51 07 |.$q.g..^... E.Q.|
-00000330 98 f0 75 3c 5c f3 16 88 ba e7 76 fe 10 18 41 38 |..u<\.....v...A8|
-00000340 d5 df 7f 8b d3 2e 1c 0a 4c 83 57 fc e5 63 35 68 |........L.W..c5h|
-00000350 6e 23 5b c3 0c 9d f9 ab f8 3c 86 b6 ec 54 ec 52 |n#[......<...T.R|
-00000360 a4 45 cf 7b 31 a7 04 ef 5b 0b b1 11 50 8c 95 25 |.E.{1...[...P..%|
-00000370 9a 17 9b 4d 65 9c 0b d3 bb 0d 98 10 d9 34 52 7a |...Me........4Rz|
-00000380 f8 1e 9e 78 cb 41 27 47 31 cb 25 42 90 e9 3c 02 |...x.A'G1.%B..<.|
-00000390 49 17 01 5f 06 d2 f4 58 35 75 d5 9d 54 65 15 0d |I.._...X5u..Te..|
-000003a0 02 7e 94 fd c8 ac b8 c4 97 1c 9a 1c 9a 23 d5 d3 |.~...........#..|
-000003b0 44 c6 9a dd f9 b4 d1 48 e9 3d a0 5b d4 66 b3 d9 |D......H.=.[.f..|
-000003c0 11 0c d5 6d 0e 06 9c 00 90 30 d7 97 06 dc 0e e2 |...m.....0......|
-000003d0 59 51 7f b5 2e b8 f7 eb be 66 56 fa 9d a4 92 db |YQ.......fV.....|
-000003e0 82 3a d9 fc bd da c5 23 f6 2c 7b 36 2f a8 57 8e |.:.....#.,{6/.W.|
-000003f0 c6 0a 48 50 e3 f4 e7 07 95 48 9b 45 a9 ba cb e0 |..HP.....H.E....|
-00000400 3e ee 10 f9 0e cc 16 03 03 00 46 24 71 bf 67 14 |>.........F$q.g.|
-00000410 d6 5e 2f 97 87 ae b8 b4 fb f1 67 2b e7 0f f4 be |.^/.......g+....|
-00000420 24 0a f8 4a c0 42 4b 40 d3 ea e7 e0 f7 2a 9b 80 |$..J.BK at .....*..|
-00000430 bb 62 c0 2d d5 f8 52 19 49 d4 4c 45 1d c2 28 e7 |.b.-..R.I.LE..(.|
-00000440 8f fd b2 47 0e 22 d1 e1 b1 33 c1 26 6a fd 3f 9f |...G."...3.&j.?.|
-00000450 d8 |.|
+00000000 16 03 03 00 81 39 20 22 4a e1 4e 21 2e 78 35 50 |.....9 "J.N!.x5P|
+00000010 8a d4 c4 c6 a9 20 74 8e 10 4b fd 31 4c ba c4 7f |..... t..K.1L...|
+00000020 14 91 ab 4b 7a b2 7a 86 56 cc 61 ed 12 63 4a d5 |...Kz.z.V.a..cJ.|
+00000030 b5 c9 48 6e ae 10 71 fc 30 f5 e5 36 8b e2 7d 9d |..Hn..q.0..6..}.|
+00000040 93 e2 34 cd 8e a0 72 c4 19 9b 62 eb 9b c4 5e c3 |..4...r...b...^.|
+00000050 df 22 d4 16 4d 88 b1 d5 e5 74 ac 9d 38 40 7d 1f |."..M....t..8@}.|
+00000060 40 bd 86 e5 fc 19 88 bb 67 cf 3f 22 0f 39 1f 8f |@.......g.?".9..|
+00000070 40 5c ee 29 48 00 c1 bf 6a f1 85 51 03 c0 e8 7a |@\.)H...j..Q...z|
+00000080 2e f4 2a f9 b6 fb 16 03 03 02 69 59 b1 5a b9 98 |..*.......iY.Z..|
+00000090 86 77 af 76 a7 4c 69 0d 83 79 3c 9a b9 3c dd 49 |.w.v.Li..y<..<.I|
+000000a0 f2 0f ef d2 38 ac 31 b0 9b 5d 57 ed a7 ca f9 79 |....8.1..]W....y|
+000000b0 7c ef 58 f7 ca 7e 0c 60 1c 53 09 c5 06 dd b8 31 ||.X..~.`.S.....1|
+000000c0 09 88 af 50 9f c2 2a 2c 24 89 9e 57 ae c8 e6 49 |...P..*,$..W...I|
+000000d0 f4 6f 46 e9 dd 38 f1 52 e9 06 50 38 69 b3 e1 69 |.oF..8.R..P8i..i|
+000000e0 f5 33 28 54 39 43 05 b9 04 04 c2 d9 3d 34 da 48 |.3(T9C......=4.H|
+000000f0 99 7e 8a b2 59 d1 d3 20 da 34 c8 ab 91 f7 66 69 |.~..Y.. .4....fi|
+00000100 3a 4f fc 6d ee e6 ef f5 c0 b0 08 bf 59 c0 f8 e5 |:O.m........Y...|
+00000110 dc c6 dc c6 49 a7 d5 3c 22 0f e3 9f 39 0b 2a 09 |....I..<"...9.*.|
+00000120 7a 56 f8 90 33 05 06 09 21 6f 6a 53 0d 89 63 2a |zV..3...!ojS..c*|
+00000130 76 28 19 33 73 e5 a0 2a fa d2 82 bf 4c 43 84 f9 |v(.3s..*....LC..|
+00000140 e1 bb 7f 31 62 04 c5 26 ed 16 40 f5 6a 04 e0 c5 |...1b..&.. at .j...|
+00000150 4e fe bd e3 4c 57 e2 61 41 2f 9a 95 7f 8a e1 34 |N...LW.aA/.....4|
+00000160 64 f4 fc ce 13 e5 0c 68 c1 e5 29 df e7 b1 56 0b |d......h..)...V.|
+00000170 42 6b fc d6 5d 63 0b 3c 0c ca ce 38 11 50 f2 64 |Bk..]c.<...8.P.d|
+00000180 1a 6e 16 da 3e 69 cf 82 ba a0 03 0f 9d 72 ed 10 |.n..>i.......r..|
+00000190 78 b2 54 c0 be 9c 16 fa 15 4b 88 db dd 85 dd 08 |x.T......K......|
+000001a0 bd f4 50 a0 50 01 77 7a cf 20 c1 3e 50 55 5f bd |..P.P.wz. .>PU_.|
+000001b0 4a ba b4 d5 6d 51 38 b2 6d 4f fc b5 af b9 92 ff |J...mQ8.mO......|
+000001c0 c4 44 f1 0e db 4d 71 09 15 b3 c3 37 47 57 03 35 |.D...Mq....7GW.5|
+000001d0 95 de da 33 31 8c 60 bc 8a 97 2d f8 27 9b 4e dc |...31.`...-.'.N.|
+000001e0 2a 6d aa 3e 4d eb 8f 97 b8 fa d4 ef f6 27 d9 da |*m.>M........'..|
+000001f0 a6 fe 38 91 4b 96 ff 75 4b 71 52 9f 37 e4 d9 85 |..8.K..uKqR.7...|
+00000200 a8 d8 ac 21 e9 b2 c0 4f c0 c0 e3 3a 9f ab e0 93 |...!...O...:....|
+00000210 dc 03 18 30 92 55 33 67 58 f3 47 f3 0a 95 bc 33 |...0.U3gX.G....3|
+00000220 70 73 e1 5b 9d 63 cf f7 c7 9b da 9e 5d 2e 7a 66 |ps.[.c......].zf|
+00000230 03 b1 b8 5c fa b9 f4 fb 4e 0b 38 9a 97 f0 c9 e5 |...\....N.8.....|
+00000240 ce 18 33 ea 66 1c 59 cd 41 3e af 71 7c bf 00 a0 |..3.f.Y.A>.q|...|
+00000250 d9 ee 20 d7 80 a9 5d 55 b8 f8 92 7b 7e 4f bc 66 |.. ...]U...{~O.f|
+00000260 92 98 6a c6 15 5b e3 1d 59 14 d9 d0 5a 30 c0 4d |..j..[..Y...Z0.M|
+00000270 37 f5 d9 40 a4 f9 f4 ad b6 cf 55 98 03 1e e7 13 |7.. at ......U.....|
+00000280 5a 23 49 69 36 fa ae 9d c2 cb 90 16 cc 36 f4 41 |Z#Ii6........6.A|
+00000290 3a c7 56 9f 05 23 be 1d 3f 8f 90 41 09 6b 88 9a |:.V..#..?..A.k..|
+000002a0 70 91 76 e1 6d f0 5c 86 de 77 a4 83 c7 d5 3c c4 |p.v.m.\..w....<.|
+000002b0 67 ff b1 a2 e2 f5 61 4f 3b 4d 38 5d c9 c2 8c 97 |g.....aO;M8]....|
+000002c0 e2 a7 c0 72 3b 5e 4c d9 0f 18 a8 b9 77 8d 31 8f |...r;^L.....w.1.|
+000002d0 d9 73 ac 33 a6 7a b5 bd 5e 58 b4 51 22 be d8 d4 |.s.3.z..^X.Q"...|
+000002e0 f5 e1 bc 37 80 d3 cf 3b 58 be 3e ce 33 83 1c 46 |...7...;X.>.3..F|
+000002f0 8b f3 f3 56 16 03 03 00 bc 30 f0 e1 0b eb 80 fe |...V.....0......|
+00000300 5f fb 94 c9 5a 04 08 82 0f 0b b5 9b f7 f6 f6 d3 |_...Z...........|
+00000310 7e 68 e7 e5 2e cf a0 56 e6 b7 70 0a 63 5e 53 42 |~h.....V..p.c^SB|
+00000320 7f 27 ec 82 a0 5d e3 e8 77 27 40 3c 6d 47 ce dd |.'...]..w'@<mG..|
+00000330 89 6e ac 0c 48 ab 25 d1 8e 4e 4e b8 99 69 a5 94 |.n..H.%..NN..i..|
+00000340 8d 19 ab f9 82 6b 28 e3 b8 5f f7 75 a8 dd 1f b5 |.....k(.._.u....|
+00000350 0a ff d1 72 4f 82 9b 9e 8e b3 3f f9 73 d6 cd ea |...rO.....?.s...|
+00000360 c8 5b 51 4e 7f 16 a5 4b 81 5e 9a d7 a3 f2 64 35 |.[QN...K.^....d5|
+00000370 fd 2e dc 11 07 10 04 63 80 77 eb 0d d2 ba 9f 7c |.......c.w.....||
+00000380 ad 66 eb 0a 2e f7 f2 3d d3 a4 04 7b 83 8f 84 94 |.f.....=...{....|
+00000390 93 8e 8c 74 2a b0 3a 3e e1 33 92 f9 59 e5 0a 56 |...t*.:>.3..Y..V|
+000003a0 95 3a 8b dc 1f 24 6c 08 07 c0 f1 20 6d 96 43 71 |.:...$l.... m.Cq|
+000003b0 bf c6 92 81 e3 16 03 03 00 3a 91 c1 13 a0 26 c9 |.........:....&.|
+000003c0 12 6a 09 23 5b 8b e8 da 10 cc 4d 00 ed 9e a6 09 |.j.#[.....M.....|
+000003d0 d8 d4 c0 b7 f0 cd 5f 7a 6e 4d 31 21 f6 6a 22 e7 |......_znM1!.j".|
+000003e0 6e 25 11 94 4a f2 b1 f1 b2 c9 30 4b e4 cd f3 f5 |n%..J.....0K....|
+000003f0 ce 86 e7 5d 16 03 03 00 14 20 c5 91 f0 6e 21 b8 |...]..... ...n!.|
+00000400 e8 a1 bb cf 62 ed 4b 5a fa 19 40 ea 54 |....b.KZ.. at .T|
>>> Flow 13 (client to server)
-00000000 16 03 03 02 89 00 00 00 00 00 00 00 02 32 20 c7 |.............2 .|
-00000010 66 2d 3f e5 9b f9 e0 1c 7c 1f 3e 21 d9 51 af 9a |f-?.....|.>!.Q..|
-00000020 60 65 99 c7 3e 0b 48 f2 a3 8f eb ea 75 da af 60 |`e..>.H.....u..`|
-00000030 2e 5b ac 7f 9f d1 1f 69 86 18 49 3b 18 a2 e5 c5 |.[.....i..I;....|
-00000040 d0 c7 fe 3e c6 15 3d 5d 04 4d aa 7e 28 e3 20 d3 |...>..=].M.~(. .|
-00000050 55 c2 ed 4f 61 5f cc f9 39 5f 7d 3a 0f f2 81 5d |U..Oa_..9_}:...]|
-00000060 fd 4e 86 92 12 cd 2b b7 e6 46 49 b7 b8 5f 8f e5 |.N....+..FI.._..|
-00000070 b7 5e 64 2f 13 33 65 1c c8 c4 38 bd 70 94 23 e9 |.^d/.3e...8.p.#.|
-00000080 b6 57 81 c8 23 d1 57 85 91 c5 bc 5b 33 55 eb f5 |.W..#.W....[3U..|
-00000090 2d b3 76 53 44 e2 e8 66 fe 42 de f8 6f 03 37 d4 |-.vSD..f.B..o.7.|
-000000a0 a0 a4 75 7a 03 7f 00 92 eb 45 2f b8 5d 01 d3 4b |..uz.....E/.]..K|
-000000b0 e7 ca 2f 5b 3b 20 67 dc 32 2a 4c 06 1b 03 97 c1 |../[; g.2*L.....|
-000000c0 38 40 35 79 31 25 b0 fe d8 f3 b7 ee 6c ad 62 3e |8 at 5y1%......l.b>|
-000000d0 60 d6 96 6a 10 2b 14 8a 9e 72 f4 c9 63 6a 63 14 |`..j.+...r..cjc.|
-000000e0 d1 b0 e4 1f e9 3d 85 9d ed 11 3f 85 eb fa ca 46 |.....=....?....F|
-000000f0 17 f8 45 d5 65 28 79 8d 63 8e d7 22 40 9f c7 25 |..E.e(y.c.."@..%|
-00000100 ae e0 72 9f 60 70 95 59 99 25 41 1a e6 e9 45 cb |..r.`p.Y.%A...E.|
-00000110 3d 5a 2e 2d 4d c2 3c f2 3a 01 61 1f 96 d7 78 1a |=Z.-M.<.:.a...x.|
-00000120 cd 14 bd 87 75 23 10 7f 67 e4 8e fa 0a 9d 5d e9 |....u#..g.....].|
-00000130 12 f8 c7 35 c1 37 4c a4 91 a1 a5 de 79 9a a7 9c |...5.7L.....y...|
-00000140 ce d2 c9 72 a8 fa a3 27 24 8d 14 4e d7 11 f3 e9 |...r...'$..N....|
-00000150 07 4d 6d 47 92 4d e2 75 9a 71 d0 1e dd 09 61 0e |.MmG.M.u.q....a.|
-00000160 16 36 84 3a b1 dd 9b f8 09 dd 73 78 ed f7 29 4e |.6.:......sx..)N|
-00000170 a6 29 b0 31 54 72 ac 4b 7a 49 13 ba 9b ef b6 8b |.).1Tr.KzI......|
-00000180 48 dd a1 a7 9d 25 0e b7 37 42 5f 70 27 a7 59 40 |H....%..7B_p'.Y@|
-00000190 fe 72 1a 23 3e 71 b7 56 ef ff 02 c0 c9 07 99 20 |.r.#>q.V....... |
-000001a0 19 d2 9e 65 a5 5e f1 15 d3 ec 6e bb b1 c4 bf c0 |...e.^....n.....|
-000001b0 f8 71 19 bc 77 30 93 72 33 eb 1b c0 62 07 5e ca |.q..w0.r3...b.^.|
-000001c0 4a bf 89 5d 5d 44 23 fb 58 8e 71 b4 58 41 b9 97 |J..]]D#.X.q.XA..|
-000001d0 8b da b6 a0 b6 40 54 46 01 b9 47 79 21 bc 7c f3 |..... at TF..Gy!.|.|
-000001e0 4c 46 a3 92 ce d6 ec ac 3b 5d 6f 19 65 d1 b0 cd |LF......;]o.e...|
-000001f0 19 cd 2e 9d 6e 7d d3 57 44 c2 dd c6 56 dd e6 2b |....n}.WD...V..+|
-00000200 06 c6 f1 46 f1 ba ce e6 d9 c8 1e 03 5d b5 15 37 |...F........]..7|
-00000210 9d 8a d2 01 e7 28 33 30 a2 2b a3 42 d1 05 2f e9 |.....(30.+.B../.|
-00000220 7f 50 bf c8 7f 7b f8 c7 7e 12 3f 97 5e d5 1c 34 |.P...{..~.?.^..4|
-00000230 eb bf 2e c2 f0 6b 36 4e 09 c9 73 0e bb 3a cd f8 |.....k6N..s..:..|
-00000240 5f 2a 13 4d f2 92 b3 ae 4f dd 0e 82 a0 58 a9 be |_*.M....O....X..|
-00000250 2f c1 20 5c 64 48 11 e3 66 18 22 4d ea aa 76 21 |/. \dH..f."M..v!|
-00000260 07 ac 5a f2 14 38 a7 d8 9a 58 f8 92 62 77 3c 59 |..Z..8...X..bw<Y|
-00000270 1a 31 4e 3f 56 55 2b 9f 87 96 9c 7e c5 f0 10 fa |.1N?VU+....~....|
-00000280 90 a1 0b 9e e4 66 74 99 80 da 58 85 3d bd 16 03 |.....ft...X.=...|
-00000290 03 00 5e 00 00 00 00 00 00 00 03 42 d9 1d 19 27 |..^........B...'|
-000002a0 98 c0 29 9e bc 35 99 e9 e9 de f5 7c b7 2f ce a1 |..)..5.....|./..|
-000002b0 48 fe a9 79 26 c3 f1 74 63 73 3b 8d b7 4c 47 11 |H..y&..tcs;..LG.|
-000002c0 7c ea 6d 09 4c 1c 10 1d c9 b4 63 d4 5e c4 f1 34 ||.m.L.....c.^..4|
-000002d0 94 63 1c 04 a1 5f d0 65 7c b6 dd 2b a3 1c 1b 5f |.c..._.e|..+..._|
-000002e0 5c d6 dc 7f e7 df c4 75 ad df cc ae 71 47 64 cc |\......u....qGd.|
-000002f0 96 16 03 03 00 a0 00 00 00 00 00 00 00 04 61 37 |..............a7|
-00000300 a3 98 54 d1 7c 5d 14 b9 04 72 6e 02 ab 1a 15 2c |..T.|]...rn....,|
-00000310 93 07 15 ab 56 b1 ac d5 75 75 2e 25 ae 5e 3f fa |....V...uu.%.^?.|
-00000320 d0 20 ff 9d e0 ef fd 25 ed 4d 60 56 c7 33 07 d0 |. .....%.M`V.3..|
-00000330 57 09 e4 12 bd aa f0 d2 cc de 0d 45 23 ab b6 67 |W..........E#..g|
-00000340 ea d3 bc e1 4d 3a 75 9f 2d bb 53 b4 70 67 ce 63 |....M:u.-.S.pg.c|
-00000350 83 29 fa 27 2b db ea a3 19 be 79 77 cd 75 fb bf |.).'+.....yw.u..|
-00000360 c1 27 86 a6 a9 27 06 49 e1 77 13 0d e4 78 0c 07 |.'...'.I.w...x..|
-00000370 d4 1c af 76 f4 7b 05 04 5f 0f ec 66 f9 03 3e 81 |...v.{.._..f..>.|
-00000380 41 be 24 5f 43 2a 99 56 06 a9 d7 be ca 62 46 a2 |A.$_C*.V.....bF.|
-00000390 ba e1 a6 8b 1b 0a 14 03 03 00 19 00 00 00 00 00 |................|
-000003a0 00 00 05 f9 8f d4 80 bf ed b3 38 3a 12 d9 91 b6 |..........8:....|
-000003b0 cf 87 1a 1b 16 03 03 00 28 00 00 00 00 00 00 00 |........(.......|
-000003c0 00 fb 80 da 9a 59 82 9d d2 35 57 57 dd 76 a1 b1 |.....Y...5WW.v..|
-000003d0 4a dc a5 cb f6 81 3f e3 4d cc 0e 7f 3a 96 85 f3 |J.....?.M...:...|
-000003e0 ea |.|
+00000000 16 03 03 02 69 1a b5 80 9c c6 42 be a6 d9 d1 c8 |....i.....B.....|
+00000010 0b 2c f7 f8 2a 1a 02 f6 db 48 8b 5c 45 fc 28 41 |.,..*....H.\E.(A|
+00000020 a4 db 35 fb a7 a9 72 07 19 86 9e e9 dc 53 48 fb |..5...r......SH.|
+00000030 97 94 f3 a0 0d 8d 46 69 cf eb d9 ea de 21 a3 f4 |......Fi.....!..|
+00000040 b9 94 4f 8f 09 c3 de 66 fa 20 83 34 fc 50 ae c6 |..O....f. .4.P..|
+00000050 13 f6 7c c5 80 45 17 51 af a9 da bd 24 dd f6 15 |..|..E.Q....$...|
+00000060 8e c4 b4 e6 10 54 85 23 9d fe 72 b1 4c 2f ab ec |.....T.#..r.L/..|
+00000070 78 9a 06 60 03 96 f7 d0 af dd 94 26 c9 67 1d e5 |x..`.......&.g..|
+00000080 9f 87 22 c4 11 82 f1 4c f5 68 a7 fd d8 f3 dc ac |.."....L.h......|
+00000090 35 90 6b c2 97 1c 78 54 d9 b2 3c d8 9d 13 66 42 |5.k...xT..<...fB|
+000000a0 6e 3b 1b 8f 32 4e 8f b5 a0 60 6e e4 35 fd d5 b4 |n;..2N...`n.5...|
+000000b0 f8 fb a6 a9 c7 b7 31 39 8e 90 0c 42 bc 1a 4f 67 |......19...B..Og|
+000000c0 fa b3 10 a8 45 01 88 8a dd 41 43 c6 6c 41 9d 28 |....E....AC.lA.(|
+000000d0 bd 4c 43 85 4c 3b 7c 03 c4 55 70 f1 49 a0 d6 52 |.LC.L;|..Up.I..R|
+000000e0 5c 49 3e 2b d7 e8 a9 75 5e 92 bf f3 4c 1c c3 7e |\I>+...u^...L..~|
+000000f0 69 ca 52 25 07 bb 54 e0 58 2d 28 ba 50 30 81 e8 |i.R%..T.X-(.P0..|
+00000100 93 0d 9d 78 3d c0 f1 c3 34 72 29 f1 da 60 de 84 |...x=...4r)..`..|
+00000110 aa fc d3 0f 2b 1e 1a 9c 7c af 6f 6a 4c cc 88 36 |....+...|.ojL..6|
+00000120 03 03 34 79 f9 89 6d 41 bb 19 61 6a 60 75 d7 0f |..4y..mA..aj`u..|
+00000130 dc 22 7a e4 36 91 32 2b 99 24 36 19 4b 4c c4 ae |."z.6.2+.$6.KL..|
+00000140 4f 98 6d f0 97 ce bc b4 ee 97 30 97 0b 54 8c 14 |O.m.......0..T..|
+00000150 8f d5 9d 44 ae 0a a6 07 9f 39 f6 66 80 cb fa 27 |...D.....9.f...'|
+00000160 bb 2f 26 bb c3 1a a4 9b a0 d3 e8 75 13 49 da 0a |./&........u.I..|
+00000170 8f cc e8 15 77 f8 05 c2 17 a0 ff e7 2a 59 bc c8 |....w.......*Y..|
+00000180 67 b5 7e b8 78 1e 32 81 22 3e 57 28 ee 51 96 b7 |g.~.x.2.">W(.Q..|
+00000190 0e dc 3f d1 00 16 a5 eb 01 cb c3 e3 5b 01 ad a9 |..?.........[...|
+000001a0 d5 1b ac 9b e2 0d 9a 6f 7a 2f f1 7d 05 57 6d 2d |.......oz/.}.Wm-|
+000001b0 9d 35 68 88 e7 c5 e0 fb 9d 87 a7 ef 71 d8 47 b8 |.5h.........q.G.|
+000001c0 19 8e 87 d8 b1 36 0f 52 ab 98 8b 97 43 53 86 be |.....6.R....CS..|
+000001d0 9d 86 2a cd 7c b0 46 c4 48 89 5b 6c 1e 93 9e a2 |..*.|.F.H.[l....|
+000001e0 15 af 60 8f 84 75 99 97 53 11 23 f9 0d ba 78 12 |..`..u..S.#...x.|
+000001f0 9b a9 04 91 d0 3a b3 4d 7b 67 a0 fa 78 5c 19 d6 |.....:.M{g..x\..|
+00000200 88 d2 21 f6 8d e4 91 d1 76 95 67 9d 4e 3b a1 d2 |..!.....v.g.N;..|
+00000210 61 c3 d2 a6 53 fd 82 93 20 7e f6 07 a0 49 3a ea |a...S... ~...I:.|
+00000220 bc 73 03 0b f2 df 51 ac 35 d8 e4 35 9d 13 56 b5 |.s....Q.5..5..V.|
+00000230 be fc 7c 36 8b 37 a0 71 57 62 bd 89 38 18 90 1e |..|6.7.qWb..8...|
+00000240 7a 1f b3 8f 73 55 32 94 5a 3a 31 91 b3 95 bd 61 |z...sU2.Z:1....a|
+00000250 ea 93 9d f0 38 33 fb 5b 28 3d a7 29 a4 91 de 85 |....83.[(=.)....|
+00000260 9c 16 63 10 81 c6 e0 11 92 3d 53 db 69 95 16 03 |..c......=S.i...|
+00000270 03 00 35 f7 3a b7 d1 20 aa f7 ed b1 c7 46 52 cb |..5.:.. .....FR.|
+00000280 6e dd e2 f4 ae 83 20 cd 6c 59 b5 26 f9 81 7e 6c |n..... .lY.&..~l|
+00000290 ed e9 0b 2a f1 3a dc f8 d6 ed e5 6d 89 14 3d 79 |...*.:.....m..=y|
+000002a0 e7 c8 af 89 30 eb 98 3d 16 03 03 00 98 a0 59 2f |....0..=......Y/|
+000002b0 cd d9 f6 63 e3 53 47 77 e5 c4 fc 2e 12 d7 24 8a |...c.SGw......$.|
+000002c0 4c c7 d8 c9 77 4f bc 3c af 93 6f 57 3d 6f 5d 1c |L...wO.<..oW=o].|
+000002d0 6a 5a 2c 42 1c e0 92 d5 5e 34 c8 a5 9e 11 21 16 |jZ,B....^4....!.|
+000002e0 01 1a 08 af 4e f6 a1 e3 19 a6 81 41 3d 7a f3 d1 |....N......A=z..|
+000002f0 e0 9e 55 90 42 4b d9 5c 46 b7 eb c8 fb 83 1c 97 |..U.BK.\F.......|
+00000300 9e d9 74 bb 7f 2f 4d 61 89 46 db 32 da 1a 76 95 |..t../Ma.F.2..v.|
+00000310 88 f8 ca 62 14 88 dc 97 b8 58 82 74 16 78 be c5 |...b.....X.t.x..|
+00000320 f9 78 a4 88 c1 d4 6b 36 6e 54 60 a5 21 30 47 07 |.x....k6nT`.!0G.|
+00000330 e8 2d 22 ce a5 17 fb 43 10 9d 74 c9 64 a3 db ac |.-"....C..t.d...|
+00000340 d9 24 7a a7 5d 14 03 03 00 11 68 20 87 e9 9b 91 |.$z.].....h ....|
+00000350 81 67 2b 31 c4 47 e8 9b 2e 7c c4 16 03 03 00 20 |.g+1.G...|..... |
+00000360 ef 6f 3d 0f 23 fa 77 8c a9 46 d9 0d b0 d9 f8 16 |.o=.#.w..F......|
+00000370 62 e2 07 21 ec b6 a7 78 ce a6 ea b3 68 c1 c7 af |b..!...x....h...|
>>> Flow 14 (server to client)
-00000000 14 03 03 00 19 24 71 bf 67 14 d6 5e 30 cc 1c 3f |.....$q.g..^0..?|
-00000010 3c 20 07 b3 c3 79 d0 6e fd 59 e6 0d 47 fd 16 03 |< ...y.n.Y..G...|
-00000020 03 00 28 54 db a5 f7 3d b3 18 49 39 e5 59 93 bb |..(T...=..I9.Y..|
-00000030 64 93 1c ed 46 d6 f8 89 94 45 ba 4a 9e 73 2e cb |d...F....E.J.s..|
-00000040 03 18 e4 26 6d 33 e3 34 73 d6 fc 17 03 03 00 21 |...&m3.4s......!|
-00000050 54 db a5 f7 3d b3 18 4a aa 45 38 3b 50 02 44 37 |T...=..J.E8;P.D7|
-00000060 6a d1 3e f9 d3 3b 33 33 d5 84 2d 52 33 7d 68 84 |j.>..;33..-R3}h.|
-00000070 ef |.|
+00000000 14 03 03 00 11 bb 45 96 9e 08 cb e4 24 c2 e3 71 |......E.....$..q|
+00000010 40 d1 ef a1 5e 2f 16 03 03 00 20 1b 3f 69 fb ae |@...^/.... .?i..|
+00000020 cd 98 15 59 16 14 cf a5 16 af 36 6d 6d 3a 49 06 |...Y......6mm:I.|
+00000030 a6 f9 cf 53 ea 9a b7 3b 48 d2 e3 17 03 03 00 19 |...S...;H.......|
+00000040 72 2c 82 a0 8c 6c 8b c3 78 e4 41 1b ff ba 92 6d |r,...l..x.A....m|
+00000050 3c 4d 9c c3 95 e3 27 b9 82 |<M....'..|
>>> Flow 15 (client to server)
-00000000 15 03 03 00 1a 00 00 00 00 00 00 00 01 55 5f 94 |.............U_.|
-00000010 25 d0 89 86 cb 8f 33 6f b7 b6 35 ec 0f 6a 87 |%.....3o..5..j.|
+00000000 15 03 03 00 12 3d f9 72 53 84 b5 a4 ec 27 39 cc |.....=.rS....'9.|
+00000010 72 29 c0 e6 37 7b 0f |r)..7{.|
diff --git a/src/crypto/tls/testdata/Client-TLSv12-RenegotiateTwiceRejected b/src/crypto/tls/testdata/Client-TLSv12-RenegotiateTwiceRejected
index fe2fa88..737ccc6 100644
--- a/src/crypto/tls/testdata/Client-TLSv12-RenegotiateTwiceRejected
+++ b/src/crypto/tls/testdata/Client-TLSv12-RenegotiateTwiceRejected
@@ -1,255 +1,234 @@
>>> Flow 1 (client to server)
-00000000 16 03 01 00 85 01 00 00 81 03 03 00 00 00 00 00 |................|
+00000000 16 03 01 00 91 01 00 00 8d 03 03 00 00 00 00 00 |................|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
-00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 22 c0 2f |............."./|
-00000030 c0 2b c0 30 c0 2c c0 11 c0 07 c0 13 c0 09 c0 14 |.+.0.,..........|
-00000040 c0 0a 00 9c 00 9d 00 05 00 2f 00 35 c0 12 00 0a |........./.5....|
-00000050 01 00 00 36 00 05 00 05 01 00 00 00 00 00 0a 00 |...6............|
-00000060 08 00 06 00 17 00 18 00 19 00 0b 00 02 01 00 00 |................|
-00000070 0d 00 0e 00 0c 04 01 04 03 05 01 05 03 02 01 02 |................|
-00000080 03 ff 01 00 01 00 00 12 00 00 |..........|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2c cc a8 |.............,..|
+00000030 cc a9 c0 2f c0 2b c0 30 c0 2c c0 27 c0 13 c0 23 |.../.+.0.,.'...#|
+00000040 c0 09 c0 14 c0 0a 00 9c 00 9d 00 3c 00 2f 00 35 |...........<./.5|
+00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 38 00 05 |.............8..|
+00000060 00 05 01 00 00 00 00 00 0a 00 0a 00 08 00 1d 00 |................|
+00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 0e 00 |................|
+00000080 0c 04 01 04 03 05 01 05 03 02 01 02 03 ff 01 00 |................|
+00000090 01 00 00 12 00 00 |......|
>>> Flow 2 (server to client)
-00000000 16 03 03 00 59 02 00 00 55 03 03 51 0e b9 8f 73 |....Y...U..Q...s|
-00000010 ec 20 17 90 80 3a 43 7a bc 19 19 f5 75 c3 76 a6 |. ...:Cz....u.v.|
-00000020 53 53 4b 77 ce dd ca 4b 1b 1e ed 20 8d e5 a7 6f |SSKw...K... ...o|
-00000030 53 e9 a4 06 4b 01 a6 08 a1 90 e5 da c9 e3 74 b0 |S...K.........t.|
-00000040 87 1f 17 1a 68 d3 f7 ae 39 b8 3e 80 c0 2f 00 00 |....h...9.>../..|
+00000000 16 03 03 00 59 02 00 00 55 03 03 75 f6 1b 17 2f |....Y...U..u.../|
+00000010 e0 d4 19 06 0d 93 90 51 46 d9 c3 a0 cd 45 6c 85 |.......QF....El.|
+00000020 94 87 01 21 3e 92 62 1d e7 d1 39 20 07 26 a1 5b |...!>.b...9 .&.[|
+00000030 d2 4a 61 40 ba 58 c0 23 0c 3f c3 08 5d 28 04 94 |.Ja at .X.#.?..](..|
+00000040 a9 34 37 28 64 75 6f 9c ae fa 1f 24 cc a8 00 00 |.47(duo....$....|
00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................|
-00000060 03 02 71 0b 00 02 6d 00 02 6a 00 02 67 30 82 02 |..q...m..j..g0..|
-00000070 63 30 82 01 cc a0 03 02 01 02 02 09 00 a2 73 00 |c0............s.|
-00000080 0c 81 00 cb f3 30 0d 06 09 2a 86 48 86 f7 0d 01 |.....0...*.H....|
-00000090 01 0b 05 00 30 2b 31 17 30 15 06 03 55 04 0a 13 |....0+1.0...U...|
-000000a0 0e 47 6f 6f 67 6c 65 20 54 45 53 54 49 4e 47 31 |.Google TESTING1|
-000000b0 10 30 0e 06 03 55 04 03 13 07 47 6f 20 52 6f 6f |.0...U....Go Roo|
-000000c0 74 30 1e 17 0d 31 35 30 31 30 31 30 30 30 30 30 |t0...15010100000|
-000000d0 30 5a 17 0d 32 35 30 31 30 31 30 30 30 30 30 30 |0Z..250101000000|
-000000e0 5a 30 26 31 17 30 15 06 03 55 04 0a 13 0e 47 6f |Z0&1.0...U....Go|
-000000f0 6f 67 6c 65 20 54 45 53 54 49 4e 47 31 0b 30 09 |ogle TESTING1.0.|
-00000100 06 03 55 04 03 13 02 47 6f 30 81 9f 30 0d 06 09 |..U....Go0..0...|
-00000110 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 30 |*.H............0|
-00000120 81 89 02 81 81 00 af 87 88 f6 20 1b 95 65 6c 14 |.......... ..el.|
-00000130 ab 44 05 af 3b 45 14 e3 b7 6d fd 00 63 4d 95 7f |.D..;E...m..cM..|
-00000140 fe 6a 62 35 86 c0 4a f9 18 7c f6 aa 25 5e 7a 64 |.jb5..J..|..%^zd|
-00000150 31 66 00 ba f4 8e 92 af c7 6b d8 76 d4 f3 5f 41 |1f.......k.v.._A|
-00000160 cb 6e 56 15 97 1b 97 c1 3c 12 39 21 66 3d 2b 16 |.nV.....<.9!f=+.|
-00000170 d1 bc db 1c c0 a7 da b7 ca ad ba da cb d5 21 50 |..............!P|
-00000180 ec de 8d ab d1 6b 81 4b 89 02 f3 c4 be c1 6c 89 |.....k.K......l.|
-00000190 b1 44 84 bd 21 d1 04 7d 9d 16 4d f9 82 15 f6 ef |.D..!..}..M.....|
-000001a0 fa d6 09 47 f2 fb 02 03 01 00 01 a3 81 93 30 81 |...G..........0.|
-000001b0 90 30 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 05 |.0...U..........|
-000001c0 a0 30 1d 06 03 55 1d 25 04 16 30 14 06 08 2b 06 |.0...U.%..0...+.|
-000001d0 01 05 05 07 03 01 06 08 2b 06 01 05 05 07 03 02 |........+.......|
-000001e0 30 0c 06 03 55 1d 13 01 01 ff 04 02 30 00 30 19 |0...U.......0.0.|
-000001f0 06 03 55 1d 0e 04 12 04 10 12 50 8d 89 6f 1b d1 |..U.......P..o..|
-00000200 dc 54 4d 6e cb 69 5e 06 f4 30 1b 06 03 55 1d 23 |.TMn.i^..0...U.#|
-00000210 04 14 30 12 80 10 bf 3d b6 a9 66 f2 b8 40 cf ea |..0....=..f.. at ..|
-00000220 b4 03 78 48 1a 41 30 19 06 03 55 1d 11 04 12 30 |..xH.A0...U....0|
-00000230 10 82 0e 65 78 61 6d 70 6c 65 2e 67 6f 6c 61 6e |...example.golan|
-00000240 67 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 |g0...*.H........|
-00000250 03 81 81 00 92 7c af 91 55 12 18 96 59 31 a6 48 |.....|..U...Y1.H|
-00000260 40 d5 2d d5 ee bb 02 a0 f5 c2 1e 7c 9b b3 30 7d |@.-........|..0}|
-00000270 3c dc 76 da 4f 3d c0 fa ae 2d 33 24 6b 03 7b 1b |<.v.O=...-3$k.{.|
-00000280 67 59 11 21 b5 11 bc 77 b9 d9 e0 6e a8 2d 2e 35 |gY.!...w...n.-.5|
-00000290 fa 64 5f 22 3e 63 10 6b be ff 14 86 6d 0d f0 15 |.d_">c.k....m...|
-000002a0 31 a8 14 38 1e 3b 84 87 2c cb 98 ed 51 76 b9 b1 |1..8.;..,...Qv..|
-000002b0 4f dd db 9b 84 04 86 40 fa 51 dd ba b4 8d eb e3 |O...... at .Q......|
-000002c0 46 de 46 b9 4f 86 c7 f9 a4 c2 41 34 ac cc f6 ea |F.F.O.....A4....|
-000002d0 b0 ab 39 18 16 03 03 00 cd 0c 00 00 c9 03 00 17 |..9.............|
-000002e0 41 04 5e 2e 43 b7 c2 0f e8 4a 33 aa b8 d6 04 7f |A.^.C....J3.....|
-000002f0 2b be a2 e3 6f fa 05 1a d1 64 a7 d1 ec 45 f9 16 |+...o....d...E..|
-00000300 b7 75 ad f2 52 3e a3 60 67 f8 fb 87 a0 c0 d4 2f |.u..R>.`g....../|
-00000310 f4 66 c9 dd 38 40 79 5b 16 75 0b 16 6a d8 e5 ad |.f..8 at y[.u..j...|
-00000320 63 f3 04 01 00 80 5e 89 b3 6b f4 a1 35 b3 27 be |c.....^..k..5.'.|
-00000330 6a d4 39 42 7c ac e2 d4 9f a0 a0 a3 95 22 b5 09 |j.9B|........"..|
-00000340 70 4a 0c 6f cf 7f 69 f9 7d 27 c4 0d e7 b8 9c 82 |pJ.o..i.}'......|
-00000350 c9 0d 1d bb 5c 23 20 eb ca 09 ca 02 a0 56 27 10 |....\# ......V'.|
-00000360 c5 d6 13 7d cd 05 64 cc 53 20 5d df ac 00 90 7f |...}..d.S ].....|
-00000370 d7 cd f2 a1 07 9c 06 c2 e6 d1 94 60 d3 c6 97 a6 |...........`....|
-00000380 3c e5 89 67 e7 cc b7 c1 ba 75 dc 17 2b 47 ce 23 |<..g.....u..+G.#|
-00000390 a3 37 3b 3f 32 39 ae 4a 64 17 d2 64 d1 75 23 8a |.7;?29.Jd..d.u#.|
-000003a0 e3 b4 fa 75 17 72 16 03 03 00 04 0e 00 00 00 |...u.r.........|
+00000060 03 02 59 0b 00 02 55 00 02 52 00 02 4f 30 82 02 |..Y...U..R..O0..|
+00000070 4b 30 82 01 b4 a0 03 02 01 02 02 09 00 e8 f0 9d |K0..............|
+00000080 3f e2 5b ea a6 30 0d 06 09 2a 86 48 86 f7 0d 01 |?.[..0...*.H....|
+00000090 01 0b 05 00 30 1f 31 0b 30 09 06 03 55 04 0a 13 |....0.1.0...U...|
+000000a0 02 47 6f 31 10 30 0e 06 03 55 04 03 13 07 47 6f |.Go1.0...U....Go|
+000000b0 20 52 6f 6f 74 30 1e 17 0d 31 36 30 31 30 31 30 | Root0...1601010|
+000000c0 30 30 30 30 30 5a 17 0d 32 35 30 31 30 31 30 30 |00000Z..25010100|
+000000d0 30 30 30 30 5a 30 1a 31 0b 30 09 06 03 55 04 0a |0000Z0.1.0...U..|
+000000e0 13 02 47 6f 31 0b 30 09 06 03 55 04 03 13 02 47 |..Go1.0...U....G|
+000000f0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....|
+00000100 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 db 46 |.......0.......F|
+00000110 7d 93 2e 12 27 06 48 bc 06 28 21 ab 7e c4 b6 a2 |}...'.H..(!.~...|
+00000120 5d fe 1e 52 45 88 7a 36 47 a5 08 0d 92 42 5b c2 |]..RE.z6G....B[.|
+00000130 81 c0 be 97 79 98 40 fb 4f 6d 14 fd 2b 13 8b c2 |....y. at .Om..+...|
+00000140 a5 2e 67 d8 d4 09 9e d6 22 38 b7 4a 0b 74 73 2b |..g....."8.J.ts+|
+00000150 c2 34 f1 d1 93 e5 96 d9 74 7b f3 58 9f 6c 61 3c |.4......t{.X.la<|
+00000160 c0 b0 41 d4 d9 2b 2b 24 23 77 5b 1c 3b bd 75 5d |..A..++$#w[.;.u]|
+00000170 ce 20 54 cf a1 63 87 1d 1e 24 c4 f3 1d 1a 50 8b |. T..c...$....P.|
+00000180 aa b6 14 43 ed 97 a7 75 62 f4 14 c8 52 d7 02 03 |...C...ub...R...|
+00000190 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..|
+000001a0 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%|
+000001b0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........|
+000001c0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...|
+000001d0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....|
+000001e0 10 9f 91 16 1f 43 43 3e 49 a6 de 6d b6 80 d7 9f |.....CC>I..m....|
+000001f0 60 30 1b 06 03 55 1d 23 04 14 30 12 80 10 48 13 |`0...U.#..0...H.|
+00000200 49 4d 13 7e 16 31 bb a3 01 d5 ac ab 6e 7b 30 19 |IM.~.1......n{0.|
+00000210 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp|
+00000220 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H|
+00000230 86 f7 0d 01 01 0b 05 00 03 81 81 00 9d 30 cc 40 |.............0.@|
+00000240 2b 5b 50 a0 61 cb ba e5 53 58 e1 ed 83 28 a9 58 |+[P.a...SX...(.X|
+00000250 1a a9 38 a4 95 a1 ac 31 5a 1a 84 66 3d 43 d3 2d |..8....1Z..f=C.-|
+00000260 d9 0b f2 97 df d3 20 64 38 92 24 3a 00 bc cf 9c |...... d8.$:....|
+00000270 7d b7 40 20 01 5f aa d3 16 61 09 a2 76 fd 13 c3 |}.@ ._...a..v...|
+00000280 cc e1 0c 5c ee b1 87 82 f1 6c 04 ed 73 bb b3 43 |...\.....l..s..C|
+00000290 77 8d 0c 1c f1 0f a1 d8 40 83 61 c9 4c 72 2b 9d |w....... at .a.Lr+.|
+000002a0 ae db 46 06 06 4d f4 c1 b3 3e c0 d1 bd 42 d4 db |..F..M...>...B..|
+000002b0 fe 3d 13 60 84 5c 21 d3 3b e9 fa e7 16 03 03 00 |.=.`.\!.;.......|
+000002c0 ac 0c 00 00 a8 03 00 1d 20 84 74 e5 bc 24 39 39 |........ .t..$99|
+000002d0 e0 6e 35 fb 34 87 76 0d 78 89 35 5c 85 e7 92 da |.n5.4.v.x.5\....|
+000002e0 e1 39 f4 b2 e7 ec d5 cd 58 04 01 00 80 cf 3a 57 |.9......X.....:W|
+000002f0 6a 8b b7 72 d8 a2 6b 47 87 77 8b 7a bf 63 6c e8 |j..r..kG.w.z.cl.|
+00000300 d4 20 6a 6a 9c 62 b6 ef 4b 9f a7 89 8c a6 fd 02 |. jj.b..K.......|
+00000310 92 2f 8d 07 44 09 f6 d9 03 99 39 49 1d 8d 1b 7f |./..D.....9I....|
+00000320 eb eb 4b a6 fb 9f 83 3b 3d d3 61 3e e4 d3 22 24 |..K....;=.a>.."$|
+00000330 c1 44 76 e8 75 c7 aa 31 96 e3 50 bb 76 3e 87 02 |.Dv.u..1..P.v>..|
+00000340 b9 1d 82 dd 55 ee 05 b9 b5 1e 65 90 2c 50 c9 87 |....U.....e.,P..|
+00000350 49 dd 35 c8 84 67 6e 52 3a 3b ec 3c 63 f4 0f 95 |I.5..gnR:;.<c...|
+00000360 87 05 8e ec bd d7 97 9f 9a 14 78 d7 97 16 03 03 |..........x.....|
+00000370 00 04 0e 00 00 00 |......|
>>> Flow 3 (client to server)
-00000000 16 03 03 00 46 10 00 00 42 41 04 1e 18 37 ef 0d |....F...BA...7..|
-00000010 19 51 88 35 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd |.Q.5uq..T[....g.|
-00000020 a7 24 20 3e b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e |.$ >.V...(^.+-O.|
-00000030 f1 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 |...lK[.V.2B.X..I|
-00000040 a6 b5 68 1a 41 03 56 6b dc 5a 89 14 03 03 00 01 |..h.A.Vk.Z......|
-00000050 01 16 03 03 00 28 00 00 00 00 00 00 00 00 4f ef |.....(........O.|
-00000060 08 7c a7 de 53 70 7e 78 fb 08 79 97 1f bd 33 92 |.|..Sp~x..y...3.|
-00000070 c5 46 4d 64 32 bb 94 f0 07 ad 7d 00 86 9e |.FMd2.....}...|
+00000000 16 03 03 00 25 10 00 00 21 20 2f e5 7d a3 47 cd |....%...! /.}.G.|
+00000010 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af c4 |bC.(.._.).0.....|
+00000020 cf c2 ed 90 99 5f 58 cb 3b 74 14 03 03 00 01 01 |....._X.;t......|
+00000030 16 03 03 00 20 3e a2 12 3b a4 83 4a c2 0e 93 d5 |.... >..;..J....|
+00000040 98 d5 2e 11 9e 60 60 23 78 5a 63 49 f1 7a ee c4 |.....``#xZcI.z..|
+00000050 47 00 6c 4e fb |G.lN.|
>>> Flow 4 (server to client)
-00000000 14 03 03 00 01 01 16 03 03 00 28 59 c3 19 1f ed |..........(Y....|
-00000010 d1 1b 54 5b 66 81 47 29 9a 77 84 87 a0 bd c5 d4 |..T[f.G).w......|
-00000020 f0 4e e2 11 d3 1d 26 dd 87 7a 55 11 48 37 7f 3a |.N....&..zU.H7.:|
-00000030 2c fc 62 |,.b|
+00000000 14 03 03 00 01 01 16 03 03 00 20 6d 78 5b 5f 1b |.......... mx[_.|
+00000010 2c 05 ba 92 46 e2 f0 04 48 fa a1 da be 93 ed fd |,...F...H.......|
+00000020 f5 f8 b8 dd 00 60 09 a6 36 3c c4 |.....`..6<.|
>>> Flow 5 (client to server)
-00000000 17 03 03 00 1e 00 00 00 00 00 00 00 01 02 12 57 |...............W|
-00000010 9d 64 c5 47 13 95 13 7b 2b 3e e0 f7 ae 49 0f c7 |.d.G...{+>...I..|
-00000020 0e 3a 67 |.:g|
+00000000 17 03 03 00 16 a4 db 13 bc c1 6e 06 9e 6d 1a c9 |..........n..m..|
+00000010 85 a7 e9 28 b8 27 74 19 8f 1a bc |...(.'t....|
>>> Flow 6 (server to client)
-00000000 16 03 03 00 1c 59 c3 19 1f ed d1 1b 55 ac 23 dc |.....Y......U.#.|
-00000010 0c 35 65 1e 7a 65 4f 47 13 46 a0 d0 d0 4d 0a 1f |.5e.zeOG.F...M..|
-00000020 5c |\|
+00000000 16 03 03 00 14 fa a3 77 3c 76 11 5d be 12 4f 6a |.......w<v.]..Oj|
+00000010 f7 0d 26 73 ab 7c bd 4b 19 |..&s.|.K.|
>>> Flow 7 (client to server)
-00000000 16 03 03 00 a9 00 00 00 00 00 00 00 02 c0 05 0c |................|
-00000010 76 0a 46 19 16 17 a6 75 af 11 bb 73 37 74 a4 26 |v.F....u...s7t.&|
-00000020 d9 16 93 b8 19 5e 2f 17 52 d1 12 9e 36 90 4e c9 |.....^/.R...6.N.|
-00000030 7a f9 89 75 3b d9 d4 e1 2e cf a0 5d 03 7d cc f6 |z..u;......].}..|
-00000040 73 aa a9 52 c7 65 78 d0 89 6f b1 15 6e f9 9e 55 |s..R.ex..o..n..U|
-00000050 42 9e 22 09 df 97 00 31 b8 73 57 1b 93 ff 0c e7 |B."....1.sW.....|
-00000060 46 29 40 79 a7 c0 de b9 44 93 7b 4d 35 a0 35 65 |F)@y....D.{M5.5e|
-00000070 6e 58 07 90 2b 11 49 26 10 f7 c7 32 f7 8e 6e a7 |nX..+.I&...2..n.|
-00000080 9b 75 ba cb 4a ce f7 f0 f1 31 ca 04 a6 02 d0 62 |.u..J....1.....b|
-00000090 da 9b 8b 27 8e 04 b8 4a 49 0d d6 31 10 93 30 37 |...'...JI..1..07|
-000000a0 ad ea d7 c4 49 98 90 f3 a1 45 f4 69 2e 59 |....I....E.i.Y|
+00000000 16 03 03 00 ad 59 80 a4 91 95 56 2a 01 ee 04 84 |.....Y....V*....|
+00000010 f9 d2 dd a5 2c a6 46 a8 69 a3 c7 47 7e eb 54 da |....,.F.i..G~.T.|
+00000020 ec cc 9d aa e1 0a b1 7c e9 cf 9f c9 c8 12 62 35 |.......|......b5|
+00000030 d2 4a eb 28 0d 9b aa a4 d5 79 66 f7 72 4c 26 10 |.J.(.....yf.rL&.|
+00000040 b6 71 db 4a 68 8b 47 f9 47 e3 6d a6 4e 99 d5 0b |.q.Jh.G.G.m.N...|
+00000050 27 b2 2c 23 9b 58 60 8a 37 a1 8e 26 09 26 2a 46 |'.,#.X`.7..&.&*F|
+00000060 e6 24 7f 9b cb 6b d1 9d b1 c0 48 c9 50 8b ab 06 |.$...k....H.P...|
+00000070 05 57 ef 1a e0 bd ce db ca 3d e1 59 df 24 4c 02 |.W.......=.Y.$L.|
+00000080 bf 1b 9e 48 52 42 6c dd 8f fa 82 68 56 52 a6 be |...HRBl....hVR..|
+00000090 d0 93 cb 43 74 e1 2f 86 cc e1 4c fa ba fc 1d f0 |...Ct./...L.....|
+000000a0 d5 20 3a 79 b3 b8 b7 24 b5 cf 4c dd a5 d0 4d 18 |. :y...$..L...M.|
+000000b0 15 55 |.U|
>>> Flow 8 (server to client)
-00000000 16 03 03 00 89 59 c3 19 1f ed d1 1b 56 c8 38 86 |.....Y......V.8.|
-00000010 22 b6 5f 55 cb 0c e1 40 e6 12 f2 71 d5 09 bc 47 |"._U... at ...q...G|
-00000020 ea 83 38 3a 58 f4 34 da ae 7f 64 fb 8c bc 71 64 |..8:X.4...d...qd|
-00000030 1b aa 84 e4 3e c1 cc c4 a9 05 36 13 5a 9b 1e c0 |....>.....6.Z...|
-00000040 44 cc 86 54 f0 75 b7 d0 aa b0 f0 3a b5 c7 f1 cc |D..T.u.....:....|
-00000050 1f cd 8e 9e 9e bb 24 23 c3 05 0b a5 1d f3 0b 41 |......$#.......A|
-00000060 41 19 89 1e ee 51 fc b3 e8 e2 6e a8 3f c4 8b ab |A....Q....n.?...|
-00000070 cb af d9 a1 7e 1c db e7 6c f6 23 71 c6 31 db 40 |....~...l.#q.1.@|
-00000080 a8 a7 08 fb 1a ff 8d 94 53 88 9a 11 73 6a 16 03 |........S...sj..|
-00000090 03 02 89 59 c3 19 1f ed d1 1b 57 17 dd 9c b5 a5 |...Y......W.....|
-000000a0 89 12 3a 14 61 34 e0 1d 0b 35 d6 3a 6c 09 93 2b |..:.a4...5.:l..+|
-000000b0 6c 69 ee f4 f3 be fb 42 33 99 fd 9a e6 21 38 68 |li.....B3....!8h|
-000000c0 a6 19 37 43 24 81 ba 35 12 fe ab ed 49 0b 03 54 |..7C$..5....I..T|
-000000d0 11 a7 74 4d bb ba e7 b9 f3 ee 6a 4e 1a 84 2f 03 |..tM......jN../.|
-000000e0 0c d1 28 21 49 84 f4 3c 5b 15 92 07 5c 6a 24 89 |..(!I..<[...\j$.|
-000000f0 00 cf 78 31 76 23 0f 9d 45 3b 93 a5 68 ee 9c 73 |..x1v#..E;..h..s|
-00000100 14 3f 08 30 37 40 4e 8b a4 02 03 3c 4b 52 74 99 |.?.07 at N....<KRt.|
-00000110 0e 9a ec 40 c6 74 16 ef c5 48 68 33 86 d7 06 57 |... at .t...Hh3...W|
-00000120 bf 8a 6f 3f 41 fe 4d f2 37 0a 1b fd fb 66 55 bd |..o?A.M.7....fU.|
-00000130 70 4d b0 8c 4f 78 24 eb 1f 8f 22 c7 aa 07 89 04 |pM..Ox$...".....|
-00000140 6a b3 07 15 37 25 21 63 97 39 b1 c1 9b fa 81 5e |j...7%!c.9.....^|
-00000150 69 c9 c7 4a 9c 5d b3 6a 41 d0 5e b9 f4 d5 5c a1 |i..J.].jA.^...\.|
-00000160 8e 8a ad 58 6e 5c 4f 73 62 38 1c 5f 8d b1 67 63 |...Xn\Osb8._..gc|
-00000170 49 da 4b 4e 83 54 34 8f 8d 12 de 4e 43 4d dc b9 |I.KN.T4....NCM..|
-00000180 02 ab 08 59 db 0b 45 7e f5 b8 e2 33 f1 04 de 16 |...Y..E~...3....|
-00000190 05 bf b4 2b 07 a1 11 e4 9e 48 f7 52 ab 20 89 04 |...+.....H.R. ..|
-000001a0 a7 44 28 7a 12 6c 19 ab 2f 68 1a d9 26 ec 72 a0 |.D(z.l../h..&.r.|
-000001b0 62 83 48 6f 4b 70 7d 74 3a 43 4f a6 38 37 fe 59 |b.HoKp}t:CO.87.Y|
-000001c0 6e 72 5d 81 7d 2c c7 e1 6b 06 47 41 56 17 2c 25 |nr].},..k.GAV.,%|
-000001d0 06 b1 7f f5 10 0a 31 a3 12 b1 5c 01 2f e0 a6 e4 |......1...\./...|
-000001e0 fa ab d2 0b 02 77 ad ac f8 54 db 70 20 0a 1f 04 |.....w...T.p ...|
-000001f0 86 a8 32 05 26 ee 7d e0 e9 03 19 cc 8f 67 f5 b6 |..2.&.}......g..|
-00000200 97 fe 06 5e c1 d5 df 25 f5 39 70 64 57 a8 c9 84 |...^...%.9pdW...|
-00000210 8f 0f 25 f8 c8 f9 17 70 e5 00 3c 4a 9f 4b c1 d9 |..%....p..<J.K..|
-00000220 6e b8 1a e4 6d 85 a4 e2 42 44 71 ba 43 9b 03 70 |n...m...BDq.C..p|
-00000230 14 ff 72 5e 5c 69 24 2e 52 0c 73 8b df 50 99 68 |..r^\i$.R.s..P.h|
-00000240 57 81 c1 ed b6 33 fc 74 15 45 fd a2 c4 8c f8 95 |W....3.t.E......|
-00000250 bf 8d 0e 92 91 42 72 77 03 ec c6 f6 9a 02 ca 7d |.....Brw.......}|
-00000260 3c 87 72 eb 8d 30 3a 5c b4 03 4a 6d 2e 83 22 c5 |<.r..0:\..Jm..".|
-00000270 e2 4a 95 83 7a 72 72 f2 2a 11 25 4a bd 04 16 ab |.J..zrr.*.%J....|
-00000280 6a 48 44 2b 99 fb 6f 61 9a 14 4a 42 1e bf d1 82 |jHD+..oa..JB....|
-00000290 db 62 5f ac 1e 6d 1d 1b 0d 4b 9d 8d 3a 84 94 b4 |.b_..m...K..:...|
-000002a0 aa 08 5b 90 7f d2 46 b0 a7 40 f4 55 76 6b 0d 4c |..[...F.. at .Uvk.L|
-000002b0 8e e3 8c fd ed 33 7d 93 f8 d8 c3 db 26 2d db a1 |.....3}.....&-..|
-000002c0 24 bc b0 fb 26 5f ec 13 5f 97 05 bb 5c 3c cc a3 |$...&_.._...\<..|
-000002d0 c2 57 58 cd 2e 70 0c a7 77 c5 e5 e8 0c 42 f2 e0 |.WX..p..w....B..|
-000002e0 1c 11 0f 62 4b 84 49 c2 b7 10 83 2e 16 1c 38 d4 |...bK.I.......8.|
-000002f0 10 f7 ca 71 7a 87 c5 a3 66 d2 98 1e c8 f2 c0 37 |...qz...f......7|
-00000300 0e 28 31 fe 8e 3e f4 03 74 6e 91 42 22 cb 5d 7f |.(1..>..tn.B".].|
-00000310 d2 22 da 3c f2 a0 2d 09 a9 a5 2d 14 16 03 03 00 |.".<..-...-.....|
-00000320 e5 59 c3 19 1f ed d1 1b 58 3f 19 93 55 cb 19 f8 |.Y......X?..U...|
-00000330 02 1a 43 b3 b2 6c 4e 3e ee 99 b3 df fd 45 24 ac |..C..lN>.....E$.|
-00000340 63 e7 45 cc a4 44 ca cf 3a e1 81 88 01 9a b3 64 |c.E..D..:......d|
-00000350 fe 6b 36 57 9f 81 fc 40 8d ef 21 af 00 be 43 f7 |.k6W... at ..!...C.|
-00000360 a3 3b a3 fa f0 01 f2 b4 ab 8a d1 a8 14 58 1b 6f |.;...........X.o|
-00000370 75 01 35 92 54 a7 a6 c1 99 1e 92 d8 87 53 7b 42 |u.5.T........S{B|
-00000380 4a 76 96 5e e9 db bb 4e f1 d9 bb e6 d2 b0 34 10 |Jv.^...N......4.|
-00000390 1b 4c d5 2c ca af 19 0d 3e 77 ee 77 0e 5f ff e2 |.L.,....>w.w._..|
-000003a0 02 c5 4a f2 ec 0b 7d cf d1 e7 3c 72 d2 17 4d 6c |..J...}...<r..Ml|
-000003b0 a7 ca 3a 1b 00 2b 69 17 e5 a9 82 69 49 c2 ff 8a |..:..+i....iI...|
-000003c0 f1 e8 ab 1b c3 8d da f1 31 ba a6 f4 7c 3c 01 6f |........1...|<.o|
-000003d0 ed a8 6f e2 4f a3 68 77 b7 54 b5 87 1b 5c 5c fb |..o.O.hw.T...\\.|
-000003e0 83 bf 48 4d 36 43 d6 f7 0a 48 74 f3 44 9d 43 53 |..HM6C...Ht.D.CS|
-000003f0 f8 54 1b 57 97 24 53 5a 93 e2 e9 33 f0 35 5f 0a |.T.W.$SZ...3.5_.|
-00000400 0d 4c ce 92 4d c9 16 03 03 00 46 59 c3 19 1f ed |.L..M.....FY....|
-00000410 d1 1b 59 80 50 fc 3a 56 e0 0b 06 b4 58 39 0c d8 |..Y.P.:V....X9..|
-00000420 4b b1 11 7a bd cf 1c 78 41 62 ee 22 74 61 7d 61 |K..z...xAb."ta}a|
-00000430 91 3d 0a 74 a4 b0 cd 25 70 19 a5 de d8 1b df 12 |.=.t...%p.......|
-00000440 4e b8 71 db ac bc 48 ea 89 32 ec 27 69 02 0d 8b |N.q...H..2.'i...|
-00000450 83 |.|
+00000000 16 03 03 00 81 10 b8 d9 9a 82 21 14 86 6d ef e4 |..........!..m..|
+00000010 b6 bc 10 84 80 a6 72 7b dc 24 ba e1 e5 d2 bb d2 |......r{.$......|
+00000020 9f 09 d3 d7 37 20 ec 7d bd 13 e0 bd 40 44 8a 6e |....7 .}.... at D.n|
+00000030 7f f6 d5 42 03 4b 00 b5 87 99 ac 6d 11 03 38 46 |...B.K.....m..8F|
+00000040 33 71 c4 10 ce da 36 d6 c1 41 9f 96 8e eb 4b 99 |3q....6..A....K.|
+00000050 24 07 8c 6b 88 2c f1 dd 31 35 ba 43 0f 60 bf b0 |$..k.,..15.C.`..|
+00000060 74 77 a9 d4 a7 65 f6 68 e2 70 4a 7e fe db ab 13 |tw...e.h.pJ~....|
+00000070 7f 51 c3 0f b4 93 42 12 d6 29 5d 44 5c df 17 6e |.Q....B..)]D\..n|
+00000080 73 1d b8 95 fc 8b 16 03 03 02 69 64 5d 4f b4 3a |s.........id]O.:|
+00000090 23 98 07 51 63 18 09 07 9a 8c dd 8e 51 a8 ca 23 |#..Qc.......Q..#|
+000000a0 37 21 f4 d5 e0 8f 03 1c 6f 6d c4 60 dd 99 8f 4b |7!......om.`...K|
+000000b0 4c 11 f7 78 f8 aa f6 29 87 cf 4d ba 89 87 2a c9 |L..x...)..M...*.|
+000000c0 48 66 48 d3 a6 19 8a 84 f6 db 17 b4 59 5b e4 8e |HfH.........Y[..|
+000000d0 8e ef fc 32 10 aa 0d 57 47 68 82 07 72 95 03 f6 |...2...WGh..r...|
+000000e0 e5 c1 c3 01 00 f9 85 4f 0f 85 37 73 f7 c5 af a2 |.......O..7s....|
+000000f0 37 96 ba 06 49 6a 2d a2 23 39 2e 9b f1 fc 01 de |7...Ij-.#9......|
+00000100 53 75 ee 34 ae 27 ea 49 6a d8 d0 cd 9b e8 60 b7 |Su.4.'.Ij.....`.|
+00000110 f6 b1 8e 26 ec 6c 36 87 d6 70 49 07 e0 96 2a bd |...&.l6..pI...*.|
+00000120 45 a3 b1 f5 dc b0 a3 4f dc d8 c3 fd 4f fb 98 13 |E......O....O...|
+00000130 67 55 99 39 b5 16 19 72 9d f1 5a cf 6e 53 d9 03 |gU.9...r..Z.nS..|
+00000140 05 f5 81 07 a1 38 a1 e5 4c 76 51 1a ae f6 4b f6 |.....8..LvQ...K.|
+00000150 b2 a7 84 1e 2a 31 b0 b8 9f 41 e8 e5 32 18 44 4c |....*1...A..2.DL|
+00000160 0b fb e3 d9 4c dd 45 c5 c4 c4 57 bf f7 5a dc f6 |....L.E...W..Z..|
+00000170 73 98 d4 ea 2f c0 cb 35 97 c1 45 94 37 87 d3 8c |s.../..5..E.7...|
+00000180 65 3f ee a8 67 a6 00 80 92 02 76 e8 0a 04 ce 7a |e?..g.....v....z|
+00000190 79 4f cd 70 1a 31 5a 03 83 01 de 1f 4a 46 39 4e |yO.p.1Z.....JF9N|
+000001a0 d0 80 6e 67 d7 e6 fc ba 74 4b 57 d2 3c 19 7b 03 |..ng....tKW.<.{.|
+000001b0 ab 9a e2 f7 db 58 c2 b7 58 96 55 88 e6 e2 e2 f8 |.....X..X.U.....|
+000001c0 ab e9 b0 12 ef ff e6 53 7b 4e 01 2f 65 0d 05 f0 |.......S{N./e...|
+000001d0 95 9f 46 d2 ae e7 33 5c 37 56 ab 67 95 87 81 59 |..F...3\7V.g...Y|
+000001e0 f2 35 76 78 ed 13 63 a3 58 52 af 46 e6 aa c3 99 |.5vx..c.XR.F....|
+000001f0 37 9d 10 25 cc 7f 7e 63 e1 96 6d 7a 8e ac 9e 00 |7..%..~c..mz....|
+00000200 d1 0e 7a 48 b6 82 77 6a a0 17 d1 77 70 f8 40 4a |..zH..wj...wp. at J|
+00000210 c4 90 da b0 3f 25 68 f5 9f dd 5e ec 95 02 19 53 |....?%h...^....S|
+00000220 08 6a 13 11 88 9e 2b 25 b8 28 cd 58 36 d7 d3 95 |.j....+%.(.X6...|
+00000230 f5 91 63 92 ff 3b d2 4f 75 ae 47 6c 64 8a a4 76 |..c..;.Ou.Gld..v|
+00000240 48 96 a7 35 d6 35 22 96 4d 4f ee 45 fb 88 52 68 |H..5.5".MO.E..Rh|
+00000250 4e 38 93 e8 08 6a e6 f3 00 a7 f7 b0 0b 68 41 ab |N8...j.......hA.|
+00000260 9b 3a 92 2b fd b2 71 14 77 91 48 e7 70 62 b5 b0 |.:.+..q.w.H.pb..|
+00000270 45 90 35 d2 b3 22 f5 70 6c 62 7f 55 6b 56 42 f8 |E.5..".plb.UkVB.|
+00000280 6c 87 a7 60 45 37 f0 41 41 ec 73 f5 f1 d9 d2 84 |l..`E7.AA.s.....|
+00000290 bd 88 bc 9b 43 ec 8b b3 c4 3a 59 2c 30 61 30 98 |....C....:Y,0a0.|
+000002a0 78 d3 e7 85 dd 7e 80 b8 fb b3 bf 7e 11 79 e8 20 |x....~.....~.y. |
+000002b0 aa b8 81 94 10 5c f8 ba 70 4c 1e 7c 35 8f 48 30 |.....\..pL.|5.H0|
+000002c0 17 38 d6 1c 91 ed 00 2c f7 af 29 d3 cb 9b ab 6b |.8.....,..)....k|
+000002d0 b3 fa 6e 1a 9b a8 cf 08 8e 03 a5 f7 76 17 74 3a |..n.........v.t:|
+000002e0 9e 36 ae 19 fd 2c 44 14 f3 2b 1d 01 db e1 96 22 |.6...,D..+....."|
+000002f0 25 14 5b d8 16 03 03 00 bc bb 8c bb cf f9 d7 76 |%.[............v|
+00000300 7a a7 d6 e0 29 cb 45 21 8d 57 0b 81 0c e0 96 05 |z...).E!.W......|
+00000310 c7 96 67 43 0f 41 11 e9 c2 07 2d 62 17 b4 64 01 |..gC.A....-b..d.|
+00000320 c5 75 79 dc 9c 36 3f ea 42 ea 09 a7 bc 0f 6b b1 |.uy..6?.B.....k.|
+00000330 b4 4d ae 38 0a ca 51 d0 97 46 b6 55 12 7c 24 28 |.M.8..Q..F.U.|$(|
+00000340 77 16 64 42 53 70 c4 52 ed e5 aa 20 3a 00 7e d0 |w.dBSp.R... :.~.|
+00000350 9e 99 e4 56 5f ef 30 56 00 8b e7 31 6d 66 6d dc |...V_.0V...1mfm.|
+00000360 58 8a b0 60 6f 16 a7 b0 14 a5 9d 3d 38 94 6e 16 |X..`o......=8.n.|
+00000370 a3 22 76 e9 59 d8 90 cd 32 83 bb 8c c5 23 cb c2 |."v.Y...2....#..|
+00000380 c5 03 02 de 13 97 ac 4e 99 9f 4d 6d aa ed 72 b7 |.......N..Mm..r.|
+00000390 76 db 8b c9 31 17 b9 1c 4a fa 87 2c 6b dc 07 82 |v...1...J..,k...|
+000003a0 a2 39 e0 09 32 a2 8e 1c 6e 68 e1 14 ba ab 3a d4 |.9..2...nh....:.|
+000003b0 1e 4f f4 39 c7 16 03 03 00 3a cf b2 61 5f 7e ef |.O.9.....:..a_~.|
+000003c0 04 51 64 f6 3d b3 54 44 bd 8a d0 87 48 64 76 a6 |.Qd.=.TD....Hdv.|
+000003d0 0d bc 7f b7 99 d4 67 8b cd e3 c4 5d df c5 c8 fc |......g....]....|
+000003e0 be d1 c4 03 6d 61 2d 10 58 b1 7a 7c 9e 1c 6b 16 |....ma-.X.z|..k.|
+000003f0 ff 31 a8 87 16 03 03 00 14 85 99 57 4b a1 19 33 |.1.........WK..3|
+00000400 bd 9a 86 ed be 5d 24 f0 02 9d ca 1e 26 |.....]$.....&|
>>> Flow 9 (client to server)
-00000000 16 03 03 02 89 00 00 00 00 00 00 00 03 be 8d 55 |...............U|
-00000010 8a 5b 24 10 db e3 f2 11 28 0d 26 cc 1b bc 38 fa |.[$.....(.&...8.|
-00000020 1c 8c f8 c9 64 55 ec 43 16 f7 ca af 12 a8 1c 09 |....dU.C........|
-00000030 0d b0 47 bc 9f 19 02 91 ab 9d 33 b4 bc 45 f7 4d |..G.......3..E.M|
-00000040 53 85 4a 91 7e d3 2d dc d6 02 6e 4a 34 51 99 db |S.J.~.-...nJ4Q..|
-00000050 f2 a1 8d 34 60 6f 15 6a f9 4d 7a 03 0b dc f7 c1 |...4`o.j.Mz.....|
-00000060 99 c2 2c b8 4c a1 63 ce a2 fb 33 0d d6 dd d4 0a |..,.L.c...3.....|
-00000070 88 0c 1d 5c ea 06 00 33 3a 06 6e 3d 63 b4 d5 0c |...\...3:.n=c...|
-00000080 9b 69 f0 86 72 db 47 52 3d 61 0b 66 57 8d 7b 67 |.i..r.GR=a.fW.{g|
-00000090 1e 42 aa b8 ca e6 d3 07 56 cf f5 09 14 25 a2 1d |.B......V....%..|
-000000a0 3b 3e dd 0c 41 ac 66 05 3b db 59 85 9d e2 9f 8b |;>..A.f.;.Y.....|
-000000b0 21 c0 9a 3b 0b 8e 5b 4b af ac 73 87 d3 b4 34 b7 |!..;..[K..s...4.|
-000000c0 2e 26 b0 5d 10 3a 2e 00 cc ac 40 b5 72 40 69 fa |.&.].:.... at .r@i.|
-000000d0 11 04 b6 37 38 84 59 76 29 08 f0 0f 0f 79 40 7c |...78.Yv)....y@||
-000000e0 e4 08 15 b7 58 cd 6c f4 d6 77 d6 f8 cb 1d ca 5c |....X.l..w.....\|
-000000f0 41 d7 f8 64 63 14 a5 a5 3a 13 ce 55 b4 0a d9 b5 |A..dc...:..U....|
-00000100 34 f9 5e 69 f2 9a 62 88 b9 69 2f 93 08 2c 55 c4 |4.^i..b..i/..,U.|
-00000110 5d 0d cb 92 ac 2c 30 27 83 11 68 9f 74 35 5d 3a |]....,0'..h.t5]:|
-00000120 96 4c 57 91 95 a8 e7 03 fa b7 ae 8b 94 e3 39 38 |.LW...........98|
-00000130 6d e1 ad b1 f7 26 2c 90 d4 3c eb a5 5e df e4 29 |m....&,..<..^..)|
-00000140 39 ff ba d2 04 f4 b4 9c fa c2 da 34 bc 04 32 07 |9..........4..2.|
-00000150 db 52 38 fd 92 89 4c e9 50 13 e5 90 e7 f1 88 5e |.R8...L.P......^|
-00000160 c1 7a 9b fa 6e 1f 99 ce 52 77 0c 03 d8 a6 5d 64 |.z..n...Rw....]d|
-00000170 ab 58 82 93 10 a1 4f 35 ea a3 6d af a9 64 17 3d |.X....O5..m..d.=|
-00000180 fc a8 d8 9e 7e d7 44 af 2a c1 d6 a8 4d 78 b3 0b |....~.D.*...Mx..|
-00000190 d1 0b 3d 54 e2 c8 df 84 61 cb 92 1a d8 ce 23 a3 |..=T....a.....#.|
-000001a0 68 f7 af 40 53 09 f0 cc 00 7d 39 83 2c 6d f4 44 |h.. at S....}9.,m.D|
-000001b0 d6 95 59 06 0a ef 9c 74 39 b3 70 cb 0a 0c 13 cd |..Y....t9.p.....|
-000001c0 ec 1f bf 75 93 01 1a 35 68 75 8b 80 15 80 7d a9 |...u...5hu....}.|
-000001d0 d0 25 9a 52 bc 02 bf 71 eb 60 76 2a 74 90 c8 16 |.%.R...q.`v*t...|
-000001e0 80 03 c2 a8 0c be 94 7c 12 b0 ee 45 3a 38 09 5a |.......|...E:8.Z|
-000001f0 bf 8b ca 78 f3 9e 79 8a 9f 65 57 84 f8 33 79 2a |...x..y..eW..3y*|
-00000200 f8 8c e0 c8 4b 9e 12 19 b1 3f ba cf 9d db 48 13 |....K....?....H.|
-00000210 b4 b0 53 0e 7a 6b 1d 21 13 45 37 8d 90 75 88 f9 |..S.zk.!.E7..u..|
-00000220 b5 9d 41 d0 ee 95 5f 6a e5 96 b6 48 ce 3b 43 20 |..A..._j...H.;C |
-00000230 47 15 db eb ba af 6d bf 38 26 e7 ad 86 ba 1e 91 |G.....m.8&......|
-00000240 be 8b df ba 5c 30 6e 3c 13 6a 96 68 13 24 bf 06 |....\0n<.j.h.$..|
-00000250 f1 d2 b0 05 8f 8e 21 7f 6a 09 5f b8 be 0b c5 5f |......!.j._...._|
-00000260 67 60 94 ec 78 65 6f 70 94 9b 15 82 07 f4 88 fb |g`..xeop........|
-00000270 a2 94 68 f7 57 0a 9c ec ab 3f 8f d5 83 ec 6a 24 |..h.W....?....j$|
-00000280 6f 88 4f 22 7f a1 82 cb ef ec 4c 33 b9 c1 16 03 |o.O"......L3....|
-00000290 03 00 5e 00 00 00 00 00 00 00 04 34 f9 69 a5 83 |..^........4.i..|
-000002a0 c5 86 34 51 f0 07 5b 44 51 36 c1 0d f7 71 c7 1b |..4Q..[DQ6...q..|
-000002b0 70 27 aa 35 cd c7 10 76 fd 96 27 dc bc 6f 39 ff |p'.5...v..'..o9.|
-000002c0 f1 a7 de e3 c5 21 70 e9 70 b1 52 d2 f0 be c0 72 |.....!p.p.R....r|
-000002d0 e5 aa 2b 1a 1d a8 8f 10 37 b5 2f c7 b9 32 c8 3c |..+.....7./..2.<|
-000002e0 7c c8 11 a5 dc aa 84 12 57 f1 ff 3b f9 04 a4 29 ||.......W..;...)|
-000002f0 24 16 03 03 00 a0 00 00 00 00 00 00 00 05 1a 86 |$...............|
-00000300 c7 35 6f 23 c5 38 85 85 0e 31 df 33 1a 42 6e f8 |.5o#.8...1.3.Bn.|
-00000310 c3 f7 81 29 aa 03 85 8c 5a 8a e1 9b 1c d3 6f 7d |...)....Z.....o}|
-00000320 36 41 45 30 06 2b dd 19 dc 22 9e 9e d4 bc 0e 51 |6AE0.+...".....Q|
-00000330 65 59 e9 7e 1b a1 d1 54 4b 3c 9a 41 de b9 43 98 |eY.~...TK<.A..C.|
-00000340 a5 ef 7a b8 77 69 f7 a5 80 02 d6 46 73 96 89 46 |..z.wi.....Fs..F|
-00000350 43 3a d7 ae 21 64 db 05 b5 7d fc 83 a3 75 ba ad |C:..!d...}...u..|
-00000360 0d d2 d6 9b 51 3b cb 37 85 46 92 b5 57 eb 2c dc |....Q;.7.F..W.,.|
-00000370 b2 8f e2 c0 7f 29 bf 5e bd f0 26 dd 31 e4 31 af |.....).^..&.1.1.|
-00000380 09 51 e4 26 09 56 a2 f4 5d fc c5 cb c8 da 51 ee |.Q.&.V..].....Q.|
-00000390 35 2e bb 3e ee bb 14 03 03 00 19 00 00 00 00 00 |5..>............|
-000003a0 00 00 06 b5 3d 07 af c9 3f ad f0 25 b4 5e b9 0f |....=...?..%.^..|
-000003b0 fa f0 16 48 16 03 03 00 28 00 00 00 00 00 00 00 |...H....(.......|
-000003c0 00 43 54 67 b4 f1 0e 1d 9d 7f ab f7 4c b6 77 3f |.CTg........L.w?|
-000003d0 d0 17 da 6a 61 75 a8 c8 42 47 fb 2a f7 22 85 02 |...jau..BG.*."..|
-000003e0 b0 |.|
+00000000 16 03 03 02 69 8c c7 01 da 38 a5 36 3d 2c 21 1c |....i....8.6=,!.|
+00000010 64 1b b8 e7 c2 cd 17 06 b6 51 0e e6 d9 d9 18 c5 |d........Q......|
+00000020 a9 c9 ac 5d 2d 23 f8 15 92 b2 e1 62 6e d7 8d 58 |...]-#.....bn..X|
+00000030 5b d9 b8 26 e5 ec 0f 61 15 3e 12 70 89 0d 3f 4e |[..&...a.>.p..?N|
+00000040 e3 2e 18 42 7c c7 59 7b e1 48 d9 a8 cf b1 cd 38 |...B|.Y{.H.....8|
+00000050 17 90 97 89 2e 4f 4b df 58 b0 9f 4e 95 d2 e9 70 |.....OK.X..N...p|
+00000060 6d 0b 82 af b7 05 be 11 26 d8 f9 89 e6 d6 44 f5 |m.......&.....D.|
+00000070 db 7c 8c 91 61 78 dc 68 98 9b 10 17 5b 85 42 93 |.|..ax.h....[.B.|
+00000080 31 a2 16 97 72 c5 f2 d0 81 76 a6 9b b7 9c 14 ab |1...r....v......|
+00000090 a7 bf 19 f7 34 e3 8f 3f a5 aa 23 c8 49 07 1b 6f |....4..?..#.I..o|
+000000a0 e5 5d 65 66 a1 dc d2 e7 bb c2 4b 9e a7 9a dc d6 |.]ef......K.....|
+000000b0 72 42 d3 71 d3 51 a4 3a 82 f7 cd 2a 15 34 da 6d |rB.q.Q.:...*.4.m|
+000000c0 44 3a a9 7d 6e 4c ce a5 ba 6b 5b 3b 88 8c e1 29 |D:.}nL...k[;...)|
+000000d0 ee a8 17 1b 02 36 8f 68 c9 9e e6 f1 bf e3 e3 e0 |.....6.h........|
+000000e0 cd 6d 7f ff c2 4d 3f 88 c7 9b 75 20 e5 cd fa fa |.m...M?...u ....|
+000000f0 a0 d7 10 6a c1 00 73 f9 df bd 22 60 8c 82 71 e6 |...j..s..."`..q.|
+00000100 56 aa 90 bf c7 a8 82 51 e7 23 42 ec 99 f5 b9 aa |V......Q.#B.....|
+00000110 3c cc c6 32 11 29 1f a6 ae 89 03 04 e8 de 9f f4 |<..2.)..........|
+00000120 bd 87 ae af 91 ee a2 f3 e2 6d 7b 87 ad 67 16 2d |.........m{..g.-|
+00000130 ad 92 34 38 52 ed 7c 38 92 45 16 26 9f 65 d2 67 |..48R.|8.E.&.e.g|
+00000140 3e 33 a1 bd b2 f6 d3 c8 76 96 52 11 0d 8d ac a6 |>3......v.R.....|
+00000150 27 10 6a 43 63 5f 82 41 e7 fe 91 24 68 70 bd 2c |'.jCc_.A...$hp.,|
+00000160 35 fd 0e 49 ec 3a dd f3 c0 af 5c f4 61 9a 2a 00 |5..I.:....\.a.*.|
+00000170 59 b5 28 24 f0 cf d3 25 bc 77 65 74 04 ee 4b 5e |Y.($...%.wet..K^|
+00000180 2b 9f 1d 27 e2 dd 1a ed ab e5 ff d6 1a 55 d7 4d |+..'.........U.M|
+00000190 5c da 14 96 21 43 f6 c3 2d 78 e5 75 60 69 26 ce |\...!C..-x.u`i&.|
+000001a0 7a 66 5e 42 91 0e ef 41 c2 c4 e6 15 8a 9a 17 a1 |zf^B...A........|
+000001b0 d9 23 2c cc c7 81 00 71 b0 52 ec 4e ea eb f9 75 |.#,....q.R.N...u|
+000001c0 2e 87 16 b4 ba 25 8c 09 f1 23 f9 ee ea db 0e b5 |.....%...#......|
+000001d0 d0 dd 47 9b b6 06 a3 f3 5e 0d 34 5a ba 76 cd 0a |..G.....^.4Z.v..|
+000001e0 b1 9f 8a 99 aa d3 02 2e b6 04 7b c5 d3 2f dc d7 |..........{../..|
+000001f0 68 af 6b 88 90 0a 94 a4 29 65 0b ba b3 da f2 cd |h.k.....)e......|
+00000200 51 93 4f ea b4 f8 54 c7 28 e3 2d 63 d0 62 54 d9 |Q.O...T.(.-c.bT.|
+00000210 27 a0 85 57 7b a2 f2 f5 a5 25 83 1b e2 36 15 06 |'..W{....%...6..|
+00000220 41 ae e1 f9 ca a5 c6 59 2d da 4a ed 10 7b 80 01 |A......Y-.J..{..|
+00000230 06 39 f2 a8 4b 22 37 4d aa 84 79 85 71 29 1b 4e |.9..K"7M..y.q).N|
+00000240 c3 79 af 13 f5 4e 3c 6d fa 8c d7 55 13 2b 48 3d |.y...N<m...U.+H=|
+00000250 9a 79 e2 b4 3f 59 f8 f9 6c d2 39 51 e0 6e c2 c3 |.y..?Y..l.9Q.n..|
+00000260 09 06 d4 e0 4f 76 a6 54 b8 9d ef 30 ba 80 16 03 |....Ov.T...0....|
+00000270 03 00 35 df a1 cc 0f 77 42 24 fe 38 ac ec 25 cf |..5....wB$.8..%.|
+00000280 13 85 03 87 73 b4 c0 d9 97 d0 a8 8e 12 f4 13 61 |....s..........a|
+00000290 42 40 03 a6 b6 6c d3 dd d9 92 f0 e9 bc bc a7 22 |B at ...l........."|
+000002a0 64 cf 4b 00 97 71 ac 3b 16 03 03 00 98 f7 61 85 |d.K..q.;......a.|
+000002b0 47 fc 23 b5 34 4b 1f 10 c7 12 51 07 a2 40 40 48 |G.#.4K....Q..@@H|
+000002c0 1c 79 52 3a a7 9d ca 45 62 a2 53 71 bd 23 0a 77 |.yR:...Eb.Sq.#.w|
+000002d0 0b 7f 8c ff f2 51 da 91 07 d7 67 71 bb ec 02 8d |.....Q....gq....|
+000002e0 3f 79 dc d9 af f4 4c 78 3e ac 8d 30 ed eb c9 19 |?y....Lx>..0....|
+000002f0 96 89 a7 0f 7c fb 96 18 84 86 e7 bd e2 35 31 0c |....|........51.|
+00000300 7a 51 d7 94 6b 61 62 7a 6a d8 56 62 e6 cf bf 60 |zQ..kabzj.Vb...`|
+00000310 df 7a c5 ce d3 87 ea 2f 5a ad 90 d4 39 f7 47 8e |.z...../Z...9.G.|
+00000320 8b d3 6b 8e e0 3f 2f 59 71 e4 e6 bf 3f 4a 29 a8 |..k..?/Yq...?J).|
+00000330 60 df 1b 5c 2d 21 ab 0a a5 9f 5a a2 a3 d6 08 3c |`..\-!....Z....<|
+00000340 4a 4b f9 d6 a0 14 03 03 00 11 44 a4 62 7e c1 4a |JK........D.b~.J|
+00000350 4e 56 dd 08 65 b2 ab 12 cd fa 8d 16 03 03 00 20 |NV..e.......... |
+00000360 b4 52 5a e8 33 b6 23 b1 b4 e6 59 da b0 84 52 94 |.RZ.3.#...Y...R.|
+00000370 70 de dc 02 f6 41 e3 27 7c 27 56 6a 7c 92 e3 48 |p....A.'|'Vj|..H|
>>> Flow 10 (server to client)
-00000000 14 03 03 00 19 59 c3 19 1f ed d1 1b 5a 9d 51 67 |.....Y......Z.Qg|
-00000010 ff ed 61 fd 01 85 c2 46 f1 26 e1 08 c3 5b 16 03 |..a....F.&...[..|
-00000020 03 00 28 02 08 83 98 20 78 eb a5 8e f5 d3 31 b6 |..(.... x.....1.|
-00000030 6d 4b 3a 9c cd 76 30 ca 92 4b 6c 17 2c d8 c5 d5 |mK:..v0..Kl.,...|
-00000040 7d 59 76 f8 ff 0c 8f f4 f6 fb 81 17 03 03 00 21 |}Yv............!|
-00000050 02 08 83 98 20 78 eb a6 9b c6 07 33 3b 43 e4 5b |.... x.....3;C.[|
-00000060 c6 d4 31 6e 2b 5b 4a 65 c2 0a df 27 02 a2 3e 3b |..1n+[Je...'..>;|
-00000070 04 16 03 03 00 1c 02 08 83 98 20 78 eb a7 43 45 |.......... x..CE|
-00000080 df 9b 74 94 81 17 21 b1 7d d5 c0 7a 2b cc 38 a1 |..t...!.}..z+.8.|
-00000090 30 1d |0.|
+00000000 14 03 03 00 11 c7 92 b3 aa a0 91 21 4f 42 96 0c |...........!OB..|
+00000010 3a 92 c3 53 55 d1 16 03 03 00 20 4b da e5 1c 08 |:..SU..... K....|
+00000020 ce a7 33 f1 a6 c7 47 52 19 68 b4 f5 1d 66 a7 38 |..3...GR.h...f.8|
+00000030 97 45 43 9f ca b5 db 2c 14 fc f4 17 03 03 00 19 |.EC....,........|
+00000040 28 f4 bb bf c1 5a 2d 1e b8 fc c7 fc 55 16 e9 cc |(....Z-.....U...|
+00000050 43 a3 63 58 7e 2c 60 77 23 16 03 03 00 14 2c e6 |C.cX~,`w#.....,.|
+00000060 25 0a b7 26 7b 13 55 62 f1 fe 6e fe 0e 57 53 57 |%..&{.Ub..n..WSW|
+00000070 19 1b |..|
>>> Flow 11 (client to server)
-00000000 15 03 03 00 1a 00 00 00 00 00 00 00 01 d6 2b 5a |..............+Z|
-00000010 7d c9 ba d3 94 cc 45 26 1c 1e 1e 70 39 6c 4e 15 |}.....E&...p9lN.|
-00000020 03 03 00 1a 00 00 00 00 00 00 00 02 fd 76 21 e8 |.............v!.|
-00000030 b5 16 14 43 36 9f 61 14 6d 40 76 e3 14 11 |...C6.a.m at v...|
+00000000 15 03 03 00 12 dd 2b 00 09 fd 8c 7d 21 3d 7c 06 |......+....}!=|.|
+00000010 93 ca c9 21 b2 3e 20 15 03 03 00 12 90 32 4b 3b |...!.> ......2K;|
+00000020 33 4d fd 69 55 81 aa 42 16 ae 47 b9 4c 06 |3M.iU..B..G.L.|
diff --git a/src/crypto/tls/testdata/Client-TLSv12-RenegotiationRejected b/src/crypto/tls/testdata/Client-TLSv12-RenegotiationRejected
index 90adc18..cb96432 100644
--- a/src/crypto/tls/testdata/Client-TLSv12-RenegotiationRejected
+++ b/src/crypto/tls/testdata/Client-TLSv12-RenegotiationRejected
@@ -1,97 +1,89 @@
>>> Flow 1 (client to server)
-00000000 16 03 01 00 85 01 00 00 81 03 03 00 00 00 00 00 |................|
+00000000 16 03 01 00 91 01 00 00 8d 03 03 00 00 00 00 00 |................|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
-00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 22 c0 2f |............."./|
-00000030 c0 2b c0 30 c0 2c c0 11 c0 07 c0 13 c0 09 c0 14 |.+.0.,..........|
-00000040 c0 0a 00 9c 00 9d 00 05 00 2f 00 35 c0 12 00 0a |........./.5....|
-00000050 01 00 00 36 00 05 00 05 01 00 00 00 00 00 0a 00 |...6............|
-00000060 08 00 06 00 17 00 18 00 19 00 0b 00 02 01 00 00 |................|
-00000070 0d 00 0e 00 0c 04 01 04 03 05 01 05 03 02 01 02 |................|
-00000080 03 ff 01 00 01 00 00 12 00 00 |..........|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2c cc a8 |.............,..|
+00000030 cc a9 c0 2f c0 2b c0 30 c0 2c c0 27 c0 13 c0 23 |.../.+.0.,.'...#|
+00000040 c0 09 c0 14 c0 0a 00 9c 00 9d 00 3c 00 2f 00 35 |...........<./.5|
+00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 38 00 05 |.............8..|
+00000060 00 05 01 00 00 00 00 00 0a 00 0a 00 08 00 1d 00 |................|
+00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 0e 00 |................|
+00000080 0c 04 01 04 03 05 01 05 03 02 01 02 03 ff 01 00 |................|
+00000090 01 00 00 12 00 00 |......|
>>> Flow 2 (server to client)
-00000000 16 03 03 00 59 02 00 00 55 03 03 b1 7d c5 82 a4 |....Y...U...}...|
-00000010 f7 1d 3a b9 c0 da 13 7c 2f 75 22 a4 5f 2e 58 2a |..:....|/u"._.X*|
-00000020 39 eb 18 7c bb 0d 98 ba 51 2e 4a 20 41 40 2f 53 |9..|....Q.J A@/S|
-00000030 bc 16 e0 a4 44 07 f0 5e 8f 43 a3 69 87 0b 94 dd |....D..^.C.i....|
-00000040 60 a0 20 d0 25 e1 a1 a0 b8 0d d8 00 c0 2f 00 00 |`. .%......../..|
+00000000 16 03 03 00 59 02 00 00 55 03 03 91 a6 bc 02 ab |....Y...U.......|
+00000010 19 62 2c de 45 57 ba 71 c0 b0 4d 78 5e f4 c2 b9 |.b,.EW.q..Mx^...|
+00000020 81 ba 8b d6 b1 9b c8 fb 0c 7c 40 20 dc 66 80 5b |.........|@ .f.[|
+00000030 20 3c 60 65 7f 9e 0c 67 a8 f3 22 c9 c5 48 80 fa | <`e...g.."..H..|
+00000040 02 a1 1a 48 6d 1c 46 07 db 6c 8e 85 cc a8 00 00 |...Hm.F..l......|
00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................|
-00000060 03 02 71 0b 00 02 6d 00 02 6a 00 02 67 30 82 02 |..q...m..j..g0..|
-00000070 63 30 82 01 cc a0 03 02 01 02 02 09 00 a2 73 00 |c0............s.|
-00000080 0c 81 00 cb f3 30 0d 06 09 2a 86 48 86 f7 0d 01 |.....0...*.H....|
-00000090 01 0b 05 00 30 2b 31 17 30 15 06 03 55 04 0a 13 |....0+1.0...U...|
-000000a0 0e 47 6f 6f 67 6c 65 20 54 45 53 54 49 4e 47 31 |.Google TESTING1|
-000000b0 10 30 0e 06 03 55 04 03 13 07 47 6f 20 52 6f 6f |.0...U....Go Roo|
-000000c0 74 30 1e 17 0d 31 35 30 31 30 31 30 30 30 30 30 |t0...15010100000|
-000000d0 30 5a 17 0d 32 35 30 31 30 31 30 30 30 30 30 30 |0Z..250101000000|
-000000e0 5a 30 26 31 17 30 15 06 03 55 04 0a 13 0e 47 6f |Z0&1.0...U....Go|
-000000f0 6f 67 6c 65 20 54 45 53 54 49 4e 47 31 0b 30 09 |ogle TESTING1.0.|
-00000100 06 03 55 04 03 13 02 47 6f 30 81 9f 30 0d 06 09 |..U....Go0..0...|
-00000110 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 30 |*.H............0|
-00000120 81 89 02 81 81 00 af 87 88 f6 20 1b 95 65 6c 14 |.......... ..el.|
-00000130 ab 44 05 af 3b 45 14 e3 b7 6d fd 00 63 4d 95 7f |.D..;E...m..cM..|
-00000140 fe 6a 62 35 86 c0 4a f9 18 7c f6 aa 25 5e 7a 64 |.jb5..J..|..%^zd|
-00000150 31 66 00 ba f4 8e 92 af c7 6b d8 76 d4 f3 5f 41 |1f.......k.v.._A|
-00000160 cb 6e 56 15 97 1b 97 c1 3c 12 39 21 66 3d 2b 16 |.nV.....<.9!f=+.|
-00000170 d1 bc db 1c c0 a7 da b7 ca ad ba da cb d5 21 50 |..............!P|
-00000180 ec de 8d ab d1 6b 81 4b 89 02 f3 c4 be c1 6c 89 |.....k.K......l.|
-00000190 b1 44 84 bd 21 d1 04 7d 9d 16 4d f9 82 15 f6 ef |.D..!..}..M.....|
-000001a0 fa d6 09 47 f2 fb 02 03 01 00 01 a3 81 93 30 81 |...G..........0.|
-000001b0 90 30 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 05 |.0...U..........|
-000001c0 a0 30 1d 06 03 55 1d 25 04 16 30 14 06 08 2b 06 |.0...U.%..0...+.|
-000001d0 01 05 05 07 03 01 06 08 2b 06 01 05 05 07 03 02 |........+.......|
-000001e0 30 0c 06 03 55 1d 13 01 01 ff 04 02 30 00 30 19 |0...U.......0.0.|
-000001f0 06 03 55 1d 0e 04 12 04 10 12 50 8d 89 6f 1b d1 |..U.......P..o..|
-00000200 dc 54 4d 6e cb 69 5e 06 f4 30 1b 06 03 55 1d 23 |.TMn.i^..0...U.#|
-00000210 04 14 30 12 80 10 bf 3d b6 a9 66 f2 b8 40 cf ea |..0....=..f.. at ..|
-00000220 b4 03 78 48 1a 41 30 19 06 03 55 1d 11 04 12 30 |..xH.A0...U....0|
-00000230 10 82 0e 65 78 61 6d 70 6c 65 2e 67 6f 6c 61 6e |...example.golan|
-00000240 67 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 |g0...*.H........|
-00000250 03 81 81 00 92 7c af 91 55 12 18 96 59 31 a6 48 |.....|..U...Y1.H|
-00000260 40 d5 2d d5 ee bb 02 a0 f5 c2 1e 7c 9b b3 30 7d |@.-........|..0}|
-00000270 3c dc 76 da 4f 3d c0 fa ae 2d 33 24 6b 03 7b 1b |<.v.O=...-3$k.{.|
-00000280 67 59 11 21 b5 11 bc 77 b9 d9 e0 6e a8 2d 2e 35 |gY.!...w...n.-.5|
-00000290 fa 64 5f 22 3e 63 10 6b be ff 14 86 6d 0d f0 15 |.d_">c.k....m...|
-000002a0 31 a8 14 38 1e 3b 84 87 2c cb 98 ed 51 76 b9 b1 |1..8.;..,...Qv..|
-000002b0 4f dd db 9b 84 04 86 40 fa 51 dd ba b4 8d eb e3 |O...... at .Q......|
-000002c0 46 de 46 b9 4f 86 c7 f9 a4 c2 41 34 ac cc f6 ea |F.F.O.....A4....|
-000002d0 b0 ab 39 18 16 03 03 00 cd 0c 00 00 c9 03 00 17 |..9.............|
-000002e0 41 04 62 2a a7 2d 1f 7a 8d 7e 8a 9e 84 db df e2 |A.b*.-.z.~......|
-000002f0 7c 35 d8 a1 9f ec 23 ef c7 c2 9a c5 45 02 6f eb ||5....#.....E.o.|
-00000300 24 ed 77 e1 ca fe 9a be 06 1e ea 30 5a e7 13 00 |$.w........0Z...|
-00000310 47 52 a4 a2 d8 ee 9d 4e 87 f5 48 83 6f 5d 8e 02 |GR.....N..H.o]..|
-00000320 ff f5 04 01 00 80 19 f6 63 a1 47 d1 cf 4d 28 73 |........c.G..M(s|
-00000330 4e 31 03 78 b5 17 ba 53 64 d0 b8 3f 04 77 9d 6b |N1.x...Sd..?.w.k|
-00000340 85 d0 d4 1e 02 90 b9 ab 10 dc d7 b1 79 1b 12 80 |............y...|
-00000350 e1 5a 4b 69 80 2d 2a 37 4c fd 72 a9 c3 8e 2a 1f |.ZKi.-*7L.r...*.|
-00000360 1a 3f 74 49 c6 49 ce 2f 02 58 3f 68 f0 f6 b5 8a |.?tI.I./.X?h....|
-00000370 16 11 8b 63 15 6a f2 91 f1 74 a8 f0 6d dc 91 0a |...c.j...t..m...|
-00000380 b4 e2 4e 10 14 1d b9 da 05 29 bf 31 30 ee 7d a5 |..N......).10.}.|
-00000390 75 4e da ff db 43 04 a7 55 4b dd 93 4c 5f 32 be |uN...C..UK..L_2.|
-000003a0 e9 23 c9 a1 23 86 16 03 03 00 04 0e 00 00 00 |.#..#..........|
+00000060 03 02 59 0b 00 02 55 00 02 52 00 02 4f 30 82 02 |..Y...U..R..O0..|
+00000070 4b 30 82 01 b4 a0 03 02 01 02 02 09 00 e8 f0 9d |K0..............|
+00000080 3f e2 5b ea a6 30 0d 06 09 2a 86 48 86 f7 0d 01 |?.[..0...*.H....|
+00000090 01 0b 05 00 30 1f 31 0b 30 09 06 03 55 04 0a 13 |....0.1.0...U...|
+000000a0 02 47 6f 31 10 30 0e 06 03 55 04 03 13 07 47 6f |.Go1.0...U....Go|
+000000b0 20 52 6f 6f 74 30 1e 17 0d 31 36 30 31 30 31 30 | Root0...1601010|
+000000c0 30 30 30 30 30 5a 17 0d 32 35 30 31 30 31 30 30 |00000Z..25010100|
+000000d0 30 30 30 30 5a 30 1a 31 0b 30 09 06 03 55 04 0a |0000Z0.1.0...U..|
+000000e0 13 02 47 6f 31 0b 30 09 06 03 55 04 03 13 02 47 |..Go1.0...U....G|
+000000f0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....|
+00000100 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 db 46 |.......0.......F|
+00000110 7d 93 2e 12 27 06 48 bc 06 28 21 ab 7e c4 b6 a2 |}...'.H..(!.~...|
+00000120 5d fe 1e 52 45 88 7a 36 47 a5 08 0d 92 42 5b c2 |]..RE.z6G....B[.|
+00000130 81 c0 be 97 79 98 40 fb 4f 6d 14 fd 2b 13 8b c2 |....y. at .Om..+...|
+00000140 a5 2e 67 d8 d4 09 9e d6 22 38 b7 4a 0b 74 73 2b |..g....."8.J.ts+|
+00000150 c2 34 f1 d1 93 e5 96 d9 74 7b f3 58 9f 6c 61 3c |.4......t{.X.la<|
+00000160 c0 b0 41 d4 d9 2b 2b 24 23 77 5b 1c 3b bd 75 5d |..A..++$#w[.;.u]|
+00000170 ce 20 54 cf a1 63 87 1d 1e 24 c4 f3 1d 1a 50 8b |. T..c...$....P.|
+00000180 aa b6 14 43 ed 97 a7 75 62 f4 14 c8 52 d7 02 03 |...C...ub...R...|
+00000190 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..|
+000001a0 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%|
+000001b0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........|
+000001c0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...|
+000001d0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....|
+000001e0 10 9f 91 16 1f 43 43 3e 49 a6 de 6d b6 80 d7 9f |.....CC>I..m....|
+000001f0 60 30 1b 06 03 55 1d 23 04 14 30 12 80 10 48 13 |`0...U.#..0...H.|
+00000200 49 4d 13 7e 16 31 bb a3 01 d5 ac ab 6e 7b 30 19 |IM.~.1......n{0.|
+00000210 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp|
+00000220 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H|
+00000230 86 f7 0d 01 01 0b 05 00 03 81 81 00 9d 30 cc 40 |.............0.@|
+00000240 2b 5b 50 a0 61 cb ba e5 53 58 e1 ed 83 28 a9 58 |+[P.a...SX...(.X|
+00000250 1a a9 38 a4 95 a1 ac 31 5a 1a 84 66 3d 43 d3 2d |..8....1Z..f=C.-|
+00000260 d9 0b f2 97 df d3 20 64 38 92 24 3a 00 bc cf 9c |...... d8.$:....|
+00000270 7d b7 40 20 01 5f aa d3 16 61 09 a2 76 fd 13 c3 |}.@ ._...a..v...|
+00000280 cc e1 0c 5c ee b1 87 82 f1 6c 04 ed 73 bb b3 43 |...\.....l..s..C|
+00000290 77 8d 0c 1c f1 0f a1 d8 40 83 61 c9 4c 72 2b 9d |w....... at .a.Lr+.|
+000002a0 ae db 46 06 06 4d f4 c1 b3 3e c0 d1 bd 42 d4 db |..F..M...>...B..|
+000002b0 fe 3d 13 60 84 5c 21 d3 3b e9 fa e7 16 03 03 00 |.=.`.\!.;.......|
+000002c0 ac 0c 00 00 a8 03 00 1d 20 f5 fd 54 ea 3e bb 70 |........ ..T.>.p|
+000002d0 fb 8e fb e4 8a 25 1f 9d 3d 9a fb fb 9d ff d1 52 |.....%..=......R|
+000002e0 81 9d b0 ea a1 e6 b0 87 2f 04 01 00 80 77 54 16 |......../....wT.|
+000002f0 98 5d 22 c4 7f 9b 2a 44 dd e4 0d 78 c2 60 6a ad |.]"...*D...x.`j.|
+00000300 91 9d d9 ed 93 0b 4e b4 c6 26 f1 94 6d e0 cc f4 |......N..&..m...|
+00000310 8d fa 9c ec 70 f5 5b ac 80 d7 5e 4f 49 04 bc 24 |....p.[...^OI..$|
+00000320 8e 0a 7d 44 e1 7e 47 1e a8 68 d1 fe 6f 41 0d 4a |..}D.~G..h..oA.J|
+00000330 e5 5b f6 f6 a3 af 76 21 56 1a 25 d2 03 3c f4 dd |.[....v!V.%..<..|
+00000340 0c 13 ce 56 8a 61 6f 5b 8c a1 04 43 82 87 64 20 |...V.ao[...C..d |
+00000350 4a 3b ec 90 d7 59 aa ca 08 3a 39 57 f1 56 57 6a |J;...Y...:9W.VWj|
+00000360 18 c9 14 7f e3 8d 83 0f e2 0b 4d 24 01 16 03 03 |..........M$....|
+00000370 00 04 0e 00 00 00 |......|
>>> Flow 3 (client to server)
-00000000 16 03 03 00 46 10 00 00 42 41 04 1e 18 37 ef 0d |....F...BA...7..|
-00000010 19 51 88 35 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd |.Q.5uq..T[....g.|
-00000020 a7 24 20 3e b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e |.$ >.V...(^.+-O.|
-00000030 f1 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 |...lK[.V.2B.X..I|
-00000040 a6 b5 68 1a 41 03 56 6b dc 5a 89 14 03 03 00 01 |..h.A.Vk.Z......|
-00000050 01 16 03 03 00 28 00 00 00 00 00 00 00 00 d4 cb |.....(..........|
-00000060 e2 c0 1e fe cb b0 d6 fe da 7c 8f 8c b2 2f f7 c1 |.........|.../..|
-00000070 3d e9 52 6e 70 c1 13 13 87 ff 12 85 6c 2c |=.Rnp.......l,|
+00000000 16 03 03 00 25 10 00 00 21 20 2f e5 7d a3 47 cd |....%...! /.}.G.|
+00000010 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af c4 |bC.(.._.).0.....|
+00000020 cf c2 ed 90 99 5f 58 cb 3b 74 14 03 03 00 01 01 |....._X.;t......|
+00000030 16 03 03 00 20 6b ce 5c 2f df 85 e7 5e fa 51 48 |.... k.\/...^.QH|
+00000040 f9 31 a5 02 64 c7 1e b1 2e f2 6b 86 30 43 23 91 |.1..d.....k.0C#.|
+00000050 76 6b 40 74 2b |vk at t+|
>>> Flow 4 (server to client)
-00000000 14 03 03 00 01 01 16 03 03 00 28 0a 86 ff b2 73 |..........(....s|
-00000010 35 40 a1 89 9f 21 1f 0b 2f 79 50 70 eb 74 e1 2f |5 at ...!../yPp.t./|
-00000020 4d bc 5c 3c 85 0b 60 cc 73 36 e4 08 01 0a 4c 75 |M.\<..`.s6....Lu|
-00000030 0f a2 9c |...|
+00000000 14 03 03 00 01 01 16 03 03 00 20 e7 1e 88 10 2d |.......... ....-|
+00000010 dc 35 6d 2b 4a 91 39 5d 5c 46 ed 2e 45 6f 41 38 |.5m+J.9]\F..EoA8|
+00000020 66 0f 15 58 f8 af d8 a6 6c 99 61 |f..X....l.a|
>>> Flow 5 (client to server)
-00000000 17 03 03 00 1e 00 00 00 00 00 00 00 01 c9 78 b7 |..............x.|
-00000010 07 d1 a9 95 fc b4 aa 57 16 77 86 fb c7 a9 c6 12 |.......W.w......|
-00000020 bc bd 09 |...|
+00000000 17 03 03 00 16 ab 2a df 2f 3c 07 6a 24 98 55 0b |......*./<.j$.U.|
+00000010 67 20 2d 92 cd 9a 44 74 da fd 6a |g -...Dt..j|
>>> Flow 6 (server to client)
-00000000 16 03 03 00 1c 0a 86 ff b2 73 35 40 a2 4d b1 9b |.........s5 at .M..|
-00000010 eb 51 76 71 6b b8 88 fe 21 60 bb 8b 2a cc e3 3e |.Qvqk...!`..*..>|
-00000020 d5 |.|
+00000000 16 03 03 00 14 d6 fb e7 9a 76 2a 6f e1 e9 33 1a |.........v*o..3.|
+00000010 77 07 fd 7f 98 af 1e 04 43 |w.......C|
>>> Flow 7 (client to server)
-00000000 15 03 03 00 1a 00 00 00 00 00 00 00 02 0e da c6 |................|
-00000010 01 09 cc 0f bb 7d de c9 41 8d 30 b5 d5 b7 f2 15 |.....}..A.0.....|
-00000020 03 03 00 1a 00 00 00 00 00 00 00 03 a7 0e 24 98 |..............$.|
-00000030 32 62 1b a9 98 17 b6 b3 71 af 88 7a a3 6b |2b......q..z.k|
+00000000 15 03 03 00 12 7e e3 20 96 03 31 8c 6a 31 f8 62 |.....~. ..1.j1.b|
+00000010 02 a7 a4 ce 77 83 c1 15 03 03 00 12 b9 91 75 45 |....w.........uE|
+00000020 a5 4a f9 c6 6d b2 5c c3 0a 1a 26 63 00 04 |.J..m.\...&c..|
diff --git a/src/crypto/tls/testdata/Client-TLSv12-SCT b/src/crypto/tls/testdata/Client-TLSv12-SCT
index e6187ba..a0f6a09 100644
--- a/src/crypto/tls/testdata/Client-TLSv12-SCT
+++ b/src/crypto/tls/testdata/Client-TLSv12-SCT
@@ -1,19 +1,20 @@
>>> Flow 1 (client to server)
-00000000 16 03 01 00 85 01 00 00 81 03 03 00 00 00 00 00 |................|
+00000000 16 03 01 00 91 01 00 00 8d 03 03 00 00 00 00 00 |................|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
-00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 22 c0 2f |............."./|
-00000030 c0 2b c0 30 c0 2c c0 11 c0 07 c0 13 c0 09 c0 14 |.+.0.,..........|
-00000040 c0 0a 00 9c 00 9d 00 05 00 2f 00 35 c0 12 00 0a |........./.5....|
-00000050 01 00 00 36 00 05 00 05 01 00 00 00 00 00 0a 00 |...6............|
-00000060 08 00 06 00 17 00 18 00 19 00 0b 00 02 01 00 00 |................|
-00000070 0d 00 0e 00 0c 04 01 04 03 05 01 05 03 02 01 02 |................|
-00000080 03 ff 01 00 01 00 00 12 00 00 |..........|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2c cc a8 |.............,..|
+00000030 cc a9 c0 2f c0 2b c0 30 c0 2c c0 27 c0 13 c0 23 |.../.+.0.,.'...#|
+00000040 c0 09 c0 14 c0 0a 00 9c 00 9d 00 3c 00 2f 00 35 |...........<./.5|
+00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 38 00 05 |.............8..|
+00000060 00 05 01 00 00 00 00 00 0a 00 0a 00 08 00 1d 00 |................|
+00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 0e 00 |................|
+00000080 0c 04 01 04 03 05 01 05 03 02 01 02 03 ff 01 00 |................|
+00000090 01 00 00 12 00 00 |......|
>>> Flow 2 (server to client)
-00000000 16 03 03 01 c6 02 00 01 c2 03 03 5d d8 84 38 51 |...........]..8Q|
-00000010 c6 51 9e 6c d3 e0 b2 d7 81 2a 9b 1c 06 0b 11 c8 |.Q.l.....*......|
-00000020 54 90 f3 d1 66 83 7a 68 2f 65 8b 20 ac 8b 35 9a |T...f.zh/e. ..5.|
-00000030 31 25 04 c9 89 31 27 80 8f 10 74 8e 3c 4f 20 bc |1%...1'...t.<O .|
-00000040 3b 46 9d d0 91 f3 ca 7e 0e 59 b7 72 c0 2f 00 01 |;F.....~.Y.r./..|
+00000000 16 03 03 01 c6 02 00 01 c2 03 03 08 db 5c c4 da |.............\..|
+00000010 fe 2c a2 21 0d c4 9e c4 14 b9 e3 15 d7 c5 2c 84 |.,.!..........,.|
+00000020 f2 b8 0e 32 67 9e 72 08 9c 17 6b 20 86 09 60 52 |...2g.r...k ..`R|
+00000030 9d 53 ba c8 8a c3 1a 11 c0 e5 c6 a0 59 49 ed cb |.S..........YI..|
+00000040 e0 6f 0a 56 e9 4f bf 02 2f 23 10 b8 cc a8 00 01 |.o.V.O../#......|
00000050 7a ff 01 00 01 00 00 0b 00 04 03 00 01 02 00 12 |z...............|
00000060 01 69 01 67 00 75 00 a4 b9 09 90 b4 18 58 14 87 |.i.g.u.......X..|
00000070 bb 13 a2 cc 67 70 0a 3c 35 98 04 f9 1b df b8 e3 |....gp.<5.......|
@@ -37,77 +38,70 @@
00000190 91 bc f1 b5 40 be 1e 2e e7 5c b4 74 27 ed 8f 9b |.... at ....\.t'...|
000001a0 02 e9 fa c2 4c ba a2 be 02 21 00 af 43 64 52 71 |....L....!..CdRq|
000001b0 15 29 58 40 91 c7 08 16 96 03 a8 73 a5 65 a0 6c |.)X at .......s.e.l|
-000001c0 b8 48 56 5a b6 29 83 64 6d 2a 9d 16 03 03 02 71 |.HVZ.).dm*.....q|
-000001d0 0b 00 02 6d 00 02 6a 00 02 67 30 82 02 63 30 82 |...m..j..g0..c0.|
-000001e0 01 cc a0 03 02 01 02 02 09 00 a2 73 00 0c 81 00 |...........s....|
-000001f0 cb f3 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 |..0...*.H.......|
-00000200 00 30 2b 31 17 30 15 06 03 55 04 0a 13 0e 47 6f |.0+1.0...U....Go|
-00000210 6f 67 6c 65 20 54 45 53 54 49 4e 47 31 10 30 0e |ogle TESTING1.0.|
-00000220 06 03 55 04 03 13 07 47 6f 20 52 6f 6f 74 30 1e |..U....Go Root0.|
-00000230 17 0d 31 35 30 31 30 31 30 30 30 30 30 30 5a 17 |..150101000000Z.|
-00000240 0d 32 35 30 31 30 31 30 30 30 30 30 30 5a 30 26 |.250101000000Z0&|
-00000250 31 17 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c |1.0...U....Googl|
-00000260 65 20 54 45 53 54 49 4e 47 31 0b 30 09 06 03 55 |e TESTING1.0...U|
-00000270 04 03 13 02 47 6f 30 81 9f 30 0d 06 09 2a 86 48 |....Go0..0...*.H|
-00000280 86 f7 0d 01 01 01 05 00 03 81 8d 00 30 81 89 02 |............0...|
-00000290 81 81 00 af 87 88 f6 20 1b 95 65 6c 14 ab 44 05 |....... ..el..D.|
-000002a0 af 3b 45 14 e3 b7 6d fd 00 63 4d 95 7f fe 6a 62 |.;E...m..cM...jb|
-000002b0 35 86 c0 4a f9 18 7c f6 aa 25 5e 7a 64 31 66 00 |5..J..|..%^zd1f.|
-000002c0 ba f4 8e 92 af c7 6b d8 76 d4 f3 5f 41 cb 6e 56 |......k.v.._A.nV|
-000002d0 15 97 1b 97 c1 3c 12 39 21 66 3d 2b 16 d1 bc db |.....<.9!f=+....|
-000002e0 1c c0 a7 da b7 ca ad ba da cb d5 21 50 ec de 8d |...........!P...|
-000002f0 ab d1 6b 81 4b 89 02 f3 c4 be c1 6c 89 b1 44 84 |..k.K......l..D.|
-00000300 bd 21 d1 04 7d 9d 16 4d f9 82 15 f6 ef fa d6 09 |.!..}..M........|
-00000310 47 f2 fb 02 03 01 00 01 a3 81 93 30 81 90 30 0e |G..........0..0.|
-00000320 06 03 55 1d 0f 01 01 ff 04 04 03 02 05 a0 30 1d |..U...........0.|
-00000330 06 03 55 1d 25 04 16 30 14 06 08 2b 06 01 05 05 |..U.%..0...+....|
-00000340 07 03 01 06 08 2b 06 01 05 05 07 03 02 30 0c 06 |.....+.......0..|
-00000350 03 55 1d 13 01 01 ff 04 02 30 00 30 19 06 03 55 |.U.......0.0...U|
-00000360 1d 0e 04 12 04 10 12 50 8d 89 6f 1b d1 dc 54 4d |.......P..o...TM|
-00000370 6e cb 69 5e 06 f4 30 1b 06 03 55 1d 23 04 14 30 |n.i^..0...U.#..0|
-00000380 12 80 10 bf 3d b6 a9 66 f2 b8 40 cf ea b4 03 78 |....=..f.. at ....x|
-00000390 48 1a 41 30 19 06 03 55 1d 11 04 12 30 10 82 0e |H.A0...U....0...|
-000003a0 65 78 61 6d 70 6c 65 2e 67 6f 6c 61 6e 67 30 0d |example.golang0.|
-000003b0 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 03 81 81 |..*.H...........|
-000003c0 00 92 7c af 91 55 12 18 96 59 31 a6 48 40 d5 2d |..|..U...Y1.H at .-|
-000003d0 d5 ee bb 02 a0 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 |........|..0}<.v|
-000003e0 da 4f 3d c0 fa ae 2d 33 24 6b 03 7b 1b 67 59 11 |.O=...-3$k.{.gY.|
-000003f0 21 b5 11 bc 77 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f |!...w...n.-.5.d_|
-00000400 22 3e 63 10 6b be ff 14 86 6d 0d f0 15 31 a8 14 |">c.k....m...1..|
-00000410 38 1e 3b 84 87 2c cb 98 ed 51 76 b9 b1 4f dd db |8.;..,...Qv..O..|
-00000420 9b 84 04 86 40 fa 51 dd ba b4 8d eb e3 46 de 46 |.... at .Q......F.F|
-00000430 b9 4f 86 c7 f9 a4 c2 41 34 ac cc f6 ea b0 ab 39 |.O.....A4......9|
-00000440 18 16 03 03 00 cd 0c 00 00 c9 03 00 17 41 04 1e |.............A..|
-00000450 d1 1c 5c d3 00 41 84 cd f7 e2 78 ad b5 7d 5b f2 |..\..A....x..}[.|
-00000460 23 5b 1a 18 44 3f 86 8e 3e 52 f2 4b b6 7d 84 b4 |#[..D?..>R.K.}..|
-00000470 1d 98 83 8f 2f 58 07 92 1f 58 2a 8d 8c e3 fa b7 |..../X...X*.....|
-00000480 aa 78 7e 33 9a 64 b9 b6 cb 78 94 be 2b c3 ac 04 |.x~3.d...x..+...|
-00000490 01 00 80 65 9f 42 e3 24 5c cd 18 aa 08 8e 6b bf |...e.B.$\.....k.|
-000004a0 39 15 2a a3 e6 42 1c 9d 6b 34 39 a2 2c 58 f5 5f |9.*..B..k49.,X._|
-000004b0 3e fb 2a 4c 01 2b e5 20 4e f5 69 77 c1 62 8f 68 |>.*L.+. N.iw.b.h|
-000004c0 be b4 c4 77 27 c9 4a 97 6d 18 7f 45 fd c9 9e 24 |...w'.J.m..E...$|
-000004d0 19 6b d9 00 c5 52 1a 34 a3 c9 cb eb 92 fc f6 48 |.k...R.4.......H|
-000004e0 3d 89 8a ff 82 be 55 c9 92 e2 24 86 b0 99 c6 e8 |=.....U...$.....|
-000004f0 a5 4c b7 bc 5a e5 f3 81 94 ee 15 47 e7 5e 8c 66 |.L..Z......G.^.f|
-00000500 32 72 7d 81 78 61 fe 25 98 dd 07 a2 92 4c eb ed |2r}.xa.%.....L..|
-00000510 f1 a7 17 16 03 03 00 04 0e 00 00 00 |............|
+000001c0 b8 48 56 5a b6 29 83 64 6d 2a 9d 16 03 03 02 59 |.HVZ.).dm*.....Y|
+000001d0 0b 00 02 55 00 02 52 00 02 4f 30 82 02 4b 30 82 |...U..R..O0..K0.|
+000001e0 01 b4 a0 03 02 01 02 02 09 00 e8 f0 9d 3f e2 5b |.............?.[|
+000001f0 ea a6 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 |..0...*.H.......|
+00000200 00 30 1f 31 0b 30 09 06 03 55 04 0a 13 02 47 6f |.0.1.0...U....Go|
+00000210 31 10 30 0e 06 03 55 04 03 13 07 47 6f 20 52 6f |1.0...U....Go Ro|
+00000220 6f 74 30 1e 17 0d 31 36 30 31 30 31 30 30 30 30 |ot0...1601010000|
+00000230 30 30 5a 17 0d 32 35 30 31 30 31 30 30 30 30 30 |00Z..25010100000|
+00000240 30 5a 30 1a 31 0b 30 09 06 03 55 04 0a 13 02 47 |0Z0.1.0...U....G|
+00000250 6f 31 0b 30 09 06 03 55 04 03 13 02 47 6f 30 81 |o1.0...U....Go0.|
+00000260 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 01 05 00 |.0...*.H........|
+00000270 03 81 8d 00 30 81 89 02 81 81 00 db 46 7d 93 2e |....0.......F}..|
+00000280 12 27 06 48 bc 06 28 21 ab 7e c4 b6 a2 5d fe 1e |.'.H..(!.~...]..|
+00000290 52 45 88 7a 36 47 a5 08 0d 92 42 5b c2 81 c0 be |RE.z6G....B[....|
+000002a0 97 79 98 40 fb 4f 6d 14 fd 2b 13 8b c2 a5 2e 67 |.y. at .Om..+.....g|
+000002b0 d8 d4 09 9e d6 22 38 b7 4a 0b 74 73 2b c2 34 f1 |....."8.J.ts+.4.|
+000002c0 d1 93 e5 96 d9 74 7b f3 58 9f 6c 61 3c c0 b0 41 |.....t{.X.la<..A|
+000002d0 d4 d9 2b 2b 24 23 77 5b 1c 3b bd 75 5d ce 20 54 |..++$#w[.;.u]. T|
+000002e0 cf a1 63 87 1d 1e 24 c4 f3 1d 1a 50 8b aa b6 14 |..c...$....P....|
+000002f0 43 ed 97 a7 75 62 f4 14 c8 52 d7 02 03 01 00 01 |C...ub...R......|
+00000300 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f 01 01 ff |...0..0...U.....|
+00000310 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 04 16 30 |......0...U.%..0|
+00000320 14 06 08 2b 06 01 05 05 07 03 01 06 08 2b 06 01 |...+.........+..|
+00000330 05 05 07 03 02 30 0c 06 03 55 1d 13 01 01 ff 04 |.....0...U......|
+00000340 02 30 00 30 19 06 03 55 1d 0e 04 12 04 10 9f 91 |.0.0...U........|
+00000350 16 1f 43 43 3e 49 a6 de 6d b6 80 d7 9f 60 30 1b |..CC>I..m....`0.|
+00000360 06 03 55 1d 23 04 14 30 12 80 10 48 13 49 4d 13 |..U.#..0...H.IM.|
+00000370 7e 16 31 bb a3 01 d5 ac ab 6e 7b 30 19 06 03 55 |~.1......n{0...U|
+00000380 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 6c 65 2e |....0...example.|
+00000390 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 86 f7 0d |golang0...*.H...|
+000003a0 01 01 0b 05 00 03 81 81 00 9d 30 cc 40 2b 5b 50 |..........0. at +[P|
+000003b0 a0 61 cb ba e5 53 58 e1 ed 83 28 a9 58 1a a9 38 |.a...SX...(.X..8|
+000003c0 a4 95 a1 ac 31 5a 1a 84 66 3d 43 d3 2d d9 0b f2 |....1Z..f=C.-...|
+000003d0 97 df d3 20 64 38 92 24 3a 00 bc cf 9c 7d b7 40 |... d8.$:....}.@|
+000003e0 20 01 5f aa d3 16 61 09 a2 76 fd 13 c3 cc e1 0c | ._...a..v......|
+000003f0 5c ee b1 87 82 f1 6c 04 ed 73 bb b3 43 77 8d 0c |\.....l..s..Cw..|
+00000400 1c f1 0f a1 d8 40 83 61 c9 4c 72 2b 9d ae db 46 |..... at .a.Lr+...F|
+00000410 06 06 4d f4 c1 b3 3e c0 d1 bd 42 d4 db fe 3d 13 |..M...>...B...=.|
+00000420 60 84 5c 21 d3 3b e9 fa e7 16 03 03 00 ac 0c 00 |`.\!.;..........|
+00000430 00 a8 03 00 1d 20 27 94 d8 62 00 f3 3f 21 e6 e1 |..... '..b..?!..|
+00000440 0f 1f 2d 9b 37 4d cf 72 34 48 72 2e 85 46 dd b6 |..-.7M.r4Hr..F..|
+00000450 32 23 64 b3 4b 63 04 01 00 80 82 34 e5 7f 70 51 |2#d.Kc.....4..pQ|
+00000460 42 3b ab 51 61 73 1f 2c 64 04 1d 66 96 ff f9 95 |B;.Qas.,d..f....|
+00000470 86 09 a8 75 11 16 34 05 17 fb 96 9c fb 78 40 4c |...u..4......x at L|
+00000480 10 5b ee 0d 31 a0 77 32 a8 0f 19 ef a4 30 cd 08 |.[..1.w2.....0..|
+00000490 cb f5 ec 36 fa 24 0a ca 0b d8 16 02 d1 34 86 a7 |...6.$.......4..|
+000004a0 f8 e3 cb e6 62 1c cd 40 d6 4f 0c 2f 5b 66 12 6f |....b.. at .O./[f.o|
+000004b0 8a 2f c4 ef ac 46 86 44 90 e0 65 38 94 4d 5e df |./...F.D..e8.M^.|
+000004c0 51 a3 40 6e 64 b6 00 6b 88 97 7b 43 78 d9 df 70 |Q. at nd..k..{Cx..p|
+000004d0 fe 66 66 56 82 14 ed ab 08 cd 16 03 03 00 04 0e |.ffV............|
+000004e0 00 00 00 |...|
>>> Flow 3 (client to server)
-00000000 16 03 03 00 46 10 00 00 42 41 04 1e 18 37 ef 0d |....F...BA...7..|
-00000010 19 51 88 35 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd |.Q.5uq..T[....g.|
-00000020 a7 24 20 3e b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e |.$ >.V...(^.+-O.|
-00000030 f1 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 |...lK[.V.2B.X..I|
-00000040 a6 b5 68 1a 41 03 56 6b dc 5a 89 14 03 03 00 01 |..h.A.Vk.Z......|
-00000050 01 16 03 03 00 28 00 00 00 00 00 00 00 00 f0 4f |.....(.........O|
-00000060 fe 22 53 9e e1 61 f4 45 4e 41 ff 5e e4 63 25 f7 |."S..a.ENA.^.c%.|
-00000070 b2 f6 0a ea 89 75 7f d4 e7 3a cc e8 c2 2c |.....u...:...,|
+00000000 16 03 03 00 25 10 00 00 21 20 2f e5 7d a3 47 cd |....%...! /.}.G.|
+00000010 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af c4 |bC.(.._.).0.....|
+00000020 cf c2 ed 90 99 5f 58 cb 3b 74 14 03 03 00 01 01 |....._X.;t......|
+00000030 16 03 03 00 20 7a 58 e1 33 d4 ce ca 57 ef ea b9 |.... zX.3...W...|
+00000040 9d f2 4d ec ce 86 4b e9 c2 b5 64 dd 0f 32 f0 66 |..M...K...d..2.f|
+00000050 65 42 74 d8 59 |eBt.Y|
>>> Flow 4 (server to client)
-00000000 14 03 03 00 01 01 16 03 03 00 28 ad 49 0a 66 16 |..........(.I.f.|
-00000010 6d 64 42 c2 ab 38 bf 81 3d d9 14 13 d6 69 27 81 |mdB..8..=....i'.|
-00000020 ea 5c 53 fd 6c bf 81 6c 06 81 a5 67 f2 cd ed a3 |.\S.l..l...g....|
-00000030 d4 c2 08 |...|
+00000000 14 03 03 00 01 01 16 03 03 00 20 27 df 9b 14 a1 |.......... '....|
+00000010 cd a5 83 5b 6b 30 60 a3 ae 8d 64 56 fe 8e 87 a2 |...[k0`...dV....|
+00000020 ff 1b 54 72 c8 7c b2 85 9d 8a de |..Tr.|.....|
>>> Flow 5 (client to server)
-00000000 17 03 03 00 1e 00 00 00 00 00 00 00 01 5c ab e3 |.............\..|
-00000010 f9 61 72 9e 44 46 1a 05 e9 00 eb 5b e0 73 22 03 |.ar.DF.....[.s".|
-00000020 9f 90 f9 15 03 03 00 1a 00 00 00 00 00 00 00 02 |................|
-00000030 04 28 a4 9d 07 79 95 40 0f f0 eb b9 5d 97 bf 87 |.(...y. at ....]...|
-00000040 4a b6 |J.|
+00000000 17 03 03 00 16 c7 bf a9 7a 72 07 27 88 9a ec 1b |........zr.'....|
+00000010 d3 44 f2 20 88 e4 c2 8b 61 86 5c 15 03 03 00 12 |.D. ....a.\.....|
+00000020 35 ab f5 f6 92 f9 db 23 bf f1 8e e8 65 62 cf 48 |5......#....eb.H|
+00000030 91 9d |..|
diff --git a/src/crypto/tls/testdata/Client-TLSv12-X25519-ECDHE-RSA-AES-GCM b/src/crypto/tls/testdata/Client-TLSv12-X25519-ECDHE-RSA-AES-GCM
new file mode 100644
index 0000000..90541fd
--- /dev/null
+++ b/src/crypto/tls/testdata/Client-TLSv12-X25519-ECDHE-RSA-AES-GCM
@@ -0,0 +1,85 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 8b 01 00 00 87 03 03 00 00 00 00 00 |................|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2c cc a8 |.............,..|
+00000030 cc a9 c0 2f c0 2b c0 30 c0 2c c0 27 c0 13 c0 23 |.../.+.0.,.'...#|
+00000040 c0 09 c0 14 c0 0a 00 9c 00 9d 00 3c 00 2f 00 35 |...........<./.5|
+00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 32 00 05 |.............2..|
+00000060 00 05 01 00 00 00 00 00 0a 00 04 00 02 00 1d 00 |................|
+00000070 0b 00 02 01 00 00 0d 00 0e 00 0c 04 01 04 03 05 |................|
+00000080 01 05 03 02 01 02 03 ff 01 00 01 00 00 12 00 00 |................|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 59 02 00 00 55 03 03 07 42 b0 44 05 |....Y...U...B.D.|
+00000010 b1 6d 3c f0 60 fe 6a f2 1f 8f 1d 88 de 4b 6a 1b |.m<.`.j......Kj.|
+00000020 4f 72 60 4d 42 a5 f7 77 eb 86 c2 20 99 35 47 07 |Or`MB..w... .5G.|
+00000030 64 60 32 52 2e 1d 54 d5 b7 e2 26 85 72 c1 ec 8d |d`2R..T...&.r...|
+00000040 fb 59 86 91 46 7d ad 16 bd b7 38 94 c0 2f 00 00 |.Y..F}....8../..|
+00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................|
+00000060 03 02 59 0b 00 02 55 00 02 52 00 02 4f 30 82 02 |..Y...U..R..O0..|
+00000070 4b 30 82 01 b4 a0 03 02 01 02 02 09 00 e8 f0 9d |K0..............|
+00000080 3f e2 5b ea a6 30 0d 06 09 2a 86 48 86 f7 0d 01 |?.[..0...*.H....|
+00000090 01 0b 05 00 30 1f 31 0b 30 09 06 03 55 04 0a 13 |....0.1.0...U...|
+000000a0 02 47 6f 31 10 30 0e 06 03 55 04 03 13 07 47 6f |.Go1.0...U....Go|
+000000b0 20 52 6f 6f 74 30 1e 17 0d 31 36 30 31 30 31 30 | Root0...1601010|
+000000c0 30 30 30 30 30 5a 17 0d 32 35 30 31 30 31 30 30 |00000Z..25010100|
+000000d0 30 30 30 30 5a 30 1a 31 0b 30 09 06 03 55 04 0a |0000Z0.1.0...U..|
+000000e0 13 02 47 6f 31 0b 30 09 06 03 55 04 03 13 02 47 |..Go1.0...U....G|
+000000f0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....|
+00000100 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 db 46 |.......0.......F|
+00000110 7d 93 2e 12 27 06 48 bc 06 28 21 ab 7e c4 b6 a2 |}...'.H..(!.~...|
+00000120 5d fe 1e 52 45 88 7a 36 47 a5 08 0d 92 42 5b c2 |]..RE.z6G....B[.|
+00000130 81 c0 be 97 79 98 40 fb 4f 6d 14 fd 2b 13 8b c2 |....y. at .Om..+...|
+00000140 a5 2e 67 d8 d4 09 9e d6 22 38 b7 4a 0b 74 73 2b |..g....."8.J.ts+|
+00000150 c2 34 f1 d1 93 e5 96 d9 74 7b f3 58 9f 6c 61 3c |.4......t{.X.la<|
+00000160 c0 b0 41 d4 d9 2b 2b 24 23 77 5b 1c 3b bd 75 5d |..A..++$#w[.;.u]|
+00000170 ce 20 54 cf a1 63 87 1d 1e 24 c4 f3 1d 1a 50 8b |. T..c...$....P.|
+00000180 aa b6 14 43 ed 97 a7 75 62 f4 14 c8 52 d7 02 03 |...C...ub...R...|
+00000190 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..|
+000001a0 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%|
+000001b0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........|
+000001c0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...|
+000001d0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....|
+000001e0 10 9f 91 16 1f 43 43 3e 49 a6 de 6d b6 80 d7 9f |.....CC>I..m....|
+000001f0 60 30 1b 06 03 55 1d 23 04 14 30 12 80 10 48 13 |`0...U.#..0...H.|
+00000200 49 4d 13 7e 16 31 bb a3 01 d5 ac ab 6e 7b 30 19 |IM.~.1......n{0.|
+00000210 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp|
+00000220 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H|
+00000230 86 f7 0d 01 01 0b 05 00 03 81 81 00 9d 30 cc 40 |.............0.@|
+00000240 2b 5b 50 a0 61 cb ba e5 53 58 e1 ed 83 28 a9 58 |+[P.a...SX...(.X|
+00000250 1a a9 38 a4 95 a1 ac 31 5a 1a 84 66 3d 43 d3 2d |..8....1Z..f=C.-|
+00000260 d9 0b f2 97 df d3 20 64 38 92 24 3a 00 bc cf 9c |...... d8.$:....|
+00000270 7d b7 40 20 01 5f aa d3 16 61 09 a2 76 fd 13 c3 |}.@ ._...a..v...|
+00000280 cc e1 0c 5c ee b1 87 82 f1 6c 04 ed 73 bb b3 43 |...\.....l..s..C|
+00000290 77 8d 0c 1c f1 0f a1 d8 40 83 61 c9 4c 72 2b 9d |w....... at .a.Lr+.|
+000002a0 ae db 46 06 06 4d f4 c1 b3 3e c0 d1 bd 42 d4 db |..F..M...>...B..|
+000002b0 fe 3d 13 60 84 5c 21 d3 3b e9 fa e7 16 03 03 00 |.=.`.\!.;.......|
+000002c0 ac 0c 00 00 a8 03 00 1d 20 cc f6 2e 98 6c e0 8b |........ ....l..|
+000002d0 15 17 63 6f 97 5e 37 6a a7 3c 4b f2 d4 91 e0 87 |..co.^7j.<K.....|
+000002e0 53 1d d3 9e f3 43 a9 21 40 04 01 00 80 3c 35 db |S....C.!@....<5.|
+000002f0 b1 ef 58 96 b4 3f eb 6b d5 0d b7 ab cd 51 8d 57 |..X..?.k.....Q.W|
+00000300 2b fe 3a 7f 72 42 a0 a7 7d 1d db c1 6c cd df de |+.:.rB..}...l...|
+00000310 7f 98 69 b0 0b c1 56 07 34 51 79 dc 1a 52 d1 11 |..i...V.4Qy..R..|
+00000320 ea b4 dd 0f 9d 9a 8c a3 4f 23 da 0e aa dc 2a e1 |........O#....*.|
+00000330 16 51 a4 33 e2 4f f8 34 2d b0 ba f5 f5 ed 3e 24 |.Q.3.O.4-.....>$|
+00000340 04 f0 b9 ab 81 b8 4e 39 88 8f b7 46 2c 60 b8 5c |......N9...F,`.\|
+00000350 6f 4d d4 5d 7a 04 f7 1d 82 98 a2 b1 f9 7e f0 1f |oM.]z........~..|
+00000360 cf a5 e5 28 25 d4 3d b0 32 ea eb 21 c6 16 03 03 |...(%.=.2..!....|
+00000370 00 04 0e 00 00 00 |......|
+>>> Flow 3 (client to server)
+00000000 16 03 03 00 25 10 00 00 21 20 2f e5 7d a3 47 cd |....%...! /.}.G.|
+00000010 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af c4 |bC.(.._.).0.....|
+00000020 cf c2 ed 90 99 5f 58 cb 3b 74 14 03 03 00 01 01 |....._X.;t......|
+00000030 16 03 03 00 28 00 00 00 00 00 00 00 00 75 70 c8 |....(........up.|
+00000040 c5 ef ae 60 b5 8d ba 98 1a 7d 8d c3 e4 32 fc 33 |...`.....}...2.3|
+00000050 5e 15 cc e2 d7 5d d5 76 52 1a fe ac 1e |^....].vR....|
+>>> Flow 4 (server to client)
+00000000 14 03 03 00 01 01 16 03 03 00 28 7f 2b fe 0d 9f |..........(.+...|
+00000010 93 07 fd ee 48 76 09 fb 8d 4c dd 7b b5 b5 26 36 |....Hv...L.{..&6|
+00000020 3e 05 e1 1b a7 dc 0b 4a c0 69 a8 22 33 0b 17 fc |>......J.i."3...|
+00000030 6f ab b8 |o..|
+>>> Flow 5 (client to server)
+00000000 17 03 03 00 1e 00 00 00 00 00 00 00 01 49 61 5c |.............Ia\|
+00000010 db f2 e5 63 23 3a f1 dd 12 3e 61 ed d9 4b 5f b5 |...c#:...>a..K_.|
+00000020 d3 f7 38 15 03 03 00 1a 00 00 00 00 00 00 00 02 |..8.............|
+00000030 af 09 a7 f1 e1 d9 1f 54 d1 35 19 16 b7 23 ce 4e |.......T.5...#.N|
+00000040 3a b1 |:.|
diff --git a/src/crypto/tls/testdata/Server-SSLv3-RSA-3DES b/src/crypto/tls/testdata/Server-SSLv3-RSA-3DES
index 10b7f52..11a8a1c 100644
--- a/src/crypto/tls/testdata/Server-SSLv3-RSA-3DES
+++ b/src/crypto/tls/testdata/Server-SSLv3-RSA-3DES
@@ -1,78 +1,76 @@
>>> Flow 1 (client to server)
-00000000 16 03 00 00 30 01 00 00 2c 03 00 50 32 2f f9 d5 |....0...,..P2/..|
-00000010 8f 83 ac 79 0e 0b e5 65 2c 87 79 01 7d 15 73 00 |...y...e,.y.}.s.|
-00000020 46 7c dc c6 6d 70 0b f3 d2 dc de 00 00 04 00 0a |F|..mp..........|
-00000030 00 ff 02 01 00 |.....|
+00000000 16 03 00 00 2f 01 00 00 2b 03 00 47 b4 bd 36 64 |..../...+..G..6d|
+00000010 0a 7d 37 1d 99 ac fd 1c 7a 3f d5 0f 9d 90 e3 59 |.}7.....z?.....Y|
+00000020 64 e4 fb 59 3a 4a 5f 53 d2 af 88 00 00 04 00 0a |d..Y:J_S........|
+00000030 00 ff 01 00 |....|
>>> Flow 2 (server to client)
00000000 16 03 00 00 31 02 00 00 2d 03 00 00 00 00 00 00 |....1...-.......|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 0a 00 00 |................|
-00000030 05 ff 01 00 01 00 16 03 00 02 71 0b 00 02 6d 00 |..........q...m.|
-00000040 02 6a 00 02 67 30 82 02 63 30 82 01 cc a0 03 02 |.j..g0..c0......|
-00000050 01 02 02 09 00 a2 73 00 0c 81 00 cb f3 30 0d 06 |......s......0..|
-00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 2b 31 17 |.*.H........0+1.|
-00000070 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 |0...U....Google |
-00000080 54 45 53 54 49 4e 47 31 10 30 0e 06 03 55 04 03 |TESTING1.0...U..|
-00000090 13 07 47 6f 20 52 6f 6f 74 30 1e 17 0d 31 35 30 |..Go Root0...150|
-000000a0 31 30 31 30 30 30 30 30 30 5a 17 0d 32 35 30 31 |101000000Z..2501|
-000000b0 30 31 30 30 30 30 30 30 5a 30 26 31 17 30 15 06 |01000000Z0&1.0..|
-000000c0 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 54 45 53 |.U....Google TES|
-000000d0 54 49 4e 47 31 0b 30 09 06 03 55 04 03 13 02 47 |TING1.0...U....G|
-000000e0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....|
-000000f0 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 af 87 |.......0........|
-00000100 88 f6 20 1b 95 65 6c 14 ab 44 05 af 3b 45 14 e3 |.. ..el..D..;E..|
-00000110 b7 6d fd 00 63 4d 95 7f fe 6a 62 35 86 c0 4a f9 |.m..cM...jb5..J.|
-00000120 18 7c f6 aa 25 5e 7a 64 31 66 00 ba f4 8e 92 af |.|..%^zd1f......|
-00000130 c7 6b d8 76 d4 f3 5f 41 cb 6e 56 15 97 1b 97 c1 |.k.v.._A.nV.....|
-00000140 3c 12 39 21 66 3d 2b 16 d1 bc db 1c c0 a7 da b7 |<.9!f=+.........|
-00000150 ca ad ba da cb d5 21 50 ec de 8d ab d1 6b 81 4b |......!P.....k.K|
-00000160 89 02 f3 c4 be c1 6c 89 b1 44 84 bd 21 d1 04 7d |......l..D..!..}|
-00000170 9d 16 4d f9 82 15 f6 ef fa d6 09 47 f2 fb 02 03 |..M........G....|
-00000180 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..|
-00000190 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%|
-000001a0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........|
-000001b0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...|
-000001c0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....|
-000001d0 10 12 50 8d 89 6f 1b d1 dc 54 4d 6e cb 69 5e 06 |..P..o...TMn.i^.|
-000001e0 f4 30 1b 06 03 55 1d 23 04 14 30 12 80 10 bf 3d |.0...U.#..0....=|
-000001f0 b6 a9 66 f2 b8 40 cf ea b4 03 78 48 1a 41 30 19 |..f.. at ....xH.A0.|
-00000200 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp|
-00000210 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H|
-00000220 86 f7 0d 01 01 0b 05 00 03 81 81 00 92 7c af 91 |.............|..|
-00000230 55 12 18 96 59 31 a6 48 40 d5 2d d5 ee bb 02 a0 |U...Y1.H at .-.....|
-00000240 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 da 4f 3d c0 fa |...|..0}<.v.O=..|
-00000250 ae 2d 33 24 6b 03 7b 1b 67 59 11 21 b5 11 bc 77 |.-3$k.{.gY.!...w|
-00000260 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f 22 3e 63 10 6b |...n.-.5.d_">c.k|
-00000270 be ff 14 86 6d 0d f0 15 31 a8 14 38 1e 3b 84 87 |....m...1..8.;..|
-00000280 2c cb 98 ed 51 76 b9 b1 4f dd db 9b 84 04 86 40 |,...Qv..O......@|
-00000290 fa 51 dd ba b4 8d eb e3 46 de 46 b9 4f 86 c7 f9 |.Q......F.F.O...|
-000002a0 a4 c2 41 34 ac cc f6 ea b0 ab 39 18 16 03 00 00 |..A4......9.....|
-000002b0 04 0e 00 00 00 |.....|
+00000030 05 ff 01 00 01 00 16 03 00 02 59 0b 00 02 55 00 |..........Y...U.|
+00000040 02 52 00 02 4f 30 82 02 4b 30 82 01 b4 a0 03 02 |.R..O0..K0......|
+00000050 01 02 02 09 00 e8 f0 9d 3f e2 5b ea a6 30 0d 06 |........?.[..0..|
+00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 1f 31 0b |.*.H........0.1.|
+00000070 30 09 06 03 55 04 0a 13 02 47 6f 31 10 30 0e 06 |0...U....Go1.0..|
+00000080 03 55 04 03 13 07 47 6f 20 52 6f 6f 74 30 1e 17 |.U....Go Root0..|
+00000090 0d 31 36 30 31 30 31 30 30 30 30 30 30 5a 17 0d |.160101000000Z..|
+000000a0 32 35 30 31 30 31 30 30 30 30 30 30 5a 30 1a 31 |250101000000Z0.1|
+000000b0 0b 30 09 06 03 55 04 0a 13 02 47 6f 31 0b 30 09 |.0...U....Go1.0.|
+000000c0 06 03 55 04 03 13 02 47 6f 30 81 9f 30 0d 06 09 |..U....Go0..0...|
+000000d0 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 30 |*.H............0|
+000000e0 81 89 02 81 81 00 db 46 7d 93 2e 12 27 06 48 bc |.......F}...'.H.|
+000000f0 06 28 21 ab 7e c4 b6 a2 5d fe 1e 52 45 88 7a 36 |.(!.~...]..RE.z6|
+00000100 47 a5 08 0d 92 42 5b c2 81 c0 be 97 79 98 40 fb |G....B[.....y. at .|
+00000110 4f 6d 14 fd 2b 13 8b c2 a5 2e 67 d8 d4 09 9e d6 |Om..+.....g.....|
+00000120 22 38 b7 4a 0b 74 73 2b c2 34 f1 d1 93 e5 96 d9 |"8.J.ts+.4......|
+00000130 74 7b f3 58 9f 6c 61 3c c0 b0 41 d4 d9 2b 2b 24 |t{.X.la<..A..++$|
+00000140 23 77 5b 1c 3b bd 75 5d ce 20 54 cf a1 63 87 1d |#w[.;.u]. T..c..|
+00000150 1e 24 c4 f3 1d 1a 50 8b aa b6 14 43 ed 97 a7 75 |.$....P....C...u|
+00000160 62 f4 14 c8 52 d7 02 03 01 00 01 a3 81 93 30 81 |b...R.........0.|
+00000170 90 30 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 05 |.0...U..........|
+00000180 a0 30 1d 06 03 55 1d 25 04 16 30 14 06 08 2b 06 |.0...U.%..0...+.|
+00000190 01 05 05 07 03 01 06 08 2b 06 01 05 05 07 03 02 |........+.......|
+000001a0 30 0c 06 03 55 1d 13 01 01 ff 04 02 30 00 30 19 |0...U.......0.0.|
+000001b0 06 03 55 1d 0e 04 12 04 10 9f 91 16 1f 43 43 3e |..U..........CC>|
+000001c0 49 a6 de 6d b6 80 d7 9f 60 30 1b 06 03 55 1d 23 |I..m....`0...U.#|
+000001d0 04 14 30 12 80 10 48 13 49 4d 13 7e 16 31 bb a3 |..0...H.IM.~.1..|
+000001e0 01 d5 ac ab 6e 7b 30 19 06 03 55 1d 11 04 12 30 |....n{0...U....0|
+000001f0 10 82 0e 65 78 61 6d 70 6c 65 2e 67 6f 6c 61 6e |...example.golan|
+00000200 67 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 |g0...*.H........|
+00000210 03 81 81 00 9d 30 cc 40 2b 5b 50 a0 61 cb ba e5 |.....0. at +[P.a...|
+00000220 53 58 e1 ed 83 28 a9 58 1a a9 38 a4 95 a1 ac 31 |SX...(.X..8....1|
+00000230 5a 1a 84 66 3d 43 d3 2d d9 0b f2 97 df d3 20 64 |Z..f=C.-...... d|
+00000240 38 92 24 3a 00 bc cf 9c 7d b7 40 20 01 5f aa d3 |8.$:....}.@ ._..|
+00000250 16 61 09 a2 76 fd 13 c3 cc e1 0c 5c ee b1 87 82 |.a..v......\....|
+00000260 f1 6c 04 ed 73 bb b3 43 77 8d 0c 1c f1 0f a1 d8 |.l..s..Cw.......|
+00000270 40 83 61 c9 4c 72 2b 9d ae db 46 06 06 4d f4 c1 |@.a.Lr+...F..M..|
+00000280 b3 3e c0 d1 bd 42 d4 db fe 3d 13 60 84 5c 21 d3 |.>...B...=.`.\!.|
+00000290 3b e9 fa e7 16 03 00 00 04 0e 00 00 00 |;............|
>>> Flow 3 (client to server)
-00000000 16 03 00 00 84 10 00 00 80 48 96 89 e9 d2 e6 c6 |.........H......|
-00000010 eb 9d f8 46 dd c7 d8 01 95 57 76 1a 59 1c 79 21 |...F.....Wv.Y.y!|
-00000020 94 0b 83 b2 c9 5e c1 5f 4f 12 00 10 63 12 d3 f9 |.....^._O...c...|
-00000030 ae ae 31 18 fa b4 33 37 eb b9 23 15 55 7e cf 62 |..1...37..#.U~.b|
-00000040 20 a7 cb eb 69 35 e0 35 32 e4 0a 4c c0 33 e9 7d | ...i5.52..L.3.}|
-00000050 f2 a8 4b e2 fe 90 62 7a 09 df c5 46 03 0c 52 7a |..K...bz...F..Rz|
-00000060 fb 96 dd fd 55 aa e5 be 3c 35 65 03 be e1 51 0f |....U...<5e...Q.|
-00000070 7b b3 05 6b e9 af 9b 0e e4 ea d9 34 69 a5 c2 9a |{..k.......4i...|
-00000080 71 a8 cc 0a 94 ef 91 14 88 14 03 00 00 01 01 16 |q...............|
-00000090 03 00 00 40 0c 34 26 4c cf f0 d4 a0 08 b9 b7 6b |... at .4&L.......k|
-000000a0 0a 69 55 48 91 2c 92 4c 9b e7 66 d0 b8 da 2d e7 |.iUH.,.L..f...-.|
-000000b0 89 ca f5 a4 3d 11 ff 87 22 07 c0 ed 72 9c ad 19 |....=..."...r...|
-000000c0 7d 63 2b 67 43 e3 33 76 a1 ac 69 77 55 bb 60 ba |}c+gC.3v..iwU.`.|
-000000d0 57 00 4e 2a |W.N*|
+00000000 16 03 00 00 84 10 00 00 80 43 4d 76 6b 7f b3 e6 |.........CMvk...|
+00000010 82 18 f9 8a a5 cd 45 ab 8f 1a 1d d4 9a 0a 1d 50 |......E........P|
+00000020 96 f2 08 14 a7 6b e3 ef d1 31 6b 18 d2 f5 ee e3 |.....k...1k.....|
+00000030 cd df 67 23 3d ec 70 09 07 df 32 c2 cd 60 6c 2b |..g#=.p...2..`l+|
+00000040 7f 04 cd b3 77 87 78 e5 90 60 41 0c fc 22 1a 3a |....w.x..`A..".:|
+00000050 82 29 28 92 9c f8 33 3a 72 ee 08 58 55 d5 ea 9c |.)(...3:r..XU...|
+00000060 37 96 a4 92 75 e0 29 8a 18 ad 5a c1 1f 4c aa c7 |7...u.)...Z..L..|
+00000070 49 89 6e ff 29 32 a3 c8 51 e8 50 3f 41 10 36 27 |I.n.)2..Q.P?A.6'|
+00000080 0b 60 a2 96 4b 82 a9 c6 52 14 03 00 00 01 01 16 |.`..K...R.......|
+00000090 03 00 00 40 b3 59 d0 de d1 47 8e 9e 1a 27 16 41 |... at .Y...G...'.A|
+000000a0 f7 38 4e 91 12 a0 71 89 1c 68 29 dc 60 7e 2c 39 |.8N...q..h).`~,9|
+000000b0 45 cb e6 98 8d 43 5e 76 34 ca 5b 86 24 9d 77 0a |E....C^v4.[.$.w.|
+000000c0 90 60 19 75 67 74 3d 95 1d e7 82 ee a8 9f 3a 60 |.`.ugt=.......:`|
+000000d0 8e ac 28 74 |..(t|
>>> Flow 4 (server to client)
-00000000 14 03 00 00 01 01 16 03 00 00 40 dd e1 34 c5 4a |.......... at ..4.J|
-00000010 96 76 81 49 df 1b 3d 48 cc 6c b0 3b ee 77 a9 62 |.v.I..=H.l.;.w.b|
-00000020 91 b3 16 b0 e1 79 4b 2a 95 d8 54 98 7b 5e ac 0f |.....yK*..T.{^..|
-00000030 07 3b 06 36 e1 38 dc 75 6a af f7 ce a4 b2 3f 9e |.;.6.8.uj.....?.|
-00000040 36 b1 44 ce e9 6c 34 ba ce 97 02 17 03 00 00 18 |6.D..l4.........|
-00000050 5b be 71 2f a1 15 2f e9 9b 83 8e f1 9b e7 5b 4a |[.q/../.......[J|
-00000060 a1 85 13 03 c0 f2 30 0c 17 03 00 00 28 2c d9 9e |......0.....(,..|
-00000070 f4 d2 70 2a 37 76 66 e7 f4 5c c7 55 be d8 82 49 |..p*7vf..\.U...I|
-00000080 77 e0 4f 0f 87 4b c0 b1 f3 d2 a3 63 df 62 bc ee |w.O..K.....c.b..|
-00000090 5c c2 50 2a 96 15 03 00 00 18 8b 0a 68 8a d8 64 |\.P*........h..d|
-000000a0 4e 3f f9 ee c6 b2 21 51 03 10 6b 73 3b 8c a4 bb |N?....!Q..ks;...|
-000000b0 6d f2 |m.|
+00000000 14 03 00 00 01 01 16 03 00 00 40 e8 3e 89 b5 10 |.......... at .>...|
+00000010 e4 c9 eb f7 3f 83 e5 6a 7c 04 fd e6 96 69 25 fb |....?..j|....i%.|
+00000020 0b 0b 0e f7 13 4e 99 45 d2 0e 13 22 6b d1 0e 32 |.....N.E..."k..2|
+00000030 30 b5 c4 a2 03 cf 22 59 68 5c cc 63 96 f5 01 f3 |0....."Yh\.c....|
+00000040 2c b3 b5 13 e1 9d 19 45 c0 4f 28 17 03 00 00 18 |,......E.O(.....|
+00000050 2e cb 8c b3 d4 d5 c2 18 fd 6e dc 72 7b b3 4b b8 |.........n.r{.K.|
+00000060 10 56 0a 01 af 55 e8 5a 17 03 00 00 28 3f df 74 |.V...U.Z....(?.t|
+00000070 2f b9 5b a4 43 ec 24 68 ad ff 6c 52 b5 6a 91 0c |/.[.C.$h..lR.j..|
+00000080 be 3b 25 c9 e4 40 59 66 17 cb f0 e7 6b 6e cd 43 |.;%.. at Yf....kn.C|
+00000090 ac be b7 62 d0 15 03 00 00 18 43 4d 3c fd 83 6e |...b......CM<..n|
+000000a0 e0 3f ae 40 0c 8a a1 08 d2 74 e2 60 7b d0 97 d5 |.?. at .....t.`{...|
+000000b0 e8 a5 |..|
diff --git a/src/crypto/tls/testdata/Server-SSLv3-RSA-AES b/src/crypto/tls/testdata/Server-SSLv3-RSA-AES
index e733819..771373c 100644
--- a/src/crypto/tls/testdata/Server-SSLv3-RSA-AES
+++ b/src/crypto/tls/testdata/Server-SSLv3-RSA-AES
@@ -1,79 +1,77 @@
>>> Flow 1 (client to server)
-00000000 16 03 00 00 30 01 00 00 2c 03 00 36 b0 f3 52 13 |....0...,..6..R.|
-00000010 00 17 16 8f 6e 44 24 06 84 05 5b 03 e6 8a 55 ee |....nD$...[...U.|
-00000020 75 9c a8 77 9e e0 7b 15 f9 60 6e 00 00 04 00 2f |u..w..{..`n..../|
-00000030 00 ff 02 01 00 |.....|
+00000000 16 03 00 00 2f 01 00 00 2b 03 00 26 1e 06 cd 27 |..../...+..&...'|
+00000010 f5 2a b4 8d 00 07 47 16 02 23 aa 5e 92 02 95 4a |.*....G..#.^...J|
+00000020 1a 0b a8 51 8a 6f 4a 31 3c e9 a2 00 00 04 00 2f |...Q.oJ1<....../|
+00000030 00 ff 01 00 |....|
>>> Flow 2 (server to client)
00000000 16 03 00 00 31 02 00 00 2d 03 00 00 00 00 00 00 |....1...-.......|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2f 00 00 |............./..|
-00000030 05 ff 01 00 01 00 16 03 00 02 71 0b 00 02 6d 00 |..........q...m.|
-00000040 02 6a 00 02 67 30 82 02 63 30 82 01 cc a0 03 02 |.j..g0..c0......|
-00000050 01 02 02 09 00 a2 73 00 0c 81 00 cb f3 30 0d 06 |......s......0..|
-00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 2b 31 17 |.*.H........0+1.|
-00000070 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 |0...U....Google |
-00000080 54 45 53 54 49 4e 47 31 10 30 0e 06 03 55 04 03 |TESTING1.0...U..|
-00000090 13 07 47 6f 20 52 6f 6f 74 30 1e 17 0d 31 35 30 |..Go Root0...150|
-000000a0 31 30 31 30 30 30 30 30 30 5a 17 0d 32 35 30 31 |101000000Z..2501|
-000000b0 30 31 30 30 30 30 30 30 5a 30 26 31 17 30 15 06 |01000000Z0&1.0..|
-000000c0 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 54 45 53 |.U....Google TES|
-000000d0 54 49 4e 47 31 0b 30 09 06 03 55 04 03 13 02 47 |TING1.0...U....G|
-000000e0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....|
-000000f0 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 af 87 |.......0........|
-00000100 88 f6 20 1b 95 65 6c 14 ab 44 05 af 3b 45 14 e3 |.. ..el..D..;E..|
-00000110 b7 6d fd 00 63 4d 95 7f fe 6a 62 35 86 c0 4a f9 |.m..cM...jb5..J.|
-00000120 18 7c f6 aa 25 5e 7a 64 31 66 00 ba f4 8e 92 af |.|..%^zd1f......|
-00000130 c7 6b d8 76 d4 f3 5f 41 cb 6e 56 15 97 1b 97 c1 |.k.v.._A.nV.....|
-00000140 3c 12 39 21 66 3d 2b 16 d1 bc db 1c c0 a7 da b7 |<.9!f=+.........|
-00000150 ca ad ba da cb d5 21 50 ec de 8d ab d1 6b 81 4b |......!P.....k.K|
-00000160 89 02 f3 c4 be c1 6c 89 b1 44 84 bd 21 d1 04 7d |......l..D..!..}|
-00000170 9d 16 4d f9 82 15 f6 ef fa d6 09 47 f2 fb 02 03 |..M........G....|
-00000180 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..|
-00000190 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%|
-000001a0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........|
-000001b0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...|
-000001c0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....|
-000001d0 10 12 50 8d 89 6f 1b d1 dc 54 4d 6e cb 69 5e 06 |..P..o...TMn.i^.|
-000001e0 f4 30 1b 06 03 55 1d 23 04 14 30 12 80 10 bf 3d |.0...U.#..0....=|
-000001f0 b6 a9 66 f2 b8 40 cf ea b4 03 78 48 1a 41 30 19 |..f.. at ....xH.A0.|
-00000200 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp|
-00000210 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H|
-00000220 86 f7 0d 01 01 0b 05 00 03 81 81 00 92 7c af 91 |.............|..|
-00000230 55 12 18 96 59 31 a6 48 40 d5 2d d5 ee bb 02 a0 |U...Y1.H at .-.....|
-00000240 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 da 4f 3d c0 fa |...|..0}<.v.O=..|
-00000250 ae 2d 33 24 6b 03 7b 1b 67 59 11 21 b5 11 bc 77 |.-3$k.{.gY.!...w|
-00000260 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f 22 3e 63 10 6b |...n.-.5.d_">c.k|
-00000270 be ff 14 86 6d 0d f0 15 31 a8 14 38 1e 3b 84 87 |....m...1..8.;..|
-00000280 2c cb 98 ed 51 76 b9 b1 4f dd db 9b 84 04 86 40 |,...Qv..O......@|
-00000290 fa 51 dd ba b4 8d eb e3 46 de 46 b9 4f 86 c7 f9 |.Q......F.F.O...|
-000002a0 a4 c2 41 34 ac cc f6 ea b0 ab 39 18 16 03 00 00 |..A4......9.....|
-000002b0 04 0e 00 00 00 |.....|
+00000030 05 ff 01 00 01 00 16 03 00 02 59 0b 00 02 55 00 |..........Y...U.|
+00000040 02 52 00 02 4f 30 82 02 4b 30 82 01 b4 a0 03 02 |.R..O0..K0......|
+00000050 01 02 02 09 00 e8 f0 9d 3f e2 5b ea a6 30 0d 06 |........?.[..0..|
+00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 1f 31 0b |.*.H........0.1.|
+00000070 30 09 06 03 55 04 0a 13 02 47 6f 31 10 30 0e 06 |0...U....Go1.0..|
+00000080 03 55 04 03 13 07 47 6f 20 52 6f 6f 74 30 1e 17 |.U....Go Root0..|
+00000090 0d 31 36 30 31 30 31 30 30 30 30 30 30 5a 17 0d |.160101000000Z..|
+000000a0 32 35 30 31 30 31 30 30 30 30 30 30 5a 30 1a 31 |250101000000Z0.1|
+000000b0 0b 30 09 06 03 55 04 0a 13 02 47 6f 31 0b 30 09 |.0...U....Go1.0.|
+000000c0 06 03 55 04 03 13 02 47 6f 30 81 9f 30 0d 06 09 |..U....Go0..0...|
+000000d0 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 30 |*.H............0|
+000000e0 81 89 02 81 81 00 db 46 7d 93 2e 12 27 06 48 bc |.......F}...'.H.|
+000000f0 06 28 21 ab 7e c4 b6 a2 5d fe 1e 52 45 88 7a 36 |.(!.~...]..RE.z6|
+00000100 47 a5 08 0d 92 42 5b c2 81 c0 be 97 79 98 40 fb |G....B[.....y. at .|
+00000110 4f 6d 14 fd 2b 13 8b c2 a5 2e 67 d8 d4 09 9e d6 |Om..+.....g.....|
+00000120 22 38 b7 4a 0b 74 73 2b c2 34 f1 d1 93 e5 96 d9 |"8.J.ts+.4......|
+00000130 74 7b f3 58 9f 6c 61 3c c0 b0 41 d4 d9 2b 2b 24 |t{.X.la<..A..++$|
+00000140 23 77 5b 1c 3b bd 75 5d ce 20 54 cf a1 63 87 1d |#w[.;.u]. T..c..|
+00000150 1e 24 c4 f3 1d 1a 50 8b aa b6 14 43 ed 97 a7 75 |.$....P....C...u|
+00000160 62 f4 14 c8 52 d7 02 03 01 00 01 a3 81 93 30 81 |b...R.........0.|
+00000170 90 30 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 05 |.0...U..........|
+00000180 a0 30 1d 06 03 55 1d 25 04 16 30 14 06 08 2b 06 |.0...U.%..0...+.|
+00000190 01 05 05 07 03 01 06 08 2b 06 01 05 05 07 03 02 |........+.......|
+000001a0 30 0c 06 03 55 1d 13 01 01 ff 04 02 30 00 30 19 |0...U.......0.0.|
+000001b0 06 03 55 1d 0e 04 12 04 10 9f 91 16 1f 43 43 3e |..U..........CC>|
+000001c0 49 a6 de 6d b6 80 d7 9f 60 30 1b 06 03 55 1d 23 |I..m....`0...U.#|
+000001d0 04 14 30 12 80 10 48 13 49 4d 13 7e 16 31 bb a3 |..0...H.IM.~.1..|
+000001e0 01 d5 ac ab 6e 7b 30 19 06 03 55 1d 11 04 12 30 |....n{0...U....0|
+000001f0 10 82 0e 65 78 61 6d 70 6c 65 2e 67 6f 6c 61 6e |...example.golan|
+00000200 67 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 |g0...*.H........|
+00000210 03 81 81 00 9d 30 cc 40 2b 5b 50 a0 61 cb ba e5 |.....0. at +[P.a...|
+00000220 53 58 e1 ed 83 28 a9 58 1a a9 38 a4 95 a1 ac 31 |SX...(.X..8....1|
+00000230 5a 1a 84 66 3d 43 d3 2d d9 0b f2 97 df d3 20 64 |Z..f=C.-...... d|
+00000240 38 92 24 3a 00 bc cf 9c 7d b7 40 20 01 5f aa d3 |8.$:....}.@ ._..|
+00000250 16 61 09 a2 76 fd 13 c3 cc e1 0c 5c ee b1 87 82 |.a..v......\....|
+00000260 f1 6c 04 ed 73 bb b3 43 77 8d 0c 1c f1 0f a1 d8 |.l..s..Cw.......|
+00000270 40 83 61 c9 4c 72 2b 9d ae db 46 06 06 4d f4 c1 |@.a.Lr+...F..M..|
+00000280 b3 3e c0 d1 bd 42 d4 db fe 3d 13 60 84 5c 21 d3 |.>...B...=.`.\!.|
+00000290 3b e9 fa e7 16 03 00 00 04 0e 00 00 00 |;............|
>>> Flow 3 (client to server)
-00000000 16 03 00 00 84 10 00 00 80 2d 0b b1 1c 96 72 65 |.........-....re|
-00000010 e5 3b 5b 48 35 91 b8 2e 18 b5 6c 36 a4 91 10 0e |.;[H5.....l6....|
-00000020 15 63 de fb 7e ea 44 cd 2e 2f 37 2c 88 96 30 d4 |.c..~.D../7,..0.|
-00000030 07 ff 02 9b af 84 2c 43 6c 3a 1f 75 17 4c 5e 8b |......,Cl:.u.L^.|
-00000040 4a d9 df 68 fe ad 72 c9 0c f7 a5 0c a1 70 8b 9f |J..h..r......p..|
-00000050 e7 8e 1d 32 61 8e 80 e5 3a 3a 61 ea 22 1a 67 e5 |...2a...::a.".g.|
-00000060 06 6a 5e 0c 65 bd c7 32 9c 13 c1 53 ad 8e f1 be |.j^.e..2...S....|
-00000070 4d 6c 53 89 8f 9c 49 d2 85 58 04 b5 e8 53 b4 82 |MlS...I..X...S..|
-00000080 84 46 9d 70 fa 0a 34 15 1d 14 03 00 00 01 01 16 |.F.p..4.........|
-00000090 03 00 00 40 71 c7 4b ef 6b 7a f4 a2 29 dd c0 4b |... at q.K.kz..)..K|
-000000a0 ef 04 7d ea 1c 31 16 38 ae 85 f9 89 db 2f a8 04 |..}..1.8...../..|
-000000b0 ad 61 b7 33 73 8c 31 9b 72 5a f6 8b 10 71 0c af |.a.3s.1.rZ...q..|
-000000c0 99 89 14 63 b8 19 f8 0e 2c 0f 14 c6 d6 0a bd 4f |...c....,......O|
-000000d0 96 59 0d 60 |.Y.`|
+00000000 16 03 00 00 84 10 00 00 80 66 67 59 2f 21 b9 e3 |.........fgY/!..|
+00000010 0d a9 78 0c 6b fc dc 6f 69 4e f9 00 8b 40 a2 0f |..x.k..oiN... at ..|
+00000020 5a d8 8c d2 59 ab 33 78 f6 42 2f fa cf d6 48 7a |Z...Y.3x.B/...Hz|
+00000030 59 30 94 1c 10 49 30 69 4a 6c a2 e5 ce 59 6d e3 |Y0...I0iJl...Ym.|
+00000040 49 0c a7 0a ab 17 8b c6 48 82 71 44 d5 7d 80 e5 |I.......H.qD.}..|
+00000050 6d 45 6c 10 12 01 85 71 ee dc c5 e3 19 41 ed 22 |mEl....q.....A."|
+00000060 11 5c c4 25 c6 90 ad c8 4c 48 45 8d ad 6c f4 ef |.\.%....LHE..l..|
+00000070 fb b4 2b 53 90 cc 78 b0 9e 22 e7 2c 1a 64 0e 8b |..+S..x..".,.d..|
+00000080 d8 57 54 74 c5 33 20 3f 42 14 03 00 00 01 01 16 |.WTt.3 ?B.......|
+00000090 03 00 00 40 18 b6 0a d4 9e 4d fa 8a 67 ce 8e d5 |... at .....M..g...|
+000000a0 51 31 75 65 f1 ff 54 a2 1b 80 c5 c3 a0 fc d2 78 |Q1ue..T........x|
+000000b0 0b 99 3b 65 6c 1d 52 6d a9 9f 64 13 97 d5 2e b1 |..;el.Rm..d.....|
+000000c0 76 0b a0 fb f6 16 f7 72 28 a5 8a 11 a7 46 d5 59 |v......r(....F.Y|
+000000d0 e1 f4 f3 6f |...o|
>>> Flow 4 (server to client)
-00000000 14 03 00 00 01 01 16 03 00 00 40 28 76 de 29 3b |..........@(v.);|
-00000010 48 77 56 f1 e5 97 21 20 88 9c 7d 5e 02 3d bb c9 |HwV...! ..}^.=..|
-00000020 2f b1 ce 2e 65 ac 53 ea a2 06 0e fb cf 53 28 1d |/...e.S......S(.|
-00000030 df b3 24 48 52 7a 28 d6 9e 50 83 64 da 34 c1 f4 |..$HRz(..P.d.4..|
-00000040 c9 bf ec 42 33 c4 8a 6f 89 aa 1c 17 03 00 00 20 |...B3..o....... |
-00000050 f2 af bb 38 4f 37 58 0e c4 2b 28 45 01 45 89 e9 |...8O7X..+(E.E..|
-00000060 31 5a 6d 8d 4d 1b 49 bd 7d 87 8a 62 e6 c8 03 43 |1Zm.M.I.}..b...C|
-00000070 17 03 00 00 30 60 ec e4 6f ec 88 33 d8 89 49 73 |....0`..o..3..Is|
-00000080 3a aa 67 ab 45 9f de c7 3f 0e 39 3d 9a 30 99 9c |:.g.E...?.9=.0..|
-00000090 2d 10 5f f0 7d 70 10 d5 8e ca 18 91 25 e8 9d d1 |-._.}p......%...|
-000000a0 36 b0 a7 90 9b 15 03 00 00 20 63 e9 92 98 7d b1 |6........ c...}.|
-000000b0 9a 88 07 37 b2 27 99 95 b9 16 17 74 c2 42 9c dc |...7.'.....t.B..|
-000000c0 80 32 de f4 f6 87 cb f1 87 d8 |.2........|
+00000000 14 03 00 00 01 01 16 03 00 00 40 6c 5b 64 b5 f9 |.......... at l[d..|
+00000010 76 cc 7e 51 72 46 ab 21 17 b3 fb 2b 48 c5 5a 9f |v.~QrF.!...+H.Z.|
+00000020 e6 35 14 ff df c7 a7 4b 5e 5a 9b 82 57 b5 bf 4d |.5.....K^Z..W..M|
+00000030 5f 7c a5 be 67 96 71 3a 63 ad 76 86 66 06 e9 a2 |_|..g.q:c.v.f...|
+00000040 35 39 6f 79 13 21 4b 19 c1 83 0e 17 03 00 00 20 |59oy.!K........ |
+00000050 1a 80 c5 d1 8b 33 79 89 39 fc 11 44 80 33 1a f7 |.....3y.9..D.3..|
+00000060 9f 63 96 5d c9 1a d4 56 2a ee 68 24 68 83 5d ca |.c.]...V*.h$h.].|
+00000070 17 03 00 00 30 7c d4 88 17 d0 10 66 6a b3 61 ed |....0|.....fj.a.|
+00000080 0a b5 72 55 ca fb c4 ec e2 f2 e2 bf 67 dd 3d c9 |..rU........g.=.|
+00000090 01 3b 50 5c 35 ce 28 2d e6 9c 1f 5c 70 14 46 2a |.;P\5.(-...\p.F*|
+000000a0 d8 9e ef 6a 66 15 03 00 00 20 c7 af e1 86 10 30 |...jf.... .....0|
+000000b0 41 73 88 b2 86 02 a8 60 38 61 92 32 11 22 2d 47 |As.....`8a.2."-G|
+000000c0 76 fe 22 9c 76 c2 00 ee e9 03 |v.".v.....|
diff --git a/src/crypto/tls/testdata/Server-SSLv3-RSA-RC4 b/src/crypto/tls/testdata/Server-SSLv3-RSA-RC4
index dce3ebe..f5674cc 100644
--- a/src/crypto/tls/testdata/Server-SSLv3-RSA-RC4
+++ b/src/crypto/tls/testdata/Server-SSLv3-RSA-RC4
@@ -1,74 +1,72 @@
>>> Flow 1 (client to server)
-00000000 16 03 00 00 30 01 00 00 2c 03 00 3c 64 40 96 81 |....0...,..<d at ..|
-00000010 b4 90 3d a5 bb 90 8a ba 39 73 4c cd 2d f9 4c 12 |..=.....9sL.-.L.|
-00000020 4c 6e d6 09 43 e3 eb 07 2e 52 1a 00 00 04 00 05 |Ln..C....R......|
-00000030 00 ff 02 01 00 |.....|
+00000000 16 03 00 00 2f 01 00 00 2b 03 00 3f cc 8d 3f f0 |..../...+..?..?.|
+00000010 c9 36 6f 43 43 c1 46 45 cd bf e5 ba 02 e6 55 2c |.6oCC.FE......U,|
+00000020 3a 24 4a db cb a8 f2 1d 26 3e ef 00 00 04 00 05 |:$J.....&>......|
+00000030 00 ff 01 00 |....|
>>> Flow 2 (server to client)
00000000 16 03 00 00 31 02 00 00 2d 03 00 00 00 00 00 00 |....1...-.......|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 05 00 00 |................|
-00000030 05 ff 01 00 01 00 16 03 00 02 71 0b 00 02 6d 00 |..........q...m.|
-00000040 02 6a 00 02 67 30 82 02 63 30 82 01 cc a0 03 02 |.j..g0..c0......|
-00000050 01 02 02 09 00 a2 73 00 0c 81 00 cb f3 30 0d 06 |......s......0..|
-00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 2b 31 17 |.*.H........0+1.|
-00000070 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 |0...U....Google |
-00000080 54 45 53 54 49 4e 47 31 10 30 0e 06 03 55 04 03 |TESTING1.0...U..|
-00000090 13 07 47 6f 20 52 6f 6f 74 30 1e 17 0d 31 35 30 |..Go Root0...150|
-000000a0 31 30 31 30 30 30 30 30 30 5a 17 0d 32 35 30 31 |101000000Z..2501|
-000000b0 30 31 30 30 30 30 30 30 5a 30 26 31 17 30 15 06 |01000000Z0&1.0..|
-000000c0 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 54 45 53 |.U....Google TES|
-000000d0 54 49 4e 47 31 0b 30 09 06 03 55 04 03 13 02 47 |TING1.0...U....G|
-000000e0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....|
-000000f0 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 af 87 |.......0........|
-00000100 88 f6 20 1b 95 65 6c 14 ab 44 05 af 3b 45 14 e3 |.. ..el..D..;E..|
-00000110 b7 6d fd 00 63 4d 95 7f fe 6a 62 35 86 c0 4a f9 |.m..cM...jb5..J.|
-00000120 18 7c f6 aa 25 5e 7a 64 31 66 00 ba f4 8e 92 af |.|..%^zd1f......|
-00000130 c7 6b d8 76 d4 f3 5f 41 cb 6e 56 15 97 1b 97 c1 |.k.v.._A.nV.....|
-00000140 3c 12 39 21 66 3d 2b 16 d1 bc db 1c c0 a7 da b7 |<.9!f=+.........|
-00000150 ca ad ba da cb d5 21 50 ec de 8d ab d1 6b 81 4b |......!P.....k.K|
-00000160 89 02 f3 c4 be c1 6c 89 b1 44 84 bd 21 d1 04 7d |......l..D..!..}|
-00000170 9d 16 4d f9 82 15 f6 ef fa d6 09 47 f2 fb 02 03 |..M........G....|
-00000180 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..|
-00000190 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%|
-000001a0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........|
-000001b0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...|
-000001c0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....|
-000001d0 10 12 50 8d 89 6f 1b d1 dc 54 4d 6e cb 69 5e 06 |..P..o...TMn.i^.|
-000001e0 f4 30 1b 06 03 55 1d 23 04 14 30 12 80 10 bf 3d |.0...U.#..0....=|
-000001f0 b6 a9 66 f2 b8 40 cf ea b4 03 78 48 1a 41 30 19 |..f.. at ....xH.A0.|
-00000200 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp|
-00000210 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H|
-00000220 86 f7 0d 01 01 0b 05 00 03 81 81 00 92 7c af 91 |.............|..|
-00000230 55 12 18 96 59 31 a6 48 40 d5 2d d5 ee bb 02 a0 |U...Y1.H at .-.....|
-00000240 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 da 4f 3d c0 fa |...|..0}<.v.O=..|
-00000250 ae 2d 33 24 6b 03 7b 1b 67 59 11 21 b5 11 bc 77 |.-3$k.{.gY.!...w|
-00000260 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f 22 3e 63 10 6b |...n.-.5.d_">c.k|
-00000270 be ff 14 86 6d 0d f0 15 31 a8 14 38 1e 3b 84 87 |....m...1..8.;..|
-00000280 2c cb 98 ed 51 76 b9 b1 4f dd db 9b 84 04 86 40 |,...Qv..O......@|
-00000290 fa 51 dd ba b4 8d eb e3 46 de 46 b9 4f 86 c7 f9 |.Q......F.F.O...|
-000002a0 a4 c2 41 34 ac cc f6 ea b0 ab 39 18 16 03 00 00 |..A4......9.....|
-000002b0 04 0e 00 00 00 |.....|
+00000030 05 ff 01 00 01 00 16 03 00 02 59 0b 00 02 55 00 |..........Y...U.|
+00000040 02 52 00 02 4f 30 82 02 4b 30 82 01 b4 a0 03 02 |.R..O0..K0......|
+00000050 01 02 02 09 00 e8 f0 9d 3f e2 5b ea a6 30 0d 06 |........?.[..0..|
+00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 1f 31 0b |.*.H........0.1.|
+00000070 30 09 06 03 55 04 0a 13 02 47 6f 31 10 30 0e 06 |0...U....Go1.0..|
+00000080 03 55 04 03 13 07 47 6f 20 52 6f 6f 74 30 1e 17 |.U....Go Root0..|
+00000090 0d 31 36 30 31 30 31 30 30 30 30 30 30 5a 17 0d |.160101000000Z..|
+000000a0 32 35 30 31 30 31 30 30 30 30 30 30 5a 30 1a 31 |250101000000Z0.1|
+000000b0 0b 30 09 06 03 55 04 0a 13 02 47 6f 31 0b 30 09 |.0...U....Go1.0.|
+000000c0 06 03 55 04 03 13 02 47 6f 30 81 9f 30 0d 06 09 |..U....Go0..0...|
+000000d0 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 30 |*.H............0|
+000000e0 81 89 02 81 81 00 db 46 7d 93 2e 12 27 06 48 bc |.......F}...'.H.|
+000000f0 06 28 21 ab 7e c4 b6 a2 5d fe 1e 52 45 88 7a 36 |.(!.~...]..RE.z6|
+00000100 47 a5 08 0d 92 42 5b c2 81 c0 be 97 79 98 40 fb |G....B[.....y. at .|
+00000110 4f 6d 14 fd 2b 13 8b c2 a5 2e 67 d8 d4 09 9e d6 |Om..+.....g.....|
+00000120 22 38 b7 4a 0b 74 73 2b c2 34 f1 d1 93 e5 96 d9 |"8.J.ts+.4......|
+00000130 74 7b f3 58 9f 6c 61 3c c0 b0 41 d4 d9 2b 2b 24 |t{.X.la<..A..++$|
+00000140 23 77 5b 1c 3b bd 75 5d ce 20 54 cf a1 63 87 1d |#w[.;.u]. T..c..|
+00000150 1e 24 c4 f3 1d 1a 50 8b aa b6 14 43 ed 97 a7 75 |.$....P....C...u|
+00000160 62 f4 14 c8 52 d7 02 03 01 00 01 a3 81 93 30 81 |b...R.........0.|
+00000170 90 30 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 05 |.0...U..........|
+00000180 a0 30 1d 06 03 55 1d 25 04 16 30 14 06 08 2b 06 |.0...U.%..0...+.|
+00000190 01 05 05 07 03 01 06 08 2b 06 01 05 05 07 03 02 |........+.......|
+000001a0 30 0c 06 03 55 1d 13 01 01 ff 04 02 30 00 30 19 |0...U.......0.0.|
+000001b0 06 03 55 1d 0e 04 12 04 10 9f 91 16 1f 43 43 3e |..U..........CC>|
+000001c0 49 a6 de 6d b6 80 d7 9f 60 30 1b 06 03 55 1d 23 |I..m....`0...U.#|
+000001d0 04 14 30 12 80 10 48 13 49 4d 13 7e 16 31 bb a3 |..0...H.IM.~.1..|
+000001e0 01 d5 ac ab 6e 7b 30 19 06 03 55 1d 11 04 12 30 |....n{0...U....0|
+000001f0 10 82 0e 65 78 61 6d 70 6c 65 2e 67 6f 6c 61 6e |...example.golan|
+00000200 67 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 |g0...*.H........|
+00000210 03 81 81 00 9d 30 cc 40 2b 5b 50 a0 61 cb ba e5 |.....0. at +[P.a...|
+00000220 53 58 e1 ed 83 28 a9 58 1a a9 38 a4 95 a1 ac 31 |SX...(.X..8....1|
+00000230 5a 1a 84 66 3d 43 d3 2d d9 0b f2 97 df d3 20 64 |Z..f=C.-...... d|
+00000240 38 92 24 3a 00 bc cf 9c 7d b7 40 20 01 5f aa d3 |8.$:....}.@ ._..|
+00000250 16 61 09 a2 76 fd 13 c3 cc e1 0c 5c ee b1 87 82 |.a..v......\....|
+00000260 f1 6c 04 ed 73 bb b3 43 77 8d 0c 1c f1 0f a1 d8 |.l..s..Cw.......|
+00000270 40 83 61 c9 4c 72 2b 9d ae db 46 06 06 4d f4 c1 |@.a.Lr+...F..M..|
+00000280 b3 3e c0 d1 bd 42 d4 db fe 3d 13 60 84 5c 21 d3 |.>...B...=.`.\!.|
+00000290 3b e9 fa e7 16 03 00 00 04 0e 00 00 00 |;............|
>>> Flow 3 (client to server)
-00000000 16 03 00 00 84 10 00 00 80 00 e0 40 dd e4 0f 54 |........... at ...T|
-00000010 40 66 62 06 72 2a 7a 06 2d a9 0f 16 3b 5c 63 9b |@fb.r*z.-...;\c.|
-00000020 95 82 9c d4 95 57 c0 37 d1 30 6a 33 e1 5a ec 93 |.....W.7.0j3.Z..|
-00000030 12 ec 2a 94 c6 9c b3 6c a3 4f ef cd f1 80 25 a7 |..*....l.O....%.|
-00000040 54 ca 6a 6e b9 80 0b fc f1 e9 60 a0 f5 33 24 3b |T.jn......`..3$;|
-00000050 13 04 9a f1 8a 37 cd 11 cf 95 ae 71 ba 73 8e 00 |.....7.....q.s..|
-00000060 86 17 6a 3b d5 9e a9 04 87 fd 62 ed 4c b5 01 55 |..j;......b.L..U|
-00000070 65 a2 fb e8 1d 86 a5 58 2a ad e7 fd d3 44 2f 7d |e......X*....D/}|
-00000080 25 b7 3b c7 75 39 5c 45 f6 14 03 00 00 01 01 16 |%.;.u9\E........|
-00000090 03 00 00 3c e6 58 15 b2 fb 0d 44 ed 43 d5 ff a8 |...<.X....D.C...|
-000000a0 41 25 83 41 46 da f6 8e 70 34 39 c6 6c 2c ea 1b |A%.AF...p49.l,..|
-000000b0 2a 02 5c 4b e4 87 58 33 6c d0 22 2e ce 85 df 31 |*.\K..X3l."....1|
-000000c0 0d 71 4c 1a f9 9c 64 d7 87 53 eb c9 1a 0a 16 dc |.qL...d..S......|
+00000000 16 03 00 00 84 10 00 00 80 13 5d 75 f0 6d 24 54 |..........]u.m$T|
+00000010 f5 a1 f0 13 86 61 ce ea 66 86 06 eb c8 27 78 9f |.....a..f....'x.|
+00000020 10 0d ef 94 3f 1b fb 8c 11 14 67 2a 0e 2a 1b cf |....?.....g*.*..|
+00000030 ae 5a cb ac b8 b2 ea a8 70 85 ee fd 88 a9 61 a4 |.Z......p.....a.|
+00000040 75 66 86 a5 88 96 a0 0d 6f 77 fe 63 5e 88 60 4d |uf......ow.c^.`M|
+00000050 f6 b7 93 28 99 72 e8 60 ed 64 9a 3f e6 12 ea ee |...(.r.`.d.?....|
+00000060 83 58 d4 0c 19 e0 2b ce b0 b4 fa 73 9f 78 d9 09 |.X....+....s.x..|
+00000070 8c 17 b8 f5 04 e1 de c4 fe a9 1a aa ba 0d be f3 |................|
+00000080 c8 e1 e4 e8 cc 39 4c f0 b9 14 03 00 00 01 01 16 |.....9L.........|
+00000090 03 00 00 3c 1b 70 07 7f ad 8f a7 78 fd e8 eb b2 |...<.p.....x....|
+000000a0 9a 54 86 a2 dd bc fa b6 0a 52 48 24 79 6a 04 f6 |.T.......RH$yj..|
+000000b0 28 80 1f b7 b1 c6 4e 07 a3 52 60 5a 5a 81 14 11 |(.....N..R`ZZ...|
+000000c0 d2 ee 33 71 e7 d3 ba 3e 4b 31 81 f2 f0 49 ee e4 |..3q...>K1...I..|
>>> Flow 4 (server to client)
-00000000 14 03 00 00 01 01 16 03 00 00 3c 17 a2 5b 4a 06 |..........<..[J.|
-00000010 63 6a 4b f9 ef 66 ed 31 f6 87 75 20 8b 08 8d 5d |cjK..f.1..u ...]|
-00000020 0f 72 87 dd 8d db 99 d5 06 42 2b a3 84 77 35 f2 |.r.......B+..w5.|
-00000030 1d 11 ae 0b 0c df ed 10 6e 23 27 93 29 65 25 f6 |........n#'.)e%.|
-00000040 60 b9 76 c8 95 2b 0c 17 03 00 00 21 df 08 e8 1f |`.v..+.....!....|
-00000050 2f ea 5a 61 d6 d4 4a c0 c1 b5 59 bc e1 89 6e 88 |/.Za..J...Y...n.|
-00000060 bb 8d 16 db 64 87 31 6c 2d d6 c7 d2 ed 15 03 00 |....d.1l-.......|
-00000070 00 16 a9 53 32 af 7a a4 88 02 93 6b aa 95 84 4f |...S2.z....k...O|
-00000080 17 5a 97 93 67 87 3b 07 |.Z..g.;.|
+00000000 14 03 00 00 01 01 16 03 00 00 3c 47 20 7c b9 0d |..........<G |..|
+00000010 f8 59 c0 79 25 ae 8a f3 f5 7d 0c f5 62 d4 a5 5b |.Y.y%....}..b..[|
+00000020 f6 08 36 cc 99 21 ac 80 04 48 49 2c 04 7c 87 08 |..6..!...HI,.|..|
+00000030 d3 10 43 a9 6a ec 99 96 99 0a fa cb db 95 6f fe |..C.j.........o.|
+00000040 b1 75 77 1e b7 a9 9d 17 03 00 00 21 1a 2f bc 70 |.uw........!./.p|
+00000050 2c 00 6b 55 e1 e5 81 17 1c b7 a1 11 d7 21 c1 2f |,.kU.........!./|
+00000060 3e 95 f8 48 74 a4 97 0a 9d a2 0b bc d4 15 03 00 |>..Ht...........|
+00000070 00 16 67 0d 6d 69 53 87 92 23 21 51 72 f6 31 73 |..g.miS..#!Qr.1s|
+00000080 db bd 3c e6 f4 12 4c 69 |..<...Li|
diff --git a/src/crypto/tls/testdata/Server-TLSv10-ECDHE-ECDSA-AES b/src/crypto/tls/testdata/Server-TLSv10-ECDHE-ECDSA-AES
index 9314b90..3e17081 100644
--- a/src/crypto/tls/testdata/Server-TLSv10-ECDHE-ECDSA-AES
+++ b/src/crypto/tls/testdata/Server-TLSv10-ECDHE-ECDSA-AES
@@ -1,11 +1,10 @@
>>> Flow 1 (client to server)
-00000000 16 03 01 00 5f 01 00 00 5b 03 01 ad 87 94 6b 8a |...._...[.....k.|
-00000010 38 9e 70 d6 94 8a 73 a9 39 d8 d7 25 ab 47 92 4c |8.p...s.9..%.G.L|
-00000020 b1 20 8e 4d f3 7b cd 84 5e 13 c1 00 00 04 c0 0a |. .M.{..^.......|
-00000030 00 ff 02 01 00 00 2d 00 0b 00 04 03 00 01 02 00 |......-.........|
-00000040 0a 00 1c 00 1a 00 17 00 19 00 1c 00 1b 00 18 00 |................|
-00000050 1a 00 16 00 0e 00 0d 00 0b 00 0c 00 09 00 0a 00 |................|
-00000060 0f 00 01 01 |....|
+00000000 16 03 01 00 4f 01 00 00 4b 03 01 f1 86 d0 c8 69 |....O...K......i|
+00000010 46 0b 0b 89 08 c0 82 c0 f7 f1 9a b6 d2 2b e1 46 |F............+.F|
+00000020 e6 e1 44 65 de 39 0a 68 a8 d5 1c 00 00 04 c0 0a |..De.9.h........|
+00000030 00 ff 01 00 00 1e 00 0b 00 04 03 00 01 02 00 0a |................|
+00000040 00 0a 00 08 00 1d 00 17 00 19 00 18 00 16 00 00 |................|
+00000050 00 17 00 00 |....|
>>> Flow 2 (server to client)
00000000 16 03 01 00 31 02 00 00 2d 03 01 00 00 00 00 00 |....1...-.......|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
@@ -43,41 +42,37 @@
00000210 0e bd 3f a3 8c 25 c1 33 13 83 0d 94 06 bb d4 37 |..?..%.3.......7|
00000220 7a f6 ec 7a c9 86 2e dd d7 11 69 7f 85 7c 56 de |z..z......i..|V.|
00000230 fb 31 78 2b e4 c7 78 0d ae cb be 9e 4e 36 24 31 |.1x+..x.....N6$1|
-00000240 7b 6a 0f 39 95 12 07 8f 2a 16 03 01 00 d6 0c 00 |{j.9....*.......|
-00000250 00 d2 03 00 17 41 04 1e 18 37 ef 0d 19 51 88 35 |.....A...7...Q.5|
-00000260 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd a7 24 20 3e |uq..T[....g..$ >|
-00000270 b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e f1 07 9f 6c |.V...(^.+-O....l|
-00000280 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 a6 b5 68 1a |K[.V.2B.X..I..h.|
-00000290 41 03 56 6b dc 5a 89 00 8b 30 81 88 02 42 00 8b |A.Vk.Z...0...B..|
-000002a0 48 d5 a3 a0 35 5c 31 f5 0b e8 72 7c 87 31 79 af |H...5\1...r|.1y.|
-000002b0 7f 12 93 9a f9 df d5 44 bf 08 5a 6b 1c 68 dd 73 |.......D..Zk.h.s|
-000002c0 67 0f 32 41 45 53 bf 74 cf 91 54 e7 7a 88 41 7a |g.2AES.t..T.z.Az|
-000002d0 15 ea 3d e3 b8 93 c0 3f 24 4c fb ee 25 f1 20 80 |..=....?$L..%. .|
-000002e0 02 42 01 ab 97 5f 8b 8d 22 71 f9 f5 a3 59 69 42 |.B..._.."q...YiB|
-000002f0 06 bd 12 f5 61 53 cb c8 a1 b4 90 87 12 94 9b f8 |....aS..........|
-00000300 b3 1d 34 d9 cd 64 20 9c 92 ec b5 72 35 01 44 3a |..4..d ....r5.D:|
-00000310 86 e4 54 46 0d 74 1d 4e d8 41 16 eb ac c3 8a 2f |..TF.t.N.A...../|
-00000320 20 11 ad bc 16 03 01 00 04 0e 00 00 00 | ............|
+00000240 7b 6a 0f 39 95 12 07 8f 2a 16 03 01 00 b5 0c 00 |{j.9....*.......|
+00000250 00 b1 03 00 1d 20 2f e5 7d a3 47 cd 62 43 15 28 |..... /.}.G.bC.(|
+00000260 da ac 5f bb 29 07 30 ff f6 84 af c4 cf c2 ed 90 |.._.).0.........|
+00000270 99 5f 58 cb 3b 74 00 8b 30 81 88 02 42 00 ad 93 |._X.;t..0...B...|
+00000280 e2 c2 3d 7e 95 63 17 5d 45 cf cd 27 af d2 db b3 |..=~.c.]E..'....|
+00000290 d0 bc 13 1e 6f 0a 61 3a fb 3c b3 03 61 2c 36 ae |....o.a:.<..a,6.|
+000002a0 4f be 27 e9 43 3c cf 57 9b 82 5e 7d 54 36 ed 7e |O.'.C<.W..^}T6.~|
+000002b0 0b 34 68 26 90 00 20 02 0f c1 18 bc 79 1b 90 02 |.4h&.. .....y...|
+000002c0 42 01 6b 66 9d 56 48 8e 5e 38 93 48 03 6b b9 d7 |B.kf.VH.^8.H.k..|
+000002d0 bd 14 a0 3e 8a 27 81 7f fe 4d e5 8a 12 4d 95 16 |...>.'...M...M..|
+000002e0 ef c7 8d 60 07 1d 22 f8 5d 72 0d cc be c3 51 69 |...`..".]r....Qi|
+000002f0 7a 04 e3 84 e5 ba dd 04 1d d4 4c 6f 9f 6b 12 e0 |z.........Lo.k..|
+00000300 2f 83 3c 16 03 01 00 04 0e 00 00 00 |/.<.........|
>>> Flow 3 (client to server)
-00000000 16 03 01 00 46 10 00 00 42 41 04 38 ca 59 61 cd |....F...BA.8.Ya.|
-00000010 17 4a cf a8 0b 81 c6 b7 7f 52 dd 95 d7 57 9d 24 |.J.......R...W.$|
-00000020 bb b1 02 af 57 ee b9 f9 c5 a0 c3 20 44 e1 9a e4 |....W...... D...|
-00000030 83 64 7d a1 fa 9d 2e 3b 5e be 0f af ed 96 f3 09 |.d}....;^.......|
-00000040 62 a2 22 21 72 f8 84 89 8a fd 10 14 03 01 00 01 |b."!r...........|
-00000050 01 16 03 01 00 30 bd e6 23 e0 32 b8 4c ef ce 9e |.....0..#.2.L...|
-00000060 22 a5 77 2c f1 7e 2f 8d 8b 9e a5 92 42 f9 0f 02 |".w,.~/.....B...|
-00000070 eb 2e 94 f1 6d a3 24 3f c0 ae bb c0 c4 99 08 51 |....m.$?.......Q|
-00000080 47 28 8b 4e f9 02 |G(.N..|
+00000000 16 03 01 00 25 10 00 00 21 20 18 40 ea d1 e1 17 |....%...! . at ....|
+00000010 b6 a2 a5 db 20 13 70 81 90 fc ac e8 96 7c b1 e1 |.... .p......|..|
+00000020 ff 6f 57 1f c1 64 72 94 f7 05 14 03 01 00 01 01 |.oW..dr.........|
+00000030 16 03 01 00 30 05 33 48 f0 2a 3a df df 1d c4 3d |....0.3H.*:....=|
+00000040 87 ea 9d 04 04 eb 84 bf a0 ed bc 56 2f ab 36 52 |...........V/.6R|
+00000050 d5 b2 2c 6f 8c 58 49 51 33 d5 fc df 5d 09 df e9 |..,o.XIQ3...]...|
+00000060 be 20 30 9a 37 |. 0.7|
>>> Flow 4 (server to client)
-00000000 14 03 01 00 01 01 16 03 01 00 30 11 a9 f0 95 27 |..........0....'|
-00000010 ac 0a b7 8e 0d 42 0a 2a f8 f8 e2 4f 4f 4a 79 d1 |.....B.*...OOJy.|
-00000020 73 e6 4d 42 90 3c 06 f8 7b da 26 cc 58 be 97 f6 |s.MB.<..{.&.X...|
-00000030 41 32 fb 39 2f fa e1 bc 59 2b 45 17 03 01 00 20 |A2.9/...Y+E.... |
-00000040 93 6a a1 a6 a2 e6 be bb be 2f 8f 0c 52 39 1c 6a |.j......./..R9.j|
-00000050 6d 4c af 38 f7 60 8b ad 0e c7 62 0c 8b a4 42 14 |mL.8.`....b...B.|
-00000060 17 03 01 00 30 da b0 1b ef cf 45 86 09 e9 be aa |....0.....E.....|
-00000070 0f 71 af a3 86 d0 0f 2d e8 76 39 9a c4 1f f5 c2 |.q.....-.v9.....|
-00000080 82 0a ee 34 0e a6 3b 19 b8 2c 10 ad fc 03 33 31 |...4..;..,....31|
-00000090 10 42 9b 6e 7b 15 03 01 00 20 ac 73 4d 4b 92 30 |.B.n{.... .sMK.0|
-000000a0 bf 4c bc 77 c1 87 d7 20 ad 82 bd 75 31 82 0d 34 |.L.w... ...u1..4|
-000000b0 cb b2 86 fd 4f 9c 84 a3 80 af |....O.....|
+00000000 14 03 01 00 01 01 16 03 01 00 30 8c b6 5b 83 03 |..........0..[..|
+00000010 c0 d8 83 f7 1d 24 2e ec 39 68 00 91 73 d2 5a 15 |.....$..9h..s.Z.|
+00000020 3f 83 aa e3 6d fd cc 31 58 90 e9 a9 e3 e4 78 5d |?...m..1X.....x]|
+00000030 ce 8e b3 ba cd 71 aa a2 fd f4 7c 17 03 01 00 20 |.....q....|.... |
+00000040 62 98 34 9d 01 13 13 2d 1b 27 3a 4f 10 28 48 d6 |b.4....-.':O.(H.|
+00000050 32 8c 99 2a c8 64 14 6e dc f5 7c 6d 16 59 45 8e |2..*.d.n..|m.YE.|
+00000060 17 03 01 00 30 1e ed f9 40 ad 5c 5d f6 94 c9 fd |....0... at .\]....|
+00000070 a1 ac fc 00 7b 48 9a 59 6d f5 b7 06 a4 66 25 04 |....{H.Ym....f%.|
+00000080 61 33 08 f3 66 86 21 00 fb f3 03 78 83 4c b6 c8 |a3..f.!....x.L..|
+00000090 9d 5e ea f5 7e 15 03 01 00 20 98 d8 f6 2a 79 60 |.^..~.... ...*y`|
+000000a0 8d fb c9 45 2f 27 59 17 a9 79 eb e7 b9 46 f1 57 |...E/'Y..y...F.W|
+000000b0 a6 fa ea e1 d0 23 8c 03 4f 72 |.....#..Or|
diff --git a/src/crypto/tls/testdata/Server-TLSv10-RSA-3DES b/src/crypto/tls/testdata/Server-TLSv10-RSA-3DES
index 33e8063..9590b0d 100644
--- a/src/crypto/tls/testdata/Server-TLSv10-RSA-3DES
+++ b/src/crypto/tls/testdata/Server-TLSv10-RSA-3DES
@@ -1,74 +1,72 @@
>>> Flow 1 (client to server)
-00000000 16 03 01 00 37 01 00 00 33 03 01 8d f4 8c 3d bd |....7...3.....=.|
-00000010 d8 81 53 bb f5 bc 18 69 07 09 0d 05 93 4f 6f eb |..S....i.....Oo.|
-00000020 fa fb 03 65 d4 49 a3 df 9f c3 a5 00 00 04 00 0a |...e.I..........|
-00000030 00 ff 02 01 00 00 05 00 0f 00 01 01 |............|
+00000000 16 03 01 00 39 01 00 00 35 03 01 58 71 a3 0c c4 |....9...5..Xq...|
+00000010 b6 b0 33 0a 66 3c eb c6 f4 d9 0e 99 75 d4 9e b6 |..3.f<......u...|
+00000020 03 b4 ae ae ad bc a8 ab 64 a0 27 00 00 04 00 0a |........d.'.....|
+00000030 00 ff 01 00 00 08 00 16 00 00 00 17 00 00 |..............|
>>> Flow 2 (server to client)
00000000 16 03 01 00 31 02 00 00 2d 03 01 00 00 00 00 00 |....1...-.......|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 0a 00 00 |................|
-00000030 05 ff 01 00 01 00 16 03 01 02 71 0b 00 02 6d 00 |..........q...m.|
-00000040 02 6a 00 02 67 30 82 02 63 30 82 01 cc a0 03 02 |.j..g0..c0......|
-00000050 01 02 02 09 00 a2 73 00 0c 81 00 cb f3 30 0d 06 |......s......0..|
-00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 2b 31 17 |.*.H........0+1.|
-00000070 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 |0...U....Google |
-00000080 54 45 53 54 49 4e 47 31 10 30 0e 06 03 55 04 03 |TESTING1.0...U..|
-00000090 13 07 47 6f 20 52 6f 6f 74 30 1e 17 0d 31 35 30 |..Go Root0...150|
-000000a0 31 30 31 30 30 30 30 30 30 5a 17 0d 32 35 30 31 |101000000Z..2501|
-000000b0 30 31 30 30 30 30 30 30 5a 30 26 31 17 30 15 06 |01000000Z0&1.0..|
-000000c0 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 54 45 53 |.U....Google TES|
-000000d0 54 49 4e 47 31 0b 30 09 06 03 55 04 03 13 02 47 |TING1.0...U....G|
-000000e0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....|
-000000f0 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 af 87 |.......0........|
-00000100 88 f6 20 1b 95 65 6c 14 ab 44 05 af 3b 45 14 e3 |.. ..el..D..;E..|
-00000110 b7 6d fd 00 63 4d 95 7f fe 6a 62 35 86 c0 4a f9 |.m..cM...jb5..J.|
-00000120 18 7c f6 aa 25 5e 7a 64 31 66 00 ba f4 8e 92 af |.|..%^zd1f......|
-00000130 c7 6b d8 76 d4 f3 5f 41 cb 6e 56 15 97 1b 97 c1 |.k.v.._A.nV.....|
-00000140 3c 12 39 21 66 3d 2b 16 d1 bc db 1c c0 a7 da b7 |<.9!f=+.........|
-00000150 ca ad ba da cb d5 21 50 ec de 8d ab d1 6b 81 4b |......!P.....k.K|
-00000160 89 02 f3 c4 be c1 6c 89 b1 44 84 bd 21 d1 04 7d |......l..D..!..}|
-00000170 9d 16 4d f9 82 15 f6 ef fa d6 09 47 f2 fb 02 03 |..M........G....|
-00000180 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..|
-00000190 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%|
-000001a0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........|
-000001b0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...|
-000001c0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....|
-000001d0 10 12 50 8d 89 6f 1b d1 dc 54 4d 6e cb 69 5e 06 |..P..o...TMn.i^.|
-000001e0 f4 30 1b 06 03 55 1d 23 04 14 30 12 80 10 bf 3d |.0...U.#..0....=|
-000001f0 b6 a9 66 f2 b8 40 cf ea b4 03 78 48 1a 41 30 19 |..f.. at ....xH.A0.|
-00000200 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp|
-00000210 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H|
-00000220 86 f7 0d 01 01 0b 05 00 03 81 81 00 92 7c af 91 |.............|..|
-00000230 55 12 18 96 59 31 a6 48 40 d5 2d d5 ee bb 02 a0 |U...Y1.H at .-.....|
-00000240 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 da 4f 3d c0 fa |...|..0}<.v.O=..|
-00000250 ae 2d 33 24 6b 03 7b 1b 67 59 11 21 b5 11 bc 77 |.-3$k.{.gY.!...w|
-00000260 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f 22 3e 63 10 6b |...n.-.5.d_">c.k|
-00000270 be ff 14 86 6d 0d f0 15 31 a8 14 38 1e 3b 84 87 |....m...1..8.;..|
-00000280 2c cb 98 ed 51 76 b9 b1 4f dd db 9b 84 04 86 40 |,...Qv..O......@|
-00000290 fa 51 dd ba b4 8d eb e3 46 de 46 b9 4f 86 c7 f9 |.Q......F.F.O...|
-000002a0 a4 c2 41 34 ac cc f6 ea b0 ab 39 18 16 03 01 00 |..A4......9.....|
-000002b0 04 0e 00 00 00 |.....|
+00000030 05 ff 01 00 01 00 16 03 01 02 59 0b 00 02 55 00 |..........Y...U.|
+00000040 02 52 00 02 4f 30 82 02 4b 30 82 01 b4 a0 03 02 |.R..O0..K0......|
+00000050 01 02 02 09 00 e8 f0 9d 3f e2 5b ea a6 30 0d 06 |........?.[..0..|
+00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 1f 31 0b |.*.H........0.1.|
+00000070 30 09 06 03 55 04 0a 13 02 47 6f 31 10 30 0e 06 |0...U....Go1.0..|
+00000080 03 55 04 03 13 07 47 6f 20 52 6f 6f 74 30 1e 17 |.U....Go Root0..|
+00000090 0d 31 36 30 31 30 31 30 30 30 30 30 30 5a 17 0d |.160101000000Z..|
+000000a0 32 35 30 31 30 31 30 30 30 30 30 30 5a 30 1a 31 |250101000000Z0.1|
+000000b0 0b 30 09 06 03 55 04 0a 13 02 47 6f 31 0b 30 09 |.0...U....Go1.0.|
+000000c0 06 03 55 04 03 13 02 47 6f 30 81 9f 30 0d 06 09 |..U....Go0..0...|
+000000d0 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 30 |*.H............0|
+000000e0 81 89 02 81 81 00 db 46 7d 93 2e 12 27 06 48 bc |.......F}...'.H.|
+000000f0 06 28 21 ab 7e c4 b6 a2 5d fe 1e 52 45 88 7a 36 |.(!.~...]..RE.z6|
+00000100 47 a5 08 0d 92 42 5b c2 81 c0 be 97 79 98 40 fb |G....B[.....y. at .|
+00000110 4f 6d 14 fd 2b 13 8b c2 a5 2e 67 d8 d4 09 9e d6 |Om..+.....g.....|
+00000120 22 38 b7 4a 0b 74 73 2b c2 34 f1 d1 93 e5 96 d9 |"8.J.ts+.4......|
+00000130 74 7b f3 58 9f 6c 61 3c c0 b0 41 d4 d9 2b 2b 24 |t{.X.la<..A..++$|
+00000140 23 77 5b 1c 3b bd 75 5d ce 20 54 cf a1 63 87 1d |#w[.;.u]. T..c..|
+00000150 1e 24 c4 f3 1d 1a 50 8b aa b6 14 43 ed 97 a7 75 |.$....P....C...u|
+00000160 62 f4 14 c8 52 d7 02 03 01 00 01 a3 81 93 30 81 |b...R.........0.|
+00000170 90 30 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 05 |.0...U..........|
+00000180 a0 30 1d 06 03 55 1d 25 04 16 30 14 06 08 2b 06 |.0...U.%..0...+.|
+00000190 01 05 05 07 03 01 06 08 2b 06 01 05 05 07 03 02 |........+.......|
+000001a0 30 0c 06 03 55 1d 13 01 01 ff 04 02 30 00 30 19 |0...U.......0.0.|
+000001b0 06 03 55 1d 0e 04 12 04 10 9f 91 16 1f 43 43 3e |..U..........CC>|
+000001c0 49 a6 de 6d b6 80 d7 9f 60 30 1b 06 03 55 1d 23 |I..m....`0...U.#|
+000001d0 04 14 30 12 80 10 48 13 49 4d 13 7e 16 31 bb a3 |..0...H.IM.~.1..|
+000001e0 01 d5 ac ab 6e 7b 30 19 06 03 55 1d 11 04 12 30 |....n{0...U....0|
+000001f0 10 82 0e 65 78 61 6d 70 6c 65 2e 67 6f 6c 61 6e |...example.golan|
+00000200 67 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 |g0...*.H........|
+00000210 03 81 81 00 9d 30 cc 40 2b 5b 50 a0 61 cb ba e5 |.....0. at +[P.a...|
+00000220 53 58 e1 ed 83 28 a9 58 1a a9 38 a4 95 a1 ac 31 |SX...(.X..8....1|
+00000230 5a 1a 84 66 3d 43 d3 2d d9 0b f2 97 df d3 20 64 |Z..f=C.-...... d|
+00000240 38 92 24 3a 00 bc cf 9c 7d b7 40 20 01 5f aa d3 |8.$:....}.@ ._..|
+00000250 16 61 09 a2 76 fd 13 c3 cc e1 0c 5c ee b1 87 82 |.a..v......\....|
+00000260 f1 6c 04 ed 73 bb b3 43 77 8d 0c 1c f1 0f a1 d8 |.l..s..Cw.......|
+00000270 40 83 61 c9 4c 72 2b 9d ae db 46 06 06 4d f4 c1 |@.a.Lr+...F..M..|
+00000280 b3 3e c0 d1 bd 42 d4 db fe 3d 13 60 84 5c 21 d3 |.>...B...=.`.\!.|
+00000290 3b e9 fa e7 16 03 01 00 04 0e 00 00 00 |;............|
>>> Flow 3 (client to server)
-00000000 16 03 01 00 86 10 00 00 82 00 80 6b 00 e3 47 e3 |...........k..G.|
-00000010 0d 22 44 53 7a b9 d1 14 4e e4 47 17 a1 e2 f5 d2 |."DSz...N.G.....|
-00000020 f7 82 2f 1b e2 3a 60 aa 79 36 fa 74 05 72 66 88 |../..:`.y6.t.rf.|
-00000030 3f 6a 57 8d 10 8a a1 80 3c 74 5b 29 c3 a1 b8 57 |?jW.....<t[)...W|
-00000040 20 cc 75 fc 0e 3c 09 06 46 52 b2 ca b2 cd bf 4c | .u..<..FR.....L|
-00000050 b3 12 2b 59 f1 41 a2 c7 4c 62 c7 61 26 2b 89 fe |..+Y.A..Lb.a&+..|
-00000060 01 9a b6 2b b4 15 75 05 4b f8 5b 04 9a 64 cc 06 |...+..u.K.[..d..|
-00000070 6b 8c 98 6d 51 37 50 b4 69 03 5c 9a ed e3 9a 23 |k..mQ7P.i.\....#|
-00000080 a9 68 e0 56 58 f7 f4 a0 d6 b4 55 14 03 01 00 01 |.h.VX.....U.....|
-00000090 01 16 03 01 00 28 9f ac be d9 6f ab cb 0e 45 8a |.....(....o...E.|
-000000a0 96 71 fd 23 39 b0 02 cc a6 5a 7a 64 e2 29 9f 18 |.q.#9....Zzd.)..|
-000000b0 dc 25 84 ee 76 56 3c cc d9 15 34 16 67 7e |.%..vV<...4.g~|
+00000000 16 03 01 00 86 10 00 00 82 00 80 ab 50 cd 04 9e |............P...|
+00000010 db 19 e4 18 26 ff 59 41 20 02 a5 a2 20 a3 1c 44 |....&.YA ... ..D|
+00000020 02 bc 9a 1c d9 d7 5d 5b 55 fc 2a 4d 2b 03 22 b1 |......][U.*M+.".|
+00000030 de 96 10 84 6f e3 f2 22 2d 6f cb 29 07 43 a6 6e |....o.."-o.).C.n|
+00000040 ce 23 64 f7 72 2b dc 9b c0 6f 7f bd 8e cf e2 7f |.#d.r+...o......|
+00000050 75 12 24 72 23 6b 26 08 69 76 17 c0 21 91 c0 7d |u.$r#k&.iv..!..}|
+00000060 8c 8f 20 83 08 02 0d 73 27 23 91 35 5f 3f e6 56 |.. ....s'#.5_?.V|
+00000070 1d 69 d3 1d 3b 0e fa 60 86 8b 40 ad c0 48 59 60 |.i..;..`.. at ..HY`|
+00000080 45 eb b0 77 2c 91 94 75 fd 6a d3 14 03 01 00 01 |E..w,..u.j......|
+00000090 01 16 03 01 00 28 8b 25 c1 8f 25 32 b5 cb 74 6d |.....(.%..%2..tm|
+000000a0 08 67 59 a3 ae ae 16 f9 fa 03 f6 54 42 f4 56 3f |.gY........TB.V?|
+000000b0 c4 12 66 f3 1a b0 48 95 24 79 fe 41 a5 d1 |..f...H.$y.A..|
>>> Flow 4 (server to client)
-00000000 14 03 01 00 01 01 16 03 01 00 28 f4 cf 23 f8 86 |..........(..#..|
-00000010 83 df 44 af 1c 25 b1 51 84 5b 6a f3 0e 6b 47 5c |..D..%.Q.[j..kG\|
-00000020 2a 59 67 db 42 11 f9 53 58 4e db 6f 00 b2 20 5b |*Yg.B..SXN.o.. [|
-00000030 ae a3 43 17 03 01 00 18 df e0 22 d6 05 ab 79 c7 |..C......."...y.|
-00000040 87 8a 82 83 01 bc 06 45 36 74 4d 1c 40 96 97 5f |.......E6tM. at .._|
-00000050 17 03 01 00 28 49 bd b7 e9 41 6b eb b1 aa 89 60 |....(I...Ak....`|
-00000060 21 91 df bf f4 7a 49 9d 54 04 4a 16 1a d1 44 9a |!....zI.T.J...D.|
-00000070 09 6c 4f 01 3d c0 2f d5 a3 72 a3 b2 fe 15 03 01 |.lO.=./..r......|
-00000080 00 18 5c 7a de a0 ef ed 56 99 99 01 5f b4 32 b3 |..\z....V..._.2.|
-00000090 00 be c6 cc 7e bb 6f 82 7d f7 |....~.o.}.|
+00000000 14 03 01 00 01 01 16 03 01 00 28 ff 69 ed 0f 20 |..........(.i.. |
+00000010 ff e1 42 78 b9 bc a8 61 48 82 08 a0 01 a5 98 91 |..Bx...aH.......|
+00000020 3e 39 d4 6d 17 38 a2 04 18 ed 90 3c f0 cf 6a 9a |>9.m.8.....<..j.|
+00000030 ea c5 45 17 03 01 00 18 b5 76 2c 0e f1 34 51 e5 |..E......v,..4Q.|
+00000040 f5 38 d3 9f c9 c5 d5 19 35 c3 2e ec 18 df 8e c8 |.8......5.......|
+00000050 17 03 01 00 28 47 6f e9 c0 fa b3 21 ec 6c 16 e7 |....(Go....!.l..|
+00000060 71 a8 09 15 17 86 68 1c cf fa ea 37 68 d3 33 ef |q.....h....7h.3.|
+00000070 4a b1 95 46 5b 16 d7 95 f8 13 65 2f 93 15 03 01 |J..F[.....e/....|
+00000080 00 18 1b 0c 09 81 ff fc 6d 82 84 ab 83 98 fc 72 |........m......r|
+00000090 f5 4a a0 eb 08 96 79 01 76 26 |.J....y.v&|
diff --git a/src/crypto/tls/testdata/Server-TLSv10-RSA-AES b/src/crypto/tls/testdata/Server-TLSv10-RSA-AES
index e51bc17..c175029 100644
--- a/src/crypto/tls/testdata/Server-TLSv10-RSA-AES
+++ b/src/crypto/tls/testdata/Server-TLSv10-RSA-AES
@@ -1,77 +1,75 @@
>>> Flow 1 (client to server)
-00000000 16 03 01 00 37 01 00 00 33 03 01 39 72 8e 06 ed |....7...3..9r...|
-00000010 d2 74 5c 02 74 0e 2b 7a bd 54 ce be 17 a0 4f 1a |.t\.t.+z.T....O.|
-00000020 c5 72 b1 e8 3e 2e 90 68 ff fc 6e 00 00 04 00 2f |.r..>..h..n..../|
-00000030 00 ff 02 01 00 00 05 00 0f 00 01 01 |............|
+00000000 16 03 01 00 39 01 00 00 35 03 01 82 f3 04 d5 71 |....9...5......q|
+00000010 d8 65 69 36 46 cb 45 77 b2 ef 00 75 98 e4 16 d2 |.ei6F.Ew...u....|
+00000020 70 f7 3c 97 84 49 ef da 5d cd 64 00 00 04 00 2f |p.<..I..].d..../|
+00000030 00 ff 01 00 00 08 00 16 00 00 00 17 00 00 |..............|
>>> Flow 2 (server to client)
00000000 16 03 01 00 31 02 00 00 2d 03 01 00 00 00 00 00 |....1...-.......|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2f 00 00 |............./..|
-00000030 05 ff 01 00 01 00 16 03 01 02 71 0b 00 02 6d 00 |..........q...m.|
-00000040 02 6a 00 02 67 30 82 02 63 30 82 01 cc a0 03 02 |.j..g0..c0......|
-00000050 01 02 02 09 00 a2 73 00 0c 81 00 cb f3 30 0d 06 |......s......0..|
-00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 2b 31 17 |.*.H........0+1.|
-00000070 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 |0...U....Google |
-00000080 54 45 53 54 49 4e 47 31 10 30 0e 06 03 55 04 03 |TESTING1.0...U..|
-00000090 13 07 47 6f 20 52 6f 6f 74 30 1e 17 0d 31 35 30 |..Go Root0...150|
-000000a0 31 30 31 30 30 30 30 30 30 5a 17 0d 32 35 30 31 |101000000Z..2501|
-000000b0 30 31 30 30 30 30 30 30 5a 30 26 31 17 30 15 06 |01000000Z0&1.0..|
-000000c0 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 54 45 53 |.U....Google TES|
-000000d0 54 49 4e 47 31 0b 30 09 06 03 55 04 03 13 02 47 |TING1.0...U....G|
-000000e0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....|
-000000f0 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 af 87 |.......0........|
-00000100 88 f6 20 1b 95 65 6c 14 ab 44 05 af 3b 45 14 e3 |.. ..el..D..;E..|
-00000110 b7 6d fd 00 63 4d 95 7f fe 6a 62 35 86 c0 4a f9 |.m..cM...jb5..J.|
-00000120 18 7c f6 aa 25 5e 7a 64 31 66 00 ba f4 8e 92 af |.|..%^zd1f......|
-00000130 c7 6b d8 76 d4 f3 5f 41 cb 6e 56 15 97 1b 97 c1 |.k.v.._A.nV.....|
-00000140 3c 12 39 21 66 3d 2b 16 d1 bc db 1c c0 a7 da b7 |<.9!f=+.........|
-00000150 ca ad ba da cb d5 21 50 ec de 8d ab d1 6b 81 4b |......!P.....k.K|
-00000160 89 02 f3 c4 be c1 6c 89 b1 44 84 bd 21 d1 04 7d |......l..D..!..}|
-00000170 9d 16 4d f9 82 15 f6 ef fa d6 09 47 f2 fb 02 03 |..M........G....|
-00000180 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..|
-00000190 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%|
-000001a0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........|
-000001b0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...|
-000001c0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....|
-000001d0 10 12 50 8d 89 6f 1b d1 dc 54 4d 6e cb 69 5e 06 |..P..o...TMn.i^.|
-000001e0 f4 30 1b 06 03 55 1d 23 04 14 30 12 80 10 bf 3d |.0...U.#..0....=|
-000001f0 b6 a9 66 f2 b8 40 cf ea b4 03 78 48 1a 41 30 19 |..f.. at ....xH.A0.|
-00000200 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp|
-00000210 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H|
-00000220 86 f7 0d 01 01 0b 05 00 03 81 81 00 92 7c af 91 |.............|..|
-00000230 55 12 18 96 59 31 a6 48 40 d5 2d d5 ee bb 02 a0 |U...Y1.H at .-.....|
-00000240 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 da 4f 3d c0 fa |...|..0}<.v.O=..|
-00000250 ae 2d 33 24 6b 03 7b 1b 67 59 11 21 b5 11 bc 77 |.-3$k.{.gY.!...w|
-00000260 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f 22 3e 63 10 6b |...n.-.5.d_">c.k|
-00000270 be ff 14 86 6d 0d f0 15 31 a8 14 38 1e 3b 84 87 |....m...1..8.;..|
-00000280 2c cb 98 ed 51 76 b9 b1 4f dd db 9b 84 04 86 40 |,...Qv..O......@|
-00000290 fa 51 dd ba b4 8d eb e3 46 de 46 b9 4f 86 c7 f9 |.Q......F.F.O...|
-000002a0 a4 c2 41 34 ac cc f6 ea b0 ab 39 18 16 03 01 00 |..A4......9.....|
-000002b0 04 0e 00 00 00 |.....|
+00000030 05 ff 01 00 01 00 16 03 01 02 59 0b 00 02 55 00 |..........Y...U.|
+00000040 02 52 00 02 4f 30 82 02 4b 30 82 01 b4 a0 03 02 |.R..O0..K0......|
+00000050 01 02 02 09 00 e8 f0 9d 3f e2 5b ea a6 30 0d 06 |........?.[..0..|
+00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 1f 31 0b |.*.H........0.1.|
+00000070 30 09 06 03 55 04 0a 13 02 47 6f 31 10 30 0e 06 |0...U....Go1.0..|
+00000080 03 55 04 03 13 07 47 6f 20 52 6f 6f 74 30 1e 17 |.U....Go Root0..|
+00000090 0d 31 36 30 31 30 31 30 30 30 30 30 30 5a 17 0d |.160101000000Z..|
+000000a0 32 35 30 31 30 31 30 30 30 30 30 30 5a 30 1a 31 |250101000000Z0.1|
+000000b0 0b 30 09 06 03 55 04 0a 13 02 47 6f 31 0b 30 09 |.0...U....Go1.0.|
+000000c0 06 03 55 04 03 13 02 47 6f 30 81 9f 30 0d 06 09 |..U....Go0..0...|
+000000d0 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 30 |*.H............0|
+000000e0 81 89 02 81 81 00 db 46 7d 93 2e 12 27 06 48 bc |.......F}...'.H.|
+000000f0 06 28 21 ab 7e c4 b6 a2 5d fe 1e 52 45 88 7a 36 |.(!.~...]..RE.z6|
+00000100 47 a5 08 0d 92 42 5b c2 81 c0 be 97 79 98 40 fb |G....B[.....y. at .|
+00000110 4f 6d 14 fd 2b 13 8b c2 a5 2e 67 d8 d4 09 9e d6 |Om..+.....g.....|
+00000120 22 38 b7 4a 0b 74 73 2b c2 34 f1 d1 93 e5 96 d9 |"8.J.ts+.4......|
+00000130 74 7b f3 58 9f 6c 61 3c c0 b0 41 d4 d9 2b 2b 24 |t{.X.la<..A..++$|
+00000140 23 77 5b 1c 3b bd 75 5d ce 20 54 cf a1 63 87 1d |#w[.;.u]. T..c..|
+00000150 1e 24 c4 f3 1d 1a 50 8b aa b6 14 43 ed 97 a7 75 |.$....P....C...u|
+00000160 62 f4 14 c8 52 d7 02 03 01 00 01 a3 81 93 30 81 |b...R.........0.|
+00000170 90 30 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 05 |.0...U..........|
+00000180 a0 30 1d 06 03 55 1d 25 04 16 30 14 06 08 2b 06 |.0...U.%..0...+.|
+00000190 01 05 05 07 03 01 06 08 2b 06 01 05 05 07 03 02 |........+.......|
+000001a0 30 0c 06 03 55 1d 13 01 01 ff 04 02 30 00 30 19 |0...U.......0.0.|
+000001b0 06 03 55 1d 0e 04 12 04 10 9f 91 16 1f 43 43 3e |..U..........CC>|
+000001c0 49 a6 de 6d b6 80 d7 9f 60 30 1b 06 03 55 1d 23 |I..m....`0...U.#|
+000001d0 04 14 30 12 80 10 48 13 49 4d 13 7e 16 31 bb a3 |..0...H.IM.~.1..|
+000001e0 01 d5 ac ab 6e 7b 30 19 06 03 55 1d 11 04 12 30 |....n{0...U....0|
+000001f0 10 82 0e 65 78 61 6d 70 6c 65 2e 67 6f 6c 61 6e |...example.golan|
+00000200 67 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 |g0...*.H........|
+00000210 03 81 81 00 9d 30 cc 40 2b 5b 50 a0 61 cb ba e5 |.....0. at +[P.a...|
+00000220 53 58 e1 ed 83 28 a9 58 1a a9 38 a4 95 a1 ac 31 |SX...(.X..8....1|
+00000230 5a 1a 84 66 3d 43 d3 2d d9 0b f2 97 df d3 20 64 |Z..f=C.-...... d|
+00000240 38 92 24 3a 00 bc cf 9c 7d b7 40 20 01 5f aa d3 |8.$:....}.@ ._..|
+00000250 16 61 09 a2 76 fd 13 c3 cc e1 0c 5c ee b1 87 82 |.a..v......\....|
+00000260 f1 6c 04 ed 73 bb b3 43 77 8d 0c 1c f1 0f a1 d8 |.l..s..Cw.......|
+00000270 40 83 61 c9 4c 72 2b 9d ae db 46 06 06 4d f4 c1 |@.a.Lr+...F..M..|
+00000280 b3 3e c0 d1 bd 42 d4 db fe 3d 13 60 84 5c 21 d3 |.>...B...=.`.\!.|
+00000290 3b e9 fa e7 16 03 01 00 04 0e 00 00 00 |;............|
>>> Flow 3 (client to server)
-00000000 16 03 01 00 86 10 00 00 82 00 80 0e a2 23 fe 89 |.............#..|
-00000010 46 08 20 98 da 4d 91 a4 48 40 ab 03 df 1f 00 67 |F. ..M..H at .....g|
-00000020 f3 fb fb 22 f7 8e d6 65 2c 43 a7 f4 9c 0e 25 cc |..."...e,C....%.|
-00000030 d9 3b b5 58 df bd 93 27 1c df 69 37 27 01 cb 0d |.;.X...'..i7'...|
-00000040 b4 f4 a6 8d 91 fe ef dc 9a e2 09 7c 53 1a 73 6d |...........|S.sm|
-00000050 b9 f6 89 0a 1f 94 f0 26 25 ef 73 54 20 d5 8d 77 |.......&%.sT ..w|
-00000060 36 2e e7 4c 9a f1 4a be ae 6e b6 be 16 10 31 42 |6..L..J..n....1B|
-00000070 9e d2 49 41 2c 32 52 11 bc 85 2d fa 39 80 9b f9 |..IA,2R...-.9...|
-00000080 95 fe e8 88 2a a2 57 65 7e 38 b2 14 03 01 00 01 |....*.We~8......|
-00000090 01 16 03 01 00 30 1c 6f 91 45 16 ed 25 82 ee 5f |.....0.o.E..%.._|
-000000a0 f9 f0 09 0c a4 ad 56 61 e5 b7 a2 05 50 02 b8 80 |......Va....P...|
-000000b0 ef 73 d1 11 3c 25 50 44 0d ba b5 7c fd 5d 7a df |.s..<%PD...|.]z.|
-000000c0 14 62 1b 29 be 29 |.b.).)|
+00000000 16 03 01 00 86 10 00 00 82 00 80 9c a1 18 77 22 |..............w"|
+00000010 f5 a1 cf 4d cc df 27 7c c5 7e 98 24 24 be 2f b2 |...M..'|.~.$$./.|
+00000020 1d d7 b8 2f fe 90 73 d0 fc f6 88 3c 91 a4 bc dc |.../..s....<....|
+00000030 b9 0b 48 0d 55 e5 9f c1 8a 6c 1c 7d 4d a9 12 d5 |..H.U....l.}M...|
+00000040 87 4b 9a 77 74 3d 33 8c c7 17 fb 32 09 df 86 f1 |.K.wt=3....2....|
+00000050 93 cc 17 f9 08 bd bc 0e 38 df 9d 82 ad cc 70 0c |........8.....p.|
+00000060 f5 8b 8d 99 e8 5f 3e e5 a6 c7 c2 6a 67 02 90 82 |....._>....jg...|
+00000070 28 9a 72 e1 3e 77 51 10 84 29 21 09 56 36 f2 6a |(.r.>wQ..)!.V6.j|
+00000080 1d 15 08 7b 44 41 43 59 55 8d 52 14 03 01 00 01 |...{DACYU.R.....|
+00000090 01 16 03 01 00 30 06 5b 20 42 7e 7b 1f 4b 7c 36 |.....0.[ B~{.K|6|
+000000a0 99 bb c6 b4 ea a1 19 3e 02 0c 3b 3a 38 be 80 11 |.......>..;:8...|
+000000b0 29 72 a8 12 92 ad 24 9d bf 01 3e ef 9a f1 db 33 |)r....$...>....3|
+000000c0 3e c1 dc d2 51 b1 |>...Q.|
>>> Flow 4 (server to client)
-00000000 14 03 01 00 01 01 16 03 01 00 30 5e 8c b1 dc 1f |..........0^....|
-00000010 b3 18 85 4a 46 02 fb 34 e4 05 56 78 4c e3 34 63 |...JF..4..VxL.4c|
-00000020 06 08 b4 ee 36 e2 28 ab c9 98 ee 26 4e 5b 5d 42 |....6.(....&N[]B|
-00000030 5f f8 e1 d1 2f 8b c8 ef 5a 65 40 17 03 01 00 20 |_.../...Ze at .... |
-00000040 e7 92 6e b1 60 b9 f8 cd 53 d3 37 5b 44 74 1c af |..n.`...S.7[Dt..|
-00000050 90 93 13 8e 55 25 cc 9f 57 8c f3 06 f7 ba e0 f9 |....U%..W.......|
-00000060 17 03 01 00 30 fc 83 e6 4e 8c 65 8f d1 7c c7 f4 |....0...N.e..|..|
-00000070 8b 68 0d 5d da 8e 49 45 68 ea 4c e3 7f 7d 84 87 |.h.]..IEh.L..}..|
-00000080 2f 63 e0 fb 43 24 04 cd e2 38 32 50 0a 4c 43 ce |/c..C$...82P.LC.|
-00000090 3b 12 a5 6b 99 15 03 01 00 20 2a 42 d8 57 26 79 |;..k..... *B.W&y|
-000000a0 51 ee 79 9d b2 83 b8 49 a4 e9 a2 08 34 73 c4 f5 |Q.y....I....4s..|
-000000b0 53 21 4b 78 ec 5b ce b4 4e a0 |S!Kx.[..N.|
+00000000 14 03 01 00 01 01 16 03 01 00 30 2e d5 04 91 6d |..........0....m|
+00000010 32 12 8b 41 4a 46 2c f3 7f d4 16 0a 21 c2 ac 88 |2..AJF,.....!...|
+00000020 09 a0 b5 0d 65 4e 44 e1 92 5a ae b8 3f 61 1f 35 |....eND..Z..?a.5|
+00000030 ab 3a fe bd f8 3c 2c 42 dd 68 0f 17 03 01 00 20 |.:...<,B.h..... |
+00000040 6e d4 08 98 bf b7 18 84 ee 68 f8 17 88 c5 13 7a |n........h.....z|
+00000050 73 e0 c6 ca 0d 21 4d 6b 44 dc 94 36 6c e4 a0 2f |s....!MkD..6l../|
+00000060 17 03 01 00 30 a0 45 d0 88 5d 96 48 26 46 37 33 |....0.E..].H&F73|
+00000070 f6 48 f3 38 2e 38 d7 b6 ef d5 25 bf f3 1b b6 78 |.H.8.8....%....x|
+00000080 32 a7 9c fe be 55 35 f2 07 5b b7 14 87 89 80 f2 |2....U5..[......|
+00000090 cc d5 cb c8 57 15 03 01 00 20 80 2a 8e 6c b8 5a |....W.... .*.l.Z|
+000000a0 41 b4 ae 56 ca 3f 8b a2 e1 ea a0 55 64 b5 60 44 |A..V.?.....Ud.`D|
+000000b0 8f de 33 c6 37 f7 df b5 d9 c3 |..3.7.....|
diff --git a/src/crypto/tls/testdata/Server-TLSv10-RSA-RC4 b/src/crypto/tls/testdata/Server-TLSv10-RSA-RC4
index 8d54463..3d788c3 100644
--- a/src/crypto/tls/testdata/Server-TLSv10-RSA-RC4
+++ b/src/crypto/tls/testdata/Server-TLSv10-RSA-RC4
@@ -1,71 +1,69 @@
>>> Flow 1 (client to server)
-00000000 16 03 01 00 37 01 00 00 33 03 01 b3 82 99 50 b0 |....7...3.....P.|
-00000010 1e 7a 46 48 9d 8e 93 32 3b 01 bc 50 e9 5c eb 91 |.zFH...2;..P.\..|
-00000020 25 4b c1 ea 0a 91 c9 b3 2b 54 90 00 00 04 00 05 |%K......+T......|
-00000030 00 ff 02 01 00 00 05 00 0f 00 01 01 |............|
+00000000 16 03 01 00 39 01 00 00 35 03 01 71 34 00 f7 c4 |....9...5..q4...|
+00000010 e6 94 b4 ca f2 af d5 0a 82 ce d4 f6 b7 4a a7 d1 |.............J..|
+00000020 1a 88 65 b2 3c b2 6c ec f7 eb 4a 00 00 04 00 05 |..e.<.l...J.....|
+00000030 00 ff 01 00 00 08 00 16 00 00 00 17 00 00 |..............|
>>> Flow 2 (server to client)
00000000 16 03 01 00 31 02 00 00 2d 03 01 00 00 00 00 00 |....1...-.......|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 05 00 00 |................|
-00000030 05 ff 01 00 01 00 16 03 01 02 71 0b 00 02 6d 00 |..........q...m.|
-00000040 02 6a 00 02 67 30 82 02 63 30 82 01 cc a0 03 02 |.j..g0..c0......|
-00000050 01 02 02 09 00 a2 73 00 0c 81 00 cb f3 30 0d 06 |......s......0..|
-00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 2b 31 17 |.*.H........0+1.|
-00000070 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 |0...U....Google |
-00000080 54 45 53 54 49 4e 47 31 10 30 0e 06 03 55 04 03 |TESTING1.0...U..|
-00000090 13 07 47 6f 20 52 6f 6f 74 30 1e 17 0d 31 35 30 |..Go Root0...150|
-000000a0 31 30 31 30 30 30 30 30 30 5a 17 0d 32 35 30 31 |101000000Z..2501|
-000000b0 30 31 30 30 30 30 30 30 5a 30 26 31 17 30 15 06 |01000000Z0&1.0..|
-000000c0 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 54 45 53 |.U....Google TES|
-000000d0 54 49 4e 47 31 0b 30 09 06 03 55 04 03 13 02 47 |TING1.0...U....G|
-000000e0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....|
-000000f0 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 af 87 |.......0........|
-00000100 88 f6 20 1b 95 65 6c 14 ab 44 05 af 3b 45 14 e3 |.. ..el..D..;E..|
-00000110 b7 6d fd 00 63 4d 95 7f fe 6a 62 35 86 c0 4a f9 |.m..cM...jb5..J.|
-00000120 18 7c f6 aa 25 5e 7a 64 31 66 00 ba f4 8e 92 af |.|..%^zd1f......|
-00000130 c7 6b d8 76 d4 f3 5f 41 cb 6e 56 15 97 1b 97 c1 |.k.v.._A.nV.....|
-00000140 3c 12 39 21 66 3d 2b 16 d1 bc db 1c c0 a7 da b7 |<.9!f=+.........|
-00000150 ca ad ba da cb d5 21 50 ec de 8d ab d1 6b 81 4b |......!P.....k.K|
-00000160 89 02 f3 c4 be c1 6c 89 b1 44 84 bd 21 d1 04 7d |......l..D..!..}|
-00000170 9d 16 4d f9 82 15 f6 ef fa d6 09 47 f2 fb 02 03 |..M........G....|
-00000180 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..|
-00000190 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%|
-000001a0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........|
-000001b0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...|
-000001c0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....|
-000001d0 10 12 50 8d 89 6f 1b d1 dc 54 4d 6e cb 69 5e 06 |..P..o...TMn.i^.|
-000001e0 f4 30 1b 06 03 55 1d 23 04 14 30 12 80 10 bf 3d |.0...U.#..0....=|
-000001f0 b6 a9 66 f2 b8 40 cf ea b4 03 78 48 1a 41 30 19 |..f.. at ....xH.A0.|
-00000200 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp|
-00000210 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H|
-00000220 86 f7 0d 01 01 0b 05 00 03 81 81 00 92 7c af 91 |.............|..|
-00000230 55 12 18 96 59 31 a6 48 40 d5 2d d5 ee bb 02 a0 |U...Y1.H at .-.....|
-00000240 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 da 4f 3d c0 fa |...|..0}<.v.O=..|
-00000250 ae 2d 33 24 6b 03 7b 1b 67 59 11 21 b5 11 bc 77 |.-3$k.{.gY.!...w|
-00000260 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f 22 3e 63 10 6b |...n.-.5.d_">c.k|
-00000270 be ff 14 86 6d 0d f0 15 31 a8 14 38 1e 3b 84 87 |....m...1..8.;..|
-00000280 2c cb 98 ed 51 76 b9 b1 4f dd db 9b 84 04 86 40 |,...Qv..O......@|
-00000290 fa 51 dd ba b4 8d eb e3 46 de 46 b9 4f 86 c7 f9 |.Q......F.F.O...|
-000002a0 a4 c2 41 34 ac cc f6 ea b0 ab 39 18 16 03 01 00 |..A4......9.....|
-000002b0 04 0e 00 00 00 |.....|
+00000030 05 ff 01 00 01 00 16 03 01 02 59 0b 00 02 55 00 |..........Y...U.|
+00000040 02 52 00 02 4f 30 82 02 4b 30 82 01 b4 a0 03 02 |.R..O0..K0......|
+00000050 01 02 02 09 00 e8 f0 9d 3f e2 5b ea a6 30 0d 06 |........?.[..0..|
+00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 1f 31 0b |.*.H........0.1.|
+00000070 30 09 06 03 55 04 0a 13 02 47 6f 31 10 30 0e 06 |0...U....Go1.0..|
+00000080 03 55 04 03 13 07 47 6f 20 52 6f 6f 74 30 1e 17 |.U....Go Root0..|
+00000090 0d 31 36 30 31 30 31 30 30 30 30 30 30 5a 17 0d |.160101000000Z..|
+000000a0 32 35 30 31 30 31 30 30 30 30 30 30 5a 30 1a 31 |250101000000Z0.1|
+000000b0 0b 30 09 06 03 55 04 0a 13 02 47 6f 31 0b 30 09 |.0...U....Go1.0.|
+000000c0 06 03 55 04 03 13 02 47 6f 30 81 9f 30 0d 06 09 |..U....Go0..0...|
+000000d0 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 30 |*.H............0|
+000000e0 81 89 02 81 81 00 db 46 7d 93 2e 12 27 06 48 bc |.......F}...'.H.|
+000000f0 06 28 21 ab 7e c4 b6 a2 5d fe 1e 52 45 88 7a 36 |.(!.~...]..RE.z6|
+00000100 47 a5 08 0d 92 42 5b c2 81 c0 be 97 79 98 40 fb |G....B[.....y. at .|
+00000110 4f 6d 14 fd 2b 13 8b c2 a5 2e 67 d8 d4 09 9e d6 |Om..+.....g.....|
+00000120 22 38 b7 4a 0b 74 73 2b c2 34 f1 d1 93 e5 96 d9 |"8.J.ts+.4......|
+00000130 74 7b f3 58 9f 6c 61 3c c0 b0 41 d4 d9 2b 2b 24 |t{.X.la<..A..++$|
+00000140 23 77 5b 1c 3b bd 75 5d ce 20 54 cf a1 63 87 1d |#w[.;.u]. T..c..|
+00000150 1e 24 c4 f3 1d 1a 50 8b aa b6 14 43 ed 97 a7 75 |.$....P....C...u|
+00000160 62 f4 14 c8 52 d7 02 03 01 00 01 a3 81 93 30 81 |b...R.........0.|
+00000170 90 30 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 05 |.0...U..........|
+00000180 a0 30 1d 06 03 55 1d 25 04 16 30 14 06 08 2b 06 |.0...U.%..0...+.|
+00000190 01 05 05 07 03 01 06 08 2b 06 01 05 05 07 03 02 |........+.......|
+000001a0 30 0c 06 03 55 1d 13 01 01 ff 04 02 30 00 30 19 |0...U.......0.0.|
+000001b0 06 03 55 1d 0e 04 12 04 10 9f 91 16 1f 43 43 3e |..U..........CC>|
+000001c0 49 a6 de 6d b6 80 d7 9f 60 30 1b 06 03 55 1d 23 |I..m....`0...U.#|
+000001d0 04 14 30 12 80 10 48 13 49 4d 13 7e 16 31 bb a3 |..0...H.IM.~.1..|
+000001e0 01 d5 ac ab 6e 7b 30 19 06 03 55 1d 11 04 12 30 |....n{0...U....0|
+000001f0 10 82 0e 65 78 61 6d 70 6c 65 2e 67 6f 6c 61 6e |...example.golan|
+00000200 67 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 |g0...*.H........|
+00000210 03 81 81 00 9d 30 cc 40 2b 5b 50 a0 61 cb ba e5 |.....0. at +[P.a...|
+00000220 53 58 e1 ed 83 28 a9 58 1a a9 38 a4 95 a1 ac 31 |SX...(.X..8....1|
+00000230 5a 1a 84 66 3d 43 d3 2d d9 0b f2 97 df d3 20 64 |Z..f=C.-...... d|
+00000240 38 92 24 3a 00 bc cf 9c 7d b7 40 20 01 5f aa d3 |8.$:....}.@ ._..|
+00000250 16 61 09 a2 76 fd 13 c3 cc e1 0c 5c ee b1 87 82 |.a..v......\....|
+00000260 f1 6c 04 ed 73 bb b3 43 77 8d 0c 1c f1 0f a1 d8 |.l..s..Cw.......|
+00000270 40 83 61 c9 4c 72 2b 9d ae db 46 06 06 4d f4 c1 |@.a.Lr+...F..M..|
+00000280 b3 3e c0 d1 bd 42 d4 db fe 3d 13 60 84 5c 21 d3 |.>...B...=.`.\!.|
+00000290 3b e9 fa e7 16 03 01 00 04 0e 00 00 00 |;............|
>>> Flow 3 (client to server)
-00000000 16 03 01 00 86 10 00 00 82 00 80 05 1c 93 2a 69 |..............*i|
-00000010 f7 0b 1d 59 ea ca c2 4a b1 7c ef 22 4c 7b 31 5f |...Y...J.|."L{1_|
-00000020 18 8d 32 b6 db 75 8c f8 45 07 27 e1 9f 3f 9d 0b |..2..u..E.'..?..|
-00000030 02 ac 2c 3f aa bf 79 fb d4 af 98 0c b2 c0 03 4b |..,?..y........K|
-00000040 86 26 c3 30 f3 ea 2b 1a ab 70 90 8d 01 2b 0e ff |.&.0..+..p...+..|
-00000050 4c 10 9a 29 75 cb 14 bb 85 80 98 35 fb 82 e8 b5 |L..)u......5....|
-00000060 80 6f 9d e6 3b b6 14 36 bb 61 8e 18 f2 6b da 09 |.o..;..6.a...k..|
-00000070 71 9c 6d 1e c3 60 a9 c5 8b 4e 77 41 db ec 12 49 |q.m..`...NwA...I|
-00000080 a4 c2 e2 10 ce 7f 18 05 b9 74 aa 14 03 01 00 01 |.........t......|
-00000090 01 16 03 01 00 24 3d 90 d0 f6 6f 15 94 05 a0 fb |.....$=...o.....|
-000000a0 43 83 55 b5 b1 ef e5 fd fc 00 d3 d5 25 b4 7c 9f |C.U.........%.|.|
-000000b0 e0 82 99 2a 6d 5a 26 7c 05 21 |...*mZ&|.!|
+00000000 16 03 01 00 86 10 00 00 82 00 80 a5 75 5a 20 2c |............uZ ,|
+00000010 31 f7 61 dc 73 c7 f6 4c 06 d2 b9 c0 e8 5f cc 0c |1.a.s..L....._..|
+00000020 51 70 0a 30 b2 8a bb 3b 4c 37 f6 d3 38 da 13 48 |Qp.0...;L7..8..H|
+00000030 90 4f fe 41 ec 53 3c fb 07 26 77 68 07 a0 fb 71 |.O.A.S<..&wh...q|
+00000040 b6 cc 3c cd b4 64 03 08 3a 76 97 6e 6c f1 b4 a9 |..<..d..:v.nl...|
+00000050 af f4 e0 ce bf 36 b9 8e 37 12 de 5b ac 24 06 63 |.....6..7..[.$.c|
+00000060 e2 fb 13 33 be 3b 8d 93 e3 10 95 29 21 b2 22 77 |...3.;.....)!."w|
+00000070 cb 95 b2 13 b3 76 47 98 13 1b a8 cc 50 47 ed 50 |.....vG.....PG.P|
+00000080 f0 cc ca 5a c6 a0 1e c9 9c 97 58 14 03 01 00 01 |...Z......X.....|
+00000090 01 16 03 01 00 24 e7 fd a2 7e fd 6f 53 da 29 68 |.....$...~.oS.)h|
+000000a0 c3 49 2e e9 69 a1 94 b9 e4 a0 cb a2 94 14 a6 42 |.I..i..........B|
+000000b0 df 75 1e da 95 e5 60 e3 35 f1 |.u....`.5.|
>>> Flow 4 (server to client)
-00000000 14 03 01 00 01 01 16 03 01 00 24 28 d0 1f ec 1d |..........$(....|
-00000010 9e 1d e3 80 6b 6d 3e 8b c5 f7 9c 14 a9 0b c3 53 |....km>........S|
-00000020 fd 48 d0 b3 eb d1 49 97 97 71 e9 36 b9 e6 3a 17 |.H....I..q.6..:.|
-00000030 03 01 00 21 c3 b6 2e 02 05 86 0f 57 04 dd 88 33 |...!.......W...3|
-00000040 0a ed 1d d5 a8 0f 55 54 c5 8c 87 5b 11 b7 80 7f |......UT...[....|
-00000050 30 79 e0 64 ee 15 03 01 00 16 b1 50 de 3d 18 05 |0y.d.......P.=..|
-00000060 2f db 37 4c db 62 f1 c8 d5 19 ca c2 fb a5 8a 37 |/.7L.b.........7|
+00000000 14 03 01 00 01 01 16 03 01 00 24 44 a6 c8 7b 5f |..........$D..{_|
+00000010 b9 4e c2 62 2d e0 c3 9f 76 0f b3 e5 f5 07 b7 c0 |.N.b-...v.......|
+00000020 93 cd 1f 32 3c 0a 7a 83 57 4a 24 59 ac 95 f9 17 |...2<.z.WJ$Y....|
+00000030 03 01 00 21 6f 02 76 2e 70 82 a0 6c 11 ce 3c b8 |...!o.v.p..l..<.|
+00000040 dd d3 9e 2a ee ce d7 7f 63 1a 5b 35 d0 46 68 7d |...*....c.[5.Fh}|
+00000050 21 6e 5b 64 fc 15 03 01 00 16 81 56 32 7d 51 e4 |!n[d.......V2}Q.|
+00000060 08 53 85 45 65 c3 87 ac b0 58 70 4f 6f f7 64 4e |.S.Ee....XpOo.dN|
diff --git a/src/crypto/tls/testdata/Server-TLSv11-FallbackSCSV b/src/crypto/tls/testdata/Server-TLSv11-FallbackSCSV
index a6e2137..209e621 100644
--- a/src/crypto/tls/testdata/Server-TLSv11-FallbackSCSV
+++ b/src/crypto/tls/testdata/Server-TLSv11-FallbackSCSV
@@ -1,17 +1,10 @@
>>> Flow 1 (client to server)
-00000000 16 03 01 00 cf 01 00 00 cb 03 02 ee 33 c1 3f a6 |............3.?.|
-00000010 62 ba a6 4f c7 32 25 0f 15 66 f7 35 a2 cf c0 cd |b..O.2%..f.5....|
-00000020 48 93 77 1c 04 1f fb 65 41 37 ca 00 00 70 c0 14 |H.w....eA7...p..|
-00000030 c0 0a 00 39 00 38 00 37 00 36 00 88 00 87 00 86 |...9.8.7.6......|
-00000040 00 85 c0 0f c0 05 00 35 00 84 c0 13 c0 09 00 33 |.......5.......3|
-00000050 00 32 00 31 00 30 00 9a 00 99 00 98 00 97 00 45 |.2.1.0.........E|
-00000060 00 44 00 43 00 42 c0 0e c0 04 00 2f 00 96 00 41 |.D.C.B...../...A|
-00000070 00 07 c0 11 c0 07 c0 0c c0 02 00 05 00 04 c0 12 |................|
-00000080 c0 08 00 16 00 13 00 10 00 0d c0 0d c0 03 00 0a |................|
-00000090 00 15 00 12 00 0f 00 0c 00 09 00 ff 56 00 02 01 |............V...|
-000000a0 00 00 31 00 0b 00 04 03 00 01 02 00 0a 00 1c 00 |..1.............|
-000000b0 1a 00 17 00 19 00 1c 00 1b 00 18 00 1a 00 16 00 |................|
-000000c0 0e 00 0d 00 0b 00 0c 00 09 00 0a 00 23 00 00 00 |............#...|
-000000d0 0f 00 01 01 |....|
+00000000 16 03 01 00 63 01 00 00 5f 03 02 6e 78 cc 6a ea |....c..._..nx.j.|
+00000010 13 aa a8 20 76 7d 32 ca c7 3f be 88 36 ae fb c3 |... v}2..?..6...|
+00000020 ca 95 35 70 54 20 3b 18 3b ba 82 00 00 14 c0 0a |..5pT ;.;.......|
+00000030 c0 14 00 39 c0 09 c0 13 00 33 00 35 00 2f 00 ff |...9.....3.5./..|
+00000040 56 00 01 00 00 22 00 0b 00 04 03 00 01 02 00 0a |V...."..........|
+00000050 00 0a 00 08 00 1d 00 17 00 19 00 18 00 23 00 00 |.............#..|
+00000060 00 16 00 00 00 17 00 00 |........|
>>> Flow 2 (server to client)
00000000 15 03 02 00 02 02 56 |......V|
diff --git a/src/crypto/tls/testdata/Server-TLSv11-RSA-RC4 b/src/crypto/tls/testdata/Server-TLSv11-RSA-RC4
index b3916f9..18debc4 100644
--- a/src/crypto/tls/testdata/Server-TLSv11-RSA-RC4
+++ b/src/crypto/tls/testdata/Server-TLSv11-RSA-RC4
@@ -1,71 +1,69 @@
>>> Flow 1 (client to server)
-00000000 16 03 01 00 37 01 00 00 33 03 02 95 4a cf f5 14 |....7...3...J...|
-00000010 56 9b d6 be 0c ba 0d b2 ad 65 47 d2 c6 ce 84 c9 |V........eG.....|
-00000020 f4 80 2a 4e 75 df ff 48 cf 48 9b 00 00 04 00 05 |..*Nu..H.H......|
-00000030 00 ff 02 01 00 00 05 00 0f 00 01 01 |............|
+00000000 16 03 01 00 39 01 00 00 35 03 02 15 67 73 bf 3f |....9...5...gs.?|
+00000010 6f 15 30 c2 34 2e c6 1b 23 3a 42 45 4d d9 87 a2 |o.0.4...#:BEM...|
+00000020 e7 b8 de 1c b8 2b cc 21 7a 0b a1 00 00 04 00 05 |.....+.!z.......|
+00000030 00 ff 01 00 00 08 00 16 00 00 00 17 00 00 |..............|
>>> Flow 2 (server to client)
00000000 16 03 02 00 31 02 00 00 2d 03 02 00 00 00 00 00 |....1...-.......|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 05 00 00 |................|
-00000030 05 ff 01 00 01 00 16 03 02 02 71 0b 00 02 6d 00 |..........q...m.|
-00000040 02 6a 00 02 67 30 82 02 63 30 82 01 cc a0 03 02 |.j..g0..c0......|
-00000050 01 02 02 09 00 a2 73 00 0c 81 00 cb f3 30 0d 06 |......s......0..|
-00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 2b 31 17 |.*.H........0+1.|
-00000070 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 |0...U....Google |
-00000080 54 45 53 54 49 4e 47 31 10 30 0e 06 03 55 04 03 |TESTING1.0...U..|
-00000090 13 07 47 6f 20 52 6f 6f 74 30 1e 17 0d 31 35 30 |..Go Root0...150|
-000000a0 31 30 31 30 30 30 30 30 30 5a 17 0d 32 35 30 31 |101000000Z..2501|
-000000b0 30 31 30 30 30 30 30 30 5a 30 26 31 17 30 15 06 |01000000Z0&1.0..|
-000000c0 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 54 45 53 |.U....Google TES|
-000000d0 54 49 4e 47 31 0b 30 09 06 03 55 04 03 13 02 47 |TING1.0...U....G|
-000000e0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....|
-000000f0 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 af 87 |.......0........|
-00000100 88 f6 20 1b 95 65 6c 14 ab 44 05 af 3b 45 14 e3 |.. ..el..D..;E..|
-00000110 b7 6d fd 00 63 4d 95 7f fe 6a 62 35 86 c0 4a f9 |.m..cM...jb5..J.|
-00000120 18 7c f6 aa 25 5e 7a 64 31 66 00 ba f4 8e 92 af |.|..%^zd1f......|
-00000130 c7 6b d8 76 d4 f3 5f 41 cb 6e 56 15 97 1b 97 c1 |.k.v.._A.nV.....|
-00000140 3c 12 39 21 66 3d 2b 16 d1 bc db 1c c0 a7 da b7 |<.9!f=+.........|
-00000150 ca ad ba da cb d5 21 50 ec de 8d ab d1 6b 81 4b |......!P.....k.K|
-00000160 89 02 f3 c4 be c1 6c 89 b1 44 84 bd 21 d1 04 7d |......l..D..!..}|
-00000170 9d 16 4d f9 82 15 f6 ef fa d6 09 47 f2 fb 02 03 |..M........G....|
-00000180 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..|
-00000190 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%|
-000001a0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........|
-000001b0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...|
-000001c0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....|
-000001d0 10 12 50 8d 89 6f 1b d1 dc 54 4d 6e cb 69 5e 06 |..P..o...TMn.i^.|
-000001e0 f4 30 1b 06 03 55 1d 23 04 14 30 12 80 10 bf 3d |.0...U.#..0....=|
-000001f0 b6 a9 66 f2 b8 40 cf ea b4 03 78 48 1a 41 30 19 |..f.. at ....xH.A0.|
-00000200 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp|
-00000210 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H|
-00000220 86 f7 0d 01 01 0b 05 00 03 81 81 00 92 7c af 91 |.............|..|
-00000230 55 12 18 96 59 31 a6 48 40 d5 2d d5 ee bb 02 a0 |U...Y1.H at .-.....|
-00000240 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 da 4f 3d c0 fa |...|..0}<.v.O=..|
-00000250 ae 2d 33 24 6b 03 7b 1b 67 59 11 21 b5 11 bc 77 |.-3$k.{.gY.!...w|
-00000260 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f 22 3e 63 10 6b |...n.-.5.d_">c.k|
-00000270 be ff 14 86 6d 0d f0 15 31 a8 14 38 1e 3b 84 87 |....m...1..8.;..|
-00000280 2c cb 98 ed 51 76 b9 b1 4f dd db 9b 84 04 86 40 |,...Qv..O......@|
-00000290 fa 51 dd ba b4 8d eb e3 46 de 46 b9 4f 86 c7 f9 |.Q......F.F.O...|
-000002a0 a4 c2 41 34 ac cc f6 ea b0 ab 39 18 16 03 02 00 |..A4......9.....|
-000002b0 04 0e 00 00 00 |.....|
+00000030 05 ff 01 00 01 00 16 03 02 02 59 0b 00 02 55 00 |..........Y...U.|
+00000040 02 52 00 02 4f 30 82 02 4b 30 82 01 b4 a0 03 02 |.R..O0..K0......|
+00000050 01 02 02 09 00 e8 f0 9d 3f e2 5b ea a6 30 0d 06 |........?.[..0..|
+00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 1f 31 0b |.*.H........0.1.|
+00000070 30 09 06 03 55 04 0a 13 02 47 6f 31 10 30 0e 06 |0...U....Go1.0..|
+00000080 03 55 04 03 13 07 47 6f 20 52 6f 6f 74 30 1e 17 |.U....Go Root0..|
+00000090 0d 31 36 30 31 30 31 30 30 30 30 30 30 5a 17 0d |.160101000000Z..|
+000000a0 32 35 30 31 30 31 30 30 30 30 30 30 5a 30 1a 31 |250101000000Z0.1|
+000000b0 0b 30 09 06 03 55 04 0a 13 02 47 6f 31 0b 30 09 |.0...U....Go1.0.|
+000000c0 06 03 55 04 03 13 02 47 6f 30 81 9f 30 0d 06 09 |..U....Go0..0...|
+000000d0 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 30 |*.H............0|
+000000e0 81 89 02 81 81 00 db 46 7d 93 2e 12 27 06 48 bc |.......F}...'.H.|
+000000f0 06 28 21 ab 7e c4 b6 a2 5d fe 1e 52 45 88 7a 36 |.(!.~...]..RE.z6|
+00000100 47 a5 08 0d 92 42 5b c2 81 c0 be 97 79 98 40 fb |G....B[.....y. at .|
+00000110 4f 6d 14 fd 2b 13 8b c2 a5 2e 67 d8 d4 09 9e d6 |Om..+.....g.....|
+00000120 22 38 b7 4a 0b 74 73 2b c2 34 f1 d1 93 e5 96 d9 |"8.J.ts+.4......|
+00000130 74 7b f3 58 9f 6c 61 3c c0 b0 41 d4 d9 2b 2b 24 |t{.X.la<..A..++$|
+00000140 23 77 5b 1c 3b bd 75 5d ce 20 54 cf a1 63 87 1d |#w[.;.u]. T..c..|
+00000150 1e 24 c4 f3 1d 1a 50 8b aa b6 14 43 ed 97 a7 75 |.$....P....C...u|
+00000160 62 f4 14 c8 52 d7 02 03 01 00 01 a3 81 93 30 81 |b...R.........0.|
+00000170 90 30 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 05 |.0...U..........|
+00000180 a0 30 1d 06 03 55 1d 25 04 16 30 14 06 08 2b 06 |.0...U.%..0...+.|
+00000190 01 05 05 07 03 01 06 08 2b 06 01 05 05 07 03 02 |........+.......|
+000001a0 30 0c 06 03 55 1d 13 01 01 ff 04 02 30 00 30 19 |0...U.......0.0.|
+000001b0 06 03 55 1d 0e 04 12 04 10 9f 91 16 1f 43 43 3e |..U..........CC>|
+000001c0 49 a6 de 6d b6 80 d7 9f 60 30 1b 06 03 55 1d 23 |I..m....`0...U.#|
+000001d0 04 14 30 12 80 10 48 13 49 4d 13 7e 16 31 bb a3 |..0...H.IM.~.1..|
+000001e0 01 d5 ac ab 6e 7b 30 19 06 03 55 1d 11 04 12 30 |....n{0...U....0|
+000001f0 10 82 0e 65 78 61 6d 70 6c 65 2e 67 6f 6c 61 6e |...example.golan|
+00000200 67 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 |g0...*.H........|
+00000210 03 81 81 00 9d 30 cc 40 2b 5b 50 a0 61 cb ba e5 |.....0. at +[P.a...|
+00000220 53 58 e1 ed 83 28 a9 58 1a a9 38 a4 95 a1 ac 31 |SX...(.X..8....1|
+00000230 5a 1a 84 66 3d 43 d3 2d d9 0b f2 97 df d3 20 64 |Z..f=C.-...... d|
+00000240 38 92 24 3a 00 bc cf 9c 7d b7 40 20 01 5f aa d3 |8.$:....}.@ ._..|
+00000250 16 61 09 a2 76 fd 13 c3 cc e1 0c 5c ee b1 87 82 |.a..v......\....|
+00000260 f1 6c 04 ed 73 bb b3 43 77 8d 0c 1c f1 0f a1 d8 |.l..s..Cw.......|
+00000270 40 83 61 c9 4c 72 2b 9d ae db 46 06 06 4d f4 c1 |@.a.Lr+...F..M..|
+00000280 b3 3e c0 d1 bd 42 d4 db fe 3d 13 60 84 5c 21 d3 |.>...B...=.`.\!.|
+00000290 3b e9 fa e7 16 03 02 00 04 0e 00 00 00 |;............|
>>> Flow 3 (client to server)
-00000000 16 03 02 00 86 10 00 00 82 00 80 19 c3 d4 f2 e4 |................|
-00000010 bf 4a 52 90 a4 65 f6 e7 29 1a 7f ef 0e a4 1e b4 |.JR..e..).......|
-00000020 c2 df b2 83 43 4a 1a f4 b6 cd 51 a5 24 62 3f e1 |....CJ....Q.$b?.|
-00000030 fb 5f 7e b1 10 08 3b 8a ab eb 3a a3 72 ba 31 1c |._~...;...:.r.1.|
-00000040 23 bd ef 2e 3d 13 dc 61 88 a6 af ca 80 82 5d e4 |#...=..a......].|
-00000050 d6 a2 d3 13 80 87 c6 ad a5 13 4e f1 b6 a0 5d fa |..........N...].|
-00000060 ed a7 0d 37 58 f1 54 38 18 f5 be db 90 9f 07 4a |...7X.T8.......J|
-00000070 67 25 c9 8d 9d 5e 07 62 ca db 72 74 b5 bd a0 ed |g%...^.b..rt....|
-00000080 d0 95 9f 3e cd 37 b8 96 df df 3b 14 03 02 00 01 |...>.7....;.....|
-00000090 01 16 03 02 00 24 80 53 7a 8f 23 06 a7 6b e6 be |.....$.Sz.#..k..|
-000000a0 61 c2 1a c8 35 30 6b e2 2f 82 f3 46 ff e3 1d bd |a...50k./..F....|
-000000b0 68 e9 a2 78 49 33 05 ca d9 41 |h..xI3...A|
+00000000 16 03 02 00 86 10 00 00 82 00 80 75 8e 85 93 be |...........u....|
+00000010 53 df e0 4f 65 92 ed 3d 58 34 f8 06 fd 36 e4 5a |S..Oe..=X4...6.Z|
+00000020 f7 7a 59 88 f6 ac bd de 21 ed c4 04 0d 35 19 cd |.zY.....!....5..|
+00000030 ff 3b 9f c4 bc 93 4f 21 2a 36 a3 99 a4 6f eb 1e |.;....O!*6...o..|
+00000040 7b b4 a8 a7 6d 69 a5 93 b6 e3 d2 2d be 7a c8 f3 |{...mi.....-.z..|
+00000050 9f 25 9e f9 51 75 d9 4f 05 41 0e 17 56 31 4e 3f |.%..Qu.O.A..V1N?|
+00000060 c0 15 d8 c4 29 4d e5 92 f9 ed 50 b6 88 f1 41 ea |....)M....P...A.|
+00000070 cb 5a 8c 50 12 78 16 e7 21 b6 11 ca 2c 49 cf b6 |.Z.P.x..!...,I..|
+00000080 d2 1a 16 28 f7 08 b5 c9 61 e0 18 14 03 02 00 01 |...(....a.......|
+00000090 01 16 03 02 00 24 a1 cf 1b 5d dc 4c 9c 2c d7 39 |.....$...].L.,.9|
+000000a0 af 13 e9 04 48 c0 2a aa 6f 3a 9c fb 9e 0a 25 55 |....H.*.o:....%U|
+000000b0 7e 82 3d 1b 78 d1 e3 e0 f5 30 |~.=.x....0|
>>> Flow 4 (server to client)
-00000000 14 03 02 00 01 01 16 03 02 00 24 8f 06 3e 7b 8c |..........$..>{.|
-00000010 fb f2 3d 9e 5c a9 46 56 79 2a 3a ba ad 25 30 57 |..=.\.FVy*:..%0W|
-00000020 f9 f1 16 70 51 5d 73 7e 47 74 8d c0 84 b0 31 17 |...pQ]s~Gt....1.|
-00000030 03 02 00 21 76 09 88 df 7e f7 2f c9 3d 86 b9 30 |...!v...~./.=..0|
-00000040 b0 5c ac ea db c6 d0 d5 69 55 91 7b a1 72 0b 4d |.\......iU.{.r.M|
-00000050 7d ae 6f aa 50 15 03 02 00 16 8c 31 73 86 1a c7 |}.o.P......1s...|
-00000060 ef 08 52 8a 7d 30 b8 00 3b 62 4d 21 7b 81 2c 76 |..R.}0..;bM!{.,v|
+00000000 14 03 02 00 01 01 16 03 02 00 24 7b 68 71 56 0f |..........${hqV.|
+00000010 a5 46 1c 13 34 81 b5 b6 ba 29 fb 41 46 dc fe 78 |.F..4....).AF..x|
+00000020 cc 0b 2d 75 bd fe c1 55 45 b1 fc 04 28 5e b1 17 |..-u...UE...(^..|
+00000030 03 02 00 21 0b fa a9 2f 9e 82 5b 77 30 c2 27 88 |...!.../..[w0.'.|
+00000040 f5 f3 50 47 7b 62 4c 7a d4 07 71 74 46 da 24 de |..PG{bLz..qtF.$.|
+00000050 bf 3f 56 a7 9b 15 03 02 00 16 85 26 8a 89 33 21 |.?V........&..3!|
+00000060 36 ce 69 83 84 50 fc 8f 99 b3 43 ad 6b 14 1e b2 |6.i..P....C.k...|
diff --git a/src/crypto/tls/testdata/Server-TLSv12-ALPN b/src/crypto/tls/testdata/Server-TLSv12-ALPN
index df832d7..3e90ebd 100644
--- a/src/crypto/tls/testdata/Server-TLSv12-ALPN
+++ b/src/crypto/tls/testdata/Server-TLSv12-ALPN
@@ -1,109 +1,94 @@
>>> Flow 1 (client to server)
-00000000 16 03 01 01 4d 01 00 01 49 03 03 ac 76 61 d8 20 |....M...I...va. |
-00000010 b3 c3 1d c2 3d c2 a4 b9 e2 46 a2 a1 0a 5e 08 56 |....=....F...^.V|
-00000020 4a aa 59 43 42 d6 21 9c 46 0c 21 00 00 b6 c0 30 |J.YCB.!.F.!....0|
-00000030 c0 2c c0 28 c0 24 c0 14 c0 0a 00 a5 00 a3 00 a1 |.,.(.$..........|
-00000040 00 9f 00 6b 00 6a 00 69 00 68 00 39 00 38 00 37 |...k.j.i.h.9.8.7|
-00000050 00 36 00 88 00 87 00 86 00 85 c0 32 c0 2e c0 2a |.6.........2...*|
-00000060 c0 26 c0 0f c0 05 00 9d 00 3d 00 35 00 84 c0 2f |.&.......=.5.../|
-00000070 c0 2b c0 27 c0 23 c0 13 c0 09 00 a4 00 a2 00 a0 |.+.'.#..........|
-00000080 00 9e 00 67 00 40 00 3f 00 3e 00 33 00 32 00 31 |...g. at .?.>.3.2.1|
-00000090 00 30 00 9a 00 99 00 98 00 97 00 45 00 44 00 43 |.0.........E.D.C|
-000000a0 00 42 c0 31 c0 2d c0 29 c0 25 c0 0e c0 04 00 9c |.B.1.-.).%......|
-000000b0 00 3c 00 2f 00 96 00 41 00 07 c0 11 c0 07 c0 0c |.<./...A........|
-000000c0 c0 02 00 05 00 04 c0 12 c0 08 00 16 00 13 00 10 |................|
-000000d0 00 0d c0 0d c0 03 00 0a 00 15 00 12 00 0f 00 0c |................|
-000000e0 00 09 00 ff 02 01 00 00 69 00 0b 00 04 03 00 01 |........i.......|
-000000f0 02 00 0a 00 1c 00 1a 00 17 00 19 00 1c 00 1b 00 |................|
-00000100 18 00 1a 00 16 00 0e 00 0d 00 0b 00 0c 00 09 00 |................|
-00000110 0a 00 23 00 00 00 0d 00 20 00 1e 06 01 06 02 06 |..#..... .......|
-00000120 03 05 01 05 02 05 03 04 01 04 02 04 03 03 01 03 |................|
-00000130 02 03 03 02 01 02 02 02 03 00 0f 00 01 01 00 10 |................|
-00000140 00 10 00 0e 06 70 72 6f 74 6f 32 06 70 72 6f 74 |.....proto2.prot|
-00000150 6f 31 |o1|
+00000000 16 03 01 00 bf 01 00 00 bb 03 03 18 c9 32 10 f3 |.............2..|
+00000010 be ff a8 60 c5 2a 03 cb 25 8a b3 54 8d 70 27 90 |...`.*..%..T.p'.|
+00000020 74 1e 15 3e 61 48 9b be f0 77 1f 00 00 38 c0 2c |t..>aH...w...8.,|
+00000030 c0 30 00 9f cc a9 cc a8 cc aa c0 2b c0 2f 00 9e |.0.........+./..|
+00000040 c0 24 c0 28 00 6b c0 23 c0 27 00 67 c0 0a c0 14 |.$.(.k.#.'.g....|
+00000050 00 39 c0 09 c0 13 00 33 00 9d 00 9c 00 3d 00 3c |.9.....3.....=.<|
+00000060 00 35 00 2f 00 ff 01 00 00 5a 00 0b 00 04 03 00 |.5./.....Z......|
+00000070 01 02 00 0a 00 0a 00 08 00 1d 00 17 00 19 00 18 |................|
+00000080 00 23 00 00 00 0d 00 20 00 1e 06 01 06 02 06 03 |.#..... ........|
+00000090 05 01 05 02 05 03 04 01 04 02 04 03 03 01 03 02 |................|
+000000a0 03 03 02 01 02 02 02 03 00 10 00 10 00 0e 06 70 |...............p|
+000000b0 72 6f 74 6f 32 06 70 72 6f 74 6f 31 00 16 00 00 |roto2.proto1....|
+000000c0 00 17 00 00 |....|
>>> Flow 2 (server to client)
00000000 16 03 03 00 42 02 00 00 3e 03 03 00 00 00 00 00 |....B...>.......|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000020 00 00 00 00 00 00 00 00 00 00 00 00 c0 30 00 00 |.............0..|
00000030 16 00 23 00 00 ff 01 00 01 00 00 10 00 09 00 07 |..#.............|
-00000040 06 70 72 6f 74 6f 31 16 03 03 02 71 0b 00 02 6d |.proto1....q...m|
-00000050 00 02 6a 00 02 67 30 82 02 63 30 82 01 cc a0 03 |..j..g0..c0.....|
-00000060 02 01 02 02 09 00 a2 73 00 0c 81 00 cb f3 30 0d |.......s......0.|
-00000070 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 2b 31 |..*.H........0+1|
-00000080 17 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 |.0...U....Google|
-00000090 20 54 45 53 54 49 4e 47 31 10 30 0e 06 03 55 04 | TESTING1.0...U.|
-000000a0 03 13 07 47 6f 20 52 6f 6f 74 30 1e 17 0d 31 35 |...Go Root0...15|
-000000b0 30 31 30 31 30 30 30 30 30 30 5a 17 0d 32 35 30 |0101000000Z..250|
-000000c0 31 30 31 30 30 30 30 30 30 5a 30 26 31 17 30 15 |101000000Z0&1.0.|
-000000d0 06 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 54 45 |..U....Google TE|
-000000e0 53 54 49 4e 47 31 0b 30 09 06 03 55 04 03 13 02 |STING1.0...U....|
-000000f0 47 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 |Go0..0...*.H....|
-00000100 01 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 af |........0.......|
-00000110 87 88 f6 20 1b 95 65 6c 14 ab 44 05 af 3b 45 14 |... ..el..D..;E.|
-00000120 e3 b7 6d fd 00 63 4d 95 7f fe 6a 62 35 86 c0 4a |..m..cM...jb5..J|
-00000130 f9 18 7c f6 aa 25 5e 7a 64 31 66 00 ba f4 8e 92 |..|..%^zd1f.....|
-00000140 af c7 6b d8 76 d4 f3 5f 41 cb 6e 56 15 97 1b 97 |..k.v.._A.nV....|
-00000150 c1 3c 12 39 21 66 3d 2b 16 d1 bc db 1c c0 a7 da |.<.9!f=+........|
-00000160 b7 ca ad ba da cb d5 21 50 ec de 8d ab d1 6b 81 |.......!P.....k.|
-00000170 4b 89 02 f3 c4 be c1 6c 89 b1 44 84 bd 21 d1 04 |K......l..D..!..|
-00000180 7d 9d 16 4d f9 82 15 f6 ef fa d6 09 47 f2 fb 02 |}..M........G...|
-00000190 03 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d |.......0..0...U.|
-000001a0 0f 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d |..........0...U.|
-000001b0 25 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 |%..0...+........|
-000001c0 08 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 |.+.......0...U..|
-000001d0 01 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 |.....0.0...U....|
-000001e0 04 10 12 50 8d 89 6f 1b d1 dc 54 4d 6e cb 69 5e |...P..o...TMn.i^|
-000001f0 06 f4 30 1b 06 03 55 1d 23 04 14 30 12 80 10 bf |..0...U.#..0....|
-00000200 3d b6 a9 66 f2 b8 40 cf ea b4 03 78 48 1a 41 30 |=..f.. at ....xH.A0|
-00000210 19 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d |...U....0...exam|
-00000220 70 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 |ple.golang0...*.|
-00000230 48 86 f7 0d 01 01 0b 05 00 03 81 81 00 92 7c af |H.............|.|
-00000240 91 55 12 18 96 59 31 a6 48 40 d5 2d d5 ee bb 02 |.U...Y1.H at .-....|
-00000250 a0 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 da 4f 3d c0 |....|..0}<.v.O=.|
-00000260 fa ae 2d 33 24 6b 03 7b 1b 67 59 11 21 b5 11 bc |..-3$k.{.gY.!...|
-00000270 77 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f 22 3e 63 10 |w...n.-.5.d_">c.|
-00000280 6b be ff 14 86 6d 0d f0 15 31 a8 14 38 1e 3b 84 |k....m...1..8.;.|
-00000290 87 2c cb 98 ed 51 76 b9 b1 4f dd db 9b 84 04 86 |.,...Qv..O......|
-000002a0 40 fa 51 dd ba b4 8d eb e3 46 de 46 b9 4f 86 c7 |@.Q......F.F.O..|
-000002b0 f9 a4 c2 41 34 ac cc f6 ea b0 ab 39 18 16 03 03 |...A4......9....|
-000002c0 00 cd 0c 00 00 c9 03 00 17 41 04 1e 18 37 ef 0d |.........A...7..|
-000002d0 19 51 88 35 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd |.Q.5uq..T[....g.|
-000002e0 a7 24 20 3e b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e |.$ >.V...(^.+-O.|
-000002f0 f1 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 |...lK[.V.2B.X..I|
-00000300 a6 b5 68 1a 41 03 56 6b dc 5a 89 05 01 00 80 aa |..h.A.Vk.Z......|
-00000310 8c a6 e1 51 65 fc 99 37 cf 63 d8 fd 04 52 d5 50 |...Qe..7.c...R.P|
-00000320 1f 0a f5 90 58 48 19 8d d8 0b 64 23 e4 24 56 b4 |....XH....d#.$V.|
-00000330 e5 87 0f 88 a1 7a 29 fa 88 79 99 75 6d 53 a9 50 |.....z)..y.umS.P|
-00000340 a4 9c b9 47 c2 51 87 10 b9 a5 e3 6f a9 38 b8 83 |...G.Q.....o.8..|
-00000350 0d 39 b5 28 27 5f ec 9d a3 2d 1c 53 6b da 93 0d |.9.('_...-.Sk...|
-00000360 cc cf 0c 27 7e d2 f0 05 d5 c0 04 dc 6d d4 2e 03 |...'~.......m...|
-00000370 a7 16 98 58 e4 8d fd 14 6b bb 0c 09 b0 16 35 9e |...X....k.....5.|
-00000380 78 3a 29 21 b5 2f 13 37 94 ae f7 fe 54 89 c0 16 |x:)!./.7....T...|
-00000390 03 03 00 04 0e 00 00 00 |........|
+00000040 06 70 72 6f 74 6f 31 16 03 03 02 59 0b 00 02 55 |.proto1....Y...U|
+00000050 00 02 52 00 02 4f 30 82 02 4b 30 82 01 b4 a0 03 |..R..O0..K0.....|
+00000060 02 01 02 02 09 00 e8 f0 9d 3f e2 5b ea a6 30 0d |.........?.[..0.|
+00000070 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 1f 31 |..*.H........0.1|
+00000080 0b 30 09 06 03 55 04 0a 13 02 47 6f 31 10 30 0e |.0...U....Go1.0.|
+00000090 06 03 55 04 03 13 07 47 6f 20 52 6f 6f 74 30 1e |..U....Go Root0.|
+000000a0 17 0d 31 36 30 31 30 31 30 30 30 30 30 30 5a 17 |..160101000000Z.|
+000000b0 0d 32 35 30 31 30 31 30 30 30 30 30 30 5a 30 1a |.250101000000Z0.|
+000000c0 31 0b 30 09 06 03 55 04 0a 13 02 47 6f 31 0b 30 |1.0...U....Go1.0|
+000000d0 09 06 03 55 04 03 13 02 47 6f 30 81 9f 30 0d 06 |...U....Go0..0..|
+000000e0 09 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 |.*.H............|
+000000f0 30 81 89 02 81 81 00 db 46 7d 93 2e 12 27 06 48 |0.......F}...'.H|
+00000100 bc 06 28 21 ab 7e c4 b6 a2 5d fe 1e 52 45 88 7a |..(!.~...]..RE.z|
+00000110 36 47 a5 08 0d 92 42 5b c2 81 c0 be 97 79 98 40 |6G....B[.....y.@|
+00000120 fb 4f 6d 14 fd 2b 13 8b c2 a5 2e 67 d8 d4 09 9e |.Om..+.....g....|
+00000130 d6 22 38 b7 4a 0b 74 73 2b c2 34 f1 d1 93 e5 96 |."8.J.ts+.4.....|
+00000140 d9 74 7b f3 58 9f 6c 61 3c c0 b0 41 d4 d9 2b 2b |.t{.X.la<..A..++|
+00000150 24 23 77 5b 1c 3b bd 75 5d ce 20 54 cf a1 63 87 |$#w[.;.u]. T..c.|
+00000160 1d 1e 24 c4 f3 1d 1a 50 8b aa b6 14 43 ed 97 a7 |..$....P....C...|
+00000170 75 62 f4 14 c8 52 d7 02 03 01 00 01 a3 81 93 30 |ub...R.........0|
+00000180 81 90 30 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 |..0...U.........|
+00000190 05 a0 30 1d 06 03 55 1d 25 04 16 30 14 06 08 2b |..0...U.%..0...+|
+000001a0 06 01 05 05 07 03 01 06 08 2b 06 01 05 05 07 03 |.........+......|
+000001b0 02 30 0c 06 03 55 1d 13 01 01 ff 04 02 30 00 30 |.0...U.......0.0|
+000001c0 19 06 03 55 1d 0e 04 12 04 10 9f 91 16 1f 43 43 |...U..........CC|
+000001d0 3e 49 a6 de 6d b6 80 d7 9f 60 30 1b 06 03 55 1d |>I..m....`0...U.|
+000001e0 23 04 14 30 12 80 10 48 13 49 4d 13 7e 16 31 bb |#..0...H.IM.~.1.|
+000001f0 a3 01 d5 ac ab 6e 7b 30 19 06 03 55 1d 11 04 12 |.....n{0...U....|
+00000200 30 10 82 0e 65 78 61 6d 70 6c 65 2e 67 6f 6c 61 |0...example.gola|
+00000210 6e 67 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 |ng0...*.H.......|
+00000220 00 03 81 81 00 9d 30 cc 40 2b 5b 50 a0 61 cb ba |......0. at +[P.a..|
+00000230 e5 53 58 e1 ed 83 28 a9 58 1a a9 38 a4 95 a1 ac |.SX...(.X..8....|
+00000240 31 5a 1a 84 66 3d 43 d3 2d d9 0b f2 97 df d3 20 |1Z..f=C.-...... |
+00000250 64 38 92 24 3a 00 bc cf 9c 7d b7 40 20 01 5f aa |d8.$:....}.@ ._.|
+00000260 d3 16 61 09 a2 76 fd 13 c3 cc e1 0c 5c ee b1 87 |..a..v......\...|
+00000270 82 f1 6c 04 ed 73 bb b3 43 77 8d 0c 1c f1 0f a1 |..l..s..Cw......|
+00000280 d8 40 83 61 c9 4c 72 2b 9d ae db 46 06 06 4d f4 |. at .a.Lr+...F..M.|
+00000290 c1 b3 3e c0 d1 bd 42 d4 db fe 3d 13 60 84 5c 21 |..>...B...=.`.\!|
+000002a0 d3 3b e9 fa e7 16 03 03 00 ac 0c 00 00 a8 03 00 |.;..............|
+000002b0 1d 20 2f e5 7d a3 47 cd 62 43 15 28 da ac 5f bb |. /.}.G.bC.(.._.|
+000002c0 29 07 30 ff f6 84 af c4 cf c2 ed 90 99 5f 58 cb |).0.........._X.|
+000002d0 3b 74 05 01 00 80 2e c1 51 a1 e8 92 a6 bb ad 1e |;t......Q.......|
+000002e0 4d f1 22 c5 e7 10 e6 31 1d 78 61 8a 22 a3 93 84 |M."....1.xa."...|
+000002f0 58 d6 5a c6 94 d0 da 6c 6a 35 d1 31 ea 1b 7e 55 |X.Z....lj5.1..~U|
+00000300 d6 35 a3 b7 42 e4 04 f8 31 15 15 88 5f 91 a8 7e |.5..B...1..._..~|
+00000310 3e 73 52 8f 32 50 2e ad 95 44 83 b6 88 d6 18 99 |>sR.2P...D......|
+00000320 cf 86 57 97 c0 b2 a0 91 ee a7 ac f8 38 4b 1c 8e |..W.........8K..|
+00000330 a4 58 59 4a f6 fc 88 a4 02 ed c8 04 1a 8b 7b 9e |.XYJ..........{.|
+00000340 83 91 72 ca 1e 1c e0 76 58 73 89 3a 7d 12 c5 ef |..r....vXs.:}...|
+00000350 f8 f7 45 dc ca c4 16 03 03 00 04 0e 00 00 00 |..E............|
>>> Flow 3 (client to server)
-00000000 16 03 03 00 46 10 00 00 42 41 04 35 ca 56 91 15 |....F...BA.5.V..|
-00000010 4f dd af 97 f2 2d fb df 54 2b 80 98 18 bb 33 54 |O....-..T+....3T|
-00000020 3f 7e 66 21 d3 81 38 f9 a4 b5 b9 a6 46 9a 52 8b |?~f!..8.....F.R.|
-00000030 98 f7 81 1f 77 81 78 38 01 c5 3b fb 7a b7 53 e7 |....w.x8..;.z.S.|
-00000040 ae c3 4c 2e 73 f4 8e 3a 36 0d 43 14 03 03 00 01 |..L.s..:6.C.....|
-00000050 01 16 03 03 00 28 38 26 8e 03 ad 81 9b a0 41 d9 |.....(8&......A.|
-00000060 c0 11 3f 36 dc 6b ab 6c 29 dc df 02 a3 fe b0 0f |..?6.k.l).......|
-00000070 2e b1 c6 44 39 42 d5 ef 29 30 d8 e0 f1 f9 |...D9B..)0....|
+00000000 16 03 03 00 25 10 00 00 21 20 be 4e 0d d5 31 aa |....%...! .N..1.|
+00000010 27 13 df 73 d3 8d 17 8c b3 5f 44 61 7b 01 b6 99 |'..s....._Da{...|
+00000020 7b ba b3 5d bf d4 be 3c 87 26 14 03 03 00 01 01 |{..]...<.&......|
+00000030 16 03 03 00 28 9c 86 e0 30 d4 a5 ec 0c 9e a6 08 |....(...0.......|
+00000040 ce 8a 7a ff ef be 52 0c 56 86 62 de 49 09 a1 18 |..z...R.V.b.I...|
+00000050 aa 62 e5 e3 d3 2e 4a 24 c9 ef 44 c9 67 |.b....J$..D.g|
>>> Flow 4 (server to client)
00000000 16 03 03 00 82 04 00 00 7e 00 00 00 00 00 78 50 |........~.....xP|
00000010 46 ad c1 db a8 38 86 7b 2b bb fd d0 c3 42 3e 00 |F....8.{+....B>.|
00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 94 |................|
-00000030 6f ec 80 83 61 fb fb 41 b1 31 e9 71 75 43 c3 74 |o...a..A.1.quC.t|
-00000040 a1 a0 ac fb 97 b7 69 ee a6 2f e3 a3 dd 9f de e4 |......i../......|
-00000050 80 9d d7 69 1a 2c 0b b4 02 bd ef e2 6a c1 ca 30 |...i.,......j..0|
-00000060 8b 9d 60 f9 fe 33 94 53 3a 14 a3 1a aa 5a ba ff |..`..3.S:....Z..|
-00000070 1e 94 fd 4f e7 90 0b 09 ee 80 f3 d6 d5 c0 48 83 |...O..........H.|
-00000080 98 20 d7 a4 07 99 e0 14 03 03 00 01 01 16 03 03 |. ..............|
-00000090 00 28 00 00 00 00 00 00 00 00 0d 66 de 91 4a 97 |.(.........f..J.|
-000000a0 21 c6 d2 d7 df 68 9b 7e f6 43 73 02 66 b3 5a d6 |!....h.~.Cs.f.Z.|
-000000b0 92 48 c2 c1 11 fc cd 1e 2e 4b 17 03 03 00 25 00 |.H.......K....%.|
-000000c0 00 00 00 00 00 00 01 72 0c 48 75 fa b2 8b 23 09 |.......r.Hu...#.|
-000000d0 be 76 36 a4 bc e0 62 ef bd 79 8e de 6b 39 4b 55 |.v6...b..y..k9KU|
-000000e0 8d 3c ca 14 15 03 03 00 1a 00 00 00 00 00 00 00 |.<..............|
-000000f0 02 74 5f 79 31 41 4f f5 4d 02 96 bc c3 9a 85 92 |.t_y1AO.M.......|
-00000100 44 e1 76 |D.v|
+00000030 6f ec 80 83 61 da 3d a1 df 0d 11 25 4b 66 55 09 |o...a.=....%KfU.|
+00000040 af 7a c1 82 b9 ea 2f 9f 5c f4 0a 62 15 62 c2 32 |.z..../.\..b.b.2|
+00000050 c6 37 51 5b bb 19 14 f8 73 f8 fb 82 00 ef 19 21 |.7Q[....s......!|
+00000060 e2 52 7d ab 0a 33 94 df 78 54 ba 6c 5e 94 eb 16 |.R}..3..xT.l^...|
+00000070 ad 85 01 ca d5 98 8f 8e b7 04 7e 9a 3c 35 c0 e5 |..........~.<5..|
+00000080 8f cf 27 6d b4 12 c2 14 03 03 00 01 01 16 03 03 |..'m............|
+00000090 00 28 00 00 00 00 00 00 00 00 75 da b5 10 2e 7c |.(........u....||
+000000a0 39 ec 3d 98 12 fb 5d 15 81 79 f3 c7 b1 e4 e0 54 |9.=...]..y.....T|
+000000b0 ed 27 6e bc c3 81 a0 74 7e 38 17 03 03 00 25 00 |.'n....t~8....%.|
+000000c0 00 00 00 00 00 00 01 bf 81 cc 93 49 4f b2 59 8b |...........IO.Y.|
+000000d0 53 4a 61 96 04 00 4b ac 34 d5 bd 5a 94 44 18 5b |SJa...K.4..Z.D.[|
+000000e0 7d 81 dc 05 15 03 03 00 1a 00 00 00 00 00 00 00 |}...............|
+000000f0 02 bd 32 d5 cf 4d 13 61 6a 77 8b 3e 51 b3 13 84 |..2..M.ajw.>Q...|
+00000100 e6 1a 23 |..#|
diff --git a/src/crypto/tls/testdata/Server-TLSv12-ALPN-NoMatch b/src/crypto/tls/testdata/Server-TLSv12-ALPN-NoMatch
index 35bfdc1..d40300e 100644
--- a/src/crypto/tls/testdata/Server-TLSv12-ALPN-NoMatch
+++ b/src/crypto/tls/testdata/Server-TLSv12-ALPN-NoMatch
@@ -1,108 +1,94 @@
>>> Flow 1 (client to server)
-00000000 16 03 01 01 4d 01 00 01 49 03 03 73 f2 f2 44 4f |....M...I..s..DO|
-00000010 87 05 77 e2 e7 07 ca c7 d4 36 37 4e d9 17 ba ff |..w......67N....|
-00000020 b0 e1 47 65 f8 7f fd 7a b4 85 39 00 00 b6 c0 30 |..Ge...z..9....0|
-00000030 c0 2c c0 28 c0 24 c0 14 c0 0a 00 a5 00 a3 00 a1 |.,.(.$..........|
-00000040 00 9f 00 6b 00 6a 00 69 00 68 00 39 00 38 00 37 |...k.j.i.h.9.8.7|
-00000050 00 36 00 88 00 87 00 86 00 85 c0 32 c0 2e c0 2a |.6.........2...*|
-00000060 c0 26 c0 0f c0 05 00 9d 00 3d 00 35 00 84 c0 2f |.&.......=.5.../|
-00000070 c0 2b c0 27 c0 23 c0 13 c0 09 00 a4 00 a2 00 a0 |.+.'.#..........|
-00000080 00 9e 00 67 00 40 00 3f 00 3e 00 33 00 32 00 31 |...g. at .?.>.3.2.1|
-00000090 00 30 00 9a 00 99 00 98 00 97 00 45 00 44 00 43 |.0.........E.D.C|
-000000a0 00 42 c0 31 c0 2d c0 29 c0 25 c0 0e c0 04 00 9c |.B.1.-.).%......|
-000000b0 00 3c 00 2f 00 96 00 41 00 07 c0 11 c0 07 c0 0c |.<./...A........|
-000000c0 c0 02 00 05 00 04 c0 12 c0 08 00 16 00 13 00 10 |................|
-000000d0 00 0d c0 0d c0 03 00 0a 00 15 00 12 00 0f 00 0c |................|
-000000e0 00 09 00 ff 02 01 00 00 69 00 0b 00 04 03 00 01 |........i.......|
-000000f0 02 00 0a 00 1c 00 1a 00 17 00 19 00 1c 00 1b 00 |................|
-00000100 18 00 1a 00 16 00 0e 00 0d 00 0b 00 0c 00 09 00 |................|
-00000110 0a 00 23 00 00 00 0d 00 20 00 1e 06 01 06 02 06 |..#..... .......|
-00000120 03 05 01 05 02 05 03 04 01 04 02 04 03 03 01 03 |................|
-00000130 02 03 03 02 01 02 02 02 03 00 0f 00 01 01 00 10 |................|
-00000140 00 10 00 0e 06 70 72 6f 74 6f 32 06 70 72 6f 74 |.....proto2.prot|
-00000150 6f 31 |o1|
+00000000 16 03 01 00 bf 01 00 00 bb 03 03 82 57 14 fc ab |............W...|
+00000010 56 21 ff 72 39 72 3f fe f1 9b 0f 22 00 ff ef 44 |V!.r9r?...."...D|
+00000020 da db e0 83 d2 c0 a7 1c fb f0 6c 00 00 38 c0 2c |..........l..8.,|
+00000030 c0 30 00 9f cc a9 cc a8 cc aa c0 2b c0 2f 00 9e |.0.........+./..|
+00000040 c0 24 c0 28 00 6b c0 23 c0 27 00 67 c0 0a c0 14 |.$.(.k.#.'.g....|
+00000050 00 39 c0 09 c0 13 00 33 00 9d 00 9c 00 3d 00 3c |.9.....3.....=.<|
+00000060 00 35 00 2f 00 ff 01 00 00 5a 00 0b 00 04 03 00 |.5./.....Z......|
+00000070 01 02 00 0a 00 0a 00 08 00 1d 00 17 00 19 00 18 |................|
+00000080 00 23 00 00 00 0d 00 20 00 1e 06 01 06 02 06 03 |.#..... ........|
+00000090 05 01 05 02 05 03 04 01 04 02 04 03 03 01 03 02 |................|
+000000a0 03 03 02 01 02 02 02 03 00 10 00 10 00 0e 06 70 |...............p|
+000000b0 72 6f 74 6f 32 06 70 72 6f 74 6f 31 00 16 00 00 |roto2.proto1....|
+000000c0 00 17 00 00 |....|
>>> Flow 2 (server to client)
00000000 16 03 03 00 35 02 00 00 31 03 03 00 00 00 00 00 |....5...1.......|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000020 00 00 00 00 00 00 00 00 00 00 00 00 c0 30 00 00 |.............0..|
-00000030 09 00 23 00 00 ff 01 00 01 00 16 03 03 02 71 0b |..#...........q.|
-00000040 00 02 6d 00 02 6a 00 02 67 30 82 02 63 30 82 01 |..m..j..g0..c0..|
-00000050 cc a0 03 02 01 02 02 09 00 a2 73 00 0c 81 00 cb |..........s.....|
-00000060 f3 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 |.0...*.H........|
-00000070 30 2b 31 17 30 15 06 03 55 04 0a 13 0e 47 6f 6f |0+1.0...U....Goo|
-00000080 67 6c 65 20 54 45 53 54 49 4e 47 31 10 30 0e 06 |gle TESTING1.0..|
-00000090 03 55 04 03 13 07 47 6f 20 52 6f 6f 74 30 1e 17 |.U....Go Root0..|
-000000a0 0d 31 35 30 31 30 31 30 30 30 30 30 30 5a 17 0d |.150101000000Z..|
-000000b0 32 35 30 31 30 31 30 30 30 30 30 30 5a 30 26 31 |250101000000Z0&1|
-000000c0 17 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 |.0...U....Google|
-000000d0 20 54 45 53 54 49 4e 47 31 0b 30 09 06 03 55 04 | TESTING1.0...U.|
-000000e0 03 13 02 47 6f 30 81 9f 30 0d 06 09 2a 86 48 86 |...Go0..0...*.H.|
-000000f0 f7 0d 01 01 01 05 00 03 81 8d 00 30 81 89 02 81 |...........0....|
-00000100 81 00 af 87 88 f6 20 1b 95 65 6c 14 ab 44 05 af |...... ..el..D..|
-00000110 3b 45 14 e3 b7 6d fd 00 63 4d 95 7f fe 6a 62 35 |;E...m..cM...jb5|
-00000120 86 c0 4a f9 18 7c f6 aa 25 5e 7a 64 31 66 00 ba |..J..|..%^zd1f..|
-00000130 f4 8e 92 af c7 6b d8 76 d4 f3 5f 41 cb 6e 56 15 |.....k.v.._A.nV.|
-00000140 97 1b 97 c1 3c 12 39 21 66 3d 2b 16 d1 bc db 1c |....<.9!f=+.....|
-00000150 c0 a7 da b7 ca ad ba da cb d5 21 50 ec de 8d ab |..........!P....|
-00000160 d1 6b 81 4b 89 02 f3 c4 be c1 6c 89 b1 44 84 bd |.k.K......l..D..|
-00000170 21 d1 04 7d 9d 16 4d f9 82 15 f6 ef fa d6 09 47 |!..}..M........G|
-00000180 f2 fb 02 03 01 00 01 a3 81 93 30 81 90 30 0e 06 |..........0..0..|
-00000190 03 55 1d 0f 01 01 ff 04 04 03 02 05 a0 30 1d 06 |.U...........0..|
-000001a0 03 55 1d 25 04 16 30 14 06 08 2b 06 01 05 05 07 |.U.%..0...+.....|
-000001b0 03 01 06 08 2b 06 01 05 05 07 03 02 30 0c 06 03 |....+.......0...|
-000001c0 55 1d 13 01 01 ff 04 02 30 00 30 19 06 03 55 1d |U.......0.0...U.|
-000001d0 0e 04 12 04 10 12 50 8d 89 6f 1b d1 dc 54 4d 6e |......P..o...TMn|
-000001e0 cb 69 5e 06 f4 30 1b 06 03 55 1d 23 04 14 30 12 |.i^..0...U.#..0.|
-000001f0 80 10 bf 3d b6 a9 66 f2 b8 40 cf ea b4 03 78 48 |...=..f.. at ....xH|
-00000200 1a 41 30 19 06 03 55 1d 11 04 12 30 10 82 0e 65 |.A0...U....0...e|
-00000210 78 61 6d 70 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 |xample.golang0..|
-00000220 09 2a 86 48 86 f7 0d 01 01 0b 05 00 03 81 81 00 |.*.H............|
-00000230 92 7c af 91 55 12 18 96 59 31 a6 48 40 d5 2d d5 |.|..U...Y1.H at .-.|
-00000240 ee bb 02 a0 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 da |.......|..0}<.v.|
-00000250 4f 3d c0 fa ae 2d 33 24 6b 03 7b 1b 67 59 11 21 |O=...-3$k.{.gY.!|
-00000260 b5 11 bc 77 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f 22 |...w...n.-.5.d_"|
-00000270 3e 63 10 6b be ff 14 86 6d 0d f0 15 31 a8 14 38 |>c.k....m...1..8|
-00000280 1e 3b 84 87 2c cb 98 ed 51 76 b9 b1 4f dd db 9b |.;..,...Qv..O...|
-00000290 84 04 86 40 fa 51 dd ba b4 8d eb e3 46 de 46 b9 |... at .Q......F.F.|
-000002a0 4f 86 c7 f9 a4 c2 41 34 ac cc f6 ea b0 ab 39 18 |O.....A4......9.|
-000002b0 16 03 03 00 cd 0c 00 00 c9 03 00 17 41 04 1e 18 |............A...|
-000002c0 37 ef 0d 19 51 88 35 75 71 b5 e5 54 5b 12 2e 8f |7...Q.5uq..T[...|
-000002d0 09 67 fd a7 24 20 3e b2 56 1c ce 97 28 5e f8 2b |.g..$ >.V...(^.+|
-000002e0 2d 4f 9e f1 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 |-O....lK[.V.2B.X|
-000002f0 b6 d7 49 a6 b5 68 1a 41 03 56 6b dc 5a 89 05 01 |..I..h.A.Vk.Z...|
-00000300 00 80 97 89 a3 7f 30 d1 7b 70 26 3d a4 d5 66 2e |......0.{p&=..f.|
-00000310 cd fc 02 f5 37 a5 cd 09 69 7a c6 2f b2 62 e8 a6 |....7...iz./.b..|
-00000320 88 e2 3a c4 0a 8c 77 ad d3 c9 29 49 84 81 9c cd |..:...w...)I....|
-00000330 33 44 59 2d b5 2e e7 ce 12 c5 3b 46 13 6d 4a c8 |3DY-......;F.mJ.|
-00000340 6d f6 1f e7 f1 99 13 01 ca 43 79 fa b5 78 c7 1a |m........Cy..x..|
-00000350 7d 8f 85 dd 3b ca 56 22 c3 d0 41 11 1b 13 8c 07 |}...;.V"..A.....|
-00000360 02 75 87 7a ea 68 43 30 0b 2a 38 52 b2 8f cc ea |.u.z.hC0.*8R....|
-00000370 a3 a3 cb 71 fb 97 cd 3e 74 d0 5b 9b bd 17 13 f0 |...q...>t.[.....|
-00000380 d9 fe 16 03 03 00 04 0e 00 00 00 |...........|
+00000030 09 00 23 00 00 ff 01 00 01 00 16 03 03 02 59 0b |..#...........Y.|
+00000040 00 02 55 00 02 52 00 02 4f 30 82 02 4b 30 82 01 |..U..R..O0..K0..|
+00000050 b4 a0 03 02 01 02 02 09 00 e8 f0 9d 3f e2 5b ea |............?.[.|
+00000060 a6 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 |.0...*.H........|
+00000070 30 1f 31 0b 30 09 06 03 55 04 0a 13 02 47 6f 31 |0.1.0...U....Go1|
+00000080 10 30 0e 06 03 55 04 03 13 07 47 6f 20 52 6f 6f |.0...U....Go Roo|
+00000090 74 30 1e 17 0d 31 36 30 31 30 31 30 30 30 30 30 |t0...16010100000|
+000000a0 30 5a 17 0d 32 35 30 31 30 31 30 30 30 30 30 30 |0Z..250101000000|
+000000b0 5a 30 1a 31 0b 30 09 06 03 55 04 0a 13 02 47 6f |Z0.1.0...U....Go|
+000000c0 31 0b 30 09 06 03 55 04 03 13 02 47 6f 30 81 9f |1.0...U....Go0..|
+000000d0 30 0d 06 09 2a 86 48 86 f7 0d 01 01 01 05 00 03 |0...*.H.........|
+000000e0 81 8d 00 30 81 89 02 81 81 00 db 46 7d 93 2e 12 |...0.......F}...|
+000000f0 27 06 48 bc 06 28 21 ab 7e c4 b6 a2 5d fe 1e 52 |'.H..(!.~...]..R|
+00000100 45 88 7a 36 47 a5 08 0d 92 42 5b c2 81 c0 be 97 |E.z6G....B[.....|
+00000110 79 98 40 fb 4f 6d 14 fd 2b 13 8b c2 a5 2e 67 d8 |y. at .Om..+.....g.|
+00000120 d4 09 9e d6 22 38 b7 4a 0b 74 73 2b c2 34 f1 d1 |...."8.J.ts+.4..|
+00000130 93 e5 96 d9 74 7b f3 58 9f 6c 61 3c c0 b0 41 d4 |....t{.X.la<..A.|
+00000140 d9 2b 2b 24 23 77 5b 1c 3b bd 75 5d ce 20 54 cf |.++$#w[.;.u]. T.|
+00000150 a1 63 87 1d 1e 24 c4 f3 1d 1a 50 8b aa b6 14 43 |.c...$....P....C|
+00000160 ed 97 a7 75 62 f4 14 c8 52 d7 02 03 01 00 01 a3 |...ub...R.......|
+00000170 81 93 30 81 90 30 0e 06 03 55 1d 0f 01 01 ff 04 |..0..0...U......|
+00000180 04 03 02 05 a0 30 1d 06 03 55 1d 25 04 16 30 14 |.....0...U.%..0.|
+00000190 06 08 2b 06 01 05 05 07 03 01 06 08 2b 06 01 05 |..+.........+...|
+000001a0 05 07 03 02 30 0c 06 03 55 1d 13 01 01 ff 04 02 |....0...U.......|
+000001b0 30 00 30 19 06 03 55 1d 0e 04 12 04 10 9f 91 16 |0.0...U.........|
+000001c0 1f 43 43 3e 49 a6 de 6d b6 80 d7 9f 60 30 1b 06 |.CC>I..m....`0..|
+000001d0 03 55 1d 23 04 14 30 12 80 10 48 13 49 4d 13 7e |.U.#..0...H.IM.~|
+000001e0 16 31 bb a3 01 d5 ac ab 6e 7b 30 19 06 03 55 1d |.1......n{0...U.|
+000001f0 11 04 12 30 10 82 0e 65 78 61 6d 70 6c 65 2e 67 |...0...example.g|
+00000200 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 86 f7 0d 01 |olang0...*.H....|
+00000210 01 0b 05 00 03 81 81 00 9d 30 cc 40 2b 5b 50 a0 |.........0. at +[P.|
+00000220 61 cb ba e5 53 58 e1 ed 83 28 a9 58 1a a9 38 a4 |a...SX...(.X..8.|
+00000230 95 a1 ac 31 5a 1a 84 66 3d 43 d3 2d d9 0b f2 97 |...1Z..f=C.-....|
+00000240 df d3 20 64 38 92 24 3a 00 bc cf 9c 7d b7 40 20 |.. d8.$:....}.@ |
+00000250 01 5f aa d3 16 61 09 a2 76 fd 13 c3 cc e1 0c 5c |._...a..v......\|
+00000260 ee b1 87 82 f1 6c 04 ed 73 bb b3 43 77 8d 0c 1c |.....l..s..Cw...|
+00000270 f1 0f a1 d8 40 83 61 c9 4c 72 2b 9d ae db 46 06 |.... at .a.Lr+...F.|
+00000280 06 4d f4 c1 b3 3e c0 d1 bd 42 d4 db fe 3d 13 60 |.M...>...B...=.`|
+00000290 84 5c 21 d3 3b e9 fa e7 16 03 03 00 ac 0c 00 00 |.\!.;...........|
+000002a0 a8 03 00 1d 20 2f e5 7d a3 47 cd 62 43 15 28 da |.... /.}.G.bC.(.|
+000002b0 ac 5f bb 29 07 30 ff f6 84 af c4 cf c2 ed 90 99 |._.).0..........|
+000002c0 5f 58 cb 3b 74 05 01 00 80 bf 6d 57 f5 0c 78 c4 |_X.;t.....mW..x.|
+000002d0 77 48 0e 60 67 7a 3a 1b 3e 9e d2 88 a4 89 07 ef |wH.`gz:.>.......|
+000002e0 d1 45 1a 66 7e 8c ec cb da 71 ea ec ba ed 81 9e |.E.f~....q......|
+000002f0 21 4d 2e ba d4 8f c2 0a 67 ea 3a a1 d1 67 09 66 |!M......g.:..g.f|
+00000300 dc a8 ad 16 a2 23 2a db 4f 31 65 b1 54 13 73 d1 |.....#*.O1e.T.s.|
+00000310 f6 7b 75 d9 f1 07 19 b8 67 21 87 d2 3b cf a5 6c |.{u.....g!..;..l|
+00000320 61 8e af ed 60 7f f2 56 9f 0d 0f 19 88 98 30 3a |a...`..V......0:|
+00000330 61 8c 21 e7 8b 5d ab 6f cf 93 73 33 63 cd 50 bb |a.!..].o..s3c.P.|
+00000340 dd 0e ab 4f 6a fb a3 f9 68 16 03 03 00 04 0e 00 |...Oj...h.......|
+00000350 00 00 |..|
>>> Flow 3 (client to server)
-00000000 16 03 03 00 46 10 00 00 42 41 04 ba 5b 0f e7 ec |....F...BA..[...|
-00000010 8e c8 ad 51 8c c0 50 f1 8a 2a 68 32 74 d0 95 03 |...Q..P..*h2t...|
-00000020 0c 61 f1 1c 89 ed 95 5d 9a 4a 14 ee cc 14 9a 73 |.a.....].J.....s|
-00000030 f6 db 46 dd b7 47 8a 82 3d 7a b8 9f 45 d1 a2 3f |..F..G..=z..E..?|
-00000040 f4 34 9b b6 6d 7d 41 87 c9 d5 cd 14 03 03 00 01 |.4..m}A.........|
-00000050 01 16 03 03 00 28 1e ae f6 90 a9 91 eb 4b ca 23 |.....(.......K.#|
-00000060 6e bf 9e 67 5b 38 ab f6 d6 ee 12 aa b9 b6 d0 6e |n..g[8.........n|
-00000070 a7 dd 45 91 34 45 78 a0 04 9e d8 85 48 48 |..E.4Ex.....HH|
+00000000 16 03 03 00 25 10 00 00 21 20 05 0c 3b 8b 22 36 |....%...! ..;."6|
+00000010 61 79 58 28 b0 82 65 44 39 67 93 c5 2c 3b d1 40 |ayX(..eD9g..,;.@|
+00000020 88 af 9f 38 c1 fa e0 81 a0 19 14 03 03 00 01 01 |...8............|
+00000030 16 03 03 00 28 87 2e d2 c2 ce 65 6d e8 d9 da a0 |....(.....em....|
+00000040 9d dc f5 51 b0 84 88 8d c6 a3 0a 5d 08 10 ca c6 |...Q.......]....|
+00000050 e3 83 0c 0a cb 6d ec 09 b8 9f a5 45 99 |.....m.....E.|
>>> Flow 4 (server to client)
00000000 16 03 03 00 82 04 00 00 7e 00 00 00 00 00 78 50 |........~.....xP|
00000010 46 ad c1 db a8 38 86 7b 2b bb fd d0 c3 42 3e 00 |F....8.{+....B>.|
00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 94 |................|
-00000030 6f ec 80 83 61 4f 7f 09 64 32 96 26 b5 71 46 6a |o...aO..d2.&.qFj|
-00000040 29 7d fd 0b bb 49 13 0e c8 c5 de 06 ed 47 e8 cb |)}...I.......G..|
-00000050 d8 9f 18 82 69 af ab 24 d2 78 90 ba 9a c8 24 95 |....i..$.x....$.|
-00000060 46 53 19 2e e8 33 94 3c 22 73 26 d6 86 4e 01 a4 |FS...3.<"s&..N..|
-00000070 34 ea a8 bf f2 ca b5 0d fc f6 08 b9 31 b3 42 e7 |4...........1.B.|
-00000080 c1 92 96 f9 bf 9a 00 14 03 03 00 01 01 16 03 03 |................|
-00000090 00 28 00 00 00 00 00 00 00 00 bd 51 1d 0e bd 51 |.(.........Q...Q|
-000000a0 a3 b1 03 f2 df f4 ba 9b 1e a5 a8 22 e7 ce 7c 19 |..........."..|.|
-000000b0 1a bf 37 3d 42 f4 4d 6f 63 75 17 03 03 00 25 00 |..7=B.Mocu....%.|
-000000c0 00 00 00 00 00 00 01 52 8a d2 34 52 70 f1 cf 87 |.......R..4Rp...|
-000000d0 54 4e fd e6 11 a7 76 1a f4 7b 70 e8 34 ef 01 c8 |TN....v..{p.4...|
-000000e0 6c 4a f8 6d 15 03 03 00 1a 00 00 00 00 00 00 00 |lJ.m............|
-000000f0 02 8a 4c f9 7c d1 61 a6 cd 2a e6 3a 5b b0 cb aa |..L.|.a..*.:[...|
-00000100 91 2e 8b |...|
+00000030 6f ec 80 83 61 34 53 e2 a4 e2 ff 73 4f 1b 15 8f |o...a4S....sO...|
+00000040 3b 43 47 ac 20 c6 2d 5e 52 7a 61 6f af 40 c3 5a |;CG. .-^Rzao. at .Z|
+00000050 cb 3f 7d 10 a9 90 ca cf 8d c4 c4 d4 a3 b8 1d 62 |.?}............b|
+00000060 7d a9 68 32 01 33 94 65 8b 67 73 aa 51 d4 08 1d |}.h2.3.e.gs.Q...|
+00000070 ce 76 6b ef 3d e6 ce d3 42 fe 24 cf f3 82 5b 17 |.vk.=...B.$...[.|
+00000080 5c 03 e9 50 94 8e 8b 14 03 03 00 01 01 16 03 03 |\..P............|
+00000090 00 28 00 00 00 00 00 00 00 00 c2 7c e6 69 c9 ec |.(.........|.i..|
+000000a0 b5 55 57 34 8e 86 38 e6 28 85 b0 c8 2e c8 0f a6 |.UW4..8.(.......|
+000000b0 a9 07 f4 91 47 46 dd fe c8 57 17 03 03 00 25 00 |....GF...W....%.|
+000000c0 00 00 00 00 00 00 01 39 9a a2 da d8 3d 7f 25 0e |.......9....=.%.|
+000000d0 83 a8 cd 57 d8 a4 7e 9f e1 e2 fe 3f 5a ed b9 99 |...W..~....?Z...|
+000000e0 b6 4d 97 3a 15 03 03 00 1a 00 00 00 00 00 00 00 |.M.:............|
+000000f0 02 d5 2a aa 1e 7a 60 b8 79 56 c6 56 75 11 b7 4c |..*..z`.yV.Vu..L|
+00000100 83 19 9c |...|
diff --git a/src/crypto/tls/testdata/Server-TLSv12-CipherSuiteCertPreferenceECDSA b/src/crypto/tls/testdata/Server-TLSv12-CipherSuiteCertPreferenceECDSA
index ae3748f..e286407 100644
--- a/src/crypto/tls/testdata/Server-TLSv12-CipherSuiteCertPreferenceECDSA
+++ b/src/crypto/tls/testdata/Server-TLSv12-CipherSuiteCertPreferenceECDSA
@@ -1,24 +1,15 @@
>>> Flow 1 (client to server)
-00000000 16 03 01 01 35 01 00 01 31 03 03 00 02 67 8e 1d |....5...1....g..|
-00000010 3b d2 26 20 63 c5 6a b6 68 25 02 72 ce 86 6b c7 |;.& c.j.h%.r..k.|
-00000020 97 1a 9f 4d be 02 98 ac 24 5e 82 00 00 b6 c0 30 |...M....$^.....0|
-00000030 c0 2c c0 28 c0 24 c0 14 c0 0a 00 a5 00 a3 00 a1 |.,.(.$..........|
-00000040 00 9f 00 6b 00 6a 00 69 00 68 00 39 00 38 00 37 |...k.j.i.h.9.8.7|
-00000050 00 36 00 88 00 87 00 86 00 85 c0 32 c0 2e c0 2a |.6.........2...*|
-00000060 c0 26 c0 0f c0 05 00 9d 00 3d 00 35 00 84 c0 2f |.&.......=.5.../|
-00000070 c0 2b c0 27 c0 23 c0 13 c0 09 00 a4 00 a2 00 a0 |.+.'.#..........|
-00000080 00 9e 00 67 00 40 00 3f 00 3e 00 33 00 32 00 31 |...g. at .?.>.3.2.1|
-00000090 00 30 00 9a 00 99 00 98 00 97 00 45 00 44 00 43 |.0.........E.D.C|
-000000a0 00 42 c0 31 c0 2d c0 29 c0 25 c0 0e c0 04 00 9c |.B.1.-.).%......|
-000000b0 00 3c 00 2f 00 96 00 41 00 07 c0 11 c0 07 c0 0c |.<./...A........|
-000000c0 c0 02 00 05 00 04 c0 12 c0 08 00 16 00 13 00 10 |................|
-000000d0 00 0d c0 0d c0 03 00 0a 00 15 00 12 00 0f 00 0c |................|
-000000e0 00 09 00 ff 02 01 00 00 51 00 0b 00 04 03 00 01 |........Q.......|
-000000f0 02 00 0a 00 1c 00 1a 00 17 00 19 00 1c 00 1b 00 |................|
-00000100 18 00 1a 00 16 00 0e 00 0d 00 0b 00 0c 00 09 00 |................|
-00000110 0a 00 0d 00 20 00 1e 06 01 06 02 06 03 05 01 05 |.... ...........|
-00000120 02 05 03 04 01 04 02 04 03 03 01 03 02 03 03 02 |................|
-00000130 01 02 02 02 03 00 0f 00 01 01 |..........|
+00000000 16 03 01 00 a7 01 00 00 a3 03 03 27 01 f3 21 98 |...........'..!.|
+00000010 ff 55 7f 78 32 44 b7 9d 88 6b 82 43 26 52 00 74 |.U.x2D...k.C&R.t|
+00000020 fb 05 ca be 23 1f d0 18 1f 74 c2 00 00 38 c0 2c |....#....t...8.,|
+00000030 c0 30 00 9f cc a9 cc a8 cc aa c0 2b c0 2f 00 9e |.0.........+./..|
+00000040 c0 24 c0 28 00 6b c0 23 c0 27 00 67 c0 0a c0 14 |.$.(.k.#.'.g....|
+00000050 00 39 c0 09 c0 13 00 33 00 9d 00 9c 00 3d 00 3c |.9.....3.....=.<|
+00000060 00 35 00 2f 00 ff 01 00 00 42 00 0b 00 04 03 00 |.5./.....B......|
+00000070 01 02 00 0a 00 0a 00 08 00 1d 00 17 00 19 00 18 |................|
+00000080 00 0d 00 20 00 1e 06 01 06 02 06 03 05 01 05 02 |... ............|
+00000090 05 03 04 01 04 02 04 03 03 01 03 02 03 03 02 01 |................|
+000000a0 02 02 02 03 00 16 00 00 00 17 00 00 |............|
>>> Flow 2 (server to client)
00000000 16 03 03 00 31 02 00 00 2d 03 03 00 00 00 00 00 |....1...-.......|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
@@ -56,43 +47,39 @@
00000210 0e bd 3f a3 8c 25 c1 33 13 83 0d 94 06 bb d4 37 |..?..%.3.......7|
00000220 7a f6 ec 7a c9 86 2e dd d7 11 69 7f 85 7c 56 de |z..z......i..|V.|
00000230 fb 31 78 2b e4 c7 78 0d ae cb be 9e 4e 36 24 31 |.1x+..x.....N6$1|
-00000240 7b 6a 0f 39 95 12 07 8f 2a 16 03 03 00 d8 0c 00 |{j.9....*.......|
-00000250 00 d4 03 00 17 41 04 1e 18 37 ef 0d 19 51 88 35 |.....A...7...Q.5|
-00000260 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd a7 24 20 3e |uq..T[....g..$ >|
-00000270 b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e f1 07 9f 6c |.V...(^.+-O....l|
-00000280 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 a6 b5 68 1a |K[.V.2B.X..I..h.|
-00000290 41 03 56 6b dc 5a 89 05 03 00 8b 30 81 88 02 42 |A.Vk.Z.....0...B|
-000002a0 01 bc 56 16 22 ad fd e7 ac ba c8 f5 3f c0 d7 f8 |..V.".......?...|
-000002b0 8c 64 e0 ba 09 30 c3 66 49 90 7e d2 68 86 07 72 |.d...0.fI.~.h..r|
-000002c0 20 87 a1 e1 36 92 a7 68 e2 c3 6e 34 93 a9 ca e8 | ...6..h..n4....|
-000002d0 68 3d 9e 42 c4 1e 8e 2d 95 05 ee a6 a4 2c 8d be |h=.B...-.....,..|
-000002e0 e3 88 02 42 01 16 18 77 b9 99 0e f8 46 90 46 07 |...B...w....F.F.|
-000002f0 f9 67 a9 26 68 d7 da c8 a1 d9 67 55 ec 37 11 2d |.g.&h.....gU.7.-|
-00000300 4b f3 52 f4 96 6a 0e 8a 6a 14 21 94 63 ea f9 70 |K.R..j..j.!.c..p|
-00000310 2d 57 05 8a 72 29 6e d2 60 a1 97 af 08 5b c3 cf |-W..r)n.`....[..|
-00000320 3a 82 a3 81 11 cf 16 03 03 00 04 0e 00 00 00 |:..............|
+00000240 7b 6a 0f 39 95 12 07 8f 2a 16 03 03 00 b7 0c 00 |{j.9....*.......|
+00000250 00 b3 03 00 1d 20 2f e5 7d a3 47 cd 62 43 15 28 |..... /.}.G.bC.(|
+00000260 da ac 5f bb 29 07 30 ff f6 84 af c4 cf c2 ed 90 |.._.).0.........|
+00000270 99 5f 58 cb 3b 74 05 03 00 8b 30 81 88 02 42 01 |._X.;t....0...B.|
+00000280 4f 30 aa d0 4d e5 61 db ba fc 95 15 52 ef 2a 41 |O0..M.a.....R.*A|
+00000290 b4 d6 59 ac 39 61 b6 38 08 1e 87 b3 ca 9b 49 d3 |..Y.9a.8......I.|
+000002a0 95 5a c5 29 84 cd 10 73 4a cc 09 df 1a b0 54 6d |.Z.)...sJ.....Tm|
+000002b0 b8 61 28 80 2e ec cf 95 9d 6f c3 d9 ed 80 53 63 |.a(......o....Sc|
+000002c0 d9 02 42 00 af 71 2f 91 80 ff a1 79 82 c7 d9 79 |..B..q/....y...y|
+000002d0 fa 12 a9 88 7b 93 47 be 6a dc 80 42 17 9d 85 7a |....{.G.j..B...z|
+000002e0 b8 1b fe 85 7f 5c 10 9c 9e 0e e1 71 a7 b0 12 02 |.....\.....q....|
+000002f0 e2 a4 79 c4 8d d8 02 09 01 9c 6f 7a 27 7c 1f f4 |..y.......oz'|..|
+00000300 38 46 59 46 94 16 03 03 00 04 0e 00 00 00 |8FYF..........|
>>> Flow 3 (client to server)
-00000000 16 03 03 00 46 10 00 00 42 41 04 8c 80 0c da 24 |....F...BA.....$|
-00000010 d6 66 ff cc 1b 26 d5 3f 37 37 16 8f 16 ee 0d 5f |.f...&.?77....._|
-00000020 c3 0e 62 7c e4 52 2d 43 29 e9 6b da 49 bc 99 16 |..b|.R-C).k.I...|
-00000030 28 46 8e 43 20 7f 12 66 1c 94 1c 03 55 6f 05 53 |(F.C ..f....Uo.S|
-00000040 6f b7 dc 8b 70 9d 9d c5 1f da 5b 14 03 03 00 01 |o...p.....[.....|
-00000050 01 16 03 03 00 40 17 60 dd e5 b2 58 fd 74 10 38 |..... at .`...X.t.8|
-00000060 95 b1 73 7e 8f 7a 2b d0 f5 65 80 0c dc b1 ca 29 |..s~.z+..e.....)|
-00000070 06 25 e1 f9 c3 c0 7c 88 e4 ad d3 16 0a 8a dd 1f |.%....|.........|
-00000080 a7 86 86 0f ac c7 ea f5 0f 1f 2b 97 85 b3 81 f7 |..........+.....|
-00000090 5d 42 2f 3b 72 80 |]B/;r.|
+00000000 16 03 03 00 25 10 00 00 21 20 8c 80 e4 c7 bd d7 |....%...! ......|
+00000010 ea ea 42 f7 53 24 50 28 6a e9 f3 ff 4f 4a 28 22 |..B.S$P(j...OJ("|
+00000020 a2 95 09 fc f0 d9 3e fc cc 6e 14 03 03 00 01 01 |......>..n......|
+00000030 16 03 03 00 40 79 56 60 f5 45 e7 48 9e 97 1d 49 |.... at yV`.E.H...I|
+00000040 de 59 dd b0 f0 0a d2 cc 10 f0 98 3c c2 d5 67 d6 |.Y.........<..g.|
+00000050 2c 18 2b 21 ae a3 2f ea 2d 0b ff fd e6 c2 73 25 |,.+!../.-.....s%|
+00000060 1c 01 3e 94 3a cc 1d 58 6b fb 7f 85 e4 50 ec 10 |..>.:..Xk....P..|
+00000070 b9 d7 71 cb be |..q..|
>>> Flow 4 (server to client)
00000000 14 03 03 00 01 01 16 03 03 00 40 00 00 00 00 00 |.......... at .....|
-00000010 00 00 00 00 00 00 00 00 00 00 00 82 01 fd 38 ae |..............8.|
-00000020 a4 07 8f bd 72 0a a2 b5 c5 78 09 89 65 1b 6d 1e |....r....x..e.m.|
-00000030 56 52 9d 4f de 02 15 2d 93 d8 8f d7 1f bb 07 3b |VR.O...-.......;|
-00000040 e9 62 3c 19 3e 19 65 ac 10 aa e5 17 03 03 00 40 |.b<.>.e........@|
+00000010 00 00 00 00 00 00 00 00 00 00 00 83 5c 5c e3 c0 |............\\..|
+00000020 20 56 8c 92 4b 75 f0 30 bd 67 74 52 f1 af 9c 14 | V..Ku.0.gtR....|
+00000030 29 1e e4 b2 5b c0 2c e6 48 6f 94 42 7b 21 92 96 |)...[.,.Ho.B{!..|
+00000040 0a 83 ce 1c 91 36 95 8c 14 38 57 17 03 03 00 40 |.....6...8W....@|
00000050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
-00000060 18 61 1d 26 f3 b9 34 20 00 6c 27 75 fc 35 f5 c2 |.a.&..4 .l'u.5..|
-00000070 6f 71 ca 9b 0d 70 30 46 57 7c 07 86 7d 52 a9 d6 |oq...p0FW|..}R..|
-00000080 ab fc 89 a5 48 79 ae 60 03 05 4b 17 b2 d9 6b 39 |....Hy.`..K...k9|
+00000060 73 a4 40 cf ad 86 cc 05 9e 47 5f 83 50 ae 68 d5 |s. at ......G_.P.h.|
+00000070 d1 6a a9 8c ba 74 fe c0 cc 4a 1a e3 b0 14 0d 31 |.j...t...J.....1|
+00000080 9f 06 54 e3 95 3a 89 6d 34 54 0c e4 b4 34 38 21 |..T..:.m4T...48!|
00000090 15 03 03 00 30 00 00 00 00 00 00 00 00 00 00 00 |....0...........|
-000000a0 00 00 00 00 00 8f 8d 88 88 c5 1e f5 bf 06 f2 45 |...............E|
-000000b0 e7 fe f0 24 c7 4c 92 5a 80 a7 89 c8 2b ac 49 d9 |...$.L.Z....+.I.|
-000000c0 39 00 ca 57 ec |9..W.|
+000000a0 00 00 00 00 00 e6 dd b2 11 ab a7 34 61 00 d4 09 |...........4a...|
+000000b0 bc ea c1 5f c4 e2 52 60 63 96 f0 fd 44 4e f9 0e |..._..R`c...DN..|
+000000c0 af 32 99 e4 12 |.2...|
diff --git a/src/crypto/tls/testdata/Server-TLSv12-CipherSuiteCertPreferenceRSA b/src/crypto/tls/testdata/Server-TLSv12-CipherSuiteCertPreferenceRSA
index 144ef42..1f9fbc1 100644
--- a/src/crypto/tls/testdata/Server-TLSv12-CipherSuiteCertPreferenceRSA
+++ b/src/crypto/tls/testdata/Server-TLSv12-CipherSuiteCertPreferenceRSA
@@ -1,104 +1,89 @@
>>> Flow 1 (client to server)
-00000000 16 03 01 01 35 01 00 01 31 03 03 ed 84 e2 1a c1 |....5...1.......|
-00000010 d9 3f a5 ba 70 0b 5f 3f 3b 87 79 18 27 03 92 ee |.?..p._?;.y.'...|
-00000020 b1 9f c7 36 26 e3 0b 6d fc d5 ed 00 00 b6 c0 30 |...6&..m.......0|
-00000030 c0 2c c0 28 c0 24 c0 14 c0 0a 00 a5 00 a3 00 a1 |.,.(.$..........|
-00000040 00 9f 00 6b 00 6a 00 69 00 68 00 39 00 38 00 37 |...k.j.i.h.9.8.7|
-00000050 00 36 00 88 00 87 00 86 00 85 c0 32 c0 2e c0 2a |.6.........2...*|
-00000060 c0 26 c0 0f c0 05 00 9d 00 3d 00 35 00 84 c0 2f |.&.......=.5.../|
-00000070 c0 2b c0 27 c0 23 c0 13 c0 09 00 a4 00 a2 00 a0 |.+.'.#..........|
-00000080 00 9e 00 67 00 40 00 3f 00 3e 00 33 00 32 00 31 |...g. at .?.>.3.2.1|
-00000090 00 30 00 9a 00 99 00 98 00 97 00 45 00 44 00 43 |.0.........E.D.C|
-000000a0 00 42 c0 31 c0 2d c0 29 c0 25 c0 0e c0 04 00 9c |.B.1.-.).%......|
-000000b0 00 3c 00 2f 00 96 00 41 00 07 c0 11 c0 07 c0 0c |.<./...A........|
-000000c0 c0 02 00 05 00 04 c0 12 c0 08 00 16 00 13 00 10 |................|
-000000d0 00 0d c0 0d c0 03 00 0a 00 15 00 12 00 0f 00 0c |................|
-000000e0 00 09 00 ff 02 01 00 00 51 00 0b 00 04 03 00 01 |........Q.......|
-000000f0 02 00 0a 00 1c 00 1a 00 17 00 19 00 1c 00 1b 00 |................|
-00000100 18 00 1a 00 16 00 0e 00 0d 00 0b 00 0c 00 09 00 |................|
-00000110 0a 00 0d 00 20 00 1e 06 01 06 02 06 03 05 01 05 |.... ...........|
-00000120 02 05 03 04 01 04 02 04 03 03 01 03 02 03 03 02 |................|
-00000130 01 02 02 02 03 00 0f 00 01 01 |..........|
+00000000 16 03 01 00 a7 01 00 00 a3 03 03 1d 39 c9 33 73 |............9.3s|
+00000010 c2 b9 71 d8 66 23 63 a7 5c 9e 50 b6 3e a5 f9 bb |..q.f#c.\.P.>...|
+00000020 34 1b 71 e1 09 4f ae d5 53 8a e8 00 00 38 c0 2c |4.q..O..S....8.,|
+00000030 c0 30 00 9f cc a9 cc a8 cc aa c0 2b c0 2f 00 9e |.0.........+./..|
+00000040 c0 24 c0 28 00 6b c0 23 c0 27 00 67 c0 0a c0 14 |.$.(.k.#.'.g....|
+00000050 00 39 c0 09 c0 13 00 33 00 9d 00 9c 00 3d 00 3c |.9.....3.....=.<|
+00000060 00 35 00 2f 00 ff 01 00 00 42 00 0b 00 04 03 00 |.5./.....B......|
+00000070 01 02 00 0a 00 0a 00 08 00 1d 00 17 00 19 00 18 |................|
+00000080 00 0d 00 20 00 1e 06 01 06 02 06 03 05 01 05 02 |... ............|
+00000090 05 03 04 01 04 02 04 03 03 01 03 02 03 03 02 01 |................|
+000000a0 02 02 02 03 00 16 00 00 00 17 00 00 |............|
>>> Flow 2 (server to client)
00000000 16 03 03 00 31 02 00 00 2d 03 03 00 00 00 00 00 |....1...-.......|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000020 00 00 00 00 00 00 00 00 00 00 00 00 c0 14 00 00 |................|
-00000030 05 ff 01 00 01 00 16 03 03 02 71 0b 00 02 6d 00 |..........q...m.|
-00000040 02 6a 00 02 67 30 82 02 63 30 82 01 cc a0 03 02 |.j..g0..c0......|
-00000050 01 02 02 09 00 a2 73 00 0c 81 00 cb f3 30 0d 06 |......s......0..|
-00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 2b 31 17 |.*.H........0+1.|
-00000070 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 |0...U....Google |
-00000080 54 45 53 54 49 4e 47 31 10 30 0e 06 03 55 04 03 |TESTING1.0...U..|
-00000090 13 07 47 6f 20 52 6f 6f 74 30 1e 17 0d 31 35 30 |..Go Root0...150|
-000000a0 31 30 31 30 30 30 30 30 30 5a 17 0d 32 35 30 31 |101000000Z..2501|
-000000b0 30 31 30 30 30 30 30 30 5a 30 26 31 17 30 15 06 |01000000Z0&1.0..|
-000000c0 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 54 45 53 |.U....Google TES|
-000000d0 54 49 4e 47 31 0b 30 09 06 03 55 04 03 13 02 47 |TING1.0...U....G|
-000000e0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....|
-000000f0 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 af 87 |.......0........|
-00000100 88 f6 20 1b 95 65 6c 14 ab 44 05 af 3b 45 14 e3 |.. ..el..D..;E..|
-00000110 b7 6d fd 00 63 4d 95 7f fe 6a 62 35 86 c0 4a f9 |.m..cM...jb5..J.|
-00000120 18 7c f6 aa 25 5e 7a 64 31 66 00 ba f4 8e 92 af |.|..%^zd1f......|
-00000130 c7 6b d8 76 d4 f3 5f 41 cb 6e 56 15 97 1b 97 c1 |.k.v.._A.nV.....|
-00000140 3c 12 39 21 66 3d 2b 16 d1 bc db 1c c0 a7 da b7 |<.9!f=+.........|
-00000150 ca ad ba da cb d5 21 50 ec de 8d ab d1 6b 81 4b |......!P.....k.K|
-00000160 89 02 f3 c4 be c1 6c 89 b1 44 84 bd 21 d1 04 7d |......l..D..!..}|
-00000170 9d 16 4d f9 82 15 f6 ef fa d6 09 47 f2 fb 02 03 |..M........G....|
-00000180 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..|
-00000190 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%|
-000001a0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........|
-000001b0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...|
-000001c0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....|
-000001d0 10 12 50 8d 89 6f 1b d1 dc 54 4d 6e cb 69 5e 06 |..P..o...TMn.i^.|
-000001e0 f4 30 1b 06 03 55 1d 23 04 14 30 12 80 10 bf 3d |.0...U.#..0....=|
-000001f0 b6 a9 66 f2 b8 40 cf ea b4 03 78 48 1a 41 30 19 |..f.. at ....xH.A0.|
-00000200 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp|
-00000210 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H|
-00000220 86 f7 0d 01 01 0b 05 00 03 81 81 00 92 7c af 91 |.............|..|
-00000230 55 12 18 96 59 31 a6 48 40 d5 2d d5 ee bb 02 a0 |U...Y1.H at .-.....|
-00000240 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 da 4f 3d c0 fa |...|..0}<.v.O=..|
-00000250 ae 2d 33 24 6b 03 7b 1b 67 59 11 21 b5 11 bc 77 |.-3$k.{.gY.!...w|
-00000260 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f 22 3e 63 10 6b |...n.-.5.d_">c.k|
-00000270 be ff 14 86 6d 0d f0 15 31 a8 14 38 1e 3b 84 87 |....m...1..8.;..|
-00000280 2c cb 98 ed 51 76 b9 b1 4f dd db 9b 84 04 86 40 |,...Qv..O......@|
-00000290 fa 51 dd ba b4 8d eb e3 46 de 46 b9 4f 86 c7 f9 |.Q......F.F.O...|
-000002a0 a4 c2 41 34 ac cc f6 ea b0 ab 39 18 16 03 03 00 |..A4......9.....|
-000002b0 cd 0c 00 00 c9 03 00 17 41 04 1e 18 37 ef 0d 19 |........A...7...|
-000002c0 51 88 35 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd a7 |Q.5uq..T[....g..|
-000002d0 24 20 3e b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e f1 |$ >.V...(^.+-O..|
-000002e0 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 a6 |..lK[.V.2B.X..I.|
-000002f0 b5 68 1a 41 03 56 6b dc 5a 89 05 01 00 80 7c 5c |.h.A.Vk.Z.....|\|
-00000300 f6 68 cc 07 f0 bd ec 30 07 d0 70 1b c6 95 a4 14 |.h.....0..p.....|
-00000310 67 3a 83 a1 43 ff 0a c3 f0 b7 ee 59 f8 c7 09 65 |g:..C......Y...e|
-00000320 08 ac 18 34 d4 8f 46 c4 2c 91 7b 57 95 e0 54 03 |...4..F.,.{W..T.|
-00000330 d8 8e b6 53 61 74 77 8b a3 5f 23 f0 06 dc 3a 56 |...Satw.._#...:V|
-00000340 61 80 5e 31 d5 75 c3 05 9f d0 06 1f c5 32 ba 79 |a.^1.u.......2.y|
-00000350 fd 14 a9 54 5a 18 b4 2b 09 0e 19 ab 76 0b 12 5d |...TZ..+....v..]|
-00000360 52 27 ce b8 dd 4c f8 f2 d2 70 56 43 19 53 b3 13 |R'...L...pVC.S..|
-00000370 b9 b7 65 ce cd 50 ed 4a 9f 42 96 c7 3c b9 16 03 |..e..P.J.B..<...|
-00000380 03 00 04 0e 00 00 00 |.......|
+00000030 05 ff 01 00 01 00 16 03 03 02 59 0b 00 02 55 00 |..........Y...U.|
+00000040 02 52 00 02 4f 30 82 02 4b 30 82 01 b4 a0 03 02 |.R..O0..K0......|
+00000050 01 02 02 09 00 e8 f0 9d 3f e2 5b ea a6 30 0d 06 |........?.[..0..|
+00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 1f 31 0b |.*.H........0.1.|
+00000070 30 09 06 03 55 04 0a 13 02 47 6f 31 10 30 0e 06 |0...U....Go1.0..|
+00000080 03 55 04 03 13 07 47 6f 20 52 6f 6f 74 30 1e 17 |.U....Go Root0..|
+00000090 0d 31 36 30 31 30 31 30 30 30 30 30 30 5a 17 0d |.160101000000Z..|
+000000a0 32 35 30 31 30 31 30 30 30 30 30 30 5a 30 1a 31 |250101000000Z0.1|
+000000b0 0b 30 09 06 03 55 04 0a 13 02 47 6f 31 0b 30 09 |.0...U....Go1.0.|
+000000c0 06 03 55 04 03 13 02 47 6f 30 81 9f 30 0d 06 09 |..U....Go0..0...|
+000000d0 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 30 |*.H............0|
+000000e0 81 89 02 81 81 00 db 46 7d 93 2e 12 27 06 48 bc |.......F}...'.H.|
+000000f0 06 28 21 ab 7e c4 b6 a2 5d fe 1e 52 45 88 7a 36 |.(!.~...]..RE.z6|
+00000100 47 a5 08 0d 92 42 5b c2 81 c0 be 97 79 98 40 fb |G....B[.....y. at .|
+00000110 4f 6d 14 fd 2b 13 8b c2 a5 2e 67 d8 d4 09 9e d6 |Om..+.....g.....|
+00000120 22 38 b7 4a 0b 74 73 2b c2 34 f1 d1 93 e5 96 d9 |"8.J.ts+.4......|
+00000130 74 7b f3 58 9f 6c 61 3c c0 b0 41 d4 d9 2b 2b 24 |t{.X.la<..A..++$|
+00000140 23 77 5b 1c 3b bd 75 5d ce 20 54 cf a1 63 87 1d |#w[.;.u]. T..c..|
+00000150 1e 24 c4 f3 1d 1a 50 8b aa b6 14 43 ed 97 a7 75 |.$....P....C...u|
+00000160 62 f4 14 c8 52 d7 02 03 01 00 01 a3 81 93 30 81 |b...R.........0.|
+00000170 90 30 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 05 |.0...U..........|
+00000180 a0 30 1d 06 03 55 1d 25 04 16 30 14 06 08 2b 06 |.0...U.%..0...+.|
+00000190 01 05 05 07 03 01 06 08 2b 06 01 05 05 07 03 02 |........+.......|
+000001a0 30 0c 06 03 55 1d 13 01 01 ff 04 02 30 00 30 19 |0...U.......0.0.|
+000001b0 06 03 55 1d 0e 04 12 04 10 9f 91 16 1f 43 43 3e |..U..........CC>|
+000001c0 49 a6 de 6d b6 80 d7 9f 60 30 1b 06 03 55 1d 23 |I..m....`0...U.#|
+000001d0 04 14 30 12 80 10 48 13 49 4d 13 7e 16 31 bb a3 |..0...H.IM.~.1..|
+000001e0 01 d5 ac ab 6e 7b 30 19 06 03 55 1d 11 04 12 30 |....n{0...U....0|
+000001f0 10 82 0e 65 78 61 6d 70 6c 65 2e 67 6f 6c 61 6e |...example.golan|
+00000200 67 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 |g0...*.H........|
+00000210 03 81 81 00 9d 30 cc 40 2b 5b 50 a0 61 cb ba e5 |.....0. at +[P.a...|
+00000220 53 58 e1 ed 83 28 a9 58 1a a9 38 a4 95 a1 ac 31 |SX...(.X..8....1|
+00000230 5a 1a 84 66 3d 43 d3 2d d9 0b f2 97 df d3 20 64 |Z..f=C.-...... d|
+00000240 38 92 24 3a 00 bc cf 9c 7d b7 40 20 01 5f aa d3 |8.$:....}.@ ._..|
+00000250 16 61 09 a2 76 fd 13 c3 cc e1 0c 5c ee b1 87 82 |.a..v......\....|
+00000260 f1 6c 04 ed 73 bb b3 43 77 8d 0c 1c f1 0f a1 d8 |.l..s..Cw.......|
+00000270 40 83 61 c9 4c 72 2b 9d ae db 46 06 06 4d f4 c1 |@.a.Lr+...F..M..|
+00000280 b3 3e c0 d1 bd 42 d4 db fe 3d 13 60 84 5c 21 d3 |.>...B...=.`.\!.|
+00000290 3b e9 fa e7 16 03 03 00 ac 0c 00 00 a8 03 00 1d |;...............|
+000002a0 20 2f e5 7d a3 47 cd 62 43 15 28 da ac 5f bb 29 | /.}.G.bC.(.._.)|
+000002b0 07 30 ff f6 84 af c4 cf c2 ed 90 99 5f 58 cb 3b |.0.........._X.;|
+000002c0 74 05 01 00 80 06 d4 bd e4 7b 10 77 89 d7 d4 d6 |t........{.w....|
+000002d0 4e f6 3e 46 49 db ee 5c 4e bc ee fe cb 8b a6 9b |N.>FI..\N.......|
+000002e0 5c f6 99 fb 31 96 60 a8 23 09 f6 31 65 53 f0 6e |\...1.`.#..1eS.n|
+000002f0 07 5c 32 f9 59 5d 8b c0 b4 74 c8 01 85 8a b7 19 |.\2.Y]...t......|
+00000300 ab 19 08 68 6a e8 2f 81 bd 04 9b 38 ab d9 27 66 |...hj./....8..'f|
+00000310 d7 a5 3f 75 9c 4f 81 5b 9e 69 10 20 2b f2 1d a2 |..?u.O.[.i. +...|
+00000320 8f fc 7f ba ee 5b 76 8b 19 3f 46 60 01 25 99 72 |.....[v..?F`.%.r|
+00000330 78 24 02 8e 28 d5 24 f1 2e 6b 70 53 75 ec e2 8d |x$..(.$..kpSu...|
+00000340 76 ab e0 8e e8 16 03 03 00 04 0e 00 00 00 |v.............|
>>> Flow 3 (client to server)
-00000000 16 03 03 00 46 10 00 00 42 41 04 36 1c 6c f5 0a |....F...BA.6.l..|
-00000010 7f 52 84 ac 5a 27 45 76 79 a6 89 f1 1d d9 30 30 |.R..Z'Evy.....00|
-00000020 b6 64 af c7 34 11 12 b3 b9 72 83 e6 78 bc 06 74 |.d..4....r..x..t|
-00000030 a7 a4 10 01 34 77 5c 05 88 82 0f a9 cf 8d e8 68 |....4w\........h|
-00000040 09 80 c7 79 b6 e9 5a 2a 5f 80 5e 14 03 03 00 01 |...y..Z*_.^.....|
-00000050 01 16 03 03 00 40 ef f9 3c 34 cd 26 70 c9 7b 60 |..... at ..<4.&p.{`|
-00000060 a7 27 0a 2b 86 18 2f 10 ad 48 3f 2e 9e 88 13 d6 |.'.+../..H?.....|
-00000070 d8 c6 fd 35 99 be 09 e6 dd ae 02 06 ea df 60 62 |...5..........`b|
-00000080 e0 f8 67 ea 9d c8 8c 11 d8 5a e7 6a a6 b2 eb 62 |..g......Z.j...b|
-00000090 23 b2 d2 be 75 58 |#...uX|
+00000000 16 03 03 00 25 10 00 00 21 20 21 75 22 84 bc b7 |....%...! !u"...|
+00000010 82 b3 03 d2 42 ff b6 ce 76 26 88 bf 8f 72 fc dd |....B...v&...r..|
+00000020 63 9b f1 4c 22 6d 12 cc d3 57 14 03 03 00 01 01 |c..L"m...W......|
+00000030 16 03 03 00 40 20 2b 26 bd 60 1b 27 a1 32 cb ab |....@ +&.`.'.2..|
+00000040 30 83 9c 47 59 7d f5 bb d9 45 8a d9 3e 29 86 4d |0..GY}...E..>).M|
+00000050 54 86 48 38 25 d9 b9 af 36 7c 7a f0 ae f6 b6 4e |T.H8%...6|z....N|
+00000060 a1 76 93 91 26 f3 c9 49 b5 6d 49 cf 22 97 bf c7 |.v..&..I.mI."...|
+00000070 db 44 c8 7a e3 |.D.z.|
>>> Flow 4 (server to client)
00000000 14 03 03 00 01 01 16 03 03 00 40 00 00 00 00 00 |.......... at .....|
-00000010 00 00 00 00 00 00 00 00 00 00 00 a6 52 02 4f 20 |............R.O |
-00000020 f6 d7 2d 2d 7c 65 4e 7b 43 33 32 50 9b c6 68 2c |..--|eN{C32P..h,|
-00000030 c0 6a 02 6f c6 bc 38 d8 06 c0 42 ba c1 41 ce 5c |.j.o..8...B..A.\|
-00000040 d0 a0 5f fc 8a 31 33 26 a2 79 9a 17 03 03 00 40 |.._..13&.y.....@|
+00000010 00 00 00 00 00 00 00 00 00 00 00 43 7c 61 f2 30 |...........C|a.0|
+00000020 c6 4a c2 76 da 7d 84 c6 ed 5d ee 2e 9c 33 e4 3b |.J.v.}...]...3.;|
+00000030 e3 a1 ea ee 44 02 4b f7 90 f6 0c 8b 45 d7 26 2e |....D.K.....E.&.|
+00000040 4a 37 43 1d 93 44 79 e6 5d c5 8c 17 03 03 00 40 |J7C..Dy.]......@|
00000050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
-00000060 f2 42 8f e8 79 0d f3 c0 a0 b7 8a 5e de b8 52 c4 |.B..y......^..R.|
-00000070 b6 9d b2 10 00 e8 a3 19 27 12 ac 38 e7 d8 ec 89 |........'..8....|
-00000080 af 7d 68 15 03 e8 c4 c8 08 34 ad ad 15 7b 69 bb |.}h......4...{i.|
+00000060 b2 e4 62 17 e2 d4 d8 73 2b ea 77 39 78 51 1a 86 |..b....s+.w9xQ..|
+00000070 64 54 1f 36 9a cc a1 c0 d2 6d df b7 8a 2e 68 b0 |dT.6.....m....h.|
+00000080 79 9a 9f a1 15 b1 78 fa db 2e 5a 43 0d fe 45 71 |y.....x...ZC..Eq|
00000090 15 03 03 00 30 00 00 00 00 00 00 00 00 00 00 00 |....0...........|
-000000a0 00 00 00 00 00 a0 a5 02 ff b1 77 9a 8f e0 fc ca |..........w.....|
-000000b0 86 ee ca 9c 7c 3b ca 61 33 7f f9 12 54 79 41 97 |....|;.a3...TyA.|
-000000c0 b0 7d bd 9b 93 |.}...|
+000000a0 00 00 00 00 00 04 8c d0 bf 15 9f b4 55 22 b8 8e |............U"..|
+000000b0 a5 a7 df ed bd b2 ab 88 71 38 bd b2 5d b4 5e 8e |........q8..].^.|
+000000c0 54 fc e4 63 5a |T..cZ|
diff --git a/src/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedAndECDSAGiven b/src/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedAndECDSAGiven
index 626024c..7a950db 100644
--- a/src/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedAndECDSAGiven
+++ b/src/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedAndECDSAGiven
@@ -1,57 +1,56 @@
>>> Flow 1 (client to server)
-00000000 16 03 01 00 5b 01 00 00 57 03 03 55 46 9e 3b 51 |....[...W..UF.;Q|
-00000010 e7 cd bf df bc fe 0d 5a 5a de a6 09 6c 72 cb ea |.......ZZ...lr..|
-00000020 ab f8 a6 fd 9a 5b be 77 7d 25 20 00 00 04 00 05 |.....[.w}% .....|
-00000030 00 ff 02 01 00 00 29 00 0d 00 20 00 1e 06 01 06 |......)... .....|
-00000040 02 06 03 05 01 05 02 05 03 04 01 04 02 04 03 03 |................|
-00000050 01 03 02 03 03 02 01 02 02 02 03 00 0f 00 01 01 |................|
+00000000 16 03 01 00 5d 01 00 00 59 03 03 8e 50 ff 02 c4 |....]...Y...P...|
+00000010 3b 5e dd ee 59 d1 3a e1 db f1 30 f4 bb a7 8a 8c |;^..Y.:...0.....|
+00000020 b2 d2 1a fd f8 a4 c9 e4 5f 41 e1 00 00 04 00 2f |........_A...../|
+00000030 00 ff 01 00 00 2c 00 0d 00 20 00 1e 06 01 06 02 |.....,... ......|
+00000040 06 03 05 01 05 02 05 03 04 01 04 02 04 03 03 01 |................|
+00000050 03 02 03 03 02 01 02 02 02 03 00 16 00 00 00 17 |................|
+00000060 00 00 |..|
>>> Flow 2 (server to client)
00000000 16 03 03 00 31 02 00 00 2d 03 03 00 00 00 00 00 |....1...-.......|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
-00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 05 00 00 |................|
-00000030 05 ff 01 00 01 00 16 03 03 02 71 0b 00 02 6d 00 |..........q...m.|
-00000040 02 6a 00 02 67 30 82 02 63 30 82 01 cc a0 03 02 |.j..g0..c0......|
-00000050 01 02 02 09 00 a2 73 00 0c 81 00 cb f3 30 0d 06 |......s......0..|
-00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 2b 31 17 |.*.H........0+1.|
-00000070 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 |0...U....Google |
-00000080 54 45 53 54 49 4e 47 31 10 30 0e 06 03 55 04 03 |TESTING1.0...U..|
-00000090 13 07 47 6f 20 52 6f 6f 74 30 1e 17 0d 31 35 30 |..Go Root0...150|
-000000a0 31 30 31 30 30 30 30 30 30 5a 17 0d 32 35 30 31 |101000000Z..2501|
-000000b0 30 31 30 30 30 30 30 30 5a 30 26 31 17 30 15 06 |01000000Z0&1.0..|
-000000c0 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 54 45 53 |.U....Google TES|
-000000d0 54 49 4e 47 31 0b 30 09 06 03 55 04 03 13 02 47 |TING1.0...U....G|
-000000e0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....|
-000000f0 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 af 87 |.......0........|
-00000100 88 f6 20 1b 95 65 6c 14 ab 44 05 af 3b 45 14 e3 |.. ..el..D..;E..|
-00000110 b7 6d fd 00 63 4d 95 7f fe 6a 62 35 86 c0 4a f9 |.m..cM...jb5..J.|
-00000120 18 7c f6 aa 25 5e 7a 64 31 66 00 ba f4 8e 92 af |.|..%^zd1f......|
-00000130 c7 6b d8 76 d4 f3 5f 41 cb 6e 56 15 97 1b 97 c1 |.k.v.._A.nV.....|
-00000140 3c 12 39 21 66 3d 2b 16 d1 bc db 1c c0 a7 da b7 |<.9!f=+.........|
-00000150 ca ad ba da cb d5 21 50 ec de 8d ab d1 6b 81 4b |......!P.....k.K|
-00000160 89 02 f3 c4 be c1 6c 89 b1 44 84 bd 21 d1 04 7d |......l..D..!..}|
-00000170 9d 16 4d f9 82 15 f6 ef fa d6 09 47 f2 fb 02 03 |..M........G....|
-00000180 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..|
-00000190 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%|
-000001a0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........|
-000001b0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...|
-000001c0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....|
-000001d0 10 12 50 8d 89 6f 1b d1 dc 54 4d 6e cb 69 5e 06 |..P..o...TMn.i^.|
-000001e0 f4 30 1b 06 03 55 1d 23 04 14 30 12 80 10 bf 3d |.0...U.#..0....=|
-000001f0 b6 a9 66 f2 b8 40 cf ea b4 03 78 48 1a 41 30 19 |..f.. at ....xH.A0.|
-00000200 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp|
-00000210 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H|
-00000220 86 f7 0d 01 01 0b 05 00 03 81 81 00 92 7c af 91 |.............|..|
-00000230 55 12 18 96 59 31 a6 48 40 d5 2d d5 ee bb 02 a0 |U...Y1.H at .-.....|
-00000240 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 da 4f 3d c0 fa |...|..0}<.v.O=..|
-00000250 ae 2d 33 24 6b 03 7b 1b 67 59 11 21 b5 11 bc 77 |.-3$k.{.gY.!...w|
-00000260 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f 22 3e 63 10 6b |...n.-.5.d_">c.k|
-00000270 be ff 14 86 6d 0d f0 15 31 a8 14 38 1e 3b 84 87 |....m...1..8.;..|
-00000280 2c cb 98 ed 51 76 b9 b1 4f dd db 9b 84 04 86 40 |,...Qv..O......@|
-00000290 fa 51 dd ba b4 8d eb e3 46 de 46 b9 4f 86 c7 f9 |.Q......F.F.O...|
-000002a0 a4 c2 41 34 ac cc f6 ea b0 ab 39 18 16 03 03 00 |..A4......9.....|
-000002b0 17 0d 00 00 13 02 01 40 00 0c 04 01 04 03 05 01 |....... at ........|
-000002c0 05 03 02 01 02 03 00 00 16 03 03 00 04 0e 00 00 |................|
-000002d0 00 |.|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2f 00 00 |............./..|
+00000030 05 ff 01 00 01 00 16 03 03 02 59 0b 00 02 55 00 |..........Y...U.|
+00000040 02 52 00 02 4f 30 82 02 4b 30 82 01 b4 a0 03 02 |.R..O0..K0......|
+00000050 01 02 02 09 00 e8 f0 9d 3f e2 5b ea a6 30 0d 06 |........?.[..0..|
+00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 1f 31 0b |.*.H........0.1.|
+00000070 30 09 06 03 55 04 0a 13 02 47 6f 31 10 30 0e 06 |0...U....Go1.0..|
+00000080 03 55 04 03 13 07 47 6f 20 52 6f 6f 74 30 1e 17 |.U....Go Root0..|
+00000090 0d 31 36 30 31 30 31 30 30 30 30 30 30 5a 17 0d |.160101000000Z..|
+000000a0 32 35 30 31 30 31 30 30 30 30 30 30 5a 30 1a 31 |250101000000Z0.1|
+000000b0 0b 30 09 06 03 55 04 0a 13 02 47 6f 31 0b 30 09 |.0...U....Go1.0.|
+000000c0 06 03 55 04 03 13 02 47 6f 30 81 9f 30 0d 06 09 |..U....Go0..0...|
+000000d0 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 30 |*.H............0|
+000000e0 81 89 02 81 81 00 db 46 7d 93 2e 12 27 06 48 bc |.......F}...'.H.|
+000000f0 06 28 21 ab 7e c4 b6 a2 5d fe 1e 52 45 88 7a 36 |.(!.~...]..RE.z6|
+00000100 47 a5 08 0d 92 42 5b c2 81 c0 be 97 79 98 40 fb |G....B[.....y. at .|
+00000110 4f 6d 14 fd 2b 13 8b c2 a5 2e 67 d8 d4 09 9e d6 |Om..+.....g.....|
+00000120 22 38 b7 4a 0b 74 73 2b c2 34 f1 d1 93 e5 96 d9 |"8.J.ts+.4......|
+00000130 74 7b f3 58 9f 6c 61 3c c0 b0 41 d4 d9 2b 2b 24 |t{.X.la<..A..++$|
+00000140 23 77 5b 1c 3b bd 75 5d ce 20 54 cf a1 63 87 1d |#w[.;.u]. T..c..|
+00000150 1e 24 c4 f3 1d 1a 50 8b aa b6 14 43 ed 97 a7 75 |.$....P....C...u|
+00000160 62 f4 14 c8 52 d7 02 03 01 00 01 a3 81 93 30 81 |b...R.........0.|
+00000170 90 30 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 05 |.0...U..........|
+00000180 a0 30 1d 06 03 55 1d 25 04 16 30 14 06 08 2b 06 |.0...U.%..0...+.|
+00000190 01 05 05 07 03 01 06 08 2b 06 01 05 05 07 03 02 |........+.......|
+000001a0 30 0c 06 03 55 1d 13 01 01 ff 04 02 30 00 30 19 |0...U.......0.0.|
+000001b0 06 03 55 1d 0e 04 12 04 10 9f 91 16 1f 43 43 3e |..U..........CC>|
+000001c0 49 a6 de 6d b6 80 d7 9f 60 30 1b 06 03 55 1d 23 |I..m....`0...U.#|
+000001d0 04 14 30 12 80 10 48 13 49 4d 13 7e 16 31 bb a3 |..0...H.IM.~.1..|
+000001e0 01 d5 ac ab 6e 7b 30 19 06 03 55 1d 11 04 12 30 |....n{0...U....0|
+000001f0 10 82 0e 65 78 61 6d 70 6c 65 2e 67 6f 6c 61 6e |...example.golan|
+00000200 67 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 |g0...*.H........|
+00000210 03 81 81 00 9d 30 cc 40 2b 5b 50 a0 61 cb ba e5 |.....0. at +[P.a...|
+00000220 53 58 e1 ed 83 28 a9 58 1a a9 38 a4 95 a1 ac 31 |SX...(.X..8....1|
+00000230 5a 1a 84 66 3d 43 d3 2d d9 0b f2 97 df d3 20 64 |Z..f=C.-...... d|
+00000240 38 92 24 3a 00 bc cf 9c 7d b7 40 20 01 5f aa d3 |8.$:....}.@ ._..|
+00000250 16 61 09 a2 76 fd 13 c3 cc e1 0c 5c ee b1 87 82 |.a..v......\....|
+00000260 f1 6c 04 ed 73 bb b3 43 77 8d 0c 1c f1 0f a1 d8 |.l..s..Cw.......|
+00000270 40 83 61 c9 4c 72 2b 9d ae db 46 06 06 4d f4 c1 |@.a.Lr+...F..M..|
+00000280 b3 3e c0 d1 bd 42 d4 db fe 3d 13 60 84 5c 21 d3 |.>...B...=.`.\!.|
+00000290 3b e9 fa e7 16 03 03 00 17 0d 00 00 13 02 01 40 |;..............@|
+000002a0 00 0c 04 01 04 03 05 01 05 03 02 01 02 03 00 00 |................|
+000002b0 16 03 03 00 04 0e 00 00 00 |.........|
>>> Flow 3 (client to server)
00000000 16 03 03 02 0a 0b 00 02 06 00 02 03 00 02 00 30 |...............0|
00000010 82 01 fc 30 82 01 5e 02 09 00 9a 30 84 6c 26 35 |...0..^....0.l&5|
@@ -86,32 +85,40 @@
000001e0 be e8 91 b3 da 1a f5 5d a3 23 f5 26 8b 45 70 8d |.......].#.&.Ep.|
000001f0 65 62 9b 7e 01 99 3d 18 f6 10 9a 38 61 9b 2e 57 |eb.~..=....8a..W|
00000200 e4 fa cc b1 8a ce e2 23 a0 87 f0 e1 67 51 eb 16 |.......#....gQ..|
-00000210 03 03 00 86 10 00 00 82 00 80 03 64 6f 74 1b 0e |...........dot..|
-00000220 df 6b a4 8e f8 ec b5 02 c2 d6 7a 9a f3 bf 3e 32 |.k........z...>2|
-00000230 ba 41 dd 61 33 8a 63 fb 71 e6 87 68 32 9c 41 d5 |.A.a3.c.q..h2.A.|
-00000240 59 ee 93 55 16 e9 0a 01 72 14 93 23 82 73 91 3a |Y..U....r..#.s.:|
-00000250 6d 3c e6 e0 a8 33 34 84 80 59 65 6b c1 6d 01 19 |m<...34..Yek.m..|
-00000260 cc d5 4f 1d f6 88 4f cc b5 c6 3c 9c 68 4a be 47 |..O...O...<.hJ.G|
-00000270 c2 67 61 a4 e3 c3 00 c0 9c d4 83 ed b5 65 25 a4 |.ga..........e%.|
-00000280 2e 1c 8d 47 3f 80 b8 1d 5b 74 a2 bf fa b9 b7 e2 |...G?...[t......|
-00000290 58 94 ba ec a9 cf 1c 56 ef 0a 16 03 03 00 92 0f |X......V........|
-000002a0 00 00 8e 04 03 00 8a 30 81 87 02 41 75 cf 19 3a |.......0...Au..:|
-000002b0 a1 9e e9 69 c7 f3 63 0b 46 c2 60 35 e1 cc 95 0d |...i..c.F.`5....|
-000002c0 ee 0f ad 28 17 b4 b2 09 ea 38 18 c7 08 84 b6 ac |...(.....8......|
-000002d0 65 03 b9 49 c3 ea ff e4 45 d3 15 14 3a 94 14 0c |e..I....E...:...|
-000002e0 cb 48 ce 75 c2 a4 4a 0e 7d d8 f0 c5 5f 02 42 01 |.H.u..J.}..._.B.|
-000002f0 99 dd c7 54 ce ee 38 bb 18 16 eb 92 0a 53 0b 92 |...T..8......S..|
-00000300 d8 73 73 48 b3 0a 3b ea 12 ea 62 d3 88 99 00 54 |.ssH..;...b....T|
-00000310 bc 92 28 7d 66 b3 17 7f e7 5f 69 50 d1 a1 4c 6a |..(}f...._iP..Lj|
-00000320 99 60 00 59 0a 4d 6c 97 05 54 ee 82 5a e1 c5 88 |.`.Y.Ml..T..Z...|
-00000330 1b 14 03 03 00 01 01 16 03 03 00 24 80 64 11 aa |...........$.d..|
-00000340 cc 9d 1c 83 b6 2f 56 dc 48 cb 33 e5 0f 25 a2 42 |...../V.H.3..%.B|
-00000350 df b8 a6 cc 64 93 10 63 ad 76 91 27 3f c7 8f d4 |....d..c.v.'?...|
+00000210 03 03 00 86 10 00 00 82 00 80 2b 80 6e 49 b8 ec |..........+.nI..|
+00000220 12 7a 7c f3 2a d3 7e 16 a0 39 e5 77 61 7a 56 15 |.z|.*.~..9.wazV.|
+00000230 97 c6 64 63 13 cf 09 d0 1b f5 b6 78 1d cb 86 4f |..dc.......x...O|
+00000240 14 84 c9 e6 5d 3c 6b 61 5e 46 83 7e ef 1d 74 d4 |....]<ka^F.~..t.|
+00000250 3b 8c 78 be 26 92 24 04 b4 6f 21 88 03 8d 92 a8 |;.x.&.$..o!.....|
+00000260 60 c6 08 b5 75 5d 2f 2c 71 60 5f 54 27 a0 fa 83 |`...u]/,q`_T'...|
+00000270 4d 39 1e 22 1e 1e 60 92 51 ac 2d 35 c7 cf fc 5e |M9."..`.Q.-5...^|
+00000280 db e3 60 37 6b 4e 7c d8 04 f3 09 54 de 38 af 57 |..`7kN|....T.8.W|
+00000290 20 d0 f5 08 5a a8 6f 65 03 55 16 03 03 00 93 0f | ...Z.oe.U......|
+000002a0 00 00 8f 04 03 00 8b 30 81 88 02 42 00 97 84 ac |.......0...B....|
+000002b0 cf 9b df b0 3a c8 9d a6 da 8c 11 87 35 2a d7 d0 |....:.......5*..|
+000002c0 15 df e1 02 ca 85 3f 1c a5 21 17 8c 8a 73 1b 76 |......?..!...s.v|
+000002d0 8d 0f af 26 ea b5 7f 87 a6 b6 c8 61 32 27 fc f4 |...&.......a2'..|
+000002e0 b7 c5 c3 2c 53 61 59 5a 5d 12 c6 dd 9e 54 02 42 |...,SaYZ]....T.B|
+000002f0 01 04 3f 82 bb a4 5c ea ea c9 9c 2a 75 96 c2 88 |..?...\....*u...|
+00000300 5a ae f8 2e 29 01 cf 7b a4 20 83 df ec c8 9d 37 |Z...)..{. .....7|
+00000310 0c 33 fb 20 73 51 47 6d 81 d0 75 b1 19 ed 02 00 |.3. sQGm..u.....|
+00000320 b8 40 67 75 b9 72 63 9c 1e e1 c9 44 93 d6 ec e7 |. at gu.rc....D....|
+00000330 16 5c 14 03 03 00 01 01 16 03 03 00 40 43 51 cf |.\.......... at CQ.|
+00000340 07 b2 de 6e 40 10 eb dd 3f 84 6a 54 a3 7f b2 48 |...n at ...?.jT...H|
+00000350 b3 aa 3c d4 e7 69 32 7c 77 ba e9 0b 99 b3 c9 e8 |..<..i2|w.......|
+00000360 c5 53 29 9a 6b 82 ee 7d 5e a9 ae 63 fa a9 af 21 |.S).k..}^..c...!|
+00000370 f2 04 b1 a1 bf f1 10 4c 65 6c 49 34 a0 |.......LelI4.|
>>> Flow 4 (server to client)
-00000000 14 03 03 00 01 01 16 03 03 00 24 24 8d e5 5f d9 |..........$$.._.|
-00000010 99 7d d4 f2 5f f4 4b e3 b4 8e 33 84 7a c3 cb bf |.}.._.K...3.z...|
-00000020 21 00 94 db 7b 7f 6c fa a0 f2 9f 0e e9 3b 27 17 |!...{.l......;'.|
-00000030 03 03 00 21 67 f8 3a ff c1 3b cb de 04 bf 49 a6 |...!g.:..;....I.|
-00000040 9a 45 56 ab 64 99 06 7e 40 cc a7 f6 4e 1e ca cb |.EV.d..~@...N...|
-00000050 11 87 da 58 b7 15 03 03 00 16 10 1b 62 97 25 bf |...X........b.%.|
-00000060 84 c1 23 d6 76 4a a1 da 07 c7 25 68 f6 6e 63 55 |..#.vJ....%h.ncU|
+00000000 14 03 03 00 01 01 16 03 03 00 40 00 00 00 00 00 |.......... at .....|
+00000010 00 00 00 00 00 00 00 00 00 00 00 93 a2 18 a9 e2 |................|
+00000020 51 be f7 bd c0 05 64 51 0a 17 9d 58 11 d1 a6 b9 |Q.....dQ...X....|
+00000030 6d 1e 42 16 e4 bc bf 09 f2 b9 29 20 74 8a cd 8a |m.B.......) t...|
+00000040 b6 31 04 64 fb 5b 1f 83 c3 19 78 17 03 03 00 40 |.1.d.[....x....@|
+00000050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000060 ee c4 d0 5d 69 37 2b fc dc 9c f1 77 df 44 6f da |...]i7+....w.Do.|
+00000070 4e 22 05 05 3a 6c 32 a8 6c c2 fb ce ca a7 1b 54 |N"..:l2.l......T|
+00000080 2a 25 ae cf 77 e4 47 21 33 b6 29 54 62 00 dd 30 |*%..w.G!3.)Tb..0|
+00000090 15 03 03 00 30 00 00 00 00 00 00 00 00 00 00 00 |....0...........|
+000000a0 00 00 00 00 00 cf e1 fd e3 5f d3 19 cd 05 70 79 |........._....py|
+000000b0 be 16 a5 26 18 f1 92 bc 73 bd 6f 4d 33 3d 6f 8a |...&....s.oM3=o.|
+000000c0 13 51 7c 57 c7 |.Q|W.|
diff --git a/src/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedAndGiven b/src/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedAndGiven
index 819825c..c81acc8 100644
--- a/src/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedAndGiven
+++ b/src/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedAndGiven
@@ -1,116 +1,123 @@
>>> Flow 1 (client to server)
-00000000 16 03 01 00 5b 01 00 00 57 03 03 87 41 6f c5 67 |....[...W...Ao.g|
-00000010 07 3b 12 46 ad aa d2 be 0d 08 98 e3 c7 4b ac 48 |.;.F.........K.H|
-00000020 67 02 6b 3b dc 84 79 c5 57 e9 89 00 00 04 00 05 |g.k;..y.W.......|
-00000030 00 ff 02 01 00 00 29 00 0d 00 20 00 1e 06 01 06 |......)... .....|
-00000040 02 06 03 05 01 05 02 05 03 04 01 04 02 04 03 03 |................|
-00000050 01 03 02 03 03 02 01 02 02 02 03 00 0f 00 01 01 |................|
+00000000 16 03 01 00 5d 01 00 00 59 03 03 f3 3a db 98 ff |....]...Y...:...|
+00000010 29 a2 30 75 53 87 b3 5f 00 b5 9f 77 4d 88 38 ea |).0uS.._...wM.8.|
+00000020 e9 87 f4 a4 e4 da dd 73 00 47 d1 00 00 04 00 2f |.......s.G...../|
+00000030 00 ff 01 00 00 2c 00 0d 00 20 00 1e 06 01 06 02 |.....,... ......|
+00000040 06 03 05 01 05 02 05 03 04 01 04 02 04 03 03 01 |................|
+00000050 03 02 03 03 02 01 02 02 02 03 00 16 00 00 00 17 |................|
+00000060 00 00 |..|
>>> Flow 2 (server to client)
00000000 16 03 03 00 31 02 00 00 2d 03 03 00 00 00 00 00 |....1...-.......|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
-00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 05 00 00 |................|
-00000030 05 ff 01 00 01 00 16 03 03 02 71 0b 00 02 6d 00 |..........q...m.|
-00000040 02 6a 00 02 67 30 82 02 63 30 82 01 cc a0 03 02 |.j..g0..c0......|
-00000050 01 02 02 09 00 a2 73 00 0c 81 00 cb f3 30 0d 06 |......s......0..|
-00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 2b 31 17 |.*.H........0+1.|
-00000070 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 |0...U....Google |
-00000080 54 45 53 54 49 4e 47 31 10 30 0e 06 03 55 04 03 |TESTING1.0...U..|
-00000090 13 07 47 6f 20 52 6f 6f 74 30 1e 17 0d 31 35 30 |..Go Root0...150|
-000000a0 31 30 31 30 30 30 30 30 30 5a 17 0d 32 35 30 31 |101000000Z..2501|
-000000b0 30 31 30 30 30 30 30 30 5a 30 26 31 17 30 15 06 |01000000Z0&1.0..|
-000000c0 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 54 45 53 |.U....Google TES|
-000000d0 54 49 4e 47 31 0b 30 09 06 03 55 04 03 13 02 47 |TING1.0...U....G|
-000000e0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....|
-000000f0 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 af 87 |.......0........|
-00000100 88 f6 20 1b 95 65 6c 14 ab 44 05 af 3b 45 14 e3 |.. ..el..D..;E..|
-00000110 b7 6d fd 00 63 4d 95 7f fe 6a 62 35 86 c0 4a f9 |.m..cM...jb5..J.|
-00000120 18 7c f6 aa 25 5e 7a 64 31 66 00 ba f4 8e 92 af |.|..%^zd1f......|
-00000130 c7 6b d8 76 d4 f3 5f 41 cb 6e 56 15 97 1b 97 c1 |.k.v.._A.nV.....|
-00000140 3c 12 39 21 66 3d 2b 16 d1 bc db 1c c0 a7 da b7 |<.9!f=+.........|
-00000150 ca ad ba da cb d5 21 50 ec de 8d ab d1 6b 81 4b |......!P.....k.K|
-00000160 89 02 f3 c4 be c1 6c 89 b1 44 84 bd 21 d1 04 7d |......l..D..!..}|
-00000170 9d 16 4d f9 82 15 f6 ef fa d6 09 47 f2 fb 02 03 |..M........G....|
-00000180 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..|
-00000190 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%|
-000001a0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........|
-000001b0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...|
-000001c0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....|
-000001d0 10 12 50 8d 89 6f 1b d1 dc 54 4d 6e cb 69 5e 06 |..P..o...TMn.i^.|
-000001e0 f4 30 1b 06 03 55 1d 23 04 14 30 12 80 10 bf 3d |.0...U.#..0....=|
-000001f0 b6 a9 66 f2 b8 40 cf ea b4 03 78 48 1a 41 30 19 |..f.. at ....xH.A0.|
-00000200 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp|
-00000210 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H|
-00000220 86 f7 0d 01 01 0b 05 00 03 81 81 00 92 7c af 91 |.............|..|
-00000230 55 12 18 96 59 31 a6 48 40 d5 2d d5 ee bb 02 a0 |U...Y1.H at .-.....|
-00000240 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 da 4f 3d c0 fa |...|..0}<.v.O=..|
-00000250 ae 2d 33 24 6b 03 7b 1b 67 59 11 21 b5 11 bc 77 |.-3$k.{.gY.!...w|
-00000260 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f 22 3e 63 10 6b |...n.-.5.d_">c.k|
-00000270 be ff 14 86 6d 0d f0 15 31 a8 14 38 1e 3b 84 87 |....m...1..8.;..|
-00000280 2c cb 98 ed 51 76 b9 b1 4f dd db 9b 84 04 86 40 |,...Qv..O......@|
-00000290 fa 51 dd ba b4 8d eb e3 46 de 46 b9 4f 86 c7 f9 |.Q......F.F.O...|
-000002a0 a4 c2 41 34 ac cc f6 ea b0 ab 39 18 16 03 03 00 |..A4......9.....|
-000002b0 17 0d 00 00 13 02 01 40 00 0c 04 01 04 03 05 01 |....... at ........|
-000002c0 05 03 02 01 02 03 00 00 16 03 03 00 04 0e 00 00 |................|
-000002d0 00 |.|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2f 00 00 |............./..|
+00000030 05 ff 01 00 01 00 16 03 03 02 59 0b 00 02 55 00 |..........Y...U.|
+00000040 02 52 00 02 4f 30 82 02 4b 30 82 01 b4 a0 03 02 |.R..O0..K0......|
+00000050 01 02 02 09 00 e8 f0 9d 3f e2 5b ea a6 30 0d 06 |........?.[..0..|
+00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 1f 31 0b |.*.H........0.1.|
+00000070 30 09 06 03 55 04 0a 13 02 47 6f 31 10 30 0e 06 |0...U....Go1.0..|
+00000080 03 55 04 03 13 07 47 6f 20 52 6f 6f 74 30 1e 17 |.U....Go Root0..|
+00000090 0d 31 36 30 31 30 31 30 30 30 30 30 30 5a 17 0d |.160101000000Z..|
+000000a0 32 35 30 31 30 31 30 30 30 30 30 30 5a 30 1a 31 |250101000000Z0.1|
+000000b0 0b 30 09 06 03 55 04 0a 13 02 47 6f 31 0b 30 09 |.0...U....Go1.0.|
+000000c0 06 03 55 04 03 13 02 47 6f 30 81 9f 30 0d 06 09 |..U....Go0..0...|
+000000d0 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 30 |*.H............0|
+000000e0 81 89 02 81 81 00 db 46 7d 93 2e 12 27 06 48 bc |.......F}...'.H.|
+000000f0 06 28 21 ab 7e c4 b6 a2 5d fe 1e 52 45 88 7a 36 |.(!.~...]..RE.z6|
+00000100 47 a5 08 0d 92 42 5b c2 81 c0 be 97 79 98 40 fb |G....B[.....y. at .|
+00000110 4f 6d 14 fd 2b 13 8b c2 a5 2e 67 d8 d4 09 9e d6 |Om..+.....g.....|
+00000120 22 38 b7 4a 0b 74 73 2b c2 34 f1 d1 93 e5 96 d9 |"8.J.ts+.4......|
+00000130 74 7b f3 58 9f 6c 61 3c c0 b0 41 d4 d9 2b 2b 24 |t{.X.la<..A..++$|
+00000140 23 77 5b 1c 3b bd 75 5d ce 20 54 cf a1 63 87 1d |#w[.;.u]. T..c..|
+00000150 1e 24 c4 f3 1d 1a 50 8b aa b6 14 43 ed 97 a7 75 |.$....P....C...u|
+00000160 62 f4 14 c8 52 d7 02 03 01 00 01 a3 81 93 30 81 |b...R.........0.|
+00000170 90 30 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 05 |.0...U..........|
+00000180 a0 30 1d 06 03 55 1d 25 04 16 30 14 06 08 2b 06 |.0...U.%..0...+.|
+00000190 01 05 05 07 03 01 06 08 2b 06 01 05 05 07 03 02 |........+.......|
+000001a0 30 0c 06 03 55 1d 13 01 01 ff 04 02 30 00 30 19 |0...U.......0.0.|
+000001b0 06 03 55 1d 0e 04 12 04 10 9f 91 16 1f 43 43 3e |..U..........CC>|
+000001c0 49 a6 de 6d b6 80 d7 9f 60 30 1b 06 03 55 1d 23 |I..m....`0...U.#|
+000001d0 04 14 30 12 80 10 48 13 49 4d 13 7e 16 31 bb a3 |..0...H.IM.~.1..|
+000001e0 01 d5 ac ab 6e 7b 30 19 06 03 55 1d 11 04 12 30 |....n{0...U....0|
+000001f0 10 82 0e 65 78 61 6d 70 6c 65 2e 67 6f 6c 61 6e |...example.golan|
+00000200 67 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 |g0...*.H........|
+00000210 03 81 81 00 9d 30 cc 40 2b 5b 50 a0 61 cb ba e5 |.....0. at +[P.a...|
+00000220 53 58 e1 ed 83 28 a9 58 1a a9 38 a4 95 a1 ac 31 |SX...(.X..8....1|
+00000230 5a 1a 84 66 3d 43 d3 2d d9 0b f2 97 df d3 20 64 |Z..f=C.-...... d|
+00000240 38 92 24 3a 00 bc cf 9c 7d b7 40 20 01 5f aa d3 |8.$:....}.@ ._..|
+00000250 16 61 09 a2 76 fd 13 c3 cc e1 0c 5c ee b1 87 82 |.a..v......\....|
+00000260 f1 6c 04 ed 73 bb b3 43 77 8d 0c 1c f1 0f a1 d8 |.l..s..Cw.......|
+00000270 40 83 61 c9 4c 72 2b 9d ae db 46 06 06 4d f4 c1 |@.a.Lr+...F..M..|
+00000280 b3 3e c0 d1 bd 42 d4 db fe 3d 13 60 84 5c 21 d3 |.>...B...=.`.\!.|
+00000290 3b e9 fa e7 16 03 03 00 17 0d 00 00 13 02 01 40 |;..............@|
+000002a0 00 0c 04 01 04 03 05 01 05 03 02 01 02 03 00 00 |................|
+000002b0 16 03 03 00 04 0e 00 00 00 |.........|
>>> Flow 3 (client to server)
-00000000 16 03 03 01 fb 0b 00 01 f7 00 01 f4 00 01 f1 30 |...............0|
-00000010 82 01 ed 30 82 01 58 a0 03 02 01 02 02 01 00 30 |...0..X........0|
-00000020 0b 06 09 2a 86 48 86 f7 0d 01 01 05 30 26 31 10 |...*.H......0&1.|
-00000030 30 0e 06 03 55 04 0a 13 07 41 63 6d 65 20 43 6f |0...U....Acme Co|
-00000040 31 12 30 10 06 03 55 04 03 13 09 31 32 37 2e 30 |1.0...U....127.0|
-00000050 2e 30 2e 31 30 1e 17 0d 31 31 31 32 30 38 30 37 |.0.10...11120807|
-00000060 35 35 31 32 5a 17 0d 31 32 31 32 30 37 30 38 30 |5512Z..121207080|
-00000070 30 31 32 5a 30 26 31 10 30 0e 06 03 55 04 0a 13 |012Z0&1.0...U...|
-00000080 07 41 63 6d 65 20 43 6f 31 12 30 10 06 03 55 04 |.Acme Co1.0...U.|
-00000090 03 13 09 31 32 37 2e 30 2e 30 2e 31 30 81 9c 30 |...127.0.0.10..0|
-000000a0 0b 06 09 2a 86 48 86 f7 0d 01 01 01 03 81 8c 00 |...*.H..........|
-000000b0 30 81 88 02 81 80 4e d0 7b 31 e3 82 64 d9 59 c0 |0.....N.{1..d.Y.|
-000000c0 c2 87 a4 5e 1e 8b 73 33 c7 63 53 df 66 92 06 84 |...^..s3.cS.f...|
-000000d0 f6 64 d5 8f e4 36 a7 1d 2b e8 b3 20 36 45 23 b5 |.d...6..+.. 6E#.|
-000000e0 e3 95 ae ed e0 f5 20 9c 8d 95 df 7f 5a 12 ef 87 |...... .....Z...|
-000000f0 e4 5b 68 e4 e9 0e 74 ec 04 8a 7f de 93 27 c4 01 |.[h...t......'..|
-00000100 19 7a bd f2 dc 3d 14 ab d0 54 ca 21 0c d0 4d 6e |.z...=...T.!..Mn|
-00000110 87 2e 5c c5 d2 bb 4d 4b 4f ce b6 2c f7 7e 88 ec |..\...MKO..,.~..|
-00000120 7c d7 02 91 74 a6 1e 0c 1a da e3 4a 5a 2e de 13 ||...t......JZ...|
-00000130 9c 4c 40 88 59 93 02 03 01 00 01 a3 32 30 30 30 |.L at .Y.......2000|
-00000140 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 00 a0 30 |...U...........0|
-00000150 0d 06 03 55 1d 0e 04 06 04 04 01 02 03 04 30 0f |...U..........0.|
-00000160 06 03 55 1d 23 04 08 30 06 80 04 01 02 03 04 30 |..U.#..0.......0|
-00000170 0b 06 09 2a 86 48 86 f7 0d 01 01 05 03 81 81 00 |...*.H..........|
-00000180 36 1f b3 7a 0c 75 c9 6e 37 46 61 2b d5 bd c0 a7 |6..z.u.n7Fa+....|
-00000190 4b cc 46 9a 81 58 7c 85 79 29 c8 c8 c6 67 dd 32 |K.F..X|.y)...g.2|
-000001a0 56 45 2b 75 b6 e9 24 a9 50 9a be 1f 5a fa 1a 15 |VE+u..$.P...Z...|
-000001b0 d9 cc 55 95 72 16 83 b9 c2 b6 8f fd 88 8c 38 84 |..U.r.........8.|
-000001c0 1d ab 5d 92 31 13 4f fd 83 3b c6 9d f1 11 62 b6 |..].1.O..;....b.|
-000001d0 8b ec ab 67 be c8 64 b0 11 50 46 58 17 6b 99 1c |...g..d..PFX.k..|
-000001e0 d3 1d fc 06 f1 0e e5 96 a8 0c f9 78 20 b7 44 18 |...........x .D.|
-000001f0 51 8d 10 7e 4f 94 67 df a3 4e 70 73 8e 90 91 85 |Q..~O.g..Nps....|
-00000200 16 03 03 00 86 10 00 00 82 00 80 79 a7 23 10 fc |...........y.#..|
-00000210 64 a7 ab 17 ce d6 8b ab ff c2 44 40 3b ba b4 c6 |d.........D@;...|
-00000220 86 b7 66 7d be 9b fa 66 f9 f6 bb e4 f7 02 16 ea |..f}...f........|
-00000230 0f 13 9c 8a 98 3a 34 e6 58 82 dc dc 27 3a 3d 5c |.....:4.X...':=\|
-00000240 99 09 db 48 54 a5 5a a2 16 7f ba 99 d9 0d ca fb |...HT.Z.........|
-00000250 4a 9e b7 f6 3a ab 26 ef f9 df a2 0c 4c 45 19 3b |J...:.&.....LE.;|
-00000260 b2 9f 21 cd ff fc cc c7 fb 91 fa 54 93 a9 42 a9 |..!........T..B.|
-00000270 4c 48 4a 8c 7b 9a d7 90 97 f6 21 89 03 f6 a5 86 |LHJ.{.....!.....|
-00000280 83 6f 21 19 2f 5b f8 ec a6 36 e9 16 03 03 00 88 |.o!./[...6......|
-00000290 0f 00 00 84 04 01 00 80 0f 9d 15 cc c0 0b 71 8a |..............q.|
-000002a0 b9 95 ca 9a 86 ff bf 93 8d da 64 ce 99 28 e2 6e |..........d..(.n|
-000002b0 6d 6f 34 c9 03 fa 87 96 b0 1d 4f b2 3c 9e 4d 2c |mo4.......O.<.M,|
-000002c0 df be 7d fb 53 fe 90 6f 45 f3 f0 d9 ab 70 d4 df |..}.S..oE....p..|
-000002d0 5a 95 a4 53 12 02 c1 45 15 c2 2b 69 7e 5f 6f cd |Z..S...E..+i~_o.|
-000002e0 b3 eb 5d ff 48 36 94 ad 28 29 fe 47 40 ab 9c eb |..].H6..().G at ...|
-000002f0 02 f9 ca 7d e0 48 9f 6e a4 9f 1e c2 d7 fd 16 18 |...}.H.n........|
-00000300 db ad d9 35 27 89 96 c8 c4 70 10 be a4 5d 6b b4 |...5'....p...]k.|
-00000310 d8 61 70 93 08 00 0f c9 14 03 03 00 01 01 16 03 |.ap.............|
-00000320 03 00 24 7b ee b7 23 12 63 f0 80 ca b3 6f d3 b8 |..${..#.c....o..|
-00000330 ca cc 4a 54 06 ea e5 3e 73 f2 de 1d d6 16 7e 61 |..JT...>s.....~a|
-00000340 32 76 eb f8 8a 66 74 |2v...ft|
+00000000 16 03 03 01 fd 0b 00 01 f9 00 01 f6 00 01 f3 30 |...............0|
+00000010 82 01 ef 30 82 01 58 a0 03 02 01 02 02 10 5c 19 |...0..X.......\.|
+00000020 c1 89 65 83 55 6f dc 0b c9 b9 93 9f e9 bc 30 0d |..e.Uo........0.|
+00000030 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 12 31 |..*.H........0.1|
+00000040 10 30 0e 06 03 55 04 0a 13 07 41 63 6d 65 20 43 |.0...U....Acme C|
+00000050 6f 30 1e 17 0d 31 36 30 38 31 37 32 31 35 32 33 |o0...16081721523|
+00000060 31 5a 17 0d 31 37 30 38 31 37 32 31 35 32 33 31 |1Z..170817215231|
+00000070 5a 30 12 31 10 30 0e 06 03 55 04 0a 13 07 41 63 |Z0.1.0...U....Ac|
+00000080 6d 65 20 43 6f 30 81 9f 30 0d 06 09 2a 86 48 86 |me Co0..0...*.H.|
+00000090 f7 0d 01 01 01 05 00 03 81 8d 00 30 81 89 02 81 |...........0....|
+000000a0 81 00 ba 6f aa 86 bd cf bf 9f f2 ef 5c 94 60 78 |...o........\.`x|
+000000b0 6f e8 13 f2 d1 96 6f cd d9 32 6e 22 37 ce 41 f9 |o.....o..2n"7.A.|
+000000c0 ca 5d 29 ac e1 27 da 61 a2 ee 81 cb 10 c7 df 34 |.])..'.a.......4|
+000000d0 58 95 86 e9 3d 19 e6 5c 27 73 60 c8 8d 78 02 f4 |X...=..\'s`..x..|
+000000e0 1d a4 98 09 a3 19 70 69 3c 25 62 66 2a ab 22 23 |......pi<%bf*."#|
+000000f0 c5 7b 85 38 4f 2e 09 73 32 a7 bd 3e 9b ad ca 84 |.{.8O..s2..>....|
+00000100 07 e6 0f 3a ff 77 c5 9d 41 85 00 8a b6 9b ee b0 |...:.w..A.......|
+00000110 a4 3f 2d 4c 4c e6 42 3e bb 51 c8 dd 48 54 f4 0c |.?-LL.B>.Q..HT..|
+00000120 8e 47 02 03 01 00 01 a3 46 30 44 30 0e 06 03 55 |.G......F0D0...U|
+00000130 1d 0f 01 01 ff 04 04 03 02 05 a0 30 13 06 03 55 |...........0...U|
+00000140 1d 25 04 0c 30 0a 06 08 2b 06 01 05 05 07 03 01 |.%..0...+.......|
+00000150 30 0c 06 03 55 1d 13 01 01 ff 04 02 30 00 30 0f |0...U.......0.0.|
+00000160 06 03 55 1d 11 04 08 30 06 87 04 7f 00 00 01 30 |..U....0.......0|
+00000170 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 03 81 |...*.H..........|
+00000180 81 00 46 ab 44 a2 fb 28 54 f8 5a 67 f8 62 94 f1 |..F.D..(T.Zg.b..|
+00000190 9a b2 18 9e f2 b1 de 1d 7e 6f 76 95 a9 ba e7 5d |........~ov....]|
+000001a0 a8 16 6c 9c f7 09 d3 37 e4 4b 2b 36 7c 01 ad 41 |..l....7.K+6|..A|
+000001b0 d2 32 d8 c3 d2 93 f9 10 6b 8e 95 b9 2c 17 8a a3 |.2......k...,...|
+000001c0 44 48 bc 59 13 83 16 04 88 a4 81 5c 25 0d 98 0c |DH.Y.......\%...|
+000001d0 ac 11 b1 28 56 be 1d cd 61 62 84 09 bf d6 80 c6 |...(V...ab......|
+000001e0 45 8d 82 2c b4 d8 83 9b db c9 22 b7 2a 12 11 7b |E..,......".*..{|
+000001f0 fa 02 3b c1 c9 ff ea c9 9d a8 49 d3 95 d7 d5 0e |..;.......I.....|
+00000200 e5 35 16 03 03 00 86 10 00 00 82 00 80 47 31 82 |.5...........G1.|
+00000210 ae c1 d2 74 3f a4 74 5a 57 16 ae e2 d0 46 72 53 |...t?.tZW....FrS|
+00000220 e1 5e 6a e8 e4 d5 8c 84 2b d9 82 c1 4a da 9e 1d |.^j.....+...J...|
+00000230 a0 da 60 08 0d 35 0c 55 6d 6a 68 04 09 ee 94 39 |..`..5.Umjh....9|
+00000240 c7 a3 49 7f 2c ee 6a cf 09 01 bd 08 d3 59 0a bd |..I.,.j......Y..|
+00000250 7f 6c d3 26 eb be 7b fd 9b 17 fd e2 6e 82 d1 c7 |.l.&..{.....n...|
+00000260 dd c3 64 8c 87 f0 41 f2 71 75 f1 0a 01 26 5b 97 |..d...A.qu...&[.|
+00000270 94 ba ac 50 df 19 32 39 80 ae 14 ea 4a d2 e5 9f |...P..29....J...|
+00000280 5d 07 9f 2d 89 ac 83 33 40 aa 8e cc 2c 16 03 03 |]..-...3 at ...,...|
+00000290 00 88 0f 00 00 84 04 01 00 80 7d 37 8b 6f be e9 |..........}7.o..|
+000002a0 e7 fa 4c 28 cf 16 0d 28 40 e9 f2 9a 11 22 fc 8a |..L(...(@...."..|
+000002b0 2c 52 f7 36 af 1a cf d7 8a f8 17 19 9f ed 9d 1d |,R.6............|
+000002c0 43 f9 e2 fb 0f dd ca d6 1d 4c 03 4e 25 8d 5c 4c |C........L.N%.\L|
+000002d0 95 98 02 db cf ea 44 2a ad 36 74 e3 08 07 e3 9a |......D*.6t.....|
+000002e0 50 6c dc 46 a1 f5 84 9b 65 7f 48 94 b5 de cc a9 |Pl.F....e.H.....|
+000002f0 cf ee 0e 31 f2 f8 6f 8f 19 4b 29 14 b4 32 1d 21 |...1..o..K)..2.!|
+00000300 02 d2 da 64 68 e8 a1 72 cc ee 64 48 d8 74 e5 64 |...dh..r..dH.t.d|
+00000310 90 b3 50 cc 3e 25 0e b1 88 53 14 03 03 00 01 01 |..P.>%...S......|
+00000320 16 03 03 00 40 6a 61 6b 3e ea 63 2c b8 26 95 e2 |.... at jak>.c,.&..|
+00000330 5f 83 e3 c3 cd c3 b7 a8 0b 76 81 8a 5b 46 ff 41 |_........v..[F.A|
+00000340 c2 02 eb 21 85 31 b9 ba 2e 30 e7 6e 8d 1c 49 15 |...!.1...0.n..I.|
+00000350 af a0 a7 67 62 b7 42 8c fa a8 04 8c 23 7a 3d 39 |...gb.B.....#z=9|
+00000360 74 18 70 2b 99 |t.p+.|
>>> Flow 4 (server to client)
-00000000 14 03 03 00 01 01 16 03 03 00 24 64 d5 a4 78 e9 |..........$d..x.|
-00000010 f1 1d d1 34 f7 b3 95 87 18 f6 cf 65 c6 f0 02 08 |...4.......e....|
-00000020 69 f5 6d aa f2 da fc 2c ac fc aa f8 25 aa 50 17 |i.m....,....%.P.|
-00000030 03 03 00 21 9f 94 f8 78 46 58 2c 21 0d 30 04 89 |...!...xFX,!.0..|
-00000040 bd 35 03 dc 04 b6 0f 6f 22 65 db 3d 8d 96 00 0c |.5.....o"e.=....|
-00000050 db bf e5 b3 59 15 03 03 00 16 a6 35 f2 07 5e 32 |....Y......5..^2|
-00000060 4e 09 e4 31 3a f6 4a 83 c2 03 db b9 bf b0 eb 6d |N..1:.J........m|
+00000000 14 03 03 00 01 01 16 03 03 00 40 00 00 00 00 00 |.......... at .....|
+00000010 00 00 00 00 00 00 00 00 00 00 00 a6 5b 7c b0 91 |............[|..|
+00000020 53 f6 d5 e4 34 71 4f 64 2a 03 9d 75 62 d9 8d a8 |S...4qOd*..ub...|
+00000030 39 7b e1 d8 31 80 26 db 14 f3 3a 52 66 7d 12 31 |9{..1.&...:Rf}.1|
+00000040 29 14 7f a1 39 b6 1c e0 c9 55 6e 17 03 03 00 40 |)...9....Un....@|
+00000050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000060 5e 00 64 9b 25 cd 74 94 b7 65 6e 83 8e 5b 68 e8 |^.d.%.t..en..[h.|
+00000070 59 4c f0 31 8b f2 0c 59 2a ff 11 8e 43 d4 73 fd |YL.1...Y*...C.s.|
+00000080 b3 2a 76 59 25 52 32 76 bd 2e 1d 4d 0a 53 d7 c2 |.*vY%R2v...M.S..|
+00000090 15 03 03 00 30 00 00 00 00 00 00 00 00 00 00 00 |....0...........|
+000000a0 00 00 00 00 00 23 96 6e 7d 41 bb 51 4f 40 52 07 |.....#.n}A.QO at R.|
+000000b0 90 cc 6c bd c0 bb 99 d4 8a 91 7b 8a f3 24 ef 71 |..l.......{..$.q|
+000000c0 20 d4 98 b0 14 | ....|
diff --git a/src/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedNotGiven b/src/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedNotGiven
index 903272b..091de90 100644
--- a/src/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedNotGiven
+++ b/src/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedNotGiven
@@ -1,76 +1,83 @@
>>> Flow 1 (client to server)
-00000000 16 03 01 00 5b 01 00 00 57 03 03 9a 56 e0 d9 b8 |....[...W...V...|
-00000010 ac d5 88 c7 2f d1 87 1b 44 c6 ff 7b 4f 6f f0 2a |..../...D..{Oo.*|
-00000020 56 a1 9e 46 86 4b 6f 91 29 29 3b 00 00 04 00 05 |V..F.Ko.));.....|
-00000030 00 ff 02 01 00 00 29 00 0d 00 20 00 1e 06 01 06 |......)... .....|
-00000040 02 06 03 05 01 05 02 05 03 04 01 04 02 04 03 03 |................|
-00000050 01 03 02 03 03 02 01 02 02 02 03 00 0f 00 01 01 |................|
+00000000 16 03 01 00 5d 01 00 00 59 03 03 41 24 db 27 37 |....]...Y..A$.'7|
+00000010 2e 1e a8 61 b7 7f 08 f1 83 84 fb d5 a2 96 e0 53 |...a...........S|
+00000020 1a 2b cd 8e 50 38 7b a5 64 d8 92 00 00 04 00 2f |.+..P8{.d....../|
+00000030 00 ff 01 00 00 2c 00 0d 00 20 00 1e 06 01 06 02 |.....,... ......|
+00000040 06 03 05 01 05 02 05 03 04 01 04 02 04 03 03 01 |................|
+00000050 03 02 03 03 02 01 02 02 02 03 00 16 00 00 00 17 |................|
+00000060 00 00 |..|
>>> Flow 2 (server to client)
00000000 16 03 03 00 31 02 00 00 2d 03 03 00 00 00 00 00 |....1...-.......|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
-00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 05 00 00 |................|
-00000030 05 ff 01 00 01 00 16 03 03 02 71 0b 00 02 6d 00 |..........q...m.|
-00000040 02 6a 00 02 67 30 82 02 63 30 82 01 cc a0 03 02 |.j..g0..c0......|
-00000050 01 02 02 09 00 a2 73 00 0c 81 00 cb f3 30 0d 06 |......s......0..|
-00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 2b 31 17 |.*.H........0+1.|
-00000070 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 |0...U....Google |
-00000080 54 45 53 54 49 4e 47 31 10 30 0e 06 03 55 04 03 |TESTING1.0...U..|
-00000090 13 07 47 6f 20 52 6f 6f 74 30 1e 17 0d 31 35 30 |..Go Root0...150|
-000000a0 31 30 31 30 30 30 30 30 30 5a 17 0d 32 35 30 31 |101000000Z..2501|
-000000b0 30 31 30 30 30 30 30 30 5a 30 26 31 17 30 15 06 |01000000Z0&1.0..|
-000000c0 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 54 45 53 |.U....Google TES|
-000000d0 54 49 4e 47 31 0b 30 09 06 03 55 04 03 13 02 47 |TING1.0...U....G|
-000000e0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....|
-000000f0 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 af 87 |.......0........|
-00000100 88 f6 20 1b 95 65 6c 14 ab 44 05 af 3b 45 14 e3 |.. ..el..D..;E..|
-00000110 b7 6d fd 00 63 4d 95 7f fe 6a 62 35 86 c0 4a f9 |.m..cM...jb5..J.|
-00000120 18 7c f6 aa 25 5e 7a 64 31 66 00 ba f4 8e 92 af |.|..%^zd1f......|
-00000130 c7 6b d8 76 d4 f3 5f 41 cb 6e 56 15 97 1b 97 c1 |.k.v.._A.nV.....|
-00000140 3c 12 39 21 66 3d 2b 16 d1 bc db 1c c0 a7 da b7 |<.9!f=+.........|
-00000150 ca ad ba da cb d5 21 50 ec de 8d ab d1 6b 81 4b |......!P.....k.K|
-00000160 89 02 f3 c4 be c1 6c 89 b1 44 84 bd 21 d1 04 7d |......l..D..!..}|
-00000170 9d 16 4d f9 82 15 f6 ef fa d6 09 47 f2 fb 02 03 |..M........G....|
-00000180 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..|
-00000190 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%|
-000001a0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........|
-000001b0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...|
-000001c0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....|
-000001d0 10 12 50 8d 89 6f 1b d1 dc 54 4d 6e cb 69 5e 06 |..P..o...TMn.i^.|
-000001e0 f4 30 1b 06 03 55 1d 23 04 14 30 12 80 10 bf 3d |.0...U.#..0....=|
-000001f0 b6 a9 66 f2 b8 40 cf ea b4 03 78 48 1a 41 30 19 |..f.. at ....xH.A0.|
-00000200 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp|
-00000210 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H|
-00000220 86 f7 0d 01 01 0b 05 00 03 81 81 00 92 7c af 91 |.............|..|
-00000230 55 12 18 96 59 31 a6 48 40 d5 2d d5 ee bb 02 a0 |U...Y1.H at .-.....|
-00000240 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 da 4f 3d c0 fa |...|..0}<.v.O=..|
-00000250 ae 2d 33 24 6b 03 7b 1b 67 59 11 21 b5 11 bc 77 |.-3$k.{.gY.!...w|
-00000260 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f 22 3e 63 10 6b |...n.-.5.d_">c.k|
-00000270 be ff 14 86 6d 0d f0 15 31 a8 14 38 1e 3b 84 87 |....m...1..8.;..|
-00000280 2c cb 98 ed 51 76 b9 b1 4f dd db 9b 84 04 86 40 |,...Qv..O......@|
-00000290 fa 51 dd ba b4 8d eb e3 46 de 46 b9 4f 86 c7 f9 |.Q......F.F.O...|
-000002a0 a4 c2 41 34 ac cc f6 ea b0 ab 39 18 16 03 03 00 |..A4......9.....|
-000002b0 17 0d 00 00 13 02 01 40 00 0c 04 01 04 03 05 01 |....... at ........|
-000002c0 05 03 02 01 02 03 00 00 16 03 03 00 04 0e 00 00 |................|
-000002d0 00 |.|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2f 00 00 |............./..|
+00000030 05 ff 01 00 01 00 16 03 03 02 59 0b 00 02 55 00 |..........Y...U.|
+00000040 02 52 00 02 4f 30 82 02 4b 30 82 01 b4 a0 03 02 |.R..O0..K0......|
+00000050 01 02 02 09 00 e8 f0 9d 3f e2 5b ea a6 30 0d 06 |........?.[..0..|
+00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 1f 31 0b |.*.H........0.1.|
+00000070 30 09 06 03 55 04 0a 13 02 47 6f 31 10 30 0e 06 |0...U....Go1.0..|
+00000080 03 55 04 03 13 07 47 6f 20 52 6f 6f 74 30 1e 17 |.U....Go Root0..|
+00000090 0d 31 36 30 31 30 31 30 30 30 30 30 30 5a 17 0d |.160101000000Z..|
+000000a0 32 35 30 31 30 31 30 30 30 30 30 30 5a 30 1a 31 |250101000000Z0.1|
+000000b0 0b 30 09 06 03 55 04 0a 13 02 47 6f 31 0b 30 09 |.0...U....Go1.0.|
+000000c0 06 03 55 04 03 13 02 47 6f 30 81 9f 30 0d 06 09 |..U....Go0..0...|
+000000d0 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 30 |*.H............0|
+000000e0 81 89 02 81 81 00 db 46 7d 93 2e 12 27 06 48 bc |.......F}...'.H.|
+000000f0 06 28 21 ab 7e c4 b6 a2 5d fe 1e 52 45 88 7a 36 |.(!.~...]..RE.z6|
+00000100 47 a5 08 0d 92 42 5b c2 81 c0 be 97 79 98 40 fb |G....B[.....y. at .|
+00000110 4f 6d 14 fd 2b 13 8b c2 a5 2e 67 d8 d4 09 9e d6 |Om..+.....g.....|
+00000120 22 38 b7 4a 0b 74 73 2b c2 34 f1 d1 93 e5 96 d9 |"8.J.ts+.4......|
+00000130 74 7b f3 58 9f 6c 61 3c c0 b0 41 d4 d9 2b 2b 24 |t{.X.la<..A..++$|
+00000140 23 77 5b 1c 3b bd 75 5d ce 20 54 cf a1 63 87 1d |#w[.;.u]. T..c..|
+00000150 1e 24 c4 f3 1d 1a 50 8b aa b6 14 43 ed 97 a7 75 |.$....P....C...u|
+00000160 62 f4 14 c8 52 d7 02 03 01 00 01 a3 81 93 30 81 |b...R.........0.|
+00000170 90 30 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 05 |.0...U..........|
+00000180 a0 30 1d 06 03 55 1d 25 04 16 30 14 06 08 2b 06 |.0...U.%..0...+.|
+00000190 01 05 05 07 03 01 06 08 2b 06 01 05 05 07 03 02 |........+.......|
+000001a0 30 0c 06 03 55 1d 13 01 01 ff 04 02 30 00 30 19 |0...U.......0.0.|
+000001b0 06 03 55 1d 0e 04 12 04 10 9f 91 16 1f 43 43 3e |..U..........CC>|
+000001c0 49 a6 de 6d b6 80 d7 9f 60 30 1b 06 03 55 1d 23 |I..m....`0...U.#|
+000001d0 04 14 30 12 80 10 48 13 49 4d 13 7e 16 31 bb a3 |..0...H.IM.~.1..|
+000001e0 01 d5 ac ab 6e 7b 30 19 06 03 55 1d 11 04 12 30 |....n{0...U....0|
+000001f0 10 82 0e 65 78 61 6d 70 6c 65 2e 67 6f 6c 61 6e |...example.golan|
+00000200 67 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 |g0...*.H........|
+00000210 03 81 81 00 9d 30 cc 40 2b 5b 50 a0 61 cb ba e5 |.....0. at +[P.a...|
+00000220 53 58 e1 ed 83 28 a9 58 1a a9 38 a4 95 a1 ac 31 |SX...(.X..8....1|
+00000230 5a 1a 84 66 3d 43 d3 2d d9 0b f2 97 df d3 20 64 |Z..f=C.-...... d|
+00000240 38 92 24 3a 00 bc cf 9c 7d b7 40 20 01 5f aa d3 |8.$:....}.@ ._..|
+00000250 16 61 09 a2 76 fd 13 c3 cc e1 0c 5c ee b1 87 82 |.a..v......\....|
+00000260 f1 6c 04 ed 73 bb b3 43 77 8d 0c 1c f1 0f a1 d8 |.l..s..Cw.......|
+00000270 40 83 61 c9 4c 72 2b 9d ae db 46 06 06 4d f4 c1 |@.a.Lr+...F..M..|
+00000280 b3 3e c0 d1 bd 42 d4 db fe 3d 13 60 84 5c 21 d3 |.>...B...=.`.\!.|
+00000290 3b e9 fa e7 16 03 03 00 17 0d 00 00 13 02 01 40 |;..............@|
+000002a0 00 0c 04 01 04 03 05 01 05 03 02 01 02 03 00 00 |................|
+000002b0 16 03 03 00 04 0e 00 00 00 |.........|
>>> Flow 3 (client to server)
00000000 16 03 03 00 07 0b 00 00 03 00 00 00 16 03 03 00 |................|
-00000010 86 10 00 00 82 00 80 3a 72 91 a2 c3 ba 83 75 1b |.......:r.....u.|
-00000020 d3 f6 1c 07 7f 92 a8 b0 1f 47 42 cc 8d 4e 7e 1e |.........GB..N~.|
-00000030 23 49 44 29 53 19 9f 3b 5c bb 5d ed 6c d9 49 5d |#ID)S..;\.].l.I]|
-00000040 6e f9 d1 59 9d 40 67 b3 0c ee 41 85 6c 4a 4d 3b |n..Y. at g...A.lJM;|
-00000050 c1 e6 c8 7f 93 15 cb 2a 17 64 da 70 f3 2a c3 7c |.......*.d.p.*.||
-00000060 a2 02 48 19 fb 74 5a dc 52 0d 80 6b ed c0 8c 15 |..H..tZ.R..k....|
-00000070 3e 3b 34 7c 55 6e 95 e0 d1 4a 7f b0 bc 33 67 a7 |>;4|Un...J...3g.|
-00000080 3b 40 bb eb 83 58 4a fb fb 01 9b 0d fa ef 83 c4 |;@...XJ.........|
-00000090 87 10 75 0c a7 ad 91 14 03 03 00 01 01 16 03 03 |..u.............|
-000000a0 00 24 18 ce de 8d ab c1 6e 3b 0b 51 fe 94 ae 0a |.$......n;.Q....|
-000000b0 39 9c 4d a2 90 53 d4 1e 5f f6 96 5a 51 f2 39 c1 |9.M..S.._..ZQ.9.|
-000000c0 d6 06 c0 4e 58 99 |...NX.|
+00000010 86 10 00 00 82 00 80 61 2e 6b ad 77 48 8d 2f 0e |.......a.k.wH./.|
+00000020 e6 27 64 fd 95 22 72 68 80 8e 2b 0e b2 0f cc be |.'d.."rh..+.....|
+00000030 19 31 93 1d d3 0a fb 00 da 50 26 66 17 59 6b e9 |.1.......P&f.Yk.|
+00000040 7e 16 4e 24 ba 68 0a 0c 69 2f 03 74 34 50 12 85 |~.N$.h..i/.t4P..|
+00000050 4a f0 6c 52 d4 dd 13 18 c7 a4 9d ea f0 c6 94 d9 |J.lR............|
+00000060 ae fe 19 6c 83 dd ed 38 e3 d2 21 18 e6 76 11 e7 |...l...8..!..v..|
+00000070 62 13 8b 56 65 e0 f6 61 d9 db 7c 7b 5b 57 13 3d |b..Ve..a..|{[W.=|
+00000080 58 64 67 8d 9f 3f 6a a0 70 c5 c6 d0 db eb 17 3f |Xdg..?j.p......?|
+00000090 6c 58 d7 c3 ba ec 4c 14 03 03 00 01 01 16 03 03 |lX....L.........|
+000000a0 00 40 6e 24 1b a4 b3 e7 d4 c2 7e cb bd 82 2d 4c |. at n$......~...-L|
+000000b0 a8 f1 5e 81 c8 61 a6 2c 6a e3 6d 30 7f fa c7 f3 |..^..a.,j.m0....|
+000000c0 f6 b1 b1 4f 0b 23 9a fd 66 81 48 97 4b 0f 88 07 |...O.#..f.H.K...|
+000000d0 37 7b 97 b0 62 6c 2a e1 47 65 e9 f9 cd c1 79 99 |7{..bl*.Ge....y.|
+000000e0 6d 84 |m.|
>>> Flow 4 (server to client)
-00000000 14 03 03 00 01 01 16 03 03 00 24 8b 7e 57 f3 7d |..........$.~W.}|
-00000010 ab 44 f0 c7 53 2d 39 08 14 32 12 4e 4b 45 9a e3 |.D..S-9..2.NKE..|
-00000020 1c 43 36 16 59 a0 4b e4 78 43 d2 a5 dc 96 b1 17 |.C6.Y.K.xC......|
-00000030 03 03 00 21 54 89 75 23 de 7d c7 c6 80 a6 a6 69 |...!T.u#.}.....i|
-00000040 d0 a8 95 77 71 a0 89 34 f4 c3 31 73 bb b0 ac d7 |...wq..4..1s....|
-00000050 e5 e4 83 4b 10 15 03 03 00 16 0d 44 43 67 21 cc |...K.......DCg!.|
-00000060 6c c1 7e 72 99 aa 7f a1 de 10 0b 36 ae 05 d9 9e |l.~r.......6....|
+00000000 14 03 03 00 01 01 16 03 03 00 40 00 00 00 00 00 |.......... at .....|
+00000010 00 00 00 00 00 00 00 00 00 00 00 40 c6 62 4e 26 |........... at .bN&|
+00000020 e7 32 09 ba d6 3b 71 79 8e 75 ee fb af 09 db c5 |.2...;qy.u......|
+00000030 a5 8b cd 1f 90 f3 65 86 4a b4 b1 9a e8 1e 80 f6 |......e.J.......|
+00000040 ad db bd c2 9f ec 98 42 0b 37 30 17 03 03 00 40 |.......B.70....@|
+00000050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000060 a9 74 3c 13 87 f4 cf 77 be 07 c2 a1 e0 47 4e 52 |.t<....w.....GNR|
+00000070 c2 86 da 08 c2 93 21 80 4c 19 51 cc 0d 76 49 75 |......!.L.Q..vIu|
+00000080 0b 48 3d e0 e2 01 93 4b f1 73 91 17 aa 00 b5 71 |.H=....K.s.....q|
+00000090 15 03 03 00 30 00 00 00 00 00 00 00 00 00 00 00 |....0...........|
+000000a0 00 00 00 00 00 1f 2f 2d d7 39 06 c4 59 49 80 66 |....../-.9..YI.f|
+000000b0 6c 35 2e a7 45 ee 0a 05 4b 1e 7f 78 5d cd 24 2c |l5..E...K..x].$,|
+000000c0 0a 3e 55 1c 7d |.>U.}|
diff --git a/src/crypto/tls/testdata/Server-TLSv12-ECDHE-ECDSA-AES b/src/crypto/tls/testdata/Server-TLSv12-ECDHE-ECDSA-AES
index 8b04a5a..b412980 100644
--- a/src/crypto/tls/testdata/Server-TLSv12-ECDHE-ECDSA-AES
+++ b/src/crypto/tls/testdata/Server-TLSv12-ECDHE-ECDSA-AES
@@ -1,13 +1,12 @@
>>> Flow 1 (client to server)
-00000000 16 03 01 00 83 01 00 00 7f 03 03 ec 8e d0 43 01 |..............C.|
-00000010 8e 81 3f d8 1f 7e 96 f1 de 4c 94 18 09 1d c5 8c |..?..~...L......|
-00000020 3a 58 68 5b 3e 7d 46 66 fe 04 74 00 00 04 c0 0a |:Xh[>}Ff..t.....|
-00000030 00 ff 02 01 00 00 51 00 0b 00 04 03 00 01 02 00 |......Q.........|
-00000040 0a 00 1c 00 1a 00 17 00 19 00 1c 00 1b 00 18 00 |................|
-00000050 1a 00 16 00 0e 00 0d 00 0b 00 0c 00 09 00 0a 00 |................|
-00000060 0d 00 20 00 1e 06 01 06 02 06 03 05 01 05 02 05 |.. .............|
-00000070 03 04 01 04 02 04 03 03 01 03 02 03 03 02 01 02 |................|
-00000080 02 02 03 00 0f 00 01 01 |........|
+00000000 16 03 01 00 73 01 00 00 6f 03 03 f0 4f 82 cc 2a |....s...o...O..*|
+00000010 27 0b 7f 2e e4 af 6d ba 4e fe 61 99 fc 0a 44 ee |'.....m.N.a...D.|
+00000020 c0 4e 7b 3a 7c f0 6d 12 b7 7d 9e 00 00 04 c0 0a |.N{:|.m..}......|
+00000030 00 ff 01 00 00 42 00 0b 00 04 03 00 01 02 00 0a |.....B..........|
+00000040 00 0a 00 08 00 1d 00 17 00 19 00 18 00 0d 00 20 |............... |
+00000050 00 1e 06 01 06 02 06 03 05 01 05 02 05 03 04 01 |................|
+00000060 04 02 04 03 03 01 03 02 03 03 02 01 02 02 02 03 |................|
+00000070 00 16 00 00 00 17 00 00 |........|
>>> Flow 2 (server to client)
00000000 16 03 03 00 31 02 00 00 2d 03 03 00 00 00 00 00 |....1...-.......|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
@@ -45,43 +44,39 @@
00000210 0e bd 3f a3 8c 25 c1 33 13 83 0d 94 06 bb d4 37 |..?..%.3.......7|
00000220 7a f6 ec 7a c9 86 2e dd d7 11 69 7f 85 7c 56 de |z..z......i..|V.|
00000230 fb 31 78 2b e4 c7 78 0d ae cb be 9e 4e 36 24 31 |.1x+..x.....N6$1|
-00000240 7b 6a 0f 39 95 12 07 8f 2a 16 03 03 00 d8 0c 00 |{j.9....*.......|
-00000250 00 d4 03 00 17 41 04 1e 18 37 ef 0d 19 51 88 35 |.....A...7...Q.5|
-00000260 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd a7 24 20 3e |uq..T[....g..$ >|
-00000270 b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e f1 07 9f 6c |.V...(^.+-O....l|
-00000280 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 a6 b5 68 1a |K[.V.2B.X..I..h.|
-00000290 41 03 56 6b dc 5a 89 05 03 00 8b 30 81 88 02 42 |A.Vk.Z.....0...B|
-000002a0 01 08 89 99 1c 91 97 fb e8 5b 69 5f f5 36 66 d6 |.........[i_.6f.|
-000002b0 dd 53 04 09 c8 7f c1 25 28 8c 28 57 55 3a 95 3f |.S.....%(.(WU:.?|
-000002c0 ab 09 47 9a 27 74 83 84 44 cf 86 b7 5e 7f fe db |..G.'t..D...^...|
-000002d0 05 33 3c 1a b7 f6 bc ff 0d 33 e4 ec 3c e2 1d e2 |.3<......3..<...|
-000002e0 6e ab 02 42 00 92 4e 45 a7 86 e4 bd 40 82 b7 04 |n..B..NE.... at ...|
-000002f0 12 fe 34 ab e3 c9 4a 05 1f 4e 58 79 67 58 94 53 |..4...J..NXygX.S|
-00000300 e8 1b ba 60 76 92 00 99 a7 5f 0a 98 cb e3 1e de |...`v...._......|
-00000310 0c df 18 76 58 d5 e1 f1 ef a5 da 9a a3 62 77 50 |...vX........bwP|
-00000320 37 d0 22 d0 31 90 16 03 03 00 04 0e 00 00 00 |7.".1..........|
+00000240 7b 6a 0f 39 95 12 07 8f 2a 16 03 03 00 b7 0c 00 |{j.9....*.......|
+00000250 00 b3 03 00 1d 20 2f e5 7d a3 47 cd 62 43 15 28 |..... /.}.G.bC.(|
+00000260 da ac 5f bb 29 07 30 ff f6 84 af c4 cf c2 ed 90 |.._.).0.........|
+00000270 99 5f 58 cb 3b 74 05 03 00 8b 30 81 88 02 42 01 |._X.;t....0...B.|
+00000280 2d d4 82 80 01 6b e6 8c 6a 2a b3 09 1b 0d 86 e6 |-....k..j*......|
+00000290 62 92 85 46 d9 e3 b2 e9 f1 5e 77 c2 27 fd 2b 68 |b..F.....^w.'.+h|
+000002a0 6a e1 3d e2 42 d2 86 96 42 b1 3b 50 7b e2 2c 34 |j.=.B...B.;P{.,4|
+000002b0 d3 e7 f6 14 89 48 eb 5c 9a 98 98 ab f3 db 85 06 |.....H.\........|
+000002c0 cb 02 42 00 df 42 94 63 a5 ff 43 a5 20 5d 83 09 |..B..B.c..C. ]..|
+000002d0 88 7d 10 ff ec 32 33 28 1d 43 b2 d2 bf 39 0c 63 |.}...23(.C...9.c|
+000002e0 9a c0 f8 0e 9f 71 a7 9a 5d 27 1a 5c f2 36 80 b3 |.....q..]'.\.6..|
+000002f0 71 0f d3 c0 fd 0d 5d 02 90 c4 9d 90 db 74 ad f6 |q.....]......t..|
+00000300 22 8f 6b 9d 55 16 03 03 00 04 0e 00 00 00 |".k.U.........|
>>> Flow 3 (client to server)
-00000000 16 03 03 00 46 10 00 00 42 41 04 9e 94 25 4f 70 |....F...BA...%Op|
-00000010 a8 e0 87 3a 09 6c 58 4f 5e 76 d9 63 dc c3 d5 63 |...:.lXO^v.c...c|
-00000020 be f2 75 ff 23 23 79 6b 82 fe 56 f5 b9 7a 55 55 |..u.##yk..V..zUU|
-00000030 32 3b ee c5 f0 1f 7b e9 82 01 21 8d 06 03 48 95 |2;....{...!...H.|
-00000040 21 b8 fa 9d 18 2a 08 9c 71 a8 4d 14 03 03 00 01 |!....*..q.M.....|
-00000050 01 16 03 03 00 40 31 f0 7b 5f e8 94 a3 7f b0 12 |..... at 1.{_......|
-00000060 a9 80 87 26 eb cf b6 87 61 e7 5b 9b 36 3d 11 bb |...&....a.[.6=..|
-00000070 21 55 5c f7 e8 f3 b7 1e f2 06 0d c5 a9 8d f8 48 |!U\............H|
-00000080 c2 2b 8f 83 be 17 4f ec ff 8e 24 44 74 25 09 40 |.+....O...$Dt%.@|
-00000090 90 fd 70 4d fb bb |..pM..|
+00000000 16 03 03 00 25 10 00 00 21 20 af 52 73 d4 46 4d |....%...! .Rs.FM|
+00000010 bc 0e dd 56 1f 7f 72 ce 6c 99 b9 64 53 7d 53 8d |...V..r.l..dS}S.|
+00000020 0c a4 75 8c 83 3b 4b 76 2d 4f 14 03 03 00 01 01 |..u..;Kv-O......|
+00000030 16 03 03 00 40 a0 ef 9f 54 a8 ab 7c 5b 4a a1 b2 |.... at ...T..|[J..|
+00000040 5d 5b 6a d7 a7 32 35 46 58 d0 ba 38 6f 94 6e 9a |][j..25FX..8o.n.|
+00000050 41 16 82 ed 4d 39 c4 ff 06 bf 2c 67 47 70 56 4e |A...M9....,gGpVN|
+00000060 c5 ac 7f a0 5d d9 89 82 7a d9 36 07 55 b3 20 f4 |....]...z.6.U. .|
+00000070 b2 73 cf c3 7d |.s..}|
>>> Flow 4 (server to client)
00000000 14 03 03 00 01 01 16 03 03 00 40 00 00 00 00 00 |.......... at .....|
-00000010 00 00 00 00 00 00 00 00 00 00 00 13 eb 4e 56 3d |.............NV=|
-00000020 1b 10 2e e8 08 65 b9 53 9e 56 49 b7 e9 25 35 94 |.....e.S.VI..%5.|
-00000030 c7 df 7d f7 78 2e f3 8b 9c 2b 9d 42 90 91 5c 97 |..}.x....+.B..\.|
-00000040 22 20 ca 6d a2 83 b3 d8 b3 71 64 17 03 03 00 40 |" .m.....qd....@|
+00000010 00 00 00 00 00 00 00 00 00 00 00 73 5f db 9e 08 |...........s_...|
+00000020 10 38 3b c0 95 6b dd fc 16 b2 d1 db 63 13 ca d5 |.8;..k......c...|
+00000030 b5 be 5a 1d 74 b5 75 f3 a2 63 59 be a7 d0 ab 0d |..Z.t.u..cY.....|
+00000040 d3 43 83 8a 1d 59 ed fd ea f0 b9 17 03 03 00 40 |.C...Y.........@|
00000050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
-00000060 97 f1 c4 2e bf 6d 85 d5 3d 4b 4a 8b ee 53 08 5a |.....m..=KJ..S.Z|
-00000070 db 8b 75 49 d9 cb db e3 86 90 ac 93 ce e7 9a 70 |..uI...........p|
-00000080 4c dc 4a f4 c9 f6 b5 fd f0 3f 9f e9 f9 c3 b3 c6 |L.J......?......|
+00000060 cf 20 4f 4f bf c4 00 05 1e ca 7f 6f 69 77 e9 52 |. OO.......oiw.R|
+00000070 14 61 02 6d f1 c0 ad 7c 1a 34 cf b2 7a 58 4a 70 |.a.m...|.4..zXJp|
+00000080 11 36 5f e9 21 62 cb eb 8f e7 11 04 bf 66 03 69 |.6_.!b.......f.i|
00000090 15 03 03 00 30 00 00 00 00 00 00 00 00 00 00 00 |....0...........|
-000000a0 00 00 00 00 00 5e b1 b7 21 7d 89 65 66 17 d8 79 |.....^..!}.ef..y|
-000000b0 26 db ad 08 28 2c e7 7a c4 ec 93 19 4f c8 bb 5c |&...(,.z....O..\|
-000000c0 c2 9e 09 56 07 |...V.|
+000000a0 00 00 00 00 00 f5 35 92 09 6c 45 c0 27 95 98 a9 |......5..lE.'...|
+000000b0 86 56 53 1f a8 01 d5 0b 79 0e 91 15 3b 9a 07 21 |.VS.....y...;..!|
+000000c0 cb ce f0 2b 6a |...+j|
diff --git a/src/crypto/tls/testdata/Server-TLSv12-IssueTicket b/src/crypto/tls/testdata/Server-TLSv12-IssueTicket
index 2760508..feced4b 100644
--- a/src/crypto/tls/testdata/Server-TLSv12-IssueTicket
+++ b/src/crypto/tls/testdata/Server-TLSv12-IssueTicket
@@ -1,83 +1,89 @@
>>> Flow 1 (client to server)
-00000000 16 03 01 00 5f 01 00 00 5b 03 03 6e cc 37 81 0a |...._...[..n.7..|
-00000010 b9 fe 58 30 8e 32 61 3c b1 38 1e 2b f6 ab 44 ee |..X0.2a<.8.+..D.|
-00000020 f2 cc fe 6e fe 40 65 49 d9 ba aa 00 00 04 00 05 |...n. at eI........|
-00000030 00 ff 02 01 00 00 2d 00 23 00 00 00 0d 00 20 00 |......-.#..... .|
-00000040 1e 06 01 06 02 06 03 05 01 05 02 05 03 04 01 04 |................|
-00000050 02 04 03 03 01 03 02 03 03 02 01 02 02 02 03 00 |................|
-00000060 0f 00 01 01 |....|
+00000000 16 03 01 00 61 01 00 00 5d 03 03 b1 be 1f 18 b6 |....a...].......|
+00000010 a2 5d 4f 2f a0 e5 3b c4 4a 2d 76 bd 98 92 32 85 |.]O/..;.J-v...2.|
+00000020 9d 6b 9e 10 4b fc 03 7b fb bc e4 00 00 04 00 2f |.k..K..{......./|
+00000030 00 ff 01 00 00 30 00 23 00 00 00 0d 00 20 00 1e |.....0.#..... ..|
+00000040 06 01 06 02 06 03 05 01 05 02 05 03 04 01 04 02 |................|
+00000050 04 03 03 01 03 02 03 03 02 01 02 02 02 03 00 16 |................|
+00000060 00 00 00 17 00 00 |......|
>>> Flow 2 (server to client)
00000000 16 03 03 00 35 02 00 00 31 03 03 00 00 00 00 00 |....5...1.......|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
-00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 05 00 00 |................|
-00000030 09 00 23 00 00 ff 01 00 01 00 16 03 03 02 71 0b |..#...........q.|
-00000040 00 02 6d 00 02 6a 00 02 67 30 82 02 63 30 82 01 |..m..j..g0..c0..|
-00000050 cc a0 03 02 01 02 02 09 00 a2 73 00 0c 81 00 cb |..........s.....|
-00000060 f3 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 |.0...*.H........|
-00000070 30 2b 31 17 30 15 06 03 55 04 0a 13 0e 47 6f 6f |0+1.0...U....Goo|
-00000080 67 6c 65 20 54 45 53 54 49 4e 47 31 10 30 0e 06 |gle TESTING1.0..|
-00000090 03 55 04 03 13 07 47 6f 20 52 6f 6f 74 30 1e 17 |.U....Go Root0..|
-000000a0 0d 31 35 30 31 30 31 30 30 30 30 30 30 5a 17 0d |.150101000000Z..|
-000000b0 32 35 30 31 30 31 30 30 30 30 30 30 5a 30 26 31 |250101000000Z0&1|
-000000c0 17 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 |.0...U....Google|
-000000d0 20 54 45 53 54 49 4e 47 31 0b 30 09 06 03 55 04 | TESTING1.0...U.|
-000000e0 03 13 02 47 6f 30 81 9f 30 0d 06 09 2a 86 48 86 |...Go0..0...*.H.|
-000000f0 f7 0d 01 01 01 05 00 03 81 8d 00 30 81 89 02 81 |...........0....|
-00000100 81 00 af 87 88 f6 20 1b 95 65 6c 14 ab 44 05 af |...... ..el..D..|
-00000110 3b 45 14 e3 b7 6d fd 00 63 4d 95 7f fe 6a 62 35 |;E...m..cM...jb5|
-00000120 86 c0 4a f9 18 7c f6 aa 25 5e 7a 64 31 66 00 ba |..J..|..%^zd1f..|
-00000130 f4 8e 92 af c7 6b d8 76 d4 f3 5f 41 cb 6e 56 15 |.....k.v.._A.nV.|
-00000140 97 1b 97 c1 3c 12 39 21 66 3d 2b 16 d1 bc db 1c |....<.9!f=+.....|
-00000150 c0 a7 da b7 ca ad ba da cb d5 21 50 ec de 8d ab |..........!P....|
-00000160 d1 6b 81 4b 89 02 f3 c4 be c1 6c 89 b1 44 84 bd |.k.K......l..D..|
-00000170 21 d1 04 7d 9d 16 4d f9 82 15 f6 ef fa d6 09 47 |!..}..M........G|
-00000180 f2 fb 02 03 01 00 01 a3 81 93 30 81 90 30 0e 06 |..........0..0..|
-00000190 03 55 1d 0f 01 01 ff 04 04 03 02 05 a0 30 1d 06 |.U...........0..|
-000001a0 03 55 1d 25 04 16 30 14 06 08 2b 06 01 05 05 07 |.U.%..0...+.....|
-000001b0 03 01 06 08 2b 06 01 05 05 07 03 02 30 0c 06 03 |....+.......0...|
-000001c0 55 1d 13 01 01 ff 04 02 30 00 30 19 06 03 55 1d |U.......0.0...U.|
-000001d0 0e 04 12 04 10 12 50 8d 89 6f 1b d1 dc 54 4d 6e |......P..o...TMn|
-000001e0 cb 69 5e 06 f4 30 1b 06 03 55 1d 23 04 14 30 12 |.i^..0...U.#..0.|
-000001f0 80 10 bf 3d b6 a9 66 f2 b8 40 cf ea b4 03 78 48 |...=..f.. at ....xH|
-00000200 1a 41 30 19 06 03 55 1d 11 04 12 30 10 82 0e 65 |.A0...U....0...e|
-00000210 78 61 6d 70 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 |xample.golang0..|
-00000220 09 2a 86 48 86 f7 0d 01 01 0b 05 00 03 81 81 00 |.*.H............|
-00000230 92 7c af 91 55 12 18 96 59 31 a6 48 40 d5 2d d5 |.|..U...Y1.H at .-.|
-00000240 ee bb 02 a0 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 da |.......|..0}<.v.|
-00000250 4f 3d c0 fa ae 2d 33 24 6b 03 7b 1b 67 59 11 21 |O=...-3$k.{.gY.!|
-00000260 b5 11 bc 77 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f 22 |...w...n.-.5.d_"|
-00000270 3e 63 10 6b be ff 14 86 6d 0d f0 15 31 a8 14 38 |>c.k....m...1..8|
-00000280 1e 3b 84 87 2c cb 98 ed 51 76 b9 b1 4f dd db 9b |.;..,...Qv..O...|
-00000290 84 04 86 40 fa 51 dd ba b4 8d eb e3 46 de 46 b9 |... at .Q......F.F.|
-000002a0 4f 86 c7 f9 a4 c2 41 34 ac cc f6 ea b0 ab 39 18 |O.....A4......9.|
-000002b0 16 03 03 00 04 0e 00 00 00 |.........|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2f 00 00 |............./..|
+00000030 09 00 23 00 00 ff 01 00 01 00 16 03 03 02 59 0b |..#...........Y.|
+00000040 00 02 55 00 02 52 00 02 4f 30 82 02 4b 30 82 01 |..U..R..O0..K0..|
+00000050 b4 a0 03 02 01 02 02 09 00 e8 f0 9d 3f e2 5b ea |............?.[.|
+00000060 a6 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 |.0...*.H........|
+00000070 30 1f 31 0b 30 09 06 03 55 04 0a 13 02 47 6f 31 |0.1.0...U....Go1|
+00000080 10 30 0e 06 03 55 04 03 13 07 47 6f 20 52 6f 6f |.0...U....Go Roo|
+00000090 74 30 1e 17 0d 31 36 30 31 30 31 30 30 30 30 30 |t0...16010100000|
+000000a0 30 5a 17 0d 32 35 30 31 30 31 30 30 30 30 30 30 |0Z..250101000000|
+000000b0 5a 30 1a 31 0b 30 09 06 03 55 04 0a 13 02 47 6f |Z0.1.0...U....Go|
+000000c0 31 0b 30 09 06 03 55 04 03 13 02 47 6f 30 81 9f |1.0...U....Go0..|
+000000d0 30 0d 06 09 2a 86 48 86 f7 0d 01 01 01 05 00 03 |0...*.H.........|
+000000e0 81 8d 00 30 81 89 02 81 81 00 db 46 7d 93 2e 12 |...0.......F}...|
+000000f0 27 06 48 bc 06 28 21 ab 7e c4 b6 a2 5d fe 1e 52 |'.H..(!.~...]..R|
+00000100 45 88 7a 36 47 a5 08 0d 92 42 5b c2 81 c0 be 97 |E.z6G....B[.....|
+00000110 79 98 40 fb 4f 6d 14 fd 2b 13 8b c2 a5 2e 67 d8 |y. at .Om..+.....g.|
+00000120 d4 09 9e d6 22 38 b7 4a 0b 74 73 2b c2 34 f1 d1 |...."8.J.ts+.4..|
+00000130 93 e5 96 d9 74 7b f3 58 9f 6c 61 3c c0 b0 41 d4 |....t{.X.la<..A.|
+00000140 d9 2b 2b 24 23 77 5b 1c 3b bd 75 5d ce 20 54 cf |.++$#w[.;.u]. T.|
+00000150 a1 63 87 1d 1e 24 c4 f3 1d 1a 50 8b aa b6 14 43 |.c...$....P....C|
+00000160 ed 97 a7 75 62 f4 14 c8 52 d7 02 03 01 00 01 a3 |...ub...R.......|
+00000170 81 93 30 81 90 30 0e 06 03 55 1d 0f 01 01 ff 04 |..0..0...U......|
+00000180 04 03 02 05 a0 30 1d 06 03 55 1d 25 04 16 30 14 |.....0...U.%..0.|
+00000190 06 08 2b 06 01 05 05 07 03 01 06 08 2b 06 01 05 |..+.........+...|
+000001a0 05 07 03 02 30 0c 06 03 55 1d 13 01 01 ff 04 02 |....0...U.......|
+000001b0 30 00 30 19 06 03 55 1d 0e 04 12 04 10 9f 91 16 |0.0...U.........|
+000001c0 1f 43 43 3e 49 a6 de 6d b6 80 d7 9f 60 30 1b 06 |.CC>I..m....`0..|
+000001d0 03 55 1d 23 04 14 30 12 80 10 48 13 49 4d 13 7e |.U.#..0...H.IM.~|
+000001e0 16 31 bb a3 01 d5 ac ab 6e 7b 30 19 06 03 55 1d |.1......n{0...U.|
+000001f0 11 04 12 30 10 82 0e 65 78 61 6d 70 6c 65 2e 67 |...0...example.g|
+00000200 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 86 f7 0d 01 |olang0...*.H....|
+00000210 01 0b 05 00 03 81 81 00 9d 30 cc 40 2b 5b 50 a0 |.........0. at +[P.|
+00000220 61 cb ba e5 53 58 e1 ed 83 28 a9 58 1a a9 38 a4 |a...SX...(.X..8.|
+00000230 95 a1 ac 31 5a 1a 84 66 3d 43 d3 2d d9 0b f2 97 |...1Z..f=C.-....|
+00000240 df d3 20 64 38 92 24 3a 00 bc cf 9c 7d b7 40 20 |.. d8.$:....}.@ |
+00000250 01 5f aa d3 16 61 09 a2 76 fd 13 c3 cc e1 0c 5c |._...a..v......\|
+00000260 ee b1 87 82 f1 6c 04 ed 73 bb b3 43 77 8d 0c 1c |.....l..s..Cw...|
+00000270 f1 0f a1 d8 40 83 61 c9 4c 72 2b 9d ae db 46 06 |.... at .a.Lr+...F.|
+00000280 06 4d f4 c1 b3 3e c0 d1 bd 42 d4 db fe 3d 13 60 |.M...>...B...=.`|
+00000290 84 5c 21 d3 3b e9 fa e7 16 03 03 00 04 0e 00 00 |.\!.;...........|
+000002a0 00 |.|
>>> Flow 3 (client to server)
-00000000 16 03 03 00 86 10 00 00 82 00 80 5d f3 3b c6 24 |...........].;.$|
-00000010 34 17 eb e1 6c de fa cd ed 6f 42 74 01 5f 4b 22 |4...l....oBt._K"|
-00000020 9e 79 da 68 9f e9 f8 af 84 6b b7 38 52 f3 5e a1 |.y.h.....k.8R.^.|
-00000030 e2 aa d1 48 15 1e 39 6e 18 59 3e dc 57 4a fb b1 |...H..9n.Y>.WJ..|
-00000040 18 18 40 ae 84 da d8 76 50 65 3b a5 d9 7a 72 b1 |.. at ....vPe;..zr.|
-00000050 51 07 65 08 0e 1d 05 f5 47 a8 7d 79 89 1e fe 00 |Q.e.....G.}y....|
-00000060 89 af 01 7f 4d 0c 11 d7 02 cf 88 7b be 03 c5 65 |....M......{...e|
-00000070 44 77 32 56 5c da 01 53 d1 dd d9 b4 5f 42 85 da |Dw2V\..S...._B..|
-00000080 82 0b 95 59 45 a3 7a 48 d4 00 22 14 03 03 00 01 |...YE.zH..".....|
-00000090 01 16 03 03 00 24 dd 06 a2 4b a0 8e 8b 31 f2 26 |.....$...K...1.&|
-000000a0 b2 6f d4 5d ff 34 eb 31 42 16 e7 c2 26 3d f7 16 |.o.].4.1B...&=..|
-000000b0 ed bd 41 4b 6f d4 03 fb b7 83 |..AKo.....|
+00000000 16 03 03 00 86 10 00 00 82 00 80 8f f0 5a 2f 01 |.............Z/.|
+00000010 99 79 e6 f2 a0 31 a4 02 d8 c0 1e 70 e8 67 58 bd |.y...1.....p.gX.|
+00000020 a0 2a 37 3a 3c 2d 45 53 e7 d2 7d 94 16 ea 10 5c |.*7:<-ES..}....\|
+00000030 07 91 36 87 ab f6 d1 7a c7 40 a7 7f 23 1b ef 33 |..6....z. at ..#..3|
+00000040 80 ea 7d 75 d3 62 de 7d d2 6b cf 90 54 0f e7 02 |..}u.b.}.k..T...|
+00000050 03 85 ef 38 f4 e9 88 8f e4 7c 8c ac 95 e6 88 f4 |...8.....|......|
+00000060 05 f7 c7 89 4a 64 de 34 5f 09 c2 84 19 36 c1 42 |....Jd.4_....6.B|
+00000070 ea 03 69 38 7e 32 10 8a b5 cf c7 2f 8e c6 5f 29 |..i8~2...../.._)|
+00000080 4e 8a 8e d4 17 6c 9c 18 7b ea df 14 03 03 00 01 |N....l..{.......|
+00000090 01 16 03 03 00 40 5f 50 47 5a 97 52 9d 11 b5 db |..... at _PGZ.R....|
+000000a0 ab 7b b9 e3 74 52 c5 cd f4 73 18 cf 12 c4 fe 07 |.{..tR...s......|
+000000b0 88 5f a9 18 7a 12 23 67 ec 72 07 9f 19 b5 bf 52 |._..z.#g.r.....R|
+000000c0 2f dd 26 66 25 98 8c 5a 07 0f 26 c1 b0 38 6c 01 |/.&f%..Z..&..8l.|
+000000d0 e4 f4 ee dd b3 72 |.....r|
>>> Flow 4 (server to client)
00000000 16 03 03 00 82 04 00 00 7e 00 00 00 00 00 78 50 |........~.....xP|
00000010 46 ad c1 db a8 38 86 7b 2b bb fd d0 c3 42 3e 00 |F....8.{+....B>.|
00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 94 |................|
-00000030 6f 2c b5 83 61 4d 51 5f 33 46 48 fe 9e e9 83 f4 |o,..aMQ_3FH.....|
-00000040 b1 aa c9 b1 61 2a b2 9d 0f 17 c4 09 f6 26 7a 75 |....a*.......&zu|
-00000050 f1 19 99 db 36 d8 32 f0 94 61 4f 8f ed 80 33 51 |....6.2..aO...3Q|
-00000060 f3 c6 15 84 6b 33 94 c8 4f 84 b7 7c 27 6d 8f fe |....k3..O..|'m..|
-00000070 41 8e b2 92 ca 80 e8 6c ba 75 77 f5 3a 87 17 ae |A......l.uw.:...|
-00000080 f8 b9 6b 10 f9 85 da 14 03 03 00 01 01 16 03 03 |..k.............|
-00000090 00 24 70 bd b9 24 02 ce 69 8a 07 c7 c8 7e cf b7 |.$p..$..i....~..|
-000000a0 4e 2b e2 dc 47 fc f7 3a c8 2d ab a0 9a ed 27 d9 |N+..G..:.-....'.|
-000000b0 71 ea 45 29 d6 25 17 03 03 00 21 d9 28 ee 99 04 |q.E).%....!.(...|
-000000c0 35 ff ca 3d 30 3f 76 fb 08 1a 56 73 f5 72 c3 fa |5..=0?v...Vs.r..|
-000000d0 cd 9e 3c 1b 3f 43 4d 56 92 38 9e a6 15 03 03 00 |..<.?CMV.8......|
-000000e0 16 6f 55 57 7b 81 6f 7d fa 90 76 0b 5b 6d 95 35 |.oUW{.o}..v.[m.5|
-000000f0 39 9f a8 c9 dc b7 80 |9......|
+00000030 6f 2c 9f 83 61 0b b1 b7 9e 10 2d 0c 56 e8 70 66 |o,..a.....-.V.pf|
+00000040 ad de b1 15 74 2f 8b 08 8c 96 bb 4b 1b 4e dd 81 |....t/.....K.N..|
+00000050 0e bf 84 4d 43 8f c0 7e a0 7f be c0 59 bf 83 26 |...MC..~....Y..&|
+00000060 0f a2 22 52 2c 33 94 5a 77 54 f3 b5 f2 22 51 d5 |.."R,3.ZwT..."Q.|
+00000070 24 c2 60 c3 2e 0f 9c 5e 33 3b e8 7c 52 2a 76 08 |$.`....^3;.|R*v.|
+00000080 58 ac 47 98 bc 36 b6 14 03 03 00 01 01 16 03 03 |X.G..6..........|
+00000090 00 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |. at ..............|
+000000a0 00 00 31 fa c3 6c 95 c0 86 a5 55 30 41 c3 2d 6b |..1..l....U0A.-k|
+000000b0 a5 00 0b af 33 63 de 80 01 3d 7a 38 8e a7 f4 b1 |....3c...=z8....|
+000000c0 2d bb e3 1d 1a b4 61 18 b5 d9 d1 7f d1 9a e7 e8 |-.....a.........|
+000000d0 49 ee 17 03 03 00 40 00 00 00 00 00 00 00 00 00 |I..... at .........|
+000000e0 00 00 00 00 00 00 00 a6 d5 e4 a8 9b d3 7d 72 1c |.............}r.|
+000000f0 ff 14 03 68 34 c9 ca 0d 2e 80 a1 09 f7 92 f6 86 |...h4...........|
+00000100 44 22 e8 1c ea e9 dd cc a7 92 9a 72 ec 22 5b 82 |D".........r."[.|
+00000110 7b 43 02 f7 fa 59 7b 15 03 03 00 30 00 00 00 00 |{C...Y{....0....|
+00000120 00 00 00 00 00 00 00 00 00 00 00 00 5f ab 03 1d |............_...|
+00000130 08 72 07 6d 78 66 5b 18 ec 3a b7 ea 75 96 ce 95 |.r.mxf[..:..u...|
+00000140 0c c9 6f 86 91 14 30 d6 2e 5d b1 b4 |..o...0..]..|
diff --git a/src/crypto/tls/testdata/Server-TLSv12-IssueTicketPreDisable b/src/crypto/tls/testdata/Server-TLSv12-IssueTicketPreDisable
index b5eb6c7..467e332 100644
--- a/src/crypto/tls/testdata/Server-TLSv12-IssueTicketPreDisable
+++ b/src/crypto/tls/testdata/Server-TLSv12-IssueTicketPreDisable
@@ -1,83 +1,89 @@
>>> Flow 1 (client to server)
-00000000 16 03 01 00 5f 01 00 00 5b 03 03 54 25 f9 0f b8 |...._...[..T%...|
-00000010 2d 52 a0 17 b6 62 1c 60 38 31 30 67 f1 55 9c c8 |-R...b.`810g.U..|
-00000020 d3 74 65 bf cd 34 fb 6f f2 60 7c 00 00 04 00 05 |.te..4.o.`|.....|
-00000030 00 ff 02 01 00 00 2d 00 23 00 00 00 0d 00 20 00 |......-.#..... .|
-00000040 1e 06 01 06 02 06 03 05 01 05 02 05 03 04 01 04 |................|
-00000050 02 04 03 03 01 03 02 03 03 02 01 02 02 02 03 00 |................|
-00000060 0f 00 01 01 |....|
+00000000 16 03 01 00 61 01 00 00 5d 03 03 91 2f b7 db 1e |....a...].../...|
+00000010 41 ac c6 17 1d 0f 0c 8e 86 15 e0 de e9 c8 6b f5 |A.............k.|
+00000020 69 c7 bf ad ff 63 58 2b b1 79 a6 00 00 04 00 2f |i....cX+.y...../|
+00000030 00 ff 01 00 00 30 00 23 00 00 00 0d 00 20 00 1e |.....0.#..... ..|
+00000040 06 01 06 02 06 03 05 01 05 02 05 03 04 01 04 02 |................|
+00000050 04 03 03 01 03 02 03 03 02 01 02 02 02 03 00 16 |................|
+00000060 00 00 00 17 00 00 |......|
>>> Flow 2 (server to client)
00000000 16 03 03 00 35 02 00 00 31 03 03 00 00 00 00 00 |....5...1.......|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
-00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 05 00 00 |................|
-00000030 09 00 23 00 00 ff 01 00 01 00 16 03 03 02 71 0b |..#...........q.|
-00000040 00 02 6d 00 02 6a 00 02 67 30 82 02 63 30 82 01 |..m..j..g0..c0..|
-00000050 cc a0 03 02 01 02 02 09 00 a2 73 00 0c 81 00 cb |..........s.....|
-00000060 f3 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 |.0...*.H........|
-00000070 30 2b 31 17 30 15 06 03 55 04 0a 13 0e 47 6f 6f |0+1.0...U....Goo|
-00000080 67 6c 65 20 54 45 53 54 49 4e 47 31 10 30 0e 06 |gle TESTING1.0..|
-00000090 03 55 04 03 13 07 47 6f 20 52 6f 6f 74 30 1e 17 |.U....Go Root0..|
-000000a0 0d 31 35 30 31 30 31 30 30 30 30 30 30 5a 17 0d |.150101000000Z..|
-000000b0 32 35 30 31 30 31 30 30 30 30 30 30 5a 30 26 31 |250101000000Z0&1|
-000000c0 17 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 |.0...U....Google|
-000000d0 20 54 45 53 54 49 4e 47 31 0b 30 09 06 03 55 04 | TESTING1.0...U.|
-000000e0 03 13 02 47 6f 30 81 9f 30 0d 06 09 2a 86 48 86 |...Go0..0...*.H.|
-000000f0 f7 0d 01 01 01 05 00 03 81 8d 00 30 81 89 02 81 |...........0....|
-00000100 81 00 af 87 88 f6 20 1b 95 65 6c 14 ab 44 05 af |...... ..el..D..|
-00000110 3b 45 14 e3 b7 6d fd 00 63 4d 95 7f fe 6a 62 35 |;E...m..cM...jb5|
-00000120 86 c0 4a f9 18 7c f6 aa 25 5e 7a 64 31 66 00 ba |..J..|..%^zd1f..|
-00000130 f4 8e 92 af c7 6b d8 76 d4 f3 5f 41 cb 6e 56 15 |.....k.v.._A.nV.|
-00000140 97 1b 97 c1 3c 12 39 21 66 3d 2b 16 d1 bc db 1c |....<.9!f=+.....|
-00000150 c0 a7 da b7 ca ad ba da cb d5 21 50 ec de 8d ab |..........!P....|
-00000160 d1 6b 81 4b 89 02 f3 c4 be c1 6c 89 b1 44 84 bd |.k.K......l..D..|
-00000170 21 d1 04 7d 9d 16 4d f9 82 15 f6 ef fa d6 09 47 |!..}..M........G|
-00000180 f2 fb 02 03 01 00 01 a3 81 93 30 81 90 30 0e 06 |..........0..0..|
-00000190 03 55 1d 0f 01 01 ff 04 04 03 02 05 a0 30 1d 06 |.U...........0..|
-000001a0 03 55 1d 25 04 16 30 14 06 08 2b 06 01 05 05 07 |.U.%..0...+.....|
-000001b0 03 01 06 08 2b 06 01 05 05 07 03 02 30 0c 06 03 |....+.......0...|
-000001c0 55 1d 13 01 01 ff 04 02 30 00 30 19 06 03 55 1d |U.......0.0...U.|
-000001d0 0e 04 12 04 10 12 50 8d 89 6f 1b d1 dc 54 4d 6e |......P..o...TMn|
-000001e0 cb 69 5e 06 f4 30 1b 06 03 55 1d 23 04 14 30 12 |.i^..0...U.#..0.|
-000001f0 80 10 bf 3d b6 a9 66 f2 b8 40 cf ea b4 03 78 48 |...=..f.. at ....xH|
-00000200 1a 41 30 19 06 03 55 1d 11 04 12 30 10 82 0e 65 |.A0...U....0...e|
-00000210 78 61 6d 70 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 |xample.golang0..|
-00000220 09 2a 86 48 86 f7 0d 01 01 0b 05 00 03 81 81 00 |.*.H............|
-00000230 92 7c af 91 55 12 18 96 59 31 a6 48 40 d5 2d d5 |.|..U...Y1.H at .-.|
-00000240 ee bb 02 a0 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 da |.......|..0}<.v.|
-00000250 4f 3d c0 fa ae 2d 33 24 6b 03 7b 1b 67 59 11 21 |O=...-3$k.{.gY.!|
-00000260 b5 11 bc 77 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f 22 |...w...n.-.5.d_"|
-00000270 3e 63 10 6b be ff 14 86 6d 0d f0 15 31 a8 14 38 |>c.k....m...1..8|
-00000280 1e 3b 84 87 2c cb 98 ed 51 76 b9 b1 4f dd db 9b |.;..,...Qv..O...|
-00000290 84 04 86 40 fa 51 dd ba b4 8d eb e3 46 de 46 b9 |... at .Q......F.F.|
-000002a0 4f 86 c7 f9 a4 c2 41 34 ac cc f6 ea b0 ab 39 18 |O.....A4......9.|
-000002b0 16 03 03 00 04 0e 00 00 00 |.........|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2f 00 00 |............./..|
+00000030 09 00 23 00 00 ff 01 00 01 00 16 03 03 02 59 0b |..#...........Y.|
+00000040 00 02 55 00 02 52 00 02 4f 30 82 02 4b 30 82 01 |..U..R..O0..K0..|
+00000050 b4 a0 03 02 01 02 02 09 00 e8 f0 9d 3f e2 5b ea |............?.[.|
+00000060 a6 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 |.0...*.H........|
+00000070 30 1f 31 0b 30 09 06 03 55 04 0a 13 02 47 6f 31 |0.1.0...U....Go1|
+00000080 10 30 0e 06 03 55 04 03 13 07 47 6f 20 52 6f 6f |.0...U....Go Roo|
+00000090 74 30 1e 17 0d 31 36 30 31 30 31 30 30 30 30 30 |t0...16010100000|
+000000a0 30 5a 17 0d 32 35 30 31 30 31 30 30 30 30 30 30 |0Z..250101000000|
+000000b0 5a 30 1a 31 0b 30 09 06 03 55 04 0a 13 02 47 6f |Z0.1.0...U....Go|
+000000c0 31 0b 30 09 06 03 55 04 03 13 02 47 6f 30 81 9f |1.0...U....Go0..|
+000000d0 30 0d 06 09 2a 86 48 86 f7 0d 01 01 01 05 00 03 |0...*.H.........|
+000000e0 81 8d 00 30 81 89 02 81 81 00 db 46 7d 93 2e 12 |...0.......F}...|
+000000f0 27 06 48 bc 06 28 21 ab 7e c4 b6 a2 5d fe 1e 52 |'.H..(!.~...]..R|
+00000100 45 88 7a 36 47 a5 08 0d 92 42 5b c2 81 c0 be 97 |E.z6G....B[.....|
+00000110 79 98 40 fb 4f 6d 14 fd 2b 13 8b c2 a5 2e 67 d8 |y. at .Om..+.....g.|
+00000120 d4 09 9e d6 22 38 b7 4a 0b 74 73 2b c2 34 f1 d1 |...."8.J.ts+.4..|
+00000130 93 e5 96 d9 74 7b f3 58 9f 6c 61 3c c0 b0 41 d4 |....t{.X.la<..A.|
+00000140 d9 2b 2b 24 23 77 5b 1c 3b bd 75 5d ce 20 54 cf |.++$#w[.;.u]. T.|
+00000150 a1 63 87 1d 1e 24 c4 f3 1d 1a 50 8b aa b6 14 43 |.c...$....P....C|
+00000160 ed 97 a7 75 62 f4 14 c8 52 d7 02 03 01 00 01 a3 |...ub...R.......|
+00000170 81 93 30 81 90 30 0e 06 03 55 1d 0f 01 01 ff 04 |..0..0...U......|
+00000180 04 03 02 05 a0 30 1d 06 03 55 1d 25 04 16 30 14 |.....0...U.%..0.|
+00000190 06 08 2b 06 01 05 05 07 03 01 06 08 2b 06 01 05 |..+.........+...|
+000001a0 05 07 03 02 30 0c 06 03 55 1d 13 01 01 ff 04 02 |....0...U.......|
+000001b0 30 00 30 19 06 03 55 1d 0e 04 12 04 10 9f 91 16 |0.0...U.........|
+000001c0 1f 43 43 3e 49 a6 de 6d b6 80 d7 9f 60 30 1b 06 |.CC>I..m....`0..|
+000001d0 03 55 1d 23 04 14 30 12 80 10 48 13 49 4d 13 7e |.U.#..0...H.IM.~|
+000001e0 16 31 bb a3 01 d5 ac ab 6e 7b 30 19 06 03 55 1d |.1......n{0...U.|
+000001f0 11 04 12 30 10 82 0e 65 78 61 6d 70 6c 65 2e 67 |...0...example.g|
+00000200 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 86 f7 0d 01 |olang0...*.H....|
+00000210 01 0b 05 00 03 81 81 00 9d 30 cc 40 2b 5b 50 a0 |.........0. at +[P.|
+00000220 61 cb ba e5 53 58 e1 ed 83 28 a9 58 1a a9 38 a4 |a...SX...(.X..8.|
+00000230 95 a1 ac 31 5a 1a 84 66 3d 43 d3 2d d9 0b f2 97 |...1Z..f=C.-....|
+00000240 df d3 20 64 38 92 24 3a 00 bc cf 9c 7d b7 40 20 |.. d8.$:....}.@ |
+00000250 01 5f aa d3 16 61 09 a2 76 fd 13 c3 cc e1 0c 5c |._...a..v......\|
+00000260 ee b1 87 82 f1 6c 04 ed 73 bb b3 43 77 8d 0c 1c |.....l..s..Cw...|
+00000270 f1 0f a1 d8 40 83 61 c9 4c 72 2b 9d ae db 46 06 |.... at .a.Lr+...F.|
+00000280 06 4d f4 c1 b3 3e c0 d1 bd 42 d4 db fe 3d 13 60 |.M...>...B...=.`|
+00000290 84 5c 21 d3 3b e9 fa e7 16 03 03 00 04 0e 00 00 |.\!.;...........|
+000002a0 00 |.|
>>> Flow 3 (client to server)
-00000000 16 03 03 00 86 10 00 00 82 00 80 19 db c8 25 14 |..............%.|
-00000010 e0 7b 6e 87 7b 59 2d 85 8b 47 ce 31 d7 3a 53 06 |.{n.{Y-..G.1.:S.|
-00000020 ff cf 89 ae 45 fd 59 d2 50 c2 31 33 48 81 a8 d7 |....E.Y.P.13H...|
-00000030 47 36 b9 bd 8d f3 f9 f8 c2 6d 6a 8a 6b c4 e5 53 |G6.......mj.k..S|
-00000040 24 52 40 66 49 a9 56 74 4c 94 bc 85 5b 79 5a e1 |$R at fI.VtL...[yZ.|
-00000050 66 3c 42 d8 ca e1 3f c5 36 b8 b5 8c b2 ea 87 68 |f<B...?.6......h|
-00000060 70 eb e3 da 27 fe ed f5 d0 4a c7 fe 46 0b 0f 29 |p...'....J..F..)|
-00000070 19 41 ef dd a9 85 8a 67 02 41 04 30 20 07 09 55 |.A.....g.A.0 ..U|
-00000080 ff 92 44 f1 59 49 39 dd fa d7 a0 14 03 03 00 01 |..D.YI9.........|
-00000090 01 16 03 03 00 24 82 b5 7b d1 7c 03 93 88 fd 97 |.....$..{.|.....|
-000000a0 54 b7 ff 39 a7 11 c3 cd 53 f3 1c 6c ed ab b6 a0 |T..9....S..l....|
-000000b0 1c b9 89 f0 1a f8 5f 15 7f 85 |......_...|
+00000000 16 03 03 00 86 10 00 00 82 00 80 c5 0c 17 b1 b2 |................|
+00000010 65 0b b7 7b 45 6f cb 7d b4 9c 5c 82 3a 1a 75 11 |e..{Eo.}..\.:.u.|
+00000020 22 6f 41 3a 81 e2 81 2e 74 f8 70 61 fd e1 7c ce |"oA:....t.pa..|.|
+00000030 bf 06 d7 29 77 07 b3 9d cc 33 25 53 17 12 43 ae |...)w....3%S..C.|
+00000040 4f df ad a4 3e 49 6e 97 50 b6 23 d0 fa 3d a6 bc |O...>In.P.#..=..|
+00000050 38 d8 5f 2b 45 a7 d0 aa cd b1 39 03 8f 62 9e 46 |8._+E.....9..b.F|
+00000060 50 d4 83 1d b8 76 41 29 d4 40 9a 65 41 8d 1c f0 |P....vA). at .eA...|
+00000070 d4 4d 88 d2 5e 42 ec c8 86 d6 fd df 65 d8 f1 82 |.M..^B......e...|
+00000080 8f 6a 80 31 1a 0e fc 13 2b 90 a8 14 03 03 00 01 |.j.1....+.......|
+00000090 01 16 03 03 00 40 50 ad ed 91 c4 6a ed f8 aa 06 |..... at P....j....|
+000000a0 9e 13 03 38 bf 83 ef 4b 8e d5 89 d4 a3 f8 d9 8d |...8...K........|
+000000b0 bb 88 72 a6 16 f6 5d d5 ca 55 bb e4 76 47 08 35 |..r...]..U..vG.5|
+000000c0 b9 fb 92 a4 0a b9 36 d7 62 44 81 e8 cf db ad 9a |......6.bD......|
+000000d0 6d 72 c0 af 70 bd |mr..p.|
>>> Flow 4 (server to client)
00000000 16 03 03 00 82 04 00 00 7e 00 00 00 00 00 78 50 |........~.....xP|
00000010 46 ad c1 db a8 38 86 7b 2b bb fd d0 c3 42 3e 00 |F....8.{+....B>.|
00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 94 |................|
-00000030 6f 2c b5 83 61 01 55 65 2a 95 38 d4 d5 5f 41 c1 |o,..a.Ue*.8.._A.|
-00000040 45 e4 f8 4b 3b 08 44 df 0b 72 11 93 cd d4 ff 36 |E..K;.D..r.....6|
-00000050 0f 4f 3a a9 4c 9f ab c7 ae 88 97 bc 1e ff 2d 27 |.O:.L.........-'|
-00000060 39 a8 82 84 ae 33 94 48 8b 1c 58 9d 60 65 3c 3f |9....3.H..X.`e<?|
-00000070 17 9d 6a eb 50 cd 65 04 bb c7 28 c8 0d 57 44 52 |..j.P.e...(..WDR|
-00000080 e0 17 de df f3 13 b1 14 03 03 00 01 01 16 03 03 |................|
-00000090 00 24 5a 41 90 0a eb d9 6b 02 68 3d 98 12 1d fa |.$ZA....k.h=....|
-000000a0 46 7d 73 ea 8e 49 72 a5 2f 04 40 5c 7d 03 c7 3a |F}s..Ir./.@\}..:|
-000000b0 6e 50 7c 87 bb 13 17 03 03 00 21 46 da ec ad 52 |nP|.......!F...R|
-000000c0 ea 5a 01 89 15 77 79 af 86 02 b5 89 c8 97 dc f7 |.Z...wy.........|
-000000d0 ac 73 09 87 7a 61 57 d6 9b 17 10 af 15 03 03 00 |.s..zaW.........|
-000000e0 16 bb 20 22 ad 6e 65 66 8c d6 07 e3 82 5f ac 1e |.. ".nef....._..|
-000000f0 ec 54 72 eb 2d c5 af |.Tr.-..|
+00000030 6f 2c 9f 83 61 2e fe 48 fe f6 bb 98 a0 6f b0 be |o,..a..H.....o..|
+00000040 9e 86 d7 b2 f2 67 c7 44 c7 3d e4 2b de d0 f4 d2 |.....g.D.=.+....|
+00000050 17 51 84 8e 7a a7 80 c4 65 14 f7 49 09 68 15 56 |.Q..z...e..I.h.V|
+00000060 68 32 41 d1 6f 33 94 a1 3a c9 37 20 5d e6 b0 6f |h2A.o3..:.7 ]..o|
+00000070 37 0a 10 e3 28 e1 34 b6 6d e6 7a 44 24 7f 2f cf |7...(.4.m.zD$./.|
+00000080 1b ae dd 4c d0 11 75 14 03 03 00 01 01 16 03 03 |...L..u.........|
+00000090 00 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |. at ..............|
+000000a0 00 00 7e 4a 31 e8 7d c6 eb 34 56 3b 62 0c 11 a2 |..~J1.}..4V;b...|
+000000b0 f0 bd 9b 9a 4c c9 39 2d ed 21 dd 0c 72 3a 92 e1 |....L.9-.!..r:..|
+000000c0 0f b3 7f 71 c5 cf 2a 6f 68 bc 8e 84 7e d5 10 2e |...q..*oh...~...|
+000000d0 c3 d4 17 03 03 00 40 00 00 00 00 00 00 00 00 00 |...... at .........|
+000000e0 00 00 00 00 00 00 00 43 76 cc 74 b3 1c 89 c0 6b |.......Cv.t....k|
+000000f0 96 f7 2c 84 c1 0a 6e d6 7f b4 76 76 2c 2f 74 6a |..,...n...vv,/tj|
+00000100 c7 4e 18 69 1c 97 cd ca f2 7a 33 01 3e 6f bb 54 |.N.i.....z3.>o.T|
+00000110 49 4e 8e 1d f4 13 74 15 03 03 00 30 00 00 00 00 |IN....t....0....|
+00000120 00 00 00 00 00 00 00 00 00 00 00 00 2d 70 b1 13 |............-p..|
+00000130 a9 e3 72 ca 05 8e 8d b7 f4 97 de 58 46 aa 2a 9c |..r........XF.*.|
+00000140 2f 8c 3e 59 7b 64 e5 51 61 7f a6 39 |/.>Y{d.Qa..9|
diff --git a/src/crypto/tls/testdata/Server-TLSv12-RSA-3DES b/src/crypto/tls/testdata/Server-TLSv12-RSA-3DES
index 23b6c5b..af50381 100644
--- a/src/crypto/tls/testdata/Server-TLSv12-RSA-3DES
+++ b/src/crypto/tls/testdata/Server-TLSv12-RSA-3DES
@@ -1,77 +1,76 @@
>>> Flow 1 (client to server)
-00000000 16 03 01 00 5b 01 00 00 57 03 03 1e c8 d0 4c b2 |....[...W.....L.|
-00000010 8d 37 e1 88 c7 0f e0 6a 21 3c 5e 8a bf fa 97 1f |.7.....j!<^.....|
-00000020 5b 28 bc 6d 47 32 0a 6b f7 11 f5 00 00 04 00 0a |[(.mG2.k........|
-00000030 00 ff 02 01 00 00 29 00 0d 00 20 00 1e 06 01 06 |......)... .....|
-00000040 02 06 03 05 01 05 02 05 03 04 01 04 02 04 03 03 |................|
-00000050 01 03 02 03 03 02 01 02 02 02 03 00 0f 00 01 01 |................|
+00000000 16 03 01 00 5d 01 00 00 59 03 03 0c fb 72 82 e5 |....]...Y....r..|
+00000010 9a 04 90 c8 0d 73 25 9a 3f 88 e3 48 71 a2 33 3e |.....s%.?..Hq.3>|
+00000020 90 32 74 bc 12 38 d6 3a d3 11 1d 00 00 04 00 0a |.2t..8.:........|
+00000030 00 ff 01 00 00 2c 00 0d 00 20 00 1e 06 01 06 02 |.....,... ......|
+00000040 06 03 05 01 05 02 05 03 04 01 04 02 04 03 03 01 |................|
+00000050 03 02 03 03 02 01 02 02 02 03 00 16 00 00 00 17 |................|
+00000060 00 00 |..|
>>> Flow 2 (server to client)
00000000 16 03 03 00 31 02 00 00 2d 03 03 00 00 00 00 00 |....1...-.......|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 0a 00 00 |................|
-00000030 05 ff 01 00 01 00 16 03 03 02 71 0b 00 02 6d 00 |..........q...m.|
-00000040 02 6a 00 02 67 30 82 02 63 30 82 01 cc a0 03 02 |.j..g0..c0......|
-00000050 01 02 02 09 00 a2 73 00 0c 81 00 cb f3 30 0d 06 |......s......0..|
-00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 2b 31 17 |.*.H........0+1.|
-00000070 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 |0...U....Google |
-00000080 54 45 53 54 49 4e 47 31 10 30 0e 06 03 55 04 03 |TESTING1.0...U..|
-00000090 13 07 47 6f 20 52 6f 6f 74 30 1e 17 0d 31 35 30 |..Go Root0...150|
-000000a0 31 30 31 30 30 30 30 30 30 5a 17 0d 32 35 30 31 |101000000Z..2501|
-000000b0 30 31 30 30 30 30 30 30 5a 30 26 31 17 30 15 06 |01000000Z0&1.0..|
-000000c0 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 54 45 53 |.U....Google TES|
-000000d0 54 49 4e 47 31 0b 30 09 06 03 55 04 03 13 02 47 |TING1.0...U....G|
-000000e0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....|
-000000f0 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 af 87 |.......0........|
-00000100 88 f6 20 1b 95 65 6c 14 ab 44 05 af 3b 45 14 e3 |.. ..el..D..;E..|
-00000110 b7 6d fd 00 63 4d 95 7f fe 6a 62 35 86 c0 4a f9 |.m..cM...jb5..J.|
-00000120 18 7c f6 aa 25 5e 7a 64 31 66 00 ba f4 8e 92 af |.|..%^zd1f......|
-00000130 c7 6b d8 76 d4 f3 5f 41 cb 6e 56 15 97 1b 97 c1 |.k.v.._A.nV.....|
-00000140 3c 12 39 21 66 3d 2b 16 d1 bc db 1c c0 a7 da b7 |<.9!f=+.........|
-00000150 ca ad ba da cb d5 21 50 ec de 8d ab d1 6b 81 4b |......!P.....k.K|
-00000160 89 02 f3 c4 be c1 6c 89 b1 44 84 bd 21 d1 04 7d |......l..D..!..}|
-00000170 9d 16 4d f9 82 15 f6 ef fa d6 09 47 f2 fb 02 03 |..M........G....|
-00000180 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..|
-00000190 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%|
-000001a0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........|
-000001b0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...|
-000001c0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....|
-000001d0 10 12 50 8d 89 6f 1b d1 dc 54 4d 6e cb 69 5e 06 |..P..o...TMn.i^.|
-000001e0 f4 30 1b 06 03 55 1d 23 04 14 30 12 80 10 bf 3d |.0...U.#..0....=|
-000001f0 b6 a9 66 f2 b8 40 cf ea b4 03 78 48 1a 41 30 19 |..f.. at ....xH.A0.|
-00000200 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp|
-00000210 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H|
-00000220 86 f7 0d 01 01 0b 05 00 03 81 81 00 92 7c af 91 |.............|..|
-00000230 55 12 18 96 59 31 a6 48 40 d5 2d d5 ee bb 02 a0 |U...Y1.H at .-.....|
-00000240 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 da 4f 3d c0 fa |...|..0}<.v.O=..|
-00000250 ae 2d 33 24 6b 03 7b 1b 67 59 11 21 b5 11 bc 77 |.-3$k.{.gY.!...w|
-00000260 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f 22 3e 63 10 6b |...n.-.5.d_">c.k|
-00000270 be ff 14 86 6d 0d f0 15 31 a8 14 38 1e 3b 84 87 |....m...1..8.;..|
-00000280 2c cb 98 ed 51 76 b9 b1 4f dd db 9b 84 04 86 40 |,...Qv..O......@|
-00000290 fa 51 dd ba b4 8d eb e3 46 de 46 b9 4f 86 c7 f9 |.Q......F.F.O...|
-000002a0 a4 c2 41 34 ac cc f6 ea b0 ab 39 18 16 03 03 00 |..A4......9.....|
-000002b0 04 0e 00 00 00 |.....|
+00000030 05 ff 01 00 01 00 16 03 03 02 59 0b 00 02 55 00 |..........Y...U.|
+00000040 02 52 00 02 4f 30 82 02 4b 30 82 01 b4 a0 03 02 |.R..O0..K0......|
+00000050 01 02 02 09 00 e8 f0 9d 3f e2 5b ea a6 30 0d 06 |........?.[..0..|
+00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 1f 31 0b |.*.H........0.1.|
+00000070 30 09 06 03 55 04 0a 13 02 47 6f 31 10 30 0e 06 |0...U....Go1.0..|
+00000080 03 55 04 03 13 07 47 6f 20 52 6f 6f 74 30 1e 17 |.U....Go Root0..|
+00000090 0d 31 36 30 31 30 31 30 30 30 30 30 30 5a 17 0d |.160101000000Z..|
+000000a0 32 35 30 31 30 31 30 30 30 30 30 30 5a 30 1a 31 |250101000000Z0.1|
+000000b0 0b 30 09 06 03 55 04 0a 13 02 47 6f 31 0b 30 09 |.0...U....Go1.0.|
+000000c0 06 03 55 04 03 13 02 47 6f 30 81 9f 30 0d 06 09 |..U....Go0..0...|
+000000d0 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 30 |*.H............0|
+000000e0 81 89 02 81 81 00 db 46 7d 93 2e 12 27 06 48 bc |.......F}...'.H.|
+000000f0 06 28 21 ab 7e c4 b6 a2 5d fe 1e 52 45 88 7a 36 |.(!.~...]..RE.z6|
+00000100 47 a5 08 0d 92 42 5b c2 81 c0 be 97 79 98 40 fb |G....B[.....y. at .|
+00000110 4f 6d 14 fd 2b 13 8b c2 a5 2e 67 d8 d4 09 9e d6 |Om..+.....g.....|
+00000120 22 38 b7 4a 0b 74 73 2b c2 34 f1 d1 93 e5 96 d9 |"8.J.ts+.4......|
+00000130 74 7b f3 58 9f 6c 61 3c c0 b0 41 d4 d9 2b 2b 24 |t{.X.la<..A..++$|
+00000140 23 77 5b 1c 3b bd 75 5d ce 20 54 cf a1 63 87 1d |#w[.;.u]. T..c..|
+00000150 1e 24 c4 f3 1d 1a 50 8b aa b6 14 43 ed 97 a7 75 |.$....P....C...u|
+00000160 62 f4 14 c8 52 d7 02 03 01 00 01 a3 81 93 30 81 |b...R.........0.|
+00000170 90 30 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 05 |.0...U..........|
+00000180 a0 30 1d 06 03 55 1d 25 04 16 30 14 06 08 2b 06 |.0...U.%..0...+.|
+00000190 01 05 05 07 03 01 06 08 2b 06 01 05 05 07 03 02 |........+.......|
+000001a0 30 0c 06 03 55 1d 13 01 01 ff 04 02 30 00 30 19 |0...U.......0.0.|
+000001b0 06 03 55 1d 0e 04 12 04 10 9f 91 16 1f 43 43 3e |..U..........CC>|
+000001c0 49 a6 de 6d b6 80 d7 9f 60 30 1b 06 03 55 1d 23 |I..m....`0...U.#|
+000001d0 04 14 30 12 80 10 48 13 49 4d 13 7e 16 31 bb a3 |..0...H.IM.~.1..|
+000001e0 01 d5 ac ab 6e 7b 30 19 06 03 55 1d 11 04 12 30 |....n{0...U....0|
+000001f0 10 82 0e 65 78 61 6d 70 6c 65 2e 67 6f 6c 61 6e |...example.golan|
+00000200 67 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 |g0...*.H........|
+00000210 03 81 81 00 9d 30 cc 40 2b 5b 50 a0 61 cb ba e5 |.....0. at +[P.a...|
+00000220 53 58 e1 ed 83 28 a9 58 1a a9 38 a4 95 a1 ac 31 |SX...(.X..8....1|
+00000230 5a 1a 84 66 3d 43 d3 2d d9 0b f2 97 df d3 20 64 |Z..f=C.-...... d|
+00000240 38 92 24 3a 00 bc cf 9c 7d b7 40 20 01 5f aa d3 |8.$:....}.@ ._..|
+00000250 16 61 09 a2 76 fd 13 c3 cc e1 0c 5c ee b1 87 82 |.a..v......\....|
+00000260 f1 6c 04 ed 73 bb b3 43 77 8d 0c 1c f1 0f a1 d8 |.l..s..Cw.......|
+00000270 40 83 61 c9 4c 72 2b 9d ae db 46 06 06 4d f4 c1 |@.a.Lr+...F..M..|
+00000280 b3 3e c0 d1 bd 42 d4 db fe 3d 13 60 84 5c 21 d3 |.>...B...=.`.\!.|
+00000290 3b e9 fa e7 16 03 03 00 04 0e 00 00 00 |;............|
>>> Flow 3 (client to server)
-00000000 16 03 03 00 86 10 00 00 82 00 80 4d c2 e0 9b 40 |...........M...@|
-00000010 44 52 aa 55 06 71 0b bc 17 89 3a 94 d8 d0 1d ed |DR.U.q....:.....|
-00000020 70 d3 21 30 1b be 97 e0 72 30 60 05 de 9a a9 dd |p.!0....r0`.....|
-00000030 8c 0c 81 78 3a 15 9c 1c c6 22 81 0a 10 57 d1 9a |...x:...."...W..|
-00000040 17 5c 74 9e 58 79 4b f1 70 d9 d9 21 d8 79 64 fa |.\t.XyK.p..!.yd.|
-00000050 aa a5 e6 93 2a 16 57 23 a7 17 fb 71 b6 c2 d3 5b |....*.W#...q...[|
-00000060 3d 22 50 16 47 17 5f 15 e8 f1 30 da 10 69 84 25 |="P.G._...0..i.%|
-00000070 05 d0 b5 f0 e8 69 72 4e 93 d3 7c 1a 01 6d 37 fb |.....irN..|..m7.|
-00000080 cf e1 af f9 da dd 71 56 9b 08 24 14 03 03 00 01 |......qV..$.....|
-00000090 01 16 03 03 00 30 53 ab b5 09 5a 36 36 df b1 ed |.....0S...Z66...|
-000000a0 d2 69 5c 45 0b a9 02 8f 6d 25 d4 01 da 5f 27 ab |.i\E....m%..._'.|
-000000b0 ba 89 6e ee d8 91 24 f8 5e ca 6e 4d 51 41 88 3c |..n...$.^.nMQA.<|
-000000c0 f8 67 b4 fb d3 cb |.g....|
+00000000 16 03 03 00 86 10 00 00 82 00 80 04 90 54 41 b9 |.............TA.|
+00000010 22 12 39 d9 1d 0b b8 6c d4 b3 8a ec 78 42 80 a5 |".9....l....xB..|
+00000020 03 c9 2a 9e 95 6f a0 28 3a 5c e9 59 28 ba 49 9b |..*..o.(:\.Y(.I.|
+00000030 37 63 61 3f c4 ac ba 55 6b 85 a5 27 ed 37 b9 25 |7ca?...Uk..'.7.%|
+00000040 04 cf 84 ad 43 6b ab 13 fa 72 29 b8 01 d9 aa 0c |....Ck...r).....|
+00000050 be b1 9a c4 5a 05 3d 2d 71 b4 72 f5 3a 77 fb 6b |....Z.=-q.r.:w.k|
+00000060 45 b0 5b 00 f8 1e f9 70 7f a4 64 c9 1e 35 56 0b |E.[....p..d..5V.|
+00000070 68 07 4c 04 95 f4 ca b1 0a b3 25 2b 93 2d be 80 |h.L.......%+.-..|
+00000080 76 15 75 07 23 ee 25 f3 1b a8 2f 14 03 03 00 01 |v.u.#.%.../.....|
+00000090 01 16 03 03 00 30 e5 cd 56 75 e6 a4 58 e5 33 cc |.....0..Vu..X.3.|
+000000a0 95 23 e0 7f 01 f2 45 21 bb 7d 7c 17 1f 59 7c f9 |.#....E!.}|..Y|.|
+000000b0 38 05 a3 95 4d 9b f2 3f 9d 84 2c 31 15 8b 4d d4 |8...M..?..,1..M.|
+000000c0 17 3c 62 2b f6 71 |.<b+.q|
>>> Flow 4 (server to client)
00000000 14 03 03 00 01 01 16 03 03 00 30 00 00 00 00 00 |..........0.....|
-00000010 00 00 00 50 83 52 65 2d 6e 76 aa 8d 2d 46 06 12 |...P.Re-nv..-F..|
-00000020 1a e7 25 79 28 61 9e 2d 07 0b fb 3c 77 38 d8 b0 |..%y(a.-...<w8..|
-00000030 af ca 86 8a 51 07 4d 83 39 81 9b 17 03 03 00 30 |....Q.M.9......0|
-00000040 00 00 00 00 00 00 00 00 a1 ea 74 b2 7b fc 3f 9d |..........t.{.?.|
-00000050 bc eb 9d 09 a2 56 4a ff d4 fd 00 23 0b e6 69 62 |.....VJ....#..ib|
-00000060 0e 4c 82 43 3f 21 8f b8 fd 5c ce 37 6c 57 d2 98 |.L.C?!...\.7lW..|
-00000070 15 03 03 00 20 00 00 00 00 00 00 00 00 dc 47 cc |.... .........G.|
-00000080 34 eb 9e 7f d0 8f 5a 32 e6 6d 76 15 18 cc 8d 21 |4.....Z2.mv....!|
-00000090 43 91 81 31 81 |C..1.|
+00000010 00 00 00 b3 85 c2 1b ac 9e c2 01 f7 0f 76 6d 09 |.............vm.|
+00000020 5c 4f 9f a6 89 1b 56 e3 05 0b 7e 0d 9d 6b 36 35 |\O....V...~..k65|
+00000030 49 99 aa 4c 14 3b 69 2a 87 71 7d 17 03 03 00 30 |I..L.;i*.q}....0|
+00000040 00 00 00 00 00 00 00 00 15 65 d4 be e5 1b c9 29 |.........e.....)|
+00000050 e9 3a c4 22 72 f8 0c 40 c7 f5 45 a1 a3 c8 a8 64 |.:."r.. at ..E....d|
+00000060 22 4c 6c 79 3f 32 66 d4 05 09 a8 d4 d8 a8 f3 c7 |"Lly?2f.........|
+00000070 15 03 03 00 20 00 00 00 00 00 00 00 00 fc 8d c6 |.... ...........|
+00000080 3d b1 c4 9f 30 26 e3 b9 46 8f ce 9f 7e 5b 1e a3 |=...0&..F...~[..|
+00000090 d0 98 64 3c 0d |..d<.|
diff --git a/src/crypto/tls/testdata/Server-TLSv12-RSA-AES b/src/crypto/tls/testdata/Server-TLSv12-RSA-AES
index 66155e7..813f748 100644
--- a/src/crypto/tls/testdata/Server-TLSv12-RSA-AES
+++ b/src/crypto/tls/testdata/Server-TLSv12-RSA-AES
@@ -1,81 +1,80 @@
>>> Flow 1 (client to server)
-00000000 16 03 01 00 5b 01 00 00 57 03 03 5a ba 29 44 35 |....[...W..Z.)D5|
-00000010 c4 48 64 61 06 84 70 5c b5 65 ad 01 9b b2 29 0d |.Hda..p\.e....).|
-00000020 d1 46 17 3a 27 fb 92 d8 aa 21 aa 00 00 04 00 2f |.F.:'....!...../|
-00000030 00 ff 02 01 00 00 29 00 0d 00 20 00 1e 06 01 06 |......)... .....|
-00000040 02 06 03 05 01 05 02 05 03 04 01 04 02 04 03 03 |................|
-00000050 01 03 02 03 03 02 01 02 02 02 03 00 0f 00 01 01 |................|
+00000000 16 03 01 00 5d 01 00 00 59 03 03 7a e5 86 e2 0a |....]...Y..z....|
+00000010 53 e7 ba 32 d1 57 47 ed 45 29 1b 33 2c 58 33 8f |S..2.WG.E).3,X3.|
+00000020 36 2c 50 6f f9 c7 3b 12 40 23 e2 00 00 04 00 2f |6,Po..;.@#...../|
+00000030 00 ff 01 00 00 2c 00 0d 00 20 00 1e 06 01 06 02 |.....,... ......|
+00000040 06 03 05 01 05 02 05 03 04 01 04 02 04 03 03 01 |................|
+00000050 03 02 03 03 02 01 02 02 02 03 00 16 00 00 00 17 |................|
+00000060 00 00 |..|
>>> Flow 2 (server to client)
00000000 16 03 03 00 31 02 00 00 2d 03 03 00 00 00 00 00 |....1...-.......|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2f 00 00 |............./..|
-00000030 05 ff 01 00 01 00 16 03 03 02 71 0b 00 02 6d 00 |..........q...m.|
-00000040 02 6a 00 02 67 30 82 02 63 30 82 01 cc a0 03 02 |.j..g0..c0......|
-00000050 01 02 02 09 00 a2 73 00 0c 81 00 cb f3 30 0d 06 |......s......0..|
-00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 2b 31 17 |.*.H........0+1.|
-00000070 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 |0...U....Google |
-00000080 54 45 53 54 49 4e 47 31 10 30 0e 06 03 55 04 03 |TESTING1.0...U..|
-00000090 13 07 47 6f 20 52 6f 6f 74 30 1e 17 0d 31 35 30 |..Go Root0...150|
-000000a0 31 30 31 30 30 30 30 30 30 5a 17 0d 32 35 30 31 |101000000Z..2501|
-000000b0 30 31 30 30 30 30 30 30 5a 30 26 31 17 30 15 06 |01000000Z0&1.0..|
-000000c0 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 54 45 53 |.U....Google TES|
-000000d0 54 49 4e 47 31 0b 30 09 06 03 55 04 03 13 02 47 |TING1.0...U....G|
-000000e0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....|
-000000f0 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 af 87 |.......0........|
-00000100 88 f6 20 1b 95 65 6c 14 ab 44 05 af 3b 45 14 e3 |.. ..el..D..;E..|
-00000110 b7 6d fd 00 63 4d 95 7f fe 6a 62 35 86 c0 4a f9 |.m..cM...jb5..J.|
-00000120 18 7c f6 aa 25 5e 7a 64 31 66 00 ba f4 8e 92 af |.|..%^zd1f......|
-00000130 c7 6b d8 76 d4 f3 5f 41 cb 6e 56 15 97 1b 97 c1 |.k.v.._A.nV.....|
-00000140 3c 12 39 21 66 3d 2b 16 d1 bc db 1c c0 a7 da b7 |<.9!f=+.........|
-00000150 ca ad ba da cb d5 21 50 ec de 8d ab d1 6b 81 4b |......!P.....k.K|
-00000160 89 02 f3 c4 be c1 6c 89 b1 44 84 bd 21 d1 04 7d |......l..D..!..}|
-00000170 9d 16 4d f9 82 15 f6 ef fa d6 09 47 f2 fb 02 03 |..M........G....|
-00000180 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..|
-00000190 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%|
-000001a0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........|
-000001b0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...|
-000001c0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....|
-000001d0 10 12 50 8d 89 6f 1b d1 dc 54 4d 6e cb 69 5e 06 |..P..o...TMn.i^.|
-000001e0 f4 30 1b 06 03 55 1d 23 04 14 30 12 80 10 bf 3d |.0...U.#..0....=|
-000001f0 b6 a9 66 f2 b8 40 cf ea b4 03 78 48 1a 41 30 19 |..f.. at ....xH.A0.|
-00000200 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp|
-00000210 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H|
-00000220 86 f7 0d 01 01 0b 05 00 03 81 81 00 92 7c af 91 |.............|..|
-00000230 55 12 18 96 59 31 a6 48 40 d5 2d d5 ee bb 02 a0 |U...Y1.H at .-.....|
-00000240 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 da 4f 3d c0 fa |...|..0}<.v.O=..|
-00000250 ae 2d 33 24 6b 03 7b 1b 67 59 11 21 b5 11 bc 77 |.-3$k.{.gY.!...w|
-00000260 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f 22 3e 63 10 6b |...n.-.5.d_">c.k|
-00000270 be ff 14 86 6d 0d f0 15 31 a8 14 38 1e 3b 84 87 |....m...1..8.;..|
-00000280 2c cb 98 ed 51 76 b9 b1 4f dd db 9b 84 04 86 40 |,...Qv..O......@|
-00000290 fa 51 dd ba b4 8d eb e3 46 de 46 b9 4f 86 c7 f9 |.Q......F.F.O...|
-000002a0 a4 c2 41 34 ac cc f6 ea b0 ab 39 18 16 03 03 00 |..A4......9.....|
-000002b0 04 0e 00 00 00 |.....|
+00000030 05 ff 01 00 01 00 16 03 03 02 59 0b 00 02 55 00 |..........Y...U.|
+00000040 02 52 00 02 4f 30 82 02 4b 30 82 01 b4 a0 03 02 |.R..O0..K0......|
+00000050 01 02 02 09 00 e8 f0 9d 3f e2 5b ea a6 30 0d 06 |........?.[..0..|
+00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 1f 31 0b |.*.H........0.1.|
+00000070 30 09 06 03 55 04 0a 13 02 47 6f 31 10 30 0e 06 |0...U....Go1.0..|
+00000080 03 55 04 03 13 07 47 6f 20 52 6f 6f 74 30 1e 17 |.U....Go Root0..|
+00000090 0d 31 36 30 31 30 31 30 30 30 30 30 30 5a 17 0d |.160101000000Z..|
+000000a0 32 35 30 31 30 31 30 30 30 30 30 30 5a 30 1a 31 |250101000000Z0.1|
+000000b0 0b 30 09 06 03 55 04 0a 13 02 47 6f 31 0b 30 09 |.0...U....Go1.0.|
+000000c0 06 03 55 04 03 13 02 47 6f 30 81 9f 30 0d 06 09 |..U....Go0..0...|
+000000d0 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 30 |*.H............0|
+000000e0 81 89 02 81 81 00 db 46 7d 93 2e 12 27 06 48 bc |.......F}...'.H.|
+000000f0 06 28 21 ab 7e c4 b6 a2 5d fe 1e 52 45 88 7a 36 |.(!.~...]..RE.z6|
+00000100 47 a5 08 0d 92 42 5b c2 81 c0 be 97 79 98 40 fb |G....B[.....y. at .|
+00000110 4f 6d 14 fd 2b 13 8b c2 a5 2e 67 d8 d4 09 9e d6 |Om..+.....g.....|
+00000120 22 38 b7 4a 0b 74 73 2b c2 34 f1 d1 93 e5 96 d9 |"8.J.ts+.4......|
+00000130 74 7b f3 58 9f 6c 61 3c c0 b0 41 d4 d9 2b 2b 24 |t{.X.la<..A..++$|
+00000140 23 77 5b 1c 3b bd 75 5d ce 20 54 cf a1 63 87 1d |#w[.;.u]. T..c..|
+00000150 1e 24 c4 f3 1d 1a 50 8b aa b6 14 43 ed 97 a7 75 |.$....P....C...u|
+00000160 62 f4 14 c8 52 d7 02 03 01 00 01 a3 81 93 30 81 |b...R.........0.|
+00000170 90 30 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 05 |.0...U..........|
+00000180 a0 30 1d 06 03 55 1d 25 04 16 30 14 06 08 2b 06 |.0...U.%..0...+.|
+00000190 01 05 05 07 03 01 06 08 2b 06 01 05 05 07 03 02 |........+.......|
+000001a0 30 0c 06 03 55 1d 13 01 01 ff 04 02 30 00 30 19 |0...U.......0.0.|
+000001b0 06 03 55 1d 0e 04 12 04 10 9f 91 16 1f 43 43 3e |..U..........CC>|
+000001c0 49 a6 de 6d b6 80 d7 9f 60 30 1b 06 03 55 1d 23 |I..m....`0...U.#|
+000001d0 04 14 30 12 80 10 48 13 49 4d 13 7e 16 31 bb a3 |..0...H.IM.~.1..|
+000001e0 01 d5 ac ab 6e 7b 30 19 06 03 55 1d 11 04 12 30 |....n{0...U....0|
+000001f0 10 82 0e 65 78 61 6d 70 6c 65 2e 67 6f 6c 61 6e |...example.golan|
+00000200 67 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 |g0...*.H........|
+00000210 03 81 81 00 9d 30 cc 40 2b 5b 50 a0 61 cb ba e5 |.....0. at +[P.a...|
+00000220 53 58 e1 ed 83 28 a9 58 1a a9 38 a4 95 a1 ac 31 |SX...(.X..8....1|
+00000230 5a 1a 84 66 3d 43 d3 2d d9 0b f2 97 df d3 20 64 |Z..f=C.-...... d|
+00000240 38 92 24 3a 00 bc cf 9c 7d b7 40 20 01 5f aa d3 |8.$:....}.@ ._..|
+00000250 16 61 09 a2 76 fd 13 c3 cc e1 0c 5c ee b1 87 82 |.a..v......\....|
+00000260 f1 6c 04 ed 73 bb b3 43 77 8d 0c 1c f1 0f a1 d8 |.l..s..Cw.......|
+00000270 40 83 61 c9 4c 72 2b 9d ae db 46 06 06 4d f4 c1 |@.a.Lr+...F..M..|
+00000280 b3 3e c0 d1 bd 42 d4 db fe 3d 13 60 84 5c 21 d3 |.>...B...=.`.\!.|
+00000290 3b e9 fa e7 16 03 03 00 04 0e 00 00 00 |;............|
>>> Flow 3 (client to server)
-00000000 16 03 03 00 86 10 00 00 82 00 80 ad e8 09 aa 07 |................|
-00000010 c0 3c 8b 39 d2 a8 bd ca 59 eb cf 0a de 33 3e d2 |.<.9....Y....3>.|
-00000020 4f 76 1f 7a 96 50 b3 52 6b 04 9e 6f f1 06 2b 4a |Ov.z.P.Rk..o..+J|
-00000030 7f 01 f2 51 a3 a7 1e f6 20 a7 27 4e 97 68 61 98 |...Q.... .'N.ha.|
-00000040 9f fd bd aa e8 e6 80 4d 9a 65 51 35 11 44 e4 2c |.......M.eQ5.D.,|
-00000050 a2 47 33 d1 b6 b7 d5 40 c0 17 34 ff e2 12 8e 00 |.G3.... at ..4.....|
-00000060 41 e6 4f 3e 56 2f d9 30 6b d9 99 e3 9f ce 10 ba |A.O>V/.0k.......|
-00000070 7c 95 3b 49 c9 5f 1e 97 37 90 e4 da 9a e0 01 5f ||.;I._..7......_|
-00000080 b8 6f 95 19 40 0f ca 63 76 6b 2a 14 03 03 00 01 |.o.. at ..cvk*.....|
-00000090 01 16 03 03 00 40 86 cb f5 69 1b ee 67 6e 3b be |..... at ...i..gn;.|
-000000a0 e0 de 22 06 8c d4 f4 98 a6 45 1c 2f e5 f0 b4 25 |.."......E./...%|
-000000b0 f4 c0 87 7f e8 1c 2c 1d 20 52 50 fe dc a3 0c 22 |......,. RP...."|
-000000c0 b7 7f d3 9c 42 b8 23 d0 3e fd 93 be a2 50 28 dd |....B.#.>....P(.|
-000000d0 79 f3 c6 90 c7 bb |y.....|
+00000000 16 03 03 00 86 10 00 00 82 00 80 8f 13 d1 23 1b |..............#.|
+00000010 8d 28 c7 a3 97 66 9f 8a c1 13 a1 c9 3b 25 93 7a |.(...f......;%.z|
+00000020 ea 54 58 fc 57 41 ca 92 77 99 13 01 61 e4 73 90 |.TX.WA..w...a.s.|
+00000030 c7 f1 2b 5e 5e 79 cf 69 7d 6b 3f 6e 5f 2e b0 f5 |..+^^y.i}k?n_...|
+00000040 f7 53 2b 46 15 92 6c 20 95 6b 44 6a 0a 3d 0b 56 |.S+F..l .kDj.=.V|
+00000050 66 53 ff 55 ec 38 10 cf 76 2c 0e ab 45 7a 02 6a |fS.U.8..v,..Ez.j|
+00000060 75 07 11 80 6c d0 57 79 ed d6 4b b8 a0 04 91 a0 |u...l.Wy..K.....|
+00000070 d4 4b 76 38 9c b3 a6 2e 0c 3e 63 a8 18 15 c9 ab |.Kv8.....>c.....|
+00000080 54 69 cd e5 6f 3c 56 a6 5f a7 e0 14 03 03 00 01 |Ti..o<V._.......|
+00000090 01 16 03 03 00 40 06 07 16 b4 7f fa 1a 8f 9b 1a |..... at ..........|
+000000a0 a3 23 ba 5f ce ff 0a 70 b1 11 2b 84 77 7a 78 1a |.#._...p..+.wzx.|
+000000b0 6c 32 93 6c 31 e8 e5 26 12 97 14 33 a9 77 71 19 |l2.l1..&...3.wq.|
+000000c0 0b 20 5d 8f 3c 71 0d a4 b9 94 aa ff 42 8e d3 2d |. ].<q......B..-|
+000000d0 7e 57 3b 35 41 cc |~W;5A.|
>>> Flow 4 (server to client)
00000000 14 03 03 00 01 01 16 03 03 00 40 00 00 00 00 00 |.......... at .....|
-00000010 00 00 00 00 00 00 00 00 00 00 00 70 e5 19 ef 25 |...........p...%|
-00000020 05 0b 02 79 2b 79 49 e6 2c ad c0 e7 03 b3 40 68 |...y+yI.,..... at h|
-00000030 67 98 31 7c 7e 85 86 a8 5c de 72 3f d1 59 12 20 |g.1|~...\.r?.Y. |
-00000040 87 95 44 57 64 35 03 f5 68 61 20 17 03 03 00 40 |..DWd5..ha ....@|
+00000010 00 00 00 00 00 00 00 00 00 00 00 51 27 cd 07 6e |...........Q'..n|
+00000020 72 c8 17 ba e7 62 7c d0 49 55 e7 e6 c5 2c 93 39 |r....b|.IU...,.9|
+00000030 55 02 f5 fa 9a 7a 6f c5 79 6f ff 0f 4b b9 3d ad |U....zo.yo..K.=.|
+00000040 23 c7 53 ad 13 2d d6 da 83 d0 67 17 03 03 00 40 |#.S..-....g....@|
00000050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
-00000060 1b 17 7c bb 04 4f 31 7b da 40 5e 93 64 97 4a 8d |..|..O1{.@^.d.J.|
-00000070 98 cf 77 2d 01 53 37 53 2c 59 8f ca ac 65 ae f3 |..w-.S7S,Y...e..|
-00000080 f8 d4 ae 67 74 c8 72 21 67 51 9a 1b 71 f2 0e 04 |...gt.r!gQ..q...|
+00000060 f5 09 3b 69 c2 1f f8 03 78 1b 13 57 ca 92 96 eb |..;i....x..W....|
+00000070 f8 71 30 09 5a 68 01 47 96 b1 5b 7d b7 57 5e 70 |.q0.Zh.G..[}.W^p|
+00000080 00 77 bb 55 32 7b d9 a5 f7 e2 a8 6d 4b d6 be c6 |.w.U2{.....mK...|
00000090 15 03 03 00 30 00 00 00 00 00 00 00 00 00 00 00 |....0...........|
-000000a0 00 00 00 00 00 fd 36 99 3d c7 44 1b 30 39 4a a7 |......6.=.D.09J.|
-000000b0 40 43 e3 01 2b 22 3d c6 8c a1 0d 73 d5 16 d2 25 |@C..+"=....s...%|
-000000c0 19 c8 d7 76 ee |...v.|
+000000a0 00 00 00 00 00 58 1e a0 14 82 8d e4 c5 92 35 79 |.....X........5y|
+000000b0 3b 5e 3a fe 97 18 db 27 19 7e b5 14 8c 01 fb 6a |;^:....'.~.....j|
+000000c0 e4 26 96 e6 de |.&...|
diff --git a/src/crypto/tls/testdata/Server-TLSv12-RSA-AES-GCM b/src/crypto/tls/testdata/Server-TLSv12-RSA-AES-GCM
index a6e7a07..4e52915 100644
--- a/src/crypto/tls/testdata/Server-TLSv12-RSA-AES-GCM
+++ b/src/crypto/tls/testdata/Server-TLSv12-RSA-AES-GCM
@@ -1,86 +1,79 @@
>>> Flow 1 (client to server)
-00000000 16 03 01 00 83 01 00 00 7f 03 03 19 c7 02 a0 bf |................|
-00000010 5a fb c2 d4 f5 68 0a 19 0f 5e 3a 6b c5 88 17 0b |Z....h...^:k....|
-00000020 35 ff df ee 06 32 ad 32 99 0e c9 00 00 04 c0 2f |5....2.2......./|
-00000030 00 ff 02 01 00 00 51 00 0b 00 04 03 00 01 02 00 |......Q.........|
-00000040 0a 00 1c 00 1a 00 17 00 19 00 1c 00 1b 00 18 00 |................|
-00000050 1a 00 16 00 0e 00 0d 00 0b 00 0c 00 09 00 0a 00 |................|
-00000060 0d 00 20 00 1e 06 01 06 02 06 03 05 01 05 02 05 |.. .............|
-00000070 03 04 01 04 02 04 03 03 01 03 02 03 03 02 01 02 |................|
-00000080 02 02 03 00 0f 00 01 01 |........|
+00000000 16 03 01 00 73 01 00 00 6f 03 03 4e 1a d7 67 e4 |....s...o..N..g.|
+00000010 d1 11 85 bc 62 59 da 8f ea d0 a0 2b 9b d3 47 aa |....bY.....+..G.|
+00000020 d0 39 6f 3f 42 dc 7c 16 bb 25 ef 00 00 04 c0 2f |.9o?B.|..%...../|
+00000030 00 ff 01 00 00 42 00 0b 00 04 03 00 01 02 00 0a |.....B..........|
+00000040 00 0a 00 08 00 1d 00 17 00 19 00 18 00 0d 00 20 |............... |
+00000050 00 1e 06 01 06 02 06 03 05 01 05 02 05 03 04 01 |................|
+00000060 04 02 04 03 03 01 03 02 03 03 02 01 02 02 02 03 |................|
+00000070 00 16 00 00 00 17 00 00 |........|
>>> Flow 2 (server to client)
00000000 16 03 03 00 31 02 00 00 2d 03 03 00 00 00 00 00 |....1...-.......|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000020 00 00 00 00 00 00 00 00 00 00 00 00 c0 2f 00 00 |............./..|
-00000030 05 ff 01 00 01 00 16 03 03 02 71 0b 00 02 6d 00 |..........q...m.|
-00000040 02 6a 00 02 67 30 82 02 63 30 82 01 cc a0 03 02 |.j..g0..c0......|
-00000050 01 02 02 09 00 a2 73 00 0c 81 00 cb f3 30 0d 06 |......s......0..|
-00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 2b 31 17 |.*.H........0+1.|
-00000070 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 |0...U....Google |
-00000080 54 45 53 54 49 4e 47 31 10 30 0e 06 03 55 04 03 |TESTING1.0...U..|
-00000090 13 07 47 6f 20 52 6f 6f 74 30 1e 17 0d 31 35 30 |..Go Root0...150|
-000000a0 31 30 31 30 30 30 30 30 30 5a 17 0d 32 35 30 31 |101000000Z..2501|
-000000b0 30 31 30 30 30 30 30 30 5a 30 26 31 17 30 15 06 |01000000Z0&1.0..|
-000000c0 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 54 45 53 |.U....Google TES|
-000000d0 54 49 4e 47 31 0b 30 09 06 03 55 04 03 13 02 47 |TING1.0...U....G|
-000000e0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....|
-000000f0 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 af 87 |.......0........|
-00000100 88 f6 20 1b 95 65 6c 14 ab 44 05 af 3b 45 14 e3 |.. ..el..D..;E..|
-00000110 b7 6d fd 00 63 4d 95 7f fe 6a 62 35 86 c0 4a f9 |.m..cM...jb5..J.|
-00000120 18 7c f6 aa 25 5e 7a 64 31 66 00 ba f4 8e 92 af |.|..%^zd1f......|
-00000130 c7 6b d8 76 d4 f3 5f 41 cb 6e 56 15 97 1b 97 c1 |.k.v.._A.nV.....|
-00000140 3c 12 39 21 66 3d 2b 16 d1 bc db 1c c0 a7 da b7 |<.9!f=+.........|
-00000150 ca ad ba da cb d5 21 50 ec de 8d ab d1 6b 81 4b |......!P.....k.K|
-00000160 89 02 f3 c4 be c1 6c 89 b1 44 84 bd 21 d1 04 7d |......l..D..!..}|
-00000170 9d 16 4d f9 82 15 f6 ef fa d6 09 47 f2 fb 02 03 |..M........G....|
-00000180 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..|
-00000190 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%|
-000001a0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........|
-000001b0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...|
-000001c0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....|
-000001d0 10 12 50 8d 89 6f 1b d1 dc 54 4d 6e cb 69 5e 06 |..P..o...TMn.i^.|
-000001e0 f4 30 1b 06 03 55 1d 23 04 14 30 12 80 10 bf 3d |.0...U.#..0....=|
-000001f0 b6 a9 66 f2 b8 40 cf ea b4 03 78 48 1a 41 30 19 |..f.. at ....xH.A0.|
-00000200 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp|
-00000210 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H|
-00000220 86 f7 0d 01 01 0b 05 00 03 81 81 00 92 7c af 91 |.............|..|
-00000230 55 12 18 96 59 31 a6 48 40 d5 2d d5 ee bb 02 a0 |U...Y1.H at .-.....|
-00000240 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 da 4f 3d c0 fa |...|..0}<.v.O=..|
-00000250 ae 2d 33 24 6b 03 7b 1b 67 59 11 21 b5 11 bc 77 |.-3$k.{.gY.!...w|
-00000260 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f 22 3e 63 10 6b |...n.-.5.d_">c.k|
-00000270 be ff 14 86 6d 0d f0 15 31 a8 14 38 1e 3b 84 87 |....m...1..8.;..|
-00000280 2c cb 98 ed 51 76 b9 b1 4f dd db 9b 84 04 86 40 |,...Qv..O......@|
-00000290 fa 51 dd ba b4 8d eb e3 46 de 46 b9 4f 86 c7 f9 |.Q......F.F.O...|
-000002a0 a4 c2 41 34 ac cc f6 ea b0 ab 39 18 16 03 03 00 |..A4......9.....|
-000002b0 cd 0c 00 00 c9 03 00 17 41 04 1e 18 37 ef 0d 19 |........A...7...|
-000002c0 51 88 35 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd a7 |Q.5uq..T[....g..|
-000002d0 24 20 3e b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e f1 |$ >.V...(^.+-O..|
-000002e0 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 a6 |..lK[.V.2B.X..I.|
-000002f0 b5 68 1a 41 03 56 6b dc 5a 89 05 01 00 80 97 53 |.h.A.Vk.Z......S|
-00000300 cc 1f a2 55 e2 52 69 a6 b3 78 4f 7e 34 3e 37 e4 |...U.Ri..xO~4>7.|
-00000310 e0 bb 15 ff 96 f8 1d 9c 11 03 2c 68 ca 6d 2b 3c |..........,h.m+<|
-00000320 b3 96 64 21 d6 3f 81 42 07 c0 1b 85 7e a9 65 54 |..d!.?.B....~.eT|
-00000330 23 89 33 c1 71 b9 29 72 47 8a 0e 71 75 20 d7 b6 |#.3.q.)rG..qu ..|
-00000340 9d c2 ac c1 a8 dc 6c 0e 7e 29 93 fc b2 68 83 2e |......l.~)...h..|
-00000350 e1 fe e5 eb 54 d7 c3 30 f2 8f 9d 91 49 48 4f 84 |....T..0....IHO.|
-00000360 1a d5 47 75 27 bf c8 09 65 4a a8 7c 65 a0 d0 23 |..Gu'...eJ.|e..#|
-00000370 9f 26 d6 57 62 cb e1 06 64 90 16 73 1b d4 16 03 |.&.Wb...d..s....|
-00000380 03 00 04 0e 00 00 00 |.......|
+00000030 05 ff 01 00 01 00 16 03 03 02 59 0b 00 02 55 00 |..........Y...U.|
+00000040 02 52 00 02 4f 30 82 02 4b 30 82 01 b4 a0 03 02 |.R..O0..K0......|
+00000050 01 02 02 09 00 e8 f0 9d 3f e2 5b ea a6 30 0d 06 |........?.[..0..|
+00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 1f 31 0b |.*.H........0.1.|
+00000070 30 09 06 03 55 04 0a 13 02 47 6f 31 10 30 0e 06 |0...U....Go1.0..|
+00000080 03 55 04 03 13 07 47 6f 20 52 6f 6f 74 30 1e 17 |.U....Go Root0..|
+00000090 0d 31 36 30 31 30 31 30 30 30 30 30 30 5a 17 0d |.160101000000Z..|
+000000a0 32 35 30 31 30 31 30 30 30 30 30 30 5a 30 1a 31 |250101000000Z0.1|
+000000b0 0b 30 09 06 03 55 04 0a 13 02 47 6f 31 0b 30 09 |.0...U....Go1.0.|
+000000c0 06 03 55 04 03 13 02 47 6f 30 81 9f 30 0d 06 09 |..U....Go0..0...|
+000000d0 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 30 |*.H............0|
+000000e0 81 89 02 81 81 00 db 46 7d 93 2e 12 27 06 48 bc |.......F}...'.H.|
+000000f0 06 28 21 ab 7e c4 b6 a2 5d fe 1e 52 45 88 7a 36 |.(!.~...]..RE.z6|
+00000100 47 a5 08 0d 92 42 5b c2 81 c0 be 97 79 98 40 fb |G....B[.....y. at .|
+00000110 4f 6d 14 fd 2b 13 8b c2 a5 2e 67 d8 d4 09 9e d6 |Om..+.....g.....|
+00000120 22 38 b7 4a 0b 74 73 2b c2 34 f1 d1 93 e5 96 d9 |"8.J.ts+.4......|
+00000130 74 7b f3 58 9f 6c 61 3c c0 b0 41 d4 d9 2b 2b 24 |t{.X.la<..A..++$|
+00000140 23 77 5b 1c 3b bd 75 5d ce 20 54 cf a1 63 87 1d |#w[.;.u]. T..c..|
+00000150 1e 24 c4 f3 1d 1a 50 8b aa b6 14 43 ed 97 a7 75 |.$....P....C...u|
+00000160 62 f4 14 c8 52 d7 02 03 01 00 01 a3 81 93 30 81 |b...R.........0.|
+00000170 90 30 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 05 |.0...U..........|
+00000180 a0 30 1d 06 03 55 1d 25 04 16 30 14 06 08 2b 06 |.0...U.%..0...+.|
+00000190 01 05 05 07 03 01 06 08 2b 06 01 05 05 07 03 02 |........+.......|
+000001a0 30 0c 06 03 55 1d 13 01 01 ff 04 02 30 00 30 19 |0...U.......0.0.|
+000001b0 06 03 55 1d 0e 04 12 04 10 9f 91 16 1f 43 43 3e |..U..........CC>|
+000001c0 49 a6 de 6d b6 80 d7 9f 60 30 1b 06 03 55 1d 23 |I..m....`0...U.#|
+000001d0 04 14 30 12 80 10 48 13 49 4d 13 7e 16 31 bb a3 |..0...H.IM.~.1..|
+000001e0 01 d5 ac ab 6e 7b 30 19 06 03 55 1d 11 04 12 30 |....n{0...U....0|
+000001f0 10 82 0e 65 78 61 6d 70 6c 65 2e 67 6f 6c 61 6e |...example.golan|
+00000200 67 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 |g0...*.H........|
+00000210 03 81 81 00 9d 30 cc 40 2b 5b 50 a0 61 cb ba e5 |.....0. at +[P.a...|
+00000220 53 58 e1 ed 83 28 a9 58 1a a9 38 a4 95 a1 ac 31 |SX...(.X..8....1|
+00000230 5a 1a 84 66 3d 43 d3 2d d9 0b f2 97 df d3 20 64 |Z..f=C.-...... d|
+00000240 38 92 24 3a 00 bc cf 9c 7d b7 40 20 01 5f aa d3 |8.$:....}.@ ._..|
+00000250 16 61 09 a2 76 fd 13 c3 cc e1 0c 5c ee b1 87 82 |.a..v......\....|
+00000260 f1 6c 04 ed 73 bb b3 43 77 8d 0c 1c f1 0f a1 d8 |.l..s..Cw.......|
+00000270 40 83 61 c9 4c 72 2b 9d ae db 46 06 06 4d f4 c1 |@.a.Lr+...F..M..|
+00000280 b3 3e c0 d1 bd 42 d4 db fe 3d 13 60 84 5c 21 d3 |.>...B...=.`.\!.|
+00000290 3b e9 fa e7 16 03 03 00 ac 0c 00 00 a8 03 00 1d |;...............|
+000002a0 20 2f e5 7d a3 47 cd 62 43 15 28 da ac 5f bb 29 | /.}.G.bC.(.._.)|
+000002b0 07 30 ff f6 84 af c4 cf c2 ed 90 99 5f 58 cb 3b |.0.........._X.;|
+000002c0 74 05 01 00 80 b2 49 30 60 b7 0c 48 cb 9f 1c 75 |t.....I0`..H...u|
+000002d0 a6 b0 b0 7b 5e e6 f9 bc 5a 49 d4 51 e2 76 4c 01 |...{^...ZI.Q.vL.|
+000002e0 55 bd 37 cf 86 75 4f 33 9b fd 3c fc bb da 81 a9 |U.7..uO3..<.....|
+000002f0 26 7b 82 31 c5 51 0f d4 e8 fa a3 16 45 19 c8 40 |&{.1.Q......E..@|
+00000300 23 fa 32 bc 05 36 fb a7 a2 d9 6f e7 bc b8 27 0b |#.2..6....o...'.|
+00000310 2a 9e 7b 95 fd b4 c0 2e f0 73 fe fb a2 ea 20 a2 |*.{......s.... .|
+00000320 73 73 96 c8 bc 82 58 09 84 fc f4 09 2a c8 68 cb |ss....X.....*.h.|
+00000330 66 b0 de 2c 78 7a d4 ec 06 f1 1c 52 03 5a 69 24 |f..,xz.....R.Zi$|
+00000340 c4 e6 bb 68 f4 16 03 03 00 04 0e 00 00 00 |...h..........|
>>> Flow 3 (client to server)
-00000000 16 03 03 00 46 10 00 00 42 41 04 1a 94 a7 1a 36 |....F...BA.....6|
-00000010 d1 ca ad d7 e8 64 03 84 b4 a6 9f dc 30 a2 a3 60 |.....d......0..`|
-00000020 a0 5a 1f a0 3d 8e d1 b8 96 75 37 ee a6 3f d6 ad |.Z..=....u7..?..|
-00000030 93 b6 7d 58 99 53 04 4b 6e c6 7f 04 bf 60 f9 ba |..}X.S.Kn....`..|
-00000040 e7 b8 04 73 10 77 ff 22 93 b2 7b 14 03 03 00 01 |...s.w."..{.....|
-00000050 01 16 03 03 00 28 29 6b 2b 14 21 a7 e4 84 c0 9d |.....()k+.!.....|
-00000060 92 07 cd dd 0b eb c1 b0 76 06 71 48 46 93 b8 05 |........v.qHF...|
-00000070 1a 2b 53 14 da 34 ac 05 4c cc 4d 47 12 28 |.+S..4..L.MG.(|
+00000000 16 03 03 00 25 10 00 00 21 20 41 d4 8d 53 2e 47 |....%...! A..S.G|
+00000010 b8 35 ba 86 3c 41 07 2e c1 a0 9d c2 e9 11 d8 20 |.5..<A......... |
+00000020 a1 fa 0a ff 28 64 5b af c3 67 14 03 03 00 01 01 |....(d[..g......|
+00000030 16 03 03 00 28 78 fd 19 36 4d a7 ca ab ba 06 6b |....(x..6M.....k|
+00000040 3f a5 79 17 2f 2b ec f6 19 db 17 1a 52 ea 72 0b |?.y./+......R.r.|
+00000050 01 af 56 8b 14 8f 8a 04 f3 ff ea fe 33 |..V.........3|
>>> Flow 4 (server to client)
00000000 14 03 03 00 01 01 16 03 03 00 28 00 00 00 00 00 |..........(.....|
-00000010 00 00 00 b9 c9 6f cb 58 df 1c a1 0a 79 4e fa 8f |.....o.X....yN..|
-00000020 41 55 8a 0a f8 d1 83 88 28 fb 44 00 8a a5 11 39 |AU......(.D....9|
-00000030 5b d4 83 17 03 03 00 25 00 00 00 00 00 00 00 01 |[......%........|
-00000040 85 4f 2a 54 aa c0 ce 7b 1e 4e e4 64 56 57 68 5e |.O*T...{.N.dVWh^|
-00000050 fa 41 67 8a da 9d f4 78 a6 c6 13 76 7c 15 03 03 |.Ag....x...v|...|
-00000060 00 1a 00 00 00 00 00 00 00 02 38 71 21 c6 82 bc |..........8q!...|
-00000070 2e 37 14 1d 15 2f 74 9d 7c 99 d8 66 |.7.../t.|..f|
+00000010 00 00 00 ec 99 e0 9a 83 28 94 e6 72 4f be 28 24 |........(..rO.($|
+00000020 64 bd 9d 86 79 cc ab 05 15 39 06 6e da 0c b8 4e |d...y....9.n...N|
+00000030 6c a9 f3 17 03 03 00 25 00 00 00 00 00 00 00 01 |l......%........|
+00000040 9a d7 b0 54 dd 3c ae 8e 3f 1f 41 68 a5 01 a0 da |...T.<..?.Ah....|
+00000050 e8 8e 90 55 1a 11 f0 70 8d a3 af a4 29 15 03 03 |...U...p....)...|
+00000060 00 1a 00 00 00 00 00 00 00 02 a8 96 cb 16 d7 b1 |................|
+00000070 41 7e bc 0e 01 8f cc 47 40 e5 c7 2a |A~.....G at ..*|
diff --git a/src/crypto/tls/testdata/Server-TLSv12-RSA-AES256-GCM-SHA384 b/src/crypto/tls/testdata/Server-TLSv12-RSA-AES256-GCM-SHA384
index cc94ac7..36be9da 100644
--- a/src/crypto/tls/testdata/Server-TLSv12-RSA-AES256-GCM-SHA384
+++ b/src/crypto/tls/testdata/Server-TLSv12-RSA-AES256-GCM-SHA384
@@ -1,86 +1,79 @@
>>> Flow 1 (client to server)
-00000000 16 03 01 00 83 01 00 00 7f 03 03 55 9b 71 e2 46 |...........U.q.F|
-00000010 88 58 c4 16 6a 6e 14 3d 3a 5a f9 fe ec 68 71 24 |.X..jn.=:Z...hq$|
-00000020 d0 06 6f a1 56 8f d6 15 42 6b ba 00 00 04 c0 30 |..o.V...Bk.....0|
-00000030 00 ff 02 01 00 00 51 00 0b 00 04 03 00 01 02 00 |......Q.........|
-00000040 0a 00 1c 00 1a 00 17 00 19 00 1c 00 1b 00 18 00 |................|
-00000050 1a 00 16 00 0e 00 0d 00 0b 00 0c 00 09 00 0a 00 |................|
-00000060 0d 00 20 00 1e 06 01 06 02 06 03 05 01 05 02 05 |.. .............|
-00000070 03 04 01 04 02 04 03 03 01 03 02 03 03 02 01 02 |................|
-00000080 02 02 03 00 0f 00 01 01 |........|
+00000000 16 03 01 00 73 01 00 00 6f 03 03 b7 d2 dc fe 53 |....s...o......S|
+00000010 d6 13 08 19 be 30 22 17 db a7 06 9b 62 82 14 38 |.....0".....b..8|
+00000020 2e 68 70 08 02 7d 22 64 13 75 f5 00 00 04 c0 30 |.hp..}"d.u.....0|
+00000030 00 ff 01 00 00 42 00 0b 00 04 03 00 01 02 00 0a |.....B..........|
+00000040 00 0a 00 08 00 1d 00 17 00 19 00 18 00 0d 00 20 |............... |
+00000050 00 1e 06 01 06 02 06 03 05 01 05 02 05 03 04 01 |................|
+00000060 04 02 04 03 03 01 03 02 03 03 02 01 02 02 02 03 |................|
+00000070 00 16 00 00 00 17 00 00 |........|
>>> Flow 2 (server to client)
00000000 16 03 03 00 31 02 00 00 2d 03 03 00 00 00 00 00 |....1...-.......|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000020 00 00 00 00 00 00 00 00 00 00 00 00 c0 30 00 00 |.............0..|
-00000030 05 ff 01 00 01 00 16 03 03 02 71 0b 00 02 6d 00 |..........q...m.|
-00000040 02 6a 00 02 67 30 82 02 63 30 82 01 cc a0 03 02 |.j..g0..c0......|
-00000050 01 02 02 09 00 a2 73 00 0c 81 00 cb f3 30 0d 06 |......s......0..|
-00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 2b 31 17 |.*.H........0+1.|
-00000070 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 |0...U....Google |
-00000080 54 45 53 54 49 4e 47 31 10 30 0e 06 03 55 04 03 |TESTING1.0...U..|
-00000090 13 07 47 6f 20 52 6f 6f 74 30 1e 17 0d 31 35 30 |..Go Root0...150|
-000000a0 31 30 31 30 30 30 30 30 30 5a 17 0d 32 35 30 31 |101000000Z..2501|
-000000b0 30 31 30 30 30 30 30 30 5a 30 26 31 17 30 15 06 |01000000Z0&1.0..|
-000000c0 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 54 45 53 |.U....Google TES|
-000000d0 54 49 4e 47 31 0b 30 09 06 03 55 04 03 13 02 47 |TING1.0...U....G|
-000000e0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....|
-000000f0 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 af 87 |.......0........|
-00000100 88 f6 20 1b 95 65 6c 14 ab 44 05 af 3b 45 14 e3 |.. ..el..D..;E..|
-00000110 b7 6d fd 00 63 4d 95 7f fe 6a 62 35 86 c0 4a f9 |.m..cM...jb5..J.|
-00000120 18 7c f6 aa 25 5e 7a 64 31 66 00 ba f4 8e 92 af |.|..%^zd1f......|
-00000130 c7 6b d8 76 d4 f3 5f 41 cb 6e 56 15 97 1b 97 c1 |.k.v.._A.nV.....|
-00000140 3c 12 39 21 66 3d 2b 16 d1 bc db 1c c0 a7 da b7 |<.9!f=+.........|
-00000150 ca ad ba da cb d5 21 50 ec de 8d ab d1 6b 81 4b |......!P.....k.K|
-00000160 89 02 f3 c4 be c1 6c 89 b1 44 84 bd 21 d1 04 7d |......l..D..!..}|
-00000170 9d 16 4d f9 82 15 f6 ef fa d6 09 47 f2 fb 02 03 |..M........G....|
-00000180 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..|
-00000190 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%|
-000001a0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........|
-000001b0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...|
-000001c0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....|
-000001d0 10 12 50 8d 89 6f 1b d1 dc 54 4d 6e cb 69 5e 06 |..P..o...TMn.i^.|
-000001e0 f4 30 1b 06 03 55 1d 23 04 14 30 12 80 10 bf 3d |.0...U.#..0....=|
-000001f0 b6 a9 66 f2 b8 40 cf ea b4 03 78 48 1a 41 30 19 |..f.. at ....xH.A0.|
-00000200 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp|
-00000210 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H|
-00000220 86 f7 0d 01 01 0b 05 00 03 81 81 00 92 7c af 91 |.............|..|
-00000230 55 12 18 96 59 31 a6 48 40 d5 2d d5 ee bb 02 a0 |U...Y1.H at .-.....|
-00000240 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 da 4f 3d c0 fa |...|..0}<.v.O=..|
-00000250 ae 2d 33 24 6b 03 7b 1b 67 59 11 21 b5 11 bc 77 |.-3$k.{.gY.!...w|
-00000260 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f 22 3e 63 10 6b |...n.-.5.d_">c.k|
-00000270 be ff 14 86 6d 0d f0 15 31 a8 14 38 1e 3b 84 87 |....m...1..8.;..|
-00000280 2c cb 98 ed 51 76 b9 b1 4f dd db 9b 84 04 86 40 |,...Qv..O......@|
-00000290 fa 51 dd ba b4 8d eb e3 46 de 46 b9 4f 86 c7 f9 |.Q......F.F.O...|
-000002a0 a4 c2 41 34 ac cc f6 ea b0 ab 39 18 16 03 03 00 |..A4......9.....|
-000002b0 cd 0c 00 00 c9 03 00 17 41 04 1e 18 37 ef 0d 19 |........A...7...|
-000002c0 51 88 35 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd a7 |Q.5uq..T[....g..|
-000002d0 24 20 3e b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e f1 |$ >.V...(^.+-O..|
-000002e0 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 a6 |..lK[.V.2B.X..I.|
-000002f0 b5 68 1a 41 03 56 6b dc 5a 89 05 01 00 80 7f 44 |.h.A.Vk.Z......D|
-00000300 af 7b 21 01 6b f0 1c 75 d3 6b 28 99 68 e1 0e d3 |.{!.k..u.k(.h...|
-00000310 a8 cb 5a 2e 23 ad d7 92 73 46 5b 66 88 bd f1 d6 |..Z.#...sF[f....|
-00000320 5d 52 d1 07 53 88 9c 64 e3 ce 80 b3 39 7f 9e 2b |]R..S..d....9..+|
-00000330 0a 02 a7 e1 3e 00 70 51 3b b4 52 d1 3c 4a e9 f7 |....>.pQ;.R.<J..|
-00000340 0f 85 fa ff d7 ba 96 fc 77 8e 66 8d c6 4c b8 c2 |........w.f..L..|
-00000350 a5 d3 ad 72 f0 8c ba d2 bf 1c 81 7b 4e d5 9e 80 |...r.......{N...|
-00000360 7e b2 90 a0 2f d6 ad c2 33 43 da 46 b0 22 40 ff |~.../...3C.F."@.|
-00000370 df 95 b3 1e f1 97 b9 7b 61 3c 78 d9 ae cb 16 03 |.......{a<x.....|
-00000380 03 00 04 0e 00 00 00 |.......|
+00000030 05 ff 01 00 01 00 16 03 03 02 59 0b 00 02 55 00 |..........Y...U.|
+00000040 02 52 00 02 4f 30 82 02 4b 30 82 01 b4 a0 03 02 |.R..O0..K0......|
+00000050 01 02 02 09 00 e8 f0 9d 3f e2 5b ea a6 30 0d 06 |........?.[..0..|
+00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 1f 31 0b |.*.H........0.1.|
+00000070 30 09 06 03 55 04 0a 13 02 47 6f 31 10 30 0e 06 |0...U....Go1.0..|
+00000080 03 55 04 03 13 07 47 6f 20 52 6f 6f 74 30 1e 17 |.U....Go Root0..|
+00000090 0d 31 36 30 31 30 31 30 30 30 30 30 30 5a 17 0d |.160101000000Z..|
+000000a0 32 35 30 31 30 31 30 30 30 30 30 30 5a 30 1a 31 |250101000000Z0.1|
+000000b0 0b 30 09 06 03 55 04 0a 13 02 47 6f 31 0b 30 09 |.0...U....Go1.0.|
+000000c0 06 03 55 04 03 13 02 47 6f 30 81 9f 30 0d 06 09 |..U....Go0..0...|
+000000d0 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 30 |*.H............0|
+000000e0 81 89 02 81 81 00 db 46 7d 93 2e 12 27 06 48 bc |.......F}...'.H.|
+000000f0 06 28 21 ab 7e c4 b6 a2 5d fe 1e 52 45 88 7a 36 |.(!.~...]..RE.z6|
+00000100 47 a5 08 0d 92 42 5b c2 81 c0 be 97 79 98 40 fb |G....B[.....y. at .|
+00000110 4f 6d 14 fd 2b 13 8b c2 a5 2e 67 d8 d4 09 9e d6 |Om..+.....g.....|
+00000120 22 38 b7 4a 0b 74 73 2b c2 34 f1 d1 93 e5 96 d9 |"8.J.ts+.4......|
+00000130 74 7b f3 58 9f 6c 61 3c c0 b0 41 d4 d9 2b 2b 24 |t{.X.la<..A..++$|
+00000140 23 77 5b 1c 3b bd 75 5d ce 20 54 cf a1 63 87 1d |#w[.;.u]. T..c..|
+00000150 1e 24 c4 f3 1d 1a 50 8b aa b6 14 43 ed 97 a7 75 |.$....P....C...u|
+00000160 62 f4 14 c8 52 d7 02 03 01 00 01 a3 81 93 30 81 |b...R.........0.|
+00000170 90 30 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 05 |.0...U..........|
+00000180 a0 30 1d 06 03 55 1d 25 04 16 30 14 06 08 2b 06 |.0...U.%..0...+.|
+00000190 01 05 05 07 03 01 06 08 2b 06 01 05 05 07 03 02 |........+.......|
+000001a0 30 0c 06 03 55 1d 13 01 01 ff 04 02 30 00 30 19 |0...U.......0.0.|
+000001b0 06 03 55 1d 0e 04 12 04 10 9f 91 16 1f 43 43 3e |..U..........CC>|
+000001c0 49 a6 de 6d b6 80 d7 9f 60 30 1b 06 03 55 1d 23 |I..m....`0...U.#|
+000001d0 04 14 30 12 80 10 48 13 49 4d 13 7e 16 31 bb a3 |..0...H.IM.~.1..|
+000001e0 01 d5 ac ab 6e 7b 30 19 06 03 55 1d 11 04 12 30 |....n{0...U....0|
+000001f0 10 82 0e 65 78 61 6d 70 6c 65 2e 67 6f 6c 61 6e |...example.golan|
+00000200 67 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 |g0...*.H........|
+00000210 03 81 81 00 9d 30 cc 40 2b 5b 50 a0 61 cb ba e5 |.....0. at +[P.a...|
+00000220 53 58 e1 ed 83 28 a9 58 1a a9 38 a4 95 a1 ac 31 |SX...(.X..8....1|
+00000230 5a 1a 84 66 3d 43 d3 2d d9 0b f2 97 df d3 20 64 |Z..f=C.-...... d|
+00000240 38 92 24 3a 00 bc cf 9c 7d b7 40 20 01 5f aa d3 |8.$:....}.@ ._..|
+00000250 16 61 09 a2 76 fd 13 c3 cc e1 0c 5c ee b1 87 82 |.a..v......\....|
+00000260 f1 6c 04 ed 73 bb b3 43 77 8d 0c 1c f1 0f a1 d8 |.l..s..Cw.......|
+00000270 40 83 61 c9 4c 72 2b 9d ae db 46 06 06 4d f4 c1 |@.a.Lr+...F..M..|
+00000280 b3 3e c0 d1 bd 42 d4 db fe 3d 13 60 84 5c 21 d3 |.>...B...=.`.\!.|
+00000290 3b e9 fa e7 16 03 03 00 ac 0c 00 00 a8 03 00 1d |;...............|
+000002a0 20 2f e5 7d a3 47 cd 62 43 15 28 da ac 5f bb 29 | /.}.G.bC.(.._.)|
+000002b0 07 30 ff f6 84 af c4 cf c2 ed 90 99 5f 58 cb 3b |.0.........._X.;|
+000002c0 74 05 01 00 80 b8 c4 6a be 2a dd 47 03 7b 84 72 |t......j.*.G.{.r|
+000002d0 0b a4 c0 a7 2e b5 a4 be c7 6a 2a 8b d0 23 6f b5 |.........j*..#o.|
+000002e0 bc 0e ba 3c f5 9d a3 90 b0 af 80 11 bd 22 b5 7b |...<.........".{|
+000002f0 3c 53 f8 54 d0 b4 b0 53 28 75 0d 15 58 88 c2 90 |<S.T...S(u..X...|
+00000300 69 ea e0 08 aa 07 93 15 ae ed e5 a8 3d 2d 9c 62 |i...........=-.b|
+00000310 1d 40 26 7d 0e d3 23 52 71 71 ff ea 18 f9 0a eb |.@&}..#Rqq......|
+00000320 78 8a 8f 9e 12 8c 0b 33 a8 ee 42 76 16 29 58 ec |x......3..Bv.)X.|
+00000330 ea 6d 22 48 0d d0 68 c3 97 8d e9 ec cd 10 f6 47 |.m"H..h........G|
+00000340 c9 9d 42 12 54 16 03 03 00 04 0e 00 00 00 |..B.T.........|
>>> Flow 3 (client to server)
-00000000 16 03 03 00 46 10 00 00 42 41 04 d8 85 85 d2 78 |....F...BA.....x|
-00000010 27 a5 0a bb 10 67 ec a9 d8 11 f0 ba b9 d7 21 39 |'....g........!9|
-00000020 ed c7 0a a0 a2 69 ab fb 9b 15 e0 d7 ec ca 97 c8 |.....i..........|
-00000030 c0 b2 66 0b 2c 68 37 ac f0 34 fa 3a 07 dd f2 ae |..f.,h7..4.:....|
-00000040 8e f6 e3 eb de 08 1f 56 e5 66 eb 14 03 03 00 01 |.......V.f......|
-00000050 01 16 03 03 00 28 f5 2d 89 00 0c 9d d9 0e 54 1b |.....(.-......T.|
-00000060 71 84 4d c7 bb 98 36 8c 29 b6 06 d8 7b df d9 92 |q.M...6.)...{...|
-00000070 01 00 16 44 5e e3 db f3 8f b7 fa 43 0c f7 |...D^......C..|
+00000000 16 03 03 00 25 10 00 00 21 20 20 df 4a b8 02 4f |....%...! .J..O|
+00000010 31 db 22 90 59 57 20 23 e1 72 8d 28 60 b3 f2 77 |1.".YW #.r.(`..w|
+00000020 db 3a ce 64 5a a5 63 94 be 09 14 03 03 00 01 01 |.:.dZ.c.........|
+00000030 16 03 03 00 28 de 72 f3 c3 b2 aa b4 9b b7 fe 35 |....(.r........5|
+00000040 3b 25 af 74 47 d3 49 39 07 d9 70 37 30 d0 b7 47 |;%.tG.I9..p70..G|
+00000050 bf ad 97 08 44 59 a7 3c 12 f2 4a 2d 7c |....DY.<..J-||
>>> Flow 4 (server to client)
00000000 14 03 03 00 01 01 16 03 03 00 28 00 00 00 00 00 |..........(.....|
-00000010 00 00 00 a4 82 dc d1 67 ed 17 ae 22 13 0d ac d2 |.......g..."....|
-00000020 f4 58 44 5b b4 c6 25 29 80 b6 bc 63 0e 67 22 6e |.XD[..%)...c.g"n|
-00000030 18 92 48 17 03 03 00 25 00 00 00 00 00 00 00 01 |..H....%........|
-00000040 a0 fe 37 25 fb 4d 29 96 f9 01 67 19 d8 83 26 68 |..7%.M)...g...&h|
-00000050 d0 e8 58 2c ef 90 a3 b5 26 51 26 a9 28 15 03 03 |..X,....&Q&.(...|
-00000060 00 1a 00 00 00 00 00 00 00 02 91 4b d5 54 4a ef |...........K.TJ.|
-00000070 22 88 ab b7 a2 bb 20 5a b2 3e 7b 36 |"..... Z.>{6|
+00000010 00 00 00 16 18 e1 e8 d4 c0 d1 19 3a 50 10 85 fc |...........:P...|
+00000020 fc 3e 27 54 e4 57 b6 e7 c4 25 d5 4e 10 ad 0f ff |.>'T.W...%.N....|
+00000030 ad 45 8c 17 03 03 00 25 00 00 00 00 00 00 00 01 |.E.....%........|
+00000040 50 b8 af 5f a2 3e 0f f7 f0 81 1f 32 69 39 2f f2 |P.._.>.....2i9/.|
+00000050 47 28 80 fb d0 46 d4 b7 a2 ba e3 71 ea 15 03 03 |G(...F.....q....|
+00000060 00 1a 00 00 00 00 00 00 00 02 c4 64 7a 81 b3 3a |...........dz..:|
+00000070 2c 71 35 ec f7 0c 52 36 20 2c eb fe |,q5...R6 ,..|
diff --git a/src/crypto/tls/testdata/Server-TLSv12-RSA-RC4 b/src/crypto/tls/testdata/Server-TLSv12-RSA-RC4
index c55f891..e49d1bc 100644
--- a/src/crypto/tls/testdata/Server-TLSv12-RSA-RC4
+++ b/src/crypto/tls/testdata/Server-TLSv12-RSA-RC4
@@ -1,73 +1,72 @@
>>> Flow 1 (client to server)
-00000000 16 03 01 00 5b 01 00 00 57 03 03 ec 96 78 51 74 |....[...W....xQt|
-00000010 1b f2 21 ad f2 4f 50 aa 67 f1 20 e2 4f d3 4d 0e |..!..OP.g. .O.M.|
-00000020 54 91 df 91 d8 81 e3 75 bb 20 c2 00 00 04 00 05 |T......u. ......|
-00000030 00 ff 02 01 00 00 29 00 0d 00 20 00 1e 06 01 06 |......)... .....|
-00000040 02 06 03 05 01 05 02 05 03 04 01 04 02 04 03 03 |................|
-00000050 01 03 02 03 03 02 01 02 02 02 03 00 0f 00 01 01 |................|
+00000000 16 03 01 00 5d 01 00 00 59 03 03 55 3e 1a 3f cc |....]...Y..U>.?.|
+00000010 14 18 07 db 5e 97 15 33 62 9d de 56 7b ea 52 bf |....^..3b..V{.R.|
+00000020 a3 ce c2 75 3f 52 0a 2f 3e 99 07 00 00 04 00 05 |...u?R./>.......|
+00000030 00 ff 01 00 00 2c 00 0d 00 20 00 1e 06 01 06 02 |.....,... ......|
+00000040 06 03 05 01 05 02 05 03 04 01 04 02 04 03 03 01 |................|
+00000050 03 02 03 03 02 01 02 02 02 03 00 16 00 00 00 17 |................|
+00000060 00 00 |..|
>>> Flow 2 (server to client)
00000000 16 03 03 00 31 02 00 00 2d 03 03 00 00 00 00 00 |....1...-.......|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 05 00 00 |................|
-00000030 05 ff 01 00 01 00 16 03 03 02 71 0b 00 02 6d 00 |..........q...m.|
-00000040 02 6a 00 02 67 30 82 02 63 30 82 01 cc a0 03 02 |.j..g0..c0......|
-00000050 01 02 02 09 00 a2 73 00 0c 81 00 cb f3 30 0d 06 |......s......0..|
-00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 2b 31 17 |.*.H........0+1.|
-00000070 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 |0...U....Google |
-00000080 54 45 53 54 49 4e 47 31 10 30 0e 06 03 55 04 03 |TESTING1.0...U..|
-00000090 13 07 47 6f 20 52 6f 6f 74 30 1e 17 0d 31 35 30 |..Go Root0...150|
-000000a0 31 30 31 30 30 30 30 30 30 5a 17 0d 32 35 30 31 |101000000Z..2501|
-000000b0 30 31 30 30 30 30 30 30 5a 30 26 31 17 30 15 06 |01000000Z0&1.0..|
-000000c0 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 54 45 53 |.U....Google TES|
-000000d0 54 49 4e 47 31 0b 30 09 06 03 55 04 03 13 02 47 |TING1.0...U....G|
-000000e0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....|
-000000f0 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 af 87 |.......0........|
-00000100 88 f6 20 1b 95 65 6c 14 ab 44 05 af 3b 45 14 e3 |.. ..el..D..;E..|
-00000110 b7 6d fd 00 63 4d 95 7f fe 6a 62 35 86 c0 4a f9 |.m..cM...jb5..J.|
-00000120 18 7c f6 aa 25 5e 7a 64 31 66 00 ba f4 8e 92 af |.|..%^zd1f......|
-00000130 c7 6b d8 76 d4 f3 5f 41 cb 6e 56 15 97 1b 97 c1 |.k.v.._A.nV.....|
-00000140 3c 12 39 21 66 3d 2b 16 d1 bc db 1c c0 a7 da b7 |<.9!f=+.........|
-00000150 ca ad ba da cb d5 21 50 ec de 8d ab d1 6b 81 4b |......!P.....k.K|
-00000160 89 02 f3 c4 be c1 6c 89 b1 44 84 bd 21 d1 04 7d |......l..D..!..}|
-00000170 9d 16 4d f9 82 15 f6 ef fa d6 09 47 f2 fb 02 03 |..M........G....|
-00000180 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..|
-00000190 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%|
-000001a0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........|
-000001b0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...|
-000001c0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....|
-000001d0 10 12 50 8d 89 6f 1b d1 dc 54 4d 6e cb 69 5e 06 |..P..o...TMn.i^.|
-000001e0 f4 30 1b 06 03 55 1d 23 04 14 30 12 80 10 bf 3d |.0...U.#..0....=|
-000001f0 b6 a9 66 f2 b8 40 cf ea b4 03 78 48 1a 41 30 19 |..f.. at ....xH.A0.|
-00000200 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp|
-00000210 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H|
-00000220 86 f7 0d 01 01 0b 05 00 03 81 81 00 92 7c af 91 |.............|..|
-00000230 55 12 18 96 59 31 a6 48 40 d5 2d d5 ee bb 02 a0 |U...Y1.H at .-.....|
-00000240 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 da 4f 3d c0 fa |...|..0}<.v.O=..|
-00000250 ae 2d 33 24 6b 03 7b 1b 67 59 11 21 b5 11 bc 77 |.-3$k.{.gY.!...w|
-00000260 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f 22 3e 63 10 6b |...n.-.5.d_">c.k|
-00000270 be ff 14 86 6d 0d f0 15 31 a8 14 38 1e 3b 84 87 |....m...1..8.;..|
-00000280 2c cb 98 ed 51 76 b9 b1 4f dd db 9b 84 04 86 40 |,...Qv..O......@|
-00000290 fa 51 dd ba b4 8d eb e3 46 de 46 b9 4f 86 c7 f9 |.Q......F.F.O...|
-000002a0 a4 c2 41 34 ac cc f6 ea b0 ab 39 18 16 03 03 00 |..A4......9.....|
-000002b0 04 0e 00 00 00 |.....|
+00000030 05 ff 01 00 01 00 16 03 03 02 59 0b 00 02 55 00 |..........Y...U.|
+00000040 02 52 00 02 4f 30 82 02 4b 30 82 01 b4 a0 03 02 |.R..O0..K0......|
+00000050 01 02 02 09 00 e8 f0 9d 3f e2 5b ea a6 30 0d 06 |........?.[..0..|
+00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 1f 31 0b |.*.H........0.1.|
+00000070 30 09 06 03 55 04 0a 13 02 47 6f 31 10 30 0e 06 |0...U....Go1.0..|
+00000080 03 55 04 03 13 07 47 6f 20 52 6f 6f 74 30 1e 17 |.U....Go Root0..|
+00000090 0d 31 36 30 31 30 31 30 30 30 30 30 30 5a 17 0d |.160101000000Z..|
+000000a0 32 35 30 31 30 31 30 30 30 30 30 30 5a 30 1a 31 |250101000000Z0.1|
+000000b0 0b 30 09 06 03 55 04 0a 13 02 47 6f 31 0b 30 09 |.0...U....Go1.0.|
+000000c0 06 03 55 04 03 13 02 47 6f 30 81 9f 30 0d 06 09 |..U....Go0..0...|
+000000d0 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 30 |*.H............0|
+000000e0 81 89 02 81 81 00 db 46 7d 93 2e 12 27 06 48 bc |.......F}...'.H.|
+000000f0 06 28 21 ab 7e c4 b6 a2 5d fe 1e 52 45 88 7a 36 |.(!.~...]..RE.z6|
+00000100 47 a5 08 0d 92 42 5b c2 81 c0 be 97 79 98 40 fb |G....B[.....y. at .|
+00000110 4f 6d 14 fd 2b 13 8b c2 a5 2e 67 d8 d4 09 9e d6 |Om..+.....g.....|
+00000120 22 38 b7 4a 0b 74 73 2b c2 34 f1 d1 93 e5 96 d9 |"8.J.ts+.4......|
+00000130 74 7b f3 58 9f 6c 61 3c c0 b0 41 d4 d9 2b 2b 24 |t{.X.la<..A..++$|
+00000140 23 77 5b 1c 3b bd 75 5d ce 20 54 cf a1 63 87 1d |#w[.;.u]. T..c..|
+00000150 1e 24 c4 f3 1d 1a 50 8b aa b6 14 43 ed 97 a7 75 |.$....P....C...u|
+00000160 62 f4 14 c8 52 d7 02 03 01 00 01 a3 81 93 30 81 |b...R.........0.|
+00000170 90 30 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 05 |.0...U..........|
+00000180 a0 30 1d 06 03 55 1d 25 04 16 30 14 06 08 2b 06 |.0...U.%..0...+.|
+00000190 01 05 05 07 03 01 06 08 2b 06 01 05 05 07 03 02 |........+.......|
+000001a0 30 0c 06 03 55 1d 13 01 01 ff 04 02 30 00 30 19 |0...U.......0.0.|
+000001b0 06 03 55 1d 0e 04 12 04 10 9f 91 16 1f 43 43 3e |..U..........CC>|
+000001c0 49 a6 de 6d b6 80 d7 9f 60 30 1b 06 03 55 1d 23 |I..m....`0...U.#|
+000001d0 04 14 30 12 80 10 48 13 49 4d 13 7e 16 31 bb a3 |..0...H.IM.~.1..|
+000001e0 01 d5 ac ab 6e 7b 30 19 06 03 55 1d 11 04 12 30 |....n{0...U....0|
+000001f0 10 82 0e 65 78 61 6d 70 6c 65 2e 67 6f 6c 61 6e |...example.golan|
+00000200 67 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 |g0...*.H........|
+00000210 03 81 81 00 9d 30 cc 40 2b 5b 50 a0 61 cb ba e5 |.....0. at +[P.a...|
+00000220 53 58 e1 ed 83 28 a9 58 1a a9 38 a4 95 a1 ac 31 |SX...(.X..8....1|
+00000230 5a 1a 84 66 3d 43 d3 2d d9 0b f2 97 df d3 20 64 |Z..f=C.-...... d|
+00000240 38 92 24 3a 00 bc cf 9c 7d b7 40 20 01 5f aa d3 |8.$:....}.@ ._..|
+00000250 16 61 09 a2 76 fd 13 c3 cc e1 0c 5c ee b1 87 82 |.a..v......\....|
+00000260 f1 6c 04 ed 73 bb b3 43 77 8d 0c 1c f1 0f a1 d8 |.l..s..Cw.......|
+00000270 40 83 61 c9 4c 72 2b 9d ae db 46 06 06 4d f4 c1 |@.a.Lr+...F..M..|
+00000280 b3 3e c0 d1 bd 42 d4 db fe 3d 13 60 84 5c 21 d3 |.>...B...=.`.\!.|
+00000290 3b e9 fa e7 16 03 03 00 04 0e 00 00 00 |;............|
>>> Flow 3 (client to server)
-00000000 16 03 03 00 86 10 00 00 82 00 80 05 4b 04 74 76 |............K.tv|
-00000010 73 3a 92 04 4d 8b 3b 59 c2 43 c5 f4 07 e8 bc a3 |s:..M.;Y.C......|
-00000020 62 44 b7 80 9f 8f bc 43 8a 67 09 64 a7 93 9f f9 |bD.....C.g.d....|
-00000030 2c 55 03 4b e5 87 9d 18 a2 c3 48 4f 02 6e e0 23 |,U.K......HO.n.#|
-00000040 0b 2f 57 81 e4 38 50 11 d6 b1 71 4f c2 e5 a4 03 |./W..8P...qO....|
-00000050 34 a4 eb a1 42 47 79 05 bc 7b b8 26 5b c1 f9 82 |4...BGy..{.&[...|
-00000060 fc 58 49 eb 04 52 fe 57 3c ed 5c 2b d8 fe 49 d7 |.XI..R.W<.\+..I.|
-00000070 d2 2e 6c e8 74 74 0d 87 b3 f6 2d f0 ff 03 f0 2d |..l.tt....-....-|
-00000080 c8 a2 20 89 3f 3f 11 e1 fb 93 85 14 03 03 00 01 |.. .??..........|
-00000090 01 16 03 03 00 24 9a 81 c0 9e 76 b6 3d 78 37 8e |.....$....v.=x7.|
-000000a0 ab 33 48 93 bb 0d f4 86 3c ff 72 28 10 35 c2 10 |.3H.....<.r(.5..|
-000000b0 f0 a0 ff 0c 20 f3 c4 29 83 a6 |.... ..)..|
+00000000 16 03 03 00 86 10 00 00 82 00 80 a7 55 0a e7 33 |............U..3|
+00000010 8e be 5a 3a b4 f4 06 6e fc 0e 42 6e f3 0c 01 5a |..Z:...n..Bn...Z|
+00000020 65 73 36 bd cd be 0f 65 2f d2 88 1a f0 5e f8 07 |es6....e/....^..|
+00000030 c1 fe 5f 5f d6 f5 fa 79 24 44 0d 33 4f e6 74 88 |..__...y$D.3O.t.|
+00000040 86 f1 76 84 29 b4 f2 ae eb 9b 00 a2 6a e4 97 58 |..v.).......j..X|
+00000050 8b 2e 04 8f 8f 5e fe b4 9d 38 1d 8d 40 a4 9b a2 |.....^...8.. at ...|
+00000060 17 50 8a e5 39 c9 e9 41 3e 0d 9c 42 2c 7a 88 bf |.P..9..A>..B,z..|
+00000070 f7 09 4e 27 0b fe cc 53 13 07 d5 7e 0e e6 02 3c |..N'...S...~...<|
+00000080 8a 3f f9 03 df b6 65 a0 77 ee 50 14 03 03 00 01 |.?....e.w.P.....|
+00000090 01 16 03 03 00 24 5f 41 3e 38 05 08 74 62 5b 4e |.....$_A>8..tb[N|
+000000a0 94 55 98 74 5c 65 1a 4c 49 08 1d 77 d7 f0 12 47 |.U.t\e.LI..w...G|
+000000b0 d2 ef a6 31 5c 36 03 b5 b5 9d |...1\6....|
>>> Flow 4 (server to client)
-00000000 14 03 03 00 01 01 16 03 03 00 24 93 15 62 c5 2b |..........$..b.+|
-00000010 4f 8a d7 0f 70 1f 9d 11 fc 8f 9a a9 b7 d7 44 50 |O...p.........DP|
-00000020 6e 0e 5b d7 3b de 15 7d 17 35 31 42 1f a4 40 17 |n.[.;..}.51B.. at .|
-00000030 03 03 00 21 a9 ca 73 e9 ce 2d 21 ef 7d bc 40 91 |...!..s..-!.}. at .|
-00000040 41 c9 53 62 af 09 8e b4 37 0f fa ab b7 76 8f 5b |A.Sb....7....v.[|
-00000050 7d 0f 04 48 49 15 03 03 00 16 76 b1 d7 91 88 6f |}..HI.....v....o|
-00000060 b4 e7 a4 f1 d2 c2 ac 50 db 31 ae 5c f7 53 a1 68 |.......P.1.\.S.h|
+00000000 14 03 03 00 01 01 16 03 03 00 24 6f 68 a2 c0 4d |..........$oh..M|
+00000010 f4 cb c0 e5 8b 19 f9 2e 46 c3 3b 92 eb a9 42 8b |........F.;...B.|
+00000020 03 4a e2 62 9d f1 c0 39 b1 63 61 08 15 b0 ca 17 |.J.b...9.ca.....|
+00000030 03 03 00 21 50 9e 16 ce 7e af 8f 43 d1 1c 30 37 |...!P...~..C..07|
+00000040 85 e9 68 3a 9c 7e 26 90 dc 14 b1 ec 91 20 2b 4a |..h:.~&...... +J|
+00000050 24 b4 fa b1 50 15 03 03 00 16 59 74 08 41 73 01 |$...P.....Yt.As.|
+00000060 22 19 0b 35 6b 4d ee d2 15 50 42 de cc cf cc 09 |"..5kM...PB.....|
diff --git a/src/crypto/tls/testdata/Server-TLSv12-Resume b/src/crypto/tls/testdata/Server-TLSv12-Resume
index 521376c..366ca8f 100644
--- a/src/crypto/tls/testdata/Server-TLSv12-Resume
+++ b/src/crypto/tls/testdata/Server-TLSv12-Resume
@@ -1,37 +1,41 @@
>>> Flow 1 (client to server)
-00000000 16 03 01 00 f7 01 00 00 f3 03 03 35 70 0b ed 1c |...........5p...|
-00000010 83 57 b1 7b 0a 47 ce d4 07 3a 49 96 93 4c a1 83 |.W.{.G...:I..L..|
-00000020 4b ab b7 ab 7d b0 14 be dd 91 92 20 09 34 b7 de |K...}...... .4..|
-00000030 bd 43 e8 cd 8e f3 43 aa 04 64 8f 0a 55 a6 58 ed |.C....C..d..U.X.|
-00000040 31 8b 3d 4c 84 4f 2c 6d b0 b1 75 6f 00 04 00 05 |1.=L.O,m..uo....|
-00000050 00 ff 02 01 00 00 a5 00 23 00 78 50 46 ad c1 db |........#.xPF...|
-00000060 a8 38 86 7b 2b bb fd d0 c3 42 3e 00 00 00 00 00 |.8.{+....B>.....|
-00000070 00 00 00 00 00 00 00 00 00 00 00 94 6f 2c b5 83 |............o,..|
-00000080 61 4d 51 5f 33 46 48 fe 9e e9 83 f4 b1 aa c9 b1 |aMQ_3FH.........|
-00000090 61 2a b2 9d 0f 17 c4 09 f6 26 7a 75 f1 19 99 db |a*.......&zu....|
-000000a0 36 d8 32 f0 94 61 4f 8f ed 80 33 51 f3 c6 15 84 |6.2..aO...3Q....|
-000000b0 6b 33 94 c8 4f 84 b7 7c 27 6d 8f fe 41 8e b2 92 |k3..O..|'m..A...|
-000000c0 ca 80 e8 6c ba 75 77 f5 3a 87 17 ae f8 b9 6b 10 |...l.uw.:.....k.|
-000000d0 f9 85 da 00 0d 00 20 00 1e 06 01 06 02 06 03 05 |...... .........|
-000000e0 01 05 02 05 03 04 01 04 02 04 03 03 01 03 02 03 |................|
-000000f0 03 02 01 02 02 02 03 00 0f 00 01 01 |............|
+00000000 16 03 01 00 f9 01 00 00 f5 03 03 23 77 58 99 0e |...........#wX..|
+00000010 44 ed 63 44 e4 e4 eb d1 83 c3 9c d0 24 12 a3 b9 |D.cD........$...|
+00000020 55 6b 4d da bf 84 9d 35 de 43 a0 20 7b 93 cb d3 |UkM....5.C. {...|
+00000030 c5 ce 5e d5 aa 48 91 a4 b2 c2 d7 72 09 0d 21 78 |..^..H.....r..!x|
+00000040 f0 ac 7a ed 9a a9 ad dd 51 8b b2 1c 00 04 00 2f |..z.....Q....../|
+00000050 00 ff 01 00 00 a8 00 23 00 78 50 46 ad c1 db a8 |.......#.xPF....|
+00000060 38 86 7b 2b bb fd d0 c3 42 3e 00 00 00 00 00 00 |8.{+....B>......|
+00000070 00 00 00 00 00 00 00 00 00 00 94 6f 2c 9f 83 61 |...........o,..a|
+00000080 0b b1 b7 9e 10 2d 0c 56 e8 70 66 ad de b1 15 74 |.....-.V.pf....t|
+00000090 2f 8b 08 8c 96 bb 4b 1b 4e dd 81 0e bf 84 4d 43 |/.....K.N.....MC|
+000000a0 8f c0 7e a0 7f be c0 59 bf 83 26 0f a2 22 52 2c |..~....Y..&.."R,|
+000000b0 33 94 5a 77 54 f3 b5 f2 22 51 d5 24 c2 60 c3 2e |3.ZwT..."Q.$.`..|
+000000c0 0f 9c 5e 33 3b e8 7c 52 2a 76 08 58 ac 47 98 bc |..^3;.|R*v.X.G..|
+000000d0 36 b6 00 0d 00 20 00 1e 06 01 06 02 06 03 05 01 |6.... ..........|
+000000e0 05 02 05 03 04 01 04 02 04 03 03 01 03 02 03 03 |................|
+000000f0 02 01 02 02 02 03 00 16 00 00 00 17 00 00 |..............|
>>> Flow 2 (server to client)
00000000 16 03 03 00 51 02 00 00 4d 03 03 00 00 00 00 00 |....Q...M.......|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
-00000020 00 00 00 00 00 00 00 00 00 00 00 20 09 34 b7 de |........... .4..|
-00000030 bd 43 e8 cd 8e f3 43 aa 04 64 8f 0a 55 a6 58 ed |.C....C..d..U.X.|
-00000040 31 8b 3d 4c 84 4f 2c 6d b0 b1 75 6f 00 05 00 00 |1.=L.O,m..uo....|
+00000020 00 00 00 00 00 00 00 00 00 00 00 20 7b 93 cb d3 |........... {...|
+00000030 c5 ce 5e d5 aa 48 91 a4 b2 c2 d7 72 09 0d 21 78 |..^..H.....r..!x|
+00000040 f0 ac 7a ed 9a a9 ad dd 51 8b b2 1c 00 2f 00 00 |..z.....Q..../..|
00000050 05 ff 01 00 01 00 14 03 03 00 01 01 16 03 03 00 |................|
-00000060 24 18 67 37 5a c6 ea 3f 5f 06 2d c3 f1 2a ff d3 |$.g7Z..?_.-..*..|
-00000070 45 ce fe 38 1a e6 39 25 e7 e5 01 4d 6e fd 23 af |E..8..9%...Mn.#.|
-00000080 dc 67 1b 1d e2 |.g...|
+00000060 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |@...............|
+00000070 00 ac d9 95 88 c6 37 e8 3c 24 d8 d9 15 46 25 c6 |......7.<$...F%.|
+00000080 32 0c 75 80 11 3d 89 53 1c 7a b1 78 6a c1 1a d7 |2.u..=.S.z.xj...|
+00000090 91 6e c2 55 99 84 11 43 cd 62 99 3b 28 1b 2e 08 |.n.U...C.b.;(...|
+000000a0 a8 |.|
>>> Flow 3 (client to server)
-00000000 14 03 03 00 01 01 16 03 03 00 24 b5 75 e6 1d 1d |..........$.u...|
-00000010 cb 2c 5d 9f d1 07 de 23 11 84 c2 59 50 55 72 27 |.,]....#...YPUr'|
-00000020 f2 5e 34 e2 c1 53 bf 21 5f f4 c4 2c f1 e1 7a |.^4..S.!_..,..z|
+00000000 14 03 03 00 01 01 16 03 03 00 40 67 fd 43 2a 0b |.......... at g.C*.|
+00000010 14 6b 89 53 84 a8 04 62 d6 30 af 68 eb 8e 2a de |.k.S...b.0.h..*.|
+00000020 67 c9 40 af 8b ac dd 29 a4 20 e4 da b0 dd c3 05 |g. at ....). ......|
+00000030 82 83 8f 75 77 db 6c fe e7 20 54 e3 eb 51 31 68 |...uw.l.. T..Q1h|
+00000040 da 11 a3 6d a1 34 d9 f5 d1 ef c9 |...m.4.....|
>>> Flow 4 (server to client)
-00000000 17 03 03 00 21 93 92 dd 07 a3 8f 3d 34 6d b8 94 |....!......=4m..|
-00000010 a7 6f 18 27 e7 cd 30 0a 08 4f b6 9b cb 43 93 27 |.o.'..0..O...C.'|
-00000020 b6 8b 83 ae d6 8a 15 03 03 00 16 68 a1 a4 f8 66 |...........h...f|
-00000030 8a c0 e7 d3 97 83 cb 35 94 84 7a e6 47 3c 97 8c |.......5..z.G<..|
-00000040 69 |i|
+00000000 17 03 03 00 40 00 00 00 00 00 00 00 00 00 00 00 |.... at ...........|
+00000010 00 00 00 00 00 ee e2 75 6f 78 b0 88 1a 8b 9b 91 |.......uox......|
+00000020 c9 8c 3b ae a5 93 71 12 55 66 f8 09 a5 1f 4b 1b |..;...q.Uf....K.|
+00000030 c2 fe 65 8b 3d d9 dc fa af dc 29 1b 83 da e0 6a |..e.=.....)....j|
+00000040 4b cd d0 dc 27 |K...'|
diff --git a/src/crypto/tls/testdata/Server-TLSv12-ResumeDisabled b/src/crypto/tls/testdata/Server-TLSv12-ResumeDisabled
index c3cd2ef..3474837 100644
--- a/src/crypto/tls/testdata/Server-TLSv12-ResumeDisabled
+++ b/src/crypto/tls/testdata/Server-TLSv12-ResumeDisabled
@@ -1,83 +1,89 @@
>>> Flow 1 (client to server)
-00000000 16 03 01 00 f7 01 00 00 f3 03 03 2b 89 3f 02 47 |...........+.?.G|
-00000010 f6 14 64 3b 64 08 84 6e 9c e1 c9 4d 4f 30 92 06 |..d;d..n...MO0..|
-00000020 d1 19 58 5d 93 30 41 4d a6 2c f6 20 53 3c e7 f4 |..X].0AM.,. S<..|
-00000030 23 7e 59 b1 32 c4 2d db 0b 6f ab 64 4a 72 c9 31 |#~Y.2.-..o.dJr.1|
-00000040 d9 b9 38 a8 b4 4e 0c 39 f8 f4 61 7a 00 04 00 05 |..8..N.9..az....|
-00000050 00 ff 02 01 00 00 a5 00 23 00 78 50 46 ad c1 db |........#.xPF...|
-00000060 a8 38 86 7b 2b bb fd d0 c3 42 3e 00 00 00 00 00 |.8.{+....B>.....|
-00000070 00 00 00 00 00 00 00 00 00 00 00 94 6f 2c b5 83 |............o,..|
-00000080 61 01 55 65 2a 95 38 d4 d5 5f 41 c1 45 e4 f8 4b |a.Ue*.8.._A.E..K|
-00000090 3b 08 44 df 0b 72 11 93 cd d4 ff 36 0f 4f 3a a9 |;.D..r.....6.O:.|
-000000a0 4c 9f ab c7 ae 88 97 bc 1e ff 2d 27 39 a8 82 84 |L.........-'9...|
-000000b0 ae 33 94 48 8b 1c 58 9d 60 65 3c 3f 17 9d 6a eb |.3.H..X.`e<?..j.|
-000000c0 50 cd 65 04 bb c7 28 c8 0d 57 44 52 e0 17 de df |P.e...(..WDR....|
-000000d0 f3 13 b1 00 0d 00 20 00 1e 06 01 06 02 06 03 05 |...... .........|
-000000e0 01 05 02 05 03 04 01 04 02 04 03 03 01 03 02 03 |................|
-000000f0 03 02 01 02 02 02 03 00 0f 00 01 01 |............|
+00000000 16 03 01 00 f9 01 00 00 f5 03 03 e8 59 b4 a7 b2 |............Y...|
+00000010 77 86 57 47 0d d7 7b 2b c1 a2 04 fd 8d 4d e4 f5 |w.WG..{+.....M..|
+00000020 be e2 65 8e 28 9a fe c3 19 fc 43 20 40 38 fb 60 |..e.(.....C @8.`|
+00000030 f8 2f 36 f4 85 1d ee f1 53 f2 90 cf 3c 58 36 cd |./6.....S...<X6.|
+00000040 bd 22 b4 0c 92 a9 17 56 f9 b4 dd 9b 00 04 00 2f |.".....V......./|
+00000050 00 ff 01 00 00 a8 00 23 00 78 50 46 ad c1 db a8 |.......#.xPF....|
+00000060 38 86 7b 2b bb fd d0 c3 42 3e 00 00 00 00 00 00 |8.{+....B>......|
+00000070 00 00 00 00 00 00 00 00 00 00 94 6f 2c 9f 83 61 |...........o,..a|
+00000080 2e fe 48 fe f6 bb 98 a0 6f b0 be 9e 86 d7 b2 f2 |..H.....o.......|
+00000090 67 c7 44 c7 3d e4 2b de d0 f4 d2 17 51 84 8e 7a |g.D.=.+.....Q..z|
+000000a0 a7 80 c4 65 14 f7 49 09 68 15 56 68 32 41 d1 6f |...e..I.h.Vh2A.o|
+000000b0 33 94 a1 3a c9 37 20 5d e6 b0 6f 37 0a 10 e3 28 |3..:.7 ]..o7...(|
+000000c0 e1 34 b6 6d e6 7a 44 24 7f 2f cf 1b ae dd 4c d0 |.4.m.zD$./....L.|
+000000d0 11 75 00 0d 00 20 00 1e 06 01 06 02 06 03 05 01 |.u... ..........|
+000000e0 05 02 05 03 04 01 04 02 04 03 03 01 03 02 03 03 |................|
+000000f0 02 01 02 02 02 03 00 16 00 00 00 17 00 00 |..............|
>>> Flow 2 (server to client)
00000000 16 03 03 00 31 02 00 00 2d 03 03 00 00 00 00 00 |....1...-.......|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
-00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 05 00 00 |................|
-00000030 05 ff 01 00 01 00 16 03 03 02 71 0b 00 02 6d 00 |..........q...m.|
-00000040 02 6a 00 02 67 30 82 02 63 30 82 01 cc a0 03 02 |.j..g0..c0......|
-00000050 01 02 02 09 00 a2 73 00 0c 81 00 cb f3 30 0d 06 |......s......0..|
-00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 2b 31 17 |.*.H........0+1.|
-00000070 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 |0...U....Google |
-00000080 54 45 53 54 49 4e 47 31 10 30 0e 06 03 55 04 03 |TESTING1.0...U..|
-00000090 13 07 47 6f 20 52 6f 6f 74 30 1e 17 0d 31 35 30 |..Go Root0...150|
-000000a0 31 30 31 30 30 30 30 30 30 5a 17 0d 32 35 30 31 |101000000Z..2501|
-000000b0 30 31 30 30 30 30 30 30 5a 30 26 31 17 30 15 06 |01000000Z0&1.0..|
-000000c0 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 54 45 53 |.U....Google TES|
-000000d0 54 49 4e 47 31 0b 30 09 06 03 55 04 03 13 02 47 |TING1.0...U....G|
-000000e0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....|
-000000f0 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 af 87 |.......0........|
-00000100 88 f6 20 1b 95 65 6c 14 ab 44 05 af 3b 45 14 e3 |.. ..el..D..;E..|
-00000110 b7 6d fd 00 63 4d 95 7f fe 6a 62 35 86 c0 4a f9 |.m..cM...jb5..J.|
-00000120 18 7c f6 aa 25 5e 7a 64 31 66 00 ba f4 8e 92 af |.|..%^zd1f......|
-00000130 c7 6b d8 76 d4 f3 5f 41 cb 6e 56 15 97 1b 97 c1 |.k.v.._A.nV.....|
-00000140 3c 12 39 21 66 3d 2b 16 d1 bc db 1c c0 a7 da b7 |<.9!f=+.........|
-00000150 ca ad ba da cb d5 21 50 ec de 8d ab d1 6b 81 4b |......!P.....k.K|
-00000160 89 02 f3 c4 be c1 6c 89 b1 44 84 bd 21 d1 04 7d |......l..D..!..}|
-00000170 9d 16 4d f9 82 15 f6 ef fa d6 09 47 f2 fb 02 03 |..M........G....|
-00000180 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..|
-00000190 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%|
-000001a0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........|
-000001b0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...|
-000001c0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....|
-000001d0 10 12 50 8d 89 6f 1b d1 dc 54 4d 6e cb 69 5e 06 |..P..o...TMn.i^.|
-000001e0 f4 30 1b 06 03 55 1d 23 04 14 30 12 80 10 bf 3d |.0...U.#..0....=|
-000001f0 b6 a9 66 f2 b8 40 cf ea b4 03 78 48 1a 41 30 19 |..f.. at ....xH.A0.|
-00000200 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp|
-00000210 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H|
-00000220 86 f7 0d 01 01 0b 05 00 03 81 81 00 92 7c af 91 |.............|..|
-00000230 55 12 18 96 59 31 a6 48 40 d5 2d d5 ee bb 02 a0 |U...Y1.H at .-.....|
-00000240 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 da 4f 3d c0 fa |...|..0}<.v.O=..|
-00000250 ae 2d 33 24 6b 03 7b 1b 67 59 11 21 b5 11 bc 77 |.-3$k.{.gY.!...w|
-00000260 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f 22 3e 63 10 6b |...n.-.5.d_">c.k|
-00000270 be ff 14 86 6d 0d f0 15 31 a8 14 38 1e 3b 84 87 |....m...1..8.;..|
-00000280 2c cb 98 ed 51 76 b9 b1 4f dd db 9b 84 04 86 40 |,...Qv..O......@|
-00000290 fa 51 dd ba b4 8d eb e3 46 de 46 b9 4f 86 c7 f9 |.Q......F.F.O...|
-000002a0 a4 c2 41 34 ac cc f6 ea b0 ab 39 18 16 03 03 00 |..A4......9.....|
-000002b0 04 0e 00 00 00 |.....|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2f 00 00 |............./..|
+00000030 05 ff 01 00 01 00 16 03 03 02 59 0b 00 02 55 00 |..........Y...U.|
+00000040 02 52 00 02 4f 30 82 02 4b 30 82 01 b4 a0 03 02 |.R..O0..K0......|
+00000050 01 02 02 09 00 e8 f0 9d 3f e2 5b ea a6 30 0d 06 |........?.[..0..|
+00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 1f 31 0b |.*.H........0.1.|
+00000070 30 09 06 03 55 04 0a 13 02 47 6f 31 10 30 0e 06 |0...U....Go1.0..|
+00000080 03 55 04 03 13 07 47 6f 20 52 6f 6f 74 30 1e 17 |.U....Go Root0..|
+00000090 0d 31 36 30 31 30 31 30 30 30 30 30 30 5a 17 0d |.160101000000Z..|
+000000a0 32 35 30 31 30 31 30 30 30 30 30 30 5a 30 1a 31 |250101000000Z0.1|
+000000b0 0b 30 09 06 03 55 04 0a 13 02 47 6f 31 0b 30 09 |.0...U....Go1.0.|
+000000c0 06 03 55 04 03 13 02 47 6f 30 81 9f 30 0d 06 09 |..U....Go0..0...|
+000000d0 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 30 |*.H............0|
+000000e0 81 89 02 81 81 00 db 46 7d 93 2e 12 27 06 48 bc |.......F}...'.H.|
+000000f0 06 28 21 ab 7e c4 b6 a2 5d fe 1e 52 45 88 7a 36 |.(!.~...]..RE.z6|
+00000100 47 a5 08 0d 92 42 5b c2 81 c0 be 97 79 98 40 fb |G....B[.....y. at .|
+00000110 4f 6d 14 fd 2b 13 8b c2 a5 2e 67 d8 d4 09 9e d6 |Om..+.....g.....|
+00000120 22 38 b7 4a 0b 74 73 2b c2 34 f1 d1 93 e5 96 d9 |"8.J.ts+.4......|
+00000130 74 7b f3 58 9f 6c 61 3c c0 b0 41 d4 d9 2b 2b 24 |t{.X.la<..A..++$|
+00000140 23 77 5b 1c 3b bd 75 5d ce 20 54 cf a1 63 87 1d |#w[.;.u]. T..c..|
+00000150 1e 24 c4 f3 1d 1a 50 8b aa b6 14 43 ed 97 a7 75 |.$....P....C...u|
+00000160 62 f4 14 c8 52 d7 02 03 01 00 01 a3 81 93 30 81 |b...R.........0.|
+00000170 90 30 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 05 |.0...U..........|
+00000180 a0 30 1d 06 03 55 1d 25 04 16 30 14 06 08 2b 06 |.0...U.%..0...+.|
+00000190 01 05 05 07 03 01 06 08 2b 06 01 05 05 07 03 02 |........+.......|
+000001a0 30 0c 06 03 55 1d 13 01 01 ff 04 02 30 00 30 19 |0...U.......0.0.|
+000001b0 06 03 55 1d 0e 04 12 04 10 9f 91 16 1f 43 43 3e |..U..........CC>|
+000001c0 49 a6 de 6d b6 80 d7 9f 60 30 1b 06 03 55 1d 23 |I..m....`0...U.#|
+000001d0 04 14 30 12 80 10 48 13 49 4d 13 7e 16 31 bb a3 |..0...H.IM.~.1..|
+000001e0 01 d5 ac ab 6e 7b 30 19 06 03 55 1d 11 04 12 30 |....n{0...U....0|
+000001f0 10 82 0e 65 78 61 6d 70 6c 65 2e 67 6f 6c 61 6e |...example.golan|
+00000200 67 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 |g0...*.H........|
+00000210 03 81 81 00 9d 30 cc 40 2b 5b 50 a0 61 cb ba e5 |.....0. at +[P.a...|
+00000220 53 58 e1 ed 83 28 a9 58 1a a9 38 a4 95 a1 ac 31 |SX...(.X..8....1|
+00000230 5a 1a 84 66 3d 43 d3 2d d9 0b f2 97 df d3 20 64 |Z..f=C.-...... d|
+00000240 38 92 24 3a 00 bc cf 9c 7d b7 40 20 01 5f aa d3 |8.$:....}.@ ._..|
+00000250 16 61 09 a2 76 fd 13 c3 cc e1 0c 5c ee b1 87 82 |.a..v......\....|
+00000260 f1 6c 04 ed 73 bb b3 43 77 8d 0c 1c f1 0f a1 d8 |.l..s..Cw.......|
+00000270 40 83 61 c9 4c 72 2b 9d ae db 46 06 06 4d f4 c1 |@.a.Lr+...F..M..|
+00000280 b3 3e c0 d1 bd 42 d4 db fe 3d 13 60 84 5c 21 d3 |.>...B...=.`.\!.|
+00000290 3b e9 fa e7 16 03 03 00 04 0e 00 00 00 |;............|
>>> Flow 3 (client to server)
-00000000 16 03 03 00 86 10 00 00 82 00 80 ab d9 61 5e d3 |.............a^.|
-00000010 87 d7 eb 21 12 6f f9 61 dd 8b de 76 d7 14 70 2f |...!.o.a...v..p/|
-00000020 9c 0f 3c d4 4c 77 41 e2 ac 73 18 c3 0f 66 f2 b1 |..<.LwA..s...f..|
-00000030 fd 4b 1e d9 cb 5c 94 16 4d c2 98 f9 0d 55 f7 79 |.K...\..M....U.y|
-00000040 e2 8d 2c 87 96 e7 10 fb 78 fb ce 27 5d 9f ac 97 |..,.....x..']...|
-00000050 d6 54 6f 0c 78 dc 7b 2e 49 4c e2 42 24 b9 3d de |.To.x.{.IL.B$.=.|
-00000060 89 5f 1a 40 54 33 11 96 89 6f 59 25 5e 89 60 40 |._. at T3...oY%^.`@|
-00000070 83 8c 0e 92 0e 7d 68 9d 17 74 ba 39 e8 6f e3 43 |.....}h..t.9.o.C|
-00000080 44 80 e6 62 4b 35 43 21 5b eb 32 14 03 03 00 01 |D..bK5C![.2.....|
-00000090 01 16 03 03 00 24 77 1a b5 2c 88 d7 a6 83 f5 30 |.....$w..,.....0|
-000000a0 a0 c3 b4 45 a6 af 9b c2 ac 55 cf 73 4f a0 ba e5 |...E.....U.sO...|
-000000b0 2a be 9c 97 d2 d2 0b e9 95 0e |*.........|
+00000000 16 03 03 00 86 10 00 00 82 00 80 5e 04 66 f2 27 |...........^.f.'|
+00000010 99 3b f8 15 9f b8 4a ab 8c 32 10 0d 5b c9 5b 0b |.;....J..2..[.[.|
+00000020 04 69 dc 2b 9e bb 28 38 b6 a0 0f 32 ae 8c 96 64 |.i.+..(8...2...d|
+00000030 63 97 6b b6 63 94 45 84 03 28 d1 d8 85 2f a7 bb |c.k.c.E..(.../..|
+00000040 be ca 3e f5 30 27 e1 fd e5 cc bc b5 61 3d 26 8d |..>.0'......a=&.|
+00000050 0e 93 dd 78 07 5c fe 1b a9 57 c7 ce e6 df eb 28 |...x.\...W.....(|
+00000060 74 ce 12 f3 df 3f c0 9e 54 b6 e0 b0 ea f7 08 c6 |t....?..T.......|
+00000070 e1 9b cb e7 e9 41 b0 b4 68 2f f2 9b 1a 0a e3 17 |.....A..h/......|
+00000080 df d7 18 ff 95 ca 36 07 32 ff f9 14 03 03 00 01 |......6.2.......|
+00000090 01 16 03 03 00 40 cb c3 74 05 82 ab 93 07 a2 8b |..... at ..t.......|
+000000a0 24 27 c0 21 3e d1 15 12 9a 85 20 5b f5 7e 7e 0a |$'.!>..... [.~~.|
+000000b0 a0 8e b2 de aa 25 2a b3 3d 12 1b 01 45 ec 36 53 |.....%*.=...E.6S|
+000000c0 32 1d 81 c7 1d a6 96 c2 a9 2e af fa 90 6e 76 bb |2............nv.|
+000000d0 a2 bc 43 91 c9 ca |..C...|
>>> Flow 4 (server to client)
-00000000 14 03 03 00 01 01 16 03 03 00 24 a9 ae 0c a5 ed |..........$.....|
-00000010 51 10 d9 14 71 41 40 bd be f5 44 98 11 2f d8 0f |Q...qA at ...D../..|
-00000020 4d 42 bf 28 53 bf 02 7e d6 16 92 7f dd 03 ec 17 |MB.(S..~........|
-00000030 03 03 00 21 46 c2 68 a1 6a 35 67 e7 7d 62 71 43 |...!F.h.j5g.}bqC|
-00000040 6b ea d6 fc 22 fc 2d ad 45 d6 6d 98 9e e5 88 a0 |k...".-.E.m.....|
-00000050 ac 80 f7 6f 05 15 03 03 00 16 0c ae f4 fc 0e 09 |...o............|
-00000060 0b 09 73 69 83 0d 00 89 39 ff f6 20 4e 2b 88 3d |..si....9.. N+.=|
+00000000 14 03 03 00 01 01 16 03 03 00 40 00 00 00 00 00 |.......... at .....|
+00000010 00 00 00 00 00 00 00 00 00 00 00 7f 39 4c 83 d4 |............9L..|
+00000020 ca a2 7a a8 eb 3e 45 18 6e 33 3d 6f eb 2d 4f 72 |..z..>E.n3=o.-Or|
+00000030 35 ee c3 f8 22 fd 39 28 47 23 55 16 6c 47 80 b7 |5...".9(G#U.lG..|
+00000040 65 31 15 f6 89 79 96 bd 6a df 1d 17 03 03 00 40 |e1...y..j......@|
+00000050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000060 0c ea 0d 87 9a 24 d5 cc 26 9a a2 32 df 04 24 7d |.....$..&..2..$}|
+00000070 45 ed 35 4e 5b a0 57 c1 c7 f1 0f 8b b0 f9 49 85 |E.5N[.W.......I.|
+00000080 d6 e6 36 26 d5 f3 e4 00 76 d0 d6 20 be b3 31 e5 |..6&....v.. ..1.|
+00000090 15 03 03 00 30 00 00 00 00 00 00 00 00 00 00 00 |....0...........|
+000000a0 00 00 00 00 00 6c 51 e9 c2 e8 4f 43 e2 ce 01 9d |.....lQ...OC....|
+000000b0 d9 6f d7 c7 bf 16 d9 28 ca 8a ea 5e d5 84 ba 55 |.o.....(...^...U|
+000000c0 b7 23 9d 79 28 |.#.y(|
diff --git a/src/crypto/tls/testdata/Server-TLSv12-SNI b/src/crypto/tls/testdata/Server-TLSv12-SNI
index ae52ac2..852cc63 100644
--- a/src/crypto/tls/testdata/Server-TLSv12-SNI
+++ b/src/crypto/tls/testdata/Server-TLSv12-SNI
@@ -1,64 +1,81 @@
>>> Flow 1 (client to server)
-00000000 16 03 01 00 6f 01 00 00 6b 03 03 07 0f b6 b9 cc |....o...k.......|
-00000010 db 23 57 92 d0 9b 37 72 9d ad 9a 0d 17 6b dd b8 |.#W...7r.....k..|
-00000020 81 b7 7c 54 dd 68 fe 4e 28 00 39 00 00 04 00 2f |..|T.h.N(.9..../|
-00000030 00 ff 02 01 00 00 3d 00 00 00 10 00 0e 00 00 0b |......=.........|
-00000040 73 6e 69 74 65 73 74 2e 63 6f 6d 00 0d 00 20 00 |snitest.com... .|
-00000050 1e 06 01 06 02 06 03 05 01 05 02 05 03 04 01 04 |................|
-00000060 02 04 03 03 01 03 02 03 03 02 01 02 02 02 03 00 |................|
-00000070 0f 00 01 01 |....|
+00000000 16 03 01 00 71 01 00 00 6d 03 03 35 8f 03 0b f4 |....q...m..5....|
+00000010 81 dd d7 ec 8b cc 85 bd 07 5b 83 16 cc 6e b2 67 |.........[...n.g|
+00000020 fd 33 69 81 14 9a 14 9d 37 43 5a 00 00 04 00 2f |.3i.....7CZ..../|
+00000030 00 ff 01 00 00 40 00 00 00 10 00 0e 00 00 0b 73 |..... at .........s|
+00000040 6e 69 74 65 73 74 2e 63 6f 6d 00 0d 00 20 00 1e |nitest.com... ..|
+00000050 06 01 06 02 06 03 05 01 05 02 05 03 04 01 04 02 |................|
+00000060 04 03 03 01 03 02 03 03 02 01 02 02 02 03 00 16 |................|
+00000070 00 00 00 17 00 00 |......|
>>> Flow 2 (server to client)
00000000 16 03 03 00 31 02 00 00 2d 03 03 00 00 00 00 00 |....1...-.......|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2f 00 00 |............./..|
-00000030 05 ff 01 00 01 00 16 03 03 02 00 0b 00 01 fc 00 |................|
-00000040 01 f9 00 01 f6 30 82 01 f2 30 82 01 5d a0 03 02 |.....0...0..]...|
-00000050 01 02 02 01 00 30 0b 06 09 2a 86 48 86 f7 0d 01 |.....0...*.H....|
-00000060 01 05 30 28 31 10 30 0e 06 03 55 04 0a 13 07 41 |..0(1.0...U....A|
-00000070 63 6d 65 20 43 6f 31 14 30 12 06 03 55 04 03 13 |cme Co1.0...U...|
-00000080 0b 73 6e 69 74 65 73 74 2e 63 6f 6d 30 1e 17 0d |.snitest.com0...|
-00000090 31 32 30 34 31 31 31 37 34 30 33 35 5a 17 0d 31 |120411174035Z..1|
-000000a0 33 30 34 31 31 31 37 34 35 33 35 5a 30 28 31 10 |30411174535Z0(1.|
-000000b0 30 0e 06 03 55 04 0a 13 07 41 63 6d 65 20 43 6f |0...U....Acme Co|
-000000c0 31 14 30 12 06 03 55 04 03 13 0b 73 6e 69 74 65 |1.0...U....snite|
-000000d0 73 74 2e 63 6f 6d 30 81 9d 30 0b 06 09 2a 86 48 |st.com0..0...*.H|
-000000e0 86 f7 0d 01 01 01 03 81 8d 00 30 81 89 02 81 81 |..........0.....|
-000000f0 00 bb 79 d6 f5 17 b5 e5 bf 46 10 d0 dc 69 be e6 |..y......F...i..|
-00000100 2b 07 43 5a d0 03 2d 8a 7a 43 85 b7 14 52 e7 a5 |+.CZ..-.zC...R..|
-00000110 65 4c 2c 78 b8 23 8c b5 b4 82 e5 de 1f 95 3b 7e |eL,x.#........;~|
-00000120 62 a5 2c a5 33 d6 fe 12 5c 7a 56 fc f5 06 bf fa |b.,.3...\zV.....|
-00000130 58 7b 26 3f b5 cd 04 d3 d0 c9 21 96 4a c7 f4 54 |X{&?......!.J..T|
-00000140 9f 5a bf ef 42 71 00 fe 18 99 07 7f 7e 88 7d 7d |.Z..Bq......~.}}|
-00000150 f1 04 39 c4 a2 2e db 51 c9 7c e3 c0 4c 3b 32 66 |..9....Q.|..L;2f|
-00000160 01 cf af b1 1d b8 71 9a 1d db db 89 6b ae da 2d |......q.....k..-|
-00000170 79 02 03 01 00 01 a3 32 30 30 30 0e 06 03 55 1d |y......2000...U.|
-00000180 0f 01 01 ff 04 04 03 02 00 a0 30 0d 06 03 55 1d |..........0...U.|
-00000190 0e 04 06 04 04 01 02 03 04 30 0f 06 03 55 1d 23 |.........0...U.#|
-000001a0 04 08 30 06 80 04 01 02 03 04 30 0b 06 09 2a 86 |..0.......0...*.|
-000001b0 48 86 f7 0d 01 01 05 03 81 81 00 89 c6 45 5f 1c |H............E_.|
-000001c0 1f 5e f8 eb 1a b1 74 ee 24 39 05 9f 5c 42 59 bb |.^....t.$9..\BY.|
-000001d0 1a 8d 86 cd b1 d0 56 f5 6a 71 7d a4 0e 95 ab 90 |......V.jq}.....|
-000001e0 f5 9e 8d ea f6 27 c1 57 99 50 94 db 08 02 26 6e |.....'.W.P....&n|
-000001f0 b3 4f c6 84 2d ea 8a 4b 68 d9 c1 38 91 03 ab 84 |.O..-..Kh..8....|
-00000200 fb 9e 1f 85 d9 b5 d2 3f f2 31 2c 86 70 fb b5 40 |.......?.1,.p..@|
-00000210 14 82 45 a4 eb af e2 64 d9 0c 8a 4c f4 f8 5b 0f |..E....d...L..[.|
-00000220 ac 12 ac 2f c4 a3 15 4b ad 52 46 28 68 af 96 c6 |.../...K.RF(h...|
-00000230 2c 65 25 d6 52 b6 e3 18 45 bd cc 16 03 03 00 04 |,e%.R...E.......|
-00000240 0e 00 00 00 |....|
+00000030 05 ff 01 00 01 00 16 03 03 02 59 0b 00 02 55 00 |..........Y...U.|
+00000040 02 52 00 02 4f 30 82 02 4b 30 82 01 b4 a0 03 02 |.R..O0..K0......|
+00000050 01 02 02 09 00 e8 f0 9d 3f e2 5b ea a6 30 0d 06 |........?.[..0..|
+00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 1f 31 0b |.*.H........0.1.|
+00000070 30 09 06 03 55 04 0a 13 02 47 6f 31 10 30 0e 06 |0...U....Go1.0..|
+00000080 03 55 04 03 13 07 47 6f 20 52 6f 6f 74 30 1e 17 |.U....Go Root0..|
+00000090 0d 31 36 30 31 30 31 30 30 30 30 30 30 5a 17 0d |.160101000000Z..|
+000000a0 32 35 30 31 30 31 30 30 30 30 30 30 5a 30 1a 31 |250101000000Z0.1|
+000000b0 0b 30 09 06 03 55 04 0a 13 02 47 6f 31 0b 30 09 |.0...U....Go1.0.|
+000000c0 06 03 55 04 03 13 02 47 6f 30 81 9f 30 0d 06 09 |..U....Go0..0...|
+000000d0 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 30 |*.H............0|
+000000e0 81 89 02 81 81 00 db 46 7d 93 2e 12 27 06 48 bc |.......F}...'.H.|
+000000f0 06 28 21 ab 7e c4 b6 a2 5d fe 1e 52 45 88 7a 36 |.(!.~...]..RE.z6|
+00000100 47 a5 08 0d 92 42 5b c2 81 c0 be 97 79 98 40 fb |G....B[.....y. at .|
+00000110 4f 6d 14 fd 2b 13 8b c2 a5 2e 67 d8 d4 09 9e d6 |Om..+.....g.....|
+00000120 22 38 b7 4a 0b 74 73 2b c2 34 f1 d1 93 e5 96 d9 |"8.J.ts+.4......|
+00000130 74 7b f3 58 9f 6c 61 3c c0 b0 41 d4 d9 2b 2b 24 |t{.X.la<..A..++$|
+00000140 23 77 5b 1c 3b bd 75 5d ce 20 54 cf a1 63 87 1d |#w[.;.u]. T..c..|
+00000150 1e 24 c4 f3 1d 1a 50 8b aa b6 14 43 ed 97 a7 75 |.$....P....C...u|
+00000160 62 f4 14 c8 52 d7 02 03 01 00 01 a3 81 93 30 81 |b...R.........0.|
+00000170 90 30 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 05 |.0...U..........|
+00000180 a0 30 1d 06 03 55 1d 25 04 16 30 14 06 08 2b 06 |.0...U.%..0...+.|
+00000190 01 05 05 07 03 01 06 08 2b 06 01 05 05 07 03 02 |........+.......|
+000001a0 30 0c 06 03 55 1d 13 01 01 ff 04 02 30 00 30 19 |0...U.......0.0.|
+000001b0 06 03 55 1d 0e 04 12 04 10 9f 91 16 1f 43 43 3e |..U..........CC>|
+000001c0 49 a6 de 6d b6 80 d7 9f 60 30 1b 06 03 55 1d 23 |I..m....`0...U.#|
+000001d0 04 14 30 12 80 10 48 13 49 4d 13 7e 16 31 bb a3 |..0...H.IM.~.1..|
+000001e0 01 d5 ac ab 6e 7b 30 19 06 03 55 1d 11 04 12 30 |....n{0...U....0|
+000001f0 10 82 0e 65 78 61 6d 70 6c 65 2e 67 6f 6c 61 6e |...example.golan|
+00000200 67 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 |g0...*.H........|
+00000210 03 81 81 00 9d 30 cc 40 2b 5b 50 a0 61 cb ba e5 |.....0. at +[P.a...|
+00000220 53 58 e1 ed 83 28 a9 58 1a a9 38 a4 95 a1 ac 31 |SX...(.X..8....1|
+00000230 5a 1a 84 66 3d 43 d3 2d d9 0b f2 97 df d3 20 64 |Z..f=C.-...... d|
+00000240 38 92 24 3a 00 bc cf 9c 7d b7 40 20 01 5f aa d3 |8.$:....}.@ ._..|
+00000250 16 61 09 a2 76 fd 13 c3 cc e1 0c 5c ee b1 87 82 |.a..v......\....|
+00000260 f1 6c 04 ed 73 bb b3 43 77 8d 0c 1c f1 0f a1 d8 |.l..s..Cw.......|
+00000270 40 83 61 c9 4c 72 2b 9d ae db 46 06 06 4d f4 c1 |@.a.Lr+...F..M..|
+00000280 b3 3e c0 d1 bd 42 d4 db fe 3d 13 60 84 5c 21 d3 |.>...B...=.`.\!.|
+00000290 3b e9 fa e7 16 03 03 00 04 0e 00 00 00 |;............|
>>> Flow 3 (client to server)
-00000000 16 03 03 00 86 10 00 00 82 00 80 72 6a 6f a8 c9 |...........rjo..|
-00000010 3e 4c 33 da 92 23 97 68 fc 4e ca 74 77 98 f3 88 |>L3..#.h.N.tw...|
-00000020 ba a0 55 b6 a0 6f ff c8 db 2b 90 17 1f 45 bc 26 |..U..o...+...E.&|
-00000030 62 6e b9 91 96 b9 03 5d eb f2 a2 59 87 7b 81 4a |bn.....]...Y.{.J|
-00000040 0c f9 e2 23 60 e3 c7 4d 53 4f 3a 1f c5 5f dd 15 |...#`..MSO:.._..|
-00000050 cc 78 c5 21 fd 33 02 68 77 7c 8d 5f e8 80 a7 84 |.x.!.3.hw|._....|
-00000060 a7 2c b3 1f 64 df 8a 63 e9 b3 24 02 c1 6a 94 bd |.,..d..c..$..j..|
-00000070 a1 62 e5 32 e5 d9 83 25 0d 0f 1a 02 90 8a cd 79 |.b.2...%.......y|
-00000080 1c bd 4a c2 f4 5d a0 24 c6 c1 ae 14 03 03 00 01 |..J..].$........|
-00000090 01 16 03 03 00 40 1f 1a 17 47 15 25 5b 3d 5f e5 |..... at ...G.%[=_.|
-000000a0 f4 d9 64 47 5f 80 09 f7 dd 5a ff 58 19 08 b5 db |..dG_....Z.X....|
-000000b0 38 88 a4 44 07 01 fb 80 1d 89 b2 d4 af 95 80 b3 |8..D............|
-000000c0 75 13 82 0e 24 12 1d 5c 29 72 1d 21 d4 69 16 e0 |u...$..\)r.!.i..|
-000000d0 b5 4b 46 62 fe f7 |.KFb..|
+00000000 16 03 03 00 86 10 00 00 82 00 80 4c 15 46 23 91 |...........L.F#.|
+00000010 a0 d8 6c 45 f0 49 7e 70 84 9f bf 53 3d 68 2c cc |..lE.I~p...S=h,.|
+00000020 20 3f 28 bd cf e6 6e fd e6 90 ff 87 14 82 65 00 | ?(...n.......e.|
+00000030 d6 b6 ef 5a 0c d6 30 76 88 d2 37 33 39 de 00 b4 |...Z..0v..739...|
+00000040 ec dd 30 3b f6 88 ff 4c b2 98 75 77 fd c3 61 38 |..0;...L..uw..a8|
+00000050 2d 00 f7 14 d8 a4 37 22 c0 db 8a bd 12 0b b8 cc |-.....7"........|
+00000060 37 82 78 d3 0e f2 0b 9b 51 c5 26 c5 e2 ce 3e 0e |7.x.....Q.&...>.|
+00000070 04 34 39 83 a8 f5 65 ff 40 d9 9b 4a 11 6b b3 d2 |.49...e. at ..J.k..|
+00000080 f7 02 78 a9 7c f4 69 56 3a a4 98 14 03 03 00 01 |..x.|.iV:.......|
+00000090 01 16 03 03 00 40 d6 90 b3 07 d1 a1 c1 12 35 07 |..... at ........5.|
+000000a0 4e c0 df 4b 17 cc fa 49 47 c9 22 c3 6f 70 fa ee |N..K...IG.".op..|
+000000b0 cf b3 61 d6 06 54 cd ce c2 15 17 8a a0 f6 5c 43 |..a..T........\C|
+000000c0 7c 92 ce 89 d4 96 53 d0 c7 e6 9a 24 bc 5a 83 e5 ||.....S....$.Z..|
+000000d0 9c 65 72 e7 80 a4 |.er...|
>>> Flow 4 (server to client)
-00000000 15 03 03 00 02 02 14 |.......|
+00000000 14 03 03 00 01 01 16 03 03 00 40 00 00 00 00 00 |.......... at .....|
+00000010 00 00 00 00 00 00 00 00 00 00 00 a0 61 69 4c 9d |............aiL.|
+00000020 68 f3 f8 f6 a0 ef 1b f4 a2 f5 83 fa 03 87 ad 67 |h..............g|
+00000030 7e 9f df c6 ce 9f 69 ce 22 fc de 91 0d 18 00 fb |~.....i.".......|
+00000040 c1 5d a1 2d bb 89 29 4f f6 de 57 17 03 03 00 40 |.].-..)O..W....@|
+00000050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000060 bb 54 f4 80 69 1d 3b 9c e7 9c 1a fb 4e 3d c1 02 |.T..i.;.....N=..|
+00000070 d3 05 86 35 47 61 59 aa 45 54 ae a2 59 4c 75 8c |...5GaY.ET..YLu.|
+00000080 8d a9 7d 7f a0 4b d9 65 7a 53 ef 7e ed a3 fa 9e |..}..K.ezS.~....|
+00000090 15 03 03 00 30 00 00 00 00 00 00 00 00 00 00 00 |....0...........|
+000000a0 00 00 00 00 00 cc fd 0f cb 74 a5 36 ce c1 cd 54 |.........t.6...T|
+000000b0 6f 66 81 c0 ab ff 72 ea f3 1f a6 b7 ef 46 45 68 |of....r......FEh|
+000000c0 9b 0b 7f 4f 46 |...OF|
diff --git a/src/crypto/tls/testdata/Server-TLSv12-SNI-GetCertificate b/src/crypto/tls/testdata/Server-TLSv12-SNI-GetCertificate
index 7ac8dc9..b35cd8d 100644
--- a/src/crypto/tls/testdata/Server-TLSv12-SNI-GetCertificate
+++ b/src/crypto/tls/testdata/Server-TLSv12-SNI-GetCertificate
@@ -1,64 +1,81 @@
>>> Flow 1 (client to server)
-00000000 16 03 01 00 6f 01 00 00 6b 03 03 fe d6 ce b5 1b |....o...k.......|
-00000010 1c 50 0c db 9c 35 5d 0e f2 ee 57 3f 65 83 9f 28 |.P...5]...W?e..(|
-00000020 96 50 1c e0 7f 95 f9 17 39 4f c3 00 00 04 00 2f |.P......9O...../|
-00000030 00 ff 02 01 00 00 3d 00 00 00 10 00 0e 00 00 0b |......=.........|
-00000040 73 6e 69 74 65 73 74 2e 63 6f 6d 00 0d 00 20 00 |snitest.com... .|
-00000050 1e 06 01 06 02 06 03 05 01 05 02 05 03 04 01 04 |................|
-00000060 02 04 03 03 01 03 02 03 03 02 01 02 02 02 03 00 |................|
-00000070 0f 00 01 01 |....|
+00000000 16 03 01 00 71 01 00 00 6d 03 03 31 c7 3f 2b 99 |....q...m..1.?+.|
+00000010 95 d8 d5 b7 91 ab 95 c6 09 35 0c 2b bd b6 94 1e |.........5.+....|
+00000020 64 4a 2d b6 43 23 a0 01 e7 93 22 00 00 04 00 2f |dJ-.C#...."..../|
+00000030 00 ff 01 00 00 40 00 00 00 10 00 0e 00 00 0b 73 |..... at .........s|
+00000040 6e 69 74 65 73 74 2e 63 6f 6d 00 0d 00 20 00 1e |nitest.com... ..|
+00000050 06 01 06 02 06 03 05 01 05 02 05 03 04 01 04 02 |................|
+00000060 04 03 03 01 03 02 03 03 02 01 02 02 02 03 00 16 |................|
+00000070 00 00 00 17 00 00 |......|
>>> Flow 2 (server to client)
00000000 16 03 03 00 31 02 00 00 2d 03 03 00 00 00 00 00 |....1...-.......|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2f 00 00 |............./..|
-00000030 05 ff 01 00 01 00 16 03 03 02 00 0b 00 01 fc 00 |................|
-00000040 01 f9 00 01 f6 30 82 01 f2 30 82 01 5d a0 03 02 |.....0...0..]...|
-00000050 01 02 02 01 00 30 0b 06 09 2a 86 48 86 f7 0d 01 |.....0...*.H....|
-00000060 01 05 30 28 31 10 30 0e 06 03 55 04 0a 13 07 41 |..0(1.0...U....A|
-00000070 63 6d 65 20 43 6f 31 14 30 12 06 03 55 04 03 13 |cme Co1.0...U...|
-00000080 0b 73 6e 69 74 65 73 74 2e 63 6f 6d 30 1e 17 0d |.snitest.com0...|
-00000090 31 32 30 34 31 31 31 37 34 30 33 35 5a 17 0d 31 |120411174035Z..1|
-000000a0 33 30 34 31 31 31 37 34 35 33 35 5a 30 28 31 10 |30411174535Z0(1.|
-000000b0 30 0e 06 03 55 04 0a 13 07 41 63 6d 65 20 43 6f |0...U....Acme Co|
-000000c0 31 14 30 12 06 03 55 04 03 13 0b 73 6e 69 74 65 |1.0...U....snite|
-000000d0 73 74 2e 63 6f 6d 30 81 9d 30 0b 06 09 2a 86 48 |st.com0..0...*.H|
-000000e0 86 f7 0d 01 01 01 03 81 8d 00 30 81 89 02 81 81 |..........0.....|
-000000f0 00 bb 79 d6 f5 17 b5 e5 bf 46 10 d0 dc 69 be e6 |..y......F...i..|
-00000100 2b 07 43 5a d0 03 2d 8a 7a 43 85 b7 14 52 e7 a5 |+.CZ..-.zC...R..|
-00000110 65 4c 2c 78 b8 23 8c b5 b4 82 e5 de 1f 95 3b 7e |eL,x.#........;~|
-00000120 62 a5 2c a5 33 d6 fe 12 5c 7a 56 fc f5 06 bf fa |b.,.3...\zV.....|
-00000130 58 7b 26 3f b5 cd 04 d3 d0 c9 21 96 4a c7 f4 54 |X{&?......!.J..T|
-00000140 9f 5a bf ef 42 71 00 fe 18 99 07 7f 7e 88 7d 7d |.Z..Bq......~.}}|
-00000150 f1 04 39 c4 a2 2e db 51 c9 7c e3 c0 4c 3b 32 66 |..9....Q.|..L;2f|
-00000160 01 cf af b1 1d b8 71 9a 1d db db 89 6b ae da 2d |......q.....k..-|
-00000170 79 02 03 01 00 01 a3 32 30 30 30 0e 06 03 55 1d |y......2000...U.|
-00000180 0f 01 01 ff 04 04 03 02 00 a0 30 0d 06 03 55 1d |..........0...U.|
-00000190 0e 04 06 04 04 01 02 03 04 30 0f 06 03 55 1d 23 |.........0...U.#|
-000001a0 04 08 30 06 80 04 01 02 03 04 30 0b 06 09 2a 86 |..0.......0...*.|
-000001b0 48 86 f7 0d 01 01 05 03 81 81 00 89 c6 45 5f 1c |H............E_.|
-000001c0 1f 5e f8 eb 1a b1 74 ee 24 39 05 9f 5c 42 59 bb |.^....t.$9..\BY.|
-000001d0 1a 8d 86 cd b1 d0 56 f5 6a 71 7d a4 0e 95 ab 90 |......V.jq}.....|
-000001e0 f5 9e 8d ea f6 27 c1 57 99 50 94 db 08 02 26 6e |.....'.W.P....&n|
-000001f0 b3 4f c6 84 2d ea 8a 4b 68 d9 c1 38 91 03 ab 84 |.O..-..Kh..8....|
-00000200 fb 9e 1f 85 d9 b5 d2 3f f2 31 2c 86 70 fb b5 40 |.......?.1,.p..@|
-00000210 14 82 45 a4 eb af e2 64 d9 0c 8a 4c f4 f8 5b 0f |..E....d...L..[.|
-00000220 ac 12 ac 2f c4 a3 15 4b ad 52 46 28 68 af 96 c6 |.../...K.RF(h...|
-00000230 2c 65 25 d6 52 b6 e3 18 45 bd cc 16 03 03 00 04 |,e%.R...E.......|
-00000240 0e 00 00 00 |....|
+00000030 05 ff 01 00 01 00 16 03 03 02 59 0b 00 02 55 00 |..........Y...U.|
+00000040 02 52 00 02 4f 30 82 02 4b 30 82 01 b4 a0 03 02 |.R..O0..K0......|
+00000050 01 02 02 09 00 e8 f0 9d 3f e2 5b ea a6 30 0d 06 |........?.[..0..|
+00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 1f 31 0b |.*.H........0.1.|
+00000070 30 09 06 03 55 04 0a 13 02 47 6f 31 10 30 0e 06 |0...U....Go1.0..|
+00000080 03 55 04 03 13 07 47 6f 20 52 6f 6f 74 30 1e 17 |.U....Go Root0..|
+00000090 0d 31 36 30 31 30 31 30 30 30 30 30 30 5a 17 0d |.160101000000Z..|
+000000a0 32 35 30 31 30 31 30 30 30 30 30 30 5a 30 1a 31 |250101000000Z0.1|
+000000b0 0b 30 09 06 03 55 04 0a 13 02 47 6f 31 0b 30 09 |.0...U....Go1.0.|
+000000c0 06 03 55 04 03 13 02 47 6f 30 81 9f 30 0d 06 09 |..U....Go0..0...|
+000000d0 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 30 |*.H............0|
+000000e0 81 89 02 81 81 00 db 46 7d 93 2e 12 27 06 48 bc |.......F}...'.H.|
+000000f0 06 28 21 ab 7e c4 b6 a2 5d fe 1e 52 45 88 7a 36 |.(!.~...]..RE.z6|
+00000100 47 a5 08 0d 92 42 5b c2 81 c0 be 97 79 98 40 fb |G....B[.....y. at .|
+00000110 4f 6d 14 fd 2b 13 8b c2 a5 2e 67 d8 d4 09 9e d6 |Om..+.....g.....|
+00000120 22 38 b7 4a 0b 74 73 2b c2 34 f1 d1 93 e5 96 d9 |"8.J.ts+.4......|
+00000130 74 7b f3 58 9f 6c 61 3c c0 b0 41 d4 d9 2b 2b 24 |t{.X.la<..A..++$|
+00000140 23 77 5b 1c 3b bd 75 5d ce 20 54 cf a1 63 87 1d |#w[.;.u]. T..c..|
+00000150 1e 24 c4 f3 1d 1a 50 8b aa b6 14 43 ed 97 a7 75 |.$....P....C...u|
+00000160 62 f4 14 c8 52 d7 02 03 01 00 01 a3 81 93 30 81 |b...R.........0.|
+00000170 90 30 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 05 |.0...U..........|
+00000180 a0 30 1d 06 03 55 1d 25 04 16 30 14 06 08 2b 06 |.0...U.%..0...+.|
+00000190 01 05 05 07 03 01 06 08 2b 06 01 05 05 07 03 02 |........+.......|
+000001a0 30 0c 06 03 55 1d 13 01 01 ff 04 02 30 00 30 19 |0...U.......0.0.|
+000001b0 06 03 55 1d 0e 04 12 04 10 9f 91 16 1f 43 43 3e |..U..........CC>|
+000001c0 49 a6 de 6d b6 80 d7 9f 60 30 1b 06 03 55 1d 23 |I..m....`0...U.#|
+000001d0 04 14 30 12 80 10 48 13 49 4d 13 7e 16 31 bb a3 |..0...H.IM.~.1..|
+000001e0 01 d5 ac ab 6e 7b 30 19 06 03 55 1d 11 04 12 30 |....n{0...U....0|
+000001f0 10 82 0e 65 78 61 6d 70 6c 65 2e 67 6f 6c 61 6e |...example.golan|
+00000200 67 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 |g0...*.H........|
+00000210 03 81 81 00 9d 30 cc 40 2b 5b 50 a0 61 cb ba e5 |.....0. at +[P.a...|
+00000220 53 58 e1 ed 83 28 a9 58 1a a9 38 a4 95 a1 ac 31 |SX...(.X..8....1|
+00000230 5a 1a 84 66 3d 43 d3 2d d9 0b f2 97 df d3 20 64 |Z..f=C.-...... d|
+00000240 38 92 24 3a 00 bc cf 9c 7d b7 40 20 01 5f aa d3 |8.$:....}.@ ._..|
+00000250 16 61 09 a2 76 fd 13 c3 cc e1 0c 5c ee b1 87 82 |.a..v......\....|
+00000260 f1 6c 04 ed 73 bb b3 43 77 8d 0c 1c f1 0f a1 d8 |.l..s..Cw.......|
+00000270 40 83 61 c9 4c 72 2b 9d ae db 46 06 06 4d f4 c1 |@.a.Lr+...F..M..|
+00000280 b3 3e c0 d1 bd 42 d4 db fe 3d 13 60 84 5c 21 d3 |.>...B...=.`.\!.|
+00000290 3b e9 fa e7 16 03 03 00 04 0e 00 00 00 |;............|
>>> Flow 3 (client to server)
-00000000 16 03 03 00 86 10 00 00 82 00 80 6f bc 33 c8 2d |...........o.3.-|
-00000010 5a 50 65 2f 06 1a 45 16 9e 5b ab 97 43 b1 9e 96 |ZPe/..E..[..C...|
-00000020 b5 4a fe c3 7c e8 e4 07 ea 00 47 d2 51 23 11 ae |.J..|.....G.Q#..|
-00000030 11 a8 79 71 b9 c6 82 17 40 ae c7 fc cd 05 4d 6d |..yq.... at .....Mm|
-00000040 cb bc f1 ce 30 d0 10 37 4a e6 aa d3 14 fb bc 62 |....0..7J......b|
-00000050 eb 6c fa ec e1 e1 dd 63 39 95 0b 87 71 a0 83 ba |.l.....c9...q...|
-00000060 bf 25 f8 a9 d3 c4 35 e1 88 23 85 56 c6 f4 0b 10 |.%....5..#.V....|
-00000070 d1 70 f8 0a 3d a1 08 17 ce 27 2d 4c a7 c5 b5 0d |.p..=....'-L....|
-00000080 f2 43 b7 b9 02 21 7a eb 40 d2 66 14 03 03 00 01 |.C...!z. at .f.....|
-00000090 01 16 03 03 00 40 0a 93 47 0b 6e 40 ff cd 09 a5 |..... at ..G.n@....|
-000000a0 bc a4 c5 a8 c3 1c 0a fb d4 2e 8a 2f 0c f3 d6 e1 |.........../....|
-000000b0 de 1f 56 2f 09 61 2d 31 d5 b1 29 6b f2 18 8b f2 |..V/.a-1..)k....|
-000000c0 0c 0e 09 5f ec 11 56 af 44 8b e5 2d 09 68 eb c2 |..._..V.D..-.h..|
-000000d0 91 4d 04 b2 10 02 |.M....|
+00000000 16 03 03 00 86 10 00 00 82 00 80 c9 3a 9d ea e3 |............:...|
+00000010 19 f1 07 77 61 ef 5a aa ed 0f 26 b4 7a 45 db 05 |...wa.Z...&.zE..|
+00000020 bd 51 77 f5 ee 7b c1 83 9c 95 49 7b 70 5e 5b fe |.Qw..{....I{p^[.|
+00000030 25 d2 3d 64 74 b8 a4 97 fd cb b9 75 7b 8f b0 59 |%.=dt......u{..Y|
+00000040 30 bf b3 41 ce 54 83 0a ca 29 49 5a fe 29 4c 53 |0..A.T...)IZ.)LS|
+00000050 fb d6 6e 46 d9 f7 31 17 d6 ee f9 ac 41 82 22 11 |..nF..1.....A.".|
+00000060 a7 34 07 41 50 43 2f 83 f6 1f c6 c0 9d 4a 67 5a |.4.APC/......JgZ|
+00000070 af 44 59 c0 00 33 be 24 f7 0a a4 fe 76 6b 03 05 |.DY..3.$....vk..|
+00000080 2e ec 4d 49 db 6e e5 0a 5f af 09 14 03 03 00 01 |..MI.n.._.......|
+00000090 01 16 03 03 00 40 ad 89 4d 25 a2 ce 98 8c cf b6 |..... at ..M%......|
+000000a0 f5 f4 76 6b e7 71 66 4a f9 a7 67 fb 1d 6c a7 83 |..vk.qfJ..g..l..|
+000000b0 3b 1d 6a af 65 f2 c1 1d 97 03 5b c2 34 ee 3b 8e |;.j.e.....[.4.;.|
+000000c0 cc bd 8f 3a b8 9b 4f 90 3f de 1e 97 1e 8e 61 37 |...:..O.?.....a7|
+000000d0 2d 30 35 84 3b 26 |-05.;&|
>>> Flow 4 (server to client)
-00000000 15 03 03 00 02 02 14 |.......|
+00000000 14 03 03 00 01 01 16 03 03 00 40 00 00 00 00 00 |.......... at .....|
+00000010 00 00 00 00 00 00 00 00 00 00 00 fe 23 de 33 4b |............#.3K|
+00000020 55 f2 8e 73 09 ba ae f1 12 bd f7 15 75 90 8f 19 |U..s........u...|
+00000030 1b 19 b6 3f 2c 19 47 87 a9 43 d5 1e 85 fb 0c 90 |...?,.G..C......|
+00000040 c8 18 72 8f 08 6f 48 43 3c 5c 5a 17 03 03 00 40 |..r..oHC<\Z....@|
+00000050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000060 4d 44 d7 eb a3 94 00 74 90 9d c0 bd 8e 11 eb b6 |MD.....t........|
+00000070 93 43 c6 14 0d ba c2 aa f0 f5 2d 85 9a 7c 27 44 |.C........-..|'D|
+00000080 fc d8 46 76 b2 21 4f 70 1a 9a df 9e 3a 8f a3 58 |..Fv.!Op....:..X|
+00000090 15 03 03 00 30 00 00 00 00 00 00 00 00 00 00 00 |....0...........|
+000000a0 00 00 00 00 00 91 0f c3 2a 98 79 57 39 3c 68 98 |........*.yW9<h.|
+000000b0 df 36 12 de e5 15 ee cb 80 ce 33 d9 20 95 33 38 |.6........3. .38|
+000000c0 8b d8 ed 8f 9b |.....|
diff --git a/src/crypto/tls/testdata/Server-TLSv12-SNI-GetCertificateNotFound b/src/crypto/tls/testdata/Server-TLSv12-SNI-GetCertificateNotFound
index 32c0d4a..8ba207b 100644
--- a/src/crypto/tls/testdata/Server-TLSv12-SNI-GetCertificateNotFound
+++ b/src/crypto/tls/testdata/Server-TLSv12-SNI-GetCertificateNotFound
@@ -1,64 +1,81 @@
>>> Flow 1 (client to server)
-00000000 16 03 01 00 6f 01 00 00 6b 03 03 64 29 6e 67 3d |....o...k..d)ng=|
-00000010 5a 13 48 8a ae a5 67 6b 2f 5b 76 d2 c1 df 23 c6 |Z.H...gk/[v...#.|
-00000020 f9 52 26 33 ce 0b 03 f6 53 a7 db 00 00 04 00 2f |.R&3....S....../|
-00000030 00 ff 02 01 00 00 3d 00 00 00 10 00 0e 00 00 0b |......=.........|
-00000040 73 6e 69 74 65 73 74 2e 63 6f 6d 00 0d 00 20 00 |snitest.com... .|
-00000050 1e 06 01 06 02 06 03 05 01 05 02 05 03 04 01 04 |................|
-00000060 02 04 03 03 01 03 02 03 03 02 01 02 02 02 03 00 |................|
-00000070 0f 00 01 01 |....|
+00000000 16 03 01 00 71 01 00 00 6d 03 03 f8 16 6b 20 c3 |....q...m....k .|
+00000010 a4 cf fc ca 04 47 7a f9 cc d9 cf 4a 15 ff 6e 82 |.....Gz....J..n.|
+00000020 14 6a 91 91 7f f1 f4 42 e6 7c d4 00 00 04 00 2f |.j.....B.|...../|
+00000030 00 ff 01 00 00 40 00 00 00 10 00 0e 00 00 0b 73 |..... at .........s|
+00000040 6e 69 74 65 73 74 2e 63 6f 6d 00 0d 00 20 00 1e |nitest.com... ..|
+00000050 06 01 06 02 06 03 05 01 05 02 05 03 04 01 04 02 |................|
+00000060 04 03 03 01 03 02 03 03 02 01 02 02 02 03 00 16 |................|
+00000070 00 00 00 17 00 00 |......|
>>> Flow 2 (server to client)
00000000 16 03 03 00 31 02 00 00 2d 03 03 00 00 00 00 00 |....1...-.......|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2f 00 00 |............./..|
-00000030 05 ff 01 00 01 00 16 03 03 02 00 0b 00 01 fc 00 |................|
-00000040 01 f9 00 01 f6 30 82 01 f2 30 82 01 5d a0 03 02 |.....0...0..]...|
-00000050 01 02 02 01 00 30 0b 06 09 2a 86 48 86 f7 0d 01 |.....0...*.H....|
-00000060 01 05 30 28 31 10 30 0e 06 03 55 04 0a 13 07 41 |..0(1.0...U....A|
-00000070 63 6d 65 20 43 6f 31 14 30 12 06 03 55 04 03 13 |cme Co1.0...U...|
-00000080 0b 73 6e 69 74 65 73 74 2e 63 6f 6d 30 1e 17 0d |.snitest.com0...|
-00000090 31 32 30 34 31 31 31 37 34 30 33 35 5a 17 0d 31 |120411174035Z..1|
-000000a0 33 30 34 31 31 31 37 34 35 33 35 5a 30 28 31 10 |30411174535Z0(1.|
-000000b0 30 0e 06 03 55 04 0a 13 07 41 63 6d 65 20 43 6f |0...U....Acme Co|
-000000c0 31 14 30 12 06 03 55 04 03 13 0b 73 6e 69 74 65 |1.0...U....snite|
-000000d0 73 74 2e 63 6f 6d 30 81 9d 30 0b 06 09 2a 86 48 |st.com0..0...*.H|
-000000e0 86 f7 0d 01 01 01 03 81 8d 00 30 81 89 02 81 81 |..........0.....|
-000000f0 00 bb 79 d6 f5 17 b5 e5 bf 46 10 d0 dc 69 be e6 |..y......F...i..|
-00000100 2b 07 43 5a d0 03 2d 8a 7a 43 85 b7 14 52 e7 a5 |+.CZ..-.zC...R..|
-00000110 65 4c 2c 78 b8 23 8c b5 b4 82 e5 de 1f 95 3b 7e |eL,x.#........;~|
-00000120 62 a5 2c a5 33 d6 fe 12 5c 7a 56 fc f5 06 bf fa |b.,.3...\zV.....|
-00000130 58 7b 26 3f b5 cd 04 d3 d0 c9 21 96 4a c7 f4 54 |X{&?......!.J..T|
-00000140 9f 5a bf ef 42 71 00 fe 18 99 07 7f 7e 88 7d 7d |.Z..Bq......~.}}|
-00000150 f1 04 39 c4 a2 2e db 51 c9 7c e3 c0 4c 3b 32 66 |..9....Q.|..L;2f|
-00000160 01 cf af b1 1d b8 71 9a 1d db db 89 6b ae da 2d |......q.....k..-|
-00000170 79 02 03 01 00 01 a3 32 30 30 30 0e 06 03 55 1d |y......2000...U.|
-00000180 0f 01 01 ff 04 04 03 02 00 a0 30 0d 06 03 55 1d |..........0...U.|
-00000190 0e 04 06 04 04 01 02 03 04 30 0f 06 03 55 1d 23 |.........0...U.#|
-000001a0 04 08 30 06 80 04 01 02 03 04 30 0b 06 09 2a 86 |..0.......0...*.|
-000001b0 48 86 f7 0d 01 01 05 03 81 81 00 89 c6 45 5f 1c |H............E_.|
-000001c0 1f 5e f8 eb 1a b1 74 ee 24 39 05 9f 5c 42 59 bb |.^....t.$9..\BY.|
-000001d0 1a 8d 86 cd b1 d0 56 f5 6a 71 7d a4 0e 95 ab 90 |......V.jq}.....|
-000001e0 f5 9e 8d ea f6 27 c1 57 99 50 94 db 08 02 26 6e |.....'.W.P....&n|
-000001f0 b3 4f c6 84 2d ea 8a 4b 68 d9 c1 38 91 03 ab 84 |.O..-..Kh..8....|
-00000200 fb 9e 1f 85 d9 b5 d2 3f f2 31 2c 86 70 fb b5 40 |.......?.1,.p..@|
-00000210 14 82 45 a4 eb af e2 64 d9 0c 8a 4c f4 f8 5b 0f |..E....d...L..[.|
-00000220 ac 12 ac 2f c4 a3 15 4b ad 52 46 28 68 af 96 c6 |.../...K.RF(h...|
-00000230 2c 65 25 d6 52 b6 e3 18 45 bd cc 16 03 03 00 04 |,e%.R...E.......|
-00000240 0e 00 00 00 |....|
+00000030 05 ff 01 00 01 00 16 03 03 02 59 0b 00 02 55 00 |..........Y...U.|
+00000040 02 52 00 02 4f 30 82 02 4b 30 82 01 b4 a0 03 02 |.R..O0..K0......|
+00000050 01 02 02 09 00 e8 f0 9d 3f e2 5b ea a6 30 0d 06 |........?.[..0..|
+00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 1f 31 0b |.*.H........0.1.|
+00000070 30 09 06 03 55 04 0a 13 02 47 6f 31 10 30 0e 06 |0...U....Go1.0..|
+00000080 03 55 04 03 13 07 47 6f 20 52 6f 6f 74 30 1e 17 |.U....Go Root0..|
+00000090 0d 31 36 30 31 30 31 30 30 30 30 30 30 5a 17 0d |.160101000000Z..|
+000000a0 32 35 30 31 30 31 30 30 30 30 30 30 5a 30 1a 31 |250101000000Z0.1|
+000000b0 0b 30 09 06 03 55 04 0a 13 02 47 6f 31 0b 30 09 |.0...U....Go1.0.|
+000000c0 06 03 55 04 03 13 02 47 6f 30 81 9f 30 0d 06 09 |..U....Go0..0...|
+000000d0 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 30 |*.H............0|
+000000e0 81 89 02 81 81 00 db 46 7d 93 2e 12 27 06 48 bc |.......F}...'.H.|
+000000f0 06 28 21 ab 7e c4 b6 a2 5d fe 1e 52 45 88 7a 36 |.(!.~...]..RE.z6|
+00000100 47 a5 08 0d 92 42 5b c2 81 c0 be 97 79 98 40 fb |G....B[.....y. at .|
+00000110 4f 6d 14 fd 2b 13 8b c2 a5 2e 67 d8 d4 09 9e d6 |Om..+.....g.....|
+00000120 22 38 b7 4a 0b 74 73 2b c2 34 f1 d1 93 e5 96 d9 |"8.J.ts+.4......|
+00000130 74 7b f3 58 9f 6c 61 3c c0 b0 41 d4 d9 2b 2b 24 |t{.X.la<..A..++$|
+00000140 23 77 5b 1c 3b bd 75 5d ce 20 54 cf a1 63 87 1d |#w[.;.u]. T..c..|
+00000150 1e 24 c4 f3 1d 1a 50 8b aa b6 14 43 ed 97 a7 75 |.$....P....C...u|
+00000160 62 f4 14 c8 52 d7 02 03 01 00 01 a3 81 93 30 81 |b...R.........0.|
+00000170 90 30 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 05 |.0...U..........|
+00000180 a0 30 1d 06 03 55 1d 25 04 16 30 14 06 08 2b 06 |.0...U.%..0...+.|
+00000190 01 05 05 07 03 01 06 08 2b 06 01 05 05 07 03 02 |........+.......|
+000001a0 30 0c 06 03 55 1d 13 01 01 ff 04 02 30 00 30 19 |0...U.......0.0.|
+000001b0 06 03 55 1d 0e 04 12 04 10 9f 91 16 1f 43 43 3e |..U..........CC>|
+000001c0 49 a6 de 6d b6 80 d7 9f 60 30 1b 06 03 55 1d 23 |I..m....`0...U.#|
+000001d0 04 14 30 12 80 10 48 13 49 4d 13 7e 16 31 bb a3 |..0...H.IM.~.1..|
+000001e0 01 d5 ac ab 6e 7b 30 19 06 03 55 1d 11 04 12 30 |....n{0...U....0|
+000001f0 10 82 0e 65 78 61 6d 70 6c 65 2e 67 6f 6c 61 6e |...example.golan|
+00000200 67 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 |g0...*.H........|
+00000210 03 81 81 00 9d 30 cc 40 2b 5b 50 a0 61 cb ba e5 |.....0. at +[P.a...|
+00000220 53 58 e1 ed 83 28 a9 58 1a a9 38 a4 95 a1 ac 31 |SX...(.X..8....1|
+00000230 5a 1a 84 66 3d 43 d3 2d d9 0b f2 97 df d3 20 64 |Z..f=C.-...... d|
+00000240 38 92 24 3a 00 bc cf 9c 7d b7 40 20 01 5f aa d3 |8.$:....}.@ ._..|
+00000250 16 61 09 a2 76 fd 13 c3 cc e1 0c 5c ee b1 87 82 |.a..v......\....|
+00000260 f1 6c 04 ed 73 bb b3 43 77 8d 0c 1c f1 0f a1 d8 |.l..s..Cw.......|
+00000270 40 83 61 c9 4c 72 2b 9d ae db 46 06 06 4d f4 c1 |@.a.Lr+...F..M..|
+00000280 b3 3e c0 d1 bd 42 d4 db fe 3d 13 60 84 5c 21 d3 |.>...B...=.`.\!.|
+00000290 3b e9 fa e7 16 03 03 00 04 0e 00 00 00 |;............|
>>> Flow 3 (client to server)
-00000000 16 03 03 00 86 10 00 00 82 00 80 7b 3b b8 73 f0 |...........{;.s.|
-00000010 78 2c 75 91 ee 4a ac 6e 9d 08 8e ef dd 52 fb 38 |x,u..J.n.....R.8|
-00000020 d7 6f b3 39 8a 8c 3c dc 4b e0 a9 2b 0b de 9a d6 |.o.9..<.K..+....|
-00000030 38 72 ae 0f 76 87 4b f6 45 17 f6 fa b2 5a 07 30 |8r..v.K.E....Z.0|
-00000040 5b ef e7 40 e0 95 98 bf 8d 8d 5e 7a 6a ea 2d 2e |[.. at ......^zj.-.|
-00000050 9c 99 e4 47 6b 4f 16 32 fb 0d a7 01 36 2e 06 f2 |...GkO.2....6...|
-00000060 65 74 b6 ed 07 51 60 7a 98 d6 77 36 f4 c7 f6 b1 |et...Q`z..w6....|
-00000070 f1 6a 3e 38 7c 79 5c c6 b4 53 5c 85 fb 0b 2c f9 |.j>8|y\..S\...,.|
-00000080 2c 60 97 c8 73 f7 22 ef 52 4c 10 14 03 03 00 01 |,`..s.".RL......|
-00000090 01 16 03 03 00 40 4c 73 6e 5e 66 9d 53 2e fa b7 |..... at Lsn^f.S...|
-000000a0 90 2d 52 55 13 d2 67 28 aa 1a 6f 62 42 ef 2f 4d |.-RU..g(..obB./M|
-000000b0 04 1d ef 64 8f 1a 70 c0 d0 bf 06 72 ee db 3e 43 |...d..p....r..>C|
-000000c0 7f ed 37 bb a1 62 0c c5 c8 a9 c0 51 8f 77 95 b3 |..7..b.....Q.w..|
-000000d0 72 7e 01 89 c4 32 |r~...2|
+00000000 16 03 03 00 86 10 00 00 82 00 80 80 e8 00 cc 09 |................|
+00000010 fc 87 20 9f 2a 38 33 6f cb 61 71 86 6d 55 6a 87 |.. .*83o.aq.mUj.|
+00000020 e0 22 78 62 4e 3b 98 5c 87 fd 3b 1c 73 d3 77 7e |."xbN;.\..;.s.w~|
+00000030 a4 c3 6f d4 6d 82 65 40 0e 70 2f 24 e9 7d ff 49 |..o.m.e at .p/$.}.I|
+00000040 c7 bd 45 44 af ae a5 7a 06 06 5e 1e ce 31 73 4b |..ED...z..^..1sK|
+00000050 4a 38 f0 11 ba 32 58 ab a5 94 12 13 30 83 95 85 |J8...2X.....0...|
+00000060 f5 7e 8d a7 cc 6d 19 14 f9 b0 dc 64 e5 4d b1 7d |.~...m.....d.M.}|
+00000070 e6 95 d4 4a 7f 85 11 5b a7 c9 32 84 c2 ec 2e c3 |...J...[..2.....|
+00000080 40 fe 5c e2 cf 5b 96 8a 72 9f 9f 14 03 03 00 01 |@.\..[..r.......|
+00000090 01 16 03 03 00 40 a8 d2 5b 24 28 2b 86 1e c1 2e |..... at ..[$(+....|
+000000a0 6f da 7a ac 6b bf 02 ea 10 5d 9c 71 fb 19 eb 17 |o.z.k....].q....|
+000000b0 19 b2 07 7c b9 df d0 6d 9f 80 cf 37 a0 2a 18 c9 |...|...m...7.*..|
+000000c0 e9 b5 9f 94 42 6a 6b 33 55 fb 6d 94 3b 79 ed 26 |....Bjk3U.m.;y.&|
+000000d0 5c 5a 7f 68 2c d8 |\Z.h,.|
>>> Flow 4 (server to client)
-00000000 15 03 03 00 02 02 14 |.......|
+00000000 14 03 03 00 01 01 16 03 03 00 40 00 00 00 00 00 |.......... at .....|
+00000010 00 00 00 00 00 00 00 00 00 00 00 18 e9 b5 96 14 |................|
+00000020 38 98 d4 23 cd e5 32 0e 09 ae b3 3b 90 a4 4d c2 |8..#..2....;..M.|
+00000030 e5 a8 df 72 e8 97 0b 67 cb 87 f4 d0 3e 52 ca d1 |...r...g....>R..|
+00000040 28 94 ed 88 6c cb 62 53 b2 a1 04 17 03 03 00 40 |(...l.bS.......@|
+00000050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000060 0e e3 b0 da 4b 19 ca 29 7b 1d c8 e3 0d d7 f2 97 |....K..){.......|
+00000070 b0 0b 6e f0 d2 4b f0 c4 ca 87 75 3c ae 66 e1 b3 |..n..K....u<.f..|
+00000080 06 e3 e6 90 54 fd 31 f7 5d 3b 6f de 0f d5 e4 09 |....T.1.];o.....|
+00000090 15 03 03 00 30 00 00 00 00 00 00 00 00 00 00 00 |....0...........|
+000000a0 00 00 00 00 00 ee a1 b0 94 b5 86 71 73 66 14 ac |...........qsf..|
+000000b0 5c 4e 1b 67 27 af db b6 e3 44 15 38 b1 f5 e0 13 |\N.g'....D.8....|
+000000c0 a5 e1 82 c0 6a |....j|
diff --git a/src/crypto/tls/testdata/Server-TLSv12-X25519-ECDHE-RSA-AES-GCM b/src/crypto/tls/testdata/Server-TLSv12-X25519-ECDHE-RSA-AES-GCM
new file mode 100644
index 0000000..89587e9
--- /dev/null
+++ b/src/crypto/tls/testdata/Server-TLSv12-X25519-ECDHE-RSA-AES-GCM
@@ -0,0 +1,79 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 73 01 00 00 6f 03 03 33 6d f4 4a 4b |....s...o..3m.JK|
+00000010 48 35 ef 62 e9 bd 66 90 7e 73 62 bf 93 51 3d 90 |H5.b..f.~sb..Q=.|
+00000020 9e f1 17 ae bd 24 28 54 44 50 8e 00 00 04 c0 2f |.....$(TDP...../|
+00000030 00 ff 01 00 00 42 00 0b 00 04 03 00 01 02 00 0a |.....B..........|
+00000040 00 0a 00 08 00 1d 00 17 00 19 00 18 00 0d 00 20 |............... |
+00000050 00 1e 06 01 06 02 06 03 05 01 05 02 05 03 04 01 |................|
+00000060 04 02 04 03 03 01 03 02 03 03 02 01 02 02 02 03 |................|
+00000070 00 16 00 00 00 17 00 00 |........|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 31 02 00 00 2d 03 03 00 00 00 00 00 |....1...-.......|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 c0 2f 00 00 |............./..|
+00000030 05 ff 01 00 01 00 16 03 03 02 59 0b 00 02 55 00 |..........Y...U.|
+00000040 02 52 00 02 4f 30 82 02 4b 30 82 01 b4 a0 03 02 |.R..O0..K0......|
+00000050 01 02 02 09 00 e8 f0 9d 3f e2 5b ea a6 30 0d 06 |........?.[..0..|
+00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 1f 31 0b |.*.H........0.1.|
+00000070 30 09 06 03 55 04 0a 13 02 47 6f 31 10 30 0e 06 |0...U....Go1.0..|
+00000080 03 55 04 03 13 07 47 6f 20 52 6f 6f 74 30 1e 17 |.U....Go Root0..|
+00000090 0d 31 36 30 31 30 31 30 30 30 30 30 30 5a 17 0d |.160101000000Z..|
+000000a0 32 35 30 31 30 31 30 30 30 30 30 30 5a 30 1a 31 |250101000000Z0.1|
+000000b0 0b 30 09 06 03 55 04 0a 13 02 47 6f 31 0b 30 09 |.0...U....Go1.0.|
+000000c0 06 03 55 04 03 13 02 47 6f 30 81 9f 30 0d 06 09 |..U....Go0..0...|
+000000d0 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 30 |*.H............0|
+000000e0 81 89 02 81 81 00 db 46 7d 93 2e 12 27 06 48 bc |.......F}...'.H.|
+000000f0 06 28 21 ab 7e c4 b6 a2 5d fe 1e 52 45 88 7a 36 |.(!.~...]..RE.z6|
+00000100 47 a5 08 0d 92 42 5b c2 81 c0 be 97 79 98 40 fb |G....B[.....y. at .|
+00000110 4f 6d 14 fd 2b 13 8b c2 a5 2e 67 d8 d4 09 9e d6 |Om..+.....g.....|
+00000120 22 38 b7 4a 0b 74 73 2b c2 34 f1 d1 93 e5 96 d9 |"8.J.ts+.4......|
+00000130 74 7b f3 58 9f 6c 61 3c c0 b0 41 d4 d9 2b 2b 24 |t{.X.la<..A..++$|
+00000140 23 77 5b 1c 3b bd 75 5d ce 20 54 cf a1 63 87 1d |#w[.;.u]. T..c..|
+00000150 1e 24 c4 f3 1d 1a 50 8b aa b6 14 43 ed 97 a7 75 |.$....P....C...u|
+00000160 62 f4 14 c8 52 d7 02 03 01 00 01 a3 81 93 30 81 |b...R.........0.|
+00000170 90 30 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 05 |.0...U..........|
+00000180 a0 30 1d 06 03 55 1d 25 04 16 30 14 06 08 2b 06 |.0...U.%..0...+.|
+00000190 01 05 05 07 03 01 06 08 2b 06 01 05 05 07 03 02 |........+.......|
+000001a0 30 0c 06 03 55 1d 13 01 01 ff 04 02 30 00 30 19 |0...U.......0.0.|
+000001b0 06 03 55 1d 0e 04 12 04 10 9f 91 16 1f 43 43 3e |..U..........CC>|
+000001c0 49 a6 de 6d b6 80 d7 9f 60 30 1b 06 03 55 1d 23 |I..m....`0...U.#|
+000001d0 04 14 30 12 80 10 48 13 49 4d 13 7e 16 31 bb a3 |..0...H.IM.~.1..|
+000001e0 01 d5 ac ab 6e 7b 30 19 06 03 55 1d 11 04 12 30 |....n{0...U....0|
+000001f0 10 82 0e 65 78 61 6d 70 6c 65 2e 67 6f 6c 61 6e |...example.golan|
+00000200 67 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 |g0...*.H........|
+00000210 03 81 81 00 9d 30 cc 40 2b 5b 50 a0 61 cb ba e5 |.....0. at +[P.a...|
+00000220 53 58 e1 ed 83 28 a9 58 1a a9 38 a4 95 a1 ac 31 |SX...(.X..8....1|
+00000230 5a 1a 84 66 3d 43 d3 2d d9 0b f2 97 df d3 20 64 |Z..f=C.-...... d|
+00000240 38 92 24 3a 00 bc cf 9c 7d b7 40 20 01 5f aa d3 |8.$:....}.@ ._..|
+00000250 16 61 09 a2 76 fd 13 c3 cc e1 0c 5c ee b1 87 82 |.a..v......\....|
+00000260 f1 6c 04 ed 73 bb b3 43 77 8d 0c 1c f1 0f a1 d8 |.l..s..Cw.......|
+00000270 40 83 61 c9 4c 72 2b 9d ae db 46 06 06 4d f4 c1 |@.a.Lr+...F..M..|
+00000280 b3 3e c0 d1 bd 42 d4 db fe 3d 13 60 84 5c 21 d3 |.>...B...=.`.\!.|
+00000290 3b e9 fa e7 16 03 03 00 ac 0c 00 00 a8 03 00 1d |;...............|
+000002a0 20 2f e5 7d a3 47 cd 62 43 15 28 da ac 5f bb 29 | /.}.G.bC.(.._.)|
+000002b0 07 30 ff f6 84 af c4 cf c2 ed 90 99 5f 58 cb 3b |.0.........._X.;|
+000002c0 74 05 01 00 80 61 aa 96 74 97 9f 2a 81 df 73 4d |t....a..t..*..sM|
+000002d0 58 fb 8b 34 d9 51 02 1d 30 45 98 11 fa 20 cc 48 |X..4.Q..0E... .H|
+000002e0 18 8d 92 4a bc bf 34 c2 52 cc 7b 7d 93 32 f9 98 |...J..4.R.{}.2..|
+000002f0 eb d0 6d 58 4c 24 71 f1 78 cc ee 4d f8 26 26 d3 |..mXL$q.x..M.&&.|
+00000300 b0 1c 46 67 ff 75 fc b5 b3 75 31 f3 9d d6 51 07 |..Fg.u...u1...Q.|
+00000310 7a c1 2f 52 3f 88 23 f2 90 74 d0 77 6d 2b c7 31 |z./R?.#..t.wm+.1|
+00000320 3d 81 a8 b9 84 a6 8f 96 25 91 e8 31 3b e9 20 b8 |=.......%..1;. .|
+00000330 c4 11 68 da 58 0a ee 79 de fe 32 29 d6 24 b0 56 |..h.X..y..2).$.V|
+00000340 ab e8 b5 57 fc 16 03 03 00 04 0e 00 00 00 |...W..........|
+>>> Flow 3 (client to server)
+00000000 16 03 03 00 25 10 00 00 21 20 eb 0e 38 40 3f 32 |....%...! ..8@?2|
+00000010 a4 95 fb c4 de e5 82 9a 4b 46 37 de 29 e5 6b e6 |........KF7.).k.|
+00000020 44 bf f0 af 0c 62 19 bd 5c 0e 14 03 03 00 01 01 |D....b..\.......|
+00000030 16 03 03 00 28 67 ad 91 f6 8d 8a 39 f7 f2 a6 42 |....(g.....9...B|
+00000040 f2 8c 2f 1d b3 1d dd f1 88 65 7e 66 d2 d9 70 09 |../......e~f..p.|
+00000050 4e 12 90 0d 0b d5 a5 a6 20 bc 32 63 05 |N....... .2c.|
+>>> Flow 4 (server to client)
+00000000 14 03 03 00 01 01 16 03 03 00 28 00 00 00 00 00 |..........(.....|
+00000010 00 00 00 56 b1 b8 16 9a 27 c6 ee d4 7f b7 68 83 |...V....'.....h.|
+00000020 43 3b 04 92 ec cc c7 db 82 f8 7d 04 64 1d 55 cf |C;........}.d.U.|
+00000030 02 69 ac 17 03 03 00 25 00 00 00 00 00 00 00 01 |.i.....%........|
+00000040 d6 69 51 5d 3b 00 93 c2 a6 19 97 7d bf a9 d9 96 |.iQ];......}....|
+00000050 43 1d ae 32 c3 52 1a f0 18 ba 10 4c e0 15 03 03 |C..2.R.....L....|
+00000060 00 1a 00 00 00 00 00 00 00 02 1e 8a 5e 37 c0 b1 |............^7..|
+00000070 0d 1e c9 6a 90 23 d6 4c 5c 47 5b bf |...j.#.L\G[.|
diff --git a/src/crypto/tls/tls.go b/src/crypto/tls/tls.go
index 8eef884..f2e5aea 100644
--- a/src/crypto/tls/tls.go
+++ b/src/crypto/tls/tls.go
@@ -5,7 +5,7 @@
// Package tls partially implements TLS 1.2, as specified in RFC 5246.
package tls
-// BUG(agl): The crypto/tls package does not implement countermeasures
+// BUG(agl): The crypto/tls package only implements some countermeasures
// against Lucky13 attacks on CBC-mode encryption. See
// http://www.isg.rhul.ac.uk/tls/TLStiming.pdf and
// https://www.imperialviolet.org/2013/02/04/luckythirteen.html.
@@ -102,7 +102,7 @@ func DialWithDialer(dialer *net.Dialer, network, addr string, config *Config) (*
timeout := dialer.Timeout
if !dialer.Deadline.IsZero() {
- deadlineTimeout := dialer.Deadline.Sub(time.Now())
+ deadlineTimeout := time.Until(dialer.Deadline)
if timeout == 0 || deadlineTimeout < timeout {
timeout = deadlineTimeout
}
@@ -135,7 +135,7 @@ func DialWithDialer(dialer *net.Dialer, network, addr string, config *Config) (*
// from the hostname we're connecting to.
if config.ServerName == "" {
// Make a copy to avoid polluting argument or default.
- c := config.clone()
+ c := config.Clone()
c.ServerName = hostname
config = c
}
diff --git a/src/crypto/tls/tls_test.go b/src/crypto/tls/tls_test.go
index 48b46a0..8933f4f 100644
--- a/src/crypto/tls/tls_test.go
+++ b/src/crypto/tls/tls_test.go
@@ -11,6 +11,7 @@ import (
"fmt"
"internal/testenv"
"io"
+ "io/ioutil"
"math"
"math/rand"
"net"
@@ -98,6 +99,7 @@ var keyPairTests = []struct {
}
func TestX509KeyPair(t *testing.T) {
+ t.Parallel()
var pem []byte
for _, test := range keyPairTests {
pem = []byte(test.cert + test.key)
@@ -241,7 +243,7 @@ func testConnReadNonzeroAndEOF(t *testing.T, delay time.Duration) error {
srvCh <- nil
return
}
- serverConfig := testConfig.clone()
+ serverConfig := testConfig.Clone()
srv := Server(sconn, serverConfig)
if err := srv.Handshake(); err != nil {
serr = fmt.Errorf("handshake: %v", err)
@@ -251,7 +253,7 @@ func testConnReadNonzeroAndEOF(t *testing.T, delay time.Duration) error {
srvCh <- srv
}()
- clientConfig := testConfig.clone()
+ clientConfig := testConfig.Clone()
conn, err := Dial("tcp", ln.Addr().String(), clientConfig)
if err != nil {
t.Fatal(err)
@@ -293,18 +295,20 @@ func TestTLSUniqueMatches(t *testing.T) {
for i := 0; i < 2; i++ {
sconn, err := ln.Accept()
if err != nil {
- t.Fatal(err)
+ t.Error(err)
+ return
}
- serverConfig := testConfig.clone()
+ serverConfig := testConfig.Clone()
srv := Server(sconn, serverConfig)
if err := srv.Handshake(); err != nil {
- t.Fatal(err)
+ t.Error(err)
+ return
}
serverTLSUniques <- srv.ConnectionState().TLSUnique
}
}()
- clientConfig := testConfig.clone()
+ clientConfig := testConfig.Clone()
clientConfig.ClientSessionCache = NewLRUClientSessionCache(1)
conn, err := Dial("tcp", ln.Addr().String(), clientConfig)
if err != nil {
@@ -394,7 +398,7 @@ func TestConnCloseBreakingWrite(t *testing.T) {
srvCh <- nil
return
}
- serverConfig := testConfig.clone()
+ serverConfig := testConfig.Clone()
srv := Server(sconn, serverConfig)
if err := srv.Handshake(); err != nil {
serr = fmt.Errorf("handshake: %v", err)
@@ -414,7 +418,7 @@ func TestConnCloseBreakingWrite(t *testing.T) {
Conn: cconn,
}
- clientConfig := testConfig.clone()
+ clientConfig := testConfig.Clone()
tconn := Client(conn, clientConfig)
if err := tconn.Handshake(); err != nil {
t.Fatal(err)
@@ -458,6 +462,112 @@ func TestConnCloseBreakingWrite(t *testing.T) {
}
}
+func TestConnCloseWrite(t *testing.T) {
+ ln := newLocalListener(t)
+ defer ln.Close()
+
+ clientDoneChan := make(chan struct{})
+
+ serverCloseWrite := func() error {
+ sconn, err := ln.Accept()
+ if err != nil {
+ return fmt.Errorf("accept: %v", err)
+ }
+ defer sconn.Close()
+
+ serverConfig := testConfig.Clone()
+ srv := Server(sconn, serverConfig)
+ if err := srv.Handshake(); err != nil {
+ return fmt.Errorf("handshake: %v", err)
+ }
+ defer srv.Close()
+
+ data, err := ioutil.ReadAll(srv)
+ if err != nil {
+ return err
+ }
+ if len(data) > 0 {
+ return fmt.Errorf("Read data = %q; want nothing", data)
+ }
+
+ if err := srv.CloseWrite(); err != nil {
+ return fmt.Errorf("server CloseWrite: %v", err)
+ }
+
+ // Wait for clientCloseWrite to finish, so we know we
+ // tested the CloseWrite before we defer the
+ // sconn.Close above, which would also cause the
+ // client to unblock like CloseWrite.
+ <-clientDoneChan
+ return nil
+ }
+
+ clientCloseWrite := func() error {
+ defer close(clientDoneChan)
+
+ clientConfig := testConfig.Clone()
+ conn, err := Dial("tcp", ln.Addr().String(), clientConfig)
+ if err != nil {
+ return err
+ }
+ if err := conn.Handshake(); err != nil {
+ return err
+ }
+ defer conn.Close()
+
+ if err := conn.CloseWrite(); err != nil {
+ return fmt.Errorf("client CloseWrite: %v", err)
+ }
+
+ if _, err := conn.Write([]byte{0}); err != errShutdown {
+ return fmt.Errorf("CloseWrite error = %v; want errShutdown", err)
+ }
+
+ data, err := ioutil.ReadAll(conn)
+ if err != nil {
+ return err
+ }
+ if len(data) > 0 {
+ return fmt.Errorf("Read data = %q; want nothing", data)
+ }
+ return nil
+ }
+
+ errChan := make(chan error, 2)
+
+ go func() { errChan <- serverCloseWrite() }()
+ go func() { errChan <- clientCloseWrite() }()
+
+ for i := 0; i < 2; i++ {
+ select {
+ case err := <-errChan:
+ if err != nil {
+ t.Fatal(err)
+ }
+ case <-time.After(10 * time.Second):
+ t.Fatal("deadlock")
+ }
+ }
+
+ // Also test CloseWrite being called before the handshake is
+ // finished:
+ {
+ ln2 := newLocalListener(t)
+ defer ln2.Close()
+
+ netConn, err := net.Dial("tcp", ln2.Addr().String())
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer netConn.Close()
+ conn := Client(netConn, testConfig.Clone())
+
+ if err := conn.CloseWrite(); err != errEarlyCloseWrite {
+ t.Errorf("CloseWrite error = %v; want errEarlyCloseWrite", err)
+ }
+ }
+}
+
func TestClone(t *testing.T) {
var c1 Config
v := reflect.ValueOf(&c1).Elem()
@@ -477,12 +587,12 @@ func TestClone(t *testing.T) {
case "Rand":
f.Set(reflect.ValueOf(io.Reader(os.Stdin)))
continue
- case "Time", "GetCertificate":
+ case "Time", "GetCertificate", "GetConfigForClient", "VerifyPeerCertificate", "GetClientCertificate":
// DeepEqual can't compare functions.
continue
case "Certificates":
f.Set(reflect.ValueOf([]Certificate{
- {Certificate: [][]byte{[]byte{'b'}}},
+ {Certificate: [][]byte{{'b'}}},
}))
continue
case "NameToCertificate":
@@ -494,6 +604,10 @@ func TestClone(t *testing.T) {
case "ClientSessionCache":
f.Set(reflect.ValueOf(NewLRUClientSessionCache(10)))
continue
+ case "KeyLogWriter":
+ f.Set(reflect.ValueOf(io.Writer(os.Stdout)))
+ continue
+
}
q, ok := quick.Value(f.Type(), rnd)
@@ -503,7 +617,11 @@ func TestClone(t *testing.T) {
f.Set(q)
}
- c2 := c1.clone()
+ c2 := c1.Clone()
+ // DeepEqual also compares unexported fields, thus c2 needs to have run
+ // serverInit in order to be DeepEqual to c1. Cloning it and discarding
+ // the result is sufficient.
+ c2.Clone()
if !reflect.DeepEqual(&c1, c2) {
t.Errorf("clone failed to copy a field")
@@ -551,7 +669,8 @@ func throughput(b *testing.B, totalBytes int64, dynamicRecordSizingDisabled bool
// (cannot call b.Fatal in goroutine)
panic(fmt.Errorf("accept: %v", err))
}
- serverConfig := testConfig.clone()
+ serverConfig := testConfig.Clone()
+ serverConfig.CipherSuites = nil // the defaults may prefer faster ciphers
serverConfig.DynamicRecordSizingDisabled = dynamicRecordSizingDisabled
srv := Server(sconn, serverConfig)
if err := srv.Handshake(); err != nil {
@@ -564,7 +683,8 @@ func throughput(b *testing.B, totalBytes int64, dynamicRecordSizingDisabled bool
}()
b.SetBytes(totalBytes)
- clientConfig := testConfig.clone()
+ clientConfig := testConfig.Clone()
+ clientConfig.CipherSuites = nil // the defaults may prefer faster ciphers
clientConfig.DynamicRecordSizingDisabled = dynamicRecordSizingDisabled
buf := make([]byte, bufsize)
@@ -641,7 +761,7 @@ func latency(b *testing.B, bps int, dynamicRecordSizingDisabled bool) {
// (cannot call b.Fatal in goroutine)
panic(fmt.Errorf("accept: %v", err))
}
- serverConfig := testConfig.clone()
+ serverConfig := testConfig.Clone()
serverConfig.DynamicRecordSizingDisabled = dynamicRecordSizingDisabled
srv := Server(&slowConn{sconn, bps}, serverConfig)
if err := srv.Handshake(); err != nil {
@@ -651,7 +771,7 @@ func latency(b *testing.B, bps int, dynamicRecordSizingDisabled bool) {
}
}()
- clientConfig := testConfig.clone()
+ clientConfig := testConfig.Clone()
clientConfig.DynamicRecordSizingDisabled = dynamicRecordSizingDisabled
buf := make([]byte, 16384)
diff --git a/src/crypto/x509/cert_pool.go b/src/crypto/x509/cert_pool.go
index 8438bf6..fea33df 100644
--- a/src/crypto/x509/cert_pool.go
+++ b/src/crypto/x509/cert_pool.go
@@ -4,11 +4,7 @@
package x509
-import (
- "encoding/pem"
- "errors"
- "runtime"
-)
+import "encoding/pem"
// CertPool is a set of certificates.
type CertPool struct {
@@ -30,9 +26,6 @@ func NewCertPool() *CertPool {
// Any mutations to the returned pool are not written to disk and do
// not affect any other pool.
func SystemCertPool() (*CertPool, error) {
- if runtime.GOOS == "windows" {
- return nil, errors.New("crypto/x509: system root pool is not available on Windows")
- }
return loadSystemRoots()
}
@@ -86,10 +79,8 @@ func (s *CertPool) AddCert(cert *Certificate) {
}
// Check that the certificate isn't being added twice.
- for _, c := range s.certs {
- if c.Equal(cert) {
- return
- }
+ if s.contains(cert) {
+ return
}
n := len(s.certs)
diff --git a/src/crypto/x509/pkix/pkix.go b/src/crypto/x509/pkix/pkix.go
index faad406..39fd78d 100644
--- a/src/crypto/x509/pkix/pkix.go
+++ b/src/crypto/x509/pkix/pkix.go
@@ -64,34 +64,36 @@ func (n *Name) FillFromRDNSequence(rdns *RDNSequence) {
if len(rdn) == 0 {
continue
}
- atv := rdn[0]
- n.Names = append(n.Names, atv)
- value, ok := atv.Value.(string)
- if !ok {
- continue
- }
- t := atv.Type
- if len(t) == 4 && t[0] == 2 && t[1] == 5 && t[2] == 4 {
- switch t[3] {
- case 3:
- n.CommonName = value
- case 5:
- n.SerialNumber = value
- case 6:
- n.Country = append(n.Country, value)
- case 7:
- n.Locality = append(n.Locality, value)
- case 8:
- n.Province = append(n.Province, value)
- case 9:
- n.StreetAddress = append(n.StreetAddress, value)
- case 10:
- n.Organization = append(n.Organization, value)
- case 11:
- n.OrganizationalUnit = append(n.OrganizationalUnit, value)
- case 17:
- n.PostalCode = append(n.PostalCode, value)
+ for _, atv := range rdn {
+ n.Names = append(n.Names, atv)
+ value, ok := atv.Value.(string)
+ if !ok {
+ continue
+ }
+
+ t := atv.Type
+ if len(t) == 4 && t[0] == 2 && t[1] == 5 && t[2] == 4 {
+ switch t[3] {
+ case 3:
+ n.CommonName = value
+ case 5:
+ n.SerialNumber = value
+ case 6:
+ n.Country = append(n.Country, value)
+ case 7:
+ n.Locality = append(n.Locality, value)
+ case 8:
+ n.Province = append(n.Province, value)
+ case 9:
+ n.StreetAddress = append(n.StreetAddress, value)
+ case 10:
+ n.Organization = append(n.Organization, value)
+ case 11:
+ n.OrganizationalUnit = append(n.OrganizationalUnit, value)
+ case 17:
+ n.PostalCode = append(n.PostalCode, value)
+ }
}
}
}
diff --git a/src/crypto/x509/root_cgo_darwin.go b/src/crypto/x509/root_cgo_darwin.go
index d599174..ea86b60 100644
--- a/src/crypto/x509/root_cgo_darwin.go
+++ b/src/crypto/x509/root_cgo_darwin.go
@@ -7,7 +7,7 @@
package x509
/*
-#cgo CFLAGS: -mmacosx-version-min=10.6 -D__MAC_OS_X_VERSION_MAX_ALLOWED=1060
+#cgo CFLAGS: -mmacosx-version-min=10.6 -D__MAC_OS_X_VERSION_MAX_ALLOWED=1080
#cgo LDFLAGS: -framework CoreFoundation -framework Security
#include <errno.h>
@@ -73,11 +73,10 @@ int useOldCode() {
//
// On success it returns 0 and fills pemRoots with a CFDataRef that contains the extracted root
// certificates of the system. On failure, the function returns -1.
-// Additionally, it fills untrustedPemRoots with certs that must be removed from pemRoots.
//
-// Note: The CFDataRef returned in pemRoots and untrustedPemRoots must
-// be released (using CFRelease) after we've consumed its content.
-int FetchPEMRoots(CFDataRef *pemRoots, CFDataRef *untrustedPemRoots) {
+// Note: The CFDataRef returned in pemRoots must be released (using CFRelease) after
+// we've consumed its content.
+int FetchPEMRoots(CFDataRef *pemRoots) {
if (useOldCode()) {
return FetchPEMRoots_MountainLion(pemRoots);
}
@@ -94,69 +93,23 @@ int FetchPEMRoots(CFDataRef *pemRoots, CFDataRef *untrustedPemRoots) {
return -1;
}
- // kSecTrustSettingsResult is defined as CFSTR("kSecTrustSettingsResult"),
- // but the Go linker's internal linking mode can't handle CFSTR relocations.
- // Create our own dynamic string instead and release it below.
- CFStringRef policy = CFStringCreateWithCString(NULL, "kSecTrustSettingsResult", kCFStringEncodingUTF8);
-
CFMutableDataRef combinedData = CFDataCreateMutable(kCFAllocatorDefault, 0);
- CFMutableDataRef combinedUntrustedData = CFDataCreateMutable(kCFAllocatorDefault, 0);
for (int i = 0; i < numDomains; i++) {
CFArrayRef certs = NULL;
+ // Only get certificates from domain that are trusted
OSStatus err = SecTrustSettingsCopyCertificates(domains[i], &certs);
if (err != noErr) {
continue;
}
- CFIndex numCerts = CFArrayGetCount(certs);
+ int numCerts = CFArrayGetCount(certs);
for (int j = 0; j < numCerts; j++) {
CFDataRef data = NULL;
CFErrorRef errRef = NULL;
- CFArrayRef trustSettings = NULL;
SecCertificateRef cert = (SecCertificateRef)CFArrayGetValueAtIndex(certs, j);
if (cert == NULL) {
continue;
}
- // We only want trusted certs.
- int untrusted = 0;
- if (i != 0) {
- // Certs found in the system domain are always trusted. If the user
- // configures "Never Trust" on such a cert, it will also be found in the
- // admin or user domain, causing it to be added to untrustedPemRoots. The
- // Go code will then clean this up.
-
- // Trust may be stored in any of the domains. According to Apple's
- // SecTrustServer.c, "user trust settings overrule admin trust settings",
- // so take the last trust settings array we find.
- // Skip the system domain since it is always trusted.
- for (int k = 1; k < numDomains; k++) {
- CFArrayRef domainTrustSettings = NULL;
- err = SecTrustSettingsCopyTrustSettings(cert, domains[k], &domainTrustSettings);
- if (err == errSecSuccess && domainTrustSettings != NULL) {
- if (trustSettings) {
- CFRelease(trustSettings);
- }
- trustSettings = domainTrustSettings;
- }
- }
- if (trustSettings == NULL) {
- // "this certificate must be verified to a known trusted certificate"; aka not a root.
- continue;
- }
- for (CFIndex k = 0; k < CFArrayGetCount(trustSettings); k++) {
- CFNumberRef cfNum;
- CFDictionaryRef tSetting = (CFDictionaryRef)CFArrayGetValueAtIndex(trustSettings, k);
- if (CFDictionaryGetValueIfPresent(tSetting, policy, (const void**)&cfNum)){
- SInt32 result = 0;
- CFNumberGetValue(cfNum, kCFNumberSInt32Type, &result);
- // TODO: The rest of the dictionary specifies conditions for evaluation.
- if (result == kSecTrustSettingsResultDeny) {
- untrusted = 1;
- }
- }
- }
- CFRelease(trustSettings);
- }
// We only want to add Root CAs, so make sure Subject and Issuer Name match
CFDataRef subjectName = SecCertificateCopyNormalizedSubjectContent(cert, &errRef);
if (errRef != NULL) {
@@ -185,16 +138,13 @@ int FetchPEMRoots(CFDataRef *pemRoots, CFDataRef *untrustedPemRoots) {
}
if (data != NULL) {
- CFMutableDataRef appendTo = untrusted ? combinedUntrustedData : combinedData;
- CFDataAppendBytes(appendTo, CFDataGetBytePtr(data), CFDataGetLength(data));
+ CFDataAppendBytes(combinedData, CFDataGetBytePtr(data), CFDataGetLength(data));
CFRelease(data);
}
}
CFRelease(certs);
}
- CFRelease(policy);
*pemRoots = combinedData;
- *untrustedPemRoots = combinedUntrustedData;
return 0;
}
*/
@@ -208,8 +158,7 @@ func loadSystemRoots() (*CertPool, error) {
roots := NewCertPool()
var data C.CFDataRef = nil
- var untrustedData C.CFDataRef = nil
- err := C.FetchPEMRoots(&data, &untrustedData)
+ err := C.FetchPEMRoots(&data)
if err == -1 {
// TODO: better error message
return nil, errors.New("crypto/x509: failed to load darwin system roots with cgo")
@@ -218,19 +167,5 @@ func loadSystemRoots() (*CertPool, error) {
defer C.CFRelease(C.CFTypeRef(data))
buf := C.GoBytes(unsafe.Pointer(C.CFDataGetBytePtr(data)), C.int(C.CFDataGetLength(data)))
roots.AppendCertsFromPEM(buf)
- if untrustedData == nil {
- return roots, nil
- }
- defer C.CFRelease(C.CFTypeRef(untrustedData))
- buf = C.GoBytes(unsafe.Pointer(C.CFDataGetBytePtr(untrustedData)), C.int(C.CFDataGetLength(untrustedData)))
- untrustedRoots := NewCertPool()
- untrustedRoots.AppendCertsFromPEM(buf)
-
- trustedRoots := NewCertPool()
- for _, c := range roots.certs {
- if !untrustedRoots.contains(c) {
- trustedRoots.AddCert(c)
- }
- }
- return trustedRoots, nil
+ return roots, nil
}
diff --git a/src/crypto/x509/root_darwin.go b/src/crypto/x509/root_darwin.go
index 59b303d..78de56c 100644
--- a/src/crypto/x509/root_darwin.go
+++ b/src/crypto/x509/root_darwin.go
@@ -6,27 +6,12 @@
package x509
-import (
- "bytes"
- "encoding/pem"
- "fmt"
- "io/ioutil"
- "os"
- "os/exec"
- "strconv"
- "sync"
- "syscall"
-)
+import "os/exec"
func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate, err error) {
return nil, nil
}
-// This code is only used when compiling without cgo.
-// It is here, instead of root_nocgo_darwin.go, so that tests can check it
-// even if the tests are run with cgo enabled.
-// The linker will not include these unused functions in binaries built with cgo enabled.
-
func execSecurityRoots() (*CertPool, error) {
cmd := exec.Command("/usr/bin/security", "find-certificate", "-a", "-p", "/System/Library/Keychains/SystemRootCertificates.keychain")
data, err := cmd.Output()
@@ -34,100 +19,7 @@ func execSecurityRoots() (*CertPool, error) {
return nil, err
}
- var (
- mu sync.Mutex
- roots = NewCertPool()
- )
- add := func(cert *Certificate) {
- mu.Lock()
- defer mu.Unlock()
- roots.AddCert(cert)
- }
- blockCh := make(chan *pem.Block)
- var wg sync.WaitGroup
- for i := 0; i < 4; i++ {
- wg.Add(1)
- go func() {
- defer wg.Done()
- for block := range blockCh {
- verifyCertWithSystem(block, add)
- }
- }()
- }
- for len(data) > 0 {
- var block *pem.Block
- block, data = pem.Decode(data)
- if block == nil {
- break
- }
- if block.Type != "CERTIFICATE" || len(block.Headers) != 0 {
- continue
- }
- blockCh <- block
- }
- close(blockCh)
- wg.Wait()
+ roots := NewCertPool()
+ roots.AppendCertsFromPEM(data)
return roots, nil
}
-
-func verifyCertWithSystem(block *pem.Block, add func(*Certificate)) {
- data := pem.EncodeToMemory(block)
- var cmd *exec.Cmd
- if needsTmpFiles() {
- f, err := ioutil.TempFile("", "cert")
- if err != nil {
- fmt.Fprintf(os.Stderr, "can't create temporary file for cert: %v", err)
- return
- }
- defer os.Remove(f.Name())
- if _, err := f.Write(data); err != nil {
- fmt.Fprintf(os.Stderr, "can't write temporary file for cert: %v", err)
- return
- }
- if err := f.Close(); err != nil {
- fmt.Fprintf(os.Stderr, "can't write temporary file for cert: %v", err)
- return
- }
- cmd = exec.Command("/usr/bin/security", "verify-cert", "-c", f.Name(), "-l")
- } else {
- cmd = exec.Command("/usr/bin/security", "verify-cert", "-c", "/dev/stdin", "-l")
- cmd.Stdin = bytes.NewReader(data)
- }
- if cmd.Run() == nil {
- // Non-zero exit means untrusted
- cert, err := ParseCertificate(block.Bytes)
- if err != nil {
- return
- }
-
- add(cert)
- }
-}
-
-var versionCache struct {
- sync.Once
- major int
-}
-
-// needsTmpFiles reports whether the OS is <= 10.11 (which requires real
-// files as arguments to the security command).
-func needsTmpFiles() bool {
- versionCache.Do(func() {
- release, err := syscall.Sysctl("kern.osrelease")
- if err != nil {
- return
- }
- for i, c := range release {
- if c == '.' {
- release = release[:i]
- break
- }
- }
- major, err := strconv.Atoi(release)
- if err != nil {
- return
- }
- versionCache.major = major
- })
- return versionCache.major <= 15
-}
diff --git a/src/crypto/x509/root_darwin_test.go b/src/crypto/x509/root_darwin_test.go
index c8ca3ea..8b6b151 100644
--- a/src/crypto/x509/root_darwin_test.go
+++ b/src/crypto/x509/root_darwin_test.go
@@ -29,7 +29,6 @@ func TestSystemRoots(t *testing.T) {
// On Mavericks, there are 212 bundled certs; require only
// 150 here, since this is just a sanity check, and the
// exact number will vary over time.
- t.Logf("got %d roots", len(tt.certs))
if want, have := 150, len(tt.certs); have < want {
t.Fatalf("want at least %d system roots, have %d", want, have)
}
diff --git a/src/crypto/x509/root_linux.go b/src/crypto/x509/root_linux.go
index cfeca69..38dd72d 100644
--- a/src/crypto/x509/root_linux.go
+++ b/src/crypto/x509/root_linux.go
@@ -6,8 +6,9 @@ package x509
// Possible certificate files; stop after finding one.
var certFiles = []string{
- "/etc/ssl/certs/ca-certificates.crt", // Debian/Ubuntu/Gentoo etc.
- "/etc/pki/tls/certs/ca-bundle.crt", // Fedora/RHEL
- "/etc/ssl/ca-bundle.pem", // OpenSUSE
- "/etc/pki/tls/cacert.pem", // OpenELEC
+ "/etc/ssl/certs/ca-certificates.crt", // Debian/Ubuntu/Gentoo etc.
+ "/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem", // CentOS/RHEL 7
+ "/etc/pki/tls/certs/ca-bundle.crt", // Fedora/RHEL 6
+ "/etc/ssl/ca-bundle.pem", // OpenSUSE
+ "/etc/pki/tls/cacert.pem", // OpenELEC
}
diff --git a/src/crypto/x509/root_windows.go b/src/crypto/x509/root_windows.go
index 392c869..ca2fba5 100644
--- a/src/crypto/x509/root_windows.go
+++ b/src/crypto/x509/root_windows.go
@@ -225,4 +225,37 @@ func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate
return chains, nil
}
-func loadSystemRoots() (*CertPool, error) { return nil, nil }
+func loadSystemRoots() (*CertPool, error) {
+ const CRYPT_E_NOT_FOUND = 0x80092004
+
+ store, err := syscall.CertOpenSystemStore(0, syscall.StringToUTF16Ptr("ROOT"))
+ if err != nil {
+ return nil, err
+ }
+ defer syscall.CertCloseStore(store, 0)
+
+ roots := NewCertPool()
+ var cert *syscall.CertContext
+ for {
+ cert, err = syscall.CertEnumCertificatesInStore(store, cert)
+ if err != nil {
+ if errno, ok := err.(syscall.Errno); ok {
+ if errno == CRYPT_E_NOT_FOUND {
+ break
+ }
+ }
+ return nil, err
+ }
+ if cert == nil {
+ break
+ }
+ // Copy the buf, since ParseCertificate does not create its own copy.
+ buf := (*[1 << 20]byte)(unsafe.Pointer(cert.EncodedCert))[:]
+ buf2 := make([]byte, cert.Length)
+ copy(buf2, buf)
+ if c, err := ParseCertificate(buf2); err == nil {
+ roots.AddCert(c)
+ }
+ }
+ return roots, nil
+}
diff --git a/src/crypto/x509/verify.go b/src/crypto/x509/verify.go
index 85c083f..0d3de30 100644
--- a/src/crypto/x509/verify.go
+++ b/src/crypto/x509/verify.go
@@ -5,6 +5,7 @@
package x509
import (
+ "bytes"
"errors"
"fmt"
"net"
@@ -33,6 +34,9 @@ const (
// IncompatibleUsage results when the certificate's key usage indicates
// that it may only be used for a different purpose.
IncompatibleUsage
+ // NameMismatch results when the subject name of a parent certificate
+ // does not match the issuer name in the child.
+ NameMismatch
)
// CertificateInvalidError results when an odd error occurs. Users of this
@@ -54,6 +58,8 @@ func (e CertificateInvalidError) Error() string {
return "x509: too many intermediates for path length constraint"
case IncompatibleUsage:
return "x509: certificate specifies an incompatible key usage"
+ case NameMismatch:
+ return "x509: issuer name does not match subject from issuing certificate"
}
return "x509: unknown error"
}
@@ -87,12 +93,16 @@ func (h HostnameError) Error() string {
valid = c.Subject.CommonName
}
}
+
+ if len(valid) == 0 {
+ return "x509: certificate is not valid for any names, but wanted to match " + h.Host
+ }
return "x509: certificate is valid for " + valid + ", not " + h.Host
}
// UnknownAuthorityError results when the certificate issuer is unknown
type UnknownAuthorityError struct {
- cert *Certificate
+ Cert *Certificate
// hintErr contains an error that may be helpful in determining why an
// authority wasn't found.
hintErr error
@@ -108,8 +118,9 @@ func (e UnknownAuthorityError) Error() string {
if len(certName) == 0 {
if len(e.hintCert.Subject.Organization) > 0 {
certName = e.hintCert.Subject.Organization[0]
+ } else {
+ certName = "serial:" + e.hintCert.SerialNumber.String()
}
- certName = "serial:" + e.hintCert.SerialNumber.String()
}
s += fmt.Sprintf(" (possibly because of %q while trying to verify candidate authority certificate %q)", e.hintErr, certName)
}
@@ -153,8 +164,40 @@ const (
rootCertificate
)
+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.
+ if len(constraint) == 0 {
+ return true
+ }
+
+ if len(domain) < len(constraint) {
+ return false
+ }
+
+ prefixLen := len(domain) - len(constraint)
+ if !strings.EqualFold(domain[prefixLen:], constraint) {
+ return false
+ }
+
+ if prefixLen == 0 {
+ return true
+ }
+
+ isSubdomain := domain[prefixLen-1] == '.'
+ constraintHasLeadingDot := constraint[0] == '.'
+ return isSubdomain != constraintHasLeadingDot
+}
+
// isValid performs validity checks on the c.
func (c *Certificate) isValid(certType int, currentChain []*Certificate, opts *VerifyOptions) error {
+ if len(currentChain) > 0 {
+ child := currentChain[len(currentChain)-1]
+ if !bytes.Equal(child.RawIssuer, c.RawSubject) {
+ return CertificateInvalidError{c, NameMismatch}
+ }
+ }
+
now := opts.CurrentTime
if now.IsZero() {
now = time.Now()
@@ -165,12 +208,9 @@ func (c *Certificate) isValid(certType int, currentChain []*Certificate, opts *V
if len(c.PermittedDNSDomains) > 0 {
ok := false
- for _, domain := range c.PermittedDNSDomains {
- if opts.DNSName == domain ||
- (strings.HasSuffix(opts.DNSName, domain) &&
- len(opts.DNSName) >= 1+len(domain) &&
- opts.DNSName[len(opts.DNSName)-len(domain)-1] == '.') {
- ok = true
+ for _, constraint := range c.PermittedDNSDomains {
+ ok = matchNameConstraint(opts.DNSName, constraint)
+ if ok {
break
}
}
@@ -262,9 +302,13 @@ func (c *Certificate) Verify(opts VerifyOptions) (chains [][]*Certificate, err e
}
}
- candidateChains, err := c.buildChains(make(map[int][][]*Certificate), []*Certificate{c}, &opts)
- if err != nil {
- return
+ var candidateChains [][]*Certificate
+ if opts.Roots.contains(c) {
+ candidateChains = append(candidateChains, []*Certificate{c})
+ } else {
+ if candidateChains, err = c.buildChains(make(map[int][][]*Certificate), []*Certificate{c}, &opts); err != nil {
+ return nil, err
+ }
}
keyUsages := opts.KeyUsages
@@ -302,8 +346,16 @@ func appendToFreshChain(chain []*Certificate, cert *Certificate) []*Certificate
func (c *Certificate) buildChains(cache map[int][][]*Certificate, currentChain []*Certificate, opts *VerifyOptions) (chains [][]*Certificate, err error) {
possibleRoots, failedRoot, rootErr := opts.Roots.findVerifiedParents(c)
+nextRoot:
for _, rootNum := range possibleRoots {
root := opts.Roots.certs[rootNum]
+
+ for _, cert := range currentChain {
+ if cert.Equal(root) {
+ continue nextRoot
+ }
+ }
+
err = root.isValid(rootCertificate, currentChain, opts)
if err != nil {
continue
@@ -316,7 +368,7 @@ nextIntermediate:
for _, intermediateNum := range possibleIntermediates {
intermediate := opts.Intermediates.certs[intermediateNum]
for _, cert := range currentChain {
- if cert == intermediate {
+ if cert.Equal(intermediate) {
continue nextIntermediate
}
}
diff --git a/src/crypto/x509/verify_test.go b/src/crypto/x509/verify_test.go
index bacf7de..15c4091 100644
--- a/src/crypto/x509/verify_test.go
+++ b/src/crypto/x509/verify_test.go
@@ -8,6 +8,7 @@ import (
"crypto/x509/pkix"
"encoding/pem"
"errors"
+ "fmt"
"runtime"
"strings"
"testing"
@@ -103,10 +104,6 @@ var verifyTests = []verifyTest{
expectedChains: [][]string{
{"Google", "Google Internet Authority", "GeoTrust"},
- // TODO(agl): this is ok, but it would be nice if the
- // chain building didn't visit the same SPKI
- // twice.
- {"Google", "Google Internet Authority", "GeoTrust", "GeoTrust"},
},
// CAPI doesn't build the chain with the duplicated GeoTrust
// entry so the results don't match. Thus we skip this test
@@ -129,12 +126,8 @@ var verifyTests = []verifyTest{
roots: []string{startComRoot},
currentTime: 1302726541,
- // Skip when using systemVerify, since Windows
- // can only return a single chain to us (for now).
- systemSkip: true,
expectedChains: [][]string{
{"dnssec-exp", "StartCom Class 1", "StartCom Certification Authority"},
- {"dnssec-exp", "StartCom Class 1", "StartCom Certification Authority", "StartCom Certification Authority"},
},
},
{
@@ -235,6 +228,41 @@ var verifyTests = []verifyTest{
},
},
},
+ {
+ // Putting a certificate as a root directly should work as a
+ // way of saying “exactly this”.
+ leaf: selfSigned,
+ roots: []string{selfSigned},
+ currentTime: 1471624472,
+ dnsName: "foo.example",
+ systemSkip: true,
+
+ expectedChains: [][]string{
+ {"Acme Co"},
+ },
+ },
+ {
+ // Putting a certificate as a root directly should not skip
+ // other checks however.
+ leaf: selfSigned,
+ roots: []string{selfSigned},
+ currentTime: 1471624472,
+ dnsName: "notfoo.example",
+ systemSkip: true,
+
+ errorCallback: expectHostnameError,
+ },
+ {
+ // The issuer name in the leaf doesn't exactly match the
+ // subject name in the root. Go does not perform
+ // canonicalization and so should reject this. See issue 14955.
+ leaf: issuerSubjectMatchLeaf,
+ roots: []string{issuerSubjectMatchRoot},
+ currentTime: 1475787715,
+ systemSkip: true,
+
+ errorCallback: expectSubjectIssuerMismatcthError,
+ },
}
func expectHostnameError(t *testing.T, i int, err error) (ok bool) {
@@ -262,10 +290,15 @@ func expectUsageError(t *testing.T, i int, err error) (ok bool) {
}
func expectAuthorityUnknown(t *testing.T, i int, err error) (ok bool) {
- if _, ok := err.(UnknownAuthorityError); !ok {
+ e, ok := err.(UnknownAuthorityError)
+ if !ok {
t.Errorf("#%d: error was not UnknownAuthorityError: %s", i, err)
return false
}
+ if e.Cert == nil {
+ t.Errorf("#%d: error was UnknownAuthorityError, but missing Cert: %s", i, err)
+ return false
+ }
return true
}
@@ -289,6 +322,14 @@ func expectHashError(t *testing.T, i int, err error) bool {
return true
}
+func expectSubjectIssuerMismatcthError(t *testing.T, i int, err error) (ok bool) {
+ if inval, ok := err.(CertificateInvalidError); !ok || inval.Reason != NameMismatch {
+ t.Errorf("#%d: error was not a NameMismatch: %s", i, err)
+ return false
+ }
+ return true
+}
+
func certificateFromPEM(pemBytes string) (*Certificate, error) {
block, _ := pem.Decode([]byte(pemBytes))
if block == nil {
@@ -1088,3 +1129,253 @@ Nr4TDea9Y355e6cJDUCrat2PisP29owaQgVR1EX1n6diIWgVIEM8med8vSTYqZEX
c4g/VhsxOBi0cQ+azcgOno4uG+GMmIPLHzHxREzGBHNJdmAPx/i9F4BrLunMTA5a
mnkPIAou1Z5jJh5VkpTYghdae9C8x49OhgQ=
-----END CERTIFICATE-----`
+
+const selfSigned = `-----BEGIN CERTIFICATE-----
+MIIC/DCCAeSgAwIBAgIRAK0SWRVmi67xU3z0gkgY+PkwDQYJKoZIhvcNAQELBQAw
+EjEQMA4GA1UEChMHQWNtZSBDbzAeFw0xNjA4MTkxNjMzNDdaFw0xNzA4MTkxNjMz
+NDdaMBIxEDAOBgNVBAoTB0FjbWUgQ28wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
+ggEKAoIBAQDWkm1kdCwxyKEt6OTmZitkmLGH8cQu9z7rUdrhW8lWNm4kh2SuaUWP
+pscBjda5iqg51aoKuWJR2rw6ElDne+X5eit2FT8zJgAU8v39lMFjbaVZfS9TFOYF
+w0Tk0Luo/PyKJpZnwhsP++iiGQiteJbndy8aLKmJ2MpLfpDGIgxEIyNb5dgoDi0D
+WReDCpE6K9WDYqvKVGnQ2Jvqqra6Gfx0tFkuqJxQuqA8aUOlPHcCH4KBZdNEoXdY
+YL3E4dCAh0YiDs80wNZx4cHqEM3L8gTEFqW2Tn1TSuPZO6gjJ9QPsuUZVjaMZuuO
+NVxqLGujZkDzARhC3fBpptMuaAfi20+BAgMBAAGjTTBLMA4GA1UdDwEB/wQEAwIF
+oDATBgNVHSUEDDAKBggrBgEFBQcDATAMBgNVHRMBAf8EAjAAMBYGA1UdEQQPMA2C
+C2Zvby5leGFtcGxlMA0GCSqGSIb3DQEBCwUAA4IBAQBPvvfnDhsHWt+/cfwdAVim
+4EDn+hYOMkTQwU0pouYIvY8QXYkZ8MBxpBtBMK4JhFU+ewSWoBAEH2dCCvx/BDxN
+UGTSJHMbsvJHcFvdmsvvRxOqQ/cJz7behx0cfoeHMwcs0/vWv8ms5wHesb5Ek7L0
+pl01FCBGTcncVqr6RK1r4fTpeCCfRIERD+YRJz8TtPH6ydesfLL8jIV40H8NiDfG
+vRAvOtNiKtPzFeQVdbRPOskC4rcHyPeiDAMAMixeLi63+CFty4da3r5lRezeedCE
+cw3ESZzThBwWqvPOtJdpXdm+r57pDW8qD+/0lY8wfImMNkQAyCUCLg/1Lxt/hrBj
+-----END CERTIFICATE-----`
+
+const issuerSubjectMatchRoot = `
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 161640039802297062 (0x23e42c281e55ae6)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: O=Golang, CN=Root ca
+ Validity
+ Not Before: Jan 1 00:00:00 2015 GMT
+ Not After : Jan 1 00:00:00 2025 GMT
+ Subject: O=Golang, CN=Root ca
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (1024 bit)
+ Modulus:
+ 00:e9:0e:7f:11:0c:e6:5a:e6:86:83:70:f6:51:07:
+ 2e:02:78:11:f5:b2:24:92:38:ee:26:62:02:c7:94:
+ f1:3e:a1:77:6a:c0:8f:d5:22:68:b6:5d:e2:4c:da:
+ e0:85:11:35:c2:92:72:49:8d:81:b4:88:97:6b:b7:
+ fc:b2:44:5b:d9:4d:06:70:f9:0c:c6:8f:e9:b3:df:
+ a3:6a:84:6c:43:59:be:9d:b2:d0:76:9b:c3:d7:fa:
+ 99:59:c3:b8:e5:f3:53:03:bd:49:d6:b3:cc:a2:43:
+ fe:ad:c2:0b:b9:01:b8:56:29:94:03:24:a7:0d:28:
+ 21:29:a9:ae:94:5b:4a:f9:9f
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Key Usage: critical
+ Certificate Sign
+ X509v3 Extended Key Usage:
+ TLS Web Server Authentication, TLS Web Client Authentication
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Subject Key Identifier:
+ 40:37:D7:01:FB:40:2F:B8:1C:7E:54:04:27:8C:59:01
+ Signature Algorithm: sha256WithRSAEncryption
+ 6f:84:df:49:e0:99:d4:71:66:1d:32:86:56:cb:ea:5a:6b:0e:
+ 00:6a:d1:5a:6e:1f:06:23:07:ff:cb:d1:1a:74:e4:24:43:0b:
+ aa:2a:a0:73:75:25:82:bc:bf:3f:a9:f8:48:88:ac:ed:3a:94:
+ 3b:0d:d3:88:c8:67:44:61:33:df:71:6c:c5:af:ed:16:8c:bf:
+ 82:f9:49:bb:e3:2a:07:53:36:37:25:77:de:91:a4:77:09:7f:
+ 6f:b2:91:58:c4:05:89:ea:8e:fa:e1:3b:19:ef:f8:f6:94:b7:
+ 7b:27:e6:e4:84:dd:2b:f5:93:f5:3c:d8:86:c5:38:01:56:5c:
+ 9f:6d
+-----BEGIN CERTIFICATE-----
+MIICIDCCAYmgAwIBAgIIAj5CwoHlWuYwDQYJKoZIhvcNAQELBQAwIzEPMA0GA1UE
+ChMGR29sYW5nMRAwDgYDVQQDEwdSb290IGNhMB4XDTE1MDEwMTAwMDAwMFoXDTI1
+MDEwMTAwMDAwMFowIzEPMA0GA1UEChMGR29sYW5nMRAwDgYDVQQDEwdSb290IGNh
+MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDpDn8RDOZa5oaDcPZRBy4CeBH1
+siSSOO4mYgLHlPE+oXdqwI/VImi2XeJM2uCFETXCknJJjYG0iJdrt/yyRFvZTQZw
++QzGj+mz36NqhGxDWb6dstB2m8PX+plZw7jl81MDvUnWs8yiQ/6twgu5AbhWKZQD
+JKcNKCEpqa6UW0r5nwIDAQABo10wWzAOBgNVHQ8BAf8EBAMCAgQwHQYDVR0lBBYw
+FAYIKwYBBQUHAwEGCCsGAQUFBwMCMA8GA1UdEwEB/wQFMAMBAf8wGQYDVR0OBBIE
+EEA31wH7QC+4HH5UBCeMWQEwDQYJKoZIhvcNAQELBQADgYEAb4TfSeCZ1HFmHTKG
+VsvqWmsOAGrRWm4fBiMH/8vRGnTkJEMLqiqgc3Ulgry/P6n4SIis7TqUOw3TiMhn
+RGEz33Fsxa/tFoy/gvlJu+MqB1M2NyV33pGkdwl/b7KRWMQFieqO+uE7Ge/49pS3
+eyfm5ITdK/WT9TzYhsU4AVZcn20=
+-----END CERTIFICATE-----`
+
+const issuerSubjectMatchLeaf = `
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 16785088708916013734 (0xe8f09d3fe25beaa6)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: O=Golang, CN=Root CA
+ Validity
+ Not Before: Jan 1 00:00:00 2015 GMT
+ Not After : Jan 1 00:00:00 2025 GMT
+ Subject: O=Golang, CN=Leaf
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (1024 bit)
+ Modulus:
+ 00:db:46:7d:93:2e:12:27:06:48:bc:06:28:21:ab:
+ 7e:c4:b6:a2:5d:fe:1e:52:45:88:7a:36:47:a5:08:
+ 0d:92:42:5b:c2:81:c0:be:97:79:98:40:fb:4f:6d:
+ 14:fd:2b:13:8b:c2:a5:2e:67:d8:d4:09:9e:d6:22:
+ 38:b7:4a:0b:74:73:2b:c2:34:f1:d1:93:e5:96:d9:
+ 74:7b:f3:58:9f:6c:61:3c:c0:b0:41:d4:d9:2b:2b:
+ 24:23:77:5b:1c:3b:bd:75:5d:ce:20:54:cf:a1:63:
+ 87:1d:1e:24:c4:f3:1d:1a:50:8b:aa:b6:14:43:ed:
+ 97:a7:75:62:f4:14:c8:52:d7
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Key Usage: critical
+ Digital Signature, Key Encipherment
+ X509v3 Extended Key Usage:
+ TLS Web Server Authentication, TLS Web Client Authentication
+ X509v3 Basic Constraints: critical
+ CA:FALSE
+ X509v3 Subject Key Identifier:
+ 9F:91:16:1F:43:43:3E:49:A6:DE:6D:B6:80:D7:9F:60
+ X509v3 Authority Key Identifier:
+ keyid:40:37:D7:01:FB:40:2F:B8:1C:7E:54:04:27:8C:59:01
+
+ Signature Algorithm: sha256WithRSAEncryption
+ 8d:86:05:da:89:f5:1d:c5:16:14:41:b9:34:87:2b:5c:38:99:
+ e3:d9:5a:5b:7a:5b:de:0b:5c:08:45:09:6f:1c:9d:31:5f:08:
+ ca:7a:a3:99:da:83:0b:22:be:4f:02:35:91:4e:5d:5c:37:bf:
+ 89:22:58:7d:30:76:d2:2f:d0:a0:ee:77:9e:77:c0:d6:19:eb:
+ ec:a0:63:35:6a:80:9b:80:1a:80:de:64:bc:40:38:3c:22:69:
+ ad:46:26:a2:3d:ea:f4:c2:92:49:16:03:96:ae:64:21:b9:7c:
+ ee:64:91:47:81:aa:b4:0c:09:2b:12:1a:b2:f3:af:50:b3:b1:
+ ce:24
+-----BEGIN CERTIFICATE-----
+MIICODCCAaGgAwIBAgIJAOjwnT/iW+qmMA0GCSqGSIb3DQEBCwUAMCMxDzANBgNV
+BAoTBkdvbGFuZzEQMA4GA1UEAxMHUm9vdCBDQTAeFw0xNTAxMDEwMDAwMDBaFw0y
+NTAxMDEwMDAwMDBaMCAxDzANBgNVBAoTBkdvbGFuZzENMAsGA1UEAxMETGVhZjCB
+nzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA20Z9ky4SJwZIvAYoIat+xLaiXf4e
+UkWIejZHpQgNkkJbwoHAvpd5mED7T20U/SsTi8KlLmfY1Ame1iI4t0oLdHMrwjTx
+0ZPlltl0e/NYn2xhPMCwQdTZKyskI3dbHDu9dV3OIFTPoWOHHR4kxPMdGlCLqrYU
+Q+2Xp3Vi9BTIUtcCAwEAAaN3MHUwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQG
+CCsGAQUFBwMBBggrBgEFBQcDAjAMBgNVHRMBAf8EAjAAMBkGA1UdDgQSBBCfkRYf
+Q0M+SabebbaA159gMBsGA1UdIwQUMBKAEEA31wH7QC+4HH5UBCeMWQEwDQYJKoZI
+hvcNAQELBQADgYEAjYYF2on1HcUWFEG5NIcrXDiZ49laW3pb3gtcCEUJbxydMV8I
+ynqjmdqDCyK+TwI1kU5dXDe/iSJYfTB20i/QoO53nnfA1hnr7KBjNWqAm4AagN5k
+vEA4PCJprUYmoj3q9MKSSRYDlq5kIbl87mSRR4GqtAwJKxIasvOvULOxziQ=
+-----END CERTIFICATE-----
+`
+
+var unknownAuthorityErrorTests = []struct {
+ cert string
+ expected string
+}{
+ {selfSignedWithCommonName, "x509: certificate signed by unknown authority (possibly because of \"empty\" while trying to verify candidate authority certificate \"test\")"},
+ {selfSignedNoCommonNameWithOrgName, "x509: certificate signed by unknown authority (possibly because of \"empty\" while trying to verify candidate authority certificate \"ca\")"},
+ {selfSignedNoCommonNameNoOrgName, "x509: certificate signed by unknown authority (possibly because of \"empty\" while trying to verify candidate authority certificate \"serial:0\")"},
+}
+
+func TestUnknownAuthorityError(t *testing.T) {
+ for i, tt := range unknownAuthorityErrorTests {
+ der, _ := pem.Decode([]byte(tt.cert))
+ if der == nil {
+ t.Errorf("#%d: Unable to decode PEM block", i)
+ }
+ c, err := ParseCertificate(der.Bytes)
+ if err != nil {
+ t.Errorf("#%d: Unable to parse certificate -> %s", i, err)
+ }
+ uae := &UnknownAuthorityError{
+ Cert: c,
+ hintErr: fmt.Errorf("empty"),
+ hintCert: c,
+ }
+ actual := uae.Error()
+ if strings.Compare(actual, tt.expected) != 0 {
+ t.Errorf("#%d: UnknownAuthorityError.Error() response invalid actual: %s expected: %s", i, actual, tt.expected)
+ }
+ }
+}
+
+var nameConstraintTests = []struct {
+ constraint, domain string
+ shouldMatch bool
+}{
+ {"", "anything.com", true},
+ {"example.com", "example.com", true},
+ {"example.com", "ExAmPle.coM", true},
+ {"example.com", "exampl1.com", false},
+ {"example.com", "www.ExAmPle.coM", true},
+ {"example.com", "notexample.com", false},
+ {".example.com", "example.com", false},
+ {".example.com", "www.example.com", true},
+ {".example.com", "www..example.com", false},
+}
+
+func TestNameConstraints(t *testing.T) {
+ for i, test := range nameConstraintTests {
+ result := matchNameConstraint(test.domain, test.constraint)
+ if result != test.shouldMatch {
+ t.Errorf("unexpected result for test #%d: domain=%s, constraint=%s, result=%t", i, test.domain, test.constraint, result)
+ }
+ }
+}
+
+const selfSignedWithCommonName = `-----BEGIN CERTIFICATE-----
+MIIDCjCCAfKgAwIBAgIBADANBgkqhkiG9w0BAQsFADAaMQswCQYDVQQKEwJjYTEL
+MAkGA1UEAxMCY2EwHhcNMTYwODI4MTcwOTE4WhcNMjEwODI3MTcwOTE4WjAcMQsw
+CQYDVQQKEwJjYTENMAsGA1UEAxMEdGVzdDCCASIwDQYJKoZIhvcNAQEBBQADggEP
+ADCCAQoCggEBAOH55PfRsbvmcabfLLko1w/yuapY/hk13Cgmc3WE/Z1ZStxGiVxY
+gQVH9n4W/TbUsrep/TmcC4MV7xEm5252ArcgaH6BeQ4QOTFj/6Jx0RT7U/ix+79x
+8RRysf7OlzNpGIctwZEM7i/G+0ZfqX9ULxL/EW9tppSxMX1jlXZQarnU7BERL5cH
++G2jcbU9H28FXYishqpVYE9L7xrXMm61BAwvGKB0jcVW6JdhoAOSfQbbgp7JjIlq
+czXqUsv1UdORO/horIoJptynTvuARjZzyWatya6as7wyOgEBllE6BjPK9zpn+lp3
+tQ8dwKVqm/qBPhIrVqYG/Ec7pIv8mJfYabMCAwEAAaNZMFcwDgYDVR0PAQH/BAQD
+AgOoMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDATAMBgNVHRMBAf8EAjAA
+MAoGA1UdDgQDBAEAMAwGA1UdIwQFMAOAAQAwDQYJKoZIhvcNAQELBQADggEBAAAM
+XMFphzq4S5FBcRdB2fRrmcoz+jEROBWvIH/1QUJeBEBz3ZqBaJYfBtQTvqCA5Rjw
+dxyIwVd1W3q3aSulM0tO62UCU6L6YeeY/eq8FmpD7nMJo7kCrXUUAMjxbYvS3zkT
+v/NErK6SgWnkQiPJBZNX1Q9+aSbLT/sbaCTdbWqcGNRuLGJkmqfIyoxRt0Hhpqsx
+jP5cBaVl50t4qoCuVIE9cOucnxYXnI7X5HpXWvu8Pfxo4SwVjb1az8Fk5s8ZnxGe
+fPB6Q3L/pKBe0SEe5GywpwtokPLB3lAygcuHbxp/1FlQ1NQZqq+vgXRIla26bNJf
+IuYkJwt6w+LH/9HZgf8=
+-----END CERTIFICATE-----`
+const selfSignedNoCommonNameWithOrgName = `-----BEGIN CERTIFICATE-----
+MIIC+zCCAeOgAwIBAgIBADANBgkqhkiG9w0BAQsFADAaMQswCQYDVQQKEwJjYTEL
+MAkGA1UEAxMCY2EwHhcNMTYwODI4MTgxMzQ4WhcNMjEwODI3MTgxMzQ4WjANMQsw
+CQYDVQQKEwJjYTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL5EjrUa
+7EtOMxWiIgTzp2FlQvncPsG329O3l3uNGnbigb8TmNMw2M8UhoDjd84pnU5RAfqd
+8t5TJyw/ybnIKBN131Q2xX+gPQ0dFyMvcO+i1CUgCxmYZomKVA2MXO1RD1hLTYGS
+gOVjc3no3MBwd8uVQp0NStqJ1QvLtNG4Uy+B28qe+ZFGGbjGqx8/CU4A8Szlpf7/
+xAZR8w5qFUUlpA2LQYeHHJ5fQVXw7kyL1diNrKNi0G3qcY0IrBh++hT+hnEEXyXu
+g8a0Ux18hoE8D6rAr34rCZl6AWfqW5wjwm+N5Ns2ugr9U4N8uCKJYMPHb2CtdubU
+46IzVucpTfGLdaMCAwEAAaNZMFcwDgYDVR0PAQH/BAQDAgOoMB0GA1UdJQQWMBQG
+CCsGAQUFBwMCBggrBgEFBQcDATAMBgNVHRMBAf8EAjAAMAoGA1UdDgQDBAEAMAwG
+A1UdIwQFMAOAAQAwDQYJKoZIhvcNAQELBQADggEBAEn5SgVpJ3zjsdzPqK7Qd/sB
+bYd1qtPHlrszjhbHBg35C6mDgKhcv4o6N+fuC+FojZb8lIxWzJtvT9pQbfy/V6u3
+wOb816Hm71uiP89sioIOKCvSAstj/p9doKDOUaKOcZBTw0PS2m9eja8bnleZzBvK
+rD8cNkHf74v98KvBhcwBlDifVzmkWzMG6TL1EkRXUyLKiWgoTUFSkCDV927oXXMR
+DKnszq+AVw+K8hbeV2A7GqT7YfeqOAvSbatTDnDtKOPmlCnQui8A149VgZzXv7eU
+29ssJSqjUPyp58dlV6ZuynxPho1QVZUOQgnJToXIQ3/5vIvJRXy52GJCs4/Gh/w=
+-----END CERTIFICATE-----`
+const selfSignedNoCommonNameNoOrgName = `-----BEGIN CERTIFICATE-----
+MIIC7jCCAdagAwIBAgIBADANBgkqhkiG9w0BAQsFADAaMQswCQYDVQQKEwJjYTEL
+MAkGA1UEAxMCY2EwHhcNMTYwODI4MTgxOTQ1WhcNMjEwODI3MTgxOTQ1WjAAMIIB
+IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAp3E+Jl6DpgzogHUW/i/AAcCM
+fnNJLOamNVKFGmmxhb4XTHxRaWoTzrlsyzIMS0WzivvJeZVe6mWbvuP2kZanKgIz
+35YXRTR9HbqkNTMuvnpUESzWxbGWE2jmt2+a/Jnz89FS4WIYRhF7nI2z8PvZOfrI
+2gETTT2tEpoF2S4soaYfm0DBeT8K0/rogAaf+oeUS6V+v3miRcAooJgpNJGu9kqm
+S0xKPn1RCFVjpiRd6YNS0xZirjYQIBMFBvoSoHjaOdgJptNRBprYPOxVJ/ItzGf0
+kPmzPFCx2tKfxV9HLYBPgxi+fP3IIx8aIYuJn8yReWtYEMYU11hDPeAFN5Gm+wID
+AQABo1kwVzAOBgNVHQ8BAf8EBAMCA6gwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsG
+AQUFBwMBMAwGA1UdEwEB/wQCMAAwCgYDVR0OBAMEAQAwDAYDVR0jBAUwA4ABADAN
+BgkqhkiG9w0BAQsFAAOCAQEATZVOFeiCpPM5QysToLv+8k7Rjoqt6L5IxMUJGEpq
+4ENmldmwkhEKr9VnYEJY3njydnnTm97d9vOfnLj9nA9wMBODeOO3KL2uJR2oDnmM
+9z1NSe2aQKnyBb++DM3ZdikpHn/xEpGV19pYKFQVn35x3lpPh2XijqRDO/erKemb
+w67CoNRb81dy+4Q1lGpA8ORoLWh5fIq2t2eNGc4qB8vlTIKiESzAwu7u3sRfuWQi
+4R+gnfLd37FWflMHwztFbVTuNtPOljCX0LN7KcuoXYlr05RhQrmoN7fQHsrZMNLs
+8FVjHdKKu+uPstwd04Uy4BR/H2y1yerN9j/L6ZkMl98iiA==
+-----END CERTIFICATE-----`
diff --git a/src/crypto/x509/x509.go b/src/crypto/x509/x509.go
index 9ad3cf2..d9077db 100644
--- a/src/crypto/x509/x509.go
+++ b/src/crypto/x509/x509.go
@@ -67,9 +67,8 @@ func marshalPublicKey(pub interface{}) (publicKeyBytes []byte, publicKeyAlgorith
return nil, pkix.AlgorithmIdentifier{}, err
}
publicKeyAlgorithm.Algorithm = oidPublicKeyRSA
- // This is a NULL parameters value which is technically
- // superfluous, but most other code includes it and, by
- // doing this, we match their public key hashes.
+ // 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,
}
@@ -179,21 +178,36 @@ const (
ECDSAWithSHA256
ECDSAWithSHA384
ECDSAWithSHA512
+ SHA256WithRSAPSS
+ SHA384WithRSAPSS
+ SHA512WithRSAPSS
)
+func (algo SignatureAlgorithm) isRSAPSS() bool {
+ switch algo {
+ case SHA256WithRSAPSS, SHA384WithRSAPSS, SHA512WithRSAPSS:
+ return true
+ default:
+ return false
+ }
+}
+
var algoName = [...]string{
- MD2WithRSA: "MD2-RSA",
- MD5WithRSA: "MD5-RSA",
- SHA1WithRSA: "SHA1-RSA",
- SHA256WithRSA: "SHA256-RSA",
- SHA384WithRSA: "SHA384-RSA",
- SHA512WithRSA: "SHA512-RSA",
- DSAWithSHA1: "DSA-SHA1",
- DSAWithSHA256: "DSA-SHA256",
- ECDSAWithSHA1: "ECDSA-SHA1",
- ECDSAWithSHA256: "ECDSA-SHA256",
- ECDSAWithSHA384: "ECDSA-SHA384",
- ECDSAWithSHA512: "ECDSA-SHA512",
+ MD2WithRSA: "MD2-RSA",
+ MD5WithRSA: "MD5-RSA",
+ SHA1WithRSA: "SHA1-RSA",
+ SHA256WithRSA: "SHA256-RSA",
+ SHA384WithRSA: "SHA384-RSA",
+ SHA512WithRSA: "SHA512-RSA",
+ SHA256WithRSAPSS: "SHA256-RSAPSS",
+ SHA384WithRSAPSS: "SHA384-RSAPSS",
+ SHA512WithRSAPSS: "SHA512-RSAPSS",
+ DSAWithSHA1: "DSA-SHA1",
+ DSAWithSHA256: "DSA-SHA256",
+ ECDSAWithSHA1: "ECDSA-SHA1",
+ ECDSAWithSHA256: "ECDSA-SHA256",
+ ECDSAWithSHA384: "ECDSA-SHA384",
+ ECDSAWithSHA512: "ECDSA-SHA512",
}
func (algo SignatureAlgorithm) String() string {
@@ -269,12 +283,24 @@ var (
oidSignatureSHA256WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 11}
oidSignatureSHA384WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 12}
oidSignatureSHA512WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 13}
+ oidSignatureRSAPSS = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 10}
oidSignatureDSAWithSHA1 = asn1.ObjectIdentifier{1, 2, 840, 10040, 4, 3}
oidSignatureDSAWithSHA256 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 3, 2}
oidSignatureECDSAWithSHA1 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 1}
oidSignatureECDSAWithSHA256 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 2}
oidSignatureECDSAWithSHA384 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 3}
oidSignatureECDSAWithSHA512 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 4}
+
+ oidSHA256 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 2, 1}
+ oidSHA384 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 2, 2}
+ oidSHA512 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 2, 3}
+
+ oidMGF1 = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 8}
+
+ // oidISOSignatureSHA1WithRSA means the same as oidSignatureSHA1WithRSA
+ // but it's specified by ISO. Microsoft's makecert.exe has been known
+ // to produce certificates with this OID.
+ oidISOSignatureSHA1WithRSA = asn1.ObjectIdentifier{1, 3, 14, 3, 2, 29}
)
var signatureAlgorithmDetails = []struct {
@@ -286,9 +312,13 @@ var signatureAlgorithmDetails = []struct {
{MD2WithRSA, oidSignatureMD2WithRSA, RSA, crypto.Hash(0) /* no value for MD2 */},
{MD5WithRSA, oidSignatureMD5WithRSA, RSA, crypto.MD5},
{SHA1WithRSA, oidSignatureSHA1WithRSA, RSA, crypto.SHA1},
+ {SHA1WithRSA, oidISOSignatureSHA1WithRSA, RSA, crypto.SHA1},
{SHA256WithRSA, oidSignatureSHA256WithRSA, RSA, crypto.SHA256},
{SHA384WithRSA, oidSignatureSHA384WithRSA, RSA, crypto.SHA384},
{SHA512WithRSA, oidSignatureSHA512WithRSA, RSA, crypto.SHA512},
+ {SHA256WithRSAPSS, oidSignatureRSAPSS, RSA, crypto.SHA256},
+ {SHA384WithRSAPSS, oidSignatureRSAPSS, RSA, crypto.SHA384},
+ {SHA512WithRSAPSS, oidSignatureRSAPSS, RSA, crypto.SHA512},
{DSAWithSHA1, oidSignatureDSAWithSHA1, DSA, crypto.SHA1},
{DSAWithSHA256, oidSignatureDSAWithSHA256, DSA, crypto.SHA256},
{ECDSAWithSHA1, oidSignatureECDSAWithSHA1, ECDSA, crypto.SHA1},
@@ -297,12 +327,115 @@ var signatureAlgorithmDetails = []struct {
{ECDSAWithSHA512, oidSignatureECDSAWithSHA512, ECDSA, crypto.SHA512},
}
-func getSignatureAlgorithmFromOID(oid asn1.ObjectIdentifier) SignatureAlgorithm {
- for _, details := range signatureAlgorithmDetails {
- if oid.Equal(details.oid) {
- return details.algo
+// pssParameters reflects the parameters in an AlgorithmIdentifier that
+// specifies RSA PSS. See https://tools.ietf.org/html/rfc3447#appendix-A.2.3
+type pssParameters struct {
+ // The following three fields are not marked as
+ // optional because the default values specify SHA-1,
+ // which is no longer suitable for use in signatures.
+ Hash pkix.AlgorithmIdentifier `asn1:"explicit,tag:0"`
+ MGF pkix.AlgorithmIdentifier `asn1:"explicit,tag:1"`
+ SaltLength int `asn1:"explicit,tag:2"`
+ TrailerField int `asn1:"optional,explicit,tag:3,default:1"`
+}
+
+// rsaPSSParameters returns an asn1.RawValue suitable for use as the Parameters
+// in an AlgorithmIdentifier that specifies RSA PSS.
+func rsaPSSParameters(hashFunc crypto.Hash) asn1.RawValue {
+ var hashOID asn1.ObjectIdentifier
+
+ switch hashFunc {
+ case crypto.SHA256:
+ hashOID = oidSHA256
+ case crypto.SHA384:
+ hashOID = oidSHA384
+ case crypto.SHA512:
+ hashOID = oidSHA512
+ }
+
+ params := pssParameters{
+ Hash: pkix.AlgorithmIdentifier{
+ Algorithm: hashOID,
+ Parameters: asn1.RawValue{
+ Tag: 5, /* ASN.1 NULL */
+ },
+ },
+ MGF: pkix.AlgorithmIdentifier{
+ Algorithm: oidMGF1,
+ },
+ SaltLength: hashFunc.Size(),
+ TrailerField: 1,
+ }
+
+ mgf1Params := pkix.AlgorithmIdentifier{
+ Algorithm: hashOID,
+ Parameters: asn1.RawValue{
+ Tag: 5, /* ASN.1 NULL */
+ },
+ }
+
+ var err error
+ params.MGF.Parameters.FullBytes, err = asn1.Marshal(mgf1Params)
+ if err != nil {
+ panic(err)
+ }
+
+ serialized, err := asn1.Marshal(params)
+ if err != nil {
+ panic(err)
+ }
+
+ return asn1.RawValue{FullBytes: serialized}
+}
+
+func getSignatureAlgorithmFromAI(ai pkix.AlgorithmIdentifier) SignatureAlgorithm {
+ if !ai.Algorithm.Equal(oidSignatureRSAPSS) {
+ for _, details := range signatureAlgorithmDetails {
+ if ai.Algorithm.Equal(details.oid) {
+ return details.algo
+ }
}
+ return UnknownSignatureAlgorithm
+ }
+
+ // RSA PSS is special because it encodes important parameters
+ // in the Parameters.
+
+ var params pssParameters
+ if _, err := asn1.Unmarshal(ai.Parameters.FullBytes, ¶ms); err != nil {
+ return UnknownSignatureAlgorithm
+ }
+
+ var mgf1HashFunc pkix.AlgorithmIdentifier
+ if _, err := asn1.Unmarshal(params.MGF.Parameters.FullBytes, &mgf1HashFunc); err != nil {
+ return UnknownSignatureAlgorithm
}
+
+ // PSS is greatly overburdened with options. This code forces
+ // them into three buckets by requiring that the MGF1 hash
+ // function always match the message hash function (as
+ // recommended in
+ // 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) ||
+ !params.MGF.Algorithm.Equal(oidMGF1) ||
+ !mgf1HashFunc.Algorithm.Equal(params.Hash.Algorithm) ||
+ !bytes.Equal(mgf1HashFunc.Parameters.FullBytes, asn1NULL) ||
+ params.TrailerField != 1 {
+ return UnknownSignatureAlgorithm
+ }
+
+ switch {
+ case params.Hash.Algorithm.Equal(oidSHA256) && params.SaltLength == 32:
+ return SHA256WithRSAPSS
+ case params.Hash.Algorithm.Equal(oidSHA384) && params.SaltLength == 48:
+ return SHA384WithRSAPSS
+ case params.Hash.Algorithm.Equal(oidSHA512) && params.SaltLength == 64:
+ return SHA512WithRSAPSS
+ }
+
return UnknownSignatureAlgorithm
}
@@ -681,11 +814,11 @@ func checkSignature(algo SignatureAlgorithm, signed, signature []byte, publicKey
switch algo {
case SHA1WithRSA, DSAWithSHA1, ECDSAWithSHA1:
hashType = crypto.SHA1
- case SHA256WithRSA, DSAWithSHA256, ECDSAWithSHA256:
+ case SHA256WithRSA, SHA256WithRSAPSS, DSAWithSHA256, ECDSAWithSHA256:
hashType = crypto.SHA256
- case SHA384WithRSA, ECDSAWithSHA384:
+ case SHA384WithRSA, SHA384WithRSAPSS, ECDSAWithSHA384:
hashType = crypto.SHA384
- case SHA512WithRSA, ECDSAWithSHA512:
+ case SHA512WithRSA, SHA512WithRSAPSS, ECDSAWithSHA512:
hashType = crypto.SHA512
case MD2WithRSA, MD5WithRSA:
return InsecureAlgorithmError(algo)
@@ -703,7 +836,11 @@ func checkSignature(algo SignatureAlgorithm, signed, signature []byte, publicKey
switch pub := publicKey.(type) {
case *rsa.PublicKey:
- return rsa.VerifyPKCS1v15(pub, hashType, digest, signature)
+ if algo.isRSAPSS() {
+ return rsa.VerifyPSS(pub, hashType, digest, signature, &rsa.PSSOptions{SaltLength: rsa.PSSSaltLengthEqualsHash})
+ } else {
+ return rsa.VerifyPKCS1v15(pub, hashType, digest, signature)
+ }
case *dsa.PublicKey:
dsaSig := new(dsaSignature)
if rest, err := asn1.Unmarshal(signature, dsaSig); err != nil {
@@ -738,7 +875,7 @@ func checkSignature(algo SignatureAlgorithm, signed, signature []byte, publicKey
// CheckCRLSignature checks that the signature in crl is from c.
func (c *Certificate) CheckCRLSignature(crl *pkix.CertificateList) error {
- algo := getSignatureAlgorithmFromOID(crl.SignatureAlgorithm.Algorithm)
+ algo := getSignatureAlgorithmFromAI(crl.SignatureAlgorithm)
return c.CheckSignature(algo, crl.TBSCertList.Raw, crl.SignatureValue.RightAlign())
}
@@ -787,10 +924,19 @@ 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) {
+ return nil, errors.New("x509: RSA key missing NULL parameters")
+ }
+
p := new(rsaPublicKey)
rest, err := asn1.Unmarshal(asn1Data, p)
if err != nil {
@@ -937,7 +1083,7 @@ func parseCertificate(in *certificate) (*Certificate, error) {
out.Signature = in.SignatureValue.RightAlign()
out.SignatureAlgorithm =
- getSignatureAlgorithmFromOID(in.TBSCertificate.SignatureAlgorithm.Algorithm)
+ getSignatureAlgorithmFromAI(in.TBSCertificate.SignatureAlgorithm)
out.PublicKeyAlgorithm =
getPublicKeyAlgorithmFromOID(in.TBSCertificate.PublicKey.Algorithm.Algorithm)
@@ -1545,6 +1691,9 @@ func signingParamsForPublicKey(pub interface{}, requestedSigAlgo SignatureAlgori
err = errors.New("x509: cannot sign with hash function requested")
return
}
+ if requestedSigAlgo.isRSAPSS() {
+ sigAlgo.Parameters = rsaPSSParameters(hashFunc)
+ }
found = true
break
}
@@ -1577,6 +1726,10 @@ func CreateCertificate(rand io.Reader, template, parent *Certificate, pub, priv
return nil, errors.New("x509: certificate private key does not implement crypto.Signer")
}
+ if template.SerialNumber == nil {
+ return nil, errors.New("x509: no SerialNumber given")
+ }
+
hashFunc, signatureAlgorithm, err := signingParamsForPublicKey(key.Public(), template.SignatureAlgorithm)
if err != nil {
return nil, err
@@ -1629,8 +1782,17 @@ func CreateCertificate(rand io.Reader, template, parent *Certificate, pub, priv
h.Write(tbsCertContents)
digest := h.Sum(nil)
+ var signerOpts crypto.SignerOpts
+ signerOpts = hashFunc
+ if template.SignatureAlgorithm != 0 && template.SignatureAlgorithm.isRSAPSS() {
+ signerOpts = &rsa.PSSOptions{
+ SaltLength: rsa.PSSSaltLengthEqualsHash,
+ Hash: hashFunc,
+ }
+ }
+
var signature []byte
- signature, err = key.Sign(rand, digest, hashFunc)
+ signature, err = key.Sign(rand, digest, signerOpts)
if err != nil {
return
}
@@ -1804,7 +1966,7 @@ func newRawAttributes(attributes []pkix.AttributeTypeAndValueSET) ([]asn1.RawVal
return nil, err
}
if len(rest) != 0 {
- return nil, errors.New("x509: failed to unmarshall raw CSR Attributes")
+ return nil, errors.New("x509: failed to unmarshal raw CSR Attributes")
}
return rawAttributes, nil
}
@@ -2035,7 +2197,7 @@ func parseCertificateRequest(in *certificateRequest) (*CertificateRequest, error
RawSubject: in.TBSCSR.Subject.FullBytes,
Signature: in.SignatureValue.RightAlign(),
- SignatureAlgorithm: getSignatureAlgorithmFromOID(in.SignatureAlgorithm.Algorithm),
+ SignatureAlgorithm: getSignatureAlgorithmFromAI(in.SignatureAlgorithm),
PublicKeyAlgorithm: getPublicKeyAlgorithmFromOID(in.TBSCSR.PublicKey.Algorithm.Algorithm),
diff --git a/src/crypto/x509/x509_test.go b/src/crypto/x509/x509_test.go
index c6448d3..354545c 100644
--- a/src/crypto/x509/x509_test.go
+++ b/src/crypto/x509/x509_test.go
@@ -24,6 +24,7 @@ import (
"net"
"os/exec"
"reflect"
+ "strings"
"testing"
"time"
)
@@ -85,14 +86,21 @@ FF53oIpvxe/SCOymfWq/LW849Ytv3Xwod0+wzAP8STXG4HSELS4UedPYeHJJJYcZ
-----END PUBLIC KEY-----
`
-var pemPrivateKey = `-----BEGIN RSA PRIVATE KEY-----
-MIIBOgIBAAJBALKZD0nEffqM1ACuak0bijtqE2QrI/KLADv7l3kK3ppMyCuLKoF0
-fd7Ai2KW5ToIwzFofvJcS/STa6HA5gQenRUCAwEAAQJBAIq9amn00aS0h/CrjXqu
-/ThglAXJmZhOMPVn4eiu7/ROixi9sex436MaVeMqSNf7Ex9a8fRNfWss7Sqd9eWu
-RTUCIQDasvGASLqmjeffBNLTXV2A5g4t+kLVCpsEIZAycV5GswIhANEPLmax0ME/
-EO+ZJ79TJKN5yiGBRsv5yvx5UiHxajEXAiAhAol5N4EUyq6I9w1rYdhPMGpLfk7A
-IU2snfRJ6Nq2CQIgFrPsWRCkV+gOYcajD17rEqmuLrdIRexpg8N1DOSXoJ8CIGlS
-tAboUGBxTDq3ZroNism3DaMIbKPyYrAqhKov1h5V
+var pemPrivateKey = `
+-----BEGIN RSA PRIVATE KEY-----
+MIICXAIBAAKBgQCxoeCUW5KJxNPxMp+KmCxKLc1Zv9Ny+4CFqcUXVUYH69L3mQ7v
+IWrJ9GBfcaA7BPQqUlWxWM+OCEQZH1EZNIuqRMNQVuIGCbz5UQ8w6tS0gcgdeGX7
+J7jgCQ4RK3F/PuCM38QBLaHx988qG8NMc6VKErBjctCXFHQt14lerd5KpQIDAQAB
+AoGAYrf6Hbk+mT5AI33k2Jt1kcweodBP7UkExkPxeuQzRVe0KVJw0EkcFhywKpr1
+V5eLMrILWcJnpyHE5slWwtFHBG6a5fLaNtsBBtcAIfqTQ0Vfj5c6SzVaJv0Z5rOd
+7gQF6isy3t3w9IF3We9wXQKzT6q5ypPGdm6fciKQ8RnzREkCQQDZwppKATqQ41/R
+vhSj90fFifrGE6aVKC1hgSpxGQa4oIdsYYHwMzyhBmWW9Xv/R+fPyr8ZwPxp2c12
+33QwOLPLAkEA0NNUb+z4ebVVHyvSwF5jhfJxigim+s49KuzJ1+A2RaSApGyBZiwS
+rWvWkB471POAKUYt5ykIWVZ83zcceQiNTwJBAMJUFQZX5GDqWFc/zwGoKkeR49Yi
+MTXIvf7Wmv6E++eFcnT461FlGAUHRV+bQQXGsItR/opIG7mGogIkVXa3E1MCQARX
+AAA7eoZ9AEHflUeuLn9QJI/r0hyQQLEtrpwv6rDT1GCWaLII5HJ6NUFVf4TTcqxo
+6vdM4QGKTJoO+SaCyP0CQFdpcxSAuzpFcKv0IlJ8XzS/cy+mweCMwyJ1PFEc4FX6
+wg/HcAJWY60xZTJDFN+Qfx8ZQvBEin6c2/h+zZi5IVY=
-----END RSA PRIVATE KEY-----
`
@@ -127,13 +135,13 @@ func bigFromHexString(s string) *big.Int {
var rsaPrivateKey = &rsa.PrivateKey{
PublicKey: rsa.PublicKey{
- N: bigFromString("9353930466774385905609975137998169297361893554149986716853295022578535724979677252958524466350471210367835187480748268864277464700638583474144061408845077"),
+ N: bigFromString("124737666279038955318614287965056875799409043964547386061640914307192830334599556034328900586693254156136128122194531292927142396093148164407300419162827624945636708870992355233833321488652786796134504707628792159725681555822420087112284637501705261187690946267527866880072856272532711620639179596808018872997"),
E: 65537,
},
- D: bigFromString("7266398431328116344057699379749222532279343923819063639497049039389899328538543087657733766554155839834519529439851673014800261285757759040931985506583861"),
+ D: bigFromString("69322600686866301945688231018559005300304807960033948687567105312977055197015197977971637657636780793670599180105424702854759606794705928621125408040473426339714144598640466128488132656829419518221592374964225347786430566310906679585739468938549035854760501049443920822523780156843263434219450229353270690889"),
Primes: []*big.Int{
- bigFromString("98920366548084643601728869055592650835572950932266967461790948584315647051443"),
- bigFromString("94560208308847015747498523884063394671606671904944666360068158221458669711639"),
+ bigFromString("11405025354575369741595561190164746858706645478381139288033759331174478411254205003127028642766986913445391069745480057674348716675323735886284176682955723"),
+ bigFromString("10937079261204603443118731009201819560867324167189758120988909645641782263430128449826989846631183550578761324239709121189827307416350485191350050332642639"),
},
}
@@ -340,6 +348,9 @@ func TestCreateSelfSignedCertificate(t *testing.T) {
{"RSA/ECDSA", &testPrivateKey.PublicKey, ecdsaPriv, false, ECDSAWithSHA384},
{"ECDSA/RSA", &ecdsaPriv.PublicKey, testPrivateKey, false, SHA256WithRSA},
{"ECDSA/ECDSA", &ecdsaPriv.PublicKey, ecdsaPriv, true, ECDSAWithSHA1},
+ {"RSAPSS/RSAPSS", &testPrivateKey.PublicKey, testPrivateKey, true, SHA256WithRSAPSS},
+ {"ECDSA/RSAPSS", &ecdsaPriv.PublicKey, testPrivateKey, false, SHA256WithRSAPSS},
+ {"RSAPSS/ECDSA", &testPrivateKey.PublicKey, ecdsaPriv, false, ECDSAWithSHA384},
}
testExtKeyUsage := []ExtKeyUsage{ExtKeyUsageClientAuth, ExtKeyUsageServerAuth}
@@ -761,16 +772,76 @@ func TestVerifyCertificateWithDSASignature(t *testing.T) {
}
}
+var rsaPSSSelfSignedPEM = `-----BEGIN CERTIFICATE-----
+MIIGHjCCA9KgAwIBAgIBdjBBBgkqhkiG9w0BAQowNKAPMA0GCWCGSAFlAwQCAQUA
+oRwwGgYJKoZIhvcNAQEIMA0GCWCGSAFlAwQCAQUAogMCASAwbjELMAkGA1UEBhMC
+SlAxHDAaBgNVBAoME0phcGFuZXNlIEdvdmVybm1lbnQxKDAmBgNVBAsMH1RoZSBN
+aW5pc3RyeSBvZiBGb3JlaWduIEFmZmFpcnMxFzAVBgNVBAMMDmUtcGFzc3BvcnRD
+U0NBMB4XDTEzMDUxNDA1MDczMFoXDTI5MDUxNDA1MDczMFowbjELMAkGA1UEBhMC
+SlAxHDAaBgNVBAoME0phcGFuZXNlIEdvdmVybm1lbnQxKDAmBgNVBAsMH1RoZSBN
+aW5pc3RyeSBvZiBGb3JlaWduIEFmZmFpcnMxFzAVBgNVBAMMDmUtcGFzc3BvcnRD
+U0NBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAx/E3WRVxcCDXhoST
+8nVSLjW6hwM4Ni99AegWzcGtfGFo0zjFA1Cl5URqxauvYu3gQgQHBGA1CovWeGrl
+yVSRzOL1imcYsSgLOcnhVYB3Xcrof4ebv9+W+TwNdc9YzAwcj8rNd5nP6PKXIQ+W
+PCkEOXdyb80YEnxuT+NPjkVfFSPBS7QYZpvT2fwy4fZ0eh48253+7VleSmTO0mqj
+7TlzaG56q150SLZbhpOd8jD8bM/wACnLCPR88wj4hCcDLEwoLyY85HJCTIQQMnoT
+UpqyzEeupPREIm6yi4d8C9YqIWFn2YTnRcWcmMaJLzq+kYwKoudfnoC6RW2vzZXn
+defQs68IZuK+uALu9G3JWGPgu0CQGj0JNDT8zkiDV++4eNrZczWKjr1YnAL+VbLK
+bApwL2u19l2WDpfUklimhWfraqHNIUKU6CjZOG31RzXcplIj0mtqs0E1r7r357Es
+yFoB28iNo4cz1lCulh0E4WJzWzLZcT4ZspHHRCFyvYnXoibXEV1nULq8ByKKG0FS
+7nn4SseoV+8PvjHLPhmHGMvi4mxkbcXdV3wthHT1/HXdqY84A4xHWt1+sB/TpTek
+tDhFlEfcUygvTu58UtOnysomOVVeERmi7WSujfzKsGJAJYeetiA5R+zX7BxeyFVE
+qW0zh1Tkwh0S8LRe5diJh4+6FG0CAwEAAaNfMF0wHQYDVR0OBBYEFD+oahaikBTV
+Urk81Uz7kRS2sx0aMA4GA1UdDwEB/wQEAwIBBjAYBgNVHSAEETAPMA0GCyqDCIaP
+fgYFAQEBMBIGA1UdEwEB/wQIMAYBAf8CAQAwQQYJKoZIhvcNAQEKMDSgDzANBglg
+hkgBZQMEAgEFAKEcMBoGCSqGSIb3DQEBCDANBglghkgBZQMEAgEFAKIDAgEgA4IC
+AQAaxWBQn5CZuNBfyzL57mn31ukHUFd61OMROSX3PT7oCv1Dy+C2AdRlxOcbN3/n
+li0yfXUUqiY3COlLAHKRlkr97mLtxEFoJ0R8nVN2IQdChNQM/XSCzSGyY8NVa1OR
+TTpEWLnexJ9kvIdbFXwUqdTnAkOI0m7Rg8j+E+lRRHg1xDAA1qKttrtUj3HRQWf3
+kNTu628SiMvap6aIdncburaK56MP7gkR1Wr/ichOfjIA3Jgw2PapI31i0GqeMd66
+U1+lC9FeyMAJpuSVp/SoiYzYo+79SFcVoM2yw3yAnIKg7q9GLYYqzncdykT6C06c
+15gWFI6igmReAsD9ITSvYh0jLrLHfEYcPTOD3ZXJ4EwwHtWSoO3gq1EAtOYKu/Lv
+C8zfBsZcFdsHvsSiYeBU8Oioe42mguky3Ax9O7D805Ek6R68ra07MW/G4YxvV7IN
+2BfSaYy8MX9IG0ZMIOcoc0FeF5xkFmJ7kdrlTaJzC0IE9PNxNaH5QnOAFB8vxHcO
+FioUxb6UKdHcPLR1VZtAdTdTMjSJxUqD/35Cdfqs7oDJXz8f6TXO2Tdy6G++YUs9
+qsGZWxzFvvkXUkQSl0dQQ5jO/FtUJcAVXVVp20LxPemfatAHpW31WdJYeWSQWky2
++f9b5TXKXVyjlUL7uHxowWrT2AtTchDH22wTEtqLEF9Z3Q==
+-----END CERTIFICATE-----`
+
+func TestRSAPSSSelfSigned(t *testing.T) {
+ der, _ := pem.Decode([]byte(rsaPSSSelfSignedPEM))
+ if der == nil {
+ t.Fatal("Failed to find PEM block")
+ }
+
+ cert, err := ParseCertificate(der.Bytes)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if err = cert.CheckSignatureFrom(cert); err != nil {
+ t.Fatal(err)
+ }
+}
+
const pemCertificate = `-----BEGIN CERTIFICATE-----
-MIIB5DCCAZCgAwIBAgIBATALBgkqhkiG9w0BAQUwLTEQMA4GA1UEChMHQWNtZSBDbzEZMBcGA1UE
-AxMQdGVzdC5leGFtcGxlLmNvbTAeFw03MDAxMDEwMDE2NDBaFw03MDAxMDIwMzQ2NDBaMC0xEDAO
-BgNVBAoTB0FjbWUgQ28xGTAXBgNVBAMTEHRlc3QuZXhhbXBsZS5jb20wWjALBgkqhkiG9w0BAQED
-SwAwSAJBALKZD0nEffqM1ACuak0bijtqE2QrI/KLADv7l3kK3ppMyCuLKoF0fd7Ai2KW5ToIwzFo
-fvJcS/STa6HA5gQenRUCAwEAAaOBnjCBmzAOBgNVHQ8BAf8EBAMCAAQwDwYDVR0TAQH/BAUwAwEB
-/zANBgNVHQ4EBgQEAQIDBDAPBgNVHSMECDAGgAQBAgMEMBsGA1UdEQQUMBKCEHRlc3QuZXhhbXBs
-ZS5jb20wDwYDVR0gBAgwBjAEBgIqAzAqBgNVHR4EIzAhoB8wDoIMLmV4YW1wbGUuY29tMA2CC2V4
-YW1wbGUuY29tMAsGCSqGSIb3DQEBBQNBAHKZKoS1wEQOGhgklx4+/yFYQlnqwKXvar/ZecQvJwui
-0seMQnwBhwdBkHfVIU2Fu5VUMRyxlf0ZNaDXcpU581k=
+MIIDATCCAemgAwIBAgIRAKQkkrFx1T/dgB/Go/xBM5swDQYJKoZIhvcNAQELBQAw
+EjEQMA4GA1UEChMHQWNtZSBDbzAeFw0xNjA4MTcyMDM2MDdaFw0xNzA4MTcyMDM2
+MDdaMBIxEDAOBgNVBAoTB0FjbWUgQ28wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
+ggEKAoIBAQDAoJtjG7M6InsWwIo+l3qq9u+g2rKFXNu9/mZ24XQ8XhV6PUR+5HQ4
+jUFWC58ExYhottqK5zQtKGkw5NuhjowFUgWB/VlNGAUBHtJcWR/062wYrHBYRxJH
+qVXOpYKbIWwFKoXu3hcpg/CkdOlDWGKoZKBCwQwUBhWE7MDhpVdQ+ZljUJWL+FlK
+yQK5iRsJd5TGJ6VUzLzdT4fmN2DzeK6GLeyMpVpU3sWV90JJbxWQ4YrzkKzYhMmB
+EcpXTG2wm+ujiHU/k2p8zlf8Sm7VBM/scmnMFt0ynNXop4FWvJzEm1G0xD2t+e2I
+5Utr04dOZPCgkm++QJgYhtZvgW7ZZiGTAgMBAAGjUjBQMA4GA1UdDwEB/wQEAwIF
+oDATBgNVHSUEDDAKBggrBgEFBQcDATAMBgNVHRMBAf8EAjAAMBsGA1UdEQQUMBKC
+EHRlc3QuZXhhbXBsZS5jb20wDQYJKoZIhvcNAQELBQADggEBADpqKQxrthH5InC7
+X96UP0OJCu/lLEMkrjoEWYIQaFl7uLPxKH5AmQPH4lYwF7u7gksR7owVG9QU9fs6
+1fK7II9CVgCd/4tZ0zm98FmU4D0lHGtPARrrzoZaqVZcAvRnFTlPX5pFkPhVjjai
+/mkxX9LpD8oK1445DFHxK5UjLMmPIIWd8EOi+v5a+hgGwnJpoW7hntSl8kHMtTmy
+fnnktsblSUV4lRCit0ymC7Ojhe+gzCCwkgs5kDzVVag+tnl/0e2DloIjASwOhpbH
+KVcg7fBd484ht/sS+l0dsB4KDOSpd8JzVDMF8OZqlaydizoJO0yWr9GbCN1+OKq5
+EhLrEqU=
-----END CERTIFICATE-----`
func TestCRLCreation(t *testing.T) {
@@ -867,7 +938,7 @@ func TestParsePEMCRL(t *testing.T) {
func TestImports(t *testing.T) {
testenv.MustHaveGoRun(t)
- if err := exec.Command("go", "run", "x509_test_import.go").Run(); err != nil {
+ if err := exec.Command(testenv.GoToolPath(t), "run", "x509_test_import.go").Run(); err != nil {
t.Errorf("failed to run x509_test_import.go: %s", err)
}
}
@@ -1284,3 +1355,112 @@ func TestMD5(t *testing.T) {
t.Fatalf("certificate verification returned %v (%T), wanted InsecureAlgorithmError", err, err)
}
}
+
+// certMissingRSANULL contains an RSA public key where the AlgorithmIdentifer
+// parameters are omitted rather than being an ASN.1 NULL.
+const certMissingRSANULL = `
+-----BEGIN CERTIFICATE-----
+MIIB7TCCAVigAwIBAgIBADALBgkqhkiG9w0BAQUwJjEQMA4GA1UEChMHQWNtZSBD
+bzESMBAGA1UEAxMJMTI3LjAuMC4xMB4XDTExMTIwODA3NTUxMloXDTEyMTIwNzA4
+MDAxMlowJjEQMA4GA1UEChMHQWNtZSBDbzESMBAGA1UEAxMJMTI3LjAuMC4xMIGc
+MAsGCSqGSIb3DQEBAQOBjAAwgYgCgYBO0Hsx44Jk2VnAwoekXh6LczPHY1PfZpIG
+hPZk1Y/kNqcdK+izIDZFI7Xjla7t4PUgnI2V339aEu+H5Fto5OkOdOwEin/ekyfE
+ARl6vfLcPRSr0FTKIQzQTW6HLlzF0rtNS0/Otiz3fojsfNcCkXSmHgwa2uNKWi7e
+E5xMQIhZkwIDAQABozIwMDAOBgNVHQ8BAf8EBAMCAKAwDQYDVR0OBAYEBAECAwQw
+DwYDVR0jBAgwBoAEAQIDBDALBgkqhkiG9w0BAQUDgYEANh+zegx1yW43RmEr1b3A
+p0vMRpqBWHyFeSnIyMZn3TJWRSt1tukkqVCavh9a+hoV2cxVlXIWg7nCto/9iIw4
+hB2rXZIxE0/9gzvGnfERYraL7KtnvshksBFQRlgXa5kc0x38BvEO5ZaoDPl4ILdE
+GFGNEH5PlGffo05wc46QkYU=
+-----END CERTIFICATE-----`
+
+func TestRSAMissingNULLParameters(t *testing.T) {
+ block, _ := pem.Decode([]byte(certMissingRSANULL))
+ if _, err := ParseCertificate(block.Bytes); err == nil {
+ t.Error("unexpected success when parsing certificate with missing RSA NULL parameter")
+ } else if !strings.Contains(err.Error(), "missing NULL") {
+ t.Errorf("unrecognised error when parsing certificate with missing RSA NULL parameter: %s", err)
+ }
+}
+
+const certISOOID = `
+-----BEGIN CERTIFICATE-----
+MIIB5TCCAVKgAwIBAgIQtwyL3RPWV7dJQp34HwZG9DAJBgUrDgMCHQUAMBExDzAN
+BgNVBAMTBm15dGVzdDAeFw0xNjA4MDkyMjExMDVaFw0zOTEyMzEyMzU5NTlaMBEx
+DzANBgNVBAMTBm15dGVzdDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEArzIH
+GsyDB3ohIGkkvijF2PTRUX1bvOtY1eUUpjwHyu0twpAKSuaQv2Ha+/63+aHe8O86
+BT+98wjXFX6RFSagtAujo80rIF2dSm33BGt18pDN8v6zp93dnAm0jRaSQrHJ75xw
+5O+S1oEYR1LtUoFJy6qB104j6aINBAgOiLIKiMkCAwEAAaNGMEQwQgYDVR0BBDsw
+OYAQVuYVQ/WDjdGSkZRlTtJDNKETMBExDzANBgNVBAMTBm15dGVzdIIQtwyL3RPW
+V7dJQp34HwZG9DAJBgUrDgMCHQUAA4GBABngrSkH7vG5lY4sa4AZF59lAAXqBVJE
+J4TBiKC62hCdZv18rBleP6ETfhbPg7pTs8p4ebQbpmtNxRS9Lw3MzQ8Ya5Ybwzj2
+NwBSyCtCQl7mrEg4nJqJl4A2EUhnET/oVxU0oTV/SZ3ziGXcY1oG1s6vidV7TZTu
+MCRtdSdaM7g3
+-----END CERTIFICATE-----`
+
+func TestISOOIDInCertificate(t *testing.T) {
+ block, _ := pem.Decode([]byte(certISOOID))
+ if cert, err := ParseCertificate(block.Bytes); err != nil {
+ t.Errorf("certificate with ISO OID failed to parse: %s", err)
+ } else if cert.SignatureAlgorithm == UnknownSignatureAlgorithm {
+ t.Errorf("ISO OID not recognised in certificate")
+ }
+}
+
+// certMultipleRDN contains a RelativeDistinguishedName with two elements (the
+// common name and serial number). This particular certificate was the first
+// such certificate in the “Pilot” Certificate Transparency log.
+const certMultipleRDN = `
+-----BEGIN CERTIFICATE-----
+MIIFRzCCBC+gAwIBAgIEOl59NTANBgkqhkiG9w0BAQUFADA9MQswCQYDVQQGEwJz
+aTEbMBkGA1UEChMSc3RhdGUtaW5zdGl0dXRpb25zMREwDwYDVQQLEwhzaWdvdi1j
+YTAeFw0xMjExMTYxMDUyNTdaFw0xNzExMTYxMjQ5MDVaMIGLMQswCQYDVQQGEwJz
+aTEbMBkGA1UEChMSc3RhdGUtaW5zdGl0dXRpb25zMRkwFwYDVQQLExB3ZWItY2Vy
+dGlmaWNhdGVzMRAwDgYDVQQLEwdTZXJ2ZXJzMTIwFAYDVQQFEw0xMjM2NDg0MDEw
+MDEwMBoGA1UEAxMTZXBvcnRhbC5tc3MuZWR1cy5zaTCCASIwDQYJKoZIhvcNAQEB
+BQADggEPADCCAQoCggEBAMrNkZH9MPuBTjMGNk3sJX8V+CkFx/4ru7RTlLS6dlYM
+098dtSfJ3s2w0p/1NB9UmR8j0yS0Kg6yoZ3ShsSO4DWBtcQD8820a6BYwqxxQTNf
+HSRZOc+N/4TQrvmK6t4k9Aw+YEYTMrWOU4UTeyhDeCcUsBdh7HjfWsVaqNky+2sv
+oic3zP5gF+2QfPkvOoHT3FLR8olNhViIE6Kk3eFIEs4dkq/ZzlYdLb8pHQoj/sGI
+zFmA5AFvm1HURqOmJriFjBwaCtn8AVEYOtQrnUCzJYu1ex8azyS2ZgYMX0u8A5Z/
+y2aMS/B2W+H79WcgLpK28vPwe7vam0oFrVytAd+u65ECAwEAAaOCAf4wggH6MA4G
+A1UdDwEB/wQEAwIFoDBABgNVHSAEOTA3MDUGCisGAQQBr1kBAwMwJzAlBggrBgEF
+BQcCARYZaHR0cDovL3d3dy5jYS5nb3Yuc2kvY3BzLzAfBgNVHREEGDAWgRRwb2Rw
+b3JhLm1pemtzQGdvdi5zaTCB8QYDVR0fBIHpMIHmMFWgU6BRpE8wTTELMAkGA1UE
+BhMCc2kxGzAZBgNVBAoTEnN0YXRlLWluc3RpdHV0aW9uczERMA8GA1UECxMIc2ln
+b3YtY2ExDjAMBgNVBAMTBUNSTDM5MIGMoIGJoIGGhldsZGFwOi8veDUwMC5nb3Yu
+c2kvb3U9c2lnb3YtY2Esbz1zdGF0ZS1pbnN0aXR1dGlvbnMsYz1zaT9jZXJ0aWZp
+Y2F0ZVJldm9jYXRpb25MaXN0P2Jhc2WGK2h0dHA6Ly93d3cuc2lnb3YtY2EuZ292
+LnNpL2NybC9zaWdvdi1jYS5jcmwwKwYDVR0QBCQwIoAPMjAxMjExMTYxMDUyNTda
+gQ8yMDE3MTExNjEyNDkwNVowHwYDVR0jBBgwFoAUHvjUU2uzgwbpBAZXAvmlv8ZY
+PHIwHQYDVR0OBBYEFGI1Duuu+wTGDZka/xHNbwcbM69ZMAkGA1UdEwQCMAAwGQYJ
+KoZIhvZ9B0EABAwwChsEVjcuMQMCA6gwDQYJKoZIhvcNAQEFBQADggEBAHny0K1y
+BQznrzDu3DDpBcGYguKU0dvU9rqsV1ua4nxkriSMWjgsX6XJFDdDW60I3P4VWab5
+ag5fZzbGqi8kva/CzGgZh+CES0aWCPy+4Gb8lwOTt+854/laaJvd6kgKTER7z7U9
+9C86Ch2y4sXNwwwPJ1A9dmrZJZOcJjS/WYZgwaafY2Hdxub5jqPE5nehwYUPVu9R
+uH6/skk4OEKcfOtN0hCnISOVuKYyS4ANARWRG5VGHIH06z3lGUVARFRJ61gtAprd
+La+fgSS+LVZ+kU2TkeoWAKvGq8MAgDq4D4Xqwekg7WKFeuyusi/NI5rm40XgjBMF
+DF72IUofoVt7wo0=
+-----END CERTIFICATE-----`
+
+func TestMultipleRDN(t *testing.T) {
+ block, _ := pem.Decode([]byte(certMultipleRDN))
+ cert, err := ParseCertificate(block.Bytes)
+ if err != nil {
+ t.Fatalf("certificate with two elements in an RDN failed to parse: %v", err)
+ }
+
+ if want := "eportal.mss.edus.si"; cert.Subject.CommonName != want {
+ t.Errorf("got common name of %q, but want %q", cert.Subject.CommonName, want)
+ }
+
+ if want := "1236484010010"; cert.Subject.SerialNumber != want {
+ t.Errorf("got serial number of %q, but want %q", cert.Subject.SerialNumber, want)
+ }
+}
+
+func TestSystemCertPool(t *testing.T) {
+ _, err := SystemCertPool()
+ if err != nil {
+ t.Fatal(err)
+ }
+}
diff --git a/src/database/sql/convert.go b/src/database/sql/convert.go
index 99aed23..4b4dfc4 100644
--- a/src/database/sql/convert.go
+++ b/src/database/sql/convert.go
@@ -17,12 +17,19 @@ import (
var errNilPtr = errors.New("destination pointer is nil") // embedded in descriptive error
+func describeNamedValue(nv *driver.NamedValue) string {
+ if len(nv.Name) == 0 {
+ return fmt.Sprintf("$%d", nv.Ordinal)
+ }
+ return fmt.Sprintf("with name %q", nv.Name)
+}
+
// 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.Value, error) {
- dargs := make([]driver.Value, len(args))
+func driverArgs(ds *driverStmt, args []interface{}) ([]driver.NamedValue, error) {
+ nvargs := make([]driver.NamedValue, len(args))
var si driver.Stmt
if ds != nil {
si = ds.si
@@ -33,26 +40,39 @@ func driverArgs(ds *driverStmt, args []interface{}) ([]driver.Value, error) {
if !ok {
for n, arg := range args {
var err error
- dargs[n], err = driver.DefaultParameterConverter.ConvertValue(arg)
+ nv := &nvargs[n]
+ nv.Ordinal = n + 1
+ if np, ok := arg.(NamedArg); ok {
+ 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 #%d's type: %v", n, err)
+ return nil, fmt.Errorf("sql: converting Exec argument %s type: %v", describeNamedValue(nv), err)
}
}
- return dargs, nil
+ return nvargs, nil
}
// Let the Stmt convert its own arguments.
for n, arg := range args {
+ nv := &nvargs[n]
+ nv.Ordinal = n + 1
+ if np, ok := arg.(NamedArg); ok {
+ 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 svi, ok := arg.(driver.Valuer); ok {
- sv, err := svi.Value()
+ if vr, ok := arg.(driver.Valuer); ok {
+ sv, err := callValuerValue(vr)
if err != nil {
- return nil, fmt.Errorf("sql: argument index %d from Value: %v", n, err)
+ return nil, fmt.Errorf("sql: argument %s from Value: %v", describeNamedValue(nv), err)
}
if !driver.IsValue(sv) {
- return nil, fmt.Errorf("sql: argument index %d: non-subset type %T returned from Value", n, sv)
+ return nil, fmt.Errorf("sql: argument %s: non-subset type %T returned from Value", describeNamedValue(nv), sv)
}
arg = sv
}
@@ -66,18 +86,18 @@ func driverArgs(ds *driverStmt, args []interface{}) ([]driver.Value, error) {
// same error.
var err error
ds.Lock()
- dargs[n], err = cc.ColumnConverter(n).ConvertValue(arg)
+ nv.Value, err = cc.ColumnConverter(n).ConvertValue(arg)
ds.Unlock()
if err != nil {
- return nil, fmt.Errorf("sql: converting argument #%d's type: %v", n, err)
+ return nil, fmt.Errorf("sql: converting argument %s type: %v", describeNamedValue(nv), err)
}
- if !driver.IsValue(dargs[n]) {
- return nil, fmt.Errorf("sql: driver ColumnConverter error converted %T to unsupported type %T",
- arg, dargs[n])
+ 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)
}
}
- return dargs, nil
+ return nvargs, nil
}
// convertAssign copies to dest the value in src, converting it if possible.
@@ -330,3 +350,25 @@ func asBytes(buf []byte, rv reflect.Value) (b []byte, ok bool) {
}
return
}
+
+var valuerReflectType = reflect.TypeOf((*driver.Valuer)(nil)).Elem()
+
+// callValuerValue returns vr.Value(), with one exception:
+// If vr.Value is an auto-generated method on a pointer type and the
+// pointer is nil, it would panic at runtime in the panicwrap
+// method. Treat it like nil instead.
+// Issue 8415.
+//
+// This is so people can implement driver.Value on value types and
+// still use nil pointers to those types to mean nil/NULL, just like
+// string/*string.
+//
+// This function is mirrored in the database/sql/driver package.
+func callValuerValue(vr driver.Valuer) (v driver.Value, err error) {
+ if rv := reflect.ValueOf(vr); rv.Kind() == reflect.Ptr &&
+ rv.IsNil() &&
+ rv.Type().Elem().Implements(valuerReflectType) {
+ return nil, nil
+ }
+ return vr.Value()
+}
diff --git a/src/database/sql/convert_test.go b/src/database/sql/convert_test.go
index ab81f2f..4dfab1f 100644
--- a/src/database/sql/convert_test.go
+++ b/src/database/sql/convert_test.go
@@ -9,6 +9,7 @@ import (
"fmt"
"reflect"
"runtime"
+ "strings"
"testing"
"time"
)
@@ -389,3 +390,85 @@ func TestUserDefinedBytes(t *testing.T) {
t.Fatal("userDefinedBytes got potentially dirty driver memory")
}
}
+
+type Valuer_V string
+
+func (v Valuer_V) Value() (driver.Value, error) {
+ return strings.ToUpper(string(v)), nil
+}
+
+type Valuer_P string
+
+func (p *Valuer_P) Value() (driver.Value, error) {
+ if p == nil {
+ return "nil-to-str", nil
+ }
+ return strings.ToUpper(string(*p)), nil
+}
+
+func TestDriverArgs(t *testing.T) {
+ var nilValuerVPtr *Valuer_V
+ var nilValuerPPtr *Valuer_P
+ var nilStrPtr *string
+ tests := []struct {
+ args []interface{}
+ want []driver.NamedValue
+ }{
+ 0: {
+ args: []interface{}{Valuer_V("foo")},
+ want: []driver.NamedValue{
+ driver.NamedValue{
+ Ordinal: 1,
+ Value: "FOO",
+ },
+ },
+ },
+ 1: {
+ args: []interface{}{nilValuerVPtr},
+ want: []driver.NamedValue{
+ driver.NamedValue{
+ Ordinal: 1,
+ Value: nil,
+ },
+ },
+ },
+ 2: {
+ args: []interface{}{nilValuerPPtr},
+ want: []driver.NamedValue{
+ driver.NamedValue{
+ Ordinal: 1,
+ Value: "nil-to-str",
+ },
+ },
+ },
+ 3: {
+ args: []interface{}{"plain-str"},
+ want: []driver.NamedValue{
+ driver.NamedValue{
+ Ordinal: 1,
+ Value: "plain-str",
+ },
+ },
+ },
+ 4: {
+ args: []interface{}{nilStrPtr},
+ want: []driver.NamedValue{
+ driver.NamedValue{
+ Ordinal: 1,
+ Value: nil,
+ },
+ },
+ },
+ }
+ for i, tt := range tests {
+ ds := new(driverStmt)
+ got, err := driverArgs(ds, tt.args)
+ if err != nil {
+ t.Errorf("test[%d]: %v", i, err)
+ continue
+ }
+ if !reflect.DeepEqual(got, tt.want) {
+ t.Errorf("test[%d]: got %v, want %v", i, got, tt.want)
+ }
+ }
+}
diff --git a/src/database/sql/ctxutil.go b/src/database/sql/ctxutil.go
new file mode 100644
index 0000000..7c05ce2
--- /dev/null
+++ b/src/database/sql/ctxutil.go
@@ -0,0 +1,156 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package sql
+
+import (
+ "context"
+ "database/sql/driver"
+ "errors"
+)
+
+func ctxDriverPrepare(ctx context.Context, ci driver.Conn, query string) (driver.Stmt, error) {
+ if ciCtx, is := ci.(driver.ConnPrepareContext); is {
+ return ciCtx.PrepareContext(ctx, query)
+ }
+ si, err := ci.Prepare(query)
+ if err == nil {
+ select {
+ default:
+ case <-ctx.Done():
+ si.Close()
+ return nil, ctx.Err()
+ }
+ }
+ return si, err
+}
+
+func ctxDriverExec(ctx context.Context, execer driver.Execer, query string, nvdargs []driver.NamedValue) (driver.Result, error) {
+ if execerCtx, is := execer.(driver.ExecerContext); is {
+ return execerCtx.ExecContext(ctx, query, nvdargs)
+ }
+ dargs, err := namedValueToValue(nvdargs)
+ if err != nil {
+ return nil, err
+ }
+
+ resi, err := execer.Exec(query, dargs)
+ if err == nil {
+ select {
+ default:
+ case <-ctx.Done():
+ return resi, ctx.Err()
+ }
+ }
+ return resi, err
+}
+
+func ctxDriverQuery(ctx context.Context, queryer driver.Queryer, query string, nvdargs []driver.NamedValue) (driver.Rows, error) {
+ if queryerCtx, is := queryer.(driver.QueryerContext); is {
+ ret, err := queryerCtx.QueryContext(ctx, query, nvdargs)
+ return ret, err
+ }
+ dargs, err := namedValueToValue(nvdargs)
+ if err != nil {
+ return nil, err
+ }
+
+ rowsi, err := queryer.Query(query, dargs)
+ if err == nil {
+ select {
+ default:
+ case <-ctx.Done():
+ rowsi.Close()
+ return nil, ctx.Err()
+ }
+ }
+ return rowsi, err
+}
+
+func ctxDriverStmtExec(ctx context.Context, si driver.Stmt, nvdargs []driver.NamedValue) (driver.Result, error) {
+ if siCtx, is := si.(driver.StmtExecContext); is {
+ return siCtx.ExecContext(ctx, nvdargs)
+ }
+ dargs, err := namedValueToValue(nvdargs)
+ if err != nil {
+ return nil, err
+ }
+
+ resi, err := si.Exec(dargs)
+ if err == nil {
+ select {
+ default:
+ case <-ctx.Done():
+ return resi, ctx.Err()
+ }
+ }
+ return resi, err
+}
+
+func ctxDriverStmtQuery(ctx context.Context, si driver.Stmt, nvdargs []driver.NamedValue) (driver.Rows, error) {
+ if siCtx, is := si.(driver.StmtQueryContext); is {
+ return siCtx.QueryContext(ctx, nvdargs)
+ }
+ dargs, err := namedValueToValue(nvdargs)
+ if err != nil {
+ return nil, err
+ }
+
+ rowsi, err := si.Query(dargs)
+ if err == nil {
+ select {
+ default:
+ case <-ctx.Done():
+ rowsi.Close()
+ return nil, ctx.Err()
+ }
+ }
+ return rowsi, err
+}
+
+var errLevelNotSupported = errors.New("sql: selected isolation level is not supported")
+
+func ctxDriverBegin(ctx context.Context, ci driver.Conn) (driver.Tx, error) {
+ if ciCtx, is := ci.(driver.ConnBeginContext); is {
+ return ciCtx.BeginContext(ctx)
+ }
+
+ if ctx.Done() == context.Background().Done() {
+ return ci.Begin()
+ }
+
+ // Check the transaction level in ctx. If set and non-default
+ // then return an error here as the BeginContext driver value is not supported.
+ if level, ok := driver.IsolationFromContext(ctx); ok && level != driver.IsolationLevel(LevelDefault) {
+ return nil, errors.New("sql: driver does not support non-default isolation level")
+ }
+
+ // Check for a read-only parameter in ctx. If a read-only transaction is
+ // requested return an error as the BeginContext driver value is not supported.
+ if ro := driver.ReadOnlyFromContext(ctx); ro {
+ return nil, errors.New("sql: driver does not support read-only transactions")
+ }
+
+ txi, err := ci.Begin()
+ if err == nil {
+ select {
+ default:
+ case <-ctx.Done():
+ txi.Rollback()
+ return nil, ctx.Err()
+ }
+ }
+ return txi, err
+}
+
+func namedValueToValue(named []driver.NamedValue) ([]driver.Value, error) {
+ dargs := make([]driver.Value, len(named))
+ for n, param := range named {
+ if len(param.Name) > 0 {
+ return nil, errors.New("sql: driver does not support the use of Named Parameters")
+ }
+ dargs[n] = param.Value
+ }
+ return dargs, nil
+}
diff --git a/src/database/sql/driver/driver.go b/src/database/sql/driver/driver.go
index 4dba85a..c8cbbf0 100644
--- a/src/database/sql/driver/driver.go
+++ b/src/database/sql/driver/driver.go
@@ -8,7 +8,12 @@
// Most code should use package sql.
package driver
-import "errors"
+import (
+ "context"
+ "database/sql/internal"
+ "errors"
+ "reflect"
+)
// Value is a value that drivers must be able to handle.
// It is either nil or an instance of one of these types:
@@ -21,6 +26,16 @@ import "errors"
// time.Time
type Value interface{}
+// NamedValue holds both the value name and value.
+// The Ordinal is the position of the parameter starting from one and is always set.
+// If the Name is not empty it should be used for the parameter identifier and
+// not the ordinal position.
+type NamedValue struct {
+ Name string
+ Ordinal int
+ Value Value
+}
+
// Driver is the interface that must be implemented by a database
// driver.
type Driver interface {
@@ -54,6 +69,17 @@ var ErrSkip = errors.New("driver: skip fast-path; continue as if unimplemented")
// you shouldn't return ErrBadConn.
var ErrBadConn = errors.New("driver: bad connection")
+// Pinger is an optional interface that may be implemented by a Conn.
+//
+// If a Conn does not implement Pinger, the sql package's DB.Ping and
+// DB.PingContext will check if there is at least one Conn available.
+//
+// If Conn.Ping returns ErrBadConn, DB.Ping and DB.PingContext will remove
+// the Conn from pool.
+type Pinger interface {
+ Ping(ctx context.Context) error
+}
+
// Execer is an optional interface that may be implemented by a Conn.
//
// If a Conn does not implement Execer, the sql package's DB.Exec will
@@ -61,10 +87,25 @@ var ErrBadConn = errors.New("driver: bad connection")
// statement.
//
// Exec may return ErrSkip.
+//
+// Deprecated: Drivers should implement ExecerContext instead (or additionally).
type Execer interface {
Exec(query string, args []Value) (Result, error)
}
+// ExecerContext is an optional interface that may be implemented by a Conn.
+//
+// If a Conn does not implement ExecerContext, the sql package's DB.Exec will
+// first prepare a query, execute the statement, and then close the
+// statement.
+//
+// ExecerContext may return ErrSkip.
+//
+// ExecerContext must honor the context timeout and return when the context is canceled.
+type ExecerContext interface {
+ ExecContext(ctx context.Context, query string, args []NamedValue) (Result, error)
+}
+
// Queryer is an optional interface that may be implemented by a Conn.
//
// If a Conn does not implement Queryer, the sql package's DB.Query will
@@ -72,10 +113,25 @@ type Execer interface {
// statement.
//
// Query may return ErrSkip.
+//
+// Deprecated: Drivers should implement QueryerContext instead (or additionally).
type Queryer interface {
Query(query string, args []Value) (Rows, error)
}
+// QueryerContext is an optional interface that may be implemented by a Conn.
+//
+// If a Conn does not implement QueryerContext, the sql package's DB.Query will
+// first prepare a query, execute the statement, and then close the
+// statement.
+//
+// QueryerContext may return ErrSkip.
+//
+// QueryerContext must honor the context timeout and return when the context is canceled.
+type QueryerContext interface {
+ QueryContext(ctx context.Context, query string, args []NamedValue) (Rows, error)
+}
+
// Conn is a connection to a database. It is not used concurrently
// by multiple goroutines.
//
@@ -95,9 +151,56 @@ type Conn interface {
Close() error
// Begin starts and returns a new transaction.
+ //
+ // Deprecated: Drivers should implement ConnBeginContext instead (or additionally).
Begin() (Tx, error)
}
+// ConnPrepareContext enhances the Conn interface with context.
+type ConnPrepareContext interface {
+ // PrepareContext returns a prepared statement, bound to this connection.
+ // context is for the preparation of the statement,
+ // it must not store the context within the statement itself.
+ PrepareContext(ctx context.Context, query string) (Stmt, error)
+}
+
+// IsolationLevel is the transaction isolation level stored in Context.
+//
+// This type should be considered identical to sql.IsolationLevel along
+// with any values defined on it.
+type IsolationLevel int
+
+// IsolationFromContext extracts the isolation level from a Context.
+func IsolationFromContext(ctx context.Context) (level IsolationLevel, ok bool) {
+ level, ok = ctx.Value(internal.IsolationLevelKey{}).(IsolationLevel)
+ return level, ok
+}
+
+// ReadOnlyFromContext extracts the read-only property from a Context.
+// When readonly is true the transaction must be set to read-only
+// or return an error.
+func ReadOnlyFromContext(ctx context.Context) (readonly bool) {
+ readonly, _ = ctx.Value(internal.ReadOnlyKey{}).(bool)
+ return readonly
+}
+
+// ConnBeginContext enhances the Conn interface with context.
+type ConnBeginContext interface {
+ // BeginContext starts and returns a new transaction.
+ // If the context is canceled by the user the sql package will
+ // call Tx.Rollback before discarding and closing the connection.
+ //
+ // This must call IsolationFromContext to determine if there is a set
+ // isolation level. If the driver does not support setting the isolation
+ // level and one is set or if there is a set isolation level
+ // but the set level is not supported, an error must be returned.
+ //
+ // This must also call ReadOnlyFromContext to determine if the read-only
+ // value is true to either set the read-only transaction property if supported
+ // or return an error if it is not supported.
+ BeginContext(ctx context.Context) (Tx, error)
+}
+
// Result is the result of a query execution.
type Result interface {
// LastInsertId returns the database's auto-generated ID
@@ -132,13 +235,35 @@ type Stmt interface {
// Exec executes a query that doesn't return rows, such
// as an INSERT or UPDATE.
+ //
+ // Deprecated: Drivers should implement StmtExecContext instead (or additionally).
Exec(args []Value) (Result, error)
// Query executes a query that may return rows, such as a
// SELECT.
+ //
+ // Deprecated: Drivers should implement StmtQueryContext instead (or additionally).
Query(args []Value) (Rows, error)
}
+// StmtExecContext enhances the Stmt interface by providing Exec with context.
+type StmtExecContext interface {
+ // ExecContext executes a query that doesn't return rows, such
+ // as an INSERT or UPDATE.
+ //
+ // ExecContext must honor the context timeout and return when it is canceled.
+ ExecContext(ctx context.Context, args []NamedValue) (Result, error)
+}
+
+// StmtQueryContext enhances the Stmt interface by providing Query with context.
+type StmtQueryContext interface {
+ // QueryContext executes a query that may return rows, such as a
+ // SELECT.
+ //
+ // QueryContext must honor the context timeout and return when it is canceled.
+ QueryContext(ctx context.Context, args []NamedValue) (Rows, 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.
@@ -169,6 +294,76 @@ type Rows interface {
Next(dest []Value) error
}
+// RowsNextResultSet extends the Rows interface by providing a way to signal
+// the driver to advance to the next result set.
+type RowsNextResultSet interface {
+ Rows
+
+ // HasNextResultSet is called at the end of the current result set and
+ // reports whether there is another result set after the current one.
+ HasNextResultSet() bool
+
+ // NextResultSet advances the driver to the next result set even
+ // if there are remaining rows in the current result set.
+ //
+ // NextResultSet should return io.EOF when there are no more result sets.
+ NextResultSet() error
+}
+
+// RowsColumnTypeScanType may be implemented by Rows. It should return
+// the value type that can be used to scan types into. For example, the database
+// column type "bigint" this should return "reflect.TypeOf(int64(0))".
+type RowsColumnTypeScanType interface {
+ Rows
+ ColumnTypeScanType(index int) reflect.Type
+}
+
+// RowsColumnTypeDatabaseTypeName may be implemented by Rows. It should return the
+// database system type name without the length. Type names should be uppercase.
+// Examples of returned types: "VARCHAR", "NVARCHAR", "VARCHAR2", "CHAR", "TEXT",
+// "DECIMAL", "SMALLINT", "INT", "BIGINT", "BOOL", "[]BIGINT", "JSONB", "XML",
+// "TIMESTAMP".
+type RowsColumnTypeDatabaseTypeName interface {
+ Rows
+ ColumnTypeDatabaseTypeName(index int) string
+}
+
+// RowsColumnTypeLength may be implemented by Rows. It should return the length
+// of the column type if the column is a variable length type. If the column is
+// not a variable length type ok should return false.
+// If length is not limited other than system limits, it should return math.MaxInt64.
+// The following are examples of returned values for various types:
+// TEXT (math.MaxInt64, true)
+// varchar(10) (10, true)
+// nvarchar(10) (10, true)
+// decimal (0, false)
+// int (0, false)
+// bytea(30) (30, true)
+type RowsColumnTypeLength interface {
+ Rows
+ ColumnTypeLength(index int) (length int64, ok bool)
+}
+
+// RowsColumnTypeNullable may be implemented by Rows. The nullable value should
+// be true if it is known the column may be null, or false if the column is known
+// to be not nullable.
+// If the column nullability is unknown, ok should be false.
+type RowsColumnTypeNullable interface {
+ Rows
+ ColumnTypeNullable(index int) (nullable, ok bool)
+}
+
+// RowsColumnTypePrecisionScale may be implemented by Rows. It should return
+// the precision and scale for decimal types. If not applicable, ok should be false.
+// The following are examples of returned values for various types:
+// decimal(38, 4) (38, 4, true)
+// int (0, 0, false)
+// decimal (math.MaxInt64, math.MaxInt64, true)
+type RowsColumnTypePrecisionScale interface {
+ Rows
+ ColumnTypePrecisionScale(index int) (precision, scale int64, ok bool)
+}
+
// Tx is a transaction.
type Tx interface {
Commit() error
diff --git a/src/database/sql/driver/types.go b/src/database/sql/driver/types.go
index e480e70..8b3cb6c 100644
--- a/src/database/sql/driver/types.go
+++ b/src/database/sql/driver/types.go
@@ -198,9 +198,9 @@ func IsScanValue(v interface{}) bool {
// Value method is used to return a Value. As a fallback, the provided
// argument's underlying type is used to convert it to a Value:
// underlying integer types are converted to int64, floats to float64,
-// and strings to []byte. If the argument is a nil pointer,
-// ConvertValue returns a nil Value. If the argument is a non-nil
-// pointer, it is dereferenced and ConvertValue is called
+// bool, string, and []byte to themselves. If the argument is a nil
+// pointer, ConvertValue returns a nil Value. If the argument is a
+// non-nil pointer, it is dereferenced and ConvertValue is called
// recursively. Other types are an error.
var DefaultParameterConverter defaultConverter
@@ -208,13 +208,35 @@ type defaultConverter struct{}
var _ ValueConverter = defaultConverter{}
+var valuerReflectType = reflect.TypeOf((*Valuer)(nil)).Elem()
+
+// callValuerValue returns vr.Value(), with one exception:
+// If vr.Value is an auto-generated method on a pointer type and the
+// pointer is nil, it would panic at runtime in the panicwrap
+// method. Treat it like nil instead.
+// Issue 8415.
+//
+// This is so people can implement driver.Value on value types and
+// still use nil pointers to those types to mean nil/NULL, just like
+// string/*string.
+//
+// This function is mirrored in the database/sql package.
+func callValuerValue(vr Valuer) (v Value, err error) {
+ if rv := reflect.ValueOf(vr); rv.Kind() == reflect.Ptr &&
+ rv.IsNil() &&
+ rv.Type().Elem().Implements(valuerReflectType) {
+ return nil, nil
+ }
+ return vr.Value()
+}
+
func (defaultConverter) ConvertValue(v interface{}) (Value, error) {
if IsValue(v) {
return v, nil
}
- if svi, ok := v.(Valuer); ok {
- sv, err := svi.Value()
+ if vr, ok := v.(Valuer); ok {
+ sv, err := callValuerValue(vr)
if err != nil {
return nil, err
}
@@ -245,6 +267,16 @@ func (defaultConverter) ConvertValue(v interface{}) (Value, error) {
return int64(u64), nil
case reflect.Float32, reflect.Float64:
return rv.Float(), nil
+ case reflect.Bool:
+ return rv.Bool(), nil
+ case reflect.Slice:
+ ek := rv.Type().Elem().Kind()
+ if ek == reflect.Uint8 {
+ return rv.Bytes(), nil
+ }
+ return nil, fmt.Errorf("unsupported type %T, a slice of %s", v, ek)
+ case reflect.String:
+ return rv.String(), nil
}
return nil, fmt.Errorf("unsupported type %T, a %s", v, rv.Kind())
}
diff --git a/src/database/sql/driver/types_test.go b/src/database/sql/driver/types_test.go
index 1ce0ff0..0379bf8 100644
--- a/src/database/sql/driver/types_test.go
+++ b/src/database/sql/driver/types_test.go
@@ -20,6 +20,16 @@ type valueConverterTest struct {
var now = time.Now()
var answer int64 = 42
+type (
+ i int64
+ f float64
+ b bool
+ bs []byte
+ s string
+ t time.Time
+ is []int
+)
+
var valueConverterTests = []valueConverterTest{
{Bool, "true", true, ""},
{Bool, "True", true, ""},
@@ -41,6 +51,12 @@ var valueConverterTests = []valueConverterTest{
{DefaultParameterConverter, (*int64)(nil), nil, ""},
{DefaultParameterConverter, &answer, answer, ""},
{DefaultParameterConverter, &now, now, ""},
+ {DefaultParameterConverter, i(9), int64(9), ""},
+ {DefaultParameterConverter, f(0.1), float64(0.1), ""},
+ {DefaultParameterConverter, b(true), true, ""},
+ {DefaultParameterConverter, bs{1}, []byte{1}, ""},
+ {DefaultParameterConverter, s("a"), "a", ""},
+ {DefaultParameterConverter, is{1}, nil, "unsupported type driver.is, a slice of int"},
}
func TestValueConverters(t *testing.T) {
diff --git a/src/database/sql/example_test.go b/src/database/sql/example_test.go
index dcb74e0..ce56ca4 100644
--- a/src/database/sql/example_test.go
+++ b/src/database/sql/example_test.go
@@ -44,3 +44,65 @@ func ExampleDB_QueryRow() {
fmt.Printf("Username is %s\n", username)
}
}
+
+func ExampleDB_Query_multipleResultSets() {
+ age := 27
+ q := `
+create temp table uid (id bigint); -- Create temp table for queries.
+insert into uid
+select id from users where age < ?; -- Populate temp table.
+
+-- First result set.
+select
+ users.id, name
+from
+ users
+ join uid on users.id = uid.id
+;
+
+-- Second result set.
+select
+ ur.user, ur.role
+from
+ user_roles as ur
+ join uid on uid.id = ur.user
+;
+ `
+ rows, err := db.Query(q, age)
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer rows.Close()
+
+ for rows.Next() {
+ var (
+ id int64
+ name string
+ )
+ if err := rows.Scan(&id, &name); err != nil {
+ log.Fatal(err)
+ }
+ fmt.Printf("id %d name is %s\n", id, name)
+ }
+ if !rows.NextResultSet() {
+ log.Fatal("expected more result sets", rows.Err())
+ }
+ var roleMap = map[int64]string{
+ 1: "user",
+ 2: "admin",
+ 3: "gopher",
+ }
+ for rows.Next() {
+ var (
+ id int64
+ role int64
+ )
+ if err := rows.Scan(&id, &role); err != nil {
+ log.Fatal(err)
+ }
+ fmt.Printf("id %d has role %s\n", id, roleMap[role])
+ }
+ if err := rows.Err(); err != nil {
+ log.Fatal(err)
+ }
+}
diff --git a/src/database/sql/fakedb_test.go b/src/database/sql/fakedb_test.go
index 5b238bf..416b97d 100644
--- a/src/database/sql/fakedb_test.go
+++ b/src/database/sql/fakedb_test.go
@@ -5,11 +5,13 @@
package sql
import (
+ "context"
"database/sql/driver"
"errors"
"fmt"
"io"
"log"
+ "reflect"
"sort"
"strconv"
"strings"
@@ -32,10 +34,16 @@ var _ = log.Printf
// where types are: "string", [u]int{8,16,32,64}, "bool"
// INSERT|<tablename>|col=val,col2=val2,col3=?
// SELECT|<tablename>|projectcol1,projectcol2|filtercol=?,filtercol2=?
+// SELECT|<tablename>|projectcol1,projectcol2|filtercol=?param1,filtercol2=?param2
//
// Any of these can be preceded by PANIC|<method>|, to cause the
// named method on fakeStmt to panic.
//
+// Any of these can be proceeded by WAIT|<duration>|, to cause the
+// named method on fakeStmt to sleep for the specified duration.
+//
+// Multiple of these can be combined when separated with a semicolon.
+//
// When opening a fakeDriver's database, it starts empty with no
// tables. All tables and data are stored in memory only.
type fakeDriver struct {
@@ -101,6 +109,12 @@ type fakeTx struct {
c *fakeConn
}
+type boundCol struct {
+ Column string
+ Placeholder string
+ Ordinal int
+}
+
type fakeStmt struct {
c *fakeConn
q string // just for debugging
@@ -108,6 +122,9 @@ type fakeStmt struct {
cmd string
table string
panic string
+ wait time.Duration
+
+ next *fakeStmt // used for returning multiple results.
closed bool
@@ -116,7 +133,7 @@ type fakeStmt struct {
colValue []interface{} // used by INSERT (mix of strings and "?" for bound params)
placeholders int // used by INSERT/SELECT: number of ? params
- whereCol []string // used by SELECT (all placeholders)
+ whereCol []boundCol // used by SELECT (all placeholders)
placeholderConverter []driver.ValueConverter // used by INSERT
}
@@ -335,18 +352,23 @@ func (c *fakeConn) Close() (err error) {
return nil
}
-func checkSubsetTypes(args []driver.Value) error {
- for n, arg := range args {
- switch arg.(type) {
+func checkSubsetTypes(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 #%d: %v, type %T", n+1, arg, arg)
+ return fmt.Errorf("fakedb_test: invalid argument ordinal %[1]d: %[2]v, type %[2]T", arg.Ordinal, arg.Value)
}
}
return nil
}
func (c *fakeConn) Exec(query string, args []driver.Value) (driver.Result, error) {
+ // Ensure that ExecContext is called if available.
+ panic("ExecContext was not called.")
+}
+
+func (c *fakeConn) ExecContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Result, error) {
// This is an optional interface, but it's implemented here
// just to check that all the args are of the proper types.
// ErrSkip is returned so the caller acts as if we didn't
@@ -359,6 +381,11 @@ func (c *fakeConn) Exec(query string, args []driver.Value) (driver.Result, error
}
func (c *fakeConn) Query(query string, args []driver.Value) (driver.Rows, error) {
+ // Ensure that ExecContext is called if available.
+ panic("QueryContext was not called.")
+}
+
+func (c *fakeConn) QueryContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Rows, error) {
// This is an optional interface, but it's implemented here
// just to check that all the args are of the proper types.
// ErrSkip is returned so the caller acts as if we didn't
@@ -377,12 +404,13 @@ func errf(msg string, args ...interface{}) error {
// parts are table|selectCol1,selectCol2|whereCol=?,whereCol2=?
// (note that where columns must always contain ? marks,
// just a limitation for fakedb)
-func (c *fakeConn) prepareSelect(stmt *fakeStmt, parts []string) (driver.Stmt, error) {
+func (c *fakeConn) prepareSelect(stmt *fakeStmt, parts []string) (*fakeStmt, error) {
if len(parts) != 3 {
stmt.Close()
return nil, errf("invalid SELECT syntax with %d parts; want 3", len(parts))
}
stmt.table = parts[0]
+
stmt.colName = strings.Split(parts[1], ",")
for n, colspec := range strings.Split(parts[2], ",") {
if colspec == "" {
@@ -399,19 +427,19 @@ func (c *fakeConn) prepareSelect(stmt *fakeStmt, parts []string) (driver.Stmt, e
stmt.Close()
return nil, errf("SELECT on table %q references non-existent column %q", stmt.table, column)
}
- if value != "?" {
+ if !strings.HasPrefix(value, "?") {
stmt.Close()
return nil, errf("SELECT on table %q has pre-bound value for where column %q; need a question mark",
stmt.table, column)
}
- stmt.whereCol = append(stmt.whereCol, column)
stmt.placeholders++
+ stmt.whereCol = append(stmt.whereCol, boundCol{Column: column, Placeholder: value, Ordinal: stmt.placeholders})
}
return stmt, nil
}
// parts are table|col=type,col2=type2
-func (c *fakeConn) prepareCreate(stmt *fakeStmt, parts []string) (driver.Stmt, error) {
+func (c *fakeConn) prepareCreate(stmt *fakeStmt, parts []string) (*fakeStmt, error) {
if len(parts) != 2 {
stmt.Close()
return nil, errf("invalid CREATE syntax with %d parts; want 2", len(parts))
@@ -430,7 +458,7 @@ func (c *fakeConn) prepareCreate(stmt *fakeStmt, parts []string) (driver.Stmt, e
}
// parts are table|col=?,col2=val
-func (c *fakeConn) prepareInsert(stmt *fakeStmt, parts []string) (driver.Stmt, error) {
+func (c *fakeConn) prepareInsert(stmt *fakeStmt, parts []string) (*fakeStmt, error) {
if len(parts) != 2 {
stmt.Close()
return nil, errf("invalid INSERT syntax with %d parts; want 2", len(parts))
@@ -450,7 +478,7 @@ func (c *fakeConn) prepareInsert(stmt *fakeStmt, parts []string) (driver.Stmt, e
}
stmt.colName = append(stmt.colName, column)
- if value != "?" {
+ if !strings.HasPrefix(value, "?") {
var subsetVal interface{}
// Convert to driver subset type
switch ctype {
@@ -473,7 +501,7 @@ func (c *fakeConn) prepareInsert(stmt *fakeStmt, parts []string) (driver.Stmt, e
} else {
stmt.placeholders++
stmt.placeholderConverter = append(stmt.placeholderConverter, converterForType(ctype))
- stmt.colValue = append(stmt.colValue, "?")
+ stmt.colValue = append(stmt.colValue, value)
}
}
return stmt, nil
@@ -483,6 +511,10 @@ func (c *fakeConn) prepareInsert(stmt *fakeStmt, parts []string) (driver.Stmt, e
var hookPrepareBadConn func() bool
func (c *fakeConn) Prepare(query string) (driver.Stmt, error) {
+ panic("use PrepareContext")
+}
+
+func (c *fakeConn) PrepareContext(ctx context.Context, query string) (driver.Stmt, error) {
c.numPrepare++
if c.db == nil {
panic("nil c.db; conn = " + fmt.Sprintf("%#v", c))
@@ -492,38 +524,72 @@ func (c *fakeConn) Prepare(query string) (driver.Stmt, error) {
return nil, driver.ErrBadConn
}
- parts := strings.Split(query, "|")
- if len(parts) < 1 {
- return nil, errf("empty query")
- }
- stmt := &fakeStmt{q: query, c: c}
- if len(parts) >= 3 && parts[0] == "PANIC" {
- stmt.panic = parts[1]
- parts = parts[2:]
- }
- cmd := parts[0]
- stmt.cmd = cmd
- parts = parts[1:]
+ 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}
+ if firstStmt == nil {
+ firstStmt = stmt
+ }
+ if len(parts) >= 3 {
+ switch parts[0] {
+ case "PANIC":
+ stmt.panic = parts[1]
+ parts = parts[2:]
+ case "WAIT":
+ wait, err := time.ParseDuration(parts[1])
+ if err != nil {
+ return nil, errf("expected section after WAIT to be a duration, got %q %v", parts[1], err)
+ }
+ parts = parts[2:]
+ stmt.wait = wait
+ }
+ }
+ cmd := parts[0]
+ stmt.cmd = cmd
+ parts = parts[1:]
+
+ if stmt.wait > 0 {
+ wait := time.NewTimer(stmt.wait)
+ select {
+ case <-wait.C:
+ case <-ctx.Done():
+ wait.Stop()
+ return nil, ctx.Err()
+ }
+ }
- c.incrStat(&c.stmtsMade)
- switch cmd {
- case "WIPE":
- // Nothing
- case "SELECT":
- return c.prepareSelect(stmt, parts)
- case "CREATE":
- return c.prepareCreate(stmt, parts)
- case "INSERT":
- return c.prepareInsert(stmt, parts)
- case "NOSERT":
- // Do all the prep-work like for an INSERT but don't actually insert the row.
- // Used for some of the concurrent tests.
- return c.prepareInsert(stmt, parts)
- default:
- stmt.Close()
- return nil, errf("unsupported command type %q", cmd)
+ c.incrStat(&c.stmtsMade)
+ var err error
+ switch cmd {
+ case "WIPE":
+ // Nothing
+ case "SELECT":
+ stmt, err = c.prepareSelect(stmt, parts)
+ case "CREATE":
+ stmt, err = c.prepareCreate(stmt, parts)
+ case "INSERT":
+ stmt, err = c.prepareInsert(stmt, parts)
+ case "NOSERT":
+ // Do all the prep-work like for an INSERT but don't actually insert the row.
+ // Used for some of the concurrent tests.
+ stmt, err = c.prepareInsert(stmt, parts)
+ default:
+ stmt.Close()
+ return nil, errf("unsupported command type %q", cmd)
+ }
+ if err != nil {
+ return nil, err
+ }
+ if prev != nil {
+ prev.next = stmt
+ }
+ prev = stmt
}
- return stmt, nil
+ return firstStmt, nil
}
func (s *fakeStmt) ColumnConverter(idx int) driver.ValueConverter {
@@ -550,6 +616,9 @@ func (s *fakeStmt) Close() error {
s.c.incrStat(&s.c.stmtsClosed)
s.closed = true
}
+ if s.next != nil {
+ s.next.Close()
+ }
return nil
}
@@ -559,6 +628,9 @@ var errClosed = errors.New("fakedb: statement has been closed")
var hookExecBadConn func() bool
func (s *fakeStmt) Exec(args []driver.Value) (driver.Result, error) {
+ panic("Using ExecContext")
+}
+func (s *fakeStmt) ExecContext(ctx context.Context, args []driver.NamedValue) (driver.Result, error) {
if s.panic == "Exec" {
panic(s.panic)
}
@@ -575,6 +647,16 @@ func (s *fakeStmt) Exec(args []driver.Value) (driver.Result, error) {
return nil, err
}
+ if s.wait > 0 {
+ time.Sleep(s.wait)
+ }
+
+ select {
+ default:
+ case <-ctx.Done():
+ return nil, ctx.Err()
+ }
+
db := s.c.db
switch s.cmd {
case "WIPE":
@@ -599,7 +681,7 @@ func (s *fakeStmt) Exec(args []driver.Value) (driver.Result, error) {
// When doInsert is true, add the row to the table.
// When doInsert is false do prep-work and error checking, but don't
// actually add the row to the table.
-func (s *fakeStmt) execInsert(args []driver.Value, doInsert bool) (driver.Result, error) {
+func (s *fakeStmt) execInsert(args []driver.NamedValue, doInsert bool) (driver.Result, error) {
db := s.c.db
if len(args) != s.placeholders {
panic("error in pkg db; should only get here if size is correct")
@@ -625,8 +707,18 @@ func (s *fakeStmt) execInsert(args []driver.Value, doInsert bool) (driver.Result
return nil, fmt.Errorf("fakedb: column %q doesn't exist or dropped since prepared statement was created", colname)
}
var val interface{}
- if strvalue, ok := s.colValue[n].(string); ok && strvalue == "?" {
- val = args[argPos]
+ if strvalue, ok := s.colValue[n].(string); ok && strings.HasPrefix(strvalue, "?") {
+ if strvalue == "?" {
+ val = args[argPos].Value
+ } else {
+ // Assign value from argument placeholder name.
+ for _, a := range args {
+ if a.Name == strvalue {
+ val = a.Value
+ break
+ }
+ }
+ }
argPos++
} else {
val = s.colValue[n]
@@ -646,6 +738,10 @@ func (s *fakeStmt) execInsert(args []driver.Value, doInsert bool) (driver.Result
var hookQueryBadConn func() bool
func (s *fakeStmt) Query(args []driver.Value) (driver.Rows, error) {
+ panic("Use QueryContext")
+}
+
+func (s *fakeStmt) QueryContext(ctx context.Context, args []driver.NamedValue) (driver.Rows, error) {
if s.panic == "Query" {
panic(s.panic)
}
@@ -667,65 +763,101 @@ func (s *fakeStmt) Query(args []driver.Value) (driver.Rows, error) {
panic("error in pkg db; should only get here if size is correct")
}
- db.mu.Lock()
- t, ok := db.table(s.table)
- db.mu.Unlock()
- if !ok {
- return nil, fmt.Errorf("fakedb: table %q doesn't exist", s.table)
- }
+ setMRows := make([][]*row, 0, 1)
+ setColumns := make([][]string, 0, 1)
+ setColType := make([][]string, 0, 1)
- if s.table == "magicquery" {
- if len(s.whereCol) == 2 && s.whereCol[0] == "op" && s.whereCol[1] == "millis" {
- if args[0] == "sleep" {
- time.Sleep(time.Duration(args[1].(int64)) * time.Millisecond)
- }
+ for {
+ db.mu.Lock()
+ t, ok := db.table(s.table)
+ db.mu.Unlock()
+ if !ok {
+ return nil, fmt.Errorf("fakedb: table %q doesn't exist", s.table)
}
- }
-
- t.mu.Lock()
- defer t.mu.Unlock()
- colIdx := make(map[string]int) // select column name -> column index in table
- for _, name := range s.colName {
- idx := t.columnIndex(name)
- if idx == -1 {
- return nil, fmt.Errorf("fakedb: unknown column name %q", name)
+ if s.table == "magicquery" {
+ if len(s.whereCol) == 2 && s.whereCol[0].Column == "op" && s.whereCol[1].Column == "millis" {
+ if args[0].Value == "sleep" {
+ time.Sleep(time.Duration(args[1].Value.(int64)) * time.Millisecond)
+ }
+ }
}
- colIdx[name] = idx
- }
- mrows := []*row{}
-rows:
- for _, trow := range t.rows {
- // Process the where clause, skipping non-match rows. This is lazy
- // and just uses fmt.Sprintf("%v") to test equality. Good enough
- // for test code.
- for widx, wcol := range s.whereCol {
- idx := t.columnIndex(wcol)
+ t.mu.Lock()
+
+ colIdx := make(map[string]int) // select column name -> column index in table
+ for _, name := range s.colName {
+ idx := t.columnIndex(name)
if idx == -1 {
- return nil, fmt.Errorf("db: invalid where clause column %q", wcol)
+ t.mu.Unlock()
+ return nil, fmt.Errorf("fakedb: unknown column name %q", name)
}
- tcol := trow.cols[idx]
- if bs, ok := tcol.([]byte); ok {
- // lazy hack to avoid sprintf %v on a []byte
- tcol = string(bs)
+ colIdx[name] = idx
+ }
+
+ mrows := []*row{}
+ rows:
+ for _, trow := range t.rows {
+ // Process the where clause, skipping non-match rows. This is lazy
+ // and just uses fmt.Sprintf("%v") to test equality. Good enough
+ // for test code.
+ for _, wcol := range s.whereCol {
+ idx := t.columnIndex(wcol.Column)
+ if idx == -1 {
+ t.mu.Unlock()
+ return nil, fmt.Errorf("db: invalid where clause column %q", wcol)
+ }
+ tcol := trow.cols[idx]
+ if bs, ok := tcol.([]byte); ok {
+ // lazy hack to avoid sprintf %v on a []byte
+ tcol = string(bs)
+ }
+ var argValue interface{}
+ if wcol.Placeholder == "?" {
+ argValue = args[wcol.Ordinal-1].Value
+ } else {
+ // Assign arg value from placeholder name.
+ for _, a := range args {
+ if a.Name == wcol.Placeholder {
+ argValue = a.Value
+ break
+ }
+ }
+ }
+ if fmt.Sprintf("%v", tcol) != fmt.Sprintf("%v", argValue) {
+ continue rows
+ }
}
- if fmt.Sprintf("%v", tcol) != fmt.Sprintf("%v", args[widx]) {
- continue rows
+ mrow := &row{cols: make([]interface{}, len(s.colName))}
+ for seli, name := range s.colName {
+ mrow.cols[seli] = trow.cols[colIdx[name]]
}
+ mrows = append(mrows, mrow)
}
- mrow := &row{cols: make([]interface{}, len(s.colName))}
- for seli, name := range s.colName {
- mrow.cols[seli] = trow.cols[colIdx[name]]
+
+ var colType []string
+ for _, column := range s.colName {
+ colType = append(colType, t.coltype[t.columnIndex(column)])
}
- mrows = append(mrows, mrow)
+
+ t.mu.Unlock()
+
+ setMRows = append(setMRows, mrows)
+ setColumns = append(setColumns, s.colName)
+ setColType = append(setColType, colType)
+
+ if s.next == nil {
+ break
+ }
+ s = s.next
}
cursor := &rowsCursor{
- pos: -1,
- rows: mrows,
- cols: s.colName,
- errPos: -1,
+ posRow: -1,
+ rows: setMRows,
+ cols: setColumns,
+ colType: setColType,
+ errPos: -1,
}
return cursor, nil
}
@@ -760,10 +892,12 @@ func (tx *fakeTx) Rollback() error {
}
type rowsCursor struct {
- cols []string
- pos int
- rows []*row
- closed bool
+ 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
@@ -786,7 +920,11 @@ func (rc *rowsCursor) Close() error {
}
func (rc *rowsCursor) Columns() []string {
- return rc.cols
+ return rc.cols[rc.posSet]
+}
+
+func (rc *rowsCursor) ColumnTypeScanType(index int) reflect.Type {
+ return colTypeToReflectType(rc.colType[rc.posSet][index])
}
var rowsCursorNextHook func(dest []driver.Value) error
@@ -799,14 +937,14 @@ func (rc *rowsCursor) Next(dest []driver.Value) error {
if rc.closed {
return errors.New("fakedb: cursor is closed")
}
- rc.pos++
- if rc.pos == rc.errPos {
+ rc.posRow++
+ if rc.posRow == rc.errPos {
return rc.err
}
- if rc.pos >= len(rc.rows) {
+ if rc.posRow >= len(rc.rows[rc.posSet]) {
return io.EOF // per interface spec
}
- for i, v := range rc.rows[rc.pos].cols {
+ for i, v := range rc.rows[rc.posSet][rc.posRow].cols {
// TODO(bradfitz): convert to subset types? naah, I
// think the subset types should only be input to
// driver, but the sql package should be able to handle
@@ -831,6 +969,19 @@ func (rc *rowsCursor) Next(dest []driver.Value) error {
return nil
}
+func (rc *rowsCursor) HasNextResultSet() bool {
+ return rc.posSet < len(rc.rows)-1
+}
+
+func (rc *rowsCursor) NextResultSet() error {
+ if rc.HasNextResultSet() {
+ rc.posSet++
+ rc.posRow = -1
+ return nil
+ }
+ return io.EOF // Per interface spec.
+}
+
// fakeDriverString is like driver.String, but indirects pointers like
// DefaultValueConverter.
//
@@ -882,3 +1033,29 @@ func converterForType(typ string) driver.ValueConverter {
}
panic("invalid fakedb column type of " + typ)
}
+
+func colTypeToReflectType(typ string) reflect.Type {
+ switch typ {
+ case "bool":
+ return reflect.TypeOf(false)
+ case "nullbool":
+ return reflect.TypeOf(NullBool{})
+ case "int32":
+ return reflect.TypeOf(int32(0))
+ case "string":
+ return reflect.TypeOf("")
+ case "nullstring":
+ return reflect.TypeOf(NullString{})
+ case "int64":
+ return reflect.TypeOf(int64(0))
+ case "nullint64":
+ return reflect.TypeOf(NullInt64{})
+ case "float64":
+ return reflect.TypeOf(float64(0))
+ case "nullfloat64":
+ return reflect.TypeOf(NullFloat64{})
+ case "datetime":
+ return reflect.TypeOf(time.Time{})
+ }
+ panic("invalid fakedb column type of " + typ)
+}
diff --git a/src/database/sql/internal/types.go b/src/database/sql/internal/types.go
new file mode 100644
index 0000000..1895144
--- /dev/null
+++ b/src/database/sql/internal/types.go
@@ -0,0 +1,11 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package internal
+
+// Context keys that set transaction properties for sql.BeginContext.
+type (
+ IsolationLevelKey struct{} // context value is driver.IsolationLevel
+ ReadOnlyKey struct{} // context value is bool
+)
diff --git a/src/database/sql/sql.go b/src/database/sql/sql.go
index 09de1c3..a620707 100644
--- a/src/database/sql/sql.go
+++ b/src/database/sql/sql.go
@@ -13,10 +13,13 @@
package sql
import (
+ "context"
"database/sql/driver"
+ "database/sql/internal"
"errors"
"fmt"
"io"
+ "reflect"
"runtime"
"sort"
"sync"
@@ -66,6 +69,74 @@ func Drivers() []string {
return list
}
+// A NamedArg used as an argument to Query or Exec
+// binds to the corresponding named parameter in the SQL statement.
+type NamedArg struct {
+ _Named_Fields_Required struct{}
+
+ // Name of the parameter placeholder. If empty the ordinal position in the
+ // argument list will be used.
+ Name string
+
+ // Value of the parameter. It may be assigned the same value types as
+ // the query arguments.
+ Value interface{}
+}
+
+// Named provides a more concise way to create NamedArg values.
+//
+// Example usage:
+//
+// db.ExecContext(ctx, `
+// delete from Invoice
+// where
+// TimeCreated < @end
+// and TimeCreated >= @start;`,
+// sql.Named("start", startTime),
+// sql.Named("end", endTime),
+// )
+func Named(name string, value interface{}) NamedArg {
+ // This method exists because the go1compat promise
+ // doesn't guarantee that structs don't grow more fields,
+ // so unkeyed struct literals are a vet error. Thus, we don't
+ // want to allow sql.NamedArg{name, value}.
+ return NamedArg{Name: name, Value: value}
+}
+
+// IsolationLevel is the transaction isolation level stored in Context.
+// The IsolationLevel is set with IsolationContext and the context
+// should be passed to BeginContext.
+type IsolationLevel int
+
+// Various isolation levels that drivers may support in BeginContext.
+// If a driver does not support a given isolation level an error may be returned.
+//
+// See https://en.wikipedia.org/wiki/Isolation_(database_systems)#Isolation_levels.
+const (
+ LevelDefault IsolationLevel = iota
+ LevelReadUncommitted
+ LevelReadCommitted
+ LevelWriteCommitted
+ LevelRepeatableRead
+ LevelSnapshot
+ LevelSerializable
+ LevelLinearizable
+)
+
+// IsolationContext returns a new Context that carries the provided isolation level.
+// The context must contain the isolation level before beginning the transaction
+// with BeginContext.
+func IsolationContext(ctx context.Context, level IsolationLevel) context.Context {
+ return context.WithValue(ctx, internal.IsolationLevelKey{}, driver.IsolationLevel(level))
+}
+
+// ReadOnlyWithContext returns a new Context that carries the provided
+// read-only transaction property. The context must contain the read-only property
+// before beginning the transaction with BeginContext.
+func ReadOnlyContext(ctx context.Context) context.Context {
+ return context.WithValue(ctx, internal.ReadOnlyKey{}, true)
+}
+
// RawBytes is a byte slice that holds a reference to memory owned by
// the database itself. After a Scan into a RawBytes, the slice is only
// valid until the next call to Next, Scan, or Close.
@@ -272,7 +343,7 @@ type driverConn struct {
ci driver.Conn
closed bool
finalClosed bool // ci.Close has been called
- openStmt map[driver.Stmt]bool
+ openStmt map[*driverStmt]bool
// guarded by db.mu
inUse bool
@@ -284,10 +355,10 @@ func (dc *driverConn) releaseConn(err error) {
dc.db.putConn(dc, err)
}
-func (dc *driverConn) removeOpenStmt(si driver.Stmt) {
+func (dc *driverConn) removeOpenStmt(ds *driverStmt) {
dc.Lock()
defer dc.Unlock()
- delete(dc.openStmt, si)
+ delete(dc.openStmt, ds)
}
func (dc *driverConn) expired(timeout time.Duration) bool {
@@ -297,28 +368,23 @@ func (dc *driverConn) expired(timeout time.Duration) bool {
return dc.createdAt.Add(timeout).Before(nowFunc())
}
-func (dc *driverConn) prepareLocked(query string) (driver.Stmt, error) {
- si, err := dc.ci.Prepare(query)
- if err == nil {
- // Track each driverConn's open statements, so we can close them
- // before closing the conn.
- //
- // TODO(bradfitz): let drivers opt out of caring about
- // stmt closes if the conn is about to close anyway? For now
- // do the safe thing, in case stmts need to be closed.
- //
- // TODO(bradfitz): after Go 1.2, closing driver.Stmts
- // should be moved to driverStmt, using unique
- // *driverStmts everywhere (including from
- // *Stmt.connStmt, instead of returning a
- // driver.Stmt), using driverStmt as a pointer
- // everywhere, and making it a finalCloser.
- if dc.openStmt == nil {
- dc.openStmt = make(map[driver.Stmt]bool)
- }
- dc.openStmt[si] = true
+func (dc *driverConn) prepareLocked(ctx context.Context, query string) (*driverStmt, error) {
+ si, err := ctxDriverPrepare(ctx, dc.ci, query)
+ if err != nil {
+ return nil, err
}
- return si, err
+
+ // Track each driverConn's open statements, so we can close them
+ // before closing the conn.
+ //
+ // Wrap all driver.Stmt is *driverStmt to ensure they are only closed once.
+ if dc.openStmt == nil {
+ dc.openStmt = make(map[*driverStmt]bool)
+ }
+ ds := &driverStmt{Locker: dc, si: si}
+ dc.openStmt[ds] = true
+
+ return ds, nil
}
// the dc.db's Mutex is held.
@@ -350,17 +416,26 @@ func (dc *driverConn) Close() error {
}
func (dc *driverConn) finalClose() error {
- dc.Lock()
+ var err error
- for si := range dc.openStmt {
- si.Close()
+ // Each *driverStmt has a lock to the dc. Copy the list out of the dc
+ // before calling close on each stmt.
+ var openStmt []*driverStmt
+ withLock(dc, func() {
+ openStmt = make([]*driverStmt, 0, len(dc.openStmt))
+ for ds := range dc.openStmt {
+ openStmt = append(openStmt, ds)
+ }
+ dc.openStmt = nil
+ })
+ for _, ds := range openStmt {
+ ds.Close()
}
- dc.openStmt = nil
-
- err := dc.ci.Close()
- dc.ci = nil
- dc.finalClosed = true
- dc.Unlock()
+ withLock(dc, func() {
+ dc.finalClosed = true
+ err = dc.ci.Close()
+ dc.ci = nil
+ })
dc.db.mu.Lock()
dc.db.numOpen--
@@ -377,12 +452,21 @@ func (dc *driverConn) finalClose() error {
type driverStmt struct {
sync.Locker // the *driverConn
si driver.Stmt
+ closed bool
+ closeErr error // return value of previous Close call
}
+// Close ensures dirver.Stmt is only closed once any always returns the same
+// result.
func (ds *driverStmt) Close() error {
ds.Lock()
defer ds.Unlock()
- return ds.si.Close()
+ if ds.closed {
+ return ds.closeErr
+ }
+ ds.closed = true
+ ds.closeErr = ds.si.Close()
+ return ds.closeErr
}
// depSet is a finalCloser's outstanding dependencies
@@ -494,18 +578,36 @@ func Open(driverName, dataSourceName string) (*DB, error) {
return db, nil
}
-// Ping verifies a connection to the database is still alive,
+// PingContext verifies a connection to the database is still alive,
// establishing a connection if necessary.
-func (db *DB) Ping() error {
- // TODO(bradfitz): give drivers an optional hook to implement
- // this in a more efficient or more reliable way, if they
- // have one.
- dc, err := db.conn(cachedOrNewConn)
+func (db *DB) PingContext(ctx context.Context) 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, alwaysNewConn)
+ }
if err != nil {
return err
}
- db.putConn(dc, nil)
- return nil
+
+ if pinger, ok := dc.ci.(driver.Pinger); ok {
+ err = pinger.Ping(ctx)
+ }
+ db.putConn(dc, err)
+ return err
+}
+
+// Ping verifies a connection to the database is still alive,
+// establishing a connection if necessary.
+func (db *DB) Ping() error {
+ return db.PingContext(context.Background())
}
// Close closes the database, releasing any open resources.
@@ -777,12 +879,19 @@ type connRequest struct {
var errDBClosed = errors.New("sql: database is closed")
// conn returns a newly-opened or cached *driverConn.
-func (db *DB) conn(strategy connReuseStrategy) (*driverConn, error) {
+func (db *DB) conn(ctx context.Context, strategy connReuseStrategy) (*driverConn, error) {
db.mu.Lock()
if db.closed {
db.mu.Unlock()
return nil, errDBClosed
}
+ // Check if the context is expired.
+ select {
+ default:
+ case <-ctx.Done():
+ db.mu.Unlock()
+ return nil, ctx.Err()
+ }
lifetime := db.maxLifetime
// Prefer a free connection, if possible.
@@ -808,15 +917,21 @@ func (db *DB) conn(strategy connReuseStrategy) (*driverConn, error) {
req := make(chan connRequest, 1)
db.connRequests = append(db.connRequests, req)
db.mu.Unlock()
- ret, ok := <-req
- if !ok {
- return nil, errDBClosed
- }
- if ret.err == nil && ret.conn.expired(lifetime) {
- ret.conn.Close()
- return nil, driver.ErrBadConn
+
+ // Timeout the connection request with the context.
+ select {
+ case <-ctx.Done():
+ return nil, ctx.Err()
+ case ret, ok := <-req:
+ if !ok {
+ return nil, errDBClosed
+ }
+ if ret.err == nil && ret.conn.expired(lifetime) {
+ ret.conn.Close()
+ return nil, driver.ErrBadConn
+ }
+ return ret.conn, ret.err
}
- return ret.conn, ret.err
}
db.numOpen++ // optimistically
@@ -844,21 +959,22 @@ func (db *DB) conn(strategy connReuseStrategy) (*driverConn, error) {
// putConnHook is a hook for testing.
var putConnHook func(*DB, *driverConn)
-// noteUnusedDriverStatement notes that si is no longer used and should
+// noteUnusedDriverStatement notes that ds is no longer used and should
// be closed whenever possible (when c is next not in use), unless c is
// already closed.
-func (db *DB) noteUnusedDriverStatement(c *driverConn, si driver.Stmt) {
+func (db *DB) noteUnusedDriverStatement(c *driverConn, ds *driverStmt) {
db.mu.Lock()
defer db.mu.Unlock()
if c.inUse {
c.onPut = append(c.onPut, func() {
- si.Close()
+ ds.Close()
})
} else {
c.Lock()
- defer c.Unlock()
- if !c.finalClosed {
- si.Close()
+ fc := c.finalClosed
+ c.Unlock()
+ if !fc {
+ ds.Close()
}
}
}
@@ -952,40 +1068,53 @@ func (db *DB) putConnDBLocked(dc *driverConn, err error) bool {
// connection to be opened.
const maxBadConnRetries = 2
-// Prepare creates a prepared statement for later queries or executions.
+// 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.
-func (db *DB) Prepare(query string) (*Stmt, error) {
+//
+// The provided context is used for the preparation of the statement, not for the
+// execution of the statement.
+func (db *DB) PrepareContext(ctx context.Context, query string) (*Stmt, error) {
var stmt *Stmt
var err error
for i := 0; i < maxBadConnRetries; i++ {
- stmt, err = db.prepare(query, cachedOrNewConn)
+ stmt, err = db.prepare(ctx, query, cachedOrNewConn)
if err != driver.ErrBadConn {
break
}
}
if err == driver.ErrBadConn {
- return db.prepare(query, alwaysNewConn)
+ return db.prepare(ctx, query, alwaysNewConn)
}
return stmt, err
}
-func (db *DB) prepare(query string, strategy connReuseStrategy) (*Stmt, error) {
+// Prepare creates a prepared statement for later queries or executions.
+// Multiple queries or executions may be run concurrently from the
+// returned statement.
+// The caller must call the statement's Close method
+// when the statement is no longer needed.
+func (db *DB) Prepare(query string) (*Stmt, error) {
+ return db.PrepareContext(context.Background(), query)
+}
+
+func (db *DB) prepare(ctx context.Context, query string, strategy connReuseStrategy) (*Stmt, error) {
// TODO: check if db.driver supports an optional
// driver.Preparer interface and call that instead, if so,
// otherwise we make a prepared statement that's bound
// to a connection, and to execute this prepared statement
// we either need to use this connection (if it's free), else
// get a new connection + re-prepare + execute on that one.
- dc, err := db.conn(strategy)
+ dc, err := db.conn(ctx, strategy)
if err != nil {
return nil, err
}
- dc.Lock()
- si, err := dc.prepareLocked(query)
- dc.Unlock()
+ var ds *driverStmt
+ withLock(dc, func() {
+ ds, err = dc.prepareLocked(ctx, query)
+ })
if err != nil {
db.putConn(dc, err)
return nil, err
@@ -993,7 +1122,7 @@ func (db *DB) prepare(query string, strategy connReuseStrategy) (*Stmt, error) {
stmt := &Stmt{
db: db,
query: query,
- css: []connStmt{{dc, si}},
+ css: []connStmt{{dc, ds}},
lastNumClosed: atomic.LoadUint64(&db.numClosed),
}
db.addDep(stmt, stmt)
@@ -1001,25 +1130,31 @@ func (db *DB) prepare(query string, strategy connReuseStrategy) (*Stmt, error) {
return stmt, nil
}
-// Exec executes a query without returning any rows.
+// ExecContext executes a query without returning any rows.
// The args are for any placeholder parameters in the query.
-func (db *DB) Exec(query string, args ...interface{}) (Result, error) {
+func (db *DB) ExecContext(ctx context.Context, query string, args ...interface{}) (Result, error) {
var res Result
var err error
for i := 0; i < maxBadConnRetries; i++ {
- res, err = db.exec(query, args, cachedOrNewConn)
+ res, err = db.exec(ctx, query, args, cachedOrNewConn)
if err != driver.ErrBadConn {
break
}
}
if err == driver.ErrBadConn {
- return db.exec(query, args, alwaysNewConn)
+ return db.exec(ctx, query, args, alwaysNewConn)
}
return res, err
}
-func (db *DB) exec(query string, args []interface{}, strategy connReuseStrategy) (res Result, err error) {
- dc, err := db.conn(strategy)
+// Exec executes a query without returning any rows.
+// The args are for any placeholder parameters in the query.
+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) {
+ dc, err := db.conn(ctx, strategy)
if err != nil {
return nil, err
}
@@ -1028,13 +1163,15 @@ func (db *DB) exec(query string, args []interface{}, strategy connReuseStrategy)
}()
if execer, ok := dc.ci.(driver.Execer); ok {
- dargs, err := driverArgs(nil, args)
+ var dargs []driver.NamedValue
+ dargs, err = driverArgs(nil, args)
if err != nil {
return nil, err
}
- dc.Lock()
- resi, err := execer.Exec(query, dargs)
- dc.Unlock()
+ var resi driver.Result
+ withLock(dc, func() {
+ resi, err = ctxDriverExec(ctx, execer, query, dargs)
+ })
if err != driver.ErrSkip {
if err != nil {
return nil, err
@@ -1043,54 +1180,63 @@ func (db *DB) exec(query string, args []interface{}, strategy connReuseStrategy)
}
}
- dc.Lock()
- si, err := dc.ci.Prepare(query)
- dc.Unlock()
+ var si driver.Stmt
+ withLock(dc, func() {
+ si, err = ctxDriverPrepare(ctx, dc.ci, query)
+ })
if err != nil {
return nil, err
}
- defer withLock(dc, func() { si.Close() })
- return resultFromStatement(driverStmt{dc, si}, args...)
+ ds := &driverStmt{Locker: dc, si: si}
+ defer ds.Close()
+ return resultFromStatement(ctx, ds, args...)
}
-// Query executes a query that returns rows, typically a SELECT.
+// QueryContext executes a query that returns rows, typically a SELECT.
// The args are for any placeholder parameters in the query.
-func (db *DB) Query(query string, args ...interface{}) (*Rows, error) {
+func (db *DB) QueryContext(ctx context.Context, query string, args ...interface{}) (*Rows, error) {
var rows *Rows
var err error
for i := 0; i < maxBadConnRetries; i++ {
- rows, err = db.query(query, args, cachedOrNewConn)
+ rows, err = db.query(ctx, query, args, cachedOrNewConn)
if err != driver.ErrBadConn {
break
}
}
if err == driver.ErrBadConn {
- return db.query(query, args, alwaysNewConn)
+ return db.query(ctx, query, args, alwaysNewConn)
}
return rows, err
}
-func (db *DB) query(query string, args []interface{}, strategy connReuseStrategy) (*Rows, error) {
- ci, err := db.conn(strategy)
+// Query executes a query that returns rows, typically a SELECT.
+// The args are for any placeholder parameters in the query.
+func (db *DB) Query(query string, args ...interface{}) (*Rows, error) {
+ return db.QueryContext(context.Background(), query, args...)
+}
+
+func (db *DB) query(ctx context.Context, query string, args []interface{}, strategy connReuseStrategy) (*Rows, error) {
+ ci, err := db.conn(ctx, strategy)
if err != nil {
return nil, err
}
- return db.queryConn(ci, ci.releaseConn, query, args)
+ return db.queryConn(ctx, ci, ci.releaseConn, query, args)
}
// queryConn executes a query on the given connection.
// The connection gets released by the releaseConn function.
-func (db *DB) queryConn(dc *driverConn, releaseConn func(error), query string, args []interface{}) (*Rows, error) {
+func (db *DB) queryConn(ctx 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)
if err != nil {
releaseConn(err)
return nil, err
}
- dc.Lock()
- rowsi, err := queryer.Query(query, dargs)
- dc.Unlock()
+ var rowsi driver.Rows
+ withLock(dc, func() {
+ rowsi, err = ctxDriverQuery(ctx, queryer, query, dargs)
+ })
if err != driver.ErrSkip {
if err != nil {
releaseConn(err)
@@ -1103,24 +1249,25 @@ func (db *DB) queryConn(dc *driverConn, releaseConn func(error), query string, a
releaseConn: releaseConn,
rowsi: rowsi,
}
+ rows.initContextClose(ctx)
return rows, nil
}
}
- dc.Lock()
- si, err := dc.ci.Prepare(query)
- dc.Unlock()
+ var si driver.Stmt
+ var err error
+ withLock(dc, func() {
+ si, err = ctxDriverPrepare(ctx, dc.ci, query)
+ })
if err != nil {
releaseConn(err)
return nil, err
}
- ds := driverStmt{dc, si}
- rowsi, err := rowsiFromStatement(ds, args...)
+ ds := &driverStmt{Locker: dc, si: si}
+ rowsi, err := rowsiFromStatement(ctx, ds, args...)
if err != nil {
- dc.Lock()
- si.Close()
- dc.Unlock()
+ ds.Close()
releaseConn(err)
return nil, err
}
@@ -1131,53 +1278,94 @@ func (db *DB) queryConn(dc *driverConn, releaseConn func(error), query string, a
dc: dc,
releaseConn: releaseConn,
rowsi: rowsi,
- closeStmt: si,
+ closeStmt: ds,
}
+ rows.initContextClose(ctx)
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.
+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}
+}
+
// 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.
func (db *DB) QueryRow(query string, args ...interface{}) *Row {
- rows, err := db.Query(query, args...)
- return &Row{rows: rows, err: err}
+ return db.QueryRowContext(context.Background(), query, args...)
}
-// Begin starts a transaction. The isolation level is dependent on
-// the driver.
-func (db *DB) Begin() (*Tx, error) {
+// BeginContext 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
+// BeginContext is canceled.
+//
+// An isolation level may be set by setting the value in the context
+// before calling this. If a non-default isolation level is used
+// that the driver doesn't support an error will be returned. Different drivers
+// may have slightly different meanings for the same isolation level.
+func (db *DB) BeginContext(ctx context.Context) (*Tx, error) {
var tx *Tx
var err error
for i := 0; i < maxBadConnRetries; i++ {
- tx, err = db.begin(cachedOrNewConn)
+ tx, err = db.begin(ctx, cachedOrNewConn)
if err != driver.ErrBadConn {
break
}
}
if err == driver.ErrBadConn {
- return db.begin(alwaysNewConn)
+ return db.begin(ctx, alwaysNewConn)
}
return tx, err
}
-func (db *DB) begin(strategy connReuseStrategy) (tx *Tx, err error) {
- dc, err := db.conn(strategy)
+// Begin starts a transaction. The default isolation level is dependent on
+// the driver.
+func (db *DB) Begin() (*Tx, error) {
+ return db.BeginContext(context.Background())
+}
+
+func (db *DB) begin(ctx context.Context, strategy connReuseStrategy) (tx *Tx, err error) {
+ dc, err := db.conn(ctx, strategy)
if err != nil {
return nil, err
}
- dc.Lock()
- txi, err := dc.ci.Begin()
- dc.Unlock()
+ var txi driver.Tx
+ withLock(dc, func() {
+ txi, err = ctxDriverBegin(ctx, dc.ci)
+ })
if err != nil {
db.putConn(dc, err)
return nil, err
}
- return &Tx{
- db: db,
- dc: dc,
- txi: txi,
- }, nil
+
+ // Schedule the transaction to rollback when the context is cancelled.
+ // 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,
+ }
+ go func(tx *Tx) {
+ select {
+ case <-tx.ctx.Done():
+ if !tx.isDone() {
+ // Discard and close the connection used to ensure the transaction
+ // is closed and the resources are released.
+ tx.rollback(true)
+ }
+ }
+ }(tx)
+ return tx, nil
}
// Driver returns the database's underlying driver.
@@ -1203,10 +1391,11 @@ type Tx struct {
dc *driverConn
txi driver.Tx
- // done transitions from false to true exactly once, on Commit
+ // done transitions from 0 to 1 exactly once, on Commit
// or Rollback. once done, all operations fail with
// ErrTxDone.
- done bool
+ // Use atomic operations on value when checking value.
+ done int32
// All Stmts prepared for this transaction. These will be closed after the
// transaction has been committed or rolled back.
@@ -1214,22 +1403,34 @@ type Tx struct {
sync.Mutex
v []*Stmt
}
+
+ // cancel is called after done transitions from false to true.
+ cancel func()
+
+ // ctx lives for the life of the transaction.
+ ctx context.Context
+}
+
+func (tx *Tx) isDone() bool {
+ return atomic.LoadInt32(&tx.done) != 0
}
+// ErrTxDone is returned by any operation that is performed on a transaction
+// that has already been committed or rolled back.
var ErrTxDone = errors.New("sql: Transaction has already been committed or rolled back")
func (tx *Tx) close(err error) {
- if tx.done {
+ if !atomic.CompareAndSwapInt32(&tx.done, 0, 1) {
panic("double close") // internal error
}
- tx.done = true
tx.db.putConn(tx.dc, err)
+ tx.cancel()
tx.dc = nil
tx.txi = nil
}
-func (tx *Tx) grabConn() (*driverConn, error) {
- if tx.done {
+func (tx *Tx) grabConn(ctx context.Context) (*driverConn, error) {
+ if tx.isDone() {
return nil, ErrTxDone
}
return tx.dc, nil
@@ -1238,20 +1439,26 @@ func (tx *Tx) grabConn() (*driverConn, error) {
// Closes all Stmts prepared for this transaction.
func (tx *Tx) closePrepared() {
tx.stmts.Lock()
+ defer tx.stmts.Unlock()
for _, stmt := range tx.stmts.v {
stmt.Close()
}
- tx.stmts.Unlock()
}
// Commit commits the transaction.
func (tx *Tx) Commit() error {
- if tx.done {
+ select {
+ default:
+ case <-tx.ctx.Done():
+ return tx.ctx.Err()
+ }
+ if tx.isDone() {
return ErrTxDone
}
- tx.dc.Lock()
- err := tx.txi.Commit()
- tx.dc.Unlock()
+ var err error
+ withLock(tx.dc, func() {
+ err = tx.txi.Commit()
+ })
if err != driver.ErrBadConn {
tx.closePrepared()
}
@@ -1259,28 +1466,42 @@ func (tx *Tx) Commit() error {
return err
}
-// Rollback aborts the transaction.
-func (tx *Tx) Rollback() error {
- if tx.done {
+// rollback aborts the transaction and optionally forces the pool to discard
+// the connection.
+func (tx *Tx) rollback(discardConn bool) error {
+ if tx.isDone() {
return ErrTxDone
}
- tx.dc.Lock()
- err := tx.txi.Rollback()
- tx.dc.Unlock()
+ var err error
+ withLock(tx.dc, func() {
+ err = tx.txi.Rollback()
+ })
if err != driver.ErrBadConn {
tx.closePrepared()
}
+ if discardConn {
+ err = driver.ErrBadConn
+ }
tx.close(err)
return err
}
+// Rollback aborts the transaction.
+func (tx *Tx) Rollback() error {
+ return tx.rollback(false)
+}
+
// Prepare creates a prepared statement for use within a transaction.
//
-// The returned statement operates within the transaction and can no longer
-// be used once the transaction has been committed or rolled back.
+// The returned statement operates within the transaction and will be closed
+// when the transaction has been committed or rolled back.
//
// To use an existing prepared statement on this transaction, see Tx.Stmt.
-func (tx *Tx) Prepare(query string) (*Stmt, error) {
+//
+// The provided context will be used for the preparation of the context, not
+// 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) {
// 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
@@ -1294,14 +1515,15 @@ func (tx *Tx) Prepare(query string) (*Stmt, error) {
// 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()
+ dc, err := tx.grabConn(ctx)
if err != nil {
return nil, err
}
- dc.Lock()
- si, err := dc.ci.Prepare(query)
- dc.Unlock()
+ var si driver.Stmt
+ withLock(dc, func() {
+ si, err = ctxDriverPrepare(ctx, dc.ci, query)
+ })
if err != nil {
return nil, err
}
@@ -1309,7 +1531,7 @@ func (tx *Tx) Prepare(query string) (*Stmt, error) {
stmt := &Stmt{
db: tx.db,
tx: tx,
- txsi: &driverStmt{
+ txds: &driverStmt{
Locker: dc,
si: si,
},
@@ -1321,7 +1543,17 @@ func (tx *Tx) Prepare(query string) (*Stmt, error) {
return stmt, nil
}
-// Stmt returns a transaction-specific prepared statement from
+// Prepare creates a prepared statement for use within a transaction.
+//
+// The returned statement operates within the transaction and can no longer
+// be used once the transaction has been committed or rolled back.
+//
+// To use an existing prepared statement on this transaction, see Tx.Stmt.
+func (tx *Tx) Prepare(query string) (*Stmt, error) {
+ return tx.PrepareContext(context.Background(), query)
+}
+
+// StmtContext returns a transaction-specific prepared statement from
// an existing statement.
//
// Example:
@@ -1329,11 +1561,11 @@ func (tx *Tx) Prepare(query string) (*Stmt, error) {
// ...
// tx, err := db.Begin()
// ...
-// res, err := tx.Stmt(updateMoney).Exec(123.45, 98293203)
+// res, err := tx.StmtContext(ctx, updateMoney).Exec(123.45, 98293203)
//
-// The returned statement operates within the transaction and can no longer
-// be used once the transaction has been committed or rolled back.
-func (tx *Tx) Stmt(stmt *Stmt) *Stmt {
+// 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 {
// 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
@@ -1342,17 +1574,18 @@ func (tx *Tx) Stmt(stmt *Stmt) *Stmt {
if tx.db != stmt.db {
return &Stmt{stickyErr: errors.New("sql: Tx.Stmt: statement from different database used")}
}
- dc, err := tx.grabConn()
+ dc, err := tx.grabConn(ctx)
if err != nil {
return &Stmt{stickyErr: err}
}
- dc.Lock()
- si, err := dc.ci.Prepare(stmt.query)
- dc.Unlock()
+ var si driver.Stmt
+ withLock(dc, func() {
+ si, err = ctxDriverPrepare(ctx, dc.ci, stmt.query)
+ })
txs := &Stmt{
db: tx.db,
tx: tx,
- txsi: &driverStmt{
+ txds: &driverStmt{
Locker: dc,
si: si,
},
@@ -1365,10 +1598,26 @@ func (tx *Tx) Stmt(stmt *Stmt) *Stmt {
return txs
}
-// Exec executes a query that doesn't return rows.
+// Stmt returns a transaction-specific prepared statement from
+// an existing statement.
+//
+// Example:
+// updateMoney, err := db.Prepare("UPDATE balance SET money=money+? WHERE id=?")
+// ...
+// tx, err := db.Begin()
+// ...
+// res, err := tx.Stmt(updateMoney).Exec(123.45, 98293203)
+//
+// The returned statement operates within the transaction and will be closed
+// when the transaction has been committed or rolled back.
+func (tx *Tx) Stmt(stmt *Stmt) *Stmt {
+ return tx.StmtContext(context.Background(), stmt)
+}
+
+// ExecContext executes a query that doesn't return rows.
// For example: an INSERT and UPDATE.
-func (tx *Tx) Exec(query string, args ...interface{}) (Result, error) {
- dc, err := tx.grabConn()
+func (tx *Tx) ExecContext(ctx context.Context, query string, args ...interface{}) (Result, error) {
+ dc, err := tx.grabConn(ctx)
if err != nil {
return nil, err
}
@@ -1378,9 +1627,10 @@ func (tx *Tx) Exec(query string, args ...interface{}) (Result, error) {
if err != nil {
return nil, err
}
- dc.Lock()
- resi, err := execer.Exec(query, dargs)
- dc.Unlock()
+ var resi driver.Result
+ withLock(dc, func() {
+ resi, err = ctxDriverExec(ctx, execer, query, dargs)
+ })
if err == nil {
return driverResult{dc, resi}, nil
}
@@ -1389,39 +1639,59 @@ func (tx *Tx) Exec(query string, args ...interface{}) (Result, error) {
}
}
- dc.Lock()
- si, err := dc.ci.Prepare(query)
- dc.Unlock()
+ var si driver.Stmt
+ withLock(dc, func() {
+ si, err = ctxDriverPrepare(ctx, dc.ci, query)
+ })
if err != nil {
return nil, err
}
- defer withLock(dc, func() { si.Close() })
+ ds := &driverStmt{Locker: dc, si: si}
+ defer ds.Close()
- return resultFromStatement(driverStmt{dc, si}, args...)
+ return resultFromStatement(ctx, ds, args...)
}
-// Query executes a query that returns rows, typically a SELECT.
-func (tx *Tx) Query(query string, args ...interface{}) (*Rows, error) {
- dc, err := tx.grabConn()
+// Exec executes a query that doesn't return rows.
+// For example: an INSERT and UPDATE.
+func (tx *Tx) Exec(query string, args ...interface{}) (Result, error) {
+ return tx.ExecContext(context.Background(), query, args...)
+}
+
+// QueryContext executes a query that returns rows, typically a SELECT.
+func (tx *Tx) QueryContext(ctx context.Context, query string, args ...interface{}) (*Rows, error) {
+ dc, err := tx.grabConn(ctx)
if err != nil {
return nil, err
}
releaseConn := func(error) {}
- return tx.db.queryConn(dc, releaseConn, query, args)
+ return tx.db.queryConn(ctx, dc, releaseConn, query, args)
+}
+
+// Query executes a query that returns rows, typically a SELECT.
+func (tx *Tx) Query(query string, args ...interface{}) (*Rows, error) {
+ return tx.QueryContext(context.Background(), 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.
+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}
}
// 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.
func (tx *Tx) QueryRow(query string, args ...interface{}) *Row {
- rows, err := tx.Query(query, args...)
- return &Row{rows: rows, err: err}
+ return tx.QueryRowContext(context.Background(), query, args...)
}
// connStmt is a prepared statement on a particular connection.
type connStmt struct {
dc *driverConn
- si driver.Stmt
+ ds *driverStmt
}
// Stmt is a prepared statement.
@@ -1436,7 +1706,7 @@ type Stmt struct {
// If in a transaction, else both nil:
tx *Tx
- txsi *driverStmt
+ txds *driverStmt
mu sync.Mutex // protects the rest of the fields
closed bool
@@ -1452,15 +1722,15 @@ type Stmt struct {
lastNumClosed uint64
}
-// Exec executes a prepared statement with the given arguments and
+// ExecContext executes a prepared statement with the given arguments and
// returns a Result summarizing the effect of the statement.
-func (s *Stmt) Exec(args ...interface{}) (Result, error) {
+func (s *Stmt) ExecContext(ctx context.Context, args ...interface{}) (Result, error) {
s.closemu.RLock()
defer s.closemu.RUnlock()
var res Result
for i := 0; i < maxBadConnRetries; i++ {
- dc, releaseConn, si, err := s.connStmt()
+ _, releaseConn, ds, err := s.connStmt(ctx)
if err != nil {
if err == driver.ErrBadConn {
continue
@@ -1468,7 +1738,7 @@ func (s *Stmt) Exec(args ...interface{}) (Result, error) {
return nil, err
}
- res, err = resultFromStatement(driverStmt{dc, si}, args...)
+ res, err = resultFromStatement(ctx, ds, args...)
releaseConn(err)
if err != driver.ErrBadConn {
return res, err
@@ -1477,13 +1747,19 @@ func (s *Stmt) Exec(args ...interface{}) (Result, error) {
return nil, driver.ErrBadConn
}
-func driverNumInput(ds driverStmt) int {
+// Exec executes a prepared statement with the given arguments and
+// returns a Result summarizing the effect of the statement.
+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(ds driverStmt, args ...interface{}) (Result, error) {
+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
@@ -1493,14 +1769,15 @@ func resultFromStatement(ds driverStmt, args ...interface{}) (Result, error) {
return nil, fmt.Errorf("sql: expected %d arguments, got %d", want, len(args))
}
- dargs, err := driverArgs(&ds, args)
+ dargs, err := driverArgs(ds, args)
if err != nil {
return nil, err
}
ds.Lock()
defer ds.Unlock()
- resi, err := ds.si.Exec(dargs)
+
+ resi, err := ctxDriverStmtExec(ctx, ds.si, dargs)
if err != nil {
return nil, err
}
@@ -1536,7 +1813,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() (ci *driverConn, releaseConn func(error), si driver.Stmt, err error) {
+func (s *Stmt) connStmt(ctx context.Context) (ci *driverConn, releaseConn func(error), ds *driverStmt, err error) {
if err = s.stickyErr; err != nil {
return
}
@@ -1551,19 +1828,18 @@ func (s *Stmt) connStmt() (ci *driverConn, releaseConn func(error), si driver.St
// transaction was created on.
if s.tx != nil {
s.mu.Unlock()
- ci, err = s.tx.grabConn() // blocks, waiting for the connection.
+ ci, err = s.tx.grabConn(ctx) // blocks, waiting for the connection.
if err != nil {
return
}
releaseConn = func(error) {}
- return ci, releaseConn, s.txsi.si, nil
+ return ci, releaseConn, s.txds, nil
}
s.removeClosedStmtLocked()
s.mu.Unlock()
- // TODO(bradfitz): or always wait for one? make configurable later?
- dc, err := s.db.conn(cachedOrNewConn)
+ dc, err := s.db.conn(ctx, cachedOrNewConn)
if err != nil {
return nil, nil, nil, err
}
@@ -1572,36 +1848,36 @@ func (s *Stmt) connStmt() (ci *driverConn, releaseConn func(error), si driver.St
for _, v := range s.css {
if v.dc == dc {
s.mu.Unlock()
- return dc, dc.releaseConn, v.si, nil
+ return dc, dc.releaseConn, v.ds, nil
}
}
s.mu.Unlock()
// No luck; we need to prepare the statement on this connection
- dc.Lock()
- si, err = dc.prepareLocked(s.query)
- dc.Unlock()
+ withLock(dc, func() {
+ ds, err = dc.prepareLocked(ctx, s.query)
+ })
if err != nil {
s.db.putConn(dc, err)
return nil, nil, nil, err
}
s.mu.Lock()
- cs := connStmt{dc, si}
+ cs := connStmt{dc, ds}
s.css = append(s.css, cs)
s.mu.Unlock()
- return dc, dc.releaseConn, si, nil
+ return dc, dc.releaseConn, ds, nil
}
-// Query executes a prepared query statement with the given arguments
+// QueryContext executes a prepared query statement with the given arguments
// and returns the query results as a *Rows.
-func (s *Stmt) Query(args ...interface{}) (*Rows, error) {
+func (s *Stmt) QueryContext(ctx context.Context, args ...interface{}) (*Rows, error) {
s.closemu.RLock()
defer s.closemu.RUnlock()
var rowsi driver.Rows
for i := 0; i < maxBadConnRetries; i++ {
- dc, releaseConn, si, err := s.connStmt()
+ dc, releaseConn, ds, err := s.connStmt(ctx)
if err != nil {
if err == driver.ErrBadConn {
continue
@@ -1609,7 +1885,7 @@ func (s *Stmt) Query(args ...interface{}) (*Rows, error) {
return nil, err
}
- rowsi, err = rowsiFromStatement(driverStmt{dc, si}, args...)
+ rowsi, err = rowsiFromStatement(ctx, ds, args...)
if err == nil {
// Note: ownership of ci passes to the *Rows, to be freed
// with releaseConn.
@@ -1618,6 +1894,7 @@ func (s *Stmt) Query(args ...interface{}) (*Rows, error) {
rowsi: rowsi,
// releaseConn set below
}
+ rows.initContextClose(ctx)
s.db.addDep(s, rows)
rows.releaseConn = func(err error) {
releaseConn(err)
@@ -1634,10 +1911,17 @@ func (s *Stmt) Query(args ...interface{}) (*Rows, error) {
return nil, driver.ErrBadConn
}
-func rowsiFromStatement(ds driverStmt, args ...interface{}) (driver.Rows, error) {
- ds.Lock()
- want := ds.si.NumInput()
- ds.Unlock()
+// Query executes a prepared query statement with the given arguments
+// and returns the query results as a *Rows.
+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) {
+ var want int
+ withLock(ds, func() {
+ want = ds.si.NumInput()
+ })
// -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
@@ -1646,21 +1930,22 @@ func rowsiFromStatement(ds driverStmt, args ...interface{}) (driver.Rows, error)
return nil, fmt.Errorf("sql: statement expects %d inputs; got %d", want, len(args))
}
- dargs, err := driverArgs(&ds, args)
+ dargs, err := driverArgs(ds, args)
if err != nil {
return nil, err
}
ds.Lock()
- rowsi, err := ds.si.Query(dargs)
- ds.Unlock()
+ defer ds.Unlock()
+
+ rowsi, err := ctxDriverStmtQuery(ctx, ds.si, dargs)
if err != nil {
return nil, err
}
return rowsi, nil
}
-// QueryRow executes a prepared query statement with the given arguments.
+// QueryRowContext executes a prepared query statement with the given arguments.
// If an error occurs during the execution of the statement, that error will
// be returned by a call to Scan on the returned *Row, which is always non-nil.
// If the query selects no rows, the *Row's Scan will return ErrNoRows.
@@ -1670,15 +1955,30 @@ func rowsiFromStatement(ds driverStmt, args ...interface{}) (driver.Rows, error)
// Example usage:
//
// var name string
-// err := nameByUseridStmt.QueryRow(id).Scan(&name)
-func (s *Stmt) QueryRow(args ...interface{}) *Row {
- rows, err := s.Query(args...)
+// err := nameByUseridStmt.QueryRowContext(ctx, id).Scan(&name)
+func (s *Stmt) QueryRowContext(ctx context.Context, args ...interface{}) *Row {
+ rows, err := s.QueryContext(ctx, args...)
if err != nil {
return &Row{err: err}
}
return &Row{rows: rows}
}
+// QueryRow executes a prepared query statement with the given arguments.
+// If an error occurs during the execution of the statement, that error will
+// be returned by a call to Scan on the returned *Row, which is always non-nil.
+// 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.
+//
+// Example usage:
+//
+// var name string
+// err := nameByUseridStmt.QueryRow(id).Scan(&name)
+func (s *Stmt) QueryRow(args ...interface{}) *Row {
+ return s.QueryRowContext(context.Background(), args...)
+}
+
// Close closes the statement.
func (s *Stmt) Close() error {
s.closemu.Lock()
@@ -1693,13 +1993,11 @@ func (s *Stmt) Close() error {
return nil
}
s.closed = true
+ s.mu.Unlock()
if s.tx != nil {
- err := s.txsi.Close()
- s.mu.Unlock()
- return err
+ return s.txds.Close()
}
- s.mu.Unlock()
return s.db.removeDep(s, s)
}
@@ -1709,8 +2007,8 @@ func (s *Stmt) finalClose() error {
defer s.mu.Unlock()
if s.css != nil {
for _, v := range s.css {
- s.db.noteUnusedDriverStatement(v.dc, v.si)
- v.dc.removeOpenStmt(v.si)
+ s.db.noteUnusedDriverStatement(v.dc, v.ds)
+ v.dc.removeOpenStmt(v.ds)
}
s.css = nil
}
@@ -1736,10 +2034,28 @@ type Rows struct {
releaseConn func(error)
rowsi driver.Rows
- closed bool
+ // closed value is 1 when the Rows is closed.
+ // Use atomic operations on value when checking value.
+ closed int32
+ ctxClose chan struct{} // closed when Rows is closed, may be null.
lastcols []driver.Value
lasterr error // non-nil only if closed is true
- closeStmt driver.Stmt // if non-nil, statement to Close on close
+ closeStmt *driverStmt // if non-nil, statement to Close on close
+}
+
+func (rs *Rows) initContextClose(ctx context.Context) {
+ if ctx.Done() == context.Background().Done() {
+ return
+ }
+
+ rs.ctxClose = make(chan struct{})
+ go func() {
+ select {
+ case <-ctx.Done():
+ rs.Close()
+ case <-rs.ctxClose:
+ }
+ }()
}
// Next prepares the next result row for reading with the Scan method. It
@@ -1749,7 +2065,7 @@ type Rows struct {
//
// Every call to Scan, even the first one, must be preceded by a call to Next.
func (rs *Rows) Next() bool {
- if rs.closed {
+ if rs.isClosed() {
return false
}
if rs.lastcols == nil {
@@ -1757,6 +2073,47 @@ func (rs *Rows) Next() bool {
}
rs.lasterr = rs.rowsi.Next(rs.lastcols)
if rs.lasterr != nil {
+ // Close the connection if there is a driver error.
+ if rs.lasterr != io.EOF {
+ rs.Close()
+ return false
+ }
+ nextResultSet, ok := rs.rowsi.(driver.RowsNextResultSet)
+ if !ok {
+ rs.Close()
+ return false
+ }
+ // The driver is at the end of the current result set.
+ // Test to see if there is another result set after the current one.
+ // Only close Rows if there is no futher result sets to read.
+ if !nextResultSet.HasNextResultSet() {
+ rs.Close()
+ }
+ return false
+ }
+ return true
+}
+
+// NextResultSet prepares the next result set for reading. It returns true if
+// there is further result sets, or false if there is no further result set
+// or if there is an error advancing to it. The Err method should be consulted
+// to distinguish between the two cases.
+//
+// After calling NextResultSet, the Next method should always be called before
+// scanning. If there are further result sets they may not have rows in the result
+// set.
+func (rs *Rows) NextResultSet() bool {
+ if rs.isClosed() {
+ return false
+ }
+ rs.lastcols = nil
+ nextResultSet, ok := rs.rowsi.(driver.RowsNextResultSet)
+ if !ok {
+ rs.Close()
+ return false
+ }
+ rs.lasterr = nextResultSet.NextResultSet()
+ if rs.lasterr != nil {
rs.Close()
return false
}
@@ -1776,7 +2133,7 @@ func (rs *Rows) Err() error {
// Columns returns an error if the rows are closed, or if the rows
// are from QueryRow and there was a deferred error.
func (rs *Rows) Columns() ([]string, error) {
- if rs.closed {
+ if rs.isClosed() {
return nil, errors.New("sql: Rows are closed")
}
if rs.rowsi == nil {
@@ -1785,6 +2142,107 @@ func (rs *Rows) Columns() ([]string, error) {
return rs.rowsi.Columns(), nil
}
+// ColumnTypes returns column information such as column type, length,
+// and nullable. Some information may not be available from some drivers.
+func (rs *Rows) ColumnTypes() ([]*ColumnType, error) {
+ if rs.isClosed() {
+ return nil, errors.New("sql: Rows are closed")
+ }
+ if rs.rowsi == nil {
+ return nil, errors.New("sql: no Rows available")
+ }
+ return rowsColumnInfoSetup(rs.rowsi), nil
+}
+
+// ColumnType contains the name and type of a column.
+type ColumnType struct {
+ name string
+
+ hasNullable bool
+ hasLength bool
+ hasPrecisionScale bool
+
+ nullable bool
+ length int64
+ databaseType string
+ precision int64
+ scale int64
+ scanType reflect.Type
+}
+
+// Name returns the name or alias of the column.
+func (ci *ColumnType) Name() string {
+ return ci.name
+}
+
+// Length returns the column type length for variable length column types such
+// as text and binary field types. If the type length is unbounded the value will
+// be math.MaxInt64 (any database limits will still apply).
+// If the column type is not variable length, such as an int, or if not supported
+// by the driver ok is false.
+func (ci *ColumnType) Length() (length int64, ok bool) {
+ return ci.length, ci.hasLength
+}
+
+// DecimalSize returns the scale and precision of a decimal type.
+// If not applicable or if not supported ok is false.
+func (ci *ColumnType) DecimalSize() (precision, scale int64, ok bool) {
+ return ci.precision, ci.scale, ci.hasPrecisionScale
+}
+
+// ScanType returns a Go type suitable for scanning into using Rows.Scan.
+// If a driver does not support this property ScanType will return
+// the type of an empty interface.
+func (ci *ColumnType) ScanType() reflect.Type {
+ return ci.scanType
+}
+
+// Nullable returns whether the column may be null.
+// If a driver does not support this property ok will be false.
+func (ci *ColumnType) Nullable() (nullable, ok bool) {
+ return ci.nullable, ci.hasNullable
+}
+
+// DatabaseTypeName returns the database system name of the column type. If an empty
+// string is returned the driver type name is not supported.
+// Consult your driver documentation for a list of driver data types. Length specifiers
+// are not included.
+// Common type include "VARCHAR", "TEXT", "NVARCHAR", "DECIMAL", "BOOL", "INT", "BIGINT".
+func (ci *ColumnType) DatabaseTypeName() string {
+ return ci.databaseType
+}
+
+func rowsColumnInfoSetup(rowsi driver.Rows) []*ColumnType {
+ names := rowsi.Columns()
+
+ list := make([]*ColumnType, len(names))
+ for i := range list {
+ ci := &ColumnType{
+ name: names[i],
+ }
+ list[i] = ci
+
+ if prop, ok := rowsi.(driver.RowsColumnTypeScanType); ok {
+ ci.scanType = prop.ColumnTypeScanType(i)
+ } else {
+ ci.scanType = reflect.TypeOf(new(interface{})).Elem()
+ }
+ if prop, ok := rowsi.(driver.RowsColumnTypeDatabaseTypeName); ok {
+ ci.databaseType = prop.ColumnTypeDatabaseTypeName(i)
+ }
+ if prop, ok := rowsi.(driver.RowsColumnTypeLength); ok {
+ ci.length, ci.hasLength = prop.ColumnTypeLength(i)
+ }
+ if prop, ok := rowsi.(driver.RowsColumnTypeNullable); ok {
+ ci.nullable, ci.hasNullable = prop.ColumnTypeNullable(i)
+ }
+ if prop, ok := rowsi.(driver.RowsColumnTypePrecisionScale); ok {
+ ci.precision, ci.scale, ci.hasPrecisionScale = prop.ColumnTypePrecisionScale(i)
+ }
+ }
+ return list
+}
+
// Scan copies the columns in the current row into the values pointed
// at by dest. The number of values in dest must be the same as the
// number of columns in Rows.
@@ -1837,7 +2295,7 @@ func (rs *Rows) Columns() ([]string, error) {
// For scanning into *bool, the source may be true, false, 1, 0, or
// string inputs parseable by strconv.ParseBool.
func (rs *Rows) Scan(dest ...interface{}) error {
- if rs.closed {
+ if rs.isClosed() {
return errors.New("sql: Rows are closed")
}
if rs.lastcols == nil {
@@ -1857,14 +2315,21 @@ func (rs *Rows) Scan(dest ...interface{}) error {
var rowsCloseHook func(*Rows, *error)
-// Close closes the Rows, preventing further enumeration. If Next returns
-// false, the Rows are closed automatically and it will suffice to check the
+func (rs *Rows) isClosed() bool {
+ return atomic.LoadInt32(&rs.closed) != 0
+}
+
+// Close closes the Rows, preventing further enumeration. If Next is called
+// and returns false and there are no further result sets,
+// the Rows are closed automatically and it will suffice to check the
// result of Err. Close is idempotent and does not affect the result of Err.
func (rs *Rows) Close() error {
- if rs.closed {
+ if !atomic.CompareAndSwapInt32(&rs.closed, 0, 1) {
return nil
}
- rs.closed = true
+ if rs.ctxClose != nil {
+ close(rs.ctxClose)
+ }
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 08df0c7..27fb765 100644
--- a/src/database/sql/sql_test.go
+++ b/src/database/sql/sql_test.go
@@ -5,6 +5,7 @@
package sql
import (
+ "context"
"database/sql/driver"
"errors"
"fmt"
@@ -23,6 +24,17 @@ func init() {
c *driverConn
}
freedFrom := make(map[dbConn]string)
+ var mu sync.Mutex
+ getFreedFrom := func(c dbConn) string {
+ mu.Lock()
+ defer mu.Unlock()
+ return freedFrom[c]
+ }
+ setFreedFrom := func(c dbConn, s string) {
+ mu.Lock()
+ defer mu.Unlock()
+ freedFrom[c] = s
+ }
putConnHook = func(db *DB, c *driverConn) {
idx := -1
for i, v := range db.freeConn {
@@ -35,10 +47,10 @@ func init() {
// print before panic, as panic may get lost due to conflicting panic
// (all goroutines asleep) elsewhere, since we might not unlock
// the mutex in freeConn here.
- println("double free of conn. conflicts are:\nA) " + freedFrom[dbConn{db, c}] + "\n\nand\nB) " + stack())
+ println("double free of conn. conflicts are:\nA) " + getFreedFrom(dbConn{db, c}) + "\n\nand\nB) " + stack())
panic("double free of conn.")
}
- freedFrom[dbConn{db, c}] = stack()
+ setFreedFrom(dbConn{db, c}, stack())
}
}
@@ -140,10 +152,7 @@ func closeDB(t testing.TB, db *DB) {
if err != nil {
t.Fatalf("error closing DB: %v", err)
}
- db.mu.Lock()
- count := db.numOpen
- db.mu.Unlock()
- if count != 0 {
+ if count := db.numOpenConns(); count != 0 {
t.Fatalf("%d connections still open after closing DB", count)
}
}
@@ -182,6 +191,12 @@ func (db *DB) numFreeConns() int {
return len(db.freeConn)
}
+func (db *DB) numOpenConns() int {
+ db.mu.Lock()
+ defer db.mu.Unlock()
+ return db.numOpen
+}
+
// clearAllConns closes all connections in db.
func (db *DB) clearAllConns(t *testing.T) {
db.SetMaxIdleConns(0)
@@ -260,6 +275,257 @@ func TestQuery(t *testing.T) {
}
}
+func TestQueryContext(t *testing.T) {
+ db := newTestDB(t, "people")
+ defer closeDB(t, db)
+ prepares0 := numPrepares(t, db)
+
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+
+ rows, err := db.QueryContext(ctx, "SELECT|people|age,name|")
+ if err != nil {
+ t.Fatalf("Query: %v", err)
+ }
+ type row struct {
+ age int
+ name string
+ }
+ got := []row{}
+ index := 0
+ for rows.Next() {
+ if index == 2 {
+ cancel()
+ time.Sleep(10 * time.Millisecond)
+ }
+ var r row
+ err = rows.Scan(&r.age, &r.name)
+ if err != nil {
+ if index == 2 {
+ break
+ }
+ t.Fatalf("Scan: %v", err)
+ }
+ if index == 2 && err == nil {
+ t.Fatal("expected an error on last scan")
+ }
+ got = append(got, r)
+ index++
+ }
+ err = rows.Err()
+ if err != nil {
+ t.Fatalf("Err: %v", err)
+ }
+ want := []row{
+ {age: 1, name: "Alice"},
+ {age: 2, name: "Bob"},
+ }
+ if !reflect.DeepEqual(got, want) {
+ t.Errorf("mismatch.\n got: %#v\nwant: %#v", got, want)
+ }
+
+ // And verify that the final rows.Next() call, which hit EOF,
+ // also closed the rows connection.
+ if n := db.numFreeConns(); n != 1 {
+ t.Fatalf("free conns after query hitting EOF = %d; want 1", n)
+ }
+ if prepares := numPrepares(t, db) - prepares0; prepares != 1 {
+ t.Errorf("executed %d Prepare statements; want 1", prepares)
+ }
+}
+
+func waitCondition(waitFor, checkEvery time.Duration, fn func() bool) bool {
+ deadline := time.Now().Add(waitFor)
+ for time.Now().Before(deadline) {
+ if fn() {
+ return true
+ }
+ time.Sleep(checkEvery)
+ }
+ return false
+}
+
+func TestQueryContextWait(t *testing.T) {
+ db := newTestDB(t, "people")
+ defer closeDB(t, db)
+ prepares0 := numPrepares(t, db)
+
+ ctx, _ := context.WithTimeout(context.Background(), time.Millisecond*15)
+
+ // This will trigger the *fakeConn.Prepare method which will take time
+ // performing the query. The ctxDriverPrepare func will check the context
+ // after this and close the rows and return an error.
+ _, err := db.QueryContext(ctx, "WAIT|1s|SELECT|people|age,name|")
+ if err != context.DeadlineExceeded {
+ t.Fatalf("expected QueryContext to error with context deadline exceeded but returned %v", err)
+ }
+
+ // Verify closed rows connection after error condition.
+ if n := db.numFreeConns(); n != 1 {
+ t.Fatalf("free conns after query hitting EOF = %d; want 1", n)
+ }
+ if prepares := numPrepares(t, db) - prepares0; prepares != 1 {
+ t.Errorf("executed %d Prepare statements; want 1", prepares)
+ }
+}
+
+func TestTxContextWait(t *testing.T) {
+ db := newTestDB(t, "people")
+ defer closeDB(t, db)
+
+ ctx, _ := context.WithTimeout(context.Background(), time.Millisecond*15)
+
+ tx, err := db.BeginContext(ctx)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // This will trigger the *fakeConn.Prepare method which will take time
+ // performing the query. The ctxDriverPrepare func will check the context
+ // after this and close the rows and return an error.
+ _, err = tx.QueryContext(ctx, "WAIT|1s|SELECT|people|age,name|")
+ if err != context.DeadlineExceeded {
+ t.Fatalf("expected QueryContext to error with context deadline exceeded but returned %v", err)
+ }
+
+ var numFree int
+ if !waitCondition(5*time.Second, 5*time.Millisecond, func() bool {
+ numFree = db.numFreeConns()
+ return numFree == 0
+ }) {
+ t.Fatalf("free conns after hitting EOF = %d; want 0", numFree)
+ }
+
+ // Ensure the dropped connection allows more connections to be made.
+ // Checked on DB Close.
+ waitCondition(5*time.Second, 5*time.Millisecond, func() bool {
+ return db.numOpenConns() == 0
+ })
+}
+
+func TestMultiResultSetQuery(t *testing.T) {
+ db := newTestDB(t, "people")
+ defer closeDB(t, db)
+ prepares0 := numPrepares(t, db)
+ rows, err := db.Query("SELECT|people|age,name|;SELECT|people|name|")
+ if err != nil {
+ t.Fatalf("Query: %v", err)
+ }
+ type row1 struct {
+ age int
+ name string
+ }
+ type row2 struct {
+ name string
+ }
+ got1 := []row1{}
+ for rows.Next() {
+ var r row1
+ err = rows.Scan(&r.age, &r.name)
+ if err != nil {
+ t.Fatalf("Scan: %v", err)
+ }
+ got1 = append(got1, r)
+ }
+ err = rows.Err()
+ if err != nil {
+ t.Fatalf("Err: %v", err)
+ }
+ want1 := []row1{
+ {age: 1, name: "Alice"},
+ {age: 2, name: "Bob"},
+ {age: 3, name: "Chris"},
+ }
+ if !reflect.DeepEqual(got1, want1) {
+ t.Errorf("mismatch.\n got1: %#v\nwant: %#v", got1, want1)
+ }
+
+ if !rows.NextResultSet() {
+ t.Errorf("expected another result set")
+ }
+
+ got2 := []row2{}
+ for rows.Next() {
+ var r row2
+ err = rows.Scan(&r.name)
+ if err != nil {
+ t.Fatalf("Scan: %v", err)
+ }
+ got2 = append(got2, r)
+ }
+ err = rows.Err()
+ if err != nil {
+ t.Fatalf("Err: %v", err)
+ }
+ want2 := []row2{
+ {name: "Alice"},
+ {name: "Bob"},
+ {name: "Chris"},
+ }
+ if !reflect.DeepEqual(got2, want2) {
+ t.Errorf("mismatch.\n got: %#v\nwant: %#v", got2, want2)
+ }
+ if rows.NextResultSet() {
+ t.Errorf("expected no more result sets")
+ }
+
+ // And verify that the final rows.Next() call, which hit EOF,
+ // also closed the rows connection.
+ if n := db.numFreeConns(); n != 1 {
+ t.Fatalf("free conns after query hitting EOF = %d; want 1", n)
+ }
+ if prepares := numPrepares(t, db) - prepares0; prepares != 1 {
+ t.Errorf("executed %d Prepare statements; want 1", prepares)
+ }
+}
+
+func TestQueryNamedArg(t *testing.T) {
+ db := newTestDB(t, "people")
+ defer closeDB(t, db)
+ prepares0 := numPrepares(t, db)
+ rows, err := db.Query(
+ // Ensure the name and age parameters only match on placeholder name, not position.
+ "SELECT|people|age,name|name=?name,age=?age",
+ Named("?age", 2),
+ Named("?name", "Bob"),
+ )
+ if err != nil {
+ t.Fatalf("Query: %v", err)
+ }
+ type row struct {
+ age int
+ name string
+ }
+ got := []row{}
+ for rows.Next() {
+ var r row
+ err = rows.Scan(&r.age, &r.name)
+ if err != nil {
+ t.Fatalf("Scan: %v", err)
+ }
+ got = append(got, r)
+ }
+ err = rows.Err()
+ if err != nil {
+ t.Fatalf("Err: %v", err)
+ }
+ want := []row{
+ {age: 2, name: "Bob"},
+ }
+ if !reflect.DeepEqual(got, want) {
+ t.Errorf("mismatch.\n got: %#v\nwant: %#v", got, want)
+ }
+
+ // And verify that the final rows.Next() call, which hit EOF,
+ // also closed the rows connection.
+ if n := db.numFreeConns(); n != 1 {
+ t.Fatalf("free conns after query hitting EOF = %d; want 1", n)
+ }
+ if prepares := numPrepares(t, db) - prepares0; prepares != 1 {
+ t.Errorf("executed %d Prepare statements; want 1", prepares)
+ }
+}
+
func TestByteOwnership(t *testing.T) {
db := newTestDB(t, "people")
defer closeDB(t, db)
@@ -317,6 +583,56 @@ func TestRowsColumns(t *testing.T) {
}
}
+func TestRowsColumnTypes(t *testing.T) {
+ db := newTestDB(t, "people")
+ defer closeDB(t, db)
+ rows, err := db.Query("SELECT|people|age,name|")
+ if err != nil {
+ t.Fatalf("Query: %v", err)
+ }
+ tt, err := rows.ColumnTypes()
+ if err != nil {
+ t.Fatalf("ColumnTypes: %v", err)
+ }
+
+ types := make([]reflect.Type, len(tt))
+ for i, tp := range tt {
+ st := tp.ScanType()
+ if st == nil {
+ t.Errorf("scantype is null for column %q", tp.Name())
+ continue
+ }
+ types[i] = st
+ }
+ values := make([]interface{}, len(tt))
+ for i := range values {
+ values[i] = reflect.New(types[i]).Interface()
+ }
+ ct := 0
+ for rows.Next() {
+ err = rows.Scan(values...)
+ if err != nil {
+ t.Fatalf("failed to scan values in %v", err)
+ }
+ ct++
+ if ct == 0 {
+ if values[0].(string) != "Bob" {
+ t.Errorf("Expected Bob, got %v", values[0])
+ }
+ if values[1].(int) != 2 {
+ t.Errorf("Expected 2, got %v", values[1])
+ }
+ }
+ }
+ if ct != 3 {
+ t.Errorf("expected 3 rows, got %d", ct)
+ }
+
+ if err := rows.Close(); err != nil {
+ t.Errorf("error closing rows: %s", err)
+ }
+}
+
func TestQueryRow(t *testing.T) {
db := newTestDB(t, "people")
defer closeDB(t, db)
@@ -439,7 +755,7 @@ func TestStatementClose(t *testing.T) {
msg string
}{
{&Stmt{stickyErr: want}, "stickyErr not propagated"},
- {&Stmt{tx: &Tx{}, txsi: &driverStmt{&sync.Mutex{}, stubDriverStmt{want}}}, "driverStmt.Close() error not propagated"},
+ {&Stmt{tx: &Tx{}, txds: &driverStmt{Locker: &sync.Mutex{}, si: stubDriverStmt{want}}}, "driverStmt.Close() error not propagated"},
}
for _, test := range tests {
if err := test.stmt.Close(); err != want {
@@ -513,8 +829,8 @@ func TestExec(t *testing.T) {
{[]interface{}{7, 9}, ""},
// Invalid conversions:
- {[]interface{}{"Brad", int64(0xFFFFFFFF)}, "sql: converting argument #1's type: sql/driver: value 4294967295 overflows int32"},
- {[]interface{}{"Brad", "strconv fail"}, "sql: converting argument #1's type: sql/driver: value \"strconv fail\" can't be converted to int32"},
+ {[]interface{}{"Brad", int64(0xFFFFFFFF)}, "sql: converting argument $2 type: sql/driver: value 4294967295 overflows int32"},
+ {[]interface{}{"Brad", "strconv fail"}, `sql: converting argument $2 type: sql/driver: value "strconv fail" can't be converted to int32`},
// Wrong number of args:
{[]interface{}{}, "sql: expected 2 arguments, got 0"},
@@ -1159,17 +1475,19 @@ func TestMaxOpenConnsOnBusy(t *testing.T) {
db.SetMaxOpenConns(3)
- conn0, err := db.conn(cachedOrNewConn)
+ ctx := context.Background()
+
+ conn0, err := db.conn(ctx, cachedOrNewConn)
if err != nil {
t.Fatalf("db open conn fail: %v", err)
}
- conn1, err := db.conn(cachedOrNewConn)
+ conn1, err := db.conn(ctx, cachedOrNewConn)
if err != nil {
t.Fatalf("db open conn fail: %v", err)
}
- conn2, err := db.conn(cachedOrNewConn)
+ conn2, err := db.conn(ctx, cachedOrNewConn)
if err != nil {
t.Fatalf("db open conn fail: %v", err)
}
@@ -1203,7 +1521,11 @@ func TestPendingConnsAfterErr(t *testing.T) {
tryOpen = maxOpen*2 + 2
)
- db := newTestDB(t, "people")
+ // No queries will be run.
+ db, err := Open("test", fakeDBName)
+ if err != nil {
+ t.Fatalf("Open: %v", err)
+ }
defer closeDB(t, db)
defer func() {
for k, v := range db.lastPut {
@@ -1215,29 +1537,29 @@ func TestPendingConnsAfterErr(t *testing.T) {
db.SetMaxIdleConns(0)
errOffline := errors.New("db offline")
+
defer func() { setHookOpenErr(nil) }()
errs := make(chan error, tryOpen)
- unblock := make(chan struct{})
+ var opening sync.WaitGroup
+ opening.Add(tryOpen)
+
setHookOpenErr(func() error {
- <-unblock // block until all connections are in flight
+ // Wait for all connections to enqueue.
+ opening.Wait()
return errOffline
})
- var opening sync.WaitGroup
- opening.Add(tryOpen)
for i := 0; i < tryOpen; i++ {
go func() {
opening.Done() // signal one connection is in flight
- _, err := db.Exec("INSERT|people|name=Julia,age=19")
+ _, err := db.Exec("will never run")
errs <- err
}()
}
- opening.Wait() // wait for all workers to begin running
- time.Sleep(10 * time.Millisecond) // make extra sure all workers are blocked
- close(unblock) // let all workers proceed
+ opening.Wait() // wait for all workers to begin running
const timeout = 5 * time.Second
to := time.NewTimer(timeout)
@@ -1254,6 +1576,24 @@ func TestPendingConnsAfterErr(t *testing.T) {
t.Fatalf("orphaned connection request(s), still waiting after %v", timeout)
}
}
+
+ // Wait a reasonable time for the database to close all connections.
+ tick := time.NewTicker(3 * time.Millisecond)
+ defer tick.Stop()
+ for {
+ select {
+ case <-tick.C:
+ db.mu.Lock()
+ if db.numOpen == 0 {
+ db.mu.Unlock()
+ return
+ }
+ db.mu.Unlock()
+ case <-to.C:
+ // Closing the database will check for numOpen and fail the test.
+ return
+ }
+ }
}
func TestSingleOpenConn(t *testing.T) {
@@ -2279,7 +2619,8 @@ func TestConnectionLeak(t *testing.T) {
go func() {
r, err := db.Query("SELECT|people|name|")
if err != nil {
- t.Fatal(err)
+ t.Error(err)
+ return
}
r.Close()
wg.Done()
@@ -2299,6 +2640,97 @@ func TestConnectionLeak(t *testing.T) {
wg.Wait()
}
+// badConn implements a bad driver.Conn, for TestBadDriver.
+// The Exec method panics.
+type badConn struct{}
+
+func (bc badConn) Prepare(query string) (driver.Stmt, error) {
+ return nil, errors.New("badConn Prepare")
+}
+
+func (bc badConn) Close() error {
+ return nil
+}
+
+func (bc badConn) Begin() (driver.Tx, error) {
+ return nil, errors.New("badConn Begin")
+}
+
+func (bc badConn) Exec(query string, args []driver.Value) (driver.Result, error) {
+ panic("badConn.Exec")
+}
+
+// badDriver is a driver.Driver that uses badConn.
+type badDriver struct{}
+
+func (bd badDriver) Open(name string) (driver.Conn, error) {
+ return badConn{}, nil
+}
+
+// Issue 15901.
+func TestBadDriver(t *testing.T) {
+ Register("bad", badDriver{})
+ db, err := Open("bad", "ignored")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer func() {
+ if r := recover(); r == nil {
+ t.Error("expected panic")
+ } else {
+ if want := "badConn.Exec"; r.(string) != want {
+ t.Errorf("panic was %v, expected %v", r, want)
+ }
+ }
+ }()
+ defer db.Close()
+ db.Exec("ignored")
+}
+
+type pingDriver struct {
+ fails bool
+}
+
+type pingConn struct {
+ badConn
+ driver *pingDriver
+}
+
+var pingError = errors.New("Ping failed")
+
+func (pc pingConn) Ping(ctx context.Context) error {
+ if pc.driver.fails {
+ return pingError
+ }
+ return nil
+}
+
+var _ driver.Pinger = pingConn{}
+
+func (pd *pingDriver) Open(name string) (driver.Conn, error) {
+ return pingConn{driver: pd}, nil
+}
+
+func TestPing(t *testing.T) {
+ driver := &pingDriver{}
+ Register("ping", driver)
+
+ db, err := Open("ping", "ignored")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if err := db.Ping(); err != nil {
+ t.Errorf("err was %#v, expected nil", err)
+ return
+ }
+
+ driver.fails = true
+ if err := db.Ping(); err != pingError {
+ t.Errorf("err was %#v, expected pingError", err)
+ }
+}
+
func BenchmarkConcurrentDBExec(b *testing.B) {
b.ReportAllocs()
ct := new(concurrentDBExecTest)
diff --git a/src/debug/elf/file.go b/src/debug/elf/file.go
index c173ea9..8eeab65 100644
--- a/src/debug/elf/file.go
+++ b/src/debug/elf/file.go
@@ -579,7 +579,7 @@ func (f *File) Section(name string) *Section {
}
// applyRelocations applies relocations to dst. rels is a relocations section
-// in RELA format.
+// in REL or RELA format.
func (f *File) applyRelocations(dst []byte, rels []byte) error {
switch {
case f.Class == ELFCLASS64 && f.Machine == EM_X86_64:
@@ -594,10 +594,14 @@ func (f *File) applyRelocations(dst []byte, rels []byte) error {
return f.applyRelocationsPPC(dst, rels)
case f.Class == ELFCLASS64 && f.Machine == EM_PPC64:
return f.applyRelocationsPPC64(dst, rels)
+ case f.Class == ELFCLASS32 && f.Machine == EM_MIPS:
+ return f.applyRelocationsMIPS(dst, rels)
case f.Class == ELFCLASS64 && f.Machine == EM_MIPS:
return f.applyRelocationsMIPS64(dst, rels)
case f.Class == ELFCLASS64 && f.Machine == EM_S390:
return f.applyRelocationss390x(dst, rels)
+ case f.Class == ELFCLASS64 && f.Machine == EM_SPARCV9:
+ return f.applyRelocationsSPARC64(dst, rels)
default:
return errors.New("applyRelocations: not implemented")
}
@@ -861,6 +865,44 @@ func (f *File) applyRelocationsPPC64(dst []byte, rels []byte) error {
return nil
}
+func (f *File) applyRelocationsMIPS(dst []byte, rels []byte) error {
+ // 8 is the size of Rel32.
+ if len(rels)%8 != 0 {
+ return errors.New("length of relocation section is not a multiple of 8")
+ }
+
+ symbols, _, err := f.getSymbols(SHT_SYMTAB)
+ if err != nil {
+ return err
+ }
+
+ b := bytes.NewReader(rels)
+ var rel Rel32
+
+ for b.Len() > 0 {
+ binary.Read(b, f.ByteOrder, &rel)
+ symNo := rel.Info >> 8
+ t := R_MIPS(rel.Info & 0xff)
+
+ if symNo == 0 || symNo > uint32(len(symbols)) {
+ continue
+ }
+ sym := &symbols[symNo-1]
+
+ switch t {
+ case R_MIPS_32:
+ if rel.Off+4 >= uint32(len(dst)) {
+ continue
+ }
+ val := f.ByteOrder.Uint32(dst[rel.Off : rel.Off+4])
+ val += uint32(sym.Value)
+ f.ByteOrder.PutUint32(dst[rel.Off:rel.Off+4], val)
+ }
+ }
+
+ return nil
+}
+
func (f *File) applyRelocationsMIPS64(dst []byte, rels []byte) error {
// 24 is the size of Rela64.
if len(rels)%24 != 0 {
@@ -962,6 +1004,51 @@ func (f *File) applyRelocationss390x(dst []byte, rels []byte) error {
return nil
}
+func (f *File) applyRelocationsSPARC64(dst []byte, rels []byte) error {
+ // 24 is the size of Rela64.
+ if len(rels)%24 != 0 {
+ return errors.New("length of relocation section is not a multiple of 24")
+ }
+
+ symbols, _, err := f.getSymbols(SHT_SYMTAB)
+ if err != nil {
+ return err
+ }
+
+ b := bytes.NewReader(rels)
+ var rela Rela64
+
+ for b.Len() > 0 {
+ binary.Read(b, f.ByteOrder, &rela)
+ symNo := rela.Info >> 32
+ t := R_SPARC(rela.Info & 0xff)
+
+ if symNo == 0 || symNo > uint64(len(symbols)) {
+ continue
+ }
+ sym := &symbols[symNo-1]
+ if SymType(sym.Info&0xf) != STT_SECTION {
+ // We don't handle non-section relocations for now.
+ continue
+ }
+
+ switch t {
+ case R_SPARC_64, R_SPARC_UA64:
+ if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
+ continue
+ }
+ f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], uint64(rela.Addend))
+ case R_SPARC_32, R_SPARC_UA32:
+ if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 {
+ continue
+ }
+ f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], uint32(rela.Addend))
+ }
+ }
+
+ return nil
+}
+
func (f *File) DWARF() (*dwarf.Data, error) {
// sectionData gets the data for s, checks its size, and
// applies any applicable relations.
diff --git a/src/debug/elf/file_test.go b/src/debug/elf/file_test.go
index b189219..58bdf27 100644
--- a/src/debug/elf/file_test.go
+++ b/src/debug/elf/file_test.go
@@ -492,6 +492,63 @@ var relocationTests = []relocationTest{
},
},
{
+ "testdata/go-relocation-test-gcc620-sparc64.obj",
+ []relocationTestEntry{
+ {0, &dwarf.Entry{
+ Offset: 0xb,
+ Tag: dwarf.TagCompileUnit,
+ Children: true,
+ Field: []dwarf.Field{
+ {Attr: dwarf.AttrProducer, Val: "GNU C11 6.2.0 20160914 -mcpu=v9 -g -fstack-protector-strong", Class: dwarf.ClassString},
+ {Attr: dwarf.AttrLanguage, Val: int64(12), Class: dwarf.ClassConstant},
+ {Attr: dwarf.AttrName, Val: "hello.c", Class: dwarf.ClassString},
+ {Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString},
+ {Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress},
+ {Attr: dwarf.AttrHighpc, Val: int64(0x2c), Class: dwarf.ClassConstant},
+ {Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr},
+ },
+ }},
+ },
+ },
+ {
+ "testdata/go-relocation-test-gcc492-mipsle.obj",
+ []relocationTestEntry{
+ {0, &dwarf.Entry{
+ Offset: 0xb,
+ Tag: dwarf.TagCompileUnit,
+ Children: true,
+ Field: []dwarf.Field{
+ {Attr: dwarf.AttrProducer, Val: "GNU C 4.9.2 -mel -march=mips2 -mtune=mips32 -mllsc -mno-shared -mabi=32 -g", Class: dwarf.ClassString},
+ {Attr: dwarf.AttrLanguage, Val: int64(1), Class: dwarf.ClassConstant},
+ {Attr: dwarf.AttrName, Val: "hello.c", Class: dwarf.ClassString},
+ {Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString},
+ {Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress},
+ {Attr: dwarf.AttrHighpc, Val: int64(0x58), Class: dwarf.ClassConstant},
+ {Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr},
+ },
+ }},
+ },
+ },
+ {
+ "testdata/go-relocation-test-gcc540-mips.obj",
+ []relocationTestEntry{
+ {0, &dwarf.Entry{
+ Offset: 0xb,
+ Tag: dwarf.TagCompileUnit,
+ Children: true,
+ Field: []dwarf.Field{
+ {Attr: dwarf.AttrProducer, Val: "GNU C11 5.4.0 20160609 -meb -mips32 -mtune=mips32r2 -mfpxx -mllsc -mno-shared -mabi=32 -g -gdwarf-2", Class: dwarf.ClassString},
+ {Attr: dwarf.AttrLanguage, Val: int64(12), Class: dwarf.ClassConstant},
+ {Attr: dwarf.AttrName, Val: "hello.c", Class: dwarf.ClassString},
+ {Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString},
+ {Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress},
+ {Attr: dwarf.AttrHighpc, Val: uint64(0x5c), Class: dwarf.ClassAddress},
+ {Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr},
+ },
+ }},
+ },
+ },
+ {
"testdata/go-relocation-test-gcc493-mips64le.obj",
[]relocationTestEntry{
{0, &dwarf.Entry{
diff --git a/src/debug/elf/testdata/go-relocation-test-gcc492-mipsle.obj b/src/debug/elf/testdata/go-relocation-test-gcc492-mipsle.obj
new file mode 100644
index 0000000..a5fbcfb
Binary files /dev/null and b/src/debug/elf/testdata/go-relocation-test-gcc492-mipsle.obj differ
diff --git a/src/debug/elf/testdata/go-relocation-test-gcc540-mips.obj b/src/debug/elf/testdata/go-relocation-test-gcc540-mips.obj
new file mode 100644
index 0000000..270c777
Binary files /dev/null and b/src/debug/elf/testdata/go-relocation-test-gcc540-mips.obj differ
diff --git a/src/debug/elf/testdata/go-relocation-test-gcc620-sparc64.obj b/src/debug/elf/testdata/go-relocation-test-gcc620-sparc64.obj
new file mode 100644
index 0000000..d65c23e
Binary files /dev/null and b/src/debug/elf/testdata/go-relocation-test-gcc620-sparc64.obj differ
diff --git a/src/debug/gosym/pclntab.go b/src/debug/gosym/pclntab.go
index e859d5a..e94ed19 100644
--- a/src/debug/gosym/pclntab.go
+++ b/src/debug/gosym/pclntab.go
@@ -291,13 +291,17 @@ func (t *LineTable) step(p *[]byte, pc *uint64, val *int32, first bool) bool {
return true
}
+// PCValue looks up the given PC in a pc value table. target is the
+// offset of the pc from the entry point.
+func PCValue(tab []byte, target uint64, quantum int) int {
+ t := LineTable{Data: tab, quantum: uint32(quantum)}
+ return int(t.pcvalue(0, 0, target))
+}
+
// pcvalue reports the value associated with the target pc.
// off is the offset to the beginning of the pc-value table,
// and entry is the start PC for the corresponding function.
func (t *LineTable) pcvalue(off uint32, entry, targetpc uint64) int32 {
- if off == 0 {
- return -1
- }
p := t.Data[off:]
val := int32(-1)
diff --git a/src/debug/gosym/pclntab_test.go b/src/debug/gosym/pclntab_test.go
index 9f82e31..7e7cee6 100644
--- a/src/debug/gosym/pclntab_test.go
+++ b/src/debug/gosym/pclntab_test.go
@@ -37,7 +37,7 @@ func dotest(t *testing.T) {
// the resulting binary looks like it was built from pclinetest.s,
// but we have renamed it to keep it away from the go tool.
pclinetestBinary = filepath.Join(pclineTempDir, "pclinetest")
- cmd := exec.Command("go", "tool", "asm", "-o", pclinetestBinary+".o", "pclinetest.asm")
+ cmd := exec.Command(testenv.GoToolPath(t), "tool", "asm", "-o", pclinetestBinary+".o", "pclinetest.asm")
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
if err := cmd.Run(); err != nil {
@@ -58,7 +58,7 @@ func dotest(t *testing.T) {
t.Fatal(err)
}
- cmd = exec.Command("go", "tool", "link", "-H", "linux",
+ cmd = exec.Command(testenv.GoToolPath(t), "tool", "link", "-H", "linux",
"-o", pclinetestBinary, pclinetestBinary+".o")
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
diff --git a/src/debug/macho/macho.go b/src/debug/macho/macho.go
index 3164753..40ac74e 100644
--- a/src/debug/macho/macho.go
+++ b/src/debug/macho/macho.go
@@ -145,7 +145,7 @@ type Section32 struct {
Reserve2 uint32
}
-// A Section32 is a 64-bit Mach-O section header.
+// A Section64 is a 64-bit Mach-O section header.
type Section64 struct {
Name [16]byte
Seg [16]byte
diff --git a/src/debug/pe/file.go b/src/debug/pe/file.go
index 3074ba0..87f225c 100644
--- a/src/debug/pe/file.go
+++ b/src/debug/pe/file.go
@@ -13,14 +13,17 @@ import (
"os"
)
+// Avoid use of post-Go 1.4 io features, to make safe for toolchain bootstrap.
+const seekStart = 0
+
// A File represents an open PE file.
type File struct {
FileHeader
OptionalHeader interface{} // of type *OptionalHeader32 or *OptionalHeader64
Sections []*Section
Symbols []*Symbol // COFF symbols with auxiliary symbol records removed
- _COFFSymbols []COFFSymbol // all COFF symbols (including auxiliary symbol records)
- _StringTable _StringTable
+ COFFSymbols []COFFSymbol // all COFF symbols (including auxiliary symbol records)
+ StringTable StringTable
closer io.Closer
}
@@ -80,7 +83,7 @@ func NewFile(r io.ReaderAt) (*File, error) {
} else {
base = int64(0)
}
- sr.Seek(base, io.SeekStart)
+ sr.Seek(base, seekStart)
if err := binary.Read(sr, binary.LittleEndian, &f.FileHeader); err != nil {
return nil, err
}
@@ -93,23 +96,23 @@ func NewFile(r io.ReaderAt) (*File, error) {
var err error
// Read string table.
- f._StringTable, err = readStringTable(&f.FileHeader, sr)
+ f.StringTable, err = readStringTable(&f.FileHeader, sr)
if err != nil {
return nil, err
}
// Read symbol table.
- f._COFFSymbols, err = readCOFFSymbols(&f.FileHeader, sr)
+ f.COFFSymbols, err = readCOFFSymbols(&f.FileHeader, sr)
if err != nil {
return nil, err
}
- f.Symbols, err = removeAuxSymbols(f._COFFSymbols, f._StringTable)
+ f.Symbols, err = removeAuxSymbols(f.COFFSymbols, f.StringTable)
if err != nil {
return nil, err
}
// Read optional header.
- sr.Seek(base, io.SeekStart)
+ sr.Seek(base, seekStart)
if err := binary.Read(sr, binary.LittleEndian, &f.FileHeader); err != nil {
return nil, err
}
@@ -141,7 +144,7 @@ func NewFile(r io.ReaderAt) (*File, error) {
if err := binary.Read(sr, binary.LittleEndian, sh); err != nil {
return nil, err
}
- name, err := sh.fullName(f._StringTable)
+ name, err := sh.fullName(f.StringTable)
if err != nil {
return nil, err
}
@@ -168,7 +171,7 @@ func NewFile(r io.ReaderAt) (*File, error) {
}
for i := range f.Sections {
var err error
- f.Sections[i]._Relocs, err = readRelocs(&f.Sections[i].SectionHeader, sr)
+ f.Sections[i].Relocs, err = readRelocs(&f.Sections[i].SectionHeader, sr)
if err != nil {
return nil, err
}
diff --git a/src/debug/pe/file_test.go b/src/debug/pe/file_test.go
index 964caf5..5a740c8 100644
--- a/src/debug/pe/file_test.go
+++ b/src/debug/pe/file_test.go
@@ -307,7 +307,7 @@ func main() {
src := filepath.Join(tmpdir, "a.go")
exe := filepath.Join(tmpdir, "a.exe")
err = ioutil.WriteFile(src, []byte(prog), 0644)
- output, err := exec.Command("go", "build", "-o", exe, src).CombinedOutput()
+ output, err := exec.Command(testenv.GoToolPath(t), "build", "-o", exe, src).CombinedOutput()
if err != nil {
t.Fatalf("building test executable failed: %s %s", err, output)
}
diff --git a/src/debug/pe/section.go b/src/debug/pe/section.go
index 8e6690f..b641158 100644
--- a/src/debug/pe/section.go
+++ b/src/debug/pe/section.go
@@ -28,7 +28,7 @@ type SectionHeader32 struct {
// fullName finds real name of section sh. Normally name is stored
// in sh.Name, but if it is longer then 8 characters, it is stored
// in COFF string table st instead.
-func (sh *SectionHeader32) fullName(st _StringTable) (string, error) {
+func (sh *SectionHeader32) fullName(st StringTable) (string, error) {
if sh.Name[0] != '/' {
return cstring(sh.Name[:]), nil
}
@@ -41,23 +41,23 @@ func (sh *SectionHeader32) fullName(st _StringTable) (string, error) {
// TODO(brainman): copy all IMAGE_REL_* consts from ldpe.go here
-// _Reloc represents a PE COFF relocation.
+// Reloc represents a PE COFF relocation.
// Each section contains its own relocation list.
-type _Reloc struct {
+type Reloc struct {
VirtualAddress uint32
SymbolTableIndex uint32
Type uint16
}
-func readRelocs(sh *SectionHeader, r io.ReadSeeker) ([]_Reloc, error) {
+func readRelocs(sh *SectionHeader, r io.ReadSeeker) ([]Reloc, error) {
if sh.NumberOfRelocations <= 0 {
return nil, nil
}
- _, err := r.Seek(int64(sh.PointerToRelocations), io.SeekStart)
+ _, err := r.Seek(int64(sh.PointerToRelocations), seekStart)
if err != nil {
return nil, fmt.Errorf("fail to seek to %q section relocations: %v", sh.Name, err)
}
- relocs := make([]_Reloc, sh.NumberOfRelocations)
+ relocs := make([]Reloc, sh.NumberOfRelocations)
err = binary.Read(r, binary.LittleEndian, relocs)
if err != nil {
return nil, fmt.Errorf("fail to read section relocations: %v", err)
@@ -83,7 +83,7 @@ type SectionHeader struct {
// Section provides access to PE COFF section.
type Section struct {
SectionHeader
- _Relocs []_Reloc
+ Relocs []Reloc
// Embed ReaderAt for ReadAt method.
// Do not embed SectionReader directly
diff --git a/src/debug/pe/string.go b/src/debug/pe/string.go
index 69837f6..c30255f 100644
--- a/src/debug/pe/string.go
+++ b/src/debug/pe/string.go
@@ -1,4 +1,4 @@
-// Copyright 2016 The Go Authors. All rights reserved.
+// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
@@ -19,16 +19,16 @@ func cstring(b []byte) string {
return string(b[:i])
}
-// _StringTable is a COFF string table.
-type _StringTable []byte
+// StringTable is a COFF string table.
+type StringTable []byte
-func readStringTable(fh *FileHeader, r io.ReadSeeker) (_StringTable, error) {
+func readStringTable(fh *FileHeader, r io.ReadSeeker) (StringTable, error) {
// COFF string table is located right after COFF symbol table.
if fh.PointerToSymbolTable <= 0 {
return nil, nil
}
offset := fh.PointerToSymbolTable + COFFSymbolSize*fh.NumberOfSymbols
- _, err := r.Seek(int64(offset), io.SeekStart)
+ _, err := r.Seek(int64(offset), seekStart)
if err != nil {
return nil, fmt.Errorf("fail to seek to string table: %v", err)
}
@@ -47,13 +47,13 @@ func readStringTable(fh *FileHeader, r io.ReadSeeker) (_StringTable, error) {
if err != nil {
return nil, fmt.Errorf("fail to read string table: %v", err)
}
- return _StringTable(buf), nil
+ return StringTable(buf), nil
}
// TODO(brainman): decide if start parameter should be int instead of uint32
// String extracts string from COFF string table st at offset start.
-func (st _StringTable) String(start uint32) (string, error) {
+func (st StringTable) String(start uint32) (string, error) {
// start includes 4 bytes of string table length
if start < 4 {
return "", fmt.Errorf("offset %d is before the start of string table", start)
diff --git a/src/debug/pe/symbol.go b/src/debug/pe/symbol.go
index 7b8cbf2..7fa5948 100644
--- a/src/debug/pe/symbol.go
+++ b/src/debug/pe/symbol.go
@@ -23,10 +23,13 @@ type COFFSymbol struct {
}
func readCOFFSymbols(fh *FileHeader, r io.ReadSeeker) ([]COFFSymbol, error) {
+ if fh.PointerToSymbolTable == 0 {
+ return nil, nil
+ }
if fh.NumberOfSymbols <= 0 {
return nil, nil
}
- _, err := r.Seek(int64(fh.PointerToSymbolTable), io.SeekStart)
+ _, err := r.Seek(int64(fh.PointerToSymbolTable), seekStart)
if err != nil {
return nil, fmt.Errorf("fail to seek to symbol table: %v", err)
}
@@ -46,17 +49,17 @@ func isSymNameOffset(name [8]byte) (bool, uint32) {
return false, 0
}
-// _FullName finds real name of symbol sym. Normally name is stored
+// FullName finds real name of symbol sym. Normally name is stored
// in sym.Name, but if it is longer then 8 characters, it is stored
// in COFF string table st instead.
-func (sym *COFFSymbol) _FullName(st _StringTable) (string, error) {
+func (sym *COFFSymbol) FullName(st StringTable) (string, error) {
if ok, offset := isSymNameOffset(sym.Name); ok {
return st.String(offset)
}
return cstring(sym.Name[:]), nil
}
-func removeAuxSymbols(allsyms []COFFSymbol, st _StringTable) ([]*Symbol, error) {
+func removeAuxSymbols(allsyms []COFFSymbol, st StringTable) ([]*Symbol, error) {
if len(allsyms) == 0 {
return nil, nil
}
@@ -67,7 +70,7 @@ func removeAuxSymbols(allsyms []COFFSymbol, st _StringTable) ([]*Symbol, error)
aux--
continue
}
- name, err := sym._FullName(st)
+ name, err := sym.FullName(st)
if err != nil {
return nil, err
}
diff --git a/src/encoding/asn1/asn1.go b/src/encoding/asn1/asn1.go
index 2b5ad08..044f74a 100644
--- a/src/encoding/asn1/asn1.go
+++ b/src/encoding/asn1/asn1.go
@@ -841,6 +841,13 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam
case reflect.Struct:
structType := fieldType
+ for i := 0; i < structType.NumField(); i++ {
+ if structType.Field(i).PkgPath != "" {
+ err = StructuralError{"struct contains unexported fields"}
+ return
+ }
+ }
+
if structType.NumField() > 0 &&
structType.Field(0).Type == rawContentsType {
bytes := bytes[initOffset:offset]
@@ -969,7 +976,7 @@ 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
+// 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
diff --git a/src/encoding/asn1/asn1_test.go b/src/encoding/asn1/asn1_test.go
index f8623fa..9976656 100644
--- a/src/encoding/asn1/asn1_test.go
+++ b/src/encoding/asn1/asn1_test.go
@@ -132,9 +132,13 @@ func TestParseBigInt(t *testing.T) {
if ret.String() != test.base10 {
t.Errorf("#%d: bad result from %x, got %s want %s", i, test.in, ret.String(), test.base10)
}
- fw := newForkableWriter()
- marshalBigInt(fw, ret)
- result := fw.Bytes()
+ e, err := makeBigInt(ret)
+ if err != nil {
+ t.Errorf("%d: err=%q", i, err)
+ continue
+ }
+ result := make([]byte, e.Len())
+ e.Encode(result)
if !bytes.Equal(result, test.in) {
t.Errorf("#%d: got %x from marshaling %s, want %x", i, result, ret, test.in)
}
@@ -963,7 +967,7 @@ func TestUnmarshalInvalidUTF8(t *testing.T) {
func TestMarshalNilValue(t *testing.T) {
nilValueTestData := []interface{}{
nil,
- struct{ v interface{} }{},
+ struct{ V interface{} }{},
}
for i, test := range nilValueTestData {
if _, err := Marshal(test); err == nil {
@@ -971,3 +975,32 @@ func TestMarshalNilValue(t *testing.T) {
}
}
}
+
+type unexported struct {
+ X int
+ y int
+}
+
+type exported struct {
+ X int
+ Y int
+}
+
+func TestUnexportedStructField(t *testing.T) {
+ want := StructuralError{"struct contains unexported fields"}
+
+ _, err := Marshal(unexported{X: 5, y: 1})
+ if err != want {
+ t.Errorf("got %v, want %v", err, want)
+ }
+
+ bs, err := Marshal(exported{X: 5, Y: 1})
+ if err != nil {
+ t.Fatal(err)
+ }
+ var u unexported
+ _, err = Unmarshal(bs, &u)
+ if err != want {
+ t.Errorf("got %v, want %v", err, want)
+ }
+}
diff --git a/src/encoding/asn1/marshal.go b/src/encoding/asn1/marshal.go
index 30797ef..76d0b0c 100644
--- a/src/encoding/asn1/marshal.go
+++ b/src/encoding/asn1/marshal.go
@@ -5,77 +5,125 @@
package asn1
import (
- "bytes"
"errors"
"fmt"
- "io"
"math/big"
"reflect"
"time"
"unicode/utf8"
)
-// A forkableWriter is an in-memory buffer that can be
-// 'forked' to create new forkableWriters that bracket the
-// original. After
-// pre, post := w.fork()
-// the overall sequence of bytes represented is logically w+pre+post.
-type forkableWriter struct {
- *bytes.Buffer
- pre, post *forkableWriter
+var (
+ byte00Encoder encoder = byteEncoder(0x00)
+ byteFFEncoder encoder = byteEncoder(0xff)
+)
+
+// encoder represents a ASN.1 element that is waiting to be marshaled.
+type encoder interface {
+ // Len returns the number of bytes needed to marshal this element.
+ Len() int
+ // Encode encodes this element by writing Len() bytes to dst.
+ Encode(dst []byte)
+}
+
+type byteEncoder byte
+
+func (c byteEncoder) Len() int {
+ return 1
}
-func newForkableWriter() *forkableWriter {
- return &forkableWriter{new(bytes.Buffer), nil, nil}
+func (c byteEncoder) Encode(dst []byte) {
+ dst[0] = byte(c)
}
-func (f *forkableWriter) fork() (pre, post *forkableWriter) {
- if f.pre != nil || f.post != nil {
- panic("have already forked")
+type bytesEncoder []byte
+
+func (b bytesEncoder) Len() int {
+ return len(b)
+}
+
+func (b bytesEncoder) Encode(dst []byte) {
+ if copy(dst, b) != len(b) {
+ panic("internal error")
}
- f.pre = newForkableWriter()
- f.post = newForkableWriter()
- return f.pre, f.post
}
-func (f *forkableWriter) Len() (l int) {
- l += f.Buffer.Len()
- if f.pre != nil {
- l += f.pre.Len()
+type stringEncoder string
+
+func (s stringEncoder) Len() int {
+ return len(s)
+}
+
+func (s stringEncoder) Encode(dst []byte) {
+ if copy(dst, s) != len(s) {
+ panic("internal error")
}
- if f.post != nil {
- l += f.post.Len()
+}
+
+type multiEncoder []encoder
+
+func (m multiEncoder) Len() int {
+ var size int
+ for _, e := range m {
+ size += e.Len()
}
- return
+ return size
}
-func (f *forkableWriter) writeTo(out io.Writer) (n int, err error) {
- n, err = out.Write(f.Bytes())
- if err != nil {
- return
+func (m multiEncoder) Encode(dst []byte) {
+ var off int
+ for _, e := range m {
+ e.Encode(dst[off:])
+ off += e.Len()
}
+}
- var nn int
+type taggedEncoder struct {
+ // scratch contains temporary space for encoding the tag and length of
+ // an element in order to avoid extra allocations.
+ scratch [8]byte
+ tag encoder
+ body encoder
+}
- if f.pre != nil {
- nn, err = f.pre.writeTo(out)
- n += nn
- if err != nil {
- return
- }
+func (t *taggedEncoder) Len() int {
+ return t.tag.Len() + t.body.Len()
+}
+
+func (t *taggedEncoder) Encode(dst []byte) {
+ t.tag.Encode(dst)
+ t.body.Encode(dst[t.tag.Len():])
+}
+
+type int64Encoder int64
+
+func (i int64Encoder) Len() int {
+ n := 1
+
+ for i > 127 {
+ n++
+ i >>= 8
}
- if f.post != nil {
- nn, err = f.post.writeTo(out)
- n += nn
+ for i < -128 {
+ n++
+ i >>= 8
}
- return
+
+ return n
}
-func marshalBase128Int(out *forkableWriter, n int64) (err error) {
+func (i int64Encoder) Encode(dst []byte) {
+ n := i.Len()
+
+ for j := 0; j < n; j++ {
+ dst[j] = byte(i >> uint((n-1-j)*8))
+ }
+}
+
+func base128IntLength(n int64) int {
if n == 0 {
- err = out.WriteByte(0)
- return
+ return 1
}
l := 0
@@ -83,54 +131,33 @@ func marshalBase128Int(out *forkableWriter, n int64) (err error) {
l++
}
+ return l
+}
+
+func appendBase128Int(dst []byte, n int64) []byte {
+ l := base128IntLength(n)
+
for i := l - 1; i >= 0; i-- {
o := byte(n >> uint(i*7))
o &= 0x7f
if i != 0 {
o |= 0x80
}
- err = out.WriteByte(o)
- if err != nil {
- return
- }
- }
-
- return nil
-}
-func marshalInt64(out *forkableWriter, i int64) (err error) {
- n := int64Length(i)
-
- for ; n > 0; n-- {
- err = out.WriteByte(byte(i >> uint((n-1)*8)))
- if err != nil {
- return
- }
+ dst = append(dst, o)
}
- return nil
+ return dst
}
-func int64Length(i int64) (numBytes int) {
- numBytes = 1
-
- for i > 127 {
- numBytes++
- i >>= 8
+func makeBigInt(n *big.Int) (encoder, error) {
+ if n == nil {
+ return nil, StructuralError{"empty integer"}
}
- for i < -128 {
- numBytes++
- i >>= 8
- }
-
- return
-}
-
-func marshalBigInt(out *forkableWriter, n *big.Int) (err error) {
if n.Sign() < 0 {
// A negative number has to be converted to two's-complement
- // form. So we'll subtract 1 and invert. If the
+ // form. So we'll invert and subtract 1. If the
// most-significant-bit isn't set then we'll need to pad the
// beginning with 0xff in order to keep the number negative.
nMinus1 := new(big.Int).Neg(n)
@@ -140,41 +167,31 @@ func marshalBigInt(out *forkableWriter, n *big.Int) (err error) {
bytes[i] ^= 0xff
}
if len(bytes) == 0 || bytes[0]&0x80 == 0 {
- err = out.WriteByte(0xff)
- if err != nil {
- return
- }
+ return multiEncoder([]encoder{byteFFEncoder, bytesEncoder(bytes)}), nil
}
- _, err = out.Write(bytes)
+ return bytesEncoder(bytes), nil
} else if n.Sign() == 0 {
// Zero is written as a single 0 zero rather than no bytes.
- err = out.WriteByte(0x00)
+ return byte00Encoder, nil
} else {
bytes := n.Bytes()
if len(bytes) > 0 && bytes[0]&0x80 != 0 {
// We'll have to pad this with 0x00 in order to stop it
// looking like a negative number.
- err = out.WriteByte(0)
- if err != nil {
- return
- }
+ return multiEncoder([]encoder{byte00Encoder, bytesEncoder(bytes)}), nil
}
- _, err = out.Write(bytes)
+ return bytesEncoder(bytes), nil
}
- return
}
-func marshalLength(out *forkableWriter, i int) (err error) {
+func appendLength(dst []byte, i int) []byte {
n := lengthLength(i)
for ; n > 0; n-- {
- err = out.WriteByte(byte(i >> uint((n-1)*8)))
- if err != nil {
- return
- }
+ dst = append(dst, byte(i>>uint((n-1)*8)))
}
- return nil
+ return dst
}
func lengthLength(i int) (numBytes int) {
@@ -186,123 +203,104 @@ func lengthLength(i int) (numBytes int) {
return
}
-func marshalTagAndLength(out *forkableWriter, t tagAndLength) (err error) {
+func appendTagAndLength(dst []byte, t tagAndLength) []byte {
b := uint8(t.class) << 6
if t.isCompound {
b |= 0x20
}
if t.tag >= 31 {
b |= 0x1f
- err = out.WriteByte(b)
- if err != nil {
- return
- }
- err = marshalBase128Int(out, int64(t.tag))
- if err != nil {
- return
- }
+ dst = append(dst, b)
+ dst = appendBase128Int(dst, int64(t.tag))
} else {
b |= uint8(t.tag)
- err = out.WriteByte(b)
- if err != nil {
- return
- }
+ dst = append(dst, b)
}
if t.length >= 128 {
l := lengthLength(t.length)
- err = out.WriteByte(0x80 | byte(l))
- if err != nil {
- return
- }
- err = marshalLength(out, t.length)
- if err != nil {
- return
- }
+ dst = append(dst, 0x80|byte(l))
+ dst = appendLength(dst, t.length)
} else {
- err = out.WriteByte(byte(t.length))
- if err != nil {
- return
- }
+ dst = append(dst, byte(t.length))
}
- return nil
+ return dst
}
-func marshalBitString(out *forkableWriter, b BitString) (err error) {
- paddingBits := byte((8 - b.BitLength%8) % 8)
- err = out.WriteByte(paddingBits)
- if err != nil {
- return
- }
- _, err = out.Write(b.Bytes)
- return
+type bitStringEncoder BitString
+
+func (b bitStringEncoder) Len() int {
+ return len(b.Bytes) + 1
}
-func marshalObjectIdentifier(out *forkableWriter, oid []int) (err error) {
- if len(oid) < 2 || oid[0] > 2 || (oid[0] < 2 && oid[1] >= 40) {
- return StructuralError{"invalid object identifier"}
+func (b bitStringEncoder) Encode(dst []byte) {
+ dst[0] = byte((8 - b.BitLength%8) % 8)
+ if copy(dst[1:], b.Bytes) != len(b.Bytes) {
+ panic("internal error")
}
+}
- err = marshalBase128Int(out, int64(oid[0]*40+oid[1]))
- if err != nil {
- return
+type oidEncoder []int
+
+func (oid oidEncoder) Len() int {
+ l := base128IntLength(int64(oid[0]*40 + oid[1]))
+ for i := 2; i < len(oid); i++ {
+ l += base128IntLength(int64(oid[i]))
}
+ return l
+}
+
+func (oid oidEncoder) Encode(dst []byte) {
+ dst = appendBase128Int(dst[:0], int64(oid[0]*40+oid[1]))
for i := 2; i < len(oid); i++ {
- err = marshalBase128Int(out, int64(oid[i]))
- if err != nil {
- return
- }
+ dst = appendBase128Int(dst, int64(oid[i]))
}
+}
- return
+func makeObjectIdentifier(oid []int) (e encoder, err error) {
+ if len(oid) < 2 || oid[0] > 2 || (oid[0] < 2 && oid[1] >= 40) {
+ return nil, StructuralError{"invalid object identifier"}
+ }
+
+ return oidEncoder(oid), nil
}
-func marshalPrintableString(out *forkableWriter, s string) (err error) {
- b := []byte(s)
- for _, c := range b {
- if !isPrintable(c) {
- return StructuralError{"PrintableString contains invalid character"}
+func makePrintableString(s string) (e encoder, err error) {
+ for i := 0; i < len(s); i++ {
+ if !isPrintable(s[i]) {
+ return nil, StructuralError{"PrintableString contains invalid character"}
}
}
- _, err = out.Write(b)
- return
+ return stringEncoder(s), nil
}
-func marshalIA5String(out *forkableWriter, s string) (err error) {
- b := []byte(s)
- for _, c := range b {
- if c > 127 {
- return StructuralError{"IA5String contains invalid character"}
+func makeIA5String(s string) (e encoder, err error) {
+ for i := 0; i < len(s); i++ {
+ if s[i] > 127 {
+ return nil, StructuralError{"IA5String contains invalid character"}
}
}
- _, err = out.Write(b)
- return
+ return stringEncoder(s), nil
}
-func marshalUTF8String(out *forkableWriter, s string) (err error) {
- _, err = out.Write([]byte(s))
- return
+func makeUTF8String(s string) encoder {
+ return stringEncoder(s)
}
-func marshalTwoDigits(out *forkableWriter, v int) (err error) {
- err = out.WriteByte(byte('0' + (v/10)%10))
- if err != nil {
- return
- }
- return out.WriteByte(byte('0' + v%10))
+func appendTwoDigits(dst []byte, v int) []byte {
+ return append(dst, byte('0'+(v/10)%10), byte('0'+v%10))
}
-func marshalFourDigits(out *forkableWriter, v int) (err error) {
+func appendFourDigits(dst []byte, v int) []byte {
var bytes [4]byte
for i := range bytes {
bytes[3-i] = '0' + byte(v%10)
v /= 10
}
- _, err = out.Write(bytes[:])
- return
+ return append(dst, bytes[:]...)
}
func outsideUTCRange(t time.Time) bool {
@@ -310,80 +308,75 @@ func outsideUTCRange(t time.Time) bool {
return year < 1950 || year >= 2050
}
-func marshalUTCTime(out *forkableWriter, t time.Time) (err error) {
+func makeUTCTime(t time.Time) (e encoder, err error) {
+ dst := make([]byte, 0, 18)
+
+ dst, err = appendUTCTime(dst, t)
+ if err != nil {
+ return nil, err
+ }
+
+ return bytesEncoder(dst), nil
+}
+
+func makeGeneralizedTime(t time.Time) (e encoder, err error) {
+ dst := make([]byte, 0, 20)
+
+ dst, err = appendGeneralizedTime(dst, t)
+ if err != nil {
+ return nil, err
+ }
+
+ return bytesEncoder(dst), nil
+}
+
+func appendUTCTime(dst []byte, t time.Time) (ret []byte, err error) {
year := t.Year()
switch {
case 1950 <= year && year < 2000:
- err = marshalTwoDigits(out, year-1900)
+ dst = appendTwoDigits(dst, year-1900)
case 2000 <= year && year < 2050:
- err = marshalTwoDigits(out, year-2000)
+ dst = appendTwoDigits(dst, year-2000)
default:
- return StructuralError{"cannot represent time as UTCTime"}
- }
- if err != nil {
- return
+ return nil, StructuralError{"cannot represent time as UTCTime"}
}
- return marshalTimeCommon(out, t)
+ return appendTimeCommon(dst, t), nil
}
-func marshalGeneralizedTime(out *forkableWriter, t time.Time) (err error) {
+func appendGeneralizedTime(dst []byte, t time.Time) (ret []byte, err error) {
year := t.Year()
if year < 0 || year > 9999 {
- return StructuralError{"cannot represent time as GeneralizedTime"}
- }
- if err = marshalFourDigits(out, year); err != nil {
- return
+ return nil, StructuralError{"cannot represent time as GeneralizedTime"}
}
- return marshalTimeCommon(out, t)
+ dst = appendFourDigits(dst, year)
+
+ return appendTimeCommon(dst, t), nil
}
-func marshalTimeCommon(out *forkableWriter, t time.Time) (err error) {
+func appendTimeCommon(dst []byte, t time.Time) []byte {
_, month, day := t.Date()
- err = marshalTwoDigits(out, int(month))
- if err != nil {
- return
- }
-
- err = marshalTwoDigits(out, day)
- if err != nil {
- return
- }
+ dst = appendTwoDigits(dst, int(month))
+ dst = appendTwoDigits(dst, day)
hour, min, sec := t.Clock()
- err = marshalTwoDigits(out, hour)
- if err != nil {
- return
- }
-
- err = marshalTwoDigits(out, min)
- if err != nil {
- return
- }
-
- err = marshalTwoDigits(out, sec)
- if err != nil {
- return
- }
+ dst = appendTwoDigits(dst, hour)
+ dst = appendTwoDigits(dst, min)
+ dst = appendTwoDigits(dst, sec)
_, offset := t.Zone()
switch {
case offset/60 == 0:
- err = out.WriteByte('Z')
- return
+ return append(dst, 'Z')
case offset > 0:
- err = out.WriteByte('+')
+ dst = append(dst, '+')
case offset < 0:
- err = out.WriteByte('-')
- }
-
- if err != nil {
- return
+ dst = append(dst, '-')
}
offsetMinutes := offset / 60
@@ -391,13 +384,10 @@ func marshalTimeCommon(out *forkableWriter, t time.Time) (err error) {
offsetMinutes = -offsetMinutes
}
- err = marshalTwoDigits(out, offsetMinutes/60)
- if err != nil {
- return
- }
+ dst = appendTwoDigits(dst, offsetMinutes/60)
+ dst = appendTwoDigits(dst, offsetMinutes%60)
- err = marshalTwoDigits(out, offsetMinutes%60)
- return
+ return dst
}
func stripTagAndLength(in []byte) []byte {
@@ -408,114 +398,130 @@ func stripTagAndLength(in []byte) []byte {
return in[offset:]
}
-func marshalBody(out *forkableWriter, value reflect.Value, params fieldParameters) (err error) {
+func makeBody(value reflect.Value, params fieldParameters) (e encoder, err error) {
switch value.Type() {
case flagType:
- return nil
+ return bytesEncoder(nil), nil
case timeType:
t := value.Interface().(time.Time)
if params.timeType == TagGeneralizedTime || outsideUTCRange(t) {
- return marshalGeneralizedTime(out, t)
- } else {
- return marshalUTCTime(out, t)
+ return makeGeneralizedTime(t)
}
+ return makeUTCTime(t)
case bitStringType:
- return marshalBitString(out, value.Interface().(BitString))
+ return bitStringEncoder(value.Interface().(BitString)), nil
case objectIdentifierType:
- return marshalObjectIdentifier(out, value.Interface().(ObjectIdentifier))
+ return makeObjectIdentifier(value.Interface().(ObjectIdentifier))
case bigIntType:
- return marshalBigInt(out, value.Interface().(*big.Int))
+ return makeBigInt(value.Interface().(*big.Int))
}
switch v := value; v.Kind() {
case reflect.Bool:
if v.Bool() {
- return out.WriteByte(255)
- } else {
- return out.WriteByte(0)
+ return byteFFEncoder, nil
}
+ return byte00Encoder, nil
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- return marshalInt64(out, v.Int())
+ return int64Encoder(v.Int()), nil
case reflect.Struct:
t := v.Type()
+ for i := 0; i < t.NumField(); i++ {
+ if t.Field(i).PkgPath != "" {
+ return nil, StructuralError{"struct contains unexported fields"}
+ }
+ }
+
startingField := 0
+ n := t.NumField()
+ if n == 0 {
+ return bytesEncoder(nil), nil
+ }
+
// If the first element of the structure is a non-empty
// RawContents, then we don't bother serializing the rest.
- if t.NumField() > 0 && t.Field(0).Type == rawContentsType {
+ if t.Field(0).Type == rawContentsType {
s := v.Field(0)
if s.Len() > 0 {
- bytes := make([]byte, s.Len())
- for i := 0; i < s.Len(); i++ {
- bytes[i] = uint8(s.Index(i).Uint())
- }
+ bytes := s.Bytes()
/* The RawContents will contain the tag and
* length fields but we'll also be writing
* those ourselves, so we strip them out of
* bytes */
- _, err = out.Write(stripTagAndLength(bytes))
- return
- } else {
- startingField = 1
+ return bytesEncoder(stripTagAndLength(bytes)), nil
}
+
+ startingField = 1
}
- for i := startingField; i < t.NumField(); i++ {
- var pre *forkableWriter
- pre, out = out.fork()
- err = marshalField(pre, v.Field(i), parseFieldParameters(t.Field(i).Tag.Get("asn1")))
- if err != nil {
- return
+ switch n1 := n - startingField; n1 {
+ case 0:
+ return bytesEncoder(nil), nil
+ case 1:
+ return makeField(v.Field(startingField), parseFieldParameters(t.Field(startingField).Tag.Get("asn1")))
+ default:
+ m := make([]encoder, n1)
+ for i := 0; i < n1; i++ {
+ m[i], err = makeField(v.Field(i+startingField), parseFieldParameters(t.Field(i+startingField).Tag.Get("asn1")))
+ if err != nil {
+ return nil, err
+ }
}
+
+ return multiEncoder(m), nil
}
- return
case reflect.Slice:
sliceType := v.Type()
if sliceType.Elem().Kind() == reflect.Uint8 {
- bytes := make([]byte, v.Len())
- for i := 0; i < v.Len(); i++ {
- bytes[i] = uint8(v.Index(i).Uint())
- }
- _, err = out.Write(bytes)
- return
+ return bytesEncoder(v.Bytes()), nil
}
var fp fieldParameters
- for i := 0; i < v.Len(); i++ {
- var pre *forkableWriter
- pre, out = out.fork()
- err = marshalField(pre, v.Index(i), fp)
- if err != nil {
- return
+
+ switch l := v.Len(); l {
+ case 0:
+ return bytesEncoder(nil), nil
+ case 1:
+ return makeField(v.Index(0), fp)
+ default:
+ m := make([]encoder, l)
+
+ for i := 0; i < l; i++ {
+ m[i], err = makeField(v.Index(i), fp)
+ if err != nil {
+ return nil, err
+ }
}
+
+ return multiEncoder(m), nil
}
- return
case reflect.String:
switch params.stringType {
case TagIA5String:
- return marshalIA5String(out, v.String())
+ return makeIA5String(v.String())
case TagPrintableString:
- return marshalPrintableString(out, v.String())
+ return makePrintableString(v.String())
default:
- return marshalUTF8String(out, v.String())
+ return makeUTF8String(v.String()), nil
}
}
- return StructuralError{"unknown Go type"}
+ return nil, StructuralError{"unknown Go type"}
}
-func marshalField(out *forkableWriter, v reflect.Value, params fieldParameters) (err error) {
+func makeField(v reflect.Value, params fieldParameters) (e encoder, err error) {
if !v.IsValid() {
- return fmt.Errorf("asn1: cannot marshal nil value")
+ return nil, fmt.Errorf("asn1: cannot marshal nil value")
}
// If the field is an interface{} then recurse into it.
if v.Kind() == reflect.Interface && v.Type().NumMethod() == 0 {
- return marshalField(out, v.Elem(), params)
+ return makeField(v.Elem(), params)
}
if v.Kind() == reflect.Slice && v.Len() == 0 && params.omitEmpty {
- return
+ return bytesEncoder(nil), nil
}
if params.optional && params.defaultValue != nil && canHaveDefaultValue(v.Kind()) {
@@ -523,7 +529,7 @@ func marshalField(out *forkableWriter, v reflect.Value, params fieldParameters)
defaultValue.SetInt(*params.defaultValue)
if reflect.DeepEqual(v.Interface(), defaultValue.Interface()) {
- return
+ return bytesEncoder(nil), nil
}
}
@@ -532,37 +538,36 @@ func marshalField(out *forkableWriter, v reflect.Value, params fieldParameters)
// behaviour, but it's what Go has traditionally done.
if params.optional && params.defaultValue == nil {
if reflect.DeepEqual(v.Interface(), reflect.Zero(v.Type()).Interface()) {
- return
+ return bytesEncoder(nil), nil
}
}
if v.Type() == rawValueType {
rv := v.Interface().(RawValue)
if len(rv.FullBytes) != 0 {
- _, err = out.Write(rv.FullBytes)
- } else {
- err = marshalTagAndLength(out, tagAndLength{rv.Class, rv.Tag, len(rv.Bytes), rv.IsCompound})
- if err != nil {
- return
- }
- _, err = out.Write(rv.Bytes)
+ return bytesEncoder(rv.FullBytes), nil
}
- return
+
+ t := new(taggedEncoder)
+
+ t.tag = bytesEncoder(appendTagAndLength(t.scratch[:0], tagAndLength{rv.Class, rv.Tag, len(rv.Bytes), rv.IsCompound}))
+ t.body = bytesEncoder(rv.Bytes)
+
+ return t, nil
}
tag, isCompound, ok := getUniversalType(v.Type())
if !ok {
- err = StructuralError{fmt.Sprintf("unknown Go type: %v", v.Type())}
- return
+ return nil, StructuralError{fmt.Sprintf("unknown Go type: %v", v.Type())}
}
class := ClassUniversal
if params.timeType != 0 && tag != TagUTCTime {
- return StructuralError{"explicit time type given to non-time member"}
+ return nil, StructuralError{"explicit time type given to non-time member"}
}
if params.stringType != 0 && tag != TagPrintableString {
- return StructuralError{"explicit string type given to non-string member"}
+ return nil, StructuralError{"explicit string type given to non-string member"}
}
switch tag {
@@ -574,7 +579,7 @@ func marshalField(out *forkableWriter, v reflect.Value, params fieldParameters)
for _, r := range v.String() {
if r >= utf8.RuneSelf || !isPrintable(byte(r)) {
if !utf8.ValidString(v.String()) {
- return errors.New("asn1: string not valid UTF-8")
+ return nil, errors.New("asn1: string not valid UTF-8")
}
tag = TagUTF8String
break
@@ -591,46 +596,46 @@ func marshalField(out *forkableWriter, v reflect.Value, params fieldParameters)
if params.set {
if tag != TagSequence {
- return StructuralError{"non sequence tagged as set"}
+ return nil, StructuralError{"non sequence tagged as set"}
}
tag = TagSet
}
- tags, body := out.fork()
+ t := new(taggedEncoder)
- err = marshalBody(body, v, params)
+ t.body, err = makeBody(v, params)
if err != nil {
- return
+ return nil, err
}
- bodyLen := body.Len()
+ bodyLen := t.body.Len()
- var explicitTag *forkableWriter
if params.explicit {
- explicitTag, tags = tags.fork()
- }
+ t.tag = bytesEncoder(appendTagAndLength(t.scratch[:0], tagAndLength{class, tag, bodyLen, isCompound}))
- if !params.explicit && params.tag != nil {
- // implicit tag.
- tag = *params.tag
- class = ClassContextSpecific
- }
+ tt := new(taggedEncoder)
- err = marshalTagAndLength(tags, tagAndLength{class, tag, bodyLen, isCompound})
- if err != nil {
- return
- }
+ tt.body = t
- if params.explicit {
- err = marshalTagAndLength(explicitTag, tagAndLength{
+ tt.tag = bytesEncoder(appendTagAndLength(tt.scratch[:0], tagAndLength{
class: ClassContextSpecific,
tag: *params.tag,
- length: bodyLen + tags.Len(),
+ length: bodyLen + t.tag.Len(),
isCompound: true,
- })
+ }))
+
+ return tt, nil
+ }
+
+ if params.tag != nil {
+ // implicit tag.
+ tag = *params.tag
+ class = ClassContextSpecific
}
- return err
+ t.tag = bytesEncoder(appendTagAndLength(t.scratch[:0], tagAndLength{class, tag, bodyLen, isCompound}))
+
+ return t, nil
}
// Marshal returns the ASN.1 encoding of val.
@@ -643,13 +648,11 @@ func marshalField(out *forkableWriter, v reflect.Value, params fieldParameters)
// printable: causes strings to be marshaled as ASN.1, PrintableString strings.
// utf8: causes strings to be marshaled as ASN.1, UTF8 strings
func Marshal(val interface{}) ([]byte, error) {
- var out bytes.Buffer
- v := reflect.ValueOf(val)
- f := newForkableWriter()
- err := marshalField(f, v, fieldParameters{})
+ e, err := makeField(reflect.ValueOf(val), fieldParameters{})
if err != nil {
return nil, err
}
- _, err = f.writeTo(&out)
- return out.Bytes(), err
+ b := make([]byte, e.Len())
+ e.Encode(b)
+ return b, nil
}
diff --git a/src/encoding/asn1/marshal_test.go b/src/encoding/asn1/marshal_test.go
index cdca8aa..10db1aa 100644
--- a/src/encoding/asn1/marshal_test.go
+++ b/src/encoding/asn1/marshal_test.go
@@ -8,6 +8,7 @@ import (
"bytes"
"encoding/hex"
"math/big"
+ "strings"
"testing"
"time"
)
@@ -167,9 +168,42 @@ func TestMarshal(t *testing.T) {
}
}
+type marshalErrTest struct {
+ in interface{}
+ err string
+}
+
+var marshalErrTests = []marshalErrTest{
+ {bigIntStruct{nil}, "empty integer"},
+}
+
+func TestMarshalError(t *testing.T) {
+ for i, test := range marshalErrTests {
+ _, err := Marshal(test.in)
+ if err == nil {
+ t.Errorf("#%d should fail, but success", i)
+ continue
+ }
+
+ if !strings.Contains(err.Error(), test.err) {
+ t.Errorf("#%d got: %v want %v", i, err, test.err)
+ }
+ }
+}
+
func TestInvalidUTF8(t *testing.T) {
_, err := Marshal(string([]byte{0xff, 0xff}))
if err == nil {
t.Errorf("invalid UTF8 string was accepted")
}
}
+
+func BenchmarkMarshal(b *testing.B) {
+ b.ReportAllocs()
+
+ for i := 0; i < b.N; i++ {
+ for _, test := range marshalTests {
+ Marshal(test.in)
+ }
+ }
+}
diff --git a/src/encoding/base64/base64.go b/src/encoding/base64/base64.go
index c2116d8..d2efad4 100644
--- a/src/encoding/base64/base64.go
+++ b/src/encoding/base64/base64.go
@@ -23,6 +23,7 @@ type Encoding struct {
encode [64]byte
decodeMap [256]byte
padChar rune
+ strict bool
}
const (
@@ -62,6 +63,14 @@ func (enc Encoding) WithPadding(padding rune) *Encoding {
return &enc
}
+// Strict creates a new encoding identical to enc except with
+// strict decoding enabled. In this mode, the decoder requires that
+// trailing padding bits are zero, as described in RFC 4648 section 3.5.
+func (enc Encoding) Strict() *Encoding {
+ enc.strict = true
+ return &enc
+}
+
// StdEncoding is the standard base64 encoding, as defined in
// RFC 4648.
var StdEncoding = NewEncoding(encodeStd)
@@ -311,15 +320,24 @@ func (enc *Encoding) decode(dst, src []byte) (n int, end bool, err error) {
// Convert 4x 6bit source bytes into 3 bytes
val := uint(dbuf[0])<<18 | uint(dbuf[1])<<12 | uint(dbuf[2])<<6 | uint(dbuf[3])
+ dbuf[2], dbuf[1], dbuf[0] = byte(val>>0), byte(val>>8), byte(val>>16)
switch dlen {
case 4:
- dst[2] = byte(val >> 0)
+ dst[2] = dbuf[2]
+ dbuf[2] = 0
fallthrough
case 3:
- dst[1] = byte(val >> 8)
+ dst[1] = dbuf[1]
+ if enc.strict && dbuf[2] != 0 {
+ return n, end, CorruptInputError(si - 1)
+ }
+ dbuf[1] = 0
fallthrough
case 2:
- dst[0] = byte(val >> 16)
+ dst[0] = dbuf[0]
+ if enc.strict && (dbuf[1] != 0 || dbuf[2] != 0) {
+ return n, end, CorruptInputError(si - 2)
+ }
}
dst = dst[dinc:]
n += dlen - 1
diff --git a/src/encoding/base64/base64_test.go b/src/encoding/base64/base64_test.go
index 19ddb92..e2e1d59 100644
--- a/src/encoding/base64/base64_test.go
+++ b/src/encoding/base64/base64_test.go
@@ -85,6 +85,11 @@ var encodingTests = []encodingTest{
{RawStdEncoding, rawRef},
{RawURLEncoding, rawUrlRef},
{funnyEncoding, funnyRef},
+ {StdEncoding.Strict(), stdRef},
+ {URLEncoding.Strict(), urlRef},
+ {RawStdEncoding.Strict(), rawRef},
+ {RawURLEncoding.Strict(), rawUrlRef},
+ {funnyEncoding.Strict(), funnyRef},
}
var bigtest = testpair{
@@ -436,6 +441,22 @@ func TestDecoderIssue7733(t *testing.T) {
}
}
+func TestDecoderIssue15656(t *testing.T) {
+ _, err := StdEncoding.Strict().DecodeString("WvLTlMrX9NpYDQlEIFlnDB==")
+ want := CorruptInputError(22)
+ if !reflect.DeepEqual(want, err) {
+ t.Errorf("Error = %v; want CorruptInputError(22)", err)
+ }
+ _, err = StdEncoding.Strict().DecodeString("WvLTlMrX9NpYDQlEIFlnDA==")
+ if err != nil {
+ t.Errorf("Error = %v; want nil", err)
+ }
+ _, err = StdEncoding.DecodeString("WvLTlMrX9NpYDQlEIFlnDB==")
+ if err != nil {
+ t.Errorf("Error = %v; want nil", err)
+ }
+}
+
func BenchmarkEncodeToString(b *testing.B) {
data := make([]byte, 8192)
b.SetBytes(int64(len(data)))
diff --git a/src/encoding/binary/binary.go b/src/encoding/binary/binary.go
index 46c6add..3834254 100644
--- a/src/encoding/binary/binary.go
+++ b/src/encoding/binary/binary.go
@@ -7,7 +7,7 @@
//
// Numbers are translated by reading and writing fixed-size values.
// A fixed-size value is either a fixed-size arithmetic
-// type (int8, uint8, int16, float32, complex64, ...)
+// type (bool, int8, uint8, int16, float32, complex64, ...)
// or an array or struct containing only fixed-size values.
//
// The varint functions encode and decode single integer values using
@@ -147,6 +147,8 @@ func (bigEndian) GoString() string { return "binary.BigEndian" }
// of fixed-size values.
// Bytes read from r are decoded using the specified byte order
// and written to successive fields of the data.
+// When decoding boolean values, a zero byte is decoded as false, and
+// any other non-zero byte is decoded as true.
// When reading into structs, the field data for fields with
// blank (_) field names is skipped; i.e., blank field names
// may be used for padding.
@@ -169,6 +171,8 @@ func Read(r io.Reader, order ByteOrder, data interface{}) error {
return err
}
switch data := data.(type) {
+ case *bool:
+ *data = b[0] != 0
case *int8:
*data = int8(b[0])
case *uint8:
@@ -185,8 +189,12 @@ func Read(r io.Reader, order ByteOrder, data interface{}) error {
*data = int64(order.Uint64(bs))
case *uint64:
*data = order.Uint64(bs)
- case []int8:
+ case []bool:
for i, x := range bs { // Easier to loop over the input for 8-bit values.
+ data[i] = x != 0
+ }
+ case []int8:
+ for i, x := range bs {
data[i] = int8(x)
}
case []uint8:
@@ -243,6 +251,7 @@ func Read(r io.Reader, order ByteOrder, data interface{}) error {
// Write writes the binary representation of data into w.
// Data must be a fixed-size value or a slice of fixed-size
// values, or a pointer to such data.
+// Boolean values encode as one byte: 1 for true, and 0 for false.
// Bytes written to w are encoded using the specified byte order
// and read from successive fields of the data.
// When writing structs, zero values are written for fields
@@ -258,6 +267,26 @@ func Write(w io.Writer, order ByteOrder, data interface{}) error {
bs = b[:n]
}
switch v := data.(type) {
+ case *bool:
+ if *v {
+ b[0] = 1
+ } else {
+ b[0] = 0
+ }
+ case bool:
+ if v {
+ b[0] = 1
+ } else {
+ b[0] = 0
+ }
+ case []bool:
+ for i, x := range v {
+ if x {
+ bs[i] = 1
+ } else {
+ bs[i] = 0
+ }
+ }
case *int8:
b[0] = byte(*v)
case int8:
@@ -378,7 +407,8 @@ func sizeof(t reflect.Type) int {
}
return sum
- case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
+ case reflect.Bool,
+ reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
reflect.Float32, reflect.Float64, reflect.Complex64, reflect.Complex128:
return int(t.Size())
@@ -395,6 +425,21 @@ type coder struct {
type decoder coder
type encoder coder
+func (d *decoder) bool() bool {
+ x := d.buf[0]
+ d.buf = d.buf[1:]
+ return x != 0
+}
+
+func (e *encoder) bool(x bool) {
+ if x {
+ e.buf[0] = 1
+ } else {
+ e.buf[0] = 0
+ }
+ e.buf = e.buf[1:]
+}
+
func (d *decoder) uint8() uint8 {
x := d.buf[0]
d.buf = d.buf[1:]
@@ -485,6 +530,9 @@ func (d *decoder) value(v reflect.Value) {
d.value(v.Index(i))
}
+ case reflect.Bool:
+ v.SetBool(d.bool())
+
case reflect.Int8:
v.SetInt(int64(d.int8()))
case reflect.Int16:
@@ -547,6 +595,9 @@ func (e *encoder) value(v reflect.Value) {
e.value(v.Index(i))
}
+ case reflect.Bool:
+ e.bool(v.Bool())
+
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
switch v.Type().Kind() {
case reflect.Int8:
@@ -609,7 +660,7 @@ func (e *encoder) skip(v reflect.Value) {
// It returns zero if the type cannot be implemented by the fast path in Read or Write.
func intDataSize(data interface{}) int {
switch data := data.(type) {
- case int8, uint8, *int8, *uint8:
+ case bool, int8, uint8, *bool, *int8, *uint8:
return 1
case []int8:
return len(data)
diff --git a/src/encoding/binary/binary_test.go b/src/encoding/binary/binary_test.go
index c0728e9..fc7f276 100644
--- a/src/encoding/binary/binary_test.go
+++ b/src/encoding/binary/binary_test.go
@@ -27,6 +27,8 @@ type Struct struct {
Complex64 complex64
Complex128 complex128
Array [4]uint8
+ Bool bool
+ BoolArray [4]bool
}
type T struct {
@@ -58,6 +60,9 @@ var s = Struct{
),
[4]uint8{0x43, 0x44, 0x45, 0x46},
+
+ true,
+ [4]bool{true, false, true, false},
}
var big = []byte{
@@ -76,6 +81,9 @@ var big = []byte{
51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66,
67, 68, 69, 70,
+
+ 1,
+ 1, 0, 1, 0,
}
var little = []byte{
@@ -94,6 +102,9 @@ var little = []byte{
58, 57, 56, 55, 54, 53, 52, 51, 66, 65, 64, 63, 62, 61, 60, 59,
67, 68, 69, 70,
+
+ 1,
+ 1, 0, 1, 0,
}
var src = []byte{1, 2, 3, 4, 5, 6, 7, 8}
@@ -141,6 +152,25 @@ func TestWriteSlice(t *testing.T) {
checkResult(t, "WriteSlice", BigEndian, err, buf.Bytes(), src)
}
+func TestReadBool(t *testing.T) {
+ var res bool
+ var err error
+ err = Read(bytes.NewReader([]byte{0}), BigEndian, &res)
+ checkResult(t, "ReadBool", BigEndian, err, res, false)
+ res = false
+ err = Read(bytes.NewReader([]byte{1}), BigEndian, &res)
+ checkResult(t, "ReadBool", BigEndian, err, res, true)
+ res = false
+ err = Read(bytes.NewReader([]byte{2}), BigEndian, &res)
+ checkResult(t, "ReadBool", BigEndian, err, res, true)
+}
+
+func TestReadBoolSlice(t *testing.T) {
+ slice := make([]bool, 4)
+ err := Read(bytes.NewReader([]byte{0, 1, 2, 255}), BigEndian, slice)
+ checkResult(t, "ReadBoolSlice", BigEndian, err, slice, []bool{false, true, true, true})
+}
+
// Addresses of arrays are easier to manipulate with reflection than are slices.
var intArrays = []interface{}{
&[100]int8{},
@@ -422,16 +452,15 @@ func BenchmarkReadInts(b *testing.B) {
Read(r, BigEndian, &ls.Uint32)
Read(r, BigEndian, &ls.Uint64)
}
-
+ b.StopTimer()
want := s
want.Float32 = 0
want.Float64 = 0
want.Complex64 = 0
want.Complex128 = 0
- for i := range want.Array {
- want.Array[i] = 0
- }
- b.StopTimer()
+ want.Array = [4]uint8{0, 0, 0, 0}
+ want.Bool = false
+ want.BoolArray = [4]bool{false, false, false, false}
if b.N > 0 && !reflect.DeepEqual(ls, want) {
b.Fatalf("struct doesn't match:\ngot %v;\nwant %v", ls, want)
}
diff --git a/src/encoding/csv/reader.go b/src/encoding/csv/reader.go
index a5e03a9..c8c4ca7 100644
--- a/src/encoding/csv/reader.go
+++ b/src/encoding/csv/reader.go
@@ -114,7 +114,14 @@ type Reader struct {
line int
column int
r *bufio.Reader
- field bytes.Buffer
+ // lineBuffer holds the unescaped fields read by readField, one after another.
+ // The fields can be accessed by using the indexes in fieldIndexes.
+ // Example: for the row `a,"b","c""d",e` lineBuffer will contain `abc"de` and
+ // fieldIndexes will contain the indexes 0, 1, 2, 5.
+ lineBuffer bytes.Buffer
+ // Indexes of fields inside lineBuffer
+ // The i'th field starts at offset fieldIndexes[i] in lineBuffer.
+ fieldIndexes []int
}
// NewReader returns a new Reader that reads from r.
@@ -134,8 +141,12 @@ func (r *Reader) error(err error) error {
}
}
-// Read reads one record from r. The record is a slice of strings with each
-// string representing one field.
+// Read reads one record (a slice of fields) from r.
+// If the record has an unexpected number of fields,
+// Read returns the record along with the error ErrFieldCount.
+// 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.
func (r *Reader) Read() (record []string, err error) {
for {
record, err = r.parseRecord()
@@ -233,31 +244,54 @@ func (r *Reader) parseRecord() (fields []string, err error) {
}
r.r.UnreadRune()
+ r.lineBuffer.Reset()
+ r.fieldIndexes = r.fieldIndexes[:0]
+
// At this point we have at least one field.
for {
+ idx := r.lineBuffer.Len()
+
haveField, delim, err := r.parseField()
if haveField {
- // If FieldsPerRecord is greater than 0 we can assume the final
- // length of fields to be equal to FieldsPerRecord.
- if r.FieldsPerRecord > 0 && fields == nil {
- fields = make([]string, 0, r.FieldsPerRecord)
- }
- fields = append(fields, r.field.String())
+ r.fieldIndexes = append(r.fieldIndexes, idx)
}
+
if delim == '\n' || err == io.EOF {
- return fields, err
- } else if err != nil {
+ if len(r.fieldIndexes) == 0 {
+ return nil, err
+ }
+ break
+ }
+
+ if err != nil {
return nil, err
}
}
+
+ fieldCount := len(r.fieldIndexes)
+ // Using this approach (creating a single string and taking slices of it)
+ // means that a single reference to any of the fields will retain the whole
+ // string. The risk of a nontrivial space leak caused by this is considered
+ // minimal and a tradeoff for better performance through the combined
+ // allocations.
+ line := r.lineBuffer.String()
+ fields = make([]string, fieldCount)
+
+ for i, idx := range r.fieldIndexes {
+ if i == fieldCount-1 {
+ fields[i] = line[idx:]
+ } else {
+ fields[i] = line[idx:r.fieldIndexes[i+1]]
+ }
+ }
+
+ return fields, nil
}
// parseField parses the next field in the record. The read field is
-// located in r.field. Delim is the first character not part of the field
+// appended to r.lineBuffer. Delim is the first character not part of the field
// (r.Comma or '\n').
func (r *Reader) parseField() (haveField bool, delim rune, err error) {
- r.field.Reset()
-
r1, err := r.readRune()
for err == nil && r.TrimLeadingSpace && r1 != '\n' && unicode.IsSpace(r1) {
r1, err = r.readRune()
@@ -310,19 +344,19 @@ func (r *Reader) parseField() (haveField bool, delim rune, err error) {
return false, 0, r.error(ErrQuote)
}
// accept the bare quote
- r.field.WriteRune('"')
+ r.lineBuffer.WriteRune('"')
}
case '\n':
r.line++
r.column = -1
}
- r.field.WriteRune(r1)
+ r.lineBuffer.WriteRune(r1)
}
default:
// unquoted field
for {
- r.field.WriteRune(r1)
+ r.lineBuffer.WriteRune(r1)
r1, err = r.readRune()
if err != nil || r1 == r.Comma {
break
diff --git a/src/encoding/csv/reader_test.go b/src/encoding/csv/reader_test.go
index be1002d..7b3aca4 100644
--- a/src/encoding/csv/reader_test.go
+++ b/src/encoding/csv/reader_test.go
@@ -5,6 +5,7 @@
package csv
import (
+ "io"
"reflect"
"strings"
"testing"
@@ -292,8 +293,52 @@ func TestRead(t *testing.T) {
}
}
-func BenchmarkRead(b *testing.B) {
- data := `x,y,z,w
+// nTimes is an io.Reader which yields the string s n times.
+type nTimes struct {
+ s string
+ n int
+ off int
+}
+
+func (r *nTimes) Read(p []byte) (n int, err error) {
+ for {
+ if r.n <= 0 || r.s == "" {
+ return n, io.EOF
+ }
+ n0 := copy(p, r.s[r.off:])
+ p = p[n0:]
+ n += n0
+ r.off += n0
+ if r.off == len(r.s) {
+ r.off = 0
+ r.n--
+ }
+ if len(p) == 0 {
+ return
+ }
+ }
+}
+
+// benchmarkRead measures reading the provided CSV rows data.
+// initReader, if non-nil, modifies the Reader before it's used.
+func benchmarkRead(b *testing.B, initReader func(*Reader), rows string) {
+ b.ReportAllocs()
+ r := NewReader(&nTimes{s: rows, n: b.N})
+ if initReader != nil {
+ initReader(r)
+ }
+ for {
+ _, err := r.Read()
+ if err == io.EOF {
+ break
+ }
+ if err != nil {
+ b.Fatal(err)
+ }
+ }
+}
+
+const benchmarkCSVData = `x,y,z,w
x,y,z,
x,y,,
x,,,
@@ -305,11 +350,22 @@ x,,,
"","","",""
`
- for i := 0; i < b.N; i++ {
- _, err := NewReader(strings.NewReader(data)).ReadAll()
+func BenchmarkRead(b *testing.B) {
+ benchmarkRead(b, nil, benchmarkCSVData)
+}
- if err != nil {
- b.Fatalf("could not read data: %s", err)
- }
- }
+func BenchmarkReadWithFieldsPerRecord(b *testing.B) {
+ benchmarkRead(b, func(r *Reader) { r.FieldsPerRecord = 4 }, benchmarkCSVData)
+}
+
+func BenchmarkReadWithoutFieldsPerRecord(b *testing.B) {
+ benchmarkRead(b, func(r *Reader) { r.FieldsPerRecord = -1 }, benchmarkCSVData)
+}
+
+func BenchmarkReadLargeFields(b *testing.B) {
+ benchmarkRead(b, nil, 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/encoder.go b/src/encoding/gob/encoder.go
index d6c8fdd..40ec81b 100644
--- a/src/encoding/gob/encoder.go
+++ b/src/encoding/gob/encoder.go
@@ -215,6 +215,9 @@ func (enc *Encoder) sendTypeId(state *encoderState, ut *userTypeInfo) {
// guaranteeing that all necessary type information has been transmitted first.
// Passing a nil pointer to EncodeValue will panic, as they cannot be transmitted by gob.
func (enc *Encoder) EncodeValue(value reflect.Value) error {
+ if value.Kind() == reflect.Invalid {
+ return errors.New("gob: cannot encode nil value")
+ }
if value.Kind() == reflect.Ptr && value.IsNil() {
panic("gob: cannot encode nil pointer of type " + value.Type().String())
}
diff --git a/src/encoding/gob/encoder_test.go b/src/encoding/gob/encoder_test.go
index 22090a1..9256848 100644
--- a/src/encoding/gob/encoder_test.go
+++ b/src/encoding/gob/encoder_test.go
@@ -830,6 +830,20 @@ func TestPtrToMapOfMap(t *testing.T) {
}
}
+// Test that untyped nils generate an error, not a panic.
+// See Issue 16204.
+func TestCatchInvalidNilValue(t *testing.T) {
+ encodeErr, panicErr := encodeAndRecover(nil)
+ if panicErr != nil {
+ t.Fatalf("panicErr=%v, should not panic encoding untyped nil", panicErr)
+ }
+ if encodeErr == nil {
+ t.Errorf("got err=nil, want non-nil error when encoding untyped nil value")
+ } else if !strings.Contains(encodeErr.Error(), "nil value") {
+ t.Errorf("expected 'nil value' error; got err=%v", encodeErr)
+ }
+}
+
// A top-level nil pointer generates a panic with a helpful string-valued message.
func TestTopLevelNilPointer(t *testing.T) {
var ip *int
diff --git a/src/encoding/hex/example_test.go b/src/encoding/hex/example_test.go
new file mode 100644
index 0000000..3580757
--- /dev/null
+++ b/src/encoding/hex/example_test.go
@@ -0,0 +1,98 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package hex_test
+
+import (
+ "encoding/hex"
+ "fmt"
+ "log"
+ "os"
+)
+
+func ExampleEncode() {
+ src := []byte("Hello Gopher!")
+
+ dst := make([]byte, hex.EncodedLen(len(src)))
+ hex.Encode(dst, src)
+
+ fmt.Printf("%s\n", dst)
+
+ // Output:
+ // 48656c6c6f20476f7068657221
+}
+
+func ExampleDecode() {
+ src := []byte("48656c6c6f20476f7068657221")
+
+ dst := make([]byte, hex.DecodedLen(len(src)))
+ n, err := hex.Decode(dst, src)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ fmt.Printf("%s\n", dst[:n])
+
+ // Output:
+ // Hello Gopher!
+}
+
+func ExampleDecodeString() {
+ const s = "48656c6c6f20476f7068657221"
+ decoded, err := hex.DecodeString(s)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ fmt.Printf("%s\n", decoded)
+
+ // Output:
+ // Hello Gopher!
+}
+
+func ExampleDump() {
+ content := []byte("Go is an open source programming language.")
+
+ fmt.Printf("%s", hex.Dump(content))
+
+ // Output:
+ // 00000000 47 6f 20 69 73 20 61 6e 20 6f 70 65 6e 20 73 6f |Go is an open so|
+ // 00000010 75 72 63 65 20 70 72 6f 67 72 61 6d 6d 69 6e 67 |urce programming|
+ // 00000020 20 6c 61 6e 67 75 61 67 65 2e | language.|
+}
+
+func ExampleDumper() {
+ lines := []string{
+ "Go is an open source programming language.",
+ "\n",
+ "We encourage all Go users to subscribe to golang-announce.",
+ }
+
+ stdoutDumper := hex.Dumper(os.Stdout)
+
+ defer stdoutDumper.Close()
+
+ for _, line := range lines {
+ stdoutDumper.Write([]byte(line))
+ }
+
+ // Output:
+ // 00000000 47 6f 20 69 73 20 61 6e 20 6f 70 65 6e 20 73 6f |Go is an open so|
+ // 00000010 75 72 63 65 20 70 72 6f 67 72 61 6d 6d 69 6e 67 |urce programming|
+ // 00000020 20 6c 61 6e 67 75 61 67 65 2e 0a 57 65 20 65 6e | language..We en|
+ // 00000030 63 6f 75 72 61 67 65 20 61 6c 6c 20 47 6f 20 75 |courage all Go u|
+ // 00000040 73 65 72 73 20 74 6f 20 73 75 62 73 63 72 69 62 |sers to subscrib|
+ // 00000050 65 20 74 6f 20 67 6f 6c 61 6e 67 2d 61 6e 6e 6f |e to golang-anno|
+ // 00000060 75 6e 63 65 2e |unce.|
+}
+
+func ExampleEncodeToString() {
+ src := []byte("Hello")
+ encodedStr := hex.EncodeToString(src)
+
+ fmt.Printf("%s\n", encodedStr)
+
+ // Output:
+ // 48656c6c6f
+}
diff --git a/src/encoding/hex/hex.go b/src/encoding/hex/hex.go
index 73a2503..b43c1c4 100644
--- a/src/encoding/hex/hex.go
+++ b/src/encoding/hex/hex.go
@@ -12,9 +12,13 @@ import (
"io"
)
-const hextable = "0123456789abcdef"
+var hextable = [16]byte{
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+ 'a', 'b', 'c', 'd', 'e', 'f',
+}
// EncodedLen returns the length of an encoding of n source bytes.
+// Specifically, it returns n * 2.
func EncodedLen(n int) int { return n * 2 }
// Encode encodes src into EncodedLen(len(src))
@@ -40,12 +44,15 @@ func (e InvalidByteError) Error() string {
return fmt.Sprintf("encoding/hex: invalid byte: %#U", rune(e))
}
+// DecodedLen returns the length of a decoding of x source bytes.
+// Specifically, it returns x / 2.
func DecodedLen(x int) int { return x / 2 }
-// Decode decodes src into DecodedLen(len(src)) bytes, returning the actual
-// number of bytes written to dst.
+// Decode decodes src into DecodedLen(len(src)) bytes,
+// returning the actual number of bytes written to dst.
//
-// If Decode encounters invalid input, it returns an error describing the failure.
+// Decode expects that src contain only hexadecimal
+// characters and that src should have an even length.
func Decode(dst, src []byte) (int, error) {
if len(src)%2 == 1 {
return 0, ErrLength
diff --git a/src/encoding/hex/hex_test.go b/src/encoding/hex/hex_test.go
index b969636..64dabbd 100644
--- a/src/encoding/hex/hex_test.go
+++ b/src/encoding/hex/hex_test.go
@@ -6,6 +6,7 @@ package hex
import (
"bytes"
+ "fmt"
"testing"
)
@@ -151,3 +152,18 @@ var expectedHexDump = []byte(`00000000 1e 1f 20 21 22 23 24 25 26 27 28 29 2a
00000010 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d |./0123456789:;<=|
00000020 3e 3f 40 41 42 43 44 45 |>?@ABCDE|
`)
+
+var sink []byte
+
+func BenchmarkEncode(b *testing.B) {
+ for _, size := range []int{256, 1024, 4096, 16384} {
+ src := bytes.Repeat([]byte{2, 3, 5, 7, 9, 11, 13, 17}, size/8)
+ sink = make([]byte, 2*size)
+
+ b.Run(fmt.Sprintf("%v", size), func(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Encode(sink, src)
+ }
+ })
+ }
+}
diff --git a/src/encoding/json/decode.go b/src/encoding/json/decode.go
index 2eda875..77fc460 100644
--- a/src/encoding/json/decode.go
+++ b/src/encoding/json/decode.go
@@ -34,6 +34,13 @@ import (
// the value pointed at by the pointer. If the pointer is nil, Unmarshal
// allocates a new value for it to point to.
//
+// To unmarshal JSON into a value implementing the Unmarshaler interface,
+// Unmarshal calls that value's UnmarshalJSON method, including
+// when the input is a JSON null.
+// Otherwise, if the value implements encoding.TextUnmarshaler
+// and the input is a JSON quoted string, Unmarshal calls that value's
+// UnmarshalText method with the unquoted form of the string.
+//
// To unmarshal JSON into a struct, Unmarshal matches incoming object
// keys to the keys used by Marshal (either the struct field name or its tag),
// preferring an exact match but also accepting a case-insensitive match.
@@ -63,8 +70,8 @@ import (
//
// To unmarshal a JSON object into a map, Unmarshal first establishes a map to
// use. If the map is nil, Unmarshal allocates a new map. Otherwise Unmarshal
-// reuses the existing map, keeping existing entries. Unmarshal then stores key-
-// value pairs from the JSON object into the map. The map's key type must
+// reuses the existing map, keeping existing entries. Unmarshal then stores
+// key-value pairs from the JSON object into the map. The map's key type must
// either be a string, an integer, or implement encoding.TextUnmarshaler.
//
// If a JSON value is not appropriate for a given target type,
@@ -102,6 +109,9 @@ func Unmarshal(data []byte, v interface{}) error {
// The input can be assumed to be a valid encoding of
// a JSON value. UnmarshalJSON must copy the JSON data
// if it wishes to retain the data after returning.
+//
+// By convention, to approximate the behavior of Unmarshal itself,
+// Unmarshalers implement UnmarshalJSON([]byte("null")) as a no-op.
type Unmarshaler interface {
UnmarshalJSON([]byte) error
}
@@ -112,9 +122,14 @@ type UnmarshalTypeError struct {
Value string // description of JSON value - "bool", "array", "number -5"
Type reflect.Type // type of Go value it could not be assigned to
Offset int64 // error occurred after reading Offset bytes
+ Struct string // name of the struct type containing the field
+ Field string // name of the field holding the Go value
}
func (e *UnmarshalTypeError) Error() string {
+ if e.Struct != "" || e.Field != "" {
+ return "json: cannot unmarshal " + e.Value + " into Go struct field " + e.Struct + "." + e.Field + " of type " + e.Type.String()
+ }
return "json: cannot unmarshal " + e.Value + " into Go value of type " + e.Type.String()
}
@@ -248,10 +263,14 @@ func isValidNumber(s string) bool {
// decodeState represents the state while decoding a JSON value.
type decodeState struct {
- data []byte
- off int // read offset in data
- scan scanner
- nextscan scanner // for calls to nextValue
+ data []byte
+ off int // read offset in data
+ scan scanner
+ nextscan scanner // for calls to nextValue
+ errorContext struct { // provides context for type errors
+ Struct string
+ Field string
+ }
savedError error
useNumber bool
}
@@ -265,22 +284,37 @@ func (d *decodeState) init(data []byte) *decodeState {
d.data = data
d.off = 0
d.savedError = nil
+ d.errorContext.Struct = ""
+ d.errorContext.Field = ""
return d
}
// error aborts the decoding by panicking with err.
func (d *decodeState) error(err error) {
- panic(err)
+ panic(d.addErrorContext(err))
}
// saveError saves the first err it is called with,
// for reporting at the end of the unmarshal.
func (d *decodeState) saveError(err error) {
if d.savedError == nil {
- d.savedError = err
+ d.savedError = d.addErrorContext(err)
}
}
+// addErrorContext returns a new error enhanced with information from d.errorContext
+func (d *decodeState) addErrorContext(err error) error {
+ if d.errorContext.Struct != "" || d.errorContext.Field != "" {
+ switch err := err.(type) {
+ case *UnmarshalTypeError:
+ err.Struct = d.errorContext.Struct
+ err.Field = d.errorContext.Field
+ return err
+ }
+ }
+ return err
+}
+
// next cuts off and returns the next full JSON value in d.data[d.off:].
// The next value is known to be an object or array, not a literal.
func (d *decodeState) next() []byte {
@@ -434,8 +468,10 @@ func (d *decodeState) indirect(v reflect.Value, decodingNull bool) (Unmarshaler,
if u, ok := v.Interface().(Unmarshaler); ok {
return u, nil, reflect.Value{}
}
- if u, ok := v.Interface().(encoding.TextUnmarshaler); ok {
- return nil, u, reflect.Value{}
+ if !decodingNull {
+ if u, ok := v.Interface().(encoding.TextUnmarshaler); ok {
+ return nil, u, reflect.Value{}
+ }
}
}
v = v.Elem()
@@ -457,7 +493,7 @@ func (d *decodeState) array(v reflect.Value) {
return
}
if ut != nil {
- d.saveError(&UnmarshalTypeError{"array", v.Type(), int64(d.off)})
+ d.saveError(&UnmarshalTypeError{Value: "array", Type: v.Type(), Offset: int64(d.off)})
d.off--
d.next()
return
@@ -476,7 +512,7 @@ func (d *decodeState) array(v reflect.Value) {
// Otherwise it's invalid.
fallthrough
default:
- d.saveError(&UnmarshalTypeError{"array", v.Type(), int64(d.off)})
+ d.saveError(&UnmarshalTypeError{Value: "array", Type: v.Type(), Offset: int64(d.off)})
d.off--
d.next()
return
@@ -566,7 +602,7 @@ func (d *decodeState) object(v reflect.Value) {
return
}
if ut != nil {
- d.saveError(&UnmarshalTypeError{"object", v.Type(), int64(d.off)})
+ d.saveError(&UnmarshalTypeError{Value: "object", Type: v.Type(), Offset: int64(d.off)})
d.off--
d.next() // skip over { } in input
return
@@ -594,7 +630,7 @@ func (d *decodeState) object(v reflect.Value) {
reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
default:
if !reflect.PtrTo(t.Key()).Implements(textUnmarshalerType) {
- d.saveError(&UnmarshalTypeError{"object", v.Type(), int64(d.off)})
+ d.saveError(&UnmarshalTypeError{Value: "object", Type: v.Type(), Offset: int64(d.off)})
d.off--
d.next() // skip over { } in input
return
@@ -604,9 +640,9 @@ func (d *decodeState) object(v reflect.Value) {
v.Set(reflect.MakeMap(t))
}
case reflect.Struct:
-
+ // ok
default:
- d.saveError(&UnmarshalTypeError{"object", v.Type(), int64(d.off)})
+ d.saveError(&UnmarshalTypeError{Value: "object", Type: v.Type(), Offset: int64(d.off)})
d.off--
d.next() // skip over { } in input
return
@@ -671,6 +707,8 @@ func (d *decodeState) object(v reflect.Value) {
}
subv = subv.Field(i)
}
+ d.errorContext.Field = f.name
+ d.errorContext.Struct = v.Type().Name()
}
}
@@ -682,7 +720,6 @@ func (d *decodeState) object(v reflect.Value) {
d.error(errPhase)
}
- // Read value.
if destring {
switch qv := d.valueQuoted().(type) {
case nil:
@@ -714,7 +751,7 @@ func (d *decodeState) object(v reflect.Value) {
s := string(key)
n, err := strconv.ParseInt(s, 10, 64)
if err != nil || reflect.Zero(kt).OverflowInt(n) {
- d.saveError(&UnmarshalTypeError{"number " + s, kt, int64(start + 1)})
+ d.saveError(&UnmarshalTypeError{Value: "number " + s, Type: kt, Offset: int64(start + 1)})
return
}
kv = reflect.ValueOf(n).Convert(kt)
@@ -722,7 +759,7 @@ func (d *decodeState) object(v reflect.Value) {
s := string(key)
n, err := strconv.ParseUint(s, 10, 64)
if err != nil || reflect.Zero(kt).OverflowUint(n) {
- d.saveError(&UnmarshalTypeError{"number " + s, kt, int64(start + 1)})
+ d.saveError(&UnmarshalTypeError{Value: "number " + s, Type: kt, Offset: int64(start + 1)})
return
}
kv = reflect.ValueOf(n).Convert(kt)
@@ -741,6 +778,9 @@ func (d *decodeState) object(v reflect.Value) {
if op != scanObjectValue {
d.error(errPhase)
}
+
+ d.errorContext.Struct = ""
+ d.errorContext.Field = ""
}
}
@@ -767,7 +807,7 @@ func (d *decodeState) convertNumber(s string) (interface{}, error) {
}
f, err := strconv.ParseFloat(s, 64)
if err != nil {
- return nil, &UnmarshalTypeError{"number " + s, reflect.TypeOf(0.0), int64(d.off)}
+ return nil, &UnmarshalTypeError{Value: "number " + s, Type: reflect.TypeOf(0.0), Offset: int64(d.off)}
}
return f, nil
}
@@ -786,8 +826,8 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type()))
return
}
- wantptr := item[0] == 'n' // null
- u, ut, pv := d.indirect(v, wantptr)
+ isNull := item[0] == 'n' // null
+ u, ut, pv := d.indirect(v, isNull)
if u != nil {
err := u.UnmarshalJSON(item)
if err != nil {
@@ -800,7 +840,16 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
if fromQuoted {
d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type()))
} else {
- d.saveError(&UnmarshalTypeError{"string", v.Type(), int64(d.off)})
+ var val string
+ switch item[0] {
+ case 'n':
+ val = "null"
+ case 't', 'f':
+ val = "bool"
+ default:
+ val = "number"
+ }
+ d.saveError(&UnmarshalTypeError{Value: val, Type: v.Type(), Offset: int64(d.off)})
}
return
}
@@ -823,19 +872,31 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
switch c := item[0]; c {
case 'n': // null
+ // The main parser checks that only true and false can reach here,
+ // but if this was a quoted string input, it could be anything.
+ if fromQuoted && string(item) != "null" {
+ d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type()))
+ break
+ }
switch v.Kind() {
case reflect.Interface, reflect.Ptr, reflect.Map, reflect.Slice:
v.Set(reflect.Zero(v.Type()))
// otherwise, ignore null for primitives/string
}
case 't', 'f': // true, false
- value := c == 't'
+ value := item[0] == 't'
+ // The main parser checks that only true and false can reach here,
+ // but if this was a quoted string input, it could be anything.
+ if fromQuoted && string(item) != "true" && string(item) != "false" {
+ d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type()))
+ break
+ }
switch v.Kind() {
default:
if fromQuoted {
d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type()))
} else {
- d.saveError(&UnmarshalTypeError{"bool", v.Type(), int64(d.off)})
+ d.saveError(&UnmarshalTypeError{Value: "bool", Type: v.Type(), Offset: int64(d.off)})
}
case reflect.Bool:
v.SetBool(value)
@@ -843,7 +904,7 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
if v.NumMethod() == 0 {
v.Set(reflect.ValueOf(value))
} else {
- d.saveError(&UnmarshalTypeError{"bool", v.Type(), int64(d.off)})
+ d.saveError(&UnmarshalTypeError{Value: "bool", Type: v.Type(), Offset: int64(d.off)})
}
}
@@ -858,10 +919,10 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
}
switch v.Kind() {
default:
- d.saveError(&UnmarshalTypeError{"string", v.Type(), int64(d.off)})
+ d.saveError(&UnmarshalTypeError{Value: "string", Type: v.Type(), Offset: int64(d.off)})
case reflect.Slice:
if v.Type().Elem().Kind() != reflect.Uint8 {
- d.saveError(&UnmarshalTypeError{"string", v.Type(), int64(d.off)})
+ d.saveError(&UnmarshalTypeError{Value: "string", Type: v.Type(), Offset: int64(d.off)})
break
}
b := make([]byte, base64.StdEncoding.DecodedLen(len(s)))
@@ -877,7 +938,7 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
if v.NumMethod() == 0 {
v.Set(reflect.ValueOf(string(s)))
} else {
- d.saveError(&UnmarshalTypeError{"string", v.Type(), int64(d.off)})
+ d.saveError(&UnmarshalTypeError{Value: "string", Type: v.Type(), Offset: int64(d.off)})
}
}
@@ -902,7 +963,7 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
if fromQuoted {
d.error(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type()))
} else {
- d.error(&UnmarshalTypeError{"number", v.Type(), int64(d.off)})
+ d.error(&UnmarshalTypeError{Value: "number", Type: v.Type(), Offset: int64(d.off)})
}
case reflect.Interface:
n, err := d.convertNumber(s)
@@ -911,7 +972,7 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
break
}
if v.NumMethod() != 0 {
- d.saveError(&UnmarshalTypeError{"number", v.Type(), int64(d.off)})
+ d.saveError(&UnmarshalTypeError{Value: "number", Type: v.Type(), Offset: int64(d.off)})
break
}
v.Set(reflect.ValueOf(n))
@@ -919,7 +980,7 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
n, err := strconv.ParseInt(s, 10, 64)
if err != nil || v.OverflowInt(n) {
- d.saveError(&UnmarshalTypeError{"number " + s, v.Type(), int64(d.off)})
+ d.saveError(&UnmarshalTypeError{Value: "number " + s, Type: v.Type(), Offset: int64(d.off)})
break
}
v.SetInt(n)
@@ -927,7 +988,7 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
n, err := strconv.ParseUint(s, 10, 64)
if err != nil || v.OverflowUint(n) {
- d.saveError(&UnmarshalTypeError{"number " + s, v.Type(), int64(d.off)})
+ d.saveError(&UnmarshalTypeError{Value: "number " + s, Type: v.Type(), Offset: int64(d.off)})
break
}
v.SetUint(n)
@@ -935,7 +996,7 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
case reflect.Float32, reflect.Float64:
n, err := strconv.ParseFloat(s, v.Type().Bits())
if err != nil || v.OverflowFloat(n) {
- d.saveError(&UnmarshalTypeError{"number " + s, v.Type(), int64(d.off)})
+ d.saveError(&UnmarshalTypeError{Value: "number " + s, Type: v.Type(), Offset: int64(d.off)})
break
}
v.SetFloat(n)
diff --git a/src/encoding/json/decode_test.go b/src/encoding/json/decode_test.go
index 255ff5c..bd38ddd 100644
--- a/src/encoding/json/decode_test.go
+++ b/src/encoding/json/decode_test.go
@@ -11,6 +11,7 @@ import (
"fmt"
"image"
"math"
+ "math/big"
"net"
"reflect"
"strconv"
@@ -33,6 +34,11 @@ type V struct {
F1 interface{}
F2 int32
F3 Number
+ F4 *VOuter
+}
+
+type VOuter struct {
+ V V
}
// ifaceNumAsFloat64/ifaceNumAsNumber are used to test unmarshaling with and
@@ -374,6 +380,10 @@ type unmarshalTest struct {
golden bool
}
+type B struct {
+ B bool `json:",string"`
+}
+
var unmarshalTests = []unmarshalTest{
// basic types
{in: `true`, ptr: new(bool), out: true},
@@ -389,7 +399,7 @@ var unmarshalTests = []unmarshalTest{
{in: `"g-clef: \uD834\uDD1E"`, ptr: new(string), out: "g-clef: \U0001D11E"},
{in: `"invalid: \uD834x\uDD1E"`, ptr: new(string), out: "invalid: \uFFFDx\uFFFD"},
{in: "null", ptr: new(interface{}), out: nil},
- {in: `{"X": [1,2,3], "Y": 4}`, ptr: new(T), out: T{Y: 4}, err: &UnmarshalTypeError{"array", reflect.TypeOf(""), 7}},
+ {in: `{"X": [1,2,3], "Y": 4}`, ptr: new(T), out: T{Y: 4}, err: &UnmarshalTypeError{"array", reflect.TypeOf(""), 7, "T", "X"}},
{in: `{"x": 1}`, ptr: new(tx), out: tx{}},
{in: `{"F1":1,"F2":2,"F3":3}`, ptr: new(V), out: V{F1: float64(1), F2: int32(2), F3: Number("3")}},
{in: `{"F1":1,"F2":2,"F3":3}`, ptr: new(V), out: V{F1: Number("1"), F2: int32(2), F3: Number("3")}, useNumber: true},
@@ -504,22 +514,22 @@ var unmarshalTests = []unmarshalTest{
{
in: `{"abc":"abc"}`,
ptr: new(map[int]string),
- err: &UnmarshalTypeError{"number abc", reflect.TypeOf(0), 2},
+ err: &UnmarshalTypeError{Value: "number abc", Type: reflect.TypeOf(0), Offset: 2},
},
{
in: `{"256":"abc"}`,
ptr: new(map[uint8]string),
- err: &UnmarshalTypeError{"number 256", reflect.TypeOf(uint8(0)), 2},
+ err: &UnmarshalTypeError{Value: "number 256", Type: reflect.TypeOf(uint8(0)), Offset: 2},
},
{
in: `{"128":"abc"}`,
ptr: new(map[int8]string),
- err: &UnmarshalTypeError{"number 128", reflect.TypeOf(int8(0)), 2},
+ err: &UnmarshalTypeError{Value: "number 128", Type: reflect.TypeOf(int8(0)), Offset: 2},
},
{
in: `{"-1":"abc"}`,
ptr: new(map[uint8]string),
- err: &UnmarshalTypeError{"number -1", reflect.TypeOf(uint8(0)), 2},
+ err: &UnmarshalTypeError{Value: "number -1", Type: reflect.TypeOf(uint8(0)), Offset: 2},
},
// Map keys can be encoding.TextUnmarshalers.
@@ -653,12 +663,12 @@ var unmarshalTests = []unmarshalTest{
{
in: `{"2009-11-10T23:00:00Z": "hello world"}`,
ptr: &map[Point]string{},
- err: &UnmarshalTypeError{"object", reflect.TypeOf(map[Point]string{}), 1},
+ err: &UnmarshalTypeError{Value: "object", Type: reflect.TypeOf(map[Point]string{}), Offset: 1},
},
{
in: `{"asdf": "hello world"}`,
ptr: &map[unmarshaler]string{},
- err: &UnmarshalTypeError{"object", reflect.TypeOf(map[unmarshaler]string{}), 1},
+ err: &UnmarshalTypeError{Value: "object", Type: reflect.TypeOf(map[unmarshaler]string{}), Offset: 1},
},
// related to issue 13783.
@@ -738,6 +748,51 @@ var unmarshalTests = []unmarshalTest{
out: []intWithPtrMarshalText{1, 2, 3},
golden: true,
},
+
+ {in: `0.000001`, ptr: new(float64), out: 0.000001, golden: true},
+ {in: `1e-7`, ptr: new(float64), out: 1e-7, golden: true},
+ {in: `100000000000000000000`, ptr: new(float64), out: 100000000000000000000.0, golden: true},
+ {in: `1e+21`, ptr: new(float64), out: 1e21, golden: true},
+ {in: `-0.000001`, ptr: new(float64), out: -0.000001, golden: true},
+ {in: `-1e-7`, ptr: new(float64), out: -1e-7, golden: true},
+ {in: `-100000000000000000000`, ptr: new(float64), out: -100000000000000000000.0, golden: true},
+ {in: `-1e+21`, ptr: new(float64), out: -1e21, golden: true},
+ {in: `999999999999999900000`, ptr: new(float64), out: 999999999999999900000.0, golden: true},
+ {in: `9007199254740992`, ptr: new(float64), out: 9007199254740992.0, golden: true},
+ {in: `9007199254740993`, ptr: new(float64), out: 9007199254740992.0, golden: false},
+
+ {
+ in: `{"V": {"F2": "hello"}}`,
+ ptr: new(VOuter),
+ err: &UnmarshalTypeError{
+ Value: "string",
+ Struct: "V",
+ Field: "F2",
+ Type: reflect.TypeOf(int32(0)),
+ Offset: 20,
+ },
+ },
+ {
+ in: `{"V": {"F4": {}, "F2": "hello"}}`,
+ ptr: new(VOuter),
+ err: &UnmarshalTypeError{
+ Value: "string",
+ Struct: "V",
+ Field: "F2",
+ Type: reflect.TypeOf(int32(0)),
+ Offset: 30,
+ },
+ },
+
+ // issue 15146.
+ // invalid inputs in wrongStringTests below.
+ {in: `{"B":"true"}`, ptr: new(B), out: B{true}, golden: true},
+ {in: `{"B":"false"}`, ptr: new(B), out: B{false}, golden: true},
+ {in: `{"B": "maybe"}`, ptr: new(B), err: errors.New(`json: invalid use of ,string struct tag, trying to unmarshal "maybe" into bool`)},
+ {in: `{"B": "tru"}`, ptr: new(B), err: errors.New(`json: invalid use of ,string struct tag, trying to unmarshal "tru" into bool`)},
+ {in: `{"B": "False"}`, ptr: new(B), err: errors.New(`json: invalid use of ,string struct tag, trying to unmarshal "False" into bool`)},
+ {in: `{"B": "null"}`, ptr: new(B), out: B{false}},
+ {in: `{"B": "nul"}`, ptr: new(B), err: errors.New(`json: invalid use of ,string struct tag, trying to unmarshal "nul" into bool`)},
}
func TestMarshal(t *testing.T) {
@@ -1470,40 +1525,148 @@ func TestInterfaceSet(t *testing.T) {
}
}
+type NullTest struct {
+ Bool bool
+ Int int
+ Int8 int8
+ Int16 int16
+ Int32 int32
+ Int64 int64
+ Uint uint
+ Uint8 uint8
+ Uint16 uint16
+ Uint32 uint32
+ Uint64 uint64
+ Float32 float32
+ Float64 float64
+ String string
+ PBool *bool
+ Map map[string]string
+ Slice []string
+ Interface interface{}
+
+ PRaw *RawMessage
+ PTime *time.Time
+ PBigInt *big.Int
+ PText *MustNotUnmarshalText
+ PBuffer *bytes.Buffer // has methods, just not relevant ones
+ PStruct *struct{}
+
+ Raw RawMessage
+ Time time.Time
+ BigInt big.Int
+ Text MustNotUnmarshalText
+ Buffer bytes.Buffer
+ Struct struct{}
+}
+
+type NullTestStrings struct {
+ Bool bool `json:",string"`
+ Int int `json:",string"`
+ Int8 int8 `json:",string"`
+ Int16 int16 `json:",string"`
+ Int32 int32 `json:",string"`
+ Int64 int64 `json:",string"`
+ Uint uint `json:",string"`
+ Uint8 uint8 `json:",string"`
+ Uint16 uint16 `json:",string"`
+ Uint32 uint32 `json:",string"`
+ Uint64 uint64 `json:",string"`
+ Float32 float32 `json:",string"`
+ Float64 float64 `json:",string"`
+ String string `json:",string"`
+ PBool *bool `json:",string"`
+ Map map[string]string `json:",string"`
+ Slice []string `json:",string"`
+ Interface interface{} `json:",string"`
+
+ PRaw *RawMessage `json:",string"`
+ PTime *time.Time `json:",string"`
+ PBigInt *big.Int `json:",string"`
+ PText *MustNotUnmarshalText `json:",string"`
+ PBuffer *bytes.Buffer `json:",string"`
+ PStruct *struct{} `json:",string"`
+
+ Raw RawMessage `json:",string"`
+ Time time.Time `json:",string"`
+ BigInt big.Int `json:",string"`
+ Text MustNotUnmarshalText `json:",string"`
+ Buffer bytes.Buffer `json:",string"`
+ Struct struct{} `json:",string"`
+}
+
// JSON null values should be ignored for primitives and string values instead of resulting in an error.
// Issue 2540
func TestUnmarshalNulls(t *testing.T) {
+ // Unmarshal docs:
+ // 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
+ // ``not present,'' unmarshaling a JSON null into any other Go type has no effect
+ // on the value and produces no error.
+
jsonData := []byte(`{
- "Bool" : null,
- "Int" : null,
- "Int8" : null,
- "Int16" : null,
- "Int32" : null,
- "Int64" : null,
- "Uint" : null,
- "Uint8" : null,
- "Uint16" : null,
- "Uint32" : null,
- "Uint64" : null,
- "Float32" : null,
- "Float64" : null,
- "String" : null}`)
-
- nulls := All{
- Bool: true,
- Int: 2,
- Int8: 3,
- Int16: 4,
- Int32: 5,
- Int64: 6,
- Uint: 7,
- Uint8: 8,
- Uint16: 9,
- Uint32: 10,
- Uint64: 11,
- Float32: 12.1,
- Float64: 13.1,
- String: "14"}
+ "Bool" : null,
+ "Int" : null,
+ "Int8" : null,
+ "Int16" : null,
+ "Int32" : null,
+ "Int64" : null,
+ "Uint" : null,
+ "Uint8" : null,
+ "Uint16" : null,
+ "Uint32" : null,
+ "Uint64" : null,
+ "Float32" : null,
+ "Float64" : null,
+ "String" : null,
+ "PBool": null,
+ "Map": null,
+ "Slice": null,
+ "Interface": null,
+ "PRaw": null,
+ "PTime": null,
+ "PBigInt": null,
+ "PText": null,
+ "PBuffer": null,
+ "PStruct": null,
+ "Raw": null,
+ "Time": null,
+ "BigInt": null,
+ "Text": null,
+ "Buffer": null,
+ "Struct": null
+ }`)
+ nulls := NullTest{
+ Bool: true,
+ Int: 2,
+ Int8: 3,
+ Int16: 4,
+ Int32: 5,
+ Int64: 6,
+ Uint: 7,
+ Uint8: 8,
+ Uint16: 9,
+ Uint32: 10,
+ Uint64: 11,
+ Float32: 12.1,
+ Float64: 13.1,
+ String: "14",
+ PBool: new(bool),
+ Map: map[string]string{},
+ Slice: []string{},
+ Interface: new(MustNotUnmarshalJSON),
+ PRaw: new(RawMessage),
+ PTime: new(time.Time),
+ PBigInt: new(big.Int),
+ PText: new(MustNotUnmarshalText),
+ PStruct: new(struct{}),
+ PBuffer: new(bytes.Buffer),
+ Raw: RawMessage("123"),
+ Time: time.Unix(123456789, 0),
+ BigInt: *big.NewInt(123),
+ }
+
+ before := nulls.Time.String()
err := Unmarshal(jsonData, &nulls)
if err != nil {
@@ -1512,9 +1675,61 @@ func TestUnmarshalNulls(t *testing.T) {
if !nulls.Bool || nulls.Int != 2 || nulls.Int8 != 3 || nulls.Int16 != 4 || nulls.Int32 != 5 || nulls.Int64 != 6 ||
nulls.Uint != 7 || nulls.Uint8 != 8 || nulls.Uint16 != 9 || nulls.Uint32 != 10 || nulls.Uint64 != 11 ||
nulls.Float32 != 12.1 || nulls.Float64 != 13.1 || nulls.String != "14" {
-
t.Errorf("Unmarshal of null values affected primitives")
}
+
+ if nulls.PBool != nil {
+ t.Errorf("Unmarshal of null did not clear nulls.PBool")
+ }
+ if nulls.Map != nil {
+ t.Errorf("Unmarshal of null did not clear nulls.Map")
+ }
+ if nulls.Slice != nil {
+ t.Errorf("Unmarshal of null did not clear nulls.Slice")
+ }
+ if nulls.Interface != nil {
+ t.Errorf("Unmarshal of null did not clear nulls.Interface")
+ }
+ if nulls.PRaw != nil {
+ t.Errorf("Unmarshal of null did not clear nulls.PRaw")
+ }
+ if nulls.PTime != nil {
+ t.Errorf("Unmarshal of null did not clear nulls.PTime")
+ }
+ if nulls.PBigInt != nil {
+ t.Errorf("Unmarshal of null did not clear nulls.PBigInt")
+ }
+ if nulls.PText != nil {
+ t.Errorf("Unmarshal of null did not clear nulls.PText")
+ }
+ if nulls.PBuffer != nil {
+ t.Errorf("Unmarshal of null did not clear nulls.PBuffer")
+ }
+ if nulls.PStruct != nil {
+ t.Errorf("Unmarshal of null did not clear nulls.PStruct")
+ }
+
+ if string(nulls.Raw) != "null" {
+ t.Errorf("Unmarshal of RawMessage null did not record null: %v", string(nulls.Raw))
+ }
+ if nulls.Time.String() != before {
+ t.Errorf("Unmarshal of time.Time null set time to %v", nulls.Time.String())
+ }
+ if nulls.BigInt.String() != "123" {
+ t.Errorf("Unmarshal of big.Int null set int to %v", nulls.BigInt.String())
+ }
+}
+
+type MustNotUnmarshalJSON struct{}
+
+func (x MustNotUnmarshalJSON) UnmarshalJSON(data []byte) error {
+ return errors.New("MustNotUnmarshalJSON was used")
+}
+
+type MustNotUnmarshalText struct{}
+
+func (x MustNotUnmarshalText) UnmarshalText(text []byte) error {
+ return errors.New("MustNotUnmarshalText was used")
}
func TestStringKind(t *testing.T) {
@@ -1540,8 +1755,8 @@ func TestStringKind(t *testing.T) {
}
}
-// Custom types with []byte as underlying type could not be marshalled
-// and then unmarshalled.
+// Custom types with []byte as underlying type could not be marshaled
+// and then unmarshaled.
// Issue 8962.
func TestByteKind(t *testing.T) {
type byteKind []byte
@@ -1753,7 +1968,7 @@ var invalidUnmarshalTextTests = []struct {
{nil, "json: Unmarshal(nil)"},
{struct{}{}, "json: Unmarshal(non-pointer struct {})"},
{(*int)(nil), "json: Unmarshal(nil *int)"},
- {new(net.IP), "json: cannot unmarshal string into Go value of type *net.IP"},
+ {new(net.IP), "json: cannot unmarshal number into Go value of type *net.IP"},
}
func TestInvalidUnmarshalText(t *testing.T) {
diff --git a/src/encoding/json/encode.go b/src/encoding/json/encode.go
index 6bb6de8..8f21dda 100644
--- a/src/encoding/json/encode.go
+++ b/src/encoding/json/encode.go
@@ -34,7 +34,7 @@ import (
// and is not a nil pointer, Marshal calls its MarshalJSON method
// to produce JSON. If no MarshalJSON method is present but the
// value implements encoding.TextMarshaler instead, Marshal calls
-// its MarshalText method.
+// its MarshalText method and encodes the result as a JSON string.
// The nil pointer exception is not strictly necessary
// but mimics a similar, necessary exception in the behavior of
// UnmarshalJSON.
@@ -50,25 +50,33 @@ import (
// The angle brackets "<" and ">" are escaped to "\u003c" and "\u003e"
// to keep some browsers from misinterpreting JSON output as HTML.
// Ampersand "&" is also escaped to "\u0026" for the same reason.
-// This escaping can be disabled using an Encoder with DisableHTMLEscaping.
+// This escaping can be disabled using an Encoder that had SetEscapeHTML(false)
+// called on it.
//
// Array and slice values encode as JSON arrays, except that
// []byte encodes as a base64-encoded string, and a nil slice
// encodes as the null JSON value.
//
-// Struct values encode as JSON objects. Each exported struct field
-// becomes a member of the object unless
-// - the field's tag is "-", or
-// - the field is empty and its tag specifies the "omitempty" option.
-// The empty values are false, 0, any
-// nil pointer or interface value, and any array, slice, map, or string of
-// length zero. The object's default key string is the struct field name
-// but can be specified in the struct field's tag value. The "json" key in
-// the struct field's tag value is the key name, followed by an optional comma
-// and options. Examples:
+// Struct values encode as JSON objects.
+// Each exported struct field becomes a member of the object, using the
+// field name as the object key, unless the field is omitted for one of the
+// reasons given below.
//
-// // Field is ignored by this package.
-// Field int `json:"-"`
+// The encoding of each struct field can be customized by the format string
+// stored under the "json" key in the struct field's tag.
+// The format string gives the name of the field, possibly followed by a
+// comma-separated list of options. The name may be empty in order to
+// specify options without overriding the default field name.
+//
+// The "omitempty" option specifies that the field should be omitted
+// from the encoding if the field has an empty value, defined as
+// false, 0, a nil pointer, a nil interface value, and any empty array,
+// slice, map, or string.
+//
+// As a special case, if the field tag is "-", the field is always omitted.
+// Note that a field with name "-" can still be generated using the tag "-,".
+//
+// Examples of struct field tags and their meanings:
//
// // Field appears in JSON as key "myName".
// Field int `json:"myName"`
@@ -83,6 +91,12 @@ import (
// // Note the leading comma.
// Field int `json:",omitempty"`
//
+// // Field is ignored by this package.
+// Field int `json:"-"`
+//
+// // Field appears in JSON as key "-".
+// Field int `json:"-,"`
+//
// The "string" option signals that a field is stored as JSON inside a
// JSON-encoded string. It applies only to fields of string, floating point,
// integer, or boolean types. This extra level of encoding is sometimes used
@@ -110,7 +124,9 @@ import (
//
// 1) Of those fields, if any are JSON-tagged, only tagged fields are considered,
// even if there are multiple untagged fields that would otherwise conflict.
+//
// 2) If there is exactly one field (tagged or not according to the first rule), that is selected.
+//
// 3) Otherwise there are multiple fields, and all are ignored; no error occurs.
//
// Handling of anonymous struct fields is new in Go 1.1.
@@ -427,7 +443,11 @@ func marshalerEncoder(e *encodeState, v reflect.Value, opts encOpts) {
e.WriteString("null")
return
}
- m := v.Interface().(Marshaler)
+ m, ok := v.Interface().(Marshaler)
+ if !ok {
+ e.WriteString("null")
+ return
+ }
b, err := m.MarshalJSON()
if err == nil {
// copy JSON into buffer, checking validity.
@@ -525,7 +545,31 @@ func (bits floatEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) {
if math.IsInf(f, 0) || math.IsNaN(f) {
e.error(&UnsupportedValueError{v, strconv.FormatFloat(f, 'g', -1, int(bits))})
}
- b := strconv.AppendFloat(e.scratch[:0], f, 'g', -1, int(bits))
+
+ // Convert as if by ES6 number to string conversion.
+ // This matches most other JSON generators.
+ // See golang.org/issue/6384 and golang.org/issue/14135.
+ // Like fmt %g, but the exponent cutoffs are different
+ // and exponents themselves are not padded to two digits.
+ b := e.scratch[:0]
+ abs := math.Abs(f)
+ fmt := byte('f')
+ // Note: Must use float32 comparisons for underlying float32 value to get precise cutoffs right.
+ if abs != 0 {
+ if bits == 64 && (abs < 1e-6 || abs >= 1e21) || bits == 32 && (float32(abs) < 1e-6 || float32(abs) >= 1e21) {
+ fmt = 'e'
+ }
+ }
+ b = strconv.AppendFloat(b, f, fmt, -1, int(bits))
+ if fmt == 'e' {
+ // clean up e-09 to e-9
+ n := len(b)
+ if n >= 4 && b[n-4] == 'e' && b[n-3] == '-' && b[n-2] == '0' {
+ b[n-2] = b[n-1]
+ b = b[:n-1]
+ }
+ }
+
if opts.quoted {
e.WriteByte('"')
}
@@ -635,7 +679,7 @@ func (me *mapEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) {
e.error(&MarshalerError{v.Type(), err})
}
}
- sort.Sort(byString(sv))
+ sort.Slice(sv, func(i, j int) bool { return sv[i].s < sv[j].s })
for i, kv := range sv {
if i > 0 {
@@ -834,15 +878,6 @@ func (w *reflectWithString) resolve() error {
panic("unexpected map key type")
}
-// byString is a slice of reflectWithString where the reflect.Value is either
-// a string or an encoding.TextMarshaler.
-// It implements the methods to sort by string.
-type byString []reflectWithString
-
-func (sv byString) Len() int { return len(sv) }
-func (sv byString) Swap(i, j int) { sv[i], sv[j] = sv[j], sv[i] }
-func (sv byString) Less(i, j int) bool { return sv[i].s < sv[j].s }
-
// NOTE: keep in sync with stringBytes below.
func (e *encodeState) string(s string, escapeHTML bool) int {
len0 := e.Len()
@@ -850,8 +885,7 @@ func (e *encodeState) string(s string, escapeHTML bool) int {
start := 0
for i := 0; i < len(s); {
if b := s[i]; b < utf8.RuneSelf {
- if 0x20 <= b && b != '\\' && b != '"' &&
- (!escapeHTML || b != '<' && b != '>' && b != '&') {
+ if htmlSafeSet[b] || (!escapeHTML && safeSet[b]) {
i++
continue
}
@@ -928,8 +962,7 @@ func (e *encodeState) stringBytes(s []byte, escapeHTML bool) int {
start := 0
for i := 0; i < len(s); {
if b := s[i]; b < utf8.RuneSelf {
- if 0x20 <= b && b != '\\' && b != '"' &&
- (!escapeHTML || b != '<' && b != '>' && b != '&') {
+ if htmlSafeSet[b] || (!escapeHTML && safeSet[b]) {
i++
continue
}
@@ -1018,28 +1051,6 @@ func fillField(f field) field {
return f
}
-// byName sorts field by name, breaking ties with depth,
-// then breaking ties with "name came from json tag", then
-// breaking ties with index sequence.
-type byName []field
-
-func (x byName) Len() int { return len(x) }
-
-func (x byName) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
-
-func (x byName) Less(i, j int) bool {
- if x[i].name != x[j].name {
- return x[i].name < x[j].name
- }
- if len(x[i].index) != len(x[j].index) {
- return len(x[i].index) < len(x[j].index)
- }
- if x[i].tag != x[j].tag {
- return x[i].tag
- }
- return byIndex(x).Less(i, j)
-}
-
// byIndex sorts field by index sequence.
type byIndex []field
@@ -1157,7 +1168,22 @@ func typeFields(t reflect.Type) []field {
}
}
- sort.Sort(byName(fields))
+ sort.Slice(fields, func(i, j int) bool {
+ x := fields
+ // sort field by name, breaking ties with depth, then
+ // breaking ties with "name came from json tag", then
+ // breaking ties with index sequence.
+ if x[i].name != x[j].name {
+ return x[i].name < x[j].name
+ }
+ if len(x[i].index) != len(x[j].index) {
+ return len(x[i].index) < len(x[j].index)
+ }
+ if x[i].tag != x[j].tag {
+ return x[i].tag
+ }
+ return byIndex(x).Less(i, j)
+ })
// Delete all fields that are hidden by the Go rules for embedded fields,
// except that fields with JSON tags are promoted.
diff --git a/src/encoding/json/encode_test.go b/src/encoding/json/encode_test.go
index b484022..6d574cf 100644
--- a/src/encoding/json/encode_test.go
+++ b/src/encoding/json/encode_test.go
@@ -7,8 +7,11 @@ package json
import (
"bytes"
"fmt"
+ "log"
"math"
"reflect"
+ "regexp"
+ "strconv"
"testing"
"unicode"
)
@@ -290,6 +293,44 @@ type BugX struct {
BugB
}
+// Issue 16042. Even if a nil interface value is passed in
+// as long as it implements MarshalJSON, it should be marshaled.
+type nilMarshaler string
+
+func (nm *nilMarshaler) MarshalJSON() ([]byte, error) {
+ if nm == nil {
+ return Marshal("0zenil0")
+ }
+ return Marshal("zenil:" + string(*nm))
+}
+
+// Issue 16042.
+func TestNilMarshal(t *testing.T) {
+ testCases := []struct {
+ v interface{}
+ want string
+ }{
+ {v: nil, want: `null`},
+ {v: new(float64), want: `0`},
+ {v: []interface{}(nil), want: `null`},
+ {v: []string(nil), want: `null`},
+ {v: map[string]string(nil), want: `null`},
+ {v: []byte(nil), want: `null`},
+ {v: struct{ M string }{"gopher"}, want: `{"M":"gopher"}`},
+ {v: struct{ M Marshaler }{}, want: `{"M":null}`},
+ {v: struct{ M Marshaler }{(*nilMarshaler)(nil)}, want: `{"M":"0zenil0"}`},
+ {v: struct{ M interface{} }{(*nilMarshaler)(nil)}, want: `{"M":null}`},
+ }
+
+ for _, tt := range testCases {
+ out, err := Marshal(tt.v)
+ if err != nil || string(out) != tt.want {
+ t.Errorf("Marshal(%#v) = %#q, %#v, want %#q, nil", tt.v, out, err, tt.want)
+ continue
+ }
+ }
+}
+
// Issue 5245.
func TestEmbeddedBug(t *testing.T) {
v := BugB{
@@ -375,6 +416,7 @@ func TestDuplicatedFieldDisappears(t *testing.T) {
}
func TestStringBytes(t *testing.T) {
+ t.Parallel()
// Test that encodeState.stringBytes and encodeState.string use the same encoding.
var r []rune
for i := '\u0000'; i <= unicode.MaxRune; i++ {
@@ -418,30 +460,6 @@ func TestStringBytes(t *testing.T) {
}
}
-func TestIssue6458(t *testing.T) {
- type Foo struct {
- M RawMessage
- }
- x := Foo{RawMessage(`"foo"`)}
-
- b, err := Marshal(&x)
- if err != nil {
- t.Fatal(err)
- }
- if want := `{"M":"foo"}`; string(b) != want {
- t.Errorf("Marshal(&x) = %#q; want %#q", b, want)
- }
-
- b, err = Marshal(x)
- if err != nil {
- t.Fatal(err)
- }
-
- if want := `{"M":"ImZvbyI="}`; string(b) != want {
- t.Errorf("Marshal(x) = %#q; want %#q", b, want)
- }
-}
-
func TestIssue10281(t *testing.T) {
type Foo struct {
N Number
@@ -483,7 +501,7 @@ func TestEncodePointerString(t *testing.T) {
t.Fatalf("Unmarshal: %v", err)
}
if back.N == nil {
- t.Fatalf("Unmarshalled nil N field")
+ t.Fatalf("Unmarshaled nil N field")
}
if *back.N != 42 {
t.Fatalf("*N = %d; want 42", *back.N)
@@ -611,3 +629,208 @@ func TestTextMarshalerMapKeysAreSorted(t *testing.T) {
t.Errorf("Marshal map with text.Marshaler keys: got %#q, want %#q", b, want)
}
}
+
+var re = regexp.MustCompile
+
+// syntactic checks on form of marshaled floating point numbers.
+var badFloatREs = []*regexp.Regexp{
+ re(`p`), // no binary exponential notation
+ re(`^\+`), // no leading + sign
+ re(`^-?0[^.]`), // no unnecessary leading zeros
+ re(`^-?\.`), // leading zero required before decimal point
+ re(`\.(e|$)`), // no trailing decimal
+ re(`\.[0-9]+0(e|$)`), // no trailing zero in fraction
+ re(`^-?(0|[0-9]{2,})\..*e`), // exponential notation must have normalized mantissa
+ re(`e[0-9]`), // positive exponent must be signed
+ re(`e[+-]0`), // exponent must not have leading zeros
+ re(`e-[1-6]$`), // not tiny enough for exponential notation
+ re(`e+(.|1.|20)$`), // not big enough for exponential notation
+ re(`^-?0\.0000000`), // too tiny, should use exponential notation
+ re(`^-?[0-9]{22}`), // too big, should use exponential notation
+ re(`[1-9][0-9]{16}[1-9]`), // too many significant digits in integer
+ re(`[1-9][0-9.]{17}[1-9]`), // too many significant digits in decimal
+ // below here for float32 only
+ re(`[1-9][0-9]{8}[1-9]`), // too many significant digits in integer
+ re(`[1-9][0-9.]{9}[1-9]`), // too many significant digits in decimal
+}
+
+func TestMarshalFloat(t *testing.T) {
+ t.Parallel()
+ nfail := 0
+ test := func(f float64, bits int) {
+ vf := interface{}(f)
+ if bits == 32 {
+ f = float64(float32(f)) // round
+ vf = float32(f)
+ }
+ bout, err := Marshal(vf)
+ if err != nil {
+ t.Errorf("Marshal(%T(%g)): %v", vf, vf, err)
+ nfail++
+ return
+ }
+ out := string(bout)
+
+ // result must convert back to the same float
+ g, err := strconv.ParseFloat(out, bits)
+ if err != nil {
+ t.Errorf("Marshal(%T(%g)) = %q, cannot parse back: %v", vf, vf, out, err)
+ nfail++
+ return
+ }
+ if f != g || fmt.Sprint(f) != fmt.Sprint(g) { // fmt.Sprint handles ±0
+ t.Errorf("Marshal(%T(%g)) = %q (is %g, not %g)", vf, vf, out, float32(g), vf)
+ nfail++
+ return
+ }
+
+ bad := badFloatREs
+ if bits == 64 {
+ bad = bad[:len(bad)-2]
+ }
+ for _, re := range bad {
+ if re.MatchString(out) {
+ t.Errorf("Marshal(%T(%g)) = %q, must not match /%s/", vf, vf, out, re)
+ nfail++
+ return
+ }
+ }
+ }
+
+ var (
+ bigger = math.Inf(+1)
+ smaller = math.Inf(-1)
+ )
+
+ var digits = "1.2345678901234567890123"
+ for i := len(digits); i >= 2; i-- {
+ for exp := -30; exp <= 30; exp++ {
+ for _, sign := range "+-" {
+ for bits := 32; bits <= 64; bits += 32 {
+ s := fmt.Sprintf("%c%se%d", sign, digits[:i], exp)
+ f, err := strconv.ParseFloat(s, bits)
+ if err != nil {
+ log.Fatal(err)
+ }
+ next := math.Nextafter
+ if bits == 32 {
+ next = func(g, h float64) float64 {
+ return float64(math.Nextafter32(float32(g), float32(h)))
+ }
+ }
+ test(f, bits)
+ test(next(f, bigger), bits)
+ test(next(f, smaller), bits)
+ if nfail > 50 {
+ t.Fatalf("stopping test early")
+ }
+ }
+ }
+ }
+ }
+ test(0, 64)
+ test(math.Copysign(0, -1), 64)
+ test(0, 32)
+ test(math.Copysign(0, -1), 32)
+}
+
+func TestMarshalRawMessageValue(t *testing.T) {
+ type (
+ T1 struct {
+ M RawMessage `json:",omitempty"`
+ }
+ T2 struct {
+ M *RawMessage `json:",omitempty"`
+ }
+ )
+
+ var (
+ rawNil = RawMessage(nil)
+ rawEmpty = RawMessage([]byte{})
+ rawText = RawMessage([]byte(`"foo"`))
+ )
+
+ tests := []struct {
+ in interface{}
+ want string
+ ok bool
+ }{
+ // Test with nil RawMessage.
+ {rawNil, "null", true},
+ {&rawNil, "null", true},
+ {[]interface{}{rawNil}, "[null]", true},
+ {&[]interface{}{rawNil}, "[null]", true},
+ {[]interface{}{&rawNil}, "[null]", true},
+ {&[]interface{}{&rawNil}, "[null]", true},
+ {struct{ M RawMessage }{rawNil}, `{"M":null}`, true},
+ {&struct{ M RawMessage }{rawNil}, `{"M":null}`, true},
+ {struct{ M *RawMessage }{&rawNil}, `{"M":null}`, true},
+ {&struct{ M *RawMessage }{&rawNil}, `{"M":null}`, true},
+ {map[string]interface{}{"M": rawNil}, `{"M":null}`, true},
+ {&map[string]interface{}{"M": rawNil}, `{"M":null}`, true},
+ {map[string]interface{}{"M": &rawNil}, `{"M":null}`, true},
+ {&map[string]interface{}{"M": &rawNil}, `{"M":null}`, true},
+ {T1{rawNil}, "{}", true},
+ {T2{&rawNil}, `{"M":null}`, true},
+ {&T1{rawNil}, "{}", true},
+ {&T2{&rawNil}, `{"M":null}`, true},
+
+ // Test with empty, but non-nil, RawMessage.
+ {rawEmpty, "", false},
+ {&rawEmpty, "", false},
+ {[]interface{}{rawEmpty}, "", false},
+ {&[]interface{}{rawEmpty}, "", false},
+ {[]interface{}{&rawEmpty}, "", false},
+ {&[]interface{}{&rawEmpty}, "", false},
+ {struct{ X RawMessage }{rawEmpty}, "", false},
+ {&struct{ X RawMessage }{rawEmpty}, "", false},
+ {struct{ X *RawMessage }{&rawEmpty}, "", false},
+ {&struct{ X *RawMessage }{&rawEmpty}, "", false},
+ {map[string]interface{}{"nil": rawEmpty}, "", false},
+ {&map[string]interface{}{"nil": rawEmpty}, "", false},
+ {map[string]interface{}{"nil": &rawEmpty}, "", false},
+ {&map[string]interface{}{"nil": &rawEmpty}, "", false},
+ {T1{rawEmpty}, "{}", true},
+ {T2{&rawEmpty}, "", false},
+ {&T1{rawEmpty}, "{}", true},
+ {&T2{&rawEmpty}, "", false},
+
+ // Test with RawMessage with some text.
+ //
+ // The tests below marked with Issue6458 used to generate "ImZvbyI=" instead "foo".
+ // This behavior was intentionally changed in Go 1.8.
+ // See https://github.com/golang/go/issues/14493#issuecomment-255857318
+ {rawText, `"foo"`, true}, // Issue6458
+ {&rawText, `"foo"`, true},
+ {[]interface{}{rawText}, `["foo"]`, true}, // Issue6458
+ {&[]interface{}{rawText}, `["foo"]`, true}, // Issue6458
+ {[]interface{}{&rawText}, `["foo"]`, true},
+ {&[]interface{}{&rawText}, `["foo"]`, true},
+ {struct{ M RawMessage }{rawText}, `{"M":"foo"}`, true}, // Issue6458
+ {&struct{ M RawMessage }{rawText}, `{"M":"foo"}`, true},
+ {struct{ M *RawMessage }{&rawText}, `{"M":"foo"}`, true},
+ {&struct{ M *RawMessage }{&rawText}, `{"M":"foo"}`, true},
+ {map[string]interface{}{"M": rawText}, `{"M":"foo"}`, true}, // Issue6458
+ {&map[string]interface{}{"M": rawText}, `{"M":"foo"}`, true}, // Issue6458
+ {map[string]interface{}{"M": &rawText}, `{"M":"foo"}`, true},
+ {&map[string]interface{}{"M": &rawText}, `{"M":"foo"}`, true},
+ {T1{rawText}, `{"M":"foo"}`, true}, // Issue6458
+ {T2{&rawText}, `{"M":"foo"}`, true},
+ {&T1{rawText}, `{"M":"foo"}`, true},
+ {&T2{&rawText}, `{"M":"foo"}`, true},
+ }
+
+ for i, tt := range tests {
+ b, err := Marshal(tt.in)
+ if ok := (err == nil); ok != tt.ok {
+ if err != nil {
+ t.Errorf("test %d, unexpected failure: %v", i, err)
+ } else {
+ t.Errorf("test %d, unexpected success", i)
+ }
+ }
+ if got := string(b); got != tt.want {
+ t.Errorf("test %d, Marshal(%#v) = %q, want %q", i, tt.in, got, tt.want)
+ }
+ }
+}
diff --git a/src/encoding/json/example_marshaling_test.go b/src/encoding/json/example_marshaling_test.go
new file mode 100644
index 0000000..7f15c74
--- /dev/null
+++ b/src/encoding/json/example_marshaling_test.go
@@ -0,0 +1,73 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package json_test
+
+import (
+ "encoding/json"
+ "fmt"
+ "log"
+ "strings"
+)
+
+type Animal int
+
+const (
+ Unknown Animal = iota
+ Gopher
+ Zebra
+)
+
+func (a *Animal) UnmarshalJSON(b []byte) error {
+ var s string
+ if err := json.Unmarshal(b, &s); err != nil {
+ return err
+ }
+ switch strings.ToLower(s) {
+ default:
+ *a = Unknown
+ case "gopher":
+ *a = Gopher
+ case "zebra":
+ *a = Zebra
+ }
+
+ return nil
+}
+
+func (a Animal) MarshalJSON() ([]byte, error) {
+ var s string
+ switch a {
+ default:
+ s = "unknown"
+ case Gopher:
+ s = "gopher"
+ case Zebra:
+ s = "zebra"
+ }
+
+ return json.Marshal(s)
+}
+
+func Example_customMarshalJSON() {
+ blob := `["gopher","armadillo","zebra","unknown","gopher","bee","gopher","zebra"]`
+ var zoo []Animal
+ if err := json.Unmarshal([]byte(blob), &zoo); err != nil {
+ log.Fatal(err)
+ }
+
+ census := make(map[Animal]int)
+ for _, animal := range zoo {
+ census[animal] += 1
+ }
+
+ fmt.Printf("Zoo Census:\n* Gophers: %d\n* Zebras: %d\n* Unknown: %d\n",
+ census[Gopher], census[Zebra], census[Unknown])
+
+ // Output:
+ // Zoo Census:
+ // * Gophers: 3
+ // * Zebras: 2
+ // * Unknown: 3
+}
diff --git a/src/encoding/json/example_test.go b/src/encoding/json/example_test.go
index 555eff9..e4dffd9 100644
--- a/src/encoding/json/example_test.go
+++ b/src/encoding/json/example_test.go
@@ -174,7 +174,7 @@ func ExampleDecoder_Decode_stream() {
}
// This example uses RawMessage to delay parsing part of a JSON message.
-func ExampleRawMessage() {
+func ExampleRawMessage_unmarshal() {
type Color struct {
Space string
Point json.RawMessage // delay parsing until we know the color space
@@ -219,6 +219,30 @@ func ExampleRawMessage() {
// RGB &{98 218 255}
}
+// This example uses RawMessage to use a precomputed JSON during marshal.
+func ExampleRawMessage_marshal() {
+ h := json.RawMessage(`{"precomputed": true}`)
+
+ c := struct {
+ Header *json.RawMessage `json:"header"`
+ Body string `json:"body"`
+ }{Header: &h, Body: "Hello Gophers!"}
+
+ b, err := json.MarshalIndent(&c, "", "\t")
+ if err != nil {
+ fmt.Println("error:", err)
+ }
+ os.Stdout.Write(b)
+
+ // Output:
+ // {
+ // "header": {
+ // "precomputed": true
+ // },
+ // "body": "Hello Gophers!"
+ // }
+}
+
func ExampleIndent() {
type Road struct {
Name string
diff --git a/src/encoding/json/scanner_test.go b/src/encoding/json/scanner_test.go
index 70a2897..c5c1be3 100644
--- a/src/encoding/json/scanner_test.go
+++ b/src/encoding/json/scanner_test.go
@@ -119,6 +119,7 @@ func TestCompactBig(t *testing.T) {
}
func TestIndentBig(t *testing.T) {
+ t.Parallel()
initBig()
var buf bytes.Buffer
if err := Indent(&buf, jsonBig, "", "\t"); err != nil {
diff --git a/src/encoding/json/stream.go b/src/encoding/json/stream.go
index 87f0e57..95e30ce 100644
--- a/src/encoding/json/stream.go
+++ b/src/encoding/json/stream.go
@@ -246,9 +246,12 @@ func (enc *Encoder) SetEscapeHTML(on bool) {
// be used to delay JSON decoding or precompute a JSON encoding.
type RawMessage []byte
-// MarshalJSON returns *m as the JSON encoding of m.
-func (m *RawMessage) MarshalJSON() ([]byte, error) {
- return *m, nil
+// MarshalJSON returns m as the JSON encoding of m.
+func (m RawMessage) MarshalJSON() ([]byte, error) {
+ if m == nil {
+ return []byte("null"), nil
+ }
+ return m, nil
}
// UnmarshalJSON sets *m to a copy of data.
diff --git a/src/encoding/json/tables.go b/src/encoding/json/tables.go
new file mode 100644
index 0000000..10acdc1
--- /dev/null
+++ b/src/encoding/json/tables.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 json
+
+import "unicode/utf8"
+
+// safeSet holds the value true if the ASCII character with the given array
+// position can be represented inside a JSON string without any further
+// escaping.
+//
+// All values are true except for the ASCII control characters (0-31), the
+// double quote ("), and the backslash character ("\").
+var safeSet = [utf8.RuneSelf]bool{
+ ' ': true,
+ '!': true,
+ '"': false,
+ '#': true,
+ '$': true,
+ '%': true,
+ '&': true,
+ '\'': true,
+ '(': true,
+ ')': true,
+ '*': true,
+ '+': true,
+ ',': true,
+ '-': true,
+ '.': true,
+ '/': true,
+ '0': true,
+ '1': true,
+ '2': true,
+ '3': true,
+ '4': true,
+ '5': true,
+ '6': true,
+ '7': true,
+ '8': true,
+ '9': true,
+ ':': true,
+ ';': true,
+ '<': true,
+ '=': true,
+ '>': true,
+ '?': true,
+ '@': true,
+ 'A': true,
+ 'B': true,
+ 'C': true,
+ 'D': true,
+ 'E': true,
+ 'F': true,
+ 'G': true,
+ 'H': true,
+ 'I': true,
+ 'J': true,
+ 'K': true,
+ 'L': true,
+ 'M': true,
+ 'N': true,
+ 'O': true,
+ 'P': true,
+ 'Q': true,
+ 'R': true,
+ 'S': true,
+ 'T': true,
+ 'U': true,
+ 'V': true,
+ 'W': true,
+ 'X': true,
+ 'Y': true,
+ 'Z': true,
+ '[': true,
+ '\\': false,
+ ']': true,
+ '^': true,
+ '_': true,
+ '`': true,
+ 'a': true,
+ 'b': true,
+ 'c': true,
+ 'd': true,
+ 'e': true,
+ 'f': true,
+ 'g': true,
+ 'h': true,
+ 'i': true,
+ 'j': true,
+ 'k': true,
+ 'l': true,
+ 'm': true,
+ 'n': true,
+ 'o': true,
+ 'p': true,
+ 'q': true,
+ 'r': true,
+ 's': true,
+ 't': true,
+ 'u': true,
+ 'v': true,
+ 'w': true,
+ 'x': true,
+ 'y': true,
+ 'z': true,
+ '{': true,
+ '|': true,
+ '}': true,
+ '~': true,
+ '\u007f': true,
+}
+
+// htmlSafeSet holds the value true if the ASCII character with the given
+// array position can be safely represented inside a JSON string, embedded
+// inside of HTML <script> tags, without any additional escaping.
+//
+// All values are true except for the ASCII control characters (0-31), the
+// double quote ("), the backslash character ("\"), HTML opening and closing
+// tags ("<" and ">"), and the ampersand ("&").
+var htmlSafeSet = [utf8.RuneSelf]bool{
+ ' ': true,
+ '!': true,
+ '"': false,
+ '#': true,
+ '$': true,
+ '%': true,
+ '&': false,
+ '\'': true,
+ '(': true,
+ ')': true,
+ '*': true,
+ '+': true,
+ ',': true,
+ '-': true,
+ '.': true,
+ '/': true,
+ '0': true,
+ '1': true,
+ '2': true,
+ '3': true,
+ '4': true,
+ '5': true,
+ '6': true,
+ '7': true,
+ '8': true,
+ '9': true,
+ ':': true,
+ ';': true,
+ '<': false,
+ '=': true,
+ '>': false,
+ '?': true,
+ '@': true,
+ 'A': true,
+ 'B': true,
+ 'C': true,
+ 'D': true,
+ 'E': true,
+ 'F': true,
+ 'G': true,
+ 'H': true,
+ 'I': true,
+ 'J': true,
+ 'K': true,
+ 'L': true,
+ 'M': true,
+ 'N': true,
+ 'O': true,
+ 'P': true,
+ 'Q': true,
+ 'R': true,
+ 'S': true,
+ 'T': true,
+ 'U': true,
+ 'V': true,
+ 'W': true,
+ 'X': true,
+ 'Y': true,
+ 'Z': true,
+ '[': true,
+ '\\': false,
+ ']': true,
+ '^': true,
+ '_': true,
+ '`': true,
+ 'a': true,
+ 'b': true,
+ 'c': true,
+ 'd': true,
+ 'e': true,
+ 'f': true,
+ 'g': true,
+ 'h': true,
+ 'i': true,
+ 'j': true,
+ 'k': true,
+ 'l': true,
+ 'm': true,
+ 'n': true,
+ 'o': true,
+ 'p': true,
+ 'q': true,
+ 'r': true,
+ 's': true,
+ 't': true,
+ 'u': true,
+ 'v': true,
+ 'w': true,
+ 'x': true,
+ 'y': true,
+ 'z': true,
+ '{': true,
+ '|': true,
+ '}': true,
+ '~': true,
+ '\u007f': true,
+}
diff --git a/src/encoding/json/tagkey_test.go b/src/encoding/json/tagkey_test.go
index c1739ea..f77c49c 100644
--- a/src/encoding/json/tagkey_test.go
+++ b/src/encoding/json/tagkey_test.go
@@ -44,6 +44,10 @@ type punctuationTag struct {
V string `json:"!#$%&()*+-./:<=>?@[]^_{|}~"` // https://golang.org/issue/3546
}
+type dashTag struct {
+ V string `json:"-,"`
+}
+
type emptyTag struct {
W string
}
@@ -80,6 +84,7 @@ var structTagObjectKeyTests = []struct {
{basicLatin6xTag{"6x"}, "6x", "abcdefghijklmno"},
{basicLatin7xTag{"7x"}, "7x", "pqrstuvwxyz"},
{miscPlaneTag{"いろはにほへと"}, "いろはにほへと", "色は匂へど"},
+ {dashTag{"foo"}, "foo", "-"},
{emptyTag{"Pour Moi"}, "Pour Moi", "W"},
{misnamedTag{"Animal Kingdom"}, "Animal Kingdom", "X"},
{badFormatTag{"Orfevre"}, "Orfevre", "Y"},
diff --git a/src/encoding/pem/example_test.go b/src/encoding/pem/example_test.go
new file mode 100644
index 0000000..900b31c
--- /dev/null
+++ b/src/encoding/pem/example_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 pem_test
+
+import (
+ "crypto/x509"
+ "encoding/pem"
+ "fmt"
+ "log"
+)
+
+func ExampleDecode() {
+ var pubPEMData = []byte(`
+-----BEGIN PUBLIC KEY-----
+MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAlRuRnThUjU8/prwYxbty
+WPT9pURI3lbsKMiB6Fn/VHOKE13p4D8xgOCADpdRagdT6n4etr9atzDKUSvpMtR3
+CP5noNc97WiNCggBjVWhs7szEe8ugyqF23XwpHQ6uV1LKH50m92MbOWfCtjU9p/x
+qhNpQQ1AZhqNy5Gevap5k8XzRmjSldNAFZMY7Yv3Gi+nyCwGwpVtBUwhuLzgNFK/
+yDtw2WcWmUU7NuC8Q6MWvPebxVtCfVp/iQU6q60yyt6aGOBkhAX0LpKAEhKidixY
+nP9PNVBvxgu3XZ4P36gZV6+ummKdBVnc3NqwBLu5+CcdRdusmHPHd5pHf4/38Z3/
+6qU2a/fPvWzceVTEgZ47QjFMTCTmCwNt29cvi7zZeQzjtwQgn4ipN9NibRH/Ax/q
+TbIzHfrJ1xa2RteWSdFjwtxi9C20HUkjXSeI4YlzQMH0fPX6KCE7aVePTOnB69I/
+a9/q96DiXZajwlpq3wFctrs1oXqBp5DVrCIj8hU2wNgB7LtQ1mCtsYz//heai0K9
+PhE4X6hiE0YmeAZjR0uHl8M/5aW9xCoJ72+12kKpWAa0SFRWLy6FejNYCYpkupVJ
+yecLk/4L1W0l6jQQZnWErXZYe0PNFcmwGXy1Rep83kfBRNKRy5tvocalLlwXLdUk
+AIU+2GKjyT3iMuzZxxFxPFMCAwEAAQ==
+-----END PUBLIC KEY-----
+and some more`)
+
+ block, rest := pem.Decode(pubPEMData)
+ if block == nil || block.Type != "PUBLIC KEY" {
+ log.Fatal("failed to decode PEM block containing public key")
+ }
+
+ pub, err := x509.ParsePKIXPublicKey(block.Bytes)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ fmt.Printf("Got a %T, with remaining data: %q", pub, rest)
+ // Output: Got a *rsa.PublicKey, with remaining data: "and some more"
+}
diff --git a/src/encoding/pem/pem.go b/src/encoding/pem/pem.go
index ff2bed1..fbf4999 100644
--- a/src/encoding/pem/pem.go
+++ b/src/encoding/pem/pem.go
@@ -119,19 +119,36 @@ func Decode(data []byte) (p *Block, rest []byte) {
rest = next
}
- var endIndex int
+ var endIndex, endTrailerIndex int
+
// If there were no headers, the END line might occur
// immediately, without a leading newline.
if len(p.Headers) == 0 && bytes.HasPrefix(rest, pemEnd[1:]) {
endIndex = 0
+ endTrailerIndex = len(pemEnd) - 1
} else {
endIndex = bytes.Index(rest, pemEnd)
+ endTrailerIndex = endIndex + len(pemEnd)
}
if endIndex < 0 {
return decodeError(data, rest)
}
+ // After the "-----" of the ending line should be the same type and a
+ // final five dashes.
+ endTrailer := rest[endTrailerIndex:]
+ endTrailerLen := len(typeLine) + len(pemEndOfLine)
+ if len(endTrailer) < endTrailerLen {
+ return decodeError(data, rest)
+ }
+
+ endTrailer = endTrailer[:endTrailerLen]
+ if !bytes.HasPrefix(endTrailer, typeLine) ||
+ !bytes.HasSuffix(endTrailer, pemEndOfLine) {
+ 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 958dbc1..6321dec 100644
--- a/src/encoding/pem/pem_test.go
+++ b/src/encoding/pem/pem_test.go
@@ -78,6 +78,48 @@ func TestDecode(t *testing.T) {
}
}
+const pemTooFewEndingDashes = `
+-----BEGIN FOO-----
+dGVzdA==
+-----END FOO----`
+
+const pemWrongEndingType = `
+-----BEGIN FOO-----
+dGVzdA==
+-----END BAR-----`
+
+const pemMissingEndingSpace = `
+-----BEGIN FOO-----
+dGVzdA==
+-----ENDBAR-----`
+
+var badPEMTests = []struct {
+ name string
+ input string
+}{
+ {
+ "too few trailing dashes",
+ pemTooFewEndingDashes,
+ },
+ {
+ "incorrect ending type",
+ pemWrongEndingType,
+ },
+ {
+ "missing ending space",
+ pemMissingEndingSpace,
+ },
+}
+
+func TestBadDecode(t *testing.T) {
+ for _, test := range badPEMTests {
+ result, _ := Decode([]byte(test.input))
+ if result != nil {
+ t.Errorf("unexpected success while parsing %q", test.name)
+ }
+ }
+}
+
func TestEncode(t *testing.T) {
r := EncodeToMemory(privateKey2)
if string(r) != pemPrivateKey2 {
diff --git a/src/encoding/xml/marshal.go b/src/encoding/xml/marshal.go
index abb078c..1176f5d 100644
--- a/src/encoding/xml/marshal.go
+++ b/src/encoding/xml/marshal.go
@@ -24,10 +24,10 @@ const (
// Marshal returns the XML encoding of v.
//
-// Marshal handles an array or slice by marshalling each of the elements.
-// Marshal handles a pointer by marshalling the value it points at or, if the
+// Marshal handles an array or slice by marshaling each of the elements.
+// Marshal handles a pointer by marshaling the value it points at or, if the
// pointer is nil, by writing nothing. Marshal handles an interface value by
-// marshalling the value it contains or, if the interface value is nil, by
+// marshaling the value it contains or, if the interface value is nil, by
// writing nothing. Marshal handles all other data by writing one or more XML
// elements containing the data.
//
@@ -36,9 +36,9 @@ const (
// - the value of the XMLName field of type Name
// - the tag of the struct field used to obtain the data
// - the name of the struct field used to obtain the data
-// - the name of the marshalled type
+// - the name of the marshaled type
//
-// The XML element for a struct contains marshalled elements for each of the
+// The XML element for a struct contains marshaled elements for each of the
// exported fields of the struct, with these exceptions:
// - the XMLName field, described above, is omitted.
// - a field with tag "-" is omitted.
@@ -51,9 +51,9 @@ const (
// - a field with tag ",cdata" is written as character data
// wrapped in one or more <![CDATA[ ... ]]> tags, not as an XML element.
// - a field with tag ",innerxml" is written verbatim, not subject
-// to the usual marshalling procedure.
+// to the usual marshaling procedure.
// - a field with tag ",comment" is written as an XML comment, not
-// subject to the usual marshalling procedure. It must not contain
+// subject to the usual marshaling procedure. It must not contain
// the "--" string within it.
// - a field with a tag including the "omitempty" option is omitted
// if the field value is empty. The empty values are false, 0, any
@@ -494,7 +494,6 @@ func (p *printer) marshalValue(val reflect.Value, finfo *fieldInfo, startTemplat
continue
}
fv := finfo.value(val)
- name := Name{Space: finfo.xmlns, Local: finfo.name}
if finfo.flags&fOmitEmpty != 0 && isEmptyValue(fv) {
continue
@@ -504,69 +503,10 @@ func (p *printer) marshalValue(val reflect.Value, finfo *fieldInfo, startTemplat
continue
}
- if fv.CanInterface() && fv.Type().Implements(marshalerAttrType) {
- attr, err := fv.Interface().(MarshalerAttr).MarshalXMLAttr(name)
- if err != nil {
- return err
- }
- if attr.Name.Local != "" {
- start.Attr = append(start.Attr, attr)
- }
- continue
- }
-
- if fv.CanAddr() {
- pv := fv.Addr()
- if pv.CanInterface() && pv.Type().Implements(marshalerAttrType) {
- attr, err := pv.Interface().(MarshalerAttr).MarshalXMLAttr(name)
- if err != nil {
- return err
- }
- if attr.Name.Local != "" {
- start.Attr = append(start.Attr, attr)
- }
- continue
- }
- }
-
- if fv.CanInterface() && fv.Type().Implements(textMarshalerType) {
- text, err := fv.Interface().(encoding.TextMarshaler).MarshalText()
- if err != nil {
- return err
- }
- start.Attr = append(start.Attr, Attr{name, string(text)})
- continue
- }
-
- if fv.CanAddr() {
- pv := fv.Addr()
- if pv.CanInterface() && pv.Type().Implements(textMarshalerType) {
- text, err := pv.Interface().(encoding.TextMarshaler).MarshalText()
- if err != nil {
- return err
- }
- start.Attr = append(start.Attr, Attr{name, string(text)})
- continue
- }
- }
-
- // Dereference or skip nil pointer, interface values.
- switch fv.Kind() {
- case reflect.Ptr, reflect.Interface:
- if fv.IsNil() {
- continue
- }
- fv = fv.Elem()
- }
-
- s, b, err := p.marshalSimple(fv.Type(), fv)
- if err != nil {
+ name := Name{Space: finfo.xmlns, Local: finfo.name}
+ if err := p.marshalAttr(&start, name, fv); err != nil {
return err
}
- if b != nil {
- s = string(b)
- }
- start.Attr = append(start.Attr, Attr{name, s})
}
if err := p.writeStart(&start); err != nil {
@@ -596,6 +536,90 @@ func (p *printer) marshalValue(val reflect.Value, finfo *fieldInfo, startTemplat
return p.cachedWriteError()
}
+// marshalAttr marshals an attribute with the given name and value, adding to start.Attr.
+func (p *printer) marshalAttr(start *StartElement, name Name, val reflect.Value) error {
+ if val.CanInterface() && val.Type().Implements(marshalerAttrType) {
+ attr, err := val.Interface().(MarshalerAttr).MarshalXMLAttr(name)
+ if err != nil {
+ return err
+ }
+ if attr.Name.Local != "" {
+ start.Attr = append(start.Attr, attr)
+ }
+ return nil
+ }
+
+ if val.CanAddr() {
+ pv := val.Addr()
+ if pv.CanInterface() && pv.Type().Implements(marshalerAttrType) {
+ attr, err := pv.Interface().(MarshalerAttr).MarshalXMLAttr(name)
+ if err != nil {
+ return err
+ }
+ if attr.Name.Local != "" {
+ start.Attr = append(start.Attr, attr)
+ }
+ return nil
+ }
+ }
+
+ if val.CanInterface() && val.Type().Implements(textMarshalerType) {
+ text, err := val.Interface().(encoding.TextMarshaler).MarshalText()
+ if err != nil {
+ return err
+ }
+ start.Attr = append(start.Attr, Attr{name, string(text)})
+ return nil
+ }
+
+ if val.CanAddr() {
+ pv := val.Addr()
+ if pv.CanInterface() && pv.Type().Implements(textMarshalerType) {
+ text, err := pv.Interface().(encoding.TextMarshaler).MarshalText()
+ if err != nil {
+ return err
+ }
+ start.Attr = append(start.Attr, Attr{name, string(text)})
+ return nil
+ }
+ }
+
+ // Dereference or skip nil pointer, interface values.
+ switch val.Kind() {
+ case reflect.Ptr, reflect.Interface:
+ if val.IsNil() {
+ return nil
+ }
+ val = val.Elem()
+ }
+
+ // Walk slices.
+ if val.Kind() == reflect.Slice && val.Type().Elem().Kind() != reflect.Uint8 {
+ n := val.Len()
+ for i := 0; i < n; i++ {
+ if err := p.marshalAttr(start, name, val.Index(i)); err != nil {
+ return err
+ }
+ }
+ return nil
+ }
+
+ if val.Type() == attrType {
+ start.Attr = append(start.Attr, val.Interface().(Attr))
+ return nil
+ }
+
+ s, b, err := p.marshalSimple(val.Type(), val)
+ if err != nil {
+ return err
+ }
+ if b != nil {
+ s = string(b)
+ }
+ start.Attr = append(start.Attr, Attr{name, s})
+ return nil
+}
+
// defaultStart returns the default start element to use,
// given the reflect type, field info, and start template.
func defaultStart(typ reflect.Type, finfo *fieldInfo, startTemplate *StartElement) StartElement {
@@ -760,14 +784,6 @@ func (p *printer) marshalStruct(tinfo *typeInfo, val reflect.Value) error {
}
vf := finfo.value(val)
- // Dereference or skip nil pointer, interface values.
- switch vf.Kind() {
- case reflect.Ptr, reflect.Interface:
- if !vf.IsNil() {
- vf = vf.Elem()
- }
- }
-
switch finfo.flags & fMode {
case fCDATA, fCharData:
emit := EscapeText
@@ -800,6 +816,16 @@ func (p *printer) marshalStruct(tinfo *typeInfo, val reflect.Value) error {
continue
}
}
+ // Drill into interfaces and pointers.
+ // This can turn into an infinite loop given a cyclic chain,
+ // but it matches the Go 1 behavior.
+ for vf.Kind() == reflect.Interface || vf.Kind() == reflect.Ptr {
+ if vf.IsNil() {
+ return nil
+ }
+ vf = vf.Elem()
+ }
+
var scratch [64]byte
switch vf.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
diff --git a/src/encoding/xml/marshal_test.go b/src/encoding/xml/marshal_test.go
index fe8b16f..d79b99a 100644
--- a/src/encoding/xml/marshal_test.go
+++ b/src/encoding/xml/marshal_test.go
@@ -199,6 +199,17 @@ type AttrTest struct {
Bytes []byte `xml:",attr"`
}
+type AttrsTest struct {
+ Attrs []Attr `xml:",any,attr"`
+ Int int `xml:",attr"`
+ Named int `xml:"int,attr"`
+ Float float64 `xml:",attr"`
+ Uint8 uint8 `xml:",attr"`
+ Bool bool `xml:",attr"`
+ Str string `xml:",attr"`
+ Bytes []byte `xml:",attr"`
+}
+
type OmitAttrTest struct {
Int int `xml:",attr,omitempty"`
Named int `xml:"int,attr,omitempty"`
@@ -207,6 +218,7 @@ type OmitAttrTest struct {
Bool bool `xml:",attr,omitempty"`
Str string `xml:",attr,omitempty"`
Bytes []byte `xml:",attr,omitempty"`
+ PStr *string `xml:",attr,omitempty"`
}
type OmitFieldTest struct {
@@ -217,6 +229,7 @@ type OmitFieldTest struct {
Bool bool `xml:",omitempty"`
Str string `xml:",omitempty"`
Bytes []byte `xml:",omitempty"`
+ PStr *string `xml:",omitempty"`
Ptr *PresenceTest `xml:",omitempty"`
}
@@ -317,6 +330,10 @@ func (m *MyMarshalerAttrTest) MarshalXMLAttr(name Name) (Attr, error) {
return Attr{name, "hello world"}, nil
}
+func (m *MyMarshalerAttrTest) UnmarshalXMLAttr(attr Attr) error {
+ return nil
+}
+
type MarshalerStruct struct {
Foo MyMarshalerAttrTest `xml:",attr"`
}
@@ -373,12 +390,13 @@ var (
nameAttr = "Sarah"
ageAttr = uint(12)
contentsAttr = "lorem ipsum"
+ empty = ""
)
// Unless explicitly stated as such (or *Plain), all of the
// tests below are two-way tests. When introducing new tests,
// please try to make them two-way as well to ensure that
-// marshalling and unmarshalling are as symmetrical as feasible.
+// marshaling and unmarshaling are as symmetrical as feasible.
var marshalTests = []struct {
Value interface{}
ExpectXML string
@@ -823,6 +841,53 @@ var marshalTests = []struct {
` Bool="false" Str="" Bytes=""></AttrTest>`,
},
{
+ Value: &AttrsTest{
+ Attrs: []Attr{
+ {Name: Name{Local: "Answer"}, Value: "42"},
+ {Name: Name{Local: "Int"}, Value: "8"},
+ {Name: Name{Local: "int"}, Value: "9"},
+ {Name: Name{Local: "Float"}, Value: "23.5"},
+ {Name: Name{Local: "Uint8"}, Value: "255"},
+ {Name: Name{Local: "Bool"}, Value: "true"},
+ {Name: Name{Local: "Str"}, Value: "str"},
+ {Name: Name{Local: "Bytes"}, Value: "byt"},
+ },
+ },
+ ExpectXML: `<AttrsTest Answer="42" Int="8" int="9" Float="23.5" Uint8="255" Bool="true" Str="str" Bytes="byt" Int="0" int="0" Float="0" Uint8="0" Bool="false" Str="" Bytes=""></AttrsTest>`,
+ MarshalOnly: true,
+ },
+ {
+ Value: &AttrsTest{
+ Attrs: []Attr{
+ {Name: Name{Local: "Answer"}, Value: "42"},
+ },
+ Int: 8,
+ Named: 9,
+ Float: 23.5,
+ Uint8: 255,
+ Bool: true,
+ Str: "str",
+ Bytes: []byte("byt"),
+ },
+ ExpectXML: `<AttrsTest Answer="42" Int="8" int="9" Float="23.5" Uint8="255" Bool="true" Str="str" Bytes="byt"></AttrsTest>`,
+ },
+ {
+ Value: &AttrsTest{
+ Attrs: []Attr{
+ {Name: Name{Local: "Int"}, Value: "0"},
+ {Name: Name{Local: "int"}, Value: "0"},
+ {Name: Name{Local: "Float"}, Value: "0"},
+ {Name: Name{Local: "Uint8"}, Value: "0"},
+ {Name: Name{Local: "Bool"}, Value: "false"},
+ {Name: Name{Local: "Str"}},
+ {Name: Name{Local: "Bytes"}},
+ },
+ Bytes: []byte{},
+ },
+ ExpectXML: `<AttrsTest Int="0" int="0" Float="0" Uint8="0" Bool="false" Str="" Bytes="" Int="0" int="0" Float="0" Uint8="0" Bool="false" Str="" Bytes=""></AttrsTest>`,
+ MarshalOnly: true,
+ },
+ {
Value: &OmitAttrTest{
Int: 8,
Named: 9,
@@ -831,9 +896,10 @@ var marshalTests = []struct {
Bool: true,
Str: "str",
Bytes: []byte("byt"),
+ PStr: &empty,
},
ExpectXML: `<OmitAttrTest Int="8" int="9" Float="23.5" Uint8="255"` +
- ` Bool="true" Str="str" Bytes="byt"></OmitAttrTest>`,
+ ` Bool="true" Str="str" Bytes="byt" PStr=""></OmitAttrTest>`,
},
{
Value: &OmitAttrTest{},
@@ -864,6 +930,7 @@ var marshalTests = []struct {
Bool: true,
Str: "str",
Bytes: []byte("byt"),
+ PStr: &empty,
Ptr: &PresenceTest{},
},
ExpectXML: `<OmitFieldTest>` +
@@ -874,6 +941,7 @@ var marshalTests = []struct {
`<Bool>true</Bool>` +
`<Str>str</Str>` +
`<Bytes>byt</Bytes>` +
+ `<PStr></PStr>` +
`<Ptr></Ptr>` +
`</OmitFieldTest>`,
},
@@ -1092,7 +1160,7 @@ type AttrParent struct {
}
type BadAttr struct {
- Name []string `xml:"name,attr"`
+ Name map[string]string `xml:"name,attr"`
}
var marshalErrorTests = []struct {
@@ -1128,8 +1196,8 @@ var marshalErrorTests = []struct {
Err: `xml: X>Y chain not valid with attr flag`,
},
{
- Value: BadAttr{[]string{"X", "Y"}},
- Err: `xml: unsupported type: []string`,
+ Value: BadAttr{map[string]string{"X": "Y"}},
+ Err: `xml: unsupported type: map[string]string`,
},
}
@@ -1732,7 +1800,7 @@ func TestDecodeEncode(t *testing.T) {
in.WriteString(`<?xml version="1.0" encoding="UTF-8"?>
<?Target Instruction?>
<root>
-</root>
+</root>
`)
dec := NewDecoder(&in)
enc := NewEncoder(&out)
@@ -1823,3 +1891,14 @@ func TestSimpleUseOfEncodeToken(t *testing.T) {
t.Errorf("enc.EncodeToken: expected %q; got %q", want, buf.String())
}
}
+
+// Issue 16158. Decoder.unmarshalAttr ignores the return value of copyValue.
+func TestIssue16158(t *testing.T) {
+ const data = `<foo b="HELLOWORLD"></foo>`
+ err := Unmarshal([]byte(data), &struct {
+ B byte `xml:"b,attr,omitempty"`
+ }{})
+ 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 937432e..5a89d5f 100644
--- a/src/encoding/xml/read.go
+++ b/src/encoding/xml/read.go
@@ -52,6 +52,11 @@ import (
// the explicit name in a struct field tag of the form "name,attr",
// Unmarshal records the attribute value in that field.
//
+// * If the XML element has an attribute not handled by the previous
+// rule and the struct has a field with an associated tag containing
+// ",any,attr", Unmarshal records the attribute value in the first
+// such field.
+//
// * If the XML element contains character data, that data is
// accumulated in the first struct field that has tag ",chardata".
// The struct field may have type []byte or string.
@@ -85,7 +90,7 @@ import (
// * An anonymous struct field is handled as if the fields of its
// value were part of the outer struct.
//
-// * A struct field with tag "-" is never unmarshalled into.
+// * A struct field with tag "-" is never unmarshaled into.
//
// Unmarshal maps an XML element to a string or []byte by saving the
// concatenation of that element's character data in the string or
@@ -94,8 +99,12 @@ import (
// Unmarshal maps an attribute value to a string or []byte by saving
// the value in the string or slice.
//
-// Unmarshal maps an XML element to a slice by extending the length of
-// the slice and mapping the element to the newly created value.
+// Unmarshal maps an attribute value to an Attr by saving the attribute,
+// including its name, in the Attr.
+//
+// Unmarshal maps an XML element or attribute value to a slice by
+// extending the length of the slice and mapping the element or attribute
+// to the newly created value.
//
// Unmarshal maps an XML element or attribute value to a bool by
// setting it to the boolean value represented by the string.
@@ -133,7 +142,7 @@ func (d *Decoder) DecodeElement(v interface{}, start *StartElement) error {
return d.unmarshal(val.Elem(), start)
}
-// An UnmarshalError represents an error in the unmarshalling process.
+// An UnmarshalError represents an error in the unmarshaling process.
type UnmarshalError string
func (e UnmarshalError) Error() string { return string(e) }
@@ -232,7 +241,6 @@ func (p *Decoder) unmarshalAttr(val reflect.Value, attr Attr) error {
}
val = val.Elem()
}
-
if val.CanInterface() && val.Type().Implements(unmarshalerAttrType) {
// This is an unmarshaler with a non-pointer receiver,
// so it's likely to be incorrect, but we do what we're told.
@@ -258,11 +266,30 @@ func (p *Decoder) unmarshalAttr(val reflect.Value, attr Attr) error {
}
}
- copyValue(val, []byte(attr.Value))
- return nil
+ if val.Type().Kind() == reflect.Slice && val.Type().Elem().Kind() != reflect.Uint8 {
+ // Slice of element values.
+ // Grow slice.
+ n := val.Len()
+ val.Set(reflect.Append(val, reflect.Zero(val.Type().Elem())))
+
+ // Recur to read element into slice.
+ if err := p.unmarshalAttr(val.Index(n), attr); err != nil {
+ val.SetLen(n)
+ return err
+ }
+ return nil
+ }
+
+ if val.Type() == attrType {
+ val.Set(reflect.ValueOf(attr))
+ return nil
+ }
+
+ return copyValue(val, []byte(attr.Value))
}
var (
+ attrType = reflect.TypeOf(Attr{})
unmarshalerType = reflect.TypeOf((*Unmarshaler)(nil)).Elem()
unmarshalerAttrType = reflect.TypeOf((*UnmarshalerAttr)(nil)).Elem()
textUnmarshalerType = reflect.TypeOf((*encoding.TextUnmarshaler)(nil)).Elem()
@@ -359,16 +386,7 @@ func (p *Decoder) unmarshal(val reflect.Value, start *StartElement) error {
// Slice of element values.
// Grow slice.
n := v.Len()
- if n >= v.Cap() {
- ncap := 2 * n
- if ncap < 4 {
- ncap = 4
- }
- new := reflect.MakeSlice(typ, n, ncap)
- reflect.Copy(new, v)
- v.Set(new)
- }
- v.SetLen(n + 1)
+ v.Set(reflect.Append(val, reflect.Zero(v.Type().Elem())))
// Recur to read element into slice.
if err := p.unmarshal(v.Index(n), start); err != nil {
@@ -415,22 +433,40 @@ func (p *Decoder) unmarshal(val reflect.Value, start *StartElement) error {
}
// Assign attributes.
- // Also, determine whether we need to save character data or comments.
- for i := range tinfo.fields {
- finfo := &tinfo.fields[i]
- switch finfo.flags & fMode {
- case fAttr:
- strv := finfo.value(sv)
- // Look for attribute.
- for _, a := range start.Attr {
+ for _, a := range start.Attr {
+ handled := false
+ any := -1
+ for i := range tinfo.fields {
+ finfo := &tinfo.fields[i]
+ switch finfo.flags & fMode {
+ case fAttr:
+ strv := finfo.value(sv)
if a.Name.Local == finfo.name && (finfo.xmlns == "" || finfo.xmlns == a.Name.Space) {
if err := p.unmarshalAttr(strv, a); err != nil {
return err
}
- break
+ handled = true
+ }
+
+ case fAny | fAttr:
+ if any == -1 {
+ any = i
}
}
+ }
+ if !handled && any >= 0 {
+ finfo := &tinfo.fields[any]
+ strv := finfo.value(sv)
+ if err := p.unmarshalAttr(strv, a); err != nil {
+ return err
+ }
+ }
+ }
+ // Determine whether we need to save character data or comments.
+ for i := range tinfo.fields {
+ finfo := &tinfo.fields[i]
+ switch finfo.flags & fMode {
case fCDATA, fCharData:
if !saveData.IsValid() {
saveData = finfo.value(sv)
@@ -546,7 +582,9 @@ Loop:
case reflect.String:
t.SetString(string(saveXMLData))
case reflect.Slice:
- t.Set(reflect.ValueOf(saveXMLData))
+ if t.Type().Elem().Kind() == reflect.Uint8 {
+ t.Set(reflect.ValueOf(saveXMLData))
+ }
}
return nil
diff --git a/src/encoding/xml/read_test.go b/src/encoding/xml/read_test.go
index 7a98092..273c303 100644
--- a/src/encoding/xml/read_test.go
+++ b/src/encoding/xml/read_test.go
@@ -705,7 +705,7 @@ func TestUnmarshalIntoInterface(t *testing.T) {
}
pea, ok := pod.Pea.(*Pea)
if !ok {
- t.Fatalf("unmarshalled into wrong type: have %T want *Pea", pod.Pea)
+ t.Fatalf("unmarshaled into wrong type: have %T want *Pea", pod.Pea)
}
have, want := pea.Cotelydon, "Green stuff"
if have != want {
@@ -733,3 +733,22 @@ func TestMalformedComment(t *testing.T) {
}
}
}
+
+type IXField struct {
+ Five int `xml:"five"`
+ NotInnerXML []string `xml:",innerxml"`
+}
+
+// Issue 15600. ",innerxml" on a field that can't hold it.
+func TestInvalidInnerXMLType(t *testing.T) {
+ v := new(IXField)
+ if err := Unmarshal([]byte(`<tag><five>5</five><innertag/></tag>`), v); err != nil {
+ t.Errorf("Unmarshal failed: got %v", err)
+ }
+ if v.Five != 5 {
+ t.Errorf("Five = %v, want 5", v.Five)
+ }
+ if v.NotInnerXML != nil {
+ t.Errorf("NotInnerXML = %v, want nil", v.NotInnerXML)
+ }
+}
diff --git a/src/encoding/xml/typeinfo.go b/src/encoding/xml/typeinfo.go
index 70da962..6623c78 100644
--- a/src/encoding/xml/typeinfo.go
+++ b/src/encoding/xml/typeinfo.go
@@ -48,7 +48,7 @@ var tinfoLock sync.RWMutex
var nameType = reflect.TypeOf(Name{})
// getTypeInfo returns the typeInfo structure with details necessary
-// for marshalling and unmarshalling typ.
+// for marshaling and unmarshaling typ.
func getTypeInfo(typ reflect.Type) (*typeInfo, error) {
tinfoLock.RLock()
tinfo, ok := tinfoMap[typ]
@@ -151,7 +151,7 @@ func structFieldInfo(typ reflect.Type, f *reflect.StructField) (*fieldInfo, erro
switch mode := finfo.flags & fMode; mode {
case 0:
finfo.flags |= fElement
- case fAttr, fCDATA, fCharData, fInnerXml, fComment, fAny:
+ case fAttr, fCDATA, fCharData, fInnerXml, fComment, fAny, fAny | fAttr:
if f.Name == "XMLName" || tag != "" && mode != fAttr {
valid = false
}
@@ -214,7 +214,7 @@ func structFieldInfo(typ reflect.Type, f *reflect.StructField) (*fieldInfo, erro
}
// If the field type has an XMLName field, the names must match
- // so that the behavior of both marshalling and unmarshalling
+ // so that the behavior of both marshaling and unmarshaling
// is straightforward and unambiguous.
if finfo.flags&fElement != 0 {
ftyp := f.Type
@@ -334,7 +334,7 @@ Loop:
return nil
}
-// A TagPathError represents an error in the unmarshalling process
+// A TagPathError represents an error in the unmarshaling process
// caused by the use of field tags with conflicting paths.
type TagPathError struct {
Struct reflect.Type
diff --git a/src/expvar/expvar.go b/src/expvar/expvar.go
index d5465c5..7339fa0 100644
--- a/src/expvar/expvar.go
+++ b/src/expvar/expvar.go
@@ -49,6 +49,10 @@ type Int struct {
i int64
}
+func (v *Int) Value() int64 {
+ return atomic.LoadInt64(&v.i)
+}
+
func (v *Int) String() string {
return strconv.FormatInt(atomic.LoadInt64(&v.i), 10)
}
@@ -66,6 +70,10 @@ type Float struct {
f uint64
}
+func (v *Float) Value() float64 {
+ return math.Float64frombits(atomic.LoadUint64(&v.f))
+}
+
func (v *Float) String() string {
return strconv.FormatFloat(
math.Float64frombits(atomic.LoadUint64(&v.f)), 'g', -1, 64)
@@ -219,6 +227,14 @@ type String struct {
s string
}
+func (v *String) Value() string {
+ v.mu.RLock()
+ defer v.mu.RUnlock()
+ return v.s
+}
+
+// String implements the Val interface. To get the unquoted string
+// use Value.
func (v *String) String() string {
v.mu.RLock()
s := v.s
@@ -237,6 +253,10 @@ func (v *String) Set(value string) {
// and formatting the returned value using JSON.
type Func func() interface{}
+func (f Func) Value() interface{} {
+ return f()
+}
+
func (f Func) String() string {
v, _ := json.Marshal(f())
return string(v)
@@ -322,6 +342,13 @@ func expvarHandler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "\n}\n")
}
+// Handler returns the expvar HTTP Handler.
+//
+// This is only needed to install the handler in a non-standard location.
+func Handler() http.Handler {
+ return http.HandlerFunc(expvarHandler)
+}
+
func cmdline() interface{} {
return os.Args
}
diff --git a/src/expvar/expvar_test.go b/src/expvar/expvar_test.go
index 7b1c9df..0efa864 100644
--- a/src/expvar/expvar_test.go
+++ b/src/expvar/expvar_test.go
@@ -7,13 +7,12 @@ package expvar
import (
"bytes"
"encoding/json"
- "math"
"net"
"net/http/httptest"
+ "reflect"
"runtime"
"strconv"
"sync"
- "sync/atomic"
"testing"
)
@@ -58,6 +57,10 @@ func TestInt(t *testing.T) {
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)
+ }
}
func BenchmarkIntAdd(b *testing.B) {
@@ -80,10 +83,6 @@ func BenchmarkIntSet(b *testing.B) {
})
}
-func (v *Float) val() float64 {
- return math.Float64frombits(atomic.LoadUint64(&v.f))
-}
-
func TestFloat(t *testing.T) {
RemoveAll()
reqs := NewFloat("requests-float")
@@ -96,8 +95,8 @@ func TestFloat(t *testing.T) {
reqs.Add(1.5)
reqs.Add(1.25)
- if v := reqs.val(); v != 2.75 {
- t.Errorf("reqs.val() = %v, want 2.75", v)
+ if v := reqs.Value(); v != 2.75 {
+ t.Errorf("reqs.Value() = %v, want 2.75", v)
}
if s := reqs.String(); s != "2.75" {
@@ -105,8 +104,8 @@ func TestFloat(t *testing.T) {
}
reqs.Add(-2)
- if v := reqs.val(); v != 0.75 {
- t.Errorf("reqs.val() = %v, want 0.75", v)
+ if v := reqs.Value(); v != 0.75 {
+ t.Errorf("reqs.Value() = %v, want 0.75", v)
}
}
@@ -146,6 +145,10 @@ func TestString(t *testing.T) {
t.Errorf("from %q, name.String() = %q, want %q", name.s, s, want)
}
+ if s, want := name.Value(), "Mike"; s != want {
+ t.Errorf("from %q, name.Value() = %q, want %q", name.s, s, want)
+ }
+
// Make sure we produce safe JSON output.
name.Set(`<`)
if s, want := name.String(), "\"\\u003c\""; s != want {
@@ -177,7 +180,7 @@ func TestMapCounter(t *testing.T) {
if x := colors.m["blue"].(*Int).i; x != 4 {
t.Errorf("colors.m[\"blue\"] = %v, want 4", x)
}
- if x := colors.m[`green "midori"`].(*Float).val(); x != 4.125 {
+ if x := colors.m[`green "midori"`].(*Float).Value(); x != 4.125 {
t.Errorf("colors.m[`green \"midori\"] = %v, want 4.125", x)
}
@@ -242,6 +245,9 @@ func TestFunc(t *testing.T) {
if s, exp := f.String(), `["a","b"]`; s != exp {
t.Errorf(`f.String() = %q, want %q`, s, exp)
}
+ if v := f.Value(); !reflect.DeepEqual(v, x) {
+ t.Errorf(`f.Value() = %q, want %q`, v, x)
+ }
x = 17
if s, exp := f.String(), `17`; s != exp {
diff --git a/src/flag/export_test.go b/src/flag/export_test.go
index 12d3dc7..edbe83c 100644
--- a/src/flag/export_test.go
+++ b/src/flag/export_test.go
@@ -13,5 +13,6 @@ import "os"
// exit the program.
func ResetForTesting(usage func()) {
CommandLine = NewFlagSet(os.Args[0], ContinueOnError)
+ CommandLine.Usage = commandLineUsage
Usage = usage
}
diff --git a/src/flag/flag.go b/src/flag/flag.go
index fa0f05e..bbbc55a 100644
--- a/src/flag/flag.go
+++ b/src/flag/flag.go
@@ -94,7 +94,7 @@ func (b *boolValue) Set(s string) error {
func (b *boolValue) Get() interface{} { return bool(*b) }
-func (b *boolValue) String() string { return fmt.Sprintf("%v", *b) }
+func (b *boolValue) String() string { return strconv.FormatBool(bool(*b)) }
func (b *boolValue) IsBoolFlag() bool { return true }
@@ -121,7 +121,7 @@ func (i *intValue) Set(s string) error {
func (i *intValue) Get() interface{} { return int(*i) }
-func (i *intValue) String() string { return fmt.Sprintf("%v", *i) }
+func (i *intValue) String() string { return strconv.Itoa(int(*i)) }
// -- int64 Value
type int64Value int64
@@ -139,7 +139,7 @@ func (i *int64Value) Set(s string) error {
func (i *int64Value) Get() interface{} { return int64(*i) }
-func (i *int64Value) String() string { return fmt.Sprintf("%v", *i) }
+func (i *int64Value) String() string { return strconv.FormatInt(int64(*i), 10) }
// -- uint Value
type uintValue uint
@@ -157,7 +157,7 @@ func (i *uintValue) Set(s string) error {
func (i *uintValue) Get() interface{} { return uint(*i) }
-func (i *uintValue) String() string { return fmt.Sprintf("%v", *i) }
+func (i *uintValue) String() string { return strconv.FormatUint(uint64(*i), 10) }
// -- uint64 Value
type uint64Value uint64
@@ -175,7 +175,7 @@ func (i *uint64Value) Set(s string) error {
func (i *uint64Value) Get() interface{} { return uint64(*i) }
-func (i *uint64Value) String() string { return fmt.Sprintf("%v", *i) }
+func (i *uint64Value) String() string { return strconv.FormatUint(uint64(*i), 10) }
// -- string Value
type stringValue string
@@ -192,7 +192,7 @@ func (s *stringValue) Set(val string) error {
func (s *stringValue) Get() interface{} { return string(*s) }
-func (s *stringValue) String() string { return fmt.Sprintf("%s", *s) }
+func (s *stringValue) String() string { return string(*s) }
// -- float64 Value
type float64Value float64
@@ -210,7 +210,7 @@ func (f *float64Value) Set(s string) error {
func (f *float64Value) Get() interface{} { return float64(*f) }
-func (f *float64Value) String() string { return fmt.Sprintf("%v", *f) }
+func (f *float64Value) String() string { return strconv.FormatFloat(float64(*f), 'g', -1, 64) }
// -- time.Duration Value
type durationValue time.Duration
@@ -238,6 +238,8 @@ func (d *durationValue) String() string { return (*time.Duration)(d).String() }
// rather than using the next command-line argument.
//
// Set is called once, in command line order, for each flag present.
+// The flag package may call the String method with a zero-valued receiver,
+// such as a nil pointer.
type Value interface {
String() string
Set(string) error
@@ -500,7 +502,7 @@ func PrintDefaults() {
}
// defaultUsage is the default function to print a usage message.
-func defaultUsage(f *FlagSet) {
+func (f *FlagSet) defaultUsage() {
if f.name == "" {
fmt.Fprintf(f.out(), "Usage:\n")
} else {
@@ -819,11 +821,7 @@ func (f *FlagSet) failf(format string, a ...interface{}) error {
// or the appropriate default usage function otherwise.
func (f *FlagSet) usage() {
if f.Usage == nil {
- if f == CommandLine {
- Usage()
- } else {
- defaultUsage(f)
- }
+ f.defaultUsage()
} else {
f.Usage()
}
@@ -953,6 +951,18 @@ func Parsed() bool {
// methods of CommandLine.
var CommandLine = NewFlagSet(os.Args[0], ExitOnError)
+func init() {
+ // Override generic FlagSet default Usage with call to global Usage.
+ // Note: This is not CommandLine.Usage = Usage,
+ // because we want any eventual call to use any updated value of Usage,
+ // not the value it has when this line is run.
+ CommandLine.Usage = commandLineUsage
+}
+
+func commandLineUsage() {
+ Usage()
+}
+
// NewFlagSet returns a new, empty flag set with the specified name and
// error handling property.
func NewFlagSet(name string, errorHandling ErrorHandling) *FlagSet {
@@ -960,6 +970,7 @@ func NewFlagSet(name string, errorHandling ErrorHandling) *FlagSet {
name: name,
errorHandling: errorHandling,
}
+ f.Usage = f.defaultUsage
return f
}
diff --git a/src/fmt/doc.go b/src/fmt/doc.go
index c312914..a2faecb 100644
--- a/src/fmt/doc.go
+++ b/src/fmt/doc.go
@@ -48,13 +48,10 @@
Pointer:
%p base 16 notation, with leading 0x
- There is no 'u' flag. Integers are printed unsigned if they have unsigned type.
- Similarly, there is no need to specify the size of the operand (int8, int64).
-
The default format for %v is:
bool: %t
int, int8 etc.: %d
- uint, uint8 etc.: %d, %x if printed with %#v
+ uint, uint8 etc.: %d, %#x if printed with %#v
float32, complex64, etc: %g
string: %s
chan: %p
@@ -177,6 +174,9 @@
that type has a String method. Such pathologies are rare, however,
and the package does not protect against them.
+ When printing a struct, fmt cannot and therefore does not invoke
+ formatting methods such as Error or String on unexported fields.
+
Explicit argument indexes:
In Printf, Sprintf, and Fprintf, the default behavior is for each
@@ -247,31 +247,42 @@
Scanln, Fscanln and Sscanln stop scanning at a newline and
require that the items be followed by a newline or EOF.
- Scanf, Fscanf and Sscanf require that (after skipping spaces)
- newlines in the format are matched by newlines in the input
- and vice versa. This behavior differs from the corresponding
- routines in C, which uniformly treat newlines as spaces.
-
- When scanning with Scanf, Fscanf, and Sscanf, all non-empty
- runs of space characters (except newline) are equivalent
- to a single space in both the format and the input. With
- that proviso, text in the format string must match the input
- text; scanning stops if it does not, with the return value
- of the function indicating the number of arguments scanned.
-
Scanf, Fscanf, and Sscanf parse the arguments according to a
- format string, analogous to that of Printf. For example, %x
- will scan an integer as a hexadecimal number, and %v will scan
- the default representation format for the value.
-
- The formats behave analogously to those of Printf with the
- following exceptions:
-
- %p is not implemented
- %T is not implemented
- %e %E %f %F %g %G are all equivalent and scan any floating point or complex value
- %s and %v on strings scan a space-delimited token
- Flags # and + are not implemented.
+ format string, analogous to that of Printf. In the text that
+ follows, 'space' means any Unicode whitespace character
+ except newline.
+
+ In the format string, a verb introduced by the % character
+ consumes and parses input; these verbs are described in more
+ detail below. A character other than %, space, or newline in
+ the format consumes exactly that input character, which must
+ be present. A newline with zero or more spaces before it in
+ the format string consumes zero or more spaces in the input
+ followed by a single newline or the end of the input. A space
+ following a newline in the format string consumes zero or more
+ spaces in the input. Otherwise, any run of one or more spaces
+ in the format string consumes as many spaces as possible in
+ the input. Unless the run of spaces in the format string
+ appears adjacent to a newline, the run must consume at least
+ one space from the input or find the end of the input.
+
+ The handling of spaces and newlines differs from that of C's
+ scanf family: in C, newlines are treated as any other space,
+ and it is never an error when a run of spaces in the format
+ string finds no spaces to consume in the input.
+
+ The verbs behave analogously to those of Printf.
+ For example, %x will scan an integer as a hexadecimal number,
+ and %v will scan the default representation format for the value.
+ The Printf verbs %p and %T and the flags # and + are not implemented,
+ and the verbs %e %E %f %F %g and %G are all equivalent and scan any
+ floating-point or complex value.
+
+ Input processed by verbs is implicitly space-delimited: the
+ implementation of every verb except %c starts by discarding
+ leading spaces from the remaining input, and the %s verb
+ (and %v reading into a string) stops consuming input at the first
+ space or newline character.
The familiar base-setting prefixes 0 (octal) and 0x
(hexadecimal) are accepted when scanning integers without
@@ -300,6 +311,9 @@
All arguments to be scanned must be either pointers to basic
types or implementations of the Scanner interface.
+ Like Scanf and Fscanf, Sscanf need not consume its entire input.
+ There is no way to recover how much of the input string Sscanf used.
+
Note: Fscan etc. can read one character (rune) past the input
they return, which means that a loop calling a scan routine
may skip some of the input. This is usually a problem only
diff --git a/src/fmt/export_test.go b/src/fmt/export_test.go
index 12d5a11..14163a2 100644
--- a/src/fmt/export_test.go
+++ b/src/fmt/export_test.go
@@ -5,3 +5,4 @@
package fmt
var IsSpace = isSpace
+var Parsenum = parsenum
diff --git a/src/fmt/fmt_test.go b/src/fmt/fmt_test.go
index 5fb2a63..6f8c155 100644
--- a/src/fmt/fmt_test.go
+++ b/src/fmt/fmt_test.go
@@ -605,7 +605,10 @@ var fmtTests = []struct {
{"%x", I(23), `3c32333e`},
{"%#x", I(23), `0x3c32333e`},
{"%# x", I(23), `0x3c 0x32 0x33 0x3e`},
- {"%d", I(23), `23`}, // Stringer applies only to string formats.
+ // Stringer applies only to string formats.
+ {"%d", I(23), `23`},
+ // Stringer applies to the extracted value.
+ {"%s", reflect.ValueOf(I(23)), `<23>`},
// go syntax
{"%#v", A{1, 2, "a", []int{1, 2}}, `fmt_test.A{i:1, j:0x2, s:"a", x:[]int{1, 2}}`},
@@ -1737,3 +1740,26 @@ func TestFormatterFlags(t *testing.T) {
}
}
}
+
+func TestParsenum(t *testing.T) {
+ testCases := []struct {
+ s string
+ start, end int
+ num int
+ isnum bool
+ newi int
+ }{
+ {"a123", 0, 4, 0, false, 0},
+ {"1234", 1, 1, 0, false, 1},
+ {"123a", 0, 4, 123, true, 3},
+ {"12a3", 0, 4, 12, true, 2},
+ {"1234", 0, 4, 1234, true, 4},
+ {"1a234", 1, 3, 0, false, 1},
+ }
+ for _, tt := range testCases {
+ num, isnum, newi := Parsenum(tt.s, tt.start, tt.end)
+ if num != tt.num || isnum != tt.isnum || newi != tt.newi {
+ t.Errorf("parsenum(%q, %d, %d) = %d, %v, %d, want %d, %v, %d", tt.s, tt.start, tt.end, num, isnum, newi, tt.num, tt.isnum, tt.newi)
+ }
+ }
+}
diff --git a/src/fmt/format.go b/src/fmt/format.go
index 0236475..f770483 100644
--- a/src/fmt/format.go
+++ b/src/fmt/format.go
@@ -46,7 +46,7 @@ type fmt struct {
wid int // width
prec int // precision
- // intbuf is large enought to store %b of an int64 with a sign and
+ // intbuf is large enough to store %b of an int64 with a sign and
// avoids padding at the end of the struct on 32 bit architectures.
intbuf [68]byte
}
diff --git a/src/fmt/print.go b/src/fmt/print.go
index f8c7316..75301a2 100644
--- a/src/fmt/print.go
+++ b/src/fmt/print.go
@@ -659,6 +659,14 @@ func (p *pp) printArg(arg interface{}, verb rune) {
case []byte:
p.fmtBytes(f, verb, "[]byte")
case reflect.Value:
+ // Handle extractable values with special methods
+ // since printValue does not handle them at depth 0.
+ if f.IsValid() && f.CanInterface() {
+ p.arg = f.Interface()
+ if p.handleMethods(verb) {
+ return
+ }
+ }
p.printValue(f, verb, 0)
default:
// If the type is not simple, it might have methods.
diff --git a/src/fmt/scan.go b/src/fmt/scan.go
index fdf4197..cd7232c 100644
--- a/src/fmt/scan.go
+++ b/src/fmt/scan.go
@@ -1075,6 +1075,58 @@ func (s *ss) doScan(a []interface{}) (numProcessed int, err error) {
func (s *ss) advance(format string) (i int) {
for i < len(format) {
fmtc, w := utf8.DecodeRuneInString(format[i:])
+
+ // Space processing.
+ // In the rest of this comment "space" means spaces other than newline.
+ // Newline in the format matches input of zero or more spaces and then newline or end-of-input.
+ // Spaces in the format before the newline are collapsed into the newline.
+ // Spaces in the format after the newline match zero or more spaces after the corresponding input newline.
+ // Other spaces in the format match input of one or more spaces or end-of-input.
+ if isSpace(fmtc) {
+ newlines := 0
+ trailingSpace := false
+ for isSpace(fmtc) && i < len(format) {
+ if fmtc == '\n' {
+ newlines++
+ trailingSpace = false
+ } else {
+ trailingSpace = true
+ }
+ i += w
+ fmtc, w = utf8.DecodeRuneInString(format[i:])
+ }
+ for j := 0; j < newlines; j++ {
+ inputc := s.getRune()
+ for isSpace(inputc) && inputc != '\n' {
+ inputc = s.getRune()
+ }
+ if inputc != '\n' && inputc != eof {
+ s.errorString("newline in format does not match input")
+ }
+ }
+ if trailingSpace {
+ inputc := s.getRune()
+ if newlines == 0 {
+ // If the trailing space stood alone (did not follow a newline),
+ // it must find at least one space to consume.
+ if !isSpace(inputc) && inputc != eof {
+ s.errorString("expected space in input to match format")
+ }
+ if inputc == '\n' {
+ s.errorString("newline in input does not match format")
+ }
+ }
+ for isSpace(inputc) && inputc != '\n' {
+ inputc = s.getRune()
+ }
+ if inputc != eof {
+ s.UnreadRune()
+ }
+ }
+ continue
+ }
+
+ // Verbs.
if fmtc == '%' {
// % at end of string is an error.
if i+w == len(format) {
@@ -1087,48 +1139,8 @@ func (s *ss) advance(format string) (i int) {
}
i += w // skip the first %
}
- sawSpace := false
- wasNewline := false
- // Skip spaces in format but absorb at most one newline.
- for isSpace(fmtc) && i < len(format) {
- if fmtc == '\n' {
- if wasNewline { // Already saw one; stop here.
- break
- }
- wasNewline = true
- }
- sawSpace = true
- i += w
- fmtc, w = utf8.DecodeRuneInString(format[i:])
- }
- if sawSpace {
- // There was space in the format, so there should be space
- // in the input.
- inputc := s.getRune()
- if inputc == eof {
- return
- }
- if !isSpace(inputc) {
- // Space in format but not in input.
- s.errorString("expected space in input to match format")
- }
- // Skip spaces but stop at newline.
- for inputc != '\n' && isSpace(inputc) {
- inputc = s.getRune()
- }
- if inputc == '\n' {
- if !wasNewline {
- s.errorString("newline in input does not match format")
- }
- // We've reached a newline, stop now; don't read further.
- return
- }
- s.UnreadRune()
- if wasNewline {
- s.errorString("newline in format does not match input")
- }
- continue
- }
+
+ // Literals.
inputc := s.mustReadRune()
if fmtc != inputc {
s.UnreadRune()
diff --git a/src/fmt/scan_test.go b/src/fmt/scan_test.go
index e36b62e..d7019d9 100644
--- a/src/fmt/scan_test.go
+++ b/src/fmt/scan_test.go
@@ -291,6 +291,97 @@ var scanfTests = []ScanfTest{
{"%c", " ", &uintVal, uint(' ')}, // %c must accept a blank.
{"%c", "\t", &uintVal, uint('\t')}, // %c must accept any space.
{"%c", "\n", &uintVal, uint('\n')}, // %c must accept any space.
+
+ // space handling
+ {"%d", "27", &intVal, 27},
+ {"%d", "27 ", &intVal, 27},
+ {"%d", " 27", &intVal, 27},
+ {"%d", " 27 ", &intVal, 27},
+
+ {"X%d", "X27", &intVal, 27},
+ {"X%d", "X27 ", &intVal, 27},
+ {"X%d", "X 27", &intVal, 27},
+ {"X%d", "X 27 ", &intVal, 27},
+
+ {"X %d", "X27", &intVal, nil}, // expected space in input to match format
+ {"X %d", "X27 ", &intVal, nil}, // expected space in input to match format
+ {"X %d", "X 27", &intVal, 27},
+ {"X %d", "X 27 ", &intVal, 27},
+
+ {"%dX", "27X", &intVal, 27},
+ {"%dX", "27 X", &intVal, nil}, // input does not match format
+ {"%dX", " 27X", &intVal, 27},
+ {"%dX", " 27 X", &intVal, nil}, // input does not match format
+
+ {"%d X", "27X", &intVal, nil}, // expected space in input to match format
+ {"%d X", "27 X", &intVal, 27},
+ {"%d X", " 27X", &intVal, nil}, // expected space in input to match format
+ {"%d X", " 27 X", &intVal, 27},
+
+ {"X %d X", "X27X", &intVal, nil}, // expected space in input to match format
+ {"X %d X", "X27 X", &intVal, nil}, // expected space in input to match format
+ {"X %d X", "X 27X", &intVal, nil}, // expected space in input to match format
+ {"X %d X", "X 27 X", &intVal, 27},
+
+ {"X %s X", "X27X", &stringVal, nil}, // expected space in input to match format
+ {"X %s X", "X27 X", &stringVal, nil}, // expected space in input to match format
+ {"X %s X", "X 27X", &stringVal, nil}, // unexpected EOF
+ {"X %s X", "X 27 X", &stringVal, "27"},
+
+ {"X%sX", "X27X", &stringVal, nil}, // unexpected EOF
+ {"X%sX", "X27 X", &stringVal, nil}, // input does not match format
+ {"X%sX", "X 27X", &stringVal, nil}, // unexpected EOF
+ {"X%sX", "X 27 X", &stringVal, nil}, // input does not match format
+
+ {"X%s", "X27", &stringVal, "27"},
+ {"X%s", "X27 ", &stringVal, "27"},
+ {"X%s", "X 27", &stringVal, "27"},
+ {"X%s", "X 27 ", &stringVal, "27"},
+
+ {"X%dX", "X27X", &intVal, 27},
+ {"X%dX", "X27 X", &intVal, nil}, // input does not match format
+ {"X%dX", "X 27X", &intVal, 27},
+ {"X%dX", "X 27 X", &intVal, nil}, // input does not match format
+
+ {"X%dX", "X27X", &intVal, 27},
+ {"X%dX", "X27X ", &intVal, 27},
+ {"X%dX", " X27X", &intVal, nil}, // input does not match format
+ {"X%dX", " X27X ", &intVal, nil}, // input does not match format
+
+ {"X%dX\n", "X27X", &intVal, 27},
+ {"X%dX \n", "X27X ", &intVal, 27},
+ {"X%dX\n", "X27X\n", &intVal, 27},
+ {"X%dX\n", "X27X \n", &intVal, 27},
+
+ {"X%dX \n", "X27X", &intVal, 27},
+ {"X%dX \n", "X27X ", &intVal, 27},
+ {"X%dX \n", "X27X\n", &intVal, 27},
+ {"X%dX \n", "X27X \n", &intVal, 27},
+
+ {"X%c", "X\n", &runeVal, '\n'},
+ {"X%c", "X \n", &runeVal, ' '},
+ {"X %c", "X!", &runeVal, nil}, // expected space in input to match format
+ {"X %c", "X\n", &runeVal, nil}, // newline in input does not match format
+ {"X %c", "X !", &runeVal, '!'},
+ {"X %c", "X \n", &runeVal, '\n'},
+
+ {" X%dX", "X27X", &intVal, nil}, // expected space in input to match format
+ {" X%dX", "X27X ", &intVal, nil}, // expected space in input to match format
+ {" X%dX", " X27X", &intVal, 27},
+ {" X%dX", " X27X ", &intVal, 27},
+
+ {"X%dX ", "X27X", &intVal, 27},
+ {"X%dX ", "X27X ", &intVal, 27},
+ {"X%dX ", " X27X", &intVal, nil}, // input does not match format
+ {"X%dX ", " X27X ", &intVal, nil}, // input does not match format
+
+ {" X%dX ", "X27X", &intVal, nil}, // expected space in input to match format
+ {" X%dX ", "X27X ", &intVal, nil}, // expected space in input to match format
+ {" X%dX ", " X27X", &intVal, 27},
+ {" X%dX ", " X27X ", &intVal, 27},
+
+ {"%d\nX", "27\nX", &intVal, 27},
+ {"%dX\n X", "27X\n X", &intVal, 27},
}
var overflowTests = []ScanTest{
@@ -416,11 +507,17 @@ func TestScanf(t *testing.T) {
for _, test := range scanfTests {
n, err := Sscanf(test.text, test.format, test.in)
if err != nil {
- t.Errorf("got error scanning (%q, %q): %s", test.format, test.text, err)
+ if test.out != nil {
+ t.Errorf("Sscanf(%q, %q): unexpected error: %v", test.text, test.format, err)
+ }
+ continue
+ }
+ if test.out == nil {
+ t.Errorf("Sscanf(%q, %q): unexpected success", test.text, test.format)
continue
}
if n != 1 {
- t.Errorf("count error on entry (%q, %q): got %d", test.format, test.text, n)
+ t.Errorf("Sscanf(%q, %q): parsed %d field, want 1", test.text, test.format, n)
continue
}
// The incoming value may be a pointer
@@ -430,7 +527,7 @@ func TestScanf(t *testing.T) {
}
val := v.Interface()
if !reflect.DeepEqual(val, test.out) {
- t.Errorf("scanning (%q, %q): expected %#v got %#v, type %T", test.format, test.text, test.out, val, val)
+ t.Errorf("Sscanf(%q, %q): parsed value %T(%#v), want %T(%#v)", test.text, test.format, val, val, test.out, test.out)
}
}
}
@@ -1113,9 +1210,47 @@ func TestScanfNewlineMatchFormat(t *testing.T) {
{"space-newline in both", "1 \n2", "%d \n%d", 2, true},
{"extra space in format", "1\n2", "%d\n %d", 2, true},
{"two extra spaces in format", "1\n2", "%d \n %d", 2, true},
+ {"space vs newline 0000", "1\n2", "%d\n%d", 2, true},
+ {"space vs newline 0001", "1\n2", "%d\n %d", 2, true},
+ {"space vs newline 0010", "1\n2", "%d \n%d", 2, true},
+ {"space vs newline 0011", "1\n2", "%d \n %d", 2, true},
+ {"space vs newline 0100", "1\n 2", "%d\n%d", 2, true},
+ {"space vs newline 0101", "1\n 2", "%d\n%d ", 2, true},
+ {"space vs newline 0110", "1\n 2", "%d \n%d", 2, true},
+ {"space vs newline 0111", "1\n 2", "%d \n %d", 2, true},
+ {"space vs newline 1000", "1 \n2", "%d\n%d", 2, true},
+ {"space vs newline 1001", "1 \n2", "%d\n %d", 2, true},
+ {"space vs newline 1010", "1 \n2", "%d \n%d", 2, true},
+ {"space vs newline 1011", "1 \n2", "%d \n %d", 2, true},
+ {"space vs newline 1100", "1 \n 2", "%d\n%d", 2, true},
+ {"space vs newline 1101", "1 \n 2", "%d\n %d", 2, true},
+ {"space vs newline 1110", "1 \n 2", "%d \n%d", 2, true},
+ {"space vs newline 1111", "1 \n 2", "%d \n %d", 2, true},
+ {"space vs newline no-percent 0000", "1\n2", "1\n2", 0, true},
+ {"space vs newline no-percent 0001", "1\n2", "1\n 2", 0, true},
+ {"space vs newline no-percent 0010", "1\n2", "1 \n2", 0, true},
+ {"space vs newline no-percent 0011", "1\n2", "1 \n 2", 0, true},
+ {"space vs newline no-percent 0100", "1\n 2", "1\n2", 0, false}, // fails: space after nl in input but not pattern
+ {"space vs newline no-percent 0101", "1\n 2", "1\n2 ", 0, false}, // fails: space after nl in input but not pattern
+ {"space vs newline no-percent 0110", "1\n 2", "1 \n2", 0, false}, // fails: space after nl in input but not pattern
+ {"space vs newline no-percent 0111", "1\n 2", "1 \n 2", 0, true},
+ {"space vs newline no-percent 1000", "1 \n2", "1\n2", 0, true},
+ {"space vs newline no-percent 1001", "1 \n2", "1\n 2", 0, true},
+ {"space vs newline no-percent 1010", "1 \n2", "1 \n2", 0, true},
+ {"space vs newline no-percent 1011", "1 \n2", "1 \n 2", 0, true},
+ {"space vs newline no-percent 1100", "1 \n 2", "1\n2", 0, false}, // fails: space after nl in input but not pattern
+ {"space vs newline no-percent 1101", "1 \n 2", "1\n 2", 0, true},
+ {"space vs newline no-percent 1110", "1 \n 2", "1 \n2", 0, false}, // fails: space after nl in input but not pattern
+ {"space vs newline no-percent 1111", "1 \n 2", "1 \n 2", 0, true},
}
for _, test := range tests {
- n, err := Sscanf(test.text, test.format, &a, &b)
+ var n int
+ var err error
+ if strings.Contains(test.format, "%") {
+ n, err = Sscanf(test.text, test.format, &a, &b)
+ } else {
+ n, err = Sscanf(test.text, test.format)
+ }
if n != test.count {
t.Errorf("%s: expected to scan %d item(s), scanned %d", test.name, test.count, n)
}
diff --git a/src/go/ast/ast.go b/src/go/ast/ast.go
index d3dcd79..a197b5a 100644
--- a/src/go/ast/ast.go
+++ b/src/go/ast/ast.go
@@ -317,7 +317,7 @@ type (
Fun Expr // function expression
Lparen token.Pos // position of "("
Args []Expr // function arguments; or nil
- Ellipsis token.Pos // position of "...", if any
+ Ellipsis token.Pos // position of "..." (token.NoPos if there is no "...")
Rparen token.Pos // position of ")"
}
@@ -902,7 +902,7 @@ type (
// A GenDecl node (generic declaration node) represents an import,
// constant, type or variable declaration. A valid Lparen position
- // (Lparen.Line > 0) indicates a parenthesized declaration.
+ // (Lparen.IsValid()) indicates a parenthesized declaration.
//
// Relationship between Tok value and Specs element type:
//
diff --git a/src/go/build/build.go b/src/go/build/build.go
index 9706b8b..f6aabcb 100644
--- a/src/go/build/build.go
+++ b/src/go/build/build.go
@@ -256,13 +256,32 @@ func (ctxt *Context) SrcDirs() []string {
// if set, or else the compiled code's GOARCH, GOOS, and GOROOT.
var Default Context = defaultContext()
+func defaultGOPATH() string {
+ env := "HOME"
+ if runtime.GOOS == "windows" {
+ env = "USERPROFILE"
+ } else if runtime.GOOS == "plan9" {
+ env = "home"
+ }
+ if home := os.Getenv(env); home != "" {
+ def := filepath.Join(home, "go")
+ if def == runtime.GOROOT() {
+ // Don't set the default GOPATH to GOROOT,
+ // as that will trigger warnings from the go tool.
+ return ""
+ }
+ return def
+ }
+ return ""
+}
+
func defaultContext() Context {
var c Context
c.GOARCH = envOr("GOARCH", runtime.GOARCH)
c.GOOS = envOr("GOOS", runtime.GOOS)
c.GOROOT = pathpkg.Clean(runtime.GOROOT())
- c.GOPATH = envOr("GOPATH", "")
+ c.GOPATH = envOr("GOPATH", defaultGOPATH())
c.Compiler = runtime.Compiler
// Each major Go release in the Go 1.x series should add a tag here.
@@ -270,9 +289,13 @@ 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"}
+ c.ReleaseTags = []string{"go1.1", "go1.2", "go1.3", "go1.4", "go1.5", "go1.6", "go1.7", "go1.8"}
- switch os.Getenv("CGO_ENABLED") {
+ env := os.Getenv("CGO_ENABLED")
+ if env == "" {
+ env = defaultCGO_ENABLED
+ }
+ switch env {
case "1":
c.CgoEnabled = true
case "0":
@@ -336,6 +359,11 @@ const (
// See golang.org/s/go15vendor for more information.
//
// Setting IgnoreVendor ignores vendor directories.
+ //
+ // In contrast to the package's ImportPath,
+ // the returned package's Imports, TestImports, and XTestImports
+ // are always the exact import paths from the source files:
+ // Import makes no attempt to resolve or check those paths.
IgnoreVendor
)
@@ -381,15 +409,15 @@ type Package struct {
CgoPkgConfig []string // Cgo pkg-config directives
// Dependency information
- Imports []string // imports from GoFiles, CgoFiles
+ Imports []string // import paths from GoFiles, CgoFiles
ImportPos map[string][]token.Position // line information for Imports
// Test information
TestGoFiles []string // _test.go files in package
- TestImports []string // imports from TestGoFiles
+ TestImports []string // import paths from TestGoFiles
TestImportPos map[string][]token.Position // line information for TestImports
XTestGoFiles []string // _test.go files outside package
- XTestImports []string // imports from XTestGoFiles
+ XTestImports []string // import paths from XTestGoFiles
XTestImportPos map[string][]token.Position // line information for XTestImports
}
@@ -410,11 +438,16 @@ func (ctxt *Context) ImportDir(dir string, mode ImportMode) (*Package, error) {
// containing no buildable Go source files. (It may still contain
// test files, files hidden by build tags, and so on.)
type NoGoError struct {
- Dir string
+ Dir string
+ Ignored bool // whether any Go files were ignored due to build tags
}
func (e *NoGoError) Error() string {
- return "no buildable Go source files in " + e.Dir
+ msg := "no buildable Go source files in " + e.Dir
+ if e.Ignored {
+ msg += " (.go files ignored due to build tags)"
+ }
+ return msg
}
// MultiplePackageError describes a directory containing
@@ -636,7 +669,7 @@ func (ctxt *Context) Import(path string, srcDir string, mode ImportMode) (*Packa
format = "\t%s"
}
if len(tried.gopath) == 0 {
- paths = append(paths, "\t($GOPATH not set)")
+ paths = append(paths, "\t($GOPATH not set. For more details see: 'go help gopath')")
}
return p, fmt.Errorf("cannot find package %q in any of:\n%s", path, strings.Join(paths, "\n"))
}
@@ -846,7 +879,7 @@ Found:
return p, badGoError
}
if len(p.GoFiles)+len(p.CgoFiles)+len(p.TestGoFiles)+len(p.XTestGoFiles) == 0 {
- return p, &NoGoError{p.Dir}
+ return p, &NoGoError{Dir: p.Dir, Ignored: len(p.IgnoredGoFiles) > 0}
}
for tag := range allTags {
@@ -1063,10 +1096,14 @@ func (ctxt *Context) matchFile(dir, name string, returnImports bool, allTags map
}
// Look for +build comments to accept or reject the file.
- if !ctxt.shouldBuild(data, allTags, binaryOnly) && !ctxt.UseAllFiles {
+ var sawBinaryOnly bool
+ if !ctxt.shouldBuild(data, allTags, &sawBinaryOnly) && !ctxt.UseAllFiles {
return
}
+ if binaryOnly != nil && sawBinaryOnly {
+ *binaryOnly = true
+ }
match = true
return
}
@@ -1110,9 +1147,8 @@ var binaryOnlyComment = []byte("//go:binary-only-package")
//
// marks the file as applicable only on Windows and Linux.
//
-// If shouldBuild finds a //go:binary-only-package comment in a file that
-// should be built, it sets *binaryOnly to true. Otherwise it does
-// not change *binaryOnly.
+// If shouldBuild finds a //go:binary-only-package comment in the file,
+// it sets *binaryOnly to true. Otherwise it does not change *binaryOnly.
//
func (ctxt *Context) shouldBuild(content []byte, allTags map[string]bool, binaryOnly *bool) bool {
sawBinaryOnly := false
@@ -1282,7 +1318,8 @@ func expandSrcDir(str string, srcdir string) (string, bool) {
// 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.
-const safeString = "+-.,/0123456789=ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz:$@"
+// The % is for Jenkins. See golang.org/issue/16959.
+const safeString = "+-.,/0123456789=ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz:$@%"
const safeSpaces = " "
var safeBytes = []byte(safeSpaces + safeString)
diff --git a/src/go/build/build_test.go b/src/go/build/build_test.go
index 198a649..8ca8e5e 100644
--- a/src/go/build/build_test.go
+++ b/src/go/build/build_test.go
@@ -93,6 +93,17 @@ func TestEmptyFolderImport(t *testing.T) {
}
}
+func TestIgnoredGoFilesImport(t *testing.T) {
+ _, err := Import(".", "testdata/ignored", 0)
+ e, ok := err.(*NoGoError)
+ if !ok {
+ t.Fatal(`Import("testdata/ignored") did not return NoGoError.`)
+ }
+ if !e.Ignored {
+ t.Fatal(`Import("testdata/ignored") should have ignored Go files.`)
+ }
+}
+
func TestMultiplePackageImport(t *testing.T) {
_, err := Import(".", "testdata/multi", 0)
mpe, ok := err.(*MultiplePackageError)
@@ -283,6 +294,7 @@ func TestShellSafety(t *testing.T) {
result bool
}{
{"-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", "/tmp/[0]", "-I/tmp", true},
diff --git a/src/go/build/deps_test.go b/src/go/build/deps_test.go
index 5b25291..e6f2288 100644
--- a/src/go/build/deps_test.go
+++ b/src/go/build/deps_test.go
@@ -59,7 +59,6 @@ var pkgDeps = map[string][]string{
"math": {"unsafe"},
"math/cmplx": {"math"},
"math/rand": {"L0", "math"},
- "sort": {},
"strconv": {"L0", "unicode/utf8", "math"},
"unicode/utf16": {},
"unicode/utf8": {},
@@ -94,8 +93,8 @@ var pkgDeps = map[string][]string{
// L3 adds reflection and some basic utility packages
// and interface definitions, but nothing that makes
// system calls.
- "crypto": {"L2", "hash"}, // interfaces
- "crypto/cipher": {"L2", "crypto/subtle"}, // interfaces
+ "crypto": {"L2", "hash"}, // interfaces
+ "crypto/cipher": {"L2", "crypto/subtle"},
"crypto/subtle": {},
"encoding/base32": {"L2"},
"encoding/base64": {"L2"},
@@ -109,11 +108,13 @@ var pkgDeps = map[string][]string{
"image/color": {"L2"}, // interfaces
"image/color/palette": {"L2", "image/color"},
"reflect": {"L2"},
+ "sort": {"reflect"},
"L3": {
"L2",
"crypto",
"crypto/cipher",
+ "crypto/internal/cipherhw",
"crypto/subtle",
"encoding/base32",
"encoding/base64",
@@ -170,17 +171,18 @@ 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": {"L2", "fmt", "os", "text/tabwriter"},
- "runtime/trace": {"L0"},
- "text/tabwriter": {"L2"},
-
- "testing": {"L2", "flag", "fmt", "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/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", "context", "flag", "fmt", "internal/race", "os", "runtime/debug", "runtime/pprof", "runtime/trace", "time"},
"testing/iotest": {"L2", "log"},
"testing/quick": {"L2", "flag", "fmt", "reflect"},
- "internal/testenv": {"L2", "OS", "flag", "testing"},
+ "internal/testenv": {"L2", "OS", "flag", "testing", "syscall"},
// L4 is defined as L3+fmt+log+time, because in general once
// you're using L3 packages, use of fmt, log, or time is not a big deal.
@@ -219,50 +221,53 @@ var pkgDeps = map[string][]string{
"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", "database/sql/driver"},
- "database/sql/driver": {"L4", "time"},
- "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"},
- "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"},
+ "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"},
"html/template": {
"L4", "OS", "encoding/json", "html", "text/template",
@@ -297,7 +302,7 @@ var pkgDeps = map[string][]string{
"context", "math/rand", "os", "sort", "syscall", "time",
"internal/nettrace",
"internal/syscall/windows", "internal/singleflight", "internal/race",
- "golang_org/x/net/route",
+ "golang_org/x/net/lif", "golang_org/x/net/route",
},
// NET enables use of basic network-related packages.
@@ -332,6 +337,9 @@ var pkgDeps = map[string][]string{
"crypto/sha1",
"crypto/sha256",
"crypto/sha512",
+ "golang_org/x/crypto/chacha20poly1305",
+ "golang_org/x/crypto/curve25519",
+ "golang_org/x/crypto/poly1305",
},
// Random byte, number generation.
@@ -375,16 +383,24 @@ var pkgDeps = map[string][]string{
// HTTP, kingpin of dependencies.
"net/http": {
"L4", "NET", "OS",
- "context", "compress/gzip", "container/list", "crypto/tls",
- "mime/multipart", "runtime/debug",
- "net/http/internal",
+ "compress/gzip",
+ "container/list",
+ "context",
+ "crypto/rand",
+ "crypto/tls",
"golang_org/x/net/http2/hpack",
+ "golang_org/x/net/idna",
"golang_org/x/net/lex/httplex",
+ "golang_org/x/text/unicode/norm",
+ "golang_org/x/text/width",
"internal/nettrace",
+ "mime/multipart",
"net/http/httptrace",
+ "net/http/internal",
+ "runtime/debug",
},
"net/http/internal": {"L4"},
- "net/http/httptrace": {"context", "internal/nettrace", "net", "reflect", "time"},
+ "net/http/httptrace": {"context", "crypto/tls", "internal/nettrace", "net", "reflect", "time"},
// HTTP-using packages.
"expvar": {"L4", "OS", "encoding/json", "net/http"},
@@ -392,7 +408,7 @@ var pkgDeps = map[string][]string{
"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/httputil": {"L4", "NET", "OS", "net/http", "net/http/internal"},
+ "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"},
"net/rpc/jsonrpc": {"L4", "NET", "encoding/json", "net/rpc"},
diff --git a/src/go/build/doc.go b/src/go/build/doc.go
index 9f7ac8f..979d047 100644
--- a/src/go/build/doc.go
+++ b/src/go/build/doc.go
@@ -104,6 +104,7 @@
// - "go1.5", from Go version 1.5 onward
// - "go1.6", from Go version 1.6 onward
// - "go1.7", from Go version 1.7 onward
+// - "go1.8", from Go version 1.8 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/build/syslist.go b/src/go/build/syslist.go
index c83622b..73fdbe6 100644
--- a/src/go/build/syslist.go
+++ b/src/go/build/syslist.go
@@ -4,5 +4,5 @@
package build
-const goosList = "android darwin dragonfly freebsd linux nacl netbsd openbsd plan9 solaris windows "
+const goosList = "android darwin dragonfly freebsd linux nacl netbsd openbsd plan9 solaris windows zos "
const goarchList = "386 amd64 amd64p32 arm armbe arm64 arm64be ppc64 ppc64le mips mipsle mips64 mips64le mips64p32 mips64p32le ppc s390 s390x sparc sparc64 "
diff --git a/src/go/build/testdata/ignored/ignored.go b/src/go/build/testdata/ignored/ignored.go
new file mode 100644
index 0000000..48a2ae8
--- /dev/null
+++ b/src/go/build/testdata/ignored/ignored.go
@@ -0,0 +1,3 @@
+// +build alwaysignore
+
+package ignored
diff --git a/src/go/constant/value.go b/src/go/constant/value.go
index ab10ae3..7c32473 100644
--- a/src/go/constant/value.go
+++ b/src/go/constant/value.go
@@ -43,13 +43,14 @@ type Value interface {
// Kind returns the value kind.
Kind() Kind
- // String returns a short, human-readable form of the value.
+ // String returns a short, quoted (human-readable) form of the value.
// For numeric values, the result may be an approximation;
// for String values the result may be a shortened string.
// Use ExactString for a string representing a value exactly.
String() string
- // ExactString returns an exact, printable form of the value.
+ // ExactString returns an exact, quoted (human-readable) form of the value.
+ // If the Value is of Kind String, use StringVal to obtain the unquoted string.
ExactString() string
// Prevent external implementations.
@@ -847,6 +848,10 @@ Error:
func ord(x Value) int {
switch x.(type) {
+ default:
+ // force invalid value into "x position" in match
+ // (don't panic here so that callers can provide a better error message)
+ return -1
case unknownVal:
return 0
case boolVal, stringVal:
@@ -861,15 +866,13 @@ func ord(x Value) int {
return 5
case complexVal:
return 6
- default:
- panic("unreachable")
}
}
// match returns the matching representation (same type) with the
// smallest complexity for two values x and y. If one of them is
-// numeric, both of them must be numeric. If one of them is Unknown,
-// both results are Unknown.
+// numeric, both of them must be numeric. If one of them is Unknown
+// or invalid (say, nil) both results are that value.
//
func match(x, y Value) (_, _ Value) {
if ord(x) > ord(y) {
@@ -879,9 +882,6 @@ func match(x, y Value) (_, _ Value) {
// ord(x) <= ord(y)
switch x := x.(type) {
- case unknownVal:
- return x, x
-
case boolVal, stringVal, complexVal:
return x, y
@@ -920,6 +920,7 @@ func match(x, y Value) (_, _ Value) {
case complexVal:
return vtoc(x), y
}
+
case floatVal:
switch y := y.(type) {
case floatVal:
@@ -929,18 +930,23 @@ func match(x, y Value) (_, _ Value) {
}
}
- panic("unreachable")
+ // force unknown and invalid values into "x position" in callers of match
+ // (don't panic here so that callers can provide a better error message)
+ return x, x
}
// BinaryOp returns the result of the binary expression x op y.
// The operation must be defined for the operands. If one of the
// operands is Unknown, the result is Unknown.
+// BinaryOp doesn't handle comparisons or shifts; use Compare
+// or Shift instead.
+//
// To force integer division of Int operands, use op == token.QUO_ASSIGN
// instead of token.QUO; the result is guaranteed to be Int in this case.
// Division by zero leads to a run-time panic.
//
-func BinaryOp(x Value, op token.Token, y Value) Value {
- x, y = match(x, y)
+func BinaryOp(x_ Value, op token.Token, y_ Value) Value {
+ x, y := match(x_, y_)
switch x := x.(type) {
case unknownVal:
@@ -1107,7 +1113,7 @@ func BinaryOp(x Value, op token.Token, y Value) Value {
}
Error:
- panic(fmt.Sprintf("invalid binary operation %v %s %v", x, op, y))
+ panic(fmt.Sprintf("invalid binary operation %v %s %v", x_, op, y_))
}
func add(x, y Value) Value { return BinaryOp(x, token.ADD, y) }
@@ -1167,7 +1173,7 @@ func cmpZero(x int, op token.Token) bool {
case token.GEQ:
return x >= 0
}
- panic("unreachable")
+ panic(fmt.Sprintf("invalid comparison %v %s 0", x, op))
}
// Compare returns the result of the comparison x op y.
@@ -1175,8 +1181,8 @@ func cmpZero(x int, op token.Token) bool {
// If one of the operands is Unknown, the result is
// false.
//
-func Compare(x Value, op token.Token, y Value) bool {
- x, y = match(x, y)
+func Compare(x_ Value, op token.Token, y_ Value) bool {
+ x, y := match(x_, y_)
switch x := x.(type) {
case unknownVal:
@@ -1246,5 +1252,5 @@ func Compare(x Value, op token.Token, y Value) bool {
}
}
- panic(fmt.Sprintf("invalid comparison %v %s %v", x, op, y))
+ panic(fmt.Sprintf("invalid comparison %v %s %v", x_, op, y_))
}
diff --git a/src/go/doc/comment.go b/src/go/doc/comment.go
index ed8eef4..15e034b 100644
--- a/src/go/doc/comment.go
+++ b/src/go/doc/comment.go
@@ -53,7 +53,7 @@ const (
filePart = `[a-zA-Z0-9_?%#~&/\-+=()]+` // parentheses may not be matching; see pairedParensPrefixLen
urlRx = `(` + protocol + `)://` + // http://
hostPart + `([.:]` + hostPart + `)*/?` + // //www.google.com:8080/
- filePart + `([:.,]` + filePart + `)*`
+ filePart + `([:.,;]` + filePart + `)*`
)
var matchRx = regexp.MustCompile(`(` + urlRx + `)|(` + identRx + `)`)
diff --git a/src/go/doc/comment_test.go b/src/go/doc/comment_test.go
index ad65c2a..76dfbea 100644
--- a/src/go/doc/comment_test.go
+++ b/src/go/doc/comment_test.go
@@ -162,6 +162,7 @@ var emphasizeTests = []struct {
{"Hello http://example.com/%2f/ /world.", `Hello <a href="http://example.com/%2f/">http://example.com/%2f/</a> /world.`},
{"Lorem http: ipsum //host/path", "Lorem http: ipsum //host/path"},
{"javascript://is/not/linked", "javascript://is/not/linked"},
+ {"http://git.qemu.org/?p=qemu.git;a=blob;f=qapi-schema.json;hb=HEAD", `<a href="http://git.qemu.org/?p=qemu.git;a=blob;f=qapi-schema.json;hb=HEAD">http://git.qemu.org/?p=qemu.git;a=blob;f=qapi-schema.json;hb=HEAD</a>`},
}
func TestEmphasize(t *testing.T) {
diff --git a/src/go/doc/reader.go b/src/go/doc/reader.go
index e4e7b7c..8e82353 100644
--- a/src/go/doc/reader.go
+++ b/src/go/doc/reader.go
@@ -362,6 +362,11 @@ func (r *reader) readFunc(fun *ast.FuncDecl) {
// associate methods with the receiver type, if any
if fun.Recv != nil {
// method
+ if len(fun.Recv.List) == 0 {
+ // should not happen (incorrect AST); (See issue 17788)
+ // don't show this method
+ return
+ }
recvTypeName, imp := baseTypeName(fun.Recv.List[0].Type)
if imp {
// should not happen (incorrect AST);
@@ -645,7 +650,9 @@ func (r *reader) computeMethodSets() {
func (r *reader) cleanupTypes() {
for _, t := range r.types {
visible := r.isVisible(t.name)
- if t.decl == nil && (predeclaredTypes[t.name] || visible && (t.isEmbedded || r.hasDotImp)) {
+ predeclared := predeclaredTypes[t.name]
+
+ if t.decl == nil && (predeclared || visible && (t.isEmbedded || r.hasDotImp)) {
// t.name is a predeclared type (and was not redeclared in this package),
// or it was embedded somewhere but its declaration is missing (because
// the AST is incomplete), or we have a dot-import (and all bets are off):
@@ -660,10 +667,12 @@ func (r *reader) cleanupTypes() {
r.funcs[name] = f
}
// 3) move methods
- for name, m := range t.methods {
- // don't overwrite functions with the same name - drop them
- if _, found := r.funcs[name]; !found {
- r.funcs[name] = m
+ if !predeclared {
+ for name, m := range t.methods {
+ // don't overwrite functions with the same name - drop them
+ if _, found := r.funcs[name]; !found {
+ r.funcs[name] = m
+ }
}
}
}
@@ -809,6 +818,11 @@ func noteBodies(notes []*Note) []string {
// ----------------------------------------------------------------------------
// Predeclared identifiers
+// IsPredeclared reports whether s is a predeclared identifier.
+func IsPredeclared(s string) bool {
+ return predeclaredTypes[s] || predeclaredFuncs[s] || predeclaredConstants[s]
+}
+
var predeclaredTypes = map[string]bool{
"bool": true,
"byte": true,
diff --git a/src/go/doc/testdata/issue17788.0.golden b/src/go/doc/testdata/issue17788.0.golden
new file mode 100644
index 0000000..42c00da
--- /dev/null
+++ b/src/go/doc/testdata/issue17788.0.golden
@@ -0,0 +1,8 @@
+//
+PACKAGE issue17788
+
+IMPORTPATH
+ testdata/issue17788
+
+FILENAMES
+ testdata/issue17788.go
diff --git a/src/go/doc/testdata/issue17788.1.golden b/src/go/doc/testdata/issue17788.1.golden
new file mode 100644
index 0000000..42c00da
--- /dev/null
+++ b/src/go/doc/testdata/issue17788.1.golden
@@ -0,0 +1,8 @@
+//
+PACKAGE issue17788
+
+IMPORTPATH
+ testdata/issue17788
+
+FILENAMES
+ testdata/issue17788.go
diff --git a/src/go/doc/testdata/issue17788.2.golden b/src/go/doc/testdata/issue17788.2.golden
new file mode 100644
index 0000000..42c00da
--- /dev/null
+++ b/src/go/doc/testdata/issue17788.2.golden
@@ -0,0 +1,8 @@
+//
+PACKAGE issue17788
+
+IMPORTPATH
+ testdata/issue17788
+
+FILENAMES
+ testdata/issue17788.go
diff --git a/src/go/doc/testdata/issue17788.go b/src/go/doc/testdata/issue17788.go
new file mode 100644
index 0000000..883ad5f
--- /dev/null
+++ b/src/go/doc/testdata/issue17788.go
@@ -0,0 +1,8 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package issue17788
+
+func ( /* receiver type */ ) f0() {
+}
diff --git a/src/go/doc/testdata/predeclared.0.golden b/src/go/doc/testdata/predeclared.0.golden
new file mode 100644
index 0000000..9f37b06
--- /dev/null
+++ b/src/go/doc/testdata/predeclared.0.golden
@@ -0,0 +1,8 @@
+// Package predeclared is a go/doc test for handling of exported ...
+PACKAGE predeclared
+
+IMPORTPATH
+ testdata/predeclared
+
+FILENAMES
+ testdata/predeclared.go
diff --git a/src/go/doc/testdata/predeclared.1.golden b/src/go/doc/testdata/predeclared.1.golden
new file mode 100644
index 0000000..2ff8ee6
--- /dev/null
+++ b/src/go/doc/testdata/predeclared.1.golden
@@ -0,0 +1,22 @@
+// Package predeclared is a go/doc test for handling of exported ...
+PACKAGE predeclared
+
+IMPORTPATH
+ testdata/predeclared
+
+FILENAMES
+ testdata/predeclared.go
+
+TYPES
+ //
+ type bool int
+
+ // Must not be visible.
+ func (b bool) String() string
+
+ //
+ type error struct{}
+
+ // Must not be visible.
+ func (e error) Error() string
+
diff --git a/src/go/doc/testdata/predeclared.2.golden b/src/go/doc/testdata/predeclared.2.golden
new file mode 100644
index 0000000..9f37b06
--- /dev/null
+++ b/src/go/doc/testdata/predeclared.2.golden
@@ -0,0 +1,8 @@
+// Package predeclared is a go/doc test for handling of exported ...
+PACKAGE predeclared
+
+IMPORTPATH
+ testdata/predeclared
+
+FILENAMES
+ testdata/predeclared.go
diff --git a/src/go/doc/testdata/predeclared.go b/src/go/doc/testdata/predeclared.go
new file mode 100644
index 0000000..c6dd806
--- /dev/null
+++ b/src/go/doc/testdata/predeclared.go
@@ -0,0 +1,22 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package predeclared is a go/doc test for handling of
+// exported methods on locally-defined predeclared types.
+// See issue 9860.
+package predeclared
+
+type error struct{}
+
+// Must not be visible.
+func (e error) Error() string {
+ return ""
+}
+
+type bool int
+
+// Must not be visible.
+func (b bool) String() string {
+ return ""
+}
diff --git a/src/go/format/format_test.go b/src/go/format/format_test.go
index b5817a5..72b8d5a 100644
--- a/src/go/format/format_test.go
+++ b/src/go/format/format_test.go
@@ -6,9 +6,11 @@ package format
import (
"bytes"
+ "fmt"
"go/parser"
"go/token"
"io/ioutil"
+ "log"
"strings"
"testing"
)
@@ -143,3 +145,28 @@ func TestPartial(t *testing.T) {
}
}
}
+
+func ExampleNode() {
+ const expr = "(6+2*3)/4"
+
+ // parser.ParseExpr parses the argument and returns the
+ // corresponding ast.Node.
+ node, err := parser.ParseExpr(expr)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ // Create a FileSet for node. Since the node does not come
+ // from a real source file, fset will be empty.
+ fset := token.NewFileSet()
+
+ var buf bytes.Buffer
+ err = Node(&buf, fset, node)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ fmt.Println(buf.String())
+
+ // Output: (6 + 2*3) / 4
+}
diff --git a/src/go/internal/gccgoimporter/importer.go b/src/go/internal/gccgoimporter/importer.go
index 19b9c73..a22d8fe 100644
--- a/src/go/internal/gccgoimporter/importer.go
+++ b/src/go/internal/gccgoimporter/importer.go
@@ -63,6 +63,7 @@ func findExportFile(searchpaths []string, pkgpath string) (string, error) {
const (
gccgov1Magic = "v1;\n"
+ gccgov2Magic = "v2;\n"
goimporterMagic = "\n$$ "
archiveMagic = "!<ar"
)
@@ -91,7 +92,7 @@ func openExportFile(fpath string) (reader io.ReadSeeker, closer io.Closer, err e
var elfreader io.ReaderAt
switch string(magic[:]) {
- case gccgov1Magic, goimporterMagic:
+ case gccgov1Magic, gccgov2Magic, goimporterMagic:
// Raw export data.
reader = f
return
@@ -168,7 +169,7 @@ func GetImporter(searchpaths []string, initmap map[*types.Package]InitData) Impo
}
switch string(magic[:]) {
- case gccgov1Magic:
+ case gccgov1Magic, gccgov2Magic:
var p parser
p.init(fpath, reader, imports)
pkg = p.parsePackage()
diff --git a/src/go/internal/gccgoimporter/importer_test.go b/src/go/internal/gccgoimporter/importer_test.go
index c10fa48..58abbba 100644
--- a/src/go/internal/gccgoimporter/importer_test.go
+++ b/src/go/internal/gccgoimporter/importer_test.go
@@ -95,6 +95,7 @@ var importerTests = [...]importerTest{
{pkgpath: "complexnums", name: "NP", want: "const NP untyped complex", wantval: "(-1 + 1i)"},
{pkgpath: "complexnums", name: "PN", want: "const PN untyped complex", wantval: "(1 + -1i)"},
{pkgpath: "complexnums", name: "PP", want: "const PP untyped complex", wantval: "(1 + 1i)"},
+ {pkgpath: "conversions", name: "Bits", want: "const Bits Units", wantval: `"bits"`},
// TODO: enable this entry once bug has been tracked down
//{pkgpath: "imports", wantinits: []string{"imports..import", "fmt..import", "math..import"}},
}
diff --git a/src/go/internal/gccgoimporter/parser.go b/src/go/internal/gccgoimporter/parser.go
index c06cce4..7312cb4 100644
--- a/src/go/internal/gccgoimporter/parser.go
+++ b/src/go/internal/gccgoimporter/parser.go
@@ -19,6 +19,7 @@ import (
type parser struct {
scanner scanner.Scanner
+ version string // format version
tok rune // current token
lit string // literal string; only valid for Ident, Int, String tokens
pkgpath string // package path of imported package
@@ -245,9 +246,20 @@ func (p *parser) parseVar(pkg *types.Package) *types.Var {
return types.NewVar(token.NoPos, pkg, name, p.parseType(pkg))
}
-// ConstValue = string | "false" | "true" | ["-"] (int ["'"] | FloatOrComplex) .
+// Conversion = "convert" "(" Type "," ConstValue ")" .
+func (p *parser) parseConversion(pkg *types.Package) (val constant.Value, typ types.Type) {
+ p.expectKeyword("convert")
+ p.expect('(')
+ typ = p.parseType(pkg)
+ p.expect(',')
+ val, _ = p.parseConstValue(pkg)
+ p.expect(')')
+ return
+}
+
+// ConstValue = string | "false" | "true" | ["-"] (int ["'"] | FloatOrComplex) | Conversion .
// FloatOrComplex = float ["i" | ("+"|"-") float "i"] .
-func (p *parser) parseConstValue() (val constant.Value, typ types.Type) {
+func (p *parser) parseConstValue(pkg *types.Package) (val constant.Value, typ types.Type) {
switch p.tok {
case scanner.String:
str := p.parseString()
@@ -262,6 +274,9 @@ func (p *parser) parseConstValue() (val constant.Value, typ types.Type) {
case "true":
b = true
+ case "convert":
+ return p.parseConversion(pkg)
+
default:
p.errorf("expected const value, got %s (%q)", scanner.TokenString(p.tok), p.lit)
}
@@ -348,7 +363,7 @@ func (p *parser) parseConst(pkg *types.Package) *types.Const {
typ = p.parseType(pkg)
}
p.expect('=')
- val, vtyp := p.parseConstValue()
+ val, vtyp := p.parseConstValue(pkg)
if typ == nil {
typ = vtyp
}
@@ -723,7 +738,7 @@ func (p *parser) maybeCreatePackage() {
}
}
-// InitDataDirective = "v1" ";" |
+// InitDataDirective = ( "v1" | "v2" ) ";" |
// "priority" int ";" |
// "init" { PackageInit } ";" |
// "checksum" unquotedString ";" .
@@ -734,7 +749,8 @@ func (p *parser) parseInitDataDirective() {
}
switch p.lit {
- case "v1":
+ case "v1", "v2":
+ p.version = p.lit
p.next()
p.expect(';')
@@ -766,8 +782,9 @@ func (p *parser) parseInitDataDirective() {
}
// Directive = InitDataDirective |
-// "package" unquotedString ";" |
+// "package" unquotedString [ unquotedString ] [ unquotedString ] ";" |
// "pkgpath" unquotedString ";" |
+// "prefix" unquotedString ";" |
// "import" unquotedString unquotedString string ";" |
// "func" Func ";" |
// "type" Type ";" |
@@ -780,13 +797,17 @@ func (p *parser) parseDirective() {
}
switch p.lit {
- case "v1", "priority", "init", "checksum":
+ case "v1", "v2", "priority", "init", "checksum":
p.parseInitDataDirective()
case "package":
p.next()
p.pkgname = p.parseUnquotedString()
p.maybeCreatePackage()
+ if p.version == "v2" && p.tok != ';' {
+ p.parseUnquotedString()
+ p.parseUnquotedString()
+ }
p.expect(';')
case "pkgpath":
@@ -795,6 +816,11 @@ func (p *parser) parseDirective() {
p.maybeCreatePackage()
p.expect(';')
+ case "prefix":
+ p.next()
+ p.pkgpath = p.parseUnquotedString()
+ p.expect(';')
+
case "import":
p.next()
pkgname := p.parseUnquotedString()
diff --git a/src/go/internal/gccgoimporter/testdata/conversions.go b/src/go/internal/gccgoimporter/testdata/conversions.go
new file mode 100644
index 0000000..653927a
--- /dev/null
+++ b/src/go/internal/gccgoimporter/testdata/conversions.go
@@ -0,0 +1,5 @@
+package conversions
+
+type Units string
+
+const Bits = Units("bits")
diff --git a/src/go/internal/gccgoimporter/testdata/conversions.gox b/src/go/internal/gccgoimporter/testdata/conversions.gox
new file mode 100644
index 0000000..7de6cda
--- /dev/null
+++ b/src/go/internal/gccgoimporter/testdata/conversions.gox
@@ -0,0 +1,6 @@
+v2;
+package conversions;
+prefix go;
+package conversions go.conversions go.conversions;
+const Bits <type 1 "Units" <type -16>> = convert(<type 1>, "bits");
+type <type 1>;
diff --git a/src/go/internal/gcimporter/bimport.go b/src/go/internal/gcimporter/bimport.go
index 75c2d91..a8f3490 100644
--- a/src/go/internal/gcimporter/bimport.go
+++ b/src/go/internal/gcimporter/bimport.go
@@ -11,7 +11,9 @@ import (
"go/token"
"go/types"
"sort"
+ "strconv"
"strings"
+ "sync"
"unicode"
"unicode/utf8"
)
@@ -21,7 +23,7 @@ type importer struct {
data []byte
path string
buf []byte // for reading strings
- version string
+ version int // export format version
// object lists
strList []string // in order of appearance
@@ -33,6 +35,8 @@ type importer struct {
posInfoFormat bool
prevFile string
prevLine int
+ fset *token.FileSet
+ files map[string]*token.File
// debugging support
debugFormat bool
@@ -41,37 +45,74 @@ type importer struct {
// BImportData imports a package from the serialized package data
// and returns the number of bytes consumed and a reference to the package.
-// If data is obviously malformed, an error is returned but in
-// general it is not recommended to call BImportData on untrusted data.
-func BImportData(imports map[string]*types.Package, data []byte, path string) (int, *types.Package, error) {
+// 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) {
+ // 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).
+ 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),
+ }
+
+ // read version info
+ var versionstr string
+ if b := p.rawByte(); b == 'c' || b == 'd' {
+ // Go1.7 encoding; first byte encodes low-level
+ // encoding format (compact vs debug).
+ // For backward-compatibility only (avoid problems with
+ // old installed packages). Newly compiled packages use
+ // the extensible format string.
+ // TODO(gri) Remove this support eventually; after Go1.8.
+ if b == 'd' {
+ p.debugFormat = true
+ }
+ p.trackAllTypes = p.rawByte() == 'a'
+ p.posInfoFormat = p.int() != 0
+ versionstr = p.string()
+ if versionstr == "v1" {
+ p.version = 0
+ }
+ } else {
+ // Go1.8 extensible encoding
+ // read version string and extract version number (ignore anything after the version number)
+ versionstr = p.rawStringln(b)
+ if s := strings.SplitN(versionstr, " ", 3); len(s) >= 2 && s[0] == "version" {
+ if v, err := strconv.Atoi(s[1]); err == nil && v > 0 {
+ p.version = v
+ }
+ }
}
- // read low-level encoding format
- switch format := p.rawByte(); format {
- case 'c':
- // compact format - nothing to do
- case 'd':
- p.debugFormat = true
+ // read version specific flags - extend as necessary
+ switch p.version {
+ // case 4:
+ // ...
+ // fallthrough
+ case 3, 2, 1:
+ p.debugFormat = p.rawStringln(p.rawByte()) == "debug"
+ p.trackAllTypes = p.int() != 0
+ p.posInfoFormat = p.int() != 0
+ case 0:
+ // Go1.7 encoding format - nothing to do here
default:
- return p.read, nil, fmt.Errorf("invalid encoding format in export data: got %q; want 'c' or 'd'", format)
+ errorf("unknown export format version %d (%q)", p.version, versionstr)
}
- p.trackAllTypes = p.rawByte() == 'a'
-
- p.posInfoFormat = p.int() != 0
-
// --- generic export data ---
- p.version = p.string()
- if p.version != "v0" && p.version != "v1" {
- return p.read, nil, fmt.Errorf("unknown export data version: %s", p.version)
- }
-
// populate typList with predeclared "known" types
p.typList = append(p.typList, predeclared...)
@@ -91,7 +132,7 @@ func BImportData(imports map[string]*types.Package, data []byte, path string) (i
// self-verification
if count := p.int(); count != objcount {
- panic(fmt.Sprintf("got %d objects; want %d", objcount, count))
+ errorf("got %d objects; want %d", objcount, count)
}
// ignore compiler-specific import data
@@ -119,6 +160,10 @@ func BImportData(imports map[string]*types.Package, data []byte, path string) (i
return p.read, pkg, nil
}
+func errorf(format string, args ...interface{}) {
+ panic(fmt.Sprintf(format, args...))
+}
+
func (p *importer) pkg() *types.Package {
// if the package was seen before, i is its index (>= 0)
i := p.tagOrIndex()
@@ -128,7 +173,7 @@ func (p *importer) pkg() *types.Package {
// otherwise, i is the package tag (< 0)
if i != packageTag {
- panic(fmt.Sprintf("unexpected package tag %d", i))
+ errorf("unexpected package tag %d", i)
}
// read package data
@@ -137,13 +182,13 @@ func (p *importer) pkg() *types.Package {
// we should never see an empty package name
if name == "" {
- panic("empty package name in import")
+ errorf("empty package name in import")
}
// an empty path denotes the package we are currently importing;
// it must be the first package we see
if (path == "") != (len(p.pkgList) == 0) {
- panic(fmt.Sprintf("package path %q for pkg index %d", path, len(p.pkgList)))
+ errorf("package path %q for pkg index %d", path, len(p.pkgList))
}
// if the package was imported before, use that one; otherwise create a new one
@@ -155,61 +200,104 @@ func (p *importer) pkg() *types.Package {
pkg = types.NewPackage(path, name)
p.imports[path] = pkg
} else if pkg.Name() != name {
- panic(fmt.Sprintf("conflicting names %s and %s for package %q", pkg.Name(), name, path))
+ errorf("conflicting names %s and %s for package %q", pkg.Name(), name, path)
}
p.pkgList = append(p.pkgList, pkg)
return pkg
}
+// 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:
+ return constTag
+ case *types.TypeName:
+ return typeTag
+ case *types.Var:
+ 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")
+ }
+}
+
+func sameObj(a, b types.Object) bool {
+ // Because unnamed types are not canonicalized, we cannot simply compare types for
+ // (pointer) identity.
+ // Ideally we'd check equality of constant values as well, but this is good enough.
+ return objTag(a) == objTag(b) && types.Identical(a.Type(), b.Type())
+}
+
func (p *importer) declare(obj types.Object) {
pkg := obj.Pkg()
if alt := pkg.Scope().Insert(obj); alt != nil {
- // This could only trigger if we import a (non-type) object a second time.
- // This should never happen because 1) we only import a package once; and
- // b) we ignore compiler-specific export data which may contain functions
- // whose inlined function bodies refer to other functions that were already
- // imported.
- // (See also the comment in cmd/compile/internal/gc/bimport.go importer.obj,
- // switch case importing functions).
- panic(fmt.Sprintf("inconsistent import:\n\t%v\npreviously imported as:\n\t%v\n", alt, obj))
+ // 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
+ // 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
+ // 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.
+ if !sameObj(obj, alt) {
+ errorf("inconsistent import:\n\t%v\npreviously imported as:\n\t%v\n", obj, alt)
+ }
}
}
func (p *importer) obj(tag int) {
switch tag {
case constTag:
- p.pos()
+ pos := p.pos()
pkg, name := p.qualifiedName()
typ := p.typ(nil)
val := p.value()
- p.declare(types.NewConst(token.NoPos, pkg, name, typ, val))
+ p.declare(types.NewConst(pos, pkg, name, typ, val))
case typeTag:
- _ = p.typ(nil)
+ p.typ(nil)
case varTag:
- p.pos()
+ pos := p.pos()
pkg, name := p.qualifiedName()
typ := p.typ(nil)
- p.declare(types.NewVar(token.NoPos, pkg, name, typ))
+ p.declare(types.NewVar(pos, pkg, name, typ))
case funcTag:
- p.pos()
+ pos := p.pos()
pkg, name := p.qualifiedName()
params, isddd := p.paramList()
result, _ := p.paramList()
sig := types.NewSignature(nil, params, result, isddd)
- p.declare(types.NewFunc(token.NoPos, pkg, name, sig))
+ 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:
- panic(fmt.Sprintf("unexpected object tag %d", tag))
+ errorf("unexpected object tag %d", tag)
}
}
-func (p *importer) pos() {
+func (p *importer) pos() token.Pos {
if !p.posInfoFormat {
- return
+ return token.NoPos
}
file := p.prevFile
@@ -225,12 +313,45 @@ func (p *importer) pos() {
}
p.prevLine = line
- // TODO(gri) register new position
+ // Synthesize a token.Pos
+
+ // Since we don't know the set of needed file positions, we
+ // reserve maxlines positions per file.
+ const maxlines = 64 * 1024
+ f := p.files[file]
+ if f == nil {
+ f = p.fset.AddFile(file, -1, maxlines)
+ p.files[file] = f
+ // Allocate the fake linebreak indices on first use.
+ // TODO(adonovan): opt: save ~512KB using a more complex scheme?
+ fakeLinesOnce.Do(func() {
+ fakeLines = make([]int, maxlines)
+ for i := range fakeLines {
+ fakeLines[i] = i
+ }
+ })
+ f.SetLines(fakeLines)
+ }
+
+ if line > maxlines {
+ line = 1
+ }
+
+ // Treat the file as if it contained only newlines
+ // and column=1: use the line number as the offset.
+ return f.Pos(line - 1)
}
+var (
+ fakeLines []int
+ fakeLinesOnce sync.Once
+)
+
func (p *importer) qualifiedName() (pkg *types.Package, name string) {
name = p.string()
- pkg = p.pkg()
+ if name != "" {
+ pkg = p.pkg()
+ }
return
}
@@ -263,19 +384,19 @@ func (p *importer) typ(parent *types.Package) types.Type {
switch i {
case namedTag:
// read type object
- p.pos()
+ pos := p.pos()
parent, name := p.qualifiedName()
scope := parent.Scope()
obj := scope.Lookup(name)
// if the object doesn't exist yet, create and insert it
if obj == nil {
- obj = types.NewTypeName(token.NoPos, parent, name, nil)
+ obj = types.NewTypeName(pos, parent, name, nil)
scope.Insert(obj)
}
if _, ok := obj.(*types.TypeName); !ok {
- panic(fmt.Sprintf("pkg = %s, name = %s => %s", parent, name, obj))
+ errorf("pkg = %s, name = %s => %s", parent, name, obj)
}
// associate new named type with obj if it doesn't exist yet
@@ -296,7 +417,7 @@ func (p *importer) typ(parent *types.Package) types.Type {
// read associated methods
for i := p.int(); i > 0; i-- {
// TODO(gri) replace this with something closer to fieldName
- p.pos()
+ pos := p.pos()
name := p.string()
if !exported(name) {
p.pkg()
@@ -305,13 +426,10 @@ func (p *importer) typ(parent *types.Package) types.Type {
recv, _ := p.paramList() // TODO(gri) do we need a full param list for the receiver?
params, isddd := p.paramList()
result, _ := p.paramList()
-
- if p.version == "v1" {
- p.int() // nointerface flag - discarded
- }
+ p.int() // go:nointerface pragma - discarded
sig := types.NewSignature(recv.At(0), params, result, isddd)
- t0.AddMethod(types.NewFunc(token.NoPos, parent, name, sig))
+ t0.AddMethod(types.NewFunc(pos, parent, name, sig))
}
return t
@@ -385,7 +503,7 @@ func (p *importer) typ(parent *types.Package) types.Type {
// no embedded interfaces with gc compiler
if p.int() != 0 {
- panic("unexpected embedded interface")
+ errorf("unexpected embedded interface")
}
t := types.NewInterface(p.methodList(parent), nil)
@@ -421,14 +539,15 @@ func (p *importer) typ(parent *types.Package) types.Type {
case 3 /* Cboth */ :
dir = types.SendRecv
default:
- panic(fmt.Sprintf("unexpected channel dir %d", d))
+ errorf("unexpected channel dir %d", d)
}
val := p.typ(parent)
*t = *types.NewChan(dir, val)
return t
default:
- panic(fmt.Sprintf("unexpected type tag %d", i))
+ errorf("unexpected type tag %d", i) // panics
+ panic("unreachable")
}
}
@@ -445,7 +564,7 @@ func (p *importer) fieldList(parent *types.Package) (fields []*types.Var, tags [
}
func (p *importer) field(parent *types.Package) *types.Var {
- p.pos()
+ pos := p.pos()
pkg, name := p.fieldName(parent)
typ := p.typ(parent)
@@ -459,12 +578,12 @@ func (p *importer) field(parent *types.Package) *types.Var {
case *types.Named:
name = typ.Obj().Name()
default:
- panic("anonymous field expected")
+ errorf("anonymous field expected")
}
anonymous = true
}
- return types.NewField(token.NoPos, pkg, name, typ, anonymous)
+ return types.NewField(pos, pkg, name, typ, anonymous)
}
func (p *importer) methodList(parent *types.Package) (methods []*types.Func) {
@@ -478,28 +597,28 @@ func (p *importer) methodList(parent *types.Package) (methods []*types.Func) {
}
func (p *importer) method(parent *types.Package) *types.Func {
- p.pos()
+ pos := p.pos()
pkg, name := p.fieldName(parent)
params, isddd := p.paramList()
result, _ := p.paramList()
sig := types.NewSignature(nil, params, result, isddd)
- return types.NewFunc(token.NoPos, pkg, name, sig)
+ return types.NewFunc(pos, pkg, name, sig)
}
func (p *importer) fieldName(parent *types.Package) (*types.Package, string) {
+ name := p.string()
pkg := parent
if pkg == nil {
// use the imported package instead
pkg = p.pkgList[0]
}
- name := p.string()
- if name == "" {
- return pkg, "" // anonymous
+ if p.version == 0 && name == "_" {
+ // version 0 didn't export a package for _ fields
+ return pkg, name
}
- if name == "?" || name != "_" && !exported(name) {
- // explicitly qualified field
+ if name != "" && !exported(name) {
if name == "?" {
- name = "" // anonymous
+ name = ""
}
pkg = p.pkg()
}
@@ -538,7 +657,7 @@ func (p *importer) param(named bool) (*types.Var, bool) {
if named {
name = p.string()
if name == "" {
- panic("expected named parameter")
+ errorf("expected named parameter")
}
if name != "_" {
pkg = p.pkg()
@@ -575,8 +694,11 @@ func (p *importer) value() constant.Value {
return constant.BinaryOp(re, token.ADD, constant.MakeImag(im))
case stringTag:
return constant.MakeString(p.string())
+ case unknownTag:
+ return constant.MakeUnknown()
default:
- panic(fmt.Sprintf("unexpected value tag %d", tag))
+ errorf("unexpected value tag %d", tag) // panics
+ panic("unreachable")
}
}
@@ -639,7 +761,7 @@ func (p *importer) tagOrIndex() int {
func (p *importer) int() int {
x := p.int64()
if int64(int(x)) != x {
- panic("exported integer too large")
+ errorf("exported integer too large")
}
return int(x)
}
@@ -678,24 +800,34 @@ func (p *importer) string() string {
func (p *importer) marker(want byte) {
if got := p.rawByte(); got != want {
- panic(fmt.Sprintf("incorrect marker: got %c; want %c (pos = %d)", got, want, p.read))
+ errorf("incorrect marker: got %c; want %c (pos = %d)", got, want, p.read)
}
pos := p.read
if n := int(p.rawInt64()); n != pos {
- panic(fmt.Sprintf("incorrect position: got %d; want %d", n, pos))
+ errorf("incorrect position: got %d; want %d", n, pos)
}
}
-// rawInt64 should only be used by low-level decoders
+// rawInt64 should only be used by low-level decoders.
func (p *importer) rawInt64() int64 {
i, err := binary.ReadVarint(p)
if err != nil {
- panic(fmt.Sprintf("read error: %v", err))
+ errorf("read error: %v", err)
}
return i
}
+// rawStringln should only be used to read the initial version string.
+func (p *importer) rawStringln(b byte) string {
+ p.buf = p.buf[:0]
+ for b != '\n' {
+ p.buf = append(p.buf, b)
+ b = p.rawByte()
+ }
+ return string(p.buf)
+}
+
// needed for binary.ReadVarint in rawInt64
func (p *importer) ReadByte() (byte, error) {
return p.rawByte(), nil
@@ -716,7 +848,7 @@ func (p *importer) rawByte() byte {
case '|':
// nothing to do
default:
- panic("unexpected escape sequence in export data")
+ errorf("unexpected escape sequence in export data")
}
}
p.data = p.data[r:]
@@ -758,7 +890,11 @@ const (
fractionTag // not used by gc
complexTag
stringTag
+ nilTag // only used by gc (appears in exported inlined function bodies)
unknownTag // not used by gc (only appears in packages with errors)
+
+ // Aliases
+ aliasTag
)
var predeclared = []types.Type{
diff --git a/src/go/internal/gcimporter/exportdata.go b/src/go/internal/gcimporter/exportdata.go
index 4c0d2fe..c12e459 100644
--- a/src/go/internal/gcimporter/exportdata.go
+++ b/src/go/internal/gcimporter/exportdata.go
@@ -8,7 +8,6 @@ package gcimporter
import (
"bufio"
- "errors"
"fmt"
"io"
"strconv"
@@ -29,7 +28,7 @@ func readGopackHeader(r *bufio.Reader) (name string, size int, err error) {
s := strings.TrimSpace(string(hdr[16+12+6+6+8:][:10]))
size, err = strconv.Atoi(s)
if err != nil || hdr[len(hdr)-2] != '`' || hdr[len(hdr)-1] != '\n' {
- err = errors.New("invalid archive header")
+ err = fmt.Errorf("invalid archive header")
return
}
name = strings.TrimSpace(string(hdr[:16]))
@@ -46,6 +45,7 @@ func FindExportData(r *bufio.Reader) (hdr string, err error) {
// Read first line to make sure this is an object file.
line, err := r.ReadSlice('\n')
if err != nil {
+ err = fmt.Errorf("can't find export data (%v)", err)
return
}
@@ -58,13 +58,14 @@ func FindExportData(r *bufio.Reader) (hdr string, err error) {
// First entry should be __.PKGDEF.
if name != "__.PKGDEF" {
- err = errors.New("go archive is missing __.PKGDEF")
+ err = fmt.Errorf("go archive is missing __.PKGDEF")
return
}
// Read first line of __.PKGDEF data, so that line
// is once again the first line of the input.
if line, err = r.ReadSlice('\n'); err != nil {
+ err = fmt.Errorf("can't find export data (%v)", err)
return
}
}
@@ -72,7 +73,7 @@ func FindExportData(r *bufio.Reader) (hdr string, err error) {
// Now at __.PKGDEF in archive or still at beginning of file.
// Either way, line should begin with "go object ".
if !strings.HasPrefix(string(line), "go object ") {
- err = errors.New("not a go object file")
+ err = fmt.Errorf("not a Go object file")
return
}
@@ -80,6 +81,7 @@ func FindExportData(r *bufio.Reader) (hdr string, err error) {
// Begins after first line starting with $$.
for line[0] != '$' {
if line, err = r.ReadSlice('\n'); err != nil {
+ err = fmt.Errorf("can't find export data (%v)", err)
return
}
}
diff --git a/src/go/internal/gcimporter/gcimporter.go b/src/go/internal/gcimporter/gcimporter.go
index 2c6e676..f99f0f8 100644
--- a/src/go/internal/gcimporter/gcimporter.go
+++ b/src/go/internal/gcimporter/gcimporter.go
@@ -7,21 +7,14 @@ package gcimporter // import "go/internal/gcimporter"
import (
"bufio"
- "errors"
"fmt"
"go/build"
"go/token"
- "io"
+ "go/types"
"io/ioutil"
"os"
"path/filepath"
- "sort"
- "strconv"
"strings"
- "text/scanner"
-
- exact "go/constant"
- "go/types"
)
// debugging/development support
@@ -86,38 +79,6 @@ func FindPkg(path, srcDir string) (filename, id string) {
return
}
-// ImportData imports a package by reading the gc-generated export data,
-// adds the corresponding package object to the packages map indexed by id,
-// and returns the object.
-//
-// The packages map must contains all packages already imported. The data
-// reader position must be the beginning of the export data section. The
-// filename is only used in error messages.
-//
-// If packages[id] contains the completely imported package, that package
-// can be used directly, and there is no need to call this function (but
-// there is also no harm but for extra time used).
-//
-func ImportData(packages map[string]*types.Package, filename, id string, data io.Reader) (pkg *types.Package, err error) {
- // support for parser error handling
- defer func() {
- switch r := recover().(type) {
- case nil:
- // nothing to do
- case importError:
- err = r
- default:
- panic(r) // internal error
- }
- }()
-
- var p parser
- p.init(filename, id, data, packages)
- pkg = p.parseExport()
-
- return
-}
-
// Import imports a gc-generated package given its import path and srcDir, adds
// the corresponding package object to the packages map, and returns the object.
// The packages map must contain all packages already imported.
@@ -146,7 +107,7 @@ func Import(packages map[string]*types.Package, path, srcDir string) (pkg *types
f.Close()
if err != nil {
// add file name to error
- err = fmt.Errorf("reading export data: %s: %v", filename, err)
+ err = fmt.Errorf("%s: %v", filename, err)
}
}()
@@ -158,12 +119,15 @@ func Import(packages map[string]*types.Package, path, srcDir string) (pkg *types
switch hdr {
case "$$\n":
- return ImportData(packages, filename, id, buf)
+ err = fmt.Errorf("import %q: old export format no longer supported (recompile library)", path)
case "$$B\n":
var data []byte
data, err = ioutil.ReadAll(buf)
if err == nil {
- _, pkg, err = BImportData(packages, data, id)
+ // TODO(gri): allow clients of go/importer to provide a FileSet.
+ // Or, define a new standard go/types/gcexportdata package.
+ fset := token.NewFileSet()
+ _, pkg, err = BImportData(fset, packages, data, id)
return
}
default:
@@ -173,312 +137,6 @@ func Import(packages map[string]*types.Package, path, srcDir string) (pkg *types
return
}
-// ----------------------------------------------------------------------------
-// Parser
-
-// TODO(gri) Imported objects don't have position information.
-// Ideally use the debug table line info; alternatively
-// create some fake position (or the position of the
-// import). That way error messages referring to imported
-// objects can print meaningful information.
-
-// parser parses the exports inside a gc compiler-produced
-// object/archive file and populates its scope with the results.
-type parser struct {
- scanner scanner.Scanner
- tok rune // current token
- lit string // literal string; only valid for Ident, Int, String tokens
- id string // package id of imported package
- sharedPkgs map[string]*types.Package // package id -> package object (across importer)
- localPkgs map[string]*types.Package // package id -> package object (just this package)
-}
-
-func (p *parser) init(filename, id string, src io.Reader, packages map[string]*types.Package) {
- p.scanner.Init(src)
- p.scanner.Error = func(_ *scanner.Scanner, msg string) { p.error(msg) }
- p.scanner.Mode = scanner.ScanIdents | scanner.ScanInts | scanner.ScanChars | scanner.ScanStrings | scanner.ScanComments | scanner.SkipComments
- p.scanner.Whitespace = 1<<'\t' | 1<<' '
- p.scanner.Filename = filename // for good error messages
- p.next()
- p.id = id
- p.sharedPkgs = packages
- if debug {
- // check consistency of packages map
- for _, pkg := range packages {
- if pkg.Name() == "" {
- fmt.Printf("no package name for %s\n", pkg.Path())
- }
- }
- }
-}
-
-func (p *parser) next() {
- p.tok = p.scanner.Scan()
- switch p.tok {
- case scanner.Ident, scanner.Int, scanner.Char, scanner.String, '·':
- p.lit = p.scanner.TokenText()
- default:
- p.lit = ""
- }
- if debug {
- fmt.Printf("%s: %q -> %q\n", scanner.TokenString(p.tok), p.scanner.TokenText(), p.lit)
- }
-}
-
-func declTypeName(pkg *types.Package, name string) *types.TypeName {
- scope := pkg.Scope()
- if obj := scope.Lookup(name); obj != nil {
- return obj.(*types.TypeName)
- }
- obj := types.NewTypeName(token.NoPos, pkg, name, nil)
- // a named type may be referred to before the underlying type
- // is known - set it up
- types.NewNamed(obj, nil, nil)
- scope.Insert(obj)
- return obj
-}
-
-// ----------------------------------------------------------------------------
-// Error handling
-
-// Internal errors are boxed as importErrors.
-type importError struct {
- pos scanner.Position
- err error
-}
-
-func (e importError) Error() string {
- return fmt.Sprintf("import error %s (byte offset = %d): %s", e.pos, e.pos.Offset, e.err)
-}
-
-func (p *parser) error(err interface{}) {
- if s, ok := err.(string); ok {
- err = errors.New(s)
- }
- // panic with a runtime.Error if err is not an error
- panic(importError{p.scanner.Pos(), err.(error)})
-}
-
-func (p *parser) errorf(format string, args ...interface{}) {
- p.error(fmt.Sprintf(format, args...))
-}
-
-func (p *parser) expect(tok rune) string {
- lit := p.lit
- if p.tok != tok {
- p.errorf("expected %s, got %s (%s)", scanner.TokenString(tok), scanner.TokenString(p.tok), lit)
- }
- p.next()
- return lit
-}
-
-func (p *parser) expectSpecial(tok string) {
- sep := 'x' // not white space
- i := 0
- for i < len(tok) && p.tok == rune(tok[i]) && sep > ' ' {
- sep = p.scanner.Peek() // if sep <= ' ', there is white space before the next token
- p.next()
- i++
- }
- if i < len(tok) {
- p.errorf("expected %q, got %q", tok, tok[0:i])
- }
-}
-
-func (p *parser) expectKeyword(keyword string) {
- lit := p.expect(scanner.Ident)
- if lit != keyword {
- p.errorf("expected keyword %s, got %q", keyword, lit)
- }
-}
-
-// ----------------------------------------------------------------------------
-// Qualified and unqualified names
-
-// PackageId = string_lit .
-//
-func (p *parser) parsePackageId() string {
- id, err := strconv.Unquote(p.expect(scanner.String))
- if err != nil {
- p.error(err)
- }
- // id == "" stands for the imported package id
- // (only known at time of package installation)
- if id == "" {
- id = p.id
- }
- return id
-}
-
-// PackageName = ident .
-//
-func (p *parser) parsePackageName() string {
- return p.expect(scanner.Ident)
-}
-
-// dotIdentifier = ( ident | '·' ) { ident | int | '·' } .
-func (p *parser) parseDotIdent() string {
- ident := ""
- if p.tok != scanner.Int {
- sep := 'x' // not white space
- for (p.tok == scanner.Ident || p.tok == scanner.Int || p.tok == '·') && sep > ' ' {
- ident += p.lit
- sep = p.scanner.Peek() // if sep <= ' ', there is white space before the next token
- p.next()
- }
- }
- if ident == "" {
- p.expect(scanner.Ident) // use expect() for error handling
- }
- return ident
-}
-
-// QualifiedName = "@" PackageId "." ( "?" | dotIdentifier ) .
-//
-func (p *parser) parseQualifiedName() (id, name string) {
- p.expect('@')
- id = p.parsePackageId()
- p.expect('.')
- // Per rev f280b8a485fd (10/2/2013), qualified names may be used for anonymous fields.
- if p.tok == '?' {
- p.next()
- } else {
- name = p.parseDotIdent()
- }
- return
-}
-
-// getPkg returns the package for a given id. If the package is
-// not found, create the package and add it to the p.localPkgs
-// and p.sharedPkgs maps. name is the (expected) name of the
-// package. If name == "", the package name is expected to be
-// set later via an import clause in the export data.
-//
-// id identifies a package, usually by a canonical package path like
-// "encoding/json" but possibly by a non-canonical import path like
-// "./json".
-//
-func (p *parser) getPkg(id, name string) *types.Package {
- // package unsafe is not in the packages maps - handle explicitly
- if id == "unsafe" {
- return types.Unsafe
- }
-
- pkg := p.localPkgs[id]
- if pkg == nil {
- // first import of id from this package
- pkg = p.sharedPkgs[id]
- if pkg == nil {
- // first import of id by this importer;
- // add (possibly unnamed) pkg to shared packages
- pkg = types.NewPackage(id, name)
- p.sharedPkgs[id] = pkg
- }
- // add (possibly unnamed) pkg to local packages
- if p.localPkgs == nil {
- p.localPkgs = make(map[string]*types.Package)
- }
- p.localPkgs[id] = pkg
- } else if name != "" {
- // package exists already and we have an expected package name;
- // make sure names match or set package name if necessary
- if pname := pkg.Name(); pname == "" {
- pkg.SetName(name)
- } else if pname != name {
- p.errorf("%s package name mismatch: %s (given) vs %s (expected)", id, pname, name)
- }
- }
- return pkg
-}
-
-// parseExportedName is like parseQualifiedName, but
-// the package id is resolved to an imported *types.Package.
-//
-func (p *parser) parseExportedName() (pkg *types.Package, name string) {
- id, name := p.parseQualifiedName()
- pkg = p.getPkg(id, "")
- return
-}
-
-// ----------------------------------------------------------------------------
-// Types
-
-// BasicType = identifier .
-//
-func (p *parser) parseBasicType() types.Type {
- id := p.expect(scanner.Ident)
- obj := types.Universe.Lookup(id)
- if obj, ok := obj.(*types.TypeName); ok {
- return obj.Type()
- }
- p.errorf("not a basic type: %s", id)
- return nil
-}
-
-// ArrayType = "[" int_lit "]" Type .
-//
-func (p *parser) parseArrayType(parent *types.Package) types.Type {
- // "[" already consumed and lookahead known not to be "]"
- lit := p.expect(scanner.Int)
- p.expect(']')
- elem := p.parseType(parent)
- n, err := strconv.ParseInt(lit, 10, 64)
- if err != nil {
- p.error(err)
- }
- return types.NewArray(elem, n)
-}
-
-// MapType = "map" "[" Type "]" Type .
-//
-func (p *parser) parseMapType(parent *types.Package) types.Type {
- p.expectKeyword("map")
- p.expect('[')
- key := p.parseType(parent)
- p.expect(']')
- elem := p.parseType(parent)
- return types.NewMap(key, elem)
-}
-
-// Name = identifier | "?" | QualifiedName .
-//
-// For unqualified and anonymous names, the returned package is the parent
-// package unless parent == nil, in which case the returned package is the
-// package being imported. (The parent package is not nil if the the name
-// is an unqualified struct field or interface method name belonging to a
-// type declared in another package.)
-//
-// For qualified names, the returned package is nil (and not created if
-// it doesn't exist yet) unless materializePkg is set (which creates an
-// unnamed package with valid package path). In the latter case, a
-// subsequent import clause is expected to provide a name for the package.
-//
-func (p *parser) parseName(parent *types.Package, materializePkg bool) (pkg *types.Package, name string) {
- pkg = parent
- if pkg == nil {
- pkg = p.sharedPkgs[p.id]
- }
- switch p.tok {
- case scanner.Ident:
- name = p.lit
- p.next()
- case '?':
- // anonymous
- p.next()
- case '@':
- // exported name prefixed with package path
- pkg = nil
- var id string
- id, name = p.parseQualifiedName()
- if materializePkg {
- pkg = p.getPkg(id, "")
- }
- default:
- p.error("name expected")
- }
- return
-}
-
func deref(typ types.Type) types.Type {
if p, _ := typ.(*types.Pointer); p != nil {
return p.Elem()
@@ -486,531 +144,6 @@ func deref(typ types.Type) types.Type {
return typ
}
-// Field = Name Type [ string_lit ] .
-//
-func (p *parser) parseField(parent *types.Package) (*types.Var, string) {
- pkg, name := p.parseName(parent, true)
- typ := p.parseType(parent)
- anonymous := false
- if name == "" {
- // anonymous field - typ must be T or *T and T must be a type name
- switch typ := deref(typ).(type) {
- case *types.Basic: // basic types are named types
- pkg = nil // objects defined in Universe scope have no package
- name = typ.Name()
- case *types.Named:
- name = typ.Obj().Name()
- default:
- p.errorf("anonymous field expected")
- }
- anonymous = true
- }
- tag := ""
- if p.tok == scanner.String {
- s := p.expect(scanner.String)
- var err error
- tag, err = strconv.Unquote(s)
- if err != nil {
- p.errorf("invalid struct tag %s: %s", s, err)
- }
- }
- return types.NewField(token.NoPos, pkg, name, typ, anonymous), tag
-}
-
-// StructType = "struct" "{" [ FieldList ] "}" .
-// FieldList = Field { ";" Field } .
-//
-func (p *parser) parseStructType(parent *types.Package) types.Type {
- var fields []*types.Var
- var tags []string
-
- p.expectKeyword("struct")
- p.expect('{')
- for i := 0; p.tok != '}' && p.tok != scanner.EOF; i++ {
- if i > 0 {
- p.expect(';')
- }
- fld, tag := p.parseField(parent)
- if tag != "" && tags == nil {
- tags = make([]string, i)
- }
- if tags != nil {
- tags = append(tags, tag)
- }
- fields = append(fields, fld)
- }
- p.expect('}')
-
- return types.NewStruct(fields, tags)
-}
-
-// Parameter = ( identifier | "?" ) [ "..." ] Type [ string_lit ] .
-//
-func (p *parser) parseParameter() (par *types.Var, isVariadic bool) {
- _, name := p.parseName(nil, false)
- // remove gc-specific parameter numbering
- if i := strings.Index(name, "·"); i >= 0 {
- name = name[:i]
- }
- if p.tok == '.' {
- p.expectSpecial("...")
- isVariadic = true
- }
- typ := p.parseType(nil)
- if isVariadic {
- typ = types.NewSlice(typ)
- }
- // ignore argument tag (e.g. "noescape")
- if p.tok == scanner.String {
- p.next()
- }
- // TODO(gri) should we provide a package?
- par = types.NewVar(token.NoPos, nil, name, typ)
- return
-}
-
-// Parameters = "(" [ ParameterList ] ")" .
-// ParameterList = { Parameter "," } Parameter .
-//
-func (p *parser) parseParameters() (list []*types.Var, isVariadic bool) {
- p.expect('(')
- for p.tok != ')' && p.tok != scanner.EOF {
- if len(list) > 0 {
- p.expect(',')
- }
- par, variadic := p.parseParameter()
- list = append(list, par)
- if variadic {
- if isVariadic {
- p.error("... not on final argument")
- }
- isVariadic = true
- }
- }
- p.expect(')')
-
- return
-}
-
-// Signature = Parameters [ Result ] .
-// Result = Type | Parameters .
-//
-func (p *parser) parseSignature(recv *types.Var) *types.Signature {
- params, isVariadic := p.parseParameters()
-
- // optional result type
- var results []*types.Var
- if p.tok == '(' {
- var variadic bool
- results, variadic = p.parseParameters()
- if variadic {
- p.error("... not permitted on result type")
- }
- }
-
- return types.NewSignature(recv, types.NewTuple(params...), types.NewTuple(results...), isVariadic)
-}
-
-// InterfaceType = "interface" "{" [ MethodList ] "}" .
-// MethodList = Method { ";" Method } .
-// Method = Name Signature .
-//
-// The methods of embedded interfaces are always "inlined"
-// by the compiler and thus embedded interfaces are never
-// visible in the export data.
-//
-func (p *parser) parseInterfaceType(parent *types.Package) types.Type {
- var methods []*types.Func
-
- p.expectKeyword("interface")
- p.expect('{')
- for i := 0; p.tok != '}' && p.tok != scanner.EOF; i++ {
- if i > 0 {
- p.expect(';')
- }
- pkg, name := p.parseName(parent, true)
- sig := p.parseSignature(nil)
- methods = append(methods, types.NewFunc(token.NoPos, pkg, name, sig))
- }
- p.expect('}')
-
- // Complete requires the type's embedded interfaces to be fully defined,
- // but we do not define any
- return types.NewInterface(methods, nil).Complete()
-}
-
-// ChanType = ( "chan" [ "<-" ] | "<-" "chan" ) Type .
-//
-func (p *parser) parseChanType(parent *types.Package) types.Type {
- dir := types.SendRecv
- if p.tok == scanner.Ident {
- p.expectKeyword("chan")
- if p.tok == '<' {
- p.expectSpecial("<-")
- dir = types.SendOnly
- }
- } else {
- p.expectSpecial("<-")
- p.expectKeyword("chan")
- dir = types.RecvOnly
- }
- elem := p.parseType(parent)
- return types.NewChan(dir, elem)
-}
-
-// Type =
-// BasicType | TypeName | ArrayType | SliceType | StructType |
-// PointerType | FuncType | InterfaceType | MapType | ChanType |
-// "(" Type ")" .
-//
-// BasicType = ident .
-// TypeName = ExportedName .
-// SliceType = "[" "]" Type .
-// PointerType = "*" Type .
-// FuncType = "func" Signature .
-//
-func (p *parser) parseType(parent *types.Package) types.Type {
- switch p.tok {
- case scanner.Ident:
- switch p.lit {
- default:
- return p.parseBasicType()
- case "struct":
- return p.parseStructType(parent)
- case "func":
- // FuncType
- p.next()
- return p.parseSignature(nil)
- case "interface":
- return p.parseInterfaceType(parent)
- case "map":
- return p.parseMapType(parent)
- case "chan":
- return p.parseChanType(parent)
- }
- case '@':
- // TypeName
- pkg, name := p.parseExportedName()
- return declTypeName(pkg, name).Type()
- case '[':
- p.next() // look ahead
- if p.tok == ']' {
- // SliceType
- p.next()
- return types.NewSlice(p.parseType(parent))
- }
- return p.parseArrayType(parent)
- case '*':
- // PointerType
- p.next()
- return types.NewPointer(p.parseType(parent))
- case '<':
- return p.parseChanType(parent)
- case '(':
- // "(" Type ")"
- p.next()
- typ := p.parseType(parent)
- p.expect(')')
- return typ
- }
- p.errorf("expected type, got %s (%q)", scanner.TokenString(p.tok), p.lit)
- return nil
-}
-
-// ----------------------------------------------------------------------------
-// Declarations
-
-// ImportDecl = "import" PackageName PackageId .
-//
-func (p *parser) parseImportDecl() {
- p.expectKeyword("import")
- name := p.parsePackageName()
- p.getPkg(p.parsePackageId(), name)
-}
-
-// int_lit = [ "+" | "-" ] { "0" ... "9" } .
-//
-func (p *parser) parseInt() string {
- s := ""
- switch p.tok {
- case '-':
- s = "-"
- p.next()
- case '+':
- p.next()
- }
- return s + p.expect(scanner.Int)
-}
-
-// number = int_lit [ "p" int_lit ] .
-//
-func (p *parser) parseNumber() (typ *types.Basic, val exact.Value) {
- // mantissa
- mant := exact.MakeFromLiteral(p.parseInt(), token.INT, 0)
- if mant == nil {
- panic("invalid mantissa")
- }
-
- if p.lit == "p" {
- // exponent (base 2)
- p.next()
- exp, err := strconv.ParseInt(p.parseInt(), 10, 0)
- if err != nil {
- p.error(err)
- }
- if exp < 0 {
- denom := exact.MakeInt64(1)
- denom = exact.Shift(denom, token.SHL, uint(-exp))
- typ = types.Typ[types.UntypedFloat]
- val = exact.BinaryOp(mant, token.QUO, denom)
- return
- }
- if exp > 0 {
- mant = exact.Shift(mant, token.SHL, uint(exp))
- }
- typ = types.Typ[types.UntypedFloat]
- val = mant
- return
- }
-
- typ = types.Typ[types.UntypedInt]
- val = mant
- return
-}
-
-// ConstDecl = "const" ExportedName [ Type ] "=" Literal .
-// Literal = bool_lit | int_lit | float_lit | complex_lit | rune_lit | string_lit .
-// bool_lit = "true" | "false" .
-// complex_lit = "(" float_lit "+" float_lit "i" ")" .
-// rune_lit = "(" int_lit "+" int_lit ")" .
-// string_lit = `"` { unicode_char } `"` .
-//
-func (p *parser) parseConstDecl() {
- p.expectKeyword("const")
- pkg, name := p.parseExportedName()
-
- var typ0 types.Type
- if p.tok != '=' {
- // constant types are never structured - no need for parent type
- typ0 = p.parseType(nil)
- }
-
- p.expect('=')
- var typ types.Type
- var val exact.Value
- switch p.tok {
- case scanner.Ident:
- // bool_lit
- if p.lit != "true" && p.lit != "false" {
- p.error("expected true or false")
- }
- typ = types.Typ[types.UntypedBool]
- val = exact.MakeBool(p.lit == "true")
- p.next()
-
- case '-', scanner.Int:
- // int_lit
- typ, val = p.parseNumber()
-
- case '(':
- // complex_lit or rune_lit
- p.next()
- if p.tok == scanner.Char {
- p.next()
- p.expect('+')
- typ = types.Typ[types.UntypedRune]
- _, val = p.parseNumber()
- p.expect(')')
- break
- }
- _, re := p.parseNumber()
- p.expect('+')
- _, im := p.parseNumber()
- p.expectKeyword("i")
- p.expect(')')
- typ = types.Typ[types.UntypedComplex]
- val = exact.BinaryOp(re, token.ADD, exact.MakeImag(im))
-
- case scanner.Char:
- // rune_lit
- typ = types.Typ[types.UntypedRune]
- val = exact.MakeFromLiteral(p.lit, token.CHAR, 0)
- p.next()
-
- case scanner.String:
- // string_lit
- typ = types.Typ[types.UntypedString]
- val = exact.MakeFromLiteral(p.lit, token.STRING, 0)
- p.next()
-
- default:
- p.errorf("expected literal got %s", scanner.TokenString(p.tok))
- }
-
- if typ0 == nil {
- typ0 = typ
- }
-
- pkg.Scope().Insert(types.NewConst(token.NoPos, pkg, name, typ0, val))
-}
-
-// TypeDecl = "type" ExportedName Type .
-//
-func (p *parser) parseTypeDecl() {
- p.expectKeyword("type")
- pkg, name := p.parseExportedName()
- obj := declTypeName(pkg, name)
-
- // The type object may have been imported before and thus already
- // have a type associated with it. We still need to parse the type
- // structure, but throw it away if the object already has a type.
- // This ensures that all imports refer to the same type object for
- // a given type declaration.
- typ := p.parseType(pkg)
-
- if name := obj.Type().(*types.Named); name.Underlying() == nil {
- name.SetUnderlying(typ)
- }
-}
-
-// VarDecl = "var" ExportedName Type .
-//
-func (p *parser) parseVarDecl() {
- p.expectKeyword("var")
- pkg, name := p.parseExportedName()
- typ := p.parseType(pkg)
- pkg.Scope().Insert(types.NewVar(token.NoPos, pkg, name, typ))
-}
-
-// Func = Signature [ Body ] .
-// Body = "{" ... "}" .
-//
-func (p *parser) parseFunc(recv *types.Var) *types.Signature {
- sig := p.parseSignature(recv)
- if p.tok == '{' {
- p.next()
- for i := 1; i > 0; p.next() {
- switch p.tok {
- case '{':
- i++
- case '}':
- i--
- }
- }
- }
- return sig
-}
-
-// MethodDecl = "func" Receiver Name Func .
-// Receiver = "(" ( identifier | "?" ) [ "*" ] ExportedName ")" .
-//
-func (p *parser) parseMethodDecl() {
- // "func" already consumed
- p.expect('(')
- recv, _ := p.parseParameter() // receiver
- p.expect(')')
-
- // determine receiver base type object
- base := deref(recv.Type()).(*types.Named)
-
- // parse method name, signature, and possibly inlined body
- _, name := p.parseName(nil, false)
- sig := p.parseFunc(recv)
-
- // methods always belong to the same package as the base type object
- pkg := base.Obj().Pkg()
-
- // add method to type unless type was imported before
- // and method exists already
- // TODO(gri) This leads to a quadratic algorithm - ok for now because method counts are small.
- base.AddMethod(types.NewFunc(token.NoPos, pkg, name, sig))
-}
-
-// FuncDecl = "func" ExportedName Func .
-//
-func (p *parser) parseFuncDecl() {
- // "func" already consumed
- pkg, name := p.parseExportedName()
- typ := p.parseFunc(nil)
- pkg.Scope().Insert(types.NewFunc(token.NoPos, pkg, name, typ))
-}
-
-// Decl = [ ImportDecl | ConstDecl | TypeDecl | VarDecl | FuncDecl | MethodDecl ] "\n" .
-//
-func (p *parser) parseDecl() {
- if p.tok == scanner.Ident {
- switch p.lit {
- case "import":
- p.parseImportDecl()
- case "const":
- p.parseConstDecl()
- case "type":
- p.parseTypeDecl()
- case "var":
- p.parseVarDecl()
- case "func":
- p.next() // look ahead
- if p.tok == '(' {
- p.parseMethodDecl()
- } else {
- p.parseFuncDecl()
- }
- }
- }
- p.expect('\n')
-}
-
-// ----------------------------------------------------------------------------
-// Export
-
-// Export = "PackageClause { Decl } "$$" .
-// PackageClause = "package" PackageName [ "safe" ] "\n" .
-//
-func (p *parser) parseExport() *types.Package {
- p.expectKeyword("package")
- name := p.parsePackageName()
- if p.tok == scanner.Ident && p.lit == "safe" {
- // package was compiled with -u option - ignore
- p.next()
- }
- p.expect('\n')
-
- pkg := p.getPkg(p.id, name)
-
- for p.tok != '$' && p.tok != scanner.EOF {
- p.parseDecl()
- }
-
- if ch := p.scanner.Peek(); p.tok != '$' || ch != '$' {
- // don't call next()/expect() since reading past the
- // export data may cause scanner errors (e.g. NUL chars)
- p.errorf("expected '$$', got %s %c", scanner.TokenString(p.tok), ch)
- }
-
- if n := p.scanner.ErrorCount; n != 0 {
- p.errorf("expected no scanner errors, got %d", n)
- }
-
- // Record all locally referenced packages as imports.
- var imports []*types.Package
- for id, pkg2 := range p.localPkgs {
- if pkg2.Name() == "" {
- p.errorf("%s package has no name", id)
- }
- if id == p.id {
- continue // avoid self-edge
- }
- imports = append(imports, pkg2)
- }
- sort.Sort(byPath(imports))
- pkg.SetImports(imports)
-
- // package was imported completely and without errors
- pkg.MarkComplete()
-
- return pkg
-}
-
type byPath []*types.Package
func (a byPath) Len() int { return len(a) }
diff --git a/src/go/internal/gcimporter/gcimporter_test.go b/src/go/internal/gcimporter/gcimporter_test.go
index d8c5bcf..a0697fa 100644
--- a/src/go/internal/gcimporter/gcimporter_test.go
+++ b/src/go/internal/gcimporter/gcimporter_test.go
@@ -5,6 +5,7 @@
package gcimporter
import (
+ "bytes"
"fmt"
"internal/testenv"
"io/ioutil"
@@ -34,22 +35,7 @@ func skipSpecialPlatforms(t *testing.T) {
}
func compile(t *testing.T, dirname, filename string) string {
- testenv.MustHaveGoBuild(t)
- cmd := exec.Command("go", "tool", "compile", filename)
- cmd.Dir = dirname
- out, err := cmd.CombinedOutput()
- if err != nil {
- t.Logf("%s", out)
- t.Fatalf("go tool compile %s failed: %s", filename, err)
- }
- // filename should end with ".go"
- return filepath.Join(dirname, filename[:len(filename)-2]+"o")
-}
-
-// TODO(gri) Remove this function once we switched to new export format by default.
-func compileNewExport(t *testing.T, dirname, filename string) string {
- testenv.MustHaveGoBuild(t)
- cmd := exec.Command("go", "tool", "compile", "-newexport", filename)
+ cmd := exec.Command(testenv.GoToolPath(t), "tool", "compile", filename)
cmd.Dir = dirname
out, err := cmd.CombinedOutput()
if err != nil {
@@ -121,6 +107,8 @@ func TestImportTestdata(t *testing.T) {
// additional packages that are not strictly required for
// import processing alone (they are exported to err "on
// the safe side").
+ // TODO(gri) update the want list to be precise, now that
+ // the textual export data is gone.
got := fmt.Sprint(pkg.Imports())
for _, want := range []string{"go/ast", "go/token"} {
if !strings.Contains(got, want) {
@@ -130,27 +118,66 @@ func TestImportTestdata(t *testing.T) {
}
}
-// TODO(gri) Remove this function once we switched to new export format by default
-// (and update the comment and want list in TestImportTestdata).
-func TestImportTestdataNewExport(t *testing.T) {
+func TestVersionHandling(t *testing.T) {
+ skipSpecialPlatforms(t) // we really only need to exclude nacl platforms, but this is fine
+
// 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 := compileNewExport(t, "testdata", "exports.go"); outFn != "" {
- defer os.Remove(outFn)
+ const dir = "./testdata/versions"
+ list, err := ioutil.ReadDir(dir)
+ if err != nil {
+ t.Fatal(err)
}
- if pkg := testPath(t, "./testdata/exports", "."); pkg != nil {
- // The package's Imports list must include all packages
- // explicitly imported by exports.go, plus all packages
- // referenced indirectly via exported objects in exports.go.
- want := `[package ast ("go/ast") package token ("go/token")]`
- got := fmt.Sprint(pkg.Imports())
- if got != want {
- t.Errorf(`Package("exports").Imports() = %s, want %s`, got, want)
+ for _, f := range list {
+ name := f.Name()
+ if !strings.HasSuffix(name, ".a") {
+ continue // not a package file
+ }
+ if strings.Contains(name, "corrupted") {
+ continue // don't process a leftover corrupted file
+ }
+ pkgpath := "./" + name[:len(name)-2]
+
+ // test that export data can be imported
+ _, err := Import(make(map[string]*types.Package), pkgpath, dir)
+ if err != nil {
+ t.Errorf("import %q failed: %v", pkgpath, err)
+ continue
+ }
+
+ // create file with corrupted export data
+ // 1) read file
+ data, err := ioutil.ReadFile(filepath.Join(dir, name))
+ if err != nil {
+ t.Fatal(err)
+ }
+ // 2) find export data
+ i := bytes.Index(data, []byte("\n$$B\n")) + 5
+ j := bytes.Index(data[i:], []byte("\n$$\n")) + i
+ if i < 0 || j < 0 || i > j {
+ t.Fatalf("export data section not found (i = %d, j = %d)", i, j)
+ }
+ // 3) corrupt the data (increment every 7th byte)
+ for k := j - 13; k >= i; k -= 7 {
+ data[k]++
+ }
+ // 4) write the file
+ pkgpath += "_corrupted"
+ filename := filepath.Join(dir, pkgpath) + ".a"
+ ioutil.WriteFile(filename, data, 0666)
+ defer os.Remove(filename)
+
+ // test that importing the corrupted file results in an error
+ _, err = Import(make(map[string]*types.Package), pkgpath, dir)
+ if err == nil {
+ t.Errorf("import corrupted %q succeeded", pkgpath)
+ } else if msg := err.Error(); !strings.Contains(msg, "version skew") {
+ t.Errorf("import %q error incorrect (%s)", pkgpath, msg)
}
}
}
diff --git a/src/go/internal/gcimporter/testdata/exports.go b/src/go/internal/gcimporter/testdata/exports.go
index 8ee28b0..9a0273b 100644
--- a/src/go/internal/gcimporter/testdata/exports.go
+++ b/src/go/internal/gcimporter/testdata/exports.go
@@ -7,9 +7,7 @@
package exports
-import (
- "go/ast"
-)
+import "go/ast"
// Issue 3682: Correctly read dotted identifiers from export data.
const init1 = 0
@@ -77,7 +75,8 @@ type (
var (
V0 int
- V1 = -991.0
+ V1 = -991.0
+ V2 float32 = 1.2
)
func F1() {}
diff --git a/src/go/internal/gcimporter/testdata/versions/test.go b/src/go/internal/gcimporter/testdata/versions/test.go
new file mode 100644
index 0000000..ac9c968
--- /dev/null
+++ b/src/go/internal/gcimporter/testdata/versions/test.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.
+
+// To create a test case for a new export format version,
+// build this package with the latest compiler and store
+// the resulting .a file appropriately named in the versions
+// directory. The VersionHandling test will pick it up.
+//
+// In the testdata/versions:
+//
+// go build -o test_go1.$X_$Y.a test.go
+//
+// with $X = Go version and $Y = export format version.
+//
+// Make sure this source is extended such that it exercises
+// whatever export format change has taken place.
+
+package test
+
+// Any release before and including Go 1.7 didn't encode
+// the package for a blank struct field.
+type BlankField struct {
+ _ int
+}
diff --git a/src/go/internal/gcimporter/testdata/versions/test_go1.7_0.a b/src/go/internal/gcimporter/testdata/versions/test_go1.7_0.a
new file mode 100644
index 0000000..edb6c3f
Binary files /dev/null and b/src/go/internal/gcimporter/testdata/versions/test_go1.7_0.a differ
diff --git a/src/go/internal/gcimporter/testdata/versions/test_go1.7_1.a b/src/go/internal/gcimporter/testdata/versions/test_go1.7_1.a
new file mode 100644
index 0000000..554d04a
Binary files /dev/null and b/src/go/internal/gcimporter/testdata/versions/test_go1.7_1.a differ
diff --git a/src/go/printer/printer.go b/src/go/printer/printer.go
index a3eaa66..eabf23e 100644
--- a/src/go/printer/printer.go
+++ b/src/go/printer/printer.go
@@ -712,6 +712,16 @@ func (p *printer) writeCommentSuffix(needsLinebreak bool) (wroteNewline, dropped
return
}
+// containsLinebreak reports whether the whitespace buffer contains any line breaks.
+func (p *printer) containsLinebreak() bool {
+ for _, ch := range p.wsbuf {
+ if ch == newline || ch == formfeed {
+ return true
+ }
+ }
+ return false
+}
+
// intersperseComments consumes all comments that appear before the next token
// tok and prints it together with the buffered whitespace (i.e., the whitespace
// that needs to be written before the next token). A heuristic is used to mix
@@ -730,23 +740,31 @@ func (p *printer) intersperseComments(next token.Position, tok token.Token) (wro
}
if last != nil {
- // if the last comment is a /*-style comment and the next item
+ // If the last comment is a /*-style comment and the next item
// follows on the same line but is not a comma, and not a "closing"
// token immediately following its corresponding "opening" token,
- // add an extra blank for separation unless explicitly disabled
+ // add an extra separator unless explicitly disabled. Use a blank
+ // as separator unless we have pending linebreaks and they are not
+ // disabled, in which case we want a linebreak (issue 15137).
+ needsLinebreak := false
if p.mode&noExtraBlank == 0 &&
last.Text[1] == '*' && p.lineFor(last.Pos()) == next.Line &&
tok != token.COMMA &&
(tok != token.RPAREN || p.prevOpen == token.LPAREN) &&
(tok != token.RBRACK || p.prevOpen == token.LBRACK) {
- p.writeByte(' ', 1)
+ if p.containsLinebreak() && p.mode&noExtraLinebreak == 0 {
+ needsLinebreak = true
+ } else {
+ p.writeByte(' ', 1)
+ }
+ }
+ // Ensure that there is a line break after a //-style comment,
+ // before EOF, and before a closing '}' unless explicitly disabled.
+ if last.Text[1] == '/' ||
+ tok == token.EOF ||
+ tok == token.RBRACE && p.mode&noExtraLinebreak == 0 {
+ needsLinebreak = true
}
- // ensure that there is a line break after a //-style comment,
- // before a closing '}' unless explicitly disabled, or at eof
- needsLinebreak :=
- last.Text[1] == '/' ||
- tok == token.RBRACE && p.mode&noExtraLinebreak == 0 ||
- tok == token.EOF
return p.writeCommentSuffix(needsLinebreak)
}
@@ -1292,6 +1310,8 @@ func (cfg *Config) Fprint(output io.Writer, fset *token.FileSet, node interface{
// Fprint "pretty-prints" an AST node to output.
// It calls Config.Fprint with default settings.
+// Note that gofmt uses tabs for indentation but spaces for alignent;
+// use format.Node (package go/format) for output that matches gofmt.
//
func Fprint(output io.Writer, fset *token.FileSet, node interface{}) error {
return (&Config{Tabwidth: 8}).Fprint(output, fset, node)
diff --git a/src/go/printer/printer_test.go b/src/go/printer/printer_test.go
index 73f9ead..0badbfb 100644
--- a/src/go/printer/printer_test.go
+++ b/src/go/printer/printer_test.go
@@ -197,12 +197,17 @@ var data = []entry{
}
func TestFiles(t *testing.T) {
+ t.Parallel()
for _, e := range data {
source := filepath.Join(dataDir, e.source)
golden := filepath.Join(dataDir, e.golden)
- check(t, source, golden, e.mode)
- // TODO(gri) check that golden is idempotent
- //check(t, golden, golden, e.mode)
+ mode := e.mode
+ t.Run(e.source, func(t *testing.T) {
+ t.Parallel()
+ check(t, source, golden, mode)
+ // TODO(gri) check that golden is idempotent
+ //check(t, golden, golden, e.mode)
+ })
}
}
@@ -295,6 +300,7 @@ func testComment(t *testing.T, f *ast.File, srclen int, comment *ast.Comment) {
// even if the position information of comments introducing newlines
// is incorrect.
func TestBadComments(t *testing.T) {
+ t.Parallel()
const src = `
// first comment - text and position changed by test
package p
@@ -481,6 +487,7 @@ func TestStmtLists(t *testing.T) {
}
func TestBaseIndent(t *testing.T) {
+ t.Parallel()
// The testfile must not contain multi-line raw strings since those
// are not indented (because their values must not change) and make
// this test fail.
@@ -495,28 +502,31 @@ func TestBaseIndent(t *testing.T) {
panic(err) // error in test
}
- var buf bytes.Buffer
for indent := 0; indent < 4; indent++ {
- buf.Reset()
- (&Config{Tabwidth: tabwidth, Indent: indent}).Fprint(&buf, fset, file)
- // all code must be indented by at least 'indent' tabs
- lines := bytes.Split(buf.Bytes(), []byte{'\n'})
- for i, line := range lines {
- if len(line) == 0 {
- continue // empty lines don't have indentation
- }
- n := 0
- for j, b := range line {
- if b != '\t' {
- // end of indentation
- n = j
- break
+ indent := indent
+ t.Run(fmt.Sprint(indent), func(t *testing.T) {
+ t.Parallel()
+ var buf bytes.Buffer
+ (&Config{Tabwidth: tabwidth, Indent: indent}).Fprint(&buf, fset, file)
+ // all code must be indented by at least 'indent' tabs
+ lines := bytes.Split(buf.Bytes(), []byte{'\n'})
+ for i, line := range lines {
+ if len(line) == 0 {
+ continue // empty lines don't have indentation
+ }
+ n := 0
+ for j, b := range line {
+ if b != '\t' {
+ // end of indentation
+ n = j
+ break
+ }
+ }
+ if n < indent {
+ t.Errorf("line %d: got only %d tabs; want at least %d: %q", i, n, indent, line)
}
}
- if n < indent {
- t.Errorf("line %d: got only %d tabs; want at least %d: %q", i, n, indent, line)
- }
- }
+ })
}
}
@@ -567,6 +577,7 @@ func (l *limitWriter) Write(buf []byte) (n int, err error) {
// Test whether the printer stops writing after the first error
func TestWriteErrors(t *testing.T) {
+ t.Parallel()
const filename = "printer.go"
src, err := ioutil.ReadFile(filename)
if err != nil {
diff --git a/src/go/printer/testdata/comments.golden b/src/go/printer/testdata/comments.golden
index 849fa62..4d92e65 100644
--- a/src/go/printer/testdata/comments.golden
+++ b/src/go/printer/testdata/comments.golden
@@ -601,6 +601,32 @@ func _() {
_ = a
}
+// Test cases from issues 11274, 15137:
+// Semicolon must not be lost when multiple statements are on the same line with a comment.
+func _() {
+ x := 0 /**/
+ y := 1
+}
+
+func _() {
+ f()
+ f()
+ f() /* comment */
+ f()
+ f() /* comment */
+ f()
+ f() /* a */ /* b */
+ f()
+ f() /* a */ /* b */
+ f()
+ f() /* a */ /* b */
+ f()
+}
+
+func _() {
+ f() /* a */ /* b */
+}
+
// Comments immediately adjacent to punctuation followed by a newline
// remain after the punctuation (looks better and permits alignment of
// comments).
diff --git a/src/go/printer/testdata/comments.input b/src/go/printer/testdata/comments.input
index 30cd23c..40351ee 100644
--- a/src/go/printer/testdata/comments.input
+++ b/src/go/printer/testdata/comments.input
@@ -607,6 +607,24 @@ func _() {
_ = a
}
+// Test cases from issues 11274, 15137:
+// Semicolon must not be lost when multiple statements are on the same line with a comment.
+func _() {
+ x := 0 /**/; y := 1
+}
+
+func _() {
+ f(); f()
+ f(); /* comment */ f()
+ f() /* comment */; f()
+ f(); /* a */ /* b */ f()
+ f() /* a */ /* b */; f()
+ f() /* a */; /* b */ f()
+}
+
+func _() {
+ f() /* a */ /* b */ }
+
// Comments immediately adjacent to punctuation followed by a newline
// remain after the punctuation (looks better and permits alignment of
// comments).
diff --git a/src/go/scanner/scanner.go b/src/go/scanner/scanner.go
index ce660c7..a86e4eb 100644
--- a/src/go/scanner/scanner.go
+++ b/src/go/scanner/scanner.go
@@ -349,7 +349,11 @@ exponent:
if s.ch == '-' || s.ch == '+' {
s.next()
}
- s.scanMantissa(10)
+ if digitVal(s.ch) < 10 {
+ s.scanMantissa(10)
+ } else {
+ s.error(offs, "illegal floating-point exponent")
+ }
}
if s.ch == 'i' {
diff --git a/src/go/scanner/scanner_test.go b/src/go/scanner/scanner_test.go
index 0d21905..ff41c03 100644
--- a/src/go/scanner/scanner_test.go
+++ b/src/go/scanner/scanner_test.go
@@ -716,6 +716,7 @@ var errors = []struct {
{"078.", token.FLOAT, 0, "078.", ""},
{"07801234567.", token.FLOAT, 0, "07801234567.", ""},
{"078e0", token.FLOAT, 0, "078e0", ""},
+ {"0E", token.FLOAT, 0, "0E", "illegal floating-point exponent"}, // issue 17621
{"078", token.INT, 0, "078", "illegal octal number"},
{"07800000009", token.INT, 0, "07800000009", "illegal octal number"},
{"0x", token.INT, 0, "0x", "illegal hexadecimal number"},
diff --git a/src/go/token/position.go b/src/go/token/position.go
index 7306083..d4171d8 100644
--- a/src/go/token/position.go
+++ b/src/go/token/position.go
@@ -446,7 +446,9 @@ 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
diff --git a/src/go/token/position_test.go b/src/go/token/position_test.go
index d26939c..63984bc 100644
--- a/src/go/token/position_test.go
+++ b/src/go/token/position_test.go
@@ -214,7 +214,7 @@ func TestFileSetCacheUnlikely(t *testing.T) {
}
}
-// issue 4345. Test concurrent use of FileSet.Pos does not trigger a
+// issue 4345. Test that concurrent use of FileSet.Pos does not trigger a
// race in the FileSet position cache.
func TestFileSetRace(t *testing.T) {
fset := NewFileSet()
@@ -237,6 +237,35 @@ func TestFileSetRace(t *testing.T) {
stop.Wait()
}
+// issue 16548. Test that concurrent use of File.AddLine and FileSet.PositionFor
+// does not trigger a race in the FileSet position cache.
+func TestFileSetRace2(t *testing.T) {
+ const N = 1e3
+ var (
+ fset = NewFileSet()
+ file = fset.AddFile("", -1, N)
+ ch = make(chan int, 2)
+ )
+
+ go func() {
+ for i := 0; i < N; i++ {
+ file.AddLine(i)
+ }
+ ch <- 1
+ }()
+
+ go func() {
+ pos := file.Pos(0)
+ for i := 0; i < N; i++ {
+ fset.PositionFor(pos, false)
+ }
+ ch <- 1
+ }()
+
+ <-ch
+ <-ch
+}
+
func TestPositionFor(t *testing.T) {
src := []byte(`
foo
diff --git a/src/go/types/api.go b/src/go/types/api.go
index ca109f0..4494989 100644
--- a/src/go/types/api.go
+++ b/src/go/types/api.go
@@ -135,7 +135,8 @@ type Config struct {
// be incomplete.
type Info struct {
// Types maps expressions to their types, and for constant
- // expressions, their values. Invalid expressions are omitted.
+ // expressions, also their values. Invalid expressions are
+ // omitted.
//
// For (possibly parenthesized) identifiers denoting built-in
// functions, the recorded signatures are call-site specific:
@@ -143,9 +144,13 @@ type Info struct {
// an argument-specific signature. Otherwise, the recorded type
// is invalid.
//
- // Identifiers on the lhs of declarations (i.e., the identifiers
- // which are being declared) are collected in the Defs map.
- // Identifiers denoting packages are collected in the Uses maps.
+ // The Types map does not record the type of every identifier,
+ // only those that appear where an arbitrary expression is
+ // permitted. For instance, the identifier f in a selector
+ // expression x.f is found only in the Selections map, the
+ // identifier z in a variable declaration 'var z int' is found
+ // only in the Defs map, and identifiers denoting packages in
+ // qualified identifiers are collected in the Uses map.
Types map[ast.Expr]TypeAndValue
// Defs maps identifiers to the objects they define (including
diff --git a/src/go/types/api_test.go b/src/go/types/api_test.go
index 035ffd6..1208eb8 100644
--- a/src/go/types/api_test.go
+++ b/src/go/types/api_test.go
@@ -171,13 +171,11 @@ func TestTypesInfo(t *testing.T) {
`x.(int)`,
`(int, bool)`,
},
- // TODO(gri): uncomment if we accept issue 8189.
- // {`package p2; type mybool bool; var m map[string]complex128; var b mybool; func _() { _, b = m["foo"] }`,
- // `m["foo"]`,
- // `(complex128, p2.mybool)`,
- // },
- // TODO(gri): remove if we accept issue 8189.
- {`package p2; var m map[string]complex128; var b bool; func _() { _, b = m["foo"] }`,
+ {`package p2a; type mybool bool; var m map[string]complex128; var b mybool; func _() { _, b = m["foo"] }`,
+ `m["foo"]`,
+ `(complex128, p2a.mybool)`,
+ },
+ {`package p2b; var m map[string]complex128; var b bool; func _() { _, b = m["foo"] }`,
`m["foo"]`,
`(complex128, bool)`,
},
@@ -573,26 +571,25 @@ func TestInitOrderInfo(t *testing.T) {
"a = next()", "b = next()", "c = next()", "d = next()", "e = next()", "f = next()", "_ = makeOrder()",
}},
// test case for issue 10709
- // TODO(gri) enable once the issue is fixed
- // {`package p13
-
- // var (
- // v = t.m()
- // t = makeT(0)
- // )
-
- // type T struct{}
-
- // func (T) m() int { return 0 }
-
- // func makeT(n int) T {
- // if n > 0 {
- // return makeT(n-1)
- // }
- // return T{}
- // }`, []string{
- // "t = makeT(0)", "v = t.m()",
- // }},
+ {`package p13
+
+ var (
+ v = t.m()
+ t = makeT(0)
+ )
+
+ type T struct{}
+
+ func (T) m() int { return 0 }
+
+ func makeT(n int) T {
+ if n > 0 {
+ return makeT(n-1)
+ }
+ return T{}
+ }`, []string{
+ "t = makeT(0)", "v = t.m()",
+ }},
// test case for issue 10709: same as test before, but variable decls swapped
{`package p14
@@ -613,6 +610,24 @@ func TestInitOrderInfo(t *testing.T) {
}`, []string{
"t = makeT(0)", "v = t.m()",
}},
+ // another candidate possibly causing problems with issue 10709
+ {`package p15
+
+ var y1 = f1()
+
+ func f1() int { return g1() }
+ func g1() int { f1(); return x1 }
+
+ var x1 = 0
+
+ var y2 = f2()
+
+ func f2() int { return g2() }
+ func g2() int { return x2 }
+
+ var x2 = 0`, []string{
+ "x1 = 0", "y1 = f1()", "x2 = 0", "y2 = f2()",
+ }},
}
for _, test := range tests {
@@ -1001,7 +1016,11 @@ func TestScopeLookupParent(t *testing.T) {
}
var info Info
makePkg := func(path string, files ...*ast.File) {
- imports[path], _ = conf.Check(path, fset, files, &info)
+ var err error
+ imports[path], err = conf.Check(path, fset, files, &info)
+ if err != nil {
+ t.Fatal(err)
+ }
}
makePkg("lib", mustParse("package lib; var X int"))
@@ -1009,17 +1028,44 @@ func TestScopeLookupParent(t *testing.T) {
// name at that point and checks that it resolves to a decl of
// the specified kind and line number. "undef" means undefined.
mainSrc := `
+/*lib=pkgname:5*/ /*X=var:1*/ /*Pi=const:8*/ /*T=typename:9*/ /*Y=var:10*/ /*F=func:12*/
package main
+
import "lib"
-var Y = lib.X
-func f() {
- print(Y) /*Y=var:4*/
- z /*z=undef*/ := /*z=undef*/ 1 /*z=var:7*/
- print(z)
- /*f=func:5*/ /*lib=pkgname:3*/
- type /*T=undef*/ T /*T=typename:10*/ *T
+import . "lib"
+
+const Pi = 3.1415
+type T struct{}
+var Y, _ = lib.X, X
+
+func F(){
+ const pi, e = 3.1415, /*pi=undef*/ 2.71828 /*pi=const:13*/ /*e=const:13*/
+ type /*t=undef*/ t /*t=typename:14*/ *t
+ print(Y) /*Y=var:10*/
+ x, Y := Y, /*x=undef*/ /*Y=var:10*/ Pi /*x=var:16*/ /*Y=var:16*/ ; _ = x; _ = Y
+ var F = /*F=func:12*/ F /*F=var:17*/ ; _ = F
+
+ var a []int
+ for i, x := range /*i=undef*/ /*x=var:16*/ a /*i=var:20*/ /*x=var:20*/ { _ = i; _ = x }
+
+ var i interface{}
+ switch y := i.(type) { /*y=undef*/
+ case /*y=undef*/ int /*y=var:23*/ :
+ case float32, /*y=undef*/ float64 /*y=var:23*/ :
+ default /*y=var:23*/:
+ println(y)
+ }
+ /*y=undef*/
+
+ switch int := i.(type) {
+ case /*int=typename:0*/ int /*int=var:31*/ :
+ println(int)
+ default /*int=var:31*/ :
+ }
}
+/*main=undef*/
`
+
info.Uses = make(map[*ast.Ident]Object)
f := mustParse(mainSrc)
makePkg("main", f)
@@ -1125,3 +1171,279 @@ func TestIssue15305(t *testing.T) {
}
t.Errorf("CallExpr has no type")
}
+
+// TestCompositeLitTypes verifies that Info.Types registers the correct
+// types for composite literal expressions and composite literal type
+// expressions.
+func TestCompositeLitTypes(t *testing.T) {
+ for _, test := range []struct {
+ lit, typ string
+ }{
+ {`[16]byte{}`, `[16]byte`},
+ {`[...]byte{}`, `[0]byte`}, // test for issue #14092
+ {`[...]int{1, 2, 3}`, `[3]int`}, // test for issue #14092
+ {`[...]int{90: 0, 98: 1, 2}`, `[100]int`}, // test for issue #14092
+ {`[]int{}`, `[]int`},
+ {`map[string]bool{"foo": true}`, `map[string]bool`},
+ {`struct{}{}`, `struct{}`},
+ {`struct{x, y int; z complex128}{}`, `struct{x int; y int; z complex128}`},
+ } {
+ fset := token.NewFileSet()
+ f, err := parser.ParseFile(fset, test.lit, "package p; var _ = "+test.lit, 0)
+ if err != nil {
+ t.Fatalf("%s: %v", test.lit, err)
+ }
+
+ info := &Info{
+ Types: make(map[ast.Expr]TypeAndValue),
+ }
+ if _, err = new(Config).Check("p", fset, []*ast.File{f}, info); err != nil {
+ t.Fatalf("%s: %v", test.lit, err)
+ }
+
+ cmptype := func(x ast.Expr, want string) {
+ tv, ok := info.Types[x]
+ if !ok {
+ t.Errorf("%s: no Types entry found", test.lit)
+ return
+ }
+ if tv.Type == nil {
+ t.Errorf("%s: type is nil", test.lit)
+ return
+ }
+ if got := tv.Type.String(); got != want {
+ t.Errorf("%s: got %v, want %s", test.lit, got, want)
+ }
+ }
+
+ // test type of composite literal expression
+ rhs := f.Decls[0].(*ast.GenDecl).Specs[0].(*ast.ValueSpec).Values[0]
+ cmptype(rhs, test.typ)
+
+ // test type of composite literal type expression
+ cmptype(rhs.(*ast.CompositeLit).Type, test.typ)
+ }
+}
+
+// TestObjectParents verifies that objects have parent scopes or not
+// as specified by the Object interface.
+func TestObjectParents(t *testing.T) {
+ const src = `
+package p
+
+const C = 0
+
+type T1 struct {
+ a, b int
+ T2
+}
+
+type T2 interface {
+ im1()
+ im2()
+}
+
+func (T1) m1() {}
+func (*T1) m2() {}
+
+func f(x int) { y := x; print(y) }
+`
+
+ fset := token.NewFileSet()
+ f, err := parser.ParseFile(fset, "src", src, 0)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ info := &Info{
+ Defs: make(map[*ast.Ident]Object),
+ }
+ if _, err = new(Config).Check("p", fset, []*ast.File{f}, info); err != nil {
+ t.Fatal(err)
+ }
+
+ for ident, obj := range info.Defs {
+ if obj == nil {
+ // only package names and implicit vars have a nil object
+ // (in this test we only need to handle the package name)
+ if ident.Name != "p" {
+ t.Errorf("%v has nil object", ident)
+ }
+ continue
+ }
+
+ // struct fields, type-associated and interface methods
+ // have no parent scope
+ wantParent := true
+ switch obj := obj.(type) {
+ case *Var:
+ if obj.IsField() {
+ wantParent = false
+ }
+ case *Func:
+ if obj.Type().(*Signature).Recv() != nil { // method
+ wantParent = false
+ }
+ }
+
+ gotParent := obj.Parent() != nil
+ switch {
+ case gotParent && !wantParent:
+ t.Errorf("%v: want no parent, got %s", ident, obj.Parent())
+ case !gotParent && wantParent:
+ t.Errorf("%v: no parent found", ident)
+ }
+ }
+}
+
+// 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) {
+ testenv.MustHaveGoBuild(t)
+
+ const src = `
+package p
+
+import(
+ "go/build"
+ "go/types"
+)
+
+// 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)
+`
+
+ 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",
+ }
+
+ 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)
+ }
+ delete(defs, ident.Name) // mark as found
+ } else {
+ t.Errorf("unexpected alias def of %v", ident)
+ }
+ }
+ }
+
+ if len(defs) != 0 {
+ t.Errorf("missing aliases: %v", defs)
+ }
+
+ // verify Uses
+ uses := map[string]string{
+ "Invalid": "types.Invalid",
+ "Struct": "types.Struct",
+ "Default": "build.Default",
+ "Implements": "types.Implements",
+ }
+
+ 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)
+ }
+ 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 6ebf3b5..18f893d 100644
--- a/src/go/types/assignments.go
+++ b/src/go/types/assignments.go
@@ -41,7 +41,7 @@ func (check *Checker) assignment(x *operand, T Type, context string) {
x.mode = invalid
return
}
- target = defaultType(x.typ)
+ target = Default(x.typ)
}
check.convertUntyped(x, target)
if x.mode == invalid {
@@ -116,7 +116,7 @@ func (check *Checker) initVar(lhs *Var, x *operand, context string) Type {
lhs.typ = Typ[Invalid]
return nil
}
- typ = defaultType(typ)
+ typ = Default(typ)
}
lhs.typ = typ
}
diff --git a/src/go/types/builtins.go b/src/go/types/builtins.go
index 0082be9..596a989 100644
--- a/src/go/types/builtins.go
+++ b/src/go/types/builtins.go
@@ -434,7 +434,7 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
return
}
if nargs < min || min+1 < nargs {
- check.errorf(call.Pos(), "%s expects %d or %d arguments; found %d", call, min, min+1, nargs)
+ check.errorf(call.Pos(), "%v expects %d or %d arguments; found %d", call, min, min+1, nargs)
return
}
var sizes []int64 // constant integer arguments, if any
@@ -595,7 +595,7 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
return
}
if !constant.BoolVal(x.val) {
- check.errorf(call.Pos(), "%s failed", call)
+ check.errorf(call.Pos(), "%v failed", call)
// compile-time assertion failure - safe to continue
}
// result is constant - no need to record signature
@@ -632,7 +632,7 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
func makeSig(res Type, args ...Type) *Signature {
list := make([]*Var, len(args))
for i, param := range args {
- list[i] = NewVar(token.NoPos, nil, "", defaultType(param))
+ list[i] = NewVar(token.NoPos, nil, "", Default(param))
}
params := NewTuple(list...)
var result *Tuple
diff --git a/src/go/types/call.go b/src/go/types/call.go
index 45f3e9a..8e5c537 100644
--- a/src/go/types/call.go
+++ b/src/go/types/call.go
@@ -275,24 +275,34 @@ 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 pkg, _ := obj.(*PkgName); pkg != nil {
- assert(pkg.pkg == check.pkg)
- check.recordUse(ident, pkg)
- pkg.used = true
- exp := pkg.imported.scope.Lookup(sel)
+ if pname, _ := obj.(*PkgName); pname != nil {
+ assert(pname.pkg == check.pkg)
+ check.recordUse(ident, pname)
+ pname.used = true
+ pkg := pname.imported
+ exp := pkg.scope.Lookup(sel)
if exp == nil {
- if !pkg.imported.fake {
- check.errorf(e.Pos(), "%s not declared by package %s", sel, ident)
+ if !pkg.fake {
+ check.errorf(e.Pos(), "%s not declared by package %s", sel, pkg.name)
}
goto Error
}
if !exp.Exported() {
- check.errorf(e.Pos(), "%s not exported by package %s", sel, ident)
+ check.errorf(e.Pos(), "%s not exported by package %s", sel, pkg.name)
// 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
switch exp := exp.(type) {
@@ -315,6 +325,7 @@ func (check *Checker) selector(x *operand, e *ast.SelectorExpr) {
x.typ = exp.typ
x.id = exp.id
default:
+ check.dump("unexpected object %v", exp)
unreachable()
}
x.expr = e
diff --git a/src/go/types/check.go b/src/go/types/check.go
index 0279be0..28e94f1 100644
--- a/src/go/types/check.go
+++ b/src/go/types/check.go
@@ -345,7 +345,6 @@ func (check *Checker) recordImplicit(node ast.Node, obj Object) {
func (check *Checker) recordSelection(x *ast.SelectorExpr, kind SelectionKind, recv Type, obj Object, index []int, indirect bool) {
assert(obj != nil && (recv == nil || len(index) > 0))
check.recordUse(x.Sel, obj)
- // TODO(gri) Should we also call recordTypeAndValue?
if m := check.Selections; m != nil {
m[x] = &Selection{kind, recv, obj, index, indirect}
}
diff --git a/src/go/types/check_test.go b/src/go/types/check_test.go
index 5e2043b..f844575 100644
--- a/src/go/types/check_test.go
+++ b/src/go/types/check_test.go
@@ -72,6 +72,7 @@ var tests = [][]string{
{"testdata/const1.src"},
{"testdata/constdecl.src"},
{"testdata/vardecl.src"},
+ //{"testdata/aliasdecl.src"},
{"testdata/expr0.src"},
{"testdata/expr1.src"},
{"testdata/expr2.src"},
@@ -80,6 +81,7 @@ var tests = [][]string{
{"testdata/shifts.src"},
{"testdata/builtins.src"},
{"testdata/conversions.src"},
+ {"testdata/conversions2.src"},
{"testdata/stmt0.src"},
{"testdata/stmt1.src"},
{"testdata/gotos.src"},
diff --git a/src/go/types/conversions.go b/src/go/types/conversions.go
index f98cc8d..2bf1e2d 100644
--- a/src/go/types/conversions.go
+++ b/src/go/types/conversions.go
@@ -55,7 +55,7 @@ func (check *Checker) conversion(x *operand, T Type) {
// not []byte as type for the constant "foo").
// - Keep untyped nil for untyped nil arguments.
if IsInterface(T) || constArg && !isConstType(T) {
- final = defaultType(x.typ)
+ final = Default(x.typ)
}
check.updateExprType(x.expr, final, true)
}
@@ -69,18 +69,19 @@ func (x *operand) convertibleTo(conf *Config, T Type) bool {
return true
}
- // "x's type and T have identical underlying types"
+ // "x's type and T have identical underlying types if tags are ignored"
V := x.typ
Vu := V.Underlying()
Tu := T.Underlying()
- if Identical(Vu, Tu) {
+ if IdenticalIgnoreTags(Vu, Tu) {
return true
}
- // "x's type and T are unnamed pointer types and their pointer base types have identical underlying types"
+ // "x's type and T are unnamed pointer types and their pointer base types
+ // have identical underlying types if tags are ignored"
if V, ok := V.(*Pointer); ok {
if T, ok := T.(*Pointer); ok {
- if Identical(V.base.Underlying(), T.base.Underlying()) {
+ if IdenticalIgnoreTags(V.base.Underlying(), T.base.Underlying()) {
return true
}
}
diff --git a/src/go/types/decl.go b/src/go/types/decl.go
index 1ecfb35..dced7a6 100644
--- a/src/go/types/decl.go
+++ b/src/go/types/decl.go
@@ -85,6 +85,10 @@ func (check *Checker) objDecl(obj Object, def *Named, path []*TypeName) {
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()
}
@@ -329,6 +333,106 @@ 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
diff --git a/src/go/types/expr.go b/src/go/types/expr.go
index 4430c45..f76da17 100644
--- a/src/go/types/expr.go
+++ b/src/go/types/expr.go
@@ -541,7 +541,7 @@ func (check *Checker) convertUntyped(x *operand, target Type) {
if !t.Empty() {
goto Error
}
- target = defaultType(x.typ)
+ target = Default(x.typ)
}
case *Pointer, *Signature, *Slice, *Map, *Chan:
if !x.isNil() {
@@ -605,8 +605,8 @@ func (check *Checker) comparison(x, y *operand, op token.Token) {
// time will be materialized. Update the expression trees.
// If the current types are untyped, the materialized type
// is the respective default type.
- check.updateExprType(x.expr, defaultType(x.typ), true)
- check.updateExprType(y.expr, defaultType(y.typ), true)
+ check.updateExprType(x.expr, Default(x.typ), true)
+ check.updateExprType(y.expr, Default(y.typ), true)
}
// spec: "Comparison operators compare two operands and yield
@@ -1015,32 +1015,38 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind {
}
case *ast.CompositeLit:
- typ := hint
- openArray := false
- if e.Type != nil {
+ var typ, base Type
+
+ switch {
+ case e.Type != nil:
+ // composite literal type present - use it
// [...]T array types may only appear with composite literals.
// Check for them here so we don't have to handle ... in general.
- typ = nil
if atyp, _ := e.Type.(*ast.ArrayType); atyp != nil && atyp.Len != nil {
if ellip, _ := atyp.Len.(*ast.Ellipsis); ellip != nil && ellip.Elt == nil {
// We have an "open" [...]T array type.
// Create a new ArrayType with unknown length (-1)
// and finish setting it up after analyzing the literal.
typ = &Array{len: -1, elem: check.typ(atyp.Elt)}
- openArray = true
+ base = typ
+ break
}
}
- if typ == nil {
- typ = check.typ(e.Type)
- }
- }
- if typ == nil {
+ typ = check.typ(e.Type)
+ base = typ
+
+ case hint != nil:
+ // no composite literal type present - use hint (element type of enclosing type)
+ typ = hint
+ base, _ = deref(typ.Underlying()) // *T implies &T{}
+
+ default:
// TODO(gri) provide better error messages depending on context
check.error(e.Pos(), "missing type in composite literal")
goto Error
}
- switch typ, _ := deref(typ); utyp := typ.Underlying().(type) {
+ switch utyp := base.Underlying().(type) {
case *Struct:
if len(e.Elts) == 0 {
break
@@ -1106,9 +1112,12 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind {
case *Array:
n := check.indexedElts(e.Elts, utyp.elem, utyp.len)
- // if we have an "open" [...]T array, set the length now that we know it
- if openArray {
+ // If we have an "open" [...]T array, set the length now that we know it
+ // and record the type for [...] (usually done by check.typExpr which is
+ // not called for [...]).
+ if utyp.len < 0 {
utyp.len = n
+ check.recordTypeAndValue(e.Type, typexpr, utyp, nil)
}
case *Slice:
diff --git a/src/go/types/initorder.go b/src/go/types/initorder.go
index cf9b870..966dccb 100644
--- a/src/go/types/initorder.go
+++ b/src/go/types/initorder.go
@@ -15,7 +15,7 @@ func (check *Checker) initOrder() {
// built from several calls to (*Checker).Files. Clear it.
check.Info.InitOrder = check.Info.InitOrder[:0]
- // Compute the transposed object dependency graph and initialize
+ // Compute the object dependency graph and initialize
// a priority queue with the list of graph nodes.
pq := nodeQueue(dependencyGraph(check.objMap))
heap.Init(&pq)
@@ -25,22 +25,25 @@ func (check *Checker) initOrder() {
fmt.Printf("Computing initialization order for %s\n\n", check.pkg)
fmt.Println("Object dependency graph:")
for obj, d := range check.objMap {
- if len(d.deps) > 0 {
- fmt.Printf("\t%s depends on\n", obj.Name())
- for dep := range d.deps {
- fmt.Printf("\t\t%s\n", dep.Name())
+ // only print objects that may appear in the dependency graph
+ if obj, _ := obj.(dependency); obj != nil {
+ if len(d.deps) > 0 {
+ fmt.Printf("\t%s depends on\n", obj.Name())
+ for dep := range d.deps {
+ fmt.Printf("\t\t%s\n", dep.Name())
+ }
+ } else {
+ fmt.Printf("\t%s has no dependencies\n", obj.Name())
}
- } else {
- fmt.Printf("\t%s has no dependencies\n", obj.Name())
}
}
fmt.Println()
- fmt.Println("Transposed object dependency graph:")
+ fmt.Println("Transposed object dependency graph (functions eliminated):")
for _, n := range pq {
- fmt.Printf("\t%s depends on %d nodes\n", n.obj.Name(), n.in)
- for _, out := range n.out {
- fmt.Printf("\t\t%s is dependent\n", out.obj.Name())
+ fmt.Printf("\t%s depends on %d nodes\n", n.obj.Name(), n.ndeps)
+ for p := range n.pred {
+ fmt.Printf("\t\t%s is dependent\n", p.obj.Name())
}
}
fmt.Println()
@@ -54,34 +57,40 @@ func (check *Checker) initOrder() {
// In a valid Go program, those nodes always have zero dependencies (after
// removing all incoming dependencies), otherwise there are initialization
// cycles.
- mark := 0
emitted := make(map[*declInfo]bool)
for len(pq) > 0 {
// get the next node
- n := heap.Pop(&pq).(*objNode)
+ n := heap.Pop(&pq).(*graphNode)
if debug {
fmt.Printf("\t%s (src pos %d) depends on %d nodes now\n",
- n.obj.Name(), n.obj.order(), n.in)
+ n.obj.Name(), n.obj.order(), n.ndeps)
}
// if n still depends on other nodes, we have a cycle
- if n.in > 0 {
- mark++ // mark nodes using a different value each time
- cycle := findPath(n, n, mark)
- if i := valIndex(cycle); i >= 0 {
- check.reportCycle(cycle, i)
+ if n.ndeps > 0 {
+ cycle := findPath(check.objMap, n.obj, n.obj, make(objSet))
+ // If n.obj is not part of the cycle (e.g., n.obj->b->c->d->c),
+ // cycle will be nil. Don't report anything in that case since
+ // the cycle is reported when the algorithm gets to an object
+ // in the cycle.
+ // Furthermore, once an object in the cycle is encountered,
+ // the cycle will be broken (dependency count will be reduced
+ // below), and so the remaining nodes in the cycle don't trigger
+ // another error (unless they are part of multiple cycles).
+ if cycle != nil {
+ check.reportCycle(cycle)
}
- // ok to continue, but the variable initialization order
+ // Ok to continue, but the variable initialization order
// will be incorrect at this point since it assumes no
- // cycle errors
+ // cycle errors.
}
// reduce dependency count of all dependent nodes
// and update priority queue
- for _, out := range n.out {
- out.in--
- heap.Fix(&pq, out.index)
+ for p := range n.pred {
+ p.ndeps--
+ heap.Fix(&pq, p.index)
}
// record the init order for variables with initializers only
@@ -118,102 +127,147 @@ func (check *Checker) initOrder() {
}
}
-// findPath returns the (reversed) list of nodes z, ... c, b, a,
-// such that there is a path (list of edges) from a to z.
+// findPath returns the (reversed) list of objects []Object{to, ... from}
+// such that there is a path of object dependencies from 'from' to 'to'.
// If there is no such path, the result is nil.
-// Nodes marked with the value mark are considered "visited";
-// unvisited nodes are marked during the graph search.
-func findPath(a, z *objNode, mark int) []*objNode {
- if a.mark == mark {
+func findPath(objMap map[Object]*declInfo, from, to Object, visited objSet) []Object {
+ if visited[from] {
return nil // node already seen
}
- a.mark = mark
+ visited[from] = true
- for _, n := range a.out {
- if n == z {
- return []*objNode{z}
+ for d := range objMap[from].deps {
+ if d == to {
+ return []Object{d}
}
- if P := findPath(n, z, mark); P != nil {
- return append(P, n)
+ if P := findPath(objMap, d, to, visited); P != nil {
+ return append(P, d)
}
}
return nil
}
-// valIndex returns the index of the first constant or variable in a,
-// if any; or a value < 0.
-func valIndex(a []*objNode) int {
- for i, n := range a {
- switch n.obj.(type) {
- case *Const, *Var:
- return i
- }
- }
- return -1
-}
-
-// reportCycle reports an error for the cycle starting at i.
-func (check *Checker) reportCycle(cycle []*objNode, i int) {
- obj := cycle[i].obj
+// reportCycle reports an error for the given cycle.
+func (check *Checker) reportCycle(cycle []Object) {
+ obj := cycle[0]
check.errorf(obj.Pos(), "initialization cycle for %s", obj.Name())
- // print cycle
- for _ = range cycle {
+ // subtle loop: print cycle[i] for i = 0, n-1, n-2, ... 1 for len(cycle) = n
+ for i := len(cycle) - 1; i >= 0; i-- {
check.errorf(obj.Pos(), "\t%s refers to", obj.Name()) // secondary error, \t indented
- i++
- if i >= len(cycle) {
- i = 0
- }
- obj = cycle[i].obj
+ obj = cycle[i]
}
+ // print cycle[0] again to close the cycle
check.errorf(obj.Pos(), "\t%s", obj.Name())
}
-// An objNode represents a node in the object dependency graph.
-// Each node b in a.out represents an edge a->b indicating that
-// b depends on a.
-// Nodes may be marked for cycle detection. A node n is marked
-// if n.mark corresponds to the current mark value.
-type objNode struct {
- obj Object // object represented by this node
- in int // number of nodes this node depends on
- out []*objNode // list of nodes that depend on this node
- index int // node index in list of nodes
- mark int // for cycle detection
+// ----------------------------------------------------------------------------
+// Object dependency graph
+
+// A dependency is an object that may be a dependency in an initialization
+// expression. Only constants, variables, and functions can be dependencies.
+// Constants are here because constant expression cycles are reported during
+// initialization order computation.
+type dependency interface {
+ Object
+ isDependency()
+}
+
+// A graphNode represents a node in the object dependency graph.
+// Each node p in n.pred represents an edge p->n, and each node
+// s in n.succ represents an edge n->s; with a->b indicating that
+// a depends on b.
+type graphNode struct {
+ obj dependency // object represented by this node
+ pred, succ nodeSet // consumers and dependencies of this node (lazily initialized)
+ index int // node index in graph slice/priority queue
+ ndeps int // number of outstanding dependencies before this object can be initialized
+}
+
+type nodeSet map[*graphNode]bool
+
+func (s *nodeSet) add(p *graphNode) {
+ if *s == nil {
+ *s = make(nodeSet)
+ }
+ (*s)[p] = true
}
-// dependencyGraph computes the transposed object dependency graph
-// from the given objMap. The transposed graph is returned as a list
-// of nodes; an edge d->n indicates that node n depends on node d.
-func dependencyGraph(objMap map[Object]*declInfo) []*objNode {
- // M maps each object to its corresponding node
- M := make(map[Object]*objNode, len(objMap))
+// dependencyGraph computes the object dependency graph from the given objMap,
+// with any function nodes removed. The resulting graph contains only constants
+// and variables.
+func dependencyGraph(objMap map[Object]*declInfo) []*graphNode {
+ // M is the dependency (Object) -> graphNode mapping
+ M := make(map[dependency]*graphNode)
for obj := range objMap {
- M[obj] = &objNode{obj: obj}
+ // only consider nodes that may be an initialization dependency
+ if obj, _ := obj.(dependency); obj != nil {
+ M[obj] = &graphNode{obj: obj}
+ }
}
- // G is the graph of nodes n
- G := make([]*objNode, len(M))
- i := 0
+ // compute edges for graph M
+ // (We need to include all nodes, even isolated ones, because they still need
+ // to be scheduled for initialization in correct order relative to other nodes.)
for obj, n := range M {
- deps := objMap[obj].deps
- n.in = len(deps)
- for d := range deps {
- d := M[d] // node n depends on node d
- d.out = append(d.out, n) // add edge d->n
+ // for each dependency obj -> d (= deps[i]), create graph edges n->s and s->n
+ for d := range objMap[obj].deps {
+ // only consider nodes that may be an initialization dependency
+ if d, _ := d.(dependency); d != nil {
+ d := M[d]
+ n.succ.add(d)
+ d.pred.add(n)
+ }
}
+ }
- G[i] = n
+ // remove function nodes and collect remaining graph nodes in G
+ // (Mutually recursive functions may introduce cycles among themselves
+ // which are permitted. Yet such cycles may incorrectly inflate the dependency
+ // count for variables which in turn may not get scheduled for initialization
+ // in correct order.)
+ var G []*graphNode
+ for obj, n := range M {
+ if _, ok := obj.(*Func); ok {
+ // connect each predecessor p of n with each successor s
+ // and drop the function node (don't collect it in G)
+ for p := range n.pred {
+ // ignore self-cycles
+ if p != n {
+ // Each successor s of n becomes a successor of p, and
+ // each predecessor p of n becomes a predecessor of s.
+ for s := range n.succ {
+ // ignore self-cycles
+ if s != n {
+ p.succ.add(s)
+ s.pred.add(p)
+ delete(s.pred, n) // remove edge to n
+ }
+ }
+ delete(p.succ, n) // remove edge to n
+ }
+ }
+ } else {
+ // collect non-function nodes
+ G = append(G, n)
+ }
+ }
+
+ // fill in index and ndeps fields
+ for i, n := range G {
n.index = i
- i++
+ n.ndeps = len(n.succ)
}
return G
}
+// ----------------------------------------------------------------------------
+// Priority queue
+
// nodeQueue implements the container/heap interface;
// a nodeQueue may be used as a priority queue.
-type nodeQueue []*objNode
+type nodeQueue []*graphNode
func (a nodeQueue) Len() int { return len(a) }
@@ -227,7 +281,7 @@ func (a nodeQueue) Less(i, j int) bool {
x, y := a[i], a[j]
// nodes are prioritized by number of incoming dependencies (1st key)
// and source order (2nd key)
- return x.in < y.in || x.in == y.in && x.obj.order() < y.obj.order()
+ return x.ndeps < y.ndeps || x.ndeps == y.ndeps && x.obj.order() < y.obj.order()
}
func (a *nodeQueue) Push(x interface{}) {
diff --git a/src/go/types/object.go b/src/go/types/object.go
index 707b806..6c0c5c4 100644
--- a/src/go/types/object.go
+++ b/src/go/types/object.go
@@ -19,7 +19,7 @@ import (
// All objects implement the Object interface.
//
type Object interface {
- Parent() *Scope // scope in which this object is declared
+ Parent() *Scope // scope in which this object is declared; nil for methods and struct fields
Pos() token.Pos // position of object identifier in declaration
Pkg() *Package // nil for objects in the Universe scope and labels
Name() string // package local object name
@@ -152,6 +152,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.
type TypeName struct {
@@ -184,8 +185,8 @@ func NewField(pos token.Pos, pkg *Package, name string, typ Type, anonymous bool
}
func (obj *Var) Anonymous() bool { return obj.anonymous }
-
-func (obj *Var) IsField() bool { return obj.isField }
+func (obj *Var) IsField() bool { return obj.isField }
+func (*Var) isDependency() {} // a variable may be a dependency of an initialization expression
// A Func represents a declared function, concrete method, or abstract
// (interface) method. Its Type() is always a *Signature.
@@ -211,10 +212,31 @@ func (obj *Func) FullName() string {
return buf.String()
}
-func (obj *Func) Scope() *Scope {
- return obj.typ.(*Signature).scope
+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
@@ -273,6 +295,10 @@ 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
@@ -327,14 +353,15 @@ 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 *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 *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 writeFuncName(buf *bytes.Buffer, f *Func, qf Qualifier) {
if f.typ != nil {
diff --git a/src/go/types/ordering.go b/src/go/types/ordering.go
index 6bb98f2..3579abf 100644
--- a/src/go/types/ordering.go
+++ b/src/go/types/ordering.go
@@ -56,13 +56,9 @@ func (check *Checker) resolveOrder() []Object {
// sort interface types topologically by dependencies,
// and in source order if there are no dependencies
sort.Sort(inSourceOrder(ifaces))
- if debug {
- for _, obj := range ifaces {
- assert(check.objMap[obj].mark == 0)
- }
- }
+ visited := make(objSet)
for _, obj := range ifaces {
- check.appendInPostOrder(&order, obj)
+ check.appendInPostOrder(&order, obj, visited)
}
// sort everything else in source order
@@ -89,25 +85,25 @@ func (check *Checker) interfaceFor(obj Object) *ast.InterfaceType {
return ityp
}
-func (check *Checker) appendInPostOrder(order *[]Object, obj Object) {
- d := check.objMap[obj]
- if d.mark != 0 {
+func (check *Checker) appendInPostOrder(order *[]Object, obj Object, visited objSet) {
+ if visited[obj] {
// We've already seen this object; either because it's
// already added to order, or because we have a cycle.
// In both cases we stop. Cycle errors are reported
// when type-checking types.
return
}
- d.mark = 1
+ visited[obj] = true
+ d := check.objMap[obj]
for _, obj := range orderedSetObjects(d.deps) {
- check.appendInPostOrder(order, obj)
+ check.appendInPostOrder(order, obj, visited)
}
*order = append(*order, obj)
}
-func orderedSetObjects(set map[Object]bool) []Object {
+func orderedSetObjects(set objSet) []Object {
list := make([]Object, len(set))
i := 0
for obj := range set {
diff --git a/src/go/types/predicates.go b/src/go/types/predicates.go
index 5509069..21fd81e 100644
--- a/src/go/types/predicates.go
+++ b/src/go/types/predicates.go
@@ -112,7 +112,12 @@ func hasNil(typ Type) bool {
// Identical reports whether x and y are identical.
func Identical(x, y Type) bool {
- return identical(x, y, nil)
+ return identical(x, y, true, nil)
+}
+
+// IdenticalIgnoreTags reports whether x and y are identical if tags are ignored.
+func IdenticalIgnoreTags(x, y Type) bool {
+ return identical(x, y, false, nil)
}
// An ifacePair is a node in a stack of interface type pairs compared for identity.
@@ -125,7 +130,7 @@ func (p *ifacePair) identical(q *ifacePair) bool {
return p.x == q.x && p.y == q.y || p.x == q.y && p.y == q.x
}
-func identical(x, y Type, p *ifacePair) bool {
+func identical(x, y Type, cmpTags bool, p *ifacePair) bool {
if x == y {
return true
}
@@ -143,13 +148,13 @@ func identical(x, y Type, p *ifacePair) bool {
// Two array types are identical if they have identical element types
// and the same array length.
if y, ok := y.(*Array); ok {
- return x.len == y.len && identical(x.elem, y.elem, p)
+ return x.len == y.len && identical(x.elem, y.elem, cmpTags, p)
}
case *Slice:
// Two slice types are identical if they have identical element types.
if y, ok := y.(*Slice); ok {
- return identical(x.elem, y.elem, p)
+ return identical(x.elem, y.elem, cmpTags, p)
}
case *Struct:
@@ -162,9 +167,9 @@ func identical(x, y Type, p *ifacePair) bool {
for i, f := range x.fields {
g := y.fields[i]
if f.anonymous != g.anonymous ||
- x.Tag(i) != y.Tag(i) ||
+ cmpTags && x.Tag(i) != y.Tag(i) ||
!f.sameId(g.pkg, g.name) ||
- !identical(f.typ, g.typ, p) {
+ !identical(f.typ, g.typ, cmpTags, p) {
return false
}
}
@@ -175,7 +180,7 @@ func identical(x, y Type, p *ifacePair) bool {
case *Pointer:
// Two pointer types are identical if they have identical base types.
if y, ok := y.(*Pointer); ok {
- return identical(x.base, y.base, p)
+ return identical(x.base, y.base, cmpTags, p)
}
case *Tuple:
@@ -186,7 +191,7 @@ func identical(x, y Type, p *ifacePair) bool {
if x != nil {
for i, v := range x.vars {
w := y.vars[i]
- if !identical(v.typ, w.typ, p) {
+ if !identical(v.typ, w.typ, cmpTags, p) {
return false
}
}
@@ -202,8 +207,8 @@ func identical(x, y Type, p *ifacePair) bool {
// names are not required to match.
if y, ok := y.(*Signature); ok {
return x.variadic == y.variadic &&
- identical(x.params, y.params, p) &&
- identical(x.results, y.results, p)
+ identical(x.params, y.params, cmpTags, p) &&
+ identical(x.results, y.results, cmpTags, p)
}
case *Interface:
@@ -249,7 +254,7 @@ func identical(x, y Type, p *ifacePair) bool {
}
for i, f := range a {
g := b[i]
- if f.Id() != g.Id() || !identical(f.typ, g.typ, q) {
+ if f.Id() != g.Id() || !identical(f.typ, g.typ, cmpTags, q) {
return false
}
}
@@ -260,14 +265,14 @@ func identical(x, y Type, p *ifacePair) bool {
case *Map:
// Two map types are identical if they have identical key and value types.
if y, ok := y.(*Map); ok {
- return identical(x.key, y.key, p) && identical(x.elem, y.elem, p)
+ return identical(x.key, y.key, cmpTags, p) && identical(x.elem, y.elem, cmpTags, p)
}
case *Chan:
// Two channel types are identical if they have identical value types
// and the same direction.
if y, ok := y.(*Chan); ok {
- return x.dir == y.dir && identical(x.elem, y.elem, p)
+ return x.dir == y.dir && identical(x.elem, y.elem, cmpTags, p)
}
case *Named:
@@ -286,11 +291,11 @@ func identical(x, y Type, p *ifacePair) bool {
return false
}
-// defaultType returns the default "typed" type for an "untyped" type;
+// Default returns the default "typed" type for an "untyped" type;
// it returns the incoming type for all other types. The default type
// for untyped nil is untyped nil.
//
-func defaultType(typ Type) Type {
+func Default(typ Type) Type {
if t, ok := typ.(*Basic); ok {
switch t.kind {
case UntypedBool:
diff --git a/src/go/types/resolver.go b/src/go/types/resolver.go
index cb8e72e..046e147 100644
--- a/src/go/types/resolver.go
+++ b/src/go/types/resolver.go
@@ -14,18 +14,23 @@ import (
"unicode"
)
-// A declInfo describes a package-level const, type, var, or func declaration.
+// A declInfo describes a package-level const, type, var, func, or alias declaration.
type declInfo struct {
file *Scope // scope of file containing this declaration
lhs []*Var // lhs of n:1 variable declarations, or nil
typ ast.Expr // type, or nil
- init ast.Expr // init expression, or nil
+ init ast.Expr // init/orig expression, or nil
fdecl *ast.FuncDecl // func declaration, or nil
- deps map[Object]bool // type and init dependencies; lazily allocated
- mark int // for dependency analysis
+ // The deps field tracks initialization expression dependencies.
+ // As a special (overloaded) case, it also tracks dependencies of
+ // interface types on embedded interfaces (see ordering.go).
+ deps objSet // lazily initialized
}
+// An objSet is simply a set of objects.
+type objSet map[Object]bool
+
// hasInitializer reports whether the declared object has an initialization
// expression or function body.
func (d *declInfo) hasInitializer() bool {
@@ -36,7 +41,7 @@ func (d *declInfo) hasInitializer() bool {
func (d *declInfo) addDep(obj Object) {
m := d.deps
if m == nil {
- m = make(map[Object]bool)
+ m = make(objSet)
d.deps = m
}
m[obj] = true
@@ -269,6 +274,13 @@ 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:
diff --git a/src/go/types/sizes.go b/src/go/types/sizes.go
index 87c3ce4..3bbe5ae 100644
--- a/src/go/types/sizes.go
+++ b/src/go/types/sizes.go
@@ -64,12 +64,25 @@ func (s *StdSizes) Alignof(T Type) int64 {
}
}
return max
+ case *Slice, *Interface:
+ // Multiword data structures are effectively structs
+ // in which each element has size WordSize.
+ return s.WordSize
+ case *Basic:
+ // Strings are like slices and interfaces.
+ if t.Info()&IsString != 0 {
+ return s.WordSize
+ }
}
a := s.Sizeof(T) // may be 0
// spec: "For a variable x of any type: unsafe.Alignof(x) is at least 1."
if a < 1 {
return 1
}
+ // complex{64,128} are aligned like [2]float{32,64}.
+ if isComplex(T) {
+ a /= 2
+ }
if a > s.MaxAlign {
return s.MaxAlign
}
@@ -132,8 +145,8 @@ func (s *StdSizes) Sizeof(T Type) int64 {
if n == 0 {
return 0
}
- setOffsets(t, s)
- return t.offsets[n-1] + s.Sizeof(t.fields[n-1].typ)
+ offsets := s.Offsetsof(t.fields)
+ return offsets[n-1] + s.Sizeof(t.fields[n-1].typ)
case *Interface:
return s.WordSize * 2
}
@@ -158,22 +171,18 @@ func (conf *Config) offsetsof(T *Struct) []int64 {
if T.NumFields() > 0 {
// compute offsets on demand
if s := conf.Sizes; s != nil {
- calculated := setOffsets(T, s)
- offsets = T.offsets
- if calculated {
- // sanity checks
- if len(offsets) != T.NumFields() {
- panic("Config.Sizes.Offsetsof returned the wrong number of offsets")
- }
- for _, o := range offsets {
- if o < 0 {
- panic("Config.Sizes.Offsetsof returned an offset < 0")
- }
+ offsets = s.Offsetsof(T.fields)
+ // sanity checks
+ if len(offsets) != T.NumFields() {
+ panic("Config.Sizes.Offsetsof returned the wrong number of offsets")
+ }
+ for _, o := range offsets {
+ if o < 0 {
+ panic("Config.Sizes.Offsetsof returned an offset < 0")
}
}
} else {
- setOffsets(T, &stdSizes)
- offsets = T.offsets
+ offsets = stdSizes.Offsetsof(T.fields)
}
}
return offsets
@@ -207,15 +216,3 @@ func align(x, a int64) int64 {
y := x + a - 1
return y - y%a
}
-
-// setOffsets sets the offsets of s for the given sizes if necessary.
-// The result is true if the offsets were not set before; otherwise it
-// is false.
-func setOffsets(s *Struct, sizes Sizes) bool {
- var calculated bool
- s.offsetsOnce.Do(func() {
- calculated = true
- s.offsets = sizes.Offsetsof(s.fields)
- })
- return calculated
-}
diff --git a/src/go/types/sizes_test.go b/src/go/types/sizes_test.go
new file mode 100644
index 0000000..539b4e3
--- /dev/null
+++ b/src/go/types/sizes_test.go
@@ -0,0 +1,112 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file contains tests for sizes.
+
+package types_test
+
+import (
+ "go/ast"
+ "go/importer"
+ "go/parser"
+ "go/token"
+ "go/types"
+ "testing"
+)
+
+// findStructType typechecks src and returns the first struct type encountered.
+func findStructType(t *testing.T, src string) *types.Struct {
+ fset := token.NewFileSet()
+ f, err := parser.ParseFile(fset, "x.go", src, 0)
+ if err != nil {
+ t.Fatal(err)
+ }
+ info := types.Info{Types: make(map[ast.Expr]types.TypeAndValue)}
+ var conf types.Config
+ _, err = conf.Check("x", fset, []*ast.File{f}, &info)
+ if err != nil {
+ t.Fatal(err)
+ }
+ for _, tv := range info.Types {
+ if ts, ok := tv.Type.(*types.Struct); ok {
+ return ts
+ }
+ }
+ t.Fatalf("failed to find a struct type in src:\n%s\n", src)
+ return nil
+}
+
+// Issue 16316
+func TestMultipleSizeUse(t *testing.T) {
+ const src = `
+package main
+
+type S struct {
+ i int
+ b bool
+ s string
+ n int
+}
+`
+ ts := findStructType(t, src)
+ sizes := types.StdSizes{WordSize: 4, MaxAlign: 4}
+ if got := sizes.Sizeof(ts); got != 20 {
+ t.Errorf("Sizeof(%v) with WordSize 4 = %d want 20", ts, got)
+ }
+ sizes = types.StdSizes{WordSize: 8, MaxAlign: 8}
+ if got := sizes.Sizeof(ts); got != 40 {
+ t.Errorf("Sizeof(%v) with WordSize 8 = %d want 40", ts, got)
+ }
+}
+
+// Issue 16464
+func TestAlignofNaclSlice(t *testing.T) {
+ const src = `
+package main
+
+var s struct {
+ x *int
+ y []byte
+}
+`
+ ts := findStructType(t, src)
+ sizes := &types.StdSizes{WordSize: 4, MaxAlign: 8}
+ var fields []*types.Var
+ // Make a copy manually :(
+ for i := 0; i < ts.NumFields(); i++ {
+ fields = append(fields, ts.Field(i))
+ }
+ offsets := sizes.Offsetsof(fields)
+ if offsets[0] != 0 || offsets[1] != 4 {
+ t.Errorf("OffsetsOf(%v) = %v want %v", ts, offsets, []int{0, 4})
+ }
+}
+
+func TestIssue16902(t *testing.T) {
+ const src = `
+package a
+
+import "unsafe"
+
+const _ = unsafe.Offsetof(struct{ x int64 }{}.x)
+`
+ fset := token.NewFileSet()
+ f, err := parser.ParseFile(fset, "x.go", src, 0)
+ if err != nil {
+ t.Fatal(err)
+ }
+ info := types.Info{Types: make(map[ast.Expr]types.TypeAndValue)}
+ conf := types.Config{
+ Importer: importer.Default(),
+ Sizes: &types.StdSizes{WordSize: 8, MaxAlign: 8},
+ }
+ _, err = conf.Check("x", fset, []*ast.File{f}, &info)
+ if err != nil {
+ t.Fatal(err)
+ }
+ for _, tv := range info.Types {
+ _ = conf.Sizes.Sizeof(tv.Type)
+ _ = conf.Sizes.Alignof(tv.Type)
+ }
+}
diff --git a/src/go/types/stdlib_test.go b/src/go/types/stdlib_test.go
index bd5afaf..1c6d7b5 100644
--- a/src/go/types/stdlib_test.go
+++ b/src/go/types/stdlib_test.go
@@ -156,6 +156,7 @@ func TestStdFixed(t *testing.T) {
"issue7746.go", // large constants - consumes too much memory
"issue11362.go", // canonical import path check
"issue15002.go", // uses Mmap; testTestDir should consult build tags
+ "issue16369.go", // go/types handles this correctly - not an issue
)
}
diff --git a/src/go/types/stmt.go b/src/go/types/stmt.go
index 5764430..4e423bd 100644
--- a/src/go/types/stmt.go
+++ b/src/go/types/stmt.go
@@ -68,13 +68,19 @@ func (check *Checker) usage(scope *Scope) {
}
// stmtContext is a bitset describing which
-// control-flow statements are permissible.
+// control-flow statements are permissible,
+// and provides additional context information
+// for better error messages.
type stmtContext uint
const (
+ // permissible control-flow statements
breakOk stmtContext = 1 << iota
continueOk
fallthroughOk
+
+ // additional context information
+ finalSwitchCase
)
func (check *Checker) simpleStmt(s ast.Stmt) {
@@ -292,7 +298,7 @@ func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) {
}(check.scope)
}
- inner := ctxt &^ fallthroughOk
+ inner := ctxt &^ (fallthroughOk | finalSwitchCase)
switch s := s.(type) {
case *ast.BadStmt, *ast.EmptyStmt:
// ignore
@@ -454,7 +460,11 @@ func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) {
}
case token.FALLTHROUGH:
if ctxt&fallthroughOk == 0 {
- check.error(s.Pos(), "fallthrough statement out of place")
+ msg := "fallthrough statement out of place"
+ if ctxt&finalSwitchCase != 0 {
+ msg = "cannot fallthrough final case in switch"
+ }
+ check.error(s.Pos(), msg)
}
default:
check.invalidAST(s.Pos(), "branch statement: %s", s.Tok)
@@ -523,6 +533,8 @@ func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) {
inner := inner
if i+1 < len(s.Body.List) {
inner |= fallthroughOk
+ } else {
+ inner |= finalSwitchCase
}
check.stmtList(inner, clause.Body)
check.closeScope()
@@ -616,9 +628,9 @@ func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) {
T = x.typ
}
obj := NewVar(lhs.Pos(), check.pkg, lhs.Name, T)
- scopePos := clause.End()
- if len(clause.Body) > 0 {
- scopePos = clause.Body[0].Pos()
+ scopePos := clause.Pos() + token.Pos(len("default")) // for default clause (len(List) == 0)
+ if n := len(clause.List); n > 0 {
+ scopePos = clause.List[n-1].End()
}
check.declare(check.scope, nil, obj, scopePos)
check.recordImplicit(clause, obj)
@@ -810,12 +822,12 @@ func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) {
// declare variables
if len(vars) > 0 {
+ scopePos := s.X.End()
for _, obj := range vars {
// spec: "The scope of a constant or variable identifier declared inside
// a function begins at the end of the ConstSpec or VarSpec (ShortVarDecl
// for short variable declarations) and ends at the end of the innermost
// containing block."
- scopePos := s.End()
check.declare(check.scope, nil /* recordDef already called */, obj, scopePos)
}
} else {
diff --git a/src/go/types/testdata/conversions2.src b/src/go/types/testdata/conversions2.src
new file mode 100644
index 0000000..93a5f18
--- /dev/null
+++ b/src/go/types/testdata/conversions2.src
@@ -0,0 +1,313 @@
+// Copyright 2016 The Go 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 various valid and invalid struct assignments and conversions.
+// Does not compile.
+
+package conversions2
+
+type I interface {
+ m()
+}
+
+// conversions between structs
+
+func _() {
+ type S struct{}
+ type T struct{}
+ var s S
+ var t T
+ var u struct{}
+ s = s
+ s = t // ERROR "cannot use .* in assignment"
+ s = u
+ s = S(s)
+ s = S(t)
+ s = S(u)
+ t = u
+ t = T(u)
+}
+
+func _() {
+ type S struct{ x int }
+ type T struct {
+ x int "foo"
+ }
+ var s S
+ var t T
+ var u struct {
+ x int "bar"
+ }
+ s = s
+ s = t // ERROR "cannot use .* in assignment"
+ s = u // ERROR "cannot use .* in assignment"
+ s = S(s)
+ s = S(t)
+ s = S(u)
+ t = u // ERROR "cannot use .* in assignment"
+ t = T(u)
+}
+
+func _() {
+ type E struct{ x int }
+ type S struct{ x E }
+ type T struct {
+ x E "foo"
+ }
+ var s S
+ var t T
+ var u struct {
+ x E "bar"
+ }
+ s = s
+ s = t // ERROR "cannot use .* in assignment"
+ s = u // ERROR "cannot use .* in assignment"
+ s = S(s)
+ s = S(t)
+ s = S(u)
+ t = u // ERROR "cannot use .* in assignment"
+ t = T(u)
+}
+
+func _() {
+ type S struct {
+ x struct {
+ x int "foo"
+ }
+ }
+ type T struct {
+ x struct {
+ x int "bar"
+ } "foo"
+ }
+ var s S
+ var t T
+ var u struct {
+ x struct {
+ x int "bar"
+ } "bar"
+ }
+ s = s
+ s = t // ERROR "cannot use .* in assignment"
+ s = u // ERROR "cannot use .* in assignment"
+ s = S(s)
+ s = S(t)
+ s = S(u)
+ t = u // ERROR "cannot use .* in assignment"
+ t = T(u)
+}
+
+func _() {
+ type E1 struct {
+ x int "foo"
+ }
+ type E2 struct {
+ x int "bar"
+ }
+ type S struct{ x E1 }
+ type T struct {
+ x E2 "foo"
+ }
+ var s S
+ var t T
+ var u struct {
+ x E2 "bar"
+ }
+ s = s
+ s = t // ERROR "cannot use .* in assignment"
+ s = u // ERROR "cannot use .* in assignment"
+ s = S(s)
+ s = S(t /* ERROR "cannot convert" */ )
+ s = S(u /* ERROR "cannot convert" */ )
+ t = u // ERROR "cannot use .* in assignment"
+ t = T(u)
+}
+
+func _() {
+ type E struct{ x int }
+ type S struct {
+ f func(struct {
+ x int "foo"
+ })
+ }
+ type T struct {
+ f func(struct {
+ x int "bar"
+ })
+ }
+ var s S
+ var t T
+ var u struct{ f func(E) }
+ s = s
+ s = t // ERROR "cannot use .* in assignment"
+ s = u // ERROR "cannot use .* in assignment"
+ s = S(s)
+ s = S(t)
+ s = S(u /* ERROR "cannot convert" */ )
+ t = u // ERROR "cannot use .* in assignment"
+ t = T(u /* ERROR "cannot convert" */ )
+}
+
+// conversions between pointers to structs
+
+func _() {
+ type S struct{}
+ type T struct{}
+ var s *S
+ var t *T
+ var u *struct{}
+ s = s
+ s = t // ERROR "cannot use .* in assignment"
+ s = u // ERROR "cannot use .* in assignment"
+ s = (*S)(s)
+ s = (*S)(t)
+ s = (*S)(u)
+ t = u // ERROR "cannot use .* in assignment"
+ t = (*T)(u)
+}
+
+func _() {
+ type S struct{ x int }
+ type T struct {
+ x int "foo"
+ }
+ var s *S
+ var t *T
+ var u *struct {
+ x int "bar"
+ }
+ s = s
+ s = t // ERROR "cannot use .* in assignment"
+ s = u // ERROR "cannot use .* in assignment"
+ s = (*S)(s)
+ s = (*S)(t)
+ s = (*S)(u)
+ t = u // ERROR "cannot use .* in assignment"
+ t = (*T)(u)
+}
+
+func _() {
+ type E struct{ x int }
+ type S struct{ x E }
+ type T struct {
+ x E "foo"
+ }
+ var s *S
+ var t *T
+ var u *struct {
+ x E "bar"
+ }
+ s = s
+ s = t // ERROR "cannot use .* in assignment"
+ s = u // ERROR "cannot use .* in assignment"
+ s = (*S)(s)
+ s = (*S)(t)
+ s = (*S)(u)
+ t = u // ERROR "cannot use .* in assignment"
+ t = (*T)(u)
+}
+
+func _() {
+ type S struct {
+ x struct {
+ x int "foo"
+ }
+ }
+ type T struct {
+ x struct {
+ x int "bar"
+ } "foo"
+ }
+ var s *S
+ var t *T
+ var u *struct {
+ x struct {
+ x int "bar"
+ } "bar"
+ }
+ s = s
+ s = t // ERROR "cannot use .* in assignment"
+ s = u // ERROR "cannot use .* in assignment"
+ s = (*S)(s)
+ s = (*S)(t)
+ s = (*S)(u)
+ t = u // ERROR "cannot use .* in assignment"
+ t = (*T)(u)
+}
+
+func _() {
+ type E1 struct {
+ x int "foo"
+ }
+ type E2 struct {
+ x int "bar"
+ }
+ type S struct{ x E1 }
+ type T struct {
+ x E2 "foo"
+ }
+ var s *S
+ var t *T
+ var u *struct {
+ x E2 "bar"
+ }
+ s = s
+ s = t // ERROR "cannot use .* in assignment"
+ s = u // ERROR "cannot use .* in assignment"
+ s = (*S)(s)
+ s = (*S)(t /* ERROR "cannot convert" */ )
+ s = (*S)(u /* ERROR "cannot convert" */ )
+ t = u // ERROR "cannot use .* in assignment"
+ t = (*T)(u)
+}
+
+func _() {
+ type E struct{ x int }
+ type S struct {
+ f func(struct {
+ x int "foo"
+ })
+ }
+ type T struct {
+ f func(struct {
+ x int "bar"
+ })
+ }
+ var s *S
+ var t *T
+ var u *struct{ f func(E) }
+ s = s
+ s = t // ERROR "cannot use .* in assignment"
+ s = u // ERROR "cannot use .* in assignment"
+ s = (*S)(s)
+ s = (*S)(t)
+ s = (*S)(u /* ERROR "cannot convert" */ )
+ t = u // ERROR "cannot use .* in assignment"
+ t = (*T)(u /* ERROR "cannot convert" */ )
+}
+
+func _() {
+ type E struct{ x int }
+ type S struct {
+ f func(*struct {
+ x int "foo"
+ })
+ }
+ type T struct {
+ f func(*struct {
+ x int "bar"
+ })
+ }
+ var s *S
+ var t *T
+ var u *struct{ f func(E) }
+ s = s
+ s = t // ERROR "cannot use .* in assignment"
+ s = u // ERROR "cannot use .* in assignment"
+ s = (*S)(s)
+ s = (*S)(t)
+ s = (*S)(u /* ERROR "cannot convert" */ )
+ t = u // ERROR "cannot use .* in assignment"
+ t = (*T)(u /* ERROR "cannot convert" */ )
+}
diff --git a/src/go/types/testdata/expr3.src b/src/go/types/testdata/expr3.src
index 53c03e7..ab1a9f6 100644
--- a/src/go/types/testdata/expr3.src
+++ b/src/go/types/testdata/expr3.src
@@ -324,6 +324,22 @@ func slice_literals() {
// recursively so
_ = [][]T{{}, []T{{}}, {{1, 2, 3}}}
+
+ // issue 17954
+ type T0 *struct { s string }
+ _ = []T0{{}}
+ _ = []T0{{"foo"}}
+
+ type T1 *struct{ int }
+ _ = []T1{}
+ _ = []T1{{0}, {1}, {2}}
+
+ type T2 T1
+ _ = []T2{}
+ _ = []T2{{0}, {1}, {2}}
+
+ _ = map[T0]T2{}
+ _ = map[T0]T2{{}: {}}
}
const index2 int = 2
@@ -393,6 +409,14 @@ func map_literals() {
type Point struct { x, y float32 }
_ = map[string]Point{"orig": {0, 0}}
_ = map[*Point]string{{0, 0}: "orig"}
+
+ // issue 17954
+ type T0 *struct{ s string }
+ type T1 *struct{ int }
+ type T2 T1
+
+ _ = map[T0]T2{}
+ _ = map[T0]T2{{}: {}}
}
var key2 string = "bar"
diff --git a/src/go/types/testdata/stmt0.src b/src/go/types/testdata/stmt0.src
index 0c727c3..87f08e4 100644
--- a/src/go/types/testdata/stmt0.src
+++ b/src/go/types/testdata/stmt0.src
@@ -536,7 +536,7 @@ func switches1() {
default:
fallthrough; ;
case 4:
- fallthrough /* ERROR "fallthrough statement out of place" */
+ fallthrough /* ERROR "cannot fallthrough final case in switch" */
}
var y interface{}
@@ -573,7 +573,7 @@ func switches1() {
goto L6
goto L7
goto L8
- L6: L7: L8: fallthrough /* ERROR "fallthrough statement out of place" */
+ L6: L7: L8: fallthrough /* ERROR "cannot fallthrough final case in switch" */
}
switch x {
@@ -589,6 +589,14 @@ func switches1() {
fallthrough /* ERROR "fallthrough statement out of place" */
{ /* empty block is not an empty statement */ }; ;
default:
+ fallthrough /* ERROR "cannot fallthrough final case in switch" */
+ }
+
+ switch x {
+ case 0:
+ {
+ fallthrough /* ERROR "fallthrough statement out of place" */
+ }
}
}
diff --git a/src/go/types/type.go b/src/go/types/type.go
index 4e00da3..01adee8 100644
--- a/src/go/types/type.go
+++ b/src/go/types/type.go
@@ -4,10 +4,7 @@
package types
-import (
- "sort"
- "sync"
-)
+import "sort"
// A Type represents a type of Go.
// All types implement the Type interface.
@@ -121,10 +118,8 @@ func (s *Slice) Elem() Type { return s.elem }
// A Struct represents a struct type.
type Struct struct {
- fields []*Var
- tags []string // field tags; nil if there are no tags
- offsets []int64 // field offsets in bytes, lazily initialized
- offsetsOnce sync.Once // for threadsafe lazy initialization of offsets
+ fields []*Var
+ tags []string // field tags; nil if there are no tags
}
// NewStruct returns a new struct with the given fields and corresponding field tags.
diff --git a/src/go/types/typexpr.go b/src/go/types/typexpr.go
index 931b924..ecc0a7d 100644
--- a/src/go/types/typexpr.go
+++ b/src/go/types/typexpr.go
@@ -45,6 +45,17 @@ 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)
@@ -623,8 +634,7 @@ func (check *Checker) structType(styp *Struct, e *ast.StructType, path []*TypeNa
// current field typ and tag
var typ Type
var tag string
- // anonymous != nil indicates an anonymous field.
- add := func(field *ast.Field, ident *ast.Ident, anonymous *TypeName, pos token.Pos) {
+ add := func(field *ast.Field, ident *ast.Ident, anonymous bool, pos token.Pos) {
if tag != "" && tags == nil {
tags = make([]string, len(fields))
}
@@ -633,15 +643,12 @@ func (check *Checker) structType(styp *Struct, e *ast.StructType, path []*TypeNa
}
name := ident.Name
- fld := NewField(pos, check.pkg, name, typ, anonymous != nil)
+ fld := NewField(pos, check.pkg, name, typ, anonymous)
// spec: "Within a struct, non-blank field names must be unique."
if name == "_" || check.declareInSet(&fset, pos, fld) {
fields = append(fields, fld)
check.recordDef(ident, fld)
}
- if anonymous != nil {
- check.recordUse(ident, anonymous)
- }
}
for _, f := range list.List {
@@ -650,7 +657,7 @@ 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, nil, name.Pos())
+ add(f, name, false, name.Pos())
}
} else {
// anonymous field
@@ -668,7 +675,7 @@ func (check *Checker) structType(styp *Struct, e *ast.StructType, path []*TypeNa
check.errorf(pos, "anonymous field type cannot be unsafe.Pointer")
continue
}
- add(f, name, Universe.Lookup(t.name).(*TypeName), pos)
+ add(f, name, true, pos)
case *Named:
// spec: "An embedded type must be specified as a type name
@@ -690,7 +697,7 @@ func (check *Checker) structType(styp *Struct, e *ast.StructType, path []*TypeNa
continue
}
}
- add(f, name, t.obj, pos)
+ add(f, name, true, pos)
default:
check.invalidAST(pos, "anonymous field type %s must be named", typ)
diff --git a/src/hash/crc32/crc32.go b/src/hash/crc32/crc32.go
index c3ac7b8..8aa91b1 100644
--- a/src/hash/crc32/crc32.go
+++ b/src/hash/crc32/crc32.go
@@ -20,9 +20,6 @@ import (
// The size of a CRC-32 checksum in bytes.
const Size = 4
-// Use "slice by 8" when payload >= this value.
-const sliceBy8Cutoff = 16
-
// Predefined polynomials.
const (
// IEEE is by far and away the most common CRC-32 polynomial.
@@ -43,71 +40,96 @@ const (
// Table is a 256-word table representing the polynomial for efficient processing.
type Table [256]uint32
+// This file makes use of functions implemented in architecture-specific files.
+// The interface that they implement is as follows:
+//
+// // archAvailableIEEE reports whether an architecture-specific CRC32-IEEE
+// // algorithm is available.
+// archAvailableIEEE() bool
+//
+// // archInitIEEE initializes the architecture-specific CRC3-IEEE algorithm.
+// // It can only be called if archAvailableIEEE() returns true.
+// archInitIEEE()
+//
+// // archUpdateIEEE updates the given CRC32-IEEE. It can only be called if
+// // archInitIEEE() was previously called.
+// archUpdateIEEE(crc uint32, p []byte) uint32
+//
+// // archAvailableCastagnoli reports whether an architecture-specific
+// // CRC32-C algorithm is available.
+// archAvailableCastagnoli() bool
+//
+// // archInitCastagnoli initializes the architecture-specific CRC32-C
+// // algorithm. It can only be called if archAvailableCastagnoli() returns
+// // true.
+// archInitCastagnoli()
+//
+// // archUpdateCastagnoli updates the given CRC32-C. It can only be called
+// // if archInitCastagnoli() was previously called.
+// archUpdateCastagnoli(crc uint32, p []byte) uint32
+
// castagnoliTable points to a lazily initialized Table for the Castagnoli
// polynomial. MakeTable will always return this value when asked to make a
// Castagnoli table so we can compare against it to find when the caller is
// using this polynomial.
var castagnoliTable *Table
var castagnoliTable8 *slicing8Table
+var castagnoliArchImpl bool
+var updateCastagnoli func(crc uint32, p []byte) uint32
var castagnoliOnce sync.Once
func castagnoliInit() {
- castagnoliTable = makeTable(Castagnoli)
- castagnoliTable8 = makeTable8(Castagnoli)
+ castagnoliTable = simpleMakeTable(Castagnoli)
+ castagnoliArchImpl = archAvailableCastagnoli()
+
+ if castagnoliArchImpl {
+ archInitCastagnoli()
+ updateCastagnoli = archUpdateCastagnoli
+ } else {
+ // Initialize the slicing-by-8 table.
+ castagnoliTable8 = slicingMakeTable(Castagnoli)
+ updateCastagnoli = func(crc uint32, p []byte) uint32 {
+ return slicingUpdate(crc, castagnoliTable8, p)
+ }
+ }
}
// IEEETable is the table for the IEEE polynomial.
-var IEEETable = makeTable(IEEE)
-
-// slicing8Table is array of 8 Tables
-type slicing8Table [8]Table
+var IEEETable = simpleMakeTable(IEEE)
// ieeeTable8 is the slicing8Table for IEEE
var ieeeTable8 *slicing8Table
-var ieeeTable8Once sync.Once
+var ieeeArchImpl bool
+var updateIEEE func(crc uint32, p []byte) uint32
+var ieeeOnce sync.Once
+
+func ieeeInit() {
+ ieeeArchImpl = archAvailableIEEE()
+
+ if ieeeArchImpl {
+ archInitIEEE()
+ updateIEEE = archUpdateIEEE
+ } else {
+ // Initialize the slicing-by-8 table.
+ ieeeTable8 = slicingMakeTable(IEEE)
+ updateIEEE = func(crc uint32, p []byte) uint32 {
+ return slicingUpdate(crc, ieeeTable8, p)
+ }
+ }
+}
// MakeTable returns a Table constructed from the specified polynomial.
// The contents of this Table must not be modified.
func MakeTable(poly uint32) *Table {
switch poly {
case IEEE:
+ ieeeOnce.Do(ieeeInit)
return IEEETable
case Castagnoli:
castagnoliOnce.Do(castagnoliInit)
return castagnoliTable
}
- return makeTable(poly)
-}
-
-// makeTable returns the Table constructed from the specified polynomial.
-func makeTable(poly uint32) *Table {
- t := new(Table)
- for i := 0; i < 256; i++ {
- crc := uint32(i)
- for j := 0; j < 8; j++ {
- if crc&1 == 1 {
- crc = (crc >> 1) ^ poly
- } else {
- crc >>= 1
- }
- }
- t[i] = crc
- }
- return t
-}
-
-// makeTable8 returns slicing8Table constructed from the specified polynomial.
-func makeTable8(poly uint32) *slicing8Table {
- t := new(slicing8Table)
- t[0] = *makeTable(poly)
- for i := 0; i < 256; i++ {
- crc := t[0][i]
- for j := 1; j < 8; j++ {
- crc = t[0][crc&0xFF] ^ (crc >> 8)
- t[j][i] = crc
- }
- }
- return t
+ return simpleMakeTable(poly)
}
// digest represents the partial evaluation of a checksum.
@@ -119,7 +141,12 @@ type digest struct {
// New creates a new hash.Hash32 computing the CRC-32 checksum
// using the polynomial represented by the Table.
// Its Sum method will lay the value out in big-endian byte order.
-func New(tab *Table) hash.Hash32 { return &digest{0, tab} }
+func New(tab *Table) hash.Hash32 {
+ if tab == IEEETable {
+ ieeeOnce.Do(ieeeInit)
+ }
+ return &digest{0, tab}
+}
// NewIEEE creates a new hash.Hash32 computing the CRC-32 checksum
// using the IEEE polynomial.
@@ -132,44 +159,32 @@ func (d *digest) BlockSize() int { return 1 }
func (d *digest) Reset() { d.crc = 0 }
-func update(crc uint32, tab *Table, p []byte) uint32 {
- crc = ^crc
- for _, v := range p {
- crc = tab[byte(crc)^v] ^ (crc >> 8)
- }
- return ^crc
-}
-
-// updateSlicingBy8 updates CRC using Slicing-by-8
-func updateSlicingBy8(crc uint32, tab *slicing8Table, p []byte) uint32 {
- crc = ^crc
- for len(p) > 8 {
- crc ^= uint32(p[0]) | uint32(p[1])<<8 | uint32(p[2])<<16 | uint32(p[3])<<24
- crc = tab[0][p[7]] ^ tab[1][p[6]] ^ tab[2][p[5]] ^ tab[3][p[4]] ^
- tab[4][crc>>24] ^ tab[5][(crc>>16)&0xFF] ^
- tab[6][(crc>>8)&0xFF] ^ tab[7][crc&0xFF]
- p = p[8:]
- }
- crc = ^crc
- if len(p) == 0 {
- return crc
- }
- return update(crc, &tab[0], p)
-}
-
// Update returns the result of adding the bytes in p to the crc.
func Update(crc uint32, tab *Table, p []byte) uint32 {
switch tab {
case castagnoliTable:
return updateCastagnoli(crc, p)
case IEEETable:
+ // Unfortunately, because IEEETable is exported, IEEE may be used without a
+ // call to MakeTable. We have to make sure it gets initialized in that case.
+ ieeeOnce.Do(ieeeInit)
return updateIEEE(crc, p)
+ default:
+ return simpleUpdate(crc, tab, p)
}
- return update(crc, tab, p)
}
func (d *digest) Write(p []byte) (n int, err error) {
- d.crc = Update(d.crc, d.tab, p)
+ switch d.tab {
+ case castagnoliTable:
+ d.crc = updateCastagnoli(d.crc, p)
+ case IEEETable:
+ // We only create digest objects through New() which takes care of
+ // initialization in this case.
+ d.crc = updateIEEE(d.crc, p)
+ default:
+ d.crc = simpleUpdate(d.crc, d.tab, p)
+ }
return len(p), nil
}
@@ -186,4 +201,7 @@ func Checksum(data []byte, tab *Table) uint32 { return Update(0, tab, data) }
// ChecksumIEEE returns the CRC-32 checksum of data
// using the IEEE polynomial.
-func ChecksumIEEE(data []byte) uint32 { return updateIEEE(0, data) }
+func ChecksumIEEE(data []byte) uint32 {
+ ieeeOnce.Do(ieeeInit)
+ return updateIEEE(0, data)
+}
diff --git a/src/hash/crc32/crc32_amd64.go b/src/hash/crc32/crc32_amd64.go
index a0180a1..369a436 100644
--- a/src/hash/crc32/crc32_amd64.go
+++ b/src/hash/crc32/crc32_amd64.go
@@ -2,8 +2,14 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// AMD64-specific hardware-assisted CRC32 algorithms. See crc32.go for a
+// description of the interface that each architecture-specific file
+// implements.
+
package crc32
+import "unsafe"
+
// This file contains the code to call the SSE 4.2 version of the Castagnoli
// and IEEE CRC.
@@ -13,11 +19,20 @@ func haveSSE41() bool
func haveSSE42() bool
func haveCLMUL() bool
-// castagnoliSSE42 is defined in crc_amd64.s and uses the SSE4.2 CRC32
+// castagnoliSSE42 is defined in crc32_amd64.s and uses the SSE4.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
+// instruction.
+//go:noescape
+func castagnoliSSE42Triple(
+ crcA, crcB, crcC uint32,
+ a, b, c []byte,
+ rounds uint32,
+) (retA uint32, retB uint32, retC uint32)
+
// ieeeCLMUL is defined in crc_amd64.s and uses the PCLMULQDQ
// instruction as well as SSE 4.1.
//go:noescape
@@ -26,35 +41,188 @@ func ieeeCLMUL(crc uint32, p []byte) uint32
var sse42 = haveSSE42()
var useFastIEEE = haveCLMUL() && haveSSE41()
-func updateCastagnoli(crc uint32, p []byte) uint32 {
- if sse42 {
- return castagnoliSSE42(crc, p)
+const castagnoliK1 = 168
+const castagnoliK2 = 1344
+
+type sse42Table [4]Table
+
+var castagnoliSSE42TableK1 *sse42Table
+var castagnoliSSE42TableK2 *sse42Table
+
+func archAvailableCastagnoli() bool {
+ return sse42
+}
+
+func archInitCastagnoli() {
+ if !sse42 {
+ panic("arch-specific Castagnoli not available")
}
- // Use slicing-by-8 on larger inputs.
- if len(p) >= sliceBy8Cutoff {
- return updateSlicingBy8(crc, castagnoliTable8, p)
+ castagnoliSSE42TableK1 = new(sse42Table)
+ castagnoliSSE42TableK2 = new(sse42Table)
+ // See description in updateCastagnoli.
+ // t[0][i] = CRC(i000, O)
+ // t[1][i] = CRC(0i00, O)
+ // t[2][i] = CRC(00i0, O)
+ // t[3][i] = CRC(000i, O)
+ // where O is a sequence of K zeros.
+ var tmp [castagnoliK2]byte
+ for b := 0; b < 4; b++ {
+ for i := 0; i < 256; i++ {
+ val := uint32(i) << uint32(b*8)
+ castagnoliSSE42TableK1[b][i] = castagnoliSSE42(val, tmp[:castagnoliK1])
+ castagnoliSSE42TableK2[b][i] = castagnoliSSE42(val, tmp[:])
+ }
}
- return update(crc, castagnoliTable, p)
}
-func updateIEEE(crc uint32, p []byte) uint32 {
- if useFastIEEE && len(p) >= 64 {
- left := len(p) & 15
- do := len(p) - left
- crc = ^ieeeCLMUL(^crc, p[:do])
- if left > 0 {
- crc = update(crc, IEEETable, p[do:])
+// castagnoliShift computes the CRC32-C of K1 or K2 zeroes (depending on the
+// table given) with the given initial crc value. This corresponds to
+// CRC(crc, O) in the description in updateCastagnoli.
+func castagnoliShift(table *sse42Table, crc uint32) uint32 {
+ return table[3][crc>>24] ^
+ table[2][(crc>>16)&0xFF] ^
+ table[1][(crc>>8)&0xFF] ^
+ table[0][crc&0xFF]
+}
+
+func archUpdateCastagnoli(crc uint32, p []byte) uint32 {
+ if !sse42 {
+ panic("not available")
+ }
+
+ // This method is inspired from the algorithm in Intel's white paper:
+ // "Fast CRC Computation for iSCSI Polynomial Using CRC32 Instruction"
+ // The same strategy of splitting the buffer in three is used but the
+ // combining calculation is different; the complete derivation is explained
+ // below.
+ //
+ // -- The basic idea --
+ //
+ // The CRC32 instruction (available in SSE4.2) can process 8 bytes at a
+ // time. In recent Intel architectures the instruction takes 3 cycles;
+ // however the processor can pipeline up to three instructions if they
+ // don't depend on each other.
+ //
+ // Roughly this means that we can process three buffers in about the same
+ // time we can process one buffer.
+ //
+ // The idea is then to split the buffer in three, CRC the three pieces
+ // separately and then combine the results.
+ //
+ // Combining the results requires precomputed tables, so we must choose a
+ // fixed buffer length to optimize. The longer the length, the faster; but
+ // only buffers longer than this length will use the optimization. We choose
+ // two cutoffs and compute tables for both:
+ // - one around 512: 168*3=504
+ // - one around 4KB: 1344*3=4032
+ //
+ // -- The nitty gritty --
+ //
+ // Let CRC(I, X) be the non-inverted CRC32-C of the sequence X (with
+ // initial non-inverted CRC I). This function has the following properties:
+ // (a) CRC(I, AB) = CRC(CRC(I, A), B)
+ // (b) CRC(I, A xor B) = CRC(I, A) xor CRC(0, B)
+ //
+ // Say we want to compute CRC(I, ABC) where A, B, C are three sequences of
+ // K bytes each, where K is a fixed constant. Let O be the sequence of K zero
+ // bytes.
+ //
+ // CRC(I, ABC) = CRC(I, ABO xor C)
+ // = CRC(I, ABO) xor CRC(0, C)
+ // = CRC(CRC(I, AB), O) xor CRC(0, C)
+ // = CRC(CRC(I, AO xor B), O) xor CRC(0, C)
+ // = CRC(CRC(I, AO) xor CRC(0, B), O) xor CRC(0, C)
+ // = CRC(CRC(CRC(I, A), O) xor CRC(0, B), O) xor CRC(0, C)
+ //
+ // The castagnoliSSE42Triple function can compute CRC(I, A), CRC(0, B),
+ // and CRC(0, C) efficiently. We just need to find a way to quickly compute
+ // CRC(uvwx, O) given a 4-byte initial value uvwx. We can precompute these
+ // values; since we can't have a 32-bit table, we break it up into four
+ // 8-bit tables:
+ //
+ // CRC(uvwx, O) = CRC(u000, O) xor
+ // CRC(0v00, O) xor
+ // CRC(00w0, O) xor
+ // CRC(000x, O)
+ //
+ // We can compute tables corresponding to the four terms for all 8-bit
+ // values.
+
+ crc = ^crc
+
+ // If a buffer is long enough to use the optimization, process the first few
+ // bytes to align the buffer to an 8 byte boundary (if necessary).
+ if len(p) >= castagnoliK1*3 {
+ delta := int(uintptr(unsafe.Pointer(&p[0])) & 7)
+ if delta != 0 {
+ delta = 8 - delta
+ crc = castagnoliSSE42(crc, p[:delta])
+ p = p[delta:]
}
- return crc
}
- // Use slicing-by-8 on larger inputs.
- if len(p) >= sliceBy8Cutoff {
- ieeeTable8Once.Do(func() {
- ieeeTable8 = makeTable8(IEEE)
- })
- return updateSlicingBy8(crc, ieeeTable8, p)
+ // Process 3*K2 at a time.
+ for len(p) >= castagnoliK2*3 {
+ // Compute CRC(I, A), CRC(0, B), and CRC(0, C).
+ crcA, crcB, crcC := castagnoliSSE42Triple(
+ crc, 0, 0,
+ p, p[castagnoliK2:], p[castagnoliK2*2:],
+ castagnoliK2/24)
+
+ // CRC(I, AB) = CRC(CRC(I, A), O) xor CRC(0, B)
+ crcAB := castagnoliShift(castagnoliSSE42TableK2, crcA) ^ crcB
+ // CRC(I, ABC) = CRC(CRC(I, AB), O) xor CRC(0, C)
+ crc = castagnoliShift(castagnoliSSE42TableK2, crcAB) ^ crcC
+ p = p[castagnoliK2*3:]
+ }
+
+ // Process 3*K1 at a time.
+ for len(p) >= castagnoliK1*3 {
+ // Compute CRC(I, A), CRC(0, B), and CRC(0, C).
+ crcA, crcB, crcC := castagnoliSSE42Triple(
+ crc, 0, 0,
+ p, p[castagnoliK1:], p[castagnoliK1*2:],
+ castagnoliK1/24)
+
+ // CRC(I, AB) = CRC(CRC(I, A), O) xor CRC(0, B)
+ crcAB := castagnoliShift(castagnoliSSE42TableK1, crcA) ^ crcB
+ // CRC(I, ABC) = CRC(CRC(I, AB), O) xor CRC(0, C)
+ crc = castagnoliShift(castagnoliSSE42TableK1, crcAB) ^ crcC
+ p = p[castagnoliK1*3:]
+ }
+
+ // Use the simple implementation for what's left.
+ crc = castagnoliSSE42(crc, p)
+ return ^crc
+}
+
+func archAvailableIEEE() bool {
+ return useFastIEEE
+}
+
+var archIeeeTable8 *slicing8Table
+
+func archInitIEEE() {
+ if !useFastIEEE {
+ panic("not available")
}
+ // We still use slicing-by-8 for small buffers.
+ archIeeeTable8 = slicingMakeTable(IEEE)
+}
- return update(crc, IEEETable, p)
+func archUpdateIEEE(crc uint32, p []byte) uint32 {
+ if !useFastIEEE {
+ panic("not available")
+ }
+
+ if len(p) >= 64 {
+ left := len(p) & 15
+ do := len(p) - left
+ crc = ^ieeeCLMUL(^crc, p[:do])
+ p = p[do:]
+ }
+ if len(p) == 0 {
+ return crc
+ }
+ return slicingUpdate(crc, archIeeeTable8, p)
}
diff --git a/src/hash/crc32/crc32_amd64.s b/src/hash/crc32/crc32_amd64.s
index caacfae..50c0ec8 100644
--- a/src/hash/crc32/crc32_amd64.s
+++ b/src/hash/crc32/crc32_amd64.s
@@ -4,54 +4,136 @@
#include "textflag.h"
+// castagnoliSSE42 updates the (non-inverted) crc with the given buffer.
+//
// func castagnoliSSE42(crc uint32, p []byte) uint32
TEXT ·castagnoliSSE42(SB),NOSPLIT,$0
MOVL crc+0(FP), AX // CRC value
MOVQ p+8(FP), SI // data pointer
MOVQ p_len+16(FP), CX // len(p)
- NOTL AX
-
- /* If there's less than 8 bytes to process, we do it byte-by-byte. */
+ // If there are fewer than 8 bytes to process, skip alignment.
CMPQ CX, $8
- JL cleanup
+ JL less_than_8
- /* Process individual bytes until the input is 8-byte aligned. */
-startup:
MOVQ SI, BX
ANDQ $7, BX
JZ aligned
+ // Process the first few bytes to 8-byte align the input.
+
+ // BX = 8 - BX. We need to process this many bytes to align.
+ SUBQ $1, BX
+ XORQ $7, BX
+
+ BTQ $0, BX
+ JNC align_2
+
CRC32B (SI), AX
DECQ CX
INCQ SI
- JMP startup
+
+align_2:
+ BTQ $1, BX
+ JNC align_4
+
+ // CRC32W (SI), AX
+ BYTE $0x66; BYTE $0xf2; BYTE $0x0f; BYTE $0x38; BYTE $0xf1; BYTE $0x06
+
+ SUBQ $2, CX
+ ADDQ $2, SI
+
+align_4:
+ BTQ $2, BX
+ JNC aligned
+
+ // CRC32L (SI), AX
+ BYTE $0xf2; BYTE $0x0f; BYTE $0x38; BYTE $0xf1; BYTE $0x06
+
+ SUBQ $4, CX
+ ADDQ $4, SI
aligned:
- /* The input is now 8-byte aligned and we can process 8-byte chunks. */
+ // The input is now 8-byte aligned and we can process 8-byte chunks.
CMPQ CX, $8
- JL cleanup
+ JL less_than_8
CRC32Q (SI), AX
ADDQ $8, SI
SUBQ $8, CX
JMP aligned
-cleanup:
- /* We may have some bytes left over that we process one at a time. */
- CMPQ CX, $0
- JE done
+less_than_8:
+ // We may have some bytes left over; process 4 bytes, then 2, then 1.
+ BTQ $2, CX
+ JNC less_than_4
+
+ // CRC32L (SI), AX
+ BYTE $0xf2; BYTE $0x0f; BYTE $0x38; BYTE $0xf1; BYTE $0x06
+ ADDQ $4, SI
+
+less_than_4:
+ BTQ $1, CX
+ JNC less_than_2
+
+ // CRC32W (SI), AX
+ BYTE $0x66; BYTE $0xf2; BYTE $0x0f; BYTE $0x38; BYTE $0xf1; BYTE $0x06
+ ADDQ $2, SI
+
+less_than_2:
+ BTQ $0, CX
+ JNC done
CRC32B (SI), AX
- INCQ SI
- DECQ CX
- JMP cleanup
done:
- NOTL AX
MOVL AX, ret+32(FP)
RET
+// castagnoliSSE42Triple updates three (non-inverted) crcs with (24*rounds)
+// bytes from each buffer.
+//
+// func castagnoliSSE42Triple(
+// crc1, crc2, crc3 uint32,
+// a, b, c []byte,
+// rounds uint32,
+// ) (retA uint32, retB uint32, retC uint32)
+TEXT ·castagnoliSSE42Triple(SB),NOSPLIT,$0
+ MOVL crcA+0(FP), AX
+ MOVL crcB+4(FP), CX
+ MOVL crcC+8(FP), DX
+
+ MOVQ a+16(FP), R8 // data pointer
+ MOVQ b+40(FP), R9 // data pointer
+ MOVQ c+64(FP), R10 // data pointer
+
+ MOVL rounds+88(FP), R11
+
+loop:
+ CRC32Q (R8), AX
+ CRC32Q (R9), CX
+ CRC32Q (R10), DX
+
+ CRC32Q 8(R8), AX
+ CRC32Q 8(R9), CX
+ CRC32Q 8(R10), DX
+
+ CRC32Q 16(R8), AX
+ CRC32Q 16(R9), CX
+ CRC32Q 16(R10), DX
+
+ ADDQ $24, R8
+ ADDQ $24, R9
+ ADDQ $24, R10
+
+ DECQ R11
+ JNZ loop
+
+ MOVL AX, retA+96(FP)
+ MOVL CX, retB+100(FP)
+ MOVL DX, retC+104(FP)
+ RET
+
// func haveSSE42() bool
TEXT ·haveSSE42(SB),NOSPLIT,$0
XORQ AX, AX
diff --git a/src/hash/crc32/crc32_amd64p32.go b/src/hash/crc32/crc32_amd64p32.go
index 1f6cd34..9d728fc 100644
--- a/src/hash/crc32/crc32_amd64p32.go
+++ b/src/hash/crc32/crc32_amd64p32.go
@@ -7,36 +7,35 @@ package crc32
// This file contains the code to call the SSE 4.2 version of the Castagnoli
// CRC.
-// haveSSE42 is defined in crc_amd64p32.s and uses CPUID to test for SSE 4.2
+// haveSSE42 is defined in crc32_amd64p32.s and uses CPUID to test for SSE 4.2
// support.
func haveSSE42() bool
-// castagnoliSSE42 is defined in crc_amd64.s and uses the SSE4.2 CRC32
+// 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 updateCastagnoli(crc uint32, p []byte) uint32 {
- if sse42 {
- return castagnoliSSE42(crc, p)
- }
- // Use slicing-by-8 on larger inputs.
- if len(p) >= sliceBy8Cutoff {
- return updateSlicingBy8(crc, castagnoliTable8, p)
- }
- return update(crc, castagnoliTable, p)
+func archAvailableCastagnoli() bool {
+ return sse42
}
-func updateIEEE(crc uint32, p []byte) uint32 {
- // Use slicing-by-8 on larger inputs.
- if len(p) >= sliceBy8Cutoff {
- ieeeTable8Once.Do(func() {
- ieeeTable8 = makeTable8(IEEE)
- })
- return updateSlicingBy8(crc, ieeeTable8, p)
+func archInitCastagnoli() {
+ if !sse42 {
+ panic("not available")
}
+ // No initialization necessary.
+}
- return update(crc, IEEETable, p)
+func archUpdateCastagnoli(crc uint32, p []byte) uint32 {
+ if !sse42 {
+ panic("not available")
+ }
+ return castagnoliSSE42(crc, p)
}
+
+func archAvailableIEEE() bool { return false }
+func archInitIEEE() { panic("not available") }
+func archUpdateIEEE(crc uint32, p []byte) uint32 { panic("not available") }
diff --git a/src/hash/crc32/crc32_generic.go b/src/hash/crc32/crc32_generic.go
index 10a6367..abacbb6 100644
--- a/src/hash/crc32/crc32_generic.go
+++ b/src/hash/crc32/crc32_generic.go
@@ -2,28 +2,88 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build !amd64,!amd64p32,!s390x
+// This file contains CRC32 algorithms that are not specific to any architecture
+// and don't use hardware acceleration.
+//
+// The simple (and slow) CRC32 implementation only uses a 256*4 bytes table.
+//
+// The slicing-by-8 algorithm is a faster implementation that uses a bigger
+// table (8*256*4 bytes).
package crc32
-// This file contains the generic version of updateCastagnoli which does
-// slicing-by-8, or uses the fallback for very small sizes.
+// simpleMakeTable allocates and constructs a Table for the specified
+// polynomial. The table is suitable for use with the simple algorithm
+// (simpleUpdate).
+func simpleMakeTable(poly uint32) *Table {
+ t := new(Table)
+ simplePopulateTable(poly, t)
+ return t
+}
+
+// simplePopulateTable constructs a Table for the specified polynomial, suitable
+// for use with simpleUpdate.
+func simplePopulateTable(poly uint32, t *Table) {
+ for i := 0; i < 256; i++ {
+ crc := uint32(i)
+ for j := 0; j < 8; j++ {
+ if crc&1 == 1 {
+ crc = (crc >> 1) ^ poly
+ } else {
+ crc >>= 1
+ }
+ }
+ t[i] = crc
+ }
+}
+
+// simpleUpdate uses the simple algorithm to update the CRC, given a table that
+// was previously computed using simpleMakeTable.
+func simpleUpdate(crc uint32, tab *Table, p []byte) uint32 {
+ crc = ^crc
+ for _, v := range p {
+ crc = tab[byte(crc)^v] ^ (crc >> 8)
+ }
+ return ^crc
+}
+
+// Use slicing-by-8 when payload >= this value.
+const slicing8Cutoff = 16
-func updateCastagnoli(crc uint32, p []byte) uint32 {
- // Use slicing-by-8 on larger inputs.
- if len(p) >= sliceBy8Cutoff {
- return updateSlicingBy8(crc, castagnoliTable8, p)
+// slicing8Table is array of 8 Tables, used by the slicing-by-8 algorithm.
+type slicing8Table [8]Table
+
+// slicingMakeTable constructs a slicing8Table for the specified polynomial. The
+// table is suitable for use with the slicing-by-8 algorithm (slicingUpdate).
+func slicingMakeTable(poly uint32) *slicing8Table {
+ t := new(slicing8Table)
+ simplePopulateTable(poly, &t[0])
+ for i := 0; i < 256; i++ {
+ crc := t[0][i]
+ for j := 1; j < 8; j++ {
+ crc = t[0][crc&0xFF] ^ (crc >> 8)
+ t[j][i] = crc
+ }
}
- return update(crc, castagnoliTable, p)
+ return t
}
-func updateIEEE(crc uint32, p []byte) uint32 {
- // Use slicing-by-8 on larger inputs.
- if len(p) >= sliceBy8Cutoff {
- ieeeTable8Once.Do(func() {
- ieeeTable8 = makeTable8(IEEE)
- })
- return updateSlicingBy8(crc, ieeeTable8, p)
+// slicingUpdate uses the slicing-by-8 algorithm to update the CRC, given a
+// table that was previously computed using slicingMakeTable.
+func slicingUpdate(crc uint32, tab *slicing8Table, p []byte) uint32 {
+ if len(p) >= slicing8Cutoff {
+ crc = ^crc
+ for len(p) > 8 {
+ crc ^= uint32(p[0]) | uint32(p[1])<<8 | uint32(p[2])<<16 | uint32(p[3])<<24
+ crc = tab[0][p[7]] ^ tab[1][p[6]] ^ tab[2][p[5]] ^ tab[3][p[4]] ^
+ tab[4][crc>>24] ^ tab[5][(crc>>16)&0xFF] ^
+ tab[6][(crc>>8)&0xFF] ^ tab[7][crc&0xFF]
+ p = p[8:]
+ }
+ crc = ^crc
+ }
+ if len(p) == 0 {
+ return crc
}
- return update(crc, IEEETable, p)
+ return simpleUpdate(crc, &tab[0], p)
}
diff --git a/src/hash/crc32/crc32_otherarch.go b/src/hash/crc32/crc32_otherarch.go
new file mode 100644
index 0000000..cc96076
--- /dev/null
+++ b/src/hash/crc32/crc32_otherarch.go
@@ -0,0 +1,15 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !amd64,!amd64p32,!s390x
+
+package crc32
+
+func archAvailableIEEE() bool { return false }
+func archInitIEEE() { panic("not available") }
+func archUpdateIEEE(crc uint32, p []byte) uint32 { panic("not available") }
+
+func archAvailableCastagnoli() bool { return false }
+func archInitCastagnoli() { panic("not available") }
+func archUpdateCastagnoli(crc uint32, p []byte) uint32 { panic("not available") }
diff --git a/src/hash/crc32/crc32_s390x.go b/src/hash/crc32/crc32_s390x.go
index befb58f..d13000d 100644
--- a/src/hash/crc32/crc32_s390x.go
+++ b/src/hash/crc32/crc32_s390x.go
@@ -25,58 +25,65 @@ func vectorizedCastagnoli(crc uint32, p []byte) uint32
//go:noescape
func vectorizedIEEE(crc uint32, p []byte) uint32
-func genericCastagnoli(crc uint32, p []byte) uint32 {
- // Use slicing-by-8 on larger inputs.
- if len(p) >= sliceBy8Cutoff {
- return updateSlicingBy8(crc, castagnoliTable8, p)
- }
- return update(crc, castagnoliTable, p)
+func archAvailableCastagnoli() bool {
+ return hasVX
}
-func genericIEEE(crc uint32, p []byte) uint32 {
- // Use slicing-by-8 on larger inputs.
- if len(p) >= sliceBy8Cutoff {
- ieeeTable8Once.Do(func() {
- ieeeTable8 = makeTable8(IEEE)
- })
- return updateSlicingBy8(crc, ieeeTable8, p)
+var archCastagnoliTable8 *slicing8Table
+
+func archInitCastagnoli() {
+ if !hasVX {
+ panic("not available")
}
- return update(crc, IEEETable, p)
+ // We still use slicing-by-8 for small buffers.
+ archCastagnoliTable8 = slicingMakeTable(Castagnoli)
}
-// updateCastagnoli calculates the checksum of p using
-// vectorizedCastagnoli if possible and falling back onto
-// genericCastagnoli as needed.
-func updateCastagnoli(crc uint32, p []byte) uint32 {
- // Use vectorized function if vector facility is available and
- // data length is above threshold.
- if hasVX && len(p) >= vxMinLen {
+// archUpdateCastagnoli calculates the checksum of p using
+// vectorizedCastagnoli.
+func archUpdateCastagnoli(crc uint32, p []byte) uint32 {
+ if !hasVX {
+ panic("not available")
+ }
+ // Use vectorized function if data length is above threshold.
+ if len(p) >= vxMinLen {
aligned := len(p) & ^vxAlignMask
crc = vectorizedCastagnoli(crc, p[:aligned])
p = p[aligned:]
- // process remaining data
- if len(p) > 0 {
- crc = genericCastagnoli(crc, p)
- }
+ }
+ if len(p) == 0 {
return crc
}
- return genericCastagnoli(crc, p)
+ return slicingUpdate(crc, archCastagnoliTable8, p)
+}
+
+func archAvailableIEEE() bool {
+ return hasVX
+}
+
+var archIeeeTable8 *slicing8Table
+
+func archInitIEEE() {
+ if !hasVX {
+ panic("not available")
+ }
+ // We still use slicing-by-8 for small buffers.
+ archIeeeTable8 = slicingMakeTable(IEEE)
}
-// updateIEEE calculates the checksum of p using vectorizedIEEE if
-// possible and falling back onto genericIEEE as needed.
-func updateIEEE(crc uint32, p []byte) uint32 {
- // Use vectorized function if vector facility is available and
- // data length is above threshold.
- if hasVX && len(p) >= vxMinLen {
+// archUpdateIEEE calculates the checksum of p using vectorizedIEEE.
+func archUpdateIEEE(crc uint32, p []byte) uint32 {
+ if !hasVX {
+ panic("not available")
+ }
+ // Use vectorized function if data length is above threshold.
+ if len(p) >= vxMinLen {
aligned := len(p) & ^vxAlignMask
crc = vectorizedIEEE(crc, p[:aligned])
p = p[aligned:]
- // process remaining data
- if len(p) > 0 {
- crc = genericIEEE(crc, p)
- }
+ }
+ if len(p) == 0 {
return crc
}
- return genericIEEE(crc, p)
+ return slicingUpdate(crc, archIeeeTable8, p)
}
diff --git a/src/hash/crc32/crc32_test.go b/src/hash/crc32/crc32_test.go
index e2b3557..1356734 100644
--- a/src/hash/crc32/crc32_test.go
+++ b/src/hash/crc32/crc32_test.go
@@ -6,7 +6,7 @@ package crc32
import (
"hash"
- "io"
+ "math/rand"
"testing"
)
@@ -49,74 +49,221 @@ var golden = []test{
{0x8e0bb443, 0xdcded527, "How can you write a big system without C++? -Paul Glick"},
}
-func TestGolden(t *testing.T) {
- castagnoliTab := MakeTable(Castagnoli)
+// testGoldenIEEE verifies that the given function returns
+// correct IEEE checksums.
+func testGoldenIEEE(t *testing.T, crcFunc func(b []byte) uint32) {
+ for _, g := range golden {
+ if crc := crcFunc([]byte(g.in)); crc != g.ieee {
+ t.Errorf("IEEE(%s) = 0x%x want 0x%x", g.in, crc, g.ieee)
+ }
+ }
+}
+// testGoldenCastagnoli verifies that the given function returns
+// correct IEEE checksums.
+func testGoldenCastagnoli(t *testing.T, crcFunc func(b []byte) uint32) {
for _, g := range golden {
- ieee := NewIEEE()
- io.WriteString(ieee, g.in)
- s := ieee.Sum32()
- if s != g.ieee {
- t.Errorf("IEEE(%s) = 0x%x want 0x%x", g.in, s, g.ieee)
+ if crc := crcFunc([]byte(g.in)); crc != g.castagnoli {
+ t.Errorf("Castagnoli(%s) = 0x%x want 0x%x", g.in, crc, g.castagnoli)
}
+ }
+}
- castagnoli := New(castagnoliTab)
- io.WriteString(castagnoli, g.in)
- s = castagnoli.Sum32()
- if s != g.castagnoli {
- t.Errorf("Castagnoli(%s) = 0x%x want 0x%x", g.in, s, g.castagnoli)
+// testCrossCheck generates random buffers of various lengths and verifies that
+// the two "update" functions return the same result.
+func testCrossCheck(t *testing.T, crcFunc1, crcFunc2 func(crc uint32, b []byte) uint32) {
+ // 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,
+ 4030, 4031, 4032, 4033, 4036, 4040, 4048, 4096, 5000, 10000}
+ for _, length := range lengths {
+ p := make([]byte, length)
+ _, _ = rand.Read(p)
+ crcInit := uint32(rand.Int63())
+ crc1 := crcFunc1(crcInit, p)
+ crc2 := crcFunc2(crcInit, p)
+ if crc1 != crc2 {
+ t.Errorf("mismatch: 0x%x vs 0x%x (buffer length %d)", crc1, crc2, length)
}
+ }
+}
- if len(g.in) > 0 {
- // The SSE4.2 implementation of this has code to deal
- // with misaligned data so we ensure that we test that
- // too.
- castagnoli = New(castagnoliTab)
- io.WriteString(castagnoli, g.in[:1])
- io.WriteString(castagnoli, g.in[1:])
- s = castagnoli.Sum32()
- if s != g.castagnoli {
- t.Errorf("Castagnoli[misaligned](%s) = 0x%x want 0x%x", g.in, s, g.castagnoli)
- }
+// TestSimple tests the simple generic algorithm.
+func TestSimple(t *testing.T) {
+ tab := simpleMakeTable(IEEE)
+ testGoldenIEEE(t, func(b []byte) uint32 {
+ return simpleUpdate(0, tab, b)
+ })
+
+ tab = simpleMakeTable(Castagnoli)
+ testGoldenCastagnoli(t, func(b []byte) uint32 {
+ return simpleUpdate(0, tab, b)
+ })
+}
+
+// TestSimple tests the slicing-by-8 algorithm.
+func TestSlicing(t *testing.T) {
+ tab := slicingMakeTable(IEEE)
+ testGoldenIEEE(t, func(b []byte) uint32 {
+ return slicingUpdate(0, tab, b)
+ })
+
+ tab = slicingMakeTable(Castagnoli)
+ testGoldenCastagnoli(t, func(b []byte) uint32 {
+ return slicingUpdate(0, tab, b)
+ })
+
+ // Cross-check various polys against the simple algorithm.
+ for _, poly := range []uint32{IEEE, Castagnoli, Koopman, 0xD5828281} {
+ t1 := simpleMakeTable(poly)
+ f1 := func(crc uint32, b []byte) uint32 {
+ return simpleUpdate(crc, t1, b)
+ }
+ t2 := slicingMakeTable(poly)
+ f2 := func(crc uint32, b []byte) uint32 {
+ return slicingUpdate(crc, t2, b)
}
+ testCrossCheck(t, f1, f2)
+ }
+}
+
+func TestArchIEEE(t *testing.T) {
+ if !archAvailableIEEE() {
+ t.Skip("Arch-specific IEEE not available.")
+ }
+ archInitIEEE()
+ slicingTable := slicingMakeTable(IEEE)
+ testCrossCheck(t, archUpdateIEEE, func(crc uint32, b []byte) uint32 {
+ return slicingUpdate(crc, slicingTable, b)
+ })
+}
+
+func TestArchCastagnoli(t *testing.T) {
+ if !archAvailableCastagnoli() {
+ t.Skip("Arch-specific Castagnoli not available.")
+ }
+ archInitCastagnoli()
+ slicingTable := slicingMakeTable(Castagnoli)
+ testCrossCheck(t, archUpdateCastagnoli, func(crc uint32, b []byte) uint32 {
+ return slicingUpdate(crc, slicingTable, b)
+ })
+}
+
+func TestGolden(t *testing.T) {
+ testGoldenIEEE(t, ChecksumIEEE)
+
+ // Some implementations have special code to deal with misaligned
+ // data; test that as well.
+ for delta := 1; delta <= 7; delta++ {
+ testGoldenIEEE(t, func(b []byte) uint32 {
+ ieee := NewIEEE()
+ d := delta
+ if d >= len(b) {
+ d = len(b)
+ }
+ ieee.Write(b[:d])
+ ieee.Write(b[d:])
+ return ieee.Sum32()
+ })
+ }
+
+ castagnoliTab := MakeTable(Castagnoli)
+ if castagnoliTab == nil {
+ t.Errorf("nil Castagnoli Table")
+ }
+
+ testGoldenCastagnoli(t, func(b []byte) uint32 {
+ castagnoli := New(castagnoliTab)
+ castagnoli.Write(b)
+ return castagnoli.Sum32()
+ })
+
+ // Some implementations have special code to deal with misaligned
+ // data; test that as well.
+ for delta := 1; delta <= 7; delta++ {
+ testGoldenCastagnoli(t, func(b []byte) uint32 {
+ castagnoli := New(castagnoliTab)
+ d := delta
+ if d >= len(b) {
+ d = len(b)
+ }
+ castagnoli.Write(b[:d])
+ castagnoli.Write(b[d:])
+ return castagnoli.Sum32()
+ })
}
}
func BenchmarkIEEECrc40B(b *testing.B) {
- benchmark(b, NewIEEE(), 40)
+ benchmark(b, NewIEEE(), 40, 0)
}
func BenchmarkIEEECrc1KB(b *testing.B) {
- benchmark(b, NewIEEE(), 1<<10)
+ benchmark(b, NewIEEE(), 1<<10, 0)
}
func BenchmarkIEEECrc4KB(b *testing.B) {
- benchmark(b, NewIEEE(), 4<<10)
+ benchmark(b, NewIEEE(), 4<<10, 0)
}
func BenchmarkIEEECrc32KB(b *testing.B) {
- benchmark(b, NewIEEE(), 32<<10)
+ 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)
+ 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)
+ 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)
+ 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)
+ benchmark(b, New(MakeTable(Castagnoli)), 32<<10, 0)
+}
+
+func BenchmarkCastagnoliCrc32KBMisaligned(b *testing.B) {
+ benchmark(b, New(MakeTable(Castagnoli)), 32<<10, 1)
}
-func benchmark(b *testing.B, h hash.Hash32, n int64) {
+func benchmark(b *testing.B, h hash.Hash32, n, alignment int64) {
b.SetBytes(n)
- data := make([]byte, n)
+ data := make([]byte, n+alignment)
+ data = data[alignment:]
for i := range data {
data[i] = byte(i)
}
diff --git a/src/html/template/clone_test.go b/src/html/template/clone_test.go
index d7c62fa..b500715 100644
--- a/src/html/template/clone_test.go
+++ b/src/html/template/clone_test.go
@@ -7,7 +7,9 @@ package template
import (
"bytes"
"errors"
+ "fmt"
"io/ioutil"
+ "sync"
"testing"
"text/template/parse"
)
@@ -194,3 +196,69 @@ func TestFuncMapWorksAfterClone(t *testing.T) {
t.Errorf("clone error message mismatch want %q got %q", wantErr, gotErr)
}
}
+
+// https://golang.org/issue/16101
+func TestTemplateCloneExecuteRace(t *testing.T) {
+ const (
+ input = `<title>{{block "a" .}}a{{end}}</title><body>{{block "b" .}}b{{end}}<body>`
+ overlay = `{{define "b"}}A{{end}}`
+ )
+ outer := Must(New("outer").Parse(input))
+ tmpl := Must(Must(outer.Clone()).Parse(overlay))
+
+ var wg sync.WaitGroup
+ for i := 0; i < 10; i++ {
+ wg.Add(1)
+ go func() {
+ defer wg.Done()
+ for i := 0; i < 100; i++ {
+ if err := tmpl.Execute(ioutil.Discard, "data"); err != nil {
+ panic(err)
+ }
+ }
+ }()
+ }
+ wg.Wait()
+}
+
+func TestTemplateCloneLookup(t *testing.T) {
+ // Template.escape makes an assumption that the template associated
+ // with t.Name() is t. Check that this holds.
+ tmpl := Must(New("x").Parse("a"))
+ tmpl = Must(tmpl.Clone())
+ if tmpl.Lookup(tmpl.Name()) != tmpl {
+ t.Error("after Clone, tmpl.Lookup(tmpl.Name()) != tmpl")
+ }
+}
+
+func TestCloneGrowth(t *testing.T) {
+ tmpl := Must(New("root").Parse(`<title>{{block "B". }}Arg{{end}}</title>`))
+ tmpl = Must(tmpl.Clone())
+ Must(tmpl.Parse(`{{define "B"}}Text{{end}}`))
+ for i := 0; i < 10; i++ {
+ tmpl.Execute(ioutil.Discard, nil)
+ }
+ if len(tmpl.DefinedTemplates()) > 200 {
+ t.Fatalf("too many templates: %v", len(tmpl.DefinedTemplates()))
+ }
+}
+
+// https://golang.org/issue/17735
+func TestCloneRedefinedName(t *testing.T) {
+ const base = `
+{{ define "a" -}}<title>{{ template "b" . -}}</title>{{ end -}}
+{{ define "b" }}{{ end -}}
+`
+ const page = `{{ template "a" . }}`
+
+ t1 := Must(New("a").Parse(base))
+
+ for i := 0; i < 2; i++ {
+ t2 := Must(t1.Clone())
+ t2 = Must(t2.New(fmt.Sprintf("%d", i)).Parse(page))
+ err := t2.Execute(ioutil.Discard, nil)
+ if err != nil {
+ t.Fatal(err)
+ }
+ }
+}
diff --git a/src/html/template/content_test.go b/src/html/template/content_test.go
index e698328..0b4365c 100644
--- a/src/html/template/content_test.go
+++ b/src/html/template/content_test.go
@@ -162,6 +162,47 @@ func TestTypedContent(t *testing.T) {
},
},
{
+ `<script type="text/javascript">alert("{{.}}")</script>`,
+ []string{
+ `\x3cb\x3e \x22foo%\x22 O\x27Reilly \x26bar;`,
+ `a[href =~ \x22\/\/example.com\x22]#foo`,
+ `Hello, \x3cb\x3eWorld\x3c\/b\x3e \x26amp;tc!`,
+ ` dir=\x22ltr\x22`,
+ `c \x26\x26 alert(\x22Hello, World!\x22);`,
+ // Escape sequence not over-escaped.
+ `Hello, World \x26 O\x27Reilly\x21`,
+ `greeting=H%69\x26addressee=(World)`,
+ },
+ },
+ {
+ `<script type="text/javascript">alert({{.}})</script>`,
+ []string{
+ `"\u003cb\u003e \"foo%\" O'Reilly \u0026bar;"`,
+ `"a[href =~ \"//example.com\"]#foo"`,
+ `"Hello, \u003cb\u003eWorld\u003c/b\u003e \u0026amp;tc!"`,
+ `" dir=\"ltr\""`,
+ // Not escaped.
+ `c && alert("Hello, World!");`,
+ // Escape sequence not over-escaped.
+ `"Hello, World & O'Reilly\x21"`,
+ `"greeting=H%69\u0026addressee=(World)"`,
+ },
+ },
+ {
+ // Not treated as JS. The output is same as for <div>{{.}}</div>
+ `<script type="text/template">{{.}}</script>`,
+ []string{
+ `<b> "foo%" O'Reilly &bar;`,
+ `a[href =~ "//example.com"]#foo`,
+ // Not escaped.
+ `Hello, <b>World</b> &tc!`,
+ ` dir="ltr"`,
+ `c && alert("Hello, World!");`,
+ `Hello, World & O'Reilly\x21`,
+ `greeting=H%69&addressee=(World)`,
+ },
+ },
+ {
`<button onclick='alert("{{.}}")'>`,
[]string{
`\x3cb\x3e \x22foo%\x22 O\x27Reilly \x26bar;`,
diff --git a/src/html/template/context.go b/src/html/template/context.go
index c90fc1f..37a3faf 100644
--- a/src/html/template/context.go
+++ b/src/html/template/context.go
@@ -285,7 +285,8 @@ type element uint8
const (
// elementNone occurs outside a special tag or special element body.
elementNone element = iota
- // elementScript corresponds to the raw text <script> element.
+ // elementScript corresponds to the raw text <script> element
+ // with JS MIME type or no type attribute.
elementScript
// elementStyle corresponds to the raw text <style> element.
elementStyle
@@ -319,6 +320,8 @@ const (
attrNone attr = iota
// attrScript corresponds to an event handler attribute.
attrScript
+ // attrScriptType corresponds to the type attribute in script HTML element
+ attrScriptType
// attrStyle corresponds to the style attribute whose value is CSS.
attrStyle
// attrURL corresponds to an attribute whose value is a URL.
@@ -326,10 +329,11 @@ const (
)
var attrNames = [...]string{
- attrNone: "attrNone",
- attrScript: "attrScript",
- attrStyle: "attrStyle",
- attrURL: "attrURL",
+ attrNone: "attrNone",
+ attrScript: "attrScript",
+ attrScriptType: "attrScriptType",
+ attrStyle: "attrStyle",
+ attrURL: "attrURL",
}
func (a attr) String() string {
diff --git a/src/html/template/doc.go b/src/html/template/doc.go
index e1e9cad..cb89812 100644
--- a/src/html/template/doc.go
+++ b/src/html/template/doc.go
@@ -129,7 +129,7 @@ then the template output is
<script>var pair = {"A": "foo", "B": "bar"};</script>
-See package json to understand how non-string content is marshalled for
+See package json to understand how non-string content is marshaled for
embedding in JavaScript contexts.
diff --git a/src/html/template/error.go b/src/html/template/error.go
index 5637384..cbcaf92 100644
--- a/src/html/template/error.go
+++ b/src/html/template/error.go
@@ -44,7 +44,7 @@ const (
// OK indicates the lack of an error.
OK ErrorCode = iota
- // ErrAmbigContext: "... appears in an ambiguous URL context"
+ // ErrAmbigContext: "... appears in an ambiguous context within a URL"
// Example:
// <a href="
// {{if .C}}
diff --git a/src/html/template/escape.go b/src/html/template/escape.go
index 8f2fe46..0e7d2be 100644
--- a/src/html/template/escape.go
+++ b/src/html/template/escape.go
@@ -161,7 +161,7 @@ func (e *escaper) escapeAction(c context, n *parse.ActionNode) context {
case urlPartUnknown:
return context{
state: stateError,
- err: errorf(ErrAmbigContext, n, n.Line, "%s appears in an ambiguous URL context", n),
+ err: errorf(ErrAmbigContext, n, n.Line, "%s appears in an ambiguous context within a URL", n),
}
default:
panic(c.urlPart.String())
@@ -673,6 +673,8 @@ func contextAfterText(c context, s []byte) (context, int) {
return transitionFunc[c.state](c, s[:i])
}
+ // We are at the beginning of an attribute value.
+
i := bytes.IndexAny(s, delimEnds[c.delim])
if i == -1 {
i = len(s)
@@ -703,13 +705,21 @@ func contextAfterText(c context, s []byte) (context, int) {
}
return c, len(s)
}
+
+ element := c.element
+
+ // If this is a non-JS "type" attribute inside "script" tag, do not treat the contents as JS.
+ if c.state == stateAttr && c.element == elementScript && c.attr == attrScriptType && !isJSType(string(s[:i])) {
+ element = elementNone
+ }
+
if c.delim != delimSpaceOrTagEnd {
// Consume any quote.
i++
}
// On exiting an attribute, we discard all state information
// except the state and element.
- return context{state: stateTag, element: c.element}, i
+ return context{state: stateTag, element: element}, i
}
// editActionNode records a change to an action pipeline for later commit.
diff --git a/src/html/template/escape_test.go b/src/html/template/escape_test.go
index 023ee57..f6ace49 100644
--- a/src/html/template/escape_test.go
+++ b/src/html/template/escape_test.go
@@ -903,7 +903,7 @@ func TestErrors(t *testing.T) {
},
{
`<a href="{{if .F}}/foo?a={{else}}/bar/{{end}}{{.H}}">`,
- "z:1:47: {{.H}} appears in an ambiguous URL context",
+ "z:1:47: {{.H}} appears in an ambiguous context within a URL",
},
{
`<a onclick="alert('Hello \`,
@@ -1365,6 +1365,10 @@ func TestEscapeText(t *testing.T) {
context{state: stateTag, element: elementScript},
},
{
+ `<script>`,
+ context{state: stateJS, jsCtx: jsCtxRegexp, element: elementScript},
+ },
+ {
`<script>foo`,
context{state: stateJS, jsCtx: jsCtxDivOp, element: elementScript},
},
@@ -1389,6 +1393,14 @@ func TestEscapeText(t *testing.T) {
context{state: stateText},
},
{
+ `<script type="text/template">`,
+ context{state: stateText},
+ },
+ {
+ `<script type="notjs">`,
+ context{state: stateText},
+ },
+ {
`<Script>`,
context{state: stateJS, element: elementScript},
},
diff --git a/src/html/template/js.go b/src/html/template/js.go
index f6d166b..8f1185c 100644
--- a/src/html/template/js.go
+++ b/src/html/template/js.go
@@ -162,14 +162,14 @@ func jsValEscaper(args ...interface{}) string {
// a division operator it is not turned into a line comment:
// x/{{y}}
// turning into
- // x//* error marshalling y:
+ // x//* error marshaling y:
// second line of error message */null
return fmt.Sprintf(" /* %s */null ", strings.Replace(err.Error(), "*/", "* /", -1))
}
// TODO: maybe post-process output to prevent it from containing
// "<!--", "-->", "<![CDATA[", "]]>", or "</script"
- // in case custom marshallers produce output containing those.
+ // in case custom marshalers produce output containing those.
// TODO: Maybe abbreviate \u00ab to \xab to produce more compact output.
if len(b) == 0 {
@@ -362,3 +362,41 @@ func isJSIdentPart(r rune) bool {
}
return false
}
+
+// isJSType returns true if the given MIME type should be considered JavaScript.
+//
+// It is used to determine whether a script tag with a type attribute is a javascript container.
+func isJSType(mimeType string) bool {
+ // per
+ // http://www.w3.org/TR/html5/scripting-1.html#attr-script-type
+ // https://tools.ietf.org/html/rfc7231#section-3.1.1
+ // http://tools.ietf.org/html/rfc4329#section-3
+
+ // discard parameters
+ if i := strings.Index(mimeType, ";"); i >= 0 {
+ mimeType = mimeType[:i]
+ }
+ mimeType = strings.TrimSpace(mimeType)
+ switch mimeType {
+ case
+ "application/ecmascript",
+ "application/javascript",
+ "application/x-ecmascript",
+ "application/x-javascript",
+ "text/ecmascript",
+ "text/javascript",
+ "text/javascript1.0",
+ "text/javascript1.1",
+ "text/javascript1.2",
+ "text/javascript1.3",
+ "text/javascript1.4",
+ "text/javascript1.5",
+ "text/jscript",
+ "text/livescript",
+ "text/x-ecmascript",
+ "text/x-javascript":
+ return true
+ default:
+ return false
+ }
+}
diff --git a/src/html/template/js_test.go b/src/html/template/js_test.go
index 7af7997..58fc37a 100644
--- a/src/html/template/js_test.go
+++ b/src/html/template/js_test.go
@@ -332,6 +332,24 @@ func TestEscapersOnLower7AndSelectHighCodepoints(t *testing.T) {
}
}
+func TestIsJsMimeType(t *testing.T) {
+ tests := []struct {
+ in string
+ out bool
+ }{
+ {"application/javascript;version=1.8", true},
+ {"application/javascript;version=1.8;foo=bar", true},
+ {"application/javascript/version=1.8", false},
+ {"text/javascript", true},
+ }
+
+ for _, test := range tests {
+ if isJSType(test.in) != test.out {
+ t.Errorf("isJSType(%q) = %v, want %v", test.in, !test.out, test.out)
+ }
+ }
+}
+
func BenchmarkJSValEscaperWithNum(b *testing.B) {
for i := 0; i < b.N; i++ {
jsValEscaper(3.141592654)
diff --git a/src/html/template/template.go b/src/html/template/template.go
index 063e46d..b313a6b 100644
--- a/src/html/template/template.go
+++ b/src/html/template/template.go
@@ -33,8 +33,9 @@ var escapeOK = fmt.Errorf("template escaped correctly")
// nameSpace is the data structure shared by all templates in an association.
type nameSpace struct {
- mu sync.Mutex
- set map[string]*Template
+ mu sync.Mutex
+ set map[string]*Template
+ escaped bool
}
// Templates returns a slice of the templates associated with t, including t
@@ -74,13 +75,28 @@ func (t *Template) Option(opt ...string) *Template {
return t
}
+// checkCanParse checks whether it is OK to parse templates.
+// If not, it returns an error.
+func (t *Template) checkCanParse() error {
+ if t == nil {
+ return nil
+ }
+ t.nameSpace.mu.Lock()
+ defer t.nameSpace.mu.Unlock()
+ if t.nameSpace.escaped {
+ return fmt.Errorf("html/template: cannot Parse after Execute")
+ }
+ return nil
+}
+
// escape escapes all associated templates.
func (t *Template) escape() error {
t.nameSpace.mu.Lock()
defer t.nameSpace.mu.Unlock()
+ t.nameSpace.escaped = true
if t.escapeErr == nil {
if t.Tree == nil {
- return fmt.Errorf("template: %q is an incomplete or empty template%s", t.Name(), t.DefinedTemplates())
+ return fmt.Errorf("template: %q is an incomplete or empty template", t.Name())
}
if err := escapeTemplate(t, t.text.Root, t.Name()); err != nil {
return err
@@ -124,6 +140,7 @@ func (t *Template) ExecuteTemplate(wr io.Writer, name string, data interface{})
func (t *Template) lookupAndEscapeTemplate(name string) (tmpl *Template, err error) {
t.nameSpace.mu.Lock()
defer t.nameSpace.mu.Unlock()
+ t.nameSpace.escaped = true
tmpl = t.set[name]
if tmpl == nil {
return nil, fmt.Errorf("html/template: %q is undefined", name)
@@ -150,22 +167,27 @@ func (t *Template) DefinedTemplates() string {
return t.text.DefinedTemplates()
}
-// Parse parses a string into a template. Nested template definitions
-// will be associated with the top-level template t. Parse may be
-// called multiple times to parse definitions of templates to associate
-// with t. It is an error if a resulting template is non-empty (contains
-// content other than template definitions) and would replace a
-// non-empty template with the same name. (In multiple calls to Parse
-// with the same receiver template, only one call can contain text
-// other than space, comments, and template definitions.)
-func (t *Template) Parse(src string) (*Template, error) {
- t.nameSpace.mu.Lock()
- t.escapeErr = nil
- t.nameSpace.mu.Unlock()
- ret, err := t.text.Parse(src)
+// Parse parses text as a template body for t.
+// Named template definitions ({{define ...}} or {{block ...}} statements) in text
+// define additional templates associated with t and are removed from the
+// definition of t itself.
+//
+// Templates can be redefined in successive calls to Parse,
+// before the first use of Execute on t or any associated template.
+// A template definition with a body containing only white space and comments
+// is considered empty and will not replace an existing template's body.
+// This allows using Parse to add new named template definitions without
+// overwriting the main template body.
+func (t *Template) Parse(text string) (*Template, error) {
+ if err := t.checkCanParse(); err != nil {
+ return nil, err
+ }
+
+ ret, err := t.text.Parse(text)
if err != nil {
return nil, err
}
+
// In general, all the named templates might have changed underfoot.
// Regardless, some new ones may have been defined.
// The template.Template set has been updated; update ours.
@@ -176,11 +198,7 @@ func (t *Template) Parse(src string) (*Template, error) {
tmpl := t.set[name]
if tmpl == nil {
tmpl = t.new(name)
- } else if tmpl.escapeErr != nil {
- return nil, fmt.Errorf("html/template: cannot redefine %q after it has executed", name)
}
- // Restore our record of this text/template to its unescaped original state.
- tmpl.escapeErr = nil
tmpl.text = v
tmpl.Tree = v.Tree
}
@@ -190,13 +208,14 @@ func (t *Template) Parse(src string) (*Template, error) {
// AddParseTree creates a new template with the name and parse tree
// and associates it with t.
//
-// It returns an error if t has already been executed.
+// It returns an error if t or any associated template has already been executed.
func (t *Template) AddParseTree(name string, tree *parse.Tree) (*Template, error) {
+ if err := t.checkCanParse(); err != nil {
+ return nil, err
+ }
+
t.nameSpace.mu.Lock()
defer t.nameSpace.mu.Unlock()
- if t.escapeErr != nil {
- return nil, fmt.Errorf("html/template: cannot AddParseTree to %q after it has executed", t.Name())
- }
text, err := t.text.AddParseTree(name, tree)
if err != nil {
return nil, err
@@ -252,7 +271,8 @@ func (t *Template) Clone() (*Template, error) {
ret.nameSpace,
}
}
- return ret, nil
+ // Return the template associated with the name of this template.
+ return ret.set[ret.Name()], nil
}
// New allocates a new HTML template with the given name.
@@ -361,6 +381,8 @@ func ParseFiles(filenames ...string) (*Template, error) {
//
// When parsing multiple files with the same name in different directories,
// the last one mentioned will be the one that results.
+//
+// ParseFiles returns an error if t or any associated template has already been executed.
func (t *Template) ParseFiles(filenames ...string) (*Template, error) {
return parseFiles(t, filenames...)
}
@@ -368,6 +390,10 @@ func (t *Template) ParseFiles(filenames ...string) (*Template, error) {
// parseFiles is the helper for the method and function. If the argument
// template is nil, it is created from the first file.
func parseFiles(t *Template, filenames ...string) (*Template, error) {
+ if err := t.checkCanParse(); err != nil {
+ return nil, err
+ }
+
if len(filenames) == 0 {
// Not really a problem, but be consistent.
return nil, fmt.Errorf("html/template: no files named in call to ParseFiles")
@@ -422,12 +448,17 @@ func ParseGlob(pattern string) (*Template, error) {
//
// When parsing multiple files with the same name in different directories,
// the last one mentioned will be the one that results.
+//
+// ParseGlob returns an error if t or any associated template has already been executed.
func (t *Template) ParseGlob(pattern string) (*Template, error) {
return parseGlob(t, pattern)
}
// parseGlob is the implementation of the function and method ParseGlob.
func parseGlob(t *Template, pattern string) (*Template, error) {
+ if err := t.checkCanParse(); err != nil {
+ return nil, err
+ }
filenames, err := filepath.Glob(pattern)
if err != nil {
return nil, err
diff --git a/src/html/template/template_test.go b/src/html/template/template_test.go
index 46df1f8..90c5a73 100644
--- a/src/html/template/template_test.go
+++ b/src/html/template/template_test.go
@@ -1,7 +1,13 @@
-package template
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package template_test
import (
"bytes"
+ . "html/template"
+ "strings"
"testing"
)
@@ -27,3 +33,125 @@ func TestTemplateClone(t *testing.T) {
t.Fatalf("got %q; want %q", got, want)
}
}
+
+func TestRedefineNonEmptyAfterExecution(t *testing.T) {
+ c := newTestCase(t)
+ c.mustParse(c.root, `foo`)
+ c.mustExecute(c.root, nil, "foo")
+ c.mustNotParse(c.root, `bar`)
+}
+
+func TestRedefineEmptyAfterExecution(t *testing.T) {
+ c := newTestCase(t)
+ c.mustParse(c.root, ``)
+ c.mustExecute(c.root, nil, "")
+ c.mustNotParse(c.root, `foo`)
+ c.mustExecute(c.root, nil, "")
+}
+
+func TestRedefineAfterNonExecution(t *testing.T) {
+ c := newTestCase(t)
+ c.mustParse(c.root, `{{if .}}<{{template "X"}}>{{end}}{{define "X"}}foo{{end}}`)
+ c.mustExecute(c.root, 0, "")
+ c.mustNotParse(c.root, `{{define "X"}}bar{{end}}`)
+ c.mustExecute(c.root, 1, "<foo>")
+}
+
+func TestRedefineAfterNamedExecution(t *testing.T) {
+ c := newTestCase(t)
+ c.mustParse(c.root, `<{{template "X" .}}>{{define "X"}}foo{{end}}`)
+ c.mustExecute(c.root, nil, "<foo>")
+ c.mustNotParse(c.root, `{{define "X"}}bar{{end}}`)
+ c.mustExecute(c.root, nil, "<foo>")
+}
+
+func TestRedefineNestedByNameAfterExecution(t *testing.T) {
+ c := newTestCase(t)
+ c.mustParse(c.root, `{{define "X"}}foo{{end}}`)
+ c.mustExecute(c.lookup("X"), nil, "foo")
+ c.mustNotParse(c.root, `{{define "X"}}bar{{end}}`)
+ c.mustExecute(c.lookup("X"), nil, "foo")
+}
+
+func TestRedefineNestedByTemplateAfterExecution(t *testing.T) {
+ c := newTestCase(t)
+ c.mustParse(c.root, `{{define "X"}}foo{{end}}`)
+ c.mustExecute(c.lookup("X"), nil, "foo")
+ c.mustNotParse(c.lookup("X"), `bar`)
+ c.mustExecute(c.lookup("X"), nil, "foo")
+}
+
+func TestRedefineSafety(t *testing.T) {
+ c := newTestCase(t)
+ c.mustParse(c.root, `<html><a href="{{template "X"}}">{{define "X"}}{{end}}`)
+ c.mustExecute(c.root, nil, `<html><a href="">`)
+ // Note: Every version of Go prior to Go 1.8 accepted the redefinition of "X"
+ // on the next line, but luckily kept it from being used in the outer template.
+ // Now we reject it, which makes clearer that we're not going to use it.
+ c.mustNotParse(c.root, `{{define "X"}}" bar="baz{{end}}`)
+ c.mustExecute(c.root, nil, `<html><a href="">`)
+}
+
+func TestRedefineTopUse(t *testing.T) {
+ c := newTestCase(t)
+ c.mustParse(c.root, `{{template "X"}}{{.}}{{define "X"}}{{end}}`)
+ c.mustExecute(c.root, 42, `42`)
+ c.mustNotParse(c.root, `{{define "X"}}<script>{{end}}`)
+ c.mustExecute(c.root, 42, `42`)
+}
+
+func TestRedefineOtherParsers(t *testing.T) {
+ c := newTestCase(t)
+ c.mustParse(c.root, ``)
+ c.mustExecute(c.root, nil, ``)
+ if _, err := c.root.ParseFiles("no.template"); err == nil || !strings.Contains(err.Error(), "Execute") {
+ t.Errorf("ParseFiles: %v\nwanted error about already having Executed", err)
+ }
+ if _, err := c.root.ParseGlob("*.no.template"); err == nil || !strings.Contains(err.Error(), "Execute") {
+ t.Errorf("ParseGlob: %v\nwanted error about already having Executed", err)
+ }
+ if _, err := c.root.AddParseTree("t1", c.root.Tree); err == nil || !strings.Contains(err.Error(), "Execute") {
+ t.Errorf("AddParseTree: %v\nwanted error about already having Executed", err)
+ }
+}
+
+type testCase struct {
+ t *testing.T
+ root *Template
+}
+
+func newTestCase(t *testing.T) *testCase {
+ return &testCase{
+ t: t,
+ root: New("root"),
+ }
+}
+
+func (c *testCase) lookup(name string) *Template {
+ return c.root.Lookup(name)
+}
+
+func (c *testCase) mustParse(t *Template, text string) {
+ _, err := t.Parse(text)
+ if err != nil {
+ c.t.Fatalf("parse: %v", err)
+ }
+}
+
+func (c *testCase) mustNotParse(t *Template, text string) {
+ _, err := t.Parse(text)
+ if err == nil {
+ c.t.Fatalf("parse: unexpected success")
+ }
+}
+
+func (c *testCase) mustExecute(t *Template, val interface{}, want string) {
+ var buf bytes.Buffer
+ err := t.Execute(&buf, val)
+ if err != nil {
+ c.t.Fatalf("execute: %v", err)
+ }
+ if buf.String() != want {
+ c.t.Fatalf("template output:\n%s\nwant:\n%s", buf.String(), want)
+ }
+}
diff --git a/src/html/template/transition.go b/src/html/template/transition.go
index aefe035..4a4716d 100644
--- a/src/html/template/transition.go
+++ b/src/html/template/transition.go
@@ -105,14 +105,21 @@ func tTag(c context, s []byte) (context, int) {
err: errorf(ErrBadHTML, nil, 0, "expected space, attr name, or end of tag, but got %q", s[i:]),
}, len(s)
}
- switch attrType(string(s[i:j])) {
- case contentTypeURL:
- attr = attrURL
- case contentTypeCSS:
- attr = attrStyle
- case contentTypeJS:
- attr = attrScript
+
+ attrName := string(s[i:j])
+ if c.element == elementScript && attrName == "type" {
+ attr = attrScriptType
+ } else {
+ switch attrType(attrName) {
+ case contentTypeURL:
+ attr = attrURL
+ case contentTypeCSS:
+ attr = attrStyle
+ case contentTypeJS:
+ attr = attrScript
+ }
}
+
if j == len(s) {
state = stateAttrName
} else {
@@ -149,10 +156,11 @@ func tAfterName(c context, s []byte) (context, int) {
}
var attrStartStates = [...]state{
- attrNone: stateAttr,
- attrScript: stateJS,
- attrStyle: stateCSS,
- attrURL: stateURL,
+ attrNone: stateAttr,
+ attrScript: stateJS,
+ attrScriptType: stateAttr,
+ attrStyle: stateCSS,
+ attrURL: stateURL,
}
// tBeforeValue is the context transition function for stateBeforeValue.
diff --git a/src/html/template/url.go b/src/html/template/url.go
index 246bfd3..02123b2 100644
--- a/src/html/template/url.go
+++ b/src/html/template/url.go
@@ -32,7 +32,7 @@ func urlEscaper(args ...interface{}) string {
return urlProcessor(false, args...)
}
-// urlEscaper normalizes URL content so it can be embedded in a quote-delimited
+// urlNormalizer normalizes URL content so it can be embedded in a quote-delimited
// string or parenthesis delimited url(...).
// The normalizer does not encode all HTML specials. Specifically, it does not
// encode '&' so correct embedding in an HTML attribute requires escaping of
diff --git a/src/image/color/color.go b/src/image/color/color.go
index 1044339..0832c59 100644
--- a/src/image/color/color.go
+++ b/src/image/color/color.go
@@ -246,8 +246,18 @@ func grayModel(c Color) Color {
return c
}
r, g, b, _ := c.RGBA()
- y := (299*r + 587*g + 114*b + 500) / 1000
- return Gray{uint8(y >> 8)}
+
+ // These coefficients (the fractions 0.299, 0.587 and 0.114) are the same
+ // as those given by the JFIF specification and used by func RGBToYCbCr in
+ // ycbcr.go.
+ //
+ // Note that 19595 + 38470 + 7471 equals 65536.
+ //
+ // The 24 is 16 + 8. The 16 is the same as used in RGBToYCbCr. The 8 is
+ // because the return value is 8 bit color, not 16 bit color.
+ y := (19595*r + 38470*g + 7471*b + 1<<15) >> 24
+
+ return Gray{uint8(y)}
}
func gray16Model(c Color) Color {
@@ -255,7 +265,14 @@ func gray16Model(c Color) Color {
return c
}
r, g, b, _ := c.RGBA()
- y := (299*r + 587*g + 114*b + 500) / 1000
+
+ // These coefficients (the fractions 0.299, 0.587 and 0.114) are the same
+ // as those given by the JFIF specification and used by func RGBToYCbCr in
+ // ycbcr.go.
+ //
+ // Note that 19595 + 38470 + 7471 equals 65536.
+ y := (19595*r + 38470*g + 7471*b + 1<<15) >> 16
+
return Gray16{uint16(y)}
}
diff --git a/src/image/color/ycbcr.go b/src/image/color/ycbcr.go
index 3df5d36..18d1a56 100644
--- a/src/image/color/ycbcr.go
+++ b/src/image/color/ycbcr.go
@@ -17,6 +17,8 @@ func RGBToYCbCr(r, g, b uint8) (uint8, uint8, uint8) {
b1 := int32(b)
// yy is in range [0,0xff].
+ //
+ // Note that 19595 + 38470 + 7471 equals 65536.
yy := (19595*r1 + 38470*g1 + 7471*b1 + 1<<15) >> 16
// The bit twiddling below is equivalent to
@@ -32,6 +34,8 @@ func RGBToYCbCr(r, g, b uint8) (uint8, uint8, uint8) {
// Note that the uint8 type conversion in the return
// statement will convert ^int32(0) to 0xff.
// The code below to compute cr uses a similar pattern.
+ //
+ // Note that -11056 - 21712 + 32768 equals 0.
cb := -11056*r1 - 21712*g1 + 32768*b1 + 257<<15
if uint32(cb)&0xff000000 == 0 {
cb >>= 16
@@ -39,6 +43,7 @@ func RGBToYCbCr(r, g, b uint8) (uint8, uint8, uint8) {
cb = ^(cb >> 31)
}
+ // Note that 32768 - 27440 - 5328 equals 0.
cr := 32768*r1 - 27440*g1 - 5328*b1 + 257<<15
if uint32(cr)&0xff000000 == 0 {
cr >>= 16
@@ -134,24 +139,39 @@ func (c YCbCr) RGBA() (uint32, uint32, uint32, uint32) {
yy1 := int32(c.Y) * 0x10100 // Convert 0x12 to 0x121200.
cb1 := int32(c.Cb) - 128
cr1 := int32(c.Cr) - 128
- r := (yy1 + 91881*cr1) >> 8
- g := (yy1 - 22554*cb1 - 46802*cr1) >> 8
- b := (yy1 + 116130*cb1) >> 8
- if r < 0 {
- r = 0
- } else if r > 0xffff {
- r = 0xffff
+
+ // The bit twiddling below is equivalent to
+ //
+ // r := (yy1 + 91881*cr1) >> 8
+ // if r < 0 {
+ // r = 0
+ // } else if r > 0xff {
+ // r = 0xffff
+ // }
+ //
+ // but uses fewer branches and is faster.
+ // The code below to compute g and b uses a similar pattern.
+ r := yy1 + 91881*cr1
+ if uint32(r)&0xff000000 == 0 {
+ r >>= 8
+ } else {
+ r = ^(r >> 31) & 0xffff
}
- if g < 0 {
- g = 0
- } else if g > 0xffff {
- g = 0xffff
+
+ g := yy1 - 22554*cb1 - 46802*cr1
+ if uint32(g)&0xff000000 == 0 {
+ g >>= 8
+ } else {
+ g = ^(g >> 31) & 0xffff
}
- if b < 0 {
- b = 0
- } else if b > 0xffff {
- b = 0xffff
+
+ b := yy1 + 116130*cb1
+ if uint32(b)&0xff000000 == 0 {
+ b >>= 8
+ } else {
+ b = ^(b >> 31) & 0xffff
}
+
return uint32(r), uint32(g), uint32(b), 0xffff
}
@@ -179,23 +199,37 @@ func (c NYCbCrA) RGBA() (uint32, uint32, uint32, uint32) {
yy1 := int32(c.Y) * 0x10100 // Convert 0x12 to 0x121200.
cb1 := int32(c.Cb) - 128
cr1 := int32(c.Cr) - 128
- r := (yy1 + 91881*cr1) >> 8
- g := (yy1 - 22554*cb1 - 46802*cr1) >> 8
- b := (yy1 + 116130*cb1) >> 8
- if r < 0 {
- r = 0
- } else if r > 0xffff {
- r = 0xffff
+
+ // The bit twiddling below is equivalent to
+ //
+ // r := (yy1 + 91881*cr1) >> 8
+ // if r < 0 {
+ // r = 0
+ // } else if r > 0xff {
+ // r = 0xffff
+ // }
+ //
+ // but uses fewer branches and is faster.
+ // The code below to compute g and b uses a similar pattern.
+ r := yy1 + 91881*cr1
+ if uint32(r)&0xff000000 == 0 {
+ r >>= 8
+ } else {
+ r = ^(r >> 31) & 0xffff
}
- if g < 0 {
- g = 0
- } else if g > 0xffff {
- g = 0xffff
+
+ g := yy1 - 22554*cb1 - 46802*cr1
+ if uint32(g)&0xff000000 == 0 {
+ g >>= 8
+ } else {
+ g = ^(g >> 31) & 0xffff
}
- if b < 0 {
- b = 0
- } else if b > 0xffff {
- b = 0xffff
+
+ b := yy1 + 116130*cb1
+ if uint32(b)&0xff000000 == 0 {
+ b >>= 8
+ } else {
+ b = ^(b >> 31) & 0xffff
}
// The second part of this method applies the alpha.
diff --git a/src/image/color/ycbcr_test.go b/src/image/color/ycbcr_test.go
index 561699f..85c1b98 100644
--- a/src/image/color/ycbcr_test.go
+++ b/src/image/color/ycbcr_test.go
@@ -172,7 +172,8 @@ func TestPalette(t *testing.T) {
}
}
-var sink uint8
+var sink8 uint8
+var sink32 uint32
func BenchmarkYCbCrToRGB(b *testing.B) {
// YCbCrToRGB does saturating arithmetic.
@@ -180,17 +181,17 @@ func BenchmarkYCbCrToRGB(b *testing.B) {
// different paths through the generated code.
b.Run("0", func(b *testing.B) {
for i := 0; i < b.N; i++ {
- sink, sink, sink = YCbCrToRGB(0, 0, 0)
+ sink8, sink8, sink8 = YCbCrToRGB(0, 0, 0)
}
})
b.Run("128", func(b *testing.B) {
for i := 0; i < b.N; i++ {
- sink, sink, sink = YCbCrToRGB(128, 128, 128)
+ sink8, sink8, sink8 = YCbCrToRGB(128, 128, 128)
}
})
b.Run("255", func(b *testing.B) {
for i := 0; i < b.N; i++ {
- sink, sink, sink = YCbCrToRGB(255, 255, 255)
+ sink8, sink8, sink8 = YCbCrToRGB(255, 255, 255)
}
})
}
@@ -201,17 +202,65 @@ func BenchmarkRGBToYCbCr(b *testing.B) {
// through the generated code.
b.Run("0", func(b *testing.B) {
for i := 0; i < b.N; i++ {
- sink, sink, sink = RGBToYCbCr(0, 0, 0)
+ sink8, sink8, sink8 = RGBToYCbCr(0, 0, 0)
}
})
b.Run("Cb", func(b *testing.B) {
for i := 0; i < b.N; i++ {
- sink, sink, sink = RGBToYCbCr(0, 0, 255)
+ sink8, sink8, sink8 = RGBToYCbCr(0, 0, 255)
}
})
b.Run("Cr", func(b *testing.B) {
for i := 0; i < b.N; i++ {
- sink, sink, sink = RGBToYCbCr(255, 0, 0)
+ sink8, sink8, sink8 = RGBToYCbCr(255, 0, 0)
+ }
+ })
+}
+
+func BenchmarkYCbCrToRGBA(b *testing.B) {
+ // RGB does saturating arithmetic.
+ // Low, middle, and high values can take
+ // different paths through the generated code.
+ b.Run("0", func(b *testing.B) {
+ c := YCbCr{0, 0, 0}
+ for i := 0; i < b.N; i++ {
+ sink32, sink32, sink32, sink32 = c.RGBA()
+ }
+ })
+ b.Run("128", func(b *testing.B) {
+ c := YCbCr{128, 128, 128}
+ for i := 0; i < b.N; i++ {
+ sink32, sink32, sink32, sink32 = c.RGBA()
+ }
+ })
+ b.Run("255", func(b *testing.B) {
+ c := YCbCr{255, 255, 255}
+ for i := 0; i < b.N; i++ {
+ sink32, sink32, sink32, sink32 = c.RGBA()
+ }
+ })
+}
+
+func BenchmarkNYCbCrAToRGBA(b *testing.B) {
+ // RGBA does saturating arithmetic.
+ // Low, middle, and high values can take
+ // different paths through the generated code.
+ b.Run("0", func(b *testing.B) {
+ c := NYCbCrA{YCbCr{0, 0, 0}, 0xff}
+ for i := 0; i < b.N; i++ {
+ sink32, sink32, sink32, sink32 = c.RGBA()
+ }
+ })
+ b.Run("128", func(b *testing.B) {
+ c := NYCbCrA{YCbCr{128, 128, 128}, 0xff}
+ for i := 0; i < b.N; i++ {
+ sink32, sink32, sink32, sink32 = c.RGBA()
+ }
+ })
+ b.Run("255", func(b *testing.B) {
+ c := NYCbCrA{YCbCr{255, 255, 255}, 0xff}
+ for i := 0; i < b.N; i++ {
+ sink32, sink32, sink32, sink32 = c.RGBA()
}
})
}
diff --git a/src/image/draw/bench_test.go b/src/image/draw/bench_test.go
index 7b89f95..a41d7e7 100644
--- a/src/image/draw/bench_test.go
+++ b/src/image/draw/bench_test.go
@@ -74,7 +74,7 @@ func bench(b *testing.B, dcm, scm, mcm color.Model, op Op) {
var src image.Image
switch scm {
case nil:
- src = &image.Uniform{C: color.RGBA{0x11, 0x22, 0x33, 0xff}}
+ src = &image.Uniform{C: color.RGBA{0x11, 0x22, 0x33, 0x44}}
case color.CMYKModel:
src1 := image.NewCMYK(image.Rect(0, 0, srcw, srch))
for y := 0; y < srch; y++ {
diff --git a/src/image/draw/draw.go b/src/image/draw/draw.go
index 6a16cd3..a31dd42 100644
--- a/src/image/draw/draw.go
+++ b/src/image/draw/draw.go
@@ -116,7 +116,12 @@ func DrawMask(dst Image, r image.Rectangle, src image.Image, sp image.Point, mas
if mask == nil {
switch src0 := src.(type) {
case *image.Uniform:
- drawFillOver(dst0, r, src0)
+ sr, sg, sb, sa := src0.RGBA()
+ if sa == 0xffff {
+ drawFillSrc(dst0, r, sr, sg, sb, sa)
+ } else {
+ drawFillOver(dst0, r, sr, sg, sb, sa)
+ }
return
case *image.RGBA:
drawCopyOver(dst0, r, src0, sp)
@@ -150,7 +155,8 @@ func DrawMask(dst Image, r image.Rectangle, src image.Image, sp image.Point, mas
if mask == nil {
switch src0 := src.(type) {
case *image.Uniform:
- drawFillSrc(dst0, r, src0)
+ sr, sg, sb, sa := src0.RGBA()
+ drawFillSrc(dst0, r, sr, sg, sb, sa)
return
case *image.RGBA:
drawCopySrc(dst0, r, src0, sp)
@@ -232,8 +238,7 @@ func DrawMask(dst Image, r image.Rectangle, src image.Image, sp image.Point, mas
}
}
-func drawFillOver(dst *image.RGBA, r image.Rectangle, src *image.Uniform) {
- sr, sg, sb, sa := src.RGBA()
+func drawFillOver(dst *image.RGBA, r image.Rectangle, sr, sg, sb, sa uint32) {
// The 0x101 is here for the same reason as in drawRGBA.
a := (m - sa) * 0x101
i0 := dst.PixOffset(r.Min.X, r.Min.Y)
@@ -255,8 +260,7 @@ func drawFillOver(dst *image.RGBA, r image.Rectangle, src *image.Uniform) {
}
}
-func drawFillSrc(dst *image.RGBA, r image.Rectangle, src *image.Uniform) {
- sr, sg, sb, sa := src.RGBA()
+func drawFillSrc(dst *image.RGBA, r image.Rectangle, sr, sg, sb, sa uint32) {
sr8 := uint8(sr >> 8)
sg8 := uint8(sg >> 8)
sb8 := uint8(sb >> 8)
diff --git a/src/image/draw/example_test.go b/src/image/draw/example_test.go
new file mode 100644
index 0000000..2ccc2f4
--- /dev/null
+++ b/src/image/draw/example_test.go
@@ -0,0 +1,48 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package draw_test
+
+import (
+ "fmt"
+ "image"
+ "image/color"
+ "image/draw"
+ "math"
+)
+
+func ExampleDrawer_floydSteinberg() {
+ const width = 130
+ const height = 50
+
+ im := image.NewGray(image.Rectangle{Max: image.Point{X: width, Y: height}})
+ for x := 0; x < width; x++ {
+ for y := 0; y < height; y++ {
+ dist := math.Sqrt(math.Pow(float64(x-width/2), 2)/3+math.Pow(float64(y-height/2), 2)) / (height / 1.5) * 255
+ var gray uint8
+ if dist > 255 {
+ gray = 255
+ } else {
+ gray = uint8(dist)
+ }
+ im.SetGray(x, y, color.Gray{Y: 255 - gray})
+ }
+ }
+ pi := image.NewPaletted(im.Bounds(), []color.Color{
+ color.Gray{Y: 255},
+ color.Gray{Y: 160},
+ color.Gray{Y: 70},
+ color.Gray{Y: 35},
+ color.Gray{Y: 0},
+ })
+
+ draw.FloydSteinberg.Draw(pi, im.Bounds(), im, image.ZP)
+ shade := []string{" ", "░", "▒", "▓", "█"}
+ for i, p := range pi.Pix {
+ fmt.Print(shade[p])
+ if (i+1)%width == 0 {
+ fmt.Print("\n")
+ }
+ }
+}
diff --git a/src/image/gif/reader.go b/src/image/gif/reader.go
index 6181a94..e611128 100644
--- a/src/image/gif/reader.go
+++ b/src/image/gif/reader.go
@@ -63,6 +63,22 @@ const (
eApplication = 0xFF // Application
)
+func readFull(r io.Reader, b []byte) error {
+ _, err := io.ReadFull(r, b)
+ if err == io.EOF {
+ err = io.ErrUnexpectedEOF
+ }
+ return err
+}
+
+func readByte(r io.ByteReader) (byte, error) {
+ b, err := r.ReadByte()
+ if err == io.EOF {
+ err = io.ErrUnexpectedEOF
+ }
+ return b, err
+}
+
// decoder is the type used to decode a GIF file.
type decoder struct {
r reader
@@ -124,7 +140,7 @@ func (b *blockReader) Read(p []byte) (int, error) {
return 0, b.err
}
b.slice = b.tmp[:blockLen]
- if _, b.err = io.ReadFull(b.r, b.slice); b.err != nil {
+ if b.err = readFull(b.r, b.slice); b.err != nil {
return 0, b.err
}
}
@@ -151,9 +167,9 @@ func (d *decoder) decode(r io.Reader, configOnly bool) error {
}
for {
- c, err := d.r.ReadByte()
+ c, err := readByte(d.r)
if err != nil {
- return err
+ return fmt.Errorf("gif: reading frames: %v", err)
}
switch c {
case sExtension:
@@ -198,9 +214,9 @@ func (d *decoder) decode(r io.Reader, configOnly bool) error {
m.Palette = p
}
}
- litWidth, err := d.r.ReadByte()
+ litWidth, err := readByte(d.r)
if err != nil {
- return err
+ return fmt.Errorf("gif: reading image data: %v", err)
}
if litWidth < 2 || litWidth > 8 {
return fmt.Errorf("gif: pixel size in decode out of range: %d", litWidth)
@@ -209,9 +225,9 @@ func (d *decoder) decode(r io.Reader, configOnly bool) error {
br := &blockReader{r: d.r}
lzwr := lzw.NewReader(br, lzw.LSB, int(litWidth))
defer lzwr.Close()
- if _, err = io.ReadFull(lzwr, m.Pix); err != nil {
+ if err = readFull(lzwr, m.Pix); err != nil {
if err != io.ErrUnexpectedEOF {
- return err
+ return fmt.Errorf("gif: reading image data: %v", err)
}
return errNotEnough
}
@@ -228,13 +244,13 @@ func (d *decoder) decode(r io.Reader, configOnly bool) error {
// See https://golang.org/issue/9856 for an example GIF.
if n, err := lzwr.Read(d.tmp[:1]); n != 0 || (err != io.EOF && err != io.ErrUnexpectedEOF) {
if err != nil {
- return err
+ return fmt.Errorf("gif: reading image data: %v", err)
}
return errTooMuch
}
if n, err := br.Read(d.tmp[:1]); n != 0 || err != io.EOF {
if err != nil {
- return err
+ return fmt.Errorf("gif: reading image data: %v", err)
}
return errTooMuch
}
@@ -264,7 +280,7 @@ func (d *decoder) decode(r io.Reader, configOnly bool) error {
case sTrailer:
if len(d.image) == 0 {
- return io.ErrUnexpectedEOF
+ return fmt.Errorf("gif: missing image data")
}
return nil
@@ -275,13 +291,13 @@ func (d *decoder) decode(r io.Reader, configOnly bool) error {
}
func (d *decoder) readHeaderAndScreenDescriptor() error {
- _, err := io.ReadFull(d.r, d.tmp[:13])
+ err := readFull(d.r, d.tmp[:13])
if err != nil {
- return err
+ return fmt.Errorf("gif: reading header: %v", err)
}
d.vers = string(d.tmp[:6])
if d.vers != "GIF87a" && d.vers != "GIF89a" {
- return fmt.Errorf("gif: can't recognize format %s", d.vers)
+ return fmt.Errorf("gif: can't recognize format %q", d.vers)
}
d.width = int(d.tmp[6]) + int(d.tmp[7])<<8
d.height = int(d.tmp[8]) + int(d.tmp[9])<<8
@@ -298,9 +314,9 @@ func (d *decoder) readHeaderAndScreenDescriptor() error {
func (d *decoder) readColorTable(fields byte) (color.Palette, error) {
n := 1 << (1 + uint(fields&fColorTableBitsMask))
- _, err := io.ReadFull(d.r, d.tmp[:3*n])
+ err := readFull(d.r, d.tmp[:3*n])
if err != nil {
- return nil, fmt.Errorf("gif: short read on color table: %s", err)
+ return nil, fmt.Errorf("gif: reading color table: %s", err)
}
j, p := 0, make(color.Palette, n)
for i := range p {
@@ -311,9 +327,9 @@ func (d *decoder) readColorTable(fields byte) (color.Palette, error) {
}
func (d *decoder) readExtension() error {
- extension, err := d.r.ReadByte()
+ extension, err := readByte(d.r)
if err != nil {
- return err
+ return fmt.Errorf("gif: reading extension: %v", err)
}
size := 0
switch extension {
@@ -324,9 +340,9 @@ func (d *decoder) readExtension() error {
case eComment:
// nothing to do but read the data.
case eApplication:
- b, err := d.r.ReadByte()
+ b, err := readByte(d.r)
if err != nil {
- return err
+ return fmt.Errorf("gif: reading extension: %v", err)
}
// The spec requires size be 11, but Adobe sometimes uses 10.
size = int(b)
@@ -334,8 +350,8 @@ func (d *decoder) readExtension() error {
return fmt.Errorf("gif: unknown extension 0x%.2x", extension)
}
if size > 0 {
- if _, err := io.ReadFull(d.r, d.tmp[:size]); err != nil {
- return err
+ if err := readFull(d.r, d.tmp[:size]); err != nil {
+ return fmt.Errorf("gif: reading extension: %v", err)
}
}
@@ -343,8 +359,11 @@ func (d *decoder) readExtension() error {
// this extension defines a loop count.
if extension == eApplication && string(d.tmp[:size]) == "NETSCAPE2.0" {
n, err := d.readBlock()
- if n == 0 || err != nil {
- return err
+ if err != nil {
+ return fmt.Errorf("gif: reading extension: %v", err)
+ }
+ if n == 0 {
+ return nil
}
if n == 3 && d.tmp[0] == 1 {
d.loopCount = int(d.tmp[1]) | int(d.tmp[2])<<8
@@ -352,14 +371,17 @@ func (d *decoder) readExtension() error {
}
for {
n, err := d.readBlock()
- if n == 0 || err != nil {
- return err
+ if err != nil {
+ return fmt.Errorf("gif: reading extension: %v", err)
+ }
+ if n == 0 {
+ return nil
}
}
}
func (d *decoder) readGraphicControl() error {
- if _, err := io.ReadFull(d.r, d.tmp[:6]); err != nil {
+ if err := readFull(d.r, d.tmp[:6]); err != nil {
return fmt.Errorf("gif: can't read graphic control: %s", err)
}
if d.tmp[0] != 4 {
@@ -379,7 +401,7 @@ func (d *decoder) readGraphicControl() error {
}
func (d *decoder) newImageFromDescriptor() (*image.Paletted, error) {
- if _, err := io.ReadFull(d.r, d.tmp[:9]); err != nil {
+ if err := readFull(d.r, d.tmp[:9]); err != nil {
return nil, fmt.Errorf("gif: can't read image descriptor: %s", err)
}
left := int(d.tmp[0]) + int(d.tmp[1])<<8
@@ -399,11 +421,14 @@ func (d *decoder) newImageFromDescriptor() (*image.Paletted, error) {
}
func (d *decoder) readBlock() (int, error) {
- n, err := d.r.ReadByte()
+ n, err := readByte(d.r)
if n == 0 || err != nil {
return 0, err
}
- return io.ReadFull(d.r, d.tmp[:n])
+ if err := readFull(d.r, d.tmp[:n]); err != nil {
+ return 0, err
+ }
+ return int(n), nil
}
// interlaceScan defines the ordering for a pass of the interlace algorithm.
diff --git a/src/image/gif/reader_test.go b/src/image/gif/reader_test.go
index 90c8149..1267ba0 100644
--- a/src/image/gif/reader_test.go
+++ b/src/image/gif/reader_test.go
@@ -10,6 +10,7 @@ import (
"image"
"image/color"
"reflect"
+ "strings"
"testing"
)
@@ -292,3 +293,19 @@ func TestLoopCount(t *testing.T) {
t.Errorf("loop count mismatch: %d vs %d", img.LoopCount, img1.LoopCount)
}
}
+
+func TestUnexpectedEOF(t *testing.T) {
+ for i := len(testGIF) - 1; i >= 0; i-- {
+ _, err := Decode(bytes.NewReader(testGIF[:i]))
+ if err == errNotEnough {
+ continue
+ }
+ text := ""
+ if err != nil {
+ text = err.Error()
+ }
+ if !strings.HasPrefix(text, "gif:") || !strings.HasSuffix(text, ": unexpected EOF") {
+ t.Errorf("Decode(testGIF[:%d]) = %v, want gif: ...: unexpected EOF", i, err)
+ }
+ }
+}
diff --git a/src/image/png/example_test.go b/src/image/png/example_test.go
new file mode 100644
index 0000000..c437632
--- /dev/null
+++ b/src/image/png/example_test.go
@@ -0,0 +1,77 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package png_test
+
+import (
+ "encoding/base64"
+ "fmt"
+ "image"
+ "image/color"
+ "image/png"
+ "io"
+ "log"
+ "os"
+ "strings"
+)
+
+const gopher = `iVBORw0KGgoAAAANSUhEUgAAAEsAAAA8CAAAAAALAhhPAAAFfUlEQVRYw62XeWwUVRzHf2+OPbo9d7tsWyiyaZti6eWGAhISoIGKECEKCAiJJkYTiUgTMYSIosYYBBIUIxoSPIINEBDi2VhwkQrVsj1ESgu9doHWdrul7ba73WNm3vOPtsseM9MdwvvrzTs+8/t95ze/33sI5BqiabU6m9En8oNjduLnAEDLUsQXFF8tQ5oxK3vmnNmDSMtrncks9Hhtt/qeWZapHb1ha3UqYSWVl2ZmpWgaXMXGohQAvmeop3bjTRtv6SgaK/Pb9/bFzUrYslbFAmHPp+3WhAYdr+7GN/YnpN46Opv55VDsJkoEpMrY/vO2BIYQ6LLvm0ThY3MzDzzeSJeeWNyTkgnIE5ePKsvKlcg/0T9QMzXalwXMlj54z4c0rh/mzEfr+FgWEz2w6uk8dkzFAgcARAgNp1ZYef8b [...]
+
+// gopherPNG creates an io.Reader by decoding the base64 encoded image data string in the gopher constant.
+func gopherPNG() io.Reader { return base64.NewDecoder(base64.StdEncoding, strings.NewReader(gopher)) }
+
+func ExampleDecode() {
+ // This example uses png.Decode which can only decode PNG images.
+ // Consider using the general image.Decode as it can sniff and decode any registered image format.
+ img, err := png.Decode(gopherPNG())
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ levels := []string{" ", "░", "▒", "▓", "█"}
+
+ for y := img.Bounds().Min.Y; y < img.Bounds().Max.Y; y++ {
+ for x := img.Bounds().Min.X; x < img.Bounds().Max.X; x++ {
+ c := color.GrayModel.Convert(img.At(x, y)).(color.Gray)
+ level := c.Y / 51 // 51 * 5 = 255
+ if level == 5 {
+ level--
+ }
+ fmt.Print(levels[level])
+ }
+ fmt.Print("\n")
+ }
+}
+
+func ExampleEncode() {
+ const width, height = 256, 256
+
+ // Create a colored image of the given width and height.
+ img := image.NewNRGBA(image.Rect(0, 0, width, height))
+
+ for y := 0; y < height; y++ {
+ for x := 0; x < width; x++ {
+ img.Set(x, y, color.NRGBA{
+ R: uint8((x + y) & 255),
+ G: uint8((x + y) << 1 & 255),
+ B: uint8((x + y) << 2 & 255),
+ A: 255,
+ })
+ }
+ }
+
+ f, err := os.Create("image.png")
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ if err := png.Encode(f, img); err != nil {
+ f.Close()
+ log.Fatal(err)
+ }
+
+ if err := f.Close(); err != nil {
+ log.Fatal(err)
+ }
+}
diff --git a/src/image/png/reader.go b/src/image/png/reader.go
index 2dd5ed8..32f78f0 100644
--- a/src/image/png/reader.go
+++ b/src/image/png/reader.go
@@ -113,6 +113,11 @@ type decoder struct {
idatLength uint32
tmp [3 * 256]byte
interlace int
+
+ // useTransparent and transparent are used for grayscale and truecolor
+ // transparency, as opposed to palette transparency.
+ useTransparent bool
+ transparent [6]byte
}
// A FormatError reports that the input is not a valid PNG.
@@ -252,20 +257,51 @@ func (d *decoder) parsePLTE(length uint32) error {
}
func (d *decoder) parsetRNS(length uint32) error {
- if length > 256 {
- return FormatError("bad tRNS length")
- }
- n, err := io.ReadFull(d.r, d.tmp[:length])
- if err != nil {
- return err
- }
- d.crc.Write(d.tmp[:n])
switch d.cb {
- case cbG8, cbG16:
- return UnsupportedError("grayscale transparency")
+ case cbG1, cbG2, cbG4, cbG8, cbG16:
+ if length != 2 {
+ return FormatError("bad tRNS length")
+ }
+ n, err := io.ReadFull(d.r, d.tmp[:length])
+ if err != nil {
+ return err
+ }
+ d.crc.Write(d.tmp[:n])
+
+ copy(d.transparent[:], d.tmp[:length])
+ switch d.cb {
+ case cbG1:
+ d.transparent[1] *= 0xff
+ case cbG2:
+ d.transparent[1] *= 0x55
+ case cbG4:
+ d.transparent[1] *= 0x11
+ }
+ d.useTransparent = true
+
case cbTC8, cbTC16:
- return UnsupportedError("truecolor transparency")
+ if length != 6 {
+ return FormatError("bad tRNS length")
+ }
+ n, err := io.ReadFull(d.r, d.tmp[:length])
+ if err != nil {
+ return err
+ }
+ d.crc.Write(d.tmp[:n])
+
+ copy(d.transparent[:], d.tmp[:length])
+ d.useTransparent = true
+
case cbP1, cbP2, cbP4, cbP8:
+ if length > 256 {
+ return FormatError("bad tRNS length")
+ }
+ n, err := io.ReadFull(d.r, d.tmp[:length])
+ if err != nil {
+ return err
+ }
+ d.crc.Write(d.tmp[:n])
+
if len(d.palette) < n {
d.palette = d.palette[:n]
}
@@ -273,7 +309,8 @@ func (d *decoder) parsetRNS(length uint32) error {
rgba := d.palette[i].(color.RGBA)
d.palette[i] = color.NRGBA{rgba.R, rgba.G, rgba.B, d.tmp[i]}
}
- case cbGA8, cbGA16, cbTCA8, cbTCA16:
+
+ default:
return FormatError("tRNS, color type mismatch")
}
return d.verifyChecksum()
@@ -366,7 +403,7 @@ func (d *decoder) decode() (image.Image, error) {
// readImagePass reads a single image pass, sized according to the pass number.
func (d *decoder) readImagePass(r io.Reader, pass int, allocateOnly bool) (image.Image, error) {
- var bitsPerPixel int = 0
+ bitsPerPixel := 0
pixOffset := 0
var (
gray *image.Gray
@@ -394,16 +431,26 @@ func (d *decoder) readImagePass(r io.Reader, pass int, allocateOnly bool) (image
switch d.cb {
case cbG1, cbG2, cbG4, cbG8:
bitsPerPixel = d.depth
- gray = image.NewGray(image.Rect(0, 0, width, height))
- img = gray
+ if d.useTransparent {
+ nrgba = image.NewNRGBA(image.Rect(0, 0, width, height))
+ img = nrgba
+ } else {
+ gray = image.NewGray(image.Rect(0, 0, width, height))
+ img = gray
+ }
case cbGA8:
bitsPerPixel = 16
nrgba = image.NewNRGBA(image.Rect(0, 0, width, height))
img = nrgba
case cbTC8:
bitsPerPixel = 24
- rgba = image.NewRGBA(image.Rect(0, 0, width, height))
- img = rgba
+ if d.useTransparent {
+ nrgba = image.NewNRGBA(image.Rect(0, 0, width, height))
+ img = nrgba
+ } else {
+ rgba = image.NewRGBA(image.Rect(0, 0, width, height))
+ img = rgba
+ }
case cbP1, cbP2, cbP4, cbP8:
bitsPerPixel = d.depth
paletted = image.NewPaletted(image.Rect(0, 0, width, height), d.palette)
@@ -414,16 +461,26 @@ func (d *decoder) readImagePass(r io.Reader, pass int, allocateOnly bool) (image
img = nrgba
case cbG16:
bitsPerPixel = 16
- gray16 = image.NewGray16(image.Rect(0, 0, width, height))
- img = gray16
+ if d.useTransparent {
+ nrgba64 = image.NewNRGBA64(image.Rect(0, 0, width, height))
+ img = nrgba64
+ } else {
+ gray16 = image.NewGray16(image.Rect(0, 0, width, height))
+ img = gray16
+ }
case cbGA16:
bitsPerPixel = 32
nrgba64 = image.NewNRGBA64(image.Rect(0, 0, width, height))
img = nrgba64
case cbTC16:
bitsPerPixel = 48
- rgba64 = image.NewRGBA64(image.Rect(0, 0, width, height))
- img = rgba64
+ if d.useTransparent {
+ nrgba64 = image.NewNRGBA64(image.Rect(0, 0, width, height))
+ img = nrgba64
+ } else {
+ rgba64 = image.NewRGBA64(image.Rect(0, 0, width, height))
+ img = rgba64
+ }
case cbTCA16:
bitsPerPixel = 64
nrgba64 = image.NewNRGBA64(image.Rect(0, 0, width, height))
@@ -483,27 +540,75 @@ func (d *decoder) readImagePass(r io.Reader, pass int, allocateOnly bool) (image
// Convert from bytes to colors.
switch d.cb {
case cbG1:
- for x := 0; x < width; x += 8 {
- b := cdat[x/8]
- for x2 := 0; x2 < 8 && x+x2 < width; x2++ {
- gray.SetGray(x+x2, y, color.Gray{(b >> 7) * 0xff})
- b <<= 1
+ if d.useTransparent {
+ ty := d.transparent[1]
+ for x := 0; x < width; x += 8 {
+ b := cdat[x/8]
+ for x2 := 0; x2 < 8 && x+x2 < width; x2++ {
+ ycol := (b >> 7) * 0xff
+ acol := uint8(0xff)
+ if ycol == ty {
+ acol = 0x00
+ }
+ nrgba.SetNRGBA(x+x2, y, color.NRGBA{ycol, ycol, ycol, acol})
+ b <<= 1
+ }
+ }
+ } else {
+ for x := 0; x < width; x += 8 {
+ b := cdat[x/8]
+ for x2 := 0; x2 < 8 && x+x2 < width; x2++ {
+ gray.SetGray(x+x2, y, color.Gray{(b >> 7) * 0xff})
+ b <<= 1
+ }
}
}
case cbG2:
- for x := 0; x < width; x += 4 {
- b := cdat[x/4]
- for x2 := 0; x2 < 4 && x+x2 < width; x2++ {
- gray.SetGray(x+x2, y, color.Gray{(b >> 6) * 0x55})
- b <<= 2
+ if d.useTransparent {
+ ty := d.transparent[1]
+ for x := 0; x < width; x += 4 {
+ b := cdat[x/4]
+ for x2 := 0; x2 < 4 && x+x2 < width; x2++ {
+ ycol := (b >> 6) * 0x55
+ acol := uint8(0xff)
+ if ycol == ty {
+ acol = 0x00
+ }
+ nrgba.SetNRGBA(x+x2, y, color.NRGBA{ycol, ycol, ycol, acol})
+ b <<= 2
+ }
+ }
+ } else {
+ for x := 0; x < width; x += 4 {
+ b := cdat[x/4]
+ for x2 := 0; x2 < 4 && x+x2 < width; x2++ {
+ gray.SetGray(x+x2, y, color.Gray{(b >> 6) * 0x55})
+ b <<= 2
+ }
}
}
case cbG4:
- for x := 0; x < width; x += 2 {
- b := cdat[x/2]
- for x2 := 0; x2 < 2 && x+x2 < width; x2++ {
- gray.SetGray(x+x2, y, color.Gray{(b >> 4) * 0x11})
- b <<= 4
+ if d.useTransparent {
+ ty := d.transparent[1]
+ for x := 0; x < width; x += 2 {
+ b := cdat[x/2]
+ for x2 := 0; x2 < 2 && x+x2 < width; x2++ {
+ ycol := (b >> 4) * 0x11
+ acol := uint8(0xff)
+ if ycol == ty {
+ acol = 0x00
+ }
+ nrgba.SetNRGBA(x+x2, y, color.NRGBA{ycol, ycol, ycol, acol})
+ b <<= 4
+ }
+ }
+ } else {
+ for x := 0; x < width; x += 2 {
+ b := cdat[x/2]
+ for x2 := 0; x2 < 2 && x+x2 < width; x2++ {
+ gray.SetGray(x+x2, y, color.Gray{(b >> 4) * 0x11})
+ b <<= 4
+ }
}
}
case cbG8:
@@ -515,16 +620,37 @@ func (d *decoder) readImagePass(r io.Reader, pass int, allocateOnly bool) (image
nrgba.SetNRGBA(x, y, color.NRGBA{ycol, ycol, ycol, cdat[2*x+1]})
}
case cbTC8:
- pix, i, j := rgba.Pix, pixOffset, 0
- for x := 0; x < width; x++ {
- pix[i+0] = cdat[j+0]
- pix[i+1] = cdat[j+1]
- pix[i+2] = cdat[j+2]
- pix[i+3] = 0xff
- i += 4
- j += 3
+ if d.useTransparent {
+ pix, i, j := nrgba.Pix, pixOffset, 0
+ tr, tg, tb := d.transparent[1], d.transparent[3], d.transparent[5]
+ for x := 0; x < width; x++ {
+ r := cdat[j+0]
+ g := cdat[j+1]
+ b := cdat[j+2]
+ a := uint8(0xff)
+ if r == tr && g == tg && b == tb {
+ a = 0x00
+ }
+ pix[i+0] = r
+ pix[i+1] = g
+ pix[i+2] = b
+ pix[i+3] = a
+ i += 4
+ j += 3
+ }
+ pixOffset += nrgba.Stride
+ } else {
+ pix, i, j := rgba.Pix, pixOffset, 0
+ for x := 0; x < width; x++ {
+ pix[i+0] = cdat[j+0]
+ pix[i+1] = cdat[j+1]
+ pix[i+2] = cdat[j+2]
+ pix[i+3] = 0xff
+ i += 4
+ j += 3
+ }
+ pixOffset += rgba.Stride
}
- pixOffset += rgba.Stride
case cbP1:
for x := 0; x < width; x += 8 {
b := cdat[x/8]
@@ -575,9 +701,21 @@ func (d *decoder) readImagePass(r io.Reader, pass int, allocateOnly bool) (image
copy(nrgba.Pix[pixOffset:], cdat)
pixOffset += nrgba.Stride
case cbG16:
- for x := 0; x < width; x++ {
- ycol := uint16(cdat[2*x+0])<<8 | uint16(cdat[2*x+1])
- gray16.SetGray16(x, y, color.Gray16{ycol})
+ if d.useTransparent {
+ ty := uint16(d.transparent[0])<<8 | uint16(d.transparent[1])
+ for x := 0; x < width; x++ {
+ ycol := uint16(cdat[2*x+0])<<8 | uint16(cdat[2*x+1])
+ acol := uint16(0xffff)
+ if ycol == ty {
+ acol = 0x0000
+ }
+ nrgba64.SetNRGBA64(x, y, color.NRGBA64{ycol, ycol, ycol, acol})
+ }
+ } else {
+ for x := 0; x < width; x++ {
+ ycol := uint16(cdat[2*x+0])<<8 | uint16(cdat[2*x+1])
+ gray16.SetGray16(x, y, color.Gray16{ycol})
+ }
}
case cbGA16:
for x := 0; x < width; x++ {
@@ -586,11 +724,27 @@ func (d *decoder) readImagePass(r io.Reader, pass int, allocateOnly bool) (image
nrgba64.SetNRGBA64(x, y, color.NRGBA64{ycol, ycol, ycol, acol})
}
case cbTC16:
- for x := 0; x < width; x++ {
- rcol := uint16(cdat[6*x+0])<<8 | uint16(cdat[6*x+1])
- gcol := uint16(cdat[6*x+2])<<8 | uint16(cdat[6*x+3])
- bcol := uint16(cdat[6*x+4])<<8 | uint16(cdat[6*x+5])
- rgba64.SetRGBA64(x, y, color.RGBA64{rcol, gcol, bcol, 0xffff})
+ if d.useTransparent {
+ tr := uint16(d.transparent[0])<<8 | uint16(d.transparent[1])
+ tg := uint16(d.transparent[2])<<8 | uint16(d.transparent[3])
+ tb := uint16(d.transparent[4])<<8 | uint16(d.transparent[5])
+ for x := 0; x < width; x++ {
+ rcol := uint16(cdat[6*x+0])<<8 | uint16(cdat[6*x+1])
+ gcol := uint16(cdat[6*x+2])<<8 | uint16(cdat[6*x+3])
+ bcol := uint16(cdat[6*x+4])<<8 | uint16(cdat[6*x+5])
+ acol := uint16(0xffff)
+ if rcol == tr && gcol == tg && bcol == tb {
+ acol = 0x0000
+ }
+ nrgba64.SetNRGBA64(x, y, color.NRGBA64{rcol, gcol, bcol, acol})
+ }
+ } else {
+ for x := 0; x < width; x++ {
+ rcol := uint16(cdat[6*x+0])<<8 | uint16(cdat[6*x+1])
+ gcol := uint16(cdat[6*x+2])<<8 | uint16(cdat[6*x+3])
+ bcol := uint16(cdat[6*x+4])<<8 | uint16(cdat[6*x+5])
+ rgba64.SetRGBA64(x, y, color.RGBA64{rcol, gcol, bcol, 0xffff})
+ }
}
case cbTCA16:
for x := 0; x < width; x++ {
@@ -709,7 +863,11 @@ func (d *decoder) parseChunk() error {
d.stage = dsSeenPLTE
return d.parsePLTE(length)
case "tRNS":
- if d.stage != dsSeenPLTE {
+ if cbPaletted(d.cb) {
+ if d.stage != dsSeenPLTE {
+ return chunkOrderError
+ }
+ } else if d.stage != dsSeenIHDR {
return chunkOrderError
}
d.stage = dsSeentRNS
diff --git a/src/image/png/reader_test.go b/src/image/png/reader_test.go
index 0bc4203..b9e9f4d 100644
--- a/src/image/png/reader_test.go
+++ b/src/image/png/reader_test.go
@@ -39,6 +39,21 @@ var filenames = []string{
"basn4a16",
"basn6a08",
"basn6a16",
+ "ftbbn0g01",
+ "ftbbn0g02",
+ "ftbbn0g04",
+ "ftbbn2c16",
+ "ftbbn3p08",
+ "ftbgn2c16",
+ "ftbgn3p08",
+ "ftbrn2c08",
+ "ftbwn0g16",
+ "ftbwn3p08",
+ "ftbyn3p08",
+ "ftp0n0g08",
+ "ftp0n2c08",
+ "ftp0n3p08",
+ "ftp1n3p08",
}
var filenamesPaletted = []string{
@@ -64,6 +79,50 @@ func readPNG(filename string) (image.Image, error) {
return Decode(f)
}
+// fakebKGDs maps from filenames to fake bKGD chunks for our approximation to
+// the sng command-line tool. Package png doesn't keep that metadata when
+// png.Decode returns an image.Image.
+var fakebKGDs = map[string]string{
+ "ftbbn0g01": "bKGD {gray: 0;}\n",
+ "ftbbn0g02": "bKGD {gray: 0;}\n",
+ "ftbbn0g04": "bKGD {gray: 0;}\n",
+ "ftbbn2c16": "bKGD {red: 0; green: 0; blue: 65535;}\n",
+ "ftbbn3p08": "bKGD {index: 245}\n",
+ "ftbgn2c16": "bKGD {red: 0; green: 65535; blue: 0;}\n",
+ "ftbgn3p08": "bKGD {index: 245}\n",
+ "ftbrn2c08": "bKGD {red: 255; green: 0; blue: 0;}\n",
+ "ftbwn0g16": "bKGD {gray: 65535;}\n",
+ "ftbwn3p08": "bKGD {index: 0}\n",
+ "ftbyn3p08": "bKGD {index: 245}\n",
+}
+
+// fakegAMAs maps from filenames to fake gAMA chunks for our approximation to
+// the sng command-line tool. Package png doesn't keep that metadata when
+// png.Decode returns an image.Image.
+var fakegAMAs = map[string]string{
+ "ftbbn0g01": "",
+ "ftbbn0g02": "gAMA {0.45455}\n",
+}
+
+// fakeIHDRUsings maps from filenames to fake IHDR "using" lines for our
+// approximation to the sng command-line tool. The PNG model is that
+// transparency (in the tRNS chunk) is separate to the color/grayscale/palette
+// color model (in the IHDR chunk). The Go model is that the concrete
+// image.Image type returned by png.Decode, such as image.RGBA (with all pixels
+// having 100% alpha) or image.NRGBA, encapsulates whether or not the image has
+// transparency. This map is a hack to work around the fact that the Go model
+// can't otherwise discriminate PNG's "IHDR says color (with no alpha) but tRNS
+// says alpha" and "IHDR says color with alpha".
+var fakeIHDRUsings = map[string]string{
+ "ftbbn0g01": " using grayscale;\n",
+ "ftbbn0g02": " using grayscale;\n",
+ "ftbbn0g04": " using grayscale;\n",
+ "ftbbn2c16": " using color;\n",
+ "ftbgn2c16": " using color;\n",
+ "ftbrn2c08": " using color;\n",
+ "ftbwn0g16": " using grayscale;\n",
+}
+
// An approximation of the sng command-line tool.
func sng(w io.WriteCloser, filename string, png image.Image) {
defer w.Close()
@@ -95,25 +154,35 @@ func sng(w io.WriteCloser, filename string, png image.Image) {
// Write the filename and IHDR.
io.WriteString(w, "#SNG: from "+filename+".png\nIHDR {\n")
fmt.Fprintf(w, " width: %d; height: %d; bitdepth: %d;\n", bounds.Dx(), bounds.Dy(), bitdepth)
- switch {
- case cm == color.RGBAModel, cm == color.RGBA64Model:
- io.WriteString(w, " using color;\n")
- case cm == color.NRGBAModel, cm == color.NRGBA64Model:
- io.WriteString(w, " using color alpha;\n")
- case cm == color.GrayModel, cm == color.Gray16Model:
- io.WriteString(w, " using grayscale;\n")
- case cpm != nil:
- io.WriteString(w, " using color palette;\n")
- default:
- io.WriteString(w, "unknown PNG decoder color model\n")
+ if s, ok := fakeIHDRUsings[filename]; ok {
+ io.WriteString(w, s)
+ } else {
+ switch {
+ case cm == color.RGBAModel, cm == color.RGBA64Model:
+ io.WriteString(w, " using color;\n")
+ case cm == color.NRGBAModel, cm == color.NRGBA64Model:
+ io.WriteString(w, " using color alpha;\n")
+ case cm == color.GrayModel, cm == color.Gray16Model:
+ io.WriteString(w, " using grayscale;\n")
+ case cpm != nil:
+ io.WriteString(w, " using color palette;\n")
+ default:
+ io.WriteString(w, "unknown PNG decoder color model\n")
+ }
}
io.WriteString(w, "}\n")
- // We fake a gAMA output. The test files have a gAMA chunk but the go PNG parser ignores it
- // (the PNG spec section 11.3 says "Ancillary chunks may be ignored by a decoder").
- io.WriteString(w, "gAMA {1.0000}\n")
+ // We fake a gAMA chunk. The test files have a gAMA chunk but the go PNG
+ // parser ignores it (the PNG spec section 11.3 says "Ancillary chunks may
+ // be ignored by a decoder").
+ if s, ok := fakegAMAs[filename]; ok {
+ io.WriteString(w, s)
+ } else {
+ io.WriteString(w, "gAMA {1.0000}\n")
+ }
// Write the PLTE and tRNS (if applicable).
+ useTransparent := false
if cpm != nil {
lastAlpha := -1
io.WriteString(w, "PLTE {\n")
@@ -133,6 +202,9 @@ func sng(w io.WriteCloser, filename string, png image.Image) {
fmt.Fprintf(w, " (%3d,%3d,%3d) # rgb = (0x%02x,0x%02x,0x%02x)\n", r, g, b, r, g, b)
}
io.WriteString(w, "}\n")
+ if s, ok := fakebKGDs[filename]; ok {
+ io.WriteString(w, s)
+ }
if lastAlpha != -1 {
io.WriteString(w, "tRNS {\n")
for i := 0; i <= lastAlpha; i++ {
@@ -142,6 +214,42 @@ func sng(w io.WriteCloser, filename string, png image.Image) {
}
io.WriteString(w, "}\n")
}
+ } else if strings.HasPrefix(filename, "ft") {
+ if s, ok := fakebKGDs[filename]; ok {
+ io.WriteString(w, s)
+ }
+ // We fake a tRNS chunk. The test files' grayscale and truecolor
+ // transparent images all have their top left corner transparent.
+ switch c := png.At(0, 0).(type) {
+ case color.NRGBA:
+ if c.A == 0 {
+ useTransparent = true
+ io.WriteString(w, "tRNS {\n")
+ switch filename {
+ case "ftbbn0g01", "ftbbn0g02", "ftbbn0g04":
+ // The standard image package doesn't have a "gray with
+ // alpha" type. Instead, we use an image.NRGBA.
+ fmt.Fprintf(w, " gray: %d;\n", c.R)
+ default:
+ fmt.Fprintf(w, " red: %d; green: %d; blue: %d;\n", c.R, c.G, c.B)
+ }
+ io.WriteString(w, "}\n")
+ }
+ case color.NRGBA64:
+ if c.A == 0 {
+ useTransparent = true
+ io.WriteString(w, "tRNS {\n")
+ switch filename {
+ case "ftbwn0g16":
+ // The standard image package doesn't have a "gray16 with
+ // alpha" type. Instead, we use an image.NRGBA64.
+ fmt.Fprintf(w, " gray: %d;\n", c.R)
+ default:
+ fmt.Fprintf(w, " red: %d; green: %d; blue: %d;\n", c.R, c.G, c.B)
+ }
+ io.WriteString(w, "}\n")
+ }
+ }
}
// Write the IMAGE.
@@ -171,12 +279,30 @@ func sng(w io.WriteCloser, filename string, png image.Image) {
case cm == color.NRGBAModel:
for x := bounds.Min.X; x < bounds.Max.X; x++ {
nrgba := png.At(x, y).(color.NRGBA)
- fmt.Fprintf(w, "%02x%02x%02x%02x ", nrgba.R, nrgba.G, nrgba.B, nrgba.A)
+ switch filename {
+ case "ftbbn0g01", "ftbbn0g02", "ftbbn0g04":
+ fmt.Fprintf(w, "%02x", nrgba.R)
+ default:
+ if useTransparent {
+ fmt.Fprintf(w, "%02x%02x%02x ", nrgba.R, nrgba.G, nrgba.B)
+ } else {
+ fmt.Fprintf(w, "%02x%02x%02x%02x ", nrgba.R, nrgba.G, nrgba.B, nrgba.A)
+ }
+ }
}
case cm == color.NRGBA64Model:
for x := bounds.Min.X; x < bounds.Max.X; x++ {
nrgba64 := png.At(x, y).(color.NRGBA64)
- fmt.Fprintf(w, "%04x%04x%04x%04x ", nrgba64.R, nrgba64.G, nrgba64.B, nrgba64.A)
+ switch filename {
+ case "ftbwn0g16":
+ fmt.Fprintf(w, "%04x ", nrgba64.R)
+ default:
+ if useTransparent {
+ fmt.Fprintf(w, "%04x%04x%04x ", nrgba64.R, nrgba64.G, nrgba64.B)
+ } else {
+ fmt.Fprintf(w, "%04x%04x%04x%04x ", nrgba64.R, nrgba64.G, nrgba64.B, nrgba64.A)
+ }
+ }
}
case cpm != nil:
var b, c int
@@ -256,8 +382,23 @@ func TestReader(t *testing.T) {
}
ps := pb.Text()
ss := sb.Text()
+
+ // Newer versions of the sng command line tool append an optional
+ // color name to the RGB tuple. For example:
+ // # rgb = (0xff,0xff,0xff) grey100
+ // # rgb = (0x00,0x00,0xff) blue1
+ // instead of the older version's plainer:
+ // # rgb = (0xff,0xff,0xff)
+ // # rgb = (0x00,0x00,0xff)
+ // We strip any such name.
+ if strings.Contains(ss, "# rgb = (") && !strings.HasSuffix(ss, ")") {
+ if i := strings.LastIndex(ss, ") "); i >= 0 {
+ ss = ss[:i+1]
+ }
+ }
+
if ps != ss {
- t.Errorf("%s: Mismatch\n%sversus\n%s\n", fn, ps, ss)
+ t.Errorf("%s: Mismatch\n%s\nversus\n%s\n", fn, ps, ss)
break
}
}
diff --git a/src/image/png/testdata/pngsuite/README b/src/image/png/testdata/pngsuite/README
index c0f78bd..01d1d89 100644
--- a/src/image/png/testdata/pngsuite/README
+++ b/src/image/png/testdata/pngsuite/README
@@ -1,21 +1,20 @@
The *.png and README.original files in this directory are copied from
-libpng.org, specifically contrib/pngsuite/* in libpng-1.2.40.tar.gz.
+libpng.org, specifically contrib/pngsuite/* in libpng 1.6.26.
+
README.original gives the following license for those files:
Permission to use, copy, and distribute these images for any purpose
and without fee is hereby granted.
-
-The files basn0g01-30.png, basn0g02-29.png and basn0g04-31.png are in fact
-not part of pngsuite but were created from files in pngsuite. Their non-power-
-of-two sizes makes them useful for testing bit-depths smaller than a byte.
+The files basn0g01-30.png, basn0g02-29.png and basn0g04-31.png are in fact not
+part of pngsuite but were created from files in pngsuite. Their non-power-of-2
+sizes makes them useful for testing bit-depths smaller than a byte.
basn3a08.png was generated from basn6a08.png using the pngnq tool, which
converted it to the 8-bit paletted image with alpha values in tRNS chunk.
-The *.sng files in this directory were generated from the *.png files
-by the sng command-line tool and some hand editing. The files
-basn0g0{1,2,4}.sng were actually generated by first converting the PNG
-to a bitdepth of 8 and then running sng on them. basn4a08.sng was generated
-by from a 16-bit rgba version of basn4a08.png rather than the original
-gray + alpha.
+The *.sng files in this directory were generated from the *.png files by the
+sng command-line tool and some hand editing. The files basn0g0{1,2,4}.sng and
+ftbbn0g0{1,2,4}.sng were actually generated by first converting the PNG to a
+bitdepth of 8 and then running sng on them. basn4a08.sng was generated from a
+16-bit rgba version of basn4a08.png rather than the original gray + alpha.
diff --git a/src/image/png/testdata/pngsuite/ftbbn0g01.png b/src/image/png/testdata/pngsuite/ftbbn0g01.png
new file mode 100644
index 0000000..ba746ff
Binary files /dev/null and b/src/image/png/testdata/pngsuite/ftbbn0g01.png differ
diff --git a/src/image/png/testdata/pngsuite/ftbbn0g01.sng b/src/image/png/testdata/pngsuite/ftbbn0g01.sng
new file mode 100644
index 0000000..c5347a4
--- /dev/null
+++ b/src/image/png/testdata/pngsuite/ftbbn0g01.sng
@@ -0,0 +1,44 @@
+#SNG: from ftbbn0g01.png
+IHDR {
+ width: 32; height: 32; bitdepth: 8;
+ using grayscale;
+}
+bKGD {gray: 0;}
+tRNS {
+ gray: 0;
+}
+IMAGE {
+ pixels hex
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+00ffffffffffffff000000000000000000000000000000000000000000000000
+00ffffffffffffffff0000000000000000000000000000000000000000000000
+00ffffffffffffffffff00000000000000000000000000000000000000000000
+00ffffff0000ffffffff00000000000000000000000000000000000000000000
+00ffffff000000ffffff00000000000000000000000000000000000000000000
+00ffffff000000ffffff00ffffff000000ffffff000000000000000000000000
+00ffffff00ffffffffff00ffffff000000ffffff000000000000000000000000
+00ffffffffffffffffff00ffffffff0000ffffff000000000000000000000000
+00ffffffffffffffff0000ffffffff0000ffffff000000000000000000000000
+00ffffffffff0000000000ffffffffff00ffffff000000000000000000000000
+00ffffff00000000000000ffffffffff00ffffff0000000000ffffffffff0000
+00ffffff00000000000000ffffffffffffffffff000000ffffffffffffffff00
+00ffffff00000000000000ffffffffffffffffff000000ffffffffffffffff00
+00ffffff00000000000000ffffffffffffffffff0000ffffffffff00ffffff00
+0000000000000000000000ffffff00ffffffffff0000ffffffff000000000000
+0000000000000000000000ffffff00ffffffffff0000ffffff00000000000000
+0000000000000000000000ffffff0000ffffffff0000ffffff0000ffffff0000
+0000000000000000000000ffffff000000ffffff0000ffffff00ffffffffff00
+0000000000000000000000ffffff000000ffffff0000ffffff0000ffffffff00
+00000000000000000000000000000000000000000000ffffff00000000ffff00
+00000000000000000000000000000000000000000000ffffffff0000ffffff00
+00000000000000000000000000000000000000000000ffffffffffffffffff00
+0000000000000000000000000000000000000000000000ffffffffffffffff00
+000000000000000000000000000000000000000000000000ffffffffffff0000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+}
diff --git a/src/image/png/testdata/pngsuite/ftbbn0g02.png b/src/image/png/testdata/pngsuite/ftbbn0g02.png
new file mode 100644
index 0000000..3d83bd6
Binary files /dev/null and b/src/image/png/testdata/pngsuite/ftbbn0g02.png differ
diff --git a/src/image/png/testdata/pngsuite/ftbbn0g02.sng b/src/image/png/testdata/pngsuite/ftbbn0g02.sng
new file mode 100644
index 0000000..9686a6a
--- /dev/null
+++ b/src/image/png/testdata/pngsuite/ftbbn0g02.sng
@@ -0,0 +1,45 @@
+#SNG: from ftbbn0g02.png
+IHDR {
+ width: 32; height: 32; bitdepth: 8;
+ using grayscale;
+}
+gAMA {0.45455}
+bKGD {gray: 0;}
+tRNS {
+ gray: 0;
+}
+IMAGE {
+ pixels hex
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+00aaaaaaaaaaaaaa000000000000000000000000000000000000000000000000
+00aaaaaaaaaaaaaaaa0000000000000000000000000000000000000000000000
+00aaaaaaaaaaaaaaaaaa00000000000000000000000000000000000000000000
+00aaaaaa0000aaaaaaaa00000000000000000000000000000000000000000000
+00aaaaaa000000aaaaaa00000000000000000000000000000000000000000000
+00aaaaaa000000aaaaaa00aaaaaa000000aaaaaa000000000000000000000000
+00aaaaaa00aaaaaaaaaa00aaaaaa000000aaaaaa000000000000000000000000
+00aaaaaaaaaaaaaaaaaa00aaaaaaaa0000aaaaaa000000000000000000000000
+00aaaaaaaaaaaaaaaa0000aaaaaaaa0000aaaaaa000000000000000000000000
+00aaaaaaaaaa0000000000aaaaaaaaaa00aaaaaa000000000000000000000000
+00aaaaaa00000000000000aaaaaaaaaa00aaaaaa0000000000aaaaaaaaaa0000
+00aaaaaa00000000000000aaaaaaaaaaaaaaaaaa000000aaaaaaaaaaaaaaaa00
+00aaaaaa00000000000000aaaaaaaaaaaaaaaaaa000000aaaaaaaaaaaaaaaa00
+00aaaaaa00000000000000aaaaaaaaaaaaaaaaaa0000aaaaaaaaaa00aaaaaa00
+0000000000000000000000aaaaaa00aaaaaaaaaa0000aaaaaaaa000000000000
+0000000000000000000000aaaaaa00aaaaaaaaaa0000aaaaaa00000000000000
+0000000000000000000000aaaaaa0000aaaaaaaa0000aaaaaa0000aaaaaa0000
+0000000000000000000000aaaaaa000000aaaaaa0000aaaaaa00aaaaaaaaaa00
+0000000000000000000000aaaaaa000000aaaaaa0000aaaaaa0000aaaaaaaa00
+00000000000000000000000000000000000000000000aaaaaa00000000aaaa00
+00000000000000000000000000000000000000000000aaaaaaaa0000aaaaaa00
+00000000000000000000000000000000000000000000aaaaaaaaaaaaaaaaaa00
+0000000000000000000000000000000000000000000000aaaaaaaaaaaaaaaa00
+000000000000000000000000000000000000000000000000aaaaaaaaaaaa0000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+}
diff --git a/src/image/png/testdata/pngsuite/ftbbn0g04.png b/src/image/png/testdata/pngsuite/ftbbn0g04.png
new file mode 100644
index 0000000..39a7050
Binary files /dev/null and b/src/image/png/testdata/pngsuite/ftbbn0g04.png differ
diff --git a/src/image/png/testdata/pngsuite/ftbbn0g04.sng b/src/image/png/testdata/pngsuite/ftbbn0g04.sng
new file mode 100644
index 0000000..518ba6c
--- /dev/null
+++ b/src/image/png/testdata/pngsuite/ftbbn0g04.sng
@@ -0,0 +1,45 @@
+#SNG: from ftbbn0g04.png
+IHDR {
+ width: 32; height: 32; bitdepth: 8;
+ using grayscale;
+}
+gAMA {1.0000}
+bKGD {gray: 0;}
+tRNS {
+ gray: 255;
+}
+IMAGE {
+ pixels hex
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffddcceeffffffffffffffffffffffffffffff
+ffffffffffffffffffffffeebb776655446699ddffffffffffffffffffffffff
+ffffffffffffffffeebb886666553322222222335599ccffffffffffffffffff
+ffffffffffeecc997766554433333322334422112222336699ccffffffffffff
+ffffffcc997777664433333333444433334444332233335566777799cceeffff
+ffffcc777777775533333344556655444444444444332266777777776699ffff
+ffffdd8888887766444466777777777766555555445566777777775555bbffff
+ffffee8888888888777777777777777777777777777777777766555544eeffff
+ffffff8866667788998888777777777777777777777777665555444455ffffff
+ffffff8866778888999999998877777777777777777755331111334488ffffff
+ffffff99667788889999999999998877777777776655221111111133aaffffff
+ffffff99666688888899997777999999887766555533221111001122ddffffff
+ffffffaa666677888899886666669999997755554422111122111144ffffffff
+ffffffbb666666888888777755669999997755552222113344223377ffffffff
+ffffffcc666655778877777755779999996655332211334422111199ffffffff
+ffffffdd6666446688557777557799999966552222113311111111ccffffffff
+ffffffee6666555588666677557799999966442211222211111122eeffffffff
+ffffffff6666555577775577557799999955332211332211111155ffffffffff
+ffffffff6666665566775577557799999955331111443311111188ffffffffff
+ffffffff88666655667755665577999988552211114433111111ccffffffffff
+ffffffffffaa66666666666655779999885522111133111122bbffffffffffff
+ffffffffffffcc6666666666557788998855221111111122ccffffffffffffff
+ffffffffffffffee886666665577888877553311111133ddffffffffffffffff
+ffffffffffffffffffaa666655778888775544221144eeffffffffffffffffff
+ffffffffffffffffffffcc77557788886655553377ffffffffffffffffffffff
+ffffffffffffffffffffffee9988888866555599ffffffffffffffffffffffff
+ffffffffffffffffffffffffffbb88886655bbffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffdd8866ccffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffeeddffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+}
diff --git a/src/image/png/testdata/pngsuite/ftbbn2c16.png b/src/image/png/testdata/pngsuite/ftbbn2c16.png
new file mode 100644
index 0000000..dd3168e
Binary files /dev/null and b/src/image/png/testdata/pngsuite/ftbbn2c16.png differ
diff --git a/src/image/png/testdata/pngsuite/ftbbn2c16.sng b/src/image/png/testdata/pngsuite/ftbbn2c16.sng
new file mode 100644
index 0000000..76989fa
--- /dev/null
+++ b/src/image/png/testdata/pngsuite/ftbbn2c16.sng
@@ -0,0 +1,45 @@
+#SNG: from ftbbn2c16.png
+IHDR {
+ width: 32; height: 32; bitdepth: 16;
+ using color;
+}
+gAMA {1.0000}
+bKGD {red: 0; green: 0; blue: 65535;}
+tRNS {
+ red: 65535; green: 65535; blue: 65535;
+}
+IMAGE {
+ pixels hex
+ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff e3e3e3e3e3e3 c9c9c9c9c9c9 f1f1f1f1f1f1 ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff e8e8e8e8e8e8 b5b5b5b5b5b5 7e7e7e7e7e7e 656565656565 6e6e52525252 7e7e2e2e2e2e a6a643434343 c7c790909090 ebebdddddddd ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff eeeeeeeeeeee bfbfbfbfbfbf 898989898989 676767676767 6b6b5d5d5d5d 7a7a39393939 8a8a12121212 8d8d00010000 858500000000 777700000000 848400000000 9a9a01010101 a2a22d2d2d2d bfbf7d7d7d7d ddddd0d0d0d0 fcfcfcfcfcfc ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff f2f2f2f2f2f2 c4c4c4c4c4c4 959595959595 727272727272 6f6f6b6b6b6b 777744444444 87871e1e1e1e 959501010101 9f9f00010000 919100000000 808000010000 72720c0c0c0c 61612d2d2d2d 53530e0e0e0e 505000000000 595900010000 858500000000 929206060606 7a7a66666666 a0a0a0a0a0a0 cfcfcfcfcfcf f8f8f8f8f8f8 ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff f7f7f7f7f7f7 cacacacacaca 9a9a9a9a9a9a 767676767676 737373737373 7c7c5d5d5d5d 87872e2e2e2e 939307070707 9e9e00010000 a9a900000000 b0b000000000 c9c900000000 cfcf00000000 b9b900010000 a2a201010101 8c8c19191919 85852a2a2a2a 7f7f13131313 818100010000 969600000000 8f8f00000000 6b6b53535353 6e6e6e6e6e6e 737373737373 767676767676 9b9b9b9b9b9b c4c4c4c4c4c4 eeeeeeeeeeee ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff cccccccccccc 7f7f7f7f7f7f 767676767676 757575757575 757575757575 96962f2f2f2f b8b800010000 b4b400000000 b6b600010000 adad0c0c0c0c 94943a3a3a3a 929250505050 b9b923232323 d6d602020202 e2e200010000 efef00000000 e7e700000000 dada00000000 cfcf00010000 baba00000000 7d7d01010101 6f6f6b6b6b6b 757575757575 757575757575 757575757575 757575757575 6a6a6a6a6a6a 9a9a9a9a9a9a ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff dcdcdcdcdcdc 858585858585 888888888888 848484848484 7b7b7b7b7b7b 858554545454 b7b713131313 a9a91d1d1d1d 8d8d4f4f4f4f 787875757575 777777777777 777777777777 777777777777 81816b6b6b6b aaaa41414141 d6d620202020 ecec10101010 e9e90c0c0c0c d0d012121212 a5a528282828 7b7b58585858 777777777777 777777777777 777777777777 707070707070 5c5c5c5c5c5c 525252525252 bdbdbdbdbdbd ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff eaeaeaeaeaea 848484848484 818181818181 858588888585 8e8e8e8e8e8e 898989898989 7f7f7f7f7f7f 797979797979 797979797979 797979797979 797979797979 797979797979 797979797979 797979797979 797979797979 797979797979 797979797979 797979797979 797979797979 797979797979 797979797979 797979797979 767676767676 636363636363 545454545454 505050505050 4c4c4c4c4c4c e6e6e6e6e6e6 ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff f8f8f8f8f8f8 7f7f84847f7f 252597972525 0404a5a50404 3939a4a43939 8b8b94948b8b 939393939393 8f8f8f8f8f8f 838383838383 7b7b7b7b7b7b 7b7b7b7b7b7b 7b7b7b7b7b7b 7b7b7b7b7b7b 7b7b7b7b7b7b 7b7b7b7b7b7b 7b7b7b7b7b7b 7b7b7b7b7b7b 7b7b7b7b7b7b 7a7a7a7a7a7a 7a7a7a7a7a7a 797979797979 6a6a6a6a6a6a 575757575757 505050505050 4c4c4c4c4c4c 494949494949 595959595959 ffffffffffff ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff ffffffffffff 8a8a8a8a8a8a 0101b3b30101 0000c6c60001 0000f2f20000 5959b6b65959 929292929292 959595959595 979797979797 949494949494 878787878787 7c7c7c7c7c7c 7c7c7c7c7c7c 7c7c7c7c7c7c 7c7c7c7c7c7c 7c7c7c7c7c7c 7c7c7c7c7c7c 7c7c7c7c7c7c 7c7c7c7c7c7c 717171717171 5a5a5a5a6060 282828288585 040404049393 0c0c0c0c7878 282828285858 464646464a4a 828282828282 ffffffffffff ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff ffffffffffff 929292929292 0c0cabab0c0c 0000bdbd0001 0000f4f40000 2020dddd2020 919191919191 949494949494 979797979797 999999999999 9b9b9b9b9b9b 999999999999 8b8b8b8b8b8b 7f7f7f7f7f7f 7e7e7e7e7e7e 7e7e7e7e7e7e 7d7d7d7d7d7d 777777777777 626262626262 535353536060 12121212bebe 00010000cccc 000000009292 000000016969 000000006767 2a2a2a2a5555 acacacacacac ffffffffffff ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff ffffffffffff 949494949494 1616a1a11616 0000b4b40001 0000e2e20000 0000f4f40000 7676a2a27676 939393939393 8d8d97978d8d 46469e9e4646 4646a7a74646 8e8e9e9e8e8e 9e9e9e9e9e9e 9c9c9c9c9c9c 8e8e8e8e8e8e 7e7e7e7e7e7e 6a6a6a6a6a6a 5a5a5a5a5a5a 575757575a5a 18181818cdcd 00010000f0f0 00000000a0a0 020202026060 010101013d3d 000100006161 1d1d1d1d5959 d6d6d6d6d6d6 ffffffffffff ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff ffffffffffff a4a4a4a4a4a4 212198982121 0000aaaa0001 0000c8c80000 0000f4f40000 3b3bcaca3b3b 929292929292 4a4aacac4a4a 0001bcbc0000 0000a9a90000 2f2f9a9a2f2f 9d9d9d9d9d9d 9f9f9f9f9f9f a0a0a0a0a0a0 7a7a7a7a7a7a 5a5a5a5a5a5a 595959595959 31313131a1a1 00010000ffff 00000000c6c6 030303035b5b 191919192424 0c0c0c0c1515 0c0c0c0c5555 3b3b3b3b5353 fbfbfbfbfbfb ffffffffffff ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff ffffffffffff b6b6b6b6b6b6 2b2b8f8f2b2b 0000a2a20001 0000adad0000 0000ebeb0000 0707eded0707 898995958989 4343a7a74343 0001c9c90000 000099990000 383895953838 9c9c9c9c9c9c 9e9e9e9e9e9e 9f9f9f9f9f9f 747474747474 595959595959 505050506767 05050505f5f5 00010000f0f0 030303037070 383838384646 484848484848 161616163939 2b2b2b2b5555 727272727272 ffffffffffff ffffffffffff ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff ffffffffffff c7c7c7c7c7c7 343486863434 0000b1b10001 00008d8d0000 0000d2d20000 0000f3f30000 4c4c9b9b4c4c 3b3b9e9e3b3b 0001c7c70000 000098980000 3d3d94943d3d 9b9b9b9b9b9b 9d9d9d9d9d9d 9e9e9e9e9e9e 6e6e6e6e6e6e 595959595959 2b2b2b2badad 00000001ffff 00000000a6a6 252525255959 434343434f4f 161616167e7e 000000019f9f 010101018e8e 9c9c9c9ca1a1 ffffffffffff ffffffffffff ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff ffffffffffff d8d8d8d8d8d8 3e3e7d7d3e3e 0000b1b10001 00007b7b0000 0000b8b80000 0000f1f10000 17178b8b1717 3b3b9c9c3b3b 0001c6c60000 000097970000 3d3d93933d3d 9a9a9a9a9a9a 9b9b9b9b9b9b 9d9d9d9d9d9d 676767676767 575757575959 09090909eeee 00000001f0f0 040404046b6b 333333335a5a 070707079090 000000009e9e 000000017c7c 0d0d0d0d5d5d c7c7c7c7c7c7 ffffffffffff ffffffffffff ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff ffffffffffff eaeaeaeaeaea 474774744747 0000adad0001 000085850000 090998980909 0000dcdc0000 0000a7a70000 232398982323 0001c3c30000 000096960000 3f3f92923f3f 989898989898 9a9a9a9a9a9a 9c9c9c9c9c9c 616161616161 424242427f7f 00010000ffff 00000001b9b9 1a1a1a1a5d5d 161616164949 000000007b7b 000000006b6b 000000016b6b 1c1c1c1c5656 f4f4f4f4f4f4 ffffffffffff ffffffffffff ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff ffffffffffff fcfcfcfcfcfc 50506c6c5050 0000a9a90001 000095950000 2d2d77772d2d 0000c1c10000 0000c5c50000 010193930101 0001c1c10000 000090900000 4b4b91914b4b 979797979797 999999999999 9a9a9a9a9a9a 5a5a5a5a5a5a 2b2b2b2ba4a4 00010000f6f6 000000018686 2f2f2f2f5353 191919193030 020202026363 000000007373 000000019b9b 4d4d4d4d7070 ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff ffffffffffff ffffffffffff 686873736868 0000a4a40001 0000a4a40000 3e3e65653e3e 1414a5a51414 0000d4d40000 00008b8b0001 0000bfbf0000 00008e8e0000 4a4a90904a4a 959595959595 979797979797 969696969696 575757575757 1a1a1a1ab5b5 00010000dede 000000016868 3f3f3f3f4b4b 2b2b2b2b2b2b 0c0c0c0c6d6d 00000000b3b3 000000016b6b 868686869292 ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff ffffffffffff ffffffffffff 8c8c8c8c8c8c 05059e9e0505 0001b0b00000 343466663434 404085854040 0000caca0000 000097970001 0000bcbc0000 00008c8c0000 49498e8e4949 939393939393 959595959595 8f8f8f8f8f8f 565656565656 0f0f0f0fb7b7 00010000b9b9 030303036666 474747474747 2f2f2f2f6464 00010000a2a2 000000009d9d 090909095858 c5c5c5c5c5c5 ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff ffffffffffff ffffffffffff fafafafafafa 9090b0b09090 343485853434 616164646161 63636a6a6363 0606afaf0606 0000aeae0001 0000b9b90000 00008b8b0000 53538d8d5353 919191919191 939393939393 898989898989 555555555555 0a0a0a0aa8a8 000100009d9d 070707076363 343434345c5c 040404049b9b 00010000b1b1 1a1a1a1a4d4d b5b5b5b5bbbb ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff d0d0d0d0d0d0 6d6d6d6d6d6d 656565656565 2d2d8f8f2d2d 0000b2b20001 0000b6b60000 000089890000 55558b8b5555 8f8f8f8f8f8f 919191919191 818181818181 555555555555 151515157e7e 000100008484 010101016565 010101018484 000100009191 1c1c1c1c6e6e cecececed0d0 ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ecececececec 868686868686 585870705858 0000afaf0001 0000b3b30000 000088880000 535389895353 8d8d8d8d8d8d 8f8f8f8f8f8f 7a7a7a7a7a7a 545454545454 2c2c2c2c4949 020202026b6b 000000016464 000000006363 292929297474 dfdfdfdfe5e5 ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff fcfcfcfcfcfc aaaaaaaaaaaa 212198982121 0001b0b00000 000086860000 575787875757 8b8b8b8b8b8b 8d8d8d8d8d8d 747474747474 535353535353 3d3d3d3d3d3d 1a1a1a1a2323 0d0d0d0d4343 474747477272 ededededefef ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff d1d1d6d6d1d1 38389b9b3838 2d2d77772d2d 7d7d81817d7d 888888888888 8b8b8b8b8b8b 6d6d6d6d6d6d 525252525252 4f4f4f4f4f4f 373737373737 777777777777 fafafafafafa ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff efefefefefef a0a0a0a0a0a0 838383838383 868686868686 888888888888 676767676767 515151515151 505050505050 a0a0a0a0a0a0 fdfdfdfdfdfd ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff fefefefefefe c0c0c0c0c0c0 858585858585 868686868686 616161616161 525252525252 b7b7b7b7b7b7 ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff dededededede 909090909090 656565656565 cccccccccccc ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff f5f5f5f5f5f5 e3e3e3e3e3e3 ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff
+}
diff --git a/src/image/png/testdata/pngsuite/ftbbn3p08.png b/src/image/png/testdata/pngsuite/ftbbn3p08.png
new file mode 100644
index 0000000..0ede357
Binary files /dev/null and b/src/image/png/testdata/pngsuite/ftbbn3p08.png differ
diff --git a/src/image/png/testdata/pngsuite/ftbbn3p08.sng b/src/image/png/testdata/pngsuite/ftbbn3p08.sng
new file mode 100644
index 0000000..429d99b
--- /dev/null
+++ b/src/image/png/testdata/pngsuite/ftbbn3p08.sng
@@ -0,0 +1,292 @@
+#SNG: from ftbbn3p08.png
+IHDR {
+ width: 32; height: 32; bitdepth: 8;
+ using color palette;
+}
+gAMA {1.0000}
+PLTE {
+ (255,255,255) # rgb = (0xff,0xff,0xff) grey100
+ (128, 86, 86) # rgb = (0x80,0x56,0x56)
+ (181,181,184) # rgb = (0xb5,0xb5,0xb8)
+ (168, 66, 66) # rgb = (0xa8,0x42,0x42)
+ (159,159,159) # rgb = (0x9f,0x9f,0x9f)
+ (177, 32, 32) # rgb = (0xb1,0x20,0x20)
+ (139, 21, 21) # rgb = (0x8b,0x15,0x15)
+ (157,157,157) # rgb = (0x9d,0x9d,0x9d)
+ ( 27, 27, 89) # rgb = (0x1b,0x1b,0x59)
+ (155,155,155) # rgb = (0x9b,0x9b,0x9b)
+ ( 0, 0,132) # rgb = (0x00,0x00,0x84)
+ (153,153,153) # rgb = (0x99,0x99,0x99) grey60
+ (143,167,143) # rgb = (0x8f,0xa7,0x8f)
+ (151,151,151) # rgb = (0x97,0x97,0x97)
+ (149,149,149) # rgb = (0x95,0x95,0x95)
+ (147,147,147) # rgb = (0x93,0x93,0x93)
+ ( 41, 41, 86) # rgb = (0x29,0x29,0x56)
+ (145,145,145) # rgb = (0x91,0x91,0x91) grey57
+ ( 0, 0,155) # rgb = (0x00,0x00,0x9b)
+ (143,143,143) # rgb = (0x8f,0x8f,0x8f) grey56
+ (139,149,139) # rgb = (0x8b,0x95,0x8b)
+ ( 46, 46,167) # rgb = (0x2e,0x2e,0xa7)
+ (141,141,141) # rgb = (0x8d,0x8d,0x8d)
+ (128, 0, 0) # rgb = (0x80,0x00,0x00)
+ (139,139,139) # rgb = (0x8b,0x8b,0x8b)
+ (185, 0, 0) # rgb = (0xb9,0x00,0x00)
+ (137,137,137) # rgb = (0x89,0x89,0x89)
+ ( 12, 12,213) # rgb = (0x0c,0x0c,0xd5)
+ (120,117,117) # rgb = (0x78,0x75,0x75)
+ (135,135,135) # rgb = (0x87,0x87,0x87) grey53
+ ( 0, 0,178) # rgb = (0x00,0x00,0xb2)
+ (133,133,133) # rgb = (0x85,0x85,0x85) grey52
+ (165, 0, 0) # rgb = (0xa5,0x00,0x00)
+ (222, 0, 0) # rgb = (0xde,0x00,0x00)
+ (129,129,129) # rgb = (0x81,0x81,0x81)
+ (127,127,127) # rgb = (0x7f,0x7f,0x7f) grey50
+ ( 0, 0,158) # rgb = (0x00,0x00,0x9e)
+ (125,125,125) # rgb = (0x7d,0x7d,0x7d) grey49
+ ( 0, 0,201) # rgb = (0x00,0x00,0xc9)
+ (123,123,123) # rgb = (0x7b,0x7b,0x7b)
+ (121,121,121) # rgb = (0x79,0x79,0x79)
+ ( 55, 55, 86) # rgb = (0x37,0x37,0x56)
+ (119,119,119) # rgb = (0x77,0x77,0x77)
+ (117,117,117) # rgb = (0x75,0x75,0x75) grey46
+ (115,115,115) # rgb = (0x73,0x73,0x73) grey45
+ ( 72,169, 72) # rgb = (0x48,0xa9,0x48)
+ (142, 0, 0) # rgb = (0x8e,0x00,0x00)
+ ( 2, 2,100) # rgb = (0x02,0x02,0x64)
+ ( 0, 0, 98) # rgb = (0x00,0x00,0x62)
+ ( 86,137, 86) # rgb = (0x56,0x89,0x56)
+ ( 40, 40,124) # rgb = (0x28,0x28,0x7c)
+ ( 83,139, 83) # rgb = (0x53,0x8b,0x53)
+ (137,137,143) # rgb = (0x89,0x89,0x8f)
+ (103,103,103) # rgb = (0x67,0x67,0x67)
+ (101,101,101) # rgb = (0x65,0x65,0x65)
+ ( 93,109, 93) # rgb = (0x5d,0x6d,0x5d)
+ ( 19,229, 19) # rgb = (0x13,0xe5,0x13)
+ (134, 38, 38) # rgb = (0x86,0x26,0x26)
+ (111, 45, 45) # rgb = (0x6f,0x2d,0x2d)
+ ( 68,145, 68) # rgb = (0x44,0x91,0x44)
+ ( 97, 97, 97) # rgb = (0x61,0x61,0x61) grey38
+ ( 59,157, 59) # rgb = (0x3b,0x9d,0x3b)
+ ( 68,137, 68) # rgb = (0x44,0x89,0x44)
+ ( 61,147, 61) # rgb = (0x3d,0x93,0x3d)
+ ( 0, 0,164) # rgb = (0x00,0x00,0xa4)
+ ( 0,243, 0) # rgb = (0x00,0xf3,0x00)
+ ( 0,241, 0) # rgb = (0x00,0xf1,0x00)
+ ( 89, 89, 89) # rgb = (0x59,0x59,0x59) grey35
+ ( 87, 87, 87) # rgb = (0x57,0x57,0x57) grey34
+ ( 85, 85, 85) # rgb = (0x55,0x55,0x55)
+ ( 83, 83, 83) # rgb = (0x53,0x53,0x53)
+ ( 52,133, 52) # rgb = (0x34,0x85,0x34)
+ ( 81, 81, 81) # rgb = (0x51,0x51,0x51)
+ ( 36,151, 36) # rgb = (0x24,0x97,0x24)
+ ( 79, 79, 79) # rgb = (0x4f,0x4f,0x4f) grey31
+ ( 58, 58, 65) # rgb = (0x3a,0x3a,0x41)
+ ( 16, 16,186) # rgb = (0x10,0x10,0xba)
+ (178, 15, 15) # rgb = (0xb2,0x0f,0x0f)
+ ( 0,199, 0) # rgb = (0x00,0xc7,0x00)
+ ( 0,197, 0) # rgb = (0x00,0xc5,0x00)
+ (252,252,252) # rgb = (0xfc,0xfc,0xfc) grey99
+ ( 0,195, 0) # rgb = (0x00,0xc3,0x00)
+ ( 4, 4,151) # rgb = (0x04,0x04,0x97)
+ ( 0,193, 0) # rgb = (0x00,0xc1,0x00)
+ ( 45,119, 45) # rgb = (0x2d,0x77,0x2d)
+ (250,250,250) # rgb = (0xfa,0xfa,0xfa) grey98
+ ( 0,191, 0) # rgb = (0x00,0xbf,0x00)
+ ( 0, 0,104) # rgb = (0x00,0x00,0x68)
+ ( 0,189, 0) # rgb = (0x00,0xbd,0x00)
+ (218,212,212) # rgb = (0xda,0xd4,0xd4)
+ ( 16, 16,123) # rgb = (0x10,0x10,0x7b)
+ ( 9,173, 9) # rgb = (0x09,0xad,0x09)
+ (248,248,248) # rgb = (0xf8,0xf8,0xf8)
+ ( 0,185, 0) # rgb = (0x00,0xb9,0x00)
+ ( 0,183, 0) # rgb = (0x00,0xb7,0x00)
+ (156,156,161) # rgb = (0x9c,0x9c,0xa1)
+ (246,246,246) # rgb = (0xf6,0xf6,0xf6)
+ ( 12,161, 12) # rgb = (0x0c,0xa1,0x0c)
+ ( 0,179, 0) # rgb = (0x00,0xb3,0x00)
+ ( 0,177, 0) # rgb = (0x00,0xb1,0x00)
+ ( 16,145, 16) # rgb = (0x10,0x91,0x10)
+ ( 0,171, 0) # rgb = (0x00,0xab,0x00)
+ (242,242,242) # rgb = (0xf2,0xf2,0xf2) grey95
+ ( 0,169, 0) # rgb = (0x00,0xa9,0x00)
+ ( 0,167, 0) # rgb = (0x00,0xa7,0x00)
+ (238,238,238) # rgb = (0xee,0xee,0xee)
+ (236,236,236) # rgb = (0xec,0xec,0xec)
+ ( 0,151, 0) # rgb = (0x00,0x97,0x00)
+ (234,234,234) # rgb = (0xea,0xea,0xea)
+ ( 0, 0,107) # rgb = (0x00,0x00,0x6b)
+ ( 0,141, 0) # rgb = (0x00,0x8d,0x00)
+ ( 0,139, 0) # rgb = (0x00,0x8b,0x00) green4
+ ( 0,137, 0) # rgb = (0x00,0x89,0x00)
+ ( 0,135, 0) # rgb = (0x00,0x87,0x00)
+ ( 49, 49, 49) # rgb = (0x31,0x31,0x31)
+ ( 25, 25, 42) # rgb = (0x19,0x19,0x2a)
+ ( 7, 7, 64) # rgb = (0x07,0x07,0x40)
+ ( 18, 18,174) # rgb = (0x12,0x12,0xae)
+ ( 9, 9,238) # rgb = (0x09,0x09,0xee)
+ (211,214,211) # rgb = (0xd3,0xd6,0xd3)
+ (204,204,204) # rgb = (0xcc,0xcc,0xcc) grey80
+ (147, 0, 0) # rgb = (0x93,0x00,0x00)
+ (163, 42, 42) # rgb = (0xa3,0x2a,0x2a)
+ (198,198,198) # rgb = (0xc6,0xc6,0xc6)
+ (196,196,196) # rgb = (0xc4,0xc4,0xc4) grey77
+ (204, 0, 0) # rgb = (0xcc,0x00,0x00)
+ (211, 10, 10) # rgb = (0xd3,0x0a,0x0a)
+ (129,107,107) # rgb = (0x81,0x6b,0x6b)
+ (120, 62, 62) # rgb = (0x78,0x3e,0x3e)
+ ( 3, 3,109) # rgb = (0x03,0x03,0x6d)
+ ( 0, 0,159) # rgb = (0x00,0x00,0x9f)
+ ( 10, 10, 86) # rgb = (0x0a,0x0a,0x56)
+ ( 70, 70, 72) # rgb = (0x46,0x46,0x48)
+ ( 65, 65, 77) # rgb = (0x41,0x41,0x4d)
+ (115, 93, 93) # rgb = (0x73,0x5d,0x5d)
+ ( 81, 7, 7) # rgb = (0x51,0x07,0x07)
+ (168,168,168) # rgb = (0xa8,0xa8,0xa8) grey66
+ (237,237,239) # rgb = (0xed,0xed,0xef)
+ (160,160,160) # rgb = (0xa0,0xa0,0xa0)
+ (158,158,158) # rgb = (0x9e,0x9e,0x9e) grey62
+ (156,156,156) # rgb = (0x9c,0x9c,0x9c) grey61
+ ( 0, 0,185) # rgb = (0x00,0x00,0xb9)
+ (154,154,154) # rgb = (0x9a,0x9a,0x9a)
+ (178, 0, 0) # rgb = (0xb2,0x00,0x00)
+ (152,152,152) # rgb = (0x98,0x98,0x98)
+ (235, 0, 0) # rgb = (0xeb,0x00,0x00)
+ (150,150,150) # rgb = (0x96,0x96,0x96) grey59
+ (158, 0, 0) # rgb = (0x9e,0x00,0x00)
+ (148,148,148) # rgb = (0x94,0x94,0x94) grey58
+ ( 19, 19, 28) # rgb = (0x13,0x13,0x1c)
+ (146,146,146) # rgb = (0x92,0x92,0x92)
+ (144,144,144) # rgb = (0x90,0x90,0x90)
+ (142,142,142) # rgb = (0x8e,0x8e,0x8e)
+ ( 0, 0,145) # rgb = (0x00,0x00,0x91)
+ (138,138,138) # rgb = (0x8a,0x8a,0x8a) grey54
+ (136,136,136) # rgb = (0x88,0x88,0x88)
+ (118,162,118) # rgb = (0x76,0xa2,0x76)
+ (133,136,133) # rgb = (0x85,0x88,0x85)
+ (134,134,134) # rgb = (0x86,0x86,0x86)
+ (132,132,132) # rgb = (0x84,0x84,0x84)
+ (120, 15, 15) # rgb = (0x78,0x0f,0x0f)
+ (130,130,130) # rgb = (0x82,0x82,0x82) grey51
+ (126,130,126) # rgb = (0x7e,0x82,0x7e)
+ (126,126,126) # rgb = (0x7e,0x7e,0x7e)
+ (124,124,124) # rgb = (0x7c,0x7c,0x7c)
+ (122,122,122) # rgb = (0x7a,0x7a,0x7a) grey48
+ ( 74,192, 74) # rgb = (0x4a,0xc0,0x4a)
+ (118,118,118) # rgb = (0x76,0x76,0x76)
+ (116,116,116) # rgb = (0x74,0x74,0x74)
+ (114,114,114) # rgb = (0x72,0x72,0x72)
+ (112,112,112) # rgb = (0x70,0x70,0x70) grey44
+ (152, 0, 0) # rgb = (0x98,0x00,0x00)
+ (110,110,110) # rgb = (0x6e,0x6e,0x6e) grey43
+ (106,112,106) # rgb = (0x6a,0x70,0x6a)
+ (122,102,102) # rgb = (0x7a,0x66,0x66)
+ (106,106,106) # rgb = (0x6a,0x6a,0x6a)
+ (132, 0, 0) # rgb = (0x84,0x00,0x00)
+ ( 68,162, 68) # rgb = (0x44,0xa2,0x44)
+ ( 75,150, 75) # rgb = (0x4b,0x96,0x4b)
+ ( 97,100, 97) # rgb = (0x61,0x64,0x61)
+ ( 98, 98, 98) # rgb = (0x62,0x62,0x62)
+ ( 0,244, 0) # rgb = (0x00,0xf4,0x00)
+ ( 56,152, 56) # rgb = (0x38,0x98,0x38)
+ ( 92, 92, 92) # rgb = (0x5c,0x5c,0x5c) grey36
+ ( 90, 90, 90) # rgb = (0x5a,0x5a,0x5a)
+ ( 0,230, 0) # rgb = (0x00,0xe6,0x00)
+ ( 2, 2, 93) # rgb = (0x02,0x02,0x5d)
+ ( 66,120, 66) # rgb = (0x42,0x78,0x42)
+ ( 86, 86, 86) # rgb = (0x56,0x56,0x56)
+ ( 0, 0,240) # rgb = (0x00,0x00,0xf0)
+ ( 46,148, 46) # rgb = (0x2e,0x94,0x2e)
+ ( 71,104, 71) # rgb = (0x47,0x68,0x47)
+ ( 49, 49, 96) # rgb = (0x31,0x31,0x60)
+ ( 0,216, 0) # rgb = (0x00,0xd8,0x00)
+ ( 82, 82, 82) # rgb = (0x52,0x52,0x52) grey32
+ ( 80, 80, 80) # rgb = (0x50,0x50,0x50)
+ ( 0,206, 0) # rgb = (0x00,0xce,0x00)
+ ( 33,152, 33) # rgb = (0x21,0x98,0x21)
+ ( 20, 20,109) # rgb = (0x14,0x14,0x6d)
+ ( 0,200, 0) # rgb = (0x00,0xc8,0x00)
+ ( 76, 76, 76) # rgb = (0x4c,0x4c,0x4c)
+ (253,253,253) # rgb = (0xfd,0xfd,0xfd)
+ ( 0,198, 0) # rgb = (0x00,0xc6,0x00)
+ ( 0, 0,157) # rgb = (0x00,0x00,0x9d)
+ (111,107,107) # rgb = (0x6f,0x6b,0x6b)
+ (234, 14, 14) # rgb = (0xea,0x0e,0x0e)
+ ( 72, 72, 72) # rgb = (0x48,0x48,0x48)
+ ( 0,188, 0) # rgb = (0x00,0xbc,0x00)
+ ( 52,102, 52) # rgb = (0x34,0x66,0x34)
+ ( 2, 2,245) # rgb = (0x02,0x02,0xf5)
+ ( 83, 83, 96) # rgb = (0x53,0x53,0x60)
+ ( 0,176, 0) # rgb = (0x00,0xb0,0x00)
+ ( 0,174, 0) # rgb = (0x00,0xae,0x00)
+ (183, 0, 0) # rgb = (0xb7,0x00,0x00)
+ ( 0,164, 0) # rgb = (0x00,0xa4,0x00)
+ (239,239,239) # rgb = (0xef,0xef,0xef)
+ ( 0,162, 0) # rgb = (0x00,0xa2,0x00)
+ (143, 79, 79) # rgb = (0x8f,0x4f,0x4f)
+ (149, 52, 52) # rgb = (0x95,0x34,0x34)
+ ( 0,152, 0) # rgb = (0x00,0x98,0x00)
+ ( 0,150, 0) # rgb = (0x00,0x96,0x00)
+ ( 0,146, 0) # rgb = (0x00,0x92,0x00)
+ (231,231,231) # rgb = (0xe7,0xe7,0xe7)
+ ( 0,140, 0) # rgb = (0x00,0x8c,0x00)
+ (227,227,227) # rgb = (0xe3,0xe3,0xe3) grey89
+ ( 0,128, 0) # rgb = (0x00,0x80,0x00)
+ (146, 6, 6) # rgb = (0x92,0x06,0x06)
+ ( 1, 1,111) # rgb = (0x01,0x01,0x6f)
+ (100, 86, 89) # rgb = (0x64,0x56,0x59)
+ ( 0, 0,100) # rgb = (0x00,0x00,0x64)
+ ( 78, 78,107) # rgb = (0x4e,0x4e,0x6b)
+ (207,207,207) # rgb = (0xcf,0xcf,0xcf) grey81
+ (221,221,224) # rgb = (0xdd,0xdd,0xe0)
+ ( 0, 0,123) # rgb = (0x00,0x00,0x7b)
+ (201,201,201) # rgb = (0xc9,0xc9,0xc9) grey79
+ ( 22, 22, 65) # rgb = (0x16,0x16,0x41)
+ ( 33, 33, 89) # rgb = (0x21,0x21,0x59)
+ ( 87, 87, 89) # rgb = (0x57,0x57,0x59)
+ ( 68, 68,120) # rgb = (0x44,0x44,0x78)
+ (191,191,191) # rgb = (0xbf,0xbf,0xbf) grey75
+ (235,221,221) # rgb = (0xeb,0xdd,0xdd)
+ ( 45, 45, 84) # rgb = (0x2d,0x2d,0x54)
+ ( 10, 10, 96) # rgb = (0x0a,0x0a,0x60)
+ ( 0, 0,255) # rgb = (0x00,0x00,0xff) blue1
+ (191,125,125) # rgb = (0xbf,0x7d,0x7d)
+ ( 0, 0, 0) # rgb = (0x00,0x00,0x00) grey0
+}
+bKGD {index: 245}
+tRNS {
+ 0}
+IMAGE {
+ pixels hex
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000e0ea66000000000000000000000000000000
+0000000000000000000000de02a336e43903f4f0000000000000000000000000
+000000000000000069ef1a358680062eb017b0ab7af459500000000000000000
+0000000000667c0ea9cc803979937917a03a878787b0e2ae8ae75c0000000000
+00005cea8ea72c8639e293208f7d7d19200639a017ab2ee4ac2ca7097c690000
+00007823a72b2bda198fd54ddad90521219191217d1917cc2b2b2b2baf8e0000
+0000e81f9b9f27014d05d91c2a2a2a7f037ecdcd7e7a012a2a2aaab7c2ef0000
+00006c9f229d981a23282828282828282828282828282828a7b445c3c8de0000
+00005ca249d63d140f139f272727272727272727a5a528af44c3c8ce43000000
+0000009a62ca41a6960e0d941da4a4a4a4a4a4a4a4a9b732525a1084a1000000
+000000965b58b53811940d0b090b1823a3a3252ab4d24c269957571088000000
+000000946162b9b59c0f14b12d0c8b8c98a3afb8ed1bbd82ba74300877000000
+00000088c565c7b5a6962dcf67be07048aa5b84315f326ba7395832950000000
+00000002bed8d4b94214b1c7dbb68c8b04a843e6d1bd814bceeb10a900000000
+0000007b47636ec441b23d4edb3f09078bac4315f340ec855a82995f00000000
+00000059bb63e15d42643dca6b3f8e090735ed76bd81c05224e9f27b00000000
+0000006cbbd47161c1684951dc3f908e8c3ceef38d08ebe96d6d086000000000
+00000050bf67dc54534fdd53ddb20d0b8eb815d10af1732fe312e60000000000
+00000000add6d6bf61c16f566eb20e0d924475bd578572c61e6d340000000000
+0000000016d8d3d03ec76bcfdf3b0f0e13bc4c8d2f84c040cb837b0000000000
+00000000550c47b3365bd45d6f33110f1a4575cbf2c0521e0802000000000000
+000000000000e7ac36be625e7031131122455a0a2f0a99c6e700000000000000
+000000000000006a9e37d36270331613a545f181e53032e80000000000000000
+00000000000000005088c5d371311816a8464b7374ee89000000000000000000
+0000000000000000000077b654a29b18acc24a722a5500000000000000000000
+0000000000000000000000d78a9f9e9b3548c38ac90000000000000000000000
+00000000000000000000000000ef1f9e3cc20200000000000000000000000000
+0000000000000000000000000000e89736780000000000000000000000000000
+00000000000000000000000000000060e0000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+}
diff --git a/src/image/png/testdata/pngsuite/ftbgn2c16.png b/src/image/png/testdata/pngsuite/ftbgn2c16.png
new file mode 100644
index 0000000..85cec39
Binary files /dev/null and b/src/image/png/testdata/pngsuite/ftbgn2c16.png differ
diff --git a/src/image/png/testdata/pngsuite/ftbgn2c16.sng b/src/image/png/testdata/pngsuite/ftbgn2c16.sng
new file mode 100644
index 0000000..0f5621d
--- /dev/null
+++ b/src/image/png/testdata/pngsuite/ftbgn2c16.sng
@@ -0,0 +1,45 @@
+#SNG: from ftbgn2c16.png
+IHDR {
+ width: 32; height: 32; bitdepth: 16;
+ using color;
+}
+gAMA {1.0000}
+bKGD {red: 0; green: 65535; blue: 0;}
+tRNS {
+ red: 65535; green: 65535; blue: 65535;
+}
+IMAGE {
+ pixels hex
+ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff e3e3e3e3e3e3 c9c9c9c9c9c9 f1f1f1f1f1f1 ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff e8e8e8e8e8e8 b5b5b5b5b5b5 7e7e7e7e7e7e 656565656565 6e6e52525252 7e7e2e2e2e2e a6a643434343 c7c790909090 ebebdddddddd ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff eeeeeeeeeeee bfbfbfbfbfbf 898989898989 676767676767 6b6b5d5d5d5d 7a7a39393939 8a8a12121212 8d8d00010000 858500000000 777700000000 848400000000 9a9a01010101 a2a22d2d2d2d bfbf7d7d7d7d ddddd0d0d0d0 fcfcfcfcfcfc ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff f2f2f2f2f2f2 c4c4c4c4c4c4 959595959595 727272727272 6f6f6b6b6b6b 777744444444 87871e1e1e1e 959501010101 9f9f00010000 919100000000 808000010000 72720c0c0c0c 61612d2d2d2d 53530e0e0e0e 505000000000 595900010000 858500000000 929206060606 7a7a66666666 a0a0a0a0a0a0 cfcfcfcfcfcf f8f8f8f8f8f8 ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff f7f7f7f7f7f7 cacacacacaca 9a9a9a9a9a9a 767676767676 737373737373 7c7c5d5d5d5d 87872e2e2e2e 939307070707 9e9e00010000 a9a900000000 b0b000000000 c9c900000000 cfcf00000000 b9b900010000 a2a201010101 8c8c19191919 85852a2a2a2a 7f7f13131313 818100010000 969600000000 8f8f00000000 6b6b53535353 6e6e6e6e6e6e 737373737373 767676767676 9b9b9b9b9b9b c4c4c4c4c4c4 eeeeeeeeeeee ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff cccccccccccc 7f7f7f7f7f7f 767676767676 757575757575 757575757575 96962f2f2f2f b8b800010000 b4b400000000 b6b600010000 adad0c0c0c0c 94943a3a3a3a 929250505050 b9b923232323 d6d602020202 e2e200010000 efef00000000 e7e700000000 dada00000000 cfcf00010000 baba00000000 7d7d01010101 6f6f6b6b6b6b 757575757575 757575757575 757575757575 757575757575 6a6a6a6a6a6a 9a9a9a9a9a9a ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff dcdcdcdcdcdc 858585858585 888888888888 848484848484 7b7b7b7b7b7b 858554545454 b7b713131313 a9a91d1d1d1d 8d8d4f4f4f4f 787875757575 777777777777 777777777777 777777777777 81816b6b6b6b aaaa41414141 d6d620202020 ecec10101010 e9e90c0c0c0c d0d012121212 a5a528282828 7b7b58585858 777777777777 777777777777 777777777777 707070707070 5c5c5c5c5c5c 525252525252 bdbdbdbdbdbd ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff eaeaeaeaeaea 848484848484 818181818181 858588888585 8e8e8e8e8e8e 898989898989 7f7f7f7f7f7f 797979797979 797979797979 797979797979 797979797979 797979797979 797979797979 797979797979 797979797979 797979797979 797979797979 797979797979 797979797979 797979797979 797979797979 797979797979 767676767676 636363636363 545454545454 505050505050 4c4c4c4c4c4c e6e6e6e6e6e6 ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff f8f8f8f8f8f8 7f7f84847f7f 252597972525 0404a5a50404 3939a4a43939 8b8b94948b8b 939393939393 8f8f8f8f8f8f 838383838383 7b7b7b7b7b7b 7b7b7b7b7b7b 7b7b7b7b7b7b 7b7b7b7b7b7b 7b7b7b7b7b7b 7b7b7b7b7b7b 7b7b7b7b7b7b 7b7b7b7b7b7b 7b7b7b7b7b7b 7a7a7a7a7a7a 7a7a7a7a7a7a 797979797979 6a6a6a6a6a6a 575757575757 505050505050 4c4c4c4c4c4c 494949494949 595959595959 ffffffffffff ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff ffffffffffff 8a8a8a8a8a8a 0101b3b30101 0000c6c60001 0000f2f20000 5959b6b65959 929292929292 959595959595 979797979797 949494949494 878787878787 7c7c7c7c7c7c 7c7c7c7c7c7c 7c7c7c7c7c7c 7c7c7c7c7c7c 7c7c7c7c7c7c 7c7c7c7c7c7c 7c7c7c7c7c7c 7c7c7c7c7c7c 717171717171 5a5a5a5a6060 282828288585 040404049393 0c0c0c0c7878 282828285858 464646464a4a 828282828282 ffffffffffff ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff ffffffffffff 929292929292 0c0cabab0c0c 0000bdbd0001 0000f4f40000 2020dddd2020 919191919191 949494949494 979797979797 999999999999 9b9b9b9b9b9b 999999999999 8b8b8b8b8b8b 7f7f7f7f7f7f 7e7e7e7e7e7e 7e7e7e7e7e7e 7d7d7d7d7d7d 777777777777 626262626262 535353536060 12121212bebe 00010000cccc 000000009292 000000016969 000000006767 2a2a2a2a5555 acacacacacac ffffffffffff ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff ffffffffffff 949494949494 1616a1a11616 0000b4b40001 0000e2e20000 0000f4f40000 7676a2a27676 939393939393 8d8d97978d8d 46469e9e4646 4646a7a74646 8e8e9e9e8e8e 9e9e9e9e9e9e 9c9c9c9c9c9c 8e8e8e8e8e8e 7e7e7e7e7e7e 6a6a6a6a6a6a 5a5a5a5a5a5a 575757575a5a 18181818cdcd 00010000f0f0 00000000a0a0 020202026060 010101013d3d 000100006161 1d1d1d1d5959 d6d6d6d6d6d6 ffffffffffff ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff ffffffffffff a4a4a4a4a4a4 212198982121 0000aaaa0001 0000c8c80000 0000f4f40000 3b3bcaca3b3b 929292929292 4a4aacac4a4a 0001bcbc0000 0000a9a90000 2f2f9a9a2f2f 9d9d9d9d9d9d 9f9f9f9f9f9f a0a0a0a0a0a0 7a7a7a7a7a7a 5a5a5a5a5a5a 595959595959 31313131a1a1 00010000ffff 00000000c6c6 030303035b5b 191919192424 0c0c0c0c1515 0c0c0c0c5555 3b3b3b3b5353 fbfbfbfbfbfb ffffffffffff ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff ffffffffffff b6b6b6b6b6b6 2b2b8f8f2b2b 0000a2a20001 0000adad0000 0000ebeb0000 0707eded0707 898995958989 4343a7a74343 0001c9c90000 000099990000 383895953838 9c9c9c9c9c9c 9e9e9e9e9e9e 9f9f9f9f9f9f 747474747474 595959595959 505050506767 05050505f5f5 00010000f0f0 030303037070 383838384646 484848484848 161616163939 2b2b2b2b5555 727272727272 ffffffffffff ffffffffffff ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff ffffffffffff c7c7c7c7c7c7 343486863434 0000b1b10001 00008d8d0000 0000d2d20000 0000f3f30000 4c4c9b9b4c4c 3b3b9e9e3b3b 0001c7c70000 000098980000 3d3d94943d3d 9b9b9b9b9b9b 9d9d9d9d9d9d 9e9e9e9e9e9e 6e6e6e6e6e6e 595959595959 2b2b2b2badad 00000001ffff 00000000a6a6 252525255959 434343434f4f 161616167e7e 000000019f9f 010101018e8e 9c9c9c9ca1a1 ffffffffffff ffffffffffff ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff ffffffffffff d8d8d8d8d8d8 3e3e7d7d3e3e 0000b1b10001 00007b7b0000 0000b8b80000 0000f1f10000 17178b8b1717 3b3b9c9c3b3b 0001c6c60000 000097970000 3d3d93933d3d 9a9a9a9a9a9a 9b9b9b9b9b9b 9d9d9d9d9d9d 676767676767 575757575959 09090909eeee 00000001f0f0 040404046b6b 333333335a5a 070707079090 000000009e9e 000000017c7c 0d0d0d0d5d5d c7c7c7c7c7c7 ffffffffffff ffffffffffff ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff ffffffffffff eaeaeaeaeaea 474774744747 0000adad0001 000085850000 090998980909 0000dcdc0000 0000a7a70000 232398982323 0001c3c30000 000096960000 3f3f92923f3f 989898989898 9a9a9a9a9a9a 9c9c9c9c9c9c 616161616161 424242427f7f 00010000ffff 00000001b9b9 1a1a1a1a5d5d 161616164949 000000007b7b 000000006b6b 000000016b6b 1c1c1c1c5656 f4f4f4f4f4f4 ffffffffffff ffffffffffff ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff ffffffffffff fcfcfcfcfcfc 50506c6c5050 0000a9a90001 000095950000 2d2d77772d2d 0000c1c10000 0000c5c50000 010193930101 0001c1c10000 000090900000 4b4b91914b4b 979797979797 999999999999 9a9a9a9a9a9a 5a5a5a5a5a5a 2b2b2b2ba4a4 00010000f6f6 000000018686 2f2f2f2f5353 191919193030 020202026363 000000007373 000000019b9b 4d4d4d4d7070 ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff ffffffffffff ffffffffffff 686873736868 0000a4a40001 0000a4a40000 3e3e65653e3e 1414a5a51414 0000d4d40000 00008b8b0001 0000bfbf0000 00008e8e0000 4a4a90904a4a 959595959595 979797979797 969696969696 575757575757 1a1a1a1ab5b5 00010000dede 000000016868 3f3f3f3f4b4b 2b2b2b2b2b2b 0c0c0c0c6d6d 00000000b3b3 000000016b6b 868686869292 ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff ffffffffffff ffffffffffff 8c8c8c8c8c8c 05059e9e0505 0001b0b00000 343466663434 404085854040 0000caca0000 000097970001 0000bcbc0000 00008c8c0000 49498e8e4949 939393939393 959595959595 8f8f8f8f8f8f 565656565656 0f0f0f0fb7b7 00010000b9b9 030303036666 474747474747 2f2f2f2f6464 00010000a2a2 000000009d9d 090909095858 c5c5c5c5c5c5 ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff ffffffffffff ffffffffffff fafafafafafa 9090b0b09090 343485853434 616164646161 63636a6a6363 0606afaf0606 0000aeae0001 0000b9b90000 00008b8b0000 53538d8d5353 919191919191 939393939393 898989898989 555555555555 0a0a0a0aa8a8 000100009d9d 070707076363 343434345c5c 040404049b9b 00010000b1b1 1a1a1a1a4d4d b5b5b5b5bbbb ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff d0d0d0d0d0d0 6d6d6d6d6d6d 656565656565 2d2d8f8f2d2d 0000b2b20001 0000b6b60000 000089890000 55558b8b5555 8f8f8f8f8f8f 919191919191 818181818181 555555555555 151515157e7e 000100008484 010101016565 010101018484 000100009191 1c1c1c1c6e6e cecececed0d0 ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ecececececec 868686868686 585870705858 0000afaf0001 0000b3b30000 000088880000 535389895353 8d8d8d8d8d8d 8f8f8f8f8f8f 7a7a7a7a7a7a 545454545454 2c2c2c2c4949 020202026b6b 000000016464 000000006363 292929297474 dfdfdfdfe5e5 ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff fcfcfcfcfcfc aaaaaaaaaaaa 212198982121 0001b0b00000 000086860000 575787875757 8b8b8b8b8b8b 8d8d8d8d8d8d 747474747474 535353535353 3d3d3d3d3d3d 1a1a1a1a2323 0d0d0d0d4343 474747477272 ededededefef ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff d1d1d6d6d1d1 38389b9b3838 2d2d77772d2d 7d7d81817d7d 888888888888 8b8b8b8b8b8b 6d6d6d6d6d6d 525252525252 4f4f4f4f4f4f 373737373737 777777777777 fafafafafafa ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff efefefefefef a0a0a0a0a0a0 838383838383 868686868686 888888888888 676767676767 515151515151 505050505050 a0a0a0a0a0a0 fdfdfdfdfdfd ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff fefefefefefe c0c0c0c0c0c0 858585858585 868686868686 616161616161 525252525252 b7b7b7b7b7b7 ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff dededededede 909090909090 656565656565 cccccccccccc ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff f5f5f5f5f5f5 e3e3e3e3e3e3 ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff
+ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff ffffffffffff
+}
diff --git a/src/image/png/testdata/pngsuite/ftbgn3p08.png b/src/image/png/testdata/pngsuite/ftbgn3p08.png
new file mode 100644
index 0000000..8cf2e6f
Binary files /dev/null and b/src/image/png/testdata/pngsuite/ftbgn3p08.png differ
diff --git a/src/image/png/testdata/pngsuite/ftbgn3p08.sng b/src/image/png/testdata/pngsuite/ftbgn3p08.sng
new file mode 100644
index 0000000..0e3b7bd
--- /dev/null
+++ b/src/image/png/testdata/pngsuite/ftbgn3p08.sng
@@ -0,0 +1,292 @@
+#SNG: from ftbgn3p08.png
+IHDR {
+ width: 32; height: 32; bitdepth: 8;
+ using color palette;
+}
+gAMA {1.0000}
+PLTE {
+ (255,255,255) # rgb = (0xff,0xff,0xff) grey100
+ (128, 86, 86) # rgb = (0x80,0x56,0x56)
+ (181,181,184) # rgb = (0xb5,0xb5,0xb8)
+ (168, 66, 66) # rgb = (0xa8,0x42,0x42)
+ (159,159,159) # rgb = (0x9f,0x9f,0x9f)
+ (177, 32, 32) # rgb = (0xb1,0x20,0x20)
+ (139, 21, 21) # rgb = (0x8b,0x15,0x15)
+ (157,157,157) # rgb = (0x9d,0x9d,0x9d)
+ ( 27, 27, 89) # rgb = (0x1b,0x1b,0x59)
+ (155,155,155) # rgb = (0x9b,0x9b,0x9b)
+ ( 0, 0,132) # rgb = (0x00,0x00,0x84)
+ (153,153,153) # rgb = (0x99,0x99,0x99) grey60
+ (143,167,143) # rgb = (0x8f,0xa7,0x8f)
+ (151,151,151) # rgb = (0x97,0x97,0x97)
+ (149,149,149) # rgb = (0x95,0x95,0x95)
+ (147,147,147) # rgb = (0x93,0x93,0x93)
+ ( 41, 41, 86) # rgb = (0x29,0x29,0x56)
+ (145,145,145) # rgb = (0x91,0x91,0x91) grey57
+ ( 0, 0,155) # rgb = (0x00,0x00,0x9b)
+ (143,143,143) # rgb = (0x8f,0x8f,0x8f) grey56
+ (139,149,139) # rgb = (0x8b,0x95,0x8b)
+ ( 46, 46,167) # rgb = (0x2e,0x2e,0xa7)
+ (141,141,141) # rgb = (0x8d,0x8d,0x8d)
+ (128, 0, 0) # rgb = (0x80,0x00,0x00)
+ (139,139,139) # rgb = (0x8b,0x8b,0x8b)
+ (185, 0, 0) # rgb = (0xb9,0x00,0x00)
+ (137,137,137) # rgb = (0x89,0x89,0x89)
+ ( 12, 12,213) # rgb = (0x0c,0x0c,0xd5)
+ (120,117,117) # rgb = (0x78,0x75,0x75)
+ (135,135,135) # rgb = (0x87,0x87,0x87) grey53
+ ( 0, 0,178) # rgb = (0x00,0x00,0xb2)
+ (133,133,133) # rgb = (0x85,0x85,0x85) grey52
+ (165, 0, 0) # rgb = (0xa5,0x00,0x00)
+ (222, 0, 0) # rgb = (0xde,0x00,0x00)
+ (129,129,129) # rgb = (0x81,0x81,0x81)
+ (127,127,127) # rgb = (0x7f,0x7f,0x7f) grey50
+ ( 0, 0,158) # rgb = (0x00,0x00,0x9e)
+ (125,125,125) # rgb = (0x7d,0x7d,0x7d) grey49
+ ( 0, 0,201) # rgb = (0x00,0x00,0xc9)
+ (123,123,123) # rgb = (0x7b,0x7b,0x7b)
+ (121,121,121) # rgb = (0x79,0x79,0x79)
+ ( 55, 55, 86) # rgb = (0x37,0x37,0x56)
+ (119,119,119) # rgb = (0x77,0x77,0x77)
+ (117,117,117) # rgb = (0x75,0x75,0x75) grey46
+ (115,115,115) # rgb = (0x73,0x73,0x73) grey45
+ ( 72,169, 72) # rgb = (0x48,0xa9,0x48)
+ (142, 0, 0) # rgb = (0x8e,0x00,0x00)
+ ( 2, 2,100) # rgb = (0x02,0x02,0x64)
+ ( 0, 0, 98) # rgb = (0x00,0x00,0x62)
+ ( 86,137, 86) # rgb = (0x56,0x89,0x56)
+ ( 40, 40,124) # rgb = (0x28,0x28,0x7c)
+ ( 83,139, 83) # rgb = (0x53,0x8b,0x53)
+ (137,137,143) # rgb = (0x89,0x89,0x8f)
+ (103,103,103) # rgb = (0x67,0x67,0x67)
+ (101,101,101) # rgb = (0x65,0x65,0x65)
+ ( 93,109, 93) # rgb = (0x5d,0x6d,0x5d)
+ ( 19,229, 19) # rgb = (0x13,0xe5,0x13)
+ (134, 38, 38) # rgb = (0x86,0x26,0x26)
+ (111, 45, 45) # rgb = (0x6f,0x2d,0x2d)
+ ( 68,145, 68) # rgb = (0x44,0x91,0x44)
+ ( 97, 97, 97) # rgb = (0x61,0x61,0x61) grey38
+ ( 59,157, 59) # rgb = (0x3b,0x9d,0x3b)
+ ( 68,137, 68) # rgb = (0x44,0x89,0x44)
+ ( 61,147, 61) # rgb = (0x3d,0x93,0x3d)
+ ( 0, 0,164) # rgb = (0x00,0x00,0xa4)
+ ( 0,243, 0) # rgb = (0x00,0xf3,0x00)
+ ( 0,241, 0) # rgb = (0x00,0xf1,0x00)
+ ( 89, 89, 89) # rgb = (0x59,0x59,0x59) grey35
+ ( 87, 87, 87) # rgb = (0x57,0x57,0x57) grey34
+ ( 85, 85, 85) # rgb = (0x55,0x55,0x55)
+ ( 83, 83, 83) # rgb = (0x53,0x53,0x53)
+ ( 52,133, 52) # rgb = (0x34,0x85,0x34)
+ ( 81, 81, 81) # rgb = (0x51,0x51,0x51)
+ ( 36,151, 36) # rgb = (0x24,0x97,0x24)
+ ( 79, 79, 79) # rgb = (0x4f,0x4f,0x4f) grey31
+ ( 58, 58, 65) # rgb = (0x3a,0x3a,0x41)
+ ( 16, 16,186) # rgb = (0x10,0x10,0xba)
+ (178, 15, 15) # rgb = (0xb2,0x0f,0x0f)
+ ( 0,199, 0) # rgb = (0x00,0xc7,0x00)
+ ( 0,197, 0) # rgb = (0x00,0xc5,0x00)
+ (252,252,252) # rgb = (0xfc,0xfc,0xfc) grey99
+ ( 0,195, 0) # rgb = (0x00,0xc3,0x00)
+ ( 4, 4,151) # rgb = (0x04,0x04,0x97)
+ ( 0,193, 0) # rgb = (0x00,0xc1,0x00)
+ ( 45,119, 45) # rgb = (0x2d,0x77,0x2d)
+ (250,250,250) # rgb = (0xfa,0xfa,0xfa) grey98
+ ( 0,191, 0) # rgb = (0x00,0xbf,0x00)
+ ( 0, 0,104) # rgb = (0x00,0x00,0x68)
+ ( 0,189, 0) # rgb = (0x00,0xbd,0x00)
+ (218,212,212) # rgb = (0xda,0xd4,0xd4)
+ ( 16, 16,123) # rgb = (0x10,0x10,0x7b)
+ ( 9,173, 9) # rgb = (0x09,0xad,0x09)
+ (248,248,248) # rgb = (0xf8,0xf8,0xf8)
+ ( 0,185, 0) # rgb = (0x00,0xb9,0x00)
+ ( 0,183, 0) # rgb = (0x00,0xb7,0x00)
+ (156,156,161) # rgb = (0x9c,0x9c,0xa1)
+ (246,246,246) # rgb = (0xf6,0xf6,0xf6)
+ ( 12,161, 12) # rgb = (0x0c,0xa1,0x0c)
+ ( 0,179, 0) # rgb = (0x00,0xb3,0x00)
+ ( 0,177, 0) # rgb = (0x00,0xb1,0x00)
+ ( 16,145, 16) # rgb = (0x10,0x91,0x10)
+ ( 0,171, 0) # rgb = (0x00,0xab,0x00)
+ (242,242,242) # rgb = (0xf2,0xf2,0xf2) grey95
+ ( 0,169, 0) # rgb = (0x00,0xa9,0x00)
+ ( 0,167, 0) # rgb = (0x00,0xa7,0x00)
+ (238,238,238) # rgb = (0xee,0xee,0xee)
+ (236,236,236) # rgb = (0xec,0xec,0xec)
+ ( 0,151, 0) # rgb = (0x00,0x97,0x00)
+ (234,234,234) # rgb = (0xea,0xea,0xea)
+ ( 0, 0,107) # rgb = (0x00,0x00,0x6b)
+ ( 0,141, 0) # rgb = (0x00,0x8d,0x00)
+ ( 0,139, 0) # rgb = (0x00,0x8b,0x00) green4
+ ( 0,137, 0) # rgb = (0x00,0x89,0x00)
+ ( 0,135, 0) # rgb = (0x00,0x87,0x00)
+ ( 49, 49, 49) # rgb = (0x31,0x31,0x31)
+ ( 25, 25, 42) # rgb = (0x19,0x19,0x2a)
+ ( 7, 7, 64) # rgb = (0x07,0x07,0x40)
+ ( 18, 18,174) # rgb = (0x12,0x12,0xae)
+ ( 9, 9,238) # rgb = (0x09,0x09,0xee)
+ (211,214,211) # rgb = (0xd3,0xd6,0xd3)
+ (204,204,204) # rgb = (0xcc,0xcc,0xcc) grey80
+ (147, 0, 0) # rgb = (0x93,0x00,0x00)
+ (163, 42, 42) # rgb = (0xa3,0x2a,0x2a)
+ (198,198,198) # rgb = (0xc6,0xc6,0xc6)
+ (196,196,196) # rgb = (0xc4,0xc4,0xc4) grey77
+ (204, 0, 0) # rgb = (0xcc,0x00,0x00)
+ (211, 10, 10) # rgb = (0xd3,0x0a,0x0a)
+ (129,107,107) # rgb = (0x81,0x6b,0x6b)
+ (120, 62, 62) # rgb = (0x78,0x3e,0x3e)
+ ( 3, 3,109) # rgb = (0x03,0x03,0x6d)
+ ( 0, 0,159) # rgb = (0x00,0x00,0x9f)
+ ( 10, 10, 86) # rgb = (0x0a,0x0a,0x56)
+ ( 70, 70, 72) # rgb = (0x46,0x46,0x48)
+ ( 65, 65, 77) # rgb = (0x41,0x41,0x4d)
+ (115, 93, 93) # rgb = (0x73,0x5d,0x5d)
+ ( 81, 7, 7) # rgb = (0x51,0x07,0x07)
+ (168,168,168) # rgb = (0xa8,0xa8,0xa8) grey66
+ (237,237,239) # rgb = (0xed,0xed,0xef)
+ (160,160,160) # rgb = (0xa0,0xa0,0xa0)
+ (158,158,158) # rgb = (0x9e,0x9e,0x9e) grey62
+ (156,156,156) # rgb = (0x9c,0x9c,0x9c) grey61
+ ( 0, 0,185) # rgb = (0x00,0x00,0xb9)
+ (154,154,154) # rgb = (0x9a,0x9a,0x9a)
+ (178, 0, 0) # rgb = (0xb2,0x00,0x00)
+ (152,152,152) # rgb = (0x98,0x98,0x98)
+ (235, 0, 0) # rgb = (0xeb,0x00,0x00)
+ (150,150,150) # rgb = (0x96,0x96,0x96) grey59
+ (158, 0, 0) # rgb = (0x9e,0x00,0x00)
+ (148,148,148) # rgb = (0x94,0x94,0x94) grey58
+ ( 19, 19, 28) # rgb = (0x13,0x13,0x1c)
+ (146,146,146) # rgb = (0x92,0x92,0x92)
+ (144,144,144) # rgb = (0x90,0x90,0x90)
+ (142,142,142) # rgb = (0x8e,0x8e,0x8e)
+ ( 0, 0,145) # rgb = (0x00,0x00,0x91)
+ (138,138,138) # rgb = (0x8a,0x8a,0x8a) grey54
+ (136,136,136) # rgb = (0x88,0x88,0x88)
+ (118,162,118) # rgb = (0x76,0xa2,0x76)
+ (133,136,133) # rgb = (0x85,0x88,0x85)
+ (134,134,134) # rgb = (0x86,0x86,0x86)
+ (132,132,132) # rgb = (0x84,0x84,0x84)
+ (120, 15, 15) # rgb = (0x78,0x0f,0x0f)
+ (130,130,130) # rgb = (0x82,0x82,0x82) grey51
+ (126,130,126) # rgb = (0x7e,0x82,0x7e)
+ (126,126,126) # rgb = (0x7e,0x7e,0x7e)
+ (124,124,124) # rgb = (0x7c,0x7c,0x7c)
+ (122,122,122) # rgb = (0x7a,0x7a,0x7a) grey48
+ ( 74,192, 74) # rgb = (0x4a,0xc0,0x4a)
+ (118,118,118) # rgb = (0x76,0x76,0x76)
+ (116,116,116) # rgb = (0x74,0x74,0x74)
+ (114,114,114) # rgb = (0x72,0x72,0x72)
+ (112,112,112) # rgb = (0x70,0x70,0x70) grey44
+ (152, 0, 0) # rgb = (0x98,0x00,0x00)
+ (110,110,110) # rgb = (0x6e,0x6e,0x6e) grey43
+ (106,112,106) # rgb = (0x6a,0x70,0x6a)
+ (122,102,102) # rgb = (0x7a,0x66,0x66)
+ (106,106,106) # rgb = (0x6a,0x6a,0x6a)
+ (132, 0, 0) # rgb = (0x84,0x00,0x00)
+ ( 68,162, 68) # rgb = (0x44,0xa2,0x44)
+ ( 75,150, 75) # rgb = (0x4b,0x96,0x4b)
+ ( 97,100, 97) # rgb = (0x61,0x64,0x61)
+ ( 98, 98, 98) # rgb = (0x62,0x62,0x62)
+ ( 0,244, 0) # rgb = (0x00,0xf4,0x00)
+ ( 56,152, 56) # rgb = (0x38,0x98,0x38)
+ ( 92, 92, 92) # rgb = (0x5c,0x5c,0x5c) grey36
+ ( 90, 90, 90) # rgb = (0x5a,0x5a,0x5a)
+ ( 0,230, 0) # rgb = (0x00,0xe6,0x00)
+ ( 2, 2, 93) # rgb = (0x02,0x02,0x5d)
+ ( 66,120, 66) # rgb = (0x42,0x78,0x42)
+ ( 86, 86, 86) # rgb = (0x56,0x56,0x56)
+ ( 0, 0,240) # rgb = (0x00,0x00,0xf0)
+ ( 46,148, 46) # rgb = (0x2e,0x94,0x2e)
+ ( 71,104, 71) # rgb = (0x47,0x68,0x47)
+ ( 49, 49, 96) # rgb = (0x31,0x31,0x60)
+ ( 0,216, 0) # rgb = (0x00,0xd8,0x00)
+ ( 82, 82, 82) # rgb = (0x52,0x52,0x52) grey32
+ ( 80, 80, 80) # rgb = (0x50,0x50,0x50)
+ ( 0,206, 0) # rgb = (0x00,0xce,0x00)
+ ( 33,152, 33) # rgb = (0x21,0x98,0x21)
+ ( 20, 20,109) # rgb = (0x14,0x14,0x6d)
+ ( 0,200, 0) # rgb = (0x00,0xc8,0x00)
+ ( 76, 76, 76) # rgb = (0x4c,0x4c,0x4c)
+ (253,253,253) # rgb = (0xfd,0xfd,0xfd)
+ ( 0,198, 0) # rgb = (0x00,0xc6,0x00)
+ ( 0, 0,157) # rgb = (0x00,0x00,0x9d)
+ (111,107,107) # rgb = (0x6f,0x6b,0x6b)
+ (234, 14, 14) # rgb = (0xea,0x0e,0x0e)
+ ( 72, 72, 72) # rgb = (0x48,0x48,0x48)
+ ( 0,188, 0) # rgb = (0x00,0xbc,0x00)
+ ( 52,102, 52) # rgb = (0x34,0x66,0x34)
+ ( 2, 2,245) # rgb = (0x02,0x02,0xf5)
+ ( 83, 83, 96) # rgb = (0x53,0x53,0x60)
+ ( 0,176, 0) # rgb = (0x00,0xb0,0x00)
+ ( 0,174, 0) # rgb = (0x00,0xae,0x00)
+ (183, 0, 0) # rgb = (0xb7,0x00,0x00)
+ ( 0,164, 0) # rgb = (0x00,0xa4,0x00)
+ (239,239,239) # rgb = (0xef,0xef,0xef)
+ ( 0,162, 0) # rgb = (0x00,0xa2,0x00)
+ (143, 79, 79) # rgb = (0x8f,0x4f,0x4f)
+ (149, 52, 52) # rgb = (0x95,0x34,0x34)
+ ( 0,152, 0) # rgb = (0x00,0x98,0x00)
+ ( 0,150, 0) # rgb = (0x00,0x96,0x00)
+ ( 0,146, 0) # rgb = (0x00,0x92,0x00)
+ (231,231,231) # rgb = (0xe7,0xe7,0xe7)
+ ( 0,140, 0) # rgb = (0x00,0x8c,0x00)
+ (227,227,227) # rgb = (0xe3,0xe3,0xe3) grey89
+ ( 0,128, 0) # rgb = (0x00,0x80,0x00)
+ (146, 6, 6) # rgb = (0x92,0x06,0x06)
+ ( 1, 1,111) # rgb = (0x01,0x01,0x6f)
+ (100, 86, 89) # rgb = (0x64,0x56,0x59)
+ ( 0, 0,100) # rgb = (0x00,0x00,0x64)
+ ( 78, 78,107) # rgb = (0x4e,0x4e,0x6b)
+ (207,207,207) # rgb = (0xcf,0xcf,0xcf) grey81
+ (221,221,224) # rgb = (0xdd,0xdd,0xe0)
+ ( 0, 0,123) # rgb = (0x00,0x00,0x7b)
+ (201,201,201) # rgb = (0xc9,0xc9,0xc9) grey79
+ ( 22, 22, 65) # rgb = (0x16,0x16,0x41)
+ ( 33, 33, 89) # rgb = (0x21,0x21,0x59)
+ ( 87, 87, 89) # rgb = (0x57,0x57,0x59)
+ ( 68, 68,120) # rgb = (0x44,0x44,0x78)
+ (191,191,191) # rgb = (0xbf,0xbf,0xbf) grey75
+ (235,221,221) # rgb = (0xeb,0xdd,0xdd)
+ ( 45, 45, 84) # rgb = (0x2d,0x2d,0x54)
+ ( 10, 10, 96) # rgb = (0x0a,0x0a,0x60)
+ ( 0, 0,255) # rgb = (0x00,0x00,0xff) blue1
+ (191,125,125) # rgb = (0xbf,0x7d,0x7d)
+ (170,170,170) # rgb = (0xaa,0xaa,0xaa)
+}
+bKGD {index: 245}
+tRNS {
+ 0}
+IMAGE {
+ pixels hex
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000e0ea66000000000000000000000000000000
+0000000000000000000000de02a336e43903f4f0000000000000000000000000
+000000000000000069ef1a358680062eb017b0ab7af459500000000000000000
+0000000000667c0ea9cc803979937917a03a878787b0e2ae8ae75c0000000000
+00005cea8ea72c8639e293208f7d7d19200639a017ab2ee4ac2ca7097c690000
+00007823a72b2bda198fd54ddad90521219191217d1917cc2b2b2b2baf8e0000
+0000e81f9b9f27014d05d91c2a2a2a7f037ecdcd7e7a012a2a2aaab7c2ef0000
+00006c9f229d981a23282828282828282828282828282828a7b445c3c8de0000
+00005ca249d63d140f139f272727272727272727a5a528af44c3c8ce43000000
+0000009a62ca41a6960e0d941da4a4a4a4a4a4a4a4a9b732525a1084a1000000
+000000965b58b53811940d0b090b1823a3a3252ab4d24c269957571088000000
+000000946162b9b59c0f14b12d0c8b8c98a3afb8ed1bbd82ba74300877000000
+00000088c565c7b5a6962dcf67be07048aa5b84315f326ba7395832950000000
+00000002bed8d4b94214b1c7dbb68c8b04a843e6d1bd814bceeb10a900000000
+0000007b47636ec441b23d4edb3f09078bac4315f340ec855a82995f00000000
+00000059bb63e15d42643dca6b3f8e090735ed76bd81c05224e9f27b00000000
+0000006cbbd47161c1684951dc3f908e8c3ceef38d08ebe96d6d086000000000
+00000050bf67dc54534fdd53ddb20d0b8eb815d10af1732fe312e60000000000
+00000000add6d6bf61c16f566eb20e0d924475bd578572c61e6d340000000000
+0000000016d8d3d03ec76bcfdf3b0f0e13bc4c8d2f84c040cb837b0000000000
+00000000550c47b3365bd45d6f33110f1a4575cbf2c0521e0802000000000000
+000000000000e7ac36be625e7031131122455a0a2f0a99c6e700000000000000
+000000000000006a9e37d36270331613a545f181e53032e80000000000000000
+00000000000000005088c5d371311816a8464b7374ee89000000000000000000
+0000000000000000000077b654a29b18acc24a722a5500000000000000000000
+0000000000000000000000d78a9f9e9b3548c38ac90000000000000000000000
+00000000000000000000000000ef1f9e3cc20200000000000000000000000000
+0000000000000000000000000000e89736780000000000000000000000000000
+00000000000000000000000000000060e0000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+}
diff --git a/src/image/png/testdata/pngsuite/ftbrn2c08.png b/src/image/png/testdata/pngsuite/ftbrn2c08.png
new file mode 100644
index 0000000..5cca0d6
Binary files /dev/null and b/src/image/png/testdata/pngsuite/ftbrn2c08.png differ
diff --git a/src/image/png/testdata/pngsuite/ftbrn2c08.sng b/src/image/png/testdata/pngsuite/ftbrn2c08.sng
new file mode 100644
index 0000000..9569bda
--- /dev/null
+++ b/src/image/png/testdata/pngsuite/ftbrn2c08.sng
@@ -0,0 +1,45 @@
+#SNG: from ftbrn2c08.png
+IHDR {
+ width: 32; height: 32; bitdepth: 8;
+ using color;
+}
+gAMA {1.0000}
+bKGD {red: 255; green: 0; blue: 0;}
+tRNS {
+ red: 255; green: 255; blue: 255;
+}
+IMAGE {
+ pixels hex
+ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff
+ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff
+ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff e3e3e3 c9c9c9 f1f1f1 ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff
+ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff e8e8e8 b5b5b5 7e7e7e 656565 6e5252 7e2e2e a64343 c79090 ebdddd ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff
+ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff eeeeee bfbfbf 898989 676767 6b5d5d 7a3939 8a1212 8d0000 850000 770000 840000 9a0101 a22d2d bf7d7d ddd0d0 fcfcfc ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff
+ffffff ffffff ffffff ffffff ffffff f2f2f2 c4c4c4 959595 727272 6f6b6b 774444 871e1e 950101 9f0000 910000 800000 720c0c 612d2d 530e0e 500000 590000 850000 920606 7a6666 a0a0a0 cfcfcf f8f8f8 ffffff ffffff ffffff ffffff ffffff
+ffffff ffffff f7f7f7 cacaca 9a9a9a 767676 737373 7c5d5d 872e2e 930707 9e0000 a90000 b00000 c90000 cf0000 b90000 a20101 8c1919 852a2a 7f1313 810000 960000 8f0000 6b5353 6e6e6e 737373 767676 9b9b9b c4c4c4 eeeeee ffffff ffffff
+ffffff ffffff cccccc 7f7f7f 767676 757575 757575 962f2f b80000 b40000 b60000 ad0c0c 943a3a 925050 b92323 d60202 e20000 ef0000 e70000 da0000 cf0000 ba0000 7d0101 6f6b6b 757575 757575 757575 757575 6a6a6a 9a9a9a ffffff ffffff
+ffffff ffffff dcdcdc 858585 888888 848484 7b7b7b 855454 b71313 a91d1d 8d4f4f 787575 777777 777777 777777 816b6b aa4141 d62020 ec1010 e90c0c d01212 a52828 7b5858 777777 777777 777777 707070 5c5c5c 525252 bdbdbd ffffff ffffff
+ffffff ffffff eaeaea 848484 818181 858885 8e8e8e 898989 7f7f7f 797979 797979 797979 797979 797979 797979 797979 797979 797979 797979 797979 797979 797979 797979 797979 767676 636363 545454 505050 4c4c4c e6e6e6 ffffff ffffff
+ffffff ffffff f8f8f8 7f847f 259725 04a504 39a439 8b948b 939393 8f8f8f 838383 7b7b7b 7b7b7b 7b7b7b 7b7b7b 7b7b7b 7b7b7b 7b7b7b 7b7b7b 7b7b7b 7a7a7a 7a7a7a 797979 6a6a6a 575757 505050 4c4c4c 494949 595959 ffffff ffffff ffffff
+ffffff ffffff ffffff 8a8a8a 01b301 00c600 00f200 59b659 929292 959595 979797 949494 878787 7c7c7c 7c7c7c 7c7c7c 7c7c7c 7c7c7c 7c7c7c 7c7c7c 7c7c7c 717171 5a5a60 282885 040493 0c0c78 282858 46464a 828282 ffffff ffffff ffffff
+ffffff ffffff ffffff 929292 0cab0c 00bd00 00f400 20dd20 919191 949494 979797 999999 9b9b9b 999999 8b8b8b 7f7f7f 7e7e7e 7e7e7e 7d7d7d 777777 626262 535360 1212be 0000cc 000092 000069 000067 2a2a55 acacac ffffff ffffff ffffff
+ffffff ffffff ffffff 949494 16a116 00b400 00e200 00f400 76a276 939393 8d978d 469e46 46a746 8e9e8e 9e9e9e 9c9c9c 8e8e8e 7e7e7e 6a6a6a 5a5a5a 57575a 1818cd 0000f0 0000a0 020260 01013d 000061 1d1d59 d6d6d6 ffffff ffffff ffffff
+ffffff ffffff ffffff a4a4a4 219821 00aa00 00c800 00f400 3bca3b 929292 4aac4a 00bc00 00a900 2f9a2f 9d9d9d 9f9f9f a0a0a0 7a7a7a 5a5a5a 595959 3131a1 0000ff 0000c6 03035b 191924 0c0c15 0c0c55 3b3b53 fbfbfb ffffff ffffff ffffff
+ffffff ffffff ffffff b6b6b6 2b8f2b 00a200 00ad00 00eb00 07ed07 899589 43a743 00c900 009900 389538 9c9c9c 9e9e9e 9f9f9f 747474 595959 505067 0505f5 0000f0 030370 383846 484848 161639 2b2b55 727272 ffffff ffffff ffffff ffffff
+ffffff ffffff ffffff c7c7c7 348634 00b100 008d00 00d200 00f300 4c9b4c 3b9e3b 00c700 009800 3d943d 9b9b9b 9d9d9d 9e9e9e 6e6e6e 595959 2b2bad 0000ff 0000a6 252559 43434f 16167e 00009f 01018e 9c9ca1 ffffff ffffff ffffff ffffff
+ffffff ffffff ffffff d8d8d8 3e7d3e 00b100 007b00 00b800 00f100 178b17 3b9c3b 00c600 009700 3d933d 9a9a9a 9b9b9b 9d9d9d 676767 575759 0909ee 0000f0 04046b 33335a 070790 00009e 00007c 0d0d5d c7c7c7 ffffff ffffff ffffff ffffff
+ffffff ffffff ffffff eaeaea 477447 00ad00 008500 099809 00dc00 00a700 239823 00c300 009600 3f923f 989898 9a9a9a 9c9c9c 616161 42427f 0000ff 0000b9 1a1a5d 161649 00007b 00006b 00006b 1c1c56 f4f4f4 ffffff ffffff ffffff ffffff
+ffffff ffffff ffffff fcfcfc 506c50 00a900 009500 2d772d 00c100 00c500 019301 00c100 009000 4b914b 979797 999999 9a9a9a 5a5a5a 2b2ba4 0000f6 000086 2f2f53 191930 020263 000073 00009b 4d4d70 ffffff ffffff ffffff ffffff ffffff
+ffffff ffffff ffffff ffffff 687368 00a400 00a400 3e653e 14a514 00d400 008b00 00bf00 008e00 4a904a 959595 979797 969696 575757 1a1ab5 0000de 000068 3f3f4b 2b2b2b 0c0c6d 0000b3 00006b 868692 ffffff ffffff ffffff ffffff ffffff
+ffffff ffffff ffffff ffffff 8c8c8c 059e05 00b000 346634 408540 00ca00 009700 00bc00 008c00 498e49 939393 959595 8f8f8f 565656 0f0fb7 0000b9 030366 474747 2f2f64 0000a2 00009d 090958 c5c5c5 ffffff ffffff ffffff ffffff ffffff
+ffffff ffffff ffffff ffffff fafafa 90b090 348534 616461 636a63 06af06 00ae00 00b900 008b00 538d53 919191 939393 898989 555555 0a0aa8 00009d 070763 34345c 04049b 0000b1 1a1a4d b5b5bb ffffff ffffff ffffff ffffff ffffff ffffff
+ffffff ffffff ffffff ffffff ffffff ffffff d0d0d0 6d6d6d 656565 2d8f2d 00b200 00b600 008900 558b55 8f8f8f 919191 818181 555555 15157e 000084 010165 010184 000091 1c1c6e ceced0 ffffff ffffff ffffff ffffff ffffff ffffff ffffff
+ffffff ffffff ffffff ffffff ffffff ffffff ffffff ececec 868686 587058 00af00 00b300 008800 538953 8d8d8d 8f8f8f 7a7a7a 545454 2c2c49 02026b 000064 000063 292974 dfdfe5 ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff
+ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff fcfcfc aaaaaa 219821 00b000 008600 578757 8b8b8b 8d8d8d 747474 535353 3d3d3d 1a1a23 0d0d43 474772 ededef ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff
+ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff d1d6d1 389b38 2d772d 7d817d 888888 8b8b8b 6d6d6d 525252 4f4f4f 373737 777777 fafafa ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff
+ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff efefef a0a0a0 838383 868686 888888 676767 515151 505050 a0a0a0 fdfdfd ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff
+ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff fefefe c0c0c0 858585 868686 616161 525252 b7b7b7 ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff
+ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff dedede 909090 656565 cccccc ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff
+ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff f5f5f5 e3e3e3 ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff
+ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff ffffff
+}
diff --git a/src/image/png/testdata/pngsuite/ftbwn0g16.png b/src/image/png/testdata/pngsuite/ftbwn0g16.png
new file mode 100644
index 0000000..99bdeed
Binary files /dev/null and b/src/image/png/testdata/pngsuite/ftbwn0g16.png differ
diff --git a/src/image/png/testdata/pngsuite/ftbwn0g16.sng b/src/image/png/testdata/pngsuite/ftbwn0g16.sng
new file mode 100644
index 0000000..3fca307
--- /dev/null
+++ b/src/image/png/testdata/pngsuite/ftbwn0g16.sng
@@ -0,0 +1,45 @@
+#SNG: from ftbwn0g16.png
+IHDR {
+ width: 32; height: 32; bitdepth: 16;
+ using grayscale;
+}
+gAMA {1.0000}
+bKGD {gray: 65535;}
+tRNS {
+ gray: 65535;
+}
+IMAGE {
+ pixels hex
+ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff
+ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff
+ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff e3e3 c9c9 f1f1 ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff
+ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff e8e8 b5b5 7e7e 6565 5ab9 462f 60f8 a111 e210 ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff
+ffff ffff ffff ffff ffff ffff ffff ffff eeee bfbf 8989 6767 6190 4cba 3614 2a50 27e9 23b5 279c 2eea 5049 914b d4b7 fcfc ffff ffff ffff ffff ffff ffff ffff ffff
+ffff ffff ffff ffff ffff f2f2 c4c4 9595 7272 6c9e 5392 3da0 2d6a 2fb7 2b83 2669 2aa7 3cc7 22c2 1801 1ab5 27e9 3008 6c66 a0a0 cfcf f8f8 ffff ffff ffff ffff ffff
+ffff ffff f7f7 caca 9a9a 7676 7373 66aa 48e3 3109 2f6a 32b6 34d0 3c50 3e1d 3784 3151 3b9b 4578 337b 26b6 2d03 2ae9 5a87 6e6e 7373 7676 9b9b c4c4 eeee ffff ffff
+ffff ffff cccc 7f7f 7676 7575 7575 4e17 3737 3603 369d 3c5c 553c 641e 5026 419f 43d1 47b7 4551 416a 3e1e 37d0 2636 6c9e 7575 7575 7575 7575 6a6a 9a9a ffff ffff
+ffff ffff dcdc 8585 8888 8484 7b7b 6308 4449 471f 61ea 765b 7777 7777 7777 7205 60c3 56bd 5214 4e5d 4b15 4daa 62d9 7777 7777 7777 7070 5c5c 5252 bdbd ffff ffff
+ffff ffff eaea 8484 8181 8749 8e8e 8989 7f7f 7979 7979 7979 7979 7979 7979 7979 7979 7979 7979 7979 7979 7979 7979 7979 7676 6363 5454 5050 4c4c e6e6 ffff ffff
+ffff ffff f8f8 8271 6847 62d4 783c 90d8 9393 8f8f 8383 7b7b 7b7b 7b7b 7b7b 7b7b 7b7b 7b7b 7b7b 7b7b 7a7a 7a7a 7979 6a6a 5757 5050 4c4c 4949 5959 ffff ffff ffff
+ffff ffff ffff 8a8a 69d4 749a 8e83 901d 9292 9595 9797 9494 8787 7c7c 7c7c 7c7c 7c7c 7c7c 7c7c 7c7c 7c7c 7171 5b0b 32d9 1474 1876 2dac 46bc 8282 ffff ffff ffff
+ffff ffff ffff 9292 69ae 6f4d 8fb1 8f6d 9191 9494 9797 9999 9b9b 9999 8b8b 7f7f 7e7e 7e7e 7d7d 7777 6262 54d2 25d7 1773 10c8 0c12 0bd7 2f1b acac ffff ffff ffff
+ffff ffff ffff 9494 67f1 6a00 8517 8fb1 905f 9393 9371 7a19 7f65 97fa 9e9e 9c9c 8e8e 7e7e 6a6a 5a5a 57af 2ce6 1b97 1264 0cd0 07e7 0b27 2403 d6d6 ffff ffff ffff
+ffff ffff ffff a4a4 6735 641d 75c7 8fb1 8f71 9292 8400 6eb6 6386 6e32 9d9d 9f9f a0a0 7a7a 5a5a 5959 3e11 1d50 16c2 0d21 1a5d 0d15 1470 3dfd fbfb ffff ffff ffff
+ffff ffff ffff b6b6 660f 5f67 65e1 8a64 8e79 909a 7e27 765e 5a1a 6efc 9c9c 9e9e 9f9f 7474 5959 52f5 209b 1b97 0f8a 39d4 4848 1a1c 2fff 7272 ffff ffff ffff ffff
+ffff ffff ffff c7c7 647e 683c 5309 7bab 8f1a 7ad2 7588 7531 5983 7079 9b9b 9d9d 9e9e 6e6e 5959 3a1c 1d50 1315 2b1f 44a4 220a 1247 1136 9d2f ffff ffff ffff ffff
+ffff ffff ffff d8d8 6358 683c 486f 6c5b 8dec 5b67 745a 749a 58ec 6fe2 9a9a 9b9b 9d9d 6767 5792 235c 1b97 0fdb 37af 16c6 1229 0e41 163f c7c7 ffff ffff ffff ffff
+ffff ffff ffff eaea 61c7 65e1 4e53 5d3f 818e 6258 6809 72d6 5855 7020 9898 9a9a 9c9c 6161 4945 1d50 1544 21ce 1bf3 0e23 0c4d 0c4d 22c7 f4f4 ffff ffff ffff ffff
+ffff ffff ffff fcfc 60cd 6386 57bf 58c1 71a8 7403 56fb 71a8 54cd 7484 9797 9999 9a9a 5a5a 3914 1c47 0f68 3352 1bbe 0d28 0d38 11d2 5153 ffff ffff ffff ffff ffff
+ffff ffff ffff ffff 6ee2 6094 6094 5535 6978 7cd8 51db 707a 539f 7383 9595 9797 9696 5757 2beb 1985 0bf5 40a0 2b2b 1732 1493 0c4d 87e7 ffff ffff ffff ffff ffff
+ffff ffff ffff ffff 8c8c 5f1f 67a5 51a6 68e2 76f5 58ec 6eb6 5272 71eb 9393 9595 8f8f 5656 225f 1544 0e64 4747 3547 129f 120c 121e c5c5 ffff ffff ffff ffff ffff
+ffff ffff ffff ffff fafa a368 63e7 6325 6782 698c 6678 6cf2 51db 757b 9191 9393 8989 5555 1c33 120c 119a 38cd 155f 1459 1ff7 b666 ffff ffff ffff ffff ffff ffff
+ffff ffff ffff ffff ffff ffff d0d0 6d6d 6565 66e3 68d3 6b2e 50ae 7522 8f8f 9191 8181 5555 2127 0f2d 0c80 1010 10ab 2589 cf09 ffff ffff ffff ffff ffff ffff ffff
+ffff ffff ffff ffff ffff ffff ffff ecec 8686 667a 670e 6969 5017 7320 8d8d 8f8f 7a7a 5454 2f81 0e14 0b7f 0b61 31c8 e090 ffff ffff ffff ffff ffff ffff ffff ffff
+ffff ffff ffff ffff ffff ffff ffff ffff fcfc aaaa 6735 67a5 4ee9 739b 8b8b 8d8d 7474 5353 3d3d 1b23 1342 4c38 ee28 ffff ffff ffff ffff ffff ffff ffff ffff ffff
+ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff d4c3 7285 58c1 7fd8 8888 8b8b 6d6d 5252 4f4f 3737 7777 fafa ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff
+ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff efef a0a0 8383 8686 8888 6767 5151 5050 a0a0 fdfd ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff
+ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff fefe c0c0 8585 8686 6161 5252 b7b7 ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff
+ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff dede 9090 6565 cccc ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff
+ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff f5f5 e3e3 ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff
+ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff ffff
+}
diff --git a/src/image/png/testdata/pngsuite/ftbwn3p08.png b/src/image/png/testdata/pngsuite/ftbwn3p08.png
new file mode 100644
index 0000000..eacab7a
Binary files /dev/null and b/src/image/png/testdata/pngsuite/ftbwn3p08.png differ
diff --git a/src/image/png/testdata/pngsuite/ftbwn3p08.sng b/src/image/png/testdata/pngsuite/ftbwn3p08.sng
new file mode 100644
index 0000000..7b5aff6
--- /dev/null
+++ b/src/image/png/testdata/pngsuite/ftbwn3p08.sng
@@ -0,0 +1,291 @@
+#SNG: from ftbwn3p08.png
+IHDR {
+ width: 32; height: 32; bitdepth: 8;
+ using color palette;
+}
+gAMA {1.0000}
+PLTE {
+ (255,255,255) # rgb = (0xff,0xff,0xff) grey100
+ (128, 86, 86) # rgb = (0x80,0x56,0x56)
+ (181,181,184) # rgb = (0xb5,0xb5,0xb8)
+ (168, 66, 66) # rgb = (0xa8,0x42,0x42)
+ (159,159,159) # rgb = (0x9f,0x9f,0x9f)
+ (177, 32, 32) # rgb = (0xb1,0x20,0x20)
+ (139, 21, 21) # rgb = (0x8b,0x15,0x15)
+ (157,157,157) # rgb = (0x9d,0x9d,0x9d)
+ ( 27, 27, 89) # rgb = (0x1b,0x1b,0x59)
+ (155,155,155) # rgb = (0x9b,0x9b,0x9b)
+ ( 0, 0,132) # rgb = (0x00,0x00,0x84)
+ (153,153,153) # rgb = (0x99,0x99,0x99) grey60
+ (143,167,143) # rgb = (0x8f,0xa7,0x8f)
+ (151,151,151) # rgb = (0x97,0x97,0x97)
+ (149,149,149) # rgb = (0x95,0x95,0x95)
+ (147,147,147) # rgb = (0x93,0x93,0x93)
+ ( 41, 41, 86) # rgb = (0x29,0x29,0x56)
+ (145,145,145) # rgb = (0x91,0x91,0x91) grey57
+ ( 0, 0,155) # rgb = (0x00,0x00,0x9b)
+ (143,143,143) # rgb = (0x8f,0x8f,0x8f) grey56
+ (139,149,139) # rgb = (0x8b,0x95,0x8b)
+ ( 46, 46,167) # rgb = (0x2e,0x2e,0xa7)
+ (141,141,141) # rgb = (0x8d,0x8d,0x8d)
+ (128, 0, 0) # rgb = (0x80,0x00,0x00)
+ (139,139,139) # rgb = (0x8b,0x8b,0x8b)
+ (185, 0, 0) # rgb = (0xb9,0x00,0x00)
+ (137,137,137) # rgb = (0x89,0x89,0x89)
+ ( 12, 12,213) # rgb = (0x0c,0x0c,0xd5)
+ (120,117,117) # rgb = (0x78,0x75,0x75)
+ (135,135,135) # rgb = (0x87,0x87,0x87) grey53
+ ( 0, 0,178) # rgb = (0x00,0x00,0xb2)
+ (133,133,133) # rgb = (0x85,0x85,0x85) grey52
+ (165, 0, 0) # rgb = (0xa5,0x00,0x00)
+ (222, 0, 0) # rgb = (0xde,0x00,0x00)
+ (129,129,129) # rgb = (0x81,0x81,0x81)
+ (127,127,127) # rgb = (0x7f,0x7f,0x7f) grey50
+ ( 0, 0,158) # rgb = (0x00,0x00,0x9e)
+ (125,125,125) # rgb = (0x7d,0x7d,0x7d) grey49
+ ( 0, 0,201) # rgb = (0x00,0x00,0xc9)
+ (123,123,123) # rgb = (0x7b,0x7b,0x7b)
+ (121,121,121) # rgb = (0x79,0x79,0x79)
+ ( 55, 55, 86) # rgb = (0x37,0x37,0x56)
+ (119,119,119) # rgb = (0x77,0x77,0x77)
+ (117,117,117) # rgb = (0x75,0x75,0x75) grey46
+ (115,115,115) # rgb = (0x73,0x73,0x73) grey45
+ ( 72,169, 72) # rgb = (0x48,0xa9,0x48)
+ (142, 0, 0) # rgb = (0x8e,0x00,0x00)
+ ( 2, 2,100) # rgb = (0x02,0x02,0x64)
+ ( 0, 0, 98) # rgb = (0x00,0x00,0x62)
+ ( 86,137, 86) # rgb = (0x56,0x89,0x56)
+ ( 40, 40,124) # rgb = (0x28,0x28,0x7c)
+ ( 83,139, 83) # rgb = (0x53,0x8b,0x53)
+ (137,137,143) # rgb = (0x89,0x89,0x8f)
+ (103,103,103) # rgb = (0x67,0x67,0x67)
+ (101,101,101) # rgb = (0x65,0x65,0x65)
+ ( 93,109, 93) # rgb = (0x5d,0x6d,0x5d)
+ ( 19,229, 19) # rgb = (0x13,0xe5,0x13)
+ (134, 38, 38) # rgb = (0x86,0x26,0x26)
+ (111, 45, 45) # rgb = (0x6f,0x2d,0x2d)
+ ( 68,145, 68) # rgb = (0x44,0x91,0x44)
+ ( 97, 97, 97) # rgb = (0x61,0x61,0x61) grey38
+ ( 59,157, 59) # rgb = (0x3b,0x9d,0x3b)
+ ( 68,137, 68) # rgb = (0x44,0x89,0x44)
+ ( 61,147, 61) # rgb = (0x3d,0x93,0x3d)
+ ( 0, 0,164) # rgb = (0x00,0x00,0xa4)
+ ( 0,243, 0) # rgb = (0x00,0xf3,0x00)
+ ( 0,241, 0) # rgb = (0x00,0xf1,0x00)
+ ( 89, 89, 89) # rgb = (0x59,0x59,0x59) grey35
+ ( 87, 87, 87) # rgb = (0x57,0x57,0x57) grey34
+ ( 85, 85, 85) # rgb = (0x55,0x55,0x55)
+ ( 83, 83, 83) # rgb = (0x53,0x53,0x53)
+ ( 52,133, 52) # rgb = (0x34,0x85,0x34)
+ ( 81, 81, 81) # rgb = (0x51,0x51,0x51)
+ ( 36,151, 36) # rgb = (0x24,0x97,0x24)
+ ( 79, 79, 79) # rgb = (0x4f,0x4f,0x4f) grey31
+ ( 58, 58, 65) # rgb = (0x3a,0x3a,0x41)
+ ( 16, 16,186) # rgb = (0x10,0x10,0xba)
+ (178, 15, 15) # rgb = (0xb2,0x0f,0x0f)
+ ( 0,199, 0) # rgb = (0x00,0xc7,0x00)
+ ( 0,197, 0) # rgb = (0x00,0xc5,0x00)
+ (252,252,252) # rgb = (0xfc,0xfc,0xfc) grey99
+ ( 0,195, 0) # rgb = (0x00,0xc3,0x00)
+ ( 4, 4,151) # rgb = (0x04,0x04,0x97)
+ ( 0,193, 0) # rgb = (0x00,0xc1,0x00)
+ ( 45,119, 45) # rgb = (0x2d,0x77,0x2d)
+ (250,250,250) # rgb = (0xfa,0xfa,0xfa) grey98
+ ( 0,191, 0) # rgb = (0x00,0xbf,0x00)
+ ( 0, 0,104) # rgb = (0x00,0x00,0x68)
+ ( 0,189, 0) # rgb = (0x00,0xbd,0x00)
+ (218,212,212) # rgb = (0xda,0xd4,0xd4)
+ ( 16, 16,123) # rgb = (0x10,0x10,0x7b)
+ ( 9,173, 9) # rgb = (0x09,0xad,0x09)
+ (248,248,248) # rgb = (0xf8,0xf8,0xf8)
+ ( 0,185, 0) # rgb = (0x00,0xb9,0x00)
+ ( 0,183, 0) # rgb = (0x00,0xb7,0x00)
+ (156,156,161) # rgb = (0x9c,0x9c,0xa1)
+ (246,246,246) # rgb = (0xf6,0xf6,0xf6)
+ ( 12,161, 12) # rgb = (0x0c,0xa1,0x0c)
+ ( 0,179, 0) # rgb = (0x00,0xb3,0x00)
+ ( 0,177, 0) # rgb = (0x00,0xb1,0x00)
+ ( 16,145, 16) # rgb = (0x10,0x91,0x10)
+ ( 0,171, 0) # rgb = (0x00,0xab,0x00)
+ (242,242,242) # rgb = (0xf2,0xf2,0xf2) grey95
+ ( 0,169, 0) # rgb = (0x00,0xa9,0x00)
+ ( 0,167, 0) # rgb = (0x00,0xa7,0x00)
+ (238,238,238) # rgb = (0xee,0xee,0xee)
+ (236,236,236) # rgb = (0xec,0xec,0xec)
+ ( 0,151, 0) # rgb = (0x00,0x97,0x00)
+ (234,234,234) # rgb = (0xea,0xea,0xea)
+ ( 0, 0,107) # rgb = (0x00,0x00,0x6b)
+ ( 0,141, 0) # rgb = (0x00,0x8d,0x00)
+ ( 0,139, 0) # rgb = (0x00,0x8b,0x00) green4
+ ( 0,137, 0) # rgb = (0x00,0x89,0x00)
+ ( 0,135, 0) # rgb = (0x00,0x87,0x00)
+ ( 49, 49, 49) # rgb = (0x31,0x31,0x31)
+ ( 25, 25, 42) # rgb = (0x19,0x19,0x2a)
+ ( 7, 7, 64) # rgb = (0x07,0x07,0x40)
+ ( 18, 18,174) # rgb = (0x12,0x12,0xae)
+ ( 9, 9,238) # rgb = (0x09,0x09,0xee)
+ (211,214,211) # rgb = (0xd3,0xd6,0xd3)
+ (204,204,204) # rgb = (0xcc,0xcc,0xcc) grey80
+ (147, 0, 0) # rgb = (0x93,0x00,0x00)
+ (163, 42, 42) # rgb = (0xa3,0x2a,0x2a)
+ (198,198,198) # rgb = (0xc6,0xc6,0xc6)
+ (196,196,196) # rgb = (0xc4,0xc4,0xc4) grey77
+ (204, 0, 0) # rgb = (0xcc,0x00,0x00)
+ (211, 10, 10) # rgb = (0xd3,0x0a,0x0a)
+ (129,107,107) # rgb = (0x81,0x6b,0x6b)
+ (120, 62, 62) # rgb = (0x78,0x3e,0x3e)
+ ( 3, 3,109) # rgb = (0x03,0x03,0x6d)
+ ( 0, 0,159) # rgb = (0x00,0x00,0x9f)
+ ( 10, 10, 86) # rgb = (0x0a,0x0a,0x56)
+ ( 70, 70, 72) # rgb = (0x46,0x46,0x48)
+ ( 65, 65, 77) # rgb = (0x41,0x41,0x4d)
+ (115, 93, 93) # rgb = (0x73,0x5d,0x5d)
+ ( 81, 7, 7) # rgb = (0x51,0x07,0x07)
+ (168,168,168) # rgb = (0xa8,0xa8,0xa8) grey66
+ (237,237,239) # rgb = (0xed,0xed,0xef)
+ (160,160,160) # rgb = (0xa0,0xa0,0xa0)
+ (158,158,158) # rgb = (0x9e,0x9e,0x9e) grey62
+ (156,156,156) # rgb = (0x9c,0x9c,0x9c) grey61
+ ( 0, 0,185) # rgb = (0x00,0x00,0xb9)
+ (154,154,154) # rgb = (0x9a,0x9a,0x9a)
+ (178, 0, 0) # rgb = (0xb2,0x00,0x00)
+ (152,152,152) # rgb = (0x98,0x98,0x98)
+ (235, 0, 0) # rgb = (0xeb,0x00,0x00)
+ (150,150,150) # rgb = (0x96,0x96,0x96) grey59
+ (158, 0, 0) # rgb = (0x9e,0x00,0x00)
+ (148,148,148) # rgb = (0x94,0x94,0x94) grey58
+ ( 19, 19, 28) # rgb = (0x13,0x13,0x1c)
+ (146,146,146) # rgb = (0x92,0x92,0x92)
+ (144,144,144) # rgb = (0x90,0x90,0x90)
+ (142,142,142) # rgb = (0x8e,0x8e,0x8e)
+ ( 0, 0,145) # rgb = (0x00,0x00,0x91)
+ (138,138,138) # rgb = (0x8a,0x8a,0x8a) grey54
+ (136,136,136) # rgb = (0x88,0x88,0x88)
+ (118,162,118) # rgb = (0x76,0xa2,0x76)
+ (133,136,133) # rgb = (0x85,0x88,0x85)
+ (134,134,134) # rgb = (0x86,0x86,0x86)
+ (132,132,132) # rgb = (0x84,0x84,0x84)
+ (120, 15, 15) # rgb = (0x78,0x0f,0x0f)
+ (130,130,130) # rgb = (0x82,0x82,0x82) grey51
+ (126,130,126) # rgb = (0x7e,0x82,0x7e)
+ (126,126,126) # rgb = (0x7e,0x7e,0x7e)
+ (124,124,124) # rgb = (0x7c,0x7c,0x7c)
+ (122,122,122) # rgb = (0x7a,0x7a,0x7a) grey48
+ ( 74,192, 74) # rgb = (0x4a,0xc0,0x4a)
+ (118,118,118) # rgb = (0x76,0x76,0x76)
+ (116,116,116) # rgb = (0x74,0x74,0x74)
+ (114,114,114) # rgb = (0x72,0x72,0x72)
+ (112,112,112) # rgb = (0x70,0x70,0x70) grey44
+ (152, 0, 0) # rgb = (0x98,0x00,0x00)
+ (110,110,110) # rgb = (0x6e,0x6e,0x6e) grey43
+ (106,112,106) # rgb = (0x6a,0x70,0x6a)
+ (122,102,102) # rgb = (0x7a,0x66,0x66)
+ (106,106,106) # rgb = (0x6a,0x6a,0x6a)
+ (132, 0, 0) # rgb = (0x84,0x00,0x00)
+ ( 68,162, 68) # rgb = (0x44,0xa2,0x44)
+ ( 75,150, 75) # rgb = (0x4b,0x96,0x4b)
+ ( 97,100, 97) # rgb = (0x61,0x64,0x61)
+ ( 98, 98, 98) # rgb = (0x62,0x62,0x62)
+ ( 0,244, 0) # rgb = (0x00,0xf4,0x00)
+ ( 56,152, 56) # rgb = (0x38,0x98,0x38)
+ ( 92, 92, 92) # rgb = (0x5c,0x5c,0x5c) grey36
+ ( 90, 90, 90) # rgb = (0x5a,0x5a,0x5a)
+ ( 0,230, 0) # rgb = (0x00,0xe6,0x00)
+ ( 2, 2, 93) # rgb = (0x02,0x02,0x5d)
+ ( 66,120, 66) # rgb = (0x42,0x78,0x42)
+ ( 86, 86, 86) # rgb = (0x56,0x56,0x56)
+ ( 0, 0,240) # rgb = (0x00,0x00,0xf0)
+ ( 46,148, 46) # rgb = (0x2e,0x94,0x2e)
+ ( 71,104, 71) # rgb = (0x47,0x68,0x47)
+ ( 49, 49, 96) # rgb = (0x31,0x31,0x60)
+ ( 0,216, 0) # rgb = (0x00,0xd8,0x00)
+ ( 82, 82, 82) # rgb = (0x52,0x52,0x52) grey32
+ ( 80, 80, 80) # rgb = (0x50,0x50,0x50)
+ ( 0,206, 0) # rgb = (0x00,0xce,0x00)
+ ( 33,152, 33) # rgb = (0x21,0x98,0x21)
+ ( 20, 20,109) # rgb = (0x14,0x14,0x6d)
+ ( 0,200, 0) # rgb = (0x00,0xc8,0x00)
+ ( 76, 76, 76) # rgb = (0x4c,0x4c,0x4c)
+ (253,253,253) # rgb = (0xfd,0xfd,0xfd)
+ ( 0,198, 0) # rgb = (0x00,0xc6,0x00)
+ ( 0, 0,157) # rgb = (0x00,0x00,0x9d)
+ (111,107,107) # rgb = (0x6f,0x6b,0x6b)
+ (234, 14, 14) # rgb = (0xea,0x0e,0x0e)
+ ( 72, 72, 72) # rgb = (0x48,0x48,0x48)
+ ( 0,188, 0) # rgb = (0x00,0xbc,0x00)
+ ( 52,102, 52) # rgb = (0x34,0x66,0x34)
+ ( 2, 2,245) # rgb = (0x02,0x02,0xf5)
+ ( 83, 83, 96) # rgb = (0x53,0x53,0x60)
+ ( 0,176, 0) # rgb = (0x00,0xb0,0x00)
+ ( 0,174, 0) # rgb = (0x00,0xae,0x00)
+ (183, 0, 0) # rgb = (0xb7,0x00,0x00)
+ ( 0,164, 0) # rgb = (0x00,0xa4,0x00)
+ (239,239,239) # rgb = (0xef,0xef,0xef)
+ ( 0,162, 0) # rgb = (0x00,0xa2,0x00)
+ (143, 79, 79) # rgb = (0x8f,0x4f,0x4f)
+ (149, 52, 52) # rgb = (0x95,0x34,0x34)
+ ( 0,152, 0) # rgb = (0x00,0x98,0x00)
+ ( 0,150, 0) # rgb = (0x00,0x96,0x00)
+ ( 0,146, 0) # rgb = (0x00,0x92,0x00)
+ (231,231,231) # rgb = (0xe7,0xe7,0xe7)
+ ( 0,140, 0) # rgb = (0x00,0x8c,0x00)
+ (227,227,227) # rgb = (0xe3,0xe3,0xe3) grey89
+ ( 0,128, 0) # rgb = (0x00,0x80,0x00)
+ (146, 6, 6) # rgb = (0x92,0x06,0x06)
+ ( 1, 1,111) # rgb = (0x01,0x01,0x6f)
+ (100, 86, 89) # rgb = (0x64,0x56,0x59)
+ ( 0, 0,100) # rgb = (0x00,0x00,0x64)
+ ( 78, 78,107) # rgb = (0x4e,0x4e,0x6b)
+ (207,207,207) # rgb = (0xcf,0xcf,0xcf) grey81
+ (221,221,224) # rgb = (0xdd,0xdd,0xe0)
+ ( 0, 0,123) # rgb = (0x00,0x00,0x7b)
+ (201,201,201) # rgb = (0xc9,0xc9,0xc9) grey79
+ ( 22, 22, 65) # rgb = (0x16,0x16,0x41)
+ ( 33, 33, 89) # rgb = (0x21,0x21,0x59)
+ ( 87, 87, 89) # rgb = (0x57,0x57,0x59)
+ ( 68, 68,120) # rgb = (0x44,0x44,0x78)
+ (191,191,191) # rgb = (0xbf,0xbf,0xbf) grey75
+ (235,221,221) # rgb = (0xeb,0xdd,0xdd)
+ ( 45, 45, 84) # rgb = (0x2d,0x2d,0x54)
+ ( 10, 10, 96) # rgb = (0x0a,0x0a,0x60)
+ ( 0, 0,255) # rgb = (0x00,0x00,0xff) blue1
+ (191,125,125) # rgb = (0xbf,0x7d,0x7d)
+}
+bKGD {index: 0}
+tRNS {
+ 0}
+IMAGE {
+ pixels hex
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000e0ea66000000000000000000000000000000
+0000000000000000000000de02a336e43903f4f0000000000000000000000000
+000000000000000069ef1a358680062eb017b0ab7af459500000000000000000
+0000000000667c0ea9cc803979937917a03a878787b0e2ae8ae75c0000000000
+00005cea8ea72c8639e293208f7d7d19200639a017ab2ee4ac2ca7097c690000
+00007823a72b2bda198fd54ddad90521219191217d1917cc2b2b2b2baf8e0000
+0000e81f9b9f27014d05d91c2a2a2a7f037ecdcd7e7a012a2a2aaab7c2ef0000
+00006c9f229d981a23282828282828282828282828282828a7b445c3c8de0000
+00005ca249d63d140f139f272727272727272727a5a528af44c3c8ce43000000
+0000009a62ca41a6960e0d941da4a4a4a4a4a4a4a4a9b732525a1084a1000000
+000000965b58b53811940d0b090b1823a3a3252ab4d24c269957571088000000
+000000946162b9b59c0f14b12d0c8b8c98a3afb8ed1bbd82ba74300877000000
+00000088c565c7b5a6962dcf67be07048aa5b84315f326ba7395832950000000
+00000002bed8d4b94214b1c7dbb68c8b04a843e6d1bd814bceeb10a900000000
+0000007b47636ec441b23d4edb3f09078bac4315f340ec855a82995f00000000
+00000059bb63e15d42643dca6b3f8e090735ed76bd81c05224e9f27b00000000
+0000006cbbd47161c1684951dc3f908e8c3ceef38d08ebe96d6d086000000000
+00000050bf67dc54534fdd53ddb20d0b8eb815d10af1732fe312e60000000000
+00000000add6d6bf61c16f566eb20e0d924475bd578572c61e6d340000000000
+0000000016d8d3d03ec76bcfdf3b0f0e13bc4c8d2f84c040cb837b0000000000
+00000000550c47b3365bd45d6f33110f1a4575cbf2c0521e0802000000000000
+000000000000e7ac36be625e7031131122455a0a2f0a99c6e700000000000000
+000000000000006a9e37d36270331613a545f181e53032e80000000000000000
+00000000000000005088c5d371311816a8464b7374ee89000000000000000000
+0000000000000000000077b654a29b18acc24a722a5500000000000000000000
+0000000000000000000000d78a9f9e9b3548c38ac90000000000000000000000
+00000000000000000000000000ef1f9e3cc20200000000000000000000000000
+0000000000000000000000000000e89736780000000000000000000000000000
+00000000000000000000000000000060e0000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+}
diff --git a/src/image/png/testdata/pngsuite/ftbyn3p08.png b/src/image/png/testdata/pngsuite/ftbyn3p08.png
new file mode 100644
index 0000000..656db09
Binary files /dev/null and b/src/image/png/testdata/pngsuite/ftbyn3p08.png differ
diff --git a/src/image/png/testdata/pngsuite/ftbyn3p08.sng b/src/image/png/testdata/pngsuite/ftbyn3p08.sng
new file mode 100644
index 0000000..5d61987
--- /dev/null
+++ b/src/image/png/testdata/pngsuite/ftbyn3p08.sng
@@ -0,0 +1,292 @@
+#SNG: from ftbyn3p08.png
+IHDR {
+ width: 32; height: 32; bitdepth: 8;
+ using color palette;
+}
+gAMA {1.0000}
+PLTE {
+ (255,255,255) # rgb = (0xff,0xff,0xff) grey100
+ (128, 86, 86) # rgb = (0x80,0x56,0x56)
+ (181,181,184) # rgb = (0xb5,0xb5,0xb8)
+ (168, 66, 66) # rgb = (0xa8,0x42,0x42)
+ (159,159,159) # rgb = (0x9f,0x9f,0x9f)
+ (177, 32, 32) # rgb = (0xb1,0x20,0x20)
+ (139, 21, 21) # rgb = (0x8b,0x15,0x15)
+ (157,157,157) # rgb = (0x9d,0x9d,0x9d)
+ ( 27, 27, 89) # rgb = (0x1b,0x1b,0x59)
+ (155,155,155) # rgb = (0x9b,0x9b,0x9b)
+ ( 0, 0,132) # rgb = (0x00,0x00,0x84)
+ (153,153,153) # rgb = (0x99,0x99,0x99) grey60
+ (143,167,143) # rgb = (0x8f,0xa7,0x8f)
+ (151,151,151) # rgb = (0x97,0x97,0x97)
+ (149,149,149) # rgb = (0x95,0x95,0x95)
+ (147,147,147) # rgb = (0x93,0x93,0x93)
+ ( 41, 41, 86) # rgb = (0x29,0x29,0x56)
+ (145,145,145) # rgb = (0x91,0x91,0x91) grey57
+ ( 0, 0,155) # rgb = (0x00,0x00,0x9b)
+ (143,143,143) # rgb = (0x8f,0x8f,0x8f) grey56
+ (139,149,139) # rgb = (0x8b,0x95,0x8b)
+ ( 46, 46,167) # rgb = (0x2e,0x2e,0xa7)
+ (141,141,141) # rgb = (0x8d,0x8d,0x8d)
+ (128, 0, 0) # rgb = (0x80,0x00,0x00)
+ (139,139,139) # rgb = (0x8b,0x8b,0x8b)
+ (185, 0, 0) # rgb = (0xb9,0x00,0x00)
+ (137,137,137) # rgb = (0x89,0x89,0x89)
+ ( 12, 12,213) # rgb = (0x0c,0x0c,0xd5)
+ (120,117,117) # rgb = (0x78,0x75,0x75)
+ (135,135,135) # rgb = (0x87,0x87,0x87) grey53
+ ( 0, 0,178) # rgb = (0x00,0x00,0xb2)
+ (133,133,133) # rgb = (0x85,0x85,0x85) grey52
+ (165, 0, 0) # rgb = (0xa5,0x00,0x00)
+ (222, 0, 0) # rgb = (0xde,0x00,0x00)
+ (129,129,129) # rgb = (0x81,0x81,0x81)
+ (127,127,127) # rgb = (0x7f,0x7f,0x7f) grey50
+ ( 0, 0,158) # rgb = (0x00,0x00,0x9e)
+ (125,125,125) # rgb = (0x7d,0x7d,0x7d) grey49
+ ( 0, 0,201) # rgb = (0x00,0x00,0xc9)
+ (123,123,123) # rgb = (0x7b,0x7b,0x7b)
+ (121,121,121) # rgb = (0x79,0x79,0x79)
+ ( 55, 55, 86) # rgb = (0x37,0x37,0x56)
+ (119,119,119) # rgb = (0x77,0x77,0x77)
+ (117,117,117) # rgb = (0x75,0x75,0x75) grey46
+ (115,115,115) # rgb = (0x73,0x73,0x73) grey45
+ ( 72,169, 72) # rgb = (0x48,0xa9,0x48)
+ (142, 0, 0) # rgb = (0x8e,0x00,0x00)
+ ( 2, 2,100) # rgb = (0x02,0x02,0x64)
+ ( 0, 0, 98) # rgb = (0x00,0x00,0x62)
+ ( 86,137, 86) # rgb = (0x56,0x89,0x56)
+ ( 40, 40,124) # rgb = (0x28,0x28,0x7c)
+ ( 83,139, 83) # rgb = (0x53,0x8b,0x53)
+ (137,137,143) # rgb = (0x89,0x89,0x8f)
+ (103,103,103) # rgb = (0x67,0x67,0x67)
+ (101,101,101) # rgb = (0x65,0x65,0x65)
+ ( 93,109, 93) # rgb = (0x5d,0x6d,0x5d)
+ ( 19,229, 19) # rgb = (0x13,0xe5,0x13)
+ (134, 38, 38) # rgb = (0x86,0x26,0x26)
+ (111, 45, 45) # rgb = (0x6f,0x2d,0x2d)
+ ( 68,145, 68) # rgb = (0x44,0x91,0x44)
+ ( 97, 97, 97) # rgb = (0x61,0x61,0x61) grey38
+ ( 59,157, 59) # rgb = (0x3b,0x9d,0x3b)
+ ( 68,137, 68) # rgb = (0x44,0x89,0x44)
+ ( 61,147, 61) # rgb = (0x3d,0x93,0x3d)
+ ( 0, 0,164) # rgb = (0x00,0x00,0xa4)
+ ( 0,243, 0) # rgb = (0x00,0xf3,0x00)
+ ( 0,241, 0) # rgb = (0x00,0xf1,0x00)
+ ( 89, 89, 89) # rgb = (0x59,0x59,0x59) grey35
+ ( 87, 87, 87) # rgb = (0x57,0x57,0x57) grey34
+ ( 85, 85, 85) # rgb = (0x55,0x55,0x55)
+ ( 83, 83, 83) # rgb = (0x53,0x53,0x53)
+ ( 52,133, 52) # rgb = (0x34,0x85,0x34)
+ ( 81, 81, 81) # rgb = (0x51,0x51,0x51)
+ ( 36,151, 36) # rgb = (0x24,0x97,0x24)
+ ( 79, 79, 79) # rgb = (0x4f,0x4f,0x4f) grey31
+ ( 58, 58, 65) # rgb = (0x3a,0x3a,0x41)
+ ( 16, 16,186) # rgb = (0x10,0x10,0xba)
+ (178, 15, 15) # rgb = (0xb2,0x0f,0x0f)
+ ( 0,199, 0) # rgb = (0x00,0xc7,0x00)
+ ( 0,197, 0) # rgb = (0x00,0xc5,0x00)
+ (252,252,252) # rgb = (0xfc,0xfc,0xfc) grey99
+ ( 0,195, 0) # rgb = (0x00,0xc3,0x00)
+ ( 4, 4,151) # rgb = (0x04,0x04,0x97)
+ ( 0,193, 0) # rgb = (0x00,0xc1,0x00)
+ ( 45,119, 45) # rgb = (0x2d,0x77,0x2d)
+ (250,250,250) # rgb = (0xfa,0xfa,0xfa) grey98
+ ( 0,191, 0) # rgb = (0x00,0xbf,0x00)
+ ( 0, 0,104) # rgb = (0x00,0x00,0x68)
+ ( 0,189, 0) # rgb = (0x00,0xbd,0x00)
+ (218,212,212) # rgb = (0xda,0xd4,0xd4)
+ ( 16, 16,123) # rgb = (0x10,0x10,0x7b)
+ ( 9,173, 9) # rgb = (0x09,0xad,0x09)
+ (248,248,248) # rgb = (0xf8,0xf8,0xf8)
+ ( 0,185, 0) # rgb = (0x00,0xb9,0x00)
+ ( 0,183, 0) # rgb = (0x00,0xb7,0x00)
+ (156,156,161) # rgb = (0x9c,0x9c,0xa1)
+ (246,246,246) # rgb = (0xf6,0xf6,0xf6)
+ ( 12,161, 12) # rgb = (0x0c,0xa1,0x0c)
+ ( 0,179, 0) # rgb = (0x00,0xb3,0x00)
+ ( 0,177, 0) # rgb = (0x00,0xb1,0x00)
+ ( 16,145, 16) # rgb = (0x10,0x91,0x10)
+ ( 0,171, 0) # rgb = (0x00,0xab,0x00)
+ (242,242,242) # rgb = (0xf2,0xf2,0xf2) grey95
+ ( 0,169, 0) # rgb = (0x00,0xa9,0x00)
+ ( 0,167, 0) # rgb = (0x00,0xa7,0x00)
+ (238,238,238) # rgb = (0xee,0xee,0xee)
+ (236,236,236) # rgb = (0xec,0xec,0xec)
+ ( 0,151, 0) # rgb = (0x00,0x97,0x00)
+ (234,234,234) # rgb = (0xea,0xea,0xea)
+ ( 0, 0,107) # rgb = (0x00,0x00,0x6b)
+ ( 0,141, 0) # rgb = (0x00,0x8d,0x00)
+ ( 0,139, 0) # rgb = (0x00,0x8b,0x00) green4
+ ( 0,137, 0) # rgb = (0x00,0x89,0x00)
+ ( 0,135, 0) # rgb = (0x00,0x87,0x00)
+ ( 49, 49, 49) # rgb = (0x31,0x31,0x31)
+ ( 25, 25, 42) # rgb = (0x19,0x19,0x2a)
+ ( 7, 7, 64) # rgb = (0x07,0x07,0x40)
+ ( 18, 18,174) # rgb = (0x12,0x12,0xae)
+ ( 9, 9,238) # rgb = (0x09,0x09,0xee)
+ (211,214,211) # rgb = (0xd3,0xd6,0xd3)
+ (204,204,204) # rgb = (0xcc,0xcc,0xcc) grey80
+ (147, 0, 0) # rgb = (0x93,0x00,0x00)
+ (163, 42, 42) # rgb = (0xa3,0x2a,0x2a)
+ (198,198,198) # rgb = (0xc6,0xc6,0xc6)
+ (196,196,196) # rgb = (0xc4,0xc4,0xc4) grey77
+ (204, 0, 0) # rgb = (0xcc,0x00,0x00)
+ (211, 10, 10) # rgb = (0xd3,0x0a,0x0a)
+ (129,107,107) # rgb = (0x81,0x6b,0x6b)
+ (120, 62, 62) # rgb = (0x78,0x3e,0x3e)
+ ( 3, 3,109) # rgb = (0x03,0x03,0x6d)
+ ( 0, 0,159) # rgb = (0x00,0x00,0x9f)
+ ( 10, 10, 86) # rgb = (0x0a,0x0a,0x56)
+ ( 70, 70, 72) # rgb = (0x46,0x46,0x48)
+ ( 65, 65, 77) # rgb = (0x41,0x41,0x4d)
+ (115, 93, 93) # rgb = (0x73,0x5d,0x5d)
+ ( 81, 7, 7) # rgb = (0x51,0x07,0x07)
+ (168,168,168) # rgb = (0xa8,0xa8,0xa8) grey66
+ (237,237,239) # rgb = (0xed,0xed,0xef)
+ (160,160,160) # rgb = (0xa0,0xa0,0xa0)
+ (158,158,158) # rgb = (0x9e,0x9e,0x9e) grey62
+ (156,156,156) # rgb = (0x9c,0x9c,0x9c) grey61
+ ( 0, 0,185) # rgb = (0x00,0x00,0xb9)
+ (154,154,154) # rgb = (0x9a,0x9a,0x9a)
+ (178, 0, 0) # rgb = (0xb2,0x00,0x00)
+ (152,152,152) # rgb = (0x98,0x98,0x98)
+ (235, 0, 0) # rgb = (0xeb,0x00,0x00)
+ (150,150,150) # rgb = (0x96,0x96,0x96) grey59
+ (158, 0, 0) # rgb = (0x9e,0x00,0x00)
+ (148,148,148) # rgb = (0x94,0x94,0x94) grey58
+ ( 19, 19, 28) # rgb = (0x13,0x13,0x1c)
+ (146,146,146) # rgb = (0x92,0x92,0x92)
+ (144,144,144) # rgb = (0x90,0x90,0x90)
+ (142,142,142) # rgb = (0x8e,0x8e,0x8e)
+ ( 0, 0,145) # rgb = (0x00,0x00,0x91)
+ (138,138,138) # rgb = (0x8a,0x8a,0x8a) grey54
+ (136,136,136) # rgb = (0x88,0x88,0x88)
+ (118,162,118) # rgb = (0x76,0xa2,0x76)
+ (133,136,133) # rgb = (0x85,0x88,0x85)
+ (134,134,134) # rgb = (0x86,0x86,0x86)
+ (132,132,132) # rgb = (0x84,0x84,0x84)
+ (120, 15, 15) # rgb = (0x78,0x0f,0x0f)
+ (130,130,130) # rgb = (0x82,0x82,0x82) grey51
+ (126,130,126) # rgb = (0x7e,0x82,0x7e)
+ (126,126,126) # rgb = (0x7e,0x7e,0x7e)
+ (124,124,124) # rgb = (0x7c,0x7c,0x7c)
+ (122,122,122) # rgb = (0x7a,0x7a,0x7a) grey48
+ ( 74,192, 74) # rgb = (0x4a,0xc0,0x4a)
+ (118,118,118) # rgb = (0x76,0x76,0x76)
+ (116,116,116) # rgb = (0x74,0x74,0x74)
+ (114,114,114) # rgb = (0x72,0x72,0x72)
+ (112,112,112) # rgb = (0x70,0x70,0x70) grey44
+ (152, 0, 0) # rgb = (0x98,0x00,0x00)
+ (110,110,110) # rgb = (0x6e,0x6e,0x6e) grey43
+ (106,112,106) # rgb = (0x6a,0x70,0x6a)
+ (122,102,102) # rgb = (0x7a,0x66,0x66)
+ (106,106,106) # rgb = (0x6a,0x6a,0x6a)
+ (132, 0, 0) # rgb = (0x84,0x00,0x00)
+ ( 68,162, 68) # rgb = (0x44,0xa2,0x44)
+ ( 75,150, 75) # rgb = (0x4b,0x96,0x4b)
+ ( 97,100, 97) # rgb = (0x61,0x64,0x61)
+ ( 98, 98, 98) # rgb = (0x62,0x62,0x62)
+ ( 0,244, 0) # rgb = (0x00,0xf4,0x00)
+ ( 56,152, 56) # rgb = (0x38,0x98,0x38)
+ ( 92, 92, 92) # rgb = (0x5c,0x5c,0x5c) grey36
+ ( 90, 90, 90) # rgb = (0x5a,0x5a,0x5a)
+ ( 0,230, 0) # rgb = (0x00,0xe6,0x00)
+ ( 2, 2, 93) # rgb = (0x02,0x02,0x5d)
+ ( 66,120, 66) # rgb = (0x42,0x78,0x42)
+ ( 86, 86, 86) # rgb = (0x56,0x56,0x56)
+ ( 0, 0,240) # rgb = (0x00,0x00,0xf0)
+ ( 46,148, 46) # rgb = (0x2e,0x94,0x2e)
+ ( 71,104, 71) # rgb = (0x47,0x68,0x47)
+ ( 49, 49, 96) # rgb = (0x31,0x31,0x60)
+ ( 0,216, 0) # rgb = (0x00,0xd8,0x00)
+ ( 82, 82, 82) # rgb = (0x52,0x52,0x52) grey32
+ ( 80, 80, 80) # rgb = (0x50,0x50,0x50)
+ ( 0,206, 0) # rgb = (0x00,0xce,0x00)
+ ( 33,152, 33) # rgb = (0x21,0x98,0x21)
+ ( 20, 20,109) # rgb = (0x14,0x14,0x6d)
+ ( 0,200, 0) # rgb = (0x00,0xc8,0x00)
+ ( 76, 76, 76) # rgb = (0x4c,0x4c,0x4c)
+ (253,253,253) # rgb = (0xfd,0xfd,0xfd)
+ ( 0,198, 0) # rgb = (0x00,0xc6,0x00)
+ ( 0, 0,157) # rgb = (0x00,0x00,0x9d)
+ (111,107,107) # rgb = (0x6f,0x6b,0x6b)
+ (234, 14, 14) # rgb = (0xea,0x0e,0x0e)
+ ( 72, 72, 72) # rgb = (0x48,0x48,0x48)
+ ( 0,188, 0) # rgb = (0x00,0xbc,0x00)
+ ( 52,102, 52) # rgb = (0x34,0x66,0x34)
+ ( 2, 2,245) # rgb = (0x02,0x02,0xf5)
+ ( 83, 83, 96) # rgb = (0x53,0x53,0x60)
+ ( 0,176, 0) # rgb = (0x00,0xb0,0x00)
+ ( 0,174, 0) # rgb = (0x00,0xae,0x00)
+ (183, 0, 0) # rgb = (0xb7,0x00,0x00)
+ ( 0,164, 0) # rgb = (0x00,0xa4,0x00)
+ (239,239,239) # rgb = (0xef,0xef,0xef)
+ ( 0,162, 0) # rgb = (0x00,0xa2,0x00)
+ (143, 79, 79) # rgb = (0x8f,0x4f,0x4f)
+ (149, 52, 52) # rgb = (0x95,0x34,0x34)
+ ( 0,152, 0) # rgb = (0x00,0x98,0x00)
+ ( 0,150, 0) # rgb = (0x00,0x96,0x00)
+ ( 0,146, 0) # rgb = (0x00,0x92,0x00)
+ (231,231,231) # rgb = (0xe7,0xe7,0xe7)
+ ( 0,140, 0) # rgb = (0x00,0x8c,0x00)
+ (227,227,227) # rgb = (0xe3,0xe3,0xe3) grey89
+ ( 0,128, 0) # rgb = (0x00,0x80,0x00)
+ (146, 6, 6) # rgb = (0x92,0x06,0x06)
+ ( 1, 1,111) # rgb = (0x01,0x01,0x6f)
+ (100, 86, 89) # rgb = (0x64,0x56,0x59)
+ ( 0, 0,100) # rgb = (0x00,0x00,0x64)
+ ( 78, 78,107) # rgb = (0x4e,0x4e,0x6b)
+ (207,207,207) # rgb = (0xcf,0xcf,0xcf) grey81
+ (221,221,224) # rgb = (0xdd,0xdd,0xe0)
+ ( 0, 0,123) # rgb = (0x00,0x00,0x7b)
+ (201,201,201) # rgb = (0xc9,0xc9,0xc9) grey79
+ ( 22, 22, 65) # rgb = (0x16,0x16,0x41)
+ ( 33, 33, 89) # rgb = (0x21,0x21,0x59)
+ ( 87, 87, 89) # rgb = (0x57,0x57,0x59)
+ ( 68, 68,120) # rgb = (0x44,0x44,0x78)
+ (191,191,191) # rgb = (0xbf,0xbf,0xbf) grey75
+ (235,221,221) # rgb = (0xeb,0xdd,0xdd)
+ ( 45, 45, 84) # rgb = (0x2d,0x2d,0x54)
+ ( 10, 10, 96) # rgb = (0x0a,0x0a,0x60)
+ ( 0, 0,255) # rgb = (0x00,0x00,0xff) blue1
+ (191,125,125) # rgb = (0xbf,0x7d,0x7d)
+ (255,255, 0) # rgb = (0xff,0xff,0x00) yellow1
+}
+bKGD {index: 245}
+tRNS {
+ 0}
+IMAGE {
+ pixels hex
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000e0ea66000000000000000000000000000000
+0000000000000000000000de02a336e43903f4f0000000000000000000000000
+000000000000000069ef1a358680062eb017b0ab7af459500000000000000000
+0000000000667c0ea9cc803979937917a03a878787b0e2ae8ae75c0000000000
+00005cea8ea72c8639e293208f7d7d19200639a017ab2ee4ac2ca7097c690000
+00007823a72b2bda198fd54ddad90521219191217d1917cc2b2b2b2baf8e0000
+0000e81f9b9f27014d05d91c2a2a2a7f037ecdcd7e7a012a2a2aaab7c2ef0000
+00006c9f229d981a23282828282828282828282828282828a7b445c3c8de0000
+00005ca249d63d140f139f272727272727272727a5a528af44c3c8ce43000000
+0000009a62ca41a6960e0d941da4a4a4a4a4a4a4a4a9b732525a1084a1000000
+000000965b58b53811940d0b090b1823a3a3252ab4d24c269957571088000000
+000000946162b9b59c0f14b12d0c8b8c98a3afb8ed1bbd82ba74300877000000
+00000088c565c7b5a6962dcf67be07048aa5b84315f326ba7395832950000000
+00000002bed8d4b94214b1c7dbb68c8b04a843e6d1bd814bceeb10a900000000
+0000007b47636ec441b23d4edb3f09078bac4315f340ec855a82995f00000000
+00000059bb63e15d42643dca6b3f8e090735ed76bd81c05224e9f27b00000000
+0000006cbbd47161c1684951dc3f908e8c3ceef38d08ebe96d6d086000000000
+00000050bf67dc54534fdd53ddb20d0b8eb815d10af1732fe312e60000000000
+00000000add6d6bf61c16f566eb20e0d924475bd578572c61e6d340000000000
+0000000016d8d3d03ec76bcfdf3b0f0e13bc4c8d2f84c040cb837b0000000000
+00000000550c47b3365bd45d6f33110f1a4575cbf2c0521e0802000000000000
+000000000000e7ac36be625e7031131122455a0a2f0a99c6e700000000000000
+000000000000006a9e37d36270331613a545f181e53032e80000000000000000
+00000000000000005088c5d371311816a8464b7374ee89000000000000000000
+0000000000000000000077b654a29b18acc24a722a5500000000000000000000
+0000000000000000000000d78a9f9e9b3548c38ac90000000000000000000000
+00000000000000000000000000ef1f9e3cc20200000000000000000000000000
+0000000000000000000000000000e89736780000000000000000000000000000
+00000000000000000000000000000060e0000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+}
diff --git a/src/image/png/testdata/pngsuite/ftp0n0g08.png b/src/image/png/testdata/pngsuite/ftp0n0g08.png
new file mode 100644
index 0000000..333465f
Binary files /dev/null and b/src/image/png/testdata/pngsuite/ftp0n0g08.png differ
diff --git a/src/image/png/testdata/pngsuite/ftp0n0g08.sng b/src/image/png/testdata/pngsuite/ftp0n0g08.sng
new file mode 100644
index 0000000..c8abd33
--- /dev/null
+++ b/src/image/png/testdata/pngsuite/ftp0n0g08.sng
@@ -0,0 +1,41 @@
+#SNG: from ftp0n0g08.png
+IHDR {
+ width: 32; height: 32; bitdepth: 8;
+ using grayscale;
+}
+gAMA {1.0000}
+IMAGE {
+ pixels hex
+7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f
+7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f
+7f7f7f7f7f7f7f7f7f7f7f7f7f7fe3c9f17f7f7f7f7f7f7f7f7f7f7f7f7f7f7f
+7f7f7f7f7f7f7f7f7f7f7fe8b57e655a4661a1e17f7f7f7f7f7f7f7f7f7f7f7f
+7f7f7f7f7f7f7f7feebf8967614d362a2824282f5091d4fc7f7f7f7f7f7f7f7f
+7f7f7f7f7ff2c495726c533e2e302c272b3d23181b28306ca0cff87f7f7f7f7f
+7f7ff7ca9a76736649313033353c3e38313c4533272d2b5a6e73769bc4ee7f7f
+7f7fcc7f7675754e3736373c55645042444845423e38266c757575756a9a7f7f
+7f7fdc8588847b6344476276777777726157524e4b4e63777777705c52bd7f7f
+7f7fea8481878e897f797979797979797979797979797979766354504ce67f7f
+7f7ff88268627890938f837b7b7b7b7b7b7b7b7b7a7a796a57504c49597f7f7f
+7f7f7f8a69748e8f92959794877c7c7c7c7c7c7c7c715b3314182d46827f7f7f
+7f7f7f92696f8f8f919497999b998b7f7e7e7d7762542517110c0c2fac7f7f7f
+7f7f7f946769848f9093937a7f979e9c8e7e6a5a572d1b120d080b24d67f7f7f
+7f7f7fa46764758f8f92836e636e9d9fa07a5a593e1d160d1a0d143efb7f7f7f
+7f7f7fb6665f658a8e907e765a6e9c9e9f745953201b0f3a481a30727f7f7f7f
+7f7f7fc76468537b8e7a757559709b9d9e6e593a1d132b442212119d7f7f7f7f
+7f7f7fd86368486c8d5b7474586f9a9b9d6757231b103717120e16c77f7f7f7f
+7f7f7fea61654e5d816268725870989a9c61491d15221c0e0c0c23f47f7f7f7f
+7f7f7ffc6063575871735771547497999a5a391c0f331c0d0d12517f7f7f7f7f
+7f7f7f7f6e606055697c51705373959796572c190c402b17140c877f7f7f7f7f
+7f7f7f7f8c5f67516876586e527193958f5622150e4735121212c57f7f7f7f7f
+7f7f7f7ffaa363636769666c5175919389551c121139151420b67f7f7f7f7f7f
+7f7f7f7f7f7fd06d6566686b50758f918155210f0c101025ce7f7f7f7f7f7f7f
+7f7f7f7f7f7f7fec8666676950738d8f7a542f0e0b0b31e07f7f7f7f7f7f7f7f
+7f7f7f7f7f7f7f7ffcaa67674f738b8d74533d1b134ced7f7f7f7f7f7f7f7f7f
+7f7f7f7f7f7f7f7f7f7fd472587f888b6d524f3777fa7f7f7f7f7f7f7f7f7f7f
+7f7f7f7f7f7f7f7f7f7f7fefa0838688675150a0fd7f7f7f7f7f7f7f7f7f7f7f
+7f7f7f7f7f7f7f7f7f7f7f7ffec085866152b77f7f7f7f7f7f7f7f7f7f7f7f7f
+7f7f7f7f7f7f7f7f7f7f7f7f7f7fde9065cc7f7f7f7f7f7f7f7f7f7f7f7f7f7f
+7f7f7f7f7f7f7f7f7f7f7f7f7f7f7ff5e37f7f7f7f7f7f7f7f7f7f7f7f7f7f7f
+7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f
+}
diff --git a/src/image/png/testdata/pngsuite/ftp0n2c08.png b/src/image/png/testdata/pngsuite/ftp0n2c08.png
new file mode 100644
index 0000000..fc6e42c
Binary files /dev/null and b/src/image/png/testdata/pngsuite/ftp0n2c08.png differ
diff --git a/src/image/png/testdata/pngsuite/ftp0n2c08.sng b/src/image/png/testdata/pngsuite/ftp0n2c08.sng
new file mode 100644
index 0000000..d41c7eb
--- /dev/null
+++ b/src/image/png/testdata/pngsuite/ftp0n2c08.sng
@@ -0,0 +1,41 @@
+#SNG: from ftp0n2c08.png
+IHDR {
+ width: 32; height: 32; bitdepth: 8;
+ using color;
+}
+gAMA {1.0000}
+IMAGE {
+ pixels hex
+7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f
+7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f
+7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f e3e3e3 c9c9c9 f1f1f1 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f
+7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f e8e8e8 b5b5b5 7e7e7e 656565 6e5252 7e2e2e a64343 c79090 ebdddd 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f
+7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f eeeeee bfbfbf 898989 676767 6b5d5d 7a3939 8a1212 8d0000 850000 770000 840000 9a0101 a22d2d bf7d7d ddd0d0 fcfcfc 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f
+7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f f2f2f2 c4c4c4 959595 727272 6f6b6b 774444 871e1e 950101 9f0000 910000 800000 720c0c 612d2d 530e0e 500000 590000 850000 920606 7a6666 a0a0a0 cfcfcf f8f8f8 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f
+7f7f7f 7f7f7f f7f7f7 cacaca 9a9a9a 767676 737373 7c5d5d 872e2e 930707 9e0000 a90000 b00000 c90000 cf0000 b90000 a20101 8c1919 852a2a 7f1313 810000 960000 8f0000 6b5353 6e6e6e 737373 767676 9b9b9b c4c4c4 eeeeee 7f7f7f 7f7f7f
+7f7f7f 7f7f7f cccccc 7f7f7f 767676 757575 757575 962f2f b80000 b40000 b60000 ad0c0c 943a3a 925050 b92323 d60202 e20000 ef0000 e70000 da0000 cf0000 ba0000 7d0101 6f6b6b 757575 757575 757575 757575 6a6a6a 9a9a9a 7f7f7f 7f7f7f
+7f7f7f 7f7f7f dcdcdc 858585 888888 848484 7b7b7b 855454 b71313 a91d1d 8d4f4f 787575 777777 777777 777777 816b6b aa4141 d62020 ec1010 e90c0c d01212 a52828 7b5858 777777 777777 777777 707070 5c5c5c 525252 bdbdbd 7f7f7f 7f7f7f
+7f7f7f 7f7f7f eaeaea 848484 818181 858885 8e8e8e 898989 7f7f7f 797979 797979 797979 797979 797979 797979 797979 797979 797979 797979 797979 797979 797979 797979 797979 767676 636363 545454 505050 4c4c4c e6e6e6 7f7f7f 7f7f7f
+7f7f7f 7f7f7f f8f8f8 7f847f 259725 04a504 39a439 8b948b 939393 8f8f8f 838383 7b7b7b 7b7b7b 7b7b7b 7b7b7b 7b7b7b 7b7b7b 7b7b7b 7b7b7b 7b7b7b 7a7a7a 7a7a7a 797979 6a6a6a 575757 505050 4c4c4c 494949 595959 7f7f7f 7f7f7f 7f7f7f
+7f7f7f 7f7f7f 7f7f7f 8a8a8a 01b301 00c600 00f200 59b659 929292 959595 979797 949494 878787 7c7c7c 7c7c7c 7c7c7c 7c7c7c 7c7c7c 7c7c7c 7c7c7c 7c7c7c 717171 5a5a60 282885 040493 0c0c78 282858 46464a 828282 7f7f7f 7f7f7f 7f7f7f
+7f7f7f 7f7f7f 7f7f7f 929292 0cab0c 00bd00 00f400 20dd20 919191 949494 979797 999999 9b9b9b 999999 8b8b8b 7f7f7f 7e7e7e 7e7e7e 7d7d7d 777777 626262 535360 1212be 0000cc 000092 000069 000067 2a2a55 acacac 7f7f7f 7f7f7f 7f7f7f
+7f7f7f 7f7f7f 7f7f7f 949494 16a116 00b400 00e200 00f400 76a276 939393 8d978d 469e46 46a746 8e9e8e 9e9e9e 9c9c9c 8e8e8e 7e7e7e 6a6a6a 5a5a5a 57575a 1818cd 0000f0 0000a0 020260 01013d 000061 1d1d59 d6d6d6 7f7f7f 7f7f7f 7f7f7f
+7f7f7f 7f7f7f 7f7f7f a4a4a4 219821 00aa00 00c800 00f400 3bca3b 929292 4aac4a 00bc00 00a900 2f9a2f 9d9d9d 9f9f9f a0a0a0 7a7a7a 5a5a5a 595959 3131a1 0000ff 0000c6 03035b 191924 0c0c15 0c0c55 3b3b53 fbfbfb 7f7f7f 7f7f7f 7f7f7f
+7f7f7f 7f7f7f 7f7f7f b6b6b6 2b8f2b 00a200 00ad00 00eb00 07ed07 899589 43a743 00c900 009900 389538 9c9c9c 9e9e9e 9f9f9f 747474 595959 505067 0505f5 0000f0 030370 383846 484848 161639 2b2b55 727272 7f7f7f 7f7f7f 7f7f7f 7f7f7f
+7f7f7f 7f7f7f 7f7f7f c7c7c7 348634 00b100 008d00 00d200 00f300 4c9b4c 3b9e3b 00c700 009800 3d943d 9b9b9b 9d9d9d 9e9e9e 6e6e6e 595959 2b2bad 0000ff 0000a6 252559 43434f 16167e 00009f 01018e 9c9ca1 7f7f7f 7f7f7f 7f7f7f 7f7f7f
+7f7f7f 7f7f7f 7f7f7f d8d8d8 3e7d3e 00b100 007b00 00b800 00f100 178b17 3b9c3b 00c600 009700 3d933d 9a9a9a 9b9b9b 9d9d9d 676767 575759 0909ee 0000f0 04046b 33335a 070790 00009e 00007c 0d0d5d c7c7c7 7f7f7f 7f7f7f 7f7f7f 7f7f7f
+7f7f7f 7f7f7f 7f7f7f eaeaea 477447 00ad00 008500 099809 00dc00 00a700 239823 00c300 009600 3f923f 989898 9a9a9a 9c9c9c 616161 42427f 0000ff 0000b9 1a1a5d 161649 00007b 00006b 00006b 1c1c56 f4f4f4 7f7f7f 7f7f7f 7f7f7f 7f7f7f
+7f7f7f 7f7f7f 7f7f7f fcfcfc 506c50 00a900 009500 2d772d 00c100 00c500 019301 00c100 009000 4b914b 979797 999999 9a9a9a 5a5a5a 2b2ba4 0000f6 000086 2f2f53 191930 020263 000073 00009b 4d4d70 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f
+7f7f7f 7f7f7f 7f7f7f 7f7f7f 687368 00a400 00a400 3e653e 14a514 00d400 008b00 00bf00 008e00 4a904a 959595 979797 969696 575757 1a1ab5 0000de 000068 3f3f4b 2b2b2b 0c0c6d 0000b3 00006b 868692 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f
+7f7f7f 7f7f7f 7f7f7f 7f7f7f 8c8c8c 059e05 00b000 346634 408540 00ca00 009700 00bc00 008c00 498e49 939393 959595 8f8f8f 565656 0f0fb7 0000b9 030366 474747 2f2f64 0000a2 00009d 090958 c5c5c5 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f
+7f7f7f 7f7f7f 7f7f7f 7f7f7f fafafa 90b090 348534 616461 636a63 06af06 00ae00 00b900 008b00 538d53 919191 939393 898989 555555 0a0aa8 00009d 070763 34345c 04049b 0000b1 1a1a4d b5b5bb 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f
+7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f d0d0d0 6d6d6d 656565 2d8f2d 00b200 00b600 008900 558b55 8f8f8f 919191 818181 555555 15157e 000084 010165 010184 000091 1c1c6e ceced0 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f
+7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f ececec 868686 587058 00af00 00b300 008800 538953 8d8d8d 8f8f8f 7a7a7a 545454 2c2c49 02026b 000064 000063 292974 dfdfe5 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f
+7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f fcfcfc aaaaaa 219821 00b000 008600 578757 8b8b8b 8d8d8d 747474 535353 3d3d3d 1a1a23 0d0d43 474772 ededef 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f
+7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f d1d6d1 389b38 2d772d 7d817d 888888 8b8b8b 6d6d6d 525252 4f4f4f 373737 777777 fafafa 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f
+7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f efefef a0a0a0 838383 868686 888888 676767 515151 505050 a0a0a0 fdfdfd 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f
+7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f fefefe c0c0c0 858585 868686 616161 525252 b7b7b7 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f
+7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f dedede 909090 656565 cccccc 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f
+7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f f5f5f5 e3e3e3 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f
+7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f 7f7f7f
+}
diff --git a/src/image/png/testdata/pngsuite/ftp0n3p08.png b/src/image/png/testdata/pngsuite/ftp0n3p08.png
new file mode 100644
index 0000000..69a69e5
Binary files /dev/null and b/src/image/png/testdata/pngsuite/ftp0n3p08.png differ
diff --git a/src/image/png/testdata/pngsuite/ftp0n3p08.sng b/src/image/png/testdata/pngsuite/ftp0n3p08.sng
new file mode 100644
index 0000000..f1f8448
--- /dev/null
+++ b/src/image/png/testdata/pngsuite/ftp0n3p08.sng
@@ -0,0 +1,288 @@
+#SNG: from ftp0n3p08.png
+IHDR {
+ width: 32; height: 32; bitdepth: 8;
+ using color palette;
+}
+gAMA {1.0000}
+PLTE {
+ ( 20, 20,109) # rgb = (0x14,0x14,0x6d)
+ (128, 86, 86) # rgb = (0x80,0x56,0x56)
+ (181,181,184) # rgb = (0xb5,0xb5,0xb8)
+ (168, 66, 66) # rgb = (0xa8,0x42,0x42)
+ (159,159,159) # rgb = (0x9f,0x9f,0x9f)
+ (177, 32, 32) # rgb = (0xb1,0x20,0x20)
+ (139, 21, 21) # rgb = (0x8b,0x15,0x15)
+ (157,157,157) # rgb = (0x9d,0x9d,0x9d)
+ ( 27, 27, 89) # rgb = (0x1b,0x1b,0x59)
+ (155,155,155) # rgb = (0x9b,0x9b,0x9b)
+ ( 0, 0,132) # rgb = (0x00,0x00,0x84)
+ (153,153,153) # rgb = (0x99,0x99,0x99) grey60
+ (143,167,143) # rgb = (0x8f,0xa7,0x8f)
+ (151,151,151) # rgb = (0x97,0x97,0x97)
+ (149,149,149) # rgb = (0x95,0x95,0x95)
+ (147,147,147) # rgb = (0x93,0x93,0x93)
+ ( 41, 41, 86) # rgb = (0x29,0x29,0x56)
+ (145,145,145) # rgb = (0x91,0x91,0x91) grey57
+ ( 0, 0,155) # rgb = (0x00,0x00,0x9b)
+ (143,143,143) # rgb = (0x8f,0x8f,0x8f) grey56
+ (139,149,139) # rgb = (0x8b,0x95,0x8b)
+ ( 46, 46,167) # rgb = (0x2e,0x2e,0xa7)
+ (141,141,141) # rgb = (0x8d,0x8d,0x8d)
+ (128, 0, 0) # rgb = (0x80,0x00,0x00)
+ (139,139,139) # rgb = (0x8b,0x8b,0x8b)
+ (185, 0, 0) # rgb = (0xb9,0x00,0x00)
+ (137,137,137) # rgb = (0x89,0x89,0x89)
+ ( 12, 12,213) # rgb = (0x0c,0x0c,0xd5)
+ (120,117,117) # rgb = (0x78,0x75,0x75)
+ (135,135,135) # rgb = (0x87,0x87,0x87) grey53
+ ( 0, 0,178) # rgb = (0x00,0x00,0xb2)
+ (133,133,133) # rgb = (0x85,0x85,0x85) grey52
+ (165, 0, 0) # rgb = (0xa5,0x00,0x00)
+ (222, 0, 0) # rgb = (0xde,0x00,0x00)
+ (129,129,129) # rgb = (0x81,0x81,0x81)
+ (127,127,127) # rgb = (0x7f,0x7f,0x7f) grey50
+ ( 0, 0,158) # rgb = (0x00,0x00,0x9e)
+ (125,125,125) # rgb = (0x7d,0x7d,0x7d) grey49
+ ( 0, 0,201) # rgb = (0x00,0x00,0xc9)
+ (123,123,123) # rgb = (0x7b,0x7b,0x7b)
+ (121,121,121) # rgb = (0x79,0x79,0x79)
+ ( 55, 55, 86) # rgb = (0x37,0x37,0x56)
+ (119,119,119) # rgb = (0x77,0x77,0x77)
+ (117,117,117) # rgb = (0x75,0x75,0x75) grey46
+ (115,115,115) # rgb = (0x73,0x73,0x73) grey45
+ ( 72,169, 72) # rgb = (0x48,0xa9,0x48)
+ (142, 0, 0) # rgb = (0x8e,0x00,0x00)
+ ( 2, 2,100) # rgb = (0x02,0x02,0x64)
+ ( 0, 0, 98) # rgb = (0x00,0x00,0x62)
+ ( 86,137, 86) # rgb = (0x56,0x89,0x56)
+ ( 40, 40,124) # rgb = (0x28,0x28,0x7c)
+ ( 83,139, 83) # rgb = (0x53,0x8b,0x53)
+ (137,137,143) # rgb = (0x89,0x89,0x8f)
+ (103,103,103) # rgb = (0x67,0x67,0x67)
+ (101,101,101) # rgb = (0x65,0x65,0x65)
+ ( 93,109, 93) # rgb = (0x5d,0x6d,0x5d)
+ ( 19,229, 19) # rgb = (0x13,0xe5,0x13)
+ (134, 38, 38) # rgb = (0x86,0x26,0x26)
+ (111, 45, 45) # rgb = (0x6f,0x2d,0x2d)
+ ( 68,145, 68) # rgb = (0x44,0x91,0x44)
+ ( 97, 97, 97) # rgb = (0x61,0x61,0x61) grey38
+ ( 59,157, 59) # rgb = (0x3b,0x9d,0x3b)
+ ( 68,137, 68) # rgb = (0x44,0x89,0x44)
+ ( 61,147, 61) # rgb = (0x3d,0x93,0x3d)
+ ( 0, 0,164) # rgb = (0x00,0x00,0xa4)
+ ( 0,243, 0) # rgb = (0x00,0xf3,0x00)
+ ( 0,241, 0) # rgb = (0x00,0xf1,0x00)
+ ( 89, 89, 89) # rgb = (0x59,0x59,0x59) grey35
+ ( 87, 87, 87) # rgb = (0x57,0x57,0x57) grey34
+ ( 85, 85, 85) # rgb = (0x55,0x55,0x55)
+ ( 83, 83, 83) # rgb = (0x53,0x53,0x53)
+ ( 52,133, 52) # rgb = (0x34,0x85,0x34)
+ ( 81, 81, 81) # rgb = (0x51,0x51,0x51)
+ ( 36,151, 36) # rgb = (0x24,0x97,0x24)
+ ( 79, 79, 79) # rgb = (0x4f,0x4f,0x4f) grey31
+ ( 58, 58, 65) # rgb = (0x3a,0x3a,0x41)
+ ( 16, 16,186) # rgb = (0x10,0x10,0xba)
+ (178, 15, 15) # rgb = (0xb2,0x0f,0x0f)
+ ( 0,199, 0) # rgb = (0x00,0xc7,0x00)
+ ( 0,197, 0) # rgb = (0x00,0xc5,0x00)
+ (252,252,252) # rgb = (0xfc,0xfc,0xfc) grey99
+ ( 0,195, 0) # rgb = (0x00,0xc3,0x00)
+ ( 4, 4,151) # rgb = (0x04,0x04,0x97)
+ ( 0,193, 0) # rgb = (0x00,0xc1,0x00)
+ ( 45,119, 45) # rgb = (0x2d,0x77,0x2d)
+ (250,250,250) # rgb = (0xfa,0xfa,0xfa) grey98
+ ( 0,191, 0) # rgb = (0x00,0xbf,0x00)
+ ( 0, 0,104) # rgb = (0x00,0x00,0x68)
+ ( 0,189, 0) # rgb = (0x00,0xbd,0x00)
+ (218,212,212) # rgb = (0xda,0xd4,0xd4)
+ ( 16, 16,123) # rgb = (0x10,0x10,0x7b)
+ ( 9,173, 9) # rgb = (0x09,0xad,0x09)
+ (248,248,248) # rgb = (0xf8,0xf8,0xf8)
+ ( 0,185, 0) # rgb = (0x00,0xb9,0x00)
+ ( 0,183, 0) # rgb = (0x00,0xb7,0x00)
+ (156,156,161) # rgb = (0x9c,0x9c,0xa1)
+ (246,246,246) # rgb = (0xf6,0xf6,0xf6)
+ ( 12,161, 12) # rgb = (0x0c,0xa1,0x0c)
+ ( 0,179, 0) # rgb = (0x00,0xb3,0x00)
+ ( 0,177, 0) # rgb = (0x00,0xb1,0x00)
+ ( 16,145, 16) # rgb = (0x10,0x91,0x10)
+ ( 0,171, 0) # rgb = (0x00,0xab,0x00)
+ (242,242,242) # rgb = (0xf2,0xf2,0xf2) grey95
+ ( 0,169, 0) # rgb = (0x00,0xa9,0x00)
+ ( 0,167, 0) # rgb = (0x00,0xa7,0x00)
+ (238,238,238) # rgb = (0xee,0xee,0xee)
+ (236,236,236) # rgb = (0xec,0xec,0xec)
+ ( 0,151, 0) # rgb = (0x00,0x97,0x00)
+ (234,234,234) # rgb = (0xea,0xea,0xea)
+ ( 0, 0,107) # rgb = (0x00,0x00,0x6b)
+ ( 0,141, 0) # rgb = (0x00,0x8d,0x00)
+ ( 0,139, 0) # rgb = (0x00,0x8b,0x00) green4
+ ( 0,137, 0) # rgb = (0x00,0x89,0x00)
+ ( 0,135, 0) # rgb = (0x00,0x87,0x00)
+ ( 49, 49, 49) # rgb = (0x31,0x31,0x31)
+ ( 25, 25, 42) # rgb = (0x19,0x19,0x2a)
+ ( 7, 7, 64) # rgb = (0x07,0x07,0x40)
+ ( 18, 18,174) # rgb = (0x12,0x12,0xae)
+ ( 9, 9,238) # rgb = (0x09,0x09,0xee)
+ (211,214,211) # rgb = (0xd3,0xd6,0xd3)
+ (204,204,204) # rgb = (0xcc,0xcc,0xcc) grey80
+ (147, 0, 0) # rgb = (0x93,0x00,0x00)
+ (163, 42, 42) # rgb = (0xa3,0x2a,0x2a)
+ (198,198,198) # rgb = (0xc6,0xc6,0xc6)
+ (196,196,196) # rgb = (0xc4,0xc4,0xc4) grey77
+ (204, 0, 0) # rgb = (0xcc,0x00,0x00)
+ (211, 10, 10) # rgb = (0xd3,0x0a,0x0a)
+ (129,107,107) # rgb = (0x81,0x6b,0x6b)
+ (120, 62, 62) # rgb = (0x78,0x3e,0x3e)
+ ( 3, 3,109) # rgb = (0x03,0x03,0x6d)
+ ( 0, 0,159) # rgb = (0x00,0x00,0x9f)
+ ( 10, 10, 86) # rgb = (0x0a,0x0a,0x56)
+ ( 70, 70, 72) # rgb = (0x46,0x46,0x48)
+ ( 65, 65, 77) # rgb = (0x41,0x41,0x4d)
+ (115, 93, 93) # rgb = (0x73,0x5d,0x5d)
+ ( 81, 7, 7) # rgb = (0x51,0x07,0x07)
+ (168,168,168) # rgb = (0xa8,0xa8,0xa8) grey66
+ (237,237,239) # rgb = (0xed,0xed,0xef)
+ (160,160,160) # rgb = (0xa0,0xa0,0xa0)
+ (158,158,158) # rgb = (0x9e,0x9e,0x9e) grey62
+ (156,156,156) # rgb = (0x9c,0x9c,0x9c) grey61
+ ( 0, 0,185) # rgb = (0x00,0x00,0xb9)
+ (154,154,154) # rgb = (0x9a,0x9a,0x9a)
+ (178, 0, 0) # rgb = (0xb2,0x00,0x00)
+ (152,152,152) # rgb = (0x98,0x98,0x98)
+ (235, 0, 0) # rgb = (0xeb,0x00,0x00)
+ (150,150,150) # rgb = (0x96,0x96,0x96) grey59
+ (158, 0, 0) # rgb = (0x9e,0x00,0x00)
+ (148,148,148) # rgb = (0x94,0x94,0x94) grey58
+ ( 19, 19, 28) # rgb = (0x13,0x13,0x1c)
+ (146,146,146) # rgb = (0x92,0x92,0x92)
+ (144,144,144) # rgb = (0x90,0x90,0x90)
+ (142,142,142) # rgb = (0x8e,0x8e,0x8e)
+ ( 0, 0,145) # rgb = (0x00,0x00,0x91)
+ (138,138,138) # rgb = (0x8a,0x8a,0x8a) grey54
+ (136,136,136) # rgb = (0x88,0x88,0x88)
+ (118,162,118) # rgb = (0x76,0xa2,0x76)
+ (133,136,133) # rgb = (0x85,0x88,0x85)
+ (134,134,134) # rgb = (0x86,0x86,0x86)
+ (132,132,132) # rgb = (0x84,0x84,0x84)
+ (120, 15, 15) # rgb = (0x78,0x0f,0x0f)
+ (130,130,130) # rgb = (0x82,0x82,0x82) grey51
+ (126,130,126) # rgb = (0x7e,0x82,0x7e)
+ (126,126,126) # rgb = (0x7e,0x7e,0x7e)
+ (124,124,124) # rgb = (0x7c,0x7c,0x7c)
+ (122,122,122) # rgb = (0x7a,0x7a,0x7a) grey48
+ ( 74,192, 74) # rgb = (0x4a,0xc0,0x4a)
+ (118,118,118) # rgb = (0x76,0x76,0x76)
+ (116,116,116) # rgb = (0x74,0x74,0x74)
+ (114,114,114) # rgb = (0x72,0x72,0x72)
+ (112,112,112) # rgb = (0x70,0x70,0x70) grey44
+ (152, 0, 0) # rgb = (0x98,0x00,0x00)
+ (110,110,110) # rgb = (0x6e,0x6e,0x6e) grey43
+ (106,112,106) # rgb = (0x6a,0x70,0x6a)
+ (122,102,102) # rgb = (0x7a,0x66,0x66)
+ (106,106,106) # rgb = (0x6a,0x6a,0x6a)
+ (132, 0, 0) # rgb = (0x84,0x00,0x00)
+ ( 68,162, 68) # rgb = (0x44,0xa2,0x44)
+ ( 75,150, 75) # rgb = (0x4b,0x96,0x4b)
+ ( 97,100, 97) # rgb = (0x61,0x64,0x61)
+ ( 98, 98, 98) # rgb = (0x62,0x62,0x62)
+ ( 0,244, 0) # rgb = (0x00,0xf4,0x00)
+ ( 56,152, 56) # rgb = (0x38,0x98,0x38)
+ ( 92, 92, 92) # rgb = (0x5c,0x5c,0x5c) grey36
+ ( 90, 90, 90) # rgb = (0x5a,0x5a,0x5a)
+ ( 0,230, 0) # rgb = (0x00,0xe6,0x00)
+ ( 2, 2, 93) # rgb = (0x02,0x02,0x5d)
+ ( 66,120, 66) # rgb = (0x42,0x78,0x42)
+ ( 86, 86, 86) # rgb = (0x56,0x56,0x56)
+ ( 0, 0,240) # rgb = (0x00,0x00,0xf0)
+ ( 46,148, 46) # rgb = (0x2e,0x94,0x2e)
+ ( 71,104, 71) # rgb = (0x47,0x68,0x47)
+ ( 49, 49, 96) # rgb = (0x31,0x31,0x60)
+ ( 0,216, 0) # rgb = (0x00,0xd8,0x00)
+ ( 82, 82, 82) # rgb = (0x52,0x52,0x52) grey32
+ ( 80, 80, 80) # rgb = (0x50,0x50,0x50)
+ ( 0,206, 0) # rgb = (0x00,0xce,0x00)
+ ( 33,152, 33) # rgb = (0x21,0x98,0x21)
+ (255,255,255) # rgb = (0xff,0xff,0xff) grey100
+ ( 0,200, 0) # rgb = (0x00,0xc8,0x00)
+ ( 76, 76, 76) # rgb = (0x4c,0x4c,0x4c)
+ (253,253,253) # rgb = (0xfd,0xfd,0xfd)
+ ( 0,198, 0) # rgb = (0x00,0xc6,0x00)
+ ( 0, 0,157) # rgb = (0x00,0x00,0x9d)
+ (111,107,107) # rgb = (0x6f,0x6b,0x6b)
+ (234, 14, 14) # rgb = (0xea,0x0e,0x0e)
+ ( 72, 72, 72) # rgb = (0x48,0x48,0x48)
+ ( 0,188, 0) # rgb = (0x00,0xbc,0x00)
+ ( 52,102, 52) # rgb = (0x34,0x66,0x34)
+ ( 2, 2,245) # rgb = (0x02,0x02,0xf5)
+ ( 83, 83, 96) # rgb = (0x53,0x53,0x60)
+ ( 0,176, 0) # rgb = (0x00,0xb0,0x00)
+ ( 0,174, 0) # rgb = (0x00,0xae,0x00)
+ (183, 0, 0) # rgb = (0xb7,0x00,0x00)
+ ( 0,164, 0) # rgb = (0x00,0xa4,0x00)
+ (239,239,239) # rgb = (0xef,0xef,0xef)
+ ( 0,162, 0) # rgb = (0x00,0xa2,0x00)
+ (143, 79, 79) # rgb = (0x8f,0x4f,0x4f)
+ (149, 52, 52) # rgb = (0x95,0x34,0x34)
+ ( 0,152, 0) # rgb = (0x00,0x98,0x00)
+ ( 0,150, 0) # rgb = (0x00,0x96,0x00)
+ ( 0,146, 0) # rgb = (0x00,0x92,0x00)
+ (231,231,231) # rgb = (0xe7,0xe7,0xe7)
+ ( 0,140, 0) # rgb = (0x00,0x8c,0x00)
+ (227,227,227) # rgb = (0xe3,0xe3,0xe3) grey89
+ ( 0,128, 0) # rgb = (0x00,0x80,0x00)
+ (146, 6, 6) # rgb = (0x92,0x06,0x06)
+ ( 1, 1,111) # rgb = (0x01,0x01,0x6f)
+ (100, 86, 89) # rgb = (0x64,0x56,0x59)
+ ( 0, 0,100) # rgb = (0x00,0x00,0x64)
+ ( 78, 78,107) # rgb = (0x4e,0x4e,0x6b)
+ (207,207,207) # rgb = (0xcf,0xcf,0xcf) grey81
+ (221,221,224) # rgb = (0xdd,0xdd,0xe0)
+ ( 0, 0,123) # rgb = (0x00,0x00,0x7b)
+ (201,201,201) # rgb = (0xc9,0xc9,0xc9) grey79
+ ( 22, 22, 65) # rgb = (0x16,0x16,0x41)
+ ( 33, 33, 89) # rgb = (0x21,0x21,0x59)
+ ( 87, 87, 89) # rgb = (0x57,0x57,0x59)
+ ( 68, 68,120) # rgb = (0x44,0x44,0x78)
+ (191,191,191) # rgb = (0xbf,0xbf,0xbf) grey75
+ (235,221,221) # rgb = (0xeb,0xdd,0xdd)
+ ( 45, 45, 84) # rgb = (0x2d,0x2d,0x54)
+ ( 10, 10, 96) # rgb = (0x0a,0x0a,0x60)
+ ( 0, 0,255) # rgb = (0x00,0x00,0xff) blue1
+ (191,125,125) # rgb = (0xbf,0x7d,0x7d)
+}
+IMAGE {
+ pixels hex
+2323232323232323232323232323232323232323232323232323232323232323
+2323232323232323232323232323232323232323232323232323232323232323
+2323232323232323232323232323e0ea66232323232323232323232323232323
+2323232323232323232323de02a336e43903f4f0232323232323232323232323
+232323232323232369ef1a358680062eb017b0ab7af459502323232323232323
+2323232323667c0ea9cc803979937917a03a878787b0e2ae8ae75c2323232323
+23235cea8ea72c8639e293208f7d7d19200639a017ab2ee4ac2ca7097c692323
+23237823a72b2bda198fd54ddad90521219191217d1917cc2b2b2b2baf8e2323
+2323e81f9b9f27014d05d91c2a2a2a7f037ecdcd7e7a012a2a2aaab7c2ef2323
+23236c9f229d981a23282828282828282828282828282828a7b445c3c8de2323
+23235ca249d63d140f139f272727272727272727a5a528af44c3c8ce43232323
+2323239a62ca41a6960e0d941da4a4a4a4a4a4a4a4a9b732525a1084a1232323
+232323965b58b53811940d0b090b1823a3a3252ab4d24c269957571088232323
+232323946162b9b59c0f14b12d0c8b8c98a3afb8ed1bbd82ba74300877232323
+23232388c565c7b5a6962dcf67be07048aa5b84315f326ba7395832950232323
+23232302bed8d4b94214b1c7dbb68c8b04a843e6d1bd814bceeb10a923232323
+2323237b47636ec441b23d4edb3f09078bac4315f340ec855a82995f23232323
+23232359bb63e15d42643dca6b3f8e090735ed76bd81c05224e9f27b23232323
+2323236cbbd47161c1684951dc3f908e8c3ceef38d08ebe96d6d086023232323
+23232350bf67dc54534fdd53ddb20d0b8eb815d10af1732fe312e62323232323
+23232323add6d6bf61c16f566eb20e0d924475bd578572001e6d342323232323
+2323232316d8d3d03ec76bcfdf3b0f0e13bc4c8d2f84c040cb837b2323232323
+23232323550c47b3365bd45d6f33110f1a4575cbf2c0521e0802232323232323
+232323232323e7ac36be625e7031131122455a0a2f0a9900e723232323232323
+232323232323236a9e37d36270331613a545f181e53032e82323232323232323
+23232323232323235088c5d371311816a8464b7374ee89232323232323232323
+2323232323232323232377b654a29b18acc24a722a5523232323232323232323
+2323232323232323232323d78a9f9e9b3548c38ac92323232323232323232323
+232323232323232323232323c6ef1f9e3cc20223232323232323232323232323
+2323232323232323232323232323e89736782323232323232323232323232323
+23232323232323232323232323232360e0232323232323232323232323232323
+2323232323232323232323232323232323232323232323232323232323232323
+}
diff --git a/src/image/png/testdata/pngsuite/ftp1n3p08.png b/src/image/png/testdata/pngsuite/ftp1n3p08.png
new file mode 100644
index 0000000..a6c9f35
Binary files /dev/null and b/src/image/png/testdata/pngsuite/ftp1n3p08.png differ
diff --git a/src/image/png/testdata/pngsuite/ftp1n3p08.sng b/src/image/png/testdata/pngsuite/ftp1n3p08.sng
new file mode 100644
index 0000000..2d179e2
--- /dev/null
+++ b/src/image/png/testdata/pngsuite/ftp1n3p08.sng
@@ -0,0 +1,290 @@
+#SNG: from ftp1n3p08.png
+IHDR {
+ width: 32; height: 32; bitdepth: 8;
+ using color palette;
+}
+gAMA {1.0000}
+PLTE {
+ (255,255,255) # rgb = (0xff,0xff,0xff) grey100
+ (128, 86, 86) # rgb = (0x80,0x56,0x56)
+ (181,181,184) # rgb = (0xb5,0xb5,0xb8)
+ (168, 66, 66) # rgb = (0xa8,0x42,0x42)
+ (159,159,159) # rgb = (0x9f,0x9f,0x9f)
+ (177, 32, 32) # rgb = (0xb1,0x20,0x20)
+ (139, 21, 21) # rgb = (0x8b,0x15,0x15)
+ (157,157,157) # rgb = (0x9d,0x9d,0x9d)
+ ( 27, 27, 89) # rgb = (0x1b,0x1b,0x59)
+ (155,155,155) # rgb = (0x9b,0x9b,0x9b)
+ ( 0, 0,132) # rgb = (0x00,0x00,0x84)
+ (153,153,153) # rgb = (0x99,0x99,0x99) grey60
+ (143,167,143) # rgb = (0x8f,0xa7,0x8f)
+ (151,151,151) # rgb = (0x97,0x97,0x97)
+ (149,149,149) # rgb = (0x95,0x95,0x95)
+ (147,147,147) # rgb = (0x93,0x93,0x93)
+ ( 41, 41, 86) # rgb = (0x29,0x29,0x56)
+ (145,145,145) # rgb = (0x91,0x91,0x91) grey57
+ ( 0, 0,155) # rgb = (0x00,0x00,0x9b)
+ (143,143,143) # rgb = (0x8f,0x8f,0x8f) grey56
+ (139,149,139) # rgb = (0x8b,0x95,0x8b)
+ ( 46, 46,167) # rgb = (0x2e,0x2e,0xa7)
+ (141,141,141) # rgb = (0x8d,0x8d,0x8d)
+ (128, 0, 0) # rgb = (0x80,0x00,0x00)
+ (139,139,139) # rgb = (0x8b,0x8b,0x8b)
+ (185, 0, 0) # rgb = (0xb9,0x00,0x00)
+ (137,137,137) # rgb = (0x89,0x89,0x89)
+ ( 12, 12,213) # rgb = (0x0c,0x0c,0xd5)
+ (120,117,117) # rgb = (0x78,0x75,0x75)
+ (135,135,135) # rgb = (0x87,0x87,0x87) grey53
+ ( 0, 0,178) # rgb = (0x00,0x00,0xb2)
+ (133,133,133) # rgb = (0x85,0x85,0x85) grey52
+ (165, 0, 0) # rgb = (0xa5,0x00,0x00)
+ (222, 0, 0) # rgb = (0xde,0x00,0x00)
+ (129,129,129) # rgb = (0x81,0x81,0x81)
+ (127,127,127) # rgb = (0x7f,0x7f,0x7f) grey50
+ ( 0, 0,158) # rgb = (0x00,0x00,0x9e)
+ (125,125,125) # rgb = (0x7d,0x7d,0x7d) grey49
+ ( 0, 0,201) # rgb = (0x00,0x00,0xc9)
+ (123,123,123) # rgb = (0x7b,0x7b,0x7b)
+ (121,121,121) # rgb = (0x79,0x79,0x79)
+ ( 55, 55, 86) # rgb = (0x37,0x37,0x56)
+ (119,119,119) # rgb = (0x77,0x77,0x77)
+ (117,117,117) # rgb = (0x75,0x75,0x75) grey46
+ (115,115,115) # rgb = (0x73,0x73,0x73) grey45
+ ( 72,169, 72) # rgb = (0x48,0xa9,0x48)
+ (142, 0, 0) # rgb = (0x8e,0x00,0x00)
+ ( 2, 2,100) # rgb = (0x02,0x02,0x64)
+ ( 0, 0, 98) # rgb = (0x00,0x00,0x62)
+ ( 86,137, 86) # rgb = (0x56,0x89,0x56)
+ ( 40, 40,124) # rgb = (0x28,0x28,0x7c)
+ ( 83,139, 83) # rgb = (0x53,0x8b,0x53)
+ (137,137,143) # rgb = (0x89,0x89,0x8f)
+ (103,103,103) # rgb = (0x67,0x67,0x67)
+ (101,101,101) # rgb = (0x65,0x65,0x65)
+ ( 93,109, 93) # rgb = (0x5d,0x6d,0x5d)
+ ( 19,229, 19) # rgb = (0x13,0xe5,0x13)
+ (134, 38, 38) # rgb = (0x86,0x26,0x26)
+ (111, 45, 45) # rgb = (0x6f,0x2d,0x2d)
+ ( 68,145, 68) # rgb = (0x44,0x91,0x44)
+ ( 97, 97, 97) # rgb = (0x61,0x61,0x61) grey38
+ ( 59,157, 59) # rgb = (0x3b,0x9d,0x3b)
+ ( 68,137, 68) # rgb = (0x44,0x89,0x44)
+ ( 61,147, 61) # rgb = (0x3d,0x93,0x3d)
+ ( 0, 0,164) # rgb = (0x00,0x00,0xa4)
+ ( 0,243, 0) # rgb = (0x00,0xf3,0x00)
+ ( 0,241, 0) # rgb = (0x00,0xf1,0x00)
+ ( 89, 89, 89) # rgb = (0x59,0x59,0x59) grey35
+ ( 87, 87, 87) # rgb = (0x57,0x57,0x57) grey34
+ ( 85, 85, 85) # rgb = (0x55,0x55,0x55)
+ ( 83, 83, 83) # rgb = (0x53,0x53,0x53)
+ ( 52,133, 52) # rgb = (0x34,0x85,0x34)
+ ( 81, 81, 81) # rgb = (0x51,0x51,0x51)
+ ( 36,151, 36) # rgb = (0x24,0x97,0x24)
+ ( 79, 79, 79) # rgb = (0x4f,0x4f,0x4f) grey31
+ ( 58, 58, 65) # rgb = (0x3a,0x3a,0x41)
+ ( 16, 16,186) # rgb = (0x10,0x10,0xba)
+ (178, 15, 15) # rgb = (0xb2,0x0f,0x0f)
+ ( 0,199, 0) # rgb = (0x00,0xc7,0x00)
+ ( 0,197, 0) # rgb = (0x00,0xc5,0x00)
+ (252,252,252) # rgb = (0xfc,0xfc,0xfc) grey99
+ ( 0,195, 0) # rgb = (0x00,0xc3,0x00)
+ ( 4, 4,151) # rgb = (0x04,0x04,0x97)
+ ( 0,193, 0) # rgb = (0x00,0xc1,0x00)
+ ( 45,119, 45) # rgb = (0x2d,0x77,0x2d)
+ (250,250,250) # rgb = (0xfa,0xfa,0xfa) grey98
+ ( 0,191, 0) # rgb = (0x00,0xbf,0x00)
+ ( 0, 0,104) # rgb = (0x00,0x00,0x68)
+ ( 0,189, 0) # rgb = (0x00,0xbd,0x00)
+ (218,212,212) # rgb = (0xda,0xd4,0xd4)
+ ( 16, 16,123) # rgb = (0x10,0x10,0x7b)
+ ( 9,173, 9) # rgb = (0x09,0xad,0x09)
+ (248,248,248) # rgb = (0xf8,0xf8,0xf8)
+ ( 0,185, 0) # rgb = (0x00,0xb9,0x00)
+ ( 0,183, 0) # rgb = (0x00,0xb7,0x00)
+ (156,156,161) # rgb = (0x9c,0x9c,0xa1)
+ (246,246,246) # rgb = (0xf6,0xf6,0xf6)
+ ( 12,161, 12) # rgb = (0x0c,0xa1,0x0c)
+ ( 0,179, 0) # rgb = (0x00,0xb3,0x00)
+ ( 0,177, 0) # rgb = (0x00,0xb1,0x00)
+ ( 16,145, 16) # rgb = (0x10,0x91,0x10)
+ ( 0,171, 0) # rgb = (0x00,0xab,0x00)
+ (242,242,242) # rgb = (0xf2,0xf2,0xf2) grey95
+ ( 0,169, 0) # rgb = (0x00,0xa9,0x00)
+ ( 0,167, 0) # rgb = (0x00,0xa7,0x00)
+ (238,238,238) # rgb = (0xee,0xee,0xee)
+ (236,236,236) # rgb = (0xec,0xec,0xec)
+ ( 0,151, 0) # rgb = (0x00,0x97,0x00)
+ (234,234,234) # rgb = (0xea,0xea,0xea)
+ ( 0, 0,107) # rgb = (0x00,0x00,0x6b)
+ ( 0,141, 0) # rgb = (0x00,0x8d,0x00)
+ ( 0,139, 0) # rgb = (0x00,0x8b,0x00) green4
+ ( 0,137, 0) # rgb = (0x00,0x89,0x00)
+ ( 0,135, 0) # rgb = (0x00,0x87,0x00)
+ ( 49, 49, 49) # rgb = (0x31,0x31,0x31)
+ ( 25, 25, 42) # rgb = (0x19,0x19,0x2a)
+ ( 7, 7, 64) # rgb = (0x07,0x07,0x40)
+ ( 18, 18,174) # rgb = (0x12,0x12,0xae)
+ ( 9, 9,238) # rgb = (0x09,0x09,0xee)
+ (211,214,211) # rgb = (0xd3,0xd6,0xd3)
+ (204,204,204) # rgb = (0xcc,0xcc,0xcc) grey80
+ (147, 0, 0) # rgb = (0x93,0x00,0x00)
+ (163, 42, 42) # rgb = (0xa3,0x2a,0x2a)
+ (198,198,198) # rgb = (0xc6,0xc6,0xc6)
+ (196,196,196) # rgb = (0xc4,0xc4,0xc4) grey77
+ (204, 0, 0) # rgb = (0xcc,0x00,0x00)
+ (211, 10, 10) # rgb = (0xd3,0x0a,0x0a)
+ (129,107,107) # rgb = (0x81,0x6b,0x6b)
+ (120, 62, 62) # rgb = (0x78,0x3e,0x3e)
+ ( 3, 3,109) # rgb = (0x03,0x03,0x6d)
+ ( 0, 0,159) # rgb = (0x00,0x00,0x9f)
+ ( 10, 10, 86) # rgb = (0x0a,0x0a,0x56)
+ ( 70, 70, 72) # rgb = (0x46,0x46,0x48)
+ ( 65, 65, 77) # rgb = (0x41,0x41,0x4d)
+ (115, 93, 93) # rgb = (0x73,0x5d,0x5d)
+ ( 81, 7, 7) # rgb = (0x51,0x07,0x07)
+ (168,168,168) # rgb = (0xa8,0xa8,0xa8) grey66
+ (237,237,239) # rgb = (0xed,0xed,0xef)
+ (160,160,160) # rgb = (0xa0,0xa0,0xa0)
+ (158,158,158) # rgb = (0x9e,0x9e,0x9e) grey62
+ (156,156,156) # rgb = (0x9c,0x9c,0x9c) grey61
+ ( 0, 0,185) # rgb = (0x00,0x00,0xb9)
+ (154,154,154) # rgb = (0x9a,0x9a,0x9a)
+ (178, 0, 0) # rgb = (0xb2,0x00,0x00)
+ (152,152,152) # rgb = (0x98,0x98,0x98)
+ (235, 0, 0) # rgb = (0xeb,0x00,0x00)
+ (150,150,150) # rgb = (0x96,0x96,0x96) grey59
+ (158, 0, 0) # rgb = (0x9e,0x00,0x00)
+ (148,148,148) # rgb = (0x94,0x94,0x94) grey58
+ ( 19, 19, 28) # rgb = (0x13,0x13,0x1c)
+ (146,146,146) # rgb = (0x92,0x92,0x92)
+ (144,144,144) # rgb = (0x90,0x90,0x90)
+ (142,142,142) # rgb = (0x8e,0x8e,0x8e)
+ ( 0, 0,145) # rgb = (0x00,0x00,0x91)
+ (138,138,138) # rgb = (0x8a,0x8a,0x8a) grey54
+ (136,136,136) # rgb = (0x88,0x88,0x88)
+ (118,162,118) # rgb = (0x76,0xa2,0x76)
+ (133,136,133) # rgb = (0x85,0x88,0x85)
+ (134,134,134) # rgb = (0x86,0x86,0x86)
+ (132,132,132) # rgb = (0x84,0x84,0x84)
+ (120, 15, 15) # rgb = (0x78,0x0f,0x0f)
+ (130,130,130) # rgb = (0x82,0x82,0x82) grey51
+ (126,130,126) # rgb = (0x7e,0x82,0x7e)
+ (126,126,126) # rgb = (0x7e,0x7e,0x7e)
+ (124,124,124) # rgb = (0x7c,0x7c,0x7c)
+ (122,122,122) # rgb = (0x7a,0x7a,0x7a) grey48
+ ( 74,192, 74) # rgb = (0x4a,0xc0,0x4a)
+ (118,118,118) # rgb = (0x76,0x76,0x76)
+ (116,116,116) # rgb = (0x74,0x74,0x74)
+ (114,114,114) # rgb = (0x72,0x72,0x72)
+ (112,112,112) # rgb = (0x70,0x70,0x70) grey44
+ (152, 0, 0) # rgb = (0x98,0x00,0x00)
+ (110,110,110) # rgb = (0x6e,0x6e,0x6e) grey43
+ (106,112,106) # rgb = (0x6a,0x70,0x6a)
+ (122,102,102) # rgb = (0x7a,0x66,0x66)
+ (106,106,106) # rgb = (0x6a,0x6a,0x6a)
+ (132, 0, 0) # rgb = (0x84,0x00,0x00)
+ ( 68,162, 68) # rgb = (0x44,0xa2,0x44)
+ ( 75,150, 75) # rgb = (0x4b,0x96,0x4b)
+ ( 97,100, 97) # rgb = (0x61,0x64,0x61)
+ ( 98, 98, 98) # rgb = (0x62,0x62,0x62)
+ ( 0,244, 0) # rgb = (0x00,0xf4,0x00)
+ ( 56,152, 56) # rgb = (0x38,0x98,0x38)
+ ( 92, 92, 92) # rgb = (0x5c,0x5c,0x5c) grey36
+ ( 90, 90, 90) # rgb = (0x5a,0x5a,0x5a)
+ ( 0,230, 0) # rgb = (0x00,0xe6,0x00)
+ ( 2, 2, 93) # rgb = (0x02,0x02,0x5d)
+ ( 66,120, 66) # rgb = (0x42,0x78,0x42)
+ ( 86, 86, 86) # rgb = (0x56,0x56,0x56)
+ ( 0, 0,240) # rgb = (0x00,0x00,0xf0)
+ ( 46,148, 46) # rgb = (0x2e,0x94,0x2e)
+ ( 71,104, 71) # rgb = (0x47,0x68,0x47)
+ ( 49, 49, 96) # rgb = (0x31,0x31,0x60)
+ ( 0,216, 0) # rgb = (0x00,0xd8,0x00)
+ ( 82, 82, 82) # rgb = (0x52,0x52,0x52) grey32
+ ( 80, 80, 80) # rgb = (0x50,0x50,0x50)
+ ( 0,206, 0) # rgb = (0x00,0xce,0x00)
+ ( 33,152, 33) # rgb = (0x21,0x98,0x21)
+ ( 20, 20,109) # rgb = (0x14,0x14,0x6d)
+ ( 0,200, 0) # rgb = (0x00,0xc8,0x00)
+ ( 76, 76, 76) # rgb = (0x4c,0x4c,0x4c)
+ (253,253,253) # rgb = (0xfd,0xfd,0xfd)
+ ( 0,198, 0) # rgb = (0x00,0xc6,0x00)
+ ( 0, 0,157) # rgb = (0x00,0x00,0x9d)
+ (111,107,107) # rgb = (0x6f,0x6b,0x6b)
+ (234, 14, 14) # rgb = (0xea,0x0e,0x0e)
+ ( 72, 72, 72) # rgb = (0x48,0x48,0x48)
+ ( 0,188, 0) # rgb = (0x00,0xbc,0x00)
+ ( 52,102, 52) # rgb = (0x34,0x66,0x34)
+ ( 2, 2,245) # rgb = (0x02,0x02,0xf5)
+ ( 83, 83, 96) # rgb = (0x53,0x53,0x60)
+ ( 0,176, 0) # rgb = (0x00,0xb0,0x00)
+ ( 0,174, 0) # rgb = (0x00,0xae,0x00)
+ (183, 0, 0) # rgb = (0xb7,0x00,0x00)
+ ( 0,164, 0) # rgb = (0x00,0xa4,0x00)
+ (239,239,239) # rgb = (0xef,0xef,0xef)
+ ( 0,162, 0) # rgb = (0x00,0xa2,0x00)
+ (143, 79, 79) # rgb = (0x8f,0x4f,0x4f)
+ (149, 52, 52) # rgb = (0x95,0x34,0x34)
+ ( 0,152, 0) # rgb = (0x00,0x98,0x00)
+ ( 0,150, 0) # rgb = (0x00,0x96,0x00)
+ ( 0,146, 0) # rgb = (0x00,0x92,0x00)
+ (231,231,231) # rgb = (0xe7,0xe7,0xe7)
+ ( 0,140, 0) # rgb = (0x00,0x8c,0x00)
+ (227,227,227) # rgb = (0xe3,0xe3,0xe3) grey89
+ ( 0,128, 0) # rgb = (0x00,0x80,0x00)
+ (146, 6, 6) # rgb = (0x92,0x06,0x06)
+ ( 1, 1,111) # rgb = (0x01,0x01,0x6f)
+ (100, 86, 89) # rgb = (0x64,0x56,0x59)
+ ( 0, 0,100) # rgb = (0x00,0x00,0x64)
+ ( 78, 78,107) # rgb = (0x4e,0x4e,0x6b)
+ (207,207,207) # rgb = (0xcf,0xcf,0xcf) grey81
+ (221,221,224) # rgb = (0xdd,0xdd,0xe0)
+ ( 0, 0,123) # rgb = (0x00,0x00,0x7b)
+ (201,201,201) # rgb = (0xc9,0xc9,0xc9) grey79
+ ( 22, 22, 65) # rgb = (0x16,0x16,0x41)
+ ( 33, 33, 89) # rgb = (0x21,0x21,0x59)
+ ( 87, 87, 89) # rgb = (0x57,0x57,0x59)
+ ( 68, 68,120) # rgb = (0x44,0x44,0x78)
+ (191,191,191) # rgb = (0xbf,0xbf,0xbf) grey75
+ (235,221,221) # rgb = (0xeb,0xdd,0xdd)
+ ( 45, 45, 84) # rgb = (0x2d,0x2d,0x54)
+ ( 10, 10, 96) # rgb = (0x0a,0x0a,0x60)
+ ( 0, 0,255) # rgb = (0x00,0x00,0xff) blue1
+ (191,125,125) # rgb = (0xbf,0x7d,0x7d)
+}
+tRNS {
+ 0}
+IMAGE {
+ pixels hex
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000e0ea66000000000000000000000000000000
+0000000000000000000000de02a336e43903f4f0000000000000000000000000
+000000000000000069ef1a358680062eb017b0ab7af459500000000000000000
+0000000000667c0ea9cc803979937917a03a878787b0e2ae8ae75c0000000000
+00005cea8ea72c8639e293208f7d7d19200639a017ab2ee4ac2ca7097c690000
+00007823a72b2bda198fd54ddad90521219191217d1917cc2b2b2b2baf8e0000
+0000e81f9b9f27014d05d91c2a2a2a7f037ecdcd7e7a012a2a2aaab7c2ef0000
+00006c9f229d981a23282828282828282828282828282828a7b445c3c8de0000
+00005ca249d63d140f139f272727272727272727a5a528af44c3c8ce43000000
+0000009a62ca41a6960e0d941da4a4a4a4a4a4a4a4a9b732525a1084a1000000
+000000965b58b53811940d0b090b1823a3a3252ab4d24c269957571088000000
+000000946162b9b59c0f14b12d0c8b8c98a3afb8ed1bbd82ba74300877000000
+00000088c565c7b5a6962dcf67be07048aa5b84315f326ba7395832950000000
+00000002bed8d4b94214b1c7dbb68c8b04a843e6d1bd814bceeb10a900000000
+0000007b47636ec441b23d4edb3f09078bac4315f340ec855a82995f00000000
+00000059bb63e15d42643dca6b3f8e090735ed76bd81c05224e9f27b00000000
+0000006cbbd47161c1684951dc3f908e8c3ceef38d08ebe96d6d086000000000
+00000050bf67dc54534fdd53ddb20d0b8eb815d10af1732fe312e60000000000
+00000000add6d6bf61c16f566eb20e0d924475bd578572c61e6d340000000000
+0000000016d8d3d03ec76bcfdf3b0f0e13bc4c8d2f84c040cb837b0000000000
+00000000550c47b3365bd45d6f33110f1a4575cbf2c0521e0802000000000000
+000000000000e7ac36be625e7031131122455a0a2f0a99c6e700000000000000
+000000000000006a9e37d36270331613a545f181e53032e80000000000000000
+00000000000000005088c5d371311816a8464b7374ee89000000000000000000
+0000000000000000000077b654a29b18acc24a722a5500000000000000000000
+0000000000000000000000d78a9f9e9b3548c38ac90000000000000000000000
+00000000000000000000000000ef1f9e3cc20200000000000000000000000000
+0000000000000000000000000000e89736780000000000000000000000000000
+00000000000000000000000000000060e0000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+}
diff --git a/src/image/png/writer.go b/src/image/png/writer.go
index df23270..dd87d81 100644
--- a/src/image/png/writer.go
+++ b/src/image/png/writer.go
@@ -420,8 +420,11 @@ func writeImage(w io.Writer, m image.Image, cb int, level int) error {
}
// Apply the filter.
+ // Skip filter for NoCompression and paletted images (cbP8) as
+ // "filters are rarely useful on palette images" and will result
+ // in larger files (see http://www.libpng.org/pub/png/book/chapter09.html).
f := ftNone
- if level != zlib.NoCompression {
+ if level != zlib.NoCompression && cb != cbP8 {
f = filter(&cr, pr, bpp)
}
diff --git a/src/index/suffixarray/example_test.go b/src/index/suffixarray/example_test.go
new file mode 100644
index 0000000..ea10bfd
--- /dev/null
+++ b/src/index/suffixarray/example_test.go
@@ -0,0 +1,22 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package suffixarray_test
+
+import (
+ "fmt"
+ "index/suffixarray"
+)
+
+func ExampleIndex_Lookup() {
+ index := suffixarray.New([]byte("banana"))
+ offsets := index.Lookup([]byte("ana"), -1)
+ for _, off := range offsets {
+ fmt.Println(off)
+ }
+
+ // Unordered output:
+ // 1
+ // 3
+}
diff --git a/src/cmd/internal/pprof/profile/encode.go b/src/internal/pprof/profile/encode.go
similarity index 100%
rename from src/cmd/internal/pprof/profile/encode.go
rename to src/internal/pprof/profile/encode.go
diff --git a/src/cmd/internal/pprof/profile/filter.go b/src/internal/pprof/profile/filter.go
similarity index 100%
rename from src/cmd/internal/pprof/profile/filter.go
rename to src/internal/pprof/profile/filter.go
diff --git a/src/internal/pprof/profile/legacy_profile.go b/src/internal/pprof/profile/legacy_profile.go
new file mode 100644
index 0000000..d69f8de
--- /dev/null
+++ b/src/internal/pprof/profile/legacy_profile.go
@@ -0,0 +1,1266 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file implements parsers to convert legacy profiles into the
+// profile.proto format.
+
+package profile
+
+import (
+ "bufio"
+ "bytes"
+ "fmt"
+ "io"
+ "math"
+ "regexp"
+ "strconv"
+ "strings"
+)
+
+var (
+ countStartRE = regexp.MustCompile(`\A(\w+) profile: total \d+\n\z`)
+ countRE = regexp.MustCompile(`\A(\d+) @(( 0x[0-9a-f]+)+)\n\z`)
+
+ heapHeaderRE = regexp.MustCompile(`heap profile: *(\d+): *(\d+) *\[ *(\d+): *(\d+) *\] *@ *(heap[_a-z0-9]*)/?(\d*)`)
+ heapSampleRE = regexp.MustCompile(`(-?\d+): *(-?\d+) *\[ *(\d+): *(\d+) *] @([ x0-9a-f]*)`)
+
+ contentionSampleRE = regexp.MustCompile(`(\d+) *(\d+) @([ x0-9a-f]*)`)
+
+ hexNumberRE = regexp.MustCompile(`0x[0-9a-f]+`)
+
+ growthHeaderRE = regexp.MustCompile(`heap profile: *(\d+): *(\d+) *\[ *(\d+): *(\d+) *\] @ growthz`)
+
+ fragmentationHeaderRE = regexp.MustCompile(`heap profile: *(\d+): *(\d+) *\[ *(\d+): *(\d+) *\] @ fragmentationz`)
+
+ threadzStartRE = regexp.MustCompile(`--- threadz \d+ ---`)
+ threadStartRE = regexp.MustCompile(`--- Thread ([[:xdigit:]]+) \(name: (.*)/(\d+)\) stack: ---`)
+
+ procMapsRE = regexp.MustCompile(`([[:xdigit:]]+)-([[:xdigit:]]+)\s+([-rwxp]+)\s+([[:xdigit:]]+)\s+([[:xdigit:]]+):([[:xdigit:]]+)\s+([[:digit:]]+)\s*(\S+)?`)
+
+ briefMapsRE = regexp.MustCompile(`\s*([[:xdigit:]]+)-([[:xdigit:]]+):\s*(\S+)(\s.*@)?([[:xdigit:]]+)?`)
+
+ // LegacyHeapAllocated instructs the heapz parsers to use the
+ // allocated memory stats instead of the default in-use memory. Note
+ // that tcmalloc doesn't provide all allocated memory, only in-use
+ // stats.
+ LegacyHeapAllocated bool
+)
+
+func isSpaceOrComment(line string) bool {
+ trimmed := strings.TrimSpace(line)
+ return len(trimmed) == 0 || trimmed[0] == '#'
+}
+
+// parseGoCount parses a Go count profile (e.g., threadcreate or
+// goroutine) and returns a new Profile.
+func parseGoCount(b []byte) (*Profile, error) {
+ r := bytes.NewBuffer(b)
+
+ var line string
+ var err error
+ for {
+ // Skip past comments and empty lines seeking a real header.
+ line, err = r.ReadString('\n')
+ if err != nil {
+ return nil, err
+ }
+ if !isSpaceOrComment(line) {
+ break
+ }
+ }
+
+ m := countStartRE.FindStringSubmatch(line)
+ if m == nil {
+ return nil, errUnrecognized
+ }
+ profileType := m[1]
+ p := &Profile{
+ PeriodType: &ValueType{Type: profileType, Unit: "count"},
+ Period: 1,
+ SampleType: []*ValueType{{Type: profileType, Unit: "count"}},
+ }
+ locations := make(map[uint64]*Location)
+ for {
+ line, err = r.ReadString('\n')
+ if err != nil {
+ if err == io.EOF {
+ break
+ }
+ return nil, err
+ }
+ if isSpaceOrComment(line) {
+ continue
+ }
+ if strings.HasPrefix(line, "---") {
+ break
+ }
+ m := countRE.FindStringSubmatch(line)
+ if m == nil {
+ return nil, errMalformed
+ }
+ n, err := strconv.ParseInt(m[1], 0, 64)
+ if err != nil {
+ return nil, errMalformed
+ }
+ fields := strings.Fields(m[2])
+ locs := make([]*Location, 0, len(fields))
+ for _, stk := range fields {
+ addr, err := strconv.ParseUint(stk, 0, 64)
+ if err != nil {
+ return nil, errMalformed
+ }
+ // Adjust all frames by -1 to land on the call instruction.
+ addr--
+ loc := locations[addr]
+ if loc == nil {
+ loc = &Location{
+ Address: addr,
+ }
+ locations[addr] = loc
+ p.Location = append(p.Location, loc)
+ }
+ locs = append(locs, loc)
+ }
+ p.Sample = append(p.Sample, &Sample{
+ Location: locs,
+ Value: []int64{n},
+ })
+ }
+
+ if err = parseAdditionalSections(strings.TrimSpace(line), r, p); err != nil {
+ return nil, err
+ }
+ return p, nil
+}
+
+// remapLocationIDs ensures there is a location for each address
+// referenced by a sample, and remaps the samples to point to the new
+// location ids.
+func (p *Profile) remapLocationIDs() {
+ seen := make(map[*Location]bool, len(p.Location))
+ var locs []*Location
+
+ for _, s := range p.Sample {
+ for _, l := range s.Location {
+ if seen[l] {
+ continue
+ }
+ l.ID = uint64(len(locs) + 1)
+ locs = append(locs, l)
+ seen[l] = true
+ }
+ }
+ p.Location = locs
+}
+
+func (p *Profile) remapFunctionIDs() {
+ seen := make(map[*Function]bool, len(p.Function))
+ var fns []*Function
+
+ for _, l := range p.Location {
+ for _, ln := range l.Line {
+ fn := ln.Function
+ if fn == nil || seen[fn] {
+ continue
+ }
+ fn.ID = uint64(len(fns) + 1)
+ fns = append(fns, fn)
+ seen[fn] = true
+ }
+ }
+ p.Function = fns
+}
+
+// remapMappingIDs matches location addresses with existing mappings
+// and updates them appropriately. This is O(N*M), if this ever shows
+// up as a bottleneck, evaluate sorting the mappings and doing a
+// binary search, which would make it O(N*log(M)).
+func (p *Profile) remapMappingIDs() {
+ if len(p.Mapping) == 0 {
+ return
+ }
+
+ // Some profile handlers will incorrectly set regions for the main
+ // executable if its section is remapped. Fix them through heuristics.
+
+ // Remove the initial mapping if named '/anon_hugepage' and has a
+ // consecutive adjacent mapping.
+ if m := p.Mapping[0]; strings.HasPrefix(m.File, "/anon_hugepage") {
+ if len(p.Mapping) > 1 && m.Limit == p.Mapping[1].Start {
+ p.Mapping = p.Mapping[1:]
+ }
+ }
+
+ // Subtract the offset from the start of the main mapping if it
+ // ends up at a recognizable start address.
+ const expectedStart = 0x400000
+ if m := p.Mapping[0]; m.Start-m.Offset == expectedStart {
+ m.Start = expectedStart
+ m.Offset = 0
+ }
+
+ for _, l := range p.Location {
+ if a := l.Address; a != 0 {
+ for _, m := range p.Mapping {
+ if m.Start <= a && a < m.Limit {
+ l.Mapping = m
+ break
+ }
+ }
+ }
+ }
+
+ // Reset all mapping IDs.
+ for i, m := range p.Mapping {
+ m.ID = uint64(i + 1)
+ }
+}
+
+var cpuInts = []func([]byte) (uint64, []byte){
+ get32l,
+ get32b,
+ get64l,
+ get64b,
+}
+
+func get32l(b []byte) (uint64, []byte) {
+ if len(b) < 4 {
+ return 0, nil
+ }
+ return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24, b[4:]
+}
+
+func get32b(b []byte) (uint64, []byte) {
+ if len(b) < 4 {
+ return 0, nil
+ }
+ return uint64(b[3]) | uint64(b[2])<<8 | uint64(b[1])<<16 | uint64(b[0])<<24, b[4:]
+}
+
+func get64l(b []byte) (uint64, []byte) {
+ if len(b) < 8 {
+ return 0, nil
+ }
+ return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 | uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56, b[8:]
+}
+
+func get64b(b []byte) (uint64, []byte) {
+ if len(b) < 8 {
+ return 0, nil
+ }
+ return uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 | uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56, b[8:]
+}
+
+// ParseTracebacks parses a set of tracebacks and returns a newly
+// populated profile. It will accept any text file and generate a
+// Profile out of it with any hex addresses it can identify, including
+// a process map if it can recognize one. Each sample will include a
+// tag "source" with the addresses recognized in string format.
+func ParseTracebacks(b []byte) (*Profile, error) {
+ r := bytes.NewBuffer(b)
+
+ p := &Profile{
+ PeriodType: &ValueType{Type: "trace", Unit: "count"},
+ Period: 1,
+ SampleType: []*ValueType{
+ {Type: "trace", Unit: "count"},
+ },
+ }
+
+ var sources []string
+ var sloc []*Location
+
+ locs := make(map[uint64]*Location)
+ for {
+ l, err := r.ReadString('\n')
+ if err != nil {
+ if err != io.EOF {
+ return nil, err
+ }
+ if l == "" {
+ break
+ }
+ }
+ if sectionTrigger(l) == memoryMapSection {
+ break
+ }
+ if s, addrs := extractHexAddresses(l); len(s) > 0 {
+ for _, addr := range addrs {
+ // Addresses from stack traces point to the next instruction after
+ // each call. Adjust by -1 to land somewhere on the actual call.
+ addr--
+ loc := locs[addr]
+ if locs[addr] == nil {
+ loc = &Location{
+ Address: addr,
+ }
+ p.Location = append(p.Location, loc)
+ locs[addr] = loc
+ }
+ sloc = append(sloc, loc)
+ }
+
+ sources = append(sources, s...)
+ } else {
+ if len(sources) > 0 || len(sloc) > 0 {
+ addTracebackSample(sloc, sources, p)
+ sloc, sources = nil, nil
+ }
+ }
+ }
+
+ // Add final sample to save any leftover data.
+ if len(sources) > 0 || len(sloc) > 0 {
+ addTracebackSample(sloc, sources, p)
+ }
+
+ if err := p.ParseMemoryMap(r); err != nil {
+ return nil, err
+ }
+ return p, nil
+}
+
+func addTracebackSample(l []*Location, s []string, p *Profile) {
+ p.Sample = append(p.Sample,
+ &Sample{
+ Value: []int64{1},
+ Location: l,
+ Label: map[string][]string{"source": s},
+ })
+}
+
+// parseCPU parses a profilez legacy profile and returns a newly
+// populated Profile.
+//
+// The general format for profilez samples is a sequence of words in
+// binary format. The first words are a header with the following data:
+// 1st word -- 0
+// 2nd word -- 3
+// 3rd word -- 0 if a c++ application, 1 if a java application.
+// 4th word -- Sampling period (in microseconds).
+// 5th word -- Padding.
+func parseCPU(b []byte) (*Profile, error) {
+ var parse func([]byte) (uint64, []byte)
+ var n1, n2, n3, n4, n5 uint64
+ for _, parse = range cpuInts {
+ var tmp []byte
+ n1, tmp = parse(b)
+ n2, tmp = parse(tmp)
+ n3, tmp = parse(tmp)
+ n4, tmp = parse(tmp)
+ n5, tmp = parse(tmp)
+
+ if tmp != nil && n1 == 0 && n2 == 3 && n3 == 0 && n4 > 0 && n5 == 0 {
+ b = tmp
+ return cpuProfile(b, int64(n4), parse)
+ }
+ }
+ return nil, errUnrecognized
+}
+
+// cpuProfile returns a new Profile from C++ profilez data.
+// b is the profile bytes after the header, period is the profiling
+// period, and parse is a function to parse 8-byte chunks from the
+// profile in its native endianness.
+func cpuProfile(b []byte, period int64, parse func(b []byte) (uint64, []byte)) (*Profile, error) {
+ p := &Profile{
+ Period: period * 1000,
+ PeriodType: &ValueType{Type: "cpu", Unit: "nanoseconds"},
+ SampleType: []*ValueType{
+ {Type: "samples", Unit: "count"},
+ {Type: "cpu", Unit: "nanoseconds"},
+ },
+ }
+ var err error
+ if b, _, err = parseCPUSamples(b, parse, true, p); err != nil {
+ return nil, err
+ }
+
+ // If all samples have the same second-to-the-bottom frame, it
+ // strongly suggests that it is an uninteresting artifact of
+ // measurement -- a stack frame pushed by the signal handler. The
+ // bottom frame is always correct as it is picked up from the signal
+ // structure, not the stack. Check if this is the case and if so,
+ // remove.
+ if len(p.Sample) > 1 && len(p.Sample[0].Location) > 1 {
+ allSame := true
+ id1 := p.Sample[0].Location[1].Address
+ for _, s := range p.Sample {
+ if len(s.Location) < 2 || id1 != s.Location[1].Address {
+ allSame = false
+ break
+ }
+ }
+ if allSame {
+ for _, s := range p.Sample {
+ s.Location = append(s.Location[:1], s.Location[2:]...)
+ }
+ }
+ }
+
+ if err := p.ParseMemoryMap(bytes.NewBuffer(b)); err != nil {
+ return nil, err
+ }
+ return p, nil
+}
+
+// parseCPUSamples parses a collection of profilez samples from a
+// profile.
+//
+// profilez samples are a repeated sequence of stack frames of the
+// form:
+// 1st word -- The number of times this stack was encountered.
+// 2nd word -- The size of the stack (StackSize).
+// 3rd word -- The first address on the stack.
+// ...
+// StackSize + 2 -- The last address on the stack
+// The last stack trace is of the form:
+// 1st word -- 0
+// 2nd word -- 1
+// 3rd word -- 0
+//
+// Addresses from stack traces may point to the next instruction after
+// each call. Optionally adjust by -1 to land somewhere on the actual
+// call (except for the leaf, which is not a call).
+func parseCPUSamples(b []byte, parse func(b []byte) (uint64, []byte), adjust bool, p *Profile) ([]byte, map[uint64]*Location, error) {
+ locs := make(map[uint64]*Location)
+ for len(b) > 0 {
+ var count, nstk uint64
+ count, b = parse(b)
+ nstk, b = parse(b)
+ if b == nil || nstk > uint64(len(b)/4) {
+ return nil, nil, errUnrecognized
+ }
+ var sloc []*Location
+ addrs := make([]uint64, nstk)
+ for i := 0; i < int(nstk); i++ {
+ addrs[i], b = parse(b)
+ }
+
+ if count == 0 && nstk == 1 && addrs[0] == 0 {
+ // End of data marker
+ break
+ }
+ for i, addr := range addrs {
+ if adjust && i > 0 {
+ addr--
+ }
+ loc := locs[addr]
+ if loc == nil {
+ loc = &Location{
+ Address: addr,
+ }
+ locs[addr] = loc
+ p.Location = append(p.Location, loc)
+ }
+ sloc = append(sloc, loc)
+ }
+ p.Sample = append(p.Sample,
+ &Sample{
+ Value: []int64{int64(count), int64(count) * p.Period},
+ Location: sloc,
+ })
+ }
+ // Reached the end without finding the EOD marker.
+ return b, locs, nil
+}
+
+// parseHeap parses a heapz legacy or a growthz profile and
+// returns a newly populated Profile.
+func parseHeap(b []byte) (p *Profile, err error) {
+ r := bytes.NewBuffer(b)
+ l, err := r.ReadString('\n')
+ if err != nil {
+ return nil, errUnrecognized
+ }
+
+ sampling := ""
+
+ if header := heapHeaderRE.FindStringSubmatch(l); header != nil {
+ p = &Profile{
+ SampleType: []*ValueType{
+ {Type: "objects", Unit: "count"},
+ {Type: "space", Unit: "bytes"},
+ },
+ PeriodType: &ValueType{Type: "objects", Unit: "bytes"},
+ }
+
+ var period int64
+ if len(header[6]) > 0 {
+ if period, err = strconv.ParseInt(header[6], 10, 64); err != nil {
+ return nil, errUnrecognized
+ }
+ }
+
+ switch header[5] {
+ case "heapz_v2", "heap_v2":
+ sampling, p.Period = "v2", period
+ case "heapprofile":
+ sampling, p.Period = "", 1
+ case "heap":
+ sampling, p.Period = "v2", period/2
+ default:
+ return nil, errUnrecognized
+ }
+ } else if header = growthHeaderRE.FindStringSubmatch(l); header != nil {
+ p = &Profile{
+ SampleType: []*ValueType{
+ {Type: "objects", Unit: "count"},
+ {Type: "space", Unit: "bytes"},
+ },
+ PeriodType: &ValueType{Type: "heapgrowth", Unit: "count"},
+ Period: 1,
+ }
+ } else if header = fragmentationHeaderRE.FindStringSubmatch(l); header != nil {
+ p = &Profile{
+ SampleType: []*ValueType{
+ {Type: "objects", Unit: "count"},
+ {Type: "space", Unit: "bytes"},
+ },
+ PeriodType: &ValueType{Type: "allocations", Unit: "count"},
+ Period: 1,
+ }
+ } else {
+ return nil, errUnrecognized
+ }
+
+ if LegacyHeapAllocated {
+ for _, st := range p.SampleType {
+ st.Type = "alloc_" + st.Type
+ }
+ } else {
+ for _, st := range p.SampleType {
+ st.Type = "inuse_" + st.Type
+ }
+ }
+
+ locs := make(map[uint64]*Location)
+ for {
+ l, err = r.ReadString('\n')
+ if err != nil {
+ if err != io.EOF {
+ return nil, err
+ }
+
+ if l == "" {
+ break
+ }
+ }
+
+ if isSpaceOrComment(l) {
+ continue
+ }
+ l = strings.TrimSpace(l)
+
+ if sectionTrigger(l) != unrecognizedSection {
+ break
+ }
+
+ value, blocksize, addrs, err := parseHeapSample(l, p.Period, sampling)
+ if err != nil {
+ return nil, err
+ }
+ var sloc []*Location
+ for _, addr := range addrs {
+ // Addresses from stack traces point to the next instruction after
+ // each call. Adjust by -1 to land somewhere on the actual call.
+ addr--
+ loc := locs[addr]
+ if locs[addr] == nil {
+ loc = &Location{
+ Address: addr,
+ }
+ p.Location = append(p.Location, loc)
+ locs[addr] = loc
+ }
+ sloc = append(sloc, loc)
+ }
+
+ p.Sample = append(p.Sample, &Sample{
+ Value: value,
+ Location: sloc,
+ NumLabel: map[string][]int64{"bytes": {blocksize}},
+ })
+ }
+
+ if err = parseAdditionalSections(l, r, p); err != nil {
+ return nil, err
+ }
+ return p, nil
+}
+
+// parseHeapSample parses a single row from a heap profile into a new Sample.
+func parseHeapSample(line string, rate int64, sampling string) (value []int64, blocksize int64, addrs []uint64, err error) {
+ sampleData := heapSampleRE.FindStringSubmatch(line)
+ if len(sampleData) != 6 {
+ return value, blocksize, addrs, fmt.Errorf("unexpected number of sample values: got %d, want 6", len(sampleData))
+ }
+
+ // Use first two values by default; tcmalloc sampling generates the
+ // same value for both, only the older heap-profile collect separate
+ // stats for in-use and allocated objects.
+ valueIndex := 1
+ if LegacyHeapAllocated {
+ valueIndex = 3
+ }
+
+ var v1, v2 int64
+ if v1, err = strconv.ParseInt(sampleData[valueIndex], 10, 64); err != nil {
+ return value, blocksize, addrs, fmt.Errorf("malformed sample: %s: %v", line, err)
+ }
+ if v2, err = strconv.ParseInt(sampleData[valueIndex+1], 10, 64); err != nil {
+ return value, blocksize, addrs, fmt.Errorf("malformed sample: %s: %v", line, err)
+ }
+
+ if v1 == 0 {
+ if v2 != 0 {
+ return value, blocksize, addrs, fmt.Errorf("allocation count was 0 but allocation bytes was %d", v2)
+ }
+ } else {
+ blocksize = v2 / v1
+ if sampling == "v2" {
+ v1, v2 = scaleHeapSample(v1, v2, rate)
+ }
+ }
+
+ value = []int64{v1, v2}
+ addrs = parseHexAddresses(sampleData[5])
+
+ return value, blocksize, addrs, nil
+}
+
+// extractHexAddresses extracts hex numbers from a string and returns
+// them, together with their numeric value, in a slice.
+func extractHexAddresses(s string) ([]string, []uint64) {
+ hexStrings := hexNumberRE.FindAllString(s, -1)
+ var ids []uint64
+ for _, s := range hexStrings {
+ if id, err := strconv.ParseUint(s, 0, 64); err == nil {
+ ids = append(ids, id)
+ } else {
+ // Do not expect any parsing failures due to the regexp matching.
+ panic("failed to parse hex value:" + s)
+ }
+ }
+ return hexStrings, ids
+}
+
+// parseHexAddresses parses hex numbers from a string and returns them
+// in a slice.
+func parseHexAddresses(s string) []uint64 {
+ _, ids := extractHexAddresses(s)
+ return ids
+}
+
+// scaleHeapSample adjusts the data from a heapz Sample to
+// account for its probability of appearing in the collected
+// data. heapz profiles are a sampling of the memory allocations
+// requests in a program. We estimate the unsampled value by dividing
+// each collected sample by its probability of appearing in the
+// profile. heapz v2 profiles rely on a poisson process to determine
+// which samples to collect, based on the desired average collection
+// rate R. The probability of a sample of size S to appear in that
+// profile is 1-exp(-S/R).
+func scaleHeapSample(count, size, rate int64) (int64, int64) {
+ if count == 0 || size == 0 {
+ return 0, 0
+ }
+
+ if rate <= 1 {
+ // if rate==1 all samples were collected so no adjustment is needed.
+ // if rate<1 treat as unknown and skip scaling.
+ return count, size
+ }
+
+ avgSize := float64(size) / float64(count)
+ scale := 1 / (1 - math.Exp(-avgSize/float64(rate)))
+
+ return int64(float64(count) * scale), int64(float64(size) * scale)
+}
+
+// parseContention parses a 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.
+// This code converts the text output from runtime into a *Profile. (In the future
+// the runtime might write a serialized Profile directly making this unnecessary.)
+func parseContention(b []byte) (*Profile, error) {
+ r := bytes.NewBuffer(b)
+ var l string
+ var err error
+ for {
+ // Skip past comments and empty lines seeking a real header.
+ l, err = r.ReadString('\n')
+ if err != nil {
+ return nil, err
+ }
+ if !isSpaceOrComment(l) {
+ break
+ }
+ }
+
+ if strings.HasPrefix(l, "--- contentionz ") {
+ return parseCppContention(r)
+ } else if strings.HasPrefix(l, "--- mutex:") {
+ return parseCppContention(r)
+ } else if strings.HasPrefix(l, "--- contention:") {
+ return parseCppContention(r)
+ }
+ return nil, errUnrecognized
+}
+
+// parseCppContention parses the output from synchronization_profiling.cc
+// for backward compatibility, and the compatible (non-debug) block profile
+// output from the Go runtime.
+func parseCppContention(r *bytes.Buffer) (*Profile, error) {
+ p := &Profile{
+ PeriodType: &ValueType{Type: "contentions", Unit: "count"},
+ Period: 1,
+ SampleType: []*ValueType{
+ {Type: "contentions", Unit: "count"},
+ {Type: "delay", Unit: "nanoseconds"},
+ },
+ }
+
+ var cpuHz int64
+ var l string
+ var err error
+ // Parse text of the form "attribute = value" before the samples.
+ const delimiter = "="
+ for {
+ l, err = r.ReadString('\n')
+ if err != nil {
+ if err != io.EOF {
+ return nil, err
+ }
+
+ if l == "" {
+ break
+ }
+ }
+ if isSpaceOrComment(l) {
+ continue
+ }
+
+ if l = strings.TrimSpace(l); l == "" {
+ continue
+ }
+
+ if strings.HasPrefix(l, "---") {
+ break
+ }
+
+ attr := strings.SplitN(l, delimiter, 2)
+ if len(attr) != 2 {
+ break
+ }
+ key, val := strings.TrimSpace(attr[0]), strings.TrimSpace(attr[1])
+ var err error
+ switch key {
+ case "cycles/second":
+ if cpuHz, err = strconv.ParseInt(val, 0, 64); err != nil {
+ return nil, errUnrecognized
+ }
+ case "sampling period":
+ if p.Period, err = strconv.ParseInt(val, 0, 64); err != nil {
+ return nil, errUnrecognized
+ }
+ case "ms since reset":
+ ms, err := strconv.ParseInt(val, 0, 64)
+ if err != nil {
+ return nil, errUnrecognized
+ }
+ p.DurationNanos = ms * 1000 * 1000
+ case "format":
+ // CPP contentionz profiles don't have format.
+ return nil, errUnrecognized
+ case "resolution":
+ // CPP contentionz profiles don't have resolution.
+ return nil, errUnrecognized
+ case "discarded samples":
+ default:
+ return nil, errUnrecognized
+ }
+ }
+
+ locs := make(map[uint64]*Location)
+ for {
+ if !isSpaceOrComment(l) {
+ if l = strings.TrimSpace(l); strings.HasPrefix(l, "---") {
+ break
+ }
+ value, addrs, err := parseContentionSample(l, p.Period, cpuHz)
+ if err != nil {
+ return nil, err
+ }
+ var sloc []*Location
+ for _, addr := range addrs {
+ // Addresses from stack traces point to the next instruction after
+ // each call. Adjust by -1 to land somewhere on the actual call.
+ addr--
+ loc := locs[addr]
+ if locs[addr] == nil {
+ loc = &Location{
+ Address: addr,
+ }
+ p.Location = append(p.Location, loc)
+ locs[addr] = loc
+ }
+ sloc = append(sloc, loc)
+ }
+ p.Sample = append(p.Sample, &Sample{
+ Value: value,
+ Location: sloc,
+ })
+ }
+
+ if l, err = r.ReadString('\n'); err != nil {
+ if err != io.EOF {
+ return nil, err
+ }
+ if l == "" {
+ break
+ }
+ }
+ }
+
+ if err = parseAdditionalSections(l, r, p); err != nil {
+ return nil, err
+ }
+
+ return p, nil
+}
+
+// parseContentionSample parses a single row from a contention profile
+// into a new Sample.
+func parseContentionSample(line string, period, cpuHz int64) (value []int64, addrs []uint64, err error) {
+ sampleData := contentionSampleRE.FindStringSubmatch(line)
+ if sampleData == nil {
+ return value, addrs, errUnrecognized
+ }
+
+ v1, err := strconv.ParseInt(sampleData[1], 10, 64)
+ if err != nil {
+ return value, addrs, fmt.Errorf("malformed sample: %s: %v", line, err)
+ }
+ v2, err := strconv.ParseInt(sampleData[2], 10, 64)
+ if err != nil {
+ return value, addrs, fmt.Errorf("malformed sample: %s: %v", line, err)
+ }
+
+ // Unsample values if period and cpuHz are available.
+ // - Delays are scaled to cycles and then to nanoseconds.
+ // - Contentions are scaled to cycles.
+ if period > 0 {
+ if cpuHz > 0 {
+ cpuGHz := float64(cpuHz) / 1e9
+ v1 = int64(float64(v1) * float64(period) / cpuGHz)
+ }
+ v2 = v2 * period
+ }
+
+ value = []int64{v2, v1}
+ addrs = parseHexAddresses(sampleData[3])
+
+ return value, addrs, nil
+}
+
+// parseThread parses a Threadz profile and returns a new Profile.
+func parseThread(b []byte) (*Profile, error) {
+ r := bytes.NewBuffer(b)
+
+ var line string
+ var err error
+ for {
+ // Skip past comments and empty lines seeking a real header.
+ line, err = r.ReadString('\n')
+ if err != nil {
+ return nil, err
+ }
+ if !isSpaceOrComment(line) {
+ break
+ }
+ }
+
+ if m := threadzStartRE.FindStringSubmatch(line); m != nil {
+ // Advance over initial comments until first stack trace.
+ for {
+ line, err = r.ReadString('\n')
+ if err != nil {
+ if err != io.EOF {
+ return nil, err
+ }
+
+ if line == "" {
+ break
+ }
+ }
+ if sectionTrigger(line) != unrecognizedSection || line[0] == '-' {
+ break
+ }
+ }
+ } else if t := threadStartRE.FindStringSubmatch(line); len(t) != 4 {
+ return nil, errUnrecognized
+ }
+
+ p := &Profile{
+ SampleType: []*ValueType{{Type: "thread", Unit: "count"}},
+ PeriodType: &ValueType{Type: "thread", Unit: "count"},
+ Period: 1,
+ }
+
+ locs := make(map[uint64]*Location)
+ // Recognize each thread and populate profile samples.
+ for sectionTrigger(line) == unrecognizedSection {
+ if strings.HasPrefix(line, "---- no stack trace for") {
+ line = ""
+ break
+ }
+ if t := threadStartRE.FindStringSubmatch(line); len(t) != 4 {
+ return nil, errUnrecognized
+ }
+
+ var addrs []uint64
+ line, addrs, err = parseThreadSample(r)
+ if err != nil {
+ return nil, errUnrecognized
+ }
+ if len(addrs) == 0 {
+ // We got a --same as previous threads--. Bump counters.
+ if len(p.Sample) > 0 {
+ s := p.Sample[len(p.Sample)-1]
+ s.Value[0]++
+ }
+ continue
+ }
+
+ var sloc []*Location
+ for _, addr := range addrs {
+ // Addresses from stack traces point to the next instruction after
+ // each call. Adjust by -1 to land somewhere on the actual call.
+ addr--
+ loc := locs[addr]
+ if locs[addr] == nil {
+ loc = &Location{
+ Address: addr,
+ }
+ p.Location = append(p.Location, loc)
+ locs[addr] = loc
+ }
+ sloc = append(sloc, loc)
+ }
+
+ p.Sample = append(p.Sample, &Sample{
+ Value: []int64{1},
+ Location: sloc,
+ })
+ }
+
+ if err = parseAdditionalSections(line, r, p); err != nil {
+ return nil, err
+ }
+
+ return p, nil
+}
+
+// parseThreadSample parses a symbolized or unsymbolized stack trace.
+// Returns the first line after the traceback, the sample (or nil if
+// it hits a 'same-as-previous' marker) and an error.
+func parseThreadSample(b *bytes.Buffer) (nextl string, addrs []uint64, err error) {
+ var l string
+ sameAsPrevious := false
+ for {
+ if l, err = b.ReadString('\n'); err != nil {
+ if err != io.EOF {
+ return "", nil, err
+ }
+ if l == "" {
+ break
+ }
+ }
+ if l = strings.TrimSpace(l); l == "" {
+ continue
+ }
+
+ if strings.HasPrefix(l, "---") {
+ break
+ }
+ if strings.Contains(l, "same as previous thread") {
+ sameAsPrevious = true
+ continue
+ }
+
+ addrs = append(addrs, parseHexAddresses(l)...)
+ }
+
+ if sameAsPrevious {
+ return l, nil, nil
+ }
+ return l, addrs, nil
+}
+
+// parseAdditionalSections parses any additional sections in the
+// profile, ignoring any unrecognized sections.
+func parseAdditionalSections(l string, b *bytes.Buffer, p *Profile) (err error) {
+ for {
+ if sectionTrigger(l) == memoryMapSection {
+ break
+ }
+ // Ignore any unrecognized sections.
+ if l, err := b.ReadString('\n'); err != nil {
+ if err != io.EOF {
+ return err
+ }
+ if l == "" {
+ break
+ }
+ }
+ }
+ return p.ParseMemoryMap(b)
+}
+
+// ParseMemoryMap parses a memory map in the format of
+// /proc/self/maps, and overrides the mappings in the current profile.
+// It renumbers the samples and locations in the profile correspondingly.
+func (p *Profile) ParseMemoryMap(rd io.Reader) error {
+ b := bufio.NewReader(rd)
+
+ var attrs []string
+ var r *strings.Replacer
+ const delimiter = "="
+ for {
+ l, err := b.ReadString('\n')
+ if err != nil {
+ if err != io.EOF {
+ return err
+ }
+ if l == "" {
+ break
+ }
+ }
+ if l = strings.TrimSpace(l); l == "" {
+ continue
+ }
+
+ if r != nil {
+ l = r.Replace(l)
+ }
+ m, err := parseMappingEntry(l)
+ if err != nil {
+ if err == errUnrecognized {
+ // Recognize assignments of the form: attr=value, and replace
+ // $attr with value on subsequent mappings.
+ if attr := strings.SplitN(l, delimiter, 2); len(attr) == 2 {
+ attrs = append(attrs, "$"+strings.TrimSpace(attr[0]), strings.TrimSpace(attr[1]))
+ r = strings.NewReplacer(attrs...)
+ }
+ // Ignore any unrecognized entries
+ continue
+ }
+ return err
+ }
+ if m == nil || (m.File == "" && len(p.Mapping) != 0) {
+ // In some cases the first entry may include the address range
+ // but not the name of the file. It should be followed by
+ // another entry with the name.
+ continue
+ }
+ if len(p.Mapping) == 1 && p.Mapping[0].File == "" {
+ // Update the name if this is the entry following that empty one.
+ p.Mapping[0].File = m.File
+ continue
+ }
+ p.Mapping = append(p.Mapping, m)
+ }
+ p.remapLocationIDs()
+ p.remapFunctionIDs()
+ p.remapMappingIDs()
+ return nil
+}
+
+func parseMappingEntry(l string) (*Mapping, error) {
+ mapping := &Mapping{}
+ var err error
+ if me := procMapsRE.FindStringSubmatch(l); len(me) == 9 {
+ if !strings.Contains(me[3], "x") {
+ // Skip non-executable entries.
+ return nil, nil
+ }
+ if mapping.Start, err = strconv.ParseUint(me[1], 16, 64); err != nil {
+ return nil, errUnrecognized
+ }
+ if mapping.Limit, err = strconv.ParseUint(me[2], 16, 64); err != nil {
+ return nil, errUnrecognized
+ }
+ if me[4] != "" {
+ if mapping.Offset, err = strconv.ParseUint(me[4], 16, 64); err != nil {
+ return nil, errUnrecognized
+ }
+ }
+ mapping.File = me[8]
+ return mapping, nil
+ }
+
+ if me := briefMapsRE.FindStringSubmatch(l); len(me) == 6 {
+ if mapping.Start, err = strconv.ParseUint(me[1], 16, 64); err != nil {
+ return nil, errUnrecognized
+ }
+ if mapping.Limit, err = strconv.ParseUint(me[2], 16, 64); err != nil {
+ return nil, errUnrecognized
+ }
+ mapping.File = me[3]
+ if me[5] != "" {
+ if mapping.Offset, err = strconv.ParseUint(me[5], 16, 64); err != nil {
+ return nil, errUnrecognized
+ }
+ }
+ return mapping, nil
+ }
+
+ return nil, errUnrecognized
+}
+
+type sectionType int
+
+const (
+ unrecognizedSection sectionType = iota
+ memoryMapSection
+)
+
+var memoryMapTriggers = []string{
+ "--- Memory map: ---",
+ "MAPPED_LIBRARIES:",
+}
+
+func sectionTrigger(line string) sectionType {
+ for _, trigger := range memoryMapTriggers {
+ if strings.Contains(line, trigger) {
+ return memoryMapSection
+ }
+ }
+ return unrecognizedSection
+}
+
+func (p *Profile) addLegacyFrameInfo() {
+ switch {
+ case isProfileType(p, heapzSampleTypes) ||
+ isProfileType(p, heapzInUseSampleTypes) ||
+ isProfileType(p, heapzAllocSampleTypes):
+ p.DropFrames, p.KeepFrames = allocRxStr, allocSkipRxStr
+ case isProfileType(p, contentionzSampleTypes):
+ p.DropFrames, p.KeepFrames = lockRxStr, ""
+ default:
+ p.DropFrames, p.KeepFrames = cpuProfilerRxStr, ""
+ }
+}
+
+var heapzSampleTypes = []string{"allocations", "size"} // early Go pprof profiles
+var heapzInUseSampleTypes = []string{"inuse_objects", "inuse_space"}
+var heapzAllocSampleTypes = []string{"alloc_objects", "alloc_space"}
+var contentionzSampleTypes = []string{"contentions", "delay"}
+
+func isProfileType(p *Profile, t []string) bool {
+ st := p.SampleType
+ if len(st) != len(t) {
+ return false
+ }
+
+ for i := range st {
+ if st[i].Type != t[i] {
+ return false
+ }
+ }
+ return true
+}
+
+var allocRxStr = strings.Join([]string{
+ // POSIX entry points.
+ `calloc`,
+ `cfree`,
+ `malloc`,
+ `free`,
+ `memalign`,
+ `do_memalign`,
+ `(__)?posix_memalign`,
+ `pvalloc`,
+ `valloc`,
+ `realloc`,
+
+ // TC malloc.
+ `tcmalloc::.*`,
+ `tc_calloc`,
+ `tc_cfree`,
+ `tc_malloc`,
+ `tc_free`,
+ `tc_memalign`,
+ `tc_posix_memalign`,
+ `tc_pvalloc`,
+ `tc_valloc`,
+ `tc_realloc`,
+ `tc_new`,
+ `tc_delete`,
+ `tc_newarray`,
+ `tc_deletearray`,
+ `tc_new_nothrow`,
+ `tc_newarray_nothrow`,
+
+ // Memory-allocation routines on OS X.
+ `malloc_zone_malloc`,
+ `malloc_zone_calloc`,
+ `malloc_zone_valloc`,
+ `malloc_zone_realloc`,
+ `malloc_zone_memalign`,
+ `malloc_zone_free`,
+
+ // Go runtime
+ `runtime\..*`,
+
+ // Other misc. memory allocation routines
+ `BaseArena::.*`,
+ `(::)?do_malloc_no_errno`,
+ `(::)?do_malloc_pages`,
+ `(::)?do_malloc`,
+ `DoSampledAllocation`,
+ `MallocedMemBlock::MallocedMemBlock`,
+ `_M_allocate`,
+ `__builtin_(vec_)?delete`,
+ `__builtin_(vec_)?new`,
+ `__gnu_cxx::new_allocator::allocate`,
+ `__libc_malloc`,
+ `__malloc_alloc_template::allocate`,
+ `allocate`,
+ `cpp_alloc`,
+ `operator new(\[\])?`,
+ `simple_alloc::allocate`,
+}, `|`)
+
+var allocSkipRxStr = strings.Join([]string{
+ // Preserve Go runtime frames that appear in the middle/bottom of
+ // the stack.
+ `runtime\.panic`,
+ `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.*`,
+ `(Mutex::)?AwaitCommon.*`,
+ `(Mutex::)?Unlock.*`,
+ `(Mutex::)?UnlockSlow.*`,
+ `(Mutex::)?ReaderUnlock.*`,
+ `(MutexLock::)?~MutexLock.*`,
+ `(SpinLock::)?Unlock.*`,
+ `(SpinLock::)?SlowUnlock.*`,
+ `(SpinLockHolder::)?~SpinLockHolder.*`,
+}, `|`)
diff --git a/src/cmd/internal/pprof/profile/profile.go b/src/internal/pprof/profile/profile.go
similarity index 100%
rename from src/cmd/internal/pprof/profile/profile.go
rename to src/internal/pprof/profile/profile.go
diff --git a/src/internal/pprof/profile/profile_test.go b/src/internal/pprof/profile/profile_test.go
new file mode 100644
index 0000000..e1963f3
--- /dev/null
+++ b/src/internal/pprof/profile/profile_test.go
@@ -0,0 +1,79 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package profile
+
+import (
+ "bytes"
+ "testing"
+)
+
+func TestEmptyProfile(t *testing.T) {
+ var buf bytes.Buffer
+ p, err := Parse(&buf)
+ if err != nil {
+ t.Error("Want no error, got", err)
+ }
+ if p == nil {
+ t.Fatal("Want a valid profile, got <nil>")
+ }
+ if !p.Empty() {
+ t.Errorf("Profile should be empty, got %#v", p)
+ }
+}
+
+func TestParseContention(t *testing.T) {
+ tests := []struct {
+ name string
+ in string
+ wantErr bool
+ }{
+ {
+ name: "valid",
+ in: `--- mutex:
+cycles/second=3491920901
+sampling period=1
+43227965305 1659640 @ 0x45e851 0x45f764 0x4a2be1 0x44ea31
+34035731690 15760 @ 0x45e851 0x45f764 0x4a2b17 0x44ea31
+`,
+ },
+ {
+ name: "valid with comment",
+ in: `--- mutex:
+cycles/second=3491920901
+sampling period=1
+43227965305 1659640 @ 0x45e851 0x45f764 0x4a2be1 0x44ea31
+# 0x45e850 sync.(*Mutex).Unlock+0x80 /go/src/sync/mutex.go:126
+# 0x45f763 sync.(*RWMutex).Unlock+0x83 /go/src/sync/rwmutex.go:125
+# 0x4a2be0 main.main.func3+0x70 /go/src/internal/pprof/profile/a_binary.go:58
+
+34035731690 15760 @ 0x45e851 0x45f764 0x4a2b17 0x44ea31
+# 0x45e850 sync.(*Mutex).Unlock+0x80 /go/src/sync/mutex.go:126
+# 0x45f763 sync.(*RWMutex).Unlock+0x83 /go/src/sync/rwmutex.go:125
+# 0x4a2b16 main.main.func2+0xd6 /go/src/internal/pprof/profile/a_binary.go:48
+`,
+ },
+ {
+ name: "empty",
+ in: `--- mutex:`,
+ wantErr: true,
+ },
+ {
+ name: "invalid header",
+ in: `--- channel:
+43227965305 1659640 @ 0x45e851 0x45f764 0x4a2be1 0x44ea31`,
+ wantErr: true,
+ },
+ }
+ for _, tc := range tests {
+ _, err := parseContention([]byte(tc.in))
+ if tc.wantErr && err == nil {
+ t.Errorf("parseContention(%q) succeeded unexpectedly", tc.name)
+ }
+ if !tc.wantErr && err != nil {
+ t.Errorf("parseContention(%q) failed unexpectedly: %v", tc.name, err)
+ }
+ }
+
+}
diff --git a/src/cmd/internal/pprof/profile/proto.go b/src/internal/pprof/profile/proto.go
similarity index 100%
rename from src/cmd/internal/pprof/profile/proto.go
rename to src/internal/pprof/profile/proto.go
diff --git a/src/cmd/internal/pprof/profile/proto_test.go b/src/internal/pprof/profile/proto_test.go
similarity index 100%
rename from src/cmd/internal/pprof/profile/proto_test.go
rename to src/internal/pprof/profile/proto_test.go
diff --git a/src/cmd/internal/pprof/profile/prune.go b/src/internal/pprof/profile/prune.go
similarity index 100%
rename from src/cmd/internal/pprof/profile/prune.go
rename to src/internal/pprof/profile/prune.go
diff --git a/src/internal/race/norace.go b/src/internal/race/norace.go
index 7ef5912..d83c016 100644
--- a/src/internal/race/norace.go
+++ b/src/internal/race/norace.go
@@ -38,3 +38,5 @@ func ReadRange(addr unsafe.Pointer, len int) {
func WriteRange(addr unsafe.Pointer, len int) {
}
+
+func Errors() int { return 0 }
diff --git a/src/internal/race/race.go b/src/internal/race/race.go
index 6c721f6..2e7d97b 100644
--- a/src/internal/race/race.go
+++ b/src/internal/race/race.go
@@ -48,3 +48,7 @@ func ReadRange(addr unsafe.Pointer, len int) {
func WriteRange(addr unsafe.Pointer, len int) {
runtime.RaceWriteRange(addr, len)
}
+
+func Errors() int {
+ return runtime.RaceErrors()
+}
diff --git a/src/internal/syscall/unix/getrandom_linux_mipsx.go b/src/internal/syscall/unix/getrandom_linux_mipsx.go
new file mode 100644
index 0000000..af7b722
--- /dev/null
+++ b/src/internal/syscall/unix/getrandom_linux_mipsx.go
@@ -0,0 +1,11 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build mips mipsle
+
+package unix
+
+// Linux getrandom system call number.
+// See GetRandom in getrandom_linux.go.
+const randomTrap uintptr = 4353
diff --git a/src/internal/syscall/windows/mksyscall.go b/src/internal/syscall/windows/mksyscall.go
new file mode 100644
index 0000000..91fa2b3
--- /dev/null
+++ b/src/internal/syscall/windows/mksyscall.go
@@ -0,0 +1,7 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package windows
+
+//go:generate go run $GOROOT/src/syscall/mksyscall_windows.go -output zsyscall_windows.go syscall_windows.go security_windows.go
diff --git a/src/internal/syscall/windows/registry/mksyscall.go b/src/internal/syscall/windows/registry/mksyscall.go
new file mode 100644
index 0000000..0772153
--- /dev/null
+++ b/src/internal/syscall/windows/registry/mksyscall.go
@@ -0,0 +1,7 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package registry
+
+//go:generate go run $GOROOT/src/syscall/mksyscall_windows.go -output zsyscall_windows.go syscall.go
diff --git a/src/internal/syscall/windows/registry/syscall.go b/src/internal/syscall/windows/registry/syscall.go
index 5426cae..a6525da 100644
--- a/src/internal/syscall/windows/registry/syscall.go
+++ b/src/internal/syscall/windows/registry/syscall.go
@@ -8,8 +8,6 @@ package registry
import "syscall"
-//go:generate go run $GOROOT/src/syscall/mksyscall_windows.go -output zsyscall_windows.go syscall.go
-
const (
_REG_OPTION_NON_VOLATILE = 0
diff --git a/src/internal/syscall/windows/registry/zsyscall_windows.go b/src/internal/syscall/windows/registry/zsyscall_windows.go
index 62affc0..a3a1f5f 100644
--- a/src/internal/syscall/windows/registry/zsyscall_windows.go
+++ b/src/internal/syscall/windows/registry/zsyscall_windows.go
@@ -10,6 +10,31 @@ import (
var _ unsafe.Pointer
+// Do the interface allocations only once for common
+// Errno values.
+const (
+ errnoERROR_IO_PENDING = 997
+)
+
+var (
+ errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING)
+)
+
+// errnoErr returns common boxed Errno values, to prevent
+// allocations at runtime.
+func errnoErr(e syscall.Errno) error {
+ switch e {
+ case 0:
+ return nil
+ case errnoERROR_IO_PENDING:
+ return errERROR_IO_PENDING
+ }
+ // TODO: add more here, after collecting data on the common
+ // error values see on Windows. (perhaps when running
+ // all.bat?)
+ return e
+}
+
var (
modadvapi32 = syscall.NewLazyDLL(sysdll.Add("advapi32.dll"))
modkernel32 = syscall.NewLazyDLL(sysdll.Add("kernel32.dll"))
@@ -76,7 +101,7 @@ func expandEnvironmentStrings(src *uint16, dst *uint16, size uint32) (n uint32,
n = uint32(r0)
if n == 0 {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = syscall.EINVAL
}
diff --git a/src/internal/syscall/windows/reparse_windows.go b/src/internal/syscall/windows/reparse_windows.go
new file mode 100644
index 0000000..7c6ad8f
--- /dev/null
+++ b/src/internal/syscall/windows/reparse_windows.go
@@ -0,0 +1,64 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package windows
+
+const (
+ FSCTL_SET_REPARSE_POINT = 0x000900A4
+ IO_REPARSE_TAG_MOUNT_POINT = 0xA0000003
+
+ SYMLINK_FLAG_RELATIVE = 1
+)
+
+// These structures are described
+// in https://msdn.microsoft.com/en-us/library/cc232007.aspx
+// and https://msdn.microsoft.com/en-us/library/cc232006.aspx.
+
+// REPARSE_DATA_BUFFER_HEADER is a common part of REPARSE_DATA_BUFFER structure.
+type REPARSE_DATA_BUFFER_HEADER struct {
+ ReparseTag uint32
+ // The size, in bytes, of the reparse data that follows
+ // the common portion of the REPARSE_DATA_BUFFER element.
+ // This value is the length of the data starting at the
+ // SubstituteNameOffset field.
+ ReparseDataLength uint16
+ Reserved uint16
+}
+
+type SymbolicLinkReparseBuffer struct {
+ // The integer that contains the offset, in bytes,
+ // of the substitute name string in the PathBuffer array,
+ // computed as an offset from byte 0 of PathBuffer. Note that
+ // this offset must be divided by 2 to get the array index.
+ SubstituteNameOffset uint16
+ // The integer that contains the length, in bytes, of the
+ // substitute name string. If this string is null-terminated,
+ // SubstituteNameLength does not include the Unicode null character.
+ SubstituteNameLength uint16
+ // PrintNameOffset is similar to SubstituteNameOffset.
+ PrintNameOffset uint16
+ // PrintNameLength is similar to SubstituteNameLength.
+ PrintNameLength uint16
+ // Flags specifies whether the substitute name is a full path name or
+ // a path name relative to the directory containing the symbolic link.
+ Flags uint32
+ PathBuffer [1]uint16
+}
+
+type MountPointReparseBuffer struct {
+ // The integer that contains the offset, in bytes,
+ // of the substitute name string in the PathBuffer array,
+ // computed as an offset from byte 0 of PathBuffer. Note that
+ // this offset must be divided by 2 to get the array index.
+ SubstituteNameOffset uint16
+ // The integer that contains the length, in bytes, of the
+ // substitute name string. If this string is null-terminated,
+ // SubstituteNameLength does not include the Unicode null character.
+ SubstituteNameLength uint16
+ // PrintNameOffset is similar to SubstituteNameOffset.
+ PrintNameOffset uint16
+ // PrintNameLength is similar to SubstituteNameLength.
+ PrintNameLength uint16
+ PathBuffer [1]uint16
+}
diff --git a/src/internal/syscall/windows/security_windows.go b/src/internal/syscall/windows/security_windows.go
new file mode 100644
index 0000000..2c145e1
--- /dev/null
+++ b/src/internal/syscall/windows/security_windows.go
@@ -0,0 +1,57 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package windows
+
+import (
+ "syscall"
+)
+
+const (
+ SecurityAnonymous = 0
+ SecurityIdentification = 1
+ SecurityImpersonation = 2
+ SecurityDelegation = 3
+)
+
+//sys ImpersonateSelf(impersonationlevel uint32) (err error) = advapi32.ImpersonateSelf
+//sys RevertToSelf() (err error) = advapi32.RevertToSelf
+
+const (
+ TOKEN_ADJUST_PRIVILEGES = 0x0020
+ SE_PRIVILEGE_ENABLED = 0x00000002
+)
+
+type LUID struct {
+ LowPart uint32
+ HighPart int32
+}
+
+type LUID_AND_ATTRIBUTES struct {
+ Luid LUID
+ Attributes uint32
+}
+
+type TOKEN_PRIVILEGES struct {
+ PrivilegeCount uint32
+ Privileges [1]LUID_AND_ATTRIBUTES
+}
+
+//sys OpenThreadToken(h syscall.Handle, access uint32, openasself bool, token *syscall.Token) (err error) = advapi32.OpenThreadToken
+//sys LookupPrivilegeValue(systemname *uint16, name *uint16, luid *LUID) (err error) = advapi32.LookupPrivilegeValueW
+//sys adjustTokenPrivileges(token syscall.Token, disableAllPrivileges bool, newstate *TOKEN_PRIVILEGES, buflen uint32, prevstate *TOKEN_PRIVILEGES, returnlen *uint32) (ret uint32, err error) [true] = advapi32.AdjustTokenPrivileges
+
+func AdjustTokenPrivileges(token syscall.Token, disableAllPrivileges bool, newstate *TOKEN_PRIVILEGES, buflen uint32, prevstate *TOKEN_PRIVILEGES, returnlen *uint32) error {
+ ret, err := adjustTokenPrivileges(token, disableAllPrivileges, newstate, buflen, prevstate, returnlen)
+ if ret == 0 {
+ // AdjustTokenPrivileges call failed
+ return err
+ }
+ // AdjustTokenPrivileges call succeeded
+ if err == syscall.EINVAL {
+ // GetLastError returned ERROR_SUCCESS
+ return nil
+ }
+ return err
+}
diff --git a/src/internal/syscall/windows/syscall_windows.go b/src/internal/syscall/windows/syscall_windows.go
index 7b2bc79..ec08a5a 100644
--- a/src/internal/syscall/windows/syscall_windows.go
+++ b/src/internal/syscall/windows/syscall_windows.go
@@ -6,7 +6,10 @@ package windows
import "syscall"
-//go:generate go run ../../../syscall/mksyscall_windows.go -output zsyscall_windows.go syscall_windows.go
+const (
+ ERROR_SHARING_VIOLATION syscall.Errno = 32
+ ERROR_NO_UNICODE_TRANSLATION syscall.Errno = 1113
+)
const GAA_FLAG_INCLUDE_PREFIX = 0x00000010
@@ -107,6 +110,7 @@ const (
//sys GetAdaptersAddresses(family uint32, flags uint32, reserved uintptr, adapterAddresses *IpAdapterAddresses, sizePointer *uint32) (errcode error) = iphlpapi.GetAdaptersAddresses
//sys GetComputerNameEx(nameformat uint32, buf *uint16, n *uint32) (err error) = GetComputerNameExW
//sys MoveFileEx(from *uint16, to *uint16, flags uint32) (err error) = MoveFileExW
+//sys GetModuleFileName(module syscall.Handle, fn *uint16, len uint32) (n uint32, err error) = kernel32.GetModuleFileNameW
const (
ComputerNameNetBIOS = 0
@@ -139,5 +143,25 @@ func Rename(oldpath, newpath string) error {
return MoveFileEx(from, to, MOVEFILE_REPLACE_EXISTING)
}
+const MB_ERR_INVALID_CHARS = 8
+
//sys GetACP() (acp uint32) = kernel32.GetACP
+//sys GetConsoleCP() (ccp uint32) = kernel32.GetConsoleCP
//sys MultiByteToWideChar(codePage uint32, dwFlags uint32, str *byte, nstr int32, wchar *uint16, nwchar int32) (nwrite int32, err error) = kernel32.MultiByteToWideChar
+//sys GetCurrentThread() (pseudoHandle syscall.Handle, err error) = kernel32.GetCurrentThread
+
+const STYPE_DISKTREE = 0x00
+
+type SHARE_INFO_2 struct {
+ Netname *uint16
+ Type uint32
+ Remark *uint16
+ Permissions uint32
+ MaxUses uint32
+ CurrentUses uint32
+ Path *uint16
+ Passwd *uint16
+}
+
+//sys NetShareAdd(serverName *uint16, level uint32, buf *byte, parmErr *uint16) (neterr error) = netapi32.NetShareAdd
+//sys NetShareDel(serverName *uint16, netName *uint16, reserved uint32) (neterr error) = netapi32.NetShareDel
diff --git a/src/internal/syscall/windows/zsyscall_windows.go b/src/internal/syscall/windows/zsyscall_windows.go
index 6929acf..7a2ffee 100644
--- a/src/internal/syscall/windows/zsyscall_windows.go
+++ b/src/internal/syscall/windows/zsyscall_windows.go
@@ -10,15 +10,52 @@ import (
var _ unsafe.Pointer
+// Do the interface allocations only once for common
+// Errno values.
+const (
+ errnoERROR_IO_PENDING = 997
+)
+
+var (
+ errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING)
+)
+
+// errnoErr returns common boxed Errno values, to prevent
+// allocations at runtime.
+func errnoErr(e syscall.Errno) error {
+ switch e {
+ case 0:
+ return nil
+ case errnoERROR_IO_PENDING:
+ return errERROR_IO_PENDING
+ }
+ // TODO: add more here, after collecting data on the common
+ // error values see on Windows. (perhaps when running
+ // all.bat?)
+ return e
+}
+
var (
modiphlpapi = syscall.NewLazyDLL(sysdll.Add("iphlpapi.dll"))
modkernel32 = syscall.NewLazyDLL(sysdll.Add("kernel32.dll"))
+ modnetapi32 = syscall.NewLazyDLL(sysdll.Add("netapi32.dll"))
+ modadvapi32 = syscall.NewLazyDLL(sysdll.Add("advapi32.dll"))
- procGetAdaptersAddresses = modiphlpapi.NewProc("GetAdaptersAddresses")
- procGetComputerNameExW = modkernel32.NewProc("GetComputerNameExW")
- procMoveFileExW = modkernel32.NewProc("MoveFileExW")
- procGetACP = modkernel32.NewProc("GetACP")
- procMultiByteToWideChar = modkernel32.NewProc("MultiByteToWideChar")
+ procGetAdaptersAddresses = modiphlpapi.NewProc("GetAdaptersAddresses")
+ procGetComputerNameExW = modkernel32.NewProc("GetComputerNameExW")
+ procMoveFileExW = modkernel32.NewProc("MoveFileExW")
+ procGetModuleFileNameW = modkernel32.NewProc("GetModuleFileNameW")
+ procGetACP = modkernel32.NewProc("GetACP")
+ procGetConsoleCP = modkernel32.NewProc("GetConsoleCP")
+ procMultiByteToWideChar = modkernel32.NewProc("MultiByteToWideChar")
+ procGetCurrentThread = modkernel32.NewProc("GetCurrentThread")
+ procNetShareAdd = modnetapi32.NewProc("NetShareAdd")
+ procNetShareDel = modnetapi32.NewProc("NetShareDel")
+ procImpersonateSelf = modadvapi32.NewProc("ImpersonateSelf")
+ procRevertToSelf = modadvapi32.NewProc("RevertToSelf")
+ procOpenThreadToken = modadvapi32.NewProc("OpenThreadToken")
+ procLookupPrivilegeValueW = modadvapi32.NewProc("LookupPrivilegeValueW")
+ procAdjustTokenPrivileges = modadvapi32.NewProc("AdjustTokenPrivileges")
)
func GetAdaptersAddresses(family uint32, flags uint32, reserved uintptr, adapterAddresses *IpAdapterAddresses, sizePointer *uint32) (errcode error) {
@@ -33,7 +70,7 @@ func GetComputerNameEx(nameformat uint32, buf *uint16, n *uint32) (err error) {
r1, _, e1 := syscall.Syscall(procGetComputerNameExW.Addr(), 3, uintptr(nameformat), uintptr(unsafe.Pointer(buf)), uintptr(unsafe.Pointer(n)))
if r1 == 0 {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = syscall.EINVAL
}
@@ -45,7 +82,20 @@ func MoveFileEx(from *uint16, to *uint16, flags uint32) (err error) {
r1, _, e1 := syscall.Syscall(procMoveFileExW.Addr(), 3, uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(to)), uintptr(flags))
if r1 == 0 {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func GetModuleFileName(module syscall.Handle, fn *uint16, len uint32) (n uint32, err error) {
+ r0, _, e1 := syscall.Syscall(procGetModuleFileNameW.Addr(), 3, uintptr(module), uintptr(unsafe.Pointer(fn)), uintptr(len))
+ n = uint32(r0)
+ if n == 0 {
+ if e1 != 0 {
+ err = errnoErr(e1)
} else {
err = syscall.EINVAL
}
@@ -59,12 +109,120 @@ func GetACP() (acp uint32) {
return
}
+func GetConsoleCP() (ccp uint32) {
+ r0, _, _ := syscall.Syscall(procGetConsoleCP.Addr(), 0, 0, 0, 0)
+ ccp = uint32(r0)
+ return
+}
+
func MultiByteToWideChar(codePage uint32, dwFlags uint32, str *byte, nstr int32, wchar *uint16, nwchar int32) (nwrite int32, err error) {
r0, _, e1 := syscall.Syscall6(procMultiByteToWideChar.Addr(), 6, uintptr(codePage), uintptr(dwFlags), uintptr(unsafe.Pointer(str)), uintptr(nstr), uintptr(unsafe.Pointer(wchar)), uintptr(nwchar))
nwrite = int32(r0)
if nwrite == 0 {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func GetCurrentThread() (pseudoHandle syscall.Handle, err error) {
+ r0, _, e1 := syscall.Syscall(procGetCurrentThread.Addr(), 0, 0, 0, 0)
+ pseudoHandle = syscall.Handle(r0)
+ if pseudoHandle == 0 {
+ if e1 != 0 {
+ err = errnoErr(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func NetShareAdd(serverName *uint16, level uint32, buf *byte, parmErr *uint16) (neterr error) {
+ r0, _, _ := syscall.Syscall6(procNetShareAdd.Addr(), 4, uintptr(unsafe.Pointer(serverName)), uintptr(level), uintptr(unsafe.Pointer(buf)), uintptr(unsafe.Pointer(parmErr)), 0, 0)
+ if r0 != 0 {
+ neterr = syscall.Errno(r0)
+ }
+ return
+}
+
+func NetShareDel(serverName *uint16, netName *uint16, reserved uint32) (neterr error) {
+ r0, _, _ := syscall.Syscall(procNetShareDel.Addr(), 3, uintptr(unsafe.Pointer(serverName)), uintptr(unsafe.Pointer(netName)), uintptr(reserved))
+ if r0 != 0 {
+ neterr = syscall.Errno(r0)
+ }
+ return
+}
+
+func ImpersonateSelf(impersonationlevel uint32) (err error) {
+ r1, _, e1 := syscall.Syscall(procImpersonateSelf.Addr(), 1, uintptr(impersonationlevel), 0, 0)
+ if r1 == 0 {
+ if e1 != 0 {
+ err = errnoErr(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func RevertToSelf() (err error) {
+ r1, _, e1 := syscall.Syscall(procRevertToSelf.Addr(), 0, 0, 0, 0)
+ if r1 == 0 {
+ if e1 != 0 {
+ err = errnoErr(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func OpenThreadToken(h syscall.Handle, access uint32, openasself bool, token *syscall.Token) (err error) {
+ var _p0 uint32
+ if openasself {
+ _p0 = 1
+ } else {
+ _p0 = 0
+ }
+ r1, _, e1 := syscall.Syscall6(procOpenThreadToken.Addr(), 4, uintptr(h), uintptr(access), uintptr(_p0), uintptr(unsafe.Pointer(token)), 0, 0)
+ if r1 == 0 {
+ if e1 != 0 {
+ err = errnoErr(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func LookupPrivilegeValue(systemname *uint16, name *uint16, luid *LUID) (err error) {
+ r1, _, e1 := syscall.Syscall(procLookupPrivilegeValueW.Addr(), 3, uintptr(unsafe.Pointer(systemname)), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(luid)))
+ if r1 == 0 {
+ if e1 != 0 {
+ err = errnoErr(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func adjustTokenPrivileges(token syscall.Token, disableAllPrivileges bool, newstate *TOKEN_PRIVILEGES, buflen uint32, prevstate *TOKEN_PRIVILEGES, returnlen *uint32) (ret uint32, err error) {
+ var _p0 uint32
+ if disableAllPrivileges {
+ _p0 = 1
+ } else {
+ _p0 = 0
+ }
+ r0, _, e1 := syscall.Syscall6(procAdjustTokenPrivileges.Addr(), 6, uintptr(token), uintptr(_p0), uintptr(unsafe.Pointer(newstate)), uintptr(buflen), uintptr(unsafe.Pointer(prevstate)), uintptr(unsafe.Pointer(returnlen)))
+ ret = uint32(r0)
+ if true {
+ if e1 != 0 {
+ err = errnoErr(e1)
} else {
err = syscall.EINVAL
}
diff --git a/src/internal/testenv/testenv.go b/src/internal/testenv/testenv.go
index f134f6b..10384b6 100644
--- a/src/internal/testenv/testenv.go
+++ b/src/internal/testenv/testenv.go
@@ -11,6 +11,7 @@
package testenv
import (
+ "errors"
"flag"
"os"
"os/exec"
@@ -67,26 +68,36 @@ func MustHaveGoRun(t *testing.T) {
}
// GoToolPath reports the path to the Go tool.
+// It is a convenience wrapper around GoTool.
// If the tool is unavailable GoToolPath calls t.Skip.
// If the tool should be available and isn't, GoToolPath calls t.Fatal.
func GoToolPath(t *testing.T) string {
MustHaveGoBuild(t)
+ path, err := GoTool()
+ if err != nil {
+ t.Fatal(err)
+ }
+ return path
+}
+// GoTool reports the path to the Go tool.
+func GoTool() (string, error) {
+ if !HasGoBuild() {
+ return "", errors.New("platform cannot run go tool")
+ }
var exeSuffix string
if runtime.GOOS == "windows" {
exeSuffix = ".exe"
}
-
path := filepath.Join(runtime.GOROOT(), "bin", "go"+exeSuffix)
if _, err := os.Stat(path); err == nil {
- return path
+ return path, nil
}
-
goBin, err := exec.LookPath("go" + exeSuffix)
if err != nil {
- t.Fatalf("cannot find go tool: %v", err)
+ return "", errors.New("cannot find go tool: " + err.Error())
}
- return goBin
+ return goBin, nil
}
// HasExec reports whether the current system can start new processes
@@ -127,6 +138,37 @@ func MustHaveExternalNetwork(t *testing.T) {
}
}
+// HasSymlink reports whether the current system can use os.Symlink.
+func HasSymlink() bool {
+ ok, _ := hasSymlink()
+ return ok
+}
+
+// MustHaveSymlink reports whether the current system can use os.Symlink.
+// If not, MustHaveSymlink calls t.Skip with an explanation.
+func MustHaveSymlink(t *testing.T) {
+ ok, reason := hasSymlink()
+ if !ok {
+ t.Skipf("skipping test: cannot make symlinks on %s/%s%s", runtime.GOOS, runtime.GOARCH, reason)
+ }
+}
+
+// HasLink reports whether the current system can use os.Link.
+func HasLink() bool {
+ // From Android release M (Marshmallow), hard linking files is blocked
+ // and an attempt to call link() on a file will return EACCES.
+ // - https://code.google.com/p/android-developer-preview/issues/detail?id=3150
+ return runtime.GOOS != "plan9" && runtime.GOOS != "android"
+}
+
+// MustHaveLink reports whether the current system can use os.Link.
+// If not, MustHaveLink calls t.Skip with an explanation.
+func MustHaveLink(t *testing.T) {
+ if !HasLink() {
+ t.Skipf("skipping test: hardlinks are not supported on %s/%s", runtime.GOOS, runtime.GOARCH)
+ }
+}
+
var flaky = flag.Bool("flaky", false, "run known-flaky tests too")
func SkipFlaky(t *testing.T, issue int) {
diff --git a/src/internal/testenv/testenv_notwin.go b/src/internal/testenv/testenv_notwin.go
new file mode 100644
index 0000000..d8ce6cd
--- /dev/null
+++ b/src/internal/testenv/testenv_notwin.go
@@ -0,0 +1,20 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !windows
+
+package testenv
+
+import (
+ "runtime"
+)
+
+func hasSymlink() (ok bool, reason string) {
+ switch runtime.GOOS {
+ case "android", "nacl", "plan9":
+ return false, ""
+ }
+
+ return true, ""
+}
diff --git a/src/internal/testenv/testenv_windows.go b/src/internal/testenv/testenv_windows.go
new file mode 100644
index 0000000..e593f64
--- /dev/null
+++ b/src/internal/testenv/testenv_windows.go
@@ -0,0 +1,49 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package testenv
+
+import (
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "sync"
+ "syscall"
+)
+
+var symlinkOnce sync.Once
+var winSymlinkErr error
+
+func initWinHasSymlink() {
+ tmpdir, err := ioutil.TempDir("", "symtest")
+ if err != nil {
+ panic("failed to create temp directory: " + err.Error())
+ }
+ defer os.RemoveAll(tmpdir)
+
+ err = os.Symlink("target", filepath.Join(tmpdir, "symlink"))
+ if err != nil {
+ err = err.(*os.LinkError).Err
+ switch err {
+ case syscall.EWINDOWS, syscall.ERROR_PRIVILEGE_NOT_HELD:
+ winSymlinkErr = err
+ }
+ }
+ os.Remove("target")
+}
+
+func hasSymlink() (ok bool, reason string) {
+ symlinkOnce.Do(initWinHasSymlink)
+
+ switch winSymlinkErr {
+ case nil:
+ return true, ""
+ case syscall.EWINDOWS:
+ return false, ": symlinks are not supported on your version of Windows"
+ case syscall.ERROR_PRIVILEGE_NOT_HELD:
+ return false, ": you don't have enough privileges to create symlinks"
+ }
+
+ return false, ""
+}
diff --git a/src/internal/trace/goroutines.go b/src/internal/trace/goroutines.go
index f8673e2..923a157 100644
--- a/src/internal/trace/goroutines.go
+++ b/src/internal/trace/goroutines.go
@@ -48,7 +48,7 @@ func GoroutineStats(events []*Event) map[uint64]*GDesc {
g := &GDesc{ID: ev.Args[0], CreationTime: ev.Ts, gdesc: new(gdesc)}
g.blockSchedTime = ev.Ts
gs[g.ID] = g
- case EvGoStart:
+ case EvGoStart, EvGoStartLabel:
g := gs[ev.G]
if g.PC == 0 {
g.PC = ev.Stk[0].PC
@@ -83,6 +83,10 @@ func GoroutineStats(events []*Event) map[uint64]*GDesc {
g := gs[ev.G]
g.ExecTime += ev.Ts - g.lastStartTime
g.blockNetTime = ev.Ts
+ case EvGoBlockGC:
+ g := gs[ev.G]
+ g.ExecTime += ev.Ts - g.lastStartTime
+ g.blockGCTime = ev.Ts
case EvGoUnblock:
g := gs[ev.Args[0]]
if g.blockNetTime != 0 {
diff --git a/src/internal/trace/mkcanned.bash b/src/internal/trace/mkcanned.bash
new file mode 100755
index 0000000..78c5572
--- /dev/null
+++ b/src/internal/trace/mkcanned.bash
@@ -0,0 +1,19 @@
+#!/usr/bin/env bash
+# Copyright 2016 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+# mkcanned.bash creates canned traces for the trace test suite using
+# the current Go version.
+
+set -e
+
+if [ $# != 1 ]; then
+ echo "usage: $0 <label>" >&2
+ exit 1
+fi
+
+go test -run ClientServerParallel4 -trace "testdata/http_$1_good" net/http
+go test -run 'TraceStress$|TraceStressStartStop$' runtime/trace -savetraces
+mv ../../runtime/trace/TestTraceStress.trace "testdata/stress_$1_good"
+mv ../../runtime/trace/TestTraceStressStartStop.trace "testdata/stress_start_stop_$1_good"
diff --git a/src/internal/trace/order.go b/src/internal/trace/order.go
index 8ca2da5..36ed58d 100644
--- a/src/internal/trace/order.go
+++ b/src/internal/trace/order.go
@@ -150,7 +150,7 @@ func stateTransition(ev *Event) (g uint64, init, next gState) {
g = ev.G
init = gState{1, gRunnable}
next = gState{2, gWaiting}
- case EvGoStart:
+ case EvGoStart, EvGoStartLabel:
g = ev.G
init = gState{ev.Args[1], gRunnable}
next = gState{ev.Args[1] + 1, gRunning}
@@ -165,7 +165,8 @@ func stateTransition(ev *Event) (g uint64, init, next gState) {
init = gState{noseq, gRunnable}
next = gState{seqinc, gRunning}
case EvGoBlock, EvGoBlockSend, EvGoBlockRecv, EvGoBlockSelect,
- EvGoBlockSync, EvGoBlockCond, EvGoBlockNet, EvGoSleep, EvGoSysBlock:
+ EvGoBlockSync, EvGoBlockCond, EvGoBlockNet, EvGoSleep,
+ EvGoSysBlock, EvGoBlockGC:
g = ev.G
init = gState{noseq, gRunning}
next = gState{noseq, gWaiting}
diff --git a/src/internal/trace/parser.go b/src/internal/trace/parser.go
index c31517f..efa8540 100644
--- a/src/internal/trace/parser.go
+++ b/src/internal/trace/parser.go
@@ -28,12 +28,13 @@ type Event struct {
StkID uint64 // unique stack ID
Stk []*Frame // stack trace (can be empty)
Args [3]uint64 // event-type-specific arguments
+ SArgs []string // event-type-specific string args
// linked event (can be nil), depends on event type:
// for GCStart: the GCStop
// for GCScanStart: the GCScanDone
// for GCSweepStart: the GCSweepDone
// for GoCreate: first GoStart of the created goroutine
- // for GoStart: the associated GoEnd, GoBlock or other blocking event
+ // for GoStart/GoStartLabel: the associated GoEnd, GoBlock or other blocking event
// for GoSched/GoPreempt: the next GoStart
// for GoBlock and other blocking events: the unblock event
// for GoUnblock: the associated GoStart
@@ -56,6 +57,7 @@ const (
TimerP // depicts timer unblocks
NetpollP // depicts network unblocks
SyscallP // depicts returns from syscalls
+ GCP // depicts GC state
)
// Parse parses, post-processes and verifies the trace.
@@ -125,7 +127,9 @@ func readTrace(r io.Reader) (ver int, events []rawEvent, strings map[uint64]stri
return
}
switch ver {
- case 1005, 1007:
+ case 1005, 1007, 1008:
+ // Note: When adding a new version, add canned traces
+ // from the old version to the test suite using mkcanned.bash.
break
default:
err = fmt.Errorf("unsupported trace file version %v.%v (update Go toolchain) %v", ver/1000, ver%1000, ver)
@@ -362,15 +366,18 @@ func parseEvents(ver int, rawEvents []rawEvent, strings map[uint64]string) (even
}
}
switch raw.typ {
- case EvGoStart, EvGoStartLocal:
+ case EvGoStart, EvGoStartLocal, EvGoStartLabel:
lastG = e.Args[0]
e.G = lastG
+ if raw.typ == EvGoStartLabel {
+ e.SArgs = []string{strings[e.Args[2]]}
+ }
case EvGCStart, EvGCDone, EvGCScanStart, EvGCScanDone:
e.G = 0
case EvGoEnd, EvGoStop, EvGoSched, EvGoPreempt,
EvGoSleep, EvGoBlock, EvGoBlockSend, EvGoBlockRecv,
EvGoBlockSelect, EvGoBlockSync, EvGoBlockCond, EvGoBlockNet,
- EvGoSysBlock:
+ EvGoSysBlock, EvGoBlockGC:
lastG = 0
case EvGoSysExit, EvGoWaiting, EvGoInSyscall:
e.G = e.Args[0]
@@ -548,6 +555,8 @@ func postProcessTrace(ver int, events []*Event) error {
return fmt.Errorf("previous GC is not ended before a new one (offset %v, time %v)", ev.Off, ev.Ts)
}
evGC = ev
+ // Attribute this to the global GC state.
+ ev.P = GCP
case EvGCDone:
if evGC == nil {
return fmt.Errorf("bogus GC end (offset %v, time %v)", ev.Off, ev.Ts)
@@ -581,11 +590,13 @@ func postProcessTrace(ver int, events []*Event) error {
return fmt.Errorf("g %v is not runnable before EvGoWaiting (offset %v, time %v)", ev.G, ev.Off, ev.Ts)
}
g.state = gWaiting
+ g.ev = ev
case EvGoInSyscall:
if g.state != gRunnable {
return fmt.Errorf("g %v is not runnable before EvGoInSyscall (offset %v, time %v)", ev.G, ev.Off, ev.Ts)
}
g.state = gWaiting
+ g.ev = ev
case EvGoCreate:
if err := checkRunning(p, g, ev, true); err != nil {
return err
@@ -594,7 +605,7 @@ func postProcessTrace(ver int, events []*Event) error {
return fmt.Errorf("g %v already exists (offset %v, time %v)", ev.Args[0], ev.Off, ev.Ts)
}
gs[ev.Args[0]] = gdesc{state: gRunnable, ev: ev, evCreate: ev}
- case EvGoStart:
+ case EvGoStart, EvGoStartLabel:
if g.state != gRunnable {
return fmt.Errorf("g %v is not runnable before start (offset %v, time %v)", ev.G, ev.Off, ev.Ts)
}
@@ -678,7 +689,7 @@ func postProcessTrace(ver int, events []*Event) error {
g.state = gRunnable
g.ev = ev
case EvGoSleep, EvGoBlock, EvGoBlockSend, EvGoBlockRecv,
- EvGoBlockSelect, EvGoBlockSync, EvGoBlockCond, EvGoBlockNet:
+ EvGoBlockSelect, EvGoBlockSync, EvGoBlockCond, EvGoBlockNet, EvGoBlockGC:
if err := checkRunning(p, g, ev, false); err != nil {
return err
}
@@ -853,8 +864,8 @@ const (
EvProcStop = 6 // stop of P [timestamp]
EvGCStart = 7 // GC start [timestamp, seq, stack id]
EvGCDone = 8 // GC done [timestamp]
- EvGCScanStart = 9 // GC scan start [timestamp]
- EvGCScanDone = 10 // GC scan done [timestamp]
+ 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]
@@ -885,7 +896,9 @@ const (
EvGoStartLocal = 38 // goroutine starts running on the same P as the last event [timestamp, goroutine id]
EvGoUnblockLocal = 39 // goroutine is unblocked on the same P as the last event [timestamp, goroutine id, stack]
EvGoSysExitLocal = 40 // syscall exit on the same P as the last event [timestamp, goroutine id, real timestamp]
- EvCount = 41
+ 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
)
var EventDescriptions = [EvCount]struct {
@@ -935,4 +948,6 @@ var EventDescriptions = [EvCount]struct {
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{}},
}
diff --git a/src/internal/trace/parser_test.go b/src/internal/trace/parser_test.go
index daad3e3..d6f580a 100644
--- a/src/internal/trace/parser_test.go
+++ b/src/internal/trace/parser_test.go
@@ -90,52 +90,13 @@ func TestParseVersion(t *testing.T) {
func TestTimestampOverflow(t *testing.T) {
// Test that parser correctly handles large timestamps (long tracing).
- w := newWriter()
- w.emit(EvBatch, 0, 0)
- w.emit(EvFrequency, 1e9)
+ w := NewWriter()
+ w.Emit(EvBatch, 0, 0)
+ w.Emit(EvFrequency, 1e9)
for ts := uint64(1); ts < 1e16; ts *= 2 {
- w.emit(EvGoCreate, ts, ts, 0, 0)
+ w.Emit(EvGoCreate, ts, ts, 0, 0)
}
if _, err := Parse(w, ""); err != nil {
t.Fatalf("failed to parse: %v", err)
}
}
-
-type writer struct {
- bytes.Buffer
-}
-
-func newWriter() *writer {
- w := new(writer)
- w.Write([]byte("go 1.7 trace\x00\x00\x00\x00"))
- return w
-}
-
-func (w *writer) emit(typ byte, args ...uint64) {
- nargs := byte(len(args)) - 1
- if nargs > 3 {
- nargs = 3
- }
- buf := []byte{typ | nargs<<6}
- if nargs == 3 {
- buf = append(buf, 0)
- }
- for _, a := range args {
- buf = appendVarint(buf, a)
- }
- if nargs == 3 {
- buf[1] = byte(len(buf) - 2)
- }
- n, err := w.Write(buf)
- if n != len(buf) || err != nil {
- panic("failed to write")
- }
-}
-
-func appendVarint(buf []byte, v uint64) []byte {
- for ; v >= 0x80; v >>= 7 {
- buf = append(buf, 0x80|byte(v))
- }
- buf = append(buf, byte(v))
- return buf
-}
diff --git a/src/internal/trace/testdata/http_1_7_good b/src/internal/trace/testdata/http_1_7_good
new file mode 100644
index 0000000..b0e318e
Binary files /dev/null and b/src/internal/trace/testdata/http_1_7_good differ
diff --git a/src/internal/trace/testdata/stress_1_7_good b/src/internal/trace/testdata/stress_1_7_good
new file mode 100644
index 0000000..b4d927d
Binary files /dev/null and b/src/internal/trace/testdata/stress_1_7_good differ
diff --git a/src/internal/trace/testdata/stress_start_stop_1_7_good b/src/internal/trace/testdata/stress_start_stop_1_7_good
new file mode 100644
index 0000000..c23ed7d
Binary files /dev/null and b/src/internal/trace/testdata/stress_start_stop_1_7_good differ
diff --git a/src/internal/trace/writer.go b/src/internal/trace/writer.go
new file mode 100644
index 0000000..a481f50
--- /dev/null
+++ b/src/internal/trace/writer.go
@@ -0,0 +1,45 @@
+package trace
+
+import "bytes"
+
+// Writer is a test trace writer.
+type Writer struct {
+ bytes.Buffer
+}
+
+func NewWriter() *Writer {
+ w := new(Writer)
+ w.Write([]byte("go 1.7 trace\x00\x00\x00\x00"))
+ return w
+}
+
+// Emit writes an event record to the trace.
+// See Event types for valid types and required arguments.
+func (w *Writer) Emit(typ byte, args ...uint64) {
+ nargs := byte(len(args)) - 1
+ if nargs > 3 {
+ nargs = 3
+ }
+ buf := []byte{typ | nargs<<6}
+ if nargs == 3 {
+ buf = append(buf, 0)
+ }
+ for _, a := range args {
+ buf = appendVarint(buf, a)
+ }
+ if nargs == 3 {
+ buf[1] = byte(len(buf) - 2)
+ }
+ n, err := w.Write(buf)
+ if n != len(buf) || err != nil {
+ panic("failed to write")
+ }
+}
+
+func appendVarint(buf []byte, v uint64) []byte {
+ for ; v >= 0x80; v >>= 7 {
+ buf = append(buf, 0x80|byte(v))
+ }
+ buf = append(buf, byte(v))
+ return buf
+}
diff --git a/src/io/io.go b/src/io/io.go
index 19d0ae5..3cab728 100644
--- a/src/io/io.go
+++ b/src/io/io.go
@@ -402,11 +402,10 @@ func copyBuffer(dst Writer, src Reader, buf []byte) (written int64, err error) {
break
}
}
- if er == EOF {
- break
- }
if er != nil {
- err = er
+ if er != EOF {
+ err = er
+ }
break
}
}
diff --git a/src/io/ioutil/ioutil.go b/src/io/ioutil/ioutil.go
index 8ecbb2d..f0da616 100644
--- a/src/io/ioutil/ioutil.go
+++ b/src/io/ioutil/ioutil.go
@@ -88,13 +88,6 @@ func WriteFile(filename string, data []byte, perm os.FileMode) error {
return err
}
-// byName implements sort.Interface.
-type byName []os.FileInfo
-
-func (f byName) Len() int { return len(f) }
-func (f byName) Less(i, j int) bool { return f[i].Name() < f[j].Name() }
-func (f byName) Swap(i, j int) { f[i], f[j] = f[j], f[i] }
-
// ReadDir reads the directory named by dirname and returns
// a list of directory entries sorted by filename.
func ReadDir(dirname string) ([]os.FileInfo, error) {
@@ -107,7 +100,7 @@ func ReadDir(dirname string) ([]os.FileInfo, error) {
if err != nil {
return nil, err
}
- sort.Sort(byName(list))
+ sort.Slice(list, func(i, j int) bool { return list[i].Name() < list[j].Name() })
return list, nil
}
diff --git a/src/io/ioutil/tempfile.go b/src/io/ioutil/tempfile.go
index 42718cc..e5e315c 100644
--- a/src/io/ioutil/tempfile.go
+++ b/src/io/ioutil/tempfile.go
@@ -90,6 +90,11 @@ func TempDir(dir, prefix string) (name string, err error) {
}
continue
}
+ if os.IsNotExist(err) {
+ if _, err := os.Stat(dir); os.IsNotExist(err) {
+ return "", err
+ }
+ }
if err == nil {
name = try
}
diff --git a/src/io/ioutil/tempfile_test.go b/src/io/ioutil/tempfile_test.go
index d2a132a..6a70aed 100644
--- a/src/io/ioutil/tempfile_test.go
+++ b/src/io/ioutil/tempfile_test.go
@@ -51,3 +51,19 @@ func TestTempDir(t *testing.T) {
}
}
}
+
+// test that we return a nice error message if the dir argument to TempDir doesn't
+// exist (or that it's empty and os.TempDir doesn't exist)
+func TestTempDir_BadDir(t *testing.T) {
+ dir, err := TempDir("", "TestTempDir_BadDir")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer os.RemoveAll(dir)
+
+ badDir := filepath.Join(dir, "not-exist")
+ _, err = TempDir(badDir, "foo")
+ if pe, ok := err.(*os.PathError); !ok || !os.IsNotExist(err) || pe.Path != badDir {
+ t.Errorf("TempDir error = %#v; want PathError for path %q satisifying os.IsNotExist", err, badDir)
+ }
+}
diff --git a/src/io/multi.go b/src/io/multi.go
index 3a9d036..46e45a6 100644
--- a/src/io/multi.go
+++ b/src/io/multi.go
@@ -19,6 +19,7 @@ func (mr *multiReader) Read(p []byte) (n int, err error) {
}
n, err = mr.readers[0].Read(p)
if err == EOF {
+ mr.readers[0] = nil // permit earlier GC
mr.readers = mr.readers[1:]
}
if n > 0 || err != EOF {
diff --git a/src/io/multi_test.go b/src/io/multi_test.go
index 5c6bb84..16e351a 100644
--- a/src/io/multi_test.go
+++ b/src/io/multi_test.go
@@ -14,6 +14,7 @@ import (
"runtime"
"strings"
"testing"
+ "time"
)
func TestMultiReader(t *testing.T) {
@@ -211,7 +212,7 @@ func (b byteAndEOFReader) Read(p []byte) (n int, err error) {
return 1, EOF
}
-// In Go 1.7, this yielded bytes forever.
+// This used to yield bytes forever; issue 16795.
func TestMultiReaderSingleByteWithEOF(t *testing.T) {
got, err := ioutil.ReadAll(LimitReader(MultiReader(byteAndEOFReader('a'), byteAndEOFReader('b')), 10))
if err != nil {
@@ -234,3 +235,32 @@ func TestMultiReaderFinalEOF(t *testing.T) {
t.Errorf("got %v, %v; want 1, EOF", n, err)
}
}
+
+func TestMultiReaderFreesExhaustedReaders(t *testing.T) {
+ var mr Reader
+ closed := make(chan struct{})
+ {
+ 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" {
+ t.Fatalf(`ReadFull = %d (%q), %v; want 3, "foo", nil`, n, buf[:n], err)
+ }
+
+ runtime.GC()
+ select {
+ case <-closed:
+ case <-time.After(5 * time.Second):
+ t.Fatal("timeout waiting for collection of buf1")
+ }
+
+ if n, err := ReadFull(mr, buf[:2]); err != nil || string(buf[:2]) != "ar" {
+ t.Fatalf(`ReadFull = %d (%q), %v; want 2, "ar", nil`, n, buf[:n], err)
+ }
+}
diff --git a/src/io/pipe.go b/src/io/pipe.go
index 7e98cd2..6145872 100644
--- a/src/io/pipe.go
+++ b/src/io/pipe.go
@@ -148,7 +148,7 @@ type PipeWriter struct {
}
// Write implements the standard Write interface:
-// it writes data to the pipe, blocking until readers
+// it writes data to the pipe, blocking until one or more readers
// have consumed all the data or the read end is closed.
// If the read end is closed with an error, that err is
// returned as err; otherwise err is ErrClosedPipe.
@@ -175,11 +175,17 @@ func (w *PipeWriter) CloseWithError(err error) error {
// Pipe creates a synchronous in-memory pipe.
// It can be used to connect code expecting an io.Reader
// with code expecting an io.Writer.
-// Reads on one end are matched with writes on the other,
-// copying data directly between the two; there is no internal buffering.
-// It is safe to call Read and Write in parallel with each other or with
-// Close. Close will complete once pending I/O is done. Parallel calls to
-// Read, and parallel calls to Write, are also safe:
+//
+// Reads and Writes on the pipe are matched one to one
+// except when multiple Reads are needed to consume a single Write.
+// That is, each Write to the PipeWriter blocks until it has satisfied
+// one or more Reads from the PipeReader that fully consume
+// the written data.
+// The data is copied directly from the Write to the corresponding
+// Read (or Reads); there is no internal buffering.
+//
+// It is safe to call Read and Write in parallel with each other or with Close.
+// Parallel calls to Read and parallel calls to Write are also safe:
// the individual calls will be gated sequentially.
func Pipe() (*PipeReader, *PipeWriter) {
p := new(pipe)
diff --git a/src/log/log.go b/src/log/log.go
index 26cdb53..58b8788 100644
--- a/src/log/log.go
+++ b/src/log/log.go
@@ -8,6 +8,8 @@
// Panic[f|ln], which are easier to use than creating a Logger manually.
// That logger writes to standard error and prints the date and time
// of each logged message.
+// Every log message is output on a separate line: if the message being
+// printed does not end in a newline, the logger will add one.
// The Fatal functions call os.Exit(1) after writing the log message.
// The Panic functions call panic after writing the log message.
package log
diff --git a/src/log/syslog/doc.go b/src/log/syslog/doc.go
index dfcc2dd..5458523 100644
--- a/src/log/syslog/doc.go
+++ b/src/log/syslog/doc.go
@@ -10,7 +10,7 @@
// the syslog client will attempt to reconnect to the server
// and write again.
//
-// The syslog package is frozen and not accepting new features.
+// The syslog package is frozen and is not accepting new features.
// Some external packages provide more functionality. See:
//
// https://godoc.org/?q=syslog
diff --git a/src/log/syslog/example_test.go b/src/log/syslog/example_test.go
new file mode 100644
index 0000000..3d5b76d
--- /dev/null
+++ b/src/log/syslog/example_test.go
@@ -0,0 +1,23 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !windows,!nacl,!plan9
+
+package syslog_test
+
+import (
+ "fmt"
+ "log"
+ "log/syslog"
+)
+
+func ExampleDial() {
+ sysLog, err := syslog.Dial("tcp", "localhost:1234",
+ syslog.LOG_WARNING|syslog.LOG_DAEMON, "demotag")
+ if err != nil {
+ log.Fatal(err)
+ }
+ fmt.Fprintf(sysLog, "This is a daemon warning with demotag.")
+ sysLog.Emerg("And this is a daemon emergency with demotag.")
+}
diff --git a/src/log/syslog/syslog.go b/src/log/syslog/syslog.go
index 9e888dd..df9ffb8 100644
--- a/src/log/syslog/syslog.go
+++ b/src/log/syslog/syslog.go
@@ -112,6 +112,8 @@ func New(priority Priority, tag string) (*Writer, error) {
// writer sends a log message with the given facility, severity and
// tag.
// 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.
func Dial(network, raddr string, priority Priority, tag string) (*Writer, error) {
if priority < 0 || priority > LOG_LOCAL7|LOG_DEBUG {
return nil, errors.New("log/syslog: invalid priority")
diff --git a/src/log/syslog/syslog_test.go b/src/log/syslog/syslog_test.go
index 52363f9..1263be6 100644
--- a/src/log/syslog/syslog_test.go
+++ b/src/log/syslog/syslog_test.go
@@ -134,6 +134,7 @@ func startServer(n, la string, done chan<- string) (addr string, sock io.Closer,
}
func TestWithSimulated(t *testing.T) {
+ t.Parallel()
msg := "Test 123"
var transport []string
for _, n := range []string{"unix", "unixgram", "udp", "tcp"} {
@@ -262,6 +263,7 @@ func check(t *testing.T, in, out string) {
}
func TestWrite(t *testing.T) {
+ t.Parallel()
tests := []struct {
pri Priority
pre string
@@ -367,7 +369,8 @@ func TestConcurrentReconnect(t *testing.T) {
defer wg.Done()
w, err := Dial(net, addr, LOG_USER|LOG_ERR, "tag")
if err != nil {
- t.Fatalf("syslog.Dial() failed: %v", err)
+ t.Errorf("syslog.Dial() failed: %v", err)
+ return
}
defer w.Close()
for i := 0; i < M; i++ {
diff --git a/src/make.bash b/src/make.bash
index 1a1412a..84aaab5 100755
--- a/src/make.bash
+++ b/src/make.bash
@@ -47,6 +47,8 @@
# FC: Command line to run to compile Fortran code for GOARCH.
# This is used by cgo. Default is "gfortran".
#
+# PKG_CONFIG: Path to pkg-config tool. Default is "pkg-config".
+#
# GO_DISTFLAGS: extra flags to provide to "dist bootstrap".
set -e
diff --git a/src/make.rc b/src/make.rc
index 243f83c..ba3554c 100755
--- a/src/make.rc
+++ b/src/make.rc
@@ -80,7 +80,7 @@ if(~ $sysname vx32)
if(! ~ $GOHOSTARCH $GOARCH || ! ~ $GOHOSTOS $GOOS){
echo '##### Building packages and commands for host,' $GOHOSTOS/$GOHOSTARCH^.
- GOOS=$GOHOSTOS GOARCH=$GOHOSTARCH GOBIN= \
+ GOOS=$GOHOSTOS GOARCH=$GOHOSTARCH GOBIN=() \
$GOTOOLDIR/go_bootstrap install -gcflags $"GO_GCFLAGS -ldflags $"GO_LDFLAGS -v $pflag std cmd
echo
}
diff --git a/src/math/all_test.go b/src/math/all_test.go
index d9ea1fd..3d8cd72 100644
--- a/src/math/all_test.go
+++ b/src/math/all_test.go
@@ -1165,21 +1165,88 @@ var frexpSC = []fi{
{NaN(), 0},
}
-var vfgammaSC = []float64{
- Inf(-1),
- -3,
- Copysign(0, -1),
- 0,
- Inf(1),
- NaN(),
-}
-var gammaSC = []float64{
- NaN(),
- NaN(),
- Inf(-1),
- Inf(1),
- Inf(1),
- NaN(),
+var vfgamma = [][2]float64{
+ {Inf(1), Inf(1)},
+ {Inf(-1), NaN()},
+ {0, Inf(1)},
+ {Copysign(0, -1), Inf(-1)},
+ {NaN(), NaN()},
+ {-1, NaN()},
+ {-2, NaN()},
+ {-3, NaN()},
+ {-1e16, NaN()},
+ {-1e300, NaN()},
+ {1.7e308, Inf(1)},
+
+ // Test inputs inspired by Python test suite.
+ // Outputs computed at high precision by PARI/GP.
+ // If recomputing table entries, be careful to use
+ // high-precision (%.1000g) formatting of the float64 inputs.
+ // For example, -2.0000000000000004 is the float64 with exact value
+ // -2.00000000000000044408920985626161695, and
+ // gamma(-2.0000000000000004) = -1249999999999999.5386078562728167651513, while
+ // gamma(-2.00000000000000044408920985626161695) = -1125899906826907.2044875028130093136826.
+ // Thus the table lists -1.1258999068426235e+15 as the answer.
+ {0.5, 1.772453850905516},
+ {1.5, 0.886226925452758},
+ {2.5, 1.329340388179137},
+ {3.5, 3.3233509704478426},
+ {-0.5, -3.544907701811032},
+ {-1.5, 2.363271801207355},
+ {-2.5, -0.9453087204829419},
+ {-3.5, 0.2700882058522691},
+ {0.1, 9.51350769866873},
+ {0.01, 99.4325851191506},
+ {1e-08, 9.999999942278434e+07},
+ {1e-16, 1e+16},
+ {0.001, 999.4237724845955},
+ {1e-16, 1e+16},
+ {1e-308, 1e+308},
+ {5.6e-309, 1.7857142857142864e+308},
+ {5.5e-309, Inf(1)},
+ {1e-309, Inf(1)},
+ {1e-323, Inf(1)},
+ {5e-324, Inf(1)},
+ {-0.1, -10.686287021193193},
+ {-0.01, -100.58719796441078},
+ {-1e-08, -1.0000000057721567e+08},
+ {-1e-16, -1e+16},
+ {-0.001, -1000.5782056293586},
+ {-1e-16, -1e+16},
+ {-1e-308, -1e+308},
+ {-5.6e-309, -1.7857142857142864e+308},
+ {-5.5e-309, Inf(-1)},
+ {-1e-309, Inf(-1)},
+ {-1e-323, Inf(-1)},
+ {-5e-324, Inf(-1)},
+ {-0.9999999999999999, -9.007199254740992e+15},
+ {-1.0000000000000002, 4.5035996273704955e+15},
+ {-1.9999999999999998, 2.2517998136852485e+15},
+ {-2.0000000000000004, -1.1258999068426235e+15},
+ {-100.00000000000001, -7.540083334883109e-145},
+ {-99.99999999999999, 7.540083334884096e-145},
+ {17, 2.0922789888e+13},
+ {171, 7.257415615307999e+306},
+ {171.6, 1.5858969096672565e+308},
+ {171.624, 1.7942117599248104e+308},
+ {171.625, Inf(1)},
+ {172, Inf(1)},
+ {2000, Inf(1)},
+ {-100.5, -3.3536908198076787e-159},
+ {-160.5, -5.255546447007829e-286},
+ {-170.5, -3.3127395215386074e-308},
+ {-171.5, 1.9316265431712e-310},
+ {-176.5, -1.196e-321},
+ {-177.5, 5e-324},
+ {-178.5, Copysign(0, -1)},
+ {-179.5, 0},
+ {-201.0001, 0},
+ {-202.9999, Copysign(0, -1)},
+ {-1000.5, Copysign(0, -1)},
+ {-1.0000000003e+09, Copysign(0, -1)},
+ {-4.5035996273704955e+15, 0},
+ {-63.349078729022985, 4.177797167776188e-88},
+ {-127.45117632943295, 1.183111089623681e-214},
}
var vfhypotSC = [][2]float64{
@@ -1735,6 +1802,12 @@ var logbBC = []float64{
}
func tolerance(a, b, e float64) bool {
+ // Multiplying by e here can underflow denormal values to zero.
+ // Check a==b so that at least if a and b are small and identical
+ // we say they match.
+ if a == b {
+ return true
+ }
d := a - b
if d < 0 {
d = -d
@@ -1974,7 +2047,7 @@ func TestExp(t *testing.T) {
func testExp(t *testing.T, Exp func(float64) float64, name string) {
for i := 0; i < len(vf); i++ {
- if f := Exp(vf[i]); !close(exp[i], f) {
+ if f := Exp(vf[i]); !veryclose(exp[i], f) {
t.Errorf("%s(%g) = %g, want %g", name, vf[i], f, exp[i])
}
}
@@ -2147,9 +2220,18 @@ func TestGamma(t *testing.T) {
t.Errorf("Gamma(%g) = %g, want %g", vf[i], f, gamma[i])
}
}
- for i := 0; i < len(vfgammaSC); i++ {
- if f := Gamma(vfgammaSC[i]); !alike(gammaSC[i], f) {
- t.Errorf("Gamma(%g) = %g, want %g", vfgammaSC[i], f, gammaSC[i])
+ for _, g := range vfgamma {
+ f := Gamma(g[0])
+ var ok bool
+ if IsNaN(g[1]) || IsInf(g[1], 0) || g[1] == 0 || f == 0 {
+ ok = alike(g[1], f)
+ } else if g[0] > -50 && g[0] <= 171 {
+ ok = veryclose(g[1], f)
+ } else {
+ ok = close(g[1], f)
+ }
+ if !ok {
+ t.Errorf("Gamma(%g) = %g, want %g", g[0], f, g[1])
}
}
}
@@ -3000,27 +3082,36 @@ func BenchmarkSinh(b *testing.B) {
var Global float64
-func BenchmarkSqrt(b *testing.B) {
+func BenchmarkSqrtIndirect(b *testing.B) {
x, y := 0.0, 10.0
+ f := Sqrt
for i := 0; i < b.N; i++ {
- x += Sqrt(y)
+ x += f(y)
}
Global = x
}
-func BenchmarkSqrtIndirect(b *testing.B) {
- x, y := 0.0, 10.0
+func BenchmarkSqrtLatency(b *testing.B) {
+ x := 10.0
+ for i := 0; i < b.N; i++ {
+ x = Sqrt(x)
+ }
+ Global = x
+}
+
+func BenchmarkSqrtIndirectLatency(b *testing.B) {
+ x := 10.0
f := Sqrt
for i := 0; i < b.N; i++ {
- x += f(y)
+ x = f(x)
}
Global = x
}
-func BenchmarkSqrtGo(b *testing.B) {
- x, y := 0.0, 10.0
+func BenchmarkSqrtGoLatency(b *testing.B) {
+ x := 10.0
for i := 0; i < b.N; i++ {
- x += SqrtGo(y)
+ x = SqrtGo(x)
}
Global = x
}
diff --git a/src/math/arith_s390x.go b/src/math/arith_s390x.go
new file mode 100644
index 0000000..892935a
--- /dev/null
+++ b/src/math/arith_s390x.go
@@ -0,0 +1,29 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+func log10TrampolineSetup(x float64) float64
+func log10Asm(x float64) float64
+
+func cosTrampolineSetup(x float64) float64
+func cosAsm(x float64) float64
+
+func coshTrampolineSetup(x float64) float64
+func coshAsm(x float64) float64
+
+func sinTrampolineSetup(x float64) float64
+func sinAsm(x float64) float64
+
+func sinhTrampolineSetup(x float64) float64
+func sinhAsm(x float64) float64
+
+func tanhTrampolineSetup(x float64) float64
+func tanhAsm(x float64) float64
+
+// hasVectorFacility reports whether the machine has the z/Architecture
+// vector facility installed and enabled.
+func hasVectorFacility() bool
+
+var hasVX = hasVectorFacility()
diff --git a/src/math/arith_s390x_test.go b/src/math/arith_s390x_test.go
new file mode 100644
index 0000000..b4f3070
--- /dev/null
+++ b/src/math/arith_s390x_test.go
@@ -0,0 +1,144 @@
+// Copyright 2016 The Go 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 whether the non vector routines are working, even when the tests are run on a
+// vector-capable machine.
+package math_test
+
+import (
+ . "math"
+ "testing"
+)
+
+func TestCosNovec(t *testing.T) {
+ if !HasVX {
+ t.Skipf("no vector support")
+ }
+ for i := 0; i < len(vf); i++ {
+ if f := CosNoVec(vf[i]); !veryclose(cos[i], f) {
+ t.Errorf("Cos(%g) = %g, want %g", vf[i], f, cos[i])
+ }
+ }
+ for i := 0; i < len(vfcosSC); i++ {
+ if f := CosNoVec(vfcosSC[i]); !alike(cosSC[i], f) {
+ t.Errorf("Cos(%g) = %g, want %g", vfcosSC[i], f, cosSC[i])
+ }
+ }
+}
+
+func TestCoshNovec(t *testing.T) {
+ if !HasVX {
+ t.Skipf("no vector support")
+ }
+ for i := 0; i < len(vf); i++ {
+ if f := CoshNoVec(vf[i]); !close(cosh[i], f) {
+ t.Errorf("Cosh(%g) = %g, want %g", vf[i], f, cosh[i])
+ }
+ }
+ for i := 0; i < len(vfcoshSC); i++ {
+ if f := CoshNoVec(vfcoshSC[i]); !alike(coshSC[i], f) {
+ t.Errorf("Cosh(%g) = %g, want %g", vfcoshSC[i], f, coshSC[i])
+ }
+ }
+}
+func TestSinNovec(t *testing.T) {
+ if !HasVX {
+ t.Skipf("no vector support")
+ }
+ for i := 0; i < len(vf); i++ {
+ if f := SinNoVec(vf[i]); !veryclose(sin[i], f) {
+ t.Errorf("Sin(%g) = %g, want %g", vf[i], f, sin[i])
+ }
+ }
+ for i := 0; i < len(vfsinSC); i++ {
+ if f := SinNoVec(vfsinSC[i]); !alike(sinSC[i], f) {
+ t.Errorf("Sin(%g) = %g, want %g", vfsinSC[i], f, sinSC[i])
+ }
+ }
+}
+
+func TestSinhNovec(t *testing.T) {
+ if !HasVX {
+ t.Skipf("no vector support")
+ }
+ for i := 0; i < len(vf); i++ {
+ if f := SinhNoVec(vf[i]); !close(sinh[i], f) {
+ t.Errorf("Sinh(%g) = %g, want %g", vf[i], f, sinh[i])
+ }
+ }
+ for i := 0; i < len(vfsinhSC); i++ {
+ if f := SinhNoVec(vfsinhSC[i]); !alike(sinhSC[i], f) {
+ t.Errorf("Sinh(%g) = %g, want %g", vfsinhSC[i], f, sinhSC[i])
+ }
+ }
+}
+
+// Check that math functions of high angle values
+// return accurate results. [Since (vf[i] + large) - large != vf[i],
+// testing for Trig(vf[i] + large) == Trig(vf[i]), where large is
+// a multiple of 2*Pi, is misleading.]
+func TestLargeCosNovec(t *testing.T) {
+ if !HasVX {
+ t.Skipf("no vector support")
+ }
+ large := float64(100000 * Pi)
+ for i := 0; i < len(vf); i++ {
+ f1 := cosLarge[i]
+ f2 := CosNoVec(vf[i] + large)
+ if !close(f1, f2) {
+ t.Errorf("Cos(%g) = %g, want %g", vf[i]+large, f2, f1)
+ }
+ }
+}
+
+func TestLargeSinNovec(t *testing.T) {
+ if !HasVX {
+ t.Skipf("no vector support")
+ }
+ large := float64(100000 * Pi)
+ for i := 0; i < len(vf); i++ {
+ f1 := sinLarge[i]
+ f2 := SinNoVec(vf[i] + large)
+ if !close(f1, f2) {
+ t.Errorf("Sin(%g) = %g, want %g", vf[i]+large, f2, f1)
+ }
+ }
+}
+
+func TestTanhNovec(t *testing.T) {
+ if !HasVX {
+ t.Skipf("no vector support")
+ }
+ for i := 0; i < len(vf); i++ {
+ if f := TanhNoVec(vf[i]); !veryclose(tanh[i], f) {
+ t.Errorf("Tanh(%g) = %g, want %g", vf[i], f, tanh[i])
+ }
+ }
+ for i := 0; i < len(vftanhSC); i++ {
+ if f := TanhNoVec(vftanhSC[i]); !alike(tanhSC[i], f) {
+ t.Errorf("Tanh(%g) = %g, want %g", vftanhSC[i], f, tanhSC[i])
+ }
+ }
+
+}
+
+func TestLog10Novec(t *testing.T) {
+ if !HasVX {
+ t.Skipf("no vector support")
+ }
+ for i := 0; i < len(vf); i++ {
+ a := Abs(vf[i])
+ if f := Log10NoVec(a); !veryclose(log10[i], f) {
+ t.Errorf("Log10(%g) = %g, want %g", a, f, log10[i])
+ }
+ }
+ if f := Log10NoVec(E); f != Log10E {
+ t.Errorf("Log10(%g) = %g, want %g", E, f, Log10E)
+ }
+ for i := 0; i < len(vflogSC); i++ {
+ if f := Log10NoVec(vflogSC[i]); !alike(logSC[i], f) {
+ t.Errorf("Log10(%g) = %g, want %g", vflogSC[i], f, logSC[i])
+ }
+ }
+}
diff --git a/src/math/big/arith_amd64.s b/src/math/big/arith_amd64.s
index b69a2c6..a7eba67 100644
--- a/src/math/big/arith_amd64.s
+++ b/src/math/big/arith_amd64.s
@@ -326,6 +326,41 @@ TEXT ·mulAddVWW(SB),NOSPLIT,$0
MOVQ r+56(FP), CX // c = r
MOVQ z_len+8(FP), R11
MOVQ $0, BX // i = 0
+
+ CMPQ R11, $4
+ JL E5
+
+U5: // i+4 <= n
+ // regular loop body unrolled 4x
+ MOVQ (0*8)(R8)(BX*8), AX
+ MULQ R9
+ ADDQ CX, AX
+ ADCQ $0, DX
+ MOVQ AX, (0*8)(R10)(BX*8)
+ MOVQ DX, CX
+ MOVQ (1*8)(R8)(BX*8), AX
+ MULQ R9
+ ADDQ CX, AX
+ ADCQ $0, DX
+ MOVQ AX, (1*8)(R10)(BX*8)
+ MOVQ DX, CX
+ MOVQ (2*8)(R8)(BX*8), AX
+ MULQ R9
+ ADDQ CX, AX
+ ADCQ $0, DX
+ MOVQ AX, (2*8)(R10)(BX*8)
+ MOVQ DX, CX
+ MOVQ (3*8)(R8)(BX*8), AX
+ MULQ R9
+ ADDQ CX, AX
+ ADCQ $0, DX
+ MOVQ AX, (3*8)(R10)(BX*8)
+ MOVQ DX, CX
+ ADDQ $4, BX // i += 4
+
+ LEAQ 4(BX), DX
+ CMPQ DX, R11
+ JLE U5
JMP E5
L5: MOVQ (R8)(BX*8), AX
diff --git a/src/math/big/arith_decl_s390x.go b/src/math/big/arith_decl_s390x.go
new file mode 100644
index 0000000..0f11481
--- /dev/null
+++ b/src/math/big/arith_decl_s390x.go
@@ -0,0 +1,23 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !math_big_pure_go
+
+package big
+
+func addVV_check(z, x, y []Word) (c Word)
+func addVV_vec(z, x, y []Word) (c Word)
+func addVV_novec(z, x, y []Word) (c Word)
+func subVV_check(z, x, y []Word) (c Word)
+func subVV_vec(z, x, y []Word) (c Word)
+func subVV_novec(z, x, y []Word) (c Word)
+func addVW_check(z, x []Word, y Word) (c Word)
+func addVW_vec(z, x []Word, y Word) (c Word)
+func addVW_novec(z, x []Word, y Word) (c Word)
+func subVW_check(z, x []Word, y Word) (c Word)
+func subVW_vec(z, x []Word, y Word) (c Word)
+func subVW_novec(z, x []Word, y Word) (c Word)
+func hasVectorFacility() bool
+
+var hasVX = hasVectorFacility()
diff --git a/src/math/big/arith_mipsx.s b/src/math/big/arith_mipsx.s
new file mode 100644
index 0000000..ac23114
--- /dev/null
+++ b/src/math/big/arith_mipsx.s
@@ -0,0 +1,46 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !math_big_pure_go,mips !math_big_pure_go,mipsle
+
+#include "textflag.h"
+
+// This file provides fast assembly versions for the elementary
+// arithmetic operations on vectors implemented in arith.go.
+
+TEXT ·mulWW(SB),NOSPLIT,$0
+ JMP ·mulWW_g(SB)
+
+TEXT ·divWW(SB),NOSPLIT,$0
+ JMP ·divWW_g(SB)
+
+TEXT ·addVV(SB),NOSPLIT,$0
+ JMP ·addVV_g(SB)
+
+TEXT ·subVV(SB),NOSPLIT,$0
+ JMP ·subVV_g(SB)
+
+TEXT ·addVW(SB),NOSPLIT,$0
+ JMP ·addVW_g(SB)
+
+TEXT ·subVW(SB),NOSPLIT,$0
+ JMP ·subVW_g(SB)
+
+TEXT ·shlVU(SB),NOSPLIT,$0
+ JMP ·shlVU_g(SB)
+
+TEXT ·shrVU(SB),NOSPLIT,$0
+ JMP ·shrVU_g(SB)
+
+TEXT ·mulAddVWW(SB),NOSPLIT,$0
+ JMP ·mulAddVWW_g(SB)
+
+TEXT ·addMulVVW(SB),NOSPLIT,$0
+ JMP ·addMulVVW_g(SB)
+
+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
new file mode 100644
index 0000000..47fe8f1
--- /dev/null
+++ b/src/math/big/arith_ppc64.s
@@ -0,0 +1,14 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !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
new file mode 100644
index 0000000..b78cdfe
--- /dev/null
+++ b/src/math/big/arith_ppc64le.s
@@ -0,0 +1,50 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +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 d4d4171..89d1cbf 100644
--- a/src/math/big/arith_ppc64x.s
+++ b/src/math/big/arith_ppc64x.s
@@ -9,38 +9,178 @@
// This file provides fast assembly versions for the elementary
// arithmetic operations on vectors implemented in arith.go.
-TEXT ·mulWW(SB),NOSPLIT,$0
- BR ·mulWW_g(SB)
+// func mulWW(x, y Word) (z1, z0 Word)
+TEXT ·mulWW(SB), NOSPLIT, $0
+ MOVD x+0(FP), R4
+ MOVD y+8(FP), R5
+ MULHDU R4, R5, R6
+ MULLD R4, R5, R7
+ MOVD R6, z1+16(FP)
+ MOVD R7, z0+24(FP)
+ RET
-TEXT ·divWW(SB),NOSPLIT,$0
- BR ·divWW_g(SB)
-
-TEXT ·addVV(SB),NOSPLIT,$0
+TEXT ·addVV(SB), NOSPLIT, $0
BR ·addVV_g(SB)
-TEXT ·subVV(SB),NOSPLIT,$0
- BR ·subVV_g(SB)
+// func subVV(z, x, y []Word) (c Word)
+// z[i] = x[i] - y[i] for all i, carrying
+TEXT ·subVV(SB), NOSPLIT, $0
+ MOVD z_len+8(FP), R7
+ MOVD x+24(FP), R8
+ 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
+
+ SUBC R0, R0 // clear CA
+ JMP 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)
-TEXT ·addVW(SB),NOSPLIT,$0
+ ADD R29, R5 // i++
+
+sublend:
+ CMP R5, R7
+ BLT subloop
+
+ ADDZE R4
+ XOR R29, R4
+ MOVD R4, c+72(FP)
+ RET
+
+TEXT ·addVW(SB), NOSPLIT, $0
BR ·addVW_g(SB)
-TEXT ·subVW(SB),NOSPLIT,$0
+TEXT ·subVW(SB), NOSPLIT, $0
BR ·subVW_g(SB)
-TEXT ·shlVU(SB),NOSPLIT,$0
+TEXT ·shlVU(SB), NOSPLIT, $0
BR ·shlVU_g(SB)
-TEXT ·shrVU(SB),NOSPLIT,$0
+TEXT ·shrVU(SB), NOSPLIT, $0
BR ·shrVU_g(SB)
-TEXT ·mulAddVWW(SB),NOSPLIT,$0
- BR ·mulAddVWW_g(SB)
+// func mulAddVWW(z, x []Word, y, r Word) (c Word)
+TEXT ·mulAddVWW(SB), NOSPLIT, $0
+ MOVD z+0(FP), R10
+ MOVD x+24(FP), R8
+ MOVD y+48(FP), R9
+ MOVD r+56(FP), R4 // c = r
+ MOVD z_len+8(FP), R11
+ MOVD $0, R3 // i = 0
+ MOVD $8, R18
+ MOVD $1, R19
+
+ JMP e5
+
+l5:
+ MULLD R18, R3, R5
+ MOVD (R8)(R5), R20
+ MULLD R9, R20, R6
+ MULHDU R9, R20, R7
+ ADDC R4, R6
+ ADDZE R7
+ MOVD R6, (R10)(R5)
+ MOVD R7, R4
+ ADD R19, R3
+
+e5:
+ CMP R3, R11
+ BLT l5
+
+ MOVD R4, c+64(FP)
+ RET
+
+// func addMulVVW(z, x []Word, y Word) (c Word)
+TEXT ·addMulVVW(SB), NOSPLIT, $0
+ MOVD z+0(FP), R10
+ MOVD x+24(FP), R8
+ MOVD y+48(FP), R9
+ MOVD z_len+8(FP), R22
+
+ MOVD $0, R5 // i = 0
+ MOVD $0, R4 // c = 0
+ MOVD $8, R28
+ MOVD $-2, R23
+ AND R22, R23 // mask the last bit of z.len
+ MOVD $2, R24
+ CMP R23, R24
+ BGE unrolled
+ JMP end
+
+unrolled:
+ MOVD $8, R19 // no (RA)(RB*8) on power
+ MULLD R5, R19
+ MOVD (R10)(R19), R11 // R11 = z[i]
+ MOVD (R8)(R19), R16 // R16 = x[i]
+ ADD R28, R19, R25
+ MOVD (R10)(R25), R17
+ MOVD (R8)(R25), R18
+
+ MULLD R9, R16, R12
+ MULHDU R9, R16, R14
+ MULLD R9, R18, R6
+ MULHDU R9, R18, R7
+ ADDC R4, R12
+ ADDZE R14
+ ADDC R11, R12 // z[i] = (x[i]*y) + z[i] + carry
+ ADDZE R14 // carry = high order bits + add carry
+ MOVD R12, (R10)(R19)
+ ADDC R14, R6
+ ADDZE R7
+ ADDC R17, R6
+ ADDZE R7
+ MOVD R6, (R10)(R25)
+ MOVD R7, R4
+
+ ADD R24, R5
+ CMP R5, R23
+ BLT unrolled
+ JMP end
+
+loop:
+ MOVD $8, R19
+ MULLD R5, R19
+ MOVD (R10)(R19), R11
+ MOVD (R8)(R19), R16
+ MULLD R9, R16, R12
+ MULHDU R9, R16, R14
+ ADDC R4, R12
+ ADDZE R14
+ ADDC R11, R12
+ ADDZE R14
+ MOVD R12, (R10)(R19)
+ MOVD R14, R4
+
+ MOVD $1, R15
+ ADD R15, R5
+
+end:
+ CMP R5, R22
+ BLT loop
-TEXT ·addMulVVW(SB),NOSPLIT,$0
- BR ·addMulVVW_g(SB)
+ MOVD R4, c+56(FP)
+ RET
-TEXT ·divWVW(SB),NOSPLIT,$0
+TEXT ·divWVW(SB), NOSPLIT, $0
BR ·divWVW_g(SB)
-TEXT ·bitLen(SB),NOSPLIT,$0
- BR ·bitLen_g(SB)
+// 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
diff --git a/src/math/big/arith_s390x.s b/src/math/big/arith_s390x.s
index a691970..bddfd9e 100644
--- a/src/math/big/arith_s390x.s
+++ b/src/math/big/arith_s390x.s
@@ -9,93 +9,464 @@
// This file provides fast assembly versions for the elementary
// arithmetic operations on vectors implemented in arith.go.
+TEXT ·hasVectorFacility(SB),NOSPLIT,$24-1
+ MOVD $x-24(SP), R1
+ XC $24, 0(R1), 0(R1) // clear the storage
+ MOVD $2, R0 // R0 is the number of double words stored -1
+ WORD $0xB2B01000 // STFLE 0(R1)
+ XOR R0, R0 // reset the value of R0
+ MOVBZ z-8(SP), R1
+ AND $0x40, R1
+ BEQ novector
+vectorinstalled:
+ // check if the vector instruction has been enabled
+ VLEIB $0, $0xF, V16
+ VLGVB $0, V16, R1
+ CMPBNE R1, $0xF, novector
+ MOVB $1, ret+0(FP) // have vx
+ RET
+novector:
+ MOVB $0, ret+0(FP) // no vx
+ RET
+
TEXT ·mulWW(SB),NOSPLIT,$0
- MOVD x+0(FP), R3
- MOVD y+8(FP), R4
- MULHDU R3, R4
- MOVD R10, z1+16(FP)
- MOVD R11, z0+24(FP)
+ MOVD x+0(FP), R3
+ MOVD y+8(FP), R4
+ MULHDU R3, R4
+ MOVD R10, z1+16(FP)
+ MOVD R11, z0+24(FP)
RET
// func divWW(x1, x0, y Word) (q, r Word)
TEXT ·divWW(SB),NOSPLIT,$0
- MOVD x1+0(FP), R10
- MOVD x0+8(FP), R11
- MOVD y+16(FP), R5
- WORD $0xb98700a5 // dlgr r10,r5
- MOVD R11, q+24(FP)
- MOVD R10, r+32(FP)
+ MOVD x1+0(FP), R10
+ MOVD x0+8(FP), R11
+ MOVD y+16(FP), R5
+ WORD $0xb98700a5 // dlgr r10,r5
+ MOVD R11, q+24(FP)
+ MOVD R10, r+32(FP)
RET
// DI = R3, CX = R4, SI = r10, r8 = r8, r9=r9, r10 = r2 , r11 = r5, r12 = r6, r13 = r7, r14 = r1 (R0 set to 0) + use R11
// func addVV(z, x, y []Word) (c Word)
+
+
TEXT ·addVV(SB),NOSPLIT,$0
- MOVD z_len+8(FP), R3
- MOVD x+24(FP), R8
- MOVD y+48(FP), R9
- MOVD z+0(FP), R2
+ MOVD addvectorfacility+0x00(SB),R1
+ BR (R1)
+
+TEXT ·addVV_check(SB),NOSPLIT, $0
+ MOVB ·hasVX(SB), R1
+ CMPBEQ R1, $1, vectorimpl // vectorfacility = 1, vector supported
+ MOVD $addvectorfacility+0x00(SB), R1
+ MOVD $·addVV_novec(SB), R2
+ MOVD R2, 0(R1)
+ //MOVD $·addVV_novec(SB), 0(R1)
+ BR ·addVV_novec(SB)
+vectorimpl:
+ MOVD $addvectorfacility+0x00(SB), R1
+ MOVD $·addVV_vec(SB), R2
+ MOVD R2, 0(R1)
+ //MOVD $·addVV_vec(SB), 0(R1)
+ BR ·addVV_vec(SB)
+
+GLOBL addvectorfacility+0x00(SB), NOPTR, $8
+DATA addvectorfacility+0x00(SB)/8, $·addVV_check(SB)
+
+TEXT ·addVV_vec(SB),NOSPLIT,$0
+ MOVD z_len+8(FP), R3
+ MOVD x+24(FP), R8
+ MOVD y+48(FP), R9
+ MOVD z+0(FP), R2
+
+ MOVD $0, R4 // c = 0
+ MOVD $0, R0 // make sure it's zero
+ MOVD $0, R10 // i = 0
- MOVD $0, R4 // c = 0
- MOVD $0, R0 // make sure it's zero
- MOVD $0, R10 // i = 0
// s/JL/JMP/ below to disable the unrolled loop
- SUB $4, R3 // n -= 4
- BLT v1 // if n < 0 goto v1
+ SUB $4, R3
+ BLT v1
+ SUB $12, R3 // n -= 16
+ BLT A1 // if n < 0 goto A1
+
+ MOVD R8, R5
+ MOVD R9, R6
+ MOVD R2, R7
+ // n >= 0
+ // regular loop body unrolled 16x
+ VZERO V0 // c = 0
+UU1: VLM 0(R5), V1, V4 // 64-bytes into V1..V8
+ ADD $64, R5
+ VPDI $0x4,V1,V1,V1 // flip the doublewords to big-endian order
+ VPDI $0x4,V2,V2,V2 // flip the doublewords to big-endian order
+
+
+ VLM 0(R6), V9, V12 // 64-bytes into V9..V16
+ ADD $64, R6
+ VPDI $0x4,V9,V9,V9 // flip the doublewords to big-endian order
+ VPDI $0x4,V10,V10,V10 // flip the doublewords to big-endian order
+
+ VACCCQ V1, V9, V0, V25
+ VACQ V1, V9, V0, V17
+ VACCCQ V2, V10, V25, V26
+ VACQ V2, V10, V25, V18
+
+
+ VLM 0(R5), V5, V6 // 32-bytes into V1..V8
+ VLM 0(R6), V13, V14 // 32-bytes into V9..V16
+ ADD $32, R5
+ ADD $32, R6
+
+ VPDI $0x4,V3,V3,V3 // flip the doublewords to big-endian order
+ VPDI $0x4,V4,V4,V4 // flip the doublewords to big-endian order
+ VPDI $0x4,V11,V11,V11 // flip the doublewords to big-endian order
+ VPDI $0x4,V12,V12,V12 // flip the doublewords to big-endian order
+
+ VACCCQ V3, V11, V26, V27
+ VACQ V3, V11, V26, V19
+ VACCCQ V4, V12, V27, V28
+ VACQ V4, V12, V27, V20
+
+ VLM 0(R5), V7, V8 // 32-bytes into V1..V8
+ VLM 0(R6), V15, V16 // 32-bytes into V9..V16
+ ADD $32, R5
+ ADD $32, R6
+
+ VPDI $0x4,V5,V5,V5 // flip the doublewords to big-endian order
+ VPDI $0x4,V6,V6,V6 // flip the doublewords to big-endian order
+ VPDI $0x4,V13,V13,V13 // flip the doublewords to big-endian order
+ VPDI $0x4,V14,V14,V14 // flip the doublewords to big-endian order
+
+ VACCCQ V5, V13, V28, V29
+ VACQ V5, V13, V28, V21
+ VACCCQ V6, V14, V29, V30
+ VACQ V6, V14, V29, V22
+
+ VPDI $0x4,V7,V7,V7 // flip the doublewords to big-endian order
+ VPDI $0x4,V8,V8,V8 // flip the doublewords to big-endian order
+ VPDI $0x4,V15,V15,V15 // flip the doublewords to big-endian order
+ VPDI $0x4,V16,V16,V16 // flip the doublewords to big-endian order
+
+ VACCCQ V7, V15, V30, V31
+ VACQ V7, V15, V30, V23
+ VACCCQ V8, V16, V31, V0 //V0 has carry-over
+ VACQ V8, V16, V31, V24
+
+ VPDI $0x4,V17,V17,V17 // flip the doublewords to big-endian order
+ VPDI $0x4,V18,V18,V18 // flip the doublewords to big-endian order
+ VPDI $0x4,V19,V19,V19 // flip the doublewords to big-endian order
+ VPDI $0x4,V20,V20,V20 // flip the doublewords to big-endian order
+ VPDI $0x4,V21,V21,V21 // flip the doublewords to big-endian order
+ VPDI $0x4,V22,V22,V22 // flip the doublewords to big-endian order
+ VPDI $0x4,V23,V23,V23 // flip the doublewords to big-endian order
+ VPDI $0x4,V24,V24,V24 // flip the doublewords to big-endian order
+ VSTM V17, V24, 0(R7) // 128-bytes into z
+ ADD $128, R7
+ ADD $128, R10 // i += 16
+ SUB $16, R3 // n -= 16
+ BGE UU1 // if n >= 0 goto U1
+ VLGVG $1, V0, R4 // put cf into R4
+ NEG R4, R4 // save cf
+
+A1: ADD $12, R3 // n += 16
+
+
+ // s/JL/JMP/ below to disable the unrolled loop
+ BLT v1 // if n < 0 goto v1
U1: // n >= 0
// regular loop body unrolled 4x
- MOVD 0(R8)(R10*1), R5
- MOVD 8(R8)(R10*1), R6
- MOVD 16(R8)(R10*1), R7
- MOVD 24(R8)(R10*1), R1
- ADDC R4, R4 // restore CF
- MOVD 0(R9)(R10*1), R11
- ADDE R11, R5
- MOVD 8(R9)(R10*1), R11
- ADDE R11, R6
- MOVD 16(R9)(R10*1), R11
- ADDE R11, R7
- MOVD 24(R9)(R10*1), R11
- ADDE R11, R1
- MOVD R0, R4
- ADDE R4, R4 // save CF
- NEG R4, R4
- MOVD R5, 0(R2)(R10*1)
- MOVD R6, 8(R2)(R10*1)
- MOVD R7, 16(R2)(R10*1)
- MOVD R1, 24(R2)(R10*1)
+ MOVD 0(R8)(R10*1), R5
+ MOVD 8(R8)(R10*1), R6
+ MOVD 16(R8)(R10*1), R7
+ MOVD 24(R8)(R10*1), R1
+ ADDC R4, R4 // restore CF
+ MOVD 0(R9)(R10*1), R11
+ ADDE R11, R5
+ MOVD 8(R9)(R10*1), R11
+ ADDE R11, R6
+ MOVD 16(R9)(R10*1), R11
+ ADDE R11, R7
+ MOVD 24(R9)(R10*1), R11
+ ADDE R11, R1
+ MOVD R0, R4
+ ADDE R4, R4 // save CF
+ NEG R4, R4
+ MOVD R5, 0(R2)(R10*1)
+ MOVD R6, 8(R2)(R10*1)
+ MOVD R7, 16(R2)(R10*1)
+ MOVD R1, 24(R2)(R10*1)
+
+
+ ADD $32, R10 // i += 4
+ SUB $4, R3 // n -= 4
+ BGE U1 // if n >= 0 goto U1
+
+v1: ADD $4, R3 // n += 4
+ BLE E1 // if n <= 0 goto E1
+L1: // n > 0
+ ADDC R4, R4 // restore CF
+ MOVD 0(R8)(R10*1), R5
+ MOVD 0(R9)(R10*1), R11
+ ADDE R11, R5
+ MOVD R5, 0(R2)(R10*1)
+ MOVD R0, R4
+ ADDE R4, R4 // save CF
+ NEG R4, R4
+
+ ADD $8, R10 // i++
+ SUB $1, R3 // n--
+ BGT L1 // if n > 0 goto L1
+
+E1: NEG R4, R4
+ MOVD R4, c+72(FP) // return c
+ RET
- ADD $32, R10 // i += 4
- SUB $4, R3 // n -= 4
- BGE U1 // if n >= 0 goto U1
+TEXT ·addVV_novec(SB),NOSPLIT,$0
+novec:
+ MOVD z_len+8(FP), R3
+ MOVD x+24(FP), R8
+ MOVD y+48(FP), R9
+ MOVD z+0(FP), R2
-v1: ADD $4, R3 // n += 4
- BLE E1 // if n <= 0 goto E1
+ MOVD $0, R4 // c = 0
+ MOVD $0, R0 // make sure it's zero
+ MOVD $0, R10 // i = 0
-L1: // n > 0
- ADDC R4, R4 // restore CF
- MOVD 0(R8)(R10*1), R5
- MOVD 0(R9)(R10*1), R11
- ADDE R11, R5
- MOVD R5, 0(R2)(R10*1)
- MOVD R0, R4
- ADDE R4, R4 // save CF
- NEG R4, R4
+ // s/JL/JMP/ below to disable the unrolled loop
+ SUB $4, R3 // n -= 4
+ BLT v1n // if n < 0 goto v1n
+U1n: // n >= 0
+ // regular loop body unrolled 4x
+ MOVD 0(R8)(R10*1), R5
+ MOVD 8(R8)(R10*1), R6
+ MOVD 16(R8)(R10*1), R7
+ MOVD 24(R8)(R10*1), R1
+ ADDC R4, R4 // restore CF
+ MOVD 0(R9)(R10*1), R11
+ ADDE R11, R5
+ MOVD 8(R9)(R10*1), R11
+ ADDE R11, R6
+ MOVD 16(R9)(R10*1), R11
+ ADDE R11, R7
+ MOVD 24(R9)(R10*1), R11
+ ADDE R11, R1
+ MOVD R0, R4
+ ADDE R4, R4 // save CF
+ NEG R4, R4
+ MOVD R5, 0(R2)(R10*1)
+ MOVD R6, 8(R2)(R10*1)
+ MOVD R7, 16(R2)(R10*1)
+ MOVD R1, 24(R2)(R10*1)
+
+
+ ADD $32, R10 // i += 4
+ SUB $4, R3 // n -= 4
+ BGE U1n // if n >= 0 goto U1n
+
+v1n: ADD $4, R3 // n += 4
+ BLE E1n // if n <= 0 goto E1n
+
+L1n: // n > 0
+ ADDC R4, R4 // restore CF
+ MOVD 0(R8)(R10*1), R5
+ MOVD 0(R9)(R10*1), R11
+ ADDE R11, R5
+ MOVD R5, 0(R2)(R10*1)
+ MOVD R0, R4
+ ADDE R4, R4 // save CF
+ NEG R4, R4
+
+ ADD $8, R10 // i++
+ SUB $1, R3 // n--
+ BGT L1n // if n > 0 goto L1n
+
+E1n: NEG R4, R4
+ MOVD R4, c+72(FP) // return c
+ RET
- ADD $8, R10 // i++
- SUB $1, R3 // n--
- BGT L1 // if n > 0 goto L1
-E1: NEG R4, R4
- MOVD R4, c+72(FP) // return c
+TEXT ·subVV(SB),NOSPLIT,$0
+ MOVD subvectorfacility+0x00(SB),R1
+ BR (R1)
+
+TEXT ·subVV_check(SB),NOSPLIT,$0
+ MOVB ·hasVX(SB), R1
+ CMPBEQ R1, $1, vectorimpl // vectorfacility = 1, vector supported
+ MOVD $subvectorfacility+0x00(SB), R1
+ MOVD $·subVV_novec(SB), R2
+ MOVD R2, 0(R1)
+ //MOVD $·subVV_novec(SB), 0(R1)
+ BR ·subVV_novec(SB)
+vectorimpl:
+ MOVD $subvectorfacility+0x00(SB), R1
+ MOVD $·subVV_vec(SB), R2
+ MOVD R2, 0(R1)
+ //MOVD $·subVV_vec(SB), 0(R1)
+ BR ·subVV_vec(SB)
+
+GLOBL subvectorfacility+0x00(SB), NOPTR, $8
+DATA subvectorfacility+0x00(SB)/8, $·subVV_check(SB)
+
+// DI = R3, CX = R4, SI = r10, r8 = r8, r9=r9, r10 = r2 , r11 = r5, r12 = r6, r13 = r7, r14 = r1 (R0 set to 0) + use R11
+// func subVV(z, x, y []Word) (c Word)
+// (same as addVV except for SUBC/SUBE instead of ADDC/ADDE and label names)
+TEXT ·subVV_vec(SB),NOSPLIT,$0
+ MOVD z_len+8(FP), R3
+ MOVD x+24(FP), R8
+ MOVD y+48(FP), R9
+ MOVD z+0(FP), R2
+ MOVD $0, R4 // c = 0
+ MOVD $0, R0 // make sure it's zero
+ MOVD $0, R10 // i = 0
+
+ // s/JL/JMP/ below to disable the unrolled loop
+ SUB $4, R3 // n -= 4
+ BLT v1 // if n < 0 goto v1
+ SUB $12, R3 // n -= 16
+ BLT A1 // if n < 0 goto A1
+
+ MOVD R8, R5
+ MOVD R9, R6
+ MOVD R2, R7
+
+ // n >= 0
+ // regular loop body unrolled 16x
+ VZERO V0 // cf = 0
+ MOVD $1, R4 // for 390 subtraction cf starts as 1 (no borrow)
+ VLVGG $1, R4, V0 //put carry into V0
+
+UU1: VLM 0(R5), V1, V4 // 64-bytes into V1..V8
+ ADD $64, R5
+ VPDI $0x4,V1,V1,V1 // flip the doublewords to big-endian order
+ VPDI $0x4,V2,V2,V2 // flip the doublewords to big-endian order
+
+
+ VLM 0(R6), V9, V12 // 64-bytes into V9..V16
+ ADD $64, R6
+ VPDI $0x4,V9,V9,V9 // flip the doublewords to big-endian order
+ VPDI $0x4,V10,V10,V10 // flip the doublewords to big-endian order
+
+ VSBCBIQ V1, V9, V0, V25
+ VSBIQ V1, V9, V0, V17
+ VSBCBIQ V2, V10, V25, V26
+ VSBIQ V2, V10, V25, V18
+
+
+ VLM 0(R5), V5, V6 // 32-bytes into V1..V8
+ VLM 0(R6), V13, V14 // 32-bytes into V9..V16
+ ADD $32, R5
+ ADD $32, R6
+
+ VPDI $0x4,V3,V3,V3 // flip the doublewords to big-endian order
+ VPDI $0x4,V4,V4,V4 // flip the doublewords to big-endian order
+ VPDI $0x4,V11,V11,V11 // flip the doublewords to big-endian order
+ VPDI $0x4,V12,V12,V12 // flip the doublewords to big-endian order
+
+ VSBCBIQ V3, V11, V26, V27
+ VSBIQ V3, V11, V26, V19
+ VSBCBIQ V4, V12, V27, V28
+ VSBIQ V4, V12, V27, V20
+
+ VLM 0(R5), V7, V8 // 32-bytes into V1..V8
+ VLM 0(R6), V15, V16 // 32-bytes into V9..V16
+ ADD $32, R5
+ ADD $32, R6
+
+ VPDI $0x4,V5,V5,V5 // flip the doublewords to big-endian order
+ VPDI $0x4,V6,V6,V6 // flip the doublewords to big-endian order
+ VPDI $0x4,V13,V13,V13 // flip the doublewords to big-endian order
+ VPDI $0x4,V14,V14,V14 // flip the doublewords to big-endian order
+
+ VSBCBIQ V5, V13, V28, V29
+ VSBIQ V5, V13, V28, V21
+ VSBCBIQ V6, V14, V29, V30
+ VSBIQ V6, V14, V29, V22
+
+ VPDI $0x4,V7,V7,V7 // flip the doublewords to big-endian order
+ VPDI $0x4,V8,V8,V8 // flip the doublewords to big-endian order
+ VPDI $0x4,V15,V15,V15 // flip the doublewords to big-endian order
+ VPDI $0x4,V16,V16,V16 // flip the doublewords to big-endian order
+
+ VSBCBIQ V7, V15, V30, V31
+ VSBIQ V7, V15, V30, V23
+ VSBCBIQ V8, V16, V31, V0 //V0 has carry-over
+ VSBIQ V8, V16, V31, V24
+
+ VPDI $0x4,V17,V17,V17 // flip the doublewords to big-endian order
+ VPDI $0x4,V18,V18,V18 // flip the doublewords to big-endian order
+ VPDI $0x4,V19,V19,V19 // flip the doublewords to big-endian order
+ VPDI $0x4,V20,V20,V20 // flip the doublewords to big-endian order
+ VPDI $0x4,V21,V21,V21 // flip the doublewords to big-endian order
+ VPDI $0x4,V22,V22,V22 // flip the doublewords to big-endian order
+ VPDI $0x4,V23,V23,V23 // flip the doublewords to big-endian order
+ VPDI $0x4,V24,V24,V24 // flip the doublewords to big-endian order
+ VSTM V17, V24, 0(R7) // 128-bytes into z
+ ADD $128, R7
+ ADD $128, R10 // i += 16
+ SUB $16, R3 // n -= 16
+ BGE UU1 // if n >= 0 goto U1
+ VLGVG $1, V0, R4 // put cf into R4
+ SUB $1, R4 // save cf
+
+A1: ADD $12, R3 // n += 16
+ BLT v1 // if n < 0 goto v1
+
+U1: // n >= 0
+ // regular loop body unrolled 4x
+ MOVD 0(R8)(R10*1), R5
+ MOVD 8(R8)(R10*1), R6
+ MOVD 16(R8)(R10*1), R7
+ MOVD 24(R8)(R10*1), R1
+ MOVD R0, R11
+ SUBC R4, R11 // restore CF
+ MOVD 0(R9)(R10*1), R11
+ SUBE R11, R5
+ MOVD 8(R9)(R10*1), R11
+ SUBE R11, R6
+ MOVD 16(R9)(R10*1), R11
+ SUBE R11, R7
+ MOVD 24(R9)(R10*1), R11
+ SUBE R11, R1
+ MOVD R0, R4
+ SUBE R4, R4 // save CF
+ MOVD R5, 0(R2)(R10*1)
+ MOVD R6, 8(R2)(R10*1)
+ MOVD R7, 16(R2)(R10*1)
+ MOVD R1, 24(R2)(R10*1)
+
+ ADD $32, R10 // i += 4
+ SUB $4, R3 // n -= 4
+ BGE U1 // if n >= 0 goto U1n
+
+v1: ADD $4, R3 // n += 4
+ BLE E1 // if n <= 0 goto E1
+
+L1: // n > 0
+ MOVD R0, R11
+ SUBC R4, R11 // restore CF
+ MOVD 0(R8)(R10*1), R5
+ MOVD 0(R9)(R10*1), R11
+ SUBE R11, R5
+ MOVD R5, 0(R2)(R10*1)
+ MOVD R0, R4
+ SUBE R4, R4 // save CF
+
+ ADD $8, R10 // i++
+ SUB $1, R3 // n--
+ BGT L1 // if n > 0 goto L1n
+
+E1: NEG R4, R4
+ MOVD R4, c+72(FP) // return c
RET
+
// DI = R3, CX = R4, SI = r10, r8 = r8, r9=r9, r10 = r2 , r11 = r5, r12 = r6, r13 = r7, r14 = r1 (R0 set to 0) + use R11
// func subVV(z, x, y []Word) (c Word)
// (same as addVV except for SUBC/SUBE instead of ADDC/ADDE and label names)
-TEXT ·subVV(SB),NOSPLIT,$0
+TEXT ·subVV_novec(SB),NOSPLIT,$0
MOVD z_len+8(FP), R3
MOVD x+24(FP), R8
MOVD y+48(FP), R9
@@ -158,9 +529,163 @@ E1: NEG R4, R4
MOVD R4, c+72(FP) // return c
RET
-
-// func addVW(z, x []Word, y Word) (c Word)
TEXT ·addVW(SB),NOSPLIT,$0
+ MOVD addwvectorfacility+0x00(SB),R1
+ BR (R1)
+
+TEXT ·addVW_check(SB),NOSPLIT,$0
+ MOVB ·hasVX(SB), R1
+ CMPBEQ R1, $1, vectorimpl // vectorfacility = 1, vector supported
+ MOVD $addwvectorfacility+0x00(SB), R1
+ MOVD $·addVW_novec(SB), R2
+ MOVD R2, 0(R1)
+ //MOVD $·addVW_novec(SB), 0(R1)
+ BR ·addVW_novec(SB)
+vectorimpl:
+ MOVD $addwvectorfacility+0x00(SB), R1
+ MOVD $·addVW_vec(SB), R2
+ MOVD R2, 0(R1)
+ //MOVD $·addVW_vec(SB), 0(R1)
+ BR ·addVW_vec(SB)
+
+GLOBL addwvectorfacility+0x00(SB), NOPTR, $8
+DATA addwvectorfacility+0x00(SB)/8, $·addVW_check(SB)
+
+
+// func addVW_vec(z, x []Word, y Word) (c Word)
+TEXT ·addVW_vec(SB),NOSPLIT,$0
+ MOVD z_len+8(FP), R3
+ MOVD x+24(FP), R8
+ MOVD y+48(FP), R4 // c = y
+ MOVD z+0(FP), R2
+
+ MOVD $0, R0 // make sure it's zero
+ MOVD $0, R10 // i = 0
+ MOVD R8, R5
+ MOVD R2, R7
+
+ // s/JL/JMP/ below to disable the unrolled loop
+ SUB $4, R3 // n -= 4
+ BLT v10 // if n < 0 goto v10
+ SUB $12, R3
+ BLT A10
+
+ // n >= 0
+ // regular loop body unrolled 16x
+
+ VZERO V0 // prepare V0 to be final carry register
+ VZERO V9 // to ensure upper half is zero
+ VLVGG $1, R4, V9
+UU1: VLM 0(R5), V1, V4 // 64-bytes into V1..V4
+ ADD $64, R5
+ VPDI $0x4,V1,V1,V1 // flip the doublewords to big-endian order
+ VPDI $0x4,V2,V2,V2 // flip the doublewords to big-endian order
+
+
+ VACCCQ V1, V9, V0, V25
+ VACQ V1, V9, V0, V17
+ VZERO V9
+ VACCCQ V2, V9, V25, V26
+ VACQ V2, V9, V25, V18
+
+
+ VLM 0(R5), V5, V6 // 32-bytes into V5..V6
+ ADD $32, R5
+
+ VPDI $0x4,V3,V3,V3 // flip the doublewords to big-endian order
+ VPDI $0x4,V4,V4,V4 // flip the doublewords to big-endian order
+
+ VACCCQ V3, V9, V26, V27
+ VACQ V3, V9, V26, V19
+ VACCCQ V4, V9, V27, V28
+ VACQ V4, V9, V27, V20
+
+ VLM 0(R5), V7, V8 // 32-bytes into V7..V8
+ ADD $32, R5
+
+ VPDI $0x4,V5,V5,V5 // flip the doublewords to big-endian order
+ VPDI $0x4,V6,V6,V6 // flip the doublewords to big-endian order
+
+ VACCCQ V5, V9, V28, V29
+ VACQ V5, V9, V28, V21
+ VACCCQ V6, V9, V29, V30
+ VACQ V6, V9, V29, V22
+
+ VPDI $0x4,V7,V7,V7 // flip the doublewords to big-endian order
+ VPDI $0x4,V8,V8,V8 // flip the doublewords to big-endian order
+
+ VACCCQ V7, V9, V30, V31
+ VACQ V7, V9, V30, V23
+ VACCCQ V8, V9, V31, V0 //V0 has carry-over
+ VACQ V8, V9, V31, V24
+
+ VPDI $0x4,V17,V17,V17 // flip the doublewords to big-endian order
+ VPDI $0x4,V18,V18,V18 // flip the doublewords to big-endian order
+ VPDI $0x4,V19,V19,V19 // flip the doublewords to big-endian order
+ VPDI $0x4,V20,V20,V20 // flip the doublewords to big-endian order
+ VPDI $0x4,V21,V21,V21 // flip the doublewords to big-endian order
+ VPDI $0x4,V22,V22,V22 // flip the doublewords to big-endian order
+ VPDI $0x4,V23,V23,V23 // flip the doublewords to big-endian order
+ VPDI $0x4,V24,V24,V24 // flip the doublewords to big-endian order
+ VSTM V17, V24, 0(R7) // 128-bytes into z
+ ADD $128, R7
+ ADD $128, R10 // i += 16
+ SUB $16, R3 // n -= 16
+ BGE UU1 // if n >= 0 goto U1
+ VLGVG $1, V0, R4 // put cf into R4 in case we branch to v10
+
+A10: ADD $12, R3 // n += 16
+
+
+ // s/JL/JMP/ below to disable the unrolled loop
+
+ BLT v10 // if n < 0 goto v10
+
+
+U4: // n >= 0
+ // regular loop body unrolled 4x
+ MOVD 0(R8)(R10*1), R5
+ MOVD 8(R8)(R10*1), R6
+ MOVD 16(R8)(R10*1), R7
+ MOVD 24(R8)(R10*1), R1
+ ADDC R4, R5
+ ADDE R0, R6
+ ADDE R0, R7
+ ADDE R0, R1
+ ADDE R0, R0
+ MOVD R0, R4 // save CF
+ SUB R0, R0
+ MOVD R5, 0(R2)(R10*1)
+ MOVD R6, 8(R2)(R10*1)
+ MOVD R7, 16(R2)(R10*1)
+ MOVD R1, 24(R2)(R10*1)
+
+ ADD $32, R10 // i += 4 -> i +=32
+ SUB $4, R3 // n -= 4
+ BGE U4 // if n >= 0 goto U4
+
+v10: ADD $4, R3 // n += 4
+ BLE E10 // if n <= 0 goto E4
+
+
+L4: // n > 0
+ MOVD 0(R8)(R10*1), R5
+ ADDC R4, R5
+ ADDE R0, R0
+ MOVD R0, R4 // save CF
+ SUB R0, R0
+ MOVD R5, 0(R2)(R10*1)
+
+ ADD $8, R10 // i++
+ SUB $1, R3 // n--
+ BGT L4 // if n > 0 goto L4
+
+E10: MOVD R4, c+56(FP) // return c
+
+ RET
+
+
+TEXT ·addVW_novec(SB),NOSPLIT,$0
//DI = R3, CX = R4, SI = r10, r8 = r8, r10 = r2 , r11 = r5, r12 = r6, r13 = r7, r14 = r1 (R0 set to 0)
MOVD z_len+8(FP), R3
MOVD x+24(FP), R8
@@ -214,10 +739,166 @@ E4: MOVD R4, c+56(FP) // return c
RET
+TEXT ·subVW(SB),NOSPLIT,$0
+ MOVD subwvectorfacility+0x00(SB),R1
+ BR (R1)
+
+TEXT ·subVW_check(SB),NOSPLIT,$0
+ MOVB ·hasVX(SB), R1
+ CMPBEQ R1, $1, vectorimpl // vectorfacility = 1, vector supported
+ MOVD $subwvectorfacility+0x00(SB), R1
+ MOVD $·subVW_novec(SB), R2
+ MOVD R2, 0(R1)
+ //MOVD $·subVW_novec(SB), 0(R1)
+ BR ·subVW_novec(SB)
+vectorimpl:
+ MOVD $subwvectorfacility+0x00(SB), R1
+ MOVD $·subVW_vec(SB), R2
+ MOVD R2, 0(R1)
+ //MOVD $·subVW_vec(SB), 0(R1)
+ BR ·subVW_vec(SB)
+
+GLOBL subwvectorfacility+0x00(SB), NOPTR, $8
+DATA subwvectorfacility+0x00(SB)/8, $·subVW_check(SB)
+
+// func subVW(z, x []Word, y Word) (c Word)
+TEXT ·subVW_vec(SB),NOSPLIT,$0
+ MOVD z_len+8(FP), R3
+ MOVD x+24(FP), R8
+ MOVD y+48(FP), R4 // c = y
+ MOVD z+0(FP), R2
+
+ MOVD $0, R0 // make sure it's zero
+ MOVD $0, R10 // i = 0
+ MOVD R8, R5
+ MOVD R2, R7
+
+ // s/JL/JMP/ below to disable the unrolled loop
+ SUB $4, R3 // n -= 4
+ BLT v11 // if n < 0 goto v11
+ SUB $12, R3
+ BLT A11
+
+ VZERO V0
+ MOVD $1, R6 // prepare V0 to be final carry register
+ VLVGG $1, R6, V0 // borrow is initially "no borrow"
+ VZERO V9 // to ensure upper half is zero
+ VLVGG $1, R4, V9
+
+ // n >= 0
+ // regular loop body unrolled 16x
+
+
+UU1: VLM 0(R5), V1, V4 // 64-bytes into V1..V4
+ ADD $64, R5
+ VPDI $0x4,V1,V1,V1 // flip the doublewords to big-endian order
+ VPDI $0x4,V2,V2,V2 // flip the doublewords to big-endian order
+
+
+ VSBCBIQ V1, V9, V0, V25
+ VSBIQ V1, V9, V0, V17
+ VZERO V9
+ VSBCBIQ V2, V9, V25, V26
+ VSBIQ V2, V9, V25, V18
+
+ VLM 0(R5), V5, V6 // 32-bytes into V5..V6
+ ADD $32, R5
+
+ VPDI $0x4,V3,V3,V3 // flip the doublewords to big-endian order
+ VPDI $0x4,V4,V4,V4 // flip the doublewords to big-endian order
+
+
+ VSBCBIQ V3, V9, V26, V27
+ VSBIQ V3, V9, V26, V19
+ VSBCBIQ V4, V9, V27, V28
+ VSBIQ V4, V9, V27, V20
+
+ VLM 0(R5), V7, V8 // 32-bytes into V7..V8
+ ADD $32, R5
+
+ VPDI $0x4,V5,V5,V5 // flip the doublewords to big-endian order
+ VPDI $0x4,V6,V6,V6 // flip the doublewords to big-endian order
+
+ VSBCBIQ V5, V9, V28, V29
+ VSBIQ V5, V9, V28, V21
+ VSBCBIQ V6, V9, V29, V30
+ VSBIQ V6, V9, V29, V22
+
+ VPDI $0x4,V7,V7,V7 // flip the doublewords to big-endian order
+ VPDI $0x4,V8,V8,V8 // flip the doublewords to big-endian order
+
+ VSBCBIQ V7, V9, V30, V31
+ VSBIQ V7, V9, V30, V23
+ VSBCBIQ V8, V9, V31, V0 // V0 has carry-over
+ VSBIQ V8, V9, V31, V24
+
+ VPDI $0x4,V17,V17,V17 // flip the doublewords to big-endian order
+ VPDI $0x4,V18,V18,V18 // flip the doublewords to big-endian order
+ VPDI $0x4,V19,V19,V19 // flip the doublewords to big-endian order
+ VPDI $0x4,V20,V20,V20 // flip the doublewords to big-endian order
+ VPDI $0x4,V21,V21,V21 // flip the doublewords to big-endian order
+ VPDI $0x4,V22,V22,V22 // flip the doublewords to big-endian order
+ VPDI $0x4,V23,V23,V23 // flip the doublewords to big-endian order
+ VPDI $0x4,V24,V24,V24 // flip the doublewords to big-endian order
+ VSTM V17, V24, 0(R7) // 128-bytes into z
+ ADD $128, R7
+ ADD $128, R10 // i += 16
+ SUB $16, R3 // n -= 16
+ BGE UU1 // if n >= 0 goto U1
+ VLGVG $1, V0, R4 // put cf into R4 in case we branch to v10
+ SUB $1, R4 // save cf
+ NEG R4, R4
+A11: ADD $12, R3 // n += 16
+
+ BLT v11 // if n < 0 goto v11
+
+ // n >= 0
+ // regular loop body unrolled 4x
+
+U4: // n >= 0
+ // regular loop body unrolled 4x
+ MOVD 0(R8)(R10*1), R5
+ MOVD 8(R8)(R10*1), R6
+ MOVD 16(R8)(R10*1), R7
+ MOVD 24(R8)(R10*1), R1
+ SUBC R4, R5 //SLGR -> SUBC
+ SUBE R0, R6 //SLBGR -> SUBE
+ SUBE R0, R7
+ SUBE R0, R1
+ SUBE R4, R4 // save CF
+ NEG R4, R4
+ MOVD R5, 0(R2)(R10*1)
+ MOVD R6, 8(R2)(R10*1)
+ MOVD R7, 16(R2)(R10*1)
+ MOVD R1, 24(R2)(R10*1)
+
+ ADD $32, R10 // i += 4 -> i +=32
+ SUB $4, R3 // n -= 4
+ BGE U4 // if n >= 0 goto U4
+
+v11: ADD $4, R3 // n += 4
+ BLE E11 // if n <= 0 goto E4
+
+L4: // n > 0
+
+ MOVD 0(R8)(R10*1), R5
+ SUBC R4, R5
+ SUBE R4, R4 // save CF
+ NEG R4, R4
+ MOVD R5, 0(R2)(R10*1)
+
+ ADD $8, R10 // i++
+ SUB $1, R3 // n--
+ BGT L4 // if n > 0 goto L4
+
+E11: MOVD R4, c+56(FP) // return c
+
+ RET
+
//DI = R3, CX = R4, SI = r10, r8 = r8, r10 = r2 , r11 = r5, r12 = r6, r13 = r7, r14 = r1 (R0 set to 0)
// func subVW(z, x []Word, y Word) (c Word)
// (same as addVW except for SUBC/SUBE instead of ADDC/ADDE and label names)
-TEXT ·subVW(SB),NOSPLIT,$0
+TEXT ·subVW_novec(SB),NOSPLIT,$0
MOVD z_len+8(FP), R3
MOVD x+24(FP), R8
MOVD y+48(FP), R4 // c = y
@@ -270,296 +951,299 @@ E4: MOVD R4, c+56(FP) // return c
// func shlVU(z, x []Word, s uint) (c Word)
TEXT ·shlVU(SB),NOSPLIT,$0
- MOVD z_len+8(FP), R5
- SUB $1, R5 // n--
- BLT X8b // n < 0 (n <= 0)
+ MOVD z_len+8(FP), R5
+ MOVD $0, R0
+ SUB $1, R5 // n--
+ BLT X8b // n < 0 (n <= 0)
// n > 0
- MOVD s+48(FP), R4
- CMPBEQ R0, R4, Z80 //handle 0 case beq
- MOVD $64, R6
- CMPBEQ R6, R4, Z864 //handle 64 case beq
- MOVD z+0(FP), R2
- MOVD x+24(FP), R8
- SLD $3, R5 // n = n*8
- SUB R4, R6, R7
- MOVD (R8)(R5*1), R10 // w1 = x[i-1]
- SRD R7, R10, R3
- MOVD R3, c+56(FP)
-
- MOVD $0, R1 // i = 0
- BR E8
+ MOVD s+48(FP), R4
+ CMPBEQ R0, R4, Z80 //handle 0 case beq
+ MOVD $64, R6
+ CMPBEQ R6, R4, Z864 //handle 64 case beq
+ MOVD z+0(FP), R2
+ MOVD x+24(FP), R8
+ SLD $3, R5 // n = n*8
+ SUB R4, R6, R7
+ MOVD (R8)(R5*1), R10 // w1 = x[i-1]
+ SRD R7, R10, R3
+ MOVD R3, c+56(FP)
+
+ MOVD $0, R1 // i = 0
+ BR E8
// i < n-1
-L8: MOVD R10, R3 // w = w1
- MOVD -8(R8)(R5*1), R10 // w1 = x[i+1]
+L8: MOVD R10, R3 // w = w1
+ MOVD -8(R8)(R5*1), R10 // w1 = x[i+1]
- SLD R4, R3 // w<<s | w1>>ŝ
- SRD R7, R10, R6
- OR R6, R3
- MOVD R3, (R2)(R5*1) // z[i] = w<<s | w1>>ŝ
- SUB $8, R5 // i--
+ SLD R4, R3 // w<<s | w1>>ŝ
+ SRD R7, R10, R6
+ OR R6, R3
+ MOVD R3, (R2)(R5*1) // z[i] = w<<s | w1>>ŝ
+ SUB $8, R5 // i--
-E8: CMPBGT R5, R0, L8 // i < n-1
+E8: CMPBGT R5, R0, L8 // i < n-1
// i >= n-1
-X8a: SLD R4, R10 // w1<<s
- MOVD R10, (R2) // z[0] = w1<<s
+X8a: SLD R4, R10 // w1<<s
+ MOVD R10, (R2) // z[0] = w1<<s
RET
-X8b: MOVD R0, c+56(FP)
+X8b: MOVD R0, c+56(FP)
RET
-Z80: MOVD z+0(FP), R2
- MOVD x+24(FP), R8
- SLD $3, R5 // n = n*8
+Z80: MOVD z+0(FP), R2
+ MOVD x+24(FP), R8
+ SLD $3, R5 // n = n*8
- MOVD (R8), R10
- MOVD $0, R3
- MOVD R3, c+56(FP)
+ MOVD (R8), R10
+ MOVD $0, R3
+ MOVD R3, c+56(FP)
- MOVD $0, R1 // i = 0
- BR E8Z
+ MOVD $0, R1 // i = 0
+ BR E8Z
// i < n-1
-L8Z: MOVD R10, R3
- MOVD 8(R8)(R1*1), R10
+L8Z: MOVD R10, R3
+ MOVD 8(R8)(R1*1), R10
- MOVD R3, (R2)(R1*1)
- ADD $8, R1
+ MOVD R3, (R2)(R1*1)
+ ADD $8, R1
-E8Z: CMPBLT R1, R5, L8Z
+E8Z: CMPBLT R1, R5, L8Z
// i >= n-1
- MOVD R10, (R2)(R5*1)
+ MOVD R10, (R2)(R5*1)
RET
-Z864: MOVD z+0(FP), R2
- MOVD x+24(FP), R8
- SLD $3, R5 // n = n*8
- MOVD (R8)(R5*1), R3 // w1 = x[n-1]
- MOVD R3, c+56(FP) // z[i] = x[n-1]
+Z864: MOVD z+0(FP), R2
+ MOVD x+24(FP), R8
+ SLD $3, R5 // n = n*8
+ MOVD (R8)(R5*1), R3 // w1 = x[n-1]
+ MOVD R3, c+56(FP) // z[i] = x[n-1]
- BR E864
+ BR E864
// i < n-1
-L864: MOVD -8(R8)(R5*1), R3
+L864: MOVD -8(R8)(R5*1), R3
- MOVD R3, (R2)(R5*1) // z[i] = x[n-1]
- SUB $8, R5 // i--
+ MOVD R3, (R2)(R5*1) // z[i] = x[n-1]
+ SUB $8, R5 // i--
-E864: CMPBGT R5, R0, L864 // i < n-1
+E864: CMPBGT R5, R0, L864 // i < n-1
- MOVD R0, (R2) // z[n-1] = 0
+ MOVD R0, (R2) // z[n-1] = 0
RET
// CX = R4, r8 = r8, r10 = r2 , r11 = r5, DX = r3, AX = r10 , BX = R1 , 64-count = r7 (R0 set to 0) temp = R6
// func shrVU(z, x []Word, s uint) (c Word)
TEXT ·shrVU(SB),NOSPLIT,$0
- MOVD z_len+8(FP), R5
- SUB $1, R5 // n--
- BLT X9b // n < 0 (n <= 0)
+ MOVD z_len+8(FP), R5
+ MOVD $0, R0
+ SUB $1, R5 // n--
+ BLT X9b // n < 0 (n <= 0)
// n > 0
- MOVD s+48(FP), R4
- CMPBEQ R0, R4, ZB0 //handle 0 case beq
- MOVD $64, R6
- CMPBEQ R6, R4, ZB64 //handle 64 case beq
- MOVD z+0(FP), R2
- MOVD x+24(FP), R8
- SLD $3, R5 // n = n*8
- SUB R4, R6, R7
- MOVD (R8), R10 // w1 = x[0]
- SLD R7, R10, R3
- MOVD R3, c+56(FP)
-
- MOVD $0, R1 // i = 0
- BR E9
+ MOVD s+48(FP), R4
+ CMPBEQ R0, R4, ZB0 //handle 0 case beq
+ MOVD $64, R6
+ CMPBEQ R6, R4, ZB64 //handle 64 case beq
+ MOVD z+0(FP), R2
+ MOVD x+24(FP), R8
+ SLD $3, R5 // n = n*8
+ SUB R4, R6, R7
+ MOVD (R8), R10 // w1 = x[0]
+ SLD R7, R10, R3
+ MOVD R3, c+56(FP)
+
+ MOVD $0, R1 // i = 0
+ BR E9
// i < n-1
-L9: MOVD R10, R3 // w = w1
- MOVD 8(R8)(R1*1), R10 // w1 = x[i+1]
+L9: MOVD R10, R3 // w = w1
+ MOVD 8(R8)(R1*1), R10 // w1 = x[i+1]
- SRD R4, R3 // w>>s | w1<<s
- SLD R7, R10, R6
- OR R6, R3
- MOVD R3, (R2)(R1*1) // z[i] = w>>s | w1<<s
- ADD $8, R1 // i++
+ SRD R4, R3 // w>>s | w1<<s
+ SLD R7, R10, R6
+ OR R6, R3
+ MOVD R3, (R2)(R1*1) // z[i] = w>>s | w1<<s
+ ADD $8, R1 // i++
-E9: CMPBLT R1, R5, L9 // i < n-1
+E9: CMPBLT R1, R5, L9 // i < n-1
// i >= n-1
-X9a: SRD R4, R10 // w1>>s
- MOVD R10, (R2)(R5*1) // z[n-1] = w1>>s
+X9a: SRD R4, R10 // w1>>s
+ MOVD R10, (R2)(R5*1) // z[n-1] = w1>>s
RET
-X9b: MOVD R0, c+56(FP)
+X9b: MOVD R0, c+56(FP)
RET
-ZB0: MOVD z+0(FP), R2
- MOVD x+24(FP), R8
- SLD $3, R5 // n = n*8
+ZB0: MOVD z+0(FP), R2
+ MOVD x+24(FP), R8
+ SLD $3, R5 // n = n*8
- MOVD (R8), R10 // w1 = x[0]
- MOVD $0, R3 // R10 << 64
- MOVD R3, c+56(FP)
+ MOVD (R8), R10 // w1 = x[0]
+ MOVD $0, R3 // R10 << 64
+ MOVD R3, c+56(FP)
- MOVD $0, R1 // i = 0
- BR E9Z
+ MOVD $0, R1 // i = 0
+ BR E9Z
// i < n-1
-L9Z: MOVD R10, R3 // w = w1
- MOVD 8(R8)(R1*1), R10 // w1 = x[i+1]
+L9Z: MOVD R10, R3 // w = w1
+ MOVD 8(R8)(R1*1), R10 // w1 = x[i+1]
- MOVD R3, (R2)(R1*1) // z[i] = w>>s | w1<<s
- ADD $8, R1 // i++
+ MOVD R3, (R2)(R1*1) // z[i] = w>>s | w1<<s
+ ADD $8, R1 // i++
-E9Z: CMPBLT R1, R5, L9Z // i < n-1
+E9Z: CMPBLT R1, R5, L9Z // i < n-1
// i >= n-1
- MOVD R10, (R2)(R5*1) // z[n-1] = w1>>s
+ MOVD R10, (R2)(R5*1) // z[n-1] = w1>>s
RET
-ZB64: MOVD z+0(FP), R2
- MOVD x+24(FP), R8
- SLD $3, R5 // n = n*8
- MOVD (R8), R3 // w1 = x[0]
- MOVD R3, c+56(FP)
+ZB64: MOVD z+0(FP), R2
+ MOVD x+24(FP), R8
+ SLD $3, R5 // n = n*8
+ MOVD (R8), R3 // w1 = x[0]
+ MOVD R3, c+56(FP)
- MOVD $0, R1 // i = 0
- BR E964
+ MOVD $0, R1 // i = 0
+ BR E964
// i < n-1
-L964: MOVD 8(R8)(R1*1), R3 // w1 = x[i+1]
+L964: MOVD 8(R8)(R1*1), R3 // w1 = x[i+1]
- MOVD R3, (R2)(R1*1) // z[i] = w>>s | w1<<s
- ADD $8, R1 // i++
+ MOVD R3, (R2)(R1*1) // z[i] = w>>s | w1<<s
+ ADD $8, R1 // i++
-E964: CMPBLT R1, R5, L964 // i < n-1
+E964: CMPBLT R1, R5, L964 // i < n-1
// i >= n-1
- MOVD $0, R10 // w1>>s
- MOVD R10, (R2)(R5*1) // z[n-1] = w1>>s
+ MOVD $0, R10 // w1>>s
+ MOVD R10, (R2)(R5*1) // z[n-1] = w1>>s
RET
// CX = R4, r8 = r8, r9=r9, r10 = r2 , r11 = r5, DX = r3, AX = r6 , BX = R1 , (R0 set to 0) + use R11 + use R7 for i
// func mulAddVWW(z, x []Word, y, r Word) (c Word)
TEXT ·mulAddVWW(SB),NOSPLIT,$0
- MOVD z+0(FP), R2
- MOVD x+24(FP), R8
- MOVD y+48(FP), R9
- MOVD r+56(FP), R4 // c = r
- MOVD z_len+8(FP), R5
- MOVD $0, R1 // i = 0
- MOVD $0, R7 // i*8 = 0
- MOVD $0, R0 // make sure it's zero
- BR E5
-
-L5: MOVD (R8)(R1*1), R6
- MULHDU R9, R6
- ADDC R4, R11 //add to low order bits
- ADDE R0, R6
- MOVD R11, (R2)(R1*1)
- MOVD R6, R4
- ADD $8, R1 // i*8 + 8
- ADD $1, R7 // i++
-
-E5: CMPBLT R7, R5, L5 // i < n
-
- MOVD R4, c+64(FP)
+ MOVD z+0(FP), R2
+ MOVD x+24(FP), R8
+ MOVD y+48(FP), R9
+ MOVD r+56(FP), R4 // c = r
+ MOVD z_len+8(FP), R5
+ MOVD $0, R1 // i = 0
+ MOVD $0, R7 // i*8 = 0
+ MOVD $0, R0 // make sure it's zero
+ BR E5
+
+L5: MOVD (R8)(R1*1), R6
+ MULHDU R9, R6
+ ADDC R4, R11 //add to low order bits
+ ADDE R0, R6
+ MOVD R11, (R2)(R1*1)
+ MOVD R6, R4
+ ADD $8, R1 // i*8 + 8
+ ADD $1, R7 // i++
+
+E5: CMPBLT R7, R5, L5 // i < n
+
+ MOVD R4, c+64(FP)
RET
// func addMulVVW(z, x []Word, y Word) (c Word)
// CX = R4, r8 = r8, r9=r9, r10 = r2 , r11 = r5, AX = r11, DX = R6, r12=r12, BX = R1 , (R0 set to 0) + use R11 + use R7 for i
TEXT ·addMulVVW(SB),NOSPLIT,$0
- MOVD z+0(FP), R2
- MOVD x+24(FP), R8
- MOVD y+48(FP), R9
- MOVD z_len+8(FP), R5
-
- MOVD $0, R1 // i*8 = 0
- MOVD $0, R7 // i = 0
- MOVD $0, R0 // make sure it's zero
- MOVD $0, R4 // c = 0
-
- MOVD R5, R12
- AND $-2, R12
- CMPBGE R5, $2, A6
- BR E6
-
-A6: MOVD (R8)(R1*1), R6
- MULHDU R9, R6
- MOVD (R2)(R1*1), R10
- ADDC R10, R11 //add to low order bits
- ADDE R0, R6
- ADDC R4, R11
- ADDE R0, R6
- MOVD R6, R4
- MOVD R11, (R2)(R1*1)
-
- MOVD (8)(R8)(R1*1), R6
- MULHDU R9, R6
- MOVD (8)(R2)(R1*1), R10
- ADDC R10, R11 //add to low order bits
- ADDE R0, R6
- ADDC R4, R11
- ADDE R0, R6
- MOVD R6, R4
- MOVD R11, (8)(R2)(R1*1)
-
- ADD $16, R1 // i*8 + 8
- ADD $2, R7 // i++
-
- CMPBLT R7, R12, A6
- BR E6
-
-L6: MOVD (R8)(R1*1), R6
- MULHDU R9, R6
- MOVD (R2)(R1*1), R10
- ADDC R10, R11 //add to low order bits
- ADDE R0, R6
- ADDC R4, R11
- ADDE R0, R6
- MOVD R6, R4
- MOVD R11, (R2)(R1*1)
-
- ADD $8, R1 // i*8 + 8
- ADD $1, R7 // i++
-
-E6: CMPBLT R7, R5, L6 // i < n
-
- MOVD R4, c+56(FP)
+ MOVD z+0(FP), R2
+ MOVD x+24(FP), R8
+ MOVD y+48(FP), R9
+ MOVD z_len+8(FP), R5
+
+ MOVD $0, R1 // i*8 = 0
+ MOVD $0, R7 // i = 0
+ MOVD $0, R0 // make sure it's zero
+ MOVD $0, R4 // c = 0
+
+ MOVD R5, R12
+ AND $-2, R12
+ CMPBGE R5, $2, A6
+ BR E6
+
+A6: MOVD (R8)(R1*1), R6
+ MULHDU R9, R6
+ MOVD (R2)(R1*1), R10
+ ADDC R10, R11 //add to low order bits
+ ADDE R0, R6
+ ADDC R4, R11
+ ADDE R0, R6
+ MOVD R6, R4
+ MOVD R11, (R2)(R1*1)
+
+ MOVD (8)(R8)(R1*1), R6
+ MULHDU R9, R6
+ MOVD (8)(R2)(R1*1), R10
+ ADDC R10, R11 //add to low order bits
+ ADDE R0, R6
+ ADDC R4, R11
+ ADDE R0, R6
+ MOVD R6, R4
+ MOVD R11, (8)(R2)(R1*1)
+
+ ADD $16, R1 // i*8 + 8
+ ADD $2, R7 // i++
+
+ CMPBLT R7, R12, A6
+ BR E6
+
+L6: MOVD (R8)(R1*1), R6
+ MULHDU R9, R6
+ MOVD (R2)(R1*1), R10
+ ADDC R10, R11 //add to low order bits
+ ADDE R0, R6
+ ADDC R4, R11
+ ADDE R0, R6
+ MOVD R6, R4
+ MOVD R11, (R2)(R1*1)
+
+ ADD $8, R1 // i*8 + 8
+ ADD $1, R7 // i++
+
+E6: CMPBLT R7, R5, L6 // i < n
+
+ MOVD R4, c+56(FP)
RET
// func divWVW(z []Word, xn Word, x []Word, y Word) (r Word)
// CX = R4, r8 = r8, r9=r9, r10 = r2 , r11 = r5, AX = r11, DX = R6, r12=r12, BX = R1(*8) , (R0 set to 0) + use R11 + use R7 for i
TEXT ·divWVW(SB),NOSPLIT,$0
- MOVD z+0(FP), R2
- MOVD xn+24(FP), R10 // r = xn
- MOVD x+32(FP), R8
- MOVD y+56(FP), R9
- MOVD z_len+8(FP), R7 // i = z
- SLD $3, R7, R1 // i*8
- MOVD $0, R0 // make sure it's zero
- BR E7
-
-L7: MOVD (R8)(R1*1), R11
- WORD $0xB98700A9 //DLGR R10,R9
- MOVD R11, (R2)(R1*1)
-
-E7: SUB $1, R7 // i--
- SUB $8, R1
- BGE L7 // i >= 0
-
- MOVD R10, r+64(FP)
+ MOVD z+0(FP), R2
+ MOVD xn+24(FP), R10 // r = xn
+ MOVD x+32(FP), R8
+ MOVD y+56(FP), R9
+ MOVD z_len+8(FP), R7 // i = z
+ SLD $3, R7, R1 // i*8
+ MOVD $0, R0 // make sure it's zero
+ BR E7
+
+L7: MOVD (R8)(R1*1), R11
+ WORD $0xB98700A9 //DLGR R10,R9
+ MOVD R11, (R2)(R1*1)
+
+E7: SUB $1, R7 // i--
+ SUB $8, R1
+ BGE L7 // i >= 0
+
+ MOVD R10, r+64(FP)
RET
// func bitLen(x Word) (n int)
TEXT ·bitLen(SB),NOSPLIT,$0
- MOVD x+0(FP), R2
- WORD $0xb9830022 // FLOGR R2,R2
- MOVD $64, R3
- SUB R2, R3
- MOVD R3, n+8(FP)
+ 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
new file mode 100644
index 0000000..31a777e
--- /dev/null
+++ b/src/math/big/arith_s390x_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.
+
+// +build s390x !math_big_pure_go
+
+package big
+
+import (
+ "testing"
+)
+
+// Tests whether the non vector routines are working, even when the tests are run on a
+// vector-capable machine
+
+func TestFunVVnovec(t *testing.T) {
+ if hasVX == true {
+ for _, a := range sumVV {
+ arg := a
+ testFunVV(t, "addVV_novec", addVV_novec, arg)
+
+ arg = argVV{a.z, a.y, a.x, a.c}
+ testFunVV(t, "addVV_novec symmetric", addVV_novec, arg)
+
+ arg = argVV{a.x, a.z, a.y, a.c}
+ testFunVV(t, "subVV_novec", subVV_novec, arg)
+
+ arg = argVV{a.y, a.z, a.x, a.c}
+ testFunVV(t, "subVV_novec symmetric", subVV_novec, arg)
+ }
+ }
+}
+
+func TestFunVWnovec(t *testing.T) {
+ if hasVX == true {
+ for _, a := range sumVW {
+ arg := a
+ testFunVW(t, "addVW_novec", addVW_novec, arg)
+
+ arg = argVW{a.x, a.z, a.y, a.c}
+ testFunVW(t, "subVW_novec", subVW_novec, arg)
+ }
+ }
+}
diff --git a/src/math/big/arith_test.go b/src/math/big/arith_test.go
index 75862b4..f2b3083 100644
--- a/src/math/big/arith_test.go
+++ b/src/math/big/arith_test.go
@@ -6,10 +6,14 @@ package big
import (
"fmt"
+ "internal/testenv"
"math/rand"
+ "strings"
"testing"
)
+var isRaceBuilder = strings.HasSuffix(testenv.Builder(), "-race")
+
type funWW func(x, y, c Word) (z1, z0 Word)
type argWW struct {
x, y, c, z1, z0 Word
@@ -123,6 +127,9 @@ var benchSizes = []int{1, 2, 3, 4, 5, 1e1, 1e2, 1e3, 1e4, 1e5}
func BenchmarkAddVV(b *testing.B) {
for _, n := range benchSizes {
+ if isRaceBuilder && n > 1e3 {
+ continue
+ }
x := rndV(n)
y := rndV(n)
z := make([]Word, n)
@@ -233,6 +240,9 @@ func TestFunVW(t *testing.T) {
func BenchmarkAddVW(b *testing.B) {
for _, n := range benchSizes {
+ if isRaceBuilder && n > 1e3 {
+ continue
+ }
x := rndV(n)
y := rndW()
z := make([]Word, n)
@@ -371,6 +381,9 @@ func TestMulAddWWW(t *testing.T) {
func BenchmarkAddMulVVW(b *testing.B) {
for _, n := range benchSizes {
+ if isRaceBuilder && n > 1e3 {
+ continue
+ }
x := rndV(n)
y := rndW()
z := make([]Word, n)
diff --git a/src/math/big/decimal.go b/src/math/big/decimal.go
index 2c0c9da..2dfa032 100644
--- a/src/math/big/decimal.go
+++ b/src/math/big/decimal.go
@@ -125,11 +125,12 @@ func shr(x *decimal, s uint) {
// read a digit, write a digit
w := 0 // write index
+ mask := Word(1)<<s - 1
for r < len(x.mant) {
ch := Word(x.mant[r])
r++
d := n >> s
- n -= d << s
+ n &= mask // n -= d << s
x.mant[w] = byte(d + '0')
w++
n = n*10 + ch - '0'
@@ -138,7 +139,7 @@ func shr(x *decimal, s uint) {
// write extra digits that still fit
for n > 0 && w < len(x.mant) {
d := n >> s
- n -= d << s
+ n &= mask
x.mant[w] = byte(d + '0')
w++
n = n * 10
@@ -148,7 +149,7 @@ func shr(x *decimal, s uint) {
// append additional digits that didn't fit
for n > 0 {
d := n >> s
- n -= d << s
+ n &= mask
x.mant = append(x.mant, byte(d+'0'))
n = n * 10
}
diff --git a/src/math/big/decimal_test.go b/src/math/big/decimal_test.go
index 15bdb18..424811e 100644
--- a/src/math/big/decimal_test.go
+++ b/src/math/big/decimal_test.go
@@ -4,7 +4,10 @@
package big
-import "testing"
+import (
+ "fmt"
+ "testing"
+)
func TestDecimalString(t *testing.T) {
for _, test := range []struct {
@@ -105,12 +108,27 @@ func TestDecimalRounding(t *testing.T) {
}
}
+var sink string
+
func BenchmarkDecimalConversion(b *testing.B) {
for i := 0; i < b.N; i++ {
for shift := -100; shift <= +100; shift++ {
var d decimal
d.init(natOne, shift)
- d.String()
+ sink = d.String()
}
}
}
+
+func BenchmarkFloatString(b *testing.B) {
+ x := new(Float)
+ for _, prec := range []uint{1e2, 1e3, 1e4, 1e5} {
+ x.SetPrec(prec).SetRat(NewRat(1, 3))
+ b.Run(fmt.Sprintf("%v", prec), func(b *testing.B) {
+ b.ReportAllocs()
+ for i := 0; i < b.N; i++ {
+ sink = x.String()
+ }
+ })
+ }
+}
diff --git a/src/math/big/doc.go b/src/math/big/doc.go
index a3c2375..65ed019 100644
--- a/src/math/big/doc.go
+++ b/src/math/big/doc.go
@@ -31,7 +31,7 @@ setters, for instance:
var z1 Int
z1.SetUint64(123) // z1 := 123
- z2 := new(Rat).SetFloat64(1.2) // z2 := 6/5
+ z2 := new(Rat).SetFloat64(1.25) // z2 := 5/4
z3 := new(Float).SetInt(z1) // z3 := 123.0
Setters, numeric operations and predicates are represented as methods of
diff --git a/src/math/big/example_test.go b/src/math/big/example_test.go
index ac79552..cfc7735 100644
--- a/src/math/big/example_test.go
+++ b/src/math/big/example_test.go
@@ -51,6 +51,19 @@ func ExampleInt_Scan() {
// Output: 18446744073709551617
}
+func ExampleFloat_Scan() {
+ // The Scan function is rarely used directly;
+ // the fmt package recognizes it as an implementation of fmt.Scanner.
+ f := new(big.Float)
+ _, err := fmt.Sscan("1.19282e99", f)
+ if err != nil {
+ log.Println("error scanning value:", err)
+ } else {
+ fmt.Println(f)
+ }
+ // Output: 1.19282e+99
+}
+
// This example demonstrates how to use big.Int to compute the smallest
// Fibonacci number with 100 decimal digits and to test whether it is prime.
func Example_fibonacci() {
diff --git a/src/math/big/float.go b/src/math/big/float.go
index 7a9c2b3..aabd7b4 100644
--- a/src/math/big/float.go
+++ b/src/math/big/float.go
@@ -1210,20 +1210,30 @@ func (z *Float) uadd(x, y *Float) {
ex := int64(x.exp) - int64(len(x.mant))*_W
ey := int64(y.exp) - int64(len(y.mant))*_W
+ al := alias(z.mant, x.mant) || alias(z.mant, y.mant)
+
// TODO(gri) having a combined add-and-shift primitive
// could make this code significantly faster
switch {
case ex < ey:
- // cannot re-use z.mant w/o testing for aliasing
- t := nat(nil).shl(y.mant, uint(ey-ex))
- z.mant = z.mant.add(x.mant, t)
+ if al {
+ t := nat(nil).shl(y.mant, uint(ey-ex))
+ z.mant = z.mant.add(x.mant, t)
+ } else {
+ z.mant = z.mant.shl(y.mant, uint(ey-ex))
+ z.mant = z.mant.add(x.mant, z.mant)
+ }
default:
// ex == ey, no shift needed
z.mant = z.mant.add(x.mant, y.mant)
case ex > ey:
- // cannot re-use z.mant w/o testing for aliasing
- t := nat(nil).shl(x.mant, uint(ex-ey))
- z.mant = z.mant.add(t, y.mant)
+ if al {
+ t := nat(nil).shl(x.mant, uint(ex-ey))
+ z.mant = z.mant.add(t, y.mant)
+ } else {
+ z.mant = z.mant.shl(x.mant, uint(ex-ey))
+ z.mant = z.mant.add(z.mant, y.mant)
+ }
ex = ey
}
// len(z.mant) > 0
@@ -1247,18 +1257,28 @@ func (z *Float) usub(x, y *Float) {
ex := int64(x.exp) - int64(len(x.mant))*_W
ey := int64(y.exp) - int64(len(y.mant))*_W
+ al := alias(z.mant, x.mant) || alias(z.mant, y.mant)
+
switch {
case ex < ey:
- // cannot re-use z.mant w/o testing for aliasing
- t := nat(nil).shl(y.mant, uint(ey-ex))
- z.mant = t.sub(x.mant, t)
+ if al {
+ t := nat(nil).shl(y.mant, uint(ey-ex))
+ z.mant = t.sub(x.mant, t)
+ } else {
+ z.mant = z.mant.shl(y.mant, uint(ey-ex))
+ z.mant = z.mant.sub(x.mant, z.mant)
+ }
default:
// ex == ey, no shift needed
z.mant = z.mant.sub(x.mant, y.mant)
case ex > ey:
- // cannot re-use z.mant w/o testing for aliasing
- t := nat(nil).shl(x.mant, uint(ex-ey))
- z.mant = t.sub(t, y.mant)
+ if al {
+ t := nat(nil).shl(x.mant, uint(ex-ey))
+ z.mant = t.sub(t, y.mant)
+ } else {
+ z.mant = z.mant.shl(x.mant, uint(ex-ey))
+ z.mant = z.mant.sub(z.mant, y.mant)
+ }
ex = ey
}
diff --git a/src/math/big/float_test.go b/src/math/big/float_test.go
index 464619b..7d4bd31 100644
--- a/src/math/big/float_test.go
+++ b/src/math/big/float_test.go
@@ -5,6 +5,7 @@
package big
import (
+ "flag"
"fmt"
"math"
"strconv"
@@ -1495,12 +1496,14 @@ func TestFloatQuo(t *testing.T) {
}
}
+var long = flag.Bool("long", false, "run very long tests")
+
// TestFloatQuoSmoke tests all divisions x/y for values x, y in the range [-n, +n];
// it serves as a smoke test for basic correctness of division.
func TestFloatQuoSmoke(t *testing.T) {
- n := 1000
- if testing.Short() {
- n = 10
+ n := 10
+ if *long {
+ n = 1000
}
const dprec = 3 // max. precision variation
@@ -1762,3 +1765,41 @@ func TestFloatCmpSpecialValues(t *testing.T) {
}
}
}
+
+func BenchmarkFloatAdd(b *testing.B) {
+ x := new(Float)
+ y := new(Float)
+ z := new(Float)
+
+ for _, prec := range []uint{10, 1e2, 1e3, 1e4, 1e5} {
+ x.SetPrec(prec).SetRat(NewRat(1, 3))
+ y.SetPrec(prec).SetRat(NewRat(1, 6))
+ z.SetPrec(prec)
+
+ b.Run(fmt.Sprintf("%v", prec), func(b *testing.B) {
+ b.ReportAllocs()
+ for i := 0; i < b.N; i++ {
+ z.Add(x, y)
+ }
+ })
+ }
+}
+
+func BenchmarkFloatSub(b *testing.B) {
+ x := new(Float)
+ y := new(Float)
+ z := new(Float)
+
+ for _, prec := range []uint{10, 1e2, 1e3, 1e4, 1e5} {
+ x.SetPrec(prec).SetRat(NewRat(1, 3))
+ y.SetPrec(prec).SetRat(NewRat(1, 6))
+ z.SetPrec(prec)
+
+ b.Run(fmt.Sprintf("%v", prec), func(b *testing.B) {
+ b.ReportAllocs()
+ for i := 0; i < b.N; i++ {
+ z.Sub(x, y)
+ }
+ })
+ }
+}
diff --git a/src/math/big/floatconv.go b/src/math/big/floatconv.go
index a884df6..95d1bf8 100644
--- a/src/math/big/floatconv.go
+++ b/src/math/big/floatconv.go
@@ -12,9 +12,13 @@ import (
"strings"
)
+var floatZero Float
+
// SetString sets z to the value of s and returns z and a boolean indicating
// success. s must be a floating-point number of the same format as accepted
-// by Parse, with base argument 0.
+// by Parse, with base argument 0. The entire string (not just a prefix) must
+// be valid for success. If the operation failed, the value of z is undefined
+// but the returned value is nil.
func (z *Float) SetString(s string) (*Float, bool) {
if f, _, err := z.Parse(s, 0); err == nil {
return f, true
@@ -212,17 +216,18 @@ func (z *Float) pow5(n uint64) *Float {
//
// It sets z to the (possibly rounded) value of the corresponding floating-
// point value, and returns z, the actual base b, and an error err, if any.
+// The entire string (not just a prefix) must be consumed for success.
// If z's precision is 0, it is changed to 64 before rounding takes effect.
// The number must be of the form:
//
// number = [ sign ] [ prefix ] mantissa [ exponent ] | infinity .
// sign = "+" | "-" .
-// prefix = "0" ( "x" | "X" | "b" | "B" ) .
+// prefix = "0" ( "x" | "X" | "b" | "B" ) .
// mantissa = digits | digits "." [ digits ] | "." digits .
// exponent = ( "E" | "e" | "p" ) [ sign ] digits .
// digits = digit { digit } .
// digit = "0" ... "9" | "a" ... "z" | "A" ... "Z" .
-// infinity = [ sign ] ( "inf" | "Inf" ) .
+// infinity = [ sign ] ( "inf" | "Inf" ) .
//
// The base argument must be 0, 2, 10, or 16. Providing an invalid base
// argument will lead to a run-time panic.
@@ -273,3 +278,16 @@ func (z *Float) Parse(s string, base int) (f *Float, b int, err error) {
func ParseFloat(s string, base int, prec uint, mode RoundingMode) (f *Float, b int, err error) {
return new(Float).SetPrec(prec).SetMode(mode).Parse(s, base)
}
+
+var _ fmt.Scanner = &floatZero // *Float must implement fmt.Scanner
+
+// Scan is a support routine for fmt.Scanner; it sets z to the value of
+// the scanned number. It accepts formats whose verbs are supported by
+// fmt.Scan for floating point values, which are:
+// 'b' (binary), 'e', 'E', 'f', 'F', 'g' and 'G'.
+// Scan doesn't handle ±Inf.
+func (z *Float) Scan(s fmt.ScanState, ch rune) error {
+ s.SkipSpace()
+ _, _, err := z.scan(byteReader{s}, 0)
+ return err
+}
diff --git a/src/math/big/floatconv_test.go b/src/math/big/floatconv_test.go
index b2a1ab0..edcb2eb 100644
--- a/src/math/big/floatconv_test.go
+++ b/src/math/big/floatconv_test.go
@@ -5,6 +5,7 @@
package big
import (
+ "bytes"
"fmt"
"math"
"strconv"
@@ -665,3 +666,54 @@ func BenchmarkParseFloatLargeExp(b *testing.B) {
}
}
}
+
+func TestFloatScan(t *testing.T) {
+ var floatScanTests = []struct {
+ input string
+ format string
+ output string
+ remaining int
+ wantErr bool
+ }{
+ 0: {"10.0", "%f", "10", 0, false},
+ 1: {"23.98+2.0", "%v", "23.98", 4, false},
+ 2: {"-1+1", "%v", "-1", 2, false},
+ 3: {" 00000", "%v", "0", 0, false},
+ 4: {"-123456p-78", "%b", "-4.084816388e-19", 0, false},
+ 5: {"+123", "%b", "123", 0, false},
+ 6: {"-1.234e+56", "%e", "-1.234e+56", 0, false},
+ 7: {"-1.234E-56", "%E", "-1.234e-56", 0, false},
+ 8: {"-1.234e+567", "%g", "-1.234e+567", 0, false},
+ 9: {"+1234567891011.234", "%G", "1.234567891e+12", 0, false},
+
+ // Scan doesn't handle ±Inf.
+ 10: {"Inf", "%v", "", 3, true},
+ 11: {"-Inf", "%v", "", 3, true},
+ 12: {"-Inf", "%v", "", 3, true},
+ }
+
+ var buf bytes.Buffer
+ for i, test := range floatScanTests {
+ x := new(Float)
+ buf.Reset()
+ buf.WriteString(test.input)
+ _, err := fmt.Fscanf(&buf, test.format, x)
+ if test.wantErr {
+ if err == nil {
+ t.Errorf("#%d want non-nil err", i)
+ }
+ continue
+ }
+
+ if err != nil {
+ t.Errorf("#%d error: %s", i, err)
+ }
+
+ if x.String() != test.output {
+ t.Errorf("#%d got %s; want %s", i, x.String(), test.output)
+ }
+ if buf.Len() != test.remaining {
+ t.Errorf("#%d got %d bytes remaining; want %d", i, buf.Len(), test.remaining)
+ }
+ }
+}
diff --git a/src/math/big/floatexample_test.go b/src/math/big/floatexample_test.go
index fb799d5..0c6668c 100644
--- a/src/math/big/floatexample_test.go
+++ b/src/math/big/floatexample_test.go
@@ -11,7 +11,7 @@ import (
)
func ExampleFloat_Add() {
- // Operating on numbers of different precision.
+ // Operate on numbers of different precision.
var x, y, z big.Float
x.SetInt64(1000) // x is automatically set to 64bit precision
y.SetFloat64(2.718281828) // y is automatically set to 53bit precision
@@ -26,8 +26,8 @@ func ExampleFloat_Add() {
// z = 1002.718282 (0x.faadf854p+10, prec = 32, acc = Below)
}
-func Example_Shift() {
- // Implementing Float "shift" by modifying the (binary) exponents directly.
+func ExampleFloat_shift() {
+ // Implement Float "shift" by modifying the (binary) exponents directly.
for s := -5; s <= 5; s++ {
x := big.NewFloat(0.5)
x.SetMantExp(x, x.MantExp(nil)+s) // shift x by s
diff --git a/src/math/big/floatmarsh.go b/src/math/big/floatmarsh.go
index 3725d4b..d1c1dab 100644
--- a/src/math/big/floatmarsh.go
+++ b/src/math/big/floatmarsh.go
@@ -16,7 +16,7 @@ const floatGobVersion byte = 1
// GobEncode implements the gob.GobEncoder interface.
// The Float value and all its attributes (precision,
-// rounding mode, accuracy) are marshalled.
+// rounding mode, accuracy) are marshaled.
func (x *Float) GobEncode() ([]byte, error) {
if x == nil {
return nil, nil
diff --git a/src/math/big/ftoa.go b/src/math/big/ftoa.go
index 57b16e1..d2a8588 100644
--- a/src/math/big/ftoa.go
+++ b/src/math/big/ftoa.go
@@ -376,6 +376,8 @@ func min(x, y int) int {
return y
}
+var _ fmt.Formatter = &floatZero // *Float must implement fmt.Formatter
+
// Format implements fmt.Formatter. It accepts all the regular
// formats for floating-point numbers ('b', 'e', 'E', 'f', 'F',
// 'g', 'G') as well as 'p' and 'v'. See (*Float).Text for the
diff --git a/src/math/big/gcd_test.go b/src/math/big/gcd_test.go
index a929bf5..3cca2ec 100644
--- a/src/math/big/gcd_test.go
+++ b/src/math/big/gcd_test.go
@@ -20,6 +20,9 @@ func randInt(r *rand.Rand, size uint) *Int {
}
func runGCD(b *testing.B, aSize, bSize uint) {
+ if isRaceBuilder && (aSize > 1000 || bSize > 1000) {
+ b.Skip("skipping on race builder")
+ }
b.Run("WithoutXY", func(b *testing.B) {
runGCDExt(b, aSize, bSize, false)
})
diff --git a/src/math/big/int.go b/src/math/big/int.go
index f2a75d1..a2c1b58 100644
--- a/src/math/big/int.go
+++ b/src/math/big/int.go
@@ -361,7 +361,8 @@ func (x *Int) Uint64() uint64 {
}
// SetString sets z to the value of s, interpreted in the given base,
-// and returns z and a boolean indicating success. If SetString fails,
+// and returns z and a boolean indicating success. The entire string
+// (not just a prefix) must be valid for success. If SetString fails,
// the value of z is undefined but the returned value is nil.
//
// The base argument must be 0 or a value between 2 and MaxBase. If the base
@@ -371,12 +372,11 @@ func (x *Int) Uint64() uint64 {
//
func (z *Int) SetString(s string, base int) (*Int, bool) {
r := strings.NewReader(s)
- _, _, err := z.scan(r, base)
- if err != nil {
+ if _, _, err := z.scan(r, base); err != nil {
return nil, false
}
- _, err = r.ReadByte()
- if err != io.EOF {
+ // entire string must have been consumed
+ if _, err := r.ReadByte(); err != io.EOF {
return nil, false
}
return z, true // err == io.EOF => scan consumed all of s
@@ -550,19 +550,6 @@ func (z *Int) binaryGCD(a, b *Int) *Int {
return z.Lsh(u, k)
}
-// ProbablyPrime performs n Miller-Rabin tests to check whether x is prime.
-// If x is prime, it returns true.
-// If x is not prime, it returns false with probability at least 1 - ¼ⁿ.
-//
-// It is not suitable for judging primes that an adversary may have crafted
-// to fool this test.
-func (x *Int) ProbablyPrime(n int) bool {
- if n <= 0 {
- panic("non-positive n for ProbablyPrime")
- }
- return !x.neg && x.abs.probablyPrime(n)
-}
-
// Rand sets z to a pseudo-random number in [0, n) and returns z.
func (z *Int) Rand(rnd *rand.Rand, n *Int) *Int {
z.neg = false
@@ -577,6 +564,11 @@ func (z *Int) Rand(rnd *rand.Rand, n *Int) *Int {
// ModInverse sets z to the multiplicative inverse of g in the ring ℤ/nℤ
// and returns z. If g and n are not relatively prime, the result is undefined.
func (z *Int) ModInverse(g, n *Int) *Int {
+ if g.neg {
+ // GCD expects parameters a and b to be > 0.
+ var g2 Int
+ g = g2.Mod(g, n)
+ }
var d Int
d.GCD(z, nil, g, n)
// x and y are such that g*x + n*y = d. Since g and n are
@@ -932,3 +924,14 @@ func (z *Int) Not(x *Int) *Int {
z.neg = true // z cannot be zero if x is positive
return z
}
+
+// Sqrt sets z to ⌊√x⌋, the largest integer such that z² ≤ x, and returns z.
+// It panics if x is negative.
+func (z *Int) Sqrt(x *Int) *Int {
+ if x.neg {
+ panic("square root of negative number")
+ }
+ z.neg = false
+ z.abs = z.abs.sqrt(x.abs)
+ return z
+}
diff --git a/src/math/big/int_test.go b/src/math/big/int_test.go
index 45a3765..b8e0778 100644
--- a/src/math/big/int_test.go
+++ b/src/math/big/int_test.go
@@ -9,6 +9,7 @@ import (
"encoding/hex"
"fmt"
"math/rand"
+ "strings"
"testing"
"testing/quick"
)
@@ -478,6 +479,18 @@ func TestQuoStepD6(t *testing.T) {
}
}
+func BenchmarkQuoRem(b *testing.B) {
+ x, _ := new(Int).SetString("153980389784927331788354528594524332344709972855165340650588877572729725338415474372475094155672066328274535240275856844648695200875763869073572078279316458648124537905600131008790701752441155668003033945258023841165089852359980273279085783159654751552359397986180318708491098942831252291841441726305535546071", 0)
+ y, _ := new(Int).SetString("7746362281539803897849273317883545285945243323447099728551653406505888775727297253384154743724750941556720663282745352402758568446486952008757638690735720782793164586481245379056001310087907017524411556680030339452580238411650898523599802732790857831596547515523593979861803187084910989428312522918414417263055355460715745539358014631136245887418412633787074173796862711588221766398229333338511838891484974940633857861775630560092874987828057333663969469797013996 [...]
+ q := new(Int)
+ r := new(Int)
+
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ q.QuoRem(y, x, r)
+ }
+}
+
var bitLenTests = []struct {
in string
out int
@@ -572,6 +585,19 @@ var expTests = []struct {
{"0xffffffffffffffff00000001", "0xffffffffffffffff00000001", "0xffffffffffffffff00000001", "0"},
{"0xffffffffffffffffffffffff00000001", "0xffffffffffffffffffffffff00000001", "0xffffffffffffffffffffffff00000001", "0"},
{"0xffffffffffffffffffffffffffffffff00000001", "0xffffffffffffffffffffffffffffffff00000001", "0xffffffffffffffffffffffffffffffff00000001", "0"},
+
+ {
+ "2",
+ "0xB08FFB20760FFED58FADA86DFEF71AD72AA0FA763219618FE022C197E54708BB1191C66470250FCE8879487507CEE41381CA4D932F81C2B3F1AB20B539D50DCD",
+ "0xAC6BDB41324A9A9BF166DE5E1389582FAF72B6651987EE07FC3192943DB56050A37329CBB4A099ED8193E0757767A13DD52312AB4B03310DCD7F48A9DA04FD50E8083969EDB767B0CF6095179A163AB3661A05FBD5FAAAE82918A9962F0B93B855F97993EC975EEAA80D740ADBF4FF747359D041D5C33EA71D281E446B14773BCA97B43A23FB801676BD207A436C6481F1D2B9078717461A5B9D32E688F87748544523B524B0D57D5EA77A2775D2ECFA032CFBDBF52FB3786160279004E57AE6AF874E7303CE53299CCC041C7BC308D82A5698F3A8D0C38271AE35F8E9DBFBB694B5C803D89F7AE435DE236D525F54759B65E37 [...]
+ "0x6AADD3E3E424D5B713FCAA8D8945B1E055166132038C57BBD2D51C833F0C5EA2007A2324CE514F8E8C2F008A2F36F44005A4039CB55830986F734C93DAF0EB4BAB54A6A8C7081864F44346E9BC6F0A3EB9F2C0146A00C6A05187D0C101E1F2D038CDB70CB5E9E05A2D188AB6CBB46286624D4415E7D4DBFAD3BCC6009D915C406EED38F468B940F41E6BEDC0430DD78E6F19A7DA3A27498A4181E24D738B0072D8F6ADB8C9809A5B033A09785814FD9919F6EF9F83EEA519BEC593855C4C10CBEEC582D4AE0792158823B0275E6AEC35242740468FAF3D5C60FD1E376362B6322F78B7ED0CA1C5BBCD2B49734A56C0967A1D01A [...]
+ },
+ {
+ "2",
+ "0xB08FFB20760FFED58FADA86DFEF71AD72AA0FA763219618FE022C197E54708BB1191C66470250FCE8879487507CEE41381CA4D932F81C2B3F1AB20B539D50DCD",
+ "0xAC6BDB41324A9A9BF166DE5E1389582FAF72B6651987EE07FC3192943DB56050A37329CBB4A099ED8193E0757767A13DD52312AB4B03310DCD7F48A9DA04FD50E8083969EDB767B0CF6095179A163AB3661A05FBD5FAAAE82918A9962F0B93B855F97993EC975EEAA80D740ADBF4FF747359D041D5C33EA71D281E446B14773BCA97B43A23FB801676BD207A436C6481F1D2B9078717461A5B9D32E688F87748544523B524B0D57D5EA77A2775D2ECFA032CFBDBF52FB3786160279004E57AE6AF874E7303CE53299CCC041C7BC308D82A5698F3A8D0C38271AE35F8E9DBFBB694B5C803D89F7AE435DE236D525F54759B65E37 [...]
+ "0x7858794B5897C29F4ED0B40913416AB6C48588484E6A45F2ED3E26C941D878E923575AAC434EE2750E6439A6976F9BB4D64CEDB2A53CE8D04DD48CADCDF8E46F22747C6B81C6CEA86C0D873FBF7CEF262BAAC43A522BD7F32F3CDAC52B9337C77B3DCFB3DB3EDD80476331E82F4B1DF8EFDC1220C92656DFC9197BDC1877804E28D928A2A284B8DED506CBA304435C9D0133C246C98A7D890D1DE60CBC53A024361DA83A9B8775019083D22AC6820ED7C3C68F8E801DD4EC779EE0A05C6EB682EF9840D285B838369BA7E148FA27691D524FAEAF7C6ECE2A4B99A294B9F2C241857B5B90CC8BFFCFCF18DFA7D676131D5CD3855 [...]
+ },
}
func TestExp(t *testing.T) {
@@ -614,6 +640,26 @@ func TestExp(t *testing.T) {
}
}
+func BenchmarkExp(b *testing.B) {
+ x, _ := new(Int).SetString("1100128911836308964601735937211796349925054637526904754277792800610324687668875673576090568060464662435319686957275262328514040875542037404931764642818527007955537276350311564605460286759366292389414094083747950719493426753283169456551646676502543490234831452562741851564658816095586283902205135365305294707313608478074272972787480345764384819749954829757002692692750250563429707952729900426776978076856569545994523558689262705917888499877298939750506120639545559 [...]
+ y, _ := new(Int).SetString("0xAC6BDB41324A9A9BF166DE5E1389582FAF72B6651987EE07FC3192943DB56050A37329CBB4A099ED8193E0757767A13DD52312AB4B03310DCD7F48A9DA04FD50E8083969EDB767B0CF6095179A163AB3661A05FBD5FAAAE82918A9962F0B93B855F97993EC975EEAA80D740ADBF4FF747359D041D5C33EA71D281E446B14773BCA97B43A23FB801676BD207A436C6481F1D2B9078717461A5B9D32E688F87748544523B524B0D57D5EA77A2775D2ECFA032CFBDBF52FB3786160279004E57AE6AF874E7303CE53299CCC041C7BC308D82A5698F3A8D0C38271AE35F8E9DBFBB694B5C803D89F7 [...]
+ n, _ := new(Int).SetString("0xAC6BDB41324A9A9BF166DE5E1389582FAF72B6651987EE07FC3192943DB56050A37329CBB4A099ED8193E0757767A13DD52312AB4B03310DCD7F48A9DA04FD50E8083969EDB767B0CF6095179A163AB3661A05FBD5FAAAE82918A9962F0B93B855F97993EC975EEAA80D740ADBF4FF747359D041D5C33EA71D281E446B14773BCA97B43A23FB801676BD207A436C6481F1D2B9078717461A5B9D32E688F87748544523B524B0D57D5EA77A2775D2ECFA032CFBDBF52FB3786160279004E57AE6AF874E7303CE53299CCC041C7BC308D82A5698F3A8D0C38271AE35F8E9DBFBB694B5C803D89F7 [...]
+ out := new(Int)
+ for i := 0; i < b.N; i++ {
+ out.Exp(x, y, n)
+ }
+}
+
+func BenchmarkExp2(b *testing.B) {
+ x, _ := new(Int).SetString("2", 0)
+ y, _ := new(Int).SetString("0xAC6BDB41324A9A9BF166DE5E1389582FAF72B6651987EE07FC3192943DB56050A37329CBB4A099ED8193E0757767A13DD52312AB4B03310DCD7F48A9DA04FD50E8083969EDB767B0CF6095179A163AB3661A05FBD5FAAAE82918A9962F0B93B855F97993EC975EEAA80D740ADBF4FF747359D041D5C33EA71D281E446B14773BCA97B43A23FB801676BD207A436C6481F1D2B9078717461A5B9D32E688F87748544523B524B0D57D5EA77A2775D2ECFA032CFBDBF52FB3786160279004E57AE6AF874E7303CE53299CCC041C7BC308D82A5698F3A8D0C38271AE35F8E9DBFBB694B5C803D89F7 [...]
+ n, _ := new(Int).SetString("0xAC6BDB41324A9A9BF166DE5E1389582FAF72B6651987EE07FC3192943DB56050A37329CBB4A099ED8193E0757767A13DD52312AB4B03310DCD7F48A9DA04FD50E8083969EDB767B0CF6095179A163AB3661A05FBD5FAAAE82918A9962F0B93B855F97993EC975EEAA80D740ADBF4FF747359D041D5C33EA71D281E446B14773BCA97B43A23FB801676BD207A436C6481F1D2B9078717461A5B9D32E688F87748544523B524B0D57D5EA77A2775D2ECFA032CFBDBF52FB3786160279004E57AE6AF874E7303CE53299CCC041C7BC308D82A5698F3A8D0C38271AE35F8E9DBFBB694B5C803D89F7 [...]
+ out := new(Int)
+ for i := 0; i < b.N; i++ {
+ out.Exp(x, y, n)
+ }
+}
+
func checkGcd(aBytes, bBytes []byte) bool {
x := new(Int)
y := new(Int)
@@ -715,85 +761,6 @@ func TestGcd(t *testing.T) {
}
}
-var primes = []string{
- "2",
- "3",
- "5",
- "7",
- "11",
-
- "13756265695458089029",
- "13496181268022124907",
- "10953742525620032441",
- "17908251027575790097",
-
- // https://golang.org/issue/638
- "18699199384836356663",
-
- "98920366548084643601728869055592650835572950932266967461790948584315647051443",
- "94560208308847015747498523884063394671606671904944666360068158221458669711639",
-
- // http://primes.utm.edu/lists/small/small3.html
- "449417999055441493994709297093108513015373787049558499205492347871729927573118262811508386655998299074566974373711472560655026288668094291699357843464363003144674940345912431129144354948751003607115263071543163",
- "230975859993204150666423538988557839555560243929065415434980904258310530753006723857139742334640122533598517597674807096648905501653461687601339782814316124971547968912893214002992086353183070342498989426570593",
- "5521712099665906221540423207019333379125265462121169655563495403888449493493629943498064604536961775110765377745550377067893607246020694972959780839151452457728855382113555867743022746090187341871655890805971735385789993",
- "203956878356401977405765866929034577280193993314348263094772646453283062722701277632936616063144088173312372882677123879538709400158306567338328279154499698366071906766440037074217117805690872792848149112022286332144876183376326512083574821647933992961249917319836219304274280243803104015000563790123",
-
- // ECC primes: http://tools.ietf.org/html/draft-ladd-safecurves-02
- "3618502788666131106986593281521497120414687020801267626233049500247285301239", // Curve1174: 2^251-9
- "57896044618658097711785492504343953926634992332820282019728792003956564819949", // Curve25519: 2^255-19
- "9850501549098619803069760025035903451269934817616361666987073351061430442874302652853566563721228910201656997576599", // E-382: 2^382-105
- "42307582002575910332922579714097346549017899709713998034217522897561970639123926132812109468141778230245837569601494931472367", // Curve41417: 2^414-17
- "6864797660130609714981900799081393217269435300143305409394463459185543183397656052122559640661454554977296311391480858037121987999716643812574028291115057151", // E-521: 2^521-1
-}
-
-var composites = []string{
- "0",
- "1",
- "21284175091214687912771199898307297748211672914763848041968395774954376176754",
- "6084766654921918907427900243509372380954290099172559290432744450051395395951",
- "84594350493221918389213352992032324280367711247940675652888030554255915464401",
- "82793403787388584738507275144194252681",
-}
-
-func TestProbablyPrime(t *testing.T) {
- nreps := 20
- if testing.Short() {
- nreps = 1
- }
- for i, s := range primes {
- p, _ := new(Int).SetString(s, 10)
- if !p.ProbablyPrime(nreps) {
- t.Errorf("#%d prime found to be non-prime (%s)", i, s)
- }
- }
-
- for i, s := range composites {
- c, _ := new(Int).SetString(s, 10)
- if c.ProbablyPrime(nreps) {
- t.Errorf("#%d composite found to be prime (%s)", i, s)
- }
- if testing.Short() {
- break
- }
- }
-
- // check that ProbablyPrime panics if n <= 0
- c := NewInt(11) // a prime
- for _, n := range []int{-1, 0, 1} {
- func() {
- defer func() {
- if n <= 0 && recover() == nil {
- t.Fatalf("expected panic from ProbablyPrime(%d)", n)
- }
- }()
- if !c.ProbablyPrime(n) {
- t.Fatalf("%v should be a prime", c)
- }
- }()
- }
-}
-
type intShiftTest struct {
in string
shift uint
@@ -1229,6 +1196,9 @@ func BenchmarkModSqrt224_3Mod4(b *testing.B) {
}
func BenchmarkModSqrt5430_Tonelli(b *testing.B) {
+ if isRaceBuilder {
+ b.Skip("skipping on race builder")
+ }
p := tri(5430)
x := new(Int).SetUint64(2)
for i := 0; i < b.N; i++ {
@@ -1238,6 +1208,9 @@ func BenchmarkModSqrt5430_Tonelli(b *testing.B) {
}
func BenchmarkModSqrt5430_3Mod4(b *testing.B) {
+ if isRaceBuilder {
+ b.Skip("skipping on race builder")
+ }
p := tri(5430)
x := new(Int).SetUint64(2)
for i := 0; i < b.N; i++ {
@@ -1303,6 +1276,7 @@ var modInverseTests = []struct {
}{
{"1234567", "458948883992"},
{"239487239847", "2410312426921032588552076022197566074856950548502459942654116941958108831682612228890093858261341614673227141477904012196503648957050582631942730706805009223062734745341073406696246014589361659774041027169249453200378729434170325843778659198143763193776859869524088940195577346119843545301547043747207749969763750084308926339295559968882457872412993810129130294592999947926365264059284647209730384947211681434464714438488520940127459844288859336526896320919633919"},
+ {"-10", "13"}, // issue #16984
}
func TestModInverse(t *testing.T) {
@@ -1480,3 +1454,44 @@ func TestIssue2607(t *testing.T) {
n := NewInt(10)
n.Rand(rand.New(rand.NewSource(9)), n)
}
+
+func TestSqrt(t *testing.T) {
+ root := 0
+ r := new(Int)
+ for i := 0; i < 10000; i++ {
+ if (root+1)*(root+1) <= i {
+ root++
+ }
+ n := NewInt(int64(i))
+ r.SetInt64(-2)
+ r.Sqrt(n)
+ if r.Cmp(NewInt(int64(root))) != 0 {
+ t.Errorf("Sqrt(%v) = %v, want %v", n, r, root)
+ }
+ }
+
+ for i := 0; i < 1000; i += 10 {
+ n, _ := new(Int).SetString("1"+strings.Repeat("0", i), 10)
+ r := new(Int).Sqrt(n)
+ root, _ := new(Int).SetString("1"+strings.Repeat("0", i/2), 10)
+ if r.Cmp(root) != 0 {
+ t.Errorf("Sqrt(1e%d) = %v, want 1e%d", i, r, i/2)
+ }
+ }
+
+ // Test aliasing.
+ r.SetInt64(100)
+ r.Sqrt(r)
+ if r.Int64() != 10 {
+ t.Errorf("Sqrt(100) = %v, want 10 (aliased output)", r.Int64())
+ }
+}
+
+func BenchmarkSqrt(b *testing.B) {
+ n, _ := new(Int).SetString("1"+strings.Repeat("0", 1001), 10)
+ b.ResetTimer()
+ t := new(Int)
+ for i := 0; i < b.N; i++ {
+ t.Sqrt(n)
+ }
+}
diff --git a/src/math/big/intconv.go b/src/math/big/intconv.go
index daf674a..91a62ce 100644
--- a/src/math/big/intconv.go
+++ b/src/math/big/intconv.go
@@ -52,6 +52,8 @@ func writeMultiple(s fmt.State, text string, count int) {
}
}
+var _ fmt.Formatter = intOne // *Int must implement fmt.Formatter
+
// Format implements fmt.Formatter. It accepts the formats
// 'b' (binary), 'o' (octal), 'd' (decimal), 'x' (lowercase
// hexadecimal), and 'X' (uppercase hexadecimal).
@@ -223,6 +225,8 @@ func (r byteReader) UnreadByte() error {
return r.UnreadRune()
}
+var _ fmt.Scanner = intOne // *Int must implement fmt.Scanner
+
// Scan is a support routine for fmt.Scanner; it sets z to the value of
// the scanned number. It accepts the formats 'b' (binary), 'o' (octal),
// 'd' (decimal), 'x' (lowercase hexadecimal), and 'X' (uppercase hexadecimal).
diff --git a/src/math/big/intmarsh.go b/src/math/big/intmarsh.go
index 4ff57b6..ee1e414 100644
--- a/src/math/big/intmarsh.go
+++ b/src/math/big/intmarsh.go
@@ -59,7 +59,7 @@ func (z *Int) UnmarshalText(text []byte) error {
return nil
}
-// The JSON marshallers are only here for API backward compatibility
+// The JSON marshalers are only here for API backward compatibility
// (programs that explicitly look for these two methods). JSON works
// fine with the TextMarshaler only.
@@ -70,5 +70,9 @@ func (x *Int) MarshalJSON() ([]byte, error) {
// UnmarshalJSON implements the json.Unmarshaler interface.
func (z *Int) UnmarshalJSON(text []byte) error {
+ // Ignore null, like in the main JSON package.
+ if string(text) == "null" {
+ return nil
+ }
return z.UnmarshalText(text)
}
diff --git a/src/math/big/nat.go b/src/math/big/nat.go
index 2e65d2a..9b1a626 100644
--- a/src/math/big/nat.go
+++ b/src/math/big/nat.go
@@ -542,16 +542,21 @@ func (z nat) div(z2, u, v nat) (q, r nat) {
return
}
-// getNat returns a nat of len n. The contents may not be zero.
-func getNat(n int) nat {
- var z nat
+// getNat returns a *nat of len n. The contents may not be zero.
+// The pool holds *nat to avoid allocation when converting to interface{}.
+func getNat(n int) *nat {
+ var z *nat
if v := natPool.Get(); v != nil {
- z = v.(nat)
+ z = v.(*nat)
}
- return z.make(n)
+ if z == nil {
+ z = new(nat)
+ }
+ *z = z.make(n)
+ return z
}
-func putNat(x nat) {
+func putNat(x *nat) {
natPool.Put(x)
}
@@ -575,7 +580,8 @@ func (z nat) divLarge(u, uIn, v nat) (q, r nat) {
}
q = z.make(m + 1)
- qhatv := getNat(n + 1)
+ qhatvp := getNat(n + 1)
+ qhatv := *qhatvp
if alias(u, uIn) || alias(u, v) {
u = nil // u is an alias for uIn or v - cannot reuse
}
@@ -583,36 +589,40 @@ func (z nat) divLarge(u, uIn, v nat) (q, r nat) {
u.clear() // TODO(gri) no need to clear if we allocated a new u
// D1.
- var v1 nat
+ var v1p *nat
shift := nlz(v[n-1])
if shift > 0 {
// do not modify v, it may be used by another goroutine simultaneously
- v1 = getNat(n)
+ v1p = getNat(n)
+ v1 := *v1p
shlVU(v1, v, shift)
v = v1
}
u[len(uIn)] = shlVU(u[0:len(uIn)], uIn, shift)
// D2.
+ vn1 := v[n-1]
for j := m; j >= 0; j-- {
// D3.
qhat := Word(_M)
- if u[j+n] != v[n-1] {
+ if ujn := u[j+n]; ujn != vn1 {
var rhat Word
- qhat, rhat = divWW(u[j+n], u[j+n-1], v[n-1])
+ qhat, rhat = divWW(ujn, u[j+n-1], vn1)
// x1 | x2 = q̂v_{n-2}
- x1, x2 := mulWW(qhat, v[n-2])
+ vn2 := v[n-2]
+ x1, x2 := mulWW(qhat, vn2)
// test if q̂v_{n-2} > br̂ + u_{j+n-2}
- for greaterThan(x1, x2, rhat, u[j+n-2]) {
+ ujn2 := u[j+n-2]
+ for greaterThan(x1, x2, rhat, ujn2) {
qhat--
prevRhat := rhat
- rhat += v[n-1]
+ rhat += vn1
// v[n-1] >= 0, so this tests for overflow.
if rhat < prevRhat {
break
}
- x1, x2 = mulWW(qhat, v[n-2])
+ x1, x2 = mulWW(qhat, vn2)
}
}
@@ -628,10 +638,10 @@ func (z nat) divLarge(u, uIn, v nat) (q, r nat) {
q[j] = qhat
}
- if v1 != nil {
- putNat(v1)
+ if v1p != nil {
+ putNat(v1p)
}
- putNat(qhatv)
+ putNat(qhatvp)
q = q.norm()
shrVU(u, u, shift)
@@ -650,14 +660,14 @@ func (x nat) bitLen() int {
const deBruijn32 = 0x077CB531
-var deBruijn32Lookup = []byte{
+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{
+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,
@@ -950,7 +960,7 @@ func (z nat) expNN(x, y, m nat) nat {
// (x^2...x^15) but then reduces the number of multiply-reduces by a
// third. Even for a 32-bit exponent, this reduces the number of
// operations. Uses Montgomery method for odd moduli.
- if len(x) > 1 && len(y) > 1 && len(m) > 0 {
+ if x.cmp(natOne) > 0 && len(y) > 1 && len(m) > 0 {
if m[0]&1 == 1 {
return z.expNNMontgomery(x, y, m)
}
@@ -1169,96 +1179,6 @@ func (z nat) expNNMontgomery(x, y, m nat) nat {
return zz.norm()
}
-// probablyPrime performs n Miller-Rabin tests to check whether x is prime.
-// If x is prime, it returns true.
-// If x is not prime, it returns false with probability at least 1 - ¼ⁿ.
-//
-// It is not suitable for judging primes that an adversary may have crafted
-// to fool this test.
-func (n nat) probablyPrime(reps int) bool {
- if len(n) == 0 {
- return false
- }
-
- if len(n) == 1 {
- if n[0] < 2 {
- return false
- }
-
- if n[0]%2 == 0 {
- return n[0] == 2
- }
-
- // We have to exclude these cases because we reject all
- // multiples of these numbers below.
- switch n[0] {
- case 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53:
- return true
- }
- }
-
- if n[0]&1 == 0 {
- return false // n is even
- }
-
- const primesProduct32 = 0xC0CFD797 // Π {p ∈ primes, 2 < p <= 29}
- const primesProduct64 = 0xE221F97C30E94E1D // Π {p ∈ primes, 2 < p <= 53}
-
- var r Word
- switch _W {
- case 32:
- r = n.modW(primesProduct32)
- case 64:
- r = n.modW(primesProduct64 & _M)
- default:
- panic("Unknown word size")
- }
-
- if r%3 == 0 || r%5 == 0 || r%7 == 0 || r%11 == 0 ||
- r%13 == 0 || r%17 == 0 || r%19 == 0 || r%23 == 0 || r%29 == 0 {
- return false
- }
-
- if _W == 64 && (r%31 == 0 || r%37 == 0 || r%41 == 0 ||
- r%43 == 0 || r%47 == 0 || r%53 == 0) {
- return false
- }
-
- nm1 := nat(nil).sub(n, natOne)
- // determine q, k such that nm1 = q << k
- k := nm1.trailingZeroBits()
- q := nat(nil).shr(nm1, k)
-
- nm3 := nat(nil).sub(nm1, natTwo)
- rand := rand.New(rand.NewSource(int64(n[0])))
-
- var x, y, quotient nat
- nm3Len := nm3.bitLen()
-
-NextRandom:
- for i := 0; i < reps; i++ {
- x = x.random(rand, nm3, nm3Len)
- x = x.add(x, natTwo)
- y = y.expNN(x, q, n)
- if y.cmp(natOne) == 0 || y.cmp(nm1) == 0 {
- continue
- }
- for j := uint(1); j < k; j++ {
- y = y.mul(y, y)
- quotient, y = quotient.div(y, y, n)
- if y.cmp(nm1) == 0 {
- continue NextRandom
- }
- if y.cmp(natOne) == 0 {
- return false
- }
- }
- return false
- }
-
- return true
-}
-
// bytes writes the value of z into buf using big-endian encoding.
// len(buf) must be >= len(z)*_S. The value of z is encoded in the
// slice buf[i:]. The number i of unused bytes at the beginning of
@@ -1303,3 +1223,37 @@ func (z nat) setBytes(buf []byte) nat {
return z.norm()
}
+
+// sqrt sets z = ⌊√x⌋
+func (z nat) sqrt(x nat) nat {
+ if x.cmp(natOne) <= 0 {
+ return z.set(x)
+ }
+ if alias(z, x) {
+ z = nil
+ }
+
+ // Start with value known to be too large and repeat "z = ⌊(z + ⌊x/z⌋)/2⌋" until it stops getting smaller.
+ // See Brent and Zimmermann, Modern Computer Arithmetic, Algorithm 1.13 (SqrtInt).
+ // https://members.loria.fr/PZimmermann/mca/pub226.html
+ // If x is one less than a perfect square, the sequence oscillates between the correct z and z+1;
+ // otherwise it converges to the correct z and stays there.
+ var z1, z2 nat
+ z1 = z
+ z1 = z1.setUint64(1)
+ z1 = z1.shl(z1, uint(x.bitLen()/2+1)) // must be ≥ √x
+ for n := 0; ; n++ {
+ z2, _ = z2.div(nil, x, z1)
+ z2 = z2.add(z2, z1)
+ z2 = z2.shr(z2, 1)
+ if z2.cmp(z1) >= 0 {
+ // z1 is answer.
+ // Figure out whether z1 or z2 is currently aliased to z by looking at loop count.
+ if n&1 == 0 {
+ return z1
+ }
+ return z.set(z1)
+ }
+ z1, z2 = z2, z1
+ }
+}
diff --git a/src/math/big/natconv_test.go b/src/math/big/natconv_test.go
index 79901d1..bdb60e6 100644
--- a/src/math/big/natconv_test.go
+++ b/src/math/big/natconv_test.go
@@ -278,6 +278,9 @@ func BenchmarkScan(b *testing.B) {
const x = 10
for _, base := range []int{2, 8, 10, 16} {
for _, y := range []Word{10, 100, 1000, 10000, 100000} {
+ if isRaceBuilder && y > 1000 {
+ continue
+ }
b.Run(fmt.Sprintf("%d/Base%d", y, base), func(b *testing.B) {
b.StopTimer()
var z nat
@@ -301,6 +304,9 @@ func BenchmarkString(b *testing.B) {
const x = 10
for _, base := range []int{2, 8, 10, 16} {
for _, y := range []Word{10, 100, 1000, 10000, 100000} {
+ if isRaceBuilder && y > 1000 {
+ continue
+ }
b.Run(fmt.Sprintf("%d/Base%d", y, base), func(b *testing.B) {
b.StopTimer()
var z nat
diff --git a/src/math/big/prime.go b/src/math/big/prime.go
new file mode 100644
index 0000000..3e9690e
--- /dev/null
+++ b/src/math/big/prime.go
@@ -0,0 +1,320 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package big
+
+import "math/rand"
+
+// ProbablyPrime reports whether x is probably prime,
+// applying the Miller-Rabin test with n pseudorandomly chosen bases
+// as well as a Baillie-PSW test.
+//
+// If x is prime, ProbablyPrime returns true.
+// If x is chosen randomly and not prime, ProbablyPrime probably returns false.
+// The probability of returning true for a randomly chosen non-prime is at most ¼ⁿ.
+//
+// ProbablyPrime is 100% accurate for inputs less than 2⁶⁴.
+// See Menezes et al., Handbook of Applied Cryptography, 1997, pp. 145-149,
+// and FIPS 186-4 Appendix F for further discussion of the error probabilities.
+//
+// ProbablyPrime is not suitable for judging primes that an adversary may
+// have crafted to fool the test.
+//
+// As of Go 1.8, ProbablyPrime(0) is allowed and applies only a Baillie-PSW test.
+// Before Go 1.8, ProbablyPrime applied only the Miller-Rabin tests, and ProbablyPrime(0) panicked.
+func (x *Int) ProbablyPrime(n int) bool {
+ // Note regarding the doc comment above:
+ // It would be more precise to say that the Baillie-PSW test uses the
+ // extra strong Lucas test as its Lucas test, but since no one knows
+ // how to tell any of the Lucas tests apart inside a Baillie-PSW test
+ // (they all work equally well empirically), that detail need not be
+ // documented or implicitly guaranteed.
+ // The comment does avoid saying "the" Baillie-PSW test
+ // because of this general ambiguity.
+
+ if n < 0 {
+ panic("negative n for ProbablyPrime")
+ }
+ if x.neg || len(x.abs) == 0 {
+ return false
+ }
+
+ // primeBitMask records the primes < 64.
+ const primeBitMask uint64 = 1<<2 | 1<<3 | 1<<5 | 1<<7 |
+ 1<<11 | 1<<13 | 1<<17 | 1<<19 | 1<<23 | 1<<29 | 1<<31 |
+ 1<<37 | 1<<41 | 1<<43 | 1<<47 | 1<<53 | 1<<59 | 1<<61
+
+ w := x.abs[0]
+ if len(x.abs) == 1 && w < 64 {
+ return primeBitMask&(1<<w) != 0
+ }
+
+ if w&1 == 0 {
+ return false // n is even
+ }
+
+ const primesA = 3 * 5 * 7 * 11 * 13 * 17 * 19 * 23 * 37
+ const primesB = 29 * 31 * 41 * 43 * 47 * 53
+
+ var rA, rB uint32
+ switch _W {
+ case 32:
+ rA = uint32(x.abs.modW(primesA))
+ rB = uint32(x.abs.modW(primesB))
+ case 64:
+ r := x.abs.modW((primesA * primesB) & _M)
+ rA = uint32(r % primesA)
+ rB = uint32(r % primesB)
+ default:
+ panic("math/big: invalid word size")
+ }
+
+ if rA%3 == 0 || rA%5 == 0 || rA%7 == 0 || rA%11 == 0 || rA%13 == 0 || rA%17 == 0 || rA%19 == 0 || rA%23 == 0 || rA%37 == 0 ||
+ rB%29 == 0 || rB%31 == 0 || rB%41 == 0 || rB%43 == 0 || rB%47 == 0 || rB%53 == 0 {
+ return false
+ }
+
+ return x.abs.probablyPrimeMillerRabin(n+1, true) && x.abs.probablyPrimeLucas()
+}
+
+// probablyPrimeMillerRabin reports whether n passes reps rounds of the
+// Miller-Rabin primality test, using pseudo-randomly chosen bases.
+// If force2 is true, one of the rounds is forced to use base 2.
+// See Handbook of Applied Cryptography, p. 139, Algorithm 4.24.
+// The number n is known to be non-zero.
+func (n nat) probablyPrimeMillerRabin(reps int, force2 bool) bool {
+ nm1 := nat(nil).sub(n, natOne)
+ // determine q, k such that nm1 = q << k
+ k := nm1.trailingZeroBits()
+ q := nat(nil).shr(nm1, k)
+
+ nm3 := nat(nil).sub(nm1, natTwo)
+ rand := rand.New(rand.NewSource(int64(n[0])))
+
+ var x, y, quotient nat
+ nm3Len := nm3.bitLen()
+
+NextRandom:
+ for i := 0; i < reps; i++ {
+ if i == reps-1 && force2 {
+ x = x.set(natTwo)
+ } else {
+ x = x.random(rand, nm3, nm3Len)
+ x = x.add(x, natTwo)
+ }
+ y = y.expNN(x, q, n)
+ if y.cmp(natOne) == 0 || y.cmp(nm1) == 0 {
+ continue
+ }
+ for j := uint(1); j < k; j++ {
+ y = y.mul(y, y)
+ quotient, y = quotient.div(y, y, n)
+ if y.cmp(nm1) == 0 {
+ continue NextRandom
+ }
+ if y.cmp(natOne) == 0 {
+ return false
+ }
+ }
+ return false
+ }
+
+ return true
+}
+
+// probablyPrimeLucas reports whether n passes the "almost extra strong" Lucas probable prime test,
+// using Baillie-OEIS parameter selection. This corresponds to "AESLPSP" on Jacobsen's tables (link below).
+// The combination of this test and a Miller-Rabin/Fermat test with base 2 gives a Baillie-PSW test.
+//
+// References:
+//
+// Baillie and Wagstaff, "Lucas Pseudoprimes", Mathematics of Computation 35(152),
+// October 1980, pp. 1391-1417, especially page 1401.
+// http://www.ams.org/journals/mcom/1980-35-152/S0025-5718-1980-0583518-6/S0025-5718-1980-0583518-6.pdf
+//
+// Grantham, "Frobenius Pseudoprimes", Mathematics of Computation 70(234),
+// March 2000, pp. 873-891.
+// http://www.ams.org/journals/mcom/2001-70-234/S0025-5718-00-01197-2/S0025-5718-00-01197-2.pdf
+//
+// Baillie, "Extra strong Lucas pseudoprimes", OEIS A217719, https://oeis.org/A217719.
+//
+// Jacobsen, "Pseudoprime Statistics, Tables, and Data", http://ntheory.org/pseudoprimes.html.
+//
+// Nicely, "The Baillie-PSW Primality Test", http://www.trnicely.net/misc/bpsw.html.
+// (Note that Nicely's definition of the "extra strong" test gives the wrong Jacobi condition,
+// as pointed out by Jacobsen.)
+//
+// Crandall and Pomerance, Prime Numbers: A Computational Perspective, 2nd ed.
+// Springer, 2005.
+func (n nat) probablyPrimeLucas() bool {
+ // Discard 0, 1.
+ if len(n) == 0 || n.cmp(natOne) == 0 {
+ return false
+ }
+ // Two is the only even prime.
+ // Already checked by caller, but here to allow testing in isolation.
+ if n[0]&1 == 0 {
+ return n.cmp(natTwo) == 0
+ }
+
+ // Baillie-OEIS "method C" for choosing D, P, Q,
+ // as in https://oeis.org/A217719/a217719.txt:
+ // try increasing P ≥ 3 such that D = P² - 4 (so Q = 1)
+ // until Jacobi(D, n) = -1.
+ // The search is expected to succeed for non-square n after just a few trials.
+ // After more than expected failures, check whether n is square
+ // (which would cause Jacobi(D, n) = 1 for all D not dividing n).
+ p := Word(3)
+ d := nat{1}
+ t1 := nat(nil) // temp
+ intD := &Int{abs: d}
+ intN := &Int{abs: n}
+ for ; ; p++ {
+ if p > 10000 {
+ // This is widely believed to be impossible.
+ // If we get a report, we'll want the exact number n.
+ panic("math/big: internal error: cannot find (D/n) = -1 for " + intN.String())
+ }
+ d[0] = p*p - 4
+ j := Jacobi(intD, intN)
+ if j == -1 {
+ break
+ }
+ if j == 0 {
+ // d = p²-4 = (p-2)(p+2).
+ // If (d/n) == 0 then d shares a prime factor with n.
+ // Since the loop proceeds in increasing p and starts with p-2==1,
+ // the shared prime factor must be p+2.
+ // If p+2 == n, then n is prime; otherwise p+2 is a proper factor of n.
+ return len(n) == 1 && n[0] == p+2
+ }
+ if p == 40 {
+ // We'll never find (d/n) = -1 if n is a square.
+ // If n is a non-square we expect to find a d in just a few attempts on average.
+ // After 40 attempts, take a moment to check if n is indeed a square.
+ t1 = t1.sqrt(n)
+ t1 = t1.mul(t1, t1)
+ if t1.cmp(n) == 0 {
+ return false
+ }
+ }
+ }
+
+ // Grantham definition of "extra strong Lucas pseudoprime", after Thm 2.3 on p. 876
+ // (D, P, Q above have become Δ, b, 1):
+ //
+ // Let U_n = U_n(b, 1), V_n = V_n(b, 1), and Δ = b²-4.
+ // An extra strong Lucas pseudoprime to base b is a composite n = 2^r s + Jacobi(Δ, n),
+ // where s is odd and gcd(n, 2*Δ) = 1, such that either (i) U_s ≡ 0 mod n and V_s ≡ ±2 mod n,
+ // or (ii) V_{2^t s} ≡ 0 mod n for some 0 ≤ t < r-1.
+ //
+ // We know gcd(n, Δ) = 1 or else we'd have found Jacobi(d, n) == 0 above.
+ // We know gcd(n, 2) = 1 because n is odd.
+ //
+ // Arrange s = (n - Jacobi(Δ, n)) / 2^r = (n+1) / 2^r.
+ s := nat(nil).add(n, natOne)
+ r := int(s.trailingZeroBits())
+ s = s.shr(s, uint(r))
+ nm2 := nat(nil).sub(n, natTwo) // n-2
+
+ // We apply the "almost extra strong" test, which checks the above conditions
+ // except for U_s ≡ 0 mod n, which allows us to avoid computing any U_k values.
+ // Jacobsen points out that maybe we should just do the full extra strong test:
+ // "It is also possible to recover U_n using Crandall and Pomerance equation 3.13:
+ // U_n = D^-1 (2V_{n+1} - PV_n) allowing us to run the full extra-strong test
+ // at the cost of a single modular inversion. This computation is easy and fast in GMP,
+ // so we can get the full extra-strong test at essentially the same performance as the
+ // almost extra strong test."
+
+ // Compute Lucas sequence V_s(b, 1), where:
+ //
+ // V(0) = 2
+ // V(1) = P
+ // V(k) = P V(k-1) - Q V(k-2).
+ //
+ // (Remember that due to method C above, P = b, Q = 1.)
+ //
+ // In general V(k) = α^k + β^k, where α and β are roots of x² - Px + Q.
+ // Crandall and Pomerance (p.147) observe that for 0 ≤ j ≤ k,
+ //
+ // V(j+k) = V(j)V(k) - V(k-j).
+ //
+ // So in particular, to quickly double the subscript:
+ //
+ // V(2k) = V(k)² - 2
+ // V(2k+1) = V(k) V(k+1) - P
+ //
+ // We can therefore start with k=0 and build up to k=s in log₂(s) steps.
+ natP := nat(nil).setWord(p)
+ vk := nat(nil).setWord(2)
+ vk1 := nat(nil).setWord(p)
+ t2 := nat(nil) // temp
+ for i := int(s.bitLen()); i >= 0; i-- {
+ if s.bit(uint(i)) != 0 {
+ // k' = 2k+1
+ // V(k') = V(2k+1) = V(k) V(k+1) - P.
+ t1 = t1.mul(vk, vk1)
+ t1 = t1.add(t1, n)
+ t1 = t1.sub(t1, natP)
+ t2, vk = t2.div(vk, t1, n)
+ // V(k'+1) = V(2k+2) = V(k+1)² - 2.
+ t1 = t1.mul(vk1, vk1)
+ t1 = t1.add(t1, nm2)
+ t2, vk1 = t2.div(vk1, t1, n)
+ } else {
+ // k' = 2k
+ // V(k'+1) = V(2k+1) = V(k) V(k+1) - P.
+ t1 = t1.mul(vk, vk1)
+ t1 = t1.add(t1, n)
+ t1 = t1.sub(t1, natP)
+ t2, vk1 = t2.div(vk1, t1, n)
+ // V(k') = V(2k) = V(k)² - 2
+ t1 = t1.mul(vk, vk)
+ t1 = t1.add(t1, nm2)
+ t2, vk = t2.div(vk, t1, n)
+ }
+ }
+
+ // Now k=s, so vk = V(s). Check V(s) ≡ ±2 (mod n).
+ if vk.cmp(natTwo) == 0 || vk.cmp(nm2) == 0 {
+ // Check U(s) ≡ 0.
+ // As suggested by Jacobsen, apply Crandall and Pomerance equation 3.13:
+ //
+ // U(k) = D⁻¹ (2 V(k+1) - P V(k))
+ //
+ // Since we are checking for U(k) == 0 it suffices to check 2 V(k+1) == P V(k) mod n,
+ // or P V(k) - 2 V(k+1) == 0 mod n.
+ t1 := t1.mul(vk, natP)
+ t2 := t2.shl(vk1, 1)
+ if t1.cmp(t2) < 0 {
+ t1, t2 = t2, t1
+ }
+ t1 = t1.sub(t1, t2)
+ t3 := vk1 // steal vk1, no longer needed below
+ vk1 = nil
+ _ = vk1
+ t2, t3 = t2.div(t3, t1, n)
+ if len(t3) == 0 {
+ return true
+ }
+ }
+
+ // Check V(2^t s) ≡ 0 mod n for some 0 ≤ t < r-1.
+ for t := 0; t < r-1; t++ {
+ if len(vk) == 0 { // vk == 0
+ return true
+ }
+ // Optimization: V(k) = 2 is a fixed point for V(k') = V(k)² - 2,
+ // so if V(k) = 2, we can stop: we will never find a future V(k) == 0.
+ if len(vk) == 1 && vk[0] == 2 { // vk == 2
+ return false
+ }
+ // k' = 2k
+ // V(k') = V(2k) = V(k)² - 2
+ t1 = t1.mul(vk, vk)
+ t1 = t1.sub(t1, natTwo)
+ t2, vk = t2.div(vk, t1, n)
+ }
+ return false
+}
diff --git a/src/math/big/prime_test.go b/src/math/big/prime_test.go
new file mode 100644
index 0000000..a2d3d18
--- /dev/null
+++ b/src/math/big/prime_test.go
@@ -0,0 +1,214 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package big
+
+import (
+ "fmt"
+ "strings"
+ "testing"
+ "unicode"
+)
+
+var primes = []string{
+ "2",
+ "3",
+ "5",
+ "7",
+ "11",
+
+ "13756265695458089029",
+ "13496181268022124907",
+ "10953742525620032441",
+ "17908251027575790097",
+
+ // https://golang.org/issue/638
+ "18699199384836356663",
+
+ "98920366548084643601728869055592650835572950932266967461790948584315647051443",
+ "94560208308847015747498523884063394671606671904944666360068158221458669711639",
+
+ // http://primes.utm.edu/lists/small/small3.html
+ "449417999055441493994709297093108513015373787049558499205492347871729927573118262811508386655998299074566974373711472560655026288668094291699357843464363003144674940345912431129144354948751003607115263071543163",
+ "230975859993204150666423538988557839555560243929065415434980904258310530753006723857139742334640122533598517597674807096648905501653461687601339782814316124971547968912893214002992086353183070342498989426570593",
+ "5521712099665906221540423207019333379125265462121169655563495403888449493493629943498064604536961775110765377745550377067893607246020694972959780839151452457728855382113555867743022746090187341871655890805971735385789993",
+ "203956878356401977405765866929034577280193993314348263094772646453283062722701277632936616063144088173312372882677123879538709400158306567338328279154499698366071906766440037074217117805690872792848149112022286332144876183376326512083574821647933992961249917319836219304274280243803104015000563790123",
+
+ // ECC primes: http://tools.ietf.org/html/draft-ladd-safecurves-02
+ "3618502788666131106986593281521497120414687020801267626233049500247285301239", // Curve1174: 2^251-9
+ "57896044618658097711785492504343953926634992332820282019728792003956564819949", // Curve25519: 2^255-19
+ "9850501549098619803069760025035903451269934817616361666987073351061430442874302652853566563721228910201656997576599", // E-382: 2^382-105
+ "42307582002575910332922579714097346549017899709713998034217522897561970639123926132812109468141778230245837569601494931472367", // Curve41417: 2^414-17
+ "6864797660130609714981900799081393217269435300143305409394463459185543183397656052122559640661454554977296311391480858037121987999716643812574028291115057151", // E-521: 2^521-1
+}
+
+var composites = []string{
+ "0",
+ "1",
+ "21284175091214687912771199898307297748211672914763848041968395774954376176754",
+ "6084766654921918907427900243509372380954290099172559290432744450051395395951",
+ "84594350493221918389213352992032324280367711247940675652888030554255915464401",
+ "82793403787388584738507275144194252681",
+
+ // Arnault, "Rabin-Miller Primality Test: Composite Numbers Which Pass It",
+ // Mathematics of Computation, 64(209) (January 1995), pp. 335-361.
+ "1195068768795265792518361315725116351898245581", // strong pseudoprime to prime bases 2 through 29
+ // strong pseudoprime to all prime bases up to 200
+ `
+ 80383745745363949125707961434194210813883768828755814583748891752229
+ 74273765333652186502336163960045457915042023603208766569966760987284
+ 0439654082329287387918508691668573282677617710293896977394701670823
+ 0428687109997439976544144845341155872450633409279022275296229414984
+ 2306881685404326457534018329786111298960644845216191652872597534901`,
+
+ // Extra-strong Lucas pseudoprimes. https://oeis.org/A217719
+ "989",
+ "3239",
+ "5777",
+ "10877",
+ "27971",
+ "29681",
+ "30739",
+ "31631",
+ "39059",
+ "72389",
+ "73919",
+ "75077",
+ "100127",
+ "113573",
+ "125249",
+ "137549",
+ "137801",
+ "153931",
+ "155819",
+ "161027",
+ "162133",
+ "189419",
+ "218321",
+ "231703",
+ "249331",
+ "370229",
+ "429479",
+ "430127",
+ "459191",
+ "473891",
+ "480689",
+ "600059",
+ "621781",
+ "632249",
+ "635627",
+
+ "3673744903",
+ "3281593591",
+ "2385076987",
+ "2738053141",
+ "2009621503",
+ "1502682721",
+ "255866131",
+ "117987841",
+ "587861",
+
+ "6368689",
+ "8725753",
+ "80579735209",
+ "105919633",
+}
+
+func cutSpace(r rune) rune {
+ if unicode.IsSpace(r) {
+ return -1
+ }
+ return r
+}
+
+func TestProbablyPrime(t *testing.T) {
+ nreps := 20
+ if testing.Short() {
+ nreps = 3
+ }
+ for i, s := range primes {
+ p, _ := new(Int).SetString(s, 10)
+ if !p.ProbablyPrime(nreps) || !p.ProbablyPrime(1) || !p.ProbablyPrime(0) {
+ t.Errorf("#%d prime found to be non-prime (%s)", i, s)
+ }
+ }
+
+ for i, s := range composites {
+ s = strings.Map(cutSpace, s)
+ c, _ := new(Int).SetString(s, 10)
+ if c.ProbablyPrime(nreps) || c.ProbablyPrime(1) || c.ProbablyPrime(0) {
+ t.Errorf("#%d composite found to be prime (%s)", i, s)
+ }
+ }
+
+ // check that ProbablyPrime panics if n <= 0
+ c := NewInt(11) // a prime
+ for _, n := range []int{-1, 0, 1} {
+ func() {
+ defer func() {
+ if n < 0 && recover() == nil {
+ t.Fatalf("expected panic from ProbablyPrime(%d)", n)
+ }
+ }()
+ if !c.ProbablyPrime(n) {
+ t.Fatalf("%v should be a prime", c)
+ }
+ }()
+ }
+}
+
+func BenchmarkProbablyPrime(b *testing.B) {
+ p, _ := new(Int).SetString("203956878356401977405765866929034577280193993314348263094772646453283062722701277632936616063144088173312372882677123879538709400158306567338328279154499698366071906766440037074217117805690872792848149112022286332144876183376326512083574821647933992961249917319836219304274280243803104015000563790123", 10)
+ for _, n := range []int{0, 1, 5, 10, 20} {
+ b.Run(fmt.Sprintf("n=%d", n), func(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ p.ProbablyPrime(n)
+ }
+ })
+ }
+
+ b.Run("Lucas", func(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ p.abs.probablyPrimeLucas()
+ }
+ })
+ b.Run("MillerRabinBase2", func(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ p.abs.probablyPrimeMillerRabin(1, true)
+ }
+ })
+}
+
+func TestMillerRabinPseudoprimes(t *testing.T) {
+ testPseudoprimes(t, "probablyPrimeMillerRabin",
+ func(n nat) bool { return n.probablyPrimeMillerRabin(1, true) && !n.probablyPrimeLucas() },
+ // https://oeis.org/A001262
+ []int{2047, 3277, 4033, 4681, 8321, 15841, 29341, 42799, 49141, 52633, 65281, 74665, 80581, 85489, 88357, 90751})
+}
+
+func TestLucasPseudoprimes(t *testing.T) {
+ testPseudoprimes(t, "probablyPrimeLucas",
+ func(n nat) bool { return n.probablyPrimeLucas() && !n.probablyPrimeMillerRabin(1, true) },
+ // https://oeis.org/A217719
+ []int{989, 3239, 5777, 10877, 27971, 29681, 30739, 31631, 39059, 72389, 73919, 75077})
+}
+
+func testPseudoprimes(t *testing.T, name string, cond func(nat) bool, want []int) {
+ n := nat{1}
+ for i := 3; i < 100000; i += 2 {
+ 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)
+ } else if !pseudo && len(want) >= 1 && i == want[0] {
+ t.Errorf("%s(%v, base=2) = false, want true", name, i)
+ }
+ if len(want) > 0 && i == want[0] {
+ want = want[1:]
+ }
+ }
+ if len(want) > 0 {
+ t.Fatalf("forgot to test %v", want)
+ }
+}
diff --git a/src/math/big/rat_test.go b/src/math/big/rat_test.go
index 3a06fca..afda686 100644
--- a/src/math/big/rat_test.go
+++ b/src/math/big/rat_test.go
@@ -382,9 +382,9 @@ func TestFloat32Distribution(t *testing.T) {
9,
11,
}
- var winc, einc = uint64(1), 1 // soak test (~1.5s on x86-64)
- if testing.Short() {
- winc, einc = 5, 15 // quick test (~60ms on x86-64)
+ var winc, einc = uint64(5), 15 // quick test (~60ms on x86-64)
+ if *long {
+ winc, einc = uint64(1), 1 // soak test (~1.5s on x86-64)
}
for _, sign := range "+-" {
@@ -430,9 +430,9 @@ func TestFloat64Distribution(t *testing.T) {
9,
11,
}
- var winc, einc = uint64(1), 1 // soak test (~75s on x86-64)
- if testing.Short() {
- winc, einc = 10, 500 // quick test (~12ms on x86-64)
+ var winc, einc = uint64(10), 500 // quick test (~12ms on x86-64)
+ if *long {
+ winc, einc = uint64(1), 1 // soak test (~75s on x86-64)
}
for _, sign := range "+-" {
diff --git a/src/math/big/ratconv.go b/src/math/big/ratconv.go
index ef2b675..a6a401c 100644
--- a/src/math/big/ratconv.go
+++ b/src/math/big/ratconv.go
@@ -18,6 +18,9 @@ func ratTok(ch rune) bool {
return strings.ContainsRune("+-/0123456789.eE", ch)
}
+var ratZero Rat
+var _ fmt.Scanner = &ratZero // *Rat must implement fmt.Scanner
+
// Scan is a support routine for fmt.Scanner. It accepts the formats
// 'e', 'E', 'f', 'F', 'g', 'G', and 'v'. All formats are equivalent.
func (z *Rat) Scan(s fmt.ScanState, ch rune) error {
@@ -36,8 +39,9 @@ func (z *Rat) Scan(s fmt.ScanState, ch rune) error {
// SetString sets z to the value of s and returns z and a boolean indicating
// success. s can be given as a fraction "a/b" or as a floating-point number
-// optionally followed by an exponent. If the operation failed, the value of
-// z is undefined but the returned value is nil.
+// optionally followed by an exponent. The entire string (not just a prefix)
+// must be valid for success. If the operation failed, the value of z is un-
+// defined but the returned value is nil.
func (z *Rat) SetString(s string) (*Rat, bool) {
if len(s) == 0 {
return nil, false
@@ -49,9 +53,13 @@ func (z *Rat) SetString(s string) (*Rat, bool) {
if _, ok := z.a.SetString(s[:sep], 0); !ok {
return nil, false
}
- s = s[sep+1:]
+ r := strings.NewReader(s[sep+1:])
var err error
- if z.b.abs, _, _, err = z.b.abs.scan(strings.NewReader(s), 0, false); err != nil {
+ if z.b.abs, _, _, err = z.b.abs.scan(r, 0, false); err != nil {
+ return nil, false
+ }
+ // entire string must have been consumed
+ if _, err = r.ReadByte(); err != io.EOF {
return nil, false
}
if len(z.b.abs) == 0 {
diff --git a/src/math/big/ratconv_test.go b/src/math/big/ratconv_test.go
index 35ad6cc..56ac8d7 100644
--- a/src/math/big/ratconv_test.go
+++ b/src/math/big/ratconv_test.go
@@ -50,6 +50,10 @@ var setStringTests = []StringTest{
{"204211327800791583.81095", "4084226556015831676219/20000", true},
{"0e9999999999", "0", true}, // issue #16176
{in: "1/0"},
+ {in: "4/3/2"}, // issue 17001
+ {in: "4/3/"},
+ {in: "4/3."},
+ {in: "4/"},
}
// These are not supported by fmt.Fscanf.
@@ -59,6 +63,7 @@ var setStringTests2 = []StringTest{
{"-010.", "-10", true},
{"0x10/0x20", "1/2", true},
{"0b1000/3", "8/3", true},
+ {in: "4/3x"},
// TODO(gri) add more tests
}
@@ -139,7 +144,7 @@ func TestFloatString(t *testing.T) {
}
// Test inputs to Rat.SetString. The prefix "long:" causes the test
-// to be skipped in --test.short mode. (The threshold is about 500us.)
+// to be skipped except in -long mode. (The threshold is about 500us.)
var float64inputs = []string{
// Constants plundered from strconv/testfp.txt.
@@ -345,7 +350,7 @@ func isFinite(f float64) bool {
func TestFloat32SpecialCases(t *testing.T) {
for _, input := range float64inputs {
if strings.HasPrefix(input, "long:") {
- if testing.Short() {
+ if !*long {
continue
}
input = input[len("long:"):]
@@ -401,7 +406,7 @@ func TestFloat32SpecialCases(t *testing.T) {
func TestFloat64SpecialCases(t *testing.T) {
for _, input := range float64inputs {
if strings.HasPrefix(input, "long:") {
- if testing.Short() {
+ if !*long {
continue
}
input = input[len("long:"):]
diff --git a/src/math/cmplx/cmath_test.go b/src/math/cmplx/cmath_test.go
index d904be8..7a5c485 100644
--- a/src/math/cmplx/cmath_test.go
+++ b/src/math/cmplx/cmath_test.go
@@ -759,6 +759,14 @@ func TestTanh(t *testing.T) {
}
}
+// See issue 17577
+func TestInfiniteLoopIntanSeries(t *testing.T) {
+ want := Inf()
+ if got := Cot(0); got != want {
+ t.Errorf("Cot(0): got %g, want %g", got, want)
+ }
+}
+
func BenchmarkAbs(b *testing.B) {
for i := 0; i < b.N; i++ {
Abs(complex(2.5, 3.5))
diff --git a/src/math/cmplx/example_test.go b/src/math/cmplx/example_test.go
new file mode 100644
index 0000000..f0ed963
--- /dev/null
+++ b/src/math/cmplx/example_test.go
@@ -0,0 +1,28 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cmplx_test
+
+import (
+ "fmt"
+ "math"
+ "math/cmplx"
+)
+
+func ExampleAbs() {
+ fmt.Printf("%.1f", cmplx.Abs(3+4i))
+ // Output: 5.0
+}
+
+// ExampleExp computes Euler's identity.
+func ExampleExp() {
+ fmt.Printf("%.1f", cmplx.Exp(1i*math.Pi)+1)
+ // Output: (0.0+0.0i)
+}
+
+func ExamplePolar() {
+ r, theta := cmplx.Polar(2i)
+ fmt.Printf("r: %.1f, θ: %.1f*π", r, theta/math.Pi)
+ // Output: r: 2.0, θ: 0.5*π
+}
diff --git a/src/math/cmplx/tan.go b/src/math/cmplx/tan.go
index 9485315..2990552 100644
--- a/src/math/cmplx/tan.go
+++ b/src/math/cmplx/tan.go
@@ -120,9 +120,9 @@ func tanSeries(z complex128) float64 {
rn := 0.0
d := 0.0
for {
- rn += 1
+ rn++
f *= rn
- rn += 1
+ rn++
f *= rn
x2 *= x
y2 *= y
@@ -130,16 +130,18 @@ func tanSeries(z complex128) float64 {
t /= f
d += t
- rn += 1
+ rn++
f *= rn
- rn += 1
+ rn++
f *= rn
x2 *= x
y2 *= y
t = y2 - x2
t /= f
d += t
- if math.Abs(t/d) <= MACHEP {
+ if !(math.Abs(t/d) > MACHEP) {
+ // Caution: Use ! and > instead of <= for correct behavior if t/d is NaN.
+ // See issue 17577.
break
}
}
diff --git a/src/math/cosh_s390x.s b/src/math/cosh_s390x.s
new file mode 100644
index 0000000..d061bd0
--- /dev/null
+++ b/src/math/cosh_s390x.s
@@ -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.
+
+#include "textflag.h"
+
+// Constants
+DATA coshrodataL23<>+0(SB)/8, $0.231904681384629956E-16
+DATA coshrodataL23<>+8(SB)/8, $0.693147180559945286E+00
+DATA coshrodataL23<>+16(SB)/8, $0.144269504088896339E+01
+DATA coshrodataL23<>+24(SB)/8, $704.E0
+GLOBL coshrodataL23<>+0(SB), RODATA, $32
+DATA coshxinf<>+0(SB)/8, $0x7FF0000000000000
+GLOBL coshxinf<>+0(SB), RODATA, $8
+DATA coshxlim1<>+0(SB)/8, $800.E0
+GLOBL coshxlim1<>+0(SB), RODATA, $8
+DATA coshxaddhy<>+0(SB)/8, $0xc2f0000100003fdf
+GLOBL coshxaddhy<>+0(SB), RODATA, $8
+DATA coshx4ff<>+0(SB)/8, $0x4ff0000000000000
+GLOBL coshx4ff<>+0(SB), RODATA, $8
+DATA coshe1<>+0(SB)/8, $0x3ff000000000000a
+GLOBL coshe1<>+0(SB), RODATA, $8
+
+// Log multiplier table
+DATA coshtab<>+0(SB)/8, $0.442737824274138381E-01
+DATA coshtab<>+8(SB)/8, $0.263602189790660309E-01
+DATA coshtab<>+16(SB)/8, $0.122565642281703586E-01
+DATA coshtab<>+24(SB)/8, $0.143757052860721398E-02
+DATA coshtab<>+32(SB)/8, $-.651375034121276075E-02
+DATA coshtab<>+40(SB)/8, $-.119317678849450159E-01
+DATA coshtab<>+48(SB)/8, $-.150868749549871069E-01
+DATA coshtab<>+56(SB)/8, $-.161992609578469234E-01
+DATA coshtab<>+64(SB)/8, $-.154492360403337917E-01
+DATA coshtab<>+72(SB)/8, $-.129850717389178721E-01
+DATA coshtab<>+80(SB)/8, $-.892902649276657891E-02
+DATA coshtab<>+88(SB)/8, $-.338202636596794887E-02
+DATA coshtab<>+96(SB)/8, $0.357266307045684762E-02
+DATA coshtab<>+104(SB)/8, $0.118665304327406698E-01
+DATA coshtab<>+112(SB)/8, $0.214434994118118914E-01
+DATA coshtab<>+120(SB)/8, $0.322580645161290314E-01
+GLOBL coshtab<>+0(SB), RODATA, $128
+
+// Minimax polynomial approximations
+DATA coshe2<>+0(SB)/8, $0.500000000000004237e+00
+GLOBL coshe2<>+0(SB), RODATA, $8
+DATA coshe3<>+0(SB)/8, $0.166666666630345592e+00
+GLOBL coshe3<>+0(SB), RODATA, $8
+DATA coshe4<>+0(SB)/8, $0.416666664838056960e-01
+GLOBL coshe4<>+0(SB), RODATA, $8
+DATA coshe5<>+0(SB)/8, $0.833349307718286047e-02
+GLOBL coshe5<>+0(SB), RODATA, $8
+DATA coshe6<>+0(SB)/8, $0.138926439368309441e-02
+GLOBL coshe6<>+0(SB), RODATA, $8
+
+// Cosh returns the hyperbolic cosine of x.
+//
+// Special cases are:
+// Cosh(±0) = 1
+// Cosh(±Inf) = +Inf
+// Cosh(NaN) = NaN
+// The algorithm used is minimax polynomial approximation
+// with coefficients determined with a Remez exchange algorithm.
+
+TEXT ·coshAsm(SB),NOSPLIT,$0-16
+ FMOVD x+0(FP), F0
+ MOVD $coshrodataL23<>+0(SB), R9
+ WORD $0xB3120000 //ltdbr %f0,%f0
+ MOVD $0x4086000000000000, R2
+ MOVD $0x4086000000000000, R3
+ BLTU L19
+ FMOVD F0, F4
+L2:
+ WORD $0xED409018 //cdb %f4,.L24-.L23(%r9)
+ BYTE $0x00
+ BYTE $0x19
+ BGE L14 //jnl .L14
+ BVS L14
+ WFCEDBS V4, V4, V2
+ BEQ L20
+L1:
+ FMOVD F0, ret+8(FP)
+ RET
+
+L14:
+ WFCEDBS V4, V4, V2
+ BVS L1
+ MOVD $coshxlim1<>+0(SB), R1
+ FMOVD 0(R1), F2
+ WFCHEDBS V4, V2, V2
+ BEQ L21
+ MOVD $coshxaddhy<>+0(SB), R1
+ FMOVD coshrodataL23<>+16(SB), F5
+ FMOVD 0(R1), F2
+ WFMSDB V0, V5, V2, V5
+ FMOVD coshrodataL23<>+8(SB), F3
+ FADD F5, F2
+ MOVD $coshe6<>+0(SB), R1
+ WFMSDB V2, V3, V0, V3
+ FMOVD 0(R1), F6
+ WFMDB V3, V3, V1
+ MOVD $coshe4<>+0(SB), R1
+ FMOVD coshrodataL23<>+0(SB), F7
+ WFMADB V2, V7, V3, V2
+ FMOVD 0(R1), F3
+ MOVD $coshe5<>+0(SB), R1
+ WFMADB V1, V6, V3, V6
+ FMOVD 0(R1), F7
+ MOVD $coshe3<>+0(SB), R1
+ FMOVD 0(R1), F3
+ WFMADB V1, V7, V3, V7
+ FNEG F2, F3
+ WORD $0xB3CD0015 //lgdr %r1,%f5
+ MOVD $coshe2<>+0(SB), R3
+ WFCEDBS V4, V0, V0
+ FMOVD 0(R3), F5
+ MOVD $coshe1<>+0(SB), R3
+ WFMADB V1, V6, V5, V6
+ FMOVD 0(R3), F5
+ WORD $0xEC21000F //risbgn %r2,%r1,64-64+0,64-64+0+16-1,64-0-16
+ BYTE $0x30
+ BYTE $0x59
+ WFMADB V1, V7, V5, V1
+ BVS L22
+ WORD $0xEC4139BC //risbg %r4,%r1,57,128+60,3
+ BYTE $0x03
+ BYTE $0x55
+ MOVD $coshtab<>+0(SB), R3
+ WFMADB V3, V6, V1, V6
+ WORD $0x68043000 //ld %f0,0(%r4,%r3)
+ FMSUB F0, F3, F2, 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
+ MOVD $coshx4ff<>+0(SB), R1
+ FMOVD 0(R1), F0
+ FMUL F2, F0
+ FMOVD F0, ret+8(FP)
+ RET
+
+L19:
+ FNEG F0, F4
+ BR L2
+L20:
+ MOVD $coshxaddhy<>+0(SB), R1
+ FMOVD coshrodataL23<>+16(SB), F3
+ FMOVD 0(R1), F2
+ WFMSDB V0, V3, V2, V3
+ FMOVD coshrodataL23<>+8(SB), F4
+ FADD F3, F2
+ MOVD $coshe6<>+0(SB), R1
+ FMSUB F4, F2, F0, F0
+ FMOVD 0(R1), F6
+ WFMDB V0, V0, V1
+ MOVD $coshe4<>+0(SB), R1
+ FMOVD 0(R1), F4
+ MOVD $coshe5<>+0(SB), R1
+ FMOVD coshrodataL23<>+0(SB), F5
+ WFMADB V1, V6, V4, V6
+ FMADD F5, F2, F0, F0
+ FMOVD 0(R1), F2
+ MOVD $coshe3<>+0(SB), R1
+ FMOVD 0(R1), F4
+ WFMADB V1, V2, V4, V2
+ MOVD $coshe2<>+0(SB), R1
+ FMOVD 0(R1), F5
+ FNEG F0, F4
+ WFMADB V1, V6, V5, V6
+ MOVD $coshe1<>+0(SB), R1
+ FMOVD 0(R1), F5
+ WFMADB V1, V2, V5, V1
+ WORD $0xB3CD0013 //lgdr %r1,%f3
+ MOVD $coshtab<>+0(SB), R5
+ WFMADB V4, V6, V1, V3
+ WORD $0xEC4139BC //risbg %r4,%r1,57,128+60,3
+ BYTE $0x03
+ BYTE $0x55
+ WFMSDB V4, V6, V1, V6
+ WORD $0x68145000 //ld %f1,0(%r4,%r5)
+ WFMSDB V4, V1, V0, V2
+ WORD $0xA7487FBE //lhi %r4,32702
+ FMADD F3, F2, F1, 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
+ WORD $0xEC21000F //risbgn %r2,%r1,64-64+0,64-64+0+16-1,64-0-16
+ BYTE $0x30
+ BYTE $0x59
+ WFMADB V0, V6, V2, V6
+ 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
+ FADD F2, F0
+ FMOVD F0, ret+8(FP)
+ RET
+
+L22:
+ WORD $0xA7387FBE //lhi %r3,32702
+ MOVD $coshtab<>+0(SB), R4
+ SUBW R1, R3
+ WFMSDB V3, V6, V1, V6
+ WORD $0xEC3339BC //risbg %r3,%r3,57,128+60,3
+ BYTE $0x03
+ BYTE $0x55
+ WORD $0x68034000 //ld %f0,0(%r3,%r4)
+ FMSUB F0, F3, F2, F2
+ WORD $0xA7386FBE //lhi %r3,28606
+ WFMADB V2, V6, V0, V6
+ SUBW R1, R3, R1
+ BR L17
+L21:
+ MOVD $coshxinf<>+0(SB), R1
+ FMOVD 0(R1), F0
+ FMOVD F0, ret+8(FP)
+ RET
+
diff --git a/src/math/dim_arm64.s b/src/math/dim_arm64.s
new file mode 100644
index 0000000..4b6b592
--- /dev/null
+++ b/src/math/dim_arm64.s
@@ -0,0 +1,78 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "textflag.h"
+
+#define PosInf 0x7FF0000000000000
+#define NaN 0x7FF8000000000001
+#define NegInf 0xFFF0000000000000
+
+// func Dim(x, y float64) float64
+TEXT ·Dim(SB),NOSPLIT,$0
+ // (+Inf, +Inf) special case
+ MOVD $PosInf, R0
+ MOVD x+0(FP), R1
+ MOVD y+8(FP), R2
+ CMP R0, R1
+ BNE dim2
+ CMP R0, R2
+ BEQ bothInf
+dim2: // (-Inf, -Inf) special case
+ MOVD $NegInf, R0
+ CMP R0, R1
+ BNE dim3
+ CMP R0, R2
+ BEQ bothInf
+dim3: // normal case
+ FMOVD R1, F0
+ FMOVD R2, F1
+ FMOVD $0.0, F2
+ FSUBD F1, F0
+ FMAXD F0, F2, F0
+ FMOVD F0, ret+16(FP)
+ RET
+bothInf:
+ MOVD $NaN, R0
+ MOVD R0, ret+16(FP)
+ RET
+
+// func ·Max(x, y float64) float64
+TEXT ·Max(SB),NOSPLIT,$0
+ // +Inf special cases
+ MOVD $PosInf, R0
+ MOVD x+0(FP), R1
+ CMP R0, R1
+ BEQ isPosInf
+ MOVD y+8(FP), R2
+ CMP R0, R2
+ BEQ isPosInf
+ // normal case
+ FMOVD R1, F0
+ FMOVD R2, F1
+ FMAXD F0, F1, F0
+ FMOVD F0, ret+16(FP)
+ RET
+isPosInf: // return +Inf
+ MOVD R0, ret+16(FP)
+ RET
+
+// func Min(x, y float64) float64
+TEXT ·Min(SB),NOSPLIT,$0
+ // -Inf special cases
+ MOVD $NegInf, R0
+ MOVD x+0(FP), R1
+ CMP R0, R1
+ BEQ isNegInf
+ MOVD y+8(FP), R2
+ CMP R0, R2
+ BEQ isNegInf
+ // normal case
+ FMOVD R1, F0
+ FMOVD R2, F1
+ FMIND F0, F1, F0
+ FMOVD F0, ret+16(FP)
+ RET
+isNegInf: // return -Inf
+ MOVD R0, ret+16(FP)
+ RET
diff --git a/src/math/exp_386.s b/src/math/exp_386.s
index 18a92ef..9d63295 100644
--- a/src/math/exp_386.s
+++ b/src/math/exp_386.s
@@ -6,36 +6,6 @@
// func Exp(x float64) float64
TEXT ·Exp(SB),NOSPLIT,$0
-// test bits for not-finite
- MOVL x_hi+4(FP), AX
- ANDL $0x7ff00000, AX
- CMPL AX, $0x7ff00000
- JEQ not_finite
- FLDL2E // F0=log2(e)
- FMULD x+0(FP), F0 // F0=x*log2(e)
- FMOVD F0, F1 // F0=x*log2(e), F1=x*log2(e)
- FRNDINT // F0=int(x*log2(e)), F1=x*log2(e)
- FSUBD F0, F1 // F0=int(x*log2(e)), F1=x*log2(e)-int(x*log2(e))
- FXCHD F0, F1 // F0=x*log2(e)-int(x*log2(e)), F1=int(x*log2(e))
- F2XM1 // F0=2**(x*log2(e)-int(x*log2(e)))-1, F1=int(x*log2(e))
- FLD1 // F0=1, F1=2**(x*log2(e)-int(x*log2(e)))-1, F2=int(x*log2(e))
- FADDDP F0, F1 // F0=2**(x*log2(e)-int(x*log2(e))), F1=int(x*log2(e))
- FSCALE // F0=e**x, F1=int(x*log2(e))
- FMOVDP F0, F1 // F0=e**x
- FMOVDP F0, ret+8(FP)
- RET
-not_finite:
-// test bits for -Inf
- MOVL x_hi+4(FP), BX
- MOVL x_lo+0(FP), CX
- CMPL BX, $0xfff00000
- JNE not_neginf
- CMPL CX, $0
- JNE not_neginf
- FLDZ // F0=0
- FMOVDP F0, ret+8(FP)
- RET
-not_neginf:
- MOVL CX, ret_lo+8(FP)
- MOVL BX, ret_hi+12(FP)
- RET
+ // Used to use 387 assembly (FLDL2E+F2XM1) here,
+ // but it was both slower and less accurate than the portable Go code.
+ JMP ·exp(SB)
diff --git a/src/math/expm1.go b/src/math/expm1.go
index 8ce67e5..7dd75a8 100644
--- a/src/math/expm1.go
+++ b/src/math/expm1.go
@@ -229,7 +229,7 @@ func expm1(x float64) float64 {
}
t := Float64frombits(uint64(0x3ff-k) << 52) // 2**-k
y := x - (e + t)
- y += 1
+ y++
y = Float64frombits(Float64bits(y) + uint64(k)<<52) // add k to y's exponent
return y
}
diff --git a/src/math/export_s390x_test.go b/src/math/export_s390x_test.go
new file mode 100644
index 0000000..3fdbd86
--- /dev/null
+++ b/src/math/export_s390x_test.go
@@ -0,0 +1,14 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+// Export internal functions and variable for testing.
+var Log10NoVec = log10
+var CosNoVec = cos
+var CoshNoVec = cosh
+var SinNoVec = sin
+var SinhNoVec = sinh
+var TanhNoVec = tanh
+var HasVX = hasVX
diff --git a/src/math/floor_arm64.s b/src/math/floor_arm64.s
new file mode 100644
index 0000000..6d240d4
--- /dev/null
+++ b/src/math/floor_arm64.s
@@ -0,0 +1,26 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "textflag.h"
+
+// func Floor(x float64) float64
+TEXT ·Floor(SB),NOSPLIT,$0
+ FMOVD x+0(FP), F0
+ FRINTMD F0, F0
+ FMOVD F0, ret+8(FP)
+ RET
+
+// func Ceil(x float64) float64
+TEXT ·Ceil(SB),NOSPLIT,$0
+ FMOVD x+0(FP), F0
+ FRINTPD F0, F0
+ FMOVD F0, ret+8(FP)
+ RET
+
+// func Trunc(x float64) float64
+TEXT ·Trunc(SB),NOSPLIT,$0
+ FMOVD x+0(FP), F0
+ FRINTZD F0, F0
+ FMOVD F0, ret+8(FP)
+ RET
diff --git a/src/math/floor_ppc64x.s b/src/math/floor_ppc64x.s
new file mode 100644
index 0000000..2ab011d
--- /dev/null
+++ b/src/math/floor_ppc64x.s
@@ -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.
+
+// +build ppc64 ppc64le
+
+#include "textflag.h"
+
+TEXT ·Floor(SB),NOSPLIT,$0
+ FMOVD x+0(FP), F0
+ FRIM F0, F0
+ FMOVD F0, ret+8(FP)
+ RET
+
+TEXT ·Ceil(SB),NOSPLIT,$0
+ FMOVD x+0(FP), F0
+ FRIP F0, F0
+ FMOVD F0, ret+8(FP)
+ RET
+
+TEXT ·Trunc(SB),NOSPLIT,$0
+ FMOVD x+0(FP), F0
+ FRIZ F0, F0
+ FMOVD F0, ret+8(FP)
+ RET
diff --git a/src/math/floor_s390x.s b/src/math/floor_s390x.s
new file mode 100644
index 0000000..896e79b
--- /dev/null
+++ b/src/math/floor_s390x.s
@@ -0,0 +1,26 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "textflag.h"
+
+// func Floor(x float64) float64
+TEXT ·Floor(SB),NOSPLIT,$0
+ FMOVD x+0(FP), F0
+ FIDBR $7, F0, F0
+ FMOVD F0, ret+8(FP)
+ RET
+
+// func Ceil(x float64) float64
+TEXT ·Ceil(SB),NOSPLIT,$0
+ FMOVD x+0(FP), F0
+ FIDBR $6, F0, F0
+ FMOVD F0, ret+8(FP)
+ RET
+
+// func Trunc(x float64) float64
+TEXT ·Trunc(SB),NOSPLIT,$0
+ FMOVD x+0(FP), F0
+ FIDBR $5, F0, F0
+ FMOVD F0, ret+8(FP)
+ RET
diff --git a/src/math/gamma.go b/src/math/gamma.go
index 841ec11..cc9e869 100644
--- a/src/math/gamma.go
+++ b/src/math/gamma.go
@@ -91,23 +91,31 @@ var _gamS = [...]float64{
}
// Gamma function computed by Stirling's formula.
-// The polynomial is valid for 33 <= x <= 172.
-func stirling(x float64) float64 {
+// The pair of results must be multiplied together to get the actual answer.
+// The multiplication is left to the caller so that, if careful, the caller can avoid
+// infinity for 172 <= x <= 180.
+// The polynomial is valid for 33 <= x <= 172; larger values are only used
+// in reciprocal and produce denormalized floats. The lower precision there
+// masks any imprecision in the polynomial.
+func stirling(x float64) (float64, float64) {
+ if x > 200 {
+ return Inf(1), 1
+ }
const (
SqrtTwoPi = 2.506628274631000502417
MaxStirling = 143.01608
)
w := 1 / x
w = 1 + w*((((_gamS[0]*w+_gamS[1])*w+_gamS[2])*w+_gamS[3])*w+_gamS[4])
- y := Exp(x)
+ y1 := Exp(x)
+ y2 := 1.0
if x > MaxStirling { // avoid Pow() overflow
v := Pow(x, 0.5*x-0.25)
- y = v * (v / y)
+ y1, y2 = v, v/y1
} else {
- y = Pow(x, x-0.5) / y
+ y1 = Pow(x, x-0.5) / y1
}
- y = SqrtTwoPi * y * w
- return y
+ return y1, SqrtTwoPi * w * y2
}
// Gamma returns the Gamma function of x.
@@ -125,22 +133,26 @@ func Gamma(x float64) float64 {
switch {
case isNegInt(x) || IsInf(x, -1) || IsNaN(x):
return NaN()
+ case IsInf(x, 1):
+ return Inf(1)
case x == 0:
if Signbit(x) {
return Inf(-1)
}
return Inf(1)
- case x < -170.5674972726612 || x > 171.61447887182298:
- return Inf(1)
}
q := Abs(x)
p := Floor(q)
if q > 33 {
if x >= 0 {
- return stirling(x)
+ y1, y2 := stirling(x)
+ return y1 * y2
}
+ // Note: x is negative but (checked above) not a negative integer,
+ // so x must be small enough to be in range for conversion to int64.
+ // If |x| were >= 2⁶³ it would have to be an integer.
signgam := 1
- if ip := int(p); ip&1 == 0 {
+ if ip := int64(p); ip&1 == 0 {
signgam = -1
}
z := q - p
@@ -152,7 +164,14 @@ func Gamma(x float64) float64 {
if z == 0 {
return Inf(signgam)
}
- z = Pi / (Abs(z) * stirling(q))
+ sq1, sq2 := stirling(q)
+ absz := Abs(z)
+ d := absz * sq1 * sq2
+ if IsInf(d, 0) {
+ z = Pi / absz / sq1 / sq2
+ } else {
+ z = Pi / d
+ }
return float64(signgam) * z
}
diff --git a/src/math/j0.go b/src/math/j0.go
index cbef7aa..fe26791 100644
--- a/src/math/j0.go
+++ b/src/math/j0.go
@@ -305,20 +305,20 @@ var p0S2 = [5]float64{
}
func pzero(x float64) float64 {
- var p [6]float64
- var q [5]float64
+ var p *[6]float64
+ var q *[5]float64
if x >= 8 {
- p = p0R8
- q = p0S8
+ p = &p0R8
+ q = &p0S8
} else if x >= 4.5454 {
- p = p0R5
- q = p0S5
+ p = &p0R5
+ q = &p0S5
} else if x >= 2.8571 {
- p = p0R3
- q = p0S3
+ p = &p0R3
+ q = &p0S3
} else if x >= 2 {
- p = p0R2
- q = p0S2
+ p = &p0R2
+ q = &p0S2
}
z := 1 / (x * x)
r := p[0] + z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5]))))
@@ -408,19 +408,19 @@ var q0S2 = [6]float64{
}
func qzero(x float64) float64 {
- var p, q [6]float64
+ var p, q *[6]float64
if x >= 8 {
- p = q0R8
- q = q0S8
+ p = &q0R8
+ q = &q0S8
} else if x >= 4.5454 {
- p = q0R5
- q = q0S5
+ p = &q0R5
+ q = &q0S5
} else if x >= 2.8571 {
- p = q0R3
- q = q0S3
+ p = &q0R3
+ q = &q0S3
} else if x >= 2 {
- p = q0R2
- q = q0S2
+ p = &q0R2
+ q = &q0S2
}
z := 1 / (x * x)
r := p[0] + z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5]))))
diff --git a/src/math/j1.go b/src/math/j1.go
index d359d90..f1adcb6 100644
--- a/src/math/j1.go
+++ b/src/math/j1.go
@@ -298,20 +298,20 @@ var p1S2 = [5]float64{
}
func pone(x float64) float64 {
- var p [6]float64
- var q [5]float64
+ var p *[6]float64
+ var q *[5]float64
if x >= 8 {
- p = p1R8
- q = p1S8
+ p = &p1R8
+ q = &p1S8
} else if x >= 4.5454 {
- p = p1R5
- q = p1S5
+ p = &p1R5
+ q = &p1S5
} else if x >= 2.8571 {
- p = p1R3
- q = p1S3
+ p = &p1R3
+ q = &p1S3
} else if x >= 2 {
- p = p1R2
- q = p1S2
+ p = &p1R2
+ q = &p1S2
}
z := 1 / (x * x)
r := p[0] + z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5]))))
@@ -401,19 +401,19 @@ var q1S2 = [6]float64{
}
func qone(x float64) float64 {
- var p, q [6]float64
+ var p, q *[6]float64
if x >= 8 {
- p = q1R8
- q = q1S8
+ p = &q1R8
+ q = &q1S8
} else if x >= 4.5454 {
- p = q1R5
- q = q1S5
+ p = &q1R5
+ q = &q1S5
} else if x >= 2.8571 {
- p = q1R3
- q = q1S3
+ p = &q1R3
+ q = &q1S3
} else if x >= 2 {
- p = q1R2
- q = q1S2
+ p = &q1R2
+ q = &q1S2
}
z := 1 / (x * x)
r := p[0] + z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5]))))
diff --git a/src/math/jn.go b/src/math/jn.go
index 721112f..3422782 100644
--- a/src/math/jn.go
+++ b/src/math/jn.go
@@ -174,7 +174,7 @@ func Jn(n int, x float64) float64 {
q1 := w*z - 1
k := 1
for q1 < 1e9 {
- k += 1
+ k++
z += h
q0, q1 = q1, z*q1-q0
}
diff --git a/src/math/log10_s390x.s b/src/math/log10_s390x.s
new file mode 100644
index 0000000..460bcd9
--- /dev/null
+++ b/src/math/log10_s390x.s
@@ -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.
+
+#include "textflag.h"
+
+// Minimax polynomial coefficients and other constants
+DATA log10rodataL19<>+0(SB)/8, $0.000000000000000000E+00
+DATA log10rodataL19<>+8(SB)/8, $-1.0
+DATA log10rodataL19<>+16(SB)/8, $0x7FF8000000000000 //+NanN
+DATA log10rodataL19<>+24(SB)/8, $.15375570329280596749
+DATA log10rodataL19<>+32(SB)/8, $.60171950900703668594E+04
+DATA log10rodataL19<>+40(SB)/8, $-1.9578460454940795898
+DATA log10rodataL19<>+48(SB)/8, $0.78962633073318517310E-01
+DATA log10rodataL19<>+56(SB)/8, $-.71784211884836937993E-02
+DATA log10rodataL19<>+64(SB)/8, $0.87011165920689940661E-03
+DATA log10rodataL19<>+72(SB)/8, $-.11865158981621437541E-03
+DATA log10rodataL19<>+80(SB)/8, $0.17258413403018680410E-04
+DATA log10rodataL19<>+88(SB)/8, $0.40752932047883484315E-06
+DATA log10rodataL19<>+96(SB)/8, $-.26149194688832680410E-05
+DATA log10rodataL19<>+104(SB)/8, $0.92453396963875026759E-08
+DATA log10rodataL19<>+112(SB)/8, $-.64572084905921579630E-07
+DATA log10rodataL19<>+120(SB)/8, $-5.5
+DATA log10rodataL19<>+128(SB)/8, $18446744073709551616.
+GLOBL log10rodataL19<>+0(SB), RODATA, $136
+
+// Table of log10 correction terms
+DATA log10tab2074<>+0(SB)/8, $0.254164497922885069E-01
+DATA log10tab2074<>+8(SB)/8, $0.179018857989381839E-01
+DATA log10tab2074<>+16(SB)/8, $0.118926768029048674E-01
+DATA log10tab2074<>+24(SB)/8, $0.722595568238080033E-02
+DATA log10tab2074<>+32(SB)/8, $0.376393570022739135E-02
+DATA log10tab2074<>+40(SB)/8, $0.138901135928814326E-02
+DATA log10tab2074<>+48(SB)/8, $0
+DATA log10tab2074<>+56(SB)/8, $-0.490780466387818203E-03
+DATA log10tab2074<>+64(SB)/8, $-0.159811431402137571E-03
+DATA log10tab2074<>+72(SB)/8, $0.925796337165100494E-03
+DATA log10tab2074<>+80(SB)/8, $0.270683176738357035E-02
+DATA log10tab2074<>+88(SB)/8, $0.513079030821304758E-02
+DATA log10tab2074<>+96(SB)/8, $0.815089785397996303E-02
+DATA log10tab2074<>+104(SB)/8, $0.117253060262419215E-01
+DATA log10tab2074<>+112(SB)/8, $0.158164239345343963E-01
+DATA log10tab2074<>+120(SB)/8, $0.203903595489229786E-01
+GLOBL log10tab2074<>+0(SB), RODATA, $128
+
+// Log10 returns the decimal 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
+// with coefficients determined with a Remez exchange algorithm.
+
+TEXT ·log10Asm(SB),NOSPLIT,$8-16
+ FMOVD x+0(FP), F0
+ MOVD $log10rodataL19<>+0(SB), R9
+ FMOVD F0, x-8(SP)
+ WORD $0xC0298006 //iilf %r2,2147909631
+ BYTE $0x7F
+ BYTE $0xFF
+ WORD $0x5840F008 //l %r4, 8(%r15)
+ SUBW R4, R2, R3
+ WORD $0xEC5320AF //risbg %r5,%r3,32,128+47,0
+ BYTE $0x00
+ BYTE $0x55
+ MOVH $0x0, R1
+ WORD $0xEC15001F //risbgn %r1,%r5,64-64+0,64-64+0+32-1,64-0-32
+ BYTE $0x20
+ BYTE $0x59
+ WORD $0xC0590016 //iilf %r5,1507327
+ BYTE $0xFF
+ BYTE $0xFF
+ MOVW R4, R10
+ MOVW R5, R11
+ CMPBLE R10, R11, L2
+ WORD $0xC0297FEF //iilf %r2,2146435071
+ BYTE $0xFF
+ BYTE $0xFF
+ MOVW R4, R10
+ MOVW R2, R11
+ CMPBLE R10, R11, L16
+L3:
+L1:
+ FMOVD F0, ret+8(FP)
+ RET
+
+L2:
+ WORD $0xB3120000 //ltdbr %f0,%f0
+ BLEU L13
+ WORD $0xED009080 //mdb %f0,.L20-.L19(%r9)
+ BYTE $0x00
+ BYTE $0x1C
+ FMOVD F0, x-8(SP)
+ WORD $0x5B20F008 //s %r2, 8(%r15)
+ WORD $0xEC3239BC //risbg %r3,%r2,57,128+60,64-13
+ BYTE $0x33
+ BYTE $0x55
+ ANDW $0xFFFF0000, R2
+ WORD $0xEC12001F //risbgn %r1,%r2,64-64+0,64-64+0+32-1,64-0-32
+ BYTE $0x20
+ BYTE $0x59
+ ADDW $0x4000000, R2
+ BLEU L17
+L8:
+ SRW $8, R2, R2
+ ORW $0x45000000, R2
+L4:
+ FMOVD log10rodataL19<>+120(SB), F2
+ WORD $0xB3C10041 //ldgr %f4,%r1
+ WFMADB V4, V0, V2, V0
+ FMOVD log10rodataL19<>+112(SB), F4
+ FMOVD log10rodataL19<>+104(SB), F6
+ WFMADB V0, V6, V4, V6
+ FMOVD log10rodataL19<>+96(SB), F4
+ FMOVD log10rodataL19<>+88(SB), F1
+ WFMADB V0, V1, V4, V1
+ WFMDB V0, V0, V4
+ FMOVD log10rodataL19<>+80(SB), F2
+ WFMADB V6, V4, V1, V6
+ FMOVD log10rodataL19<>+72(SB), F1
+ WFMADB V0, V2, V1, V2
+ FMOVD log10rodataL19<>+64(SB), F1
+ WORD $0xEC3339BC //risbg %r3,%r3,57,128+60,0
+ BYTE $0x00
+ BYTE $0x55
+ WFMADB V4, V6, V2, V6
+ FMOVD log10rodataL19<>+56(SB), F2
+ WFMADB V0, V1, V2, V1
+ VLVGF $0, R2, V2
+ WFMADB V4, V6, V1, V4
+ LDEBR F2, F2
+ FMOVD log10rodataL19<>+48(SB), F6
+ WFMADB V0, V4, V6, V4
+ FMOVD log10rodataL19<>+40(SB), F1
+ FMOVD log10rodataL19<>+32(SB), F6
+ MOVD $log10tab2074<>+0(SB), R1
+ WFMADB V2, V1, V6, V2
+ WORD $0x68331000 //ld %f3,0(%r3,%r1)
+ WFMADB V0, V4, V3, V0
+ FMOVD log10rodataL19<>+24(SB), F4
+ FMADD F4, F2, F0, F0
+ FMOVD F0, ret+8(FP)
+ RET
+
+L16:
+ WORD $0xEC2328B7 //risbg %r2,%r3,40,128+55,64-8
+ BYTE $0x38
+ BYTE $0x55
+ WORD $0xEC3339BC //risbg %r3,%r3,57,128+60,64-13
+ BYTE $0x33
+ BYTE $0x55
+ ORW $0x45000000, R2
+ BR L4
+L13:
+ BGE L18 //jnl .L18
+ BVS L18
+ FMOVD log10rodataL19<>+16(SB), F0
+ BR L1
+L17:
+ SRAW $1, R2, R2
+ SUBW $0x40000000, R2
+ BR L8
+L18:
+ FMOVD log10rodataL19<>+8(SB), F0
+ WORD $0xED009000 //ddb %f0,.L36-.L19(%r9)
+ BYTE $0x00
+ BYTE $0x1D
+ BR L1
diff --git a/src/math/log1p.go b/src/math/log1p.go
index d1bddfb..b128a16 100644
--- a/src/math/log1p.go
+++ b/src/math/log1p.go
@@ -167,7 +167,7 @@ func log1p(x float64) float64 {
if iu < 0x0006a09e667f3bcd { // mantissa of Sqrt(2)
u = Float64frombits(iu | 0x3ff0000000000000) // normalize u
} else {
- k += 1
+ k++
u = Float64frombits(iu | 0x3fe0000000000000) // normalize u/2
iu = (0x0010000000000000 - iu) >> 2
}
@@ -179,10 +179,9 @@ func log1p(x float64) float64 {
if f == 0 {
if k == 0 {
return 0
- } else {
- c += float64(k) * Ln2Lo
- return float64(k)*Ln2Hi + c
}
+ c += float64(k) * Ln2Lo
+ return float64(k)*Ln2Hi + c
}
R = hfsq * (1.0 - 0.66666666666666666*f) // avoid division
if k == 0 {
diff --git a/src/math/modf_386.s b/src/math/modf_386.s
index d9b1eeb..e916073 100644
--- a/src/math/modf_386.s
+++ b/src/math/modf_386.s
@@ -7,16 +7,16 @@
// func Modf(f float64) (int float64, frac float64)
TEXT ·Modf(SB),NOSPLIT,$0
// special case for f == -0.0
- MOVL f+4(FP), DX // high word
- MOVL f+0(FP), AX // low word
+ MOVL f_hi+4(FP), DX // high word
+ MOVL f_lo+0(FP), AX // low word
CMPL DX, $(1<<31) // beginning of -0.0
JNE notNegativeZero
CMPL AX, $0 // could be denormalized
JNE notNegativeZero
- MOVL AX, int+8(FP)
- MOVL DX, int+12(FP)
- MOVL AX, frac+16(FP)
- MOVL DX, frac+20(FP)
+ MOVL AX, int_lo+8(FP)
+ MOVL DX, int_hi+12(FP)
+ MOVL AX, frac_lo+16(FP)
+ MOVL DX, frac_hi+20(FP)
RET
notNegativeZero:
FMOVD f+0(FP), F0 // F0=f
diff --git a/src/math/modf_arm64.s b/src/math/modf_arm64.s
new file mode 100644
index 0000000..7c70ef3
--- /dev/null
+++ b/src/math/modf_arm64.s
@@ -0,0 +1,18 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "textflag.h"
+
+// func Modf(f float64) (int float64, frac float64)
+TEXT ·Modf(SB),NOSPLIT,$0
+ MOVD f+0(FP), R0
+ FMOVD R0, F0
+ FRINTZD F0, F1
+ FMOVD F1, int+8(FP)
+ FSUBD F1, F0
+ FMOVD F0, R1
+ AND $(1<<63), R0
+ ORR R0, R1 // must have same sign
+ MOVD R1, frac+16(FP)
+ RET
diff --git a/src/math/rand/gen_cooked.go b/src/math/rand/gen_cooked.go
new file mode 100644
index 0000000..567b7a8
--- /dev/null
+++ b/src/math/rand/gen_cooked.go
@@ -0,0 +1,89 @@
+// Copyright 2009 The Go Authors. 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 computes the value of rng_cooked in rng.go,
+// which is used for seeding all instances of rand.Source.
+// a 64bit and a 63bit version of the array is printed to
+// the standard output.
+
+package main
+
+import "fmt"
+
+const (
+ length = 607
+ tap = 273
+ mask = (1 << 63) - 1
+ a = 48271
+ m = (1 << 31) - 1
+ q = 44488
+ r = 3399
+)
+
+var (
+ rngVec [length]int64
+ rngTap, rngFeed int
+)
+
+func seedrand(x int32) int32 {
+ hi := x / q
+ lo := x % q
+ x = a*lo - r*hi
+ if x < 0 {
+ x += m
+ }
+ return x
+}
+
+func srand(seed int32) {
+ rngTap = 0
+ rngFeed = length - tap
+ seed %= m
+ if seed < 0 {
+ seed += m
+ } else if seed == 0 {
+ seed = 89482311
+ }
+ x := seed
+ for i := -20; i < length; i++ {
+ x = seedrand(x)
+ if i >= 0 {
+ var u int64
+ u = int64(x) << 20
+ x = seedrand(x)
+ u ^= int64(x) << 10
+ x = seedrand(x)
+ u ^= int64(x)
+ rngVec[i] = u
+ }
+ }
+}
+
+func vrand() int64 {
+ rngTap--
+ if rngTap < 0 {
+ rngTap += length
+ }
+ rngFeed--
+ if rngFeed < 0 {
+ rngFeed += length
+ }
+ x := (rngVec[rngFeed] + rngVec[rngTap])
+ rngVec[rngFeed] = x
+ return x
+}
+
+func main() {
+ srand(1)
+ for i := uint64(0); i < 7.8e12; i++ {
+ vrand()
+ }
+ fmt.Printf("rngVec after 7.8e12 calls to vrand:\n%#v\n", rngVec)
+ for i := range rngVec {
+ rngVec[i] &= mask
+ }
+ fmt.Printf("lower 63bit of rngVec after 7.8e12 calls to vrand:\n%#v\n", rngVec)
+}
diff --git a/src/math/rand/race_test.go b/src/math/rand/race_test.go
index 48f6c29..186c716 100644
--- a/src/math/rand/race_test.go
+++ b/src/math/rand/race_test.go
@@ -33,6 +33,7 @@ func TestConcurrent(t *testing.T) {
seed += int64(Int63n(Int63()))
seed += int64(NormFloat64())
seed += int64(Uint32())
+ seed += int64(Uint64())
for _, p := range Perm(10) {
seed += int64(p)
}
diff --git a/src/math/rand/rand.go b/src/math/rand/rand.go
index dd8d43c..9fe1cbd 100644
--- a/src/math/rand/rand.go
+++ b/src/math/rand/rand.go
@@ -23,7 +23,20 @@ type Source interface {
Seed(seed int64)
}
+// A Source64 is a Source that can also generate
+// uniformly-distributed pseudo-random uint64 values in
+// the range [0, 1<<64) directly.
+// If a Rand r's underlying Source s implements Source64,
+// then r.Uint64 returns the result of one call to s.Uint64
+// instead of making two calls to s.Int63.
+type Source64 interface {
+ Source
+ Uint64() uint64
+}
+
// NewSource returns a new pseudo-random Source seeded with the given value.
+// Unlike the default Source used by top-level functions, this source is not
+// safe for concurrent use by multiple goroutines.
func NewSource(seed int64) Source {
var rng rngSource
rng.Seed(seed)
@@ -33,6 +46,7 @@ func NewSource(seed int64) Source {
// A Rand is a source of random numbers.
type Rand struct {
src Source
+ s64 Source64 // non-nil if src is source64
// readVal contains remainder of 63-bit integer used for bytes
// generation during most recent Read call.
@@ -46,7 +60,10 @@ type Rand struct {
// New returns a new Rand that uses random values from src
// to generate other random values.
-func New(src Source) *Rand { return &Rand{src: src} }
+func New(src Source) *Rand {
+ s64, _ := src.(Source64)
+ return &Rand{src: src, s64: s64}
+}
// Seed uses the provided seed value to initialize the generator to a deterministic state.
// Seed should not be called concurrently with any other Rand method.
@@ -66,6 +83,14 @@ func (r *Rand) Int63() int64 { return r.src.Int63() }
// Uint32 returns a pseudo-random 32-bit value as a uint32.
func (r *Rand) Uint32() uint32 { return uint32(r.Int63() >> 31) }
+// Uint64 returns a pseudo-random 64-bit value as a uint64.
+func (r *Rand) Uint64() uint64 {
+ if r.s64 != nil {
+ return r.s64.Uint64()
+ }
+ return uint64(r.Int63())>>31 | uint64(r.Int63())<<32
+}
+
// Int31 returns a non-negative pseudo-random 31-bit integer as an int32.
func (r *Rand) Int31() int32 { return int32(r.Int63() >> 32) }
@@ -207,7 +232,7 @@ func read(p []byte, int63 func() int64, readVal *int64, readPos *int8) (n int, e
* Top-level convenience functions
*/
-var globalRand = New(&lockedSource{src: NewSource(1)})
+var globalRand = New(&lockedSource{src: NewSource(1).(Source64)})
// Seed uses the provided seed value to initialize the default Source to a
// deterministic state. If Seed is not called, the generator behaves as
@@ -224,6 +249,10 @@ func Int63() int64 { return globalRand.Int63() }
// from the default Source.
func Uint32() uint32 { return globalRand.Uint32() }
+// Uint64 returns a pseudo-random 64-bit value as a uint64
+// from the default Source.
+func Uint64() uint64 { return globalRand.Uint64() }
+
// Int31 returns a non-negative pseudo-random 31-bit integer as an int32
// from the default Source.
func Int31() int32 { return globalRand.Int31() }
@@ -286,7 +315,7 @@ func ExpFloat64() float64 { return globalRand.ExpFloat64() }
type lockedSource struct {
lk sync.Mutex
- src Source
+ src Source64
}
func (r *lockedSource) Int63() (n int64) {
@@ -296,6 +325,13 @@ func (r *lockedSource) Int63() (n int64) {
return
}
+func (r *lockedSource) Uint64() (n uint64) {
+ r.lk.Lock()
+ n = r.src.Uint64()
+ r.lk.Unlock()
+ return
+}
+
func (r *lockedSource) Seed(seed int64) {
r.lk.Lock()
r.src.Seed(seed)
diff --git a/src/math/rand/rand_test.go b/src/math/rand/rand_test.go
index 6f31279..bf509e0 100644
--- a/src/math/rand/rand_test.go
+++ b/src/math/rand/rand_test.go
@@ -328,13 +328,26 @@ func TestExpTables(t *testing.T) {
}
}
+func hasSlowFloatingPoint() bool {
+ switch runtime.GOARCH {
+ case "arm":
+ return os.Getenv("GOARM") == "5"
+ case "mips", "mipsle", "mips64", "mips64le":
+ // Be conservative and assume that all mips boards
+ // have emulated floating point.
+ // TODO: detect what it actually has.
+ return true
+ }
+ return false
+}
+
func TestFloat32(t *testing.T) {
// For issue 6721, the problem came after 7533753 calls, so check 10e6.
num := int(10e6)
// But do the full amount only on builders (not locally).
// But ARM5 floating point emulation is slow (Issue 10749), so
// do less for that builder:
- if testing.Short() && (testenv.Builder() == "" || runtime.GOARCH == "arm" && os.Getenv("GOARM") == "5") {
+ if testing.Short() && (testenv.Builder() == "" || hasSlowFloatingPoint()) {
num /= 100 // 1.72 seconds instead of 172 seconds
}
diff --git a/src/math/rand/regress_test.go b/src/math/rand/regress_test.go
index 4dd965c..e31e6c5 100644
--- a/src/math/rand/regress_test.go
+++ b/src/math/rand/regress_test.go
@@ -381,4 +381,24 @@ var regressGolden = []interface{}{
uint32(75079301), // Uint32()
uint32(3380456901), // Uint32()
uint32(3433369789), // Uint32()
+ uint64(8717895732742165505), // Uint64()
+ uint64(2259404117704393152), // Uint64()
+ uint64(6050128673802995827), // Uint64()
+ uint64(9724605487393973602), // Uint64()
+ uint64(12613765599614152010), // Uint64()
+ uint64(11893357769247901871), // Uint64()
+ uint64(1774932891286980153), // Uint64()
+ uint64(15267744271532198264), // Uint64()
+ uint64(17498302081433670737), // Uint64()
+ uint64(1543572285742637646), // Uint64()
+ uint64(11885104867954719224), // Uint64()
+ uint64(17548432336275752516), // Uint64()
+ uint64(7837839688282259259), // Uint64()
+ uint64(2518412263346885298), // Uint64()
+ uint64(5617773211005988520), // Uint64()
+ uint64(11562935753659892057), // Uint64()
+ uint64(16368296284793757383), // Uint64()
+ uint64(161231572858529631), // Uint64()
+ uint64(16482847956365694147), // Uint64()
+ uint64(16596477517051940556), // Uint64()
}
diff --git a/src/math/rand/rng.go b/src/math/rand/rng.go
index 947c49f..f922417 100644
--- a/src/math/rand/rng.go
+++ b/src/math/rand/rng.go
@@ -23,161 +23,159 @@ const (
)
var (
- // cooked random numbers
- // the state of the rng
- // after 780e10 iterations
+ // Used for seeding. See gen_cooked.go for details.
rng_cooked [_LEN]int64 = [...]int64{
- 5041579894721019882, 4646389086726545243, 1395769623340756751, 5333664234075297259,
- 2875692520355975054, 9033628115061424579, 7143218595135194537, 4812947590706362721,
- 7937252194349799378, 5307299880338848416, 8209348851763925077, 2115741599318814044,
- 4593015457530856296, 8140875735541888011, 3319429241265089026, 8619815648190321034,
- 1727074043483619500, 113108499721038619, 4569519971459345583, 5062833859075314731,
- 2387618771259064424, 2716131344356686112, 6559392774825876886, 7650093201692370310,
- 7684323884043752161, 257867835996031390, 6593456519409015164, 271327514973697897,
- 2789386447340118284, 1065192797246149621, 3344507881999356393, 4459797941780066633,
- 7465081662728599889, 1014950805555097187, 4449440729345990775, 3481109366438502643,
+ -4181792142133755926, -4576982950128230565, 1395769623340756751, 5333664234075297259,
+ -6347679516498800754, 9033628115061424579, 7143218595135194537, 4812947590706362721,
+ 7937252194349799378, 5307299880338848416, 8209348851763925077, -7107630437535961764,
+ 4593015457530856296, 8140875735541888011, -5903942795589686782, -603556388664454774,
+ -7496297993371156308, 113108499721038619, 4569519971459345583, -4160538177779461077,
+ -6835753265595711384, -6507240692498089696, 6559392774825876886, 7650093201692370310,
+ 7684323884043752161, -8965504200858744418, -2629915517445760644, 271327514973697897,
+ -6433985589514657524, 1065192797246149621, 3344507881999356393, -4763574095074709175,
+ 7465081662728599889, 1014950805555097187, -4773931307508785033, -5742262670416273165,
2418672789110888383, 5796562887576294778, 4484266064449540171, 3738982361971787048,
- 4523597184512354423, 10530508058128498, 8633833783282346118, 2625309929628791628,
- 8660405965245884302, 10162832508971942, 6540714680961817391, 7031802312784620857,
- 6240911277345944669, 831864355460801054, 8004434137542152891, 2116287251661052151,
+ -4699774852342421385, 10530508058128498, -589538253572429690, -6598062107225984180,
+ 8660405965245884302, 10162832508971942, -2682657355892958417, 7031802312784620857,
+ 6240911277345944669, 831864355460801054, -1218937899312622917, 2116287251661052151,
2202309800992166967, 9161020366945053561, 4069299552407763864, 4936383537992622449,
- 457351505131524928, 342195045928179354, 2847771682816600509, 2068020115986376518,
- 4368649989588021065, 887231587095185257, 5563591506886576496, 6816225200251950296,
- 5616972787034086048, 8471809303394836566, 1686575021641186857, 4045484338074262002,
- 4244156215201778923, 7848217333783577387, 5632136521049761902, 833283142057835272,
- 9029726508369077193, 3243583134664087292, 4316371101804477087, 8937849979965997980,
- 6446940406810434101, 1679342092332374735, 6050638460742422078, 6993520719509581582,
- 7640877852514293609, 5881353426285907985, 812786550756860885, 4541845584483343330,
- 2725470216277009086, 4980675660146853729, 5210769080603236061, 8894283318990530821,
- 6326442804750084282, 1495812843684243920, 7069751578799128019, 7370257291860230865,
- 6756929275356942261, 4706794511633873654, 7824520467827898663, 8549875090542453214,
- 33650829478596156, 1328918435751322643, 7297902601803624459, 1011190183918857495,
- 2238025036817854944, 5147159997473910359, 896512091560522982, 2659470849286379941,
- 6097729358393448602, 1731725986304753684, 4106255841983812711, 8327155210721535508,
- 8477511620686074402, 5803876044675762232, 8435417780860221662, 5988852856651071244,
- 4715837297103951910, 7566171971264485114, 505808562678895611, 5070098180695063370,
- 842110666775871513, 572156825025677802, 1791881013492340891, 3393267094866038768,
- 3778721850472236509, 2352769483186201278, 1292459583847367458, 8897907043675088419,
- 5781809037144163536, 2733958794029492513, 5092019688680754699, 8996124554772526841,
- 4234737173186232084, 5027558287275472836, 4635198586344772304, 8687338893267139351,
- 5907508150730407386, 784756255473944452, 972392927514829904, 5422057694808175112,
- 5158420642969283891, 9048531678558643225, 2407211146698877100, 7583282216521099569,
- 3940796514530962282, 3341174631045206375, 3095313889586102949, 7405321895688238710,
- 5832080132947175283, 7890064875145919662, 8184139210799583195, 1149859861409226130,
- 1464597243840211302, 4641648007187991873, 3516491885471466898, 956288521791657692,
+ 457351505131524928, -8881176990926596454, -6375600354038175299, -7155351920868399290,
+ 4368649989588021065, 887231587095185257, -3659780529968199312, -2407146836602825512,
+ 5616972787034086048, -751562733459939242, 1686575021641186857, -5177887698780513806,
+ -4979215821652996885, -1375154703071198421, 5632136521049761902, -8390088894796940536,
+ -193645528485698615, -5979788902190688516, -4907000935050298721, -285522056888777828,
+ -2776431630044341707, 1679342092332374735, 6050638460742422078, -2229851317345194226,
+ -1582494184340482199, 5881353426285907985, 812786550756860885, 4541845584483343330,
+ -6497901820577766722, 4980675660146853729, -4012602956251539747, -329088717864244987,
+ -2896929232104691526, 1495812843684243920, -2153620458055647789, 7370257291860230865,
+ -2466442761497833547, 4706794511633873654, -1398851569026877145, 8549875090542453214,
+ -9189721207376179652, -7894453601103453165, 7297902601803624459, 1011190183918857495,
+ -6985347000036920864, 5147159997473910359, -8326859945294252826, 2659470849286379941,
+ 6097729358393448602, -7491646050550022124, -5117116194870963097, -896216826133240300,
+ -745860416168701406, 5803876044675762232, -787954255994554146, -3234519180203704564,
+ -4507534739750823898, -1657200065590290694, 505808562678895611, -4153273856159712438,
+ -8381261370078904295, 572156825025677802, 1791881013492340891, 3393267094866038768,
+ -5444650186382539299, 2352769483186201278, -7930912453007408350, -325464993179687389,
+ -3441562999710612272, -6489413242825283295, 5092019688680754699, -227247482082248967,
+ 4234737173186232084, 5027558287275472836, 4635198586344772304, -536033143587636457,
+ 5907508150730407386, -8438615781380831356, 972392927514829904, -3801314342046600696,
+ -4064951393885491917, -174840358296132583, 2407211146698877100, -1640089820333676239,
+ 3940796514530962282, -5882197405809569433, 3095313889586102949, -1818050141166537098,
+ 5832080132947175283, 7890064875145919662, 8184139210799583195, -8073512175445549678,
+ -7758774793014564506, -4581724029666783935, 3516491885471466898, -8267083515063118116,
6657089965014657519, 5220884358887979358, 1796677326474620641, 5340761970648932916,
1147977171614181568, 5066037465548252321, 2574765911837859848, 1085848279845204775,
- 3350107529868390359, 6116438694366558490, 2107701075971293812, 1803294065921269267,
- 2469478054175558874, 7368243281019965984, 3791908367843677526, 185046971116456637,
- 2257095756513439648, 7217693971077460129, 909049953079504259, 7196649268545224266,
- 5637660345400869599, 3955544945427965183, 8057528650917418961, 4139268440301127643,
- 6621926588513568059, 1373361136802681441, 6527366231383600011, 3507654575162700890,
- 9202058512774729859, 1954818376891585542, 6640380907130175705, 8299563319178235687,
- 3901867355218954373, 7046310742295574065, 6847195391333990232, 1572638100518868053,
- 8850422670118399721, 3631909142291992901, 5158881091950831288, 2882958317343121593,
- 4763258931815816403, 6280052734341785344, 4243789408204964850, 2043464728020827976,
- 6545300466022085465, 4562580375758598164, 5495451168795427352, 1738312861590151095,
- 553004618757816492, 6895160632757959823, 8233623922264685171, 7139506338801360852,
- 8550891222387991669, 5535668688139305547, 2430933853350256242, 5401941257863201076,
- 8159640039107728799, 6157493831600770366, 7632066283658143750, 6308328381617103346,
+ -5873264506986385449, 6116438694366558490, 2107701075971293812, -7420077970933506541,
+ 2469478054175558874, -1855128755834809824, -5431463669011098282, -9038325065738319171,
+ -6966276280341336160, 7217693971077460129, -8314322083775271549, 7196649268545224266,
+ -3585711691453906209, -5267827091426810625, 8057528650917418961, -5084103596553648165,
+ -2601445448341207749, -7850010900052094367, 6527366231383600011, 3507654575162700890,
+ 9202058512774729859, 1954818376891585542, -2582991129724600103, 8299563319178235687,
+ -5321504681635821435, 7046310742295574065, -2376176645520785576, -7650733936335907755,
+ 8850422670118399721, 3631909142291992901, 5158881091950831288, -6340413719511654215,
+ 4763258931815816403, 6280052734341785344, -4979582628649810958, 2043464728020827976,
+ -2678071570832690343, 4562580375758598164, 5495451168795427352, -7485059175264624713,
+ 553004618757816492, 6895160632757959823, -989748114590090637, 7139506338801360852,
+ -672480814466784139, 5535668688139305547, 2430933853350256242, -3821430778991574732,
+ -1063731997747047009, -3065878205254005442, 7632066283658143750, 6308328381617103346,
3681878764086140361, 3289686137190109749, 6587997200611086848, 244714774258135476,
- 4079788377417136100, 8090302575944624335, 2945117363431356361, 864324395848741045,
- 3009039260312620700, 8430027460082534031, 401084700045993341, 7254622446438694921,
- 4707864159563588614, 5640248530963493951, 5982507712689997893, 3315098242282210105,
- 5503847578771918426, 3941971367175193882, 8118566580304798074, 3839261274019871296,
- 7062410411742090847, 741381002980207668, 6027994129690250817, 2497829994150063930,
- 6251390334426228834, 1368930247903518833, 8809096399316380241, 6492004350391900708,
- 2462145737463489636, 404828418920299174, 4153026434231690595, 261785715255475940,
- 5464715384600071357, 592710404378763017, 6764129236657751224, 8513655718539357449,
- 5820343663801914208, 385298524683789911, 5224135003438199467, 6303131641338802145,
- 7150122561309371392, 368107899140673753, 3115186834558311558, 2915636353584281051,
+ -5143583659437639708, 8090302575944624335, 2945117363431356361, -8359047641006034763,
+ 3009039260312620700, -793344576772241777, 401084700045993341, -1968749590416080887,
+ 4707864159563588614, -3583123505891281857, -3240864324164777915, -5908273794572565703,
+ -3719524458082857382, -5281400669679581926, 8118566580304798074, 3839261274019871296,
+ 7062410411742090847, -8481991033874568140, 6027994129690250817, -6725542042704711878,
+ -2971981702428546974, -7854441788951256975, 8809096399316380241, 6492004350391900708,
+ 2462145737463489636, -8818543617934476634, -5070345602623085213, -8961586321599299868,
+ -3758656652254704451, -8630661632476012791, 6764129236657751224, -709716318315418359,
+ -3403028373052861600, -8838073512170985897, -3999237033416576341, -2920240395515973663,
+ -2073249475545404416, 368107899140673753, -6108185202296464250, -6307735683270494757,
4782583894627718279, 6718292300699989587, 8387085186914375220, 3387513132024756289,
- 4654329375432538231, 8930667561363381602, 5374373436876319273, 7623042350483453954,
- 7725442901813263321, 9186225467561587250, 4091027289597503355, 2357631606492579800,
- 2530936820058611833, 1636551876240043639, 5564664674334965799, 1452244145334316253,
- 2061642381019690829, 1279580266495294036, 9108481583171221009, 6023278686734049809,
- 5007630032676973346, 2153168792952589781, 6720334534964750538, 6041546491134794105,
- 3433922409283786309, 2285479922797300912, 3110614940896576130, 6366559590722842893,
- 5418791419666136509, 7163298419643543757, 4891138053923696990, 580618510277907015,
- 1684034065251686769, 4429514767357295841, 330346578555450005, 1119637995812174675,
- 7177515271653460134, 4589042248470800257, 7693288629059004563, 143607045258444228,
- 246994305896273627, 866417324803099287, 6473547110565816071, 3092379936208876896,
- 2058427839513754051, 5133784708526867938, 8785882556301281247, 6149332666841167611,
- 8585842181454472135, 6137678347805511274, 2070447184436970006, 5708223427705576541,
- 5999657892458244504, 4358391411789012426, 325123008708389849, 6837621693887290924,
- 4843721905315627004, 6010651222149276415, 5398352198963874652, 4602025990114250980,
- 1044646352569048800, 9106614159853161675, 829256115228593269, 4919284369102997000,
- 2681532557646850893, 3681559472488511871, 5307999518958214035, 6334130388442829274,
- 2658708232916537604, 1163313865052186287, 581945337509520675, 3648778920718647903,
- 4423673246306544414, 1620799783996955743, 220828013409515943, 8150384699999389761,
- 4287360518296753003, 4590000184845883843, 5513660857261085186, 6964829100392774275,
- 478991688350776035, 8746140185685648781, 228500091334420247, 1356187007457302238,
- 3019253992034194581, 3152601605678500003, 430152752706002213, 5559581553696971176,
- 4916432985369275664, 663574931734554391, 3420773838927732076, 2868348622579915573,
- 1999319134044418520, 3328689518636282723, 2587672709781371173, 1517255313529399333,
- 3092343956317362483, 3662252519007064108, 972445599196498113, 7664865435875959367,
- 1708913533482282562, 6917817162668868494, 3217629022545312900, 2570043027221707107,
- 8739788839543624613, 2488075924621352812, 4694002395387436668, 4559628481798514356,
+ 4654329375432538231, -292704475491394206, -3848998599978456535, 7623042350483453954,
+ 7725442901813263321, 9186225467561587250, -5132344747257272453, -6865740430362196008,
+ 2530936820058611833, 1636551876240043639, -3658707362519810009, 1452244145334316253,
+ -7161729655835084979, -7943791770359481772, 9108481583171221009, -3200093350120725999,
+ 5007630032676973346, 2153168792952589781, 6720334534964750538, -3181825545719981703,
+ 3433922409283786309, 2285479922797300912, 3110614940896576130, -2856812446131932915,
+ -3804580617188639299, 7163298419643543757, 4891138053923696990, 580618510277907015,
+ 1684034065251686769, 4429514767357295841, -8893025458299325803, -8103734041042601133,
+ 7177515271653460134, 4589042248470800257, -1530083407795771245, 143607045258444228,
+ 246994305896273627, -8356954712051676521, 6473547110565816071, 3092379936208876896,
+ 2058427839513754051, -4089587328327907870, 8785882556301281247, -3074039370013608197,
+ -637529855400303673, 6137678347805511274, -7152924852417805802, 5708223427705576541,
+ -3223714144396531304, 4358391411789012426, 325123008708389849, 6837621693887290924,
+ 4843721905315627004, -3212720814705499393, -3825019837890901156, 4602025990114250980,
+ 1044646352569048800, 9106614159853161675, -8394115921626182539, -4304087667751778808,
+ 2681532557646850893, 3681559472488511871, -3915372517896561773, -2889241648411946534,
+ -6564663803938238204, -8060058171802589521, 581945337509520675, 3648778920718647903,
+ -4799698790548231394, -7602572252857820065, 220828013409515943, -1072987336855386047,
+ 4287360518296753003, -4633371852008891965, 5513660857261085186, -2258542936462001533,
+ -8744380348503999773, 8746140185685648781, 228500091334420247, 1356187007457302238,
+ 3019253992034194581, 3152601605678500003, -8793219284148773595, 5559581553696971176,
+ 4916432985369275664, -8559797105120221417, -5802598197927043732, 2868348622579915573,
+ -7224052902810357288, -5894682518218493085, 2587672709781371173, -7706116723325376475,
+ 3092343956317362483, -5561119517847711700, 972445599196498113, -1558506600978816441,
+ 1708913533482282562, -2305554874185907314, -6005743014309462908, -6653329009633068701,
+ -483583197311151195, 2488075924621352812, -4529369641467339140, -4663743555056261452,
2997203966153298104, 1282559373026354493, 240113143146674385, 8665713329246516443,
- 628141331766346752, 4571950817186770476, 1472811188152235408, 7596648026010355826,
- 6091219417754424743, 7834161864828164065, 7103445518877254909, 4390861237357459201,
- 4442653864240571734, 8903482404847331368, 622261699494173647, 6037261250297213248,
- 504404948065709118, 7275215526217113061, 1011176780856001400, 2194750105623461063,
- 2623071828615234808, 5157313728073836108, 3738405111966602044, 2539767524076729570,
- 2467284396349269342, 5256026990536851868, 7841086888628396109, 6640857538655893162,
- 1202087339038317498, 2113514992440715978, 7534350895342931403, 4925284734898484745,
- 5145623771477493805, 8225140880134972332, 2719520354384050532, 9132346697815513771,
- 4332154495710163773, 7137789594094346916, 6994721091344268833, 6667228574869048934,
- 655440045726677499, 59934747298466858, 6124974028078036405, 8957774780655365418,
- 2332206071942466437, 1701056712286369627, 3154897383618636503, 1637766181387607527,
- 2460521277767576533, 197309393502684135, 643677854385267315, 2543179307861934850,
- 4350769010207485119, 4754652089410667672, 2015595502641514512, 7999059458976458608,
- 4287946071480840813, 8362686366770308971, 6486469209321732151, 3617727845841796026,
- 7554353525834302244, 4450022655153542367, 1605195740213535749, 5327014565305508387,
- 4626575813550328320, 2692222020597705149, 241045573717249868, 5098046974627094010,
- 7916882295460730264, 884817090297530579, 5329160409530630596, 7790979528857726136,
- 4955070238059373407, 4918537275422674302, 3008076183950404629, 3007769226071157901,
- 2470346235617803020, 8928702772696731736, 7856187920214445904, 4474874585391974885,
- 7900176660600710914, 2140571127916226672, 2425445057265199971, 2486055153341847830,
- 4186670094382025798, 1883939007446035042, 8808666044074867985, 3734134241178479257,
- 4065968871360089196, 6953124200385847784, 1305686814738899057, 1637739099014457647,
- 3656125660947993209, 3966759634633167020, 3106378204088556331, 6328899822778449810,
- 4565385105440252958, 1979884289539493806, 2331793186920865425, 3783206694208922581,
- 8464961209802336085, 2843963751609577687, 3030678195484896323, 4793717574095772604,
+ 628141331766346752, -4651421219668005332, -7750560848702540400, 7596648026010355826,
+ -3132152619100351065, 7834161864828164065, 7103445518877254909, 4390861237357459201,
+ -4780718172614204074, -319889632007444440, 622261699494173647, -3186110786557562560,
+ -8718967088789066690, -1948156510637662747, -8212195255998774408, -7028621931231314745,
+ 2623071828615234808, -4066058308780939700, -5484966924888173764, -6683604512778046238,
+ -6756087640505506466, 5256026990536851868, 7841086888628396109, 6640857538655893162,
+ -8021284697816458310, -7109857044414059830, -1689021141511844405, -4298087301956291063,
+ -4077748265377282003, -998231156719803476, 2719520354384050532, 9132346697815513771,
+ 4332154495710163773, -2085582442760428892, 6994721091344268833, -2556143461985726874,
+ -8567931991128098309, 59934747298466858, -3098398008776739403, -265597256199410390,
+ 2332206071942466437, -7522315324568406181, 3154897383618636503, -7585605855467168281,
+ -6762850759087199275, 197309393502684135, -8579694182469508493, 2543179307861934850,
+ 4350769010207485119, -4468719947444108136, -7207776534213261296, -1224312577878317200,
+ 4287946071480840813, 8362686366770308971, 6486469209321732151, -5605644191012979782,
+ -1669018511020473564, 4450022655153542367, -7618176296641240059, -3896357471549267421,
+ -4596796223304447488, -6531150016257070659, -8982326463137525940, -4125325062227681798,
+ -1306489741394045544, -8338554946557245229, 5329160409530630596, 7790979528857726136,
+ 4955070238059373407, -4304834761432101506, -6215295852904371179, 3007769226071157901,
+ -6753025801236972788, 8928702772696731736, 7856187920214445904, -4748497451462800923,
+ 7900176660600710914, -7082800908938549136, -6797926979589575837, -6737316883512927978,
+ 4186670094382025798, 1883939007446035042, -414705992779907823, 3734134241178479257,
+ 4065968871360089196, 6953124200385847784, -7917685222115876751, -7585632937840318161,
+ -5567246375906782599, -5256612402221608788, 3106378204088556331, -2894472214076325998,
+ 4565385105440252958, 1979884289539493806, -6891578849933910383, 3783206694208922581,
+ 8464961209802336085, 2843963751609577687, 3030678195484896323, -4429654462759003204,
4459239494808162889, 402587895800087237, 8057891408711167515, 4541888170938985079,
- 1042662272908816815, 5557303057122568958, 2647678726283249984, 2144477441549833761,
- 5806352215355387087, 7117771003473903623, 5916597177708541638, 462597715452321361,
- 8833658097025758785, 5970273481425315300, 563813119381731307, 2768349550652697015,
- 1598828206250873866, 5206393647403558110, 6235043485709261823, 3152217402014639496,
- 8469693267274066490, 125672920241807416, 5311079624024060938, 6663754932310491587,
- 8736848295048751716, 4488039774992061878, 5923302823487327109, 140891791083103236,
- 7414942793393574290, 7990420780896957397, 4317817392807076702, 3625184369705367340,
- 2740722765288122703, 5743100009702758344, 5997898640509039159, 8854493341352484163,
- 5242208035432907801, 701338899890987198, 7609280429197514109, 3020985755112334161,
- 6651322707055512866, 2635195723621160615, 5144520864246028816, 1035086515727829828,
- 1567242097116389047, 8172389260191636581, 6337820351429292273, 2163012566996458925,
- 2743190902890262681, 1906367633221323427, 6011544915663598137, 5932255307352610768,
- 2241128460406315459, 895504896216695588, 3094483003111372717, 4583857460292963101,
- 9079887171656594975, 8839289181930711403, 5762740387243057873, 4225072055348026230,
- 1838220598389033063, 3801620336801580414, 8823526620080073856, 1776617605585100335,
- 7899055018877642622, 5421679761463003041, 5521102963086275121, 4248279443559365898,
- 8735487530905098534, 1760527091573692978, 7142485049657745894, 8222656872927218123,
- 4969531564923704323, 3394475942196872480, 6424174453260338141, 359248545074932887,
- 3273651282831730598, 6797106199797138596, 3030918217665093212, 145600834617314036,
- 6036575856065626233, 740416251634527158, 7080427635449935582, 6951781370868335478,
- 399922722363687927, 294902314447253185, 7844950936339178523, 880320858634709042,
- 6192655680808675579, 411604686384710388, 9026808440365124461, 6440783557497587732,
+ 1042662272908816815, -3666068979732206850, 2647678726283249984, 2144477441549833761,
+ -3417019821499388721, -2105601033380872185, 5916597177708541638, -8760774321402454447,
+ 8833658097025758785, 5970273481425315300, 563813119381731307, -6455022486202078793,
+ 1598828206250873866, -4016978389451217698, -2988328551145513985, -6071154634840136312,
+ 8469693267274066490, 125672920241807416, -3912292412830714870, -2559617104544284221,
+ -486523741806024092, -4735332261862713930, 5923302823487327109, -9082480245771672572,
+ -1808429243461201518, 7990420780896957397, 4317817392807076702, 3625184369705367340,
+ -6482649271566653105, -3480272027152017464, -3225473396345736649, -368878695502291645,
+ -3981164001421868007, -8522033136963788610, 7609280429197514109, 3020985755112334161,
+ -2572049329799262942, 2635195723621160615, 5144520864246028816, -8188285521126945980,
+ 1567242097116389047, 8172389260191636581, -2885551685425483535, -7060359469858316883,
+ -6480181133964513127, -7317004403633452381, 6011544915663598137, 5932255307352610768,
+ 2241128460406315459, -8327867140638080220, 3094483003111372717, 4583857460292963101,
+ 9079887171656594975, -384082854924064405, -3460631649611717935, 4225072055348026230,
+ -7385151438465742745, 3801620336801580414, -399845416774701952, -7446754431269675473,
+ 7899055018877642622, 5421679761463003041, 5521102963086275121, -4975092593295409910,
+ 8735487530905098534, -7462844945281082830, -2080886987197029914, -1000715163927557685,
+ -4253840471931071485, -5828896094657903328, 6424174453260338141, 359248545074932887,
+ -5949720754023045210, -2426265837057637212, 3030918217665093212, -9077771202237461772,
+ -3186796180789149575, 740416251634527158, -2142944401404840226, 6951781370868335478,
+ 399922722363687927, -8928469722407522623, -1378421100515597285, -8343051178220066766,
+ -3030716356046100229, -8811767350470065420, 9026808440365124461, 6440783557497587732,
4615674634722404292, 539897290441580544, 2096238225866883852, 8751955639408182687,
- 1907224908052289603, 7381039757301768559, 6157238513393239656, 7749994231914157575,
+ -7316147128802486205, 7381039757301768559, 6157238513393239656, -1473377804940618233,
8629571604380892756, 5280433031239081479, 7101611890139813254, 2479018537985767835,
- 7169176924412769570, 7942066497793203302, 1357759729055557688, 2278447439451174845,
- 3625338785743880657, 6477479539006708521, 8976185375579272206, 5511371554711836120,
+ 7169176924412769570, -1281305539061572506, -7865612307799218120, 2278447439451174845,
+ 3625338785743880657, 6477479539006708521, 8976185375579272206, -3712000482142939688,
1326024180520890843, 7537449876596048829, 5464680203499696154, 3189671183162196045,
- 6346751753565857109, 241159987320630307, 3095793449658682053, 8978332846736310159,
- 2902794662273147216, 7208698530190629697, 7276901792339343736, 1732385229314443140,
- 4133292154170828382, 2918308698224194548, 1519461397937144458, 5293934712616591764,
- 4922828954023452664, 2879211533496425641, 5896236396443472108, 8465043815351752425,
- 7329020396871624740, 8915471717014488588, 2944902635677463047, 7052079073493465134,
+ 6346751753565857109, -8982212049534145501, -6127578587196093755, -245039190118465649,
+ -6320577374581628592, 7208698530190629697, 7276901792339343736, -7490986807540332668,
+ 4133292154170828382, 2918308698224194548, -7703910638917631350, -3929437324238184044,
+ -4300543082831323144, -6344160503358350167, 5896236396443472108, -758328221503023383,
+ -1894351639983151068, -307900319840287220, -6278469401177312761, -2171292963361310674,
8382142935188824023, 9103922860780351547, 4152330101494654406,
}
)
@@ -223,13 +221,18 @@ func (rng *rngSource) Seed(seed int64) {
x = seedrand(x)
u ^= int64(x)
u ^= rng_cooked[i]
- rng.vec[i] = u & _MASK
+ rng.vec[i] = u
}
}
}
// Int63 returns a non-negative pseudo-random 63-bit integer as an int64.
func (rng *rngSource) Int63() int64 {
+ return int64(rng.Uint64() & _MASK)
+}
+
+// Uint64 returns a non-negative pseudo-random 64-bit integer as an uint64.
+func (rng *rngSource) Uint64() uint64 {
rng.tap--
if rng.tap < 0 {
rng.tap += _LEN
@@ -240,7 +243,7 @@ func (rng *rngSource) Int63() int64 {
rng.feed += _LEN
}
- x := (rng.vec[rng.feed] + rng.vec[rng.tap]) & _MASK
+ x := rng.vec[rng.feed] + rng.vec[rng.tap]
rng.vec[rng.feed] = x
- return x
+ return uint64(x)
}
diff --git a/src/math/sin.go b/src/math/sin.go
index ed85f21..7a75a5f 100644
--- a/src/math/sin.go
+++ b/src/math/sin.go
@@ -140,8 +140,8 @@ func cos(x float64) float64 {
// map zeros to origin
if j&1 == 1 {
- j += 1
- y += 1
+ j++
+ y++
}
j &= 7 // octant modulo 2Pi radians (360 degrees)
if j > 3 {
@@ -200,8 +200,8 @@ func sin(x float64) float64 {
// map zeros to origin
if j&1 == 1 {
- j += 1
- y += 1
+ j++
+ y++
}
j &= 7 // octant modulo 2Pi radians (360 degrees)
// reflect in x axis
diff --git a/src/math/sin_s390x.s b/src/math/sin_s390x.s
new file mode 100644
index 0000000..5dc823c
--- /dev/null
+++ b/src/math/sin_s390x.s
@@ -0,0 +1,356 @@
+// Copyright 2016 The Go 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"
+
+// Various constants
+DATA sincosxnan<>+0(SB)/8, $0x7ff8000000000000
+GLOBL sincosxnan<>+0(SB), RODATA, $8
+DATA sincosxlim<>+0(SB)/8, $0x432921fb54442d19
+GLOBL sincosxlim<>+0(SB), RODATA, $8
+DATA sincosxadd<>+0(SB)/8, $0xc338000000000000
+GLOBL sincosxadd<>+0(SB), RODATA, $8
+DATA sincosxpi2l<>+0(SB)/8, $0.108285667392191389e-31
+GLOBL sincosxpi2l<>+0(SB), RODATA, $8
+DATA sincosxpi2m<>+0(SB)/8, $0.612323399573676480e-16
+GLOBL sincosxpi2m<>+0(SB), RODATA, $8
+DATA sincosxpi2h<>+0(SB)/8, $0.157079632679489656e+01
+GLOBL sincosxpi2h<>+0(SB), RODATA, $8
+DATA sincosrpi2<>+0(SB)/8, $0.636619772367581341e+00
+GLOBL sincosrpi2<>+0(SB), RODATA, $8
+
+// Minimax polynomial approximations
+DATA sincosc0<>+0(SB)/8, $0.100000000000000000E+01
+GLOBL sincosc0<>+0(SB), RODATA, $8
+DATA sincosc1<>+0(SB)/8, $-.499999999999999833E+00
+GLOBL sincosc1<>+0(SB), RODATA, $8
+DATA sincosc2<>+0(SB)/8, $0.416666666666625843E-01
+GLOBL sincosc2<>+0(SB), RODATA, $8
+DATA sincosc3<>+0(SB)/8, $-.138888888885498984E-02
+GLOBL sincosc3<>+0(SB), RODATA, $8
+DATA sincosc4<>+0(SB)/8, $0.248015871681607202E-04
+GLOBL sincosc4<>+0(SB), RODATA, $8
+DATA sincosc5<>+0(SB)/8, $-.275572911309937875E-06
+GLOBL sincosc5<>+0(SB), RODATA, $8
+DATA sincosc6<>+0(SB)/8, $0.208735047247632818E-08
+GLOBL sincosc6<>+0(SB), RODATA, $8
+DATA sincosc7<>+0(SB)/8, $-.112753632738365317E-10
+GLOBL sincosc7<>+0(SB), RODATA, $8
+DATA sincoss0<>+0(SB)/8, $0.100000000000000000E+01
+GLOBL sincoss0<>+0(SB), RODATA, $8
+DATA sincoss1<>+0(SB)/8, $-.166666666666666657E+00
+GLOBL sincoss1<>+0(SB), RODATA, $8
+DATA sincoss2<>+0(SB)/8, $0.833333333333309209E-02
+GLOBL sincoss2<>+0(SB), RODATA, $8
+DATA sincoss3<>+0(SB)/8, $-.198412698410701448E-03
+GLOBL sincoss3<>+0(SB), RODATA, $8
+DATA sincoss4<>+0(SB)/8, $0.275573191453906794E-05
+GLOBL sincoss4<>+0(SB), RODATA, $8
+DATA sincoss5<>+0(SB)/8, $-.250520918387633290E-07
+GLOBL sincoss5<>+0(SB), RODATA, $8
+DATA sincoss6<>+0(SB)/8, $0.160571285514715856E-09
+GLOBL sincoss6<>+0(SB), RODATA, $8
+DATA sincoss7<>+0(SB)/8, $-.753213484933210972E-12
+GLOBL sincoss7<>+0(SB), RODATA, $8
+
+// Sin returns the sine of the radian argument x.
+//
+// Special cases are:
+// Sin(±0) = ±0
+// Sin(±Inf) = NaN
+// Sin(NaN) = NaN
+// The algorithm used is minimax polynomial approximation.
+// with coefficients determined with a Remez exchange algorithm.
+
+TEXT ·sinAsm(SB),NOSPLIT,$0-16
+ FMOVD x+0(FP), F0
+ //special case Sin(±0) = ±0
+ FMOVD $(0.0), F1
+ FCMPU F0, F1
+ BEQ sinIsZero
+ WORD $0xB3120000 //ltdbr %f0,%f0
+ BLTU L17
+ FMOVD F0, F5
+L2:
+ MOVD $sincoss7<>+0(SB), R1
+ FMOVD 0(R1), F4
+ MOVD $sincoss6<>+0(SB), R1
+ FMOVD 0(R1), F1
+ MOVD $sincoss5<>+0(SB), R1
+ VLEG $0, 0(R1), V18
+ MOVD $sincoss4<>+0(SB), R1
+ FMOVD 0(R1), F6
+ MOVD $sincoss2<>+0(SB), R1
+ VLEG $0, 0(R1), V16
+ MOVD $sincoss3<>+0(SB), R1
+ FMOVD 0(R1), F7
+ MOVD $sincoss1<>+0(SB), R1
+ FMOVD 0(R1), F3
+ MOVD $sincoss0<>+0(SB), R1
+ FMOVD 0(R1), F2
+ WFCHDBS V2, V5, V2
+ BEQ L18
+ MOVD $sincosrpi2<>+0(SB), R1
+ FMOVD 0(R1), F3
+ MOVD $sincosxadd<>+0(SB), R1
+ FMOVD 0(R1), F2
+ WFMSDB V0, V3, V2, V3
+ FMOVD 0(R1), F6
+ FADD F3, F6
+ MOVD $sincosxpi2h<>+0(SB), R1
+ FMOVD 0(R1), F2
+ FMSUB F2, F6, F0, F0
+ MOVD $sincosxpi2m<>+0(SB), R1
+ FMOVD 0(R1), F4
+ FMADD F4, F6, F0, F0
+ MOVD $sincosxpi2l<>+0(SB), R1
+ WFMDB V0, V0, V1
+ FMOVD 0(R1), F7
+ WFMDB V1, V1, V2
+ WORD $0xB3CD0013 //lgdr %r1,%f3
+ MOVD $sincosxlim<>+0(SB), R2
+ WORD $0xA7110001 //tmll %r1,1
+ BEQ L6
+ FMOVD 0(R2), F0
+ WFCHDBS V0, V5, V0
+ BNE L14
+ MOVD $sincosc7<>+0(SB), R2
+ FMOVD 0(R2), F0
+ MOVD $sincosc6<>+0(SB), R2
+ FMOVD 0(R2), F4
+ MOVD $sincosc5<>+0(SB), R2
+ WFMADB V1, V0, V4, V0
+ FMOVD 0(R2), F6
+ MOVD $sincosc4<>+0(SB), R2
+ WFMADB V1, V0, V6, V0
+ FMOVD 0(R2), F4
+ MOVD $sincosc2<>+0(SB), R2
+ FMOVD 0(R2), F6
+ WFMADB V2, V4, V6, V4
+ MOVD $sincosc3<>+0(SB), R2
+ FMOVD 0(R2), F3
+ MOVD $sincosc1<>+0(SB), R2
+ WFMADB V2, V0, V3, V0
+ FMOVD 0(R2), F6
+ WFMADB V1, V4, V6, V4
+ WORD $0xA7110002 //tmll %r1,2
+ WFMADB V2, V0, V4, V0
+ MOVD $sincosc0<>+0(SB), R1
+ FMOVD 0(R1), F2
+ WFMADB V1, V0, V2, V0
+ BNE L15
+ FMOVD F0, ret+8(FP)
+ RET
+
+L6:
+ FMOVD 0(R2), F4
+ WFCHDBS V4, V5, V4
+ BNE L14
+ MOVD $sincoss7<>+0(SB), R2
+ FMOVD 0(R2), F4
+ MOVD $sincoss6<>+0(SB), R2
+ FMOVD 0(R2), F3
+ MOVD $sincoss5<>+0(SB), R2
+ WFMADB V1, V4, V3, V4
+ WFMADB V6, V7, V0, V6
+ FMOVD 0(R2), F0
+ MOVD $sincoss4<>+0(SB), R2
+ FMADD F4, F1, F0, F0
+ FMOVD 0(R2), F3
+ MOVD $sincoss2<>+0(SB), R2
+ FMOVD 0(R2), F4
+ MOVD $sincoss3<>+0(SB), R2
+ WFMADB V2, V3, V4, V3
+ FMOVD 0(R2), F4
+ MOVD $sincoss1<>+0(SB), R2
+ WFMADB V2, V0, V4, V0
+ FMOVD 0(R2), F4
+ WFMADB V1, V3, V4, V3
+ FNEG F6, F4
+ WFMADB V2, V0, V3, V2
+ WFMDB V4, V1, V0
+ WORD $0xA7110002 //tmll %r1,2
+ WFMSDB V0, V2, V6, V0
+ BNE L15
+ FMOVD F0, ret+8(FP)
+ RET
+
+L14:
+ MOVD $sincosxnan<>+0(SB), R1
+ FMOVD 0(R1), F0
+ FMOVD F0, ret+8(FP)
+ RET
+
+L18:
+ WFMDB V0, V0, V2
+ WFMADB V2, V4, V1, V4
+ WFMDB V2, V2, V1
+ WFMADB V2, V4, V18, V4
+ WFMADB V1, V6, V16, V6
+ WFMADB V1, V4, V7, V4
+ WFMADB V2, V6, V3, V6
+ FMUL F0, F2
+ WFMADB V1, V4, V6, V4
+ FMADD F4, F2, F0, F0
+ FMOVD F0, ret+8(FP)
+ RET
+
+L17:
+ FNEG F0, F5
+ BR L2
+L15:
+ FNEG F0, F0
+ FMOVD F0, ret+8(FP)
+ RET
+
+
+sinIsZero:
+ FMOVD F0, ret+8(FP)
+ RET
+
+// Cos returns the cosine of the radian argument.
+//
+// Special cases are:
+// Cos(±Inf) = NaN
+// Cos(NaN) = NaN
+// The algorithm used is minimax polynomial approximation.
+// with coefficients determined with a Remez exchange algorithm.
+
+TEXT ·cosAsm(SB),NOSPLIT,$0-16
+ FMOVD x+0(FP), F0
+ WORD $0xB3120000 //ltdbr %f0,%f0
+ BLTU L35
+ FMOVD F0, F1
+L21:
+ MOVD $sincosc7<>+0(SB), R1
+ FMOVD 0(R1), F4
+ MOVD $sincosc6<>+0(SB), R1
+ VLEG $0, 0(R1), V20
+ MOVD $sincosc5<>+0(SB), R1
+ VLEG $0, 0(R1), V18
+ MOVD $sincosc4<>+0(SB), R1
+ FMOVD 0(R1), F6
+ MOVD $sincosc2<>+0(SB), R1
+ VLEG $0, 0(R1), V16
+ MOVD $sincosc3<>+0(SB), R1
+ FMOVD 0(R1), F7
+ MOVD $sincosc1<>+0(SB), R1
+ FMOVD 0(R1), F5
+ MOVD $sincosrpi2<>+0(SB), R1
+ FMOVD 0(R1), F2
+ MOVD $sincosxadd<>+0(SB), R1
+ FMOVD 0(R1), F3
+ MOVD $sincoss0<>+0(SB), R1
+ WFMSDB V0, V2, V3, V2
+ FMOVD 0(R1), F3
+ WFCHDBS V3, V1, V3
+ WORD $0xB3CD0012 //lgdr %r1,%f2
+ BEQ L36
+ MOVD $sincosxadd<>+0(SB), R2
+ FMOVD 0(R2), F4
+ FADD F2, F4
+ MOVD $sincosxpi2h<>+0(SB), R2
+ FMOVD 0(R2), F2
+ WFMSDB V4, V2, V0, V2
+ MOVD $sincosxpi2m<>+0(SB), R2
+ FMOVD 0(R2), F0
+ WFMADB V4, V0, V2, V0
+ MOVD $sincosxpi2l<>+0(SB), R2
+ WFMDB V0, V0, V2
+ FMOVD 0(R2), F5
+ WFMDB V2, V2, V6
+ MOVD $sincosxlim<>+0(SB), R2
+ WORD $0xA7110001 //tmll %r1,1
+ BNE L25
+ FMOVD 0(R2), F0
+ WFCHDBS V0, V1, V0
+ BNE L33
+ MOVD $sincosc7<>+0(SB), R2
+ FMOVD 0(R2), F0
+ MOVD $sincosc6<>+0(SB), R2
+ FMOVD 0(R2), F4
+ MOVD $sincosc5<>+0(SB), R2
+ WFMADB V2, V0, V4, V0
+ FMOVD 0(R2), F1
+ MOVD $sincosc4<>+0(SB), R2
+ WFMADB V2, V0, V1, V0
+ FMOVD 0(R2), F4
+ MOVD $sincosc2<>+0(SB), R2
+ FMOVD 0(R2), F1
+ WFMADB V6, V4, V1, V4
+ MOVD $sincosc3<>+0(SB), R2
+ FMOVD 0(R2), F3
+ MOVD $sincosc1<>+0(SB), R2
+ WFMADB V6, V0, V3, V0
+ FMOVD 0(R2), F1
+ WFMADB V2, V4, V1, V4
+ WORD $0xA7110002 //tmll %r1,2
+ WFMADB V6, V0, V4, V0
+ MOVD $sincosc0<>+0(SB), R1
+ FMOVD 0(R1), F4
+ WFMADB V2, V0, V4, V0
+ BNE L34
+ FMOVD F0, ret+8(FP)
+ RET
+
+L25:
+ FMOVD 0(R2), F3
+ WFCHDBS V3, V1, V1
+ BNE L33
+ MOVD $sincoss7<>+0(SB), R2
+ FMOVD 0(R2), F1
+ MOVD $sincoss6<>+0(SB), R2
+ FMOVD 0(R2), F3
+ MOVD $sincoss5<>+0(SB), R2
+ WFMADB V2, V1, V3, V1
+ FMOVD 0(R2), F3
+ MOVD $sincoss4<>+0(SB), R2
+ WFMADB V2, V1, V3, V1
+ FMOVD 0(R2), F3
+ MOVD $sincoss2<>+0(SB), R2
+ FMOVD 0(R2), F7
+ WFMADB V6, V3, V7, V3
+ MOVD $sincoss3<>+0(SB), R2
+ FMADD F5, F4, F0, F0
+ FMOVD 0(R2), F4
+ MOVD $sincoss1<>+0(SB), R2
+ FMADD F1, F6, F4, F4
+ FMOVD 0(R2), F1
+ FMADD F3, F2, F1, F1
+ FMUL F0, F2
+ WFMADB V6, V4, V1, V6
+ WORD $0xA7110002 //tmll %r1,2
+ FMADD F6, F2, F0, F0
+ BNE L34
+ FMOVD F0, ret+8(FP)
+ RET
+
+L33:
+ MOVD $sincosxnan<>+0(SB), R1
+ FMOVD 0(R1), F0
+ FMOVD F0, ret+8(FP)
+ RET
+
+L36:
+ FMUL F0, F0
+ MOVD $sincosc0<>+0(SB), R1
+ WFMDB V0, V0, V1
+ WFMADB V0, V4, V20, V4
+ WFMADB V1, V6, V16, V6
+ WFMADB V0, V4, V18, V4
+ WFMADB V0, V6, V5, V6
+ WFMADB V1, V4, V7, V4
+ FMOVD 0(R1), F2
+ WFMADB V1, V4, V6, V4
+ WFMADB V0, V4, V2, V0
+ FMOVD F0, ret+8(FP)
+ RET
+
+L35:
+ FNEG F0, F1
+ BR L21
+L34:
+ FNEG F0, F0
+ FMOVD F0, ret+8(FP)
+ RET
diff --git a/src/math/sincos.go b/src/math/sincos.go
index 7180303..6e663d0 100644
--- a/src/math/sincos.go
+++ b/src/math/sincos.go
@@ -40,8 +40,8 @@ func sincos(x float64) (sin, cos float64) {
y := float64(j) // integer part of x/(Pi/4), as float
if j&1 == 1 { // map zeros to origin
- j += 1
- y += 1
+ j++
+ y++
}
j &= 7 // octant modulo 2Pi radians (360 degrees)
if j > 3 { // reflect in x axis
diff --git a/src/math/sinh.go b/src/math/sinh.go
index 139b911..2bdd7b1 100644
--- a/src/math/sinh.go
+++ b/src/math/sinh.go
@@ -22,7 +22,9 @@ package math
// Sinh(±0) = ±0
// Sinh(±Inf) = ±Inf
// Sinh(NaN) = NaN
-func Sinh(x float64) float64 {
+func Sinh(x float64) float64
+
+func sinh(x float64) float64 {
// The coefficients are #2029 from Hart & Cheney. (20.36D)
const (
P0 = -0.6307673640497716991184787251e+6
@@ -66,7 +68,9 @@ func Sinh(x float64) float64 {
// Cosh(±0) = 1
// Cosh(±Inf) = +Inf
// Cosh(NaN) = NaN
-func Cosh(x float64) float64 {
+func Cosh(x float64) float64
+
+func cosh(x float64) float64 {
if x < 0 {
x = -x
}
diff --git a/src/math/sinh_s390x.s b/src/math/sinh_s390x.s
new file mode 100644
index 0000000..e492415
--- /dev/null
+++ b/src/math/sinh_s390x.s
@@ -0,0 +1,261 @@
+// Copyright 2016 The Go 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 sinhrodataL21<>+0(SB)/8, $0.231904681384629956E-16
+DATA sinhrodataL21<>+8(SB)/8, $0.693147180559945286E+00
+DATA sinhrodataL21<>+16(SB)/8, $704.E0
+GLOBL sinhrodataL21<>+0(SB), RODATA, $24
+DATA sinhrlog2<>+0(SB)/8, $0x3ff7154760000000
+GLOBL sinhrlog2<>+0(SB), RODATA, $8
+DATA sinhxinf<>+0(SB)/8, $0x7ff0000000000000
+GLOBL sinhxinf<>+0(SB), RODATA, $8
+DATA sinhxinit<>+0(SB)/8, $0x3ffb504f333f9de6
+GLOBL sinhxinit<>+0(SB), RODATA, $8
+DATA sinhxlim1<>+0(SB)/8, $800.E0
+GLOBL sinhxlim1<>+0(SB), RODATA, $8
+DATA sinhxadd<>+0(SB)/8, $0xc3200001610007fb
+GLOBL sinhxadd<>+0(SB), RODATA, $8
+DATA sinhx4ff<>+0(SB)/8, $0x4ff0000000000000
+GLOBL sinhx4ff<>+0(SB), RODATA, $8
+
+// Minimax polynomial approximations
+DATA sinhe0<>+0(SB)/8, $0.11715728752538099300E+01
+GLOBL sinhe0<>+0(SB), RODATA, $8
+DATA sinhe1<>+0(SB)/8, $0.11715728752538099300E+01
+GLOBL sinhe1<>+0(SB), RODATA, $8
+DATA sinhe2<>+0(SB)/8, $0.58578643762688526692E+00
+GLOBL sinhe2<>+0(SB), RODATA, $8
+DATA sinhe3<>+0(SB)/8, $0.19526214587563004497E+00
+GLOBL sinhe3<>+0(SB), RODATA, $8
+DATA sinhe4<>+0(SB)/8, $0.48815536475176217404E-01
+GLOBL sinhe4<>+0(SB), RODATA, $8
+DATA sinhe5<>+0(SB)/8, $0.97631072948627397816E-02
+GLOBL sinhe5<>+0(SB), RODATA, $8
+DATA sinhe6<>+0(SB)/8, $0.16271839297756073153E-02
+GLOBL sinhe6<>+0(SB), RODATA, $8
+DATA sinhe7<>+0(SB)/8, $0.23245485387271142509E-03
+GLOBL sinhe7<>+0(SB), RODATA, $8
+DATA sinhe8<>+0(SB)/8, $0.29080955860869629131E-04
+GLOBL sinhe8<>+0(SB), RODATA, $8
+DATA sinhe9<>+0(SB)/8, $0.32311267157667725278E-05
+GLOBL sinhe9<>+0(SB), RODATA, $8
+
+// Sinh returns the hyperbolic sine of the argument.
+//
+// Special cases are:
+// Sinh(±0) = ±0
+// Sinh(±Inf) = ±Inf
+// Sinh(NaN) = NaN
+// The algorithm used is minimax polynomial approximation
+// with coefficients determined with a Remez exchange algorithm.
+
+TEXT ·sinhAsm(SB),NOSPLIT,$0-16
+ FMOVD x+0(FP), F0
+ //specail case Sinh(±0) = ±0
+ FMOVD $(0.0), F1
+ FCMPU F0, F1
+ BEQ sinhIsZero
+ //specail case Sinh(±Inf = ±Inf
+ FMOVD $1.797693134862315708145274237317043567981e+308, F1
+ FCMPU F1, F0
+ BLEU sinhIsInf
+ FMOVD $-1.797693134862315708145274237317043567981e+308, F1
+ FCMPU F1, F0
+ BGT sinhIsInf
+
+ MOVD $sinhrodataL21<>+0(SB), R5
+ WORD $0xB3120000 //ltdbr %f0,%f0
+ MOVD sinhxinit<>+0(SB), R1
+ FMOVD F0, F4
+ MOVD R1, R3
+ BLTU L19
+ FMOVD F0, F2
+L2:
+ WORD $0xED205010 //cdb %f2,.L22-.L21(%r5)
+ BYTE $0x00
+ BYTE $0x19
+ BGE L15 //jnl .L15
+ BVS L15
+ WFCEDBS V2, V2, V0
+ BEQ L20
+L12:
+ FMOVD F4, F0
+ FMOVD F0, ret+8(FP)
+ RET
+
+L15:
+ WFCEDBS V2, V2, V0
+ BVS L12
+ MOVD $sinhxlim1<>+0(SB), R2
+ FMOVD 0(R2), F0
+ WFCHDBS V0, V2, V0
+ BEQ L6
+ WFCHEDBS V4, V2, V6
+ MOVD $sinhxinf<>+0(SB), R1
+ FMOVD 0(R1), F0
+ BNE LEXITTAGsinh
+ WFCHDBS V2, V4, V2
+ BNE L16
+ FNEG F0, F0
+ FMOVD F0, ret+8(FP)
+ RET
+
+L19:
+ FNEG F0, F2
+ BR L2
+L6:
+ MOVD $sinhxadd<>+0(SB), R2
+ FMOVD 0(R2), F0
+ MOVD sinhrlog2<>+0(SB), R2
+ WORD $0xB3C10062 //ldgr %f6,%r2
+ WFMSDB V4, V6, V0, V16
+ FMOVD sinhrodataL21<>+8(SB), F6
+ WFADB V0, V16, V0
+ FMOVD sinhrodataL21<>+0(SB), F3
+ WFMSDB V0, V6, V4, V6
+ MOVD $sinhe9<>+0(SB), R2
+ WFMADB V0, V3, V6, V0
+ FMOVD 0(R2), F1
+ MOVD $sinhe7<>+0(SB), R2
+ WFMDB V0, V0, V6
+ FMOVD 0(R2), F5
+ MOVD $sinhe8<>+0(SB), R2
+ FMOVD 0(R2), F3
+ MOVD $sinhe6<>+0(SB), R2
+ WFMADB V6, V1, V5, V1
+ FMOVD 0(R2), F5
+ MOVD $sinhe5<>+0(SB), R2
+ FMOVD 0(R2), F7
+ MOVD $sinhe3<>+0(SB), R2
+ WFMADB V6, V3, V5, V3
+ FMOVD 0(R2), F5
+ MOVD $sinhe4<>+0(SB), R2
+ WFMADB V6, V7, V5, V7
+ FMOVD 0(R2), F5
+ MOVD $sinhe2<>+0(SB), R2
+ VLEG $0, 0(R2), V20
+ WFMDB V6, V6, V18
+ WFMADB V6, V5, V20, V5
+ WFMADB V1, V18, V7, V1
+ FNEG F0, F0
+ WFMADB V3, V18, V5, V3
+ MOVD $sinhe1<>+0(SB), R3
+ WFCEDBS V2, V4, V2
+ FMOVD 0(R3), F5
+ MOVD $sinhe0<>+0(SB), R3
+ WFMADB V6, V1, V5, V1
+ FMOVD 0(R3), F5
+ VLGVG $0, V16, R2
+ WFMADB V6, V3, V5, V6
+ RLL $3, R2, R2
+ WORD $0xEC12000F //risbgn %r1,%r2,64-64+0,64-64+0+16-1,64-0-16
+ BYTE $0x30
+ BYTE $0x59
+ BEQ L9
+ WFMSDB V0, V1, V6, V0
+ MOVD $sinhx4ff<>+0(SB), R3
+ FNEG F0, F0
+ FMOVD 0(R3), F2
+ FMUL F2, F0
+ ANDW $0xFFFF, R2
+ WORD $0xA53FEFB6 //llill %r3,61366
+ SUBW R2, R3, R2
+ 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
+ FMUL F2, F0
+ FMOVD F0, ret+8(FP)
+ RET
+
+L20:
+ MOVD $sinhxadd<>+0(SB), R2
+ FMOVD 0(R2), F2
+ MOVD sinhrlog2<>+0(SB), R2
+ WORD $0xB3C10002 //ldgr %f0,%r2
+ WFMSDB V4, V0, V2, V6
+ FMOVD sinhrodataL21<>+8(SB), F0
+ FADD F6, F2
+ MOVD $sinhe9<>+0(SB), R2
+ FMSUB F0, F2, F4, F4
+ FMOVD 0(R2), F1
+ FMOVD sinhrodataL21<>+0(SB), F3
+ MOVD $sinhe7<>+0(SB), R2
+ FMADD F3, F2, F4, 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
+ 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
+ MOVD $sinhe5<>+0(SB), R1
+ WFMADB V2, V3, V5, V3
+ FMOVD 0(R1), F5
+ MOVD $sinhe3<>+0(SB), R1
+ FMOVD 0(R1), F6
+ WFMDB V2, V2, V7
+ WFMADB V2, V5, V6, V5
+ WORD $0xA7487FB6 //lhi %r4,32694
+ FNEG F4, F4
+ ANDW $0xFFFF, R2
+ SUBW R2, R4, R2
+ 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
+ WFADB V0, V6, V16
+ MOVD $sinhe4<>+0(SB), R1
+ WFMADB V1, V7, V5, V1
+ WFMDB V4, V16, V4
+ FMOVD 0(R1), F5
+ MOVD $sinhe2<>+0(SB), R1
+ VLEG $0, 0(R1), V16
+ MOVD $sinhe1<>+0(SB), R1
+ WFMADB V2, V5, V16, V5
+ VLEG $0, 0(R1), V16
+ WFMADB V3, V7, V5, V3
+ WFMADB V2, V1, V16, V1
+ FSUB F6, F0
+ FMUL F1, F4
+ MOVD $sinhe0<>+0(SB), R1
+ FMOVD 0(R1), F6
+ WFMADB V2, V3, V6, V2
+ WFMADB V0, V2, V4, V0
+ FMOVD F0, ret+8(FP)
+ RET
+
+L9:
+ WFMADB V0, V1, V6, V0
+ MOVD $sinhx4ff<>+0(SB), R3
+ FMOVD 0(R3), F2
+ FMUL F2, F0
+ WORD $0xA72AF000 //ahi %r2,-4096
+ 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
+ FMUL F2, F0
+ FMOVD F0, ret+8(FP)
+ RET
+
+L16:
+ FMOVD F0, ret+8(FP)
+ RET
+
+LEXITTAGsinh:
+sinhIsInf:
+sinhIsZero:
+ FMOVD F0, ret+8(FP)
+ RET
diff --git a/src/math/sinh_stub.s b/src/math/sinh_stub.s
new file mode 100644
index 0000000..4caaa0c
--- /dev/null
+++ b/src/math/sinh_stub.s
@@ -0,0 +1,17 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build 386 amd64 amd64p32 arm
+
+#include "textflag.h"
+
+TEXT ·Sinh(SB),NOSPLIT,$0
+ JMP ·sinh(SB)
+
+TEXT ·Cosh(SB),NOSPLIT,$0
+ JMP ·cosh(SB)
+
+TEXT ·Tanh(SB),NOSPLIT,$0
+ JMP ·tanh(SB)
+
diff --git a/src/math/sqrt_amd64.s b/src/math/sqrt_amd64.s
index f8d825d..1102903 100644
--- a/src/math/sqrt_amd64.s
+++ b/src/math/sqrt_amd64.s
@@ -5,7 +5,8 @@
#include "textflag.h"
// func Sqrt(x float64) float64
-TEXT ·Sqrt(SB),NOSPLIT,$0
+TEXT ·Sqrt(SB), NOSPLIT, $0
+ XORPS X0, X0 // break dependency
SQRTSD x+0(FP), X0
- MOVSD X0, ret+8(FP)
+ MOVSD X0, ret+8(FP)
RET
diff --git a/src/math/sqrt_mipsx.s b/src/math/sqrt_mipsx.s
new file mode 100644
index 0000000..1b27d49
--- /dev/null
+++ b/src/math/sqrt_mipsx.s
@@ -0,0 +1,14 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build mips mipsle
+
+#include "textflag.h"
+
+// func Sqrt(x float64) float64
+TEXT ·Sqrt(SB),NOSPLIT,$0
+ MOVD x+0(FP), F0
+ SQRTD F0, F0
+ MOVD F0, ret+8(FP)
+ RET
diff --git a/src/math/stubs_arm64.s b/src/math/stubs_arm64.s
index 04de911..d8c9aa8 100644
--- a/src/math/stubs_arm64.s
+++ b/src/math/stubs_arm64.s
@@ -18,33 +18,18 @@ TEXT ·Atan2(SB),NOSPLIT,$0
TEXT ·Atan(SB),NOSPLIT,$0
B ·atan(SB)
-TEXT ·Dim(SB),NOSPLIT,$0
- B ·dim(SB)
-
-TEXT ·Min(SB),NOSPLIT,$0
- B ·min(SB)
-
-TEXT ·Max(SB),NOSPLIT,$0
- B ·max(SB)
-
TEXT ·Exp2(SB),NOSPLIT,$0
B ·exp2(SB)
+TEXT ·Cosh(SB),NOSPLIT,$0
+ B ·cosh(SB)
+
TEXT ·Expm1(SB),NOSPLIT,$0
B ·expm1(SB)
TEXT ·Exp(SB),NOSPLIT,$0
B ·exp(SB)
-TEXT ·Floor(SB),NOSPLIT,$0
- B ·floor(SB)
-
-TEXT ·Ceil(SB),NOSPLIT,$0
- B ·ceil(SB)
-
-TEXT ·Trunc(SB),NOSPLIT,$0
- B ·trunc(SB)
-
TEXT ·Frexp(SB),NOSPLIT,$0
B ·frexp(SB)
@@ -66,9 +51,6 @@ TEXT ·Log1p(SB),NOSPLIT,$0
TEXT ·Log(SB),NOSPLIT,$0
B ·log(SB)
-TEXT ·Modf(SB),NOSPLIT,$0
- B ·modf(SB)
-
TEXT ·Mod(SB),NOSPLIT,$0
B ·mod(SB)
@@ -81,8 +63,14 @@ TEXT ·Sincos(SB),NOSPLIT,$0
TEXT ·Sin(SB),NOSPLIT,$0
B ·sin(SB)
+TEXT ·Sinh(SB),NOSPLIT,$0
+ B ·sinh(SB)
+
TEXT ·Cos(SB),NOSPLIT,$0
B ·cos(SB)
TEXT ·Tan(SB),NOSPLIT,$0
B ·tan(SB)
+
+TEXT ·Tanh(SB),NOSPLIT,$0
+ B ·tanh(SB)
diff --git a/src/math/stubs_mips64x.s b/src/math/stubs_mips64x.s
index 97e6e4c..21df5cc 100644
--- a/src/math/stubs_mips64x.s
+++ b/src/math/stubs_mips64x.s
@@ -81,11 +81,20 @@ TEXT ·Sincos(SB),NOSPLIT,$0
TEXT ·Sin(SB),NOSPLIT,$0
JMP ·sin(SB)
+TEXT ·Sinh(SB),NOSPLIT,$0
+ JMP ·sinh(SB)
+
TEXT ·Cos(SB),NOSPLIT,$0
JMP ·cos(SB)
+TEXT ·Cosh(SB),NOSPLIT,$0
+ JMP ·cosh(SB)
+
TEXT ·Sqrt(SB),NOSPLIT,$0
JMP ·sqrt(SB)
TEXT ·Tan(SB),NOSPLIT,$0
JMP ·tan(SB)
+
+TEXT ·Tanh(SB),NOSPLIT,$0
+ JMP ·tanh(SB)
diff --git a/src/math/stubs_mipsx.s b/src/math/stubs_mipsx.s
new file mode 100644
index 0000000..b869768
--- /dev/null
+++ b/src/math/stubs_mipsx.s
@@ -0,0 +1,98 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build mips mipsle
+
+#include "textflag.h"
+
+TEXT ·Asin(SB),NOSPLIT,$0
+ JMP ·asin(SB)
+
+TEXT ·Acos(SB),NOSPLIT,$0
+ JMP ·acos(SB)
+
+TEXT ·Atan2(SB),NOSPLIT,$0
+ JMP ·atan2(SB)
+
+TEXT ·Atan(SB),NOSPLIT,$0
+ JMP ·atan(SB)
+
+TEXT ·Dim(SB),NOSPLIT,$0
+ JMP ·dim(SB)
+
+TEXT ·Min(SB),NOSPLIT,$0
+ JMP ·min(SB)
+
+TEXT ·Max(SB),NOSPLIT,$0
+ JMP ·max(SB)
+
+TEXT ·Exp2(SB),NOSPLIT,$0
+ JMP ·exp2(SB)
+
+TEXT ·Expm1(SB),NOSPLIT,$0
+ JMP ·expm1(SB)
+
+TEXT ·Exp(SB),NOSPLIT,$0
+ JMP ·exp(SB)
+
+TEXT ·Floor(SB),NOSPLIT,$0
+ JMP ·floor(SB)
+
+TEXT ·Ceil(SB),NOSPLIT,$0
+ JMP ·ceil(SB)
+
+TEXT ·Trunc(SB),NOSPLIT,$0
+ JMP ·trunc(SB)
+
+TEXT ·Frexp(SB),NOSPLIT,$0
+ JMP ·frexp(SB)
+
+TEXT ·Hypot(SB),NOSPLIT,$0
+ JMP ·hypot(SB)
+
+TEXT ·Ldexp(SB),NOSPLIT,$0
+ JMP ·ldexp(SB)
+
+TEXT ·Log10(SB),NOSPLIT,$0
+ JMP ·log10(SB)
+
+TEXT ·Log2(SB),NOSPLIT,$0
+ JMP ·log2(SB)
+
+TEXT ·Log1p(SB),NOSPLIT,$0
+ JMP ·log1p(SB)
+
+TEXT ·Log(SB),NOSPLIT,$0
+ JMP ·log(SB)
+
+TEXT ·Modf(SB),NOSPLIT,$0
+ JMP ·modf(SB)
+
+TEXT ·Mod(SB),NOSPLIT,$0
+ JMP ·mod(SB)
+
+TEXT ·Remainder(SB),NOSPLIT,$0
+ JMP ·remainder(SB)
+
+TEXT ·Sincos(SB),NOSPLIT,$0
+ JMP ·sincos(SB)
+
+TEXT ·Sin(SB),NOSPLIT,$0
+ JMP ·sin(SB)
+
+TEXT ·Sinh(SB),NOSPLIT,$0
+ JMP ·sinh(SB)
+
+TEXT ·Cos(SB),NOSPLIT,$0
+ JMP ·cos(SB)
+
+TEXT ·Cosh(SB),NOSPLIT,$0
+ JMP ·cosh(SB)
+
+TEXT ·Tan(SB),NOSPLIT,$0
+ JMP ·tan(SB)
+
+TEXT ·Tanh(SB),NOSPLIT,$0
+ JMP ·tanh(SB)
+
diff --git a/src/math/stubs_ppc64x.s b/src/math/stubs_ppc64x.s
index a57357e..b622016 100644
--- a/src/math/stubs_ppc64x.s
+++ b/src/math/stubs_ppc64x.s
@@ -36,15 +36,6 @@ TEXT ·Expm1(SB),NOSPLIT,$0
TEXT ·Exp(SB),NOSPLIT,$0
BR ·exp(SB)
-TEXT ·Floor(SB),NOSPLIT,$0
- BR ·floor(SB)
-
-TEXT ·Ceil(SB),NOSPLIT,$0
- BR ·ceil(SB)
-
-TEXT ·Trunc(SB),NOSPLIT,$0
- BR ·trunc(SB)
-
TEXT ·Frexp(SB),NOSPLIT,$0
BR ·frexp(SB)
@@ -81,8 +72,17 @@ TEXT ·Sincos(SB),NOSPLIT,$0
TEXT ·Sin(SB),NOSPLIT,$0
BR ·sin(SB)
+TEXT ·Sinh(SB),NOSPLIT,$0
+ BR ·sinh(SB)
+
TEXT ·Cos(SB),NOSPLIT,$0
BR ·cos(SB)
+TEXT ·Cosh(SB),NOSPLIT,$0
+ BR ·cosh(SB)
+
TEXT ·Tan(SB),NOSPLIT,$0
BR ·tan(SB)
+
+TEXT ·Tanh(SB),NOSPLIT,$0
+ BR ·tanh(SB)
diff --git a/src/math/stubs_s390x.s b/src/math/stubs_s390x.s
index 7686844..8da55c5 100644
--- a/src/math/stubs_s390x.s
+++ b/src/math/stubs_s390x.s
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-#include "../runtime/textflag.h"
+#include "textflag.h"
TEXT ·Asin(SB),NOSPLIT,$0
BR ·asin(SB)
@@ -25,15 +25,6 @@ TEXT ·Expm1(SB),NOSPLIT,$0
TEXT ·Exp(SB),NOSPLIT,$0
BR ·exp(SB)
-TEXT ·Floor(SB),NOSPLIT,$0
- BR ·floor(SB)
-
-TEXT ·Ceil(SB),NOSPLIT,$0
- BR ·ceil(SB)
-
-TEXT ·Trunc(SB),NOSPLIT,$0
- BR ·trunc(SB)
-
TEXT ·Frexp(SB),NOSPLIT,$0
BR ·frexp(SB)
@@ -43,9 +34,6 @@ TEXT ·Hypot(SB),NOSPLIT,$0
TEXT ·Ldexp(SB),NOSPLIT,$0
BR ·ldexp(SB)
-TEXT ·Log10(SB),NOSPLIT,$0
- BR ·log10(SB)
-
TEXT ·Log2(SB),NOSPLIT,$0
BR ·log2(SB)
@@ -67,11 +55,154 @@ TEXT ·Remainder(SB),NOSPLIT,$0
TEXT ·Sincos(SB),NOSPLIT,$0
BR ·sincos(SB)
-TEXT ·Sin(SB),NOSPLIT,$0
- BR ·sin(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
+ XC $24, 0(R1), 0(R1) // clear the storage
+ MOVD $2, R0 // R0 is the number of double words stored -1
+ WORD $0xB2B01000 // STFLE 0(R1)
+ XOR R0, R0 // reset the value of R0
+ MOVBZ z-8(SP), R1
+ AND $0x40, R1
+ BEQ novector
+vectorinstalled:
+ // check if the vector instruction has been enabled
+ VLEIB $0, $0xF, V16
+ VLGVB $0, V16, R1
+ CMPBNE R1, $0xF, novector
+ MOVB $1, ret+0(FP) // have vx
+ RET
+novector:
+ MOVB $0, ret+0(FP) // no vx
+ RET
+
+TEXT ·Log10(SB),NOSPLIT,$0
+ 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 $·log10(SB), R2
+ MOVD R2, 0(R1)
+ BR ·log10(SB)
+vectorimpl:
+ 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)
+
TEXT ·Cos(SB),NOSPLIT,$0
- BR ·cos(SB)
+ 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 $·cos(SB), R2
+ MOVD R2, 0(R1)
+ BR ·cos(SB)
+vectorimpl:
+ 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)
+
+
+TEXT ·Cosh(SB),NOSPLIT,$0
+ 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 $·cosh(SB), R2
+ MOVD R2, 0(R1)
+ BR ·cosh(SB)
+vectorimpl:
+ 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)
+
+
+TEXT ·Sin(SB),NOSPLIT,$0
+ 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 $·sin(SB), R2
+ MOVD R2, 0(R1)
+ BR ·sin(SB)
+vectorimpl:
+ 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)
+
+
+TEXT ·Sinh(SB),NOSPLIT,$0
+ 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 $·sinh(SB), R2
+ MOVD R2, 0(R1)
+ BR ·sinh(SB)
+vectorimpl:
+ 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)
+
+
+
+TEXT ·Tanh(SB),NOSPLIT,$0
+ 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 $·tanh(SB), R2
+ MOVD R2, 0(R1)
+ BR ·tanh(SB)
+vectorimpl:
+ 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)
+
-TEXT ·Tan(SB),NOSPLIT,$0
- BR ·tan(SB)
diff --git a/src/math/tan.go b/src/math/tan.go
index 285eff1..aa2fb37 100644
--- a/src/math/tan.go
+++ b/src/math/tan.go
@@ -108,8 +108,8 @@ func tan(x float64) float64 {
/* map zeros and singularities to origin */
if j&1 == 1 {
- j += 1
- y += 1
+ j++
+ y++
}
z := ((x - y*PI4A) - y*PI4B) - y*PI4C
diff --git a/src/math/tanh.go b/src/math/tanh.go
index cf0ffa1..eaa0e4c 100644
--- a/src/math/tanh.go
+++ b/src/math/tanh.go
@@ -71,7 +71,9 @@ var tanhQ = [...]float64{
// Tanh(±0) = ±0
// Tanh(±Inf) = ±1
// Tanh(NaN) = NaN
-func Tanh(x float64) float64 {
+func Tanh(x float64) float64
+
+func tanh(x float64) float64 {
const MAXLOG = 8.8029691931113054295988e+01 // log(2**127)
z := Abs(x)
switch {
diff --git a/src/math/tanh_s390x.s b/src/math/tanh_s390x.s
new file mode 100644
index 0000000..1b76c14
--- /dev/null
+++ b/src/math/tanh_s390x.s
@@ -0,0 +1,173 @@
+// Copyright 2016 The Go 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 tanhrodataL18<>+0(SB)/8, $-1.0
+DATA tanhrodataL18<>+8(SB)/8, $-2.0
+DATA tanhrodataL18<>+16(SB)/8, $1.0
+DATA tanhrodataL18<>+24(SB)/8, $2.0
+DATA tanhrodataL18<>+32(SB)/8, $0.20000000000000011868E+01
+DATA tanhrodataL18<>+40(SB)/8, $0.13333333333333341256E+01
+DATA tanhrodataL18<>+48(SB)/8, $0.26666666663549111502E+00
+DATA tanhrodataL18<>+56(SB)/8, $0.66666666658721844678E+00
+DATA tanhrodataL18<>+64(SB)/8, $0.88890217768964374821E-01
+DATA tanhrodataL18<>+72(SB)/8, $0.25397199429103821138E-01
+DATA tanhrodataL18<>+80(SB)/8, $-.346573590279972643E+00
+DATA tanhrodataL18<>+88(SB)/8, $20.E0
+GLOBL tanhrodataL18<>+0(SB), RODATA, $96
+
+// Constants
+DATA tanhrlog2<>+0(SB)/8, $0x4007154760000000
+GLOBL tanhrlog2<>+0(SB), RODATA, $8
+DATA tanhxadd<>+0(SB)/8, $0xc2f0000100003ff0
+GLOBL tanhxadd<>+0(SB), RODATA, $8
+DATA tanhxmone<>+0(SB)/8, $-1.0
+GLOBL tanhxmone<>+0(SB), RODATA, $8
+DATA tanhxzero<>+0(SB)/8, $0
+GLOBL tanhxzero<>+0(SB), RODATA, $8
+
+// Polynomial coefficients
+DATA tanhtab<>+0(SB)/8, $0.000000000000000000E+00
+DATA tanhtab<>+8(SB)/8, $-.171540871271399150E-01
+DATA tanhtab<>+16(SB)/8, $-.306597931864376363E-01
+DATA tanhtab<>+24(SB)/8, $-.410200970469965021E-01
+DATA tanhtab<>+32(SB)/8, $-.486343079978231466E-01
+DATA tanhtab<>+40(SB)/8, $-.538226193725835820E-01
+DATA tanhtab<>+48(SB)/8, $-.568439602538111520E-01
+DATA tanhtab<>+56(SB)/8, $-.579091847395528847E-01
+DATA tanhtab<>+64(SB)/8, $-.571909584179366341E-01
+DATA tanhtab<>+72(SB)/8, $-.548312665987204407E-01
+DATA tanhtab<>+80(SB)/8, $-.509471843643441085E-01
+DATA tanhtab<>+88(SB)/8, $-.456353588448863359E-01
+DATA tanhtab<>+96(SB)/8, $-.389755254243262365E-01
+DATA tanhtab<>+104(SB)/8, $-.310332908285244231E-01
+DATA tanhtab<>+112(SB)/8, $-.218623539150173528E-01
+DATA tanhtab<>+120(SB)/8, $-.115062908917949451E-01
+GLOBL tanhtab<>+0(SB), RODATA, $128
+
+// Tanh returns the hyperbolic tangent of the argument.
+//
+// Special cases are:
+// Tanh(±0) = ±0
+// Tanh(±Inf) = ±1
+// Tanh(NaN) = NaN
+// The algorithm used is minimax polynomial approximation using a table of
+// polynomial coefficients determined with a Remez exchange algorithm.
+
+TEXT ·tanhAsm(SB),NOSPLIT,$0-16
+ FMOVD x+0(FP), F0
+ //specail case Tanh(±0) = ±0
+ FMOVD $(0.0), F1
+ FCMPU F0, F1
+ BEQ tanhIsZero
+ MOVD $tanhrodataL18<>+0(SB), R5
+ WORD $0xB3120000 //ltdbr %f0,%f0
+ MOVD $0x4034000000000000, R1
+ BLTU L15
+ FMOVD F0, F1
+L2:
+ MOVD $tanhxadd<>+0(SB), R2
+ FMOVD 0(R2), F2
+ MOVD tanhrlog2<>+0(SB), R2
+ WORD $0xB3C10042 //ldgr %f4,%r2
+ WFMSDB V0, V4, V2, V4
+ MOVD $tanhtab<>+0(SB), R3
+ WORD $0xB3CD0024 //lgdr %r2,%f4
+ WORD $0xEC4239BC //risbg %r4,%r2,57,128+60,3
+ BYTE $0x03
+ BYTE $0x55
+ WORD $0xED105058 //cdb %f1,.L19-.L18(%r5)
+ BYTE $0x00
+ BYTE $0x19
+ WORD $0xEC12000F //risbgn %r1,%r2,64-64+0,64-64+0+16-1,64-0-16
+ BYTE $0x30
+ BYTE $0x59
+ WORD $0x68543000 //ld %f5,0(%r4,%r3)
+ WORD $0xB3C10061 //ldgr %f6,%r1
+ BLT L3
+ MOVD $tanhxzero<>+0(SB), R1
+ FMOVD 0(R1), F2
+ WFCHDBS V0, V2, V4
+ BEQ L9
+ WFCHDBS V2, V0, V2
+ BNE L1
+ MOVD $tanhxmone<>+0(SB), R1
+ FMOVD 0(R1), F0
+ FMOVD F0, ret+8(FP)
+ RET
+
+L3:
+ FADD F4, F2
+ FMOVD tanhrodataL18<>+80(SB), F4
+ FMADD F4, F2, F0, F0
+ FMOVD tanhrodataL18<>+72(SB), F1
+ WFMDB V0, V0, V3
+ FMOVD tanhrodataL18<>+64(SB), F2
+ WFMADB V0, V1, V2, V1
+ FMOVD tanhrodataL18<>+56(SB), F4
+ FMOVD tanhrodataL18<>+48(SB), F2
+ WFMADB V1, V3, V4, V1
+ FMOVD tanhrodataL18<>+40(SB), F4
+ WFMADB V3, V2, V4, V2
+ FMOVD tanhrodataL18<>+32(SB), F4
+ WORD $0xB9270022 //lhr %r2,%r2
+ WFMADB V3, V1, V4, V1
+ FMOVD tanhrodataL18<>+24(SB), F4
+ WFMADB V3, V2, V4, V3
+ WFMADB V0, V5, V0, V2
+ WFMADB V0, V1, V3, V0
+ WORD $0xA7183ECF //lhi %r1,16079
+ WFMADB V0, V2, V5, V2
+ FMUL F6, F2
+ MOVW R2, R10
+ MOVW R1, R11
+ CMPBLE R10, R11, L16
+ FMOVD F6, F0
+ WORD $0xED005010 //adb %f0,.L28-.L18(%r5)
+ BYTE $0x00
+ BYTE $0x1A
+ WORD $0xA7184330 //lhi %r1,17200
+ FADD F2, F0
+ MOVW R2, R10
+ MOVW R1, R11
+ CMPBGT R10, R11, L17
+ WORD $0xED605010 //sdb %f6,.L28-.L18(%r5)
+ BYTE $0x00
+ BYTE $0x1B
+ FADD F6, F2
+ WFDDB V0, V2, V0
+ FMOVD F0, ret+8(FP)
+ RET
+
+L9:
+ FMOVD tanhrodataL18<>+16(SB), F0
+L1:
+ FMOVD F0, ret+8(FP)
+ RET
+
+L15:
+ FNEG F0, F1
+ BR L2
+L16:
+ FADD F6, F2
+ FMOVD tanhrodataL18<>+8(SB), F0
+ FMADD F4, F2, F0, F0
+ FMOVD tanhrodataL18<>+0(SB), F4
+ FNEG F0, F0
+ WFMADB V0, V2, V4, V0
+ FMOVD F0, ret+8(FP)
+ RET
+
+L17:
+ WFDDB V0, V4, V0
+ FMOVD tanhrodataL18<>+16(SB), F2
+ WFSDB V0, V2, V0
+ FMOVD F0, ret+8(FP)
+ RET
+
+tanhIsZero: //return ±0
+ FMOVD F0, ret+8(FP)
+ RET
diff --git a/src/mime/mediatype.go b/src/mime/mediatype.go
index 1845401..75cc903 100644
--- a/src/mime/mediatype.go
+++ b/src/mime/mediatype.go
@@ -248,24 +248,33 @@ func consumeValue(v string) (value, rest string) {
}
// parse a quoted-string
- rest = v[1:] // consume the leading quote
buffer := new(bytes.Buffer)
- var nextIsLiteral bool
- for idx, r := range rest {
- switch {
- case nextIsLiteral:
- buffer.WriteRune(r)
- nextIsLiteral = false
- case r == '"':
- return buffer.String(), rest[idx+1:]
- case r == '\\':
- nextIsLiteral = true
- case r != '\r' && r != '\n':
- buffer.WriteRune(r)
- default:
+ for i := 1; i < len(v); i++ {
+ r := v[i]
+ if r == '"' {
+ return buffer.String(), v[i+1:]
+ }
+ // When MSIE sends a full file path (in "intranet mode"), it does not
+ // escape backslashes: "C:\dev\go\foo.txt", not "C:\\dev\\go\\foo.txt".
+ //
+ // No known MIME generators emit unnecessary backslash escapes
+ // for simple token characters like numbers and letters.
+ //
+ // If we see an unnecessary backslash escape, assume it is from MSIE
+ // and intended as a literal backslash. This makes Go servers deal better
+ // with MSIE without affecting the way they handle conforming MIME
+ // generators.
+ if r == '\\' && i+1 < len(v) && !isTokenChar(rune(v[i+1])) {
+ buffer.WriteByte(v[i+1])
+ i++
+ continue
+ }
+ if r == '\r' || r == '\n' {
return "", v
}
+ buffer.WriteByte(v[i])
}
+ // Did not find end quote.
return "", v
}
diff --git a/src/mime/mediatype_test.go b/src/mime/mediatype_test.go
index 9afa558..c5fc906 100644
--- a/src/mime/mediatype_test.go
+++ b/src/mime/mediatype_test.go
@@ -138,10 +138,11 @@ func TestParseMediaType(t *testing.T) {
m("title", "This is even more ***fun*** isn't it!")},
// Tests from http://greenbytes.de/tech/tc2231/
+ // Note: Backslash escape handling is a bit loose, like MSIE.
// TODO(bradfitz): add the rest of the tests from that site.
{`attachment; filename="f\oo.html"`,
"attachment",
- m("filename", "foo.html")},
+ m("filename", "f\\oo.html")},
{`attachment; filename="\"quoting\" tested.html"`,
"attachment",
m("filename", `"quoting" tested.html`)},
@@ -165,7 +166,7 @@ func TestParseMediaType(t *testing.T) {
m("filename", "foo-%41.html")},
{`attachment; filename="foo-%\41.html"`,
"attachment",
- m("filename", "foo-%41.html")},
+ m("filename", "foo-%\\41.html")},
{`filename=foo.html`,
"", m()},
{`x=y; filename=foo.html`,
@@ -220,18 +221,21 @@ func TestParseMediaType(t *testing.T) {
// Empty string used to be mishandled.
{`foo; bar=""`, "foo", m("bar", "")},
+
+ // Microsoft browers in intranet mode do not think they need to escape \ in file name.
+ {`form-data; name="file"; filename="C:\dev\go\robots.txt"`, "form-data", m("name", "file", "filename", `C:\dev\go\robots.txt`)},
}
for _, test := range tests {
mt, params, err := ParseMediaType(test.in)
if err != nil {
if test.t != "" {
- t.Errorf("for input %q, unexpected error: %v", test.in, err)
+ t.Errorf("for input %#q, unexpected error: %v", test.in, err)
continue
}
continue
}
if g, e := mt, test.t; g != e {
- t.Errorf("for input %q, expected type %q, got %q",
+ t.Errorf("for input %#q, expected type %q, got %q",
test.in, e, g)
continue
}
@@ -239,7 +243,7 @@ func TestParseMediaType(t *testing.T) {
continue
}
if !reflect.DeepEqual(params, test.p) {
- t.Errorf("for input %q, wrong params.\n"+
+ t.Errorf("for input %#q, wrong params.\n"+
"expected: %#v\n"+
" got: %#v",
test.in, test.p, params)
diff --git a/src/mime/multipart/multipart.go b/src/mime/multipart/multipart.go
index 205348c..1954808 100644
--- a/src/mime/multipart/multipart.go
+++ b/src/mime/multipart/multipart.go
@@ -42,9 +42,7 @@ type Part struct {
// during Read calls.
Header textproto.MIMEHeader
- buffer *bytes.Buffer
- mr *Reader
- bytesRead int
+ mr *Reader
disposition string
dispositionParams map[string]string
@@ -53,6 +51,11 @@ type Part struct {
// wrapper around such a reader, decoding the
// Content-Transfer-Encoding
r io.Reader
+
+ n int // known data bytes waiting in mr.bufReader
+ total int64 // total data bytes read already
+ err error // error to return when n == 0
+ readErr error // read error observed from mr.bufReader
}
// FormName returns the name parameter if p has a Content-Disposition
@@ -126,7 +129,6 @@ func newPart(mr *Reader) (*Part, error) {
bp := &Part{
Header: make(map[string][]string),
mr: mr,
- buffer: new(bytes.Buffer),
}
if err := bp.populateHeaders(); err != nil {
return nil, err
@@ -161,65 +163,118 @@ type partReader struct {
p *Part
}
-func (pr partReader) Read(d []byte) (n int, err error) {
+func (pr partReader) Read(d []byte) (int, error) {
p := pr.p
- defer func() {
- p.bytesRead += n
- }()
- if p.buffer.Len() >= len(d) {
- // Internal buffer of unconsumed data is large enough for
- // the read request. No need to parse more at the moment.
- return p.buffer.Read(d)
+ br := p.mr.bufReader
+
+ // Read into buffer until we identify some data to return,
+ // or we find a reason to stop (boundary or read error).
+ for p.n == 0 && p.err == nil {
+ peek, _ := br.Peek(br.Buffered())
+ p.n, p.err = scanUntilBoundary(peek, p.mr.dashBoundary, p.mr.nlDashBoundary, p.total, p.readErr)
+ if p.n == 0 && p.err == nil {
+ // Force buffered I/O to read more into buffer.
+ _, p.readErr = br.Peek(len(peek) + 1)
+ if p.readErr == io.EOF {
+ p.readErr = io.ErrUnexpectedEOF
+ }
+ }
}
- peek, err := p.mr.bufReader.Peek(peekBufferSize) // TODO(bradfitz): add buffer size accessor
-
- // Look for an immediate empty part without a leading \r\n
- // before the boundary separator. Some MIME code makes empty
- // parts like this. Most browsers, however, write the \r\n
- // before the subsequent boundary even for empty parts and
- // won't hit this path.
- if p.bytesRead == 0 && p.mr.peekBufferIsEmptyPart(peek) {
- return 0, io.EOF
+
+ // Read out from "data to return" part of buffer.
+ if p.n == 0 {
+ return 0, p.err
}
- unexpectedEOF := err == io.EOF
- if err != nil && !unexpectedEOF {
- return 0, fmt.Errorf("multipart: Part Read: %v", err)
+ n := len(d)
+ if n > p.n {
+ n = p.n
}
- if peek == nil {
- panic("nil peek buf")
+ n, _ = br.Read(d[:n])
+ p.total += int64(n)
+ p.n -= n
+ if p.n == 0 {
+ return n, p.err
}
- // Search the peek buffer for "\r\n--boundary". If found,
- // consume everything up to the boundary. If not, consume only
- // as much of the peek buffer as cannot hold the boundary
- // string.
- nCopy := 0
- foundBoundary := false
- if idx, isEnd := p.mr.peekBufferSeparatorIndex(peek); idx != -1 {
- nCopy = idx
- foundBoundary = isEnd
- if !isEnd && nCopy == 0 {
- nCopy = 1 // make some progress.
+ return n, nil
+}
+
+// scanUntilBoundary scans buf to identify how much of it can be safely
+// returned as part of the Part body.
+// dashBoundary is "--boundary".
+// nlDashBoundary is "\r\n--boundary" or "\n--boundary", depending on what mode we are in.
+// The comments below (and the name) assume "\n--boundary", but either is accepted.
+// total is the number of bytes read out so far. If total == 0, then a leading "--boundary" is recognized.
+// readErr is the read error, if any, that followed reading the bytes in buf.
+// scanUntilBoundary returns the number of data bytes from buf that can be
+// returned as part of the Part body and also the error to return (if any)
+// once those data bytes are done.
+func scanUntilBoundary(buf, dashBoundary, nlDashBoundary []byte, total int64, readErr error) (int, error) {
+ if total == 0 {
+ // At beginning of body, allow dashBoundary.
+ if bytes.HasPrefix(buf, dashBoundary) {
+ switch matchAfterPrefix(buf, dashBoundary, readErr) {
+ case -1:
+ return len(dashBoundary), nil
+ case 0:
+ return 0, nil
+ case +1:
+ return 0, io.EOF
+ }
+ }
+ if bytes.HasPrefix(dashBoundary, buf) {
+ return 0, readErr
}
- } else if safeCount := len(peek) - len(p.mr.nlDashBoundary); safeCount > 0 {
- nCopy = safeCount
- } else if unexpectedEOF {
- // If we've run out of peek buffer and the boundary
- // wasn't found (and can't possibly fit), we must have
- // hit the end of the file unexpectedly.
- return 0, io.ErrUnexpectedEOF
}
- if nCopy > 0 {
- if _, err := io.CopyN(p.buffer, p.mr.bufReader, int64(nCopy)); err != nil {
- return 0, err
+
+ // Search for "\n--boundary".
+ if i := bytes.Index(buf, nlDashBoundary); i >= 0 {
+ switch matchAfterPrefix(buf[i:], nlDashBoundary, readErr) {
+ case -1:
+ return i + len(nlDashBoundary), nil
+ case 0:
+ return i, nil
+ case +1:
+ return i, io.EOF
+ }
+ }
+ if bytes.HasPrefix(nlDashBoundary, buf) {
+ return 0, readErr
+ }
+
+ // Otherwise, anything up to the final \n is not part of the boundary
+ // and so must be part of the body.
+ // Also if the section from the final \n onward is not a prefix of the boundary,
+ // it too must be part of the body.
+ i := bytes.LastIndexByte(buf, nlDashBoundary[0])
+ if i >= 0 && bytes.HasPrefix(nlDashBoundary, buf[i:]) {
+ return i, nil
+ }
+ return len(buf), readErr
+}
+
+// matchAfterPrefix checks whether buf should be considered to match the boundary.
+// The prefix is "--boundary" or "\r\n--boundary" or "\n--boundary",
+// and the caller has verified already that bytes.HasPrefix(buf, prefix) is true.
+//
+// matchAfterPrefix returns +1 if the buffer does match the boundary,
+// meaning the prefix is followed by a dash, space, tab, cr, nl, or end of input.
+// It returns -1 if the buffer definitely does NOT match the boundary,
+// meaning the prefix is followed by some other character.
+// For example, "--foobar" does not match "--foo".
+// It returns 0 more input needs to be read to make the decision,
+// meaning that len(buf) == len(prefix) and readErr == nil.
+func matchAfterPrefix(buf, prefix []byte, readErr error) int {
+ if len(buf) == len(prefix) {
+ if readErr != nil {
+ return +1
}
+ return 0
}
- n, err = p.buffer.Read(d)
- if err == io.EOF && !foundBoundary {
- // If the boundary hasn't been reached there's more to
- // read, so don't pass through an EOF from the buffer
- err = nil
+ c := buf[len(prefix)]
+ if c == ' ' || c == '\t' || c == '\r' || c == '\n' || c == '-' {
+ return +1
}
- return
+ return -1
}
func (p *Part) Close() error {
@@ -337,64 +392,6 @@ func (mr *Reader) isBoundaryDelimiterLine(line []byte) (ret bool) {
return bytes.Equal(rest, mr.nl)
}
-// peekBufferIsEmptyPart reports whether the provided peek-ahead
-// buffer represents an empty part. It is called only if we've not
-// already read any bytes in this part and checks for the case of MIME
-// software not writing the \r\n on empty parts. Some does, some
-// doesn't.
-//
-// This checks that what follows the "--boundary" is actually the end
-// ("--boundary--" with optional whitespace) or optional whitespace
-// and then a newline, so we don't catch "--boundaryFAKE", in which
-// case the whole line is part of the data.
-func (mr *Reader) peekBufferIsEmptyPart(peek []byte) bool {
- // End of parts case.
- // Test whether peek matches `^--boundary--[ \t]*(?:\r\n|$)`
- if bytes.HasPrefix(peek, mr.dashBoundaryDash) {
- rest := peek[len(mr.dashBoundaryDash):]
- rest = skipLWSPChar(rest)
- return bytes.HasPrefix(rest, mr.nl) || len(rest) == 0
- }
- if !bytes.HasPrefix(peek, mr.dashBoundary) {
- return false
- }
- // Test whether rest matches `^[ \t]*\r\n`)
- rest := peek[len(mr.dashBoundary):]
- rest = skipLWSPChar(rest)
- return bytes.HasPrefix(rest, mr.nl)
-}
-
-// peekBufferSeparatorIndex returns the index of mr.nlDashBoundary in
-// peek and whether it is a real boundary (and not a prefix of an
-// unrelated separator). To be the end, the peek buffer must contain a
-// newline after the boundary or contain the ending boundary (--separator--).
-func (mr *Reader) peekBufferSeparatorIndex(peek []byte) (idx int, isEnd bool) {
- idx = bytes.Index(peek, mr.nlDashBoundary)
- if idx == -1 {
- return
- }
-
- peek = peek[idx+len(mr.nlDashBoundary):]
- if len(peek) == 0 || len(peek) == 1 && peek[0] == '-' {
- return idx, false
- }
- if len(peek) > 1 && peek[0] == '-' && peek[1] == '-' {
- return idx, true
- }
- peek = skipLWSPChar(peek)
- // Don't have a complete line after the peek.
- if bytes.IndexByte(peek, '\n') == -1 {
- return idx, false
- }
- if len(peek) > 0 && peek[0] == '\n' {
- return idx, true
- }
- if len(peek) > 1 && peek[0] == '\r' && peek[1] == '\n' {
- return idx, true
- }
- return idx, false
-}
-
// skipLWSPChar returns b with leading spaces and tabs removed.
// RFC 822 defines:
// LWSP-char = SPACE / HTAB
diff --git a/src/mime/multipart/multipart_test.go b/src/mime/multipart/multipart_test.go
index 82a7f86..7fbee90 100644
--- a/src/mime/multipart/multipart_test.go
+++ b/src/mime/multipart/multipart_test.go
@@ -125,6 +125,7 @@ func TestMultipartSlowInput(t *testing.T) {
}
func testMultipart(t *testing.T, r io.Reader, onlyNewlines bool) {
+ t.Parallel()
reader := NewReader(r, "MyBoundary")
buf := new(bytes.Buffer)
@@ -323,6 +324,73 @@ func (s *slowReader) Read(p []byte) (int, error) {
return s.r.Read(p[:1])
}
+type sentinelReader struct {
+ // done is closed when this reader is read from.
+ done chan struct{}
+}
+
+func (s *sentinelReader) Read([]byte) (int, error) {
+ if s.done != nil {
+ close(s.done)
+ s.done = nil
+ }
+ return 0, io.EOF
+}
+
+// TestMultipartStreamReadahead tests that PartReader does not block
+// on reading past the end of a part, ensuring that it can be used on
+// a stream like multipart/x-mixed-replace. See golang.org/issue/15431
+func TestMultipartStreamReadahead(t *testing.T) {
+ testBody1 := `
+This is a multi-part message. This line is ignored.
+--MyBoundary
+foo-bar: baz
+
+Body
+--MyBoundary
+`
+ testBody2 := `foo-bar: bop
+
+Body 2
+--MyBoundary--
+`
+ done1 := make(chan struct{})
+ reader := NewReader(
+ io.MultiReader(
+ strings.NewReader(testBody1),
+ &sentinelReader{done1},
+ strings.NewReader(testBody2)),
+ "MyBoundary")
+
+ var i int
+ readPart := func(hdr textproto.MIMEHeader, body string) {
+ part, err := reader.NextPart()
+ if part == nil || err != nil {
+ t.Fatalf("Part %d: NextPart failed: %v", i, err)
+ }
+
+ if !reflect.DeepEqual(part.Header, hdr) {
+ t.Errorf("Part %d: part.Header = %v, want %v", i, part.Header, hdr)
+ }
+ data, err := ioutil.ReadAll(part)
+ expectEq(t, body, string(data), fmt.Sprintf("Part %d body", i))
+ if err != nil {
+ t.Fatalf("Part %d: ReadAll failed: %v", i, err)
+ }
+ i++
+ }
+
+ readPart(textproto.MIMEHeader{"Foo-Bar": {"baz"}}, "Body")
+
+ select {
+ case <-done1:
+ t.Errorf("Reader read past second boundary")
+ default:
+ }
+
+ readPart(textproto.MIMEHeader{"Foo-Bar": {"bop"}}, "Body 2")
+}
+
func TestLineContinuation(t *testing.T) {
// This body, extracted from an email, contains headers that span multiple
// lines.
@@ -755,6 +823,7 @@ func partsFromReader(r *Reader) ([]headerBody, error) {
}
func TestParseAllSizes(t *testing.T) {
+ t.Parallel()
const maxSize = 5 << 10
var buf bytes.Buffer
body := strings.Repeat("a", maxSize)
diff --git a/src/mime/quotedprintable/example_test.go b/src/mime/quotedprintable/example_test.go
new file mode 100644
index 0000000..5a9ab45
--- /dev/null
+++ b/src/mime/quotedprintable/example_test.go
@@ -0,0 +1,37 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package quotedprintable_test
+
+import (
+ "fmt"
+ "io/ioutil"
+ "mime/quotedprintable"
+ "os"
+ "strings"
+)
+
+func ExampleNewReader() {
+ for _, s := range []string{
+ `=48=65=6C=6C=6F=2C=20=47=6F=70=68=65=72=73=21`,
+ `invalid escape: <b style="font-size: 200%">hello</b>`,
+ "Hello, Gophers! This symbol will be unescaped: =3D and this will be written in =\r\none line.",
+ } {
+ b, err := ioutil.ReadAll(quotedprintable.NewReader(strings.NewReader(s)))
+ fmt.Printf("%s %v\n", b, err)
+ }
+ // Output:
+ // Hello, Gophers! <nil>
+ // invalid escape: <b style="font-size: 200%">hello</b> <nil>
+ // Hello, Gophers! This symbol will be unescaped: = and this will be written in one line. <nil>
+}
+
+func ExampleNewWriter() {
+ w := quotedprintable.NewWriter(os.Stdout)
+ w.Write([]byte("These symbols will be escaped: = \t"))
+ w.Close()
+
+ // Output:
+ // These symbols will be escaped: =3D =09
+}
diff --git a/src/mime/quotedprintable/reader.go b/src/mime/quotedprintable/reader.go
index 3bd6833..b142240 100644
--- a/src/mime/quotedprintable/reader.go
+++ b/src/mime/quotedprintable/reader.go
@@ -74,6 +74,11 @@ func (r *Reader) Read(p []byte) (n int, err error) {
// 1. in addition to "=\r\n", "=\n" is also treated as soft line break.
// 2. it will pass through a '\r' or '\n' not preceded by '=', consistent
// with other broken QP encoders & decoders.
+ // 3. it accepts soft line-break (=) at end of message (issue 15486); i.e.
+ // the final byte read from the underlying reader is allowed to be '=',
+ // and it will be silently ignored.
+ // 4. it takes = as literal = if not followed by two hex digits
+ // but not at end of line (issue 13219).
for len(p) > 0 {
if len(r.line) == 0 {
if r.rerr != nil {
@@ -89,7 +94,8 @@ func (r *Reader) Read(p []byte) (n int, err error) {
if bytes.HasSuffix(r.line, softSuffix) {
rightStripped := wholeLine[len(r.line):]
r.line = r.line[:len(r.line)-1]
- if !bytes.HasPrefix(rightStripped, lf) && !bytes.HasPrefix(rightStripped, crlf) {
+ if !bytes.HasPrefix(rightStripped, lf) && !bytes.HasPrefix(rightStripped, crlf) &&
+ !(len(rightStripped) == 0 && len(r.line) > 0 && r.rerr == io.EOF) {
r.rerr = fmt.Errorf("quotedprintable: invalid bytes after =: %q", rightStripped)
}
} else if hasLF {
@@ -107,6 +113,11 @@ func (r *Reader) Read(p []byte) (n int, err error) {
case b == '=':
b, err = readHexByte(r.line[1:])
if err != nil {
+ if len(r.line) >= 2 && r.line[1] != '\r' && r.line[1] != '\n' {
+ // Take the = as a literal =.
+ b = '='
+ break
+ }
return n, err
}
r.line = r.line[2:] // 2 of the 3; other 1 is done below
diff --git a/src/mime/quotedprintable/reader_test.go b/src/mime/quotedprintable/reader_test.go
index e77b261..ca016f9 100644
--- a/src/mime/quotedprintable/reader_test.go
+++ b/src/mime/quotedprintable/reader_test.go
@@ -30,7 +30,7 @@ func TestReader(t *testing.T) {
{in: "foo bar=3d", want: "foo bar="}, // lax.
{in: "foo bar=\n", want: "foo bar"},
{in: "foo bar\n", want: "foo bar\n"}, // somewhat lax.
- {in: "foo bar=0", want: "foo bar", err: io.ErrUnexpectedEOF},
+ {in: "foo bar=0", want: "foo bar=0"}, // lax
{in: "foo bar=0D=0A", want: "foo bar\r\n"},
{in: " A B \r\n C ", want: " A B\r\n C"},
{in: " A B =\r\n C ", want: " A B C"},
@@ -58,6 +58,9 @@ func TestReader(t *testing.T) {
{in: "foo=\nbar", want: "foobar"},
{in: "foo=\rbar", want: "foo", err: "quotedprintable: invalid hex byte 0x0d"},
{in: "foo=\r\r\r \nbar", want: "foo", err: `quotedprintable: invalid bytes after =: "\r\r\r \n"`},
+ // Issue 15486, accept trailing soft line-break at end of input.
+ {in: "foo=", want: "foo"},
+ {in: "=", want: "", err: `quotedprintable: invalid bytes after =: ""`},
// Example from RFC 2045:
{in: "Now's the time =\n" + "for all folk to come=\n" + " to the aid of their country.",
@@ -191,13 +194,10 @@ func TestExhaustive(t *testing.T) {
}
sort.Strings(outcomes)
got := strings.Join(outcomes, "\n")
- want := `OK: 21576
-invalid bytes after =: 3397
-quotedprintable: invalid hex byte 0x0a: 1400
-quotedprintable: invalid hex byte 0x0d: 2700
-quotedprintable: invalid hex byte 0x20: 2490
-quotedprintable: invalid hex byte 0x3d: 440
-unexpected EOF: 3122`
+ want := `OK: 28934
+invalid bytes after =: 3949
+quotedprintable: invalid hex byte 0x0d: 2048
+unexpected EOF: 194`
if got != want {
t.Errorf("Got:\n%s\nWant:\n%s", got, want)
}
diff --git a/src/net/cgo_unix.go b/src/net/cgo_unix.go
index 5a1eed8..56d34b6 100644
--- a/src/net/cgo_unix.go
+++ b/src/net/cgo_unix.go
@@ -96,6 +96,11 @@ func cgoLookupPort(ctx context.Context, network, service string) (port int, err
func cgoLookupServicePort(hints *C.struct_addrinfo, network, service string) (port int, err error) {
s := C.CString(service)
+ // Lowercase the service name in the C-allocated memory.
+ for i := 0; i < len(service); i++ {
+ bp := (*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(s)) + uintptr(i)))
+ *bp = lowerASCII(*bp)
+ }
var res *C.struct_addrinfo
defer C.free(unsafe.Pointer(s))
gerrno, err := C.getaddrinfo(nil, s, hints, &res)
diff --git a/src/net/conf.go b/src/net/conf.go
index eb72916..c10aafe 100644
--- a/src/net/conf.go
+++ b/src/net/conf.go
@@ -179,8 +179,6 @@ func (c *conf) hostLookupOrder(hostname string) (ret hostLookupOrder) {
}
}
- hasDot := byteIndex(hostname, '.') != -1
-
// Canonicalize the hostname by removing any trailing dot.
if stringsHasSuffix(hostname, ".") {
hostname = hostname[:len(hostname)-1]
@@ -220,10 +218,14 @@ func (c *conf) hostLookupOrder(hostname string) (ret hostLookupOrder) {
var first string
for _, src := range srcs {
if src.source == "myhostname" {
- if hostname == "" || hasDot {
- continue
+ if isLocalhost(hostname) || isGateway(hostname) {
+ return fallbackOrder
}
- return fallbackOrder
+ hn, err := getHostname()
+ if err != nil || stringsEqualFold(hostname, hn) {
+ return fallbackOrder
+ }
+ continue
}
if src.source == "files" || src.source == "dns" {
if !src.standardCriteria() {
@@ -293,7 +295,7 @@ func goDebugNetDNS() (dnsMode string, debugLevel int) {
return
}
if '0' <= s[0] && s[0] <= '9' {
- debugLevel, _, _ = dtoi(s, 0)
+ debugLevel, _, _ = dtoi(s)
} else {
dnsMode = s
}
@@ -306,3 +308,15 @@ func goDebugNetDNS() (dnsMode string, debugLevel int) {
parsePart(goDebug)
return
}
+
+// isLocalhost reports whether h should be considered a "localhost"
+// name for the myhostname NSS module.
+func isLocalhost(h string) bool {
+ return stringsEqualFold(h, "localhost") || stringsEqualFold(h, "localhost.localdomain") || stringsHasSuffixFold(h, ".localhost") || stringsHasSuffixFold(h, ".localhost.localdomain")
+}
+
+// isGateway reports whether h should be considered a "gateway"
+// name for the myhostname NSS module.
+func isGateway(h string) bool {
+ return stringsEqualFold(h, "gateway")
+}
diff --git a/src/net/conf_test.go b/src/net/conf_test.go
index ec8814b..17d03f4 100644
--- a/src/net/conf_test.go
+++ b/src/net/conf_test.go
@@ -13,8 +13,9 @@ import (
)
type nssHostTest struct {
- host string
- want hostLookupOrder
+ host string
+ localhost string
+ want hostLookupOrder
}
func nssStr(s string) *nssConf { return parseNSSConf(strings.NewReader(s)) }
@@ -42,8 +43,8 @@ func TestConfHostLookupOrder(t *testing.T) {
resolv: defaultResolvConf,
},
hostTests: []nssHostTest{
- {"foo.local", hostLookupCgo},
- {"google.com", hostLookupCgo},
+ {"foo.local", "myhostname", hostLookupCgo},
+ {"google.com", "myhostname", hostLookupCgo},
},
},
{
@@ -54,7 +55,7 @@ func TestConfHostLookupOrder(t *testing.T) {
resolv: defaultResolvConf,
},
hostTests: []nssHostTest{
- {"x.com", hostLookupDNSFiles},
+ {"x.com", "myhostname", hostLookupDNSFiles},
},
},
{
@@ -65,7 +66,7 @@ func TestConfHostLookupOrder(t *testing.T) {
resolv: defaultResolvConf,
},
hostTests: []nssHostTest{
- {"x.com", hostLookupFilesDNS},
+ {"x.com", "myhostname", hostLookupFilesDNS},
},
},
{
@@ -75,11 +76,11 @@ func TestConfHostLookupOrder(t *testing.T) {
resolv: defaultResolvConf,
},
hostTests: []nssHostTest{
- {"foo.local", hostLookupCgo},
- {"foo.local.", hostLookupCgo},
- {"foo.LOCAL", hostLookupCgo},
- {"foo.LOCAL.", hostLookupCgo},
- {"google.com", hostLookupFilesDNS},
+ {"foo.local", "myhostname", hostLookupCgo},
+ {"foo.local.", "myhostname", hostLookupCgo},
+ {"foo.LOCAL", "myhostname", hostLookupCgo},
+ {"foo.LOCAL.", "myhostname", hostLookupCgo},
+ {"google.com", "myhostname", hostLookupFilesDNS},
},
},
{
@@ -89,7 +90,7 @@ func TestConfHostLookupOrder(t *testing.T) {
nss: nssStr("foo: bar"),
resolv: defaultResolvConf,
},
- hostTests: []nssHostTest{{"google.com", hostLookupFilesDNS}},
+ hostTests: []nssHostTest{{"google.com", "myhostname", hostLookupFilesDNS}},
},
// On OpenBSD, no resolv.conf means no DNS.
{
@@ -98,7 +99,7 @@ func TestConfHostLookupOrder(t *testing.T) {
goos: "openbsd",
resolv: defaultResolvConf,
},
- hostTests: []nssHostTest{{"google.com", hostLookupFiles}},
+ hostTests: []nssHostTest{{"google.com", "myhostname", hostLookupFiles}},
},
{
name: "solaris_no_nsswitch",
@@ -107,7 +108,7 @@ func TestConfHostLookupOrder(t *testing.T) {
nss: &nssConf{err: os.ErrNotExist},
resolv: defaultResolvConf,
},
- hostTests: []nssHostTest{{"google.com", hostLookupCgo}},
+ hostTests: []nssHostTest{{"google.com", "myhostname", hostLookupCgo}},
},
{
name: "openbsd_lookup_bind_file",
@@ -116,8 +117,8 @@ func TestConfHostLookupOrder(t *testing.T) {
resolv: &dnsConfig{lookup: []string{"bind", "file"}},
},
hostTests: []nssHostTest{
- {"google.com", hostLookupDNSFiles},
- {"foo.local", hostLookupDNSFiles},
+ {"google.com", "myhostname", hostLookupDNSFiles},
+ {"foo.local", "myhostname", hostLookupDNSFiles},
},
},
{
@@ -126,7 +127,7 @@ func TestConfHostLookupOrder(t *testing.T) {
goos: "openbsd",
resolv: &dnsConfig{lookup: []string{"file", "bind"}},
},
- hostTests: []nssHostTest{{"google.com", hostLookupFilesDNS}},
+ hostTests: []nssHostTest{{"google.com", "myhostname", hostLookupFilesDNS}},
},
{
name: "openbsd_lookup_bind",
@@ -134,7 +135,7 @@ func TestConfHostLookupOrder(t *testing.T) {
goos: "openbsd",
resolv: &dnsConfig{lookup: []string{"bind"}},
},
- hostTests: []nssHostTest{{"google.com", hostLookupDNS}},
+ hostTests: []nssHostTest{{"google.com", "myhostname", hostLookupDNS}},
},
{
name: "openbsd_lookup_file",
@@ -142,7 +143,7 @@ func TestConfHostLookupOrder(t *testing.T) {
goos: "openbsd",
resolv: &dnsConfig{lookup: []string{"file"}},
},
- hostTests: []nssHostTest{{"google.com", hostLookupFiles}},
+ hostTests: []nssHostTest{{"google.com", "myhostname", hostLookupFiles}},
},
{
name: "openbsd_lookup_yp",
@@ -150,7 +151,7 @@ func TestConfHostLookupOrder(t *testing.T) {
goos: "openbsd",
resolv: &dnsConfig{lookup: []string{"file", "bind", "yp"}},
},
- hostTests: []nssHostTest{{"google.com", hostLookupCgo}},
+ hostTests: []nssHostTest{{"google.com", "myhostname", hostLookupCgo}},
},
{
name: "openbsd_lookup_two",
@@ -158,7 +159,7 @@ func TestConfHostLookupOrder(t *testing.T) {
goos: "openbsd",
resolv: &dnsConfig{lookup: []string{"file", "foo"}},
},
- hostTests: []nssHostTest{{"google.com", hostLookupCgo}},
+ hostTests: []nssHostTest{{"google.com", "myhostname", hostLookupCgo}},
},
{
name: "openbsd_lookup_empty",
@@ -166,7 +167,7 @@ func TestConfHostLookupOrder(t *testing.T) {
goos: "openbsd",
resolv: &dnsConfig{lookup: nil},
},
- hostTests: []nssHostTest{{"google.com", hostLookupDNSFiles}},
+ hostTests: []nssHostTest{{"google.com", "myhostname", hostLookupDNSFiles}},
},
// glibc lacking an nsswitch.conf, per
// http://www.gnu.org/software/libc/manual/html_node/Notes-on-NSS-Configuration-File.html
@@ -177,7 +178,7 @@ func TestConfHostLookupOrder(t *testing.T) {
nss: &nssConf{err: os.ErrNotExist},
resolv: defaultResolvConf,
},
- hostTests: []nssHostTest{{"google.com", hostLookupDNSFiles}},
+ hostTests: []nssHostTest{{"google.com", "myhostname", hostLookupDNSFiles}},
},
{
name: "files_mdns_dns",
@@ -186,8 +187,8 @@ func TestConfHostLookupOrder(t *testing.T) {
resolv: defaultResolvConf,
},
hostTests: []nssHostTest{
- {"x.com", hostLookupFilesDNS},
- {"x.local", hostLookupCgo},
+ {"x.com", "myhostname", hostLookupFilesDNS},
+ {"x.local", "myhostname", hostLookupCgo},
},
},
{
@@ -197,9 +198,9 @@ func TestConfHostLookupOrder(t *testing.T) {
resolv: defaultResolvConf,
},
hostTests: []nssHostTest{
- {"x.com", hostLookupDNS},
- {"x\\.com", hostLookupCgo}, // punt on weird glibc escape
- {"foo.com%en0", hostLookupCgo}, // and IPv6 zones
+ {"x.com", "myhostname", hostLookupDNS},
+ {"x\\.com", "myhostname", hostLookupCgo}, // punt on weird glibc escape
+ {"foo.com%en0", "myhostname", hostLookupCgo}, // and IPv6 zones
},
},
{
@@ -210,8 +211,8 @@ func TestConfHostLookupOrder(t *testing.T) {
hasMDNSAllow: true,
},
hostTests: []nssHostTest{
- {"x.com", hostLookupCgo},
- {"x.local", hostLookupCgo},
+ {"x.com", "myhostname", hostLookupCgo},
+ {"x.local", "myhostname", hostLookupCgo},
},
},
{
@@ -221,9 +222,9 @@ func TestConfHostLookupOrder(t *testing.T) {
resolv: defaultResolvConf,
},
hostTests: []nssHostTest{
- {"x.com", hostLookupFilesDNS},
- {"x", hostLookupFilesDNS},
- {"x.local", hostLookupCgo},
+ {"x.com", "myhostname", hostLookupFilesDNS},
+ {"x", "myhostname", hostLookupFilesDNS},
+ {"x.local", "myhostname", hostLookupCgo},
},
},
{
@@ -233,9 +234,9 @@ func TestConfHostLookupOrder(t *testing.T) {
resolv: defaultResolvConf,
},
hostTests: []nssHostTest{
- {"x.com", hostLookupDNSFiles},
- {"x", hostLookupDNSFiles},
- {"x.local", hostLookupCgo},
+ {"x.com", "myhostname", hostLookupDNSFiles},
+ {"x", "myhostname", hostLookupDNSFiles},
+ {"x.local", "myhostname", hostLookupCgo},
},
},
{
@@ -245,7 +246,7 @@ func TestConfHostLookupOrder(t *testing.T) {
resolv: defaultResolvConf,
},
hostTests: []nssHostTest{
- {"x.com", hostLookupCgo},
+ {"x.com", "myhostname", hostLookupCgo},
},
},
{
@@ -255,9 +256,23 @@ func TestConfHostLookupOrder(t *testing.T) {
resolv: defaultResolvConf,
},
hostTests: []nssHostTest{
- {"x.com", hostLookupFilesDNS},
- {"somehostname", hostLookupCgo},
- {"", hostLookupFilesDNS}, // Issue 13623
+ {"x.com", "myhostname", hostLookupFilesDNS},
+ {"myhostname", "myhostname", hostLookupCgo},
+ {"myHostname", "myhostname", hostLookupCgo},
+ {"myhostname.dot", "myhostname.dot", hostLookupCgo},
+ {"myHostname.dot", "myhostname.dot", hostLookupCgo},
+ {"gateway", "myhostname", hostLookupCgo},
+ {"Gateway", "myhostname", hostLookupCgo},
+ {"localhost", "myhostname", hostLookupCgo},
+ {"Localhost", "myhostname", hostLookupCgo},
+ {"anything.localhost", "myhostname", hostLookupCgo},
+ {"Anything.localhost", "myhostname", hostLookupCgo},
+ {"localhost.localdomain", "myhostname", hostLookupCgo},
+ {"Localhost.Localdomain", "myhostname", hostLookupCgo},
+ {"anything.localhost.localdomain", "myhostname", hostLookupCgo},
+ {"Anything.Localhost.Localdomain", "myhostname", hostLookupCgo},
+ {"somehostname", "myhostname", hostLookupFilesDNS},
+ {"", "myhostname", hostLookupFilesDNS}, // Issue 13623
},
},
{
@@ -267,8 +282,9 @@ func TestConfHostLookupOrder(t *testing.T) {
resolv: defaultResolvConf,
},
hostTests: []nssHostTest{
- {"x.com", hostLookupFilesDNS},
- {"somehostname", hostLookupCgo},
+ {"x.com", "myhostname", hostLookupFilesDNS},
+ {"somehostname", "myhostname", hostLookupFilesDNS},
+ {"myhostname", "myhostname", hostLookupCgo},
},
},
// Debian Squeeze is just "dns,files", but lists all
@@ -282,8 +298,8 @@ func TestConfHostLookupOrder(t *testing.T) {
resolv: defaultResolvConf,
},
hostTests: []nssHostTest{
- {"x.com", hostLookupDNSFiles},
- {"somehostname", hostLookupDNSFiles},
+ {"x.com", "myhostname", hostLookupDNSFiles},
+ {"somehostname", "myhostname", hostLookupDNSFiles},
},
},
{
@@ -292,7 +308,7 @@ func TestConfHostLookupOrder(t *testing.T) {
nss: nssStr("foo: bar"),
resolv: &dnsConfig{servers: defaultNS, ndots: 1, timeout: 5, attempts: 2, unknownOpt: true},
},
- hostTests: []nssHostTest{{"google.com", hostLookupCgo}},
+ hostTests: []nssHostTest{{"google.com", "myhostname", hostLookupCgo}},
},
// Android should always use cgo.
{
@@ -303,12 +319,18 @@ func TestConfHostLookupOrder(t *testing.T) {
resolv: defaultResolvConf,
},
hostTests: []nssHostTest{
- {"x.com", hostLookupCgo},
+ {"x.com", "myhostname", hostLookupCgo},
},
},
}
+
+ origGetHostname := getHostname
+ defer func() { getHostname = origGetHostname }()
+
for _, tt := range tests {
for _, ht := range tt.hostTests {
+ getHostname = func() (string, error) { return ht.localhost, nil }
+
gotOrder := tt.c.hostLookupOrder(ht.host)
if gotOrder != ht.want {
t.Errorf("%s: hostLookupOrder(%q) = %v; want %v", tt.name, ht.host, gotOrder, ht.want)
diff --git a/src/net/dial.go b/src/net/dial.go
index 55edb43..5db3585 100644
--- a/src/net/dial.go
+++ b/src/net/dial.go
@@ -59,6 +59,9 @@ type Dialer struct {
// that do not support keep-alives ignore this field.
KeepAlive time.Duration
+ // Resolver optionally specifies an alternate resolver to use.
+ Resolver *Resolver
+
// Cancel is an optional channel whose closure indicates that
// the dial should be canceled. Not all types of dials support
// cancelation.
@@ -92,6 +95,13 @@ func (d *Dialer) deadline(ctx context.Context, now time.Time) (earliest time.Tim
return minNonzeroTime(earliest, d.Deadline)
}
+func (d *Dialer) resolver() *Resolver {
+ if d.Resolver != nil {
+ return d.Resolver
+ }
+ return DefaultResolver
+}
+
// partialDeadline returns the deadline to use for a single address,
// when multiple addresses are pending.
func partialDeadline(now, deadline time.Time, addrsRemaining int) (time.Time, error) {
@@ -141,7 +151,7 @@ func parseNetwork(ctx context.Context, net string) (afnet string, proto int, err
switch afnet {
case "ip", "ip4", "ip6":
protostr := net[i+1:]
- proto, i, ok := dtoi(protostr, 0)
+ proto, i, ok := dtoi(protostr)
if !ok || i != len(protostr) {
proto, err = lookupProtocol(ctx, protostr)
if err != nil {
@@ -156,7 +166,7 @@ func parseNetwork(ctx context.Context, net string) (afnet string, proto int, err
// resolverAddrList resolves addr using hint and returns a list of
// addresses. The result contains at least one address when error is
// nil.
-func resolveAddrList(ctx context.Context, op, network, addr string, hint Addr) (addrList, error) {
+func (r *Resolver) resolveAddrList(ctx context.Context, op, network, addr string, hint Addr) (addrList, error) {
afnet, _, err := parseNetwork(ctx, network)
if err != nil {
return nil, err
@@ -166,7 +176,6 @@ func resolveAddrList(ctx context.Context, op, network, addr string, hint Addr) (
}
switch afnet {
case "unix", "unixgram", "unixpacket":
- // TODO(bradfitz): push down context
addr, err := ResolveUnixAddr(afnet, addr)
if err != nil {
return nil, err
@@ -176,7 +185,7 @@ func resolveAddrList(ctx context.Context, op, network, addr string, hint Addr) (
}
return addrList{addr}, nil
}
- addrs, err := internetAddrList(ctx, afnet, addr)
+ addrs, err := r.internetAddrList(ctx, afnet, addr)
if err != nil || op != "dial" || hint == nil {
return addrs, err
}
@@ -221,7 +230,7 @@ func resolveAddrList(ctx context.Context, op, network, addr string, hint Addr) (
}
}
if len(naddrs) == 0 {
- return nil, errNoSuitableAddress
+ return nil, &AddrError{Err: errNoSuitableAddress.Error(), Addr: hint.String()}
}
return naddrs, nil
}
@@ -326,7 +335,7 @@ func (d *Dialer) DialContext(ctx context.Context, network, address string) (Conn
resolveCtx = context.WithValue(resolveCtx, nettrace.TraceKey{}, &shadow)
}
- addrs, err := resolveAddrList(resolveCtx, "dial", network, address, d.LocalAddr)
+ addrs, err := d.resolver().resolveAddrList(resolveCtx, "dial", network, address, d.LocalAddr)
if err != nil {
return nil, &OpError{Op: "dial", Net: network, Source: nil, Addr: nil, Err: err}
}
@@ -524,8 +533,11 @@ func dialSingle(ctx context.Context, dp *dialParam, ra Addr) (c Conn, err error)
// 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 a hostname is not recommended because this creates a socket
+// for at most one of its IP addresses.
func Listen(net, laddr string) (Listener, error) {
- addrs, err := resolveAddrList(context.Background(), "listen", net, laddr, nil)
+ addrs, err := DefaultResolver.resolveAddrList(context.Background(), "listen", net, laddr, nil)
if err != nil {
return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: nil, Err: err}
}
@@ -551,8 +563,11 @@ func Listen(net, laddr string) (Listener, error) {
// 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.
+//
+// Listening on a hostname is not recommended because this creates a socket
+// for at most one of its IP addresses.
func ListenPacket(net, laddr string) (PacketConn, error) {
- addrs, err := resolveAddrList(context.Background(), "listen", net, laddr, nil)
+ addrs, err := DefaultResolver.resolveAddrList(context.Background(), "listen", net, laddr, nil)
if err != nil {
return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: nil, Err: err}
}
diff --git a/src/net/dial_test.go b/src/net/dial_test.go
index 8b21e6b..6ba8e95 100644
--- a/src/net/dial_test.go
+++ b/src/net/dial_test.go
@@ -55,6 +55,23 @@ func TestProhibitionaryDialArg(t *testing.T) {
}
}
+func TestDialLocal(t *testing.T) {
+ ln, err := newLocalListener("tcp")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer ln.Close()
+ _, port, err := SplitHostPort(ln.Addr().String())
+ if err != nil {
+ t.Fatal(err)
+ }
+ c, err := Dial("tcp", JoinHostPort("", port))
+ if err != nil {
+ t.Fatal(err)
+ }
+ c.Close()
+}
+
func TestDialTimeoutFDLeak(t *testing.T) {
switch runtime.GOOS {
case "plan9":
diff --git a/src/net/dnsclient.go b/src/net/dnsclient.go
index f1835b8..2ab5639 100644
--- a/src/net/dnsclient.go
+++ b/src/net/dnsclient.go
@@ -113,12 +113,20 @@ func equalASCIILabel(x, y string) bool {
return true
}
+// isDomainName checks if a string is a presentation-format domain name
+// (currently restricted to hostname-compatible "preferred name" LDH labels and
+// SRV-like "underscore labels"; see golang.org/issue/12421).
func isDomainName(s string) bool {
// See RFC 1035, RFC 3696.
- if len(s) == 0 {
- return false
- }
- if len(s) > 255 {
+ // Presentation format has dots before every label except the first, and the
+ // terminal empty label is optional here because we assume fully-qualified
+ // (absolute) input. We must therefore reserve space for the first and last
+ // labels' length octets in wire format, where they are necessary and the
+ // maximum total length is 255.
+ // So our _effective_ maximum is 253, but 254 is not rejected if the last
+ // character is a dot.
+ l := len(s)
+ if l == 0 || l > 254 || l == 254 && s[l-1] != '.' {
return false
}
diff --git a/src/net/dnsclient_unix.go b/src/net/dnsclient_unix.go
index b5b6ffb..2980302 100644
--- a/src/net/dnsclient_unix.go
+++ b/src/net/dnsclient_unix.go
@@ -125,7 +125,7 @@ func (d *Dialer) dialDNS(ctx context.Context, network, server string) (dnsConn,
// 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[i] are IP
+ // 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 {
@@ -182,13 +182,14 @@ 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) {
- if len(cfg.servers) == 0 {
- return "", nil, &DNSError{Err: "no DNS servers", Name: name}
- }
-
var lastErr error
+ serverOffset := cfg.serverOffset()
+ sLen := uint32(len(cfg.servers))
+
for i := 0; i < cfg.attempts; i++ {
- for _, server := range cfg.servers {
+ for j := uint32(0); j < sLen; j++ {
+ server := cfg.servers[(serverOffset+j)%sLen]
+
msg, err := exchange(ctx, server, name, qtype, cfg.timeout)
if err != nil {
lastErr = &DNSError{
@@ -315,7 +316,12 @@ func (conf *resolverConfig) releaseSema() {
func lookup(ctx context.Context, name string, qtype uint16) (cname string, rrs []dnsRR, err error) {
if !isDomainName(name) {
- return "", nil, &DNSError{Err: "invalid domain name", Name: name}
+ // We used to use "invalid domain name" as the error,
+ // but that is a detail of the specific lookup mechanism.
+ // Other lookups might allow broader name syntax
+ // (for example Multicast DNS allows UTF-8; see RFC 6762).
+ // For consistency with libc resolvers, report no such host.
+ return "", nil, &DNSError{Err: errNoSuchHost.Error(), Name: name}
}
resolvConf.tryUpdate("/etc/resolv.conf")
resolvConf.mu.RLock()
@@ -356,14 +362,21 @@ func (conf *dnsConfig) nameList(name string) []string {
return nil
}
+ // Check name length (see isDomainName).
+ l := len(name)
+ rooted := l > 0 && name[l-1] == '.'
+ if l > 254 || l == 254 && rooted {
+ return nil
+ }
+
// If name is rooted (trailing dot), try only that name.
- rooted := len(name) > 0 && name[len(name)-1] == '.'
if rooted {
return []string{name}
}
hasNdots := count(name, '.') >= conf.ndots
name += "."
+ l++
// Build list of search choices.
names := make([]string, 0, 1+len(conf.search))
@@ -371,9 +384,11 @@ func (conf *dnsConfig) nameList(name string) []string {
if hasNdots {
names = append(names, name)
}
- // Try suffixes.
+ // Try suffixes that are not too long (see isDomainName).
for _, suffix := range conf.search {
- names = append(names, name+suffix)
+ if l+len(suffix) <= 254 {
+ names = append(names, name+suffix)
+ }
}
// Try unsuffixed, if not tried first above.
if !hasNdots {
@@ -455,8 +470,9 @@ 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, name string) (addrs []IPAddr, err error) {
- return goLookupIPOrder(ctx, name, hostLookupFilesDNS)
+func goLookupIP(ctx context.Context, host string) (addrs []IPAddr, err error) {
+ order := systemConf().hostLookupOrder(host)
+ return goLookupIPOrder(ctx, host, order)
}
func goLookupIPOrder(ctx context.Context, name string, order hostLookupOrder) (addrs []IPAddr, err error) {
@@ -467,7 +483,8 @@ func goLookupIPOrder(ctx context.Context, name string, order hostLookupOrder) (a
}
}
if !isDomainName(name) {
- return nil, &DNSError{Err: "invalid domain name", Name: name}
+ // See comment in func lookup above about use of errNoSuchHost.
+ return nil, &DNSError{Err: errNoSuchHost.Error(), Name: name}
}
resolvConf.tryUpdate("/etc/resolv.conf")
resolvConf.mu.RLock()
diff --git a/src/net/dnsclient_unix_test.go b/src/net/dnsclient_unix_test.go
index 6ebeeae..7dc364d 100644
--- a/src/net/dnsclient_unix_test.go
+++ b/src/net/dnsclient_unix_test.go
@@ -411,7 +411,7 @@ func TestGoLookupIPWithResolverConfig(t *testing.T) {
// We need to take care with errors on both
// DNS message exchange layer and DNS
// transport layer because goLookupIP may fail
- // when the IP connectivty on node under test
+ // 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)
@@ -668,12 +668,14 @@ func TestIgnoreDNSForgeries(t *testing.T) {
b := make([]byte, 512)
n, err := s.Read(b)
if err != nil {
- t.Fatal(err)
+ t.Error(err)
+ return
}
msg := &dnsMsg{}
if !msg.Unpack(b[:n]) {
- t.Fatal("invalid DNS query")
+ t.Error("invalid DNS query")
+ return
}
s.Write([]byte("garbage DNS response packet"))
@@ -682,7 +684,8 @@ func TestIgnoreDNSForgeries(t *testing.T) {
msg.id++ // make invalid ID
b, ok := msg.Pack()
if !ok {
- t.Fatal("failed to pack DNS response")
+ t.Error("failed to pack DNS response")
+ return
}
s.Write(b)
@@ -701,7 +704,8 @@ func TestIgnoreDNSForgeries(t *testing.T) {
b, ok = msg.Pack()
if !ok {
- t.Fatal("failed to pack DNS response")
+ t.Error("failed to pack DNS response")
+ return
}
s.Write(b)
}()
@@ -797,3 +801,73 @@ func TestRetryTimeout(t *testing.T) {
t.Error("deadline0 still zero", deadline0)
}
}
+
+func TestRotate(t *testing.T) {
+ // without rotation, always uses the first server
+ testRotate(t, false, []string{"192.0.2.1", "192.0.2.2"}, []string{"192.0.2.1:53", "192.0.2.1:53", "192.0.2.1:53"})
+
+ // with rotation, rotates through back to first
+ testRotate(t, true, []string{"192.0.2.1", "192.0.2.2"}, []string{"192.0.2.1:53", "192.0.2.2:53", "192.0.2.1:53"})
+}
+
+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)
+ }
+ defer conf.teardown()
+
+ var confLines []string
+ for _, ns := range nameservers {
+ confLines = append(confLines, "nameserver "+ns)
+ }
+ if rotate {
+ confLines = append(confLines, "options rotate")
+ }
+
+ if err := conf.writeAndUpdate(confLines); err != nil {
+ t.Fatal(err)
+ }
+
+ d := &fakeDNSDialer{}
+ testHookDNSDialer = func() dnsDialer { return d }
+
+ var usedServers []string
+ d.rh = func(s string, q *dnsMsg, _ time.Time) (*dnsMsg, error) {
+ usedServers = append(usedServers, s)
+
+ r := &dnsMsg{
+ dnsMsgHdr: dnsMsgHdr{
+ id: q.id,
+ response: true,
+ recursion_available: true,
+ },
+ question: q.question,
+ answer: []dnsRR{
+ &dnsRR_CNAME{
+ Hdr: dnsRR_Header{
+ Name: q.question[0].Name,
+ Rrtype: dnsTypeCNAME,
+ Class: dnsClassINET,
+ },
+ Cname: "golang.org",
+ },
+ },
+ }
+ return r, nil
+ }
+
+ // len(nameservers) + 1 to allow rotation to get back to start
+ for i := 0; i < len(nameservers)+1; i++ {
+ if _, err := goLookupCNAME(context.Background(), "www.golang.org"); err != nil {
+ t.Fatal(err)
+ }
+ }
+
+ if !reflect.DeepEqual(usedServers, wantServers) {
+ t.Fatalf("rotate=%t got used servers:\n%v\nwant:\n%v", rotate, usedServers, wantServers)
+ }
+}
diff --git a/src/net/dnsconfig_unix.go b/src/net/dnsconfig_unix.go
index aec575e..9c8108d 100644
--- a/src/net/dnsconfig_unix.go
+++ b/src/net/dnsconfig_unix.go
@@ -10,6 +10,7 @@ package net
import (
"os"
+ "sync/atomic"
"time"
)
@@ -29,6 +30,7 @@ type dnsConfig struct {
lookup []string // OpenBSD top-level database "lookup" order
err error // any error that occurs during open of resolv.conf
mtime time.Time // time of resolv.conf modification
+ soffset uint32 // used by serverOffset
}
// See resolv.conf(5) on a Linux machine.
@@ -91,19 +93,21 @@ func dnsReadConfig(filename string) *dnsConfig {
for _, s := range f[1:] {
switch {
case hasPrefix(s, "ndots:"):
- n, _, _ := dtoi(s, 6)
- if n < 1 {
- n = 1
+ n, _, _ := dtoi(s[6:])
+ if n < 0 {
+ n = 0
+ } else if n > 15 {
+ n = 15
}
conf.ndots = n
case hasPrefix(s, "timeout:"):
- n, _, _ := dtoi(s, 8)
+ n, _, _ := dtoi(s[8:])
if n < 1 {
n = 1
}
conf.timeout = time.Duration(n) * time.Second
case hasPrefix(s, "attempts:"):
- n, _, _ := dtoi(s, 9)
+ n, _, _ := dtoi(s[9:])
if n < 1 {
n = 1
}
@@ -134,6 +138,17 @@ func dnsReadConfig(filename string) *dnsConfig {
return conf
}
+// serverOffset returns an offset that can be used to determine
+// indices of servers in c.servers when making queries.
+// When the rotate option is enabled, this offset increases.
+// Otherwise it is always 0.
+func (c *dnsConfig) serverOffset() uint32 {
+ if c.rotate {
+ return atomic.AddUint32(&c.soffset, 1) - 1 // return 0 to start
+ }
+ return 0
+}
+
func dnsDefaultSearch() []string {
hn, err := getHostname()
if err != nil {
diff --git a/src/net/dnsconfig_unix_test.go b/src/net/dnsconfig_unix_test.go
index 9fd6dbf..37bdeb0 100644
--- a/src/net/dnsconfig_unix_test.go
+++ b/src/net/dnsconfig_unix_test.go
@@ -10,6 +10,7 @@ import (
"errors"
"os"
"reflect"
+ "strings"
"testing"
"time"
)
@@ -61,6 +62,36 @@ var dnsReadConfigTests = []struct {
},
},
{
+ name: "testdata/invalid-ndots-resolv.conf",
+ want: &dnsConfig{
+ servers: defaultNS,
+ ndots: 0,
+ timeout: 5 * time.Second,
+ attempts: 2,
+ search: []string{"domain.local."},
+ },
+ },
+ {
+ name: "testdata/large-ndots-resolv.conf",
+ want: &dnsConfig{
+ servers: defaultNS,
+ ndots: 15,
+ timeout: 5 * time.Second,
+ attempts: 2,
+ search: []string{"domain.local."},
+ },
+ },
+ {
+ name: "testdata/negative-ndots-resolv.conf",
+ want: &dnsConfig{
+ servers: defaultNS,
+ ndots: 0,
+ timeout: 5 * time.Second,
+ attempts: 2,
+ search: []string{"domain.local."},
+ },
+ },
+ {
name: "testdata/openbsd-resolv.conf",
want: &dnsConfig{
ndots: 1,
@@ -154,3 +185,55 @@ func TestDNSDefaultSearch(t *testing.T) {
}
}
}
+
+func TestDNSNameLength(t *testing.T) {
+ origGetHostname := getHostname
+ defer func() { getHostname = origGetHostname }()
+ getHostname = func() (string, error) { return "host.domain.local", nil }
+
+ var char63 = ""
+ for i := 0; i < 63; i++ {
+ char63 += "a"
+ }
+ longDomain := strings.Repeat(char63+".", 5) + "example"
+
+ for _, tt := range dnsReadConfigTests {
+ conf := dnsReadConfig(tt.name)
+ if conf.err != nil {
+ t.Fatal(conf.err)
+ }
+
+ var shortestSuffix int
+ for _, suffix := range tt.want.search {
+ if shortestSuffix == 0 || len(suffix) < shortestSuffix {
+ shortestSuffix = len(suffix)
+ }
+ }
+
+ // Test a name that will be maximally long when prefixing the shortest
+ // suffix (accounting for the intervening dot).
+ longName := longDomain[len(longDomain)-254+1+shortestSuffix:]
+ if longName[0] == '.' || longName[1] == '.' {
+ longName = "aa." + longName[3:]
+ }
+ for _, fqdn := range conf.nameList(longName) {
+ if len(fqdn) > 254 {
+ t.Errorf("got %d; want less than or equal to 254", len(fqdn))
+ }
+ }
+
+ // Now test a name that's too long for suffixing.
+ unsuffixable := "a." + longName[1:]
+ unsuffixableResults := conf.nameList(unsuffixable)
+ if len(unsuffixableResults) != 1 {
+ t.Errorf("suffixed names %v; want []", unsuffixableResults[1:])
+ }
+
+ // Now test a name that's too long for DNS.
+ tooLong := "a." + longDomain
+ tooLongResults := conf.nameList(tooLong)
+ if tooLongResults != nil {
+ t.Errorf("suffixed names %v; want nil", tooLongResults)
+ }
+ }
+}
diff --git a/src/net/dnsmsg.go b/src/net/dnsmsg.go
index afdb44c..8f6c7b6 100644
--- a/src/net/dnsmsg.go
+++ b/src/net/dnsmsg.go
@@ -69,7 +69,7 @@ const (
)
// A dnsStruct describes how to iterate over its fields to emulate
-// reflective marshalling.
+// reflective marshaling.
type dnsStruct interface {
// Walk iterates over fields of a structure and calls f
// with a reference to that field, the name of the field
diff --git a/src/net/dnsmsg_test.go b/src/net/dnsmsg_test.go
index 25bd98c..2a25a21 100644
--- a/src/net/dnsmsg_test.go
+++ b/src/net/dnsmsg_test.go
@@ -117,7 +117,7 @@ func TestDNSParseSRVReply(t *testing.T) {
if !ok {
t.Fatal("unpacking packet failed")
}
- msg.String() // exercise this code path
+ _ = msg.String() // exercise this code path
if g, e := len(msg.answer), 5; g != e {
t.Errorf("len(msg.answer) = %d; want %d", g, e)
}
@@ -165,7 +165,7 @@ func TestDNSParseCorruptSRVReply(t *testing.T) {
if !ok {
t.Fatal("unpacking packet failed")
}
- msg.String() // exercise this code path
+ _ = msg.String() // exercise this code path
if g, e := len(msg.answer), 5; g != e {
t.Errorf("len(msg.answer) = %d; want %d", g, e)
}
@@ -393,7 +393,7 @@ func TestIsResponseTo(t *testing.T) {
for i := range badResponses {
if badResponses[i].IsResponseTo(&query) {
- t.Error("%v: got true, want false", i)
+ t.Errorf("%v: got true, want false", i)
}
}
}
diff --git a/src/net/dnsname_test.go b/src/net/dnsname_test.go
index bc777b8..e0f786d 100644
--- a/src/net/dnsname_test.go
+++ b/src/net/dnsname_test.go
@@ -32,14 +32,12 @@ var dnsNameTests = []dnsNameTest{
func emitDNSNameTest(ch chan<- dnsNameTest) {
defer close(ch)
- var char59 = ""
var char63 = ""
- var char64 = ""
- for i := 0; i < 59; i++ {
- char59 += "a"
+ for i := 0; i < 63; i++ {
+ char63 += "a"
}
- char63 = char59 + "aaaa"
- char64 = char63 + "a"
+ char64 := char63 + "a"
+ longDomain := strings.Repeat(char63+".", 5) + "example"
for _, tc := range dnsNameTests {
ch <- tc
@@ -47,14 +45,15 @@ func emitDNSNameTest(ch chan<- dnsNameTest) {
ch <- dnsNameTest{char63 + ".com", true}
ch <- dnsNameTest{char64 + ".com", false}
- // 255 char name is fine:
- ch <- dnsNameTest{char59 + "." + char63 + "." + char63 + "." +
- char63 + ".com",
- true}
- // 256 char name is bad:
- ch <- dnsNameTest{char59 + "a." + char63 + "." + char63 + "." +
- char63 + ".com",
- false}
+
+ // Remember: wire format is two octets longer than presentation
+ // (length octets for the first and [root] last labels).
+ // 253 is fine:
+ ch <- dnsNameTest{longDomain[len(longDomain)-253:], true}
+ // A terminal dot doesn't contribute to length:
+ ch <- dnsNameTest{longDomain[len(longDomain)-253:] + ".", true}
+ // 254 is bad:
+ ch <- dnsNameTest{longDomain[len(longDomain)-254:], false}
}
func TestDNSName(t *testing.T) {
diff --git a/src/net/error_test.go b/src/net/error_test.go
index d6de5a3..c23da49 100644
--- a/src/net/error_test.go
+++ b/src/net/error_test.go
@@ -97,7 +97,8 @@ second:
goto third
}
switch nestedErr {
- case errCanceled, errClosing, errMissingAddress, errNoSuitableAddress:
+ case errCanceled, errClosing, errMissingAddress, errNoSuitableAddress,
+ context.DeadlineExceeded, context.Canceled:
return nil
}
return fmt.Errorf("unexpected type on 2nd nested level: %T", nestedErr)
@@ -230,23 +231,27 @@ func TestDialAddrError(t *testing.T) {
} {
var err error
var c Conn
+ var op string
if tt.lit != "" {
c, err = Dial(tt.network, JoinHostPort(tt.lit, "0"))
+ op = fmt.Sprintf("Dial(%q, %q)", tt.network, JoinHostPort(tt.lit, "0"))
} else {
c, err = DialTCP(tt.network, nil, tt.addr)
+ op = fmt.Sprintf("DialTCP(%q, %q)", tt.network, tt.addr)
}
if err == nil {
c.Close()
- t.Errorf("%s %q/%v: should fail", tt.network, tt.lit, tt.addr)
+ t.Errorf("%s succeeded, want error", op)
continue
}
if perr := parseDialError(err); perr != nil {
- t.Error(perr)
+ t.Errorf("%s: %v", op, perr)
continue
}
- aerr, ok := err.(*OpError).Err.(*AddrError)
+ operr := err.(*OpError).Err
+ aerr, ok := operr.(*AddrError)
if !ok {
- t.Errorf("%s %q/%v: should be AddrError: %v", tt.network, tt.lit, tt.addr, err)
+ t.Errorf("%s: %v is %T, want *AddrError", op, err, operr)
continue
}
want := tt.lit
@@ -254,7 +259,7 @@ func TestDialAddrError(t *testing.T) {
want = tt.addr.IP.String()
}
if aerr.Addr != want {
- t.Fatalf("%s: got %q; want %q", tt.network, aerr.Addr, want)
+ t.Errorf("%s: %v, error Addr=%q, want %q", op, err, aerr.Addr, want)
}
}
}
@@ -521,6 +526,10 @@ third:
if isPlatformError(nestedErr) {
return nil
}
+ switch nestedErr {
+ case os.ErrClosed: // for Plan 9
+ return nil
+ }
return fmt.Errorf("unexpected type on 3rd nested level: %T", nestedErr)
}
diff --git a/src/net/example_test.go b/src/net/example_test.go
index 6f2f907..9dd1732 100644
--- a/src/net/example_test.go
+++ b/src/net/example_test.go
@@ -5,6 +5,7 @@
package net_test
import (
+ "fmt"
"io"
"log"
"net"
@@ -34,3 +35,15 @@ func ExampleListener() {
}(conn)
}
}
+
+func ExampleCIDRMask() {
+ // This mask corresponds to a /31 subnet for IPv4.
+ fmt.Println(net.CIDRMask(31, 32))
+
+ // This mask corresponds to a /64 subnet for IPv6.
+ fmt.Println(net.CIDRMask(64, 128))
+
+ // Output:
+ // fffffffe
+ // ffffffffffffffff0000000000000000
+}
diff --git a/src/net/fd_io_plan9.go b/src/net/fd_io_plan9.go
new file mode 100644
index 0000000..76da0c5
--- /dev/null
+++ b/src/net/fd_io_plan9.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 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_plan9.go b/src/net/fd_plan9.go
index 7533232..300d8c4 100644
--- a/src/net/fd_plan9.go
+++ b/src/net/fd_plan9.go
@@ -7,21 +7,37 @@ package net
import (
"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
// immutable until Close
- net string
- n string
- dir string
- ctl, data *os.File
- laddr, raddr Addr
+ net string
+ n string
+ dir string
+ 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 (
@@ -32,8 +48,16 @@ func sysInit() {
netdir = "/net"
}
-func newFD(net, name string, ctl, data *os.File, laddr, raddr Addr) (*netFD, error) {
- return &netFD{net: net, n: name, dir: netdir + "/" + net + "/" + name, ctl: ctl, data: data, laddr: laddr, raddr: raddr}, nil
+func newFD(net, name string, listen, ctl, data *os.File, laddr, raddr Addr) (*netFD, error) {
+ return &netFD{
+ net: net,
+ n: name,
+ dir: netdir + "/" + net + "/" + name,
+ listen: listen,
+ ctl: ctl, data: data,
+ laddr: laddr,
+ raddr: raddr,
+ }, nil
}
func (fd *netFD) init() error {
@@ -64,11 +88,20 @@ func (fd *netFD) destroy() {
err = err1
}
}
+ if fd.listen != nil {
+ if err1 := fd.listen.Close(); err1 != nil && err == nil {
+ err = err1
+ }
+ }
fd.ctl = nil
fd.data = nil
+ fd.listen = nil
}
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
}
@@ -79,10 +112,15 @@ func (fd *netFD) Read(b []byte) (n int, err error) {
if len(b) == 0 {
return 0, nil
}
- n, err = fd.data.Read(b)
+ 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
+ }
if fd.net == "udp" && err == io.EOF {
n = 0
err = nil
@@ -91,6 +129,9 @@ 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
}
@@ -98,7 +139,13 @@ func (fd *netFD) Write(b []byte) (n int, err error) {
return 0, err
}
defer fd.writeUnlock()
- return fd.data.Write(b)
+ fd.waio = newAsyncIO(fd.data.Write, b)
+ n, err = fd.waio.Wait()
+ fd.waio = nil
+ if isInterrupted(err) {
+ err = errTimeout
+ }
+ return
}
func (fd *netFD) closeRead() error {
@@ -124,11 +171,10 @@ func (fd *netFD) Close() error {
}
if fd.net == "tcp" {
// The following line is required to unblock Reads.
- // For some reason, WriteString returns an error:
- // "write /net/tcp/39/listen: inappropriate use of fd"
- // But without it, Reads on dead conns hang forever.
- // See Issue 9554.
- fd.ctl.WriteString("hangup")
+ _, err := fd.ctl.WriteString("close")
+ if err != nil {
+ return err
+ }
}
err := fd.ctl.Close()
if fd.data != nil {
@@ -136,8 +182,14 @@ func (fd *netFD) Close() error {
err = err1
}
}
+ if fd.listen != nil {
+ if err1 := fd.listen.Close(); err1 != nil && err == nil {
+ err = err1
+ }
+ }
fd.ctl = nil
fd.data = nil
+ fd.listen = nil
return err
}
@@ -165,15 +217,74 @@ func (fd *netFD) file(f *os.File, s string) (*os.File, error) {
}
func (fd *netFD) setDeadline(t time.Time) error {
- return syscall.EPLAN9
+ return setDeadlineImpl(fd, t, 'r'+'w')
}
func (fd *netFD) setReadDeadline(t time.Time) error {
- return syscall.EPLAN9
+ return setDeadlineImpl(fd, t, 'r')
}
func (fd *netFD) setWriteDeadline(t time.Time) error {
- return syscall.EPLAN9
+ 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 {
@@ -187,3 +298,7 @@ func setWriteBuffer(fd *netFD, bytes int) error {
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
index cda8b82..8398760 100644
--- a/src/net/fd_poll_nacl.go
+++ b/src/net/fd_poll_nacl.go
@@ -5,6 +5,7 @@
package net
import (
+ "runtime"
"syscall"
"time"
)
@@ -22,6 +23,7 @@ func (pd *pollDesc) evict() {
pd.closing = true
if pd.fd != nil {
syscall.StopIO(pd.fd.sysfd)
+ runtime.KeepAlive(pd.fd)
}
}
diff --git a/src/net/fd_poll_runtime.go b/src/net/fd_poll_runtime.go
index 6c1d095..62b69fc 100644
--- a/src/net/fd_poll_runtime.go
+++ b/src/net/fd_poll_runtime.go
@@ -7,6 +7,7 @@
package net
import (
+ "runtime"
"sync"
"syscall"
"time"
@@ -33,6 +34,7 @@ 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)
}
@@ -120,7 +122,7 @@ func (fd *netFD) setWriteDeadline(t time.Time) error {
}
func setDeadlineImpl(fd *netFD, t time.Time, mode int) error {
- diff := int64(t.Sub(time.Now()))
+ 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
diff --git a/src/net/fd_unix.go b/src/net/fd_unix.go
index 11dde76..3c95fc0 100644
--- a/src/net/fd_unix.go
+++ b/src/net/fd_unix.go
@@ -24,11 +24,15 @@ type netFD struct {
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
}
@@ -37,7 +41,7 @@ func sysInit() {
}
func newFD(sysfd, family, sotype int, net string) (*netFD, error) {
- return &netFD{sysfd: sysfd, family: family, sotype: sotype, net: net}, nil
+ return &netFD{sysfd: sysfd, family: family, sotype: sotype, net: net, isStream: sotype == syscall.SOCK_STREAM}, nil
}
func (fd *netFD) init() error {
@@ -235,6 +239,9 @@ func (fd *netFD) Read(p []byte) (n int, err error) {
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 {
@@ -318,7 +325,11 @@ func (fd *netFD) Write(p []byte) (nn int, err error) {
}
for {
var n int
- n, err = syscall.Write(fd.sysfd, p[nn:])
+ 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
}
diff --git a/src/net/fd_windows.go b/src/net/fd_windows.go
index b0b6769..a976f2a 100644
--- a/src/net/fd_windows.go
+++ b/src/net/fd_windows.go
@@ -96,6 +96,7 @@ type operation struct {
rsan int32
handle syscall.Handle
flags uint32
+ bufs []syscall.WSABuf
}
func (o *operation) InitBuf(buf []byte) {
@@ -106,6 +107,30 @@ func (o *operation) InitBuf(buf []byte) {
}
}
+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
@@ -239,6 +264,7 @@ type netFD struct {
sysfd syscall.Handle
family int
sotype int
+ isStream bool
isConnected bool
skipSyncNotif bool
net string
@@ -257,7 +283,7 @@ func newFD(sysfd syscall.Handle, family, sotype int, net string) (*netFD, error)
return nil, initErr
}
onceStartServer.Do(startServer)
- return &netFD{sysfd: sysfd, family: family, sotype: sotype, net: net}, nil
+ return &netFD{sysfd: sysfd, family: family, sotype: sotype, net: net, isStream: sotype == syscall.SOCK_STREAM}, nil
}
func (fd *netFD) init() error {
@@ -483,6 +509,42 @@ func (fd *netFD) Write(buf []byte) (int, error) {
return n, err
}
+func (c *conn) writeBuffers(v *Buffers) (int64, error) {
+ if !c.ok() {
+ return 0, syscall.EINVAL
+ }
+ 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, 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
+}
+
func (fd *netFD) writeTo(buf []byte, sa syscall.Sockaddr) (int, error) {
if len(buf) == 0 {
return 0, nil
@@ -541,7 +603,7 @@ func (fd *netFD) acceptOne(rawsa []syscall.RawSockaddrAny, o *operation) (*netFD
netfd.Close()
return nil, os.NewSyscallError("setsockopt", err)
}
-
+ runtime.KeepAlive(fd)
return netfd, nil
}
diff --git a/src/net/file.go b/src/net/file.go
index 1aad477..0709985 100644
--- a/src/net/file.go
+++ b/src/net/file.go
@@ -6,6 +6,9 @@ package net
import "os"
+// BUG(mikio): On NaCl and Windows, the FileConn, FileListener and
+// FilePacketConn functions are not implemented.
+
type fileAddr string
func (fileAddr) Network() string { return "file+net" }
diff --git a/src/net/file_plan9.go b/src/net/file_plan9.go
index 2939c09..d16e5a1 100644
--- a/src/net/file_plan9.go
+++ b/src/net/file_plan9.go
@@ -81,7 +81,7 @@ func newFileFD(f *os.File) (net *netFD, err error) {
if err != nil {
return nil, err
}
- return newFD(comp[1], name, ctl, nil, laddr, nil)
+ return newFD(comp[1], name, nil, ctl, nil, laddr, nil)
}
func fileConn(f *os.File) (Conn, error) {
diff --git a/src/net/http/client.go b/src/net/http/client.go
index 993c247..fe2b019 100644
--- a/src/net/http/client.go
+++ b/src/net/http/client.go
@@ -18,6 +18,7 @@ import (
"io/ioutil"
"log"
"net/url"
+ "sort"
"strings"
"sync"
"time"
@@ -33,6 +34,25 @@ import (
// A Client is higher-level than a RoundTripper (such as Transport)
// and additionally handles HTTP details such as cookies and
// redirects.
+//
+// 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.
+//
type Client struct {
// Transport specifies the mechanism by which individual
// HTTP requests are made.
@@ -56,8 +76,14 @@ type Client struct {
CheckRedirect func(req *Request, via []*Request) error
// Jar specifies the cookie jar.
- // If Jar is nil, cookies are not sent in requests and ignored
- // in responses.
+ //
+ // The Jar is used to insert relevant cookies into every
+ // outbound Request and is updated with the cookie values
+ // of every inbound Response. The Jar is consulted for every
+ // redirect that the Client follows.
+ //
+ // If Jar is nil, cookies are only sent if they are explicitly
+ // set on the Request.
Jar CookieJar
// Timeout specifies a time limit for requests made by this
@@ -155,40 +181,6 @@ func (c *Client) send(req *Request, deadline time.Time) (*Response, error) {
return resp, nil
}
-// Do sends an HTTP request and returns an HTTP response, following
-// policy (such as redirects, cookies, auth) as configured on the
-// client.
-//
-// An error is returned if caused by client policy (such as
-// CheckRedirect), or failure to speak HTTP (such as a network
-// connectivity problem). A non-2xx status code doesn't cause an
-// error.
-//
-// If the returned error is nil, the Response will contain a non-nil
-// Body which the user is expected to close. If the Body is not
-// closed, the Client's underlying RoundTripper (typically Transport)
-// may not be able to re-use a persistent TCP connection to the server
-// for a subsequent "keep-alive" request.
-//
-// The request Body, if non-nil, will be closed by the underlying
-// Transport, even on errors.
-//
-// On error, any Response can be ignored. A non-nil Response with a
-// non-nil error only occurs when CheckRedirect fails, and even then
-// the returned Response.Body is already closed.
-//
-// Generally Get, Post, or PostForm will be used instead of Do.
-func (c *Client) Do(req *Request) (*Response, error) {
- method := valueOrDefault(req.Method, "GET")
- if method == "GET" || method == "HEAD" {
- return c.doFollowingRedirects(req, shouldRedirectGet)
- }
- if method == "POST" || method == "PUT" {
- return c.doFollowingRedirects(req, shouldRedirectPost)
- }
- return c.send(req, c.deadline())
-}
-
func (c *Client) deadline() time.Time {
if c.Timeout > 0 {
return time.Now().Add(c.Timeout)
@@ -251,7 +243,7 @@ func send(ireq *Request, rt RoundTripper, deadline time.Time) (*Response, error)
if !deadline.IsZero() {
forkReq()
}
- stopTimer, wasCanceled := setRequestCancel(req, rt, deadline)
+ stopTimer, didTimeout := setRequestCancel(req, rt, deadline)
resp, err := rt.RoundTrip(req)
if err != nil {
@@ -271,9 +263,9 @@ func send(ireq *Request, rt RoundTripper, deadline time.Time) (*Response, error)
}
if !deadline.IsZero() {
resp.Body = &cancelTimerBody{
- stop: stopTimer,
- rc: resp.Body,
- reqWasCanceled: wasCanceled,
+ stop: stopTimer,
+ rc: resp.Body,
+ reqDidTimeout: didTimeout,
}
}
return resp, nil
@@ -282,7 +274,7 @@ func send(ireq *Request, rt RoundTripper, deadline time.Time) (*Response, error)
// setRequestCancel sets the Cancel field of req, if deadline is
// non-zero. The RoundTripper's type is used to determine whether the legacy
// CancelRequest behavior should be used.
-func setRequestCancel(req *Request, rt RoundTripper, deadline time.Time) (stopTimer func(), wasCanceled func() bool) {
+func setRequestCancel(req *Request, rt RoundTripper, deadline time.Time) (stopTimer func(), didTimeout func() bool) {
if deadline.IsZero() {
return nop, alwaysFalse
}
@@ -292,15 +284,6 @@ func setRequestCancel(req *Request, rt RoundTripper, deadline time.Time) (stopTi
cancel := make(chan struct{})
req.Cancel = cancel
- wasCanceled = func() bool {
- select {
- case <-cancel:
- return true
- default:
- return false
- }
- }
-
doCancel := func() {
// The new way:
close(cancel)
@@ -324,19 +307,23 @@ func setRequestCancel(req *Request, rt RoundTripper, deadline time.Time) (stopTi
var once sync.Once
stopTimer = func() { once.Do(func() { close(stopTimerCh) }) }
- timer := time.NewTimer(deadline.Sub(time.Now()))
+ timer := time.NewTimer(time.Until(deadline))
+ var timedOut atomicBool
+
go func() {
select {
case <-initialReqCancel:
doCancel()
+ timer.Stop()
case <-timer.C:
+ timedOut.setTrue()
doCancel()
case <-stopTimerCh:
timer.Stop()
}
}()
- return stopTimer, wasCanceled
+ return stopTimer, timedOut.isSet
}
// See 2 (end of page 4) http://www.ietf.org/rfc/rfc2617.txt
@@ -349,26 +336,6 @@ func basicAuth(username, password string) string {
return base64.StdEncoding.EncodeToString([]byte(auth))
}
-// True if the specified HTTP status code is one for which the Get utility should
-// automatically redirect.
-func shouldRedirectGet(statusCode int) bool {
- switch statusCode {
- case StatusMovedPermanently, StatusFound, StatusSeeOther, StatusTemporaryRedirect:
- return true
- }
- return false
-}
-
-// True if the specified HTTP status code is one for which the Post utility should
-// automatically redirect.
-func shouldRedirectPost(statusCode int) bool {
- switch statusCode {
- case StatusFound, StatusSeeOther:
- return true
- }
- return false
-}
-
// Get issues a GET to the specified URL. If the response is one of
// the following redirect codes, Get follows the redirect, up to a
// maximum of 10 redirects:
@@ -377,6 +344,7 @@ func shouldRedirectPost(statusCode int) bool {
// 302 (Found)
// 303 (See Other)
// 307 (Temporary Redirect)
+// 308 (Permanent Redirect)
//
// An error is returned if there were too many redirects or if there
// was an HTTP protocol error. A non-2xx response doesn't cause an
@@ -401,6 +369,7 @@ func Get(url string) (resp *Response, err error) {
// 302 (Found)
// 303 (See Other)
// 307 (Temporary Redirect)
+// 308 (Permanent Redirect)
//
// An error is returned if the Client's CheckRedirect function fails
// or if there was an HTTP protocol error. A non-2xx response doesn't
@@ -415,7 +384,7 @@ func (c *Client) Get(url string) (resp *Response, err error) {
if err != nil {
return nil, err
}
- return c.doFollowingRedirects(req, shouldRedirectGet)
+ return c.Do(req)
}
func alwaysFalse() bool { return false }
@@ -436,16 +405,77 @@ func (c *Client) checkRedirect(req *Request, via []*Request) error {
return fn(req, via)
}
-func (c *Client) doFollowingRedirects(req *Request, shouldRedirect func(int) bool) (*Response, error) {
+// redirectBehavior describes what should happen when the
+// client encounters a 3xx status code from the server
+func redirectBehavior(reqMethod string, resp *Response, via []*Request) (redirectMethod string, shouldRedirect bool) {
+ switch resp.StatusCode {
+ case 301, 302, 303:
+ redirectMethod = "GET"
+ shouldRedirect = true
+ case 307, 308:
+ redirectMethod = reqMethod
+ shouldRedirect = true
+
+ // Treat 307 and 308 specially, since they're new in
+ // Go 1.8, and they also require re-sending the request body.
+ loc := resp.Header.Get("Location")
+ if loc == "" {
+ // 308s have been observed in the wild being served
+ // without Location headers. Since Go 1.7 and earlier
+ // didn't follow these codes, just stop here instead
+ // of returning an error.
+ // See Issue 17773.
+ shouldRedirect = false
+ break
+ }
+ ireq := via[0]
+ if ireq.GetBody == nil && ireq.outgoingLength() != 0 {
+ // We had a request body, and 307/308 require
+ // re-sending it, but GetBody is not defined. So just
+ // return this response to the user instead of an
+ // error, like we did in Go 1.7 and earlier.
+ shouldRedirect = false
+ }
+ }
+
+ return redirectMethod, shouldRedirect
+}
+
+// Do sends an HTTP request and returns an HTTP response, following
+// policy (such as redirects, cookies, auth) as configured on the
+// client.
+//
+// An error is returned if caused by client policy (such as
+// CheckRedirect), or failure to speak HTTP (such as a network
+// connectivity problem). A non-2xx status code doesn't cause an
+// error.
+//
+// If the returned error is nil, the Response will contain a non-nil
+// Body which the user is expected to close. If the Body is not
+// closed, the Client's underlying RoundTripper (typically Transport)
+// may not be able to re-use a persistent TCP connection to the server
+// for a subsequent "keep-alive" request.
+//
+// The request Body, if non-nil, will be closed by the underlying
+// Transport, even on errors.
+//
+// On error, any Response can be ignored. A non-nil Response with a
+// non-nil error only occurs when CheckRedirect fails, and even then
+// the returned Response.Body is already closed.
+//
+// Generally Get, Post, or PostForm will be used instead of Do.
+func (c *Client) Do(req *Request) (*Response, error) {
if req.URL == nil {
req.closeBody()
return nil, errors.New("http: nil Request.URL")
}
var (
- deadline = c.deadline()
- reqs []*Request
- resp *Response
+ deadline = c.deadline()
+ reqs []*Request
+ resp *Response
+ copyHeaders = c.makeHeadersCopier(req)
+ redirectMethod string
)
uerr := func(err error) error {
req.closeBody()
@@ -476,16 +506,27 @@ func (c *Client) doFollowingRedirects(req *Request, shouldRedirect func(int) boo
}
ireq := reqs[0]
req = &Request{
- Method: ireq.Method,
+ Method: redirectMethod,
Response: resp,
URL: u,
Header: make(Header),
Cancel: ireq.Cancel,
ctx: ireq.ctx,
}
- if ireq.Method == "POST" || ireq.Method == "PUT" {
- req.Method = "GET"
+ if ireq.GetBody != nil {
+ req.Body, err = ireq.GetBody()
+ if err != nil {
+ return nil, uerr(err)
+ }
+ req.ContentLength = ireq.ContentLength
}
+
+ // Copy original headers before setting the Referer,
+ // in case the user set Referer on their first request.
+ // If they really want to override, they can do it in
+ // their CheckRedirect func.
+ copyHeaders(req)
+
// Add the Referer header from the most recent
// request URL to the new one, if it's not https->http:
if ref := refererForURL(reqs[len(reqs)-1].URL, req.URL); ref != "" {
@@ -523,7 +564,6 @@ func (c *Client) doFollowingRedirects(req *Request, shouldRedirect func(int) boo
}
reqs = append(reqs, req)
-
var err error
if resp, err = c.send(req, deadline); err != nil {
if !deadline.IsZero() && !time.Now().Before(deadline) {
@@ -535,9 +575,77 @@ func (c *Client) doFollowingRedirects(req *Request, shouldRedirect func(int) boo
return nil, uerr(err)
}
- if !shouldRedirect(resp.StatusCode) {
+ var shouldRedirect bool
+ redirectMethod, shouldRedirect = redirectBehavior(req.Method, resp, reqs)
+ if !shouldRedirect {
return resp, nil
}
+
+ req.closeBody()
+ }
+}
+
+// makeHeadersCopier makes a function that copies headers from the
+// initial Request, ireq. For every redirect, this function must be called
+// so that it can copy headers into the upcoming Request.
+func (c *Client) makeHeadersCopier(ireq *Request) func(*Request) {
+ // The headers to copy are from the very initial request.
+ // We use a closured callback to keep a reference to these original headers.
+ var (
+ ireqhdr = ireq.Header.clone()
+ icookies map[string][]*Cookie
+ )
+ if c.Jar != nil && ireq.Header.Get("Cookie") != "" {
+ icookies = make(map[string][]*Cookie)
+ for _, c := range ireq.Cookies() {
+ icookies[c.Name] = append(icookies[c.Name], c)
+ }
+ }
+
+ preq := ireq // The previous request
+ return func(req *Request) {
+ // If Jar is present and there was some initial cookies provided
+ // via the request header, then we may need to alter the initial
+ // cookies as we follow redirects since each redirect may end up
+ // modifying a pre-existing cookie.
+ //
+ // Since cookies already set in the request header do not contain
+ // information about the original domain and path, the logic below
+ // assumes any new set cookies override the original cookie
+ // regardless of domain or path.
+ //
+ // See https://golang.org/issue/17494
+ if c.Jar != nil && icookies != nil {
+ var changed bool
+ resp := req.Response // The response that caused the upcoming redirect
+ for _, c := range resp.Cookies() {
+ if _, ok := icookies[c.Name]; ok {
+ delete(icookies, c.Name)
+ changed = true
+ }
+ }
+ if changed {
+ ireqhdr.Del("Cookie")
+ var ss []string
+ for _, cs := range icookies {
+ for _, c := range cs {
+ ss = append(ss, c.Name+"="+c.Value)
+ }
+ }
+ sort.Strings(ss) // Ensure deterministic headers
+ ireqhdr.Set("Cookie", strings.Join(ss, "; "))
+ }
+ }
+
+ // Copy the initial request's Header values
+ // (at least the safe ones).
+ for k, vv := range ireqhdr {
+ if shouldCopyHeaderOnRedirect(k, preq.URL, req.URL) {
+ req.Header[k] = vv
+ }
+ }
+
+ preq = req // Update previous Request with the current request
}
}
@@ -558,8 +666,8 @@ func defaultCheckRedirect(req *Request, via []*Request) error {
// Post is a wrapper around DefaultClient.Post.
//
// To set custom headers, use NewRequest and DefaultClient.Do.
-func Post(url string, bodyType string, body io.Reader) (resp *Response, err error) {
- return DefaultClient.Post(url, bodyType, body)
+func Post(url string, contentType string, body io.Reader) (resp *Response, err error) {
+ return DefaultClient.Post(url, contentType, body)
}
// Post issues a POST to the specified URL.
@@ -570,13 +678,13 @@ func Post(url string, bodyType string, body io.Reader) (resp *Response, err erro
// request.
//
// To set custom headers, use NewRequest and Client.Do.
-func (c *Client) Post(url string, bodyType string, body io.Reader) (resp *Response, err error) {
+func (c *Client) Post(url string, contentType string, body io.Reader) (resp *Response, err error) {
req, err := NewRequest("POST", url, body)
if err != nil {
return nil, err
}
- req.Header.Set("Content-Type", bodyType)
- return c.doFollowingRedirects(req, shouldRedirectPost)
+ req.Header.Set("Content-Type", contentType)
+ return c.Do(req)
}
// PostForm issues a POST to the specified URL, with data's keys and
@@ -605,7 +713,7 @@ func (c *Client) PostForm(url string, data url.Values) (resp *Response, err erro
return c.Post(url, "application/x-www-form-urlencoded", strings.NewReader(data.Encode()))
}
-// Head issues a HEAD to the specified URL. If the response is one of
+// Head issues a HEAD to the specified URL. If the response is one of
// the following redirect codes, Head follows the redirect, up to a
// maximum of 10 redirects:
//
@@ -613,13 +721,14 @@ func (c *Client) PostForm(url string, data url.Values) (resp *Response, err erro
// 302 (Found)
// 303 (See Other)
// 307 (Temporary Redirect)
+// 308 (Permanent Redirect)
//
// Head is a wrapper around DefaultClient.Head
func Head(url string) (resp *Response, err error) {
return DefaultClient.Head(url)
}
-// Head issues a HEAD to the specified URL. If the response is one of the
+// Head issues a HEAD to the specified URL. If the response is one of the
// following redirect codes, Head follows the redirect after calling the
// Client's CheckRedirect function:
//
@@ -627,22 +736,23 @@ func Head(url string) (resp *Response, err error) {
// 302 (Found)
// 303 (See Other)
// 307 (Temporary Redirect)
+// 308 (Permanent Redirect)
func (c *Client) Head(url string) (resp *Response, err error) {
req, err := NewRequest("HEAD", url, nil)
if err != nil {
return nil, err
}
- return c.doFollowingRedirects(req, shouldRedirectGet)
+ return c.Do(req)
}
// cancelTimerBody is an io.ReadCloser that wraps rc with two features:
// 1) on Read error or close, the stop func is called.
-// 2) On Read failure, if reqWasCanceled is true, the error is wrapped and
+// 2) On Read failure, if reqDidTimeout is true, the error is wrapped and
// marked as net.Error that hit its timeout.
type cancelTimerBody struct {
- stop func() // stops the time.Timer waiting to cancel the request
- rc io.ReadCloser
- reqWasCanceled func() bool
+ stop func() // stops the time.Timer waiting to cancel the request
+ rc io.ReadCloser
+ reqDidTimeout func() bool
}
func (b *cancelTimerBody) Read(p []byte) (n int, err error) {
@@ -654,7 +764,7 @@ func (b *cancelTimerBody) Read(p []byte) (n int, err error) {
if err == io.EOF {
return n, err
}
- if b.reqWasCanceled() {
+ if b.reqDidTimeout() {
err = &httpError{
err: err.Error() + " (Client.Timeout exceeded while reading body)",
timeout: true,
@@ -668,3 +778,52 @@ func (b *cancelTimerBody) Close() error {
b.stop()
return err
}
+
+func shouldCopyHeaderOnRedirect(headerKey string, initial, dest *url.URL) bool {
+ switch CanonicalHeaderKey(headerKey) {
+ case "Authorization", "Www-Authenticate", "Cookie", "Cookie2":
+ // Permit sending auth/cookie headers from "foo.com"
+ // to "sub.foo.com".
+
+ // Note that we don't send all cookies to subdomains
+ // automatically. This function is only used for
+ // Cookies set explicitly on the initial outgoing
+ // client request. Cookies automatically added via the
+ // CookieJar mechanism continue to follow each
+ // cookie's scope as set by Set-Cookie. But for
+ // outgoing requests with the Cookie header set
+ // directly, we don't know their scope, so we assume
+ // it's for *.domain.com.
+
+ // TODO(bradfitz): once issue 16142 is fixed, make
+ // this code use those URL accessors, and consider
+ // "http://foo.com" and "http://foo.com:80" as
+ // equivalent?
+
+ // TODO(bradfitz): better hostname canonicalization,
+ // at least once we figure out IDNA/Punycode (issue
+ // 13835).
+ ihost := strings.ToLower(initial.Host)
+ dhost := strings.ToLower(dest.Host)
+ return isDomainOrSubdomain(dhost, ihost)
+ }
+ // All other headers are copied:
+ return true
+}
+
+// isDomainOrSubdomain reports whether sub is a subdomain (or exact
+// match) of the parent domain.
+//
+// Both domains must already be in canonical form.
+func isDomainOrSubdomain(sub, parent string) bool {
+ if sub == parent {
+ return true
+ }
+ // If sub is "foo.example.com" and parent is "example.com",
+ // that means sub must end in "."+parent.
+ // Do it without allocating.
+ if !strings.HasSuffix(sub, parent) {
+ return false
+ }
+ return sub[len(sub)-len(parent)-1] == '.'
+}
diff --git a/src/net/http/client_test.go b/src/net/http/client_test.go
index a9b1948..a5f58cb 100644
--- a/src/net/http/client_test.go
+++ b/src/net/http/client_test.go
@@ -19,8 +19,10 @@ import (
"log"
"net"
. "net/http"
+ "net/http/cookiejar"
"net/http/httptest"
"net/url"
+ "reflect"
"strconv"
"strings"
"sync"
@@ -65,11 +67,13 @@ func (w chanWriter) Write(p []byte) (n int, err error) {
}
func TestClient(t *testing.T) {
+ setParallel(t)
defer afterTest(t)
ts := httptest.NewServer(robotsTxtHandler)
defer ts.Close()
- r, err := Get(ts.URL)
+ c := &Client{Transport: &Transport{DisableKeepAlives: true}}
+ r, err := c.Get(ts.URL)
var b []byte
if err == nil {
b, err = pedanticReadAll(r.Body)
@@ -109,6 +113,7 @@ func (t *recordingTransport) RoundTrip(req *Request) (resp *Response, err error)
}
func TestGetRequestFormat(t *testing.T) {
+ setParallel(t)
defer afterTest(t)
tr := &recordingTransport{}
client := &Client{Transport: tr}
@@ -195,6 +200,7 @@ func TestPostFormRequestFormat(t *testing.T) {
}
func TestClientRedirects(t *testing.T) {
+ setParallel(t)
defer afterTest(t)
var ts *httptest.Server
ts = httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
@@ -206,14 +212,17 @@ func TestClientRedirects(t *testing.T) {
}
}
if n < 15 {
- Redirect(w, r, fmt.Sprintf("/?n=%d", n+1), StatusFound)
+ Redirect(w, r, fmt.Sprintf("/?n=%d", n+1), StatusTemporaryRedirect)
return
}
fmt.Fprintf(w, "n=%d", n)
}))
defer ts.Close()
- c := &Client{}
+ tr := &Transport{}
+ defer tr.CloseIdleConnections()
+
+ c := &Client{Transport: tr}
_, 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)
@@ -242,11 +251,14 @@ func TestClientRedirects(t *testing.T) {
var checkErr error
var lastVia []*Request
var lastReq *Request
- c = &Client{CheckRedirect: func(req *Request, via []*Request) error {
- lastReq = req
- lastVia = via
- return checkErr
- }}
+ c = &Client{
+ Transport: tr,
+ CheckRedirect: func(req *Request, via []*Request) error {
+ lastReq = req
+ lastVia = via
+ return checkErr
+ },
+ }
res, err := c.Get(ts.URL)
if err != nil {
t.Fatalf("Get error: %v", err)
@@ -292,20 +304,27 @@ func TestClientRedirects(t *testing.T) {
}
func TestClientRedirectContext(t *testing.T) {
+ setParallel(t)
defer afterTest(t)
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
- Redirect(w, r, "/", StatusFound)
+ Redirect(w, r, "/", StatusTemporaryRedirect)
}))
defer ts.Close()
+ tr := &Transport{}
+ defer tr.CloseIdleConnections()
+
ctx, cancel := context.WithCancel(context.Background())
- c := &Client{CheckRedirect: func(req *Request, via []*Request) error {
- cancel()
- if len(via) > 2 {
- return errors.New("too many redirects")
- }
- return nil
- }}
+ c := &Client{
+ Transport: tr,
+ CheckRedirect: func(req *Request, via []*Request) error {
+ cancel()
+ if len(via) > 2 {
+ return errors.New("too many redirects")
+ }
+ return nil
+ },
+ }
req, _ := NewRequest("GET", ts.URL, nil)
req = req.WithContext(ctx)
_, err := c.Do(req)
@@ -313,12 +332,96 @@ func TestClientRedirectContext(t *testing.T) {
if !ok {
t.Fatalf("got error %T; want *url.Error", err)
}
- if ue.Err != ExportErrRequestCanceled && ue.Err != ExportErrRequestCanceledConn {
- t.Errorf("url.Error.Err = %v; want errRequestCanceled or errRequestCanceledConn", ue.Err)
+ if ue.Err != context.Canceled {
+ t.Errorf("url.Error.Err = %v; want %v", ue.Err, context.Canceled)
}
}
+type redirectTest struct {
+ suffix string
+ want int // response code
+ redirectBody string
+}
+
func TestPostRedirects(t *testing.T) {
+ postRedirectTests := []redirectTest{
+ {"/", 200, "first"},
+ {"/?code=301&next=302", 200, "c301"},
+ {"/?code=302&next=302", 200, "c302"},
+ {"/?code=303&next=301", 200, "c303wc301"}, // Issue 9348
+ {"/?code=304", 304, "c304"},
+ {"/?code=305", 305, "c305"},
+ {"/?code=307&next=303,308,302", 200, "c307"},
+ {"/?code=308&next=302,301", 200, "c308"},
+ {"/?code=404", 404, "c404"},
+ }
+
+ wantSegments := []string{
+ `POST / "first"`,
+ `POST /?code=301&next=302 "c301"`,
+ `GET /?code=302 "c301"`,
+ `GET / "c301"`,
+ `POST /?code=302&next=302 "c302"`,
+ `GET /?code=302 "c302"`,
+ `GET / "c302"`,
+ `POST /?code=303&next=301 "c303wc301"`,
+ `GET /?code=301 "c303wc301"`,
+ `GET / "c303wc301"`,
+ `POST /?code=304 "c304"`,
+ `POST /?code=305 "c305"`,
+ `POST /?code=307&next=303,308,302 "c307"`,
+ `POST /?code=303&next=308,302 "c307"`,
+ `GET /?code=308&next=302 "c307"`,
+ `GET /?code=302 "c307"`,
+ `GET / "c307"`,
+ `POST /?code=308&next=302,301 "c308"`,
+ `POST /?code=302&next=301 "c308"`,
+ `GET /?code=301 "c308"`,
+ `GET / "c308"`,
+ `POST /?code=404 "c404"`,
+ }
+ want := strings.Join(wantSegments, "\n")
+ testRedirectsByMethod(t, "POST", postRedirectTests, want)
+}
+
+func TestDeleteRedirects(t *testing.T) {
+ deleteRedirectTests := []redirectTest{
+ {"/", 200, "first"},
+ {"/?code=301&next=302,308", 200, "c301"},
+ {"/?code=302&next=302", 200, "c302"},
+ {"/?code=303", 200, "c303"},
+ {"/?code=307&next=301,308,303,302,304", 304, "c307"},
+ {"/?code=308&next=307", 200, "c308"},
+ {"/?code=404", 404, "c404"},
+ }
+
+ wantSegments := []string{
+ `DELETE / "first"`,
+ `DELETE /?code=301&next=302,308 "c301"`,
+ `GET /?code=302&next=308 "c301"`,
+ `GET /?code=308 "c301"`,
+ `GET / "c301"`,
+ `DELETE /?code=302&next=302 "c302"`,
+ `GET /?code=302 "c302"`,
+ `GET / "c302"`,
+ `DELETE /?code=303 "c303"`,
+ `GET / "c303"`,
+ `DELETE /?code=307&next=301,308,303,302,304 "c307"`,
+ `DELETE /?code=301&next=308,303,302,304 "c307"`,
+ `GET /?code=308&next=303,302,304 "c307"`,
+ `GET /?code=303&next=302,304 "c307"`,
+ `GET /?code=302&next=304 "c307"`,
+ `GET /?code=304 "c307"`,
+ `DELETE /?code=308&next=307 "c308"`,
+ `DELETE /?code=307 "c308"`,
+ `DELETE / "c308"`,
+ `DELETE /?code=404 "c404"`,
+ }
+ want := strings.Join(wantSegments, "\n")
+ testRedirectsByMethod(t, "DELETE", deleteRedirectTests, want)
+}
+
+func testRedirectsByMethod(t *testing.T, method string, table []redirectTest, want string) {
defer afterTest(t)
var log struct {
sync.Mutex
@@ -327,29 +430,35 @@ func TestPostRedirects(t *testing.T) {
var ts *httptest.Server
ts = httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
log.Lock()
- fmt.Fprintf(&log.Buffer, "%s %s ", r.Method, r.RequestURI)
+ slurp, _ := ioutil.ReadAll(r.Body)
+ fmt.Fprintf(&log.Buffer, "%s %s %q\n", r.Method, r.RequestURI, slurp)
log.Unlock()
- if v := r.URL.Query().Get("code"); v != "" {
+ urlQuery := r.URL.Query()
+ if v := urlQuery.Get("code"); v != "" {
+ location := ts.URL
+ if final := urlQuery.Get("next"); final != "" {
+ splits := strings.Split(final, ",")
+ first, rest := splits[0], splits[1:]
+ location = fmt.Sprintf("%s?code=%s", location, first)
+ if len(rest) > 0 {
+ location = fmt.Sprintf("%s&next=%s", location, strings.Join(rest, ","))
+ }
+ }
code, _ := strconv.Atoi(v)
if code/100 == 3 {
- w.Header().Set("Location", ts.URL)
+ w.Header().Set("Location", location)
}
w.WriteHeader(code)
}
}))
defer ts.Close()
- tests := []struct {
- suffix string
- want int // response code
- }{
- {"/", 200},
- {"/?code=301", 301},
- {"/?code=302", 200},
- {"/?code=303", 200},
- {"/?code=404", 404},
- }
- for _, tt := range tests {
- res, err := Post(ts.URL+tt.suffix, "text/plain", strings.NewReader("Some content"))
+
+ 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)
+
if err != nil {
t.Fatal(err)
}
@@ -360,13 +469,17 @@ func TestPostRedirects(t *testing.T) {
log.Lock()
got := log.String()
log.Unlock()
- want := "POST / POST /?code=301 POST /?code=302 GET / POST /?code=303 GET / POST /?code=404 "
+
+ got = strings.TrimSpace(got)
+ want = strings.TrimSpace(want)
+
if got != want {
- t.Errorf("Log differs.\n Got: %q\nWant: %q", got, want)
+ t.Errorf("Log differs.\n Got:\n%s\nWant:\n%s\n", got, want)
}
}
func TestClientRedirectUseResponse(t *testing.T) {
+ setParallel(t)
defer afterTest(t)
const body = "Hello, world."
var ts *httptest.Server
@@ -381,12 +494,18 @@ func TestClientRedirectUseResponse(t *testing.T) {
}))
defer ts.Close()
- c := &Client{CheckRedirect: func(req *Request, via []*Request) error {
- if req.Response == nil {
- t.Error("expected non-nil Request.Response")
- }
- return ErrUseLastResponse
- }}
+ 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
+ },
+ }
res, err := c.Get(ts.URL)
if err != nil {
t.Fatal(err)
@@ -404,6 +523,57 @@ func TestClientRedirectUseResponse(t *testing.T) {
}
}
+// Issue 17773: don't follow a 308 (or 307) if the response doesn't
+// have a Location header.
+func TestClientRedirect308NoLocation(t *testing.T) {
+ setParallel(t)
+ defer afterTest(t)
+ ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ w.Header().Set("Foo", "Bar")
+ w.WriteHeader(308)
+ }))
+ defer ts.Close()
+ res, err := Get(ts.URL)
+ if err != nil {
+ t.Fatal(err)
+ }
+ res.Body.Close()
+ if res.StatusCode != 308 {
+ t.Errorf("status = %d; want %d", res.StatusCode, 308)
+ }
+ if got := res.Header.Get("Foo"); got != "Bar" {
+ t.Errorf("Foo header = %q; want Bar", got)
+ }
+}
+
+// Don't follow a 307/308 if we can't resent the request body.
+func TestClientRedirect308NoGetBody(t *testing.T) {
+ setParallel(t)
+ defer afterTest(t)
+ const fakeURL = "https://localhost:1234/" // won't be hit
+ ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ w.Header().Set("Location", fakeURL)
+ w.WriteHeader(308)
+ }))
+ defer ts.Close()
+ req, err := NewRequest("POST", ts.URL, strings.NewReader("some body"))
+ if err != nil {
+ t.Fatal(err)
+ }
+ req.GetBody = nil // so it can't rewind.
+ res, err := DefaultClient.Do(req)
+ if err != nil {
+ t.Fatal(err)
+ }
+ res.Body.Close()
+ if res.StatusCode != 308 {
+ t.Errorf("status = %d; want %d", res.StatusCode, 308)
+ }
+ if got := res.Header.Get("Location"); got != fakeURL {
+ t.Errorf("Location header = %q; want %q", got, fakeURL)
+ }
+}
+
var expectedCookies = []*Cookie{
{Name: "ChocolateChip", Value: "tasty"},
{Name: "First", Value: "Hit"},
@@ -476,12 +646,16 @@ func (j *TestJar) Cookies(u *url.URL) []*Cookie {
}
func TestRedirectCookiesJar(t *testing.T) {
+ setParallel(t)
defer afterTest(t)
var ts *httptest.Server
ts = httptest.NewServer(echoCookiesRedirectHandler)
defer ts.Close()
+ tr := &Transport{}
+ defer tr.CloseIdleConnections()
c := &Client{
- Jar: new(TestJar),
+ Transport: tr,
+ Jar: new(TestJar),
}
u, _ := url.Parse(ts.URL)
c.Jar.SetCookies(u, []*Cookie{expectedCookies[0]})
@@ -665,6 +839,7 @@ func TestClientWrites(t *testing.T) {
}
func TestClientInsecureTransport(t *testing.T) {
+ setParallel(t)
defer afterTest(t)
ts := httptest.NewTLSServer(HandlerFunc(func(w ResponseWriter, r *Request) {
w.Write([]byte("Hello"))
@@ -842,6 +1017,7 @@ func TestResponseSetsTLSConnectionState(t *testing.T) {
func TestHTTPSClientDetectsHTTPServer(t *testing.T) {
defer afterTest(t)
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {}))
+ ts.Config.ErrorLog = quietLog
defer ts.Close()
_, err := Get(strings.Replace(ts.URL, "http", "https", 1))
@@ -895,6 +1071,7 @@ func testClientHeadContentLength(t *testing.T, h2 bool) {
}
func TestEmptyPasswordAuth(t *testing.T) {
+ setParallel(t)
defer afterTest(t)
gopher := "gopher"
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
@@ -915,7 +1092,9 @@ func TestEmptyPasswordAuth(t *testing.T) {
}
}))
defer ts.Close()
- c := &Client{}
+ tr := &Transport{}
+ defer tr.CloseIdleConnections()
+ c := &Client{Transport: tr}
req, err := NewRequest("GET", ts.URL, nil)
if err != nil {
t.Fatal(err)
@@ -1007,10 +1186,10 @@ func TestClientTimeout_h1(t *testing.T) { testClientTimeout(t, h1Mode) }
func TestClientTimeout_h2(t *testing.T) { testClientTimeout(t, h2Mode) }
func testClientTimeout(t *testing.T, h2 bool) {
- if testing.Short() {
- t.Skip("skipping in short mode")
- }
+ setParallel(t)
defer afterTest(t)
+ testDone := make(chan struct{}) // closed in defer below
+
sawRoot := make(chan bool, 1)
sawSlow := make(chan bool, 1)
cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
@@ -1020,19 +1199,26 @@ func testClientTimeout(t *testing.T, h2 bool) {
return
}
if r.URL.Path == "/slow" {
+ sawSlow <- true
w.Write([]byte("Hello"))
w.(Flusher).Flush()
- sawSlow <- true
- time.Sleep(2 * time.Second)
+ <-testDone
return
}
}))
defer cst.close()
- const timeout = 500 * time.Millisecond
+ defer close(testDone) // before cst.close, to unblock /slow handler
+
+ // 200ms should be long enough to get a normal request (the /
+ // handler), but not so long that it makes the test slow.
+ const timeout = 200 * time.Millisecond
cst.c.Timeout = timeout
res, err := cst.c.Get(cst.ts.URL)
if err != nil {
+ if strings.Contains(err.Error(), "Client.Timeout") {
+ t.Skipf("host too slow to get fast resource in %v", timeout)
+ }
t.Fatal(err)
}
@@ -1057,7 +1243,7 @@ func testClientTimeout(t *testing.T, h2 bool) {
res.Body.Close()
}()
- const failTime = timeout * 2
+ const failTime = 5 * time.Second
select {
case err := <-errc:
if err == nil {
@@ -1082,11 +1268,9 @@ func TestClientTimeout_Headers_h2(t *testing.T) { testClientTimeout_Headers(t, h
// Client.Timeout firing before getting to the body
func testClientTimeout_Headers(t *testing.T, h2 bool) {
- if testing.Short() {
- t.Skip("skipping in short mode")
- }
+ setParallel(t)
defer afterTest(t)
- donec := make(chan bool)
+ donec := make(chan bool, 1)
cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
<-donec
}))
@@ -1100,9 +1284,10 @@ func testClientTimeout_Headers(t *testing.T, h2 bool) {
// doesn't know this, so synchronize explicitly.
defer func() { donec <- true }()
- cst.c.Timeout = 500 * time.Millisecond
- _, err := cst.c.Get(cst.ts.URL)
+ cst.c.Timeout = 5 * time.Millisecond
+ res, err := cst.c.Get(cst.ts.URL)
if err == nil {
+ res.Body.Close()
t.Fatal("got response from Get; expected error")
}
if _, ok := err.(*url.Error); !ok {
@@ -1120,9 +1305,40 @@ func testClientTimeout_Headers(t *testing.T, h2 bool) {
}
}
+// Issue 16094: if Client.Timeout is set but not hit, a Timeout error shouldn't be
+// returned.
+func TestClientTimeoutCancel(t *testing.T) {
+ setParallel(t)
+ defer afterTest(t)
+
+ testDone := make(chan struct{})
+ ctx, cancel := context.WithCancel(context.Background())
+
+ cst := newClientServerTest(t, h1Mode, HandlerFunc(func(w ResponseWriter, r *Request) {
+ w.(Flusher).Flush()
+ <-testDone
+ }))
+ defer cst.close()
+ defer close(testDone)
+
+ cst.c.Timeout = 1 * time.Hour
+ req, _ := NewRequest("GET", cst.ts.URL, nil)
+ req.Cancel = ctx.Done()
+ res, err := cst.c.Do(req)
+ if err != nil {
+ t.Fatal(err)
+ }
+ cancel()
+ _, err = io.Copy(ioutil.Discard, res.Body)
+ if err != ExportErrRequestCanceled {
+ t.Fatalf("error = %v; want errRequestCanceled", err)
+ }
+}
+
func TestClientRedirectEatsBody_h1(t *testing.T) { testClientRedirectEatsBody(t, h1Mode) }
func TestClientRedirectEatsBody_h2(t *testing.T) { testClientRedirectEatsBody(t, h2Mode) }
func testClientRedirectEatsBody(t *testing.T, h2 bool) {
+ setParallel(t)
defer afterTest(t)
saw := make(chan string, 2)
cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
@@ -1138,10 +1354,10 @@ func testClientRedirectEatsBody(t *testing.T, h2 bool) {
t.Fatal(err)
}
_, err = ioutil.ReadAll(res.Body)
+ res.Body.Close()
if err != nil {
t.Fatal(err)
}
- res.Body.Close()
var first string
select {
@@ -1229,3 +1445,296 @@ func TestClientRedirectResponseWithoutRequest(t *testing.T) {
// Check that this doesn't crash:
c.Get("http://dummy.tld")
}
+
+// Issue 4800: copy (some) headers when Client follows a redirect
+func TestClientCopyHeadersOnRedirect(t *testing.T) {
+ const (
+ ua = "some-agent/1.2"
+ xfoo = "foo-val"
+ )
+ var ts2URL string
+ ts1 := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ want := Header{
+ "User-Agent": []string{ua},
+ "X-Foo": []string{xfoo},
+ "Referer": []string{ts2URL},
+ "Accept-Encoding": []string{"gzip"},
+ }
+ if !reflect.DeepEqual(r.Header, want) {
+ t.Errorf("Request.Header = %#v; want %#v", r.Header, want)
+ }
+ if t.Failed() {
+ w.Header().Set("Result", "got errors")
+ } else {
+ w.Header().Set("Result", "ok")
+ }
+ }))
+ defer ts1.Close()
+ ts2 := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ Redirect(w, r, ts1.URL, StatusFound)
+ }))
+ 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
+ },
+ }
+
+ req, _ := NewRequest("GET", ts2.URL, nil)
+ req.Header.Add("User-Agent", ua)
+ req.Header.Add("X-Foo", xfoo)
+ req.Header.Add("Cookie", "foo=bar")
+ req.Header.Add("Authorization", "secretpassword")
+ res, err := c.Do(req)
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer res.Body.Close()
+ if res.StatusCode != 200 {
+ t.Fatal(res.Status)
+ }
+ if got := res.Header.Get("Result"); got != "ok" {
+ t.Errorf("result = %q; want ok", got)
+ }
+}
+
+// Issue 17494: cookies should be altered when Client follows redirects.
+func TestClientAltersCookiesOnRedirect(t *testing.T) {
+ cookieMap := func(cs []*Cookie) map[string][]string {
+ m := make(map[string][]string)
+ for _, c := range cs {
+ m[c.Name] = append(m[c.Name], c.Value)
+ }
+ return m
+ }
+
+ ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ var want map[string][]string
+ got := cookieMap(r.Cookies())
+
+ c, _ := r.Cookie("Cycle")
+ switch c.Value {
+ case "0":
+ want = map[string][]string{
+ "Cookie1": {"OldValue1a", "OldValue1b"},
+ "Cookie2": {"OldValue2"},
+ "Cookie3": {"OldValue3a", "OldValue3b"},
+ "Cookie4": {"OldValue4"},
+ "Cycle": {"0"},
+ }
+ SetCookie(w, &Cookie{Name: "Cycle", Value: "1", Path: "/"})
+ SetCookie(w, &Cookie{Name: "Cookie2", Path: "/", MaxAge: -1}) // Delete cookie from Header
+ Redirect(w, r, "/", StatusFound)
+ case "1":
+ want = map[string][]string{
+ "Cookie1": {"OldValue1a", "OldValue1b"},
+ "Cookie3": {"OldValue3a", "OldValue3b"},
+ "Cookie4": {"OldValue4"},
+ "Cycle": {"1"},
+ }
+ SetCookie(w, &Cookie{Name: "Cycle", Value: "2", Path: "/"})
+ SetCookie(w, &Cookie{Name: "Cookie3", Value: "NewValue3", Path: "/"}) // Modify cookie in Header
+ SetCookie(w, &Cookie{Name: "Cookie4", Value: "NewValue4", Path: "/"}) // Modify cookie in Jar
+ Redirect(w, r, "/", StatusFound)
+ case "2":
+ want = map[string][]string{
+ "Cookie1": {"OldValue1a", "OldValue1b"},
+ "Cookie3": {"NewValue3"},
+ "Cookie4": {"NewValue4"},
+ "Cycle": {"2"},
+ }
+ SetCookie(w, &Cookie{Name: "Cycle", Value: "3", Path: "/"})
+ SetCookie(w, &Cookie{Name: "Cookie5", Value: "NewValue5", Path: "/"}) // Insert cookie into Jar
+ Redirect(w, r, "/", StatusFound)
+ case "3":
+ want = map[string][]string{
+ "Cookie1": {"OldValue1a", "OldValue1b"},
+ "Cookie3": {"NewValue3"},
+ "Cookie4": {"NewValue4"},
+ "Cookie5": {"NewValue5"},
+ "Cycle": {"3"},
+ }
+ // Don't redirect to ensure the loop ends.
+ default:
+ t.Errorf("unexpected redirect cycle")
+ return
+ }
+
+ if !reflect.DeepEqual(got, want) {
+ t.Errorf("redirect %s, Cookie = %v, want %v", c.Value, got, want)
+ }
+ }))
+ defer ts.Close()
+
+ tr := &Transport{}
+ defer tr.CloseIdleConnections()
+ jar, _ := cookiejar.New(nil)
+ c := &Client{
+ Transport: tr,
+ Jar: jar,
+ }
+
+ u, _ := url.Parse(ts.URL)
+ req, _ := NewRequest("GET", ts.URL, nil)
+ req.AddCookie(&Cookie{Name: "Cookie1", Value: "OldValue1a"})
+ req.AddCookie(&Cookie{Name: "Cookie1", Value: "OldValue1b"})
+ req.AddCookie(&Cookie{Name: "Cookie2", Value: "OldValue2"})
+ req.AddCookie(&Cookie{Name: "Cookie3", Value: "OldValue3a"})
+ req.AddCookie(&Cookie{Name: "Cookie3", Value: "OldValue3b"})
+ jar.SetCookies(u, []*Cookie{{Name: "Cookie4", Value: "OldValue4", Path: "/"}})
+ jar.SetCookies(u, []*Cookie{{Name: "Cycle", Value: "0", Path: "/"}})
+ res, err := c.Do(req)
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer res.Body.Close()
+ if res.StatusCode != 200 {
+ t.Fatal(res.Status)
+ }
+}
+
+// Part of Issue 4800
+func TestShouldCopyHeaderOnRedirect(t *testing.T) {
+ tests := []struct {
+ header string
+ initialURL string
+ destURL string
+ want bool
+ }{
+ {"User-Agent", "http://foo.com/", "http://bar.com/", true},
+ {"X-Foo", "http://foo.com/", "http://bar.com/", true},
+
+ // Sensitive headers:
+ {"cookie", "http://foo.com/", "http://bar.com/", false},
+ {"cookie2", "http://foo.com/", "http://bar.com/", false},
+ {"authorization", "http://foo.com/", "http://bar.com/", false},
+ {"www-authenticate", "http://foo.com/", "http://bar.com/", false},
+
+ // But subdomains should work:
+ {"www-authenticate", "http://foo.com/", "http://foo.com/", true},
+ {"www-authenticate", "http://foo.com/", "http://sub.foo.com/", true},
+ {"www-authenticate", "http://foo.com/", "http://notfoo.com/", false},
+ // TODO(bradfitz): make this test work, once issue 16142 is fixed:
+ // {"www-authenticate", "http://foo.com:80/", "http://foo.com/", true},
+ }
+ for i, tt := range tests {
+ u0, err := url.Parse(tt.initialURL)
+ if err != nil {
+ t.Errorf("%d. initial URL %q parse error: %v", i, tt.initialURL, err)
+ continue
+ }
+ u1, err := url.Parse(tt.destURL)
+ if err != nil {
+ t.Errorf("%d. dest URL %q parse error: %v", i, tt.destURL, err)
+ continue
+ }
+ got := Export_shouldCopyHeaderOnRedirect(tt.header, u0, u1)
+ if got != tt.want {
+ t.Errorf("%d. shouldCopyHeaderOnRedirect(%q, %q => %q) = %v; want %v",
+ i, tt.header, tt.initialURL, tt.destURL, got, tt.want)
+ }
+ }
+}
+
+func TestClientRedirectTypes(t *testing.T) {
+ setParallel(t)
+ defer afterTest(t)
+
+ tests := [...]struct {
+ method string
+ serverStatus int
+ wantMethod string // desired subsequent client method
+ }{
+ 0: {method: "POST", serverStatus: 301, wantMethod: "GET"},
+ 1: {method: "POST", serverStatus: 302, wantMethod: "GET"},
+ 2: {method: "POST", serverStatus: 303, wantMethod: "GET"},
+ 3: {method: "POST", serverStatus: 307, wantMethod: "POST"},
+ 4: {method: "POST", serverStatus: 308, wantMethod: "POST"},
+
+ 5: {method: "HEAD", serverStatus: 301, wantMethod: "GET"},
+ 6: {method: "HEAD", serverStatus: 302, wantMethod: "GET"},
+ 7: {method: "HEAD", serverStatus: 303, wantMethod: "GET"},
+ 8: {method: "HEAD", serverStatus: 307, wantMethod: "HEAD"},
+ 9: {method: "HEAD", serverStatus: 308, wantMethod: "HEAD"},
+
+ 10: {method: "GET", serverStatus: 301, wantMethod: "GET"},
+ 11: {method: "GET", serverStatus: 302, wantMethod: "GET"},
+ 12: {method: "GET", serverStatus: 303, wantMethod: "GET"},
+ 13: {method: "GET", serverStatus: 307, wantMethod: "GET"},
+ 14: {method: "GET", serverStatus: 308, wantMethod: "GET"},
+
+ 15: {method: "DELETE", serverStatus: 301, wantMethod: "GET"},
+ 16: {method: "DELETE", serverStatus: 302, wantMethod: "GET"},
+ 17: {method: "DELETE", serverStatus: 303, wantMethod: "GET"},
+ 18: {method: "DELETE", serverStatus: 307, wantMethod: "DELETE"},
+ 19: {method: "DELETE", serverStatus: 308, wantMethod: "DELETE"},
+
+ 20: {method: "PUT", serverStatus: 301, wantMethod: "GET"},
+ 21: {method: "PUT", serverStatus: 302, wantMethod: "GET"},
+ 22: {method: "PUT", serverStatus: 303, wantMethod: "GET"},
+ 23: {method: "PUT", serverStatus: 307, wantMethod: "PUT"},
+ 24: {method: "PUT", serverStatus: 308, wantMethod: "PUT"},
+
+ 25: {method: "MADEUPMETHOD", serverStatus: 301, wantMethod: "GET"},
+ 26: {method: "MADEUPMETHOD", serverStatus: 302, wantMethod: "GET"},
+ 27: {method: "MADEUPMETHOD", serverStatus: 303, wantMethod: "GET"},
+ 28: {method: "MADEUPMETHOD", serverStatus: 307, wantMethod: "MADEUPMETHOD"},
+ 29: {method: "MADEUPMETHOD", serverStatus: 308, wantMethod: "MADEUPMETHOD"},
+ }
+
+ handlerc := make(chan HandlerFunc, 1)
+
+ ts := httptest.NewServer(HandlerFunc(func(rw ResponseWriter, req *Request) {
+ h := <-handlerc
+ h(rw, req)
+ }))
+ defer ts.Close()
+
+ tr := &Transport{}
+ defer tr.CloseIdleConnections()
+
+ for i, tt := range tests {
+ handlerc <- func(w ResponseWriter, r *Request) {
+ w.Header().Set("Location", ts.URL)
+ w.WriteHeader(tt.serverStatus)
+ }
+
+ req, err := NewRequest(tt.method, ts.URL, nil)
+ if err != nil {
+ t.Errorf("#%d: NewRequest: %v", i, err)
+ 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)
+ }
+ handlerc <- func(rw ResponseWriter, req *Request) {
+ // TODO: Check that the body is valid when we do 307 and 308 support
+ }
+ return nil
+ }
+
+ res, err := c.Do(req)
+ if err != nil {
+ t.Errorf("#%d: Response: %v", i, err)
+ continue
+ }
+
+ res.Body.Close()
+ }
+}
diff --git a/src/net/http/clientserver_test.go b/src/net/http/clientserver_test.go
index 8caba28..53556a1 100644
--- a/src/net/http/clientserver_test.go
+++ b/src/net/http/clientserver_test.go
@@ -44,6 +44,19 @@ func (t *clientServerTest) close() {
t.ts.Close()
}
+func (t *clientServerTest) getURL(u string) string {
+ res, err := t.c.Get(u)
+ if err != nil {
+ t.t.Fatal(err)
+ }
+ defer res.Body.Close()
+ slurp, err := ioutil.ReadAll(res.Body)
+ if err != nil {
+ t.t.Fatal(err)
+ }
+ return string(slurp)
+}
+
func (t *clientServerTest) scheme() string {
if t.h2 {
return "https"
@@ -56,6 +69,10 @@ const (
h2Mode = true
)
+var optQuietLog = func(ts *httptest.Server) {
+ ts.Config.ErrorLog = quietLog
+}
+
func newClientServerTest(t *testing.T, h2 bool, h Handler, opts ...interface{}) *clientServerTest {
cst := &clientServerTest{
t: t,
@@ -64,21 +81,23 @@ func newClientServerTest(t *testing.T, h2 bool, h Handler, opts ...interface{})
tr: &Transport{},
}
cst.c = &Client{Transport: cst.tr}
+ cst.ts = httptest.NewUnstartedServer(h)
for _, opt := range opts {
switch opt := opt.(type) {
case func(*Transport):
opt(cst.tr)
+ case func(*httptest.Server):
+ opt(cst.ts)
default:
t.Fatalf("unhandled option type %T", opt)
}
}
if !h2 {
- cst.ts = httptest.NewServer(h)
+ cst.ts.Start()
return cst
}
- cst.ts = httptest.NewUnstartedServer(h)
ExportHttp2ConfigureServer(cst.ts.Config, nil)
cst.ts.TLS = cst.ts.Config.TLSConfig
cst.ts.StartTLS()
@@ -170,6 +189,7 @@ func (tt h12Compare) reqFunc() reqFunc {
}
func (tt h12Compare) run(t *testing.T) {
+ setParallel(t)
cst1 := newClientServerTest(t, false, HandlerFunc(tt.Handler), tt.Opts...)
defer cst1.close()
cst2 := newClientServerTest(t, true, HandlerFunc(tt.Handler), tt.Opts...)
@@ -938,6 +958,7 @@ func testStarRequest(t *testing.T, method string, h2 bool) {
// Issue 13957
func TestTransportDiscardsUnneededConns(t *testing.T) {
+ setParallel(t)
defer afterTest(t)
cst := newClientServerTest(t, h2Mode, HandlerFunc(func(w ResponseWriter, r *Request) {
fmt.Fprintf(w, "Hello, %v", r.RemoteAddr)
@@ -1022,6 +1043,7 @@ func TestTransportGCRequest_Body_h2(t *testing.T) { testTransportGCRequest(t,
func TestTransportGCRequest_NoBody_h1(t *testing.T) { testTransportGCRequest(t, h1Mode, false) }
func TestTransportGCRequest_NoBody_h2(t *testing.T) { testTransportGCRequest(t, h2Mode, false) }
func testTransportGCRequest(t *testing.T, h2, body bool) {
+ setParallel(t)
defer afterTest(t)
cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
ioutil.ReadAll(r.Body)
@@ -1068,10 +1090,11 @@ func TestTransportRejectsInvalidHeaders_h2(t *testing.T) {
testTransportRejectsInvalidHeaders(t, h2Mode)
}
func testTransportRejectsInvalidHeaders(t *testing.T, h2 bool) {
+ setParallel(t)
defer afterTest(t)
cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
fmt.Fprintf(w, "Handler saw headers: %q", r.Header)
- }))
+ }), optQuietLog)
defer cst.close()
cst.tr.DisableKeepAlives = true
@@ -1139,24 +1162,44 @@ func testBogusStatusWorks(t *testing.T, h2 bool) {
}
}
-func TestInterruptWithPanic_h1(t *testing.T) { testInterruptWithPanic(t, h1Mode) }
-func TestInterruptWithPanic_h2(t *testing.T) { testInterruptWithPanic(t, h2Mode) }
-func testInterruptWithPanic(t *testing.T, h2 bool) {
- log.SetOutput(ioutil.Discard) // is noisy otherwise
- defer log.SetOutput(os.Stderr)
-
+func TestInterruptWithPanic_h1(t *testing.T) { testInterruptWithPanic(t, h1Mode, "boom") }
+func TestInterruptWithPanic_h2(t *testing.T) { testInterruptWithPanic(t, h2Mode, "boom") }
+func TestInterruptWithPanic_nil_h1(t *testing.T) { testInterruptWithPanic(t, h1Mode, nil) }
+func TestInterruptWithPanic_nil_h2(t *testing.T) { testInterruptWithPanic(t, h2Mode, nil) }
+func TestInterruptWithPanic_ErrAbortHandler_h1(t *testing.T) {
+ testInterruptWithPanic(t, h1Mode, ErrAbortHandler)
+}
+func TestInterruptWithPanic_ErrAbortHandler_h2(t *testing.T) {
+ testInterruptWithPanic(t, h2Mode, ErrAbortHandler)
+}
+func testInterruptWithPanic(t *testing.T, h2 bool, panicValue interface{}) {
+ setParallel(t)
const msg = "hello"
defer afterTest(t)
+
+ testDone := make(chan struct{})
+ defer close(testDone)
+
+ var errorLog lockedBytesBuffer
+ gotHeaders := make(chan bool, 1)
cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
io.WriteString(w, msg)
w.(Flusher).Flush()
- panic("no more")
- }))
+
+ select {
+ case <-gotHeaders:
+ case <-testDone:
+ }
+ panic(panicValue)
+ }), func(ts *httptest.Server) {
+ ts.Config.ErrorLog = log.New(&errorLog, "", 0)
+ })
defer cst.close()
res, err := cst.c.Get(cst.ts.URL)
if err != nil {
t.Fatal(err)
}
+ gotHeaders <- true
defer res.Body.Close()
slurp, err := ioutil.ReadAll(res.Body)
if string(slurp) != msg {
@@ -1165,6 +1208,42 @@ func testInterruptWithPanic(t *testing.T, h2 bool) {
if err == nil {
t.Errorf("client read all successfully; want some error")
}
+ logOutput := func() string {
+ errorLog.Lock()
+ defer errorLog.Unlock()
+ return errorLog.String()
+ }
+ wantStackLogged := panicValue != nil && panicValue != ErrAbortHandler
+
+ if err := waitErrCondition(5*time.Second, 10*time.Millisecond, func() error {
+ gotLog := logOutput()
+ if !wantStackLogged {
+ if gotLog == "" {
+ return nil
+ }
+ return fmt.Errorf("want no log output; got: %s", gotLog)
+ }
+ if gotLog == "" {
+ return fmt.Errorf("wanted a stack trace logged; got nothing")
+ }
+ if !strings.Contains(gotLog, "created by ") && strings.Count(gotLog, "\n") < 6 {
+ return fmt.Errorf("output doesn't look like a panic stack trace. Got: %s", gotLog)
+ }
+ return nil
+ }); err != nil {
+ t.Fatal(err)
+ }
+}
+
+type lockedBytesBuffer struct {
+ sync.Mutex
+ bytes.Buffer
+}
+
+func (b *lockedBytesBuffer) Write(p []byte) (int, error) {
+ b.Lock()
+ defer b.Unlock()
+ return b.Buffer.Write(p)
}
// Issue 15366
@@ -1200,6 +1279,7 @@ func TestH12_AutoGzipWithDumpResponse(t *testing.T) {
func TestCloseIdleConnections_h1(t *testing.T) { testCloseIdleConnections(t, h1Mode) }
func TestCloseIdleConnections_h2(t *testing.T) { testCloseIdleConnections(t, h2Mode) }
func testCloseIdleConnections(t *testing.T, h2 bool) {
+ setParallel(t)
defer afterTest(t)
cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
w.Header().Set("X-Addr", r.RemoteAddr)
@@ -1234,3 +1314,70 @@ func (x noteCloseConn) Close() error {
x.closeFunc()
return x.Conn.Close()
}
+
+type testErrorReader struct{ t *testing.T }
+
+func (r testErrorReader) Read(p []byte) (n int, err error) {
+ r.t.Error("unexpected Read call")
+ return 0, io.EOF
+}
+
+func TestNoSniffExpectRequestBody_h1(t *testing.T) { testNoSniffExpectRequestBody(t, h1Mode) }
+func TestNoSniffExpectRequestBody_h2(t *testing.T) { testNoSniffExpectRequestBody(t, h2Mode) }
+
+func testNoSniffExpectRequestBody(t *testing.T, h2 bool) {
+ defer afterTest(t)
+ cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
+ w.WriteHeader(StatusUnauthorized)
+ }))
+ defer cst.close()
+
+ // Set ExpectContinueTimeout non-zero so RoundTrip won't try to write it.
+ cst.tr.ExpectContinueTimeout = 10 * time.Second
+
+ req, err := NewRequest("POST", cst.ts.URL, testErrorReader{t})
+ if err != nil {
+ t.Fatal(err)
+ }
+ req.ContentLength = 0 // so transport is tempted to sniff it
+ req.Header.Set("Expect", "100-continue")
+ res, err := cst.tr.RoundTrip(req)
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer res.Body.Close()
+ if res.StatusCode != StatusUnauthorized {
+ t.Errorf("status code = %v; want %v", res.StatusCode, StatusUnauthorized)
+ }
+}
+
+func TestServerUndeclaredTrailers_h1(t *testing.T) { testServerUndeclaredTrailers(t, h1Mode) }
+func TestServerUndeclaredTrailers_h2(t *testing.T) { testServerUndeclaredTrailers(t, h2Mode) }
+func testServerUndeclaredTrailers(t *testing.T, h2 bool) {
+ defer afterTest(t)
+ cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
+ w.Header().Set("Foo", "Bar")
+ w.Header().Set("Trailer:Foo", "Baz")
+ w.(Flusher).Flush()
+ w.Header().Add("Trailer:Foo", "Baz2")
+ w.Header().Set("Trailer:Bar", "Quux")
+ }))
+ defer cst.close()
+ res, err := cst.c.Get(cst.ts.URL)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if _, err := io.Copy(ioutil.Discard, res.Body); err != nil {
+ t.Fatal(err)
+ }
+ res.Body.Close()
+ delete(res.Header, "Date")
+ delete(res.Header, "Content-Type")
+
+ if want := (Header{"Foo": {"Bar"}}); !reflect.DeepEqual(res.Header, want) {
+ t.Errorf("Header = %#v; want %#v", res.Header, want)
+ }
+ if want := (Header{"Foo": {"Baz", "Baz2"}, "Bar": {"Quux"}}); !reflect.DeepEqual(res.Trailer, want) {
+ t.Errorf("Trailer = %#v; want %#v", res.Trailer, want)
+ }
+}
diff --git a/src/net/http/cookie.go b/src/net/http/cookie.go
index 1ea0e93..5a67476 100644
--- a/src/net/http/cookie.go
+++ b/src/net/http/cookie.go
@@ -6,7 +6,6 @@ package http
import (
"bytes"
- "fmt"
"log"
"net"
"strconv"
@@ -40,7 +39,11 @@ type Cookie struct {
// readSetCookies parses all "Set-Cookie" values from
// the header h and returns the successfully parsed Cookies.
func readSetCookies(h Header) []*Cookie {
- cookies := []*Cookie{}
+ cookieCount := len(h["Set-Cookie"])
+ if cookieCount == 0 {
+ return []*Cookie{}
+ }
+ cookies := make([]*Cookie, 0, cookieCount)
for _, line := range h["Set-Cookie"] {
parts := strings.Split(strings.TrimSpace(line), ";")
if len(parts) == 1 && parts[0] == "" {
@@ -55,8 +58,8 @@ func readSetCookies(h Header) []*Cookie {
if !isCookieNameValid(name) {
continue
}
- value, success := parseCookieValue(value, true)
- if !success {
+ value, ok := parseCookieValue(value, true)
+ if !ok {
continue
}
c := &Cookie{
@@ -75,8 +78,8 @@ func readSetCookies(h Header) []*Cookie {
attr, val = attr[:j], attr[j+1:]
}
lowerAttr := strings.ToLower(attr)
- val, success = parseCookieValue(val, false)
- if !success {
+ val, ok = parseCookieValue(val, false)
+ if !ok {
c.Unparsed = append(c.Unparsed, parts[i])
continue
}
@@ -96,10 +99,9 @@ func readSetCookies(h Header) []*Cookie {
break
}
if secs <= 0 {
- c.MaxAge = -1
- } else {
- c.MaxAge = secs
+ secs = -1
}
+ c.MaxAge = secs
continue
case "expires":
c.RawExpires = val
@@ -142,9 +144,13 @@ func (c *Cookie) String() string {
return ""
}
var b bytes.Buffer
- fmt.Fprintf(&b, "%s=%s", sanitizeCookieName(c.Name), sanitizeCookieValue(c.Value))
+ b.WriteString(sanitizeCookieName(c.Name))
+ b.WriteRune('=')
+ b.WriteString(sanitizeCookieValue(c.Value))
+
if len(c.Path) > 0 {
- fmt.Fprintf(&b, "; Path=%s", sanitizeCookiePath(c.Path))
+ b.WriteString("; Path=")
+ b.WriteString(sanitizeCookiePath(c.Path))
}
if len(c.Domain) > 0 {
if validCookieDomain(c.Domain) {
@@ -156,25 +162,31 @@ func (c *Cookie) String() string {
if d[0] == '.' {
d = d[1:]
}
- fmt.Fprintf(&b, "; Domain=%s", d)
+ b.WriteString("; Domain=")
+ b.WriteString(d)
} else {
- log.Printf("net/http: invalid Cookie.Domain %q; dropping domain attribute",
- c.Domain)
+ log.Printf("net/http: invalid Cookie.Domain %q; dropping domain attribute", c.Domain)
}
}
- if c.Expires.Unix() > 0 {
- fmt.Fprintf(&b, "; Expires=%s", c.Expires.UTC().Format(TimeFormat))
+ if validCookieExpires(c.Expires) {
+ b.WriteString("; Expires=")
+ b2 := b.Bytes()
+ b.Reset()
+ b.Write(c.Expires.UTC().AppendFormat(b2, TimeFormat))
}
if c.MaxAge > 0 {
- fmt.Fprintf(&b, "; Max-Age=%d", c.MaxAge)
+ b.WriteString("; Max-Age=")
+ b2 := b.Bytes()
+ b.Reset()
+ b.Write(strconv.AppendInt(b2, int64(c.MaxAge), 10))
} else if c.MaxAge < 0 {
- fmt.Fprintf(&b, "; Max-Age=0")
+ b.WriteString("; Max-Age=0")
}
if c.HttpOnly {
- fmt.Fprintf(&b, "; HttpOnly")
+ b.WriteString("; HttpOnly")
}
if c.Secure {
- fmt.Fprintf(&b, "; Secure")
+ b.WriteString("; Secure")
}
return b.String()
}
@@ -184,12 +196,12 @@ func (c *Cookie) String() string {
//
// if filter isn't empty, only cookies of that name are returned
func readCookies(h Header, filter string) []*Cookie {
- cookies := []*Cookie{}
lines, ok := h["Cookie"]
if !ok {
- return cookies
+ return []*Cookie{}
}
+ cookies := []*Cookie{}
for _, line := range lines {
parts := strings.Split(strings.TrimSpace(line), ";")
if len(parts) == 1 && parts[0] == "" {
@@ -212,8 +224,8 @@ func readCookies(h Header, filter string) []*Cookie {
if filter != "" && filter != name {
continue
}
- val, success := parseCookieValue(val, true)
- if !success {
+ val, ok := parseCookieValue(val, true)
+ if !ok {
continue
}
cookies = append(cookies, &Cookie{Name: name, Value: val})
@@ -234,6 +246,12 @@ func validCookieDomain(v string) bool {
return false
}
+// validCookieExpires returns whether v is a valid cookie expires-value.
+func validCookieExpires(t time.Time) bool {
+ // IETF RFC 6265 Section 5.1.1.5, the year must not be less than 1601
+ return t.Year() >= 1601
+}
+
// isCookieDomainName returns whether s is a valid domain name or a valid
// domain name with a leading dot '.'. It is almost a direct copy of
// package net's isDomainName.
diff --git a/src/net/http/cookie_test.go b/src/net/http/cookie_test.go
index 95e6147..b3e54f8 100644
--- a/src/net/http/cookie_test.go
+++ b/src/net/http/cookie_test.go
@@ -56,6 +56,15 @@ var writeSetCookiesTests = []struct {
&Cookie{Name: "cookie-9", Value: "expiring", Expires: time.Unix(1257894000, 0)},
"cookie-9=expiring; Expires=Tue, 10 Nov 2009 23:00:00 GMT",
},
+ // According to IETF 6265 Section 5.1.1.5, the year cannot be less than 1601
+ {
+ &Cookie{Name: "cookie-10", Value: "expiring-1601", Expires: time.Date(1601, 1, 1, 1, 1, 1, 1, time.UTC)},
+ "cookie-10=expiring-1601; Expires=Mon, 01 Jan 1601 01:01:01 GMT",
+ },
+ {
+ &Cookie{Name: "cookie-11", Value: "invalid-expiry", Expires: time.Date(1600, 1, 1, 1, 1, 1, 1, time.UTC)},
+ "cookie-11=invalid-expiry",
+ },
// The "special" cookies have values containing commas or spaces which
// are disallowed by RFC 6265 but are common in the wild.
{
@@ -426,3 +435,92 @@ func TestCookieSanitizePath(t *testing.T) {
t.Errorf("Expected substring %q in log output. Got:\n%s", sub, got)
}
}
+
+func BenchmarkCookieString(b *testing.B) {
+ const wantCookieString = `cookie-9=i3e01nf61b6t23bvfmplnanol3; Path=/restricted/; Domain=example.com; Expires=Tue, 10 Nov 2009 23:00:00 GMT; Max-Age=3600`
+ c := &Cookie{
+ Name: "cookie-9",
+ Value: "i3e01nf61b6t23bvfmplnanol3",
+ Expires: time.Unix(1257894000, 0),
+ Path: "/restricted/",
+ Domain: ".example.com",
+ MaxAge: 3600,
+ }
+ var benchmarkCookieString string
+ b.ReportAllocs()
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ benchmarkCookieString = c.String()
+ }
+ if have, want := benchmarkCookieString, wantCookieString; have != want {
+ b.Fatalf("Have: %v Want: %v", have, want)
+ }
+}
+
+func BenchmarkReadSetCookies(b *testing.B) {
+ header := Header{
+ "Set-Cookie": {
+ "NID=99=YsDT5i3E-CXax-; expires=Wed, 23-Nov-2011 01:05:03 GMT; path=/; domain=.google.ch; HttpOnly",
+ ".ASPXAUTH=7E3AA; expires=Wed, 07-Mar-2012 14:25:06 GMT; path=/; HttpOnly",
+ },
+ }
+ wantCookies := []*Cookie{
+ {
+ Name: "NID",
+ Value: "99=YsDT5i3E-CXax-",
+ Path: "/",
+ Domain: ".google.ch",
+ HttpOnly: true,
+ Expires: time.Date(2011, 11, 23, 1, 5, 3, 0, time.UTC),
+ RawExpires: "Wed, 23-Nov-2011 01:05:03 GMT",
+ Raw: "NID=99=YsDT5i3E-CXax-; expires=Wed, 23-Nov-2011 01:05:03 GMT; path=/; domain=.google.ch; HttpOnly",
+ },
+ {
+ Name: ".ASPXAUTH",
+ Value: "7E3AA",
+ Path: "/",
+ Expires: time.Date(2012, 3, 7, 14, 25, 6, 0, time.UTC),
+ RawExpires: "Wed, 07-Mar-2012 14:25:06 GMT",
+ HttpOnly: true,
+ Raw: ".ASPXAUTH=7E3AA; expires=Wed, 07-Mar-2012 14:25:06 GMT; path=/; HttpOnly",
+ },
+ }
+ var c []*Cookie
+ b.ReportAllocs()
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ c = readSetCookies(header)
+ }
+ if !reflect.DeepEqual(c, wantCookies) {
+ b.Fatalf("readSetCookies:\nhave: %s\nwant: %s\n", toJSON(c), toJSON(wantCookies))
+ }
+}
+
+func BenchmarkReadCookies(b *testing.B) {
+ header := Header{
+ "Cookie": {
+ `de=; client_region=0; rpld1=0:hispeed.ch|20:che|21:zh|22:zurich|23:47.36|24:8.53|; rpld0=1:08|; backplane-channel=newspaper.com:1471; devicetype=0; osfam=0; rplmct=2; s_pers=%20s_vmonthnum%3D1472680800496%2526vn%253D1%7C1472680800496%3B%20s_nr%3D1471686767664-New%7C1474278767664%3B%20s_lv%3D1471686767669%7C1566294767669%3B%20s_lv_s%3DFirst%2520Visit%7C1471688567669%3B%20s_monthinvisit%3Dtrue%7C1471688567677%3B%20gvp_p5%3Dsports%253Ablog%253Aearly-lead%2520-%2520184693%2520-%252020160 [...]
+ },
+ }
+ wantCookies := []*Cookie{
+ {Name: "de", Value: ""},
+ {Name: "client_region", Value: "0"},
+ {Name: "rpld1", Value: "0:hispeed.ch|20:che|21:zh|22:zurich|23:47.36|24:8.53|"},
+ {Name: "rpld0", Value: "1:08|"},
+ {Name: "backplane-channel", Value: "newspaper.com:1471"},
+ {Name: "devicetype", Value: "0"},
+ {Name: "osfam", Value: "0"},
+ {Name: "rplmct", Value: "2"},
+ {Name: "s_pers", Value: "%20s_vmonthnum%3D1472680800496%2526vn%253D1%7C1472680800496%3B%20s_nr%3D1471686767664-New%7C1474278767664%3B%20s_lv%3D1471686767669%7C1566294767669%3B%20s_lv_s%3DFirst%2520Visit%7C1471688567669%3B%20s_monthinvisit%3Dtrue%7C1471688567677%3B%20gvp_p5%3Dsports%253Ablog%253Aearly-lead%2520-%2520184693%2520-%252020160820%2520-%2520u-s%7C1471688567681%3B%20gvp_p51%3Dwp%2520-%2520sports%7C1471688567684%3B"},
+ {Name: "s_sess", Value: "%20s_wp_ep%3Dhomepage%3B%20s._ref%3Dhttps%253A%252F%252Fwww.google.ch%252F%3B%20s_cc%3Dtrue%3B%20s_ppvl%3Dsports%25253Ablog%25253Aearly-lead%252520-%252520184693%252520-%25252020160820%252520-%252520u-lawyer%252C12%252C12%252C502%252C1231%252C502%252C1680%252C1050%252C2%252CP%3B%20s_ppv%3Dsports%25253Ablog%25253Aearly-lead%252520-%252520184693%252520-%25252020160820%252520-%252520u-s-lawyer%252C12%252C12%252C502%252C1231%252C502%252C1680%252C1050%252C2%252CP%3B [...]
+ }
+ var c []*Cookie
+ b.ReportAllocs()
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ c = readCookies(header, "")
+ }
+ if !reflect.DeepEqual(c, wantCookies) {
+ b.Fatalf("readCookies:\nhave: %s\nwant: %s\n", toJSON(c), toJSON(wantCookies))
+ }
+}
diff --git a/src/net/http/cookiejar/dummy_publicsuffix_test.go b/src/net/http/cookiejar/dummy_publicsuffix_test.go
new file mode 100644
index 0000000..9b31173
--- /dev/null
+++ b/src/net/http/cookiejar/dummy_publicsuffix_test.go
@@ -0,0 +1,21 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cookiejar_test
+
+import "net/http/cookiejar"
+
+type dummypsl struct {
+ List cookiejar.PublicSuffixList
+}
+
+func (dummypsl) PublicSuffix(domain string) string {
+ return domain
+}
+
+func (dummypsl) String() string {
+ return "dummy"
+}
+
+var publicsuffix = dummypsl{}
diff --git a/src/net/http/cookiejar/example_test.go b/src/net/http/cookiejar/example_test.go
new file mode 100644
index 0000000..91728ca
--- /dev/null
+++ b/src/net/http/cookiejar/example_test.go
@@ -0,0 +1,65 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cookiejar_test
+
+import (
+ "fmt"
+ "log"
+ "net/http"
+ "net/http/cookiejar"
+ "net/http/httptest"
+ "net/url"
+)
+
+func ExampleNew() {
+ // Start a server to give us cookies.
+ ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ if cookie, err := r.Cookie("Flavor"); err != nil {
+ http.SetCookie(w, &http.Cookie{Name: "Flavor", Value: "Chocolate Chip"})
+ } else {
+ cookie.Value = "Oatmeal Raisin"
+ http.SetCookie(w, cookie)
+ }
+ }))
+ defer ts.Close()
+
+ u, err := url.Parse(ts.URL)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ // All users of cookiejar should import "golang.org/x/net/publicsuffix"
+ jar, err := cookiejar.New(&cookiejar.Options{PublicSuffixList: publicsuffix.List})
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ client := &http.Client{
+ Jar: jar,
+ }
+
+ if _, err = client.Get(u.String()); err != nil {
+ log.Fatal(err)
+ }
+
+ fmt.Println("After 1st request:")
+ for _, cookie := range jar.Cookies(u) {
+ fmt.Printf(" %s: %s\n", cookie.Name, cookie.Value)
+ }
+
+ if _, err = client.Get(u.String()); err != nil {
+ log.Fatal(err)
+ }
+
+ fmt.Println("After 2nd request:")
+ for _, cookie := range jar.Cookies(u) {
+ fmt.Printf(" %s: %s\n", cookie.Name, cookie.Value)
+ }
+ // Output:
+ // After 1st request:
+ // Flavor: Chocolate Chip
+ // After 2nd request:
+ // Flavor: Oatmeal Raisin
+}
diff --git a/src/net/http/cookiejar/jar.go b/src/net/http/cookiejar/jar.go
index 0e0fac9..f89abbc 100644
--- a/src/net/http/cookiejar/jar.go
+++ b/src/net/http/cookiejar/jar.go
@@ -107,7 +107,7 @@ type entry struct {
seqNum uint64
}
-// Id returns the domain;path;name triple of e as an id.
+// id returns the domain;path;name triple of e as an id.
func (e *entry) id() string {
return fmt.Sprintf("%s;%s;%s", e.Domain, e.Path, e.Name)
}
@@ -147,24 +147,6 @@ func hasDotSuffix(s, suffix string) bool {
return len(s) > len(suffix) && s[len(s)-len(suffix)-1] == '.' && s[len(s)-len(suffix):] == suffix
}
-// byPathLength is a []entry sort.Interface that sorts according to RFC 6265
-// section 5.4 point 2: by longest path and then by earliest creation time.
-type byPathLength []entry
-
-func (s byPathLength) Len() int { return len(s) }
-
-func (s byPathLength) Less(i, j int) bool {
- if len(s[i].Path) != len(s[j].Path) {
- return len(s[i].Path) > len(s[j].Path)
- }
- if !s[i].Creation.Equal(s[j].Creation) {
- return s[i].Creation.Before(s[j].Creation)
- }
- return s[i].seqNum < s[j].seqNum
-}
-
-func (s byPathLength) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
-
// Cookies implements the Cookies method of the http.CookieJar interface.
//
// It returns an empty slice if the URL's scheme is not HTTP or HTTPS.
@@ -221,7 +203,18 @@ func (j *Jar) cookies(u *url.URL, now time.Time) (cookies []*http.Cookie) {
}
}
- sort.Sort(byPathLength(selected))
+ // sort according to RFC 6265 section 5.4 point 2: by longest
+ // path and then by earliest creation time.
+ sort.Slice(selected, func(i, j int) bool {
+ s := selected
+ if len(s[i].Path) != len(s[j].Path) {
+ return len(s[i].Path) > len(s[j].Path)
+ }
+ if !s[i].Creation.Equal(s[j].Creation) {
+ return s[i].Creation.Before(s[j].Creation)
+ }
+ return s[i].seqNum < s[j].seqNum
+ })
for _, e := range selected {
cookies = append(cookies, &http.Cookie{Name: e.Name, Value: e.Value})
}
diff --git a/src/net/http/doc.go b/src/net/http/doc.go
index 4ec8272..7855fea 100644
--- a/src/net/http/doc.go
+++ b/src/net/http/doc.go
@@ -44,7 +44,8 @@ For control over proxies, TLS configuration, keep-alives,
compression, and other settings, create a Transport:
tr := &http.Transport{
- TLSClientConfig: &tls.Config{RootCAs: pool},
+ MaxIdleConns: 10,
+ IdleConnTimeout: 30 * time.Second,
DisableCompression: true,
}
client := &http.Client{Transport: tr}
@@ -77,19 +78,30 @@ custom Server:
}
log.Fatal(s.ListenAndServe())
-The http package has transparent support for the HTTP/2 protocol when
-using HTTPS. Programs that must disable HTTP/2 can do so by setting
-Transport.TLSNextProto (for clients) or Server.TLSNextProto (for
-servers) to a non-nil, empty map. Alternatively, the following GODEBUG
-environment variables are currently supported:
+Starting with Go 1.6, the http package has transparent support for the
+HTTP/2 protocol when using HTTPS. Programs that must disable HTTP/2
+can do so by setting Transport.TLSNextProto (for clients) or
+Server.TLSNextProto (for servers) to a non-nil, empty
+map. Alternatively, the following GODEBUG environment variables are
+currently supported:
GODEBUG=http2client=0 # disable HTTP/2 client support
GODEBUG=http2server=0 # disable HTTP/2 server support
GODEBUG=http2debug=1 # enable verbose HTTP/2 debug logs
GODEBUG=http2debug=2 # ... even more verbose, with frame dumps
-The GODEBUG variables are not covered by Go's API compatibility promise.
-HTTP/2 support was added in Go 1.6. Please report any issues instead of
-disabling HTTP/2 support: https://golang.org/s/http2bug
+The GODEBUG variables are not covered by Go's API compatibility
+promise. Please report any issues before disabling HTTP/2
+support: https://golang.org/s/http2bug
+
+The http package's Transport and Server both automatically enable
+HTTP/2 support for simple configurations. To enable HTTP/2 for more
+complex configurations, to use lower-level HTTP/2 features, or to use
+a newer version of Go's http2 package, import "golang.org/x/net/http2"
+directly and use its ConfigureTransport and/or ConfigureServer
+functions. Manually configuring HTTP/2 via the golang.org/x/net/http2
+package takes precedence over the net/http package's built-in HTTP/2
+support.
+
*/
package http
diff --git a/src/net/http/export_test.go b/src/net/http/export_test.go
index 9c5ba08..b61f58b 100644
--- a/src/net/http/export_test.go
+++ b/src/net/http/export_test.go
@@ -24,6 +24,7 @@ var (
ExportErrRequestCanceled = errRequestCanceled
ExportErrRequestCanceledConn = errRequestCanceledConn
ExportServeFile = serveFile
+ ExportScanETag = scanETag
ExportHttp2ConfigureServer = http2ConfigureServer
)
@@ -87,6 +88,12 @@ func (t *Transport) IdleConnKeysForTesting() (keys []string) {
return
}
+func (t *Transport) IdleConnKeyCountForTesting() int {
+ t.idleMu.Lock()
+ defer t.idleMu.Unlock()
+ return len(t.idleConn)
+}
+
func (t *Transport) IdleConnStrsForTesting() []string {
var ret []string
t.idleMu.Lock()
@@ -100,6 +107,24 @@ func (t *Transport) IdleConnStrsForTesting() []string {
return ret
}
+func (t *Transport) IdleConnStrsForTesting_h2() []string {
+ var ret []string
+ noDialPool := t.h2transport.ConnPool.(http2noDialClientConnPool)
+ pool := noDialPool.http2clientConnPool
+
+ pool.mu.Lock()
+ defer pool.mu.Unlock()
+
+ for k, cc := range pool.conns {
+ for range cc {
+ ret = append(ret, k)
+ }
+ }
+
+ sort.Strings(ret)
+ return ret
+}
+
func (t *Transport) IdleConnCountForTesting(cacheKey string) int {
t.idleMu.Lock()
defer t.idleMu.Unlock()
@@ -160,3 +185,17 @@ func ExportHttp2ConfigureTransport(t *Transport) error {
t.h2transport = t2
return nil
}
+
+var Export_shouldCopyHeaderOnRedirect = shouldCopyHeaderOnRedirect
+
+func (s *Server) ExportAllConnsIdle() bool {
+ s.mu.Lock()
+ defer s.mu.Unlock()
+ for c := range s.activeConn {
+ st, ok := c.curState.Load().(ConnState)
+ if !ok || st != StateIdle {
+ return false
+ }
+ }
+ return true
+}
diff --git a/src/net/http/fcgi/fcgi.go b/src/net/http/fcgi/fcgi.go
index 3374841..5057d70 100644
--- a/src/net/http/fcgi/fcgi.go
+++ b/src/net/http/fcgi/fcgi.go
@@ -3,8 +3,12 @@
// license that can be found in the LICENSE file.
// Package fcgi implements the FastCGI protocol.
+//
+// The protocol is not an official standard and the original
+// documentation is no longer online. See the Internet Archive's
+// mirror at: https://web.archive.org/web/20150420080736/http://www.fastcgi.com/drupal/node/6?q=node/22
+//
// Currently only the responder role is supported.
-// The protocol is defined at http://www.fastcgi.com/drupal/node/6?q=node/22
package fcgi
// This file defines the raw protocol and some utilities used by the child and
diff --git a/src/net/http/fs.go b/src/net/http/fs.go
index c7a58a6..bf63bb5 100644
--- a/src/net/http/fs.go
+++ b/src/net/http/fs.go
@@ -77,7 +77,7 @@ func dirList(w ResponseWriter, f File) {
Error(w, "Error reading directory", StatusInternalServerError)
return
}
- sort.Sort(byName(dirs))
+ sort.Slice(dirs, func(i, j int) bool { return dirs[i].Name() < dirs[j].Name() })
w.Header().Set("Content-Type", "text/html; charset=utf-8")
fmt.Fprintf(w, "<pre>\n")
@@ -98,7 +98,8 @@ func dirList(w ResponseWriter, f File) {
// ServeContent replies to the request using the content in the
// provided ReadSeeker. The main benefit of ServeContent over io.Copy
// is that it handles Range requests properly, sets the MIME type, and
-// handles If-Modified-Since requests.
+// handles If-Match, If-Unmodified-Since, If-None-Match, If-Modified-Since,
+// and If-Range requests.
//
// If the response's Content-Type header is not set, ServeContent
// first tries to deduce the type from name's file extension and,
@@ -115,8 +116,8 @@ func dirList(w ResponseWriter, f File) {
// The content's Seek method must work: ServeContent uses
// a seek to the end of the content to determine its size.
//
-// If the caller has set w's ETag header, ServeContent uses it to
-// handle requests using If-Range and If-None-Match.
+// If the caller has set w's ETag header formatted per RFC 7232, section 2.3,
+// ServeContent uses it to handle requests using If-Match, If-None-Match, or If-Range.
//
// Note that *os.File implements the io.ReadSeeker interface.
func ServeContent(w ResponseWriter, req *Request, name string, modtime time.Time, content io.ReadSeeker) {
@@ -140,15 +141,17 @@ func ServeContent(w ResponseWriter, req *Request, name string, modtime time.Time
// users.
var errSeeker = errors.New("seeker can't seek")
+// errNoOverlap is returned by serveContent's parseRange if first-byte-pos of
+// all of the byte-range-spec values is greater than the content size.
+var errNoOverlap = errors.New("invalid range: failed to overlap")
+
// if name is empty, filename is unknown. (used for mime type, before sniffing)
// if modtime.IsZero(), modtime is unknown.
// content must be seeked to the beginning of the file.
// The sizeFunc is called at most once. Its error, if any, is sent in the HTTP response.
func serveContent(w ResponseWriter, r *Request, name string, modtime time.Time, sizeFunc func() (int64, error), content io.ReadSeeker) {
- if checkLastModified(w, r, modtime) {
- return
- }
- rangeReq, done := checkETag(w, r, modtime)
+ setLastModified(w, modtime)
+ done, rangeReq := checkPreconditions(w, r, modtime)
if done {
return
}
@@ -189,6 +192,9 @@ func serveContent(w ResponseWriter, r *Request, name string, modtime time.Time,
if size >= 0 {
ranges, err := parseRange(rangeReq, size)
if err != nil {
+ if err == errNoOverlap {
+ w.Header().Set("Content-Range", fmt.Sprintf("bytes */%d", size))
+ }
Error(w, err.Error(), StatusRequestedRangeNotSatisfiable)
return
}
@@ -263,90 +269,245 @@ func serveContent(w ResponseWriter, r *Request, name string, modtime time.Time,
}
}
-var unixEpochTime = time.Unix(0, 0)
-
-// modtime is the modification time of the resource to be served, or IsZero().
-// return value is whether this request is now complete.
-func checkLastModified(w ResponseWriter, r *Request, modtime time.Time) bool {
- if modtime.IsZero() || modtime.Equal(unixEpochTime) {
- // If the file doesn't have a modtime (IsZero), or the modtime
- // is obviously garbage (Unix time == 0), then ignore modtimes
- // and don't process the If-Modified-Since header.
- return false
+// scanETag determines if a syntactically valid ETag is present at s. If so,
+// the ETag and remaining text after consuming ETag is returned. Otherwise,
+// it returns "", "".
+func scanETag(s string) (etag string, remain string) {
+ s = textproto.TrimString(s)
+ start := 0
+ if strings.HasPrefix(s, "W/") {
+ start = 2
+ }
+ if len(s[start:]) < 2 || s[start] != '"' {
+ return "", ""
+ }
+ // ETag is either W/"text" or "text".
+ // See RFC 7232 2.3.
+ for i := start + 1; i < len(s); i++ {
+ c := s[i]
+ switch {
+ // Character values allowed in ETags.
+ case c == 0x21 || c >= 0x23 && c <= 0x7E || c >= 0x80:
+ case c == '"':
+ return string(s[:i+1]), s[i+1:]
+ default:
+ break
+ }
}
+ return "", ""
+}
- // The Date-Modified header truncates sub-second precision, so
- // use mtime < t+1s instead of mtime <= t to check for unmodified.
- if t, err := time.Parse(TimeFormat, r.Header.Get("If-Modified-Since")); err == nil && modtime.Before(t.Add(1*time.Second)) {
- h := w.Header()
- delete(h, "Content-Type")
- delete(h, "Content-Length")
- w.WriteHeader(StatusNotModified)
- return true
- }
- w.Header().Set("Last-Modified", modtime.UTC().Format(TimeFormat))
- return false
+// etagStrongMatch reports whether a and b match using strong ETag comparison.
+// Assumes a and b are valid ETags.
+func etagStrongMatch(a, b string) bool {
+ return a == b && a != "" && a[0] == '"'
}
-// checkETag implements If-None-Match and If-Range checks.
-//
-// The ETag or modtime must have been previously set in the
-// ResponseWriter's headers. The modtime is only compared at second
-// granularity and may be the zero value to mean unknown.
-//
-// The return value is the effective request "Range" header to use and
-// whether this request is now considered done.
-func checkETag(w ResponseWriter, r *Request, modtime time.Time) (rangeReq string, done bool) {
- etag := w.Header().get("Etag")
- rangeReq = r.Header.get("Range")
-
- // Invalidate the range request if the entity doesn't match the one
- // the client was expecting.
- // "If-Range: version" means "ignore the Range: header unless version matches the
- // current file."
- // We only support ETag versions.
- // The caller must have set the ETag on the response already.
- if ir := r.Header.get("If-Range"); ir != "" && ir != etag {
- // The If-Range value is typically the ETag value, but it may also be
- // the modtime date. See golang.org/issue/8367.
- timeMatches := false
- if !modtime.IsZero() {
- if t, err := ParseTime(ir); err == nil && t.Unix() == modtime.Unix() {
- timeMatches = true
- }
+// etagWeakMatch reports whether a and b match using weak ETag comparison.
+// Assumes a and b are valid ETags.
+func etagWeakMatch(a, b string) bool {
+ return strings.TrimPrefix(a, "W/") == strings.TrimPrefix(b, "W/")
+}
+
+// condResult is the result of an HTTP request precondition check.
+// See https://tools.ietf.org/html/rfc7232 section 3.
+type condResult int
+
+const (
+ condNone condResult = iota
+ condTrue
+ condFalse
+)
+
+func checkIfMatch(w ResponseWriter, r *Request) condResult {
+ im := r.Header.Get("If-Match")
+ if im == "" {
+ return condNone
+ }
+ for {
+ im = textproto.TrimString(im)
+ if len(im) == 0 {
+ break
+ }
+ if im[0] == ',' {
+ im = im[1:]
+ continue
+ }
+ if im[0] == '*' {
+ return condTrue
}
- if !timeMatches {
- rangeReq = ""
+ etag, remain := scanETag(im)
+ if etag == "" {
+ break
+ }
+ if etagStrongMatch(etag, w.Header().get("Etag")) {
+ return condTrue
}
+ im = remain
}
- if inm := r.Header.get("If-None-Match"); inm != "" {
- // Must know ETag.
+ return condFalse
+}
+
+func checkIfUnmodifiedSince(w ResponseWriter, r *Request, modtime time.Time) condResult {
+ ius := r.Header.Get("If-Unmodified-Since")
+ if ius == "" || isZeroTime(modtime) {
+ return condNone
+ }
+ if t, err := ParseTime(ius); err == nil {
+ // The Date-Modified header truncates sub-second precision, so
+ // use mtime < t+1s instead of mtime <= t to check for unmodified.
+ if modtime.Before(t.Add(1 * time.Second)) {
+ return condTrue
+ }
+ return condFalse
+ }
+ return condNone
+}
+
+func checkIfNoneMatch(w ResponseWriter, r *Request) condResult {
+ inm := r.Header.get("If-None-Match")
+ if inm == "" {
+ return condNone
+ }
+ buf := inm
+ for {
+ buf = textproto.TrimString(buf)
+ if len(buf) == 0 {
+ break
+ }
+ if buf[0] == ',' {
+ buf = buf[1:]
+ }
+ if buf[0] == '*' {
+ return condFalse
+ }
+ etag, remain := scanETag(buf)
if etag == "" {
- return rangeReq, false
+ break
+ }
+ if etagWeakMatch(etag, w.Header().get("Etag")) {
+ return condFalse
}
+ buf = remain
+ }
+ return condTrue
+}
+
+func checkIfModifiedSince(w ResponseWriter, r *Request, modtime time.Time) condResult {
+ if r.Method != "GET" && r.Method != "HEAD" {
+ return condNone
+ }
+ ims := r.Header.Get("If-Modified-Since")
+ if ims == "" || isZeroTime(modtime) {
+ return condNone
+ }
+ t, err := ParseTime(ims)
+ if err != nil {
+ return condNone
+ }
+ // The Date-Modified header truncates sub-second precision, so
+ // use mtime < t+1s instead of mtime <= t to check for unmodified.
+ if modtime.Before(t.Add(1 * time.Second)) {
+ return condFalse
+ }
+ return condTrue
+}
+
+func checkIfRange(w ResponseWriter, r *Request, modtime time.Time) condResult {
+ if r.Method != "GET" {
+ return condNone
+ }
+ ir := r.Header.get("If-Range")
+ if ir == "" {
+ return condNone
+ }
+ etag, _ := scanETag(ir)
+ if etag != "" {
+ if etagStrongMatch(etag, w.Header().Get("Etag")) {
+ return condTrue
+ } else {
+ return condFalse
+ }
+ }
+ // The If-Range value is typically the ETag value, but it may also be
+ // the modtime date. See golang.org/issue/8367.
+ if modtime.IsZero() {
+ return condFalse
+ }
+ t, err := ParseTime(ir)
+ if err != nil {
+ return condFalse
+ }
+ if t.Unix() == modtime.Unix() {
+ return condTrue
+ }
+ return condFalse
+}
+
+var unixEpochTime = time.Unix(0, 0)
+
+// isZeroTime reports whether t is obviously unspecified (either zero or Unix()=0).
+func isZeroTime(t time.Time) bool {
+ return t.IsZero() || t.Equal(unixEpochTime)
+}
+
+func setLastModified(w ResponseWriter, modtime time.Time) {
+ if !isZeroTime(modtime) {
+ w.Header().Set("Last-Modified", modtime.UTC().Format(TimeFormat))
+ }
+}
- // TODO(bradfitz): non-GET/HEAD requests require more work:
- // sending a different status code on matches, and
- // also can't use weak cache validators (those with a "W/
- // prefix). But most users of ServeContent will be using
- // it on GET or HEAD, so only support those for now.
- if r.Method != "GET" && r.Method != "HEAD" {
- return rangeReq, false
+func writeNotModified(w ResponseWriter) {
+ // RFC 7232 section 4.1:
+ // a sender SHOULD NOT generate representation metadata other than the
+ // above listed fields unless said metadata exists for the purpose of
+ // guiding cache updates (e.g., Last-Modified might be useful if the
+ // response does not have an ETag field).
+ h := w.Header()
+ delete(h, "Content-Type")
+ delete(h, "Content-Length")
+ if h.Get("Etag") != "" {
+ delete(h, "Last-Modified")
+ }
+ w.WriteHeader(StatusNotModified)
+}
+
+// checkPreconditions evaluates request preconditions and reports whether a precondition
+// resulted in sending StatusNotModified or StatusPreconditionFailed.
+func checkPreconditions(w ResponseWriter, r *Request, modtime time.Time) (done bool, rangeHeader string) {
+ // This function carefully follows RFC 7232 section 6.
+ ch := checkIfMatch(w, r)
+ if ch == condNone {
+ ch = checkIfUnmodifiedSince(w, r, modtime)
+ }
+ if ch == condFalse {
+ w.WriteHeader(StatusPreconditionFailed)
+ return true, ""
+ }
+ switch checkIfNoneMatch(w, r) {
+ case condFalse:
+ if r.Method == "GET" || r.Method == "HEAD" {
+ writeNotModified(w)
+ return true, ""
+ } else {
+ w.WriteHeader(StatusPreconditionFailed)
+ return true, ""
}
+ case condNone:
+ if checkIfModifiedSince(w, r, modtime) == condFalse {
+ writeNotModified(w)
+ return true, ""
+ }
+ }
- // TODO(bradfitz): deal with comma-separated or multiple-valued
- // list of If-None-match values. For now just handle the common
- // case of a single item.
- if inm == etag || inm == "*" {
- h := w.Header()
- delete(h, "Content-Type")
- delete(h, "Content-Length")
- w.WriteHeader(StatusNotModified)
- return "", true
+ rangeHeader = r.Header.get("Range")
+ if rangeHeader != "" {
+ if checkIfRange(w, r, modtime) == condFalse {
+ rangeHeader = ""
}
}
- return rangeReq, false
+ return false, rangeHeader
}
// name is '/'-separated, not filepath.Separator.
@@ -419,9 +580,11 @@ 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 checkLastModified(w, r, d.ModTime()) {
+ if checkIfModifiedSince(w, r, d.ModTime()) == condFalse {
+ writeNotModified(w)
return
}
+ w.Header().Set("Last-Modified", d.ModTime().UTC().Format(TimeFormat))
dirList(w, f)
return
}
@@ -543,6 +706,7 @@ func (r httpRange) mimeHeader(contentType string, size int64) textproto.MIMEHead
}
// parseRange parses a Range header string as per RFC 2616.
+// errNoOverlap is returned if none of the ranges overlap.
func parseRange(s string, size int64) ([]httpRange, error) {
if s == "" {
return nil, nil // header not present
@@ -552,6 +716,7 @@ func parseRange(s string, size int64) ([]httpRange, error) {
return nil, errors.New("invalid range")
}
var ranges []httpRange
+ noOverlap := false
for _, ra := range strings.Split(s[len(b):], ",") {
ra = strings.TrimSpace(ra)
if ra == "" {
@@ -577,9 +742,15 @@ func parseRange(s string, size int64) ([]httpRange, error) {
r.length = size - r.start
} else {
i, err := strconv.ParseInt(start, 10, 64)
- if err != nil || i >= size || i < 0 {
+ if err != nil || i < 0 {
return nil, errors.New("invalid range")
}
+ if i >= size {
+ // If the range begins after the size of the content,
+ // then it does not overlap.
+ noOverlap = true
+ continue
+ }
r.start = i
if end == "" {
// If no end is specified, range extends to end of the file.
@@ -597,6 +768,10 @@ func parseRange(s string, size int64) ([]httpRange, error) {
}
ranges = append(ranges, r)
}
+ if noOverlap && len(ranges) == 0 {
+ // The specified ranges did not overlap with the content.
+ return nil, errNoOverlap
+ }
return ranges, nil
}
@@ -628,9 +803,3 @@ func sumRangesSize(ranges []httpRange) (size int64) {
}
return
}
-
-type byName []os.FileInfo
-
-func (s byName) Len() int { return len(s) }
-func (s byName) Less(i, j int) bool { return s[i].Name() < s[j].Name() }
-func (s byName) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
diff --git a/src/net/http/fs_test.go b/src/net/http/fs_test.go
index c811891..17a0e4a 100644
--- a/src/net/http/fs_test.go
+++ b/src/net/http/fs_test.go
@@ -68,6 +68,7 @@ var ServeFileRangeTests = []struct {
}
func TestServeFile(t *testing.T) {
+ setParallel(t)
defer afterTest(t)
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
ServeFile(w, r, "testdata/file")
@@ -274,6 +275,7 @@ func TestFileServerEscapesNames(t *testing.T) {
{`"'<>&`, `<a href="%22%27%3C%3E&">"'<>&</a>`},
{`?foo=bar#baz`, `<a href="%3Ffoo=bar%23baz">?foo=bar#baz</a>`},
{`<combo>?foo`, `<a href="%3Ccombo%3E%3Ffoo"><combo>?foo</a>`},
+ {`foo:bar`, `<a href="./foo:bar">foo:bar</a>`},
}
// We put each test file in its own directory in the fakeFS so we can look at it in isolation.
@@ -765,6 +767,7 @@ func TestServeContent(t *testing.T) {
reqHeader map[string]string
wantLastMod string
wantContentType string
+ wantContentRange string
wantStatus int
}
htmlModTime := mustStat(t, "testdata/index.html").ModTime()
@@ -782,8 +785,9 @@ func TestServeContent(t *testing.T) {
wantStatus: 200,
},
"not_modified_modtime": {
- file: "testdata/style.css",
- modtime: htmlModTime,
+ file: "testdata/style.css",
+ serveETag: `"foo"`, // Last-Modified sent only when no ETag
+ modtime: htmlModTime,
reqHeader: map[string]string{
"If-Modified-Since": htmlModTime.UTC().Format(TimeFormat),
},
@@ -792,6 +796,7 @@ func TestServeContent(t *testing.T) {
"not_modified_modtime_with_contenttype": {
file: "testdata/style.css",
serveContentType: "text/css", // explicit content type
+ serveETag: `"foo"`, // Last-Modified sent only when no ETag
modtime: htmlModTime,
reqHeader: map[string]string{
"If-Modified-Since": htmlModTime.UTC().Format(TimeFormat),
@@ -808,21 +813,62 @@ func TestServeContent(t *testing.T) {
},
"not_modified_etag_no_seek": {
content: panicOnSeek{nil}, // should never be called
- serveETag: `"foo"`,
+ serveETag: `W/"foo"`, // If-None-Match uses weak ETag comparison
reqHeader: map[string]string{
- "If-None-Match": `"foo"`,
+ "If-None-Match": `"baz", W/"foo"`,
},
wantStatus: 304,
},
+ "if_none_match_mismatch": {
+ file: "testdata/style.css",
+ serveETag: `"foo"`,
+ reqHeader: map[string]string{
+ "If-None-Match": `"Foo"`,
+ },
+ wantStatus: 200,
+ wantContentType: "text/css; charset=utf-8",
+ },
"range_good": {
file: "testdata/style.css",
serveETag: `"A"`,
reqHeader: map[string]string{
"Range": "bytes=0-4",
},
- wantStatus: StatusPartialContent,
+ wantStatus: StatusPartialContent,
+ wantContentType: "text/css; charset=utf-8",
+ wantContentRange: "bytes 0-4/8",
+ },
+ "range_match": {
+ file: "testdata/style.css",
+ serveETag: `"A"`,
+ reqHeader: map[string]string{
+ "Range": "bytes=0-4",
+ "If-Range": `"A"`,
+ },
+ wantStatus: StatusPartialContent,
+ wantContentType: "text/css; charset=utf-8",
+ wantContentRange: "bytes 0-4/8",
+ },
+ "range_match_weak_etag": {
+ file: "testdata/style.css",
+ serveETag: `W/"A"`,
+ reqHeader: map[string]string{
+ "Range": "bytes=0-4",
+ "If-Range": `W/"A"`,
+ },
+ wantStatus: 200,
wantContentType: "text/css; charset=utf-8",
},
+ "range_no_overlap": {
+ file: "testdata/style.css",
+ serveETag: `"A"`,
+ reqHeader: map[string]string{
+ "Range": "bytes=10-20",
+ },
+ wantStatus: StatusRequestedRangeNotSatisfiable,
+ wantContentType: "text/plain; charset=utf-8",
+ wantContentRange: "bytes */8",
+ },
// An If-Range resource for entity "A", but entity "B" is now current.
// The Range request should be ignored.
"range_no_match": {
@@ -842,9 +888,10 @@ func TestServeContent(t *testing.T) {
"Range": "bytes=0-4",
"If-Range": "Wed, 25 Jun 2014 17:12:18 GMT",
},
- wantStatus: StatusPartialContent,
- wantContentType: "text/css; charset=utf-8",
- wantLastMod: "Wed, 25 Jun 2014 17:12:18 GMT",
+ wantStatus: StatusPartialContent,
+ wantContentType: "text/css; charset=utf-8",
+ wantContentRange: "bytes 0-4/8",
+ wantLastMod: "Wed, 25 Jun 2014 17:12:18 GMT",
},
"range_with_modtime_nanos": {
file: "testdata/style.css",
@@ -853,9 +900,10 @@ func TestServeContent(t *testing.T) {
"Range": "bytes=0-4",
"If-Range": "Wed, 25 Jun 2014 17:12:18 GMT",
},
- wantStatus: StatusPartialContent,
- wantContentType: "text/css; charset=utf-8",
- wantLastMod: "Wed, 25 Jun 2014 17:12:18 GMT",
+ wantStatus: StatusPartialContent,
+ wantContentType: "text/css; charset=utf-8",
+ wantContentRange: "bytes 0-4/8",
+ wantLastMod: "Wed, 25 Jun 2014 17:12:18 GMT",
},
"unix_zero_modtime": {
content: strings.NewReader("<html>foo"),
@@ -863,6 +911,62 @@ func TestServeContent(t *testing.T) {
wantStatus: StatusOK,
wantContentType: "text/html; charset=utf-8",
},
+ "ifmatch_matches": {
+ file: "testdata/style.css",
+ serveETag: `"A"`,
+ reqHeader: map[string]string{
+ "If-Match": `"Z", "A"`,
+ },
+ wantStatus: 200,
+ wantContentType: "text/css; charset=utf-8",
+ },
+ "ifmatch_star": {
+ file: "testdata/style.css",
+ serveETag: `"A"`,
+ reqHeader: map[string]string{
+ "If-Match": `*`,
+ },
+ wantStatus: 200,
+ wantContentType: "text/css; charset=utf-8",
+ },
+ "ifmatch_failed": {
+ file: "testdata/style.css",
+ serveETag: `"A"`,
+ reqHeader: map[string]string{
+ "If-Match": `"B"`,
+ },
+ wantStatus: 412,
+ wantContentType: "text/plain; charset=utf-8",
+ },
+ "ifmatch_fails_on_weak_etag": {
+ file: "testdata/style.css",
+ serveETag: `W/"A"`,
+ reqHeader: map[string]string{
+ "If-Match": `W/"A"`,
+ },
+ wantStatus: 412,
+ wantContentType: "text/plain; charset=utf-8",
+ },
+ "if_unmodified_since_true": {
+ file: "testdata/style.css",
+ modtime: htmlModTime,
+ reqHeader: map[string]string{
+ "If-Unmodified-Since": htmlModTime.UTC().Format(TimeFormat),
+ },
+ wantStatus: 200,
+ wantContentType: "text/css; charset=utf-8",
+ wantLastMod: htmlModTime.UTC().Format(TimeFormat),
+ },
+ "if_unmodified_since_false": {
+ file: "testdata/style.css",
+ modtime: htmlModTime,
+ reqHeader: map[string]string{
+ "If-Unmodified-Since": htmlModTime.Add(-2 * time.Second).UTC().Format(TimeFormat),
+ },
+ wantStatus: 412,
+ wantContentType: "text/plain; charset=utf-8",
+ wantLastMod: htmlModTime.UTC().Format(TimeFormat),
+ },
}
for testName, tt := range tests {
var content io.ReadSeeker
@@ -903,6 +1007,9 @@ func TestServeContent(t *testing.T) {
if g, e := res.Header.Get("Content-Type"), tt.wantContentType; g != e {
t.Errorf("test %q: content-type = %q, want %q", testName, g, e)
}
+ if g, e := res.Header.Get("Content-Range"), tt.wantContentRange; g != e {
+ t.Errorf("test %q: content-range = %q, want %q", testName, g, e)
+ }
if g, e := res.Header.Get("Last-Modified"), tt.wantLastMod; g != e {
t.Errorf("test %q: last-modified = %q, want %q", testName, g, e)
}
@@ -958,6 +1065,7 @@ func TestServeContentErrorMessages(t *testing.T) {
// verifies that sendfile is being used on Linux
func TestLinuxSendfile(t *testing.T) {
+ setParallel(t)
defer afterTest(t)
if runtime.GOOS != "linux" {
t.Skip("skipping; linux-only test")
@@ -978,10 +1086,12 @@ func TestLinuxSendfile(t *testing.T) {
syscalls := "sendfile,sendfile64"
switch runtime.GOARCH {
- case "mips64", "mips64le", "s390x":
+ case "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")
}
var buf bytes.Buffer
@@ -1008,10 +1118,9 @@ func TestLinuxSendfile(t *testing.T) {
Post(fmt.Sprintf("http://%s/quit", ln.Addr()), "", nil)
child.Wait()
- rx := regexp.MustCompile(`sendfile(64)?\(\d+,\s*\d+,\s*NULL,\s*\d+\)\s*=\s*\d+\s*\n`)
- rxResume := regexp.MustCompile(`<\.\.\. sendfile(64)? resumed> \)\s*=\s*\d+\s*\n`)
+ rx := regexp.MustCompile(`sendfile(64)?\(\d+,\s*\d+,\s*NULL,\s*\d+`)
out := buf.String()
- if !rx.MatchString(out) && !rxResume.MatchString(out) {
+ if !rx.MatchString(out) {
t.Errorf("no sendfile system call found in:\n%s", out)
}
}
@@ -1090,3 +1199,26 @@ func (d fileServerCleanPathDir) Open(path string) (File, error) {
}
type panicOnSeek struct{ io.ReadSeeker }
+
+func Test_scanETag(t *testing.T) {
+ tests := []struct {
+ in string
+ wantETag string
+ wantRemain string
+ }{
+ {`W/"etag-1"`, `W/"etag-1"`, ""},
+ {`"etag-2"`, `"etag-2"`, ""},
+ {`"etag-1", "etag-2"`, `"etag-1"`, `, "etag-2"`},
+ {"", "", ""},
+ {"", "", ""},
+ {"W/", "", ""},
+ {`W/"truc`, "", ""},
+ {`w/"case-sensitive"`, "", ""},
+ }
+ for _, test := range tests {
+ etag, remain := ExportScanETag(test.in)
+ if etag != test.wantETag || remain != test.wantRemain {
+ t.Errorf("scanETag(%q)=%q %q, want %q %q", test.in, etag, remain, test.wantETag, test.wantRemain)
+ }
+ }
+}
diff --git a/src/net/http/h2_bundle.go b/src/net/http/h2_bundle.go
index 063043a..bb7f05d 100644
--- a/src/net/http/h2_bundle.go
+++ b/src/net/http/h2_bundle.go
@@ -21,6 +21,7 @@ import (
"bytes"
"compress/gzip"
"context"
+ "crypto/rand"
"crypto/tls"
"encoding/binary"
"errors"
@@ -43,6 +44,7 @@ import (
"time"
"golang_org/x/net/http2/hpack"
+ "golang_org/x/net/idna"
"golang_org/x/net/lex/httplex"
)
@@ -1254,7 +1256,7 @@ func (f *http2Framer) WriteSettings(settings ...http2Setting) error {
return f.endWrite()
}
-// WriteSettings writes an empty SETTINGS frame with the ACK bit set.
+// WriteSettingsAck writes an empty SETTINGS frame with the ACK bit set.
//
// It will perform exactly one Write to the underlying Writer.
// It is the caller's responsibility to not call other Write methods concurrently.
@@ -2091,6 +2093,13 @@ type http2clientTrace httptrace.ClientTrace
func http2reqContext(r *Request) context.Context { return r.Context() }
+func (t *http2Transport) idleConnTimeout() time.Duration {
+ if t.t1 != nil {
+ return t.t1.IdleConnTimeout
+ }
+ return 0
+}
+
func http2setResponseUncompressed(res *Response) { res.Uncompressed = true }
func http2traceGotConn(req *Request, cc *http2ClientConn) {
@@ -2145,6 +2154,40 @@ func http2requestTrace(req *Request) *http2clientTrace {
return (*http2clientTrace)(trace)
}
+// Ping sends a PING frame to the server and waits for the ack.
+func (cc *http2ClientConn) Ping(ctx context.Context) error {
+ return cc.ping(ctx)
+}
+
+func http2cloneTLSConfig(c *tls.Config) *tls.Config { return c.Clone() }
+
+var _ Pusher = (*http2responseWriter)(nil)
+
+// Push implements http.Pusher.
+func (w *http2responseWriter) Push(target string, opts *PushOptions) error {
+ internalOpts := http2pushOptions{}
+ if opts != nil {
+ internalOpts.Method = opts.Method
+ internalOpts.Header = opts.Header
+ }
+ return w.push(target, internalOpts)
+}
+
+func http2configureServer18(h1 *Server, h2 *http2Server) error {
+ if h2.IdleTimeout == 0 {
+ if h1.IdleTimeout != 0 {
+ h2.IdleTimeout = h1.IdleTimeout
+ } else {
+ h2.IdleTimeout = h1.ReadTimeout
+ }
+ }
+ return nil
+}
+
+func http2shouldLogPanic(panicValue interface{}) bool {
+ return panicValue != nil && panicValue != ErrAbortHandler
+}
+
var http2DebugGoroutines = os.Getenv("DEBUG_HTTP2_GOROUTINES") == "1"
type http2goroutineLock uint64
@@ -2368,6 +2411,7 @@ var (
http2VerboseLogs bool
http2logFrameWrites bool
http2logFrameReads bool
+ http2inTests bool
)
func init() {
@@ -2409,13 +2453,23 @@ var (
type http2streamState int
+// HTTP/2 stream states.
+//
+// See http://tools.ietf.org/html/rfc7540#section-5.1.
+//
+// For simplicity, the server code merges "reserved (local)" into
+// "half-closed (remote)". This is one less state transition to track.
+// The only downside is that we send PUSH_PROMISEs slightly less
+// liberally than allowable. More discussion here:
+// https://lists.w3.org/Archives/Public/ietf-http-wg/2016JulSep/0599.html
+//
+// "reserved (remote)" is omitted since the client code does not
+// support server push.
const (
http2stateIdle http2streamState = iota
http2stateOpen
http2stateHalfClosedLocal
http2stateHalfClosedRemote
- http2stateResvLocal
- http2stateResvRemote
http2stateClosed
)
@@ -2424,8 +2478,6 @@ var http2stateName = [...]string{
http2stateOpen: "Open",
http2stateHalfClosedLocal: "HalfClosedLocal",
http2stateHalfClosedRemote: "HalfClosedRemote",
- http2stateResvLocal: "ResvLocal",
- http2stateResvRemote: "ResvRemote",
http2stateClosed: "Closed",
}
@@ -2586,13 +2638,27 @@ func http2newBufferedWriter(w io.Writer) *http2bufferedWriter {
return &http2bufferedWriter{w: w}
}
+// bufWriterPoolBufferSize is the size of bufio.Writer's
+// buffers created using bufWriterPool.
+//
+// TODO: pick a less arbitrary value? this is a bit under
+// (3 x typical 1500 byte MTU) at least. Other than that,
+// not much thought went into it.
+const http2bufWriterPoolBufferSize = 4 << 10
+
var http2bufWriterPool = sync.Pool{
New: func() interface{} {
-
- return bufio.NewWriterSize(nil, 4<<10)
+ return bufio.NewWriterSize(nil, http2bufWriterPoolBufferSize)
},
}
+func (w *http2bufferedWriter) Available() int {
+ if w.bw == nil {
+ return http2bufWriterPoolBufferSize
+ }
+ return w.bw.Available()
+}
+
func (w *http2bufferedWriter) Write(p []byte) (n int, err error) {
if w.bw == nil {
bw := http2bufWriterPool.Get().(*bufio.Writer)
@@ -2686,6 +2752,19 @@ func (s *http2sorter) SortStrings(ss []string) {
s.v = save
}
+// 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 "//",
+// *) 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
+func http2validPseudoPath(v string) bool {
+ return (len(v) > 0 && v[0] == '/' && (len(v) == 1 || v[1] != '/')) || v == "*"
+}
+
// 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)
@@ -2882,6 +2961,15 @@ type http2Server struct {
// PermitProhibitedCipherSuites, if true, permits the use of
// cipher suites prohibited by the HTTP/2 spec.
PermitProhibitedCipherSuites bool
+
+ // IdleTimeout specifies how long until idle clients should be
+ // closed with a GOAWAY frame. PING frames are not considered
+ // activity for the purposes of IdleTimeout.
+ IdleTimeout time.Duration
+
+ // NewWriteScheduler constructs a write scheduler for a connection.
+ // If nil, a default scheduler is chosen.
+ NewWriteScheduler func() http2WriteScheduler
}
func (s *http2Server) maxReadFrameSize() uint32 {
@@ -2904,9 +2992,15 @@ func (s *http2Server) maxConcurrentStreams() uint32 {
//
// ConfigureServer must be called before s begins serving.
func http2ConfigureServer(s *Server, conf *http2Server) error {
+ if s == nil {
+ panic("nil *http.Server")
+ }
if conf == nil {
conf = new(http2Server)
}
+ if err := http2configureServer18(s, conf); err != nil {
+ return err
+ }
if s.TLSConfig == nil {
s.TLSConfig = new(tls.Config)
@@ -2945,8 +3039,6 @@ func http2ConfigureServer(s *Server, conf *http2Server) error {
s.TLSConfig.NextProtos = append(s.TLSConfig.NextProtos, http2NextProtoTLS)
}
- s.TLSConfig.NextProtos = append(s.TLSConfig.NextProtos, "h2-14")
-
if s.TLSNextProto == nil {
s.TLSNextProto = map[string]func(*Server, *tls.Conn, Handler){}
}
@@ -2960,7 +3052,6 @@ func http2ConfigureServer(s *Server, conf *http2Server) error {
})
}
s.TLSNextProto[http2NextProtoTLS] = protoHandler
- s.TLSNextProto["h2-14"] = protoHandler
return nil
}
@@ -3014,29 +3105,35 @@ 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 http2frameWriteMsg, 8),
- wroteFrameCh: make(chan http2frameWriteResult, 1),
- bodyReadCh: make(chan http2bodyReadMsg),
- doneServing: make(chan struct{}),
- advMaxStreams: s.maxConcurrentStreams(),
- writeSched: http2writeScheduler{
- maxFrameSize: http2initialMaxFrameSize,
- },
+ 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,
}
+ if s.NewWriteScheduler != nil {
+ sc.writeSched = s.NewWriteScheduler()
+ } else {
+ sc.writeSched = http2NewRandomWriteScheduler()
+ }
+
sc.flow.add(http2initialWindowSize)
sc.inflow.add(http2initialWindowSize)
sc.hpackEncoder = hpack.NewEncoder(&sc.headerWriteBuf)
@@ -3090,16 +3187,18 @@ type http2serverConn struct {
handler Handler
baseCtx http2contextContext
framer *http2Framer
- doneServing chan struct{} // closed when serverConn.serve ends
- readFrameCh chan http2readFrameResult // written by serverConn.readFrames
- wantWriteFrameCh chan http2frameWriteMsg // 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
- 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
+ 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
+ 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
remoteAddrStr string
+ writeSched http2WriteScheduler
// Everything following is owned by the serve loop; use serveG.check():
serveG http2goroutineLock // used to verify funcs are on serve()
@@ -3109,22 +3208,27 @@ type http2serverConn struct {
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
- curOpenStreams uint32 // client's number of open streams
- maxStreamID uint32 // max ever seen
+ 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 write goroutine but haven't heard back on wroteFrameCh
+ 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
- writeSched http2writeScheduler
- inGoAway bool // we've started to or sent GOAWAY
- needToSendGoAway bool // we need to schedule a GOAWAY frame write
+ 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
- freeRequestBodyBuf []byte // if non-nil, a free initialWindowSize buffer for getRequestBodyBuf
+ idleTimer *time.Timer // nil if unused
+ idleTimerCh <-chan time.Time // nil if unused
// Owned by the writeFrameAsync goroutine:
headerWriteBuf bytes.Buffer
@@ -3168,11 +3272,11 @@ type http2stream struct {
numTrailerValues int64
weight uint8
state http2streamState
- sentReset bool // only true once detached from streams map
- gotReset bool // only true once detacted from streams map
- gotTrailerHeader bool // HEADER frame for trailers was seen
- wroteHeaders bool // whether we wrote headers (not status 100)
- reqBuf []byte
+ sentReset bool // only true once detached from streams map
+ gotReset bool // only true once detacted from streams map
+ gotTrailerHeader bool // HEADER frame for trailers was seen
+ wroteHeaders bool // whether we wrote headers (not status 100)
+ reqBuf []byte // if non-nil, body pipe buffer to return later at EOF
trailer Header // accumulated trailers
reqTrailer Header // handler's Request.Trailer
@@ -3195,8 +3299,14 @@ func (sc *http2serverConn) state(streamID uint32) (http2streamState, *http2strea
return st.state, st
}
- if streamID <= sc.maxStreamID {
- return http2stateClosed, nil
+ if streamID%2 == 1 {
+ if streamID <= sc.maxClientStreamID {
+ return http2stateClosed, nil
+ }
+ } else {
+ if streamID <= sc.maxPushPromiseID {
+ return http2stateClosed, nil
+ }
}
return http2stateIdle, nil
}
@@ -3328,17 +3438,17 @@ func (sc *http2serverConn) readFrames() {
// frameWriteResult is the message passed from writeFrameAsync to the serve goroutine.
type http2frameWriteResult struct {
- wm http2frameWriteMsg // what was written (or attempted)
- err error // result of the writeFrame call
+ wr http2FrameWriteRequest // what was written (or attempted)
+ err error // result of the writeFrame call
}
// writeFrameAsync runs in its own goroutine and writes a single frame
// and then reports when it's done.
// At most one goroutine can be running writeFrameAsync at a time per
// serverConn.
-func (sc *http2serverConn) writeFrameAsync(wm http2frameWriteMsg) {
- err := wm.write.writeFrame(sc)
- sc.wroteFrameCh <- http2frameWriteResult{wm, err}
+func (sc *http2serverConn) writeFrameAsync(wr http2FrameWriteRequest) {
+ err := wr.write.writeFrame(sc)
+ sc.wroteFrameCh <- http2frameWriteResult{wr, err}
}
func (sc *http2serverConn) closeAllStreamsOnConnClose() {
@@ -3382,7 +3492,7 @@ func (sc *http2serverConn) serve() {
sc.vlogf("http2: server connection from %v on %p", sc.conn.RemoteAddr(), sc.hs)
}
- sc.writeFrame(http2frameWriteMsg{
+ sc.writeFrame(http2FrameWriteRequest{
write: http2writeSettings{
{http2SettingMaxFrameSize, sc.srv.maxReadFrameSize()},
{http2SettingMaxConcurrentStreams, sc.advMaxStreams},
@@ -3399,6 +3509,17 @@ func (sc *http2serverConn) serve() {
sc.setConnState(StateActive)
sc.setConnState(StateIdle)
+ if sc.srv.IdleTimeout != 0 {
+ sc.idleTimer = time.NewTimer(sc.srv.IdleTimeout)
+ defer sc.idleTimer.Stop()
+ sc.idleTimerCh = sc.idleTimer.C
+ }
+
+ var gracefulShutdownCh <-chan struct{}
+ if sc.hs != nil {
+ gracefulShutdownCh = http2h1ServerShutdownChan(sc.hs)
+ }
+
go sc.readFrames()
settingsTimer := time.NewTimer(http2firstSettingsTimeout)
@@ -3406,8 +3527,10 @@ func (sc *http2serverConn) serve() {
for {
loopNum++
select {
- case wm := <-sc.wantWriteFrameCh:
- sc.writeFrame(wm)
+ case wr := <-sc.wantWriteFrameCh:
+ sc.writeFrame(wr)
+ case spr := <-sc.wantStartPushCh:
+ sc.startPush(spr)
case res := <-sc.wroteFrameCh:
sc.wroteFrame(res)
case res := <-sc.readFrameCh:
@@ -3424,12 +3547,22 @@ func (sc *http2serverConn) serve() {
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)
}
+
+ if sc.inGoAway && sc.curClientStreams == 0 && !sc.needToSendGoAway && !sc.writingFrame {
+ return
+ }
}
}
@@ -3477,7 +3610,7 @@ func (sc *http2serverConn) writeDataFromHandler(stream *http2stream, data []byte
ch := http2errChanPool.Get().(chan error)
writeArg := http2writeDataPool.Get().(*http2writeData)
*writeArg = http2writeData{stream.id, data, endStream}
- err := sc.writeFrameFromHandler(http2frameWriteMsg{
+ err := sc.writeFrameFromHandler(http2FrameWriteRequest{
write: writeArg,
stream: stream,
done: ch,
@@ -3507,17 +3640,17 @@ func (sc *http2serverConn) writeDataFromHandler(stream *http2stream, data []byte
return err
}
-// writeFrameFromHandler sends wm to sc.wantWriteFrameCh, but aborts
+// writeFrameFromHandler sends wr to sc.wantWriteFrameCh, but aborts
// if the connection has gone away.
//
// This must not be run from the serve goroutine itself, else it might
// deadlock writing to sc.wantWriteFrameCh (which is only mildly
// buffered and is read by serve itself). If you're on the serve
// goroutine, call writeFrame instead.
-func (sc *http2serverConn) writeFrameFromHandler(wm http2frameWriteMsg) error {
+func (sc *http2serverConn) writeFrameFromHandler(wr http2FrameWriteRequest) error {
sc.serveG.checkNotOn()
select {
- case sc.wantWriteFrameCh <- wm:
+ case sc.wantWriteFrameCh <- wr:
return nil
case <-sc.doneServing:
@@ -3533,36 +3666,36 @@ func (sc *http2serverConn) writeFrameFromHandler(wm http2frameWriteMsg) error {
// make it onto the wire
//
// If you're not on the serve goroutine, use writeFrameFromHandler instead.
-func (sc *http2serverConn) writeFrame(wm http2frameWriteMsg) {
+func (sc *http2serverConn) writeFrame(wr http2FrameWriteRequest) {
sc.serveG.check()
var ignoreWrite bool
- switch wm.write.(type) {
+ switch wr.write.(type) {
case *http2writeResHeaders:
- wm.stream.wroteHeaders = true
+ wr.stream.wroteHeaders = true
case http2write100ContinueHeadersFrame:
- if wm.stream.wroteHeaders {
+ if wr.stream.wroteHeaders {
ignoreWrite = true
}
}
if !ignoreWrite {
- sc.writeSched.add(wm)
+ sc.writeSched.Push(wr)
}
sc.scheduleFrameWrite()
}
-// startFrameWrite starts a goroutine to write wm (in a separate
+// startFrameWrite starts a goroutine to write wr (in a separate
// goroutine since that might block on the network), and updates the
-// serve goroutine's state about the world, updated from info in wm.
-func (sc *http2serverConn) startFrameWrite(wm http2frameWriteMsg) {
+// serve goroutine's state about the world, updated from info in wr.
+func (sc *http2serverConn) startFrameWrite(wr http2FrameWriteRequest) {
sc.serveG.check()
if sc.writingFrame {
panic("internal error: can only be writing one frame at a time")
}
- st := wm.stream
+ st := wr.stream
if st != nil {
switch st.state {
case http2stateHalfClosedLocal:
@@ -3573,13 +3706,31 @@ func (sc *http2serverConn) startFrameWrite(wm http2frameWriteMsg) {
sc.scheduleFrameWrite()
return
}
- panic(fmt.Sprintf("internal error: attempt to send a write %v on a closed stream", wm))
+ panic(fmt.Sprintf("internal error: attempt to send a write %v on a closed stream", wr))
+ }
+ }
+ if wpp, ok := wr.write.(*http2writePushPromise); ok {
+ var err error
+ wpp.promisedID, err = wpp.allocatePromisedID()
+ if err != nil {
+ sc.writingFrameAsync = false
+ if wr.done != nil {
+ wr.done <- err
+ }
+ return
}
}
sc.writingFrame = true
sc.needsFrameFlush = true
- go sc.writeFrameAsync(wm)
+ if wr.write.staysWithinBuffer(sc.bw.Available()) {
+ sc.writingFrameAsync = false
+ err := wr.write.writeFrame(sc)
+ sc.wroteFrame(http2frameWriteResult{wr, err})
+ } else {
+ sc.writingFrameAsync = true
+ go sc.writeFrameAsync(wr)
+ }
}
// errHandlerPanicked is the error given to any callers blocked in a read from
@@ -3595,24 +3746,25 @@ func (sc *http2serverConn) wroteFrame(res http2frameWriteResult) {
panic("internal error: expected to be already writing a frame")
}
sc.writingFrame = false
+ sc.writingFrameAsync = false
- wm := res.wm
- st := wm.stream
+ wr := res.wr
+ st := wr.stream
- closeStream := http2endsStream(wm.write)
+ closeStream := http2endsStream(wr.write)
- if _, ok := wm.write.(http2handlerPanicRST); ok {
+ if _, ok := wr.write.(http2handlerPanicRST); ok {
sc.closeStream(st, http2errHandlerPanicked)
}
- if ch := wm.done; ch != nil {
+ if ch := wr.done; ch != nil {
select {
case ch <- res.err:
default:
- panic(fmt.Sprintf("unbuffered done channel passed in for type %T", wm.write))
+ panic(fmt.Sprintf("unbuffered done channel passed in for type %T", wr.write))
}
}
- wm.write = nil
+ wr.write = nil
if closeStream {
if st == nil {
@@ -3646,47 +3798,68 @@ func (sc *http2serverConn) wroteFrame(res http2frameWriteResult) {
// flush the write buffer.
func (sc *http2serverConn) scheduleFrameWrite() {
sc.serveG.check()
- if sc.writingFrame {
- return
- }
- if sc.needToSendGoAway {
- sc.needToSendGoAway = false
- sc.startFrameWrite(http2frameWriteMsg{
- write: &http2writeGoAway{
- maxStreamID: sc.maxStreamID,
- code: sc.goAwayCode,
- },
- })
- return
- }
- if sc.needToSendSettingsAck {
- sc.needToSendSettingsAck = false
- sc.startFrameWrite(http2frameWriteMsg{write: http2writeSettingsAck{}})
+ if sc.writingFrame || sc.inFrameScheduleLoop {
return
}
- if !sc.inGoAway {
- if wm, ok := sc.writeSched.take(); ok {
- sc.startFrameWrite(wm)
- return
+ sc.inFrameScheduleLoop = true
+ for !sc.writingFrameAsync {
+ if sc.needToSendGoAway {
+ sc.needToSendGoAway = false
+ sc.startFrameWrite(http2FrameWriteRequest{
+ write: &http2writeGoAway{
+ maxStreamID: sc.maxClientStreamID,
+ code: sc.goAwayCode,
+ },
+ })
+ continue
}
+ if sc.needToSendSettingsAck {
+ sc.needToSendSettingsAck = false
+ sc.startFrameWrite(http2FrameWriteRequest{write: http2writeSettingsAck{}})
+ continue
+ }
+ if !sc.inGoAway || sc.goAwayCode == http2ErrCodeNo {
+ if wr, ok := sc.writeSched.Pop(); ok {
+ sc.startFrameWrite(wr)
+ continue
+ }
+ }
+ if sc.needsFrameFlush {
+ sc.startFrameWrite(http2FrameWriteRequest{write: http2flushFrameWriter{}})
+ sc.needsFrameFlush = false
+ continue
+ }
+ break
}
- if sc.needsFrameFlush {
- sc.startFrameWrite(http2frameWriteMsg{write: http2flushFrameWriter{}})
- sc.needsFrameFlush = false
- return
- }
+ 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.
+func (sc *http2serverConn) startGracefulShutdown() {
+ sc.goAwayIn(http2ErrCodeNo, 0)
}
func (sc *http2serverConn) goAway(code http2ErrCode) {
sc.serveG.check()
- if sc.inGoAway {
- return
- }
+ var forceCloseIn time.Duration
if code != http2ErrCodeNo {
- sc.shutDownIn(250 * time.Millisecond)
+ forceCloseIn = 250 * time.Millisecond
} else {
- sc.shutDownIn(1 * time.Second)
+ forceCloseIn = 1 * time.Second
+ }
+ sc.goAwayIn(code, forceCloseIn)
+}
+
+func (sc *http2serverConn) goAwayIn(code http2ErrCode, forceCloseIn time.Duration) {
+ sc.serveG.check()
+ if sc.inGoAway {
+ return
+ }
+ if forceCloseIn != 0 {
+ sc.shutDownIn(forceCloseIn)
}
sc.inGoAway = true
sc.needToSendGoAway = true
@@ -3702,7 +3875,7 @@ func (sc *http2serverConn) shutDownIn(d time.Duration) {
func (sc *http2serverConn) resetStream(se http2StreamError) {
sc.serveG.check()
- sc.writeFrame(http2frameWriteMsg{write: se})
+ sc.writeFrame(http2FrameWriteRequest{write: se})
if st, ok := sc.streams[se.StreamID]; ok {
st.sentReset = true
sc.closeStream(st, se)
@@ -3782,6 +3955,8 @@ func (sc *http2serverConn) processFrame(f http2Frame) error {
return sc.processResetStream(f)
case *http2PriorityFrame:
return sc.processPriority(f)
+ case *http2GoAwayFrame:
+ return sc.processGoAway(f)
case *http2PushPromiseFrame:
return http2ConnectionError(http2ErrCodeProtocol)
@@ -3801,7 +3976,10 @@ func (sc *http2serverConn) processPing(f *http2PingFrame) error {
return http2ConnectionError(http2ErrCodeProtocol)
}
- sc.writeFrame(http2frameWriteMsg{write: http2writePingAck{f}})
+ if sc.inGoAway && sc.goAwayCode != http2ErrCodeNo {
+ return nil
+ }
+ sc.writeFrame(http2FrameWriteRequest{write: http2writePingAck{f}})
return nil
}
@@ -3809,7 +3987,11 @@ func (sc *http2serverConn) processWindowUpdate(f *http2WindowUpdateFrame) error
sc.serveG.check()
switch {
case f.StreamID != 0:
- st := sc.streams[f.StreamID]
+ state, st := sc.state(f.StreamID)
+ if state == http2stateIdle {
+
+ return http2ConnectionError(http2ErrCodeProtocol)
+ }
if st == nil {
return nil
@@ -3848,11 +4030,21 @@ func (sc *http2serverConn) closeStream(st *http2stream, err error) {
panic(fmt.Sprintf("invariant; can't close stream in state %v", st.state))
}
st.state = http2stateClosed
- sc.curOpenStreams--
- if sc.curOpenStreams == 0 {
- sc.setConnState(StateIdle)
+ if st.isPushed() {
+ sc.curPushedStreams--
+ } else {
+ sc.curClientStreams--
}
delete(sc.streams, st.id)
+ if len(sc.streams) == 0 {
+ sc.setConnState(StateIdle)
+ if sc.srv.IdleTimeout != 0 {
+ sc.idleTimer.Reset(sc.srv.IdleTimeout)
+ }
+ if http2h1ServerKeepAlivesDisabled(sc.hs) {
+ sc.startGracefulShutdown()
+ }
+ }
if p := st.body; p != nil {
sc.sendWindowUpdate(nil, p.Len())
@@ -3860,11 +4052,7 @@ func (sc *http2serverConn) closeStream(st *http2stream, err error) {
p.CloseWithError(err)
}
st.cw.Close()
- sc.writeSched.forgetStream(st.id)
- if st.reqBuf != nil {
-
- sc.freeRequestBodyBuf = st.reqBuf
- }
+ sc.writeSched.CloseStream(st.id)
}
func (sc *http2serverConn) processSettings(f *http2SettingsFrame) error {
@@ -3904,7 +4092,7 @@ func (sc *http2serverConn) processSetting(s http2Setting) error {
case http2SettingInitialWindowSize:
return sc.processSettingInitialWindowSize(s.Val)
case http2SettingMaxFrameSize:
- sc.writeSched.maxFrameSize = s.Val
+ sc.maxFrameSize = int32(s.Val)
case http2SettingMaxHeaderListSize:
sc.peerMaxHeaderListSize = s.Val
default:
@@ -3933,11 +4121,18 @@ func (sc *http2serverConn) processSettingInitialWindowSize(val uint32) error {
func (sc *http2serverConn) processData(f *http2DataFrame) error {
sc.serveG.check()
+ if sc.inGoAway && sc.goAwayCode != http2ErrCodeNo {
+ return nil
+ }
data := f.Data()
id := f.Header().StreamID
- st, ok := sc.streams[id]
- if !ok || st.state != http2stateOpen || st.gotTrailerHeader {
+ state, st := sc.state(id)
+ if id == 0 || state == http2stateIdle {
+
+ return http2ConnectionError(http2ErrCodeProtocol)
+ }
+ if st == nil || state != http2stateOpen || st.gotTrailerHeader {
if sc.inflow.available() < int32(f.Length) {
return http2streamError(id, http2ErrCodeFlowControl)
@@ -3985,6 +4180,24 @@ func (sc *http2serverConn) processData(f *http2DataFrame) error {
return nil
}
+func (sc *http2serverConn) processGoAway(f *http2GoAwayFrame) error {
+ sc.serveG.check()
+ if f.ErrCode != http2ErrCodeNo {
+ sc.logf("http2: received GOAWAY %+v, starting graceful shutdown", f)
+ } else {
+ sc.vlogf("http2: received GOAWAY %+v, starting graceful shutdown", f)
+ }
+ sc.startGracefulShutdown()
+
+ sc.pushEnabled = false
+ return nil
+}
+
+// isPushed reports whether the stream is server-initiated.
+func (st *http2stream) isPushed() bool {
+ return st.id%2 == 0
+}
+
// endStream closes a Request.Body's pipe. It is called when a DATA
// frame says a request body is over (or after trailers).
func (st *http2stream) endStream() {
@@ -4014,7 +4227,7 @@ func (st *http2stream) copyTrailersToHandlerRequest() {
func (sc *http2serverConn) processHeaders(f *http2MetaHeadersFrame) error {
sc.serveG.check()
- id := f.Header().StreamID
+ id := f.StreamID
if sc.inGoAway {
return nil
@@ -4024,50 +4237,39 @@ func (sc *http2serverConn) processHeaders(f *http2MetaHeadersFrame) error {
return http2ConnectionError(http2ErrCodeProtocol)
}
- st := sc.streams[f.Header().StreamID]
- if st != nil {
+ if st := sc.streams[f.StreamID]; st != nil {
return st.processTrailerHeaders(f)
}
- if id <= sc.maxStreamID {
+ if id <= sc.maxClientStreamID {
return http2ConnectionError(http2ErrCodeProtocol)
}
- sc.maxStreamID = id
+ sc.maxClientStreamID = id
- ctx, cancelCtx := http2contextWithCancel(sc.baseCtx)
- st = &http2stream{
- sc: sc,
- id: id,
- state: http2stateOpen,
- ctx: ctx,
- cancelCtx: cancelCtx,
+ if sc.idleTimer != nil {
+ sc.idleTimer.Stop()
}
- if f.StreamEnded() {
- st.state = http2stateHalfClosedRemote
- }
- st.cw.Init()
- st.flow.conn = &sc.flow
- st.flow.add(sc.initialWindowSize)
- st.inflow.conn = &sc.inflow
- st.inflow.add(http2initialWindowSize)
+ if sc.curClientStreams+1 > sc.advMaxStreams {
+ if sc.unackedSettings == 0 {
- sc.streams[id] = st
- if f.HasPriority() {
- http2adjustStreamPriority(sc.streams, st.id, f.Priority)
- }
- sc.curOpenStreams++
- if sc.curOpenStreams == 1 {
- sc.setConnState(StateActive)
+ return http2streamError(id, http2ErrCodeProtocol)
+ }
+
+ return http2streamError(id, http2ErrCodeRefusedStream)
}
- if sc.curOpenStreams > sc.advMaxStreams {
- if sc.unackedSettings == 0 {
+ initialState := http2stateOpen
+ if f.StreamEnded() {
+ initialState = http2stateHalfClosedRemote
+ }
+ st := sc.newStream(id, 0, initialState)
- return http2streamError(st.id, http2ErrCodeProtocol)
+ if f.HasPriority() {
+ if err := http2checkPriority(f.StreamID, f.Priority); err != nil {
+ return err
}
-
- return http2streamError(st.id, http2ErrCodeRefusedStream)
+ sc.writeSched.AdjustStream(st.id, f.Priority)
}
rw, req, err := sc.newWriterAndRequest(st, f)
@@ -4085,10 +4287,14 @@ func (sc *http2serverConn) processHeaders(f *http2MetaHeadersFrame) error {
if f.Truncated {
handler = http2handleHeaderListTooLong
- } else if err := http2checkValidHTTP2Request(req); err != nil {
+ } else if err := http2checkValidHTTP2RequestHeaders(req.Header); err != nil {
handler = http2new400Handler(err)
}
+ if sc.hs.ReadTimeout != 0 {
+ sc.conn.SetReadDeadline(time.Time{})
+ }
+
go sc.runHandler(rw, req, handler)
return nil
}
@@ -4121,90 +4327,138 @@ func (st *http2stream) processTrailerHeaders(f *http2MetaHeadersFrame) error {
return nil
}
-func (sc *http2serverConn) processPriority(f *http2PriorityFrame) error {
- http2adjustStreamPriority(sc.streams, f.StreamID, f.http2PriorityParam)
+func http2checkPriority(streamID uint32, p http2PriorityParam) error {
+ if streamID == p.StreamDep {
+
+ return http2streamError(streamID, http2ErrCodeProtocol)
+ }
return nil
}
-func http2adjustStreamPriority(streams map[uint32]*http2stream, streamID uint32, priority http2PriorityParam) {
- st, ok := streams[streamID]
- if !ok {
+func (sc *http2serverConn) processPriority(f *http2PriorityFrame) error {
+ if sc.inGoAway {
+ return nil
+ }
+ if err := http2checkPriority(f.StreamID, f.http2PriorityParam); err != nil {
+ return err
+ }
+ sc.writeSched.AdjustStream(f.StreamID, f.http2PriorityParam)
+ return nil
+}
- return
+func (sc *http2serverConn) newStream(id, pusherID uint32, state http2streamState) *http2stream {
+ sc.serveG.check()
+ if id == 0 {
+ panic("internal error: cannot create stream with id 0")
}
- st.weight = priority.Weight
- parent := streams[priority.StreamDep]
- if parent == st {
- return
+ ctx, cancelCtx := http2contextWithCancel(sc.baseCtx)
+ st := &http2stream{
+ sc: sc,
+ id: id,
+ state: state,
+ ctx: ctx,
+ cancelCtx: cancelCtx,
}
+ st.cw.Init()
+ st.flow.conn = &sc.flow
+ st.flow.add(sc.initialWindowSize)
+ st.inflow.conn = &sc.inflow
+ st.inflow.add(http2initialWindowSize)
- for piter := parent; piter != nil; piter = piter.parent {
- if piter == st {
- parent.parent = st.parent
- break
- }
+ sc.streams[id] = st
+ sc.writeSched.OpenStream(st.id, http2OpenStreamOptions{PusherID: pusherID})
+ if st.isPushed() {
+ sc.curPushedStreams++
+ } else {
+ sc.curClientStreams++
}
- st.parent = parent
- if priority.Exclusive && (st.parent != nil || priority.StreamDep == 0) {
- for _, openStream := range streams {
- if openStream != st && openStream.parent == st.parent {
- openStream.parent = st
- }
- }
+ if sc.curClientStreams+sc.curPushedStreams == 1 {
+ sc.setConnState(StateActive)
}
+
+ return st
}
func (sc *http2serverConn) newWriterAndRequest(st *http2stream, f *http2MetaHeadersFrame) (*http2responseWriter, *Request, error) {
sc.serveG.check()
- method := f.PseudoValue("method")
- path := f.PseudoValue("path")
- scheme := f.PseudoValue("scheme")
- authority := f.PseudoValue("authority")
+ rp := http2requestParam{
+ method: f.PseudoValue("method"),
+ scheme: f.PseudoValue("scheme"),
+ authority: f.PseudoValue("authority"),
+ path: f.PseudoValue("path"),
+ }
- isConnect := method == "CONNECT"
+ isConnect := rp.method == "CONNECT"
if isConnect {
- if path != "" || scheme != "" || authority == "" {
+ if rp.path != "" || rp.scheme != "" || rp.authority == "" {
return nil, nil, http2streamError(f.StreamID, http2ErrCodeProtocol)
}
- } else if method == "" || path == "" ||
- (scheme != "https" && scheme != "http") {
+ } else if rp.method == "" || rp.path == "" || (rp.scheme != "https" && rp.scheme != "http") {
return nil, nil, http2streamError(f.StreamID, http2ErrCodeProtocol)
}
bodyOpen := !f.StreamEnded()
- if method == "HEAD" && bodyOpen {
+ if rp.method == "HEAD" && bodyOpen {
return nil, nil, http2streamError(f.StreamID, http2ErrCodeProtocol)
}
- var tlsState *tls.ConnectionState // nil if not scheme https
- if scheme == "https" {
- tlsState = sc.tlsState
+ rp.header = make(Header)
+ for _, hf := range f.RegularFields() {
+ rp.header.Add(sc.canonicalHeader(hf.Name), hf.Value)
+ }
+ if rp.authority == "" {
+ rp.authority = rp.header.Get("Host")
}
- header := make(Header)
- for _, hf := range f.RegularFields() {
- header.Add(sc.canonicalHeader(hf.Name), hf.Value)
+ rw, req, err := sc.newWriterAndRequestNoBody(st, rp)
+ if err != nil {
+ 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
+ }
}
+ return rw, req, nil
+}
+
+type http2requestParam struct {
+ method string
+ scheme, authority, path string
+ header Header
+}
+
+func (sc *http2serverConn) newWriterAndRequestNoBody(st *http2stream, rp http2requestParam) (*http2responseWriter, *Request, error) {
+ sc.serveG.check()
- if authority == "" {
- authority = header.Get("Host")
+ var tlsState *tls.ConnectionState // nil if not scheme https
+ if rp.scheme == "https" {
+ tlsState = sc.tlsState
}
- needsContinue := header.Get("Expect") == "100-continue"
+
+ needsContinue := rp.header.Get("Expect") == "100-continue"
if needsContinue {
- header.Del("Expect")
+ rp.header.Del("Expect")
}
- if cookies := header["Cookie"]; len(cookies) > 1 {
- header.Set("Cookie", strings.Join(cookies, "; "))
+ if cookies := rp.header["Cookie"]; len(cookies) > 1 {
+ rp.header.Set("Cookie", strings.Join(cookies, "; "))
}
// Setup Trailers
var trailer Header
- for _, v := range header["Trailer"] {
+ for _, v := range rp.header["Trailer"] {
for _, key := range strings.Split(v, ",") {
key = CanonicalHeaderKey(strings.TrimSpace(key))
switch key {
@@ -4218,55 +4472,42 @@ func (sc *http2serverConn) newWriterAndRequest(st *http2stream, f *http2MetaHead
}
}
}
- delete(header, "Trailer")
+ delete(rp.header, "Trailer")
- body := &http2requestBody{
- conn: sc,
- stream: st,
- needsContinue: needsContinue,
- }
var url_ *url.URL
var requestURI string
- if isConnect {
- url_ = &url.URL{Host: authority}
- requestURI = authority
+ if rp.method == "CONNECT" {
+ url_ = &url.URL{Host: rp.authority}
+ requestURI = rp.authority
} else {
var err error
- url_, err = url.ParseRequestURI(path)
+ url_, err = url.ParseRequestURI(rp.path)
if err != nil {
- return nil, nil, http2streamError(f.StreamID, http2ErrCodeProtocol)
+ return nil, nil, http2streamError(st.id, http2ErrCodeProtocol)
}
- requestURI = path
+ requestURI = rp.path
+ }
+
+ body := &http2requestBody{
+ conn: sc,
+ stream: st,
+ needsContinue: needsContinue,
}
req := &Request{
- Method: method,
+ Method: rp.method,
URL: url_,
RemoteAddr: sc.remoteAddrStr,
- Header: header,
+ Header: rp.header,
RequestURI: requestURI,
Proto: "HTTP/2.0",
ProtoMajor: 2,
ProtoMinor: 0,
TLS: tlsState,
- Host: authority,
+ Host: rp.authority,
Body: body,
Trailer: trailer,
}
req = http2requestWithContext(req, st.ctx)
- if bodyOpen {
-
- buf := make([]byte, http2initialWindowSize)
-
- body.pipe = &http2pipe{
- b: &http2fixedBuffer{buf: buf},
- }
-
- if vv, ok := header["Content-Length"]; ok {
- req.ContentLength, _ = strconv.ParseInt(vv[0], 10, 64)
- } else {
- req.ContentLength = -1
- }
- }
rws := http2responseWriterStatePool.Get().(*http2responseWriterState)
bwSave := rws.bw
@@ -4282,13 +4523,22 @@ func (sc *http2serverConn) newWriterAndRequest(st *http2stream, f *http2MetaHead
return rw, req, nil
}
-func (sc *http2serverConn) getRequestBodyBuf() []byte {
- sc.serveG.check()
- if buf := sc.freeRequestBodyBuf; buf != nil {
- sc.freeRequestBodyBuf = nil
- return buf
+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:
}
- return make([]byte, http2initialWindowSize)
}
// Run on its own goroutine.
@@ -4298,15 +4548,17 @@ func (sc *http2serverConn) runHandler(rw *http2responseWriter, req *Request, han
rw.rws.stream.cancelCtx()
if didPanic {
e := recover()
- // Same as net/http:
- const size = 64 << 10
- buf := make([]byte, size)
- buf = buf[:runtime.Stack(buf, false)]
- sc.writeFrameFromHandler(http2frameWriteMsg{
+ sc.writeFrameFromHandler(http2FrameWriteRequest{
write: http2handlerPanicRST{rw.rws.stream.id},
stream: rw.rws.stream,
})
- sc.logf("http2: panic serving %v: %v\n%s", sc.conn.RemoteAddr(), e, buf)
+
+ if http2shouldLogPanic(e) {
+ const size = 64 << 10
+ buf := make([]byte, size)
+ buf = buf[:runtime.Stack(buf, false)]
+ sc.logf("http2: panic serving %v: %v\n%s", sc.conn.RemoteAddr(), e, buf)
+ }
return
}
rw.handlerDone()
@@ -4334,7 +4586,7 @@ func (sc *http2serverConn) writeHeaders(st *http2stream, headerData *http2writeR
errc = http2errChanPool.Get().(chan error)
}
- if err := sc.writeFrameFromHandler(http2frameWriteMsg{
+ if err := sc.writeFrameFromHandler(http2FrameWriteRequest{
write: headerData,
stream: st,
done: errc,
@@ -4357,7 +4609,7 @@ func (sc *http2serverConn) writeHeaders(st *http2stream, headerData *http2writeR
// called from handler goroutines.
func (sc *http2serverConn) write100ContinueHeaders(st *http2stream) {
- sc.writeFrameFromHandler(http2frameWriteMsg{
+ sc.writeFrameFromHandler(http2FrameWriteRequest{
write: http2write100ContinueHeadersFrame{st.id},
stream: st,
})
@@ -4373,11 +4625,19 @@ type http2bodyReadMsg struct {
// called from handler goroutines.
// 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) {
+func (sc *http2serverConn) noteBodyReadFromHandler(st *http2stream, n int, err error) {
sc.serveG.checkNotOn()
- select {
- case sc.bodyReadCh <- http2bodyReadMsg{st, n}:
- case <-sc.doneServing:
+ 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)
+ }
}
}
@@ -4419,7 +4679,7 @@ func (sc *http2serverConn) sendWindowUpdate32(st *http2stream, n int32) {
if st != nil {
streamID = st.id
}
- sc.writeFrame(http2frameWriteMsg{
+ sc.writeFrame(http2FrameWriteRequest{
write: http2writeWindowUpdate{streamID: streamID, n: uint32(n)},
stream: st,
})
@@ -4434,16 +4694,19 @@ func (sc *http2serverConn) sendWindowUpdate32(st *http2stream, n int32) {
}
}
+// requestBody is the Handler's Request.Body type.
+// Read and Close may be called concurrently.
type http2requestBody struct {
stream *http2stream
conn *http2serverConn
- closed bool
+ closed bool // for use by Close only
+ sawEOF bool // for use by Read only
pipe *http2pipe // non-nil if we have a HTTP entity message body
needsContinue bool // need to send a 100-continue
}
func (b *http2requestBody) Close() error {
- if b.pipe != nil {
+ if b.pipe != nil && !b.closed {
b.pipe.BreakWithError(http2errClosedBody)
}
b.closed = true
@@ -4455,13 +4718,17 @@ func (b *http2requestBody) Read(p []byte) (n int, err error) {
b.needsContinue = false
b.conn.write100ContinueHeaders(b.stream)
}
- if b.pipe == nil {
+ if b.pipe == nil || b.sawEOF {
return 0, io.EOF
}
n, err = b.pipe.Read(p)
- if n > 0 {
- b.conn.noteBodyReadFromHandler(b.stream, n)
+ if err == io.EOF {
+ b.sawEOF = true
+ }
+ if b.conn == nil && http2inTests {
+ return
}
+ b.conn.noteBodyReadFromHandler(b.stream, n, err)
return
}
@@ -4696,8 +4963,9 @@ func (w *http2responseWriter) CloseNotify() <-chan bool {
if ch == nil {
ch = make(chan bool, 1)
rws.closeNotifierCh = ch
+ cw := rws.stream.cw
go func() {
- rws.stream.cw.Wait()
+ cw.Wait()
ch <- true
}()
}
@@ -4793,6 +5061,172 @@ func (w *http2responseWriter) handlerDone() {
http2responseWriterStatePool.Put(rws)
}
+// Push errors.
+var (
+ http2ErrRecursivePush = errors.New("http2: recursive push not allowed")
+ http2ErrPushLimitReached = errors.New("http2: push would exceed peer's SETTINGS_MAX_CONCURRENT_STREAMS")
+)
+
+// pushOptions is the internal version of http.PushOptions, which we
+// cannot include here because it's only defined in Go 1.8 and later.
+type http2pushOptions struct {
+ Method string
+ Header Header
+}
+
+func (w *http2responseWriter) push(target string, opts http2pushOptions) error {
+ st := w.rws.stream
+ sc := st.sc
+ sc.serveG.checkNotOn()
+
+ if st.isPushed() {
+ return http2ErrRecursivePush
+ }
+
+ if opts.Method == "" {
+ opts.Method = "GET"
+ }
+ if opts.Header == nil {
+ opts.Header = Header{}
+ }
+ wantScheme := "http"
+ if w.rws.req.TLS != nil {
+ wantScheme = "https"
+ }
+
+ u, err := url.Parse(target)
+ if err != nil {
+ return err
+ }
+ if u.Scheme == "" {
+ if !strings.HasPrefix(target, "/") {
+ return fmt.Errorf("target must be an absolute URL or an absolute path: %q", target)
+ }
+ u.Scheme = wantScheme
+ u.Host = w.rws.req.Host
+ } else {
+ if u.Scheme != wantScheme {
+ return fmt.Errorf("cannot push URL with scheme %q from request with scheme %q", u.Scheme, wantScheme)
+ }
+ if u.Host == "" {
+ return errors.New("URL must have a host")
+ }
+ }
+ for k := range opts.Header {
+ if strings.HasPrefix(k, ":") {
+ return fmt.Errorf("promised request headers cannot include psuedo header %q", k)
+ }
+
+ switch strings.ToLower(k) {
+ case "content-length", "content-encoding", "trailer", "te", "expect", "host":
+ return fmt.Errorf("promised request headers cannot include %q", k)
+ }
+ }
+ if err := http2checkValidHTTP2RequestHeaders(opts.Header); err != nil {
+ return err
+ }
+
+ if opts.Method != "GET" && opts.Method != "HEAD" {
+ return fmt.Errorf("method %q must be GET or HEAD", opts.Method)
+ }
+
+ msg := http2startPushRequest{
+ parent: st,
+ method: opts.Method,
+ url: u,
+ header: http2cloneHeader(opts.Header),
+ done: http2errChanPool.Get().(chan error),
+ }
+
+ select {
+ case <-sc.doneServing:
+ return http2errClientDisconnected
+ case <-st.cw:
+ return http2errStreamClosed
+ case sc.wantStartPushCh <- msg:
+ }
+
+ select {
+ case <-sc.doneServing:
+ return http2errClientDisconnected
+ case <-st.cw:
+ return http2errStreamClosed
+ case err := <-msg.done:
+ http2errChanPool.Put(msg.done)
+ return err
+ }
+}
+
+type http2startPushRequest struct {
+ parent *http2stream
+ method string
+ url *url.URL
+ header Header
+ done chan error
+}
+
+func (sc *http2serverConn) startPush(msg http2startPushRequest) {
+ sc.serveG.check()
+
+ if msg.parent.state != http2stateOpen && msg.parent.state != http2stateHalfClosedRemote {
+
+ msg.done <- http2errStreamClosed
+ return
+ }
+
+ if !sc.pushEnabled {
+ msg.done <- ErrNotSupported
+ return
+ }
+
+ allocatePromisedID := func() (uint32, error) {
+ sc.serveG.check()
+
+ if !sc.pushEnabled {
+ return 0, ErrNotSupported
+ }
+
+ if sc.curPushedStreams+1 > sc.clientMaxStreams {
+ return 0, http2ErrPushLimitReached
+ }
+
+ if sc.maxPushPromiseID+2 >= 1<<31 {
+ sc.startGracefulShutdown()
+ return 0, http2ErrPushLimitReached
+ }
+ sc.maxPushPromiseID += 2
+ promisedID := sc.maxPushPromiseID
+
+ 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: msg.header,
+ })
+ if err != nil {
+
+ panic(fmt.Sprintf("newWriterAndRequestNoBody(%+v): %v", msg.url, err))
+ }
+
+ go sc.runHandler(rw, req, sc.handler.ServeHTTP)
+ return promisedID, nil
+ }
+
+ sc.writeFrame(http2FrameWriteRequest{
+ write: &http2writePushPromise{
+ streamID: msg.parent.id,
+ method: msg.method,
+ url: msg.url,
+ h: msg.header,
+ allocatePromisedID: allocatePromisedID,
+ },
+ stream: msg.parent,
+ done: msg.done,
+ })
+}
+
// foreachHeaderElement splits v according to the "#rule" construction
// in RFC 2616 section 2.1 and calls fn for each non-empty element.
func http2foreachHeaderElement(v string, fn func(string)) {
@@ -4820,16 +5254,16 @@ var http2connHeaders = []string{
"Upgrade",
}
-// checkValidHTTP2Request checks whether req is a valid HTTP/2 request,
+// checkValidHTTP2RequestHeaders checks whether h is a valid HTTP/2 request,
// per RFC 7540 Section 8.1.2.2.
// The returned error is reported to users.
-func http2checkValidHTTP2Request(req *Request) error {
- for _, h := range http2connHeaders {
- if _, ok := req.Header[h]; ok {
- return fmt.Errorf("request header %q is not valid in HTTP/2", h)
+func http2checkValidHTTP2RequestHeaders(h Header) error {
+ for _, k := range http2connHeaders {
+ if _, ok := h[k]; ok {
+ return fmt.Errorf("request header %q is not valid in HTTP/2", k)
}
}
- te := req.Header["Te"]
+ te := h["Te"]
if len(te) > 0 && (len(te) > 1 || (te[0] != "trailers" && te[0] != "")) {
return errors.New(`request header "TE" may only be "trailers" in HTTP/2`)
}
@@ -4877,6 +5311,45 @@ 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.
+func http2h1ServerKeepAlivesDisabled(hs *Server) bool {
+ var x interface{} = hs
+ type I interface {
+ doKeepAlives() bool
+ }
+ if hs, ok := x.(I); ok {
+ return !hs.doKeepAlives()
+ }
+ return false
+}
+
const (
// transportDefaultConnFlow is how many connection-level flow control
// tokens we give the server at start-up, past the default 64k.
@@ -4997,6 +5470,9 @@ type http2ClientConn struct {
readerDone chan struct{} // closed on error
readerErr error // set before readerDone is closed
+ idleTimeout time.Duration // or 0 for never
+ idleTimer *time.Timer
+
mu sync.Mutex // guards following
cond *sync.Cond // hold mu; broadcast on flow/closed changes
flow http2flow // our conn-level flow control quota (cs.flow is per stream)
@@ -5007,6 +5483,7 @@ type http2ClientConn struct {
goAwayDebug string // goAway frame's debug data, retained as a string
streams map[uint32]*http2clientStream // client-initiated
nextStreamID uint32
+ pings map[[8]byte]chan struct{} // in flight ping data to notification channel
bw *bufio.Writer
br *bufio.Reader
fr *http2Framer
@@ -5041,6 +5518,7 @@ type http2clientStream struct {
bytesRemain int64 // -1 means unknown; owned by transportResponseBody.Read
readErr error // sticky read error; owned by transportResponseBody.Read
stopReqBody error // if non-nil, stop writing req body; guarded by cc.mu
+ didReset bool // whether we sent a RST_STREAM to the server; guarded by cc.mu
peerReset chan struct{} // closed on peer reset
resetErr error // populated before peerReset is closed
@@ -5068,15 +5546,26 @@ func (cs *http2clientStream) awaitRequestCancel(req *Request) {
}
select {
case <-req.Cancel:
+ cs.cancelStream()
cs.bufPipe.CloseWithError(http2errRequestCanceled)
- cs.cc.writeStreamReset(cs.ID, http2ErrCodeCancel, nil)
case <-ctx.Done():
+ cs.cancelStream()
cs.bufPipe.CloseWithError(ctx.Err())
- cs.cc.writeStreamReset(cs.ID, http2ErrCodeCancel, nil)
case <-cs.done:
}
}
+func (cs *http2clientStream) cancelStream() {
+ cs.cc.mu.Lock()
+ didReset := cs.didReset
+ cs.didReset = true
+ cs.cc.mu.Unlock()
+
+ if !didReset {
+ cs.cc.writeStreamReset(cs.ID, http2ErrCodeCancel, nil)
+ }
+}
+
// checkResetOrDone reports any error sent in a RST_STREAM frame by the
// server, or errStreamClosed if the stream is complete.
func (cs *http2clientStream) checkResetOrDone() error {
@@ -5133,14 +5622,18 @@ func (t *http2Transport) RoundTrip(req *Request) (*Response, error) {
// authorityAddr returns a given authority (a host/IP, or host:port / ip:port)
// and returns a host:port. The port 443 is added if needed.
func http2authorityAddr(scheme string, authority string) (addr string) {
- if _, _, err := net.SplitHostPort(authority); err == nil {
- return authority
+ host, port, err := net.SplitHostPort(authority)
+ if err != nil {
+ port = "443"
+ if scheme == "http" {
+ port = "80"
+ }
+ host = authority
}
- port := "443"
- if scheme == "http" {
- port = "80"
+ if a, err := idna.ToASCII(host); err == nil {
+ host = a
}
- return net.JoinHostPort(authority, port)
+ return net.JoinHostPort(host, port)
}
// RoundTripOpt is like RoundTrip, but takes options.
@@ -5203,7 +5696,7 @@ func (t *http2Transport) dialClientConn(addr string, singleUse bool) (*http2Clie
func (t *http2Transport) newTLSConfig(host string) *tls.Config {
cfg := new(tls.Config)
if t.TLSClientConfig != nil {
- *cfg = *t.TLSClientConfig
+ *cfg = *http2cloneTLSConfig(t.TLSClientConfig)
}
if !http2strSliceContains(cfg.NextProtos, http2NextProtoTLS) {
cfg.NextProtos = append([]string{http2NextProtoTLS}, cfg.NextProtos...)
@@ -5273,6 +5766,11 @@ func (t *http2Transport) newClientConn(c net.Conn, singleUse bool) (*http2Client
streams: make(map[uint32]*http2clientStream),
singleUse: singleUse,
wantSettingsAck: true,
+ pings: make(map[[8]byte]chan struct{}),
+ }
+ if d := t.idleConnTimeout(); d != 0 {
+ cc.idleTimeout = d
+ cc.idleTimer = time.AfterFunc(d, cc.onIdleTimeout)
}
if http2VerboseLogs {
t.vlogf("http2: Transport creating client conn %p to %v", cc, c.RemoteAddr())
@@ -5345,6 +5843,16 @@ func (cc *http2ClientConn) canTakeNewRequestLocked() bool {
cc.nextStreamID < math.MaxInt32
}
+// 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
+// connection. The timer could just call closeIfIdle, but this is more
+// clear.
+func (cc *http2ClientConn) onIdleTimeout() {
+ cc.closeIfIdle()
+}
+
func (cc *http2ClientConn) closeIfIdle() {
cc.mu.Lock()
if len(cc.streams) > 0 {
@@ -5437,13 +5945,13 @@ func (cc *http2ClientConn) responseHeaderTimeout() time.Duration {
// Certain headers are special-cased as okay but not transmitted later.
func http2checkConnHeaders(req *Request) error {
if v := req.Header.Get("Upgrade"); v != "" {
- return errors.New("http2: invalid Upgrade request header")
+ return fmt.Errorf("http2: invalid Upgrade request header: %q", req.Header["Upgrade"])
}
- if v := req.Header.Get("Transfer-Encoding"); (v != "" && v != "chunked") || len(req.Header["Transfer-Encoding"]) > 1 {
- return errors.New("http2: invalid Transfer-Encoding request header")
+ if vv := req.Header["Transfer-Encoding"]; len(vv) > 0 && (len(vv) > 1 || vv[0] != "" && vv[0] != "chunked") {
+ return fmt.Errorf("http2: invalid Transfer-Encoding request header: %q", vv)
}
- if v := req.Header.Get("Connection"); (v != "" && v != "close" && v != "keep-alive") || len(req.Header["Connection"]) > 1 {
- return errors.New("http2: invalid Connection request header")
+ if vv := req.Header["Connection"]; len(vv) > 0 && (len(vv) > 1 || vv[0] != "" && vv[0] != "close" && vv[0] != "keep-alive") {
+ return fmt.Errorf("http2: invalid Connection request header: %q", vv)
}
return nil
}
@@ -5465,6 +5973,9 @@ func (cc *http2ClientConn) RoundTrip(req *Request) (*Response, error) {
if err := http2checkConnHeaders(req); err != nil {
return nil, err
}
+ if cc.idleTimer != nil {
+ cc.idleTimer.Stop()
+ }
trailers, err := http2commaSeparatedTrailers(req)
if err != nil {
@@ -5779,6 +6290,26 @@ func (cc *http2ClientConn) encodeHeaders(req *Request, addGzipHeader bool, trail
if host == "" {
host = req.URL.Host
}
+ host, err := httplex.PunycodeHostPort(host)
+ if err != nil {
+ return nil, err
+ }
+
+ var path string
+ if req.Method != "CONNECT" {
+ path = req.URL.RequestURI()
+ if !http2validPseudoPath(path) {
+ orig := path
+ path = strings.TrimPrefix(path, req.URL.Scheme+"://"+host)
+ if !http2validPseudoPath(path) {
+ if req.URL.Opaque != "" {
+ return nil, fmt.Errorf("invalid request :path %q from URL.Opaque = %q", orig, req.URL.Opaque)
+ } else {
+ return nil, fmt.Errorf("invalid request :path %q", orig)
+ }
+ }
+ }
+ }
for k, vv := range req.Header {
if !httplex.ValidHeaderFieldName(k) {
@@ -5794,8 +6325,8 @@ func (cc *http2ClientConn) encodeHeaders(req *Request, addGzipHeader bool, trail
cc.writeHeader(":authority", host)
cc.writeHeader(":method", req.Method)
if req.Method != "CONNECT" {
- cc.writeHeader(":path", req.URL.RequestURI())
- cc.writeHeader(":scheme", "https")
+ cc.writeHeader(":path", path)
+ cc.writeHeader(":scheme", req.URL.Scheme)
}
if trailers != "" {
cc.writeHeader("trailer", trailers)
@@ -5913,6 +6444,9 @@ func (cc *http2ClientConn) streamByID(id uint32, andRemove bool) *http2clientStr
if andRemove && cs != nil && !cc.closed {
cc.lastActive = time.Now()
delete(cc.streams, id)
+ if len(cc.streams) == 0 && cc.idleTimer != nil {
+ cc.idleTimer.Reset(cc.idleTimeout)
+ }
close(cs.done)
cc.cond.Broadcast()
}
@@ -5969,6 +6503,10 @@ func (rl *http2clientConnReadLoop) cleanup() {
defer cc.t.connPool().MarkDead(cc)
defer close(cc.readerDone)
+ if cc.idleTimer != nil {
+ cc.idleTimer.Stop()
+ }
+
err := cc.readerErr
cc.mu.Lock()
if cc.goAway != nil && http2isEOFOrNetReadError(err) {
@@ -6371,9 +6909,10 @@ func (rl *http2clientConnReadLoop) processData(f *http2DataFrame) error {
cc.bw.Flush()
cc.wmu.Unlock()
}
+ didReset := cs.didReset
cc.mu.Unlock()
- if len(data) > 0 {
+ if len(data) > 0 && !didReset {
if _, err := cs.bufPipe.Write(data); err != nil {
rl.endStreamError(cs, err)
return err
@@ -6524,9 +7063,56 @@ func (rl *http2clientConnReadLoop) processResetStream(f *http2RSTStreamFrame) er
return nil
}
+// Ping sends a PING frame to the server and waits for the ack.
+// Public implementation is in go17.go and not_go17.go
+func (cc *http2ClientConn) ping(ctx http2contextContext) error {
+ c := make(chan struct{})
+ // Generate a random payload
+ var p [8]byte
+ for {
+ if _, err := rand.Read(p[:]); err != nil {
+ return err
+ }
+ cc.mu.Lock()
+
+ if _, found := cc.pings[p]; !found {
+ cc.pings[p] = c
+ cc.mu.Unlock()
+ break
+ }
+ cc.mu.Unlock()
+ }
+ cc.wmu.Lock()
+ if err := cc.fr.WritePing(false, p); err != nil {
+ cc.wmu.Unlock()
+ return err
+ }
+ if err := cc.bw.Flush(); err != nil {
+ cc.wmu.Unlock()
+ return err
+ }
+ cc.wmu.Unlock()
+ select {
+ case <-c:
+ return nil
+ case <-ctx.Done():
+ return ctx.Err()
+ case <-cc.readerDone:
+
+ return cc.readerErr
+ }
+}
+
func (rl *http2clientConnReadLoop) processPing(f *http2PingFrame) error {
if f.IsAck() {
+ cc := rl.cc
+ cc.mu.Lock()
+ defer cc.mu.Unlock()
+ if c, ok := cc.pings[f.Data]; ok {
+ close(c)
+ delete(cc.pings, f.Data)
+ }
return nil
}
cc := rl.cc
@@ -6701,6 +7287,11 @@ func http2isConnectionCloseRequest(req *Request) bool {
// writeFramer is implemented by any type that is used to write frames.
type http2writeFramer interface {
writeFrame(http2writeContext) error
+
+ // staysWithinBuffer reports whether this writer promises that
+ // it will only write less than or equal to size bytes, and it
+ // won't Flush the write context.
+ staysWithinBuffer(size int) bool
}
// writeContext is the interface needed by the various frame writer
@@ -6743,8 +7334,16 @@ func (http2flushFrameWriter) writeFrame(ctx http2writeContext) error {
return ctx.Flush()
}
+func (http2flushFrameWriter) staysWithinBuffer(max int) bool { return false }
+
type http2writeSettings []http2Setting
+func (s http2writeSettings) staysWithinBuffer(max int) bool {
+ const settingSize = 6 // uint16 + uint32
+ return http2frameHeaderLen+settingSize*len(s) <= max
+
+}
+
func (s http2writeSettings) writeFrame(ctx http2writeContext) error {
return ctx.Framer().WriteSettings([]http2Setting(s)...)
}
@@ -6764,6 +7363,8 @@ func (p *http2writeGoAway) writeFrame(ctx http2writeContext) error {
return err
}
+func (*http2writeGoAway) staysWithinBuffer(max int) bool { return false }
+
type http2writeData struct {
streamID uint32
p []byte
@@ -6778,6 +7379,10 @@ func (w *http2writeData) writeFrame(ctx http2writeContext) error {
return ctx.Framer().WriteData(w.streamID, w.endStream, w.p)
}
+func (w *http2writeData) staysWithinBuffer(max int) bool {
+ return http2frameHeaderLen+len(w.p) <= max
+}
+
// handlerPanicRST is the message sent from handler goroutines when
// the handler panics.
type http2handlerPanicRST struct {
@@ -6788,22 +7393,59 @@ func (hp http2handlerPanicRST) writeFrame(ctx http2writeContext) error {
return ctx.Framer().WriteRSTStream(hp.StreamID, http2ErrCodeInternal)
}
+func (hp http2handlerPanicRST) staysWithinBuffer(max int) bool { return http2frameHeaderLen+4 <= max }
+
func (se http2StreamError) writeFrame(ctx http2writeContext) error {
return ctx.Framer().WriteRSTStream(se.StreamID, se.Code)
}
+func (se http2StreamError) staysWithinBuffer(max int) bool { return http2frameHeaderLen+4 <= max }
+
type http2writePingAck struct{ pf *http2PingFrame }
func (w http2writePingAck) writeFrame(ctx http2writeContext) error {
return ctx.Framer().WritePing(true, w.pf.Data)
}
+func (w http2writePingAck) staysWithinBuffer(max int) bool {
+ return http2frameHeaderLen+len(w.pf.Data) <= max
+}
+
type http2writeSettingsAck struct{}
func (http2writeSettingsAck) writeFrame(ctx http2writeContext) error {
return ctx.Framer().WriteSettingsAck()
}
+func (http2writeSettingsAck) staysWithinBuffer(max int) bool { return http2frameHeaderLen <= max }
+
+// splitHeaderBlock splits headerBlock into fragments so that each fragment fits
+// in a single frame, then calls fn for each fragment. firstFrag/lastFrag are true
+// for the first/last fragment, respectively.
+func http2splitHeaderBlock(ctx http2writeContext, headerBlock []byte, fn func(ctx http2writeContext, frag []byte, firstFrag, lastFrag bool) error) error {
+ // For now we're lazy and just pick the minimum MAX_FRAME_SIZE
+ // that all peers must support (16KB). Later we could care
+ // more and send larger frames if the peer advertised it, but
+ // there's little point. Most headers are small anyway (so we
+ // generally won't have CONTINUATION frames), and extra frames
+ // only waste 9 bytes anyway.
+ const maxFrameSize = 16384
+
+ first := true
+ for len(headerBlock) > 0 {
+ frag := headerBlock
+ if len(frag) > maxFrameSize {
+ frag = frag[:maxFrameSize]
+ }
+ headerBlock = headerBlock[len(frag):]
+ if err := fn(ctx, frag, first, len(headerBlock) == 0); err != nil {
+ return err
+ }
+ first = false
+ }
+ return nil
+}
+
// writeResHeaders is a request to write a HEADERS and 0+ CONTINUATION frames
// for HTTP response headers or trailers from a server handler.
type http2writeResHeaders struct {
@@ -6825,6 +7467,11 @@ func http2encKV(enc *hpack.Encoder, k, v string) {
enc.WriteField(hpack.HeaderField{Name: k, Value: v})
}
+func (w *http2writeResHeaders) staysWithinBuffer(max int) bool {
+
+ return false
+}
+
func (w *http2writeResHeaders) writeFrame(ctx http2writeContext) error {
enc, buf := ctx.HeaderEncoder()
buf.Reset()
@@ -6850,39 +7497,69 @@ func (w *http2writeResHeaders) writeFrame(ctx http2writeContext) error {
panic("unexpected empty hpack")
}
- // For now we're lazy and just pick the minimum MAX_FRAME_SIZE
- // that all peers must support (16KB). Later we could care
- // more and send larger frames if the peer advertised it, but
- // there's little point. Most headers are small anyway (so we
- // generally won't have CONTINUATION frames), and extra frames
- // only waste 9 bytes anyway.
- const maxFrameSize = 16384
+ return http2splitHeaderBlock(ctx, headerBlock, w.writeHeaderBlock)
+}
- first := true
- for len(headerBlock) > 0 {
- frag := headerBlock
- if len(frag) > maxFrameSize {
- frag = frag[:maxFrameSize]
- }
- headerBlock = headerBlock[len(frag):]
- endHeaders := len(headerBlock) == 0
- var err error
- if first {
- first = false
- err = ctx.Framer().WriteHeaders(http2HeadersFrameParam{
- StreamID: w.streamID,
- BlockFragment: frag,
- EndStream: w.endStream,
- EndHeaders: endHeaders,
- })
- } else {
- err = ctx.Framer().WriteContinuation(w.streamID, endHeaders, frag)
- }
- if err != nil {
- return err
- }
+func (w *http2writeResHeaders) writeHeaderBlock(ctx http2writeContext, frag []byte, firstFrag, lastFrag bool) error {
+ if firstFrag {
+ return ctx.Framer().WriteHeaders(http2HeadersFrameParam{
+ StreamID: w.streamID,
+ BlockFragment: frag,
+ EndStream: w.endStream,
+ EndHeaders: lastFrag,
+ })
+ } else {
+ return ctx.Framer().WriteContinuation(w.streamID, lastFrag, frag)
+ }
+}
+
+// writePushPromise is a request to write a PUSH_PROMISE and 0+ CONTINUATION frames.
+type http2writePushPromise struct {
+ streamID uint32 // pusher stream
+ method string // for :method
+ url *url.URL // for :scheme, :authority, :path
+ h Header
+
+ // Creates an ID for a pushed stream. This runs on serveG just before
+ // the frame is written. The returned ID is copied to promisedID.
+ allocatePromisedID func() (uint32, error)
+ promisedID uint32
+}
+
+func (w *http2writePushPromise) staysWithinBuffer(max int) bool {
+
+ return false
+}
+
+func (w *http2writePushPromise) writeFrame(ctx http2writeContext) error {
+ enc, buf := ctx.HeaderEncoder()
+ buf.Reset()
+
+ http2encKV(enc, ":method", w.method)
+ http2encKV(enc, ":scheme", w.url.Scheme)
+ http2encKV(enc, ":authority", w.url.Host)
+ http2encKV(enc, ":path", w.url.RequestURI())
+ http2encodeHeaders(enc, w.h, nil)
+
+ headerBlock := buf.Bytes()
+ if len(headerBlock) == 0 {
+ panic("unexpected empty hpack")
+ }
+
+ return http2splitHeaderBlock(ctx, headerBlock, w.writeHeaderBlock)
+}
+
+func (w *http2writePushPromise) writeHeaderBlock(ctx http2writeContext, frag []byte, firstFrag, lastFrag bool) error {
+ if firstFrag {
+ return ctx.Framer().WritePushPromise(http2PushPromiseParam{
+ StreamID: w.streamID,
+ PromiseID: w.promisedID,
+ BlockFragment: frag,
+ EndHeaders: lastFrag,
+ })
+ } else {
+ return ctx.Framer().WriteContinuation(w.streamID, lastFrag, frag)
}
- return nil
}
type http2write100ContinueHeadersFrame struct {
@@ -6901,15 +7578,24 @@ func (w http2write100ContinueHeadersFrame) writeFrame(ctx http2writeContext) err
})
}
+func (w http2write100ContinueHeadersFrame) staysWithinBuffer(max int) bool {
+
+ return 9+2*(len(":status")+len("100")) <= max
+}
+
type http2writeWindowUpdate struct {
streamID uint32 // or 0 for conn-level
n uint32
}
+func (wu http2writeWindowUpdate) staysWithinBuffer(max int) bool { return http2frameHeaderLen+4 <= max }
+
func (wu http2writeWindowUpdate) writeFrame(ctx http2writeContext) error {
return ctx.Framer().WriteWindowUpdate(wu.streamID, wu.n)
}
+// encodeHeaders encodes an http.Header. If keys is not nil, then (k, h[k])
+// is encoded only only if k is in keys.
func http2encodeHeaders(enc *hpack.Encoder, h Header, keys []string) {
if keys == nil {
sorter := http2sorterPool.Get().(*http2sorter)
@@ -6939,14 +7625,51 @@ func http2encodeHeaders(enc *hpack.Encoder, h Header, keys []string) {
}
}
-// frameWriteMsg is a request to write a frame.
-type http2frameWriteMsg struct {
+// WriteScheduler is the interface implemented by HTTP/2 write schedulers.
+// Methods are never called concurrently.
+type http2WriteScheduler interface {
+ // OpenStream opens a new stream in the write scheduler.
+ // It is illegal to call this with streamID=0 or with a streamID that is
+ // already open -- the call may panic.
+ OpenStream(streamID uint32, options http2OpenStreamOptions)
+
+ // CloseStream closes a stream in the write scheduler. Any frames queued on
+ // this stream should be discarded. It is illegal to call this on a stream
+ // that is not open -- the call may panic.
+ CloseStream(streamID uint32)
+
+ // AdjustStream adjusts the priority of the given stream. This may be called
+ // on a stream that has not yet been opened or has been closed. Note that
+ // RFC 7540 allows PRIORITY frames to be sent on streams in any state. See:
+ // https://tools.ietf.org/html/rfc7540#section-5.1
+ AdjustStream(streamID uint32, priority http2PriorityParam)
+
+ // Push queues a frame in the scheduler.
+ Push(wr http2FrameWriteRequest)
+
+ // Pop dequeues the next frame to write. Returns false if no frames can
+ // be written. Frames with a given wr.StreamID() are Pop'd in the same
+ // order they are Push'd.
+ Pop() (wr http2FrameWriteRequest, ok bool)
+}
+
+// OpenStreamOptions specifies extra options for WriteScheduler.OpenStream.
+type http2OpenStreamOptions struct {
+ // PusherID is zero if the stream was initiated by the client. Otherwise,
+ // PusherID names the stream that pushed the newly opened stream.
+ PusherID uint32
+}
+
+// FrameWriteRequest is a request to write a frame.
+type http2FrameWriteRequest struct {
// write is the interface value that does the writing, once the
- // writeScheduler (below) has decided to select this frame
- // to write. The write functions are all defined in write.go.
+ // WriteScheduler has selected this frame to write. The write
+ // functions are all defined in write.go.
write http2writeFramer
- stream *http2stream // used for prioritization. nil for non-stream frames.
+ // stream is the stream on which this frame will be written.
+ // nil for non-stream frames like PING and SETTINGS.
+ stream *http2stream
// done, if non-nil, must be a buffered channel with space for
// 1 message and is sent the return value from write (or an
@@ -6954,247 +7677,626 @@ type http2frameWriteMsg struct {
done chan error
}
-// for debugging only:
-func (wm http2frameWriteMsg) String() string {
- var streamID uint32
- if wm.stream != nil {
- streamID = wm.stream.id
+// StreamID returns the id of the stream this frame will be written to.
+// 0 is used for non-stream frames such as PING and SETTINGS.
+func (wr http2FrameWriteRequest) StreamID() uint32 {
+ if wr.stream == nil {
+ if se, ok := wr.write.(http2StreamError); ok {
+
+ return se.StreamID
+ }
+ return 0
+ }
+ return wr.stream.id
+}
+
+// DataSize returns the number of flow control bytes that must be consumed
+// to write this entire frame. This is 0 for non-DATA frames.
+func (wr http2FrameWriteRequest) DataSize() int {
+ if wd, ok := wr.write.(*http2writeData); ok {
+ return len(wd.p)
}
+ return 0
+}
+
+// Consume consumes min(n, available) bytes from this frame, where available
+// is the number of flow control bytes available on the stream. Consume returns
+// 0, 1, or 2 frames, where the integer return value gives the number of frames
+// returned.
+//
+// If flow control prevents consuming any bytes, this returns (_, _, 0). If
+// the entire frame was consumed, this returns (wr, _, 1). Otherwise, this
+// returns (consumed, rest, 2), where 'consumed' contains the consumed bytes and
+// 'rest' contains the remaining bytes. The consumed bytes are deducted from the
+// underlying stream's flow control budget.
+func (wr http2FrameWriteRequest) Consume(n int32) (http2FrameWriteRequest, http2FrameWriteRequest, int) {
+ var empty http2FrameWriteRequest
+
+ wd, ok := wr.write.(*http2writeData)
+ if !ok || len(wd.p) == 0 {
+ return wr, empty, 1
+ }
+
+ allowed := wr.stream.flow.available()
+ if n < allowed {
+ allowed = n
+ }
+ if wr.stream.sc.maxFrameSize < allowed {
+ allowed = wr.stream.sc.maxFrameSize
+ }
+ if allowed <= 0 {
+ return empty, empty, 0
+ }
+ if len(wd.p) > int(allowed) {
+ wr.stream.flow.take(allowed)
+ consumed := http2FrameWriteRequest{
+ stream: wr.stream,
+ write: &http2writeData{
+ streamID: wd.streamID,
+ p: wd.p[:allowed],
+
+ endStream: false,
+ },
+
+ done: nil,
+ }
+ rest := http2FrameWriteRequest{
+ stream: wr.stream,
+ write: &http2writeData{
+ streamID: wd.streamID,
+ p: wd.p[allowed:],
+ endStream: wd.endStream,
+ },
+ done: wr.done,
+ }
+ return consumed, rest, 2
+ }
+
+ wr.stream.flow.take(int32(len(wd.p)))
+ return wr, empty, 1
+}
+
+// String is for debugging only.
+func (wr http2FrameWriteRequest) String() string {
var des string
- if s, ok := wm.write.(fmt.Stringer); ok {
+ if s, ok := wr.write.(fmt.Stringer); ok {
des = s.String()
} else {
- des = fmt.Sprintf("%T", wm.write)
+ des = fmt.Sprintf("%T", wr.write)
}
- return fmt.Sprintf("[frameWriteMsg stream=%d, ch=%v, type: %v]", streamID, wm.done != nil, des)
+ return fmt.Sprintf("[FrameWriteRequest stream=%d, ch=%v, writer=%v]", wr.StreamID(), wr.done != nil, des)
}
-// writeScheduler tracks pending frames to write, priorities, and decides
-// the next one to use. It is not thread-safe.
-type http2writeScheduler struct {
- // zero are frames not associated with a specific stream.
- // They're sent before any stream-specific freams.
- zero http2writeQueue
+// writeQueue is used by implementations of WriteScheduler.
+type http2writeQueue struct {
+ s []http2FrameWriteRequest
+}
- // maxFrameSize is the maximum size of a DATA frame
- // we'll write. Must be non-zero and between 16K-16M.
- maxFrameSize uint32
+func (q *http2writeQueue) empty() bool { return len(q.s) == 0 }
- // sq contains the stream-specific queues, keyed by stream ID.
- // when a stream is idle, it's deleted from the map.
- sq map[uint32]*http2writeQueue
+func (q *http2writeQueue) push(wr http2FrameWriteRequest) {
+ q.s = append(q.s, wr)
+}
- // canSend is a slice of memory that's reused between frame
- // scheduling decisions to hold the list of writeQueues (from sq)
- // which have enough flow control data to send. After canSend is
- // built, the best is selected.
- canSend []*http2writeQueue
+func (q *http2writeQueue) shift() http2FrameWriteRequest {
+ if len(q.s) == 0 {
+ panic("invalid use of queue")
+ }
+ wr := q.s[0]
- // pool of empty queues for reuse.
- queuePool []*http2writeQueue
+ copy(q.s, q.s[1:])
+ q.s[len(q.s)-1] = http2FrameWriteRequest{}
+ q.s = q.s[:len(q.s)-1]
+ return wr
}
-func (ws *http2writeScheduler) putEmptyQueue(q *http2writeQueue) {
- if len(q.s) != 0 {
- panic("queue must be empty")
+// consume consumes up to n bytes from q.s[0]. If the frame is
+// entirely consumed, it is removed from the queue. If the frame
+// is partially consumed, the frame is kept with the consumed
+// bytes removed. Returns true iff any bytes were consumed.
+func (q *http2writeQueue) consume(n int32) (http2FrameWriteRequest, bool) {
+ if len(q.s) == 0 {
+ return http2FrameWriteRequest{}, false
}
- ws.queuePool = append(ws.queuePool, q)
+ consumed, rest, numresult := q.s[0].Consume(n)
+ switch numresult {
+ case 0:
+ return http2FrameWriteRequest{}, false
+ case 1:
+ q.shift()
+ case 2:
+ q.s[0] = rest
+ }
+ return consumed, true
}
-func (ws *http2writeScheduler) getEmptyQueue() *http2writeQueue {
- ln := len(ws.queuePool)
+type http2writeQueuePool []*http2writeQueue
+
+// put inserts an unused writeQueue into the pool.
+func (p *http2writeQueuePool) put(q *http2writeQueue) {
+ for i := range q.s {
+ q.s[i] = http2FrameWriteRequest{}
+ }
+ q.s = q.s[:0]
+ *p = append(*p, q)
+}
+
+// get returns an empty writeQueue.
+func (p *http2writeQueuePool) get() *http2writeQueue {
+ ln := len(*p)
if ln == 0 {
return new(http2writeQueue)
}
- q := ws.queuePool[ln-1]
- ws.queuePool = ws.queuePool[:ln-1]
+ x := ln - 1
+ q := (*p)[x]
+ (*p)[x] = nil
+ *p = (*p)[:x]
return q
}
-func (ws *http2writeScheduler) empty() bool { return ws.zero.empty() && len(ws.sq) == 0 }
+// RFC 7540, Section 5.3.5: the default weight is 16.
+const http2priorityDefaultWeight = 15 // 16 = 15 + 1
-func (ws *http2writeScheduler) add(wm http2frameWriteMsg) {
- st := wm.stream
- if st == nil {
- ws.zero.push(wm)
+// PriorityWriteSchedulerConfig configures a priorityWriteScheduler.
+type http2PriorityWriteSchedulerConfig struct {
+ // MaxClosedNodesInTree controls the maximum number of closed streams to
+ // retain in the priority tree. Setting this to zero saves a small amount
+ // of memory at the cost of performance.
+ //
+ // See RFC 7540, Section 5.3.4:
+ // "It is possible for a stream to become closed while prioritization
+ // information ... is in transit. ... This potentially creates suboptimal
+ // prioritization, since the stream could be given a priority that is
+ // different from what is intended. To avoid these problems, an endpoint
+ // SHOULD retain stream prioritization state for a period after streams
+ // become closed. The longer state is retained, the lower the chance that
+ // streams are assigned incorrect or default priority values."
+ MaxClosedNodesInTree int
+
+ // MaxIdleNodesInTree controls the maximum number of idle streams to
+ // retain in the priority tree. Setting this to zero saves a small amount
+ // of memory at the cost of performance.
+ //
+ // See RFC 7540, Section 5.3.4:
+ // Similarly, streams that are in the "idle" state can be assigned
+ // priority or become a parent of other streams. This allows for the
+ // creation of a grouping node in the dependency tree, which enables
+ // more flexible expressions of priority. Idle streams begin with a
+ // default priority (Section 5.3.5).
+ MaxIdleNodesInTree int
+
+ // ThrottleOutOfOrderWrites enables write throttling to help ensure that
+ // data is delivered in priority order. This works around a race where
+ // stream B depends on stream A and both streams are about to call Write
+ // to queue DATA frames. If B wins the race, a naive scheduler would eagerly
+ // write as much data from B as possible, but this is suboptimal because A
+ // is a higher-priority stream. With throttling enabled, we write a small
+ // amount of data from B to minimize the amount of bandwidth that B can
+ // steal from A.
+ ThrottleOutOfOrderWrites bool
+}
+
+// NewPriorityWriteScheduler constructs a WriteScheduler that schedules
+// frames by following HTTP/2 priorities as described in RFC 7340 Section 5.3.
+// If cfg is nil, default options are used.
+func http2NewPriorityWriteScheduler(cfg *http2PriorityWriteSchedulerConfig) http2WriteScheduler {
+ if cfg == nil {
+
+ cfg = &http2PriorityWriteSchedulerConfig{
+ MaxClosedNodesInTree: 10,
+ MaxIdleNodesInTree: 10,
+ ThrottleOutOfOrderWrites: false,
+ }
+ }
+
+ ws := &http2priorityWriteScheduler{
+ nodes: make(map[uint32]*http2priorityNode),
+ maxClosedNodesInTree: cfg.MaxClosedNodesInTree,
+ maxIdleNodesInTree: cfg.MaxIdleNodesInTree,
+ enableWriteThrottle: cfg.ThrottleOutOfOrderWrites,
+ }
+ ws.nodes[0] = &ws.root
+ if cfg.ThrottleOutOfOrderWrites {
+ ws.writeThrottleLimit = 1024
} else {
- ws.streamQueue(st.id).push(wm)
+ ws.writeThrottleLimit = math.MaxInt32
}
+ return ws
+}
+
+type http2priorityNodeState int
+
+const (
+ http2priorityNodeOpen http2priorityNodeState = iota
+ http2priorityNodeClosed
+ http2priorityNodeIdle
+)
+
+// priorityNode is a node in an HTTP/2 priority tree.
+// Each node is associated with a single stream ID.
+// See RFC 7540, Section 5.3.
+type http2priorityNode struct {
+ q http2writeQueue // queue of pending frames to write
+ id uint32 // id of the stream, or 0 for the root of the tree
+ weight uint8 // the actual weight is weight+1, so the value is in [1,256]
+ state http2priorityNodeState // open | closed | idle
+ bytes int64 // number of bytes written by this node, or 0 if closed
+ subtreeBytes int64 // sum(node.bytes) of all nodes in this subtree
+
+ // These links form the priority tree.
+ parent *http2priorityNode
+ kids *http2priorityNode // start of the kids list
+ prev, next *http2priorityNode // doubly-linked list of siblings
}
-func (ws *http2writeScheduler) streamQueue(streamID uint32) *http2writeQueue {
- if q, ok := ws.sq[streamID]; ok {
- return q
+func (n *http2priorityNode) setParent(parent *http2priorityNode) {
+ if n == parent {
+ panic("setParent to self")
}
- if ws.sq == nil {
- ws.sq = make(map[uint32]*http2writeQueue)
+ if n.parent == parent {
+ return
+ }
+
+ if parent := n.parent; parent != nil {
+ if n.prev == nil {
+ parent.kids = n.next
+ } else {
+ n.prev.next = n.next
+ }
+ if n.next != nil {
+ n.next.prev = n.prev
+ }
+ }
+
+ n.parent = parent
+ if parent == nil {
+ n.next = nil
+ n.prev = nil
+ } else {
+ n.next = parent.kids
+ n.prev = nil
+ if n.next != nil {
+ n.next.prev = n
+ }
+ parent.kids = n
}
- q := ws.getEmptyQueue()
- ws.sq[streamID] = q
- return q
}
-// take returns the most important frame to write and removes it from the scheduler.
-// It is illegal to call this if the scheduler is empty or if there are no connection-level
-// flow control bytes available.
-func (ws *http2writeScheduler) take() (wm http2frameWriteMsg, ok bool) {
- if ws.maxFrameSize == 0 {
- panic("internal error: ws.maxFrameSize not initialized or invalid")
+func (n *http2priorityNode) addBytes(b int64) {
+ n.bytes += b
+ for ; n != nil; n = n.parent {
+ n.subtreeBytes += b
}
+}
- if !ws.zero.empty() {
- return ws.zero.shift(), true
+// walkReadyInOrder iterates over the tree in priority order, calling f for each node
+// with a non-empty write queue. When f returns true, this funcion returns true and the
+// walk halts. tmp is used as scratch space for sorting.
+//
+// f(n, openParent) takes two arguments: the node to visit, n, and a bool that is true
+// if any ancestor p of n is still open (ignoring the root node).
+func (n *http2priorityNode) walkReadyInOrder(openParent bool, tmp *[]*http2priorityNode, f func(*http2priorityNode, bool) bool) bool {
+ if !n.q.empty() && f(n, openParent) {
+ return true
}
- if len(ws.sq) == 0 {
- return
+ if n.kids == nil {
+ return false
+ }
+
+ if n.id != 0 {
+ openParent = openParent || (n.state == http2priorityNodeOpen)
}
- for id, q := range ws.sq {
- if q.firstIsNoCost() {
- return ws.takeFrom(id, q)
+ w := n.kids.weight
+ needSort := false
+ for k := n.kids.next; k != nil; k = k.next {
+ if k.weight != w {
+ needSort = true
+ break
}
}
+ if !needSort {
+ for k := n.kids; k != nil; k = k.next {
+ if k.walkReadyInOrder(openParent, tmp, f) {
+ return true
+ }
+ }
+ return false
+ }
- if len(ws.canSend) != 0 {
- panic("should be empty")
+ *tmp = (*tmp)[:0]
+ for n.kids != nil {
+ *tmp = append(*tmp, n.kids)
+ n.kids.setParent(nil)
}
- for _, q := range ws.sq {
- if n := ws.streamWritableBytes(q); n > 0 {
- ws.canSend = append(ws.canSend, q)
+ sort.Sort(http2sortPriorityNodeSiblings(*tmp))
+ for i := len(*tmp) - 1; i >= 0; i-- {
+ (*tmp)[i].setParent(n)
+ }
+ for k := n.kids; k != nil; k = k.next {
+ if k.walkReadyInOrder(openParent, tmp, f) {
+ return true
}
}
- if len(ws.canSend) == 0 {
- return
+ return false
+}
+
+type http2sortPriorityNodeSiblings []*http2priorityNode
+
+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 {
+
+ 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 {
+ return wi >= wk
+ }
+ if bk == 0 {
+ return false
}
- defer ws.zeroCanSend()
+ return bi/bk <= wi/wk
+}
+
+type http2priorityWriteScheduler struct {
+ // root is the root of the priority tree, where root.id = 0.
+ // The root queues control frames that are not associated with any stream.
+ root http2priorityNode
+
+ // nodes maps stream ids to priority tree nodes.
+ nodes map[uint32]*http2priorityNode
- q := ws.canSend[0]
+ // maxID is the maximum stream id in nodes.
+ maxID uint32
- return ws.takeFrom(q.streamID(), q)
+ // lists of nodes that have been closed or are idle, but are kept in
+ // the tree for improved prioritization. When the lengths exceed either
+ // maxClosedNodesInTree or maxIdleNodesInTree, old nodes are discarded.
+ closedNodes, idleNodes []*http2priorityNode
+
+ // From the config.
+ maxClosedNodesInTree int
+ maxIdleNodesInTree int
+ writeThrottleLimit int32
+ enableWriteThrottle bool
+
+ // tmp is scratch space for priorityNode.walkReadyInOrder to reduce allocations.
+ tmp []*http2priorityNode
+
+ // pool of empty queues for reuse.
+ queuePool http2writeQueuePool
}
-// zeroCanSend is defered from take.
-func (ws *http2writeScheduler) zeroCanSend() {
- for i := range ws.canSend {
- ws.canSend[i] = nil
+func (ws *http2priorityWriteScheduler) OpenStream(streamID uint32, options http2OpenStreamOptions) {
+
+ if curr := ws.nodes[streamID]; curr != nil {
+ if curr.state != http2priorityNodeIdle {
+ panic(fmt.Sprintf("stream %d already opened", streamID))
+ }
+ curr.state = http2priorityNodeOpen
+ return
+ }
+
+ parent := ws.nodes[options.PusherID]
+ if parent == nil {
+ parent = &ws.root
+ }
+ n := &http2priorityNode{
+ q: *ws.queuePool.get(),
+ id: streamID,
+ weight: http2priorityDefaultWeight,
+ state: http2priorityNodeOpen,
+ }
+ n.setParent(parent)
+ ws.nodes[streamID] = n
+ if streamID > ws.maxID {
+ ws.maxID = streamID
}
- ws.canSend = ws.canSend[:0]
}
-// streamWritableBytes returns the number of DATA bytes we could write
-// from the given queue's stream, if this stream/queue were
-// selected. It is an error to call this if q's head isn't a
-// *writeData.
-func (ws *http2writeScheduler) streamWritableBytes(q *http2writeQueue) int32 {
- wm := q.head()
- ret := wm.stream.flow.available()
- if ret == 0 {
- return 0
+func (ws *http2priorityWriteScheduler) CloseStream(streamID uint32) {
+ if streamID == 0 {
+ panic("violation of WriteScheduler interface: cannot close stream 0")
}
- if int32(ws.maxFrameSize) < ret {
- ret = int32(ws.maxFrameSize)
+ if ws.nodes[streamID] == nil {
+ panic(fmt.Sprintf("violation of WriteScheduler interface: unknown stream %d", streamID))
}
- if ret == 0 {
- panic("internal error: ws.maxFrameSize not initialized or invalid")
+ if ws.nodes[streamID].state != http2priorityNodeOpen {
+ panic(fmt.Sprintf("violation of WriteScheduler interface: stream %d already closed", streamID))
}
- wd := wm.write.(*http2writeData)
- if len(wd.p) < int(ret) {
- ret = int32(len(wd.p))
+
+ n := ws.nodes[streamID]
+ n.state = http2priorityNodeClosed
+ n.addBytes(-n.bytes)
+
+ q := n.q
+ ws.queuePool.put(&q)
+ n.q.s = nil
+ if ws.maxClosedNodesInTree > 0 {
+ ws.addClosedOrIdleNode(&ws.closedNodes, ws.maxClosedNodesInTree, n)
+ } else {
+ ws.removeNode(n)
}
- return ret
}
-func (ws *http2writeScheduler) takeFrom(id uint32, q *http2writeQueue) (wm http2frameWriteMsg, ok bool) {
- wm = q.head()
-
- if wd, ok := wm.write.(*http2writeData); ok && len(wd.p) > 0 {
- allowed := wm.stream.flow.available()
- if allowed == 0 {
+func (ws *http2priorityWriteScheduler) AdjustStream(streamID uint32, priority http2PriorityParam) {
+ if streamID == 0 {
+ panic("adjustPriority on root")
+ }
- return http2frameWriteMsg{}, false
+ n := ws.nodes[streamID]
+ if n == nil {
+ if streamID <= ws.maxID || ws.maxIdleNodesInTree == 0 {
+ return
}
- if int32(ws.maxFrameSize) < allowed {
- allowed = int32(ws.maxFrameSize)
+ ws.maxID = streamID
+ n = &http2priorityNode{
+ q: *ws.queuePool.get(),
+ id: streamID,
+ weight: http2priorityDefaultWeight,
+ state: http2priorityNodeIdle,
}
+ n.setParent(&ws.root)
+ ws.nodes[streamID] = n
+ ws.addClosedOrIdleNode(&ws.idleNodes, ws.maxIdleNodesInTree, n)
+ }
- if len(wd.p) > int(allowed) {
- wm.stream.flow.take(allowed)
- chunk := wd.p[:allowed]
- wd.p = wd.p[allowed:]
+ parent := ws.nodes[priority.StreamDep]
+ if parent == nil {
+ n.setParent(&ws.root)
+ n.weight = http2priorityDefaultWeight
+ return
+ }
- return http2frameWriteMsg{
- stream: wm.stream,
- write: &http2writeData{
- streamID: wd.streamID,
- p: chunk,
+ if n == parent {
+ return
+ }
- endStream: false,
- },
+ for x := parent.parent; x != nil; x = x.parent {
+ if x == n {
+ parent.setParent(n.parent)
+ break
+ }
+ }
- done: nil,
- }, true
+ if priority.Exclusive {
+ k := parent.kids
+ for k != nil {
+ next := k.next
+ if k != n {
+ k.setParent(n)
+ }
+ k = next
}
- wm.stream.flow.take(int32(len(wd.p)))
}
- q.shift()
- if q.empty() {
- ws.putEmptyQueue(q)
- delete(ws.sq, id)
+ n.setParent(parent)
+ n.weight = priority.Weight
+}
+
+func (ws *http2priorityWriteScheduler) Push(wr http2FrameWriteRequest) {
+ var n *http2priorityNode
+ if id := wr.StreamID(); id == 0 {
+ n = &ws.root
+ } else {
+ n = ws.nodes[id]
+ if n == nil {
+ panic("add on non-open stream")
+ }
}
- return wm, true
+ n.q.push(wr)
}
-func (ws *http2writeScheduler) forgetStream(id uint32) {
- q, ok := ws.sq[id]
- if !ok {
+func (ws *http2priorityWriteScheduler) Pop() (wr http2FrameWriteRequest, ok bool) {
+ ws.root.walkReadyInOrder(false, &ws.tmp, func(n *http2priorityNode, openParent bool) bool {
+ limit := int32(math.MaxInt32)
+ if openParent {
+ limit = ws.writeThrottleLimit
+ }
+ wr, ok = n.q.consume(limit)
+ if !ok {
+ return false
+ }
+ n.addBytes(int64(wr.DataSize()))
+
+ if openParent {
+ ws.writeThrottleLimit += 1024
+ if ws.writeThrottleLimit < 0 {
+ ws.writeThrottleLimit = math.MaxInt32
+ }
+ } else if ws.enableWriteThrottle {
+ ws.writeThrottleLimit = 1024
+ }
+ return true
+ })
+ return wr, ok
+}
+
+func (ws *http2priorityWriteScheduler) addClosedOrIdleNode(list *[]*http2priorityNode, maxSize int, n *http2priorityNode) {
+ if maxSize == 0 {
return
}
- delete(ws.sq, id)
+ if len(*list) == maxSize {
- for i := range q.s {
- q.s[i] = http2frameWriteMsg{}
+ ws.removeNode((*list)[0])
+ x := (*list)[1:]
+ copy(*list, x)
+ *list = (*list)[:len(x)]
}
- q.s = q.s[:0]
- ws.putEmptyQueue(q)
+ *list = append(*list, n)
}
-type http2writeQueue struct {
- s []http2frameWriteMsg
+func (ws *http2priorityWriteScheduler) removeNode(n *http2priorityNode) {
+ for k := n.kids; k != nil; k = k.next {
+ k.setParent(n.parent)
+ }
+ n.setParent(nil)
+ delete(ws.nodes, n.id)
}
-// streamID returns the stream ID for a non-empty stream-specific queue.
-func (q *http2writeQueue) streamID() uint32 { return q.s[0].stream.id }
+// NewRandomWriteScheduler constructs a WriteScheduler that ignores HTTP/2
+// priorities. Control frames like SETTINGS and PING are written before DATA
+// frames, but if no control frames are queued and multiple streams have queued
+// HEADERS or DATA frames, Pop selects a ready stream arbitrarily.
+func http2NewRandomWriteScheduler() http2WriteScheduler {
+ return &http2randomWriteScheduler{sq: make(map[uint32]*http2writeQueue)}
+}
-func (q *http2writeQueue) empty() bool { return len(q.s) == 0 }
+type http2randomWriteScheduler struct {
+ // zero are frames not associated with a specific stream.
+ zero http2writeQueue
+
+ // sq contains the stream-specific queues, keyed by stream ID.
+ // When a stream is idle or closed, it's deleted from the map.
+ sq map[uint32]*http2writeQueue
-func (q *http2writeQueue) push(wm http2frameWriteMsg) {
- q.s = append(q.s, wm)
+ // pool of empty queues for reuse.
+ queuePool http2writeQueuePool
}
-// head returns the next item that would be removed by shift.
-func (q *http2writeQueue) head() http2frameWriteMsg {
- if len(q.s) == 0 {
- panic("invalid use of queue")
- }
- return q.s[0]
+func (ws *http2randomWriteScheduler) OpenStream(streamID uint32, options http2OpenStreamOptions) {
+
}
-func (q *http2writeQueue) shift() http2frameWriteMsg {
- if len(q.s) == 0 {
- panic("invalid use of queue")
+func (ws *http2randomWriteScheduler) CloseStream(streamID uint32) {
+ q, ok := ws.sq[streamID]
+ if !ok {
+ return
}
- wm := q.s[0]
+ delete(ws.sq, streamID)
+ ws.queuePool.put(q)
+}
+
+func (ws *http2randomWriteScheduler) AdjustStream(streamID uint32, priority http2PriorityParam) {
- copy(q.s, q.s[1:])
- q.s[len(q.s)-1] = http2frameWriteMsg{}
- q.s = q.s[:len(q.s)-1]
- return wm
}
-func (q *http2writeQueue) firstIsNoCost() bool {
- if df, ok := q.s[0].write.(*http2writeData); ok {
- return len(df.p) == 0
+func (ws *http2randomWriteScheduler) Push(wr http2FrameWriteRequest) {
+ id := wr.StreamID()
+ if id == 0 {
+ ws.zero.push(wr)
+ return
}
- return true
+ q, ok := ws.sq[id]
+ if !ok {
+ q = ws.queuePool.get()
+ ws.sq[id] = q
+ }
+ q.push(wr)
+}
+
+func (ws *http2randomWriteScheduler) Pop() (http2FrameWriteRequest, bool) {
+
+ if !ws.zero.empty() {
+ return ws.zero.shift(), true
+ }
+
+ for _, q := range ws.sq {
+ if wr, ok := q.consume(math.MaxInt32); ok {
+ return wr, true
+ }
+ }
+ return http2FrameWriteRequest{}, false
}
diff --git a/src/net/http/header.go b/src/net/http/header.go
index 6343165..8321692 100644
--- a/src/net/http/header.go
+++ b/src/net/http/header.go
@@ -32,9 +32,11 @@ func (h Header) Set(key, value string) {
}
// Get gets the first value associated with the given key.
+// It is case insensitive; textproto.CanonicalMIMEHeaderKey is used
+// to canonicalize the provided key.
// If there are no values associated with the key, Get returns "".
-// To access multiple values of a key, access the map directly
-// with CanonicalHeaderKey.
+// To access multiple values of a key, or to use non-canonical keys,
+// access the map directly.
func (h Header) Get(key string) string {
return textproto.MIMEHeader(h).Get(key)
}
diff --git a/src/net/http/http.go b/src/net/http/http.go
index b34ae41..826f7ff 100644
--- a/src/net/http/http.go
+++ b/src/net/http/http.go
@@ -5,7 +5,11 @@
package http
import (
+ "io"
+ "strconv"
"strings"
+ "time"
+ "unicode/utf8"
"golang_org/x/net/lex/httplex"
)
@@ -14,6 +18,10 @@ import (
// Transport's byte-limiting readers.
const maxInt64 = 1<<63 - 1
+// aLongTimeAgo is a non-zero time, far in the past, used for
+// immediate cancelation of network operations.
+var aLongTimeAgo = time.Unix(233431200, 0)
+
// TODO(bradfitz): move common stuff here. The other files have accumulated
// generic http stuff in random places.
@@ -41,3 +49,93 @@ func removeEmptyPort(host string) string {
func isNotToken(r rune) bool {
return !httplex.IsTokenRune(r)
}
+
+func isASCII(s string) bool {
+ for i := 0; i < len(s); i++ {
+ if s[i] >= utf8.RuneSelf {
+ return false
+ }
+ }
+ return true
+}
+
+func hexEscapeNonASCII(s string) string {
+ newLen := 0
+ for i := 0; i < len(s); i++ {
+ if s[i] >= utf8.RuneSelf {
+ newLen += 3
+ } else {
+ newLen++
+ }
+ }
+ if newLen == len(s) {
+ return s
+ }
+ b := make([]byte, 0, newLen)
+ for i := 0; i < len(s); i++ {
+ if s[i] >= utf8.RuneSelf {
+ b = append(b, '%')
+ b = strconv.AppendInt(b, int64(s[i]), 16)
+ } else {
+ b = append(b, s[i])
+ }
+ }
+ return string(b)
+}
+
+// NoBody is an io.ReadCloser with no bytes. Read always returns EOF
+// and Close always returns nil. It can be used in an outgoing client
+// request to explicitly signal that a request has zero bytes.
+// An alternative, however, is to simply set Request.Body to nil.
+var NoBody = noBody{}
+
+type noBody struct{}
+
+func (noBody) Read([]byte) (int, error) { return 0, io.EOF }
+func (noBody) Close() error { return nil }
+func (noBody) WriteTo(io.Writer) (int64, error) { return 0, nil }
+
+var (
+ // verify that an io.Copy from NoBody won't require a buffer:
+ _ io.WriterTo = NoBody
+ _ io.ReadCloser = NoBody
+)
+
+// PushOptions describes options for Pusher.Push.
+type PushOptions struct {
+ // Method specifies the HTTP method for the promised request.
+ // If set, it must be "GET" or "HEAD". Empty means "GET".
+ Method string
+
+ // Header specifies additional promised request headers. This cannot
+ // include HTTP/2 pseudo header fields like ":path" and ":scheme",
+ // which will be added automatically.
+ Header Header
+}
+
+// Pusher is the interface implemented by ResponseWriters that support
+// HTTP/2 server push. For more background, see
+// https://tools.ietf.org/html/rfc7540#section-8.2.
+type Pusher interface {
+ // Push initiates an HTTP/2 server push. This constructs a synthetic
+ // request using the given target and options, serializes that request
+ // into a PUSH_PROMISE frame, then dispatches that request using the
+ // server's request handler. If opts is nil, default options are used.
+ //
+ // The target must either be an absolute path (like "/path") or an absolute
+ // URL that contains a valid host and the same scheme as the parent request.
+ // If the target is a path, it will inherit the scheme and host of the
+ // parent request.
+ //
+ // The HTTP/2 spec disallows recursive pushes and cross-authority pushes.
+ // Push may or may not detect these invalid pushes; however, invalid
+ // pushes will be detected and canceled by conforming clients.
+ //
+ // Handlers that wish to push URL X should call Push before sending any
+ // data that may trigger a request for URL X. This avoids a race where the
+ // client issues requests for X before receiving the PUSH_PROMISE for X.
+ //
+ // Push returns ErrNotSupported if the client has disabled push or if push
+ // is not supported on the underlying connection.
+ Push(target string, opts *PushOptions) error
+}
diff --git a/src/net/http/http_test.go b/src/net/http/http_test.go
index 34da4bb..8f466bb 100644
--- a/src/net/http/http_test.go
+++ b/src/net/http/http_test.go
@@ -12,8 +12,13 @@ import (
"os/exec"
"reflect"
"testing"
+ "time"
)
+func init() {
+ shutdownPollInterval = 5 * time.Millisecond
+}
+
func TestForeachHeaderElement(t *testing.T) {
tests := []struct {
in string
@@ -51,6 +56,18 @@ func TestCleanHost(t *testing.T) {
{"www.google.com foo", "www.google.com"},
{"www.google.com/foo", "www.google.com"},
{" first character is a space", ""},
+ {"[1::6]:8080", "[1::6]:8080"},
+
+ // Punycode:
+ {"гофер.рф/foo", "xn--c1ae0ajs.xn--p1ai"},
+ {"bücher.de", "xn--bcher-kva.de"},
+ {"bücher.de:8080", "xn--bcher-kva.de:8080"},
+ // Verify we convert to lowercase before punycode:
+ {"BÜCHER.de", "xn--bcher-kva.de"},
+ {"BÜCHER.de:8080", "xn--bcher-kva.de:8080"},
+ // Verify we normalize to NFC before punycode:
+ {"gophér.nfc", "xn--gophr-esa.nfc"}, // NFC input; no work needed
+ {"goph\u0065\u0301r.nfd", "xn--gophr-esa.nfd"}, // NFD input
}
for _, tt := range tests {
got := cleanHost(tt.in)
@@ -65,8 +82,9 @@ func TestCleanHost(t *testing.T) {
// This catches accidental dependencies between the HTTP transport and
// server code.
func TestCmdGoNoHTTPServer(t *testing.T) {
+ t.Parallel()
goBin := testenv.GoToolPath(t)
- out, err := exec.Command("go", "tool", "nm", goBin).CombinedOutput()
+ out, err := exec.Command(goBin, "tool", "nm", goBin).CombinedOutput()
if err != nil {
t.Fatalf("go tool nm: %v: %s", err, out)
}
diff --git a/src/net/http/httptest/example_test.go b/src/net/http/httptest/example_test.go
index 124ce75..bd2c496 100644
--- a/src/net/http/httptest/example_test.go
+++ b/src/net/http/httptest/example_test.go
@@ -6,6 +6,7 @@ package httptest_test
import (
"fmt"
+ "io"
"io/ioutil"
"log"
"net/http"
@@ -14,15 +15,24 @@ import (
func ExampleResponseRecorder() {
handler := func(w http.ResponseWriter, r *http.Request) {
- http.Error(w, "something failed", http.StatusInternalServerError)
+ io.WriteString(w, "<html><body>Hello World!</body></html>")
}
req := httptest.NewRequest("GET", "http://example.com/foo", nil)
w := httptest.NewRecorder()
handler(w, req)
- fmt.Printf("%d - %s", w.Code, w.Body.String())
- // Output: 500 - something failed
+ resp := w.Result()
+ body, _ := ioutil.ReadAll(resp.Body)
+
+ fmt.Println(resp.StatusCode)
+ fmt.Println(resp.Header.Get("Content-Type"))
+ fmt.Println(string(body))
+
+ // Output:
+ // 200
+ // text/html; charset=utf-8
+ // <html><body>Hello World!</body></html>
}
func ExampleServer() {
diff --git a/src/net/http/httptest/httptest.go b/src/net/http/httptest/httptest.go
index e2148a6..f7202da 100644
--- a/src/net/http/httptest/httptest.go
+++ b/src/net/http/httptest/httptest.go
@@ -35,6 +35,9 @@ import (
//
// NewRequest panics on error for ease of use in testing, where a
// panic is acceptable.
+//
+// To generate a client HTTP request instead of a server request, see
+// the NewRequest function in the net/http package.
func NewRequest(method, target string, body io.Reader) *http.Request {
if method == "" {
method = "GET"
diff --git a/src/net/http/httptest/recorder.go b/src/net/http/httptest/recorder.go
index 0ad26a3..5f1aa6a 100644
--- a/src/net/http/httptest/recorder.go
+++ b/src/net/http/httptest/recorder.go
@@ -8,15 +8,33 @@ import (
"bytes"
"io/ioutil"
"net/http"
+ "strconv"
+ "strings"
)
// ResponseRecorder is an implementation of http.ResponseWriter that
// records its mutations for later inspection in tests.
type ResponseRecorder struct {
- Code int // the HTTP response code from WriteHeader
- HeaderMap http.Header // the HTTP response headers
- Body *bytes.Buffer // if non-nil, the bytes.Buffer to append written data to
- Flushed bool
+ // Code is the HTTP response code set by WriteHeader.
+ //
+ // Note that if a Handler never calls WriteHeader or Write,
+ // this might end up being 0, rather than the implicit
+ // http.StatusOK. To get the implicit value, use the Result
+ // method.
+ Code int
+
+ // HeaderMap contains the headers explicitly set by the Handler.
+ //
+ // To get the implicit headers set by the server (such as
+ // automatic Content-Type), use the Result method.
+ HeaderMap http.Header
+
+ // Body is the buffer to which the Handler's Write calls are sent.
+ // If nil, the Writes are silently discarded.
+ Body *bytes.Buffer
+
+ // Flushed is whether the Handler called Flush.
+ Flushed bool
result *http.Response // cache of Result's return value
snapHeader http.Header // snapshot of HeaderMap at first Write
@@ -136,6 +154,9 @@ func (rw *ResponseRecorder) Flush() {
// first write call, or at the time of this call, if the handler never
// did a write.
//
+// The Response.Body is guaranteed to be non-nil and Body.Read call is
+// guaranteed to not return any error other than io.EOF.
+//
// Result must only be called after the handler has finished running.
func (rw *ResponseRecorder) Result() *http.Response {
if rw.result != nil {
@@ -159,6 +180,7 @@ func (rw *ResponseRecorder) Result() *http.Response {
if rw.Body != nil {
res.Body = ioutil.NopCloser(bytes.NewReader(rw.Body.Bytes()))
}
+ res.ContentLength = parseContentLength(res.Header.Get("Content-Length"))
if trailers, ok := rw.snapHeader["Trailer"]; ok {
res.Trailer = make(http.Header, len(trailers))
@@ -181,5 +203,33 @@ func (rw *ResponseRecorder) Result() *http.Response {
res.Trailer[k] = vv2
}
}
+ for k, vv := range rw.HeaderMap {
+ if !strings.HasPrefix(k, http.TrailerPrefix) {
+ continue
+ }
+ if res.Trailer == nil {
+ res.Trailer = make(http.Header)
+ }
+ for _, v := range vv {
+ res.Trailer.Add(strings.TrimPrefix(k, http.TrailerPrefix), v)
+ }
+ }
return res
}
+
+// parseContentLength trims whitespace from s and returns -1 if no value
+// is set, or the value if it's >= 0.
+//
+// This a modified version of same function found in net/http/transfer.go. This
+// one just ignores an invalid header.
+func parseContentLength(cl string) int64 {
+ cl = strings.TrimSpace(cl)
+ if cl == "" {
+ return -1
+ }
+ n, err := strconv.ParseInt(cl, 10, 64)
+ if err != nil {
+ return -1
+ }
+ return n
+}
diff --git a/src/net/http/httptest/recorder_test.go b/src/net/http/httptest/recorder_test.go
index d4e7137..9afba4e 100644
--- a/src/net/http/httptest/recorder_test.go
+++ b/src/net/http/httptest/recorder_test.go
@@ -94,6 +94,14 @@ func TestRecorder(t *testing.T) {
return nil
}
}
+ hasContentLength := func(length int64) checkFunc {
+ return func(rec *ResponseRecorder) error {
+ if got := rec.Result().ContentLength; got != length {
+ return fmt.Errorf("ContentLength = %d; want %d", got, length)
+ }
+ return nil
+ }
+ }
tests := []struct {
name string
@@ -141,7 +149,7 @@ func TestRecorder(t *testing.T) {
w.(http.Flusher).Flush() // also sends a 200
w.WriteHeader(201)
},
- check(hasStatus(200), hasFlush(true)),
+ check(hasStatus(200), hasFlush(true), hasContentLength(-1)),
},
{
"Content-Type detection",
@@ -199,6 +207,7 @@ func TestRecorder(t *testing.T) {
w.Header().Set("Trailer-A", "valuea")
w.Header().Set("Trailer-C", "valuec")
w.Header().Set("Trailer-NotDeclared", "should be omitted")
+ w.Header().Set("Trailer:Trailer-D", "with prefix")
},
check(
hasStatus(200),
@@ -208,6 +217,7 @@ func TestRecorder(t *testing.T) {
hasTrailer("Trailer-A", "valuea"),
hasTrailer("Trailer-C", "valuec"),
hasNotTrailers("Non-Trailer", "Trailer-B", "Trailer-NotDeclared"),
+ hasTrailer("Trailer-D", "with prefix"),
),
},
{
@@ -244,6 +254,16 @@ func TestRecorder(t *testing.T) {
hasNotHeaders("X-Bar"),
),
},
+ {
+ "setting Content-Length header",
+ func(w http.ResponseWriter, r *http.Request) {
+ body := "Some body"
+ contentLength := fmt.Sprintf("%d", len(body))
+ w.Header().Set("Content-Length", contentLength)
+ io.WriteString(w, body)
+ },
+ check(hasStatus(200), hasContents("Some body"), hasContentLength(9)),
+ },
}
r, _ := http.NewRequest("GET", "http://foo.com/", nil)
for _, tt := range tests {
diff --git a/src/net/http/httptest/server.go b/src/net/http/httptest/server.go
index 8608077..7118214 100644
--- a/src/net/http/httptest/server.go
+++ b/src/net/http/httptest/server.go
@@ -16,7 +16,6 @@ import (
"net/http"
"net/http/internal"
"os"
- "runtime"
"sync"
"time"
)
@@ -114,9 +113,10 @@ func (s *Server) StartTLS() {
}
existingConfig := s.TLS
- s.TLS = new(tls.Config)
if existingConfig != nil {
- *s.TLS = *existingConfig
+ s.TLS = existingConfig.Clone()
+ } else {
+ s.TLS = new(tls.Config)
}
if s.TLS.NextProtos == nil {
s.TLS.NextProtos = []string{"http/1.1"}
@@ -293,15 +293,6 @@ func (s *Server) closeConn(c net.Conn) { s.closeConnChan(c, nil) }
// closeConnChan is like closeConn, but takes an optional channel to receive a value
// when the goroutine closing c is done.
func (s *Server) closeConnChan(c net.Conn, done chan<- struct{}) {
- if runtime.GOOS == "plan9" {
- // Go's Plan 9 net package isn't great at unblocking reads when
- // their underlying TCP connections are closed. Don't trust
- // that that the ConnState state machine will get to
- // StateClosed. Instead, just go there directly. Plan 9 may leak
- // resources if the syscall doesn't end up returning. Oh well.
- s.forgetConn(c)
- }
-
c.Close()
if done != nil {
done <- struct{}{}
diff --git a/src/net/http/httptrace/example_test.go b/src/net/http/httptrace/example_test.go
new file mode 100644
index 0000000..07fdc0a
--- /dev/null
+++ b/src/net/http/httptrace/example_test.go
@@ -0,0 +1,29 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package httptrace_test
+
+import (
+ "fmt"
+ "log"
+ "net/http"
+ "net/http/httptrace"
+)
+
+func Example() {
+ req, _ := http.NewRequest("GET", "http://example.com", nil)
+ trace := &httptrace.ClientTrace{
+ GotConn: func(connInfo httptrace.GotConnInfo) {
+ fmt.Printf("Got Conn: %+v\n", connInfo)
+ },
+ DNSDone: func(dnsInfo httptrace.DNSDoneInfo) {
+ fmt.Printf("DNS Info: %+v\n", dnsInfo)
+ },
+ }
+ req = req.WithContext(httptrace.WithClientTrace(req.Context(), trace))
+ _, err := http.DefaultTransport.RoundTrip(req)
+ if err != nil {
+ log.Fatal(err)
+ }
+}
diff --git a/src/net/http/httptrace/trace.go b/src/net/http/httptrace/trace.go
index 6f187a7..3b74179 100644
--- a/src/net/http/httptrace/trace.go
+++ b/src/net/http/httptrace/trace.go
@@ -1,6 +1,6 @@
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.h
+// license that can be found in the LICENSE file.
// Package httptrace provides mechanisms to trace the events within
// HTTP client requests.
@@ -8,6 +8,7 @@ package httptrace
import (
"context"
+ "crypto/tls"
"internal/nettrace"
"net"
"reflect"
@@ -65,11 +66,16 @@ func WithClientTrace(ctx context.Context, trace *ClientTrace) context.Context {
return ctx
}
-// ClientTrace is a set of hooks to run at various stages of an HTTP
-// client request. Any particular hook may be nil. Functions may be
-// called concurrently from different goroutines, starting after the
-// call to Transport.RoundTrip and ending either when RoundTrip
-// returns an error, or when the Response.Body is closed.
+// ClientTrace is a set of hooks to run at various stages of an outgoing
+// HTTP request. Any particular hook may be nil. Functions may be
+// called concurrently from different goroutines and some may be called
+// after the request has completed or failed.
+//
+// ClientTrace currently traces a single HTTP request & response
+// during a single round trip and has no hooks that span a series
+// of redirected requests.
+//
+// See https://blog.golang.org/http-tracing for more.
type ClientTrace struct {
// GetConn is called before a connection is created or
// retrieved from an idle pool. The hostPort is the
@@ -119,6 +125,16 @@ type ClientTrace struct {
// enabled, this may be called multiple times.
ConnectDone func(network, addr string, err error)
+ // TLSHandshakeStart is called when the TLS handshake is started. When
+ // connecting to a HTTPS site via a HTTP proxy, the handshake happens after
+ // the CONNECT request is processed by the proxy.
+ TLSHandshakeStart func()
+
+ // TLSHandshakeDone is called after the TLS handshake with either the
+ // successful handshake's connection state, or a non-nil error on handshake
+ // failure.
+ TLSHandshakeDone func(tls.ConnectionState, error)
+
// WroteHeaders is called after the Transport has written
// the request headers.
WroteHeaders func()
diff --git a/src/net/http/httptrace/trace_test.go b/src/net/http/httptrace/trace_test.go
index c7eaed8..bb57ada 100644
--- a/src/net/http/httptrace/trace_test.go
+++ b/src/net/http/httptrace/trace_test.go
@@ -1,14 +1,41 @@
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.h
+// license that can be found in the LICENSE file.
package httptrace
import (
"bytes"
+ "context"
"testing"
)
+func TestWithClientTrace(t *testing.T) {
+ var buf bytes.Buffer
+ connectStart := func(b byte) func(network, addr string) {
+ return func(network, addr string) {
+ buf.WriteByte(b)
+ }
+ }
+
+ ctx := context.Background()
+ oldtrace := &ClientTrace{
+ ConnectStart: connectStart('O'),
+ }
+ ctx = WithClientTrace(ctx, oldtrace)
+ newtrace := &ClientTrace{
+ ConnectStart: connectStart('N'),
+ }
+ ctx = WithClientTrace(ctx, newtrace)
+ trace := ContextClientTrace(ctx)
+
+ buf.Reset()
+ trace.ConnectStart("net", "addr")
+ if got, want := buf.String(), "NO"; got != want {
+ t.Errorf("got %q; want %q", got, want)
+ }
+}
+
func TestCompose(t *testing.T) {
var buf bytes.Buffer
var testNum int
diff --git a/src/net/http/httputil/persist.go b/src/net/http/httputil/persist.go
index 87ddd52..cbedf25 100644
--- a/src/net/http/httputil/persist.go
+++ b/src/net/http/httputil/persist.go
@@ -15,9 +15,14 @@ import (
)
var (
+ // Deprecated: No longer used.
ErrPersistEOF = &http.ProtocolError{ErrorString: "persistent connection closed"}
- ErrClosed = &http.ProtocolError{ErrorString: "connection closed by user"}
- ErrPipeline = &http.ProtocolError{ErrorString: "pipeline error"}
+
+ // Deprecated: No longer used.
+ ErrClosed = &http.ProtocolError{ErrorString: "connection closed by user"}
+
+ // Deprecated: No longer used.
+ ErrPipeline = &http.ProtocolError{ErrorString: "pipeline error"}
)
// This is an API usage error - the local side is closed.
diff --git a/src/net/http/httputil/reverseproxy.go b/src/net/http/httputil/reverseproxy.go
index 49c120a..7867505 100644
--- a/src/net/http/httputil/reverseproxy.go
+++ b/src/net/http/httputil/reverseproxy.go
@@ -7,6 +7,7 @@
package httputil
import (
+ "context"
"io"
"log"
"net"
@@ -51,6 +52,11 @@ type ReverseProxy struct {
// get byte slices for use by io.CopyBuffer when
// copying HTTP response bodies.
BufferPool BufferPool
+
+ // ModifyResponse is an optional function that
+ // modifies the Response from the backend.
+ // If it returns an error, the proxy returns a StatusBadGateway error.
+ ModifyResponse func(*http.Response) error
}
// A BufferPool is an interface for getting and returning temporary
@@ -120,76 +126,59 @@ var hopHeaders = []string{
"Upgrade",
}
-type requestCanceler interface {
- CancelRequest(*http.Request)
-}
-
-type runOnFirstRead struct {
- io.Reader // optional; nil means empty body
-
- fn func() // Run before first Read, then set to nil
-}
-
-func (c *runOnFirstRead) Read(bs []byte) (int, error) {
- if c.fn != nil {
- c.fn()
- c.fn = nil
- }
- if c.Reader == nil {
- return 0, io.EOF
- }
- return c.Reader.Read(bs)
-}
-
func (p *ReverseProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
transport := p.Transport
if transport == nil {
transport = http.DefaultTransport
}
+ ctx := req.Context()
+ if cn, ok := rw.(http.CloseNotifier); ok {
+ var cancel context.CancelFunc
+ ctx, cancel = context.WithCancel(ctx)
+ defer cancel()
+ notifyChan := cn.CloseNotify()
+ go func() {
+ select {
+ case <-notifyChan:
+ cancel()
+ case <-ctx.Done():
+ }
+ }()
+ }
+
outreq := new(http.Request)
*outreq = *req // includes shallow copies of maps, but okay
-
- if closeNotifier, ok := rw.(http.CloseNotifier); ok {
- if requestCanceler, ok := transport.(requestCanceler); ok {
- reqDone := make(chan struct{})
- defer close(reqDone)
-
- clientGone := closeNotifier.CloseNotify()
-
- outreq.Body = struct {
- io.Reader
- io.Closer
- }{
- Reader: &runOnFirstRead{
- Reader: outreq.Body,
- fn: func() {
- go func() {
- select {
- case <-clientGone:
- requestCanceler.CancelRequest(outreq)
- case <-reqDone:
- }
- }()
- },
- },
- Closer: outreq.Body,
- }
- }
+ if req.ContentLength == 0 {
+ outreq.Body = nil // Issue 16036: nil Body for http.Transport retries
}
+ outreq = outreq.WithContext(ctx)
p.Director(outreq)
- outreq.Proto = "HTTP/1.1"
- outreq.ProtoMajor = 1
- outreq.ProtoMinor = 1
outreq.Close = false
- // Remove hop-by-hop headers to the backend. Especially
- // important is "Connection" because we want a persistent
- // connection, regardless of what the client sent to us. This
- // is modifying the same underlying map from req (shallow
+ // We are modifying the same underlying map from req (shallow
// copied above) so we only copy it if necessary.
copiedHeaders := false
+
+ // Remove hop-by-hop headers listed in the "Connection" header.
+ // See RFC 2616, section 14.10.
+ if c := outreq.Header.Get("Connection"); c != "" {
+ for _, f := range strings.Split(c, ",") {
+ if f = strings.TrimSpace(f); f != "" {
+ if !copiedHeaders {
+ outreq.Header = make(http.Header)
+ copyHeader(outreq.Header, req.Header)
+ copiedHeaders = true
+ }
+ outreq.Header.Del(f)
+ }
+ }
+ }
+
+ // Remove hop-by-hop headers to the backend. Especially
+ // important is "Connection" because we want a persistent
+ // connection, regardless of what the client sent to us.
for _, h := range hopHeaders {
if outreq.Header.Get(h) != "" {
if !copiedHeaders {
@@ -218,16 +207,34 @@ func (p *ReverseProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
return
}
+ // Remove hop-by-hop headers listed in the
+ // "Connection" header of the response.
+ if c := res.Header.Get("Connection"); c != "" {
+ for _, f := range strings.Split(c, ",") {
+ if f = strings.TrimSpace(f); f != "" {
+ res.Header.Del(f)
+ }
+ }
+ }
+
for _, h := range hopHeaders {
res.Header.Del(h)
}
+ if p.ModifyResponse != nil {
+ if err := p.ModifyResponse(res); err != nil {
+ p.logf("http: proxy error: %v", err)
+ rw.WriteHeader(http.StatusBadGateway)
+ return
+ }
+ }
+
copyHeader(rw.Header(), res.Header)
// The "Trailer" header isn't included in the Transport's response,
// at least for *http.Transport. Build it up from Trailer.
if len(res.Trailer) > 0 {
- var trailerKeys []string
+ trailerKeys := make([]string, 0, len(res.Trailer))
for k := range res.Trailer {
trailerKeys = append(trailerKeys, k)
}
@@ -266,12 +273,40 @@ func (p *ReverseProxy) copyResponse(dst io.Writer, src io.Reader) {
if p.BufferPool != nil {
buf = p.BufferPool.Get()
}
- io.CopyBuffer(dst, src, buf)
+ p.copyBuffer(dst, src, buf)
if p.BufferPool != nil {
p.BufferPool.Put(buf)
}
}
+func (p *ReverseProxy) copyBuffer(dst io.Writer, src io.Reader, buf []byte) (int64, error) {
+ if len(buf) == 0 {
+ buf = make([]byte, 32*1024)
+ }
+ var written int64
+ for {
+ nr, rerr := src.Read(buf)
+ if rerr != nil && rerr != io.EOF {
+ p.logf("httputil: ReverseProxy read error during body copy: %v", rerr)
+ }
+ if nr > 0 {
+ nw, werr := dst.Write(buf[:nr])
+ if nw > 0 {
+ written += int64(nw)
+ }
+ if werr != nil {
+ return written, werr
+ }
+ if nr != nw {
+ return written, io.ErrShortWrite
+ }
+ }
+ if rerr != nil {
+ return written, rerr
+ }
+ }
+}
+
func (p *ReverseProxy) logf(format string, args ...interface{}) {
if p.ErrorLog != nil {
p.ErrorLog.Printf(format, args...)
diff --git a/src/net/http/httputil/reverseproxy_test.go b/src/net/http/httputil/reverseproxy_test.go
index fe7cdb8..20c4e16 100644
--- a/src/net/http/httputil/reverseproxy_test.go
+++ b/src/net/http/httputil/reverseproxy_test.go
@@ -9,6 +9,8 @@ package httputil
import (
"bufio"
"bytes"
+ "errors"
+ "fmt"
"io"
"io/ioutil"
"log"
@@ -135,6 +137,61 @@ func TestReverseProxy(t *testing.T) {
}
+// Issue 16875: remove any proxied headers mentioned in the "Connection"
+// header value.
+func TestReverseProxyStripHeadersPresentInConnection(t *testing.T) {
+ const fakeConnectionToken = "X-Fake-Connection-Token"
+ const backendResponse = "I am the backend"
+ backend := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ if c := r.Header.Get(fakeConnectionToken); c != "" {
+ t.Errorf("handler got header %q = %q; want empty", fakeConnectionToken, c)
+ }
+ if c := r.Header.Get("Upgrade"); c != "" {
+ t.Errorf("handler got header %q = %q; want empty", "Upgrade", c)
+ }
+ w.Header().Set("Connection", "Upgrade, "+fakeConnectionToken)
+ w.Header().Set("Upgrade", "should be deleted")
+ w.Header().Set(fakeConnectionToken, "should be deleted")
+ io.WriteString(w, backendResponse)
+ }))
+ defer backend.Close()
+ backendURL, err := url.Parse(backend.URL)
+ if err != nil {
+ t.Fatal(err)
+ }
+ proxyHandler := NewSingleHostReverseProxy(backendURL)
+ frontend := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ proxyHandler.ServeHTTP(w, r)
+ if c := r.Header.Get("Upgrade"); c != "original value" {
+ t.Errorf("handler modified header %q = %q; want %q", "Upgrade", c, "original value")
+ }
+ }))
+ defer frontend.Close()
+
+ getReq, _ := http.NewRequest("GET", frontend.URL, nil)
+ 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)
+ if err != nil {
+ t.Fatalf("Get: %v", err)
+ }
+ defer res.Body.Close()
+ bodyBytes, err := ioutil.ReadAll(res.Body)
+ if err != nil {
+ t.Fatalf("reading body: %v", err)
+ }
+ if got, want := string(bodyBytes), backendResponse; got != want {
+ t.Errorf("got body %q; want %q", got, want)
+ }
+ if c := res.Header.Get("Upgrade"); c != "" {
+ t.Errorf("handler got header %q = %q; want empty", "Upgrade", c)
+ }
+ if c := res.Header.Get(fakeConnectionToken); c != "" {
+ t.Errorf("handler got header %q = %q; want empty", fakeConnectionToken, c)
+ }
+}
+
func TestXForwardedFor(t *testing.T) {
const prevForwardedFor = "client ip"
const backendResponse = "I am the backend"
@@ -260,14 +317,14 @@ func TestReverseProxyCancelation(t *testing.T) {
reqInFlight := make(chan struct{})
backend := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- close(reqInFlight)
+ close(reqInFlight) // cause the client to cancel its request
select {
case <-time.After(10 * time.Second):
// Note: this should only happen in broken implementations, and the
// closenotify case should be instantaneous.
- t.Log("Failed to close backend connection")
- t.Fail()
+ t.Error("Handler never saw CloseNotify")
+ return
case <-w.(http.CloseNotifier).CloseNotify():
}
@@ -300,13 +357,13 @@ func TestReverseProxyCancelation(t *testing.T) {
}()
res, err := http.DefaultClient.Do(getReq)
if res != nil {
- t.Fatal("Non-nil response")
+ t.Errorf("got response %v; want nil", res.Status)
}
if err == nil {
// This should be an error like:
// Get http://127.0.0.1:58079: read tcp 127.0.0.1:58079:
// use of closed network connection
- t.Fatal("DefaultClient.Do() returned nil error")
+ t.Error("DefaultClient.Do() returned nil error; want non-nil error")
}
}
@@ -495,3 +552,115 @@ func TestReverseProxy_Post(t *testing.T) {
t.Errorf("got body %q; expected %q", g, e)
}
}
+
+type RoundTripperFunc func(*http.Request) (*http.Response, error)
+
+func (fn RoundTripperFunc) RoundTrip(req *http.Request) (*http.Response, error) {
+ return fn(req)
+}
+
+// Issue 16036: send a Request with a nil Body when possible
+func TestReverseProxy_NilBody(t *testing.T) {
+ backendURL, _ := url.Parse("http://fake.tld/")
+ proxyHandler := NewSingleHostReverseProxy(backendURL)
+ proxyHandler.ErrorLog = log.New(ioutil.Discard, "", 0) // quiet for tests
+ proxyHandler.Transport = RoundTripperFunc(func(req *http.Request) (*http.Response, error) {
+ if req.Body != nil {
+ t.Error("Body != nil; want a nil Body")
+ }
+ return nil, errors.New("done testing the interesting part; so force a 502 Gateway error")
+ })
+ frontend := httptest.NewServer(proxyHandler)
+ defer frontend.Close()
+
+ res, err := http.DefaultClient.Get(frontend.URL)
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer res.Body.Close()
+ if res.StatusCode != 502 {
+ t.Errorf("status code = %v; want 502 (Gateway Error)", res.Status)
+ }
+}
+
+// Issue 14237. Test ModifyResponse and that an error from it
+// causes the proxy to return StatusBadGateway, or StatusOK otherwise.
+func TestReverseProxyModifyResponse(t *testing.T) {
+ backendServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ w.Header().Add("X-Hit-Mod", fmt.Sprintf("%v", r.URL.Path == "/mod"))
+ }))
+ defer backendServer.Close()
+
+ rpURL, _ := url.Parse(backendServer.URL)
+ rproxy := NewSingleHostReverseProxy(rpURL)
+ rproxy.ErrorLog = log.New(ioutil.Discard, "", 0) // quiet for tests
+ rproxy.ModifyResponse = func(resp *http.Response) error {
+ if resp.Header.Get("X-Hit-Mod") != "true" {
+ return fmt.Errorf("tried to by-pass proxy")
+ }
+ return nil
+ }
+
+ frontendProxy := httptest.NewServer(rproxy)
+ defer frontendProxy.Close()
+
+ tests := []struct {
+ url string
+ wantCode int
+ }{
+ {frontendProxy.URL + "/mod", http.StatusOK},
+ {frontendProxy.URL + "/schedule", http.StatusBadGateway},
+ }
+
+ for i, tt := range tests {
+ resp, err := http.Get(tt.url)
+ if err != nil {
+ t.Fatalf("failed to reach proxy: %v", err)
+ }
+ if g, e := resp.StatusCode, tt.wantCode; g != e {
+ t.Errorf("#%d: got res.StatusCode %d; expected %d", i, g, e)
+ }
+ resp.Body.Close()
+ }
+}
+
+// Issue 16659: log errors from short read
+func TestReverseProxy_CopyBuffer(t *testing.T) {
+ backendServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ out := "this call was relayed by the reverse proxy"
+ // Coerce a wrong content length to induce io.UnexpectedEOF
+ w.Header().Set("Content-Length", fmt.Sprintf("%d", len(out)*2))
+ fmt.Fprintln(w, out)
+ }))
+ defer backendServer.Close()
+
+ rpURL, err := url.Parse(backendServer.URL)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ var proxyLog bytes.Buffer
+ rproxy := NewSingleHostReverseProxy(rpURL)
+ rproxy.ErrorLog = log.New(&proxyLog, "", log.Lshortfile)
+ frontendProxy := httptest.NewServer(rproxy)
+ defer frontendProxy.Close()
+
+ resp, err := http.Get(frontendProxy.URL)
+ if err != nil {
+ t.Fatalf("failed to reach proxy: %v", err)
+ }
+ defer resp.Body.Close()
+
+ if _, err := ioutil.ReadAll(resp.Body); err == nil {
+ t.Fatalf("want non-nil error")
+ }
+ expected := []string{
+ "EOF",
+ "read",
+ }
+ for _, phrase := range expected {
+ if !bytes.Contains(proxyLog.Bytes(), []byte(phrase)) {
+ t.Errorf("expected log to contain phrase %q", phrase)
+ }
+ }
+}
diff --git a/src/net/http/internal/chunked.go b/src/net/http/internal/chunked.go
index 2e62c00..63f321d 100644
--- a/src/net/http/internal/chunked.go
+++ b/src/net/http/internal/chunked.go
@@ -35,10 +35,11 @@ func NewChunkedReader(r io.Reader) io.Reader {
}
type chunkedReader struct {
- r *bufio.Reader
- n uint64 // unread bytes in chunk
- err error
- buf [2]byte
+ r *bufio.Reader
+ n uint64 // unread bytes in chunk
+ err error
+ buf [2]byte
+ checkEnd bool // whether need to check for \r\n chunk footer
}
func (cr *chunkedReader) beginChunk() {
@@ -68,6 +69,21 @@ func (cr *chunkedReader) chunkHeaderAvailable() bool {
func (cr *chunkedReader) Read(b []uint8) (n int, err error) {
for cr.err == nil {
+ if cr.checkEnd {
+ if n > 0 && cr.r.Buffered() < 2 {
+ // We have some data. Return early (per the io.Reader
+ // contract) instead of potentially blocking while
+ // reading more.
+ break
+ }
+ if _, cr.err = io.ReadFull(cr.r, cr.buf[:2]); cr.err == nil {
+ if string(cr.buf[:]) != "\r\n" {
+ cr.err = errors.New("malformed chunked encoding")
+ break
+ }
+ }
+ cr.checkEnd = false
+ }
if cr.n == 0 {
if n > 0 && !cr.chunkHeaderAvailable() {
// We've read enough. Don't potentially block
@@ -92,11 +108,7 @@ func (cr *chunkedReader) Read(b []uint8) (n int, err error) {
// If we're at the end of a chunk, read the next two
// bytes to verify they are "\r\n".
if cr.n == 0 && cr.err == nil {
- if _, cr.err = io.ReadFull(cr.r, cr.buf[:2]); cr.err == nil {
- if cr.buf[0] != '\r' || cr.buf[1] != '\n' {
- cr.err = errors.New("malformed chunked encoding")
- }
- }
+ cr.checkEnd = true
}
}
return n, cr.err
diff --git a/src/net/http/internal/chunked_test.go b/src/net/http/internal/chunked_test.go
index 9abe1ab..d067165 100644
--- a/src/net/http/internal/chunked_test.go
+++ b/src/net/http/internal/chunked_test.go
@@ -185,3 +185,30 @@ func TestChunkReadingIgnoresExtensions(t *testing.T) {
t.Errorf("read %q; want %q", g, e)
}
}
+
+// Issue 17355: ChunkedReader shouldn't block waiting for more data
+// if it can return something.
+func TestChunkReadPartial(t *testing.T) {
+ pr, pw := io.Pipe()
+ go func() {
+ pw.Write([]byte("7\r\n1234567"))
+ }()
+ cr := NewChunkedReader(pr)
+ readBuf := make([]byte, 7)
+ n, err := cr.Read(readBuf)
+ if err != nil {
+ t.Fatal(err)
+ }
+ want := "1234567"
+ if n != 7 || string(readBuf) != want {
+ t.Fatalf("Read: %v %q; want %d, %q", n, readBuf[:n], len(want), want)
+ }
+ go func() {
+ pw.Write([]byte("xx"))
+ }()
+ _, err = cr.Read(readBuf)
+ if got := fmt.Sprint(err); !strings.Contains(got, "malformed") {
+ t.Fatalf("second read = %v; want malformed error", err)
+ }
+
+}
diff --git a/src/net/http/main_test.go b/src/net/http/main_test.go
index aea6e12..438bd2e 100644
--- a/src/net/http/main_test.go
+++ b/src/net/http/main_test.go
@@ -6,6 +6,8 @@ package http_test
import (
"fmt"
+ "io/ioutil"
+ "log"
"net/http"
"os"
"runtime"
@@ -15,6 +17,8 @@ import (
"time"
)
+var quietLog = log.New(ioutil.Discard, "", 0)
+
func TestMain(m *testing.M) {
v := m.Run()
if v == 0 && goroutineLeaked() {
@@ -134,3 +138,20 @@ func waitCondition(waitFor, checkEvery time.Duration, fn func() bool) bool {
}
return false
}
+
+// waitErrCondition is like waitCondition but with errors instead of bools.
+func waitErrCondition(waitFor, checkEvery time.Duration, fn func() error) error {
+ deadline := time.Now().Add(waitFor)
+ var err error
+ for time.Now().Before(deadline) {
+ if err = fn(); err == nil {
+ return nil
+ }
+ time.Sleep(checkEvery)
+ }
+ 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 e2e911d..4c1f6b5 100644
--- a/src/net/http/npn_test.go
+++ b/src/net/http/npn_test.go
@@ -18,6 +18,7 @@ import (
)
func TestNextProtoUpgrade(t *testing.T) {
+ setParallel(t)
defer afterTest(t)
ts := httptest.NewUnstartedServer(HandlerFunc(func(w ResponseWriter, r *Request) {
fmt.Fprintf(w, "path=%s,proto=", r.URL.Path)
diff --git a/src/net/http/range_test.go b/src/net/http/range_test.go
index ef911af..114987e 100644
--- a/src/net/http/range_test.go
+++ b/src/net/http/range_test.go
@@ -38,7 +38,7 @@ var ParseRangeTests = []struct {
{"bytes=0-", 10, []httpRange{{0, 10}}},
{"bytes=5-", 10, []httpRange{{5, 5}}},
{"bytes=0-20", 10, []httpRange{{0, 10}}},
- {"bytes=15-,0-5", 10, nil},
+ {"bytes=15-,0-5", 10, []httpRange{{0, 6}}},
{"bytes=1-2,5-", 10, []httpRange{{1, 2}, {5, 5}}},
{"bytes=-2 , 7-", 11, []httpRange{{9, 2}, {7, 4}}},
{"bytes=0-0 ,2-2, 7-", 11, []httpRange{{0, 1}, {2, 1}, {7, 4}}},
diff --git a/src/net/http/readrequest_test.go b/src/net/http/readrequest_test.go
index 4bf646b..28a148b 100644
--- a/src/net/http/readrequest_test.go
+++ b/src/net/http/readrequest_test.go
@@ -25,7 +25,7 @@ type reqTest struct {
}
var noError = ""
-var noBody = ""
+var noBodyStr = ""
var noTrailer Header = nil
var reqTests = []reqTest{
@@ -95,7 +95,7 @@ var reqTests = []reqTest{
RequestURI: "/",
},
- noBody,
+ noBodyStr,
noTrailer,
noError,
},
@@ -121,7 +121,7 @@ var reqTests = []reqTest{
RequestURI: "//user at host/is/actually/a/path/",
},
- noBody,
+ noBodyStr,
noTrailer,
noError,
},
@@ -131,7 +131,7 @@ var reqTests = []reqTest{
"GET ../../../../etc/passwd HTTP/1.1\r\n" +
"Host: test\r\n\r\n",
nil,
- noBody,
+ noBodyStr,
noTrailer,
"parse ../../../../etc/passwd: invalid URI for request",
},
@@ -141,7 +141,7 @@ var reqTests = []reqTest{
"GET HTTP/1.1\r\n" +
"Host: test\r\n\r\n",
nil,
- noBody,
+ noBodyStr,
noTrailer,
"parse : empty url",
},
@@ -227,7 +227,7 @@ var reqTests = []reqTest{
RequestURI: "www.google.com:443",
},
- noBody,
+ noBodyStr,
noTrailer,
noError,
},
@@ -251,7 +251,7 @@ var reqTests = []reqTest{
RequestURI: "127.0.0.1:6060",
},
- noBody,
+ noBodyStr,
noTrailer,
noError,
},
@@ -275,7 +275,7 @@ var reqTests = []reqTest{
RequestURI: "/_goRPC_",
},
- noBody,
+ noBodyStr,
noTrailer,
noError,
},
@@ -299,7 +299,7 @@ var reqTests = []reqTest{
RequestURI: "*",
},
- noBody,
+ noBodyStr,
noTrailer,
noError,
},
@@ -323,7 +323,7 @@ var reqTests = []reqTest{
RequestURI: "*",
},
- noBody,
+ noBodyStr,
noTrailer,
noError,
},
@@ -350,7 +350,7 @@ var reqTests = []reqTest{
RequestURI: "/",
},
- noBody,
+ noBodyStr,
noTrailer,
noError,
},
@@ -376,7 +376,7 @@ var reqTests = []reqTest{
RequestURI: "/",
},
- noBody,
+ noBodyStr,
noTrailer,
noError,
},
@@ -397,7 +397,7 @@ var reqTests = []reqTest{
ContentLength: -1,
Close: true,
},
- noBody,
+ noBodyStr,
noTrailer,
noError,
},
diff --git a/src/net/http/request.go b/src/net/http/request.go
index dc55592..fd9ea54 100644
--- a/src/net/http/request.go
+++ b/src/net/http/request.go
@@ -18,12 +18,17 @@ import (
"io/ioutil"
"mime"
"mime/multipart"
+ "net"
"net/http/httptrace"
"net/textproto"
"net/url"
"strconv"
"strings"
"sync"
+
+ "golang_org/x/net/idna"
+ "golang_org/x/text/unicode/norm"
+ "golang_org/x/text/width"
)
const (
@@ -34,21 +39,40 @@ const (
// is either not present in the request or not a file field.
var ErrMissingFile = errors.New("http: no such file")
-// HTTP request parsing errors.
+// ProtocolError represents an HTTP protocol error.
+//
+// Deprecated: Not all errors in the http package related to protocol errors
+// are of type ProtocolError.
type ProtocolError struct {
ErrorString string
}
-func (err *ProtocolError) Error() string { return err.ErrorString }
+func (pe *ProtocolError) Error() string { return pe.ErrorString }
var (
- ErrHeaderTooLong = &ProtocolError{"header too long"}
- ErrShortBody = &ProtocolError{"entity body too short"}
- ErrNotSupported = &ProtocolError{"feature not supported"}
- ErrUnexpectedTrailer = &ProtocolError{"trailer header without chunked transfer encoding"}
+ // ErrNotSupported is returned by the Push method of Pusher
+ // implementations to indicate that HTTP/2 Push support is not
+ // available.
+ ErrNotSupported = &ProtocolError{"feature not supported"}
+
+ // ErrUnexpectedTrailer is returned by the Transport when a server
+ // replies with a Trailer header, but without a chunked reply.
+ ErrUnexpectedTrailer = &ProtocolError{"trailer header without chunked transfer encoding"}
+
+ // ErrMissingBoundary is returned by Request.MultipartReader when the
+ // request's Content-Type does not include a "boundary" parameter.
+ ErrMissingBoundary = &ProtocolError{"no multipart boundary param in Content-Type"}
+
+ // ErrNotMultipart is returned by Request.MultipartReader when the
+ // request's Content-Type is not multipart/form-data.
+ ErrNotMultipart = &ProtocolError{"request Content-Type isn't multipart/form-data"}
+
+ // Deprecated: ErrHeaderTooLong is not used.
+ ErrHeaderTooLong = &ProtocolError{"header too long"}
+ // Deprecated: ErrShortBody is not used.
+ ErrShortBody = &ProtocolError{"entity body too short"}
+ // Deprecated: ErrMissingContentLength is not used.
ErrMissingContentLength = &ProtocolError{"missing ContentLength in HEAD response"}
- ErrNotMultipart = &ProtocolError{"request Content-Type isn't multipart/form-data"}
- ErrMissingBoundary = &ProtocolError{"no multipart boundary param in Content-Type"}
)
type badStringError struct {
@@ -146,11 +170,20 @@ type Request struct {
// Handler does not need to.
Body io.ReadCloser
+ // GetBody defines an optional func to return a new copy of
+ // Body. It used for client requests when a redirect requires
+ // reading the body more than once. Use of GetBody still
+ // requires setting Body.
+ //
+ // For server requests it is unused.
+ GetBody func() (io.ReadCloser, error)
+
// ContentLength records the length of the associated content.
// The value -1 indicates that the length is unknown.
// Values >= 0 indicate that the given number of bytes may
// be read from Body.
- // For client requests, a value of 0 means unknown if Body is not nil.
+ // For client requests, a value of 0 with a non-nil Body is
+ // also treated as unknown.
ContentLength int64
// TransferEncoding lists the transfer encodings from outermost to
@@ -175,11 +208,15 @@ type Request struct {
// For server requests Host specifies the host on which the
// URL is sought. Per RFC 2616, this is either the value of
// the "Host" header or the host name given in the URL itself.
- // It may be of the form "host:port".
+ // It may be of the form "host:port". For international domain
+ // names, Host may be in Punycode or Unicode form. Use
+ // golang.org/x/net/idna to convert it to either format if
+ // needed.
//
// For client requests Host optionally overrides the Host
// header to send. If empty, the Request.Write method uses
- // the value of URL.Host.
+ // the value of URL.Host. Host may contain an international
+ // domain name.
Host string
// Form contains the parsed form data, including both the URL
@@ -319,6 +356,8 @@ var ErrNoCookie = errors.New("http: named cookie not present")
// Cookie returns the named cookie provided in the request or
// ErrNoCookie if not found.
+// If multiple cookies match the given name, only one cookie will
+// be returned.
func (r *Request) Cookie(name string) (*Cookie, error) {
for _, c := range readCookies(r.Header, name) {
return c, nil
@@ -573,7 +612,24 @@ func (req *Request) write(w io.Writer, usingProxy bool, extraHeaders Header, wai
return nil
}
-// cleanHost strips anything after '/' or ' '.
+func idnaASCII(v string) (string, error) {
+ 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)
+}
+
+// cleanHost cleans up the host sent in request's Host header.
+//
+// It both strips anything after '/' or ' ', and puts the value
+// into Punycode form, if necessary.
+//
// Ideally we'd clean the Host header according to the spec:
// https://tools.ietf.org/html/rfc7230#section-5.4 (Host = uri-host [ ":" port ]")
// https://tools.ietf.org/html/rfc7230#section-2.7 (uri-host -> rfc3986's host)
@@ -584,9 +640,21 @@ func (req *Request) write(w io.Writer, usingProxy bool, extraHeaders Header, wai
// first offending character.
func cleanHost(in string) string {
if i := strings.IndexAny(in, " /"); i != -1 {
- return in[:i]
+ in = in[:i]
+ }
+ host, port, err := net.SplitHostPort(in)
+ if err != nil { // input was just a host
+ a, err := idnaASCII(in)
+ if err != nil {
+ return in // garbage in, garbage out
+ }
+ return a
}
- return in
+ a, err := idnaASCII(host)
+ if err != nil {
+ return in // garbage in, garbage out
+ }
+ return net.JoinHostPort(a, port)
}
// removeZone removes IPv6 zone identifier from host.
@@ -658,11 +726,11 @@ func validMethod(method string) bool {
// methods Do, Post, and PostForm, and Transport.RoundTrip.
//
// NewRequest returns a Request suitable for use with Client.Do or
-// Transport.RoundTrip.
-// To create a request for use with testing a Server Handler use either
-// ReadRequest or manually update the Request fields. See the Request
-// type's documentation for the difference between inbound and outbound
-// request fields.
+// Transport.RoundTrip. To create a request for use with testing a
+// Server Handler, either use the NewRequest function in the
+// net/http/httptest package, use ReadRequest, or manually update the
+// Request fields. See the Request type's documentation for the
+// difference between inbound and outbound request fields.
func NewRequest(method, urlStr string, body io.Reader) (*Request, error) {
if method == "" {
// We document that "" means "GET" for Request.Method, and people have
@@ -697,10 +765,39 @@ func NewRequest(method, urlStr string, body io.Reader) (*Request, error) {
switch v := body.(type) {
case *bytes.Buffer:
req.ContentLength = int64(v.Len())
+ buf := v.Bytes()
+ req.GetBody = func() (io.ReadCloser, error) {
+ r := bytes.NewReader(buf)
+ return ioutil.NopCloser(r), nil
+ }
case *bytes.Reader:
req.ContentLength = int64(v.Len())
+ snapshot := *v
+ req.GetBody = func() (io.ReadCloser, error) {
+ r := snapshot
+ return ioutil.NopCloser(&r), nil
+ }
case *strings.Reader:
req.ContentLength = int64(v.Len())
+ snapshot := *v
+ req.GetBody = func() (io.ReadCloser, error) {
+ r := snapshot
+ return ioutil.NopCloser(&r), nil
+ }
+ default:
+ req.ContentLength = -1 // unknown
+ }
+ // For client requests, Request.ContentLength of 0
+ // means either actually 0, or unknown. The only way
+ // to explicitly say that the ContentLength is zero is
+ // to set the Body to nil. But turns out too much code
+ // depends on NewRequest returning a non-nil Body,
+ // so we use a well-known ReadCloser variable instead
+ // and have the http package also treat that sentinel
+ // variable to mean explicitly zero.
+ if req.ContentLength == 0 {
+ req.Body = NoBody
+ req.GetBody = func() (io.ReadCloser, error) { return NoBody, nil }
}
}
@@ -1000,18 +1097,24 @@ func parsePostForm(r *Request) (vs url.Values, err error) {
return
}
-// ParseForm parses the raw query from the URL and updates r.Form.
+// ParseForm populates r.Form and r.PostForm.
+//
+// For all requests, ParseForm parses the raw query from the URL and updates
+// r.Form.
//
-// For POST or PUT requests, it also parses the request body as a form and
-// put the results into both r.PostForm and r.Form.
-// POST and PUT body parameters take precedence over URL query string values
-// in r.Form.
+// For POST, PUT, and PATCH requests, it also parses the request body as a form
+// and puts the results into both r.PostForm and r.Form. Request body parameters
+// take precedence over URL query string values in r.Form.
+//
+// For other HTTP methods, or when the Content-Type is not
+// application/x-www-form-urlencoded, the request Body is not read, and
+// r.PostForm is initialized to a non-nil, empty value.
//
// If the request Body's size has not already been limited by MaxBytesReader,
// the size is capped at 10MB.
//
// ParseMultipartForm calls ParseForm automatically.
-// It is idempotent.
+// ParseForm is idempotent.
func (r *Request) ParseForm() error {
var err error
if r.PostForm == nil {
@@ -1174,3 +1277,15 @@ func (r *Request) isReplayable() bool {
}
return false
}
+
+// outgoingLength reports the Content-Length of this outgoing (Client) request.
+// It maps 0 into -1 (unknown) when the Body is non-nil.
+func (r *Request) outgoingLength() int64 {
+ if r.Body == nil || r.Body == NoBody {
+ return 0
+ }
+ if r.ContentLength != 0 {
+ return r.ContentLength
+ }
+ return -1
+}
diff --git a/src/net/http/request_test.go b/src/net/http/request_test.go
index a4c88c0..3c965c1 100644
--- a/src/net/http/request_test.go
+++ b/src/net/http/request_test.go
@@ -29,9 +29,9 @@ func TestQuery(t *testing.T) {
}
}
-func TestPostQuery(t *testing.T) {
- req, _ := NewRequest("POST", "http://www.google.com/search?q=foo&q=bar&both=x&prio=1&empty=not",
- strings.NewReader("z=post&both=y&prio=2&empty="))
+func TestParseFormQuery(t *testing.T) {
+ req, _ := NewRequest("POST", "http://www.google.com/search?q=foo&q=bar&both=x&prio=1&orphan=nope&empty=not",
+ strings.NewReader("z=post&both=y&prio=2&=nokey&orphan;empty=&"))
req.Header.Set("Content-Type", "application/x-www-form-urlencoded; param=value")
if q := req.FormValue("q"); q != "foo" {
@@ -55,39 +55,30 @@ func TestPostQuery(t *testing.T) {
if prio := req.FormValue("prio"); prio != "2" {
t.Errorf(`req.FormValue("prio") = %q, want "2" (from body)`, prio)
}
- if empty := req.FormValue("empty"); empty != "" {
+ if orphan := req.Form["orphan"]; !reflect.DeepEqual(orphan, []string{"", "nope"}) {
+ t.Errorf(`req.FormValue("orphan") = %q, want "" (from body)`, orphan)
+ }
+ if empty := req.Form["empty"]; !reflect.DeepEqual(empty, []string{"", "not"}) {
t.Errorf(`req.FormValue("empty") = %q, want "" (from body)`, empty)
}
+ if nokey := req.Form[""]; !reflect.DeepEqual(nokey, []string{"nokey"}) {
+ t.Errorf(`req.FormValue("nokey") = %q, want "nokey" (from body)`, nokey)
+ }
}
-func TestPatchQuery(t *testing.T) {
- req, _ := NewRequest("PATCH", "http://www.google.com/search?q=foo&q=bar&both=x&prio=1&empty=not",
- strings.NewReader("z=post&both=y&prio=2&empty="))
- req.Header.Set("Content-Type", "application/x-www-form-urlencoded; param=value")
-
- if q := req.FormValue("q"); q != "foo" {
- t.Errorf(`req.FormValue("q") = %q, want "foo"`, q)
- }
- if z := req.FormValue("z"); z != "post" {
- t.Errorf(`req.FormValue("z") = %q, want "post"`, z)
- }
- if bq, found := req.PostForm["q"]; found {
- t.Errorf(`req.PostForm["q"] = %q, want no entry in map`, bq)
- }
- if bz := req.PostFormValue("z"); bz != "post" {
- t.Errorf(`req.PostFormValue("z") = %q, want "post"`, bz)
- }
- if qs := req.Form["q"]; !reflect.DeepEqual(qs, []string{"foo", "bar"}) {
- t.Errorf(`req.Form["q"] = %q, want ["foo", "bar"]`, qs)
- }
- if both := req.Form["both"]; !reflect.DeepEqual(both, []string{"y", "x"}) {
- t.Errorf(`req.Form["both"] = %q, want ["y", "x"]`, both)
- }
- if prio := req.FormValue("prio"); prio != "2" {
- t.Errorf(`req.FormValue("prio") = %q, want "2" (from body)`, prio)
- }
- if empty := req.FormValue("empty"); empty != "" {
- t.Errorf(`req.FormValue("empty") = %q, want "" (from body)`, empty)
+// Tests that we only parse the form automatically for certain methods.
+func TestParseFormQueryMethods(t *testing.T) {
+ for _, method := range []string{"POST", "PATCH", "PUT", "FOO"} {
+ req, _ := NewRequest(method, "http://www.google.com/search",
+ strings.NewReader("foo=bar"))
+ req.Header.Set("Content-Type", "application/x-www-form-urlencoded; param=value")
+ want := "bar"
+ if method == "FOO" {
+ want = ""
+ }
+ if got := req.FormValue("foo"); got != want {
+ t.Errorf(`for method %s, FormValue("foo") = %q; want %q`, method, got, want)
+ }
}
}
@@ -374,18 +365,68 @@ func TestFormFileOrder(t *testing.T) {
var readRequestErrorTests = []struct {
in string
- err error
+ err string
+
+ header Header
}{
- {"GET / HTTP/1.1\r\nheader:foo\r\n\r\n", nil},
- {"GET / HTTP/1.1\r\nheader:foo\r\n", io.ErrUnexpectedEOF},
- {"", io.EOF},
+ 0: {"GET / HTTP/1.1\r\nheader:foo\r\n\r\n", "", Header{"Header": {"foo"}}},
+ 1: {"GET / HTTP/1.1\r\nheader:foo\r\n", io.ErrUnexpectedEOF.Error(), nil},
+ 2: {"", io.EOF.Error(), nil},
+ 3: {
+ in: "HEAD / HTTP/1.1\r\nContent-Length:4\r\n\r\n",
+ err: "http: method cannot contain a Content-Length",
+ },
+ 4: {
+ in: "HEAD / HTTP/1.1\r\n\r\n",
+ header: Header{},
+ },
+
+ // Multiple Content-Length values should either be
+ // deduplicated if same or reject otherwise
+ // See Issue 16490.
+ 5: {
+ in: "POST / HTTP/1.1\r\nContent-Length: 10\r\nContent-Length: 0\r\n\r\nGopher hey\r\n",
+ err: "cannot contain multiple Content-Length headers",
+ },
+ 6: {
+ in: "POST / HTTP/1.1\r\nContent-Length: 10\r\nContent-Length: 6\r\n\r\nGopher\r\n",
+ err: "cannot contain multiple Content-Length headers",
+ },
+ 7: {
+ in: "PUT / HTTP/1.1\r\nContent-Length: 6 \r\nContent-Length: 6\r\nContent-Length:6\r\n\r\nGopher\r\n",
+ err: "",
+ header: Header{"Content-Length": {"6"}},
+ },
+ 8: {
+ in: "PUT / HTTP/1.1\r\nContent-Length: 1\r\nContent-Length: 6 \r\n\r\n",
+ err: "cannot contain multiple Content-Length headers",
+ },
+ 9: {
+ in: "POST / HTTP/1.1\r\nContent-Length:\r\nContent-Length: 3\r\n\r\n",
+ err: "cannot contain multiple Content-Length headers",
+ },
+ 10: {
+ in: "HEAD / HTTP/1.1\r\nContent-Length:0\r\nContent-Length: 0\r\n\r\n",
+ header: Header{"Content-Length": {"0"}},
+ },
}
func TestReadRequestErrors(t *testing.T) {
for i, tt := range readRequestErrorTests {
- _, err := ReadRequest(bufio.NewReader(strings.NewReader(tt.in)))
- if err != tt.err {
- t.Errorf("%d. got error = %v; want %v", i, err, tt.err)
+ req, err := ReadRequest(bufio.NewReader(strings.NewReader(tt.in)))
+ if err == nil {
+ if tt.err != "" {
+ t.Errorf("#%d: got nil err; want %q", i, tt.err)
+ }
+
+ if !reflect.DeepEqual(tt.header, req.Header) {
+ t.Errorf("#%d: gotHeader: %q wantHeader: %q", i, req.Header, tt.header)
+ }
+ continue
+ }
+
+ if tt.err == "" || !strings.Contains(err.Error(), tt.err) {
+ t.Errorf("%d: got error = %v; want %v", i, err, tt.err)
}
}
}
@@ -456,18 +497,22 @@ func TestNewRequestContentLength(t *testing.T) {
{bytes.NewReader([]byte("123")), 3},
{bytes.NewBuffer([]byte("1234")), 4},
{strings.NewReader("12345"), 5},
+ {strings.NewReader(""), 0},
// Not detected:
- {struct{ io.Reader }{strings.NewReader("xyz")}, 0},
- {io.NewSectionReader(strings.NewReader("x"), 0, 6), 0},
- {readByte(io.NewSectionReader(strings.NewReader("xy"), 0, 6)), 0},
+ {struct{ io.Reader }{strings.NewReader("xyz")}, -1},
+ {io.NewSectionReader(strings.NewReader("x"), 0, 6), -1},
+ {readByte(io.NewSectionReader(strings.NewReader("xy"), 0, 6)), -1},
}
- for _, tt := range tests {
+ for i, tt := range tests {
req, err := NewRequest("POST", "http://localhost/", tt.r)
if err != nil {
t.Fatal(err)
}
if req.ContentLength != tt.want {
- t.Errorf("ContentLength(%T) = %d; want %d", tt.r, req.ContentLength, tt.want)
+ t.Errorf("test[%d]: ContentLength(%T) = %d; want %d", i, tt.r, req.ContentLength, tt.want)
+ }
+ if (req.ContentLength == 0) != (req.Body == NoBody) {
+ t.Errorf("test[%d]: ContentLength = %d but Body non-nil is %v", i, req.ContentLength, req.Body != nil)
}
}
}
@@ -626,11 +671,31 @@ func TestStarRequest(t *testing.T) {
if err != nil {
return
}
+ if req.ContentLength != 0 {
+ t.Errorf("ContentLength = %d; want 0", req.ContentLength)
+ }
+ if req.Body == nil {
+ t.Errorf("Body = nil; want non-nil")
+ }
+
+ // Request.Write has Client semantics for Body/ContentLength,
+ // where ContentLength 0 means unknown if Body is non-nil, and
+ // thus chunking will happen unless we change semantics and
+ // signal that we want to serialize it as exactly zero. The
+ // only way to do that for outbound requests is with a nil
+ // Body:
+ clientReq := *req
+ clientReq.Body = nil
+
var out bytes.Buffer
- if err := req.Write(&out); err != nil {
+ if err := clientReq.Write(&out); err != nil {
t.Fatal(err)
}
- back, err := ReadRequest(bufio.NewReader(&out))
+
+ if strings.Contains(out.String(), "chunked") {
+ t.Error("wrote chunked request; want no body")
+ }
+ back, err := ReadRequest(bufio.NewReader(bytes.NewReader(out.Bytes())))
if err != nil {
t.Fatal(err)
}
@@ -719,6 +784,47 @@ func TestMaxBytesReaderStickyError(t *testing.T) {
}
}
+// verify that NewRequest sets Request.GetBody and that it works
+func TestNewRequestGetBody(t *testing.T) {
+ tests := []struct {
+ r io.Reader
+ }{
+ {r: strings.NewReader("hello")},
+ {r: bytes.NewReader([]byte("hello"))},
+ {r: bytes.NewBuffer([]byte("hello"))},
+ }
+ for i, tt := range tests {
+ req, err := NewRequest("POST", "http://foo.tld/", tt.r)
+ if err != nil {
+ t.Errorf("test[%d]: %v", i, err)
+ continue
+ }
+ if req.Body == nil {
+ t.Errorf("test[%d]: Body = nil", i)
+ continue
+ }
+ if req.GetBody == nil {
+ t.Errorf("test[%d]: GetBody = nil", i)
+ continue
+ }
+ slurp1, err := ioutil.ReadAll(req.Body)
+ if err != nil {
+ t.Errorf("test[%d]: ReadAll(Body) = %v", i, err)
+ }
+ newBody, err := req.GetBody()
+ if err != nil {
+ t.Errorf("test[%d]: GetBody = %v", i, err)
+ }
+ slurp2, err := ioutil.ReadAll(newBody)
+ if err != nil {
+ t.Errorf("test[%d]: ReadAll(GetBody()) = %v", i, err)
+ }
+ if string(slurp1) != string(slurp2) {
+ t.Errorf("test[%d]: Body %q != GetBody %q", i, slurp1, slurp2)
+ }
+ }
+}
+
func testMissingFile(t *testing.T, req *Request) {
f, fh, err := req.FormFile("missing")
if f != nil {
diff --git a/src/net/http/requestwrite_test.go b/src/net/http/requestwrite_test.go
index 2545f6f..d13e37a 100644
--- a/src/net/http/requestwrite_test.go
+++ b/src/net/http/requestwrite_test.go
@@ -28,7 +28,7 @@ type reqWriteTest struct {
var reqWriteTests = []reqWriteTest{
// HTTP/1.1 => chunked coding; no body; no trailer
- {
+ 0: {
Req: Request{
Method: "GET",
URL: &url.URL{
@@ -75,7 +75,7 @@ var reqWriteTests = []reqWriteTest{
"Proxy-Connection: keep-alive\r\n\r\n",
},
// HTTP/1.1 => chunked coding; body; empty trailer
- {
+ 1: {
Req: Request{
Method: "GET",
URL: &url.URL{
@@ -104,7 +104,7 @@ var reqWriteTests = []reqWriteTest{
chunk("abcdef") + chunk(""),
},
// HTTP/1.1 POST => chunked coding; body; empty trailer
- {
+ 2: {
Req: Request{
Method: "POST",
URL: &url.URL{
@@ -137,7 +137,7 @@ var reqWriteTests = []reqWriteTest{
},
// HTTP/1.1 POST with Content-Length, no chunking
- {
+ 3: {
Req: Request{
Method: "POST",
URL: &url.URL{
@@ -172,7 +172,7 @@ var reqWriteTests = []reqWriteTest{
},
// HTTP/1.1 POST with Content-Length in headers
- {
+ 4: {
Req: Request{
Method: "POST",
URL: mustParseURL("http://example.com/"),
@@ -201,7 +201,7 @@ var reqWriteTests = []reqWriteTest{
},
// default to HTTP/1.1
- {
+ 5: {
Req: Request{
Method: "GET",
URL: mustParseURL("/search"),
@@ -215,7 +215,7 @@ var reqWriteTests = []reqWriteTest{
},
// Request with a 0 ContentLength and a 0 byte body.
- {
+ 6: {
Req: Request{
Method: "POST",
URL: mustParseURL("/"),
@@ -227,9 +227,32 @@ var reqWriteTests = []reqWriteTest{
Body: func() io.ReadCloser { return ioutil.NopCloser(io.LimitReader(strings.NewReader("xx"), 0)) },
- // RFC 2616 Section 14.13 says Content-Length should be specified
- // unless body is prohibited by the request method.
- // Also, nginx expects it for POST and PUT.
+ WantWrite: "POST / HTTP/1.1\r\n" +
+ "Host: example.com\r\n" +
+ "User-Agent: Go-http-client/1.1\r\n" +
+ "Transfer-Encoding: chunked\r\n" +
+ "\r\n0\r\n\r\n",
+
+ WantProxy: "POST / HTTP/1.1\r\n" +
+ "Host: example.com\r\n" +
+ "User-Agent: Go-http-client/1.1\r\n" +
+ "Transfer-Encoding: chunked\r\n" +
+ "\r\n0\r\n\r\n",
+ },
+
+ // Request with a 0 ContentLength and a nil body.
+ 7: {
+ Req: Request{
+ Method: "POST",
+ URL: mustParseURL("/"),
+ Host: "example.com",
+ ProtoMajor: 1,
+ ProtoMinor: 1,
+ ContentLength: 0, // as if unset by user
+ },
+
+ Body: func() io.ReadCloser { return nil },
+
WantWrite: "POST / HTTP/1.1\r\n" +
"Host: example.com\r\n" +
"User-Agent: Go-http-client/1.1\r\n" +
@@ -244,7 +267,7 @@ var reqWriteTests = []reqWriteTest{
},
// Request with a 0 ContentLength and a 1 byte body.
- {
+ 8: {
Req: Request{
Method: "POST",
URL: mustParseURL("/"),
@@ -270,7 +293,7 @@ var reqWriteTests = []reqWriteTest{
},
// Request with a ContentLength of 10 but a 5 byte body.
- {
+ 9: {
Req: Request{
Method: "POST",
URL: mustParseURL("/"),
@@ -284,7 +307,7 @@ var reqWriteTests = []reqWriteTest{
},
// Request with a ContentLength of 4 but an 8 byte body.
- {
+ 10: {
Req: Request{
Method: "POST",
URL: mustParseURL("/"),
@@ -298,7 +321,7 @@ var reqWriteTests = []reqWriteTest{
},
// Request with a 5 ContentLength and nil body.
- {
+ 11: {
Req: Request{
Method: "POST",
URL: mustParseURL("/"),
@@ -311,7 +334,7 @@ var reqWriteTests = []reqWriteTest{
},
// Request with a 0 ContentLength and a body with 1 byte content and an error.
- {
+ 12: {
Req: Request{
Method: "POST",
URL: mustParseURL("/"),
@@ -331,7 +354,7 @@ var reqWriteTests = []reqWriteTest{
},
// Request with a 0 ContentLength and a body without content and an error.
- {
+ 13: {
Req: Request{
Method: "POST",
URL: mustParseURL("/"),
@@ -352,7 +375,7 @@ var reqWriteTests = []reqWriteTest{
// Verify that DumpRequest preserves the HTTP version number, doesn't add a Host,
// and doesn't add a User-Agent.
- {
+ 14: {
Req: Request{
Method: "GET",
URL: mustParseURL("/foo"),
@@ -373,7 +396,7 @@ var reqWriteTests = []reqWriteTest{
// an empty Host header, and don't use
// Request.Header["Host"]. This is just testing that
// we don't change Go 1.0 behavior.
- {
+ 15: {
Req: Request{
Method: "GET",
Host: "",
@@ -395,7 +418,7 @@ var reqWriteTests = []reqWriteTest{
},
// Opaque test #1 from golang.org/issue/4860
- {
+ 16: {
Req: Request{
Method: "GET",
URL: &url.URL{
@@ -414,7 +437,7 @@ var reqWriteTests = []reqWriteTest{
},
// Opaque test #2 from golang.org/issue/4860
- {
+ 17: {
Req: Request{
Method: "GET",
URL: &url.URL{
@@ -433,7 +456,7 @@ var reqWriteTests = []reqWriteTest{
},
// Testing custom case in header keys. Issue 5022.
- {
+ 18: {
Req: Request{
Method: "GET",
URL: &url.URL{
@@ -457,7 +480,7 @@ var reqWriteTests = []reqWriteTest{
},
// Request with host header field; IPv6 address with zone identifier
- {
+ 19: {
Req: Request{
Method: "GET",
URL: &url.URL{
@@ -472,7 +495,7 @@ var reqWriteTests = []reqWriteTest{
},
// Request with optional host header field; IPv6 address with zone identifier
- {
+ 20: {
Req: Request{
Method: "GET",
URL: &url.URL{
@@ -553,14 +576,14 @@ func (rc *closeChecker) Close() error {
return nil
}
-// TestRequestWriteClosesBody tests that Request.Write does close its request.Body.
+// TestRequestWriteClosesBody tests that Request.Write closes its request.Body.
// It also indirectly tests NewRequest and that it doesn't wrap an existing Closer
// inside a NopCloser, and that it serializes it correctly.
func TestRequestWriteClosesBody(t *testing.T) {
rc := &closeChecker{Reader: strings.NewReader("my body")}
req, _ := NewRequest("POST", "http://foo.com/", rc)
- if req.ContentLength != 0 {
- t.Errorf("got req.ContentLength %d, want 0", req.ContentLength)
+ if req.ContentLength != -1 {
+ t.Errorf("got req.ContentLength %d, want -1", req.ContentLength)
}
buf := new(bytes.Buffer)
req.Write(buf)
@@ -571,12 +594,7 @@ func TestRequestWriteClosesBody(t *testing.T) {
"Host: foo.com\r\n" +
"User-Agent: Go-http-client/1.1\r\n" +
"Transfer-Encoding: chunked\r\n\r\n" +
- // TODO: currently we don't buffer before chunking, so we get a
- // single "m" chunk before the other chunks, as this was the 1-byte
- // read from our MultiReader where we stitched the Body back together
- // after sniffing whether the Body was 0 bytes or not.
- chunk("m") +
- chunk("y body") +
+ chunk("my body") +
chunk("")
if buf.String() != expected {
t.Errorf("write:\n got: %s\nwant: %s", buf.String(), expected)
diff --git a/src/net/http/response.go b/src/net/http/response.go
index 5450d50..ae118fb 100644
--- a/src/net/http/response.go
+++ b/src/net/http/response.go
@@ -261,7 +261,7 @@ func (r *Response) Write(w io.Writer) error {
if n == 0 {
// Reset it to a known zero reader, in case underlying one
// is unhappy being read repeatedly.
- r1.Body = eofReader
+ r1.Body = NoBody
} else {
r1.ContentLength = -1
r1.Body = struct {
@@ -300,7 +300,7 @@ func (r *Response) Write(w io.Writer) error {
// contentLengthAlreadySent may have been already sent for
// POST/PUT requests, even if zero length. See Issue 8180.
contentLengthAlreadySent := tw.shouldSendContentLength()
- if r1.ContentLength == 0 && !chunked(r1.TransferEncoding) && !contentLengthAlreadySent {
+ if r1.ContentLength == 0 && !chunked(r1.TransferEncoding) && !contentLengthAlreadySent && bodyAllowedForStatus(r.StatusCode) {
if _, err := io.WriteString(w, "Content-Length: 0\r\n"); err != nil {
return err
}
diff --git a/src/net/http/response_test.go b/src/net/http/response_test.go
index 126da92..660d517 100644
--- a/src/net/http/response_test.go
+++ b/src/net/http/response_test.go
@@ -589,6 +589,7 @@ var readResponseCloseInMiddleTests = []struct {
// reading only part of its contents advances the read to the end of
// the request, right up until the next request.
func TestReadResponseCloseInMiddle(t *testing.T) {
+ t.Parallel()
for _, test := range readResponseCloseInMiddleTests {
fatalf := func(format string, args ...interface{}) {
args = append([]interface{}{test.chunked, test.compressed}, args...)
@@ -792,6 +793,7 @@ func TestReadResponseErrors(t *testing.T) {
type testCase struct {
name string // optional, defaults to in
in string
+ header Header
wantErr interface{} // nil, err value, or string substring
}
@@ -817,11 +819,22 @@ func TestReadResponseErrors(t *testing.T) {
}
}
+ contentLength := func(status, body string, wantErr interface{}, header Header) testCase {
+ return testCase{
+ name: fmt.Sprintf("status %q %q", status, body),
+ in: fmt.Sprintf("HTTP/1.1 %s\r\n%s", status, body),
+ wantErr: wantErr,
+ header: header,
+ }
+ }
+
+ errMultiCL := "message cannot contain multiple Content-Length headers"
+
tests := []testCase{
- {"", "", io.ErrUnexpectedEOF},
- {"", "HTTP/1.1 301 Moved Permanently\r\nFoo: bar", io.ErrUnexpectedEOF},
- {"", "HTTP/1.1", "malformed HTTP response"},
- {"", "HTTP/2.0", "malformed HTTP response"},
+ {"", "", nil, io.ErrUnexpectedEOF},
+ {"", "HTTP/1.1 301 Moved Permanently\r\nFoo: bar", nil, io.ErrUnexpectedEOF},
+ {"", "HTTP/1.1", nil, "malformed HTTP response"},
+ {"", "HTTP/2.0", nil, "malformed HTTP response"},
status("20X Unknown", true),
status("abcd Unknown", true),
status("二百/两百 OK", true),
@@ -846,7 +859,21 @@ func TestReadResponseErrors(t *testing.T) {
version("HTTP/A.B", true),
version("HTTP/1", true),
version("http/1.1", true),
+
+ contentLength("200 OK", "Content-Length: 10\r\nContent-Length: 7\r\n\r\nGopher hey\r\n", errMultiCL, nil),
+ contentLength("200 OK", "Content-Length: 7\r\nContent-Length: 7\r\n\r\nGophers\r\n", nil, Header{"Content-Length": {"7"}}),
+ contentLength("201 OK", "Content-Length: 0\r\nContent-Length: 7\r\n\r\nGophers\r\n", errMultiCL, nil),
+ contentLength("300 OK", "Content-Length: 0\r\nContent-Length: 0 \r\n\r\nGophers\r\n", nil, Header{"Content-Length": {"0"}}),
+ contentLength("200 OK", "Content-Length:\r\nContent-Length:\r\n\r\nGophers\r\n", nil, nil),
+ contentLength("206 OK", "Content-Length:\r\nContent-Length: 0 \r\nConnection: close\r\n\r\nGophers\r\n", errMultiCL, nil),
+
+ // multiple content-length headers for 204 and 304 should still be checked
+ contentLength("204 OK", "Content-Length: 7\r\nContent-Length: 8\r\n\r\n", errMultiCL, nil),
+ contentLength("204 OK", "Content-Length: 3\r\nContent-Length: 3\r\n\r\n", nil, nil),
+ contentLength("304 OK", "Content-Length: 880\r\nContent-Length: 1\r\n\r\n", errMultiCL, nil),
+ contentLength("304 OK", "Content-Length: 961\r\nContent-Length: 961\r\n\r\n", nil, nil),
}
+
for i, tt := range tests {
br := bufio.NewReader(strings.NewReader(tt.in))
_, rerr := ReadResponse(br, nil)
diff --git a/src/net/http/responsewrite_test.go b/src/net/http/responsewrite_test.go
index 90f6767..d41d898 100644
--- a/src/net/http/responsewrite_test.go
+++ b/src/net/http/responsewrite_test.go
@@ -241,7 +241,8 @@ func TestResponseWrite(t *testing.T) {
"HTTP/1.0 007 license to violate specs\r\nContent-Length: 0\r\n\r\n",
},
- // No stutter.
+ // No stutter. Status code in 1xx range response should
+ // not include a Content-Length header. See issue #16942.
{
Response{
StatusCode: 123,
@@ -253,7 +254,23 @@ func TestResponseWrite(t *testing.T) {
Body: nil,
},
- "HTTP/1.0 123 Sesame Street\r\nContent-Length: 0\r\n\r\n",
+ "HTTP/1.0 123 Sesame Street\r\n\r\n",
+ },
+
+ // Status code 204 (No content) response should not include a
+ // Content-Length header. See issue #16942.
+ {
+ Response{
+ StatusCode: 204,
+ Status: "No Content",
+ ProtoMajor: 1,
+ ProtoMinor: 0,
+ Request: dummyReq("GET"),
+ Header: Header{},
+ Body: nil,
+ },
+
+ "HTTP/1.0 204 No Content\r\n\r\n",
},
}
diff --git a/src/net/http/serve_test.go b/src/net/http/serve_test.go
index 13e5f28..593b1f3 100644
--- a/src/net/http/serve_test.go
+++ b/src/net/http/serve_test.go
@@ -156,6 +156,7 @@ func (ht handlerTest) rawResponse(req string) string {
}
func TestConsumingBodyOnNextConn(t *testing.T) {
+ t.Parallel()
defer afterTest(t)
conn := new(testConn)
for i := 0; i < 2; i++ {
@@ -237,6 +238,7 @@ var vtests = []struct {
}
func TestHostHandlers(t *testing.T) {
+ setParallel(t)
defer afterTest(t)
mux := NewServeMux()
for _, h := range handlers {
@@ -353,6 +355,7 @@ var serveMuxTests = []struct {
}
func TestServeMuxHandler(t *testing.T) {
+ setParallel(t)
mux := NewServeMux()
for _, e := range serveMuxRegister {
mux.Handle(e.pattern, e.h)
@@ -390,15 +393,16 @@ var serveMuxTests2 = []struct {
// TestServeMuxHandlerRedirects tests that automatic redirects generated by
// mux.Handler() shouldn't clear the request's query string.
func TestServeMuxHandlerRedirects(t *testing.T) {
+ setParallel(t)
mux := NewServeMux()
for _, e := range serveMuxRegister {
mux.Handle(e.pattern, e.h)
}
for _, tt := range serveMuxTests2 {
- tries := 1
+ tries := 1 // expect at most 1 redirection if redirOk is true.
turl := tt.url
- for tries > 0 {
+ for {
u, e := url.Parse(turl)
if e != nil {
t.Fatal(e)
@@ -432,6 +436,7 @@ func TestServeMuxHandlerRedirects(t *testing.T) {
// Tests for https://golang.org/issue/900
func TestMuxRedirectLeadingSlashes(t *testing.T) {
+ setParallel(t)
paths := []string{"//foo.txt", "///foo.txt", "/../../foo.txt"}
for _, path := range paths {
req, err := ReadRequest(bufio.NewReader(strings.NewReader("GET " + path + " HTTP/1.1\r\nHost: test\r\n\r\n")))
@@ -456,9 +461,6 @@ func TestMuxRedirectLeadingSlashes(t *testing.T) {
}
func TestServerTimeouts(t *testing.T) {
- if runtime.GOOS == "plan9" {
- t.Skip("skipping test; see https://golang.org/issue/7237")
- }
setParallel(t)
defer afterTest(t)
reqNum := 0
@@ -536,9 +538,7 @@ func TestServerTimeouts(t *testing.T) {
// shouldn't cause a handler to block forever on reads (next HTTP
// request) that will never happen.
func TestOnlyWriteTimeout(t *testing.T) {
- if runtime.GOOS == "plan9" {
- t.Skip("skipping test; see https://golang.org/issue/7237")
- }
+ setParallel(t)
defer afterTest(t)
var conn net.Conn
var afterTimeoutErrc = make(chan error, 1)
@@ -598,6 +598,7 @@ func (l trackLastConnListener) Accept() (c net.Conn, err error) {
// TestIdentityResponse verifies that a handler can unset
func TestIdentityResponse(t *testing.T) {
+ setParallel(t)
defer afterTest(t)
handler := HandlerFunc(func(rw ResponseWriter, req *Request) {
rw.Header().Set("Content-Length", "3")
@@ -619,13 +620,16 @@ func TestIdentityResponse(t *testing.T) {
ts := httptest.NewServer(handler)
defer ts.Close()
+ c := &Client{Transport: new(Transport)}
+ defer closeClient(c)
+
// Note: this relies on the assumption (which is true) that
// Get sends HTTP/1.1 or greater requests. Otherwise the
// server wouldn't have the choice to send back chunked
// responses.
for _, te := range []string{"", "identity"} {
url := ts.URL + "/?te=" + te
- res, err := Get(url)
+ res, err := c.Get(url)
if err != nil {
t.Fatalf("error with Get of %s: %v", url, err)
}
@@ -644,7 +648,7 @@ func TestIdentityResponse(t *testing.T) {
// Verify that ErrContentLength is returned
url := ts.URL + "/?overwrite=1"
- res, err := Get(url)
+ res, err := c.Get(url)
if err != nil {
t.Fatalf("error with Get of %s: %v", url, err)
}
@@ -674,6 +678,7 @@ func TestIdentityResponse(t *testing.T) {
}
func testTCPConnectionCloses(t *testing.T, req string, h Handler) {
+ setParallel(t)
defer afterTest(t)
s := httptest.NewServer(h)
defer s.Close()
@@ -717,6 +722,7 @@ func testTCPConnectionCloses(t *testing.T, req string, h Handler) {
}
func testTCPConnectionStaysOpen(t *testing.T, req string, handler Handler) {
+ setParallel(t)
defer afterTest(t)
ts := httptest.NewServer(handler)
defer ts.Close()
@@ -750,7 +756,7 @@ func TestServeHTTP10Close(t *testing.T) {
// TestClientCanClose verifies that clients can also force a connection to close.
func TestClientCanClose(t *testing.T) {
- testTCPConnectionCloses(t, "GET / HTTP/1.1\r\nConnection: close\r\n\r\n", HandlerFunc(func(w ResponseWriter, r *Request) {
+ testTCPConnectionCloses(t, "GET / HTTP/1.1\r\nHost: foo\r\nConnection: close\r\n\r\n", HandlerFunc(func(w ResponseWriter, r *Request) {
// Nothing.
}))
}
@@ -758,7 +764,7 @@ func TestClientCanClose(t *testing.T) {
// TestHandlersCanSetConnectionClose verifies that handlers can force a connection to close,
// even for HTTP/1.1 requests.
func TestHandlersCanSetConnectionClose11(t *testing.T) {
- testTCPConnectionCloses(t, "GET / HTTP/1.1\r\n\r\n", HandlerFunc(func(w ResponseWriter, r *Request) {
+ testTCPConnectionCloses(t, "GET / HTTP/1.1\r\nHost: foo\r\n\r\n\r\n", HandlerFunc(func(w ResponseWriter, r *Request) {
w.Header().Set("Connection", "close")
}))
}
@@ -796,6 +802,7 @@ func TestHTTP10KeepAlive304Response(t *testing.T) {
// Issue 15703
func TestKeepAliveFinalChunkWithEOF(t *testing.T) {
+ setParallel(t)
defer afterTest(t)
cst := newClientServerTest(t, false /* h1 */, HandlerFunc(func(w ResponseWriter, r *Request) {
w.(Flusher).Flush() // force chunked encoding
@@ -828,6 +835,7 @@ func TestSetsRemoteAddr_h1(t *testing.T) { testSetsRemoteAddr(t, h1Mode) }
func TestSetsRemoteAddr_h2(t *testing.T) { testSetsRemoteAddr(t, h2Mode) }
func testSetsRemoteAddr(t *testing.T, h2 bool) {
+ setParallel(t)
defer afterTest(t)
cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
fmt.Fprintf(w, "%s", r.RemoteAddr)
@@ -877,6 +885,7 @@ 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)
@@ -948,7 +957,9 @@ func TestServerAllowsBlockingRemoteAddr(t *testing.T) {
t.Fatalf("response 1 addr = %q; want %q", g, e)
}
}
+
func TestIdentityResponseHeaders(t *testing.T) {
+ // Not parallel; changes log output.
defer afterTest(t)
log.SetOutput(ioutil.Discard) // is noisy otherwise
defer log.SetOutput(os.Stderr)
@@ -960,7 +971,10 @@ func TestIdentityResponseHeaders(t *testing.T) {
}))
defer ts.Close()
- res, err := Get(ts.URL)
+ c := &Client{Transport: new(Transport)}
+ defer closeClient(c)
+
+ res, err := c.Get(ts.URL)
if err != nil {
t.Fatalf("Get error: %v", err)
}
@@ -983,6 +997,7 @@ func TestHeadResponses_h1(t *testing.T) { testHeadResponses(t, h1Mode) }
func TestHeadResponses_h2(t *testing.T) { testHeadResponses(t, h2Mode) }
func testHeadResponses(t *testing.T, h2 bool) {
+ setParallel(t)
defer afterTest(t)
cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
_, err := w.Write([]byte("<html>"))
@@ -1020,9 +1035,6 @@ func testHeadResponses(t *testing.T, h2 bool) {
}
func TestTLSHandshakeTimeout(t *testing.T) {
- if runtime.GOOS == "plan9" {
- t.Skip("skipping test; see https://golang.org/issue/7237")
- }
setParallel(t)
defer afterTest(t)
ts := httptest.NewUnstartedServer(HandlerFunc(func(w ResponseWriter, r *Request) {}))
@@ -1054,6 +1066,7 @@ func TestTLSHandshakeTimeout(t *testing.T) {
}
func TestTLSServer(t *testing.T) {
+ setParallel(t)
defer afterTest(t)
ts := httptest.NewTLSServer(HandlerFunc(func(w ResponseWriter, r *Request) {
if r.TLS != nil {
@@ -1121,6 +1134,7 @@ func TestAutomaticHTTP2_Serve_H2TLSConfig(t *testing.T) {
}
func testAutomaticHTTP2_Serve(t *testing.T, tlsConf *tls.Config, wantH2 bool) {
+ setParallel(t)
defer afterTest(t)
ln := newLocalListener(t)
ln.Close() // immediately (not a defer!)
@@ -1136,6 +1150,7 @@ func testAutomaticHTTP2_Serve(t *testing.T, tlsConf *tls.Config, wantH2 bool) {
}
func TestAutomaticHTTP2_Serve_WithTLSConfig(t *testing.T) {
+ setParallel(t)
defer afterTest(t)
ln := newLocalListener(t)
ln.Close() // immediately (not a defer!)
@@ -1177,6 +1192,7 @@ func TestAutomaticHTTP2_ListenAndServe_GetCertificate(t *testing.T) {
}
func testAutomaticHTTP2_ListenAndServe(t *testing.T, tlsConf *tls.Config) {
+ // Not parallel: uses global test hooks.
defer afterTest(t)
defer SetTestHookServerServe(nil)
var ok bool
@@ -1280,6 +1296,7 @@ var serverExpectTests = []serverExpectTest{
// correctly.
// http2 test: TestServer_Response_Automatic100Continue
func TestServerExpect(t *testing.T) {
+ setParallel(t)
defer afterTest(t)
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
// Note using r.FormValue("readbody") because for POST
@@ -1373,6 +1390,7 @@ func TestServerExpect(t *testing.T) {
// Under a ~256KB (maxPostHandlerReadBytes) threshold, the server
// should consume client request bodies that a handler didn't read.
func TestServerUnreadRequestBodyLittle(t *testing.T) {
+ setParallel(t)
defer afterTest(t)
conn := new(testConn)
body := strings.Repeat("x", 100<<10)
@@ -1413,6 +1431,7 @@ func TestServerUnreadRequestBodyLittle(t *testing.T) {
// should ignore client request bodies that a handler didn't read
// and close the connection.
func TestServerUnreadRequestBodyLarge(t *testing.T) {
+ setParallel(t)
if testing.Short() && testenv.Builder() == "" {
t.Log("skipping in short mode")
}
@@ -1546,6 +1565,7 @@ var handlerBodyCloseTests = [...]handlerBodyCloseTest{
}
func TestHandlerBodyClose(t *testing.T) {
+ setParallel(t)
if testing.Short() && testenv.Builder() == "" {
t.Skip("skipping in -short mode")
}
@@ -1625,6 +1645,7 @@ var testHandlerBodyConsumers = []testHandlerBodyConsumer{
}
func TestRequestBodyReadErrorClosesConnection(t *testing.T) {
+ setParallel(t)
defer afterTest(t)
for _, handler := range testHandlerBodyConsumers {
conn := new(testConn)
@@ -1655,6 +1676,7 @@ func TestRequestBodyReadErrorClosesConnection(t *testing.T) {
}
func TestInvalidTrailerClosesConnection(t *testing.T) {
+ setParallel(t)
defer afterTest(t)
for _, handler := range testHandlerBodyConsumers {
conn := new(testConn)
@@ -1737,7 +1759,7 @@ restart:
if !c.rd.IsZero() {
// If the deadline falls in the middle of our sleep window, deduct
// part of the sleep, then return a timeout.
- if remaining := c.rd.Sub(time.Now()); remaining < cue {
+ if remaining := time.Until(c.rd); remaining < cue {
c.script[0] = cue - remaining
time.Sleep(remaining)
return 0, syscall.ETIMEDOUT
@@ -1823,6 +1845,7 @@ func TestRequestBodyTimeoutClosesConnection(t *testing.T) {
func TestTimeoutHandler_h1(t *testing.T) { testTimeoutHandler(t, h1Mode) }
func TestTimeoutHandler_h2(t *testing.T) { testTimeoutHandler(t, h2Mode) }
func testTimeoutHandler(t *testing.T, h2 bool) {
+ setParallel(t)
defer afterTest(t)
sendHi := make(chan bool, 1)
writeErrors := make(chan error, 1)
@@ -1876,6 +1899,7 @@ func testTimeoutHandler(t *testing.T, h2 bool) {
// See issues 8209 and 8414.
func TestTimeoutHandlerRace(t *testing.T) {
+ setParallel(t)
defer afterTest(t)
delayHi := HandlerFunc(func(w ResponseWriter, r *Request) {
@@ -1892,6 +1916,9 @@ func TestTimeoutHandlerRace(t *testing.T) {
ts := httptest.NewServer(TimeoutHandler(delayHi, 20*time.Millisecond, ""))
defer ts.Close()
+ c := &Client{Transport: new(Transport)}
+ defer closeClient(c)
+
var wg sync.WaitGroup
gate := make(chan bool, 10)
n := 50
@@ -1905,7 +1932,7 @@ func TestTimeoutHandlerRace(t *testing.T) {
go func() {
defer wg.Done()
defer func() { <-gate }()
- res, err := Get(fmt.Sprintf("%s/%d", ts.URL, rand.Intn(50)))
+ res, err := c.Get(fmt.Sprintf("%s/%d", ts.URL, rand.Intn(50)))
if err == nil {
io.Copy(ioutil.Discard, res.Body)
res.Body.Close()
@@ -1917,6 +1944,7 @@ func TestTimeoutHandlerRace(t *testing.T) {
// See issues 8209 and 8414.
func TestTimeoutHandlerRaceHeader(t *testing.T) {
+ setParallel(t)
defer afterTest(t)
delay204 := HandlerFunc(func(w ResponseWriter, r *Request) {
@@ -1932,13 +1960,15 @@ func TestTimeoutHandlerRaceHeader(t *testing.T) {
if testing.Short() {
n = 10
}
+ c := &Client{Transport: new(Transport)}
+ defer closeClient(c)
for i := 0; i < n; i++ {
gate <- true
wg.Add(1)
go func() {
defer wg.Done()
defer func() { <-gate }()
- res, err := Get(ts.URL)
+ res, err := c.Get(ts.URL)
if err != nil {
t.Error(err)
return
@@ -1952,6 +1982,7 @@ func TestTimeoutHandlerRaceHeader(t *testing.T) {
// Issue 9162
func TestTimeoutHandlerRaceHeaderTimeout(t *testing.T) {
+ setParallel(t)
defer afterTest(t)
sendHi := make(chan bool, 1)
writeErrors := make(chan error, 1)
@@ -2016,11 +2047,15 @@ func TestTimeoutHandlerStartTimerWhenServing(t *testing.T) {
timeout := 300 * time.Millisecond
ts := httptest.NewServer(TimeoutHandler(handler, timeout, ""))
defer ts.Close()
+
+ c := &Client{Transport: new(Transport)}
+ defer closeClient(c)
+
// Issue was caused by the timeout handler starting the timer when
// was created, not when the request. So wait for more than the timeout
// to ensure that's not the case.
time.Sleep(2 * timeout)
- res, err := Get(ts.URL)
+ res, err := c.Get(ts.URL)
if err != nil {
t.Fatal(err)
}
@@ -2032,6 +2067,7 @@ func TestTimeoutHandlerStartTimerWhenServing(t *testing.T) {
// https://golang.org/issue/15948
func TestTimeoutHandlerEmptyResponse(t *testing.T) {
+ setParallel(t)
defer afterTest(t)
var handler HandlerFunc = func(w ResponseWriter, _ *Request) {
// No response.
@@ -2040,7 +2076,10 @@ func TestTimeoutHandlerEmptyResponse(t *testing.T) {
ts := httptest.NewServer(TimeoutHandler(handler, timeout, ""))
defer ts.Close()
- res, err := Get(ts.URL)
+ c := &Client{Transport: new(Transport)}
+ defer closeClient(c)
+
+ res, err := c.Get(ts.URL)
if err != nil {
t.Fatal(err)
}
@@ -2050,23 +2089,6 @@ func TestTimeoutHandlerEmptyResponse(t *testing.T) {
}
}
-// Verifies we don't path.Clean() on the wrong parts in redirects.
-func TestRedirectMunging(t *testing.T) {
- req, _ := NewRequest("GET", "http://example.com/", nil)
-
- resp := httptest.NewRecorder()
- Redirect(resp, req, "/foo?next=http://bar.com/", 302)
- if g, e := resp.Header().Get("Location"), "/foo?next=http://bar.com/"; g != e {
- t.Errorf("Location header was %q; want %q", g, e)
- }
-
- resp = httptest.NewRecorder()
- Redirect(resp, req, "http://localhost:8080/_ah/login?continue=http://localhost:8080/", 302)
- if g, e := resp.Header().Get("Location"), "http://localhost:8080/_ah/login?continue=http://localhost:8080/"; g != e {
- t.Errorf("Location header was %q; want %q", g, e)
- }
-}
-
func TestRedirectBadPath(t *testing.T) {
// This used to crash. It's not valid input (bad path), but it
// shouldn't crash.
@@ -2085,7 +2107,7 @@ func TestRedirectBadPath(t *testing.T) {
}
// Test different URL formats and schemes
-func TestRedirectURLFormat(t *testing.T) {
+func TestRedirect(t *testing.T) {
req, _ := NewRequest("GET", "http://example.com/qux/", nil)
var tests = []struct {
@@ -2108,6 +2130,14 @@ func TestRedirectURLFormat(t *testing.T) {
{"../quux/foobar.com/baz", "/quux/foobar.com/baz"},
// incorrect number of slashes
{"///foobar.com/baz", "/foobar.com/baz"},
+
+ // Verifies we don't path.Clean() on the wrong parts in redirects:
+ {"/foo?next=http://bar.com/", "/foo?next=http://bar.com/"},
+ {"http://localhost:8080/_ah/login?continue=http://localhost:8080/",
+ "http://localhost:8080/_ah/login?continue=http://localhost:8080/"},
+
+ {"/фубар", "/%d1%84%d1%83%d0%b1%d0%b0%d1%80"},
+ {"http://foo.com/фубар", "http://foo.com/%d1%84%d1%83%d0%b1%d0%b0%d1%80"},
}
for _, tt := range tests {
@@ -2133,6 +2163,7 @@ func TestZeroLengthPostAndResponse_h2(t *testing.T) {
}
func testZeroLengthPostAndResponse(t *testing.T, h2 bool) {
+ setParallel(t)
defer afterTest(t)
cst := newClientServerTest(t, h2, HandlerFunc(func(rw ResponseWriter, r *Request) {
all, err := ioutil.ReadAll(r.Body)
@@ -2252,12 +2283,58 @@ func testHandlerPanic(t *testing.T, withHijack, h2 bool, panicValue interface{})
}
}
+type terrorWriter struct{ t *testing.T }
+
+func (w terrorWriter) Write(p []byte) (int, error) {
+ w.t.Errorf("%s", p)
+ return len(p), nil
+}
+
+// Issue 16456: allow writing 0 bytes on hijacked conn to test hijack
+// without any log spam.
+func TestServerWriteHijackZeroBytes(t *testing.T) {
+ defer afterTest(t)
+ done := make(chan struct{})
+ ts := httptest.NewUnstartedServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ defer close(done)
+ w.(Flusher).Flush()
+ conn, _, err := w.(Hijacker).Hijack()
+ if err != nil {
+ t.Errorf("Hijack: %v", err)
+ return
+ }
+ defer conn.Close()
+ _, err = w.Write(nil)
+ if err != ErrHijacked {
+ t.Errorf("Write error = %v; want ErrHijacked", err)
+ }
+ }))
+ ts.Config.ErrorLog = log.New(terrorWriter{t}, "Unexpected write: ", 0)
+ ts.Start()
+ defer ts.Close()
+
+ tr := &Transport{}
+ defer tr.CloseIdleConnections()
+ c := &Client{Transport: tr}
+ res, err := c.Get(ts.URL)
+ if err != nil {
+ t.Fatal(err)
+ }
+ res.Body.Close()
+ select {
+ case <-done:
+ case <-time.After(5 * time.Second):
+ t.Fatal("timeout")
+ }
+}
+
func TestServerNoDate_h1(t *testing.T) { testServerNoHeader(t, h1Mode, "Date") }
func TestServerNoDate_h2(t *testing.T) { testServerNoHeader(t, h2Mode, "Date") }
func TestServerNoContentType_h1(t *testing.T) { testServerNoHeader(t, h1Mode, "Content-Type") }
func TestServerNoContentType_h2(t *testing.T) { testServerNoHeader(t, h2Mode, "Content-Type") }
func testServerNoHeader(t *testing.T, h2 bool, header string) {
+ setParallel(t)
defer afterTest(t)
cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
w.Header()[header] = nil
@@ -2275,6 +2352,7 @@ func testServerNoHeader(t *testing.T, h2 bool, header string) {
}
func TestStripPrefix(t *testing.T) {
+ setParallel(t)
defer afterTest(t)
h := HandlerFunc(func(w ResponseWriter, r *Request) {
w.Header().Set("X-Path", r.URL.Path)
@@ -2282,7 +2360,10 @@ func TestStripPrefix(t *testing.T) {
ts := httptest.NewServer(StripPrefix("/foo", h))
defer ts.Close()
- res, err := Get(ts.URL + "/foo/bar")
+ c := &Client{Transport: new(Transport)}
+ defer closeClient(c)
+
+ res, err := c.Get(ts.URL + "/foo/bar")
if err != nil {
t.Fatal(err)
}
@@ -2304,10 +2385,11 @@ func TestStripPrefix(t *testing.T) {
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) {
+ setParallel(t)
defer afterTest(t)
cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
t.Fatalf("didn't expect to get request in Handler")
- }))
+ }), optQuietLog)
defer cst.close()
req, _ := NewRequest("GET", cst.ts.URL, nil)
var bytesPerHeader = len("header12345: val12345\r\n")
@@ -2350,6 +2432,7 @@ func (cr countReader) Read(p []byte) (n int, err error) {
func TestRequestBodyLimit_h1(t *testing.T) { testRequestBodyLimit(t, h1Mode) }
func TestRequestBodyLimit_h2(t *testing.T) { testRequestBodyLimit(t, h2Mode) }
func testRequestBodyLimit(t *testing.T, h2 bool) {
+ setParallel(t)
defer afterTest(t)
const limit = 1 << 20
cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
@@ -2399,14 +2482,14 @@ func TestClientWriteShutdown(t *testing.T) {
}
err = conn.(*net.TCPConn).CloseWrite()
if err != nil {
- t.Fatalf("Dial: %v", err)
+ t.Fatalf("CloseWrite: %v", err)
}
donec := make(chan bool)
go func() {
defer close(donec)
bs, err := ioutil.ReadAll(conn)
if err != nil {
- t.Fatalf("ReadAll: %v", err)
+ t.Errorf("ReadAll: %v", err)
}
got := string(bs)
if got != "" {
@@ -2445,6 +2528,7 @@ func TestServerBufferedChunking(t *testing.T) {
// closing the TCP connection, causing the client to get a RST.
// See https://golang.org/issue/3595
func TestServerGracefulClose(t *testing.T) {
+ setParallel(t)
defer afterTest(t)
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
Error(w, "bye", StatusUnauthorized)
@@ -2557,7 +2641,8 @@ func TestCloseNotifier(t *testing.T) {
go func() {
_, err = fmt.Fprintf(conn, "GET / HTTP/1.1\r\nConnection: keep-alive\r\nHost: foo\r\n\r\n")
if err != nil {
- t.Fatal(err)
+ t.Error(err)
+ return
}
<-diec
conn.Close()
@@ -2599,7 +2684,8 @@ func TestCloseNotifierPipelined(t *testing.T) {
const req = "GET / HTTP/1.1\r\nConnection: keep-alive\r\nHost: foo\r\n\r\n"
_, err = io.WriteString(conn, req+req) // two requests
if err != nil {
- t.Fatal(err)
+ t.Error(err)
+ return
}
<-diec
conn.Close()
@@ -2707,6 +2793,7 @@ func TestHijackAfterCloseNotifier(t *testing.T) {
}
func TestHijackBeforeRequestBodyRead(t *testing.T) {
+ setParallel(t)
defer afterTest(t)
var requestBody = bytes.Repeat([]byte("a"), 1<<20)
bodyOkay := make(chan bool, 1)
@@ -3028,15 +3115,18 @@ func (l *errorListener) Addr() net.Addr {
}
func TestAcceptMaxFds(t *testing.T) {
- log.SetOutput(ioutil.Discard) // is noisy otherwise
- defer log.SetOutput(os.Stderr)
+ setParallel(t)
ln := &errorListener{[]error{
&net.OpError{
Op: "accept",
Err: syscall.EMFILE,
}}}
- err := Serve(ln, HandlerFunc(HandlerFunc(func(ResponseWriter, *Request) {})))
+ server := &Server{
+ Handler: HandlerFunc(HandlerFunc(func(ResponseWriter, *Request) {})),
+ ErrorLog: log.New(ioutil.Discard, "", 0), // noisy otherwise
+ }
+ err := server.Serve(ln)
if err != io.EOF {
t.Errorf("got error %v, want EOF", err)
}
@@ -3161,6 +3251,7 @@ func TestHTTP10ConnectionHeader(t *testing.T) {
func TestServerReaderFromOrder_h1(t *testing.T) { testServerReaderFromOrder(t, h1Mode) }
func TestServerReaderFromOrder_h2(t *testing.T) { testServerReaderFromOrder(t, h2Mode) }
func testServerReaderFromOrder(t *testing.T, h2 bool) {
+ setParallel(t)
defer afterTest(t)
pr, pw := io.Pipe()
const size = 3 << 20
@@ -3265,6 +3356,7 @@ func TestTransportAndServerSharedBodyRace_h2(t *testing.T) {
testTransportAndServerSharedBodyRace(t, h2Mode)
}
func testTransportAndServerSharedBodyRace(t *testing.T, h2 bool) {
+ setParallel(t)
defer afterTest(t)
const bodySize = 1 << 20
@@ -3453,6 +3545,7 @@ func TestAppendTime(t *testing.T) {
}
func TestServerConnState(t *testing.T) {
+ setParallel(t)
defer afterTest(t)
handler := map[string]func(w ResponseWriter, r *Request){
"/": func(w ResponseWriter, r *Request) {
@@ -3500,14 +3593,39 @@ func TestServerConnState(t *testing.T) {
}
ts.Start()
- mustGet(t, ts.URL+"/")
- mustGet(t, ts.URL+"/close")
+ tr := &Transport{}
+ defer tr.CloseIdleConnections()
+ c := &Client{Transport: tr}
+
+ mustGet := func(url string, headers ...string) {
+ req, err := NewRequest("GET", url, nil)
+ if err != nil {
+ t.Fatal(err)
+ }
+ for len(headers) > 0 {
+ req.Header.Add(headers[0], headers[1])
+ headers = headers[2:]
+ }
+ res, err := c.Do(req)
+ if err != nil {
+ t.Errorf("Error fetching %s: %v", url, err)
+ return
+ }
+ _, err = ioutil.ReadAll(res.Body)
+ defer res.Body.Close()
+ if err != nil {
+ t.Errorf("Error reading %s: %v", url, err)
+ }
+ }
+
+ mustGet(ts.URL + "/")
+ mustGet(ts.URL + "/close")
- mustGet(t, ts.URL+"/")
- mustGet(t, ts.URL+"/", "Connection", "close")
+ mustGet(ts.URL + "/")
+ mustGet(ts.URL+"/", "Connection", "close")
- mustGet(t, ts.URL+"/hijack")
- mustGet(t, ts.URL+"/hijack-panic")
+ mustGet(ts.URL + "/hijack")
+ mustGet(ts.URL + "/hijack-panic")
// New->Closed
{
@@ -3587,31 +3705,10 @@ func TestServerConnState(t *testing.T) {
}
mu.Lock()
- t.Errorf("Unexpected events.\nGot log: %s\n Want: %s\n", logString(stateLog), logString(want))
+ t.Errorf("Unexpected events.\nGot log:\n%s\n Want:\n%s\n", logString(stateLog), logString(want))
mu.Unlock()
}
-func mustGet(t *testing.T, url string, headers ...string) {
- req, err := NewRequest("GET", url, nil)
- if err != nil {
- t.Fatal(err)
- }
- for len(headers) > 0 {
- req.Header.Add(headers[0], headers[1])
- headers = headers[2:]
- }
- res, err := DefaultClient.Do(req)
- if err != nil {
- t.Errorf("Error fetching %s: %v", url, err)
- return
- }
- _, err = ioutil.ReadAll(res.Body)
- defer res.Body.Close()
- if err != nil {
- t.Errorf("Error reading %s: %v", url, err)
- }
-}
-
func TestServerKeepAlivesEnabled(t *testing.T) {
defer afterTest(t)
ts := httptest.NewUnstartedServer(HandlerFunc(func(w ResponseWriter, r *Request) {}))
@@ -3632,6 +3729,7 @@ func TestServerKeepAlivesEnabled(t *testing.T) {
func TestServerEmptyBodyRace_h1(t *testing.T) { testServerEmptyBodyRace(t, h1Mode) }
func TestServerEmptyBodyRace_h2(t *testing.T) { testServerEmptyBodyRace(t, h2Mode) }
func testServerEmptyBodyRace(t *testing.T, h2 bool) {
+ setParallel(t)
defer afterTest(t)
var n int32
cst := newClientServerTest(t, h2, HandlerFunc(func(rw ResponseWriter, req *Request) {
@@ -3695,6 +3793,7 @@ func (c *closeWriteTestConn) CloseWrite() error {
}
func TestCloseWrite(t *testing.T) {
+ setParallel(t)
var srv Server
var testConn closeWriteTestConn
c := ExportServerNewConn(&srv, &testConn)
@@ -3935,6 +4034,7 @@ Host: foo
// If a Handler finishes and there's an unread request body,
// verify the server try to do implicit read on it before replying.
func TestHandlerFinishSkipBigContentLengthRead(t *testing.T) {
+ setParallel(t)
conn := &testConn{closec: make(chan bool)}
conn.readBuf.Write([]byte(fmt.Sprintf(
"POST / HTTP/1.1\r\n" +
@@ -4033,7 +4133,11 @@ func TestServerValidatesHostHeader(t *testing.T) {
io.WriteString(&conn.readBuf, methodTarget+tt.proto+"\r\n"+tt.host+"\r\n")
ln := &oneConnListener{conn}
- go Serve(ln, HandlerFunc(func(ResponseWriter, *Request) {}))
+ srv := Server{
+ ErrorLog: quietLog,
+ Handler: HandlerFunc(func(ResponseWriter, *Request) {}),
+ }
+ go srv.Serve(ln)
<-conn.closec
res, err := ReadResponse(bufio.NewReader(&conn.writeBuf), nil)
if err != nil {
@@ -4088,6 +4192,7 @@ func TestServerHandlersCanHandleH2PRI(t *testing.T) {
// Test that we validate the valid bytes in HTTP/1 headers.
// Issue 11207.
func TestServerValidatesHeaders(t *testing.T) {
+ setParallel(t)
tests := []struct {
header string
want int
@@ -4097,9 +4202,10 @@ func TestServerValidatesHeaders(t *testing.T) {
{"X-Foo: bar\r\n", 200},
{"Foo: a space\r\n", 200},
- {"A space: foo\r\n", 400}, // space in header
- {"foo\xffbar: foo\r\n", 400}, // binary in header
- {"foo\x00bar: foo\r\n", 400}, // binary in header
+ {"A space: foo\r\n", 400}, // space in header
+ {"foo\xffbar: foo\r\n", 400}, // binary in header
+ {"foo\x00bar: foo\r\n", 400}, // binary in header
+ {"Foo: " + strings.Repeat("x", 1<<21) + "\r\n", 431}, // header too large
{"foo: foo foo\r\n", 200}, // LWS space is okay
{"foo: foo\tfoo\r\n", 200}, // LWS tab is okay
@@ -4112,7 +4218,11 @@ func TestServerValidatesHeaders(t *testing.T) {
io.WriteString(&conn.readBuf, "GET / HTTP/1.1\r\nHost: foo\r\n"+tt.header+"\r\n")
ln := &oneConnListener{conn}
- go Serve(ln, HandlerFunc(func(ResponseWriter, *Request) {}))
+ srv := Server{
+ ErrorLog: quietLog,
+ Handler: HandlerFunc(func(ResponseWriter, *Request) {}),
+ }
+ go srv.Serve(ln)
<-conn.closec
res, err := ReadResponse(bufio.NewReader(&conn.writeBuf), nil)
if err != nil {
@@ -4132,6 +4242,7 @@ func TestServerRequestContextCancel_ServeHTTPDone_h2(t *testing.T) {
testServerRequestContextCancel_ServeHTTPDone(t, h2Mode)
}
func testServerRequestContextCancel_ServeHTTPDone(t *testing.T, h2 bool) {
+ setParallel(t)
defer afterTest(t)
ctxc := make(chan context.Context, 1)
cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
@@ -4157,13 +4268,12 @@ func testServerRequestContextCancel_ServeHTTPDone(t *testing.T, h2 bool) {
}
}
+// Tests that the Request.Context available to the Handler is canceled
+// if the peer closes their TCP connection. This requires that the server
+// is always blocked in a Read call so it notices the EOF from the client.
+// See issues 15927 and 15224.
func TestServerRequestContextCancel_ConnClose(t *testing.T) {
- // Currently the context is not canceled when the connection
- // is closed because we're not reading from the connection
- // until after ServeHTTP for the previous handler is done.
- // Until the server code is modified to always be in a read
- // (Issue 15224), this test doesn't work yet.
- t.Skip("TODO(bradfitz): this test doesn't yet work; golang.org/issue/15224")
+ setParallel(t)
defer afterTest(t)
inHandler := make(chan struct{})
handlerDone := make(chan struct{})
@@ -4192,7 +4302,7 @@ func TestServerRequestContextCancel_ConnClose(t *testing.T) {
select {
case <-handlerDone:
- case <-time.After(3 * time.Second):
+ case <-time.After(4 * time.Second):
t.Fatalf("timeout waiting to see ServeHTTP exit")
}
}
@@ -4204,6 +4314,7 @@ func TestServerContext_ServerContextKey_h2(t *testing.T) {
testServerContext_ServerContextKey(t, h2Mode)
}
func testServerContext_ServerContextKey(t *testing.T, h2 bool) {
+ setParallel(t)
defer afterTest(t)
cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
ctx := r.Context()
@@ -4229,6 +4340,7 @@ func testServerContext_ServerContextKey(t *testing.T, h2 bool) {
// https://golang.org/issue/15960
func TestHandlerSetTransferEncodingChunked(t *testing.T) {
+ setParallel(t)
defer afterTest(t)
ht := newHandlerTest(HandlerFunc(func(w ResponseWriter, r *Request) {
w.Header().Set("Transfer-Encoding", "chunked")
@@ -4243,6 +4355,7 @@ func TestHandlerSetTransferEncodingChunked(t *testing.T) {
// https://golang.org/issue/16063
func TestHandlerSetTransferEncodingGzip(t *testing.T) {
+ setParallel(t)
defer afterTest(t)
ht := newHandlerTest(HandlerFunc(func(w ResponseWriter, r *Request) {
w.Header().Set("Transfer-Encoding", "gzip")
@@ -4416,13 +4529,19 @@ func BenchmarkClient(b *testing.B) {
b.StopTimer()
defer afterTest(b)
- port := os.Getenv("TEST_BENCH_SERVER_PORT") // can be set by user
- if port == "" {
- port = "39207"
- }
var data = []byte("Hello world.\n")
if server := os.Getenv("TEST_BENCH_SERVER"); server != "" {
// Server process mode.
+ port := os.Getenv("TEST_BENCH_SERVER_PORT") // can be set by user
+ if port == "" {
+ port = "0"
+ }
+ ln, err := net.Listen("tcp", "localhost:"+port)
+ if err != nil {
+ fmt.Fprintln(os.Stderr, err.Error())
+ os.Exit(1)
+ }
+ fmt.Println(ln.Addr().String())
HandleFunc("/", func(w ResponseWriter, r *Request) {
r.ParseForm()
if r.Form.Get("stop") != "" {
@@ -4431,33 +4550,44 @@ func BenchmarkClient(b *testing.B) {
w.Header().Set("Content-Type", "text/html; charset=utf-8")
w.Write(data)
})
- log.Fatal(ListenAndServe("localhost:"+port, nil))
+ var srv Server
+ log.Fatal(srv.Serve(ln))
}
// Start server process.
cmd := exec.Command(os.Args[0], "-test.run=XXXX", "-test.bench=BenchmarkClient$")
cmd.Env = append(os.Environ(), "TEST_BENCH_SERVER=yes")
+ cmd.Stderr = os.Stderr
+ stdout, err := cmd.StdoutPipe()
+ if err != nil {
+ b.Fatal(err)
+ }
if err := cmd.Start(); err != nil {
b.Fatalf("subprocess failed to start: %v", err)
}
defer cmd.Process.Kill()
+
+ // Wait for the server in the child process to respond and tell us
+ // its listening address, once it's started listening:
+ timer := time.AfterFunc(10*time.Second, func() {
+ cmd.Process.Kill()
+ })
+ defer timer.Stop()
+ bs := bufio.NewScanner(stdout)
+ if !bs.Scan() {
+ b.Fatalf("failed to read listening URL from child: %v", bs.Err())
+ }
+ url := "http://" + strings.TrimSpace(bs.Text()) + "/"
+ timer.Stop()
+ if _, err := getNoBody(url); err != nil {
+ b.Fatalf("initial probe of child process failed: %v", err)
+ }
+
done := make(chan error)
go func() {
done <- cmd.Wait()
}()
- // Wait for the server process to respond.
- url := "http://localhost:" + port + "/"
- for i := 0; i < 100; i++ {
- time.Sleep(100 * time.Millisecond)
- if _, err := getNoBody(url); err == nil {
- break
- }
- if i == 99 {
- b.Fatalf("subprocess does not respond")
- }
- }
-
// Do b.N requests to the server.
b.StartTimer()
for i := 0; i < b.N; i++ {
@@ -4719,6 +4849,7 @@ func BenchmarkCloseNotifier(b *testing.B) {
// Verify this doesn't race (Issue 16505)
func TestConcurrentServerServe(t *testing.T) {
+ setParallel(t)
for i := 0; i < 100; i++ {
ln1 := &oneConnListener{conn: nil}
ln2 := &oneConnListener{conn: nil}
@@ -4727,3 +4858,183 @@ func TestConcurrentServerServe(t *testing.T) {
go func() { srv.Serve(ln2) }()
}
}
+
+func TestServerIdleTimeout(t *testing.T) {
+ if testing.Short() {
+ t.Skip("skipping in short mode")
+ }
+ setParallel(t)
+ defer afterTest(t)
+ ts := httptest.NewUnstartedServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ io.Copy(ioutil.Discard, r.Body)
+ io.WriteString(w, r.RemoteAddr)
+ }))
+ ts.Config.ReadHeaderTimeout = 1 * time.Second
+ ts.Config.IdleTimeout = 2 * time.Second
+ ts.Start()
+ defer ts.Close()
+
+ tr := &Transport{}
+ defer tr.CloseIdleConnections()
+ c := &Client{Transport: tr}
+
+ get := func() string {
+ res, err := c.Get(ts.URL)
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer res.Body.Close()
+ slurp, err := ioutil.ReadAll(res.Body)
+ if err != nil {
+ t.Fatal(err)
+ }
+ return string(slurp)
+ }
+
+ a1, a2 := get(), get()
+ if a1 != a2 {
+ t.Fatalf("did requests on different connections")
+ }
+ time.Sleep(3 * time.Second)
+ a3 := get()
+ if a2 == a3 {
+ t.Fatal("request three unexpectedly on same connection")
+ }
+
+ // And test that ReadHeaderTimeout still works:
+ conn, err := net.Dial("tcp", ts.Listener.Addr().String())
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer conn.Close()
+ conn.Write([]byte("GET / HTTP/1.1\r\nHost: foo.com\r\n"))
+ time.Sleep(2 * time.Second)
+ if _, err := io.CopyN(ioutil.Discard, conn, 1); err == nil {
+ t.Fatal("copy byte succeeded; want err")
+ }
+}
+
+func get(t *testing.T, c *Client, url string) string {
+ res, err := c.Get(url)
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer res.Body.Close()
+ slurp, err := ioutil.ReadAll(res.Body)
+ if err != nil {
+ t.Fatal(err)
+ }
+ return string(slurp)
+}
+
+// Tests that calls to Server.SetKeepAlivesEnabled(false) closes any
+// currently-open connections.
+func TestServerSetKeepAlivesEnabledClosesConns(t *testing.T) {
+ setParallel(t)
+ defer afterTest(t)
+ ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ io.WriteString(w, r.RemoteAddr)
+ }))
+ defer ts.Close()
+
+ tr := &Transport{}
+ defer tr.CloseIdleConnections()
+ c := &Client{Transport: tr}
+
+ get := func() string { return get(t, c, ts.URL) }
+
+ a1, a2 := get(), get()
+ if a1 != a2 {
+ t.Fatal("expected first two requests on same connection")
+ }
+ var idle0 int
+ if !waitCondition(2*time.Second, 10*time.Millisecond, func() bool {
+ idle0 = tr.IdleConnKeyCountForTesting()
+ return idle0 == 1
+ }) {
+ t.Fatalf("idle count before SetKeepAlivesEnabled called = %v; want 1", idle0)
+ }
+
+ ts.Config.SetKeepAlivesEnabled(false)
+
+ var idle1 int
+ if !waitCondition(2*time.Second, 10*time.Millisecond, func() bool {
+ idle1 = tr.IdleConnKeyCountForTesting()
+ return idle1 == 0
+ }) {
+ t.Fatalf("idle count after SetKeepAlivesEnabled called = %v; want 0", idle1)
+ }
+
+ a3 := get()
+ if a3 == a2 {
+ t.Fatal("expected third request on new connection")
+ }
+}
+
+func TestServerShutdown_h1(t *testing.T) { testServerShutdown(t, h1Mode) }
+func TestServerShutdown_h2(t *testing.T) { testServerShutdown(t, h2Mode) }
+
+func testServerShutdown(t *testing.T, h2 bool) {
+ setParallel(t)
+ defer afterTest(t)
+ var doShutdown func() // set later
+ var shutdownRes = make(chan error, 1)
+ cst := newClientServerTest(t, h2, 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
+ // increase the odds of a failure if shutdown has
+ // bugs.
+ time.Sleep(20 * time.Millisecond)
+ io.WriteString(w, r.RemoteAddr)
+ }))
+ defer cst.close()
+
+ doShutdown = func() {
+ shutdownRes <- cst.ts.Config.Shutdown(context.Background())
+ }
+ get(t, cst.c, cst.ts.URL) // calls t.Fail on failure
+
+ if err := <-shutdownRes; err != nil {
+ t.Fatalf("Shutdown: %v", err)
+ }
+
+ res, err := cst.c.Get(cst.ts.URL)
+ if err == nil {
+ res.Body.Close()
+ t.Fatal("second request should fail. server should be shut down")
+ }
+}
+
+// Issue 17878: tests that we can call Close twice.
+func TestServerCloseDeadlock(t *testing.T) {
+ var s Server
+ s.Close()
+ s.Close()
+}
+
+// Issue 17717: tests that Server.SetKeepAlivesEnabled is respected by
+// both HTTP/1 and HTTP/2.
+func TestServerKeepAlivesEnabled_h1(t *testing.T) { testServerKeepAlivesEnabled(t, h1Mode) }
+func TestServerKeepAlivesEnabled_h2(t *testing.T) { testServerKeepAlivesEnabled(t, h2Mode) }
+func testServerKeepAlivesEnabled(t *testing.T, h2 bool) {
+ setParallel(t)
+ defer afterTest(t)
+ cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
+ fmt.Fprintf(w, "%v", r.RemoteAddr)
+ }))
+ defer cst.close()
+ srv := cst.ts.Config
+ srv.SetKeepAlivesEnabled(false)
+ a := cst.getURL(cst.ts.URL)
+ if !waitCondition(2*time.Second, 10*time.Millisecond, srv.ExportAllConnsIdle) {
+ t.Fatalf("test server has active conns")
+ }
+ b := cst.getURL(cst.ts.URL)
+ if a == b {
+ t.Errorf("got same connection between first and second requests")
+ }
+ if !waitCondition(2*time.Second, 10*time.Millisecond, srv.ExportAllConnsIdle) {
+ t.Fatalf("test server has active conns")
+ }
+}
diff --git a/src/net/http/server.go b/src/net/http/server.go
index 89574a8..6df9c26 100644
--- a/src/net/http/server.go
+++ b/src/net/http/server.go
@@ -40,7 +40,9 @@ var (
// ErrHijacked is returned by ResponseWriter.Write calls when
// the underlying connection has been hijacked using the
- // Hijacker interfaced.
+ // Hijacker interface. A zero-byte write on a hijacked
+ // connection will return ErrHijacked without any other side
+ // effects.
ErrHijacked = errors.New("http: connection has been hijacked")
// ErrContentLength is returned by ResponseWriter.Write calls
@@ -73,7 +75,9 @@ var (
// If ServeHTTP panics, the server (the caller of ServeHTTP) assumes
// that the effect of the panic was isolated to the active request.
// It recovers the panic, logs a stack trace to the server error log,
-// and hangs up the connection.
+// and hangs up the connection. To abort a handler so the client sees
+// an interrupted response but the server doesn't log an error, panic
+// with the value ErrAbortHandler.
type Handler interface {
ServeHTTP(ResponseWriter, *Request)
}
@@ -85,11 +89,25 @@ type Handler interface {
// has returned.
type ResponseWriter interface {
// Header returns the header map that will be sent by
- // WriteHeader. Changing the header after a call to
- // WriteHeader (or Write) has no effect unless the modified
- // headers were declared as trailers by setting the
- // "Trailer" header before the call to WriteHeader (see example).
- // To suppress implicit response headers, set their value to nil.
+ // WriteHeader. The Header map also is the mechanism with which
+ // Handlers can set HTTP trailers.
+ //
+ // Changing the header map after a call to WriteHeader (or
+ // Write) has no effect unless the modified headers are
+ // trailers.
+ //
+ // There are two ways to set Trailers. The preferred way is to
+ // predeclare in the headers which trailers you will later
+ // send by setting the "Trailer" header to the names of the
+ // trailer keys which will come later. In this case, those
+ // keys of the Header map are treated as if they were
+ // trailers. See the example. The second way, for trailer
+ // keys not known to the Handler until after the first Write,
+ // is to prefix the Header map keys with the TrailerPrefix
+ // constant value. See TrailerPrefix.
+ //
+ // To suppress implicit response headers (such as "Date"), set
+ // their value to nil.
Header() Header
// Write writes the data to the connection as part of an HTTP reply.
@@ -206,6 +224,9 @@ type conn struct {
// Immutable; never nil.
server *Server
+ // cancelCtx cancels the connection-level context.
+ cancelCtx context.CancelFunc
+
// rwc is the underlying network connection.
// This is never wrapped by other types and is the value given out
// to CloseNotifier callers. It is usually of type *net.TCPConn or
@@ -232,7 +253,6 @@ type conn struct {
r *connReader
// bufr reads from r.
- // Users of bufr must hold mu.
bufr *bufio.Reader
// bufw writes to checkConnErrorWriter{c}, which populates werr on error.
@@ -242,7 +262,11 @@ type conn struct {
// on this connection, if any.
lastMethod string
- // mu guards hijackedv, use of bufr, (*response).closeNotifyCh.
+ curReq atomic.Value // of *response (which has a Request in it)
+
+ curState atomic.Value // of ConnState
+
+ // mu guards hijackedv
mu sync.Mutex
// hijackedv is whether this connection has been hijacked
@@ -262,8 +286,12 @@ func (c *conn) hijackLocked() (rwc net.Conn, buf *bufio.ReadWriter, err error) {
if c.hijackedv {
return nil, nil, ErrHijacked
}
+ c.r.abortPendingRead()
+
c.hijackedv = true
rwc = c.rwc
+ rwc.SetDeadline(time.Time{})
+
buf = bufio.NewReadWriter(c.bufr, bufio.NewWriter(rwc))
c.setState(rwc, StateHijacked)
return
@@ -346,13 +374,7 @@ func (cw *chunkWriter) close() {
bw := cw.res.conn.bufw // conn's bufio writer
// zero chunk to mark EOF
bw.WriteString("0\r\n")
- if len(cw.res.trailers) > 0 {
- trailers := make(Header)
- for _, h := range cw.res.trailers {
- if vv := cw.res.handlerHeader[h]; len(vv) > 0 {
- trailers[h] = vv
- }
- }
+ if trailers := cw.res.finalTrailers(); trailers != nil {
trailers.Write(bw) // the writer handles noting errors
}
// final blank line after the trailers (whether
@@ -413,9 +435,48 @@ type response struct {
dateBuf [len(TimeFormat)]byte
clenBuf [10]byte
- // closeNotifyCh is non-nil once CloseNotify is called.
- // Guarded by conn.mu
- closeNotifyCh <-chan bool
+ // closeNotifyCh is the channel returned by CloseNotify.
+ // TODO(bradfitz): this is currently (for Go 1.8) always
+ // non-nil. Make this lazily-created again as it used to be?
+ closeNotifyCh chan bool
+ didCloseNotify int32 // atomic (only 0->1 winner should send)
+}
+
+// TrailerPrefix is a magic prefix for ResponseWriter.Header map keys
+// that, if present, signals that the map entry is actually for
+// the response trailers, and not the response headers. The prefix
+// is stripped after the ServeHTTP call finishes and the values are
+// sent in the trailers.
+//
+// This mechanism is intended only for trailers that are not known
+// prior to the headers being written. If the set of trailers is fixed
+// or known before the header is written, the normal Go trailers mechanism
+// is preferred:
+// https://golang.org/pkg/net/http/#ResponseWriter
+// https://golang.org/pkg/net/http/#example_ResponseWriter_trailers
+const TrailerPrefix = "Trailer:"
+
+// finalTrailers is called after the Handler exits and returns a non-nil
+// value if the Handler set any trailers.
+func (w *response) finalTrailers() Header {
+ var t Header
+ for k, vv := range w.handlerHeader {
+ if strings.HasPrefix(k, TrailerPrefix) {
+ if t == nil {
+ t = make(Header)
+ }
+ t[strings.TrimPrefix(k, TrailerPrefix)] = vv
+ }
+ }
+ for _, k := range w.trailers {
+ if t == nil {
+ t = make(Header)
+ }
+ for _, v := range w.handlerHeader[k] {
+ t.Add(k, v)
+ }
+ }
+ return t
}
type atomicBool int32
@@ -548,60 +609,148 @@ type readResult struct {
// call blocked in a background goroutine to wait for activity and
// trigger a CloseNotifier channel.
type connReader struct {
- r io.Reader
- remain int64 // bytes remaining
+ conn *conn
+
+ 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
+ remain int64 // bytes remaining
+}
+
+func (cr *connReader) lock() {
+ cr.mu.Lock()
+ if cr.cond == nil {
+ cr.cond = sync.NewCond(&cr.mu)
+ }
+}
+
+func (cr *connReader) unlock() { cr.mu.Unlock() }
+
+func (cr *connReader) startBackgroundRead() {
+ cr.lock()
+ defer cr.unlock()
+ if cr.inRead {
+ panic("invalid concurrent Body.Read call")
+ }
+ cr.inRead = true
+ go cr.backgroundRead()
+}
+
+func (cr *connReader) backgroundRead() {
+ n, err := cr.conn.rwc.Read(cr.byteBuf[:])
+ cr.lock()
+ if n == 1 {
+ cr.hasByte = true
+ // We were at EOF already (since we wouldn't be in a
+ // background read otherwise), so this is a pipelined
+ // HTTP request.
+ cr.closeNotifyFromPipelinedRequest()
+ }
+ if ne, ok := err.(net.Error); ok && cr.aborted && ne.Timeout() {
+ // Ignore this error. It's the expected error from
+ // another goroutine calling abortPendingRead.
+ } else if err != nil {
+ cr.handleReadError(err)
+ }
+ cr.aborted = false
+ cr.inRead = false
+ cr.unlock()
+ cr.cond.Broadcast()
+}
- // ch is non-nil if a background read is in progress.
- // It is guarded by conn.mu.
- ch chan readResult
+func (cr *connReader) abortPendingRead() {
+ cr.lock()
+ defer cr.unlock()
+ if !cr.inRead {
+ return
+ }
+ cr.aborted = true
+ cr.conn.rwc.SetReadDeadline(aLongTimeAgo)
+ for cr.inRead {
+ cr.cond.Wait()
+ }
+ cr.conn.rwc.SetReadDeadline(time.Time{})
}
func (cr *connReader) setReadLimit(remain int64) { cr.remain = remain }
func (cr *connReader) setInfiniteReadLimit() { cr.remain = maxInt64 }
func (cr *connReader) hitReadLimit() bool { return cr.remain <= 0 }
+// may be called from multiple goroutines.
+func (cr *connReader) handleReadError(err error) {
+ cr.conn.cancelCtx()
+ cr.closeNotify()
+}
+
+// closeNotifyFromPipelinedRequest simply calls closeNotify.
+//
+// This method wrapper is here for documentation. The callers are the
+// cases where we send on the closenotify channel because of a
+// pipelined HTTP request, per the previous Go behavior and
+// documentation (that this "MAY" happen).
+//
+// TODO: consider changing this behavior and making context
+// cancelation and closenotify work the same.
+func (cr *connReader) closeNotifyFromPipelinedRequest() {
+ cr.closeNotify()
+}
+
+// may be called from multiple goroutines.
+func (cr *connReader) closeNotify() {
+ res, _ := cr.conn.curReq.Load().(*response)
+ if res != nil {
+ if atomic.CompareAndSwapInt32(&res.didCloseNotify, 0, 1) {
+ res.closeNotifyCh <- true
+ }
+ }
+}
+
func (cr *connReader) Read(p []byte) (n int, err error) {
+ cr.lock()
+ if cr.inRead {
+ cr.unlock()
+ panic("invalid concurrent Body.Read call")
+ }
if cr.hitReadLimit() {
+ cr.unlock()
return 0, io.EOF
}
+ if cr.bgErr != nil {
+ err = cr.bgErr
+ cr.unlock()
+ return 0, err
+ }
if len(p) == 0 {
- return
+ cr.unlock()
+ return 0, nil
}
if int64(len(p)) > cr.remain {
p = p[:cr.remain]
}
-
- // Is a background read (started by CloseNotifier) already in
- // flight? If so, wait for it and use its result.
- ch := cr.ch
- if ch != nil {
- cr.ch = nil
- res := <-ch
- if res.n == 1 {
- p[0] = res.b
- cr.remain -= 1
- }
- return res.n, res.err
+ if cr.hasByte {
+ p[0] = cr.byteBuf[0]
+ cr.hasByte = false
+ cr.unlock()
+ return 1, nil
}
- n, err = cr.r.Read(p)
- cr.remain -= int64(n)
- return
-}
+ cr.inRead = true
+ cr.unlock()
+ n, err = cr.conn.rwc.Read(p)
-func (cr *connReader) startBackgroundRead(onReadComplete func()) {
- if cr.ch != nil {
- // Background read already started.
- return
+ cr.lock()
+ cr.inRead = false
+ if err != nil {
+ cr.handleReadError(err)
}
- cr.ch = make(chan readResult, 1)
- go cr.closeNotifyAwaitActivityRead(cr.ch, onReadComplete)
-}
+ cr.remain -= int64(n)
+ cr.unlock()
-func (cr *connReader) closeNotifyAwaitActivityRead(ch chan<- readResult, onReadComplete func()) {
- var buf [1]byte
- n, err := cr.r.Read(buf[:1])
- onReadComplete()
- ch <- readResult{n, err, buf[0]}
+ cr.cond.Broadcast()
+ return n, err
}
var (
@@ -633,7 +782,7 @@ func newBufioReader(r io.Reader) *bufio.Reader {
br.Reset(r)
return br
}
- // Note: if this reader size is every changed, update
+ // Note: if this reader size is ever changed, update
// TestHandlerBodyClose's assumptions.
return bufio.NewReader(r)
}
@@ -746,9 +895,18 @@ func (c *conn) readRequest(ctx context.Context) (w *response, err error) {
return nil, ErrHijacked
}
+ var (
+ wholeReqDeadline time.Time // or zero if none
+ hdrDeadline time.Time // or zero if none
+ )
+ t0 := time.Now()
+ if d := c.server.readHeaderTimeout(); d != 0 {
+ hdrDeadline = t0.Add(d)
+ }
if d := c.server.ReadTimeout; d != 0 {
- c.rwc.SetReadDeadline(time.Now().Add(d))
+ wholeReqDeadline = t0.Add(d)
}
+ c.rwc.SetReadDeadline(hdrDeadline)
if d := c.server.WriteTimeout; d != 0 {
defer func() {
c.rwc.SetWriteDeadline(time.Now().Add(d))
@@ -756,14 +914,12 @@ func (c *conn) readRequest(ctx context.Context) (w *response, err error) {
}
c.r.setReadLimit(c.server.initialReadLimitSize())
- c.mu.Lock() // while using bufr
if c.lastMethod == "POST" {
// RFC 2616 section 4.1 tolerance for old buggy clients.
peek, _ := c.bufr.Peek(4) // ReadRequest will get err below
c.bufr.Discard(numLeadingCRorLF(peek))
}
req, err := readRequest(c.bufr, keepHostHeader)
- c.mu.Unlock()
if err != nil {
if c.r.hitReadLimit() {
return nil, errTooLarge
@@ -809,6 +965,11 @@ func (c *conn) readRequest(ctx context.Context) (w *response, err error) {
body.doEarlyClose = true
}
+ // Adjust the read deadline if necessary.
+ if !hdrDeadline.Equal(wholeReqDeadline) {
+ c.rwc.SetReadDeadline(wholeReqDeadline)
+ }
+
w = &response{
conn: c,
cancelCtx: cancelCtx,
@@ -816,6 +977,7 @@ func (c *conn) readRequest(ctx context.Context) (w *response, err error) {
reqBody: req.Body,
handlerHeader: make(Header),
contentLength: -1,
+ closeNotifyCh: make(chan bool, 1),
// We populate these ahead of time so we're not
// reading from req.Header after their Handler starts
@@ -990,7 +1152,17 @@ func (cw *chunkWriter) writeHeader(p []byte) {
}
var setHeader extraHeader
+ // Don't write out the fake "Trailer:foo" keys. See TrailerPrefix.
trailers := false
+ for k := range cw.header {
+ if strings.HasPrefix(k, TrailerPrefix) {
+ if excludeHeader == nil {
+ excludeHeader = make(map[string]bool)
+ }
+ excludeHeader[k] = true
+ trailers = true
+ }
+ }
for _, v := range cw.header["Trailer"] {
trailers = true
foreachHeaderElement(v, cw.res.declareTrailer)
@@ -1318,7 +1490,9 @@ func (w *response) WriteString(data string) (n int, err error) {
// either dataB or dataS is non-zero.
func (w *response) write(lenData int, dataB []byte, dataS string) (n int, err error) {
if w.conn.hijacked() {
- w.conn.server.logf("http: response.Write on hijacked connection")
+ if lenData > 0 {
+ w.conn.server.logf("http: response.Write on hijacked connection")
+ }
return 0, ErrHijacked
}
if !w.wroteHeader {
@@ -1354,6 +1528,8 @@ func (w *response) finishRequest() {
w.cw.close()
w.conn.bufw.Flush()
+ w.conn.r.abortPendingRead()
+
// Close the body (regardless of w.closeAfterReply) so we can
// re-use its bufio.Reader later safely.
w.reqBody.Close()
@@ -1469,11 +1645,30 @@ func validNPN(proto string) bool {
}
func (c *conn) setState(nc net.Conn, state ConnState) {
- if hook := c.server.ConnState; hook != nil {
+ srv := c.server
+ switch state {
+ case StateNew:
+ srv.trackConn(c, true)
+ case StateHijacked, StateClosed:
+ srv.trackConn(c, false)
+ }
+ c.curState.Store(connStateInterface[state])
+ if hook := srv.ConnState; hook != nil {
hook(nc, state)
}
}
+// connStateInterface is an array of the interface{} versions of
+// ConnState values, so we can use them in atomic.Values later without
+// paying the cost of shoving their integers in an interface{}.
+var connStateInterface = [...]interface{}{
+ StateNew: StateNew,
+ StateActive: StateActive,
+ StateIdle: StateIdle,
+ StateHijacked: StateHijacked,
+ StateClosed: StateClosed,
+}
+
// badRequestError is a literal string (used by in the server in HTML,
// unescaped) to tell the user why their request was bad. It should
// be plain text without user info or other embedded errors.
@@ -1481,11 +1676,34 @@ type badRequestError string
func (e badRequestError) Error() string { return "Bad Request: " + string(e) }
+// ErrAbortHandler is a sentinel panic value to abort a handler.
+// While any panic from ServeHTTP aborts the response to the client,
+// panicking with ErrAbortHandler also suppresses logging of a stack
+// trace to the server's error log.
+var ErrAbortHandler = errors.New("net/http: abort Handler")
+
+// isCommonNetReadError reports whether err is a common error
+// encountered during reading a request off the network when the
+// client has gone away or had its read fail somehow. This is used to
+// determine which logs are interesting enough to log about.
+func isCommonNetReadError(err error) bool {
+ if err == io.EOF {
+ return true
+ }
+ if neterr, ok := err.(net.Error); ok && neterr.Timeout() {
+ return true
+ }
+ if oe, ok := err.(*net.OpError); ok && oe.Op == "read" {
+ return true
+ }
+ return false
+}
+
// Serve a new connection.
func (c *conn) serve(ctx context.Context) {
c.remoteAddr = c.rwc.RemoteAddr().String()
defer func() {
- if err := recover(); err != nil {
+ if err := recover(); err != nil && err != ErrAbortHandler {
const size = 64 << 10
buf := make([]byte, size)
buf = buf[:runtime.Stack(buf, false)]
@@ -1521,13 +1739,14 @@ func (c *conn) serve(ctx context.Context) {
// HTTP/1.x from here on.
- c.r = &connReader{r: c.rwc}
- c.bufr = newBufioReader(c.r)
- c.bufw = newBufioWriterSize(checkConnErrorWriter{c}, 4<<10)
-
ctx, cancelCtx := context.WithCancel(ctx)
+ c.cancelCtx = cancelCtx
defer cancelCtx()
+ c.r = &connReader{conn: c}
+ c.bufr = newBufioReader(c.r)
+ c.bufw = newBufioWriterSize(checkConnErrorWriter{c}, 4<<10)
+
for {
w, err := c.readRequest(ctx)
if c.r.remain != c.server.initialReadLimitSize() {
@@ -1535,27 +1754,29 @@ func (c *conn) serve(ctx context.Context) {
c.setState(c.rwc, StateActive)
}
if err != nil {
+ const errorHeaders = "\r\nContent-Type: text/plain; charset=utf-8\r\nConnection: close\r\n\r\n"
+
if err == errTooLarge {
// Their HTTP client may or may not be
// able to read this if we're
// responding to them and hanging up
// while they're still writing their
// request. Undefined behavior.
- io.WriteString(c.rwc, "HTTP/1.1 431 Request Header Fields Too Large\r\nContent-Type: text/plain\r\nConnection: close\r\n\r\n431 Request Header Fields Too Large")
+ const publicErr = "431 Request Header Fields Too Large"
+ fmt.Fprintf(c.rwc, "HTTP/1.1 "+publicErr+errorHeaders+publicErr)
c.closeWriteAndWait()
return
}
- if err == io.EOF {
- return // don't reply
- }
- if neterr, ok := err.(net.Error); ok && neterr.Timeout() {
+ if isCommonNetReadError(err) {
return // don't reply
}
- var publicErr string
+
+ publicErr := "400 Bad Request"
if v, ok := err.(badRequestError); ok {
- publicErr = ": " + string(v)
+ publicErr = publicErr + ": " + string(v)
}
- io.WriteString(c.rwc, "HTTP/1.1 400 Bad Request\r\nContent-Type: text/plain\r\nConnection: close\r\n\r\n400 Bad Request"+publicErr)
+
+ fmt.Fprintf(c.rwc, "HTTP/1.1 "+publicErr+errorHeaders+publicErr)
return
}
@@ -1571,11 +1792,24 @@ func (c *conn) serve(ctx context.Context) {
return
}
+ c.curReq.Store(w)
+
+ if requestBodyRemains(req.Body) {
+ registerOnHitEOF(req.Body, w.conn.r.startBackgroundRead)
+ } else {
+ if w.conn.bufr.Buffered() > 0 {
+ w.conn.r.closeNotifyFromPipelinedRequest()
+ }
+ w.conn.r.startBackgroundRead()
+ }
+
// HTTP cannot have multiple simultaneous active requests.[*]
// Until the server replies to this request, it can't read another,
// so we might as well run the handler in this goroutine.
// [*] Not strictly true: HTTP pipelining. We could let them all process
// in parallel even if their responses need to be serialized.
+ // But we're not going to implement HTTP pipelining because it
+ // was never deployed in the wild and the answer is HTTP/2.
serverHandler{c.server}.ServeHTTP(w, w.req)
w.cancelCtx()
if c.hijacked() {
@@ -1589,6 +1823,23 @@ func (c *conn) serve(ctx context.Context) {
return
}
c.setState(c.rwc, StateIdle)
+ c.curReq.Store((*response)(nil))
+
+ if !w.conn.server.doKeepAlives() {
+ // We're in shutdown mode. We might've replied
+ // to the user without "Connection: close" and
+ // they might think they can send another
+ // request, but such is life with HTTP/1.1.
+ return
+ }
+
+ if d := c.server.idleTimeout(); d != 0 {
+ c.rwc.SetReadDeadline(time.Now().Add(d))
+ if _, err := c.bufr.Peek(4); err != nil {
+ return
+ }
+ }
+ c.rwc.SetReadDeadline(time.Time{})
}
}
@@ -1624,10 +1875,6 @@ func (w *response) Hijack() (rwc net.Conn, buf *bufio.ReadWriter, err error) {
c.mu.Lock()
defer c.mu.Unlock()
- if w.closeNotifyCh != nil {
- return nil, nil, errors.New("http: Hijack is incompatible with use of CloseNotifier in same ServeHTTP call")
- }
-
// Release the bufioWriter that writes to the chunk writer, it is not
// used after a connection has been hijacked.
rwc, buf, err = c.hijackLocked()
@@ -1642,50 +1889,7 @@ func (w *response) CloseNotify() <-chan bool {
if w.handlerDone.isSet() {
panic("net/http: CloseNotify called after ServeHTTP finished")
}
- c := w.conn
- c.mu.Lock()
- defer c.mu.Unlock()
-
- if w.closeNotifyCh != nil {
- return w.closeNotifyCh
- }
- ch := make(chan bool, 1)
- w.closeNotifyCh = ch
-
- if w.conn.hijackedv {
- // CloseNotify is undefined after a hijack, but we have
- // no place to return an error, so just return a channel,
- // even though it'll never receive a value.
- return ch
- }
-
- var once sync.Once
- notify := func() { once.Do(func() { ch <- true }) }
-
- if requestBodyRemains(w.reqBody) {
- // They're still consuming the request body, so we
- // shouldn't notify yet.
- registerOnHitEOF(w.reqBody, func() {
- c.mu.Lock()
- defer c.mu.Unlock()
- startCloseNotifyBackgroundRead(c, notify)
- })
- } else {
- startCloseNotifyBackgroundRead(c, notify)
- }
- return ch
-}
-
-// c.mu must be held.
-func startCloseNotifyBackgroundRead(c *conn, notify func()) {
- if c.bufr.Buffered() > 0 {
- // They've consumed the request body, so anything
- // remaining is a pipelined request, which we
- // document as firing on.
- notify()
- } else {
- c.r.startBackgroundRead(notify)
- }
+ return w.closeNotifyCh
}
func registerOnHitEOF(rc io.ReadCloser, fn func()) {
@@ -1702,7 +1906,7 @@ func registerOnHitEOF(rc io.ReadCloser, fn func()) {
// requestBodyRemains reports whether future calls to Read
// on rc might yield more data.
func requestBodyRemains(rc io.ReadCloser) bool {
- if rc == eofReader {
+ if rc == NoBody {
return false
}
switch v := rc.(type) {
@@ -1816,7 +2020,7 @@ func Redirect(w ResponseWriter, r *Request, urlStr string, code int) {
}
}
- w.Header().Set("Location", urlStr)
+ w.Header().Set("Location", hexEscapeNonASCII(urlStr))
w.WriteHeader(code)
// RFC 2616 recommends that a short note "SHOULD" be included in the
@@ -2094,11 +2298,36 @@ func Serve(l net.Listener, handler Handler) error {
// A Server defines parameters for running an HTTP server.
// The zero value for Server is a valid configuration.
type Server struct {
- Addr string // TCP address to listen on, ":http" if empty
- Handler Handler // handler to invoke, http.DefaultServeMux if nil
- ReadTimeout time.Duration // maximum duration before timing out read of the request
- WriteTimeout time.Duration // maximum duration before timing out write of the response
- TLSConfig *tls.Config // optional TLS config, used by ListenAndServeTLS
+ Addr string // TCP address to listen on, ":http" if empty
+ Handler Handler // handler to invoke, http.DefaultServeMux if nil
+ TLSConfig *tls.Config // optional TLS config, used by ListenAndServeTLS
+
+ // ReadTimeout is the maximum duration for reading the entire
+ // request, including the body.
+ //
+ // Because ReadTimeout does not let Handlers make per-request
+ // decisions on each request body's acceptable deadline or
+ // upload rate, most users will prefer to use
+ // ReadHeaderTimeout. It is valid to use them both.
+ ReadTimeout time.Duration
+
+ // ReadHeaderTimeout is the amount of time allowed to read
+ // request headers. The connection's read deadline is reset
+ // after reading the headers and the Handler can decide what
+ // is considered too slow for the body.
+ ReadHeaderTimeout time.Duration
+
+ // WriteTimeout is the maximum duration before timing out
+ // writes of the response. It is reset whenever a new
+ // request's header is read. Like ReadTimeout, it does not
+ // let Handlers make decisions on a per-request basis.
+ WriteTimeout time.Duration
+
+ // IdleTimeout is the maximum amount of time to wait for the
+ // next request when keep-alives are enabled. If IdleTimeout
+ // is zero, the value of ReadTimeout is used. If both are
+ // zero, there is no timeout.
+ IdleTimeout time.Duration
// MaxHeaderBytes controls the maximum number of bytes the
// server will read parsing the request header's keys and
@@ -2114,7 +2343,8 @@ type Server struct {
// handle HTTP requests and will initialize the Request's TLS
// and RemoteAddr if not already set. The connection is
// automatically closed when the function returns.
- // If TLSNextProto is nil, HTTP/2 support is enabled automatically.
+ // If TLSNextProto is not nil, HTTP/2 support is not enabled
+ // automatically.
TLSNextProto map[string]func(*Server, *tls.Conn, Handler)
// ConnState specifies an optional callback function that is
@@ -2129,8 +2359,132 @@ type Server struct {
ErrorLog *log.Logger
disableKeepAlives int32 // accessed atomically.
+ inShutdown int32 // accessed atomically (non-zero means we're in Shutdown)
nextProtoOnce sync.Once // guards setupHTTP2_* init
nextProtoErr error // result of http2.ConfigureServer if used
+
+ mu sync.Mutex
+ listeners map[net.Listener]struct{}
+ activeConn map[*conn]struct{}
+ doneChan chan struct{}
+}
+
+func (s *Server) getDoneChan() <-chan struct{} {
+ s.mu.Lock()
+ defer s.mu.Unlock()
+ return s.getDoneChanLocked()
+}
+
+func (s *Server) getDoneChanLocked() chan struct{} {
+ if s.doneChan == nil {
+ s.doneChan = make(chan struct{})
+ }
+ return s.doneChan
+}
+
+func (s *Server) closeDoneChanLocked() {
+ ch := s.getDoneChanLocked()
+ select {
+ case <-ch:
+ // Already closed. Don't close again.
+ default:
+ // Safe to close here. We're the only closer, guarded
+ // by s.mu.
+ close(ch)
+ }
+}
+
+// Close immediately closes all active net.Listeners and any
+// connections in state StateNew, StateActive, or StateIdle. For a
+// graceful shutdown, use Shutdown.
+//
+// Close does not attempt to close (and does not even know about)
+// any hijacked connections, such as WebSockets.
+//
+// Close returns any error returned from closing the Server's
+// underlying Listener(s).
+func (srv *Server) Close() error {
+ srv.mu.Lock()
+ defer srv.mu.Unlock()
+ srv.closeDoneChanLocked()
+ err := srv.closeListenersLocked()
+ for c := range srv.activeConn {
+ c.rwc.Close()
+ delete(srv.activeConn, c)
+ }
+ return err
+}
+
+// shutdownPollInterval is how often we poll for quiescence
+// during Server.Shutdown. This is lower during tests, to
+// speed up tests.
+// Ideally we could find a solution that doesn't involve polling,
+// but which also doesn't have a high runtime cost (and doesn't
+// involve any contentious mutexes), but that is left as an
+// exercise for the reader.
+var shutdownPollInterval = 500 * time.Millisecond
+
+// Shutdown gracefully shuts down the server without interrupting any
+// active connections. Shutdown works by first closing all open
+// 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 does not attempt to close nor wait for hijacked
+// connections such as WebSockets. The caller of Shutdown should
+// separately notify such long-lived connections of shutdown and wait
+// for them to close, if desired.
+func (srv *Server) Shutdown(ctx context.Context) error {
+ atomic.AddInt32(&srv.inShutdown, 1)
+ defer atomic.AddInt32(&srv.inShutdown, -1)
+
+ srv.mu.Lock()
+ lnerr := srv.closeListenersLocked()
+ srv.closeDoneChanLocked()
+ srv.mu.Unlock()
+
+ ticker := time.NewTicker(shutdownPollInterval)
+ defer ticker.Stop()
+ for {
+ if srv.closeIdleConns() {
+ return lnerr
+ }
+ select {
+ case <-ctx.Done():
+ return ctx.Err()
+ case <-ticker.C:
+ }
+ }
+}
+
+// closeIdleConns closes all idle connections and reports whether the
+// server is quiescent.
+func (s *Server) closeIdleConns() bool {
+ s.mu.Lock()
+ defer s.mu.Unlock()
+ quiescent := true
+ for c := range s.activeConn {
+ st, ok := c.curState.Load().(ConnState)
+ if !ok || st != StateIdle {
+ quiescent = false
+ continue
+ }
+ c.rwc.Close()
+ delete(s.activeConn, c)
+ }
+ return quiescent
+}
+
+func (s *Server) closeListenersLocked() error {
+ var err error
+ for ln := range s.listeners {
+ if cerr := ln.Close(); cerr != nil && err == nil {
+ err = cerr
+ }
+ delete(s.listeners, ln)
+ }
+ return err
}
// A ConnState represents the state of a client connection to a server.
@@ -2243,6 +2597,8 @@ func (srv *Server) shouldConfigureHTTP2ForServe() bool {
return strSliceContains(srv.TLSConfig.NextProtos, http2NextProtoTLS)
}
+var ErrServerClosed = errors.New("http: Server closed")
+
// Serve accepts incoming connections on the Listener l, creating a
// new service goroutine for each. The service goroutines read requests and
// then call srv.Handler to reply to them.
@@ -2252,7 +2608,8 @@ func (srv *Server) shouldConfigureHTTP2ForServe() bool {
// srv.TLSConfig is non-nil and doesn't include the string "h2" in
// Config.NextProtos, HTTP/2 support is not enabled.
//
-// Serve always returns a non-nil error.
+// Serve always returns a non-nil error. After Shutdown or Close, the
+// returned error is ErrServerClosed.
func (srv *Server) Serve(l net.Listener) error {
defer l.Close()
if fn := testHookServerServe; fn != nil {
@@ -2264,14 +2621,20 @@ func (srv *Server) Serve(l net.Listener) error {
return err
}
- // TODO: allow changing base context? can't imagine concrete
- // use cases yet.
- baseCtx := context.Background()
+ srv.trackListener(l, true)
+ defer srv.trackListener(l, false)
+
+ 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 {
+ select {
+ case <-srv.getDoneChan():
+ return ErrServerClosed
+ default:
+ }
if ne, ok := e.(net.Error); ok && ne.Temporary() {
if tempDelay == 0 {
tempDelay = 5 * time.Millisecond
@@ -2294,8 +2657,57 @@ func (srv *Server) Serve(l net.Listener) error {
}
}
+func (s *Server) trackListener(ln net.Listener, add bool) {
+ s.mu.Lock()
+ defer s.mu.Unlock()
+ if s.listeners == nil {
+ s.listeners = make(map[net.Listener]struct{})
+ }
+ if add {
+ // If the *Server is being reused after a previous
+ // Close or Shutdown, reset its doneChan:
+ if len(s.listeners) == 0 && len(s.activeConn) == 0 {
+ s.doneChan = nil
+ }
+ s.listeners[ln] = struct{}{}
+ } else {
+ delete(s.listeners, ln)
+ }
+}
+
+func (s *Server) trackConn(c *conn, add bool) {
+ s.mu.Lock()
+ defer s.mu.Unlock()
+ if s.activeConn == nil {
+ s.activeConn = make(map[*conn]struct{})
+ }
+ if add {
+ s.activeConn[c] = struct{}{}
+ } else {
+ delete(s.activeConn, c)
+ }
+}
+
+func (s *Server) idleTimeout() time.Duration {
+ if s.IdleTimeout != 0 {
+ return s.IdleTimeout
+ }
+ return s.ReadTimeout
+}
+
+func (s *Server) readHeaderTimeout() time.Duration {
+ if s.ReadHeaderTimeout != 0 {
+ return s.ReadHeaderTimeout
+ }
+ return s.ReadTimeout
+}
+
func (s *Server) doKeepAlives() bool {
- return atomic.LoadInt32(&s.disableKeepAlives) == 0
+ return atomic.LoadInt32(&s.disableKeepAlives) == 0 && !s.shuttingDown()
+}
+
+func (s *Server) shuttingDown() bool {
+ return atomic.LoadInt32(&s.inShutdown) != 0
}
// SetKeepAlivesEnabled controls whether HTTP keep-alives are enabled.
@@ -2305,9 +2717,21 @@ func (s *Server) doKeepAlives() bool {
func (srv *Server) SetKeepAlivesEnabled(v bool) {
if v {
atomic.StoreInt32(&srv.disableKeepAlives, 0)
- } else {
- atomic.StoreInt32(&srv.disableKeepAlives, 1)
+ return
}
+ atomic.StoreInt32(&srv.disableKeepAlives, 1)
+
+ // Close idle HTTP/1 conns:
+ srv.closeIdleConns()
+
+ // Close HTTP/2 conns, as soon as they become idle, but reset
+ // the chan so future conns (if the listener is still active)
+ // still work and don't get a GOAWAY immediately, before their
+ // first request:
+ srv.mu.Lock()
+ defer srv.mu.Unlock()
+ srv.closeDoneChanLocked() // closes http2 conns
+ srv.doneChan = nil
}
func (s *Server) logf(format string, args ...interface{}) {
@@ -2630,24 +3054,6 @@ func (globalOptionsHandler) ServeHTTP(w ResponseWriter, r *Request) {
}
}
-type eofReaderWithWriteTo struct{}
-
-func (eofReaderWithWriteTo) WriteTo(io.Writer) (int64, error) { return 0, nil }
-func (eofReaderWithWriteTo) Read([]byte) (int, error) { return 0, io.EOF }
-
-// eofReader is a non-nil io.ReadCloser that always returns EOF.
-// It has a WriteTo method so io.Copy won't need a buffer.
-var eofReader = &struct {
- eofReaderWithWriteTo
- io.Closer
-}{
- eofReaderWithWriteTo{},
- ioutil.NopCloser(nil),
-}
-
-// Verify that an io.Copy from an eofReader won't require a buffer.
-var _ io.WriterTo = eofReader
-
// initNPNRequest is an HTTP handler that initializes certain
// uninitialized fields in its *Request. Such partially-initialized
// Requests come from NPN protocol handlers.
@@ -2662,7 +3068,7 @@ func (h initNPNRequest) ServeHTTP(rw ResponseWriter, req *Request) {
*req.TLS = h.c.ConnectionState()
}
if req.Body == nil {
- req.Body = eofReader
+ req.Body = NoBody
}
if req.RemoteAddr == "" {
req.RemoteAddr = h.c.RemoteAddr().String()
@@ -2723,6 +3129,7 @@ func (w checkConnErrorWriter) Write(p []byte) (n int, err error) {
n, err = w.c.rwc.Write(p)
if err != nil && w.c.werr == nil {
w.c.werr = err
+ w.c.cancelCtx()
}
return
}
diff --git a/src/net/http/sniff_test.go b/src/net/http/sniff_test.go
index ac404bf..38f3f81 100644
--- a/src/net/http/sniff_test.go
+++ b/src/net/http/sniff_test.go
@@ -66,6 +66,7 @@ func TestServerContentType_h1(t *testing.T) { testServerContentType(t, h1Mode) }
func TestServerContentType_h2(t *testing.T) { testServerContentType(t, h2Mode) }
func testServerContentType(t *testing.T, h2 bool) {
+ setParallel(t)
defer afterTest(t)
cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
i, _ := strconv.Atoi(r.FormValue("i"))
@@ -160,6 +161,7 @@ func testContentTypeWithCopy(t *testing.T, h2 bool) {
func TestSniffWriteSize_h1(t *testing.T) { testSniffWriteSize(t, h1Mode) }
func TestSniffWriteSize_h2(t *testing.T) { testSniffWriteSize(t, h2Mode) }
func testSniffWriteSize(t *testing.T, h2 bool) {
+ setParallel(t)
defer afterTest(t)
cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
size, _ := strconv.Atoi(r.FormValue("size"))
diff --git a/src/net/http/transfer.go b/src/net/http/transfer.go
index c653467..beafb7a 100644
--- a/src/net/http/transfer.go
+++ b/src/net/http/transfer.go
@@ -59,37 +59,18 @@ func newTransferWriter(r interface{}) (t *transferWriter, err error) {
return nil, fmt.Errorf("http: Request.ContentLength=%d with nil Body", rr.ContentLength)
}
t.Method = valueOrDefault(rr.Method, "GET")
- t.Body = rr.Body
- t.BodyCloser = rr.Body
- t.ContentLength = rr.ContentLength
t.Close = rr.Close
t.TransferEncoding = rr.TransferEncoding
t.Trailer = rr.Trailer
atLeastHTTP11 = rr.ProtoAtLeast(1, 1)
- if t.Body != nil && len(t.TransferEncoding) == 0 && atLeastHTTP11 {
- if t.ContentLength == 0 {
- // Test to see if it's actually zero or just unset.
- var buf [1]byte
- n, rerr := io.ReadFull(t.Body, buf[:])
- if rerr != nil && rerr != io.EOF {
- t.ContentLength = -1
- t.Body = errorReader{rerr}
- } else if n == 1 {
- // Oh, guess there is data in this Body Reader after all.
- // The ContentLength field just wasn't set.
- // Stich the Body back together again, re-attaching our
- // consumed byte.
- t.ContentLength = -1
- t.Body = io.MultiReader(bytes.NewReader(buf[:]), t.Body)
- } else {
- // Body is actually empty.
- t.Body = nil
- t.BodyCloser = nil
- }
- }
- if t.ContentLength < 0 {
- t.TransferEncoding = []string{"chunked"}
- }
+
+ t.Body = rr.Body
+ t.ContentLength = rr.outgoingLength()
+ if t.Body != nil {
+ t.BodyCloser = rr.Body
+ }
+ if t.ContentLength < 0 && len(t.TransferEncoding) == 0 && atLeastHTTP11 {
+ t.TransferEncoding = []string{"chunked"}
}
case *Response:
t.IsResponse = true
@@ -214,7 +195,7 @@ func (t *transferWriter) WriteBody(w io.Writer) error {
if t.Body != nil {
if chunked(t.TransferEncoding) {
if bw, ok := w.(*bufio.Writer); ok && !t.IsResponse {
- w = &internal.FlushAfterChunkWriter{bw}
+ w = &internal.FlushAfterChunkWriter{Writer: bw}
}
cw := internal.NewChunkedWriter(w)
_, err = io.Copy(cw, t.Body)
@@ -386,12 +367,12 @@ func readTransfer(msg interface{}, r *bufio.Reader) (err error) {
switch {
case chunked(t.TransferEncoding):
if noBodyExpected(t.RequestMethod) {
- t.Body = eofReader
+ t.Body = NoBody
} else {
t.Body = &body{src: internal.NewChunkedReader(r), hdr: msg, r: r, closing: t.Close}
}
case realLength == 0:
- t.Body = eofReader
+ t.Body = NoBody
case realLength > 0:
t.Body = &body{src: io.LimitReader(r, realLength), closing: t.Close}
default:
@@ -401,7 +382,7 @@ func readTransfer(msg interface{}, r *bufio.Reader) (err error) {
t.Body = &body{src: r, closing: t.Close}
} else {
// Persistent connection (i.e. HTTP/1.1)
- t.Body = eofReader
+ t.Body = NoBody
}
}
@@ -493,8 +474,29 @@ func (t *transferReader) fixTransferEncoding() error {
// function is not a method, because ultimately it should be shared by
// ReadResponse and ReadRequest.
func fixLength(isResponse bool, status int, requestMethod string, header Header, te []string) (int64, error) {
- contentLens := header["Content-Length"]
isRequest := !isResponse
+ contentLens := header["Content-Length"]
+
+ // Hardening against HTTP request smuggling
+ if len(contentLens) > 1 {
+ // Per RFC 7230 Section 3.3.2, prevent multiple
+ // Content-Length headers if they differ in value.
+ // If there are dups of the value, remove the dups.
+ // See Issue 16490.
+ first := strings.TrimSpace(contentLens[0])
+ for _, ct := range contentLens[1:] {
+ if first != strings.TrimSpace(ct) {
+ return 0, fmt.Errorf("http: message cannot contain multiple Content-Length headers; got %q", contentLens)
+ }
+ }
+
+ // deduplicate Content-Length
+ header.Del("Content-Length")
+ header.Add("Content-Length", first)
+
+ contentLens = header["Content-Length"]
+ }
+
// Logic based on response type or status
if noBodyExpected(requestMethod) {
// For HTTP requests, as part of hardening against request
@@ -514,11 +516,6 @@ func fixLength(isResponse bool, status int, requestMethod string, header Header,
return 0, nil
}
- if len(contentLens) > 1 {
- // harden against HTTP request smuggling. See RFC 7230.
- return 0, errors.New("http: message cannot contain multiple Content-Length headers")
- }
-
// Logic based on Transfer-Encoding
if chunked(te) {
return -1, nil
@@ -539,7 +536,7 @@ func fixLength(isResponse bool, status int, requestMethod string, header Header,
header.Del("Content-Length")
}
- if !isResponse {
+ if isRequest {
// RFC 2616 neither explicitly permits nor forbids an
// entity-body on a GET request so we permit one if
// declared, but we default to 0 here (not -1 below)
diff --git a/src/net/http/transport.go b/src/net/http/transport.go
index 1f07634..e484548 100644
--- a/src/net/http/transport.go
+++ b/src/net/http/transport.go
@@ -25,6 +25,7 @@ import (
"os"
"strings"
"sync"
+ "sync/atomic"
"time"
"golang_org/x/net/lex/httplex"
@@ -40,6 +41,7 @@ var DefaultTransport RoundTripper = &Transport{
DialContext: (&net.Dialer{
Timeout: 30 * time.Second,
KeepAlive: 30 * time.Second,
+ DualStack: true,
}).DialContext,
MaxIdleConns: 100,
IdleConnTimeout: 90 * time.Second,
@@ -66,8 +68,10 @@ const DefaultMaxIdleConnsPerHost = 2
// For high-level functionality, such as cookies and redirects, see Client.
//
// Transport uses HTTP/1.1 for HTTP URLs and either HTTP/1.1 or HTTP/2
-// for HTTPS URLs, depending on whether the server supports HTTP/2.
-// See the package docs for more about HTTP/2.
+// for HTTPS URLs, depending on whether the server supports HTTP/2,
+// and how the Transport is configured. The DefaultTransport supports HTTP/2.
+// To explicitly enable HTTP/2 on a transport, use golang.org/x/net/http2
+// and call ConfigureTransport. See the package docs for more about HTTP/2.
type Transport struct {
idleMu sync.Mutex
wantIdle bool // user has requested to close all idle conns
@@ -76,10 +80,10 @@ type Transport struct {
idleLRU connLRU
reqMu sync.Mutex
- reqCanceler map[*Request]func()
+ reqCanceler map[*Request]func(error)
- altMu sync.RWMutex
- altProto map[string]RoundTripper // nil or map of URI scheme => RoundTripper
+ altMu sync.Mutex // guards changing altProto only
+ altProto atomic.Value // of nil or map[string]RoundTripper, key is URI scheme
// Proxy specifies a function to return a proxy for a given
// Request. If the function returns a non-nil error, the
@@ -111,7 +115,9 @@ type Transport struct {
DialTLS func(network, addr string) (net.Conn, error)
// TLSClientConfig specifies the TLS configuration to use with
- // tls.Client. If nil, the default configuration is used.
+ // tls.Client.
+ // If nil, the default configuration is used.
+ // If non-nil, HTTP/2 support may not be enabled by default.
TLSClientConfig *tls.Config
// TLSHandshakeTimeout specifies the maximum amount of time waiting to
@@ -156,7 +162,9 @@ type Transport struct {
// ExpectContinueTimeout, if non-zero, specifies the amount of
// time to wait for a server's first response headers after fully
// writing the request headers if the request has an
- // "Expect: 100-continue" header. Zero means no timeout.
+ // "Expect: 100-continue" header. Zero means no timeout and
+ // causes the body to be sent immediately, without
+ // waiting for the server to approve.
// This time does not include the time to send the request header.
ExpectContinueTimeout time.Duration
@@ -168,9 +176,14 @@ type Transport struct {
// called with the request's authority (such as "example.com"
// or "example.com:1234") and the TLS connection. The function
// must return a RoundTripper that then handles the request.
- // If TLSNextProto is nil, HTTP/2 support is enabled automatically.
+ // If TLSNextProto is not nil, HTTP/2 support is not enabled
+ // automatically.
TLSNextProto map[string]func(authority string, c *tls.Conn) RoundTripper
+ // ProxyConnectHeader optionally specifies headers to send to
+ // proxies during CONNECT requests.
+ ProxyConnectHeader Header
+
// MaxResponseHeaderBytes specifies a limit on how many
// response bytes are allowed in the server's response
// header.
@@ -330,11 +343,9 @@ func (t *Transport) RoundTrip(req *Request) (*Response, error) {
}
}
}
- // TODO(bradfitz): switch to atomic.Value for this map instead of RWMutex
- t.altMu.RLock()
- altRT := t.altProto[scheme]
- t.altMu.RUnlock()
- if altRT != nil {
+
+ altProto, _ := t.altProto.Load().(map[string]RoundTripper)
+ if altRT := altProto[scheme]; altRT != nil {
if resp, err := altRT.RoundTrip(req); err != ErrSkipAltProtocol {
return resp, err
}
@@ -421,19 +432,15 @@ func (pc *persistConn) shouldRetryRequest(req *Request, err error) bool {
// our request (as opposed to sending an error).
return false
}
+ if _, ok := err.(nothingWrittenError); ok {
+ // We never wrote anything, so it's safe to retry.
+ return true
+ }
if !req.isReplayable() {
// Don't retry non-idempotent requests.
-
- // TODO: swap the nothingWrittenError and isReplayable checks,
- // putting the "if nothingWrittenError => return true" case
- // first, per golang.org/issue/15723
return false
}
- switch err.(type) {
- case nothingWrittenError:
- // We never wrote anything, so it's safe to retry.
- return true
- case transportReadFromServerError:
+ if _, ok := err.(transportReadFromServerError); ok {
// We got some non-EOF net.Conn.Read failure reading
// the 1st response byte from the server.
return true
@@ -463,13 +470,16 @@ var ErrSkipAltProtocol = errors.New("net/http: skip alternate protocol")
func (t *Transport) RegisterProtocol(scheme string, rt RoundTripper) {
t.altMu.Lock()
defer t.altMu.Unlock()
- if t.altProto == nil {
- t.altProto = make(map[string]RoundTripper)
- }
- if _, exists := t.altProto[scheme]; exists {
+ oldMap, _ := t.altProto.Load().(map[string]RoundTripper)
+ if _, exists := oldMap[scheme]; exists {
panic("protocol " + scheme + " already registered")
}
- t.altProto[scheme] = rt
+ newMap := make(map[string]RoundTripper)
+ for k, v := range oldMap {
+ newMap[k] = v
+ }
+ newMap[scheme] = rt
+ t.altProto.Store(newMap)
}
// CloseIdleConnections closes any connections which were previously
@@ -502,12 +512,17 @@ func (t *Transport) CloseIdleConnections() {
// cancelable context instead. CancelRequest cannot cancel HTTP/2
// requests.
func (t *Transport) CancelRequest(req *Request) {
+ t.cancelRequest(req, errRequestCanceled)
+}
+
+// Cancel an in-flight request, recording the error value.
+func (t *Transport) cancelRequest(req *Request, err error) {
t.reqMu.Lock()
cancel := t.reqCanceler[req]
delete(t.reqCanceler, req)
t.reqMu.Unlock()
if cancel != nil {
- cancel()
+ cancel(err)
}
}
@@ -557,10 +572,18 @@ func (e *envOnce) reset() {
}
func (t *Transport) connectMethodForRequest(treq *transportRequest) (cm connectMethod, err error) {
+ if port := treq.URL.Port(); !validPort(port) {
+ return cm, fmt.Errorf("invalid URL port %q", port)
+ }
cm.targetScheme = treq.URL.Scheme
cm.targetAddr = canonicalAddr(treq.URL)
if t.Proxy != nil {
cm.proxyURL, err = t.Proxy(treq.Request)
+ if err == nil && cm.proxyURL != nil {
+ if port := cm.proxyURL.Port(); !validPort(port) {
+ return cm, fmt.Errorf("invalid proxy URL port %q", port)
+ }
+ }
}
return cm, err
}
@@ -787,11 +810,11 @@ func (t *Transport) removeIdleConnLocked(pconn *persistConn) {
}
}
-func (t *Transport) setReqCanceler(r *Request, fn func()) {
+func (t *Transport) setReqCanceler(r *Request, fn func(error)) {
t.reqMu.Lock()
defer t.reqMu.Unlock()
if t.reqCanceler == nil {
- t.reqCanceler = make(map[*Request]func())
+ t.reqCanceler = make(map[*Request]func(error))
}
if fn != nil {
t.reqCanceler[r] = fn
@@ -804,7 +827,7 @@ func (t *Transport) setReqCanceler(r *Request, fn func()) {
// for the request, we don't set the function and return false.
// Since CancelRequest will clear the canceler, we can use the return value to detect if
// the request was canceled since the last setReqCancel call.
-func (t *Transport) replaceReqCanceler(r *Request, fn func()) bool {
+func (t *Transport) replaceReqCanceler(r *Request, fn func(error)) bool {
t.reqMu.Lock()
defer t.reqMu.Unlock()
_, ok := t.reqCanceler[r]
@@ -853,7 +876,7 @@ func (t *Transport) getConn(treq *transportRequest, cm connectMethod) (*persistC
// set request canceler to some non-nil function so we
// can detect whether it was cleared between now and when
// we enter roundTrip
- t.setReqCanceler(req, func() {})
+ t.setReqCanceler(req, func(error) {})
return pc, nil
}
@@ -878,8 +901,8 @@ func (t *Transport) getConn(treq *transportRequest, cm connectMethod) (*persistC
}()
}
- cancelc := make(chan struct{})
- t.setReqCanceler(req, func() { close(cancelc) })
+ cancelc := make(chan error, 1)
+ t.setReqCanceler(req, func(err error) { cancelc <- err })
go func() {
pc, err := t.dialConn(ctx, cm)
@@ -901,7 +924,12 @@ func (t *Transport) getConn(treq *transportRequest, cm connectMethod) (*persistC
select {
case <-req.Cancel:
case <-req.Context().Done():
- case <-cancelc:
+ return nil, req.Context().Err()
+ case err := <-cancelc:
+ if err == errRequestCanceled {
+ err = errRequestCanceledConn
+ }
+ return nil, err
default:
// It wasn't an error due to cancelation, so
// return the original error message:
@@ -926,10 +954,13 @@ func (t *Transport) getConn(treq *transportRequest, cm connectMethod) (*persistC
return nil, errRequestCanceledConn
case <-req.Context().Done():
handlePendingDial()
- return nil, errRequestCanceledConn
- case <-cancelc:
+ return nil, req.Context().Err()
+ case err := <-cancelc:
handlePendingDial()
- return nil, errRequestCanceledConn
+ if err == errRequestCanceled {
+ err = errRequestCanceledConn
+ }
+ return nil, err
}
}
@@ -943,6 +974,7 @@ func (t *Transport) dialConn(ctx context.Context, cm connectMethod) (*persistCon
writeErrCh: make(chan error, 1),
writeLoopDone: make(chan struct{}),
}
+ trace := httptrace.ContextClientTrace(ctx)
tlsDial := t.DialTLS != nil && cm.targetScheme == "https" && cm.proxyURL == nil
if tlsDial {
var err error
@@ -956,18 +988,28 @@ func (t *Transport) dialConn(ctx context.Context, cm connectMethod) (*persistCon
if tc, ok := pconn.conn.(*tls.Conn); ok {
// Handshake here, in case DialTLS didn't. TLSNextProto below
// depends on it for knowing the connection state.
+ if trace != nil && trace.TLSHandshakeStart != nil {
+ trace.TLSHandshakeStart()
+ }
if err := tc.Handshake(); err != nil {
go pconn.conn.Close()
+ if trace != nil && trace.TLSHandshakeDone != nil {
+ trace.TLSHandshakeDone(tls.ConnectionState{}, err)
+ }
return nil, err
}
cs := tc.ConnectionState()
+ if trace != nil && trace.TLSHandshakeDone != nil {
+ trace.TLSHandshakeDone(cs, nil)
+ }
pconn.tlsState = &cs
}
} else {
conn, err := t.dial(ctx, "tcp", cm.addr())
if err != nil {
if cm.proxyURL != nil {
- err = fmt.Errorf("http: error connecting to proxy %s: %v", cm.proxyURL, err)
+ // Return a typed error, per Issue 16997:
+ err = &net.OpError{Op: "proxyconnect", Net: "tcp", Err: err}
}
return nil, err
}
@@ -987,11 +1029,15 @@ func (t *Transport) dialConn(ctx context.Context, cm connectMethod) (*persistCon
}
case cm.targetScheme == "https":
conn := pconn.conn
+ hdr := t.ProxyConnectHeader
+ if hdr == nil {
+ hdr = make(Header)
+ }
connectReq := &Request{
Method: "CONNECT",
URL: &url.URL{Opaque: cm.targetAddr},
Host: cm.targetAddr,
- Header: make(Header),
+ Header: hdr,
}
if pa := cm.proxyAuth(); pa != "" {
connectReq.Header.Set("Proxy-Authorization", pa)
@@ -1016,7 +1062,7 @@ func (t *Transport) dialConn(ctx context.Context, cm connectMethod) (*persistCon
if cm.targetScheme == "https" && !tlsDial {
// Initiate TLS and check remote host name against certificate.
- cfg := cloneTLSClientConfig(t.TLSClientConfig)
+ cfg := cloneTLSConfig(t.TLSClientConfig)
if cfg.ServerName == "" {
cfg.ServerName = cm.tlsHost()
}
@@ -1030,6 +1076,9 @@ func (t *Transport) dialConn(ctx context.Context, cm connectMethod) (*persistCon
})
}
go func() {
+ if trace != nil && trace.TLSHandshakeStart != nil {
+ trace.TLSHandshakeStart()
+ }
err := tlsConn.Handshake()
if timer != nil {
timer.Stop()
@@ -1038,6 +1087,9 @@ func (t *Transport) dialConn(ctx context.Context, cm connectMethod) (*persistCon
}()
if err := <-errc; err != nil {
plainConn.Close()
+ if trace != nil && trace.TLSHandshakeDone != nil {
+ trace.TLSHandshakeDone(tls.ConnectionState{}, err)
+ }
return nil, err
}
if !cfg.InsecureSkipVerify {
@@ -1047,6 +1099,9 @@ func (t *Transport) dialConn(ctx context.Context, cm connectMethod) (*persistCon
}
}
cs := tlsConn.ConnectionState()
+ if trace != nil && trace.TLSHandshakeDone != nil {
+ trace.TLSHandshakeDone(cs, nil)
+ }
pconn.tlsState = &cs
pconn.conn = tlsConn
}
@@ -1235,8 +1290,8 @@ type persistConn struct {
mu sync.Mutex // guards following fields
numExpectedResponses int
closed error // set non-nil when conn is closed, before closech is closed
+ canceledErr error // set non-nil if conn is canceled
broken bool // an error has happened on this connection; marked broken so it's not reused.
- canceled bool // whether this conn was broken due a CancelRequest
reused bool // whether conn has had successful request/response and is being reused.
// mutateHeaderFunc is an optional func to modify extra
// headers on each outbound request before it's written. (the
@@ -1274,11 +1329,12 @@ func (pc *persistConn) isBroken() bool {
return b
}
-// isCanceled reports whether this connection was closed due to CancelRequest.
-func (pc *persistConn) isCanceled() bool {
+// canceled returns non-nil if the connection was closed due to
+// CancelRequest or due to context cancelation.
+func (pc *persistConn) canceled() error {
pc.mu.Lock()
defer pc.mu.Unlock()
- return pc.canceled
+ return pc.canceledErr
}
// isReused reports whether this connection is in a known broken state.
@@ -1301,10 +1357,10 @@ func (pc *persistConn) gotIdleConnTrace(idleAt time.Time) (t httptrace.GotConnIn
return
}
-func (pc *persistConn) cancelRequest() {
+func (pc *persistConn) cancelRequest(err error) {
pc.mu.Lock()
defer pc.mu.Unlock()
- pc.canceled = true
+ pc.canceledErr = err
pc.closeLocked(errRequestCanceled)
}
@@ -1332,8 +1388,8 @@ func (pc *persistConn) mapRoundTripErrorFromReadLoop(startBytesWritten int64, er
if err == nil {
return nil
}
- if pc.isCanceled() {
- return errRequestCanceled
+ if err := pc.canceled(); err != nil {
+ return err
}
if err == errServerClosedIdle {
return err
@@ -1355,8 +1411,8 @@ func (pc *persistConn) mapRoundTripErrorFromReadLoop(startBytesWritten int64, er
// its pc.closech channel close, indicating the persistConn is dead.
// (after closech is closed, pc.closed is valid).
func (pc *persistConn) mapRoundTripErrorAfterClosed(startBytesWritten int64) error {
- if pc.isCanceled() {
- return errRequestCanceled
+ if err := pc.canceled(); err != nil {
+ return err
}
err := pc.closed
if err == errServerClosedIdle {
@@ -1513,8 +1569,10 @@ func (pc *persistConn) readLoop() {
waitForBodyRead <- isEOF
if isEOF {
<-eofc // see comment above eofc declaration
- } else if err != nil && pc.isCanceled() {
- return errRequestCanceled
+ } else if err != nil {
+ if cerr := pc.canceled(); cerr != nil {
+ return cerr
+ }
}
return err
},
@@ -1554,7 +1612,7 @@ func (pc *persistConn) readLoop() {
pc.t.CancelRequest(rc.req)
case <-rc.req.Context().Done():
alive = false
- pc.t.CancelRequest(rc.req)
+ pc.t.cancelRequest(rc.req, rc.req.Context().Err())
case <-pc.closech:
alive = false
}
@@ -1840,8 +1898,8 @@ WaitResponse:
select {
case err := <-writeErrCh:
if err != nil {
- if pc.isCanceled() {
- err = errRequestCanceled
+ if cerr := pc.canceled(); cerr != nil {
+ err = cerr
}
re = responseAndError{err: err}
pc.close(fmt.Errorf("write error: %v", err))
@@ -1865,9 +1923,8 @@ WaitResponse:
case <-cancelChan:
pc.t.CancelRequest(req.Request)
cancelChan = nil
- ctxDoneChan = nil
case <-ctxDoneChan:
- pc.t.CancelRequest(req.Request)
+ pc.t.cancelRequest(req.Request, req.Context().Err())
cancelChan = nil
ctxDoneChan = nil
}
@@ -1931,11 +1988,15 @@ var portMap = map[string]string{
// canonicalAddr returns url.Host but always with a ":port" suffix
func canonicalAddr(url *url.URL) string {
- addr := url.Host
- if !hasPort(addr) {
- return addr + ":" + portMap[url.Scheme]
+ addr := url.Hostname()
+ if v, err := idnaASCII(addr); err == nil {
+ addr = v
+ }
+ port := url.Port()
+ if port == "" {
+ port = portMap[url.Scheme]
}
- return addr
+ return net.JoinHostPort(addr, port)
}
// bodyEOFSignal is used by the HTTP/1 transport when reading response
@@ -2060,75 +2121,14 @@ type fakeLocker struct{}
func (fakeLocker) Lock() {}
func (fakeLocker) Unlock() {}
-// cloneTLSConfig returns a shallow clone of the exported
-// fields of cfg, ignoring the unexported sync.Once, which
-// contains a mutex and must not be copied.
-//
-// The cfg must not be in active use by tls.Server, or else
-// there can still be a race with tls.Server updating SessionTicketKey
-// and our copying it, and also a race with the server setting
-// SessionTicketsDisabled=false on failure to set the random
-// ticket key.
-//
-// If cfg is nil, a new zero tls.Config is returned.
+// clneTLSConfig returns a shallow clone of cfg, or a new zero tls.Config if
+// cfg is nil. This is safe to call even if cfg is in active use by a TLS
+// client or server.
func cloneTLSConfig(cfg *tls.Config) *tls.Config {
if cfg == nil {
return &tls.Config{}
}
- return &tls.Config{
- Rand: cfg.Rand,
- Time: cfg.Time,
- Certificates: cfg.Certificates,
- NameToCertificate: cfg.NameToCertificate,
- GetCertificate: cfg.GetCertificate,
- RootCAs: cfg.RootCAs,
- NextProtos: cfg.NextProtos,
- ServerName: cfg.ServerName,
- ClientAuth: cfg.ClientAuth,
- ClientCAs: cfg.ClientCAs,
- InsecureSkipVerify: cfg.InsecureSkipVerify,
- CipherSuites: cfg.CipherSuites,
- PreferServerCipherSuites: cfg.PreferServerCipherSuites,
- SessionTicketsDisabled: cfg.SessionTicketsDisabled,
- SessionTicketKey: cfg.SessionTicketKey,
- ClientSessionCache: cfg.ClientSessionCache,
- MinVersion: cfg.MinVersion,
- MaxVersion: cfg.MaxVersion,
- CurvePreferences: cfg.CurvePreferences,
- DynamicRecordSizingDisabled: cfg.DynamicRecordSizingDisabled,
- Renegotiation: cfg.Renegotiation,
- }
-}
-
-// cloneTLSClientConfig is like cloneTLSConfig but omits
-// the fields SessionTicketsDisabled and SessionTicketKey.
-// This makes it safe to call cloneTLSClientConfig on a config
-// in active use by a server.
-func cloneTLSClientConfig(cfg *tls.Config) *tls.Config {
- if cfg == nil {
- return &tls.Config{}
- }
- return &tls.Config{
- Rand: cfg.Rand,
- Time: cfg.Time,
- Certificates: cfg.Certificates,
- NameToCertificate: cfg.NameToCertificate,
- GetCertificate: cfg.GetCertificate,
- RootCAs: cfg.RootCAs,
- NextProtos: cfg.NextProtos,
- ServerName: cfg.ServerName,
- ClientAuth: cfg.ClientAuth,
- ClientCAs: cfg.ClientCAs,
- InsecureSkipVerify: cfg.InsecureSkipVerify,
- CipherSuites: cfg.CipherSuites,
- PreferServerCipherSuites: cfg.PreferServerCipherSuites,
- ClientSessionCache: cfg.ClientSessionCache,
- MinVersion: cfg.MinVersion,
- MaxVersion: cfg.MaxVersion,
- CurvePreferences: cfg.CurvePreferences,
- DynamicRecordSizingDisabled: cfg.DynamicRecordSizingDisabled,
- Renegotiation: cfg.Renegotiation,
- }
+ return cfg.Clone()
}
type connLRU struct {
@@ -2169,3 +2169,15 @@ func (cl *connLRU) remove(pc *persistConn) {
func (cl *connLRU) len() int {
return len(cl.m)
}
+
+// validPort reports whether p (without the colon) is a valid port in
+// a URL, per RFC 3986 Section 3.2.3, which says the port may be
+// empty, or only contain digits.
+func validPort(p string) bool {
+ for _, r := range []byte(p) {
+ if r < '0' || r > '9' {
+ return false
+ }
+ }
+ return true
+}
diff --git a/src/net/http/transport_internal_test.go b/src/net/http/transport_internal_test.go
index a05ca6e..3d24fc1 100644
--- a/src/net/http/transport_internal_test.go
+++ b/src/net/http/transport_internal_test.go
@@ -72,3 +72,70 @@ func newLocalListener(t *testing.T) net.Listener {
}
return ln
}
+
+func dummyRequest(method string) *Request {
+ req, err := NewRequest(method, "http://fake.tld/", nil)
+ if err != nil {
+ panic(err)
+ }
+ return req
+}
+
+func TestTransportShouldRetryRequest(t *testing.T) {
+ tests := []struct {
+ pc *persistConn
+ req *Request
+
+ err error
+ want bool
+ }{
+ 0: {
+ pc: &persistConn{reused: false},
+ req: dummyRequest("POST"),
+ err: nothingWrittenError{},
+ want: false,
+ },
+ 1: {
+ pc: &persistConn{reused: true},
+ req: dummyRequest("POST"),
+ err: nothingWrittenError{},
+ want: true,
+ },
+ 2: {
+ pc: &persistConn{reused: true},
+ req: dummyRequest("POST"),
+ err: http2ErrNoCachedConn,
+ want: true,
+ },
+ 3: {
+ pc: &persistConn{reused: true},
+ req: dummyRequest("POST"),
+ err: errMissingHost,
+ want: false,
+ },
+ 4: {
+ pc: &persistConn{reused: true},
+ req: dummyRequest("POST"),
+ err: transportReadFromServerError{},
+ want: false,
+ },
+ 5: {
+ pc: &persistConn{reused: true},
+ req: dummyRequest("GET"),
+ err: transportReadFromServerError{},
+ want: true,
+ },
+ 6: {
+ pc: &persistConn{reused: true},
+ req: dummyRequest("GET"),
+ err: errServerClosedIdle,
+ want: true,
+ },
+ }
+ for i, tt := range tests {
+ got := tt.pc.shouldRetryRequest(tt.req, tt.err)
+ if got != tt.want {
+ t.Errorf("%d. shouldRetryRequest = %v; want %v", i, got, tt.want)
+ }
+ }
+}
diff --git a/src/net/http/transport_test.go b/src/net/http/transport_test.go
index 298682d..5a40265 100644
--- a/src/net/http/transport_test.go
+++ b/src/net/http/transport_test.go
@@ -441,9 +441,7 @@ func TestTransportMaxPerHostIdleConns(t *testing.T) {
}
func TestTransportRemovesDeadIdleConnections(t *testing.T) {
- if runtime.GOOS == "plan9" {
- t.Skip("skipping test; see https://golang.org/issue/15464")
- }
+ setParallel(t)
defer afterTest(t)
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
io.WriteString(w, r.RemoteAddr)
@@ -700,6 +698,7 @@ var roundTripTests = []struct {
// Test that the modification made to the Request by the RoundTripper is cleaned up
func TestRoundTripGzip(t *testing.T) {
+ setParallel(t)
defer afterTest(t)
const responseBody = "test response body"
ts := httptest.NewServer(HandlerFunc(func(rw ResponseWriter, req *Request) {
@@ -758,6 +757,7 @@ func TestRoundTripGzip(t *testing.T) {
}
func TestTransportGzip(t *testing.T) {
+ setParallel(t)
defer afterTest(t)
const testString = "The test string aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
const nRandBytes = 1024 * 1024
@@ -856,6 +856,7 @@ func TestTransportGzip(t *testing.T) {
// If a request has Expect:100-continue header, the request blocks sending body until the first response.
// Premature consumption of the request body should not be occurred.
func TestTransportExpect100Continue(t *testing.T) {
+ setParallel(t)
defer afterTest(t)
ts := httptest.NewServer(HandlerFunc(func(rw ResponseWriter, req *Request) {
@@ -966,6 +967,48 @@ func TestTransportProxy(t *testing.T) {
}
}
+// Issue 16997: test transport dial preserves typed errors
+func TestTransportDialPreservesNetOpProxyError(t *testing.T) {
+ defer afterTest(t)
+
+ var errDial = errors.New("some dial error")
+
+ tr := &Transport{
+ Proxy: func(*Request) (*url.URL, error) {
+ return url.Parse("http://proxy.fake.tld/")
+ },
+ Dial: func(string, string) (net.Conn, error) {
+ return nil, errDial
+ },
+ }
+ defer tr.CloseIdleConnections()
+
+ c := &Client{Transport: tr}
+ req, _ := NewRequest("GET", "http://fake.tld", nil)
+ res, err := c.Do(req)
+ if err == nil {
+ res.Body.Close()
+ t.Fatal("wanted a non-nil error")
+ }
+
+ uerr, ok := err.(*url.Error)
+ if !ok {
+ t.Fatalf("got %T, want *url.Error", err)
+ }
+ oe, ok := uerr.Err.(*net.OpError)
+ if !ok {
+ t.Fatalf("url.Error.Err = %T; want *net.OpError", uerr.Err)
+ }
+ want := &net.OpError{
+ Op: "proxyconnect",
+ Net: "tcp",
+ Err: errDial, // original error, unwrapped.
+ }
+ if !reflect.DeepEqual(oe, want) {
+ t.Errorf("Got error %#v; want %#v", oe, want)
+ }
+}
+
// TestTransportGzipRecursive sends a gzip quine and checks that the
// client gets the same value back. This is more cute than anything,
// but checks that we don't recurse forever, and checks that
@@ -1038,7 +1081,7 @@ func waitNumGoroutine(nmax int) int {
// tests that persistent goroutine connections shut down when no longer desired.
func TestTransportPersistConnLeak(t *testing.T) {
- setParallel(t)
+ // Not parallel: counts goroutines
defer afterTest(t)
gotReqCh := make(chan bool)
unblockCh := make(chan bool)
@@ -1102,7 +1145,7 @@ func TestTransportPersistConnLeak(t *testing.T) {
// golang.org/issue/4531: Transport leaks goroutines when
// request.ContentLength is explicitly short
func TestTransportPersistConnLeakShortBody(t *testing.T) {
- setParallel(t)
+ // Not parallel: measures goroutines.
defer afterTest(t)
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
}))
@@ -1198,6 +1241,7 @@ func TestIssue3644(t *testing.T) {
// Test that a client receives a server's reply, even if the server doesn't read
// the entire request body.
func TestIssue3595(t *testing.T) {
+ setParallel(t)
defer afterTest(t)
const deniedMsg = "sorry, denied."
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
@@ -1246,6 +1290,7 @@ func TestChunkedNoContent(t *testing.T) {
}
func TestTransportConcurrency(t *testing.T) {
+ // Not parallel: uses global test hooks.
defer afterTest(t)
maxProcs, numReqs := 16, 500
if testing.Short() {
@@ -1306,9 +1351,7 @@ func TestTransportConcurrency(t *testing.T) {
}
func TestIssue4191_InfiniteGetTimeout(t *testing.T) {
- if runtime.GOOS == "plan9" {
- t.Skip("skipping test; see https://golang.org/issue/7237")
- }
+ setParallel(t)
defer afterTest(t)
const debug = false
mux := NewServeMux()
@@ -1370,9 +1413,7 @@ func TestIssue4191_InfiniteGetTimeout(t *testing.T) {
}
func TestIssue4191_InfiniteGetToPutTimeout(t *testing.T) {
- if runtime.GOOS == "plan9" {
- t.Skip("skipping test; see https://golang.org/issue/7237")
- }
+ setParallel(t)
defer afterTest(t)
const debug = false
mux := NewServeMux()
@@ -1696,12 +1737,6 @@ func testCancelRequestWithChannelBeforeDo(t *testing.T, withCtx bool) {
defer ts.Close()
defer close(unblockc)
- // Don't interfere with the next test on plan9.
- // Cf. https://golang.org/issues/11476
- if runtime.GOOS == "plan9" {
- defer time.Sleep(500 * time.Millisecond)
- }
-
tr := &Transport{}
defer tr.CloseIdleConnections()
c := &Client{Transport: tr}
@@ -1718,8 +1753,17 @@ func testCancelRequestWithChannelBeforeDo(t *testing.T, withCtx bool) {
}
_, err := c.Do(req)
- if err == nil || !strings.Contains(err.Error(), "canceled") {
- t.Errorf("Do error = %v; want cancelation", err)
+ if ue, ok := err.(*url.Error); ok {
+ err = ue.Err
+ }
+ if withCtx {
+ if err != context.Canceled {
+ t.Errorf("Do error = %v; want %v", err, context.Canceled)
+ }
+ } else {
+ if err == nil || !strings.Contains(err.Error(), "canceled") {
+ t.Errorf("Do error = %v; want cancelation", err)
+ }
}
}
@@ -1888,6 +1932,7 @@ func TestTransportEmptyMethod(t *testing.T) {
}
func TestTransportSocketLateBinding(t *testing.T) {
+ setParallel(t)
defer afterTest(t)
mux := NewServeMux()
@@ -2152,6 +2197,7 @@ func TestProxyFromEnvironment(t *testing.T) {
}
func TestIdleConnChannelLeak(t *testing.T) {
+ // Not parallel: uses global test hooks.
var mu sync.Mutex
var n int
@@ -2383,6 +2429,7 @@ func (c byteFromChanReader) Read(p []byte) (n int, err error) {
// questionable state.
// golang.org/issue/7569
func TestTransportNoReuseAfterEarlyResponse(t *testing.T) {
+ setParallel(t)
defer afterTest(t)
var sconn struct {
sync.Mutex
@@ -2485,22 +2532,6 @@ type errorReader struct {
func (e errorReader) Read(p []byte) (int, error) { return 0, e.err }
-type plan9SleepReader struct{}
-
-func (plan9SleepReader) Read(p []byte) (int, error) {
- if runtime.GOOS == "plan9" {
- // After the fix to unblock TCP Reads in
- // https://golang.org/cl/15941, this sleep is required
- // on plan9 to make sure TCP Writes before an
- // immediate TCP close go out on the wire. On Plan 9,
- // it seems that a hangup of a TCP connection with
- // queued data doesn't send the queued data first.
- // https://golang.org/issue/9554
- time.Sleep(50 * time.Millisecond)
- }
- return 0, io.EOF
-}
-
type closerFunc func() error
func (f closerFunc) Close() error { return f() }
@@ -2595,7 +2626,7 @@ func TestTransportClosesBodyOnError(t *testing.T) {
io.Reader
io.Closer
}{
- io.MultiReader(io.LimitReader(neverEnding('x'), 1<<20), plan9SleepReader{}, errorReader{fakeErr}),
+ io.MultiReader(io.LimitReader(neverEnding('x'), 1<<20), errorReader{fakeErr}),
closerFunc(func() error {
select {
case didClose <- true:
@@ -2627,6 +2658,8 @@ func TestTransportClosesBodyOnError(t *testing.T) {
}
func TestTransportDialTLS(t *testing.T) {
+ setParallel(t)
+ defer afterTest(t)
var mu sync.Mutex // guards following
var gotReq, didDial bool
@@ -2904,14 +2937,8 @@ func TestTransportFlushesBodyChunks(t *testing.T) {
defer res.Body.Close()
want := []string{
- // Because Request.ContentLength = 0, the body is sniffed for 1 byte to determine whether there's content.
- // That explains the initial "num0" being split into "n" and "um0".
- // The first byte is included with the request headers Write. Perhaps in the future
- // we will want to flush the headers out early if the first byte of the request body is
- // taking a long time to arrive. But not yet.
"POST / HTTP/1.1\r\nHost: localhost:8080\r\nUser-Agent: x\r\nTransfer-Encoding: chunked\r\nAccept-Encoding: gzip\r\n\r\n" +
- "1\r\nn\r\n",
- "4\r\num0\n\r\n",
+ "5\r\nnum0\n\r\n",
"5\r\nnum1\n\r\n",
"5\r\nnum2\n\r\n",
"0\r\n\r\n",
@@ -3150,6 +3177,7 @@ func TestTransportReuseConnection_Gzip_ContentLength(t *testing.T) {
// Make sure we re-use underlying TCP connection for gzipped responses too.
func testTransportReuseConnection_Gzip(t *testing.T, chunked bool) {
+ setParallel(t)
defer afterTest(t)
addr := make(chan string, 2)
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
@@ -3185,6 +3213,7 @@ func testTransportReuseConnection_Gzip(t *testing.T, chunked bool) {
}
func TestTransportResponseHeaderLength(t *testing.T) {
+ setParallel(t)
defer afterTest(t)
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
if r.URL.Path == "/long" {
@@ -3248,7 +3277,7 @@ func testTransportEventTrace(t *testing.T, h2 bool, noHooks bool) {
cst.tr.ExpectContinueTimeout = 1 * time.Second
- var mu sync.Mutex
+ var mu sync.Mutex // guards buf
var buf bytes.Buffer
logf := func(format string, args ...interface{}) {
mu.Lock()
@@ -3290,10 +3319,16 @@ func testTransportEventTrace(t *testing.T, h2 bool, noHooks bool) {
Wait100Continue: func() { logf("Wait100Continue") },
Got100Continue: func() { logf("Got100Continue") },
WroteRequest: func(e httptrace.WroteRequestInfo) {
- close(gotWroteReqEvent)
logf("WroteRequest: %+v", e)
+ close(gotWroteReqEvent)
},
}
+ if h2 {
+ trace.TLSHandshakeStart = func() { logf("tls handshake start") }
+ trace.TLSHandshakeDone = func(s tls.ConnectionState, err error) {
+ logf("tls handshake done. ConnectionState = %v \n err = %v", s, err)
+ }
+ }
if noHooks {
// zero out all func pointers, trying to get some path to crash
*trace = httptrace.ClientTrace{}
@@ -3323,7 +3358,10 @@ func testTransportEventTrace(t *testing.T, h2 bool, noHooks bool) {
return
}
+ mu.Lock()
got := buf.String()
+ mu.Unlock()
+
wantOnce := func(sub string) {
if strings.Count(got, sub) != 1 {
t.Errorf("expected substring %q exactly once in output.", sub)
@@ -3342,7 +3380,10 @@ func testTransportEventTrace(t *testing.T, h2 bool, noHooks bool) {
wantOnceOrMore("connected to tcp " + addrStr + " = <nil>")
wantOnce("Reused:false WasIdle:false IdleTime:0s")
wantOnce("first response byte")
- if !h2 {
+ if h2 {
+ wantOnce("tls handshake start")
+ wantOnce("tls handshake done")
+ } else {
wantOnce("PutIdleConn = <nil>")
}
wantOnce("Wait100Continue")
@@ -3357,12 +3398,21 @@ 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")
+ }
defer afterTest(t)
tr := &Transport{}
defer tr.CloseIdleConnections()
c := &Client{Transport: tr}
- var mu sync.Mutex
+ var mu sync.Mutex // guards buf
var buf bytes.Buffer
logf := func(format string, args ...interface{}) {
mu.Lock()
@@ -3386,7 +3436,10 @@ func TestTransportEventTraceRealDNS(t *testing.T) {
t.Fatal("expected error during DNS lookup")
}
+ mu.Lock()
got := buf.String()
+ mu.Unlock()
+
wantSub := func(sub string) {
if !strings.Contains(got, sub) {
t.Errorf("expected substring %q in output.", sub)
@@ -3402,6 +3455,73 @@ func TestTransportEventTraceRealDNS(t *testing.T) {
}
}
+// Issue 14353: port can only contain digits.
+func TestTransportRejectsAlphaPort(t *testing.T) {
+ res, err := Get("http://dummy.tld:123foo/bar")
+ if err == nil {
+ res.Body.Close()
+ t.Fatal("unexpected success")
+ }
+ ue, ok := err.(*url.Error)
+ if !ok {
+ t.Fatalf("got %#v; want *url.Error", err)
+ }
+ got := ue.Err.Error()
+ want := `invalid URL port "123foo"`
+ if got != want {
+ t.Errorf("got error %q; want %q", got, want)
+ }
+}
+
+// Test the httptrace.TLSHandshake{Start,Done} hooks with a https http1
+// 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()
+
+ var mu sync.Mutex
+ var start, done bool
+ trace := &httptrace.ClientTrace{
+ TLSHandshakeStart: func() {
+ mu.Lock()
+ defer mu.Unlock()
+ start = true
+ },
+ TLSHandshakeDone: func(s tls.ConnectionState, err error) {
+ mu.Lock()
+ defer mu.Unlock()
+ done = true
+ if err != nil {
+ t.Fatal("Expected error to be nil but was:", err)
+ }
+ },
+ }
+
+ tr := &Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: true}}
+ defer tr.CloseIdleConnections()
+ c := &Client{Transport: tr}
+ req, err := NewRequest("GET", s.URL, nil)
+ if err != nil {
+ t.Fatal("Unable to construct test request:", err)
+ }
+ req = req.WithContext(httptrace.WithClientTrace(req.Context(), trace))
+
+ r, err := c.Do(req)
+ if err != nil {
+ t.Fatal("Unexpected error making request:", err)
+ }
+ r.Body.Close()
+ mu.Lock()
+ defer mu.Unlock()
+ if !start {
+ t.Fatal("Expected TLSHandshakeStart to be called, but wasn't")
+ }
+ if !done {
+ t.Fatal("Expected TLSHandshakeDone to be called, but wasnt't")
+ }
+}
+
func TestTransportMaxIdleConns(t *testing.T) {
defer afterTest(t)
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
@@ -3457,27 +3577,36 @@ func TestTransportMaxIdleConns(t *testing.T) {
}
}
-func TestTransportIdleConnTimeout(t *testing.T) {
+func TestTransportIdleConnTimeout_h1(t *testing.T) { testTransportIdleConnTimeout(t, h1Mode) }
+func TestTransportIdleConnTimeout_h2(t *testing.T) { testTransportIdleConnTimeout(t, h2Mode) }
+func testTransportIdleConnTimeout(t *testing.T, h2 bool) {
if testing.Short() {
t.Skip("skipping in short mode")
}
defer afterTest(t)
- ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ const timeout = 1 * time.Second
+
+ cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
// No body for convenience.
}))
- defer ts.Close()
-
- const timeout = 1 * time.Second
- tr := &Transport{
- IdleConnTimeout: timeout,
- }
+ defer cst.close()
+ tr := cst.tr
+ tr.IdleConnTimeout = timeout
defer tr.CloseIdleConnections()
c := &Client{Transport: tr}
+ idleConns := func() []string {
+ if h2 {
+ return tr.IdleConnStrsForTesting_h2()
+ } else {
+ return tr.IdleConnStrsForTesting()
+ }
+ }
+
var conn string
doReq := func(n int) {
- req, _ := NewRequest("GET", ts.URL, nil)
+ req, _ := NewRequest("GET", cst.ts.URL, nil)
req = req.WithContext(httptrace.WithClientTrace(context.Background(), &httptrace.ClientTrace{
PutIdleConn: func(err error) {
if err != nil {
@@ -3490,7 +3619,7 @@ func TestTransportIdleConnTimeout(t *testing.T) {
t.Fatal(err)
}
res.Body.Close()
- conns := tr.IdleConnStrsForTesting()
+ conns := idleConns()
if len(conns) != 1 {
t.Fatalf("req %v: unexpected number of idle conns: %q", n, conns)
}
@@ -3506,7 +3635,7 @@ func TestTransportIdleConnTimeout(t *testing.T) {
time.Sleep(timeout / 2)
}
time.Sleep(timeout * 3 / 2)
- if got := tr.IdleConnStrsForTesting(); len(got) != 0 {
+ if got := idleConns(); len(got) != 0 {
t.Errorf("idle conns = %q; want none", got)
}
}
@@ -3523,6 +3652,7 @@ func TestTransportIdleConnTimeout(t *testing.T) {
// know the successful tls.Dial from DialTLS will need to go into the
// idle pool. Then we give it a of time to explode.
func TestIdleConnH2Crash(t *testing.T) {
+ setParallel(t)
cst := newClientServerTest(t, h2Mode, HandlerFunc(func(w ResponseWriter, r *Request) {
// nothing
}))
@@ -3531,12 +3661,12 @@ func TestIdleConnH2Crash(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
- gotErr := make(chan bool, 1)
+ sawDoErr := make(chan bool, 1)
+ testDone := make(chan struct{})
+ defer close(testDone)
cst.tr.IdleConnTimeout = 5 * time.Millisecond
cst.tr.DialTLS = func(network, addr string) (net.Conn, error) {
- cancel()
- <-gotErr
c, err := tls.Dial(network, addr, &tls.Config{
InsecureSkipVerify: true,
NextProtos: []string{"h2"},
@@ -3550,6 +3680,17 @@ func TestIdleConnH2Crash(t *testing.T) {
c.Close()
return nil, errors.New("bogus")
}
+
+ cancel()
+
+ failTimer := time.NewTimer(5 * time.Second)
+ defer failTimer.Stop()
+ select {
+ case <-sawDoErr:
+ case <-testDone:
+ case <-failTimer.C:
+ t.Error("timeout in DialTLS, waiting too long for cst.c.Do to fail")
+ }
return c, nil
}
@@ -3560,7 +3701,7 @@ func TestIdleConnH2Crash(t *testing.T) {
res.Body.Close()
t.Fatal("unexpected success")
}
- gotErr <- true
+ sawDoErr <- true
// Wait for the explosion.
time.Sleep(cst.tr.IdleConnTimeout * 10)
@@ -3605,6 +3746,122 @@ func TestTransportReturnsPeekError(t *testing.T) {
}
}
+// Issue 13835: international domain names should work
+func TestTransportIDNA_h1(t *testing.T) { testTransportIDNA(t, h1Mode) }
+func TestTransportIDNA_h2(t *testing.T) { testTransportIDNA(t, h2Mode) }
+func testTransportIDNA(t *testing.T, h2 bool) {
+ defer afterTest(t)
+
+ const uniDomain = "гофер.го"
+ const punyDomain = "xn--c1ae0ajs.xn--c1aw"
+
+ var port string
+ cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
+ want := punyDomain + ":" + port
+ if r.Host != want {
+ t.Errorf("Host header = %q; want %q", r.Host, want)
+ }
+ if h2 {
+ if r.TLS == nil {
+ t.Errorf("r.TLS == nil")
+ } else if r.TLS.ServerName != punyDomain {
+ t.Errorf("TLS.ServerName = %q; want %q", r.TLS.ServerName, punyDomain)
+ }
+ }
+ w.Header().Set("Hit-Handler", "1")
+ }))
+ defer cst.close()
+
+ ip, port, err := net.SplitHostPort(cst.ts.Listener.Addr().String())
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // Install a fake DNS server.
+ ctx := context.WithValue(context.Background(), nettrace.LookupIPAltResolverKey{}, func(ctx context.Context, host string) ([]net.IPAddr, error) {
+ if host != punyDomain {
+ t.Errorf("got DNS host lookup for %q; want %q", host, punyDomain)
+ return nil, nil
+ }
+ return []net.IPAddr{{IP: net.ParseIP(ip)}}, nil
+ })
+
+ req, _ := NewRequest("GET", cst.scheme()+"://"+uniDomain+":"+port, nil)
+ trace := &httptrace.ClientTrace{
+ GetConn: func(hostPort string) {
+ want := net.JoinHostPort(punyDomain, port)
+ if hostPort != want {
+ t.Errorf("getting conn for %q; want %q", hostPort, want)
+ }
+ },
+ DNSStart: func(e httptrace.DNSStartInfo) {
+ if e.Host != punyDomain {
+ t.Errorf("DNSStart Host = %q; want %q", e.Host, punyDomain)
+ }
+ },
+ }
+ req = req.WithContext(httptrace.WithClientTrace(ctx, trace))
+
+ res, err := cst.tr.RoundTrip(req)
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer res.Body.Close()
+ if res.Header.Get("Hit-Handler") != "1" {
+ out, err := httputil.DumpResponse(res, true)
+ if err != nil {
+ t.Fatal(err)
+ }
+ t.Errorf("Response body wasn't from Handler. Got:\n%s\n", out)
+ }
+}
+
+// Issue 13290: send User-Agent in proxy CONNECT
+func TestTransportProxyConnectHeader(t *testing.T) {
+ defer afterTest(t)
+ reqc := make(chan *Request, 1)
+ ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ if r.Method != "CONNECT" {
+ t.Errorf("method = %q; want CONNECT", r.Method)
+ }
+ reqc <- r
+ c, _, err := w.(Hijacker).Hijack()
+ if err != nil {
+ t.Errorf("Hijack: %v", err)
+ return
+ }
+ 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)
+ },
+ }
+ defer tr.CloseIdleConnections()
+ c := &Client{Transport: tr}
+ res, err := c.Get("https://dummy.tld/") // https to force a CONNECT
+ if err == nil {
+ res.Body.Close()
+ t.Errorf("unexpected success")
+ }
+ select {
+ case <-time.After(3 * time.Second):
+ t.Fatal("timeout")
+ case r := <-reqc:
+ if got, want := r.Header.Get("User-Agent"), "foo"; got != want {
+ t.Errorf("CONNECT request User-Agent = %q; want %q", got, want)
+ }
+ if got, want := r.Header.Get("Other"), "bar"; got != want {
+ t.Errorf("CONNECT request Other = %q; want %q", got, want)
+ }
+ }
+}
+
var errFakeRoundTrip = errors.New("fake roundtrip")
type funcRoundTripper func()
diff --git a/src/net/interface.go b/src/net/interface.go
index 52b857c..301a5cf 100644
--- a/src/net/interface.go
+++ b/src/net/interface.go
@@ -10,6 +10,12 @@ import (
"time"
)
+// BUG(mikio): On NaCl, methods and functions related to
+// Interface are not implemented.
+
+// BUG(mikio): On DragonFly BSD, NetBSD, OpenBSD, Plan 9 and Solaris,
+// the MulticastAddrs method of Interface is not implemented.
+
var (
errInvalidInterface = errors.New("invalid network interface")
errInvalidInterfaceIndex = errors.New("invalid network interface index")
@@ -63,7 +69,8 @@ func (f Flags) String() string {
return s
}
-// Addrs returns interface addresses for a specific interface.
+// Addrs returns a list of unicast interface addresses for a specific
+// interface.
func (ifi *Interface) Addrs() ([]Addr, error) {
if ifi == nil {
return nil, &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: errInvalidInterface}
@@ -75,8 +82,8 @@ func (ifi *Interface) Addrs() ([]Addr, error) {
return ifat, err
}
-// MulticastAddrs returns multicast, joined group addresses for
-// a specific interface.
+// MulticastAddrs returns a list of multicast, joined group addresses
+// for a specific interface.
func (ifi *Interface) MulticastAddrs() ([]Addr, error) {
if ifi == nil {
return nil, &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: errInvalidInterface}
@@ -100,8 +107,11 @@ func Interfaces() ([]Interface, error) {
return ift, nil
}
-// InterfaceAddrs returns a list of the system's network interface
+// InterfaceAddrs returns a list of the system's unicast interface
// addresses.
+//
+// The returned list does not identify the associated interface; use
+// Interfaces and Interface.Addrs for more detail.
func InterfaceAddrs() ([]Addr, error) {
ifat, err := interfaceAddrTable(nil)
if err != nil {
@@ -111,6 +121,10 @@ func InterfaceAddrs() ([]Addr, error) {
}
// InterfaceByIndex returns the interface specified by index.
+//
+// On Solaris, it returns one of the logical network interfaces
+// sharing the logical data link; for more precision use
+// InterfaceByName.
func InterfaceByIndex(index int) (*Interface, error) {
if index <= 0 {
return nil, &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: errInvalidInterfaceIndex}
@@ -215,7 +229,7 @@ func zoneToInt(zone string) int {
defer zoneCache.RUnlock()
index, ok := zoneCache.toIndex[zone]
if !ok {
- index, _, _ = dtoi(zone, 0)
+ index, _, _ = dtoi(zone)
}
return index
}
diff --git a/src/net/interface_plan9.go b/src/net/interface_plan9.go
new file mode 100644
index 0000000..e5d7739
--- /dev/null
+++ b/src/net/interface_plan9.go
@@ -0,0 +1,198 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package net
+
+import (
+ "errors"
+ "os"
+)
+
+// If the ifindex is zero, interfaceTable returns mappings of all
+// network interfaces. Otherwise it returns a mapping of a specific
+// interface.
+func interfaceTable(ifindex int) ([]Interface, error) {
+ if ifindex == 0 {
+ n, err := interfaceCount()
+ if err != nil {
+ return nil, err
+ }
+ ifcs := make([]Interface, n)
+ for i := range ifcs {
+ ifc, err := readInterface(i)
+ if err != nil {
+ return nil, err
+ }
+ ifcs[i] = *ifc
+ }
+ return ifcs, nil
+ }
+
+ ifc, err := readInterface(ifindex - 1)
+ if err != nil {
+ return nil, err
+ }
+ return []Interface{*ifc}, nil
+}
+
+func readInterface(i int) (*Interface, error) {
+ ifc := &Interface{
+ Index: i + 1, // Offset the index by one to suit the contract
+ Name: netdir + "/ipifc/" + itoa(i), // Name is the full path to the interface path in plan9
+ }
+
+ ifcstat := ifc.Name + "/status"
+ ifcstatf, err := open(ifcstat)
+ if err != nil {
+ return nil, err
+ }
+ defer ifcstatf.close()
+
+ line, ok := ifcstatf.readLine()
+ if !ok {
+ return nil, errors.New("invalid interface status file: " + ifcstat)
+ }
+
+ fields := getFields(line)
+ if len(fields) < 4 {
+ return nil, errors.New("invalid interface status file: " + ifcstat)
+ }
+
+ device := fields[1]
+ mtustr := fields[3]
+
+ mtu, _, ok := dtoi(mtustr)
+ if !ok {
+ return nil, errors.New("invalid status file of interface: " + ifcstat)
+ }
+ ifc.MTU = mtu
+
+ // Not a loopback device
+ if device != "/dev/null" {
+ deviceaddrf, err := open(device + "/addr")
+ if err != nil {
+ return nil, err
+ }
+ defer deviceaddrf.close()
+
+ line, ok = deviceaddrf.readLine()
+ if !ok {
+ return nil, errors.New("invalid address file for interface: " + device + "/addr")
+ }
+
+ if len(line) > 0 && len(line)%2 == 0 {
+ ifc.HardwareAddr = make([]byte, len(line)/2)
+ var ok bool
+ for i := range ifc.HardwareAddr {
+ j := (i + 1) * 2
+ ifc.HardwareAddr[i], ok = xtoi2(line[i*2:j], 0)
+ if !ok {
+ ifc.HardwareAddr = ifc.HardwareAddr[:i]
+ break
+ }
+ }
+ }
+
+ ifc.Flags = FlagUp | FlagBroadcast | FlagMulticast
+ } else {
+ ifc.Flags = FlagUp | FlagMulticast | FlagLoopback
+ }
+
+ return ifc, nil
+}
+
+func interfaceCount() (int, error) {
+ d, err := os.Open(netdir + "/ipifc")
+ if err != nil {
+ return -1, err
+ }
+ defer d.Close()
+
+ names, err := d.Readdirnames(0)
+ if err != nil {
+ return -1, err
+ }
+
+ // Assumes that numbered files in ipifc are strictly
+ // the incrementing numbered directories for the
+ // interfaces
+ c := 0
+ for _, name := range names {
+ if _, _, ok := dtoi(name); !ok {
+ continue
+ }
+ c++
+ }
+
+ return c, nil
+}
+
+// If the ifi is nil, interfaceAddrTable returns addresses for all
+// network interfaces. Otherwise it returns addresses for a specific
+// interface.
+func interfaceAddrTable(ifi *Interface) ([]Addr, error) {
+ var ifcs []Interface
+ if ifi == nil {
+ var err error
+ ifcs, err = interfaceTable(0)
+ if err != nil {
+ return nil, err
+ }
+ } else {
+ ifcs = []Interface{*ifi}
+ }
+
+ addrs := make([]Addr, len(ifcs))
+ for i, ifc := range ifcs {
+ status := ifc.Name + "/status"
+ statusf, err := open(status)
+ if err != nil {
+ return nil, err
+ }
+ defer statusf.close()
+
+ line, ok := statusf.readLine()
+ line, ok = statusf.readLine()
+ if !ok {
+ return nil, errors.New("cannot parse IP address for interface: " + status)
+ }
+
+ // This assumes only a single address for the interface.
+ fields := getFields(line)
+ if len(fields) < 1 {
+ return nil, errors.New("cannot parse IP address for interface: " + status)
+ }
+ addr := fields[0]
+ ip := ParseIP(addr)
+ if ip == nil {
+ return nil, errors.New("cannot parse IP address for interface: " + status)
+ }
+
+ // The mask is represented as CIDR relative to the IPv6 address.
+ // Plan 9 internal representation is always IPv6.
+ maskfld := fields[1]
+ maskfld = maskfld[1:]
+ pfxlen, _, ok := dtoi(maskfld)
+ if !ok {
+ return nil, errors.New("cannot parse network mask for interface: " + status)
+ }
+ var mask IPMask
+ if ip.To4() != nil { // IPv4 or IPv6 IPv4-mapped address
+ mask = CIDRMask(pfxlen-8*len(v4InV6Prefix), 8*IPv4len)
+ }
+ if ip.To16() != nil && ip.To4() == nil { // IPv6 address
+ mask = CIDRMask(pfxlen, 8*IPv6len)
+ }
+
+ addrs[i] = &IPNet{IP: ip, Mask: mask}
+ }
+
+ return addrs, nil
+}
+
+// interfaceMulticastAddrTable returns addresses for a specific
+// interface.
+func interfaceMulticastAddrTable(ifi *Interface) ([]Addr, error) {
+ return nil, nil
+}
diff --git a/src/net/interface_solaris.go b/src/net/interface_solaris.go
new file mode 100644
index 0000000..dc8ffbf
--- /dev/null
+++ b/src/net/interface_solaris.go
@@ -0,0 +1,107 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package net
+
+import (
+ "syscall"
+
+ "golang_org/x/net/lif"
+)
+
+// If the ifindex is zero, interfaceTable returns mappings of all
+// network interfaces. Otherwise it returns a mapping of a specific
+// interface.
+func interfaceTable(ifindex int) ([]Interface, error) {
+ lls, err := lif.Links(syscall.AF_UNSPEC, "")
+ if err != nil {
+ return nil, err
+ }
+ var ift []Interface
+ for _, ll := range lls {
+ if ifindex != 0 && ifindex != ll.Index {
+ continue
+ }
+ ifi := Interface{Index: ll.Index, MTU: ll.MTU, Name: ll.Name, Flags: linkFlags(ll.Flags)}
+ if len(ll.Addr) > 0 {
+ ifi.HardwareAddr = HardwareAddr(ll.Addr)
+ }
+ ift = append(ift, ifi)
+ }
+ return ift, nil
+}
+
+const (
+ sysIFF_UP = 0x1
+ sysIFF_BROADCAST = 0x2
+ sysIFF_DEBUG = 0x4
+ sysIFF_LOOPBACK = 0x8
+ sysIFF_POINTOPOINT = 0x10
+ sysIFF_NOTRAILERS = 0x20
+ sysIFF_RUNNING = 0x40
+ sysIFF_NOARP = 0x80
+ sysIFF_PROMISC = 0x100
+ sysIFF_ALLMULTI = 0x200
+ sysIFF_INTELLIGENT = 0x400
+ sysIFF_MULTICAST = 0x800
+ sysIFF_MULTI_BCAST = 0x1000
+ sysIFF_UNNUMBERED = 0x2000
+ sysIFF_PRIVATE = 0x8000
+)
+
+func linkFlags(rawFlags int) Flags {
+ var f Flags
+ if rawFlags&sysIFF_UP != 0 {
+ f |= FlagUp
+ }
+ if rawFlags&sysIFF_BROADCAST != 0 {
+ f |= FlagBroadcast
+ }
+ if rawFlags&sysIFF_LOOPBACK != 0 {
+ f |= FlagLoopback
+ }
+ if rawFlags&sysIFF_POINTOPOINT != 0 {
+ f |= FlagPointToPoint
+ }
+ if rawFlags&sysIFF_MULTICAST != 0 {
+ f |= FlagMulticast
+ }
+ return f
+}
+
+// If the ifi is nil, interfaceAddrTable returns addresses for all
+// network interfaces. Otherwise it returns addresses for a specific
+// interface.
+func interfaceAddrTable(ifi *Interface) ([]Addr, error) {
+ var name string
+ if ifi != nil {
+ name = ifi.Name
+ }
+ as, err := lif.Addrs(syscall.AF_UNSPEC, name)
+ if err != nil {
+ return nil, err
+ }
+ var ifat []Addr
+ for _, a := range as {
+ var ip IP
+ var mask IPMask
+ switch a := a.(type) {
+ case *lif.Inet4Addr:
+ ip = IPv4(a.IP[0], a.IP[1], a.IP[2], a.IP[3])
+ mask = CIDRMask(a.PrefixLen, 8*IPv4len)
+ case *lif.Inet6Addr:
+ ip = make(IP, IPv6len)
+ copy(ip, a.IP[:])
+ mask = CIDRMask(a.PrefixLen, 8*IPv6len)
+ }
+ ifat = append(ifat, &IPNet{IP: ip, Mask: mask})
+ }
+ return ifat, nil
+}
+
+// interfaceMulticastAddrTable returns addresses for a specific
+// interface.
+func interfaceMulticastAddrTable(ifi *Interface) ([]Addr, error) {
+ return nil, nil
+}
diff --git a/src/net/interface_stub.go b/src/net/interface_stub.go
index f64174c..3b0a1ae 100644
--- a/src/net/interface_stub.go
+++ b/src/net/interface_stub.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build nacl plan9 solaris
+// +build nacl
package net
diff --git a/src/net/interface_test.go b/src/net/interface_test.go
index 4c695b9..38a2ca4 100644
--- a/src/net/interface_test.go
+++ b/src/net/interface_test.go
@@ -58,8 +58,15 @@ func TestInterfaces(t *testing.T) {
if err != nil {
t.Fatal(err)
}
- if !reflect.DeepEqual(ifxi, &ifi) {
- t.Errorf("got %v; want %v", ifxi, ifi)
+ switch runtime.GOOS {
+ case "solaris":
+ if ifxi.Index != ifi.Index {
+ t.Errorf("got %v; want %v", ifxi, ifi)
+ }
+ default:
+ if !reflect.DeepEqual(ifxi, &ifi) {
+ t.Errorf("got %v; want %v", ifxi, ifi)
+ }
}
ifxn, err := InterfaceByName(ifi.Name)
if err != nil {
diff --git a/src/net/ip.go b/src/net/ip.go
index d0c8263..c5b454d 100644
--- a/src/net/ip.go
+++ b/src/net/ip.go
@@ -504,29 +504,25 @@ func (n *IPNet) String() string {
// Parse IPv4 address (d.d.d.d).
func parseIPv4(s string) IP {
var p [IPv4len]byte
- i := 0
- for j := 0; j < IPv4len; j++ {
- if i >= len(s) {
+ for i := 0; i < IPv4len; i++ {
+ if len(s) == 0 {
// Missing octets.
return nil
}
- if j > 0 {
- if s[i] != '.' {
+ if i > 0 {
+ if s[0] != '.' {
return nil
}
- i++
+ s = s[1:]
}
- var (
- n int
- ok bool
- )
- n, i, ok = dtoi(s, i)
+ n, c, ok := dtoi(s)
if !ok || n > 0xFF {
return nil
}
- p[j] = byte(n)
+ s = s[c:]
+ p[i] = byte(n)
}
- if i != len(s) {
+ if len(s) != 0 {
return nil
}
return IPv4(p[0], p[1], p[2], p[3])
@@ -538,8 +534,7 @@ func parseIPv4(s string) IP {
// true.
func parseIPv6(s string, zoneAllowed bool) (ip IP, zone string) {
ip = make(IP, IPv6len)
- ellipsis := -1 // position of ellipsis in p
- i := 0 // index in string s
+ ellipsis := -1 // position of ellipsis in ip
if zoneAllowed {
s, zone = splitHostZone(s)
@@ -548,90 +543,91 @@ func parseIPv6(s string, zoneAllowed bool) (ip IP, zone string) {
// Might have leading ellipsis
if len(s) >= 2 && s[0] == ':' && s[1] == ':' {
ellipsis = 0
- i = 2
+ s = s[2:]
// Might be only ellipsis
- if i == len(s) {
+ if len(s) == 0 {
return ip, zone
}
}
// Loop, parsing hex numbers followed by colon.
- j := 0
- for j < IPv6len {
+ i := 0
+ for i < IPv6len {
// Hex number.
- n, i1, ok := xtoi(s, i)
+ n, c, ok := xtoi(s)
if !ok || n > 0xFFFF {
return nil, zone
}
// If followed by dot, might be in trailing IPv4.
- if i1 < len(s) && s[i1] == '.' {
- if ellipsis < 0 && j != IPv6len-IPv4len {
+ if c < len(s) && s[c] == '.' {
+ if ellipsis < 0 && i != IPv6len-IPv4len {
// Not the right place.
return nil, zone
}
- if j+IPv4len > IPv6len {
+ if i+IPv4len > IPv6len {
// Not enough room.
return nil, zone
}
- ip4 := parseIPv4(s[i:])
+ ip4 := parseIPv4(s)
if ip4 == nil {
return nil, zone
}
- ip[j] = ip4[12]
- ip[j+1] = ip4[13]
- ip[j+2] = ip4[14]
- ip[j+3] = ip4[15]
- i = len(s)
- j += IPv4len
+ ip[i] = ip4[12]
+ ip[i+1] = ip4[13]
+ ip[i+2] = ip4[14]
+ ip[i+3] = ip4[15]
+ s = ""
+ i += IPv4len
break
}
// Save this 16-bit chunk.
- ip[j] = byte(n >> 8)
- ip[j+1] = byte(n)
- j += 2
+ ip[i] = byte(n >> 8)
+ ip[i+1] = byte(n)
+ i += 2
// Stop at end of string.
- i = i1
- if i == len(s) {
+ s = s[c:]
+ if len(s) == 0 {
break
}
// Otherwise must be followed by colon and more.
- if s[i] != ':' || i+1 == len(s) {
+ if s[0] != ':' || len(s) == 1 {
return nil, zone
}
- i++
+ s = s[1:]
// Look for ellipsis.
- if s[i] == ':' {
+ if s[0] == ':' {
if ellipsis >= 0 { // already have one
return nil, zone
}
- ellipsis = j
- if i++; i == len(s) { // can be at end
+ ellipsis = i
+ s = s[1:]
+ if len(s) == 0 { // can be at end
break
}
}
}
// Must have used entire string.
- if i != len(s) {
+ if len(s) != 0 {
return nil, zone
}
// If didn't parse enough, expand ellipsis.
- if j < IPv6len {
+ if i < IPv6len {
if ellipsis < 0 {
return nil, zone
}
- n := IPv6len - j
- for k := j - 1; k >= ellipsis; k-- {
- ip[k+n] = ip[k]
+ n := IPv6len - i
+ for j := i - 1; j >= ellipsis; j-- {
+ ip[j+n] = ip[j]
}
- for k := ellipsis + n - 1; k >= ellipsis; k-- {
- ip[k] = 0
+ for j := ellipsis + n - 1; j >= ellipsis; j-- {
+ ip[j] = 0
}
} else if ellipsis >= 0 {
// Ellipsis must represent at least one 0 group.
@@ -677,7 +673,7 @@ func ParseCIDR(s string) (IP, *IPNet, error) {
iplen = IPv6len
ip, _ = parseIPv6(addr, false)
}
- n, i, ok := dtoi(mask, 0)
+ n, i, ok := dtoi(mask)
if ip == nil || !ok || i != len(mask) || n < 0 || n > 8*iplen {
return nil, nil, &ParseError{Type: "CIDR address", Text: s}
}
diff --git a/src/net/ip_test.go b/src/net/ip_test.go
index b6ac26d..4655163 100644
--- a/src/net/ip_test.go
+++ b/src/net/ip_test.go
@@ -28,6 +28,10 @@ var parseIPTests = []struct {
{"2001:4860:0:2001::68", IP{0x20, 0x01, 0x48, 0x60, 0, 0, 0x20, 0x01, 0, 0, 0, 0, 0, 0, 0x00, 0x68}},
{"2001:4860:0000:2001:0000:0000:0000:0068", IP{0x20, 0x01, 0x48, 0x60, 0, 0, 0x20, 0x01, 0, 0, 0, 0, 0, 0, 0x00, 0x68}},
+ {"-0.0.0.0", nil},
+ {"0.-1.0.0", nil},
+ {"0.0.-2.0", nil},
+ {"0.0.0.-3", nil},
{"127.0.0.256", nil},
{"abc", nil},
{"123:", nil},
@@ -242,13 +246,15 @@ func TestIPString(t *testing.T) {
}
}
+var sink string
+
func BenchmarkIPString(b *testing.B) {
testHookUninstaller.Do(uninstallTestHooks)
for i := 0; i < b.N; i++ {
for _, tt := range ipStringTests {
if tt.in != nil {
- tt.in.String()
+ sink = tt.in.String()
}
}
}
@@ -299,7 +305,7 @@ func BenchmarkIPMaskString(b *testing.B) {
for i := 0; i < b.N; i++ {
for _, tt := range ipMaskStringTests {
- tt.in.String()
+ sink = tt.in.String()
}
}
}
@@ -330,6 +336,12 @@ var parseCIDRTests = []struct {
{"192.168.1.1/255.255.255.0", nil, nil, &ParseError{Type: "CIDR address", Text: "192.168.1.1/255.255.255.0"}},
{"192.168.1.1/35", nil, nil, &ParseError{Type: "CIDR address", Text: "192.168.1.1/35"}},
{"2001:db8::1/-1", nil, nil, &ParseError{Type: "CIDR address", Text: "2001:db8::1/-1"}},
+ {"2001:db8::1/-0", nil, nil, &ParseError{Type: "CIDR address", Text: "2001:db8::1/-0"}},
+ {"-0.0.0.0/32", nil, nil, &ParseError{Type: "CIDR address", Text: "-0.0.0.0/32"}},
+ {"0.-1.0.0/32", nil, nil, &ParseError{Type: "CIDR address", Text: "0.-1.0.0/32"}},
+ {"0.0.-2.0/32", nil, nil, &ParseError{Type: "CIDR address", Text: "0.0.-2.0/32"}},
+ {"0.0.0.-3/32", nil, nil, &ParseError{Type: "CIDR address", Text: "0.0.0.-3/32"}},
+ {"0.0.0.0/-0", nil, nil, &ParseError{Type: "CIDR address", Text: "0.0.0.0/-0"}},
{"", nil, nil, &ParseError{Type: "CIDR address", Text: ""}},
}
diff --git a/src/net/iprawsock.go b/src/net/iprawsock.go
index 173b3cb..b3cc03e 100644
--- a/src/net/iprawsock.go
+++ b/src/net/iprawsock.go
@@ -9,6 +9,12 @@ import (
"syscall"
)
+// BUG(mikio): On NaCl, Plan 9 and Windows, the ReadMsgIP and
+// WriteMsgIP methods of IPConn are not implemented.
+
+// BUG(mikio): On Windows, the File method of IPConn is not
+// implemented.
+
// IPAddr represents the address of an IP end point.
type IPAddr struct {
IP IP
@@ -46,6 +52,9 @@ func (a *IPAddr) opAddr() Addr {
// ResolveIPAddr parses addr as an IP address of the form "host" or
// "ipv6-host%zone" and resolves the domain name on the network net,
// which must be "ip", "ip4" or "ip6".
+//
+// Resolving a hostname is not recommended because this returns at most
+// one of its IP addresses.
func ResolveIPAddr(net, addr string) (*IPAddr, error) {
if net == "" { // a hint wildcard for Go 1.0 undocumented behavior
net = "ip"
@@ -59,7 +68,7 @@ func ResolveIPAddr(net, addr string) (*IPAddr, error) {
default:
return nil, UnknownNetworkError(net)
}
- addrs, err := internetAddrList(context.Background(), afnet, addr)
+ addrs, err := DefaultResolver.internetAddrList(context.Background(), afnet, addr)
if err != nil {
return nil, err
}
diff --git a/src/net/iprawsock_posix.go b/src/net/iprawsock_posix.go
index 3e0b060..d5e229f 100644
--- a/src/net/iprawsock_posix.go
+++ b/src/net/iprawsock_posix.go
@@ -50,6 +50,10 @@ func (a *IPAddr) sockaddr(family int) (syscall.Sockaddr, error) {
return ipToSockaddr(family, a.IP, 0, a.Zone)
}
+func (a *IPAddr) toLocal(net string) sockaddr {
+ return &IPAddr{loopbackIP(net), a.Zone}
+}
+
func (c *IPConn) readFrom(b []byte) (int, *IPAddr, error) {
// TODO(cw,rsc): consider using readv if we know the family
// type to avoid the header trim/copy
diff --git a/src/net/ipsock.go b/src/net/ipsock.go
index 24daf17..c91e201 100644
--- a/src/net/ipsock.go
+++ b/src/net/ipsock.go
@@ -76,7 +76,7 @@ func (addrs addrList) partition(strategy func(Addr) bool) (primaries, fallbacks
// yielding a list of Addr objects. Known filters are nil, ipv4only,
// and ipv6only. It returns every address when the filter is nil.
// The result contains at least one address when error is nil.
-func filterAddrList(filter func(IPAddr) bool, ips []IPAddr, inetaddr func(IPAddr) Addr) (addrList, error) {
+func filterAddrList(filter func(IPAddr) bool, ips []IPAddr, inetaddr func(IPAddr) Addr, originalAddr string) (addrList, error) {
var addrs addrList
for _, ip := range ips {
if filter == nil || filter(ip) {
@@ -84,21 +84,19 @@ func filterAddrList(filter func(IPAddr) bool, ips []IPAddr, inetaddr func(IPAddr
}
}
if len(addrs) == 0 {
- return nil, errNoSuitableAddress
+ return nil, &AddrError{Err: errNoSuitableAddress.Error(), Addr: originalAddr}
}
return addrs, nil
}
-// ipv4only reports whether the kernel supports IPv4 addressing mode
-// and addr is an IPv4 address.
+// ipv4only reports whether addr is an IPv4 address.
func ipv4only(addr IPAddr) bool {
- return supportsIPv4 && addr.IP.To4() != nil
+ return addr.IP.To4() != nil
}
-// ipv6only reports whether the kernel supports IPv6 addressing mode
-// and addr is an IPv6 address except IPv4-mapped IPv6 address.
+// ipv6only reports whether addr is an IPv6 address except IPv4-mapped IPv6 address.
func ipv6only(addr IPAddr) bool {
- return supportsIPv6 && len(addr.IP) == IPv6len && addr.IP.To4() == nil
+ return len(addr.IP) == IPv6len && addr.IP.To4() == nil
}
// SplitHostPort splits a network address of the form "host:port",
@@ -190,7 +188,7 @@ func JoinHostPort(host, port string) string {
// address or a DNS name, and returns a list of internet protocol
// family addresses. The result contains at least one address when
// error is nil.
-func internetAddrList(ctx context.Context, net, addr string) (addrList, error) {
+func (r *Resolver) internetAddrList(ctx context.Context, net, addr string) (addrList, error) {
var (
err error
host, port string
@@ -202,7 +200,7 @@ func internetAddrList(ctx context.Context, net, addr string) (addrList, error) {
if host, port, err = SplitHostPort(addr); err != nil {
return nil, err
}
- if portnum, err = LookupPort(net, port); err != nil {
+ if portnum, err = r.LookupPort(ctx, net, port); err != nil {
return nil, err
}
}
@@ -228,20 +226,21 @@ func internetAddrList(ctx context.Context, net, addr string) (addrList, error) {
if host == "" {
return addrList{inetaddr(IPAddr{})}, nil
}
- // Try as a literal IP address.
- var ip IP
- if ip = parseIPv4(host); ip != nil {
- return addrList{inetaddr(IPAddr{IP: ip})}, nil
- }
- var zone string
- if ip, zone = parseIPv6(host, true); ip != nil {
- return addrList{inetaddr(IPAddr{IP: ip, Zone: zone})}, nil
- }
- // Try as a DNS name.
- ips, err := lookupIPContext(ctx, host)
- if err != nil {
- return nil, err
+
+ // Try as a literal IP address, then as a DNS name.
+ var ips []IPAddr
+ if ip := parseIPv4(host); ip != nil {
+ ips = []IPAddr{{IP: ip}}
+ } else if ip, zone := parseIPv6(host, true); ip != nil {
+ ips = []IPAddr{{IP: ip, Zone: zone}}
+ } else {
+ // Try as a DNS name.
+ ips, err = r.LookupIPAddr(ctx, host)
+ if err != nil {
+ return nil, err
+ }
}
+
var filter func(IPAddr) bool
if net != "" && net[len(net)-1] == '4' {
filter = ipv4only
@@ -249,5 +248,12 @@ func internetAddrList(ctx context.Context, net, addr string) (addrList, error) {
if net != "" && net[len(net)-1] == '6' {
filter = ipv6only
}
- return filterAddrList(filter, ips, inetaddr)
+ return filterAddrList(filter, ips, inetaddr, host)
+}
+
+func loopbackIP(net string) IP {
+ if net != "" && net[len(net)-1] == '6' {
+ return IPv6loopback
+ }
+ return IP{127, 0, 0, 1}
}
diff --git a/src/net/ipsock_plan9.go b/src/net/ipsock_plan9.go
index 2b84683..b7fd344 100644
--- a/src/net/ipsock_plan9.go
+++ b/src/net/ipsock_plan9.go
@@ -63,7 +63,7 @@ func parsePlan9Addr(s string) (ip IP, iport int, err error) {
return nil, 0, &ParseError{Type: "IP address", Text: s}
}
}
- p, _, ok := dtoi(s[i+1:], 0)
+ p, _, ok := dtoi(s[i+1:])
if !ok {
return nil, 0, &ParseError{Type: "port", Text: s}
}
@@ -119,6 +119,11 @@ func startPlan9(ctx context.Context, net string, addr Addr) (ctl *os.File, dest,
return
}
+ if port > 65535 {
+ err = InvalidAddrError("port should be < 65536")
+ return
+ }
+
clone, dest, err := queryCS1(ctx, proto, ip, port)
if err != nil {
return
@@ -193,6 +198,9 @@ func dialPlan9(ctx context.Context, net string, laddr, raddr Addr) (fd *netFD, e
}
func dialPlan9Blocking(ctx context.Context, net string, laddr, raddr Addr) (fd *netFD, err error) {
+ if isWildcard(raddr) {
+ raddr = toLocal(raddr, net)
+ }
f, dest, proto, name, err := startPlan9(ctx, net, raddr)
if err != nil {
return nil, err
@@ -213,7 +221,7 @@ func dialPlan9Blocking(ctx context.Context, net string, laddr, raddr Addr) (fd *
f.Close()
return nil, err
}
- return newFD(proto, name, f, data, laddr, raddr)
+ return newFD(proto, name, nil, f, data, laddr, raddr)
}
func listenPlan9(ctx context.Context, net string, laddr Addr) (fd *netFD, err error) {
@@ -232,11 +240,11 @@ func listenPlan9(ctx context.Context, net string, laddr Addr) (fd *netFD, err er
f.Close()
return nil, err
}
- return newFD(proto, name, f, nil, laddr, nil)
+ return newFD(proto, name, nil, f, nil, laddr, nil)
}
func (fd *netFD) netFD() (*netFD, error) {
- return newFD(fd.net, fd.n, fd.ctl, fd.data, fd.laddr, fd.raddr)
+ return newFD(fd.net, fd.n, fd.listen, fd.ctl, fd.data, fd.laddr, fd.raddr)
}
func (fd *netFD) acceptPlan9() (nfd *netFD, err error) {
@@ -245,27 +253,59 @@ func (fd *netFD) acceptPlan9() (nfd *netFD, err error) {
return nil, err
}
defer fd.readUnlock()
- f, err := os.Open(fd.dir + "/listen")
+ listen, err := os.Open(fd.dir + "/listen")
if err != nil {
return nil, err
}
var buf [16]byte
- n, err := f.Read(buf[:])
+ n, err := listen.Read(buf[:])
if err != nil {
- f.Close()
+ listen.Close()
return nil, err
}
name := string(buf[:n])
+ ctl, err := os.OpenFile(netdir+"/"+fd.net+"/"+name+"/ctl", os.O_RDWR, 0)
+ if err != nil {
+ listen.Close()
+ return nil, err
+ }
data, err := os.OpenFile(netdir+"/"+fd.net+"/"+name+"/data", os.O_RDWR, 0)
if err != nil {
- f.Close()
+ listen.Close()
+ ctl.Close()
return nil, err
}
raddr, err := readPlan9Addr(fd.net, netdir+"/"+fd.net+"/"+name+"/remote")
if err != nil {
+ listen.Close()
+ ctl.Close()
data.Close()
- f.Close()
return nil, err
}
- return newFD(fd.net, name, f, data, fd.laddr, raddr)
+ return newFD(fd.net, name, listen, ctl, data, fd.laddr, raddr)
+}
+
+func isWildcard(a Addr) bool {
+ var wildcard bool
+ switch a := a.(type) {
+ case *TCPAddr:
+ wildcard = a.isWildcard()
+ case *UDPAddr:
+ wildcard = a.isWildcard()
+ case *IPAddr:
+ wildcard = a.isWildcard()
+ }
+ return wildcard
+}
+
+func toLocal(a Addr, net string) Addr {
+ switch a := a.(type) {
+ case *TCPAddr:
+ a.IP = loopbackIP(net)
+ case *UDPAddr:
+ a.IP = loopbackIP(net)
+ case *IPAddr:
+ a.IP = loopbackIP(net)
+ }
+ return a
}
diff --git a/src/net/ipsock_posix.go b/src/net/ipsock_posix.go
index abe90ac..f4fab3f 100644
--- a/src/net/ipsock_posix.go
+++ b/src/net/ipsock_posix.go
@@ -154,6 +154,9 @@ func favoriteAddrFamily(net string, laddr, raddr sockaddr, mode string) (family
// 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)
+ }
family, ipv6only := favoriteAddrFamily(net, laddr, raddr, mode)
return socket(ctx, net, family, sotype, proto, ipv6only, laddr, raddr)
}
diff --git a/src/net/ipsock_test.go b/src/net/ipsock_test.go
index b36557a..1d0f00f 100644
--- a/src/net/ipsock_test.go
+++ b/src/net/ipsock_test.go
@@ -205,13 +205,13 @@ var addrListTests = []struct {
nil,
},
- {nil, nil, testInetaddr, nil, nil, nil, errNoSuitableAddress},
+ {nil, nil, testInetaddr, nil, nil, nil, &AddrError{errNoSuitableAddress.Error(), "ADDR"}},
- {ipv4only, nil, testInetaddr, nil, nil, nil, errNoSuitableAddress},
- {ipv4only, []IPAddr{{IP: IPv6loopback}}, testInetaddr, nil, nil, nil, errNoSuitableAddress},
+ {ipv4only, nil, testInetaddr, nil, nil, nil, &AddrError{errNoSuitableAddress.Error(), "ADDR"}},
+ {ipv4only, []IPAddr{{IP: IPv6loopback}}, testInetaddr, nil, nil, nil, &AddrError{errNoSuitableAddress.Error(), "ADDR"}},
- {ipv6only, nil, testInetaddr, nil, nil, nil, errNoSuitableAddress},
- {ipv6only, []IPAddr{{IP: IPv4(127, 0, 0, 1)}}, testInetaddr, nil, nil, nil, errNoSuitableAddress},
+ {ipv6only, nil, testInetaddr, nil, nil, nil, &AddrError{errNoSuitableAddress.Error(), "ADDR"}},
+ {ipv6only, []IPAddr{{IP: IPv4(127, 0, 0, 1)}}, testInetaddr, nil, nil, nil, &AddrError{errNoSuitableAddress.Error(), "ADDR"}},
}
func TestAddrList(t *testing.T) {
@@ -220,8 +220,8 @@ func TestAddrList(t *testing.T) {
}
for i, tt := range addrListTests {
- addrs, err := filterAddrList(tt.filter, tt.ips, tt.inetaddr)
- if err != tt.err {
+ addrs, err := filterAddrList(tt.filter, tt.ips, tt.inetaddr, "ADDR")
+ if !reflect.DeepEqual(err, tt.err) {
t.Errorf("#%v: got %v; want %v", i, err, tt.err)
}
if tt.err != nil {
diff --git a/src/net/lookup.go b/src/net/lookup.go
index c169e9e..8b5cab0 100644
--- a/src/net/lookup.go
+++ b/src/net/lookup.go
@@ -15,94 +15,137 @@ import (
// protocol numbers.
//
// See http://www.iana.org/assignments/protocol-numbers
+//
+// On Unix, this map is augmented by readProtocols via lookupProtocol.
var protocols = map[string]int{
- "icmp": 1, "ICMP": 1,
- "igmp": 2, "IGMP": 2,
- "tcp": 6, "TCP": 6,
- "udp": 17, "UDP": 17,
- "ipv6-icmp": 58, "IPV6-ICMP": 58, "IPv6-ICMP": 58,
+ "icmp": 1,
+ "igmp": 2,
+ "tcp": 6,
+ "udp": 17,
+ "ipv6-icmp": 58,
}
-// LookupHost looks up the given host using the local resolver.
-// It returns an array of that host's addresses.
-func LookupHost(host string) (addrs []string, err error) {
- // Make sure that no matter what we do later, host=="" is rejected.
- // ParseIP, for example, does accept empty strings.
- if host == "" {
- return nil, &DNSError{Err: errNoSuchHost.Error(), Name: host}
+// services contains minimal mappings between services names and port
+// numbers for platforms that don't have a complete list of port numbers
+// (some Solaris distros, nacl, etc).
+// On Unix, this map is augmented by readServices via goLookupPort.
+var services = map[string]map[string]int{
+ "udp": {
+ "domain": 53,
+ },
+ "tcp": {
+ "ftp": 21,
+ "ftps": 990,
+ "gopher": 70, // ʕ◔ϖ◔ʔ
+ "http": 80,
+ "https": 443,
+ "imap2": 143,
+ "imap3": 220,
+ "imaps": 993,
+ "pop3": 110,
+ "pop3s": 995,
+ "smtp": 25,
+ "ssh": 22,
+ "telnet": 23,
+ },
+}
+
+const maxProtoLength = len("RSVP-E2E-IGNORE") + 10 // with room to grow
+
+func lookupProtocolMap(name string) (int, error) {
+ var lowerProtocol [maxProtoLength]byte
+ n := copy(lowerProtocol[:], name)
+ lowerASCIIBytes(lowerProtocol[:n])
+ proto, found := protocols[string(lowerProtocol[:n])]
+ if !found || n != len(name) {
+ return 0, &AddrError{Err: "unknown IP protocol specified", Addr: name}
}
- if ip := ParseIP(host); ip != nil {
- return []string{host}, nil
+ return proto, nil
+}
+
+const maxServiceLength = len("mobility-header") + 10 // with room to grow
+
+func lookupPortMap(network, service string) (port int, error error) {
+ switch network {
+ case "tcp4", "tcp6":
+ network = "tcp"
+ case "udp4", "udp6":
+ network = "udp"
}
- return lookupHost(context.Background(), host)
+
+ if m, ok := services[network]; ok {
+ var lowerService [maxServiceLength]byte
+ n := copy(lowerService[:], service)
+ lowerASCIIBytes(lowerService[:n])
+ if port, ok := m[string(lowerService[:n])]; ok && n == len(service) {
+ return port, nil
+ }
+ }
+ return 0, &AddrError{Err: "unknown port", Addr: network + "/" + service}
}
-// LookupIP looks up host using the local resolver.
-// It returns an array of that host's IPv4 and IPv6 addresses.
-func LookupIP(host string) (ips []IP, err error) {
+// DefaultResolver is the resolver used by the package-level Lookup
+// functions and by Dialers without a specified Resolver.
+var DefaultResolver = &Resolver{}
+
+// A Resolver looks up names and numbers.
+//
+// A nil *Resolver is equivalent to a zero Resolver.
+type Resolver struct {
+ // PreferGo controls whether Go's built-in DNS resolver is preferred
+ // on platforms where it's available. It is equivalent to setting
+ // GODEBUG=netdns=go, but scoped to just this resolver.
+ PreferGo bool
+
+ // TODO(bradfitz): optional interface impl override hook
+ // TODO(bradfitz): Timeout time.Duration?
+}
+
+// LookupHost looks up the given host using the local resolver.
+// It returns a slice of that host's addresses.
+func LookupHost(host string) (addrs []string, err error) {
+ return DefaultResolver.LookupHost(context.Background(), host)
+}
+
+// LookupHost looks up the given host using the local resolver.
+// It returns a slice of that host's addresses.
+func (r *Resolver) LookupHost(ctx context.Context, host string) (addrs []string, err error) {
// Make sure that no matter what we do later, host=="" is rejected.
// ParseIP, for example, does accept empty strings.
if host == "" {
return nil, &DNSError{Err: errNoSuchHost.Error(), Name: host}
}
if ip := ParseIP(host); ip != nil {
- return []IP{ip}, nil
- }
- addrs, err := lookupIPMerge(context.Background(), host)
- if err != nil {
- return
- }
- ips = make([]IP, len(addrs))
- for i, addr := range addrs {
- ips[i] = addr.IP
+ return []string{host}, nil
}
- return
-}
-
-var lookupGroup singleflight.Group
-
-// lookupIPMerge wraps lookupIP, but makes sure that for any given
-// host, only one lookup is in-flight at a time. The returned memory
-// is always owned by the caller.
-func lookupIPMerge(ctx context.Context, host string) (addrs []IPAddr, err error) {
- addrsi, err, shared := lookupGroup.Do(host, func() (interface{}, error) {
- return testHookLookupIP(ctx, lookupIP, host)
- })
- return lookupIPReturn(addrsi, err, shared)
+ return r.lookupHost(ctx, host)
}
-// lookupIPReturn turns the return values from singleflight.Do into
-// the return values from LookupIP.
-func lookupIPReturn(addrsi interface{}, err error, shared bool) ([]IPAddr, error) {
+// LookupIP looks up host using the local resolver.
+// It returns a slice of that host's IPv4 and IPv6 addresses.
+func LookupIP(host string) ([]IP, error) {
+ addrs, err := DefaultResolver.LookupIPAddr(context.Background(), host)
if err != nil {
return nil, err
}
- addrs := addrsi.([]IPAddr)
- if shared {
- clone := make([]IPAddr, len(addrs))
- copy(clone, addrs)
- addrs = clone
+ ips := make([]IP, len(addrs))
+ for i, ia := range addrs {
+ ips[i] = ia.IP
}
- return addrs, nil
+ return ips, nil
}
-// ipAddrsEface returns an empty interface slice of addrs.
-func ipAddrsEface(addrs []IPAddr) []interface{} {
- s := make([]interface{}, len(addrs))
- for i, v := range addrs {
- s[i] = v
+// LookupIPAddr looks up host using the local resolver.
+// It returns a slice of that host's IPv4 and IPv6 addresses.
+func (r *Resolver) LookupIPAddr(ctx context.Context, host string) ([]IPAddr, error) {
+ // Make sure that no matter what we do later, host=="" is rejected.
+ // ParseIP, for example, does accept empty strings.
+ if host == "" {
+ return nil, &DNSError{Err: errNoSuchHost.Error(), Name: host}
+ }
+ if ip := ParseIP(host); ip != nil {
+ return []IPAddr{{IP: ip}}, nil
}
- return s
-}
-
-// lookupIPContext looks up a hostname with a context.
-//
-// TODO(bradfitz): rename this function. All the other
-// build-tag-specific lookupIP funcs also take a context now, so this
-// name is no longer great. Maybe make this lookupIPMerge and ditch
-// the other one, making its callers call this instead with a
-// context.Background().
-func lookupIPContext(ctx context.Context, host string) (addrs []IPAddr, err error) {
trace, _ := ctx.Value(nettrace.TraceKey{}).(*nettrace.Trace)
if trace != nil && trace.DNSStart != nil {
trace.DNSStart(host)
@@ -110,7 +153,7 @@ func lookupIPContext(ctx context.Context, host string) (addrs []IPAddr, err erro
// The underlying resolver func is lookupIP by default but it
// can be overridden by tests. This is needed by net/http, so it
// uses a context key instead of unexported variables.
- resolverFunc := lookupIP
+ resolverFunc := r.lookupIP
if alt, _ := ctx.Value(nettrace.LookupIPAltResolverKey{}).(func(context.Context, string) ([]IPAddr, error)); alt != nil {
resolverFunc = alt
}
@@ -140,11 +183,46 @@ func lookupIPContext(ctx context.Context, host string) (addrs []IPAddr, err erro
}
}
+// lookupGroup merges LookupIPAddr calls together for lookups
+// for the same host. The lookupGroup key is is the LookupIPAddr.host
+// argument.
+// The return values are ([]IPAddr, error).
+var lookupGroup singleflight.Group
+
+// lookupIPReturn turns the return values from singleflight.Do into
+// the return values from LookupIP.
+func lookupIPReturn(addrsi interface{}, err error, shared bool) ([]IPAddr, error) {
+ if err != nil {
+ return nil, err
+ }
+ addrs := addrsi.([]IPAddr)
+ if shared {
+ clone := make([]IPAddr, len(addrs))
+ copy(clone, addrs)
+ addrs = clone
+ }
+ return addrs, nil
+}
+
+// ipAddrsEface returns an empty interface slice of addrs.
+func ipAddrsEface(addrs []IPAddr) []interface{} {
+ s := make([]interface{}, len(addrs))
+ for i, v := range addrs {
+ s[i] = v
+ }
+ return s
+}
+
// LookupPort looks up the port for the given network and service.
func LookupPort(network, service string) (port int, err error) {
+ return DefaultResolver.LookupPort(context.Background(), network, service)
+}
+
+// LookupPort looks up the port for the given network and service.
+func (r *Resolver) LookupPort(ctx context.Context, network, service string) (port int, err error) {
port, needsLookup := parsePort(service)
if needsLookup {
- port, err = lookupPort(context.Background(), network, service)
+ port, err = r.lookupPort(ctx, network, service)
if err != nil {
return 0, err
}
@@ -160,7 +238,15 @@ func LookupPort(network, service string) (port int, err error) {
// LookupHost or LookupIP directly; both take care of resolving
// the canonical name as part of the lookup.
func LookupCNAME(name string) (cname string, err error) {
- return lookupCNAME(context.Background(), name)
+ return DefaultResolver.lookupCNAME(context.Background(), name)
+}
+
+// LookupCNAME returns the canonical DNS host for the given name.
+// Callers that do not care about the canonical name can call
+// LookupHost or LookupIP directly; both take care of resolving
+// the canonical name as part of the lookup.
+func (r *Resolver) LookupCNAME(ctx context.Context, name string) (cname string, err error) {
+ return r.lookupCNAME(ctx, name)
}
// LookupSRV tries to resolve an SRV query of the given service,
@@ -173,26 +259,63 @@ func LookupCNAME(name string) (cname string, err error) {
// publishing SRV records under non-standard names, if both service
// and proto are empty strings, LookupSRV looks up name directly.
func LookupSRV(service, proto, name string) (cname string, addrs []*SRV, err error) {
- return lookupSRV(context.Background(), service, proto, name)
+ return DefaultResolver.lookupSRV(context.Background(), service, proto, name)
+}
+
+// LookupSRV tries to resolve an SRV query of the given service,
+// protocol, and domain name. The proto is "tcp" or "udp".
+// The returned records are sorted by priority and randomized
+// by weight within a priority.
+//
+// LookupSRV constructs the DNS name to look up following RFC 2782.
+// That is, it looks up _service._proto.name. To accommodate services
+// publishing SRV records under non-standard names, if both service
+// and proto are empty strings, LookupSRV looks up name directly.
+func (r *Resolver) LookupSRV(ctx context.Context, service, proto, name string) (cname string, addrs []*SRV, err error) {
+ return r.lookupSRV(ctx, service, proto, name)
+}
+
+// LookupMX returns the DNS MX records for the given domain name sorted by preference.
+func LookupMX(name string) ([]*MX, error) {
+ return DefaultResolver.lookupMX(context.Background(), name)
}
// LookupMX returns the DNS MX records for the given domain name sorted by preference.
-func LookupMX(name string) (mxs []*MX, err error) {
- return lookupMX(context.Background(), name)
+func (r *Resolver) LookupMX(ctx context.Context, name string) ([]*MX, error) {
+ return r.lookupMX(ctx, name)
}
// LookupNS returns the DNS NS records for the given domain name.
-func LookupNS(name string) (nss []*NS, err error) {
- return lookupNS(context.Background(), name)
+func LookupNS(name string) ([]*NS, error) {
+ return DefaultResolver.lookupNS(context.Background(), name)
+}
+
+// LookupNS returns the DNS NS records for the given domain name.
+func (r *Resolver) LookupNS(ctx context.Context, name string) ([]*NS, error) {
+ return r.lookupNS(ctx, name)
}
// LookupTXT returns the DNS TXT records for the given domain name.
-func LookupTXT(name string) (txts []string, err error) {
- return lookupTXT(context.Background(), name)
+func LookupTXT(name string) ([]string, error) {
+ return DefaultResolver.lookupTXT(context.Background(), name)
+}
+
+// LookupTXT returns the DNS TXT records for the given domain name.
+func (r *Resolver) LookupTXT(ctx context.Context, name string) ([]string, error) {
+ return r.lookupTXT(ctx, name)
}
// LookupAddr performs a reverse lookup for the given address, returning a list
// of names mapping to that address.
+//
+// When using the host C library resolver, at most one result will be
+// returned. To bypass the host resolver, use a custom Resolver.
func LookupAddr(addr string) (names []string, err error) {
- return lookupAddr(context.Background(), addr)
+ return DefaultResolver.lookupAddr(context.Background(), addr)
+}
+
+// LookupAddr performs a reverse lookup for the given address, returning a list
+// of names mapping to that address.
+func (r *Resolver) LookupAddr(ctx context.Context, addr string) (names []string, err error) {
+ return r.lookupAddr(ctx, addr)
}
diff --git a/src/net/lookup_nacl.go b/src/net/lookup_nacl.go
new file mode 100644
index 0000000..43cebad
--- /dev/null
+++ b/src/net/lookup_nacl.go
@@ -0,0 +1,52 @@
+// Copyright 2011 The Go Authors. 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 net
+
+import (
+ "context"
+ "syscall"
+)
+
+func lookupProtocol(ctx context.Context, name string) (proto int, err error) {
+ return lookupProtocolMap(name)
+}
+
+func (*Resolver) lookupHost(ctx context.Context, host string) (addrs []string, err error) {
+ return nil, syscall.ENOPROTOOPT
+}
+
+func (*Resolver) lookupIP(ctx context.Context, host string) (addrs []IPAddr, err error) {
+ return nil, syscall.ENOPROTOOPT
+}
+
+func (*Resolver) lookupPort(ctx context.Context, network, service string) (port int, err error) {
+ return goLookupPort(network, service)
+}
+
+func (*Resolver) lookupCNAME(ctx context.Context, name string) (cname string, err error) {
+ return "", syscall.ENOPROTOOPT
+}
+
+func (*Resolver) lookupSRV(ctx context.Context, service, proto, name string) (cname string, srvs []*SRV, err error) {
+ return "", nil, syscall.ENOPROTOOPT
+}
+
+func (*Resolver) lookupMX(ctx context.Context, name string) (mxs []*MX, err error) {
+ return nil, syscall.ENOPROTOOPT
+}
+
+func (*Resolver) lookupNS(ctx context.Context, name string) (nss []*NS, err error) {
+ return nil, syscall.ENOPROTOOPT
+}
+
+func (*Resolver) lookupTXT(ctx context.Context, name string) (txts []string, err error) {
+ return nil, syscall.ENOPROTOOPT
+}
+
+func (*Resolver) lookupAddr(ctx context.Context, addr string) (ptrs []string, err error) {
+ return nil, syscall.ENOPROTOOPT
+}
diff --git a/src/net/lookup_plan9.go b/src/net/lookup_plan9.go
index 3f7af2a..11f2349 100644
--- a/src/net/lookup_plan9.go
+++ b/src/net/lookup_plan9.go
@@ -111,17 +111,20 @@ func lookupProtocol(ctx context.Context, name string) (proto int, err error) {
return 0, UnknownNetworkError(name)
}
s := f[1]
- if n, _, ok := dtoi(s, byteIndex(s, '=')+1); ok {
+ if n, _, ok := dtoi(s[byteIndex(s, '=')+1:]); ok {
return n, nil
}
return 0, UnknownNetworkError(name)
}
-func lookupHost(ctx context.Context, host string) (addrs []string, err error) {
+func (*Resolver) lookupHost(ctx context.Context, host string) (addrs []string, err error) {
// Use netdir/cs instead of netdir/dns because cs knows about
// host names in local network (e.g. from /lib/ndb/local)
lines, err := queryCS(ctx, "net", host, "1")
if err != nil {
+ if stringsHasSuffix(err.Error(), "dns failure") {
+ err = errNoSuchHost
+ }
return
}
loop:
@@ -148,8 +151,8 @@ loop:
return
}
-func lookupIP(ctx context.Context, host string) (addrs []IPAddr, err error) {
- lits, err := lookupHost(ctx, host)
+func (r *Resolver) lookupIP(ctx context.Context, host string) (addrs []IPAddr, err error) {
+ lits, err := r.lookupHost(ctx, host)
if err != nil {
return
}
@@ -163,14 +166,14 @@ func lookupIP(ctx context.Context, host string) (addrs []IPAddr, err error) {
return
}
-func lookupPort(ctx context.Context, network, service string) (port int, err error) {
+func (*Resolver) lookupPort(ctx context.Context, network, service string) (port int, err error) {
switch network {
case "tcp4", "tcp6":
network = "tcp"
case "udp4", "udp6":
network = "udp"
}
- lines, err := queryCS(ctx, network, "127.0.0.1", service)
+ lines, err := queryCS(ctx, network, "127.0.0.1", toLower(service))
if err != nil {
return
}
@@ -186,13 +189,13 @@ func lookupPort(ctx context.Context, network, service string) (port int, err err
if i := byteIndex(s, '!'); i >= 0 {
s = s[i+1:] // remove address
}
- if n, _, ok := dtoi(s, 0); ok {
+ if n, _, ok := dtoi(s); ok {
return n, nil
}
return 0, unknownPortError
}
-func lookupCNAME(ctx context.Context, name string) (cname string, err error) {
+func (*Resolver) lookupCNAME(ctx context.Context, name string) (cname string, err error) {
lines, err := queryDNS(ctx, name, "cname")
if err != nil {
return
@@ -205,7 +208,7 @@ func lookupCNAME(ctx context.Context, name string) (cname string, err error) {
return "", errors.New("bad response from ndb/dns")
}
-func lookupSRV(ctx context.Context, service, proto, name string) (cname string, addrs []*SRV, err error) {
+func (*Resolver) lookupSRV(ctx context.Context, service, proto, name string) (cname string, addrs []*SRV, err error) {
var target string
if service == "" && proto == "" {
target = name
@@ -221,9 +224,9 @@ func lookupSRV(ctx context.Context, service, proto, name string) (cname string,
if len(f) < 6 {
continue
}
- port, _, portOk := dtoi(f[4], 0)
- priority, _, priorityOk := dtoi(f[3], 0)
- weight, _, weightOk := dtoi(f[2], 0)
+ port, _, portOk := dtoi(f[4])
+ priority, _, priorityOk := dtoi(f[3])
+ weight, _, weightOk := dtoi(f[2])
if !(portOk && priorityOk && weightOk) {
continue
}
@@ -234,7 +237,7 @@ func lookupSRV(ctx context.Context, service, proto, name string) (cname string,
return
}
-func lookupMX(ctx context.Context, name string) (mx []*MX, err error) {
+func (*Resolver) lookupMX(ctx context.Context, name string) (mx []*MX, err error) {
lines, err := queryDNS(ctx, name, "mx")
if err != nil {
return
@@ -244,7 +247,7 @@ func lookupMX(ctx context.Context, name string) (mx []*MX, err error) {
if len(f) < 4 {
continue
}
- if pref, _, ok := dtoi(f[2], 0); ok {
+ if pref, _, ok := dtoi(f[2]); ok {
mx = append(mx, &MX{absDomainName([]byte(f[3])), uint16(pref)})
}
}
@@ -252,7 +255,7 @@ func lookupMX(ctx context.Context, name string) (mx []*MX, err error) {
return
}
-func lookupNS(ctx context.Context, name string) (ns []*NS, err error) {
+func (*Resolver) lookupNS(ctx context.Context, name string) (ns []*NS, err error) {
lines, err := queryDNS(ctx, name, "ns")
if err != nil {
return
@@ -267,7 +270,7 @@ func lookupNS(ctx context.Context, name string) (ns []*NS, err error) {
return
}
-func lookupTXT(ctx context.Context, name string) (txt []string, err error) {
+func (*Resolver) lookupTXT(ctx context.Context, name string) (txt []string, err error) {
lines, err := queryDNS(ctx, name, "txt")
if err != nil {
return
@@ -280,7 +283,7 @@ func lookupTXT(ctx context.Context, name string) (txt []string, err error) {
return
}
-func lookupAddr(ctx context.Context, addr string) (name []string, err error) {
+func (*Resolver) lookupAddr(ctx context.Context, addr string) (name []string, err error) {
arpa, err := reverseaddr(addr)
if err != nil {
return
diff --git a/src/net/lookup_stub.go b/src/net/lookup_stub.go
deleted file mode 100644
index bd096b3..0000000
--- a/src/net/lookup_stub.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.
-
-// +build nacl
-
-package net
-
-import (
- "context"
- "syscall"
-)
-
-func lookupProtocol(ctx context.Context, name string) (proto int, err error) {
- return 0, syscall.ENOPROTOOPT
-}
-
-func lookupHost(ctx context.Context, host string) (addrs []string, err error) {
- return nil, syscall.ENOPROTOOPT
-}
-
-func lookupIP(ctx context.Context, host string) (addrs []IPAddr, err error) {
- return nil, syscall.ENOPROTOOPT
-}
-
-func lookupPort(ctx context.Context, network, service string) (port int, err error) {
- return 0, syscall.ENOPROTOOPT
-}
-
-func lookupCNAME(ctx context.Context, name string) (cname string, err error) {
- return "", syscall.ENOPROTOOPT
-}
-
-func lookupSRV(ctx context.Context, service, proto, name string) (cname string, srvs []*SRV, err error) {
- return "", nil, syscall.ENOPROTOOPT
-}
-
-func lookupMX(ctx context.Context, name string) (mxs []*MX, err error) {
- return nil, syscall.ENOPROTOOPT
-}
-
-func lookupNS(ctx context.Context, name string) (nss []*NS, err error) {
- return nil, syscall.ENOPROTOOPT
-}
-
-func lookupTXT(ctx context.Context, name string) (txts []string, err error) {
- return nil, syscall.ENOPROTOOPT
-}
-
-func lookupAddr(ctx context.Context, addr string) (ptrs []string, err error) {
- return nil, syscall.ENOPROTOOPT
-}
diff --git a/src/net/lookup_test.go b/src/net/lookup_test.go
index b3aeb85..656bebb 100644
--- a/src/net/lookup_test.go
+++ b/src/net/lookup_test.go
@@ -398,11 +398,11 @@ func TestDNSFlood(t *testing.T) {
for i := 0; i < N; i++ {
name := fmt.Sprintf("%d.net-test.golang.org", i)
go func() {
- _, err := lookupIPContext(ctxHalfTimeout, name)
+ _, err := DefaultResolver.LookupIPAddr(ctxHalfTimeout, name)
c <- err
}()
go func() {
- _, err := lookupIPContext(ctxTimeout, name)
+ _, err := DefaultResolver.LookupIPAddr(ctxTimeout, name)
c <- err
}()
}
@@ -616,7 +616,7 @@ func srvString(srvs []*SRV) string {
func TestLookupPort(t *testing.T) {
// See http://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xhtml
//
- // Please be careful about adding new mappings for testings.
+ // Please be careful about adding new test cases.
// There are platforms having incomplete mappings for
// restricted resource access and security reasons.
type test struct {
@@ -648,8 +648,6 @@ func TestLookupPort(t *testing.T) {
}
switch runtime.GOOS {
- case "nacl":
- t.Skipf("not supported on %s", runtime.GOOS)
case "android":
if netGo {
t.Skipf("not supported on %s without cgo; see golang.org/issues/14576", runtime.GOOS)
@@ -670,3 +668,73 @@ func TestLookupPort(t *testing.T) {
}
}
}
+
+// Like TestLookupPort but with minimal tests that should always pass
+// because the answers are baked-in to the net package.
+func TestLookupPort_Minimal(t *testing.T) {
+ type test struct {
+ network string
+ name string
+ port int
+ }
+ var tests = []test{
+ {"tcp", "http", 80},
+ {"tcp", "HTTP", 80}, // case shouldn't matter
+ {"tcp", "https", 443},
+ {"tcp", "ssh", 22},
+ {"tcp", "gopher", 70},
+ {"tcp4", "http", 80},
+ {"tcp6", "http", 80},
+ }
+
+ for _, tt := range tests {
+ port, err := LookupPort(tt.network, tt.name)
+ if port != tt.port || err != nil {
+ t.Errorf("LookupPort(%q, %q) = %d, %v; want %d, error=nil", tt.network, tt.name, port, err, tt.port)
+ }
+ }
+}
+
+func TestLookupProtocol_Minimal(t *testing.T) {
+ type test struct {
+ name string
+ want int
+ }
+ var tests = []test{
+ {"tcp", 6},
+ {"TcP", 6}, // case shouldn't matter
+ {"icmp", 1},
+ {"igmp", 2},
+ {"udp", 17},
+ {"ipv6-icmp", 58},
+ }
+
+ for _, tt := range tests {
+ got, err := lookupProtocol(context.Background(), tt.name)
+ if got != tt.want || err != nil {
+ t.Errorf("LookupProtocol(%q) = %d, %v; want %d, error=nil", tt.name, got, err, tt.want)
+ }
+ }
+
+}
+
+func TestLookupNonLDH(t *testing.T) {
+ if runtime.GOOS == "nacl" {
+ t.Skip("skip on nacl")
+ }
+ if fixup := forceGoDNS(); fixup != nil {
+ defer fixup()
+ }
+
+ // "LDH" stands for letters, digits, and hyphens and is the usual
+ // description of standard DNS names.
+ // This test is checking that other kinds of names are reported
+ // as not found, not reported as invalid names.
+ addrs, err := LookupHost("!!!.###.bogus..domain.")
+ if err == nil {
+ t.Fatalf("lookup succeeded: %v", addrs)
+ }
+ if !strings.HasSuffix(err.Error(), errNoSuchHost.Error()) {
+ t.Fatalf("lookup error = %v, want %v", err, errNoSuchHost)
+ }
+}
diff --git a/src/net/lookup_unix.go b/src/net/lookup_unix.go
index 15397e8..35f253c 100644
--- a/src/net/lookup_unix.go
+++ b/src/net/lookup_unix.go
@@ -26,7 +26,7 @@ func readProtocols() {
if len(f) < 2 {
continue
}
- if proto, _, ok := dtoi(f[1], 0); ok {
+ if proto, _, ok := dtoi(f[1]); ok {
if _, ok := protocols[f[0]]; !ok {
protocols[f[0]] = proto
}
@@ -45,16 +45,12 @@ func readProtocols() {
// returns correspondent protocol number.
func lookupProtocol(_ context.Context, name string) (int, error) {
onceReadProtocols.Do(readProtocols)
- proto, found := protocols[name]
- if !found {
- return 0, &AddrError{Err: "unknown IP protocol specified", Addr: name}
- }
- return proto, nil
+ return lookupProtocolMap(name)
}
-func lookupHost(ctx context.Context, host string) (addrs []string, err error) {
+func (r *Resolver) lookupHost(ctx context.Context, host string) (addrs []string, err error) {
order := systemConf().hostLookupOrder(host)
- if order == hostLookupCgo {
+ if !r.PreferGo && order == hostLookupCgo {
if addrs, err, ok := cgoLookupHost(ctx, host); ok {
return addrs, err
}
@@ -64,7 +60,10 @@ func lookupHost(ctx context.Context, host string) (addrs []string, err error) {
return goLookupHostOrder(ctx, host, order)
}
-func lookupIP(ctx context.Context, host string) (addrs []IPAddr, err error) {
+func (r *Resolver) lookupIP(ctx context.Context, host string) (addrs []IPAddr, err error) {
+ if r.PreferGo {
+ return goLookupIP(ctx, host)
+ }
order := systemConf().hostLookupOrder(host)
if order == hostLookupCgo {
if addrs, err, ok := cgoLookupIP(ctx, host); ok {
@@ -76,13 +75,13 @@ func lookupIP(ctx context.Context, host string) (addrs []IPAddr, err error) {
return goLookupIPOrder(ctx, host, order)
}
-func lookupPort(ctx context.Context, network, service string) (int, error) {
+func (r *Resolver) lookupPort(ctx context.Context, network, service string) (int, error) {
// TODO: use the context if there ever becomes a need. Related
// is issue 15321. But port lookup generally just involves
// local files, and the os package has no context support. The
// files might be on a remote filesystem, though. This should
// probably race goroutines if ctx != context.Background().
- if systemConf().canUseCgo() {
+ if !r.PreferGo && systemConf().canUseCgo() {
if port, err, ok := cgoLookupPort(ctx, network, service); ok {
return port, err
}
@@ -90,8 +89,8 @@ func lookupPort(ctx context.Context, network, service string) (int, error) {
return goLookupPort(network, service)
}
-func lookupCNAME(ctx context.Context, name string) (string, error) {
- if systemConf().canUseCgo() {
+func (r *Resolver) lookupCNAME(ctx context.Context, name string) (string, error) {
+ if !r.PreferGo && systemConf().canUseCgo() {
if cname, err, ok := cgoLookupCNAME(ctx, name); ok {
return cname, err
}
@@ -99,7 +98,7 @@ func lookupCNAME(ctx context.Context, name string) (string, error) {
return goLookupCNAME(ctx, name)
}
-func lookupSRV(ctx context.Context, service, proto, name string) (string, []*SRV, error) {
+func (*Resolver) lookupSRV(ctx context.Context, service, proto, name string) (string, []*SRV, error) {
var target string
if service == "" && proto == "" {
target = name
@@ -119,7 +118,7 @@ func lookupSRV(ctx context.Context, service, proto, name string) (string, []*SRV
return cname, srvs, nil
}
-func lookupMX(ctx context.Context, name string) ([]*MX, error) {
+func (*Resolver) lookupMX(ctx context.Context, name string) ([]*MX, error) {
_, rrs, err := lookup(ctx, name, dnsTypeMX)
if err != nil {
return nil, err
@@ -133,7 +132,7 @@ func lookupMX(ctx context.Context, name string) ([]*MX, error) {
return mxs, nil
}
-func lookupNS(ctx context.Context, name string) ([]*NS, error) {
+func (*Resolver) lookupNS(ctx context.Context, name string) ([]*NS, error) {
_, rrs, err := lookup(ctx, name, dnsTypeNS)
if err != nil {
return nil, err
@@ -145,7 +144,7 @@ func lookupNS(ctx context.Context, name string) ([]*NS, error) {
return nss, nil
}
-func lookupTXT(ctx context.Context, name string) ([]string, error) {
+func (r *Resolver) lookupTXT(ctx context.Context, name string) ([]string, error) {
_, rrs, err := lookup(ctx, name, dnsTypeTXT)
if err != nil {
return nil, err
@@ -157,8 +156,8 @@ func lookupTXT(ctx context.Context, name string) ([]string, error) {
return txts, nil
}
-func lookupAddr(ctx context.Context, addr string) ([]string, error) {
- if systemConf().canUseCgo() {
+func (r *Resolver) lookupAddr(ctx context.Context, addr string) ([]string, error) {
+ if !r.PreferGo && systemConf().canUseCgo() {
if ptrs, err, ok := cgoLookupPTR(ctx, addr); ok {
return ptrs, err
}
diff --git a/src/net/lookup_windows.go b/src/net/lookup_windows.go
index 5f65c2d..5808293 100644
--- a/src/net/lookup_windows.go
+++ b/src/net/lookup_windows.go
@@ -12,10 +12,20 @@ import (
"unsafe"
)
+const _WSAHOST_NOT_FOUND = syscall.Errno(11001)
+
+func winError(call string, err error) error {
+ switch err {
+ case _WSAHOST_NOT_FOUND:
+ return errNoSuchHost
+ }
+ return os.NewSyscallError(call, err)
+}
+
func getprotobyname(name string) (proto int, err error) {
p, err := syscall.GetProtoByName(name)
if err != nil {
- return 0, os.NewSyscallError("getprotobyname", err)
+ return 0, winError("getprotobyname", err)
}
return int(p.Proto), nil
}
@@ -43,7 +53,7 @@ func lookupProtocol(ctx context.Context, name string) (int, error) {
select {
case r := <-ch:
if r.err != nil {
- if proto, ok := protocols[name]; ok {
+ if proto, err := lookupProtocolMap(name); err == nil {
return proto, nil
}
r.err = &DNSError{Err: r.err.Error(), Name: name}
@@ -54,8 +64,8 @@ func lookupProtocol(ctx context.Context, name string) (int, error) {
}
}
-func lookupHost(ctx context.Context, name string) ([]string, error) {
- ips, err := lookupIP(ctx, name)
+func (r *Resolver) lookupHost(ctx context.Context, name string) ([]string, error) {
+ ips, err := r.lookupIP(ctx, name)
if err != nil {
return nil, err
}
@@ -66,8 +76,8 @@ func lookupHost(ctx context.Context, name string) ([]string, error) {
return addrs, nil
}
-func lookupIP(ctx context.Context, name string) ([]IPAddr, error) {
- // TODO(bradfitz,brainman): use ctx?
+func (r *Resolver) lookupIP(ctx context.Context, name string) ([]IPAddr, error) {
+ // TODO(bradfitz,brainman): use ctx more. See TODO below.
type ret struct {
addrs []IPAddr
@@ -85,7 +95,7 @@ func lookupIP(ctx context.Context, name string) ([]IPAddr, error) {
var result *syscall.AddrinfoW
e := syscall.GetAddrInfoW(syscall.StringToUTF16Ptr(name), nil, &hints, &result)
if e != nil {
- ch <- ret{err: &DNSError{Err: os.NewSyscallError("getaddrinfow", e).Error(), Name: name}}
+ ch <- ret{err: &DNSError{Err: winError("getaddrinfow", e).Error(), Name: name}}
}
defer syscall.FreeAddrInfoW(result)
addrs := make([]IPAddr, 0, 5)
@@ -125,7 +135,11 @@ func lookupIP(ctx context.Context, name string) ([]IPAddr, error) {
}
}
-func lookupPort(ctx context.Context, network, service string) (int, error) {
+func (r *Resolver) lookupPort(ctx context.Context, network, service string) (int, error) {
+ if r.PreferGo {
+ return lookupPortMap(network, service)
+ }
+
// TODO(bradfitz): finish ctx plumbing. Nothing currently depends on this.
acquireThread()
defer releaseThread()
@@ -144,7 +158,10 @@ func lookupPort(ctx context.Context, network, service string) (int, error) {
var result *syscall.AddrinfoW
e := syscall.GetAddrInfoW(nil, syscall.StringToUTF16Ptr(service), &hints, &result)
if e != nil {
- return 0, &DNSError{Err: os.NewSyscallError("getaddrinfow", e).Error(), Name: network + "/" + service}
+ if port, err := lookupPortMap(network, service); err == nil {
+ return port, nil
+ }
+ return 0, &DNSError{Err: winError("getaddrinfow", e).Error(), Name: network + "/" + service}
}
defer syscall.FreeAddrInfoW(result)
if result == nil {
@@ -162,7 +179,7 @@ func lookupPort(ctx context.Context, network, service string) (int, error) {
return 0, &DNSError{Err: syscall.EINVAL.Error(), Name: network + "/" + service}
}
-func lookupCNAME(ctx context.Context, name string) (string, error) {
+func (*Resolver) lookupCNAME(ctx context.Context, name string) (string, error) {
// TODO(bradfitz): finish ctx plumbing. Nothing currently depends on this.
acquireThread()
defer releaseThread()
@@ -174,7 +191,7 @@ func lookupCNAME(ctx context.Context, name string) (string, error) {
return absDomainName([]byte(name)), nil
}
if e != nil {
- return "", &DNSError{Err: os.NewSyscallError("dnsquery", e).Error(), Name: name}
+ return "", &DNSError{Err: winError("dnsquery", e).Error(), Name: name}
}
defer syscall.DnsRecordListFree(r, 1)
@@ -183,7 +200,7 @@ func lookupCNAME(ctx context.Context, name string) (string, error) {
return absDomainName([]byte(cname)), nil
}
-func lookupSRV(ctx context.Context, service, proto, name string) (string, []*SRV, error) {
+func (*Resolver) lookupSRV(ctx context.Context, service, proto, name string) (string, []*SRV, error) {
// TODO(bradfitz): finish ctx plumbing. Nothing currently depends on this.
acquireThread()
defer releaseThread()
@@ -196,7 +213,7 @@ func lookupSRV(ctx context.Context, service, proto, name string) (string, []*SRV
var r *syscall.DNSRecord
e := syscall.DnsQuery(target, syscall.DNS_TYPE_SRV, 0, nil, &r, nil)
if e != nil {
- return "", nil, &DNSError{Err: os.NewSyscallError("dnsquery", e).Error(), Name: target}
+ return "", nil, &DNSError{Err: winError("dnsquery", e).Error(), Name: target}
}
defer syscall.DnsRecordListFree(r, 1)
@@ -209,14 +226,14 @@ func lookupSRV(ctx context.Context, service, proto, name string) (string, []*SRV
return absDomainName([]byte(target)), srvs, nil
}
-func lookupMX(ctx context.Context, name string) ([]*MX, error) {
+func (*Resolver) lookupMX(ctx context.Context, name string) ([]*MX, error) {
// TODO(bradfitz): finish ctx plumbing. Nothing currently depends on this.
acquireThread()
defer releaseThread()
var r *syscall.DNSRecord
e := syscall.DnsQuery(name, syscall.DNS_TYPE_MX, 0, nil, &r, nil)
if e != nil {
- return nil, &DNSError{Err: os.NewSyscallError("dnsquery", e).Error(), Name: name}
+ return nil, &DNSError{Err: winError("dnsquery", e).Error(), Name: name}
}
defer syscall.DnsRecordListFree(r, 1)
@@ -229,14 +246,14 @@ func lookupMX(ctx context.Context, name string) ([]*MX, error) {
return mxs, nil
}
-func lookupNS(ctx context.Context, name string) ([]*NS, error) {
+func (*Resolver) lookupNS(ctx context.Context, name string) ([]*NS, error) {
// TODO(bradfitz): finish ctx plumbing. Nothing currently depends on this.
acquireThread()
defer releaseThread()
var r *syscall.DNSRecord
e := syscall.DnsQuery(name, syscall.DNS_TYPE_NS, 0, nil, &r, nil)
if e != nil {
- return nil, &DNSError{Err: os.NewSyscallError("dnsquery", e).Error(), Name: name}
+ return nil, &DNSError{Err: winError("dnsquery", e).Error(), Name: name}
}
defer syscall.DnsRecordListFree(r, 1)
@@ -248,14 +265,14 @@ func lookupNS(ctx context.Context, name string) ([]*NS, error) {
return nss, nil
}
-func lookupTXT(ctx context.Context, name string) ([]string, error) {
+func (*Resolver) lookupTXT(ctx context.Context, name string) ([]string, error) {
// TODO(bradfitz): finish ctx plumbing. Nothing currently depends on this.
acquireThread()
defer releaseThread()
var r *syscall.DNSRecord
e := syscall.DnsQuery(name, syscall.DNS_TYPE_TEXT, 0, nil, &r, nil)
if e != nil {
- return nil, &DNSError{Err: os.NewSyscallError("dnsquery", e).Error(), Name: name}
+ return nil, &DNSError{Err: winError("dnsquery", e).Error(), Name: name}
}
defer syscall.DnsRecordListFree(r, 1)
@@ -270,7 +287,7 @@ func lookupTXT(ctx context.Context, name string) ([]string, error) {
return txts, nil
}
-func lookupAddr(ctx context.Context, addr string) ([]string, error) {
+func (*Resolver) lookupAddr(ctx context.Context, addr string) ([]string, error) {
// TODO(bradfitz): finish ctx plumbing. Nothing currently depends on this.
acquireThread()
defer releaseThread()
@@ -281,7 +298,7 @@ func lookupAddr(ctx context.Context, addr string) ([]string, error) {
var r *syscall.DNSRecord
e := syscall.DnsQuery(arpa, syscall.DNS_TYPE_PTR, 0, nil, &r, nil)
if e != nil {
- return nil, &DNSError{Err: os.NewSyscallError("dnsquery", e).Error(), Name: addr}
+ return nil, &DNSError{Err: winError("dnsquery", e).Error(), Name: addr}
}
defer syscall.DnsRecordListFree(r, 1)
diff --git a/src/net/lookup_windows_test.go b/src/net/lookup_windows_test.go
index 9af2c61..bc9ffe1 100644
--- a/src/net/lookup_windows_test.go
+++ b/src/net/lookup_windows_test.go
@@ -169,14 +169,14 @@ func nslookupMX(name string) (mx []*MX, err error) {
// golang.org mail exchanger = 2 alt1.aspmx.l.google.com.
rx := regexp.MustCompile(`(?m)^([a-z0-9.\-]+)\s+mail exchanger\s*=\s*([0-9]+)\s*([a-z0-9.\-]+)$`)
for _, ans := range rx.FindAllStringSubmatch(r, -1) {
- pref, _, _ := dtoi(ans[2], 0)
+ pref, _, _ := dtoi(ans[2])
mx = append(mx, &MX{absDomainName([]byte(ans[3])), uint16(pref)})
}
// windows nslookup syntax
// gmail.com MX preference = 30, mail exchanger = alt3.gmail-smtp-in.l.google.com
rx = regexp.MustCompile(`(?m)^([a-z0-9.\-]+)\s+MX preference\s*=\s*([0-9]+)\s*,\s*mail exchanger\s*=\s*([a-z0-9.\-]+)$`)
for _, ans := range rx.FindAllStringSubmatch(r, -1) {
- pref, _, _ := dtoi(ans[2], 0)
+ pref, _, _ := dtoi(ans[2])
mx = append(mx, &MX{absDomainName([]byte(ans[3])), uint16(pref)})
}
return
diff --git a/src/net/mail/message.go b/src/net/mail/message.go
index 0c00069..702b765 100644
--- a/src/net/mail/message.go
+++ b/src/net/mail/message.go
@@ -92,7 +92,8 @@ func init() {
}
}
-func parseDate(date string) (time.Time, error) {
+// ParseDate parses an RFC 5322 date string.
+func ParseDate(date string) (time.Time, error) {
for _, layout := range dateLayouts {
t, err := time.Parse(layout, date)
if err == nil {
@@ -106,7 +107,11 @@ func parseDate(date string) (time.Time, error) {
type Header map[string][]string
// Get gets the first value associated with the given key.
+// It is case insensitive; CanonicalMIMEHeaderKey is used
+// to canonicalize the provided key.
// If there are no values associated with the key, Get returns "".
+// To access multiple values of a key, or to use non-canonical keys,
+// access the map directly.
func (h Header) Get(key string) string {
return textproto.MIMEHeader(h).Get(key)
}
@@ -119,7 +124,7 @@ func (h Header) Date() (time.Time, error) {
if hdr == "" {
return time.Time{}, ErrHeaderNotPresent
}
- return parseDate(hdr)
+ return ParseDate(hdr)
}
// AddressList parses the named header field as a list of addresses.
@@ -345,6 +350,9 @@ func (p *addrParser) consumeAddrSpec() (spec string, err error) {
// quoted-string
debug.Printf("consumeAddrSpec: parsing quoted-string")
localPart, err = p.consumeQuotedString()
+ if localPart == "" {
+ err = errors.New("mail: empty quoted string in addr-spec")
+ }
} else {
// dot-atom
debug.Printf("consumeAddrSpec: parsing dot-atom")
@@ -462,9 +470,6 @@ Loop:
i += size
}
p.s = p.s[i+1:]
- if len(qsb) == 0 {
- return "", errors.New("mail: empty quoted-string")
- }
return string(qsb), nil
}
diff --git a/src/net/mail/message_test.go b/src/net/mail/message_test.go
index bbbba6b..f0761ab 100644
--- a/src/net/mail/message_test.go
+++ b/src/net/mail/message_test.go
@@ -110,11 +110,16 @@ func TestDateParsing(t *testing.T) {
}
date, err := hdr.Date()
if err != nil {
- t.Errorf("Failed parsing %q: %v", test.dateStr, err)
- continue
+ t.Errorf("Header(Date: %s).Date(): %v", test.dateStr, err)
+ } else if !date.Equal(test.exp) {
+ t.Errorf("Header(Date: %s).Date() = %+v, want %+v", test.dateStr, date, test.exp)
}
- if !date.Equal(test.exp) {
- t.Errorf("Parse of %q: got %+v, want %+v", test.dateStr, date, test.exp)
+
+ date, err = ParseDate(test.dateStr)
+ if err != nil {
+ t.Errorf("ParseDate(%s): %v", test.dateStr, err)
+ } else if !date.Equal(test.exp) {
+ t.Errorf("ParseDate(%s) = %+v, want %+v", test.dateStr, date, test.exp)
}
}
}
@@ -310,6 +315,16 @@ func TestAddressParsing(t *testing.T) {
},
},
},
+ // Issue 14866
+ {
+ `"" <emptystring at example.com>`,
+ []*Address{
+ {
+ Name: "",
+ Address: "emptystring at example.com",
+ },
+ },
+ },
}
for _, test := range tests {
if len(test.exp) == 1 {
diff --git a/src/net/main_test.go b/src/net/main_test.go
index 7573ded..28a8ff6 100644
--- a/src/net/main_test.go
+++ b/src/net/main_test.go
@@ -24,6 +24,8 @@ var (
)
var (
+ testTCPBig = flag.Bool("tcpbig", false, "whether to test massive size of data per read or write call on TCP connection")
+
testDNSFlood = flag.Bool("dnsflood", false, "whether to test DNS query flooding")
// If external IPv4 connectivity exists, we can try dialing
diff --git a/src/net/net.go b/src/net/net.go
index d6812d1..81206ea 100644
--- a/src/net/net.go
+++ b/src/net/net.go
@@ -102,9 +102,13 @@ func init() {
}
// Addr represents a network end point address.
+//
+// The two methods Network and String conventionally return strings
+// that can be passed as the arguments to Dial, but the exact form
+// and meaning of the strings is up to the implementation.
type Addr interface {
- Network() string // name of the network
- String() string // string form of address
+ Network() string // name of the network (for example, "tcp", "udp")
+ String() string // string form of address (for example, "192.0.2.1:25", "[2001:db8::1]:80")
}
// Conn is a generic stream-oriented network connection.
@@ -112,12 +116,12 @@ type Addr interface {
// Multiple goroutines may invoke methods on a Conn simultaneously.
type Conn interface {
// Read reads data from the connection.
- // Read can be made to time out and return a Error with Timeout() == true
+ // Read can be made to time out and return an Error with Timeout() == true
// after a fixed time limit; see SetDeadline and SetReadDeadline.
Read(b []byte) (n int, err error)
// Write writes data to the connection.
- // Write can be made to time out and return a Error with Timeout() == true
+ // Write can be made to time out and return an Error with Timeout() == true
// after a fixed time limit; see SetDeadline and SetWriteDeadline.
Write(b []byte) (n int, err error)
@@ -137,8 +141,10 @@ type Conn interface {
//
// A deadline is an absolute time after which I/O operations
// fail with a timeout (see type Error) instead of
- // blocking. The deadline applies to all future I/O, not just
- // the immediately following call to Read or Write.
+ // blocking. The deadline applies to all future and pending
+ // I/O, not just the immediately following call to Read or
+ // Write. After a deadline has been exceeded, the connection
+ // can be refreshed by setting a deadline in the future.
//
// An idle timeout can be implemented by repeatedly extending
// the deadline after successful Read or Write calls.
@@ -146,11 +152,13 @@ type Conn interface {
// A zero value for t means I/O operations will not time out.
SetDeadline(t time.Time) error
- // SetReadDeadline sets the deadline for future Read calls.
+ // SetReadDeadline sets the deadline for future Read calls
+ // and any currently-blocked Read call.
// A zero value for t means Read will not time out.
SetReadDeadline(t time.Time) error
- // SetWriteDeadline sets the deadline for future Write calls.
+ // SetWriteDeadline sets the deadline for future Write calls
+ // and any currently-blocked Write call.
// Even if write times out, it may return n > 0, indicating that
// some of the data was successfully written.
// A zero value for t means Write will not time out.
@@ -302,13 +310,13 @@ type PacketConn interface {
// bytes copied into b and the return address that
// was on the packet.
// ReadFrom can be made to time out and return
- // an error with Timeout() == true after a fixed time limit;
+ // an Error with Timeout() == true after a fixed time limit;
// see SetDeadline and SetReadDeadline.
ReadFrom(b []byte) (n int, addr Addr, err error)
// WriteTo writes a packet with payload b to addr.
// WriteTo can be made to time out and return
- // an error with Timeout() == true after a fixed time limit;
+ // an Error with Timeout() == true after a fixed time limit;
// see SetDeadline and SetWriteDeadline.
// On packet-oriented connections, write timeouts are rare.
WriteTo(b []byte, addr Addr) (n int, err error)
@@ -321,21 +329,32 @@ type PacketConn interface {
LocalAddr() Addr
// SetDeadline sets the read and write deadlines associated
- // with the connection.
+ // with the connection. It is equivalent to calling both
+ // SetReadDeadline and SetWriteDeadline.
+ //
+ // A deadline is an absolute time after which I/O operations
+ // fail with a timeout (see type Error) instead of
+ // blocking. The deadline applies to all future and pending
+ // I/O, not just the immediately following call to ReadFrom or
+ // WriteTo. After a deadline has been exceeded, the connection
+ // can be refreshed by setting a deadline in the future.
+ //
+ // An idle timeout can be implemented by repeatedly extending
+ // the deadline after successful ReadFrom or WriteTo calls.
+ //
+ // A zero value for t means I/O operations will not time out.
SetDeadline(t time.Time) error
- // SetReadDeadline sets the deadline for future Read calls.
- // If the deadline is reached, Read will fail with a timeout
- // (see type Error) instead of blocking.
- // A zero value for t means Read will not time out.
+ // SetReadDeadline sets the deadline for future ReadFrom calls
+ // and any currently-blocked ReadFrom call.
+ // A zero value for t means ReadFrom will not time out.
SetReadDeadline(t time.Time) error
- // SetWriteDeadline sets the deadline for future Write calls.
- // If the deadline is reached, Write will fail with a timeout
- // (see type Error) instead of blocking.
- // A zero value for t means Write will not time out.
+ // SetWriteDeadline sets the deadline for future WriteTo calls
+ // and any currently-blocked WriteTo call.
// Even if write times out, it may return n > 0, indicating that
// some of the data was successfully written.
+ // A zero value for t means WriteTo will not time out.
SetWriteDeadline(t time.Time) error
}
@@ -512,7 +531,7 @@ func (e *AddrError) Error() string {
}
s := e.Err
if e.Addr != "" {
- s += " " + e.Addr
+ s = "address " + e.Addr + ": " + s
}
return s
}
@@ -604,3 +623,66 @@ func acquireThread() {
func releaseThread() {
<-threadLimit
}
+
+// buffersWriter is the interface implemented by Conns that support a
+// "writev"-like batch write optimization.
+// writeBuffers should fully consume and write all chunks from the
+// provided Buffers, else it should report a non-nil error.
+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
+// optimized into an OS-specific batch write operation (such as
+// "writev").
+type Buffers [][]byte
+
+var (
+ _ io.WriterTo = (*Buffers)(nil)
+ _ io.Reader = (*Buffers)(nil)
+)
+
+func (v *Buffers) WriteTo(w io.Writer) (n int64, err error) {
+ if wv, ok := w.(buffersWriter); ok {
+ return wv.writeBuffers(v)
+ }
+ for _, b := range *v {
+ nb, err := w.Write(b)
+ n += int64(nb)
+ if err != nil {
+ v.consume(n)
+ return n, err
+ }
+ }
+ v.consume(n)
+ return n, nil
+}
+
+func (v *Buffers) Read(p []byte) (n int, err error) {
+ for len(p) > 0 && len(*v) > 0 {
+ n0 := copy(p, (*v)[0])
+ v.consume(int64(n0))
+ p = p[n0:]
+ n += n0
+ }
+ if len(*v) == 0 {
+ err = io.EOF
+ }
+ return
+}
+
+func (v *Buffers) consume(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:]
+ }
+}
diff --git a/src/net/net_test.go b/src/net/net_test.go
index b2f825d..9a9a7e5 100644
--- a/src/net/net_test.go
+++ b/src/net/net_test.go
@@ -5,6 +5,8 @@
package net
import (
+ "errors"
+ "fmt"
"io"
"net/internal/socktest"
"os"
@@ -15,7 +17,7 @@ import (
func TestCloseRead(t *testing.T) {
switch runtime.GOOS {
- case "nacl", "plan9":
+ case "plan9":
t.Skipf("not supported on %s", runtime.GOOS)
}
@@ -414,3 +416,103 @@ func TestZeroByteRead(t *testing.T) {
}
}
}
+
+// withTCPConnPair sets up a TCP connection between two peers, then
+// runs peer1 and peer2 concurrently. withTCPConnPair returns when
+// both have completed.
+func withTCPConnPair(t *testing.T, peer1, peer2 func(c *TCPConn) error) {
+ ln, err := newLocalListener("tcp")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer ln.Close()
+ errc := make(chan error, 2)
+ go func() {
+ c1, err := ln.Accept()
+ if err != nil {
+ errc <- err
+ return
+ }
+ defer c1.Close()
+ errc <- peer1(c1.(*TCPConn))
+ }()
+ go func() {
+ c2, err := Dial("tcp", ln.Addr().String())
+ if err != nil {
+ errc <- err
+ return
+ }
+ defer c2.Close()
+ errc <- peer2(c2.(*TCPConn))
+ }()
+ for i := 0; i < 2; i++ {
+ if err := <-errc; err != nil {
+ t.Fatal(err)
+ }
+ }
+}
+
+// Tests that a blocked Read is interrupted by a concurrent SetReadDeadline
+// modifying that Conn's read deadline to the past.
+// See golang.org/cl/30164 which documented this. The net/http package
+// depends on this.
+func TestReadTimeoutUnblocksRead(t *testing.T) {
+ serverDone := make(chan struct{})
+ server := func(cs *TCPConn) error {
+ defer close(serverDone)
+ errc := make(chan error, 1)
+ go func() {
+ defer close(errc)
+ go func() {
+ // TODO: find a better way to wait
+ // until we're blocked in the cs.Read
+ // call below. Sleep is lame.
+ time.Sleep(100 * time.Millisecond)
+
+ // Interrupt the upcoming Read, unblocking it:
+ cs.SetReadDeadline(time.Unix(123, 0)) // time in the past
+ }()
+ var buf [1]byte
+ n, err := cs.Read(buf[:1])
+ if n != 0 || err == nil {
+ errc <- fmt.Errorf("Read = %v, %v; want 0, non-nil", n, err)
+ }
+ }()
+ select {
+ case err := <-errc:
+ return err
+ case <-time.After(5 * time.Second):
+ buf := make([]byte, 2<<20)
+ buf = buf[:runtime.Stack(buf, true)]
+ println("Stacks at timeout:\n", string(buf))
+ return errors.New("timeout waiting for Read to finish")
+ }
+
+ }
+ // Do nothing in the client. Never write. Just wait for the
+ // server's half to be done.
+ client := func(*TCPConn) error {
+ <-serverDone
+ return nil
+ }
+ withTCPConnPair(t, client, server)
+}
+
+// Issue 17695: verify that a blocked Read is woken up by a Close.
+func TestCloseUnblocksRead(t *testing.T) {
+ t.Parallel()
+ server := func(cs *TCPConn) error {
+ // Give the client time to get stuck in a Read:
+ time.Sleep(20 * time.Millisecond)
+ cs.Close()
+ return nil
+ }
+ client := func(ss *TCPConn) error {
+ n, err := ss.Read([]byte{0})
+ if n != 0 || err != io.EOF {
+ return fmt.Errorf("Read = %v, %v; want 0, EOF", n, err)
+ }
+ return nil
+ }
+ withTCPConnPair(t, client, server)
+}
diff --git a/src/net/parse.go b/src/net/parse.go
index ed82a77..5826984 100644
--- a/src/net/parse.go
+++ b/src/net/parse.go
@@ -123,39 +123,27 @@ func getFields(s string) []string { return splitAtBytes(s, " \r\t\n") }
// Bigger than we need, not too big to worry about overflow
const big = 0xFFFFFF
-// Decimal to integer starting at &s[i0].
-// Returns number, new offset, success.
-func dtoi(s string, i0 int) (n int, i int, ok bool) {
+// Decimal to integer.
+// Returns number, characters consumed, success.
+func dtoi(s string) (n int, i int, ok bool) {
n = 0
- neg := false
- if len(s) > 0 && s[0] == '-' {
- neg = true
- s = s[1:]
- }
- for i = i0; i < len(s) && '0' <= s[i] && s[i] <= '9'; i++ {
+ for i = 0; i < len(s) && '0' <= s[i] && s[i] <= '9'; i++ {
n = n*10 + int(s[i]-'0')
if n >= big {
- if neg {
- return -big, i + 1, false
- }
return big, i, false
}
}
- if i == i0 {
- return 0, i, false
- }
- if neg {
- n = -n
- i++
+ if i == 0 {
+ return 0, 0, false
}
return n, i, true
}
-// Hexadecimal to integer starting at &s[i0].
-// Returns number, new offset, success.
-func xtoi(s string, i0 int) (n int, i int, ok bool) {
+// Hexadecimal to integer.
+// Returns number, characters consumed, success.
+func xtoi(s string) (n int, i int, ok bool) {
n = 0
- for i = i0; i < len(s); i++ {
+ for i = 0; i < len(s); i++ {
if '0' <= s[i] && s[i] <= '9' {
n *= 16
n += int(s[i] - '0')
@@ -172,7 +160,7 @@ func xtoi(s string, i0 int) (n int, i int, ok bool) {
return 0, i, false
}
}
- if i == i0 {
+ if i == 0 {
return 0, i, false
}
return n, i, true
@@ -186,7 +174,7 @@ func xtoi2(s string, e byte) (byte, bool) {
if len(s) > 2 && s[2] != e {
return 0, false
}
- n, ei, ok := xtoi(s[:2], 0)
+ n, ei, ok := xtoi(s[:2])
return byte(n), ok && ei == 2
}
@@ -346,22 +334,28 @@ func stringsHasSuffix(s, suffix string) bool {
// stringsHasSuffixFold reports whether s ends in suffix,
// ASCII-case-insensitively.
func stringsHasSuffixFold(s, suffix string) bool {
- if len(suffix) > len(s) {
+ return len(s) >= len(suffix) && stringsEqualFold(s[len(s)-len(suffix):], suffix)
+}
+
+// stringsHasPrefix is strings.HasPrefix. It reports whether s begins with prefix.
+func stringsHasPrefix(s, prefix string) bool {
+ return len(s) >= len(prefix) && s[:len(prefix)] == prefix
+}
+
+// stringsEqualFold is strings.EqualFold, ASCII only. It reports whether s and t
+// are equal, ASCII-case-insensitively.
+func stringsEqualFold(s, t string) bool {
+ if len(s) != len(t) {
return false
}
- for i := 0; i < len(suffix); i++ {
- if lowerASCII(suffix[i]) != lowerASCII(s[len(s)-len(suffix)+i]) {
+ for i := 0; i < len(s); i++ {
+ if lowerASCII(s[i]) != lowerASCII(t[i]) {
return false
}
}
return true
}
-// stringsHasPrefix is strings.HasPrefix. It reports whether s begins with prefix.
-func stringsHasPrefix(s, prefix string) bool {
- return len(s) >= len(prefix) && s[:len(prefix)] == prefix
-}
-
func readFull(r io.Reader) (all []byte, err error) {
buf := make([]byte, 1024)
for {
diff --git a/src/net/parse_test.go b/src/net/parse_test.go
index fec9200..c5f8bfd 100644
--- a/src/net/parse_test.go
+++ b/src/net/parse_test.go
@@ -86,14 +86,13 @@ func TestDtoi(t *testing.T) {
ok bool
}{
{"", 0, 0, false},
-
- {"-123456789", -big, 9, false},
- {"-1", -1, 2, true},
{"0", 0, 1, true},
{"65536", 65536, 5, true},
{"123456789", big, 8, false},
+ {"-0", 0, 0, false},
+ {"-1234", 0, 0, false},
} {
- n, i, ok := dtoi(tt.in, 0)
+ n, i, ok := dtoi(tt.in)
if n != tt.out || i != tt.off || ok != tt.ok {
t.Errorf("got %d, %d, %v; want %d, %d, %v", n, i, ok, tt.out, tt.off, tt.ok)
}
diff --git a/src/net/port_unix.go b/src/net/port_unix.go
index badf8ab..4e04781 100644
--- a/src/net/port_unix.go
+++ b/src/net/port_unix.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux netbsd openbsd solaris
+// +build darwin dragonfly freebsd linux netbsd openbsd solaris nacl
// Read system port mappings from /etc/services
@@ -10,12 +10,6 @@ package net
import "sync"
-// services contains minimal mappings between services names and port
-// numbers for platforms that don't have a complete list of port numbers
-// (some Solaris distros).
-var services = map[string]map[string]int{
- "tcp": {"http": 80},
-}
var servicesError error
var onceReadServices sync.Once
@@ -27,14 +21,14 @@ func readServices() {
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 {
- line = line[0:i]
+ line = line[:i]
}
f := getFields(line)
if len(f) < 2 {
continue
}
portnet := f[1] // "80/tcp"
- port, j, ok := dtoi(portnet, 0)
+ port, j, ok := dtoi(portnet)
if !ok || port <= 0 || j >= len(portnet) || portnet[j] != '/' {
continue
}
@@ -56,18 +50,5 @@ func readServices() {
// goLookupPort is the native Go implementation of LookupPort.
func goLookupPort(network, service string) (port int, err error) {
onceReadServices.Do(readServices)
-
- switch network {
- case "tcp4", "tcp6":
- network = "tcp"
- case "udp4", "udp6":
- network = "udp"
- }
-
- if m, ok := services[network]; ok {
- if port, ok = m[service]; ok {
- return
- }
- }
- return 0, &AddrError{Err: "unknown port", Addr: network + "/" + service}
+ return lookupPortMap(network, service)
}
diff --git a/src/net/rpc/client.go b/src/net/rpc/client.go
index 862fb1a..fce6a48 100644
--- a/src/net/rpc/client.go
+++ b/src/net/rpc/client.go
@@ -274,6 +274,8 @@ func Dial(network, address string) (*Client, error) {
return NewClient(conn), nil
}
+// Close calls the underlying codec's Close method. If the connection is already
+// shutting down, ErrShutdown is returned.
func (client *Client) Close() error {
client.mutex.Lock()
if client.closing {
diff --git a/src/net/rpc/client_test.go b/src/net/rpc/client_test.go
index ba11ff8..d116d2a 100644
--- a/src/net/rpc/client_test.go
+++ b/src/net/rpc/client_test.go
@@ -8,7 +8,6 @@ import (
"errors"
"fmt"
"net"
- "runtime"
"strings"
"testing"
)
@@ -53,9 +52,6 @@ func (s *S) Recv(nul *struct{}, reply *R) error {
}
func TestGobError(t *testing.T) {
- if runtime.GOOS == "plan9" {
- t.Skip("skipping test; see https://golang.org/issue/8908")
- }
defer func() {
err := recover()
if err == nil {
diff --git a/src/net/rpc/server.go b/src/net/rpc/server.go
index cff3241..18ea629 100644
--- a/src/net/rpc/server.go
+++ b/src/net/rpc/server.go
@@ -23,7 +23,7 @@
func (t *T) MethodName(argType T1, replyType *T2) error
- where T, T1 and T2 can be marshaled by encoding/gob.
+ where T1 and T2 can be marshaled by encoding/gob.
These requirements apply even if a different codec is used.
(In the future, these requirements may soften for custom codecs.)
@@ -55,6 +55,8 @@
package server
+ import "errors"
+
type Args struct {
A, B int
}
@@ -119,6 +121,8 @@
A server implementation will often provide a simple, type-safe wrapper for the
client.
+
+ The net/rpc package is frozen and is not accepting new features.
*/
package rpc
diff --git a/src/net/rpc/server_test.go b/src/net/rpc/server_test.go
index d04271d..8369c9d 100644
--- a/src/net/rpc/server_test.go
+++ b/src/net/rpc/server_test.go
@@ -693,7 +693,8 @@ func benchmarkEndToEndAsync(dial func() (*Client, error), b *testing.B) {
B := call.Args.(*Args).B
C := call.Reply.(*Reply).C
if A+B != C {
- b.Fatalf("incorrect reply: Add: expected %d got %d", A+B, C)
+ b.Errorf("incorrect reply: Add: expected %d got %d", A+B, C)
+ return
}
<-gate
if atomic.AddInt32(&recv, -1) == 0 {
diff --git a/src/net/smtp/smtp.go b/src/net/smtp/smtp.go
index 9e04dd7..a408fa5 100644
--- a/src/net/smtp/smtp.go
+++ b/src/net/smtp/smtp.go
@@ -9,7 +9,7 @@
// STARTTLS RFC 3207
// Additional extensions may be handled by clients.
//
-// The smtp package is frozen and not accepting new features.
+// The smtp package is frozen and is not accepting new features.
// Some external packages provide more functionality. See:
//
// https://godoc.org/?q=smtp
@@ -19,6 +19,7 @@ import (
"crypto/tls"
"encoding/base64"
"errors"
+ "fmt"
"io"
"net"
"net/textproto"
@@ -200,7 +201,7 @@ func (c *Client) Auth(a Auth) error {
}
resp64 := make([]byte, encoding.EncodedLen(len(resp)))
encoding.Encode(resp64, resp)
- code, msg64, err := c.cmd(0, "AUTH %s %s", mech, resp64)
+ code, msg64, err := c.cmd(0, strings.TrimSpace(fmt.Sprintf("AUTH %s %s", mech, resp64)))
for err == nil {
var msg []byte
switch code {
diff --git a/src/net/smtp/smtp_test.go b/src/net/smtp/smtp_test.go
index 3ae0d5b..c48fae6 100644
--- a/src/net/smtp/smtp_test.go
+++ b/src/net/smtp/smtp_test.go
@@ -94,6 +94,46 @@ func TestAuthPlain(t *testing.T) {
}
}
+// Issue 17794: don't send a trailing space on AUTH command when there's no password.
+func TestClientAuthTrimSpace(t *testing.T) {
+ server := "220 hello world\r\n" +
+ "200 some more"
+ var wrote bytes.Buffer
+ var fake faker
+ fake.ReadWriter = struct {
+ io.Reader
+ io.Writer
+ }{
+ strings.NewReader(server),
+ &wrote,
+ }
+ c, err := NewClient(fake, "fake.host")
+ if err != nil {
+ t.Fatalf("NewClient: %v", err)
+ }
+ c.tls = true
+ c.didHello = true
+ c.Auth(toServerEmptyAuth{})
+ c.Close()
+ if got, want := wrote.String(), "AUTH FOOAUTH\r\n*\r\nQUIT\r\n"; got != want {
+ t.Errorf("wrote %q; want %q", got, want)
+ }
+}
+
+// toServerEmptyAuth is an implementation of Auth that only implements
+// the Start method, and returns "FOOAUTH", nil, nil. Notably, it returns
+// zero bytes for "toServer" so we can test that we don't send spaces at
+// the end of the line. See TestClientAuthTrimSpace.
+type toServerEmptyAuth struct{}
+
+func (toServerEmptyAuth) Start(server *ServerInfo) (proto string, toServer []byte, err error) {
+ return "FOOAUTH", nil, nil
+}
+
+func (toServerEmptyAuth) Next(fromServer []byte, more bool) (toServer []byte, err error) {
+ panic("unexpected call")
+}
+
type faker struct {
io.ReadWriter
}
@@ -716,23 +756,24 @@ func sendMail(hostPort string) error {
// generated from src/crypto/tls:
// go run generate_cert.go --rsa-bits 512 --host 127.0.0.1,::1,example.com --ca --start-date "Jan 1 00:00:00 1970" --duration=1000000h
var localhostCert = []byte(`-----BEGIN CERTIFICATE-----
-MIIBdzCCASOgAwIBAgIBADALBgkqhkiG9w0BAQUwEjEQMA4GA1UEChMHQWNtZSBD
-bzAeFw03MDAxMDEwMDAwMDBaFw00OTEyMzEyMzU5NTlaMBIxEDAOBgNVBAoTB0Fj
-bWUgQ28wWjALBgkqhkiG9w0BAQEDSwAwSAJBAN55NcYKZeInyTuhcCwFMhDHCmwa
-IUSdtXdcbItRB/yfXGBhiex00IaLXQnSU+QZPRZWYqeTEbFSgihqi1PUDy8CAwEA
-AaNoMGYwDgYDVR0PAQH/BAQDAgCkMBMGA1UdJQQMMAoGCCsGAQUFBwMBMA8GA1Ud
-EwEB/wQFMAMBAf8wLgYDVR0RBCcwJYILZXhhbXBsZS5jb22HBH8AAAGHEAAAAAAA
-AAAAAAAAAAAAAAEwCwYJKoZIhvcNAQEFA0EAAoQn/ytgqpiLcZu9XKbCJsJcvkgk
-Se6AbGXgSlq+ZCEVo0qIwSgeBqmsJxUu7NCSOwVJLYNEBO2DtIxoYVk+MA==
+MIIBjjCCATigAwIBAgIQMon9v0s3pDFXvAMnPgelpzANBgkqhkiG9w0BAQsFADAS
+MRAwDgYDVQQKEwdBY21lIENvMCAXDTcwMDEwMTAwMDAwMFoYDzIwODQwMTI5MTYw
+MDAwWjASMRAwDgYDVQQKEwdBY21lIENvMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJB
+AM0u/mNXKkhAzNsFkwKZPSpC4lZZaePQ55IyaJv3ovMM2smvthnlqaUfVKVmz7FF
+wLP9csX6vGtvkZg1uWAtvfkCAwEAAaNoMGYwDgYDVR0PAQH/BAQDAgKkMBMGA1Ud
+JQQMMAoGCCsGAQUFBwMBMA8GA1UdEwEB/wQFMAMBAf8wLgYDVR0RBCcwJYILZXhh
+bXBsZS5jb22HBH8AAAGHEAAAAAAAAAAAAAAAAAAAAAEwDQYJKoZIhvcNAQELBQAD
+QQBOZsFVC7IwX+qibmSbt2IPHkUgXhfbq0a9MYhD6tHcj4gbDcTXh4kZCbgHCz22
+gfSj2/G2wxzopoISVDucuncj
-----END CERTIFICATE-----`)
// localhostKey is the private key for localhostCert.
var localhostKey = []byte(`-----BEGIN RSA PRIVATE KEY-----
-MIIBPAIBAAJBAN55NcYKZeInyTuhcCwFMhDHCmwaIUSdtXdcbItRB/yfXGBhiex0
-0IaLXQnSU+QZPRZWYqeTEbFSgihqi1PUDy8CAwEAAQJBAQdUx66rfh8sYsgfdcvV
-NoafYpnEcB5s4m/vSVe6SU7dCK6eYec9f9wpT353ljhDUHq3EbmE4foNzJngh35d
-AekCIQDhRQG5Li0Wj8TM4obOnnXUXf1jRv0UkzE9AHWLG5q3AwIhAPzSjpYUDjVW
-MCUXgckTpKCuGwbJk7424Nb8bLzf3kllAiA5mUBgjfr/WtFSJdWcPQ4Zt9KTMNKD
-EUO0ukpTwEIl6wIhAMbGqZK3zAAFdq8DD2jPx+UJXnh0rnOkZBzDtJ6/iN69AiEA
-1Aq8MJgTaYsDQWyU/hDq5YkDJc9e9DSCvUIzqxQWMQE=
+MIIBOwIBAAJBAM0u/mNXKkhAzNsFkwKZPSpC4lZZaePQ55IyaJv3ovMM2smvthnl
+qaUfVKVmz7FFwLP9csX6vGtvkZg1uWAtvfkCAwEAAQJART2qkxODLUbQ2siSx7m2
+rmBLyR/7X+nLe8aPDrMOxj3heDNl4YlaAYLexbcY8d7VDfCRBKYoAOP0UCP1Vhuf
+UQIhAO6PEI55K3SpNIdc2k5f0xz+9rodJCYzu51EwWX7r8ufAiEA3C9EkLiU2NuK
+3L3DHCN5IlUSN1Nr/lw8NIt50Yorj2cCIQCDw1VbvCV6bDLtSSXzAA51B4ZzScE7
+sHtB5EYF9Dwm9QIhAJuCquuH4mDzVjUntXjXOQPdj7sRqVGCNWdrJwOukat7AiAy
+LXLEwb77DIPoI5ZuaXQC+MnyyJj1ExC9RFcGz+bexA==
-----END RSA PRIVATE KEY-----`)
diff --git a/src/net/sock_linux.go b/src/net/sock_linux.go
index e2732c5..7bca376 100644
--- a/src/net/sock_linux.go
+++ b/src/net/sock_linux.go
@@ -17,7 +17,7 @@ func maxListenerBacklog() int {
return syscall.SOMAXCONN
}
f := getFields(l)
- n, _, ok := dtoi(f[0], 0)
+ n, _, ok := dtoi(f[0])
if n == 0 || !ok {
return syscall.SOMAXCONN
}
diff --git a/src/net/sock_posix.go b/src/net/sock_posix.go
index c3af27b..16351e1 100644
--- a/src/net/sock_posix.go
+++ b/src/net/sock_posix.go
@@ -30,6 +30,9 @@ type sockaddr interface {
// interface. It returns a nil interface when the address is
// nil.
sockaddr(family int) (syscall.Sockaddr, error)
+
+ // toLocal maps the zero address to a local system address (127.0.0.1 or ::1)
+ toLocal(net string) sockaddr
}
// socket returns a network file descriptor that is ready for
diff --git a/src/net/tcpsock.go b/src/net/tcpsock.go
index 7cffcc5..69731eb 100644
--- a/src/net/tcpsock.go
+++ b/src/net/tcpsock.go
@@ -12,6 +12,9 @@ import (
"time"
)
+// BUG(mikio): On Windows, the File method of TCPListener is not
+// implemented.
+
// TCPAddr represents the address of a TCP end point.
type TCPAddr struct {
IP IP
@@ -53,6 +56,9 @@ func (a *TCPAddr) opAddr() Addr {
// "tcp6". 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".
+//
+// Resolving a hostname is not recommended because this returns at most
+// one of its IP addresses.
func ResolveTCPAddr(net, addr string) (*TCPAddr, error) {
switch net {
case "tcp", "tcp4", "tcp6":
@@ -61,7 +67,7 @@ func ResolveTCPAddr(net, addr string) (*TCPAddr, error) {
default:
return nil, UnknownNetworkError(net)
}
- addrs, err := internetAddrList(context.Background(), net, addr)
+ addrs, err := DefaultResolver.internetAddrList(context.Background(), net, addr)
if err != nil {
return nil, err
}
@@ -81,7 +87,7 @@ func (c *TCPConn) ReadFrom(r io.Reader) (int64, error) {
}
n, err := c.readFrom(r)
if err != nil && err != io.EOF {
- err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
+ err = &OpError{Op: "readfrom", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
}
return n, err
}
diff --git a/src/net/tcpsock_posix.go b/src/net/tcpsock_posix.go
index c9a8b68..9641e5c 100644
--- a/src/net/tcpsock_posix.go
+++ b/src/net/tcpsock_posix.go
@@ -40,6 +40,10 @@ func (a *TCPAddr) sockaddr(family int) (syscall.Sockaddr, error) {
return ipToSockaddr(family, a.IP, a.Port, a.Zone)
}
+func (a *TCPAddr) toLocal(net string) sockaddr {
+ return &TCPAddr{loopbackIP(net), a.Port, a.Zone}
+}
+
func (c *TCPConn) readFrom(r io.Reader) (int64, error) {
if n, err, handled := sendFile(c.fd, r); handled {
return n, err
diff --git a/src/net/tcpsock_test.go b/src/net/tcpsock_test.go
index 4af47fc..573e834 100644
--- a/src/net/tcpsock_test.go
+++ b/src/net/tcpsock_test.go
@@ -5,6 +5,7 @@
package net
import (
+ "fmt"
"internal/testenv"
"io"
"reflect"
@@ -310,6 +311,16 @@ var resolveTCPAddrTests = []resolveTCPAddrTest{
{"tcp", ":12345", &TCPAddr{Port: 12345}, nil},
{"http", "127.0.0.1:0", nil, UnknownNetworkError("http")},
+
+ {"tcp", "127.0.0.1:http", &TCPAddr{IP: ParseIP("127.0.0.1"), Port: 80}, nil},
+ {"tcp", "[::ffff:127.0.0.1]:http", &TCPAddr{IP: ParseIP("::ffff:127.0.0.1"), Port: 80}, nil},
+ {"tcp", "[2001:db8::1]:http", &TCPAddr{IP: ParseIP("2001:db8::1"), Port: 80}, nil},
+ {"tcp4", "127.0.0.1:http", &TCPAddr{IP: ParseIP("127.0.0.1"), Port: 80}, nil},
+ {"tcp4", "[::ffff:127.0.0.1]:http", &TCPAddr{IP: ParseIP("127.0.0.1"), Port: 80}, nil},
+ {"tcp4", "[2001:db8::1]:http", nil, &AddrError{Err: errNoSuitableAddress.Error(), Addr: "2001:db8::1"}},
+ {"tcp6", "127.0.0.1:http", nil, &AddrError{Err: errNoSuitableAddress.Error(), Addr: "127.0.0.1"}},
+ {"tcp6", "[::ffff:127.0.0.1]:http", nil, &AddrError{Err: errNoSuitableAddress.Error(), Addr: "::ffff:127.0.0.1"}},
+ {"tcp6", "[2001:db8::1]:http", &TCPAddr{IP: ParseIP("2001:db8::1"), Port: 80}, nil},
}
func TestResolveTCPAddr(t *testing.T) {
@@ -317,21 +328,17 @@ func TestResolveTCPAddr(t *testing.T) {
defer func() { testHookLookupIP = origTestHookLookupIP }()
testHookLookupIP = lookupLocalhost
- for i, tt := range resolveTCPAddrTests {
+ for _, tt := range resolveTCPAddrTests {
addr, err := ResolveTCPAddr(tt.network, tt.litAddrOrName)
- if err != tt.err {
- t.Errorf("#%d: %v", i, err)
- } else if !reflect.DeepEqual(addr, tt.addr) {
- t.Errorf("#%d: got %#v; want %#v", i, addr, tt.addr)
- }
- if err != nil {
+ if !reflect.DeepEqual(addr, tt.addr) || !reflect.DeepEqual(err, tt.err) {
+ t.Errorf("ResolveTCPAddr(%q, %q) = %v, %v, want %v, %v", tt.network, tt.litAddrOrName, addr, err, tt.addr, tt.err)
continue
}
- rtaddr, err := ResolveTCPAddr(addr.Network(), addr.String())
- if err != nil {
- t.Errorf("#%d: %v", i, err)
- } else if !reflect.DeepEqual(rtaddr, addr) {
- t.Errorf("#%d: got %#v; want %#v", i, rtaddr, addr)
+ if err == nil {
+ addr2, err := ResolveTCPAddr(addr.Network(), addr.String())
+ if !reflect.DeepEqual(addr2, tt.addr) || err != tt.err {
+ t.Errorf("(%q, %q): ResolveTCPAddr(%q, %q) = %v, %v, want %v, %v", tt.network, tt.litAddrOrName, addr.Network(), addr.String(), addr2, err, tt.addr, tt.err)
+ }
}
}
}
@@ -460,11 +467,14 @@ func TestTCPConcurrentAccept(t *testing.T) {
func TestTCPReadWriteAllocs(t *testing.T) {
switch runtime.GOOS {
- case "nacl", "windows":
+ case "plan9":
+ // The implementation of asynchronous cancelable
+ // I/O on Plan 9 allocates memory.
+ // See net/fd_io_plan9.go.
+ t.Skipf("not supported on %s", runtime.GOOS)
+ case "nacl":
// NaCl needs to allocate pseudo file descriptor
// stuff. See syscall/fd_nacl.go.
- // Windows uses closures and channels for IO
- // completion port-based netpoll. See fd_windows.go.
t.Skipf("not supported on %s", runtime.GOOS)
}
@@ -474,7 +484,7 @@ func TestTCPReadWriteAllocs(t *testing.T) {
}
defer ln.Close()
var server Conn
- errc := make(chan error)
+ errc := make(chan error, 1)
go func() {
var err error
server, err = ln.Accept()
@@ -489,6 +499,7 @@ func TestTCPReadWriteAllocs(t *testing.T) {
t.Fatal(err)
}
defer server.Close()
+
var buf [128]byte
allocs := testing.AllocsPerRun(1000, func() {
_, err := server.Write(buf[:])
@@ -503,6 +514,28 @@ func TestTCPReadWriteAllocs(t *testing.T) {
if allocs > 0 {
t.Fatalf("got %v; want 0", allocs)
}
+
+ var bufwrt [128]byte
+ ch := make(chan bool)
+ defer close(ch)
+ go func() {
+ for <-ch {
+ _, err := server.Write(bufwrt[:])
+ errc <- err
+ }
+ }()
+ allocs = testing.AllocsPerRun(1000, func() {
+ ch <- true
+ if _, err = io.ReadFull(client, buf[:]); err != nil {
+ t.Fatal(err)
+ }
+ if err := <-errc; err != nil {
+ t.Fatal(err)
+ }
+ })
+ if allocs > 0 {
+ t.Fatalf("got %v; want 0", allocs)
+ }
}
func TestTCPStress(t *testing.T) {
@@ -633,3 +666,58 @@ func TestTCPSelfConnect(t *testing.T) {
}
}
}
+
+// Test that >32-bit reads work on 64-bit systems.
+// On 32-bit systems this tests that maxint reads work.
+func TestTCPBig(t *testing.T) {
+ if !*testTCPBig {
+ t.Skip("test disabled; use -tcpbig to enable")
+ }
+
+ for _, writev := range []bool{false, true} {
+ t.Run(fmt.Sprintf("writev=%v", writev), func(t *testing.T) {
+ ln, err := newLocalListener("tcp")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer ln.Close()
+
+ x := int(1 << 30)
+ x = x*5 + 1<<20 // just over 5 GB on 64-bit, just over 1GB on 32-bit
+ done := make(chan int)
+ go func() {
+ defer close(done)
+ c, err := ln.Accept()
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ buf := make([]byte, x)
+ var n int
+ if writev {
+ var n64 int64
+ n64, err = (&Buffers{buf}).WriteTo(c)
+ n = int(n64)
+ } else {
+ n, err = c.Write(buf)
+ }
+ if n != len(buf) || err != nil {
+ t.Errorf("Write(buf) = %d, %v, want %d, nil", n, err, x)
+ }
+ c.Close()
+ }()
+
+ c, err := Dial("tcp", ln.Addr().String())
+ if err != nil {
+ t.Fatal(err)
+ }
+ buf := make([]byte, x)
+ n, err := io.ReadFull(c, buf)
+ if n != len(buf) || err != nil {
+ t.Errorf("Read(buf) = %d, %v, want %d, nil", n, err, x)
+ }
+ c.Close()
+ <-done
+ })
+ }
+}
diff --git a/src/net/tcpsock_unix_test.go b/src/net/tcpsock_unix_test.go
index c07f7d7..2375fe2 100644
--- a/src/net/tcpsock_unix_test.go
+++ b/src/net/tcpsock_unix_test.go
@@ -15,7 +15,7 @@ import (
)
// See golang.org/issue/14548.
-func TestTCPSupriousConnSetupCompletion(t *testing.T) {
+func TestTCPSpuriousConnSetupCompletion(t *testing.T) {
if testing.Short() {
t.Skip("skipping in short mode")
}
@@ -57,7 +57,7 @@ func TestTCPSupriousConnSetupCompletion(t *testing.T) {
c, err := d.Dial(ln.Addr().Network(), ln.Addr().String())
if err != nil {
if perr := parseDialError(err); perr != nil {
- t.Errorf("#%d: %v", i, err)
+ t.Errorf("#%d: %v (original error: %v)", i, perr, err)
}
return
}
diff --git a/src/net/testdata/invalid-ndots-resolv.conf b/src/net/testdata/invalid-ndots-resolv.conf
new file mode 100644
index 0000000..084c164
--- /dev/null
+++ b/src/net/testdata/invalid-ndots-resolv.conf
@@ -0,0 +1 @@
+options ndots:invalid
\ No newline at end of file
diff --git a/src/net/testdata/large-ndots-resolv.conf b/src/net/testdata/large-ndots-resolv.conf
new file mode 100644
index 0000000..72968ee
--- /dev/null
+++ b/src/net/testdata/large-ndots-resolv.conf
@@ -0,0 +1 @@
+options ndots:16
\ No newline at end of file
diff --git a/src/net/testdata/negative-ndots-resolv.conf b/src/net/testdata/negative-ndots-resolv.conf
new file mode 100644
index 0000000..c11e0cc
--- /dev/null
+++ b/src/net/testdata/negative-ndots-resolv.conf
@@ -0,0 +1 @@
+options ndots:-1
\ No newline at end of file
diff --git a/src/net/textproto/header.go b/src/net/textproto/header.go
index 2e2752a..ed096d9 100644
--- a/src/net/textproto/header.go
+++ b/src/net/textproto/header.go
@@ -23,8 +23,10 @@ func (h MIMEHeader) Set(key, value string) {
}
// Get gets the first value associated with the given key.
+// It is case insensitive; CanonicalMIMEHeaderKey is used
+// to canonicalize the provided key.
// If there are no values associated with the key, Get returns "".
-// Get is a convenience method. For more complex queries,
+// To access multiple values of a key, or to use non-canonical keys,
// access the map directly.
func (h MIMEHeader) Get(key string) string {
if h == nil {
diff --git a/src/net/timeout_test.go b/src/net/timeout_test.go
index ed26f2a..55bbf44 100644
--- a/src/net/timeout_test.go
+++ b/src/net/timeout_test.go
@@ -5,7 +5,6 @@
package net
import (
- "context"
"fmt"
"internal/testenv"
"io"
@@ -152,6 +151,7 @@ var acceptTimeoutTests = []struct {
}
func TestAcceptTimeout(t *testing.T) {
+ testenv.SkipFlaky(t, 17948)
t.Parallel()
switch runtime.GOOS {
@@ -165,19 +165,18 @@ func TestAcceptTimeout(t *testing.T) {
}
defer ln.Close()
- ctx, cancel := context.WithCancel(context.Background())
- defer cancel()
+ var wg sync.WaitGroup
for i, tt := range acceptTimeoutTests {
if tt.timeout < 0 {
+ wg.Add(1)
go func() {
- var d Dialer
- c, err := d.DialContext(ctx, ln.Addr().Network(), ln.Addr().String())
+ defer wg.Done()
+ d := Dialer{Timeout: 100 * time.Millisecond}
+ c, err := d.Dial(ln.Addr().Network(), ln.Addr().String())
if err != nil {
t.Error(err)
return
}
- var b [1]byte
- c.Read(b[:])
c.Close()
}()
}
@@ -198,13 +197,14 @@ func TestAcceptTimeout(t *testing.T) {
}
if err == nil {
c.Close()
- time.Sleep(tt.timeout / 3)
+ time.Sleep(10 * time.Millisecond)
continue
}
break
}
}
}
+ wg.Wait()
}
func TestAcceptTimeoutMustReturn(t *testing.T) {
@@ -305,11 +305,6 @@ var readTimeoutTests = []struct {
}
func TestReadTimeout(t *testing.T) {
- switch runtime.GOOS {
- case "plan9":
- t.Skipf("not supported on %s", runtime.GOOS)
- }
-
handler := func(ls *localServer, ln Listener) {
c, err := ln.Accept()
if err != nil {
@@ -435,7 +430,7 @@ var readFromTimeoutTests = []struct {
func TestReadFromTimeout(t *testing.T) {
switch runtime.GOOS {
- case "nacl", "plan9":
+ case "nacl":
t.Skipf("not supported on %s", runtime.GOOS) // see golang.org/issue/8916
}
@@ -509,11 +504,6 @@ var writeTimeoutTests = []struct {
func TestWriteTimeout(t *testing.T) {
t.Parallel()
- switch runtime.GOOS {
- case "plan9":
- t.Skipf("not supported on %s", runtime.GOOS)
- }
-
ln, err := newLocalListener("tcp")
if err != nil {
t.Fatal(err)
@@ -629,7 +619,7 @@ func TestWriteToTimeout(t *testing.T) {
t.Parallel()
switch runtime.GOOS {
- case "nacl", "plan9":
+ case "nacl":
t.Skipf("not supported on %s", runtime.GOOS)
}
@@ -681,11 +671,6 @@ func TestWriteToTimeout(t *testing.T) {
func TestReadTimeoutFluctuation(t *testing.T) {
t.Parallel()
- switch runtime.GOOS {
- case "plan9":
- t.Skipf("not supported on %s", runtime.GOOS)
- }
-
ln, err := newLocalListener("tcp")
if err != nil {
t.Fatal(err)
@@ -719,11 +704,6 @@ func TestReadTimeoutFluctuation(t *testing.T) {
func TestReadFromTimeoutFluctuation(t *testing.T) {
t.Parallel()
- switch runtime.GOOS {
- case "plan9":
- t.Skipf("not supported on %s", runtime.GOOS)
- }
-
c1, err := newLocalPacketListener("udp")
if err != nil {
t.Fatal(err)
@@ -829,11 +809,6 @@ func (b neverEnding) Read(p []byte) (int, error) {
}
func testVariousDeadlines(t *testing.T) {
- switch runtime.GOOS {
- case "plan9":
- t.Skipf("not supported on %s", runtime.GOOS)
- }
-
type result struct {
n int64
err error
@@ -1030,7 +1005,7 @@ func TestReadWriteDeadlineRace(t *testing.T) {
t.Parallel()
switch runtime.GOOS {
- case "nacl", "plan9":
+ case "nacl":
t.Skipf("not supported on %s", runtime.GOOS)
}
diff --git a/src/net/udpsock.go b/src/net/udpsock.go
index 980f67c..841ef53 100644
--- a/src/net/udpsock.go
+++ b/src/net/udpsock.go
@@ -9,6 +9,15 @@ import (
"syscall"
)
+// BUG(mikio): On NaCl, Plan 9 and Windows, the ReadMsgUDP and
+// WriteMsgUDP methods of UDPConn are not implemented.
+
+// BUG(mikio): On Windows, the File method of UDPConn is not
+// implemented.
+
+// BUG(mikio): On NaCl, the ListenMulticastUDP function is not
+// implemented.
+
// UDPAddr represents the address of a UDP end point.
type UDPAddr struct {
IP IP
@@ -50,6 +59,9 @@ func (a *UDPAddr) opAddr() Addr {
// "udp6". 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".
+//
+// Resolving a hostname is not recommended because this returns at most
+// one of its IP addresses.
func ResolveUDPAddr(net, addr string) (*UDPAddr, error) {
switch net {
case "udp", "udp4", "udp6":
@@ -58,7 +70,7 @@ func ResolveUDPAddr(net, addr string) (*UDPAddr, error) {
default:
return nil, UnknownNetworkError(net)
}
- addrs, err := internetAddrList(context.Background(), net, addr)
+ addrs, err := DefaultResolver.internetAddrList(context.Background(), net, addr)
if err != nil {
return nil, err
}
diff --git a/src/net/udpsock_plan9.go b/src/net/udpsock_plan9.go
index 666f206..1ce7f88 100644
--- a/src/net/udpsock_plan9.go
+++ b/src/net/udpsock_plan9.go
@@ -109,5 +109,41 @@ func listenUDP(ctx context.Context, network string, laddr *UDPAddr) (*UDPConn, e
}
func listenMulticastUDP(ctx context.Context, network string, ifi *Interface, gaddr *UDPAddr) (*UDPConn, error) {
- return nil, syscall.EPLAN9
+ l, err := listenPlan9(ctx, network, gaddr)
+ if err != nil {
+ return nil, err
+ }
+ _, err = l.ctl.WriteString("headers")
+ if err != nil {
+ return nil, err
+ }
+ var addrs []Addr
+ if ifi != nil {
+ addrs, err = ifi.Addrs()
+ if err != nil {
+ return nil, err
+ }
+ } else {
+ addrs, err = InterfaceAddrs()
+ if err != nil {
+ return nil, err
+ }
+ }
+ for _, addr := range addrs {
+ if ipnet, ok := addr.(*IPNet); ok {
+ _, err = l.ctl.WriteString("addmulti " + ipnet.IP.String() + " " + gaddr.IP.String())
+ if err != nil {
+ return nil, err
+ }
+ }
+ }
+ l.data, err = os.OpenFile(l.dir+"/data", os.O_RDWR, 0)
+ if err != nil {
+ return nil, err
+ }
+ fd, err := l.netFD()
+ if err != nil {
+ return nil, err
+ }
+ return newUDPConn(fd), nil
}
diff --git a/src/net/udpsock_plan9_test.go b/src/net/udpsock_plan9_test.go
new file mode 100644
index 0000000..09f5a5d
--- /dev/null
+++ b/src/net/udpsock_plan9_test.go
@@ -0,0 +1,69 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package net
+
+import (
+ "internal/testenv"
+ "runtime"
+ "testing"
+)
+
+func TestListenMulticastUDP(t *testing.T) {
+ testenv.MustHaveExternalNetwork(t)
+
+ ifcs, err := Interfaces()
+ if err != nil {
+ t.Skip(err.Error())
+ }
+ if len(ifcs) == 0 {
+ t.Skip("no network interfaces found")
+ }
+
+ var mifc *Interface
+ for _, ifc := range ifcs {
+ if ifc.Flags&FlagUp|FlagMulticast != FlagUp|FlagMulticast {
+ continue
+ }
+ mifc = &ifc
+ break
+ }
+
+ if mifc == nil {
+ t.Skipf("no multicast interfaces found")
+ }
+
+ c1, err := ListenMulticastUDP("udp4", mifc, &UDPAddr{IP: ParseIP("224.0.0.254")})
+ if err != nil {
+ t.Fatalf("multicast not working on %s", runtime.GOOS)
+ }
+ c1addr := c1.LocalAddr().(*UDPAddr)
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer c1.Close()
+
+ c2, err := ListenUDP("udp4", &UDPAddr{IP: IPv4zero, Port: 0})
+ c2addr := c2.LocalAddr().(*UDPAddr)
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer c2.Close()
+
+ n, err := c2.WriteToUDP([]byte("data"), c1addr)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if n != 4 {
+ t.Fatalf("got %d; want 4", n)
+ }
+
+ n, err = c1.WriteToUDP([]byte("data"), c2addr)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if n != 4 {
+ t.Fatalf("got %d; want 4", n)
+ }
+}
diff --git a/src/net/udpsock_posix.go b/src/net/udpsock_posix.go
index 4924801..72aadca 100644
--- a/src/net/udpsock_posix.go
+++ b/src/net/udpsock_posix.go
@@ -38,6 +38,10 @@ func (a *UDPAddr) sockaddr(family int) (syscall.Sockaddr, error) {
return ipToSockaddr(family, a.IP, a.Port, a.Zone)
}
+func (a *UDPAddr) toLocal(net string) sockaddr {
+ return &UDPAddr{loopbackIP(net), a.Port, a.Zone}
+}
+
func (c *UDPConn) readFrom(b []byte) (int, *UDPAddr, error) {
var addr *UDPAddr
n, sa, err := c.fd.readFrom(b)
diff --git a/src/net/unixsock.go b/src/net/unixsock.go
index bacdaa4..b25d492 100644
--- a/src/net/unixsock.go
+++ b/src/net/unixsock.go
@@ -7,6 +7,7 @@ package net
import (
"context"
"os"
+ "sync"
"syscall"
"time"
)
@@ -120,6 +121,9 @@ func (c *UnixConn) ReadFrom(b []byte) (int, Addr, error) {
// the associated out-of-band data into oob. It returns the number of
// bytes copied into b, the number of bytes copied into oob, the flags
// that were set on the packet, and the source address of the packet.
+//
+// Note that if len(b) == 0 and len(oob) > 0, this function will still
+// read (and discard) 1 byte from the connection.
func (c *UnixConn) ReadMsgUnix(b, oob []byte) (n, oobn, flags int, addr *UnixAddr, err error) {
if !c.ok() {
return 0, 0, 0, nil, syscall.EINVAL
@@ -167,6 +171,9 @@ func (c *UnixConn) WriteTo(b []byte, addr Addr) (int, error) {
// WriteMsgUnix writes a packet to addr via c, copying the payload
// from b and the associated out-of-band data from oob. It returns
// the number of payload and out-of-band bytes written.
+//
+// Note that if len(b) == 0 and len(oob) > 0, this function will still
+// write 1 byte to the connection.
func (c *UnixConn) WriteMsgUnix(b, oob []byte, addr *UnixAddr) (n, oobn int, err error) {
if !c.ok() {
return 0, 0, syscall.EINVAL
@@ -200,9 +207,10 @@ func DialUnix(net string, laddr, raddr *UnixAddr) (*UnixConn, error) {
// typically use variables of type Listener instead of assuming Unix
// domain sockets.
type UnixListener struct {
- fd *netFD
- path string
- unlink bool
+ fd *netFD
+ path string
+ unlink bool
+ unlinkOnce sync.Once
}
func (ln *UnixListener) ok() bool { return ln != nil && ln.fd != nil }
diff --git a/src/net/unixsock_posix.go b/src/net/unixsock_posix.go
index 5f0999c..a8f892e 100644
--- a/src/net/unixsock_posix.go
+++ b/src/net/unixsock_posix.go
@@ -94,6 +94,10 @@ func (a *UnixAddr) sockaddr(family int) (syscall.Sockaddr, error) {
return &syscall.SockaddrUnix{Name: a.Name}, nil
}
+func (a *UnixAddr) toLocal(net string) sockaddr {
+ return a
+}
+
func (c *UnixConn) readFrom(b []byte) (int, *UnixAddr, error) {
var addr *UnixAddr
n, sa, err := c.fd.readFrom(b)
@@ -173,9 +177,12 @@ func (ln *UnixListener) close() error {
// is at least compatible with the auto-remove
// sequence in ListenUnix. It's only non-Go
// programs that can mess us up.
- if ln.path[0] != '@' && ln.unlink {
- syscall.Unlink(ln.path)
- }
+ // Even if there are racy calls to Close, we want to unlink only for the first one.
+ ln.unlinkOnce.Do(func() {
+ if ln.path[0] != '@' && ln.unlink {
+ syscall.Unlink(ln.path)
+ }
+ })
return ln.fd.Close()
}
@@ -187,6 +194,18 @@ func (ln *UnixListener) file() (*os.File, error) {
return f, nil
}
+// SetUnlinkOnClose sets whether the underlying socket file should be removed
+// from the file system when the listener is closed.
+//
+// The default behavior is to unlink the socket file only when package net created it.
+// That is, when the listener and the underlying socket file were created by a call to
+// Listen or ListenUnix, then by default closing the listener will remove the socket file.
+// but if the listener was created by a call to FileListener to use an already existing
+// socket file, then by default closing the listener will not remove the socket file.
+func (l *UnixListener) SetUnlinkOnClose(unlink bool) {
+ l.unlink = unlink
+}
+
func listenUnix(ctx context.Context, network string, laddr *UnixAddr) (*UnixListener, error) {
fd, err := unixSocket(ctx, network, laddr, nil, "listen")
if err != nil {
diff --git a/src/net/unixsock_test.go b/src/net/unixsock_test.go
index f0f88ed..489a29b 100644
--- a/src/net/unixsock_test.go
+++ b/src/net/unixsock_test.go
@@ -9,6 +9,7 @@ package net
import (
"bytes"
"internal/testenv"
+ "io/ioutil"
"os"
"reflect"
"runtime"
@@ -414,33 +415,104 @@ func TestUnixUnlink(t *testing.T) {
t.Skip("unix test")
}
name := testUnixAddr()
- l, err := Listen("unix", name)
- if err != nil {
- t.Fatal(err)
- }
- if _, err := os.Stat(name); err != nil {
- t.Fatalf("cannot stat unix socket after ListenUnix: %v", err)
- }
- f, _ := l.(*UnixListener).File()
- l1, err := FileListener(f)
- if err != nil {
- t.Fatal(err)
- }
- if _, err := os.Stat(name); err != nil {
- t.Fatalf("cannot stat unix socket after FileListener: %v", err)
- }
- if err := l1.Close(); err != nil {
- t.Fatalf("closing file listener: %v", err)
- }
- if _, err := os.Stat(name); err != nil {
- t.Fatalf("cannot stat unix socket after closing FileListener: %v", err)
+
+ listen := func(t *testing.T) *UnixListener {
+ l, err := Listen("unix", name)
+ if err != nil {
+ t.Fatal(err)
+ }
+ return l.(*UnixListener)
}
- f.Close()
- if _, err := os.Stat(name); err != nil {
- t.Fatalf("cannot stat unix socket after closing FileListener and fd: %v", err)
+ checkExists := func(t *testing.T, desc string) {
+ if _, err := os.Stat(name); err != nil {
+ t.Fatalf("unix socket does not exist %s: %v", desc, err)
+ }
}
- l.Close()
- if _, err := os.Stat(name); err == nil {
- t.Fatal("closing unix listener did not remove unix socket")
+ checkNotExists := func(t *testing.T, desc string) {
+ if _, err := os.Stat(name); err == nil {
+ t.Fatalf("unix socket does exist %s: %v", desc, err)
+ }
}
+
+ // Listener should remove on close.
+ t.Run("Listen", func(t *testing.T) {
+ l := listen(t)
+ checkExists(t, "after Listen")
+ l.Close()
+ checkNotExists(t, "after Listener close")
+ })
+
+ // FileListener should not.
+ t.Run("FileListener", func(t *testing.T) {
+ l := listen(t)
+ f, _ := l.File()
+ l1, _ := FileListener(f)
+ checkExists(t, "after FileListener")
+ f.Close()
+ checkExists(t, "after File close")
+ l1.Close()
+ checkExists(t, "after FileListener close")
+ l.Close()
+ checkNotExists(t, "after Listener close")
+ })
+
+ // Only first call to l.Close should remove.
+ t.Run("SecondClose", func(t *testing.T) {
+ l := listen(t)
+ checkExists(t, "after Listen")
+ l.Close()
+ checkNotExists(t, "after Listener close")
+ if err := ioutil.WriteFile(name, []byte("hello world"), 0666); err != nil {
+ t.Fatalf("cannot recreate socket file: %v", err)
+ }
+ checkExists(t, "after writing temp file")
+ l.Close()
+ checkExists(t, "after second Listener close")
+ os.Remove(name)
+ })
+
+ // SetUnlinkOnClose should do what it says.
+
+ t.Run("Listen/SetUnlinkOnClose(true)", func(t *testing.T) {
+ l := listen(t)
+ checkExists(t, "after Listen")
+ l.SetUnlinkOnClose(true)
+ l.Close()
+ checkNotExists(t, "after Listener close")
+ })
+
+ t.Run("Listen/SetUnlinkOnClose(false)", func(t *testing.T) {
+ l := listen(t)
+ checkExists(t, "after Listen")
+ l.SetUnlinkOnClose(false)
+ l.Close()
+ checkExists(t, "after Listener close")
+ os.Remove(name)
+ })
+
+ t.Run("FileListener/SetUnlinkOnClose(true)", func(t *testing.T) {
+ l := listen(t)
+ f, _ := l.File()
+ l1, _ := FileListener(f)
+ checkExists(t, "after FileListener")
+ l1.(*UnixListener).SetUnlinkOnClose(true)
+ f.Close()
+ checkExists(t, "after File close")
+ l1.Close()
+ checkNotExists(t, "after FileListener close")
+ l.Close()
+ })
+
+ t.Run("FileListener/SetUnlinkOnClose(false)", func(t *testing.T) {
+ l := listen(t)
+ f, _ := l.File()
+ l1, _ := FileListener(f)
+ checkExists(t, "after FileListener")
+ l1.(*UnixListener).SetUnlinkOnClose(false)
+ f.Close()
+ checkExists(t, "after File close")
+ l1.Close()
+ checkExists(t, "after FileListener close")
+ l.Close()
+ })
}
diff --git a/src/net/url/example_test.go b/src/net/url/example_test.go
index 645de2e..4ae7724 100644
--- a/src/net/url/example_test.go
+++ b/src/net/url/example_test.go
@@ -5,6 +5,7 @@
package url_test
import (
+ "encoding/json"
"fmt"
"log"
"net/http"
@@ -98,3 +99,21 @@ func ExampleURL_ResolveReference() {
// Output:
// http://example.com/search?q=dotnet
}
+
+func ExampleParseQuery() {
+ m, err := url.ParseQuery(`x=1&y=2&y=3;z`)
+ if err != nil {
+ log.Fatal(err)
+ }
+ fmt.Println(toJSON(m))
+ // Output:
+ // {"x":["1"], "y":["2", "3"], "z":[""]}
+}
+
+func toJSON(m interface{}) string {
+ js, err := json.Marshal(m)
+ if err != nil {
+ log.Fatal(err)
+ }
+ return strings.Replace(string(js), ",", ", ", -1)
+}
diff --git a/src/net/url/url.go b/src/net/url/url.go
index 30e9277..42a514b 100644
--- a/src/net/url/url.go
+++ b/src/net/url/url.go
@@ -74,6 +74,7 @@ type encoding int
const (
encodePath encoding = 1 + iota
+ encodePathSegment
encodeHost
encodeZone
encodeUserPassword
@@ -132,9 +133,14 @@ func shouldEscape(c byte, mode encoding) bool {
// The RFC allows : @ & = + $ but saves / ; , for assigning
// meaning to individual path segments. This package
// only manipulates the path as a whole, so we allow those
- // last two as well. That leaves only ? to escape.
+ // last three as well. That leaves only ? to escape.
return c == '?'
+ case encodePathSegment: // §3.3
+ // The RFC allows : @ & = + $ but saves / ; , for assigning
+ // meaning to individual path segments.
+ return c == '/' || c == ';' || c == ',' || c == '?'
+
case encodeUserPassword: // §3.2.1
// The RFC allows ';', ':', '&', '=', '+', '$', and ',' in
// userinfo, so we must escape only '@', '/', and '?'.
@@ -164,6 +170,15 @@ func QueryUnescape(s string) (string, error) {
return unescape(s, encodeQueryComponent)
}
+// PathUnescape does the inverse transformation of PathEscape, converting
+// %AB into the byte 0xAB. It returns an error if any % is not followed by
+// two hexadecimal digits.
+//
+// PathUnescape is identical to QueryUnescape except that it does not unescape '+' to ' ' (space).
+func PathUnescape(s string) (string, error) {
+ return unescape(s, encodePathSegment)
+}
+
// unescape unescapes a string; the mode specifies
// which section of the URL string is being unescaped.
func unescape(s string, mode encoding) (string, error) {
@@ -250,6 +265,12 @@ func QueryEscape(s string) string {
return escape(s, encodeQueryComponent)
}
+// PathEscape escapes the string so it can be safely placed
+// inside a URL path segment.
+func PathEscape(s string) string {
+ return escape(s, encodePathSegment)
+}
+
func escape(s string, mode encoding) string {
spaceCount, hexCount := 0, 0
for i := 0; i < len(s); i++ {
@@ -356,10 +377,7 @@ func (u *Userinfo) Username() string {
// Password returns the password in case it is set, and whether it is set.
func (u *Userinfo) Password() (string, bool) {
- if u.passwordSet {
- return u.password, true
- }
- return "", false
+ return u.password, u.passwordSet
}
// String returns the encoded userinfo information in the standard form
@@ -420,7 +438,7 @@ func Parse(rawurl string) (*URL, error) {
u, frag := split(rawurl, "#", true)
url, err := parse(u, false)
if err != nil {
- return nil, err
+ return nil, &Error{"parse", u, err}
}
if frag == "" {
return url, nil
@@ -437,31 +455,35 @@ func Parse(rawurl string) (*URL, error) {
// The string rawurl is assumed not to have a #fragment suffix.
// (Web browsers strip #fragment before sending the URL to a web server.)
func ParseRequestURI(rawurl string) (*URL, error) {
- return parse(rawurl, true)
+ url, err := parse(rawurl, true)
+ if err != nil {
+ return nil, &Error{"parse", rawurl, err}
+ }
+ return url, nil
}
// parse parses a URL from a string in one of two contexts. If
// viaRequest is true, the URL is assumed to have arrived via an HTTP request,
// in which case only absolute URLs or path-absolute relative URLs are allowed.
// If viaRequest is false, all forms of relative URLs are allowed.
-func parse(rawurl string, viaRequest bool) (url *URL, err error) {
+func parse(rawurl string, viaRequest bool) (*URL, error) {
var rest string
+ var err error
if rawurl == "" && viaRequest {
- err = errors.New("empty url")
- goto Error
+ return nil, errors.New("empty url")
}
- url = new(URL)
+ url := new(URL)
if rawurl == "*" {
url.Path = "*"
- return
+ return url, nil
}
// Split off possible leading "http:", "mailto:", etc.
// Cannot contain escaped characters.
if url.Scheme, rest, err = getscheme(rawurl); err != nil {
- goto Error
+ return nil, err
}
url.Scheme = strings.ToLower(url.Scheme)
@@ -479,8 +501,20 @@ func parse(rawurl string, viaRequest bool) (url *URL, err error) {
return url, nil
}
if viaRequest {
- err = errors.New("invalid URI for request")
- goto Error
+ return nil, errors.New("invalid URI for request")
+ }
+
+ // Avoid confusion with malformed schemes, like cache_object:foo/bar.
+ // See golang.org/issue/16822.
+ //
+ // RFC 3986, §3.3:
+ // In addition, a URI reference (Section 4.1) may be a relative-path reference,
+ // in which case the first path segment cannot contain a colon (":") character.
+ colon := strings.Index(rest, ":")
+ slash := strings.Index(rest, "/")
+ if colon >= 0 && (slash < 0 || colon < slash) {
+ // First path segment has colon. Not allowed in relative URL.
+ return nil, errors.New("first path segment in URL cannot contain colon")
}
}
@@ -489,23 +523,17 @@ func parse(rawurl string, viaRequest bool) (url *URL, err error) {
authority, rest = split(rest[2:], "/", false)
url.User, url.Host, err = parseAuthority(authority)
if err != nil {
- goto Error
+ return nil, err
}
}
- if url.Path, err = unescape(rest, encodePath); err != nil {
- goto Error
- }
- // RawPath is a hint as to the encoding of Path to use
- // in url.EscapedPath. If that method already gets the
- // right answer without RawPath, leave it empty.
- // This will help make sure that people don't rely on it in general.
- if url.EscapedPath() != rest && validEncodedPath(rest) {
- url.RawPath = rest
+ // Set Path and, optionally, RawPath.
+ // RawPath is a hint of the encoding of Path. We don't want to set it if
+ // the default escaping of Path is equivalent, to help make sure that people
+ // don't rely on it in general.
+ if err := url.setPath(rest); err != nil {
+ return nil, err
}
return url, nil
-
-Error:
- return nil, &Error{"parse", rawurl, err}
}
func parseAuthority(authority string) (user *Userinfo, host string, err error) {
@@ -586,6 +614,29 @@ func parseHost(host string) (string, error) {
return host, nil
}
+// setPath sets the Path and RawPath fields of the URL based on the provided
+// escaped path p. It maintains the invariant that RawPath is only specified
+// when it differs from the default encoding of the path.
+// For example:
+// - setPath("/foo/bar") will set Path="/foo/bar" and RawPath=""
+// - setPath("/foo%2fbar") will set Path="/foo/bar" and RawPath="/foo%2fbar"
+// setPath will return an error only if the provided path contains an invalid
+// escaping.
+func (u *URL) setPath(p string) error {
+ path, err := unescape(p, encodePath)
+ if err != nil {
+ return err
+ }
+ u.Path = path
+ if escp := escape(path, encodePath); p == escp {
+ // Default encoding is fine.
+ u.RawPath = ""
+ } else {
+ u.RawPath = p
+ }
+ return nil
+}
+
// EscapedPath returns the escaped form of u.Path.
// In general there are multiple possible escaped forms of any path.
// EscapedPath returns u.RawPath when it is a valid escaping of u.Path.
@@ -693,6 +744,17 @@ func (u *URL) String() string {
if path != "" && path[0] != '/' && u.Host != "" {
buf.WriteByte('/')
}
+ if buf.Len() == 0 {
+ // RFC 3986 §4.2
+ // A path segment that contains a colon character (e.g., "this:that")
+ // cannot be used as the first segment of a relative-path reference, as
+ // it would be mistaken for a scheme name. Such a segment must be
+ // preceded by a dot-segment (e.g., "./this:that") to make a relative-
+ // path reference.
+ if i := strings.IndexByte(path, ':'); i > -1 && strings.IndexByte(path[:i], '/') == -1 {
+ buf.WriteString("./")
+ }
+ }
buf.WriteString(path)
}
if u.ForceQuery || u.RawQuery != "" {
@@ -749,6 +811,10 @@ func (v Values) Del(key string) {
// ParseQuery always returns a non-nil map containing all the
// valid query parameters found; err describes the first decoding error
// encountered, if any.
+//
+// Query is expected to be a list of key=value settings separated by
+// ampersands or semicolons. A setting without an equals sign is
+// interpreted as a key set to an empty value.
func ParseQuery(query string) (Values, error) {
m := make(Values)
err := parseQuery(m, query)
@@ -852,6 +918,7 @@ func resolvePath(base, ref string) string {
}
// IsAbs reports whether the URL is absolute.
+// Absolute means that it has a non-empty scheme.
func (u *URL) IsAbs() bool {
return u.Scheme != ""
}
@@ -880,7 +947,9 @@ func (u *URL) ResolveReference(ref *URL) *URL {
}
if ref.Scheme != "" || ref.Host != "" || ref.User != nil {
// The "absoluteURI" or "net_path" cases.
- url.Path = resolvePath(ref.Path, "")
+ // We can ignore the error from setPath since we know we provided a
+ // validly-escaped path.
+ url.setPath(resolvePath(ref.EscapedPath(), ""))
return &url
}
if ref.Opaque != "" {
@@ -900,7 +969,7 @@ func (u *URL) ResolveReference(ref *URL) *URL {
// The "abs_path" or "rel_path" cases.
url.Host = u.Host
url.User = u.User
- url.Path = resolvePath(u.Path, ref.Path)
+ url.setPath(resolvePath(u.EscapedPath(), ref.EscapedPath()))
return &url
}
@@ -929,3 +998,59 @@ func (u *URL) RequestURI() string {
}
return result
}
+
+// Hostname returns u.Host, without any port number.
+//
+// If Host is an IPv6 literal with a port number, Hostname returns the
+// IPv6 literal without the square brackets. IPv6 literals may include
+// a zone identifier.
+func (u *URL) Hostname() string {
+ return stripPort(u.Host)
+}
+
+// Port returns the port part of u.Host, without the leading colon.
+// If u.Host doesn't contain a port, Port returns an empty string.
+func (u *URL) Port() string {
+ return portOnly(u.Host)
+}
+
+func stripPort(hostport string) string {
+ colon := strings.IndexByte(hostport, ':')
+ if colon == -1 {
+ return hostport
+ }
+ if i := strings.IndexByte(hostport, ']'); i != -1 {
+ return strings.TrimPrefix(hostport[:i], "[")
+ }
+ return hostport[:colon]
+}
+
+func portOnly(hostport string) string {
+ colon := strings.IndexByte(hostport, ':')
+ if colon == -1 {
+ return ""
+ }
+ if i := strings.Index(hostport, "]:"); i != -1 {
+ return hostport[i+len("]:"):]
+ }
+ if strings.Contains(hostport, "]") {
+ return ""
+ }
+ return hostport[colon+len(":"):]
+}
+
+// Marshaling interface implementations.
+// Would like to implement MarshalText/UnmarshalText but that will change the JSON representation of URLs.
+
+func (u *URL) MarshalBinary() (text []byte, err error) {
+ return []byte(u.String()), nil
+}
+
+func (u *URL) UnmarshalBinary(text []byte) error {
+ u1, err := Parse(string(text))
+ if err != nil {
+ return err
+ }
+ *u = *u1
+ return nil
+}
diff --git a/src/net/url/url_test.go b/src/net/url/url_test.go
index 7560f22..6c3bb21 100644
--- a/src/net/url/url_test.go
+++ b/src/net/url/url_test.go
@@ -5,6 +5,10 @@
package url
import (
+ "bytes"
+ encodingPkg "encoding"
+ "encoding/gob"
+ "encoding/json"
"fmt"
"io"
"net"
@@ -579,20 +583,6 @@ func ufmt(u *URL) string {
u.Opaque, u.Scheme, user, pass, u.Host, u.Path, u.RawPath, u.RawQuery, u.Fragment, u.ForceQuery)
}
-func DoTest(t *testing.T, parse func(string) (*URL, error), name string, tests []URLTest) {
- for _, tt := range tests {
- u, err := parse(tt.in)
- if err != nil {
- t.Errorf("%s(%q) returned error %s", name, tt.in, err)
- continue
- }
- if !reflect.DeepEqual(u, tt.out) {
- t.Errorf("%s(%q):\n\thave %v\n\twant %v\n",
- name, tt.in, ufmt(u), ufmt(tt.out))
- }
- }
-}
-
func BenchmarkString(b *testing.B) {
b.StopTimer()
b.ReportAllocs()
@@ -618,7 +608,16 @@ func BenchmarkString(b *testing.B) {
}
func TestParse(t *testing.T) {
- DoTest(t, Parse, "Parse", urltests)
+ for _, tt := range urltests {
+ u, err := Parse(tt.in)
+ if err != nil {
+ t.Errorf("Parse(%q) returned error %v", tt.in, err)
+ continue
+ }
+ if !reflect.DeepEqual(u, tt.out) {
+ t.Errorf("Parse(%q):\n\tgot %v\n\twant %v\n", tt.in, ufmt(u), ufmt(tt.out))
+ }
+ }
}
const pathThatLooksSchemeRelative = "//not.a.user at not.a.host/just/a/path"
@@ -665,9 +664,10 @@ var parseRequestURLTests = []struct {
func TestParseRequestURI(t *testing.T) {
for _, test := range parseRequestURLTests {
_, err := ParseRequestURI(test.url)
- valid := err == nil
- if valid != test.expectedValid {
- t.Errorf("Expected valid=%v for %q; got %v", test.expectedValid, test.url, valid)
+ if test.expectedValid && err != nil {
+ t.Errorf("ParseRequestURI(%q) gave err %v; want no error", test.url, err)
+ } else if !test.expectedValid && err == nil {
+ t.Errorf("ParseRequestURI(%q) gave nil error; want some error", test.url)
}
}
@@ -676,45 +676,69 @@ func TestParseRequestURI(t *testing.T) {
t.Fatalf("Unexpected error %v", err)
}
if url.Path != pathThatLooksSchemeRelative {
- t.Errorf("Expected path %q; got %q", pathThatLooksSchemeRelative, url.Path)
+ t.Errorf("ParseRequestURI path:\ngot %q\nwant %q", url.Path, pathThatLooksSchemeRelative)
}
}
-func DoTestString(t *testing.T, parse func(string) (*URL, error), name string, tests []URLTest) {
- for _, tt := range tests {
- u, err := parse(tt.in)
+var stringURLTests = []struct {
+ url URL
+ want string
+}{
+ // No leading slash on path should prepend slash on String() call
+ {
+ url: URL{
+ Scheme: "http",
+ Host: "www.google.com",
+ Path: "search",
+ },
+ want: "http://www.google.com/search",
+ },
+ // Relative path with first element containing ":" should be prepended with "./", golang.org/issue/17184
+ {
+ url: URL{
+ Path: "this:that",
+ },
+ want: "./this:that",
+ },
+ // Relative path with second element containing ":" should not be prepended with "./"
+ {
+ url: URL{
+ Path: "here/this:that",
+ },
+ want: "here/this:that",
+ },
+ // Non-relative path with first element containing ":" should not be prepended with "./"
+ {
+ url: URL{
+ Scheme: "http",
+ Host: "www.google.com",
+ Path: "this:that",
+ },
+ want: "http://www.google.com/this:that",
+ },
+}
+
+func TestURLString(t *testing.T) {
+ for _, tt := range urltests {
+ u, err := Parse(tt.in)
if err != nil {
- t.Errorf("%s(%q) returned error %s", name, tt.in, err)
+ t.Errorf("Parse(%q) returned error %s", tt.in, err)
continue
}
expected := tt.in
- if len(tt.roundtrip) > 0 {
+ if tt.roundtrip != "" {
expected = tt.roundtrip
}
s := u.String()
if s != expected {
- t.Errorf("%s(%q).String() == %q (expected %q)", name, tt.in, s, expected)
+ t.Errorf("Parse(%q).String() == %q (expected %q)", tt.in, s, expected)
}
}
-}
-func TestURLString(t *testing.T) {
- DoTestString(t, Parse, "Parse", urltests)
-
- // no leading slash on path should prepend
- // slash on String() call
- noslash := URLTest{
- "http://www.google.com/search",
- &URL{
- Scheme: "http",
- Host: "www.google.com",
- Path: "search",
- },
- "",
- }
- s := noslash.out.String()
- if s != noslash.in {
- t.Errorf("Expected %s; go %s", noslash.in, s)
+ for _, tt := range stringURLTests {
+ if got := tt.url.String(); got != tt.want {
+ t.Errorf("%+v.String() = %q; want %q", tt.url, got, tt.want)
+ }
}
}
@@ -780,6 +804,16 @@ var unescapeTests = []EscapeTest{
"",
EscapeError("%zz"),
},
+ {
+ "a+b",
+ "a b",
+ nil,
+ },
+ {
+ "a%20b",
+ "a b",
+ nil,
+ },
}
func TestUnescape(t *testing.T) {
@@ -788,10 +822,33 @@ func TestUnescape(t *testing.T) {
if actual != tt.out || (err != nil) != (tt.err != nil) {
t.Errorf("QueryUnescape(%q) = %q, %s; want %q, %s", tt.in, actual, err, tt.out, tt.err)
}
+
+ in := tt.in
+ out := tt.out
+ if strings.Contains(tt.in, "+") {
+ in = strings.Replace(tt.in, "+", "%20", -1)
+ actual, err := PathUnescape(in)
+ if actual != tt.out || (err != nil) != (tt.err != nil) {
+ t.Errorf("PathUnescape(%q) = %q, %s; want %q, %s", in, actual, err, tt.out, tt.err)
+ }
+ if tt.err == nil {
+ s, err := QueryUnescape(strings.Replace(tt.in, "+", "XXX", -1))
+ if err != nil {
+ continue
+ }
+ in = tt.in
+ out = strings.Replace(s, "XXX", "+", -1)
+ }
+ }
+
+ actual, err = PathUnescape(in)
+ if actual != out || (err != nil) != (tt.err != nil) {
+ t.Errorf("PathUnescape(%q) = %q, %s; want %q, %s", in, actual, err, out, tt.err)
+ }
}
}
-var escapeTests = []EscapeTest{
+var queryEscapeTests = []EscapeTest{
{
"",
"",
@@ -819,8 +876,8 @@ var escapeTests = []EscapeTest{
},
}
-func TestEscape(t *testing.T) {
- for _, tt := range escapeTests {
+func TestQueryEscape(t *testing.T) {
+ for _, tt := range queryEscapeTests {
actual := QueryEscape(tt.in)
if tt.out != actual {
t.Errorf("QueryEscape(%q) = %q, want %q", tt.in, actual, tt.out)
@@ -834,6 +891,54 @@ func TestEscape(t *testing.T) {
}
}
+var pathEscapeTests = []EscapeTest{
+ {
+ "",
+ "",
+ nil,
+ },
+ {
+ "abc",
+ "abc",
+ nil,
+ },
+ {
+ "abc+def",
+ "abc+def",
+ nil,
+ },
+ {
+ "one two",
+ "one%20two",
+ nil,
+ },
+ {
+ "10%",
+ "10%25",
+ nil,
+ },
+ {
+ " ?&=#+%!<>#\"{}|\\^[]`☺\t:/@$'()*,;",
+ "%20%3F&=%23+%25%21%3C%3E%23%22%7B%7D%7C%5C%5E%5B%5D%60%E2%98%BA%09:%2F@$%27%28%29%2A%2C%3B",
+ nil,
+ },
+}
+
+func TestPathEscape(t *testing.T) {
+ for _, tt := range pathEscapeTests {
+ actual := PathEscape(tt.in)
+ if tt.out != actual {
+ t.Errorf("PathEscape(%q) = %q, want %q", tt.in, actual, tt.out)
+ }
+
+ // for bonus points, verify that escape:unescape is an identity.
+ roundtrip, err := PathUnescape(actual)
+ if roundtrip != tt.in || err != nil {
+ t.Errorf("PathUnescape(%q) = %q, %s; want %q, %s", actual, roundtrip, err, tt.in, "[no error]")
+ }
+ }
+}
+
//var userinfoTests = []UserinfoTest{
// {"user", "password", "user:password"},
// {"foo:bar", "~!@#$%^&*()_+{}|[]\\-=`:;'\"<>?,./",
@@ -945,6 +1050,15 @@ var resolveReferenceTests = []struct {
// Fragment
{"http://foo.com/bar", ".#frag", "http://foo.com/#frag"},
+ // Paths with escaping (issue 16947).
+ {"http://foo.com/foo%2fbar/", "../baz", "http://foo.com/baz"},
+ {"http://foo.com/1/2%2f/3%2f4/5", "../../a/b/c", "http://foo.com/1/a/b/c"},
+ {"http://foo.com/1/2/3", "./a%2f../../b/..%2fc", "http://foo.com/1/2/b/..%2fc"},
+ {"http://foo.com/1/2%2f/3%2f4/5", "./a%2f../b/../c", "http://foo.com/1/2%2f/3%2f4/a%2f../c"},
+ {"http://foo.com/foo%20bar/", "../baz", "http://foo.com/baz"},
+ {"http://foo.com/foo", "../bar%2fbaz", "http://foo.com/bar%2fbaz"},
+ {"http://foo.com/foo%2dbar/", "./baz-quux", "http://foo.com/foo%2dbar/baz-quux"},
+
// RFC 3986: Normal Examples
// http://tools.ietf.org/html/rfc3986#section-5.4.1
{"http://a/b/c/d;p?q", "g:h", "g:h"},
@@ -1004,7 +1118,7 @@ func TestResolveReference(t *testing.T) {
mustParse := func(url string) *URL {
u, err := Parse(url)
if err != nil {
- t.Fatalf("Expected URL to parse: %q, got error: %v", url, err)
+ t.Fatalf("Parse(%q) got err %v", url, err)
}
return u
}
@@ -1013,8 +1127,8 @@ func TestResolveReference(t *testing.T) {
base := mustParse(test.base)
rel := mustParse(test.rel)
url := base.ResolveReference(rel)
- if url.String() != test.expected {
- t.Errorf("URL(%q).ResolveReference(%q) == %q, got %q", test.base, test.rel, test.expected, url.String())
+ if got := url.String(); got != test.expected {
+ t.Errorf("URL(%q).ResolveReference(%q)\ngot %q\nwant %q", test.base, test.rel, got, test.expected)
}
// Ensure that new instances are returned.
if base == url {
@@ -1024,8 +1138,8 @@ func TestResolveReference(t *testing.T) {
url, err := base.Parse(test.rel)
if err != nil {
t.Errorf("URL(%q).Parse(%q) failed: %v", test.base, test.rel, err)
- } else if url.String() != test.expected {
- t.Errorf("URL(%q).Parse(%q) == %q, got %q", test.base, test.rel, test.expected, url.String())
+ } else if got := url.String(); got != test.expected {
+ t.Errorf("URL(%q).Parse(%q)\ngot %q\nwant %q", test.base, test.rel, got, test.expected)
} else if base == url {
// Ensure that new instances are returned for the wrapper too.
t.Errorf("Expected URL.Parse to return new URL instance.")
@@ -1033,14 +1147,14 @@ func TestResolveReference(t *testing.T) {
// Ensure Opaque resets the URL.
url = base.ResolveReference(opaque)
if *url != *opaque {
- t.Errorf("ResolveReference failed to resolve opaque URL: want %#v, got %#v", url, opaque)
+ t.Errorf("ResolveReference failed to resolve opaque URL:\ngot %#v\nwant %#v", url, opaque)
}
// Test the convenience wrapper with an opaque URL too.
url, err = base.Parse("scheme:opaque")
if err != nil {
t.Errorf(`URL(%q).Parse("scheme:opaque") failed: %v`, test.base, err)
} else if *url != *opaque {
- t.Errorf("Parse failed to resolve opaque URL: want %#v, got %#v", url, opaque)
+ t.Errorf("Parse failed to resolve opaque URL:\ngot %#v\nwant %#v", opaque, url)
} else if base == url {
// Ensure that new instances are returned, again.
t.Errorf("Expected URL.Parse to return new URL instance.")
@@ -1271,7 +1385,7 @@ func TestParseFailure(t *testing.T) {
}
}
-func TestParseAuthority(t *testing.T) {
+func TestParseErrors(t *testing.T) {
tests := []struct {
in string
wantErr bool
@@ -1291,9 +1405,13 @@ func TestParseAuthority(t *testing.T) {
{"http://%41:8080/", true}, // not allowed: % encoding only for non-ASCII
{"mysql://x@y(z:123)/foo", false}, // golang.org/issue/12023
{"mysql://x@y(1.2.3.4:123)/foo", false},
- {"mysql://x@y([2001:db8::1]:123)/foo", false},
+
{"http://[]%20%48%54%54%50%2f%31%2e%31%0a%4d%79%48%65%61%64%65%72%3a%20%31%32%33%0a%0a/", true}, // golang.org/issue/11208
{"http://a b.com/", true}, // no space in host name please
+ {"cache_object://foo", true}, // scheme cannot have _, relative path cannot have : in first segment
+ {"cache_object:foo", true},
+ {"cache_object:foo/bar", true},
+ {"cache_object/:foo/bar", false},
}
for _, tt := range tests {
u, err := Parse(tt.in)
@@ -1462,11 +1580,106 @@ func TestURLErrorImplementsNetError(t *testing.T) {
continue
}
if err.Timeout() != tt.timeout {
- t.Errorf("%d: err.Timeout(): want %v, have %v", i+1, tt.timeout, err.Timeout())
+ t.Errorf("%d: err.Timeout(): got %v, want %v", i+1, err.Timeout(), tt.timeout)
continue
}
if err.Temporary() != tt.temporary {
- t.Errorf("%d: err.Temporary(): want %v, have %v", i+1, tt.temporary, err.Temporary())
+ t.Errorf("%d: err.Temporary(): got %v, want %v", i+1, err.Temporary(), tt.temporary)
+ }
+ }
+}
+
+func TestURLHostname(t *testing.T) {
+ tests := []struct {
+ host string // URL.Host field
+ want string
+ }{
+ {"foo.com:80", "foo.com"},
+ {"foo.com", "foo.com"},
+ {"FOO.COM", "FOO.COM"}, // no canonicalization (yet?)
+ {"1.2.3.4", "1.2.3.4"},
+ {"1.2.3.4:80", "1.2.3.4"},
+ {"[1:2:3:4]", "1:2:3:4"},
+ {"[1:2:3:4]:80", "1:2:3:4"},
+ {"[::1]:80", "::1"},
+ }
+ for _, tt := range tests {
+ u := &URL{Host: tt.host}
+ got := u.Hostname()
+ if got != tt.want {
+ t.Errorf("Hostname for Host %q = %q; want %q", tt.host, got, tt.want)
+ }
+ }
+}
+
+func TestURLPort(t *testing.T) {
+ tests := []struct {
+ host string // URL.Host field
+ want string
+ }{
+ {"foo.com", ""},
+ {"foo.com:80", "80"},
+ {"1.2.3.4", ""},
+ {"1.2.3.4:80", "80"},
+ {"[1:2:3:4]", ""},
+ {"[1:2:3:4]:80", "80"},
+ }
+ for _, tt := range tests {
+ u := &URL{Host: tt.host}
+ got := u.Port()
+ if got != tt.want {
+ t.Errorf("Port for Host %q = %q; want %q", tt.host, got, tt.want)
}
}
}
+
+var _ encodingPkg.BinaryMarshaler = (*URL)(nil)
+var _ encodingPkg.BinaryUnmarshaler = (*URL)(nil)
+
+func TestJSON(t *testing.T) {
+ u, err := Parse("https://www.google.com/x?y=z")
+ if err != nil {
+ t.Fatal(err)
+ }
+ js, err := json.Marshal(u)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // If only we could implement TextMarshaler/TextUnmarshaler,
+ // this would work:
+ //
+ // if string(js) != strconv.Quote(u.String()) {
+ // t.Errorf("json encoding: %s\nwant: %s\n", js, strconv.Quote(u.String()))
+ // }
+
+ u1 := new(URL)
+ err = json.Unmarshal(js, u1)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if u1.String() != u.String() {
+ t.Errorf("json decoded to: %s\nwant: %s\n", u1, u)
+ }
+}
+
+func TestGob(t *testing.T) {
+ u, err := Parse("https://www.google.com/x?y=z")
+ if err != nil {
+ t.Fatal(err)
+ }
+ var w bytes.Buffer
+ err = gob.NewEncoder(&w).Encode(u)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ u1 := new(URL)
+ err = gob.NewDecoder(&w).Decode(u1)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if u1.String() != u.String() {
+ t.Errorf("json decoded to: %s\nwant: %s\n", u1, u)
+ }
+}
diff --git a/src/net/writev_test.go b/src/net/writev_test.go
new file mode 100644
index 0000000..4d2fc39
--- /dev/null
+++ b/src/net/writev_test.go
@@ -0,0 +1,225 @@
+// Copyright 2016 The Go Authors. 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 (
+ "bytes"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "reflect"
+ "runtime"
+ "sync"
+ "testing"
+)
+
+func TestBuffers_read(t *testing.T) {
+ const story = "once upon a time in Gopherland ... "
+ buffers := Buffers{
+ []byte("once "),
+ []byte("upon "),
+ []byte("a "),
+ []byte("time "),
+ []byte("in "),
+ []byte("Gopherland ... "),
+ }
+ got, err := ioutil.ReadAll(&buffers)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if string(got) != story {
+ t.Errorf("read %q; want %q", got, story)
+ }
+ if len(buffers) != 0 {
+ t.Errorf("len(buffers) = %d; want 0", len(buffers))
+ }
+}
+
+func TestBuffers_consume(t *testing.T) {
+ tests := []struct {
+ in Buffers
+ consume int64
+ want Buffers
+ }{
+ {
+ in: Buffers{[]byte("foo"), []byte("bar")},
+ consume: 0,
+ want: Buffers{[]byte("foo"), []byte("bar")},
+ },
+ {
+ in: Buffers{[]byte("foo"), []byte("bar")},
+ consume: 2,
+ want: Buffers{[]byte("o"), []byte("bar")},
+ },
+ {
+ in: Buffers{[]byte("foo"), []byte("bar")},
+ consume: 3,
+ want: Buffers{[]byte("bar")},
+ },
+ {
+ in: Buffers{[]byte("foo"), []byte("bar")},
+ consume: 4,
+ want: Buffers{[]byte("ar")},
+ },
+ {
+ in: Buffers{nil, nil, nil, []byte("bar")},
+ consume: 1,
+ want: Buffers{[]byte("ar")},
+ },
+ {
+ in: Buffers{nil, nil, nil, []byte("foo")},
+ consume: 0,
+ want: Buffers{[]byte("foo")},
+ },
+ {
+ in: Buffers{nil, nil, nil},
+ consume: 0,
+ want: Buffers{},
+ },
+ }
+ for i, tt := range tests {
+ in := tt.in
+ in.consume(tt.consume)
+ if !reflect.DeepEqual(in, tt.want) {
+ t.Errorf("%d. after consume(%d) = %+v, want %+v", i, tt.consume, in, tt.want)
+ }
+ }
+}
+
+func TestBuffers_WriteTo(t *testing.T) {
+ for _, name := range []string{"WriteTo", "Copy"} {
+ for _, size := range []int{0, 10, 1023, 1024, 1025} {
+ t.Run(fmt.Sprintf("%s/%d", name, size), func(t *testing.T) {
+ testBuffer_writeTo(t, size, name == "Copy")
+ })
+ }
+ }
+}
+
+func testBuffer_writeTo(t *testing.T, chunks int, useCopy bool) {
+ oldHook := testHookDidWritev
+ defer func() { testHookDidWritev = oldHook }()
+ var writeLog struct {
+ sync.Mutex
+ log []int
+ }
+ testHookDidWritev = func(size int) {
+ writeLog.Lock()
+ writeLog.log = append(writeLog.log, size)
+ writeLog.Unlock()
+ }
+ var want bytes.Buffer
+ for i := 0; i < chunks; i++ {
+ want.WriteByte(byte(i))
+ }
+
+ withTCPConnPair(t, func(c *TCPConn) error {
+ buffers := make(Buffers, chunks)
+ for i := range buffers {
+ buffers[i] = want.Bytes()[i : i+1]
+ }
+ var n int64
+ var err error
+ if useCopy {
+ n, err = io.Copy(c, &buffers)
+ } else {
+ n, err = buffers.WriteTo(c)
+ }
+ if err != nil {
+ return err
+ }
+ if len(buffers) != 0 {
+ return fmt.Errorf("len(buffers) = %d; want 0", len(buffers))
+ }
+ if n != int64(want.Len()) {
+ return fmt.Errorf("Buffers.WriteTo returned %d; want %d", n, want.Len())
+ }
+ return nil
+ }, func(c *TCPConn) error {
+ all, err := ioutil.ReadAll(c)
+ if !bytes.Equal(all, want.Bytes()) || err != nil {
+ return fmt.Errorf("client read %q, %v; want %q, nil", all, err, want.Bytes())
+ }
+
+ writeLog.Lock() // no need to unlock
+ var gotSum int
+ for _, v := range writeLog.log {
+ gotSum += v
+ }
+
+ var wantSum int
+ switch runtime.GOOS {
+ case "darwin", "dragonfly", "freebsd", "linux", "netbsd", "openbsd":
+ var wantMinCalls int
+ wantSum = want.Len()
+ v := chunks
+ for v > 0 {
+ wantMinCalls++
+ v -= 1024
+ }
+ if len(writeLog.log) < wantMinCalls {
+ t.Errorf("write calls = %v < wanted min %v", len(writeLog.log), wantMinCalls)
+ }
+ case "windows":
+ var wantCalls int
+ wantSum = want.Len()
+ if wantSum > 0 {
+ wantCalls = 1 // windows will always do 1 syscall, unless sending empty buffer
+ }
+ if len(writeLog.log) != wantCalls {
+ t.Errorf("write calls = %v; want %v", len(writeLog.log), wantCalls)
+ }
+ }
+ if gotSum != wantSum {
+ t.Errorf("writev call sum = %v; want %v", gotSum, wantSum)
+ }
+ return nil
+ })
+}
+
+func TestWritevError(t *testing.T) {
+ if runtime.GOOS == "windows" {
+ t.Skipf("skipping the test: windows does not have problem sending large chunks of data")
+ }
+
+ ln, err := newLocalListener("tcp")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer ln.Close()
+
+ ch := make(chan Conn, 1)
+ go func() {
+ defer close(ch)
+ c, err := ln.Accept()
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ ch <- c
+ }()
+ c1, err := Dial("tcp", ln.Addr().String())
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer c1.Close()
+ c2 := <-ch
+ if c2 == nil {
+ t.Fatal("no server side connection")
+ }
+ c2.Close()
+
+ // 1 GB of data should be enough to notice the connection is gone.
+ // Just a few bytes is not enough.
+ // Arrange to reuse the same 1 MB buffer so that we don't allocate much.
+ buf := make([]byte, 1<<20)
+ buffers := make(Buffers, 1<<10)
+ for i := range buffers {
+ buffers[i] = buf
+ }
+ if _, err := buffers.WriteTo(c1); err == nil {
+ t.Fatal("Buffers.WriteTo(closed conn) succeeded, want error")
+ }
+}
diff --git a/src/net/writev_unix.go b/src/net/writev_unix.go
new file mode 100644
index 0000000..174e6bc
--- /dev/null
+++ b/src/net/writev_unix.go
@@ -0,0 +1,95 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build darwin dragonfly freebsd linux netbsd openbsd
+
+package net
+
+import (
+ "io"
+ "os"
+ "syscall"
+ "unsafe"
+)
+
+func (c *conn) writeBuffers(v *Buffers) (int64, error) {
+ if !c.ok() {
+ return 0, syscall.EINVAL
+ }
+ n, err := c.fd.writeBuffers(v)
+ if err != nil {
+ return n, &OpError{Op: "writev", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
+ }
+ return n, nil
+}
+
+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
+}
diff --git a/src/os/dir.go b/src/os/dir.go
new file mode 100644
index 0000000..6c54456
--- /dev/null
+++ b/src/os/dir.go
@@ -0,0 +1,46 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package os
+
+// Readdir reads the contents of the directory associated with file and
+// returns a slice of up to n FileInfo values, as would be returned
+// by Lstat, in directory order. Subsequent calls on the same file will yield
+// further FileInfos.
+//
+// If n > 0, Readdir returns at most n FileInfo structures. In this case, if
+// Readdir returns an empty slice, it will return a non-nil error
+// explaining why. At the end of a directory, the error is io.EOF.
+//
+// If n <= 0, Readdir returns all the FileInfo from the directory in
+// a single slice. In this case, if Readdir succeeds (reads all
+// the way to the end of the directory), it returns the slice and a
+// nil error. If it encounters an error before the end of the
+// directory, Readdir returns the FileInfo read until that point
+// and a non-nil error.
+func (f *File) Readdir(n int) ([]FileInfo, error) {
+ if f == nil {
+ return nil, ErrInvalid
+ }
+ return f.readdir(n)
+}
+
+// Readdirnames reads and returns a slice of names from the directory f.
+//
+// If n > 0, Readdirnames returns at most n names. In this case, if
+// Readdirnames returns an empty slice, it will return a non-nil error
+// explaining why. At the end of a directory, the error is io.EOF.
+//
+// If n <= 0, Readdirnames returns all the names from the directory in
+// a single slice. In this case, if Readdirnames succeeds (reads all
+// the way to the end of the directory), it returns the slice and a
+// nil error. If it encounters an error before the end of the
+// directory, Readdirnames returns the names read until that point and
+// a non-nil error.
+func (f *File) Readdirnames(n int) (names []string, err error) {
+ if f == nil {
+ return nil, ErrInvalid
+ }
+ return f.readdirnames(n)
+}
diff --git a/src/os/dir_unix.go b/src/os/dir_unix.go
index 589db85..03d949a 100644
--- a/src/os/dir_unix.go
+++ b/src/os/dir_unix.go
@@ -15,6 +15,33 @@ const (
blockSize = 4096
)
+func (f *File) readdir(n int) (fi []FileInfo, err error) {
+ dirname := f.name
+ if dirname == "" {
+ dirname = "."
+ }
+ names, err := f.Readdirnames(n)
+ fi = make([]FileInfo, 0, len(names))
+ for _, filename := range names {
+ fip, lerr := lstat(dirname + "/" + filename)
+ if IsNotExist(lerr) {
+ // File disappeared between readdir + stat.
+ // Just treat it as if it didn't exist.
+ continue
+ }
+ if lerr != nil {
+ return fi, lerr
+ }
+ fi = append(fi, fip)
+ }
+ if len(fi) == 0 && err == nil && n > 0 {
+ // Per File.Readdir, the slice must be non-empty or err
+ // must be non-nil if n > 0.
+ err = io.EOF
+ }
+ return fi, err
+}
+
func (f *File) readdirnames(n int) (names []string, err error) {
// If this file has no dirinfo, create one.
if f.dirinfo == nil {
diff --git a/src/os/dir_windows.go b/src/os/dir_windows.go
index 9313160..76024fc 100644
--- a/src/os/dir_windows.go
+++ b/src/os/dir_windows.go
@@ -4,6 +4,70 @@
package os
+import (
+ "io"
+ "syscall"
+)
+
+func (file *File) readdir(n int) (fi []FileInfo, err error) {
+ if file == nil {
+ return nil, syscall.EINVAL
+ }
+ 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 {
+ n = -1
+ size = 100
+ }
+ fi = make([]FileInfo, 0, size) // Empty with room to grow.
+ d := &file.dirinfo.data
+ for n != 0 && !file.dirinfo.isempty {
+ if file.dirinfo.needdata {
+ e := syscall.FindNextFile(file.fd, d)
+ if e != nil {
+ if e == syscall.ERROR_NO_MORE_FILES {
+ break
+ } else {
+ err = &PathError{"FindNextFile", file.name, e}
+ if !wantAll {
+ fi = nil
+ }
+ return
+ }
+ }
+ }
+ file.dirinfo.needdata = true
+ name := syscall.UTF16ToString(d.FileName[0:])
+ if name == "." || name == ".." { // Useless names
+ continue
+ }
+ f := &fileStat{
+ name: name,
+ sys: syscall.Win32FileAttributeData{
+ FileAttributes: d.FileAttributes,
+ CreationTime: d.CreationTime,
+ LastAccessTime: d.LastAccessTime,
+ LastWriteTime: d.LastWriteTime,
+ FileSizeHigh: d.FileSizeHigh,
+ FileSizeLow: d.FileSizeLow,
+ },
+ path: file.dirinfo.path + `\` + name,
+ }
+ n--
+ fi = append(fi, f)
+ }
+ if !wantAll && len(fi) == 0 {
+ return fi, io.EOF
+ }
+ return fi, nil
+}
+
func (file *File) readdirnames(n int) (names []string, err error) {
fis, err := file.Readdir(n)
names = make([]string, len(fis))
diff --git a/src/os/doc.go b/src/os/doc.go
deleted file mode 100644
index 0313eac..0000000
--- a/src/os/doc.go
+++ /dev/null
@@ -1,139 +0,0 @@
-// Copyright 2012 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package os
-
-import "time"
-
-// FindProcess looks for a running process by its pid.
-//
-// The Process it returns can be used to obtain information
-// about the underlying operating system process.
-//
-// On Unix systems, FindProcess always succeeds and returns a Process
-// for the given pid, regardless of whether the process exists.
-func FindProcess(pid int) (*Process, error) {
- return findProcess(pid)
-}
-
-// StartProcess starts a new process with the program, arguments and attributes
-// specified by name, argv and attr.
-//
-// StartProcess is a low-level interface. The os/exec package provides
-// higher-level interfaces.
-//
-// If there is an error, it will be of type *PathError.
-func StartProcess(name string, argv []string, attr *ProcAttr) (*Process, error) {
- return startProcess(name, argv, attr)
-}
-
-// Release releases any resources associated with the Process p,
-// rendering it unusable in the future.
-// Release only needs to be called if Wait is not.
-func (p *Process) Release() error {
- return p.release()
-}
-
-// Kill causes the Process to exit immediately.
-func (p *Process) Kill() error {
- return p.kill()
-}
-
-// Wait waits for the Process to exit, and then returns a
-// ProcessState describing its status and an error, if any.
-// Wait releases any resources associated with the Process.
-// On most operating systems, the Process must be a child
-// of the current process or an error will be returned.
-func (p *Process) Wait() (*ProcessState, error) {
- return p.wait()
-}
-
-// Signal sends a signal to the Process.
-// Sending Interrupt on Windows is not implemented.
-func (p *Process) Signal(sig Signal) error {
- return p.signal(sig)
-}
-
-// UserTime returns the user CPU time of the exited process and its children.
-func (p *ProcessState) UserTime() time.Duration {
- return p.userTime()
-}
-
-// SystemTime returns the system CPU time of the exited process and its children.
-func (p *ProcessState) SystemTime() time.Duration {
- return p.systemTime()
-}
-
-// Exited reports whether the program has exited.
-func (p *ProcessState) Exited() bool {
- return p.exited()
-}
-
-// Success reports whether the program exited successfully,
-// such as with exit status 0 on Unix.
-func (p *ProcessState) Success() bool {
- return p.success()
-}
-
-// Sys returns system-dependent exit information about
-// the process. Convert it to the appropriate underlying
-// type, such as syscall.WaitStatus on Unix, to access its contents.
-func (p *ProcessState) Sys() interface{} {
- return p.sys()
-}
-
-// SysUsage returns system-dependent resource usage information about
-// the exited process. Convert it to the appropriate underlying
-// type, such as *syscall.Rusage on Unix, to access its contents.
-// (On Unix, *syscall.Rusage matches struct rusage as defined in the
-// getrusage(2) manual page.)
-func (p *ProcessState) SysUsage() interface{} {
- return p.sysUsage()
-}
-
-// Hostname returns the host name reported by the kernel.
-func Hostname() (name string, err error) {
- return hostname()
-}
-
-// Readdir reads the contents of the directory associated with file and
-// returns a slice of up to n FileInfo values, as would be returned
-// by Lstat, in directory order. Subsequent calls on the same file will yield
-// further FileInfos.
-//
-// If n > 0, Readdir returns at most n FileInfo structures. In this case, if
-// Readdir returns an empty slice, it will return a non-nil error
-// explaining why. At the end of a directory, the error is io.EOF.
-//
-// If n <= 0, Readdir returns all the FileInfo from the directory in
-// a single slice. In this case, if Readdir succeeds (reads all
-// the way to the end of the directory), it returns the slice and a
-// nil error. If it encounters an error before the end of the
-// directory, Readdir returns the FileInfo read until that point
-// and a non-nil error.
-func (f *File) Readdir(n int) ([]FileInfo, error) {
- if f == nil {
- return nil, ErrInvalid
- }
- return f.readdir(n)
-}
-
-// Readdirnames reads and returns a slice of names from the directory f.
-//
-// If n > 0, Readdirnames returns at most n names. In this case, if
-// Readdirnames returns an empty slice, it will return a non-nil error
-// explaining why. At the end of a directory, the error is io.EOF.
-//
-// If n <= 0, Readdirnames returns all the names from the directory in
-// a single slice. In this case, if Readdirnames succeeds (reads all
-// the way to the end of the directory), it returns the slice and a
-// nil error. If it encounters an error before the end of the
-// directory, Readdirnames returns the names read until that point and
-// a non-nil error.
-func (f *File) Readdirnames(n int) (names []string, err error) {
- if f == nil {
- return nil, ErrInvalid
- }
- return f.readdirnames(n)
-}
diff --git a/src/os/env.go b/src/os/env.go
index 4a14714..a03b8f6 100644
--- a/src/os/env.go
+++ b/src/os/env.go
@@ -37,7 +37,7 @@ func ExpandEnv(s string) string {
// shell variable such as $*.
func isShellSpecialVar(c uint8) bool {
switch c {
- case '*', '#', '$', '@', '!', '?', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
+ case '*', '#', '$', '@', '!', '?', '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
return true
}
return false
@@ -76,6 +76,7 @@ func getShellName(s string) (string, int) {
// Getenv retrieves the value of the environment variable named by the key.
// It returns the value, which will be empty if the variable is not present.
+// To distinguish between an empty value and an unset value, use LookupEnv.
func Getenv(key string) string {
v, _ := syscall.Getenv(key)
return v
diff --git a/src/os/env_test.go b/src/os/env_test.go
index d1074cd..e5749f0 100644
--- a/src/os/env_test.go
+++ b/src/os/env_test.go
@@ -95,6 +95,34 @@ func TestUnsetenv(t *testing.T) {
}
}
+func TestClearenv(t *testing.T) {
+ const testKey = "GO_TEST_CLEARENV"
+ const testValue = "1"
+
+ // reset env
+ defer func(origEnv []string) {
+ for _, pair := range origEnv {
+ // Environment variables on Windows can begin with =
+ // http://blogs.msdn.com/b/oldnewthing/archive/2010/05/06/10008132.aspx
+ i := strings.Index(pair[1:], "=") + 1
+ if err := Setenv(pair[:i], pair[i+1:]); err != nil {
+ t.Errorf("Setenv(%q, %q) failed during reset: %v", pair[:i], pair[i+1:], err)
+ }
+ }
+ }(Environ())
+
+ if err := Setenv(testKey, testValue); err != nil {
+ t.Fatalf("Setenv(%q, %q) failed: %v", testKey, testValue, err)
+ }
+ if _, ok := LookupEnv(testKey); !ok {
+ t.Errorf("Setenv(%q, %q) didn't set $%s", testKey, testValue, testKey)
+ }
+ Clearenv()
+ if val, ok := LookupEnv(testKey); ok {
+ t.Errorf("Clearenv() didn't clear $%s, remained with value %q", testKey, val)
+ }
+}
+
func TestLookupEnv(t *testing.T) {
const smallpox = "SMALLPOX" // No one has smallpox.
value, ok := LookupEnv(smallpox) // Should not exist.
diff --git a/src/os/env_unix_test.go b/src/os/env_unix_test.go
index 5ec07ee..f7b67eb 100644
--- a/src/os/env_unix_test.go
+++ b/src/os/env_unix_test.go
@@ -7,6 +7,7 @@
package os_test
import (
+ "fmt"
. "os"
"testing"
)
@@ -28,3 +29,28 @@ func TestSetenvUnixEinval(t *testing.T) {
}
}
}
+
+var shellSpecialVarTests = []struct {
+ k, v string
+}{
+ {"*", "asterisk"},
+ {"#", "pound"},
+ {"$", "dollar"},
+ {"@", "at"},
+ {"!", "exclamation mark"},
+ {"?", "question mark"},
+ {"-", "dash"},
+}
+
+func TestExpandEnvShellSpecialVar(t *testing.T) {
+ for _, tt := range shellSpecialVarTests {
+ Setenv(tt.k, tt.v)
+ defer Unsetenv(tt.k)
+
+ argRaw := fmt.Sprintf("$%s", tt.k)
+ argWithBrace := fmt.Sprintf("${%s}", tt.k)
+ if gotRaw, gotBrace := ExpandEnv(argRaw), ExpandEnv(argWithBrace); gotRaw != gotBrace {
+ t.Errorf("ExpandEnv(%q) = %q, ExpandEnv(%q) = %q; expect them to be equal", argRaw, gotRaw, argWithBrace, gotBrace)
+ }
+ }
+}
diff --git a/src/os/error.go b/src/os/error.go
index e26ce27..7235bfb 100644
--- a/src/os/error.go
+++ b/src/os/error.go
@@ -14,6 +14,7 @@ var (
ErrPermission = errors.New("permission denied")
ErrExist = errors.New("file already exists")
ErrNotExist = errors.New("file does not exist")
+ ErrClosed = errors.New("file already closed")
)
// PathError records an error and the operation and file path that caused it.
@@ -63,3 +64,16 @@ func IsNotExist(err error) bool {
func IsPermission(err error) bool {
return isPermission(err)
}
+
+// underlyingError returns the underlying error for known os error types.
+func underlyingError(err error) error {
+ switch err := err.(type) {
+ case *PathError:
+ return err.Err
+ case *LinkError:
+ return err.Err
+ case *SyscallError:
+ return err.Err
+ }
+ return err
+}
diff --git a/src/os/error_plan9.go b/src/os/error_plan9.go
index 2dc6b39..a673439 100644
--- a/src/os/error_plan9.go
+++ b/src/os/error_plan9.go
@@ -5,46 +5,30 @@
package os
func isExist(err error) bool {
- switch pe := err.(type) {
- case nil:
- return false
- case *PathError:
- err = pe.Err
- case *LinkError:
- err = pe.Err
- case *SyscallError:
- err = pe.Err
- }
- return contains(err.Error(), " exists")
+ return checkErrMessageContent(err, " exists")
}
func isNotExist(err error) bool {
- switch pe := err.(type) {
- case nil:
- return false
- case *PathError:
- err = pe.Err
- case *LinkError:
- err = pe.Err
- case *SyscallError:
- err = pe.Err
- }
- return contains(err.Error(), "does not exist") || contains(err.Error(), "not found") ||
- contains(err.Error(), "has been removed") || contains(err.Error(), "no parent")
+ return checkErrMessageContent(err, "does not exist", "not found",
+ "has been removed", "no parent")
}
func isPermission(err error) bool {
- switch pe := err.(type) {
- case nil:
+ return checkErrMessageContent(err, "permission denied")
+}
+
+// checkErrMessageContent checks if err message contains one of msgs.
+func checkErrMessageContent(err error, msgs ...string) bool {
+ if err == nil {
return false
- case *PathError:
- err = pe.Err
- case *LinkError:
- err = pe.Err
- case *SyscallError:
- err = pe.Err
}
- return contains(err.Error(), "permission denied")
+ err = underlyingError(err)
+ for _, msg := range msgs {
+ if contains(err.Error(), msg) {
+ return true
+ }
+ }
+ return false
}
// contains is a local version of strings.Contains. It knows len(sep) > 1.
diff --git a/src/os/error_test.go b/src/os/error_test.go
index a47c173..3499cee 100644
--- a/src/os/error_test.go
+++ b/src/os/error_test.go
@@ -91,10 +91,12 @@ var isExistTests = []isExistTest{
{&os.PathError{Err: os.ErrPermission}, false, false},
{&os.PathError{Err: os.ErrExist}, true, false},
{&os.PathError{Err: os.ErrNotExist}, false, true},
+ {&os.PathError{Err: os.ErrClosed}, false, false},
{&os.LinkError{Err: os.ErrInvalid}, false, false},
{&os.LinkError{Err: os.ErrPermission}, false, false},
{&os.LinkError{Err: os.ErrExist}, true, false},
{&os.LinkError{Err: os.ErrNotExist}, false, true},
+ {&os.LinkError{Err: os.ErrClosed}, false, false},
{&os.SyscallError{Err: os.ErrNotExist}, false, true},
{&os.SyscallError{Err: os.ErrExist}, true, false},
{nil, false, false},
diff --git a/src/os/error_unix.go b/src/os/error_unix.go
index 3c78eb4..be1440c 100644
--- a/src/os/error_unix.go
+++ b/src/os/error_unix.go
@@ -9,43 +9,16 @@ package os
import "syscall"
func isExist(err error) bool {
- switch pe := err.(type) {
- case nil:
- return false
- case *PathError:
- err = pe.Err
- case *LinkError:
- err = pe.Err
- case *SyscallError:
- err = pe.Err
- }
+ err = underlyingError(err)
return err == syscall.EEXIST || err == syscall.ENOTEMPTY || err == ErrExist
}
func isNotExist(err error) bool {
- switch pe := err.(type) {
- case nil:
- return false
- case *PathError:
- err = pe.Err
- case *LinkError:
- err = pe.Err
- case *SyscallError:
- err = pe.Err
- }
+ err = underlyingError(err)
return err == syscall.ENOENT || err == ErrNotExist
}
func isPermission(err error) bool {
- switch pe := err.(type) {
- case nil:
- return false
- case *PathError:
- err = pe.Err
- case *LinkError:
- err = pe.Err
- case *SyscallError:
- err = pe.Err
- }
+ err = underlyingError(err)
return err == syscall.EACCES || err == syscall.EPERM || err == ErrPermission
}
diff --git a/src/os/error_windows.go b/src/os/error_windows.go
index 2c1c39c..02593b5 100644
--- a/src/os/error_windows.go
+++ b/src/os/error_windows.go
@@ -7,48 +7,22 @@ package os
import "syscall"
func isExist(err error) bool {
- switch pe := err.(type) {
- case nil:
- return false
- case *PathError:
- err = pe.Err
- case *LinkError:
- err = pe.Err
- case *SyscallError:
- err = pe.Err
- }
+ err = underlyingError(err)
return err == syscall.ERROR_ALREADY_EXISTS ||
+ err == syscall.ERROR_DIR_NOT_EMPTY ||
err == syscall.ERROR_FILE_EXISTS || err == ErrExist
}
const _ERROR_BAD_NETPATH = syscall.Errno(53)
func isNotExist(err error) bool {
- switch pe := err.(type) {
- case nil:
- return false
- case *PathError:
- err = pe.Err
- case *LinkError:
- err = pe.Err
- case *SyscallError:
- err = pe.Err
- }
+ err = underlyingError(err)
return err == syscall.ERROR_FILE_NOT_FOUND ||
err == _ERROR_BAD_NETPATH ||
err == syscall.ERROR_PATH_NOT_FOUND || err == ErrNotExist
}
func isPermission(err error) bool {
- switch pe := err.(type) {
- case nil:
- return false
- case *PathError:
- err = pe.Err
- case *LinkError:
- err = pe.Err
- case *SyscallError:
- err = pe.Err
- }
+ err = underlyingError(err)
return err == syscall.ERROR_ACCESS_DENIED || err == ErrPermission
}
diff --git a/src/os/error_windows_test.go b/src/os/error_windows_test.go
index 427dfdb..1635c10 100644
--- a/src/os/error_windows_test.go
+++ b/src/os/error_windows_test.go
@@ -26,6 +26,10 @@ func init() {
isExistTest{err: &os.PathError{Err: syscall.ERROR_PATH_NOT_FOUND}, is: false, isnot: true},
isExistTest{err: &os.LinkError{Err: syscall.ERROR_PATH_NOT_FOUND}, is: false, isnot: true},
isExistTest{err: &os.SyscallError{Err: syscall.ERROR_PATH_NOT_FOUND}, is: false, isnot: true},
+
+ isExistTest{err: &os.PathError{Err: syscall.ERROR_DIR_NOT_EMPTY}, is: true, isnot: false},
+ isExistTest{err: &os.LinkError{Err: syscall.ERROR_DIR_NOT_EMPTY}, is: true, isnot: false},
+ isExistTest{err: &os.SyscallError{Err: syscall.ERROR_DIR_NOT_EMPTY}, is: true, isnot: false},
)
isPermissionTests = append(isPermissionTests,
isPermissionTest{err: &os.PathError{Err: syscall.ERROR_ACCESS_DENIED}, want: true},
diff --git a/src/os/example_test.go b/src/os/example_test.go
new file mode 100644
index 0000000..07f9c76
--- /dev/null
+++ b/src/os/example_test.go
@@ -0,0 +1,106 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package os_test
+
+import (
+ "fmt"
+ "log"
+ "os"
+ "time"
+)
+
+func ExampleOpenFile() {
+ f, err := os.OpenFile("notes.txt", os.O_RDWR|os.O_CREATE, 0755)
+ if 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)
+ }
+}
+
+func ExampleChtimes() {
+ mtime := time.Date(2006, time.February, 1, 3, 4, 5, 0, time.UTC)
+ atime := time.Date(2007, time.March, 2, 4, 5, 6, 0, time.UTC)
+ if err := os.Chtimes("some-filename", atime, mtime); err != nil {
+ log.Fatal(err)
+ }
+}
+
+func ExampleFileMode() {
+ fi, err := os.Stat("some-filename")
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ switch mode := fi.Mode(); {
+ case mode.IsRegular():
+ fmt.Println("regular file")
+ case mode.IsDir():
+ fmt.Println("directory")
+ case mode&os.ModeSymlink != 0:
+ fmt.Println("symbolic link")
+ case mode&os.ModeNamedPipe != 0:
+ fmt.Println("named pipe")
+ }
+}
+
+func ExampleIsNotExist() {
+ filename := "a-nonexistent-file"
+ if _, err := os.Stat(filename); os.IsNotExist(err) {
+ fmt.Printf("file does not exist")
+ }
+ // Output:
+ // file does not exist
+}
+
+func init() {
+ os.Setenv("USER", "gopher")
+ os.Setenv("HOME", "/usr/gopher")
+ os.Unsetenv("GOPATH")
+}
+
+func ExampleExpandEnv() {
+ fmt.Println(os.ExpandEnv("$USER lives in ${HOME}."))
+
+ // Output:
+ // gopher lives in /usr/gopher.
+}
+
+func ExampleLookupEnv() {
+ show := func(key string) {
+ val, ok := os.LookupEnv(key)
+ if !ok {
+ fmt.Printf("%s not set\n", key)
+ } else {
+ fmt.Printf("%s=%s\n", key, val)
+ }
+ }
+
+ show("USER")
+ show("GOPATH")
+
+ // Output:
+ // USER=gopher
+ // GOPATH not set
+}
+
+func ExampleGetenv() {
+ fmt.Printf("%s lives in %s.\n", os.Getenv("USER"), os.Getenv("HOME"))
+
+ // Output:
+ // gopher lives in /usr/gopher.
+}
+
+func ExampleUnsetenv() {
+ os.Setenv("TMPDIR", "/my/tmp")
+ defer os.Unsetenv("TMPDIR")
+}
diff --git a/src/os/exec.go b/src/os/exec.go
index bf32498..8a53e5d 100644
--- a/src/os/exec.go
+++ b/src/os/exec.go
@@ -9,6 +9,7 @@ import (
"sync"
"sync/atomic"
"syscall"
+ "time"
)
// Process stores the information about a process created by StartProcess.
@@ -70,3 +71,89 @@ func Getpid() int { return syscall.Getpid() }
// Getppid returns the process id of the caller's parent.
func Getppid() int { return syscall.Getppid() }
+
+// FindProcess looks for a running process by its pid.
+//
+// The Process it returns can be used to obtain information
+// about the underlying operating system process.
+//
+// On Unix systems, FindProcess always succeeds and returns a Process
+// for the given pid, regardless of whether the process exists.
+func FindProcess(pid int) (*Process, error) {
+ return findProcess(pid)
+}
+
+// StartProcess starts a new process with the program, arguments and attributes
+// specified by name, argv and attr.
+//
+// StartProcess is a low-level interface. The os/exec package provides
+// higher-level interfaces.
+//
+// If there is an error, it will be of type *PathError.
+func StartProcess(name string, argv []string, attr *ProcAttr) (*Process, error) {
+ return startProcess(name, argv, attr)
+}
+
+// Release releases any resources associated with the Process p,
+// rendering it unusable in the future.
+// Release only needs to be called if Wait is not.
+func (p *Process) Release() error {
+ return p.release()
+}
+
+// Kill causes the Process to exit immediately.
+func (p *Process) Kill() error {
+ return p.kill()
+}
+
+// Wait waits for the Process to exit, and then returns a
+// ProcessState describing its status and an error, if any.
+// Wait releases any resources associated with the Process.
+// On most operating systems, the Process must be a child
+// of the current process or an error will be returned.
+func (p *Process) Wait() (*ProcessState, error) {
+ return p.wait()
+}
+
+// Signal sends a signal to the Process.
+// Sending Interrupt on Windows is not implemented.
+func (p *Process) Signal(sig Signal) error {
+ return p.signal(sig)
+}
+
+// UserTime returns the user CPU time of the exited process and its children.
+func (p *ProcessState) UserTime() time.Duration {
+ return p.userTime()
+}
+
+// SystemTime returns the system CPU time of the exited process and its children.
+func (p *ProcessState) SystemTime() time.Duration {
+ return p.systemTime()
+}
+
+// Exited reports whether the program has exited.
+func (p *ProcessState) Exited() bool {
+ return p.exited()
+}
+
+// Success reports whether the program exited successfully,
+// such as with exit status 0 on Unix.
+func (p *ProcessState) Success() bool {
+ return p.success()
+}
+
+// Sys returns system-dependent exit information about
+// the process. Convert it to the appropriate underlying
+// type, such as syscall.WaitStatus on Unix, to access its contents.
+func (p *ProcessState) Sys() interface{} {
+ return p.sys()
+}
+
+// SysUsage returns system-dependent resource usage information about
+// the exited process. Convert it to the appropriate underlying
+// type, such as *syscall.Rusage on Unix, to access its contents.
+// (On Unix, *syscall.Rusage matches struct rusage as defined in the
+// getrusage(2) manual page.)
+func (p *ProcessState) SysUsage() interface{} {
+ return p.sysUsage()
+}
diff --git a/src/os/exec/example_test.go b/src/os/exec/example_test.go
index 55eaac8..5ccb21a 100644
--- a/src/os/exec/example_test.go
+++ b/src/os/exec/example_test.go
@@ -6,11 +6,15 @@ package exec_test
import (
"bytes"
+ "context"
"encoding/json"
"fmt"
+ "io"
+ "io/ioutil"
"log"
"os/exec"
"strings"
+ "time"
)
func ExampleLookPath() {
@@ -73,3 +77,61 @@ func ExampleCmd_StdoutPipe() {
}
fmt.Printf("%s is %d years old\n", person.Name, person.Age)
}
+
+func ExampleCmd_StdinPipe() {
+ cmd := exec.Command("cat")
+ stdin, err := cmd.StdinPipe()
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ go func() {
+ defer stdin.Close()
+ io.WriteString(stdin, "values written to stdin are passed to cmd's standard input")
+ }()
+
+ out, err := cmd.CombinedOutput()
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ fmt.Printf("%s\n", out)
+}
+
+func ExampleCmd_StderrPipe() {
+ cmd := exec.Command("sh", "-c", "echo stdout; echo 1>&2 stderr")
+ stderr, err := cmd.StderrPipe()
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ if err := cmd.Start(); err != nil {
+ log.Fatal(err)
+ }
+
+ slurp, _ := ioutil.ReadAll(stderr)
+ fmt.Printf("%s\n", slurp)
+
+ if err := cmd.Wait(); err != nil {
+ log.Fatal(err)
+ }
+}
+
+func ExampleCmd_CombinedOutput() {
+ cmd := exec.Command("sh", "-c", "echo stdout; echo 1>&2 stderr")
+ stdoutStderr, err := cmd.CombinedOutput()
+ if err != nil {
+ log.Fatal(err)
+ }
+ fmt.Printf("%s\n", stdoutStderr)
+}
+
+func ExampleCommandContext() {
+ ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond)
+ defer cancel()
+
+ if err := exec.CommandContext(ctx, "sleep", "5").Run(); err != nil {
+ // This will fail after 100 milliseconds. The 5 second sleep
+ // will be interrupted.
+ }
+}
diff --git a/src/os/exec/exec.go b/src/os/exec/exec.go
index d2c1b17..c4c5168 100644
--- a/src/os/exec/exec.go
+++ b/src/os/exec/exec.go
@@ -120,12 +120,13 @@ type Cmd struct {
// It sets only the Path and Args in the returned structure.
//
// If name contains no path separators, Command uses LookPath to
-// resolve the path to a complete name if possible. Otherwise it uses
-// name directly.
+// resolve name to a complete path if possible. Otherwise it uses name
+// directly as Path.
//
// The returned Cmd's Args field is constructed from the command name
// followed by the elements of arg, so arg should not include the
-// command name itself. For example, Command("echo", "hello")
+// command name itself. For example, Command("echo", "hello").
+// Args[0] is always name, not the possibly resolved Path.
func Command(name string, arg ...string) *Cmd {
cmd := &Cmd{
Path: name,
@@ -515,15 +516,16 @@ func (c *Cmd) StdinPipe() (io.WriteCloser, error) {
c.Stdin = pr
c.closeAfterStart = append(c.closeAfterStart, pr)
wc := &closeOnce{File: pw}
- c.closeAfterWait = append(c.closeAfterWait, wc)
+ c.closeAfterWait = append(c.closeAfterWait, closerFunc(wc.safeClose))
return wc, nil
}
type closeOnce struct {
*os.File
- once sync.Once
- err error
+ writers sync.RWMutex // coordinate safeClose and Write
+ once sync.Once
+ err error
}
func (c *closeOnce) Close() error {
@@ -535,6 +537,55 @@ func (c *closeOnce) close() {
c.err = c.File.Close()
}
+type closerFunc func() error
+
+func (f closerFunc) Close() error { return f() }
+
+// safeClose closes c being careful not to race with any calls to c.Write.
+// See golang.org/issue/9307 and TestEchoFileRace in exec_test.go.
+// In theory other calls could also be excluded (by writing appropriate
+// wrappers like c.Write's implementation below), but since c is most
+// commonly used as a WriteCloser, Write is the main one to worry about.
+// See also #7970, for which this is a partial fix for this specific instance.
+// The idea is that we return a WriteCloser, and so the caller can be
+// relied upon not to call Write and Close simultaneously, but it's less
+// obvious that cmd.Wait calls Close and that the caller must not call
+// Write and cmd.Wait simultaneously. In fact that seems too onerous.
+// So we change the use of Close in cmd.Wait to use safeClose, which will
+// synchronize with any Write.
+//
+// It's important that we know this won't block forever waiting for the
+// operations being excluded. At the point where this is called,
+// the invoked command has exited and the parent copy of the read side
+// of the pipe has also been closed, so there should really be no read side
+// of the pipe left. Any active writes should return very shortly with an EPIPE,
+// making it reasonable to wait for them.
+// Technically it is possible that the child forked a sub-process or otherwise
+// handed off the read side of the pipe before exiting and the current holder
+// is not reading from the pipe, and the pipe is full, in which case the close here
+// might block waiting for the write to complete. That's probably OK.
+// It's a small enough problem to be outweighed by eliminating the race here.
+func (c *closeOnce) safeClose() error {
+ c.writers.Lock()
+ err := c.Close()
+ c.writers.Unlock()
+ return err
+}
+
+func (c *closeOnce) Write(b []byte) (int, error) {
+ c.writers.RLock()
+ n, err := c.File.Write(b)
+ c.writers.RUnlock()
+ return n, err
+}
+
+func (c *closeOnce) WriteString(s string) (int, error) {
+ c.writers.RLock()
+ n, err := c.File.WriteString(s)
+ c.writers.RUnlock()
+ return n, err
+}
+
// StdoutPipe returns a pipe that will be connected to the command's
// standard output when the command starts.
//
diff --git a/src/os/exec/exec_test.go b/src/os/exec/exec_test.go
index 4cc9847..d3ac7ab 100644
--- a/src/os/exec/exec_test.go
+++ b/src/os/exec/exec_test.go
@@ -101,6 +101,26 @@ func TestCatStdin(t *testing.T) {
}
}
+func TestEchoFileRace(t *testing.T) {
+ cmd := helperCommand(t, "echo")
+ stdin, err := cmd.StdinPipe()
+ if err != nil {
+ t.Fatalf("StdinPipe: %v", err)
+ }
+ if err := cmd.Start(); err != nil {
+ t.Fatalf("Start: %v", err)
+ }
+ wrote := make(chan bool)
+ go func() {
+ defer close(wrote)
+ fmt.Fprint(stdin, "echo\n")
+ }()
+ if err := cmd.Wait(); err != nil {
+ t.Fatalf("Wait: %v", err)
+ }
+ <-wrote
+}
+
func TestCatGoodAndBadFile(t *testing.T) {
// Testing combined output and error values.
bs, err := helperCommand(t, "cat", "/bogus/file.foo", "exec_test.go").CombinedOutput()
@@ -226,6 +246,32 @@ func TestStdinClose(t *testing.T) {
check("Wait", cmd.Wait())
}
+// Issue 17647.
+func TestStdinCloseRace(t *testing.T) {
+ cmd := helperCommand(t, "stdinClose")
+ stdin, err := cmd.StdinPipe()
+ if err != nil {
+ t.Fatalf("StdinPipe: %v", err)
+ }
+ if err := cmd.Start(); err != nil {
+ t.Fatalf("Start: %v", err)
+ }
+ go func() {
+ if err := cmd.Process.Kill(); err != nil {
+ t.Errorf("Kill: %v", err)
+ }
+ }()
+ go func() {
+ io.Copy(stdin, strings.NewReader(stdinCloseTestString))
+ if err := stdin.Close(); err != nil {
+ t.Errorf("stdin.Close: %v", err)
+ }
+ }()
+ if err := cmd.Wait(); err == nil {
+ t.Fatalf("Wait: succeeded unexpectedly")
+ }
+}
+
// Issue 5071
func TestPipeLookPathLeak(t *testing.T) {
fd0, lsof0 := numOpenFDS(t)
@@ -412,7 +458,7 @@ func TestExtraFilesFDShuffle(t *testing.T) {
buf := make([]byte, 512)
n, err := stderr.Read(buf)
if err != nil {
- t.Fatalf("Read: %s", err)
+ t.Errorf("Read: %s", err)
ch <- err.Error()
} else {
ch <- string(buf[:n])
@@ -938,7 +984,7 @@ func TestContextCancel(t *testing.T) {
}
if err := w.Close(); err != nil {
- t.Error("error closing write end of pipe: %v", err)
+ t.Errorf("error closing write end of pipe: %v", err)
}
<-readDone
diff --git a/src/os/exec_windows.go b/src/os/exec_windows.go
index 72b5a93..d89db20 100644
--- a/src/os/exec_windows.go
+++ b/src/os/exec_windows.go
@@ -63,7 +63,9 @@ func (p *Process) signal(sig Signal) error {
return errors.New("os: process already finished")
}
if sig == Kill {
- return terminateProcess(p.Pid, 1)
+ err := terminateProcess(p.Pid, 1)
+ runtime.KeepAlive(p)
+ return err
}
// TODO(rsc): Handle Interrupt too?
return syscall.Errno(syscall.EWINDOWS)
diff --git a/src/os/executable.go b/src/os/executable.go
new file mode 100644
index 0000000..8c21246
--- /dev/null
+++ b/src/os/executable.go
@@ -0,0 +1,23 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package os
+
+// Executable returns the path name for the executable that started
+// the current process. There is no guarantee that the path is still
+// pointing to the correct executable. If a symlink was used to start
+// the process, depending on the operating system, the result might
+// be the symlink or the path it pointed to. If a stable result is
+// needed, path/filepath.EvalSymlinks might help.
+//
+// Executable returns an absolute path unless an error occurred.
+//
+// The main use case is finding resources located relative to an
+// executable.
+//
+// Executable is not supported on nacl or OpenBSD (unless procfs is
+// mounted.)
+func Executable() (string, error) {
+ return executable()
+}
diff --git a/src/os/executable_darwin.go b/src/os/executable_darwin.go
new file mode 100644
index 0000000..ce5b814
--- /dev/null
+++ b/src/os/executable_darwin.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 os
+
+var executablePath string // set by ../runtime/os_darwin.go
+
+var initCwd, initCwdErr = Getwd()
+
+func executable() (string, error) {
+ ep := executablePath
+ if ep[0] != '/' {
+ if initCwdErr != nil {
+ return ep, initCwdErr
+ }
+ if len(ep) > 2 && ep[0:2] == "./" {
+ // skip "./"
+ ep = ep[2:]
+ }
+ ep = initCwd + "/" + ep
+ }
+ return ep, nil
+}
diff --git a/src/os/executable_freebsd.go b/src/os/executable_freebsd.go
new file mode 100644
index 0000000..ccaf8e6
--- /dev/null
+++ b/src/os/executable_freebsd.go
@@ -0,0 +1,33 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package os
+
+import (
+ "syscall"
+ "unsafe"
+)
+
+func executable() (string, error) {
+ mib := [4]int32{1 /* CTL_KERN */, 14 /* KERN_PROC */, 12 /* KERN_PROC_PATHNAME */, -1}
+
+ n := uintptr(0)
+ // get length
+ _, _, err := syscall.Syscall6(syscall.SYS___SYSCTL, uintptr(unsafe.Pointer(&mib[0])), 4, 0, uintptr(unsafe.Pointer(&n)), 0, 0)
+ if err != 0 {
+ return "", err
+ }
+ if n == 0 { // shouldn't happen
+ return "", nil
+ }
+ buf := make([]byte, n)
+ _, _, err = syscall.Syscall6(syscall.SYS___SYSCTL, uintptr(unsafe.Pointer(&mib[0])), 4, uintptr(unsafe.Pointer(&buf[0])), uintptr(unsafe.Pointer(&n)), 0, 0)
+ if err != 0 {
+ return "", err
+ }
+ if n == 0 { // shouldn't happen
+ return "", nil
+ }
+ return string(buf[:n-1]), nil
+}
diff --git a/src/os/executable_plan9.go b/src/os/executable_plan9.go
new file mode 100644
index 0000000..a5947ea
--- /dev/null
+++ b/src/os/executable_plan9.go
@@ -0,0 +1,19 @@
+// Copyright 2016 The Go Authors. 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 os
+
+import "syscall"
+
+func executable() (string, error) {
+ fn := "/proc/" + itoa(Getpid()) + "/text"
+ f, err := Open(fn)
+ if err != nil {
+ return "", err
+ }
+ defer f.Close()
+ return syscall.Fd2path(int(f.Fd()))
+}
diff --git a/src/os/executable_procfs.go b/src/os/executable_procfs.go
new file mode 100644
index 0000000..69a70e1
--- /dev/null
+++ b/src/os/executable_procfs.go
@@ -0,0 +1,36 @@
+// Copyright 2016 The Go Authors. 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 netbsd openbsd dragonfly nacl
+
+package os
+
+import (
+ "errors"
+ "runtime"
+)
+
+// We query the executable path at init time to avoid the problem of
+// readlink returns a path appended with " (deleted)" when the original
+// binary gets deleted.
+var executablePath, executablePathErr = func() (string, error) {
+ var procfn string
+ switch runtime.GOOS {
+ default:
+ return "", errors.New("Executable not implemented for " + runtime.GOOS)
+ case "linux", "android":
+ procfn = "/proc/self/exe"
+ case "netbsd":
+ procfn = "/proc/curproc/exe"
+ case "openbsd":
+ procfn = "/proc/curproc/file"
+ case "dragonfly":
+ procfn = "/proc/curproc/file"
+ }
+ return Readlink(procfn)
+}()
+
+func executable() (string, error) {
+ return executablePath, executablePathErr
+}
diff --git a/src/os/executable_solaris.go b/src/os/executable_solaris.go
new file mode 100644
index 0000000..80f9372
--- /dev/null
+++ b/src/os/executable_solaris.go
@@ -0,0 +1,27 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package os
+
+import "syscall"
+
+var initCwd, initCwdErr = Getwd()
+
+func executable() (string, error) {
+ path, err := syscall.Getexecname()
+ if err != nil {
+ return path, err
+ }
+ if len(path) > 0 && path[0] != '/' {
+ if initCwdErr != nil {
+ return path, initCwdErr
+ }
+ if len(path) > 2 && path[0:2] == "./" {
+ // skip "./"
+ path = path[2:]
+ }
+ return initCwd + "/" + path, nil
+ }
+ return path, nil
+}
diff --git a/src/os/executable_test.go b/src/os/executable_test.go
new file mode 100644
index 0000000..a4d8909
--- /dev/null
+++ b/src/os/executable_test.go
@@ -0,0 +1,87 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package os_test
+
+import (
+ "fmt"
+ "internal/testenv"
+ "os"
+ osexec "os/exec"
+ "path/filepath"
+ "runtime"
+ "testing"
+)
+
+const executable_EnvVar = "OSTEST_OUTPUT_EXECPATH"
+
+func TestExecutable(t *testing.T) {
+ testenv.MustHaveExec(t) // will also execlude nacl, which doesn't support Executable anyway
+ ep, err := os.Executable()
+ if err != nil {
+ switch goos := runtime.GOOS; goos {
+ case "openbsd": // procfs is not mounted by default
+ t.Skipf("Executable failed on %s: %v, expected", goos, err)
+ }
+ t.Fatalf("Executable failed: %v", err)
+ }
+ // we want fn to be of the form "dir/prog"
+ dir := filepath.Dir(filepath.Dir(ep))
+ fn, err := filepath.Rel(dir, ep)
+ if err != nil {
+ t.Fatalf("filepath.Rel: %v", err)
+ }
+ cmd := &osexec.Cmd{}
+ // make child start with a relative program path
+ cmd.Dir = dir
+ cmd.Path = fn
+ // forge argv[0] for child, so that we can verify we could correctly
+ // get real path of the executable without influenced by argv[0].
+ cmd.Args = []string{"-", "-test.run=XXXX"}
+ cmd.Env = append(os.Environ(), fmt.Sprintf("%s=1", executable_EnvVar))
+ out, err := cmd.CombinedOutput()
+ if err != nil {
+ t.Fatalf("exec(self) failed: %v", err)
+ }
+ outs := string(out)
+ if !filepath.IsAbs(outs) {
+ t.Fatalf("Child returned %q, want an absolute path", out)
+ }
+ if !sameFile(outs, ep) {
+ t.Fatalf("Child returned %q, not the same file as %q", out, ep)
+ }
+}
+
+func sameFile(fn1, fn2 string) bool {
+ fi1, err := os.Stat(fn1)
+ if err != nil {
+ return false
+ }
+ fi2, err := os.Stat(fn2)
+ if err != nil {
+ return false
+ }
+ return os.SameFile(fi1, fi2)
+}
+
+func init() {
+ if e := os.Getenv(executable_EnvVar); e != "" {
+ // first chdir to another path
+ dir := "/"
+ if runtime.GOOS == "windows" {
+ cwd, err := os.Getwd()
+ if err != nil {
+ panic(err)
+ }
+ dir = filepath.VolumeName(cwd)
+ }
+ os.Chdir(dir)
+ if ep, err := os.Executable(); err != nil {
+ fmt.Fprint(os.Stderr, "ERROR: ", err)
+ } else {
+ fmt.Fprint(os.Stderr, ep)
+ }
+ os.Exit(0)
+ }
+}
diff --git a/src/os/executable_windows.go b/src/os/executable_windows.go
new file mode 100644
index 0000000..fc5cf86
--- /dev/null
+++ b/src/os/executable_windows.go
@@ -0,0 +1,32 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package os
+
+import (
+ "internal/syscall/windows"
+ "syscall"
+)
+
+func getModuleFileName(handle syscall.Handle) (string, error) {
+ n := uint32(1024)
+ var buf []uint16
+ for {
+ buf = make([]uint16, n)
+ r, err := windows.GetModuleFileName(handle, &buf[0], n)
+ if err != nil {
+ return "", err
+ }
+ if r < n {
+ break
+ }
+ // r == n means n not big enough
+ n += 1024
+ }
+ return syscall.UTF16ToString(buf), nil
+}
+
+func executable() (string, error) {
+ return getModuleFileName(0)
+}
diff --git a/src/os/export_windows_test.go b/src/os/export_windows_test.go
new file mode 100644
index 0000000..3bb2d20
--- /dev/null
+++ b/src/os/export_windows_test.go
@@ -0,0 +1,13 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package os
+
+// Export for testing.
+
+var (
+ FixLongPath = fixLongPath
+ NewConsoleFile = newConsoleFile
+ ReadConsoleFunc = &readConsole
+)
diff --git a/src/os/file.go b/src/os/file.go
index e546441..de245c5 100644
--- a/src/os/file.go
+++ b/src/os/file.go
@@ -92,11 +92,11 @@ func (e *LinkError) Error() string {
}
// Read reads up to len(b) bytes from the File.
-// It returns the number of bytes read and an error, if any.
-// EOF is signaled by a zero count with err set to io.EOF.
+// It returns the number of bytes read and any error encountered.
+// At end of file, Read returns 0, io.EOF.
func (f *File) Read(b []byte) (n int, err error) {
- if f == nil {
- return 0, ErrInvalid
+ if err := f.checkValid("read"); err != nil {
+ return 0, err
}
n, e := f.read(b)
if n == 0 && len(b) > 0 && e == nil {
@@ -113,8 +113,8 @@ func (f *File) Read(b []byte) (n int, err error) {
// ReadAt always returns a non-nil error when n < len(b).
// At end of file, that error is io.EOF.
func (f *File) ReadAt(b []byte, off int64) (n int, err error) {
- if f == nil {
- return 0, ErrInvalid
+ if err := f.checkValid("read"); err != nil {
+ return 0, err
}
for len(b) > 0 {
m, e := f.pread(b, off)
@@ -136,8 +136,8 @@ func (f *File) ReadAt(b []byte, off int64) (n int, err error) {
// It returns the number of bytes written and an error, if any.
// Write returns a non-nil error when n != len(b).
func (f *File) Write(b []byte) (n int, err error) {
- if f == nil {
- return 0, ErrInvalid
+ if err := f.checkValid("write"); err != nil {
+ return 0, err
}
n, e := f.write(b)
if n < 0 {
@@ -159,8 +159,8 @@ func (f *File) Write(b []byte) (n int, err error) {
// It returns the number of bytes written and an error, if any.
// WriteAt returns a non-nil error when n != len(b).
func (f *File) WriteAt(b []byte, off int64) (n int, err error) {
- if f == nil {
- return 0, ErrInvalid
+ if err := f.checkValid("write"); err != nil {
+ return 0, err
}
for len(b) > 0 {
m, e := f.pwrite(b, off)
@@ -181,8 +181,8 @@ func (f *File) WriteAt(b []byte, off int64) (n int, err error) {
// It returns the new offset and an error, if any.
// The behavior of Seek on a file opened with O_APPEND is not specified.
func (f *File) Seek(offset int64, whence int) (ret int64, err error) {
- if f == nil {
- return 0, ErrInvalid
+ if err := f.checkValid("seek"); err != nil {
+ return 0, err
}
r, e := f.seek(offset, whence)
if e == nil && f.dirinfo != nil && r != 0 {
@@ -197,16 +197,13 @@ func (f *File) Seek(offset int64, whence int) (ret int64, err error) {
// WriteString is like Write, but writes the contents of string s rather than
// a slice of bytes.
func (f *File) WriteString(s string) (n int, err error) {
- if f == nil {
- return 0, ErrInvalid
- }
return f.Write([]byte(s))
}
// Mkdir creates a new directory with the specified name and permission bits.
// If there is an error, it will be of type *PathError.
func Mkdir(name string, perm FileMode) error {
- e := syscall.Mkdir(name, syscallMode(perm))
+ e := syscall.Mkdir(fixLongPath(name), syscallMode(perm))
if e != nil {
return &PathError{"mkdir", name, e}
@@ -233,8 +230,8 @@ func Chdir(dir string) error {
// which must be a directory.
// If there is an error, it will be of type *PathError.
func (f *File) Chdir() error {
- if f == nil {
- return ErrInvalid
+ if err := f.checkValid("chdir"); err != nil {
+ return err
}
if e := syscall.Fchdir(f.fd); e != nil {
return &PathError{"chdir", f.name, e}
@@ -278,3 +275,15 @@ 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
+ }
+ if f.fd == badFd {
+ return &PathError{op, f.name, ErrClosed}
+ }
+ return nil
+}
diff --git a/src/os/file_plan9.go b/src/os/file_plan9.go
index 9edb6bc..5276a7e 100644
--- a/src/os/file_plan9.go
+++ b/src/os/file_plan9.go
@@ -11,9 +11,9 @@ import (
"time"
)
-// File represents an open file descriptor.
-type File struct {
- *file
+// fixLongPath is a noop on non-Windows platforms.
+func fixLongPath(path string) string {
+ return path
}
// file is the real representation of *File.
@@ -135,21 +135,21 @@ func OpenFile(name string, flag int, perm FileMode) (*File, error) {
// Close closes the File, rendering it unusable for I/O.
// It returns an error, if any.
func (f *File) Close() error {
- if f == nil {
- return ErrInvalid
+ if err := f.checkValid("close"); err != nil {
+ return err
}
return f.file.close()
}
func (file *file) close() error {
- if file == nil || file.fd < 0 {
+ if file == nil || file.fd == badFd {
return ErrInvalid
}
var err error
if e := syscall.Close(file.fd); e != nil {
err = &PathError{"close", file.name, e}
}
- file.fd = -1 // so it can't be closed again
+ file.fd = badFd // so it can't be closed again
// no need for a finalizer anymore
runtime.SetFinalizer(file, nil)
diff --git a/src/os/file_posix.go b/src/os/file_posix.go
index 6d8076f..d817f34 100644
--- a/src/os/file_posix.go
+++ b/src/os/file_posix.go
@@ -18,7 +18,7 @@ func sigpipe() // implemented in package runtime
func Readlink(name string) (string, error) {
for len := 128; ; len *= 2 {
b := make([]byte, len)
- n, e := fixCount(syscall.Readlink(name, b))
+ n, e := fixCount(syscall.Readlink(fixLongPath(name), b))
if e != nil {
return "", &PathError{"readlink", name, e}
}
@@ -57,8 +57,8 @@ func Chmod(name string, mode FileMode) error {
// Chmod changes the mode of the file to mode.
// If there is an error, it will be of type *PathError.
func (f *File) Chmod(mode FileMode) error {
- if f == nil {
- return ErrInvalid
+ 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}
@@ -89,8 +89,8 @@ func Lchown(name string, uid, gid int) error {
// Chown changes the numeric uid and gid of the named file.
// If there is an error, it will be of type *PathError.
func (f *File) Chown(uid, gid int) error {
- if f == nil {
- return ErrInvalid
+ 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}
@@ -102,8 +102,8 @@ func (f *File) Chown(uid, gid int) error {
// It does not change the I/O offset.
// If there is an error, it will be of type *PathError.
func (f *File) Truncate(size int64) error {
- if f == nil {
- return ErrInvalid
+ if err := f.checkValid("truncate"); err != nil {
+ return err
}
if e := syscall.Ftruncate(f.fd, size); e != nil {
return &PathError{"truncate", f.name, e}
@@ -115,11 +115,11 @@ func (f *File) Truncate(size int64) error {
// Typically, this means flushing the file system's in-memory copy
// of recently written data to disk.
func (f *File) Sync() error {
- if f == nil {
- return ErrInvalid
+ if err := f.checkValid("sync"); err != nil {
+ return err
}
if e := syscall.Fsync(f.fd); e != nil {
- return NewSyscallError("fsync", e)
+ return &PathError{"sync", f.name, e}
}
return nil
}
@@ -134,7 +134,7 @@ func Chtimes(name string, atime time.Time, mtime time.Time) error {
var utimes [2]syscall.Timespec
utimes[0] = syscall.NsecToTimespec(atime.UnixNano())
utimes[1] = syscall.NsecToTimespec(mtime.UnixNano())
- if e := syscall.UtimesNano(name, utimes[0:]); e != nil {
+ if e := syscall.UtimesNano(fixLongPath(name), utimes[0:]); e != nil {
return &PathError{"chtimes", name, e}
}
return nil
diff --git a/src/os/file_unix.go b/src/os/file_unix.go
index 9b64f21..1cff93a 100644
--- a/src/os/file_unix.go
+++ b/src/os/file_unix.go
@@ -11,11 +11,16 @@ import (
"syscall"
)
-func sameFile(fs1, fs2 *fileStat) bool {
- return fs1.sys.Dev == fs2.sys.Dev && fs1.sys.Ino == fs2.sys.Ino
+// fixLongPath is a noop on non-Windows platforms.
+func fixLongPath(path string) string {
+ return path
}
func rename(oldname, newname string) error {
+ fi, err := Lstat(newname)
+ if err == nil && fi.IsDir() {
+ return &LinkError{"rename", oldname, newname, syscall.EEXIST}
+ }
e := syscall.Rename(oldname, newname)
if e != nil {
return &LinkError{"rename", oldname, newname, e}
@@ -23,11 +28,6 @@ func rename(oldname, newname string) error {
return nil
}
-// File represents an open file descriptor.
-type File struct {
- *file
-}
-
// file is the real representation of *File.
// The extra level of indirection ensures that no clients of os
// can overwrite this data, which could cause the finalizer
@@ -133,7 +133,7 @@ func (f *File) Close() error {
}
func (file *file) close() error {
- if file == nil || file.fd < 0 {
+ if file == nil || file.fd == badFd {
return syscall.EINVAL
}
var err error
@@ -147,69 +147,6 @@ func (file *file) close() error {
return err
}
-// Stat returns the FileInfo structure describing file.
-// If there is an error, it will be of type *PathError.
-func (f *File) Stat() (FileInfo, error) {
- if f == nil {
- return nil, ErrInvalid
- }
- var fs fileStat
- err := syscall.Fstat(f.fd, &fs.sys)
- if err != nil {
- return nil, &PathError{"stat", f.name, err}
- }
- fillFileStatFromSys(&fs, f.name)
- return &fs, nil
-}
-
-// Stat returns a FileInfo describing the named file.
-// If there is an error, it will be of type *PathError.
-func Stat(name string) (FileInfo, error) {
- var fs fileStat
- err := syscall.Stat(name, &fs.sys)
- if err != nil {
- return nil, &PathError{"stat", name, err}
- }
- fillFileStatFromSys(&fs, name)
- return &fs, nil
-}
-
-// Lstat returns a FileInfo describing the named file.
-// If the file is a symbolic link, the returned FileInfo
-// describes the symbolic link. Lstat makes no attempt to follow the link.
-// If there is an error, it will be of type *PathError.
-func Lstat(name string) (FileInfo, error) {
- var fs fileStat
- err := syscall.Lstat(name, &fs.sys)
- if err != nil {
- return nil, &PathError{"lstat", name, err}
- }
- fillFileStatFromSys(&fs, name)
- return &fs, nil
-}
-
-func (f *File) readdir(n int) (fi []FileInfo, err error) {
- dirname := f.name
- if dirname == "" {
- dirname = "."
- }
- names, err := f.Readdirnames(n)
- fi = make([]FileInfo, 0, len(names))
- for _, filename := range names {
- fip, lerr := lstat(dirname + "/" + filename)
- if IsNotExist(lerr) {
- // File disappeared between readdir + stat.
- // Just treat it as if it didn't exist.
- continue
- }
- if lerr != nil {
- return fi, lerr
- }
- fi = append(fi, fip)
- }
- return fi, 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
@@ -324,24 +261,6 @@ func Remove(name string) error {
return &PathError{"remove", name, e}
}
-// basename removes trailing slashes and the leading directory name from path name
-func basename(name string) string {
- i := len(name) - 1
- // Remove trailing slashes
- for ; i > 0 && name[i] == '/'; i-- {
- name = name[:i]
- }
- // Remove leading directory name
- for i--; i >= 0; i-- {
- if name[i] == '/' {
- name = name[i+1:]
- break
- }
- }
-
- return name
-}
-
// TempDir returns the default directory to use for temporary files.
func TempDir() string {
dir := Getenv("TMPDIR")
diff --git a/src/os/file_windows.go b/src/os/file_windows.go
index f470fc4..97be324 100644
--- a/src/os/file_windows.go
+++ b/src/os/file_windows.go
@@ -15,11 +15,6 @@ import (
"unsafe"
)
-// File represents an open file descriptor.
-type File struct {
- *file
-}
-
// file is the real representation of *File.
// The extra level of indirection ensures that no clients of os
// can overwrite this data, which could cause the finalizer
@@ -31,9 +26,11 @@ type file struct {
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
- readbuf []rune // input console buffer
+ 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
}
// Fd returns the Windows handle referencing the open file.
@@ -49,20 +46,27 @@ func (file *File) Fd() uintptr {
// 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}}
- var m uint32
- if syscall.GetConsoleMode(f.fd, &m) == nil {
- f.isConsole = true
- }
runtime.SetFinalizer(f.file, (*file).close)
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
+}
+
// NewFile returns a new File with the given file descriptor and name.
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)
}
@@ -82,7 +86,7 @@ const DevNull = "NUL"
func (f *file) isdir() bool { return f != nil && f.dirinfo != nil }
func openFile(name string, flag int, perm FileMode) (file *File, err error) {
- r, e := syscall.Open(name, flag|syscall.O_CLOEXEC, syscallMode(perm))
+ r, e := syscall.Open(fixLongPath(name), flag|syscall.O_CLOEXEC, syscallMode(perm))
if e != nil {
return nil, e
}
@@ -91,10 +95,13 @@ func openFile(name string, flag int, perm FileMode) (file *File, err error) {
func openDir(name string) (file *File, err error) {
var mask string
- if len(name) == 2 && name[1] == ':' { // it is a drive letter, like C:
- mask = name + `*`
+
+ path := fixLongPath(name)
+
+ if len(path) == 2 && path[1] == ':' || (len(path) > 0 && path[len(path)-1] == '\\') { // it is a drive letter, like C:
+ mask = path + `*`
} else {
- mask = name + `\*`
+ mask = path + `\*`
}
maskp, e := syscall.UTF16PtrFromString(mask)
if e != nil {
@@ -110,11 +117,11 @@ func openDir(name string) (file *File, err error) {
return nil, e
}
var fa syscall.Win32FileAttributeData
- namep, e := syscall.UTF16PtrFromString(name)
+ pathp, e := syscall.UTF16PtrFromString(path)
if e != nil {
return nil, e
}
- e = syscall.GetFileAttributesEx(namep, syscall.GetFileExInfoStandard, (*byte)(unsafe.Pointer(&fa)))
+ e = syscall.GetFileAttributesEx(pathp, syscall.GetFileExInfoStandard, (*byte)(unsafe.Pointer(&fa)))
if e != nil {
return nil, e
}
@@ -123,7 +130,7 @@ func openDir(name string) (file *File, err error) {
}
d.isempty = true
}
- d.path = name
+ d.path = path
if !isAbs(d.path) {
d.path, e = syscall.FullPath(d.path)
if e != nil {
@@ -189,71 +196,14 @@ func (file *file) close() error {
if e != nil {
err = &PathError{"close", file.name, e}
}
- file.fd = syscall.InvalidHandle // so it can't be closed again
+ file.fd = badFd // so it can't be closed again
// no need for a finalizer anymore
runtime.SetFinalizer(file, nil)
return err
}
-func (file *File) readdir(n int) (fi []FileInfo, err error) {
- if file == nil {
- return nil, syscall.EINVAL
- }
- 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 {
- n = -1
- size = 100
- }
- fi = make([]FileInfo, 0, size) // Empty with room to grow.
- d := &file.dirinfo.data
- for n != 0 && !file.dirinfo.isempty {
- if file.dirinfo.needdata {
- e := syscall.FindNextFile(file.fd, d)
- if e != nil {
- if e == syscall.ERROR_NO_MORE_FILES {
- break
- } else {
- err = &PathError{"FindNextFile", file.name, e}
- if !wantAll {
- fi = nil
- }
- return
- }
- }
- }
- file.dirinfo.needdata = true
- name := syscall.UTF16ToString(d.FileName[0:])
- if name == "." || name == ".." { // Useless names
- continue
- }
- f := &fileStat{
- name: name,
- sys: syscall.Win32FileAttributeData{
- FileAttributes: d.FileAttributes,
- CreationTime: d.CreationTime,
- LastAccessTime: d.LastAccessTime,
- LastWriteTime: d.LastWriteTime,
- FileSizeHigh: d.FileSizeHigh,
- FileSizeLow: d.FileSizeLow,
- },
- path: file.dirinfo.path + `\` + name,
- }
- n--
- fi = append(fi, f)
- }
- if !wantAll && len(fi) == 0 {
- return fi, io.EOF
- }
- return fi, nil
-}
+var readConsole = syscall.ReadConsole // changed for testing
// readConsole reads utf16 characters from console File,
// encodes them into utf8 and stores them in buffer b.
@@ -262,50 +212,70 @@ func (f *File) readConsole(b []byte) (n int, err error) {
if len(b) == 0 {
return 0, nil
}
- if len(f.readbuf) == 0 {
- numBytes := len(b)
- // Windows can't read bytes over max of int16.
- // Some versions of Windows can read even less.
- // See golang.org/issue/13697.
- if numBytes > 10000 {
- numBytes = 10000
+
+ 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)
}
- mbytes := make([]byte, numBytes)
- var nmb uint32
- err := syscall.ReadFile(f.fd, mbytes, &nmb, nil)
+ 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
}
- if nmb > 0 {
- var pmb *byte
- if len(b) > 0 {
- pmb = &mbytes[0]
- }
- acp := windows.GetACP()
- nwc, err := windows.MultiByteToWideChar(acp, 2, pmb, int32(nmb), nil, 0)
- if err != nil {
- return 0, err
- }
- wchars := make([]uint16, nwc)
- pwc := &wchars[0]
- nwc, err = windows.MultiByteToWideChar(acp, 2, pmb, int32(nmb), pwc, nwc)
- 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++
+ }
+ }
}
- f.readbuf = utf16.Decode(wchars[:nwc])
+ n := utf8.EncodeRune(buf[len(buf):cap(buf)], r)
+ buf = buf[:len(buf)+n]
+ }
+ f.readbyte = buf
+ f.readbyteOffset = 0
+ if nw == 0 {
+ break
}
}
- for i, r := range f.readbuf {
- if utf8.RuneLen(r) > len(b) {
- f.readbuf = f.readbuf[i:]
- return n, nil
+
+ 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
}
- nr := utf8.EncodeRune(b, r)
- b = b[nr:]
- n += nr
+ b[i] = x
}
- f.readbuf = nil
- return n, nil
+ f.readbyteOffset += i
+ return i, nil
}
// read reads up to len(b) bytes from the File.
@@ -450,7 +420,7 @@ func Truncate(name string, size int64) error {
// Remove removes the named file or directory.
// If there is an error, it will be of type *PathError.
func Remove(name string) error {
- p, e := syscall.UTF16PtrFromString(name)
+ p, e := syscall.UTF16PtrFromString(fixLongPath(name))
if e != nil {
return &PathError{"remove", name, e}
}
@@ -487,7 +457,7 @@ func Remove(name string) error {
}
func rename(oldname, newname string) error {
- e := windows.Rename(oldname, newname)
+ e := windows.Rename(fixLongPath(oldname), fixLongPath(newname))
if e != nil {
return &LinkError{"rename", oldname, newname, e}
}
@@ -532,11 +502,11 @@ func TempDir() string {
// Link creates newname as a hard link to the oldname file.
// If there is an error, it will be of type *LinkError.
func Link(oldname, newname string) error {
- n, err := syscall.UTF16PtrFromString(newname)
+ n, err := syscall.UTF16PtrFromString(fixLongPath(newname))
if err != nil {
return &LinkError{"link", oldname, newname, err}
}
- o, err := syscall.UTF16PtrFromString(oldname)
+ o, err := syscall.UTF16PtrFromString(fixLongPath(oldname))
if err != nil {
return &LinkError{"link", oldname, newname, err}
}
@@ -567,11 +537,11 @@ func Symlink(oldname, newname string) error {
fi, err := Lstat(destpath)
isdir := err == nil && fi.IsDir()
- n, err := syscall.UTF16PtrFromString(newname)
+ n, err := syscall.UTF16PtrFromString(fixLongPath(newname))
if err != nil {
return &LinkError{"symlink", oldname, newname, err}
}
- o, err := syscall.UTF16PtrFromString(oldname)
+ o, err := syscall.UTF16PtrFromString(fixLongPath(oldname))
if err != nil {
return &LinkError{"symlink", oldname, newname, err}
}
@@ -587,41 +557,4 @@ func Symlink(oldname, newname string) error {
return nil
}
-func fromSlash(path string) string {
- // Replace each '/' with '\\' if present
- var pathbuf []byte
- var lastSlash int
- for i, b := range path {
- if b == '/' {
- if pathbuf == nil {
- pathbuf = make([]byte, len(path))
- }
- copy(pathbuf[lastSlash:], path[lastSlash:i])
- pathbuf[i] = '\\'
- lastSlash = i + 1
- }
- }
- if pathbuf == nil {
- return path
- }
-
- copy(pathbuf[lastSlash:], path[lastSlash:])
- return string(pathbuf)
-}
-
-func dirname(path string) string {
- vol := volumeName(path)
- i := len(path) - 1
- for i >= len(vol) && !IsPathSeparator(path[i]) {
- i--
- }
- dir := path[len(vol) : i+1]
- last := len(dir) - 1
- if last > 0 && IsPathSeparator(dir[last]) {
- dir = dir[:last]
- }
- if dir == "" {
- dir = "."
- }
- return vol + dir
-}
+const badFd = syscall.InvalidHandle
diff --git a/src/os/os_test.go b/src/os/os_test.go
index baa2f07..b1e20b7 100644
--- a/src/os/os_test.go
+++ b/src/os/os_test.go
@@ -25,8 +25,6 @@ import (
"time"
)
-var supportsSymlinks = true
-
var dot = []string{
"dir_unix.go",
"env.go",
@@ -231,6 +229,28 @@ func TestRead0(t *testing.T) {
}
}
+// Reading a closed file should should return ErrClosed error
+func TestReadClosed(t *testing.T) {
+ path := sfdir + "/" + sfname
+ file, err := Open(path)
+ if err != nil {
+ t.Fatal("open failed:", err)
+ }
+ file.Close() // close immediately
+
+ b := make([]byte, 100)
+ _, err = file.Read(b)
+
+ e, ok := err.(*PathError)
+ if !ok {
+ t.Fatalf("Read: %T(%v), want PathError", e, e)
+ }
+
+ if e.Err != ErrClosed {
+ t.Errorf("Read: %v, want PathError(ErrClosed)", e)
+ }
+}
+
func testReaddirnames(dir string, contents []string, t *testing.T) {
file, err := Open(dir)
if err != nil {
@@ -580,15 +600,8 @@ func TestReaddirOfFile(t *testing.T) {
}
func TestHardLink(t *testing.T) {
- if runtime.GOOS == "plan9" {
- t.Skip("skipping on plan9, hardlinks not supported")
- }
- // From Android release M (Marshmallow), hard linking files is blocked
- // and an attempt to call link() on a file will return EACCES.
- // - https://code.google.com/p/android-developer-preview/issues/detail?id=3150
- if runtime.GOOS == "android" {
- t.Skip("skipping on android, hardlinks not supported")
- }
+ testenv.MustHaveLink(t)
+
defer chtmpdir(t)()
from, to := "hardlinktestfrom", "hardlinktestto"
Remove(from) // Just in case.
@@ -652,14 +665,8 @@ func chtmpdir(t *testing.T) func() {
}
func TestSymlink(t *testing.T) {
- switch runtime.GOOS {
- case "android", "nacl", "plan9":
- t.Skipf("skipping on %s", runtime.GOOS)
- case "windows":
- if !supportsSymlinks {
- t.Skipf("skipping on %s", runtime.GOOS)
- }
- }
+ testenv.MustHaveSymlink(t)
+
defer chtmpdir(t)()
from, to := "symlinktestfrom", "symlinktestto"
Remove(from) // Just in case.
@@ -719,14 +726,8 @@ func TestSymlink(t *testing.T) {
}
func TestLongSymlink(t *testing.T) {
- switch runtime.GOOS {
- case "android", "plan9", "nacl":
- t.Skipf("skipping on %s", runtime.GOOS)
- case "windows":
- if !supportsSymlinks {
- t.Skipf("skipping on %s", runtime.GOOS)
- }
- }
+ testenv.MustHaveSymlink(t)
+
defer chtmpdir(t)()
s := "0123456789abcdef"
// Long, but not too long: a common limit is 255.
@@ -842,6 +843,39 @@ func TestRenameFailed(t *testing.T) {
}
}
+func TestRenameToDirFailed(t *testing.T) {
+ defer chtmpdir(t)()
+ from, to := "renamefrom", "renameto"
+
+ Remove(from)
+ Remove(to)
+ Mkdir(from, 0777)
+ Mkdir(to, 0777)
+ defer Remove(from)
+ defer Remove(to)
+
+ err := Rename(from, to)
+ switch err := err.(type) {
+ case *LinkError:
+ if err.Op != "rename" {
+ t.Errorf("rename %q, %q: err.Op: want %q, got %q", from, to, "rename", err.Op)
+ }
+ if err.Old != from {
+ t.Errorf("rename %q, %q: err.Old: want %q, got %q", from, to, from, err.Old)
+ }
+ if err.New != to {
+ t.Errorf("rename %q, %q: err.New: want %q, got %q", from, to, to, err.New)
+ }
+ case nil:
+ t.Errorf("rename %q, %q: expected error, got nil", from, to)
+
+ // cleanup whatever was placed in "renameto"
+ Remove(to)
+ default:
+ t.Errorf("rename %q, %q: expected %T, got %T %v", from, to, new(LinkError), err, err)
+ }
+}
+
func exec(t *testing.T, dir, cmd string, args []string, expect string) {
r, w, err := Pipe()
if err != nil {
@@ -1030,7 +1064,7 @@ func testChtimes(t *testing.T, name string) {
}
if !pmt.Before(mt) {
- t.Errorf("ModTime didn't go backwards; was=%d, after=%d", mt, pmt)
+ t.Errorf("ModTime didn't go backwards; was=%v, after=%v", mt, pmt)
}
}
@@ -1667,6 +1701,61 @@ func TestReadAtEOF(t *testing.T) {
}
}
+func TestLongPath(t *testing.T) {
+ tmpdir := newDir("TestLongPath", t)
+ defer func(d string) {
+ if err := RemoveAll(d); err != nil {
+ t.Fatalf("RemoveAll failed: %v", err)
+ }
+ }(tmpdir)
+ for len(tmpdir) < 400 {
+ tmpdir += "/dir3456789"
+ }
+ if err := MkdirAll(tmpdir, 0755); err != nil {
+ t.Fatalf("MkdirAll failed: %v", err)
+ }
+ data := []byte("hello world\n")
+ if err := ioutil.WriteFile(tmpdir+"/foo.txt", data, 0644); err != nil {
+ t.Fatalf("ioutil.WriteFile() failed: %v", err)
+ }
+ if err := Rename(tmpdir+"/foo.txt", tmpdir+"/bar.txt"); err != nil {
+ t.Fatalf("Rename failed: %v", err)
+ }
+ mtime := time.Now().Truncate(time.Minute)
+ if err := Chtimes(tmpdir+"/bar.txt", mtime, mtime); err != nil {
+ t.Fatalf("Chtimes failed: %v", err)
+ }
+ names := []string{"bar.txt"}
+ if testenv.HasSymlink() {
+ if err := Symlink(tmpdir+"/bar.txt", tmpdir+"/symlink.txt"); err != nil {
+ t.Fatalf("Symlink failed: %v", err)
+ }
+ names = append(names, "symlink.txt")
+ }
+ if testenv.HasLink() {
+ if err := Link(tmpdir+"/bar.txt", tmpdir+"/link.txt"); err != nil {
+ t.Fatalf("Link failed: %v", err)
+ }
+ names = append(names, "link.txt")
+ }
+ for _, wantSize := range []int64{int64(len(data)), 0} {
+ for _, name := range names {
+ path := tmpdir + "/" + name
+ dir, err := Stat(path)
+ if err != nil {
+ t.Fatalf("Stat(%q) failed: %v", path, err)
+ }
+ filesize := size(path, t)
+ if dir.Size() != filesize || filesize != wantSize {
+ t.Errorf("Size(%q) is %d, len(ReadFile()) is %d, want %d", path, dir.Size(), filesize, wantSize)
+ }
+ }
+ if err := Truncate(tmpdir+"/bar.txt", 0); err != nil {
+ t.Fatalf("Truncate failed: %v", err)
+ }
+ }
+}
+
func testKillProcess(t *testing.T, processKiller func(p *Process)) {
testenv.MustHaveExec(t)
diff --git a/src/os/os_unix_test.go b/src/os/os_unix_test.go
index 5c10154..e239835 100644
--- a/src/os/os_unix_test.go
+++ b/src/os/os_unix_test.go
@@ -7,8 +7,12 @@
package os_test
import (
+ "io"
+ "io/ioutil"
. "os"
+ "path/filepath"
"runtime"
+ "strings"
"syscall"
"testing"
)
@@ -178,3 +182,38 @@ func TestLchown(t *testing.T) {
checkUidGid(t, f.Name(), int(sys.Uid), int(sys.Gid))
}
}
+
+// Issue 16919: Readdir must return a non-empty slice or an error.
+func TestReaddirRemoveRace(t *testing.T) {
+ oldStat := *LstatP
+ defer func() { *LstatP = oldStat }()
+ *LstatP = func(name string) (FileInfo, error) {
+ if strings.HasSuffix(name, "some-file") {
+ // Act like it's been deleted.
+ return nil, ErrNotExist
+ }
+ return oldStat(name)
+ }
+ dir := newDir("TestReaddirRemoveRace", t)
+ defer RemoveAll(dir)
+ if err := ioutil.WriteFile(filepath.Join(dir, "some-file"), []byte("hello"), 0644); err != nil {
+ t.Fatal(err)
+ }
+ d, err := Open(dir)
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer d.Close()
+ fis, err := d.Readdir(2) // notably, greater than zero
+ if len(fis) == 0 && err == nil {
+ // This is what used to happen (Issue 16919)
+ t.Fatal("Readdir = empty slice & err == nil")
+ }
+ if len(fis) != 0 || err != io.EOF {
+ t.Errorf("Readdir = %d entries: %v; want 0, io.EOF", len(fis), err)
+ for i, fi := range fis {
+ t.Errorf(" entry[%d]: %q, %v", i, fi.Name(), fi.Mode())
+ }
+ t.FailNow()
+ }
+}
diff --git a/src/os/os_windows_test.go b/src/os/os_windows_test.go
index 05d7a8f..54ba99b 100644
--- a/src/os/os_windows_test.go
+++ b/src/os/os_windows_test.go
@@ -5,41 +5,24 @@
package os_test
import (
+ "fmt"
+ "internal/syscall/windows"
+ "internal/testenv"
+ "io"
"io/ioutil"
"os"
osexec "os/exec"
"path/filepath"
+ "reflect"
+ "runtime"
"sort"
"strings"
"syscall"
"testing"
+ "unicode/utf16"
+ "unsafe"
)
-var supportJunctionLinks = true
-
-func init() {
- tmpdir, err := ioutil.TempDir("", "symtest")
- if err != nil {
- panic("failed to create temp directory: " + err.Error())
- }
- defer os.RemoveAll(tmpdir)
-
- err = os.Symlink("target", filepath.Join(tmpdir, "symlink"))
- if err != nil {
- err = err.(*os.LinkError).Err
- switch err {
- case syscall.EWINDOWS, syscall.ERROR_PRIVILEGE_NOT_HELD:
- supportsSymlinks = false
- }
- }
- defer os.Remove("target")
-
- b, _ := osexec.Command("cmd", "/c", "mklink", "/?").Output()
- if !strings.Contains(string(b), " /J ") {
- supportJunctionLinks = false
- }
-}
-
func TestSameWindowsFile(t *testing.T) {
temp, err := ioutil.TempDir("", "TestSameWindowsFile")
if err != nil {
@@ -93,33 +76,423 @@ func TestSameWindowsFile(t *testing.T) {
}
}
-func TestStatJunctionLink(t *testing.T) {
- if !supportJunctionLinks {
- t.Skip("skipping because junction links are not supported")
+type dirLinkTest struct {
+ name string
+ mklink func(link, target string) error
+ issueNo int // correspondent issue number (for broken tests)
+}
+
+func testDirLinks(t *testing.T, tests []dirLinkTest) {
+ tmpdir, err := ioutil.TempDir("", "testDirLinks")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer os.RemoveAll(tmpdir)
+
+ oldwd, err := os.Getwd()
+ if err != nil {
+ t.Fatal(err)
+ }
+ err = os.Chdir(tmpdir)
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer os.Chdir(oldwd)
+
+ dir := filepath.Join(tmpdir, "dir")
+ err = os.Mkdir(dir, 0777)
+ if err != nil {
+ t.Fatal(err)
+ }
+ err = ioutil.WriteFile(filepath.Join(dir, "abc"), []byte("abc"), 0644)
+ if err != nil {
+ t.Fatal(err)
+ }
+ for _, test := range tests {
+ 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)
+ continue
+ }
+
+ data, err := ioutil.ReadFile(filepath.Join(link, "abc"))
+ if err != nil {
+ t.Errorf("failed to read abc file: %v", err)
+ continue
+ }
+ if string(data) != "abc" {
+ t.Errorf(`abc file is expected to have "abc" in it, but has %v`, data)
+ continue
+ }
+
+ if test.issueNo > 0 {
+ t.Logf("skipping broken %q test: see issue %d", test.name, test.issueNo)
+ continue
+ }
+
+ fi, 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)
+ continue
+ }
+ }
+}
+
+// reparseData is used to build reparse buffer data required for tests.
+type reparseData struct {
+ substituteName namePosition
+ printName namePosition
+ pathBuf []uint16
+}
+
+type namePosition struct {
+ offset uint16
+ length uint16
+}
+
+func (rd *reparseData) addUTF16s(s []uint16) (offset uint16) {
+ off := len(rd.pathBuf) * 2
+ rd.pathBuf = append(rd.pathBuf, s...)
+ return uint16(off)
+}
+
+func (rd *reparseData) addString(s string) (offset, length uint16) {
+ p := syscall.StringToUTF16(s)
+ return rd.addUTF16s(p), uint16(len(p)-1) * 2 // do not include terminating NUL in the legth (as per PrintNameLength and SubstituteNameLength documentation)
+}
+
+func (rd *reparseData) addSubstituteName(name string) {
+ rd.substituteName.offset, rd.substituteName.length = rd.addString(name)
+}
+
+func (rd *reparseData) addPrintName(name string) {
+ rd.printName.offset, rd.printName.length = rd.addString(name)
+}
+
+func (rd *reparseData) addStringNoNUL(s string) (offset, length uint16) {
+ p := syscall.StringToUTF16(s)
+ p = p[:len(p)-1]
+ return rd.addUTF16s(p), uint16(len(p)) * 2
+}
+
+func (rd *reparseData) addSubstituteNameNoNUL(name string) {
+ rd.substituteName.offset, rd.substituteName.length = rd.addStringNoNUL(name)
+}
+
+func (rd *reparseData) addPrintNameNoNUL(name string) {
+ rd.printName.offset, rd.printName.length = rd.addStringNoNUL(name)
+}
+
+// pathBuffeLen returns length of rd pathBuf in bytes.
+func (rd *reparseData) pathBuffeLen() uint16 {
+ return uint16(len(rd.pathBuf)) * 2
+}
+
+// Windows REPARSE_DATA_BUFFER contains union member, and cannot be
+// translated into Go directly. _REPARSE_DATA_BUFFER type is to help
+// construct alternative versions of Windows REPARSE_DATA_BUFFER with
+// union part of SymbolicLinkReparseBuffer or MountPointReparseBuffer type.
+type _REPARSE_DATA_BUFFER struct {
+ header windows.REPARSE_DATA_BUFFER_HEADER
+ detail [syscall.MAXIMUM_REPARSE_DATA_BUFFER_SIZE]byte
+}
+
+func createDirLink(link string, rdb *_REPARSE_DATA_BUFFER) error {
+ err := os.Mkdir(link, 0777)
+ if err != nil {
+ return err
+ }
+
+ linkp := syscall.StringToUTF16(link)
+ fd, err := syscall.CreateFile(&linkp[0], syscall.GENERIC_WRITE, 0, nil, syscall.OPEN_EXISTING,
+ syscall.FILE_FLAG_OPEN_REPARSE_POINT|syscall.FILE_FLAG_BACKUP_SEMANTICS, 0)
+ if err != nil {
+ return err
+ }
+ defer syscall.CloseHandle(fd)
+
+ buflen := uint32(rdb.header.ReparseDataLength) + uint32(unsafe.Sizeof(rdb.header))
+ var bytesReturned uint32
+ return syscall.DeviceIoControl(fd, windows.FSCTL_SET_REPARSE_POINT,
+ (*byte)(unsafe.Pointer(&rdb.header)), buflen, nil, 0, &bytesReturned, nil)
+}
+
+func createMountPoint(link string, target *reparseData) error {
+ var buf *windows.MountPointReparseBuffer
+ buflen := uint16(unsafe.Offsetof(buf.PathBuffer)) + target.pathBuffeLen() // see ReparseDataLength documentation
+ byteblob := make([]byte, buflen)
+ buf = (*windows.MountPointReparseBuffer)(unsafe.Pointer(&byteblob[0]))
+ buf.SubstituteNameOffset = target.substituteName.offset
+ buf.SubstituteNameLength = target.substituteName.length
+ buf.PrintNameOffset = target.printName.offset
+ buf.PrintNameLength = target.printName.length
+ copy((*[2048]uint16)(unsafe.Pointer(&buf.PathBuffer[0]))[:], target.pathBuf)
+
+ var rdb _REPARSE_DATA_BUFFER
+ rdb.header.ReparseTag = windows.IO_REPARSE_TAG_MOUNT_POINT
+ rdb.header.ReparseDataLength = buflen
+ copy(rdb.detail[:], byteblob)
+
+ return createDirLink(link, &rdb)
+}
+
+func TestDirectoryJunction(t *testing.T) {
+ var tests = []dirLinkTest{
+ {
+ // Create link similar to what mklink does, by inserting \??\ at the front of absolute target.
+ name: "standard",
+ mklink: func(link, target string) error {
+ var t reparseData
+ t.addSubstituteName(`\??\` + target)
+ t.addPrintName(target)
+ return createMountPoint(link, &t)
+ },
+ },
+ {
+ // Do as junction utility https://technet.microsoft.com/en-au/sysinternals/bb896768.aspx does - set PrintNameLength to 0.
+ name: "have_blank_print_name",
+ mklink: func(link, target string) error {
+ var t reparseData
+ t.addSubstituteName(`\??\` + target)
+ t.addPrintName("")
+ return createMountPoint(link, &t)
+ },
+ },
+ }
+ output, _ := osexec.Command("cmd", "/c", "mklink", "/?").Output()
+ mklinkSupportsJunctionLinks := strings.Contains(string(output), " /J ")
+ if mklinkSupportsJunctionLinks {
+ tests = append(tests,
+ dirLinkTest{
+ name: "use_mklink_cmd",
+ mklink: func(link, target string) error {
+ output, err := osexec.Command("cmd", "/c", "mklink", "/J", link, target).CombinedOutput()
+ if err != nil {
+ t.Errorf("failed to run mklink %v %v: %v %q", link, target, err, output)
+ }
+ return nil
+ },
+ },
+ )
+ } else {
+ t.Log(`skipping "use_mklink_cmd" test, mklink does not supports directory junctions`)
+ }
+ testDirLinks(t, tests)
+}
+
+func enableCurrentThreadPrivilege(privilegeName string) error {
+ ct, err := windows.GetCurrentThread()
+ if err != nil {
+ return err
+ }
+ var t syscall.Token
+ err = windows.OpenThreadToken(ct, syscall.TOKEN_QUERY|windows.TOKEN_ADJUST_PRIVILEGES, false, &t)
+ if err != nil {
+ return err
+ }
+ defer syscall.CloseHandle(syscall.Handle(t))
+
+ var tp windows.TOKEN_PRIVILEGES
+
+ privStr, err := syscall.UTF16PtrFromString(privilegeName)
+ if err != nil {
+ return err
+ }
+ err = windows.LookupPrivilegeValue(nil, privStr, &tp.Privileges[0].Luid)
+ if err != nil {
+ return err
+ }
+ tp.PrivilegeCount = 1
+ tp.Privileges[0].Attributes = windows.SE_PRIVILEGE_ENABLED
+ return windows.AdjustTokenPrivileges(t, false, &tp, 0, nil, nil)
+}
+
+func createSymbolicLink(link string, target *reparseData, isrelative bool) error {
+ var buf *windows.SymbolicLinkReparseBuffer
+ buflen := uint16(unsafe.Offsetof(buf.PathBuffer)) + target.pathBuffeLen() // see ReparseDataLength documentation
+ byteblob := make([]byte, buflen)
+ buf = (*windows.SymbolicLinkReparseBuffer)(unsafe.Pointer(&byteblob[0]))
+ buf.SubstituteNameOffset = target.substituteName.offset
+ buf.SubstituteNameLength = target.substituteName.length
+ buf.PrintNameOffset = target.printName.offset
+ buf.PrintNameLength = target.printName.length
+ if isrelative {
+ buf.Flags = windows.SYMLINK_FLAG_RELATIVE
+ }
+ copy((*[2048]uint16)(unsafe.Pointer(&buf.PathBuffer[0]))[:], target.pathBuf)
+
+ var rdb _REPARSE_DATA_BUFFER
+ rdb.header.ReparseTag = syscall.IO_REPARSE_TAG_SYMLINK
+ rdb.header.ReparseDataLength = buflen
+ copy(rdb.detail[:], byteblob)
+
+ return createDirLink(link, &rdb)
+}
+
+func TestDirectorySymbolicLink(t *testing.T) {
+ var tests []dirLinkTest
+ output, _ := osexec.Command("cmd", "/c", "mklink", "/?").Output()
+ mklinkSupportsDirectorySymbolicLinks := strings.Contains(string(output), " /D ")
+ if mklinkSupportsDirectorySymbolicLinks {
+ tests = append(tests,
+ dirLinkTest{
+ name: "use_mklink_cmd",
+ mklink: func(link, target string) error {
+ output, err := osexec.Command("cmd", "/c", "mklink", "/D", link, target).CombinedOutput()
+ if err != nil {
+ t.Errorf("failed to run mklink %v %v: %v %q", link, target, err, output)
+ }
+ return nil
+ },
+ },
+ )
+ } else {
+ t.Log(`skipping "use_mklink_cmd" test, mklink does not supports directory symbolic links`)
+ }
+
+ // The rest of these test requires SeCreateSymbolicLinkPrivilege to be held.
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ err := windows.ImpersonateSelf(windows.SecurityImpersonation)
+ if err != nil {
+ t.Fatal(err)
}
+ defer windows.RevertToSelf()
+
+ err = enableCurrentThreadPrivilege("SeCreateSymbolicLinkPrivilege")
+ if err != nil {
+ t.Skipf(`skipping some tests, could not enable "SeCreateSymbolicLinkPrivilege": %v`, err)
+ }
+ tests = append(tests,
+ dirLinkTest{
+ name: "use_os_pkg",
+ mklink: func(link, target string) error {
+ return os.Symlink(target, link)
+ },
+ },
+ dirLinkTest{
+ // Create link similar to what mklink does, by inserting \??\ at the front of absolute target.
+ name: "standard",
+ mklink: func(link, target string) error {
+ var t reparseData
+ t.addPrintName(target)
+ t.addSubstituteName(`\??\` + target)
+ return createSymbolicLink(link, &t, false)
+ },
+ },
+ dirLinkTest{
+ name: "relative",
+ mklink: func(link, target string) error {
+ var t reparseData
+ t.addSubstituteNameNoNUL(filepath.Base(target))
+ t.addPrintNameNoNUL(filepath.Base(target))
+ return createSymbolicLink(link, &t, true)
+ },
+ },
+ )
+ testDirLinks(t, tests)
+}
+
+func TestNetworkSymbolicLink(t *testing.T) {
+ testenv.MustHaveSymlink(t)
- dir, err := ioutil.TempDir("", "go-build")
+ dir, err := ioutil.TempDir("", "TestNetworkSymbolicLink")
if err != nil {
- t.Fatalf("failed to create temp directory: %v", err)
+ t.Fatal(err)
}
defer os.RemoveAll(dir)
- link := filepath.Join(filepath.Dir(dir), filepath.Base(dir)+"-link")
+ oldwd, err := os.Getwd()
+ if err != nil {
+ t.Fatal(err)
+ }
+ err = os.Chdir(dir)
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer os.Chdir(oldwd)
+
+ shareName := "GoSymbolicLinkTestShare" // hope no conflictions
+ sharePath := filepath.Join(dir, shareName)
+ testDir := "TestDir"
+
+ err = os.MkdirAll(filepath.Join(sharePath, testDir), 0777)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ wShareName, err := syscall.UTF16PtrFromString(shareName)
+ if err != nil {
+ t.Fatal(err)
+ }
+ wSharePath, err := syscall.UTF16PtrFromString(sharePath)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ p := windows.SHARE_INFO_2{
+ Netname: wShareName,
+ Type: windows.STYPE_DISKTREE,
+ Remark: nil,
+ Permissions: 0,
+ MaxUses: 1,
+ CurrentUses: 0,
+ Path: wSharePath,
+ Passwd: nil,
+ }
+
+ err = windows.NetShareAdd(nil, 2, (*byte)(unsafe.Pointer(&p)), nil)
+ if err != nil {
+ if err == syscall.ERROR_ACCESS_DENIED {
+ t.Skip("you don't have enough privileges to add network share")
+ }
+ t.Fatal(err)
+ }
+ defer func() {
+ err := windows.NetShareDel(nil, wShareName, 0)
+ if err != nil {
+ t.Fatal(err)
+ }
+ }()
+
+ UNCPath := `\\localhost\` + shareName + `\`
- output, err := osexec.Command("cmd", "/c", "mklink", "/J", link, dir).CombinedOutput()
+ fi1, err := os.Stat(sharePath)
if err != nil {
- t.Fatalf("failed to run mklink %v %v: %v %q", link, dir, err, output)
+ t.Fatal(err)
+ }
+ fi2, err := os.Stat(UNCPath)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if !os.SameFile(fi1, fi2) {
+ t.Fatalf("%q and %q should be the same directory, but not", sharePath, UNCPath)
+ }
+
+ target := filepath.Join(UNCPath, testDir)
+ link := "link"
+
+ err = os.Symlink(target, link)
+ if err != nil {
+ t.Fatal(err)
}
defer os.Remove(link)
- fi, err := os.Stat(link)
+ got, err := os.Readlink(link)
if err != nil {
- t.Fatalf("failed to stat link %v: %v", link, err)
+ t.Fatal(err)
}
- expected := filepath.Base(dir)
- got := fi.Name()
- if !fi.IsDir() || expected != got {
- t.Fatalf("link should point to %v but points to %v instead", expected, got)
+
+ if got != target {
+ t.Errorf(`os.Readlink("%s"): got %v, want %v`, link, got, target)
}
}
@@ -245,3 +618,107 @@ func TestDeleteReadOnly(t *testing.T) {
t.Fatal(err)
}
}
+
+func TestStatSymlinkLoop(t *testing.T) {
+ testenv.MustHaveSymlink(t)
+
+ defer chtmpdir(t)()
+
+ err := os.Symlink("x", "y")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer os.Remove("y")
+
+ err = os.Symlink("y", "x")
+ if err != nil {
+ t.Fatal(err)
+ }
+ 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)
+ }
+}
+
+func TestReadStdin(t *testing.T) {
+ old := *os.ReadConsoleFunc
+ defer func() {
+ *os.ReadConsoleFunc = old
+ }()
+
+ testConsole := os.NewConsoleFile(syscall.Stdin, "test")
+
+ var tests = []string{
+ "abc",
+ "äöü",
+ "\u3042",
+ "“hi”™",
+ "hello\x1aworld",
+ "\U0001F648\U0001F649\U0001F64A",
+ }
+
+ for _, consoleSize := range []int{1, 2, 3, 10, 16, 100, 1000} {
+ for _, readSize := range []int{1, 2, 3, 4, 5, 8, 10, 16, 20, 50, 100} {
+ 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 {
+ if inputControl != nil {
+ t.Fatalf("inputControl not nil")
+ }
+ n := int(toread)
+ if n > consoleSize {
+ n = consoleSize
+ }
+ n = copy((*[10000]uint16)(unsafe.Pointer(buf))[:n], s16)
+ s16 = s16[n:]
+ *read = uint32(n)
+ t.Logf("read %d -> %d", toread, *read)
+ return nil
+ }
+
+ var all []string
+ var buf []byte
+ chunk := make([]byte, readSize)
+ for {
+ n, err := testConsole.Read(chunk)
+ buf = append(buf, chunk[:n]...)
+ if err == io.EOF {
+ all = append(all, string(buf))
+ if len(all) >= 5 {
+ break
+ }
+ buf = buf[:0]
+ } else if err != nil {
+ t.Fatalf("reading %q: error: %v", s, err)
+ }
+ if len(buf) >= 2000 {
+ t.Fatalf("reading %q: stuck in loop: %q", s, buf)
+ }
+ }
+
+ want := strings.Split(s, "\x1a")
+ for len(want) < 5 {
+ want = append(want, "")
+ }
+ if !reflect.DeepEqual(all, want) {
+ t.Errorf("reading %q:\nhave %x\nwant %x", s, all, want)
+ }
+ })
+ }
+ }
+ }
+}
+
+func TestStatPagefile(t *testing.T) {
+ _, err := os.Stat(`c:\pagefile.sys`)
+ if err == nil {
+ return
+ }
+ if os.IsNotExist(err) {
+ t.Skip(`skipping because c:\pagefile.sys is not found`)
+ }
+ t.Fatal(err)
+}
diff --git a/src/os/path_test.go b/src/os/path_test.go
index 51dc25b..6f5bfa5 100644
--- a/src/os/path_test.go
+++ b/src/os/path_test.go
@@ -5,6 +5,7 @@
package os_test
import (
+ "internal/testenv"
"io/ioutil"
. "os"
"path/filepath"
@@ -169,14 +170,7 @@ func TestRemoveAll(t *testing.T) {
}
func TestMkdirAllWithSymlink(t *testing.T) {
- switch runtime.GOOS {
- case "android", "nacl", "plan9":
- t.Skipf("skipping on %s", runtime.GOOS)
- case "windows":
- if !supportsSymlinks {
- t.Skipf("skipping on %s", runtime.GOOS)
- }
- }
+ testenv.MustHaveSymlink(t)
tmpDir, err := ioutil.TempDir("", "TestMkdirAllWithSymlink-")
if err != nil {
diff --git a/src/os/path_unix.go b/src/os/path_unix.go
index 36f8e61..ecf098c 100644
--- a/src/os/path_unix.go
+++ b/src/os/path_unix.go
@@ -15,3 +15,21 @@ const (
func IsPathSeparator(c uint8) bool {
return PathSeparator == c
}
+
+// basename removes trailing slashes and the leading directory name from path name
+func basename(name string) string {
+ i := len(name) - 1
+ // Remove trailing slashes
+ for ; i > 0 && name[i] == '/'; i-- {
+ name = name[:i]
+ }
+ // Remove leading directory name
+ for i--; i >= 0; i-- {
+ if name[i] == '/' {
+ name = name[i+1:]
+ break
+ }
+ }
+
+ return name
+}
diff --git a/src/os/path_windows.go b/src/os/path_windows.go
index c96f137..ccac1c0 100644
--- a/src/os/path_windows.go
+++ b/src/os/path_windows.go
@@ -14,3 +14,193 @@ func IsPathSeparator(c uint8) bool {
// NOTE: Windows accept / as path separator.
return c == '\\' || c == '/'
}
+
+// basename removes trailing slashes and the leading
+// directory name and drive letter from path name.
+func basename(name string) string {
+ // Remove drive letter
+ if len(name) == 2 && name[1] == ':' {
+ name = "."
+ } else if len(name) > 2 && name[1] == ':' {
+ name = name[2:]
+ }
+ i := len(name) - 1
+ // Remove trailing slashes
+ for ; i > 0 && (name[i] == '/' || name[i] == '\\'); i-- {
+ name = name[:i]
+ }
+ // Remove leading directory name
+ for i--; i >= 0; i-- {
+ if name[i] == '/' || name[i] == '\\' {
+ name = name[i+1:]
+ break
+ }
+ }
+ return name
+}
+
+func isAbs(path string) (b bool) {
+ v := volumeName(path)
+ if v == "" {
+ return false
+ }
+ path = path[len(v):]
+ if path == "" {
+ return false
+ }
+ return IsPathSeparator(path[0])
+}
+
+func volumeName(path string) (v string) {
+ if len(path) < 2 {
+ return ""
+ }
+ // with drive letter
+ c := path[0]
+ if path[1] == ':' &&
+ ('0' <= c && c <= '9' || 'a' <= c && c <= 'z' ||
+ 'A' <= c && c <= 'Z') {
+ return path[:2]
+ }
+ // is it UNC
+ if l := len(path); l >= 5 && IsPathSeparator(path[0]) && IsPathSeparator(path[1]) &&
+ !IsPathSeparator(path[2]) && path[2] != '.' {
+ // first, leading `\\` and next shouldn't be `\`. its server name.
+ for n := 3; n < l-1; n++ {
+ // second, next '\' shouldn't be repeated.
+ if IsPathSeparator(path[n]) {
+ n++
+ // third, following something characters. its share name.
+ if !IsPathSeparator(path[n]) {
+ if path[n] == '.' {
+ break
+ }
+ for ; n < l; n++ {
+ if IsPathSeparator(path[n]) {
+ break
+ }
+ }
+ return path[:n]
+ }
+ break
+ }
+ }
+ }
+ return ""
+}
+
+func fromSlash(path string) string {
+ // Replace each '/' with '\\' if present
+ var pathbuf []byte
+ var lastSlash int
+ for i, b := range path {
+ if b == '/' {
+ if pathbuf == nil {
+ pathbuf = make([]byte, len(path))
+ }
+ copy(pathbuf[lastSlash:], path[lastSlash:i])
+ pathbuf[i] = '\\'
+ lastSlash = i + 1
+ }
+ }
+ if pathbuf == nil {
+ return path
+ }
+
+ copy(pathbuf[lastSlash:], path[lastSlash:])
+ return string(pathbuf)
+}
+
+func dirname(path string) string {
+ vol := volumeName(path)
+ i := len(path) - 1
+ for i >= len(vol) && !IsPathSeparator(path[i]) {
+ i--
+ }
+ dir := path[len(vol) : i+1]
+ last := len(dir) - 1
+ if last > 0 && IsPathSeparator(dir[last]) {
+ dir = dir[:last]
+ }
+ if dir == "" {
+ dir = "."
+ }
+ return vol + dir
+}
+
+// fixLongPath returns the extended-length (\\?\-prefixed) form of
+// path when needed, in order to avoid the default 260 character file
+// path limit imposed by Windows. If path is not easily converted to
+// the extended-length form (for example, if path is a relative path
+// or contains .. elements), or is short enough, fixLongPath returns
+// path unmodified.
+//
+// See https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx#maxpath
+func fixLongPath(path string) string {
+ // Do nothing (and don't allocate) if the path is "short".
+ // Empirically (at least on the Windows Server 2013 builder),
+ // the kernel is arbitrarily okay with <= 248 bytes. That
+ // matches what the docs above say:
+ // "When using an API to create a directory, the specified
+ // path cannot be so long that you cannot append an 8.3 file
+ // name (that is, the directory name cannot exceed MAX_PATH
+ // minus 12)." Since MAX_PATH is 260, 260 - 12 = 248.
+ if len(path) <= 248 {
+ // Don't fix. (This is how Go 1.7 and earlier worked,
+ // not automatically generating the \\?\ form)
+ return path
+ }
+
+ // The extended form begins with \\?\, as in
+ // \\?\c:\windows\foo.txt or \\?\UNC\server\share\foo.txt.
+ // The extended form disables evaluation of . and .. path
+ // elements and disables the interpretation of / as equivalent
+ // to \. The conversion here rewrites / to \ and elides
+ // . elements as well as trailing or duplicate separators. For
+ // simplicity it avoids the conversion entirely for relative
+ // paths or paths containing .. elements. For now,
+ // \\server\share paths are not converted to
+ // \\?\UNC\server\share paths because the rules for doing so
+ // are less well-specified.
+ if len(path) >= 2 && path[:2] == `\\` {
+ // Don't canonicalize UNC paths.
+ return path
+ }
+ if !isAbs(path) {
+ // Relative path
+ return path
+ }
+
+ const prefix = `\\?`
+
+ pathbuf := make([]byte, len(prefix)+len(path)+len(`\`))
+ copy(pathbuf, prefix)
+ n := len(path)
+ r, w := 0, len(prefix)
+ for r < n {
+ switch {
+ case IsPathSeparator(path[r]):
+ // empty block
+ r++
+ case path[r] == '.' && (r+1 == n || IsPathSeparator(path[r+1])):
+ // /./
+ r++
+ case r+1 < n && path[r] == '.' && path[r+1] == '.' && (r+2 == n || IsPathSeparator(path[r+2])):
+ // /../ is currently unhandled
+ return path
+ default:
+ pathbuf[w] = '\\'
+ w++
+ for ; r < n && !IsPathSeparator(path[r]); r++ {
+ pathbuf[w] = path[r]
+ w++
+ }
+ }
+ }
+ // A drive's root directory needs a trailing \
+ if w == len(`\\?\c:`) {
+ pathbuf[w] = '\\'
+ w++
+ }
+ return string(pathbuf[:w])
+}
diff --git a/src/os/path_windows_test.go b/src/os/path_windows_test.go
new file mode 100644
index 0000000..cce0bdd
--- /dev/null
+++ b/src/os/path_windows_test.go
@@ -0,0 +1,46 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package os_test
+
+import (
+ "os"
+ "strings"
+ "testing"
+)
+
+func TestFixLongPath(t *testing.T) {
+ // 248 is long enough to trigger the longer-than-248 checks in
+ // fixLongPath, but short enough not to make a path component
+ // longer than 255, which is illegal on Windows. (which
+ // doesn't really matter anyway, since this is purely a string
+ // function we're testing, and it's not actually being used to
+ // do a system call)
+ veryLong := "l" + strings.Repeat("o", 248) + "ng"
+ for _, test := range []struct{ in, want string }{
+ // Short; unchanged:
+ {`C:\short.txt`, `C:\short.txt`},
+ {`C:\`, `C:\`},
+ {`C:`, `C:`},
+ // The "long" substring is replaced by a looooooong
+ // string which triggers the rewriting. Except in the
+ // cases below where it doesn't.
+ {`C:\long\foo.txt`, `\\?\C:\long\foo.txt`},
+ {`C:/long/foo.txt`, `\\?\C:\long\foo.txt`},
+ {`C:\long\foo\\bar\.\baz\\`, `\\?\C:\long\foo\bar\baz`},
+ {`\\unc\path`, `\\unc\path`},
+ {`long.txt`, `long.txt`},
+ {`C:long.txt`, `C:long.txt`},
+ {`c:\long\..\bar\baz`, `c:\long\..\bar\baz`},
+ {`\\?\c:\long\foo.txt`, `\\?\c:\long\foo.txt`},
+ {`\\?\c:\long/foo.txt`, `\\?\c:\long/foo.txt`},
+ } {
+ in := strings.Replace(test.in, "long", veryLong, -1)
+ want := strings.Replace(test.want, "long", veryLong, -1)
+ if got := os.FixLongPath(in); got != want {
+ got = strings.Replace(got, veryLong, "long", -1)
+ t.Errorf("fixLongPath(%q) = %q; want %q", test.in, got, test.want)
+ }
+ }
+}
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_windows_test.go b/src/os/signal/signal_windows_test.go
index f3e6706..c2b5901 100644
--- a/src/os/signal/signal_windows_test.go
+++ b/src/os/signal/signal_windows_test.go
@@ -6,6 +6,7 @@ package signal
import (
"bytes"
+ "internal/testenv"
"io/ioutil"
"os"
"os/exec"
@@ -75,7 +76,7 @@ func main() {
// compile it
exe := name + ".exe"
defer os.Remove(exe)
- o, err := exec.Command("go", "build", "-o", exe, src).CombinedOutput()
+ o, err := exec.Command(testenv.GoToolPath(t), "build", "-o", exe, src).CombinedOutput()
if err != nil {
t.Fatalf("Failed to compile: %v\n%v", err, string(o))
}
diff --git a/src/os/stat_plan9.go b/src/os/stat_plan9.go
index 96f056c..274d0d8 100644
--- a/src/os/stat_plan9.go
+++ b/src/os/stat_plan9.go
@@ -11,12 +11,6 @@ import (
const _BIT16SZ = 2
-func sameFile(fs1, fs2 *fileStat) bool {
- a := fs1.sys.(*syscall.Dir)
- b := fs2.sys.(*syscall.Dir)
- return a.Qid.Path == b.Qid.Path && a.Type == b.Type && a.Dev == b.Dev
-}
-
func fileInfoFromStat(d *syscall.Dir) FileInfo {
fs := &fileStat{
name: d.Name,
@@ -37,6 +31,10 @@ func fileInfoFromStat(d *syscall.Dir) FileInfo {
if d.Mode&syscall.DMTMP != 0 {
fs.mode |= ModeTemporary
}
+ // Consider all files not served by #M as device files.
+ if d.Type != 'M' {
+ fs.mode |= ModeDevice
+ }
return fs
}
diff --git a/src/os/stat_unix.go b/src/os/stat_unix.go
new file mode 100644
index 0000000..1733d3f
--- /dev/null
+++ b/src/os/stat_unix.go
@@ -0,0 +1,52 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
+
+package os
+
+import (
+ "syscall"
+)
+
+// Stat returns the FileInfo structure describing file.
+// If there is an error, it will be of type *PathError.
+func (f *File) Stat() (FileInfo, error) {
+ if f == nil {
+ return nil, ErrInvalid
+ }
+ var fs fileStat
+ err := syscall.Fstat(f.fd, &fs.sys)
+ if err != nil {
+ return nil, &PathError{"stat", f.name, err}
+ }
+ fillFileStatFromSys(&fs, f.name)
+ return &fs, nil
+}
+
+// Stat returns a FileInfo describing the named file.
+// If there is an error, it will be of type *PathError.
+func Stat(name string) (FileInfo, error) {
+ var fs fileStat
+ err := syscall.Stat(name, &fs.sys)
+ if err != nil {
+ return nil, &PathError{"stat", name, err}
+ }
+ fillFileStatFromSys(&fs, name)
+ return &fs, nil
+}
+
+// Lstat returns a FileInfo describing the named file.
+// If the file is a symbolic link, the returned FileInfo
+// describes the symbolic link. Lstat makes no attempt to follow the link.
+// If there is an error, it will be of type *PathError.
+func Lstat(name string) (FileInfo, error) {
+ var fs fileStat
+ err := syscall.Lstat(name, &fs.sys)
+ if err != nil {
+ return nil, &PathError{"lstat", name, err}
+ }
+ fillFileStatFromSys(&fs, name)
+ return &fs, nil
+}
diff --git a/src/os/stat_windows.go b/src/os/stat_windows.go
index e55eeb0..fdabf73 100644
--- a/src/os/stat_windows.go
+++ b/src/os/stat_windows.go
@@ -5,6 +5,7 @@
package os
import (
+ "internal/syscall/windows"
"syscall"
"unsafe"
)
@@ -61,7 +62,7 @@ func (file *File) Stat() (FileInfo, error) {
func Stat(name string) (FileInfo, error) {
var fi FileInfo
var err error
- for {
+ for i := 0; i < 255; i++ {
fi, err = Lstat(name)
if err != nil {
return fi, err
@@ -74,6 +75,7 @@ func Stat(name string) (FileInfo, error) {
return fi, err
}
}
+ return nil, &PathError{"Stat", name, syscall.ELOOP}
}
// Lstat returns the FileInfo structure describing the named file.
@@ -88,13 +90,29 @@ func Lstat(name string) (FileInfo, error) {
return &devNullStat, nil
}
fs := &fileStat{name: basename(name)}
- namep, e := syscall.UTF16PtrFromString(name)
+ namep, e := syscall.UTF16PtrFromString(fixLongPath(name))
if e != nil {
return nil, &PathError{"Lstat", name, e}
}
e = syscall.GetFileAttributesEx(namep, syscall.GetFileExInfoStandard, (*byte)(unsafe.Pointer(&fs.sys)))
if e != nil {
- return nil, &PathError{"GetFileAttributesEx", name, e}
+ if e != windows.ERROR_SHARING_VIOLATION {
+ 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
}
fs.path = name
if !isAbs(fs.path) {
@@ -105,77 +123,3 @@ func Lstat(name string) (FileInfo, error) {
}
return fs, nil
}
-
-// basename removes trailing slashes and the leading
-// directory name and drive letter from path name.
-func basename(name string) string {
- // Remove drive letter
- if len(name) == 2 && name[1] == ':' {
- name = "."
- } else if len(name) > 2 && name[1] == ':' {
- name = name[2:]
- }
- i := len(name) - 1
- // Remove trailing slashes
- for ; i > 0 && (name[i] == '/' || name[i] == '\\'); i-- {
- name = name[:i]
- }
- // Remove leading directory name
- for i--; i >= 0; i-- {
- if name[i] == '/' || name[i] == '\\' {
- name = name[i+1:]
- break
- }
- }
- return name
-}
-
-func isAbs(path string) (b bool) {
- v := volumeName(path)
- if v == "" {
- return false
- }
- path = path[len(v):]
- if path == "" {
- return false
- }
- return IsPathSeparator(path[0])
-}
-
-func volumeName(path string) (v string) {
- if len(path) < 2 {
- return ""
- }
- // with drive letter
- c := path[0]
- if path[1] == ':' &&
- ('0' <= c && c <= '9' || 'a' <= c && c <= 'z' ||
- 'A' <= c && c <= 'Z') {
- return path[:2]
- }
- // is it UNC
- if l := len(path); l >= 5 && IsPathSeparator(path[0]) && IsPathSeparator(path[1]) &&
- !IsPathSeparator(path[2]) && path[2] != '.' {
- // first, leading `\\` and next shouldn't be `\`. its server name.
- for n := 3; n < l-1; n++ {
- // second, next '\' shouldn't be repeated.
- if IsPathSeparator(path[n]) {
- n++
- // third, following something characters. its share name.
- if !IsPathSeparator(path[n]) {
- if path[n] == '.' {
- break
- }
- for ; n < l; n++ {
- if IsPathSeparator(path[n]) {
- break
- }
- }
- return path[:n]
- }
- break
- }
- }
- }
- return ""
-}
diff --git a/src/os/sys.go b/src/os/sys.go
new file mode 100644
index 0000000..28b0f6b
--- /dev/null
+++ b/src/os/sys.go
@@ -0,0 +1,10 @@
+// Copyright 2012 The Go Authors. 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
+
+// Hostname returns the host name reported by the kernel.
+func Hostname() (name string, err error) {
+ return hostname()
+}
diff --git a/src/os/types.go b/src/os/types.go
index 12b593f..c565483 100644
--- a/src/os/types.go
+++ b/src/os/types.go
@@ -12,6 +12,11 @@ import (
// Getpagesize returns the underlying system's memory page size.
func Getpagesize() int { return syscall.Getpagesize() }
+// File represents an open file descriptor.
+type File struct {
+ *file // os specific
+}
+
// A FileInfo describes a file and is returned by Stat and Lstat.
type FileInfo interface {
Name() string // base name of the file
diff --git a/src/os/types_plan9.go b/src/os/types_plan9.go
index 6d46ca9..125da66 100644
--- a/src/os/types_plan9.go
+++ b/src/os/types_plan9.go
@@ -4,7 +4,10 @@
package os
-import "time"
+import (
+ "syscall"
+ "time"
+)
// A fileStat is the implementation of FileInfo returned by Stat and Lstat.
type fileStat struct {
@@ -19,3 +22,11 @@ func (fs *fileStat) Size() int64 { return fs.size }
func (fs *fileStat) Mode() FileMode { return fs.mode }
func (fs *fileStat) ModTime() time.Time { return fs.modTime }
func (fs *fileStat) Sys() interface{} { return fs.sys }
+
+func sameFile(fs1, fs2 *fileStat) bool {
+ a := fs1.sys.(*syscall.Dir)
+ b := fs2.sys.(*syscall.Dir)
+ return a.Qid.Path == b.Qid.Path && a.Type == b.Type && a.Dev == b.Dev
+}
+
+const badFd = -1
diff --git a/src/os/types_unix.go b/src/os/types_unix.go
index 056220c..1f61481 100644
--- a/src/os/types_unix.go
+++ b/src/os/types_unix.go
@@ -25,3 +25,9 @@ func (fs *fileStat) Size() int64 { return fs.size }
func (fs *fileStat) Mode() FileMode { return fs.mode }
func (fs *fileStat) ModTime() time.Time { return fs.modTime }
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/wait_wait6.go b/src/os/wait_wait6.go
index 7f4780a..b309811 100644
--- a/src/os/wait_wait6.go
+++ b/src/os/wait_wait6.go
@@ -28,6 +28,7 @@ func (p *Process) blockUntilWaitable() (bool, error) {
} else {
_, _, errno = syscall.Syscall6(syscall.SYS_WAIT6, _P_PID, uintptr(p.Pid), 0, syscall.WEXITED|syscall.WNOWAIT, 0, 0)
}
+ runtime.KeepAlive(p)
if errno != 0 {
// The wait6 system call is supported only on FreeBSD
// 9.3 and above, so it may return an ENOSYS error.
diff --git a/src/os/wait_waitid.go b/src/os/wait_waitid.go
index 74b7494..653fce9 100644
--- a/src/os/wait_waitid.go
+++ b/src/os/wait_waitid.go
@@ -26,7 +26,7 @@ func (p *Process) blockUntilWaitable() (bool, error) {
var siginfo [128]byte
psig := &siginfo[0]
_, _, e := syscall.Syscall6(syscall.SYS_WAITID, _P_PID, uintptr(p.Pid), uintptr(unsafe.Pointer(psig)), syscall.WEXITED|syscall.WNOWAIT, 0, 0)
- runtime.KeepAlive(psig)
+ runtime.KeepAlive(p)
if e != 0 {
// waitid has been available since Linux 2.6.9, but
// reportedly is not available in Ubuntu on Windows.
diff --git a/src/path/filepath/match.go b/src/path/filepath/match.go
index 9fa68f5..5168e03 100644
--- a/src/path/filepath/match.go
+++ b/src/path/filepath/match.go
@@ -240,13 +240,14 @@ func Glob(pattern string) (matches []string, err error) {
}
dir, file := Split(pattern)
+ volumeLen := 0
if runtime.GOOS == "windows" {
- dir = cleanGlobPathWindows(dir)
+ volumeLen, dir = cleanGlobPathWindows(dir)
} else {
dir = cleanGlobPath(dir)
}
- if !hasMeta(dir) {
+ if !hasMeta(dir[volumeLen:]) {
return glob(dir, file, nil)
}
@@ -283,18 +284,21 @@ func cleanGlobPath(path string) string {
}
// cleanGlobPathWindows is windows version of cleanGlobPath.
-func cleanGlobPathWindows(path string) string {
+func cleanGlobPathWindows(path string) (prefixLen int, cleaned string) {
vollen := volumeNameLen(path)
switch {
case path == "":
- return "."
+ return 0, "."
case vollen+1 == len(path) && os.IsPathSeparator(path[len(path)-1]): // /, \, C:\ and C:/
// do nothing to the path
- return path
+ return vollen + 1, path
case vollen == len(path) && len(path) == 2: // C:
- return path + "." // convert C: into C:.
+ return vollen, path + "." // convert C: into C:.
default:
- return path[0 : len(path)-1] // chop off trailing separator
+ if vollen >= len(path) {
+ vollen = len(path) - 1
+ }
+ return vollen, path[0 : len(path)-1] // chop off trailing separator
}
}
diff --git a/src/path/filepath/match_test.go b/src/path/filepath/match_test.go
index 6b068c7..3bd5598 100644
--- a/src/path/filepath/match_test.go
+++ b/src/path/filepath/match_test.go
@@ -6,6 +6,7 @@ package filepath_test
import (
"fmt"
+ "internal/testenv"
"io/ioutil"
"os"
. "path/filepath"
@@ -174,15 +175,7 @@ var globSymlinkTests = []struct {
}
func TestGlobSymlink(t *testing.T) {
- switch runtime.GOOS {
- case "android", "nacl", "plan9":
- t.Skipf("skipping on %s", runtime.GOOS)
- case "windows":
- if !supportsSymlinks {
- t.Skipf("skipping on %s", runtime.GOOS)
- }
-
- }
+ testenv.MustHaveSymlink(t)
tmpDir, err := ioutil.TempDir("", "globsymlink")
if err != nil {
diff --git a/src/path/filepath/path.go b/src/path/filepath/path.go
index 0dc559c..1d8e35c 100644
--- a/src/path/filepath/path.go
+++ b/src/path/filepath/path.go
@@ -177,7 +177,7 @@ func FromSlash(path string) string {
// SplitList splits a list of paths joined by the OS-specific ListSeparator,
// usually found in PATH or GOPATH environment variables.
// Unlike strings.Split, SplitList returns an empty slice when passed an empty
-// string. SplitList does not replace slash characters in the returned paths.
+// string.
func SplitList(path string) []string {
return splitList(path)
}
@@ -393,9 +393,14 @@ func walk(path string, info os.FileInfo, walkFn WalkFunc) error {
func Walk(root string, walkFn WalkFunc) error {
info, err := os.Lstat(root)
if err != nil {
- return walkFn(root, nil, err)
+ err = walkFn(root, nil, err)
+ } else {
+ err = walk(root, info, walkFn)
}
- return walk(root, info, walkFn)
+ if err == SkipDir {
+ return nil
+ }
+ return err
}
// readDirNames reads the directory named by dirname and returns
diff --git a/src/path/filepath/path_test.go b/src/path/filepath/path_test.go
index a3990e2..921b238 100644
--- a/src/path/filepath/path_test.go
+++ b/src/path/filepath/path_test.go
@@ -6,6 +6,7 @@ package filepath_test
import (
"errors"
+ "internal/testenv"
"io/ioutil"
"os"
"path/filepath"
@@ -15,8 +16,6 @@ import (
"testing"
)
-var supportsSymlinks = true
-
type PathTest struct {
path, result string
}
@@ -529,7 +528,7 @@ func TestWalkSkipDirOnFile(t *testing.T) {
touch(t, filepath.Join(td, "dir/foo2"))
sawFoo2 := false
- filepath.Walk(td, func(path string, info os.FileInfo, err error) error {
+ walker := func(path string, info os.FileInfo, err error) error {
if strings.HasSuffix(path, "foo2") {
sawFoo2 = true
}
@@ -537,8 +536,20 @@ func TestWalkSkipDirOnFile(t *testing.T) {
return filepath.SkipDir
}
return nil
- })
+ }
+
+ err = filepath.Walk(td, walker)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if sawFoo2 {
+ t.Errorf("SkipDir on file foo1 did not block processing of foo2")
+ }
+ err = filepath.Walk(filepath.Join(td, "dir"), walker)
+ if err != nil {
+ t.Fatal(err)
+ }
if sawFoo2 {
t.Errorf("SkipDir on file foo1 did not block processing of foo2")
}
@@ -776,13 +787,7 @@ func simpleJoin(dir, path string) string {
}
func TestEvalSymlinks(t *testing.T) {
- switch runtime.GOOS {
- case "android", "nacl", "plan9":
- t.Skipf("skipping on %s", runtime.GOOS)
- }
- if !supportsSymlinks {
- t.Skip("skipping because symlinks are not supported")
- }
+ testenv.MustHaveSymlink(t)
tmpDir, err := ioutil.TempDir("", "evalsymlink")
if err != nil {
@@ -872,6 +877,40 @@ func TestEvalSymlinks(t *testing.T) {
t.Errorf(`EvalSymlinks(".") in %q directory returns %q, want "." or %q`, d.path, p, want)
}()
+ // test EvalSymlinks("C:.") on Windows
+ if runtime.GOOS == "windows" {
+ func() {
+ defer func() {
+ err := os.Chdir(wd)
+ if err != nil {
+ t.Fatal(err)
+ }
+ }()
+
+ err := os.Chdir(path)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+
+ volDot := filepath.VolumeName(tmpDir) + "."
+
+ p, err := filepath.EvalSymlinks(volDot)
+ if err != nil {
+ t.Errorf(`EvalSymlinks("%s") in %q directory error: %v`, volDot, d.path, err)
+ return
+ }
+ if p == volDot {
+ return
+ }
+ want := filepath.Clean(findEvalSymlinksTestDirsDest(t, testdirs, d.path))
+ if p == want {
+ return
+ }
+ t.Errorf(`EvalSymlinks("%s") in %q directory returns %q, want %q or %q`, volDot, d.path, p, volDot, want)
+ }()
+ }
+
// test EvalSymlinks(".."+path)
func() {
defer func() {
@@ -923,14 +962,30 @@ func TestEvalSymlinks(t *testing.T) {
}
}
-func TestIssue13582(t *testing.T) {
- switch runtime.GOOS {
- case "android", "nacl", "plan9":
- t.Skipf("skipping on %s", runtime.GOOS)
+func TestEvalSymlinksIsNotExist(t *testing.T) {
+ testenv.MustHaveSymlink(t)
+
+ defer chtmpdir(t)()
+
+ _, err := filepath.EvalSymlinks("notexist")
+ if !os.IsNotExist(err) {
+ t.Errorf("expected the file is not found, got %v\n", err)
+ }
+
+ err = os.Symlink("notexist", "link")
+ if err != nil {
+ t.Fatal(err)
}
- if !supportsSymlinks {
- t.Skip("skipping because symlinks are not supported")
+ defer os.Remove("link")
+
+ _, err = filepath.EvalSymlinks("link")
+ if !os.IsNotExist(err) {
+ t.Errorf("expected the file is not found, got %v\n", err)
}
+}
+
+func TestIssue13582(t *testing.T) {
+ testenv.MustHaveSymlink(t)
tmpDir, err := ioutil.TempDir("", "issue13582")
if err != nil {
@@ -1006,13 +1061,16 @@ var absTestDirs = []string{
var absTests = []string{
".",
"b",
+ "b/",
"../a",
"../a/b",
"../a/b/./c/../../.././a",
+ "../a/b/./c/../../.././a/",
"$",
"$/.",
"$/a/../a/b",
"$/a/b/c/../../.././a",
+ "$/a/b/c/../../.././a/",
}
func TestAbs(t *testing.T) {
@@ -1077,7 +1135,7 @@ func TestAbs(t *testing.T) {
if !filepath.IsAbs(abspath) {
t.Errorf("Abs(%q)=%q, not an absolute path", path, abspath)
}
- if filepath.IsAbs(path) && abspath != filepath.Clean(path) {
+ if filepath.IsAbs(abspath) && abspath != filepath.Clean(abspath) {
t.Errorf("Abs(%q)=%q, isn't clean", path, abspath)
}
}
@@ -1240,11 +1298,11 @@ func TestBug3486(t *testing.T) { // https://golang.org/issue/3486
if err != nil {
t.Fatal(err)
}
- bugs := filepath.Join(root, "bugs")
+ bugs := filepath.Join(root, "fixedbugs")
ken := filepath.Join(root, "ken")
seenBugs := false
seenKen := false
- filepath.Walk(root, func(pth string, info os.FileInfo, err error) error {
+ err = filepath.Walk(root, func(pth string, info os.FileInfo, err error) error {
if err != nil {
t.Fatal(err)
}
@@ -1255,12 +1313,15 @@ func TestBug3486(t *testing.T) { // https://golang.org/issue/3486
return filepath.SkipDir
case ken:
if !seenBugs {
- t.Fatal("filepath.Walk out of order - ken before bugs")
+ t.Fatal("filepath.Walk out of order - ken before fixedbugs")
}
seenKen = true
}
return nil
})
+ if err != nil {
+ t.Fatal(err)
+ }
if !seenKen {
t.Fatalf("%q not seen", ken)
}
diff --git a/src/path/filepath/path_unix.go b/src/path/filepath/path_unix.go
index 2d242cc..dddcac0 100644
--- a/src/path/filepath/path_unix.go
+++ b/src/path/filepath/path_unix.go
@@ -20,6 +20,8 @@ func volumeNameLen(path string) int {
}
// HasPrefix exists for historical compatibility and should not be used.
+//
+// Deprecated: Use strings.HasPrefix instead.
func HasPrefix(p, prefix string) bool {
return strings.HasPrefix(p, prefix)
}
diff --git a/src/path/filepath/path_windows.go b/src/path/filepath/path_windows.go
index 41c57df..359703d 100644
--- a/src/path/filepath/path_windows.go
+++ b/src/path/filepath/path_windows.go
@@ -37,7 +37,7 @@ func volumeNameLen(path string) int {
if path[1] == ':' && ('a' <= c && c <= 'z' || 'A' <= c && c <= 'Z') {
return 2
}
- // is it UNC
+ // is it UNC? https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx
if l := len(path); l >= 5 && isSlash(path[0]) && isSlash(path[1]) &&
!isSlash(path[2]) && path[2] != '.' {
// first, leading `\\` and next shouldn't be `\`. its server name.
@@ -106,7 +106,11 @@ func splitList(path string) []string {
}
func abs(path string) (string, error) {
- return syscall.FullPath(path)
+ fullPath, err := syscall.FullPath(path)
+ if err != nil {
+ return "", err
+ }
+ return Clean(fullPath), nil
}
func join(elem []string) string {
diff --git a/src/path/filepath/path_windows_test.go b/src/path/filepath/path_windows_test.go
index 9c82a0b..73e74be 100644
--- a/src/path/filepath/path_windows_test.go
+++ b/src/path/filepath/path_windows_test.go
@@ -12,30 +12,11 @@ import (
"os/exec"
"path/filepath"
"reflect"
+ "runtime/debug"
"strings"
- "syscall"
"testing"
)
-func init() {
- tmpdir, err := ioutil.TempDir("", "symtest")
- if err != nil {
- panic("failed to create temp directory: " + err.Error())
- }
- defer os.RemoveAll(tmpdir)
-
- err = os.Symlink("target", filepath.Join(tmpdir, "symlink"))
- if err == nil {
- return
- }
-
- err = err.(*os.LinkError).Err
- switch err {
- case syscall.EWINDOWS, syscall.ERROR_PRIVILEGE_NOT_HELD:
- supportsSymlinks = false
- }
-}
-
func TestWinSplitListTestsAreValid(t *testing.T) {
comspec := os.Getenv("ComSpec")
if comspec == "" {
@@ -357,10 +338,10 @@ func TestToNorm(t *testing.T) {
{`{{tmp}}\test`, `{{tmpvol}}FOO\BAR`, `{{tmpvol}}foo\bar`},
// test relative paths begin with '\'
- {".", `{{tmpnovol}}\test\foo\bar`, `{{tmpnovol}}\test\foo\bar`},
- {".", `{{tmpnovol}}\.\test\foo\bar`, `{{tmpnovol}}\test\foo\bar`},
- {".", `{{tmpnovol}}\test\..\test\foo\bar`, `{{tmpnovol}}\test\foo\bar`},
- {".", `{{tmpnovol}}\TEST\FOO\BAR`, `{{tmpnovol}}\test\foo\bar`},
+ {"{{tmp}}", `{{tmpnovol}}\test\foo\bar`, `{{tmpnovol}}\test\foo\bar`},
+ {"{{tmp}}", `{{tmpnovol}}\.\test\foo\bar`, `{{tmpnovol}}\test\foo\bar`},
+ {"{{tmp}}", `{{tmpnovol}}\test\..\test\foo\bar`, `{{tmpnovol}}\test\foo\bar`},
+ {"{{tmp}}", `{{tmpnovol}}\TEST\FOO\BAR`, `{{tmpnovol}}\test\foo\bar`},
// test relative paths begin without '\'
{`{{tmp}}\test`, ".", `.`},
@@ -371,42 +352,52 @@ func TestToNorm(t *testing.T) {
{`{{tmp}}\test`, `FOO\BAR`, `foo\bar`},
}
- cwd, err := os.Getwd()
+ tmp, err := ioutil.TempDir("", "testToNorm")
if err != nil {
t.Fatal(err)
}
-
defer func() {
- err := os.Chdir(cwd)
+ err := os.RemoveAll(tmp)
if err != nil {
t.Fatal(err)
}
}()
- tmp, err := ioutil.TempDir("", "testToNorm")
+ // ioutil.TempDir might return "non-canonical" name.
+ ctmp, err := filepath.EvalSymlinks(tmp)
if err != nil {
t.Fatal(err)
}
- defer os.RemoveAll(tmp)
- // ioutil.TempDir might return "non-canonical" name.
- tmp, err = filepath.EvalSymlinks(tmp)
+ err = os.MkdirAll(strings.Replace(testPath, "{{tmp}}", ctmp, -1), 0777)
if err != nil {
t.Fatal(err)
}
- err = os.MkdirAll(strings.Replace(testPath, "{{tmp}}", tmp, -1), 0777)
+ cwd, err := os.Getwd()
if err != nil {
t.Fatal(err)
}
+ defer func() {
+ err := os.Chdir(cwd)
+ if err != nil {
+ t.Fatal(err)
+ }
+ }()
+
+ tmpVol := filepath.VolumeName(ctmp)
+ if len(tmpVol) != 2 {
+ t.Fatalf("unexpected temp volume name %q", tmpVol)
+ }
- tmpVol := filepath.VolumeName(tmp)
- tmpNoVol := tmp[len(tmpVol):]
+ tmpNoVol := ctmp[len(tmpVol):]
+
+ replacer := strings.NewReplacer("{{tmp}}", ctmp, "{{tmpvol}}", tmpVol, "{{tmpnovol}}", tmpNoVol)
for _, test := range testsDir {
- wd := strings.Replace(strings.Replace(strings.Replace(test.wd, "{{tmp}}", tmp, -1), "{{tmpvol}}", tmpVol, -1), "{{tmpnovol}}", tmpNoVol, -1)
- arg := strings.Replace(strings.Replace(strings.Replace(test.arg, "{{tmp}}", tmp, -1), "{{tmpvol}}", tmpVol, -1), "{{tmpnovol}}", tmpNoVol, -1)
- want := strings.Replace(strings.Replace(strings.Replace(test.want, "{{tmp}}", tmp, -1), "{{tmpvol}}", tmpVol, -1), "{{tmpnovol}}", tmpNoVol, -1)
+ wd := replacer.Replace(test.wd)
+ arg := replacer.Replace(test.arg)
+ want := replacer.Replace(test.want)
if test.wd == "." {
err := os.Chdir(cwd)
@@ -432,3 +423,10 @@ func TestToNorm(t *testing.T) {
}
}
}
+
+func TestUNC(t *testing.T) {
+ // Test that this doesn't go into an infinite recursion.
+ // See golang.org/issue/15879.
+ defer debug.SetMaxStack(debug.SetMaxStack(1e6))
+ filepath.Glob(`\\?\c:\*`)
+}
diff --git a/src/path/filepath/symlink.go b/src/path/filepath/symlink.go
index f627a94..824aee4 100644
--- a/src/path/filepath/symlink.go
+++ b/src/path/filepath/symlink.go
@@ -105,8 +105,9 @@ func walkSymlinks(path string) (string, error) {
// directory is a symlink. Stop the walk, if symlink
// target is not absolute path, and return "."
// to the caller (just like unix does).
- if path == "." && !IsAbs(newpath) {
- return ".", nil
+ // Same for "C:.".
+ if path[volumeNameLen(path):] == "." && !IsAbs(newpath) {
+ return path, nil
}
}
if i == linksWalked {
diff --git a/src/path/path.go b/src/path/path.go
index c1d4d8a..76c7814 100644
--- a/src/path/path.go
+++ b/src/path/path.go
@@ -4,6 +4,8 @@
// Package path implements utility routines for manipulating slash-separated
// paths.
+//
+// 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
new file mode 100644
index 0000000..5c822bd
--- /dev/null
+++ b/src/plugin/plugin.go
@@ -0,0 +1,73 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package plugin implements loading and symbol resolution of Go plugins.
+//
+// Currently plugins only work on Linux and Darwin.
+//
+// A plugin is a Go main package with exported functions and variables that
+// has been built with:
+//
+// go build -buildmode=plugin
+//
+// When a plugin is first opened, the init functions of all packages not
+// already part of the program are called. The main function is not run.
+// A plugin is only initialized once, and cannot be closed.
+package plugin
+
+// Plugin is a loaded Go plugin.
+type Plugin struct {
+ pluginpath string
+ loaded chan struct{} // closed when loaded
+ syms map[string]interface{}
+}
+
+// Open opens a Go plugin.
+// If a path has already been opened, then the existing *Plugin is returned.
+// It is safe for concurrent use by multiple goroutines.
+func Open(path string) (*Plugin, error) {
+ return open(path)
+}
+
+// Lookup searches for a symbol named symName in plugin p.
+// A symbol is any exported variable or function.
+// It reports an error if the symbol is not found.
+// It is safe for concurrent use by multiple goroutines.
+func (p *Plugin) Lookup(symName string) (Symbol, error) {
+ return lookup(p, symName)
+}
+
+// A Symbol is a pointer to a variable or function.
+//
+// For example, a plugin defined as
+//
+// package main
+//
+// // // No C code needed.
+// import "C"
+//
+// import "fmt"
+//
+// var V int
+//
+// func F() { fmt.Printf("Hello, number %d\n", V) }
+//
+// may be loaded with the Open function and then the exported package
+// symbols V and F can be accessed
+//
+// p, err := plugin.Open("plugin_name.so")
+// if err != nil {
+// panic(err)
+// }
+// v, err := p.Lookup("V")
+// if err != nil {
+// panic(err)
+// }
+// f, err := p.Lookup("F")
+// if err != nil {
+// panic(err)
+// }
+// *v.(*int) = 7
+// f.(func())() // prints "Hello, number 7"
+type Symbol interface{}
diff --git a/src/plugin/plugin_dlopen.go b/src/plugin/plugin_dlopen.go
new file mode 100644
index 0000000..c5b0a47
--- /dev/null
+++ b/src/plugin/plugin_dlopen.go
@@ -0,0 +1,138 @@
+// Copyright 2016 The Go Authors. 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,cgo darwin,cgo
+
+package plugin
+
+/*
+#cgo linux LDFLAGS: -ldl
+#include <dlfcn.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <stdint.h>
+
+#include <stdio.h>
+
+static uintptr_t pluginOpen(const char* path, char** err) {
+ void* h = dlopen(path, RTLD_NOW|RTLD_GLOBAL);
+ if (h == NULL) {
+ *err = (char*)dlerror();
+ }
+ return (uintptr_t)h;
+}
+
+static void* pluginLookup(uintptr_t h, const char* name, char** err) {
+ void* r = dlsym((void*)h, name);
+ if (r == NULL) {
+ *err = (char*)dlerror();
+ }
+ return r;
+}
+*/
+import "C"
+
+import (
+ "errors"
+ "sync"
+ "unsafe"
+)
+
+func open(name string) (*Plugin, error) {
+ cPath := (*C.char)(C.malloc(C.PATH_MAX + 1))
+ defer C.free(unsafe.Pointer(cPath))
+
+ cRelName := C.CString(name)
+ defer C.free(unsafe.Pointer(cRelName))
+ if C.realpath(cRelName, cPath) == nil {
+ return nil, errors.New("plugin.Open(" + name + "): realpath failed")
+ }
+
+ filepath := C.GoString(cPath)
+
+ pluginsMu.Lock()
+ if p := plugins[filepath]; p != nil {
+ pluginsMu.Unlock()
+ <-p.loaded
+ return p, nil
+ }
+ var cErr *C.char
+ h := C.pluginOpen(cPath, &cErr)
+ if h == 0 {
+ pluginsMu.Unlock()
+ return nil, errors.New("plugin.Open: " + C.GoString(cErr))
+ }
+ // TODO(crawshaw): look for plugin note, confirm it is a Go plugin
+ // and it was built with the correct toolchain.
+ if len(name) > 3 && name[len(name)-3:] == ".so" {
+ name = name[:len(name)-3]
+ }
+
+ pluginpath, syms, mismatchpkg := lastmoduleinit()
+ if mismatchpkg != "" {
+ pluginsMu.Unlock()
+ return nil, errors.New("plugin.Open: plugin was built with a different version of package " + mismatchpkg)
+ }
+ if plugins == nil {
+ plugins = make(map[string]*Plugin)
+ }
+ // This function can be called from the init function of a plugin.
+ // Drop a placeholder in the map so subsequent opens can wait on it.
+ p := &Plugin{
+ pluginpath: pluginpath,
+ loaded: make(chan struct{}),
+ syms: syms,
+ }
+ plugins[filepath] = p
+ pluginsMu.Unlock()
+
+ initStr := C.CString(pluginpath + ".init")
+ initFuncPC := C.pluginLookup(h, initStr, &cErr)
+ C.free(unsafe.Pointer(initStr))
+ if initFuncPC != nil {
+ initFuncP := &initFuncPC
+ initFunc := *(*func())(unsafe.Pointer(&initFuncP))
+ initFunc()
+ }
+
+ // Fill out the value of each plugin symbol.
+ for symName, sym := range syms {
+ isFunc := symName[0] == '.'
+ if isFunc {
+ delete(syms, symName)
+ symName = symName[1:]
+ }
+
+ cname := C.CString(pluginpath + "." + symName)
+ p := C.pluginLookup(h, cname, &cErr)
+ C.free(unsafe.Pointer(cname))
+ if p == nil {
+ return nil, errors.New("plugin.Open: could not find symbol " + symName + ": " + C.GoString(cErr))
+ }
+ valp := (*[2]unsafe.Pointer)(unsafe.Pointer(&sym))
+ if isFunc {
+ (*valp)[1] = unsafe.Pointer(&p)
+ } else {
+ (*valp)[1] = p
+ }
+ syms[symName] = sym
+ }
+ close(p.loaded)
+ return p, nil
+}
+
+func lookup(p *Plugin, symName string) (Symbol, error) {
+ if s := p.syms[symName]; s != nil {
+ return s, nil
+ }
+ return nil, errors.New("plugin: symbol " + symName + " not found in plugin " + p.pluginpath)
+}
+
+var (
+ pluginsMu sync.Mutex
+ plugins map[string]*Plugin
+)
+
+// lastmoduleinit is defined in package runtime
+func lastmoduleinit() (pluginpath string, syms map[string]interface{}, mismatchpkg string)
diff --git a/src/plugin/plugin_stubs.go b/src/plugin/plugin_stubs.go
new file mode 100644
index 0000000..f0bcb4a
--- /dev/null
+++ b/src/plugin/plugin_stubs.go
@@ -0,0 +1,17 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !linux,!darwin !cgo
+
+package plugin
+
+import "errors"
+
+func lookup(p *Plugin, symName string) (interface{}, error) {
+ return nil, errors.New("plugin: not implemented")
+}
+
+func open(name string) (*Plugin, error) {
+ return nil, errors.New("plugin: not implemented")
+}
diff --git a/src/reflect/all_test.go b/src/reflect/all_test.go
index 780799c..033a181 100644
--- a/src/reflect/all_test.go
+++ b/src/reflect/all_test.go
@@ -648,6 +648,20 @@ var (
type self struct{}
+type Loop *Loop
+type Loopy interface{}
+
+var loop1, loop2 Loop
+var loopy1, loopy2 Loopy
+
+func init() {
+ loop1 = &loop2
+ loop2 = &loop1
+
+ loopy1 = &loopy2
+ loopy2 = &loopy1
+}
+
var deepEqualTests = []DeepEqualTest{
// Equalities
{nil, nil, true},
@@ -706,6 +720,12 @@ var deepEqualTests = []DeepEqualTest{
{&[3]interface{}{1, 2, 4}, &[3]interface{}{1, 2, "s"}, false},
{Basic{1, 0.5}, NotBasic{1, 0.5}, false},
{map[uint]string{1: "one", 2: "two"}, map[int]string{2: "two", 1: "one"}, false},
+
+ // Possible loops.
+ {&loop1, &loop1, true},
+ {&loop1, &loop2, true},
+ {&loopy1, &loopy1, true},
+ {&loopy1, &loopy2, true},
}
func TestDeepEqual(t *testing.T) {
@@ -1535,6 +1555,34 @@ func BenchmarkCall(b *testing.B) {
})
}
+func BenchmarkCallArgCopy(b *testing.B) {
+ byteArray := func(n int) Value {
+ return Zero(ArrayOf(n, TypeOf(byte(0))))
+ }
+ sizes := [...]struct {
+ fv Value
+ arg Value
+ }{
+ {ValueOf(func(a [128]byte) {}), byteArray(128)},
+ {ValueOf(func(a [256]byte) {}), byteArray(256)},
+ {ValueOf(func(a [1024]byte) {}), byteArray(1024)},
+ {ValueOf(func(a [4096]byte) {}), byteArray(4096)},
+ {ValueOf(func(a [65536]byte) {}), byteArray(65536)},
+ }
+ for _, size := range sizes {
+ bench := func(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)
+ }
+ }
+ name := fmt.Sprintf("size=%v", size.arg.Len())
+ b.Run(name, bench)
+ }
+}
+
func TestMakeFunc(t *testing.T) {
f := dummy
fv := MakeFunc(TypeOf(f), func(in []Value) []Value { return in })
@@ -2277,25 +2325,39 @@ func TestFieldPkgPath(t *testing.T) {
unexported string
OtherPkgFields
}{})
- for _, test := range []struct {
+
+ type pkgpathTest struct {
index []int
pkgPath string
anonymous bool
- }{
+ }
+
+ checkPkgPath := func(name string, s []pkgpathTest) {
+ for _, test := range s {
+ f := typ.FieldByIndex(test.index)
+ if got, want := f.PkgPath, test.pkgPath; got != want {
+ t.Errorf("%s: Field(%d).PkgPath = %q, want %q", name, test.index, got, want)
+ }
+ if got, want := f.Anonymous, test.anonymous; got != want {
+ t.Errorf("%s: Field(%d).Anonymous = %v, want %v", name, test.index, got, want)
+ }
+ }
+ }
+
+ checkPkgPath("testStruct", []pkgpathTest{
{[]int{0}, "", false}, // Exported
{[]int{1}, "reflect_test", false}, // unexported
{[]int{2}, "", true}, // OtherPkgFields
{[]int{2, 0}, "", false}, // OtherExported
{[]int{2, 1}, "reflect", false}, // otherUnexported
- } {
- f := typ.FieldByIndex(test.index)
- if got, want := f.PkgPath, test.pkgPath; got != want {
- t.Errorf("Field(%d).PkgPath = %q, want %q", test.index, got, want)
- }
- if got, want := f.Anonymous, test.anonymous; got != want {
- t.Errorf("Field(%d).Anonymous = %v, want %v", test.index, got, want)
- }
- }
+ })
+
+ type localOtherPkgFields OtherPkgFields
+ typ = TypeOf(localOtherPkgFields{})
+ checkPkgPath("localOtherPkgFields", []pkgpathTest{
+ {[]int{0}, "", false}, // OtherExported
+ {[]int{1}, "reflect", false}, // otherUnexported
+ })
}
func TestVariadicType(t *testing.T) {
@@ -3070,6 +3132,9 @@ func ReadWriterV(x io.ReadWriter) Value {
}
type Empty struct{}
+type MyStruct struct {
+ x int `some:"tag"`
+}
type MyString string
type MyBytes []byte
type MyRunes []int32
@@ -3381,6 +3446,35 @@ var convertTests = []struct {
{V((func())(nil)), V(MyFunc(nil))},
{V((MyFunc)(nil)), V((func())(nil))},
+ // structs with different tags
+ {V(struct {
+ x int `some:"foo"`
+ }{}), V(struct {
+ x int `some:"bar"`
+ }{})},
+
+ {V(struct {
+ x int `some:"bar"`
+ }{}), V(struct {
+ x int `some:"foo"`
+ }{})},
+
+ {V(MyStruct{}), V(struct {
+ x int `some:"foo"`
+ }{})},
+
+ {V(struct {
+ x int `some:"foo"`
+ }{}), V(MyStruct{})},
+
+ {V(MyStruct{}), V(struct {
+ x int `some:"bar"`
+ }{})},
+
+ {V(struct {
+ x int `some:"bar"`
+ }{}), V(MyStruct{})},
+
// can convert *byte and *MyByte
{V((*byte)(nil)), V((*MyByte)(nil))},
{V((*MyByte)(nil)), V((*byte)(nil))},
@@ -3965,6 +4059,38 @@ func TestStructOf(t *testing.T) {
}
}
+ // Check size and alignment with a trailing zero-sized field.
+ st = StructOf([]StructField{
+ {
+ Name: "F1",
+ Type: TypeOf(byte(0)),
+ },
+ {
+ Name: "F2",
+ Type: TypeOf([0]*byte{}),
+ },
+ })
+ stt = TypeOf(struct {
+ G1 byte
+ G2 [0]*byte
+ }{})
+ if st.Size() != stt.Size() {
+ t.Errorf("constructed zero-padded struct size = %v, want %v", st.Size(), stt.Size())
+ }
+ if st.Align() != stt.Align() {
+ t.Errorf("constructed zero-padded struct align = %v, want %v", st.Align(), stt.Align())
+ }
+ if st.FieldAlign() != stt.FieldAlign() {
+ t.Errorf("constructed zero-padded struct field align = %v, want %v", st.FieldAlign(), stt.FieldAlign())
+ }
+ for i := 0; i < st.NumField(); i++ {
+ o1 := st.Field(i).Offset
+ o2 := stt.Field(i).Offset
+ if o1 != o2 {
+ t.Errorf("constructed zero-padded struct field %v offset = %v, want %v", i, o1, o2)
+ }
+ }
+
// check duplicate names
shouldPanic(func() {
StructOf([]StructField{
@@ -5752,3 +5878,101 @@ func BenchmarkNew(b *testing.B) {
New(v)
}
}
+
+func TestSwapper(t *testing.T) {
+ type I int
+ var a, b, c I
+ type pair struct {
+ x, y int
+ }
+ type pairPtr struct {
+ x, y int
+ p *I
+ }
+ type S string
+
+ tests := []struct {
+ in interface{}
+ i, j int
+ want interface{}
+ }{
+ {
+ in: []int{1, 20, 300},
+ i: 0,
+ j: 2,
+ want: []int{300, 20, 1},
+ },
+ {
+ in: []uintptr{1, 20, 300},
+ i: 0,
+ j: 2,
+ want: []uintptr{300, 20, 1},
+ },
+ {
+ in: []int16{1, 20, 300},
+ i: 0,
+ j: 2,
+ want: []int16{300, 20, 1},
+ },
+ {
+ in: []int8{1, 20, 100},
+ i: 0,
+ j: 2,
+ want: []int8{100, 20, 1},
+ },
+ {
+ in: []*I{&a, &b, &c},
+ i: 0,
+ j: 2,
+ want: []*I{&c, &b, &a},
+ },
+ {
+ in: []string{"eric", "sergey", "larry"},
+ i: 0,
+ j: 2,
+ want: []string{"larry", "sergey", "eric"},
+ },
+ {
+ in: []S{"eric", "sergey", "larry"},
+ i: 0,
+ j: 2,
+ want: []S{"larry", "sergey", "eric"},
+ },
+ {
+ in: []pair{{1, 2}, {3, 4}, {5, 6}},
+ i: 0,
+ j: 2,
+ want: []pair{{5, 6}, {3, 4}, {1, 2}},
+ },
+ {
+ in: []pairPtr{{1, 2, &a}, {3, 4, &b}, {5, 6, &c}},
+ i: 0,
+ j: 2,
+ 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)
+ if !DeepEqual(tt.in, tt.want) {
+ t.Errorf("%d. swapping %v and %v of %v = %v; want %v", i, tt.i, tt.j, inStr, tt.in, tt.want)
+ }
+ }
+}
+
+// TestUnaddressableField tests that the reflect package will not allow
+// a type from another package to be used as a named type with an
+// unexported field.
+//
+// This ensures that unexported fields cannot be modified by other packages.
+func TestUnaddressableField(t *testing.T) {
+ var b Buffer // type defined in reflect, a different package
+ var localBuffer struct {
+ buf []byte
+ }
+ lv := ValueOf(&localBuffer).Elem()
+ rv := ValueOf(b)
+ shouldPanic(func() {
+ lv.Set(rv)
+ })
+}
diff --git a/src/reflect/asm_mipsx.s b/src/reflect/asm_mipsx.s
new file mode 100644
index 0000000..b6df4e6
--- /dev/null
+++ b/src/reflect/asm_mipsx.s
@@ -0,0 +1,34 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build mips mipsle
+
+#include "textflag.h"
+#include "funcdata.h"
+
+#define REGCTXT R22
+
+// makeFuncStub is the code half of the function returned by MakeFunc.
+// See the comment on the declaration of makeFuncStub in makefunc.go
+// for more details.
+// No arg size here, runtime pulls arg map out of the func value.
+TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$8
+ NO_LOCAL_POINTERS
+ MOVW REGCTXT, 4(R29)
+ MOVW $argframe+0(FP), R1
+ MOVW R1, 8(R29)
+ JAL ·callReflect(SB)
+ RET
+
+// methodValueCall is the code half of the function returned by makeMethodValue.
+// See the comment on the declaration of methodValueCall in makefunc.go
+// for more details.
+// No arg size here; runtime pulls arg map out of the func value.
+TEXT ·methodValueCall(SB),(NOSPLIT|WRAPPER),$8
+ NO_LOCAL_POINTERS
+ MOVW REGCTXT, 4(R29)
+ MOVW $argframe+0(FP), R1
+ MOVW R1, 8(R29)
+ JAL ·callMethod(SB)
+ RET
diff --git a/src/reflect/deepequal.go b/src/reflect/deepequal.go
index 9770358..f3fd704 100644
--- a/src/reflect/deepequal.go
+++ b/src/reflect/deepequal.go
@@ -30,9 +30,13 @@ func deepValueEqual(v1, v2 Value, visited map[visit]bool, depth int) bool {
}
// if depth > 10 { panic("deepValueEqual") } // for debugging
+
+ // We want to avoid putting more in the visited map than we need to.
+ // For any possible reference cycle that might be encountered,
+ // hard(t) needs to return true for at least one of the types in the cycle.
hard := func(k Kind) bool {
switch k {
- case Array, Map, Slice, Struct:
+ case Map, Slice, Ptr, Interface:
return true
}
return false
@@ -142,8 +146,9 @@ func deepValueEqual(v1, v2 Value, visited map[visit]bool, depth int) bool {
//
// Interface values are deeply equal if they hold deeply equal concrete values.
//
-// Map values are deeply equal if they are the same map object
-// or if they have the same length and their corresponding keys
+// Map values are deeply equal when all of the following are true:
+// they are both nil or both non-nil, they have the same length,
+// and either they are the same map object or their corresponding keys
// (matched using Go equality) map to deeply equal values.
//
// Pointer values are deeply equal if they are equal using Go's == operator
diff --git a/src/reflect/export_test.go b/src/reflect/export_test.go
index 2cc1530..ffd1104 100644
--- a/src/reflect/export_test.go
+++ b/src/reflect/export_test.go
@@ -113,3 +113,7 @@ func IsExported(t Type) bool {
func ResolveReflectName(s string) {
resolveReflectName(newName(s, "", "", false))
}
+
+type Buffer struct {
+ buf []byte
+}
diff --git a/src/reflect/makefunc.go b/src/reflect/makefunc.go
index ad2ebd0..a7efeb8 100644
--- a/src/reflect/makefunc.go
+++ b/src/reflect/makefunc.go
@@ -70,6 +70,8 @@ func MakeFunc(typ Type, fn func(args []Value) (results []Value)) Value {
// word in the passed-in argument frame.
func makeFuncStub()
+// This type is partially duplicated as runtime.reflectMethodValue.
+// Any changes should be reflected in both.
type methodValue struct {
fn uintptr
stack *bitVector // stack bitmap for args - offset known to runtime
diff --git a/src/reflect/swapper.go b/src/reflect/swapper.go
new file mode 100644
index 0000000..5441cb0
--- /dev/null
+++ b/src/reflect/swapper.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 reflect
+
+import "unsafe"
+
+// Swapper returns a function that swaps the elements in the provided
+// slice.
+//
+// Swapper panics if the provided interface is not a slice.
+func Swapper(slice interface{}) func(i, j int) {
+ v := ValueOf(slice)
+ if v.Kind() != Slice {
+ panic(&ValueError{Method: "Swapper", Kind: v.Kind()})
+ }
+ // Fast path for slices of size 0 and 1. Nothing to swap.
+ switch v.Len() {
+ case 0:
+ return func(i, j int) { panic("reflect: slice index out of range") }
+ case 1:
+ return func(i, j int) {
+ if i != 0 || j != 0 {
+ panic("reflect: slice index out of range")
+ }
+ }
+ }
+
+ typ := v.Type().Elem().(*rtype)
+ size := typ.Size()
+ hasPtr := typ.kind&kindNoPointers == 0
+
+ // Some common & small cases, without using memmove:
+ if hasPtr {
+ if size == ptrSize {
+ ps := *(*[]unsafe.Pointer)(v.ptr)
+ return func(i, j int) { ps[i], ps[j] = ps[j], ps[i] }
+ }
+ if typ.Kind() == String {
+ ss := *(*[]string)(v.ptr)
+ return func(i, j int) { ss[i], ss[j] = ss[j], ss[i] }
+ }
+ } else {
+ switch size {
+ case 8:
+ is := *(*[]int64)(v.ptr)
+ return func(i, j int) { is[i], is[j] = is[j], is[i] }
+ case 4:
+ is := *(*[]int32)(v.ptr)
+ return func(i, j int) { is[i], is[j] = is[j], is[i] }
+ case 2:
+ is := *(*[]int16)(v.ptr)
+ return func(i, j int) { is[i], is[j] = is[j], is[i] }
+ case 1:
+ is := *(*[]int8)(v.ptr)
+ return func(i, j int) { is[i], is[j] = is[j], is[i] }
+ }
+ }
+
+ s := (*sliceHeader)(v.ptr)
+ tmp := unsafe_New(typ) // swap scratch space
+
+ return func(i, j int) {
+ if uint(i) >= uint(s.Len) || uint(j) >= uint(s.Len) {
+ panic("reflect: slice index out of range")
+ }
+ val1 := arrayAt(s.Data, i, size)
+ val2 := arrayAt(s.Data, j, size)
+ typedmemmove(typ, tmp, val1)
+ typedmemmove(typ, val1, val2)
+ typedmemmove(typ, val2, tmp)
+ }
+}
diff --git a/src/reflect/type.go b/src/reflect/type.go
index 8916710..9d6e7a6 100644
--- a/src/reflect/type.go
+++ b/src/reflect/type.go
@@ -29,6 +29,9 @@ import (
// Use the Kind method to find out the kind of type before
// calling kind-specific methods. Calling a method
// inappropriate to the kind of type causes a run-time panic.
+//
+// Type values are comparable, such as with the == operator.
+// Two Type values are equal if they represent identical types.
type Type interface {
// Methods applicable to all types.
@@ -60,7 +63,7 @@ type Type interface {
// method signature, without a receiver, and the Func field is nil.
MethodByName(string) (Method, bool)
- // NumMethod returns the number of methods in the type's method set.
+ // NumMethod returns the number of exported methods in the type's method set.
NumMethod() int
// Name returns the type's name within its package.
@@ -80,7 +83,7 @@ type Type interface {
// String returns a string representation of the type.
// The string representation may use shortened package names
// (e.g., base64 instead of "encoding/base64") and is not
- // guaranteed to be unique among types. To test for equality,
+ // guaranteed to be unique among types. To test for type identity,
// compare the Types directly.
String() string
@@ -153,9 +156,18 @@ type Type interface {
// and a boolean indicating if the field was found.
FieldByName(name string) (StructField, bool)
- // FieldByNameFunc returns the first struct field with a name
+ // FieldByNameFunc returns the struct field with a name
// that satisfies the match function and a boolean indicating if
// the field was found.
+ //
+ // FieldByNameFunc considers the fields in the struct itself
+ // and then the fields in any anonymous structs, in breadth first order,
+ // stopping at the shallowest nesting depth containing one or more
+ // fields satisfying the match function. If multiple fields at that depth
+ // satisfy the match function, they cancel each other
+ // and FieldByNameFunc returns no match.
+ // This behavior mirrors Go's handling of name lookup in
+ // structs containing anonymous fields.
FieldByNameFunc(match func(string) bool) (StructField, bool)
// In returns the type of a function type's i'th input parameter.
@@ -1144,7 +1156,7 @@ func (tag StructTag) Get(key string) string {
// the value returned by Lookup is unspecified.
func (tag StructTag) Lookup(key string) (value string, ok bool) {
// When modifying this code, also update the validateStructTag code
- // in golang.org/x/tools/cmd/vet/structtag.go.
+ // in cmd/vet/structtag.go.
for tag != "" {
// Skip leading space.
@@ -1214,8 +1226,10 @@ func (t *structType) Field(i int) (f StructField) {
f.Anonymous = true
}
if !p.name.isExported() {
- // Fields never have an import path in their name.
- f.PkgPath = t.pkgPath.name()
+ f.PkgPath = p.name.pkgPath()
+ if f.PkgPath == "" {
+ f.PkgPath = t.pkgPath.name()
+ }
}
if tag := p.name.tag(); tag != "" {
f.Tag = StructTag(tag)
@@ -1450,25 +1464,24 @@ func (t *rtype) ptrTo() *rtype {
// Create a new ptrType starting with the description
// of an *unsafe.Pointer.
- p = new(ptrType)
var iptr interface{} = (*unsafe.Pointer)(nil)
prototype := *(**ptrType)(unsafe.Pointer(&iptr))
- *p = *prototype
+ pp := *prototype
- p.str = resolveReflectName(newName(s, "", "", false))
+ pp.str = resolveReflectName(newName(s, "", "", false))
// For the type structures linked into the binary, the
// compiler provides a good hash of the string.
// Create a good hash for the new string by using
// the FNV-1 hash's mixing function to combine the
// old hash and the new "*".
- p.hash = fnv1(t.hash, '*')
+ pp.hash = fnv1(t.hash, '*')
- p.elem = t
+ pp.elem = t
- ptrMap.m[t] = p
+ ptrMap.m[t] = &pp
ptrMap.Unlock()
- return &p.rtype
+ return &pp.rtype
}
// fnv1 incorporates the list of bytes into the hash x using the FNV-1 hash function.
@@ -1582,10 +1595,22 @@ func directlyAssignable(T, V *rtype) bool {
}
// x's type T and V must have identical underlying types.
- return haveIdenticalUnderlyingType(T, V)
+ return haveIdenticalUnderlyingType(T, V, true)
}
-func haveIdenticalUnderlyingType(T, V *rtype) bool {
+func haveIdenticalType(T, V Type, cmpTags bool) bool {
+ if cmpTags {
+ return T == V
+ }
+
+ if T.Name() != V.Name() || T.Kind() != V.Kind() {
+ return false
+ }
+
+ return haveIdenticalUnderlyingType(T.common(), V.common(), false)
+}
+
+func haveIdenticalUnderlyingType(T, V *rtype, cmpTags bool) bool {
if T == V {
return true
}
@@ -1604,18 +1629,18 @@ func haveIdenticalUnderlyingType(T, V *rtype) bool {
// Composite types.
switch kind {
case Array:
- return T.Elem() == V.Elem() && T.Len() == V.Len()
+ return T.Len() == V.Len() && haveIdenticalType(T.Elem(), V.Elem(), cmpTags)
case Chan:
// Special case:
// x is a bidirectional channel value, T is a channel type,
// and x's type V and T have identical element types.
- if V.ChanDir() == BothDir && T.Elem() == V.Elem() {
+ if V.ChanDir() == BothDir && haveIdenticalType(T.Elem(), V.Elem(), cmpTags) {
return true
}
// Otherwise continue test for identical underlying type.
- return V.ChanDir() == T.ChanDir() && T.Elem() == V.Elem()
+ return V.ChanDir() == T.ChanDir() && haveIdenticalType(T.Elem(), V.Elem(), cmpTags)
case Func:
t := (*funcType)(unsafe.Pointer(T))
@@ -1624,12 +1649,12 @@ func haveIdenticalUnderlyingType(T, V *rtype) bool {
return false
}
for i := 0; i < t.NumIn(); i++ {
- if t.In(i) != v.In(i) {
+ if !haveIdenticalType(t.In(i), v.In(i), cmpTags) {
return false
}
}
for i := 0; i < t.NumOut(); i++ {
- if t.Out(i) != v.Out(i) {
+ if !haveIdenticalType(t.Out(i), v.Out(i), cmpTags) {
return false
}
}
@@ -1646,10 +1671,10 @@ func haveIdenticalUnderlyingType(T, V *rtype) bool {
return false
case Map:
- return T.Key() == V.Key() && T.Elem() == V.Elem()
+ return haveIdenticalType(T.Key(), V.Key(), cmpTags) && haveIdenticalType(T.Elem(), V.Elem(), cmpTags)
case Ptr, Slice:
- return T.Elem() == V.Elem()
+ return haveIdenticalType(T.Elem(), V.Elem(), cmpTags)
case Struct:
t := (*structType)(unsafe.Pointer(T))
@@ -1663,15 +1688,28 @@ func haveIdenticalUnderlyingType(T, V *rtype) bool {
if tf.name.name() != vf.name.name() {
return false
}
- if tf.typ != vf.typ {
+ if !haveIdenticalType(tf.typ, vf.typ, cmpTags) {
return false
}
- if tf.name.tag() != vf.name.tag() {
+ if cmpTags && tf.name.tag() != vf.name.tag() {
return false
}
if tf.offset != vf.offset {
return false
}
+ if !tf.name.isExported() {
+ tp := tf.name.pkgPath()
+ if tp == "" {
+ tp = t.pkgPath.name()
+ }
+ vp := vf.name.pkgPath()
+ if vp == "" {
+ vp = v.pkgPath.name()
+ }
+ if tp != vp {
+ return false
+ }
+ }
}
return true
}
@@ -1846,8 +1884,7 @@ func ChanOf(dir ChanDir, t Type) Type {
// Make a channel type.
var ichan interface{} = (chan unsafe.Pointer)(nil)
prototype := *(**chanType)(unsafe.Pointer(&ichan))
- ch := new(chanType)
- *ch = *prototype
+ ch := *prototype
ch.tflag = 0
ch.dir = uintptr(dir)
ch.str = resolveReflectName(newName(s, "", "", false))
@@ -1890,8 +1927,7 @@ func MapOf(key, elem Type) Type {
// Make a map type.
var imap interface{} = (map[unsafe.Pointer]unsafe.Pointer)(nil)
- mt := new(mapType)
- *mt = **(**mapType)(unsafe.Pointer(&imap))
+ mt := **(**mapType)(unsafe.Pointer(&imap))
mt.str = resolveReflectName(newName(s, "", "", false))
mt.tflag = 0
mt.hash = fnv1(etyp.hash, 'm', byte(ktyp.hash>>24), byte(ktyp.hash>>16), byte(ktyp.hash>>8), byte(ktyp.hash))
@@ -2024,7 +2060,7 @@ func FuncOf(in, out []Type, variadic bool) Type {
// Look in cache.
funcLookupCache.RLock()
for _, t := range funcLookupCache.m[hash] {
- if haveIdenticalUnderlyingType(&ft.rtype, t) {
+ if haveIdenticalUnderlyingType(&ft.rtype, t, true) {
funcLookupCache.RUnlock()
return t
}
@@ -2038,7 +2074,7 @@ func FuncOf(in, out []Type, variadic bool) Type {
funcLookupCache.m = make(map[uint32][]*rtype)
}
for _, t := range funcLookupCache.m[hash] {
- if haveIdenticalUnderlyingType(&ft.rtype, t) {
+ if haveIdenticalUnderlyingType(&ft.rtype, t, true) {
return t
}
}
@@ -2046,7 +2082,7 @@ func FuncOf(in, out []Type, variadic bool) Type {
// Look in known types for the same string representation.
str := funcStr(ft)
for _, tt := range typesByString(str) {
- if haveIdenticalUnderlyingType(&ft.rtype, tt) {
+ if haveIdenticalUnderlyingType(&ft.rtype, tt, true) {
funcLookupCache.m[hash] = append(funcLookupCache.m[hash], tt)
return tt
}
@@ -2242,15 +2278,16 @@ func bucketOf(ktyp, etyp *rtype) *rtype {
}
}
- b := new(rtype)
- b.align = ptrSize
+ b := &rtype{
+ align: ptrSize,
+ size: size,
+ kind: kind,
+ ptrdata: ptrdata,
+ gcdata: gcdata,
+ }
if overflowPad > 0 {
b.align = 8
}
- b.size = size
- b.ptrdata = ptrdata
- b.kind = kind
- b.gcdata = gcdata
s := "bucket(" + ktyp.String() + "," + etyp.String() + ")"
b.str = resolveReflectName(newName(s, "", "", false))
return b
@@ -2279,8 +2316,7 @@ func SliceOf(t Type) Type {
// Make a slice type.
var islice interface{} = ([]unsafe.Pointer)(nil)
prototype := *(**sliceType)(unsafe.Pointer(&islice))
- slice := new(sliceType)
- *slice = *prototype
+ slice := *prototype
slice.tflag = 0
slice.str = resolveReflectName(newName(s, "", "", false))
slice.hash = fnv1(typ.hash, '[')
@@ -2364,6 +2400,7 @@ func StructOf(fields []StructField) Type {
hasGCProg = false // records whether a struct-field type has a GCProg
)
+ lastzero := uintptr(0)
repr = append(repr, "struct {"...)
for i, field := range fields {
if field.Type == nil {
@@ -2534,9 +2571,22 @@ func StructOf(fields []StructField) Type {
}
size = f.offset + ft.size
+ if ft.size == 0 {
+ lastzero = size
+ }
+
fs[i] = f
}
+ if size > 0 && lastzero == size {
+ // This is a non-zero sized struct that ends in a
+ // zero-sized field. We add an extra byte of padding,
+ // to ensure that taking the address of the final
+ // zero-sized field can't manufacture a pointer to the
+ // next object in the heap. See issue 9401.
+ size++
+ }
+
var typ *structType
var ut *uncommonType
var typPin interface {
@@ -2599,7 +2649,7 @@ func StructOf(fields []StructField) Type {
structLookupCache.RLock()
for _, st := range structLookupCache.m[hash] {
t := st.common()
- if haveIdenticalUnderlyingType(&typ.rtype, t) {
+ if haveIdenticalUnderlyingType(&typ.rtype, t, true) {
structLookupCache.RUnlock()
return t
}
@@ -2616,14 +2666,14 @@ func StructOf(fields []StructField) Type {
}
for _, st := range structLookupCache.m[hash] {
t := st.common()
- if haveIdenticalUnderlyingType(&typ.rtype, t) {
+ if haveIdenticalUnderlyingType(&typ.rtype, t, true) {
return t
}
}
// Look in known types.
for _, t := range typesByString(str) {
- if haveIdenticalUnderlyingType(&typ.rtype, t) {
+ if haveIdenticalUnderlyingType(&typ.rtype, t, true) {
// 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.
@@ -2638,6 +2688,7 @@ func StructOf(fields []StructField) Type {
typ.size = size
typ.align = typalign
typ.fieldAlign = typalign
+ typ.ptrToThis = 0
if len(methods) > 0 {
typ.tflag |= tflagUncommon
}
@@ -2824,8 +2875,7 @@ func ArrayOf(count int, elem Type) Type {
// Make an array type.
var iarray interface{} = [1]unsafe.Pointer{}
prototype := *(**arrayType)(unsafe.Pointer(&iarray))
- array := new(arrayType)
- *array = *prototype
+ array := *prototype
array.str = resolveReflectName(newName(s, "", "", false))
array.hash = fnv1(typ.hash, '[')
for n := uint32(count); n > 0; n >>= 8 {
@@ -3065,13 +3115,14 @@ func funcLayout(t *rtype, rcvr *rtype) (frametype *rtype, argSize, retOffset uin
offset += -offset & (ptrSize - 1)
// build dummy rtype holding gc program
- x := new(rtype)
- x.align = ptrSize
+ x := &rtype{
+ align: ptrSize,
+ size: offset,
+ ptrdata: uintptr(ptrmap.n) * ptrSize,
+ }
if runtime.GOARCH == "amd64p32" {
x.align = 8
}
- x.size = offset
- x.ptrdata = uintptr(ptrmap.n) * ptrSize
if ptrmap.n > 0 {
x.gcdata = &ptrmap.data[0]
} else {
diff --git a/src/reflect/value.go b/src/reflect/value.go
index e6b846e..042414f 100644
--- a/src/reflect/value.go
+++ b/src/reflect/value.go
@@ -440,14 +440,16 @@ func (v Value) call(op string, in []Value) []Value {
var ret []Value
if nout == 0 {
- memclr(args, frametype.size)
+ // This is untyped because the frame is really a
+ // stack, even though it's a heap object.
+ memclrNoHeapPointers(args, frametype.size)
framePool.Put(args)
} else {
// Zero the now unused input area of args,
// because the Values returned by this function contain pointers to the args object,
// and will thus keep the args object alive indefinitely.
- memclr(args, retOffset)
- // Copy return values out of args.
+ memclrNoHeapPointers(args, retOffset)
+ // Wrap Values around return values in args.
ret = make([]Value, nout)
off = retOffset
for i := 0; i < nout; i++ {
@@ -644,7 +646,9 @@ func callMethod(ctxt *methodValue, frame unsafe.Pointer) {
retOffset,
frametype.size-retOffset)
- memclr(args, frametype.size)
+ // This is untyped because the frame is really a stack, even
+ // though it's a heap object.
+ memclrNoHeapPointers(args, frametype.size)
framePool.Put(args)
}
@@ -2239,14 +2243,14 @@ func convertOp(dst, src *rtype) func(Value, Type) Value {
}
// dst and src have same underlying type.
- if haveIdenticalUnderlyingType(dst, src) {
+ if haveIdenticalUnderlyingType(dst, src, false) {
return cvtDirect
}
// dst and src are unnamed pointer types with same underlying base type.
if dst.Kind() == Ptr && dst.Name() == "" &&
src.Kind() == Ptr && src.Name() == "" &&
- haveIdenticalUnderlyingType(dst.Elem().common(), src.Elem().common()) {
+ haveIdenticalUnderlyingType(dst.Elem().common(), src.Elem().common(), false) {
return cvtDirect
}
@@ -2508,7 +2512,7 @@ func typedmemmovepartial(t *rtype, dst, src unsafe.Pointer, off, size uintptr)
func typedslicecopy(elemType *rtype, dst, src sliceHeader) int
//go:noescape
-func memclr(ptr unsafe.Pointer, n uintptr)
+func memclrNoHeapPointers(ptr unsafe.Pointer, n uintptr)
// Dummy annotation marking that the value x escapes,
// for use in cases where the reflect code is so clever that
diff --git a/src/regexp/all_test.go b/src/regexp/all_test.go
index 88391ff..beb46e7 100644
--- a/src/regexp/all_test.go
+++ b/src/regexp/all_test.go
@@ -11,7 +11,7 @@ import (
"testing"
)
-var good_re = []string{
+var goodRe = []string{
``,
`.`,
`^.$`,
@@ -36,7 +36,7 @@ type stringError struct {
err string
}
-var bad_re = []stringError{
+var badRe = []stringError{
{`*`, "missing argument to repetition operator: `*`"},
{`+`, "missing argument to repetition operator: `+`"},
{`?`, "missing argument to repetition operator: `?`"},
@@ -64,14 +64,14 @@ func compileTest(t *testing.T, expr string, error string) *Regexp {
}
func TestGoodCompile(t *testing.T) {
- for i := 0; i < len(good_re); i++ {
- compileTest(t, good_re[i], "")
+ for i := 0; i < len(goodRe); i++ {
+ compileTest(t, goodRe[i], "")
}
}
func TestBadCompile(t *testing.T) {
- for i := 0; i < len(bad_re); i++ {
- compileTest(t, bad_re[i].re, bad_re[i].err)
+ for i := 0; i < len(badRe); i++ {
+ compileTest(t, badRe[i].re, badRe[i].err)
}
}
@@ -512,6 +512,32 @@ func TestSplit(t *testing.T) {
}
}
+// The following sequence of Match calls used to panic. See issue #12980.
+func TestParseAndCompile(t *testing.T) {
+ expr := "a$"
+ s := "a\nb"
+
+ for i, tc := range []struct {
+ reFlags syntax.Flags
+ expMatch bool
+ }{
+ {syntax.Perl | syntax.OneLine, false},
+ {syntax.Perl &^ syntax.OneLine, true},
+ } {
+ parsed, err := syntax.Parse(expr, tc.reFlags)
+ if err != nil {
+ t.Fatalf("%d: parse: %v", i, err)
+ }
+ re, err := Compile(parsed.String())
+ if err != nil {
+ t.Fatalf("%d: compile: %v", i, err)
+ }
+ if match := re.MatchString(s); match != tc.expMatch {
+ t.Errorf("%d: %q.MatchString(%q)=%t; expected=%t", i, re, s, match, tc.expMatch)
+ }
+ }
+}
+
// Check that one-pass cutoff does trigger.
func TestOnePassCutoff(t *testing.T) {
re, err := syntax.Parse(`^x{1,1000}y{1,1000}$`, syntax.Perl)
@@ -538,6 +564,72 @@ func TestSwitchBacktrack(t *testing.T) {
re.Match(long[:1]) // triggers backtracker
}
+func BenchmarkFind(b *testing.B) {
+ b.StopTimer()
+ re := MustCompile("a+b+")
+ wantSubs := "aaabb"
+ s := []byte("acbb" + wantSubs + "dd")
+ b.StartTimer()
+ b.ReportAllocs()
+ for i := 0; i < b.N; i++ {
+ subs := re.Find(s)
+ if string(subs) != wantSubs {
+ b.Fatalf("Find(%q) = %q; want %q", s, subs, wantSubs)
+ }
+ }
+}
+
+func BenchmarkFindString(b *testing.B) {
+ b.StopTimer()
+ re := MustCompile("a+b+")
+ wantSubs := "aaabb"
+ s := "acbb" + wantSubs + "dd"
+ b.StartTimer()
+ b.ReportAllocs()
+ for i := 0; i < b.N; i++ {
+ subs := re.FindString(s)
+ if subs != wantSubs {
+ b.Fatalf("FindString(%q) = %q; want %q", s, subs, wantSubs)
+ }
+ }
+}
+
+func BenchmarkFindSubmatch(b *testing.B) {
+ b.StopTimer()
+ re := MustCompile("a(a+b+)b")
+ wantSubs := "aaabb"
+ s := []byte("acbb" + wantSubs + "dd")
+ b.StartTimer()
+ b.ReportAllocs()
+ for i := 0; i < b.N; i++ {
+ subs := re.FindSubmatch(s)
+ if string(subs[0]) != wantSubs {
+ b.Fatalf("FindSubmatch(%q)[0] = %q; want %q", s, subs[0], wantSubs)
+ }
+ if string(subs[1]) != "aab" {
+ b.Fatalf("FindSubmatch(%q)[1] = %q; want %q", s, subs[1], "aab")
+ }
+ }
+}
+
+func BenchmarkFindStringSubmatch(b *testing.B) {
+ b.StopTimer()
+ re := MustCompile("a(a+b+)b")
+ wantSubs := "aaabb"
+ s := "acbb" + wantSubs + "dd"
+ b.StartTimer()
+ b.ReportAllocs()
+ for i := 0; i < b.N; i++ {
+ subs := re.FindStringSubmatch(s)
+ if subs[0] != wantSubs {
+ b.Fatalf("FindStringSubmatch(%q)[0] = %q; want %q", s, subs[0], wantSubs)
+ }
+ if subs[1] != "aab" {
+ b.Fatalf("FindStringSubmatch(%q)[1] = %q; want %q", s, subs[1], "aab")
+ }
+ }
+}
+
func BenchmarkLiteral(b *testing.B) {
x := strings.Repeat("x", 50) + "y"
b.StopTimer()
@@ -726,3 +818,23 @@ func BenchmarkMatchParallelCopied(b *testing.B) {
}
})
}
+
+var sink string
+
+func BenchmarkQuoteMetaAll(b *testing.B) {
+ s := string(specialBytes)
+ b.SetBytes(int64(len(s)))
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ sink = QuoteMeta(s)
+ }
+}
+
+func BenchmarkQuoteMetaNone(b *testing.B) {
+ s := "abcdefghijklmnopqrstuvwxyz"
+ b.SetBytes(int64(len(s)))
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ sink = QuoteMeta(s)
+ }
+}
diff --git a/src/regexp/exec.go b/src/regexp/exec.go
index 4fd61b5..977619c 100644
--- a/src/regexp/exec.go
+++ b/src/regexp/exec.go
@@ -405,14 +405,16 @@ func (m *machine) onepass(i input, pos int) bool {
return m.matched
}
-// empty is a non-nil 0-element slice,
-// so doExecute can avoid an allocation
-// when 0 captures are requested from a successful match.
-var empty = make([]int, 0)
+// doMatch reports whether either r, b or s match the regexp.
+func (re *Regexp) doMatch(r io.RuneReader, b []byte, s string) bool {
+ return re.doExecute(r, b, s, 0, 0, nil) != nil
+}
-// doExecute finds the leftmost match in the input and returns
-// the position of its subexpressions.
-func (re *Regexp) doExecute(r io.RuneReader, b []byte, s string, pos int, ncap int) []int {
+// doExecute finds the leftmost match in the input, appends the position
+// of its subexpressions to dstCap and returns dstCap.
+//
+// nil is returned if no matches are found and non-nil if matches are found.
+func (re *Regexp) doExecute(r io.RuneReader, b []byte, s string, pos int, ncap int, dstCap []int) []int {
m := re.get()
var i input
var size int
@@ -445,12 +447,15 @@ func (re *Regexp) doExecute(r io.RuneReader, b []byte, s string, pos int, ncap i
return nil
}
}
- if ncap == 0 {
- re.put(m)
- return empty // empty but not nil
+ dstCap = append(dstCap, m.matchcap...)
+ if dstCap == nil {
+ // Keep the promise of returning non-nil value on match.
+ dstCap = arrayNoInts[:0]
}
- cap := make([]int, len(m.matchcap))
- copy(cap, m.matchcap)
re.put(m)
- return cap
+ return dstCap
}
+
+// arrayNoInts is returned by doExecute match if nil dstCap is passed
+// to it with ncap=0.
+var arrayNoInts [0]int
diff --git a/src/regexp/exec_test.go b/src/regexp/exec_test.go
index 69f187e..766394d 100644
--- a/src/regexp/exec_test.go
+++ b/src/regexp/exec_test.go
@@ -8,6 +8,7 @@ import (
"bufio"
"compress/bzip2"
"fmt"
+ "internal/testenv"
"io"
"os"
"path/filepath"
@@ -659,9 +660,14 @@ func makeText(n int) []byte {
}
func BenchmarkMatch(b *testing.B) {
+ isRaceBuilder := strings.HasSuffix(testenv.Builder(), "-race")
+
for _, data := range benchData {
r := MustCompile(data.re)
for _, size := range benchSizes {
+ if isRaceBuilder && size.n > 1<<10 {
+ continue
+ }
t := makeText(size.n)
b.Run(data.name+"/"+size.name, func(b *testing.B) {
b.SetBytes(int64(size.n))
diff --git a/src/regexp/onepass.go b/src/regexp/onepass.go
index 4991954..1b0564c 100644
--- a/src/regexp/onepass.go
+++ b/src/regexp/onepass.go
@@ -287,11 +287,6 @@ func (p runeSlice) Len() int { return len(p) }
func (p runeSlice) Less(i, j int) bool { return p[i] < p[j] }
func (p runeSlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
-// Sort is a convenience method.
-func (p runeSlice) Sort() {
- sort.Sort(p)
-}
-
var anyRuneNotNL = []rune{0, '\n' - 1, '\n' + 1, unicode.MaxRune}
var anyRune = []rune{0, unicode.MaxRune}
diff --git a/src/regexp/regexp.go b/src/regexp/regexp.go
index fe3db9f..01093d4 100644
--- a/src/regexp/regexp.go
+++ b/src/regexp/regexp.go
@@ -408,17 +408,17 @@ func (re *Regexp) LiteralPrefix() (prefix string, complete bool) {
// MatchReader reports whether the Regexp matches the text read by the
// RuneReader.
func (re *Regexp) MatchReader(r io.RuneReader) bool {
- return re.doExecute(r, nil, "", 0, 0) != nil
+ return re.doMatch(r, nil, "")
}
// MatchString reports whether the Regexp matches the string s.
func (re *Regexp) MatchString(s string) bool {
- return re.doExecute(nil, nil, s, 0, 0) != nil
+ return re.doMatch(nil, nil, s)
}
// Match reports whether the Regexp matches the byte slice b.
func (re *Regexp) Match(b []byte) bool {
- return re.doExecute(nil, b, "", 0, 0) != nil
+ return re.doMatch(nil, b, "")
}
// MatchReader checks whether a textual regular expression matches the text
@@ -502,8 +502,9 @@ func (re *Regexp) replaceAll(bsrc []byte, src string, nmatch int, repl func(dst
nmatch = re.prog.NumCap
}
+ var dstCap [2]int
for searchPos <= endPos {
- a := re.doExecute(nil, bsrc, src, searchPos, nmatch)
+ a := re.doExecute(nil, bsrc, src, searchPos, nmatch, dstCap[:0])
if len(a) == 0 {
break // no more matches
}
@@ -599,11 +600,22 @@ func special(b byte) bool {
// inside the argument text; the returned string is a regular expression matching
// the literal text. For example, QuoteMeta(`[foo]`) returns `\[foo\]`.
func QuoteMeta(s string) string {
- b := make([]byte, 2*len(s))
-
// A byte loop is correct because all metacharacters are ASCII.
- j := 0
- for i := 0; i < len(s); i++ {
+ var i int
+ for i = 0; i < len(s); i++ {
+ if special(s[i]) {
+ break
+ }
+ }
+ // No meta characters found, so return original string.
+ if i >= len(s) {
+ return s
+ }
+
+ b := make([]byte, 2*len(s)-i)
+ copy(b, s[:i])
+ j := i
+ for ; i < len(s); i++ {
if special(s[i]) {
b[j] = '\\'
j++
@@ -611,7 +623,7 @@ func QuoteMeta(s string) string {
b[j] = s[i]
j++
}
- return string(b[0:j])
+ return string(b[:j])
}
// The number of capture values in the program may correspond
@@ -641,7 +653,7 @@ func (re *Regexp) allMatches(s string, b []byte, n int, deliver func([]int)) {
}
for pos, i, prevMatchEnd := 0, 0, -1; i < n && pos <= end; {
- matches := re.doExecute(nil, b, s, pos, re.prog.NumCap)
+ matches := re.doExecute(nil, b, s, pos, re.prog.NumCap, nil)
if len(matches) == 0 {
break
}
@@ -681,7 +693,8 @@ func (re *Regexp) allMatches(s string, b []byte, n int, deliver func([]int)) {
// Find returns a slice holding the text of the leftmost match in b of the regular expression.
// A return value of nil indicates no match.
func (re *Regexp) Find(b []byte) []byte {
- a := re.doExecute(nil, b, "", 0, 2)
+ var dstCap [2]int
+ a := re.doExecute(nil, b, "", 0, 2, dstCap[:0])
if a == nil {
return nil
}
@@ -693,7 +706,7 @@ func (re *Regexp) Find(b []byte) []byte {
// b[loc[0]:loc[1]].
// A return value of nil indicates no match.
func (re *Regexp) FindIndex(b []byte) (loc []int) {
- a := re.doExecute(nil, b, "", 0, 2)
+ a := re.doExecute(nil, b, "", 0, 2, nil)
if a == nil {
return nil
}
@@ -706,7 +719,8 @@ func (re *Regexp) FindIndex(b []byte) (loc []int) {
// an empty string. Use FindStringIndex or FindStringSubmatch if it is
// necessary to distinguish these cases.
func (re *Regexp) FindString(s string) string {
- a := re.doExecute(nil, nil, s, 0, 2)
+ var dstCap [2]int
+ a := re.doExecute(nil, nil, s, 0, 2, dstCap[:0])
if a == nil {
return ""
}
@@ -718,7 +732,7 @@ func (re *Regexp) FindString(s string) string {
// itself is at s[loc[0]:loc[1]].
// A return value of nil indicates no match.
func (re *Regexp) FindStringIndex(s string) (loc []int) {
- a := re.doExecute(nil, nil, s, 0, 2)
+ a := re.doExecute(nil, nil, s, 0, 2, nil)
if a == nil {
return nil
}
@@ -731,7 +745,7 @@ func (re *Regexp) FindStringIndex(s string) (loc []int) {
// byte offset loc[0] through loc[1]-1.
// A return value of nil indicates no match.
func (re *Regexp) FindReaderIndex(r io.RuneReader) (loc []int) {
- a := re.doExecute(r, nil, "", 0, 2)
+ a := re.doExecute(r, nil, "", 0, 2, nil)
if a == nil {
return nil
}
@@ -744,7 +758,8 @@ func (re *Regexp) FindReaderIndex(r io.RuneReader) (loc []int) {
// comment.
// A return value of nil indicates no match.
func (re *Regexp) FindSubmatch(b []byte) [][]byte {
- a := re.doExecute(nil, b, "", 0, re.prog.NumCap)
+ var dstCap [4]int
+ a := re.doExecute(nil, b, "", 0, re.prog.NumCap, dstCap[:0])
if a == nil {
return nil
}
@@ -891,7 +906,7 @@ func extract(str string) (name string, num int, rest string, ok bool) {
// in the package comment.
// A return value of nil indicates no match.
func (re *Regexp) FindSubmatchIndex(b []byte) []int {
- return re.pad(re.doExecute(nil, b, "", 0, re.prog.NumCap))
+ return re.pad(re.doExecute(nil, b, "", 0, re.prog.NumCap, nil))
}
// FindStringSubmatch returns a slice of strings holding the text of the
@@ -900,7 +915,8 @@ func (re *Regexp) FindSubmatchIndex(b []byte) []int {
// package comment.
// A return value of nil indicates no match.
func (re *Regexp) FindStringSubmatch(s string) []string {
- a := re.doExecute(nil, nil, s, 0, re.prog.NumCap)
+ var dstCap [4]int
+ a := re.doExecute(nil, nil, s, 0, re.prog.NumCap, dstCap[:0])
if a == nil {
return nil
}
@@ -919,7 +935,7 @@ func (re *Regexp) FindStringSubmatch(s string) []string {
// 'Index' descriptions in the package comment.
// A return value of nil indicates no match.
func (re *Regexp) FindStringSubmatchIndex(s string) []int {
- return re.pad(re.doExecute(nil, nil, s, 0, re.prog.NumCap))
+ return re.pad(re.doExecute(nil, nil, s, 0, re.prog.NumCap, nil))
}
// FindReaderSubmatchIndex returns a slice holding the index pairs
@@ -928,7 +944,7 @@ func (re *Regexp) FindStringSubmatchIndex(s string) []int {
// by the 'Submatch' and 'Index' descriptions in the package comment. A
// return value of nil indicates no match.
func (re *Regexp) FindReaderSubmatchIndex(r io.RuneReader) []int {
- return re.pad(re.doExecute(r, nil, "", 0, re.prog.NumCap))
+ return re.pad(re.doExecute(r, nil, "", 0, re.prog.NumCap, nil))
}
const startSize = 10 // The size at which to start a slice in the 'All' routines.
diff --git a/src/runtime/HACKING.md b/src/runtime/HACKING.md
new file mode 100644
index 0000000..88fb708
--- /dev/null
+++ b/src/runtime/HACKING.md
@@ -0,0 +1,135 @@
+This is a very incomplete and probably out-of-date guide to
+programming in the Go runtime and how it differs from writing normal
+Go.
+
+Unmanaged memory
+================
+
+In general, the runtime tries to use regular heap allocation. However,
+in some cases the runtime must allocate objects outside of the garbage
+collected heap, in *unmanaged memory*. This is necessary if the
+objects are part of the memory manager itself or if they must be
+allocated in situations where the caller may not have a P.
+
+There are three mechanisms for allocating unmanaged memory:
+
+* sysAlloc obtains memory directly from the OS. This comes in whole
+ multiples of the system page size, but it can be freed with sysFree.
+
+* persistentalloc combines multiple smaller allocations into a single
+ sysAlloc to avoid fragmentation. However, there is no way to free
+ persistentalloced objects (hence the name).
+
+* fixalloc is a SLAB-style allocator that allocates objects of a fixed
+ size. fixalloced objects can be freed, but this memory can only be
+ reused by the same fixalloc pool, so it can only be reused for
+ objects of the same type.
+
+In general, types that are allocated using any of these should be
+marked `//go:notinheap` (see below).
+
+Objects that are allocated in unmanaged memory **must not** contain
+heap pointers unless the following rules are also obeyed:
+
+1. Any pointers from unmanaged memory to the heap must be added as
+ explicit garbage collection roots in `runtime.markroot`.
+
+2. If the memory is reused, the heap pointers must be zero-initialized
+ before they become visible as GC roots. Otherwise, the GC may
+ observe stale heap pointers. See "Zero-initialization versus
+ zeroing".
+
+Zero-initialization versus zeroing
+==================================
+
+There are two types of zeroing in the runtime, depending on whether
+the memory is already initialized to a type-safe state.
+
+If memory is not in a type-safe state, meaning it potentially contains
+"garbage" because it was just allocated and it is being initialized
+for first use, then it must be *zero-initialized* using
+`memclrNoHeapPointers` or non-pointer writes. This does not perform
+write barriers.
+
+If memory is already in a type-safe state and is simply being set to
+the zero value, this must be done using regular writes, `typedmemclr`,
+or `memclrHasPointers`. This performs write barriers.
+
+Runtime-only compiler directives
+================================
+
+In addition to the "//go:" directives documented in "go doc compile",
+the compiler supports additional directives only in the runtime.
+
+go:systemstack
+--------------
+
+`go:systemstack` indicates that a function must run on the system
+stack. This is checked dynamically by a special function prologue.
+
+go:nowritebarrier
+-----------------
+
+`go:nowritebarrier` directs the compiler to emit an error if the
+following function contains any write barriers. (It *does not*
+suppress the generation of write barriers; it is simply an assertion.)
+
+Usually you want `go:nowritebarrierrec`. `go:nowritebarrier` is
+primarily useful in situations where it's "nice" not to have write
+barriers, but not required for correctness.
+
+go:nowritebarrierrec and go:yeswritebarrierrec
+----------------------------------------------
+
+`go:nowritebarrierrec` directs the compiler to emit an error if the
+following function or any function it calls recursively, up to a
+`go:yeswritebarrierrec`, contains a write barrier.
+
+Logically, the compiler floods the call graph starting from each
+`go:nowritebarrierrec` function and produces an error if it encounters
+a function containing a write barrier. This flood stops at
+`go:yeswritebarrierrec` functions.
+
+`go:nowritebarrierrec` is used in the implementation of the write
+barrier to prevent infinite loops.
+
+Both directives are used in the scheduler. The write barrier requires
+an active P (`getg().m.p != nil`) and scheduler code often runs
+without an active P. In this case, `go:nowritebarrierrec` is used on
+functions that release the P or may run without a P and
+`go:yeswritebarrierrec` is used when code re-acquires an active P.
+Since these are function-level annotations, code that releases or
+acquires a P may need to be split across two functions.
+
+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:
+
+1. `new(T)`, `make([]T)`, `append([]T, ...)` and implicit heap
+ allocation of T are disallowed. (Though implicit allocations are
+ disallowed in the runtime anyway.)
+
+2. A pointer to a regular type (other than `unsafe.Pointer`) cannot be
+ converted to a pointer to a `go:notinheap` type, even if they have
+ the same underlying type.
+
+3. Any type that contains a `go:notinheap` type is itself
+ `go:notinheap`. Structs and arrays are `go:notinheap` if their
+ elements are. Maps and channels of `go:notinheap` types are
+ disallowed. To keep things explicit, any type declaration where the
+ type is implicitly `go:notinheap` must be explicitly marked
+ `go:notinheap` as well.
+
+4. Write barriers on pointers to `go:notinheap` types can be omitted.
+
+The last point is the real benefit of `go:notinheap`. The runtime uses
+it for low-level internal structures to avoid memory barriers in the
+scheduler and the memory allocator where they are illegal or simply
+inefficient. This mechanism is reasonably safe and does not compromise
+the readability of the runtime.
diff --git a/src/runtime/alg.go b/src/runtime/alg.go
index 147332e..5c378c6 100644
--- a/src/runtime/alg.go
+++ b/src/runtime/alg.go
@@ -109,7 +109,7 @@ func f32hash(p unsafe.Pointer, h uintptr) uintptr {
case f == 0:
return c1 * (c0 ^ h) // +0, -0
case f != f:
- return c1 * (c0 ^ h ^ uintptr(fastrand1())) // any kind of NaN
+ return c1 * (c0 ^ h ^ uintptr(fastrand())) // any kind of NaN
default:
return memhash(p, h, 4)
}
@@ -121,7 +121,7 @@ func f64hash(p unsafe.Pointer, h uintptr) uintptr {
case f == 0:
return c1 * (c0 ^ h) // +0, -0
case f != f:
- return c1 * (c0 ^ h ^ uintptr(fastrand1())) // any kind of NaN
+ return c1 * (c0 ^ h ^ uintptr(fastrand())) // any kind of NaN
default:
return memhash(p, h, 8)
}
@@ -275,12 +275,6 @@ func ifaceHash(i interface {
return algarray[alg_INTER].hash(noescape(unsafe.Pointer(&i)), seed)
}
-// Testing adapter for memclr
-func memclrBytes(b []byte) {
- s := (*slice)(unsafe.Pointer(&b))
- memclr(s.array, uintptr(s.len))
-}
-
const hashRandomBytes = sys.PtrSize / 4 * 64
// used in asm_{386,amd64}.s to seed the hash function
diff --git a/src/runtime/append_test.go b/src/runtime/append_test.go
index 6b8968e..6bd8f3b 100644
--- a/src/runtime/append_test.go
+++ b/src/runtime/append_test.go
@@ -100,6 +100,22 @@ func BenchmarkAppendSlice(b *testing.B) {
}
}
+var (
+ blackhole []byte
+)
+
+func BenchmarkAppendSliceLarge(b *testing.B) {
+ for _, length := range []int{1 << 10, 4 << 10, 16 << 10, 64 << 10, 256 << 10, 1024 << 10} {
+ y := make([]byte, length)
+ b.Run(fmt.Sprint(length, "Bytes"), func(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ blackhole = nil
+ blackhole = append(blackhole, y...)
+ }
+ })
+ }
+}
+
func BenchmarkAppendStr(b *testing.B) {
for _, str := range []string{
"1",
diff --git a/src/runtime/asm.s b/src/runtime/asm.s
index 646dc2f..3ddea7c 100644
--- a/src/runtime/asm.s
+++ b/src/runtime/asm.s
@@ -12,8 +12,5 @@ DATA runtime·no_pointers_stackmap+0x00(SB)/4, $2
DATA runtime·no_pointers_stackmap+0x04(SB)/4, $0
GLOBL runtime·no_pointers_stackmap(SB),RODATA, $8
-TEXT runtime·nop(SB),NOSPLIT,$0-0
- RET
-
GLOBL runtime·mheap_(SB), NOPTR, $0
GLOBL runtime·memstats(SB), NOPTR, $0
diff --git a/src/runtime/asm_386.s b/src/runtime/asm_386.s
index ea11b2b..3d0b74c 100644
--- a/src/runtime/asm_386.s
+++ b/src/runtime/asm_386.s
@@ -193,9 +193,7 @@ TEXT runtime·asminit(SB),NOSPLIT,$0-0
// Other operating systems use double precision.
// Change to double precision to match them,
// and to match other hardware that only has double.
- PUSHL $0x27F
- FLDCW 0(SP)
- POPL AX
+ FLDCW runtime·controlWord64(SB)
RET
/*
@@ -211,7 +209,11 @@ TEXT runtime·gosave(SB), NOSPLIT, $0-4
MOVL 0(SP), BX // caller's PC
MOVL BX, gobuf_pc(AX)
MOVL $0, gobuf_ret(AX)
- MOVL $0, gobuf_ctxt(AX)
+ // Assert ctxt is zero. See func save.
+ MOVL gobuf_ctxt(AX), BX
+ TESTL BX, BX
+ JZ 2(PC)
+ CALL runtime·badctxt(SB)
get_tls(CX)
MOVL g(CX), BX
MOVL BX, gobuf_g(AX)
@@ -219,8 +221,20 @@ TEXT runtime·gosave(SB), NOSPLIT, $0-4
// void gogo(Gobuf*)
// restore state from Gobuf; longjmp
-TEXT runtime·gogo(SB), NOSPLIT, $0-4
+TEXT runtime·gogo(SB), NOSPLIT, $8-4
MOVL buf+0(FP), BX // gobuf
+
+ // If ctxt is not nil, invoke deletion barrier before overwriting.
+ MOVL gobuf_ctxt(BX), DX
+ TESTL DX, DX
+ JZ nilctxt
+ LEAL gobuf_ctxt(BX), AX
+ MOVL AX, 0(SP)
+ MOVL $0, 4(SP)
+ CALL runtime·writebarrierptr_prewrite(SB)
+ MOVL buf+0(FP), BX
+
+nilctxt:
MOVL gobuf_g(BX), DX
MOVL 0(DX), CX // make sure g != nil
get_tls(CX)
@@ -356,13 +370,15 @@ TEXT runtime·morestack(SB),NOSPLIT,$0-0
MOVL g_m(BX), BX
MOVL m_g0(BX), SI
CMPL g(CX), SI
- JNE 2(PC)
+ JNE 3(PC)
+ CALL runtime·badmorestackg0(SB)
INT $3
// Cannot grow signal stack.
MOVL m_gsignal(BX), SI
CMPL g(CX), SI
- JNE 2(PC)
+ JNE 3(PC)
+ CALL runtime·badmorestackgsignal(SB)
INT $3
// Called from f.
@@ -381,7 +397,7 @@ TEXT runtime·morestack(SB),NOSPLIT,$0-0
MOVL SI, (g_sched+gobuf_g)(SI)
LEAL 4(SP), AX // f's SP
MOVL AX, (g_sched+gobuf_sp)(SI)
- MOVL DX, (g_sched+gobuf_ctxt)(SI)
+ // newstack will fill gobuf.ctxt.
// Call newstack on m->g0's stack.
MOVL m_g0(BX), BP
@@ -389,8 +405,10 @@ TEXT runtime·morestack(SB),NOSPLIT,$0-0
MOVL (g_sched+gobuf_sp)(BP), AX
MOVL -4(AX), BX // fault if CALL would, before smashing SP
MOVL AX, SP
+ PUSHL DX // ctxt argument
CALL runtime·newstack(SB)
MOVL $0, 0x1003 // crash if newstack returns
+ POPL DX // keep balance check happy
RET
TEXT runtime·morestack_noctxt(SB),NOSPLIT,$0-0
@@ -475,6 +493,7 @@ TEXT NAME(SB), WRAPPER, $MAXSIZE-20; \
PCDATA $PCDATA_StackMapIndex, $0; \
CALL AX; \
/* copy return values back */ \
+ MOVL argtype+0(FP), DX; \
MOVL argptr+8(FP), DI; \
MOVL argsize+12(FP), CX; \
MOVL retoffset+16(FP), BX; \
@@ -482,17 +501,19 @@ TEXT NAME(SB), WRAPPER, $MAXSIZE-20; \
ADDL BX, DI; \
ADDL BX, SI; \
SUBL BX, CX; \
- REP;MOVSB; \
- /* execute write barrier updates */ \
- MOVL argtype+0(FP), DX; \
- MOVL argptr+8(FP), DI; \
- MOVL argsize+12(FP), CX; \
- MOVL retoffset+16(FP), BX; \
- MOVL DX, 0(SP); \
- MOVL DI, 4(SP); \
- MOVL CX, 8(SP); \
- MOVL BX, 12(SP); \
- CALL runtime·callwritebarrier(SB); \
+ CALL callRet<>(SB); \
+ RET
+
+// callRet copies return values back at the end of call*. This is a
+// separate function so it can allocate stack space for the arguments
+// to reflectcallmove. It does not follow the Go ABI; it expects its
+// arguments in registers.
+TEXT callRet<>(SB), NOSPLIT, $16-0
+ MOVL DX, 0(SP)
+ MOVL DI, 4(SP)
+ MOVL SI, 8(SP)
+ MOVL CX, 12(SP)
+ CALL runtime·reflectcallmove(SB)
RET
CALLFN(·call16, 16)
@@ -567,7 +588,11 @@ TEXT gosave<>(SB),NOSPLIT,$0
MOVL -4(AX), AX
MOVL AX, (g_sched+gobuf_pc)(BX)
MOVL $0, (g_sched+gobuf_ret)(BX)
- MOVL $0, (g_sched+gobuf_ctxt)(BX)
+ // Assert ctxt is zero. See func save.
+ MOVL (g_sched+gobuf_ctxt)(BX), AX
+ TESTL AX, AX
+ JZ 2(PC)
+ CALL runtime·badctxt(SB)
POPL BX
POPL AX
RET
@@ -810,11 +835,6 @@ setbar:
CALL runtime·setNextBarrierPC(SB)
RET
-TEXT runtime·getcallersp(SB), NOSPLIT, $0-8
- MOVL argp+0(FP), AX
- MOVL AX, ret+4(FP)
- RET
-
// func cputicks() int64
TEXT runtime·cputicks(SB),NOSPLIT,$0-8
TESTL $0x4000000, runtime·cpuid_edx(SB) // no sse2, no mfence
@@ -845,9 +865,6 @@ TEXT runtime·ldt0setup(SB),NOSPLIT,$16-0
TEXT runtime·emptyfunc(SB),0,$0-0
RET
-TEXT runtime·abort(SB),NOSPLIT,$0-0
- INT $0x3
-
// memhash_varlen(p unsafe.Pointer, h seed) uintptr
// redirects to memhash(p, h, size) using the size
// stored in the closure.
@@ -1292,15 +1309,15 @@ eq:
// See runtime_test.go:eqstring_generic for
// equivalent Go code.
TEXT runtime·eqstring(SB),NOSPLIT,$0-17
- MOVL s1str+0(FP), SI
- MOVL s2str+8(FP), DI
+ MOVL s1_base+0(FP), SI
+ MOVL s2_base+8(FP), DI
CMPL SI, DI
JEQ same
- MOVL s1len+4(FP), BX
- LEAL v+16(FP), AX
+ MOVL s1_len+4(FP), BX
+ LEAL ret+16(FP), AX
JMP runtime·memeqbody(SB)
same:
- MOVB $1, v+16(FP)
+ MOVB $1, ret+16(FP)
RET
TEXT bytes·Equal(SB),NOSPLIT,$0-25
@@ -1578,7 +1595,7 @@ allsame:
MOVL BX, (AX)
RET
-TEXT runtime·fastrand1(SB), NOSPLIT, $0-4
+TEXT runtime·fastrand(SB), NOSPLIT, $0-4
get_tls(CX)
MOVL g(CX), AX
MOVL g_m(AX), AX
@@ -1637,3 +1654,21 @@ TEXT runtime·addmoduledata(SB),NOSPLIT,$0-0
MOVL AX, moduledata_next(DX)
MOVL AX, runtime·lastmoduledatap(SB)
RET
+
+TEXT runtime·uint32tofloat64(SB),NOSPLIT,$8-12
+ MOVL a+0(FP), AX
+ MOVL AX, 0(SP)
+ MOVL $0, 4(SP)
+ FMOVV 0(SP), F0
+ FMOVDP F0, ret+4(FP)
+ RET
+
+TEXT runtime·float64touint32(SB),NOSPLIT,$12-12
+ FMOVD a+0(FP), F0
+ FSTCW 0(SP)
+ FLDCW runtime·controlWord64trunc(SB)
+ FMOVVP F0, 4(SP)
+ FLDCW 0(SP)
+ MOVL 4(SP), AX
+ MOVL AX, ret+8(FP)
+ RET
diff --git a/src/runtime/asm_amd64.s b/src/runtime/asm_amd64.s
index 6103d54..9ffd297 100644
--- a/src/runtime/asm_amd64.s
+++ b/src/runtime/asm_amd64.s
@@ -182,8 +182,12 @@ TEXT runtime·gosave(SB), NOSPLIT, $0-8
MOVQ 0(SP), BX // caller's PC
MOVQ BX, gobuf_pc(AX)
MOVQ $0, gobuf_ret(AX)
- MOVQ $0, gobuf_ctxt(AX)
MOVQ BP, gobuf_bp(AX)
+ // Assert ctxt is zero. See func save.
+ MOVQ gobuf_ctxt(AX), BX
+ TESTQ BX, BX
+ JZ 2(PC)
+ CALL runtime·badctxt(SB)
get_tls(CX)
MOVQ g(CX), BX
MOVQ BX, gobuf_g(AX)
@@ -191,8 +195,20 @@ TEXT runtime·gosave(SB), NOSPLIT, $0-8
// void gogo(Gobuf*)
// restore state from Gobuf; longjmp
-TEXT runtime·gogo(SB), NOSPLIT, $0-8
+TEXT runtime·gogo(SB), NOSPLIT, $16-8
MOVQ buf+0(FP), BX // gobuf
+
+ // If ctxt is not nil, invoke deletion barrier before overwriting.
+ MOVQ gobuf_ctxt(BX), AX
+ TESTQ AX, AX
+ JZ nilctxt
+ LEAQ gobuf_ctxt(BX), AX
+ MOVQ AX, 0(SP)
+ MOVQ $0, 8(SP)
+ CALL runtime·writebarrierptr_prewrite(SB)
+ MOVQ buf+0(FP), BX
+
+nilctxt:
MOVQ gobuf_g(BX), DX
MOVQ 0(DX), CX // make sure g != nil
get_tls(CX)
@@ -331,13 +347,15 @@ TEXT runtime·morestack(SB),NOSPLIT,$0-0
MOVQ g_m(BX), BX
MOVQ m_g0(BX), SI
CMPQ g(CX), SI
- JNE 2(PC)
+ JNE 3(PC)
+ CALL runtime·badmorestackg0(SB)
INT $3
// Cannot grow signal stack (m->gsignal).
MOVQ m_gsignal(BX), SI
CMPQ g(CX), SI
- JNE 2(PC)
+ JNE 3(PC)
+ CALL runtime·badmorestackgsignal(SB)
INT $3
// Called from f.
@@ -356,15 +374,17 @@ TEXT runtime·morestack(SB),NOSPLIT,$0-0
MOVQ SI, (g_sched+gobuf_g)(SI)
LEAQ 8(SP), AX // f's SP
MOVQ AX, (g_sched+gobuf_sp)(SI)
- MOVQ DX, (g_sched+gobuf_ctxt)(SI)
MOVQ BP, (g_sched+gobuf_bp)(SI)
+ // newstack will fill gobuf.ctxt.
// Call newstack on m->g0's stack.
MOVQ m_g0(BX), BX
MOVQ BX, g(CX)
MOVQ (g_sched+gobuf_sp)(BX), SP
+ PUSHQ DX // ctxt argument
CALL runtime·newstack(SB)
MOVQ $0, 0x1003 // crash if newstack returns
+ POPQ DX // keep balance check happy
RET
// morestack but not preserving ctxt.
@@ -412,8 +432,6 @@ TEXT reflect·call(SB), NOSPLIT, $0-0
TEXT ·reflectcall(SB), NOSPLIT, $0-32
MOVLQZX argsize+24(FP), CX
- // NOTE(rsc): No call16, because CALLFN needs four words
- // of argument space to invoke callwritebarrier.
DISPATCH(runtime·call32, 32)
DISPATCH(runtime·call64, 64)
DISPATCH(runtime·call128, 128)
@@ -456,24 +474,28 @@ TEXT NAME(SB), WRAPPER, $MAXSIZE-32; \
PCDATA $PCDATA_StackMapIndex, $0; \
CALL (DX); \
/* copy return values back */ \
+ MOVQ argtype+0(FP), DX; \
MOVQ argptr+16(FP), DI; \
MOVLQZX argsize+24(FP), CX; \
- MOVLQZX retoffset+28(FP), BX; \
+ MOVLQZX retoffset+28(FP), BX; \
MOVQ SP, SI; \
ADDQ BX, DI; \
ADDQ BX, SI; \
SUBQ BX, CX; \
- REP;MOVSB; \
- /* execute write barrier updates */ \
- MOVQ argtype+0(FP), DX; \
- MOVQ argptr+16(FP), DI; \
- MOVLQZX argsize+24(FP), CX; \
- MOVLQZX retoffset+28(FP), BX; \
- MOVQ DX, 0(SP); \
- MOVQ DI, 8(SP); \
- MOVQ CX, 16(SP); \
- MOVQ BX, 24(SP); \
- CALL runtime·callwritebarrier(SB); \
+ CALL callRet<>(SB); \
+ RET
+
+// callRet copies return values back at the end of call*. This is a
+// separate function so it can allocate stack space for the arguments
+// to reflectcallmove. It does not follow the Go ABI; it expects its
+// arguments in registers.
+TEXT callRet<>(SB), NOSPLIT, $32-0
+ NO_LOCAL_POINTERS
+ MOVQ DX, 0(SP)
+ MOVQ DI, 8(SP)
+ MOVQ SI, 16(SP)
+ MOVQ CX, 24(SP)
+ CALL runtime·reflectcallmove(SB)
RET
CALLFN(·call32, 32)
@@ -540,8 +562,12 @@ TEXT gosave<>(SB),NOSPLIT,$0
LEAQ 8(SP), R9
MOVQ R9, (g_sched+gobuf_sp)(R8)
MOVQ $0, (g_sched+gobuf_ret)(R8)
- MOVQ $0, (g_sched+gobuf_ctxt)(R8)
MOVQ BP, (g_sched+gobuf_bp)(R8)
+ // Assert ctxt is zero. See func save.
+ MOVQ (g_sched+gobuf_ctxt)(R8), R9
+ TESTQ R9, R9
+ JZ 2(PC)
+ CALL runtime·badctxt(SB)
RET
// func asmcgocall(fn, arg unsafe.Pointer) int32
@@ -825,11 +851,6 @@ setbar:
CALL runtime·setNextBarrierPC(SB)
RET
-TEXT runtime·getcallersp(SB),NOSPLIT,$0-16
- MOVQ argp+0(FP), AX
- MOVQ AX, ret+8(FP)
- RET
-
// func cputicks() int64
TEXT runtime·cputicks(SB),NOSPLIT,$0-0
CMPB runtime·lfenceBeforeRdtsc(SB), $1
@@ -1340,15 +1361,15 @@ eq:
// See runtime_test.go:eqstring_generic for
// equivalent Go code.
TEXT runtime·eqstring(SB),NOSPLIT,$0-33
- MOVQ s1str+0(FP), SI
- MOVQ s2str+16(FP), DI
+ MOVQ s1_base+0(FP), SI
+ MOVQ s2_base+16(FP), DI
CMPQ SI, DI
JEQ eq
- MOVQ s1len+8(FP), BX
- LEAQ v+32(FP), AX
+ MOVQ s1_len+8(FP), BX
+ LEAQ ret+32(FP), AX
JMP runtime·memeqbody(SB)
eq:
- MOVB $1, v+32(FP)
+ MOVB $1, ret+32(FP)
RET
// a in SI
@@ -1695,13 +1716,41 @@ big_loop_avx2_exit:
JMP loop
-// TODO: Also use this in bytes.Index
+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
MOVQ s_len+8(FP), DX
MOVQ c+16(FP), BP
MOVQ c_len+24(FP), AX
+ MOVQ DI, R10
+ LEAQ ret+32(FP), R11
+ JMP runtime·indexShortStr(SB)
+
+TEXT bytes·indexShortStr(SB),NOSPLIT,$0-56
+ MOVQ s+0(FP), DI
+ MOVQ s_len+8(FP), DX
+ MOVQ c+24(FP), BP
+ MOVQ c_len+32(FP), AX
+ MOVQ DI, R10
+ LEAQ ret+48(FP), R11
+ JMP runtime·indexShortStr(SB)
+
+// AX: length of string, that we are searching for
+// DX: length of string, in which we are searching
+// DI: pointer to string, in which we are searching
+// BP: pointer to string, that we are searching for
+// R11: address, where to put return value
+TEXT runtime·indexShortStr(SB),NOSPLIT,$0
CMPQ AX, DX
JA fail
CMPQ DX, $16
@@ -1791,7 +1840,7 @@ loop8:
JB loop8
JMP fail
_9_or_more:
- CMPQ AX, $16
+ CMPQ AX, $15
JA _16_or_more
LEAQ 1(DI)(DX*1), DX
SUBQ AX, DX
@@ -1815,7 +1864,7 @@ partial_success9to15:
JMP fail
_16_or_more:
CMPQ AX, $16
- JA _17_to_31
+ JA _17_or_more
MOVOU (BP), X1
LEAQ -15(DI)(DX*1), DX
loop16:
@@ -1828,7 +1877,9 @@ loop16:
CMPQ DI,DX
JB loop16
JMP fail
-_17_to_31:
+_17_or_more:
+ CMPQ AX, $31
+ JA _32_or_more
LEAQ 1(DI)(DX*1), DX
SUBQ AX, DX
MOVOU -16(BP)(AX*1), X0
@@ -1852,9 +1903,56 @@ partial_success17to31:
ADDQ $1,DI
CMPQ DI,DX
JB loop17to31
+ JMP fail
+// We can get here only when AVX2 is enabled and cutoff for indexShortStr is set to 63
+// So no need to check cpuid
+_32_or_more:
+ CMPQ AX, $32
+ JA _33_to_63
+ VMOVDQU (BP), Y1
+ LEAQ -31(DI)(DX*1), DX
+loop32:
+ VMOVDQU (DI), Y2
+ VPCMPEQB Y1, Y2, Y3
+ VPMOVMSKB Y3, SI
+ CMPL SI, $0xffffffff
+ JE success_avx2
+ ADDQ $1,DI
+ CMPQ DI,DX
+ JB loop32
+ JMP fail_avx2
+_33_to_63:
+ LEAQ 1(DI)(DX*1), DX
+ SUBQ AX, DX
+ VMOVDQU -32(BP)(AX*1), Y0
+ VMOVDQU (BP), Y1
+loop33to63:
+ VMOVDQU (DI), Y2
+ VPCMPEQB Y1, Y2, Y3
+ VPMOVMSKB Y3, SI
+ CMPL SI, $0xffffffff
+ JE partial_success33to63
+ ADDQ $1,DI
+ CMPQ DI,DX
+ JB loop33to63
+ JMP fail_avx2
+partial_success33to63:
+ VMOVDQU -32(AX)(DI*1), Y3
+ VPCMPEQB Y0, Y3, Y4
+ VPMOVMSKB Y4, SI
+ CMPL SI, $0xffffffff
+ JE success_avx2
+ ADDQ $1,DI
+ CMPQ DI,DX
+ JB loop33to63
+fail_avx2:
+ VZEROUPPER
fail:
- MOVQ $-1, ret+32(FP)
+ MOVQ $-1, (R11)
RET
+success_avx2:
+ VZEROUPPER
+ JMP success
sse42:
MOVL runtime·cpuid_ecx(SB), CX
ANDL $0x100000, CX
@@ -1893,8 +1991,8 @@ loop_sse42:
sse42_success:
ADDQ CX, DI
success:
- SUBQ s+0(FP), DI
- MOVQ DI, ret+32(FP)
+ SUBQ R10, DI
+ MOVQ DI, (R11)
RET
@@ -2052,7 +2150,7 @@ eqret:
MOVB $0, ret+48(FP)
RET
-TEXT runtime·fastrand1(SB), NOSPLIT, $0-4
+TEXT runtime·fastrand(SB), NOSPLIT, $0-4
get_tls(CX)
MOVQ g(CX), AX
MOVQ g_m(AX), AX
diff --git a/src/runtime/asm_amd64p32.s b/src/runtime/asm_amd64p32.s
index 452ce04..c3c1c15 100644
--- a/src/runtime/asm_amd64p32.s
+++ b/src/runtime/asm_amd64p32.s
@@ -12,7 +12,7 @@ TEXT runtime·rt0_go(SB),NOSPLIT,$0
MOVL argc+0(FP), AX
MOVL argv+4(FP), BX
MOVL SP, CX
- SUBL $128, SP // plenty of scratch
+ SUBL $128, CX // plenty of scratch
ANDL $~15, CX
MOVL CX, SP
@@ -107,8 +107,12 @@ TEXT runtime·gosave(SB), NOSPLIT, $0-4
MOVL BX, gobuf_sp(AX)
MOVL 0(SP), BX // caller's PC
MOVL BX, gobuf_pc(AX)
- MOVL $0, gobuf_ctxt(AX)
MOVQ $0, gobuf_ret(AX)
+ // Assert ctxt is zero. See func save.
+ MOVL gobuf_ctxt(AX), BX
+ TESTL BX, BX
+ JZ 2(PC)
+ CALL runtime·badctxt(SB)
get_tls(CX)
MOVL g(CX), BX
MOVL BX, gobuf_g(AX)
@@ -116,8 +120,20 @@ TEXT runtime·gosave(SB), NOSPLIT, $0-4
// void gogo(Gobuf*)
// restore state from Gobuf; longjmp
-TEXT runtime·gogo(SB), NOSPLIT, $0-4
+TEXT runtime·gogo(SB), NOSPLIT, $8-4
MOVL buf+0(FP), BX // gobuf
+
+ // If ctxt is not nil, invoke deletion barrier before overwriting.
+ MOVL gobuf_ctxt(BX), DX
+ TESTL DX, DX
+ JZ nilctxt
+ LEAL gobuf_ctxt(BX), AX
+ MOVL AX, 0(SP)
+ MOVL $0, 4(SP)
+ CALL runtime·writebarrierptr_prewrite(SB)
+ MOVL buf+0(FP), BX
+
+nilctxt:
MOVL gobuf_g(BX), DX
MOVL 0(DX), CX // make sure g != nil
get_tls(CX)
@@ -249,13 +265,15 @@ TEXT runtime·morestack(SB),NOSPLIT,$0-0
// Cannot grow scheduler stack (m->g0).
MOVL m_g0(BX), SI
CMPL g(CX), SI
- JNE 2(PC)
+ JNE 3(PC)
+ CALL runtime·badmorestackg0(SB)
MOVL 0, AX
// Cannot grow signal stack (m->gsignal).
MOVL m_gsignal(BX), SI
CMPL g(CX), SI
- JNE 2(PC)
+ JNE 3(PC)
+ CALL runtime·badmorestackgsignal(SB)
MOVL 0, AX
// Called from f.
@@ -274,14 +292,16 @@ TEXT runtime·morestack(SB),NOSPLIT,$0-0
MOVL SI, (g_sched+gobuf_g)(SI)
LEAL 8(SP), AX // f's SP
MOVL AX, (g_sched+gobuf_sp)(SI)
- MOVL DX, (g_sched+gobuf_ctxt)(SI)
+ // newstack will fill gobuf.ctxt.
// Call newstack on m->g0's stack.
MOVL m_g0(BX), BX
MOVL BX, g(CX)
MOVL (g_sched+gobuf_sp)(BX), SP
+ PUSHQ DX // ctxt argument
CALL runtime·newstack(SB)
MOVL $0, 0x1003 // crash if newstack returns
+ POPQ DX // keep balance check happy
RET
// morestack trampolines
@@ -367,6 +387,7 @@ TEXT NAME(SB), WRAPPER, $MAXSIZE-20; \
MOVL (DX), AX; \
CALL AX; \
/* copy return values back */ \
+ MOVL argtype+0(FP), DX; \
MOVL argptr+8(FP), DI; \
MOVL argsize+12(FP), CX; \
MOVL retoffset+16(FP), BX; \
@@ -374,17 +395,19 @@ TEXT NAME(SB), WRAPPER, $MAXSIZE-20; \
ADDL BX, DI; \
ADDL BX, SI; \
SUBL BX, CX; \
- REP;MOVSB; \
- /* execute write barrier updates */ \
- MOVL argtype+0(FP), DX; \
- MOVL argptr+8(FP), DI; \
- MOVL argsize+12(FP), CX; \
- MOVL retoffset+16(FP), BX; \
- MOVL DX, 0(SP); \
- MOVL DI, 4(SP); \
- MOVL CX, 8(SP); \
- MOVL BX, 12(SP); \
- CALL runtime·callwritebarrier(SB); \
+ CALL callRet<>(SB); \
+ RET
+
+// callRet copies return values back at the end of call*. This is a
+// separate function so it can allocate stack space for the arguments
+// to reflectcallmove. It does not follow the Go ABI; it expects its
+// arguments in registers.
+TEXT callRet<>(SB), NOSPLIT, $16-0
+ MOVL DX, 0(SP)
+ MOVL DI, 4(SP)
+ MOVL SI, 8(SP)
+ MOVL CX, 12(SP)
+ CALL runtime·reflectcallmove(SB)
RET
CALLFN(·call16, 16)
@@ -449,13 +472,13 @@ TEXT runtime·asmcgocall(SB),NOSPLIT,$0-12
// cgocallback(void (*fn)(void*), void *frame, uintptr framesize)
// Not implemented.
-TEXT runtime·cgocallback(SB),NOSPLIT,$0-12
+TEXT runtime·cgocallback(SB),NOSPLIT,$0-16
MOVL 0, AX
RET
// cgocallback_gofunc(FuncVal*, void *frame, uintptr framesize)
// Not implemented.
-TEXT ·cgocallback_gofunc(SB),NOSPLIT,$0-12
+TEXT ·cgocallback_gofunc(SB),NOSPLIT,$0-16
MOVL 0, AX
RET
@@ -477,7 +500,7 @@ TEXT runtime·stackcheck(SB), NOSPLIT, $0-0
MOVL 0, AX
RET
-TEXT runtime·memclr(SB),NOSPLIT,$0-8
+TEXT runtime·memclrNoHeapPointers(SB),NOSPLIT,$0-8
MOVL ptr+0(FP), DI
MOVL n+4(FP), CX
MOVQ CX, BX
@@ -521,11 +544,6 @@ setbar:
CALL runtime·setNextBarrierPC(SB)
RET
-TEXT runtime·getcallersp(SB),NOSPLIT,$0-12
- MOVL argp+0(FP), AX
- MOVL AX, ret+8(FP)
- RET
-
// int64 runtime·cputicks(void)
TEXT runtime·cputicks(SB),NOSPLIT,$0-0
RDTSC
@@ -561,20 +579,20 @@ TEXT runtime·aeshash(SB),NOSPLIT,$0-20
MOVL AX, ret+16(FP)
RET
-TEXT runtime·aeshashstr(SB),NOSPLIT,$0-20
- MOVL AX, ret+16(FP)
+TEXT runtime·aeshashstr(SB),NOSPLIT,$0-12
+ MOVL AX, ret+8(FP)
RET
-TEXT runtime·aeshash32(SB),NOSPLIT,$0-20
- MOVL AX, ret+16(FP)
+TEXT runtime·aeshash32(SB),NOSPLIT,$0-12
+ MOVL AX, ret+8(FP)
RET
-TEXT runtime·aeshash64(SB),NOSPLIT,$0-20
- MOVL AX, ret+16(FP)
+TEXT runtime·aeshash64(SB),NOSPLIT,$0-12
+ MOVL AX, ret+8(FP)
RET
// memequal(p, q unsafe.Pointer, size uintptr) bool
-TEXT runtime·memequal(SB),NOSPLIT,$0-13
+TEXT runtime·memequal(SB),NOSPLIT,$0-17
MOVL a+0(FP), SI
MOVL b+4(FP), DI
CMPL SI, DI
@@ -607,16 +625,16 @@ eq:
// See runtime_test.go:eqstring_generic for
// equivalent Go code.
TEXT runtime·eqstring(SB),NOSPLIT,$0-17
- MOVL s1str+0(FP), SI
- MOVL s2str+8(FP), DI
+ MOVL s1_base+0(FP), SI
+ MOVL s2_base+8(FP), DI
CMPL SI, DI
JEQ same
- MOVL s1len+4(FP), BX
+ MOVL s1_len+4(FP), BX
CALL runtime·memeqbody(SB)
- MOVB AX, v+16(FP)
+ MOVB AX, ret+16(FP)
RET
same:
- MOVB $1, v+16(FP)
+ MOVB $1, ret+16(FP)
RET
// a in SI
@@ -973,7 +991,7 @@ eqret:
MOVB AX, ret+24(FP)
RET
-TEXT runtime·fastrand1(SB), NOSPLIT, $0-4
+TEXT runtime·fastrand(SB), NOSPLIT, $0-4
get_tls(CX)
MOVL g(CX), AX
MOVL g_m(AX), AX
diff --git a/src/runtime/asm_arm.s b/src/runtime/asm_arm.s
index f02297e..79c28a8 100644
--- a/src/runtime/asm_arm.s
+++ b/src/runtime/asm_arm.s
@@ -118,13 +118,30 @@ TEXT runtime·gosave(SB),NOSPLIT,$-4-4
MOVW $0, R11
MOVW R11, gobuf_lr(R0)
MOVW R11, gobuf_ret(R0)
- MOVW R11, gobuf_ctxt(R0)
+ // Assert ctxt is zero. See func save.
+ MOVW gobuf_ctxt(R0), R0
+ CMP R0, R11
+ B.EQ 2(PC)
+ CALL runtime·badctxt(SB)
RET
// void gogo(Gobuf*)
// restore state from Gobuf; longjmp
-TEXT runtime·gogo(SB),NOSPLIT,$-4-4
+TEXT runtime·gogo(SB),NOSPLIT,$8-4
+ MOVW buf+0(FP), R1
+
+ // If ctxt is not nil, invoke deletion barrier before overwriting.
+ MOVW gobuf_ctxt(R1), R0
+ CMP $0, R0
+ B.EQ nilctxt
+ MOVW $gobuf_ctxt(R1), R0
+ MOVW R0, 4(R13)
+ MOVW $0, R0
+ MOVW R0, 8(R13)
+ BL runtime·writebarrierptr_prewrite(SB)
MOVW buf+0(FP), R1
+
+nilctxt:
MOVW gobuf_g(R1), R0
BL setg<>(SB)
@@ -281,19 +298,23 @@ TEXT runtime·morestack(SB),NOSPLIT,$-4-0
MOVW g_m(g), R8
MOVW m_g0(R8), R4
CMP g, R4
- BL.EQ runtime·abort(SB)
+ BNE 3(PC)
+ BL runtime·badmorestackg0(SB)
+ B runtime·abort(SB)
// Cannot grow signal stack (m->gsignal).
MOVW m_gsignal(R8), R4
CMP g, R4
- BL.EQ runtime·abort(SB)
+ BNE 3(PC)
+ BL runtime·badmorestackgsignal(SB)
+ B runtime·abort(SB)
// Called from f.
// Set g->sched to context in f.
- MOVW R7, (g_sched+gobuf_ctxt)(g)
MOVW R13, (g_sched+gobuf_sp)(g)
MOVW LR, (g_sched+gobuf_pc)(g)
MOVW R3, (g_sched+gobuf_lr)(g)
+ // newstack will fill gobuf.ctxt.
// Called from f.
// Set m->morebuf to f's caller.
@@ -306,6 +327,9 @@ TEXT runtime·morestack(SB),NOSPLIT,$-4-0
MOVW m_g0(R8), R0
BL setg<>(SB)
MOVW (g_sched+gobuf_sp)(g), R13
+ MOVW $0, R0
+ MOVW.W R0, -8(R13) // create a call frame on g0
+ MOVW R7, 4(R13) // ctxt argument
BL runtime·newstack(SB)
// Not reached, but make sure the return PC from the call to newstack
@@ -399,6 +423,7 @@ TEXT NAME(SB), WRAPPER, $MAXSIZE-20; \
PCDATA $PCDATA_StackMapIndex, $0; \
BL (R0); \
/* copy return values back */ \
+ MOVW argtype+0(FP), R4; \
MOVW argptr+8(FP), R0; \
MOVW argsize+12(FP), R2; \
MOVW retoffset+16(FP), R3; \
@@ -406,24 +431,19 @@ TEXT NAME(SB), WRAPPER, $MAXSIZE-20; \
ADD R3, R1; \
ADD R3, R0; \
SUB R3, R2; \
-loop: \
- CMP $0, R2; \
- B.EQ end; \
- MOVBU.P 1(R1), R5; \
- MOVBU.P R5, 1(R0); \
- SUB $1, R2, R2; \
- B loop; \
-end: \
- /* execute write barrier updates */ \
- MOVW argtype+0(FP), R1; \
- MOVW argptr+8(FP), R0; \
- MOVW argsize+12(FP), R2; \
- MOVW retoffset+16(FP), R3; \
- MOVW R1, 4(R13); \
- MOVW R0, 8(R13); \
- MOVW R2, 12(R13); \
- MOVW R3, 16(R13); \
- BL runtime·callwritebarrier(SB); \
+ BL callRet<>(SB); \
+ RET
+
+// callRet copies return values back at the end of call*. This is a
+// separate function so it can allocate stack space for the arguments
+// to reflectcallmove. It does not follow the Go ABI; it expects its
+// arguments in registers.
+TEXT callRet<>(SB), NOSPLIT, $16-0
+ MOVW R4, 4(R13)
+ MOVW R0, 8(R13)
+ MOVW R1, 12(R13)
+ MOVW R2, 16(R13)
+ BL runtime·reflectcallmove(SB)
RET
CALLFN(·call16, 16)
@@ -473,13 +493,18 @@ TEXT runtime·jmpdefer(SB),NOSPLIT,$0-8
B (R1)
// Save state of caller into g->sched. Smashes R11.
-TEXT gosave<>(SB),NOSPLIT,$0
+TEXT gosave<>(SB),NOSPLIT,$-4
MOVW LR, (g_sched+gobuf_pc)(g)
MOVW R13, (g_sched+gobuf_sp)(g)
MOVW $0, R11
MOVW R11, (g_sched+gobuf_lr)(g)
MOVW R11, (g_sched+gobuf_ret)(g)
MOVW R11, (g_sched+gobuf_ctxt)(g)
+ // Assert ctxt is zero. See func save.
+ MOVW (g_sched+gobuf_ctxt)(g), R11
+ CMP $0, R11
+ B.EQ 2(PC)
+ CALL runtime·badctxt(SB)
RET
// func asmcgocall(fn, arg unsafe.Pointer) int32
@@ -695,12 +720,6 @@ setbar:
BL runtime·setNextBarrierPC(SB)
RET
-TEXT runtime·getcallersp(SB),NOSPLIT,$-4-8
- MOVW argp+0(FP), R0
- MOVW $-4(R0), R0
- MOVW R0, ret+4(FP)
- RET
-
TEXT runtime·emptyfunc(SB),0,$0-0
RET
@@ -855,13 +874,13 @@ samebytes:
// See runtime_test.go:eqstring_generic for
// equivalent Go code.
TEXT runtime·eqstring(SB),NOSPLIT,$-4-17
- MOVW s1str+0(FP), R2
- MOVW s2str+8(FP), R3
+ MOVW s1_base+0(FP), R2
+ MOVW s2_base+8(FP), R3
MOVW $1, R8
- MOVB R8, v+16(FP)
+ MOVB R8, ret+16(FP)
CMP R2, R3
RET.EQ
- MOVW s1len+4(FP), R0
+ MOVW s1_len+4(FP), R0
ADD R2, R0, R6
loop:
CMP R2, R6
@@ -871,7 +890,7 @@ loop:
CMP R4, R5
BEQ loop
MOVW $0, R8
- MOVB R8, v+16(FP)
+ MOVB R8, ret+16(FP)
RET
// TODO: share code with memequal?
@@ -952,7 +971,7 @@ _sib_notfound:
MOVW R0, ret+12(FP)
RET
-TEXT runtime·fastrand1(SB),NOSPLIT,$-4-4
+TEXT runtime·fastrand(SB),NOSPLIT,$-4-4
MOVW g_m(g), R1
MOVW m_fastrand(R1), R0
ADD.S R0, R0
@@ -1033,8 +1052,8 @@ TEXT runtime·usplitR0(SB),NOSPLIT,$0
SUB R1, R3, R1
RET
-TEXT runtime·sigreturn(SB),NOSPLIT,$0-4
- RET
+TEXT runtime·sigreturn(SB),NOSPLIT,$0-0
+ RET
#ifndef GOOS_nacl
// This is called from .init_array and follows the platform, not Go, ABI.
diff --git a/src/runtime/asm_arm64.s b/src/runtime/asm_arm64.s
index 7ebd7ba..0e286d4 100644
--- a/src/runtime/asm_arm64.s
+++ b/src/runtime/asm_arm64.s
@@ -11,9 +11,6 @@
TEXT runtime·rt0_go(SB),NOSPLIT,$0
// SP = stack; R0 = argc; R1 = argv
- // initialize essential registers
- BL runtime·reginit(SB)
-
SUB $32, RSP
MOVW R0, 8(RSP) // argc
MOVD R1, 16(RSP) // argv
@@ -100,15 +97,6 @@ TEXT runtime·breakpoint(SB),NOSPLIT,$-8-0
TEXT runtime·asminit(SB),NOSPLIT,$-8-0
RET
-TEXT runtime·reginit(SB),NOSPLIT,$-8-0
- // initialize essential FP registers
- FMOVD $4503601774854144.0, F27
- FMOVD $0.5, F29
- FSUBD F29, F29, F28
- FADDD F29, F29, F30
- FADDD F30, F30, F31
- RET
-
/*
* go-routine
*/
@@ -123,13 +111,29 @@ TEXT runtime·gosave(SB), NOSPLIT, $-8-8
MOVD g, gobuf_g(R3)
MOVD ZR, gobuf_lr(R3)
MOVD ZR, gobuf_ret(R3)
- MOVD ZR, gobuf_ctxt(R3)
+ // Assert ctxt is zero. See func save.
+ MOVD gobuf_ctxt(R3), R0
+ CMP $0, R0
+ BEQ 2(PC)
+ CALL runtime·badctxt(SB)
RET
// void gogo(Gobuf*)
// restore state from Gobuf; longjmp
-TEXT runtime·gogo(SB), NOSPLIT, $-8-8
+TEXT runtime·gogo(SB), NOSPLIT, $24-8
MOVD buf+0(FP), R5
+
+ // If ctxt is not nil, invoke deletion barrier before overwriting.
+ MOVD gobuf_ctxt(R5), R0
+ CMP $0, R0
+ BEQ nilctxt
+ MOVD $gobuf_ctxt(R5), R0
+ MOVD R0, 8(RSP)
+ MOVD ZR, 16(RSP)
+ BL runtime·writebarrierptr_prewrite(SB)
+ MOVD buf+0(FP), R5
+
+nilctxt:
MOVD gobuf_g(R5), g
BL runtime·save_g(SB)
@@ -268,22 +272,24 @@ TEXT runtime·morestack(SB),NOSPLIT,$-8-0
MOVD g_m(g), R8
MOVD m_g0(R8), R4
CMP g, R4
- BNE 2(PC)
+ BNE 3(PC)
+ BL runtime·badmorestackg0(SB)
B runtime·abort(SB)
// Cannot grow signal stack (m->gsignal).
MOVD m_gsignal(R8), R4
CMP g, R4
- BNE 2(PC)
+ BNE 3(PC)
+ BL runtime·badmorestackgsignal(SB)
B runtime·abort(SB)
// Called from f.
// Set g->sched to context in f
- MOVD R26, (g_sched+gobuf_ctxt)(g)
MOVD RSP, R0
MOVD R0, (g_sched+gobuf_sp)(g)
MOVD LR, (g_sched+gobuf_pc)(g)
MOVD R3, (g_sched+gobuf_lr)(g)
+ // newstack will fill gobuf.ctxt.
// Called from f.
// Set m->morebuf to f's callers.
@@ -297,6 +303,8 @@ TEXT runtime·morestack(SB),NOSPLIT,$-8-0
BL runtime·save_g(SB)
MOVD (g_sched+gobuf_sp)(g), R0
MOVD R0, RSP
+ MOVD.W $0, -16(RSP) // create a call frame on g0
+ MOVD R26, 8(RSP) // ctxt argument
BL runtime·newstack(SB)
// Not reached, but make sure the return PC from the call to newstack
@@ -343,8 +351,6 @@ TEXT reflect·call(SB), NOSPLIT, $0-0
TEXT ·reflectcall(SB), NOSPLIT, $-8-32
MOVWU argsize+24(FP), R16
- // NOTE(rsc): No call16, because CALLFN needs four words
- // of argument space to invoke callwritebarrier.
DISPATCH(runtime·call32, 32)
DISPATCH(runtime·call64, 64)
DISPATCH(runtime·call128, 128)
@@ -395,33 +401,27 @@ TEXT NAME(SB), WRAPPER, $MAXSIZE-24; \
PCDATA $PCDATA_StackMapIndex, $0; \
BL (R0); \
/* copy return values back */ \
+ MOVD argtype+0(FP), R7; \
MOVD arg+16(FP), R3; \
MOVWU n+24(FP), R4; \
MOVWU retoffset+28(FP), R6; \
- MOVD RSP, R5; \
+ ADD $8, RSP, R5; \
ADD R6, R5; \
ADD R6, R3; \
SUB R6, R4; \
- ADD $(8-1), R5; \
- SUB $1, R3; \
- ADD R5, R4; \
-loop: \
- CMP R5, R4; \
- BEQ end; \
- MOVBU.W 1(R5), R6; \
- MOVBU.W R6, 1(R3); \
- B loop; \
-end: \
- /* execute write barrier updates */ \
- MOVD argtype+0(FP), R7; \
- MOVD arg+16(FP), R3; \
- MOVWU n+24(FP), R4; \
- MOVWU retoffset+28(FP), R6; \
- MOVD R7, 8(RSP); \
- MOVD R3, 16(RSP); \
- MOVD R4, 24(RSP); \
- MOVD R6, 32(RSP); \
- BL runtime·callwritebarrier(SB); \
+ BL callRet<>(SB); \
+ RET
+
+// callRet copies return values back at the end of call*. This is a
+// separate function so it can allocate stack space for the arguments
+// to reflectcallmove. It does not follow the Go ABI; it expects its
+// arguments in registers.
+TEXT callRet<>(SB), NOSPLIT, $40-0
+ MOVD R7, 8(RSP)
+ MOVD R3, 16(RSP)
+ MOVD R5, 24(RSP)
+ MOVD R4, 32(RSP)
+ BL runtime·reflectcallmove(SB)
RET
// These have 8 added to make the overall frame size a multiple of 16,
@@ -499,7 +499,11 @@ TEXT gosave<>(SB),NOSPLIT,$-8
MOVD R0, (g_sched+gobuf_sp)(g)
MOVD $0, (g_sched+gobuf_lr)(g)
MOVD $0, (g_sched+gobuf_ret)(g)
- MOVD $0, (g_sched+gobuf_ctxt)(g)
+ // Assert ctxt is zero. See func save.
+ MOVD (g_sched+gobuf_ctxt)(g), R0
+ CMP $0, R0
+ BEQ 2(PC)
+ CALL runtime·badctxt(SB)
RET
// func asmcgocall(fn, arg unsafe.Pointer) int32
@@ -743,12 +747,6 @@ setbar:
BL runtime·setNextBarrierPC(SB)
RET
-TEXT runtime·getcallersp(SB),NOSPLIT,$0-16
- MOVD argp+0(FP), R0
- SUB $8, R0
- MOVD R0, ret+8(FP)
- RET
-
TEXT runtime·abort(SB),NOSPLIT,$-8-0
B (ZR)
UNDEF
@@ -869,9 +867,9 @@ samebytes:
// See runtime_test.go:eqstring_generic for
// equivalent Go code.
TEXT runtime·eqstring(SB),NOSPLIT,$0-33
- MOVD s1str+0(FP), R0
- MOVD s1len+8(FP), R1
- MOVD s2str+16(FP), R2
+ MOVD s1_base+0(FP), R0
+ MOVD s1_len+8(FP), R1
+ MOVD s2_base+16(FP), R2
ADD R0, R1 // end
loop:
CMP R0, R1
@@ -961,7 +959,7 @@ equal:
MOVB R0, ret+48(FP)
RET
-TEXT runtime·fastrand1(SB),NOSPLIT,$-8-4
+TEXT runtime·fastrand(SB),NOSPLIT,$-8-4
MOVD g_m(g), R1
MOVWU m_fastrand(R1), R0
ADD R0, R0
@@ -996,8 +994,8 @@ TEXT runtime·prefetcht2(SB),NOSPLIT,$0-8
TEXT runtime·prefetchnta(SB),NOSPLIT,$0-8
RET
-TEXT runtime·sigreturn(SB),NOSPLIT,$0-8
- RET
+TEXT runtime·sigreturn(SB),NOSPLIT,$0-0
+ RET
// This is called from .init_array and follows the platform, not Go, ABI.
TEXT runtime·addmoduledata(SB),NOSPLIT,$0-0
diff --git a/src/runtime/asm_mips64x.s b/src/runtime/asm_mips64x.s
index 7dd35aa..c2d991d 100644
--- a/src/runtime/asm_mips64x.s
+++ b/src/runtime/asm_mips64x.s
@@ -14,9 +14,6 @@
TEXT runtime·rt0_go(SB),NOSPLIT,$0
// R29 = stack; R4 = argc; R5 = argv
- // initialize essential registers
- JAL runtime·reginit(SB)
-
ADDV $-24, R29
MOVW R4, 8(R29) // argc
MOVV R5, 16(R29) // argv
@@ -88,19 +85,6 @@ TEXT runtime·breakpoint(SB),NOSPLIT,$-8-0
TEXT runtime·asminit(SB),NOSPLIT,$-8-0
RET
-TEXT _cgo_reginit(SB),NOSPLIT,$-8-0
- // crosscall1 needs to reginit, but can't
- // get at the 'runtime.reginit' symbol.
- JMP runtime·reginit(SB)
-
-TEXT runtime·reginit(SB),NOSPLIT,$-8-0
- // initialize essential FP registers
- MOVD $0.5, F26
- SUBD F26, F26, F24
- ADDD F26, F26, F28
- ADDD F28, F28, F30
- RET
-
/*
* go-routine
*/
@@ -114,13 +98,27 @@ TEXT runtime·gosave(SB), NOSPLIT, $-8-8
MOVV g, gobuf_g(R1)
MOVV R0, gobuf_lr(R1)
MOVV R0, gobuf_ret(R1)
- MOVV R0, gobuf_ctxt(R1)
+ // Assert ctxt is zero. See func save.
+ MOVV gobuf_ctxt(R1), R1
+ BEQ R1, 2(PC)
+ JAL runtime·badctxt(SB)
RET
// void gogo(Gobuf*)
// restore state from Gobuf; longjmp
-TEXT runtime·gogo(SB), NOSPLIT, $-8-8
+TEXT runtime·gogo(SB), NOSPLIT, $16-8
+ MOVV buf+0(FP), R3
+
+ // If ctxt is not nil, invoke deletion barrier before overwriting.
+ MOVV gobuf_ctxt(R3), R1
+ BEQ R1, nilctxt
+ MOVV $gobuf_ctxt(R3), R1
+ MOVV R1, 8(R29)
+ MOVV R0, 16(R29)
+ JAL runtime·writebarrierptr_prewrite(SB)
MOVV buf+0(FP), R3
+
+nilctxt:
MOVV gobuf_g(R3), g // make sure g is not nil
JAL runtime·save_g(SB)
@@ -247,20 +245,22 @@ TEXT runtime·morestack(SB),NOSPLIT,$-8-0
// Cannot grow scheduler stack (m->g0).
MOVV g_m(g), R7
MOVV m_g0(R7), R8
- BNE g, R8, 2(PC)
+ BNE g, R8, 3(PC)
+ JAL runtime·badmorestackg0(SB)
JAL runtime·abort(SB)
// Cannot grow signal stack (m->gsignal).
MOVV m_gsignal(R7), R8
- BNE g, R8, 2(PC)
+ BNE g, R8, 3(PC)
+ JAL runtime·badmorestackgsignal(SB)
JAL runtime·abort(SB)
// Called from f.
// Set g->sched to context in f.
- MOVV REGCTXT, (g_sched+gobuf_ctxt)(g)
MOVV R29, (g_sched+gobuf_sp)(g)
MOVV R31, (g_sched+gobuf_pc)(g)
MOVV R3, (g_sched+gobuf_lr)(g)
+ // newstack will fill gobuf.ctxt.
// Called from f.
// Set m->morebuf to f's caller.
@@ -272,6 +272,10 @@ TEXT runtime·morestack(SB),NOSPLIT,$-8-0
MOVV m_g0(R7), g
JAL runtime·save_g(SB)
MOVV (g_sched+gobuf_sp)(g), R29
+ // Create a stack frame on g0 to call newstack.
+ MOVV R0, -16(R29) // Zero saved LR in frame
+ ADDV $-16, R29
+ MOVV REGCTXT, 8(R29) // ctxt argument
JAL runtime·newstack(SB)
// Not reached, but make sure the return PC from the call to newstack
@@ -319,8 +323,6 @@ TEXT reflect·call(SB), NOSPLIT, $0-0
TEXT ·reflectcall(SB), NOSPLIT, $-8-32
MOVWU argsize+24(FP), R1
- // NOTE(rsc): No call16, because CALLFN needs four words
- // of argument space to invoke callwritebarrier.
DISPATCH(runtime·call32, 32)
DISPATCH(runtime·call64, 64)
DISPATCH(runtime·call128, 128)
@@ -371,33 +373,27 @@ TEXT NAME(SB), WRAPPER, $MAXSIZE-24; \
PCDATA $PCDATA_StackMapIndex, $0; \
JAL (R4); \
/* copy return values back */ \
+ MOVV argtype+0(FP), R5; \
MOVV arg+16(FP), R1; \
MOVWU n+24(FP), R2; \
MOVWU retoffset+28(FP), R4; \
- MOVV R29, R3; \
+ ADDV $8, R29, R3; \
ADDV R4, R3; \
ADDV R4, R1; \
SUBVU R4, R2; \
- ADDV $8, R3; \
- ADDV R3, R2; \
-loop: \
- BEQ R3, R2, end; \
- MOVBU (R3), R4; \
- ADDV $1, R3; \
- MOVBU R4, (R1); \
- ADDV $1, R1; \
- JMP loop; \
-end: \
- /* execute write barrier updates */ \
- MOVV argtype+0(FP), R5; \
- MOVV arg+16(FP), R1; \
- MOVWU n+24(FP), R2; \
- MOVWU retoffset+28(FP), R4; \
- MOVV R5, 8(R29); \
- MOVV R1, 16(R29); \
- MOVV R2, 24(R29); \
- MOVV R4, 32(R29); \
- JAL runtime·callwritebarrier(SB); \
+ JAL callRet<>(SB); \
+ RET
+
+// callRet copies return values back at the end of call*. This is a
+// separate function so it can allocate stack space for the arguments
+// to reflectcallmove. It does not follow the Go ABI; it expects its
+// arguments in registers.
+TEXT callRet<>(SB), NOSPLIT, $32-0
+ MOVV R5, 8(R29)
+ MOVV R1, 16(R29)
+ MOVV R3, 24(R29)
+ MOVV R2, 32(R29)
+ JAL runtime·reflectcallmove(SB)
RET
CALLFN(·call16, 16)
@@ -447,13 +443,16 @@ TEXT runtime·jmpdefer(SB), NOSPLIT, $-8-16
MOVV 0(REGCTXT), R4
JMP (R4)
-// Save state of caller into g->sched. Smashes R31.
+// Save state of caller into g->sched. Smashes R1.
TEXT gosave<>(SB),NOSPLIT,$-8
MOVV R31, (g_sched+gobuf_pc)(g)
MOVV R29, (g_sched+gobuf_sp)(g)
MOVV R0, (g_sched+gobuf_lr)(g)
MOVV R0, (g_sched+gobuf_ret)(g)
- MOVV R0, (g_sched+gobuf_ctxt)(g)
+ // Assert ctxt is zero. See func save.
+ MOVV (g_sched+gobuf_ctxt)(g), R1
+ BEQ R1, 2(PC)
+ JAL runtime·badctxt(SB)
RET
// func asmcgocall(fn, arg unsafe.Pointer) int32
@@ -659,12 +658,6 @@ setbar:
JAL runtime·setNextBarrierPC(SB)
RET
-TEXT runtime·getcallersp(SB),NOSPLIT,$0-16
- MOVV argp+0(FP), R1
- ADDV $-8, R1
- MOVV R1, ret+8(FP)
- RET
-
TEXT runtime·abort(SB),NOSPLIT,$-8-0
MOVW (R0), R0
UNDEF
@@ -746,13 +739,13 @@ eq:
// See runtime_test.go:eqstring_generic for
// equivalent Go code.
TEXT runtime·eqstring(SB),NOSPLIT,$0-33
- MOVV s1str+0(FP), R1
- MOVV s2str+16(FP), R2
+ MOVV s1_base+0(FP), R1
+ MOVV s2_base+16(FP), R2
MOVV $1, R3
MOVB R3, ret+32(FP)
BNE R1, R2, 2(PC)
RET
- MOVV s1len+8(FP), R3
+ MOVV s1_len+8(FP), R3
ADDV R1, R3, R4
loop:
BNE R1, R4, 2(PC)
@@ -838,7 +831,7 @@ notfound:
MOVV R1, ret+24(FP)
RET
-TEXT runtime·fastrand1(SB), NOSPLIT, $0-4
+TEXT runtime·fastrand(SB), NOSPLIT, $0-4
MOVV g_m(g), R2
MOVWU m_fastrand(R2), R1
ADDU R1, R1
diff --git a/src/runtime/asm_mipsx.s b/src/runtime/asm_mipsx.s
new file mode 100644
index 0000000..cd855c7
--- /dev/null
+++ b/src/runtime/asm_mipsx.s
@@ -0,0 +1,794 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build mips mipsle
+
+#include "go_asm.h"
+#include "go_tls.h"
+#include "funcdata.h"
+#include "textflag.h"
+
+#define REGCTXT R22
+
+TEXT runtime·rt0_go(SB),NOSPLIT,$0
+ // R29 = stack; R1 = argc; R2 = argv
+
+ ADDU $-12, R29
+ MOVW R1, 4(R29) // argc
+ MOVW R2, 8(R29) // argv
+
+ // create istack out of the given (operating system) stack.
+ // _cgo_init may update stackguard.
+ MOVW $runtime·g0(SB), g
+ MOVW $(-64*1024), R23
+ ADD R23, R29, R1
+ MOVW R1, g_stackguard0(g)
+ MOVW R1, g_stackguard1(g)
+ MOVW R1, (g_stack+stack_lo)(g)
+ MOVW R29, (g_stack+stack_hi)(g)
+
+// TODO(mips32): cgo
+
+nocgo:
+ // update stackguard after _cgo_init
+ MOVW (g_stack+stack_lo)(g), R1
+ ADD $const__StackGuard, R1
+ MOVW R1, g_stackguard0(g)
+ MOVW R1, g_stackguard1(g)
+
+ // set the per-goroutine and per-mach "registers"
+ MOVW $runtime·m0(SB), R1
+
+ // save m->g0 = g0
+ MOVW g, m_g0(R1)
+ // save m0 to g0->m
+ MOVW R1, g_m(g)
+
+ JAL runtime·check(SB)
+
+ // args are already prepared
+ JAL runtime·args(SB)
+ JAL runtime·osinit(SB)
+ JAL runtime·schedinit(SB)
+
+ // create a new goroutine to start program
+ MOVW $runtime·mainPC(SB), R1 // entry
+ ADDU $-12, R29
+ MOVW R1, 8(R29)
+ MOVW R0, 4(R29)
+ MOVW R0, 0(R29)
+ JAL runtime·newproc(SB)
+ ADDU $12, R29
+
+ // start this M
+ JAL runtime·mstart(SB)
+
+ UNDEF
+ RET
+
+DATA runtime·mainPC+0(SB)/4,$runtime·main(SB)
+GLOBL runtime·mainPC(SB),RODATA,$4
+
+TEXT runtime·breakpoint(SB),NOSPLIT,$0-0
+ BREAK
+ RET
+
+TEXT runtime·asminit(SB),NOSPLIT,$0-0
+ RET
+
+/*
+ * go-routine
+ */
+
+// void gosave(Gobuf*)
+// save state in Gobuf; setjmp
+TEXT runtime·gosave(SB),NOSPLIT,$-4-4
+ MOVW buf+0(FP), R1
+ MOVW R29, gobuf_sp(R1)
+ MOVW R31, gobuf_pc(R1)
+ MOVW g, gobuf_g(R1)
+ MOVW R0, gobuf_lr(R1)
+ MOVW R0, gobuf_ret(R1)
+ // Assert ctxt is zero. See func save.
+ MOVW gobuf_ctxt(R1), R1
+ BEQ R1, 2(PC)
+ JAL runtime·badctxt(SB)
+ RET
+
+// void gogo(Gobuf*)
+// restore state from Gobuf; longjmp
+TEXT runtime·gogo(SB),NOSPLIT,$8-4
+ MOVW buf+0(FP), R3
+
+ // If ctxt is not nil, invoke deletion barrier before overwriting.
+ MOVW gobuf_ctxt(R3), R1
+ BEQ R1, nilctxt
+ MOVW $gobuf_ctxt(R3), R1
+ MOVW R1, 4(R29)
+ MOVW R0, 8(R29)
+ JAL runtime·writebarrierptr_prewrite(SB)
+ MOVW buf+0(FP), R3
+
+nilctxt:
+ MOVW gobuf_g(R3), g // make sure g is not nil
+ JAL runtime·save_g(SB)
+
+ MOVW 0(g), R2
+ MOVW gobuf_sp(R3), R29
+ MOVW gobuf_lr(R3), R31
+ MOVW gobuf_ret(R3), R1
+ MOVW gobuf_ctxt(R3), REGCTXT
+ MOVW R0, gobuf_sp(R3)
+ MOVW R0, gobuf_ret(R3)
+ MOVW R0, gobuf_lr(R3)
+ MOVW R0, gobuf_ctxt(R3)
+ MOVW gobuf_pc(R3), R4
+ JMP (R4)
+
+// void mcall(fn func(*g))
+// Switch to m->g0's stack, call fn(g).
+// Fn must never return. It should gogo(&g->sched)
+// to keep running g.
+TEXT runtime·mcall(SB),NOSPLIT,$-4-4
+ // Save caller state in g->sched
+ MOVW R29, (g_sched+gobuf_sp)(g)
+ MOVW R31, (g_sched+gobuf_pc)(g)
+ MOVW R0, (g_sched+gobuf_lr)(g)
+ MOVW g, (g_sched+gobuf_g)(g)
+
+ // Switch to m->g0 & its stack, call fn.
+ MOVW g, R1
+ MOVW g_m(g), R3
+ MOVW m_g0(R3), g
+ JAL runtime·save_g(SB)
+ BNE g, R1, 2(PC)
+ JMP runtime·badmcall(SB)
+ MOVW fn+0(FP), REGCTXT // context
+ MOVW 0(REGCTXT), R4 // code pointer
+ MOVW (g_sched+gobuf_sp)(g), R29 // sp = m->g0->sched.sp
+ ADDU $-8, R29 // make room for 1 arg and fake LR
+ MOVW R1, 4(R29)
+ MOVW R0, 0(R29)
+ JAL (R4)
+ JMP runtime·badmcall2(SB)
+
+// systemstack_switch is a dummy routine that systemstack leaves at the bottom
+// of the G stack. We need to distinguish the routine that
+// lives at the bottom of the G stack from the one that lives
+// at the top of the system stack because the one at the top of
+// the system stack terminates the stack walk (see topofstack()).
+TEXT runtime·systemstack_switch(SB),NOSPLIT,$0-0
+ UNDEF
+ JAL (R31) // make sure this function is not leaf
+ RET
+
+// func systemstack(fn func())
+TEXT runtime·systemstack(SB),NOSPLIT,$0-4
+ MOVW fn+0(FP), R1 // R1 = fn
+ MOVW R1, REGCTXT // context
+ MOVW g_m(g), R2 // R2 = m
+
+ MOVW m_gsignal(R2), R3 // R3 = gsignal
+ BEQ g, R3, noswitch
+
+ MOVW m_g0(R2), R3 // R3 = g0
+ BEQ g, R3, noswitch
+
+ MOVW m_curg(R2), R4
+ BEQ g, R4, switch
+
+ // Bad: g is not gsignal, not g0, not curg. What is it?
+ // Hide call from linker nosplit analysis.
+ MOVW $runtime·badsystemstack(SB), R4
+ JAL (R4)
+
+switch:
+ // save our state in g->sched. Pretend to
+ // be systemstack_switch if the G stack is scanned.
+ MOVW $runtime·systemstack_switch(SB), R4
+ ADDU $8, R4 // get past prologue
+ MOVW R4, (g_sched+gobuf_pc)(g)
+ MOVW R29, (g_sched+gobuf_sp)(g)
+ MOVW R0, (g_sched+gobuf_lr)(g)
+ MOVW g, (g_sched+gobuf_g)(g)
+
+ // switch to g0
+ MOVW R3, g
+ JAL runtime·save_g(SB)
+ MOVW (g_sched+gobuf_sp)(g), R1
+ // make it look like mstart called systemstack on g0, to stop traceback
+ ADDU $-4, R1
+ MOVW $runtime·mstart(SB), R2
+ MOVW R2, 0(R1)
+ MOVW R1, R29
+
+ // call target function
+ MOVW 0(REGCTXT), R4 // code pointer
+ JAL (R4)
+
+ // switch back to g
+ MOVW g_m(g), R1
+ MOVW m_curg(R1), g
+ JAL runtime·save_g(SB)
+ MOVW (g_sched+gobuf_sp)(g), R29
+ MOVW R0, (g_sched+gobuf_sp)(g)
+ RET
+
+noswitch:
+ // already on m stack, just call directly
+ MOVW 0(REGCTXT), R4 // code pointer
+ JAL (R4)
+ RET
+
+/*
+ * support for morestack
+ */
+
+// Called during function prolog when more stack is needed.
+// Caller has already loaded:
+// R1: framesize, R2: argsize, R3: LR
+//
+// The traceback routines see morestack on a g0 as being
+// the top of a stack (for example, morestack calling newstack
+// calling the scheduler calling newm calling gc), so we must
+// record an argument size. For that purpose, it has no arguments.
+TEXT runtime·morestack(SB),NOSPLIT,$-4-0
+ // Cannot grow scheduler stack (m->g0).
+ MOVW g_m(g), R7
+ MOVW m_g0(R7), R8
+ BNE g, R8, 3(PC)
+ JAL runtime·badmorestackg0(SB)
+ JAL runtime·abort(SB)
+
+ // Cannot grow signal stack (m->gsignal).
+ MOVW m_gsignal(R7), R8
+ BNE g, R8, 3(PC)
+ JAL runtime·badmorestackgsignal(SB)
+ JAL runtime·abort(SB)
+
+ // Called from f.
+ // Set g->sched to context in f.
+ MOVW R29, (g_sched+gobuf_sp)(g)
+ MOVW R31, (g_sched+gobuf_pc)(g)
+ MOVW R3, (g_sched+gobuf_lr)(g)
+ // newstack will fill gobuf.ctxt.
+
+ // Called from f.
+ // Set m->morebuf to f's caller.
+ MOVW R3, (m_morebuf+gobuf_pc)(R7) // f's caller's PC
+ MOVW R29, (m_morebuf+gobuf_sp)(R7) // f's caller's SP
+ MOVW g, (m_morebuf+gobuf_g)(R7)
+
+ // Call newstack on m->g0's stack.
+ MOVW m_g0(R7), g
+ JAL runtime·save_g(SB)
+ MOVW (g_sched+gobuf_sp)(g), R29
+ // Create a stack frame on g0 to call newstack.
+ MOVW R0, -8(R29) // Zero saved LR in frame
+ ADDU $-8, R29
+ MOVW REGCTXT, 4(R29) // ctxt argument
+ JAL runtime·newstack(SB)
+
+ // Not reached, but make sure the return PC from the call to newstack
+ // is still in this function, and not the beginning of the next.
+ UNDEF
+
+TEXT runtime·morestack_noctxt(SB),NOSPLIT,$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
+// of constant-sized-frame functions to encode a few bits of size in the pc.
+
+#define DISPATCH(NAME,MAXSIZE) \
+ MOVW $MAXSIZE, R23; \
+ SGTU R1, R23, R23; \
+ BNE R23, 3(PC); \
+ MOVW $NAME(SB), R4; \
+ JMP (R4)
+
+TEXT reflect·call(SB),NOSPLIT,$0-20
+ JMP ·reflectcall(SB)
+
+TEXT ·reflectcall(SB),NOSPLIT,$-4-20
+ MOVW argsize+12(FP), R1
+
+ DISPATCH(runtime·call16, 16)
+ DISPATCH(runtime·call32, 32)
+ DISPATCH(runtime·call64, 64)
+ DISPATCH(runtime·call128, 128)
+ DISPATCH(runtime·call256, 256)
+ DISPATCH(runtime·call512, 512)
+ DISPATCH(runtime·call1024, 1024)
+ DISPATCH(runtime·call2048, 2048)
+ DISPATCH(runtime·call4096, 4096)
+ DISPATCH(runtime·call8192, 8192)
+ DISPATCH(runtime·call16384, 16384)
+ DISPATCH(runtime·call32768, 32768)
+ DISPATCH(runtime·call65536, 65536)
+ DISPATCH(runtime·call131072, 131072)
+ DISPATCH(runtime·call262144, 262144)
+ DISPATCH(runtime·call524288, 524288)
+ DISPATCH(runtime·call1048576, 1048576)
+ DISPATCH(runtime·call2097152, 2097152)
+ DISPATCH(runtime·call4194304, 4194304)
+ DISPATCH(runtime·call8388608, 8388608)
+ DISPATCH(runtime·call16777216, 16777216)
+ DISPATCH(runtime·call33554432, 33554432)
+ DISPATCH(runtime·call67108864, 67108864)
+ DISPATCH(runtime·call134217728, 134217728)
+ DISPATCH(runtime·call268435456, 268435456)
+ DISPATCH(runtime·call536870912, 536870912)
+ DISPATCH(runtime·call1073741824, 1073741824)
+ MOVW $runtime·badreflectcall(SB), R4
+ JMP (R4)
+
+#define CALLFN(NAME,MAXSIZE) \
+TEXT NAME(SB),WRAPPER,$MAXSIZE-20; \
+ NO_LOCAL_POINTERS; \
+ /* copy arguments to stack */ \
+ MOVW arg+8(FP), R1; \
+ MOVW argsize+12(FP), R2; \
+ MOVW R29, R3; \
+ ADDU $4, R3; \
+ ADDU R3, R2; \
+ BEQ R3, R2, 6(PC); \
+ MOVBU (R1), R4; \
+ ADDU $1, R1; \
+ MOVBU R4, (R3); \
+ ADDU $1, R3; \
+ JMP -5(PC); \
+ /* call function */ \
+ MOVW f+4(FP), REGCTXT; \
+ MOVW (REGCTXT), R4; \
+ PCDATA $PCDATA_StackMapIndex, $0; \
+ JAL (R4); \
+ /* copy return values back */ \
+ MOVW argtype+0(FP), R5; \
+ MOVW arg+8(FP), R1; \
+ MOVW n+12(FP), R2; \
+ MOVW retoffset+16(FP), R4; \
+ ADDU $4, R29, R3; \
+ ADDU R4, R3; \
+ ADDU R4, R1; \
+ SUBU R4, R2; \
+ JAL callRet<>(SB); \
+ RET
+
+// callRet copies return values back at the end of call*. This is a
+// separate function so it can allocate stack space for the arguments
+// to reflectcallmove. It does not follow the Go ABI; it expects its
+// arguments in registers.
+TEXT callRet<>(SB), NOSPLIT, $16-0
+ MOVW R5, 4(R29)
+ MOVW R1, 8(R29)
+ MOVW R3, 12(R29)
+ MOVW R2, 16(R29)
+ JAL runtime·reflectcallmove(SB)
+ RET
+
+CALLFN(·call16, 16)
+CALLFN(·call32, 32)
+CALLFN(·call64, 64)
+CALLFN(·call128, 128)
+CALLFN(·call256, 256)
+CALLFN(·call512, 512)
+CALLFN(·call1024, 1024)
+CALLFN(·call2048, 2048)
+CALLFN(·call4096, 4096)
+CALLFN(·call8192, 8192)
+CALLFN(·call16384, 16384)
+CALLFN(·call32768, 32768)
+CALLFN(·call65536, 65536)
+CALLFN(·call131072, 131072)
+CALLFN(·call262144, 262144)
+CALLFN(·call524288, 524288)
+CALLFN(·call1048576, 1048576)
+CALLFN(·call2097152, 2097152)
+CALLFN(·call4194304, 4194304)
+CALLFN(·call8388608, 8388608)
+CALLFN(·call16777216, 16777216)
+CALLFN(·call33554432, 33554432)
+CALLFN(·call67108864, 67108864)
+CALLFN(·call134217728, 134217728)
+CALLFN(·call268435456, 268435456)
+CALLFN(·call536870912, 536870912)
+CALLFN(·call1073741824, 1073741824)
+
+TEXT runtime·procyield(SB),NOSPLIT,$0-4
+ RET
+
+// void jmpdefer(fv, sp);
+// called from deferreturn.
+// 1. grab stored LR for caller
+// 2. sub 8 bytes to get back to JAL deferreturn
+// 3. JMP to fn
+TEXT runtime·jmpdefer(SB),NOSPLIT,$0-8
+ MOVW 0(R29), R31
+ ADDU $-8, R31
+
+ MOVW fv+0(FP), REGCTXT
+ MOVW argp+4(FP), R29
+ ADDU $-4, R29
+ NOR R0, R0 // prevent scheduling
+ MOVW 0(REGCTXT), R4
+ JMP (R4)
+
+// Save state of caller into g->sched. Smashes R1.
+TEXT gosave<>(SB),NOSPLIT,$0
+ MOVW R31, (g_sched+gobuf_pc)(g)
+ MOVW R29, (g_sched+gobuf_sp)(g)
+ MOVW R0, (g_sched+gobuf_lr)(g)
+ MOVW R0, (g_sched+gobuf_ret)(g)
+ // Assert ctxt is zero. See func save.
+ MOVW (g_sched+gobuf_ctxt)(g), R1
+ BEQ R1, 2(PC)
+ JAL runtime·badctxt(SB)
+ RET
+
+// func asmcgocall(fn, arg unsafe.Pointer) int32
+// Call fn(arg) on the scheduler stack,
+// aligned appropriately for the gcc ABI.
+// See cgocall.go for more details.
+// Not implemented.
+TEXT ·asmcgocall(SB),NOSPLIT,$0-12
+ UNDEF
+
+// cgocallback(void (*fn)(void*), void *frame, uintptr framesize)
+// Turn the fn into a Go func (by taking its address) and call
+// cgocallback_gofunc.
+// Not implemented.
+TEXT runtime·cgocallback(SB),NOSPLIT,$0-16
+ UNDEF
+
+// cgocallback_gofunc(FuncVal*, void *frame, uintptr framesize)
+// See cgocall.go for more details.
+// Not implemented.
+TEXT ·cgocallback_gofunc(SB),NOSPLIT,$0-16
+ UNDEF
+
+// void setg(G*); set g. for use by needm.
+// This only happens if iscgo, so jump straight to save_g
+TEXT runtime·setg(SB),NOSPLIT,$0-4
+ MOVW gg+0(FP), g
+ JAL runtime·save_g(SB)
+ RET
+
+// void setg_gcc(G*); set g in C TLS.
+// Must obey the gcc calling convention.
+// Not implemented.
+TEXT setg_gcc<>(SB),NOSPLIT,$0
+ UNDEF
+
+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
+
+// memhash_varlen(p unsafe.Pointer, h seed) uintptr
+// redirects to memhash(p, h, size) using the size
+// stored in the closure.
+TEXT runtime·memhash_varlen(SB),NOSPLIT,$16-12
+ GO_ARGS
+ NO_LOCAL_POINTERS
+ MOVW p+0(FP), R1
+ MOVW h+4(FP), R2
+ MOVW 4(REGCTXT), R3
+ MOVW R1, 4(R29)
+ MOVW R2, 8(R29)
+ MOVW R3, 12(R29)
+ JAL runtime·memhash(SB)
+ MOVW 16(R29), R1
+ MOVW R1, ret+8(FP)
+ RET
+
+// Not implemented.
+TEXT runtime·aeshash(SB),NOSPLIT,$0
+ UNDEF
+
+// Not implemented.
+TEXT runtime·aeshash32(SB),NOSPLIT,$0
+ UNDEF
+
+// Not implemented.
+TEXT runtime·aeshash64(SB),NOSPLIT,$0
+ UNDEF
+
+// Not implemented.
+TEXT runtime·aeshashstr(SB),NOSPLIT,$0
+ UNDEF
+
+// memequal(a, b unsafe.Pointer, size uintptr) bool
+TEXT runtime·memequal(SB),NOSPLIT,$0-13
+ MOVW a+0(FP), R1
+ MOVW b+4(FP), R2
+ BEQ R1, R2, eq
+ MOVW size+8(FP), R3
+ ADDU R1, R3, R4
+loop:
+ BNE R1, R4, test
+ MOVW $1, R1
+ MOVB R1, ret+12(FP)
+ RET
+test:
+ MOVBU (R1), R6
+ ADDU $1, R1
+ MOVBU (R2), R7
+ ADDU $1, R2
+ BEQ R6, R7, loop
+
+ MOVB R0, ret+12(FP)
+ RET
+eq:
+ MOVW $1, R1
+ MOVB R1, ret+12(FP)
+ RET
+
+// memequal_varlen(a, b unsafe.Pointer) bool
+TEXT runtime·memequal_varlen(SB),NOSPLIT,$0-9
+ MOVW a+0(FP), R1
+ MOVW b+4(FP), R2
+ BEQ R1, R2, eq
+ MOVW 4(REGCTXT), R3 // compiler stores size at offset 4 in the closure
+ ADDU R1, R3, R4
+loop:
+ BNE R1, R4, test
+ MOVW $1, R1
+ MOVB R1, ret+8(FP)
+ RET
+test:
+ MOVBU (R1), R6
+ ADDU $1, R1
+ MOVBU (R2), R7
+ ADDU $1, R2
+ BEQ R6, R7, loop
+
+ MOVB R0, ret+8(FP)
+ RET
+eq:
+ MOVW $1, R1
+ MOVB R1, ret+8(FP)
+ RET
+
+// eqstring tests whether two strings are equal.
+// The compiler guarantees that strings passed
+// to eqstring have equal length.
+// See runtime_test.go:eqstring_generic for
+// equivalent Go code.
+TEXT runtime·eqstring(SB),NOSPLIT,$0-17
+ MOVW s1_base+0(FP), R1
+ MOVW s2_base+8(FP), R2
+ MOVW $1, R3
+ MOVBU R3, ret+16(FP)
+ BNE R1, R2, 2(PC)
+ RET
+ MOVW s1_len+4(FP), R3
+ ADDU R1, R3, R4
+loop:
+ BNE R1, R4, 2(PC)
+ RET
+ MOVBU (R1), R6
+ ADDU $1, R1
+ MOVBU (R2), R7
+ ADDU $1, R2
+ BEQ R6, R7, loop
+ MOVB R0, ret+16(FP)
+ RET
+
+TEXT bytes·Equal(SB),NOSPLIT,$0-25
+ MOVW a_len+4(FP), R3
+ MOVW b_len+16(FP), R4
+ BNE R3, R4, noteq // unequal lengths are not equal
+
+ MOVW a+0(FP), R1
+ MOVW b+12(FP), R2
+ ADDU R1, R3 // end
+
+loop:
+ BEQ R1, R3, equal // reached the end
+ MOVBU (R1), R6
+ ADDU $1, R1
+ MOVBU (R2), R7
+ ADDU $1, R2
+ BEQ R6, R7, loop
+
+noteq:
+ MOVB R0, ret+24(FP)
+ RET
+
+equal:
+ MOVW $1, R1
+ MOVB R1, ret+24(FP)
+ RET
+
+TEXT bytes·IndexByte(SB),NOSPLIT,$0-20
+ MOVW s+0(FP), R1
+ MOVW s_len+4(FP), R2
+ MOVBU c+12(FP), R3 // byte to find
+ ADDU $1, R1, R4 // store base+1 for later
+ ADDU R1, R2 // end
+
+loop:
+ BEQ R1, R2, notfound
+ MOVBU (R1), R5
+ ADDU $1, R1
+ BNE R3, R5, loop
+
+ SUBU R4, R1 // R1 will be one beyond the position we want so remove (base+1)
+ MOVW R1, ret+16(FP)
+ RET
+
+notfound:
+ MOVW $-1, R1
+ MOVW R1, ret+16(FP)
+ RET
+
+TEXT strings·IndexByte(SB),NOSPLIT,$0-16
+ MOVW s_base+0(FP), R1
+ MOVW s_len+4(FP), R2
+ MOVBU c+8(FP), R3 // byte to find
+ ADDU $1, R1, R4 // store base+1 for later
+ ADDU R1, R2 // end
+
+loop:
+ BEQ R1, R2, notfound
+ MOVBU (R1), R5
+ ADDU $1, R1
+ BNE R3, R5, loop
+
+ SUBU R4, R1 // remove (base+1)
+ MOVW R1, ret+12(FP)
+ RET
+
+notfound:
+ MOVW $-1, R1
+ MOVW R1, ret+12(FP)
+ RET
+
+TEXT runtime·cmpstring(SB),NOSPLIT,$0-20
+ MOVW s1_base+0(FP), R3
+ MOVW s1_len+4(FP), R1
+ MOVW s2_base+8(FP), R4
+ MOVW s2_len+12(FP), R2
+ BEQ R3, R4, samebytes
+ SGTU R1, R2, R7
+ MOVW R1, R8
+ CMOVN R7, R2, R8 // R8 is min(R1, R2)
+
+ ADDU R3, R8 // R3 is current byte in s1, R8 is last byte in s1 to compare
+loop:
+ BEQ R3, R8, samebytes // all compared bytes were the same; compare lengths
+
+ MOVBU (R3), R6
+ ADDU $1, R3
+ MOVBU (R4), R7
+ ADDU $1, R4
+ BEQ R6, R7 , loop
+ // bytes differed
+ SGTU R6, R7, R8
+ MOVW $-1, R6
+ CMOVZ R8, R6, R8
+ JMP cmp_ret
+samebytes:
+ SGTU R1, R2, R6
+ SGTU R2, R1, R7
+ SUBU R7, R6, R8
+cmp_ret:
+ MOVW R8, ret+16(FP)
+ RET
+
+TEXT bytes·Compare(SB),NOSPLIT,$0-28
+ MOVW s1_base+0(FP), R3
+ MOVW s2_base+12(FP), R4
+ MOVW s1_len+4(FP), R1
+ MOVW s2_len+16(FP), R2
+ BEQ R3, R4, samebytes
+ SGTU R1, R2, R7
+ MOVW R1, R8
+ CMOVN R7, R2, R8 // R8 is min(R1, R2)
+
+ ADDU R3, R8 // R3 is current byte in s1, R8 is last byte in s1 to compare
+loop:
+ BEQ R3, R8, samebytes
+
+ MOVBU (R3), R6
+ ADDU $1, R3
+ MOVBU (R4), R7
+ ADDU $1, R4
+ BEQ R6, R7 , loop
+
+ SGTU R6, R7, R8
+ MOVW $-1, R6
+ CMOVZ R8, R6, R8
+ JMP cmp_ret
+samebytes:
+ SGTU R1, R2, R6
+ SGTU R2, R1, R7
+ SUBU R7, R6, R8
+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
+
+// Called from cgo wrappers, this function returns g->m->curg.stack.hi.
+// Must obey the gcc calling convention.
+// Not implemented.
+TEXT _cgo_topofstack(SB),NOSPLIT,$-4
+ UNDEF
+
+// The top-most function running on a goroutine
+// returns to goexit+PCQuantum.
+TEXT runtime·goexit(SB),NOSPLIT,$-4-0
+ NOR R0, R0 // NOP
+ JAL runtime·goexit1(SB) // does not return
+ // traceback from goexit1 must hit code range of goexit
+ NOR R0, R0 // NOP
+
+TEXT runtime·prefetcht0(SB),NOSPLIT,$0-4
+ RET
+
+TEXT runtime·prefetcht1(SB),NOSPLIT,$0-4
+ RET
+
+TEXT runtime·prefetcht2(SB),NOSPLIT,$0-4
+ RET
+
+TEXT runtime·prefetchnta(SB),NOSPLIT,$0-4
+ RET
+
+TEXT ·checkASM(SB),NOSPLIT,$0-1
+ MOVW $1, R1
+ MOVB R1, ret+0(FP)
+ RET
diff --git a/src/runtime/asm_ppc64x.s b/src/runtime/asm_ppc64x.s
index 32c63c2..1d6adcc 100644
--- a/src/runtime/asm_ppc64x.s
+++ b/src/runtime/asm_ppc64x.s
@@ -106,12 +106,6 @@ TEXT _cgo_reginit(SB),NOSPLIT|NOFRAME,$0-0
TEXT runtime·reginit(SB),NOSPLIT|NOFRAME,$0-0
// set R0 to zero, it's expected by the toolchain
XOR R0, R0
- // initialize essential FP registers
- FMOVD $4503601774854144.0, F27
- FMOVD $0.5, F29
- FSUB F29, F29, F28
- FADD F29, F29, F30
- FADD F30, F30, F31
RET
/*
@@ -128,13 +122,29 @@ TEXT runtime·gosave(SB), NOSPLIT|NOFRAME, $0-8
MOVD g, gobuf_g(R3)
MOVD R0, gobuf_lr(R3)
MOVD R0, gobuf_ret(R3)
- MOVD R0, gobuf_ctxt(R3)
+ // Assert ctxt is zero. See func save.
+ MOVD gobuf_ctxt(R3), R3
+ CMP R0, R3
+ BEQ 2(PC)
+ BL runtime·badctxt(SB)
RET
// void gogo(Gobuf*)
// restore state from Gobuf; longjmp
-TEXT runtime·gogo(SB), NOSPLIT|NOFRAME, $0-8
+TEXT runtime·gogo(SB), NOSPLIT, $16-8
MOVD buf+0(FP), R5
+
+ // If ctxt is not nil, invoke deletion barrier before overwriting.
+ MOVD gobuf_ctxt(R5), R3
+ CMP R0, R3
+ BEQ nilctxt
+ MOVD $gobuf_ctxt(R5), R3
+ MOVD R3, FIXED_FRAME+0(R1)
+ MOVD R0, FIXED_FRAME+8(R1)
+ BL runtime·writebarrierptr_prewrite(SB)
+ MOVD buf+0(FP), R5
+
+nilctxt:
MOVD gobuf_g(R5), g // make sure g is not nil
BL runtime·save_g(SB)
@@ -290,22 +300,24 @@ TEXT runtime·morestack(SB),NOSPLIT|NOFRAME,$0-0
MOVD g_m(g), R7
MOVD m_g0(R7), R8
CMP g, R8
- BNE 2(PC)
+ BNE 3(PC)
+ BL runtime·badmorestackg0(SB)
BL runtime·abort(SB)
// Cannot grow signal stack (m->gsignal).
MOVD m_gsignal(R7), R8
CMP g, R8
- BNE 2(PC)
+ BNE 3(PC)
+ BL runtime·badmorestackgsignal(SB)
BL runtime·abort(SB)
// Called from f.
// Set g->sched to context in f.
- MOVD R11, (g_sched+gobuf_ctxt)(g)
MOVD R1, (g_sched+gobuf_sp)(g)
MOVD LR, R8
MOVD R8, (g_sched+gobuf_pc)(g)
MOVD R5, (g_sched+gobuf_lr)(g)
+ // newstack will fill gobuf.ctxt.
// Called from f.
// Set m->morebuf to f's caller.
@@ -317,6 +329,8 @@ TEXT runtime·morestack(SB),NOSPLIT|NOFRAME,$0-0
MOVD m_g0(R7), g
BL runtime·save_g(SB)
MOVD (g_sched+gobuf_sp)(g), R1
+ MOVDU R0, -(FIXED_FRAME+8)(R1) // create a call frame on g0
+ MOVD R11, FIXED_FRAME+0(R1) // ctxt argument
BL runtime·newstack(SB)
// Not reached, but make sure the return PC from the call to newstack
@@ -365,8 +379,6 @@ TEXT reflect·call(SB), NOSPLIT, $0-0
TEXT ·reflectcall(SB), NOSPLIT|NOFRAME, $0-32
MOVWZ argsize+24(FP), R3
- // NOTE(rsc): No call16, because CALLFN needs four words
- // of argument space to invoke callwritebarrier.
DISPATCH(runtime·call32, 32)
DISPATCH(runtime·call64, 64)
DISPATCH(runtime·call128, 128)
@@ -420,33 +432,27 @@ TEXT NAME(SB), WRAPPER, $MAXSIZE-24; \
BL (CTR); \
MOVD 24(R1), R2; \
/* copy return values back */ \
+ MOVD argtype+0(FP), R7; \
MOVD arg+16(FP), R3; \
MOVWZ n+24(FP), R4; \
MOVWZ retoffset+28(FP), R6; \
- MOVD R1, R5; \
+ ADD $FIXED_FRAME, R1, R5; \
ADD R6, R5; \
ADD R6, R3; \
SUB R6, R4; \
- ADD $(FIXED_FRAME-1), R5; \
- SUB $1, R3; \
- ADD R5, R4; \
-loop: \
- CMP R5, R4; \
- BEQ end; \
- MOVBZU 1(R5), R6; \
- MOVBZU R6, 1(R3); \
- BR loop; \
-end: \
- /* execute write barrier updates */ \
- MOVD argtype+0(FP), R7; \
- MOVD arg+16(FP), R3; \
- MOVWZ n+24(FP), R4; \
- MOVWZ retoffset+28(FP), R6; \
- MOVD R7, FIXED_FRAME+0(R1); \
- MOVD R3, FIXED_FRAME+8(R1); \
- MOVD R4, FIXED_FRAME+16(R1); \
- MOVD R6, FIXED_FRAME+24(R1); \
- BL runtime·callwritebarrier(SB); \
+ BL callRet<>(SB); \
+ RET
+
+// callRet copies return values back at the end of call*. This is a
+// separate function so it can allocate stack space for the arguments
+// to reflectcallmove. It does not follow the Go ABI; it expects its
+// arguments in registers.
+TEXT callRet<>(SB), NOSPLIT, $32-0
+ MOVD R7, FIXED_FRAME+0(R1)
+ MOVD R3, FIXED_FRAME+8(R1)
+ MOVD R5, FIXED_FRAME+16(R1)
+ MOVD R4, FIXED_FRAME+24(R1)
+ BL runtime·reflectcallmove(SB)
RET
CALLFN(·call32, 32)
@@ -507,7 +513,11 @@ TEXT gosave<>(SB),NOSPLIT|NOFRAME,$0
MOVD R1, (g_sched+gobuf_sp)(g)
MOVD R0, (g_sched+gobuf_lr)(g)
MOVD R0, (g_sched+gobuf_ret)(g)
- MOVD R0, (g_sched+gobuf_ctxt)(g)
+ // Assert ctxt is zero. See func save.
+ MOVD (g_sched+gobuf_ctxt)(g), R31
+ CMP R0, R31
+ BEQ 2(PC)
+ BL runtime·badctxt(SB)
RET
// func asmcgocall(fn, arg unsafe.Pointer) int32
@@ -748,12 +758,6 @@ setbar:
BL runtime·setNextBarrierPC(SB)
RET
-TEXT runtime·getcallersp(SB),NOSPLIT,$0-16
- MOVD argp+0(FP), R3
- SUB $FIXED_FRAME, R3
- MOVD R3, ret+8(FP)
- RET
-
TEXT runtime·abort(SB),NOSPLIT|NOFRAME,$0-0
MOVW (R0), R0
UNDEF
@@ -824,13 +828,220 @@ eq:
MOVB R3, ret+16(FP)
RET
-// Do an efficieint memequal for ppc64
-// for reuse where possible.
+// Do an efficient memcmp for ppc64le
+// R3 = s1 len
+// R4 = s2 len
+// R5 = s1 addr
+// R6 = s2 addr
+// R7 = addr of return value
+TEXT cmpbodyLE<>(SB),NOSPLIT|NOFRAME,$0-0
+ MOVD R3,R8 // set up length
+ CMP R3,R4,CR2 // unequal?
+ BC 12,8,setuplen // BLT CR2
+ MOVD R4,R8 // use R4 for comparison len
+setuplen:
+ MOVD R8,CTR // set up loop counter
+ CMP R8,$8 // only optimize >=8
+ BLT simplecheck
+ DCBT (R5) // cache hint
+ DCBT (R6)
+ CMP R8,$32 // optimize >= 32
+ MOVD R8,R9
+ BLT setup8a // 8 byte moves only
+setup32a:
+ SRADCC $5,R8,R9 // number of 32 byte chunks
+ MOVD R9,CTR
+
+ // Special processing for 32 bytes or longer.
+ // Loading this way is faster and correct as long as the
+ // doublewords being compared are equal. Once they
+ // are found unequal, reload them in proper byte order
+ // to determine greater or less than.
+loop32a:
+ MOVD 0(R5),R9 // doublewords to compare
+ MOVD 0(R6),R10 // get 4 doublewords
+ MOVD 8(R5),R14
+ MOVD 8(R6),R15
+ CMPU R9,R10 // bytes equal?
+ MOVD $0,R16 // set up for cmpne
+ BNE cmpne // further compare for LT or GT
+ MOVD 16(R5),R9 // get next pair of doublewords
+ MOVD 16(R6),R10
+ CMPU R14,R15 // bytes match?
+ MOVD $8,R16 // set up for cmpne
+ BNE cmpne // further compare for LT or GT
+ MOVD 24(R5),R14 // get next pair of doublewords
+ MOVD 24(R6),R15
+ CMPU R9,R10 // bytes match?
+ MOVD $16,R16 // set up for cmpne
+ BNE cmpne // further compare for LT or GT
+ MOVD $-8,R16 // for cmpne, R5,R6 already inc by 32
+ ADD $32,R5 // bump up to next 32
+ ADD $32,R6
+ CMPU R14,R15 // bytes match?
+ BC 8,2,loop32a // br ctr and cr
+ BNE cmpne
+ ANDCC $24,R8,R9 // Any 8 byte chunks?
+ BEQ leftover // and result is 0
+setup8a:
+ SRADCC $3,R9,R9 // get the 8 byte count
+ BEQ leftover // shifted value is 0
+ MOVD R9,CTR // loop count for doublewords
+loop8:
+ MOVDBR (R5+R0),R9 // doublewords to compare
+ MOVDBR (R6+R0),R10 // LE compare order
+ ADD $8,R5
+ ADD $8,R6
+ CMPU R9,R10 // match?
+ BC 8,2,loop8 // bt ctr <> 0 && cr
+ BGT greater
+ BLT less
+leftover:
+ ANDCC $7,R8,R9 // check for leftover bytes
+ MOVD R9,CTR // save the ctr
+ BNE simple // leftover bytes
+ BC 12,10,equal // test CR2 for length comparison
+ BC 12,8,less
+ BR greater
+simplecheck:
+ CMP R8,$0 // remaining compare length 0
+ BNE simple // do simple compare
+ BC 12,10,equal // test CR2 for length comparison
+ BC 12,8,less // 1st len < 2nd len, result less
+ BR greater // 1st len > 2nd len must be greater
+simple:
+ MOVBZ 0(R5), R9 // get byte from 1st operand
+ ADD $1,R5
+ MOVBZ 0(R6), R10 // get byte from 2nd operand
+ ADD $1,R6
+ CMPU R9, R10
+ BC 8,2,simple // bc ctr <> 0 && cr
+ BGT greater // 1st > 2nd
+ BLT less // 1st < 2nd
+ BC 12,10,equal // test CR2 for length comparison
+ BC 12,9,greater // 2nd len > 1st len
+ BR less // must be less
+cmpne: // only here is not equal
+ MOVDBR (R5+R16),R8 // reload in reverse order
+ MOVDBR (R6+R16),R9
+ CMPU R8,R9 // compare correct endianness
+ BGT greater // here only if NE
+less:
+ MOVD $-1,R3
+ MOVD R3,(R7) // return value if A < B
+ RET
+equal:
+ MOVD $0,(R7) // return value if A == B
+ RET
+greater:
+ MOVD $1,R3
+ MOVD R3,(R7) // return value if A > B
+ RET
+
+// Do an efficient memcmp for ppc64 (BE)
+// R3 = s1 len
+// R4 = s2 len
+// R5 = s1 addr
+// R6 = s2 addr
+// R7 = addr of return value
+TEXT cmpbodyBE<>(SB),NOSPLIT|NOFRAME,$0-0
+ MOVD R3,R8 // set up length
+ CMP R3,R4,CR2 // unequal?
+ BC 12,8,setuplen // BLT CR2
+ MOVD R4,R8 // use R4 for comparison len
+setuplen:
+ MOVD R8,CTR // set up loop counter
+ CMP R8,$8 // only optimize >=8
+ BLT simplecheck
+ DCBT (R5) // cache hint
+ DCBT (R6)
+ CMP R8,$32 // optimize >= 32
+ MOVD R8,R9
+ BLT setup8a // 8 byte moves only
+
+setup32a:
+ SRADCC $5,R8,R9 // number of 32 byte chunks
+ MOVD R9,CTR
+loop32a:
+ MOVD 0(R5),R9 // doublewords to compare
+ MOVD 0(R6),R10 // get 4 doublewords
+ MOVD 8(R5),R14
+ MOVD 8(R6),R15
+ CMPU R9,R10 // bytes equal?
+ BLT less // found to be less
+ BGT greater // found to be greater
+ MOVD 16(R5),R9 // get next pair of doublewords
+ MOVD 16(R6),R10
+ CMPU R14,R15 // bytes match?
+ BLT less // found less
+ BGT greater // found greater
+ MOVD 24(R5),R14 // get next pair of doublewords
+ MOVD 24(R6),R15
+ CMPU R9,R10 // bytes match?
+ BLT less // found to be less
+ BGT greater // found to be greater
+ ADD $32,R5 // bump up to next 32
+ ADD $32,R6
+ CMPU R14,R15 // bytes match?
+ BC 8,2,loop32a // br ctr and cr
+ BLT less // with BE, byte ordering is
+ BGT greater // good for compare
+ ANDCC $24,R8,R9 // Any 8 byte chunks?
+ BEQ leftover // and result is 0
+setup8a:
+ SRADCC $3,R9,R9 // get the 8 byte count
+ BEQ leftover // shifted value is 0
+ MOVD R9,CTR // loop count for doublewords
+loop8:
+ MOVD (R5),R9
+ MOVD (R6),R10
+ ADD $8,R5
+ ADD $8,R6
+ CMPU R9,R10 // match?
+ BC 8,2,loop8 // bt ctr <> 0 && cr
+ BGT greater
+ BLT less
+leftover:
+ ANDCC $7,R8,R9 // check for leftover bytes
+ MOVD R9,CTR // save the ctr
+ BNE simple // leftover bytes
+ BC 12,10,equal // test CR2 for length comparison
+ BC 12,8,less
+ BR greater
+simplecheck:
+ CMP R8,$0 // remaining compare length 0
+ BNE simple // do simple compare
+ BC 12,10,equal // test CR2 for length comparison
+ BC 12,8,less // 1st len < 2nd len, result less
+ BR greater // same len, must be equal
+simple:
+ MOVBZ 0(R5),R9 // get byte from 1st operand
+ ADD $1,R5
+ MOVBZ 0(R6),R10 // get byte from 2nd operand
+ ADD $1,R6
+ CMPU R9,R10
+ BC 8,2,simple // bc ctr <> 0 && cr
+ BGT greater // 1st > 2nd
+ BLT less // 1st < 2nd
+ BC 12,10,equal // test CR2 for length comparison
+ BC 12,9,greater // 2nd len > 1st len
+less:
+ MOVD $-1,R3
+ MOVD R3,(R7) // return value if A < B
+ RET
+equal:
+ MOVD $0,(R7) // return value if A == B
+ RET
+greater:
+ MOVD $1,R3
+ MOVD R3,(R7) // return value if A > B
+ RET
+
+// Do an efficient memequal for ppc64
// R3 = s1
// R4 = s2
// R5 = len
// R9 = return value
-// R6, R7 clobbered
TEXT runtime·memeqbody(SB),NOSPLIT|NOFRAME,$0-0
MOVD R5,CTR
CMP R5,$8 // only optimize >=8
@@ -908,14 +1119,14 @@ equal:
// See runtime_test.go:eqstring_generic for
// equivalent Go code.
TEXT runtime·eqstring(SB),NOSPLIT,$0-33
- MOVD s1str+0(FP), R3
- MOVD s2str+16(FP), R4
+ MOVD s1_base+0(FP), R3
+ MOVD s2_base+16(FP), R4
MOVD $1, R5
MOVB R5, ret+32(FP)
CMP R3, R4
BNE 2(PC)
RET
- MOVD s1len+8(FP), R5
+ MOVD s1_len+8(FP), R5
BL runtime·memeqbody(SB)
MOVB R9, ret+32(FP)
RET
@@ -995,7 +1206,11 @@ TEXT runtime·cmpstring(SB),NOSPLIT|NOFRAME,$0-40
MOVD s2_base+16(FP), R6
MOVD s2_len+24(FP), R4
MOVD $ret+32(FP), R7
- BR runtime·cmpbody<>(SB)
+#ifdef GOARCH_ppc64le
+ BR cmpbodyLE<>(SB)
+#else
+ BR cmpbodyBE<>(SB)
+#endif
TEXT bytes·Compare(SB),NOSPLIT|NOFRAME,$0-56
MOVD s1+0(FP), R5
@@ -1003,52 +1218,13 @@ TEXT bytes·Compare(SB),NOSPLIT|NOFRAME,$0-56
MOVD s2+24(FP), R6
MOVD s2+32(FP), R4
MOVD $ret+48(FP), R7
- BR runtime·cmpbody<>(SB)
-
-// On entry:
-// R3 is the length of s1
-// R4 is the length of s2
-// R5 points to the start of s1
-// R6 points to the start of s2
-// R7 points to return value (-1/0/1 will be written here)
-//
-// On exit:
-// R5, R6, R8, R9 and R10 are clobbered
-TEXT runtime·cmpbody<>(SB),NOSPLIT|NOFRAME,$0-0
- CMP R5, R6
- BEQ samebytes // same starting pointers; compare lengths
- SUB $1, R5
- SUB $1, R6
- MOVD R4, R8
- CMP R3, R4
- BGE 2(PC)
- MOVD R3, R8 // R8 is min(R3, R4)
- ADD R5, R8 // R5 is current byte in s1, R8 is last byte in s1 to compare
-loop:
- CMP R5, R8
- BEQ samebytes // all compared bytes were the same; compare lengths
- MOVBZU 1(R5), R9
- MOVBZU 1(R6), R10
- CMP R9, R10
- BEQ loop
- // bytes differed
- MOVD $1, R4
- BGT 2(PC)
- NEG R4
- MOVD R4, (R7)
- RET
-samebytes:
- MOVD $1, R8
- CMP R3, R4
- BNE 3(PC)
- MOVD R0, (R7)
- RET
- BGT 2(PC)
- NEG R8
- MOVD R8, (R7)
- RET
+#ifdef GOARCH_ppc64le
+ BR cmpbodyLE<>(SB)
+#else
+ BR cmpbodyBE<>(SB)
+#endif
-TEXT runtime·fastrand1(SB), NOSPLIT, $0-4
+TEXT runtime·fastrand(SB), NOSPLIT, $0-4
MOVD g_m(g), R4
MOVWZ m_fastrand(R4), R3
ADD R3, R3
@@ -1109,8 +1285,8 @@ TEXT runtime·prefetcht2(SB),NOSPLIT,$0-8
TEXT runtime·prefetchnta(SB),NOSPLIT,$0-8
RET
-TEXT runtime·sigreturn(SB),NOSPLIT,$0-8
- RET
+TEXT runtime·sigreturn(SB),NOSPLIT,$0-0
+ RET
// prepGoExitFrame saves the current TOC pointer (i.e. the TOC pointer for the
// module containing runtime) to the frame that goexit will execute in when
diff --git a/src/runtime/asm_s390x.s b/src/runtime/asm_s390x.s
index 97f276c..c2212a5 100644
--- a/src/runtime/asm_s390x.s
+++ b/src/runtime/asm_s390x.s
@@ -7,44 +7,6 @@
#include "funcdata.h"
#include "textflag.h"
-// Indicate the status of vector facility
-// -1: init value
-// 0: vector not installed
-// 1: vector installed and enabled
-// 2: vector installed but not enabled
-
-DATA runtime·vectorfacility+0x00(SB)/4, $-1
-GLOBL runtime·vectorfacility(SB), NOPTR, $4
-
-TEXT runtime·checkvectorfacility(SB),NOSPLIT,$32-0
- MOVD $2, R0
- MOVD R1, tmp-32(SP)
- MOVD $x-24(SP), R1
- XC $24, 0(R1), 0(R1)
-// STFLE 0(R1)
- WORD $0xB2B01000
- MOVBZ z-8(SP), R1
- AND $0x40, R1
- BNE vectorinstalled
- MOVB $0, runtime·vectorfacility(SB) //Vector not installed
- MOVD tmp-32(SP), R1
- MOVD $0, R0
- RET
-vectorinstalled:
- // check if the vector instruction has been enabled
- VLEIB $0, $0xF, V16
- VLGVB $0, V16, R0
- CMPBEQ R0, $0xF, vectorenabled
- MOVB $2, runtime·vectorfacility(SB) //Vector installed but not enabled
- MOVD tmp-32(SP), R1
- MOVD $0, R0
- RET
-vectorenabled:
- MOVB $1, runtime·vectorfacility(SB) //Vector installed and enabled
- MOVD tmp-32(SP), R1
- MOVD $0, R0
- RET
-
TEXT runtime·rt0_go(SB),NOSPLIT,$0
// R2 = argc; R3 = argv; R11 = temp; R13 = g; R15 = stack pointer
// C TLS base pointer in AR0:AR1
@@ -110,22 +72,22 @@ nocgo:
MOVD $runtime·mainPC(SB), R2 // entry
SUB $24, R15
MOVD R2, 16(R15)
- MOVD R0, 8(R15)
- MOVD R0, 0(R15)
+ MOVD $0, 8(R15)
+ MOVD $0, 0(R15)
BL runtime·newproc(SB)
ADD $24, R15
// start this M
BL runtime·mstart(SB)
- MOVD R0, 1(R0)
+ MOVD $0, 1(R0)
RET
DATA runtime·mainPC+0(SB)/8,$runtime·main(SB)
GLOBL runtime·mainPC(SB),RODATA,$8
TEXT runtime·breakpoint(SB),NOSPLIT|NOFRAME,$0-0
- MOVD R0, 2(R0)
+ MOVD $0, 2(R0)
RET
TEXT runtime·asminit(SB),NOSPLIT|NOFRAME,$0-0
@@ -144,13 +106,27 @@ TEXT runtime·gosave(SB), NOSPLIT, $-8-8
MOVD g, gobuf_g(R3)
MOVD $0, gobuf_lr(R3)
MOVD $0, gobuf_ret(R3)
- MOVD $0, gobuf_ctxt(R3)
+ // Assert ctxt is zero. See func save.
+ MOVD gobuf_ctxt(R3), R3
+ CMPBEQ R3, $0, 2(PC)
+ BL runtime·badctxt(SB)
RET
// void gogo(Gobuf*)
// restore state from Gobuf; longjmp
-TEXT runtime·gogo(SB), NOSPLIT, $-8-8
+TEXT runtime·gogo(SB), NOSPLIT, $16-8
+ MOVD buf+0(FP), R5
+
+ // If ctxt is not nil, invoke deletion barrier before overwriting.
+ MOVD gobuf_ctxt(R5), R1
+ CMPBEQ R1, $0, nilctxt
+ MOVD $gobuf_ctxt(R5), R1
+ MOVD R1, 8(R15)
+ MOVD R0, 16(R15)
+ BL runtime·writebarrierptr_prewrite(SB)
MOVD buf+0(FP), R5
+
+nilctxt:
MOVD gobuf_g(R5), g // make sure g is not nil
BL runtime·save_g(SB)
@@ -175,7 +151,7 @@ TEXT runtime·mcall(SB), NOSPLIT, $-8-8
// Save caller state in g->sched
MOVD R15, (g_sched+gobuf_sp)(g)
MOVD LR, (g_sched+gobuf_pc)(g)
- MOVD R0, (g_sched+gobuf_lr)(g)
+ MOVD $0, (g_sched+gobuf_lr)(g)
MOVD g, (g_sched+gobuf_g)(g)
// Switch to m->g0 & its stack, call fn.
@@ -232,7 +208,7 @@ switch:
ADD $16, R6 // get past prologue
MOVD R6, (g_sched+gobuf_pc)(g)
MOVD R15, (g_sched+gobuf_sp)(g)
- MOVD R0, (g_sched+gobuf_lr)(g)
+ MOVD $0, (g_sched+gobuf_lr)(g)
MOVD g, (g_sched+gobuf_g)(g)
// switch to g0
@@ -279,22 +255,24 @@ TEXT runtime·morestack(SB),NOSPLIT|NOFRAME,$0-0
// Cannot grow scheduler stack (m->g0).
MOVD g_m(g), R7
MOVD m_g0(R7), R8
- CMPBNE g, R8, 2(PC)
+ CMPBNE g, R8, 3(PC)
+ BL runtime·badmorestackg0(SB)
BL runtime·abort(SB)
// Cannot grow signal stack (m->gsignal).
MOVD m_gsignal(R7), R8
CMP g, R8
- BNE 2(PC)
+ BNE 3(PC)
+ BL runtime·badmorestackgsignal(SB)
BL runtime·abort(SB)
// Called from f.
// Set g->sched to context in f.
- MOVD R12, (g_sched+gobuf_ctxt)(g)
MOVD R15, (g_sched+gobuf_sp)(g)
MOVD LR, R8
MOVD R8, (g_sched+gobuf_pc)(g)
MOVD R5, (g_sched+gobuf_lr)(g)
+ // newstack will fill gobuf.ctxt.
// Called from f.
// Set m->morebuf to f's caller.
@@ -306,6 +284,10 @@ TEXT runtime·morestack(SB),NOSPLIT|NOFRAME,$0-0
MOVD m_g0(R7), g
BL runtime·save_g(SB)
MOVD (g_sched+gobuf_sp)(g), R15
+ // Create a stack frame on g0 to call newstack.
+ MOVD $0, -16(R15) // Zero saved LR in frame
+ SUB $16, R15
+ MOVD R12, 8(R15) // ctxt argument
BL runtime·newstack(SB)
// Not reached, but make sure the return PC from the call to newstack
@@ -352,8 +334,6 @@ TEXT reflect·call(SB), NOSPLIT, $0-0
TEXT ·reflectcall(SB), NOSPLIT, $-8-32
MOVWZ argsize+24(FP), R3
- // NOTE(rsc): No call16, because CALLFN needs four words
- // of argument space to invoke callwritebarrier.
DISPATCH(runtime·call32, 32)
DISPATCH(runtime·call64, 64)
DISPATCH(runtime·call128, 128)
@@ -387,54 +367,49 @@ TEXT ·reflectcall(SB), NOSPLIT, $-8-32
TEXT NAME(SB), WRAPPER, $MAXSIZE-24; \
NO_LOCAL_POINTERS; \
/* copy arguments to stack */ \
- MOVD arg+16(FP), R3; \
- MOVWZ argsize+24(FP), R4; \
- MOVD R15, R5; \
- ADD $(8-1), R5; \
- SUB $1, R3; \
- ADD R5, R4; \
- CMP R5, R4; \
- BEQ 6(PC); \
- ADD $1, R3; \
- ADD $1, R5; \
- MOVBZ 0(R3), R6; \
- MOVBZ R6, 0(R5); \
- BR -6(PC); \
- /* call function */ \
+ MOVD arg+16(FP), R4; \
+ MOVWZ argsize+24(FP), R5; \
+ MOVD $stack-MAXSIZE(SP), R6; \
+loopArgs: /* copy 256 bytes at a time */ \
+ CMP R5, $256; \
+ BLT tailArgs; \
+ SUB $256, R5; \
+ MVC $256, 0(R4), 0(R6); \
+ MOVD $256(R4), R4; \
+ MOVD $256(R6), R6; \
+ BR loopArgs; \
+tailArgs: /* copy remaining bytes */ \
+ CMP R5, $0; \
+ BEQ callFunction; \
+ SUB $1, R5; \
+ EXRL $callfnMVC<>(SB), R5; \
+callFunction: \
MOVD f+8(FP), R12; \
MOVD (R12), R8; \
PCDATA $PCDATA_StackMapIndex, $0; \
BL (R8); \
/* copy return values back */ \
- MOVD arg+16(FP), R3; \
- MOVWZ n+24(FP), R4; \
- MOVWZ retoffset+28(FP), R6; \
- MOVD R15, R5; \
- ADD R6, R5; \
- ADD R6, R3; \
- SUB R6, R4; \
- ADD $(8-1), R5; \
- SUB $1, R3; \
- ADD R5, R4; \
-loop: \
- CMP R5, R4; \
- BEQ end; \
- ADD $1, R5; \
- ADD $1, R3; \
- MOVBZ 0(R5), R6; \
- MOVBZ R6, 0(R3); \
- BR loop; \
-end: \
- /* execute write barrier updates */ \
MOVD argtype+0(FP), R7; \
- MOVD arg+16(FP), R3; \
- MOVWZ n+24(FP), R4; \
- MOVWZ retoffset+28(FP), R6; \
- MOVD R7, 8(R15); \
- MOVD R3, 16(R15); \
- MOVD R4, 24(R15); \
- MOVD R6, 32(R15); \
- BL runtime·callwritebarrier(SB); \
+ MOVD arg+16(FP), R6; \
+ MOVWZ n+24(FP), R5; \
+ MOVD $stack-MAXSIZE(SP), R4; \
+ MOVWZ retoffset+28(FP), R1; \
+ ADD R1, R4; \
+ ADD R1, R6; \
+ SUB R1, R5; \
+ BL callRet<>(SB); \
+ RET
+
+// callRet copies return values back at the end of call*. This is a
+// separate function so it can allocate stack space for the arguments
+// to reflectcallmove. It does not follow the Go ABI; it expects its
+// arguments in registers.
+TEXT callRet<>(SB), NOSPLIT, $32-0
+ MOVD R7, 8(R15)
+ MOVD R6, 16(R15)
+ MOVD R4, 24(R15)
+ MOVD R5, 32(R15)
+ BL runtime·reflectcallmove(SB)
RET
CALLFN(·call32, 32)
@@ -464,6 +439,10 @@ CALLFN(·call268435456, 268435456)
CALLFN(·call536870912, 536870912)
CALLFN(·call1073741824, 1073741824)
+// Not a function: target for EXRL (execute relative long) instruction.
+TEXT callfnMVC<>(SB),NOSPLIT|NOFRAME,$0-0
+ MVC $1, 0(R4), 0(R6)
+
TEXT runtime·procyield(SB),NOSPLIT,$0-0
RET
@@ -482,13 +461,16 @@ TEXT runtime·jmpdefer(SB),NOSPLIT|NOFRAME,$0-16
MOVD 0(R12), R3
BR (R3)
-// Save state of caller into g->sched. Smashes R31.
+// Save state of caller into g->sched. Smashes R1.
TEXT gosave<>(SB),NOSPLIT|NOFRAME,$0
MOVD LR, (g_sched+gobuf_pc)(g)
MOVD R15, (g_sched+gobuf_sp)(g)
MOVD $0, (g_sched+gobuf_lr)(g)
MOVD $0, (g_sched+gobuf_ret)(g)
- MOVD $0, (g_sched+gobuf_ctxt)(g)
+ // Assert ctxt is zero. See func save.
+ MOVD (g_sched+gobuf_ctxt)(g), R1
+ CMPBEQ R1, $0, 2(PC)
+ BL runtime·badctxt(SB)
RET
// func asmcgocall(fn, arg unsafe.Pointer) int32
@@ -526,7 +508,7 @@ g0:
MOVD (g_stack+stack_hi)(R5), R5
SUB R2, R5
MOVD R5, 160(R15) // save depth in old g stack (can't just save SP, as stack might be copied during a callback)
- MOVD R0, 0(R15) // clear back chain pointer (TODO can we give it real back trace information?)
+ MOVD $0, 0(R15) // clear back chain pointer (TODO can we give it real back trace information?)
MOVD R4, R2 // arg in R2
BL R3 // can clobber: R0-R5, R14, F0-F3, F5, F7-F15
@@ -715,12 +697,6 @@ setbar:
BL runtime·setNextBarrierPC(SB)
RET
-TEXT runtime·getcallersp(SB),NOSPLIT,$0-16
- MOVD argp+0(FP), R3
- SUB $8, R3
- MOVD R3, ret+8(FP)
- RET
-
TEXT runtime·abort(SB),NOSPLIT|NOFRAME,$0-0
MOVW (R0), R0
UNDEF
@@ -765,10 +741,10 @@ TEXT runtime·aeshash64(SB),NOSPLIT|NOFRAME,$0-0
TEXT runtime·aeshashstr(SB),NOSPLIT|NOFRAME,$0-0
MOVW (R0), R15
-// memequal(p, q unsafe.Pointer, size uintptr) bool
+// memequal(a, b unsafe.Pointer, size uintptr) bool
TEXT runtime·memequal(SB),NOSPLIT|NOFRAME,$0-25
- MOVD p+0(FP), R3
- MOVD q+8(FP), R5
+ MOVD a+0(FP), R3
+ MOVD b+8(FP), R5
MOVD size+16(FP), R6
LA ret+24(FP), R7
BR runtime·memeqbody(SB)
@@ -787,9 +763,9 @@ TEXT runtime·memequal_varlen(SB),NOSPLIT|NOFRAME,$0-17
// See runtime_test.go:eqstring_generic for
// equivalent Go code.
TEXT runtime·eqstring(SB),NOSPLIT|NOFRAME,$0-33
- MOVD s1str+0(FP), R3
- MOVD s1len+8(FP), R6
- MOVD s2str+16(FP), R5
+ MOVD s1_base+0(FP), R3
+ MOVD s1_len+8(FP), R6
+ MOVD s2_base+16(FP), R5
LA ret+32(FP), R7
BR runtime·memeqbody(SB)
@@ -875,7 +851,7 @@ TEXT runtime·memeqbodyclc(SB),NOSPLIT|NOFRAME,$0-0
CLC $1, 0(R3), 0(R5)
RET
-TEXT runtime·fastrand1(SB), NOSPLIT, $0-4
+TEXT runtime·fastrand(SB), NOSPLIT, $0-4
MOVD g_m(g), R4
MOVWZ m_fastrand(R4), R3
ADD R3, R3
@@ -886,14 +862,14 @@ TEXT runtime·fastrand1(SB), NOSPLIT, $0-4
MOVW R3, ret+0(FP)
RET
-TEXT bytes·IndexByte(SB),NOSPLIT,$0-40
+TEXT bytes·IndexByte(SB),NOSPLIT|NOFRAME,$0-40
MOVD s+0(FP), R3 // s => R3
MOVD s_len+8(FP), R4 // s_len => R4
MOVBZ c+24(FP), R5 // c => R5
MOVD $ret+32(FP), R2 // &ret => R9
BR runtime·indexbytebody(SB)
-TEXT strings·IndexByte(SB),NOSPLIT,$0-32
+TEXT strings·IndexByte(SB),NOSPLIT|NOFRAME,$0-32
MOVD s+0(FP), R3 // s => R3
MOVD s_len+8(FP), R4 // s_len => R4
MOVBZ c+16(FP), R5 // c => R5
@@ -905,7 +881,7 @@ TEXT strings·IndexByte(SB),NOSPLIT,$0-32
// R4: s_len
// R5: c -- byte sought
// R2: &ret -- address to put index into
-TEXT runtime·indexbytebody(SB),NOSPLIT,$0
+TEXT runtime·indexbytebody(SB),NOSPLIT|NOFRAME,$0
CMPBEQ R4, $0, notfound
MOVD R3, R6 // store base for later
ADD R3, R4, R8 // the address after the end of the string
@@ -929,12 +905,10 @@ notfound:
RET
large:
- MOVB runtime·vectorfacility(SB), R1
- CMPBEQ R1, $-1, checkvector // vectorfacility = -1, vector not checked yet
-vectorchecked:
- CMPBEQ R1, $1, vectorimpl // vectorfacility = 1, vector supported
+ MOVBZ ·cpu+facilities_hasVX(SB), R1
+ CMPBNE R1, $0, vectorimpl
-srstimpl: // vectorfacility != 1, not support or enable vector
+srstimpl: // no vector facility
MOVBZ R5, R0 // c needs to be in R0, leave until last minute as currently R0 is expected to be 0
srstloop:
WORD $0xB25E0083 // srst %r8, %r3 (search the range [R3, R8))
@@ -952,12 +926,14 @@ notfoundr0:
vectorimpl:
//if the address is not 16byte aligned, use loop for the header
- AND $15, R3, R8
+ MOVD R3, R8
+ AND $15, R8
CMPBGT R8, $0, notaligned
aligned:
ADD R6, R4, R8
- AND $-16, R8, R7
+ MOVD R8, R7
+ AND $-16, R7
// replicate c across V17
VLVGB $0, R5, V19
VREPB $0, V19, V17
@@ -978,7 +954,8 @@ vectorloop:
RET
notaligned:
- AND $-16, R3, R8
+ MOVD R3, R8
+ AND $-16, R8
ADD $16, R8
notalignedloop:
CMPBEQ R3, R8, aligned
@@ -987,11 +964,6 @@ notalignedloop:
CMPBNE R7, R5, notalignedloop
BR found
-checkvector:
- CALL runtime·checkvectorfacility(SB)
- MOVB runtime·vectorfacility(SB), R1
- BR vectorchecked
-
TEXT runtime·return0(SB), NOSPLIT, $0
MOVW $0, R3
RET
@@ -1036,7 +1008,7 @@ TEXT runtime·prefetcht2(SB),NOSPLIT,$0-8
TEXT runtime·prefetchnta(SB),NOSPLIT,$0-8
RET
-TEXT runtime·sigreturn(SB),NOSPLIT,$0-8
+TEXT runtime·sigreturn(SB),NOSPLIT,$0-0
RET
TEXT ·publicationBarrier(SB),NOSPLIT|NOFRAME,$0-0
@@ -1104,18 +1076,238 @@ TEXT runtime·cmpbodyclc(SB),NOSPLIT|NOFRAME,$0-0
CLC $1, 0(R3), 0(R5)
RET
+// func supportsVX() bool
+TEXT strings·supportsVX(SB),NOSPLIT,$0-1
+ MOVBZ runtime·cpu+facilities_hasVX(SB), R0
+ MOVB R0, ret+0(FP)
+ RET
+
+// func supportsVX() bool
+TEXT bytes·supportsVX(SB),NOSPLIT,$0-1
+ MOVBZ runtime·cpu+facilities_hasVX(SB), R0
+ MOVB R0, ret+0(FP)
+ RET
+
+// func indexShortStr(s, sep string) int
+// Caller must confirm availability of vx facility before calling.
+TEXT strings·indexShortStr(SB),NOSPLIT|NOFRAME,$0-40
+ LMG s+0(FP), R1, R2 // R1=&s[0], R2=len(s)
+ LMG sep+16(FP), R3, R4 // R3=&sep[0], R4=len(sep)
+ MOVD $ret+32(FP), R5
+ BR runtime·indexShortStr(SB)
+
+// func indexShortStr(s, sep []byte) int
+// Caller must confirm availability of vx facility before calling.
+TEXT bytes·indexShortStr(SB),NOSPLIT|NOFRAME,$0-56
+ LMG s+0(FP), R1, R2 // R1=&s[0], R2=len(s)
+ LMG sep+24(FP), R3, R4 // R3=&sep[0], R4=len(sep)
+ MOVD $ret+48(FP), R5
+ BR runtime·indexShortStr(SB)
+
+// s: string we are searching
+// sep: string to search for
+// R1=&s[0], R2=len(s)
+// R3=&sep[0], R4=len(sep)
+// R5=&ret (int)
+// Caller must confirm availability of vx facility before calling.
+TEXT runtime·indexShortStr(SB),NOSPLIT|NOFRAME,$0
+ CMPBGT R4, R2, notfound
+ ADD R1, R2
+ SUB R4, R2 // R2=&s[len(s)-len(sep)] (last valid index)
+ CMPBEQ R4, $0, notfound
+ SUB $1, R4 // R4=len(sep)-1 for use as VLL index
+ VLL R4, (R3), V0 // contains first 16 bytes of sep
+ MOVD R1, R7
+index2plus:
+ CMPBNE R4, $1, index3plus
+ MOVD $15(R7), R9
+ CMPBGE R9, R2, index2to16
+ VGBM $0xaaaa, V31 // 0xff00ff00ff00ff00...
+ VONE V16
+ VREPH $0, V0, V1
+ CMPBGE R9, R2, index2to16
+index2loop:
+ VL 0(R7), V2 // 16 bytes, even indices
+ VL 1(R7), V4 // 16 bytes, odd indices
+ VCEQH V1, V2, V5 // compare even indices
+ VCEQH V1, V4, V6 // compare odd indices
+ VSEL V5, V6, V31, V7 // merge even and odd indices
+ VFEEBS V16, V7, V17 // find leftmost index, set condition to 1 if found
+ BLT foundV17
+ MOVD $16(R7), R7 // R7+=16
+ ADD $15, R7, R9
+ CMPBLE R9, R2, index2loop // continue if (R7+15) <= R2 (last index to search)
+ CMPBLE R7, R2, index2to16
+ BR notfound
+
+index3plus:
+ CMPBNE R4, $2, index4plus
+ ADD $15, R7, R9
+ CMPBGE R9, R2, index2to16
+ MOVD $1, R0
+ VGBM $0xaaaa, V31 // 0xff00ff00ff00ff00...
+ VONE V16
+ VREPH $0, V0, V1
+ VREPB $2, V0, V8
+index3loop:
+ VL (R7), V2 // load 16-bytes into V2
+ VLL R0, 16(R7), V3 // load 2-bytes into V3
+ VSLDB $1, V2, V3, V4 // V4=(V2:V3)<<1
+ VSLDB $2, V2, V3, V9 // V9=(V2:V3)<<2
+ VCEQH V1, V2, V5 // compare 2-byte even indices
+ VCEQH V1, V4, V6 // compare 2-byte odd indices
+ VCEQB V8, V9, V10 // compare last bytes
+ VSEL V5, V6, V31, V7 // merge even and odd indices
+ VN V7, V10, V7 // AND indices with last byte
+ VFEEBS V16, V7, V17 // find leftmost index, set condition to 1 if found
+ BLT foundV17
+ MOVD $16(R7), R7 // R7+=16
+ ADD $15, R7, R9
+ CMPBLE R9, R2, index3loop // continue if (R7+15) <= R2 (last index to search)
+ CMPBLE R7, R2, index2to16
+ BR notfound
+
+index4plus:
+ CMPBNE R4, $3, index5plus
+ ADD $15, R7, R9
+ CMPBGE R9, R2, index2to16
+ MOVD $2, R0
+ VGBM $0x8888, V29 // 0xff000000ff000000...
+ VGBM $0x2222, V30 // 0x0000ff000000ff00...
+ VGBM $0xcccc, V31 // 0xffff0000ffff0000...
+ VONE V16
+ VREPF $0, V0, V1
+index4loop:
+ VL (R7), V2 // load 16-bytes into V2
+ VLL R0, 16(R7), V3 // load 3-bytes into V3
+ VSLDB $1, V2, V3, V4 // V4=(V2:V3)<<1
+ VSLDB $2, V2, V3, V9 // V9=(V2:V3)<<1
+ VSLDB $3, V2, V3, V10 // V10=(V2:V3)<<1
+ VCEQF V1, V2, V5 // compare index 0, 4, ...
+ VCEQF V1, V4, V6 // compare index 1, 5, ...
+ VCEQF V1, V9, V11 // compare index 2, 6, ...
+ VCEQF V1, V10, V12 // compare index 3, 7, ...
+ VSEL V5, V6, V29, V13 // merge index 0, 1, 4, 5, ...
+ VSEL V11, V12, V30, V14 // merge index 2, 3, 6, 7, ...
+ VSEL V13, V14, V31, V7 // final merge
+ VFEEBS V16, V7, V17 // find leftmost index, set condition to 1 if found
+ BLT foundV17
+ MOVD $16(R7), R7 // R7+=16
+ ADD $15, R7, R9
+ CMPBLE R9, R2, index4loop // continue if (R7+15) <= R2 (last index to search)
+ CMPBLE R7, R2, index2to16
+ BR notfound
+
+index5plus:
+ CMPBGT R4, $15, index17plus
+index2to16:
+ CMPBGT R7, R2, notfound
+ MOVD $1(R7), R8
+ CMPBGT R8, R2, index2to16tail
+index2to16loop:
+ // unrolled 2x
+ VLL R4, (R7), V1
+ VLL R4, 1(R7), V2
+ VCEQGS V0, V1, V3
+ BEQ found
+ MOVD $1(R7), R7
+ VCEQGS V0, V2, V4
+ BEQ found
+ MOVD $1(R7), R7
+ CMPBLT R7, R2, index2to16loop
+ CMPBGT R7, R2, notfound
+index2to16tail:
+ VLL R4, (R7), V1
+ VCEQGS V0, V1, V2
+ BEQ found
+ BR notfound
+
+index17plus:
+ CMPBGT R4, $31, index33plus
+ SUB $16, R4, R0
+ VLL R0, 16(R3), V1
+ VONE V7
+index17to32loop:
+ VL (R7), V2
+ VLL R0, 16(R7), V3
+ VCEQG V0, V2, V4
+ VCEQG V1, V3, V5
+ VN V4, V5, V6
+ VCEQGS V6, V7, V8
+ BEQ found
+ MOVD $1(R7), R7
+ CMPBLE R7, R2, index17to32loop
+ BR notfound
+
+index33plus:
+ CMPBGT R4, $47, index49plus
+ SUB $32, R4, R0
+ VL 16(R3), V1
+ VLL R0, 32(R3), V2
+ VONE V11
+index33to48loop:
+ VL (R7), V3
+ VL 16(R7), V4
+ VLL R0, 32(R7), V5
+ VCEQG V0, V3, V6
+ VCEQG V1, V4, V7
+ VCEQG V2, V5, V8
+ VN V6, V7, V9
+ VN V8, V9, V10
+ VCEQGS V10, V11, V12
+ BEQ found
+ MOVD $1(R7), R7
+ CMPBLE R7, R2, index33to48loop
+ BR notfound
+
+index49plus:
+ CMPBGT R4, $63, index65plus
+ SUB $48, R4, R0
+ VL 16(R3), V1
+ VL 32(R3), V2
+ VLL R0, 48(R3), V3
+ VONE V15
+index49to64loop:
+ VL (R7), V4
+ VL 16(R7), V5
+ VL 32(R7), V6
+ VLL R0, 48(R7), V7
+ VCEQG V0, V4, V8
+ VCEQG V1, V5, V9
+ VCEQG V2, V6, V10
+ VCEQG V3, V7, V11
+ VN V8, V9, V12
+ VN V10, V11, V13
+ VN V12, V13, V14
+ VCEQGS V14, V15, V16
+ BEQ found
+ MOVD $1(R7), R7
+ CMPBLE R7, R2, index49to64loop
+notfound:
+ MOVD $-1, (R5)
+ RET
+
+index65plus:
+ // not implemented
+ MOVD $0, (R0)
+ RET
+
+foundV17: // index is in doubleword V17[0]
+ VLGVG $0, V17, R8
+ ADD R8, R7
+found:
+ SUB R1, R7
+ MOVD R7, (R5)
+ RET
+
// This is called from .init_array and follows the platform, not Go, ABI.
// We are overly conservative. We could only save the registers we use.
// However, since this function is only called once per loaded module
// performance is unimportant.
TEXT runtime·addmoduledata(SB),NOSPLIT|NOFRAME,$0-0
- // Save R6-R15, F0, F2, F4 and F6 in the
- // register save area of the calling function
+ // Save R6-R15 in the register save area of the calling function.
+ // Don't bother saving F8-F15 as we aren't doing any calls.
STMG R6, R15, 48(R15)
- FMOVD F0, 128(R15)
- FMOVD F2, 136(R15)
- FMOVD F4, 144(R15)
- FMOVD F6, 152(R15)
// append the argument (passed in R2, as per the ELF ABI) to the
// moduledata linked list.
@@ -1123,12 +1315,8 @@ TEXT runtime·addmoduledata(SB),NOSPLIT|NOFRAME,$0-0
MOVD R2, moduledata_next(R1)
MOVD R2, runtime·lastmoduledatap(SB)
- // Restore R6-R15, F0, F2, F4 and F6
+ // Restore R6-R15.
LMG 48(R15), R6, R15
- FMOVD F0, 128(R15)
- FMOVD F2, 136(R15)
- FMOVD F4, 144(R15)
- FMOVD F6, 152(R15)
RET
TEXT ·checkASM(SB),NOSPLIT,$0-1
diff --git a/src/runtime/atomic_mipsx.s b/src/runtime/atomic_mipsx.s
new file mode 100644
index 0000000..ed078a2
--- /dev/null
+++ b/src/runtime/atomic_mipsx.s
@@ -0,0 +1,11 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build mips mipsle
+
+#include "textflag.h"
+
+TEXT ·publicationBarrier(SB),NOSPLIT,$0
+ SYNC
+ RET
diff --git a/src/runtime/atomic_pointer.go b/src/runtime/atomic_pointer.go
index 4fe3340..292b351 100644
--- a/src/runtime/atomic_pointer.go
+++ b/src/runtime/atomic_pointer.go
@@ -20,17 +20,17 @@ import (
//
//go:nosplit
func atomicstorep(ptr unsafe.Pointer, new unsafe.Pointer) {
+ writebarrierptr_prewrite((*uintptr)(ptr), uintptr(new))
atomic.StorepNoWB(noescape(ptr), new)
- writebarrierptr_nostore((*uintptr)(ptr), uintptr(new))
}
//go:nosplit
func casp(ptr *unsafe.Pointer, old, new unsafe.Pointer) bool {
- if !atomic.Casp1((*unsafe.Pointer)(noescape(unsafe.Pointer(ptr))), noescape(old), new) {
- return false
- }
- writebarrierptr_nostore((*uintptr)(unsafe.Pointer(ptr)), uintptr(new))
- return true
+ // The write barrier is only necessary if the CAS succeeds,
+ // but since it needs to happen before the write becomes
+ // public, we have to do it conservatively all the time.
+ writebarrierptr_prewrite((*uintptr)(unsafe.Pointer(ptr)), uintptr(new))
+ return atomic.Casp1((*unsafe.Pointer)(noescape(unsafe.Pointer(ptr))), noescape(old), new)
}
// Like above, but implement in terms of sync/atomic's uintptr operations.
@@ -43,8 +43,8 @@ func sync_atomic_StoreUintptr(ptr *uintptr, new uintptr)
//go:linkname sync_atomic_StorePointer sync/atomic.StorePointer
//go:nosplit
func sync_atomic_StorePointer(ptr *unsafe.Pointer, new unsafe.Pointer) {
+ writebarrierptr_prewrite((*uintptr)(unsafe.Pointer(ptr)), uintptr(new))
sync_atomic_StoreUintptr((*uintptr)(unsafe.Pointer(ptr)), uintptr(new))
- writebarrierptr_nostore((*uintptr)(unsafe.Pointer(ptr)), uintptr(new))
}
//go:linkname sync_atomic_SwapUintptr sync/atomic.SwapUintptr
@@ -53,8 +53,8 @@ func sync_atomic_SwapUintptr(ptr *uintptr, new uintptr) uintptr
//go:linkname sync_atomic_SwapPointer sync/atomic.SwapPointer
//go:nosplit
func sync_atomic_SwapPointer(ptr *unsafe.Pointer, new unsafe.Pointer) unsafe.Pointer {
+ writebarrierptr_prewrite((*uintptr)(unsafe.Pointer(ptr)), uintptr(new))
old := unsafe.Pointer(sync_atomic_SwapUintptr((*uintptr)(noescape(unsafe.Pointer(ptr))), uintptr(new)))
- writebarrierptr_nostore((*uintptr)(unsafe.Pointer(ptr)), uintptr(new))
return old
}
@@ -64,9 +64,6 @@ func sync_atomic_CompareAndSwapUintptr(ptr *uintptr, old, new uintptr) bool
//go:linkname sync_atomic_CompareAndSwapPointer sync/atomic.CompareAndSwapPointer
//go:nosplit
func sync_atomic_CompareAndSwapPointer(ptr *unsafe.Pointer, old, new unsafe.Pointer) bool {
- if !sync_atomic_CompareAndSwapUintptr((*uintptr)(noescape(unsafe.Pointer(ptr))), uintptr(old), uintptr(new)) {
- return false
- }
- writebarrierptr_nostore((*uintptr)(unsafe.Pointer(ptr)), uintptr(new))
- return true
+ writebarrierptr_prewrite((*uintptr)(unsafe.Pointer(ptr)), uintptr(new))
+ return sync_atomic_CompareAndSwapUintptr((*uintptr)(noescape(unsafe.Pointer(ptr))), uintptr(old), uintptr(new))
}
diff --git a/src/runtime/cgo/asm_arm64.s b/src/runtime/cgo/asm_arm64.s
index e55a70f..925e930 100644
--- a/src/runtime/cgo/asm_arm64.s
+++ b/src/runtime/cgo/asm_arm64.s
@@ -43,7 +43,6 @@ TEXT crosscall2(SB),NOSPLIT,$-8
MOVD R0, R19
// Initialize Go ABI environment
- BL runtime·reginit(SB)
BL runtime·load_g(SB)
BL (R19)
diff --git a/src/runtime/cgo/asm_mips64x.s b/src/runtime/cgo/asm_mips64x.s
index 19e9014..aae2767 100644
--- a/src/runtime/cgo/asm_mips64x.s
+++ b/src/runtime/cgo/asm_mips64x.s
@@ -1,4 +1,4 @@
-// Copyright 2016 The Go Authors. All rights reserved.
+// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
@@ -18,9 +18,9 @@ TEXT crosscall2(SB),NOSPLIT,$-8
* first arg.
*/
ADDV $(-8*23), R29
- MOVV R5, (8*1)(R29)
- MOVV R6, (8*2)(R29)
- MOVV R7, (8*3)(R29)
+ MOVV R5, (8*1)(R29) // void*
+ MOVW R6, (8*2)(R29) // int32
+ MOVV R7, (8*3)(R29) // uintptr
MOVV R16, (8*4)(R29)
MOVV R17, (8*5)(R29)
MOVV R18, (8*6)(R29)
@@ -46,13 +46,9 @@ TEXT crosscall2(SB),NOSPLIT,$-8
BGEZAL R0, 1(PC)
SRLV $32, R31, RSB
SLLV $32, RSB
- JAL runtime·reginit(SB)
JAL runtime·load_g(SB)
JAL (R4)
- MOVV (8*1)(R29), R5
- MOVV (8*2)(R29), R6
- MOVV (8*3)(R29), R7
MOVV (8*4)(R29), R16
MOVV (8*5)(R29), R17
MOVV (8*6)(R29), R18
diff --git a/src/runtime/cgo/asm_s390x.s b/src/runtime/cgo/asm_s390x.s
index ae688b6..7eab8f6 100644
--- a/src/runtime/cgo/asm_s390x.s
+++ b/src/runtime/cgo/asm_s390x.s
@@ -8,36 +8,46 @@
// func crosscall2(fn func(a unsafe.Pointer, n int32, ctxt uintptr), a unsafe.Pointer, n int32, ctxt uintptr)
// Saves C callee-saved registers and calls fn with three arguments.
TEXT crosscall2(SB),NOSPLIT|NOFRAME,$0
- // Start with standard C stack frame layout and linkage
+ // Start with standard C stack frame layout and linkage.
- // Save R6-R15, F0, F2, F4 and F6 in the
- // register save area of the calling function
+ // Save R6-R15 in the register save area of the calling function.
STMG R6, R15, 48(R15)
- FMOVD F0, 128(R15)
- FMOVD F2, 136(R15)
- FMOVD F4, 144(R15)
- FMOVD F6, 152(R15)
- // Initialize Go ABI environment
- XOR R0, R0
- BL runtime·load_g(SB)
+ // Allocate 96 bytes on the stack.
+ MOVD $-96(R15), R15
+
+ // Save F8-F15 in our stack frame.
+ FMOVD F8, 32(R15)
+ FMOVD F9, 40(R15)
+ FMOVD F10, 48(R15)
+ FMOVD F11, 56(R15)
+ FMOVD F12, 64(R15)
+ FMOVD F13, 72(R15)
+ FMOVD F14, 80(R15)
+ FMOVD F15, 88(R15)
- // Allocate 32 bytes on the stack
- SUB $32, R15
+ // Initialize Go ABI environment.
+ BL runtime·load_g(SB)
MOVD R3, 8(R15) // arg1
MOVW R4, 16(R15) // arg2
MOVD R5, 24(R15) // arg3
BL (R2) // fn(arg1, arg2, arg3)
- ADD $32, R15
+ FMOVD 32(R15), F8
+ FMOVD 40(R15), F9
+ FMOVD 48(R15), F10
+ FMOVD 56(R15), F11
+ FMOVD 64(R15), F12
+ FMOVD 72(R15), F13
+ FMOVD 80(R15), F14
+ FMOVD 88(R15), F15
+
+ // De-allocate stack frame.
+ MOVD $96(R15), R15
- // Restore R6-R15, F0, F2, F4 and F6
+ // Restore R6-R15.
LMG 48(R15), R6, R15
- FMOVD F0, 128(R15)
- FMOVD F2, 136(R15)
- FMOVD F4, 144(R15)
- FMOVD F6, 152(R15)
RET
diff --git a/src/runtime/cgo/cgo.go b/src/runtime/cgo/cgo.go
index ce0e6a3..241a821 100644
--- a/src/runtime/cgo/cgo.go
+++ b/src/runtime/cgo/cgo.go
@@ -20,9 +20,6 @@ package cgo
#cgo !android,linux LDFLAGS: -lpthread
#cgo netbsd LDFLAGS: -lpthread
#cgo openbsd LDFLAGS: -lpthread
-// we must explicitly link msvcrt, because runtime needs ntdll, and ntdll
-// exports some incompatible libc functions. See golang.org/issue/12030.
-#cgo windows LDFLAGS: -lmsvcrt -lm -mthreads
#cgo CFLAGS: -Wall -Werror
diff --git a/src/runtime/cgo/gcc_context.c b/src/runtime/cgo/gcc_context.c
index 1e6cf7e..b46b604 100644
--- a/src/runtime/cgo/gcc_context.c
+++ b/src/runtime/cgo/gcc_context.c
@@ -1,4 +1,4 @@
-// Copyright 2016 The Go Authors. All rights reserved.
+// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
diff --git a/src/runtime/cgo/gcc_dragonfly_amd64.c b/src/runtime/cgo/gcc_dragonfly_amd64.c
index b534dcc..e532ad6 100644
--- a/src/runtime/cgo/gcc_dragonfly_amd64.c
+++ b/src/runtime/cgo/gcc_dragonfly_amd64.c
@@ -56,7 +56,6 @@ static void*
threadentry(void *v)
{
ThreadStart ts;
- stack_t ss;
ts = *(ThreadStart*)v;
free(v);
@@ -66,17 +65,6 @@ threadentry(void *v)
*/
setg_gcc((void*)ts.g);
- // On DragonFly, a new thread inherits the signal stack of the
- // creating thread. That confuses minit, so we remove that
- // signal stack here before calling the regular mstart. It's
- // a bit baroque to remove a signal stack here only to add one
- // in minit, but it's a simple change that keeps DragonFly
- // working like other OS's. At this point all signals are
- // blocked, so there is no race.
- memset(&ss, 0, sizeof ss);
- ss.ss_flags = SS_DISABLE;
- sigaltstack(&ss, nil);
-
crosscall_amd64(ts.fn);
return nil;
}
diff --git a/src/runtime/cgo/gcc_libinit_windows.c b/src/runtime/cgo/gcc_libinit_windows.c
index 0824e20..b6f51b3 100644
--- a/src/runtime/cgo/gcc_libinit_windows.c
+++ b/src/runtime/cgo/gcc_libinit_windows.c
@@ -12,8 +12,8 @@
#include "libcgo.h"
-static volatile long runtime_init_once_gate = 0;
-static volatile long runtime_init_once_done = 0;
+static volatile LONG runtime_init_once_gate = 0;
+static volatile LONG runtime_init_once_done = 0;
static CRITICAL_SECTION runtime_init_cs;
diff --git a/src/runtime/cgo/gcc_linux_mips64x.c b/src/runtime/cgo/gcc_linux_mips64x.c
index 5bf5197..8a95629 100644
--- a/src/runtime/cgo/gcc_linux_mips64x.c
+++ b/src/runtime/cgo/gcc_linux_mips64x.c
@@ -1,4 +1,4 @@
-// Copyright 2016 The Go Authors. All rights reserved.
+// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
diff --git a/src/runtime/cgo/gcc_mips64x.S b/src/runtime/cgo/gcc_mips64x.S
index adeb7ae..a7ef006 100644
--- a/src/runtime/cgo/gcc_mips64x.S
+++ b/src/runtime/cgo/gcc_mips64x.S
@@ -1,4 +1,4 @@
-// Copyright 2016 The Go Authors. All rights reserved.
+// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
@@ -35,8 +35,6 @@ crosscall1:
sdc1 $f30, 136($29)
sdc1 $f31, 144($29)
- dla $23,_cgo_reginit
-
// prepare SB register = pc & 0xffffffff00000000
bal 1f
1:
@@ -44,7 +42,6 @@ crosscall1:
dsll $28, $28, 32
move $20, $4 // save R4
- jalr $23 // call _cgo_reginit, set up Go ABI constant registers
move $1, $6
jalr $5 // call setg_gcc (clobbers R4)
jalr $20 // call fn
diff --git a/src/runtime/cgo/gcc_s390x.S b/src/runtime/cgo/gcc_s390x.S
index 022f82d..614de4b 100644
--- a/src/runtime/cgo/gcc_s390x.S
+++ b/src/runtime/cgo/gcc_s390x.S
@@ -1,4 +1,4 @@
-// Copyright 2016 The Go Authors. All rights reserved.
+// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
@@ -6,38 +6,48 @@
* void crosscall_s390x(void (*fn)(void), void *g)
*
* Calling into the go tool chain, where all registers are caller save.
- * Called from standard s390x C ABI, where r6-r13, r15, and f0, f2, f4 and f6 are
+ * Called from standard s390x C ABI, where r6-r13, r15, and f8-f15 are
* callee-save, so they must be saved explicitly.
*/
.globl crosscall_s390x
crosscall_s390x:
- /*
- * save r6-r15, f0, f2, f4 and f6 in the
- * register save area of the calling function
- */
- stmg %r6, %r15, 48(%r15)
- stdy %f0, 128(%r15)
- stdy %f2, 136(%r15)
- stdy %f4, 144(%r15)
- stdy %f6, 152(%r15)
-
- /* set r0 to 0 */
- xgr %r0, %r0
+ /* save r6-r15 in the register save area of the calling function */
+ stmg %r6, %r15, 48(%r15)
+
+ /* allocate 64 bytes of stack space to save f8-f15 */
+ lay %r15, -64(%r15)
+
+ /* save callee-saved floating point registers */
+ std %f8, 0(%r15)
+ std %f9, 8(%r15)
+ std %f10, 16(%r15)
+ std %f11, 24(%r15)
+ std %f12, 32(%r15)
+ std %f13, 40(%r15)
+ std %f14, 48(%r15)
+ std %f15, 56(%r15)
/* restore g pointer */
- lgr %r13, %r3
+ lgr %r13, %r3
- /* grow stack 8 bytes and call fn */
- agfi %r15, -8
+ /* call fn */
basr %r14, %r2
- agfi %r15, 8
-
- /* restore registers */
- lmg %r6, %r15, 48(%r15)
- ldy %f0, 128(%r15)
- ldy %f2, 136(%r15)
- ldy %f4, 144(%r15)
- ldy %f6, 152(%r15)
+
+ /* restore floating point registers */
+ ld %f8, 0(%r15)
+ ld %f9, 8(%r15)
+ ld %f10, 16(%r15)
+ ld %f11, 24(%r15)
+ ld %f12, 32(%r15)
+ ld %f13, 40(%r15)
+ ld %f14, 48(%r15)
+ ld %f15, 56(%r15)
+
+ /* de-allocate stack frame */
+ la %r15, 64(%r15)
+
+ /* restore general purpose registers */
+ lmg %r6, %r15, 48(%r15)
br %r14 /* restored by lmg */
diff --git a/src/runtime/cgo/gcc_setenv.c b/src/runtime/cgo/gcc_setenv.c
index 8708d40..ed5d203 100644
--- a/src/runtime/cgo/gcc_setenv.c
+++ b/src/runtime/cgo/gcc_setenv.c
@@ -13,12 +13,16 @@
void
x_cgo_setenv(char **arg)
{
+ _cgo_tsan_acquire();
setenv(arg[0], arg[1], 1);
+ _cgo_tsan_release();
}
/* Stub for calling unsetenv */
void
x_cgo_unsetenv(char *arg)
{
+ _cgo_tsan_acquire();
unsetenv(arg);
+ _cgo_tsan_release();
}
diff --git a/src/runtime/cgo/gcc_sigaction.c b/src/runtime/cgo/gcc_sigaction.c
new file mode 100644
index 0000000..5aca271
--- /dev/null
+++ b/src/runtime/cgo/gcc_sigaction.c
@@ -0,0 +1,76 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build linux,amd64
+
+#include <errno.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+#include <signal.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.
+typedef struct {
+ uintptr_t handler;
+ uint64_t flags;
+ uintptr_t restorer;
+ uint64_t mask;
+} go_sigaction_t;
+
+// SA_RESTORER is part of the kernel interface.
+// This is GNU/Linux i386/amd64 specific.
+#ifndef SA_RESTORER
+#define SA_RESTORER 0x4000000
+#endif
+
+int32_t
+x_cgo_sigaction(intptr_t signum, const go_sigaction_t *goact, go_sigaction_t *oldgoact) {
+ int32_t ret;
+ struct sigaction act;
+ struct sigaction oldact;
+ int i;
+
+ memset(&act, 0, sizeof act);
+ memset(&oldact, 0, sizeof oldact);
+
+ if (goact) {
+ if (goact->flags & SA_SIGINFO) {
+ act.sa_sigaction = (void(*)(int, siginfo_t*, void*))(goact->handler);
+ } else {
+ act.sa_handler = (void(*)(int))(goact->handler);
+ }
+ sigemptyset(&act.sa_mask);
+ for (i = 0; i < 8 * sizeof(goact->mask); i++) {
+ if (goact->mask & ((uint64_t)(1)<<i)) {
+ sigaddset(&act.sa_mask, i+1);
+ }
+ }
+ act.sa_flags = goact->flags & ~SA_RESTORER;
+ }
+
+ ret = sigaction(signum, goact ? &act : NULL, oldgoact ? &oldact : NULL);
+ if (ret == -1) {
+ /* This is what the Go code expects on failure. */
+ return errno;
+ }
+
+ if (oldgoact) {
+ if (oldact.sa_flags & SA_SIGINFO) {
+ oldgoact->handler = (uintptr_t)(oldact.sa_sigaction);
+ } else {
+ oldgoact->handler = (uintptr_t)(oldact.sa_handler);
+ }
+ oldgoact->mask = 0;
+ for (i = 0; i < 8 * sizeof(oldgoact->mask); i++) {
+ if (sigismember(&act.sa_mask, i+1) == 1) {
+ oldgoact->mask |= (uint64_t)(1)<<i;
+ }
+ }
+ oldgoact->flags = act.sa_flags;
+ }
+
+ return ret;
+}
diff --git a/src/runtime/cgo/sigaction.go b/src/runtime/cgo/sigaction.go
new file mode 100644
index 0000000..30d3f14
--- /dev/null
+++ b/src/runtime/cgo/sigaction.go
@@ -0,0 +1,22 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build linux,amd64
+
+package cgo
+
+// Import "unsafe" because we use go:linkname.
+import _ "unsafe"
+
+// When using cgo, call the C library for sigaction, so that we call into
+// any sanitizer interceptors. This supports using the memory
+// sanitizer with Go programs. The memory sanitizer only applies to
+// C/C++ code; this permits that code to see the Go runtime's existing signal
+// handlers when registering new signal handlers for the process.
+
+//go:cgo_import_static x_cgo_sigaction
+//go:linkname x_cgo_sigaction x_cgo_sigaction
+//go:linkname _cgo_sigaction _cgo_sigaction
+var x_cgo_sigaction byte
+var _cgo_sigaction = &x_cgo_sigaction
diff --git a/src/runtime/cgo_mips64x.go b/src/runtime/cgo_mips64x.go
deleted file mode 100644
index f718e92..0000000
--- a/src/runtime/cgo_mips64x.go
+++ /dev/null
@@ -1,12 +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 mips64 mips64le
-
-package runtime
-
-// crosscall1 calls into the runtime to set up the registers the
-// Go runtime expects and so the symbol it calls needs to be exported
-// for external linking to work.
-//go:cgo_export_static _cgo_reginit
diff --git a/src/runtime/cgo_mmap.go b/src/runtime/cgo_mmap.go
index a23cc79..5a2a1a2 100644
--- a/src/runtime/cgo_mmap.go
+++ b/src/runtime/cgo_mmap.go
@@ -35,7 +35,6 @@ func mmap(addr unsafe.Pointer, n uintptr, prot, flags, fd int32, off uint32) uns
// sysMmap calls the mmap system call. It is implemented in assembly.
func sysMmap(addr unsafe.Pointer, n uintptr, prot, flags, fd int32, off uint32) unsafe.Pointer
-// cgoMmap calls the mmap function in the runtime/cgo package on the
// callCgoMmap calls the mmap function in the runtime/cgo package
// using the GCC calling convention. It is implemented in assembly.
func callCgoMmap(addr unsafe.Pointer, n uintptr, prot, flags, fd int32, off uint32) uintptr
diff --git a/src/runtime/cgo_sigaction.go b/src/runtime/cgo_sigaction.go
new file mode 100644
index 0000000..4da2f40
--- /dev/null
+++ b/src/runtime/cgo_sigaction.go
@@ -0,0 +1,89 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Support for memory sanitizer. See runtime/cgo/sigaction.go.
+
+// +build linux,amd64
+
+package runtime
+
+import "unsafe"
+
+// _cgo_sigaction 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_sigaction _cgo_sigaction
+var _cgo_sigaction unsafe.Pointer
+
+//go:nosplit
+//go:nowritebarrierrec
+func rt_sigaction(sig uintptr, new, old *sigactiont, size uintptr) int32 {
+ // The runtime package is explicitly blacklisted from sanitizer
+ // instrumentation in racewalk.go, but we might be calling into instrumented C
+ // functions here — so we need the pointer parameters to be properly marked.
+ //
+ // Mark the input as having been written before the call and the output as
+ // read after.
+ if msanenabled && new != nil {
+ msanwrite(unsafe.Pointer(new), unsafe.Sizeof(*new))
+ }
+
+ var ret int32
+
+ if _cgo_sigaction == nil {
+ ret = sysSigaction(sig, new, old, size)
+ } else {
+ // We need to call _cgo_sigaction, which means we need a big enough stack
+ // for C. To complicate matters, we may be in libpreinit (before the
+ // runtime has been initialized) or in an asynchronous signal handler (with
+ // the current thread in transition between goroutines, or with the g0
+ // system stack already in use).
+
+ g := getg()
+ sp := uintptr(unsafe.Pointer(&sig))
+ switch {
+ case g == nil:
+ // No g: we're on a C stack or a signal stack.
+ ret = callCgoSigaction(sig, new, old)
+ case sp < g.stack.lo || sp >= g.stack.hi:
+ // We're no longer on g's stack, so we must be handling a signal. It's
+ // possible that we interrupted the thread during a transition between g
+ // and g0, so we should stay on the current stack to avoid corrupting g0.
+ ret = callCgoSigaction(sig, new, old)
+ default:
+ // We're running on g's stack, so either we're not in a signal handler or
+ // the signal handler has set the correct g. If we're on gsignal or g0,
+ // systemstack will make the call directly; otherwise, it will switch to
+ // g0 to ensure we have enough room to call a libc function.
+ //
+ // The function literal that we pass to systemstack is not nosplit, but
+ // that's ok: we'll be running on a fresh, clean system stack so the stack
+ // check will always succeed anyway.
+ systemstack(func() {
+ ret = callCgoSigaction(sig, new, old)
+ })
+ }
+
+ const EINVAL = 22
+ if ret == EINVAL {
+ // libc reserves certain signals — normally 32-33 — for pthreads, and
+ // returns EINVAL for sigaction calls on those signals. If we get EINVAL,
+ // fall back to making the syscall directly.
+ ret = sysSigaction(sig, new, old, size)
+ }
+ }
+
+ if msanenabled && old != nil && ret == 0 {
+ msanread(unsafe.Pointer(old), unsafe.Sizeof(*old))
+ }
+ return ret
+}
+
+// sysSigaction calls the rt_sigaction system call. It is implemented in assembly.
+//go:noescape
+func sysSigaction(sig uintptr, new, old *sigactiont, size uintptr) int32
+
+// callCgoSigaction calls the sigaction function in the runtime/cgo package
+// using the GCC calling convention. It is implemented in assembly.
+//go:noescape
+func callCgoSigaction(sig uintptr, new, old *sigactiont) int32
diff --git a/src/runtime/cgocall.go b/src/runtime/cgocall.go
index f8d6930..007406b 100644
--- a/src/runtime/cgocall.go
+++ b/src/runtime/cgocall.go
@@ -104,34 +104,48 @@ func cgocall(fn, arg unsafe.Pointer) int32 {
racereleasemerge(unsafe.Pointer(&racecgosync))
}
- /*
- * Lock g to m to ensure we stay on the same stack if we do a
- * cgo callback. Add entry to defer stack in case of panic.
- */
+ // Lock g to m to ensure we stay on the same stack if we do a
+ // cgo callback. In case of panic, unwindm calls endcgo.
lockOSThread()
mp := getg().m
mp.ncgocall++
mp.ncgo++
- defer endcgo(mp)
// Reset traceback.
mp.cgoCallers[0] = 0
- /*
- * Announce we are entering a system call
- * so that the scheduler knows to create another
- * M to run goroutines while we are in the
- * foreign code.
- *
- * The call to asmcgocall is guaranteed not to
- * split the stack and does not allocate memory,
- * so it is safe to call while "in a system call", outside
- * the $GOMAXPROCS accounting.
- */
+ // Announce we are entering a system call
+ // so that the scheduler knows to create another
+ // M to run goroutines while we are in the
+ // foreign code.
+ //
+ // The call to asmcgocall is guaranteed not to
+ // grow the stack and does not allocate memory,
+ // so it is safe to call while "in a system call", outside
+ // the $GOMAXPROCS accounting.
+ //
+ // fn may call back into Go code, in which case we'll exit the
+ // "system call", run the Go code (which may grow the stack),
+ // and then re-enter the "system call" reusing the PC and SP
+ // saved by entersyscall here.
entersyscall(0)
errno := asmcgocall(fn, arg)
exitsyscall(0)
+ // From the garbage collector's perspective, time can move
+ // backwards in the sequence above. If there's a callback into
+ // Go code, GC will see this function at the call to
+ // asmcgocall. When the Go call later returns to C, the
+ // syscall PC/SP is rolled back and the GC sees this function
+ // back at the call to entersyscall. Normally, fn and arg
+ // would be live at entersyscall and dead at asmcgocall, so if
+ // time moved backwards, GC would see these arguments as dead
+ // and then live. Prevent these undead arguments from crashing
+ // GC by forcing them to stay live across this time warp.
+ KeepAlive(fn)
+ KeepAlive(arg)
+
+ endcgo(mp)
return errno
}
@@ -314,6 +328,16 @@ func unwindm(restore *bool) {
case "arm64":
sched.sp = *(*uintptr)(unsafe.Pointer(sched.sp + 16))
}
+
+ // Call endcgo to do the accounting that cgocall will not have a
+ // chance to do during an unwind.
+ //
+ // In the case where a a Go call originates from C, ncgo is 0
+ // and there is no matching cgocall to end.
+ if mp.ncgo > 0 {
+ endcgo(mp)
+ }
+
releasem(mp)
}
@@ -360,10 +384,10 @@ var racecgosync uint64 // represents possible synchronization in C code
// pointers.)
// cgoCheckPointer checks if the argument contains a Go pointer that
-// points to a Go pointer, and panics if it does. It returns the pointer.
-func cgoCheckPointer(ptr interface{}, args ...interface{}) interface{} {
+// points to a Go pointer, and panics if it does.
+func cgoCheckPointer(ptr interface{}, args ...interface{}) {
if debug.cgocheck == 0 {
- return ptr
+ return
}
ep := (*eface)(unsafe.Pointer(&ptr))
@@ -376,7 +400,7 @@ func cgoCheckPointer(ptr interface{}, args ...interface{}) interface{} {
p = *(*unsafe.Pointer)(p)
}
if !cgoIsGoPointer(p) {
- return ptr
+ return
}
aep := (*eface)(unsafe.Pointer(&args[0]))
switch aep._type.kind & kindMask {
@@ -387,7 +411,7 @@ func cgoCheckPointer(ptr interface{}, args ...interface{}) interface{} {
}
pt := (*ptrtype)(unsafe.Pointer(t))
cgoCheckArg(pt.elem, p, true, false, cgoCheckPointerFail)
- return ptr
+ return
case kindSlice:
// Check the slice rather than the pointer.
ep = aep
@@ -405,7 +429,6 @@ func cgoCheckPointer(ptr interface{}, args ...interface{}) interface{} {
}
cgoCheckArg(t, ep.data, t.kind&kindDirectIface == 0, top, cgoCheckPointerFail)
- return ptr
}
const cgoCheckPointerFail = "cgo argument has Go pointer to Go pointer"
@@ -560,7 +583,7 @@ func cgoCheckUnknownPointer(p unsafe.Pointer, msg string) (base, i uintptr) {
return
}
- for datap := &firstmoduledata; datap != nil; datap = datap.next {
+ for _, datap := range activeModules() {
if cgoInRange(p, datap.data, datap.edata) || cgoInRange(p, datap.bss, datap.ebss) {
// We have no way to know the size of the object.
// We have to assume that it might contain a pointer.
@@ -587,7 +610,7 @@ func cgoIsGoPointer(p unsafe.Pointer) bool {
return true
}
- for datap := &firstmoduledata; datap != nil; datap = datap.next {
+ for _, datap := range activeModules() {
if cgoInRange(p, datap.data, datap.edata) || cgoInRange(p, datap.bss, datap.ebss) {
return true
}
diff --git a/src/runtime/cgocheck.go b/src/runtime/cgocheck.go
index 2d06414..8cac5d9 100644
--- a/src/runtime/cgocheck.go
+++ b/src/runtime/cgocheck.go
@@ -108,7 +108,7 @@ func cgoCheckTypedBlock(typ *_type, src unsafe.Pointer, off, size uintptr) {
}
// The type has a GC program. Try to find GC bits somewhere else.
- for datap := &firstmoduledata; datap != nil; datap = datap.next {
+ for _, datap := range activeModules() {
if cgoInRange(src, datap.data, datap.edata) {
doff := uintptr(src) - datap.data
cgoCheckBits(add(src, -doff), datap.gcdatamask.bytedata, off+doff, size)
@@ -123,7 +123,7 @@ func cgoCheckTypedBlock(typ *_type, src unsafe.Pointer, off, size uintptr) {
aoff := uintptr(src) - mheap_.arena_start
idx := aoff >> _PageShift
- s := h_spans[idx]
+ s := mheap_.spans[idx]
if s.state == _MSpanStack {
// There are no heap bits for value stored on the stack.
// For a channel receive src might be on the stack of some
diff --git a/src/runtime/chan.go b/src/runtime/chan.go
index 712ad8c..b54a46c 100644
--- a/src/runtime/chan.go
+++ b/src/runtime/chan.go
@@ -7,10 +7,16 @@ package runtime
// This file contains the implementation of Go channels.
// Invariants:
-// At least one of c.sendq and c.recvq is empty.
+// At least one of c.sendq and c.recvq is empty,
+// except for the case of an unbuffered channel with a single goroutine
+// blocked on it for both sending and receiving using a select statement,
+// in which case the length of c.sendq and c.recvq is limited only by the
+// size of the select statement.
+//
// For buffered channels, also:
// c.qcount > 0 implies that c.recvq is empty.
// c.qcount < c.dataqsiz implies that c.sendq is empty.
+
import (
"runtime/internal/atomic"
"unsafe"
@@ -281,23 +287,34 @@ func send(c *hchan, sg *sudog, ep unsafe.Pointer, unlockf func()) {
goready(gp, 4)
}
+// Sends and receives on unbuffered or empty-buffered channels are the
+// only operations where one running goroutine writes to the stack of
+// another running goroutine. The GC assumes that stack writes only
+// happen when the goroutine is running and are only done by that
+// goroutine. Using a write barrier is sufficient to make up for
+// violating that assumption, but the write barrier has to work.
+// typedmemmove will call bulkBarrierPreWrite, but the target bytes
+// are not in the heap, so that will not help. We arrange to call
+// memmove and typeBitsBulkBarrier instead.
+
func sendDirect(t *_type, sg *sudog, src unsafe.Pointer) {
- // Send on an unbuffered or empty-buffered channel is the only operation
- // in the entire runtime where one goroutine
- // writes to the stack of another goroutine. The GC assumes that
- // stack writes only happen when the goroutine is running and are
- // only done by that goroutine. Using a write barrier is sufficient to
- // make up for violating that assumption, but the write barrier has to work.
- // typedmemmove will call heapBitsBulkBarrier, but the target bytes
- // are not in the heap, so that will not help. We arrange to call
- // memmove and typeBitsBulkBarrier instead.
+ // src is on our stack, dst is a slot on another stack.
// Once we read sg.elem out of sg, it will no longer
// be updated if the destination's stack gets copied (shrunk).
// So make sure that no preemption points can happen between read & use.
dst := sg.elem
+ typeBitsBulkBarrier(t, uintptr(dst), uintptr(src), t.size)
+ memmove(dst, src, t.size)
+}
+
+func recvDirect(t *_type, sg *sudog, dst unsafe.Pointer) {
+ // dst is on our stack or the heap, src is on another stack.
+ // The channel is locked, so src will not move during this
+ // operation.
+ src := sg.elem
+ typeBitsBulkBarrier(t, uintptr(dst), uintptr(src), t.size)
memmove(dst, src, t.size)
- typeBitsBulkBarrier(t, uintptr(dst), t.size)
}
func closechan(c *hchan) {
@@ -328,7 +345,7 @@ func closechan(c *hchan) {
break
}
if sg.elem != nil {
- memclr(sg.elem, uintptr(c.elemsize))
+ typedmemclr(c.elemtype, sg.elem)
sg.elem = nil
}
if sg.releasetime != 0 {
@@ -437,7 +454,7 @@ func chanrecv(t *chantype, c *hchan, ep unsafe.Pointer, block bool) (selected, r
}
unlock(&c.lock)
if ep != nil {
- memclr(ep, uintptr(c.elemsize))
+ typedmemclr(c.elemtype, ep)
}
return true, false
}
@@ -461,7 +478,7 @@ func chanrecv(t *chantype, c *hchan, ep unsafe.Pointer, block bool) (selected, r
if ep != nil {
typedmemmove(c.elemtype, ep, qp)
}
- memclr(qp, uintptr(c.elemsize))
+ typedmemclr(c.elemtype, qp)
c.recvx++
if c.recvx == c.dataqsiz {
c.recvx = 0
@@ -530,9 +547,7 @@ func recv(c *hchan, sg *sudog, ep unsafe.Pointer, unlockf func()) {
}
if ep != nil {
// copy data from sender
- // ep points to our own stack or heap, so nothing
- // special (ala sendDirect) needed here.
- typedmemmove(c.elemtype, ep, sg.elem)
+ recvDirect(c.elemtype, sg, ep)
}
} else {
// Queue is full. Take the item at the
diff --git a/src/runtime/chan_test.go b/src/runtime/chan_test.go
index 8e8c47b..a75fa1b 100644
--- a/src/runtime/chan_test.go
+++ b/src/runtime/chan_test.go
@@ -210,11 +210,14 @@ func TestNonblockRecvRace(t *testing.T) {
select {
case <-c:
default:
- t.Fatal("chan is not ready")
+ t.Error("chan is not ready")
}
}()
close(c)
<-c
+ if t.Failed() {
+ return
+ }
}
}
@@ -311,14 +314,16 @@ func TestSelfSelect(t *testing.T) {
case c <- p:
case v := <-c:
if chanCap == 0 && v == p {
- t.Fatalf("self receive")
+ t.Errorf("self receive")
+ return
}
}
} else {
select {
case v := <-c:
if chanCap == 0 && v == p {
- t.Fatalf("self receive")
+ t.Errorf("self receive")
+ return
}
case c <- p:
}
diff --git a/src/runtime/cpuflags_amd64.go b/src/runtime/cpuflags_amd64.go
new file mode 100644
index 0000000..026f0cd
--- /dev/null
+++ b/src/runtime/cpuflags_amd64.go
@@ -0,0 +1,75 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package 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
+
+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
+}
+
+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)
+}
+
+func isIntel() bool {
+ intelSignature := [12]byte{'G', 'e', 'n', 'u', 'i', 'n', 'e', 'I', 'n', 't', 'e', 'l'}
+ return vendorStringBytes == intelSignature
+}
diff --git a/src/runtime/cpuidlow_amd64.s b/src/runtime/cpuidlow_amd64.s
new file mode 100644
index 0000000..64316c9
--- /dev/null
+++ b/src/runtime/cpuidlow_amd64.s
@@ -0,0 +1,22 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// 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 5308200..a4b14d3 100644
--- a/src/runtime/cpuprof.go
+++ b/src/runtime/cpuprof.go
@@ -4,7 +4,7 @@
// CPU profiling.
// Based on algorithms and data structures used in
-// http://code.google.com/p/google-perftools/.
+// 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
@@ -68,6 +68,7 @@ type cpuprofEntry struct {
stack [maxCPUProfStack]uintptr
}
+//go:notinheap
type cpuProfile struct {
on bool // profiling is on
wait note // goroutine waits here
diff --git a/src/runtime/cputicks.go b/src/runtime/cputicks.go
index 9162746..ccc3947 100644
--- a/src/runtime/cputicks.go
+++ b/src/runtime/cputicks.go
@@ -6,6 +6,8 @@
// +build !arm64
// +build !mips64
// +build !mips64le
+// +build !mips
+// +build !mipsle
package runtime
diff --git a/src/runtime/crash_cgo_test.go b/src/runtime/crash_cgo_test.go
index 2504bd0..7014f11 100644
--- a/src/runtime/crash_cgo_test.go
+++ b/src/runtime/crash_cgo_test.go
@@ -19,10 +19,12 @@ import (
)
func TestCgoCrashHandler(t *testing.T) {
+ t.Parallel()
testCrashHandler(t, true)
}
func TestCgoSignalDeadlock(t *testing.T) {
+ t.Parallel()
if testing.Short() && runtime.GOOS == "windows" {
t.Skip("Skipping in short mode") // takes up to 64 seconds
}
@@ -34,6 +36,7 @@ func TestCgoSignalDeadlock(t *testing.T) {
}
func TestCgoTraceback(t *testing.T) {
+ t.Parallel()
got := runTestProg(t, "testprogcgo", "CgoTraceback")
want := "OK\n"
if got != want {
@@ -42,8 +45,12 @@ func TestCgoTraceback(t *testing.T) {
}
func TestCgoCallbackGC(t *testing.T) {
- if runtime.GOOS == "plan9" || runtime.GOOS == "windows" {
+ t.Parallel()
+ switch runtime.GOOS {
+ case "plan9", "windows":
t.Skipf("no pthreads on %s", runtime.GOOS)
+ case "freebsd":
+ testenv.SkipFlaky(t, 16396)
}
if testing.Short() {
switch {
@@ -63,6 +70,7 @@ func TestCgoCallbackGC(t *testing.T) {
}
func TestCgoExternalThreadPanic(t *testing.T) {
+ t.Parallel()
if runtime.GOOS == "plan9" {
t.Skipf("no pthreads on %s", runtime.GOOS)
}
@@ -74,6 +82,7 @@ func TestCgoExternalThreadPanic(t *testing.T) {
}
func TestCgoExternalThreadSIGPROF(t *testing.T) {
+ t.Parallel()
// issue 9456.
switch runtime.GOOS {
case "plan9", "windows":
@@ -97,22 +106,42 @@ func TestCgoExternalThreadSIGPROF(t *testing.T) {
// ppc64 (issue #8912)
t.Skipf("no external linking on ppc64")
}
- got := runTestProg(t, "testprogcgo", "CgoExternalThreadSIGPROF")
- want := "OK\n"
- if got != want {
+
+ exe, err := buildTestProg(t, "testprogcgo", "-tags=threadprof")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ got, err := testEnv(exec.Command(exe, "CgoExternalThreadSIGPROF")).CombinedOutput()
+ if err != nil {
+ t.Fatalf("exit status: %v\n%s", err, got)
+ }
+
+ if want := "OK\n"; string(got) != want {
t.Fatalf("expected %q, but got:\n%s", want, got)
}
}
func TestCgoExternalThreadSignal(t *testing.T) {
+ t.Parallel()
// issue 10139
switch runtime.GOOS {
case "plan9", "windows":
t.Skipf("no pthreads on %s", runtime.GOOS)
}
- got := runTestProg(t, "testprogcgo", "CgoExternalThreadSignal")
- want := "OK\n"
- if got != want {
+
+ exe, err := buildTestProg(t, "testprogcgo", "-tags=threadprof")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ got, err := testEnv(exec.Command(exe, "CgoExternalThreadSIGPROF")).CombinedOutput()
+ if err != nil {
+ t.Fatalf("exit status: %v\n%s", err, got)
+ }
+
+ want := []byte("OK\n")
+ if !bytes.Equal(got, want) {
t.Fatalf("expected %q, but got:\n%s", want, got)
}
}
@@ -130,6 +159,7 @@ func TestCgoDLLImports(t *testing.T) {
}
func TestCgoExecSignalMask(t *testing.T) {
+ t.Parallel()
// Test issue 13164.
switch runtime.GOOS {
case "windows", "plan9":
@@ -143,6 +173,7 @@ func TestCgoExecSignalMask(t *testing.T) {
}
func TestEnsureDropM(t *testing.T) {
+ t.Parallel()
// Test for issue 13881.
switch runtime.GOOS {
case "windows", "plan9":
@@ -159,6 +190,7 @@ func TestEnsureDropM(t *testing.T) {
// Test that the program that doesn't need any cgo pointer checking
// takes about the same amount of time with it as without it.
func TestCgoCheckBytes(t *testing.T) {
+ t.Parallel()
// Make sure we don't count the build time as part of the run time.
testenv.MustHaveGoBuild(t)
exe, err := buildTestProg(t, "testprogcgo")
@@ -198,6 +230,7 @@ func TestCgoCheckBytes(t *testing.T) {
}
func TestCgoPanicDeadlock(t *testing.T) {
+ t.Parallel()
// test issue 14432
got := runTestProg(t, "testprogcgo", "CgoPanicDeadlock")
want := "panic: cgo error\n\n"
@@ -207,6 +240,7 @@ func TestCgoPanicDeadlock(t *testing.T) {
}
func TestCgoCCodeSIGPROF(t *testing.T) {
+ t.Parallel()
got := runTestProg(t, "testprogcgo", "CgoCCodeSIGPROF")
want := "OK\n"
if got != want {
@@ -215,6 +249,7 @@ func TestCgoCCodeSIGPROF(t *testing.T) {
}
func TestCgoCrashTraceback(t *testing.T) {
+ t.Parallel()
if runtime.GOOS != "linux" || runtime.GOARCH != "amd64" {
t.Skipf("not yet supported on %s/%s", runtime.GOOS, runtime.GOARCH)
}
@@ -227,6 +262,7 @@ func TestCgoCrashTraceback(t *testing.T) {
}
func TestCgoTracebackContext(t *testing.T) {
+ t.Parallel()
got := runTestProg(t, "testprogcgo", "TracebackContext")
want := "OK\n"
if got != want {
@@ -235,6 +271,7 @@ func TestCgoTracebackContext(t *testing.T) {
}
func testCgoPprof(t *testing.T, buildArg, runArg string) {
+ t.Parallel()
if runtime.GOOS != "linux" || runtime.GOARCH != "amd64" {
t.Skipf("not yet supported on %s/%s", runtime.GOOS, runtime.GOARCH)
}
@@ -252,7 +289,7 @@ func testCgoPprof(t *testing.T, buildArg, runArg string) {
fn := strings.TrimSpace(string(got))
defer os.Remove(fn)
- cmd := testEnv(exec.Command("go", "tool", "pprof", "-top", "-nodecount=1", exe, fn))
+ cmd := testEnv(exec.Command(testenv.GoToolPath(t), "tool", "pprof", "-top", "-nodecount=1", exe, fn))
found := false
for i, e := range cmd.Env {
@@ -288,3 +325,65 @@ func TestCgoPprofPIE(t *testing.T) {
func TestCgoPprofThread(t *testing.T) {
testCgoPprof(t, "", "CgoPprofThread")
}
+
+func TestCgoPprofThreadNoTraceback(t *testing.T) {
+ testCgoPprof(t, "", "CgoPprofThreadNoTraceback")
+}
+
+func TestRaceProf(t *testing.T) {
+ if runtime.GOOS != "linux" || runtime.GOARCH != "amd64" {
+ t.Skipf("not yet supported on %s/%s", runtime.GOOS, runtime.GOARCH)
+ }
+
+ testenv.MustHaveGoRun(t)
+
+ // This test requires building various packages with -race, so
+ // it's somewhat slow.
+ if testing.Short() {
+ t.Skip("skipping test in -short mode")
+ }
+
+ exe, err := buildTestProg(t, "testprogcgo", "-race")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ got, err := testEnv(exec.Command(exe, "CgoRaceprof")).CombinedOutput()
+ if err != nil {
+ t.Fatal(err)
+ }
+ want := "OK\n"
+ if string(got) != want {
+ t.Errorf("expected %q got %s", want, got)
+ }
+}
+
+func TestRaceSignal(t *testing.T) {
+ t.Parallel()
+ if runtime.GOOS != "linux" || runtime.GOARCH != "amd64" {
+ t.Skipf("not yet supported on %s/%s", runtime.GOOS, runtime.GOARCH)
+ }
+
+ testenv.MustHaveGoRun(t)
+
+ // This test requires building various packages with -race, so
+ // it's somewhat slow.
+ if testing.Short() {
+ t.Skip("skipping test in -short mode")
+ }
+
+ exe, err := buildTestProg(t, "testprogcgo", "-race")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ got, err := testEnv(exec.Command(exe, "CgoRaceSignal")).CombinedOutput()
+ if err != nil {
+ t.Logf("%s\n", got)
+ t.Fatal(err)
+ }
+ want := "OK\n"
+ if string(got) != want {
+ t.Errorf("expected %q got %s", want, got)
+ }
+}
diff --git a/src/runtime/crash_test.go b/src/runtime/crash_test.go
index a2f7ff7..9ec0ae4 100644
--- a/src/runtime/crash_test.go
+++ b/src/runtime/crash_test.go
@@ -6,6 +6,7 @@ package runtime_test
import (
"bytes"
+ "flag"
"fmt"
"internal/testenv"
"io/ioutil"
@@ -136,11 +137,10 @@ func buildTestProg(t *testing.T, binary string, flags ...string) (string, error)
}
exe := filepath.Join(testprog.dir, name+".exe")
- cmd := exec.Command("go", append([]string{"build", "-o", exe}, flags...)...)
+ cmd := exec.Command(testenv.GoToolPath(t), append([]string{"build", "-o", exe}, flags...)...)
cmd.Dir = "testdata/" + binary
out, err := testEnv(cmd).CombinedOutput()
if err != nil {
- exe = ""
target.err = fmt.Errorf("building %s %v: %v\n%s", binary, flags, err, out)
testprog.target[name] = target
return "", target.err
@@ -158,7 +158,7 @@ var (
func checkStaleRuntime(t *testing.T) {
staleRuntimeOnce.Do(func() {
// 'go run' uses the installed copy of runtime.a, which may be out of date.
- out, err := testEnv(exec.Command("go", "list", "-f", "{{.Stale}}", "runtime")).CombinedOutput()
+ out, err := testEnv(exec.Command(testenv.GoToolPath(t), "list", "-f", "{{.Stale}}", "runtime")).CombinedOutput()
if err != nil {
staleRuntimeErr = fmt.Errorf("failed to execute 'go list': %v\n%v", err, string(out))
return
@@ -401,6 +401,7 @@ func TestRecoverBeforePanicAfterGoexit(t *testing.T) {
}
func TestNetpollDeadlock(t *testing.T) {
+ t.Parallel()
output := runTestProg(t, "testprognet", "NetpollDeadlock")
want := "done\n"
if !strings.HasSuffix(output, want) {
@@ -409,6 +410,7 @@ func TestNetpollDeadlock(t *testing.T) {
}
func TestPanicTraceback(t *testing.T) {
+ t.Parallel()
output := runTestProg(t, "testprog", "PanicTraceback")
want := "panic: hello"
if !strings.HasPrefix(output, want) {
@@ -416,7 +418,7 @@ func TestPanicTraceback(t *testing.T) {
}
// Check functions in the traceback.
- fns := []string{"panic", "main.pt1.func1", "panic", "main.pt2.func1", "panic", "main.pt2", "main.pt1"}
+ fns := []string{"main.pt1.func1", "panic", "main.pt2.func1", "panic", "main.pt2", "main.pt1"}
for _, fn := range fns {
re := regexp.MustCompile(`(?m)^` + regexp.QuoteMeta(fn) + `\(.*\n`)
idx := re.FindStringIndex(output)
@@ -443,6 +445,13 @@ func TestPanicDeadlockSyscall(t *testing.T) {
testPanicDeadlock(t, "SyscallInPanic", "1\n2\npanic: 3\n\n")
}
+func TestPanicLoop(t *testing.T) {
+ output := runTestProg(t, "testprog", "PanicLoop")
+ if want := "panic while printing panic value"; !strings.Contains(output, want) {
+ t.Errorf("output does not contain %q:\n%s", want, output)
+ }
+}
+
func TestMemPprof(t *testing.T) {
testenv.MustHaveGoRun(t)
@@ -458,7 +467,7 @@ func TestMemPprof(t *testing.T) {
fn := strings.TrimSpace(string(got))
defer os.Remove(fn)
- cmd := testEnv(exec.Command("go", "tool", "pprof", "-alloc_space", "-top", exe, fn))
+ cmd := testEnv(exec.Command(testenv.GoToolPath(t), "tool", "pprof", "-alloc_space", "-top", exe, fn))
found := false
for i, e := range cmd.Env {
@@ -482,3 +491,39 @@ func TestMemPprof(t *testing.T) {
t.Error("missing MemProf in pprof output")
}
}
+
+var concurrentMapTest = flag.Bool("run_concurrent_map_tests", false, "also run flaky concurrent map tests")
+
+func TestConcurrentMapWrites(t *testing.T) {
+ if !*concurrentMapTest {
+ t.Skip("skipping without -run_concurrent_map_tests")
+ }
+ testenv.MustHaveGoRun(t)
+ output := runTestProg(t, "testprog", "concurrentMapWrites")
+ want := "fatal error: concurrent map writes"
+ if !strings.HasPrefix(output, want) {
+ t.Fatalf("output does not start with %q:\n%s", want, output)
+ }
+}
+func TestConcurrentMapReadWrite(t *testing.T) {
+ if !*concurrentMapTest {
+ t.Skip("skipping without -run_concurrent_map_tests")
+ }
+ testenv.MustHaveGoRun(t)
+ output := runTestProg(t, "testprog", "concurrentMapReadWrite")
+ want := "fatal error: concurrent map read and map write"
+ if !strings.HasPrefix(output, want) {
+ t.Fatalf("output does not start with %q:\n%s", want, output)
+ }
+}
+func TestConcurrentMapIterateWrite(t *testing.T) {
+ if !*concurrentMapTest {
+ t.Skip("skipping without -run_concurrent_map_tests")
+ }
+ testenv.MustHaveGoRun(t)
+ output := runTestProg(t, "testprog", "concurrentMapIterateWrite")
+ want := "fatal error: concurrent map iteration and map write"
+ if !strings.HasPrefix(output, want) {
+ t.Fatalf("output does not start with %q:\n%s", want, output)
+ }
+}
diff --git a/src/runtime/crash_unix_test.go b/src/runtime/crash_unix_test.go
index 6e4d04b..97deed8 100644
--- a/src/runtime/crash_unix_test.go
+++ b/src/runtime/crash_unix_test.go
@@ -37,6 +37,8 @@ func TestCrashDumpsAllThreads(t *testing.T) {
checkStaleRuntime(t)
+ t.Parallel()
+
dir, err := ioutil.TempDir("", "go-build")
if err != nil {
t.Fatalf("failed to create temp directory: %v", err)
@@ -47,7 +49,7 @@ func TestCrashDumpsAllThreads(t *testing.T) {
t.Fatalf("failed to create Go file: %v", err)
}
- cmd := exec.Command("go", "build", "-o", "a.exe")
+ cmd := exec.Command(testenv.GoToolPath(t), "build", "-o", "a.exe")
cmd.Dir = dir
out, err := testEnv(cmd).CombinedOutput()
if err != nil {
diff --git a/src/runtime/debug/garbage.go b/src/runtime/debug/garbage.go
index 8144497..c82c024 100644
--- a/src/runtime/debug/garbage.go
+++ b/src/runtime/debug/garbage.go
@@ -71,7 +71,7 @@ func ReadGCStats(stats *GCStats) {
// See the allocation at the top of the function.
sorted := stats.Pause[n : n+n]
copy(sorted, stats.Pause)
- sort.Sort(byDuration(sorted))
+ sort.Slice(sorted, func(i, j int) bool { return sorted[i] < sorted[j] })
nq := len(stats.PauseQuantiles) - 1
for i := 0; i < nq; i++ {
stats.PauseQuantiles[i] = sorted[len(sorted)*i/nq]
@@ -81,12 +81,6 @@ func ReadGCStats(stats *GCStats) {
}
}
-type byDuration []time.Duration
-
-func (x byDuration) Len() int { return len(x) }
-func (x byDuration) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
-func (x byDuration) Less(i, j int) bool { return x[i] < x[j] }
-
// SetGCPercent sets the garbage collection target percentage:
// a collection is triggered when the ratio of freshly allocated data
// to live data remaining after the previous collection reaches this percentage.
diff --git a/src/runtime/debug/garbage_test.go b/src/runtime/debug/garbage_test.go
index 6ec94aa..04e954b 100644
--- a/src/runtime/debug/garbage_test.go
+++ b/src/runtime/debug/garbage_test.go
@@ -80,7 +80,7 @@ func TestReadGCStats(t *testing.T) {
for i := 0; i < n; i++ {
dt := stats.PauseEnd[i]
if dt.UnixNano() != int64(mstats.PauseEnd[off]) {
- t.Errorf("stats.PauseEnd[%d] = %d, want %d", i, dt, mstats.PauseEnd[off])
+ t.Errorf("stats.PauseEnd[%d] = %d, want %d", i, dt.UnixNano(), mstats.PauseEnd[off])
}
off = (off + len(mstats.PauseEnd) - 1) % len(mstats.PauseEnd)
}
@@ -89,10 +89,6 @@ func TestReadGCStats(t *testing.T) {
var big = make([]byte, 1<<20)
func TestFreeOSMemory(t *testing.T) {
- if runtime.GOARCH == "arm64" || runtime.GOARCH == "ppc64" || runtime.GOARCH == "ppc64le" || runtime.GOARCH == "mips64" || runtime.GOARCH == "mips64le" ||
- runtime.GOOS == "nacl" {
- t.Skip("issue 9993; scavenger temporarily disabled on systems with physical pages larger than logical pages")
- }
var ms1, ms2 runtime.MemStats
if big == nil {
@@ -118,3 +114,16 @@ func TestSetGCPercent(t *testing.T) {
t.Errorf("SetGCPercent(123); SetGCPercent(x) = %d, want 123", new)
}
}
+
+func TestSetMaxThreadsOvf(t *testing.T) {
+ // Verify that a big threads count will not overflow the int32
+ // maxmcount variable, causing a panic (see Issue 16076).
+ //
+ // This can only happen when ints are 64 bits, since on platforms
+ // with 32 bit ints SetMaxThreads (which takes an int parameter)
+ // cannot be given anything that will overflow an int32.
+ //
+ // Call SetMaxThreads with 1<<31, but only on 64 bit systems.
+ nt := SetMaxThreads(1 << (30 + ^uint(0)>>63))
+ SetMaxThreads(nt) // restore previous value
+}
diff --git a/src/runtime/defs1_linux.go b/src/runtime/defs1_linux.go
index 87c6e02..e136d96 100644
--- a/src/runtime/defs1_linux.go
+++ b/src/runtime/defs1_linux.go
@@ -33,7 +33,7 @@ type Fpxreg1 C.struct__fpxreg
type Xmmreg1 C.struct__xmmreg
type Fpstate1 C.struct__fpstate
type Fpreg1 C.struct__fpreg
-type SigaltstackT C.struct_sigaltstack
+type StackT C.stack_t
type Mcontext C.mcontext_t
type Ucontext C.ucontext_t
type Sigcontext C.struct_sigcontext
diff --git a/src/runtime/defs1_netbsd_386.go b/src/runtime/defs1_netbsd_386.go
index f222bed..66f07ce 100644
--- a/src/runtime/defs1_netbsd_386.go
+++ b/src/runtime/defs1_netbsd_386.go
@@ -83,12 +83,6 @@ const (
_EVFILT_WRITE = 0x1
)
-type sigaltstackt struct {
- ss_sp uintptr
- ss_size uintptr
- ss_flags int32
-}
-
type sigset struct {
__bits [4]uint32
}
diff --git a/src/runtime/defs1_netbsd_amd64.go b/src/runtime/defs1_netbsd_amd64.go
index c2bde4d..9e31471 100644
--- a/src/runtime/defs1_netbsd_amd64.go
+++ b/src/runtime/defs1_netbsd_amd64.go
@@ -83,13 +83,6 @@ const (
_EVFILT_WRITE = 0x1
)
-type sigaltstackt struct {
- ss_sp uintptr
- ss_size uintptr
- ss_flags int32
- pad_cgo_0 [4]byte
-}
-
type sigset struct {
__bits [4]uint32
}
diff --git a/src/runtime/defs1_netbsd_arm.go b/src/runtime/defs1_netbsd_arm.go
index c976351..db8e4c6 100644
--- a/src/runtime/defs1_netbsd_arm.go
+++ b/src/runtime/defs1_netbsd_arm.go
@@ -83,12 +83,6 @@ const (
_EVFILT_WRITE = 0x1
)
-type sigaltstackt struct {
- ss_sp uintptr
- ss_size uintptr
- ss_flags int32
-}
-
type sigset struct {
__bits [4]uint32
}
@@ -110,6 +104,7 @@ type stackt struct {
type timespec struct {
tv_sec int64
tv_nsec int32
+ _ [4]byte // EABI
}
func (ts *timespec) set_sec(x int32) {
@@ -123,6 +118,7 @@ func (ts *timespec) set_nsec(x int32) {
type timeval struct {
tv_sec int64
tv_usec int32
+ _ [4]byte // EABI
}
func (tv *timeval) set_usec(x int32) {
@@ -135,10 +131,11 @@ type itimerval struct {
}
type mcontextt struct {
- __gregs [17]uint32
- __fpu [4 + 8*32 + 4]byte // EABI
- // __fpu [4+4*33+4]byte // not EABI
+ __gregs [17]uint32
+ _ [4]byte // EABI
+ __fpu [272]byte // EABI
_mc_tlsbase uint32
+ _ [4]byte // EABI
}
type ucontextt struct {
@@ -146,6 +143,7 @@ type ucontextt struct {
uc_link *ucontextt
uc_sigmask sigset
uc_stack stackt
+ _ [4]byte // EABI
uc_mcontext mcontextt
__uc_pad [2]int32
}
@@ -157,6 +155,7 @@ type keventt struct {
fflags uint32
data int64
udata *byte
+ _ [4]byte // EABI
}
// created by cgo -cdefs and then converted to Go
diff --git a/src/runtime/defs1_solaris_amd64.go b/src/runtime/defs1_solaris_amd64.go
index 3bb6f69..5ee3c3f 100644
--- a/src/runtime/defs1_solaris_amd64.go
+++ b/src/runtime/defs1_solaris_amd64.go
@@ -78,6 +78,7 @@ const (
_ITIMER_VIRTUAL = 0x1
_ITIMER_PROF = 0x2
+ __SC_PAGESIZE = 0xb
__SC_NPROCESSORS_ONLN = 0xf
_PTHREAD_CREATE_DETACHED = 0x40
@@ -109,20 +110,13 @@ type semt struct {
sem_pad2 [2]uint64
}
-type sigaltstackt struct {
- ss_sp *byte
- ss_size uint64
- ss_flags int32
- pad_cgo_0 [4]byte
-}
-
type sigset struct {
__sigbits [4]uint32
}
type stackt struct {
ss_sp *byte
- ss_size uint64
+ ss_size uintptr
ss_flags int32
pad_cgo_0 [4]byte
}
diff --git a/src/runtime/defs2_linux.go b/src/runtime/defs2_linux.go
index 9dea6a1..c10dfb8 100644
--- a/src/runtime/defs2_linux.go
+++ b/src/runtime/defs2_linux.go
@@ -139,7 +139,7 @@ type Timespec C.struct_timespec
type Timeval C.struct_timeval
type Sigaction C.struct_kernel_sigaction
type Siginfo C.siginfo_t
-type SigaltstackT C.struct_sigaltstack
+type StackT C.stack_t
type Sigcontext C.struct_sigcontext
type Ucontext C.struct_ucontext
type Itimerval C.struct_itimerval
diff --git a/src/runtime/defs3_linux.go b/src/runtime/defs3_linux.go
index 489c130..6aa3ee4 100644
--- a/src/runtime/defs3_linux.go
+++ b/src/runtime/defs3_linux.go
@@ -35,7 +35,7 @@ type Gregset C.elf_gregset_t
type FPregset C.elf_fpregset_t
type Vreg C.elf_vrreg_t
-type SigaltstackT C.struct_sigaltstack
+type StackT C.stack_t
// PPC64 uses sigcontext in place of mcontext in ucontext.
// see http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/arch/powerpc/include/uapi/asm/ucontext.h
diff --git a/src/runtime/defs_arm_linux.go b/src/runtime/defs_arm_linux.go
index afd6897..e51dd32 100644
--- a/src/runtime/defs_arm_linux.go
+++ b/src/runtime/defs_arm_linux.go
@@ -115,7 +115,7 @@ const (
)
type Timespec C.struct_timespec
-type SigaltstackT C.struct_sigaltstack
+type StackT C.stack_t
type Sigcontext C.struct_sigcontext
type Ucontext C.struct_ucontext
type Timeval C.struct_timeval
diff --git a/src/runtime/defs_dragonfly.go b/src/runtime/defs_dragonfly.go
index c5ebe75..ed00be0 100644
--- a/src/runtime/defs_dragonfly.go
+++ b/src/runtime/defs_dragonfly.go
@@ -109,7 +109,6 @@ const (
type Rtprio C.struct_rtprio
type Lwpparams C.struct_lwp_params
-type SigaltstackT C.struct_sigaltstack
type Sigset C.struct___sigset
type StackT C.stack_t
diff --git a/src/runtime/defs_dragonfly_amd64.go b/src/runtime/defs_dragonfly_amd64.go
index 3ac10b0..fc70103 100644
--- a/src/runtime/defs_dragonfly_amd64.go
+++ b/src/runtime/defs_dragonfly_amd64.go
@@ -99,13 +99,6 @@ type lwpparams struct {
tid2 unsafe.Pointer // *int32
}
-type sigaltstackt struct {
- ss_sp uintptr
- ss_size uintptr
- ss_flags int32
- pad_cgo_0 [4]byte
-}
-
type sigset struct {
__bits [4]uint32
}
diff --git a/src/runtime/defs_freebsd.go b/src/runtime/defs_freebsd.go
index 3f2184d..73422b7 100644
--- a/src/runtime/defs_freebsd.go
+++ b/src/runtime/defs_freebsd.go
@@ -120,7 +120,6 @@ const (
type Rtprio C.struct_rtprio
type ThrParam C.struct_thr_param
-type SigaltstackT C.struct_sigaltstack
type Sigset C.struct___sigset
type StackT C.stack_t
diff --git a/src/runtime/defs_freebsd_386.go b/src/runtime/defs_freebsd_386.go
index efcbeb7..0c05d71 100644
--- a/src/runtime/defs_freebsd_386.go
+++ b/src/runtime/defs_freebsd_386.go
@@ -111,12 +111,6 @@ type thrparam struct {
spare [3]uintptr
}
-type sigaltstackt struct {
- ss_sp *int8
- ss_size uint32
- ss_flags int32
-}
-
type sigset struct {
__bits [4]uint32
}
diff --git a/src/runtime/defs_freebsd_amd64.go b/src/runtime/defs_freebsd_amd64.go
index 594f957..b416044 100644
--- a/src/runtime/defs_freebsd_amd64.go
+++ b/src/runtime/defs_freebsd_amd64.go
@@ -112,13 +112,6 @@ type thrparam struct {
spare [3]uintptr
}
-type sigaltstackt struct {
- ss_sp *int8
- ss_size uint64
- ss_flags int32
- pad_cgo_0 [4]byte
-}
-
type sigset struct {
__bits [4]uint32
}
diff --git a/src/runtime/defs_freebsd_arm.go b/src/runtime/defs_freebsd_arm.go
index 0e9a2e9..8f85f17 100644
--- a/src/runtime/defs_freebsd_arm.go
+++ b/src/runtime/defs_freebsd_arm.go
@@ -111,12 +111,6 @@ type thrparam struct {
spare [3]uintptr
}
-type sigaltstackt struct {
- ss_sp *uint8
- ss_size uint32
- ss_flags int32
-}
-
type sigset struct {
__bits [4]uint32
}
diff --git a/src/runtime/defs_linux_386.go b/src/runtime/defs_linux_386.go
index 44d2fd1..a7e435f 100644
--- a/src/runtime/defs_linux_386.go
+++ b/src/runtime/defs_linux_386.go
@@ -168,7 +168,7 @@ type siginfo struct {
si_addr uint32
}
-type sigaltstackt struct {
+type stackt struct {
ss_sp *byte
ss_flags int32
ss_size uintptr
@@ -208,7 +208,7 @@ type sigcontext struct {
type ucontext struct {
uc_flags uint32
uc_link *ucontext
- uc_stack sigaltstackt
+ uc_stack stackt
uc_mcontext sigcontext
uc_sigmask uint32
}
diff --git a/src/runtime/defs_linux_amd64.go b/src/runtime/defs_linux_amd64.go
index 1936285..e8c6a21 100644
--- a/src/runtime/defs_linux_amd64.go
+++ b/src/runtime/defs_linux_amd64.go
@@ -205,7 +205,7 @@ type fpreg1 struct {
exponent uint16
}
-type sigaltstackt struct {
+type stackt struct {
ss_sp *byte
ss_flags int32
pad_cgo_0 [4]byte
@@ -221,7 +221,7 @@ type mcontext struct {
type ucontext struct {
uc_flags uint64
uc_link *ucontext
- uc_stack sigaltstackt
+ uc_stack stackt
uc_mcontext mcontext
uc_sigmask usigset
__fpregs_mem fpstate
diff --git a/src/runtime/defs_linux_arm.go b/src/runtime/defs_linux_arm.go
index b68b964..62ec8fa 100644
--- a/src/runtime/defs_linux_arm.go
+++ b/src/runtime/defs_linux_arm.go
@@ -101,7 +101,7 @@ func (ts *timespec) set_nsec(x int32) {
ts.tv_nsec = x
}
-type sigaltstackt struct {
+type stackt struct {
ss_sp *byte
ss_flags int32
ss_size uintptr
@@ -134,7 +134,7 @@ type sigcontext struct {
type ucontext struct {
uc_flags uint32
uc_link *ucontext
- uc_stack sigaltstackt
+ uc_stack stackt
uc_mcontext sigcontext
uc_sigmask uint32
__unused [31]int32
diff --git a/src/runtime/defs_linux_arm64.go b/src/runtime/defs_linux_arm64.go
index d1b1a36..c295bc0 100644
--- a/src/runtime/defs_linux_arm64.go
+++ b/src/runtime/defs_linux_arm64.go
@@ -153,7 +153,7 @@ type usigset struct {
__val [16]uint64
}
-type sigaltstackt struct {
+type stackt struct {
ss_sp *byte
ss_flags int32
pad_cgo_0 [4]byte
@@ -179,7 +179,7 @@ type sockaddr_un struct {
type ucontext struct {
uc_flags uint64
uc_link *ucontext
- uc_stack sigaltstackt
+ uc_stack stackt
uc_sigmask uint64
_pad [(1024 - 64) / 8]byte
_pad2 [8]byte // sigcontext must be aligned to 16-byte
diff --git a/src/runtime/defs_linux_mips64x.go b/src/runtime/defs_linux_mips64x.go
index bb3cd98..df11cb0 100644
--- a/src/runtime/defs_linux_mips64x.go
+++ b/src/runtime/defs_linux_mips64x.go
@@ -150,7 +150,7 @@ const (
_SA_RESTORER = 0
)
-type sigaltstackt struct {
+type stackt struct {
ss_sp *byte
ss_size uintptr
ss_flags int32
@@ -177,7 +177,7 @@ type sigcontext struct {
type ucontext struct {
uc_flags uint64
uc_link *ucontext
- uc_stack sigaltstackt
+ uc_stack stackt
uc_mcontext sigcontext
uc_sigmask uint64
}
diff --git a/src/runtime/defs_linux_mipsx.go b/src/runtime/defs_linux_mipsx.go
new file mode 100644
index 0000000..702fbb5
--- /dev/null
+++ b/src/runtime/defs_linux_mipsx.go
@@ -0,0 +1,188 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build mips mipsle
+// +build linux
+
+package runtime
+
+const (
+ _EINTR = 0x4
+ _EAGAIN = 0xb
+ _ENOMEM = 0xc
+
+ _PROT_NONE = 0x0
+ _PROT_READ = 0x1
+ _PROT_WRITE = 0x2
+ _PROT_EXEC = 0x4
+
+ _MAP_ANON = 0x800
+ _MAP_PRIVATE = 0x2
+ _MAP_FIXED = 0x10
+
+ _MADV_DONTNEED = 0x4
+ _MADV_HUGEPAGE = 0xe
+ _MADV_NOHUGEPAGE = 0xf
+
+ _SA_RESTART = 0x10000000
+ _SA_ONSTACK = 0x8000000
+ _SA_SIGINFO = 0x8
+
+ _SIGHUP = 0x1
+ _SIGINT = 0x2
+ _SIGQUIT = 0x3
+ _SIGILL = 0x4
+ _SIGTRAP = 0x5
+ _SIGABRT = 0x6
+ _SIGEMT = 0x7
+ _SIGFPE = 0x8
+ _SIGKILL = 0x9
+ _SIGBUS = 0xa
+ _SIGSEGV = 0xb
+ _SIGSYS = 0xc
+ _SIGPIPE = 0xd
+ _SIGALRM = 0xe
+ _SIGUSR1 = 0x10
+ _SIGUSR2 = 0x11
+ _SIGCHLD = 0x12
+ _SIGPWR = 0x13
+ _SIGWINCH = 0x14
+ _SIGURG = 0x15
+ _SIGIO = 0x16
+ _SIGSTOP = 0x17
+ _SIGTSTP = 0x18
+ _SIGCONT = 0x19
+ _SIGTTIN = 0x1a
+ _SIGTTOU = 0x1b
+ _SIGVTALRM = 0x1c
+ _SIGPROF = 0x1d
+ _SIGXCPU = 0x1e
+ _SIGXFSZ = 0x1f
+
+ _FPE_INTDIV = 0x1
+ _FPE_INTOVF = 0x2
+ _FPE_FLTDIV = 0x3
+ _FPE_FLTOVF = 0x4
+ _FPE_FLTUND = 0x5
+ _FPE_FLTRES = 0x6
+ _FPE_FLTINV = 0x7
+ _FPE_FLTSUB = 0x8
+
+ _BUS_ADRALN = 0x1
+ _BUS_ADRERR = 0x2
+ _BUS_OBJERR = 0x3
+
+ _SEGV_MAPERR = 0x1
+ _SEGV_ACCERR = 0x2
+
+ _ITIMER_REAL = 0x0
+ _ITIMER_VIRTUAL = 0x1
+ _ITIMER_PROF = 0x2
+
+ _EPOLLIN = 0x1
+ _EPOLLOUT = 0x4
+ _EPOLLERR = 0x8
+ _EPOLLHUP = 0x10
+ _EPOLLRDHUP = 0x2000
+ _EPOLLET = 0x80000000
+ _EPOLL_CLOEXEC = 0x80000
+ _EPOLL_CTL_ADD = 0x1
+ _EPOLL_CTL_DEL = 0x2
+ _EPOLL_CTL_MOD = 0x3
+)
+
+type timespec struct {
+ tv_sec int32
+ tv_nsec int32
+}
+
+//go:nosplit
+func (ts *timespec) set_sec(x int64) {
+ ts.tv_sec = int32(x)
+}
+
+//go:nosplit
+func (ts *timespec) set_nsec(x int32) {
+ ts.tv_nsec = x
+}
+
+type timeval struct {
+ tv_sec int32
+ tv_usec int32
+}
+
+//go:nosplit
+func (tv *timeval) set_usec(x int32) {
+ tv.tv_usec = x
+}
+
+type sigactiont struct {
+ sa_flags uint32
+ sa_handler uintptr
+ sa_mask [4]uint32
+ // linux header does not have sa_restorer field,
+ // but it is used in setsig(). it is no harm to put it here
+ sa_restorer uintptr
+}
+
+type siginfo struct {
+ si_signo int32
+ si_code int32
+ si_errno int32
+ // below here is a union; si_addr is the only field we use
+ si_addr uint32
+}
+
+type itimerval struct {
+ it_interval timeval
+ it_value timeval
+}
+
+type epollevent struct {
+ events uint32
+ pad_cgo_0 [4]byte
+ data uint64
+}
+
+const (
+ _O_RDONLY = 0x0
+ _O_CLOEXEC = 0x80000
+ _SA_RESTORER = 0
+)
+
+type stackt struct {
+ ss_sp *byte
+ ss_size uintptr
+ ss_flags int32
+}
+
+type sigcontext struct {
+ sc_regmask uint32
+ sc_status uint32
+ sc_pc uint64
+ sc_regs [32]uint64
+ sc_fpregs [32]uint64
+ sc_acx uint32
+ sc_fpc_csr uint32
+ sc_fpc_eir uint32
+ sc_used_math uint32
+ sc_dsp uint32
+ sc_mdhi uint64
+ sc_mdlo uint64
+ sc_hi1 uint32
+ sc_lo1 uint32
+ sc_hi2 uint32
+ sc_lo2 uint32
+ sc_hi3 uint32
+ sc_lo3 uint32
+}
+
+type ucontext struct {
+ uc_flags uint32
+ uc_link *ucontext
+ uc_stack stackt
+ Pad_cgo_0 [4]byte
+ uc_mcontext sigcontext
+ uc_sigmask [4]uint32
+}
diff --git a/src/runtime/defs_linux_ppc64.go b/src/runtime/defs_linux_ppc64.go
index 317a764..45363d1 100644
--- a/src/runtime/defs_linux_ppc64.go
+++ b/src/runtime/defs_linux_ppc64.go
@@ -170,7 +170,7 @@ type vreg struct {
u [4]uint32
}
-type sigaltstackt struct {
+type stackt struct {
ss_sp *byte
ss_flags int32
pad_cgo_0 [4]byte
@@ -193,7 +193,7 @@ type sigcontext struct {
type ucontext struct {
uc_flags uint64
uc_link *ucontext
- uc_stack sigaltstackt
+ uc_stack stackt
uc_sigmask uint64
__unused [15]uint64
uc_mcontext sigcontext
diff --git a/src/runtime/defs_linux_ppc64le.go b/src/runtime/defs_linux_ppc64le.go
index 317a764..45363d1 100644
--- a/src/runtime/defs_linux_ppc64le.go
+++ b/src/runtime/defs_linux_ppc64le.go
@@ -170,7 +170,7 @@ type vreg struct {
u [4]uint32
}
-type sigaltstackt struct {
+type stackt struct {
ss_sp *byte
ss_flags int32
pad_cgo_0 [4]byte
@@ -193,7 +193,7 @@ type sigcontext struct {
type ucontext struct {
uc_flags uint64
uc_link *ucontext
- uc_stack sigaltstackt
+ uc_stack stackt
uc_sigmask uint64
__unused [15]uint64
uc_mcontext sigcontext
diff --git a/src/runtime/defs_linux_s390x.go b/src/runtime/defs_linux_s390x.go
index 5f55d5a..ab90723 100644
--- a/src/runtime/defs_linux_s390x.go
+++ b/src/runtime/defs_linux_s390x.go
@@ -143,7 +143,7 @@ const (
_SA_RESTORER = 0
)
-type sigaltstackt struct {
+type stackt struct {
ss_sp *byte
ss_flags int32
ss_size uintptr
@@ -161,7 +161,7 @@ type sigcontext struct {
type ucontext struct {
uc_flags uint64
uc_link *ucontext
- uc_stack sigaltstackt
+ uc_stack stackt
uc_mcontext sigcontext
uc_sigmask uint64
}
diff --git a/src/runtime/defs_netbsd.go b/src/runtime/defs_netbsd.go
index b27949e..56db1f0 100644
--- a/src/runtime/defs_netbsd.go
+++ b/src/runtime/defs_netbsd.go
@@ -109,7 +109,6 @@ const (
EVFILT_WRITE = C.EVFILT_WRITE
)
-type SigaltstackT C.struct_sigaltstack
type Sigset C.sigset_t
type Siginfo C.struct__ksiginfo
diff --git a/src/runtime/defs_openbsd.go b/src/runtime/defs_openbsd.go
index 39224c9..7e72150 100644
--- a/src/runtime/defs_openbsd.go
+++ b/src/runtime/defs_openbsd.go
@@ -106,7 +106,6 @@ const (
type TforkT C.struct___tfork
-type SigaltstackT C.struct_sigaltstack
type Sigcontext C.struct_sigcontext
type Siginfo C.siginfo_t
type Sigset C.sigset_t
diff --git a/src/runtime/defs_openbsd_386.go b/src/runtime/defs_openbsd_386.go
index 4b60158..ce08111 100644
--- a/src/runtime/defs_openbsd_386.go
+++ b/src/runtime/defs_openbsd_386.go
@@ -90,12 +90,6 @@ type tforkt struct {
tf_stack uintptr
}
-type sigaltstackt struct {
- ss_sp uintptr
- ss_size uintptr
- ss_flags int32
-}
-
type sigcontext struct {
sc_gs uint32
sc_fs uint32
diff --git a/src/runtime/defs_openbsd_amd64.go b/src/runtime/defs_openbsd_amd64.go
index 3c27c91..ea07098 100644
--- a/src/runtime/defs_openbsd_amd64.go
+++ b/src/runtime/defs_openbsd_amd64.go
@@ -90,13 +90,6 @@ type tforkt struct {
tf_stack uintptr
}
-type sigaltstackt struct {
- ss_sp uintptr
- ss_size uintptr
- ss_flags int32
- pad_cgo_0 [4]byte
-}
-
type sigcontext struct {
sc_rdi uint64
sc_rsi uint64
diff --git a/src/runtime/defs_openbsd_arm.go b/src/runtime/defs_openbsd_arm.go
index aab9276..b0fb639 100644
--- a/src/runtime/defs_openbsd_arm.go
+++ b/src/runtime/defs_openbsd_arm.go
@@ -90,12 +90,6 @@ type tforkt struct {
tf_stack uintptr
}
-type sigaltstackt struct {
- ss_sp uintptr
- ss_size uintptr
- ss_flags int32
-}
-
type sigcontext struct {
__sc_unused int32
sc_mask int32
diff --git a/src/runtime/defs_plan9_386.go b/src/runtime/defs_plan9_386.go
index 54ace48..220169d 100644
--- a/src/runtime/defs_plan9_386.go
+++ b/src/runtime/defs_plan9_386.go
@@ -28,7 +28,10 @@ type sigctxt struct {
u *ureg
}
+//go:nosplit
+//go:nowritebarrierrec
func (c *sigctxt) pc() uintptr { return uintptr(c.u.pc) }
+
func (c *sigctxt) sp() uintptr { return uintptr(c.u.sp) }
func (c *sigctxt) lr() uintptr { return uintptr(0) }
diff --git a/src/runtime/defs_plan9_amd64.go b/src/runtime/defs_plan9_amd64.go
index 1633ec1..29a2643 100644
--- a/src/runtime/defs_plan9_amd64.go
+++ b/src/runtime/defs_plan9_amd64.go
@@ -37,7 +37,10 @@ type sigctxt struct {
u *ureg
}
+//go:nosplit
+//go:nowritebarrierrec
func (c *sigctxt) pc() uintptr { return uintptr(c.u.ip) }
+
func (c *sigctxt) sp() uintptr { return uintptr(c.u.sp) }
func (c *sigctxt) lr() uintptr { return uintptr(0) }
diff --git a/src/runtime/defs_plan9_arm.go b/src/runtime/defs_plan9_arm.go
index 9c700ae..1adc16e 100644
--- a/src/runtime/defs_plan9_arm.go
+++ b/src/runtime/defs_plan9_arm.go
@@ -31,7 +31,10 @@ type sigctxt struct {
u *ureg
}
+//go:nosplit
+//go:nowritebarrierrec
func (c *sigctxt) pc() uintptr { return uintptr(c.u.pc) }
+
func (c *sigctxt) sp() uintptr { return uintptr(c.u.sp) }
func (c *sigctxt) lr() uintptr { return uintptr(c.u.link) }
diff --git a/src/runtime/defs_solaris.go b/src/runtime/defs_solaris.go
index ba44e5f..0638e0b 100644
--- a/src/runtime/defs_solaris.go
+++ b/src/runtime/defs_solaris.go
@@ -133,7 +133,6 @@ const (
type SemT C.sem_t
-type SigaltstackT C.struct_sigaltstack
type Sigset C.sigset_t
type StackT C.stack_t
diff --git a/src/runtime/duff_arm64.s b/src/runtime/duff_arm64.s
index 6d4bb15..5a147fa 100644
--- a/src/runtime/duff_arm64.s
+++ b/src/runtime/duff_arm64.s
@@ -135,4 +135,389 @@ TEXT runtime·duffzero(SB), NOSPLIT, $-8-0
MOVD.W ZR, 8(R16)
RET
-// TODO: Implement runtime·duffcopy.
+TEXT runtime·duffcopy(SB), NOSPLIT, $0-0
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ MOVD.P 8(R16), R27
+ MOVD.P R27, 8(R17)
+
+ RET
diff --git a/src/runtime/export_mmap_test.go b/src/runtime/export_mmap_test.go
index bc8191e..f569627 100644
--- a/src/runtime/export_mmap_test.go
+++ b/src/runtime/export_mmap_test.go
@@ -9,7 +9,13 @@
package runtime
var Mmap = mmap
+var Munmap = munmap
const ENOMEM = _ENOMEM
const MAP_ANON = _MAP_ANON
const MAP_PRIVATE = _MAP_PRIVATE
+const MAP_FIXED = _MAP_FIXED
+
+func GetPhysPageSize() uintptr {
+ return physPageSize
+}
diff --git a/src/runtime/export_test.go b/src/runtime/export_test.go
index 199a049..9b76555 100644
--- a/src/runtime/export_test.go
+++ b/src/runtime/export_test.go
@@ -32,6 +32,9 @@ var FuncPC = funcPC
var Fastlog2 = fastlog2
+var Atoi = atoi
+var Atoi32 = atoi32
+
type LFNode struct {
Next uint64
Pushcnt uintptr
@@ -155,7 +158,11 @@ var Int32Hash = int32Hash
var Int64Hash = int64Hash
var EfaceHash = efaceHash
var IfaceHash = ifaceHash
-var MemclrBytes = memclrBytes
+
+func MemclrBytes(b []byte) {
+ s := (*slice)(unsafe.Pointer(&b))
+ memclrNoHeapPointers(s.array, uintptr(s.len))
+}
var HashLoad = &hashLoad
@@ -167,9 +174,6 @@ func GostringW(w []uint16) (s string) {
return
}
-var Gostringnocopy = gostringnocopy
-var Maxstring = &maxstring
-
type Uintreg sys.Uintreg
var Open = open
@@ -213,9 +217,6 @@ func BenchSetType(n int, x interface{}) {
const PtrSize = sys.PtrSize
-var TestingAssertE2I2GC = &testingAssertE2I2GC
-var TestingAssertE2T2GC = &testingAssertE2T2GC
-
var ForceGCPeriod = &forcegcperiod
// SetTracebackEnv is like runtime/debug.SetTraceback, but it raises
@@ -234,7 +235,7 @@ func CountPagesInUse() (pagesInUse, counted uintptr) {
pagesInUse = uintptr(mheap_.pagesInUse)
- for _, s := range h_allspans {
+ for _, s := range mheap_.allspans {
if s.state == mSpanInUse {
counted += s.npages
}
diff --git a/src/runtime/extern.go b/src/runtime/extern.go
index 441dcd9..1b53367 100644
--- a/src/runtime/extern.go
+++ b/src/runtime/extern.go
@@ -57,6 +57,11 @@ It is a comma-separated list of name=val pairs setting these named variables:
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
+ garbage collected.
+
gcstoptheworld: setting gcstoptheworld=1 disables concurrent garbage collection,
making every garbage collection a stop-the-world event. Setting gcstoptheworld=2
also disables concurrent sweeping after the garbage collection finishes.
diff --git a/src/runtime/gc_test.go b/src/runtime/gc_test.go
index d53d3ee..4a32f15 100644
--- a/src/runtime/gc_test.go
+++ b/src/runtime/gc_test.go
@@ -5,7 +5,6 @@
package runtime_test
import (
- "io"
"os"
"reflect"
"runtime"
@@ -399,37 +398,6 @@ func TestPrintGC(t *testing.T) {
close(done)
}
-// The implicit y, ok := x.(error) for the case error
-// in testTypeSwitch used to not initialize the result y
-// before passing &y to assertE2I2GC.
-// Catch this by making assertE2I2 call runtime.GC,
-// which will force a stack scan and failure if there are
-// bad pointers, and then fill the stack with bad pointers
-// and run the type switch.
-func TestAssertE2I2Liveness(t *testing.T) {
- // Note that this flag is defined in export_test.go
- // and is not available to ordinary imports of runtime.
- *runtime.TestingAssertE2I2GC = true
- defer func() {
- *runtime.TestingAssertE2I2GC = false
- }()
-
- poisonStack()
- testTypeSwitch(io.EOF)
- poisonStack()
- testAssert(io.EOF)
- poisonStack()
- testAssertVar(io.EOF)
-}
-
-func poisonStack() uintptr {
- var x [1000]uintptr
- for i := range x {
- x[i] = 0xff
- }
- return x[123]
-}
-
func testTypeSwitch(x interface{}) error {
switch y := x.(type) {
case nil:
@@ -455,16 +423,6 @@ func testAssertVar(x interface{}) error {
return nil
}
-func TestAssertE2T2Liveness(t *testing.T) {
- *runtime.TestingAssertE2T2GC = true
- defer func() {
- *runtime.TestingAssertE2T2GC = false
- }()
-
- poisonStack()
- testIfaceEqual(io.EOF)
-}
-
var a bool
//go:noinline
diff --git a/src/runtime/gcinfo_test.go b/src/runtime/gcinfo_test.go
index 011f005..14f514f 100644
--- a/src/runtime/gcinfo_test.go
+++ b/src/runtime/gcinfo_test.go
@@ -139,7 +139,7 @@ type BigStruct struct {
func infoBigStruct() []byte {
switch runtime.GOARCH {
- case "386", "arm":
+ case "386", "arm", "mips", "mipsle":
return []byte{
typePointer, // q *int
typeScalar, typeScalar, typeScalar, typeScalar, typeScalar, // w byte; e [17]byte
diff --git a/src/runtime/hash32.go b/src/runtime/hash32.go
index 2b7c5c0..be59076 100644
--- a/src/runtime/hash32.go
+++ b/src/runtime/hash32.go
@@ -6,7 +6,7 @@
// xxhash: https://code.google.com/p/xxhash/
// cityhash: https://code.google.com/p/cityhash/
-// +build 386 arm
+// +build 386 arm mips mipsle
package runtime
diff --git a/src/runtime/hash_test.go b/src/runtime/hash_test.go
index 3108b3b..a6f3cdb 100644
--- a/src/runtime/hash_test.go
+++ b/src/runtime/hash_test.go
@@ -683,6 +683,9 @@ func BenchmarkUnalignedLoad(b *testing.B) {
}
func TestCollisions(t *testing.T) {
+ if testing.Short() {
+ t.Skip("Skipping in short mode")
+ }
for i := 0; i < 16; i++ {
for j := 0; j < 16; j++ {
if j == i {
diff --git a/src/runtime/hashmap.go b/src/runtime/hashmap.go
index 509cab2..086d374 100644
--- a/src/runtime/hashmap.go
+++ b/src/runtime/hashmap.go
@@ -93,9 +93,10 @@ const (
minTopHash = 4 // minimum tophash for a normal filled cell.
// flags
- iterator = 1 // there may be an iterator using buckets
- oldIterator = 2 // there may be an iterator using oldbuckets
- hashWriting = 4 // a goroutine is writing to the map
+ iterator = 1 // there may be an iterator using buckets
+ oldIterator = 2 // there may be an iterator using oldbuckets
+ hashWriting = 4 // a goroutine is writing to the map
+ sameSizeGrow = 8 // the current map growth is to a new map of the same size
// sentinel bucket ID for iterator checks
noCheck = 1<<(8*sys.PtrSize) - 1
@@ -105,10 +106,11 @@ const (
type hmap struct {
// Note: the format of the Hmap is encoded in ../../cmd/internal/gc/reflect.go and
// ../reflect/type.go. Don't change this structure without also changing that code!
- count int // # live cells == size of map. Must be first (used by len() builtin)
- flags uint8
- B uint8 // log_2 of # of buckets (can hold up to loadFactor * 2^B items)
- hash0 uint32 // hash seed
+ count int // # live cells == size of map. Must be first (used by len() builtin)
+ flags uint8
+ B uint8 // log_2 of # of buckets (can hold up to loadFactor * 2^B items)
+ noverflow uint16 // approximate number of overflow buckets; see incrnoverflow for details
+ hash0 uint32 // hash seed
buckets unsafe.Pointer // array of 2^B Buckets. may be nil if count==0.
oldbuckets unsafe.Pointer // previous bucket array of half the size, non-nil only when growing
@@ -128,6 +130,9 @@ type hmap struct {
// A bucket for a Go map.
type bmap struct {
+ // tophash generally contains the top byte of the hash value
+ // for each key in this bucket. If tophash[0] < minTopHash,
+ // tophash[0] is a bucket evacuation state instead.
tophash [bucketCnt]uint8
// Followed by bucketCnt keys and then bucketCnt values.
// NOTE: packing all the keys together and then all the values together makes the
@@ -165,7 +170,34 @@ func (b *bmap) overflow(t *maptype) *bmap {
return *(**bmap)(add(unsafe.Pointer(b), uintptr(t.bucketsize)-sys.PtrSize))
}
+// incrnoverflow increments h.noverflow.
+// noverflow counts the number of overflow buckets.
+// This is used to trigger same-size map growth.
+// See also tooManyOverflowBuckets.
+// To keep hmap small, noverflow is a uint16.
+// When there are few buckets, noverflow is an exact count.
+// When there are many buckets, noverflow is an approximate count.
+func (h *hmap) incrnoverflow() {
+ // We trigger same-size map growth if there are
+ // as many overflow buckets as buckets.
+ // We need to be able to count to 1<<h.B.
+ if h.B < 16 {
+ h.noverflow++
+ return
+ }
+ // Increment with probability 1/(1<<(h.B-15)).
+ // When we reach 1<<15 - 1, we will have approximately
+ // as many overflow buckets as buckets.
+ mask := uint32(1)<<(h.B-15) - 1
+ // Example: if h.B == 18, then mask == 7,
+ // and fastrand & 7 == 0 with probability 1/8.
+ if fastrand()&mask == 0 {
+ h.noverflow++
+ }
+}
+
func (h *hmap) setoverflow(t *maptype, b, ovf *bmap) {
+ h.incrnoverflow()
if t.bucket.kind&kindNoPointers != 0 {
h.createOverflow()
*h.overflow[0] = append(*h.overflow[0], ovf)
@@ -238,7 +270,7 @@ func makemap(t *maptype, hint int64, h *hmap, bucket unsafe.Pointer) *hmap {
// find size parameter which will hold the requested # of elements
B := uint8(0)
- for ; hint > bucketCnt && float32(hint) > loadFactor*float32(uintptr(1)<<B); B++ {
+ for ; overLoadFactor(hint, B); B++ {
}
// allocate initial hash table
@@ -256,10 +288,11 @@ func makemap(t *maptype, hint int64, h *hmap, bucket unsafe.Pointer) *hmap {
h.count = 0
h.B = B
h.flags = 0
- h.hash0 = fastrand1()
+ h.hash0 = fastrand()
h.buckets = buckets
h.oldbuckets = nil
h.nevacuate = 0
+ h.noverflow = 0
return h
}
@@ -290,7 +323,11 @@ func mapaccess1(t *maptype, h *hmap, key unsafe.Pointer) unsafe.Pointer {
m := uintptr(1)<<h.B - 1
b := (*bmap)(add(h.buckets, (hash&m)*uintptr(t.bucketsize)))
if c := h.oldbuckets; c != nil {
- oldb := (*bmap)(add(c, (hash&(m>>1))*uintptr(t.bucketsize)))
+ if !h.sameSizeGrow() {
+ // There used to be half as many buckets; mask down one more power of two.
+ m >>= 1
+ }
+ oldb := (*bmap)(add(c, (hash&m)*uintptr(t.bucketsize)))
if !evacuated(oldb) {
b = oldb
}
@@ -344,7 +381,11 @@ func mapaccess2(t *maptype, h *hmap, key unsafe.Pointer) (unsafe.Pointer, bool)
m := uintptr(1)<<h.B - 1
b := (*bmap)(unsafe.Pointer(uintptr(h.buckets) + (hash&m)*uintptr(t.bucketsize)))
if c := h.oldbuckets; c != nil {
- oldb := (*bmap)(unsafe.Pointer(uintptr(c) + (hash&(m>>1))*uintptr(t.bucketsize)))
+ if !h.sameSizeGrow() {
+ // There used to be half as many buckets; mask down one more power of two.
+ m >>= 1
+ }
+ oldb := (*bmap)(unsafe.Pointer(uintptr(c) + (hash&m)*uintptr(t.bucketsize)))
if !evacuated(oldb) {
b = oldb
}
@@ -382,15 +423,16 @@ func mapaccessK(t *maptype, h *hmap, key unsafe.Pointer) (unsafe.Pointer, unsafe
if h == nil || h.count == 0 {
return nil, nil
}
- if h.flags&hashWriting != 0 {
- throw("concurrent map read and map write")
- }
alg := t.key.alg
hash := alg.hash(key, uintptr(h.hash0))
m := uintptr(1)<<h.B - 1
b := (*bmap)(unsafe.Pointer(uintptr(h.buckets) + (hash&m)*uintptr(t.bucketsize)))
if c := h.oldbuckets; c != nil {
- oldb := (*bmap)(unsafe.Pointer(uintptr(c) + (hash&(m>>1))*uintptr(t.bucketsize)))
+ if !h.sameSizeGrow() {
+ // There used to be half as many buckets; mask down one more power of two.
+ m >>= 1
+ }
+ oldb := (*bmap)(unsafe.Pointer(uintptr(c) + (hash&m)*uintptr(t.bucketsize)))
if !evacuated(oldb) {
b = oldb
}
@@ -439,20 +481,19 @@ func mapaccess2_fat(t *maptype, h *hmap, key, zero unsafe.Pointer) (unsafe.Point
return v, true
}
-func mapassign1(t *maptype, h *hmap, key unsafe.Pointer, val unsafe.Pointer) {
+// Like mapaccess, but allocates a slot for the key if it is not present in the map.
+func mapassign(t *maptype, h *hmap, key unsafe.Pointer) unsafe.Pointer {
if h == nil {
panic(plainError("assignment to entry in nil map"))
}
if raceenabled {
callerpc := getcallerpc(unsafe.Pointer(&t))
- pc := funcPC(mapassign1)
+ pc := funcPC(mapassign)
racewritepc(unsafe.Pointer(h), callerpc, pc)
raceReadObjectPC(t.key, key, callerpc, pc)
- raceReadObjectPC(t.elem, val, callerpc, pc)
}
if msanenabled {
msanread(key, t.key.size)
- msanread(val, t.elem.size)
}
if h.flags&hashWriting != 0 {
throw("concurrent map writes")
@@ -468,7 +509,7 @@ func mapassign1(t *maptype, h *hmap, key unsafe.Pointer, val unsafe.Pointer) {
again:
bucket := hash & (uintptr(1)<<h.B - 1)
- if h.oldbuckets != nil {
+ if h.growing() {
growWork(t, h, bucket)
}
b := (*bmap)(unsafe.Pointer(uintptr(h.buckets) + bucket*uintptr(t.bucketsize)))
@@ -479,35 +520,29 @@ again:
var inserti *uint8
var insertk unsafe.Pointer
- var insertv 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))
- insertv = add(unsafe.Pointer(b), dataOffset+bucketCnt*uintptr(t.keysize)+i*uintptr(t.valuesize))
+ val = add(unsafe.Pointer(b), dataOffset+bucketCnt*uintptr(t.keysize)+i*uintptr(t.valuesize))
}
continue
}
k := add(unsafe.Pointer(b), dataOffset+i*uintptr(t.keysize))
- k2 := k
if t.indirectkey {
- k2 = *((*unsafe.Pointer)(k2))
+ k = *((*unsafe.Pointer)(k))
}
- if !alg.equal(key, k2) {
+ if !alg.equal(key, k) {
continue
}
// already have a mapping for key. Update it.
if t.needkeyupdate {
- typedmemmove(t.key, k2, key)
+ typedmemmove(t.key, k, key)
}
- v := add(unsafe.Pointer(b), dataOffset+bucketCnt*uintptr(t.keysize)+i*uintptr(t.valuesize))
- v2 := v
- if t.indirectvalue {
- v2 = *((*unsafe.Pointer)(v2))
- }
- typedmemmove(t.elem, v2, val)
+ val = add(unsafe.Pointer(b), dataOffset+bucketCnt*uintptr(t.keysize)+i*uintptr(t.valuesize))
goto done
}
ovf := b.overflow(t)
@@ -517,8 +552,11 @@ again:
b = ovf
}
- // did not find mapping for key. Allocate new cell & add entry.
- if float32(h.count) >= loadFactor*float32((uintptr(1)<<h.B)) && h.count >= bucketCnt {
+ // 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
}
@@ -529,7 +567,7 @@ again:
h.setoverflow(t, b, newb)
inserti = &newb.tophash[0]
insertk = add(unsafe.Pointer(newb), dataOffset)
- insertv = add(insertk, bucketCnt*uintptr(t.keysize))
+ val = add(insertk, bucketCnt*uintptr(t.keysize))
}
// store new key/value at insert position
@@ -540,11 +578,9 @@ again:
}
if t.indirectvalue {
vmem := newobject(t.elem)
- *(*unsafe.Pointer)(insertv) = vmem
- insertv = vmem
+ *(*unsafe.Pointer)(val) = vmem
}
typedmemmove(t.key, insertk, key)
- typedmemmove(t.elem, insertv, val)
*inserti = top
h.count++
@@ -553,6 +589,10 @@ done:
throw("concurrent map writes")
}
h.flags &^= hashWriting
+ if t.indirectvalue {
+ val = *((*unsafe.Pointer)(val))
+ }
+ return val
}
func mapdelete(t *maptype, h *hmap, key unsafe.Pointer) {
@@ -576,7 +616,7 @@ func mapdelete(t *maptype, h *hmap, key unsafe.Pointer) {
alg := t.key.alg
hash := alg.hash(key, uintptr(h.hash0))
bucket := hash & (uintptr(1)<<h.B - 1)
- if h.oldbuckets != nil {
+ if h.growing() {
growWork(t, h, bucket)
}
b := (*bmap)(unsafe.Pointer(uintptr(h.buckets) + bucket*uintptr(t.bucketsize)))
@@ -597,9 +637,17 @@ func mapdelete(t *maptype, h *hmap, key unsafe.Pointer) {
if !alg.equal(key, k2) {
continue
}
- memclr(k, uintptr(t.keysize))
+ if t.indirectkey {
+ *(*unsafe.Pointer)(k) = nil
+ } else {
+ typedmemclr(t.key, k)
+ }
v := unsafe.Pointer(uintptr(unsafe.Pointer(b)) + dataOffset + bucketCnt*uintptr(t.keysize) + i*uintptr(t.valuesize))
- memclr(v, uintptr(t.valuesize))
+ if t.indirectvalue {
+ *(*unsafe.Pointer)(v) = nil
+ } else {
+ typedmemclr(t.elem, v)
+ }
b.tophash[i] = empty
h.count--
goto done
@@ -658,9 +706,9 @@ func mapiterinit(t *maptype, h *hmap, it *hiter) {
}
// decide where to start
- r := uintptr(fastrand1())
+ r := uintptr(fastrand())
if h.B > 31-bucketCntBits {
- r += uintptr(fastrand1()) << 31
+ r += uintptr(fastrand()) << 31
}
it.startBucket = r & (uintptr(1)<<h.B - 1)
it.offset = uint8(r >> h.B & (bucketCnt - 1))
@@ -685,6 +733,9 @@ func mapiternext(it *hiter) {
callerpc := getcallerpc(unsafe.Pointer(&it))
racereadpc(unsafe.Pointer(h), callerpc, funcPC(mapiternext))
}
+ if h.flags&hashWriting != 0 {
+ throw("concurrent map iteration and map write")
+ }
t := it.t
bucket := it.bucket
b := it.bptr
@@ -700,12 +751,12 @@ next:
it.value = nil
return
}
- if h.oldbuckets != nil && it.B == h.B {
+ if h.growing() && it.B == h.B {
// Iterator was started in the middle of a grow, and the grow isn't done yet.
// If the bucket we're looking at hasn't been filled in yet (i.e. the old
// bucket hasn't been evacuated) then we need to iterate through the old
// bucket and only return the ones that will be migrated to this bucket.
- oldbucket := bucket & (uintptr(1)<<(it.B-1) - 1)
+ oldbucket := bucket & it.h.oldbucketmask()
b = (*bmap)(add(h.oldbuckets, oldbucket*uintptr(t.bucketsize)))
if !evacuated(b) {
checkBucket = bucket
@@ -729,9 +780,9 @@ next:
k := add(unsafe.Pointer(b), dataOffset+uintptr(offi)*uintptr(t.keysize))
v := add(unsafe.Pointer(b), dataOffset+bucketCnt*uintptr(t.keysize)+uintptr(offi)*uintptr(t.valuesize))
if b.tophash[offi] != empty && b.tophash[offi] != evacuatedEmpty {
- if checkBucket != noCheck {
- // Special case: iterator was started during a grow and the
- // grow is not done yet. We're working on a bucket whose
+ if checkBucket != noCheck && !h.sameSizeGrow() {
+ // Special case: iterator was started during a grow to a larger size
+ // and the grow is not done yet. We're working on a bucket whose
// oldbucket has not been evacuated yet. Or at least, it wasn't
// evacuated when we started the bucket. So we're iterating
// through the oldbucket, skipping any keys that will go
@@ -817,21 +868,27 @@ next:
}
func hashGrow(t *maptype, h *hmap) {
- if h.oldbuckets != nil {
- throw("evacuation not done in time")
+ // If we've hit the load factor, get bigger.
+ // Otherwise, there are too many overflow buckets,
+ // so keep the same number of buckets and "grow" laterally.
+ bigger := uint8(1)
+ if !overLoadFactor(int64(h.count), h.B) {
+ bigger = 0
+ h.flags |= sameSizeGrow
}
oldbuckets := h.buckets
- newbuckets := newarray(t.bucket, 1<<(h.B+1))
+ newbuckets := newarray(t.bucket, 1<<(h.B+bigger))
flags := h.flags &^ (iterator | oldIterator)
if h.flags&iterator != 0 {
flags |= oldIterator
}
// commit the grow (atomic wrt gc)
- h.B++
+ h.B += bigger
h.flags = flags
h.oldbuckets = oldbuckets
h.buckets = newbuckets
h.nevacuate = 0
+ h.noverflow = 0
if h.overflow != nil {
// Promote current overflow buckets to the old generation.
@@ -846,35 +903,87 @@ func hashGrow(t *maptype, h *hmap) {
// by growWork() and evacuate().
}
-func growWork(t *maptype, h *hmap, bucket uintptr) {
- noldbuckets := uintptr(1) << (h.B - 1)
+// 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))
+}
+
+// tooManyOverflowBuckets reports whether noverflow buckets is too many for a map with 1<<B buckets.
+// Note that most of these overflow buckets must be in sparse use;
+// if use was dense, then we'd have already triggered regular map growth.
+func tooManyOverflowBuckets(noverflow uint16, B uint8) bool {
+ // If the threshold is too low, we do extraneous work.
+ // If the threshold is too high, maps that grow and shrink can hold on to lots of unused memory.
+ // "too many" means (approximately) as many overflow buckets as regular buckets.
+ // See incrnoverflow for more details.
+ if B < 16 {
+ return noverflow >= uint16(1)<<B
+ }
+ return noverflow >= 1<<15
+}
+
+// growing reports whether h is growing. The growth may be to the same size or bigger.
+func (h *hmap) growing() bool {
+ return h.oldbuckets != nil
+}
+
+// sameSizeGrow reports whether the current growth is to a map of the same size.
+func (h *hmap) sameSizeGrow() bool {
+ return h.flags&sameSizeGrow != 0
+}
+
+// noldbuckets calculates the number of buckets prior to the current map growth.
+func (h *hmap) noldbuckets() uintptr {
+ oldB := h.B
+ if !h.sameSizeGrow() {
+ oldB--
+ }
+ return uintptr(1) << oldB
+}
+
+// oldbucketmask provides a mask that can be applied to calculate n % noldbuckets().
+func (h *hmap) oldbucketmask() uintptr {
+ return h.noldbuckets() - 1
+}
+func growWork(t *maptype, h *hmap, bucket uintptr) {
// make sure we evacuate the oldbucket corresponding
// to the bucket we're about to use
- evacuate(t, h, bucket&(noldbuckets-1))
+ evacuate(t, h, bucket&h.oldbucketmask())
// evacuate one more oldbucket to make progress on growing
- if h.oldbuckets != nil {
+ if h.growing() {
evacuate(t, h, h.nevacuate)
}
}
func evacuate(t *maptype, h *hmap, oldbucket uintptr) {
b := (*bmap)(add(h.oldbuckets, oldbucket*uintptr(t.bucketsize)))
- newbit := uintptr(1) << (h.B - 1)
+ newbit := h.noldbuckets()
alg := t.key.alg
if !evacuated(b) {
// TODO: reuse overflow buckets instead of using new ones, if there
// is no iterator using the old buckets. (If !oldIterator.)
- x := (*bmap)(add(h.buckets, oldbucket*uintptr(t.bucketsize)))
- y := (*bmap)(add(h.buckets, (oldbucket+newbit)*uintptr(t.bucketsize)))
- xi := 0
- yi := 0
- xk := add(unsafe.Pointer(x), dataOffset)
- yk := add(unsafe.Pointer(y), dataOffset)
- xv := add(xk, bucketCnt*uintptr(t.keysize))
- yv := add(yk, bucketCnt*uintptr(t.keysize))
+ var (
+ x, y *bmap // current low/high buckets in new map
+ xi, yi int // key/val indices into x and y
+ xk, yk unsafe.Pointer // pointers to current x and y key storage
+ xv, yv unsafe.Pointer // pointers to current x and y value storage
+ )
+ x = (*bmap)(add(h.buckets, oldbucket*uintptr(t.bucketsize)))
+ xi = 0
+ xk = add(unsafe.Pointer(x), dataOffset)
+ xv = add(xk, bucketCnt*uintptr(t.keysize))
+ if !h.sameSizeGrow() {
+ // Only calculate y pointers if we're growing bigger.
+ // Otherwise GC can see bad pointers.
+ y = (*bmap)(add(h.buckets, (oldbucket+newbit)*uintptr(t.bucketsize)))
+ yi = 0
+ yk = add(unsafe.Pointer(y), dataOffset)
+ yv = add(yk, bucketCnt*uintptr(t.keysize))
+ }
for ; b != nil; b = b.overflow(t) {
k := add(unsafe.Pointer(b), dataOffset)
v := add(k, bucketCnt*uintptr(t.keysize))
@@ -891,34 +1000,38 @@ func evacuate(t *maptype, h *hmap, oldbucket uintptr) {
if t.indirectkey {
k2 = *((*unsafe.Pointer)(k2))
}
- // Compute hash to make our evacuation decision (whether we need
- // to send this key/value to bucket x or bucket y).
- hash := alg.hash(k2, uintptr(h.hash0))
- if h.flags&iterator != 0 {
- if !t.reflexivekey && !alg.equal(k2, k2) {
- // If key != key (NaNs), then the hash could be (and probably
- // will be) entirely different from the old hash. Moreover,
- // it isn't reproducible. Reproducibility is required in the
- // presence of iterators, as our evacuation decision must
- // match whatever decision the iterator made.
- // Fortunately, we have the freedom to send these keys either
- // way. Also, tophash is meaningless for these kinds of keys.
- // We let the low bit of tophash drive the evacuation decision.
- // We recompute a new random tophash for the next level so
- // these keys will get evenly distributed across all buckets
- // after multiple grows.
- if (top & 1) != 0 {
- hash |= newbit
- } else {
- hash &^= newbit
- }
- top = uint8(hash >> (sys.PtrSize*8 - 8))
- if top < minTopHash {
- top += minTopHash
+ useX := true
+ if !h.sameSizeGrow() {
+ // Compute hash to make our evacuation decision (whether we need
+ // to send this key/value to bucket x or bucket y).
+ hash := alg.hash(k2, uintptr(h.hash0))
+ if h.flags&iterator != 0 {
+ if !t.reflexivekey && !alg.equal(k2, k2) {
+ // If key != key (NaNs), then the hash could be (and probably
+ // will be) entirely different from the old hash. Moreover,
+ // it isn't reproducible. Reproducibility is required in the
+ // presence of iterators, as our evacuation decision must
+ // match whatever decision the iterator made.
+ // Fortunately, we have the freedom to send these keys either
+ // way. Also, tophash is meaningless for these kinds of keys.
+ // We let the low bit of tophash drive the evacuation decision.
+ // We recompute a new random tophash for the next level so
+ // these keys will get evenly distributed across all buckets
+ // after multiple grows.
+ if top&1 != 0 {
+ hash |= newbit
+ } else {
+ hash &^= newbit
+ }
+ top = uint8(hash >> (sys.PtrSize*8 - 8))
+ if top < minTopHash {
+ top += minTopHash
+ }
}
}
+ useX = hash&newbit == 0
}
- if (hash & newbit) == 0 {
+ if useX {
b.tophash[i] = evacuatedX
if xi == bucketCnt {
newx := (*bmap)(newobject(t.bucket))
@@ -972,7 +1085,13 @@ func evacuate(t *maptype, h *hmap, oldbucket uintptr) {
// Unlink the overflow buckets & clear key/value to help GC.
if h.flags&oldIterator == 0 {
b = (*bmap)(add(h.oldbuckets, oldbucket*uintptr(t.bucketsize)))
- memclr(add(unsafe.Pointer(b), dataOffset), uintptr(t.bucketsize)-dataOffset)
+ // Preserve b.tophash because the evacuation
+ // state is maintained there.
+ if t.bucket.kind&kindNoPointers == 0 {
+ memclrHasPointers(add(unsafe.Pointer(b), dataOffset), uintptr(t.bucketsize)-dataOffset)
+ } else {
+ memclrNoHeapPointers(add(unsafe.Pointer(b), dataOffset), uintptr(t.bucketsize)-dataOffset)
+ }
}
}
@@ -988,6 +1107,7 @@ func evacuate(t *maptype, h *hmap, oldbucket uintptr) {
if h.overflow != nil {
h.overflow[1] = nil
}
+ h.flags &^= sameSizeGrow
}
}
}
@@ -1015,7 +1135,8 @@ func reflect_mapaccess(t *maptype, h *hmap, key unsafe.Pointer) unsafe.Pointer {
//go:linkname reflect_mapassign reflect.mapassign
func reflect_mapassign(t *maptype, h *hmap, key unsafe.Pointer, val unsafe.Pointer) {
- mapassign1(t, h, key, val)
+ p := mapassign(t, h, key)
+ typedmemmove(t.elem, p, val)
}
//go:linkname reflect_mapdelete reflect.mapdelete
diff --git a/src/runtime/hashmap_fast.go b/src/runtime/hashmap_fast.go
index 8f9bb5a..b5ecc2d 100644
--- a/src/runtime/hashmap_fast.go
+++ b/src/runtime/hashmap_fast.go
@@ -29,7 +29,11 @@ func mapaccess1_fast32(t *maptype, h *hmap, key uint32) unsafe.Pointer {
m := uintptr(1)<<h.B - 1
b = (*bmap)(add(h.buckets, (hash&m)*uintptr(t.bucketsize)))
if c := h.oldbuckets; c != nil {
- oldb := (*bmap)(add(c, (hash&(m>>1))*uintptr(t.bucketsize)))
+ if !h.sameSizeGrow() {
+ // There used to be half as many buckets; mask down one more power of two.
+ m >>= 1
+ }
+ oldb := (*bmap)(add(c, (hash&m)*uintptr(t.bucketsize)))
if !evacuated(oldb) {
b = oldb
}
@@ -74,7 +78,11 @@ func mapaccess2_fast32(t *maptype, h *hmap, key uint32) (unsafe.Pointer, bool) {
m := uintptr(1)<<h.B - 1
b = (*bmap)(add(h.buckets, (hash&m)*uintptr(t.bucketsize)))
if c := h.oldbuckets; c != nil {
- oldb := (*bmap)(add(c, (hash&(m>>1))*uintptr(t.bucketsize)))
+ if !h.sameSizeGrow() {
+ // There used to be half as many buckets; mask down one more power of two.
+ m >>= 1
+ }
+ oldb := (*bmap)(add(c, (hash&m)*uintptr(t.bucketsize)))
if !evacuated(oldb) {
b = oldb
}
@@ -119,7 +127,11 @@ func mapaccess1_fast64(t *maptype, h *hmap, key uint64) unsafe.Pointer {
m := uintptr(1)<<h.B - 1
b = (*bmap)(add(h.buckets, (hash&m)*uintptr(t.bucketsize)))
if c := h.oldbuckets; c != nil {
- oldb := (*bmap)(add(c, (hash&(m>>1))*uintptr(t.bucketsize)))
+ if !h.sameSizeGrow() {
+ // There used to be half as many buckets; mask down one more power of two.
+ m >>= 1
+ }
+ oldb := (*bmap)(add(c, (hash&m)*uintptr(t.bucketsize)))
if !evacuated(oldb) {
b = oldb
}
@@ -164,7 +176,11 @@ func mapaccess2_fast64(t *maptype, h *hmap, key uint64) (unsafe.Pointer, bool) {
m := uintptr(1)<<h.B - 1
b = (*bmap)(add(h.buckets, (hash&m)*uintptr(t.bucketsize)))
if c := h.oldbuckets; c != nil {
- oldb := (*bmap)(add(c, (hash&(m>>1))*uintptr(t.bucketsize)))
+ if !h.sameSizeGrow() {
+ // There used to be half as many buckets; mask down one more power of two.
+ m >>= 1
+ }
+ oldb := (*bmap)(add(c, (hash&m)*uintptr(t.bucketsize)))
if !evacuated(oldb) {
b = oldb
}
@@ -264,7 +280,11 @@ dohash:
m := uintptr(1)<<h.B - 1
b := (*bmap)(add(h.buckets, (hash&m)*uintptr(t.bucketsize)))
if c := h.oldbuckets; c != nil {
- oldb := (*bmap)(add(c, (hash&(m>>1))*uintptr(t.bucketsize)))
+ if !h.sameSizeGrow() {
+ // There used to be half as many buckets; mask down one more power of two.
+ m >>= 1
+ }
+ oldb := (*bmap)(add(c, (hash&m)*uintptr(t.bucketsize)))
if !evacuated(oldb) {
b = oldb
}
@@ -367,7 +387,11 @@ dohash:
m := uintptr(1)<<h.B - 1
b := (*bmap)(add(h.buckets, (hash&m)*uintptr(t.bucketsize)))
if c := h.oldbuckets; c != nil {
- oldb := (*bmap)(add(c, (hash&(m>>1))*uintptr(t.bucketsize)))
+ if !h.sameSizeGrow() {
+ // There used to be half as many buckets; mask down one more power of two.
+ m >>= 1
+ }
+ oldb := (*bmap)(add(c, (hash&m)*uintptr(t.bucketsize)))
if !evacuated(oldb) {
b = oldb
}
diff --git a/src/runtime/heapdump.go b/src/runtime/heapdump.go
index c317b5f..6039417 100644
--- a/src/runtime/heapdump.go
+++ b/src/runtime/heapdump.go
@@ -437,9 +437,7 @@ func dumproots() {
dumpfields(firstmoduledata.gcbssmask)
// MSpan.types
- allspans := h_allspans
- for spanidx := uint32(0); spanidx < mheap_.nspan; spanidx++ {
- s := allspans[spanidx]
+ for _, s := range mheap_.allspans {
if s.state == _MSpanInUse {
// Finalizers
for sp := s.specials; sp != nil; sp = sp.next {
@@ -462,8 +460,7 @@ func dumproots() {
var freemark [_PageSize / 8]bool
func dumpobjs() {
- for i := uintptr(0); i < uintptr(mheap_.nspan); i++ {
- s := h_allspans[i]
+ for _, s := range mheap_.allspans {
if s.state != _MSpanInUse {
continue
}
@@ -474,7 +471,7 @@ func dumpobjs() {
throw("freemark array doesn't have enough entries")
}
- for freeIndex := s.freeindex; freeIndex < s.nelems; freeIndex++ {
+ for freeIndex := uintptr(0); freeIndex < s.nelems; freeIndex++ {
if s.isFree(freeIndex) {
freemark[freeIndex] = true
}
@@ -608,9 +605,7 @@ func dumpmemprof_callback(b *bucket, nstk uintptr, pstk *uintptr, size, allocs,
func dumpmemprof() {
iterate_memprof(dumpmemprof_callback)
- allspans := h_allspans
- for spanidx := uint32(0); spanidx < mheap_.nspan; spanidx++ {
- s := allspans[spanidx]
+ for _, s := range mheap_.allspans {
if s.state != _MSpanInUse {
continue
}
@@ -631,13 +626,12 @@ var dumphdr = []byte("go1.7 heap dump\n")
func mdump() {
// make sure we're done sweeping
- for i := uintptr(0); i < uintptr(mheap_.nspan); i++ {
- s := h_allspans[i]
+ for _, s := range mheap_.allspans {
if s.state == _MSpanInUse {
s.ensureSwept()
}
}
- memclr(unsafe.Pointer(&typecache), unsafe.Sizeof(typecache))
+ memclrNoHeapPointers(unsafe.Pointer(&typecache), unsafe.Sizeof(typecache))
dwrite(unsafe.Pointer(&dumphdr[0]), uintptr(len(dumphdr)))
dumpparams()
dumpitabs()
diff --git a/src/runtime/iface.go b/src/runtime/iface.go
index 1690147..c932e14 100644
--- a/src/runtime/iface.go
+++ b/src/runtime/iface.go
@@ -138,21 +138,53 @@ func additab(m *itab, locked, canfail bool) {
throw("invalid itab locking")
}
h := itabhash(inter, typ)
+ if m == hash[h] {
+ println("duplicate itab for", typ.string(), "and", inter.typ.string())
+ throw("duplicate itabs")
+ }
m.link = hash[h]
atomicstorep(unsafe.Pointer(&hash[h]), unsafe.Pointer(m))
}
func itabsinit() {
lock(&ifaceLock)
- for m := &firstmoduledata; m != nil; m = m.next {
- for _, i := range m.itablinks {
+ for _, md := range activeModules() {
+ for _, i := range md.itablinks {
additab(i, true, false)
}
}
unlock(&ifaceLock)
}
-func convT2E(t *_type, elem unsafe.Pointer, x unsafe.Pointer) (e eface) {
+// panicdottype is called when doing an i.(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) {
+ haveString := ""
+ if have != nil {
+ haveString = have.string()
+ }
+ panic(&TypeAssertionError{iface.string(), haveString, want.string(), ""})
+}
+
+// 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) {
+ panic(&TypeAssertionError{"", "", want.string(), ""})
+ // TODO: Add the static type we're converting from as well.
+ // It might generate a better error message.
+ // Just to match other nil conversion errors, we don't for now.
+}
+
+// The conv and assert functions below do very similar things.
+// The convXXX functions are guaranteed by the compiler to succeed.
+// The assertXXX functions may fail (either panicing or returning false,
+// depending on whether they are 1-result or 2-result).
+// The convXXX functions succeed on a nil input, whereas the assertXXX
+// functions fail on a nil input.
+
+func convT2E(t *_type, elem unsafe.Pointer) (e eface) {
if raceenabled {
raceReadObjectPC(t, elem, getcallerpc(unsafe.Pointer(&t)), funcPC(convT2E))
}
@@ -160,20 +192,19 @@ func convT2E(t *_type, elem unsafe.Pointer, x unsafe.Pointer) (e eface) {
msanread(elem, t.size)
}
if isDirectIface(t) {
+ // This case is implemented directly by the compiler.
throw("direct convT2E")
}
- if x == nil {
- x = newobject(t)
- // TODO: We allocate a zeroed object only to overwrite it with
- // actual data. Figure out how to avoid zeroing. Also below in convT2I.
- }
+ x := newobject(t)
+ // TODO: We allocate a zeroed object only to overwrite it with
+ // actual data. Figure out how to avoid zeroing. Also below in convT2I.
typedmemmove(t, x, elem)
e._type = t
e.data = x
return
}
-func convT2I(tab *itab, elem unsafe.Pointer, x unsafe.Pointer) (i iface) {
+func convT2I(tab *itab, elem unsafe.Pointer) (i iface) {
t := tab._type
if raceenabled {
raceReadObjectPC(t, elem, getcallerpc(unsafe.Pointer(&tab)), funcPC(convT2I))
@@ -182,127 +213,16 @@ func convT2I(tab *itab, elem unsafe.Pointer, x unsafe.Pointer) (i iface) {
msanread(elem, t.size)
}
if isDirectIface(t) {
+ // This case is implemented directly by the compiler.
throw("direct convT2I")
}
- if x == nil {
- x = newobject(t)
- }
+ x := newobject(t)
typedmemmove(t, x, elem)
i.tab = tab
i.data = x
return
}
-func panicdottype(have, want, iface *_type) {
- haveString := ""
- if have != nil {
- haveString = have.string()
- }
- panic(&TypeAssertionError{iface.string(), haveString, want.string(), ""})
-}
-
-func assertI2T(t *_type, i iface, r unsafe.Pointer) {
- tab := i.tab
- if tab == nil {
- panic(&TypeAssertionError{"", "", t.string(), ""})
- }
- if tab._type != t {
- panic(&TypeAssertionError{tab.inter.typ.string(), tab._type.string(), t.string(), ""})
- }
- if r != nil {
- if isDirectIface(t) {
- writebarrierptr((*uintptr)(r), uintptr(i.data))
- } else {
- typedmemmove(t, r, i.data)
- }
- }
-}
-
-func assertI2T2(t *_type, i iface, r unsafe.Pointer) bool {
- tab := i.tab
- if tab == nil || tab._type != t {
- if r != nil {
- memclr(r, t.size)
- }
- return false
- }
- if r != nil {
- if isDirectIface(t) {
- writebarrierptr((*uintptr)(r), uintptr(i.data))
- } else {
- typedmemmove(t, r, i.data)
- }
- }
- return true
-}
-
-func assertE2T(t *_type, e eface, r unsafe.Pointer) {
- if e._type == nil {
- panic(&TypeAssertionError{"", "", t.string(), ""})
- }
- if e._type != t {
- panic(&TypeAssertionError{"", e._type.string(), t.string(), ""})
- }
- if r != nil {
- if isDirectIface(t) {
- writebarrierptr((*uintptr)(r), uintptr(e.data))
- } else {
- typedmemmove(t, r, e.data)
- }
- }
-}
-
-var testingAssertE2T2GC bool
-
-// The compiler ensures that r is non-nil.
-func assertE2T2(t *_type, e eface, r unsafe.Pointer) bool {
- if testingAssertE2T2GC {
- GC()
- }
- if e._type != t {
- memclr(r, t.size)
- return false
- }
- if isDirectIface(t) {
- writebarrierptr((*uintptr)(r), uintptr(e.data))
- } else {
- typedmemmove(t, r, e.data)
- }
- return true
-}
-
-func convI2E(i iface) (r eface) {
- tab := i.tab
- if tab == nil {
- return
- }
- r._type = tab._type
- r.data = i.data
- return
-}
-
-func assertI2E(inter *interfacetype, i iface, r *eface) {
- tab := i.tab
- if tab == nil {
- // explicit conversions require non-nil interface value.
- panic(&TypeAssertionError{"", "", inter.typ.string(), ""})
- }
- r._type = tab._type
- r.data = i.data
- return
-}
-
-// The compiler ensures that r is non-nil.
-func assertI2E2(inter *interfacetype, i iface, r *eface) bool {
- tab := i.tab
- if tab == nil {
- return false
- }
- r._type = tab._type
- r.data = i.data
- return true
-}
-
func convI2I(inter *interfacetype, i iface) (r iface) {
tab := i.tab
if tab == nil {
@@ -318,7 +238,7 @@ func convI2I(inter *interfacetype, i iface) (r iface) {
return
}
-func assertI2I(inter *interfacetype, i iface, r *iface) {
+func assertI2I(inter *interfacetype, i iface) (r iface) {
tab := i.tab
if tab == nil {
// explicit conversions require non-nil interface value.
@@ -331,33 +251,27 @@ func assertI2I(inter *interfacetype, i iface, r *iface) {
}
r.tab = getitab(inter, tab._type, false)
r.data = i.data
+ return
}
-func assertI2I2(inter *interfacetype, i iface, r *iface) bool {
+func assertI2I2(inter *interfacetype, i iface) (r iface, b bool) {
tab := i.tab
if tab == nil {
- if r != nil {
- *r = iface{}
- }
- return false
+ return
}
if tab.inter != inter {
tab = getitab(inter, tab._type, true)
if tab == nil {
- if r != nil {
- *r = iface{}
- }
- return false
+ return
}
}
- if r != nil {
- r.tab = tab
- r.data = i.data
- }
- return true
+ r.tab = tab
+ r.data = i.data
+ b = true
+ return
}
-func assertE2I(inter *interfacetype, e eface, r *iface) {
+func assertE2I(inter *interfacetype, e eface) (r iface) {
t := e._type
if t == nil {
// explicit conversions require non-nil interface value.
@@ -365,56 +279,27 @@ func assertE2I(inter *interfacetype, e eface, r *iface) {
}
r.tab = getitab(inter, t, false)
r.data = e.data
+ return
}
-var testingAssertE2I2GC bool
-
-func assertE2I2(inter *interfacetype, e eface, r *iface) bool {
- if testingAssertE2I2GC {
- GC()
- }
+func assertE2I2(inter *interfacetype, e eface) (r iface, b bool) {
t := e._type
if t == nil {
- if r != nil {
- *r = iface{}
- }
- return false
+ return
}
tab := getitab(inter, t, true)
if tab == nil {
- if r != nil {
- *r = iface{}
- }
- return false
- }
- if r != nil {
- r.tab = tab
- r.data = e.data
+ return
}
- return true
+ r.tab = tab
+ r.data = e.data
+ b = true
+ return
}
//go:linkname reflect_ifaceE2I reflect.ifaceE2I
func reflect_ifaceE2I(inter *interfacetype, e eface, dst *iface) {
- assertE2I(inter, e, dst)
-}
-
-func assertE2E(inter *interfacetype, e eface, r *eface) {
- if e._type == nil {
- // explicit conversions require non-nil interface value.
- panic(&TypeAssertionError{"", "", inter.typ.string(), ""})
- }
- *r = e
-}
-
-// The compiler ensures that r is non-nil.
-func assertE2E2(inter *interfacetype, e eface, r *eface) bool {
- if e._type == nil {
- *r = eface{}
- return false
- }
- *r = e
- return true
+ *dst = assertE2I(inter, e)
}
func iterate_itabs(fn func(*itab)) {
diff --git a/src/runtime/internal/atomic/asm.s b/src/runtime/internal/atomic/asm.s
deleted file mode 100644
index 8488585..0000000
--- a/src/runtime/internal/atomic/asm.s
+++ /dev/null
@@ -1,8 +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 "textflag.h"
-
-TEXT runtime∕internal∕atomic·nop(SB),NOSPLIT,$0-0
- RET
diff --git a/src/runtime/internal/atomic/asm_386.s b/src/runtime/internal/atomic/asm_386.s
index 357d830..882906e 100644
--- a/src/runtime/internal/atomic/asm_386.s
+++ b/src/runtime/internal/atomic/asm_386.s
@@ -52,6 +52,9 @@ TEXT runtime∕internal∕atomic·Xaddint64(SB), NOSPLIT, $0-20
// }
TEXT runtime∕internal∕atomic·Cas64(SB), NOSPLIT, $0-21
MOVL ptr+0(FP), BP
+ TESTL $7, BP
+ JZ 2(PC)
+ MOVL 0, BP // crash with nil ptr deref
MOVL old_lo+4(FP), AX
MOVL old_hi+8(FP), DX
MOVL new_lo+12(FP), BX
@@ -61,7 +64,7 @@ TEXT runtime∕internal∕atomic·Cas64(SB), NOSPLIT, $0-21
SETEQ ret+20(FP)
RET
-// bool Casp(void **p, void *old, void *new)
+// bool Casp1(void **p, void *old, void *new)
// Atomically:
// if(*p == old){
// *p = new;
diff --git a/src/runtime/internal/atomic/asm_amd64.s b/src/runtime/internal/atomic/asm_amd64.s
index 0001d23..6fb5211 100644
--- a/src/runtime/internal/atomic/asm_amd64.s
+++ b/src/runtime/internal/atomic/asm_amd64.s
@@ -2,6 +2,9 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// Note: some of these functions are semantically inlined
+// by the compiler (in src/cmd/compile/internal/gc/ssa.go).
+
#include "textflag.h"
// bool Cas(int32 *val, int32 old, int32 new)
@@ -55,7 +58,7 @@ TEXT runtime∕internal∕atomic·Loadint64(SB), NOSPLIT, $0-16
TEXT runtime∕internal∕atomic·Xaddint64(SB), NOSPLIT, $0-24
JMP runtime∕internal∕atomic·Xadd64(SB)
-// bool Casp(void **val, void *old, void *new)
+// bool Casp1(void **val, void *old, void *new)
// Atomically:
// if(*val == old){
// *val = new;
diff --git a/src/runtime/internal/atomic/asm_amd64p32.s b/src/runtime/internal/atomic/asm_amd64p32.s
index 22c707c..87f7a07 100644
--- a/src/runtime/internal/atomic/asm_amd64p32.s
+++ b/src/runtime/internal/atomic/asm_amd64p32.s
@@ -55,7 +55,7 @@ TEXT runtime∕internal∕atomic·Cas64(SB), NOSPLIT, $0-25
SETEQ ret+24(FP)
RET
-// bool Casp(void **val, void *old, void *new)
+// bool Casp1(void **val, void *old, void *new)
// Atomically:
// if(*val == old){
// *val = new;
diff --git a/src/runtime/internal/atomic/asm_arm.s b/src/runtime/internal/atomic/asm_arm.s
index 12da223..5e2380e 100644
--- a/src/runtime/internal/atomic/asm_arm.s
+++ b/src/runtime/internal/atomic/asm_arm.s
@@ -19,7 +19,7 @@
// B runtime∕internal∕atomic·armcas(SB)
//
TEXT runtime∕internal∕atomic·armcas(SB),NOSPLIT,$0-13
- MOVW valptr+0(FP), R1
+ MOVW ptr+0(FP), R1
MOVW old+4(FP), R2
MOVW new+8(FP), R3
casl:
diff --git a/src/runtime/internal/atomic/asm_arm64.s b/src/runtime/internal/atomic/asm_arm64.s
index 929bf71..b6af632 100644
--- a/src/runtime/internal/atomic/asm_arm64.s
+++ b/src/runtime/internal/atomic/asm_arm64.s
@@ -47,7 +47,7 @@ TEXT runtime∕internal∕atomic·Loadint64(SB), NOSPLIT, $0-16
TEXT runtime∕internal∕atomic·Xaddint64(SB), NOSPLIT, $0-24
B runtime∕internal∕atomic·Xadd64(SB)
-// bool Casp(void **val, void *old, void *new)
+// bool Casp1(void **val, void *old, void *new)
// Atomically:
// if(*val == old){
// *val = new;
diff --git a/src/runtime/internal/atomic/asm_mipsx.s b/src/runtime/internal/atomic/asm_mipsx.s
new file mode 100644
index 0000000..30550fd
--- /dev/null
+++ b/src/runtime/internal/atomic/asm_mipsx.s
@@ -0,0 +1,149 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build mips mipsle
+
+#include "textflag.h"
+
+TEXT ·Cas(SB),NOSPLIT,$0-13
+ MOVW ptr+0(FP), R1
+ MOVW old+4(FP), R2
+ MOVW new+8(FP), R5
+ SYNC
+try_cas:
+ MOVW R5, R3
+ LL (R1), R4 // R4 = *R1
+ BNE R2, R4, cas_fail
+ SC R3, (R1) // *R1 = R3
+ BEQ R3, try_cas
+ SYNC
+ MOVB R3, ret+12(FP)
+ RET
+cas_fail:
+ MOVB R0, ret+12(FP)
+ RET
+
+TEXT ·Store(SB),NOSPLIT,$0-8
+ MOVW ptr+0(FP), R1
+ MOVW val+4(FP), R2
+ SYNC
+ MOVW R2, 0(R1)
+ SYNC
+ RET
+
+TEXT ·Load(SB),NOSPLIT,$0-8
+ MOVW ptr+0(FP), R1
+ SYNC
+ MOVW 0(R1), R1
+ SYNC
+ MOVW R1, ret+4(FP)
+ RET
+
+TEXT ·Xadd(SB),NOSPLIT,$0-12
+ MOVW ptr+0(FP), R2
+ MOVW delta+4(FP), R3
+ SYNC
+try_xadd:
+ LL (R2), R1 // R1 = *R2
+ ADDU R1, R3, R4
+ MOVW R4, R1
+ SC R4, (R2) // *R2 = R4
+ BEQ R4, try_xadd
+ SYNC
+ MOVW R1, ret+8(FP)
+ RET
+
+TEXT ·Xchg(SB),NOSPLIT,$0-12
+ MOVW ptr+0(FP), R2
+ MOVW new+4(FP), R5
+ SYNC
+try_xchg:
+ MOVW R5, R3
+ LL (R2), R1 // R1 = *R2
+ SC R3, (R2) // *R2 = R3
+ BEQ R3, try_xchg
+ SYNC
+ MOVW R1, ret+8(FP)
+ RET
+
+TEXT ·Casuintptr(SB),NOSPLIT,$0-13
+ JMP ·Cas(SB)
+
+TEXT ·Loaduintptr(SB),NOSPLIT,$0-8
+ JMP ·Load(SB)
+
+TEXT ·Loaduint(SB),NOSPLIT,$0-8
+ JMP ·Load(SB)
+
+TEXT ·Loadp(SB),NOSPLIT,$-0-8
+ JMP ·Load(SB)
+
+TEXT ·Storeuintptr(SB),NOSPLIT,$0-8
+ JMP ·Store(SB)
+
+TEXT ·Xadduintptr(SB),NOSPLIT,$0-12
+ JMP ·Xadd(SB)
+
+TEXT ·Loadint64(SB),NOSPLIT,$0-12
+ JMP ·Load64(SB)
+
+TEXT ·Xaddint64(SB),NOSPLIT,$0-20
+ JMP ·Xadd64(SB)
+
+TEXT ·Casp1(SB),NOSPLIT,$0-13
+ JMP ·Cas(SB)
+
+TEXT ·Xchguintptr(SB),NOSPLIT,$0-12
+ JMP ·Xchg(SB)
+
+TEXT ·StorepNoWB(SB),NOSPLIT,$0-8
+ JMP ·Store(SB)
+
+// void Or8(byte volatile*, byte);
+TEXT ·Or8(SB),NOSPLIT,$0-5
+ MOVW ptr+0(FP), R1
+ MOVBU val+4(FP), R2
+ MOVW $~3, R3 // Align ptr down to 4 bytes so we can use 32-bit load/store.
+ AND R1, R3
+#ifdef GOARCH_mips
+ // Big endian. ptr = ptr ^ 3
+ XOR $3, R1
+#endif
+ AND $3, R1, R4 // R4 = ((ptr & 3) * 8)
+ SLL $3, R4
+ SLL R4, R2, R2 // Shift val for aligned ptr. R2 = val << R4
+ SYNC
+try_or8:
+ LL (R3), R4 // R4 = *R3
+ OR R2, R4
+ SC R4, (R3) // *R3 = R4
+ BEQ R4, try_or8
+ SYNC
+ RET
+
+// void And8(byte volatile*, byte);
+TEXT ·And8(SB),NOSPLIT,$0-5
+ MOVW ptr+0(FP), R1
+ MOVBU val+4(FP), R2
+ MOVW $~3, R3
+ AND R1, R3
+#ifdef GOARCH_mips
+ // Big endian. ptr = ptr ^ 3
+ XOR $3, R1
+#endif
+ AND $3, R1, R4 // R4 = ((ptr & 3) * 8)
+ SLL $3, R4
+ MOVW $0xFF, R5
+ SLL R4, R2
+ SLL R4, R5
+ NOR R0, R5
+ OR R5, R2 // Shift val for aligned ptr. R2 = val << R4 | ^(0xFF << R4)
+ SYNC
+try_and8:
+ LL (R3), R4 // R4 = *R3
+ AND R2, R4
+ SC R4, (R3) // *R3 = R4
+ BEQ R4, try_and8
+ SYNC
+ RET
diff --git a/src/runtime/internal/atomic/asm_s390x.s b/src/runtime/internal/atomic/asm_s390x.s
index c84718c..e25703e 100644
--- a/src/runtime/internal/atomic/asm_s390x.s
+++ b/src/runtime/internal/atomic/asm_s390x.s
@@ -69,7 +69,7 @@ TEXT ·Xadduintptr(SB), NOSPLIT, $0-24
BR ·Xadd64(SB)
// func Xaddint64(ptr *int64, delta int64) int64
-TEXT ·Xaddint64(SB), NOSPLIT, $0-16
+TEXT ·Xaddint64(SB), NOSPLIT, $0-24
BR ·Xadd64(SB)
// func Casp1(ptr *unsafe.Pointer, old, new unsafe.Pointer) bool
@@ -141,7 +141,8 @@ TEXT ·Or8(SB), NOSPLIT, $0-9
MOVD ptr+0(FP), R3
MOVBZ val+8(FP), R4
// Calculate shift.
- AND $3, R3, R5
+ MOVD R3, R5
+ AND $3, R5
XOR $3, R5 // big endian - flip direction
SLD $3, R5 // MUL $8, R5
SLD R5, R4
@@ -159,7 +160,8 @@ TEXT ·And8(SB), NOSPLIT, $0-9
MOVD ptr+0(FP), R3
MOVBZ val+8(FP), R4
// Calculate shift.
- AND $3, R3, R5
+ MOVD R3, R5
+ AND $3, R5
XOR $3, R5 // big endian - flip direction
SLD $3, R5 // MUL $8, R5
OR $-256, R4 // create 0xffffffffffffffxx
diff --git a/src/runtime/internal/atomic/atomic_arm.go b/src/runtime/internal/atomic/atomic_arm.go
index 244237d..72af584 100644
--- a/src/runtime/internal/atomic/atomic_arm.go
+++ b/src/runtime/internal/atomic/atomic_arm.go
@@ -106,6 +106,9 @@ func Store(addr *uint32, v uint32) {
//go:nosplit
func Cas64(addr *uint64, old, new uint64) bool {
+ if uintptr(unsafe.Pointer(addr))&7 != 0 {
+ *(*int)(nil) = 0 // crash on unaligned uint64
+ }
var ok bool
addrLock(addr).lock()
if *addr == old {
@@ -118,6 +121,9 @@ func Cas64(addr *uint64, old, new uint64) bool {
//go:nosplit
func Xadd64(addr *uint64, delta int64) uint64 {
+ if uintptr(unsafe.Pointer(addr))&7 != 0 {
+ *(*int)(nil) = 0 // crash on unaligned uint64
+ }
var r uint64
addrLock(addr).lock()
r = *addr + uint64(delta)
@@ -128,6 +134,9 @@ func Xadd64(addr *uint64, delta int64) uint64 {
//go:nosplit
func Xchg64(addr *uint64, v uint64) uint64 {
+ if uintptr(unsafe.Pointer(addr))&7 != 0 {
+ *(*int)(nil) = 0 // crash on unaligned uint64
+ }
var r uint64
addrLock(addr).lock()
r = *addr
@@ -138,6 +147,9 @@ func Xchg64(addr *uint64, v uint64) uint64 {
//go:nosplit
func Load64(addr *uint64) uint64 {
+ if uintptr(unsafe.Pointer(addr))&7 != 0 {
+ *(*int)(nil) = 0 // crash on unaligned uint64
+ }
var r uint64
addrLock(addr).lock()
r = *addr
@@ -147,6 +159,9 @@ func Load64(addr *uint64) uint64 {
//go:nosplit
func Store64(addr *uint64, v uint64) {
+ if uintptr(unsafe.Pointer(addr))&7 != 0 {
+ *(*int)(nil) = 0 // crash on unaligned uint64
+ }
addrLock(addr).lock()
*addr = v
addrLock(addr).unlock()
@@ -181,3 +196,6 @@ func And8(addr *uint8, v uint8) {
}
}
}
+
+//go:nosplit
+func armcas(ptr *uint32, old, new uint32) bool
diff --git a/src/runtime/internal/atomic/atomic_arm64.go b/src/runtime/internal/atomic/atomic_arm64.go
index dc82c33..3554b7f 100644
--- a/src/runtime/internal/atomic/atomic_arm64.go
+++ b/src/runtime/internal/atomic/atomic_arm64.go
@@ -35,37 +35,11 @@ func Load64(ptr *uint64) uint64
//go:noescape
func Loadp(ptr unsafe.Pointer) unsafe.Pointer
-//go:nosplit
-func Or8(addr *uint8, v uint8) {
- // TODO(dfc) implement this in asm.
- // Align down to 4 bytes and use 32-bit CAS.
- uaddr := uintptr(unsafe.Pointer(addr))
- addr32 := (*uint32)(unsafe.Pointer(uaddr &^ 3))
- word := uint32(v) << ((uaddr & 3) * 8) // little endian
- for {
- old := *addr32
- if Cas(addr32, old, old|word) {
- return
- }
- }
-}
-
-//go:nosplit
-func And8(addr *uint8, v uint8) {
- // TODO(dfc) implement this in asm.
- // Align down to 4 bytes and use 32-bit CAS.
- uaddr := uintptr(unsafe.Pointer(addr))
- addr32 := (*uint32)(unsafe.Pointer(uaddr &^ 3))
- word := uint32(v) << ((uaddr & 3) * 8) // little endian
- mask := uint32(0xFF) << ((uaddr & 3) * 8) // little endian
- word |= ^mask
- for {
- old := *addr32
- if Cas(addr32, old, old&word) {
- return
- }
- }
-}
+//go:noescape
+func Or8(ptr *uint8, val uint8)
+
+//go:noescape
+func And8(ptr *uint8, val uint8)
//go:noescape
func Cas64(ptr *uint64, old, new uint64) bool
diff --git a/src/runtime/internal/atomic/atomic_arm64.s b/src/runtime/internal/atomic/atomic_arm64.s
index eb32f37..6c2031c 100644
--- a/src/runtime/internal/atomic/atomic_arm64.s
+++ b/src/runtime/internal/atomic/atomic_arm64.s
@@ -111,3 +111,22 @@ again:
TEXT runtime∕internal∕atomic·Xchguintptr(SB), NOSPLIT, $0-24
B runtime∕internal∕atomic·Xchg64(SB)
+
+TEXT ·And8(SB), NOSPLIT, $0-9
+ MOVD ptr+0(FP), R0
+ MOVB val+8(FP), R1
+ LDAXRB (R0), R2
+ AND R1, R2
+ STLXRB R2, (R0), R3
+ CBNZ R3, -3(PC)
+ RET
+
+TEXT ·Or8(SB), NOSPLIT, $0-9
+ MOVD ptr+0(FP), R0
+ MOVB val+8(FP), R1
+ LDAXRB (R0), R2
+ ORR R1, R2
+ STLXRB R2, (R0), R3
+ CBNZ R3, -3(PC)
+ RET
+
diff --git a/src/runtime/internal/atomic/atomic_mipsx.go b/src/runtime/internal/atomic/atomic_mipsx.go
new file mode 100644
index 0000000..93a1f1a
--- /dev/null
+++ b/src/runtime/internal/atomic/atomic_mipsx.go
@@ -0,0 +1,132 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build mips mipsle
+
+package atomic
+
+import (
+ "runtime/internal/sys"
+ "unsafe"
+)
+
+// TODO implement lock striping
+var lock struct {
+ state uint32
+ pad [sys.CacheLineSize - 4]byte
+}
+
+//go:noescape
+func spinLock(state *uint32)
+
+//go:noescape
+func spinUnlock(state *uint32)
+
+//go:nosplit
+func lockAndCheck(addr *uint64) {
+ // ensure 8-byte alignement
+ if uintptr(unsafe.Pointer(addr))&7 != 0 {
+ addr = nil
+ }
+ // force dereference before taking lock
+ _ = *addr
+
+ spinLock(&lock.state)
+}
+
+//go:nosplit
+func unlock() {
+ spinUnlock(&lock.state)
+}
+
+//go:nosplit
+func unlockNoFence() {
+ lock.state = 0
+}
+
+//go:nosplit
+func Xadd64(addr *uint64, delta int64) (new uint64) {
+ lockAndCheck(addr)
+
+ new = *addr + uint64(delta)
+ *addr = new
+
+ unlock()
+ return
+}
+
+//go:nosplit
+func Xchg64(addr *uint64, new uint64) (old uint64) {
+ lockAndCheck(addr)
+
+ old = *addr
+ *addr = new
+
+ unlock()
+ return
+}
+
+//go:nosplit
+func Cas64(addr *uint64, old, new uint64) (swapped bool) {
+ lockAndCheck(addr)
+
+ if (*addr) == old {
+ *addr = new
+ unlock()
+ return true
+ }
+
+ unlockNoFence()
+ return false
+}
+
+//go:nosplit
+func Load64(addr *uint64) (val uint64) {
+ lockAndCheck(addr)
+
+ val = *addr
+
+ unlock()
+ return
+}
+
+//go:nosplit
+func Store64(addr *uint64, val uint64) {
+ lockAndCheck(addr)
+
+ *addr = val
+
+ unlock()
+ return
+}
+
+//go:noescape
+func Xadd(ptr *uint32, delta int32) uint32
+
+//go:noescape
+func Xadduintptr(ptr *uintptr, delta uintptr) uintptr
+
+//go:noescape
+func Xchg(ptr *uint32, new uint32) uint32
+
+//go:noescape
+func Xchguintptr(ptr *uintptr, new uintptr) uintptr
+
+//go:noescape
+func Load(ptr *uint32) uint32
+
+//go:noescape
+func Loadp(ptr unsafe.Pointer) unsafe.Pointer
+
+//go:noescape
+func And8(ptr *uint8, val uint8)
+
+//go:noescape
+func Or8(ptr *uint8, val uint8)
+
+//go:noescape
+func Store(ptr *uint32, val uint32)
+
+// NO go:noescape annotation; see atomic_pointer.go.
+func StorepNoWB(ptr unsafe.Pointer, val unsafe.Pointer)
diff --git a/src/runtime/internal/atomic/atomic_mipsx.s b/src/runtime/internal/atomic/atomic_mipsx.s
new file mode 100644
index 0000000..aeebc8f
--- /dev/null
+++ b/src/runtime/internal/atomic/atomic_mipsx.s
@@ -0,0 +1,28 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build mips mipsle
+
+#include "textflag.h"
+
+TEXT ·spinLock(SB),NOSPLIT,$0-4
+ MOVW state+0(FP), R1
+ MOVW $1, R2
+ SYNC
+try_lock:
+ MOVW R2, R3
+check_again:
+ LL (R1), R4
+ BNE R4, check_again
+ SC R3, (R1)
+ BEQ R3, try_lock
+ SYNC
+ RET
+
+TEXT ·spinUnlock(SB),NOSPLIT,$0-4
+ MOVW state+0(FP), R1
+ SYNC
+ MOVW R0, (R1)
+ SYNC
+ RET
diff --git a/src/runtime/internal/atomic/atomic_ppc64x.s b/src/runtime/internal/atomic/atomic_ppc64x.s
index 1a7537e..c9c2d1f 100644
--- a/src/runtime/internal/atomic/atomic_ppc64x.s
+++ b/src/runtime/internal/atomic/atomic_ppc64x.s
@@ -6,9 +6,9 @@
#include "textflag.h"
-// uint32 runtime∕internal∕atomic·Load(uint32 volatile* addr)
+// uint32 runtime∕internal∕atomic·Load(uint32 volatile* ptr)
TEXT ·Load(SB),NOSPLIT|NOFRAME,$-8-12
- MOVD addr+0(FP), R3
+ MOVD ptr+0(FP), R3
SYNC
MOVWZ 0(R3), R3
CMPW R3, R3, CR7
@@ -17,9 +17,9 @@ TEXT ·Load(SB),NOSPLIT|NOFRAME,$-8-12
MOVW R3, ret+8(FP)
RET
-// uint64 runtime∕internal∕atomic·Load64(uint64 volatile* addr)
+// uint64 runtime∕internal∕atomic·Load64(uint64 volatile* ptr)
TEXT ·Load64(SB),NOSPLIT|NOFRAME,$-8-16
- MOVD addr+0(FP), R3
+ MOVD ptr+0(FP), R3
SYNC
MOVD 0(R3), R3
CMP R3, R3, CR7
@@ -28,9 +28,9 @@ TEXT ·Load64(SB),NOSPLIT|NOFRAME,$-8-16
MOVD R3, ret+8(FP)
RET
-// void *runtime∕internal∕atomic·Loadp(void *volatile *addr)
+// void *runtime∕internal∕atomic·Loadp(void *volatile *ptr)
TEXT ·Loadp(SB),NOSPLIT|NOFRAME,$-8-16
- MOVD addr+0(FP), R3
+ MOVD ptr+0(FP), R3
SYNC
MOVD 0(R3), R3
CMP R3, R3, CR7
diff --git a/src/runtime/internal/atomic/atomic_test.go b/src/runtime/internal/atomic/atomic_test.go
index d5dc552..879a82f 100644
--- a/src/runtime/internal/atomic/atomic_test.go
+++ b/src/runtime/internal/atomic/atomic_test.go
@@ -7,6 +7,7 @@ package atomic_test
import (
"runtime"
"runtime/internal/atomic"
+ "runtime/internal/sys"
"testing"
"unsafe"
)
@@ -51,13 +52,13 @@ func TestXadduintptr(t *testing.T) {
// Tests that xadduintptr correctly updates 64-bit values. The place where
// we actually do so is mstats.go, functions mSysStat{Inc,Dec}.
func TestXadduintptrOnUint64(t *testing.T) {
- /* if runtime.BigEndian != 0 {
+ if sys.BigEndian != 0 {
// On big endian architectures, we never use xadduintptr to update
// 64-bit values and hence we skip the test. (Note that functions
// mSysStat{Inc,Dec} in mstats.go have explicit checks for
// big-endianness.)
- return
- }*/
+ t.Skip("skip xadduintptr on big endian architecture")
+ }
const inc = 100
val := uint64(0)
atomic.Xadduintptr((*uintptr)(unsafe.Pointer(&val)), inc)
@@ -65,3 +66,40 @@ func TestXadduintptrOnUint64(t *testing.T) {
t.Fatalf("xadduintptr should increase lower-order bits, want %d, got %d", inc, val)
}
}
+
+func shouldPanic(t *testing.T, name string, f func()) {
+ defer func() {
+ if recover() == nil {
+ t.Errorf("%s did not panic", name)
+ }
+ }()
+ f()
+}
+
+// Variant of sync/atomic's TestUnaligned64:
+func TestUnaligned64(t *testing.T) {
+ // Unaligned 64-bit atomics on 32-bit systems are
+ // a continual source of pain. Test that on 32-bit systems they crash
+ // instead of failing silently.
+
+ switch runtime.GOARCH {
+ default:
+ if unsafe.Sizeof(int(0)) != 4 {
+ t.Skip("test only runs on 32-bit systems")
+ }
+ case "amd64p32":
+ // amd64p32 can handle unaligned atomics.
+ t.Skipf("test not needed on %v", runtime.GOARCH)
+ }
+
+ x := make([]uint32, 4)
+ up64 := (*uint64)(unsafe.Pointer(&x[1])) // misaligned
+ p64 := (*int64)(unsafe.Pointer(&x[1])) // misaligned
+
+ shouldPanic(t, "Load64", func() { atomic.Load64(up64) })
+ shouldPanic(t, "Loadint64", func() { atomic.Loadint64(p64) })
+ shouldPanic(t, "Store64", func() { atomic.Store64(up64, 0) })
+ shouldPanic(t, "Xadd64", func() { atomic.Xadd64(up64, 1) })
+ shouldPanic(t, "Xchg64", func() { atomic.Xchg64(up64, 1) })
+ shouldPanic(t, "Cas64", func() { atomic.Cas64(up64, 1, 2) })
+}
diff --git a/src/runtime/internal/atomic/bench_test.go b/src/runtime/internal/atomic/bench_test.go
new file mode 100644
index 0000000..47010e3
--- /dev/null
+++ b/src/runtime/internal/atomic/bench_test.go
@@ -0,0 +1,28 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package atomic_test
+
+import (
+ "runtime/internal/atomic"
+ "testing"
+)
+
+var sink interface{}
+
+func BenchmarkAtomicLoad64(b *testing.B) {
+ var x uint64
+ sink = &x
+ for i := 0; i < b.N; i++ {
+ _ = atomic.Load64(&x)
+ }
+}
+
+func BenchmarkAtomicStore64(b *testing.B) {
+ var x uint64
+ sink = &x
+ for i := 0; i < b.N; i++ {
+ atomic.Store64(&x, 0)
+ }
+}
diff --git a/src/runtime/internal/atomic/sys_nacl_arm.s b/src/runtime/internal/atomic/sys_nacl_arm.s
index efa9604..bdc1dd6 100644
--- a/src/runtime/internal/atomic/sys_nacl_arm.s
+++ b/src/runtime/internal/atomic/sys_nacl_arm.s
@@ -4,9 +4,6 @@
#include "textflag.h"
-TEXT runtime∕internal∕atomic·Casp(SB),NOSPLIT,$0
- B runtime·cas(SB)
-
// This is only valid for ARMv6+, however, NaCl/ARM is only defined
// for ARMv7A anyway.
TEXT runtime∕internal∕atomic·Cas(SB),NOSPLIT,$0
diff --git a/src/runtime/internal/sys/arch.go b/src/runtime/internal/sys/arch.go
index c175704..148e838 100644
--- a/src/runtime/internal/sys/arch.go
+++ b/src/runtime/internal/sys/arch.go
@@ -11,6 +11,7 @@ const (
ARM
ARM64
I386
+ MIPS
MIPS64
PPC64
S390X
diff --git a/src/runtime/internal/sys/arch_386.go b/src/runtime/internal/sys/arch_386.go
index 48c42f7..61d6722 100644
--- a/src/runtime/internal/sys/arch_386.go
+++ b/src/runtime/internal/sys/arch_386.go
@@ -5,14 +5,14 @@
package sys
const (
- ArchFamily = I386
- BigEndian = 0
- CacheLineSize = 64
- PhysPageSize = GoosNacl*65536 + (1-GoosNacl)*4096 // 4k normally; 64k on NaCl
- PCQuantum = 1
- Int64Align = 4
- HugePageSize = 1 << 21
- MinFrameSize = 0
+ ArchFamily = I386
+ BigEndian = 0
+ CacheLineSize = 64
+ DefaultPhysPageSize = GoosNacl*65536 + (1-GoosNacl)*4096 // 4k normally; 64k on NaCl
+ PCQuantum = 1
+ Int64Align = 4
+ HugePageSize = 1 << 21
+ MinFrameSize = 0
)
type Uintreg uint32
diff --git a/src/runtime/internal/sys/arch_amd64.go b/src/runtime/internal/sys/arch_amd64.go
index 1bbdb99..1f2114a 100644
--- a/src/runtime/internal/sys/arch_amd64.go
+++ b/src/runtime/internal/sys/arch_amd64.go
@@ -5,14 +5,14 @@
package sys
const (
- ArchFamily = AMD64
- BigEndian = 0
- CacheLineSize = 64
- PhysPageSize = 4096
- PCQuantum = 1
- Int64Align = 8
- HugePageSize = 1 << 21
- MinFrameSize = 0
+ ArchFamily = AMD64
+ BigEndian = 0
+ CacheLineSize = 64
+ DefaultPhysPageSize = 4096
+ PCQuantum = 1
+ Int64Align = 8
+ HugePageSize = 1 << 21
+ MinFrameSize = 0
)
type Uintreg uint64
diff --git a/src/runtime/internal/sys/arch_amd64p32.go b/src/runtime/internal/sys/arch_amd64p32.go
index b7011a4..0779855 100644
--- a/src/runtime/internal/sys/arch_amd64p32.go
+++ b/src/runtime/internal/sys/arch_amd64p32.go
@@ -5,14 +5,14 @@
package sys
const (
- ArchFamily = AMD64
- BigEndian = 0
- CacheLineSize = 64
- PhysPageSize = 65536*GoosNacl + 4096*(1-GoosNacl)
- PCQuantum = 1
- Int64Align = 8
- HugePageSize = 1 << 21
- MinFrameSize = 0
+ ArchFamily = AMD64
+ BigEndian = 0
+ CacheLineSize = 64
+ DefaultPhysPageSize = 65536*GoosNacl + 4096*(1-GoosNacl)
+ PCQuantum = 1
+ Int64Align = 8
+ HugePageSize = 1 << 21
+ MinFrameSize = 0
)
type Uintreg uint64
diff --git a/src/runtime/internal/sys/arch_arm.go b/src/runtime/internal/sys/arch_arm.go
index f90f52d..899010b 100644
--- a/src/runtime/internal/sys/arch_arm.go
+++ b/src/runtime/internal/sys/arch_arm.go
@@ -5,14 +5,14 @@
package sys
const (
- ArchFamily = ARM
- BigEndian = 0
- CacheLineSize = 32
- PhysPageSize = 65536*GoosNacl + 4096*(1-GoosNacl)
- PCQuantum = 4
- Int64Align = 4
- HugePageSize = 0
- MinFrameSize = 4
+ ArchFamily = ARM
+ BigEndian = 0
+ CacheLineSize = 32
+ DefaultPhysPageSize = 65536
+ PCQuantum = 4
+ Int64Align = 4
+ HugePageSize = 0
+ MinFrameSize = 4
)
type Uintreg uint32
diff --git a/src/runtime/internal/sys/arch_arm64.go b/src/runtime/internal/sys/arch_arm64.go
index aaaa4b0..2d57dda 100644
--- a/src/runtime/internal/sys/arch_arm64.go
+++ b/src/runtime/internal/sys/arch_arm64.go
@@ -5,14 +5,14 @@
package sys
const (
- ArchFamily = ARM64
- BigEndian = 0
- CacheLineSize = 32
- PhysPageSize = 65536
- PCQuantum = 4
- Int64Align = 8
- HugePageSize = 0
- MinFrameSize = 8
+ ArchFamily = ARM64
+ BigEndian = 0
+ CacheLineSize = 32
+ DefaultPhysPageSize = 65536
+ PCQuantum = 4
+ Int64Align = 8
+ HugePageSize = 0
+ MinFrameSize = 8
)
type Uintreg uint64
diff --git a/src/runtime/internal/sys/arch_mips.go b/src/runtime/internal/sys/arch_mips.go
new file mode 100644
index 0000000..65fc4f8
--- /dev/null
+++ b/src/runtime/internal/sys/arch_mips.go
@@ -0,0 +1,18 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package sys
+
+const (
+ ArchFamily = MIPS
+ BigEndian = 1
+ CacheLineSize = 32
+ DefaultPhysPageSize = 65536
+ PCQuantum = 4
+ Int64Align = 4
+ HugePageSize = 0
+ MinFrameSize = 4
+)
+
+type Uintreg uint32
diff --git a/src/runtime/internal/sys/arch_mips64.go b/src/runtime/internal/sys/arch_mips64.go
index d567259..0f6de74 100644
--- a/src/runtime/internal/sys/arch_mips64.go
+++ b/src/runtime/internal/sys/arch_mips64.go
@@ -5,14 +5,14 @@
package sys
const (
- ArchFamily = MIPS64
- BigEndian = 1
- CacheLineSize = 32
- PhysPageSize = 16384
- PCQuantum = 4
- Int64Align = 8
- HugePageSize = 0
- MinFrameSize = 8
+ ArchFamily = MIPS64
+ BigEndian = 1
+ CacheLineSize = 32
+ DefaultPhysPageSize = 16384
+ PCQuantum = 4
+ Int64Align = 8
+ HugePageSize = 0
+ MinFrameSize = 8
)
type Uintreg uint64
diff --git a/src/runtime/internal/sys/arch_mips64le.go b/src/runtime/internal/sys/arch_mips64le.go
index f8cdf2b..4ced35b 100644
--- a/src/runtime/internal/sys/arch_mips64le.go
+++ b/src/runtime/internal/sys/arch_mips64le.go
@@ -5,14 +5,14 @@
package sys
const (
- ArchFamily = MIPS64
- BigEndian = 0
- CacheLineSize = 32
- PhysPageSize = 16384
- PCQuantum = 4
- Int64Align = 8
- HugePageSize = 0
- MinFrameSize = 8
+ ArchFamily = MIPS64
+ BigEndian = 0
+ CacheLineSize = 32
+ DefaultPhysPageSize = 16384
+ PCQuantum = 4
+ Int64Align = 8
+ HugePageSize = 0
+ MinFrameSize = 8
)
type Uintreg uint64
diff --git a/src/runtime/internal/sys/arch_mipsle.go b/src/runtime/internal/sys/arch_mipsle.go
new file mode 100644
index 0000000..33e9764
--- /dev/null
+++ b/src/runtime/internal/sys/arch_mipsle.go
@@ -0,0 +1,18 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package sys
+
+const (
+ ArchFamily = MIPS
+ BigEndian = 0
+ CacheLineSize = 32
+ DefaultPhysPageSize = 65536
+ PCQuantum = 4
+ Int64Align = 4
+ HugePageSize = 0
+ MinFrameSize = 4
+)
+
+type Uintreg uint32
diff --git a/src/runtime/internal/sys/arch_ppc64.go b/src/runtime/internal/sys/arch_ppc64.go
index cdec63f..80595ee 100644
--- a/src/runtime/internal/sys/arch_ppc64.go
+++ b/src/runtime/internal/sys/arch_ppc64.go
@@ -5,14 +5,14 @@
package sys
const (
- ArchFamily = PPC64
- BigEndian = 1
- CacheLineSize = 64
- PhysPageSize = 65536
- PCQuantum = 4
- Int64Align = 8
- HugePageSize = 0
- MinFrameSize = 32
+ ArchFamily = PPC64
+ BigEndian = 1
+ CacheLineSize = 128
+ DefaultPhysPageSize = 65536
+ PCQuantum = 4
+ Int64Align = 8
+ HugePageSize = 0
+ MinFrameSize = 32
)
type Uintreg uint64
diff --git a/src/runtime/internal/sys/arch_ppc64le.go b/src/runtime/internal/sys/arch_ppc64le.go
index 4fd68f9..f68e777 100644
--- a/src/runtime/internal/sys/arch_ppc64le.go
+++ b/src/runtime/internal/sys/arch_ppc64le.go
@@ -5,14 +5,14 @@
package sys
const (
- ArchFamily = PPC64
- BigEndian = 0
- CacheLineSize = 64
- PhysPageSize = 65536
- PCQuantum = 4
- Int64Align = 8
- HugePageSize = 0
- MinFrameSize = 32
+ ArchFamily = PPC64
+ BigEndian = 0
+ CacheLineSize = 128
+ DefaultPhysPageSize = 65536
+ PCQuantum = 4
+ Int64Align = 8
+ HugePageSize = 0
+ MinFrameSize = 32
)
type Uintreg uint64
diff --git a/src/runtime/internal/sys/arch_s390x.go b/src/runtime/internal/sys/arch_s390x.go
index ca1cb86..4ec4bf8 100644
--- a/src/runtime/internal/sys/arch_s390x.go
+++ b/src/runtime/internal/sys/arch_s390x.go
@@ -5,14 +5,14 @@
package sys
const (
- ArchFamily = S390X
- BigEndian = 1
- CacheLineSize = 256
- PhysPageSize = 4096
- PCQuantum = 2
- Int64Align = 8
- HugePageSize = 0
- MinFrameSize = 8
+ ArchFamily = S390X
+ BigEndian = 1
+ CacheLineSize = 256
+ DefaultPhysPageSize = 4096
+ PCQuantum = 2
+ Int64Align = 8
+ HugePageSize = 0
+ MinFrameSize = 8
)
type Uintreg uint64
diff --git a/src/runtime/internal/sys/intrinsics.go b/src/runtime/internal/sys/intrinsics.go
index 08a062f..db2cbec 100644
--- a/src/runtime/internal/sys/intrinsics.go
+++ b/src/runtime/internal/sys/intrinsics.go
@@ -30,19 +30,6 @@ var deBruijnIdx32 = [32]byte{
30, 9, 19, 24, 29, 18, 28, 27,
}
-const deBruijn16 = 0x09af
-
-var deBruijnIdx16 = [16]byte{
- 0, 1, 2, 5, 3, 9, 6, 11,
- 15, 4, 8, 10, 14, 7, 13, 12,
-}
-
-const deBruijn8 = 0x17
-
-var deBruijnIdx8 = [8]byte{
- 0, 1, 2, 4, 7, 3, 6, 5,
-}
-
// Ctz64 counts trailing (low-order) zeroes,
// and if all are zero, then 64.
func Ctz64(x uint64) uint64 {
@@ -63,26 +50,6 @@ func Ctz32(x uint32) uint32 {
return y + z
}
-// Ctz16 counts trailing (low-order) zeroes,
-// and if all are zero, then 16.
-func Ctz16(x uint16) uint16 {
- x &= -x // isolate low-order bit
- y := x * deBruijn16 >> 12 // extract part of deBruijn sequence
- y = uint16(deBruijnIdx16[y]) // convert to bit index
- z := (x - 1) >> 11 & 16 // adjustment if zero
- return y + z
-}
-
-// Ctz8 counts trailing (low-order) zeroes,
-// and if all are zero, then 8.
-func Ctz8(x uint8) uint8 {
- x &= -x // isolate low-order bit
- y := x * deBruijn8 >> 5 // extract part of deBruijn sequence
- y = uint8(deBruijnIdx8[y]) // convert to bit index
- z := (x - 1) >> 4 & 8 // adjustment if zero
- return y + z
-}
-
// Bswap64 returns its input with byte order reversed
// 0x0102030405060708 -> 0x0807060504030201
func Bswap64(x uint64) uint64 {
diff --git a/src/runtime/internal/sys/intrinsics_386.s b/src/runtime/internal/sys/intrinsics_386.s
index 1f48e26..bc63e5e 100644
--- a/src/runtime/internal/sys/intrinsics_386.s
+++ b/src/runtime/internal/sys/intrinsics_386.s
@@ -36,22 +36,6 @@ TEXT runtime∕internal∕sys·Ctz32(SB), NOSPLIT, $0-8
MOVL AX, ret+4(FP)
RET
-TEXT runtime∕internal∕sys·Ctz16(SB), NOSPLIT, $0-6
- MOVW x+0(FP), AX
- BSFW AX, AX
- JNZ 2(PC)
- MOVW $16, AX
- MOVW AX, ret+4(FP)
- RET
-
-TEXT runtime∕internal∕sys·Ctz8(SB), NOSPLIT, $0-5
- MOVBLZX x+0(FP), AX
- BSFL AX, AX
- JNZ 2(PC)
- MOVB $8, AX
- MOVB AX, ret+4(FP)
- RET
-
TEXT runtime∕internal∕sys·Bswap64(SB), NOSPLIT, $0-16
MOVL x_lo+0(FP), AX
MOVL x_hi+4(FP), BX
diff --git a/src/runtime/internal/sys/intrinsics_stubs.go b/src/runtime/internal/sys/intrinsics_stubs.go
index 079844f..d351048 100644
--- a/src/runtime/internal/sys/intrinsics_stubs.go
+++ b/src/runtime/internal/sys/intrinsics_stubs.go
@@ -8,7 +8,5 @@ package sys
func Ctz64(x uint64) uint64
func Ctz32(x uint32) uint32
-func Ctz16(x uint16) uint16
-func Ctz8(x uint8) uint8
func Bswap64(x uint64) uint64
func Bswap32(x uint32) uint32
diff --git a/src/runtime/internal/sys/intrinsics_test.go b/src/runtime/internal/sys/intrinsics_test.go
index 097631b..1f2c8da 100644
--- a/src/runtime/internal/sys/intrinsics_test.go
+++ b/src/runtime/internal/sys/intrinsics_test.go
@@ -21,22 +21,6 @@ func TestCtz32(t *testing.T) {
}
}
}
-func TestCtz16(t *testing.T) {
- for i := uint(0); i <= 16; i++ {
- x := uint16(5) << i
- if got := sys.Ctz16(x); got != uint16(i) {
- t.Errorf("Ctz16(%d)=%d, want %d", x, got, i)
- }
- }
-}
-func TestCtz8(t *testing.T) {
- for i := uint(0); i <= 8; i++ {
- x := uint8(5) << i
- if got := sys.Ctz8(x); got != uint8(i) {
- t.Errorf("Ctz8(%d)=%d, want %d", x, got, i)
- }
- }
-}
func TestBswap64(t *testing.T) {
x := uint64(0x1122334455667788)
diff --git a/src/runtime/internal/sys/zgoarch_mips.go b/src/runtime/internal/sys/zgoarch_mips.go
new file mode 100644
index 0000000..2f733d2
--- /dev/null
+++ b/src/runtime/internal/sys/zgoarch_mips.go
@@ -0,0 +1,26 @@
+// generated by gengoos.go using 'go generate'
+
+package sys
+
+const GOARCH = `mips`
+
+const Goarch386 = 0
+const GoarchAmd64 = 0
+const GoarchAmd64p32 = 0
+const GoarchArm = 0
+const GoarchArmbe = 0
+const GoarchArm64 = 0
+const GoarchArm64be = 0
+const GoarchPpc64 = 0
+const GoarchPpc64le = 0
+const GoarchMips = 1
+const GoarchMipsle = 0
+const GoarchMips64 = 0
+const GoarchMips64le = 0
+const GoarchMips64p32 = 0
+const GoarchMips64p32le = 0
+const GoarchPpc = 0
+const GoarchS390 = 0
+const GoarchS390x = 0
+const GoarchSparc = 0
+const GoarchSparc64 = 0
diff --git a/src/runtime/internal/sys/zgoarch_mipsle.go b/src/runtime/internal/sys/zgoarch_mipsle.go
new file mode 100644
index 0000000..95f3d5a
--- /dev/null
+++ b/src/runtime/internal/sys/zgoarch_mipsle.go
@@ -0,0 +1,26 @@
+// generated by gengoos.go using 'go generate'
+
+package sys
+
+const GOARCH = `mipsle`
+
+const Goarch386 = 0
+const GoarchAmd64 = 0
+const GoarchAmd64p32 = 0
+const GoarchArm = 0
+const GoarchArmbe = 0
+const GoarchArm64 = 0
+const GoarchArm64be = 0
+const GoarchPpc64 = 0
+const GoarchPpc64le = 0
+const GoarchMips = 0
+const GoarchMipsle = 1
+const GoarchMips64 = 0
+const GoarchMips64le = 0
+const GoarchMips64p32 = 0
+const GoarchMips64p32le = 0
+const GoarchPpc = 0
+const GoarchS390 = 0
+const GoarchS390x = 0
+const GoarchSparc = 0
+const GoarchSparc64 = 0
diff --git a/src/runtime/lfstack_32bit.go b/src/runtime/lfstack_32bit.go
index 2f59e02..d36ca50 100644
--- a/src/runtime/lfstack_32bit.go
+++ b/src/runtime/lfstack_32bit.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build 386 arm nacl
+// +build 386 arm nacl mips mipsle
package runtime
diff --git a/src/runtime/malloc.go b/src/runtime/malloc.go
index b079a07..1c9efc3 100644
--- a/src/runtime/malloc.go
+++ b/src/runtime/malloc.go
@@ -2,80 +2,81 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// Memory allocator, based on tcmalloc.
+// Memory allocator.
+//
+// This was originally based on tcmalloc, but has diverged quite a bit.
// http://goog-perftools.sourceforge.net/doc/tcmalloc.html
// The main allocator works in runs of pages.
// Small allocation sizes (up to and including 32 kB) are
-// rounded to one of about 100 size classes, each of which
-// has its own free list of objects of exactly that size.
+// rounded to one of about 70 size classes, each of which
+// has its own free set of objects of exactly that size.
// Any free page of memory can be split into a set of objects
-// of one size class, which are then managed using free list
-// allocators.
+// of one size class, which are then managed using a free bitmap.
//
// The allocator's data structures are:
//
-// FixAlloc: a free-list allocator for fixed-size objects,
+// fixalloc: a free-list allocator for fixed-size off-heap objects,
// used to manage storage used by the allocator.
-// MHeap: the malloc heap, managed at page (4096-byte) granularity.
-// MSpan: a run of pages managed by the MHeap.
-// MCentral: a shared free list for a given size class.
-// MCache: a per-thread (in Go, per-P) cache for small objects.
-// MStats: allocation statistics.
+// mheap: the malloc heap, managed at page (8192-byte) granularity.
+// mspan: a run of pages managed by the mheap.
+// mcentral: collects all spans of a given size class.
+// mcache: a per-P cache of mspans with free space.
+// mstats: allocation statistics.
//
// Allocating a small object proceeds up a hierarchy of caches:
//
// 1. Round the size up to one of the small size classes
-// and look in the corresponding MCache free list.
-// If the list is not empty, allocate an object from it.
+// and look in the corresponding mspan in this P's mcache.
+// Scan the mspan's free bitmap to find a free slot.
+// If there is a free slot, allocate it.
// This can all be done without acquiring a lock.
//
-// 2. If the MCache free list is empty, replenish it by
-// taking a bunch of objects from the MCentral free list.
-// Moving a bunch amortizes the cost of acquiring the MCentral lock.
+// 2. If the mspan has no free slots, obtain a new mspan
+// from the mcentral's list of mspans of the required size
+// class that have free space.
+// Obtaining a whole span amortizes the cost of locking
+// the mcentral.
//
-// 3. If the MCentral free list is empty, replenish it by
-// allocating a run of pages from the MHeap and then
-// chopping that memory into objects of the given size.
-// Allocating many objects amortizes the cost of locking
-// the heap.
+// 3. If the mcentral's mspan list is empty, obtain a run
+// of pages from the mheap to use for the mspan.
//
-// 4. If the MHeap is empty or has no page runs large enough,
+// 4. If the mheap is empty or has no page runs large enough,
// allocate a new group of pages (at least 1MB) from the
-// operating system. Allocating a large run of pages
+// operating system. Allocating a large run of pages
// amortizes the cost of talking to the operating system.
//
-// Freeing a small object proceeds up the same hierarchy:
+// Sweeping an mspan and freeing objects on it proceeds up a similar
+// hierarchy:
+//
+// 1. If the mspan is being swept in response to allocation, it
+// is returned to the mcache to satisfy the allocation.
//
-// 1. Look up the size class for the object and add it to
-// the MCache free list.
+// 2. Otherwise, if the mspan still has allocated objects in it,
+// it is placed on the mcentral free list for the mspan's size
+// class.
//
-// 2. If the MCache free list is too long or the MCache has
-// too much memory, return some to the MCentral free lists.
+// 3. Otherwise, if all objects in the mspan are free, the mspan
+// is now "idle", so it is returned to the mheap and no longer
+// has a size class.
+// This may coalesce it with adjacent idle mspans.
//
-// 3. If all the objects in a given span have returned to
-// the MCentral list, return that span to the page heap.
+// 4. If an mspan remains idle for long enough, return its pages
+// to the operating system.
//
-// 4. If the heap has too much memory, return some to the
-// operating system.
+// Allocating and freeing a large object uses the mheap
+// directly, bypassing the mcache and mcentral.
//
-// TODO(rsc): Step 4 is not implemented.
+// Free object slots in an mspan are zeroed only if mspan.needzero is
+// false. If needzero is true, objects are zeroed as they are
+// allocated. There are various benefits to delaying zeroing this way:
//
-// Allocating and freeing a large object uses the page heap
-// directly, bypassing the MCache and MCentral free lists.
+// 1. Stack frame allocation can avoid zeroing altogether.
//
-// The small objects on the MCache and MCentral free lists
-// may or may not be zeroed. They are zeroed if and only if
-// the second word of the object is zero. A span in the
-// page heap is zeroed unless s->needzero is set. When a span
-// is allocated to break into small objects, it is zeroed if needed
-// and s->needzero is set. There are two main benefits to delaying the
-// zeroing this way:
+// 2. It exhibits better temporal locality, since the program is
+// probably about to write to the memory.
//
-// 1. stack frames allocated from the small object lists
-// or the page heap can avoid zeroing altogether.
-// 2. the cost of zeroing when reusing a small object is
-// charged to the mutator, not the garbage collector.
+// 3. We don't zero pages that never get reused.
package runtime
@@ -101,28 +102,13 @@ const (
mSpanInUse = _MSpanInUse
concurrentSweep = _ConcurrentSweep
-)
-const (
- _PageShift = 13
- _PageSize = 1 << _PageShift
- _PageMask = _PageSize - 1
-)
+ _PageSize = 1 << _PageShift
+ _PageMask = _PageSize - 1
-const (
// _64bit = 1 on 64-bit systems, 0 on 32-bit systems
_64bit = 1 << (^uintptr(0) >> 63) / 2
- // Computed constant. The definition of MaxSmallSize and the
- // algorithm in msize.go produces some number of different allocation
- // size classes. NumSizeClasses is that number. It's needed here
- // because there are static arrays of this length; when msize runs its
- // size choosing algorithm it double-checks that NumSizeClasses agrees.
- _NumSizeClasses = 67
-
- // Tunable constants.
- _MaxSmallSize = 32 << 10
-
// Tiny allocator parameters, see "Tiny allocator" comment in malloc.go.
_TinySize = 16
_TinySizeClass = 2
@@ -155,10 +141,11 @@ const (
// See https://golang.org/issue/5402 and https://golang.org/issue/5236.
// On other 64-bit platforms, we limit the arena to 512GB, or 39 bits.
// On 32-bit, we don't bother limiting anything, so we use the full 32-bit address.
+ // The only exception is mips32 which only has access to low 2GB of virtual memory.
// On Darwin/arm64, we cannot reserve more than ~5GB of virtual memory,
// but as most devices have less than 4GB of physical memory anyway, we
// try to be conservative here, and only ask for a 2GB heap.
- _MHeapMap_TotalBits = (_64bit*sys.GoosWindows)*35 + (_64bit*(1-sys.GoosWindows)*(1-sys.GoosDarwin*sys.GoarchArm64))*39 + sys.GoosDarwin*sys.GoarchArm64*31 + (1-_64bit)*32
+ _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)
@@ -168,9 +155,17 @@ const (
// on the hardware details of the machine. The garbage
// collector scales well to 32 cpus.
_MaxGcproc = 32
+
+ _MaxArena32 = 1<<32 - 1
)
-const _MaxArena32 = 1<<32 - 1
+// physPageSize is the size in bytes of the OS's physical pages.
+// Mapping and unmapping operations must be done at multiples of
+// physPageSize.
+//
+// This must be set by the OS init code (typically in osinit) before
+// mallocinit.
+var physPageSize uintptr
// OS-defined helpers:
//
@@ -211,12 +206,31 @@ const _MaxArena32 = 1<<32 - 1
// if accessed. Used only for debugging the runtime.
func mallocinit() {
- initSizes()
-
if class_to_size[_TinySizeClass] != _TinySize {
throw("bad TinySizeClass")
}
+ testdefersizes()
+
+ // Copy class sizes out for statistics table.
+ for i := range class_to_size {
+ memstats.by_size[i].size = uint32(class_to_size[i])
+ }
+
+ // Check physPageSize.
+ if physPageSize == 0 {
+ // The OS init code failed to fetch the physical page size.
+ throw("failed to get system page size")
+ }
+ if physPageSize < minPhysPageSize {
+ print("system page size (", physPageSize, ") is smaller than minimum page size (", minPhysPageSize, ")\n")
+ throw("bad system page size")
+ }
+ if physPageSize&(physPageSize-1) != 0 {
+ print("system page size (", physPageSize, ") must be a power of 2\n")
+ throw("bad system page size")
+ }
+
var p, bitmapSize, spansSize, pSize, limit uintptr
var reserved bool
@@ -337,7 +351,7 @@ func mallocinit() {
// To overcome this we ask for PageSize more and round up the pointer.
p1 := round(p, _PageSize)
- mheap_.spans = (**mspan)(unsafe.Pointer(p1))
+ spansStart := p1
mheap_.bitmap = p1 + spansSize + bitmapSize
if sys.PtrSize == 4 {
// Set arena_start such that we can accept memory
@@ -356,7 +370,7 @@ func mallocinit() {
}
// Initialize the rest of the allocator.
- mheap_.init(spansSize)
+ mheap_.init(spansStart, spansSize)
_g_ := getg()
_g_.m.mcache = allocmcache()
}
@@ -491,7 +505,7 @@ 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 int8) (v gclinkptr, s *mspan, shouldhelpgc bool) {
+func (c *mcache) nextFree(sizeclass uint8) (v gclinkptr, s *mspan, shouldhelpgc bool) {
s = c.alloc[sizeclass]
shouldhelpgc = false
freeIndex := s.nextFreeIndex()
@@ -645,11 +659,11 @@ func mallocgc(size uintptr, typ *_type, needzero bool) unsafe.Pointer {
}
size = maxTinySize
} else {
- var sizeclass int8
- if size <= 1024-8 {
- sizeclass = size_to_class8[(size+7)>>3]
+ var sizeclass uint8
+ if size <= smallSizeMax-8 {
+ sizeclass = size_to_class8[(size+smallSizeDiv-1)/smallSizeDiv]
} else {
- sizeclass = size_to_class128[(size-1024+127)>>7]
+ sizeclass = size_to_class128[(size-smallSizeMax+largeSizeDiv-1)/largeSizeDiv]
}
size = uintptr(class_to_size[sizeclass])
span := c.alloc[sizeclass]
@@ -659,7 +673,7 @@ func mallocgc(size uintptr, typ *_type, needzero bool) unsafe.Pointer {
}
x = unsafe.Pointer(v)
if needzero && span.needzero != 0 {
- memclr(unsafe.Pointer(v), size)
+ memclrNoHeapPointers(unsafe.Pointer(v), size)
}
}
} else {
@@ -781,6 +795,8 @@ func largeAlloc(size uintptr, needzero bool) *mspan {
}
// implementation of new builtin
+// compiler (both frontend and SSA backend) knows the signature
+// of this function
func newobject(typ *_type) unsafe.Pointer {
return mallocgc(typ.size, typ, true)
}
@@ -841,7 +857,7 @@ func nextSample() int32 {
// x = -log_e(q) * period
// x = log_2(q) * (-log_e(2)) * period ; Using log_2 for efficiency
const randomBitCount = 26
- q := fastrand1()%(1<<randomBitCount) + 1
+ q := fastrand()%(1<<randomBitCount) + 1
qlog := fastlog2(float64(q)) - randomBitCount
if qlog > 0 {
qlog = 0
@@ -859,7 +875,7 @@ func nextSampleNoFP() int32 {
rate = 0x3fffffff
}
if rate != 0 {
- return int32(int(fastrand1()) % (2 * rate))
+ return int32(int(fastrand()) % (2 * rate))
}
return 0
}
@@ -878,6 +894,9 @@ var globalAlloc struct {
// There is no associated free operation.
// Intended for things like function/type/debug-related persistent data.
// If align is 0, uses default align (currently 8).
+// The returned memory will be zeroed.
+//
+// Consider marking persistentalloc'd types go:notinheap.
func persistentalloc(size, align uintptr, sysStat *uint64) unsafe.Pointer {
var p unsafe.Pointer
systemstack(func() {
diff --git a/src/runtime/map_test.go b/src/runtime/map_test.go
index 496f8e8..aacd091 100644
--- a/src/runtime/map_test.go
+++ b/src/runtime/map_test.go
@@ -235,6 +235,7 @@ func TestIterGrowWithGC(t *testing.T) {
}
func testConcurrentReadsAfterGrowth(t *testing.T, useReflect bool) {
+ t.Parallel()
if runtime.GOMAXPROCS(-1) == 1 {
defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(16))
}
diff --git a/src/runtime/mbarrier.go b/src/runtime/mbarrier.go
index 4a8f501..5848b43 100644
--- a/src/runtime/mbarrier.go
+++ b/src/runtime/mbarrier.go
@@ -7,7 +7,7 @@
// For the concurrent garbage collector, the Go compiler implements
// updates to pointer-valued fields that may be in heap objects by
// emitting calls to write barriers. This file contains the actual write barrier
-// implementation, markwb, and the various wrappers called by the
+// implementation, gcmarkwb_m, and the various wrappers called by the
// compiler to implement pointer assignment, slice assignment,
// typed memmove, and so on.
@@ -18,29 +18,60 @@ import (
"unsafe"
)
-// markwb is the mark-phase write barrier, the only barrier we have.
+// gcmarkwb_m is the mark-phase write barrier, the only barrier we have.
// The rest of this file exists only to make calls to this function.
//
-// This is the Dijkstra barrier coarsened to always shade the ptr (dst) object.
-// The original Dijkstra barrier only shaded ptrs being placed in black slots.
+// This is a hybrid barrier that combines a Yuasa-style deletion
+// barrier—which shades the object whose reference is being
+// overwritten—with Dijkstra insertion barrier—which shades the object
+// whose reference is being written. The insertion part of the barrier
+// is necessary while the calling goroutine's stack is grey. In
+// pseudocode, the barrier is:
+//
+// writePointer(slot, ptr):
+// shade(*slot)
+// if current stack is grey:
+// shade(ptr)
+// *slot = ptr
+//
+// slot is the destination in Go code.
+// ptr is the value that goes into the slot in Go code.
//
// Shade indicates that it has seen a white pointer by adding the referent
// to wbuf as well as marking it.
//
-// slot is the destination (dst) in go code
-// ptr is the value that goes into the slot (src) in the go code
+// The two shades and the condition work together to prevent a mutator
+// from hiding an object from the garbage collector:
+//
+// 1. shade(*slot) prevents a mutator from hiding an object by moving
+// the sole pointer to it from the heap to its stack. If it attempts
+// to unlink an object from the heap, this will shade it.
+//
+// 2. shade(ptr) prevents a mutator from hiding an object by moving
+// the sole pointer to it from its stack into a black object in the
+// heap. If it attempts to install the pointer into a black object,
+// this will shade it.
+//
+// 3. Once a goroutine's stack is black, the shade(ptr) becomes
+// unnecessary. shade(ptr) prevents hiding an object by moving it from
+// the stack to the heap, but this requires first having a pointer
+// hidden on the stack. Immediately after a stack is scanned, it only
+// points to shaded objects, so it's not hiding anything, and the
+// shade(*slot) prevents it from hiding any other pointers on its
+// stack.
+//
+// For a detailed description of this barrier and proof of
+// correctness, see https://github.com/golang/proposal/blob/master/design/17503-eliminate-rescan.md
+//
//
//
// Dealing with memory ordering:
//
-// Dijkstra pointed out that maintaining the no black to white
-// pointers means that white to white pointers do not need
-// to be noted by the write barrier. Furthermore if either
-// white object dies before it is reached by the
-// GC then the object can be collected during this GC cycle
-// instead of waiting for the next cycle. Unfortunately the cost of
-// ensuring that the object holding the slot doesn't concurrently
-// change to black without the mutator noticing seems prohibitive.
+// Both the Yuasa and Dijkstra barriers can be made conditional on the
+// color of the object containing the slot. We chose not to make these
+// conditional because the cost of ensuring that the object holding
+// the slot doesn't concurrently change color without the mutator
+// noticing seems prohibitive.
//
// Consider the following example where the mutator writes into
// a slot and then loads the slot's mark bit while the GC thread
@@ -98,15 +129,41 @@ import (
// barriers for writes to globals so that we don't have to rescan
// global during mark termination.
//
+//
+// Publication ordering:
+//
+// The write barrier is *pre-publication*, meaning that the write
+// barrier happens prior to the *slot = ptr write that may make ptr
+// reachable by some goroutine that currently cannot reach it.
+//
+//
//go:nowritebarrierrec
+//go:systemstack
func gcmarkwb_m(slot *uintptr, ptr uintptr) {
if writeBarrier.needed {
+ // Note: This turns bad pointer writes into bad
+ // pointer reads, which could be confusing. We avoid
+ // reading from obviously bad pointers, which should
+ // take care of the vast majority of these. We could
+ // patch this up in the signal handler, or use XCHG to
+ // combine the read and the write. Checking inheap is
+ // insufficient since we need to track changes to
+ // roots outside the heap.
+ if slot1 := uintptr(unsafe.Pointer(slot)); slot1 >= minPhysPageSize {
+ if optr := *slot; optr != 0 {
+ shade(optr)
+ }
+ }
+ // TODO: Make this conditional on the caller's stack color.
if ptr != 0 && inheap(ptr) {
shade(ptr)
}
}
}
+// writebarrierptr_prewrite1 invokes a write barrier for *dst = src
+// prior to the write happening.
+//
// Write barrier calls must not happen during critical GC and scheduler
// related operations. In particular there are times when the GC assumes
// that the world is stopped but scheduler related code is still being
@@ -117,7 +174,7 @@ func gcmarkwb_m(slot *uintptr, ptr uintptr) {
// that we are in one these critical section and throw if the write is of
// a pointer to a heap object.
//go:nosplit
-func writebarrierptr_nostore1(dst *uintptr, src uintptr) {
+func writebarrierptr_prewrite1(dst *uintptr, src uintptr) {
mp := acquirem()
if mp.inwb || mp.dying > 0 {
releasem(mp)
@@ -125,7 +182,7 @@ func writebarrierptr_nostore1(dst *uintptr, src uintptr) {
}
systemstack(func() {
if mp.p == 0 && memstats.enablegc && !mp.inwb && inheap(src) {
- throw("writebarrierptr_nostore1 called with mp.p == nil")
+ throw("writebarrierptr_prewrite1 called with mp.p == nil")
}
mp.inwb = true
gcmarkwb_m(dst, src)
@@ -138,11 +195,11 @@ func writebarrierptr_nostore1(dst *uintptr, src uintptr) {
// but if we do that, Go inserts a write barrier on *dst = src.
//go:nosplit
func writebarrierptr(dst *uintptr, src uintptr) {
- *dst = src
if writeBarrier.cgo {
cgoCheckWriteBarrier(dst, src)
}
if !writeBarrier.needed {
+ *dst = src
return
}
if src != 0 && src < minPhysPageSize {
@@ -151,13 +208,16 @@ func writebarrierptr(dst *uintptr, src uintptr) {
throw("bad pointer in write barrier")
})
}
- writebarrierptr_nostore1(dst, src)
+ writebarrierptr_prewrite1(dst, src)
+ *dst = src
}
-// Like writebarrierptr, but the store has already been applied.
-// Do not reapply.
+// writebarrierptr_prewrite is like writebarrierptr, but the store
+// will be performed by the caller after this call. The caller must
+// not allow preemption between this call and the write.
+//
//go:nosplit
-func writebarrierptr_nostore(dst *uintptr, src uintptr) {
+func writebarrierptr_prewrite(dst *uintptr, src uintptr) {
if writeBarrier.cgo {
cgoCheckWriteBarrier(dst, src)
}
@@ -167,24 +227,38 @@ func writebarrierptr_nostore(dst *uintptr, src uintptr) {
if src != 0 && src < minPhysPageSize {
systemstack(func() { throw("bad pointer in write barrier") })
}
- writebarrierptr_nostore1(dst, src)
+ writebarrierptr_prewrite1(dst, src)
}
// typedmemmove copies a value of type t to dst from src.
//go:nosplit
func typedmemmove(typ *_type, dst, src unsafe.Pointer) {
+ if typ.kind&kindNoPointers == 0 {
+ bulkBarrierPreWrite(uintptr(dst), uintptr(src), typ.size)
+ }
+ // There's a race here: if some other goroutine can write to
+ // src, it may change some pointer in src after we've
+ // performed the write barrier but before we perform the
+ // memory copy. This safe because the write performed by that
+ // other goroutine must also be accompanied by a write
+ // barrier, so at worst we've unnecessarily greyed the old
+ // pointer that was in src.
memmove(dst, src, typ.size)
if writeBarrier.cgo {
cgoCheckMemmove(typ, dst, src, 0, typ.size)
}
- if typ.kind&kindNoPointers != 0 {
- return
- }
- heapBitsBulkBarrier(uintptr(dst), typ.size)
}
//go:linkname reflect_typedmemmove reflect.typedmemmove
func reflect_typedmemmove(typ *_type, dst, src unsafe.Pointer) {
+ if raceenabled {
+ raceWriteObjectPC(typ, dst, getcallerpc(unsafe.Pointer(&typ)), funcPC(reflect_typedmemmove))
+ raceReadObjectPC(typ, src, getcallerpc(unsafe.Pointer(&typ)), funcPC(reflect_typedmemmove))
+ }
+ if msanenabled {
+ msanwrite(dst, typ.size)
+ msanread(src, typ.size)
+ }
typedmemmove(typ, dst, src)
}
@@ -192,34 +266,38 @@ func reflect_typedmemmove(typ *_type, dst, src unsafe.Pointer) {
// dst and src point off bytes into the value and only copies size bytes.
//go:linkname reflect_typedmemmovepartial reflect.typedmemmovepartial
func reflect_typedmemmovepartial(typ *_type, dst, src unsafe.Pointer, off, size uintptr) {
+ if writeBarrier.needed && typ.kind&kindNoPointers == 0 && size >= sys.PtrSize {
+ // Pointer-align start address for bulk barrier.
+ adst, asrc, asize := dst, src, size
+ if frag := -off & (sys.PtrSize - 1); frag != 0 {
+ adst = add(dst, frag)
+ asrc = add(src, frag)
+ asize -= frag
+ }
+ bulkBarrierPreWrite(uintptr(adst), uintptr(asrc), asize&^(sys.PtrSize-1))
+ }
+
memmove(dst, src, size)
if writeBarrier.cgo {
cgoCheckMemmove(typ, dst, src, off, size)
}
- if !writeBarrier.needed || typ.kind&kindNoPointers != 0 || size < sys.PtrSize {
- return
- }
-
- if frag := -off & (sys.PtrSize - 1); frag != 0 {
- dst = add(dst, frag)
- size -= frag
- }
- heapBitsBulkBarrier(uintptr(dst), size&^(sys.PtrSize-1))
}
-// callwritebarrier is invoked at the end of reflectcall, to execute
-// write barrier operations to record the fact that a call's return
-// values have just been copied to frame, starting at retoffset
-// and continuing to framesize. The entire frame (not just the return
-// values) is described by typ. Because the copy has already
-// happened, we call writebarrierptr_nostore, and this is nosplit so
-// the copy and write barrier appear atomic to GC.
+// reflectcallmove is invoked by reflectcall to copy the return values
+// out of the stack and into the heap, invoking the necessary write
+// barriers. dst, src, and size describe the return value area to
+// copy. typ describes the entire frame (not just the return values).
+// typ may be nil, which indicates write barriers are not needed.
+//
+// It must be nosplit and must only call nosplit functions because the
+// stack map of reflectcall is wrong.
+//
//go:nosplit
-func callwritebarrier(typ *_type, frame unsafe.Pointer, framesize, retoffset uintptr) {
- if !writeBarrier.needed || typ == nil || typ.kind&kindNoPointers != 0 || framesize-retoffset < sys.PtrSize {
- return
+func reflectcallmove(typ *_type, dst, src unsafe.Pointer, size uintptr) {
+ if writeBarrier.needed && typ != nil && typ.kind&kindNoPointers == 0 && size >= sys.PtrSize {
+ bulkBarrierPreWrite(uintptr(dst), uintptr(src), size)
}
- heapBitsBulkBarrier(uintptr(add(frame, retoffset)), framesize-retoffset)
+ memmove(dst, src, size)
}
//go:nosplit
@@ -300,8 +378,51 @@ func reflect_typedslicecopy(elemType *_type, dst, src slice) int {
if n > src.len {
n = src.len
}
- memmove(dst.array, src.array, uintptr(n)*elemType.size)
+ if n == 0 {
+ return 0
+ }
+
+ size := uintptr(n) * elemType.size
+ if raceenabled {
+ callerpc := getcallerpc(unsafe.Pointer(&elemType))
+ pc := funcPC(reflect_typedslicecopy)
+ racewriterangepc(dst.array, size, callerpc, pc)
+ racereadrangepc(src.array, size, callerpc, pc)
+ }
+ if msanenabled {
+ msanwrite(dst.array, size)
+ msanread(src.array, size)
+ }
+
+ memmove(dst.array, src.array, size)
return n
}
return typedslicecopy(elemType, dst, src)
}
+
+// typedmemclr clears the typed memory at ptr with type typ. The
+// memory at ptr must already be initialized (and hence in type-safe
+// state). If the memory is being initialized for the first time, see
+// memclrNoHeapPointers.
+//
+// If the caller knows that typ has pointers, it can alternatively
+// call memclrHasPointers.
+//
+//go:nosplit
+func typedmemclr(typ *_type, ptr unsafe.Pointer) {
+ if typ.kind&kindNoPointers == 0 {
+ bulkBarrierPreWrite(uintptr(ptr), 0, typ.size)
+ }
+ memclrNoHeapPointers(ptr, typ.size)
+}
+
+// memclrHasPointers clears n bytes of typed memory starting at ptr.
+// The caller must ensure that the type of the object at ptr has
+// pointers, usually by checking typ.kind&kindNoPointers. However, ptr
+// does not have to point to the start of the allocation.
+//
+//go:nosplit
+func memclrHasPointers(ptr unsafe.Pointer, n uintptr) {
+ bulkBarrierPreWrite(uintptr(ptr), 0, n)
+ memclrNoHeapPointers(ptr, n)
+}
diff --git a/src/runtime/mbitmap.go b/src/runtime/mbitmap.go
index ccefbcd..89d8a4c 100644
--- a/src/runtime/mbitmap.go
+++ b/src/runtime/mbitmap.go
@@ -78,13 +78,13 @@ import (
const (
bitPointer = 1 << 0
- bitMarked = 1 << 4 // TODO: Rename bitScan.
+ bitScan = 1 << 4
- heapBitsShift = 1 // shift offset between successive bitPointer or bitMarked entries
+ heapBitsShift = 1 // shift offset between successive bitPointer or bitScan entries
heapBitmapScale = sys.PtrSize * (8 / 2) // number of data bytes described by one heap bitmap byte
- // all mark/pointer bits in a byte
- bitMarkedAll = bitMarked | bitMarked<<heapBitsShift | bitMarked<<(2*heapBitsShift) | bitMarked<<(3*heapBitsShift)
+ // all scan/pointer bits in a byte
+ bitScanAll = bitScan | bitScan<<heapBitsShift | bitScan<<(2*heapBitsShift) | bitScan<<(3*heapBitsShift)
bitPointerAll = bitPointer | bitPointer<<heapBitsShift | bitPointer<<(2*heapBitsShift) | bitPointer<<(3*heapBitsShift)
)
@@ -151,7 +151,7 @@ func (h *mheap) mapBits(arena_used uintptr) {
n := (arena_used - mheap_.arena_start) / heapBitmapScale
n = round(n, bitmapChunk)
- n = round(n, sys.PhysPageSize)
+ n = round(n, physPageSize)
if h.bitmap_mapped >= n {
return
}
@@ -264,7 +264,11 @@ func (s *mspan) nextFreeIndex() uintptr {
return result
}
+// isFree returns whether the index'th object in s is unallocated.
func (s *mspan) isFree(index uintptr) bool {
+ if index < s.freeindex {
+ return false
+ }
whichByte := index / 8
whichBit := index % 8
byteVal := *addb(s.allocBits, whichByte)
@@ -336,7 +340,7 @@ func (m markBits) clearMarkedNonAtomic() {
// markBitsForSpan returns the markBits for the span base address base.
func markBitsForSpan(base uintptr) (mbits markBits) {
if base < mheap_.arena_start || base >= mheap_.arena_used {
- throw("heapBitsForSpan: base out of range")
+ throw("markBitsForSpan: base out of range")
}
mbits = markBitsForAddr(base)
if mbits.mask != 1 {
@@ -394,7 +398,7 @@ func heapBitsForObject(p, refBase, refOff uintptr) (base uintptr, hbits heapBits
idx := off >> _PageShift
// p points into the heap, but possibly to the middle of an object.
// Consult the span table to find the block beginning.
- s = h_spans[idx]
+ s = mheap_.spans[idx]
if s == nil || p < s.base() || p >= s.limit || s.state != mSpanInUse {
if s == nil || s.state == _MSpanStack {
// If s is nil, the virtual address has never been part of the heap.
@@ -421,7 +425,7 @@ func heapBitsForObject(p, refBase, refOff uintptr) (base uintptr, hbits heapBits
} else {
print(" to unused region of span")
}
- print("idx=", hex(idx), " span.base()=", hex(s.base()), " span.limit=", hex(s.limit), " span.state=", s.state, "\n")
+ print(" idx=", hex(idx), " span.base()=", hex(s.base()), " span.limit=", hex(s.limit), " span.state=", s.state, "\n")
if refBase != 0 {
print("runtime: found in object at *(", hex(refBase), "+", hex(refOff), ")\n")
gcDumpObject("object", refBase, refOff)
@@ -435,7 +439,7 @@ func heapBitsForObject(p, refBase, refOff uintptr) (base uintptr, hbits heapBits
if s.baseMask != 0 {
// optimize for power of 2 sized objects.
base = s.base()
- base = base + (p-base)&s.baseMask
+ base = base + (p-base)&uintptr(s.baseMask)
objIndex = (base - s.base()) >> s.divShift
// base = p & s.baseMask is faster for small spans,
// but doesn't work for large spans.
@@ -444,7 +448,7 @@ func heapBitsForObject(p, refBase, refOff uintptr) (base uintptr, hbits heapBits
base = s.base()
if p-base >= s.elemsize {
// n := (p - base) / s.elemsize, using division by multiplication
- objIndex = uintptr(uint64(p-base) >> s.divShift * uint64(s.divMul) >> s.divShift2)
+ objIndex = uintptr(p-base) >> s.divShift * uintptr(s.divMul) >> s.divShift2
base += objIndex * s.elemsize
}
}
@@ -481,7 +485,7 @@ func (h heapBits) forward(n uintptr) heapBits {
return heapBits{subtractb(h.bitp, n/4), uint32(n%4) * heapBitsShift}
}
-// The caller can test isMarked and isPointer by &-ing with bitMarked and bitPointer.
+// The caller can test morePointers and isPointer by &-ing with bitScan and bitPointer.
// The result includes in its higher bits the bits for subsequent words
// described by the same bitmap byte.
func (h heapBits) bits() uint32 {
@@ -494,7 +498,7 @@ func (h heapBits) bits() uint32 {
// are scalars.
// h must not describe the second word of the object.
func (h heapBits) morePointers() bool {
- return h.bits()&bitMarked != 0
+ return h.bits()&bitScan != 0
}
// isPointer reports whether the heap bits describe a pointer word.
@@ -512,7 +516,7 @@ func (h heapBits) hasPointers(size uintptr) bool {
if size == sys.PtrSize { // 1-word objects are always pointers
return true
}
- return (*h.bitp>>h.shift)&bitMarked != 0
+ return (*h.bitp>>h.shift)&bitScan != 0
}
// isCheckmarked reports whether the heap bits have the checkmarked bit set.
@@ -527,7 +531,7 @@ func (h heapBits) isCheckmarked(size uintptr) bool {
// so we know that the initial word's 2-bit pair
// and the second word's 2-bit pair are in the
// same heap bitmap byte, *h.bitp.
- return (*h.bitp>>(heapBitsShift+h.shift))&bitMarked != 0
+ return (*h.bitp>>(heapBitsShift+h.shift))&bitScan != 0
}
// setCheckmarked sets the checkmarked bit.
@@ -539,96 +543,114 @@ func (h heapBits) setCheckmarked(size uintptr) {
atomic.Or8(h.bitp, bitPointer<<h.shift)
return
}
- atomic.Or8(h.bitp, bitMarked<<(heapBitsShift+h.shift))
+ atomic.Or8(h.bitp, bitScan<<(heapBitsShift+h.shift))
}
-// heapBitsBulkBarrier executes writebarrierptr_nostore
-// for every pointer slot in the memory range [p, p+size),
-// using the heap, data, or BSS bitmap to locate those pointer slots.
-// This executes the write barriers necessary after a memmove.
-// Both p and size must be pointer-aligned.
-// The range [p, p+size) must lie within a single object.
+// bulkBarrierPreWrite executes writebarrierptr_prewrite1
+// for every pointer slot in the memory range [src, src+size),
+// using pointer/scalar information from [dst, dst+size).
+// This executes the write barriers necessary before a memmove.
+// src, dst, and size must be pointer-aligned.
+// The range [dst, dst+size) must lie within a single object.
+//
+// As a special case, src == 0 indicates that this is being used for a
+// memclr. bulkBarrierPreWrite will pass 0 for the src of each write
+// barrier.
//
-// Callers should call heapBitsBulkBarrier immediately after
-// calling memmove(p, src, size). This function is marked nosplit
+// Callers should call bulkBarrierPreWrite immediately before
+// calling memmove(dst, src, size). This function is marked nosplit
// to avoid being preempted; the GC must not stop the goroutine
// between the memmove and the execution of the barriers.
+// The caller is also responsible for cgo pointer checks if this
+// may be writing Go pointers into non-Go memory.
//
-// The heap bitmap is not maintained for allocations containing
-// no pointers at all; any caller of heapBitsBulkBarrier must first
+// The pointer bitmap is not maintained for allocations containing
+// no pointers at all; any caller of bulkBarrierPreWrite must first
// make sure the underlying allocation contains pointers, usually
// by checking typ.kind&kindNoPointers.
//
//go:nosplit
-func heapBitsBulkBarrier(p, size uintptr) {
- if (p|size)&(sys.PtrSize-1) != 0 {
- throw("heapBitsBulkBarrier: unaligned arguments")
+func bulkBarrierPreWrite(dst, src, size uintptr) {
+ if (dst|src|size)&(sys.PtrSize-1) != 0 {
+ throw("bulkBarrierPreWrite: unaligned arguments")
}
if !writeBarrier.needed {
return
}
- if !inheap(p) {
- // If p is on the stack and in a higher frame than the
+ 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 p.
+ // frame containing dst.
//
- // Executing write barriers on p is complicated in the
+ // 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 p, which we can do by simply
+ // frame containing dst, which we can do by simply
// unwinding the stack barriers between the current SP
- // and p's frame.
+ // and dst's frame.
gp := getg().m.curg
- if gp != nil && gp.stack.lo <= p && p < gp.stack.hi {
+ 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, p)
+ gcUnwindBarriers(gp, dst)
})
return
}
- // If p is a global, use the data or BSS bitmaps to
+ // If dst is a global, use the data or BSS bitmaps to
// execute write barriers.
- for datap := &firstmoduledata; datap != nil; datap = datap.next {
- if datap.data <= p && p < datap.edata {
- bulkBarrierBitmap(p, size, p-datap.data, datap.gcdatamask.bytedata)
+ for _, datap := range activeModules() {
+ if datap.data <= dst && dst < datap.edata {
+ bulkBarrierBitmap(dst, src, size, dst-datap.data, datap.gcdatamask.bytedata)
return
}
}
- for datap := &firstmoduledata; datap != nil; datap = datap.next {
- if datap.bss <= p && p < datap.ebss {
- bulkBarrierBitmap(p, size, p-datap.bss, datap.gcbssmask.bytedata)
+ for _, datap := range activeModules() {
+ if datap.bss <= dst && dst < datap.ebss {
+ bulkBarrierBitmap(dst, src, size, dst-datap.bss, datap.gcbssmask.bytedata)
return
}
}
return
}
- h := heapBitsForAddr(p)
- for i := uintptr(0); i < size; i += sys.PtrSize {
- if h.isPointer() {
- x := (*uintptr)(unsafe.Pointer(p + i))
- writebarrierptr_nostore(x, *x)
+ h := heapBitsForAddr(dst)
+ if src == 0 {
+ for i := uintptr(0); i < size; i += sys.PtrSize {
+ if h.isPointer() {
+ dstx := (*uintptr)(unsafe.Pointer(dst + i))
+ writebarrierptr_prewrite1(dstx, 0)
+ }
+ h = h.next()
+ }
+ } else {
+ for i := uintptr(0); i < size; i += sys.PtrSize {
+ if h.isPointer() {
+ dstx := (*uintptr)(unsafe.Pointer(dst + i))
+ srcx := (*uintptr)(unsafe.Pointer(src + i))
+ writebarrierptr_prewrite1(dstx, *srcx)
+ }
+ h = h.next()
}
- h = h.next()
}
}
-// bulkBarrierBitmap executes write barriers for [p, p+size) using a
-// 1-bit pointer bitmap. p is assumed to start maskOffset bytes into
-// the data covered by the bitmap in bits.
+// bulkBarrierBitmap executes write barriers for copying from [src,
+// src+size) to [dst, dst+size) using a 1-bit pointer bitmap. src is
+// assumed to start maskOffset bytes into the data covered by the
+// bitmap in bits (which may not be a multiple of 8).
//
-// This is used by heapBitsBulkBarrier for writes to data and BSS.
+// This is used by bulkBarrierPreWrite for writes to data and BSS.
//
//go:nosplit
-func bulkBarrierBitmap(p, size, maskOffset uintptr, bits *uint8) {
+func bulkBarrierBitmap(dst, src, size, maskOffset uintptr, bits *uint8) {
word := maskOffset / sys.PtrSize
bits = addb(bits, word/8)
mask := uint8(1) << (word % 8)
@@ -644,28 +666,34 @@ func bulkBarrierBitmap(p, size, maskOffset uintptr, bits *uint8) {
mask = 1
}
if *bits&mask != 0 {
- x := (*uintptr)(unsafe.Pointer(p + i))
- writebarrierptr_nostore(x, *x)
+ dstx := (*uintptr)(unsafe.Pointer(dst + i))
+ if src == 0 {
+ writebarrierptr_prewrite1(dstx, 0)
+ } else {
+ srcx := (*uintptr)(unsafe.Pointer(src + i))
+ writebarrierptr_prewrite1(dstx, *srcx)
+ }
}
mask <<= 1
}
}
-// typeBitsBulkBarrier executes writebarrierptr_nostore
-// for every pointer slot in the memory range [p, p+size),
-// using the type bitmap to locate those pointer slots.
-// The type typ must correspond exactly to [p, p+size).
-// This executes the write barriers necessary after a copy.
-// Both p and size must be pointer-aligned.
+// typeBitsBulkBarrier executes writebarrierptr_prewrite for every
+// pointer that would be copied from [src, src+size) to [dst,
+// dst+size) by a memmove using the type bitmap to locate those
+// pointer slots.
+//
+// The type typ must correspond exactly to [src, src+size) and [dst, dst+size).
+// dst, src, and size must be pointer-aligned.
// The type typ must have a plain bitmap, not a GC program.
// The only use of this function is in channel sends, and the
// 64 kB channel element limit takes care of this for us.
//
-// Must not be preempted because it typically runs right after memmove,
-// and the GC must not complete between those two.
+// Must not be preempted because it typically runs right before memmove,
+// and the GC must observe them as an atomic action.
//
//go:nosplit
-func typeBitsBulkBarrier(typ *_type, p, size uintptr) {
+func typeBitsBulkBarrier(typ *_type, dst, src, size uintptr) {
if typ == nil {
throw("runtime: typeBitsBulkBarrier without type")
}
@@ -690,8 +718,9 @@ func typeBitsBulkBarrier(typ *_type, p, size uintptr) {
bits = bits >> 1
}
if bits&1 != 0 {
- x := (*uintptr)(unsafe.Pointer(p + i))
- writebarrierptr_nostore(x, *x)
+ dstx := (*uintptr)(unsafe.Pointer(dst + i))
+ srcx := (*uintptr)(unsafe.Pointer(src + i))
+ writebarrierptr_prewrite(dstx, *srcx)
}
}
}
@@ -730,7 +759,7 @@ func (h heapBits) initSpan(s *mspan) {
end := h.bitp
bitp := subtractb(end, nbyte-1)
for {
- *bitp = bitPointerAll | bitMarkedAll
+ *bitp = bitPointerAll | bitScanAll
if bitp == end {
break
}
@@ -738,7 +767,7 @@ func (h heapBits) initSpan(s *mspan) {
}
return
}
- memclr(unsafe.Pointer(subtractb(h.bitp, nbyte-1)), nbyte)
+ memclrNoHeapPointers(unsafe.Pointer(subtractb(h.bitp, nbyte-1)), nbyte)
}
// initCheckmarkSpan initializes a span for being checkmarked.
@@ -758,7 +787,7 @@ func (h heapBits) initCheckmarkSpan(size, n, total uintptr) {
return
}
for i := uintptr(0); i < n; i++ {
- *h.bitp &^= bitMarked << (heapBitsShift + h.shift)
+ *h.bitp &^= bitScan << (heapBitsShift + h.shift)
h = h.forward(size / sys.PtrSize)
}
}
@@ -861,9 +890,6 @@ func (s *mspan) countFree() int {
// bits that belong to neighboring objects. Also, on weakly-ordered
// machines, callers must execute a store/store (publication) barrier
// between calling this function and making the object reachable.
-//
-// TODO: This still has atomic accesses left over from when it could
-// race with GC accessing mark bits in the bitmap. Remove these.
func heapBitsSetType(x, size, dataSize uintptr, typ *_type) {
const doubleCheck = false // slow but helpful; enable to test modifications to this code
@@ -877,11 +903,7 @@ func heapBitsSetType(x, size, dataSize uintptr, typ *_type) {
if sys.PtrSize == 8 && size == sys.PtrSize {
// It's one word and it has pointers, it must be a pointer.
- // In general we'd need an atomic update here if the
- // concurrent GC were marking objects in this span,
- // because each bitmap byte describes 3 other objects
- // in addition to the one being allocated.
- // However, since all allocated one-word objects are pointers
+ // Since all allocated one-word objects are pointers
// (non-pointers are aggregated into tinySize allocations),
// initSpan sets the pointer bits for us. Nothing to do here.
if doubleCheck {
@@ -900,7 +922,7 @@ func heapBitsSetType(x, size, dataSize uintptr, typ *_type) {
ptrmask := typ.gcdata // start of 1-bit pointer mask (or GC program, handled below)
// Heap bitmap bits for 2-word object are only 4 bits,
- // so also shared with objects next to it; use atomic updates.
+ // so also shared with objects next to it.
// This is called out as a special case primarily for 32-bit systems,
// so that on 32-bit systems the code below can assume all objects
// are 4-word aligned (because they're all 16-byte aligned).
@@ -917,20 +939,11 @@ func heapBitsSetType(x, size, dataSize uintptr, typ *_type) {
if sys.PtrSize == 4 && dataSize == sys.PtrSize {
// 1 pointer object. On 32-bit machines clear the bit for the
// unused second word.
- if gcphase == _GCoff {
- *h.bitp &^= (bitPointer | bitMarked | ((bitPointer | bitMarked) << heapBitsShift)) << h.shift
- *h.bitp |= (bitPointer | bitMarked) << h.shift
- } else {
- atomic.And8(h.bitp, ^uint8((bitPointer|bitMarked|((bitPointer|bitMarked)<<heapBitsShift))<<h.shift))
- atomic.Or8(h.bitp, (bitPointer|bitMarked)<<h.shift)
- }
+ *h.bitp &^= (bitPointer | bitScan | ((bitPointer | bitScan) << heapBitsShift)) << h.shift
+ *h.bitp |= (bitPointer | bitScan) << h.shift
} else {
// 2-element slice of pointer.
- if gcphase == _GCoff {
- *h.bitp |= (bitPointer | bitMarked | bitPointer<<heapBitsShift) << h.shift
- } else {
- atomic.Or8(h.bitp, (bitPointer|bitMarked|bitPointer<<heapBitsShift)<<h.shift)
- }
+ *h.bitp |= (bitPointer | bitScan | bitPointer<<heapBitsShift) << h.shift
}
return
}
@@ -943,23 +956,13 @@ func heapBitsSetType(x, size, dataSize uintptr, typ *_type) {
}
}
b := uint32(*ptrmask)
- hb := (b & 3) | bitMarked
- if gcphase == _GCoff {
- // bitPointer == 1, bitMarked is 1 << 4, heapBitsShift is 1.
- // 110011 is shifted h.shift and complemented.
- // This clears out the bits that are about to be
- // ored into *h.hbitp in the next instructions.
- *h.bitp &^= (bitPointer | bitMarked | ((bitPointer | bitMarked) << heapBitsShift)) << h.shift
- *h.bitp |= uint8(hb << h.shift)
- } else {
- // TODO:(rlh) since the GC is not concurrently setting the
- // mark bits in the heap map anymore and malloc
- // owns the span we are allocating in why does this have
- // to be atomic?
-
- atomic.And8(h.bitp, ^uint8((bitPointer|bitMarked|((bitPointer|bitMarked)<<heapBitsShift))<<h.shift))
- atomic.Or8(h.bitp, uint8(hb<<h.shift))
- }
+ hb := (b & 3) | bitScan
+ // bitPointer == 1, bitScan is 1 << 4, heapBitsShift is 1.
+ // 110011 is shifted h.shift and complemented.
+ // This clears out the bits that are about to be
+ // ored into *h.hbitp in the next instructions.
+ *h.bitp &^= (bitPointer | bitScan | ((bitPointer | bitScan) << heapBitsShift)) << h.shift
+ *h.bitp |= uint8(hb << h.shift)
return
}
@@ -1128,9 +1131,9 @@ func heapBitsSetType(x, size, dataSize uintptr, typ *_type) {
// Phase 1: Special case for leading byte (shift==0) or half-byte (shift==4).
// The leading byte is special because it contains the bits for word 1,
- // which does not have the marked bits set.
- // The leading half-byte is special because it's a half a byte and must be
- // manipulated atomically.
+ // which does not have the scan bit set.
+ // The leading half-byte is special because it's a half a byte,
+ // so we have to be careful with the bits already there.
switch {
default:
throw("heapBitsSetType: unexpected shift")
@@ -1151,7 +1154,7 @@ func heapBitsSetType(x, size, dataSize uintptr, typ *_type) {
// TODO: It doesn't matter if we set the checkmark, so
// maybe this case isn't needed any more.
hb = b & bitPointerAll
- hb |= bitMarked | bitMarked<<(2*heapBitsShift) | bitMarked<<(3*heapBitsShift)
+ hb |= bitScan | bitScan<<(2*heapBitsShift) | bitScan<<(3*heapBitsShift)
if w += 4; w >= nw {
goto Phase3
}
@@ -1162,30 +1165,21 @@ func heapBitsSetType(x, size, dataSize uintptr, typ *_type) {
case sys.PtrSize == 8 && h.shift == 2:
// Ptrmask and heap bitmap are misaligned.
- // The bits for the first two words are in a byte shared with another object
- // and must be updated atomically.
- // NOTE(rsc): The atomic here may not be necessary.
+ // The bits for the first two words are in a byte shared
+ // with another object, so we must be careful with the bits
+ // already there.
// We took care of 1-word and 2-word objects above,
- // so this is at least a 6-word object, so our start bits
- // are shared only with the type bits of another object,
- // not with its mark bit. Since there is only one allocation
- // from a given span at a time, we should be able to set
- // these bits non-atomically. Not worth the risk right now.
+ // so this is at least a 6-word object.
hb = (b & (bitPointer | bitPointer<<heapBitsShift)) << (2 * heapBitsShift)
// This is not noscan, so set the scan bit in the
// first word.
- hb |= bitMarked << (2 * heapBitsShift)
+ hb |= bitScan << (2 * heapBitsShift)
b >>= 2
nb -= 2
- // Note: no bitMarker for second word because that's
+ // Note: no bitScan for second word because that's
// the checkmark.
- if gcphase == _GCoff {
- *hbitp &^= uint8((bitPointer | bitMarked | (bitPointer << heapBitsShift)) << (2 * heapBitsShift))
- *hbitp |= uint8(hb)
- } else {
- atomic.And8(hbitp, ^(uint8(bitPointer|bitMarked|bitPointer<<heapBitsShift) << (2 * heapBitsShift)))
- atomic.Or8(hbitp, uint8(hb))
- }
+ *hbitp &^= uint8((bitPointer | bitScan | (bitPointer << heapBitsShift)) << (2 * heapBitsShift))
+ *hbitp |= uint8(hb)
hbitp = subtract1(hbitp)
if w += 2; w >= nw {
// We know that there is more data, because we handled 2-word objects above.
@@ -1211,7 +1205,7 @@ func heapBitsSetType(x, size, dataSize uintptr, typ *_type) {
// but we'll stop at the break and then truncate
// appropriately in Phase 3.
hb = b & bitPointerAll
- hb |= bitMarkedAll
+ hb |= bitScanAll
if w += 4; w >= nw {
break
}
@@ -1259,7 +1253,7 @@ func heapBitsSetType(x, size, dataSize uintptr, typ *_type) {
// Emit bitmap byte.
hb = b & bitPointerAll
- hb |= bitMarkedAll
+ hb |= bitScanAll
if w += 4; w >= nw {
break
}
@@ -1275,7 +1269,7 @@ Phase3:
// there are more entries than possible pointer slots.
// Discard the excess entries (can't be more than 3).
mask := uintptr(1)<<(4-(w-nw)) - 1
- hb &= mask | mask<<4 // apply mask to both pointer bits and mark bits
+ hb &= mask | mask<<4 // apply mask to both pointer bits and scan bits
}
// Change nw from counting possibly-pointer words to total words in allocation.
@@ -1299,14 +1293,10 @@ Phase3:
// If w == nw+4 then there's nothing left to do: we wrote all nw entries
// and can discard the 4 sitting in hb.
// But if w == nw+2, we need to write first two in hb.
- // The byte is shared with the next object so we may need an atomic.
+ // The byte is shared with the next object, so be careful with
+ // existing bits.
if w == nw+2 {
- if gcphase == _GCoff {
- *hbitp = *hbitp&^(bitPointer|bitMarked|(bitPointer|bitMarked)<<heapBitsShift) | uint8(hb)
- } else {
- atomic.And8(hbitp, ^uint8(bitPointer|bitMarked|(bitPointer|bitMarked)<<heapBitsShift))
- atomic.Or8(hbitp, uint8(hb))
- }
+ *hbitp = *hbitp&^(bitPointer|bitScan|(bitPointer|bitScan)<<heapBitsShift) | uint8(hb)
}
Phase4:
@@ -1333,20 +1323,20 @@ Phase4:
for i := uintptr(0); i < size/sys.PtrSize; i++ {
j := i % ndata
var have, want uint8
- have = (*h.bitp >> h.shift) & (bitPointer | bitMarked)
+ have = (*h.bitp >> h.shift) & (bitPointer | bitScan)
if i >= totalptr {
want = 0 // deadmarker
if typ.kind&kindGCProg != 0 && i < (totalptr+3)/4*4 {
- want = bitMarked
+ want = bitScan
}
} else {
if j < nptr && (*addb(ptrmask, j/8)>>(j%8))&1 != 0 {
want |= bitPointer
}
if i != 1 {
- want |= bitMarked
+ want |= bitScan
} else {
- have &^= bitMarked
+ have &^= bitScan
}
}
if have != want {
@@ -1377,7 +1367,7 @@ Phase4:
// of x in the heap bitmap to scalar/dead.
func heapBitsSetTypeNoScan(x uintptr) {
h := heapBitsForAddr(uintptr(x))
- *h.bitp &^= (bitPointer | bitMarked) << h.shift
+ *h.bitp &^= (bitPointer | bitScan) << h.shift
}
var debugPtrmask struct {
@@ -1394,7 +1384,7 @@ var debugPtrmask struct {
// GC programs are only used for large allocations.
// heapBitsSetType requires that allocSize is a multiple of 4 words,
// so that the relevant bitmap bytes are not shared with surrounding
-// objects and need not be accessed with atomic instructions.
+// objects.
func heapBitsSetTypeGCProg(h heapBits, progSize, elemSize, dataSize, allocSize uintptr, prog *byte) {
if sys.PtrSize == 8 && allocSize%(4*sys.PtrSize) != 0 {
// Alignment will be wrong.
@@ -1468,7 +1458,7 @@ func heapBitsSetTypeGCProg(h heapBits, progSize, elemSize, dataSize, allocSize u
}
endProg := unsafe.Pointer(subtractb(h.bitp, (totalBits+3)/4))
endAlloc := unsafe.Pointer(subtractb(h.bitp, allocSize/heapBitmapScale))
- memclr(add(endAlloc, 1), uintptr(endProg)-uintptr(endAlloc))
+ memclrNoHeapPointers(add(endAlloc, 1), uintptr(endProg)-uintptr(endAlloc))
}
// progToPointerMask returns the 1-bit pointer mask output by the GC program prog.
@@ -1525,11 +1515,11 @@ Run:
dst = add1(dst)
bits >>= 8
} else {
- v := bits&bitPointerAll | bitMarkedAll
+ v := bits&bitPointerAll | bitScanAll
*dst = uint8(v)
dst = subtract1(dst)
bits >>= 4
- v = bits&bitPointerAll | bitMarkedAll
+ v = bits&bitPointerAll | bitScanAll
*dst = uint8(v)
dst = subtract1(dst)
bits >>= 4
@@ -1563,11 +1553,11 @@ Run:
dst = add1(dst)
bits >>= 8
} else {
- v := bits&0xf | bitMarkedAll
+ v := bits&0xf | bitScanAll
*dst = uint8(v)
dst = subtract1(dst)
bits >>= 4
- v = bits&0xf | bitMarkedAll
+ v = bits&0xf | bitScanAll
*dst = uint8(v)
dst = subtract1(dst)
bits >>= 4
@@ -1694,7 +1684,7 @@ Run:
}
} else {
for nbits >= 4 {
- *dst = uint8(bits&0xf | bitMarkedAll)
+ *dst = uint8(bits&0xf | bitScanAll)
dst = subtract1(dst)
bits >>= 4
nbits -= 4
@@ -1752,7 +1742,7 @@ Run:
for i := c / 4; i > 0; i-- {
bits |= (uintptr(*src) & 0xf) << nbits
src = subtract1(src)
- *dst = uint8(bits&0xf | bitMarkedAll)
+ *dst = uint8(bits&0xf | bitScanAll)
dst = subtract1(dst)
bits >>= 4
}
@@ -1778,7 +1768,7 @@ Run:
totalBits = (uintptr(unsafe.Pointer(dstStart))-uintptr(unsafe.Pointer(dst)))*4 + nbits
nbits += -nbits & 3
for ; nbits > 0; nbits -= 4 {
- v := bits&0xf | bitMarkedAll
+ v := bits&0xf | bitScanAll
*dst = uint8(v)
dst = subtract1(dst)
bits >>= 4
@@ -1862,7 +1852,7 @@ func getgcmask(ep interface{}) (mask []byte) {
p := e.data
t := e._type
// data or bss
- for datap := &firstmoduledata; datap != nil; datap = datap.next {
+ for _, datap := range activeModules() {
// data
if datap.data <= uintptr(p) && uintptr(p) < datap.edata {
bitmap := datap.gcdatamask.bytedata
diff --git a/src/runtime/mcache.go b/src/runtime/mcache.go
index 5938e53..c483310 100644
--- a/src/runtime/mcache.go
+++ b/src/runtime/mcache.go
@@ -11,6 +11,8 @@ import "unsafe"
//
// mcaches are allocated from non-GC'd memory, so any heap pointers
// must be specially handled.
+//
+//go:notinheap
type mcache struct {
// The following members are accessed on every malloc,
// so they are grouped here for better caching.
@@ -75,7 +77,6 @@ func allocmcache() *mcache {
lock(&mheap_.lock)
c := (*mcache)(mheap_.cachealloc.alloc())
unlock(&mheap_.lock)
- memclr(unsafe.Pointer(c), unsafe.Sizeof(*c))
for i := 0; i < _NumSizeClasses; i++ {
c.alloc[i] = &emptymspan
}
diff --git a/src/runtime/mcentral.go b/src/runtime/mcentral.go
index 7b63110..ddcf81e 100644
--- a/src/runtime/mcentral.go
+++ b/src/runtime/mcentral.go
@@ -15,6 +15,8 @@ package runtime
import "runtime/internal/atomic"
// Central list of free objects of a given size.
+//
+//go:notinheap
type mcentral struct {
lock mutex
sizeclass int32
diff --git a/src/runtime/mem_linux.go b/src/runtime/mem_linux.go
index cd0bf26..094658d 100644
--- a/src/runtime/mem_linux.go
+++ b/src/runtime/mem_linux.go
@@ -22,17 +22,14 @@ const (
var addrspace_vec [1]byte
func addrspace_free(v unsafe.Pointer, n uintptr) bool {
- // Step by the minimum possible physical page size. This is
- // safe even if we have the wrong physical page size; mincore
- // will just return EINVAL for unaligned addresses.
- for off := uintptr(0); off < n; off += minPhysPageSize {
+ for off := uintptr(0); off < n; off += physPageSize {
// Use a length of 1 byte, which the kernel will round
// up to one physical page regardless of the true
// physical page size.
errval := mincore(unsafe.Pointer(uintptr(v)+off), 1, &addrspace_vec[0])
if errval == -_EINVAL {
// Address is not a multiple of the physical
- // page size. That's fine.
+ // page size. Shouldn't happen, but just ignore it.
continue
}
// ENOMEM means unmapped, which is what we want.
@@ -138,7 +135,7 @@ func sysUnused(v unsafe.Pointer, n uintptr) {
}
}
- if uintptr(v)&(sys.PhysPageSize-1) != 0 || n&(sys.PhysPageSize-1) != 0 {
+ if uintptr(v)&(physPageSize-1) != 0 || n&(physPageSize-1) != 0 {
// madvise will round this to any physical page
// *covered* by this range, so an unaligned madvise
// will release more memory than intended.
diff --git a/src/runtime/mem_plan9.go b/src/runtime/mem_plan9.go
index 3d82a98..98bfc7f 100644
--- a/src/runtime/mem_plan9.go
+++ b/src/runtime/mem_plan9.go
@@ -38,7 +38,7 @@ func memAlloc(n uintptr) unsafe.Pointer {
p.size -= n
p = (*memHdr)(add(unsafe.Pointer(p), p.size))
}
- memclr(unsafe.Pointer(p), unsafe.Sizeof(memHdr{}))
+ *p = memHdr{}
return unsafe.Pointer(p)
}
prevp = p
@@ -48,7 +48,7 @@ func memAlloc(n uintptr) unsafe.Pointer {
func memFree(ap unsafe.Pointer, n uintptr) {
n = memRound(n)
- memclr(ap, n)
+ memclrNoHeapPointers(ap, n)
bp := (*memHdr)(ap)
bp.size = n
bpn := uintptr(ap)
@@ -63,7 +63,7 @@ func memFree(ap unsafe.Pointer, n uintptr) {
if bpn+bp.size == uintptr(unsafe.Pointer(p)) {
bp.size += p.size
bp.next = p.next
- memclr(unsafe.Pointer(p), unsafe.Sizeof(memHdr{}))
+ *p = memHdr{}
} else {
bp.next.set(p)
}
@@ -77,14 +77,14 @@ func memFree(ap unsafe.Pointer, n uintptr) {
if bpn+bp.size == uintptr(unsafe.Pointer(p.next)) {
bp.size += p.next.ptr().size
bp.next = p.next.ptr().next
- memclr(unsafe.Pointer(p.next), unsafe.Sizeof(memHdr{}))
+ *p.next.ptr() = memHdr{}
} else {
bp.next = p.next
}
if uintptr(unsafe.Pointer(p))+p.size == bpn {
p.size += bp.size
p.next = bp.next
- memclr(unsafe.Pointer(bp), unsafe.Sizeof(memHdr{}))
+ *bp = memHdr{}
} else {
p.next.set(bp)
}
diff --git a/src/runtime/memclr_386.s b/src/runtime/memclr_386.s
index ce962f3..ef6e602 100644
--- a/src/runtime/memclr_386.s
+++ b/src/runtime/memclr_386.s
@@ -8,8 +8,8 @@
// NOTE: Windows externalthreadhandler expects memclr to preserve DX.
-// void runtime·memclr(void*, uintptr)
-TEXT runtime·memclr(SB), NOSPLIT, $0-8
+// void runtime·memclrNoHeapPointers(void*, uintptr)
+TEXT runtime·memclrNoHeapPointers(SB), NOSPLIT, $0-8
MOVL ptr+0(FP), DI
MOVL n+4(FP), BX
XORL AX, AX
diff --git a/src/runtime/memclr_amd64.s b/src/runtime/memclr_amd64.s
index 6f30eca..244f5b4 100644
--- a/src/runtime/memclr_amd64.s
+++ b/src/runtime/memclr_amd64.s
@@ -8,8 +8,8 @@
// NOTE: Windows externalthreadhandler expects memclr to preserve DX.
-// void runtime·memclr(void*, uintptr)
-TEXT runtime·memclr(SB), NOSPLIT, $0-16
+// void runtime·memclrNoHeapPointers(void*, uintptr)
+TEXT runtime·memclrNoHeapPointers(SB), NOSPLIT, $0-16
MOVQ ptr+0(FP), DI
MOVQ n+8(FP), BX
XORQ AX, AX
diff --git a/src/runtime/memclr_arm.s b/src/runtime/memclr_arm.s
index c9b8586..eb37674 100644
--- a/src/runtime/memclr_arm.s
+++ b/src/runtime/memclr_arm.s
@@ -1,5 +1,5 @@
// Inferno's libkern/memset-arm.s
-// http://code.google.com/p/inferno-os/source/browse/libkern/memset-arm.s
+// https://bitbucket.org/inferno-os/inferno-os/src/default/libkern/memset-arm.s
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com). All rights reserved.
@@ -30,7 +30,7 @@
#define N R12
#define TMP R12 /* N and TMP don't overlap */
-TEXT runtime·memclr(SB),NOSPLIT,$0-8
+TEXT runtime·memclrNoHeapPointers(SB),NOSPLIT,$0-8
MOVW ptr+0(FP), TO
MOVW n+4(FP), N
MOVW $0, R0
diff --git a/src/runtime/memclr_arm64.s b/src/runtime/memclr_arm64.s
index 47c6b73..9d756bc 100644
--- a/src/runtime/memclr_arm64.s
+++ b/src/runtime/memclr_arm64.s
@@ -4,8 +4,8 @@
#include "textflag.h"
-// void runtime·memclr(void*, uintptr)
-TEXT runtime·memclr(SB),NOSPLIT,$0-16
+// void runtime·memclrNoHeapPointers(void*, uintptr)
+TEXT runtime·memclrNoHeapPointers(SB),NOSPLIT,$0-16
MOVD ptr+0(FP), R3
MOVD n+8(FP), R4
// TODO(mwhudson): this is written this way to avoid tickling
diff --git a/src/runtime/memclr_mips64x.s b/src/runtime/memclr_mips64x.s
index 30a4af3..5018d43 100644
--- a/src/runtime/memclr_mips64x.s
+++ b/src/runtime/memclr_mips64x.s
@@ -6,8 +6,8 @@
#include "textflag.h"
-// void runtime·memclr(void*, uintptr)
-TEXT runtime·memclr(SB),NOSPLIT,$0-16
+// void runtime·memclrNoHeapPointers(void*, uintptr)
+TEXT runtime·memclrNoHeapPointers(SB),NOSPLIT,$0-16
MOVV ptr+0(FP), R1
MOVV n+8(FP), R2
ADDV R1, R2, R4
diff --git a/src/runtime/memclr_mipsx.s b/src/runtime/memclr_mipsx.s
new file mode 100644
index 0000000..ad013b8
--- /dev/null
+++ b/src/runtime/memclr_mipsx.s
@@ -0,0 +1,71 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build mips mipsle
+
+#include "textflag.h"
+
+#ifdef GOARCH_mips
+#define MOVWHI MOVWL
+#define MOVWLO MOVWR
+#else
+#define MOVWHI MOVWR
+#define MOVWLO MOVWL
+#endif
+
+// void runtime·memclrNoHeapPointers(void*, uintptr)
+TEXT runtime·memclrNoHeapPointers(SB),NOSPLIT,$0-8
+ MOVW n+4(FP), R2
+ MOVW ptr+0(FP), R1
+
+ SGTU $4, R2, R3
+ ADDU R2, R1, R4
+ BNE R3, small_zero
+
+ptr_align:
+ AND $3, R1, R3
+ BEQ R3, setup
+ SUBU R1, R0, R3
+ AND $3, R3 // R3 contains number of bytes needed to align ptr
+ MOVWHI R0, 0(R1) // MOVWHI will write zeros up to next word boundary
+ SUBU R3, R2
+ ADDU R3, R1
+
+setup:
+ AND $31, R2, R6
+ AND $3, R2, R5
+ SUBU R6, R4, R6 // end pointer for 32-byte chunks
+ SUBU R5, R4, R5 // end pointer for 4-byte chunks
+
+large:
+ BEQ R1, R6, words
+ MOVW R0, 0(R1)
+ MOVW R0, 4(R1)
+ MOVW R0, 8(R1)
+ MOVW R0, 12(R1)
+ MOVW R0, 16(R1)
+ MOVW R0, 20(R1)
+ MOVW R0, 24(R1)
+ MOVW R0, 28(R1)
+ ADDU $32, R1
+ JMP large
+
+words:
+ BEQ R1, R5, tail
+ MOVW R0, 0(R1)
+ ADDU $4, R1
+ JMP words
+
+tail:
+ BEQ R1, R4, ret
+ MOVWLO R0, -1(R4)
+
+ret:
+ RET
+
+small_zero:
+ BEQ R1, R4, ret
+ MOVB R0, 0(R1)
+ ADDU $1, R1
+ JMP small_zero
diff --git a/src/runtime/memclr_plan9_386.s b/src/runtime/memclr_plan9_386.s
index 4707ab2..c3d92a9 100644
--- a/src/runtime/memclr_plan9_386.s
+++ b/src/runtime/memclr_plan9_386.s
@@ -4,8 +4,8 @@
#include "textflag.h"
-// void runtime·memclr(void*, uintptr)
-TEXT runtime·memclr(SB), NOSPLIT, $0-8
+// void runtime·memclrNoHeapPointers(void*, uintptr)
+TEXT runtime·memclrNoHeapPointers(SB), NOSPLIT, $0-8
MOVL ptr+0(FP), DI
MOVL n+4(FP), BX
XORL AX, AX
diff --git a/src/runtime/memclr_plan9_amd64.s b/src/runtime/memclr_plan9_amd64.s
index 37e61df..d4d1a3a 100644
--- a/src/runtime/memclr_plan9_amd64.s
+++ b/src/runtime/memclr_plan9_amd64.s
@@ -4,8 +4,8 @@
#include "textflag.h"
-// void runtime·memclr(void*, uintptr)
-TEXT runtime·memclr(SB),NOSPLIT,$0-16
+// void runtime·memclrNoHeapPointers(void*, uintptr)
+TEXT runtime·memclrNoHeapPointers(SB),NOSPLIT,$0-16
MOVQ ptr+0(FP), DI
MOVQ n+8(FP), CX
MOVQ CX, BX
diff --git a/src/runtime/memclr_ppc64x.s b/src/runtime/memclr_ppc64x.s
index 442faa2..e3a4673 100644
--- a/src/runtime/memclr_ppc64x.s
+++ b/src/runtime/memclr_ppc64x.s
@@ -6,26 +6,57 @@
#include "textflag.h"
-// void runtime·memclr(void*, uintptr)
-TEXT runtime·memclr(SB),NOSPLIT|NOFRAME,$0-16
- MOVD ptr+0(FP), R3
- MOVD n+8(FP), R4
- SRADCC $3, R4, R6 // R6 is the number of words to zero
- BEQ bytes
-
- SUB $8, R3
- MOVD R6, CTR
- MOVDU R0, 8(R3)
- BC 25, 0, -1(PC) // bdnz+ $-4
- ADD $8, R3
-
-bytes:
- ANDCC $7, R4, R7 // R7 is the number of bytes to zero
- BEQ done
- SUB $1, R3
- MOVD R7, CTR
- MOVBU R0, 1(R3)
- BC 25, 0, -1(PC) // bdnz+ $-4
-
-done:
+// void runtime·memclrNoHeapPointers(void*, uintptr)
+TEXT runtime·memclrNoHeapPointers(SB), NOSPLIT|NOFRAME, $0-16
+ MOVD ptr+0(FP), R3
+ MOVD n+8(FP), R4
+
+ // Determine if there are doublewords to clear
+check:
+ ANDCC $7, R4, R5 // R5: leftover bytes to clear
+ SRAD $3, R4, R6 // R6: double words to clear
+ CMP R6, $0, CR1 // CR1[EQ] set if no double words
+
+ BC 12, 6, nozerolarge // only single bytes
+ MOVD R6, CTR // R6 = number of double words
+ SRADCC $2, R6, R7 // 32 byte chunks?
+ BNE zero32setup
+
+ // Clear double words
+
+zero8:
+ MOVD R0, 0(R3) // double word
+ ADD $8, R3
+ BC 16, 0, zero8 // dec ctr, br zero8 if ctr not 0
+ BR nozerolarge // handle remainder
+
+ // Prepare to clear 32 bytes at a time.
+
+zero32setup:
+ DCBTST (R3) // prepare data cache
+ MOVD R7, CTR // number of 32 byte chunks
+
+zero32:
+ MOVD R0, 0(R3) // clear 4 double words
+ MOVD R0, 8(R3)
+ MOVD R0, 16(R3)
+ MOVD R0, 24(R3)
+ ADD $32, R3
+ BC 16, 0, zero32 // dec ctr, br zero32 if ctr not 0
+ RLDCLCC $61, R4, $3, R6 // remaining doublewords
+ BEQ nozerolarge
+ MOVD R6, CTR // set up the CTR for doublewords
+ BR zero8
+
+nozerolarge:
+ CMP R5, $0 // any remaining bytes
+ BC 4, 1, LR // ble lr
+
+zerotail:
+ MOVD R5, CTR // set up to clear tail bytes
+
+zerotailloop:
+ MOVB R0, 0(R3) // clear single bytes
+ ADD $1, R3
+ BC 16, 0, zerotailloop // dec ctr, br zerotailloop if ctr not 0
RET
diff --git a/src/runtime/memclr_s390x.s b/src/runtime/memclr_s390x.s
index 86eafec..43da10d 100644
--- a/src/runtime/memclr_s390x.s
+++ b/src/runtime/memclr_s390x.s
@@ -4,8 +4,8 @@
#include "textflag.h"
-// void runtime·memclr(void*, uintptr)
-TEXT runtime·memclr(SB),NOSPLIT|NOFRAME,$0-16
+// void runtime·memclrNoHeapPointers(void*, uintptr)
+TEXT runtime·memclrNoHeapPointers(SB),NOSPLIT|NOFRAME,$0-16
MOVD ptr+0(FP), R4
MOVD n+8(FP), R5
@@ -16,8 +16,8 @@ start:
CMPBLE R5, $15, clear12to15
CMP R5, $32
BGE clearmt32
- MOVD R0, 0(R4)
- MOVD R0, 8(R4)
+ MOVD $0, 0(R4)
+ MOVD $0, 8(R4)
ADD $16, R4
SUB $16, R5
BR start
@@ -25,79 +25,79 @@ start:
clear0to3:
CMPBEQ R5, $0, done
CMPBNE R5, $1, clear2
- MOVB R0, 0(R4)
+ MOVB $0, 0(R4)
RET
clear2:
CMPBNE R5, $2, clear3
- MOVH R0, 0(R4)
+ MOVH $0, 0(R4)
RET
clear3:
- MOVH R0, 0(R4)
- MOVB R0, 2(R4)
+ MOVH $0, 0(R4)
+ MOVB $0, 2(R4)
RET
clear4to7:
CMPBNE R5, $4, clear5
- MOVW R0, 0(R4)
+ MOVW $0, 0(R4)
RET
clear5:
CMPBNE R5, $5, clear6
- MOVW R0, 0(R4)
- MOVB R0, 4(R4)
+ MOVW $0, 0(R4)
+ MOVB $0, 4(R4)
RET
clear6:
CMPBNE R5, $6, clear7
- MOVW R0, 0(R4)
- MOVH R0, 4(R4)
+ MOVW $0, 0(R4)
+ MOVH $0, 4(R4)
RET
clear7:
- MOVW R0, 0(R4)
- MOVH R0, 4(R4)
- MOVB R0, 6(R4)
+ MOVW $0, 0(R4)
+ MOVH $0, 4(R4)
+ MOVB $0, 6(R4)
RET
clear8to11:
CMPBNE R5, $8, clear9
- MOVD R0, 0(R4)
+ MOVD $0, 0(R4)
RET
clear9:
CMPBNE R5, $9, clear10
- MOVD R0, 0(R4)
- MOVB R0, 8(R4)
+ MOVD $0, 0(R4)
+ MOVB $0, 8(R4)
RET
clear10:
CMPBNE R5, $10, clear11
- MOVD R0, 0(R4)
- MOVH R0, 8(R4)
+ MOVD $0, 0(R4)
+ MOVH $0, 8(R4)
RET
clear11:
- MOVD R0, 0(R4)
- MOVH R0, 8(R4)
- MOVB R0, 10(R4)
+ MOVD $0, 0(R4)
+ MOVH $0, 8(R4)
+ MOVB $0, 10(R4)
RET
clear12to15:
CMPBNE R5, $12, clear13
- MOVD R0, 0(R4)
- MOVW R0, 8(R4)
+ MOVD $0, 0(R4)
+ MOVW $0, 8(R4)
RET
clear13:
CMPBNE R5, $13, clear14
- MOVD R0, 0(R4)
- MOVW R0, 8(R4)
- MOVB R0, 12(R4)
+ MOVD $0, 0(R4)
+ MOVW $0, 8(R4)
+ MOVB $0, 12(R4)
RET
clear14:
CMPBNE R5, $14, clear15
- MOVD R0, 0(R4)
- MOVW R0, 8(R4)
- MOVH R0, 12(R4)
+ MOVD $0, 0(R4)
+ MOVW $0, 8(R4)
+ MOVH $0, 12(R4)
RET
clear15:
- MOVD R0, 0(R4)
- MOVW R0, 8(R4)
- MOVH R0, 12(R4)
- MOVB R0, 14(R4)
+ MOVD $0, 0(R4)
+ MOVW $0, 8(R4)
+ MOVH $0, 12(R4)
+ MOVB $0, 14(R4)
RET
clearmt32:
@@ -117,6 +117,6 @@ done:
// DO NOT CALL - target for exrl (execute relative long) instruction.
TEXT runtime·memclr_s390x_exrl_xc(SB),NOSPLIT|NOFRAME,$0-0
XC $1, 0(R4), 0(R4)
- MOVD R0, 0(R0)
+ MOVD $0, 0(R0)
RET
diff --git a/src/runtime/memmove_386.s b/src/runtime/memmove_386.s
index 52b35a6..b712ea1 100644
--- a/src/runtime/memmove_386.s
+++ b/src/runtime/memmove_386.s
@@ -1,5 +1,5 @@
// Inferno's libkern/memmove-386.s
-// http://code.google.com/p/inferno-os/source/browse/libkern/memmove-386.s
+// https://bitbucket.org/inferno-os/inferno-os/src/default/libkern/memmove-386.s
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com). All rights reserved.
diff --git a/src/runtime/memmove_amd64.s b/src/runtime/memmove_amd64.s
index 39b4c3a..464f5fd 100644
--- a/src/runtime/memmove_amd64.s
+++ b/src/runtime/memmove_amd64.s
@@ -1,5 +1,5 @@
// Derived from Inferno's libkern/memmove-386.s (adapted for amd64)
-// http://code.google.com/p/inferno-os/source/browse/libkern/memmove-386.s
+// https://bitbucket.org/inferno-os/inferno-os/src/default/libkern/memmove-386.s
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com). All rights reserved.
@@ -64,6 +64,9 @@ tail:
JBE move_129through256
// TODO: use branch table and BSR to make this just a single dispatch
+ TESTB $1, runtime·useRepMovs(SB)
+ JZ avxUnaligned
+
/*
* check and set for backwards
*/
@@ -108,7 +111,6 @@ back:
ADDQ BX, CX
CMPQ CX, DI
JLS forward
-
/*
* whole thing backwards has
* adjusted addresses
@@ -273,3 +275,242 @@ move_256through2048:
LEAQ 256(DI), DI
JGE move_256through2048
JMP tail
+
+avxUnaligned:
+ // There are two implementations of move algorithm.
+ // The first one for non-ovelapped memory regions. It uses forward copying.
+ // The second one for overlapped regions. It uses backward copying
+ MOVQ DI, CX
+ SUBQ SI, CX
+ // Now CX contains distance between SRC and DEST
+ CMPQ CX, BX
+ // If the distance lesser than region length it means that regions are overlapped
+ JC copy_backward
+
+ // Non-temporal copy would be better for big sizes.
+ CMPQ BX, $0x100000
+ JAE gobble_big_data_fwd
+
+ // Memory layout on the source side
+ // SI CX
+ // |<---------BX before correction--------->|
+ // | |<--BX corrected-->| |
+ // | | |<--- AX --->|
+ // |<-R11->| |<-128 bytes->|
+ // +----------------------------------------+
+ // | Head | Body | Tail |
+ // +-------+------------------+-------------+
+ // ^ ^ ^
+ // | | |
+ // Save head into Y4 Save tail into X5..X12
+ // |
+ // SI+R11, where R11 = ((DI & -32) + 32) - DI
+ // Algorithm:
+ // 1. Unaligned save of the tail's 128 bytes
+ // 2. Unaligned save of the head's 32 bytes
+ // 3. Destination-aligned copying of body (128 bytes per iteration)
+ // 4. Put head on the new place
+ // 5. Put the tail on the new place
+ // It can be important to satisfy processor's pipeline requirements for
+ // small sizes as the cost of unaligned memory region copying is
+ // comparable with the cost of main loop. So code is slightly messed there.
+ // There is more clean implementation of that algorithm for bigger sizes
+ // where the cost of unaligned part copying is negligible.
+ // You can see it after gobble_big_data_fwd label.
+ LEAQ (SI)(BX*1), CX
+ MOVQ DI, R10
+ // CX points to the end of buffer so we need go back slightly. We will use negative offsets there.
+ MOVOU -0x80(CX), X5
+ MOVOU -0x70(CX), X6
+ MOVQ $0x80, AX
+ // Align destination address
+ ANDQ $-32, DI
+ ADDQ $32, DI
+ // Continue tail saving.
+ MOVOU -0x60(CX), X7
+ MOVOU -0x50(CX), X8
+ // Make R11 delta between aligned and unaligned destination addresses.
+ MOVQ DI, R11
+ SUBQ R10, R11
+ // Continue tail saving.
+ MOVOU -0x40(CX), X9
+ MOVOU -0x30(CX), X10
+ // Let's make bytes-to-copy value adjusted as we've prepared unaligned part for copying.
+ SUBQ R11, BX
+ // Continue tail saving.
+ MOVOU -0x20(CX), X11
+ MOVOU -0x10(CX), X12
+ // The tail will be put on it's place after main body copying.
+ // It's time for the unaligned heading part.
+ VMOVDQU (SI), Y4
+ // Adjust source address to point past head.
+ ADDQ R11, SI
+ SUBQ AX, BX
+ // Aligned memory copying there
+gobble_128_loop:
+ VMOVDQU (SI), Y0
+ VMOVDQU 0x20(SI), Y1
+ VMOVDQU 0x40(SI), Y2
+ VMOVDQU 0x60(SI), Y3
+ ADDQ AX, SI
+ VMOVDQA Y0, (DI)
+ VMOVDQA Y1, 0x20(DI)
+ VMOVDQA Y2, 0x40(DI)
+ VMOVDQA Y3, 0x60(DI)
+ ADDQ AX, DI
+ SUBQ AX, BX
+ JA gobble_128_loop
+ // Now we can store unaligned parts.
+ ADDQ AX, BX
+ ADDQ DI, BX
+ VMOVDQU Y4, (R10)
+ VZEROUPPER
+ MOVOU X5, -0x80(BX)
+ MOVOU X6, -0x70(BX)
+ MOVOU X7, -0x60(BX)
+ MOVOU X8, -0x50(BX)
+ MOVOU X9, -0x40(BX)
+ MOVOU X10, -0x30(BX)
+ MOVOU X11, -0x20(BX)
+ MOVOU X12, -0x10(BX)
+ RET
+
+gobble_big_data_fwd:
+ // There is forward copying for big regions.
+ // It uses non-temporal mov instructions.
+ // Details of this algorithm are commented previously for small sizes.
+ LEAQ (SI)(BX*1), CX
+ MOVOU -0x80(SI)(BX*1), X5
+ MOVOU -0x70(CX), X6
+ MOVOU -0x60(CX), X7
+ MOVOU -0x50(CX), X8
+ MOVOU -0x40(CX), X9
+ MOVOU -0x30(CX), X10
+ MOVOU -0x20(CX), X11
+ MOVOU -0x10(CX), X12
+ VMOVDQU (SI), Y4
+ MOVQ DI, R8
+ ANDQ $-32, DI
+ ADDQ $32, DI
+ MOVQ DI, R10
+ SUBQ R8, R10
+ SUBQ R10, BX
+ ADDQ R10, SI
+ LEAQ (DI)(BX*1), CX
+ SUBQ $0x80, BX
+gobble_mem_fwd_loop:
+ PREFETCHNTA 0x1C0(SI)
+ PREFETCHNTA 0x280(SI)
+ // Prefetch values were choosen 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
+ VMOVDQU (SI), Y0
+ VMOVDQU 0x20(SI), Y1
+ VMOVDQU 0x40(SI), Y2
+ VMOVDQU 0x60(SI), Y3
+ ADDQ $0x80, SI
+ VMOVNTDQ Y0, (DI)
+ VMOVNTDQ Y1, 0x20(DI)
+ VMOVNTDQ Y2, 0x40(DI)
+ VMOVNTDQ Y3, 0x60(DI)
+ ADDQ $0x80, DI
+ SUBQ $0x80, BX
+ JA gobble_mem_fwd_loop
+ // NT instructions don't follow the normal cache-coherency rules.
+ // We need SFENCE there to make copied data available timely.
+ SFENCE
+ VMOVDQU Y4, (R8)
+ VZEROUPPER
+ MOVOU X5, -0x80(CX)
+ MOVOU X6, -0x70(CX)
+ MOVOU X7, -0x60(CX)
+ MOVOU X8, -0x50(CX)
+ MOVOU X9, -0x40(CX)
+ MOVOU X10, -0x30(CX)
+ MOVOU X11, -0x20(CX)
+ MOVOU X12, -0x10(CX)
+ RET
+
+copy_backward:
+ MOVQ DI, AX
+ // Backward copying is about the same as the forward one.
+ // Firstly we load unaligned tail in the beginning of region.
+ MOVOU (SI), X5
+ MOVOU 0x10(SI), X6
+ ADDQ BX, DI
+ MOVOU 0x20(SI), X7
+ MOVOU 0x30(SI), X8
+ LEAQ -0x20(DI), R10
+ MOVQ DI, R11
+ MOVOU 0x40(SI), X9
+ MOVOU 0x50(SI), X10
+ ANDQ $0x1F, R11
+ MOVOU 0x60(SI), X11
+ MOVOU 0x70(SI), X12
+ XORQ R11, DI
+ // Let's point SI to the end of region
+ ADDQ BX, SI
+ // and load unaligned head into X4.
+ VMOVDQU -0x20(SI), Y4
+ SUBQ R11, SI
+ SUBQ R11, BX
+ // If there is enough data for non-temporal moves go to special loop
+ CMPQ BX, $0x100000
+ JA gobble_big_data_bwd
+ SUBQ $0x80, BX
+gobble_mem_bwd_loop:
+ VMOVDQU -0x20(SI), Y0
+ VMOVDQU -0x40(SI), Y1
+ VMOVDQU -0x60(SI), Y2
+ VMOVDQU -0x80(SI), Y3
+ SUBQ $0x80, SI
+ VMOVDQA Y0, -0x20(DI)
+ VMOVDQA Y1, -0x40(DI)
+ VMOVDQA Y2, -0x60(DI)
+ VMOVDQA Y3, -0x80(DI)
+ SUBQ $0x80, DI
+ SUBQ $0x80, BX
+ JA gobble_mem_bwd_loop
+ // Let's store unaligned data
+ VMOVDQU Y4, (R10)
+ VZEROUPPER
+ MOVOU X5, (AX)
+ MOVOU X6, 0x10(AX)
+ MOVOU X7, 0x20(AX)
+ MOVOU X8, 0x30(AX)
+ MOVOU X9, 0x40(AX)
+ MOVOU X10, 0x50(AX)
+ MOVOU X11, 0x60(AX)
+ MOVOU X12, 0x70(AX)
+ RET
+
+gobble_big_data_bwd:
+ SUBQ $0x80, BX
+gobble_big_mem_bwd_loop:
+ PREFETCHNTA -0x1C0(SI)
+ PREFETCHNTA -0x280(SI)
+ VMOVDQU -0x20(SI), Y0
+ VMOVDQU -0x40(SI), Y1
+ VMOVDQU -0x60(SI), Y2
+ VMOVDQU -0x80(SI), Y3
+ SUBQ $0x80, SI
+ VMOVNTDQ Y0, -0x20(DI)
+ VMOVNTDQ Y1, -0x40(DI)
+ VMOVNTDQ Y2, -0x60(DI)
+ VMOVNTDQ Y3, -0x80(DI)
+ SUBQ $0x80, DI
+ SUBQ $0x80, BX
+ JA gobble_big_mem_bwd_loop
+ SFENCE
+ VMOVDQU Y4, (R10)
+ VZEROUPPER
+ MOVOU X5, (AX)
+ MOVOU X6, 0x10(AX)
+ MOVOU X7, 0x20(AX)
+ MOVOU X8, 0x30(AX)
+ MOVOU X9, 0x40(AX)
+ MOVOU X10, 0x50(AX)
+ MOVOU X11, 0x60(AX)
+ MOVOU X12, 0x70(AX)
+ RET
diff --git a/src/runtime/memmove_arm.s b/src/runtime/memmove_arm.s
index 6b880d5..504ae04 100644
--- a/src/runtime/memmove_arm.s
+++ b/src/runtime/memmove_arm.s
@@ -1,5 +1,5 @@
// Inferno's libkern/memmove-arm.s
-// http://code.google.com/p/inferno-os/source/browse/libkern/memmove-arm.s
+// https://bitbucket.org/inferno-os/inferno-os/src/default/libkern/memmove-arm.s
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com). All rights reserved.
diff --git a/src/runtime/memmove_linux_amd64_test.go b/src/runtime/memmove_linux_amd64_test.go
index 1dd5d49..d0e8b42 100644
--- a/src/runtime/memmove_linux_amd64_test.go
+++ b/src/runtime/memmove_linux_amd64_test.go
@@ -16,6 +16,7 @@ import (
// TestMemmoveOverflow maps 3GB of memory and calls memmove on
// the corresponding slice.
func TestMemmoveOverflow(t *testing.T) {
+ t.Parallel()
// Create a temporary file.
tmp, err := ioutil.TempFile("", "go-memmovetest")
if err != nil {
@@ -40,7 +41,7 @@ func TestMemmoveOverflow(t *testing.T) {
_, _, errno := syscall.Syscall6(syscall.SYS_MMAP,
base+off, 65536, syscall.PROT_READ|syscall.PROT_WRITE, syscall.MAP_SHARED|syscall.MAP_FIXED, tmp.Fd(), 0)
if errno != 0 {
- t.Fatalf("could not map a page at requested 0x%x: %s", base+off, errno)
+ t.Skipf("could not map a page at requested 0x%x: %s", base+off, errno)
}
defer syscall.Syscall(syscall.SYS_MUNMAP, base+off, 65536, 0)
}
diff --git a/src/runtime/memmove_mipsx.s b/src/runtime/memmove_mipsx.s
new file mode 100644
index 0000000..e934e4d
--- /dev/null
+++ b/src/runtime/memmove_mipsx.s
@@ -0,0 +1,258 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build mips mipsle
+
+#include "textflag.h"
+
+#ifdef GOARCH_mips
+#define MOVWHI MOVWL
+#define MOVWLO MOVWR
+#else
+#define MOVWHI MOVWR
+#define MOVWLO MOVWL
+#endif
+
+// void runtime·memmove(void*, void*, uintptr)
+TEXT runtime·memmove(SB),NOSPLIT,$-0-12
+ MOVW n+8(FP), R3
+ MOVW from+4(FP), R2
+ MOVW to+0(FP), R1
+
+ ADDU R3, R2, R4 // end pointer for source
+ ADDU R3, R1, R5 // end pointer for destination
+
+ // if destination is ahead of source, start at the end of the buffer and go backward.
+ SGTU R1, R2, R6
+ BNE R6, backward
+
+ // if less than 4 bytes, use byte by byte copying
+ SGTU $4, R3, R6
+ BNE R6, f_small_copy
+
+ // align destination to 4 bytes
+ AND $3, R1, R6
+ BEQ R6, f_dest_aligned
+ SUBU R1, R0, R6
+ AND $3, R6
+ MOVWHI 0(R2), R7
+ SUBU R6, R3
+ MOVWLO 3(R2), R7
+ ADDU R6, R2
+ MOVWHI R7, 0(R1)
+ ADDU R6, R1
+
+f_dest_aligned:
+ AND $31, R3, R7
+ AND $3, R3, R6
+ SUBU R7, R5, R7 // end pointer for 32-byte chunks
+ SUBU R6, R5, R6 // end pointer for 4-byte chunks
+
+ // if source is not aligned, use unaligned reads
+ AND $3, R2, R8
+ BNE R8, f_large_ua
+
+f_large:
+ BEQ R1, R7, f_words
+ ADDU $32, R1
+ MOVW 0(R2), R8
+ MOVW 4(R2), R9
+ MOVW 8(R2), R10
+ MOVW 12(R2), R11
+ MOVW 16(R2), R12
+ MOVW 20(R2), R13
+ MOVW 24(R2), R14
+ MOVW 28(R2), R15
+ ADDU $32, R2
+ MOVW R8, -32(R1)
+ MOVW R9, -28(R1)
+ MOVW R10, -24(R1)
+ MOVW R11, -20(R1)
+ MOVW R12, -16(R1)
+ MOVW R13, -12(R1)
+ MOVW R14, -8(R1)
+ MOVW R15, -4(R1)
+ JMP f_large
+
+f_words:
+ BEQ R1, R6, f_tail
+ ADDU $4, R1
+ MOVW 0(R2), R8
+ ADDU $4, R2
+ MOVW R8, -4(R1)
+ JMP f_words
+
+f_tail:
+ BEQ R1, R5, ret
+ MOVWLO -1(R4), R8
+ MOVWLO R8, -1(R5)
+
+ret:
+ RET
+
+f_large_ua:
+ BEQ R1, R7, f_words_ua
+ ADDU $32, R1
+ MOVWHI 0(R2), R8
+ MOVWHI 4(R2), R9
+ MOVWHI 8(R2), R10
+ MOVWHI 12(R2), R11
+ MOVWHI 16(R2), R12
+ MOVWHI 20(R2), R13
+ MOVWHI 24(R2), R14
+ MOVWHI 28(R2), R15
+ MOVWLO 3(R2), R8
+ MOVWLO 7(R2), R9
+ MOVWLO 11(R2), R10
+ MOVWLO 15(R2), R11
+ MOVWLO 19(R2), R12
+ MOVWLO 23(R2), R13
+ MOVWLO 27(R2), R14
+ MOVWLO 31(R2), R15
+ ADDU $32, R2
+ MOVW R8, -32(R1)
+ MOVW R9, -28(R1)
+ MOVW R10, -24(R1)
+ MOVW R11, -20(R1)
+ MOVW R12, -16(R1)
+ MOVW R13, -12(R1)
+ MOVW R14, -8(R1)
+ MOVW R15, -4(R1)
+ JMP f_large_ua
+
+f_words_ua:
+ BEQ R1, R6, f_tail_ua
+ MOVWHI 0(R2), R8
+ ADDU $4, R1
+ MOVWLO 3(R2), R8
+ ADDU $4, R2
+ MOVW R8, -4(R1)
+ JMP f_words_ua
+
+f_tail_ua:
+ BEQ R1, R5, ret
+ MOVWHI -4(R4), R8
+ MOVWLO -1(R4), R8
+ MOVWLO R8, -1(R5)
+ JMP ret
+
+f_small_copy:
+ BEQ R1, R5, ret
+ ADDU $1, R1
+ MOVB 0(R2), R6
+ ADDU $1, R2
+ MOVB R6, -1(R1)
+ JMP f_small_copy
+
+backward:
+ SGTU $4, R3, R6
+ BNE R6, b_small_copy
+
+ AND $3, R5, R6
+ BEQ R6, b_dest_aligned
+ MOVWHI -4(R4), R7
+ SUBU R6, R3
+ MOVWLO -1(R4), R7
+ SUBU R6, R4
+ MOVWLO R7, -1(R5)
+ SUBU R6, R5
+
+b_dest_aligned:
+ AND $31, R3, R7
+ AND $3, R3, R6
+ ADDU R7, R1, R7
+ ADDU R6, R1, R6
+
+ AND $3, R4, R8
+ BNE R8, b_large_ua
+
+b_large:
+ BEQ R5, R7, b_words
+ ADDU $-32, R5
+ MOVW -4(R4), R8
+ MOVW -8(R4), R9
+ MOVW -12(R4), R10
+ MOVW -16(R4), R11
+ MOVW -20(R4), R12
+ MOVW -24(R4), R13
+ MOVW -28(R4), R14
+ MOVW -32(R4), R15
+ ADDU $-32, R4
+ MOVW R8, 28(R5)
+ MOVW R9, 24(R5)
+ MOVW R10, 20(R5)
+ MOVW R11, 16(R5)
+ MOVW R12, 12(R5)
+ MOVW R13, 8(R5)
+ MOVW R14, 4(R5)
+ MOVW R15, 0(R5)
+ JMP b_large
+
+b_words:
+ BEQ R5, R6, b_tail
+ ADDU $-4, R5
+ MOVW -4(R4), R8
+ ADDU $-4, R4
+ MOVW R8, 0(R5)
+ JMP b_words
+
+b_tail:
+ BEQ R5, R1, ret
+ MOVWHI 0(R2), R8 // R2 and R1 have the same alignment so we don't need to load a whole word
+ MOVWHI R8, 0(R1)
+ JMP ret
+
+b_large_ua:
+ BEQ R5, R7, b_words_ua
+ ADDU $-32, R5
+ MOVWHI -4(R4), R8
+ MOVWHI -8(R4), R9
+ MOVWHI -12(R4), R10
+ MOVWHI -16(R4), R11
+ MOVWHI -20(R4), R12
+ MOVWHI -24(R4), R13
+ MOVWHI -28(R4), R14
+ MOVWHI -32(R4), R15
+ MOVWLO -1(R4), R8
+ MOVWLO -5(R4), R9
+ MOVWLO -9(R4), R10
+ MOVWLO -13(R4), R11
+ MOVWLO -17(R4), R12
+ MOVWLO -21(R4), R13
+ MOVWLO -25(R4), R14
+ MOVWLO -29(R4), R15
+ ADDU $-32, R4
+ MOVW R8, 28(R5)
+ MOVW R9, 24(R5)
+ MOVW R10, 20(R5)
+ MOVW R11, 16(R5)
+ MOVW R12, 12(R5)
+ MOVW R13, 8(R5)
+ MOVW R14, 4(R5)
+ MOVW R15, 0(R5)
+ JMP b_large_ua
+
+b_words_ua:
+ BEQ R5, R6, b_tail_ua
+ MOVWHI -4(R4), R8
+ ADDU $-4, R5
+ MOVWLO -1(R4), R8
+ ADDU $-4, R4
+ MOVW R8, 0(R5)
+ JMP b_words_ua
+
+b_tail_ua:
+ BEQ R5, R1, ret
+ MOVWHI (R2), R8
+ MOVWLO 3(R2), R8
+ MOVWHI R8, 0(R1)
+ JMP ret
+
+b_small_copy:
+ BEQ R5, R1, ret
+ ADDU $-1, R5
+ MOVB -1(R4), R6
+ ADDU $-1, R4
+ MOVB R6, 0(R5)
+ JMP b_small_copy
diff --git a/src/runtime/memmove_plan9_386.s b/src/runtime/memmove_plan9_386.s
index c4d62ec..29d44b2 100644
--- a/src/runtime/memmove_plan9_386.s
+++ b/src/runtime/memmove_plan9_386.s
@@ -1,5 +1,5 @@
// Inferno's libkern/memmove-386.s
-// http://code.google.com/p/inferno-os/source/browse/libkern/memmove-386.s
+// https://bitbucket.org/inferno-os/inferno-os/src/default/libkern/memmove-386.s
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com). All rights reserved.
diff --git a/src/runtime/memmove_plan9_amd64.s b/src/runtime/memmove_plan9_amd64.s
index 9bef31d..a5e8dfa 100644
--- a/src/runtime/memmove_plan9_amd64.s
+++ b/src/runtime/memmove_plan9_amd64.s
@@ -1,5 +1,5 @@
// Derived from Inferno's libkern/memmove-386.s (adapted for amd64)
-// http://code.google.com/p/inferno-os/source/browse/libkern/memmove-386.s
+// https://bitbucket.org/inferno-os/inferno-os/src/default/libkern/memmove-386.s
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com). All rights reserved.
diff --git a/src/runtime/memmove_test.go b/src/runtime/memmove_test.go
index 2124cb9..dbfa284 100644
--- a/src/runtime/memmove_test.go
+++ b/src/runtime/memmove_test.go
@@ -5,12 +5,15 @@
package runtime_test
import (
+ "crypto/rand"
"fmt"
+ "internal/race"
. "runtime"
"testing"
)
func TestMemmove(t *testing.T) {
+ t.Parallel()
size := 256
if testing.Short() {
size = 128 + 16
@@ -49,6 +52,7 @@ func TestMemmove(t *testing.T) {
}
func TestMemmoveAlias(t *testing.T) {
+ t.Parallel()
size := 256
if testing.Short() {
size = 128 + 16
@@ -82,6 +86,110 @@ func TestMemmoveAlias(t *testing.T) {
}
}
+func TestMemmoveLarge0x180000(t *testing.T) {
+ t.Parallel()
+ if race.Enabled {
+ t.Skip("skipping large memmove test under race detector")
+ }
+ testSize(t, 0x180000)
+}
+
+func TestMemmoveOverlapLarge0x120000(t *testing.T) {
+ t.Parallel()
+ if race.Enabled {
+ t.Skip("skipping large memmove test under race detector")
+ }
+ testOverlap(t, 0x120000)
+}
+
+func testSize(t *testing.T, size int) {
+ src := make([]byte, size)
+ dst := make([]byte, size)
+ _, _ = rand.Read(src)
+ _, _ = rand.Read(dst)
+
+ ref := make([]byte, size)
+ copyref(ref, dst)
+
+ for n := size - 50; n > 1; n >>= 1 {
+ for x := 0; x <= size-n; x = x*7 + 1 { // offset in src
+ for y := 0; y <= size-n; y = y*9 + 1 { // offset in dst
+ copy(dst[y:y+n], src[x:x+n])
+ copyref(ref[y:y+n], src[x:x+n])
+ p := cmpb(dst, ref)
+ if p >= 0 {
+ t.Fatalf("Copy failed, copying from src[%d:%d] to dst[%d:%d].\nOffset %d is different, %v != %v", x, x+n, y, y+n, p, dst[p], ref[p])
+ }
+ }
+ }
+ }
+}
+
+func testOverlap(t *testing.T, size int) {
+ src := make([]byte, size)
+ test := make([]byte, size)
+ ref := make([]byte, size)
+ _, _ = rand.Read(src)
+
+ for n := size - 50; n > 1; n >>= 1 {
+ for x := 0; x <= size-n; x = x*7 + 1 { // offset in src
+ for y := 0; y <= size-n; y = y*9 + 1 { // offset in dst
+ // Reset input
+ copyref(test, src)
+ copyref(ref, src)
+ copy(test[y:y+n], test[x:x+n])
+ if y <= x {
+ copyref(ref[y:y+n], ref[x:x+n])
+ } else {
+ copybw(ref[y:y+n], ref[x:x+n])
+ }
+ p := cmpb(test, ref)
+ if p >= 0 {
+ t.Fatalf("Copy failed, copying from src[%d:%d] to dst[%d:%d].\nOffset %d is different, %v != %v", x, x+n, y, y+n, p, test[p], ref[p])
+ }
+ }
+ }
+ }
+
+}
+
+// Forward copy.
+func copyref(dst, src []byte) {
+ for i, v := range src {
+ dst[i] = v
+ }
+}
+
+// Backwards copy
+func copybw(dst, src []byte) {
+ if len(src) == 0 {
+ return
+ }
+ for i := len(src) - 1; i >= 0; i-- {
+ dst[i] = src[i]
+ }
+}
+
+// Returns offset of difference
+func matchLen(a, b []byte, max int) int {
+ a = a[:max]
+ b = b[:max]
+ for i, av := range a {
+ if b[i] != av {
+ return i
+ }
+ }
+ return max
+}
+
+func cmpb(a, b []byte) int {
+ l := matchLen(a, b, len(a))
+ if l == len(a) {
+ return -1
+ }
+ return l
+}
+
func benchmarkSizes(b *testing.B, sizes []int, fn func(b *testing.B, n int)) {
for _, n := range sizes {
b.Run(fmt.Sprint(n), func(b *testing.B) {
diff --git a/src/runtime/mfinal.go b/src/runtime/mfinal.go
index 14ebec8..7e191d4 100644
--- a/src/runtime/mfinal.go
+++ b/src/runtime/mfinal.go
@@ -12,10 +12,14 @@ import (
"unsafe"
)
+// finblock is allocated from non-GC'd memory, so any heap pointers
+// must be specially handled.
+//
+//go:notinheap
type finblock struct {
alllink *finblock
next *finblock
- cnt int32
+ cnt uint32
_ int32
fin [(_FinBlockSize - 2*sys.PtrSize - 2*4) / unsafe.Sizeof(finalizer{})]finalizer
}
@@ -31,11 +35,11 @@ var allfin *finblock // list of all blocks
// NOTE: Layout known to queuefinalizer.
type finalizer struct {
- fn *funcval // function to call
- arg unsafe.Pointer // ptr to object
+ fn *funcval // function to call (may be a heap pointer)
+ arg unsafe.Pointer // ptr to object (may be a heap pointer)
nret uintptr // bytes of return values from fn
fint *_type // type of first argument of fn
- ot *ptrtype // type of ptr to object
+ ot *ptrtype // type of ptr to object (may be a heap pointer)
}
var finalizer1 = [...]byte{
@@ -68,9 +72,8 @@ var finalizer1 = [...]byte{
func queuefinalizer(p unsafe.Pointer, fn *funcval, nret uintptr, fint *_type, ot *ptrtype) {
lock(&finlock)
- if finq == nil || finq.cnt == int32(len(finq.fin)) {
+ if finq == nil || finq.cnt == uint32(len(finq.fin)) {
if finc == nil {
- // Note: write barrier here, assigning to finc, but should be okay.
finc = (*finblock)(persistentalloc(_FinBlockSize, 0, &memstats.gc_sys))
finc.alllink = allfin
allfin = finc
@@ -96,7 +99,7 @@ func queuefinalizer(p unsafe.Pointer, fn *funcval, nret uintptr, fint *_type, ot
finq = block
}
f := &finq.fin[finq.cnt]
- finq.cnt++
+ atomic.Xadd(&finq.cnt, +1) // Sync with markroots
f.fn = fn
f.nret = nret
f.fint = fint
@@ -109,7 +112,7 @@ func queuefinalizer(p unsafe.Pointer, fn *funcval, nret uintptr, fint *_type, ot
//go:nowritebarrier
func iterate_finq(callback func(*funcval, unsafe.Pointer, uintptr, *_type, *ptrtype)) {
for fb := allfin; fb != nil; fb = fb.alllink {
- for i := int32(0); i < fb.cnt; i++ {
+ for i := uint32(0); i < fb.cnt; i++ {
f := &fb.fin[i]
callback(f.fn, f.arg, f.nret, f.fint, f.ot)
}
@@ -179,6 +182,11 @@ func runfinq() {
if f.fint == nil {
throw("missing type in runfinq")
}
+ // frame is effectively uninitialized
+ // memory. That means we have to clear
+ // it before writing to it to avoid
+ // confusing the write barrier.
+ *(*[2]uintptr)(frame) = [2]uintptr{}
switch f.fint.kind & kindMask {
case kindPtr:
// direct use of pointer
@@ -191,7 +199,7 @@ func runfinq() {
if len(ityp.mhdr) != 0 {
// convert to interface with methods
// this conversion is guaranteed to succeed - we checked in SetFinalizer
- assertE2I(ityp, *(*eface)(frame), (*iface)(frame))
+ *(*iface)(frame) = assertE2I(ityp, *(*eface)(frame))
}
default:
throw("bad kind in runfinq")
@@ -200,11 +208,14 @@ func runfinq() {
reflectcall(nil, unsafe.Pointer(f.fn), frame, uint32(framesz), uint32(framesz))
fingRunning = false
- // drop finalizer queue references to finalized object
+ // Drop finalizer queue heap references
+ // before hiding them from markroot.
+ // This also ensures these will be
+ // clear if we reuse the finalizer.
f.fn = nil
f.arg = nil
f.ot = nil
- fb.cnt = i - 1
+ atomic.Store(&fb.cnt, i-1)
}
next := fb.next
lock(&finlock)
@@ -226,11 +237,12 @@ func runfinq() {
//
// SetFinalizer(obj, nil) clears any finalizer associated with obj.
//
-// The argument obj must be a pointer to an object allocated by
-// calling new or by taking the address of a composite literal.
+// The argument obj must be a pointer to an object allocated by calling
+// new, by taking the address of a composite literal, or by taking the
+// address of a local variable.
// The argument finalizer must be a function that takes a single argument
// to which obj's type can be assigned, and can have arbitrary ignored return
-// values. If either of these is not true, SetFinalizer aborts the
+// values. If either of these is not true, SetFinalizer may abort the
// program.
//
// Finalizers are run in dependency order: if A points at B, both have
@@ -352,7 +364,7 @@ func SetFinalizer(obj interface{}, finalizer interface{}) {
if ft.dotdotdot() {
throw("runtime.SetFinalizer: cannot pass " + etyp.string() + " to finalizer " + ftyp.string() + " because dotdotdot")
}
- if ft.dotdotdot() || ft.inCount != 1 {
+ if ft.inCount != 1 {
throw("runtime.SetFinalizer: cannot pass " + etyp.string() + " to finalizer " + ftyp.string())
}
fint := ft.in()[0]
@@ -372,7 +384,7 @@ func SetFinalizer(obj interface{}, finalizer interface{}) {
// ok - satisfies empty interface
goto okarg
}
- if assertE2I2(ityp, *efaceOf(&obj), nil) {
+ if _, ok := assertE2I2(ityp, *efaceOf(&obj)); ok {
goto okarg
}
}
@@ -416,7 +428,7 @@ func findObject(v unsafe.Pointer) (s *mspan, x unsafe.Pointer, n uintptr) {
}
p := uintptr(v) >> pageShift
q := p - arena_start>>pageShift
- s = *(**mspan)(add(unsafe.Pointer(mheap_.spans), q*sys.PtrSize))
+ s = mheap_.spans[q]
if s == nil {
return
}
diff --git a/src/runtime/mfixalloc.go b/src/runtime/mfixalloc.go
index c4ab648..fe4b0fc 100644
--- a/src/runtime/mfixalloc.go
+++ b/src/runtime/mfixalloc.go
@@ -14,10 +14,16 @@ import "unsafe"
// Malloc uses a FixAlloc wrapped around sysAlloc to manages its
// MCache and MSpan objects.
//
-// Memory returned by FixAlloc_Alloc is not zeroed.
+// Memory returned by fixalloc.alloc is zeroed by default, but the
+// caller may take responsibility for zeroing allocations by setting
+// the zero flag to false. This is only safe if the memory never
+// contains heap pointers.
+//
// The caller is responsible for locking around FixAlloc calls.
// Callers can keep state in the object but the first word is
// smashed by freeing and reallocating.
+//
+// Consider marking fixalloc'd types go:notinheap.
type fixalloc struct {
size uintptr
first func(arg, p unsafe.Pointer) // called first time p is returned
@@ -27,6 +33,7 @@ type fixalloc struct {
nchunk uint32
inuse uintptr // in-use bytes now
stat *uint64
+ zero bool // zero allocations
}
// A generic linked list of blocks. (Typically the block is bigger than sizeof(MLink).)
@@ -34,6 +41,8 @@ type fixalloc struct {
// this cannot be used by some of the internal GC structures. For example when
// the sweeper is placing an unmarked object on the free list it does not want the
// write barrier to be called since that could result in the object being reachable.
+//
+//go:notinheap
type mlink struct {
next *mlink
}
@@ -49,6 +58,7 @@ func (f *fixalloc) init(size uintptr, first func(arg, p unsafe.Pointer), arg uns
f.nchunk = 0
f.inuse = 0
f.stat = stat
+ f.zero = true
}
func (f *fixalloc) alloc() unsafe.Pointer {
@@ -61,6 +71,9 @@ func (f *fixalloc) alloc() unsafe.Pointer {
v := unsafe.Pointer(f.list)
f.list = f.list.next
f.inuse += f.size
+ if f.zero {
+ memclrNoHeapPointers(v, f.size)
+ }
return v
}
if uintptr(f.nchunk) < f.size {
diff --git a/src/runtime/mgc.go b/src/runtime/mgc.go
index 3b238cb..cc79d4c 100644
--- a/src/runtime/mgc.go
+++ b/src/runtime/mgc.go
@@ -122,6 +122,15 @@
// proportion to the allocation cost. Adjusting GOGC just changes the linear constant
// (and also the amount of extra memory used).
+// Oblets
+//
+// In order to prevent long pauses while scanning large objects and to
+// improve parallelism, the garbage collector breaks up scan jobs for
+// objects larger than maxObletBytes into "oblets" of at most
+// maxObletBytes. When scanning encounters the beginning of a large
+// object, it scans only the first oblet and enqueues the remaining
+// oblets as new scan jobs.
+
package runtime
import (
@@ -167,24 +176,29 @@ func gcinit() {
}
_ = setGCPercent(readgogc())
- for datap := &firstmoduledata; datap != nil; datap = datap.next {
- datap.gcdatamask = progToPointerMask((*byte)(unsafe.Pointer(datap.gcdata)), datap.edata-datap.data)
- datap.gcbssmask = progToPointerMask((*byte)(unsafe.Pointer(datap.gcbss)), datap.ebss-datap.bss)
+ memstats.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)
}
- memstats.next_gc = heapminimum
work.startSema = 1
work.markDoneSema = 1
}
func readgogc() int32 {
p := gogetenv("GOGC")
- if p == "" {
- return 100
- }
if p == "off" {
return -1
}
- return int32(atoi(p))
+ if n, ok := atoi32(p); ok {
+ return n
+ }
+ return 100
}
// gcenable is called after the bulk of the runtime initialization,
@@ -209,21 +223,25 @@ func setGCPercent(in int32) (out int32) {
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.
unlock(&mheap_.lock)
return out
}
// Garbage collector phase.
-// Indicates to write barrier and sychronization task to preform.
+// Indicates to write barrier and synchronization task to perform.
var gcphase uint32
// The compiler knows about this variable.
// If you change it, you must change the compiler too.
var writeBarrier struct {
- enabled bool // compiler emits a check of this before calling write barrier
- needed bool // whether we need a write barrier for current GC phase
- cgo bool // whether we need a write barrier for a cgo check
- alignme uint64 // guarantee alignment so that compiler can use a 32 or 64-bit load
+ enabled bool // compiler emits a check of this before calling write barrier
+ pad [3]byte // compiler uses 32-bit load for "enabled" field
+ needed bool // whether we need a write barrier for current GC phase
+ cgo bool // whether we need a write barrier for a cgo check
+ alignme uint64 // guarantee alignment so that compiler can use a 32 or 64-bit load
}
// gcBlackenEnabled is 1 if mutator assists and background mark
@@ -289,11 +307,19 @@ const (
gcMarkWorkerIdleMode
)
+// gcMarkWorkerModeStrings are the strings labels of gcMarkWorkerModes
+// to use in execution traces.
+var gcMarkWorkerModeStrings = [...]string{
+ "GC (dedicated)",
+ "GC (fractional)",
+ "GC (idle)",
+}
+
// gcController implements the GC pacing controller that determines
// when to trigger concurrent garbage collection and how much marking
// work to do in mutator assists and background marking.
//
-// It uses a feedback control algorithm to adjust the memstats.next_gc
+// It uses a feedback control algorithm to adjust the memstats.gc_trigger
// trigger based on the heap growth and GC CPU utilization each cycle.
// This algorithm optimizes for heap growth to match GOGC and for CPU
// utilization between assist and background marking to be 25% of
@@ -349,10 +375,6 @@ type gcControllerState struct {
// that assists and background mark workers started.
markStartTime int64
- // heapGoal is the goal memstats.heap_live for when this cycle
- // ends. This is computed at the beginning of each cycle.
- heapGoal uint64
-
// dedicatedMarkWorkersNeeded is the number of dedicated mark
// workers that need to be started. This is computed at the
// beginning of each cycle and decremented atomically as
@@ -380,8 +402,9 @@ type gcControllerState struct {
// triggerRatio is the heap growth ratio at which the garbage
// collection cycle should start. E.g., if this is 0.6, then
// GC should start when the live heap has reached 1.6 times
- // the heap size marked by the previous cycle. This is updated
- // at the end of of each cycle.
+ // 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
@@ -406,28 +429,31 @@ func (c *gcControllerState) startCycle() {
c.idleMarkTime = 0
// If this is the first GC cycle or we're operating on a very
- // small heap, fake heap_marked so it looks like next_gc is
+ // small heap, fake heap_marked so it looks like gc_trigger is
// the appropriate growth from heap_marked, even though the
// real heap_marked may not have a meaningful value (on the
// first cycle) or may be much smaller (resulting in a large
// error response).
- if memstats.next_gc <= heapminimum {
- memstats.heap_marked = uint64(float64(memstats.next_gc) / (1 + c.triggerRatio))
- memstats.heap_reachable = memstats.heap_marked
+ if memstats.gc_trigger <= heapminimum {
+ memstats.heap_marked = uint64(float64(memstats.gc_trigger) / (1 + c.triggerRatio))
}
- // Compute the heap goal for this cycle
- c.heapGoal = memstats.heap_reachable + memstats.heap_reachable*uint64(gcpercent)/100
+ // Re-compute the heap goal for this cycle in case something
+ // changed. This is the same calculation we use elsewhere.
+ memstats.next_gc = memstats.heap_marked + memstats.heap_marked*uint64(gcpercent)/100
+ if gcpercent < 0 {
+ memstats.next_gc = ^uint64(0)
+ }
// Ensure that the heap goal is at least a little larger than
// the current live heap size. This may not be the case if GC
// start is delayed or if the allocation that pushed heap_live
- // over next_gc is large or if the trigger is really close to
+ // over gc_trigger is large or if the trigger is really close to
// GOGC. Assist is proportional to this distance, so enforce a
// minimum distance, even if it means going over the GOGC goal
// by a tiny bit.
- if c.heapGoal < memstats.heap_live+1024*1024 {
- c.heapGoal = memstats.heap_live + 1024*1024
+ if memstats.next_gc < memstats.heap_live+1024*1024 {
+ memstats.next_gc = memstats.heap_live + 1024*1024
}
// Compute the total mark utilization goal and divide it among
@@ -457,7 +483,7 @@ func (c *gcControllerState) startCycle() {
print("pacer: assist ratio=", c.assistWorkPerByte,
" (scan ", memstats.heap_scan>>20, " MB in ",
work.initialHeapLive>>20, "->",
- c.heapGoal>>20, " MB)",
+ memstats.next_gc>>20, " MB)",
" workers=", c.dedicatedMarkWorkersNeeded,
"+", c.fractionalMarkWorkersNeeded, "\n")
}
@@ -506,7 +532,7 @@ func (c *gcControllerState) revise() {
}
// Compute the heap distance remaining.
- heapDistance := int64(c.heapGoal) - int64(memstats.heap_live)
+ heapDistance := int64(memstats.next_gc) - int64(memstats.heap_live)
if heapDistance <= 0 {
// This shouldn't happen, but if it does, avoid
// dividing by zero or setting the assist negative.
@@ -541,10 +567,6 @@ func (c *gcControllerState) endCycle() {
// growth if we had the desired CPU utilization). The
// difference between this estimate and the GOGC-based goal
// heap growth is the error.
- //
- // TODO(austin): next_gc is based on heap_reachable, not
- // heap_marked, which means the actual growth ratio
- // technically isn't comparable to the trigger ratio.
goalGrowthRatio := float64(gcpercent) / 100
actualGrowthRatio := float64(memstats.heap_live)/float64(memstats.heap_marked) - 1
assistDuration := nanotime() - c.markStartTime
@@ -575,7 +597,7 @@ func (c *gcControllerState) endCycle() {
// Print controller state in terms of the design
// document.
H_m_prev := memstats.heap_marked
- H_T := memstats.next_gc
+ H_T := memstats.gc_trigger
h_a := actualGrowthRatio
H_a := memstats.heap_live
h_g := goalGrowthRatio
@@ -602,6 +624,14 @@ func (c *gcControllerState) endCycle() {
//
//go:nowritebarrier
func (c *gcControllerState) enlistWorker() {
+ // If there are idle Ps, wake one so it will run an idle worker.
+ if atomic.Load(&sched.npidle) != 0 && atomic.Load(&sched.nmspinning) == 0 {
+ wakep()
+ return
+ }
+
+ // There are no idle Ps. If we need more dedicated workers,
+ // try to preempt a running P so it will switch to a worker.
if c.dedicatedMarkWorkersNeeded <= 0 {
return
}
@@ -615,7 +645,7 @@ func (c *gcControllerState) enlistWorker() {
}
myID := gp.m.p.ptr().id
for tries := 0; tries < 5; tries++ {
- id := int32(fastrand1() % uint32(gomaxprocs-1))
+ id := int32(fastrand() % uint32(gomaxprocs-1))
if id >= myID {
id++
}
@@ -751,6 +781,22 @@ var work struct {
empty uint64 // lock-free list of empty blocks workbuf
pad0 [sys.CacheLineSize]uint8 // prevents false-sharing between full/empty and nproc/nwait
+ // bytesMarked is the number of bytes marked this cycle. This
+ // includes bytes blackened in scanned objects, noscan objects
+ // that go straight to black, and permagrey objects scanned by
+ // markroot during the concurrent scan phase. This is updated
+ // atomically during the cycle. Updates may be batched
+ // arbitrarily, since the value is only read at the end of the
+ // cycle.
+ //
+ // Because of benign races during marking, this number may not
+ // be the exact number of marked bytes, but it should be very
+ // close.
+ //
+ // Put this field here because it needs 64-bit atomic access
+ // (and thus 8-byte alignment even on 32-bit architectures).
+ bytesMarked uint64
+
markrootNext uint32 // next markroot job
markrootJobs uint32 // number of markroot jobs
@@ -760,7 +806,18 @@ var work struct {
ndone uint32
alldone note
+ // helperDrainBlock indicates that GC mark termination helpers
+ // 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.
+ helperDrainBlock bool
+
// Number of roots of various root types. Set by gcMarkRootPrepare.
+ nFlushCacheRoots int
nDataRoots, nBSSRoots, nSpanRoots, nStackRoots, nRescanRoots int
// markrootDone indicates that roots have been marked at least
@@ -797,26 +854,10 @@ var work struct {
// mode is the concurrency mode of the current GC cycle.
mode gcMode
- // Copy of mheap.allspans for marker or sweeper.
- spans []*mspan
-
// totaltime is the CPU nanoseconds spent in GC since the
// program started if debug.gctrace > 0.
totaltime int64
- // bytesMarked is the number of bytes marked this cycle. This
- // includes bytes blackened in scanned objects, noscan objects
- // that go straight to black, and permagrey objects scanned by
- // markroot during the concurrent scan phase. This is updated
- // atomically during the cycle. Updates may be batched
- // arbitrarily, since the value is only read at the end of the
- // cycle.
- //
- // Because of benign races during marking, this number may not
- // be the exact number of marked bytes, but it should be very
- // close.
- bytesMarked uint64
-
// initialHeapLive is the value of memstats.heap_live at the
// beginning of this GC cycle.
initialHeapLive uint64
@@ -871,7 +912,7 @@ const (
// 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.next_gc) && memstats.enablegc && panicking == 0 && gcpercent >= 0
+ return gcphase == _GCoff && (forceTrigger || memstats.heap_live >= memstats.gc_trigger) && memstats.enablegc && panicking == 0 && gcpercent >= 0
}
// gcStart transitions the GC from _GCoff to _GCmark (if mode ==
@@ -917,7 +958,7 @@ func gcStart(mode gcMode, forceTrigger bool) {
// another thread.
useStartSema := mode == gcBackgroundMode
if useStartSema {
- semacquire(&work.startSema, false)
+ semacquire(&work.startSema, 0)
// Re-check transition condition under transition lock.
if !gcShouldStart(forceTrigger) {
semrelease(&work.startSema)
@@ -938,7 +979,7 @@ func gcStart(mode gcMode, forceTrigger bool) {
}
// Ok, we're doing it! Stop everybody else
- semacquire(&worldsema, false)
+ semacquire(&worldsema, 0)
if trace.enabled {
traceGCStart()
@@ -961,7 +1002,7 @@ func gcStart(mode gcMode, forceTrigger bool) {
systemstack(stopTheWorldWithSema)
// Finish sweep before we start concurrent scan.
systemstack(func() {
- finishsweep_m(true)
+ finishsweep_m()
})
// clearpools before we start the GC. If we wait they memory will not be
// reclaimed until the next GC cycle.
@@ -969,7 +1010,7 @@ func gcStart(mode gcMode, forceTrigger bool) {
if mode == gcBackgroundMode { // Do as much work concurrently as possible
gcController.startCycle()
- work.heapGoal = gcController.heapGoal
+ work.heapGoal = memstats.next_gc
// Enter concurrent mark phase and enable
// write barriers.
@@ -998,13 +1039,16 @@ func gcStart(mode gcMode, forceTrigger bool) {
// possible.
setGCPhase(_GCmark)
- // markrootSpans uses work.spans, so make sure
- // it is up to date.
- gcCopySpans()
-
gcBgMarkPrepare() // Must happen before assist enable.
gcMarkRootPrepare()
+ // Mark all active tinyalloc blocks. Since we're
+ // allocating from these, they need to be black like
+ // other allocations. The alternative is to blacken
+ // the tiny block on every allocation from it, which
+ // would slow down the tiny allocator.
+ gcMarkTinyAllocs()
+
// At this point all Ps have enabled the write
// barrier, thus maintaining the no white to
// black invariant. Enable mutator assists to
@@ -1052,7 +1096,7 @@ func gcStart(mode gcMode, forceTrigger bool) {
// by mark termination.
func gcMarkDone() {
top:
- semacquire(&work.markDoneSema, false)
+ semacquire(&work.markDoneSema, 0)
// Re-check transition condition under transition lock.
if !(gcphase == _GCmark && work.nwait == work.nproc && !gcMarkWorkAvailable(nil)) {
@@ -1072,9 +1116,8 @@ top:
// Transition from mark 1 to mark 2.
//
// The global work list is empty, but there can still be work
- // sitting in the per-P work caches and there can be more
- // objects reachable from global roots since they don't have write
- // barriers. Rescan some roots and flush work caches.
+ // sitting in the per-P work caches.
+ // Flush and disable work caches.
gcMarkRootCheck()
@@ -1094,8 +1137,7 @@ top:
// ensure all Ps see gcBlackenPromptly. This
// also blocks until any remaining mark 1
// workers have exited their loop so we can
- // start new mark 2 workers that will observe
- // the new root marking jobs.
+ // start new mark 2 workers.
forEachP(func(_p_ *p) {
_p_.gcw.dispose()
})
@@ -1130,11 +1172,6 @@ top:
// this before waking blocked assists.
atomic.Store(&gcBlackenEnabled, 0)
- // Flush the gcWork caches. This must be done before
- // endCycle since endCycle depends on statistics kept
- // in these caches.
- gcFlushGCWork()
-
// Wake all blocked assists. These will run when we
// start the world again.
gcWakeAllAssists()
@@ -1144,6 +1181,8 @@ top:
// world again.
semrelease(&work.markDoneSema)
+ // endCycle depends on all gcWork cache stats being
+ // flushed. This is ensured by mark 2.
gcController.endCycle()
// Perform mark termination. This will restart the world.
@@ -1207,7 +1246,7 @@ func gcMarkTermination() {
// they have gcscanvalid==true and gcworkdone==true.
// Reset these so that all stacks will be rescanned.
gcResetMarkState()
- finishsweep_m(true)
+ finishsweep_m()
// Still in STW but gcphase is _GCoff, reset to _GCmarktermination
// At this point all objects will be found during the gcMark which
@@ -1263,6 +1302,18 @@ func gcMarkTermination() {
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()
+ }
+
// Free stack spans. This must be done between GC cycles.
systemstack(freeStackSpans)
@@ -1443,14 +1494,27 @@ func gcBgMarkWorker(_p_ *p) {
throw("work.nwait was > work.nproc")
}
- switch _p_.gcMarkWorkerMode {
- default:
- throw("gcBgMarkWorker: unexpected gcMarkWorkerMode")
- case gcMarkWorkerDedicatedMode:
- gcDrain(&_p_.gcw, gcDrainNoBlock|gcDrainFlushBgCredit)
- case gcMarkWorkerFractionalMode, gcMarkWorkerIdleMode:
- gcDrain(&_p_.gcw, gcDrainUntilPreempt|gcDrainFlushBgCredit)
- }
+ systemstack(func() {
+ // Mark our goroutine preemptible so its stack
+ // can be scanned. This lets two mark workers
+ // scan each other (otherwise, they would
+ // deadlock). We must not modify anything on
+ // the G stack. However, stack shrinking is
+ // disabled for mark workers, so it is safe to
+ // read from the G stack.
+ casgstatus(gp, _Grunning, _Gwaiting)
+ switch _p_.gcMarkWorkerMode {
+ default:
+ throw("gcBgMarkWorker: unexpected gcMarkWorkerMode")
+ case gcMarkWorkerDedicatedMode:
+ gcDrain(&_p_.gcw, gcDrainNoBlock|gcDrainFlushBgCredit)
+ case gcMarkWorkerFractionalMode:
+ gcDrain(&_p_.gcw, gcDrainUntilPreempt|gcDrainFlushBgCredit)
+ case gcMarkWorkerIdleMode:
+ gcDrain(&_p_.gcw, gcDrainIdle|gcDrainUntilPreempt|gcDrainFlushBgCredit)
+ }
+ casgstatus(gp, _Gwaiting, _Grunning)
+ })
// If we are nearing the end of mark, dispose
// of the cache promptly. We must do this
@@ -1524,18 +1588,8 @@ func gcMarkWorkAvailable(p *p) bool {
return false
}
-// gcFlushGCWork disposes the gcWork caches of all Ps. The world must
-// be stopped.
-//go:nowritebarrier
-func gcFlushGCWork() {
- // Gather all cached GC work. All other Ps are stopped, so
- // it's safe to manipulate their GC work caches.
- for i := 0; i < int(gomaxprocs); i++ {
- allp[i].gcw.dispose()
- }
-}
-
// gcMark runs the mark (or, for concurrent GC, mark termination)
+// All gcWork caches must be empty.
// STW is in effect at this point.
//TODO go:nowritebarrier
func gcMark(start_time int64) {
@@ -1548,13 +1602,6 @@ func gcMark(start_time int64) {
}
work.tstart = start_time
- gcCopySpans() // TODO(rlh): should this be hoisted and done only once? Right now it is done for normal marking and also for checkmarking.
-
- // Make sure the per-P gcWork caches are empty. During mark
- // termination, these caches can still be used temporarily,
- // but must be disposed to the global lists immediately.
- gcFlushGCWork()
-
// Queue root marking jobs.
gcMarkRootPrepare()
@@ -1562,6 +1609,31 @@ 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 {
+ // 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.
+ //
+ // 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
+ // work draining from mark termination so we don't
+ // need the fallback path.
+ work.helperDrainBlock = false
+ } else {
+ work.helperDrainBlock = true
+ }
+
if trace.enabled {
traceGCScanStart()
}
@@ -1574,7 +1646,11 @@ func gcMark(start_time int64) {
gchelperstart()
gcw := &getg().m.p.ptr().gcw
- gcDrain(gcw, gcDrainBlock)
+ if work.helperDrainBlock {
+ gcDrain(gcw, gcDrainBlock)
+ } else {
+ gcDrain(gcw, gcDrainNoBlock)
+ }
gcw.dispose()
if debug.gccheckmark > 0 {
@@ -1593,6 +1669,8 @@ func gcMark(start_time int64) {
// Record that at least one root marking pass has completed.
work.markrootDone = true
+ // Double-check that all gcWork caches are empty. This should
+ // be ensured by mark 2 before we enter mark termination.
for i := 0; i < int(gomaxprocs); i++ {
gcw := &allp[i].gcw
if !gcw.empty() {
@@ -1609,42 +1687,50 @@ func gcMark(start_time int64) {
cachestats()
- // Update the reachable heap stat.
- memstats.heap_reachable = work.bytesMarked
+ // 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 reachable heap size. Assume that
- // we're in steady state, so the reachable heap size is the
+ // 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.next_gc = uint64(float64(memstats.heap_reachable) * (1 + gcController.triggerRatio))
- if memstats.next_gc < heapminimum {
- memstats.next_gc = heapminimum
+ memstats.gc_trigger = uint64(float64(memstats.heap_marked) * (1 + gcController.triggerRatio))
+ if memstats.gc_trigger < heapminimum {
+ memstats.gc_trigger = heapminimum
}
- if int64(memstats.next_gc) < 0 {
+ 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("next_gc underflow")
+ 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_marked = work.bytesMarked
memstats.heap_scan = uint64(gcController.scanWork)
- minNextGC := memstats.heap_live + sweepMinHeapDistance*uint64(gcpercent)/100
- if memstats.next_gc < minNextGC {
+ 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 reachable heap estimate is less than the live
- // heap size.
+ // the marked heap is less than the live heap size.
//
// Concurrent sweep happens in the heap growth from
- // heap_live to next_gc, so bump next_gc up to ensure
+ // 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.next_gc = minNextGC
+ 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 {
@@ -1657,12 +1743,16 @@ func gcSweep(mode gcMode) {
if gcphase != _GCoff {
throw("gcSweep being done but phase is not GCoff")
}
- gcCopySpans()
lock(&mheap_.lock)
mheap_.sweepgen += 2
mheap_.sweepdone = 0
- sweep.spanidx = 0
+ if mheap_.sweepSpans[mheap_.sweepgen/2%2].index != 0 {
+ // We should have drained this list during the last
+ // sweep phase. We certainly need to start this phase
+ // with an empty swept list.
+ throw("non-empty swept list")
+ }
unlock(&mheap_.lock)
if !_ConcurrentSweep || mode == gcForceBlockMode {
@@ -1685,7 +1775,7 @@ func gcSweep(mode gcMode) {
// 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.next_gc) - int64(memstats.heap_live)
+ 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
@@ -1706,26 +1796,6 @@ func gcSweep(mode gcMode) {
ready(sweep.g, 0, true)
}
unlock(&sweep.lock)
- mProf_GC()
-}
-
-func gcCopySpans() {
- // Cache runtime.mheap_.allspans in work.spans to avoid conflicts with
- // resizing/freeing allspans.
- // New spans can be created while GC progresses, but they are not garbage for
- // this round:
- // - new stack spans can be created even while the world is stopped.
- // - new malloc spans can be created during the concurrent sweep
- // Even if this is stop-the-world, a concurrent exitsyscall can allocate a stack from heap.
- lock(&mheap_.lock)
- // Free the old cached mark array if necessary.
- if work.spans != nil && &work.spans[0] != &h_allspans[0] {
- sysFree(unsafe.Pointer(&work.spans[0]), uintptr(len(work.spans))*unsafe.Sizeof(work.spans[0]), &memstats.other_sys)
- }
- // Cache the current array for sweeping.
- mheap_.gcspans = mheap_.allspans
- work.spans = h_allspans
- unlock(&mheap_.lock)
}
// gcResetMarkState resets global state prior to marking (concurrent
@@ -1816,7 +1886,11 @@ func gchelper() {
// Parallel mark over GC roots and heap
if gcphase == _GCmarktermination {
gcw := &_g_.m.p.ptr().gcw
- gcDrain(gcw, gcDrainBlock) // blocks in getfull
+ if work.helperDrainBlock {
+ gcDrain(gcw, gcDrainBlock) // blocks in getfull
+ } else {
+ gcDrain(gcw, gcDrainNoBlock)
+ }
gcw.dispose()
}
diff --git a/src/runtime/mgcmark.go b/src/runtime/mgcmark.go
index aa7f7a7..85130bf 100644
--- a/src/runtime/mgcmark.go
+++ b/src/runtime/mgcmark.go
@@ -14,7 +14,6 @@ import (
const (
fixedRootFinalizers = iota
- fixedRootFlushCaches
fixedRootFreeGStacks
fixedRootCount
@@ -25,6 +24,23 @@ const (
// rootBlockSpans is the number of spans to scan per span
// root.
rootBlockSpans = 8 * 1024 // 64MB worth of spans
+
+ // maxObletBytes is the maximum bytes of an object to scan at
+ // once. Larger objects will be split up into "oblets" of at
+ // most this size. Since we can scan 1–2 MB/ms, 128 KB bounds
+ // scan preemption at ~100 µs.
+ //
+ // This must be > _MaxSmallSize so that the object base is the
+ // span base.
+ maxObletBytes = 128 << 10
+
+ // idleCheckThreshold specifies how many units of work to do
+ // between run queue checks in an idle worker. Assuming a scan
+ // rate of 1 MB/ms, this is ~100 µs. Lower values have higher
+ // overhead in the scan loop (the scheduler check may perform
+ // a syscall, so its overhead is nontrivial). Higher values
+ // make the system less responsive to incoming work.
+ idleCheckThreshold = 100000
)
// gcMarkRootPrepare queues root scanning jobs (stacks, globals, and
@@ -36,6 +52,12 @@ const (
//
//go:nowritebarrier
func gcMarkRootPrepare() {
+ if gcphase == _GCmarktermination {
+ work.nFlushCacheRoots = int(gomaxprocs)
+ } else {
+ work.nFlushCacheRoots = 0
+ }
+
// Compute how many data and BSS root blocks there are.
nBlocks := func(bytes uintptr) int {
return int((bytes + rootBlockBytes - 1) / rootBlockBytes)
@@ -46,14 +68,14 @@ func gcMarkRootPrepare() {
// Only scan globals once per cycle; preferably concurrently.
if !work.markrootDone {
- for datap := &firstmoduledata; datap != nil; datap = datap.next {
+ for _, datap := range activeModules() {
nDataRoots := nBlocks(datap.edata - datap.data)
if nDataRoots > work.nDataRoots {
work.nDataRoots = nDataRoots
}
}
- for datap := &firstmoduledata; datap != nil; datap = datap.next {
+ for _, datap := range activeModules() {
nBSSRoots := nBlocks(datap.ebss - datap.bss)
if nBSSRoots > work.nBSSRoots {
work.nBSSRoots = nBSSRoots
@@ -68,7 +90,13 @@ func gcMarkRootPrepare() {
// above invariants for objects that get finalizers
// after concurrent mark. In STW GC, this will happen
// during mark termination.
- work.nSpanRoots = (len(work.spans) + rootBlockSpans - 1) / rootBlockSpans
+ //
+ // We're only interested in scanning the in-use spans,
+ // which will all be swept at this point. More spans
+ // may be added to this list during concurrent GC, but
+ // we only care about spans that were allocated before
+ // this mark phase.
+ work.nSpanRoots = mheap_.sweepSpans[mheap_.sweepgen/2%2].numBlocks()
// On the first markroot, we need to scan all Gs. Gs
// may be created after this point, but it's okay that
@@ -93,7 +121,7 @@ func gcMarkRootPrepare() {
}
work.markrootNext = 0
- work.markrootJobs = uint32(fixedRootCount + work.nDataRoots + work.nBSSRoots + work.nSpanRoots + work.nStackRoots + work.nRescanRoots)
+ work.markrootJobs = uint32(fixedRootCount + work.nFlushCacheRoots + work.nDataRoots + work.nBSSRoots + work.nSpanRoots + work.nStackRoots + work.nRescanRoots)
}
// gcMarkRootCheck checks that all roots have been scanned. It is
@@ -106,26 +134,32 @@ func gcMarkRootCheck() {
lock(&allglock)
// Check that stacks have been scanned.
- if gcphase == _GCmarktermination {
+ var gp *g
+ if gcphase == _GCmarktermination && debug.gcrescanstacks > 0 {
for i := 0; i < len(allgs); i++ {
- gp := allgs[i]
+ gp = allgs[i]
if !(gp.gcscandone && gp.gcscanvalid) && readgstatus(gp) != _Gdead {
- println("gp", gp, "goid", gp.goid,
- "status", readgstatus(gp),
- "gcscandone", gp.gcscandone,
- "gcscanvalid", gp.gcscanvalid)
- throw("scan missed a g")
+ goto fail
}
}
} else {
for i := 0; i < work.nStackRoots; i++ {
- gp := allgs[i]
+ gp = allgs[i]
if !gp.gcscandone {
- throw("scan missed a g")
+ goto fail
}
}
}
unlock(&allglock)
+ return
+
+fail:
+ println("gp", gp, "goid", gp.goid,
+ "status", readgstatus(gp),
+ "gcscandone", gp.gcscandone,
+ "gcscanvalid", gp.gcscanvalid)
+ unlock(&allglock) // Avoid self-deadlock with traceback.
+ throw("scan missed a g")
}
// ptrmask for an allocation containing a single pointer.
@@ -141,7 +175,8 @@ var oneptrmask = [...]uint8{1}
func markroot(gcw *gcWork, i uint32) {
// TODO(austin): This is a bit ridiculous. Compute and store
// the bases in gcMarkRootPrepare instead of the counts.
- baseData := uint32(fixedRootCount)
+ baseFlushCache := uint32(fixedRootCount)
+ baseData := baseFlushCache + uint32(work.nFlushCacheRoots)
baseBSS := baseData + uint32(work.nDataRoots)
baseSpans := baseBSS + uint32(work.nBSSRoots)
baseStacks := baseSpans + uint32(work.nSpanRoots)
@@ -150,24 +185,23 @@ func markroot(gcw *gcWork, i uint32) {
// Note: if you add a case here, please also update heapdump.go:dumproots.
switch {
+ case baseFlushCache <= i && i < baseData:
+ flushmcache(int(i - baseFlushCache))
+
case baseData <= i && i < baseBSS:
- for datap := &firstmoduledata; datap != nil; datap = datap.next {
+ for _, datap := range activeModules() {
markrootBlock(datap.data, datap.edata-datap.data, datap.gcdatamask.bytedata, gcw, int(i-baseData))
}
case baseBSS <= i && i < baseSpans:
- for datap := &firstmoduledata; datap != nil; datap = datap.next {
+ for _, datap := range activeModules() {
markrootBlock(datap.bss, datap.ebss-datap.bss, datap.gcbssmask.bytedata, gcw, int(i-baseBSS))
}
case i == fixedRootFinalizers:
for fb := allfin; fb != nil; fb = fb.alllink {
- scanblock(uintptr(unsafe.Pointer(&fb.fin[0])), uintptr(fb.cnt)*unsafe.Sizeof(fb.fin[0]), &finptrmask[0], gcw)
- }
-
- case i == fixedRootFlushCaches:
- if gcphase == _GCmarktermination { // Do not flush mcaches during concurrent phase.
- flushallmcaches()
+ cnt := uintptr(atomic.Load(&fb.cnt))
+ scanblock(uintptr(unsafe.Pointer(&fb.fin[0])), cnt*unsafe.Sizeof(fb.fin[0]), &finptrmask[0], gcw)
}
case i == fixedRootFreeGStacks:
@@ -190,6 +224,11 @@ func markroot(gcw *gcWork, i uint32) {
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")
}
@@ -201,24 +240,13 @@ func markroot(gcw *gcWork, i uint32) {
gp.waitsince = work.tstart
}
- if gcphase != _GCmarktermination && gp.startpc == gcBgMarkWorkerPC && readgstatus(gp) != _Gdead {
- // GC background workers may be
- // non-preemptible, so we may deadlock if we
- // try to scan them during a concurrent phase.
- // They also have tiny stacks, so just ignore
- // them until mark termination.
- gp.gcscandone = true
- queueRescan(gp)
- break
- }
-
// scang must be done on the system stack in case
// we're trying to scan our own stack.
systemstack(func() {
// If this is a self-scan, put the user G in
// _Gwaiting to prevent self-deadlock. It may
- // already be in _Gwaiting if this is mark
- // termination.
+ // already be in _Gwaiting if this is a mark
+ // worker or we're in mark termination.
userG := getg().m.curg
selfScan := gp == userG && readgstatus(userG) == _Grunning
if selfScan {
@@ -318,18 +346,14 @@ func markrootSpans(gcw *gcWork, shard int) {
}
sg := mheap_.sweepgen
- startSpan := shard * rootBlockSpans
- endSpan := (shard + 1) * rootBlockSpans
- if endSpan > len(work.spans) {
- endSpan = len(work.spans)
- }
+ spans := mheap_.sweepSpans[mheap_.sweepgen/2%2].block(shard)
// Note that work.spans may not include spans that were
// allocated between entering the scan phase and now. This is
// okay because any objects with finalizers in those spans
// must have been allocated and given finalizers after we
// entered the scan phase, so addfinalizer will have ensured
// the above invariants for them.
- for _, s := range work.spans[startSpan:endSpan] {
+ for _, s := range spans {
if s.state != mSpanInUse {
continue
}
@@ -381,7 +405,6 @@ func markrootSpans(gcw *gcWork, shard int) {
// gp must be the calling user gorountine.
//
// This must be called with preemption enabled.
-//go:nowritebarrier
func gcAssistAlloc(gp *g) {
// Don't assist in non-preemptible contexts. These are
// generally fragile and won't allow the assist to block.
@@ -392,6 +415,7 @@ func gcAssistAlloc(gp *g) {
return
}
+retry:
// Compute the amount of scan work we need to do to make the
// balance positive. When the required amount of work is low,
// we over-assist to build up credit for future allocations
@@ -403,7 +427,6 @@ func gcAssistAlloc(gp *g) {
debtBytes = int64(gcController.assistBytesPerWork * float64(scanWork))
}
-retry:
// Steal as much credit as we can from the background GC's
// scan credit. This is racy and may drop the background
// credit below 0 if two mutators steal at the same time. This
@@ -432,72 +455,14 @@ retry:
}
// Perform assist work
- completed := false
systemstack(func() {
- if atomic.Load(&gcBlackenEnabled) == 0 {
- // The gcBlackenEnabled check in malloc races with the
- // store that clears it but an atomic check in every malloc
- // would be a performance hit.
- // Instead we recheck it here on the non-preemptable system
- // stack to determine if we should preform an assist.
-
- // GC is done, so ignore any remaining debt.
- gp.gcAssistBytes = 0
- return
- }
- // Track time spent in this assist. Since we're on the
- // system stack, this is non-preemptible, so we can
- // just measure start and end time.
- startTime := nanotime()
-
- decnwait := atomic.Xadd(&work.nwait, -1)
- if decnwait == work.nproc {
- println("runtime: work.nwait =", decnwait, "work.nproc=", work.nproc)
- throw("nwait > work.nprocs")
- }
-
- // drain own cached work first in the hopes that it
- // will be more cache friendly.
- gcw := &getg().m.p.ptr().gcw
- workDone := gcDrainN(gcw, scanWork)
- // If we are near the end of the mark phase
- // dispose of the gcw.
- if gcBlackenPromptly {
- gcw.dispose()
- }
-
- // Record that we did this much scan work.
- //
- // Back out the number of bytes of assist credit that
- // this scan work counts for. The "1+" is a poor man's
- // round-up, to ensure this adds credit even if
- // assistBytesPerWork is very low.
- gp.gcAssistBytes += 1 + int64(gcController.assistBytesPerWork*float64(workDone))
-
- // If this is the last worker and we ran out of work,
- // signal a completion point.
- incnwait := atomic.Xadd(&work.nwait, +1)
- if incnwait > work.nproc {
- println("runtime: work.nwait=", incnwait,
- "work.nproc=", work.nproc,
- "gcBlackenPromptly=", gcBlackenPromptly)
- throw("work.nwait > work.nproc")
- }
-
- if incnwait == work.nproc && !gcMarkWorkAvailable(nil) {
- // This has reached a background completion
- // point.
- completed = true
- }
- duration := nanotime() - startTime
- _p_ := gp.m.p.ptr()
- _p_.gcAssistTime += duration
- if _p_.gcAssistTime > gcAssistTimeSlack {
- atomic.Xaddint64(&gcController.assistTime, _p_.gcAssistTime)
- _p_.gcAssistTime = 0
- }
+ gcAssistAlloc1(gp, scanWork)
+ // The user stack may have moved, so this can't touch
+ // anything on it until it returns from systemstack.
})
+ completed := gp.param != nil
+ gp.param = nil
if completed {
gcMarkDone()
}
@@ -524,46 +489,102 @@ retry:
// there wasn't enough work to do anyway, so we might
// as well let background marking take care of the
// work that is available.
- lock(&work.assistQueue.lock)
-
- // If the GC cycle is over, just return. This is the
- // likely path if we completed above. We do this
- // under the lock to prevent a GC cycle from ending
- // between this check and queuing the assist.
- if atomic.Load(&gcBlackenEnabled) == 0 {
- unlock(&work.assistQueue.lock)
- return
- }
-
- oldHead, oldTail := work.assistQueue.head, work.assistQueue.tail
- if oldHead == 0 {
- work.assistQueue.head.set(gp)
- } else {
- oldTail.ptr().schedlink.set(gp)
- }
- work.assistQueue.tail.set(gp)
- gp.schedlink.set(nil)
- // Recheck for background credit now that this G is in
- // the queue, but can still back out. This avoids a
- // race in case background marking has flushed more
- // credit since we checked above.
- if atomic.Loadint64(&gcController.bgScanCredit) > 0 {
- work.assistQueue.head = oldHead
- work.assistQueue.tail = oldTail
- if oldTail != 0 {
- oldTail.ptr().schedlink.set(nil)
- }
- unlock(&work.assistQueue.lock)
+ if !gcParkAssist() {
goto retry
}
- // Park for real.
- goparkunlock(&work.assistQueue.lock, "GC assist wait", traceEvGoBlock, 2)
// At this point either background GC has satisfied
// this G's assist debt, or the GC cycle is over.
}
}
+// gcAssistAlloc1 is the part of gcAssistAlloc that runs on the system
+// stack. This is a separate function to make it easier to see that
+// we're not capturing anything from the user stack, since the user
+// stack may move while we're in this function.
+//
+// gcAssistAlloc1 indicates whether this assist completed the mark
+// phase by setting gp.param to non-nil. This can't be communicated on
+// the stack since it may move.
+//
+//go:systemstack
+func gcAssistAlloc1(gp *g, scanWork int64) {
+ // Clear the flag indicating that this assist completed the
+ // mark phase.
+ gp.param = nil
+
+ if atomic.Load(&gcBlackenEnabled) == 0 {
+ // The gcBlackenEnabled check in malloc races with the
+ // store that clears it but an atomic check in every malloc
+ // would be a performance hit.
+ // Instead we recheck it here on the non-preemptable system
+ // stack to determine if we should preform an assist.
+
+ // GC is done, so ignore any remaining debt.
+ gp.gcAssistBytes = 0
+ return
+ }
+ // Track time spent in this assist. Since we're on the
+ // system stack, this is non-preemptible, so we can
+ // just measure start and end time.
+ startTime := nanotime()
+
+ decnwait := atomic.Xadd(&work.nwait, -1)
+ if decnwait == work.nproc {
+ println("runtime: work.nwait =", decnwait, "work.nproc=", work.nproc)
+ throw("nwait > work.nprocs")
+ }
+
+ // gcDrainN requires the caller to be preemptible.
+ casgstatus(gp, _Grunning, _Gwaiting)
+ gp.waitreason = "GC assist marking"
+
+ // drain own cached work first in the hopes that it
+ // will be more cache friendly.
+ gcw := &getg().m.p.ptr().gcw
+ workDone := gcDrainN(gcw, scanWork)
+ // If we are near the end of the mark phase
+ // dispose of the gcw.
+ if gcBlackenPromptly {
+ gcw.dispose()
+ }
+
+ casgstatus(gp, _Gwaiting, _Grunning)
+
+ // Record that we did this much scan work.
+ //
+ // Back out the number of bytes of assist credit that
+ // this scan work counts for. The "1+" is a poor man's
+ // round-up, to ensure this adds credit even if
+ // assistBytesPerWork is very low.
+ gp.gcAssistBytes += 1 + int64(gcController.assistBytesPerWork*float64(workDone))
+
+ // If this is the last worker and we ran out of work,
+ // signal a completion point.
+ incnwait := atomic.Xadd(&work.nwait, +1)
+ if incnwait > work.nproc {
+ println("runtime: work.nwait=", incnwait,
+ "work.nproc=", work.nproc,
+ "gcBlackenPromptly=", gcBlackenPromptly)
+ throw("work.nwait > work.nproc")
+ }
+
+ if incnwait == work.nproc && !gcMarkWorkAvailable(nil) {
+ // This has reached a background completion point. Set
+ // gp.param to a non-nil value to indicate this. It
+ // doesn't matter what we set it to (it just has to be
+ // a valid pointer).
+ gp.param = unsafe.Pointer(gp)
+ }
+ duration := nanotime() - startTime
+ _p_ := gp.m.p.ptr()
+ _p_.gcAssistTime += duration
+ if _p_.gcAssistTime > gcAssistTimeSlack {
+ atomic.Xaddint64(&gcController.assistTime, _p_.gcAssistTime)
+ _p_.gcAssistTime = 0
+ }
+}
+
// gcWakeAllAssists wakes all currently blocked assists. This is used
// at the end of a GC cycle. gcBlackenEnabled must be false to prevent
// new assists from going to sleep after this point.
@@ -575,6 +596,50 @@ func gcWakeAllAssists() {
unlock(&work.assistQueue.lock)
}
+// gcParkAssist puts the current goroutine on the assist queue and parks.
+//
+// gcParkAssist returns whether the assist is now satisfied. If it
+// returns false, the caller must retry the assist.
+//
+//go:nowritebarrier
+func gcParkAssist() bool {
+ lock(&work.assistQueue.lock)
+ // If the GC cycle finished while we were getting the lock,
+ // exit the assist. The cycle can't finish while we hold the
+ // lock.
+ if atomic.Load(&gcBlackenEnabled) == 0 {
+ unlock(&work.assistQueue.lock)
+ return true
+ }
+
+ gp := getg()
+ oldHead, oldTail := work.assistQueue.head, work.assistQueue.tail
+ if oldHead == 0 {
+ work.assistQueue.head.set(gp)
+ } else {
+ oldTail.ptr().schedlink.set(gp)
+ }
+ work.assistQueue.tail.set(gp)
+ gp.schedlink.set(nil)
+
+ // Recheck for background credit now that this G is in
+ // the queue, but can still back out. This avoids a
+ // race in case background marking has flushed more
+ // credit since we checked above.
+ if atomic.Loadint64(&gcController.bgScanCredit) > 0 {
+ work.assistQueue.head = oldHead
+ work.assistQueue.tail = oldTail
+ if oldTail != 0 {
+ oldTail.ptr().schedlink.set(nil)
+ }
+ unlock(&work.assistQueue.lock)
+ return false
+ }
+ // Park.
+ goparkunlock(&work.assistQueue.lock, "GC assist wait", traceEvGoBlockGC, 2)
+ return true
+}
+
// gcFlushBgCredit flushes scanWork units of background scan work
// credit. This first satisfies blocked assists on the
// work.assistQueue and then flushes any remaining credit to
@@ -865,6 +930,15 @@ func scanframeworker(frame *stkframe, cache *pcvalueCache, gcw *gcWork) {
// 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
@@ -894,6 +968,10 @@ func queueRescan(gp *g) {
// 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
}
@@ -921,6 +999,7 @@ const (
gcDrainUntilPreempt gcDrainFlags = 1 << iota
gcDrainNoBlock
gcDrainFlushBgCredit
+ gcDrainIdle
// gcDrainBlock means neither gcDrainUntilPreempt or
// gcDrainNoBlock. It is the default, but callers should use
@@ -934,6 +1013,9 @@ const (
// If flags&gcDrainUntilPreempt != 0, gcDrain returns when g.preempt
// is set. This implies gcDrainNoBlock.
//
+// If flags&gcDrainIdle != 0, gcDrain returns when there is other work
+// to do. This implies gcDrainNoBlock.
+//
// If flags&gcDrainNoBlock != 0, gcDrain returns as soon as it is
// unable to get more work. Otherwise, it will block until all
// blocking calls are blocked in gcDrain.
@@ -948,24 +1030,31 @@ func gcDrain(gcw *gcWork, flags gcDrainFlags) {
throw("gcDrain phase incorrect")
}
- gp := getg()
+ gp := getg().m.curg
preemptible := flags&gcDrainUntilPreempt != 0
- blocking := flags&(gcDrainUntilPreempt|gcDrainNoBlock) == 0
+ blocking := flags&(gcDrainUntilPreempt|gcDrainIdle|gcDrainNoBlock) == 0
flushBgCredit := flags&gcDrainFlushBgCredit != 0
+ idle := flags&gcDrainIdle != 0
+
+ initScanWork := gcw.scanWork
+ // idleCheck is the scan work at which to perform the next
+ // idle check with the scheduler.
+ idleCheck := initScanWork + idleCheckThreshold
// Drain root marking jobs.
if work.markrootNext < work.markrootJobs {
- for blocking || !gp.preempt {
+ for !(preemptible && gp.preempt) {
job := atomic.Xadd(&work.markrootNext, +1) - 1
if job >= work.markrootJobs {
break
}
markroot(gcw, job)
+ if idle && pollWork() {
+ goto done
+ }
}
}
- initScanWork := gcw.scanWork
-
// Drain heap marking jobs.
for !(preemptible && gp.preempt) {
// Try to keep work available on the global queue. We used to
@@ -1001,7 +1090,15 @@ func gcDrain(gcw *gcWork, flags gcDrainFlags) {
gcFlushBgCredit(gcw.scanWork - initScanWork)
initScanWork = 0
}
+ idleCheck -= gcw.scanWork
gcw.scanWork = 0
+
+ if idle && idleCheck <= 0 {
+ idleCheck += idleCheckThreshold
+ if pollWork() {
+ break
+ }
+ }
}
}
@@ -1009,6 +1106,7 @@ func gcDrain(gcw *gcWork, flags gcDrainFlags) {
// point because we must preserve the condition that the work
// buffers are empty.
+done:
// Flush remaining scan work credit.
if gcw.scanWork > 0 {
atomic.Xaddint64(&gcController.scanWork, gcw.scanWork)
@@ -1025,7 +1123,13 @@ func gcDrain(gcw *gcWork, flags gcDrainFlags) {
// buffer. Otherwise, it will perform at least n units of work, but
// may perform more because scanning is always done in whole object
// increments. It returns the amount of scan work performed.
+//
+// The caller goroutine must be in a preemptible state (e.g.,
+// _Gwaiting) to prevent deadlocks during stack scanning. As a
+// consequence, this must be called on the system stack.
+//
//go:nowritebarrier
+//go:systemstack
func gcDrainN(gcw *gcWork, scanWork int64) int64 {
if !writeBarrier.needed {
throw("gcDrainN phase incorrect")
@@ -1053,6 +1157,18 @@ func gcDrainN(gcw *gcWork, scanWork int64) int64 {
}
if b == 0 {
+ // Try to do a root job.
+ //
+ // TODO: Assists should get credit for this
+ // work.
+ if work.markrootNext < work.markrootJobs {
+ job := atomic.Xadd(&work.markrootNext, +1) - 1
+ if job < work.markrootJobs {
+ markroot(gcw, job)
+ continue
+ }
+ }
+ // No heap or root jobs.
break
}
scanobject(b, gcw)
@@ -1113,9 +1229,10 @@ func scanblock(b0, n0 uintptr, ptrmask *uint8, gcw *gcWork) {
}
// scanobject scans the object starting at b, adding pointers to gcw.
-// b must point to the beginning of a heap object; scanobject consults
-// the GC bitmap for the pointer mask and the spans for the size of the
-// object.
+// b must point to the beginning of a heap object or an oblet.
+// scanobject consults the GC bitmap for the pointer mask and the
+// spans for the size of the object.
+//
//go:nowritebarrier
func scanobject(b uintptr, gcw *gcWork) {
// Note that arena_used may change concurrently during
@@ -1130,9 +1247,11 @@ func scanobject(b uintptr, gcw *gcWork) {
arena_start := mheap_.arena_start
arena_used := mheap_.arena_used
- // Find bits of the beginning of the object.
- // b must point to the beginning of a heap object, so
- // we can get its bits and span directly.
+ // Find the bits for b and the size of the object at b.
+ //
+ // b is either the beginning of an object, in which case this
+ // is the size of the object to scan, or it points to an
+ // oblet, in which case we compute the size to scan below.
hbits := heapBitsForAddr(b)
s := spanOfUnchecked(b)
n := s.elemsize
@@ -1140,6 +1259,42 @@ func scanobject(b uintptr, gcw *gcWork) {
throw("scanobject n == 0")
}
+ if n > maxObletBytes {
+ // Large object. Break into oblets for better
+ // parallelism and lower latency.
+ if b == s.base() {
+ // It's possible this is a noscan object (not
+ // from greyobject, but from other code
+ // paths), in which case we must *not* enqueue
+ // oblets since their bitmaps will be
+ // uninitialized.
+ if !hbits.hasPointers(n) {
+ // Bypass the whole scan.
+ gcw.bytesMarked += uint64(n)
+ return
+ }
+
+ // Enqueue the other oblets to scan later.
+ // Some oblets may be in b's scalar tail, but
+ // these will be marked as "no more pointers",
+ // so we'll drop out immediately when we go to
+ // scan those.
+ for oblet := b + maxObletBytes; oblet < s.base()+s.elemsize; oblet += maxObletBytes {
+ if !gcw.putFast(oblet) {
+ gcw.put(oblet)
+ }
+ }
+ }
+
+ // Compute the size of the oblet. Since this object
+ // must be a large object, s.base() is the beginning
+ // of the object.
+ n = s.base() + s.elemsize - b
+ if n > maxObletBytes {
+ n = maxObletBytes
+ }
+ }
+
var i uintptr
for i = 0; i < n; i += sys.PtrSize {
// Find bits for this word.
@@ -1147,14 +1302,16 @@ func scanobject(b uintptr, gcw *gcWork) {
// Avoid needless hbits.next() on last iteration.
hbits = hbits.next()
}
+ // Load bits once. See CL 22712 and issue 16973 for discussion.
+ bits := hbits.bits()
// During checkmarking, 1-word objects store the checkmark
// in the type bit for the one word. The only one-word objects
// are pointers, or else they'd be merged with other non-pointer
// data into larger allocations.
- if i != 1*sys.PtrSize && !hbits.morePointers() {
+ if i != 1*sys.PtrSize && bits&bitScan == 0 {
break // no more pointers in this object
}
- if !hbits.isPointer() {
+ if bits&bitPointer == 0 {
continue // not a pointer
}
@@ -1224,6 +1381,13 @@ func greyobject(obj, base, off uintptr, hbits heapBits, span *mspan, gcw *gcWork
throw("setCheckmarked and isCheckmarked disagree")
}
} else {
+ if debug.gccheckmark > 0 && span.isFree(objIndex) {
+ print("runtime: marking free object ", hex(obj), " found at *(", hex(base), "+", hex(off), ")\n")
+ gcDumpObject("base", base, off)
+ gcDumpObject("obj", obj, ^uintptr(0))
+ throw("marking free object")
+ }
+
// If marked we have nothing to do.
if mbits.isMarked() {
return
@@ -1259,15 +1423,28 @@ func gcDumpObject(label string, obj, off uintptr) {
k := obj >> _PageShift
x := k
x -= mheap_.arena_start >> _PageShift
- s := h_spans[x]
+ s := mheap_.spans[x]
print(label, "=", hex(obj), " k=", hex(k))
if s == nil {
print(" s=nil\n")
return
}
- print(" s.base()=", hex(s.base()), " s.limit=", hex(s.limit), " s.sizeclass=", s.sizeclass, " s.elemsize=", s.elemsize, "\n")
+ print(" s.base()=", hex(s.base()), " s.limit=", hex(s.limit), " s.sizeclass=", s.sizeclass, " s.elemsize=", s.elemsize, " s.state=")
+ if 0 <= s.state && int(s.state) < len(mSpanStateNames) {
+ print(mSpanStateNames[s.state], "\n")
+ } else {
+ print("unknown(", s.state, ")\n")
+ }
+
skipped := false
- for i := uintptr(0); i < s.elemsize; i += sys.PtrSize {
+ size := s.elemsize
+ if s.state == _MSpanStack && 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.
+ size = off + sys.PtrSize
+ }
+ for i := uintptr(0); i < size; i += sys.PtrSize {
// For big objects, just print the beginning (because
// that usually hints at the object's type) and the
// fields around off.
@@ -1305,6 +1482,32 @@ func gcmarknewobject(obj, size, scanSize uintptr) {
gcw := &getg().m.p.ptr().gcw
gcw.bytesMarked += uint64(size)
gcw.scanWork += int64(scanSize)
+ if gcBlackenPromptly {
+ // There shouldn't be anything in the work queue, but
+ // we still need to flush stats.
+ gcw.dispose()
+ }
+}
+
+// gcMarkTinyAllocs greys all active tiny alloc blocks.
+//
+// The world must be stopped.
+func gcMarkTinyAllocs() {
+ for _, p := range &allp {
+ if p == nil || p.status == _Pdead {
+ break
+ }
+ c := p.mcache
+ if c == nil || c.tiny == 0 {
+ continue
+ }
+ _, hbits, span, objIndex := heapBitsForObject(c.tiny, 0, 0)
+ gcw := &p.gcw
+ greyobject(c.tiny, 0, 0, hbits, span, gcw, objIndex)
+ if gcBlackenPromptly {
+ gcw.dispose()
+ }
+ }
}
// Checkmarking
@@ -1333,7 +1536,7 @@ var useCheckmark = false
//go:nowritebarrier
func initCheckmarks() {
useCheckmark = true
- for _, s := range work.spans {
+ for _, s := range mheap_.allspans {
if s.state == _MSpanInUse {
heapBitsForSpan(s.base()).initCheckmarkSpan(s.layout())
}
@@ -1342,7 +1545,7 @@ func initCheckmarks() {
func clearCheckmarks() {
useCheckmark = false
- for _, s := range work.spans {
+ for _, s := range mheap_.allspans {
if s.state == _MSpanInUse {
heapBitsForSpan(s.base()).clearCheckmarkSpan(s.layout())
}
diff --git a/src/runtime/mgcsweep.go b/src/runtime/mgcsweep.go
index 947c38e..e74a451 100644
--- a/src/runtime/mgcsweep.go
+++ b/src/runtime/mgcsweep.go
@@ -20,14 +20,21 @@ type sweepdata struct {
parked bool
started bool
- spanidx uint32 // background sweeper position
-
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.
+//
+// The world must be stopped. This ensures there are no sweeps in
+// progress.
+//
//go:nowritebarrier
-func finishsweep_m(stw bool) {
+func finishsweep_m() {
// Sweeping must be complete before marking commences, so
// sweep any unswept spans. If this is a concurrent GC, there
// shouldn't be any spans left to sweep, so this should finish
@@ -37,20 +44,6 @@ func finishsweep_m(stw bool) {
sweep.npausesweep++
}
- // There may be some other spans being swept concurrently that
- // we need to wait for. If finishsweep_m is done with the world stopped
- // this is not required because the STW must have waited for sweeps.
- //
- // TODO(austin): As of this writing, we always pass true for stw.
- // Consider removing this code.
- if !stw {
- sg := mheap_.sweepgen
- for _, s := range work.spans {
- if s.sweepgen != sg && s.state == _MSpanInUse {
- s.ensureSwept()
- }
- }
- }
nextMarkBitArenaEpoch()
}
@@ -91,18 +84,23 @@ func sweepone() uintptr {
_g_.m.locks++
sg := mheap_.sweepgen
for {
- idx := atomic.Xadd(&sweep.spanidx, 1) - 1
- if idx >= uint32(len(work.spans)) {
+ s := mheap_.sweepSpans[1-sg/2%2].pop()
+ if s == nil {
mheap_.sweepdone = 1
_g_.m.locks--
- if debug.gcpacertrace > 0 && idx == uint32(len(work.spans)) {
+ 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)
}
- s := work.spans[idx]
if s.state != mSpanInUse {
- s.sweepgen = sg
+ // This can happen if direct sweeping already
+ // swept this span, but in that case the sweep
+ // generation should always be up-to-date.
+ if s.sweepgen != sg {
+ print("runtime: bad span s.state=", s.state, " s.sweepgen=", s.sweepgen, " sweepgen=", sg, "\n")
+ throw("non in-use span in unswept list")
+ }
continue
}
if s.sweepgen != sg-2 || !atomic.Cas(&s.sweepgen, sg-2, sg-1) {
@@ -110,6 +108,9 @@ func sweepone() uintptr {
}
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--
@@ -348,6 +349,11 @@ func (s *mspan) sweep(preserve bool) bool {
c.local_largefree += size
res = true
}
+ if !res {
+ // The span has been swept and is still in-use, so put
+ // it on the swept in-use list.
+ mheap_.sweepSpans[sweepgen/2%2].push(s)
+ }
if trace.enabled {
traceGCSweepDone()
}
diff --git a/src/runtime/mgcsweepbuf.go b/src/runtime/mgcsweepbuf.go
new file mode 100644
index 0000000..6c1118e
--- /dev/null
+++ b/src/runtime/mgcsweepbuf.go
@@ -0,0 +1,178 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runtime
+
+import (
+ "runtime/internal/atomic"
+ "runtime/internal/sys"
+ "unsafe"
+)
+
+// A gcSweepBuf is a set of *mspans.
+//
+// gcSweepBuf is safe for concurrent push operations *or* concurrent
+// pop operations, but not both simultaneously.
+type gcSweepBuf struct {
+ // A gcSweepBuf is a two-level data structure consisting of a
+ // growable spine that points to fixed-sized blocks. The spine
+ // can be accessed without locks, but adding a block or
+ // growing it requires taking the spine lock.
+ //
+ // Because each mspan covers at least 8K of heap and takes at
+ // most 8 bytes in the gcSweepBuf, the growth of the spine is
+ // quite limited.
+ //
+ // The spine and all blocks are allocated off-heap, which
+ // allows this to be used in the memory manager and avoids the
+ // need for write barriers on all of these. We never release
+ // this memory because there could be concurrent lock-free
+ // access and we're likely to reuse it anyway. (In principle,
+ // we could do this during STW.)
+
+ spineLock mutex
+ spine unsafe.Pointer // *[N]*gcSweepBlock, accessed atomically
+ spineLen uintptr // Spine array length, accessed atomically
+ spineCap uintptr // Spine array cap, accessed under lock
+
+ // index is the first unused slot in the logical concatenation
+ // of all blocks. It is accessed atomically.
+ index uint32
+}
+
+const (
+ gcSweepBlockEntries = 512 // 4KB on 64-bit
+ gcSweepBufInitSpineCap = 256 // Enough for 1GB heap on 64-bit
+)
+
+type gcSweepBlock struct {
+ spans [gcSweepBlockEntries]*mspan
+}
+
+// push adds span s to buffer b. push is safe to call concurrently
+// with other push operations, but NOT to call concurrently with pop.
+func (b *gcSweepBuf) push(s *mspan) {
+ // Obtain our slot.
+ cursor := uintptr(atomic.Xadd(&b.index, +1) - 1)
+ top, bottom := cursor/gcSweepBlockEntries, cursor%gcSweepBlockEntries
+
+ // Do we need to add a block?
+ spineLen := atomic.Loaduintptr(&b.spineLen)
+ var block *gcSweepBlock
+retry:
+ if top < spineLen {
+ spine := atomic.Loadp(unsafe.Pointer(&b.spine))
+ blockp := add(spine, sys.PtrSize*top)
+ block = (*gcSweepBlock)(atomic.Loadp(blockp))
+ } else {
+ // Add a new block to the spine, potentially growing
+ // the spine.
+ lock(&b.spineLock)
+ // spineLen cannot change until we release the lock,
+ // but may have changed while we were waiting.
+ spineLen = atomic.Loaduintptr(&b.spineLen)
+ if top < spineLen {
+ unlock(&b.spineLock)
+ goto retry
+ }
+
+ if spineLen == b.spineCap {
+ // Grow the spine.
+ newCap := b.spineCap * 2
+ if newCap == 0 {
+ newCap = gcSweepBufInitSpineCap
+ }
+ newSpine := persistentalloc(newCap*sys.PtrSize, sys.CacheLineSize, &memstats.gc_sys)
+ if b.spineCap != 0 {
+ // Blocks are allocated off-heap, so
+ // no write barriers.
+ memmove(newSpine, b.spine, b.spineCap*sys.PtrSize)
+ }
+ // Spine is allocated off-heap, so no write barrier.
+ atomic.StorepNoWB(unsafe.Pointer(&b.spine), newSpine)
+ b.spineCap = newCap
+ // We can't immediately free the old spine
+ // since a concurrent push with a lower index
+ // could still be reading from it. We let it
+ // leak because even a 1TB heap would waste
+ // less than 2MB of memory on old spines. If
+ // this is a problem, we could free old spines
+ // during STW.
+ }
+
+ // Allocate a new block and add it to the spine.
+ block = (*gcSweepBlock)(persistentalloc(unsafe.Sizeof(gcSweepBlock{}), sys.CacheLineSize, &memstats.gc_sys))
+ blockp := add(b.spine, sys.PtrSize*top)
+ // Blocks are allocated off-heap, so no write barrier.
+ atomic.StorepNoWB(blockp, unsafe.Pointer(block))
+ atomic.Storeuintptr(&b.spineLen, spineLen+1)
+ unlock(&b.spineLock)
+ }
+
+ // We have a block. Insert the span.
+ block.spans[bottom] = s
+}
+
+// pop removes and returns a span from buffer b, or nil if b is empty.
+// pop is safe to call concurrently with other pop operations, but NOT
+// to call concurrently with push.
+func (b *gcSweepBuf) pop() *mspan {
+ cursor := atomic.Xadd(&b.index, -1)
+ if int32(cursor) < 0 {
+ atomic.Xadd(&b.index, +1)
+ return nil
+ }
+
+ // There are no concurrent spine or block modifications during
+ // pop, so we can omit the atomics.
+ top, bottom := cursor/gcSweepBlockEntries, cursor%gcSweepBlockEntries
+ blockp := (**gcSweepBlock)(add(b.spine, sys.PtrSize*uintptr(top)))
+ block := *blockp
+ s := block.spans[bottom]
+ // Clear the pointer for block(i).
+ block.spans[bottom] = nil
+ return s
+}
+
+// numBlocks returns the number of blocks in buffer b. numBlocks is
+// safe to call concurrently with any other operation. Spans that have
+// been pushed prior to the call to numBlocks are guaranteed to appear
+// in some block in the range [0, numBlocks()), assuming there are no
+// intervening pops. Spans that are pushed after the call may also
+// appear in these blocks.
+func (b *gcSweepBuf) numBlocks() int {
+ return int((atomic.Load(&b.index) + gcSweepBlockEntries - 1) / gcSweepBlockEntries)
+}
+
+// block returns the spans in the i'th block of buffer b. block is
+// safe to call concurrently with push.
+func (b *gcSweepBuf) block(i int) []*mspan {
+ // Perform bounds check before loading spine address since
+ // push ensures the allocated length is at least spineLen.
+ if i < 0 || uintptr(i) >= atomic.Loaduintptr(&b.spineLen) {
+ throw("block index out of range")
+ }
+
+ // Get block i.
+ spine := atomic.Loadp(unsafe.Pointer(&b.spine))
+ blockp := add(spine, sys.PtrSize*uintptr(i))
+ block := (*gcSweepBlock)(atomic.Loadp(blockp))
+
+ // Slice the block if necessary.
+ cursor := uintptr(atomic.Load(&b.index))
+ top, bottom := cursor/gcSweepBlockEntries, cursor%gcSweepBlockEntries
+ var spans []*mspan
+ if uintptr(i) < top {
+ spans = block.spans[:]
+ } else {
+ spans = block.spans[:bottom]
+ }
+
+ // push may have reserved a slot but not filled it yet, so
+ // trim away unused entries.
+ for len(spans) > 0 && spans[len(spans)-1] == nil {
+ spans = spans[:len(spans)-1]
+ }
+ return spans
+}
diff --git a/src/runtime/mgcwork.go b/src/runtime/mgcwork.go
index d04840b..5eb05a7 100644
--- a/src/runtime/mgcwork.go
+++ b/src/runtime/mgcwork.go
@@ -28,6 +28,8 @@ const (
// 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 {
@@ -94,9 +96,10 @@ func (w *gcWork) init() {
}
// put enqueues a pointer for the garbage collector to trace.
-// obj must point to the beginning of a heap object.
+// obj must point to the beginning of a heap object or an oblet.
//go:nowritebarrier
func (w *gcWork) put(obj uintptr) {
+ flushed := false
wbuf := w.wbuf1.ptr()
if wbuf == nil {
w.init()
@@ -109,11 +112,20 @@ func (w *gcWork) put(obj uintptr) {
putfull(wbuf)
wbuf = getempty()
w.wbuf1 = wbufptrOf(wbuf)
+ flushed = true
}
}
wbuf.obj[wbuf.nobj] = obj
wbuf.nobj++
+
+ // If we put a buffer on full, let the GC controller know so
+ // it can encourage more workers to run. We delay this until
+ // the end of put so that w is in a consistent state, since
+ // enlistWorker may itself manipulate w.
+ if flushed && gcphase == _GCmark {
+ gcController.enlistWorker()
+ }
}
// putFast does a put and returns true if it can be done quickly
@@ -261,6 +273,12 @@ func (w *gcWork) balance() {
w.wbuf2 = wbufptrOf(getempty())
} else if wbuf := w.wbuf1.ptr(); wbuf.nobj > 4 {
w.wbuf1 = wbufptrOf(handoff(wbuf))
+ } else {
+ return
+ }
+ // We flushed a buffer to the full list, so wake a worker.
+ if gcphase == _GCmark {
+ gcController.enlistWorker()
}
}
@@ -279,6 +297,7 @@ type workbufhdr struct {
nobj int
}
+//go:notinheap
type workbuf struct {
workbufhdr
// account for the above fields
@@ -334,12 +353,6 @@ func putempty(b *workbuf) {
func putfull(b *workbuf) {
b.checknonempty()
lfstackpush(&work.full, &b.node)
-
- // We just made more work available. Let the GC controller
- // know so it can encourage more workers to run.
- if gcphase == _GCmark {
- gcController.enlistWorker()
- }
}
// trygetfull tries to get a full or partially empty workbuffer.
diff --git a/src/runtime/mheap.go b/src/runtime/mheap.go
index 8db2fcc..ef62eff 100644
--- a/src/runtime/mheap.go
+++ b/src/runtime/mheap.go
@@ -22,20 +22,56 @@ const minPhysPageSize = 4096
// Main malloc heap.
// The heap itself is the "free[]" and "large" arrays,
// but all the other global data is here too.
+//
+// mheap must not be heap-allocated because it contains mSpanLists,
+// which must not be heap-allocated.
+//
+//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
- allspans **mspan // all spans out there
- gcspans **mspan // copy of allspans referenced by gc marker or sweeper
- nspan uint32
- sweepgen uint32 // sweep generation, see comment in mspan
- sweepdone uint32 // all spans are swept
- // span lookup
- spans **mspan
- spans_mapped uintptr
+ sweepgen uint32 // sweep generation, see comment in mspan
+ sweepdone uint32 // all spans are swept
+
+ // allspans is a slice of all mspans ever created. Each mspan
+ // appears exactly once.
+ //
+ // The memory for allspans is manually managed and can be
+ // reallocated and move as the heap grows.
+ //
+ // In general, allspans is protected by mheap_.lock, which
+ // prevents concurrent access as well as freeing the backing
+ // store. Accesses during STW might not hold the lock, but
+ // must ensure that allocation cannot happen around the
+ // access (since that may free the backing store).
+ allspans []*mspan // all spans out there
+
+ // spans is a lookup table to map virtual address page IDs to *mspan.
+ // For allocated spans, their pages map to the span itself.
+ // For free spans, only the lowest and highest pages map to the span itself.
+ // Internal pages map to an arbitrary span.
+ // For pages that have never been allocated, spans entries are nil.
+ //
+ // This is backed by a reserved region of the address space so
+ // it can grow without moving. The memory up to len(spans) is
+ // mapped. cap(spans) indicates the total reserved memory.
+ spans []*mspan
+
+ // sweepSpans contains two mspan stacks: one of swept in-use
+ // spans, and one of unswept in-use spans. These two trade
+ // roles on each GC cycle. Since the sweepgen increases by 2
+ // on each cycle, this means the swept spans are in
+ // sweepSpans[sweepgen/2%2] and the unswept spans are in
+ // sweepSpans[1-sweepgen/2%2]. Sweeping pops spans from the
+ // unswept stack and pushes spans that are still in-use on the
+ // swept stack. Likewise, allocating an in-use span pushes it
+ // on the swept stack.
+ sweepSpans [2]gcSweepBuf
+
+ _ uint32 // align uint64 fields on 32-bit for atomics
// Proportional sweep
pagesInUse uint64 // pages of spans in stats _MSpanInUse; R/W with mheap.lock
@@ -102,24 +138,36 @@ var mheap_ mheap
// * During GC (gcphase != _GCoff), a span *must not* transition from
// stack or in-use to free. Because concurrent GC may read a pointer
// and then look up its span, the span state must be monotonic.
+type mSpanState uint8
+
const (
- _MSpanInUse = iota // allocated for garbage collected heap
- _MSpanStack // allocated for use by stack allocator
+ _MSpanDead mSpanState = iota
+ _MSpanInUse // allocated for garbage collected heap
+ _MSpanStack // allocated for use by stack allocator
_MSpanFree
- _MSpanDead
)
+// mSpanStateNames are the names of the span states, indexed by
+// mSpanState.
+var mSpanStateNames = []string{
+ "_MSpanDead",
+ "_MSpanInUse",
+ "_MSpanStack",
+ "_MSpanFree",
+}
+
// mSpanList heads a linked list of spans.
//
-// Linked list structure is based on BSD's "tail queue" data structure.
+//go:notinheap
type mSpanList struct {
- first *mspan // first span in list, or nil if none
- last **mspan // last span's next field, or first if none
+ first *mspan // first span in list, or nil if none
+ last *mspan // last span in list, or nil if none
}
+//go:notinheap
type mspan struct {
next *mspan // next span in list, or nil if none
- prev **mspan // previous span's next field, or list head's first field if none
+ 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()
@@ -186,21 +234,21 @@ type mspan struct {
// h->sweepgen is incremented by 2 after every GC
sweepgen uint32
- divMul uint32 // for divide by elemsize - divMagic.mul
- allocCount uint16 // capacity - number of objects in freelist
- sizeclass uint8 // size class
- incache bool // being used by an mcache
- state uint8 // mspaninuse etc
- needzero uint8 // needs to be zeroed before allocation
- divShift uint8 // for divide by elemsize - divMagic.shift
- divShift2 uint8 // for divide by elemsize - divMagic.shift2
- elemsize uintptr // computed from sizeclass or from npages
- unusedsince int64 // first time spotted by gc in mspanfree state
- npreleased uintptr // number of pages released to the os
- limit uintptr // end of data in span
- speciallock mutex // guards specials list
- specials *special // linked list of special records sorted by offset.
- baseMask uintptr // if non-0, elemsize is a power of 2, & this will get object allocation base
+ 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
+ incache bool // being used by an mcache
+ state mSpanState // mspaninuse etc
+ needzero uint8 // needs to be zeroed before allocation
+ divShift uint8 // for divide by elemsize - divMagic.shift
+ divShift2 uint8 // for divide by elemsize - divMagic.shift2
+ elemsize uintptr // computed from sizeclass or from npages
+ unusedsince int64 // first time spotted by gc in mspanfree state
+ npreleased uintptr // number of pages released to the os
+ limit uintptr // end of data in span
+ speciallock mutex // guards specials list
+ specials *special // linked list of special records sorted by offset.
}
func (s *mspan) base() uintptr {
@@ -216,22 +264,13 @@ func (s *mspan) layout() (size, n, total uintptr) {
return
}
-var h_allspans []*mspan // TODO: make this h.allspans once mheap can be defined in Go
-
-// h_spans is a lookup table to map virtual address page IDs to *mspan.
-// For allocated spans, their pages map to the span itself.
-// For free spans, only the lowest and highest pages map to the span itself. Internal
-// pages map to an arbitrary span.
-// For pages that have never been allocated, h_spans entries are nil.
-var h_spans []*mspan // TODO: make this h.spans once mheap can be defined in Go
-
func recordspan(vh unsafe.Pointer, p unsafe.Pointer) {
h := (*mheap)(vh)
s := (*mspan)(p)
- if len(h_allspans) >= cap(h_allspans) {
+ if len(h.allspans) >= cap(h.allspans) {
n := 64 * 1024 / sys.PtrSize
- if n < cap(h_allspans)*3/2 {
- n = cap(h_allspans) * 3 / 2
+ if n < cap(h.allspans)*3/2 {
+ n = cap(h.allspans) * 3 / 2
}
var new []*mspan
sp := (*slice)(unsafe.Pointer(&new))
@@ -239,21 +278,18 @@ func recordspan(vh unsafe.Pointer, p unsafe.Pointer) {
if sp.array == nil {
throw("runtime: cannot allocate memory")
}
- sp.len = len(h_allspans)
+ sp.len = len(h.allspans)
sp.cap = n
- if len(h_allspans) > 0 {
- copy(new, h_allspans)
- // Don't free the old array if it's referenced by sweep.
- // See the comment in mgc.go.
- if h.allspans != mheap_.gcspans {
- sysFree(unsafe.Pointer(h.allspans), uintptr(cap(h_allspans))*sys.PtrSize, &memstats.other_sys)
- }
+ if len(h.allspans) > 0 {
+ copy(new, h.allspans)
+ }
+ oldAllspans := h.allspans
+ h.allspans = new
+ if len(oldAllspans) != 0 {
+ sysFree(unsafe.Pointer(&oldAllspans[0]), uintptr(cap(oldAllspans))*unsafe.Sizeof(oldAllspans[0]), &memstats.other_sys)
}
- h_allspans = new
- h.allspans = (**mspan)(sp.array)
}
- h_allspans = append(h_allspans, s)
- h.nspan = uint32(len(h_allspans))
+ h.allspans = append(h.allspans, s)
}
// inheap reports whether b is a pointer into a (potentially dead) heap object.
@@ -266,7 +302,7 @@ func inheap(b uintptr) bool {
return false
}
// Not a beginning of a block, consult span table to find the block beginning.
- s := h_spans[(b-mheap_.arena_start)>>_PageShift]
+ s := mheap_.spans[(b-mheap_.arena_start)>>_PageShift]
if s == nil || b < s.base() || b >= s.limit || s.state != mSpanInUse {
return false
}
@@ -281,7 +317,7 @@ func inHeapOrStack(b uintptr) bool {
return false
}
// Not a beginning of a block, consult span table to find the block beginning.
- s := h_spans[(b-mheap_.arena_start)>>_PageShift]
+ s := mheap_.spans[(b-mheap_.arena_start)>>_PageShift]
if s == nil || b < s.base() {
return false
}
@@ -311,7 +347,7 @@ func spanOf(p uintptr) *mspan {
// that p points into the heap (that is, mheap_.arena_start <= p <
// mheap_.arena_used).
func spanOfUnchecked(p uintptr) *mspan {
- return h_spans[(p-mheap_.arena_start)>>_PageShift]
+ return mheap_.spans[(p-mheap_.arena_start)>>_PageShift]
}
func mlookup(v uintptr, base *uintptr, size *uintptr, sp **mspan) int32 {
@@ -364,12 +400,21 @@ func mlookup(v uintptr, base *uintptr, size *uintptr, sp **mspan) int32 {
}
// Initialize the heap.
-func (h *mheap) init(spans_size uintptr) {
+func (h *mheap) init(spansStart, spansBytes uintptr) {
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)
h.specialprofilealloc.init(unsafe.Sizeof(specialprofile{}), nil, nil, &memstats.other_sys)
+ // Don't zero mspan allocations. Background sweeping can
+ // inspect a span concurrently with allocating it, so it's
+ // important that the span's sweepgen survive across freeing
+ // and re-allocating a span to prevent background sweeping
+ // from improperly cas'ing it from 0.
+ //
+ // This is safe because mspan contains no heap pointers.
+ h.spanalloc.zero = false
+
// h->mapcache needs no init
for i := range h.free {
h.free[i].init()
@@ -382,10 +427,10 @@ func (h *mheap) init(spans_size uintptr) {
h.central[i].mcentral.init(int32(i))
}
- sp := (*slice)(unsafe.Pointer(&h_spans))
- sp.array = unsafe.Pointer(h.spans)
- sp.len = int(spans_size / sys.PtrSize)
- sp.cap = int(spans_size / sys.PtrSize)
+ sp := (*slice)(unsafe.Pointer(&h.spans))
+ sp.array = unsafe.Pointer(spansStart)
+ sp.len = 0
+ sp.cap = int(spansBytes / sys.PtrSize)
}
// mHeap_MapSpans makes sure that the spans are mapped
@@ -401,12 +446,14 @@ func (h *mheap) mapSpans(arena_used uintptr) {
n := arena_used
n -= h.arena_start
n = n / _PageSize * sys.PtrSize
- n = round(n, sys.PhysPageSize)
- if h.spans_mapped >= n {
+ n = round(n, physPageSize)
+ need := n / unsafe.Sizeof(h.spans[0])
+ have := uintptr(len(h.spans))
+ if have >= need {
return
}
- sysMap(add(unsafe.Pointer(h.spans), h.spans_mapped), n-h.spans_mapped, h.arena_reserved, &memstats.other_sys)
- h.spans_mapped = n
+ h.spans = h.spans[:need]
+ sysMap(unsafe.Pointer(&h.spans[have]), (need-have)*unsafe.Sizeof(h.spans[0]), h.arena_reserved, &memstats.other_sys)
}
// Sweeps spans in list until reclaims at least npages into heap.
@@ -517,6 +564,7 @@ func (h *mheap) alloc_m(npage uintptr, sizeclass int32, large bool) *mspan {
// Record span info, because gc needs to be
// able to map interior pointer to containing span.
atomic.Store(&s.sweepgen, h.sweepgen)
+ h.sweepSpans[h.sweepgen/2%2].push(s) // Add to swept in-use list.
s.state = _MSpanInUse
s.allocCount = 0
s.sizeclass = uint8(sizeclass)
@@ -557,15 +605,15 @@ func (h *mheap) alloc_m(npage uintptr, sizeclass int32, large bool) *mspan {
traceHeapAlloc()
}
- // h_spans is accessed concurrently without synchronization
+ // h.spans is accessed concurrently without synchronization
// from other threads. Hence, there must be a store/store
- // barrier here to ensure the writes to h_spans above happen
+ // barrier here to ensure the writes to h.spans above happen
// before the caller can publish a pointer p to an object
// allocated from s. As soon as this happens, the garbage
// collector running on another processor could read p and
- // look up s in h_spans. The unlock acts as the barrier to
+ // look up s in h.spans. The unlock acts as the barrier to
// order these writes. On the read side, the data dependency
- // between p and the index in h_spans orders the reads.
+ // between p and the index in h.spans orders the reads.
unlock(&h.lock)
return s
}
@@ -581,7 +629,7 @@ func (h *mheap) alloc(npage uintptr, sizeclass int32, large bool, needzero bool)
if s != nil {
if needzero && s.needzero != 0 {
- memclr(unsafe.Pointer(s.base()), s.npages<<_PageShift)
+ memclrNoHeapPointers(unsafe.Pointer(s.base()), s.npages<<_PageShift)
}
s.needzero = 0
}
@@ -661,10 +709,10 @@ HaveSpan:
s.npages = npage
p := (t.base() - h.arena_start) >> _PageShift
if p > 0 {
- h_spans[p-1] = s
+ h.spans[p-1] = s
}
- h_spans[p] = t
- h_spans[p+t.npages-1] = t
+ 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
@@ -675,7 +723,7 @@ HaveSpan:
p := (s.base() - h.arena_start) >> _PageShift
for n := uintptr(0); n < npage; n++ {
- h_spans[p+n] = s
+ h.spans[p+n] = s
}
memstats.heap_inuse += uint64(npage << _PageShift)
@@ -741,7 +789,7 @@ func (h *mheap) grow(npage uintptr) bool {
s.init(uintptr(v), ask>>_PageShift)
p := (s.base() - h.arena_start) >> _PageShift
for i := p; i < p+s.npages; i++ {
- h_spans[i] = s
+ h.spans[i] = s
}
atomic.Store(&s.sweepgen, h.sweepgen)
s.state = _MSpanInUse
@@ -756,7 +804,7 @@ func (h *mheap) grow(npage uintptr) bool {
func (h *mheap) lookup(v unsafe.Pointer) *mspan {
p := uintptr(v)
p -= h.arena_start
- return h_spans[p>>_PageShift]
+ return h.spans[p>>_PageShift]
}
// Look up the span at the given address.
@@ -770,7 +818,7 @@ func (h *mheap) lookupMaybe(v unsafe.Pointer) *mspan {
if uintptr(v) < h.arena_start || uintptr(v) >= h.arena_used {
return nil
}
- s := h_spans[(uintptr(v)-h.arena_start)>>_PageShift]
+ s := h.spans[(uintptr(v)-h.arena_start)>>_PageShift]
if s == nil || uintptr(v) < s.base() || uintptr(v) >= uintptr(unsafe.Pointer(s.limit)) || s.state != _MSpanInUse {
return nil
}
@@ -855,26 +903,26 @@ 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]
+ 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
- h_spans[p] = s
+ h.spans[p] = s
h.freeList(t.npages).remove(t)
t.state = _MSpanDead
h.spanalloc.free(unsafe.Pointer(t))
}
}
- if (p+s.npages)*sys.PtrSize < h.spans_mapped {
- t := h_spans[p+s.npages]
+ 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
- h_spans[p+s.npages-1] = s
+ h.spans[p+s.npages-1] = s
h.freeList(t.npages).remove(t)
t.state = _MSpanDead
h.spanalloc.free(unsafe.Pointer(t))
@@ -909,14 +957,14 @@ func scavengelist(list *mSpanList, now, limit uint64) uintptr {
if (now-uint64(s.unusedsince)) > limit && s.npreleased != s.npages {
start := s.base()
end := start + s.npages<<_PageShift
- if sys.PhysPageSize > _PageSize {
+ if physPageSize > _PageSize {
// We can only release pages in
- // PhysPageSize blocks, so round start
+ // physPageSize blocks, so round start
// and end in. (Otherwise, madvise
// will round them *out* and release
// more memory than we want.)
- start = (start + sys.PhysPageSize - 1) &^ (sys.PhysPageSize - 1)
- end &^= sys.PhysPageSize - 1
+ start = (start + physPageSize - 1) &^ (physPageSize - 1)
+ end &^= physPageSize - 1
if end <= start {
// start and end don't span a
// whole physical page.
@@ -926,7 +974,7 @@ func scavengelist(list *mSpanList, now, limit uint64) uintptr {
len := end - start
released := len - (s.npreleased << _PageShift)
- if sys.PhysPageSize > _PageSize && released == 0 {
+ if physPageSize > _PageSize && released == 0 {
continue
}
memstats.heap_released += uint64(released)
@@ -965,6 +1013,7 @@ func runtime_debug_freeOSMemory() {
// Initialize a new span with the given start and npages.
func (span *mspan) init(base uintptr, npages uintptr) {
+ // span is *not* zeroed.
span.next = nil
span.prev = nil
span.list = nil
@@ -986,28 +1035,30 @@ func (span *mspan) init(base uintptr, npages uintptr) {
}
func (span *mspan) inList() bool {
- return span.prev != nil
+ return span.list != nil
}
// Initialize an empty doubly-linked list.
func (list *mSpanList) init() {
list.first = nil
- list.last = &list.first
+ list.last = nil
}
func (list *mSpanList) remove(span *mspan) {
- if span.prev == nil || span.list != list {
+ if span.list != list {
println("runtime: failed MSpanList_Remove", span, span.prev, span.list, list)
throw("MSpanList_Remove")
}
- if span.next != nil {
- span.next.prev = span.prev
+ if list.first == span {
+ list.first = span.next
} else {
- // TODO: After we remove the span.list != list check above,
- // we could at least still check list.last == &span.next here.
+ span.prev.next = span.next
+ }
+ if list.last == span {
list.last = span.prev
+ } else {
+ span.next.prev = span.prev
}
- *span.prev = span.next
span.next = nil
span.prev = nil
span.list = nil
@@ -1024,12 +1075,14 @@ func (list *mSpanList) insert(span *mspan) {
}
span.next = list.first
if list.first != nil {
- list.first.prev = &span.next
+ // The list contains at least one span; link it in.
+ // The last span in the list doesn't change.
+ list.first.prev = span
} else {
- list.last = &span.next
+ // The list contains no spans, so this is also the last span.
+ list.last = span
}
list.first = span
- span.prev = &list.first
span.list = list
}
@@ -1038,10 +1091,15 @@ func (list *mSpanList) insertBack(span *mspan) {
println("failed MSpanList_InsertBack", span, span.next, span.prev, span.list)
throw("MSpanList_InsertBack")
}
- span.next = nil
span.prev = list.last
- *list.last = span
- list.last = &span.next
+ if list.last != nil {
+ // The list contains at least one span.
+ list.last.next = span
+ } else {
+ // The list contains no spans, so this is also the first span.
+ list.first = span
+ }
+ list.last = span
span.list = list
}
@@ -1054,6 +1112,7 @@ const (
// if that happens.
)
+//go:notinheap
type special struct {
next *special // linked list in span
offset uint16 // span offset of object
@@ -1151,12 +1210,17 @@ func removespecial(p unsafe.Pointer, kind uint8) *special {
}
// The described object has a finalizer set for it.
+//
+// specialfinalizer is allocated from non-GC'd memory, so any heap
+// pointers must be specially handled.
+//
+//go:notinheap
type specialfinalizer struct {
special special
- fn *funcval
+ fn *funcval // May be a heap pointer.
nret uintptr
- fint *_type
- ot *ptrtype
+ fint *_type // May be a heap pointer, but always live.
+ ot *ptrtype // May be a heap pointer, but always live.
}
// Adds a finalizer to the object p. Returns true if it succeeded.
@@ -1211,6 +1275,8 @@ func removefinalizer(p unsafe.Pointer) {
}
// The described object is being heap profiled.
+//
+//go:notinheap
type specialprofile struct {
special special
b *bucket
@@ -1258,6 +1324,7 @@ type gcBitsHeader struct {
next uintptr // *gcBits triggers recursive type bug. (issue 14620)
}
+//go:notinheap
type gcBits struct {
// gcBitsHeader // side step recursive type bug (issue 14620) by including fields by hand.
free uintptr // free is the index into bits of the next free byte.
@@ -1351,7 +1418,7 @@ func newArena() *gcBits {
} else {
result = gcBitsArenas.free
gcBitsArenas.free = gcBitsArenas.free.next
- memclr(unsafe.Pointer(result), gcBitsChunkBytes)
+ memclrNoHeapPointers(unsafe.Pointer(result), gcBitsChunkBytes)
}
result.next = nil
// If result.bits is not 8 byte aligned adjust index so
diff --git a/src/runtime/mkduff.go b/src/runtime/mkduff.go
index 0e7cc66..cf6b37f 100644
--- a/src/runtime/mkduff.go
+++ b/src/runtime/mkduff.go
@@ -8,14 +8,14 @@
// The compiler jumps to computed addresses within
// the routine to zero chunks of memory.
// Do not change duffzero without also
-// changing clearfat in cmd/?g/ggen.go.
+// changing the uses in cmd/compile/internal/*/*.go.
// runtime·duffcopy is a Duff's device for copying memory.
// The compiler jumps to computed addresses within
// the routine to copy chunks of memory.
// Source and destination must not overlap.
// Do not change duffcopy without also
-// changing blockcopy in cmd/?g/cgen.go.
+// changing the uses in cmd/compile/internal/*/*.go.
// See the zero* and copy* generators below
// for architecture-specific comments.
@@ -161,7 +161,17 @@ func zeroARM64(w io.Writer) {
}
func copyARM64(w io.Writer) {
- fmt.Fprintln(w, "// TODO: Implement runtime·duffcopy.")
+ // R16 (aka REGRT1): ptr to source memory
+ // R17 (aka REGRT2): ptr to destination memory
+ // R27 (aka REGTMP): scratch space
+ // R16 and R17 are updated as a side effect
+ fmt.Fprintln(w, "TEXT runtime·duffcopy(SB), NOSPLIT, $0-0")
+ for i := 0; i < 128; i++ {
+ fmt.Fprintln(w, "\tMOVD.P\t8(R16), R27")
+ fmt.Fprintln(w, "\tMOVD.P\tR27, 8(R17)")
+ fmt.Fprintln(w)
+ }
+ fmt.Fprintln(w, "\tRET")
}
func tagsPPC64x(w io.Writer) {
diff --git a/src/runtime/mksizeclasses.go b/src/runtime/mksizeclasses.go
new file mode 100644
index 0000000..587d3c7
--- /dev/null
+++ b/src/runtime/mksizeclasses.go
@@ -0,0 +1,309 @@
+// Copyright 2016 The Go Authors. 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 tables for small malloc size classes.
+//
+// See malloc.go for overview.
+//
+// The size classes are chosen so that rounding an allocation
+// request up to the next size class wastes at most 12.5% (1.125x).
+//
+// Each size class has its own page count that gets allocated
+// and chopped up when new objects of the size class are needed.
+// That page count is chosen so that chopping up the run of
+// pages into objects of the given size wastes at most 12.5% (1.125x)
+// of the memory. It is not necessary that the cutoff here be
+// the same as above.
+//
+// The two sources of waste multiply, so the worst possible case
+// for the above constraints would be that allocations of some
+// size might have a 26.6% (1.266x) overhead.
+// In practice, only one of the wastes comes into play for a
+// given size (sizes < 512 waste mainly on the round-up,
+// sizes > 512 waste mainly on the page chopping).
+//
+// TODO(rsc): Compute max waste for any given size.
+
+package main
+
+import (
+ "bytes"
+ "flag"
+ "fmt"
+ "go/format"
+ "io"
+ "io/ioutil"
+ "log"
+ "os"
+)
+
+// Generate msize.go
+
+var stdout = flag.Bool("stdout", false, "write to stdout instead of sizeclasses.go")
+
+func main() {
+ flag.Parse()
+
+ var b bytes.Buffer
+ fmt.Fprintln(&b, "// AUTO-GENERATED by mksizeclasses.go; DO NOT EDIT")
+ fmt.Fprintln(&b, "//go:generate go run mksizeclasses.go")
+ fmt.Fprintln(&b)
+ fmt.Fprintln(&b, "package runtime")
+ classes := makeClasses()
+
+ printClasses(&b, classes)
+
+ out, err := format.Source(b.Bytes())
+ if err != nil {
+ log.Fatal(err)
+ }
+ if *stdout {
+ _, err = os.Stdout.Write(out)
+ } else {
+ err = ioutil.WriteFile("sizeclasses.go", out, 0666)
+ }
+ if err != nil {
+ log.Fatal(err)
+ }
+}
+
+const (
+ // Constants that we use and will transfer to the runtime.
+ maxSmallSize = 32 << 10
+ smallSizeDiv = 8
+ smallSizeMax = 1024
+ largeSizeDiv = 128
+ pageShift = 13
+
+ // Derived constants.
+ pageSize = 1 << pageShift
+)
+
+type class struct {
+ size int // max size
+ npages int // number of pages
+
+ mul int
+ shift uint
+ shift2 uint
+ mask int
+}
+
+func powerOfTwo(x int) bool {
+ return x != 0 && x&(x-1) == 0
+}
+
+func makeClasses() []class {
+ var classes []class
+
+ classes = append(classes, class{}) // class #0 is a dummy entry
+
+ align := 8
+ for size := align; size <= maxSmallSize; size += align {
+ if powerOfTwo(size) { // bump alignment once in a while
+ if size >= 2048 {
+ align = 256
+ } else if size >= 128 {
+ align = size / 8
+ } else if size >= 16 {
+ align = 16 // required for x86 SSE instructions, if we want to use them
+ }
+ }
+ if !powerOfTwo(align) {
+ panic("incorrect alignment")
+ }
+
+ // Make the allocnpages big enough that
+ // the leftover is less than 1/8 of the total,
+ // so wasted space is at most 12.5%.
+ allocsize := pageSize
+ for allocsize%size > allocsize/8 {
+ allocsize += pageSize
+ }
+ npages := allocsize / pageSize
+
+ // If the previous sizeclass chose the same
+ // allocation size and fit the same number of
+ // objects into the page, we might as well
+ // use just this size instead of having two
+ // different sizes.
+ if len(classes) > 1 && npages == classes[len(classes)-1].npages && allocsize/size == allocsize/classes[len(classes)-1].size {
+ classes[len(classes)-1].size = size
+ continue
+ }
+ classes = append(classes, class{size: size, npages: npages})
+ }
+
+ // Increase object sizes if we can fit the same number of larger objects
+ // into the same number of pages. For example, we choose size 8448 above
+ // with 6 objects in 7 pages. But we can well use object size 9472,
+ // which is also 6 objects in 7 pages but +1024 bytes (+12.12%).
+ // We need to preserve at least largeSizeDiv alignment otherwise
+ // sizeToClass won't work.
+ for i := range classes {
+ if i == 0 {
+ continue
+ }
+ c := &classes[i]
+ psize := c.npages * pageSize
+ new_size := (psize / (psize / c.size)) &^ (largeSizeDiv - 1)
+ if new_size > c.size {
+ c.size = new_size
+ }
+ }
+
+ if len(classes) != 67 {
+ panic("number of size classes has changed")
+ }
+
+ for i := range classes {
+ computeDivMagic(&classes[i])
+ }
+
+ return classes
+}
+
+// computeDivMagic computes some magic constants to implement
+// the division required to compute object number from span offset.
+// n / c.size is implemented as n >> c.shift * c.mul >> c.shift2
+// for all 0 <= n < c.npages * pageSize
+func computeDivMagic(c *class) {
+ // divisor
+ d := c.size
+ if d == 0 {
+ return
+ }
+
+ // maximum input value for which the formula needs to work.
+ max := c.npages*pageSize - 1
+
+ if powerOfTwo(d) {
+ // If the size is a power of two, heapBitsForObject can divide even faster by masking.
+ // Compute this mask.
+ if max >= 1<<16 {
+ panic("max too big for power of two size")
+ }
+ c.mask = 1<<16 - d
+ }
+
+ // Compute pre-shift by factoring power of 2 out of d.
+ for d%2 == 0 {
+ c.shift++
+ d >>= 1
+ max >>= 1
+ }
+
+ // Find the smallest k that works.
+ // A small k allows us to fit the math required into 32 bits
+ // so we can use 32-bit multiplies and shifts on 32-bit platforms.
+nextk:
+ for k := uint(0); ; k++ {
+ mul := (int(1)<<k + d - 1) / d // ⌈2^k / d⌉
+
+ // Test to see if mul works.
+ for n := 0; n <= max; n++ {
+ if n*mul>>k != n/d {
+ continue nextk
+ }
+ }
+ if mul >= 1<<16 {
+ panic("mul too big")
+ }
+ if uint64(mul)*uint64(max) >= 1<<32 {
+ panic("mul*max too big")
+ }
+ c.mul = mul
+ c.shift2 = k
+ break
+ }
+
+ // double-check.
+ for n := 0; n <= max; n++ {
+ if n*c.mul>>c.shift2 != n/d {
+ fmt.Printf("d=%d max=%d mul=%d shift2=%d n=%d\n", d, max, c.mul, c.shift2, n)
+ panic("bad multiply magic")
+ }
+ // Also check the exact computations that will be done by the runtime,
+ // for both 32 and 64 bit operations.
+ if uint32(n)*uint32(c.mul)>>uint8(c.shift2) != uint32(n/d) {
+ fmt.Printf("d=%d max=%d mul=%d shift2=%d n=%d\n", d, max, c.mul, c.shift2, n)
+ panic("bad 32-bit multiply magic")
+ }
+ if uint64(n)*uint64(c.mul)>>uint8(c.shift2) != uint64(n/d) {
+ fmt.Printf("d=%d max=%d mul=%d shift2=%d n=%d\n", d, max, c.mul, c.shift2, n)
+ panic("bad 64-bit multiply magic")
+ }
+ }
+}
+
+func printClasses(w io.Writer, classes []class) {
+ fmt.Fprintln(w, "const (")
+ fmt.Fprintf(w, "_MaxSmallSize = %d\n", maxSmallSize)
+ fmt.Fprintf(w, "smallSizeDiv = %d\n", smallSizeDiv)
+ fmt.Fprintf(w, "smallSizeMax = %d\n", smallSizeMax)
+ fmt.Fprintf(w, "largeSizeDiv = %d\n", largeSizeDiv)
+ fmt.Fprintf(w, "_NumSizeClasses = %d\n", len(classes))
+ fmt.Fprintf(w, "_PageShift = %d\n", pageShift)
+ fmt.Fprintln(w, ")")
+
+ fmt.Fprint(w, "var class_to_size = [_NumSizeClasses]uint16 {")
+ for _, c := range classes {
+ fmt.Fprintf(w, "%d,", c.size)
+ }
+ fmt.Fprintln(w, "}")
+
+ fmt.Fprint(w, "var class_to_allocnpages = [_NumSizeClasses]uint8 {")
+ for _, c := range classes {
+ fmt.Fprintf(w, "%d,", c.npages)
+ }
+ fmt.Fprintln(w, "}")
+
+ fmt.Fprintln(w, "type divMagic struct {")
+ fmt.Fprintln(w, " shift uint8")
+ fmt.Fprintln(w, " shift2 uint8")
+ fmt.Fprintln(w, " mul uint16")
+ fmt.Fprintln(w, " baseMask uint16")
+ fmt.Fprintln(w, "}")
+ fmt.Fprint(w, "var class_to_divmagic = [_NumSizeClasses]divMagic {")
+ for _, c := range classes {
+ fmt.Fprintf(w, "{%d,%d,%d,%d},", c.shift, c.shift2, c.mul, c.mask)
+ }
+ fmt.Fprintln(w, "}")
+
+ // map from size to size class, for small sizes.
+ sc := make([]int, smallSizeMax/smallSizeDiv+1)
+ for i := range sc {
+ size := i * smallSizeDiv
+ for j, c := range classes {
+ if c.size >= size {
+ sc[i] = j
+ break
+ }
+ }
+ }
+ fmt.Fprint(w, "var size_to_class8 = [smallSizeMax/smallSizeDiv+1]uint8 {")
+ for _, v := range sc {
+ fmt.Fprintf(w, "%d,", v)
+ }
+ fmt.Fprintln(w, "}")
+
+ // map from size to size class, for large sizes.
+ sc = make([]int, (maxSmallSize-smallSizeMax)/largeSizeDiv+1)
+ for i := range sc {
+ size := smallSizeMax + i*largeSizeDiv
+ for j, c := range classes {
+ if c.size >= size {
+ sc[i] = j
+ break
+ }
+ }
+ }
+ fmt.Fprint(w, "var size_to_class128 = [(_MaxSmallSize-smallSizeMax)/largeSizeDiv+1]uint8 {")
+ for _, v := range sc {
+ fmt.Fprintf(w, "%d,", v)
+ }
+ fmt.Fprintln(w, "}")
+}
diff --git a/src/runtime/mprof.go b/src/runtime/mprof.go
index c3e4e2c..fc06d8d 100644
--- a/src/runtime/mprof.go
+++ b/src/runtime/mprof.go
@@ -22,6 +22,7 @@ const (
// profile types
memProfile bucketType = 1 + iota
blockProfile
+ mutexProfile
// size of bucket hash table
buckHashSize = 179999
@@ -40,10 +41,14 @@ type bucketType int
//
// Per-call-stack profiling information.
// Lookup by hashing call stack into a linked-list hash table.
+//
+// No heap pointers.
+//
+//go:notinheap
type bucket struct {
next *bucket
allnext *bucket
- typ bucketType // memBucket or blockBucket
+ typ bucketType // memBucket or blockBucket (includes mutexProfile)
hash uintptr
size uintptr
nstk uintptr
@@ -83,7 +88,7 @@ type memRecord struct {
}
// A blockRecord is the bucket data for a bucket of type blockProfile,
-// part of the blocking profile.
+// which is used in blocking and mutex profiles.
type blockRecord struct {
count int64
cycles int64
@@ -92,6 +97,7 @@ type blockRecord struct {
var (
mbuckets *bucket // memory profile buckets
bbuckets *bucket // blocking profile buckets
+ xbuckets *bucket // mutex profile buckets
buckhash *[179999]*bucket
bucketmem uintptr
)
@@ -104,7 +110,7 @@ func newBucket(typ bucketType, nstk int) *bucket {
throw("invalid profile bucket type")
case memProfile:
size += unsafe.Sizeof(memRecord{})
- case blockProfile:
+ case blockProfile, mutexProfile:
size += unsafe.Sizeof(blockRecord{})
}
@@ -132,7 +138,7 @@ func (b *bucket) mp() *memRecord {
// bp returns the blockRecord associated with the blockProfile bucket b.
func (b *bucket) bp() *blockRecord {
- if b.typ != blockProfile {
+ if b.typ != blockProfile && b.typ != mutexProfile {
throw("bad use of bucket.bp")
}
data := add(unsafe.Pointer(b), unsafe.Sizeof(*b)+b.nstk*unsafe.Sizeof(uintptr(0)))
@@ -184,6 +190,9 @@ func stkbucket(typ bucketType, size uintptr, stk []uintptr, alloc bool) *bucket
if typ == memProfile {
b.allnext = mbuckets
mbuckets = b
+ } else if typ == mutexProfile {
+ b.allnext = xbuckets
+ xbuckets = b
} else {
b.allnext = bbuckets
bbuckets = b
@@ -288,10 +297,20 @@ func blockevent(cycles int64, skip int) {
if cycles <= 0 {
cycles = 1
}
+ if blocksampled(cycles) {
+ saveblockevent(cycles, skip+1, blockProfile, &blockprofilerate)
+ }
+}
+
+func blocksampled(cycles int64) bool {
rate := int64(atomic.Load64(&blockprofilerate))
- if rate <= 0 || (rate > cycles && int64(fastrand1())%rate > cycles) {
- return
+ if rate <= 0 || (rate > cycles && int64(fastrand())%rate > cycles) {
+ return false
}
+ return true
+}
+
+func saveblockevent(cycles int64, skip int, which bucketType, ratep *uint64) {
gp := getg()
var nstk int
var stk [maxStack]uintptr
@@ -301,12 +320,43 @@ func blockevent(cycles int64, skip int) {
nstk = gcallers(gp.m.curg, skip, stk[:])
}
lock(&proflock)
- b := stkbucket(blockProfile, 0, stk[:nstk], true)
+ b := stkbucket(which, 0, stk[:nstk], true)
b.bp().count++
b.bp().cycles += cycles
unlock(&proflock)
}
+var mutexprofilerate uint64 // fraction sampled
+
+// SetMutexProfileFraction controls the fraction of mutex contention events
+// that are reported in the mutex profile. On average 1/rate events are
+// reported. The previous rate is returned.
+//
+// To turn off profiling entirely, pass rate 0.
+// To just read the current rate, pass rate -1.
+// (For n>1 the details of sampling may change.)
+func SetMutexProfileFraction(rate int) int {
+ if rate < 0 {
+ return int(mutexprofilerate)
+ }
+ old := mutexprofilerate
+ atomic.Store64(&mutexprofilerate, uint64(rate))
+ return int(old)
+}
+
+//go:linkname mutexevent sync.event
+func mutexevent(cycles int64, skip int) {
+ if cycles < 0 {
+ cycles = 0
+ }
+ rate := int64(atomic.Load64(&mutexprofilerate))
+ // 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)
+ }
+}
+
// Go interface to profile data.
// A StackRecord describes a single execution stack.
@@ -438,6 +488,12 @@ func record(r *MemProfileRecord, b *bucket) {
r.FreeBytes = int64(mp.free_bytes)
r.AllocObjects = int64(mp.allocs)
r.FreeObjects = int64(mp.frees)
+ if raceenabled {
+ racewriterangepc(unsafe.Pointer(&r.Stack0[0]), unsafe.Sizeof(r.Stack0), getcallerpc(unsafe.Pointer(&r)), funcPC(MemProfile))
+ }
+ if msanenabled {
+ msanwrite(unsafe.Pointer(&r.Stack0[0]), unsafe.Sizeof(r.Stack0))
+ }
copy(r.Stack0[:], b.stk())
for i := int(b.nstk); i < len(r.Stack0); i++ {
r.Stack0[i] = 0
@@ -480,6 +536,41 @@ func BlockProfile(p []BlockProfileRecord) (n int, ok bool) {
r := &p[0]
r.Count = bp.count
r.Cycles = bp.cycles
+ if raceenabled {
+ racewriterangepc(unsafe.Pointer(&r.Stack0[0]), unsafe.Sizeof(r.Stack0), getcallerpc(unsafe.Pointer(&p)), funcPC(BlockProfile))
+ }
+ if msanenabled {
+ msanwrite(unsafe.Pointer(&r.Stack0[0]), unsafe.Sizeof(r.Stack0))
+ }
+ i := copy(r.Stack0[:], b.stk())
+ for ; i < len(r.Stack0); i++ {
+ r.Stack0[i] = 0
+ }
+ p = p[1:]
+ }
+ }
+ unlock(&proflock)
+ return
+}
+
+// MutexProfile returns n, the number of records in the current mutex profile.
+// If len(p) >= n, MutexProfile copies the profile into p and returns n, true.
+// Otherwise, MutexProfile does not change p, and returns n, false.
+//
+// Most clients should use the runtime/pprof package
+// instead of calling MutexProfile directly.
+func MutexProfile(p []BlockProfileRecord) (n int, ok bool) {
+ lock(&proflock)
+ for b := xbuckets; b != nil; b = b.allnext {
+ n++
+ }
+ if n <= len(p) {
+ ok = true
+ for b := xbuckets; b != nil; b = b.allnext {
+ bp := b.bp()
+ r := &p[0]
+ r.Count = int64(bp.count)
+ r.Cycles = bp.cycles
i := copy(r.Stack0[:], b.stk())
for ; i < len(r.Stack0); i++ {
r.Stack0[i] = 0
diff --git a/src/runtime/msan_amd64.s b/src/runtime/msan_amd64.s
index 9c59eec..cbe739d 100644
--- a/src/runtime/msan_amd64.s
+++ b/src/runtime/msan_amd64.s
@@ -62,12 +62,16 @@ TEXT runtime·msanfree(SB), NOSPLIT, $0-16
TEXT msancall<>(SB), NOSPLIT, $0-0
get_tls(R12)
MOVQ g(R12), R14
+ MOVQ SP, R12 // callee-saved, preserved across the CALL
+ CMPQ R14, $0
+ JE call // no g; still on a system stack
+
MOVQ g_m(R14), R13
// Switch to g0 stack.
- MOVQ SP, R12 // callee-saved, preserved across the CALL
MOVQ m_g0(R13), R10
CMPQ R10, R14
JE call // already on g0
+
MOVQ (g_sched+gobuf_sp)(R10), SP
call:
ANDQ $~15, SP // alignment for gcc ABI
diff --git a/src/runtime/msize.go b/src/runtime/msize.go
index 18577b3..438c987 100644
--- a/src/runtime/msize.go
+++ b/src/runtime/msize.go
@@ -5,191 +5,39 @@
// Malloc small size classes.
//
// See malloc.go for overview.
-//
-// The size classes are chosen so that rounding an allocation
-// request up to the next size class wastes at most 12.5% (1.125x).
-//
-// Each size class has its own page count that gets allocated
-// and chopped up when new objects of the size class are needed.
-// That page count is chosen so that chopping up the run of
-// pages into objects of the given size wastes at most 12.5% (1.125x)
-// of the memory. It is not necessary that the cutoff here be
-// the same as above.
-//
-// The two sources of waste multiply, so the worst possible case
-// for the above constraints would be that allocations of some
-// size might have a 26.6% (1.266x) overhead.
-// In practice, only one of the wastes comes into play for a
-// given size (sizes < 512 waste mainly on the round-up,
-// sizes > 512 waste mainly on the page chopping).
-//
-// TODO(rsc): Compute max waste for any given size.
+// See also mksizeclasses.go for how we decide what size classes to use.
package runtime
-// Size classes. Computed and initialized by InitSizes.
-//
-// SizeToClass(0 <= n <= MaxSmallSize) returns the size class,
+// sizeToClass(0 <= n <= MaxSmallSize) returns the size class,
// 1 <= sizeclass < NumSizeClasses, for n.
// Size class 0 is reserved to mean "not small".
//
-// class_to_size[i] = largest size in class i
-// class_to_allocnpages[i] = number of pages to allocate when
-// making new objects in class i
-
-// The SizeToClass lookup is implemented using two arrays,
+// The sizeToClass lookup is implemented using two arrays,
// one mapping sizes <= 1024 to their class and one mapping
// sizes >= 1024 and <= MaxSmallSize to their class.
// All objects are 8-aligned, so the first array is indexed by
// the size divided by 8 (rounded up). Objects >= 1024 bytes
// are 128-aligned, so the second array is indexed by the
-// size divided by 128 (rounded up). The arrays are filled in
-// by InitSizes.
-
-var class_to_size [_NumSizeClasses]int32
-var class_to_allocnpages [_NumSizeClasses]int32
-var class_to_divmagic [_NumSizeClasses]divMagic
-
-var size_to_class8 [1024/8 + 1]int8
-var size_to_class128 [(_MaxSmallSize-1024)/128 + 1]int8
-
-func sizeToClass(size int32) int32 {
+// 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 > 1024-8 {
- return int32(size_to_class128[(size-1024+127)>>7])
- }
- return int32(size_to_class8[(size+7)>>3])
-}
-
-func initSizes() {
- // Initialize the runtime·class_to_size table (and choose class sizes in the process).
- class_to_size[0] = 0
- sizeclass := 1 // 0 means no class
- align := 8
- for size := align; size <= _MaxSmallSize; size += align {
- if size&(size-1) == 0 { // bump alignment once in a while
- if size >= 2048 {
- align = 256
- } else if size >= 128 {
- align = size / 8
- } else if size >= 16 {
- align = 16 // required for x86 SSE instructions, if we want to use them
- }
- }
- if align&(align-1) != 0 {
- throw("incorrect alignment")
- }
-
- // Make the allocnpages big enough that
- // the leftover is less than 1/8 of the total,
- // so wasted space is at most 12.5%.
- allocsize := _PageSize
- for allocsize%size > allocsize/8 {
- allocsize += _PageSize
- }
- npages := allocsize >> _PageShift
-
- // If the previous sizeclass chose the same
- // allocation size and fit the same number of
- // objects into the page, we might as well
- // use just this size instead of having two
- // different sizes.
- if sizeclass > 1 && npages == int(class_to_allocnpages[sizeclass-1]) && allocsize/size == allocsize/int(class_to_size[sizeclass-1]) {
- class_to_size[sizeclass-1] = int32(size)
- continue
- }
-
- class_to_allocnpages[sizeclass] = int32(npages)
- class_to_size[sizeclass] = int32(size)
- sizeclass++
- }
- if sizeclass != _NumSizeClasses {
- print("runtime: sizeclass=", sizeclass, " NumSizeClasses=", _NumSizeClasses, "\n")
- throw("bad NumSizeClasses")
- }
- // Check maxObjsPerSpan => number of objects invariant.
- for i, size := range class_to_size {
- if size != 0 && class_to_allocnpages[i]*pageSize/size > maxObjsPerSpan {
- throw("span contains too many objects")
- }
- if size == 0 && i != 0 {
- throw("size is 0 but class is not 0")
- }
- }
- // Initialize the size_to_class tables.
- nextsize := 0
- for sizeclass = 1; sizeclass < _NumSizeClasses; sizeclass++ {
- for ; nextsize < 1024 && nextsize <= int(class_to_size[sizeclass]); nextsize += 8 {
- size_to_class8[nextsize/8] = int8(sizeclass)
- }
- if nextsize >= 1024 {
- for ; nextsize <= int(class_to_size[sizeclass]); nextsize += 128 {
- size_to_class128[(nextsize-1024)/128] = int8(sizeclass)
- }
- }
- }
-
- // Double-check SizeToClass.
- if false {
- for n := int32(0); n < _MaxSmallSize; n++ {
- sizeclass := sizeToClass(n)
- if sizeclass < 1 || sizeclass >= _NumSizeClasses || class_to_size[sizeclass] < n {
- print("runtime: size=", n, " sizeclass=", sizeclass, " runtime·class_to_size=", class_to_size[sizeclass], "\n")
- print("incorrect SizeToClass\n")
- goto dump
- }
- if sizeclass > 1 && class_to_size[sizeclass-1] >= n {
- print("runtime: size=", n, " sizeclass=", sizeclass, " runtime·class_to_size=", class_to_size[sizeclass], "\n")
- print("SizeToClass too big\n")
- goto dump
- }
- }
- }
-
- testdefersizes()
-
- // Copy out for statistics table.
- for i := 0; i < len(class_to_size); i++ {
- memstats.by_size[i].size = uint32(class_to_size[i])
- }
-
- for i := 1; i < len(class_to_size); i++ {
- class_to_divmagic[i] = computeDivMagic(uint32(class_to_size[i]))
+ if size > smallSizeMax-8 {
+ return uint32(size_to_class128[(size-smallSizeMax+largeSizeDiv-1)/largeSizeDiv])
}
-
- return
-
-dump:
- if true {
- print("runtime: NumSizeClasses=", _NumSizeClasses, "\n")
- print("runtime·class_to_size:")
- for sizeclass = 0; sizeclass < _NumSizeClasses; sizeclass++ {
- print(" ", class_to_size[sizeclass], "")
- }
- print("\n\n")
- print("runtime: size_to_class8:")
- for i := 0; i < len(size_to_class8); i++ {
- print(" ", i*8, "=>", size_to_class8[i], "(", class_to_size[size_to_class8[i]], ")\n")
- }
- print("\n")
- print("runtime: size_to_class128:")
- for i := 0; i < len(size_to_class128); i++ {
- print(" ", i*128, "=>", size_to_class128[i], "(", class_to_size[size_to_class128[i]], ")\n")
- }
- print("\n")
- }
- throw("InitSizes failed")
+ 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 {
- if size <= 1024-8 {
- return uintptr(class_to_size[size_to_class8[(size+7)>>3]])
+ if size <= smallSizeMax-8 {
+ return uintptr(class_to_size[size_to_class8[(size+smallSizeDiv-1)/smallSizeDiv]])
} else {
- return uintptr(class_to_size[size_to_class128[(size-1024+127)>>7]])
+ return uintptr(class_to_size[size_to_class128[(size-smallSizeMax+largeSizeDiv-1)/largeSizeDiv]])
}
}
if size+_PageSize < size {
@@ -197,66 +45,3 @@ func roundupsize(size uintptr) uintptr {
}
return round(size, _PageSize)
}
-
-// divMagic holds magic constants to implement division
-// by a particular constant as a shift, multiply, and shift.
-// That is, given
-// m = computeMagic(d)
-// then
-// n/d == ((n>>m.shift) * m.mul) >> m.shift2
-//
-// The magic computation picks m such that
-// d = d₁*d₂
-// d₂= 2^m.shift
-// m.mul = ⌈2^m.shift2 / d₁⌉
-//
-// The magic computation here is tailored for malloc block sizes
-// and does not handle arbitrary d correctly. Malloc block sizes d are
-// always even, so the first shift implements the factors of 2 in d
-// and then the mul and second shift implement the odd factor
-// that remains. Because the first shift divides n by at least 2 (actually 8)
-// before the multiply gets involved, the huge corner cases that
-// require additional adjustment are impossible, so the usual
-// fixup is not needed.
-//
-// For more details see Hacker's Delight, Chapter 10, and
-// http://ridiculousfish.com/blog/posts/labor-of-division-episode-i.html
-// http://ridiculousfish.com/blog/posts/labor-of-division-episode-iii.html
-type divMagic struct {
- shift uint8
- mul uint32
- shift2 uint8
- baseMask uintptr
-}
-
-func computeDivMagic(d uint32) divMagic {
- var m divMagic
-
- // If the size is a power of two, heapBitsForObject can divide even faster by masking.
- // Compute this mask.
- if d&(d-1) == 0 {
- // It is a power of 2 (assuming dinptr != 1)
- m.baseMask = ^(uintptr(d) - 1)
- } else {
- m.baseMask = 0
- }
-
- // Compute pre-shift by factoring power of 2 out of d.
- for d&1 == 0 {
- m.shift++
- d >>= 1
- }
-
- // Compute largest k such that ⌈2^k / d⌉ fits in a 32-bit int.
- // This is always a good enough approximation.
- // We could use smaller k for some divisors but there's no point.
- k := uint8(63)
- d64 := uint64(d)
- for ((1<<k)+d64-1)/d64 >= 1<<32 {
- k--
- }
- m.mul = uint32(((1 << k) + d64 - 1) / d64) // ⌈2^k / d⌉
- m.shift2 = k
-
- return m
-}
diff --git a/src/runtime/mstats.go b/src/runtime/mstats.go
index 2d75d2f..b80ab11 100644
--- a/src/runtime/mstats.go
+++ b/src/runtime/mstats.go
@@ -14,6 +14,13 @@ import (
// Statistics.
// If you edit this structure, also edit type MemStats below.
+// Their layouts must match exactly.
+//
+// For detailed descriptions see the documentation for MemStats.
+// Fields that differ from MemStats are further documented here.
+//
+// Many of these fields are updated on the fly, while others are only
+// updated when updatememstats is called.
type mstats struct {
// General statistics.
alloc uint64 // bytes allocated and not yet freed
@@ -24,18 +31,36 @@ type mstats struct {
nfree uint64 // number of frees
// Statistics about malloc heap.
- // protected by mheap.lock
+ // 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.
heap_alloc uint64 // bytes allocated and not yet freed (same as alloc above)
- heap_sys uint64 // bytes obtained from system
+ heap_sys uint64 // virtual address space obtained from system
heap_idle uint64 // bytes in idle spans
heap_inuse uint64 // bytes in non-idle spans
heap_released uint64 // bytes released to the os
heap_objects uint64 // total number of allocated objects
+ // TODO(austin): heap_released is both useless and inaccurate
+ // in its current form. It's useless because, from the user's
+ // and OS's perspectives, there's no difference between a page
+ // that has not yet been faulted in and a page that has been
+ // released back to the OS. We could fix this by considering
+ // newly mapped spans to be "released". It's inaccurate
+ // because when we split a large span for allocation, we
+ // "unrelease" all pages in the large span and not just the
+ // ones we split off for use. This is trickier to fix because
+ // we currently don't know which pages of a span we've
+ // released. We could fix it by separating "free" and
+ // "released" spans, but then we have to allocate from runs of
+ // free and released spans.
+
// Statistics about allocation of low-level fixed-size structures.
// Protected by FixAlloc locks.
- stacks_inuse uint64 // this number is included in heap_inuse above
- stacks_sys uint64 // always 0 in mstats
+ stacks_inuse uint64 // this number is included in heap_inuse above; differs from MemStats.StackInuse
+ stacks_sys uint64 // only counts newosproc0 stack in mstats; differs from MemStats.StackSys
mspan_inuse uint64 // mspan structures
mspan_sys uint64
mcache_inuse uint64 // mcache structures
@@ -46,7 +71,7 @@ type mstats struct {
// Statistics about garbage collector.
// Protected by mheap or stopping the world during GC.
- next_gc uint64 // next gc (in heap_live time)
+ next_gc uint64 // goal heap_live for when next GC ends; ^0 if disabled
last_gc uint64 // last gc (in absolute time)
pause_total_ns uint64
pause_ns [256]uint64 // circular buffer of recent gc pause lengths
@@ -64,10 +89,19 @@ type mstats struct {
nfree uint64
}
- // Statistics below here are not exported to Go directly.
+ // 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
+ // 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.
+ gc_trigger uint64
+
+ _ uint32 // force 8-byte alignment of heap_live and prevent an alignment check crash on MIPS32.
+
// heap_live is the number of bytes considered live by the GC.
// That is: retained by the most recent GC plus allocated
// since then. heap_live <= heap_alloc, since heap_alloc
@@ -104,10 +138,6 @@ type mstats struct {
// unlike heap_live, heap_marked does not change until the
// next mark termination.
heap_marked uint64
-
- // heap_reachable is an estimate of the reachable heap bytes
- // at the end of the previous GC.
- heap_reachable uint64
}
var memstats mstats
@@ -115,47 +145,254 @@ var memstats mstats
// A MemStats records statistics about the memory allocator.
type MemStats struct {
// General statistics.
- Alloc uint64 // bytes allocated and not yet freed
- TotalAlloc uint64 // bytes allocated (even if freed)
- Sys uint64 // bytes obtained from system (sum of XxxSys below)
- Lookups uint64 // number of pointer lookups
- Mallocs uint64 // number of mallocs
- Frees uint64 // number of frees
-
- // Main allocation heap statistics.
- HeapAlloc uint64 // bytes allocated and not yet freed (same as Alloc above)
- HeapSys uint64 // bytes obtained from system
- HeapIdle uint64 // bytes in idle spans
- HeapInuse uint64 // bytes in non-idle span
- HeapReleased uint64 // bytes released to the OS
- HeapObjects uint64 // total number of allocated objects
-
- // Low-level fixed-size structure allocator statistics.
- // Inuse is bytes used now.
- // Sys is bytes obtained from system.
- StackInuse uint64 // bytes used by stack allocator
- StackSys uint64
- MSpanInuse uint64 // mspan structures
- MSpanSys uint64
- MCacheInuse uint64 // mcache structures
- MCacheSys uint64
- BuckHashSys uint64 // profiling bucket hash table
- GCSys uint64 // GC metadata
- OtherSys uint64 // other system allocations
+
+ // Alloc is bytes of allocated heap objects.
+ //
+ // This is the same as HeapAlloc (see below).
+ Alloc uint64
+
+ // TotalAlloc is cumulative bytes allocated for heap objects.
+ //
+ // TotalAlloc increases as heap objects are allocated, but
+ // unlike Alloc and HeapAlloc, it does not decrease when
+ // objects are freed.
+ TotalAlloc uint64
+
+ // Sys is the total bytes of memory obtained from the OS.
+ //
+ // Sys is the sum of the XSys fields below. Sys measures the
+ // virtual address space reserved by the Go runtime for the
+ // heap, stacks, and other internal data structures. It's
+ // likely that not all of the virtual address space is backed
+ // by physical memory at any given moment, though in general
+ // it all was at some point.
+ Sys uint64
+
+ // Lookups is the number of pointer lookups performed by the
+ // runtime.
+ //
+ // This is primarily useful for debugging runtime internals.
+ Lookups uint64
+
+ // Mallocs is the cumulative count of heap objects allocated.
+ Mallocs uint64
+
+ // Frees is the cumulative count of heap objects freed.
+ Frees uint64
+
+ // Heap memory statistics.
+ //
+ // Interpreting the heap statistics requires some knowledge of
+ // how Go organizes memory. Go divides the virtual address
+ // space of the heap into "spans", which are contiguous
+ // regions of memory 8K or larger. A span may be in one of
+ // three states:
+ //
+ // An "idle" span contains no objects or other data. The
+ // physical memory backing an idle span can be released back
+ // to the OS (but the virtual address space never is), or it
+ // can be converted into an "in use" or "stack" span.
+ //
+ // An "in use" span contains at least one heap object and may
+ // have free space available to allocate more heap objects.
+ //
+ // A "stack" span is used for goroutine stacks. Stack spans
+ // are not considered part of the heap. A span can change
+ // between heap and stack memory; it is never used for both
+ // simultaneously.
+
+ // HeapAlloc is bytes of allocated heap objects.
+ //
+ // "Allocated" heap objects include all reachable objects, as
+ // well as unreachable objects that the garbage collector has
+ // not yet freed. Specifically, HeapAlloc increases as heap
+ // objects are allocated and decreases as the heap is swept
+ // and unreachable objects are freed. Sweeping occurs
+ // incrementally between GC cycles, so these two processes
+ // occur simultaneously, and as a result HeapAlloc tends to
+ // change smoothly (in contrast with the sawtooth that is
+ // typical of stop-the-world garbage collectors).
+ HeapAlloc uint64
+
+ // HeapSys is bytes of heap memory obtained from the OS.
+ //
+ // HeapSys measures the amount of virtual address space
+ // reserved for the heap. This includes virtual address space
+ // that has been reserved but not yet used, which consumes no
+ // physical memory, but tends to be small, as well as virtual
+ // address space for which the physical memory has been
+ // returned to the OS after it became unused (see HeapReleased
+ // for a measure of the latter).
+ //
+ // HeapSys estimates the largest size the heap has had.
+ HeapSys uint64
+
+ // HeapIdle is bytes in idle (unused) spans.
+ //
+ // Idle spans have no objects in them. These spans could be
+ // (and may already have been) returned to the OS, or they can
+ // be reused for heap allocations, or they can be reused as
+ // stack memory.
+ //
+ // HeapIdle minus HeapReleased estimates the amount of memory
+ // that could be returned to the OS, but is being retained by
+ // the runtime so it can grow the heap without requesting more
+ // memory from the OS. If this difference is significantly
+ // larger than the heap size, it indicates there was a recent
+ // transient spike in live heap size.
+ HeapIdle uint64
+
+ // HeapInuse is bytes in in-use spans.
+ //
+ // In-use spans have at least one object in them. These spans
+ // can only be used for other objects of roughly the same
+ // size.
+ //
+ // HeapInuse minus HeapAlloc esimates the amount of memory
+ // that has been dedicated to particular size classes, but is
+ // not currently being used. This is an upper bound on
+ // fragmentation, but in general this memory can be reused
+ // efficiently.
+ HeapInuse uint64
+
+ // HeapReleased is bytes of physical memory returned to the OS.
+ //
+ // This counts heap memory from idle spans that was returned
+ // to the OS and has not yet been reacquired for the heap.
+ HeapReleased uint64
+
+ // HeapObjects is the number of allocated heap objects.
+ //
+ // Like HeapAlloc, this increases as objects are allocated and
+ // decreases as the heap is swept and unreachable objects are
+ // freed.
+ HeapObjects uint64
+
+ // Stack memory statistics.
+ //
+ // Stacks are not considered part of the heap, but the runtime
+ // can reuse a span of heap memory for stack memory, and
+ // vice-versa.
+
+ // StackInuse is bytes in stack spans.
+ //
+ // In-use stack spans have at least one stack in them. These
+ // spans can only be used for other stacks of the same size.
+ //
+ // There is no StackIdle because unused stack spans are
+ // returned to the heap (and hence counted toward HeapIdle).
+ StackInuse uint64
+
+ // StackSys is bytes of stack memory obtained from the OS.
+ //
+ // StackSys is StackInuse, plus any memory obtained directly
+ // from the OS for OS thread stacks (which should be minimal).
+ StackSys uint64
+
+ // Off-heap memory statistics.
+ //
+ // The following statistics measure runtime-internal
+ // structures that are not allocated from heap memory (usually
+ // because they are part of implementing the heap). Unlike
+ // heap or stack memory, any memory allocated to these
+ // structures is dedicated to these structures.
+ //
+ // These are primarily useful for debugging runtime memory
+ // overheads.
+
+ // MSpanInuse is bytes of allocated mspan structures.
+ MSpanInuse uint64
+
+ // MSpanSys is bytes of memory obtained from the OS for mspan
+ // structures.
+ MSpanSys uint64
+
+ // MCacheInuse is bytes of allocated mcache structures.
+ MCacheInuse uint64
+
+ // MCacheSys is bytes of memory obtained from the OS for
+ // mcache structures.
+ MCacheSys uint64
+
+ // BuckHashSys is bytes of memory in profiling bucket hash tables.
+ BuckHashSys uint64
+
+ // GCSys is bytes of memory in garbage collection metadata.
+ GCSys uint64
+
+ // OtherSys is bytes of memory in miscellaneous off-heap
+ // runtime allocations.
+ OtherSys uint64
// Garbage collector statistics.
- NextGC uint64 // next collection will happen when HeapAlloc ≥ this amount
- LastGC uint64 // end time of last collection (nanoseconds since 1970)
- PauseTotalNs uint64
- PauseNs [256]uint64 // circular buffer of recent GC pause durations, most recent at [(NumGC+255)%256]
- PauseEnd [256]uint64 // circular buffer of recent GC pause end times
- NumGC uint32
- GCCPUFraction float64 // fraction of CPU time used by GC
- EnableGC bool
- DebugGC bool
-
- // Per-size allocation statistics.
- // 61 is NumSizeClasses in the C code.
+
+ // NextGC is the target heap size of the next GC cycle.
+ //
+ // The garbage collector's goal is to keep HeapAlloc ≤ NextGC.
+ // At the end of each GC cycle, the target for the next cycle
+ // is computed based on the amount of reachable data and the
+ // value of GOGC.
+ NextGC uint64
+
+ // LastGC is the time the last garbage collection finished, as
+ // nanoseconds since 1970 (the UNIX epoch).
+ LastGC uint64
+
+ // PauseTotalNs is the cumulative nanoseconds in GC
+ // stop-the-world pauses since the program started.
+ //
+ // During a stop-the-world pause, all goroutines are paused
+ // and only the garbage collector can run.
+ PauseTotalNs uint64
+
+ // PauseNs is a circular buffer of recent GC stop-the-world
+ // pause times in nanoseconds.
+ //
+ // The most recent pause is at PauseNs[(NumGC+255)%256]. In
+ // general, PauseNs[N%256] records the time paused in the most
+ // recent N%256th GC cycle. There may be multiple pauses per
+ // GC cycle; this is the sum of all pauses during a cycle.
+ PauseNs [256]uint64
+
+ // PauseEnd is a circular buffer of recent GC pause end times,
+ // as nanoseconds since 1970 (the UNIX epoch).
+ //
+ // This buffer is filled the same way as PauseNs. There may be
+ // multiple pauses per GC cycle; this records the end of the
+ // last pause in a cycle.
+ PauseEnd [256]uint64
+
+ // NumGC is the number of completed GC cycles.
+ NumGC uint32
+
+ // GCCPUFraction is the fraction of this program's available
+ // CPU time used by the GC since the program started.
+ //
+ // GCCPUFraction is expressed as a number between 0 and 1,
+ // where 0 means GC has consumed none of this program's CPU. A
+ // program's available CPU time is defined as the integral of
+ // GOMAXPROCS since the program started. That is, if
+ // GOMAXPROCS is 2 and a program has been running for 10
+ // seconds, its "available CPU" is 20 seconds. GCCPUFraction
+ // does not include CPU time used for write barrier activity.
+ //
+ // This is the same as the fraction of CPU reported by
+ // GODEBUG=gctrace=1.
+ GCCPUFraction float64
+
+ // EnableGC indicates that GC is enabled. It is always true,
+ // even if GOGC=off.
+ EnableGC bool
+
+ // DebugGC is currently unused.
+ DebugGC bool
+
+ // BySize reports per-size class allocation statistics.
+ //
+ // BySize[N] gives statistics for allocations of size S where
+ // BySize[N-1].Size < S ≤ BySize[N].Size.
+ //
+ // This does not report allocations larger than BySize[60].Size.
BySize [61]struct {
Size uint32
Mallocs uint64
@@ -163,10 +400,11 @@ type MemStats struct {
}
}
-// Size of the trailing by_size array differs between Go and C,
+// Size of the trailing by_size array differs between mstats and MemStats,
// and all data after by_size is local to runtime, not exported.
-// NumSizeClasses was changed, but we cannot change Go struct because of backward compatibility.
-// sizeof_C_MStats is what C thinks about size of Go struct.
+// NumSizeClasses was changed, but we cannot change MemStats because of backward compatibility.
+// sizeof_C_MStats is the size of the prefix of mstats that
+// corresponds to MemStats. It should match Sizeof(MemStats{}).
var sizeof_C_MStats = unsafe.Offsetof(memstats.by_size) + 61*unsafe.Sizeof(memstats.by_size[0])
func init() {
@@ -175,9 +413,19 @@ func init() {
println(sizeof_C_MStats, unsafe.Sizeof(memStats))
throw("MStats vs MemStatsType size mismatch")
}
+
+ if unsafe.Offsetof(memstats.heap_live)%8 != 0 {
+ println(unsafe.Offsetof(memstats.heap_live))
+ throw("memstats.heap_live not aligned to 8 bytes")
+ }
}
// ReadMemStats populates m with memory allocator statistics.
+//
+// The returned memory allocator statistics are up to date as of the
+// call to ReadMemStats. This is in contrast with a heap profile,
+// which is a snapshot as of the most recently completed garbage
+// collection cycle.
func ReadMemStats(m *MemStats) {
stopTheWorld("read mem stats")
@@ -191,8 +439,9 @@ func ReadMemStats(m *MemStats) {
func readmemstats_m(stats *MemStats) {
updatememstats(nil)
- // Size of the trailing by_size array differs between Go and C,
- // NumSizeClasses was changed, but we cannot change Go struct because of backward compatibility.
+ // 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
@@ -286,8 +535,7 @@ func updatememstats(stats *gcstats) {
// Scan all spans and count number of alive objects.
lock(&mheap_.lock)
- for i := uint32(0); i < mheap_.nspan; i++ {
- s := h_allspans[i]
+ for _, s := range mheap_.allspans {
if s.state != mSpanInUse {
continue
}
@@ -335,19 +583,32 @@ func cachestats() {
}
}
+// flushmcache flushes the mcache of allp[i].
+//
+// The world must be stopped.
+//
+//go:nowritebarrier
+func flushmcache(i int) {
+ p := allp[i]
+ if p == nil {
+ return
+ }
+ c := p.mcache
+ if c == nil {
+ return
+ }
+ c.releaseAll()
+ stackcache_clear(c)
+}
+
+// flushallmcaches flushes the mcaches of all Ps.
+//
+// The world must be stopped.
+//
//go:nowritebarrier
func flushallmcaches() {
- for i := 0; ; i++ {
- p := allp[i]
- if p == nil {
- break
- }
- c := p.mcache
- if c == nil {
- continue
- }
- c.releaseAll()
- stackcache_clear(c)
+ for i := 0; i < int(gomaxprocs); i++ {
+ flushmcache(i)
}
}
diff --git a/src/runtime/mstkbar.go b/src/runtime/mstkbar.go
index 1bf9d57..4415559 100644
--- a/src/runtime/mstkbar.go
+++ b/src/runtime/mstkbar.go
@@ -148,6 +148,10 @@ 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
diff --git a/src/runtime/net_plan9.go b/src/runtime/net_plan9.go
new file mode 100644
index 0000000..10fd089
--- /dev/null
+++ b/src/runtime/net_plan9.go
@@ -0,0 +1,29 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runtime
+
+import (
+ _ "unsafe"
+)
+
+//go:linkname runtime_ignoreHangup net.runtime_ignoreHangup
+func runtime_ignoreHangup() {
+ getg().m.ignoreHangup = true
+}
+
+//go:linkname runtime_unignoreHangup net.runtime_unignoreHangup
+func runtime_unignoreHangup(sig string) {
+ getg().m.ignoreHangup = false
+}
+
+func ignoredNote(note *byte) bool {
+ if note == nil {
+ return false
+ }
+ if gostringnocopy(note) != "hangup" {
+ return false
+ }
+ return getg().m.ignoreHangup
+}
diff --git a/src/runtime/netpoll.go b/src/runtime/netpoll.go
index 2ef248d..10a3c88 100644
--- a/src/runtime/netpoll.go
+++ b/src/runtime/netpoll.go
@@ -39,6 +39,10 @@ const (
const pollBlockSize = 4 * 1024
// Network poller descriptor.
+//
+// No heap pointers.
+//
+//go:notinheap
type pollDesc struct {
link *pollDesc // in pollcache, protected by pollcache.lock
diff --git a/src/runtime/noasm.go b/src/runtime/noasm.go
index 0a8f9e6..586836c 100644
--- a/src/runtime/noasm.go
+++ b/src/runtime/noasm.go
@@ -3,6 +3,7 @@
// license that can be found in the LICENSE file.
// Routines that are implemented in assembly in asm_{amd64,386,arm,arm64,ppc64x,s390x}.s
+// These routines have corresponding stubs in stubs_asm.go.
// +build mips64 mips64le
diff --git a/src/runtime/os3_plan9.go b/src/runtime/os3_plan9.go
index aff1d05..26b4acd 100644
--- a/src/runtime/os3_plan9.go
+++ b/src/runtime/os3_plan9.go
@@ -100,6 +100,9 @@ func sighandler(_ureg *ureg, note *byte, gp *g) int {
return _NCONT
}
if flags&_SigNotify != 0 {
+ if ignoredNote(note) {
+ return _NCONT
+ }
if sendNote(note) {
return _NCONT
}
diff --git a/src/runtime/os3_solaris.go b/src/runtime/os3_solaris.go
index 9368e0d..067fb3b 100644
--- a/src/runtime/os3_solaris.go
+++ b/src/runtime/os3_solaris.go
@@ -127,11 +127,20 @@ func getncpu() int32 {
return n
}
+func getPageSize() uintptr {
+ n := int32(sysconf(__SC_PAGESIZE))
+ if n <= 0 {
+ return 0
+ }
+ return uintptr(n)
+}
+
func osinit() {
ncpu = getncpu()
+ physPageSize = getPageSize()
}
-func tstart_sysvicall()
+func tstart_sysvicall(newm *m) uint32
// May run with m.p==nil, so write barriers are not allowed.
//go:nowritebarrier
@@ -195,58 +204,17 @@ func mpreinit(mp *m) {
func miniterrno()
-//go:nosplit
-func msigsave(mp *m) {
- sigprocmask(_SIG_SETMASK, nil, &mp.sigmask)
-}
-
-//go:nosplit
-func msigrestore(sigmask sigset) {
- sigprocmask(_SIG_SETMASK, &sigmask, nil)
-}
-
-//go:nosplit
-func sigblock() {
- sigprocmask(_SIG_SETMASK, &sigset_all, nil)
-}
-
// Called to initialize a new m (including the bootstrap m).
// Called on the new thread, cannot allocate memory.
func minit() {
- _g_ := getg()
asmcgocall(unsafe.Pointer(funcPC(miniterrno)), unsafe.Pointer(&libc____errno))
- // Initialize signal handling
- var st sigaltstackt
- sigaltstack(nil, &st)
- if st.ss_flags&_SS_DISABLE != 0 {
- signalstack(&_g_.m.gsignal.stack)
- _g_.m.newSigstack = true
- } else {
- // Use existing signal stack.
- stsp := uintptr(unsafe.Pointer(st.ss_sp))
- _g_.m.gsignal.stack.lo = stsp
- _g_.m.gsignal.stack.hi = stsp + uintptr(st.ss_size)
- _g_.m.gsignal.stackguard0 = stsp + _StackGuard
- _g_.m.gsignal.stackguard1 = stsp + _StackGuard
- _g_.m.gsignal.stackAlloc = uintptr(st.ss_size)
- _g_.m.newSigstack = false
- }
- // restore signal mask from m.sigmask and unblock essential signals
- nmask := _g_.m.sigmask
- for i := range sigtable {
- if sigtable[i].flags&_SigUnblock != 0 {
- nmask.__sigbits[(i-1)/32] &^= 1 << ((uint32(i) - 1) & 31)
- }
- }
- sigprocmask(_SIG_SETMASK, &nmask, nil)
+ minitSignals()
}
// Called from dropm to undo the effect of an minit.
func unminit() {
- if getg().m.newSigstack {
- signalstack(nil)
- }
+ unminitSignals()
}
func memlimit() uintptr {
@@ -284,14 +252,10 @@ func sigtramp()
//go:nosplit
//go:nowritebarrierrec
-func setsig(i int32, fn uintptr, restart bool) {
+func setsig(i uint32, fn uintptr) {
var sa sigactiont
- sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK
- sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK
- if restart {
- sa.sa_flags |= _SA_RESTART
- }
+ sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK | _SA_RESTART
sa.sa_mask = sigset_all
if fn == funcPC(sighandler) {
fn = funcPC(sigtramp)
@@ -302,11 +266,10 @@ func setsig(i int32, fn uintptr, restart bool) {
//go:nosplit
//go:nowritebarrierrec
-func setsigstack(i int32) {
+func setsigstack(i uint32) {
var sa sigactiont
sigaction(i, nil, &sa)
- handler := *((*uintptr)(unsafe.Pointer(&sa._funcptr)))
- if handler == 0 || handler == _SIG_DFL || handler == _SIG_IGN || sa.sa_flags&_SA_ONSTACK != 0 {
+ if sa.sa_flags&_SA_ONSTACK != 0 {
return
}
sa.sa_flags |= _SA_ONSTACK
@@ -315,40 +278,29 @@ func setsigstack(i int32) {
//go:nosplit
//go:nowritebarrierrec
-func getsig(i int32) uintptr {
+func getsig(i uint32) uintptr {
var sa sigactiont
sigaction(i, nil, &sa)
- if *((*uintptr)(unsafe.Pointer(&sa._funcptr))) == funcPC(sigtramp) {
- return funcPC(sighandler)
- }
return *((*uintptr)(unsafe.Pointer(&sa._funcptr)))
}
+// setSignaltstackSP sets the ss_sp field of a stackt.
//go:nosplit
-func signalstack(s *stack) {
- var st sigaltstackt
- if s == nil {
- st.ss_flags = _SS_DISABLE
- } else {
- st.ss_sp = (*byte)(unsafe.Pointer(s.lo))
- st.ss_size = uint64(s.hi - s.lo)
- st.ss_flags = 0
- }
- sigaltstack(&st, nil)
+func setSignalstackSP(s *stackt, sp uintptr) {
+ *(*uintptr)(unsafe.Pointer(&s.ss_sp)) = sp
}
//go:nosplit
//go:nowritebarrierrec
-func updatesigmask(m sigmask) {
- var mask sigset
- copy(mask.__sigbits[:], m[:])
- sigprocmask(_SIG_SETMASK, &mask, nil)
+func sigaddset(mask *sigset, i int) {
+ mask.__sigbits[(i-1)/32] |= 1 << ((uint32(i) - 1) & 31)
+}
+
+func sigdelset(mask *sigset, i int) {
+ mask.__sigbits[(i-1)/32] &^= 1 << ((uint32(i) - 1) & 31)
}
-func unblocksig(sig int32) {
- var mask sigset
- mask.__sigbits[(sig-1)/32] |= 1 << ((uint32(sig) - 1) & 31)
- sigprocmask(_SIG_UNBLOCK, &mask, nil)
+func (c *sigctxt) fixsigcode(sig uint32) {
}
//go:nosplit
@@ -365,7 +317,7 @@ func semacreate(mp *m) {
// here because it could cause a deadlock.
_g_.m.libcall.fn = uintptr(unsafe.Pointer(&libc_malloc))
_g_.m.libcall.n = 1
- memclr(unsafe.Pointer(&_g_.m.scratch), uintptr(len(_g_.m.scratch.v)))
+ _g_.m.scratch = mscratch{}
_g_.m.scratch.v[0] = unsafe.Sizeof(*sem)
_g_.m.libcall.args = uintptr(unsafe.Pointer(&_g_.m.scratch))
asmcgocall(unsafe.Pointer(&asmsysvicall6), unsafe.Pointer(&_g_.m.libcall))
@@ -385,7 +337,7 @@ func semasleep(ns int64) int32 {
_m_.libcall.fn = uintptr(unsafe.Pointer(&libc_sem_reltimedwait_np))
_m_.libcall.n = 2
- memclr(unsafe.Pointer(&_m_.scratch), uintptr(len(_m_.scratch.v)))
+ _m_.scratch = mscratch{}
_m_.scratch.v[0] = _m_.waitsema
_m_.scratch.v[1] = uintptr(unsafe.Pointer(&_m_.ts))
_m_.libcall.args = uintptr(unsafe.Pointer(&_m_.scratch))
@@ -401,7 +353,7 @@ func semasleep(ns int64) int32 {
for {
_m_.libcall.fn = uintptr(unsafe.Pointer(&libc_sem_wait))
_m_.libcall.n = 1
- memclr(unsafe.Pointer(&_m_.scratch), uintptr(len(_m_.scratch.v)))
+ _m_.scratch = mscratch{}
_m_.scratch.v[0] = _m_.waitsema
_m_.libcall.args = uintptr(unsafe.Pointer(&_m_.scratch))
asmcgocall(unsafe.Pointer(&asmsysvicall6), unsafe.Pointer(&_m_.libcall))
@@ -505,11 +457,11 @@ func pthread_create(thread *pthread, attr *pthreadattr, fn uintptr, arg unsafe.P
//go:nosplit
//go:nowritebarrierrec
-func raise(sig int32) /* int32 */ {
+func raise(sig uint32) /* int32 */ {
sysvicall1(&libc_raise, uintptr(sig))
}
-func raiseproc(sig int32) /* int32 */ {
+func raiseproc(sig uint32) /* int32 */ {
pid := sysvicall0(&libc_getpid)
sysvicall2(&libc_kill, pid, uintptr(sig))
}
@@ -545,13 +497,13 @@ func setitimer(which int32, value *itimerval, ovalue *itimerval) /* int32 */ {
//go:nosplit
//go:nowritebarrierrec
-func sigaction(sig int32, act *sigactiont, oact *sigactiont) /* int32 */ {
+func sigaction(sig uint32, act *sigactiont, oact *sigactiont) /* int32 */ {
sysvicall3(&libc_sigaction, uintptr(sig), uintptr(unsafe.Pointer(act)), uintptr(unsafe.Pointer(oact)))
}
//go:nosplit
//go:nowritebarrierrec
-func sigaltstack(ss *sigaltstackt, oss *sigaltstackt) /* int32 */ {
+func sigaltstack(ss *stackt, oss *stackt) /* int32 */ {
sysvicall2(&libc_sigaltstack, uintptr(unsafe.Pointer(ss)), uintptr(unsafe.Pointer(oss)))
}
@@ -565,7 +517,7 @@ func sysconf(name int32) int64 {
return int64(sysvicall1(&libc_sysconf, uintptr(name)))
}
-func usleep1(uint32)
+func usleep1(usec uint32)
//go:nosplit
func usleep(µs uint32) {
diff --git a/src/runtime/os_darwin.go b/src/runtime/os_darwin.go
index a0e3d8e..1528167 100644
--- a/src/runtime/os_darwin.go
+++ b/src/runtime/os_darwin.go
@@ -50,11 +50,19 @@ func osinit() {
// can look at the environment first.
ncpu = getncpu()
+
+ physPageSize = getPageSize()
}
+const (
+ _CTL_HW = 6
+ _HW_NCPU = 3
+ _HW_PAGESIZE = 7
+)
+
func getncpu() int32 {
// Use sysctl to fetch hw.ncpu.
- mib := [2]uint32{6, 3}
+ 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)
@@ -64,6 +72,18 @@ func getncpu() int32 {
return 1
}
+func getPageSize() uintptr {
+ // Use sysctl to fetch hw.pagesize.
+ mib := [2]uint32{_CTL_HW, _HW_PAGESIZE}
+ out := uint32(0)
+ nout := unsafe.Sizeof(out)
+ ret := sysctl(&mib[0], 2, (*byte)(unsafe.Pointer(&out)), &nout, nil, 0)
+ if ret >= 0 && int32(out) > 0 {
+ return uintptr(out)
+ }
+ return 0
+}
+
var urandom_dev = []byte("/dev/urandom\x00")
//go:nosplit
@@ -153,64 +173,22 @@ func mpreinit(mp *m) {
mp.gsignal.m = mp
}
-//go:nosplit
-func msigsave(mp *m) {
- sigprocmask(_SIG_SETMASK, nil, &mp.sigmask)
-}
-
-//go:nosplit
-func msigrestore(sigmask sigset) {
- sigprocmask(_SIG_SETMASK, &sigmask, nil)
-}
-
-//go:nosplit
-func sigblock() {
- sigprocmask(_SIG_SETMASK, &sigset_all, nil)
-}
-
// Called to initialize a new m (including the bootstrap m).
// Called on the new thread, cannot allocate memory.
func minit() {
- // Initialize signal handling.
- _g_ := getg()
-
// The alternate signal stack is buggy on arm and arm64.
// The signal handler handles it directly.
// The sigaltstack assembly function does nothing.
if GOARCH != "arm" && GOARCH != "arm64" {
- var st stackt
- sigaltstack(nil, &st)
- if st.ss_flags&_SS_DISABLE != 0 {
- signalstack(&_g_.m.gsignal.stack)
- _g_.m.newSigstack = true
- } else {
- // Use existing signal stack.
- stsp := uintptr(unsafe.Pointer(st.ss_sp))
- _g_.m.gsignal.stack.lo = stsp
- _g_.m.gsignal.stack.hi = stsp + st.ss_size
- _g_.m.gsignal.stackguard0 = stsp + _StackGuard
- _g_.m.gsignal.stackguard1 = stsp + _StackGuard
- _g_.m.gsignal.stackAlloc = st.ss_size
- _g_.m.newSigstack = false
- }
+ minitSignalStack()
}
-
- // restore signal mask from m.sigmask and unblock essential signals
- nmask := _g_.m.sigmask
- for i := range sigtable {
- if sigtable[i].flags&_SigUnblock != 0 {
- nmask &^= 1 << (uint32(i) - 1)
- }
- }
- sigprocmask(_SIG_SETMASK, &nmask, nil)
+ minitSignalMask()
}
// Called from dropm to undo the effect of an minit.
//go:nosplit
func unminit() {
- if getg().m.newSigstack {
- signalstack(nil)
- }
+ unminitSignals()
}
// Mach IPC, to get at semaphores
@@ -436,7 +414,10 @@ func semasleep1(ns int64) int32 {
if r == 0 {
break
}
- if r == _KERN_ABORTED { // interrupted
+ // Note: We don't know how this call (with no timeout) can get _KERN_OPERATION_TIMED_OUT,
+ // but it does reliably, though at a very low rate, on OS X 10.8, 10.9, 10.10, and 10.11.
+ // See golang.org/issue/17161.
+ if r == _KERN_ABORTED || r == _KERN_OPERATION_TIMED_OUT { // interrupted
continue
}
macherror(r, "semaphore_wait")
@@ -495,7 +476,7 @@ const (
)
//go:noescape
-func sigprocmask(how uint32, new, old *sigset)
+func sigprocmask(how int32, new, old *sigset)
//go:noescape
func sigaction(mode uint32, new *sigactiont, old *usigactiont)
@@ -503,13 +484,15 @@ func sigaction(mode uint32, new *sigactiont, old *usigactiont)
//go:noescape
func sigaltstack(new, old *stackt)
-func sigtramp()
+// darwin/arm64 uses registers instead of stack-based arguments.
+// TODO: does this matter?
+func sigtramp(fn uintptr, infostyle, sig uint32, info *siginfo, ctx unsafe.Pointer)
//go:noescape
func setitimer(mode int32, new, old *itimerval)
-func raise(sig int32)
-func raiseproc(int32)
+func raise(sig uint32)
+func raiseproc(sig uint32)
//extern SigTabTT runtime·sigtab[];
@@ -519,25 +502,22 @@ var sigset_all = ^sigset(0)
//go:nosplit
//go:nowritebarrierrec
-func setsig(i int32, fn uintptr, restart bool) {
+func setsig(i uint32, fn uintptr) {
var sa sigactiont
- sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK
- if restart {
- sa.sa_flags |= _SA_RESTART
- }
+ sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK | _SA_RESTART
sa.sa_mask = ^uint32(0)
sa.sa_tramp = unsafe.Pointer(funcPC(sigtramp)) // runtime·sigtramp's job is to call into real handler
*(*uintptr)(unsafe.Pointer(&sa.__sigaction_u)) = fn
- sigaction(uint32(i), &sa, nil)
+ sigaction(i, &sa, nil)
}
//go:nosplit
//go:nowritebarrierrec
-func setsigstack(i int32) {
+func setsigstack(i uint32) {
var osa usigactiont
- sigaction(uint32(i), nil, &osa)
+ sigaction(i, nil, &osa)
handler := *(*uintptr)(unsafe.Pointer(&osa.__sigaction_u))
- if handler == 0 || handler == _SIG_DFL || handler == _SIG_IGN || osa.sa_flags&_SA_ONSTACK != 0 {
+ if osa.sa_flags&_SA_ONSTACK != 0 {
return
}
var sa sigactiont
@@ -545,38 +525,47 @@ func setsigstack(i int32) {
sa.sa_tramp = unsafe.Pointer(funcPC(sigtramp))
sa.sa_mask = osa.sa_mask
sa.sa_flags = osa.sa_flags | _SA_ONSTACK
- sigaction(uint32(i), &sa, nil)
+ sigaction(i, &sa, nil)
}
//go:nosplit
//go:nowritebarrierrec
-func getsig(i int32) uintptr {
+func getsig(i uint32) uintptr {
var sa usigactiont
- sigaction(uint32(i), nil, &sa)
+ sigaction(i, nil, &sa)
return *(*uintptr)(unsafe.Pointer(&sa.__sigaction_u))
}
+// setSignaltstackSP sets the ss_sp field of a stackt.
//go:nosplit
-func signalstack(s *stack) {
- var st stackt
- if s == nil {
- st.ss_flags = _SS_DISABLE
- } else {
- st.ss_sp = (*byte)(unsafe.Pointer(s.lo))
- st.ss_size = s.hi - s.lo
- st.ss_flags = 0
- }
- sigaltstack(&st, nil)
+func setSignalstackSP(s *stackt, sp uintptr) {
+ *(*uintptr)(unsafe.Pointer(&s.ss_sp)) = sp
}
//go:nosplit
//go:nowritebarrierrec
-func updatesigmask(m sigmask) {
- s := sigset(m[0])
- sigprocmask(_SIG_SETMASK, &s, nil)
+func sigaddset(mask *sigset, i int) {
+ *mask |= 1 << (uint32(i) - 1)
+}
+
+func sigdelset(mask *sigset, i int) {
+ *mask &^= 1 << (uint32(i) - 1)
}
-func unblocksig(sig int32) {
- mask := sigset(1) << (uint32(sig) - 1)
- sigprocmask(_SIG_UNBLOCK, &mask, nil)
+//go:linkname executablePath os.executablePath
+var executablePath string
+
+func sysargs(argc int32, argv **byte) {
+ // skip over argv, envv and the first string will be the path
+ n := argc + 1
+ for argv_index(argv, n) != nil {
+ n++
+ }
+ executablePath = gostringnocopy(argv_index(argv, n+1))
+
+ // strip "executable_path=" prefix if available, it's added after OS X 10.11.
+ const prefix = "executable_path="
+ if len(executablePath) > len(prefix) && executablePath[:len(prefix)] == prefix {
+ executablePath = executablePath[len(prefix):]
+ }
}
diff --git a/src/runtime/os_darwin_arm.go b/src/runtime/os_darwin_arm.go
index 1ccc959..ee1bd17 100644
--- a/src/runtime/os_darwin_arm.go
+++ b/src/runtime/os_darwin_arm.go
@@ -17,8 +17,8 @@ func checkgoarm() {
//go:nosplit
func cputicks() int64 {
- // Currently cputicks() is used in blocking profiler and to seed runtime·fastrand1().
+ // Currently cputicks() is used in blocking profiler and to seed runtime·fastrand().
// runtime·nanotime() is a poor approximation of CPU ticks that is enough for the profiler.
- // TODO: need more entropy to better seed fastrand1.
+ // TODO: need more entropy to better seed fastrand.
return nanotime()
}
diff --git a/src/runtime/os_darwin_arm64.go b/src/runtime/os_darwin_arm64.go
index 4d35af9..8de132d 100644
--- a/src/runtime/os_darwin_arm64.go
+++ b/src/runtime/os_darwin_arm64.go
@@ -6,8 +6,8 @@ package runtime
//go:nosplit
func cputicks() int64 {
- // Currently cputicks() is used in blocking profiler and to seed runtime·fastrand1().
+ // Currently cputicks() is used in blocking profiler and to seed runtime·fastrand().
// runtime·nanotime() is a poor approximation of CPU ticks that is enough for the profiler.
- // TODO: need more entropy to better seed fastrand1.
+ // TODO: need more entropy to better seed fastrand.
return nanotime()
}
diff --git a/src/runtime/os_dragonfly.go b/src/runtime/os_dragonfly.go
index 85d4aad..4e50679 100644
--- a/src/runtime/os_dragonfly.go
+++ b/src/runtime/os_dragonfly.go
@@ -22,10 +22,10 @@ type mOS struct{}
func lwp_create(param *lwpparams) int32
//go:noescape
-func sigaltstack(new, old *sigaltstackt)
+func sigaltstack(new, old *stackt)
//go:noescape
-func sigaction(sig int32, new, old *sigactiont)
+func sigaction(sig uint32, new, old *sigactiont)
//go:noescape
func sigprocmask(how int32, new, old *sigset)
@@ -39,8 +39,8 @@ func sysctl(mib *uint32, miblen uint32, out *byte, size *uintptr, dst *byte, nds
//go:noescape
func getrlimit(kind int32, limit unsafe.Pointer) int32
-func raise(sig int32)
-func raiseproc(sig int32)
+func raise(sig uint32)
+func raiseproc(sig uint32)
//go:noescape
func sys_umtx_sleep(addr *uint32, val, timeout int32) int32
@@ -54,8 +54,9 @@ const stackSystem = 0
// From DragonFly's <sys/sysctl.h>
const (
- _CTL_HW = 6
- _HW_NCPU = 3
+ _CTL_HW = 6
+ _HW_NCPU = 3
+ _HW_PAGESIZE = 7
)
var sigset_all = sigset{[4]uint32{^uint32(0), ^uint32(0), ^uint32(0), ^uint32(0)}}
@@ -71,6 +72,17 @@ func getncpu() int32 {
return 1
}
+func getPageSize() uintptr {
+ mib := [2]uint32{_CTL_HW, _HW_PAGESIZE}
+ out := uint32(0)
+ nout := unsafe.Sizeof(out)
+ ret := sysctl(&mib[0], 2, (*byte)(unsafe.Pointer(&out)), &nout, nil, 0)
+ if ret >= 0 {
+ return uintptr(out)
+ }
+ return 0
+}
+
//go:nosplit
func futexsleep(addr *uint32, val uint32, ns int64) {
systemstack(func() {
@@ -141,6 +153,7 @@ func newosproc(mp *m, stk unsafe.Pointer) {
func osinit() {
ncpu = getncpu()
+ physPageSize = getPageSize()
}
var urandom_dev = []byte("/dev/urandom\x00")
@@ -164,57 +177,20 @@ func mpreinit(mp *m) {
mp.gsignal.m = mp
}
-//go:nosplit
-func msigsave(mp *m) {
- sigprocmask(_SIG_SETMASK, nil, &mp.sigmask)
-}
-
-//go:nosplit
-func msigrestore(sigmask sigset) {
- sigprocmask(_SIG_SETMASK, &sigmask, nil)
-}
-
-//go:nosplit
-func sigblock() {
- sigprocmask(_SIG_SETMASK, &sigset_all, nil)
-}
-
// Called to initialize a new m (including the bootstrap m).
// Called on the new thread, cannot allocate memory.
func minit() {
- _g_ := getg()
-
// m.procid is a uint64, but lwp_start writes an int32. Fix it up.
+ _g_ := getg()
_g_.m.procid = uint64(*(*int32)(unsafe.Pointer(&_g_.m.procid)))
- // Initialize signal handling.
-
- // On DragonFly a thread created by pthread_create inherits
- // the signal stack of the creating thread. We always create
- // a new signal stack here, to avoid having two Go threads
- // using the same signal stack. This breaks the case of a
- // thread created in C that calls sigaltstack and then calls a
- // Go function, because we will lose track of the C code's
- // sigaltstack, but it's the best we can do.
- signalstack(&_g_.m.gsignal.stack)
- _g_.m.newSigstack = true
-
- // restore signal mask from m.sigmask and unblock essential signals
- nmask := _g_.m.sigmask
- for i := range sigtable {
- if sigtable[i].flags&_SigUnblock != 0 {
- nmask.__bits[(i-1)/32] &^= 1 << ((uint32(i) - 1) & 31)
- }
- }
- sigprocmask(_SIG_SETMASK, &nmask, nil)
+ minitSignals()
}
// Called from dropm to undo the effect of an minit.
//go:nosplit
func unminit() {
- if getg().m.newSigstack {
- signalstack(nil)
- }
+ unminitSignals()
}
func memlimit() uintptr {
@@ -258,12 +234,9 @@ type sigactiont struct {
//go:nosplit
//go:nowritebarrierrec
-func setsig(i int32, fn uintptr, restart bool) {
+func setsig(i uint32, fn uintptr) {
var sa sigactiont
- sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK
- if restart {
- sa.sa_flags |= _SA_RESTART
- }
+ sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK | _SA_RESTART
sa.sa_mask = sigset_all
if fn == funcPC(sighandler) {
fn = funcPC(sigtramp)
@@ -274,44 +247,33 @@ func setsig(i int32, fn uintptr, restart bool) {
//go:nosplit
//go:nowritebarrierrec
-func setsigstack(i int32) {
+func setsigstack(i uint32) {
throw("setsigstack")
}
//go:nosplit
//go:nowritebarrierrec
-func getsig(i int32) uintptr {
+func getsig(i uint32) uintptr {
var sa sigactiont
sigaction(i, nil, &sa)
- if sa.sa_sigaction == funcPC(sigtramp) {
- return funcPC(sighandler)
- }
return sa.sa_sigaction
}
+// setSignaltstackSP sets the ss_sp field of a stackt.
//go:nosplit
-func signalstack(s *stack) {
- var st sigaltstackt
- if s == nil {
- st.ss_flags = _SS_DISABLE
- } else {
- st.ss_sp = s.lo
- st.ss_size = s.hi - s.lo
- st.ss_flags = 0
- }
- sigaltstack(&st, nil)
+func setSignalstackSP(s *stackt, sp uintptr) {
+ s.ss_sp = sp
}
//go:nosplit
//go:nowritebarrierrec
-func updatesigmask(m sigmask) {
- var mask sigset
- copy(mask.__bits[:], m[:])
- sigprocmask(_SIG_SETMASK, &mask, nil)
+func sigaddset(mask *sigset, i int) {
+ mask.__bits[(i-1)/32] |= 1 << ((uint32(i) - 1) & 31)
+}
+
+func sigdelset(mask *sigset, i int) {
+ mask.__bits[(i-1)/32] &^= 1 << ((uint32(i) - 1) & 31)
}
-func unblocksig(sig int32) {
- var mask sigset
- mask.__bits[(sig-1)/32] |= 1 << ((uint32(sig) - 1) & 31)
- sigprocmask(_SIG_UNBLOCK, &mask, nil)
+func (c *sigctxt) fixsigcode(sig uint32) {
}
diff --git a/src/runtime/os_freebsd.go b/src/runtime/os_freebsd.go
index 0e09c60..35ed026 100644
--- a/src/runtime/os_freebsd.go
+++ b/src/runtime/os_freebsd.go
@@ -18,7 +18,7 @@ func thr_new(param *thrparam, size int32)
func sigaltstack(new, old *stackt)
//go:noescape
-func sigaction(sig int32, new, old *sigactiont)
+func sigaction(sig uint32, new, old *sigactiont)
//go:noescape
func sigprocmask(how int32, new, old *sigset)
@@ -31,8 +31,8 @@ func sysctl(mib *uint32, miblen uint32, out *byte, size *uintptr, dst *byte, nds
//go:noescape
func getrlimit(kind int32, limit unsafe.Pointer) int32
-func raise(sig int32)
-func raiseproc(sig int32)
+func raise(sig uint32)
+func raiseproc(sig uint32)
//go:noescape
func sys_umtx_op(addr *uint32, mode int32, val uint32, uaddr1 uintptr, ut *umtx_time) int32
@@ -41,8 +41,9 @@ func osyield()
// From FreeBSD's <sys/sysctl.h>
const (
- _CTL_HW = 6
- _HW_NCPU = 3
+ _CTL_HW = 6
+ _HW_NCPU = 3
+ _HW_PAGESIZE = 7
)
var sigset_all = sigset{[4]uint32{^uint32(0), ^uint32(0), ^uint32(0), ^uint32(0)}}
@@ -58,6 +59,17 @@ func getncpu() int32 {
return 1
}
+func getPageSize() uintptr {
+ mib := [2]uint32{_CTL_HW, _HW_PAGESIZE}
+ out := uint32(0)
+ nout := unsafe.Sizeof(out)
+ ret := sysctl(&mib[0], 2, (*byte)(unsafe.Pointer(&out)), &nout, nil, 0)
+ if ret >= 0 {
+ return uintptr(out)
+ }
+ return 0
+}
+
// FreeBSD's umtx_op syscall is effectively the same as Linux's futex, and
// thus the code is largely similar. See Linux implementation
// and lock_futex.go for comments.
@@ -128,6 +140,7 @@ func newosproc(mp *m, stk unsafe.Pointer) {
func osinit() {
ncpu = getncpu()
+ physPageSize = getPageSize()
}
var urandom_dev = []byte("/dev/urandom\x00")
@@ -151,65 +164,23 @@ func mpreinit(mp *m) {
mp.gsignal.m = mp
}
-//go:nosplit
-func msigsave(mp *m) {
- sigprocmask(_SIG_SETMASK, nil, &mp.sigmask)
-}
-
-//go:nosplit
-func msigrestore(sigmask sigset) {
- sigprocmask(_SIG_SETMASK, &sigmask, nil)
-}
-
-//go:nosplit
-func sigblock() {
- sigprocmask(_SIG_SETMASK, &sigset_all, nil)
-}
-
// Called to initialize a new m (including the bootstrap m).
// Called on the new thread, cannot allocate memory.
func minit() {
- _g_ := getg()
-
// m.procid is a uint64, but thr_new writes a uint32 on 32-bit systems.
// Fix it up. (Only matters on big-endian, but be clean anyway.)
if sys.PtrSize == 4 {
+ _g_ := getg()
_g_.m.procid = uint64(*(*uint32)(unsafe.Pointer(&_g_.m.procid)))
}
- // Initialize signal handling.
- var st stackt
- sigaltstack(nil, &st)
- if st.ss_flags&_SS_DISABLE != 0 {
- signalstack(&_g_.m.gsignal.stack)
- _g_.m.newSigstack = true
- } else {
- // Use existing signal stack.
- stsp := uintptr(unsafe.Pointer(st.ss_sp))
- _g_.m.gsignal.stack.lo = stsp
- _g_.m.gsignal.stack.hi = stsp + st.ss_size
- _g_.m.gsignal.stackguard0 = stsp + _StackGuard
- _g_.m.gsignal.stackguard1 = stsp + _StackGuard
- _g_.m.gsignal.stackAlloc = st.ss_size
- _g_.m.newSigstack = false
- }
-
- // restore signal mask from m.sigmask and unblock essential signals
- nmask := _g_.m.sigmask
- for i := range sigtable {
- if sigtable[i].flags&_SigUnblock != 0 {
- nmask.__bits[(i-1)/32] &^= 1 << ((uint32(i) - 1) & 31)
- }
- }
- sigprocmask(_SIG_SETMASK, &nmask, nil)
+ minitSignals()
}
// Called from dropm to undo the effect of an minit.
//go:nosplit
func unminit() {
- if getg().m.newSigstack {
- signalstack(nil)
- }
+ unminitSignals()
}
func memlimit() uintptr {
@@ -253,12 +224,9 @@ type sigactiont struct {
//go:nosplit
//go:nowritebarrierrec
-func setsig(i int32, fn uintptr, restart bool) {
+func setsig(i uint32, fn uintptr) {
var sa sigactiont
- sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK
- if restart {
- sa.sa_flags |= _SA_RESTART
- }
+ sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK | _SA_RESTART
sa.sa_mask = sigset_all
if fn == funcPC(sighandler) {
fn = funcPC(sigtramp)
@@ -269,44 +237,33 @@ func setsig(i int32, fn uintptr, restart bool) {
//go:nosplit
//go:nowritebarrierrec
-func setsigstack(i int32) {
+func setsigstack(i uint32) {
throw("setsigstack")
}
//go:nosplit
//go:nowritebarrierrec
-func getsig(i int32) uintptr {
+func getsig(i uint32) uintptr {
var sa sigactiont
sigaction(i, nil, &sa)
- if sa.sa_handler == funcPC(sigtramp) {
- return funcPC(sighandler)
- }
return sa.sa_handler
}
+// setSignaltstackSP sets the ss_sp field of a stackt.
//go:nosplit
-func signalstack(s *stack) {
- var st stackt
- if s == nil {
- st.ss_flags = _SS_DISABLE
- } else {
- st.ss_sp = s.lo
- st.ss_size = s.hi - s.lo
- st.ss_flags = 0
- }
- sigaltstack(&st, nil)
+func setSignalstackSP(s *stackt, sp uintptr) {
+ s.ss_sp = sp
}
//go:nosplit
//go:nowritebarrierrec
-func updatesigmask(m [(_NSIG + 31) / 32]uint32) {
- var mask sigset
- copy(mask.__bits[:], m[:])
- sigprocmask(_SIG_SETMASK, &mask, nil)
+func sigaddset(mask *sigset, i int) {
+ mask.__bits[(i-1)/32] |= 1 << ((uint32(i) - 1) & 31)
+}
+
+func sigdelset(mask *sigset, i int) {
+ mask.__bits[(i-1)/32] &^= 1 << ((uint32(i) - 1) & 31)
}
-func unblocksig(sig int32) {
- var mask sigset
- mask.__bits[(sig-1)/32] |= 1 << ((uint32(sig) - 1) & 31)
- sigprocmask(_SIG_UNBLOCK, &mask, nil)
+func (c *sigctxt) fixsigcode(sig uint32) {
}
diff --git a/src/runtime/os_freebsd_arm.go b/src/runtime/os_freebsd_arm.go
index 1f2add2..0399499 100644
--- a/src/runtime/os_freebsd_arm.go
+++ b/src/runtime/os_freebsd_arm.go
@@ -17,8 +17,8 @@ func checkgoarm() {
//go:nosplit
func cputicks() int64 {
- // Currently cputicks() is used in blocking profiler and to seed runtime·fastrand1().
+ // Currently cputicks() is used in blocking profiler and to seed runtime·fastrand().
// runtime·nanotime() is a poor approximation of CPU ticks that is enough for the profiler.
- // TODO: need more entropy to better seed fastrand1.
+ // TODO: need more entropy to better seed fastrand.
return nanotime()
}
diff --git a/src/runtime/os_linux.go b/src/runtime/os_linux.go
index 542f214..320c128 100644
--- a/src/runtime/os_linux.go
+++ b/src/runtime/os_linux.go
@@ -133,7 +133,7 @@ const (
)
//go:noescape
-func clone(flags int32, stk, mm, gg, fn unsafe.Pointer) int32
+func clone(flags int32, stk, mp, gp, fn unsafe.Pointer) int32
// May run with m.p==nil, so write barriers are not allowed.
//go:nowritebarrier
@@ -148,9 +148,9 @@ func newosproc(mp *m, stk unsafe.Pointer) {
// Disable signals during clone, so that the new thread starts
// with signals disabled. It will enable them in minit.
var oset sigset
- rtsigprocmask(_SIG_SETMASK, &sigset_all, &oset, int32(unsafe.Sizeof(oset)))
+ sigprocmask(_SIG_SETMASK, &sigset_all, &oset)
ret := clone(cloneFlags, stk, unsafe.Pointer(mp), unsafe.Pointer(mp.g0), unsafe.Pointer(funcPC(mstart)))
- rtsigprocmask(_SIG_SETMASK, &oset, nil, int32(unsafe.Sizeof(oset)))
+ sigprocmask(_SIG_SETMASK, &oset, nil)
if ret < 0 {
print("runtime: failed to create new OS thread (have ", mcount(), " already; errno=", -ret, ")\n")
@@ -182,9 +182,13 @@ var failthreadcreate = []byte("runtime: failed to create new OS thread\n")
const (
_AT_NULL = 0 // End of vector
_AT_PAGESZ = 6 // System physical page size
+ _AT_HWCAP = 16 // hardware capability bit vector
_AT_RANDOM = 25 // introduced in 2.6.29
+ _AT_HWCAP2 = 26 // hardware capability bit vector 2
)
+var procAuxv = []byte("/proc/self/auxv\x00")
+
func sysargs(argc int32, argv **byte) {
n := argc + 1
@@ -198,7 +202,30 @@ func sysargs(argc int32, argv **byte) {
// now argv+n is auxv
auxv := (*[1 << 28]uintptr)(add(unsafe.Pointer(argv), uintptr(n)*sys.PtrSize))
- for i := 0; auxv[i] != _AT_NULL; i += 2 {
+ if sysauxv(auxv[:]) == 0 {
+ // In some situations we don't get a loader-provided
+ // auxv, such as when loaded as a library on Android.
+ // Fall back to /proc/self/auxv.
+ fd := open(&procAuxv[0], 0 /* O_RDONLY */, 0)
+ if fd < 0 {
+ return
+ }
+ var buf [128]uintptr
+ n := read(fd, noescape(unsafe.Pointer(&buf[0])), int32(unsafe.Sizeof(buf)))
+ closefd(fd)
+ if n < 0 {
+ return
+ }
+ // Make sure buf is terminated, even if we didn't read
+ // the whole file.
+ buf[len(buf)-2] = _AT_NULL
+ sysauxv(buf[:])
+ }
+}
+
+func sysauxv(auxv []uintptr) int {
+ var i int
+ for ; auxv[i] != _AT_NULL; i += 2 {
tag, val := auxv[i], auxv[i+1]
switch tag {
case _AT_RANDOM:
@@ -207,21 +234,12 @@ func sysargs(argc int32, argv **byte) {
startupRandomData = (*[16]byte)(unsafe.Pointer(val))[:]
case _AT_PAGESZ:
- // Check that the true physical page size is
- // compatible with the runtime's assumed
- // physical page size.
- if sys.PhysPageSize < val {
- print("runtime: kernel page size (", val, ") is larger than runtime page size (", sys.PhysPageSize, ")\n")
- exit(1)
- }
- if sys.PhysPageSize%val != 0 {
- print("runtime: runtime page size (", sys.PhysPageSize, ") is not a multiple of kernel page size (", val, ")\n")
- exit(1)
- }
+ physPageSize = val
}
archauxv(tag, val)
}
+ return i / 2
}
func osinit() {
@@ -262,65 +280,21 @@ func mpreinit(mp *m) {
mp.gsignal.m = mp
}
-//go:nosplit
-func msigsave(mp *m) {
- smask := &mp.sigmask
- rtsigprocmask(_SIG_SETMASK, nil, smask, int32(unsafe.Sizeof(*smask)))
-}
-
-//go:nosplit
-func msigrestore(sigmask sigset) {
- rtsigprocmask(_SIG_SETMASK, &sigmask, nil, int32(unsafe.Sizeof(sigmask)))
-}
-
-//go:nosplit
-func sigblock() {
- rtsigprocmask(_SIG_SETMASK, &sigset_all, nil, int32(unsafe.Sizeof(sigset_all)))
-}
-
func gettid() uint32
// Called to initialize a new m (including the bootstrap m).
// Called on the new thread, cannot allocate memory.
func minit() {
- // Initialize signal handling.
- _g_ := getg()
-
- var st sigaltstackt
- sigaltstack(nil, &st)
- if st.ss_flags&_SS_DISABLE != 0 {
- signalstack(&_g_.m.gsignal.stack)
- _g_.m.newSigstack = true
- } else {
- // Use existing signal stack.
- stsp := uintptr(unsafe.Pointer(st.ss_sp))
- _g_.m.gsignal.stack.lo = stsp
- _g_.m.gsignal.stack.hi = stsp + st.ss_size
- _g_.m.gsignal.stackguard0 = stsp + _StackGuard
- _g_.m.gsignal.stackguard1 = stsp + _StackGuard
- _g_.m.gsignal.stackAlloc = st.ss_size
- _g_.m.newSigstack = false
- }
+ minitSignals()
// for debuggers, in case cgo created the thread
- _g_.m.procid = uint64(gettid())
-
- // restore signal mask from m.sigmask and unblock essential signals
- nmask := _g_.m.sigmask
- for i := range sigtable {
- if sigtable[i].flags&_SigUnblock != 0 {
- sigdelset(&nmask, i)
- }
- }
- rtsigprocmask(_SIG_SETMASK, &nmask, nil, int32(unsafe.Sizeof(nmask)))
+ getg().m.procid = uint64(gettid())
}
// Called from dropm to undo the effect of an minit.
//go:nosplit
func unminit() {
- if getg().m.newSigstack {
- signalstack(nil)
- }
+ unminitSignals()
}
func memlimit() uintptr {
@@ -360,25 +334,28 @@ func memlimit() uintptr {
//#endif
func sigreturn()
-func sigtramp()
+func sigtramp(sig uint32, info *siginfo, ctx unsafe.Pointer)
func cgoSigtramp()
//go:noescape
-func rt_sigaction(sig uintptr, new, old *sigactiont, size uintptr) int32
-
-//go:noescape
-func sigaltstack(new, old *sigaltstackt)
+func sigaltstack(new, old *stackt)
//go:noescape
func setitimer(mode int32, new, old *itimerval)
//go:noescape
-func rtsigprocmask(sig uint32, new, old *sigset, size int32)
+func rtsigprocmask(how int32, new, old *sigset, size int32)
+
+//go:nosplit
+//go:nowritebarrierrec
+func sigprocmask(how int32, new, old *sigset) {
+ rtsigprocmask(how, new, old, int32(unsafe.Sizeof(*new)))
+}
//go:noescape
func getrlimit(kind int32, limit unsafe.Pointer) int32
-func raise(sig int32)
-func raiseproc(sig int32)
+func raise(sig uint32)
+func raiseproc(sig uint32)
//go:noescape
func sched_getaffinity(pid, len uintptr, buf *uintptr) int32
@@ -386,13 +363,9 @@ func osyield()
//go:nosplit
//go:nowritebarrierrec
-func setsig(i int32, fn uintptr, restart bool) {
+func setsig(i uint32, fn uintptr) {
var sa sigactiont
- memclr(unsafe.Pointer(&sa), unsafe.Sizeof(sa))
- sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK | _SA_RESTORER
- if restart {
- sa.sa_flags |= _SA_RESTART
- }
+ sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK | _SA_RESTORER | _SA_RESTART
sigfillset(&sa.sa_mask)
// Although Linux manpage says "sa_restorer element is obsolete and
// should not be used". x86_64 kernel requires it. Only use it on
@@ -413,58 +386,31 @@ func setsig(i int32, fn uintptr, restart bool) {
//go:nosplit
//go:nowritebarrierrec
-func setsigstack(i int32) {
+func setsigstack(i uint32) {
var sa sigactiont
- if rt_sigaction(uintptr(i), nil, &sa, unsafe.Sizeof(sa.sa_mask)) != 0 {
- throw("rt_sigaction failure")
- }
- if sa.sa_handler == 0 || sa.sa_handler == _SIG_DFL || sa.sa_handler == _SIG_IGN || sa.sa_flags&_SA_ONSTACK != 0 {
+ rt_sigaction(uintptr(i), nil, &sa, unsafe.Sizeof(sa.sa_mask))
+ if sa.sa_flags&_SA_ONSTACK != 0 {
return
}
sa.sa_flags |= _SA_ONSTACK
- if rt_sigaction(uintptr(i), &sa, nil, unsafe.Sizeof(sa.sa_mask)) != 0 {
- throw("rt_sigaction failure")
- }
+ rt_sigaction(uintptr(i), &sa, nil, unsafe.Sizeof(sa.sa_mask))
}
//go:nosplit
//go:nowritebarrierrec
-func getsig(i int32) uintptr {
+func getsig(i uint32) uintptr {
var sa sigactiont
-
- memclr(unsafe.Pointer(&sa), unsafe.Sizeof(sa))
if rt_sigaction(uintptr(i), nil, &sa, unsafe.Sizeof(sa.sa_mask)) != 0 {
throw("rt_sigaction read failure")
}
- if sa.sa_handler == funcPC(sigtramp) || sa.sa_handler == funcPC(cgoSigtramp) {
- return funcPC(sighandler)
- }
return sa.sa_handler
}
+// setSignaltstackSP sets the ss_sp field of a stackt.
//go:nosplit
-func signalstack(s *stack) {
- var st sigaltstackt
- if s == nil {
- st.ss_flags = _SS_DISABLE
- } else {
- st.ss_sp = (*byte)(unsafe.Pointer(s.lo))
- st.ss_size = s.hi - s.lo
- st.ss_flags = 0
- }
- sigaltstack(&st, nil)
-}
-
-//go:nosplit
-//go:nowritebarrierrec
-func updatesigmask(m sigmask) {
- var mask sigset
- sigcopyset(&mask, m)
- rtsigprocmask(_SIG_SETMASK, &mask, nil, int32(unsafe.Sizeof(mask)))
+func setSignalstackSP(s *stackt, sp uintptr) {
+ *(*uintptr)(unsafe.Pointer(&s.ss_sp)) = sp
}
-func unblocksig(sig int32) {
- var mask sigset
- sigaddset(&mask, int(sig))
- rtsigprocmask(_SIG_UNBLOCK, &mask, nil, int32(unsafe.Sizeof(mask)))
+func (c *sigctxt) fixsigcode(sig uint32) {
}
diff --git a/src/runtime/os_linux_arm.go b/src/runtime/os_linux_arm.go
index 8e2765a..2b0834a 100644
--- a/src/runtime/os_linux_arm.go
+++ b/src/runtime/os_linux_arm.go
@@ -8,7 +8,6 @@ import "unsafe"
const (
_AT_PLATFORM = 15 // introduced in at least 2.6.11
- _AT_HWCAP = 16 // introduced in at least 2.6.11
_HWCAP_VFP = 1 << 6 // introduced in at least 2.6.11
_HWCAP_VFPv3 = 1 << 13 // introduced in 2.6.30
@@ -53,8 +52,8 @@ func archauxv(tag, val uintptr) {
//go:nosplit
func cputicks() int64 {
- // Currently cputicks() is used in blocking profiler and to seed fastrand1().
+ // Currently cputicks() is used in blocking profiler and to seed fastrand().
// nanotime() is a poor approximation of CPU ticks that is enough for the profiler.
- // randomNumber provides better seeding of fastrand1.
+ // randomNumber provides better seeding of fastrand.
return nanotime() + int64(randomNumber)
}
diff --git a/src/runtime/os_linux_arm64.go b/src/runtime/os_linux_arm64.go
index 43262ae..bdc341d 100644
--- a/src/runtime/os_linux_arm64.go
+++ b/src/runtime/os_linux_arm64.go
@@ -19,8 +19,8 @@ func archauxv(tag, val uintptr) {
//go:nosplit
func cputicks() int64 {
- // Currently cputicks() is used in blocking profiler and to seed fastrand1().
+ // Currently cputicks() is used in blocking profiler and to seed fastrand().
// nanotime() is a poor approximation of CPU ticks that is enough for the profiler.
- // randomNumber provides better seeding of fastrand1.
+ // randomNumber provides better seeding of fastrand.
return nanotime() + int64(randomNumber)
}
diff --git a/src/runtime/os_linux_be64.go b/src/runtime/os_linux_be64.go
new file mode 100644
index 0000000..e66dcac
--- /dev/null
+++ b/src/runtime/os_linux_be64.go
@@ -0,0 +1,48 @@
+// Copyright 2016 The Go 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 standard GNU/Linux sigset type on big-endian 64-bit machines.
+
+// +build ppc64 s390x
+
+package runtime
+
+const (
+ _SS_DISABLE = 2
+ _NSIG = 65
+ _SI_USER = 0
+ _SIG_BLOCK = 0
+ _SIG_UNBLOCK = 1
+ _SIG_SETMASK = 2
+ _RLIMIT_AS = 9
+)
+
+type sigset uint64
+
+type rlimit struct {
+ rlim_cur uintptr
+ rlim_max uintptr
+}
+
+var sigset_all = sigset(^uint64(0))
+
+//go:nosplit
+//go:nowritebarrierrec
+func sigaddset(mask *sigset, i int) {
+ if i > 64 {
+ throw("unexpected signal greater than 64")
+ }
+ *mask |= 1 << (uint(i) - 1)
+}
+
+func sigdelset(mask *sigset, i int) {
+ if i > 64 {
+ throw("unexpected signal greater than 64")
+ }
+ *mask &^= 1 << (uint(i) - 1)
+}
+
+func sigfillset(mask *uint64) {
+ *mask = ^uint64(0)
+}
diff --git a/src/runtime/os_linux_generic.go b/src/runtime/os_linux_generic.go
index a16d140..f672162 100644
--- a/src/runtime/os_linux_generic.go
+++ b/src/runtime/os_linux_generic.go
@@ -2,9 +2,12 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// +build !mips
+// +build !mipsle
// +build !mips64
// +build !mips64le
// +build !s390x
+// +build !ppc64
// +build linux
package runtime
@@ -31,6 +34,8 @@ type rlimit struct {
var sigset_all = sigset{^uint32(0), ^uint32(0)}
+//go:nosplit
+//go:nowritebarrierrec
func sigaddset(mask *sigset, i int) {
(*mask)[(i-1)/32] |= 1 << ((uint32(i) - 1) & 31)
}
@@ -42,7 +47,3 @@ func sigdelset(mask *sigset, i int) {
func sigfillset(mask *uint64) {
*mask = ^uint64(0)
}
-
-func sigcopyset(mask *sigset, m sigmask) {
- copy((*mask)[:], m[:])
-}
diff --git a/src/runtime/os_linux_mips64x.go b/src/runtime/os_linux_mips64x.go
index 8039b2f..be2b719 100644
--- a/src/runtime/os_linux_mips64x.go
+++ b/src/runtime/os_linux_mips64x.go
@@ -22,15 +22,15 @@ func archauxv(tag, val uintptr) {
//go:nosplit
func cputicks() int64 {
- // Currently cputicks() is used in blocking profiler and to seed fastrand1().
+ // Currently cputicks() is used in blocking profiler and to seed fastrand().
// nanotime() is a poor approximation of CPU ticks that is enough for the profiler.
- // randomNumber provides better seeding of fastrand1.
+ // randomNumber provides better seeding of fastrand.
return nanotime() + int64(randomNumber)
}
const (
_SS_DISABLE = 2
- _NSIG = 65
+ _NSIG = 129
_SI_USER = 0
_SIG_BLOCK = 1
_SIG_UNBLOCK = 2
@@ -47,6 +47,8 @@ type rlimit struct {
var sigset_all = sigset{^uint64(0), ^uint64(0)}
+//go:nosplit
+//go:nowritebarrierrec
func sigaddset(mask *sigset, i int) {
(*mask)[(i-1)/64] |= 1 << ((uint32(i) - 1) & 63)
}
@@ -58,7 +60,3 @@ func sigdelset(mask *sigset, i int) {
func sigfillset(mask *[2]uint64) {
(*mask)[0], (*mask)[1] = ^uint64(0), ^uint64(0)
}
-
-func sigcopyset(mask *sigset, m sigmask) {
- (*mask)[0] = uint64(m[0]) | uint64(m[1])<<32
-}
diff --git a/src/runtime/os_linux_mipsx.go b/src/runtime/os_linux_mipsx.go
new file mode 100644
index 0000000..313da1b
--- /dev/null
+++ b/src/runtime/os_linux_mipsx.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.
+
+// +build linux
+// +build mips mipsle
+
+package runtime
+
+var randomNumber uint32
+
+func archauxv(tag, val uintptr) {
+ switch tag {
+ case _AT_RANDOM:
+ // sysargs filled in startupRandomData, but that
+ // pointer may not be word aligned, so we must treat
+ // it as a byte array.
+ randomNumber = uint32(startupRandomData[4]) | uint32(startupRandomData[5])<<8 |
+ uint32(startupRandomData[6])<<16 | uint32(startupRandomData[7])<<24
+ }
+}
+
+//go:nosplit
+func cputicks() int64 {
+ // Currently cputicks() is used in blocking profiler and to seed fastrand().
+ // nanotime() is a poor approximation of CPU ticks that is enough for the profiler.
+ // randomNumber provides better seeding of fastrand1.
+ return nanotime() + int64(randomNumber)
+}
+
+const (
+ _SS_DISABLE = 2
+ _NSIG = 128 + 1
+ _SI_USER = 0
+ _SIG_BLOCK = 1
+ _SIG_UNBLOCK = 2
+ _SIG_SETMASK = 3
+ _RLIMIT_AS = 6
+)
+
+type sigset [4]uint32
+
+type rlimit struct {
+ rlim_cur uintptr
+ rlim_max uintptr
+}
+
+var sigset_all = sigset{^uint32(0), ^uint32(0), ^uint32(0), ^uint32(0)}
+
+//go:nosplit
+//go:nowritebarrierrec
+func sigaddset(mask *sigset, i int) {
+ (*mask)[(i-1)/32] |= 1 << ((uint32(i) - 1) & 31)
+}
+
+func sigdelset(mask *sigset, i int) {
+ (*mask)[(i-1)/32] &^= 1 << ((uint32(i) - 1) & 31)
+}
+
+func sigfillset(mask *[4]uint32) {
+ (*mask)[0], (*mask)[1], (*mask)[2], (*mask)[3] = ^uint32(0), ^uint32(0), ^uint32(0), ^uint32(0)
+}
diff --git a/src/runtime/os_linux_noauxv.go b/src/runtime/os_linux_noauxv.go
index 22522dd..5e9f031 100644
--- a/src/runtime/os_linux_noauxv.go
+++ b/src/runtime/os_linux_noauxv.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,!arm,!arm64,!mips64,!mips64le
+// +build !amd64,!arm,!arm64,!mips,!mipsle,!mips64,!mips64le,!s390x,!ppc64,!ppc64le
package runtime
diff --git a/src/runtime/os_linux_ppc64x.go b/src/runtime/os_linux_ppc64x.go
new file mode 100644
index 0000000..b0da98b
--- /dev/null
+++ b/src/runtime/os_linux_ppc64x.go
@@ -0,0 +1,60 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build ppc64 ppc64le
+
+package runtime
+
+import (
+ "runtime/internal/sys"
+)
+
+const (
+ // ISA level
+ // Go currently requires POWER5 as a minimum for ppc64, so we need
+ // to check for ISA 2.03 and beyond.
+ _PPC_FEATURE_POWER5_PLUS = 0x00020000 // ISA 2.03 (POWER5+)
+ _PPC_FEATURE_ARCH_2_05 = 0x00001000 // ISA 2.05 (POWER6)
+ _PPC_FEATURE_POWER6_EXT = 0x00000200 // mffgpr/mftgpr extension (POWER6x)
+ _PPC_FEATURE_ARCH_2_06 = 0x00000100 // ISA 2.06 (POWER7)
+ _PPC_FEATURE2_ARCH_2_07 = 0x80000000 // ISA 2.07 (POWER8)
+
+ // Standalone capabilities
+ _PPC_FEATURE_HAS_ALTIVEC = 0x10000000 // SIMD/Vector unit
+ _PPC_FEATURE_HAS_VSX = 0x00000080 // Vector scalar unit
+)
+
+type facilities struct {
+ _ [sys.CacheLineSize]byte
+ isPOWER5x bool // ISA 2.03
+ isPOWER6 bool // ISA 2.05
+ isPOWER6x bool // ISA 2.05 + mffgpr/mftgpr extension
+ isPOWER7 bool // ISA 2.06
+ isPOWER8 bool // ISA 2.07
+ hasVMX bool // Vector unit
+ hasVSX bool // Vector scalar unit
+ _ [sys.CacheLineSize]byte
+}
+
+// cpu can be tested at runtime in go assembler code to check for
+// a certain ISA level or hardware capability, for example:
+// ·cpu+facilities_hasVSX(SB) for checking the availability of VSX
+// or
+// ·cpu+facilities_isPOWER7(SB) for checking if the processor implements
+// ISA 2.06 instructions.
+var cpu facilities
+
+func archauxv(tag, val uintptr) {
+ switch tag {
+ case _AT_HWCAP:
+ cpu.isPOWER5x = val&_PPC_FEATURE_POWER5_PLUS != 0
+ cpu.isPOWER6 = val&_PPC_FEATURE_ARCH_2_05 != 0
+ cpu.isPOWER6x = val&_PPC_FEATURE_POWER6_EXT != 0
+ cpu.isPOWER7 = val&_PPC_FEATURE_ARCH_2_06 != 0
+ cpu.hasVMX = val&_PPC_FEATURE_HAS_ALTIVEC != 0
+ cpu.hasVSX = val&_PPC_FEATURE_HAS_VSX != 0
+ case _AT_HWCAP2:
+ cpu.isPOWER8 = val&_PPC_FEATURE2_ARCH_2_07 != 0
+ }
+}
diff --git a/src/runtime/os_linux_s390x.go b/src/runtime/os_linux_s390x.go
index e659dff..3ca6d4c 100644
--- a/src/runtime/os_linux_s390x.go
+++ b/src/runtime/os_linux_s390x.go
@@ -4,43 +4,29 @@
package runtime
-const (
- _SS_DISABLE = 2
- _NSIG = 65
- _SI_USER = 0
- _SIG_BLOCK = 0
- _SIG_UNBLOCK = 1
- _SIG_SETMASK = 2
- _RLIMIT_AS = 9
+import (
+ "runtime/internal/sys"
)
-type sigset uint64
+const (
+ // bit masks taken from bits/hwcap.h
+ _HWCAP_S390_VX = 2048 // vector facility
+)
-type rlimit struct {
- rlim_cur uintptr
- rlim_max uintptr
+// facilities is padded to avoid false sharing.
+type facilities struct {
+ _ [sys.CacheLineSize]byte
+ hasVX bool // vector facility
+ _ [sys.CacheLineSize]byte
}
-var sigset_all = sigset(^uint64(0))
-
-func sigaddset(mask *sigset, i int) {
- if i > 64 {
- throw("unexpected signal greater than 64")
- }
- *mask |= 1 << (uint(i) - 1)
-}
+// cpu indicates the availability of s390x facilities that can be used in
+// Go assembly but are optional on models supported by Go.
+var cpu facilities
-func sigdelset(mask *sigset, i int) {
- if i > 64 {
- throw("unexpected signal greater than 64")
+func archauxv(tag, val uintptr) {
+ switch tag {
+ case _AT_HWCAP: // CPU capability bit flags
+ cpu.hasVX = val&_HWCAP_S390_VX != 0
}
- *mask &^= 1 << (uint(i) - 1)
-}
-
-func sigfillset(mask *uint64) {
- *mask = ^uint64(0)
-}
-
-func sigcopyset(mask *sigset, m sigmask) {
- *mask = sigset(uint64(m[0]) | uint64(m[1])<<32)
}
diff --git a/src/runtime/os_nacl.go b/src/runtime/os_nacl.go
index 1dacc1a..7015316 100644
--- a/src/runtime/os_nacl.go
+++ b/src/runtime/os_nacl.go
@@ -45,7 +45,7 @@ func os_sigpipe() {
throw("too many writes on closed pipe")
}
-func dieFromSignal(sig int32) {
+func dieFromSignal(sig uint32) {
exit(2)
}
@@ -60,7 +60,7 @@ func sigpanic() {
panicmem()
}
-func raiseproc(sig int32) {
+func raiseproc(sig uint32) {
}
// Stubs so tests can link correctly. These should never be called.
@@ -116,6 +116,7 @@ func osinit() {
ncpu = 1
getg().m.procid = 2
//nacl_exception_handler(funcPC(sigtramp), nil);
+ physPageSize = 65536
}
func signame(sig uint32) string {
@@ -253,7 +254,7 @@ func badsignalgo(sig uintptr) {
if !sigsend(uint32(sig)) {
// A foreign thread received the signal sig, and the
// Go code does not want to handle it.
- raisebadsignal(int32(sig))
+ raisebadsignal(uint32(sig))
}
}
@@ -266,7 +267,7 @@ func badsignal2() {
var badsignal1 = []byte("runtime: signal received on thread not created by Go.\n")
-func raisebadsignal(sig int32) {
+func raisebadsignal(sig uint32) {
badsignal2()
}
diff --git a/src/runtime/os_nacl_arm.go b/src/runtime/os_nacl_arm.go
index f94c183..8669ee7 100644
--- a/src/runtime/os_nacl_arm.go
+++ b/src/runtime/os_nacl_arm.go
@@ -16,8 +16,8 @@ func checkgoarm() {
//go:nosplit
func cputicks() int64 {
- // Currently cputicks() is used in blocking profiler and to seed runtime·fastrand1().
+ // Currently cputicks() is used in blocking profiler and to seed runtime·fastrand().
// runtime·nanotime() is a poor approximation of CPU ticks that is enough for the profiler.
- // TODO: need more entropy to better seed fastrand1.
+ // TODO: need more entropy to better seed fastrand.
return nanotime()
}
diff --git a/src/runtime/os_netbsd.go b/src/runtime/os_netbsd.go
index 4c44b2b..c79b50b 100644
--- a/src/runtime/os_netbsd.go
+++ b/src/runtime/os_netbsd.go
@@ -32,21 +32,21 @@ type mOS struct {
func setitimer(mode int32, new, old *itimerval)
//go:noescape
-func sigaction(sig int32, new, old *sigactiont)
+func sigaction(sig uint32, new, old *sigactiont)
//go:noescape
-func sigaltstack(new, old *sigaltstackt)
+func sigaltstack(new, old *stackt)
//go:noescape
-func sigprocmask(mode int32, new, old *sigset)
+func sigprocmask(how int32, new, old *sigset)
//go:noescape
func sysctl(mib *uint32, miblen uint32, out *byte, size *uintptr, dst *byte, ndst uintptr) int32
func lwp_tramp()
-func raise(sig int32)
-func raiseproc(sig int32)
+func raise(sig uint32)
+func raiseproc(sig uint32)
//go:noescape
func getcontext(ctxt unsafe.Pointer)
@@ -79,8 +79,9 @@ var sigset_all = sigset{[4]uint32{^uint32(0), ^uint32(0), ^uint32(0), ^uint32(0)
// From NetBSD's <sys/sysctl.h>
const (
- _CTL_HW = 6
- _HW_NCPU = 3
+ _CTL_HW = 6
+ _HW_NCPU = 3
+ _HW_PAGESIZE = 7
)
func getncpu() int32 {
@@ -94,6 +95,17 @@ func getncpu() int32 {
return 1
}
+func getPageSize() uintptr {
+ mib := [2]uint32{_CTL_HW, _HW_PAGESIZE}
+ out := uint32(0)
+ nout := unsafe.Sizeof(out)
+ ret := sysctl(&mib[0], 2, (*byte)(unsafe.Pointer(&out)), &nout, nil, 0)
+ if ret >= 0 {
+ return uintptr(out)
+ }
+ return 0
+}
+
//go:nosplit
func semacreate(mp *m) {
}
@@ -180,12 +192,14 @@ func newosproc(mp *m, stk unsafe.Pointer) {
// At this point all signals are blocked, so there is no race.
//go:nosplit
func netbsdMstart() {
- signalstack(nil)
+ st := stackt{ss_flags: _SS_DISABLE}
+ sigaltstack(&st, nil)
mstart()
}
func osinit() {
ncpu = getncpu()
+ physPageSize = getPageSize()
}
var urandom_dev = []byte("/dev/urandom\x00")
@@ -209,29 +223,12 @@ func mpreinit(mp *m) {
mp.gsignal.m = mp
}
-//go:nosplit
-func msigsave(mp *m) {
- sigprocmask(_SIG_SETMASK, nil, &mp.sigmask)
-}
-
-//go:nosplit
-func msigrestore(sigmask sigset) {
- sigprocmask(_SIG_SETMASK, &sigmask, nil)
-}
-
-//go:nosplit
-func sigblock() {
- sigprocmask(_SIG_SETMASK, &sigset_all, nil)
-}
-
// Called to initialize a new m (including the bootstrap m).
// Called on the new thread, cannot allocate memory.
func minit() {
_g_ := getg()
_g_.m.procid = uint64(lwp_self())
- // Initialize signal handling.
-
// On NetBSD a thread created by pthread_create inherits the
// signal stack of the creating thread. We always create a
// new signal stack here, to avoid having two Go threads using
@@ -242,22 +239,13 @@ func minit() {
signalstack(&_g_.m.gsignal.stack)
_g_.m.newSigstack = true
- // restore signal mask from m.sigmask and unblock essential signals
- nmask := _g_.m.sigmask
- for i := range sigtable {
- if sigtable[i].flags&_SigUnblock != 0 {
- nmask.__bits[(i-1)/32] &^= 1 << ((uint32(i) - 1) & 31)
- }
- }
- sigprocmask(_SIG_SETMASK, &nmask, nil)
+ minitSignalMask()
}
// Called from dropm to undo the effect of an minit.
//go:nosplit
func unminit() {
- if getg().m.newSigstack {
- signalstack(nil)
- }
+ unminitSignals()
}
func memlimit() uintptr {
@@ -274,12 +262,9 @@ type sigactiont struct {
//go:nosplit
//go:nowritebarrierrec
-func setsig(i int32, fn uintptr, restart bool) {
+func setsig(i uint32, fn uintptr) {
var sa sigactiont
- sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK
- if restart {
- sa.sa_flags |= _SA_RESTART
- }
+ sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK | _SA_RESTART
sa.sa_mask = sigset_all
if fn == funcPC(sighandler) {
fn = funcPC(sigtramp)
@@ -290,44 +275,33 @@ func setsig(i int32, fn uintptr, restart bool) {
//go:nosplit
//go:nowritebarrierrec
-func setsigstack(i int32) {
+func setsigstack(i uint32) {
throw("setsigstack")
}
//go:nosplit
//go:nowritebarrierrec
-func getsig(i int32) uintptr {
+func getsig(i uint32) uintptr {
var sa sigactiont
sigaction(i, nil, &sa)
- if sa.sa_sigaction == funcPC(sigtramp) {
- return funcPC(sighandler)
- }
return sa.sa_sigaction
}
+// setSignaltstackSP sets the ss_sp field of a stackt.
//go:nosplit
-func signalstack(s *stack) {
- var st sigaltstackt
- if s == nil {
- st.ss_flags = _SS_DISABLE
- } else {
- st.ss_sp = s.lo
- st.ss_size = s.hi - s.lo
- st.ss_flags = 0
- }
- sigaltstack(&st, nil)
+func setSignalstackSP(s *stackt, sp uintptr) {
+ s.ss_sp = sp
}
//go:nosplit
//go:nowritebarrierrec
-func updatesigmask(m sigmask) {
- var mask sigset
- copy(mask.__bits[:], m[:])
- sigprocmask(_SIG_SETMASK, &mask, nil)
+func sigaddset(mask *sigset, i int) {
+ mask.__bits[(i-1)/32] |= 1 << ((uint32(i) - 1) & 31)
+}
+
+func sigdelset(mask *sigset, i int) {
+ mask.__bits[(i-1)/32] &^= 1 << ((uint32(i) - 1) & 31)
}
-func unblocksig(sig int32) {
- var mask sigset
- mask.__bits[(sig-1)/32] |= 1 << ((uint32(sig) - 1) & 31)
- sigprocmask(_SIG_UNBLOCK, &mask, nil)
+func (c *sigctxt) fixsigcode(sig uint32) {
}
diff --git a/src/runtime/os_netbsd_arm.go b/src/runtime/os_netbsd_arm.go
index 03032e8..95603da 100644
--- a/src/runtime/os_netbsd_arm.go
+++ b/src/runtime/os_netbsd_arm.go
@@ -28,8 +28,8 @@ func checkgoarm() {
//go:nosplit
func cputicks() int64 {
- // Currently cputicks() is used in blocking profiler and to seed runtime·fastrand1().
+ // Currently cputicks() is used in blocking profiler and to seed runtime·fastrand().
// runtime·nanotime() is a poor approximation of CPU ticks that is enough for the profiler.
- // TODO: need more entropy to better seed fastrand1.
+ // TODO: need more entropy to better seed fastrand.
return nanotime()
}
diff --git a/src/runtime/os_openbsd.go b/src/runtime/os_openbsd.go
index 9a5c53e..350166d 100644
--- a/src/runtime/os_openbsd.go
+++ b/src/runtime/os_openbsd.go
@@ -17,19 +17,32 @@ type mOS struct {
func setitimer(mode int32, new, old *itimerval)
//go:noescape
-func sigaction(sig int32, new, old *sigactiont)
+func sigaction(sig uint32, new, old *sigactiont)
//go:noescape
func sigaltstack(new, old *stackt)
//go:noescape
-func sigprocmask(mode int32, new sigset) sigset
+func obsdsigprocmask(how int32, new sigset) sigset
+
+//go:nosplit
+//go:nowritebarrierrec
+func sigprocmask(how int32, new, old *sigset) {
+ n := sigset(0)
+ if new != nil {
+ n = *new
+ }
+ r := obsdsigprocmask(how, n)
+ if old != nil {
+ *old = r
+ }
+}
//go:noescape
func sysctl(mib *uint32, miblen uint32, out *byte, size *uintptr, dst *byte, ndst uintptr) int32
-func raise(sig int32)
-func raiseproc(sig int32)
+func raise(sig uint32)
+func raiseproc(sig uint32)
//go:noescape
func tfork(param *tforkt, psize uintptr, mm *m, gg *g, fn uintptr) int32
@@ -57,15 +70,13 @@ const (
type sigset uint32
-const (
- sigset_none = sigset(0)
- sigset_all = ^sigset(0)
-)
+var sigset_all = ^sigset(0)
// From OpenBSD's <sys/sysctl.h>
const (
- _CTL_HW = 6
- _HW_NCPU = 3
+ _CTL_HW = 6
+ _HW_NCPU = 3
+ _HW_PAGESIZE = 7
)
func getncpu() int32 {
@@ -81,6 +92,17 @@ func getncpu() int32 {
return 1
}
+func getPageSize() uintptr {
+ mib := [2]uint32{_CTL_HW, _HW_PAGESIZE}
+ out := uint32(0)
+ nout := unsafe.Sizeof(out)
+ ret := sysctl(&mib[0], 2, (*byte)(unsafe.Pointer(&out)), &nout, nil, 0)
+ if ret >= 0 {
+ return uintptr(out)
+ }
+ return 0
+}
+
//go:nosplit
func semacreate(mp *m) {
}
@@ -148,9 +170,10 @@ func newosproc(mp *m, stk unsafe.Pointer) {
tf_stack: uintptr(stk),
}
- oset := sigprocmask(_SIG_SETMASK, sigset_all)
+ var oset sigset
+ sigprocmask(_SIG_SETMASK, &sigset_all, &oset)
ret := tfork(¶m, unsafe.Sizeof(param), mp, mp.g0, funcPC(mstart))
- sigprocmask(_SIG_SETMASK, oset)
+ sigprocmask(_SIG_SETMASK, &oset, nil)
if ret < 0 {
print("runtime: failed to create new OS thread (have ", mcount()-1, " already; errno=", -ret, ")\n")
@@ -163,6 +186,7 @@ func newosproc(mp *m, stk unsafe.Pointer) {
func osinit() {
ncpu = getncpu()
+ physPageSize = getPageSize()
}
var urandom_dev = []byte("/dev/urandom\x00")
@@ -186,62 +210,20 @@ func mpreinit(mp *m) {
mp.gsignal.m = mp
}
-//go:nosplit
-func msigsave(mp *m) {
- mp.sigmask = sigprocmask(_SIG_BLOCK, 0)
-}
-
-//go:nosplit
-func msigrestore(sigmask sigset) {
- sigprocmask(_SIG_SETMASK, sigmask)
-}
-
-//go:nosplit
-func sigblock() {
- sigprocmask(_SIG_SETMASK, sigset_all)
-}
-
// Called to initialize a new m (including the bootstrap m).
// Called on the new thread, can not allocate memory.
func minit() {
- _g_ := getg()
-
// m.procid is a uint64, but tfork writes an int32. Fix it up.
+ _g_ := getg()
_g_.m.procid = uint64(*(*int32)(unsafe.Pointer(&_g_.m.procid)))
- // Initialize signal handling
- var st stackt
- sigaltstack(nil, &st)
- if st.ss_flags&_SS_DISABLE != 0 {
- signalstack(&_g_.m.gsignal.stack)
- _g_.m.newSigstack = true
- } else {
- // Use existing signal stack.
- stsp := uintptr(unsafe.Pointer(st.ss_sp))
- _g_.m.gsignal.stack.lo = stsp
- _g_.m.gsignal.stack.hi = stsp + st.ss_size
- _g_.m.gsignal.stackguard0 = stsp + _StackGuard
- _g_.m.gsignal.stackguard1 = stsp + _StackGuard
- _g_.m.gsignal.stackAlloc = st.ss_size
- _g_.m.newSigstack = false
- }
-
- // restore signal mask from m.sigmask and unblock essential signals
- nmask := _g_.m.sigmask
- for i := range sigtable {
- if sigtable[i].flags&_SigUnblock != 0 {
- nmask &^= 1 << (uint32(i) - 1)
- }
- }
- sigprocmask(_SIG_SETMASK, nmask)
+ minitSignals()
}
// Called from dropm to undo the effect of an minit.
//go:nosplit
func unminit() {
- if getg().m.newSigstack {
- signalstack(nil)
- }
+ unminitSignals()
}
func memlimit() uintptr {
@@ -258,12 +240,9 @@ type sigactiont struct {
//go:nosplit
//go:nowritebarrierrec
-func setsig(i int32, fn uintptr, restart bool) {
+func setsig(i uint32, fn uintptr) {
var sa sigactiont
- sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK
- if restart {
- sa.sa_flags |= _SA_RESTART
- }
+ sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK | _SA_RESTART
sa.sa_mask = uint32(sigset_all)
if fn == funcPC(sighandler) {
fn = funcPC(sigtramp)
@@ -274,41 +253,33 @@ func setsig(i int32, fn uintptr, restart bool) {
//go:nosplit
//go:nowritebarrierrec
-func setsigstack(i int32) {
+func setsigstack(i uint32) {
throw("setsigstack")
}
//go:nosplit
//go:nowritebarrierrec
-func getsig(i int32) uintptr {
+func getsig(i uint32) uintptr {
var sa sigactiont
sigaction(i, nil, &sa)
- if sa.sa_sigaction == funcPC(sigtramp) {
- return funcPC(sighandler)
- }
return sa.sa_sigaction
}
+// setSignaltstackSP sets the ss_sp field of a stackt.
//go:nosplit
-func signalstack(s *stack) {
- var st stackt
- if s == nil {
- st.ss_flags = _SS_DISABLE
- } else {
- st.ss_sp = s.lo
- st.ss_size = s.hi - s.lo
- st.ss_flags = 0
- }
- sigaltstack(&st, nil)
+func setSignalstackSP(s *stackt, sp uintptr) {
+ s.ss_sp = sp
}
//go:nosplit
//go:nowritebarrierrec
-func updatesigmask(m sigmask) {
- sigprocmask(_SIG_SETMASK, sigset(m[0]))
+func sigaddset(mask *sigset, i int) {
+ *mask |= 1 << (uint32(i) - 1)
+}
+
+func sigdelset(mask *sigset, i int) {
+ *mask &^= 1 << (uint32(i) - 1)
}
-func unblocksig(sig int32) {
- mask := sigset(1) << (uint32(sig) - 1)
- sigprocmask(_SIG_UNBLOCK, mask)
+func (c *sigctxt) fixsigcode(sig uint32) {
}
diff --git a/src/runtime/os_openbsd_arm.go b/src/runtime/os_openbsd_arm.go
index b46fef0..be2e1e9 100644
--- a/src/runtime/os_openbsd_arm.go
+++ b/src/runtime/os_openbsd_arm.go
@@ -17,8 +17,8 @@ func checkgoarm() {
//go:nosplit
func cputicks() int64 {
- // Currently cputicks() is used in blocking profiler and to seed runtime·fastrand1().
+ // Currently cputicks() is used in blocking profiler and to seed runtime·fastrand().
// runtime·nanotime() is a poor approximation of CPU ticks that is enough for the profiler.
- // TODO: need more entropy to better seed fastrand1.
+ // TODO: need more entropy to better seed fastrand.
return nanotime()
}
diff --git a/src/runtime/os_plan9.go b/src/runtime/os_plan9.go
index 2f3a0d1..ba2d5c5 100644
--- a/src/runtime/os_plan9.go
+++ b/src/runtime/os_plan9.go
@@ -13,6 +13,7 @@ type mOS struct {
waitsemacount uint32
notesig *int8
errstr *byte
+ ignoreHangup bool
}
func closefd(fd int32) int32
@@ -56,7 +57,7 @@ func noted(mode int32) int32
func nsec(*int64) int64
//go:noescape
-func sigtramp(ureg, msg unsafe.Pointer)
+func sigtramp(ureg, note unsafe.Pointer)
func setfpmasks()
@@ -217,6 +218,55 @@ func getproccount() int32 {
return ncpu
}
+var devswap = []byte("/dev/swap\x00")
+var pagesize = []byte(" pagesize\n")
+
+func getPageSize() uintptr {
+ var buf [2048]byte
+ var pos int
+ fd := open(&devswap[0], _OREAD, 0)
+ if fd < 0 {
+ // There's not much we can do if /dev/swap doesn't
+ // exist. However, nothing in the memory manager uses
+ // this on Plan 9, so it also doesn't really matter.
+ return minPhysPageSize
+ }
+ for pos < len(buf) {
+ n := read(fd, unsafe.Pointer(&buf[pos]), int32(len(buf)-pos))
+ if n <= 0 {
+ break
+ }
+ pos += int(n)
+ }
+ closefd(fd)
+ text := buf[:pos]
+ // Find "<n> pagesize" line.
+ bol := 0
+ for i, c := range text {
+ if c == '\n' {
+ bol = i + 1
+ }
+ if bytesHasPrefix(text[i:], pagesize) {
+ // Parse number at the beginning of this line.
+ return uintptr(_atoi(text[bol:]))
+ }
+ }
+ // Again, the page size doesn't really matter, so use a fallback.
+ return minPhysPageSize
+}
+
+func bytesHasPrefix(s, prefix []byte) bool {
+ if len(s) < len(prefix) {
+ return false
+ }
+ for i, p := range prefix {
+ if s[i] != p {
+ return false
+ }
+ }
+ return true
+}
+
var pid = []byte("#c/pid\x00")
func getpid() uint64 {
@@ -236,6 +286,7 @@ func getpid() uint64 {
func osinit() {
initBloc()
ncpu = getproccount()
+ physPageSize = getPageSize()
getg().m.procid = getpid()
notify(unsafe.Pointer(funcPC(sigtramp)))
}
@@ -417,7 +468,7 @@ func badsignal2() {
exits(&_badsignal[0])
}
-func raisebadsignal(sig int32) {
+func raisebadsignal(sig uint32) {
badsignal2()
}
diff --git a/src/runtime/os_plan9_arm.go b/src/runtime/os_plan9_arm.go
index 30cde8f..fdce1e7 100644
--- a/src/runtime/os_plan9_arm.go
+++ b/src/runtime/os_plan9_arm.go
@@ -10,8 +10,8 @@ func checkgoarm() {
//go:nosplit
func cputicks() int64 {
- // Currently cputicks() is used in blocking profiler and to seed runtime·fastrand1().
+ // Currently cputicks() is used in blocking profiler and to seed runtime·fastrand().
// runtime·nanotime() is a poor approximation of CPU ticks that is enough for the profiler.
- // TODO: need more entropy to better seed fastrand1.
+ // TODO: need more entropy to better seed fastrand.
return nanotime()
}
diff --git a/src/runtime/os_windows.go b/src/runtime/os_windows.go
index 9147091..0db57f8 100644
--- a/src/runtime/os_windows.go
+++ b/src/runtime/os_windows.go
@@ -20,9 +20,6 @@ const (
//go:cgo_import_dynamic runtime._CreateIoCompletionPort CreateIoCompletionPort%4 "kernel32.dll"
//go:cgo_import_dynamic runtime._CreateThread CreateThread%6 "kernel32.dll"
//go:cgo_import_dynamic runtime._CreateWaitableTimerA CreateWaitableTimerA%3 "kernel32.dll"
-//go:cgo_import_dynamic runtime._CryptAcquireContextW CryptAcquireContextW%5 "advapi32.dll"
-//go:cgo_import_dynamic runtime._CryptGenRandom CryptGenRandom%3 "advapi32.dll"
-//go:cgo_import_dynamic runtime._CryptReleaseContext CryptReleaseContext%2 "advapi32.dll"
//go:cgo_import_dynamic runtime._DuplicateHandle DuplicateHandle%7 "kernel32.dll"
//go:cgo_import_dynamic runtime._ExitProcess ExitProcess%1 "kernel32.dll"
//go:cgo_import_dynamic runtime._FreeEnvironmentStringsW FreeEnvironmentStringsW%1 "kernel32.dll"
@@ -36,7 +33,6 @@ const (
//go:cgo_import_dynamic runtime._GetThreadContext GetThreadContext%2 "kernel32.dll"
//go:cgo_import_dynamic runtime._LoadLibraryW LoadLibraryW%1 "kernel32.dll"
//go:cgo_import_dynamic runtime._LoadLibraryA LoadLibraryA%1 "kernel32.dll"
-//go:cgo_import_dynamic runtime._NtWaitForSingleObject NtWaitForSingleObject%3 "ntdll.dll"
//go:cgo_import_dynamic runtime._ResumeThread ResumeThread%1 "kernel32.dll"
//go:cgo_import_dynamic runtime._SetConsoleCtrlHandler SetConsoleCtrlHandler%2 "kernel32.dll"
//go:cgo_import_dynamic runtime._SetErrorMode SetErrorMode%1 "kernel32.dll"
@@ -67,9 +63,6 @@ var (
_CreateIoCompletionPort,
_CreateThread,
_CreateWaitableTimerA,
- _CryptAcquireContextW,
- _CryptGenRandom,
- _CryptReleaseContext,
_DuplicateHandle,
_ExitProcess,
_FreeEnvironmentStringsW,
@@ -83,7 +76,6 @@ var (
_GetThreadContext,
_LoadLibraryW,
_LoadLibraryA,
- _NtWaitForSingleObject,
_ResumeThread,
_SetConsoleCtrlHandler,
_SetErrorMode,
@@ -110,6 +102,21 @@ var (
_GetQueuedCompletionStatusEx,
_LoadLibraryExW,
_ stdFunction
+
+ // Use RtlGenRandom to generate cryptographically random data.
+ // This approach has been recommended by Microsoft (see issue
+ // 15589 for details).
+ // The RtlGenRandom is not listed in advapi32.dll, instead
+ // RtlGenRandom function can be found by searching for SystemFunction036.
+ // Also some versions of Mingw cannot link to SystemFunction036
+ // when building executable as Cgo. So load SystemFunction036
+ // manually during runtime startup.
+ _RtlGenRandom stdFunction
+
+ // Load ntdll.dll manually during startup, otherwise Mingw
+ // links wrong printf function to cgo executable (see issue
+ // 12030 for details).
+ _NtWaitForSingleObject stdFunction
)
// Function to be called by windows CreateThread
@@ -167,6 +174,20 @@ func loadOptionalSyscalls() {
_AddVectoredContinueHandler = windowsFindfunc(k32, []byte("AddVectoredContinueHandler\000"))
_GetQueuedCompletionStatusEx = windowsFindfunc(k32, []byte("GetQueuedCompletionStatusEx\000"))
_LoadLibraryExW = windowsFindfunc(k32, []byte("LoadLibraryExW\000"))
+
+ var advapi32dll = []byte("advapi32.dll\000")
+ a32 := stdcall1(_LoadLibraryA, uintptr(unsafe.Pointer(&advapi32dll[0])))
+ if a32 == 0 {
+ throw("advapi32.dll not found")
+ }
+ _RtlGenRandom = windowsFindfunc(a32, []byte("SystemFunction036\000"))
+
+ var ntdll = []byte("ntdll.dll\000")
+ n32 := stdcall1(_LoadLibraryA, uintptr(unsafe.Pointer(&ntdll[0])))
+ if n32 == 0 {
+ throw("ntdll.dll not found")
+ }
+ _NtWaitForSingleObject = windowsFindfunc(n32, []byte("NtWaitForSingleObject\000"))
}
//go:nosplit
@@ -205,6 +226,12 @@ func getproccount() int32 {
return int32(info.dwnumberofprocessors)
}
+func getPageSize() uintptr {
+ var info systeminfo
+ stdcall1(_GetSystemInfo, uintptr(unsafe.Pointer(&info)))
+ return uintptr(info.dwpagesize)
+}
+
const (
currentProcess = ^uintptr(0) // -1 = current process
currentThread = ^uintptr(1) // -2 = current thread
@@ -256,6 +283,8 @@ func osinit() {
ncpu = getproccount()
+ physPageSize = getPageSize()
+
// Windows dynamic priority boosting assumes that a process has different types
// of dedicated threads -- GUI, IO, computational, etc. Go processes use
// equivalent threads that all do a mix of GUI, IO, computations, etc.
@@ -265,17 +294,9 @@ func osinit() {
//go:nosplit
func getRandomData(r []byte) {
- const (
- prov_rsa_full = 1
- crypt_verifycontext = 0xF0000000
- )
- var handle uintptr
n := 0
- if stdcall5(_CryptAcquireContextW, uintptr(unsafe.Pointer(&handle)), 0, 0, prov_rsa_full, crypt_verifycontext) != 0 {
- if stdcall3(_CryptGenRandom, handle, uintptr(len(r)), uintptr(unsafe.Pointer(&r[0]))) != 0 {
- n = len(r)
- }
- stdcall2(_CryptReleaseContext, handle, 0)
+ if stdcall2(_RtlGenRandom, uintptr(unsafe.Pointer(&r[0])), uintptr(len(r)))&0xff != 0 {
+ n = len(r)
}
extendRandom(r, n)
}
@@ -375,13 +396,11 @@ func writeConsole(handle uintptr, buf unsafe.Pointer, bufLen int32) int {
total := len(s)
w := 0
- for len(s) > 0 {
+ for _, r := range s {
if w >= len(utf16tmp)-2 {
writeConsoleUTF16(handle, utf16tmp[:w])
w = 0
}
- r, n := charntorune(s)
- s = s[n:]
if r < 0x10000 {
utf16tmp[w] = uint16(r)
w++
@@ -418,6 +437,13 @@ func writeConsoleUTF16(handle uintptr, b []uint16) {
//go:nosplit
func semasleep(ns int64) int32 {
+ const (
+ _WAIT_ABANDONED = 0x00000080
+ _WAIT_OBJECT_0 = 0x00000000
+ _WAIT_TIMEOUT = 0x00000102
+ _WAIT_FAILED = 0xFFFFFFFF
+ )
+
// store ms in ns to save stack space
if ns < 0 {
ns = _INFINITE
@@ -427,15 +453,44 @@ func semasleep(ns int64) int32 {
ns = 1
}
}
- if stdcall2(_WaitForSingleObject, getg().m.waitsema, uintptr(ns)) != 0 {
- return -1 // timeout
+
+ result := stdcall2(_WaitForSingleObject, getg().m.waitsema, uintptr(ns))
+ switch result {
+ case _WAIT_OBJECT_0: //signaled
+ return 0
+
+ case _WAIT_TIMEOUT:
+ return -1
+
+ case _WAIT_ABANDONED:
+ systemstack(func() {
+ throw("runtime.semasleep wait_abandoned")
+ })
+
+ case _WAIT_FAILED:
+ systemstack(func() {
+ print("runtime: waitforsingleobject wait_failed; errno=", getlasterror(), "\n")
+ throw("runtime.semasleep wait_failed")
+ })
+
+ default:
+ systemstack(func() {
+ print("runtime: waitforsingleobject unexpected; result=", result, "\n")
+ throw("runtime.semasleep unexpected")
+ })
}
- return 0
+
+ return -1 // unreachable
}
//go:nosplit
func semawakeup(mp *m) {
- stdcall1(_SetEvent, mp.waitsema)
+ if stdcall1(_SetEvent, mp.waitsema) == 0 {
+ systemstack(func() {
+ print("runtime: setevent failed; errno=", getlasterror(), "\n")
+ throw("runtime.semawakeup")
+ })
+ }
}
//go:nosplit
@@ -444,6 +499,12 @@ func semacreate(mp *m) {
return
}
mp.waitsema = stdcall4(_CreateEventA, 0, 0, 0, 0)
+ if mp.waitsema == 0 {
+ systemstack(func() {
+ print("runtime: createevent failed; errno=", getlasterror(), "\n")
+ throw("runtime.semacreate")
+ })
+ }
}
// May run with m.p==nil, so write barriers are not allowed. This
@@ -456,6 +517,7 @@ func newosproc(mp *m, stk unsafe.Pointer) {
thandle := stdcall6(_CreateThread, 0, 0x20000,
funcPC(tstart_stdcall), uintptr(unsafe.Pointer(mp)),
_STACK_SIZE_PARAM_IS_A_RESERVATION, 0)
+
if thandle == 0 {
print("runtime: failed to create new OS thread (have ", mcount(), " already; errno=", getlasterror(), ")\n")
throw("runtime.newosproc")
diff --git a/src/runtime/panic.go b/src/runtime/panic.go
index 60b277d..7392436 100644
--- a/src/runtime/panic.go
+++ b/src/runtime/panic.go
@@ -6,6 +6,7 @@ package runtime
import (
"runtime/internal/atomic"
+ "runtime/internal/sys"
"unsafe"
)
@@ -62,10 +63,6 @@ func panicmem() {
panic(memoryError)
}
-func throwreturn() {
- throw("no return at end of a typed function - compiler is broken")
-}
-
func throwinit() {
throw("recursive call during initialization - linker skew")
}
@@ -88,16 +85,21 @@ func deferproc(siz int32, fn *funcval) { // arguments of fn follow fn
argp := uintptr(unsafe.Pointer(&fn)) + unsafe.Sizeof(fn)
callerpc := getcallerpc(unsafe.Pointer(&siz))
- systemstack(func() {
- d := newdefer(siz)
- if d._panic != nil {
- throw("deferproc: d.panic != nil after newdefer")
- }
- d.fn = fn
- d.pc = callerpc
- d.sp = sp
- memmove(add(unsafe.Pointer(d), unsafe.Sizeof(*d)), unsafe.Pointer(argp), uintptr(siz))
- })
+ d := newdefer(siz)
+ if d._panic != nil {
+ throw("deferproc: d.panic != nil after newdefer")
+ }
+ d.fn = fn
+ d.pc = callerpc
+ d.sp = sp
+ switch siz {
+ case 0:
+ // Do nothing.
+ case sys.PtrSize:
+ *(*uintptr)(deferArgs(d)) = *(*uintptr)(unsafe.Pointer(argp))
+ default:
+ memmove(deferArgs(d), unsafe.Pointer(argp), uintptr(siz))
+ }
// deferproc returns 0 normally.
// a deferred func that stops a panic
@@ -166,6 +168,10 @@ func testdefersizes() {
// immediately after the _defer header in memory.
//go:nosplit
func deferArgs(d *_defer) unsafe.Pointer {
+ if d.siz == 0 {
+ // Avoid pointer past the defer allocation.
+ return nil
+ }
return add(unsafe.Pointer(d), unsafe.Sizeof(*d))
}
@@ -179,22 +185,30 @@ func init() {
// Allocate a Defer, usually using per-P pool.
// Each defer must be released with freedefer.
-// Note: runs on g0 stack
+//
+// This must not grow the stack because there may be a frame without
+// stack map information when this is called.
+//
+//go:nosplit
func newdefer(siz int32) *_defer {
var d *_defer
sc := deferclass(uintptr(siz))
- mp := acquirem()
+ gp := getg()
if sc < uintptr(len(p{}.deferpool)) {
- pp := mp.p.ptr()
+ pp := gp.m.p.ptr()
if len(pp.deferpool[sc]) == 0 && sched.deferpool[sc] != nil {
- lock(&sched.deferlock)
- for len(pp.deferpool[sc]) < cap(pp.deferpool[sc])/2 && sched.deferpool[sc] != nil {
- d := sched.deferpool[sc]
- sched.deferpool[sc] = d.link
- d.link = nil
- pp.deferpool[sc] = append(pp.deferpool[sc], d)
- }
- unlock(&sched.deferlock)
+ // Take the slow path on the system stack so
+ // we don't grow newdefer's stack.
+ systemstack(func() {
+ lock(&sched.deferlock)
+ for len(pp.deferpool[sc]) < cap(pp.deferpool[sc])/2 && sched.deferpool[sc] != nil {
+ d := sched.deferpool[sc]
+ sched.deferpool[sc] = d.link
+ d.link = nil
+ pp.deferpool[sc] = append(pp.deferpool[sc], d)
+ }
+ unlock(&sched.deferlock)
+ })
}
if n := len(pp.deferpool[sc]); n > 0 {
d = pp.deferpool[sc][n-1]
@@ -204,19 +218,24 @@ func newdefer(siz int32) *_defer {
}
if d == nil {
// Allocate new defer+args.
- total := roundupsize(totaldefersize(uintptr(siz)))
- d = (*_defer)(mallocgc(total, deferType, true))
+ systemstack(func() {
+ total := roundupsize(totaldefersize(uintptr(siz)))
+ d = (*_defer)(mallocgc(total, deferType, true))
+ })
}
d.siz = siz
- gp := mp.curg
d.link = gp._defer
gp._defer = d
- releasem(mp)
return d
}
// Free the given defer.
// The defer cannot be used after this call.
+//
+// This must not grow the stack because there may be a frame without a
+// stack map when this is called.
+//
+//go:nosplit
func freedefer(d *_defer) {
if d._panic != nil {
freedeferpanic()
@@ -226,31 +245,34 @@ func freedefer(d *_defer) {
}
sc := deferclass(uintptr(d.siz))
if sc < uintptr(len(p{}.deferpool)) {
- mp := acquirem()
- pp := mp.p.ptr()
+ pp := getg().m.p.ptr()
if len(pp.deferpool[sc]) == cap(pp.deferpool[sc]) {
// Transfer half of local cache to the central cache.
- var first, last *_defer
- for len(pp.deferpool[sc]) > cap(pp.deferpool[sc])/2 {
- n := len(pp.deferpool[sc])
- d := pp.deferpool[sc][n-1]
- pp.deferpool[sc][n-1] = nil
- pp.deferpool[sc] = pp.deferpool[sc][:n-1]
- if first == nil {
- first = d
- } else {
- last.link = d
+ //
+ // Take this slow path on the system stack so
+ // we don't grow freedefer's stack.
+ systemstack(func() {
+ var first, last *_defer
+ for len(pp.deferpool[sc]) > cap(pp.deferpool[sc])/2 {
+ n := len(pp.deferpool[sc])
+ d := pp.deferpool[sc][n-1]
+ pp.deferpool[sc][n-1] = nil
+ pp.deferpool[sc] = pp.deferpool[sc][:n-1]
+ if first == nil {
+ first = d
+ } else {
+ last.link = d
+ }
+ last = d
}
- last = d
- }
- lock(&sched.deferlock)
- last.link = sched.deferpool[sc]
- sched.deferpool[sc] = first
- unlock(&sched.deferlock)
+ lock(&sched.deferlock)
+ last.link = sched.deferpool[sc]
+ sched.deferpool[sc] = first
+ unlock(&sched.deferlock)
+ })
}
*d = _defer{}
pp.deferpool[sc] = append(pp.deferpool[sc], d)
- releasem(mp)
}
}
@@ -292,19 +314,23 @@ func deferreturn(arg0 uintptr) {
}
// Moving arguments around.
- // Do not allow preemption here, because the garbage collector
- // won't know the form of the arguments until the jmpdefer can
- // flip the PC over to fn.
- mp := acquirem()
- memmove(unsafe.Pointer(&arg0), deferArgs(d), uintptr(d.siz))
+ //
+ // Everything called after this point must be recursively
+ // nosplit because the garbage collector won't know the form
+ // of the arguments until the jmpdefer can flip the PC over to
+ // fn.
+ switch d.siz {
+ case 0:
+ // Do nothing.
+ case sys.PtrSize:
+ *(*uintptr)(unsafe.Pointer(&arg0)) = *(*uintptr)(deferArgs(d))
+ default:
+ memmove(unsafe.Pointer(&arg0), deferArgs(d), uintptr(d.siz))
+ }
fn := d.fn
d.fn = nil
gp._defer = d.link
- // Switch to systemstack merely to save nosplit stack space.
- systemstack(func() {
- freedefer(d)
- })
- releasem(mp)
+ freedefer(d)
jmpdefer(fn, uintptr(unsafe.Pointer(&arg0)))
}
@@ -354,6 +380,11 @@ func Goexit() {
// Used when crashing with panicking.
// This must match types handled by printany.
func preprintpanics(p *_panic) {
+ defer func() {
+ if recover() != nil {
+ throw("panic while printing panic value")
+ }
+ }()
for p != nil {
switch v := p.arg.(type) {
case error:
@@ -504,15 +535,9 @@ func gopanic(e interface{}) {
// getargp returns the location where the caller
// writes outgoing function call arguments.
//go:nosplit
+//go:noinline
func getargp(x int) uintptr {
// x is an argument mainly so that we can return its address.
- // However, we need to make the function complex enough
- // that it won't be inlined. We always pass x = 0, so this code
- // does nothing other than keep the compiler from thinking
- // the function is simple enough to inline.
- if x > 0 {
- return getcallersp(unsafe.Pointer(&x)) * 0
- }
return uintptr(noescape(unsafe.Pointer(&x)))
}
@@ -555,6 +580,11 @@ func dopanic(unused int) {
*(*int)(nil) = 0
}
+//go:linkname sync_throw sync.throw
+func sync_throw(s string) {
+ throw(s)
+}
+
//go:nosplit
func throw(s string) {
print("fatal error: ", s, "\n")
diff --git a/src/runtime/plugin.go b/src/runtime/plugin.go
new file mode 100644
index 0000000..845bf76
--- /dev/null
+++ b/src/runtime/plugin.go
@@ -0,0 +1,96 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runtime
+
+import "unsafe"
+
+//go:linkname plugin_lastmoduleinit plugin.lastmoduleinit
+func plugin_lastmoduleinit() (path string, syms map[string]interface{}, mismatchpkg string) {
+ md := firstmoduledata.next
+ if md == nil {
+ throw("runtime: no plugin module data")
+ }
+ for md.next != nil {
+ md = md.next
+ }
+ if md.typemap != nil {
+ throw("runtime: plugin already initialized")
+ }
+
+ for _, pmd := range activeModules() {
+ if pmd.pluginpath == md.pluginpath {
+ println("plugin: plugin", md.pluginpath, "already loaded")
+ throw("plugin: plugin already loaded")
+ }
+
+ if inRange(pmd.text, pmd.etext, md.text, md.etext) ||
+ inRange(pmd.bss, pmd.ebss, md.bss, md.ebss) ||
+ inRange(pmd.data, pmd.edata, md.data, md.edata) ||
+ inRange(pmd.types, pmd.etypes, md.types, md.etypes) {
+ println("plugin: new module data overlaps with previous moduledata")
+ println("\tpmd.text-etext=", hex(pmd.text), "-", hex(pmd.etext))
+ println("\tpmd.bss-ebss=", hex(pmd.bss), "-", hex(pmd.ebss))
+ println("\tpmd.data-edata=", hex(pmd.data), "-", hex(pmd.edata))
+ println("\tpmd.types-etypes=", hex(pmd.types), "-", hex(pmd.etypes))
+ println("\tmd.text-etext=", hex(md.text), "-", hex(md.etext))
+ println("\tmd.bss-ebss=", hex(md.bss), "-", hex(md.ebss))
+ println("\tmd.data-edata=", hex(md.data), "-", hex(md.edata))
+ println("\tmd.types-etypes=", hex(md.types), "-", hex(md.etypes))
+ throw("plugin: new module data overlaps with previous moduledata")
+ }
+ }
+ for _, pkghash := range md.pkghashes {
+ if pkghash.linktimehash != *pkghash.runtimehash {
+ return "", nil, pkghash.modulename
+ }
+ }
+
+ // Initialize the freshly loaded module.
+ modulesinit()
+ typelinksinit()
+
+ lock(&ifaceLock)
+ for _, i := range md.itablinks {
+ additab(i, true, false)
+ }
+ unlock(&ifaceLock)
+
+ // Build a map of symbol names to symbols. Here in the runtime
+ // we fill out the first word of the interface, the type. We
+ // pass these zero value interfaces to the plugin package,
+ // where the symbol value is filled in (usually via cgo).
+ //
+ // Because functions are handled specially in the plugin package,
+ // function symbol names are prefixed here with '.' to avoid
+ // a dependency on the reflect package.
+ syms = make(map[string]interface{}, len(md.ptab))
+ for _, ptab := range md.ptab {
+ symName := resolveNameOff(unsafe.Pointer(md.types), ptab.name)
+ t := (*_type)(unsafe.Pointer(md.types)).typeOff(ptab.typ)
+ var val interface{}
+ valp := (*[2]unsafe.Pointer)(unsafe.Pointer(&val))
+ (*valp)[0] = unsafe.Pointer(t)
+
+ name := symName.name()
+ if t.kind&kindMask == kindFunc {
+ name = "." + name
+ }
+ syms[name] = val
+ }
+ return md.pluginpath, syms, ""
+}
+
+// inRange reports whether v0 or v1 are in the range [r0, r1].
+func inRange(r0, r1, v0, v1 uintptr) bool {
+ return (v0 >= r0 && v0 <= r1) || (v1 >= r0 && v1 <= r1)
+}
+
+// A ptabEntry is generated by the compiler for each exported function
+// and global variable in the main package of a plugin. It is used to
+// initialize the plugin module's symbol map.
+type ptabEntry struct {
+ name nameOff
+ typ typeOff
+}
diff --git a/src/runtime/pprof/internal/protopprof/protomemprofile.go b/src/runtime/pprof/internal/protopprof/protomemprofile.go
new file mode 100644
index 0000000..c2ab5b5
--- /dev/null
+++ b/src/runtime/pprof/internal/protopprof/protomemprofile.go
@@ -0,0 +1,83 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package 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
new file mode 100644
index 0000000..a10fe77
--- /dev/null
+++ b/src/runtime/pprof/internal/protopprof/protomemprofile_test.go
@@ -0,0 +1,104 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+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
new file mode 100644
index 0000000..5d269c4
--- /dev/null
+++ b/src/runtime/pprof/internal/protopprof/protopprof.go
@@ -0,0 +1,105 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// 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
new file mode 100644
index 0000000..f1937b5
--- /dev/null
+++ b/src/runtime/pprof/internal/protopprof/protopprof_test.go
@@ -0,0 +1,171 @@
+// Copyright 2016 The Go Authors. 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/mprof_test.go b/src/runtime/pprof/mprof_test.go
index 0fff9d4..df4f6f8 100644
--- a/src/runtime/pprof/mprof_test.go
+++ b/src/runtime/pprof/mprof_test.go
@@ -7,6 +7,7 @@ package pprof_test
import (
"bytes"
"fmt"
+ "reflect"
"regexp"
"runtime"
. "runtime/pprof"
@@ -42,6 +43,17 @@ func allocatePersistent1K() {
}
}
+// Allocate transient memory using reflect.Call.
+
+func allocateReflectTransient() {
+ memSink = make([]byte, 2<<20)
+}
+
+func allocateReflect() {
+ rv := reflect.ValueOf(allocateReflectTransient)
+ rv.Call(nil)
+}
+
var memoryProfilerRun = 0
func TestMemoryProfiler(t *testing.T) {
@@ -61,6 +73,7 @@ func TestMemoryProfiler(t *testing.T) {
allocateTransient1M()
allocateTransient2M()
allocatePersistent1K()
+ allocateReflect()
memSink = nil
runtime.GC() // materialize stats
@@ -73,18 +86,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:40
-# 0x[0-9,a-f]+ runtime/pprof_test\.TestMemoryProfiler\+0x[0-9,a-f]+ .*/runtime/pprof/mprof_test\.go:63
+# 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
`, 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:21
-# 0x[0-9,a-f]+ runtime/pprof_test\.TestMemoryProfiler\+0x[0-9,a-f]+ .*/runtime/pprof/mprof_test.go:61
+# 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
`, (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:27
-# 0x[0-9,a-f]+ runtime/pprof_test\.TestMemoryProfiler\+0x[0-9,a-f]+ .*/runtime/pprof/mprof_test.go:62
+# 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
+`, 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
`, memoryProfilerRun, (2<<20)*memoryProfilerRun),
}
diff --git a/src/runtime/pprof/pprof.go b/src/runtime/pprof/pprof.go
index 25f7ed6..aed5b8d 100644
--- a/src/runtime/pprof/pprof.go
+++ b/src/runtime/pprof/pprof.go
@@ -73,13 +73,15 @@ import (
"bufio"
"bytes"
"fmt"
+ "internal/pprof/profile"
"io"
- "os"
"runtime"
+ "runtime/pprof/internal/protopprof"
"sort"
"strings"
"sync"
"text/tabwriter"
+ "time"
)
// BUG(rsc): Profiles are only as good as the kernel support used to generate them.
@@ -99,6 +101,7 @@ import (
// heap - a sampling of all heap allocations
// threadcreate - stack traces that led to the creation of new OS threads
// block - stack traces that led to blocking on synchronization primitives
+// mutex - stack traces of holders of contended mutexes
//
// These predefined profiles maintain themselves and panic on an explicit
// Add or Remove method call.
@@ -152,6 +155,12 @@ var blockProfile = &Profile{
write: writeBlock,
}
+var mutexProfile = &Profile{
+ name: "mutex",
+ count: countMutex,
+ write: writeMutex,
+}
+
func lockProfiles() {
profiles.mu.Lock()
if profiles.m == nil {
@@ -161,6 +170,7 @@ func lockProfiles() {
"threadcreate": threadcreateProfile,
"heap": heapProfile,
"block": blockProfile,
+ "mutex": mutexProfile,
}
}
}
@@ -202,21 +212,15 @@ func Profiles() []*Profile {
lockProfiles()
defer unlockProfiles()
- var all []*Profile
+ all := make([]*Profile, 0, len(profiles.m))
for _, p := range profiles.m {
all = append(all, p)
}
- sort.Sort(byName(all))
+ sort.Slice(all, func(i, j int) bool { return all[i].name < all[j].name })
return all
}
-type byName []*Profile
-
-func (x byName) Len() int { return len(x) }
-func (x byName) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
-func (x byName) Less(i, j int) bool { return x[i].name < x[j].name }
-
// Name returns this profile's name, which can be passed to Lookup to reobtain the profile.
func (p *Profile) Name() string {
return p.name
@@ -299,7 +303,7 @@ func (p *Profile) WriteTo(w io.Writer, debug int) error {
}
// Obtain consistent snapshot under lock; then process without lock.
- var all [][]uintptr
+ all := make([][]uintptr, 0, len(p.m))
p.mu.Lock()
for _, stk := range p.m {
all = append(all, stk)
@@ -337,17 +341,8 @@ type countProfile interface {
}
// printCountProfile prints a countProfile at the specified debug level.
+// The profile will be in compressed proto format unless debug is nonzero.
func printCountProfile(w io.Writer, debug int, name string, p countProfile) error {
- b := bufio.NewWriter(w)
- var tw *tabwriter.Writer
- w = b
- if debug > 0 {
- tw = tabwriter.NewWriter(w, 1, 8, 1, '\t', 0)
- w = tw
- }
-
- fmt.Fprintf(w, "%s profile: total %d\n", name, p.Len())
-
// Build count of each stack.
var buf bytes.Buffer
key := func(stk []uintptr) string {
@@ -373,17 +368,37 @@ func printCountProfile(w io.Writer, debug int, name string, p countProfile) erro
sort.Sort(&keysByCount{keys, count})
- for _, k := range keys {
- fmt.Fprintf(w, "%d %s\n", count[k], k)
- if debug > 0 {
- printStackRecord(w, p.Stack(index[k]), false)
+ if debug > 0 {
+ // Print debug profile in legacy format
+ tw := tabwriter.NewWriter(w, 1, 8, 1, '\t', 0)
+ fmt.Fprintf(tw, "%s profile: total %d\n", name, p.Len())
+ for _, k := range keys {
+ fmt.Fprintf(tw, "%d %s\n", count[k], k)
+ printStackRecord(tw, p.Stack(index[k]), false)
}
+ return tw.Flush()
}
- if tw != nil {
- tw.Flush()
+ // 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"}},
}
- return b.Flush()
+ for _, k := range keys {
+ stk := p.Stack(index[k])
+ c := count[k]
+ locs := make([]*profile.Location, len(stk))
+ for i, addr := range stk {
+ locs[i] = &profile.Location{Address: uint64(addr) - 1}
+ }
+ prof.Sample = append(prof.Sample, &profile.Sample{
+ Location: locs,
+ Value: []int64{int64(c)},
+ })
+ }
+ return prof.Write(w)
}
// keysByCount sorts keys with higher counts first, breaking ties by key string order.
@@ -435,12 +450,6 @@ func printStackRecord(w io.Writer, stk []uintptr, allFrames bool) {
// Interface to system profiles.
-type byInUseBytes []runtime.MemProfileRecord
-
-func (x byInUseBytes) Len() int { return len(x) }
-func (x byInUseBytes) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
-func (x byInUseBytes) Less(i, j int) bool { return x[i].InUseBytes() > x[j].InUseBytes() }
-
// WriteHeapProfile is shorthand for Lookup("heap").WriteTo(w, 0).
// It is preserved for backwards compatibility.
func WriteHeapProfile(w io.Writer) error {
@@ -476,15 +485,16 @@ func writeHeap(w io.Writer, debug int) error {
// Profile grew; try again.
}
- sort.Sort(byInUseBytes(p))
+ if debug == 0 {
+ pp := protopprof.EncodeMemProfile(p, int64(runtime.MemProfileRate), time.Now())
+ return pp.Write(w)
+ }
+
+ sort.Slice(p, func(i, j int) bool { return p[i].InUseBytes() > p[j].InUseBytes() })
b := bufio.NewWriter(w)
- var tw *tabwriter.Writer
- w = b
- if debug > 0 {
- tw = tabwriter.NewWriter(w, 1, 8, 1, '\t', 0)
- w = tw
- }
+ tw := tabwriter.NewWriter(b, 1, 8, 1, '\t', 0)
+ w = tw
var total runtime.MemProfileRecord
for i := range p {
@@ -512,9 +522,7 @@ func writeHeap(w io.Writer, debug int) error {
fmt.Fprintf(w, " %#x", pc)
}
fmt.Fprintf(w, "\n")
- if debug > 0 {
- printStackRecord(w, r.Stack(), false)
- }
+ printStackRecord(w, r.Stack(), false)
}
// Print memstats information too.
@@ -540,15 +548,15 @@ func writeHeap(w io.Writer, debug int) error {
fmt.Fprintf(w, "# MSpan = %d / %d\n", s.MSpanInuse, s.MSpanSys)
fmt.Fprintf(w, "# MCache = %d / %d\n", s.MCacheInuse, s.MCacheSys)
fmt.Fprintf(w, "# BuckHashSys = %d\n", s.BuckHashSys)
+ fmt.Fprintf(w, "# GCSys = %d\n", s.GCSys)
+ fmt.Fprintf(w, "# OtherSys = %d\n", s.OtherSys)
fmt.Fprintf(w, "# NextGC = %d\n", s.NextGC)
fmt.Fprintf(w, "# PauseNs = %d\n", s.PauseNs)
fmt.Fprintf(w, "# NumGC = %d\n", s.NumGC)
fmt.Fprintf(w, "# DebugGC = %v\n", s.DebugGC)
- if tw != nil {
- tw.Flush()
- }
+ tw.Flush()
return b.Flush()
}
@@ -672,49 +680,29 @@ func StartCPUProfile(w io.Writer) error {
}
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
for {
data := runtime.CPUProfile()
if data == nil {
break
}
- w.Write(data)
- }
-
- // We are emitting the legacy profiling format, which permits
- // a memory map following the CPU samples. The memory map is
- // simply a copy of the GNU/Linux /proc/self/maps file. The
- // profiler uses the memory map to map PC values in shared
- // libraries to a shared library in the filesystem, in order
- // to report the correct function and, if the shared library
- // has debug info, file/line. This is particularly useful for
- // PIE (position independent executables) as on ELF systems a
- // PIE is simply an executable shared library.
- //
- // Because the profiling format expects the memory map in
- // GNU/Linux format, we only do this on GNU/Linux for now. To
- // add support for profiling PIE on other ELF-based systems,
- // it may be necessary to map the system-specific mapping
- // information to the GNU/Linux format. For a reasonably
- // portable C++ version, see the FillProcSelfMaps function in
- // https://github.com/gperftools/gperftools/blob/master/src/base/sysinfo.cc
- //
- // The code that parses this mapping for the pprof tool is
- // ParseMemoryMap in cmd/internal/pprof/legacy_profile.go, but
- // don't change that code, as similar code exists in other
- // (non-Go) pprof readers. Change this code so that that code works.
- //
- // We ignore errors reading or copying the memory map; the
- // profile is likely usable without it, and we have no good way
- // to report errors.
- if runtime.GOOS == "linux" {
- f, err := os.Open("/proc/self/maps")
- if err == nil {
- io.WriteString(w, "\nMAPPED_LIBRARIES:\n")
- io.Copy(w, f)
- f.Close()
- }
+ 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))
+ }
+
+ profile.Write(w)
cpu.done <- true
}
@@ -733,18 +721,18 @@ func StopCPUProfile() {
<-cpu.done
}
-type byCycles []runtime.BlockProfileRecord
-
-func (x byCycles) Len() int { return len(x) }
-func (x byCycles) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
-func (x byCycles) Less(i, j int) bool { return x[i].Cycles > x[j].Cycles }
-
// countBlock returns the number of records in the blocking profile.
func countBlock() int {
n, _ := runtime.BlockProfile(nil)
return n
}
+// countMutex returns the number of records in the mutex profile.
+func countMutex() int {
+ n, _ := runtime.MutexProfile(nil)
+ return n
+}
+
// writeBlock writes the current blocking profile to w.
func writeBlock(w io.Writer, debug int) error {
var p []runtime.BlockProfileRecord
@@ -758,7 +746,7 @@ func writeBlock(w io.Writer, debug int) error {
}
}
- sort.Sort(byCycles(p))
+ sort.Slice(p, func(i, j int) bool { return p[i].Cycles > p[j].Cycles })
b := bufio.NewWriter(w)
var tw *tabwriter.Writer
@@ -788,4 +776,49 @@ func writeBlock(w io.Writer, debug int) error {
return b.Flush()
}
+// writeMutex writes the current mutex profile to w.
+func writeMutex(w io.Writer, debug int) error {
+ // TODO(pjw): too much common code with writeBlock. FIX!
+ var p []runtime.BlockProfileRecord
+ n, ok := runtime.MutexProfile(nil)
+ for {
+ p = make([]runtime.BlockProfileRecord, n+50)
+ n, ok = runtime.MutexProfile(p)
+ if ok {
+ p = p[:n]
+ break
+ }
+ }
+
+ sort.Slice(p, func(i, j int) bool { return p[i].Cycles > p[j].Cycles })
+
+ b := bufio.NewWriter(w)
+ var tw *tabwriter.Writer
+ w = b
+ if debug > 0 {
+ tw = tabwriter.NewWriter(w, 1, 8, 1, '\t', 0)
+ w = tw
+ }
+
+ fmt.Fprintf(w, "--- mutex:\n")
+ fmt.Fprintf(w, "cycles/second=%v\n", runtime_cyclesPerSecond())
+ fmt.Fprintf(w, "sampling period=%d\n", runtime.SetMutexProfileFraction(-1))
+ for i := range p {
+ r := &p[i]
+ fmt.Fprintf(w, "%v %v @", r.Cycles, r.Count)
+ for _, pc := range r.Stack() {
+ fmt.Fprintf(w, " %#x", pc)
+ }
+ fmt.Fprint(w, "\n")
+ if debug > 0 {
+ printStackRecord(w, r.Stack(), true)
+ }
+ }
+
+ if tw != nil {
+ tw.Flush()
+ }
+ return b.Flush()
+}
+
func runtime_cyclesPerSecond() int64
diff --git a/src/runtime/pprof/pprof_test.go b/src/runtime/pprof/pprof_test.go
index a093015..fd06607 100644
--- a/src/runtime/pprof/pprof_test.go
+++ b/src/runtime/pprof/pprof_test.go
@@ -8,8 +8,12 @@ package pprof_test
import (
"bytes"
+ "compress/gzip"
"fmt"
+ "internal/pprof/profile"
"internal/testenv"
+ "io"
+ "io/ioutil"
"math/big"
"os"
"os/exec"
@@ -20,7 +24,6 @@ import (
"sync"
"testing"
"time"
- "unsafe"
)
func cpuHogger(f func(), dur time.Duration) {
@@ -87,40 +90,17 @@ func TestCPUProfileMultithreaded(t *testing.T) {
}
func parseProfile(t *testing.T, valBytes []byte, f func(uintptr, []uintptr)) {
- // Convert []byte to []uintptr.
- l := len(valBytes)
- if i := bytes.Index(valBytes, []byte("\nMAPPED_LIBRARIES:\n")); i >= 0 {
- l = i
- }
- l /= int(unsafe.Sizeof(uintptr(0)))
- val := *(*[]uintptr)(unsafe.Pointer(&valBytes))
- val = val[:l]
-
- // 5 for the header, 3 for the trailer.
- if l < 5+3 {
- t.Logf("profile too short: %#x", val)
- if badOS[runtime.GOOS] {
- t.Skipf("ignoring failure on %s; see golang.org/issue/13841", runtime.GOOS)
- return
- }
- t.FailNow()
- }
-
- hd, val, tl := val[:5], val[5:l-3], val[l-3:]
- if hd[0] != 0 || hd[1] != 3 || hd[2] != 0 || hd[3] != 1e6/100 || hd[4] != 0 {
- t.Fatalf("unexpected header %#x", hd)
- }
-
- if tl[0] != 0 || tl[1] != 1 || tl[2] != 0 {
- t.Fatalf("malformed end-of-data marker %#x", tl)
+ p, err := profile.Parse(bytes.NewReader(valBytes))
+ if err != nil {
+ t.Fatal(err)
}
-
- for len(val) > 0 {
- if len(val) < 2 || val[0] < 1 || val[1] < 1 || uintptr(len(val)) < 2+val[1] {
- t.Fatalf("malformed profile. leftover: %#x", val)
+ 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(val[0], val[2:2+val[1]])
- val = val[2+val[1]:]
+ f(count, stk)
}
}
@@ -366,8 +346,49 @@ 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" {
+ 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
@@ -380,6 +401,12 @@ func TestStackBarrierProfiling(t *testing.T) {
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.
@@ -592,6 +619,42 @@ func blockCond() {
mu.Unlock()
}
+func TestMutexProfile(t *testing.T) {
+ old := runtime.SetMutexProfileFraction(1)
+ defer runtime.SetMutexProfileFraction(old)
+ if old != 0 {
+ t.Fatalf("need MutexProfileRate 0, got %d", old)
+ }
+
+ blockMutex()
+
+ var w bytes.Buffer
+ Lookup("mutex").WriteTo(&w, 1)
+ prof := w.String()
+
+ if !strings.HasPrefix(prof, "--- mutex:\ncycles/second=") {
+ t.Errorf("Bad profile header:\n%v", prof)
+ }
+ prof = strings.Trim(prof, "\n")
+ lines := strings.Split(prof, "\n")
+ if len(lines) != 6 {
+ t.Errorf("expected 6 lines, got %d %q\n%s", len(lines), prof, prof)
+ }
+ if len(lines) < 6 {
+ return
+ }
+ // checking that the line is like "35258904 1 @ 0x48288d 0x47cd28 0x458931"
+ r2 := `^\d+ 1 @(?: 0x[[:xdigit:]]+)+`
+ //r2 := "^[0-9]+ 1 @ 0x[0-9a-f x]+$"
+ 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.*$"
+ if ok, err := regexp.MatchString(r3, lines[5]); err != nil || !ok {
+ t.Errorf("%q didn't match %q", lines[5], r3)
+ }
+}
+
func func1(c chan int) { <-c }
func func2(c chan int) { <-c }
func func3(c chan int) { <-c }
@@ -616,13 +679,31 @@ func TestGoroutineCounts(t *testing.T) {
time.Sleep(10 * time.Millisecond) // let goroutines block on channel
var w bytes.Buffer
- Lookup("goroutine").WriteTo(&w, 1)
+ goroutineProf := Lookup("goroutine")
+
+ // Check debug profile
+ goroutineProf.WriteTo(&w, 1)
prof := w.String()
if !containsInOrder(prof, "\n50 @ ", "\n40 @", "\n10 @", "\n1 @") {
t.Errorf("expected sorted goroutine counts:\n%s", prof)
}
+ // Check proto profile
+ w.Reset()
+ goroutineProf.WriteTo(&w, 0)
+ p, err := profile.Parse(&w)
+ if err != nil {
+ t.Errorf("error parsing protobuf profile: %v", err)
+ }
+ if err := p.CheckValid(); err != nil {
+ t.Errorf("protobuf profile is invalid: %v", err)
+ }
+ if !containsCounts(p, []int64{50, 40, 10, 1}) {
+ t.Errorf("expected count profile to contain goroutines with counts %v, got %v",
+ []int64{50, 40, 10, 1}, p)
+ }
+
close(c)
time.Sleep(10 * time.Millisecond) // let goroutines exit
@@ -638,3 +719,23 @@ func containsInOrder(s string, all ...string) bool {
}
return true
}
+
+func containsCounts(prof *profile.Profile, counts []int64) bool {
+ m := make(map[int64]int)
+ for _, c := range counts {
+ m[c]++
+ }
+ for _, s := range prof.Sample {
+ // The count is the single value in the sample
+ if len(s.Value) != 1 {
+ return false
+ }
+ m[s.Value[0]]--
+ }
+ for _, n := range m {
+ if n > 0 {
+ return false
+ }
+ }
+ return true
+}
diff --git a/src/runtime/print.go b/src/runtime/print.go
index 32626c1..8fa3d39 100644
--- a/src/runtime/print.go
+++ b/src/runtime/print.go
@@ -4,7 +4,10 @@
package runtime
-import "unsafe"
+import (
+ "runtime/internal/atomic"
+ "unsafe"
+)
// The compiler knows that a print of a value of this type
// should use printhex instead of printuint (decimal).
@@ -19,6 +22,36 @@ func bytes(s string) (ret []byte) {
return
}
+var (
+ // printBacklog is a circular buffer of messages written with the builtin
+ // print* functions, for use in postmortem analysis of core dumps.
+ printBacklog [512]byte
+ printBacklogIndex int
+)
+
+// recordForPanic maintains a circular buffer of messages written by the
+// runtime leading up to a process crash, allowing the messages to be
+// extracted from a core dump.
+//
+// The text written during a process crash (following "panic" or "fatal
+// error") is not saved, since the goroutine stacks will generally be readable
+// from the runtime datastructures in the core file.
+func recordForPanic(b []byte) {
+ printlock()
+
+ if atomic.Load(&panicking) == 0 {
+ // Not actively crashing: maintain circular buffer of print output.
+ for i := 0; i < len(b); {
+ n := copy(printBacklog[printBacklogIndex:], b[i:])
+ i += n
+ printBacklogIndex += n
+ printBacklogIndex %= len(printBacklog)
+ }
+ }
+
+ printunlock()
+}
+
var debuglock mutex
// The compiler emits calls to printlock and printunlock around
@@ -53,6 +86,7 @@ func gwrite(b []byte) {
if len(b) == 0 {
return
}
+ recordForPanic(b)
gp := getg()
if gp == nil || gp.writebuf == nil {
writeErr(b)
@@ -199,10 +233,6 @@ func printpointer(p unsafe.Pointer) {
}
func printstring(s string) {
- if uintptr(len(s)) > maxstring {
- gwrite(bytes("[string too long]"))
- return
- }
gwrite(bytes(s))
}
diff --git a/src/runtime/proc.go b/src/runtime/proc.go
index e693f7e..cad1b1c 100644
--- a/src/runtime/proc.go
+++ b/src/runtime/proc.go
@@ -169,7 +169,8 @@ func main() {
cgocall(_cgo_notify_runtime_init_done, nil)
}
- main_init()
+ fn := main_init // make an indirect call, as the linker doesn't know the address of the main package when laying down the runtime
+ fn()
close(main_init_done)
needUnlock = false
@@ -180,7 +181,8 @@ func main() {
// has a main, but it is not executed.
return
}
- main_main()
+ fn = main_main // make an indirect call, as the linker doesn't know the address of the main package when laying down the runtime
+ fn()
if raceenabled {
racefini()
}
@@ -379,6 +381,29 @@ func badreflectcall() {
panic(plainError("arg size to reflect.call more than 1GB"))
}
+var badmorestackg0Msg = "fatal: morestack on g0\n"
+
+//go:nosplit
+//go:nowritebarrierrec
+func badmorestackg0() {
+ sp := stringStructOf(&badmorestackg0Msg)
+ write(2, sp.str, int32(sp.len))
+}
+
+var badmorestackgsignalMsg = "fatal: morestack on gsignal\n"
+
+//go:nosplit
+//go:nowritebarrierrec
+func badmorestackgsignal() {
+ sp := stringStructOf(&badmorestackgsignalMsg)
+ write(2, sp.str, int32(sp.len))
+}
+
+//go:nosplit
+func badctxt() {
+ throw("ctxt != 0")
+}
+
func lockedOSThread() bool {
gp := getg()
return gp.lockedm != nil && gp.m.lockedg != nil
@@ -440,8 +465,9 @@ func schedinit() {
mallocinit()
mcommoninit(_g_.m)
alginit() // maps must not be used before this call
- typelinksinit() // uses maps
- itabsinit()
+ modulesinit() // provides activeModules
+ typelinksinit() // uses maps, activeModules
+ itabsinit() // uses activeModules
msigsave(_g_.m)
initSigmask = _g_.m.sigmask
@@ -452,17 +478,14 @@ func schedinit() {
gcinit()
sched.lastpoll = uint64(nanotime())
- procs := int(ncpu)
+ procs := ncpu
+ if n, ok := atoi32(gogetenv("GOMAXPROCS")); ok && n > 0 {
+ procs = n
+ }
if procs > _MaxGomaxprocs {
procs = _MaxGomaxprocs
}
- if n := atoi(gogetenv("GOMAXPROCS")); n > 0 {
- if n > _MaxGomaxprocs {
- n = _MaxGomaxprocs
- }
- procs = n
- }
- if procresize(int32(procs)) != nil {
+ if procresize(procs) != nil {
throw("unknown runnable goroutine during bootstrap")
}
@@ -543,7 +566,7 @@ func ready(gp *g, traceskip int, next bool) {
// status is Gwaiting or Gscanwaiting, make Grunnable and put on runq
casgstatus(gp, _Gwaiting, _Grunnable)
runqput(_g_.m.p.ptr(), gp, next)
- if atomic.Load(&sched.npidle) != 0 && atomic.Load(&sched.nmspinning) == 0 { // TODO: fast atomic
+ if atomic.Load(&sched.npidle) != 0 && atomic.Load(&sched.nmspinning) == 0 {
wakep()
}
_g_.m.locks--
@@ -903,7 +926,7 @@ func restartg(gp *g) {
// in panic or being exited, this may not reliably stop all
// goroutines.
func stopTheWorld(reason string) {
- semacquire(&worldsema, false)
+ semacquire(&worldsema, 0)
getg().m.preemptoff = reason
systemstack(stopTheWorldWithSema)
}
@@ -926,7 +949,7 @@ var worldsema uint32 = 1
// preemption first and then should stopTheWorldWithSema on the system
// stack:
//
-// semacquire(&worldsema, false)
+// semacquire(&worldsema, 0)
// m.preemptoff = "reason"
// systemstack(stopTheWorldWithSema)
//
@@ -1273,8 +1296,10 @@ type cgothreadstart struct {
// Can use p for allocation context if needed.
// fn is recorded as the new m's m.mstartfn.
//
-// This function it known to the compiler to inhibit the
-// go:nowritebarrierrec annotation because it uses P for allocation.
+// This function is allowed to have write barriers even if the caller
+// isn't because it borrows _p_.
+//
+//go:yeswritebarrierrec
func allocm(_p_ *p, fn func()) *m {
_g_ := getg()
_g_.m.locks++ // disable GC because it can be called from sysmon
@@ -1427,6 +1452,7 @@ func oneNewExtraM() {
gp.syscallsp = gp.sched.sp
gp.stktopsp = gp.sched.sp
gp.gcscanvalid = true // fresh G, so no dequeueRescan necessary
+ gp.gcscandone = true
gp.gcRescan = -1
// malg returns status as Gidle, change to Gsyscall before adding to allg
// where GC will see it.
@@ -1438,7 +1464,7 @@ func oneNewExtraM() {
gp.lockedm = mp
gp.goid = int64(atomic.Xadd64(&sched.goidgen, 1))
if raceenabled {
- gp.racectx = racegostart(funcPC(newextram))
+ gp.racectx = racegostart(funcPC(newextram) + sys.PCQuantum)
}
// put on allg for garbage collector
allgadd(gp)
@@ -1550,7 +1576,7 @@ func unlockextra(mp *m) {
// Create a new m. It will start off with a call to fn, or else the scheduler.
// fn needs to be static and not a heap allocated closure.
// May run with m.p==nil, so write barriers are not allowed.
-//go:nowritebarrier
+//go:nowritebarrierrec
func newm(fn func(), _p_ *p) {
mp := allocm(_p_, fn)
mp.nextp.set(_p_)
@@ -1614,7 +1640,7 @@ func mspinning() {
// May run with m.p==nil, so write barriers are not allowed.
// If spinning is set, the caller has incremented nmspinning and startm will
// either decrement nmspinning or set m.spinning in the newly started M.
-//go:nowritebarrier
+//go:nowritebarrierrec
func startm(_p_ *p, spinning bool) {
lock(&sched.lock)
if _p_ == nil {
@@ -1659,7 +1685,7 @@ func startm(_p_ *p, spinning bool) {
// Hands off P from syscall or locked M.
// Always runs without a P, so write barriers are not allowed.
-//go:nowritebarrier
+//go:nowritebarrierrec
func handoffp(_p_ *p) {
// handoffp must start an M in any situation where
// findrunnable would return a G to run on _p_.
@@ -1752,7 +1778,7 @@ func stoplockedm() {
// Schedules the locked m to run the locked gp.
// May run during STW, so write barriers are not allowed.
-//go:nowritebarrier
+//go:nowritebarrierrec
func startlockedm(gp *g) {
_g_ := getg()
@@ -1802,6 +1828,11 @@ func gcstopm() {
// If inheritTime is true, gp inherits the remaining time in the
// current time slice. Otherwise, it starts a new time slice.
// Never returns.
+//
+// Write barriers are allowed because this is called immediately after
+// acquiring a P in several places.
+//
+//go:yeswritebarrierrec
func execute(gp *g, inheritTime bool) {
_g_ := getg()
@@ -1901,7 +1932,7 @@ top:
// If number of spinning M's >= number of busy P's, block.
// This is necessary to prevent excessive CPU consumption
// when GOMAXPROCS>>1 but the program parallelism is low.
- if !_g_.m.spinning && 2*atomic.Load(&sched.nmspinning) >= procs-atomic.Load(&sched.npidle) { // TODO: fast atomic
+ if !_g_.m.spinning && 2*atomic.Load(&sched.nmspinning) >= procs-atomic.Load(&sched.npidle) {
goto stop
}
if !_g_.m.spinning {
@@ -1909,7 +1940,7 @@ top:
atomic.Xadd(&sched.nmspinning, 1)
}
for i := 0; i < 4; i++ {
- for enum := stealOrder.start(fastrand1()); !enum.done(); enum.next() {
+ for enum := stealOrder.start(fastrand()); !enum.done(); enum.next() {
if sched.gcwaiting != 0 {
goto top
}
@@ -1992,6 +2023,26 @@ stop:
}
}
+ // Check for idle-priority GC work again.
+ if gcBlackenEnabled != 0 && gcMarkWorkAvailable(nil) {
+ lock(&sched.lock)
+ _p_ = pidleget()
+ if _p_ != nil && _p_.gcBgMarkWorker == 0 {
+ pidleput(_p_)
+ _p_ = nil
+ }
+ unlock(&sched.lock)
+ if _p_ != nil {
+ acquirep(_p_)
+ if wasSpinning {
+ _g_.m.spinning = true
+ atomic.Xadd(&sched.nmspinning, 1)
+ }
+ // Go back to idle GC check.
+ goto stop
+ }
+ }
+
// poll network
if netpollinited() && atomic.Xchg64(&sched.lastpoll, 0) != 0 {
if _g_.m.p != 0 {
@@ -2022,6 +2073,27 @@ stop:
goto top
}
+// pollWork returns true if there is non-background work this P could
+// be doing. This is a fairly lightweight check to be used for
+// background work loops, like idle GC. It checks a subset of the
+// conditions checked by the actual scheduler.
+func pollWork() bool {
+ if sched.runqsize != 0 {
+ return true
+ }
+ p := getg().m.p.ptr()
+ if !runqempty(p) {
+ return true
+ }
+ if netpollinited() && sched.lastpoll != 0 {
+ if gp := netpoll(false); gp != nil {
+ injectglist(gp)
+ return true
+ }
+ }
+ return false
+}
+
func resetspinning() {
_g_ := getg()
if !_g_.m.spinning {
@@ -2147,8 +2219,8 @@ top:
func dropg() {
_g_ := getg()
- _g_.m.curg.m = nil
- _g_.m.curg = nil
+ setMNoWB(&_g_.m.curg.m, nil)
+ setGNoWB(&_g_.m.curg, nil)
}
func parkunlock_c(gp *g, lock unsafe.Pointer) bool {
@@ -2257,8 +2329,14 @@ func goexit0(gp *g) {
schedule()
}
+// save updates getg().sched to refer to pc and sp so that a following
+// gogo will restore pc and sp.
+//
+// save must not have write barriers because invoking a write barrier
+// can clobber getg().sched.
+//
//go:nosplit
-//go:nowritebarrier
+//go:nowritebarrierrec
func save(pc, sp uintptr) {
_g_ := getg()
@@ -2266,8 +2344,13 @@ func save(pc, sp uintptr) {
_g_.sched.sp = sp
_g_.sched.lr = 0
_g_.sched.ret = 0
- _g_.sched.ctxt = nil
_g_.sched.g = guintptr(unsafe.Pointer(_g_))
+ // We need to ensure ctxt is zero, but can't have a write
+ // barrier here. However, it should always already be zero.
+ // Assert that.
+ if _g_.sched.ctxt != nil {
+ badctxt()
+ }
}
// The goroutine g is about to enter a system call.
@@ -2341,7 +2424,7 @@ func reentersyscall(pc, sp uintptr) {
save(pc, sp)
}
- if atomic.Load(&sched.sysmonwait) != 0 { // TODO: fast atomic
+ if atomic.Load(&sched.sysmonwait) != 0 {
systemstack(entersyscall_sysmon)
save(pc, sp)
}
@@ -2457,7 +2540,11 @@ func entersyscallblock_handoff() {
// Arrange for it to run on a cpu again.
// This is called only from the go syscall library, not
// from the low-level system calls used by the runtime.
+//
+// Write barriers are not allowed because our P may have been stolen.
+//
//go:nosplit
+//go:nowritebarrierrec
func exitsyscall(dummy int32) {
_g_ := getg()
@@ -2550,22 +2637,7 @@ func exitsyscallfast() bool {
// Try to re-acquire the last P.
if _g_.m.p != 0 && _g_.m.p.ptr().status == _Psyscall && atomic.Cas(&_g_.m.p.ptr().status, _Psyscall, _Prunning) {
// There's a cpu for us, so we can run.
- _g_.m.mcache = _g_.m.p.ptr().mcache
- _g_.m.p.ptr().m.set(_g_.m)
- if _g_.m.syscalltick != _g_.m.p.ptr().syscalltick {
- if trace.enabled {
- // The p was retaken and then enter into syscall again (since _g_.m.syscalltick has changed).
- // traceGoSysBlock for this syscall was already emitted,
- // but here we effectively retake the p from the new syscall running on the same p.
- systemstack(func() {
- // Denote blocking of the new syscall.
- traceGoSysBlock(_g_.m.p.ptr())
- // Denote completion of the current syscall.
- traceGoSysExit(0)
- })
- }
- _g_.m.p.ptr().syscalltick++
- }
+ exitsyscallfast_reacquired()
return true
}
@@ -2595,6 +2667,35 @@ func exitsyscallfast() bool {
return false
}
+// exitsyscallfast_reacquired is the exitsyscall path on which this G
+// has successfully reacquired the P it was running on before the
+// syscall.
+//
+// This function is allowed to have write barriers because exitsyscall
+// has acquired a P at this point.
+//
+//go:yeswritebarrierrec
+//go:nosplit
+func exitsyscallfast_reacquired() {
+ _g_ := getg()
+ _g_.m.mcache = _g_.m.p.ptr().mcache
+ _g_.m.p.ptr().m.set(_g_.m)
+ if _g_.m.syscalltick != _g_.m.p.ptr().syscalltick {
+ if trace.enabled {
+ // The p was retaken and then enter into syscall again (since _g_.m.syscalltick has changed).
+ // traceGoSysBlock for this syscall was already emitted,
+ // but here we effectively retake the p from the new syscall running on the same p.
+ systemstack(func() {
+ // Denote blocking of the new syscall.
+ traceGoSysBlock(_g_.m.p.ptr())
+ // Denote completion of the current syscall.
+ traceGoSysExit(0)
+ })
+ }
+ _g_.m.p.ptr().syscalltick++
+ }
+}
+
func exitsyscallfast_pidle() bool {
lock(&sched.lock)
_p_ := pidleget()
@@ -2612,6 +2713,8 @@ func exitsyscallfast_pidle() bool {
// exitsyscall slow path on g0.
// Failed to acquire P, enqueue gp as runnable.
+//
+//go:nowritebarrierrec
func exitsyscall0(gp *g) {
_g_ := getg()
@@ -2758,13 +2861,28 @@ func newproc1(fn *funcval, argp *uint8, narg int32, nret int32, callerpc uintptr
spArg := sp
if usesLR {
// caller's LR
- *(*unsafe.Pointer)(unsafe.Pointer(sp)) = nil
+ *(*uintptr)(unsafe.Pointer(sp)) = 0
prepGoExitFrame(sp)
spArg += sys.MinFrameSize
}
- memmove(unsafe.Pointer(spArg), unsafe.Pointer(argp), uintptr(narg))
+ if narg > 0 {
+ memmove(unsafe.Pointer(spArg), unsafe.Pointer(argp), uintptr(narg))
+ // This is a stack-to-stack copy. If write barriers
+ // are enabled and the source stack is grey (the
+ // destination is always black), then perform a
+ // barrier copy. We do this *after* the memmove
+ // because the destination stack may have garbage on
+ // it.
+ if writeBarrier.needed && !_g_.m.curg.gcscandone {
+ f := findfunc(fn.fn)
+ stkmap := (*stackmap)(funcdata(f, _FUNCDATA_ArgsPointerMaps))
+ // We're in the prologue, so it's always stack map index 0.
+ bv := stackmapdata(stkmap, 0)
+ bulkBarrierBitmap(spArg, spArg, uintptr(narg), 0, bv.bytedata)
+ }
+ }
- memclr(unsafe.Pointer(&newg.sched), unsafe.Sizeof(newg.sched))
+ memclrNoHeapPointers(unsafe.Pointer(&newg.sched), unsafe.Sizeof(newg.sched))
newg.sched.sp = sp
newg.stktopsp = sp
newg.sched.pc = funcPC(goexit) + sys.PCQuantum // +PCQuantum so that previous instruction is in same function
@@ -2806,7 +2924,7 @@ func newproc1(fn *funcval, argp *uint8, narg int32, nret int32, callerpc uintptr
}
runqput(_p_, newg, true)
- if atomic.Load(&sched.npidle) != 0 && atomic.Load(&sched.nmspinning) == 0 && unsafe.Pointer(fn.fn) != unsafe.Pointer(funcPC(main)) { // TODO: fast atomic
+ if atomic.Load(&sched.npidle) != 0 && atomic.Load(&sched.nmspinning) == 0 && runtimeInitTime != 0 {
wakep()
}
_g_.m.locks--
@@ -3035,7 +3153,12 @@ func sigprof(pc, sp, lr uintptr, gp *g, mp *m) {
}
// Profiling runs concurrently with GC, so it must not allocate.
- mp.mallocing++
+ // Set a trap in case the code does allocate.
+ // Note that on windows, one thread takes profiles of all the
+ // other threads, so mp is usually not getg().m.
+ // In fact mp may not even be stopped.
+ // See golang.org/issue/17165.
+ getg().m.mallocing++
// Define that a "user g" is a user-created goroutine, and a "system g"
// is one that is m->g0 or m->gsignal.
@@ -3185,7 +3308,7 @@ func sigprof(pc, sp, lr uintptr, gp *g, mp *m) {
}
atomic.Store(&prof.lock, 0)
}
- mp.mallocing--
+ getg().m.mallocing--
}
// If the signal handler receives a SIGPROF signal on a non-Go thread,
@@ -3194,7 +3317,8 @@ func sigprof(pc, sp, lr uintptr, gp *g, mp *m) {
var sigprofCallers cgoCallers
var sigprofCallersUse uint32
-// Called if we receive a SIGPROF signal on a non-Go thread.
+// sigprofNonGo is called if we receive a SIGPROF signal on a non-Go thread,
+// and the signal handler collected a stack trace in sigprofCallers.
// When this is called, sigprofCallersUse will be non-zero.
// g is nil, and what we can do is very limited.
//go:nosplit
@@ -3207,17 +3331,41 @@ func sigprofNonGo() {
}
// Simple cas-lock to coordinate with setcpuprofilerate.
- if atomic.Cas(&prof.lock, 0, 1) {
- if prof.hz != 0 {
- cpuprof.addNonGo(sigprofCallers[:n])
- }
- atomic.Store(&prof.lock, 0)
+ for !atomic.Cas(&prof.lock, 0, 1) {
+ osyield()
}
+ if prof.hz != 0 {
+ cpuprof.addNonGo(sigprofCallers[:n])
+ }
+ atomic.Store(&prof.lock, 0)
}
atomic.Store(&sigprofCallersUse, 0)
}
+// sigprofNonGoPC is called when a profiling signal arrived on a
+// non-Go thread and we have a single PC value, not a stack trace.
+// g is nil, and what we can do is very limited.
+//go:nosplit
+//go:nowritebarrierrec
+func sigprofNonGoPC(pc uintptr) {
+ if prof.hz != 0 {
+ pc := []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)
+ }
+}
+
// Reports whether a function will set the SP
// to an absolute value. Important that
// we don't traceback when these are at the bottom
@@ -3427,7 +3575,13 @@ func procresize(nprocs int32) *p {
}
// Associate p and the current m.
+//
+// This function is allowed to have write barriers even if the caller
+// isn't because it immediately acquires _p_.
+//
+//go:yeswritebarrierrec
func acquirep(_p_ *p) {
+ // Do the part that isn't allowed to have write barriers.
acquirep1(_p_)
// have p; write barriers now allowed
@@ -3439,8 +3593,11 @@ func acquirep(_p_ *p) {
}
}
-// May run during STW, so write barriers are not allowed.
-//go:nowritebarrier
+// acquirep1 is the first step of acquirep, which actually acquires
+// _p_. This is broken out so we can disallow write barriers for this
+// part, since we don't yet have a P.
+//
+//go:nowritebarrierrec
func acquirep1(_p_ *p) {
_g_ := getg()
@@ -3604,7 +3761,7 @@ func sysmon() {
delay = 10 * 1000
}
usleep(delay)
- if debug.schedtrace <= 0 && (sched.gcwaiting != 0 || atomic.Load(&sched.npidle) == uint32(gomaxprocs)) { // TODO: fast atomic
+ if debug.schedtrace <= 0 && (sched.gcwaiting != 0 || atomic.Load(&sched.npidle) == uint32(gomaxprocs)) {
lock(&sched.lock)
if atomic.Load(&sched.gcwaiting) != 0 || atomic.Load(&sched.npidle) == uint32(gomaxprocs) {
atomic.Store(&sched.sysmonwait, 1)
@@ -3878,7 +4035,7 @@ func schedtrace(detailed bool) {
// Put mp on midle list.
// Sched must be locked.
// May run during STW, so write barriers are not allowed.
-//go:nowritebarrier
+//go:nowritebarrierrec
func mput(mp *m) {
mp.schedlink = sched.midle
sched.midle.set(mp)
@@ -3889,7 +4046,7 @@ func mput(mp *m) {
// Try to get an m from midle list.
// Sched must be locked.
// May run during STW, so write barriers are not allowed.
-//go:nowritebarrier
+//go:nowritebarrierrec
func mget() *m {
mp := sched.midle.ptr()
if mp != nil {
@@ -3902,7 +4059,7 @@ func mget() *m {
// Put gp on the global runnable queue.
// Sched must be locked.
// May run during STW, so write barriers are not allowed.
-//go:nowritebarrier
+//go:nowritebarrierrec
func globrunqput(gp *g) {
gp.schedlink = 0
if sched.runqtail != 0 {
@@ -3917,7 +4074,7 @@ func globrunqput(gp *g) {
// Put gp at the head of the global runnable queue.
// Sched must be locked.
// May run during STW, so write barriers are not allowed.
-//go:nowritebarrier
+//go:nowritebarrierrec
func globrunqputhead(gp *g) {
gp.schedlink = sched.runqhead
sched.runqhead.set(gp)
@@ -3977,7 +4134,7 @@ func globrunqget(_p_ *p, max int32) *g {
// Put p to on _Pidle list.
// Sched must be locked.
// May run during STW, so write barriers are not allowed.
-//go:nowritebarrier
+//go:nowritebarrierrec
func pidleput(_p_ *p) {
if !runqempty(_p_) {
throw("pidleput: P has non-empty run queue")
@@ -3990,7 +4147,7 @@ func pidleput(_p_ *p) {
// Try get a p from _Pidle list.
// Sched must be locked.
// May run during STW, so write barriers are not allowed.
-//go:nowritebarrier
+//go:nowritebarrierrec
func pidleget() *p {
_p_ := sched.pidle.ptr()
if _p_ != nil {
@@ -4034,7 +4191,7 @@ const randomizeScheduler = raceenabled
// If the run queue is full, runnext puts g on the global queue.
// Executed only by the owner P.
func runqput(_p_ *p, gp *g, next bool) {
- if randomizeScheduler && next && fastrand1()%2 == 0 {
+ if randomizeScheduler && next && fastrand()%2 == 0 {
next = false
}
@@ -4087,7 +4244,7 @@ func runqputslow(_p_ *p, gp *g, h, t uint32) bool {
if randomizeScheduler {
for i := uint32(1); i <= n; i++ {
- j := fastrand1() % (i + 1)
+ j := fastrand() % (i + 1)
batch[i], batch[j] = batch[j], batch[i]
}
}
@@ -4212,7 +4369,11 @@ func runqsteal(_p_, p2 *p, stealRunNextG bool) *g {
func setMaxThreads(in int) (out int) {
lock(&sched.lock)
out = int(sched.maxmcount)
- sched.maxmcount = int32(in)
+ if in > 0x7fffffff { // MaxInt32
+ sched.maxmcount = 0x7fffffff
+ } else {
+ sched.maxmcount = int32(in)
+ }
checkmcount()
unlock(&sched.lock)
return
diff --git a/src/runtime/race.go b/src/runtime/race.go
index 42da936..d8483c0 100644
--- a/src/runtime/race.go
+++ b/src/runtime/race.go
@@ -20,6 +20,12 @@ 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)
+ return int(n)
+}
+
// private interface for the runtime
const raceenabled = true
@@ -91,23 +97,23 @@ func racecallback(cmd uintptr, ctx unsafe.Pointer) {
}
func raceSymbolizeCode(ctx *symbolizeCodeContext) {
- f := findfunc(ctx.pc)
- if f == nil {
- ctx.fn = &qq[0]
- ctx.file = &dash[0]
- ctx.line = 0
- ctx.off = ctx.pc
- ctx.res = 1
- return
+ f := FuncForPC(ctx.pc)
+ if f != nil {
+ file, line := f.FileLine(ctx.pc)
+ if line != 0 {
+ ctx.fn = cfuncname(f.raw())
+ ctx.line = uintptr(line)
+ ctx.file = &bytes(file)[0] // assume NUL-terminated
+ ctx.off = ctx.pc - f.Entry()
+ ctx.res = 1
+ return
+ }
}
-
- ctx.fn = cfuncname(f)
- file, line := funcline(f, ctx.pc)
- ctx.line = uintptr(line)
- ctx.file = &bytes(file)[0] // assume NUL-terminated
- ctx.off = ctx.pc - f.entry
+ ctx.fn = &qq[0]
+ ctx.file = &dash[0]
+ ctx.line = 0
+ ctx.off = ctx.pc
ctx.res = 1
- return
}
type symbolizeDataContext struct {
@@ -176,6 +182,9 @@ var __tsan_go_ignore_sync_begin byte
//go:linkname __tsan_go_ignore_sync_end __tsan_go_ignore_sync_end
var __tsan_go_ignore_sync_end byte
+//go:linkname __tsan_report_count __tsan_report_count
+var __tsan_report_count byte
+
// Mimic what cmd/cgo would do.
//go:cgo_import_static __tsan_init
//go:cgo_import_static __tsan_fini
@@ -192,6 +201,7 @@ var __tsan_go_ignore_sync_end byte
//go:cgo_import_static __tsan_release_merge
//go:cgo_import_static __tsan_go_ignore_sync_begin
//go:cgo_import_static __tsan_go_ignore_sync_end
+//go:cgo_import_static __tsan_report_count
// These are called from race_amd64.s.
//go:cgo_import_static __tsan_read
diff --git a/src/runtime/race/README b/src/runtime/race/README
index 95e241c..398b22f 100644
--- a/src/runtime/race/README
+++ b/src/runtime/race/README
@@ -4,4 +4,4 @@ the LLVM project (http://llvm.org/git/compiler-rt.git).
To update the .syso files use golang.org/x/build/cmd/racebuild.
-Current runtime is built on rev e35e7c00b5c7e7ee5e24d537b80cb0d34cebb038.
+Current runtime is built on rev 68e1532492f9b3fce0e9024f3c31411105965b11.
diff --git a/src/runtime/race/output_test.go b/src/runtime/race/output_test.go
index 5157f7e..587540f 100644
--- a/src/runtime/race/output_test.go
+++ b/src/runtime/race/output_test.go
@@ -7,17 +7,23 @@
package race_test
import (
+ "internal/testenv"
"io/ioutil"
"os"
"os/exec"
"path/filepath"
"regexp"
+ "runtime"
"strings"
"testing"
)
func TestOutput(t *testing.T) {
for _, test := range tests {
+ if test.goos != "" && test.goos != runtime.GOOS {
+ t.Logf("test %v runs only on %v, skipping: ", test.name, test.goos)
+ continue
+ }
dir, err := ioutil.TempDir("", "go-build")
if err != nil {
t.Fatalf("failed to create temp directory: %v", err)
@@ -41,7 +47,7 @@ func TestOutput(t *testing.T) {
t.Fatalf("failed to close file: %v", err)
}
// Pass -l to the compiler to test stack traces.
- cmd := exec.Command("go", test.run, "-race", "-gcflags=-l", src)
+ cmd := exec.Command(testenv.GoToolPath(t), test.run, "-race", "-gcflags=-l", src)
// GODEBUG spoils program output, GOMAXPROCS makes it flaky.
for _, env := range os.Environ() {
if strings.HasPrefix(env, "GODEBUG=") ||
@@ -66,11 +72,12 @@ func TestOutput(t *testing.T) {
var tests = []struct {
name string
run string
+ goos string
gorace string
source string
re string
}{
- {"simple", "run", "atexit_sleep_ms=0", `
+ {"simple", "run", "", "atexit_sleep_ms=0", `
package main
import "time"
func main() {
@@ -115,7 +122,7 @@ Found 1 data race\(s\)
exit status 66
`},
- {"exitcode", "run", "atexit_sleep_ms=0 exitcode=13", `
+ {"exitcode", "run", "", "atexit_sleep_ms=0 exitcode=13", `
package main
func main() {
done := make(chan bool)
@@ -129,7 +136,7 @@ func main() {
}
`, `exit status 13`},
- {"strip_path_prefix", "run", "atexit_sleep_ms=0 strip_path_prefix=/main.", `
+ {"strip_path_prefix", "run", "", "atexit_sleep_ms=0 strip_path_prefix=/main.", `
package main
func main() {
done := make(chan bool)
@@ -145,7 +152,7 @@ func main() {
go:7 \+0x[0-9,a-f]+
`},
- {"halt_on_error", "run", "atexit_sleep_ms=0 halt_on_error=1", `
+ {"halt_on_error", "run", "", "atexit_sleep_ms=0 halt_on_error=1", `
package main
func main() {
done := make(chan bool)
@@ -162,7 +169,7 @@ func main() {
exit status 66
`},
- {"test_fails_on_race", "test", "atexit_sleep_ms=0", `
+ {"test_fails_on_race", "test", "", "atexit_sleep_ms=0", `
package main_test
import "testing"
func TestFail(t *testing.T) {
@@ -177,11 +184,11 @@ func TestFail(t *testing.T) {
}
`, `
==================
-PASS
-Found 1 data race\(s\)
+--- FAIL: TestFail \(0...s\)
+.*testing.go:.*: race detected during execution of test
FAIL`},
- {"slicebytetostring_pc", "run", "atexit_sleep_ms=0", `
+ {"slicebytetostring_pc", "run", "", "atexit_sleep_ms=0", `
package main
func main() {
done := make(chan string)
@@ -197,4 +204,57 @@ func main() {
.*/runtime/string\.go:.*
main\.main\.func1\(\)
.*/main.go:7`},
+
+ // Test for http://golang.org/issue/17190
+ {"external_cgo_thread", "run", "linux", "atexit_sleep_ms=0", `
+package main
+
+/*
+#include <pthread.h>
+typedef struct cb {
+ int foo;
+} cb;
+extern void goCallback();
+static inline void *threadFunc(void *p) {
+ goCallback();
+ return 0;
+}
+static inline void startThread(cb* c) {
+ pthread_t th;
+ pthread_create(&th, 0, threadFunc, 0);
+}
+*/
+import "C"
+
+import "time"
+
+var racy int
+
+//export goCallback
+func goCallback() {
+ racy++
+}
+
+func main() {
+ var c C.cb
+ C.startThread(&c)
+ time.Sleep(time.Second)
+ racy++
+}
+`, `==================
+WARNING: DATA RACE
+Read at 0x[0-9,a-f]+ by main goroutine:
+ main\.main\(\)
+ .*/main\.go:34 \+0x[0-9,a-f]+
+
+Previous write at 0x[0-9,a-f]+ by goroutine [0-9]:
+ main\.goCallback\(\)
+ .*/main\.go:27 \+0x[0-9,a-f]+
+ main._cgoexpwrap_[0-9a-z]+_goCallback\(\)
+ .*/_cgo_gotypes\.go:[0-9]+ \+0x[0-9,a-f]+
+
+Goroutine [0-9] \(running\) created at:
+ runtime\.newextram\(\)
+ .*/runtime/proc.go:[0-9]+ \+0x[0-9,a-f]+
+==================`},
}
diff --git a/src/runtime/race/race_darwin_amd64.syso b/src/runtime/race/race_darwin_amd64.syso
index c19740f..89c7f57 100644
Binary files a/src/runtime/race/race_darwin_amd64.syso and b/src/runtime/race/race_darwin_amd64.syso differ
diff --git a/src/runtime/race/race_freebsd_amd64.syso b/src/runtime/race/race_freebsd_amd64.syso
index df1bc26..6312ce8 100644
Binary files a/src/runtime/race/race_freebsd_amd64.syso and b/src/runtime/race/race_freebsd_amd64.syso differ
diff --git a/src/runtime/race/race_linux_amd64.syso b/src/runtime/race/race_linux_amd64.syso
index 1740330..3795520 100644
Binary files a/src/runtime/race/race_linux_amd64.syso and b/src/runtime/race/race_linux_amd64.syso differ
diff --git a/src/runtime/race/race_test.go b/src/runtime/race/race_test.go
index 53ec74c..8cdf52d 100644
--- a/src/runtime/race/race_test.go
+++ b/src/runtime/race/race_test.go
@@ -15,6 +15,7 @@ import (
"bufio"
"bytes"
"fmt"
+ "internal/testenv"
"io"
"log"
"math/rand"
@@ -43,7 +44,7 @@ const (
)
func TestRace(t *testing.T) {
- testOutput, err := runTests()
+ testOutput, err := runTests(t)
if err != nil {
t.Fatalf("Failed to run tests: %v\n%v", err, string(testOutput))
}
@@ -141,19 +142,21 @@ func processLog(testName string, tsanLog []string) string {
// runTests assures that the package and its dependencies is
// built with instrumentation enabled and returns the output of 'go test'
// which includes possible data race reports from ThreadSanitizer.
-func runTests() ([]byte, error) {
+func runTests(t *testing.T) ([]byte, error) {
tests, err := filepath.Glob("./testdata/*_test.go")
if err != nil {
return nil, err
}
args := []string{"test", "-race", "-v"}
args = append(args, tests...)
- cmd := exec.Command("go", args...)
+ cmd := exec.Command(testenv.GoToolPath(t), args...)
// The following flags turn off heuristics that suppress seemingly identical reports.
// It is required because the tests contain a lot of data races on the same addresses
// (the tests are simple and the memory is constantly reused).
for _, env := range os.Environ() {
- if strings.HasPrefix(env, "GOMAXPROCS=") || strings.HasPrefix(env, "GODEBUG=") {
+ if strings.HasPrefix(env, "GOMAXPROCS=") ||
+ strings.HasPrefix(env, "GODEBUG=") ||
+ strings.HasPrefix(env, "GORACE=") {
continue
}
cmd.Env = append(cmd.Env, env)
@@ -170,9 +173,11 @@ func runTests() ([]byte, error) {
// (that's what is done for C++ ThreadSanitizer tests). This is issue #14119.
cmd.Env = append(cmd.Env,
"GOMAXPROCS=1",
- "GORACE=suppress_equal_stacks=0 suppress_equal_addresses=0 exitcode=0",
+ "GORACE=suppress_equal_stacks=0 suppress_equal_addresses=0",
)
- return cmd.CombinedOutput()
+ // There are races: we expect tests to fail and the exit code to be non-zero.
+ out, _ := cmd.CombinedOutput()
+ return out, nil
}
func TestIssue8102(t *testing.T) {
diff --git a/src/runtime/race/race_windows_amd64.syso b/src/runtime/race/race_windows_amd64.syso
index fd93959..b85f5d6 100644
Binary files a/src/runtime/race/race_windows_amd64.syso and b/src/runtime/race/race_windows_amd64.syso differ
diff --git a/src/runtime/race/testdata/cgo_test.go b/src/runtime/race/testdata/cgo_test.go
index ba7e7b5..211ef7d 100644
--- a/src/runtime/race/testdata/cgo_test.go
+++ b/src/runtime/race/testdata/cgo_test.go
@@ -5,13 +5,14 @@
package race_test
import (
+ "internal/testenv"
"os"
"os/exec"
"testing"
)
func TestNoRaceCgoSync(t *testing.T) {
- cmd := exec.Command("go", "run", "-race", "cgo_test_main.go")
+ cmd := exec.Command(testenv.GoToolPath(t), "run", "-race", "cgo_test_main.go")
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
if err := cmd.Run(); err != nil {
diff --git a/src/runtime/race/testdata/pool_test.go b/src/runtime/race/testdata/pool_test.go
new file mode 100644
index 0000000..161f4b7
--- /dev/null
+++ b/src/runtime/race/testdata/pool_test.go
@@ -0,0 +1,47 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package race_test
+
+import (
+ "sync"
+ "testing"
+ "time"
+)
+
+func TestRacePool(t *testing.T) {
+ // Pool randomly drops the argument on the floor during Put.
+ // Repeat so that at least one iteration gets reuse.
+ for i := 0; i < 10; i++ {
+ c := make(chan int)
+ p := &sync.Pool{New: func() interface{} { return make([]byte, 10) }}
+ x := p.Get().([]byte)
+ x[0] = 1
+ p.Put(x)
+ go func() {
+ y := p.Get().([]byte)
+ y[0] = 2
+ c <- 1
+ }()
+ x[0] = 3
+ <-c
+ }
+}
+
+func TestNoRacePool(t *testing.T) {
+ for i := 0; i < 10; i++ {
+ p := &sync.Pool{New: func() interface{} { return make([]byte, 10) }}
+ x := p.Get().([]byte)
+ x[0] = 1
+ p.Put(x)
+ go func() {
+ y := p.Get().([]byte)
+ y[0] = 2
+ p.Put(y)
+ }()
+ time.Sleep(100 * time.Millisecond)
+ x = p.Get().([]byte)
+ x[0] = 3
+ }
+}
diff --git a/src/runtime/race/testdata/reflect_test.go b/src/runtime/race/testdata/reflect_test.go
new file mode 100644
index 0000000..b567400
--- /dev/null
+++ b/src/runtime/race/testdata/reflect_test.go
@@ -0,0 +1,46 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package race_test
+
+import (
+ "reflect"
+ "testing"
+)
+
+func TestRaceReflectRW(t *testing.T) {
+ ch := make(chan bool, 1)
+ i := 0
+ v := reflect.ValueOf(&i)
+ go func() {
+ v.Elem().Set(reflect.ValueOf(1))
+ ch <- true
+ }()
+ _ = v.Elem().Int()
+ <-ch
+}
+
+func TestRaceReflectWW(t *testing.T) {
+ ch := make(chan bool, 1)
+ i := 0
+ v := reflect.ValueOf(&i)
+ go func() {
+ v.Elem().Set(reflect.ValueOf(1))
+ ch <- true
+ }()
+ v.Elem().Set(reflect.ValueOf(2))
+ <-ch
+}
+
+func TestRaceReflectCopyWW(t *testing.T) {
+ ch := make(chan bool, 1)
+ a := make([]byte, 2)
+ v := reflect.ValueOf(a)
+ go func() {
+ reflect.Copy(v, v)
+ ch <- true
+ }()
+ reflect.Copy(v, v)
+ <-ch
+}
diff --git a/src/runtime/rt0_android_amd64.s b/src/runtime/rt0_android_amd64.s
index 9af6cab..6420c9f 100644
--- a/src/runtime/rt0_android_amd64.s
+++ b/src/runtime/rt0_android_amd64.s
@@ -17,17 +17,10 @@ TEXT _rt0_amd64_android_lib(SB),NOSPLIT,$0
JMP AX
DATA _rt0_amd64_android_argv+0x00(SB)/8,$_rt0_amd64_android_argv0(SB)
-DATA _rt0_amd64_android_argv+0x08(SB)/8,$0
-DATA _rt0_amd64_android_argv+0x10(SB)/8,$0
-DATA _rt0_amd64_android_argv+0x18(SB)/8,$15 // AT_PLATFORM
-DATA _rt0_amd64_android_argv+0x20(SB)/8,$_rt0_amd64_android_auxv0(SB)
-DATA _rt0_amd64_android_argv+0x28(SB)/8,$0
-GLOBL _rt0_amd64_android_argv(SB),NOPTR,$0x30
-
-// TODO: AT_HWCAP necessary? If so, what value?
+DATA _rt0_amd64_android_argv+0x08(SB)/8,$0 // end argv
+DATA _rt0_amd64_android_argv+0x10(SB)/8,$0 // end envv
+DATA _rt0_amd64_android_argv+0x18(SB)/8,$0 // end auxv
+GLOBL _rt0_amd64_android_argv(SB),NOPTR,$0x20
DATA _rt0_amd64_android_argv0(SB)/8, $"gojni"
GLOBL _rt0_amd64_android_argv0(SB),RODATA,$8
-
-DATA _rt0_amd64_android_auxv0(SB)/8, $"x86_64"
-GLOBL _rt0_amd64_android_auxv0(SB),RODATA,$8
diff --git a/src/runtime/rt0_android_arm.s b/src/runtime/rt0_android_arm.s
index 8571253..189e290 100644
--- a/src/runtime/rt0_android_arm.s
+++ b/src/runtime/rt0_android_arm.s
@@ -19,17 +19,10 @@ TEXT _rt0_arm_android_lib(SB),NOSPLIT,$0
RET
DATA _rt0_arm_android_argv+0x00(SB)/4,$_rt0_arm_android_argv0(SB)
-DATA _rt0_arm_android_argv+0x04(SB)/4,$0
-DATA _rt0_arm_android_argv+0x08(SB)/4,$0
-DATA _rt0_arm_android_argv+0x0C(SB)/4,$15 // AT_PLATFORM
-DATA _rt0_arm_android_argv+0x10(SB)/4,$_rt0_arm_android_auxv0(SB)
-DATA _rt0_arm_android_argv+0x14(SB)/4,$16 // AT_HWCAP
-DATA _rt0_arm_android_argv+0x18(SB)/4,$0x2040 // HWCAP_VFP | HWCAP_VFPv3
-DATA _rt0_arm_android_argv+0x1C(SB)/4,$0
-GLOBL _rt0_arm_android_argv(SB),NOPTR,$0x20
+DATA _rt0_arm_android_argv+0x04(SB)/4,$0 // end argv
+DATA _rt0_arm_android_argv+0x08(SB)/4,$0 // end envv
+DATA _rt0_arm_android_argv+0x0c(SB)/4,$0 // end auxv
+GLOBL _rt0_arm_android_argv(SB),NOPTR,$0x10
DATA _rt0_arm_android_argv0(SB)/8, $"gojni"
GLOBL _rt0_arm_android_argv0(SB),RODATA,$8
-
-DATA _rt0_arm_android_auxv0(SB)/4, $"v7l"
-GLOBL _rt0_arm_android_auxv0(SB),RODATA,$4
diff --git a/src/runtime/rt0_android_arm64.s b/src/runtime/rt0_android_arm64.s
index 582fc5a..9378213 100644
--- a/src/runtime/rt0_android_arm64.s
+++ b/src/runtime/rt0_android_arm64.s
@@ -17,9 +17,10 @@ TEXT _rt0_arm64_android_lib(SB),NOSPLIT,$-8
B (R4)
DATA _rt0_arm64_android_argv+0x00(SB)/8,$_rt0_arm64_android_argv0(SB)
-DATA _rt0_arm64_android_argv+0x08(SB)/8,$0
-DATA _rt0_arm64_android_argv+0x10(SB)/8,$0
-GLOBL _rt0_arm64_android_argv(SB),NOPTR,$0x18
+DATA _rt0_arm64_android_argv+0x08(SB)/8,$0 // end argv
+DATA _rt0_arm64_android_argv+0x10(SB)/8,$0 // end envv
+DATA _rt0_arm64_android_argv+0x18(SB)/8,$0 // end auxv
+GLOBL _rt0_arm64_android_argv(SB),NOPTR,$0x20
DATA _rt0_arm64_android_argv0(SB)/8, $"gojni"
GLOBL _rt0_arm64_android_argv0(SB),RODATA,$8
diff --git a/src/runtime/rt0_linux_mipsx.s b/src/runtime/rt0_linux_mipsx.s
new file mode 100644
index 0000000..5e8c5c3
--- /dev/null
+++ b/src/runtime/rt0_linux_mipsx.s
@@ -0,0 +1,27 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build linux
+// +build mips mipsle
+
+#include "textflag.h"
+
+TEXT _rt0_mips_linux(SB),NOSPLIT,$0
+ JMP _main<>(SB)
+
+TEXT _rt0_mipsle_linux(SB),NOSPLIT,$0
+ JMP _main<>(SB)
+
+TEXT _main<>(SB),NOSPLIT,$-4
+ // In a statically linked binary, the stack contains argc,
+ // argv as argc string pointers followed by a NULL, envv as a
+ // sequence of string pointers followed by a NULL, and auxv.
+ // There is no TLS base pointer.
+ MOVW 0(R29), R1 // argc
+ ADD $4, R29, R2 // argv
+ JMP main(SB)
+
+TEXT main(SB),NOSPLIT,$-4
+ MOVW $runtime·rt0_go(SB), R4
+ JMP (R4)
diff --git a/src/runtime/rune.go b/src/runtime/rune.go
deleted file mode 100644
index 99c38e0..0000000
--- a/src/runtime/rune.go
+++ /dev/null
@@ -1,219 +0,0 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson.
- * Copyright (c) 2002 by Lucent Technologies.
- * Portions Copyright 2009 The Go Authors. All rights reserved.
- * Permission to use, copy, modify, and distribute this software for any
- * purpose without fee is hereby granted, provided that this entire notice
- * is included in all copies of any software which is or includes a copy
- * or modification of this software and in all copies of the supporting
- * documentation for such software.
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
- * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
-
-/*
- * This code is copied, with slight editing due to type differences,
- * from a subset of ../lib9/utf/rune.c [which no longer exists]
- */
-
-package runtime
-
-const (
- bit1 = 7
- bitx = 6
- bit2 = 5
- bit3 = 4
- bit4 = 3
- bit5 = 2
-
- t1 = ((1 << (bit1 + 1)) - 1) ^ 0xFF /* 0000 0000 */
- tx = ((1 << (bitx + 1)) - 1) ^ 0xFF /* 1000 0000 */
- t2 = ((1 << (bit2 + 1)) - 1) ^ 0xFF /* 1100 0000 */
- t3 = ((1 << (bit3 + 1)) - 1) ^ 0xFF /* 1110 0000 */
- t4 = ((1 << (bit4 + 1)) - 1) ^ 0xFF /* 1111 0000 */
- t5 = ((1 << (bit5 + 1)) - 1) ^ 0xFF /* 1111 1000 */
-
- rune1 = (1 << (bit1 + 0*bitx)) - 1 /* 0000 0000 0111 1111 */
- rune2 = (1 << (bit2 + 1*bitx)) - 1 /* 0000 0111 1111 1111 */
- rune3 = (1 << (bit3 + 2*bitx)) - 1 /* 1111 1111 1111 1111 */
- rune4 = (1 << (bit4 + 3*bitx)) - 1 /* 0001 1111 1111 1111 1111 1111 */
-
- maskx = (1 << bitx) - 1 /* 0011 1111 */
- testx = maskx ^ 0xFF /* 1100 0000 */
-
- runeerror = 0xFFFD
- runeself = 0x80
-
- surrogateMin = 0xD800
- surrogateMax = 0xDFFF
-
- bad = runeerror
-
- runemax = 0x10FFFF /* maximum rune value */
-)
-
-/*
- * Modified by Wei-Hwa Huang, Google Inc., on 2004-09-24
- * This is a slower but "safe" version of the old chartorune
- * that works on strings that are not necessarily null-terminated.
- *
- * If you know for sure that your string is null-terminated,
- * chartorune will be a bit faster.
- *
- * It is guaranteed not to attempt to access "length"
- * past the incoming pointer. This is to avoid
- * possible access violations. If the string appears to be
- * well-formed but incomplete (i.e., to get the whole Rune
- * we'd need to read past str+length) then we'll set the Rune
- * to Bad and return 0.
- *
- * Note that if we have decoding problems for other
- * reasons, we return 1 instead of 0.
- */
-func charntorune(s string) (rune, int) {
- /* When we're not allowed to read anything */
- if len(s) <= 0 {
- return bad, 1
- }
-
- /*
- * one character sequence (7-bit value)
- * 00000-0007F => T1
- */
- c := s[0]
- if c < tx {
- return rune(c), 1
- }
-
- // If we can't read more than one character we must stop
- if len(s) <= 1 {
- return bad, 1
- }
-
- /*
- * two character sequence (11-bit value)
- * 0080-07FF => t2 tx
- */
- c1 := s[1] ^ tx
- if (c1 & testx) != 0 {
- return bad, 1
- }
- if c < t3 {
- if c < t2 {
- return bad, 1
- }
- l := ((rune(c) << bitx) | rune(c1)) & rune2
- if l <= rune1 {
- return bad, 1
- }
- return l, 2
- }
-
- // If we can't read more than two characters we must stop
- if len(s) <= 2 {
- return bad, 1
- }
-
- /*
- * three character sequence (16-bit value)
- * 0800-FFFF => t3 tx tx
- */
- c2 := s[2] ^ tx
- if (c2 & testx) != 0 {
- return bad, 1
- }
- if c < t4 {
- l := ((((rune(c) << bitx) | rune(c1)) << bitx) | rune(c2)) & rune3
- if l <= rune2 {
- return bad, 1
- }
- if surrogateMin <= l && l <= surrogateMax {
- return bad, 1
- }
- return l, 3
- }
-
- if len(s) <= 3 {
- return bad, 1
- }
-
- /*
- * four character sequence (21-bit value)
- * 10000-1FFFFF => t4 tx tx tx
- */
- c3 := s[3] ^ tx
- if (c3 & testx) != 0 {
- return bad, 1
- }
- if c < t5 {
- l := ((((((rune(c) << bitx) | rune(c1)) << bitx) | rune(c2)) << bitx) | rune(c3)) & rune4
- if l <= rune3 || l > runemax {
- return bad, 1
- }
- return l, 4
- }
-
- // Support for 5-byte or longer UTF-8 would go here, but
- // since we don't have that, we'll just return bad.
- return bad, 1
-}
-
-// runetochar converts r to bytes and writes the result to str.
-// returns the number of bytes generated.
-func runetochar(str []byte, r rune) int {
- /* runes are signed, so convert to unsigned for range check. */
- c := uint32(r)
- /*
- * one character sequence
- * 00000-0007F => 00-7F
- */
- if c <= rune1 {
- str[0] = byte(c)
- return 1
- }
- /*
- * two character sequence
- * 0080-07FF => t2 tx
- */
- if c <= rune2 {
- str[0] = byte(t2 | (c >> (1 * bitx)))
- str[1] = byte(tx | (c & maskx))
- return 2
- }
-
- /*
- * If the rune is out of range or a surrogate half, convert it to the error rune.
- * Do this test here because the error rune encodes to three bytes.
- * Doing it earlier would duplicate work, since an out of range
- * rune wouldn't have fit in one or two bytes.
- */
- if c > runemax {
- c = runeerror
- }
- if surrogateMin <= c && c <= surrogateMax {
- c = runeerror
- }
-
- /*
- * three character sequence
- * 0800-FFFF => t3 tx tx
- */
- if c <= rune3 {
- str[0] = byte(t3 | (c >> (2 * bitx)))
- str[1] = byte(tx | ((c >> (1 * bitx)) & maskx))
- str[2] = byte(tx | (c & maskx))
- return 3
- }
-
- /*
- * four character sequence (21-bit value)
- * 10000-1FFFFF => t4 tx tx tx
- */
- str[0] = byte(t4 | (c >> (3 * bitx)))
- str[1] = byte(tx | ((c >> (2 * bitx)) & maskx))
- str[2] = byte(tx | ((c >> (1 * bitx)) & maskx))
- str[3] = byte(tx | (c & maskx))
- return 4
-}
diff --git a/src/runtime/runtime-gdb_test.go b/src/runtime/runtime-gdb_test.go
index aabe52d..94ba879 100644
--- a/src/runtime/runtime-gdb_test.go
+++ b/src/runtime/runtime-gdb_test.go
@@ -15,6 +15,7 @@ import (
"regexp"
"runtime"
"strconv"
+ "strings"
"testing"
)
@@ -23,6 +24,9 @@ func checkGdbEnvironment(t *testing.T) {
if runtime.GOOS == "darwin" {
t.Skip("gdb does not work on darwin")
}
+ if runtime.GOOS == "linux" && runtime.GOARCH == "ppc64" {
+ t.Skip("skipping gdb tests on linux/ppc64; see golang.org/issue/17366")
+ }
if final := os.Getenv("GOROOT_FINAL"); final != "" && runtime.GOROOT() != final {
t.Skip("gdb test can fail with GOROOT_FINAL pending")
}
@@ -65,18 +69,23 @@ func checkGdbPython(t *testing.T) {
const helloSource = `
package main
import "fmt"
+var gslice []string
func main() {
mapvar := make(map[string]string,5)
mapvar["abc"] = "def"
mapvar["ghi"] = "jkl"
strvar := "abc"
ptrvar := &strvar
- fmt.Println("hi") // line 10
+ slicevar := make([]string, 0, 16)
+ slicevar = append(slicevar, mapvar["abc"])
+ fmt.Println("hi") // line 12
_ = ptrvar
+ gslice = slicevar
}
`
func TestGdbPython(t *testing.T) {
+ t.Parallel()
checkGdbEnvironment(t)
checkGdbVersion(t)
checkGdbPython(t)
@@ -93,7 +102,7 @@ func TestGdbPython(t *testing.T) {
t.Fatalf("failed to create file: %v", err)
}
- cmd := exec.Command("go", "build", "-o", "a.exe")
+ cmd := exec.Command(testenv.GoToolPath(t), "build", "-o", "a.exe")
cmd.Dir = dir
out, err := testEnv(cmd).CombinedOutput()
if err != nil {
@@ -105,31 +114,27 @@ func TestGdbPython(t *testing.T) {
"-ex", "set startup-with-shell off",
"-ex", "info auto-load python-scripts",
"-ex", "set python print-stack full",
- "-ex", "br main.go:10",
+ "-ex", "br fmt.Println",
"-ex", "run",
"-ex", "echo BEGIN info goroutines\n",
"-ex", "info goroutines",
"-ex", "echo END\n",
+ "-ex", "up", // up from fmt.Println to main
"-ex", "echo BEGIN print mapvar\n",
"-ex", "print mapvar",
"-ex", "echo END\n",
"-ex", "echo BEGIN print strvar\n",
"-ex", "print strvar",
- "-ex", "echo END\n"}
-
- // without framepointer, gdb cannot backtrace our non-standard
- // stack frames on RISC architectures.
- canBackTrace := false
- switch runtime.GOARCH {
- case "amd64", "386", "ppc64", "ppc64le", "arm", "arm64", "mips64", "mips64le", "s390x":
- canBackTrace = true
- args = append(args,
- "-ex", "echo BEGIN goroutine 2 bt\n",
- "-ex", "goroutine 2 bt",
- "-ex", "echo END\n")
+ "-ex", "echo END\n",
+ "-ex", "echo BEGIN info locals\n",
+ "-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 2 bt\n",
+ "-ex", "goroutine 2 bt",
+ "-ex", "echo END\n",
+ filepath.Join(dir, "a.exe"),
}
-
- args = append(args, filepath.Join(dir, "a.exe"))
got, _ := exec.Command("gdb", args...).CombinedOutput()
firstLine := bytes.SplitN(got, []byte("\n"), 2)[0]
@@ -137,7 +142,7 @@ func TestGdbPython(t *testing.T) {
// This can happen when using all.bash with
// GOROOT_FINAL set, because the tests are run before
// the final installation of the files.
- cmd := exec.Command("go", "env", "GOROOT")
+ cmd := exec.Command(testenv.GoToolPath(t), "env", "GOROOT")
cmd.Env = []string{}
out, err := cmd.CombinedOutput()
if err != nil && bytes.Contains(out, []byte("cannot find GOROOT")) {
@@ -172,11 +177,18 @@ func TestGdbPython(t *testing.T) {
t.Fatalf("print strvar failed: %s", bl)
}
+ // Issue 16338: ssa decompose phase can split a structure into
+ // a collection of scalar vars holding the fields. In such cases
+ // the DWARF variable location expression should be of the
+ // form "var.field" and not just "field".
+ infoLocalsRe := regexp.MustCompile(`^slicevar.len = `)
+ if bl := blocks["info locals"]; !infoLocalsRe.MatchString(bl) {
+ t.Fatalf("info locals failed: %s", bl)
+ }
+
btGoroutineRe := regexp.MustCompile(`^#0\s+runtime.+at`)
- if bl := blocks["goroutine 2 bt"]; canBackTrace && !btGoroutineRe.MatchString(bl) {
+ if bl := blocks["goroutine 2 bt"]; !btGoroutineRe.MatchString(bl) {
t.Fatalf("goroutine 2 bt failed: %s", bl)
- } else if !canBackTrace {
- t.Logf("gdb cannot backtrace for GOARCH=%s, skipped goroutine backtrace test", runtime.GOARCH)
}
}
@@ -208,6 +220,7 @@ func main() {
// TestGdbBacktrace tests that gdb can unwind the stack correctly
// using only the DWARF debug info.
func TestGdbBacktrace(t *testing.T) {
+ t.Parallel()
checkGdbEnvironment(t)
checkGdbVersion(t)
@@ -227,7 +240,7 @@ func TestGdbBacktrace(t *testing.T) {
if err != nil {
t.Fatalf("failed to create file: %v", err)
}
- cmd := exec.Command("go", "build", "-o", "a.exe")
+ cmd := exec.Command(testenv.GoToolPath(t), "build", "-o", "a.exe")
cmd.Dir = dir
out, err := testEnv(cmd).CombinedOutput()
if err != nil {
@@ -263,3 +276,72 @@ func TestGdbBacktrace(t *testing.T) {
}
}
}
+
+const autotmpTypeSource = `
+package main
+
+type astruct struct {
+ a, b int
+}
+
+func main() {
+ var iface interface{} = map[string]astruct{}
+ var iface2 interface{} = []astruct{}
+ println(iface, iface2)
+}
+`
+
+// TestGdbAutotmpTypes ensures that types of autotmp variables appear in .debug_info
+// See bug #17830.
+func TestGdbAutotmpTypes(t *testing.T) {
+ t.Parallel()
+ checkGdbEnvironment(t)
+ checkGdbVersion(t)
+
+ dir, err := ioutil.TempDir("", "go-build")
+ if err != nil {
+ t.Fatalf("failed to create temp directory: %v", err)
+ }
+ defer os.RemoveAll(dir)
+
+ // Build the source code.
+ src := filepath.Join(dir, "main.go")
+ err = ioutil.WriteFile(src, []byte(autotmpTypeSource), 0644)
+ if err != nil {
+ t.Fatalf("failed to create file: %v", err)
+ }
+ cmd := exec.Command(testenv.GoToolPath(t), "build", "-gcflags=-N -l", "-o", "a.exe")
+ cmd.Dir = dir
+ out, err := testEnv(cmd).CombinedOutput()
+ if err != nil {
+ t.Fatalf("building source %v\n%s", err, out)
+ }
+
+ // Execute gdb commands.
+ args := []string{"-nx", "-batch",
+ "-ex", "set startup-with-shell off",
+ "-ex", "break main.main",
+ "-ex", "run",
+ "-ex", "step",
+ "-ex", "info types astruct",
+ filepath.Join(dir, "a.exe"),
+ }
+ got, _ := exec.Command("gdb", args...).CombinedOutput()
+
+ sgot := string(got)
+
+ // Check that the backtrace matches the source code.
+ types := []string{
+ "struct []main.astruct;",
+ "struct bucket<string,main.astruct>;",
+ "struct hash<string,main.astruct>;",
+ "struct main.astruct;",
+ "typedef struct hash<string,main.astruct> * map[string]main.astruct;",
+ }
+ for _, name := range types {
+ if !strings.Contains(sgot, name) {
+ t.Errorf("could not find %s in 'info typrs astruct' output", name)
+ t.Fatalf("gdb output:\n%v", sgot)
+ }
+ }
+}
diff --git a/src/runtime/runtime-lldb_test.go b/src/runtime/runtime-lldb_test.go
index 4c379b9..98bc906 100644
--- a/src/runtime/runtime-lldb_test.go
+++ b/src/runtime/runtime-lldb_test.go
@@ -158,7 +158,7 @@ func TestLldbPython(t *testing.T) {
t.Fatalf("failed to create file: %v", err)
}
- cmd := exec.Command("go", "build", "-gcflags", "-N -l", "-o", "a.exe")
+ cmd := exec.Command(testenv.GoToolPath(t), "build", "-gcflags", "-N -l", "-o", "a.exe")
cmd.Dir = dir
out, err := cmd.CombinedOutput()
if err != nil {
@@ -198,7 +198,7 @@ func TestDwarfAranges(t *testing.T) {
t.Fatalf("failed to create file: %v", err)
}
- cmd := exec.Command("go", "build", "-o", "a.exe")
+ cmd := exec.Command(testenv.GoToolPath(t), "build", "-o", "a.exe")
cmd.Dir = dir
out, err := cmd.CombinedOutput()
if err != nil {
diff --git a/src/runtime/runtime.go b/src/runtime/runtime.go
index d9c26cc..d8fe2f4 100644
--- a/src/runtime/runtime.go
+++ b/src/runtime/runtime.go
@@ -52,5 +52,8 @@ var argslice []string
//go:linkname syscall_runtime_envs syscall.runtime_envs
func syscall_runtime_envs() []string { return append([]string{}, envs...) }
+//go:linkname syscall_Getpagesize syscall.Getpagesize
+func syscall_Getpagesize() int { return int(physPageSize) }
+
//go:linkname os_runtime_args os.runtime_args
func os_runtime_args() []string { return append([]string{}, argslice...) }
diff --git a/src/runtime/runtime1.go b/src/runtime/runtime1.go
index 302f58d..40c0e85 100644
--- a/src/runtime/runtime1.go
+++ b/src/runtime/runtime1.go
@@ -68,7 +68,6 @@ func goargs() {
if GOOS == "windows" {
return
}
-
argslice = make([]string, argc)
for i := int32(0); i < argc; i++ {
argslice[i] = gostringnocopy(argv_index(argv, i))
@@ -322,6 +321,7 @@ var debug struct {
gcshrinkstackoff int32
gcstackbarrieroff int32
gcstackbarrierall int32
+ gcrescanstacks int32
gcstoptheworld int32
gctrace int32
invalidptr int32
@@ -341,6 +341,7 @@ var dbgvars = []dbgVar{
{"gcshrinkstackoff", &debug.gcshrinkstackoff},
{"gcstackbarrieroff", &debug.gcstackbarrieroff},
{"gcstackbarrierall", &debug.gcstackbarrierall},
+ {"gcrescanstacks", &debug.gcrescanstacks},
{"gcstoptheworld", &debug.gcstoptheworld},
{"gctrace", &debug.gctrace},
{"invalidptr", &debug.invalidptr},
@@ -374,11 +375,15 @@ func parsedebugvars() {
// is int, not int32, and should only be updated
// if specified in GODEBUG.
if key == "memprofilerate" {
- MemProfileRate = atoi(value)
+ if n, ok := atoi(value); ok {
+ MemProfileRate = n
+ }
} else {
for _, v := range dbgvars {
if v.name == key {
- *v.value = int32(atoi(value))
+ if n, ok := atoi32(value); ok {
+ *v.value = n
+ }
}
}
}
@@ -387,6 +392,13 @@ 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
}
@@ -414,7 +426,10 @@ func setTraceback(level string) {
case "crash":
t = 2<<tracebackShift | tracebackAll | tracebackCrash
default:
- t = uint32(atoi(level))<<tracebackShift | tracebackAll
+ t = tracebackAll
+ if n, ok := atoi(level); ok && n == int(uint32(n)) {
+ t |= uint32(n) << tracebackShift
+ }
}
// when C owns the process, simply exit'ing the process on fatal errors
// and panics is surprising. Be louder and abort instead.
@@ -478,11 +493,12 @@ func gomcache() *mcache {
//go:linkname reflect_typelinks reflect.typelinks
func reflect_typelinks() ([]unsafe.Pointer, [][]int32) {
- sections := []unsafe.Pointer{unsafe.Pointer(firstmoduledata.types)}
- ret := [][]int32{firstmoduledata.typelinks}
- for datap := firstmoduledata.next; datap != nil; datap = datap.next {
- sections = append(sections, unsafe.Pointer(datap.types))
- ret = append(ret, datap.typelinks)
+ modules := activeModules()
+ sections := []unsafe.Pointer{unsafe.Pointer(modules[0].types)}
+ ret := [][]int32{modules[0].typelinks}
+ for _, md := range modules[1:] {
+ sections = append(sections, unsafe.Pointer(md.types))
+ ret = append(ret, md.typelinks)
}
return sections, ret
}
diff --git a/src/runtime/runtime2.go b/src/runtime/runtime2.go
index 6119e75..696ea81 100644
--- a/src/runtime/runtime2.go
+++ b/src/runtime/runtime2.go
@@ -205,6 +205,14 @@ func (gp *guintptr) cas(old, new guintptr) bool {
return atomic.Casuintptr((*uintptr)(unsafe.Pointer(gp)), uintptr(old), uintptr(new))
}
+// setGNoWB performs *gp = new without a write barrier.
+// For times when it's impractical to use a guintptr.
+//go:nosplit
+//go:nowritebarrier
+func setGNoWB(gp **g, new *g) {
+ (*guintptr)(unsafe.Pointer(gp)).set(new)
+}
+
type puintptr uintptr
//go:nosplit
@@ -221,8 +229,25 @@ func (mp muintptr) ptr() *m { return (*m)(unsafe.Pointer(mp)) }
//go:nosplit
func (mp *muintptr) set(m *m) { *mp = muintptr(unsafe.Pointer(m)) }
+// setMNoWB performs *mp = new without a write barrier.
+// For times when it's impractical to use an muintptr.
+//go:nosplit
+//go:nowritebarrier
+func setMNoWB(mp **m, new *m) {
+ (*muintptr)(unsafe.Pointer(mp)).set(new)
+}
+
type gobuf struct {
// The offsets of sp, pc, and g are known to (hard-coded in) libmach.
+ //
+ // ctxt is unusual with respect to GC: it may be a
+ // heap-allocated funcval so write require a write barrier,
+ // but gobuf needs to be cleared from assembly. We take
+ // advantage of the fact that the only path that uses a
+ // non-nil ctxt is morestack. As a result, gogo is the only
+ // place where it may not already be nil, so gogo uses an
+ // explicit write barrier. Everywhere else that resets the
+ // gobuf asserts that ctxt is already nil.
sp uintptr
pc uintptr
g guintptr
@@ -256,6 +281,7 @@ type sudog struct {
// The following fields are never accessed concurrently.
// waitlink is only accessed by g.
+ acquiretime int64
releasetime int64
ticket uint32
waitlink *sudog // g.waiting list
@@ -498,7 +524,7 @@ type p struct {
runSafePointFn uint32 // if 1, run sched.safePointFn at next safe point
- pad [64]byte
+ pad [sys.CacheLineSize]byte
}
const (
@@ -575,11 +601,6 @@ const (
_LockInternal = 2
)
-type sigtabtt struct {
- flags int32
- name *int8
-}
-
const (
_SigNotify = 1 << iota // let signal.Notify have signal, even if from kernel
_SigKill // if signal.Notify doesn't take it, exit quietly
diff --git a/src/runtime/runtime_mmap_test.go b/src/runtime/runtime_mmap_test.go
index cf240c1..2eca6b9 100644
--- a/src/runtime/runtime_mmap_test.go
+++ b/src/runtime/runtime_mmap_test.go
@@ -8,15 +8,15 @@ package runtime_test
import (
"runtime"
- "runtime/internal/sys"
"testing"
+ "unsafe"
)
// Test that the error value returned by mmap is positive, as that is
// what the code in mem_bsd.go, mem_darwin.go, and mem_linux.go expects.
// See the uses of ENOMEM in sysMap in those files.
func TestMmapErrorSign(t *testing.T) {
- p := runtime.Mmap(nil, ^uintptr(0)&^(sys.PhysPageSize-1), 0, runtime.MAP_ANON|runtime.MAP_PRIVATE, -1, 0)
+ p := runtime.Mmap(nil, ^uintptr(0)&^(runtime.GetPhysPageSize()-1), 0, runtime.MAP_ANON|runtime.MAP_PRIVATE, -1, 0)
// The runtime.mmap function is nosplit, but t.Errorf is not.
// Reset the pointer so that we don't get an "invalid stack
@@ -28,3 +28,27 @@ func TestMmapErrorSign(t *testing.T) {
t.Errorf("mmap = %v, want %v", v, runtime.ENOMEM)
}
}
+
+func TestPhysPageSize(t *testing.T) {
+ // Mmap fails if the address is not page aligned, so we can
+ // use this to test if the page size is the true page size.
+ ps := runtime.GetPhysPageSize()
+
+ // Get a region of memory to play with. This should be page-aligned.
+ b := uintptr(runtime.Mmap(nil, 2*ps, 0, runtime.MAP_ANON|runtime.MAP_PRIVATE, -1, 0))
+ if b < 4096 {
+ t.Fatalf("Mmap: %v", b)
+ }
+
+ // Mmap should fail at a half page into the buffer.
+ err := uintptr(runtime.Mmap(unsafe.Pointer(uintptr(b)+ps/2), ps, 0, runtime.MAP_ANON|runtime.MAP_PRIVATE|runtime.MAP_FIXED, -1, 0))
+ if err >= 4096 {
+ t.Errorf("Mmap should have failed with half-page alignment %d, but succeeded: %v", ps/2, err)
+ }
+
+ // Mmap should succeed at a full page into the buffer.
+ err = uintptr(runtime.Mmap(unsafe.Pointer(uintptr(b)+ps), ps, 0, runtime.MAP_ANON|runtime.MAP_PRIVATE|runtime.MAP_FIXED, -1, 0))
+ if err < 4096 {
+ t.Errorf("Mmap at full-page alignment %d failed: %v", ps, err)
+ }
+}
diff --git a/src/runtime/select.go b/src/runtime/select.go
index 433048f..03e9e4a 100644
--- a/src/runtime/select.go
+++ b/src/runtime/select.go
@@ -270,7 +270,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(fastrand1()) % (i + 1)
+ j := int(fastrand()) % (i + 1)
pollorder[i] = pollorder[j]
pollorder[j] = uint16(i)
}
@@ -518,7 +518,7 @@ bufrecv:
if cas.elem != nil {
typedmemmove(c.elemtype, cas.elem, qp)
}
- memclr(qp, uintptr(c.elemsize))
+ typedmemclr(c.elemtype, qp)
c.recvx++
if c.recvx == c.dataqsiz {
c.recvx = 0
@@ -564,7 +564,7 @@ rclose:
*cas.receivedp = false
}
if cas.elem != nil {
- memclr(cas.elem, uintptr(c.elemsize))
+ typedmemclr(c.elemtype, cas.elem)
}
if raceenabled {
raceacquire(unsafe.Pointer(c))
diff --git a/src/runtime/sema.go b/src/runtime/sema.go
index 45fbbca..576a1fb 100644
--- a/src/runtime/sema.go
+++ b/src/runtime/sema.go
@@ -44,12 +44,12 @@ var semtable [semTabSize]struct {
//go:linkname sync_runtime_Semacquire sync.runtime_Semacquire
func sync_runtime_Semacquire(addr *uint32) {
- semacquire(addr, true)
+ semacquire(addr, semaBlockProfile)
}
//go:linkname net_runtime_Semacquire net.runtime_Semacquire
func net_runtime_Semacquire(addr *uint32) {
- semacquire(addr, true)
+ semacquire(addr, semaBlockProfile)
}
//go:linkname sync_runtime_Semrelease sync.runtime_Semrelease
@@ -57,6 +57,11 @@ func sync_runtime_Semrelease(addr *uint32) {
semrelease(addr)
}
+//go:linkname sync_runtime_SemacquireMutex sync.runtime_SemacquireMutex
+func sync_runtime_SemacquireMutex(addr *uint32) {
+ semacquire(addr, semaBlockProfile|semaMutexProfile)
+}
+
//go:linkname net_runtime_Semrelease net.runtime_Semrelease
func net_runtime_Semrelease(addr *uint32) {
semrelease(addr)
@@ -69,8 +74,15 @@ func readyWithTime(s *sudog, traceskip int) {
goready(s.g, traceskip)
}
+type semaProfileFlags int
+
+const (
+ semaBlockProfile semaProfileFlags = 1 << iota
+ semaMutexProfile
+)
+
// Called from runtime.
-func semacquire(addr *uint32, profile bool) {
+func semacquire(addr *uint32, profile semaProfileFlags) {
gp := getg()
if gp != gp.m.curg {
throw("semacquire not on the G stack")
@@ -91,10 +103,17 @@ func semacquire(addr *uint32, profile bool) {
root := semroot(addr)
t0 := int64(0)
s.releasetime = 0
- if profile && blockprofilerate > 0 {
+ s.acquiretime = 0
+ if profile&semaBlockProfile != 0 && blockprofilerate > 0 {
t0 = cputicks()
s.releasetime = -1
}
+ if profile&semaMutexProfile != 0 && mutexprofilerate > 0 {
+ if t0 == 0 {
+ t0 = cputicks()
+ }
+ s.acquiretime = t0
+ }
for {
lock(&root.lock)
// Add ourselves to nwait to disable "easy case" in semrelease.
@@ -146,8 +165,19 @@ func semrelease(addr *uint32) {
break
}
}
- unlock(&root.lock)
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
+ }
+ }
+ mutexevent(t0-s.acquiretime, 3)
+ }
+ }
+ unlock(&root.lock)
+ if s != nil { // May be slow, so unlock first
readyWithTime(s, 5)
}
}
diff --git a/src/runtime/sigaction_linux.go b/src/runtime/sigaction_linux.go
new file mode 100644
index 0000000..0b2afb0
--- /dev/null
+++ b/src/runtime/sigaction_linux.go
@@ -0,0 +1,11 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !amd64
+
+package runtime
+
+// rt_sigaction calls the rt_sigaction system call. It is implemented in assembly.
+//go:noescape
+func rt_sigaction(sig uintptr, new, old *sigactiont, size uintptr) int32
diff --git a/src/runtime/signal1_unix.go b/src/runtime/signal1_unix.go
deleted file mode 100644
index 101d16d..0000000
--- a/src/runtime/signal1_unix.go
+++ /dev/null
@@ -1,350 +0,0 @@
-// Copyright 2012 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build darwin dragonfly freebsd linux netbsd openbsd solaris
-
-package runtime
-
-import (
- "runtime/internal/sys"
- "unsafe"
-)
-
-const (
- _SIG_DFL uintptr = 0
- _SIG_IGN uintptr = 1
-)
-
-// Stores the signal handlers registered before Go installed its own.
-// These signal handlers will be invoked in cases where Go doesn't want to
-// handle a particular signal (e.g., signal occurred on a non-Go thread).
-// See sigfwdgo() for more information on when the signals are forwarded.
-//
-// Signal forwarding is currently available only on Darwin and Linux.
-var fwdSig [_NSIG]uintptr
-
-// sigmask represents a general signal mask compatible with the GOOS
-// specific sigset types: the signal numbered x is represented by bit x-1
-// to match the representation expected by sigprocmask.
-type sigmask [(_NSIG + 31) / 32]uint32
-
-// channels for synchronizing signal mask updates with the signal mask
-// thread
-var (
- disableSigChan chan uint32
- enableSigChan chan uint32
- maskUpdatedChan chan struct{}
-)
-
-func init() {
- // _NSIG is the number of signals on this operating system.
- // sigtable should describe what to do for all the possible signals.
- if len(sigtable) != _NSIG {
- print("runtime: len(sigtable)=", len(sigtable), " _NSIG=", _NSIG, "\n")
- throw("bad sigtable len")
- }
-}
-
-var signalsOK bool
-
-// Initialize signals.
-// Called by libpreinit so runtime may not be initialized.
-//go:nosplit
-//go:nowritebarrierrec
-func initsig(preinit bool) {
- if !preinit {
- // It's now OK for signal handlers to run.
- signalsOK = true
- }
-
- // For c-archive/c-shared this is called by libpreinit with
- // preinit == true.
- if (isarchive || islibrary) && !preinit {
- return
- }
-
- for i := int32(0); i < _NSIG; i++ {
- t := &sigtable[i]
- if t.flags == 0 || t.flags&_SigDefault != 0 {
- continue
- }
- fwdSig[i] = getsig(i)
-
- if !sigInstallGoHandler(i) {
- // Even if we are not installing a signal handler,
- // set SA_ONSTACK if necessary.
- if fwdSig[i] != _SIG_DFL && fwdSig[i] != _SIG_IGN {
- setsigstack(i)
- }
- continue
- }
-
- t.flags |= _SigHandling
- setsig(i, funcPC(sighandler), true)
- }
-}
-
-//go:nosplit
-//go:nowritebarrierrec
-func sigInstallGoHandler(sig int32) bool {
- // For some signals, we respect an inherited SIG_IGN handler
- // rather than insist on installing our own default handler.
- // Even these signals can be fetched using the os/signal package.
- switch sig {
- case _SIGHUP, _SIGINT:
- if fwdSig[sig] == _SIG_IGN {
- return false
- }
- }
-
- t := &sigtable[sig]
- if t.flags&_SigSetStack != 0 {
- return false
- }
-
- // When built using c-archive or c-shared, only install signal
- // handlers for synchronous signals.
- if (isarchive || islibrary) && t.flags&_SigPanic == 0 {
- return false
- }
-
- return true
-}
-
-func sigenable(sig uint32) {
- if sig >= uint32(len(sigtable)) {
- return
- }
-
- t := &sigtable[sig]
- if t.flags&_SigNotify != 0 {
- ensureSigM()
- enableSigChan <- sig
- <-maskUpdatedChan
- if t.flags&_SigHandling == 0 {
- t.flags |= _SigHandling
- fwdSig[sig] = getsig(int32(sig))
- setsig(int32(sig), funcPC(sighandler), true)
- }
- }
-}
-
-func sigdisable(sig uint32) {
- if sig >= uint32(len(sigtable)) {
- return
- }
-
- t := &sigtable[sig]
- if t.flags&_SigNotify != 0 {
- ensureSigM()
- disableSigChan <- sig
- <-maskUpdatedChan
-
- // If initsig does not install a signal handler for a
- // signal, then to go back to the state before Notify
- // we should remove the one we installed.
- if !sigInstallGoHandler(int32(sig)) {
- t.flags &^= _SigHandling
- setsig(int32(sig), fwdSig[sig], true)
- }
- }
-}
-
-func sigignore(sig uint32) {
- if sig >= uint32(len(sigtable)) {
- return
- }
-
- t := &sigtable[sig]
- if t.flags&_SigNotify != 0 {
- t.flags &^= _SigHandling
- setsig(int32(sig), _SIG_IGN, true)
- }
-}
-
-func resetcpuprofiler(hz int32) {
- var it itimerval
- if hz == 0 {
- setitimer(_ITIMER_PROF, &it, nil)
- } else {
- it.it_interval.tv_sec = 0
- it.it_interval.set_usec(1000000 / hz)
- it.it_value = it.it_interval
- setitimer(_ITIMER_PROF, &it, nil)
- }
- _g_ := getg()
- _g_.m.profilehz = hz
-}
-
-func sigpipe() {
- if sigsend(_SIGPIPE) {
- return
- }
- dieFromSignal(_SIGPIPE)
-}
-
-// dieFromSignal kills the program with a signal.
-// This provides the expected exit status for the shell.
-// This is only called with fatal signals expected to kill the process.
-//go:nosplit
-//go:nowritebarrierrec
-func dieFromSignal(sig int32) {
- setsig(sig, _SIG_DFL, false)
- updatesigmask(sigmask{})
- raise(sig)
-
- // That should have killed us. On some systems, though, raise
- // sends the signal to the whole process rather than to just
- // the current thread, which means that the signal may not yet
- // have been delivered. Give other threads a chance to run and
- // pick up the signal.
- osyield()
- osyield()
- osyield()
-
- // If we are still somehow running, just exit with the wrong status.
- exit(2)
-}
-
-// raisebadsignal is called when a signal is received on a non-Go
-// thread, and the Go program does not want to handle it (that is, the
-// program has not called os/signal.Notify for the signal).
-func raisebadsignal(sig int32, c *sigctxt) {
- if sig == _SIGPROF {
- // Ignore profiling signals that arrive on non-Go threads.
- return
- }
-
- var handler uintptr
- if sig >= _NSIG {
- handler = _SIG_DFL
- } else {
- handler = fwdSig[sig]
- }
-
- // Reset the signal handler and raise the signal.
- // We are currently running inside a signal handler, so the
- // signal is blocked. We need to unblock it before raising the
- // signal, or the signal we raise will be ignored until we return
- // from the signal handler. We know that the signal was unblocked
- // before entering the handler, or else we would not have received
- // it. That means that we don't have to worry about blocking it
- // again.
- unblocksig(sig)
- setsig(sig, handler, false)
-
- // If we're linked into a non-Go program we want to try to
- // avoid modifying the original context in which the signal
- // was raised. If the handler is the default, we know it
- // is non-recoverable, so we don't have to worry about
- // re-installing sighandler. At this point we can just
- // return and the signal will be re-raised and caught by
- // the default handler with the correct context.
- if (isarchive || islibrary) && handler == _SIG_DFL && c.sigcode() != _SI_USER {
- return
- }
-
- raise(sig)
-
- // If the signal didn't cause the program to exit, restore the
- // Go signal handler and carry on.
- //
- // We may receive another instance of the signal before we
- // restore the Go handler, but that is not so bad: we know
- // that the Go program has been ignoring the signal.
- setsig(sig, funcPC(sighandler), true)
-}
-
-func crash() {
- if GOOS == "darwin" {
- // OS X core dumps are linear dumps of the mapped memory,
- // from the first virtual byte to the last, with zeros in the gaps.
- // Because of the way we arrange the address space on 64-bit systems,
- // this means the OS X core file will be >128 GB and even on a zippy
- // workstation can take OS X well over an hour to write (uninterruptible).
- // Save users from making that mistake.
- if sys.PtrSize == 8 {
- return
- }
- }
-
- dieFromSignal(_SIGABRT)
-}
-
-// ensureSigM starts one global, sleeping thread to make sure at least one thread
-// is available to catch signals enabled for os/signal.
-func ensureSigM() {
- if maskUpdatedChan != nil {
- return
- }
- maskUpdatedChan = make(chan struct{})
- disableSigChan = make(chan uint32)
- enableSigChan = make(chan uint32)
- go func() {
- // Signal masks are per-thread, so make sure this goroutine stays on one
- // thread.
- LockOSThread()
- defer UnlockOSThread()
- // The sigBlocked mask contains the signals not active for os/signal,
- // initially all signals except the essential. When signal.Notify()/Stop is called,
- // sigenable/sigdisable in turn notify this thread to update its signal
- // mask accordingly.
- var sigBlocked sigmask
- for i := range sigBlocked {
- sigBlocked[i] = ^uint32(0)
- }
- for i := range sigtable {
- if sigtable[i].flags&_SigUnblock != 0 {
- sigBlocked[(i-1)/32] &^= 1 << ((uint32(i) - 1) & 31)
- }
- }
- updatesigmask(sigBlocked)
- for {
- select {
- case sig := <-enableSigChan:
- if b := sig - 1; sig > 0 {
- sigBlocked[b/32] &^= (1 << (b & 31))
- }
- case sig := <-disableSigChan:
- if b := sig - 1; sig > 0 {
- sigBlocked[b/32] |= (1 << (b & 31))
- }
- }
- updatesigmask(sigBlocked)
- maskUpdatedChan <- struct{}{}
- }
- }()
-}
-
-// This is called when we receive a signal when there is no signal stack.
-// This can only happen if non-Go code calls sigaltstack to disable the
-// signal stack. This is called via cgocallback to establish a stack.
-func noSignalStack(sig uint32) {
- println("signal", sig, "received on thread with no signal stack")
- throw("non-Go code disabled sigaltstack")
-}
-
-// This is called if we receive a signal when there is a signal stack
-// but we are not on it. This can only happen if non-Go code called
-// sigaction without setting the SS_ONSTACK flag.
-func sigNotOnStack(sig uint32) {
- println("signal", sig, "received but handler not on signal stack")
- throw("non-Go code set up signal handler without SA_ONSTACK flag")
-}
-
-// This runs on a foreign stack, without an m or a g. No stack split.
-//go:nosplit
-//go:norace
-//go:nowritebarrierrec
-func badsignal(sig uintptr, c *sigctxt) {
- cgocallback(unsafe.Pointer(funcPC(badsignalgo)), noescape(unsafe.Pointer(&sig)), unsafe.Sizeof(sig)+unsafe.Sizeof(c), 0)
-}
-
-func badsignalgo(sig uintptr, c *sigctxt) {
- if !sigsend(uint32(sig)) {
- // A foreign thread received the signal sig, and the
- // Go code does not want to handle it.
- raisebadsignal(int32(sig), c)
- }
-}
diff --git a/src/runtime/signal2_unix.go b/src/runtime/signal2_unix.go
deleted file mode 100644
index b137169..0000000
--- a/src/runtime/signal2_unix.go
+++ /dev/null
@@ -1,69 +0,0 @@
-// Copyright 2012 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build darwin dragonfly freebsd linux netbsd openbsd
-
-package runtime
-
-import "unsafe"
-
-//go:noescape
-func sigfwd(fn uintptr, sig uint32, info *siginfo, ctx unsafe.Pointer)
-
-// Determines if the signal should be handled by Go and if not, forwards the
-// signal to the handler that was installed before Go's. Returns whether the
-// signal was forwarded.
-// This is called by the signal handler, and the world may be stopped.
-//go:nosplit
-//go:nowritebarrierrec
-func sigfwdgo(sig uint32, info *siginfo, ctx unsafe.Pointer) bool {
- if sig >= uint32(len(sigtable)) {
- return false
- }
- fwdFn := fwdSig[sig]
-
- if !signalsOK {
- // The only way we can get here is if we are in a
- // library or archive, we installed a signal handler
- // at program startup, but the Go runtime has not yet
- // been initialized.
- if fwdFn == _SIG_DFL {
- dieFromSignal(int32(sig))
- } else {
- sigfwd(fwdFn, sig, info, ctx)
- }
- 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 {
- sigfwd(fwdFn, sig, info, ctx)
- return true
- }
-
- // Only forward synchronous signals.
- c := &sigctxt{info, ctx}
- if c.sigcode() == _SI_USER || flags&_SigPanic == 0 {
- return false
- }
- // Determine if the signal occurred inside Go code. We test that:
- // (1) we were in a goroutine (i.e., m.curg != nil), and
- // (2) we weren't in CGO (i.e., m.curg.syscallsp == 0).
- g := getg()
- if g != nil && g.m != nil && g.m.curg != nil && g.m.curg.syscallsp == 0 {
- return false
- }
- // Signal not handled by Go, forward it.
- if fwdFn != _SIG_IGN {
- sigfwd(fwdFn, sig, info, ctx)
- }
- return true
-}
diff --git a/src/runtime/signal_386.go b/src/runtime/signal_386.go
index f27cf9d..8807552 100644
--- a/src/runtime/signal_386.go
+++ b/src/runtime/signal_386.go
@@ -27,152 +27,57 @@ func dumpregs(c *sigctxt) {
print("gs ", hex(c.gs()), "\n")
}
-var crashing int32
-
-// May run during STW, so write barriers are not allowed.
-//
+//go:nosplit
//go:nowritebarrierrec
-func sighandler(sig uint32, info *siginfo, ctxt unsafe.Pointer, gp *g) {
- _g_ := getg()
- c := &sigctxt{info, ctxt}
-
- if sig == _SIGPROF {
- sigprof(uintptr(c.eip()), uintptr(c.esp()), 0, gp, _g_.m)
- return
- }
-
- flags := int32(_SigThrow)
- if sig < uint32(len(sigtable)) {
- flags = sigtable[sig].flags
- }
- if c.sigcode() != _SI_USER && flags&_SigPanic != 0 {
- // Make it look like a call to the signal func.
- // Have to pass arguments out of band since
- // augmenting the stack frame would break
- // the unwinding code.
- gp.sig = sig
- gp.sigcode0 = uintptr(c.sigcode())
- gp.sigcode1 = uintptr(c.sigaddr())
- gp.sigpc = uintptr(c.eip())
-
- if GOOS == "darwin" {
- // Work around Leopard bug that doesn't set FPE_INTDIV.
- // Look at instruction to see if it is a divide.
- // Not necessary in Snow Leopard (si_code will be != 0).
- if sig == _SIGFPE && gp.sigcode0 == 0 {
- pc := (*[4]byte)(unsafe.Pointer(gp.sigpc))
- i := 0
- if pc[i] == 0x66 { // 16-bit instruction prefix
- i++
- }
- if pc[i] == 0xF6 || pc[i] == 0xF7 {
- gp.sigcode0 = _FPE_INTDIV
- }
+func (c *sigctxt) sigpc() uintptr { return uintptr(c.eip()) }
+
+func (c *sigctxt) sigsp() uintptr { return uintptr(c.esp()) }
+func (c *sigctxt) siglr() uintptr { return 0 }
+func (c *sigctxt) fault() uintptr { return uintptr(c.sigaddr()) }
+
+// preparePanic sets up the stack to look like a call to sigpanic.
+func (c *sigctxt) preparePanic(sig uint32, gp *g) {
+ if GOOS == "darwin" {
+ // Work around Leopard bug that doesn't set FPE_INTDIV.
+ // Look at instruction to see if it is a divide.
+ // Not necessary in Snow Leopard (si_code will be != 0).
+ if sig == _SIGFPE && gp.sigcode0 == 0 {
+ pc := (*[4]byte)(unsafe.Pointer(gp.sigpc))
+ i := 0
+ if pc[i] == 0x66 { // 16-bit instruction prefix
+ i++
}
- }
-
- pc := uintptr(c.eip())
- sp := uintptr(c.esp())
-
- // If we don't recognize the PC as code
- // but we do recognize the top pointer on the stack as code,
- // then assume this was a call to non-code and treat like
- // pc == 0, to make unwinding show the context.
- if pc != 0 && findfunc(pc) == nil && findfunc(*(*uintptr)(unsafe.Pointer(sp))) != nil {
- pc = 0
- }
-
- // Only push runtime.sigpanic if pc != 0.
- // If pc == 0, probably panicked because of a
- // call to a nil func. Not pushing that onto sp will
- // make the trace look like a call to runtime.sigpanic instead.
- // (Otherwise the trace will end at runtime.sigpanic and we
- // won't get to see who faulted.)
- if pc != 0 {
- if sys.RegSize > sys.PtrSize {
- sp -= sys.PtrSize
- *(*uintptr)(unsafe.Pointer(sp)) = 0
+ if pc[i] == 0xF6 || pc[i] == 0xF7 {
+ gp.sigcode0 = _FPE_INTDIV
}
- sp -= sys.PtrSize
- *(*uintptr)(unsafe.Pointer(sp)) = pc
- c.set_esp(uint32(sp))
- }
- c.set_eip(uint32(funcPC(sigpanic)))
- return
- }
-
- if c.sigcode() == _SI_USER || flags&_SigNotify != 0 {
- if sigsend(sig) {
- return
}
}
- if c.sigcode() == _SI_USER && signal_ignored(sig) {
- return
- }
-
- if flags&_SigKill != 0 {
- dieFromSignal(int32(sig))
- }
-
- if flags&_SigThrow == 0 {
- return
- }
-
- _g_.m.throwing = 1
- _g_.m.caughtsig.set(gp)
-
- if crashing == 0 {
- startpanic()
- }
+ pc := uintptr(c.eip())
+ sp := uintptr(c.esp())
- if sig < uint32(len(sigtable)) {
- print(sigtable[sig].name, "\n")
- } else {
- print("Signal ", sig, "\n")
+ // If we don't recognize the PC as code
+ // but we do recognize the top pointer on the stack as code,
+ // then assume this was a call to non-code and treat like
+ // pc == 0, to make unwinding show the context.
+ if pc != 0 && findfunc(pc) == nil && findfunc(*(*uintptr)(unsafe.Pointer(sp))) != nil {
+ pc = 0
}
- print("PC=", hex(c.eip()), " m=", _g_.m.id, "\n")
- if _g_.m.lockedg != nil && _g_.m.ncgo > 0 && gp == _g_.m.g0 {
- print("signal arrived during cgo execution\n")
- gp = _g_.m.lockedg
- }
- print("\n")
-
- level, _, docrash := gotraceback()
- if level > 0 {
- goroutineheader(gp)
- tracebacktrap(uintptr(c.eip()), uintptr(c.esp()), 0, gp)
- if crashing > 0 && gp != _g_.m.curg && _g_.m.curg != nil && readgstatus(_g_.m.curg)&^_Gscan == _Grunning {
- // tracebackothers on original m skipped this one; trace it now.
- goroutineheader(_g_.m.curg)
- traceback(^uintptr(0), ^uintptr(0), 0, gp)
- } else if crashing == 0 {
- tracebackothers(gp)
- print("\n")
- }
- dumpregs(c)
- }
-
- if docrash {
- crashing++
- if crashing < sched.mcount {
- // There are other m's that need to dump their stacks.
- // Relay SIGQUIT to the next m by sending it to the current process.
- // All m's that have already received SIGQUIT have signal masks blocking
- // receipt of any signals, so the SIGQUIT will go to an m that hasn't seen it yet.
- // When the last m receives the SIGQUIT, it will fall through to the call to
- // crash below. Just in case the relaying gets botched, each m involved in
- // the relay sleeps for 5 seconds and then does the crash/exit itself.
- // In expected operation, the last m has received the SIGQUIT and run
- // crash/exit and the process is gone, all long before any of the
- // 5-second sleeps have finished.
- print("\n-----\n\n")
- raiseproc(_SIGQUIT)
- usleep(5 * 1000 * 1000)
+ // Only push runtime.sigpanic if pc != 0.
+ // If pc == 0, probably panicked because of a
+ // call to a nil func. Not pushing that onto sp will
+ // make the trace look like a call to runtime.sigpanic instead.
+ // (Otherwise the trace will end at runtime.sigpanic and we
+ // won't get to see who faulted.)
+ if pc != 0 {
+ if sys.RegSize > sys.PtrSize {
+ sp -= sys.PtrSize
+ *(*uintptr)(unsafe.Pointer(sp)) = 0
}
- crash()
+ sp -= sys.PtrSize
+ *(*uintptr)(unsafe.Pointer(sp)) = pc
+ c.set_esp(uint32(sp))
}
-
- exit(2)
+ c.set_eip(uint32(funcPC(sigpanic)))
}
diff --git a/src/runtime/signal_amd64x.go b/src/runtime/signal_amd64x.go
index 7b51fcc..c8a6513 100644
--- a/src/runtime/signal_amd64x.go
+++ b/src/runtime/signal_amd64x.go
@@ -36,175 +36,59 @@ func dumpregs(c *sigctxt) {
print("gs ", hex(c.gs()), "\n")
}
-var crashing int32
-
-// May run during STW, so write barriers are not allowed.
-//
+//go:nosplit
//go:nowritebarrierrec
-func sighandler(sig uint32, info *siginfo, ctxt unsafe.Pointer, gp *g) {
- _g_ := getg()
- c := &sigctxt{info, ctxt}
+func (c *sigctxt) sigpc() uintptr { return uintptr(c.rip()) }
- if sig == _SIGPROF {
- sigprof(uintptr(c.rip()), uintptr(c.rsp()), 0, gp, _g_.m)
- return
- }
+func (c *sigctxt) sigsp() uintptr { return uintptr(c.rsp()) }
+func (c *sigctxt) siglr() uintptr { return 0 }
+func (c *sigctxt) fault() uintptr { return uintptr(c.sigaddr()) }
+// preparePanic sets up the stack to look like a call to sigpanic.
+func (c *sigctxt) preparePanic(sig uint32, gp *g) {
if GOOS == "darwin" {
- // x86-64 has 48-bit virtual addresses. The top 16 bits must echo bit 47.
- // The hardware delivers a different kind of fault for a malformed address
- // than it does for an attempt to access a valid but unmapped address.
- // OS X 10.9.2 mishandles the malformed address case, making it look like
- // a user-generated signal (like someone ran kill -SEGV ourpid).
- // We pass user-generated signals to os/signal, or else ignore them.
- // Doing that here - and returning to the faulting code - results in an
- // infinite loop. It appears the best we can do is rewrite what the kernel
- // delivers into something more like the truth. The address used below
- // has very little chance of being the one that caused the fault, but it is
- // malformed, it is clearly not a real pointer, and if it does get printed
- // in real life, people will probably search for it and find this code.
- // There are no Google hits for b01dfacedebac1e or 0xb01dfacedebac1e
- // as I type this comment.
- if sig == _SIGSEGV && c.sigcode() == _SI_USER {
- c.set_sigcode(_SI_USER + 1)
- c.set_sigaddr(0xb01dfacedebac1e)
- }
- }
-
- flags := int32(_SigThrow)
- if sig < uint32(len(sigtable)) {
- flags = sigtable[sig].flags
- }
- if c.sigcode() != _SI_USER && flags&_SigPanic != 0 {
- // Make it look like a call to the signal func.
- // Have to pass arguments out of band since
- // augmenting the stack frame would break
- // the unwinding code.
- gp.sig = sig
- gp.sigcode0 = uintptr(c.sigcode())
- gp.sigcode1 = uintptr(c.sigaddr())
- gp.sigpc = uintptr(c.rip())
-
- if GOOS == "darwin" {
- // Work around Leopard bug that doesn't set FPE_INTDIV.
- // Look at instruction to see if it is a divide.
- // Not necessary in Snow Leopard (si_code will be != 0).
- if sig == _SIGFPE && gp.sigcode0 == 0 {
- pc := (*[4]byte)(unsafe.Pointer(gp.sigpc))
- i := 0
- if pc[i]&0xF0 == 0x40 { // 64-bit REX prefix
- i++
- } else if pc[i] == 0x66 { // 16-bit instruction prefix
- i++
- }
- if pc[i] == 0xF6 || pc[i] == 0xF7 {
- gp.sigcode0 = _FPE_INTDIV
- }
+ // Work around Leopard bug that doesn't set FPE_INTDIV.
+ // Look at instruction to see if it is a divide.
+ // Not necessary in Snow Leopard (si_code will be != 0).
+ if sig == _SIGFPE && gp.sigcode0 == 0 {
+ pc := (*[4]byte)(unsafe.Pointer(gp.sigpc))
+ i := 0
+ if pc[i]&0xF0 == 0x40 { // 64-bit REX prefix
+ i++
+ } else if pc[i] == 0x66 { // 16-bit instruction prefix
+ i++
}
- }
-
- pc := uintptr(c.rip())
- sp := uintptr(c.rsp())
-
- // If we don't recognize the PC as code
- // but we do recognize the top pointer on the stack as code,
- // then assume this was a call to non-code and treat like
- // pc == 0, to make unwinding show the context.
- if pc != 0 && findfunc(pc) == nil && findfunc(*(*uintptr)(unsafe.Pointer(sp))) != nil {
- pc = 0
- }
-
- // Only push runtime.sigpanic if pc != 0.
- // If pc == 0, probably panicked because of a
- // call to a nil func. Not pushing that onto sp will
- // make the trace look like a call to runtime.sigpanic instead.
- // (Otherwise the trace will end at runtime.sigpanic and we
- // won't get to see who faulted.)
- if pc != 0 {
- if sys.RegSize > sys.PtrSize {
- sp -= sys.PtrSize
- *(*uintptr)(unsafe.Pointer(sp)) = 0
+ if pc[i] == 0xF6 || pc[i] == 0xF7 {
+ gp.sigcode0 = _FPE_INTDIV
}
- sp -= sys.PtrSize
- *(*uintptr)(unsafe.Pointer(sp)) = pc
- c.set_rsp(uint64(sp))
}
- c.set_rip(uint64(funcPC(sigpanic)))
- return
}
- if c.sigcode() == _SI_USER || flags&_SigNotify != 0 {
- if sigsend(sig) {
- return
- }
- }
+ pc := uintptr(c.rip())
+ sp := uintptr(c.rsp())
- if c.sigcode() == _SI_USER && signal_ignored(sig) {
- return
+ // If we don't recognize the PC as code
+ // but we do recognize the top pointer on the stack as code,
+ // then assume this was a call to non-code and treat like
+ // pc == 0, to make unwinding show the context.
+ if pc != 0 && findfunc(pc) == nil && findfunc(*(*uintptr)(unsafe.Pointer(sp))) != nil {
+ pc = 0
}
- if flags&_SigKill != 0 {
- dieFromSignal(int32(sig))
- }
-
- if flags&_SigThrow == 0 {
- return
- }
-
- _g_.m.throwing = 1
- _g_.m.caughtsig.set(gp)
-
- if crashing == 0 {
- startpanic()
- }
-
- if sig < uint32(len(sigtable)) {
- print(sigtable[sig].name, "\n")
- } else {
- print("Signal ", sig, "\n")
- }
-
- print("PC=", hex(c.rip()), " m=", _g_.m.id, "\n")
- if _g_.m.lockedg != nil && _g_.m.ncgo > 0 && gp == _g_.m.g0 {
- print("signal arrived during cgo execution\n")
- gp = _g_.m.lockedg
- }
- print("\n")
-
- level, _, docrash := gotraceback()
- if level > 0 {
- goroutineheader(gp)
- tracebacktrap(uintptr(c.rip()), uintptr(c.rsp()), 0, gp)
- if crashing > 0 && gp != _g_.m.curg && _g_.m.curg != nil && readgstatus(_g_.m.curg)&^_Gscan == _Grunning {
- // tracebackothers on original m skipped this one; trace it now.
- goroutineheader(_g_.m.curg)
- traceback(^uintptr(0), ^uintptr(0), 0, gp)
- } else if crashing == 0 {
- tracebackothers(gp)
- print("\n")
- }
- dumpregs(c)
- }
-
- if docrash {
- crashing++
- if crashing < sched.mcount {
- // There are other m's that need to dump their stacks.
- // Relay SIGQUIT to the next m by sending it to the current process.
- // All m's that have already received SIGQUIT have signal masks blocking
- // receipt of any signals, so the SIGQUIT will go to an m that hasn't seen it yet.
- // When the last m receives the SIGQUIT, it will fall through to the call to
- // crash below. Just in case the relaying gets botched, each m involved in
- // the relay sleeps for 5 seconds and then does the crash/exit itself.
- // In expected operation, the last m has received the SIGQUIT and run
- // crash/exit and the process is gone, all long before any of the
- // 5-second sleeps have finished.
- print("\n-----\n\n")
- raiseproc(_SIGQUIT)
- usleep(5 * 1000 * 1000)
+ // Only push runtime.sigpanic if pc != 0.
+ // If pc == 0, probably panicked because of a
+ // call to a nil func. Not pushing that onto sp will
+ // make the trace look like a call to runtime.sigpanic instead.
+ // (Otherwise the trace will end at runtime.sigpanic and we
+ // won't get to see who faulted.)
+ if pc != 0 {
+ if sys.RegSize > sys.PtrSize {
+ sp -= sys.PtrSize
+ *(*uintptr)(unsafe.Pointer(sp)) = 0
}
- crash()
+ sp -= sys.PtrSize
+ *(*uintptr)(unsafe.Pointer(sp)) = pc
+ c.set_rsp(uint64(sp))
}
-
- exit(2)
+ c.set_rip(uint64(funcPC(sigpanic)))
}
diff --git a/src/runtime/signal_arm.go b/src/runtime/signal_arm.go
index 3b8eaf6..9748544 100644
--- a/src/runtime/signal_arm.go
+++ b/src/runtime/signal_arm.go
@@ -32,139 +32,43 @@ func dumpregs(c *sigctxt) {
print("fault ", hex(c.fault()), "\n")
}
-var crashing int32
-
-// May run during STW, so write barriers are not allowed.
-//
+//go:nosplit
//go:nowritebarrierrec
-func sighandler(sig uint32, info *siginfo, ctxt unsafe.Pointer, gp *g) {
- _g_ := getg()
- c := &sigctxt{info, ctxt}
-
- if sig == _SIGPROF {
- sigprof(uintptr(c.pc()), uintptr(c.sp()), uintptr(c.lr()), gp, _g_.m)
- return
- }
-
- flags := int32(_SigThrow)
- if sig < uint32(len(sigtable)) {
- flags = sigtable[sig].flags
- }
- if c.sigcode() != _SI_USER && flags&_SigPanic != 0 {
- // Make it look like a call to the signal func.
- // Have to pass arguments out of band since
- // augmenting the stack frame would break
- // the unwinding code.
- gp.sig = sig
- gp.sigcode0 = uintptr(c.sigcode())
- gp.sigcode1 = uintptr(c.fault())
- gp.sigpc = uintptr(c.pc())
-
- // We arrange lr, and pc to pretend the panicking
- // function calls sigpanic directly.
- // Always save LR to stack so that panics in leaf
- // functions are correctly handled. This smashes
- // the stack frame but we're not going back there
- // anyway.
- sp := c.sp() - 4
- c.set_sp(sp)
- *(*uint32)(unsafe.Pointer(uintptr(sp))) = c.lr()
-
- pc := gp.sigpc
-
- // If we don't recognize the PC as code
- // but we do recognize the link register as code,
- // then assume this was a call to non-code and treat like
- // pc == 0, to make unwinding show the context.
- if pc != 0 && findfunc(pc) == nil && findfunc(uintptr(c.lr())) != nil {
- pc = 0
- }
-
- // Don't bother saving PC if it's zero, which is
- // probably a call to a nil func: the old link register
- // is more useful in the stack trace.
- if pc != 0 {
- c.set_lr(uint32(pc))
- }
-
- // In case we are panicking from external C code
- c.set_r10(uint32(uintptr(unsafe.Pointer(gp))))
- c.set_pc(uint32(funcPC(sigpanic)))
- return
- }
-
- if c.sigcode() == _SI_USER || flags&_SigNotify != 0 {
- if sigsend(sig) {
- return
- }
- }
-
- if c.sigcode() == _SI_USER && signal_ignored(sig) {
- return
- }
-
- if flags&_SigKill != 0 {
- dieFromSignal(int32(sig))
- }
-
- if flags&_SigThrow == 0 {
- return
- }
-
- _g_.m.throwing = 1
- _g_.m.caughtsig.set(gp)
-
- if crashing == 0 {
- startpanic()
- }
-
- if sig < uint32(len(sigtable)) {
- print(sigtable[sig].name, "\n")
- } else {
- print("Signal ", sig, "\n")
- }
-
- print("PC=", hex(c.pc()), " m=", _g_.m.id, "\n")
- if _g_.m.lockedg != nil && _g_.m.ncgo > 0 && gp == _g_.m.g0 {
- print("signal arrived during cgo execution\n")
- gp = _g_.m.lockedg
- }
- print("\n")
-
- level, _, docrash := gotraceback()
- if level > 0 {
- goroutineheader(gp)
- tracebacktrap(uintptr(c.pc()), uintptr(c.sp()), uintptr(c.lr()), gp)
- if crashing > 0 && gp != _g_.m.curg && _g_.m.curg != nil && readgstatus(_g_.m.curg)&^_Gscan == _Grunning {
- // tracebackothers on original m skipped this one; trace it now.
- goroutineheader(_g_.m.curg)
- traceback(^uintptr(0), ^uintptr(0), 0, gp)
- } else if crashing == 0 {
- tracebackothers(gp)
- print("\n")
- }
- dumpregs(c)
+func (c *sigctxt) sigpc() uintptr { return uintptr(c.pc()) }
+
+func (c *sigctxt) sigsp() uintptr { return uintptr(c.sp()) }
+func (c *sigctxt) siglr() uintptr { return uintptr(c.lr()) }
+
+// preparePanic sets up the stack to look like a call to sigpanic.
+func (c *sigctxt) preparePanic(sig uint32, gp *g) {
+ // We arrange lr, and pc to pretend the panicking
+ // function calls sigpanic directly.
+ // Always save LR to stack so that panics in leaf
+ // functions are correctly handled. This smashes
+ // the stack frame but we're not going back there
+ // anyway.
+ sp := c.sp() - 4
+ c.set_sp(sp)
+ *(*uint32)(unsafe.Pointer(uintptr(sp))) = c.lr()
+
+ pc := gp.sigpc
+
+ // If we don't recognize the PC as code
+ // but we do recognize the link register as code,
+ // then assume this was a call to non-code and treat like
+ // pc == 0, to make unwinding show the context.
+ if pc != 0 && findfunc(pc) == nil && findfunc(uintptr(c.lr())) != nil {
+ pc = 0
}
- if docrash {
- crashing++
- if crashing < sched.mcount {
- // There are other m's that need to dump their stacks.
- // Relay SIGQUIT to the next m by sending it to the current process.
- // All m's that have already received SIGQUIT have signal masks blocking
- // receipt of any signals, so the SIGQUIT will go to an m that hasn't seen it yet.
- // When the last m receives the SIGQUIT, it will fall through to the call to
- // crash below. Just in case the relaying gets botched, each m involved in
- // the relay sleeps for 5 seconds and then does the crash/exit itself.
- // In expected operation, the last m has received the SIGQUIT and run
- // crash/exit and the process is gone, all long before any of the
- // 5-second sleeps have finished.
- print("\n-----\n\n")
- raiseproc(_SIGQUIT)
- usleep(5 * 1000 * 1000)
- }
- crash()
+ // Don't bother saving PC if it's zero, which is
+ // probably a call to a nil func: the old link register
+ // is more useful in the stack trace.
+ if pc != 0 {
+ c.set_lr(uint32(pc))
}
- exit(2)
+ // In case we are panicking from external C code
+ c.set_r10(uint32(uintptr(unsafe.Pointer(gp))))
+ c.set_pc(uint32(funcPC(sigpanic)))
}
diff --git a/src/runtime/signal_arm64.go b/src/runtime/signal_arm64.go
index 0e08623..4c6df42 100644
--- a/src/runtime/signal_arm64.go
+++ b/src/runtime/signal_arm64.go
@@ -48,139 +48,43 @@ func dumpregs(c *sigctxt) {
print("fault ", hex(c.fault()), "\n")
}
-var crashing int32
-
-// May run during STW, so write barriers are not allowed.
-//
+//go:nosplit
//go:nowritebarrierrec
-func sighandler(sig uint32, info *siginfo, ctxt unsafe.Pointer, gp *g) {
- _g_ := getg()
- c := &sigctxt{info, ctxt}
-
- if sig == _SIGPROF {
- sigprof(uintptr(c.pc()), uintptr(c.sp()), uintptr(c.lr()), gp, _g_.m)
- return
- }
-
- flags := int32(_SigThrow)
- if sig < uint32(len(sigtable)) {
- flags = sigtable[sig].flags
- }
- if c.sigcode() != _SI_USER && flags&_SigPanic != 0 {
- // Make it look like a call to the signal func.
- // Have to pass arguments out of band since
- // augmenting the stack frame would break
- // the unwinding code.
- gp.sig = sig
- gp.sigcode0 = uintptr(c.sigcode())
- gp.sigcode1 = uintptr(c.fault())
- gp.sigpc = uintptr(c.pc())
-
- // We arrange lr, and pc to pretend the panicking
- // function calls sigpanic directly.
- // Always save LR to stack so that panics in leaf
- // functions are correctly handled. This smashes
- // the stack frame but we're not going back there
- // anyway.
- sp := c.sp() - sys.SpAlign // needs only sizeof uint64, but must align the stack
- c.set_sp(sp)
- *(*uint64)(unsafe.Pointer(uintptr(sp))) = c.lr()
-
- pc := gp.sigpc
-
- // If we don't recognize the PC as code
- // but we do recognize the link register as code,
- // then assume this was a call to non-code and treat like
- // pc == 0, to make unwinding show the context.
- if pc != 0 && findfunc(pc) == nil && findfunc(uintptr(c.lr())) != nil {
- pc = 0
- }
-
- // Don't bother saving PC if it's zero, which is
- // probably a call to a nil func: the old link register
- // is more useful in the stack trace.
- if pc != 0 {
- c.set_lr(uint64(pc))
- }
-
- // In case we are panicking from external C code
- c.set_r28(uint64(uintptr(unsafe.Pointer(gp))))
- c.set_pc(uint64(funcPC(sigpanic)))
- return
- }
-
- if c.sigcode() == _SI_USER || flags&_SigNotify != 0 {
- if sigsend(sig) {
- return
- }
- }
-
- if c.sigcode() == _SI_USER && signal_ignored(sig) {
- return
- }
-
- if flags&_SigKill != 0 {
- dieFromSignal(int32(sig))
- }
-
- if flags&_SigThrow == 0 {
- return
- }
-
- _g_.m.throwing = 1
- _g_.m.caughtsig.set(gp)
-
- if crashing == 0 {
- startpanic()
- }
-
- if sig < uint32(len(sigtable)) {
- print(sigtable[sig].name, "\n")
- } else {
- print("Signal ", sig, "\n")
- }
-
- print("PC=", hex(c.pc()), " m=", _g_.m.id, "\n")
- if _g_.m.lockedg != nil && _g_.m.ncgo > 0 && gp == _g_.m.g0 {
- print("signal arrived during cgo execution\n")
- gp = _g_.m.lockedg
- }
- print("\n")
-
- level, _, docrash := gotraceback()
- if level > 0 {
- goroutineheader(gp)
- tracebacktrap(uintptr(c.pc()), uintptr(c.sp()), uintptr(c.lr()), gp)
- if crashing > 0 && gp != _g_.m.curg && _g_.m.curg != nil && readgstatus(_g_.m.curg)&^_Gscan == _Grunning {
- // tracebackothers on original m skipped this one; trace it now.
- goroutineheader(_g_.m.curg)
- traceback(^uintptr(0), ^uintptr(0), 0, gp)
- } else if crashing == 0 {
- tracebackothers(gp)
- print("\n")
- }
- dumpregs(c)
+func (c *sigctxt) sigpc() uintptr { return uintptr(c.pc()) }
+
+func (c *sigctxt) sigsp() uintptr { return uintptr(c.sp()) }
+func (c *sigctxt) siglr() uintptr { return uintptr(c.lr()) }
+
+// preparePanic sets up the stack to look like a call to sigpanic.
+func (c *sigctxt) preparePanic(sig uint32, gp *g) {
+ // We arrange lr, and pc to pretend the panicking
+ // function calls sigpanic directly.
+ // Always save LR to stack so that panics in leaf
+ // functions are correctly handled. This smashes
+ // the stack frame but we're not going back there
+ // anyway.
+ sp := c.sp() - sys.SpAlign // needs only sizeof uint64, but must align the stack
+ c.set_sp(sp)
+ *(*uint64)(unsafe.Pointer(uintptr(sp))) = c.lr()
+
+ pc := gp.sigpc
+
+ // If we don't recognize the PC as code
+ // but we do recognize the link register as code,
+ // then assume this was a call to non-code and treat like
+ // pc == 0, to make unwinding show the context.
+ if pc != 0 && findfunc(pc) == nil && findfunc(uintptr(c.lr())) != nil {
+ pc = 0
}
- if docrash {
- crashing++
- if crashing < sched.mcount {
- // There are other m's that need to dump their stacks.
- // Relay SIGQUIT to the next m by sending it to the current process.
- // All m's that have already received SIGQUIT have signal masks blocking
- // receipt of any signals, so the SIGQUIT will go to an m that hasn't seen it yet.
- // When the last m receives the SIGQUIT, it will fall through to the call to
- // crash below. Just in case the relaying gets botched, each m involved in
- // the relay sleeps for 5 seconds and then does the crash/exit itself.
- // In expected operation, the last m has received the SIGQUIT and run
- // crash/exit and the process is gone, all long before any of the
- // 5-second sleeps have finished.
- print("\n-----\n\n")
- raiseproc(_SIGQUIT)
- usleep(5 * 1000 * 1000)
- }
- crash()
+ // Don't bother saving PC if it's zero, which is
+ // probably a call to a nil func: the old link register
+ // is more useful in the stack trace.
+ if pc != 0 {
+ c.set_lr(uint64(pc))
}
- exit(2)
+ // In case we are panicking from external C code
+ c.set_r28(uint64(uintptr(unsafe.Pointer(gp))))
+ c.set_pc(uint64(funcPC(sigpanic)))
}
diff --git a/src/runtime/signal_darwin.go b/src/runtime/signal_darwin.go
index fb06de5..0c5481a 100644
--- a/src/runtime/signal_darwin.go
+++ b/src/runtime/signal_darwin.go
@@ -4,8 +4,6 @@
package runtime
-import "unsafe"
-
type sigTabT struct {
flags int32
name string
@@ -45,50 +43,3 @@ var sigtable = [...]sigTabT{
/* 30 */ {_SigNotify, "SIGUSR1: user-defined signal 1"},
/* 31 */ {_SigNotify, "SIGUSR2: user-defined signal 2"},
}
-
-//go:noescape
-func sigreturn(ctx unsafe.Pointer, infostyle uint32)
-
-//go:nosplit
-//go:nowritebarrierrec
-func sigtrampgo(fn uintptr, infostyle, sig uint32, info *siginfo, ctx unsafe.Pointer) {
- if sigfwdgo(sig, info, ctx) {
- sigreturn(ctx, infostyle)
- return
- }
- g := getg()
- if g == nil {
- badsignal(uintptr(sig), &sigctxt{info, ctx})
- sigreturn(ctx, infostyle)
- return
- }
-
- // If some non-Go code called sigaltstack, adjust.
- sp := uintptr(unsafe.Pointer(&sig))
- if sp < g.m.gsignal.stack.lo || sp >= g.m.gsignal.stack.hi {
- var st stackt
- sigaltstack(nil, &st)
- if st.ss_flags&_SS_DISABLE != 0 {
- setg(nil)
- cgocallback(unsafe.Pointer(funcPC(noSignalStack)), noescape(unsafe.Pointer(&sig)), unsafe.Sizeof(sig), 0)
- }
- stsp := uintptr(unsafe.Pointer(st.ss_sp))
- if sp < stsp || sp >= stsp+st.ss_size {
- setg(nil)
- cgocallback(unsafe.Pointer(funcPC(sigNotOnStack)), noescape(unsafe.Pointer(&sig)), unsafe.Sizeof(sig), 0)
- }
- g.m.gsignal.stack.lo = stsp
- g.m.gsignal.stack.hi = stsp + st.ss_size
- g.m.gsignal.stackguard0 = stsp + _StackGuard
- g.m.gsignal.stackguard1 = stsp + _StackGuard
- g.m.gsignal.stackAlloc = st.ss_size
- g.m.gsignal.stktopsp = getcallersp(unsafe.Pointer(&sig))
- }
-
- setg(g.m.gsignal)
- c := &sigctxt{info, ctx}
- c.fixsigcode(sig)
- sighandler(sig, info, ctx, g)
- setg(g)
- sigreturn(ctx, infostyle)
-}
diff --git a/src/runtime/signal_darwin_386.go b/src/runtime/signal_darwin_386.go
index 056f09a..c162959 100644
--- a/src/runtime/signal_darwin_386.go
+++ b/src/runtime/signal_darwin_386.go
@@ -11,16 +11,23 @@ type sigctxt struct {
ctxt unsafe.Pointer
}
-func (c *sigctxt) regs() *regs32 { return &(*ucontext)(c.ctxt).uc_mcontext.ss }
-func (c *sigctxt) eax() uint32 { return c.regs().eax }
-func (c *sigctxt) ebx() uint32 { return c.regs().ebx }
-func (c *sigctxt) ecx() uint32 { return c.regs().ecx }
-func (c *sigctxt) edx() uint32 { return c.regs().edx }
-func (c *sigctxt) edi() uint32 { return c.regs().edi }
-func (c *sigctxt) esi() uint32 { return c.regs().esi }
-func (c *sigctxt) ebp() uint32 { return c.regs().ebp }
-func (c *sigctxt) esp() uint32 { return c.regs().esp }
-func (c *sigctxt) eip() uint32 { return c.regs().eip }
+//go:nosplit
+//go:nowritebarrierrec
+func (c *sigctxt) regs() *regs32 { return &(*ucontext)(c.ctxt).uc_mcontext.ss }
+
+func (c *sigctxt) eax() uint32 { return c.regs().eax }
+func (c *sigctxt) ebx() uint32 { return c.regs().ebx }
+func (c *sigctxt) ecx() uint32 { return c.regs().ecx }
+func (c *sigctxt) edx() uint32 { return c.regs().edx }
+func (c *sigctxt) edi() uint32 { return c.regs().edi }
+func (c *sigctxt) esi() uint32 { return c.regs().esi }
+func (c *sigctxt) ebp() uint32 { return c.regs().ebp }
+func (c *sigctxt) esp() uint32 { return c.regs().esp }
+
+//go:nosplit
+//go:nowritebarrierrec
+func (c *sigctxt) eip() uint32 { return c.regs().eip }
+
func (c *sigctxt) eflags() uint32 { return c.regs().eflags }
func (c *sigctxt) cs() uint32 { return c.regs().cs }
func (c *sigctxt) fs() uint32 { return c.regs().fs }
diff --git a/src/runtime/signal_darwin_amd64.go b/src/runtime/signal_darwin_amd64.go
index d219fa4..40de481 100644
--- a/src/runtime/signal_darwin_amd64.go
+++ b/src/runtime/signal_darwin_amd64.go
@@ -11,24 +11,31 @@ type sigctxt struct {
ctxt unsafe.Pointer
}
-func (c *sigctxt) regs() *regs64 { return &(*ucontext)(c.ctxt).uc_mcontext.ss }
-func (c *sigctxt) rax() uint64 { return c.regs().rax }
-func (c *sigctxt) rbx() uint64 { return c.regs().rbx }
-func (c *sigctxt) rcx() uint64 { return c.regs().rcx }
-func (c *sigctxt) rdx() uint64 { return c.regs().rdx }
-func (c *sigctxt) rdi() uint64 { return c.regs().rdi }
-func (c *sigctxt) rsi() uint64 { return c.regs().rsi }
-func (c *sigctxt) rbp() uint64 { return c.regs().rbp }
-func (c *sigctxt) rsp() uint64 { return c.regs().rsp }
-func (c *sigctxt) r8() uint64 { return c.regs().r8 }
-func (c *sigctxt) r9() uint64 { return c.regs().r9 }
-func (c *sigctxt) r10() uint64 { return c.regs().r10 }
-func (c *sigctxt) r11() uint64 { return c.regs().r11 }
-func (c *sigctxt) r12() uint64 { return c.regs().r12 }
-func (c *sigctxt) r13() uint64 { return c.regs().r13 }
-func (c *sigctxt) r14() uint64 { return c.regs().r14 }
-func (c *sigctxt) r15() uint64 { return c.regs().r15 }
-func (c *sigctxt) rip() uint64 { return c.regs().rip }
+//go:nosplit
+//go:nowritebarrierrec
+func (c *sigctxt) regs() *regs64 { return &(*ucontext)(c.ctxt).uc_mcontext.ss }
+
+func (c *sigctxt) rax() uint64 { return c.regs().rax }
+func (c *sigctxt) rbx() uint64 { return c.regs().rbx }
+func (c *sigctxt) rcx() uint64 { return c.regs().rcx }
+func (c *sigctxt) rdx() uint64 { return c.regs().rdx }
+func (c *sigctxt) rdi() uint64 { return c.regs().rdi }
+func (c *sigctxt) rsi() uint64 { return c.regs().rsi }
+func (c *sigctxt) rbp() uint64 { return c.regs().rbp }
+func (c *sigctxt) rsp() uint64 { return c.regs().rsp }
+func (c *sigctxt) r8() uint64 { return c.regs().r8 }
+func (c *sigctxt) r9() uint64 { return c.regs().r9 }
+func (c *sigctxt) r10() uint64 { return c.regs().r10 }
+func (c *sigctxt) r11() uint64 { return c.regs().r11 }
+func (c *sigctxt) r12() uint64 { return c.regs().r12 }
+func (c *sigctxt) r13() uint64 { return c.regs().r13 }
+func (c *sigctxt) r14() uint64 { return c.regs().r14 }
+func (c *sigctxt) r15() uint64 { return c.regs().r15 }
+
+//go:nosplit
+//go:nowritebarrierrec
+func (c *sigctxt) rip() uint64 { return c.regs().rip }
+
func (c *sigctxt) rflags() uint64 { return c.regs().rflags }
func (c *sigctxt) cs() uint64 { return c.regs().cs }
func (c *sigctxt) fs() uint64 { return c.regs().fs }
@@ -60,5 +67,25 @@ func (c *sigctxt) fixsigcode(sig uint32) {
// SIGTRAP on something other than INT 3.
c.set_sigcode(_SI_USER)
}
+
+ case _SIGSEGV:
+ // x86-64 has 48-bit virtual addresses. The top 16 bits must echo bit 47.
+ // The hardware delivers a different kind of fault for a malformed address
+ // than it does for an attempt to access a valid but unmapped address.
+ // OS X 10.9.2 mishandles the malformed address case, making it look like
+ // a user-generated signal (like someone ran kill -SEGV ourpid).
+ // We pass user-generated signals to os/signal, or else ignore them.
+ // Doing that here - and returning to the faulting code - results in an
+ // infinite loop. It appears the best we can do is rewrite what the kernel
+ // delivers into something more like the truth. The address used below
+ // has very little chance of being the one that caused the fault, but it is
+ // malformed, it is clearly not a real pointer, and if it does get printed
+ // in real life, people will probably search for it and find this code.
+ // There are no Google hits for b01dfacedebac1e or 0xb01dfacedebac1e
+ // as I type this comment.
+ if c.sigcode() == _SI_USER {
+ c.set_sigcode(_SI_USER + 1)
+ c.set_sigaddr(0xb01dfacedebac1e)
+ }
}
}
diff --git a/src/runtime/signal_darwin_arm.go b/src/runtime/signal_darwin_arm.go
index 82c7c93..c88b90c 100644
--- a/src/runtime/signal_darwin_arm.go
+++ b/src/runtime/signal_darwin_arm.go
@@ -11,23 +11,30 @@ type sigctxt struct {
ctxt unsafe.Pointer
}
-func (c *sigctxt) regs() *regs32 { return &(*ucontext)(c.ctxt).uc_mcontext.ss }
-func (c *sigctxt) r0() uint32 { return c.regs().r[0] }
-func (c *sigctxt) r1() uint32 { return c.regs().r[1] }
-func (c *sigctxt) r2() uint32 { return c.regs().r[2] }
-func (c *sigctxt) r3() uint32 { return c.regs().r[3] }
-func (c *sigctxt) r4() uint32 { return c.regs().r[4] }
-func (c *sigctxt) r5() uint32 { return c.regs().r[5] }
-func (c *sigctxt) r6() uint32 { return c.regs().r[6] }
-func (c *sigctxt) r7() uint32 { return c.regs().r[7] }
-func (c *sigctxt) r8() uint32 { return c.regs().r[8] }
-func (c *sigctxt) r9() uint32 { return c.regs().r[9] }
-func (c *sigctxt) r10() uint32 { return c.regs().r[10] }
-func (c *sigctxt) fp() uint32 { return c.regs().r[11] }
-func (c *sigctxt) ip() uint32 { return c.regs().r[12] }
-func (c *sigctxt) sp() uint32 { return c.regs().sp }
-func (c *sigctxt) lr() uint32 { return c.regs().lr }
-func (c *sigctxt) pc() uint32 { return c.regs().pc }
+//go:nosplit
+//go:nowritebarrierrec
+func (c *sigctxt) regs() *regs32 { return &(*ucontext)(c.ctxt).uc_mcontext.ss }
+
+func (c *sigctxt) r0() uint32 { return c.regs().r[0] }
+func (c *sigctxt) r1() uint32 { return c.regs().r[1] }
+func (c *sigctxt) r2() uint32 { return c.regs().r[2] }
+func (c *sigctxt) r3() uint32 { return c.regs().r[3] }
+func (c *sigctxt) r4() uint32 { return c.regs().r[4] }
+func (c *sigctxt) r5() uint32 { return c.regs().r[5] }
+func (c *sigctxt) r6() uint32 { return c.regs().r[6] }
+func (c *sigctxt) r7() uint32 { return c.regs().r[7] }
+func (c *sigctxt) r8() uint32 { return c.regs().r[8] }
+func (c *sigctxt) r9() uint32 { return c.regs().r[9] }
+func (c *sigctxt) r10() uint32 { return c.regs().r[10] }
+func (c *sigctxt) fp() uint32 { return c.regs().r[11] }
+func (c *sigctxt) ip() uint32 { return c.regs().r[12] }
+func (c *sigctxt) sp() uint32 { return c.regs().sp }
+func (c *sigctxt) lr() uint32 { return c.regs().lr }
+
+//go:nosplit
+//go:nowritebarrierrec
+func (c *sigctxt) pc() uint32 { return c.regs().pc }
+
func (c *sigctxt) cpsr() uint32 { return c.regs().cpsr }
func (c *sigctxt) fault() uint32 { return c.info.si_addr }
func (c *sigctxt) sigcode() uint32 { return uint32(c.info.si_code) }
diff --git a/src/runtime/signal_darwin_arm64.go b/src/runtime/signal_darwin_arm64.go
index 12fa520..b14b9f1 100644
--- a/src/runtime/signal_darwin_arm64.go
+++ b/src/runtime/signal_darwin_arm64.go
@@ -11,40 +11,47 @@ type sigctxt struct {
ctxt unsafe.Pointer
}
+//go:nosplit
+//go:nowritebarrierrec
func (c *sigctxt) regs() *regs64 { return &(*ucontext)(c.ctxt).uc_mcontext.ss }
-func (c *sigctxt) r0() uint64 { return c.regs().x[0] }
-func (c *sigctxt) r1() uint64 { return c.regs().x[1] }
-func (c *sigctxt) r2() uint64 { return c.regs().x[2] }
-func (c *sigctxt) r3() uint64 { return c.regs().x[3] }
-func (c *sigctxt) r4() uint64 { return c.regs().x[4] }
-func (c *sigctxt) r5() uint64 { return c.regs().x[5] }
-func (c *sigctxt) r6() uint64 { return c.regs().x[6] }
-func (c *sigctxt) r7() uint64 { return c.regs().x[7] }
-func (c *sigctxt) r8() uint64 { return c.regs().x[8] }
-func (c *sigctxt) r9() uint64 { return c.regs().x[9] }
-func (c *sigctxt) r10() uint64 { return c.regs().x[10] }
-func (c *sigctxt) r11() uint64 { return c.regs().x[11] }
-func (c *sigctxt) r12() uint64 { return c.regs().x[12] }
-func (c *sigctxt) r13() uint64 { return c.regs().x[13] }
-func (c *sigctxt) r14() uint64 { return c.regs().x[14] }
-func (c *sigctxt) r15() uint64 { return c.regs().x[15] }
-func (c *sigctxt) r16() uint64 { return c.regs().x[16] }
-func (c *sigctxt) r17() uint64 { return c.regs().x[17] }
-func (c *sigctxt) r18() uint64 { return c.regs().x[18] }
-func (c *sigctxt) r19() uint64 { return c.regs().x[19] }
-func (c *sigctxt) r20() uint64 { return c.regs().x[20] }
-func (c *sigctxt) r21() uint64 { return c.regs().x[21] }
-func (c *sigctxt) r22() uint64 { return c.regs().x[22] }
-func (c *sigctxt) r23() uint64 { return c.regs().x[23] }
-func (c *sigctxt) r24() uint64 { return c.regs().x[24] }
-func (c *sigctxt) r25() uint64 { return c.regs().x[25] }
-func (c *sigctxt) r26() uint64 { return c.regs().x[26] }
-func (c *sigctxt) r27() uint64 { return c.regs().x[27] }
-func (c *sigctxt) r28() uint64 { return c.regs().x[28] }
-func (c *sigctxt) r29() uint64 { return c.regs().fp }
-func (c *sigctxt) lr() uint64 { return c.regs().lr }
-func (c *sigctxt) sp() uint64 { return c.regs().sp }
-func (c *sigctxt) pc() uint64 { return c.regs().pc }
+
+func (c *sigctxt) r0() uint64 { return c.regs().x[0] }
+func (c *sigctxt) r1() uint64 { return c.regs().x[1] }
+func (c *sigctxt) r2() uint64 { return c.regs().x[2] }
+func (c *sigctxt) r3() uint64 { return c.regs().x[3] }
+func (c *sigctxt) r4() uint64 { return c.regs().x[4] }
+func (c *sigctxt) r5() uint64 { return c.regs().x[5] }
+func (c *sigctxt) r6() uint64 { return c.regs().x[6] }
+func (c *sigctxt) r7() uint64 { return c.regs().x[7] }
+func (c *sigctxt) r8() uint64 { return c.regs().x[8] }
+func (c *sigctxt) r9() uint64 { return c.regs().x[9] }
+func (c *sigctxt) r10() uint64 { return c.regs().x[10] }
+func (c *sigctxt) r11() uint64 { return c.regs().x[11] }
+func (c *sigctxt) r12() uint64 { return c.regs().x[12] }
+func (c *sigctxt) r13() uint64 { return c.regs().x[13] }
+func (c *sigctxt) r14() uint64 { return c.regs().x[14] }
+func (c *sigctxt) r15() uint64 { return c.regs().x[15] }
+func (c *sigctxt) r16() uint64 { return c.regs().x[16] }
+func (c *sigctxt) r17() uint64 { return c.regs().x[17] }
+func (c *sigctxt) r18() uint64 { return c.regs().x[18] }
+func (c *sigctxt) r19() uint64 { return c.regs().x[19] }
+func (c *sigctxt) r20() uint64 { return c.regs().x[20] }
+func (c *sigctxt) r21() uint64 { return c.regs().x[21] }
+func (c *sigctxt) r22() uint64 { return c.regs().x[22] }
+func (c *sigctxt) r23() uint64 { return c.regs().x[23] }
+func (c *sigctxt) r24() uint64 { return c.regs().x[24] }
+func (c *sigctxt) r25() uint64 { return c.regs().x[25] }
+func (c *sigctxt) r26() uint64 { return c.regs().x[26] }
+func (c *sigctxt) r27() uint64 { return c.regs().x[27] }
+func (c *sigctxt) r28() uint64 { return c.regs().x[28] }
+func (c *sigctxt) r29() uint64 { return c.regs().fp }
+func (c *sigctxt) lr() uint64 { return c.regs().lr }
+func (c *sigctxt) sp() uint64 { return c.regs().sp }
+
+//go:nosplit
+//go:nowritebarrierrec
+func (c *sigctxt) pc() uint64 { return c.regs().pc }
+
func (c *sigctxt) fault() uint64 { return uint64(uintptr(unsafe.Pointer(c.info.si_addr))) }
func (c *sigctxt) sigcode() uint64 { return uint64(c.info.si_code) }
diff --git a/src/runtime/signal_dragonfly_amd64.go b/src/runtime/signal_dragonfly_amd64.go
index b32df29..c473edd 100644
--- a/src/runtime/signal_dragonfly_amd64.go
+++ b/src/runtime/signal_dragonfly_amd64.go
@@ -11,26 +11,33 @@ type sigctxt struct {
ctxt unsafe.Pointer
}
+//go:nosplit
+//go:nowritebarrierrec
func (c *sigctxt) regs() *mcontext {
return (*mcontext)(unsafe.Pointer(&(*ucontext)(c.ctxt).uc_mcontext))
}
-func (c *sigctxt) rax() uint64 { return c.regs().mc_rax }
-func (c *sigctxt) rbx() uint64 { return c.regs().mc_rbx }
-func (c *sigctxt) rcx() uint64 { return c.regs().mc_rcx }
-func (c *sigctxt) rdx() uint64 { return c.regs().mc_rdx }
-func (c *sigctxt) rdi() uint64 { return c.regs().mc_rdi }
-func (c *sigctxt) rsi() uint64 { return c.regs().mc_rsi }
-func (c *sigctxt) rbp() uint64 { return c.regs().mc_rbp }
-func (c *sigctxt) rsp() uint64 { return c.regs().mc_rsp }
-func (c *sigctxt) r8() uint64 { return c.regs().mc_r8 }
-func (c *sigctxt) r9() uint64 { return c.regs().mc_r9 }
-func (c *sigctxt) r10() uint64 { return c.regs().mc_r10 }
-func (c *sigctxt) r11() uint64 { return c.regs().mc_r11 }
-func (c *sigctxt) r12() uint64 { return c.regs().mc_r12 }
-func (c *sigctxt) r13() uint64 { return c.regs().mc_r13 }
-func (c *sigctxt) r14() uint64 { return c.regs().mc_r14 }
-func (c *sigctxt) r15() uint64 { return c.regs().mc_r15 }
-func (c *sigctxt) rip() uint64 { return c.regs().mc_rip }
+
+func (c *sigctxt) rax() uint64 { return c.regs().mc_rax }
+func (c *sigctxt) rbx() uint64 { return c.regs().mc_rbx }
+func (c *sigctxt) rcx() uint64 { return c.regs().mc_rcx }
+func (c *sigctxt) rdx() uint64 { return c.regs().mc_rdx }
+func (c *sigctxt) rdi() uint64 { return c.regs().mc_rdi }
+func (c *sigctxt) rsi() uint64 { return c.regs().mc_rsi }
+func (c *sigctxt) rbp() uint64 { return c.regs().mc_rbp }
+func (c *sigctxt) rsp() uint64 { return c.regs().mc_rsp }
+func (c *sigctxt) r8() uint64 { return c.regs().mc_r8 }
+func (c *sigctxt) r9() uint64 { return c.regs().mc_r9 }
+func (c *sigctxt) r10() uint64 { return c.regs().mc_r10 }
+func (c *sigctxt) r11() uint64 { return c.regs().mc_r11 }
+func (c *sigctxt) r12() uint64 { return c.regs().mc_r12 }
+func (c *sigctxt) r13() uint64 { return c.regs().mc_r13 }
+func (c *sigctxt) r14() uint64 { return c.regs().mc_r14 }
+func (c *sigctxt) r15() uint64 { return c.regs().mc_r15 }
+
+//go:nosplit
+//go:nowritebarrierrec
+func (c *sigctxt) rip() uint64 { return c.regs().mc_rip }
+
func (c *sigctxt) rflags() uint64 { return c.regs().mc_rflags }
func (c *sigctxt) cs() uint64 { return c.regs().mc_cs }
func (c *sigctxt) fs() uint64 { return c.regs().mc_ss }
diff --git a/src/runtime/signal_freebsd.go b/src/runtime/signal_freebsd.go
index c6c1269..7ce7217 100644
--- a/src/runtime/signal_freebsd.go
+++ b/src/runtime/signal_freebsd.go
@@ -4,8 +4,6 @@
package runtime
-import "unsafe"
-
type sigTabT struct {
flags int32
name string
@@ -46,42 +44,3 @@ var sigtable = [...]sigTabT{
/* 31 */ {_SigNotify, "SIGUSR2: user-defined signal 2"},
/* 32 */ {_SigNotify, "SIGTHR: reserved"},
}
-
-//go:nosplit
-//go:nowritebarrierrec
-func sigtrampgo(sig uint32, info *siginfo, ctx unsafe.Pointer) {
- if sigfwdgo(sig, info, ctx) {
- return
- }
- g := getg()
- if g == nil {
- badsignal(uintptr(sig), &sigctxt{info, ctx})
- return
- }
-
- // If some non-Go code called sigaltstack, adjust.
- sp := uintptr(unsafe.Pointer(&sig))
- if sp < g.m.gsignal.stack.lo || sp >= g.m.gsignal.stack.hi {
- var st stackt
- sigaltstack(nil, &st)
- if st.ss_flags&_SS_DISABLE != 0 {
- setg(nil)
- cgocallback(unsafe.Pointer(funcPC(noSignalStack)), noescape(unsafe.Pointer(&sig)), unsafe.Sizeof(sig), 0)
- }
- stsp := uintptr(unsafe.Pointer(st.ss_sp))
- if sp < stsp || sp >= stsp+st.ss_size {
- setg(nil)
- cgocallback(unsafe.Pointer(funcPC(sigNotOnStack)), noescape(unsafe.Pointer(&sig)), unsafe.Sizeof(sig), 0)
- }
- g.m.gsignal.stack.lo = stsp
- g.m.gsignal.stack.hi = stsp + st.ss_size
- g.m.gsignal.stackguard0 = stsp + _StackGuard
- g.m.gsignal.stackguard1 = stsp + _StackGuard
- g.m.gsignal.stackAlloc = st.ss_size
- g.m.gsignal.stktopsp = getcallersp(unsafe.Pointer(&sig))
- }
-
- setg(g.m.gsignal)
- sighandler(sig, info, ctx, g)
- setg(g)
-}
diff --git a/src/runtime/signal_freebsd_386.go b/src/runtime/signal_freebsd_386.go
index 092e6df..f7cc0df 100644
--- a/src/runtime/signal_freebsd_386.go
+++ b/src/runtime/signal_freebsd_386.go
@@ -11,16 +11,23 @@ type sigctxt struct {
ctxt unsafe.Pointer
}
+//go:nosplit
+//go:nowritebarrierrec
func (c *sigctxt) regs() *mcontext { return &(*ucontext)(c.ctxt).uc_mcontext }
-func (c *sigctxt) eax() uint32 { return c.regs().mc_eax }
-func (c *sigctxt) ebx() uint32 { return c.regs().mc_ebx }
-func (c *sigctxt) ecx() uint32 { return c.regs().mc_ecx }
-func (c *sigctxt) edx() uint32 { return c.regs().mc_edx }
-func (c *sigctxt) edi() uint32 { return c.regs().mc_edi }
-func (c *sigctxt) esi() uint32 { return c.regs().mc_esi }
-func (c *sigctxt) ebp() uint32 { return c.regs().mc_ebp }
-func (c *sigctxt) esp() uint32 { return c.regs().mc_esp }
-func (c *sigctxt) eip() uint32 { return c.regs().mc_eip }
+
+func (c *sigctxt) eax() uint32 { return c.regs().mc_eax }
+func (c *sigctxt) ebx() uint32 { return c.regs().mc_ebx }
+func (c *sigctxt) ecx() uint32 { return c.regs().mc_ecx }
+func (c *sigctxt) edx() uint32 { return c.regs().mc_edx }
+func (c *sigctxt) edi() uint32 { return c.regs().mc_edi }
+func (c *sigctxt) esi() uint32 { return c.regs().mc_esi }
+func (c *sigctxt) ebp() uint32 { return c.regs().mc_ebp }
+func (c *sigctxt) esp() uint32 { return c.regs().mc_esp }
+
+//go:nosplit
+//go:nowritebarrierrec
+func (c *sigctxt) eip() uint32 { return c.regs().mc_eip }
+
func (c *sigctxt) eflags() uint32 { return c.regs().mc_eflags }
func (c *sigctxt) cs() uint32 { return c.regs().mc_cs }
func (c *sigctxt) fs() uint32 { return c.regs().mc_fs }
diff --git a/src/runtime/signal_freebsd_amd64.go b/src/runtime/signal_freebsd_amd64.go
index a0b4a72..20b86e7 100644
--- a/src/runtime/signal_freebsd_amd64.go
+++ b/src/runtime/signal_freebsd_amd64.go
@@ -11,26 +11,33 @@ type sigctxt struct {
ctxt unsafe.Pointer
}
+//go:nosplit
+//go:nowritebarrierrec
func (c *sigctxt) regs() *mcontext {
return (*mcontext)(unsafe.Pointer(&(*ucontext)(c.ctxt).uc_mcontext))
}
-func (c *sigctxt) rax() uint64 { return c.regs().mc_rax }
-func (c *sigctxt) rbx() uint64 { return c.regs().mc_rbx }
-func (c *sigctxt) rcx() uint64 { return c.regs().mc_rcx }
-func (c *sigctxt) rdx() uint64 { return c.regs().mc_rdx }
-func (c *sigctxt) rdi() uint64 { return c.regs().mc_rdi }
-func (c *sigctxt) rsi() uint64 { return c.regs().mc_rsi }
-func (c *sigctxt) rbp() uint64 { return c.regs().mc_rbp }
-func (c *sigctxt) rsp() uint64 { return c.regs().mc_rsp }
-func (c *sigctxt) r8() uint64 { return c.regs().mc_r8 }
-func (c *sigctxt) r9() uint64 { return c.regs().mc_r9 }
-func (c *sigctxt) r10() uint64 { return c.regs().mc_r10 }
-func (c *sigctxt) r11() uint64 { return c.regs().mc_r11 }
-func (c *sigctxt) r12() uint64 { return c.regs().mc_r12 }
-func (c *sigctxt) r13() uint64 { return c.regs().mc_r13 }
-func (c *sigctxt) r14() uint64 { return c.regs().mc_r14 }
-func (c *sigctxt) r15() uint64 { return c.regs().mc_r15 }
-func (c *sigctxt) rip() uint64 { return c.regs().mc_rip }
+
+func (c *sigctxt) rax() uint64 { return c.regs().mc_rax }
+func (c *sigctxt) rbx() uint64 { return c.regs().mc_rbx }
+func (c *sigctxt) rcx() uint64 { return c.regs().mc_rcx }
+func (c *sigctxt) rdx() uint64 { return c.regs().mc_rdx }
+func (c *sigctxt) rdi() uint64 { return c.regs().mc_rdi }
+func (c *sigctxt) rsi() uint64 { return c.regs().mc_rsi }
+func (c *sigctxt) rbp() uint64 { return c.regs().mc_rbp }
+func (c *sigctxt) rsp() uint64 { return c.regs().mc_rsp }
+func (c *sigctxt) r8() uint64 { return c.regs().mc_r8 }
+func (c *sigctxt) r9() uint64 { return c.regs().mc_r9 }
+func (c *sigctxt) r10() uint64 { return c.regs().mc_r10 }
+func (c *sigctxt) r11() uint64 { return c.regs().mc_r11 }
+func (c *sigctxt) r12() uint64 { return c.regs().mc_r12 }
+func (c *sigctxt) r13() uint64 { return c.regs().mc_r13 }
+func (c *sigctxt) r14() uint64 { return c.regs().mc_r14 }
+func (c *sigctxt) r15() uint64 { return c.regs().mc_r15 }
+
+//go:nosplit
+//go:nowritebarrierrec
+func (c *sigctxt) rip() uint64 { return c.regs().mc_rip }
+
func (c *sigctxt) rflags() uint64 { return c.regs().mc_rflags }
func (c *sigctxt) cs() uint64 { return c.regs().mc_cs }
func (c *sigctxt) fs() uint64 { return uint64(c.regs().mc_fs) }
diff --git a/src/runtime/signal_freebsd_arm.go b/src/runtime/signal_freebsd_arm.go
index 0357304..9601370 100644
--- a/src/runtime/signal_freebsd_arm.go
+++ b/src/runtime/signal_freebsd_arm.go
@@ -11,23 +11,30 @@ type sigctxt struct {
ctxt unsafe.Pointer
}
+//go:nosplit
+//go:nowritebarrierrec
func (c *sigctxt) regs() *mcontext { return &(*ucontext)(c.ctxt).uc_mcontext }
-func (c *sigctxt) r0() uint32 { return c.regs().__gregs[0] }
-func (c *sigctxt) r1() uint32 { return c.regs().__gregs[1] }
-func (c *sigctxt) r2() uint32 { return c.regs().__gregs[2] }
-func (c *sigctxt) r3() uint32 { return c.regs().__gregs[3] }
-func (c *sigctxt) r4() uint32 { return c.regs().__gregs[4] }
-func (c *sigctxt) r5() uint32 { return c.regs().__gregs[5] }
-func (c *sigctxt) r6() uint32 { return c.regs().__gregs[6] }
-func (c *sigctxt) r7() uint32 { return c.regs().__gregs[7] }
-func (c *sigctxt) r8() uint32 { return c.regs().__gregs[8] }
-func (c *sigctxt) r9() uint32 { return c.regs().__gregs[9] }
-func (c *sigctxt) r10() uint32 { return c.regs().__gregs[10] }
-func (c *sigctxt) fp() uint32 { return c.regs().__gregs[11] }
-func (c *sigctxt) ip() uint32 { return c.regs().__gregs[12] }
-func (c *sigctxt) sp() uint32 { return c.regs().__gregs[13] }
-func (c *sigctxt) lr() uint32 { return c.regs().__gregs[14] }
-func (c *sigctxt) pc() uint32 { return c.regs().__gregs[15] }
+
+func (c *sigctxt) r0() uint32 { return c.regs().__gregs[0] }
+func (c *sigctxt) r1() uint32 { return c.regs().__gregs[1] }
+func (c *sigctxt) r2() uint32 { return c.regs().__gregs[2] }
+func (c *sigctxt) r3() uint32 { return c.regs().__gregs[3] }
+func (c *sigctxt) r4() uint32 { return c.regs().__gregs[4] }
+func (c *sigctxt) r5() uint32 { return c.regs().__gregs[5] }
+func (c *sigctxt) r6() uint32 { return c.regs().__gregs[6] }
+func (c *sigctxt) r7() uint32 { return c.regs().__gregs[7] }
+func (c *sigctxt) r8() uint32 { return c.regs().__gregs[8] }
+func (c *sigctxt) r9() uint32 { return c.regs().__gregs[9] }
+func (c *sigctxt) r10() uint32 { return c.regs().__gregs[10] }
+func (c *sigctxt) fp() uint32 { return c.regs().__gregs[11] }
+func (c *sigctxt) ip() uint32 { return c.regs().__gregs[12] }
+func (c *sigctxt) sp() uint32 { return c.regs().__gregs[13] }
+func (c *sigctxt) lr() uint32 { return c.regs().__gregs[14] }
+
+//go:nosplit
+//go:nowritebarrierrec
+func (c *sigctxt) pc() uint32 { return c.regs().__gregs[15] }
+
func (c *sigctxt) cpsr() uint32 { return c.regs().__gregs[16] }
func (c *sigctxt) fault() uint32 { return uint32(c.info.si_addr) }
func (c *sigctxt) trap() uint32 { return 0 }
diff --git a/src/runtime/signal_linux_386.go b/src/runtime/signal_linux_386.go
index 415f361..13d9df4 100644
--- a/src/runtime/signal_linux_386.go
+++ b/src/runtime/signal_linux_386.go
@@ -14,22 +14,29 @@ type sigctxt struct {
ctxt unsafe.Pointer
}
+//go:nosplit
+//go:nowritebarrierrec
func (c *sigctxt) regs() *sigcontext { return &(*ucontext)(c.ctxt).uc_mcontext }
-func (c *sigctxt) eax() uint32 { return c.regs().eax }
-func (c *sigctxt) ebx() uint32 { return c.regs().ebx }
-func (c *sigctxt) ecx() uint32 { return c.regs().ecx }
-func (c *sigctxt) edx() uint32 { return c.regs().edx }
-func (c *sigctxt) edi() uint32 { return c.regs().edi }
-func (c *sigctxt) esi() uint32 { return c.regs().esi }
-func (c *sigctxt) ebp() uint32 { return c.regs().ebp }
-func (c *sigctxt) esp() uint32 { return c.regs().esp }
-func (c *sigctxt) eip() uint32 { return c.regs().eip }
-func (c *sigctxt) eflags() uint32 { return c.regs().eflags }
-func (c *sigctxt) cs() uint32 { return uint32(c.regs().cs) }
-func (c *sigctxt) fs() uint32 { return uint32(c.regs().fs) }
-func (c *sigctxt) gs() uint32 { return uint32(c.regs().gs) }
-func (c *sigctxt) sigcode() uint32 { return uint32(c.info.si_code) }
-func (c *sigctxt) sigaddr() uint32 { return c.info.si_addr }
+
+func (c *sigctxt) eax() uint32 { return c.regs().eax }
+func (c *sigctxt) ebx() uint32 { return c.regs().ebx }
+func (c *sigctxt) ecx() uint32 { return c.regs().ecx }
+func (c *sigctxt) edx() uint32 { return c.regs().edx }
+func (c *sigctxt) edi() uint32 { return c.regs().edi }
+func (c *sigctxt) esi() uint32 { return c.regs().esi }
+func (c *sigctxt) ebp() uint32 { return c.regs().ebp }
+func (c *sigctxt) esp() uint32 { return c.regs().esp }
+
+//go:nosplit
+//go:nowritebarrierrec
+func (c *sigctxt) eip() uint32 { return c.regs().eip }
+
+func (c *sigctxt) eflags() uint32 { return c.regs().eflags }
+func (c *sigctxt) cs() uint32 { return uint32(c.regs().cs) }
+func (c *sigctxt) fs() uint32 { return uint32(c.regs().fs) }
+func (c *sigctxt) gs() uint32 { return uint32(c.regs().gs) }
+func (c *sigctxt) sigcode() uint32 { return uint32(c.info.si_code) }
+func (c *sigctxt) sigaddr() uint32 { return c.info.si_addr }
func (c *sigctxt) set_eip(x uint32) { c.regs().eip = x }
func (c *sigctxt) set_esp(x uint32) { c.regs().esp = x }
diff --git a/src/runtime/signal_linux_amd64.go b/src/runtime/signal_linux_amd64.go
index 433747f..210e896 100644
--- a/src/runtime/signal_linux_amd64.go
+++ b/src/runtime/signal_linux_amd64.go
@@ -14,26 +14,33 @@ type sigctxt struct {
ctxt unsafe.Pointer
}
+//go:nosplit
+//go:nowritebarrierrec
func (c *sigctxt) regs() *sigcontext {
return (*sigcontext)(unsafe.Pointer(&(*ucontext)(c.ctxt).uc_mcontext))
}
-func (c *sigctxt) rax() uint64 { return c.regs().rax }
-func (c *sigctxt) rbx() uint64 { return c.regs().rbx }
-func (c *sigctxt) rcx() uint64 { return c.regs().rcx }
-func (c *sigctxt) rdx() uint64 { return c.regs().rdx }
-func (c *sigctxt) rdi() uint64 { return c.regs().rdi }
-func (c *sigctxt) rsi() uint64 { return c.regs().rsi }
-func (c *sigctxt) rbp() uint64 { return c.regs().rbp }
-func (c *sigctxt) rsp() uint64 { return c.regs().rsp }
-func (c *sigctxt) r8() uint64 { return c.regs().r8 }
-func (c *sigctxt) r9() uint64 { return c.regs().r9 }
-func (c *sigctxt) r10() uint64 { return c.regs().r10 }
-func (c *sigctxt) r11() uint64 { return c.regs().r11 }
-func (c *sigctxt) r12() uint64 { return c.regs().r12 }
-func (c *sigctxt) r13() uint64 { return c.regs().r13 }
-func (c *sigctxt) r14() uint64 { return c.regs().r14 }
-func (c *sigctxt) r15() uint64 { return c.regs().r15 }
-func (c *sigctxt) rip() uint64 { return c.regs().rip }
+
+func (c *sigctxt) rax() uint64 { return c.regs().rax }
+func (c *sigctxt) rbx() uint64 { return c.regs().rbx }
+func (c *sigctxt) rcx() uint64 { return c.regs().rcx }
+func (c *sigctxt) rdx() uint64 { return c.regs().rdx }
+func (c *sigctxt) rdi() uint64 { return c.regs().rdi }
+func (c *sigctxt) rsi() uint64 { return c.regs().rsi }
+func (c *sigctxt) rbp() uint64 { return c.regs().rbp }
+func (c *sigctxt) rsp() uint64 { return c.regs().rsp }
+func (c *sigctxt) r8() uint64 { return c.regs().r8 }
+func (c *sigctxt) r9() uint64 { return c.regs().r9 }
+func (c *sigctxt) r10() uint64 { return c.regs().r10 }
+func (c *sigctxt) r11() uint64 { return c.regs().r11 }
+func (c *sigctxt) r12() uint64 { return c.regs().r12 }
+func (c *sigctxt) r13() uint64 { return c.regs().r13 }
+func (c *sigctxt) r14() uint64 { return c.regs().r14 }
+func (c *sigctxt) r15() uint64 { return c.regs().r15 }
+
+//go:nosplit
+//go:nowritebarrierrec
+func (c *sigctxt) rip() uint64 { return c.regs().rip }
+
func (c *sigctxt) rflags() uint64 { return c.regs().eflags }
func (c *sigctxt) cs() uint64 { return uint64(c.regs().cs) }
func (c *sigctxt) fs() uint64 { return uint64(c.regs().fs) }
diff --git a/src/runtime/signal_linux_arm.go b/src/runtime/signal_linux_arm.go
index cd6a0d7..06a57b8 100644
--- a/src/runtime/signal_linux_arm.go
+++ b/src/runtime/signal_linux_arm.go
@@ -14,28 +14,35 @@ type sigctxt struct {
ctxt unsafe.Pointer
}
+//go:nosplit
+//go:nowritebarrierrec
func (c *sigctxt) regs() *sigcontext { return &(*ucontext)(c.ctxt).uc_mcontext }
-func (c *sigctxt) r0() uint32 { return c.regs().r0 }
-func (c *sigctxt) r1() uint32 { return c.regs().r1 }
-func (c *sigctxt) r2() uint32 { return c.regs().r2 }
-func (c *sigctxt) r3() uint32 { return c.regs().r3 }
-func (c *sigctxt) r4() uint32 { return c.regs().r4 }
-func (c *sigctxt) r5() uint32 { return c.regs().r5 }
-func (c *sigctxt) r6() uint32 { return c.regs().r6 }
-func (c *sigctxt) r7() uint32 { return c.regs().r7 }
-func (c *sigctxt) r8() uint32 { return c.regs().r8 }
-func (c *sigctxt) r9() uint32 { return c.regs().r9 }
-func (c *sigctxt) r10() uint32 { return c.regs().r10 }
-func (c *sigctxt) fp() uint32 { return c.regs().fp }
-func (c *sigctxt) ip() uint32 { return c.regs().ip }
-func (c *sigctxt) sp() uint32 { return c.regs().sp }
-func (c *sigctxt) lr() uint32 { return c.regs().lr }
-func (c *sigctxt) pc() uint32 { return c.regs().pc }
-func (c *sigctxt) cpsr() uint32 { return c.regs().cpsr }
-func (c *sigctxt) fault() uint32 { return c.regs().fault_address }
-func (c *sigctxt) trap() uint32 { return c.regs().trap_no }
-func (c *sigctxt) error() uint32 { return c.regs().error_code }
-func (c *sigctxt) oldmask() uint32 { return c.regs().oldmask }
+
+func (c *sigctxt) r0() uint32 { return c.regs().r0 }
+func (c *sigctxt) r1() uint32 { return c.regs().r1 }
+func (c *sigctxt) r2() uint32 { return c.regs().r2 }
+func (c *sigctxt) r3() uint32 { return c.regs().r3 }
+func (c *sigctxt) r4() uint32 { return c.regs().r4 }
+func (c *sigctxt) r5() uint32 { return c.regs().r5 }
+func (c *sigctxt) r6() uint32 { return c.regs().r6 }
+func (c *sigctxt) r7() uint32 { return c.regs().r7 }
+func (c *sigctxt) r8() uint32 { return c.regs().r8 }
+func (c *sigctxt) r9() uint32 { return c.regs().r9 }
+func (c *sigctxt) r10() uint32 { return c.regs().r10 }
+func (c *sigctxt) fp() uint32 { return c.regs().fp }
+func (c *sigctxt) ip() uint32 { return c.regs().ip }
+func (c *sigctxt) sp() uint32 { return c.regs().sp }
+func (c *sigctxt) lr() uint32 { return c.regs().lr }
+
+//go:nosplit
+//go:nowritebarrierrec
+func (c *sigctxt) pc() uint32 { return c.regs().pc }
+
+func (c *sigctxt) cpsr() uint32 { return c.regs().cpsr }
+func (c *sigctxt) fault() uint32 { return c.regs().fault_address }
+func (c *sigctxt) trap() uint32 { return c.regs().trap_no }
+func (c *sigctxt) error() uint32 { return c.regs().error_code }
+func (c *sigctxt) oldmask() uint32 { return c.regs().oldmask }
func (c *sigctxt) sigcode() uint32 { return uint32(c.info.si_code) }
func (c *sigctxt) sigaddr() uint32 { return c.info.si_addr }
diff --git a/src/runtime/signal_linux_arm64.go b/src/runtime/signal_linux_arm64.go
index 4964e7b..f3d4d38 100644
--- a/src/runtime/signal_linux_arm64.go
+++ b/src/runtime/signal_linux_arm64.go
@@ -14,42 +14,49 @@ type sigctxt struct {
ctxt unsafe.Pointer
}
+//go:nosplit
+//go:nowritebarrierrec
func (c *sigctxt) regs() *sigcontext { return &(*ucontext)(c.ctxt).uc_mcontext }
-func (c *sigctxt) r0() uint64 { return c.regs().regs[0] }
-func (c *sigctxt) r1() uint64 { return c.regs().regs[1] }
-func (c *sigctxt) r2() uint64 { return c.regs().regs[2] }
-func (c *sigctxt) r3() uint64 { return c.regs().regs[3] }
-func (c *sigctxt) r4() uint64 { return c.regs().regs[4] }
-func (c *sigctxt) r5() uint64 { return c.regs().regs[5] }
-func (c *sigctxt) r6() uint64 { return c.regs().regs[6] }
-func (c *sigctxt) r7() uint64 { return c.regs().regs[7] }
-func (c *sigctxt) r8() uint64 { return c.regs().regs[8] }
-func (c *sigctxt) r9() uint64 { return c.regs().regs[9] }
-func (c *sigctxt) r10() uint64 { return c.regs().regs[10] }
-func (c *sigctxt) r11() uint64 { return c.regs().regs[11] }
-func (c *sigctxt) r12() uint64 { return c.regs().regs[12] }
-func (c *sigctxt) r13() uint64 { return c.regs().regs[13] }
-func (c *sigctxt) r14() uint64 { return c.regs().regs[14] }
-func (c *sigctxt) r15() uint64 { return c.regs().regs[15] }
-func (c *sigctxt) r16() uint64 { return c.regs().regs[16] }
-func (c *sigctxt) r17() uint64 { return c.regs().regs[17] }
-func (c *sigctxt) r18() uint64 { return c.regs().regs[18] }
-func (c *sigctxt) r19() uint64 { return c.regs().regs[19] }
-func (c *sigctxt) r20() uint64 { return c.regs().regs[20] }
-func (c *sigctxt) r21() uint64 { return c.regs().regs[21] }
-func (c *sigctxt) r22() uint64 { return c.regs().regs[22] }
-func (c *sigctxt) r23() uint64 { return c.regs().regs[23] }
-func (c *sigctxt) r24() uint64 { return c.regs().regs[24] }
-func (c *sigctxt) r25() uint64 { return c.regs().regs[25] }
-func (c *sigctxt) r26() uint64 { return c.regs().regs[26] }
-func (c *sigctxt) r27() uint64 { return c.regs().regs[27] }
-func (c *sigctxt) r28() uint64 { return c.regs().regs[28] }
-func (c *sigctxt) r29() uint64 { return c.regs().regs[29] }
-func (c *sigctxt) lr() uint64 { return c.regs().regs[30] }
-func (c *sigctxt) sp() uint64 { return c.regs().sp }
-func (c *sigctxt) pc() uint64 { return c.regs().pc }
-func (c *sigctxt) pstate() uint64 { return c.regs().pstate }
-func (c *sigctxt) fault() uint64 { return c.regs().fault_address }
+
+func (c *sigctxt) r0() uint64 { return c.regs().regs[0] }
+func (c *sigctxt) r1() uint64 { return c.regs().regs[1] }
+func (c *sigctxt) r2() uint64 { return c.regs().regs[2] }
+func (c *sigctxt) r3() uint64 { return c.regs().regs[3] }
+func (c *sigctxt) r4() uint64 { return c.regs().regs[4] }
+func (c *sigctxt) r5() uint64 { return c.regs().regs[5] }
+func (c *sigctxt) r6() uint64 { return c.regs().regs[6] }
+func (c *sigctxt) r7() uint64 { return c.regs().regs[7] }
+func (c *sigctxt) r8() uint64 { return c.regs().regs[8] }
+func (c *sigctxt) r9() uint64 { return c.regs().regs[9] }
+func (c *sigctxt) r10() uint64 { return c.regs().regs[10] }
+func (c *sigctxt) r11() uint64 { return c.regs().regs[11] }
+func (c *sigctxt) r12() uint64 { return c.regs().regs[12] }
+func (c *sigctxt) r13() uint64 { return c.regs().regs[13] }
+func (c *sigctxt) r14() uint64 { return c.regs().regs[14] }
+func (c *sigctxt) r15() uint64 { return c.regs().regs[15] }
+func (c *sigctxt) r16() uint64 { return c.regs().regs[16] }
+func (c *sigctxt) r17() uint64 { return c.regs().regs[17] }
+func (c *sigctxt) r18() uint64 { return c.regs().regs[18] }
+func (c *sigctxt) r19() uint64 { return c.regs().regs[19] }
+func (c *sigctxt) r20() uint64 { return c.regs().regs[20] }
+func (c *sigctxt) r21() uint64 { return c.regs().regs[21] }
+func (c *sigctxt) r22() uint64 { return c.regs().regs[22] }
+func (c *sigctxt) r23() uint64 { return c.regs().regs[23] }
+func (c *sigctxt) r24() uint64 { return c.regs().regs[24] }
+func (c *sigctxt) r25() uint64 { return c.regs().regs[25] }
+func (c *sigctxt) r26() uint64 { return c.regs().regs[26] }
+func (c *sigctxt) r27() uint64 { return c.regs().regs[27] }
+func (c *sigctxt) r28() uint64 { return c.regs().regs[28] }
+func (c *sigctxt) r29() uint64 { return c.regs().regs[29] }
+func (c *sigctxt) lr() uint64 { return c.regs().regs[30] }
+func (c *sigctxt) sp() uint64 { return c.regs().sp }
+
+//go:nosplit
+//go:nowritebarrierrec
+func (c *sigctxt) pc() uint64 { return c.regs().pc }
+
+func (c *sigctxt) pstate() uint64 { return c.regs().pstate }
+func (c *sigctxt) fault() uint64 { return c.regs().fault_address }
func (c *sigctxt) sigcode() uint64 { return uint64(c.info.si_code) }
func (c *sigctxt) sigaddr() uint64 { return c.info.si_addr }
diff --git a/src/runtime/signal_linux_mips64x.go b/src/runtime/signal_linux_mips64x.go
index 0f590e4..9e0cf42 100644
--- a/src/runtime/signal_linux_mips64x.go
+++ b/src/runtime/signal_linux_mips64x.go
@@ -17,44 +17,51 @@ type sigctxt struct {
ctxt unsafe.Pointer
}
+//go:nosplit
+//go:nowritebarrierrec
func (c *sigctxt) regs() *sigcontext { return &(*ucontext)(c.ctxt).uc_mcontext }
-func (c *sigctxt) r0() uint64 { return c.regs().sc_regs[0] }
-func (c *sigctxt) r1() uint64 { return c.regs().sc_regs[1] }
-func (c *sigctxt) r2() uint64 { return c.regs().sc_regs[2] }
-func (c *sigctxt) r3() uint64 { return c.regs().sc_regs[3] }
-func (c *sigctxt) r4() uint64 { return c.regs().sc_regs[4] }
-func (c *sigctxt) r5() uint64 { return c.regs().sc_regs[5] }
-func (c *sigctxt) r6() uint64 { return c.regs().sc_regs[6] }
-func (c *sigctxt) r7() uint64 { return c.regs().sc_regs[7] }
-func (c *sigctxt) r8() uint64 { return c.regs().sc_regs[8] }
-func (c *sigctxt) r9() uint64 { return c.regs().sc_regs[9] }
-func (c *sigctxt) r10() uint64 { return c.regs().sc_regs[10] }
-func (c *sigctxt) r11() uint64 { return c.regs().sc_regs[11] }
-func (c *sigctxt) r12() uint64 { return c.regs().sc_regs[12] }
-func (c *sigctxt) r13() uint64 { return c.regs().sc_regs[13] }
-func (c *sigctxt) r14() uint64 { return c.regs().sc_regs[14] }
-func (c *sigctxt) r15() uint64 { return c.regs().sc_regs[15] }
-func (c *sigctxt) r16() uint64 { return c.regs().sc_regs[16] }
-func (c *sigctxt) r17() uint64 { return c.regs().sc_regs[17] }
-func (c *sigctxt) r18() uint64 { return c.regs().sc_regs[18] }
-func (c *sigctxt) r19() uint64 { return c.regs().sc_regs[19] }
-func (c *sigctxt) r20() uint64 { return c.regs().sc_regs[20] }
-func (c *sigctxt) r21() uint64 { return c.regs().sc_regs[21] }
-func (c *sigctxt) r22() uint64 { return c.regs().sc_regs[22] }
-func (c *sigctxt) r23() uint64 { return c.regs().sc_regs[23] }
-func (c *sigctxt) r24() uint64 { return c.regs().sc_regs[24] }
-func (c *sigctxt) r25() uint64 { return c.regs().sc_regs[25] }
-func (c *sigctxt) r26() uint64 { return c.regs().sc_regs[26] }
-func (c *sigctxt) r27() uint64 { return c.regs().sc_regs[27] }
-func (c *sigctxt) r28() uint64 { return c.regs().sc_regs[28] }
-func (c *sigctxt) r29() uint64 { return c.regs().sc_regs[29] }
-func (c *sigctxt) r30() uint64 { return c.regs().sc_regs[30] }
-func (c *sigctxt) r31() uint64 { return c.regs().sc_regs[31] }
-func (c *sigctxt) sp() uint64 { return c.regs().sc_regs[29] }
-func (c *sigctxt) pc() uint64 { return c.regs().sc_pc }
-func (c *sigctxt) link() uint64 { return c.regs().sc_regs[31] }
-func (c *sigctxt) lo() uint64 { return c.regs().sc_mdlo }
-func (c *sigctxt) hi() uint64 { return c.regs().sc_mdhi }
+
+func (c *sigctxt) r0() uint64 { return c.regs().sc_regs[0] }
+func (c *sigctxt) r1() uint64 { return c.regs().sc_regs[1] }
+func (c *sigctxt) r2() uint64 { return c.regs().sc_regs[2] }
+func (c *sigctxt) r3() uint64 { return c.regs().sc_regs[3] }
+func (c *sigctxt) r4() uint64 { return c.regs().sc_regs[4] }
+func (c *sigctxt) r5() uint64 { return c.regs().sc_regs[5] }
+func (c *sigctxt) r6() uint64 { return c.regs().sc_regs[6] }
+func (c *sigctxt) r7() uint64 { return c.regs().sc_regs[7] }
+func (c *sigctxt) r8() uint64 { return c.regs().sc_regs[8] }
+func (c *sigctxt) r9() uint64 { return c.regs().sc_regs[9] }
+func (c *sigctxt) r10() uint64 { return c.regs().sc_regs[10] }
+func (c *sigctxt) r11() uint64 { return c.regs().sc_regs[11] }
+func (c *sigctxt) r12() uint64 { return c.regs().sc_regs[12] }
+func (c *sigctxt) r13() uint64 { return c.regs().sc_regs[13] }
+func (c *sigctxt) r14() uint64 { return c.regs().sc_regs[14] }
+func (c *sigctxt) r15() uint64 { return c.regs().sc_regs[15] }
+func (c *sigctxt) r16() uint64 { return c.regs().sc_regs[16] }
+func (c *sigctxt) r17() uint64 { return c.regs().sc_regs[17] }
+func (c *sigctxt) r18() uint64 { return c.regs().sc_regs[18] }
+func (c *sigctxt) r19() uint64 { return c.regs().sc_regs[19] }
+func (c *sigctxt) r20() uint64 { return c.regs().sc_regs[20] }
+func (c *sigctxt) r21() uint64 { return c.regs().sc_regs[21] }
+func (c *sigctxt) r22() uint64 { return c.regs().sc_regs[22] }
+func (c *sigctxt) r23() uint64 { return c.regs().sc_regs[23] }
+func (c *sigctxt) r24() uint64 { return c.regs().sc_regs[24] }
+func (c *sigctxt) r25() uint64 { return c.regs().sc_regs[25] }
+func (c *sigctxt) r26() uint64 { return c.regs().sc_regs[26] }
+func (c *sigctxt) r27() uint64 { return c.regs().sc_regs[27] }
+func (c *sigctxt) r28() uint64 { return c.regs().sc_regs[28] }
+func (c *sigctxt) r29() uint64 { return c.regs().sc_regs[29] }
+func (c *sigctxt) r30() uint64 { return c.regs().sc_regs[30] }
+func (c *sigctxt) r31() uint64 { return c.regs().sc_regs[31] }
+func (c *sigctxt) sp() uint64 { return c.regs().sc_regs[29] }
+
+//go:nosplit
+//go:nowritebarrierrec
+func (c *sigctxt) pc() uint64 { return c.regs().sc_pc }
+
+func (c *sigctxt) link() uint64 { return c.regs().sc_regs[31] }
+func (c *sigctxt) lo() uint64 { return c.regs().sc_mdlo }
+func (c *sigctxt) hi() uint64 { return c.regs().sc_mdhi }
func (c *sigctxt) sigcode() uint32 { return uint32(c.info.si_code) }
func (c *sigctxt) sigaddr() uint64 { return c.info.si_addr }
diff --git a/src/runtime/signal_linux_mipsx.go b/src/runtime/signal_linux_mipsx.go
new file mode 100644
index 0000000..c88ac4d
--- /dev/null
+++ b/src/runtime/signal_linux_mipsx.go
@@ -0,0 +1,65 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build linux
+// +build mips mipsle
+
+package runtime
+
+import "unsafe"
+
+type sigctxt struct {
+ info *siginfo
+ ctxt unsafe.Pointer
+}
+
+func (c *sigctxt) regs() *sigcontext { return &(*ucontext)(c.ctxt).uc_mcontext }
+func (c *sigctxt) r0() uint32 { return uint32(c.regs().sc_regs[0]) }
+func (c *sigctxt) r1() uint32 { return uint32(c.regs().sc_regs[1]) }
+func (c *sigctxt) r2() uint32 { return uint32(c.regs().sc_regs[2]) }
+func (c *sigctxt) r3() uint32 { return uint32(c.regs().sc_regs[3]) }
+func (c *sigctxt) r4() uint32 { return uint32(c.regs().sc_regs[4]) }
+func (c *sigctxt) r5() uint32 { return uint32(c.regs().sc_regs[5]) }
+func (c *sigctxt) r6() uint32 { return uint32(c.regs().sc_regs[6]) }
+func (c *sigctxt) r7() uint32 { return uint32(c.regs().sc_regs[7]) }
+func (c *sigctxt) r8() uint32 { return uint32(c.regs().sc_regs[8]) }
+func (c *sigctxt) r9() uint32 { return uint32(c.regs().sc_regs[9]) }
+func (c *sigctxt) r10() uint32 { return uint32(c.regs().sc_regs[10]) }
+func (c *sigctxt) r11() uint32 { return uint32(c.regs().sc_regs[11]) }
+func (c *sigctxt) r12() uint32 { return uint32(c.regs().sc_regs[12]) }
+func (c *sigctxt) r13() uint32 { return uint32(c.regs().sc_regs[13]) }
+func (c *sigctxt) r14() uint32 { return uint32(c.regs().sc_regs[14]) }
+func (c *sigctxt) r15() uint32 { return uint32(c.regs().sc_regs[15]) }
+func (c *sigctxt) r16() uint32 { return uint32(c.regs().sc_regs[16]) }
+func (c *sigctxt) r17() uint32 { return uint32(c.regs().sc_regs[17]) }
+func (c *sigctxt) r18() uint32 { return uint32(c.regs().sc_regs[18]) }
+func (c *sigctxt) r19() uint32 { return uint32(c.regs().sc_regs[19]) }
+func (c *sigctxt) r20() uint32 { return uint32(c.regs().sc_regs[20]) }
+func (c *sigctxt) r21() uint32 { return uint32(c.regs().sc_regs[21]) }
+func (c *sigctxt) r22() uint32 { return uint32(c.regs().sc_regs[22]) }
+func (c *sigctxt) r23() uint32 { return uint32(c.regs().sc_regs[23]) }
+func (c *sigctxt) r24() uint32 { return uint32(c.regs().sc_regs[24]) }
+func (c *sigctxt) r25() uint32 { return uint32(c.regs().sc_regs[25]) }
+func (c *sigctxt) r26() uint32 { return uint32(c.regs().sc_regs[26]) }
+func (c *sigctxt) r27() uint32 { return uint32(c.regs().sc_regs[27]) }
+func (c *sigctxt) r28() uint32 { return uint32(c.regs().sc_regs[28]) }
+func (c *sigctxt) r29() uint32 { return uint32(c.regs().sc_regs[29]) }
+func (c *sigctxt) r30() uint32 { return uint32(c.regs().sc_regs[30]) }
+func (c *sigctxt) r31() uint32 { return uint32(c.regs().sc_regs[31]) }
+func (c *sigctxt) sp() uint32 { return uint32(c.regs().sc_regs[29]) }
+func (c *sigctxt) pc() uint32 { return uint32(c.regs().sc_pc) }
+func (c *sigctxt) link() uint32 { return uint32(c.regs().sc_regs[31]) }
+func (c *sigctxt) lo() uint32 { return uint32(c.regs().sc_mdlo) }
+func (c *sigctxt) hi() uint32 { return uint32(c.regs().sc_mdhi) }
+
+func (c *sigctxt) sigcode() uint32 { return uint32(c.info.si_code) }
+func (c *sigctxt) sigaddr() uint32 { return c.info.si_addr }
+
+func (c *sigctxt) set_r30(x uint32) { c.regs().sc_regs[30] = uint64(x) }
+func (c *sigctxt) set_pc(x uint32) { c.regs().sc_pc = uint64(x) }
+func (c *sigctxt) set_sp(x uint32) { c.regs().sc_regs[29] = uint64(x) }
+func (c *sigctxt) set_link(x uint32) { c.regs().sc_regs[31] = uint64(x) }
+
+func (c *sigctxt) set_sigcode(x uint32) { c.info.si_code = int32(x) }
+func (c *sigctxt) set_sigaddr(x uint32) { c.info.si_addr = x }
diff --git a/src/runtime/signal_linux_ppc64x.go b/src/runtime/signal_linux_ppc64x.go
index 95835ca..b6831bc 100644
--- a/src/runtime/signal_linux_ppc64x.go
+++ b/src/runtime/signal_linux_ppc64x.go
@@ -17,46 +17,53 @@ type sigctxt struct {
ctxt unsafe.Pointer
}
+//go:nosplit
+//go:nowritebarrierrec
func (c *sigctxt) regs() *ptregs { return (*ucontext)(c.ctxt).uc_mcontext.regs }
-func (c *sigctxt) r0() uint64 { return c.regs().gpr[0] }
-func (c *sigctxt) r1() uint64 { return c.regs().gpr[1] }
-func (c *sigctxt) r2() uint64 { return c.regs().gpr[2] }
-func (c *sigctxt) r3() uint64 { return c.regs().gpr[3] }
-func (c *sigctxt) r4() uint64 { return c.regs().gpr[4] }
-func (c *sigctxt) r5() uint64 { return c.regs().gpr[5] }
-func (c *sigctxt) r6() uint64 { return c.regs().gpr[6] }
-func (c *sigctxt) r7() uint64 { return c.regs().gpr[7] }
-func (c *sigctxt) r8() uint64 { return c.regs().gpr[8] }
-func (c *sigctxt) r9() uint64 { return c.regs().gpr[9] }
-func (c *sigctxt) r10() uint64 { return c.regs().gpr[10] }
-func (c *sigctxt) r11() uint64 { return c.regs().gpr[11] }
-func (c *sigctxt) r12() uint64 { return c.regs().gpr[12] }
-func (c *sigctxt) r13() uint64 { return c.regs().gpr[13] }
-func (c *sigctxt) r14() uint64 { return c.regs().gpr[14] }
-func (c *sigctxt) r15() uint64 { return c.regs().gpr[15] }
-func (c *sigctxt) r16() uint64 { return c.regs().gpr[16] }
-func (c *sigctxt) r17() uint64 { return c.regs().gpr[17] }
-func (c *sigctxt) r18() uint64 { return c.regs().gpr[18] }
-func (c *sigctxt) r19() uint64 { return c.regs().gpr[19] }
-func (c *sigctxt) r20() uint64 { return c.regs().gpr[20] }
-func (c *sigctxt) r21() uint64 { return c.regs().gpr[21] }
-func (c *sigctxt) r22() uint64 { return c.regs().gpr[22] }
-func (c *sigctxt) r23() uint64 { return c.regs().gpr[23] }
-func (c *sigctxt) r24() uint64 { return c.regs().gpr[24] }
-func (c *sigctxt) r25() uint64 { return c.regs().gpr[25] }
-func (c *sigctxt) r26() uint64 { return c.regs().gpr[26] }
-func (c *sigctxt) r27() uint64 { return c.regs().gpr[27] }
-func (c *sigctxt) r28() uint64 { return c.regs().gpr[28] }
-func (c *sigctxt) r29() uint64 { return c.regs().gpr[29] }
-func (c *sigctxt) r30() uint64 { return c.regs().gpr[30] }
-func (c *sigctxt) r31() uint64 { return c.regs().gpr[31] }
-func (c *sigctxt) sp() uint64 { return c.regs().gpr[1] }
-func (c *sigctxt) pc() uint64 { return c.regs().nip }
-func (c *sigctxt) trap() uint64 { return c.regs().trap }
-func (c *sigctxt) ctr() uint64 { return c.regs().ctr }
-func (c *sigctxt) link() uint64 { return c.regs().link }
-func (c *sigctxt) xer() uint64 { return c.regs().xer }
-func (c *sigctxt) ccr() uint64 { return c.regs().ccr }
+
+func (c *sigctxt) r0() uint64 { return c.regs().gpr[0] }
+func (c *sigctxt) r1() uint64 { return c.regs().gpr[1] }
+func (c *sigctxt) r2() uint64 { return c.regs().gpr[2] }
+func (c *sigctxt) r3() uint64 { return c.regs().gpr[3] }
+func (c *sigctxt) r4() uint64 { return c.regs().gpr[4] }
+func (c *sigctxt) r5() uint64 { return c.regs().gpr[5] }
+func (c *sigctxt) r6() uint64 { return c.regs().gpr[6] }
+func (c *sigctxt) r7() uint64 { return c.regs().gpr[7] }
+func (c *sigctxt) r8() uint64 { return c.regs().gpr[8] }
+func (c *sigctxt) r9() uint64 { return c.regs().gpr[9] }
+func (c *sigctxt) r10() uint64 { return c.regs().gpr[10] }
+func (c *sigctxt) r11() uint64 { return c.regs().gpr[11] }
+func (c *sigctxt) r12() uint64 { return c.regs().gpr[12] }
+func (c *sigctxt) r13() uint64 { return c.regs().gpr[13] }
+func (c *sigctxt) r14() uint64 { return c.regs().gpr[14] }
+func (c *sigctxt) r15() uint64 { return c.regs().gpr[15] }
+func (c *sigctxt) r16() uint64 { return c.regs().gpr[16] }
+func (c *sigctxt) r17() uint64 { return c.regs().gpr[17] }
+func (c *sigctxt) r18() uint64 { return c.regs().gpr[18] }
+func (c *sigctxt) r19() uint64 { return c.regs().gpr[19] }
+func (c *sigctxt) r20() uint64 { return c.regs().gpr[20] }
+func (c *sigctxt) r21() uint64 { return c.regs().gpr[21] }
+func (c *sigctxt) r22() uint64 { return c.regs().gpr[22] }
+func (c *sigctxt) r23() uint64 { return c.regs().gpr[23] }
+func (c *sigctxt) r24() uint64 { return c.regs().gpr[24] }
+func (c *sigctxt) r25() uint64 { return c.regs().gpr[25] }
+func (c *sigctxt) r26() uint64 { return c.regs().gpr[26] }
+func (c *sigctxt) r27() uint64 { return c.regs().gpr[27] }
+func (c *sigctxt) r28() uint64 { return c.regs().gpr[28] }
+func (c *sigctxt) r29() uint64 { return c.regs().gpr[29] }
+func (c *sigctxt) r30() uint64 { return c.regs().gpr[30] }
+func (c *sigctxt) r31() uint64 { return c.regs().gpr[31] }
+func (c *sigctxt) sp() uint64 { return c.regs().gpr[1] }
+
+//go:nosplit
+//go:nowritebarrierrec
+func (c *sigctxt) pc() uint64 { return c.regs().nip }
+
+func (c *sigctxt) trap() uint64 { return c.regs().trap }
+func (c *sigctxt) ctr() uint64 { return c.regs().ctr }
+func (c *sigctxt) link() uint64 { return c.regs().link }
+func (c *sigctxt) xer() uint64 { return c.regs().xer }
+func (c *sigctxt) ccr() uint64 { return c.regs().ccr }
func (c *sigctxt) sigcode() uint32 { return uint32(c.info.si_code) }
func (c *sigctxt) sigaddr() uint64 { return c.info.si_addr }
diff --git a/src/runtime/signal_linux_s390x.go b/src/runtime/signal_linux_s390x.go
index 155d3a3..de71ee9 100644
--- a/src/runtime/signal_linux_s390x.go
+++ b/src/runtime/signal_linux_s390x.go
@@ -14,28 +14,35 @@ type sigctxt struct {
ctxt unsafe.Pointer
}
+//go:nosplit
+//go:nowritebarrierrec
func (c *sigctxt) regs() *sigcontext {
return (*sigcontext)(unsafe.Pointer(&(*ucontext)(c.ctxt).uc_mcontext))
}
-func (c *sigctxt) r0() uint64 { return c.regs().gregs[0] }
-func (c *sigctxt) r1() uint64 { return c.regs().gregs[1] }
-func (c *sigctxt) r2() uint64 { return c.regs().gregs[2] }
-func (c *sigctxt) r3() uint64 { return c.regs().gregs[3] }
-func (c *sigctxt) r4() uint64 { return c.regs().gregs[4] }
-func (c *sigctxt) r5() uint64 { return c.regs().gregs[5] }
-func (c *sigctxt) r6() uint64 { return c.regs().gregs[6] }
-func (c *sigctxt) r7() uint64 { return c.regs().gregs[7] }
-func (c *sigctxt) r8() uint64 { return c.regs().gregs[8] }
-func (c *sigctxt) r9() uint64 { return c.regs().gregs[9] }
-func (c *sigctxt) r10() uint64 { return c.regs().gregs[10] }
-func (c *sigctxt) r11() uint64 { return c.regs().gregs[11] }
-func (c *sigctxt) r12() uint64 { return c.regs().gregs[12] }
-func (c *sigctxt) r13() uint64 { return c.regs().gregs[13] }
-func (c *sigctxt) r14() uint64 { return c.regs().gregs[14] }
-func (c *sigctxt) r15() uint64 { return c.regs().gregs[15] }
-func (c *sigctxt) link() uint64 { return c.regs().gregs[14] }
-func (c *sigctxt) sp() uint64 { return c.regs().gregs[15] }
-func (c *sigctxt) pc() uint64 { return c.regs().psw_addr }
+
+func (c *sigctxt) r0() uint64 { return c.regs().gregs[0] }
+func (c *sigctxt) r1() uint64 { return c.regs().gregs[1] }
+func (c *sigctxt) r2() uint64 { return c.regs().gregs[2] }
+func (c *sigctxt) r3() uint64 { return c.regs().gregs[3] }
+func (c *sigctxt) r4() uint64 { return c.regs().gregs[4] }
+func (c *sigctxt) r5() uint64 { return c.regs().gregs[5] }
+func (c *sigctxt) r6() uint64 { return c.regs().gregs[6] }
+func (c *sigctxt) r7() uint64 { return c.regs().gregs[7] }
+func (c *sigctxt) r8() uint64 { return c.regs().gregs[8] }
+func (c *sigctxt) r9() uint64 { return c.regs().gregs[9] }
+func (c *sigctxt) r10() uint64 { return c.regs().gregs[10] }
+func (c *sigctxt) r11() uint64 { return c.regs().gregs[11] }
+func (c *sigctxt) r12() uint64 { return c.regs().gregs[12] }
+func (c *sigctxt) r13() uint64 { return c.regs().gregs[13] }
+func (c *sigctxt) r14() uint64 { return c.regs().gregs[14] }
+func (c *sigctxt) r15() uint64 { return c.regs().gregs[15] }
+func (c *sigctxt) link() uint64 { return c.regs().gregs[14] }
+func (c *sigctxt) sp() uint64 { return c.regs().gregs[15] }
+
+//go:nosplit
+//go:nowritebarrierrec
+func (c *sigctxt) pc() uint64 { return c.regs().psw_addr }
+
func (c *sigctxt) sigcode() uint32 { return uint32(c.info.si_code) }
func (c *sigctxt) sigaddr() uint64 { return c.info.si_addr }
@@ -70,139 +77,45 @@ func dumpregs(c *sigctxt) {
print("link ", hex(c.link()), "\n")
}
-var crashing int32
-
-// May run during STW, so write barriers are not allowed.
-//
+//go:nosplit
//go:nowritebarrierrec
-func sighandler(sig uint32, info *siginfo, ctxt unsafe.Pointer, gp *g) {
- _g_ := getg()
- c := &sigctxt{info, ctxt}
-
- if sig == _SIGPROF {
- sigprof(uintptr(c.pc()), uintptr(c.sp()), uintptr(c.link()), gp, _g_.m)
- return
- }
- flags := int32(_SigThrow)
- if sig < uint32(len(sigtable)) {
- flags = sigtable[sig].flags
- }
- if c.sigcode() != _SI_USER && flags&_SigPanic != 0 {
- // Make it look like a call to the signal func.
- // Have to pass arguments out of band since
- // augmenting the stack frame would break
- // the unwinding code.
- gp.sig = sig
- gp.sigcode0 = uintptr(c.sigcode())
- gp.sigcode1 = uintptr(c.sigaddr())
- gp.sigpc = uintptr(c.pc())
-
- // We arrange link, and pc to pretend the panicking
- // function calls sigpanic directly.
- // Always save LINK to stack so that panics in leaf
- // functions are correctly handled. This smashes
- // the stack frame but we're not going back there
- // anyway.
- sp := c.sp() - sys.MinFrameSize
- c.set_sp(sp)
- *(*uint64)(unsafe.Pointer(uintptr(sp))) = c.link()
-
- pc := uintptr(gp.sigpc)
-
- // If we don't recognize the PC as code
- // but we do recognize the link register as code,
- // then assume this was a call to non-code and treat like
- // pc == 0, to make unwinding show the context.
- if pc != 0 && findfunc(pc) == nil && findfunc(uintptr(c.link())) != nil {
- pc = 0
- }
-
- // Don't bother saving PC if it's zero, which is
- // probably a call to a nil func: the old link register
- // is more useful in the stack trace.
- if pc != 0 {
- c.set_link(uint64(pc))
- }
-
- // In case we are panicking from external C code
- c.set_r0(0)
- c.set_r13(uint64(uintptr(unsafe.Pointer(gp))))
- c.set_pc(uint64(funcPC(sigpanic)))
- return
- }
-
- if c.sigcode() == _SI_USER || flags&_SigNotify != 0 {
- if sigsend(sig) {
- return
- }
- }
-
- if c.sigcode() == _SI_USER && signal_ignored(sig) {
- return
- }
-
- if flags&_SigKill != 0 {
- dieFromSignal(int32(sig))
- }
-
- if flags&_SigThrow == 0 {
- return
- }
-
- _g_.m.throwing = 1
- _g_.m.caughtsig.set(gp)
-
- if crashing == 0 {
- startpanic()
- }
-
- if sig < uint32(len(sigtable)) {
- print(sigtable[sig].name, "\n")
- } else {
- print("Signal ", sig, "\n")
- }
-
- print("PC=", hex(c.pc()), " m=", _g_.m.id, "\n")
- if _g_.m.lockedg != nil && _g_.m.ncgo > 0 && gp == _g_.m.g0 {
- print("signal arrived during cgo execution\n")
- gp = _g_.m.lockedg
- }
- print("\n")
-
- level, _, docrash := gotraceback()
- if level > 0 {
- goroutineheader(gp)
- tracebacktrap(uintptr(c.pc()), uintptr(c.sp()), uintptr(c.link()), gp)
- if crashing > 0 && gp != _g_.m.curg && _g_.m.curg != nil && readgstatus(_g_.m.curg)&^_Gscan == _Grunning {
- // tracebackothers on original m skipped this one; trace it now.
- goroutineheader(_g_.m.curg)
- traceback(^uintptr(0), ^uintptr(0), 0, gp)
- } else if crashing == 0 {
- tracebackothers(gp)
- print("\n")
- }
- dumpregs(c)
+func (c *sigctxt) sigpc() uintptr { return uintptr(c.pc()) }
+
+func (c *sigctxt) sigsp() uintptr { return uintptr(c.sp()) }
+func (c *sigctxt) siglr() uintptr { return uintptr(c.link()) }
+func (c *sigctxt) fault() uintptr { return uintptr(c.sigaddr()) }
+
+// preparePanic sets up the stack to look like a call to sigpanic.
+func (c *sigctxt) preparePanic(sig uint32, gp *g) {
+ // We arrange link, and pc to pretend the panicking
+ // function calls sigpanic directly.
+ // Always save LINK to stack so that panics in leaf
+ // functions are correctly handled. This smashes
+ // the stack frame but we're not going back there
+ // anyway.
+ sp := c.sp() - sys.MinFrameSize
+ c.set_sp(sp)
+ *(*uint64)(unsafe.Pointer(uintptr(sp))) = c.link()
+
+ pc := uintptr(gp.sigpc)
+
+ // If we don't recognize the PC as code
+ // but we do recognize the link register as code,
+ // then assume this was a call to non-code and treat like
+ // pc == 0, to make unwinding show the context.
+ if pc != 0 && findfunc(pc) == nil && findfunc(uintptr(c.link())) != nil {
+ pc = 0
}
- if docrash {
- crashing++
- if crashing < sched.mcount {
- // There are other m's that need to dump their stacks.
- // Relay SIGQUIT to the next m by sending it to the current process.
- // All m's that have already received SIGQUIT have signal masks blocking
- // receipt of any signals, so the SIGQUIT will go to an m that hasn't seen it yet.
- // When the last m receives the SIGQUIT, it will fall through to the call to
- // crash below. Just in case the relaying gets botched, each m involved in
- // the relay sleeps for 5 seconds and then does the crash/exit itself.
- // In expected operation, the last m has received the SIGQUIT and run
- // crash/exit and the process is gone, all long before any of the
- // 5-second sleeps have finished.
- print("\n-----\n\n")
- raiseproc(_SIGQUIT)
- usleep(5 * 1000 * 1000)
- }
- crash()
+ // Don't bother saving PC if it's zero, which is
+ // probably a call to a nil func: the old link register
+ // is more useful in the stack trace.
+ if pc != 0 {
+ c.set_link(uint64(pc))
}
- exit(2)
+ // In case we are panicking from external C code
+ c.set_r0(0)
+ c.set_r13(uint64(uintptr(unsafe.Pointer(gp))))
+ c.set_pc(uint64(funcPC(sigpanic)))
}
diff --git a/src/runtime/signal_mips64x.go b/src/runtime/signal_mips64x.go
index 4dbeb42..973ec2d 100644
--- a/src/runtime/signal_mips64x.go
+++ b/src/runtime/signal_mips64x.go
@@ -51,138 +51,44 @@ func dumpregs(c *sigctxt) {
print("hi ", hex(c.hi()), "\n")
}
-var crashing int32
-
-// May run during STW, so write barriers are not allowed.
-//
+//go:nosplit
//go:nowritebarrierrec
-func sighandler(sig uint32, info *siginfo, ctxt unsafe.Pointer, gp *g) {
- _g_ := getg()
- c := &sigctxt{info, ctxt}
-
- if sig == _SIGPROF {
- sigprof(uintptr(c.pc()), uintptr(c.sp()), uintptr(c.link()), gp, _g_.m)
- return
- }
- flags := int32(_SigThrow)
- if sig < uint32(len(sigtable)) {
- flags = sigtable[sig].flags
- }
- if c.sigcode() != _SI_USER && flags&_SigPanic != 0 {
- // Make it look like a call to the signal func.
- // Have to pass arguments out of band since
- // augmenting the stack frame would break
- // the unwinding code.
- gp.sig = sig
- gp.sigcode0 = uintptr(c.sigcode())
- gp.sigcode1 = uintptr(c.sigaddr())
- gp.sigpc = uintptr(c.pc())
-
- // We arrange link, and pc to pretend the panicking
- // function calls sigpanic directly.
- // Always save LINK to stack so that panics in leaf
- // functions are correctly handled. This smashes
- // the stack frame but we're not going back there
- // anyway.
- sp := c.sp() - sys.PtrSize
- c.set_sp(sp)
- *(*uint64)(unsafe.Pointer(uintptr(sp))) = c.link()
-
- pc := gp.sigpc
-
- // If we don't recognize the PC as code
- // but we do recognize the link register as code,
- // then assume this was a call to non-code and treat like
- // pc == 0, to make unwinding show the context.
- if pc != 0 && findfunc(pc) == nil && findfunc(uintptr(c.link())) != nil {
- pc = 0
- }
-
- // Don't bother saving PC if it's zero, which is
- // probably a call to a nil func: the old link register
- // is more useful in the stack trace.
- if pc != 0 {
- c.set_link(uint64(pc))
- }
-
- // In case we are panicking from external C code
- c.set_r30(uint64(uintptr(unsafe.Pointer(gp))))
- c.set_pc(uint64(funcPC(sigpanic)))
- return
- }
-
- if c.sigcode() == _SI_USER || flags&_SigNotify != 0 {
- if sigsend(sig) {
- return
- }
- }
-
- if c.sigcode() == _SI_USER && signal_ignored(sig) {
- return
- }
-
- if flags&_SigKill != 0 {
- dieFromSignal(int32(sig))
- }
-
- if flags&_SigThrow == 0 {
- return
- }
-
- _g_.m.throwing = 1
- _g_.m.caughtsig.set(gp)
-
- if crashing == 0 {
- startpanic()
- }
-
- if sig < uint32(len(sigtable)) {
- print(sigtable[sig].name, "\n")
- } else {
- print("Signal ", sig, "\n")
- }
-
- print("PC=", hex(c.pc()), " m=", _g_.m.id, "\n")
- if _g_.m.lockedg != nil && _g_.m.ncgo > 0 && gp == _g_.m.g0 {
- print("signal arrived during cgo execution\n")
- gp = _g_.m.lockedg
- }
- print("\n")
-
- level, _, docrash := gotraceback()
- if level > 0 {
- goroutineheader(gp)
- tracebacktrap(uintptr(c.pc()), uintptr(c.sp()), uintptr(c.link()), gp)
- if crashing > 0 && gp != _g_.m.curg && _g_.m.curg != nil && readgstatus(_g_.m.curg)&^_Gscan == _Grunning {
- // tracebackothers on original m skipped this one; trace it now.
- goroutineheader(_g_.m.curg)
- traceback(^uintptr(0), ^uintptr(0), 0, gp)
- } else if crashing == 0 {
- tracebackothers(gp)
- print("\n")
- }
- dumpregs(c)
+func (c *sigctxt) sigpc() uintptr { return uintptr(c.pc()) }
+
+func (c *sigctxt) sigsp() uintptr { return uintptr(c.sp()) }
+func (c *sigctxt) siglr() uintptr { return uintptr(c.link()) }
+func (c *sigctxt) fault() uintptr { return uintptr(c.sigaddr()) }
+
+// preparePanic sets up the stack to look like a call to sigpanic.
+func (c *sigctxt) preparePanic(sig uint32, gp *g) {
+ // We arrange link, and pc to pretend the panicking
+ // function calls sigpanic directly.
+ // Always save LINK to stack so that panics in leaf
+ // functions are correctly handled. This smashes
+ // the stack frame but we're not going back there
+ // anyway.
+ sp := c.sp() - sys.PtrSize
+ c.set_sp(sp)
+ *(*uint64)(unsafe.Pointer(uintptr(sp))) = c.link()
+
+ pc := gp.sigpc
+
+ // If we don't recognize the PC as code
+ // but we do recognize the link register as code,
+ // then assume this was a call to non-code and treat like
+ // pc == 0, to make unwinding show the context.
+ if pc != 0 && findfunc(pc) == nil && findfunc(uintptr(c.link())) != nil {
+ pc = 0
}
- if docrash {
- crashing++
- if crashing < sched.mcount {
- // There are other m's that need to dump their stacks.
- // Relay SIGQUIT to the next m by sending it to the current process.
- // All m's that have already received SIGQUIT have signal masks blocking
- // receipt of any signals, so the SIGQUIT will go to an m that hasn't seen it yet.
- // When the last m receives the SIGQUIT, it will fall through to the call to
- // crash below. Just in case the relaying gets botched, each m involved in
- // the relay sleeps for 5 seconds and then does the crash/exit itself.
- // In expected operation, the last m has received the SIGQUIT and run
- // crash/exit and the process is gone, all long before any of the
- // 5-second sleeps have finished.
- print("\n-----\n\n")
- raiseproc(_SIGQUIT)
- usleep(5 * 1000 * 1000)
- }
- crash()
+ // Don't bother saving PC if it's zero, which is
+ // probably a call to a nil func: the old link register
+ // is more useful in the stack trace.
+ if pc != 0 {
+ c.set_link(uint64(pc))
}
- exit(2)
+ // In case we are panicking from external C code
+ c.set_r30(uint64(uintptr(unsafe.Pointer(gp))))
+ c.set_pc(uint64(funcPC(sigpanic)))
}
diff --git a/src/runtime/signal_mipsx.go b/src/runtime/signal_mipsx.go
new file mode 100644
index 0000000..62df79c
--- /dev/null
+++ b/src/runtime/signal_mipsx.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.
+
+// +build linux
+// +build mips mipsle
+
+package runtime
+
+import (
+ "runtime/internal/sys"
+ "unsafe"
+)
+
+func dumpregs(c *sigctxt) {
+ print("r0 ", hex(c.r0()), "\t")
+ print("r1 ", hex(c.r1()), "\n")
+ print("r2 ", hex(c.r2()), "\t")
+ print("r3 ", hex(c.r3()), "\n")
+ print("r4 ", hex(c.r4()), "\t")
+ print("r5 ", hex(c.r5()), "\n")
+ print("r6 ", hex(c.r6()), "\t")
+ print("r7 ", hex(c.r7()), "\n")
+ print("r8 ", hex(c.r8()), "\t")
+ print("r9 ", hex(c.r9()), "\n")
+ print("r10 ", hex(c.r10()), "\t")
+ print("r11 ", hex(c.r11()), "\n")
+ print("r12 ", hex(c.r12()), "\t")
+ print("r13 ", hex(c.r13()), "\n")
+ print("r14 ", hex(c.r14()), "\t")
+ print("r15 ", hex(c.r15()), "\n")
+ print("r16 ", hex(c.r16()), "\t")
+ print("r17 ", hex(c.r17()), "\n")
+ print("r18 ", hex(c.r18()), "\t")
+ print("r19 ", hex(c.r19()), "\n")
+ print("r20 ", hex(c.r20()), "\t")
+ print("r21 ", hex(c.r21()), "\n")
+ print("r22 ", hex(c.r22()), "\t")
+ print("r23 ", hex(c.r23()), "\n")
+ print("r24 ", hex(c.r24()), "\t")
+ print("r25 ", hex(c.r25()), "\n")
+ print("r26 ", hex(c.r26()), "\t")
+ print("r27 ", hex(c.r27()), "\n")
+ print("r28 ", hex(c.r28()), "\t")
+ print("r29 ", hex(c.r29()), "\n")
+ print("r30 ", hex(c.r30()), "\t")
+ print("r31 ", hex(c.r31()), "\n")
+ print("pc ", hex(c.pc()), "\t")
+ print("link ", hex(c.link()), "\n")
+ print("lo ", hex(c.lo()), "\t")
+ print("hi ", hex(c.hi()), "\n")
+}
+
+func (c *sigctxt) sigpc() uintptr { return uintptr(c.pc()) }
+func (c *sigctxt) sigsp() uintptr { return uintptr(c.sp()) }
+func (c *sigctxt) siglr() uintptr { return uintptr(c.link()) }
+func (c *sigctxt) fault() uintptr { return uintptr(c.sigaddr()) }
+
+// preparePanic sets up the stack to look like a call to sigpanic.
+func (c *sigctxt) preparePanic(sig uint32, gp *g) {
+ // We arrange link, and pc to pretend the panicking
+ // function calls sigpanic directly.
+ // Always save LINK to stack so that panics in leaf
+ // functions are correctly handled. This smashes
+ // the stack frame but we're not going back there
+ // anyway.
+ sp := c.sp() - sys.MinFrameSize
+ c.set_sp(sp)
+ *(*uint32)(unsafe.Pointer(uintptr(sp))) = c.link()
+
+ pc := gp.sigpc
+
+ // If we don't recognize the PC as code
+ // but we do recognize the link register as code,
+ // then assume this was a call to non-code and treat like
+ // pc == 0, to make unwinding show the context.
+ if pc != 0 && findfunc(pc) == nil && findfunc(uintptr(c.link())) != nil {
+ pc = 0
+ }
+
+ // Don't bother saving PC if it's zero, which is
+ // probably a call to a nil func: the old link register
+ // is more useful in the stack trace.
+ if pc != 0 {
+ c.set_link(uint32(pc))
+ }
+
+ // In case we are panicking from external C code
+ c.set_r30(uint32(uintptr(unsafe.Pointer(gp))))
+ c.set_pc(uint32(funcPC(sigpanic)))
+}
diff --git a/src/runtime/signal_nacl_386.go b/src/runtime/signal_nacl_386.go
index 1f48590..1a30a89 100644
--- a/src/runtime/signal_nacl_386.go
+++ b/src/runtime/signal_nacl_386.go
@@ -11,22 +11,29 @@ type sigctxt struct {
ctxt unsafe.Pointer
}
+//go:nosplit
+//go:nowritebarrierrec
func (c *sigctxt) regs() *excregs386 { return &(*exccontext)(c.ctxt).regs }
-func (c *sigctxt) eax() uint32 { return c.regs().eax }
-func (c *sigctxt) ebx() uint32 { return c.regs().ebx }
-func (c *sigctxt) ecx() uint32 { return c.regs().ecx }
-func (c *sigctxt) edx() uint32 { return c.regs().edx }
-func (c *sigctxt) edi() uint32 { return c.regs().edi }
-func (c *sigctxt) esi() uint32 { return c.regs().esi }
-func (c *sigctxt) ebp() uint32 { return c.regs().ebp }
-func (c *sigctxt) esp() uint32 { return c.regs().esp }
-func (c *sigctxt) eip() uint32 { return c.regs().eip }
-func (c *sigctxt) eflags() uint32 { return c.regs().eflags }
-func (c *sigctxt) cs() uint32 { return ^uint32(0) }
-func (c *sigctxt) fs() uint32 { return ^uint32(0) }
-func (c *sigctxt) gs() uint32 { return ^uint32(0) }
-func (c *sigctxt) sigcode() uint32 { return ^uint32(0) }
-func (c *sigctxt) sigaddr() uint32 { return 0 }
+
+func (c *sigctxt) eax() uint32 { return c.regs().eax }
+func (c *sigctxt) ebx() uint32 { return c.regs().ebx }
+func (c *sigctxt) ecx() uint32 { return c.regs().ecx }
+func (c *sigctxt) edx() uint32 { return c.regs().edx }
+func (c *sigctxt) edi() uint32 { return c.regs().edi }
+func (c *sigctxt) esi() uint32 { return c.regs().esi }
+func (c *sigctxt) ebp() uint32 { return c.regs().ebp }
+func (c *sigctxt) esp() uint32 { return c.regs().esp }
+
+//go:nosplit
+//go:nowritebarrierrec
+func (c *sigctxt) eip() uint32 { return c.regs().eip }
+
+func (c *sigctxt) eflags() uint32 { return c.regs().eflags }
+func (c *sigctxt) cs() uint32 { return ^uint32(0) }
+func (c *sigctxt) fs() uint32 { return ^uint32(0) }
+func (c *sigctxt) gs() uint32 { return ^uint32(0) }
+func (c *sigctxt) sigcode() uint32 { return ^uint32(0) }
+func (c *sigctxt) sigaddr() uint32 { return 0 }
func (c *sigctxt) set_eip(x uint32) { c.regs().eip = x }
func (c *sigctxt) set_esp(x uint32) { c.regs().esp = x }
diff --git a/src/runtime/signal_nacl_amd64p32.go b/src/runtime/signal_nacl_amd64p32.go
index cb72dd0..6d656fe 100644
--- a/src/runtime/signal_nacl_amd64p32.go
+++ b/src/runtime/signal_nacl_amd64p32.go
@@ -11,26 +11,33 @@ type sigctxt struct {
ctxt unsafe.Pointer
}
+//go:nosplit
+//go:nowritebarrierrec
func (c *sigctxt) regs() *excregsamd64 {
return &(*exccontext)(c.ctxt).regs
}
-func (c *sigctxt) rax() uint64 { return c.regs().rax }
-func (c *sigctxt) rbx() uint64 { return c.regs().rbx }
-func (c *sigctxt) rcx() uint64 { return c.regs().rcx }
-func (c *sigctxt) rdx() uint64 { return c.regs().rdx }
-func (c *sigctxt) rdi() uint64 { return c.regs().rdi }
-func (c *sigctxt) rsi() uint64 { return c.regs().rsi }
-func (c *sigctxt) rbp() uint64 { return c.regs().rbp }
-func (c *sigctxt) rsp() uint64 { return c.regs().rsp }
-func (c *sigctxt) r8() uint64 { return c.regs().r8 }
-func (c *sigctxt) r9() uint64 { return c.regs().r9 }
-func (c *sigctxt) r10() uint64 { return c.regs().r10 }
-func (c *sigctxt) r11() uint64 { return c.regs().r11 }
-func (c *sigctxt) r12() uint64 { return c.regs().r12 }
-func (c *sigctxt) r13() uint64 { return c.regs().r13 }
-func (c *sigctxt) r14() uint64 { return c.regs().r14 }
-func (c *sigctxt) r15() uint64 { return c.regs().r15 }
-func (c *sigctxt) rip() uint64 { return c.regs().rip }
+
+func (c *sigctxt) rax() uint64 { return c.regs().rax }
+func (c *sigctxt) rbx() uint64 { return c.regs().rbx }
+func (c *sigctxt) rcx() uint64 { return c.regs().rcx }
+func (c *sigctxt) rdx() uint64 { return c.regs().rdx }
+func (c *sigctxt) rdi() uint64 { return c.regs().rdi }
+func (c *sigctxt) rsi() uint64 { return c.regs().rsi }
+func (c *sigctxt) rbp() uint64 { return c.regs().rbp }
+func (c *sigctxt) rsp() uint64 { return c.regs().rsp }
+func (c *sigctxt) r8() uint64 { return c.regs().r8 }
+func (c *sigctxt) r9() uint64 { return c.regs().r9 }
+func (c *sigctxt) r10() uint64 { return c.regs().r10 }
+func (c *sigctxt) r11() uint64 { return c.regs().r11 }
+func (c *sigctxt) r12() uint64 { return c.regs().r12 }
+func (c *sigctxt) r13() uint64 { return c.regs().r13 }
+func (c *sigctxt) r14() uint64 { return c.regs().r14 }
+func (c *sigctxt) r15() uint64 { return c.regs().r15 }
+
+//go:nosplit
+//go:nowritebarrierrec
+func (c *sigctxt) rip() uint64 { return c.regs().rip }
+
func (c *sigctxt) rflags() uint64 { return uint64(c.regs().rflags) }
func (c *sigctxt) cs() uint64 { return ^uint64(0) }
func (c *sigctxt) fs() uint64 { return ^uint64(0) }
diff --git a/src/runtime/signal_nacl_arm.go b/src/runtime/signal_nacl_arm.go
index b99827c..959dbfb 100644
--- a/src/runtime/signal_nacl_arm.go
+++ b/src/runtime/signal_nacl_arm.go
@@ -11,24 +11,30 @@ type sigctxt struct {
ctxt unsafe.Pointer
}
+//go:nosplit
+//go:nowritebarrierrec
func (c *sigctxt) regs() *excregsarm { return &(*exccontext)(c.ctxt).regs }
-func (c *sigctxt) r0() uint32 { return c.regs().r0 }
-func (c *sigctxt) r1() uint32 { return c.regs().r1 }
-func (c *sigctxt) r2() uint32 { return c.regs().r2 }
-func (c *sigctxt) r3() uint32 { return c.regs().r3 }
-func (c *sigctxt) r4() uint32 { return c.regs().r4 }
-func (c *sigctxt) r5() uint32 { return c.regs().r5 }
-func (c *sigctxt) r6() uint32 { return c.regs().r6 }
-func (c *sigctxt) r7() uint32 { return c.regs().r7 }
-func (c *sigctxt) r8() uint32 { return c.regs().r8 }
-func (c *sigctxt) r9() uint32 { return c.regs().r9 }
-func (c *sigctxt) r10() uint32 { return c.regs().r10 }
-func (c *sigctxt) fp() uint32 { return c.regs().r11 }
-func (c *sigctxt) ip() uint32 { return c.regs().r12 }
-func (c *sigctxt) sp() uint32 { return c.regs().sp }
-func (c *sigctxt) lr() uint32 { return c.regs().lr }
-func (c *sigctxt) pc() uint32 { return c.regs().pc }
+func (c *sigctxt) r0() uint32 { return c.regs().r0 }
+func (c *sigctxt) r1() uint32 { return c.regs().r1 }
+func (c *sigctxt) r2() uint32 { return c.regs().r2 }
+func (c *sigctxt) r3() uint32 { return c.regs().r3 }
+func (c *sigctxt) r4() uint32 { return c.regs().r4 }
+func (c *sigctxt) r5() uint32 { return c.regs().r5 }
+func (c *sigctxt) r6() uint32 { return c.regs().r6 }
+func (c *sigctxt) r7() uint32 { return c.regs().r7 }
+func (c *sigctxt) r8() uint32 { return c.regs().r8 }
+func (c *sigctxt) r9() uint32 { return c.regs().r9 }
+func (c *sigctxt) r10() uint32 { return c.regs().r10 }
+func (c *sigctxt) fp() uint32 { return c.regs().r11 }
+func (c *sigctxt) ip() uint32 { return c.regs().r12 }
+func (c *sigctxt) sp() uint32 { return c.regs().sp }
+func (c *sigctxt) lr() uint32 { return c.regs().lr }
+
+//go:nosplit
+//go:nowritebarrierrec
+func (c *sigctxt) pc() uint32 { return c.regs().pc }
+
func (c *sigctxt) cpsr() uint32 { return c.regs().cpsr }
func (c *sigctxt) fault() uint32 { return ^uint32(0) }
func (c *sigctxt) trap() uint32 { return ^uint32(0) }
diff --git a/src/runtime/signal_netbsd_386.go b/src/runtime/signal_netbsd_386.go
index af49d5d..845a575 100644
--- a/src/runtime/signal_netbsd_386.go
+++ b/src/runtime/signal_netbsd_386.go
@@ -11,21 +11,28 @@ type sigctxt struct {
ctxt unsafe.Pointer
}
+//go:nosplit
+//go:nowritebarrierrec
func (c *sigctxt) regs() *mcontextt { return &(*ucontextt)(c.ctxt).uc_mcontext }
-func (c *sigctxt) eax() uint32 { return c.regs().__gregs[_REG_EAX] }
-func (c *sigctxt) ebx() uint32 { return c.regs().__gregs[_REG_EBX] }
-func (c *sigctxt) ecx() uint32 { return c.regs().__gregs[_REG_ECX] }
-func (c *sigctxt) edx() uint32 { return c.regs().__gregs[_REG_EDX] }
-func (c *sigctxt) edi() uint32 { return c.regs().__gregs[_REG_EDI] }
-func (c *sigctxt) esi() uint32 { return c.regs().__gregs[_REG_ESI] }
-func (c *sigctxt) ebp() uint32 { return c.regs().__gregs[_REG_EBP] }
-func (c *sigctxt) esp() uint32 { return c.regs().__gregs[_REG_UESP] }
-func (c *sigctxt) eip() uint32 { return c.regs().__gregs[_REG_EIP] }
-func (c *sigctxt) eflags() uint32 { return c.regs().__gregs[_REG_EFL] }
-func (c *sigctxt) cs() uint32 { return c.regs().__gregs[_REG_CS] }
-func (c *sigctxt) fs() uint32 { return c.regs().__gregs[_REG_FS] }
-func (c *sigctxt) gs() uint32 { return c.regs().__gregs[_REG_GS] }
-func (c *sigctxt) sigcode() uint32 { return uint32(c.info._code) }
+
+func (c *sigctxt) eax() uint32 { return c.regs().__gregs[_REG_EAX] }
+func (c *sigctxt) ebx() uint32 { return c.regs().__gregs[_REG_EBX] }
+func (c *sigctxt) ecx() uint32 { return c.regs().__gregs[_REG_ECX] }
+func (c *sigctxt) edx() uint32 { return c.regs().__gregs[_REG_EDX] }
+func (c *sigctxt) edi() uint32 { return c.regs().__gregs[_REG_EDI] }
+func (c *sigctxt) esi() uint32 { return c.regs().__gregs[_REG_ESI] }
+func (c *sigctxt) ebp() uint32 { return c.regs().__gregs[_REG_EBP] }
+func (c *sigctxt) esp() uint32 { return c.regs().__gregs[_REG_UESP] }
+
+//go:nosplit
+//go:nowritebarrierrec
+func (c *sigctxt) eip() uint32 { return c.regs().__gregs[_REG_EIP] }
+
+func (c *sigctxt) eflags() uint32 { return c.regs().__gregs[_REG_EFL] }
+func (c *sigctxt) cs() uint32 { return c.regs().__gregs[_REG_CS] }
+func (c *sigctxt) fs() uint32 { return c.regs().__gregs[_REG_FS] }
+func (c *sigctxt) gs() uint32 { return c.regs().__gregs[_REG_GS] }
+func (c *sigctxt) sigcode() uint32 { return uint32(c.info._code) }
func (c *sigctxt) sigaddr() uint32 {
return *(*uint32)(unsafe.Pointer(&c.info._reason[0]))
}
diff --git a/src/runtime/signal_netbsd_amd64.go b/src/runtime/signal_netbsd_amd64.go
index db230f8..67fe437 100644
--- a/src/runtime/signal_netbsd_amd64.go
+++ b/src/runtime/signal_netbsd_amd64.go
@@ -11,26 +11,33 @@ type sigctxt struct {
ctxt unsafe.Pointer
}
+//go:nosplit
+//go:nowritebarrierrec
func (c *sigctxt) regs() *mcontextt {
return (*mcontextt)(unsafe.Pointer(&(*ucontextt)(c.ctxt).uc_mcontext))
}
-func (c *sigctxt) rax() uint64 { return c.regs().__gregs[_REG_RAX] }
-func (c *sigctxt) rbx() uint64 { return c.regs().__gregs[_REG_RBX] }
-func (c *sigctxt) rcx() uint64 { return c.regs().__gregs[_REG_RCX] }
-func (c *sigctxt) rdx() uint64 { return c.regs().__gregs[_REG_RDX] }
-func (c *sigctxt) rdi() uint64 { return c.regs().__gregs[_REG_RDI] }
-func (c *sigctxt) rsi() uint64 { return c.regs().__gregs[_REG_RSI] }
-func (c *sigctxt) rbp() uint64 { return c.regs().__gregs[_REG_RBP] }
-func (c *sigctxt) rsp() uint64 { return c.regs().__gregs[_REG_RSP] }
-func (c *sigctxt) r8() uint64 { return c.regs().__gregs[_REG_R8] }
-func (c *sigctxt) r9() uint64 { return c.regs().__gregs[_REG_R8] }
-func (c *sigctxt) r10() uint64 { return c.regs().__gregs[_REG_R10] }
-func (c *sigctxt) r11() uint64 { return c.regs().__gregs[_REG_R11] }
-func (c *sigctxt) r12() uint64 { return c.regs().__gregs[_REG_R12] }
-func (c *sigctxt) r13() uint64 { return c.regs().__gregs[_REG_R13] }
-func (c *sigctxt) r14() uint64 { return c.regs().__gregs[_REG_R14] }
-func (c *sigctxt) r15() uint64 { return c.regs().__gregs[_REG_R15] }
-func (c *sigctxt) rip() uint64 { return c.regs().__gregs[_REG_RIP] }
+
+func (c *sigctxt) rax() uint64 { return c.regs().__gregs[_REG_RAX] }
+func (c *sigctxt) rbx() uint64 { return c.regs().__gregs[_REG_RBX] }
+func (c *sigctxt) rcx() uint64 { return c.regs().__gregs[_REG_RCX] }
+func (c *sigctxt) rdx() uint64 { return c.regs().__gregs[_REG_RDX] }
+func (c *sigctxt) rdi() uint64 { return c.regs().__gregs[_REG_RDI] }
+func (c *sigctxt) rsi() uint64 { return c.regs().__gregs[_REG_RSI] }
+func (c *sigctxt) rbp() uint64 { return c.regs().__gregs[_REG_RBP] }
+func (c *sigctxt) rsp() uint64 { return c.regs().__gregs[_REG_RSP] }
+func (c *sigctxt) r8() uint64 { return c.regs().__gregs[_REG_R8] }
+func (c *sigctxt) r9() uint64 { return c.regs().__gregs[_REG_R8] }
+func (c *sigctxt) r10() uint64 { return c.regs().__gregs[_REG_R10] }
+func (c *sigctxt) r11() uint64 { return c.regs().__gregs[_REG_R11] }
+func (c *sigctxt) r12() uint64 { return c.regs().__gregs[_REG_R12] }
+func (c *sigctxt) r13() uint64 { return c.regs().__gregs[_REG_R13] }
+func (c *sigctxt) r14() uint64 { return c.regs().__gregs[_REG_R14] }
+func (c *sigctxt) r15() uint64 { return c.regs().__gregs[_REG_R15] }
+
+//go:nosplit
+//go:nowritebarrierrec
+func (c *sigctxt) rip() uint64 { return c.regs().__gregs[_REG_RIP] }
+
func (c *sigctxt) rflags() uint64 { return c.regs().__gregs[_REG_RFLAGS] }
func (c *sigctxt) cs() uint64 { return c.regs().__gregs[_REG_CS] }
func (c *sigctxt) fs() uint64 { return c.regs().__gregs[_REG_FS] }
diff --git a/src/runtime/signal_netbsd_arm.go b/src/runtime/signal_netbsd_arm.go
index 4e58d3b..64cfffa 100644
--- a/src/runtime/signal_netbsd_arm.go
+++ b/src/runtime/signal_netbsd_arm.go
@@ -11,28 +11,35 @@ type sigctxt struct {
ctxt unsafe.Pointer
}
+//go:nosplit
+//go:nowritebarrierrec
func (c *sigctxt) regs() *mcontextt { return &(*ucontextt)(c.ctxt).uc_mcontext }
-func (c *sigctxt) r0() uint32 { return c.regs().__gregs[_REG_R0] }
-func (c *sigctxt) r1() uint32 { return c.regs().__gregs[_REG_R1] }
-func (c *sigctxt) r2() uint32 { return c.regs().__gregs[_REG_R2] }
-func (c *sigctxt) r3() uint32 { return c.regs().__gregs[_REG_R3] }
-func (c *sigctxt) r4() uint32 { return c.regs().__gregs[_REG_R4] }
-func (c *sigctxt) r5() uint32 { return c.regs().__gregs[_REG_R5] }
-func (c *sigctxt) r6() uint32 { return c.regs().__gregs[_REG_R6] }
-func (c *sigctxt) r7() uint32 { return c.regs().__gregs[_REG_R7] }
-func (c *sigctxt) r8() uint32 { return c.regs().__gregs[_REG_R8] }
-func (c *sigctxt) r9() uint32 { return c.regs().__gregs[_REG_R9] }
-func (c *sigctxt) r10() uint32 { return c.regs().__gregs[_REG_R10] }
-func (c *sigctxt) fp() uint32 { return c.regs().__gregs[_REG_R11] }
-func (c *sigctxt) ip() uint32 { return c.regs().__gregs[_REG_R12] }
-func (c *sigctxt) sp() uint32 { return c.regs().__gregs[_REG_R13] }
-func (c *sigctxt) lr() uint32 { return c.regs().__gregs[_REG_R14] }
-func (c *sigctxt) pc() uint32 { return c.regs().__gregs[_REG_R15] }
-func (c *sigctxt) cpsr() uint32 { return c.regs().__gregs[_REG_CPSR] }
-func (c *sigctxt) fault() uint32 { return uint32(c.info._reason) }
-func (c *sigctxt) trap() uint32 { return 0 }
-func (c *sigctxt) error() uint32 { return 0 }
-func (c *sigctxt) oldmask() uint32 { return 0 }
+
+func (c *sigctxt) r0() uint32 { return c.regs().__gregs[_REG_R0] }
+func (c *sigctxt) r1() uint32 { return c.regs().__gregs[_REG_R1] }
+func (c *sigctxt) r2() uint32 { return c.regs().__gregs[_REG_R2] }
+func (c *sigctxt) r3() uint32 { return c.regs().__gregs[_REG_R3] }
+func (c *sigctxt) r4() uint32 { return c.regs().__gregs[_REG_R4] }
+func (c *sigctxt) r5() uint32 { return c.regs().__gregs[_REG_R5] }
+func (c *sigctxt) r6() uint32 { return c.regs().__gregs[_REG_R6] }
+func (c *sigctxt) r7() uint32 { return c.regs().__gregs[_REG_R7] }
+func (c *sigctxt) r8() uint32 { return c.regs().__gregs[_REG_R8] }
+func (c *sigctxt) r9() uint32 { return c.regs().__gregs[_REG_R9] }
+func (c *sigctxt) r10() uint32 { return c.regs().__gregs[_REG_R10] }
+func (c *sigctxt) fp() uint32 { return c.regs().__gregs[_REG_R11] }
+func (c *sigctxt) ip() uint32 { return c.regs().__gregs[_REG_R12] }
+func (c *sigctxt) sp() uint32 { return c.regs().__gregs[_REG_R13] }
+func (c *sigctxt) lr() uint32 { return c.regs().__gregs[_REG_R14] }
+
+//go:nosplit
+//go:nowritebarrierrec
+func (c *sigctxt) pc() uint32 { return c.regs().__gregs[_REG_R15] }
+
+func (c *sigctxt) cpsr() uint32 { return c.regs().__gregs[_REG_CPSR] }
+func (c *sigctxt) fault() uint32 { return uint32(c.info._reason) }
+func (c *sigctxt) trap() uint32 { return 0 }
+func (c *sigctxt) error() uint32 { return 0 }
+func (c *sigctxt) oldmask() uint32 { return 0 }
func (c *sigctxt) sigcode() uint32 { return uint32(c.info._code) }
func (c *sigctxt) sigaddr() uint32 { return uint32(c.info._reason) }
diff --git a/src/runtime/signal_openbsd.go b/src/runtime/signal_openbsd.go
index efe30da..30a3b8e 100644
--- a/src/runtime/signal_openbsd.go
+++ b/src/runtime/signal_openbsd.go
@@ -4,8 +4,6 @@
package runtime
-import "unsafe"
-
type sigTabT struct {
flags int32
name string
@@ -46,42 +44,3 @@ var sigtable = [...]sigTabT{
/* 31 */ {_SigNotify, "SIGUSR2: user-defined signal 2"},
/* 32 */ {_SigNotify, "SIGTHR: reserved"},
}
-
-//go:nosplit
-//go:nowritebarrierrec
-func sigtrampgo(sig uint32, info *siginfo, ctx unsafe.Pointer) {
- if sigfwdgo(sig, info, ctx) {
- return
- }
- g := getg()
- if g == nil {
- badsignal(uintptr(sig), &sigctxt{info, ctx})
- return
- }
-
- // If some non-Go code called sigaltstack, adjust.
- sp := uintptr(unsafe.Pointer(&sig))
- if sp < g.m.gsignal.stack.lo || sp >= g.m.gsignal.stack.hi {
- var st stackt
- sigaltstack(nil, &st)
- if st.ss_flags&_SS_DISABLE != 0 {
- setg(nil)
- cgocallback(unsafe.Pointer(funcPC(noSignalStack)), noescape(unsafe.Pointer(&sig)), unsafe.Sizeof(sig), 0)
- }
- stsp := uintptr(unsafe.Pointer(st.ss_sp))
- if sp < stsp || sp >= stsp+st.ss_size {
- setg(nil)
- cgocallback(unsafe.Pointer(funcPC(sigNotOnStack)), noescape(unsafe.Pointer(&sig)), unsafe.Sizeof(sig), 0)
- }
- g.m.gsignal.stack.lo = stsp
- g.m.gsignal.stack.hi = stsp + st.ss_size
- g.m.gsignal.stackguard0 = stsp + _StackGuard
- g.m.gsignal.stackguard1 = stsp + _StackGuard
- g.m.gsignal.stackAlloc = st.ss_size
- g.m.gsignal.stktopsp = getcallersp(unsafe.Pointer(&sig))
- }
-
- setg(g.m.gsignal)
- sighandler(sig, info, ctx, g)
- setg(g)
-}
diff --git a/src/runtime/signal_openbsd_386.go b/src/runtime/signal_openbsd_386.go
index dbbb2c8..2fc4b1d 100644
--- a/src/runtime/signal_openbsd_386.go
+++ b/src/runtime/signal_openbsd_386.go
@@ -11,19 +11,25 @@ type sigctxt struct {
ctxt unsafe.Pointer
}
+//go:nosplit
+//go:nowritebarrierrec
func (c *sigctxt) regs() *sigcontext {
return (*sigcontext)(c.ctxt)
}
-func (c *sigctxt) eax() uint32 { return c.regs().sc_eax }
-func (c *sigctxt) ebx() uint32 { return c.regs().sc_ebx }
-func (c *sigctxt) ecx() uint32 { return c.regs().sc_ecx }
-func (c *sigctxt) edx() uint32 { return c.regs().sc_edx }
-func (c *sigctxt) edi() uint32 { return c.regs().sc_edi }
-func (c *sigctxt) esi() uint32 { return c.regs().sc_esi }
-func (c *sigctxt) ebp() uint32 { return c.regs().sc_ebp }
-func (c *sigctxt) esp() uint32 { return c.regs().sc_esp }
-func (c *sigctxt) eip() uint32 { return c.regs().sc_eip }
+func (c *sigctxt) eax() uint32 { return c.regs().sc_eax }
+func (c *sigctxt) ebx() uint32 { return c.regs().sc_ebx }
+func (c *sigctxt) ecx() uint32 { return c.regs().sc_ecx }
+func (c *sigctxt) edx() uint32 { return c.regs().sc_edx }
+func (c *sigctxt) edi() uint32 { return c.regs().sc_edi }
+func (c *sigctxt) esi() uint32 { return c.regs().sc_esi }
+func (c *sigctxt) ebp() uint32 { return c.regs().sc_ebp }
+func (c *sigctxt) esp() uint32 { return c.regs().sc_esp }
+
+//go:nosplit
+//go:nowritebarrierrec
+func (c *sigctxt) eip() uint32 { return c.regs().sc_eip }
+
func (c *sigctxt) eflags() uint32 { return c.regs().sc_eflags }
func (c *sigctxt) cs() uint32 { return c.regs().sc_cs }
func (c *sigctxt) fs() uint32 { return c.regs().sc_fs }
diff --git a/src/runtime/signal_openbsd_amd64.go b/src/runtime/signal_openbsd_amd64.go
index 5631ab4..091a88a 100644
--- a/src/runtime/signal_openbsd_amd64.go
+++ b/src/runtime/signal_openbsd_amd64.go
@@ -11,27 +11,33 @@ type sigctxt struct {
ctxt unsafe.Pointer
}
+//go:nosplit
+//go:nowritebarrierrec
func (c *sigctxt) regs() *sigcontext {
return (*sigcontext)(c.ctxt)
}
-func (c *sigctxt) rax() uint64 { return c.regs().sc_rax }
-func (c *sigctxt) rbx() uint64 { return c.regs().sc_rbx }
-func (c *sigctxt) rcx() uint64 { return c.regs().sc_rcx }
-func (c *sigctxt) rdx() uint64 { return c.regs().sc_rdx }
-func (c *sigctxt) rdi() uint64 { return c.regs().sc_rdi }
-func (c *sigctxt) rsi() uint64 { return c.regs().sc_rsi }
-func (c *sigctxt) rbp() uint64 { return c.regs().sc_rbp }
-func (c *sigctxt) rsp() uint64 { return c.regs().sc_rsp }
-func (c *sigctxt) r8() uint64 { return c.regs().sc_r8 }
-func (c *sigctxt) r9() uint64 { return c.regs().sc_r9 }
-func (c *sigctxt) r10() uint64 { return c.regs().sc_r10 }
-func (c *sigctxt) r11() uint64 { return c.regs().sc_r11 }
-func (c *sigctxt) r12() uint64 { return c.regs().sc_r12 }
-func (c *sigctxt) r13() uint64 { return c.regs().sc_r13 }
-func (c *sigctxt) r14() uint64 { return c.regs().sc_r14 }
-func (c *sigctxt) r15() uint64 { return c.regs().sc_r15 }
-func (c *sigctxt) rip() uint64 { return c.regs().sc_rip }
+func (c *sigctxt) rax() uint64 { return c.regs().sc_rax }
+func (c *sigctxt) rbx() uint64 { return c.regs().sc_rbx }
+func (c *sigctxt) rcx() uint64 { return c.regs().sc_rcx }
+func (c *sigctxt) rdx() uint64 { return c.regs().sc_rdx }
+func (c *sigctxt) rdi() uint64 { return c.regs().sc_rdi }
+func (c *sigctxt) rsi() uint64 { return c.regs().sc_rsi }
+func (c *sigctxt) rbp() uint64 { return c.regs().sc_rbp }
+func (c *sigctxt) rsp() uint64 { return c.regs().sc_rsp }
+func (c *sigctxt) r8() uint64 { return c.regs().sc_r8 }
+func (c *sigctxt) r9() uint64 { return c.regs().sc_r9 }
+func (c *sigctxt) r10() uint64 { return c.regs().sc_r10 }
+func (c *sigctxt) r11() uint64 { return c.regs().sc_r11 }
+func (c *sigctxt) r12() uint64 { return c.regs().sc_r12 }
+func (c *sigctxt) r13() uint64 { return c.regs().sc_r13 }
+func (c *sigctxt) r14() uint64 { return c.regs().sc_r14 }
+func (c *sigctxt) r15() uint64 { return c.regs().sc_r15 }
+
+//go:nosplit
+//go:nowritebarrierrec
+func (c *sigctxt) rip() uint64 { return c.regs().sc_rip }
+
func (c *sigctxt) rflags() uint64 { return c.regs().sc_rflags }
func (c *sigctxt) cs() uint64 { return c.regs().sc_cs }
func (c *sigctxt) fs() uint64 { return c.regs().sc_fs }
diff --git a/src/runtime/signal_openbsd_arm.go b/src/runtime/signal_openbsd_arm.go
index 3158a4e..66aea93 100644
--- a/src/runtime/signal_openbsd_arm.go
+++ b/src/runtime/signal_openbsd_arm.go
@@ -11,26 +11,32 @@ type sigctxt struct {
ctxt unsafe.Pointer
}
+//go:nosplit
+//go:nowritebarrierrec
func (c *sigctxt) regs() *sigcontext {
return (*sigcontext)(c.ctxt)
}
-func (c *sigctxt) r0() uint32 { return c.regs().sc_r0 }
-func (c *sigctxt) r1() uint32 { return c.regs().sc_r1 }
-func (c *sigctxt) r2() uint32 { return c.regs().sc_r2 }
-func (c *sigctxt) r3() uint32 { return c.regs().sc_r3 }
-func (c *sigctxt) r4() uint32 { return c.regs().sc_r4 }
-func (c *sigctxt) r5() uint32 { return c.regs().sc_r5 }
-func (c *sigctxt) r6() uint32 { return c.regs().sc_r6 }
-func (c *sigctxt) r7() uint32 { return c.regs().sc_r7 }
-func (c *sigctxt) r8() uint32 { return c.regs().sc_r8 }
-func (c *sigctxt) r9() uint32 { return c.regs().sc_r9 }
-func (c *sigctxt) r10() uint32 { return c.regs().sc_r10 }
-func (c *sigctxt) fp() uint32 { return c.regs().sc_r11 }
-func (c *sigctxt) ip() uint32 { return c.regs().sc_r12 }
-func (c *sigctxt) sp() uint32 { return c.regs().sc_usr_sp }
-func (c *sigctxt) lr() uint32 { return c.regs().sc_usr_lr }
-func (c *sigctxt) pc() uint32 { return c.regs().sc_pc }
+func (c *sigctxt) r0() uint32 { return c.regs().sc_r0 }
+func (c *sigctxt) r1() uint32 { return c.regs().sc_r1 }
+func (c *sigctxt) r2() uint32 { return c.regs().sc_r2 }
+func (c *sigctxt) r3() uint32 { return c.regs().sc_r3 }
+func (c *sigctxt) r4() uint32 { return c.regs().sc_r4 }
+func (c *sigctxt) r5() uint32 { return c.regs().sc_r5 }
+func (c *sigctxt) r6() uint32 { return c.regs().sc_r6 }
+func (c *sigctxt) r7() uint32 { return c.regs().sc_r7 }
+func (c *sigctxt) r8() uint32 { return c.regs().sc_r8 }
+func (c *sigctxt) r9() uint32 { return c.regs().sc_r9 }
+func (c *sigctxt) r10() uint32 { return c.regs().sc_r10 }
+func (c *sigctxt) fp() uint32 { return c.regs().sc_r11 }
+func (c *sigctxt) ip() uint32 { return c.regs().sc_r12 }
+func (c *sigctxt) sp() uint32 { return c.regs().sc_usr_sp }
+func (c *sigctxt) lr() uint32 { return c.regs().sc_usr_lr }
+
+//go:nosplit
+//go:nowritebarrierrec
+func (c *sigctxt) pc() uint32 { return c.regs().sc_pc }
+
func (c *sigctxt) cpsr() uint32 { return c.regs().sc_spsr }
func (c *sigctxt) fault() uint32 { return c.sigaddr() }
func (c *sigctxt) trap() uint32 { return 0 }
diff --git a/src/runtime/signal_ppc64x.go b/src/runtime/signal_ppc64x.go
index 01a4af7..f09f890 100644
--- a/src/runtime/signal_ppc64x.go
+++ b/src/runtime/signal_ppc64x.go
@@ -53,140 +53,45 @@ func dumpregs(c *sigctxt) {
print("trap ", hex(c.trap()), "\n")
}
-var crashing int32
-
-// May run during STW, so write barriers are not allowed.
-//
+//go:nosplit
//go:nowritebarrierrec
-func sighandler(sig uint32, info *siginfo, ctxt unsafe.Pointer, gp *g) {
- _g_ := getg()
- c := &sigctxt{info, ctxt}
-
- if sig == _SIGPROF {
- sigprof(uintptr(c.pc()), uintptr(c.sp()), uintptr(c.link()), gp, _g_.m)
- return
- }
- flags := int32(_SigThrow)
- if sig < uint32(len(sigtable)) {
- flags = sigtable[sig].flags
- }
- if c.sigcode() != _SI_USER && flags&_SigPanic != 0 {
- // Make it look like a call to the signal func.
- // Have to pass arguments out of band since
- // augmenting the stack frame would break
- // the unwinding code.
- gp.sig = sig
- gp.sigcode0 = uintptr(c.sigcode())
- gp.sigcode1 = uintptr(c.fault())
- gp.sigpc = uintptr(c.pc())
-
- // We arrange link, and pc to pretend the panicking
- // function calls sigpanic directly.
- // Always save LINK to stack so that panics in leaf
- // functions are correctly handled. This smashes
- // the stack frame but we're not going back there
- // anyway.
- sp := c.sp() - sys.MinFrameSize
- c.set_sp(sp)
- *(*uint64)(unsafe.Pointer(uintptr(sp))) = c.link()
-
- pc := gp.sigpc
-
- // If we don't recognize the PC as code
- // but we do recognize the link register as code,
- // then assume this was a call to non-code and treat like
- // pc == 0, to make unwinding show the context.
- if pc != 0 && findfunc(pc) == nil && findfunc(uintptr(c.link())) != nil {
- pc = 0
- }
-
- // Don't bother saving PC if it's zero, which is
- // probably a call to a nil func: the old link register
- // is more useful in the stack trace.
- if pc != 0 {
- c.set_link(uint64(pc))
- }
-
- // In case we are panicking from external C code
- c.set_r0(0)
- c.set_r30(uint64(uintptr(unsafe.Pointer(gp))))
- c.set_r12(uint64(funcPC(sigpanic)))
- c.set_pc(uint64(funcPC(sigpanic)))
- return
- }
-
- if c.sigcode() == _SI_USER || flags&_SigNotify != 0 {
- if sigsend(sig) {
- return
- }
- }
-
- if c.sigcode() == _SI_USER && signal_ignored(sig) {
- return
- }
-
- if flags&_SigKill != 0 {
- dieFromSignal(int32(sig))
- }
-
- if flags&_SigThrow == 0 {
- return
- }
-
- _g_.m.throwing = 1
- _g_.m.caughtsig.set(gp)
-
- if crashing == 0 {
- startpanic()
- }
-
- if sig < uint32(len(sigtable)) {
- print(sigtable[sig].name, "\n")
- } else {
- print("Signal ", sig, "\n")
- }
-
- print("PC=", hex(c.pc()), " m=", _g_.m.id, "\n")
- if _g_.m.lockedg != nil && _g_.m.ncgo > 0 && gp == _g_.m.g0 {
- print("signal arrived during cgo execution\n")
- gp = _g_.m.lockedg
- }
- print("\n")
-
- level, _, docrash := gotraceback()
- if level > 0 {
- goroutineheader(gp)
- tracebacktrap(uintptr(c.pc()), uintptr(c.sp()), uintptr(c.link()), gp)
- if crashing > 0 && gp != _g_.m.curg && _g_.m.curg != nil && readgstatus(_g_.m.curg)&^_Gscan == _Grunning {
- // tracebackothers on original m skipped this one; trace it now.
- goroutineheader(_g_.m.curg)
- traceback(^uintptr(0), ^uintptr(0), 0, gp)
- } else if crashing == 0 {
- tracebackothers(gp)
- print("\n")
- }
- dumpregs(c)
+func (c *sigctxt) sigpc() uintptr { return uintptr(c.pc()) }
+
+func (c *sigctxt) sigsp() uintptr { return uintptr(c.sp()) }
+func (c *sigctxt) siglr() uintptr { return uintptr(c.link()) }
+
+// preparePanic sets up the stack to look like a call to sigpanic.
+func (c *sigctxt) preparePanic(sig uint32, gp *g) {
+ // We arrange link, and pc to pretend the panicking
+ // function calls sigpanic directly.
+ // Always save LINK to stack so that panics in leaf
+ // functions are correctly handled. This smashes
+ // the stack frame but we're not going back there
+ // anyway.
+ sp := c.sp() - sys.MinFrameSize
+ c.set_sp(sp)
+ *(*uint64)(unsafe.Pointer(uintptr(sp))) = c.link()
+
+ pc := gp.sigpc
+
+ // If we don't recognize the PC as code
+ // but we do recognize the link register as code,
+ // then assume this was a call to non-code and treat like
+ // pc == 0, to make unwinding show the context.
+ if pc != 0 && findfunc(pc) == nil && findfunc(uintptr(c.link())) != nil {
+ pc = 0
}
- if docrash {
- crashing++
- if crashing < sched.mcount {
- // There are other m's that need to dump their stacks.
- // Relay SIGQUIT to the next m by sending it to the current process.
- // All m's that have already received SIGQUIT have signal masks blocking
- // receipt of any signals, so the SIGQUIT will go to an m that hasn't seen it yet.
- // When the last m receives the SIGQUIT, it will fall through to the call to
- // crash below. Just in case the relaying gets botched, each m involved in
- // the relay sleeps for 5 seconds and then does the crash/exit itself.
- // In expected operation, the last m has received the SIGQUIT and run
- // crash/exit and the process is gone, all long before any of the
- // 5-second sleeps have finished.
- print("\n-----\n\n")
- raiseproc(_SIGQUIT)
- usleep(5 * 1000 * 1000)
- }
- crash()
+ // Don't bother saving PC if it's zero, which is
+ // probably a call to a nil func: the old link register
+ // is more useful in the stack trace.
+ if pc != 0 {
+ c.set_link(uint64(pc))
}
- exit(2)
+ // In case we are panicking from external C code
+ c.set_r0(0)
+ c.set_r30(uint64(uintptr(unsafe.Pointer(gp))))
+ c.set_r12(uint64(funcPC(sigpanic)))
+ c.set_pc(uint64(funcPC(sigpanic)))
}
diff --git a/src/runtime/signal_sighandler.go b/src/runtime/signal_sighandler.go
new file mode 100644
index 0000000..5af12d7
--- /dev/null
+++ b/src/runtime/signal_sighandler.go
@@ -0,0 +1,133 @@
+// Copyright 2013 The Go Authors. 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 runtime
+
+import (
+ "unsafe"
+)
+
+// crashing is the number of m's we have waited for when implementing
+// GOTRACEBACK=crash when a signal is received.
+var crashing int32
+
+// sighandler is invoked when a signal occurs. The global g will be
+// set to a gsignal goroutine and we will be running on the alternate
+// signal stack. The parameter g will be the value of the global g
+// when the signal occurred. The sig, info, and ctxt parameters are
+// from the system signal handler: they are the parameters passed when
+// the SA is passed to the sigaction system call.
+//
+// The garbage collector may have stopped the world, so write barriers
+// are not allowed.
+//
+//go:nowritebarrierrec
+func sighandler(sig uint32, info *siginfo, ctxt unsafe.Pointer, gp *g) {
+ _g_ := getg()
+ c := &sigctxt{info, ctxt}
+
+ if sig == _SIGPROF {
+ sigprof(c.sigpc(), c.sigsp(), c.siglr(), gp, _g_.m)
+ return
+ }
+
+ flags := int32(_SigThrow)
+ if sig < uint32(len(sigtable)) {
+ flags = sigtable[sig].flags
+ }
+ if c.sigcode() != _SI_USER && flags&_SigPanic != 0 {
+ // The signal is going to cause a panic.
+ // Arrange the stack so that it looks like the point
+ // where the signal occurred made a call to the
+ // function sigpanic. Then set the PC to sigpanic.
+
+ // Have to pass arguments out of band since
+ // augmenting the stack frame would break
+ // the unwinding code.
+ gp.sig = sig
+ gp.sigcode0 = uintptr(c.sigcode())
+ gp.sigcode1 = uintptr(c.fault())
+ gp.sigpc = c.sigpc()
+
+ c.preparePanic(sig, gp)
+ return
+ }
+
+ if c.sigcode() == _SI_USER || flags&_SigNotify != 0 {
+ if sigsend(sig) {
+ return
+ }
+ }
+
+ if c.sigcode() == _SI_USER && signal_ignored(sig) {
+ return
+ }
+
+ if flags&_SigKill != 0 {
+ dieFromSignal(sig)
+ }
+
+ if flags&_SigThrow == 0 {
+ return
+ }
+
+ _g_.m.throwing = 1
+ _g_.m.caughtsig.set(gp)
+
+ if crashing == 0 {
+ startpanic()
+ }
+
+ if sig < uint32(len(sigtable)) {
+ print(sigtable[sig].name, "\n")
+ } else {
+ print("Signal ", sig, "\n")
+ }
+
+ print("PC=", hex(c.sigpc()), " m=", _g_.m.id, " sigcode=", c.sigcode(), "\n")
+ if _g_.m.lockedg != nil && _g_.m.ncgo > 0 && gp == _g_.m.g0 {
+ print("signal arrived during cgo execution\n")
+ gp = _g_.m.lockedg
+ }
+ print("\n")
+
+ level, _, docrash := gotraceback()
+ if level > 0 {
+ goroutineheader(gp)
+ tracebacktrap(c.sigpc(), c.sigsp(), c.siglr(), gp)
+ if crashing > 0 && gp != _g_.m.curg && _g_.m.curg != nil && readgstatus(_g_.m.curg)&^_Gscan == _Grunning {
+ // tracebackothers on original m skipped this one; trace it now.
+ goroutineheader(_g_.m.curg)
+ traceback(^uintptr(0), ^uintptr(0), 0, gp)
+ } else if crashing == 0 {
+ tracebackothers(gp)
+ print("\n")
+ }
+ dumpregs(c)
+ }
+
+ if docrash {
+ crashing++
+ if crashing < sched.mcount {
+ // There are other m's that need to dump their stacks.
+ // Relay SIGQUIT to the next m by sending it to the current process.
+ // All m's that have already received SIGQUIT have signal masks blocking
+ // receipt of any signals, so the SIGQUIT will go to an m that hasn't seen it yet.
+ // When the last m receives the SIGQUIT, it will fall through to the call to
+ // crash below. Just in case the relaying gets botched, each m involved in
+ // the relay sleeps for 5 seconds and then does the crash/exit itself.
+ // In expected operation, the last m has received the SIGQUIT and run
+ // crash/exit and the process is gone, all long before any of the
+ // 5-second sleeps have finished.
+ print("\n-----\n\n")
+ raiseproc(_SIGQUIT)
+ usleep(5 * 1000 * 1000)
+ }
+ crash()
+ }
+
+ exit(2)
+}
diff --git a/src/runtime/signal_sigtramp.go b/src/runtime/signal_sigtramp.go
deleted file mode 100644
index dbbbcd0..0000000
--- a/src/runtime/signal_sigtramp.go
+++ /dev/null
@@ -1,58 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build dragonfly linux netbsd
-
-package runtime
-
-import "unsafe"
-
-// Continuation of the (assembly) sigtramp() logic.
-// This may be called with the world stopped.
-//go:nosplit
-//go:nowritebarrierrec
-func sigtrampgo(sig uint32, info *siginfo, ctx unsafe.Pointer) {
- if sigfwdgo(sig, info, ctx) {
- return
- }
- g := getg()
- if g == nil {
- if sig == _SIGPROF {
- // Ignore profiling signals that arrive on
- // non-Go threads. On some systems they will
- // be handled directly by the signal handler,
- // by calling sigprofNonGo, in which case we won't
- // get here anyhow.
- return
- }
- badsignal(uintptr(sig), &sigctxt{info, ctx})
- return
- }
-
- // If some non-Go code called sigaltstack, adjust.
- sp := uintptr(unsafe.Pointer(&sig))
- if sp < g.m.gsignal.stack.lo || sp >= g.m.gsignal.stack.hi {
- var st sigaltstackt
- sigaltstack(nil, &st)
- if st.ss_flags&_SS_DISABLE != 0 {
- setg(nil)
- cgocallback(unsafe.Pointer(funcPC(noSignalStack)), noescape(unsafe.Pointer(&sig)), unsafe.Sizeof(sig), 0)
- }
- stsp := uintptr(unsafe.Pointer(st.ss_sp))
- if sp < stsp || sp >= stsp+st.ss_size {
- setg(nil)
- cgocallback(unsafe.Pointer(funcPC(sigNotOnStack)), noescape(unsafe.Pointer(&sig)), unsafe.Sizeof(sig), 0)
- }
- g.m.gsignal.stack.lo = stsp
- g.m.gsignal.stack.hi = stsp + st.ss_size
- g.m.gsignal.stackguard0 = stsp + _StackGuard
- g.m.gsignal.stackguard1 = stsp + _StackGuard
- g.m.gsignal.stackAlloc = st.ss_size
- g.m.gsignal.stktopsp = getcallersp(unsafe.Pointer(&sig))
- }
-
- setg(g.m.gsignal)
- sighandler(sig, info, ctx, g)
- setg(g)
-}
diff --git a/src/runtime/signal_solaris.go b/src/runtime/signal_solaris.go
index a86f7bf..c931c22 100644
--- a/src/runtime/signal_solaris.go
+++ b/src/runtime/signal_solaris.go
@@ -33,7 +33,7 @@ var sigtable = [...]sigTabT{
/* 20 */ {_SigNotify, "SIGWINCH: window size change"},
/* 21 */ {_SigNotify, "SIGURG: urgent socket condition"},
/* 22 */ {_SigNotify, "SIGPOLL: pollable event occurred"},
- /* 23 */ {_SigNotify + _SigDefault, "SIGSTOP: stop (cannot be caught or ignored)"},
+ /* 23 */ {0, "SIGSTOP: stop (cannot be caught or ignored)"},
/* 24 */ {_SigNotify + _SigDefault, "SIGTSTP: user stop requested from tty"},
/* 25 */ {_SigNotify + _SigDefault, "SIGCONT: stopped process has been continued"},
/* 26 */ {_SigNotify + _SigDefault, "SIGTTIN: background tty read attempted"},
diff --git a/src/runtime/signal_solaris_amd64.go b/src/runtime/signal_solaris_amd64.go
index a577c8c..b1da313 100644
--- a/src/runtime/signal_solaris_amd64.go
+++ b/src/runtime/signal_solaris_amd64.go
@@ -11,26 +11,33 @@ type sigctxt struct {
ctxt unsafe.Pointer
}
+//go:nosplit
+//go:nowritebarrierrec
func (c *sigctxt) regs() *mcontext {
return (*mcontext)(unsafe.Pointer(&(*ucontext)(c.ctxt).uc_mcontext))
}
-func (c *sigctxt) rax() uint64 { return uint64(c.regs().gregs[_REG_RAX]) }
-func (c *sigctxt) rbx() uint64 { return uint64(c.regs().gregs[_REG_RBX]) }
-func (c *sigctxt) rcx() uint64 { return uint64(c.regs().gregs[_REG_RCX]) }
-func (c *sigctxt) rdx() uint64 { return uint64(c.regs().gregs[_REG_RDX]) }
-func (c *sigctxt) rdi() uint64 { return uint64(c.regs().gregs[_REG_RDI]) }
-func (c *sigctxt) rsi() uint64 { return uint64(c.regs().gregs[_REG_RSI]) }
-func (c *sigctxt) rbp() uint64 { return uint64(c.regs().gregs[_REG_RBP]) }
-func (c *sigctxt) rsp() uint64 { return uint64(c.regs().gregs[_REG_RSP]) }
-func (c *sigctxt) r8() uint64 { return uint64(c.regs().gregs[_REG_R8]) }
-func (c *sigctxt) r9() uint64 { return uint64(c.regs().gregs[_REG_R9]) }
-func (c *sigctxt) r10() uint64 { return uint64(c.regs().gregs[_REG_R10]) }
-func (c *sigctxt) r11() uint64 { return uint64(c.regs().gregs[_REG_R11]) }
-func (c *sigctxt) r12() uint64 { return uint64(c.regs().gregs[_REG_R12]) }
-func (c *sigctxt) r13() uint64 { return uint64(c.regs().gregs[_REG_R13]) }
-func (c *sigctxt) r14() uint64 { return uint64(c.regs().gregs[_REG_R14]) }
-func (c *sigctxt) r15() uint64 { return uint64(c.regs().gregs[_REG_R15]) }
-func (c *sigctxt) rip() uint64 { return uint64(c.regs().gregs[_REG_RIP]) }
+
+func (c *sigctxt) rax() uint64 { return uint64(c.regs().gregs[_REG_RAX]) }
+func (c *sigctxt) rbx() uint64 { return uint64(c.regs().gregs[_REG_RBX]) }
+func (c *sigctxt) rcx() uint64 { return uint64(c.regs().gregs[_REG_RCX]) }
+func (c *sigctxt) rdx() uint64 { return uint64(c.regs().gregs[_REG_RDX]) }
+func (c *sigctxt) rdi() uint64 { return uint64(c.regs().gregs[_REG_RDI]) }
+func (c *sigctxt) rsi() uint64 { return uint64(c.regs().gregs[_REG_RSI]) }
+func (c *sigctxt) rbp() uint64 { return uint64(c.regs().gregs[_REG_RBP]) }
+func (c *sigctxt) rsp() uint64 { return uint64(c.regs().gregs[_REG_RSP]) }
+func (c *sigctxt) r8() uint64 { return uint64(c.regs().gregs[_REG_R8]) }
+func (c *sigctxt) r9() uint64 { return uint64(c.regs().gregs[_REG_R9]) }
+func (c *sigctxt) r10() uint64 { return uint64(c.regs().gregs[_REG_R10]) }
+func (c *sigctxt) r11() uint64 { return uint64(c.regs().gregs[_REG_R11]) }
+func (c *sigctxt) r12() uint64 { return uint64(c.regs().gregs[_REG_R12]) }
+func (c *sigctxt) r13() uint64 { return uint64(c.regs().gregs[_REG_R13]) }
+func (c *sigctxt) r14() uint64 { return uint64(c.regs().gregs[_REG_R14]) }
+func (c *sigctxt) r15() uint64 { return uint64(c.regs().gregs[_REG_R15]) }
+
+//go:nosplit
+//go:nowritebarrierrec
+func (c *sigctxt) rip() uint64 { return uint64(c.regs().gregs[_REG_RIP]) }
+
func (c *sigctxt) rflags() uint64 { return uint64(c.regs().gregs[_REG_RFLAGS]) }
func (c *sigctxt) cs() uint64 { return uint64(c.regs().gregs[_REG_CS]) }
func (c *sigctxt) fs() uint64 { return uint64(c.regs().gregs[_REG_FS]) }
diff --git a/src/runtime/signal_unix.go b/src/runtime/signal_unix.go
index f59c9b9..78381e5 100644
--- a/src/runtime/signal_unix.go
+++ b/src/runtime/signal_unix.go
@@ -6,7 +6,10 @@
package runtime
-import _ "unsafe" // for go:linkname
+import (
+ "runtime/internal/sys"
+ "unsafe"
+)
//go:linkname os_sigpipe os.sigpipe
func os_sigpipe() {
@@ -19,3 +22,638 @@ func signame(sig uint32) string {
}
return sigtable[sig].name
}
+
+const (
+ _SIG_DFL uintptr = 0
+ _SIG_IGN uintptr = 1
+)
+
+// Stores the signal handlers registered before Go installed its own.
+// These signal handlers will be invoked in cases where Go doesn't want to
+// handle a particular signal (e.g., signal occurred on a non-Go thread).
+// See sigfwdgo() for more information on when the signals are forwarded.
+//
+// Signal forwarding is currently available only on Darwin and Linux.
+var fwdSig [_NSIG]uintptr
+
+// channels for synchronizing signal mask updates with the signal mask
+// thread
+var (
+ disableSigChan chan uint32
+ enableSigChan chan uint32
+ maskUpdatedChan chan struct{}
+)
+
+func init() {
+ // _NSIG is the number of signals on this operating system.
+ // sigtable should describe what to do for all the possible signals.
+ if len(sigtable) != _NSIG {
+ print("runtime: len(sigtable)=", len(sigtable), " _NSIG=", _NSIG, "\n")
+ throw("bad sigtable len")
+ }
+}
+
+var signalsOK bool
+
+// Initialize signals.
+// Called by libpreinit so runtime may not be initialized.
+//go:nosplit
+//go:nowritebarrierrec
+func initsig(preinit bool) {
+ if !preinit {
+ // It's now OK for signal handlers to run.
+ signalsOK = true
+ }
+
+ // For c-archive/c-shared this is called by libpreinit with
+ // preinit == true.
+ if (isarchive || islibrary) && !preinit {
+ return
+ }
+
+ for i := uint32(0); i < _NSIG; i++ {
+ t := &sigtable[i]
+ if t.flags == 0 || t.flags&_SigDefault != 0 {
+ continue
+ }
+ fwdSig[i] = getsig(i)
+
+ if !sigInstallGoHandler(i) {
+ // Even if we are not installing a signal handler,
+ // set SA_ONSTACK if necessary.
+ if fwdSig[i] != _SIG_DFL && fwdSig[i] != _SIG_IGN {
+ setsigstack(i)
+ }
+ continue
+ }
+
+ t.flags |= _SigHandling
+ setsig(i, funcPC(sighandler))
+ }
+}
+
+//go:nosplit
+//go:nowritebarrierrec
+func sigInstallGoHandler(sig uint32) bool {
+ // For some signals, we respect an inherited SIG_IGN handler
+ // rather than insist on installing our own default handler.
+ // Even these signals can be fetched using the os/signal package.
+ switch sig {
+ case _SIGHUP, _SIGINT:
+ if fwdSig[sig] == _SIG_IGN {
+ return false
+ }
+ }
+
+ t := &sigtable[sig]
+ if t.flags&_SigSetStack != 0 {
+ return false
+ }
+
+ // When built using c-archive or c-shared, only install signal
+ // handlers for synchronous signals and SIGPIPE.
+ if (isarchive || islibrary) && t.flags&_SigPanic == 0 && sig != _SIGPIPE {
+ return false
+ }
+
+ return true
+}
+
+func sigenable(sig uint32) {
+ if sig >= uint32(len(sigtable)) {
+ return
+ }
+
+ t := &sigtable[sig]
+ if t.flags&_SigNotify != 0 {
+ ensureSigM()
+ enableSigChan <- sig
+ <-maskUpdatedChan
+ if t.flags&_SigHandling == 0 {
+ t.flags |= _SigHandling
+ fwdSig[sig] = getsig(sig)
+ setsig(sig, funcPC(sighandler))
+ }
+ }
+}
+
+func sigdisable(sig uint32) {
+ if sig >= uint32(len(sigtable)) {
+ return
+ }
+
+ t := &sigtable[sig]
+ if t.flags&_SigNotify != 0 {
+ ensureSigM()
+ disableSigChan <- sig
+ <-maskUpdatedChan
+
+ // If initsig does not install a signal handler for a
+ // 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])
+ }
+ }
+}
+
+func sigignore(sig uint32) {
+ if sig >= uint32(len(sigtable)) {
+ return
+ }
+
+ t := &sigtable[sig]
+ if t.flags&_SigNotify != 0 {
+ t.flags &^= _SigHandling
+ setsig(sig, _SIG_IGN)
+ }
+}
+
+func resetcpuprofiler(hz int32) {
+ var it itimerval
+ if hz == 0 {
+ setitimer(_ITIMER_PROF, &it, nil)
+ } else {
+ it.it_interval.tv_sec = 0
+ it.it_interval.set_usec(1000000 / hz)
+ it.it_value = it.it_interval
+ setitimer(_ITIMER_PROF, &it, nil)
+ }
+ _g_ := getg()
+ _g_.m.profilehz = hz
+}
+
+func sigpipe() {
+ if sigsend(_SIGPIPE) {
+ return
+ }
+ dieFromSignal(_SIGPIPE)
+}
+
+// sigtrampgo is called from the signal handler function, sigtramp,
+// written in assembly code.
+// This is called by the signal handler, and the world may be stopped.
+//go:nosplit
+//go:nowritebarrierrec
+func sigtrampgo(sig uint32, info *siginfo, ctx unsafe.Pointer) {
+ if sigfwdgo(sig, info, ctx) {
+ return
+ }
+ g := getg()
+ if g == nil {
+ c := &sigctxt{info, ctx}
+ if sig == _SIGPROF {
+ sigprofNonGoPC(c.sigpc())
+ return
+ }
+ badsignal(uintptr(sig), c)
+ return
+ }
+
+ // If some non-Go code called sigaltstack, adjust.
+ sp := uintptr(unsafe.Pointer(&sig))
+ if sp < g.m.gsignal.stack.lo || sp >= g.m.gsignal.stack.hi {
+ var st stackt
+ sigaltstack(nil, &st)
+ if st.ss_flags&_SS_DISABLE != 0 {
+ setg(nil)
+ needm(0)
+ noSignalStack(sig)
+ dropm()
+ }
+ stsp := uintptr(unsafe.Pointer(st.ss_sp))
+ if sp < stsp || sp >= stsp+st.ss_size {
+ setg(nil)
+ needm(0)
+ sigNotOnStack(sig)
+ dropm()
+ }
+ setGsignalStack(&st)
+ g.m.gsignal.stktopsp = getcallersp(unsafe.Pointer(&sig))
+ }
+
+ setg(g.m.gsignal)
+ c := &sigctxt{info, ctx}
+ c.fixsigcode(sig)
+ sighandler(sig, info, ctx, g)
+ setg(g)
+}
+
+// sigpanic turns a synchronous signal into a run-time panic.
+// If the signal handler sees a synchronous panic, it arranges the
+// stack to look like the function where the signal occurred called
+// sigpanic, sets the signal's PC value to sigpanic, and returns from
+// the signal handler. The effect is that the program will act as
+// though the function that got the signal simply called sigpanic
+// instead.
+func sigpanic() {
+ g := getg()
+ if !canpanic(g) {
+ throw("unexpected signal during runtime execution")
+ }
+
+ switch g.sig {
+ case _SIGBUS:
+ if g.sigcode0 == _BUS_ADRERR && g.sigcode1 < 0x1000 {
+ panicmem()
+ }
+ // Support runtime/debug.SetPanicOnFault.
+ if g.paniconfault {
+ panicmem()
+ }
+ print("unexpected fault address ", hex(g.sigcode1), "\n")
+ throw("fault")
+ case _SIGSEGV:
+ if (g.sigcode0 == 0 || g.sigcode0 == _SEGV_MAPERR || g.sigcode0 == _SEGV_ACCERR) && g.sigcode1 < 0x1000 {
+ panicmem()
+ }
+ // Support runtime/debug.SetPanicOnFault.
+ if g.paniconfault {
+ panicmem()
+ }
+ print("unexpected fault address ", hex(g.sigcode1), "\n")
+ throw("fault")
+ case _SIGFPE:
+ switch g.sigcode0 {
+ case _FPE_INTDIV:
+ panicdivide()
+ case _FPE_INTOVF:
+ panicoverflow()
+ }
+ panicfloat()
+ }
+
+ if g.sig >= uint32(len(sigtable)) {
+ // can't happen: we looked up g.sig in sigtable to decide to call sigpanic
+ throw("unexpected signal value")
+ }
+ panic(errorString(sigtable[g.sig].name))
+}
+
+// dieFromSignal kills the program with a signal.
+// This provides the expected exit status for the shell.
+// This is only called with fatal signals expected to kill the process.
+//go:nosplit
+//go:nowritebarrierrec
+func dieFromSignal(sig uint32) {
+ setsig(sig, _SIG_DFL)
+ unblocksig(sig)
+ raise(sig)
+
+ // That should have killed us. On some systems, though, raise
+ // sends the signal to the whole process rather than to just
+ // the current thread, which means that the signal may not yet
+ // have been delivered. Give other threads a chance to run and
+ // pick up the signal.
+ osyield()
+ osyield()
+ osyield()
+
+ // If we are still somehow running, just exit with the wrong status.
+ exit(2)
+}
+
+// raisebadsignal is called when a signal is received on a non-Go
+// thread, and the Go program does not want to handle it (that is, the
+// program has not called os/signal.Notify for the signal).
+func raisebadsignal(sig uint32, c *sigctxt) {
+ if sig == _SIGPROF {
+ // Ignore profiling signals that arrive on non-Go threads.
+ return
+ }
+
+ var handler uintptr
+ if sig >= _NSIG {
+ handler = _SIG_DFL
+ } else {
+ handler = fwdSig[sig]
+ }
+
+ // Reset the signal handler and raise the signal.
+ // We are currently running inside a signal handler, so the
+ // signal is blocked. We need to unblock it before raising the
+ // signal, or the signal we raise will be ignored until we return
+ // from the signal handler. We know that the signal was unblocked
+ // before entering the handler, or else we would not have received
+ // it. That means that we don't have to worry about blocking it
+ // again.
+ unblocksig(sig)
+ setsig(sig, handler)
+
+ // If we're linked into a non-Go program we want to try to
+ // avoid modifying the original context in which the signal
+ // was raised. If the handler is the default, we know it
+ // is non-recoverable, so we don't have to worry about
+ // re-installing sighandler. At this point we can just
+ // return and the signal will be re-raised and caught by
+ // the default handler with the correct context.
+ if (isarchive || islibrary) && handler == _SIG_DFL && c.sigcode() != _SI_USER {
+ return
+ }
+
+ raise(sig)
+
+ // Give the signal a chance to be delivered.
+ // In almost all real cases the program is about to crash,
+ // so sleeping here is not a waste of time.
+ usleep(1000)
+
+ // If the signal didn't cause the program to exit, restore the
+ // Go signal handler and carry on.
+ //
+ // We may receive another instance of the signal before we
+ // restore the Go handler, but that is not so bad: we know
+ // that the Go program has been ignoring the signal.
+ setsig(sig, funcPC(sighandler))
+}
+
+func crash() {
+ if GOOS == "darwin" {
+ // OS X core dumps are linear dumps of the mapped memory,
+ // from the first virtual byte to the last, with zeros in the gaps.
+ // Because of the way we arrange the address space on 64-bit systems,
+ // this means the OS X core file will be >128 GB and even on a zippy
+ // workstation can take OS X well over an hour to write (uninterruptible).
+ // Save users from making that mistake.
+ if sys.PtrSize == 8 {
+ return
+ }
+ }
+
+ dieFromSignal(_SIGABRT)
+}
+
+// ensureSigM starts one global, sleeping thread to make sure at least one thread
+// is available to catch signals enabled for os/signal.
+func ensureSigM() {
+ if maskUpdatedChan != nil {
+ return
+ }
+ maskUpdatedChan = make(chan struct{})
+ disableSigChan = make(chan uint32)
+ enableSigChan = make(chan uint32)
+ go func() {
+ // Signal masks are per-thread, so make sure this goroutine stays on one
+ // thread.
+ LockOSThread()
+ defer UnlockOSThread()
+ // The sigBlocked mask contains the signals not active for os/signal,
+ // initially all signals except the essential. When signal.Notify()/Stop is called,
+ // sigenable/sigdisable in turn notify this thread to update its signal
+ // mask accordingly.
+ sigBlocked := sigset_all
+ for i := range sigtable {
+ if sigtable[i].flags&_SigUnblock != 0 {
+ sigdelset(&sigBlocked, i)
+ }
+ }
+ sigprocmask(_SIG_SETMASK, &sigBlocked, nil)
+ for {
+ select {
+ case sig := <-enableSigChan:
+ if sig > 0 {
+ sigdelset(&sigBlocked, int(sig))
+ }
+ case sig := <-disableSigChan:
+ if sig > 0 {
+ sigaddset(&sigBlocked, int(sig))
+ }
+ }
+ sigprocmask(_SIG_SETMASK, &sigBlocked, nil)
+ maskUpdatedChan <- struct{}{}
+ }
+ }()
+}
+
+// This is called when we receive a signal when there is no signal stack.
+// This can only happen if non-Go code calls sigaltstack to disable the
+// signal stack.
+func noSignalStack(sig uint32) {
+ println("signal", sig, "received on thread with no signal stack")
+ throw("non-Go code disabled sigaltstack")
+}
+
+// This is called if we receive a signal when there is a signal stack
+// but we are not on it. This can only happen if non-Go code called
+// sigaction without setting the SS_ONSTACK flag.
+func sigNotOnStack(sig uint32) {
+ println("signal", sig, "received but handler not on signal stack")
+ throw("non-Go code set up signal handler without SA_ONSTACK flag")
+}
+
+// This runs on a foreign stack, without an m or a g. No stack split.
+//go:nosplit
+//go:norace
+//go:nowritebarrierrec
+func badsignal(sig uintptr, c *sigctxt) {
+ needm(0)
+ if !sigsend(uint32(sig)) {
+ // A foreign thread received the signal sig, and the
+ // Go code does not want to handle it.
+ raisebadsignal(uint32(sig), c)
+ }
+ dropm()
+}
+
+//go:noescape
+func sigfwd(fn uintptr, sig uint32, info *siginfo, ctx unsafe.Pointer)
+
+// Determines if the signal should be handled by Go and if not, forwards the
+// signal to the handler that was installed before Go's. Returns whether the
+// signal was forwarded.
+// This is called by the signal handler, and the world may be stopped.
+//go:nosplit
+//go:nowritebarrierrec
+func sigfwdgo(sig uint32, info *siginfo, ctx unsafe.Pointer) bool {
+ if sig >= uint32(len(sigtable)) {
+ return false
+ }
+ fwdFn := fwdSig[sig]
+
+ if !signalsOK {
+ // The only way we can get here is if we are in a
+ // library or archive, we installed a signal handler
+ // at program startup, but the Go runtime has not yet
+ // been initialized.
+ if fwdFn == _SIG_DFL {
+ dieFromSignal(sig)
+ } else {
+ sigfwd(fwdFn, sig, info, ctx)
+ }
+ 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 {
+ sigfwd(fwdFn, sig, info, ctx)
+ return true
+ }
+
+ c := &sigctxt{info, ctx}
+ // Only forward signals from the kernel.
+ // On Linux and Darwin there is no way to distinguish a SIGPIPE raised by a write
+ // to a closed socket or pipe from a SIGPIPE raised by kill or pthread_kill
+ // so we'll treat every SIGPIPE as kernel-generated.
+ userSig := c.sigcode() == _SI_USER &&
+ (sig != _SIGPIPE || GOOS != "linux" && GOOS != "android" && GOOS != "darwin")
+ // Only forward synchronous signals and SIGPIPE.
+ if userSig || 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).
+ g := getg()
+ if g != nil && g.m != nil && g.m.curg != nil && g.m.curg.syscallsp == 0 {
+ return false
+ }
+ // Signal not handled by Go, forward it.
+ if fwdFn != _SIG_IGN {
+ sigfwd(fwdFn, sig, info, ctx)
+ }
+ return true
+}
+
+// msigsave saves the current thread's signal mask into mp.sigmask.
+// This is used to preserve the non-Go signal mask when a non-Go
+// thread calls a Go function.
+// This is nosplit and nowritebarrierrec because it is called by needm
+// which may be called on a non-Go thread with no g available.
+//go:nosplit
+//go:nowritebarrierrec
+func msigsave(mp *m) {
+ sigprocmask(_SIG_SETMASK, nil, &mp.sigmask)
+}
+
+// msigrestore sets the current thread's signal mask to sigmask.
+// This is used to restore the non-Go signal mask when a non-Go thread
+// calls a Go function.
+// This is nosplit and nowritebarrierrec because it is called by dropm
+// after g has been cleared.
+//go:nosplit
+//go:nowritebarrierrec
+func msigrestore(sigmask sigset) {
+ sigprocmask(_SIG_SETMASK, &sigmask, nil)
+}
+
+// sigblock blocks all signals in the current thread's signal mask.
+// This is used to block signals while setting up and tearing down g
+// when a non-Go thread calls a Go function.
+// The OS-specific code is expected to define sigset_all.
+// This is nosplit and nowritebarrierrec because it is called by needm
+// which may be called on a non-Go thread with no g available.
+//go:nosplit
+//go:nowritebarrierrec
+func sigblock() {
+ sigprocmask(_SIG_SETMASK, &sigset_all, nil)
+}
+
+// unblocksig removes sig from the current thread's signal mask.
+// This is nosplit and nowritebarrierrec because it is called from
+// dieFromSignal, which can be called by sigfwdgo while running in the
+// signal handler, on the signal stack, with no g available.
+//go:nosplit
+//go:nowritebarrierrec
+func unblocksig(sig uint32) {
+ var set sigset
+ sigaddset(&set, int(sig))
+ sigprocmask(_SIG_UNBLOCK, &set, nil)
+}
+
+// minitSignals is called when initializing a new m to set the
+// thread's alternate signal stack and signal mask.
+func minitSignals() {
+ minitSignalStack()
+ minitSignalMask()
+}
+
+// minitSignalStack is called when initializing a new m to set the
+// alternate signal stack. If the alternate signal stack is not set
+// for the thread (the normal case) then set the alternate signal
+// stack to the gsignal stack. If the alternate signal stack is set
+// for the thread (the case when a non-Go thread sets the alternate
+// signal stack and then calls a Go function) then set the gsignal
+// stack to the alternate signal stack. Record which choice was made
+// in newSigstack, so that it can be undone in unminit.
+func minitSignalStack() {
+ _g_ := getg()
+ var st stackt
+ sigaltstack(nil, &st)
+ if st.ss_flags&_SS_DISABLE != 0 {
+ signalstack(&_g_.m.gsignal.stack)
+ _g_.m.newSigstack = true
+ } else {
+ setGsignalStack(&st)
+ _g_.m.newSigstack = false
+ }
+}
+
+// minitSignalMask is called when initializing a new m to set the
+// thread's signal mask. When this is called all signals have been
+// blocked for the thread. This starts with m.sigmask, which was set
+// either from initSigmask for a newly created thread or by calling
+// msigsave if this is a non-Go thread calling a Go function. It
+// removes all essential signals from the mask, thus causing those
+// signals to not be blocked. Then it sets the thread's signal mask.
+// After this is called the thread can receive signals.
+func minitSignalMask() {
+ nmask := getg().m.sigmask
+ for i := range sigtable {
+ if sigtable[i].flags&_SigUnblock != 0 {
+ sigdelset(&nmask, i)
+ }
+ }
+ sigprocmask(_SIG_SETMASK, &nmask, nil)
+}
+
+// unminitSignals is called from dropm, via unminit, to undo the
+// effect of calling minit on a non-Go thread.
+//go:nosplit
+func unminitSignals() {
+ if getg().m.newSigstack {
+ st := stackt{ss_flags: _SS_DISABLE}
+ sigaltstack(&st, nil)
+ }
+}
+
+// setGsignalStack sets the gsignal stack of the current m to an
+// alternate signal stack returned from the sigaltstack system call.
+// This is used when handling a signal if non-Go code has set the
+// alternate signal stack.
+//go:nosplit
+//go:nowritebarrierrec
+func setGsignalStack(st *stackt) {
+ g := getg()
+ stsp := uintptr(unsafe.Pointer(st.ss_sp))
+ g.m.gsignal.stack.lo = stsp
+ g.m.gsignal.stack.hi = stsp + st.ss_size
+ g.m.gsignal.stackguard0 = stsp + _StackGuard
+ g.m.gsignal.stackguard1 = stsp + _StackGuard
+ g.m.gsignal.stackAlloc = st.ss_size
+}
+
+// signalstack sets the current thread's alternate signal stack to s.
+//go:nosplit
+func signalstack(s *stack) {
+ st := stackt{ss_size: s.hi - s.lo}
+ setSignalstackSP(&st, s.lo)
+ sigaltstack(&st, nil)
+}
+
+// setsigsegv is used on darwin/arm{,64} to fake a segmentation fault.
+//go:nosplit
+func setsigsegv(pc uintptr) {
+ g := getg()
+ g.sig = _SIGSEGV
+ g.sigpc = pc
+ g.sigcode0 = _SEGV_MAPERR
+ g.sigcode1 = 0 // TODO: emulate si_addr
+}
diff --git a/src/runtime/signal_windows.go b/src/runtime/signal_windows.go
index 298dcc9..73bd5b5 100644
--- a/src/runtime/signal_windows.go
+++ b/src/runtime/signal_windows.go
@@ -205,7 +205,7 @@ func sigignore(sig uint32) {
func badsignal2()
-func raisebadsignal(sig int32) {
+func raisebadsignal(sig uint32) {
badsignal2()
}
diff --git a/src/runtime/sigpanic_unix.go b/src/runtime/sigpanic_unix.go
deleted file mode 100644
index 4cd8615..0000000
--- a/src/runtime/sigpanic_unix.go
+++ /dev/null
@@ -1,53 +0,0 @@
-// Copyright 2014 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build darwin dragonfly freebsd linux netbsd openbsd solaris
-
-package runtime
-
-func sigpanic() {
- g := getg()
- if !canpanic(g) {
- throw("unexpected signal during runtime execution")
- }
-
- switch g.sig {
- case _SIGBUS:
- if g.sigcode0 == _BUS_ADRERR && g.sigcode1 < 0x1000 || g.paniconfault {
- panicmem()
- }
- print("unexpected fault address ", hex(g.sigcode1), "\n")
- throw("fault")
- case _SIGSEGV:
- if (g.sigcode0 == 0 || g.sigcode0 == _SEGV_MAPERR || g.sigcode0 == _SEGV_ACCERR) && g.sigcode1 < 0x1000 || g.paniconfault {
- panicmem()
- }
- print("unexpected fault address ", hex(g.sigcode1), "\n")
- throw("fault")
- case _SIGFPE:
- switch g.sigcode0 {
- case _FPE_INTDIV:
- panicdivide()
- case _FPE_INTOVF:
- panicoverflow()
- }
- panicfloat()
- }
-
- if g.sig >= uint32(len(sigtable)) {
- // can't happen: we looked up g.sig in sigtable to decide to call sigpanic
- throw("unexpected signal value")
- }
- panic(errorString(sigtable[g.sig].name))
-}
-
-// setsigsegv is used on darwin/arm{,64} to fake a segmentation fault.
-//go:nosplit
-func setsigsegv(pc uintptr) {
- g := getg()
- g.sig = _SIGSEGV
- g.sigpc = pc
- g.sigcode0 = _SEGV_MAPERR
- g.sigcode1 = 0 // TODO: emulate si_addr
-}
diff --git a/src/runtime/sigtab_linux_generic.go b/src/runtime/sigtab_linux_generic.go
index ea36bf3..874148e 100644
--- a/src/runtime/sigtab_linux_generic.go
+++ b/src/runtime/sigtab_linux_generic.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 !mips
+// +build !mipsle
// +build !mips64
// +build !mips64le
// +build linux
diff --git a/src/runtime/sigtab_linux_mips64x.go b/src/runtime/sigtab_linux_mips64x.go
deleted file mode 100644
index 201fe3d..0000000
--- a/src/runtime/sigtab_linux_mips64x.go
+++ /dev/null
@@ -1,81 +0,0 @@
-// Copyright 2015 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build mips64 mips64le
-// +build linux
-
-package runtime
-
-type sigTabT struct {
- flags int32
- name string
-}
-
-var sigtable = [...]sigTabT{
- /* 0 */ {0, "SIGNONE: no trap"},
- /* 1 */ {_SigNotify + _SigKill, "SIGHUP: terminal line hangup"},
- /* 2 */ {_SigNotify + _SigKill, "SIGINT: interrupt"},
- /* 3 */ {_SigNotify + _SigThrow, "SIGQUIT: quit"},
- /* 4 */ {_SigThrow + _SigUnblock, "SIGILL: illegal instruction"},
- /* 5 */ {_SigThrow + _SigUnblock, "SIGTRAP: trace trap"},
- /* 6 */ {_SigNotify + _SigThrow, "SIGABRT: abort"},
- /* 7 */ {_SigThrow, "SIGEMT"},
- /* 8 */ {_SigPanic + _SigUnblock, "SIGFPE: floating-point exception"},
- /* 9 */ {0, "SIGKILL: kill"},
- /* 10 */ {_SigPanic + _SigUnblock, "SIGBUS: bus error"},
- /* 11 */ {_SigPanic + _SigUnblock, "SIGSEGV: segmentation violation"},
- /* 12 */ {_SigThrow, "SIGSYS: bad system call"},
- /* 13 */ {_SigNotify, "SIGPIPE: write to broken pipe"},
- /* 14 */ {_SigNotify, "SIGALRM: alarm clock"},
- /* 15 */ {_SigNotify + _SigKill, "SIGTERM: termination"},
- /* 16 */ {_SigNotify, "SIGUSR1: user-defined signal 1"},
- /* 17 */ {_SigNotify, "SIGUSR2: user-defined signal 2"},
- /* 18 */ {_SigNotify + _SigUnblock, "SIGCHLD: child status has changed"},
- /* 19 */ {_SigNotify, "SIGPWR: power failure restart"},
- /* 20 */ {_SigNotify, "SIGWINCH: window size change"},
- /* 21 */ {_SigNotify, "SIGURG: urgent condition on socket"},
- /* 22 */ {_SigNotify, "SIGIO: i/o now possible"},
- /* 23 */ {0, "SIGSTOP: stop, unblockable"},
- /* 24 */ {_SigNotify + _SigDefault, "SIGTSTP: keyboard stop"},
- /* 25 */ {_SigNotify + _SigDefault, "SIGCONT: continue"},
- /* 26 */ {_SigNotify + _SigDefault, "SIGTTIN: background read from tty"},
- /* 27 */ {_SigNotify + _SigDefault, "SIGTTOU: background write to tty"},
- /* 28 */ {_SigNotify, "SIGVTALRM: virtual alarm clock"},
- /* 29 */ {_SigNotify + _SigUnblock, "SIGPROF: profiling alarm clock"},
- /* 30 */ {_SigNotify, "SIGXCPU: cpu limit exceeded"},
- /* 31 */ {_SigNotify, "SIGXFSZ: file size limit exceeded"},
- /* 32 */ {_SigSetStack + _SigUnblock, "signal 32"}, /* SIGCANCEL; see issue 6997 */
- /* 33 */ {_SigSetStack + _SigUnblock, "signal 33"}, /* SIGSETXID; see issues 3871, 9400, 12498 */
- /* 34 */ {_SigNotify, "signal 34"},
- /* 35 */ {_SigNotify, "signal 35"},
- /* 36 */ {_SigNotify, "signal 36"},
- /* 37 */ {_SigNotify, "signal 37"},
- /* 38 */ {_SigNotify, "signal 38"},
- /* 39 */ {_SigNotify, "signal 39"},
- /* 40 */ {_SigNotify, "signal 40"},
- /* 41 */ {_SigNotify, "signal 41"},
- /* 42 */ {_SigNotify, "signal 42"},
- /* 43 */ {_SigNotify, "signal 43"},
- /* 44 */ {_SigNotify, "signal 44"},
- /* 45 */ {_SigNotify, "signal 45"},
- /* 46 */ {_SigNotify, "signal 46"},
- /* 47 */ {_SigNotify, "signal 47"},
- /* 48 */ {_SigNotify, "signal 48"},
- /* 49 */ {_SigNotify, "signal 49"},
- /* 50 */ {_SigNotify, "signal 50"},
- /* 51 */ {_SigNotify, "signal 51"},
- /* 52 */ {_SigNotify, "signal 52"},
- /* 53 */ {_SigNotify, "signal 53"},
- /* 54 */ {_SigNotify, "signal 54"},
- /* 55 */ {_SigNotify, "signal 55"},
- /* 56 */ {_SigNotify, "signal 56"},
- /* 57 */ {_SigNotify, "signal 57"},
- /* 58 */ {_SigNotify, "signal 58"},
- /* 59 */ {_SigNotify, "signal 59"},
- /* 60 */ {_SigNotify, "signal 60"},
- /* 61 */ {_SigNotify, "signal 61"},
- /* 62 */ {_SigNotify, "signal 62"},
- /* 63 */ {_SigNotify, "signal 63"},
- /* 64 */ {_SigNotify, "signal 64"},
-}
diff --git a/src/runtime/sigtab_linux_mipsx.go b/src/runtime/sigtab_linux_mipsx.go
new file mode 100644
index 0000000..8d9fb06
--- /dev/null
+++ b/src/runtime/sigtab_linux_mipsx.go
@@ -0,0 +1,145 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build mips mipsle mips64 mips64le
+// +build linux
+
+package runtime
+
+type sigTabT struct {
+ flags int32
+ name string
+}
+
+var sigtable = [...]sigTabT{
+ /* 0 */ {0, "SIGNONE: no trap"},
+ /* 1 */ {_SigNotify + _SigKill, "SIGHUP: terminal line hangup"},
+ /* 2 */ {_SigNotify + _SigKill, "SIGINT: interrupt"},
+ /* 3 */ {_SigNotify + _SigThrow, "SIGQUIT: quit"},
+ /* 4 */ {_SigThrow + _SigUnblock, "SIGILL: illegal instruction"},
+ /* 5 */ {_SigThrow + _SigUnblock, "SIGTRAP: trace trap"},
+ /* 6 */ {_SigNotify + _SigThrow, "SIGABRT: abort"},
+ /* 7 */ {_SigThrow, "SIGEMT"},
+ /* 8 */ {_SigPanic + _SigUnblock, "SIGFPE: floating-point exception"},
+ /* 9 */ {0, "SIGKILL: kill"},
+ /* 10 */ {_SigPanic + _SigUnblock, "SIGBUS: bus error"},
+ /* 11 */ {_SigPanic + _SigUnblock, "SIGSEGV: segmentation violation"},
+ /* 12 */ {_SigThrow, "SIGSYS: bad system call"},
+ /* 13 */ {_SigNotify, "SIGPIPE: write to broken pipe"},
+ /* 14 */ {_SigNotify, "SIGALRM: alarm clock"},
+ /* 15 */ {_SigNotify + _SigKill, "SIGTERM: termination"},
+ /* 16 */ {_SigNotify, "SIGUSR1: user-defined signal 1"},
+ /* 17 */ {_SigNotify, "SIGUSR2: user-defined signal 2"},
+ /* 18 */ {_SigNotify + _SigUnblock, "SIGCHLD: child status has changed"},
+ /* 19 */ {_SigNotify, "SIGPWR: power failure restart"},
+ /* 20 */ {_SigNotify, "SIGWINCH: window size change"},
+ /* 21 */ {_SigNotify, "SIGURG: urgent condition on socket"},
+ /* 22 */ {_SigNotify, "SIGIO: i/o now possible"},
+ /* 23 */ {0, "SIGSTOP: stop, unblockable"},
+ /* 24 */ {_SigNotify + _SigDefault, "SIGTSTP: keyboard stop"},
+ /* 25 */ {_SigNotify + _SigDefault, "SIGCONT: continue"},
+ /* 26 */ {_SigNotify + _SigDefault, "SIGTTIN: background read from tty"},
+ /* 27 */ {_SigNotify + _SigDefault, "SIGTTOU: background write to tty"},
+ /* 28 */ {_SigNotify, "SIGVTALRM: virtual alarm clock"},
+ /* 29 */ {_SigNotify + _SigUnblock, "SIGPROF: profiling alarm clock"},
+ /* 30 */ {_SigNotify, "SIGXCPU: cpu limit exceeded"},
+ /* 31 */ {_SigNotify, "SIGXFSZ: file size limit exceeded"},
+ /* 32 */ {_SigSetStack + _SigUnblock, "signal 32"}, /* SIGCANCEL; see issue 6997 */
+ /* 33 */ {_SigSetStack + _SigUnblock, "signal 33"}, /* SIGSETXID; see issues 3871, 9400, 12498 */
+ /* 34 */ {_SigNotify, "signal 34"},
+ /* 35 */ {_SigNotify, "signal 35"},
+ /* 36 */ {_SigNotify, "signal 36"},
+ /* 37 */ {_SigNotify, "signal 37"},
+ /* 38 */ {_SigNotify, "signal 38"},
+ /* 39 */ {_SigNotify, "signal 39"},
+ /* 40 */ {_SigNotify, "signal 40"},
+ /* 41 */ {_SigNotify, "signal 41"},
+ /* 42 */ {_SigNotify, "signal 42"},
+ /* 43 */ {_SigNotify, "signal 43"},
+ /* 44 */ {_SigNotify, "signal 44"},
+ /* 45 */ {_SigNotify, "signal 45"},
+ /* 46 */ {_SigNotify, "signal 46"},
+ /* 47 */ {_SigNotify, "signal 47"},
+ /* 48 */ {_SigNotify, "signal 48"},
+ /* 49 */ {_SigNotify, "signal 49"},
+ /* 50 */ {_SigNotify, "signal 50"},
+ /* 51 */ {_SigNotify, "signal 51"},
+ /* 52 */ {_SigNotify, "signal 52"},
+ /* 53 */ {_SigNotify, "signal 53"},
+ /* 54 */ {_SigNotify, "signal 54"},
+ /* 55 */ {_SigNotify, "signal 55"},
+ /* 56 */ {_SigNotify, "signal 56"},
+ /* 57 */ {_SigNotify, "signal 57"},
+ /* 58 */ {_SigNotify, "signal 58"},
+ /* 59 */ {_SigNotify, "signal 59"},
+ /* 60 */ {_SigNotify, "signal 60"},
+ /* 61 */ {_SigNotify, "signal 61"},
+ /* 62 */ {_SigNotify, "signal 62"},
+ /* 63 */ {_SigNotify, "signal 63"},
+ /* 64 */ {_SigNotify, "signal 64"},
+ /* 65 */ {_SigNotify, "signal 65"},
+ /* 66 */ {_SigNotify, "signal 66"},
+ /* 67 */ {_SigNotify, "signal 67"},
+ /* 68 */ {_SigNotify, "signal 68"},
+ /* 69 */ {_SigNotify, "signal 69"},
+ /* 70 */ {_SigNotify, "signal 70"},
+ /* 71 */ {_SigNotify, "signal 71"},
+ /* 72 */ {_SigNotify, "signal 72"},
+ /* 73 */ {_SigNotify, "signal 73"},
+ /* 74 */ {_SigNotify, "signal 74"},
+ /* 75 */ {_SigNotify, "signal 75"},
+ /* 76 */ {_SigNotify, "signal 76"},
+ /* 77 */ {_SigNotify, "signal 77"},
+ /* 78 */ {_SigNotify, "signal 78"},
+ /* 79 */ {_SigNotify, "signal 79"},
+ /* 80 */ {_SigNotify, "signal 80"},
+ /* 81 */ {_SigNotify, "signal 81"},
+ /* 82 */ {_SigNotify, "signal 82"},
+ /* 83 */ {_SigNotify, "signal 83"},
+ /* 84 */ {_SigNotify, "signal 84"},
+ /* 85 */ {_SigNotify, "signal 85"},
+ /* 86 */ {_SigNotify, "signal 86"},
+ /* 87 */ {_SigNotify, "signal 87"},
+ /* 88 */ {_SigNotify, "signal 88"},
+ /* 89 */ {_SigNotify, "signal 89"},
+ /* 90 */ {_SigNotify, "signal 90"},
+ /* 91 */ {_SigNotify, "signal 91"},
+ /* 92 */ {_SigNotify, "signal 92"},
+ /* 93 */ {_SigNotify, "signal 93"},
+ /* 94 */ {_SigNotify, "signal 94"},
+ /* 95 */ {_SigNotify, "signal 95"},
+ /* 96 */ {_SigNotify, "signal 96"},
+ /* 97 */ {_SigNotify, "signal 97"},
+ /* 98 */ {_SigNotify, "signal 98"},
+ /* 99 */ {_SigNotify, "signal 99"},
+ /* 100 */ {_SigNotify, "signal 100"},
+ /* 101 */ {_SigNotify, "signal 101"},
+ /* 102 */ {_SigNotify, "signal 102"},
+ /* 103 */ {_SigNotify, "signal 103"},
+ /* 104 */ {_SigNotify, "signal 104"},
+ /* 105 */ {_SigNotify, "signal 105"},
+ /* 106 */ {_SigNotify, "signal 106"},
+ /* 107 */ {_SigNotify, "signal 107"},
+ /* 108 */ {_SigNotify, "signal 108"},
+ /* 109 */ {_SigNotify, "signal 109"},
+ /* 110 */ {_SigNotify, "signal 110"},
+ /* 111 */ {_SigNotify, "signal 111"},
+ /* 112 */ {_SigNotify, "signal 112"},
+ /* 113 */ {_SigNotify, "signal 113"},
+ /* 114 */ {_SigNotify, "signal 114"},
+ /* 115 */ {_SigNotify, "signal 115"},
+ /* 116 */ {_SigNotify, "signal 116"},
+ /* 117 */ {_SigNotify, "signal 117"},
+ /* 118 */ {_SigNotify, "signal 118"},
+ /* 119 */ {_SigNotify, "signal 119"},
+ /* 120 */ {_SigNotify, "signal 120"},
+ /* 121 */ {_SigNotify, "signal 121"},
+ /* 122 */ {_SigNotify, "signal 122"},
+ /* 123 */ {_SigNotify, "signal 123"},
+ /* 124 */ {_SigNotify, "signal 124"},
+ /* 125 */ {_SigNotify, "signal 125"},
+ /* 126 */ {_SigNotify, "signal 126"},
+ /* 127 */ {_SigNotify, "signal 127"},
+ /* 128 */ {_SigNotify, "signal 128"},
+}
diff --git a/src/runtime/sizeclasses.go b/src/runtime/sizeclasses.go
new file mode 100644
index 0000000..ec30d15
--- /dev/null
+++ b/src/runtime/sizeclasses.go
@@ -0,0 +1,27 @@
+// AUTO-GENERATED by mksizeclasses.go; DO NOT EDIT
+//go:generate go run mksizeclasses.go
+
+package runtime
+
+const (
+ _MaxSmallSize = 32768
+ smallSizeDiv = 8
+ smallSizeMax = 1024
+ largeSizeDiv = 128
+ _NumSizeClasses = 67
+ _PageShift = 13
+)
+
+var class_to_size = [_NumSizeClasses]uint16{0, 8, 16, 32, 48, 64, 80, 96, 112, 128, 144, 160, 176, 192, 208, 224, 240, 256, 288, 320, 352, 384, 416, 448, 480, 512, 576, 640, 704, 768, 896, 1024, 1152, 1280, 1408, 1536, 1792, 2048, 2304, 2688, 3072, 3200, 3456, 4096, 4864, 5376, 6144, 6528, 6784, 6912, 8192, 9472, 9728, 10240, 10880, 12288, 13568, 14336, 16384, 18432, 19072, 20480, 21760, 24576, 27264, 28672, 32768}
+var class_to_allocnpages = [_NumSizeClasses]uint8{0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 2, 1, 2, 1, 3, 2, 3, 1, 3, 2, 3, 4, 5, 6, 1, 7, 6, 5, 4, 3, 5, 7, 2, 9, 7, 5, 8, 3, 10, 7, 4}
+
+type divMagic struct {
+ shift uint8
+ shift2 uint8
+ mul uint16
+ baseMask uint16
+}
+
+var class_to_divmagic = [_NumSizeClasses]divMagic{{0, 0, 0, 0}, {3, 0, 1, 65528}, {4, 0, 1, 65520}, {5, 0, 1, 65504}, {4, 9, 171, 0}, {6, 0, 1, 65472}, {4, 10, 205, 0}, {5, 9, 171, 0}, {4, 11, 293, 0}, {7, 0, 1, 65408}, {4, 9, 57, 0}, {5, 10, 205, 0}, {4, 12, 373, 0}, {6, 7, 43, 0}, {4, 13, 631, 0}, {5, 11, 293, 0}, {4, 13, 547, 0}, {8, 0, 1, 65280}, {5, 9, 57, 0}, {6, 9, 103, 0}, {5, 12, 373, 0}, {7, 7, 43, 0}, {5, 10, 79, 0}, {6, 10, 147, 0}, {5, 11, 137, 0}, {9, 0, 1, 65024}, {6, 9, 5 [...]
+var size_to_class8 = [smallSizeMax/smallSizeDiv + 1]uint8{0, 1, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, 18, 18, 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 23, 23, 23, 23, 24, 24, 24, 24, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, [...]
+var size_to_class128 = [(_MaxSmallSize-smallSizeMax)/largeSizeDiv + 1]uint8{31, 32, 33, 34, 35, 36, 36, 37, 37, 38, 38, 39, 39, 39, 40, 40, 40, 41, 42, 42, 43, 43, 43, 43, 43, 44, 44, 44, 44, 44, 44, 45, 45, 45, 45, 46, 46, 46, 46, 46, 46, 47, 47, 47, 48, 48, 49, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 52, 52, 53, 53, 53, 53, 54, 54, 54, 54, 54, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 57, 57, 57, 57, 57, [...]
diff --git a/src/runtime/slice.go b/src/runtime/slice.go
index e15e6c4..0f49df1 100644
--- a/src/runtime/slice.go
+++ b/src/runtime/slice.go
@@ -36,21 +36,18 @@ func maxSliceCap(elemsize uintptr) uintptr {
return _MaxMem / elemsize
}
-// TODO: take uintptrs instead of int64s?
-func makeslice(et *_type, len64, cap64 int64) slice {
+func makeslice(et *_type, len, cap int) slice {
// NOTE: The len > maxElements check here is not strictly necessary,
// but it produces a 'len out of range' error instead of a 'cap out of range' error
// when someone does make([]T, bignumber). 'cap out of range' is true too,
// but since the cap is only being supplied implicitly, saying len is clearer.
// See issue 4085.
maxElements := maxSliceCap(et.size)
- len := int(len64)
- if len64 < 0 || int64(len) != len64 || uintptr(len) > maxElements {
+ if len < 0 || uintptr(len) > maxElements {
panic(errorString("makeslice: len out of range"))
}
- cap := int(cap64)
- if cap < len || int64(cap) != cap64 || uintptr(cap) > maxElements {
+ if cap < len || uintptr(cap) > maxElements {
panic(errorString("makeslice: cap out of range"))
}
@@ -58,6 +55,20 @@ func makeslice(et *_type, len64, cap64 int64) slice {
return slice{p, len, cap}
}
+func makeslice64(et *_type, len64, cap64 int64) slice {
+ len := int(len64)
+ if int64(len) != len64 {
+ panic(errorString("makeslice: len out of range"))
+ }
+
+ cap := int(cap64)
+ if int64(cap) != cap64 {
+ panic(errorString("makeslice: cap out of range"))
+ }
+
+ return makeslice(et, len, cap)
+}
+
// growslice handles slice growth during append.
// It is passed the slice element type, the old slice, and the desired new minimum capacity,
// and it returns a new slice with at least that capacity, with the old data
@@ -100,19 +111,22 @@ func growslice(et *_type, old slice, cap int) slice {
}
}
- var lenmem, capmem uintptr
+ var lenmem, newlenmem, capmem uintptr
const ptrSize = unsafe.Sizeof((*byte)(nil))
switch et.size {
case 1:
lenmem = uintptr(old.len)
+ newlenmem = uintptr(cap)
capmem = roundupsize(uintptr(newcap))
newcap = int(capmem)
case ptrSize:
lenmem = uintptr(old.len) * ptrSize
+ newlenmem = uintptr(cap) * ptrSize
capmem = roundupsize(uintptr(newcap) * ptrSize)
newcap = int(capmem / ptrSize)
default:
lenmem = uintptr(old.len) * et.size
+ newlenmem = uintptr(cap) * et.size
capmem = roundupsize(uintptr(newcap) * et.size)
newcap = int(capmem / et.size)
}
@@ -125,7 +139,9 @@ func growslice(et *_type, old slice, cap int) slice {
if et.kind&kindNoPointers != 0 {
p = mallocgc(capmem, nil, false)
memmove(p, old.array, lenmem)
- memclr(add(p, lenmem), capmem-lenmem)
+ // The append() that calls growslice is going to overwrite from old.len to cap (which will be the new length).
+ // Only clear the part that will not be overwritten.
+ memclrNoHeapPointers(add(p, newlenmem), capmem-newlenmem)
} else {
// Note: can't use rawmem (which avoids zeroing of memory), because then GC can scan uninitialized memory.
p = mallocgc(capmem, et, true)
diff --git a/src/runtime/softfloat_arm.go b/src/runtime/softfloat_arm.go
index 5f609c8..3cbb4b3 100644
--- a/src/runtime/softfloat_arm.go
+++ b/src/runtime/softfloat_arm.go
@@ -446,6 +446,23 @@ execute:
}
return 1
+ case 0xeeb10b40: // D[regd] = neg D[regm]
+ m.freglo[regd] = m.freglo[regm]
+ m.freghi[regd] = m.freghi[regm] ^ 1<<31
+
+ if fptrace > 0 {
+ print("*** D[", regd, "] = neg D[", regm, "] ", hex(m.freghi[regd]), "-", hex(m.freglo[regd]), "\n")
+ }
+ return 1
+
+ case 0xeeb10a40: // F[regd] = neg F[regm]
+ m.freglo[regd] = m.freglo[regm] ^ 1<<31
+
+ if fptrace > 0 {
+ print("*** F[", regd, "] = neg F[", regm, "] ", hex(m.freglo[regd]), "\n")
+ }
+ return 1
+
case 0xeeb40bc0: // D[regd] :: D[regm] (CMPD)
cmp, nan := fcmp64(fgetd(regd), fgetd(regm))
m.fflag = fstatus(nan, cmp)
@@ -464,6 +481,24 @@ execute:
}
return 1
+ case 0xeeb50bc0: // D[regd] :: 0 (CMPD)
+ cmp, nan := fcmp64(fgetd(regd), 0)
+ m.fflag = fstatus(nan, cmp)
+
+ if fptrace > 0 {
+ print("*** cmp D[", regd, "]::0 ", hex(m.fflag), "\n")
+ }
+ return 1
+
+ case 0xeeb50ac0: // F[regd] :: 0 (CMPF)
+ cmp, nan := fcmp64(f32to64(m.freglo[regd]), 0)
+ m.fflag = fstatus(nan, cmp)
+
+ if fptrace > 0 {
+ print("*** cmp F[", regd, "]::0 ", hex(m.fflag), "\n")
+ }
+ return 1
+
case 0xeeb70ac0: // D[regd] = F[regm] (MOVFD)
fputd(regd, f32to64(m.freglo[regm]))
diff --git a/src/runtime/stack.go b/src/runtime/stack.go
index 8398a10..ea9a69a 100644
--- a/src/runtime/stack.go
+++ b/src/runtime/stack.go
@@ -90,7 +90,7 @@ const (
// The stack guard is a pointer this many bytes above the
// bottom of the stack.
- _StackGuard = 720*sys.StackGuardMultiplier + _StackSystem
+ _StackGuard = 880*sys.StackGuardMultiplier + _StackSystem
// After a stack split check the SP is allowed to be this
// many bytes below the stack guard. This saves an instruction
@@ -335,6 +335,7 @@ func stackalloc(n uint32) (stack, []stkbar) {
// 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)
@@ -342,7 +343,9 @@ func stackalloc(n uint32) (stack, []stkbar) {
throw("out of memory (stackalloc)")
}
top := uintptr(n) - nstkbar
- stkbarSlice := slice{add(v, top), 0, maxstkbar}
+ if maxstkbar != 0 {
+ stkbarSlice = slice{add(v, top), 0, maxstkbar}
+ }
return stack{uintptr(v), uintptr(v) + top}, *(*[]stkbar)(unsafe.Pointer(&stkbarSlice))
}
@@ -410,7 +413,9 @@ func stackalloc(n uint32) (stack, []stkbar) {
print(" allocated ", v, "\n")
}
top := uintptr(n) - nstkbar
- stkbarSlice := slice{add(v, top), 0, maxstkbar}
+ if maxstkbar != 0 {
+ stkbarSlice = slice{add(v, top), 0, maxstkbar}
+ }
return stack{uintptr(v), uintptr(v) + top}, *(*[]stkbar)(unsafe.Pointer(&stkbarSlice))
}
@@ -431,7 +436,7 @@ func stackfree(stk stack, n uintptr) {
}
if stackDebug >= 1 {
println("stackfree", v, n)
- memclr(v, n) // for testing, clobber stack data
+ memclrNoHeapPointers(v, n) // for testing, clobber stack data
}
if debug.efence != 0 || stackFromSystem != 0 {
if debug.efence != 0 || stackFaultOnFree != 0 {
@@ -598,11 +603,11 @@ func adjustpointers(scanp unsafe.Pointer, cbv *bitvector, adjinfo *adjustinfo, f
// Live analysis wrong?
getg().m.traceback = 2
print("runtime: bad pointer in frame ", funcname(f), " at ", pp, ": ", hex(p), "\n")
- throw("invalid stack pointer")
+ throw("invalid pointer found on stack")
}
if minp <= p && p < maxp {
if stackDebug >= 3 {
- print("adjust ptr ", p, " ", funcname(f), "\n")
+ print("adjust ptr ", hex(p), " ", funcname(f), "\n")
}
if useCAS {
ppu := (*unsafe.Pointer)(unsafe.Pointer(pp))
@@ -925,7 +930,10 @@ func round2(x int32) int32 {
//
// g->atomicstatus will be Grunning or Gscanrunning upon entry.
// If the GC is trying to stop this g then it will set preemptscan to true.
-func newstack() {
+//
+// ctxt is the value of the context register on morestack. newstack
+// will write it to g.sched.ctxt.
+func newstack(ctxt unsafe.Pointer) {
thisg := getg()
// TODO: double check all gp. shouldn't be getg().
if thisg.m.morebuf.g.ptr().stackguard0 == stackFork {
@@ -937,8 +945,13 @@ func newstack() {
traceback(morebuf.pc, morebuf.sp, morebuf.lr, morebuf.g.ptr())
throw("runtime: wrong goroutine in newstack")
}
+
+ gp := thisg.m.curg
+ // Write ctxt to gp.sched. We do this here instead of in
+ // morestack so it has the necessary write barrier.
+ gp.sched.ctxt = ctxt
+
if thisg.m.curg.throwsplit {
- gp := thisg.m.curg
// Update syscallsp, syscallpc in case traceback uses them.
morebuf := thisg.m.morebuf
gp.syscallsp = morebuf.sp
@@ -951,13 +964,11 @@ func newstack() {
throw("runtime: stack split at bad time")
}
- gp := thisg.m.curg
morebuf := thisg.m.morebuf
thisg.m.morebuf.pc = 0
thisg.m.morebuf.lr = 0
thisg.m.morebuf.sp = 0
thisg.m.morebuf.g = 0
- rewindmorestack(&gp.sched)
// NOTE: stackguard0 may change underfoot, if another thread
// is about to try to preempt gp. Read it just once and use that same
@@ -1004,14 +1015,6 @@ func newstack() {
throw("runtime: split stack overflow")
}
- if gp.sched.ctxt != nil {
- // morestack wrote sched.ctxt on its way in here,
- // without a write barrier. Run the write barrier now.
- // It is not possible to be preempted between then
- // and now, so it's okay.
- writebarrierptr_nostore((*uintptr)(unsafe.Pointer(&gp.sched.ctxt)), uintptr(gp.sched.ctxt))
- }
-
if preempt {
if gp == thisg.m.g0 {
throw("runtime: preempt g0")
@@ -1119,6 +1122,11 @@ func shrinkstack(gp *g) {
if debug.gcshrinkstackoff > 0 {
return
}
+ if gp.startpc == gcBgMarkWorkerPC {
+ // We're not allowed to shrink the gcBgMarkWorker
+ // stack (see gcBgMarkWorker for explanation).
+ return
+ }
oldsize := gp.stackAlloc
newsize := oldsize / 2
diff --git a/src/runtime/string.go b/src/runtime/string.go
index ef28ba9..822adaa 100644
--- a/src/runtime/string.go
+++ b/src/runtime/string.go
@@ -4,10 +4,7 @@
package runtime
-import (
- "runtime/internal/atomic"
- "unsafe"
-)
+import "unsafe"
// The constant is known to the compiler.
// There is no fundamental theory behind this number.
@@ -47,10 +44,9 @@ func concatstrings(buf *tmpBuf, a []string) string {
return a[idx]
}
s, b := rawstringtmp(buf, l)
- l = 0
for _, x := range a {
- copy(b[l:], x)
- l += len(x)
+ copy(b, x)
+ b = b[len(x):]
}
return s
}
@@ -113,17 +109,20 @@ func rawstringtmp(buf *tmpBuf, l int) (s string, b []byte) {
return
}
+// slicebytetostringtmp returns a "string" referring to the actual []byte bytes.
+//
+// Callers need to ensure that the returned string will not be used after
+// the calling goroutine modifies the original slice or synchronizes with
+// another goroutine.
+//
+// The function is only called when instrumenting
+// and otherwise intrinsified by the compiler.
+//
+// Some internal compiler optimizations use this function.
+// - Used for m[string(k)] lookup where m is a string-keyed map and k is a []byte.
+// - Used for "<"+string(b)+">" concatenation where b is []byte.
+// - Used for string(b)=="foo" comparison where b is []byte.
func slicebytetostringtmp(b []byte) string {
- // Return a "string" referring to the actual []byte bytes.
- // This is only for use by internal compiler optimizations
- // that know that the string form will be discarded before
- // the calling goroutine could possibly modify the original
- // slice or synchronize with another goroutine.
- // First such case is a m[string(k)] lookup where
- // m is a string-keyed map and k is a []byte.
- // Second such case is "<"+string(b)+">" concatenation where b is []byte.
- // Third such case is string(b)=="foo" comparison where b is []byte.
-
if raceenabled && len(b) > 0 {
racereadrangepc(unsafe.Pointer(&b[0]),
uintptr(len(b)),
@@ -148,28 +147,14 @@ func stringtoslicebyte(buf *tmpBuf, s string) []byte {
return b
}
-func stringtoslicebytetmp(s string) []byte {
- // Return a slice referring to the actual string bytes.
- // This is only for use by internal compiler optimizations
- // that know that the slice won't be mutated.
- // The only such case today is:
- // for i, c := range []byte(str)
-
- str := stringStructOf(&s)
- ret := slice{array: str.str, len: str.len, cap: str.len}
- return *(*[]byte)(unsafe.Pointer(&ret))
-}
-
func stringtoslicerune(buf *[tmpStringBufSize]rune, s string) []rune {
// two passes.
// unlike slicerunetostring, no race because strings are immutable.
n := 0
- t := s
- for len(s) > 0 {
- _, k := charntorune(s)
- s = s[k:]
+ for range s {
n++
}
+
var a []rune
if buf != nil && n <= len(buf) {
*buf = [tmpStringBufSize]rune{}
@@ -177,10 +162,9 @@ func stringtoslicerune(buf *[tmpStringBufSize]rune, s string) []rune {
} else {
a = rawruneslice(n)
}
+
n = 0
- for len(t) > 0 {
- r, k := charntorune(t)
- t = t[k:]
+ for _, r := range s {
a[n] = r
n++
}
@@ -200,7 +184,7 @@ func slicerunetostring(buf *tmpBuf, a []rune) string {
var dum [4]byte
size1 := 0
for _, r := range a {
- size1 += runetochar(dum[:], r)
+ size1 += encoderune(dum[:], r)
}
s, b := rawstringtmp(buf, size1+3)
size2 := 0
@@ -209,7 +193,7 @@ func slicerunetostring(buf *tmpBuf, a []rune) string {
if size2 >= size1 {
break
}
- size2 += runetochar(b[size2:], r)
+ size2 += encoderune(b[size2:], r)
}
return s[:size2]
}
@@ -239,48 +223,12 @@ func intstring(buf *[4]byte, v int64) string {
s, b = rawstring(4)
}
if int64(rune(v)) != v {
- v = runeerror
+ v = runeError
}
- n := runetochar(b, rune(v))
+ n := encoderune(b, rune(v))
return s[:n]
}
-// stringiter returns the index of the next
-// rune after the rune that starts at s[k].
-func stringiter(s string, k int) int {
- if k >= len(s) {
- // 0 is end of iteration
- return 0
- }
-
- c := s[k]
- if c < runeself {
- return k + 1
- }
-
- // multi-char rune
- _, n := charntorune(s[k:])
- return k + n
-}
-
-// stringiter2 returns the rune that starts at s[k]
-// and the index where the next rune starts.
-func stringiter2(s string, k int) (int, rune) {
- if k >= len(s) {
- // 0 is end of iteration
- return 0, 0
- }
-
- c := s[k]
- if c < runeself {
- return k + 1, rune(c)
- }
-
- // multi-char rune
- r, n := charntorune(s[k:])
- return k + n, r
-}
-
// rawstring allocates storage for a new string. The returned
// string and byte slice both refer to the same storage.
// The storage is not zeroed. Callers should use
@@ -293,12 +241,7 @@ func rawstring(size int) (s string, b []byte) {
*(*slice)(unsafe.Pointer(&b)) = slice{p, size, size}
- for {
- ms := maxstring
- if uintptr(size) <= ms || atomic.Casuintptr((*uintptr)(unsafe.Pointer(&maxstring)), ms, uintptr(size)) {
- return
- }
- }
+ return
}
// rawbyteslice allocates a new byte slice. The byte slice is not zeroed.
@@ -306,7 +249,7 @@ func rawbyteslice(size int) (b []byte) {
cap := roundupsize(uintptr(size))
p := mallocgc(cap, nil, false)
if cap != uintptr(size) {
- memclr(add(p, uintptr(size)), cap-uintptr(size))
+ memclrNoHeapPointers(add(p, uintptr(size)), cap-uintptr(size))
}
*(*slice)(unsafe.Pointer(&b)) = slice{p, size, int(cap)}
@@ -321,7 +264,7 @@ func rawruneslice(size int) (b []rune) {
mem := roundupsize(uintptr(size) * 4)
p := mallocgc(mem, nil, false)
if mem != uintptr(size)*4 {
- memclr(add(p, uintptr(size)*4), mem-uintptr(size)*4)
+ memclrNoHeapPointers(add(p, uintptr(size)*4), mem-uintptr(size)*4)
}
*(*slice)(unsafe.Pointer(&b)) = slice{p, size, int(mem / 4)}
@@ -377,13 +320,66 @@ func hasprefix(s, t string) bool {
return len(s) >= len(t) && s[:len(t)] == t
}
-func atoi(s string) int {
- n := 0
- for len(s) > 0 && '0' <= s[0] && s[0] <= '9' {
- n = n*10 + int(s[0]) - '0'
+const (
+ maxUint = ^uint(0)
+ maxInt = int(maxUint >> 1)
+)
+
+// atoi parses an int from a string s.
+// The bool result reports whether s is a number
+// representable by a value of type int.
+func atoi(s string) (int, bool) {
+ if s == "" {
+ return 0, false
+ }
+
+ neg := false
+ if s[0] == '-' {
+ neg = true
s = s[1:]
}
- return n
+
+ un := uint(0)
+ for i := 0; i < len(s); i++ {
+ c := s[i]
+ if c < '0' || c > '9' {
+ return 0, false
+ }
+ if un > maxUint/10 {
+ // overflow
+ return 0, false
+ }
+ un *= 10
+ un1 := un + uint(c) - '0'
+ if un1 < un {
+ // overflow
+ return 0, false
+ }
+ un = un1
+ }
+
+ if !neg && un > uint(maxInt) {
+ return 0, false
+ }
+ if neg && un > uint(maxInt)+1 {
+ return 0, false
+ }
+
+ n := int(un)
+ if neg {
+ n = -n
+ }
+
+ return n, true
+}
+
+// atoi32 is like atoi but for integers
+// that fit into an int32.
+func atoi32(s string) (int32, bool) {
+ if n, ok := atoi(s); n == int(int32(n)) {
+ return int32(n), ok
+ }
+ return 0, false
}
//go:nosplit
@@ -411,18 +407,10 @@ func findnullw(s *uint16) int {
return l
}
-var maxstring uintptr = 256 // a hint for print
-
//go:nosplit
func gostringnocopy(str *byte) string {
ss := stringStruct{str: unsafe.Pointer(str), len: findnull(str)}
s := *(*string)(unsafe.Pointer(&ss))
- for {
- ms := maxstring
- if uintptr(len(s)) <= ms || atomic.Casuintptr(&maxstring, ms, uintptr(len(s))) {
- break
- }
- }
return s
}
@@ -431,7 +419,7 @@ func gostringw(strw *uint16) string {
str := (*[_MaxMem/2/2 - 1]uint16)(unsafe.Pointer(strw))
n1 := 0
for i := 0; str[i] != 0; i++ {
- n1 += runetochar(buf[:], rune(str[i]))
+ n1 += encoderune(buf[:], rune(str[i]))
}
s, b := rawstring(n1 + 4)
n2 := 0
@@ -440,7 +428,7 @@ func gostringw(strw *uint16) string {
if n2 >= n1 {
break
}
- n2 += runetochar(b[n2:], rune(str[i]))
+ n2 += encoderune(b[n2:], rune(str[i]))
}
b[n2] = 0 // for luck
return s[:n2]
diff --git a/src/runtime/string_test.go b/src/runtime/string_test.go
index 0f1d82a..fcfc522 100644
--- a/src/runtime/string_test.go
+++ b/src/runtime/string_test.go
@@ -82,28 +82,50 @@ func BenchmarkCompareStringBig(b *testing.B) {
b.SetBytes(int64(len(s1)))
}
-func BenchmarkRuneIterate(b *testing.B) {
- bytes := make([]byte, 100)
- for i := range bytes {
- bytes[i] = byte('A')
- }
- s := string(bytes)
+func BenchmarkConcatStringAndBytes(b *testing.B) {
+ s1 := []byte("Gophers!")
for i := 0; i < b.N; i++ {
- for range s {
- }
+ _ = "Hello " + string(s1)
}
}
-func BenchmarkRuneIterate2(b *testing.B) {
- bytes := make([]byte, 100)
- for i := range bytes {
- bytes[i] = byte('A')
- }
- s := string(bytes)
- for i := 0; i < b.N; i++ {
- for range s {
+var stringdata = []struct{ name, data string }{
+ {"ASCII", "01234567890"},
+ {"Japanese", "日本語日本語日本語"},
+ {"MixedLength", "$Ѐࠀက퀀𐀀\U00040000\U0010FFFF"},
+}
+
+func BenchmarkRuneIterate(b *testing.B) {
+ b.Run("range", func(b *testing.B) {
+ for _, sd := range stringdata {
+ b.Run(sd.name, func(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ for range sd.data {
+ }
+ }
+ })
}
- }
+ })
+ b.Run("range1", func(b *testing.B) {
+ for _, sd := range stringdata {
+ b.Run(sd.name, func(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ for _ = range sd.data {
+ }
+ }
+ })
+ }
+ })
+ b.Run("range2", func(b *testing.B) {
+ for _, sd := range stringdata {
+ b.Run(sd.name, func(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ for _, _ = range sd.data {
+ }
+ }
+ })
+ }
+ })
}
func BenchmarkArrayEqual(b *testing.B) {
@@ -148,19 +170,6 @@ func TestLargeStringConcat(t *testing.T) {
}
}
-func TestGostringnocopy(t *testing.T) {
- max := *runtime.Maxstring
- b := make([]byte, max+10)
- for i := uintptr(0); i < max+9; i++ {
- b[i] = 'a'
- }
- _ = runtime.Gostringnocopy(&b[0])
- newmax := *runtime.Maxstring
- if newmax != max+9 {
- t.Errorf("want %d, got %d", max+9, newmax)
- }
-}
-
func TestCompareTempString(t *testing.T) {
s := strings.Repeat("x", sizeNoStack)
b := []byte(s)
@@ -270,3 +279,97 @@ func TestString2Slice(t *testing.T) {
t.Errorf("extra runes not zeroed")
}
}
+
+const intSize = 32 << (^uint(0) >> 63)
+
+type atoi64Test struct {
+ in string
+ out int64
+ ok bool
+}
+
+var atoi64tests = []atoi64Test{
+ {"", 0, false},
+ {"0", 0, true},
+ {"-0", 0, true},
+ {"1", 1, true},
+ {"-1", -1, true},
+ {"12345", 12345, true},
+ {"-12345", -12345, true},
+ {"012345", 12345, true},
+ {"-012345", -12345, true},
+ {"12345x", 0, false},
+ {"-12345x", 0, false},
+ {"98765432100", 98765432100, true},
+ {"-98765432100", -98765432100, true},
+ {"20496382327982653440", 0, false},
+ {"-20496382327982653440", 0, false},
+ {"9223372036854775807", 1<<63 - 1, true},
+ {"-9223372036854775807", -(1<<63 - 1), true},
+ {"9223372036854775808", 0, false},
+ {"-9223372036854775808", -1 << 63, true},
+ {"9223372036854775809", 0, false},
+ {"-9223372036854775809", 0, false},
+}
+
+func TestAtoi(t *testing.T) {
+ switch intSize {
+ case 32:
+ for i := range atoi32tests {
+ test := &atoi32tests[i]
+ out, ok := runtime.Atoi(test.in)
+ if test.out != int32(out) || test.ok != ok {
+ t.Errorf("atoi(%q) = (%v, %v) want (%v, %v)",
+ test.in, out, ok, test.out, test.ok)
+ }
+ }
+ case 64:
+ for i := range atoi64tests {
+ test := &atoi64tests[i]
+ out, ok := runtime.Atoi(test.in)
+ if test.out != int64(out) || test.ok != ok {
+ t.Errorf("atoi(%q) = (%v, %v) want (%v, %v)",
+ test.in, out, ok, test.out, test.ok)
+ }
+ }
+ }
+}
+
+type atoi32Test struct {
+ in string
+ out int32
+ ok bool
+}
+
+var atoi32tests = []atoi32Test{
+ {"", 0, false},
+ {"0", 0, true},
+ {"-0", 0, true},
+ {"1", 1, true},
+ {"-1", -1, true},
+ {"12345", 12345, true},
+ {"-12345", -12345, true},
+ {"012345", 12345, true},
+ {"-012345", -12345, true},
+ {"12345x", 0, false},
+ {"-12345x", 0, false},
+ {"987654321", 987654321, true},
+ {"-987654321", -987654321, true},
+ {"2147483647", 1<<31 - 1, true},
+ {"-2147483647", -(1<<31 - 1), true},
+ {"2147483648", 0, false},
+ {"-2147483648", -1 << 31, true},
+ {"2147483649", 0, false},
+ {"-2147483649", 0, false},
+}
+
+func TestAtoi32(t *testing.T) {
+ for i := range atoi32tests {
+ test := &atoi32tests[i]
+ out, ok := runtime.Atoi32(test.in)
+ if test.out != out || test.ok != ok {
+ t.Errorf("atoi32(%q) = (%v, %v) want (%v, %v)",
+ test.in, out, ok, test.out, test.ok)
+ }
+ }
+}
diff --git a/src/runtime/stubs.go b/src/runtime/stubs.go
index a594c1b..107f260 100644
--- a/src/runtime/stubs.go
+++ b/src/runtime/stubs.go
@@ -4,7 +4,10 @@
package runtime
-import "unsafe"
+import (
+ "runtime/internal/sys"
+ "unsafe"
+)
// Should be a built-in for unsafe.Pointer?
//go:nosplit
@@ -57,14 +60,24 @@ func badsystemstack() {
throw("systemstack called from unexpected goroutine")
}
-// memclr clears n bytes starting at ptr.
+// memclrNoHeapPointers clears n bytes starting at ptr.
+//
+// Usually you should use typedmemclr. memclrNoHeapPointers should be
+// used only when the caller knows that *ptr contains no heap pointers
+// because either:
+//
+// 1. *ptr is initialized memory and its type is pointer-free.
+//
+// 2. *ptr is uninitialized memory (e.g., memory that's being reused
+// for a new allocation) and hence contains only "junk".
+//
// in memclr_*.s
//go:noescape
-func memclr(ptr unsafe.Pointer, n uintptr)
+func memclrNoHeapPointers(ptr unsafe.Pointer, n uintptr)
-//go:linkname reflect_memclr reflect.memclr
-func reflect_memclr(ptr unsafe.Pointer, n uintptr) {
- memclr(ptr, n)
+//go:linkname reflect_memclrNoHeapPointers reflect.memclrNoHeapPointers
+func reflect_memclrNoHeapPointers(ptr unsafe.Pointer, n uintptr) {
+ memclrNoHeapPointers(ptr, n)
}
// memmove copies n bytes from "from" to "to".
@@ -81,7 +94,10 @@ func reflect_memmove(to, from unsafe.Pointer, n uintptr) {
var hashLoad = loadFactor
// in asm_*.s
-func fastrand1() uint32
+func fastrand() uint32
+
+//go:linkname sync_fastrand sync.fastrand
+func sync_fastrand() uint32 { return fastrand() }
// in asm_*.s
//go:noescape
@@ -90,7 +106,7 @@ func memequal(a, b unsafe.Pointer, size uintptr) bool
// noescape hides a pointer from escape analysis. noescape is
// the identity function but escape analysis doesn't think the
// output depends on the input. noescape is inlined and currently
-// compiles down to a single xor instruction.
+// compiles down to zero instructions.
// USE CAREFULLY!
//go:nosplit
func noescape(p unsafe.Pointer) unsafe.Pointer {
@@ -196,8 +212,10 @@ func setcallerpc(argp unsafe.Pointer, pc uintptr)
//go:noescape
func getcallerpc(argp unsafe.Pointer) uintptr
-//go:noescape
-func getcallersp(argp unsafe.Pointer) uintptr
+//go:nosplit
+func getcallersp(argp unsafe.Pointer) uintptr {
+ return uintptr(argp) - sys.MinFrameSize
+}
//go:noescape
func asmcgocall(fn, arg unsafe.Pointer) int32
@@ -206,6 +224,7 @@ func asmcgocall(fn, arg unsafe.Pointer) int32
const _NoArgs = ^uintptr(0)
func morestack()
+func morestack_noctxt()
func rt0_go()
// stackBarrier records that the stack has been unwound past a certain
@@ -227,32 +246,32 @@ func time_now() (sec int64, nsec int32)
// in asm_*.s
// not called directly; definitions here supply type information for traceback.
-func call32(fn, arg unsafe.Pointer, n, retoffset uint32)
-func call64(fn, arg unsafe.Pointer, n, retoffset uint32)
-func call128(fn, arg unsafe.Pointer, n, retoffset uint32)
-func call256(fn, arg unsafe.Pointer, n, retoffset uint32)
-func call512(fn, arg unsafe.Pointer, n, retoffset uint32)
-func call1024(fn, arg unsafe.Pointer, n, retoffset uint32)
-func call2048(fn, arg unsafe.Pointer, n, retoffset uint32)
-func call4096(fn, arg unsafe.Pointer, n, retoffset uint32)
-func call8192(fn, arg unsafe.Pointer, n, retoffset uint32)
-func call16384(fn, arg unsafe.Pointer, n, retoffset uint32)
-func call32768(fn, arg unsafe.Pointer, n, retoffset uint32)
-func call65536(fn, arg unsafe.Pointer, n, retoffset uint32)
-func call131072(fn, arg unsafe.Pointer, n, retoffset uint32)
-func call262144(fn, arg unsafe.Pointer, n, retoffset uint32)
-func call524288(fn, arg unsafe.Pointer, n, retoffset uint32)
-func call1048576(fn, arg unsafe.Pointer, n, retoffset uint32)
-func call2097152(fn, arg unsafe.Pointer, n, retoffset uint32)
-func call4194304(fn, arg unsafe.Pointer, n, retoffset uint32)
-func call8388608(fn, arg unsafe.Pointer, n, retoffset uint32)
-func call16777216(fn, arg unsafe.Pointer, n, retoffset uint32)
-func call33554432(fn, arg unsafe.Pointer, n, retoffset uint32)
-func call67108864(fn, arg unsafe.Pointer, n, retoffset uint32)
-func call134217728(fn, arg unsafe.Pointer, n, retoffset uint32)
-func call268435456(fn, arg unsafe.Pointer, n, retoffset uint32)
-func call536870912(fn, arg unsafe.Pointer, n, retoffset uint32)
-func call1073741824(fn, arg unsafe.Pointer, n, retoffset uint32)
+func call32(typ, fn, arg unsafe.Pointer, n, retoffset uint32)
+func call64(typ, fn, arg unsafe.Pointer, n, retoffset uint32)
+func call128(typ, fn, arg unsafe.Pointer, n, retoffset uint32)
+func call256(typ, fn, arg unsafe.Pointer, n, retoffset uint32)
+func call512(typ, fn, arg unsafe.Pointer, n, retoffset uint32)
+func call1024(typ, fn, arg unsafe.Pointer, n, retoffset uint32)
+func call2048(typ, fn, arg unsafe.Pointer, n, retoffset uint32)
+func call4096(typ, fn, arg unsafe.Pointer, n, retoffset uint32)
+func call8192(typ, fn, arg unsafe.Pointer, n, retoffset uint32)
+func call16384(typ, fn, arg unsafe.Pointer, n, retoffset uint32)
+func call32768(typ, fn, arg unsafe.Pointer, n, retoffset uint32)
+func call65536(typ, fn, arg unsafe.Pointer, n, retoffset uint32)
+func call131072(typ, fn, arg unsafe.Pointer, n, retoffset uint32)
+func call262144(typ, fn, arg unsafe.Pointer, n, retoffset uint32)
+func call524288(typ, fn, arg unsafe.Pointer, n, retoffset uint32)
+func call1048576(typ, fn, arg unsafe.Pointer, n, retoffset uint32)
+func call2097152(typ, fn, arg unsafe.Pointer, n, retoffset uint32)
+func call4194304(typ, fn, arg unsafe.Pointer, n, retoffset uint32)
+func call8388608(typ, fn, arg unsafe.Pointer, n, retoffset uint32)
+func call16777216(typ, fn, arg unsafe.Pointer, n, retoffset uint32)
+func call33554432(typ, fn, arg unsafe.Pointer, n, retoffset uint32)
+func call67108864(typ, fn, arg unsafe.Pointer, n, retoffset uint32)
+func call134217728(typ, fn, arg unsafe.Pointer, n, retoffset uint32)
+func call268435456(typ, fn, arg unsafe.Pointer, n, retoffset uint32)
+func call536870912(typ, fn, arg unsafe.Pointer, n, retoffset uint32)
+func call1073741824(typ, fn, arg unsafe.Pointer, n, retoffset uint32)
func systemstack_switch()
@@ -273,3 +292,6 @@ func round(n, a uintptr) uintptr {
// checkASM returns whether assembly runtime checks have passed.
func checkASM() bool
+
+func memequal_varlen(a, b unsafe.Pointer) bool
+func eqstring(s1, s2 string) bool
diff --git a/src/runtime/stubs32.go b/src/runtime/stubs32.go
index cd442e9..149560f 100644
--- a/src/runtime/stubs32.go
+++ b/src/runtime/stubs32.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build 386 arm amd64p32
+// +build 386 arm amd64p32 mips mipsle
package runtime
diff --git a/src/runtime/stubs_asm.go b/src/runtime/stubs_asm.go
new file mode 100644
index 0000000..fd2eed9
--- /dev/null
+++ b/src/runtime/stubs_asm.go
@@ -0,0 +1,11 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !mips64,!mips64le
+
+// Declarations for routines that are implemented in noasm.go.
+
+package runtime
+
+func cmpstring(s1, s2 string) int
diff --git a/src/runtime/symtab.go b/src/runtime/symtab.go
index 4f6fae2..8a5b0df 100644
--- a/src/runtime/symtab.go
+++ b/src/runtime/symtab.go
@@ -5,6 +5,7 @@
package runtime
import (
+ "runtime/internal/atomic"
"runtime/internal/sys"
"unsafe"
)
@@ -195,8 +196,14 @@ type moduledata struct {
end, gcdata, gcbss uintptr
types, etypes uintptr
- typelinks []int32 // offsets from types
- itablinks []*itab
+ textsectmap []textsect
+ typelinks []int32 // offsets from types
+ itablinks []*itab
+
+ ptab []ptabEntry
+
+ pluginpath string
+ pkghashes []modulehash
modulename string
modulehashes []modulehash
@@ -208,24 +215,92 @@ type moduledata struct {
next *moduledata
}
+// A modulehash is used to compare the ABI of a new module or a
+// package in a new module with the loaded program.
+//
// For each shared library a module links against, the linker creates an entry in the
// moduledata.modulehashes slice containing the name of the module, the abi hash seen
// at link time and a pointer to the runtime abi hash. These are checked in
// moduledataverify1 below.
+//
+// For each loaded plugin, the the pkghashes slice has a modulehash of the
+// newly loaded package that can be used to check the plugin's version of
+// a package against any previously loaded version of the package.
+// This is done in plugin.lastmoduleinit.
type modulehash struct {
modulename string
linktimehash string
runtimehash *string
}
+// pinnedTypemaps are the map[typeOff]*_type from the moduledata objects.
+//
+// These typemap objects are allocated at run time on the heap, but the
+// only direct reference to them is in the moduledata, created by the
+// linker and marked SNOPTRDATA so it is ignored by the GC.
+//
+// To make sure the map isn't collected, we keep a second reference here.
+var pinnedTypemaps []map[typeOff]*_type
+
var firstmoduledata moduledata // linker symbol
var lastmoduledatap *moduledata // linker symbol
+var modulesSlice unsafe.Pointer // see activeModules
+
+// activeModules returns a slice of active modules.
+//
+// A module is active once its gcdatamask and gcbssmask have been
+// assembled and it is usable by the GC.
+func activeModules() []*moduledata {
+ p := (*[]*moduledata)(atomic.Loadp(unsafe.Pointer(&modulesSlice)))
+ if p == nil {
+ return nil
+ }
+ return *p
+}
+
+// modulesinit creates the active modules slice out of all loaded modules.
+//
+// When a module is first loaded by the dynamic linker, an .init_array
+// function (written by cmd/link) is invoked to call addmoduledata,
+// appending to the module to the linked list that starts with
+// firstmoduledata.
+//
+// There are two times this can happen in the lifecycle of a Go
+// program. First, if compiled with -linkshared, a number of modules
+// built with -buildmode=shared can be loaded at program initialization.
+// Second, a Go program can load a module while running that was built
+// with -buildmode=plugin.
+//
+// After loading, this function is called which initializes the
+// moduledata so it is usable by the GC and creates a new activeModules
+// list.
+//
+// Only one goroutine may call modulesinit at a time.
+func modulesinit() {
+ modules := new([]*moduledata)
+ for md := &firstmoduledata; md != nil; md = md.next {
+ *modules = append(*modules, md)
+ if md.gcdatamask == (bitvector{}) {
+ md.gcdatamask = progToPointerMask((*byte)(unsafe.Pointer(md.gcdata)), md.edata-md.data)
+ md.gcbssmask = progToPointerMask((*byte)(unsafe.Pointer(md.gcbss)), md.ebss-md.bss)
+ }
+ }
+ atomicstorep(unsafe.Pointer(&modulesSlice), unsafe.Pointer(modules))
+}
type functab struct {
entry uintptr
funcoff uintptr
}
+// Mapping information for secondary text sections
+
+type textsect struct {
+ vaddr uintptr // prelinked section vaddr
+ length uintptr // section length
+ baseaddr uintptr // relocated section address
+}
+
const minfunc = 16 // minimum function size
const pcbucketsize = 256 * minfunc // size of bucket in the pc->func lookup table
@@ -367,13 +442,31 @@ func findfunc(pc uintptr) *_func {
ffb := (*findfuncbucket)(add(unsafe.Pointer(datap.findfunctab), b*unsafe.Sizeof(findfuncbucket{})))
idx := ffb.idx + uint32(ffb.subbuckets[i])
- if pc < datap.ftab[idx].entry {
- throw("findfunc: bad findfunctab entry")
+
+ // If the idx is beyond the end of the ftab, set it to the end of the table and search backward.
+ // This situation can occur if multiple text sections are generated to handle large text sections
+ // and the linker has inserted jump tables between them.
+
+ if idx >= uint32(len(datap.ftab)) {
+ idx = uint32(len(datap.ftab) - 1)
}
+ if pc < datap.ftab[idx].entry {
+
+ // With multiple text sections, the idx might reference a function address that
+ // is higher than the pc being searched, so search backward until the matching address is found.
- // linear search to find func with pc >= entry.
- for datap.ftab[idx+1].entry <= pc {
- idx++
+ for datap.ftab[idx].entry > pc && idx > 0 {
+ idx--
+ }
+ if idx == 0 {
+ throw("findfunc: bad findfunctab entry idx")
+ }
+ } else {
+
+ // linear search to find func with pc >= entry.
+ for datap.ftab[idx+1].entry <= pc {
+ idx++
+ }
}
return (*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[idx].funcoff]))
}
@@ -437,7 +530,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 := fastrand1() % uint32(len(cache.entries))
+ ci := fastrand() % uint32(len(cache.entries))
cache.entries[ci] = pcvalueCacheEnt{
targetpc: targetpc,
off: off,
@@ -581,5 +674,5 @@ func stackmapdata(stkmap *stackmap, n int32) bitvector {
if n < 0 || n >= stkmap.n {
throw("stackmapdata: index out of range")
}
- return bitvector{stkmap.nbit, (*byte)(add(unsafe.Pointer(&stkmap.bytedata), uintptr(n*((stkmap.nbit+31)/32*4))))}
+ return bitvector{stkmap.nbit, (*byte)(add(unsafe.Pointer(&stkmap.bytedata), uintptr(n*((stkmap.nbit+7)/8))))}
}
diff --git a/src/runtime/sys_arm.go b/src/runtime/sys_arm.go
index d2e6914..730b9c9 100644
--- a/src/runtime/sys_arm.go
+++ b/src/runtime/sys_arm.go
@@ -17,22 +17,5 @@ func gostartcall(buf *gobuf, fn, ctxt unsafe.Pointer) {
buf.ctxt = ctxt
}
-// Called to rewind context saved during morestack back to beginning of function.
-// To help us, the linker emits a jmp back to the beginning right after the
-// call to morestack. We just have to decode and apply that jump.
-func rewindmorestack(buf *gobuf) {
- var inst uint32
- if buf.pc&3 == 0 && buf.pc != 0 {
- inst = *(*uint32)(unsafe.Pointer(buf.pc))
- if inst>>24 == 0x9a || inst>>24 == 0xea {
- buf.pc += uintptr(int32(inst<<8)>>6) + 8
- return
- }
- }
-
- print("runtime: pc=", hex(buf.pc), " ", hex(inst), "\n")
- throw("runtime: misuse of rewindmorestack")
-}
-
// for testing
func usplit(x uint32) (q, r uint32)
diff --git a/src/runtime/sys_arm64.go b/src/runtime/sys_arm64.go
index dee23ef..230241d 100644
--- a/src/runtime/sys_arm64.go
+++ b/src/runtime/sys_arm64.go
@@ -16,21 +16,3 @@ func gostartcall(buf *gobuf, fn, ctxt unsafe.Pointer) {
buf.pc = uintptr(fn)
buf.ctxt = ctxt
}
-
-// Called to rewind context saved during morestack back to beginning of function.
-// To help us, the linker emits a jmp back to the beginning right after the
-// call to morestack. We just have to decode and apply that jump.
-func rewindmorestack(buf *gobuf) {
- var inst uint32
- if buf.pc&3 == 0 && buf.pc != 0 {
- inst = *(*uint32)(unsafe.Pointer(buf.pc))
- // section C3.2.6 Unconditional branch (immediate)
- if inst>>26 == 0x05 {
- buf.pc += uintptr(int32(inst<<6) >> 4)
- return
- }
- }
-
- print("runtime: pc=", hex(buf.pc), " ", hex(inst), "\n")
- throw("runtime: misuse of rewindmorestack")
-}
diff --git a/src/runtime/sys_darwin_386.s b/src/runtime/sys_darwin_386.s
index b5e65e6..200961f 100644
--- a/src/runtime/sys_darwin_386.s
+++ b/src/runtime/sys_darwin_386.s
@@ -200,7 +200,7 @@ systime:
MOVL AX, 4(SP)
MOVL $0, 8(SP) // time zone pointer
MOVL $0, 12(SP) // required as of Sierra; Issue 16570
- MOVL $116, AX
+ MOVL $116, AX // SYS_GETTIMEOFDAY
INT $0x80
CMPL AX, $0
JNE inreg
@@ -254,52 +254,37 @@ TEXT runtime·sigfwd(SB),NOSPLIT,$0-16
MOVL info+8(FP), CX
MOVL ctx+12(FP), DX
MOVL SP, SI
- SUBL $32, SP // align stack; handler might be C code
- ANDL $~15, SP
+ SUBL $32, SP
+ ANDL $~15, SP // align stack: handler might be a C function
MOVL BX, 0(SP)
MOVL CX, 4(SP)
MOVL DX, 8(SP)
- MOVL SI, 12(SP)
+ MOVL SI, 12(SP) // save SI: handler might be a Go function
CALL AX
MOVL 12(SP), AX
MOVL AX, SP
RET
-TEXT runtime·sigreturn(SB),NOSPLIT,$12-8
- MOVL ctx+0(FP), CX
- MOVL infostyle+4(FP), BX
- MOVL $0, 0(SP) // "caller PC" - ignored
- MOVL CX, 4(SP)
- MOVL BX, 8(SP)
- MOVL $184, AX // sigreturn(ucontext, infostyle)
- INT $0x80
- MOVL $0xf1, 0xf1 // crash
- RET
-
// Sigtramp's job is to call the actual signal handler.
// It is called with the following arguments on the stack:
// 0(SP) "return address" - ignored
// 4(SP) actual handler
-// 8(SP) signal number
-// 12(SP) siginfo style
+// 8(SP) siginfo style
+// 12(SP) signal number
// 16(SP) siginfo
// 20(SP) context
TEXT runtime·sigtramp(SB),NOSPLIT,$20
- MOVL fn+0(FP), BX
+ MOVL sig+8(FP), BX
MOVL BX, 0(SP)
- MOVL style+4(FP), BX
+ MOVL info+12(FP), BX
MOVL BX, 4(SP)
- MOVL sig+8(FP), BX
+ MOVL ctx+16(FP), BX
MOVL BX, 8(SP)
- MOVL info+12(FP), BX
- MOVL BX, 12(SP)
- MOVL context+16(FP), BX
- MOVL BX, 16(SP)
CALL runtime·sigtrampgo(SB)
// call sigreturn
- MOVL context+16(FP), CX
- MOVL style+4(FP), BX
+ MOVL ctx+16(FP), CX
+ MOVL infostyle+4(FP), BX
MOVL $0, 0(SP) // "caller PC" - ignored
MOVL CX, 4(SP)
MOVL BX, 8(SP)
diff --git a/src/runtime/sys_darwin_amd64.s b/src/runtime/sys_darwin_amd64.s
index ea2cc06..96fa5b9 100644
--- a/src/runtime/sys_darwin_amd64.s
+++ b/src/runtime/sys_darwin_amd64.s
@@ -158,7 +158,7 @@ systime:
MOVQ SP, DI
MOVQ $0, SI
MOVQ $0, DX // required as of Sierra; Issue 16570
- MOVL $(0x2000000+116), AX
+ MOVL $(0x2000000+116), AX // gettimeofday
SYSCALL
CMPQ AX, $0
JNE inreg
@@ -197,7 +197,7 @@ TEXT time·now(SB),NOSPLIT,$0-12
RET
TEXT runtime·sigprocmask(SB),NOSPLIT,$0
- MOVL sig+0(FP), DI
+ MOVL how+0(FP), DI
MOVQ new+8(FP), SI
MOVQ old+16(FP), DX
MOVL $(0x2000000+329), AX // pthread_sigmask (on OS X, sigprocmask==entire process)
@@ -219,33 +219,30 @@ TEXT runtime·sigaction(SB),NOSPLIT,$0-24
RET
TEXT runtime·sigfwd(SB),NOSPLIT,$0-32
- MOVQ fn+0(FP), AX
- MOVL sig+8(FP), DI
- MOVQ info+16(FP), SI
- MOVQ ctx+24(FP), DX
- MOVQ SP, BP
- SUBQ $64, SP
- ANDQ $~15, SP // alignment for x86_64 ABI
- CALL AX
- MOVQ BP, SP
+ MOVQ fn+0(FP), AX
+ MOVL sig+8(FP), DI
+ MOVQ info+16(FP), SI
+ MOVQ ctx+24(FP), DX
+ PUSHQ BP
+ MOVQ SP, BP
+ ANDQ $~15, SP // alignment for x86_64 ABI
+ CALL AX
+ MOVQ BP, SP
+ POPQ BP
RET
-TEXT runtime·sigreturn(SB),NOSPLIT,$0-12
- MOVQ ctx+0(FP), DI
- MOVL infostyle+8(FP), SI
- MOVL $(0x2000000+184), AX
- SYSCALL
- INT $3 // not reached
-
TEXT runtime·sigtramp(SB),NOSPLIT,$32
- MOVQ DI, 0(SP) // fn
- MOVL SI, 8(SP) // infostyle
- MOVL DX, 12(SP) // sig
- MOVQ CX, 16(SP) // info
- MOVQ R8, 24(SP) // ctx
+ MOVL SI, 24(SP) // save infostyle for sigreturn below
+ MOVL DX, 0(SP) // sig
+ MOVQ CX, 8(SP) // info
+ MOVQ R8, 16(SP) // ctx
MOVQ $runtime·sigtrampgo(SB), AX
CALL AX
- INT $3 // not reached (see issue 16453)
+ MOVQ 16(SP), DI // ctx
+ MOVL 24(SP), SI // infostyle
+ MOVL $(0x2000000+184), AX
+ SYSCALL
+ INT $3 // not reached
TEXT runtime·mmap(SB),NOSPLIT,$0
MOVQ addr+0(FP), DI // arg 1 addr
diff --git a/src/runtime/sys_darwin_arm.s b/src/runtime/sys_darwin_arm.s
index 52f6a94..2c03c91 100644
--- a/src/runtime/sys_darwin_arm.s
+++ b/src/runtime/sys_darwin_arm.s
@@ -106,7 +106,7 @@ TEXT runtime·raiseproc(SB),NOSPLIT,$24
MOVW $SYS_getpid, R12
SWI $0x80
// arg 1 pid already in R0 from getpid
- MOVW unnamed+0(FP), R1 // arg 2 - signal
+ MOVW sig+0(FP), R1 // arg 2 - signal
MOVW $1, R2 // arg 3 - posix
MOVW $SYS_kill, R12
SWI $0x80
@@ -286,7 +286,7 @@ ret:
B runtime·exit(SB)
TEXT runtime·sigprocmask(SB),NOSPLIT,$0
- MOVW sig+0(FP), R0
+ MOVW how+0(FP), R0
MOVW new+4(FP), R1
MOVW old+8(FP), R2
MOVW $SYS_pthread_sigmask, R12
diff --git a/src/runtime/sys_darwin_arm64.s b/src/runtime/sys_darwin_arm64.s
index 8e6b5b1..c02d000 100644
--- a/src/runtime/sys_darwin_arm64.s
+++ b/src/runtime/sys_darwin_arm64.s
@@ -271,7 +271,7 @@ ret:
B runtime·exit(SB)
TEXT runtime·sigprocmask(SB),NOSPLIT,$0
- MOVW sig+0(FP), R0
+ MOVW how+0(FP), R0
MOVD new+8(FP), R1
MOVD old+16(FP), R2
MOVW $SYS_pthread_sigmask, R16
diff --git a/src/runtime/sys_dragonfly_amd64.s b/src/runtime/sys_dragonfly_amd64.s
index be964cb..88c7f9d 100644
--- a/src/runtime/sys_dragonfly_amd64.s
+++ b/src/runtime/sys_dragonfly_amd64.s
@@ -51,18 +51,6 @@ TEXT runtime·lwp_start(SB),NOSPLIT,$0
MOVQ R13, g_m(DI)
MOVQ DI, g(CX)
- // On DragonFly, a new thread inherits the signal stack of the
- // creating thread. That confuses minit, so we remove that
- // signal stack here before calling the regular mstart. It's
- // a bit baroque to remove a signal stack here only to add one
- // in minit, but it's a simple change that keeps DragonFly
- // working like other OS's. At this point all signals are
- // blocked, so there is no race.
- SUBQ $8, SP
- MOVQ $0, 0(SP)
- CALL runtime·signalstack(SB)
- ADDQ $8, SP
-
CALL runtime·stackcheck(SB)
CALL runtime·mstart(SB)
@@ -162,7 +150,7 @@ TEXT runtime·setitimer(SB), NOSPLIT, $-8
// func now() (sec int64, nsec int32)
TEXT time·now(SB), NOSPLIT, $32
- MOVL $232, AX
+ MOVL $232, AX // clock_gettime
MOVQ $0, DI // CLOCK_REALTIME
LEAQ 8(SP), SI
SYSCALL
@@ -200,11 +188,16 @@ TEXT runtime·sigaction(SB),NOSPLIT,$-8
RET
TEXT runtime·sigfwd(SB),NOSPLIT,$0-32
- MOVL sig+8(FP), DI
+ MOVQ fn+0(FP), AX
+ MOVL sig+8(FP), DI
MOVQ info+16(FP), SI
- MOVQ ctx+24(FP), DX
- MOVQ fn+0(FP), AX
+ MOVQ ctx+24(FP), DX
+ PUSHQ BP
+ MOVQ SP, BP
+ ANDQ $~15, SP // alignment for x86_64 ABI
CALL AX
+ MOVQ BP, SP
+ POPQ BP
RET
TEXT runtime·sigtramp(SB),NOSPLIT,$24
@@ -249,8 +242,8 @@ TEXT runtime·madvise(SB),NOSPLIT,$0
RET
TEXT runtime·sigaltstack(SB),NOSPLIT,$-8
- MOVQ new+8(SP), DI
- MOVQ old+16(SP), SI
+ MOVQ new+0(FP), DI
+ MOVQ old+8(FP), SI
MOVQ $53, AX
SYSCALL
JCC 2(PC)
@@ -333,11 +326,11 @@ TEXT runtime·kqueue(SB),NOSPLIT,$0
// int32 runtime·kevent(int kq, Kevent *changelist, int nchanges, Kevent *eventlist, int nevents, Timespec *timeout);
TEXT runtime·kevent(SB),NOSPLIT,$0
- MOVL fd+0(FP), DI
- MOVQ ev1+8(FP), SI
- MOVL nev1+16(FP), DX
- MOVQ ev2+24(FP), R10
- MOVL nev2+32(FP), R8
+ MOVL kq+0(FP), DI
+ MOVQ ch+8(FP), SI
+ MOVL nch+16(FP), DX
+ MOVQ ev+24(FP), R10
+ MOVL nev+32(FP), R8
MOVQ ts+40(FP), R9
MOVL $363, AX
SYSCALL
diff --git a/src/runtime/sys_freebsd_386.s b/src/runtime/sys_freebsd_386.s
index b37abce..8b6ee1f 100644
--- a/src/runtime/sys_freebsd_386.s
+++ b/src/runtime/sys_freebsd_386.s
@@ -161,7 +161,7 @@ TEXT runtime·setitimer(SB), NOSPLIT, $-4
// func now() (sec int64, nsec int32)
TEXT time·now(SB), NOSPLIT, $32
- MOVL $232, AX
+ MOVL $232, AX // clock_gettime
LEAL 12(SP), BX
MOVL $0, 4(SP) // CLOCK_REALTIME
MOVL BX, 8(SP)
@@ -208,14 +208,20 @@ TEXT runtime·sigaction(SB),NOSPLIT,$-4
RET
TEXT runtime·sigfwd(SB),NOSPLIT,$12-16
- MOVL sig+4(FP), AX
- MOVL AX, 0(SP)
- MOVL info+8(FP), AX
- MOVL AX, 4(SP)
- MOVL ctx+12(FP), AX
- MOVL AX, 8(SP)
MOVL fn+0(FP), AX
+ MOVL sig+4(FP), BX
+ MOVL info+8(FP), CX
+ MOVL ctx+12(FP), DX
+ MOVL SP, SI
+ SUBL $32, SP
+ ANDL $~15, SP // align stack: handler might be a C function
+ MOVL BX, 0(SP)
+ MOVL CX, 4(SP)
+ MOVL DX, 8(SP)
+ MOVL SI, 12(SP) // save SI: handler might be a Go function
CALL AX
+ MOVL 12(SP), AX
+ MOVL AX, SP
RET
TEXT runtime·sigtramp(SB),NOSPLIT,$12
diff --git a/src/runtime/sys_freebsd_amd64.s b/src/runtime/sys_freebsd_amd64.s
index 277e7f8..19007dc 100644
--- a/src/runtime/sys_freebsd_amd64.s
+++ b/src/runtime/sys_freebsd_amd64.s
@@ -144,7 +144,7 @@ TEXT runtime·setitimer(SB), NOSPLIT, $-8
// func now() (sec int64, nsec int32)
TEXT time·now(SB), NOSPLIT, $32
- MOVL $232, AX
+ MOVL $232, AX // clock_gettime
MOVQ $0, DI // CLOCK_REALTIME
LEAQ 8(SP), SI
SYSCALL
@@ -184,11 +184,16 @@ TEXT runtime·sigaction(SB),NOSPLIT,$-8
RET
TEXT runtime·sigfwd(SB),NOSPLIT,$0-32
- MOVL sig+8(FP), DI
+ MOVQ fn+0(FP), AX
+ MOVL sig+8(FP), DI
MOVQ info+16(FP), SI
- MOVQ ctx+24(FP), DX
- MOVQ fn+0(FP), AX
+ MOVQ ctx+24(FP), DX
+ PUSHQ BP
+ MOVQ SP, BP
+ ANDQ $~15, SP // alignment for x86_64 ABI
CALL AX
+ MOVQ BP, SP
+ POPQ BP
RET
TEXT runtime·sigtramp(SB),NOSPLIT,$24
@@ -229,8 +234,8 @@ TEXT runtime·madvise(SB),NOSPLIT,$0
RET
TEXT runtime·sigaltstack(SB),NOSPLIT,$-8
- MOVQ new+8(SP), DI
- MOVQ old+16(SP), SI
+ MOVQ new+0(FP), DI
+ MOVQ old+8(FP), SI
MOVQ $53, AX
SYSCALL
JCC 2(PC)
@@ -311,11 +316,11 @@ TEXT runtime·kqueue(SB),NOSPLIT,$0
// int32 runtime·kevent(int kq, Kevent *changelist, int nchanges, Kevent *eventlist, int nevents, Timespec *timeout);
TEXT runtime·kevent(SB),NOSPLIT,$0
- MOVL fd+0(FP), DI
- MOVQ ev1+8(FP), SI
- MOVL nev1+16(FP), DX
- MOVQ ev2+24(FP), R10
- MOVL nev2+32(FP), R8
+ MOVL kq+0(FP), DI
+ MOVQ ch+8(FP), SI
+ MOVL nch+16(FP), DX
+ MOVQ ev+24(FP), R10
+ MOVL nev+32(FP), R8
MOVQ ts+40(FP), R9
MOVL $363, AX
SYSCALL
diff --git a/src/runtime/sys_linux_386.s b/src/runtime/sys_linux_386.s
index 4fe07e0..1d798c7 100644
--- a/src/runtime/sys_linux_386.s
+++ b/src/runtime/sys_linux_386.s
@@ -191,7 +191,7 @@ TEXT runtime·nanotime(SB), NOSPLIT, $32
TEXT runtime·rtsigprocmask(SB),NOSPLIT,$0
MOVL $175, AX // syscall entry
- MOVL sig+0(FP), BX
+ MOVL how+0(FP), BX
MOVL new+4(FP), CX
MOVL old+8(FP), DX
MOVL size+12(FP), SI
@@ -212,14 +212,20 @@ TEXT runtime·rt_sigaction(SB),NOSPLIT,$0
RET
TEXT runtime·sigfwd(SB),NOSPLIT,$12-16
- MOVL sig+4(FP), AX
- MOVL AX, 0(SP)
- MOVL info+8(FP), AX
- MOVL AX, 4(SP)
- MOVL ctx+12(FP), AX
- MOVL AX, 8(SP)
MOVL fn+0(FP), AX
+ MOVL sig+4(FP), BX
+ MOVL info+8(FP), CX
+ MOVL ctx+12(FP), DX
+ MOVL SP, SI
+ SUBL $32, SP
+ ANDL $-15, SP // align stack: handler might be a C function
+ MOVL BX, 0(SP)
+ MOVL CX, 4(SP)
+ MOVL DX, 8(SP)
+ MOVL SI, 12(SP) // save SI: handler might be a Go function
CALL AX
+ MOVL 12(SP), AX
+ MOVL AX, SP
RET
TEXT runtime·sigtramp(SB),NOSPLIT,$12
@@ -227,7 +233,7 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$12
MOVL BX, 0(SP)
MOVL info+4(FP), BX
MOVL BX, 4(SP)
- MOVL context+8(FP), BX
+ MOVL ctx+8(FP), BX
MOVL BX, 8(SP)
CALL runtime·sigtrampgo(SB)
RET
@@ -297,15 +303,15 @@ TEXT runtime·futex(SB),NOSPLIT,$0
TEXT runtime·clone(SB),NOSPLIT,$0
MOVL $120, AX // clone
MOVL flags+0(FP), BX
- MOVL stack+4(FP), CX
+ MOVL stk+4(FP), CX
MOVL $0, DX // parent tid ptr
MOVL $0, DI // child tid ptr
// Copy mp, gp, fn off parent stack for use by child.
SUBL $16, CX
- MOVL mm+8(FP), SI
+ MOVL mp+8(FP), SI
MOVL SI, 0(CX)
- MOVL gg+12(FP), SI
+ MOVL gp+12(FP), SI
MOVL SI, 4(CX)
MOVL fn+16(FP), SI
MOVL SI, 8(CX)
@@ -379,8 +385,8 @@ nog:
TEXT runtime·sigaltstack(SB),NOSPLIT,$-8
MOVL $186, AX // sigaltstack
- MOVL new+4(SP), BX
- MOVL old+8(SP), CX
+ MOVL new+0(FP), BX
+ MOVL old+4(FP), CX
INVOKE_SYSCALL
CMPL AX, $0xfffff001
JLS 2(PC)
diff --git a/src/runtime/sys_linux_amd64.s b/src/runtime/sys_linux_amd64.s
index 8a8f3cc..832b98b 100644
--- a/src/runtime/sys_linux_amd64.s
+++ b/src/runtime/sys_linux_amd64.s
@@ -197,7 +197,7 @@ fallback:
RET
TEXT runtime·rtsigprocmask(SB),NOSPLIT,$0-28
- MOVL sig+0(FP), DI
+ MOVL how+0(FP), DI
MOVQ new+8(FP), SI
MOVQ old+16(FP), DX
MOVL size+24(FP), R10
@@ -208,7 +208,7 @@ TEXT runtime·rtsigprocmask(SB),NOSPLIT,$0-28
MOVL $0xf1, 0xf1 // crash
RET
-TEXT runtime·rt_sigaction(SB),NOSPLIT,$0-36
+TEXT runtime·sysSigaction(SB),NOSPLIT,$0-36
MOVQ sig+0(FP), DI
MOVQ new+8(FP), SI
MOVQ old+16(FP), DX
@@ -218,12 +218,30 @@ TEXT runtime·rt_sigaction(SB),NOSPLIT,$0-36
MOVL AX, ret+32(FP)
RET
+// Call the function stored in _cgo_sigaction using the GCC calling convention.
+TEXT runtime·callCgoSigaction(SB),NOSPLIT,$16
+ MOVQ sig+0(FP), DI
+ MOVQ new+8(FP), SI
+ MOVQ old+16(FP), DX
+ MOVQ _cgo_sigaction(SB), AX
+ MOVQ SP, BX // callee-saved
+ ANDQ $~15, SP // alignment as per amd64 psABI
+ CALL AX
+ MOVQ BX, SP
+ MOVL AX, ret+24(FP)
+ RET
+
TEXT runtime·sigfwd(SB),NOSPLIT,$0-32
- MOVL sig+8(FP), DI
+ MOVQ fn+0(FP), AX
+ MOVL sig+8(FP), DI
MOVQ info+16(FP), SI
- MOVQ ctx+24(FP), DX
- MOVQ fn+0(FP), AX
+ MOVQ ctx+24(FP), DX
+ PUSHQ BP
+ MOVQ SP, BP
+ ANDQ $~15, SP // alignment for x86_64 ABI
CALL AX
+ MOVQ BP, SP
+ POPQ BP
RET
TEXT runtime·sigtramp(SB),NOSPLIT,$24
@@ -388,10 +406,10 @@ TEXT runtime·futex(SB),NOSPLIT,$0
MOVL AX, ret+40(FP)
RET
-// int32 clone(int32 flags, void *stack, M *mp, G *gp, void (*fn)(void));
+// int32 clone(int32 flags, void *stk, M *mp, G *gp, void (*fn)(void));
TEXT runtime·clone(SB),NOSPLIT,$0
MOVL flags+0(FP), DI
- MOVQ stack+8(FP), SI
+ MOVQ stk+8(FP), SI
MOVQ $0, DX
MOVQ $0, R10
@@ -445,8 +463,8 @@ nog:
JMP -3(PC) // keep exiting
TEXT runtime·sigaltstack(SB),NOSPLIT,$-8
- MOVQ new+8(SP), DI
- MOVQ old+16(SP), SI
+ MOVQ new+0(FP), DI
+ MOVQ old+8(FP), SI
MOVQ $131, AX
SYSCALL
CMPQ AX, $0xfffffffffffff001
@@ -548,7 +566,7 @@ TEXT runtime·access(SB),NOSPLIT,$0
TEXT runtime·connect(SB),NOSPLIT,$0-28
MOVL fd+0(FP), DI
MOVQ addr+8(FP), SI
- MOVL addrlen+16(FP), DX
+ MOVL len+16(FP), DX
MOVL $42, AX // syscall entry
SYSCALL
MOVL AX, ret+24(FP)
@@ -557,8 +575,8 @@ TEXT runtime·connect(SB),NOSPLIT,$0-28
// int socket(int domain, int type, int protocol)
TEXT runtime·socket(SB),NOSPLIT,$0-20
MOVL domain+0(FP), DI
- MOVL type+4(FP), SI
- MOVL protocol+8(FP), DX
+ MOVL typ+4(FP), SI
+ MOVL prot+8(FP), DX
MOVL $41, AX // syscall entry
SYSCALL
MOVL AX, ret+16(FP)
diff --git a/src/runtime/sys_linux_arm.s b/src/runtime/sys_linux_arm.s
index 5e5fcf0..666b879 100644
--- a/src/runtime/sys_linux_arm.s
+++ b/src/runtime/sys_linux_arm.s
@@ -235,13 +235,12 @@ TEXT runtime·nanotime(SB),NOSPLIT,$32
// int32 futex(int32 *uaddr, int32 op, int32 val,
// struct timespec *timeout, int32 *uaddr2, int32 val2);
TEXT runtime·futex(SB),NOSPLIT,$0
- // TODO: Rewrite to use FP references. Vet complains.
- MOVW 4(R13), R0
- MOVW 8(R13), R1
- MOVW 12(R13), R2
- MOVW 16(R13), R3
- MOVW 20(R13), R4
- MOVW 24(R13), R5
+ MOVW addr+0(FP), R0
+ MOVW op+4(FP), R1
+ MOVW val+8(FP), R2
+ MOVW ts+12(FP), R3
+ MOVW addr2+16(FP), R4
+ MOVW val3+20(FP), R5
MOVW $SYS_futex, R7
SWI $0
MOVW R0, ret+24(FP)
@@ -259,9 +258,9 @@ TEXT runtime·clone(SB),NOSPLIT,$0
// Copy mp, gp, fn off parent stack for use by child.
// TODO(kaib): figure out which registers are clobbered by clone and avoid stack copying
MOVW $-16(R1), R1
- MOVW mm+8(FP), R6
+ MOVW mp+8(FP), R6
MOVW R6, 0(R1)
- MOVW gg+12(FP), R6
+ MOVW gp+12(FP), R6
MOVW R6, 4(R1)
MOVW fn+16(FP), R6
MOVW R6, 8(R1)
@@ -366,7 +365,7 @@ TEXT runtime·cgoSigtramp(SB),NOSPLIT,$0
B (R11)
TEXT runtime·rtsigprocmask(SB),NOSPLIT,$0
- MOVW sig+0(FP), R0
+ MOVW how+0(FP), R0
MOVW new+4(FP), R1
MOVW old+8(FP), R2
MOVW size+12(FP), R3
@@ -491,7 +490,7 @@ TEXT runtime·access(SB),NOSPLIT,$0
TEXT runtime·connect(SB),NOSPLIT,$0
MOVW fd+0(FP), R0
MOVW addr+4(FP), R1
- MOVW addrlen+8(FP), R2
+ MOVW len+8(FP), R2
MOVW $SYS_connect, R7
SWI $0
MOVW R0, ret+12(FP)
@@ -499,8 +498,8 @@ TEXT runtime·connect(SB),NOSPLIT,$0
TEXT runtime·socket(SB),NOSPLIT,$0
MOVW domain+0(FP), R0
- MOVW type+4(FP), R1
- MOVW protocol+8(FP), R2
+ MOVW typ+4(FP), R1
+ MOVW prot+8(FP), R2
MOVW $SYS_socket, R7
SWI $0
MOVW R0, ret+12(FP)
diff --git a/src/runtime/sys_linux_arm64.s b/src/runtime/sys_linux_arm64.s
index 1bee847..1b91b44 100644
--- a/src/runtime/sys_linux_arm64.s
+++ b/src/runtime/sys_linux_arm64.s
@@ -184,14 +184,12 @@ TEXT runtime·mincore(SB),NOSPLIT,$-8-28
// func now() (sec int64, nsec int32)
TEXT time·now(SB),NOSPLIT,$24-12
- MOVD RSP, R0
- MOVD $0, R1
- MOVD $SYS_gettimeofday, R8
+ MOVW $0, R0 // CLOCK_REALTIME
+ MOVD RSP, R1
+ MOVD $SYS_clock_gettime, R8
SVC
MOVD 0(RSP), R3 // sec
- MOVD 8(RSP), R5 // usec
- MOVD $1000, R4
- MUL R4, R5
+ MOVD 8(RSP), R5 // nsec
MOVD R3, sec+0(FP)
MOVW R5, nsec+8(FP)
RET
@@ -212,7 +210,7 @@ TEXT runtime·nanotime(SB),NOSPLIT,$24-8
RET
TEXT runtime·rtsigprocmask(SB),NOSPLIT,$-8-28
- MOVW sig+0(FP), R0
+ MOVW how+0(FP), R0
MOVD new+8(FP), R1
MOVD old+16(FP), R2
MOVW size+24(FP), R3
@@ -319,8 +317,8 @@ TEXT runtime·clone(SB),NOSPLIT,$-8
MOVD stk+8(FP), R1
// Copy mp, gp, fn off parent stack for use by child.
- MOVD mm+16(FP), R10
- MOVD gg+24(FP), R11
+ MOVD mp+16(FP), R10
+ MOVD gp+24(FP), R11
MOVD fn+32(FP), R12
MOVD R10, -8(R1)
diff --git a/src/runtime/sys_linux_mips64x.s b/src/runtime/sys_linux_mips64x.s
index d4a81ca..5a75bb8 100644
--- a/src/runtime/sys_linux_mips64x.s
+++ b/src/runtime/sys_linux_mips64x.s
@@ -174,15 +174,12 @@ TEXT runtime·mincore(SB),NOSPLIT,$-8-28
// func now() (sec int64, nsec int32)
TEXT time·now(SB),NOSPLIT,$16
- MOVV $0(R29), R4
- MOVV $0, R5
- MOVV $SYS_gettimeofday, R2
+ MOVW $0, R4 // CLOCK_REALTIME
+ MOVV $0(R29), R5
+ MOVV $SYS_clock_gettime, R2
SYSCALL
MOVV 0(R29), R3 // sec
- MOVV 8(R29), R5 // usec
- MOVV $1000, R4
- MULVU R4, R5
- MOVV LO, R5
+ MOVV 8(R29), R5 // nsec
MOVV R3, sec+0(FP)
MOVW R5, nsec+8(FP)
RET
@@ -204,7 +201,7 @@ TEXT runtime·nanotime(SB),NOSPLIT,$16
RET
TEXT runtime·rtsigprocmask(SB),NOSPLIT,$-8-28
- MOVW sig+0(FP), R4
+ MOVW how+0(FP), R4
MOVV new+8(FP), R5
MOVV old+16(FP), R6
MOVW size+24(FP), R7
@@ -238,9 +235,6 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$64
SRLV $32, R31, RSB
SLLV $32, RSB
- // initialize essential registers (just in case)
- JAL runtime·reginit(SB)
-
// this might be called in external code context,
// where g is not set.
MOVB runtime·iscgo(SB), R1
@@ -309,8 +303,8 @@ TEXT runtime·clone(SB),NOSPLIT,$-8
// Copy mp, gp, fn off parent stack for use by child.
// Careful: Linux system call clobbers ???.
- MOVV mm+16(FP), R16
- MOVV gg+24(FP), R17
+ MOVV mp+16(FP), R16
+ MOVV gp+24(FP), R17
MOVV fn+32(FP), R18
MOVV R16, -8(R5)
@@ -328,8 +322,6 @@ TEXT runtime·clone(SB),NOSPLIT,$-8
RET
// In child, on new stack.
- // initialize essential registers
- JAL runtime·reginit(SB)
MOVV -32(R29), R16
MOVV $1234, R1
BEQ R16, R1, 2(PC)
diff --git a/src/runtime/sys_linux_mipsx.s b/src/runtime/sys_linux_mipsx.s
new file mode 100644
index 0000000..6f089f5
--- /dev/null
+++ b/src/runtime/sys_linux_mipsx.s
@@ -0,0 +1,467 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build linux
+// +build mips mipsle
+
+//
+// System calls and other sys.stuff for mips, Linux
+//
+
+#include "go_asm.h"
+#include "go_tls.h"
+#include "textflag.h"
+
+#define SYS_exit 4001
+#define SYS_read 4003
+#define SYS_write 4004
+#define SYS_open 4005
+#define SYS_close 4006
+#define SYS_getpid 4020
+#define SYS_kill 4037
+#define SYS_fcntl 4055
+#define SYS_gettimeofday 4078
+#define SYS_mmap 4090
+#define SYS_munmap 4091
+#define SYS_setitimer 4104
+#define SYS_clone 4120
+#define SYS_newselect 4142
+#define SYS_sched_yield 4162
+#define SYS_rt_sigreturn 4193
+#define SYS_rt_sigaction 4194
+#define SYS_rt_sigprocmask 4195
+#define SYS_sigaltstack 4206
+#define SYS_getrlimit 4076
+#define SYS_madvise 4218
+#define SYS_mincore 4217
+#define SYS_gettid 4222
+#define SYS_tkill 4236
+#define SYS_futex 4238
+#define SYS_sched_getaffinity 4240
+#define SYS_exit_group 4246
+#define SYS_epoll_create 4248
+#define SYS_epoll_ctl 4249
+#define SYS_epoll_wait 4250
+#define SYS_clock_gettime 4263
+#define SYS_epoll_create1 4326
+
+TEXT runtime·exit(SB),NOSPLIT,$0-4
+ MOVW code+0(FP), R4
+ MOVW $SYS_exit_group, R2
+ SYSCALL
+ UNDEF
+ RET
+
+TEXT runtime·exit1(SB),NOSPLIT,$0-4
+ MOVW code+0(FP), R4
+ MOVW $SYS_exit, R2
+ SYSCALL
+ UNDEF
+ RET
+
+TEXT runtime·open(SB),NOSPLIT,$0-16
+ MOVW name+0(FP), R4
+ MOVW mode+4(FP), R5
+ MOVW perm+8(FP), R6
+ MOVW $SYS_open, R2
+ SYSCALL
+ BEQ R7, 2(PC)
+ MOVW $-1, R2
+ MOVW R2, ret+12(FP)
+ RET
+
+TEXT runtime·closefd(SB),NOSPLIT,$0-8
+ MOVW fd+0(FP), R4
+ MOVW $SYS_close, R2
+ SYSCALL
+ BEQ R7, 2(PC)
+ MOVW $-1, R2
+ MOVW R2, ret+4(FP)
+ RET
+
+TEXT runtime·write(SB),NOSPLIT,$0-16
+ MOVW fd+0(FP), R4
+ MOVW p+4(FP), R5
+ MOVW n+8(FP), R6
+ MOVW $SYS_write, R2
+ SYSCALL
+ BEQ R7, 2(PC)
+ MOVW $-1, R2
+ MOVW R2, ret+12(FP)
+ RET
+
+TEXT runtime·read(SB),NOSPLIT,$0-16
+ MOVW fd+0(FP), R4
+ MOVW p+4(FP), R5
+ MOVW n+8(FP), R6
+ MOVW $SYS_read, R2
+ SYSCALL
+ BEQ R7, 2(PC)
+ MOVW $-1, R2
+ MOVW R2, ret+12(FP)
+ RET
+
+TEXT runtime·getrlimit(SB),NOSPLIT,$0-12
+ MOVW kind+0(FP), R4
+ MOVW limit+4(FP), R5
+ MOVW $SYS_getrlimit, R2
+ SYSCALL
+ MOVW R2, ret+8(FP)
+ RET
+
+TEXT runtime·usleep(SB),NOSPLIT,$28-4
+ MOVW usec+0(FP), R3
+ MOVW R3, R5
+ MOVW $1000000, R4
+ DIVU R4, R3
+ MOVW LO, R3
+ MOVW R3, 24(R29)
+ MULU R3, R4
+ MOVW LO, R4
+ SUBU R4, R5
+ MOVW R5, 28(R29)
+
+ // select(0, 0, 0, 0, &tv)
+ MOVW $0, R4
+ MOVW $0, R5
+ MOVW $0, R6
+ MOVW $0, R7
+ ADDU $24, R29, R8
+ MOVW R8, 16(R29)
+ MOVW $SYS_newselect, R2
+ SYSCALL
+ RET
+
+TEXT runtime·gettid(SB),NOSPLIT,$0-4
+ MOVW $SYS_gettid, R2
+ SYSCALL
+ MOVW R2, ret+0(FP)
+ RET
+
+TEXT runtime·raise(SB),NOSPLIT,$0-4
+ MOVW $SYS_gettid, R2
+ SYSCALL
+ MOVW R2, R4 // arg 1 tid
+ MOVW sig+0(FP), R5 // arg 2
+ MOVW $SYS_tkill, R2
+ SYSCALL
+ RET
+
+TEXT runtime·raiseproc(SB),NOSPLIT,$0
+ MOVW $SYS_getpid, R2
+ SYSCALL
+ MOVW R2, R4 // arg 1 pid
+ MOVW sig+0(FP), R5 // arg 2
+ MOVW $SYS_kill, R2
+ SYSCALL
+ RET
+
+TEXT runtime·setitimer(SB),NOSPLIT,$0-12
+ MOVW mode+0(FP), R4
+ MOVW new+4(FP), R5
+ MOVW old+8(FP), R6
+ MOVW $SYS_setitimer, R2
+ SYSCALL
+ RET
+
+TEXT runtime·mincore(SB),NOSPLIT,$0-16
+ MOVW addr+0(FP), R4
+ MOVW n+4(FP), R5
+ MOVW dst+8(FP), R6
+ MOVW $SYS_mincore, R2
+ SYSCALL
+ SUBU R2, R0, R2 // caller expects negative errno
+ MOVW R2, ret+12(FP)
+ RET
+
+// func now() (sec int64, nsec int32)
+TEXT time·now(SB),NOSPLIT,$8-12
+ MOVW $0, R4 // CLOCK_REALTIME
+ MOVW $4(R29), R5
+ MOVW $SYS_clock_gettime, R2
+ SYSCALL
+ MOVW 4(R29), R3 // sec
+ MOVW 8(R29), R5 // nsec
+#ifdef GOARCH_mips
+ MOVW R3, sec_lo+4(FP)
+ MOVW R0, sec_hi+0(FP)
+#else
+ MOVW R3, sec_lo+0(FP)
+ MOVW R0, sec_hi+4(FP)
+#endif
+ MOVW R5, nsec+8(FP)
+ RET
+
+TEXT runtime·nanotime(SB),NOSPLIT,$8-8
+ MOVW $1, R4 // CLOCK_MONOTONIC
+ MOVW $4(R29), R5
+ MOVW $SYS_clock_gettime, R2
+ SYSCALL
+ MOVW 4(R29), R3 // sec
+ MOVW 8(R29), R5 // nsec
+ // sec is in R3, nsec in R5
+ // return nsec in R3
+ MOVW $1000000000, R4
+ MULU R4, R3
+ MOVW LO, R3
+ ADDU R5, R3
+ SGTU R5, R3, R4
+#ifdef GOARCH_mips
+ MOVW R3, ret_lo+4(FP)
+#else
+ MOVW R3, ret_lo+0(FP)
+#endif
+ MOVW HI, R3
+ ADDU R4, R3
+#ifdef GOARCH_mips
+ MOVW R3, ret_hi+0(FP)
+#else
+ MOVW R3, ret_hi+4(FP)
+#endif
+ RET
+
+TEXT runtime·rtsigprocmask(SB),NOSPLIT,$0-16
+ MOVW how+0(FP), R4
+ MOVW new+4(FP), R5
+ MOVW old+8(FP), R6
+ MOVW size+12(FP), R7
+ MOVW $SYS_rt_sigprocmask, R2
+ SYSCALL
+ BEQ R7, 2(PC)
+ UNDEF // crash
+ RET
+
+TEXT runtime·rt_sigaction(SB),NOSPLIT,$0-20
+ MOVW sig+0(FP), R4
+ MOVW new+4(FP), R5
+ MOVW old+8(FP), R6
+ MOVW size+12(FP), R7
+ MOVW $SYS_rt_sigaction, R2
+ SYSCALL
+ MOVW R2, ret+16(FP)
+ RET
+
+TEXT runtime·sigfwd(SB),NOSPLIT,$0-16
+ MOVW sig+4(FP), R4
+ MOVW info+8(FP), R5
+ MOVW ctx+12(FP), R6
+ MOVW fn+0(FP), R25
+ MOVW R29, R22
+ SUBU $16, R29
+ AND $0x7, R29 // shadow space for 4 args aligned to 8 bytes as per O32 ABI
+ JAL (R25)
+ MOVW R22, R29
+ RET
+
+TEXT runtime·sigtramp(SB),NOSPLIT,$12
+ // this might be called in external code context,
+ // where g is not set.
+ MOVB runtime·iscgo(SB), R1
+ BEQ R1, 2(PC)
+ JAL runtime·load_g(SB)
+
+ MOVW R4, 4(R29)
+ MOVW R5, 8(R29)
+ MOVW R6, 12(R29)
+ MOVW $runtime·sigtrampgo(SB), R1
+ JAL (R1)
+ RET
+
+TEXT runtime·cgoSigtramp(SB),NOSPLIT,$0
+ JMP runtime·sigtramp(SB)
+
+TEXT runtime·mmap(SB),NOSPLIT,$20-28
+ MOVW addr+0(FP), R4
+ MOVW n+4(FP), R5
+ MOVW prot+8(FP), R6
+ MOVW flags+12(FP), R7
+ MOVW fd+16(FP), R8
+ MOVW off+20(FP), R9
+ MOVW R8, 16(R29)
+ MOVW R9, 20(R29)
+
+ MOVW $SYS_mmap, R2
+ SYSCALL
+ MOVW R2, ret+24(FP)
+ RET
+
+TEXT runtime·munmap(SB),NOSPLIT,$0-8
+ MOVW addr+0(FP), R4
+ MOVW n+4(FP), R5
+ MOVW $SYS_munmap, R2
+ SYSCALL
+ BEQ R7, 2(PC)
+ UNDEF // crash
+ RET
+
+TEXT runtime·madvise(SB),NOSPLIT,$0-12
+ MOVW addr+0(FP), R4
+ MOVW n+4(FP), R5
+ MOVW flags+8(FP), R6
+ MOVW $SYS_madvise, R2
+ SYSCALL
+ // ignore failure - maybe pages are locked
+ RET
+
+// int32 futex(int32 *uaddr, int32 op, int32 val, struct timespec *timeout, int32 *uaddr2, int32 val2);
+TEXT runtime·futex(SB),NOSPLIT,$20-28
+ MOVW addr+0(FP), R4
+ MOVW op+4(FP), R5
+ MOVW val+8(FP), R6
+ MOVW ts+12(FP), R7
+
+ MOVW addr2+16(FP), R8
+ MOVW val3+20(FP), R9
+
+ MOVW R8, 16(R29)
+ MOVW R9, 20(R29)
+
+ MOVW $SYS_futex, R2
+ SYSCALL
+ MOVW R2, ret+24(FP)
+ RET
+
+
+// int32 clone(int32 flags, void *stk, M *mm, G *gg, void (*fn)(void));
+TEXT runtime·clone(SB),NOSPLIT,$-4-24
+ MOVW flags+0(FP), R4
+ MOVW stk+4(FP), R5
+ MOVW R0, R6 // ptid
+ MOVW R0, R7 // tls
+
+ // O32 syscall handler unconditionally copies arguments 5-8 from stack,
+ // even for syscalls with less than 8 arguments. Reserve 32 bytes of new
+ // 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
+ MOVW fn+16(FP), R18
+
+ MOVW $1234, R1
+
+ MOVW R16, 0(R5)
+ MOVW R17, 4(R5)
+ MOVW R18, 8(R5)
+
+ MOVW R1, 12(R5)
+
+ MOVW $SYS_clone, R2
+ SYSCALL
+
+ // In parent, return.
+ BEQ R2, 5(PC)
+ SUBU R2, R0, R3
+ CMOVN R7, R3, R2
+ MOVW R2, ret+20(FP)
+ RET
+
+ // In child, on new stack.
+ // Check that SP is as we expect
+ MOVW 12(R29), R16
+ MOVW $1234, R1
+ BEQ R16, R1, 2(PC)
+ MOVW (R0), R0
+
+ // Initialize m->procid to Linux tid
+ MOVW $SYS_gettid, R2
+ SYSCALL
+
+ MOVW 0(R29), R16 // m
+ MOVW 4(R29), R17 // g
+ MOVW 8(R29), R18 // fn
+
+ BEQ R16, nog
+ BEQ R17, nog
+
+ MOVW R2, m_procid(R16)
+
+ // In child, set up new stack
+ MOVW R16, g_m(R17)
+ MOVW R17, g
+
+// TODO(mips32): doesn't have runtime·stackcheck(SB)
+
+nog:
+ // Call fn
+ ADDU $32, R29
+ JAL (R18)
+
+ // It shouldn't return. If it does, exit that thread.
+ ADDU $-32, R29
+ MOVW $0xf4, R4
+ MOVW $SYS_exit, R2
+ SYSCALL
+ UNDEF
+
+TEXT runtime·sigaltstack(SB),NOSPLIT,$0
+ MOVW new+0(FP), R4
+ MOVW old+4(FP), R5
+ MOVW $SYS_sigaltstack, R2
+ SYSCALL
+ BEQ R7, 2(PC)
+ UNDEF // crash
+ RET
+
+TEXT runtime·osyield(SB),NOSPLIT,$0
+ MOVW $SYS_sched_yield, R2
+ SYSCALL
+ RET
+
+TEXT runtime·sched_getaffinity(SB),NOSPLIT,$0-16
+ MOVW pid+0(FP), R4
+ MOVW len+4(FP), R5
+ MOVW buf+8(FP), R6
+ MOVW $SYS_sched_getaffinity, R2
+ SYSCALL
+ MOVW R2, ret+12(FP)
+ RET
+
+// int32 runtime·epollcreate(int32 size);
+TEXT runtime·epollcreate(SB),NOSPLIT,$0-8
+ MOVW size+0(FP), R4
+ MOVW $SYS_epoll_create, R2
+ SYSCALL
+ MOVW R2, ret+4(FP)
+ RET
+
+// int32 runtime·epollcreate1(int32 flags);
+TEXT runtime·epollcreate1(SB),NOSPLIT,$0-8
+ MOVW flags+0(FP), R4
+ MOVW $SYS_epoll_create1, R2
+ SYSCALL
+ MOVW R2, ret+4(FP)
+ RET
+
+// func epollctl(epfd, op, fd int32, ev *epollEvent) int
+TEXT runtime·epollctl(SB),NOSPLIT,$0-20
+ MOVW epfd+0(FP), R4
+ MOVW op+4(FP), R5
+ MOVW fd+8(FP), R6
+ MOVW ev+12(FP), R7
+ MOVW $SYS_epoll_ctl, R2
+ SYSCALL
+ MOVW R2, ret+16(FP)
+ RET
+
+// int32 runtime·epollwait(int32 epfd, EpollEvent *ev, int32 nev, int32 timeout);
+TEXT runtime·epollwait(SB),NOSPLIT,$0-20
+ MOVW epfd+0(FP), R4
+ MOVW ev+4(FP), R5
+ MOVW nev+8(FP), R6
+ MOVW timeout+12(FP), R7
+ MOVW $SYS_epoll_wait, R2
+ SYSCALL
+ MOVW R2, ret+16(FP)
+ RET
+
+// void runtime·closeonexec(int32 fd);
+TEXT runtime·closeonexec(SB),NOSPLIT,$0-4
+ MOVW fd+0(FP), R4 // fd
+ MOVW $2, R5 // F_SETFD
+ MOVW $1, R6 // FD_CLOEXEC
+ MOVW $SYS_fcntl, R2
+ SYSCALL
+ RET
diff --git a/src/runtime/sys_linux_ppc64x.s b/src/runtime/sys_linux_ppc64x.s
index 56b842a..a40fe3b 100644
--- a/src/runtime/sys_linux_ppc64x.s
+++ b/src/runtime/sys_linux_ppc64x.s
@@ -159,13 +159,11 @@ TEXT runtime·mincore(SB),NOSPLIT|NOFRAME,$0-28
// func now() (sec int64, nsec int32)
TEXT time·now(SB),NOSPLIT,$16
- MOVD $0(R1), R3
- MOVD $0, R4
- SYSCALL $SYS_gettimeofday
+ MOVD $0, R3 // CLOCK_REALTIME
+ MOVD $0(R1), R4
+ SYSCALL $SYS_clock_gettime
MOVD 0(R1), R3 // sec
- MOVD 8(R1), R5 // usec
- MOVD $1000, R4
- MULLD R4, R5
+ MOVD 8(R1), R5 // nsec
MOVD R3, sec+0(FP)
MOVW R5, nsec+8(FP)
RET
@@ -185,7 +183,7 @@ TEXT runtime·nanotime(SB),NOSPLIT,$16
RET
TEXT runtime·rtsigprocmask(SB),NOSPLIT|NOFRAME,$0-28
- MOVW sig+0(FP), R3
+ MOVW how+0(FP), R3
MOVD new+8(FP), R4
MOVD old+16(FP), R5
MOVW size+24(FP), R6
@@ -306,8 +304,8 @@ TEXT runtime·clone(SB),NOSPLIT|NOFRAME,$0
// Copy mp, gp, fn off parent stack for use by child.
// Careful: Linux system call clobbers ???.
- MOVD mm+16(FP), R7
- MOVD gg+24(FP), R8
+ MOVD mp+16(FP), R7
+ MOVD gp+24(FP), R8
MOVD fn+32(FP), R12
MOVD R7, -8(R4)
diff --git a/src/runtime/sys_linux_s390x.s b/src/runtime/sys_linux_s390x.s
index f43792b..47f34d9 100644
--- a/src/runtime/sys_linux_s390x.s
+++ b/src/runtime/sys_linux_s390x.s
@@ -171,35 +171,31 @@ TEXT runtime·mincore(SB),NOSPLIT|NOFRAME,$0-28
// func now() (sec int64, nsec int32)
TEXT time·now(SB),NOSPLIT,$16
- MOVD $0(R15), R2
- MOVD $0, R3
- MOVW $SYS_gettimeofday, R1
- SYSCALL
- MOVD 0(R15), R2 // sec
- MOVD 8(R15), R4 // usec
- MOVD $1000, R3
- MULLD R3, R4
+ MOVW $0, R2 // CLOCK_REALTIME
+ MOVD $tp-16(SP), R3
+ MOVW $SYS_clock_gettime, R1
+ SYSCALL
+ LMG tp-16(SP), R2, R3
+ // sec is in R2, nsec in R3
MOVD R2, sec+0(FP)
- MOVW R4, nsec+8(FP)
+ MOVW R3, nsec+8(FP)
RET
TEXT runtime·nanotime(SB),NOSPLIT,$16
MOVW $1, R2 // CLOCK_MONOTONIC
- MOVD $0(R15), R3
+ MOVD $tp-16(SP), R3
MOVW $SYS_clock_gettime, R1
SYSCALL
- MOVD 0(R15), R2 // sec
- MOVD 8(R15), R4 // nsec
- // sec is in R2, nsec in R4
+ LMG tp-16(SP), R2, R3
+ // sec is in R2, nsec in R3
// return nsec in R2
- MOVD $1000000000, R3
- MULLD R3, R2
- ADD R4, R2
+ MULLD $1000000000, R2
+ ADD R3, R2
MOVD R2, ret+0(FP)
RET
TEXT runtime·rtsigprocmask(SB),NOSPLIT|NOFRAME,$0-28
- MOVW sig+0(FP), R2
+ MOVW how+0(FP), R2
MOVD new+8(FP), R3
MOVD old+16(FP), R4
MOVW size+24(FP), R5
@@ -315,8 +311,8 @@ TEXT runtime·clone(SB),NOSPLIT|NOFRAME,$0
// Copy mp, gp, fn off parent stack for use by child.
// Careful: Linux system call clobbers ???.
- MOVD mm+16(FP), R7
- MOVD gg+24(FP), R8
+ MOVD mp+16(FP), R7
+ MOVD gp+24(FP), R8
MOVD fn+32(FP), R9
MOVD R7, -8(R2)
diff --git a/src/runtime/sys_mips64x.go b/src/runtime/sys_mips64x.go
index 9e7d805..cb429c3 100644
--- a/src/runtime/sys_mips64x.go
+++ b/src/runtime/sys_mips64x.go
@@ -18,26 +18,3 @@ func gostartcall(buf *gobuf, fn, ctxt unsafe.Pointer) {
buf.pc = uintptr(fn)
buf.ctxt = ctxt
}
-
-// Called to rewind context saved during morestack back to beginning of function.
-// To help us, the linker emits a jmp back to the beginning right after the
-// call to morestack. We just have to decode and apply that jump.
-func rewindmorestack(buf *gobuf) {
- var inst uint32
- if buf.pc&3 == 0 && buf.pc != 0 {
- inst = *(*uint32)(unsafe.Pointer(buf.pc))
- if inst>>26 == 2 { // JMP addr
- //print("runtime: rewind pc=", hex(buf.pc), " to pc=", hex(buf.pc &^ uintptr(1<<28-1) | uintptr((inst&^0xfc000000)<<2)), "\n");
- buf.pc &^= 1<<28 - 1
- buf.pc |= uintptr((inst &^ 0xfc000000) << 2)
- return
- }
- if inst>>16 == 0x1000 { // BEQ R0, R0, offset
- //print("runtime: rewind pc=", hex(buf.pc), " to pc=", hex(buf.pc + uintptr(int32(int16(inst&0xffff))<<2 + 4)), "\n");
- buf.pc += uintptr(int32(int16(inst&0xffff))<<2 + 4)
- return
- }
- }
- print("runtime: pc=", hex(buf.pc), " ", hex(inst), "\n")
- throw("runtime: misuse of rewindmorestack")
-}
diff --git a/src/runtime/sys_mipsx.go b/src/runtime/sys_mipsx.go
new file mode 100644
index 0000000..2819218
--- /dev/null
+++ b/src/runtime/sys_mipsx.go
@@ -0,0 +1,20 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build mips mipsle
+
+package runtime
+
+import "unsafe"
+
+// adjust Gobuf as if it executed a call to fn with context ctxt
+// and then did an immediate Gosave.
+func gostartcall(buf *gobuf, fn, ctxt unsafe.Pointer) {
+ if buf.lr != 0 {
+ throw("invalid use of gostartcall")
+ }
+ buf.lr = buf.pc
+ buf.pc = uintptr(fn)
+ buf.ctxt = ctxt
+}
diff --git a/src/runtime/sys_nacl_386.s b/src/runtime/sys_nacl_386.s
index e69a0b7..05de20c 100644
--- a/src/runtime/sys_nacl_386.s
+++ b/src/runtime/sys_nacl_386.s
@@ -368,9 +368,9 @@ ret:
// func getRandomData([]byte)
TEXT runtime·getRandomData(SB),NOSPLIT,$8-12
- MOVL buf+0(FP), AX
+ MOVL arg_base+0(FP), AX
MOVL AX, 0(SP)
- MOVL len+4(FP), AX
+ MOVL arg_len+4(FP), AX
MOVL AX, 4(SP)
NACL_SYSCALL(SYS_get_random_bytes)
RET
diff --git a/src/runtime/sys_nacl_amd64p32.s b/src/runtime/sys_nacl_amd64p32.s
index 0b29c9f..c2a24e8 100644
--- a/src/runtime/sys_nacl_amd64p32.s
+++ b/src/runtime/sys_nacl_amd64p32.s
@@ -414,8 +414,8 @@ MOVL $1, DI; NACL_SYSCALL(SYS_exit)
// func getRandomData([]byte)
TEXT runtime·getRandomData(SB),NOSPLIT,$0-12
- MOVL buf+0(FP), DI
- MOVL len+4(FP), SI
+ MOVL arg_base+0(FP), DI
+ MOVL arg_len+4(FP), SI
NACL_SYSCALL(SYS_get_random_bytes)
RET
diff --git a/src/runtime/sys_nacl_arm.s b/src/runtime/sys_nacl_arm.s
index 474d9fe..6cbc23f 100644
--- a/src/runtime/sys_nacl_arm.s
+++ b/src/runtime/sys_nacl_arm.s
@@ -303,8 +303,8 @@ TEXT runtime·nacl_sysinfo(SB),NOSPLIT,$16
// func getRandomData([]byte)
TEXT runtime·getRandomData(SB),NOSPLIT,$0-12
- MOVW buf+0(FP), R0
- MOVW len+4(FP), R1
+ MOVW arg_base+0(FP), R0
+ MOVW arg_len+4(FP), R1
NACL_SYSCALL(SYS_get_random_bytes)
RET
diff --git a/src/runtime/sys_netbsd_386.s b/src/runtime/sys_netbsd_386.s
index 0322c36..50d35e5 100644
--- a/src/runtime/sys_netbsd_386.s
+++ b/src/runtime/sys_netbsd_386.s
@@ -216,14 +216,20 @@ TEXT runtime·sigaction(SB),NOSPLIT,$24
RET
TEXT runtime·sigfwd(SB),NOSPLIT,$12-16
- MOVL sig+4(FP), AX
- MOVL AX, 0(SP)
- MOVL info+8(FP), AX
- MOVL AX, 4(SP)
- MOVL ctx+12(FP), AX
- MOVL AX, 8(SP)
MOVL fn+0(FP), AX
+ MOVL sig+4(FP), BX
+ MOVL info+8(FP), CX
+ MOVL ctx+12(FP), DX
+ MOVL SP, SI
+ SUBL $32, SP
+ ANDL $-15, SP // align stack: handler might be a C function
+ MOVL BX, 0(SP)
+ MOVL CX, 4(SP)
+ MOVL DX, 8(SP)
+ MOVL SI, 12(SP) // save SI: handler might be a Go function
CALL AX
+ MOVL 12(SP), AX
+ MOVL AX, SP
RET
TEXT runtime·sigtramp(SB),NOSPLIT,$12
@@ -285,8 +291,8 @@ TEXT runtime·lwp_tramp(SB),NOSPLIT,$0
TEXT runtime·sigaltstack(SB),NOSPLIT,$-8
MOVL $281, AX // sys___sigaltstack14
- MOVL new+4(SP), BX
- MOVL old+8(SP), CX
+ MOVL new+0(FP), BX
+ MOVL old+4(FP), CX
INT $0x80
CMPL AX, $0xfffff001
JLS 2(PC)
diff --git a/src/runtime/sys_netbsd_amd64.s b/src/runtime/sys_netbsd_amd64.s
index d6b5d35..2c50adb 100644
--- a/src/runtime/sys_netbsd_amd64.s
+++ b/src/runtime/sys_netbsd_amd64.s
@@ -207,7 +207,7 @@ TEXT runtime·getcontext(SB),NOSPLIT,$-8
RET
TEXT runtime·sigprocmask(SB),NOSPLIT,$0
- MOVL mode+0(FP), DI // arg 1 - how
+ MOVL how+0(FP), DI // arg 1 - how
MOVQ new+8(FP), SI // arg 2 - set
MOVQ old+16(FP), DX // arg 3 - oset
MOVL $293, AX // sys_sigprocmask
@@ -238,11 +238,16 @@ TEXT runtime·sigaction(SB),NOSPLIT,$-8
RET
TEXT runtime·sigfwd(SB),NOSPLIT,$0-32
- MOVL sig+8(FP), DI
+ MOVQ fn+0(FP), AX
+ MOVL sig+8(FP), DI
MOVQ info+16(FP), SI
- MOVQ ctx+24(FP), DX
- MOVQ fn+0(FP), AX
+ MOVQ ctx+24(FP), DX
+ PUSHQ BP
+ MOVQ SP, BP
+ ANDQ $~15, SP // alignment for x86_64 ABI
CALL AX
+ MOVQ BP, SP
+ POPQ BP
RET
TEXT runtime·sigtramp(SB),NOSPLIT,$32
@@ -290,8 +295,8 @@ TEXT runtime·madvise(SB),NOSPLIT,$0
RET
TEXT runtime·sigaltstack(SB),NOSPLIT,$-8
- MOVQ new+8(SP), DI // arg 1 - nss
- MOVQ old+16(SP), SI // arg 2 - oss
+ MOVQ new+0(FP), DI // arg 1 - nss
+ MOVQ old+8(FP), SI // arg 2 - oss
MOVQ $281, AX // sys___sigaltstack14
SYSCALL
JCC 2(PC)
@@ -337,11 +342,11 @@ TEXT runtime·kqueue(SB),NOSPLIT,$0
// int32 runtime·kevent(int kq, Kevent *changelist, int nchanges, Kevent *eventlist, int nevents, Timespec *timeout)
TEXT runtime·kevent(SB),NOSPLIT,$0
- MOVL fd+0(FP), DI
- MOVQ ev1+8(FP), SI
- MOVL nev1+16(FP), DX
- MOVQ ev2+24(FP), R10
- MOVL nev2+32(FP), R8
+ MOVL kq+0(FP), DI
+ MOVQ ch+8(FP), SI
+ MOVL nch+16(FP), DX
+ MOVQ ev+24(FP), R10
+ MOVL nev+32(FP), R8
MOVQ ts+40(FP), R9
MOVL $435, AX
SYSCALL
diff --git a/src/runtime/sys_netbsd_arm.s b/src/runtime/sys_netbsd_arm.s
index 3d3b65f..a8914c1 100644
--- a/src/runtime/sys_netbsd_arm.s
+++ b/src/runtime/sys_netbsd_arm.s
@@ -181,7 +181,7 @@ TEXT runtime·getcontext(SB),NOSPLIT,$-4
RET
TEXT runtime·sigprocmask(SB),NOSPLIT,$0
- MOVW mode+0(FP), R0 // arg 1 - how
+ MOVW how+0(FP), R0 // arg 1 - how
MOVW new+4(FP), R1 // arg 2 - set
MOVW old+8(FP), R2 // arg 3 - oset
SWI $0xa00125 // sys_sigprocmask
diff --git a/src/runtime/sys_openbsd_386.s b/src/runtime/sys_openbsd_386.s
index 2bb818f..e969395 100644
--- a/src/runtime/sys_openbsd_386.s
+++ b/src/runtime/sys_openbsd_386.s
@@ -187,7 +187,7 @@ TEXT runtime·sigaction(SB),NOSPLIT,$-4
MOVL $0xf1, 0xf1 // crash
RET
-TEXT runtime·sigprocmask(SB),NOSPLIT,$-4
+TEXT runtime·obsdsigprocmask(SB),NOSPLIT,$-4
MOVL $48, AX // sys_sigprocmask
INT $0x80
JAE 2(PC)
@@ -196,14 +196,20 @@ TEXT runtime·sigprocmask(SB),NOSPLIT,$-4
RET
TEXT runtime·sigfwd(SB),NOSPLIT,$12-16
- MOVL sig+4(FP), AX
- MOVL AX, 0(SP)
- MOVL info+8(FP), AX
- MOVL AX, 4(SP)
- MOVL ctx+12(FP), AX
- MOVL AX, 8(SP)
MOVL fn+0(FP), AX
+ MOVL sig+4(FP), BX
+ MOVL info+8(FP), CX
+ MOVL ctx+12(FP), DX
+ MOVL SP, SI
+ SUBL $32, SP
+ ANDL $~15, SP // align stack: handler might be a C function
+ MOVL BX, 0(SP)
+ MOVL CX, 4(SP)
+ MOVL DX, 8(SP)
+ MOVL SI, 12(SP) // save SI: handler might be a Go function
CALL AX
+ MOVL 12(SP), AX
+ MOVL AX, SP
RET
TEXT runtime·sigtramp(SB),NOSPLIT,$12
@@ -294,8 +300,8 @@ TEXT runtime·tfork(SB),NOSPLIT,$12
TEXT runtime·sigaltstack(SB),NOSPLIT,$-8
MOVL $288, AX // sys_sigaltstack
- MOVL new+4(SP), BX
- MOVL old+8(SP), CX
+ MOVL new+0(FP), BX
+ MOVL old+4(FP), CX
INT $0x80
CMPL AX, $0xfffff001
JLS 2(PC)
diff --git a/src/runtime/sys_openbsd_amd64.s b/src/runtime/sys_openbsd_amd64.s
index c9fb832..01d6bd8 100644
--- a/src/runtime/sys_openbsd_amd64.s
+++ b/src/runtime/sys_openbsd_amd64.s
@@ -218,8 +218,8 @@ TEXT runtime·sigaction(SB),NOSPLIT,$-8
MOVL $0xf1, 0xf1 // crash
RET
-TEXT runtime·sigprocmask(SB),NOSPLIT,$0
- MOVL mode+0(FP), DI // arg 1 - how
+TEXT runtime·obsdsigprocmask(SB),NOSPLIT,$0
+ MOVL how+0(FP), DI // arg 1 - how
MOVL new+4(FP), SI // arg 2 - set
MOVL $48, AX // sys_sigprocmask
SYSCALL
@@ -229,11 +229,16 @@ TEXT runtime·sigprocmask(SB),NOSPLIT,$0
RET
TEXT runtime·sigfwd(SB),NOSPLIT,$0-32
- MOVL sig+8(FP), DI
+ MOVQ fn+0(FP), AX
+ MOVL sig+8(FP), DI
MOVQ info+16(FP), SI
- MOVQ ctx+24(FP), DX
- MOVQ fn+0(FP), AX
+ MOVQ ctx+24(FP), DX
+ PUSHQ BP
+ MOVQ SP, BP
+ ANDQ $~15, SP // alignment for x86_64 ABI
CALL AX
+ MOVQ BP, SP
+ POPQ BP
RET
TEXT runtime·sigtramp(SB),NOSPLIT,$24
@@ -278,8 +283,8 @@ TEXT runtime·madvise(SB),NOSPLIT,$0
RET
TEXT runtime·sigaltstack(SB),NOSPLIT,$-8
- MOVQ new+8(SP), DI // arg 1 - nss
- MOVQ old+16(SP), SI // arg 2 - oss
+ MOVQ new+0(FP), DI // arg 1 - nss
+ MOVQ old+8(FP), SI // arg 2 - oss
MOVQ $288, AX // sys_sigaltstack
SYSCALL
JCC 2(PC)
@@ -327,11 +332,11 @@ TEXT runtime·kqueue(SB),NOSPLIT,$0
// int32 runtime·kevent(int kq, Kevent *changelist, int nchanges, Kevent *eventlist, int nevents, Timespec *timeout);
TEXT runtime·kevent(SB),NOSPLIT,$0
- MOVL fd+0(FP), DI
- MOVQ ev1+8(FP), SI
- MOVL nev1+16(FP), DX
- MOVQ ev2+24(FP), R10
- MOVL nev2+32(FP), R8
+ MOVL kq+0(FP), DI
+ MOVQ ch+8(FP), SI
+ MOVL nch+16(FP), DX
+ MOVQ ev+24(FP), R10
+ MOVL nev+32(FP), R8
MOVQ ts+40(FP), R9
MOVL $72, AX
SYSCALL
diff --git a/src/runtime/sys_openbsd_arm.s b/src/runtime/sys_openbsd_arm.s
index 29e8971..e0f775d 100644
--- a/src/runtime/sys_openbsd_arm.s
+++ b/src/runtime/sys_openbsd_arm.s
@@ -15,7 +15,7 @@
// Exit the entire program (like C exit)
TEXT runtime·exit(SB),NOSPLIT,$-4
- MOVW status+0(FP), R0 // arg 1 - status
+ MOVW code+0(FP), R0 // arg 1 - status
MOVW $1, R12 // sys_exit
SWI $0
MOVW.CS $0, R8 // crash on syscall failure
@@ -31,9 +31,9 @@ TEXT runtime·exit1(SB),NOSPLIT,$-4
RET
TEXT runtime·open(SB),NOSPLIT,$-4
- MOVW path+0(FP), R0 // arg 1 - path
- MOVW flags+4(FP), R1 // arg 2 - flags
- MOVW mode+8(FP), R2 // arg 3 - mode
+ MOVW name+0(FP), R0 // arg 1 - path
+ MOVW mode+4(FP), R1 // arg 2 - mode
+ MOVW perm+8(FP), R2 // arg 3 - perm
MOVW $5, R12 // sys_open
SWI $0
MOVW.CS $-1, R0
@@ -41,7 +41,7 @@ TEXT runtime·open(SB),NOSPLIT,$-4
RET
TEXT runtime·closefd(SB),NOSPLIT,$-4
- MOVW path+0(FP), R0 // arg 1 - path
+ MOVW fd+0(FP), R0 // arg 1 - fd
MOVW $6, R12 // sys_close
SWI $0
MOVW.CS $-1, R0
@@ -50,8 +50,8 @@ TEXT runtime·closefd(SB),NOSPLIT,$-4
TEXT runtime·read(SB),NOSPLIT,$-4
MOVW fd+0(FP), R0 // arg 1 - fd
- MOVW buf+4(FP), R1 // arg 2 - buf
- MOVW nbyte+8(FP), R2 // arg 3 - nbyte
+ MOVW p+4(FP), R1 // arg 2 - buf
+ MOVW n+8(FP), R2 // arg 3 - nbyte
MOVW $3, R12 // sys_read
SWI $0
MOVW.CS $-1, R0
@@ -60,8 +60,8 @@ TEXT runtime·read(SB),NOSPLIT,$-4
TEXT runtime·write(SB),NOSPLIT,$-4
MOVW fd+0(FP), R0 // arg 1 - fd
- MOVW buf+4(FP), R1 // arg 2 - buf
- MOVW nbyte+8(FP), R2 // arg 3 - nbyte
+ MOVW p+4(FP), R1 // arg 2 - buf
+ MOVW n+8(FP), R2 // arg 3 - nbyte
MOVW $4, R12 // sys_write
SWI $0
MOVW.CS $-1, R0
@@ -104,14 +104,14 @@ TEXT runtime·raiseproc(SB),NOSPLIT,$12
TEXT runtime·mmap(SB),NOSPLIT,$16
MOVW addr+0(FP), R0 // arg 1 - addr
- MOVW len+4(FP), R1 // arg 2 - len
+ MOVW n+4(FP), R1 // arg 2 - len
MOVW prot+8(FP), R2 // arg 3 - prot
MOVW flags+12(FP), R3 // arg 4 - flags
MOVW fd+16(FP), R4 // arg 5 - fd (on stack)
MOVW R4, 4(R13)
MOVW $0, R5 // arg 6 - pad (on stack)
MOVW R5, 8(R13)
- MOVW offset+20(FP), R6 // arg 7 - offset (on stack)
+ MOVW off+20(FP), R6 // arg 7 - offset (on stack)
MOVW R6, 12(R13) // lower 32 bits (from Go runtime)
MOVW $0, R7
MOVW R7, 16(R13) // high 32 bits
@@ -124,7 +124,7 @@ TEXT runtime·mmap(SB),NOSPLIT,$16
TEXT runtime·munmap(SB),NOSPLIT,$0
MOVW addr+0(FP), R0 // arg 1 - addr
- MOVW len+4(FP), R1 // arg 2 - len
+ MOVW n+4(FP), R1 // arg 2 - len
MOVW $73, R12 // sys_munmap
SWI $0
MOVW.CS $0, R8 // crash on syscall failure
@@ -133,8 +133,8 @@ TEXT runtime·munmap(SB),NOSPLIT,$0
TEXT runtime·madvise(SB),NOSPLIT,$0
MOVW addr+0(FP), R0 // arg 1 - addr
- MOVW len+4(FP), R1 // arg 2 - len
- MOVW behav+8(FP), R2 // arg 2 - behav
+ MOVW n+4(FP), R1 // arg 2 - len
+ MOVW flags+8(FP), R2 // arg 2 - flags
MOVW $75, R12 // sys_madvise
SWI $0
MOVW.CS $0, R8 // crash on syscall failure
@@ -142,9 +142,9 @@ TEXT runtime·madvise(SB),NOSPLIT,$0
RET
TEXT runtime·setitimer(SB),NOSPLIT,$0
- MOVW which+0(FP), R0 // arg 1 - which
- MOVW value+4(FP), R1 // arg 2 - value
- MOVW ovalue+8(FP), R2 // arg 3 - ovalue
+ MOVW mode+0(FP), R0 // arg 1 - mode
+ MOVW new+4(FP), R1 // arg 2 - new value
+ MOVW old+8(FP), R2 // arg 3 - old value
MOVW $69, R12 // sys_setitimer
SWI $0
RET
@@ -189,18 +189,18 @@ TEXT runtime·nanotime(SB),NOSPLIT,$32
RET
TEXT runtime·sigaction(SB),NOSPLIT,$0
- MOVW signum+0(FP), R0 // arg 1 - signum
- MOVW nsa+4(FP), R1 // arg 2 - nsa
- MOVW osa+8(FP), R2 // arg 3 - osa
+ MOVW sig+0(FP), R0 // arg 1 - signum
+ MOVW new+4(FP), R1 // arg 2 - new sigaction
+ MOVW old+8(FP), R2 // arg 3 - old sigaction
MOVW $46, R12 // sys_sigaction
SWI $0
MOVW.CS $3, R8 // crash on syscall failure
MOVW.CS R8, (R8)
RET
-TEXT runtime·sigprocmask(SB),NOSPLIT,$0
- MOVW how+0(FP), R0 // arg 1 - how
- MOVW mask+4(FP), R1 // arg 2 - mask
+TEXT runtime·obsdsigprocmask(SB),NOSPLIT,$0
+ MOVW how+0(FP), R0 // arg 1 - mode
+ MOVW new+4(FP), R1 // arg 2 - new
MOVW $48, R12 // sys_sigprocmask
SWI $0
MOVW.CS $3, R8 // crash on syscall failure
@@ -274,8 +274,8 @@ TEXT runtime·tfork(SB),NOSPLIT,$0
RET
TEXT runtime·sigaltstack(SB),NOSPLIT,$0
- MOVW nss+0(FP), R0 // arg 1 - nss
- MOVW oss+4(FP), R1 // arg 2 - oss
+ MOVW new+0(FP), R0 // arg 1 - new sigaltstack
+ MOVW old+4(FP), R1 // arg 2 - old sigaltstack
MOVW $288, R12 // sys_sigaltstack
SWI $0
MOVW.CS $0, R8 // crash on syscall failure
@@ -290,7 +290,7 @@ TEXT runtime·osyield(SB),NOSPLIT,$0
TEXT runtime·thrsleep(SB),NOSPLIT,$4
MOVW ident+0(FP), R0 // arg 1 - ident
MOVW clock_id+4(FP), R1 // arg 2 - clock_id
- MOVW tp+8(FP), R2 // arg 3 - tp
+ MOVW tsp+8(FP), R2 // arg 3 - tsp
MOVW lock+12(FP), R3 // arg 4 - lock
MOVW abort+16(FP), R4 // arg 5 - abort (on stack)
MOVW R4, 4(R13)
@@ -310,13 +310,13 @@ TEXT runtime·thrwakeup(SB),NOSPLIT,$0
RET
TEXT runtime·sysctl(SB),NOSPLIT,$8
- MOVW name+0(FP), R0 // arg 1 - name
- MOVW namelen+4(FP), R1 // arg 2 - namelen
- MOVW oldp+8(FP), R2 // arg 3 - oldp
- MOVW oldlenp+12(FP), R3 // arg 4 - oldlenp
- MOVW newp+16(FP), R4 // arg 5 - newp (on stack)
+ MOVW mib+0(FP), R0 // arg 1 - mib
+ MOVW miblen+4(FP), R1 // arg 2 - miblen
+ MOVW out+8(FP), R2 // arg 3 - out
+ MOVW size+12(FP), R3 // arg 4 - size
+ MOVW dst+16(FP), R4 // arg 5 - dest (on stack)
MOVW R4, 4(R13)
- MOVW newlen+20(FP), R5 // arg 6 - newlen (on stack)
+ MOVW ndst+20(FP), R5 // arg 6 - newlen (on stack)
MOVW R5, 8(R13)
ADD $4, R13
MOVW $202, R12 // sys___sysctl
@@ -337,13 +337,13 @@ TEXT runtime·kqueue(SB),NOSPLIT,$0
// int32 runtime·kevent(int kq, Kevent *changelist, int nchanges, Kevent *eventlist, int nevents, Timespec *timeout);
TEXT runtime·kevent(SB),NOSPLIT,$8
- MOVW fd+0(FP), R0 // arg 1 - fd
- MOVW changelist+4(FP), R1 // arg 2 - changelist
- MOVW nchanges+8(FP), R2 // arg 3 - nchanges
- MOVW eventlist+12(FP), R3 // arg 4 - eventlist
- MOVW nevents+16(FP), R4 // arg 5 - nevents (on stack)
+ MOVW kq+0(FP), R0 // arg 1 - kq
+ MOVW ch+4(FP), R1 // arg 2 - changelist
+ MOVW nch+8(FP), R2 // arg 3 - nchanges
+ MOVW ev+12(FP), R3 // arg 4 - eventlist
+ MOVW nev+16(FP), R4 // arg 5 - nevents (on stack)
MOVW R4, 4(R13)
- MOVW timeout+20(FP), R5 // arg 6 - timeout (on stack)
+ MOVW ts+20(FP), R5 // arg 6 - timeout (on stack)
MOVW R5, 8(R13)
ADD $4, R13
MOVW $72, R12 // sys_kevent
@@ -353,15 +353,13 @@ TEXT runtime·kevent(SB),NOSPLIT,$8
MOVW R0, ret+24(FP)
RET
-// int32 runtime·closeonexec(int32 fd);
+// func closeonexec(fd int32)
TEXT runtime·closeonexec(SB),NOSPLIT,$0
MOVW fd+0(FP), R0 // arg 1 - fd
MOVW $2, R1 // arg 2 - cmd (F_SETFD)
MOVW $1, R2 // arg 3 - arg (FD_CLOEXEC)
MOVW $92, R12 // sys_fcntl
SWI $0
- RSB.CS $0, R0
- MOVW R0, ret+4(FP)
RET
TEXT ·publicationBarrier(SB),NOSPLIT,$-4-0
diff --git a/src/runtime/sys_plan9_386.s b/src/runtime/sys_plan9_386.s
index 1af3cb1..41aa2fd 100644
--- a/src/runtime/sys_plan9_386.s
+++ b/src/runtime/sys_plan9_386.s
@@ -178,8 +178,8 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$0
RET
// save args
- MOVL ureg+4(SP), CX
- MOVL note+8(SP), DX
+ MOVL ureg+0(FP), CX
+ MOVL note+4(FP), DX
// change stack
MOVL g_m(BX), BX
diff --git a/src/runtime/sys_plan9_amd64.s b/src/runtime/sys_plan9_amd64.s
index 1492ef2..149505f 100644
--- a/src/runtime/sys_plan9_amd64.s
+++ b/src/runtime/sys_plan9_amd64.s
@@ -65,7 +65,7 @@ TEXT runtime·exits(SB),NOSPLIT,$0
TEXT runtime·brk_(SB),NOSPLIT,$0
MOVQ $24, BP
SYSCALL
- MOVQ AX, ret+8(FP)
+ MOVL AX, ret+8(FP)
RET
TEXT runtime·sleep(SB),NOSPLIT,$0
@@ -179,8 +179,8 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$0
RET
// save args
- MOVQ ureg+8(SP), CX
- MOVQ note+16(SP), DX
+ MOVQ ureg+0(FP), CX
+ MOVQ note+8(FP), DX
// change stack
MOVQ g_m(BX), BX
diff --git a/src/runtime/sys_plan9_arm.s b/src/runtime/sys_plan9_arm.s
index 6dee611..d54f56f 100644
--- a/src/runtime/sys_plan9_arm.s
+++ b/src/runtime/sys_plan9_arm.s
@@ -131,7 +131,7 @@ TEXT runtime·plan9_tsemacquire(SB),NOSPLIT,$0-12
TEXT runtime·nsec(SB),NOSPLIT,$-4-12
MOVW $SYS_NSEC, R0
SWI 0
- MOVW unnamed+0(FP), R1
+ MOVW arg+0(FP), R1
MOVW 0(R1), R0
MOVW R0, ret_lo+4(FP)
MOVW 4(R1), R0
@@ -230,7 +230,7 @@ TEXT runtime·tstart_plan9(SB),NOSPLIT,$0-4
MOVW R0, 0(R0) // not reached
RET
-//func sigtramp(ureg, msg unsafe.Pointer)
+//func sigtramp(ureg, note unsafe.Pointer)
TEXT runtime·sigtramp(SB),NOSPLIT,$0-8
// check that g and m exist
CMP $0, g
@@ -242,7 +242,7 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$0-8
// save args
MOVW ureg+0(FP), R1
- MOVW msg+4(FP), R2
+ MOVW note+4(FP), R2
// change stack
MOVW m_gsignal(R0), R3
diff --git a/src/runtime/sys_ppc64x.go b/src/runtime/sys_ppc64x.go
index 2ea1f81..796f27c 100644
--- a/src/runtime/sys_ppc64x.go
+++ b/src/runtime/sys_ppc64x.go
@@ -19,21 +19,4 @@ func gostartcall(buf *gobuf, fn, ctxt unsafe.Pointer) {
buf.ctxt = ctxt
}
-// Called to rewind context saved during morestack back to beginning of function.
-// To help us, the linker emits a jmp back to the beginning right after the
-// call to morestack. We just have to decode and apply that jump.
-func rewindmorestack(buf *gobuf) {
- var inst uint32
- if buf.pc&3 == 0 && buf.pc != 0 {
- inst = *(*uint32)(unsafe.Pointer(buf.pc))
- if inst>>26 == 18 && inst&3 == 0 {
- //print("runtime: rewind pc=", hex(buf.pc), " to pc=", hex(uintptr(buf.pc + int32(inst<<6)>>6)), "\n");
- buf.pc += uintptr(int32(inst<<6) >> 6)
- return
- }
- }
- print("runtime: pc=", hex(buf.pc), " ", hex(inst), "\n")
- throw("runtime: misuse of rewindmorestack")
-}
-
func prepGoExitFrame(sp uintptr)
diff --git a/src/runtime/sys_s390x.go b/src/runtime/sys_s390x.go
index 2aa81e7..e710840 100644
--- a/src/runtime/sys_s390x.go
+++ b/src/runtime/sys_s390x.go
@@ -16,30 +16,3 @@ func gostartcall(buf *gobuf, fn, ctxt unsafe.Pointer) {
buf.pc = uintptr(fn)
buf.ctxt = ctxt
}
-
-// Called to rewind context saved during morestack back to beginning of function.
-// To help us, the linker emits a jmp back to the beginning right after the
-// call to morestack. We just have to decode and apply that jump.
-func rewindmorestack(buf *gobuf) {
- var inst uint64
- if buf.pc&1 == 0 && buf.pc != 0 {
- inst = *(*uint64)(unsafe.Pointer(buf.pc))
- switch inst >> 48 {
- case 0xa7f4: // BRC (branch relative on condition) instruction.
- inst >>= 32
- inst &= 0xFFFF
- offset := int64(int16(inst))
- offset <<= 1
- buf.pc += uintptr(offset)
- return
- case 0xc0f4: // BRCL (branch relative on condition long) instruction.
- inst >>= 16
- inst = inst & 0xFFFFFFFF
- inst = (inst << 1) & 0xFFFFFFFF
- buf.pc += uintptr(int32(inst))
- return
- }
- }
- print("runtime: pc=", hex(buf.pc), " ", hex(inst), "\n")
- throw("runtime: misuse of rewindmorestack")
-}
diff --git a/src/runtime/sys_solaris_amd64.s b/src/runtime/sys_solaris_amd64.s
index 07a7ace..c542db3 100644
--- a/src/runtime/sys_solaris_amd64.s
+++ b/src/runtime/sys_solaris_amd64.s
@@ -289,6 +289,19 @@ exit:
ADDQ $184, SP
RET
+TEXT runtime·sigfwd(SB),NOSPLIT,$0-32
+ MOVQ fn+0(FP), AX
+ MOVL sig+8(FP), DI
+ MOVQ info+16(FP), SI
+ MOVQ ctx+24(FP), DX
+ PUSHQ BP
+ MOVQ SP, BP
+ ANDQ $~15, SP // alignment for x86_64 ABI
+ CALL AX
+ MOVQ BP, SP
+ POPQ BP
+ RET
+
// Called from runtime·usleep (Go). Can be called on Go stack, on OS stack,
// can also be called in cgo callback path without a g->m.
TEXT runtime·usleep1(SB),NOSPLIT,$0
diff --git a/src/runtime/sys_windows_386.s b/src/runtime/sys_windows_386.s
index 95130b7..bd5de33 100644
--- a/src/runtime/sys_windows_386.s
+++ b/src/runtime/sys_windows_386.s
@@ -192,7 +192,7 @@ TEXT runtime·externalthreadhandler(SB),NOSPLIT,$0
SUBL $m__size, SP // space for M
MOVL SP, 0(SP)
MOVL $m__size, 4(SP)
- CALL runtime·memclr(SB) // smashes AX,BX,CX
+ CALL runtime·memclrNoHeapPointers(SB) // smashes AX,BX,CX
LEAL m_tls(SP), CX
MOVL CX, 0x14(FS)
@@ -203,7 +203,7 @@ TEXT runtime·externalthreadhandler(SB),NOSPLIT,$0
MOVL SP, 0(SP)
MOVL $g__size, 4(SP)
- CALL runtime·memclr(SB) // smashes AX,BX,CX
+ CALL runtime·memclrNoHeapPointers(SB) // smashes AX,BX,CX
LEAL g__size(SP), BX
MOVL BX, g_m(SP)
@@ -309,7 +309,7 @@ TEXT runtime·callbackasm1+0(SB),NOSPLIT,$0
// void tstart(M *newm);
TEXT runtime·tstart(SB),NOSPLIT,$0
- MOVL newm+4(SP), CX // m
+ MOVL newm+0(FP), CX // m
MOVL m_g0(CX), DX // g
// Layout new m scheduler stack on os stack.
@@ -337,7 +337,7 @@ TEXT runtime·tstart(SB),NOSPLIT,$0
// uint32 tstart_stdcall(M *newm);
TEXT runtime·tstart_stdcall(SB),NOSPLIT,$0
- MOVL newm+4(SP), BX
+ MOVL newm+0(FP), BX
PUSHL BX
CALL runtime·tstart(SB)
diff --git a/src/runtime/sys_windows_amd64.s b/src/runtime/sys_windows_amd64.s
index 9c19737..c61b79d 100644
--- a/src/runtime/sys_windows_amd64.s
+++ b/src/runtime/sys_windows_amd64.s
@@ -45,6 +45,14 @@ loadregs:
MOVQ 8(SI), DX
MOVQ 16(SI), R8
MOVQ 24(SI), R9
+ // Floating point arguments are passed in the XMM
+ // registers. Set them here in case any of the arguments
+ // are floating point values. For details see
+ // https://msdn.microsoft.com/en-us/library/zthk2dkh.aspx
+ MOVQ CX, X0
+ MOVQ DX, X1
+ MOVQ R8, X2
+ MOVQ R9, X3
// Call stdcall function.
CALL AX
@@ -228,7 +236,7 @@ TEXT runtime·externalthreadhandler(SB),NOSPLIT|NOFRAME,$0
SUBQ $m__size, SP // space for M
MOVQ SP, 0(SP)
MOVQ $m__size, 8(SP)
- CALL runtime·memclr(SB) // smashes AX,BX,CX, maybe BP
+ CALL runtime·memclrNoHeapPointers(SB) // smashes AX,BX,CX, maybe BP
LEAQ m_tls(SP), CX
MOVQ CX, 0x28(GS)
@@ -239,7 +247,7 @@ TEXT runtime·externalthreadhandler(SB),NOSPLIT|NOFRAME,$0
MOVQ SP, 0(SP)
MOVQ $g__size, 8(SP)
- CALL runtime·memclr(SB) // smashes AX,BX,CX, maybe BP
+ CALL runtime·memclrNoHeapPointers(SB) // smashes AX,BX,CX, maybe BP
LEAQ g__size(SP), BX
MOVQ BX, g_m(SP)
diff --git a/src/runtime/sys_x86.go b/src/runtime/sys_x86.go
index f6e45cc..7e4e273 100644
--- a/src/runtime/sys_x86.go
+++ b/src/runtime/sys_x86.go
@@ -25,33 +25,3 @@ func gostartcall(buf *gobuf, fn, ctxt unsafe.Pointer) {
buf.pc = uintptr(fn)
buf.ctxt = ctxt
}
-
-// Called to rewind context saved during morestack back to beginning of function.
-// To help us, the linker emits a jmp back to the beginning right after the
-// call to morestack. We just have to decode and apply that jump.
-func rewindmorestack(buf *gobuf) {
- pc := (*[8]byte)(unsafe.Pointer(buf.pc))
- if pc[0] == 0xe9 { // jmp 4-byte offset
- buf.pc = buf.pc + 5 + uintptr(int64(*(*int32)(unsafe.Pointer(&pc[1]))))
- return
- }
- if pc[0] == 0xeb { // jmp 1-byte offset
- buf.pc = buf.pc + 2 + uintptr(int64(*(*int8)(unsafe.Pointer(&pc[1]))))
- return
- }
- if pc[0] == 0xcc {
- // This is a breakpoint inserted by gdb. We could use
- // runtime·findfunc to find the function. But if we
- // do that, then we will continue execution at the
- // function entry point, and we will not hit the gdb
- // breakpoint. So for this case we don't change
- // buf.pc, so that when we return we will execute
- // the jump instruction and carry on. This means that
- // stack unwinding may not work entirely correctly
- // (https://golang.org/issue/5723) but the user is
- // running under gdb anyhow.
- return
- }
- print("runtime: pc=", pc, " ", hex(pc[0]), " ", hex(pc[1]), " ", hex(pc[2]), " ", hex(pc[3]), " ", hex(pc[4]), "\n")
- throw("runtime: misuse of rewindmorestack")
-}
diff --git a/src/runtime/syscall_windows_test.go b/src/runtime/syscall_windows_test.go
index 4a10749..11e67df 100644
--- a/src/runtime/syscall_windows_test.go
+++ b/src/runtime/syscall_windows_test.go
@@ -10,6 +10,7 @@ import (
"internal/syscall/windows/sysdll"
"internal/testenv"
"io/ioutil"
+ "math"
"os"
"os/exec"
"path/filepath"
@@ -622,6 +623,61 @@ uintptr_t cfunc(callback f, uintptr_t n) {
}
}
+func TestFloatArgs(t *testing.T) {
+ if _, err := exec.LookPath("gcc"); err != nil {
+ t.Skip("skipping test: gcc is missing")
+ }
+ if runtime.GOARCH != "amd64" {
+ t.Skipf("skipping test: GOARCH=%s", runtime.GOARCH)
+ }
+
+ const src = `
+#include <stdint.h>
+#include <windows.h>
+
+uintptr_t cfunc(uintptr_t a, double b, float c, double d) {
+ if (a == 1 && b == 2.2 && c == 3.3f && d == 4.4e44) {
+ return 1;
+ }
+ return 0;
+}
+`
+ tmpdir, err := ioutil.TempDir("", "TestFloatArgs")
+ if err != nil {
+ t.Fatal("TempDir failed: ", err)
+ }
+ defer os.RemoveAll(tmpdir)
+
+ srcname := "mydll.c"
+ err = ioutil.WriteFile(filepath.Join(tmpdir, srcname), []byte(src), 0)
+ if err != nil {
+ t.Fatal(err)
+ }
+ outname := "mydll.dll"
+ cmd := exec.Command("gcc", "-shared", "-s", "-Werror", "-o", outname, srcname)
+ cmd.Dir = tmpdir
+ out, err := cmd.CombinedOutput()
+ if err != nil {
+ t.Fatalf("failed to build dll: %v - %v", err, string(out))
+ }
+ dllpath := filepath.Join(tmpdir, outname)
+
+ dll := syscall.MustLoadDLL(dllpath)
+ defer dll.Release()
+
+ proc := dll.MustFindProc("cfunc")
+
+ r, _, err := proc.Call(
+ 1,
+ uintptr(math.Float64bits(2.2)),
+ uintptr(math.Float32bits(3.3)),
+ uintptr(math.Float64bits(4.4e44)),
+ )
+ if r != 1 {
+ t.Errorf("got %d want 1 (err=%v)", r, err)
+ }
+}
+
func TestTimeBeginPeriod(t *testing.T) {
const TIMERR_NOERROR = 0
if *runtime.TimeBeginPeriodRetValue != TIMERR_NOERROR {
@@ -972,3 +1028,41 @@ func BenchmarkOsYield(b *testing.B) {
runtime.OsYield()
}
}
+
+func BenchmarkRunningGoProgram(b *testing.B) {
+ tmpdir, err := ioutil.TempDir("", "BenchmarkRunningGoProgram")
+ if err != nil {
+ b.Fatal(err)
+ }
+ defer os.RemoveAll(tmpdir)
+
+ src := filepath.Join(tmpdir, "main.go")
+ err = ioutil.WriteFile(src, []byte(benchmarkRunnigGoProgram), 0666)
+ if err != nil {
+ b.Fatal(err)
+ }
+
+ exe := filepath.Join(tmpdir, "main.exe")
+ cmd := exec.Command("go", "build", "-o", exe, src)
+ cmd.Dir = tmpdir
+ out, err := cmd.CombinedOutput()
+ if err != nil {
+ b.Fatalf("building main.exe failed: %v\n%s", err, out)
+ }
+
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ cmd := exec.Command(exe)
+ out, err := cmd.CombinedOutput()
+ if err != nil {
+ b.Fatalf("runing main.exe failed: %v\n%s", err, out)
+ }
+ }
+}
+
+const benchmarkRunnigGoProgram = `
+package main
+
+func main() {
+}
+`
diff --git a/src/runtime/testdata/testprog/deadlock.go b/src/runtime/testdata/testprog/deadlock.go
index c938fcf..ca2be57 100644
--- a/src/runtime/testdata/testprog/deadlock.go
+++ b/src/runtime/testdata/testprog/deadlock.go
@@ -32,6 +32,7 @@ func init() {
register("PanicTraceback", PanicTraceback)
register("GoschedInPanic", GoschedInPanic)
register("SyscallInPanic", SyscallInPanic)
+ register("PanicLoop", PanicLoop)
}
func SimpleDeadlock() {
@@ -214,3 +215,13 @@ func pt2() {
}()
panic("hello")
}
+
+type panicError struct{}
+
+func (*panicError) Error() string {
+ panic("double error")
+}
+
+func PanicLoop() {
+ panic(&panicError{})
+}
diff --git a/src/runtime/testdata/testprog/gc.go b/src/runtime/testdata/testprog/gc.go
index a0c1f82..744b610 100644
--- a/src/runtime/testdata/testprog/gc.go
+++ b/src/runtime/testdata/testprog/gc.go
@@ -98,11 +98,25 @@ func GCFairness2() {
// If the scheduling rules change, this may not be enough time
// to let all goroutines run, but for now we cycle through
// them rapidly.
+ //
+ // OpenBSD's scheduler makes every usleep() take at least
+ // 20ms, so we need a long time to ensure all goroutines have
+ // run. If they haven't run after 30ms, give it another 1000ms
+ // and check again.
time.Sleep(30 * time.Millisecond)
+ var fail bool
for i := range count {
if atomic.LoadInt64(&count[i]) == 0 {
- fmt.Printf("goroutine %d did not run\n", i)
- return
+ fail = true
+ }
+ }
+ if fail {
+ time.Sleep(1 * time.Second)
+ for i := range count {
+ if atomic.LoadInt64(&count[i]) == 0 {
+ fmt.Printf("goroutine %d did not run\n", i)
+ return
+ }
}
}
fmt.Println("OK")
diff --git a/src/runtime/testdata/testprog/map.go b/src/runtime/testdata/testprog/map.go
new file mode 100644
index 0000000..5524289
--- /dev/null
+++ b/src/runtime/testdata/testprog/map.go
@@ -0,0 +1,77 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "runtime"
+
+func init() {
+ register("concurrentMapWrites", concurrentMapWrites)
+ register("concurrentMapReadWrite", concurrentMapReadWrite)
+ register("concurrentMapIterateWrite", concurrentMapIterateWrite)
+}
+
+func concurrentMapWrites() {
+ m := map[int]int{}
+ c := make(chan struct{})
+ go func() {
+ for i := 0; i < 10000; i++ {
+ m[5] = 0
+ runtime.Gosched()
+ }
+ c <- struct{}{}
+ }()
+ go func() {
+ for i := 0; i < 10000; i++ {
+ m[6] = 0
+ runtime.Gosched()
+ }
+ c <- struct{}{}
+ }()
+ <-c
+ <-c
+}
+
+func concurrentMapReadWrite() {
+ m := map[int]int{}
+ c := make(chan struct{})
+ go func() {
+ for i := 0; i < 10000; i++ {
+ m[5] = 0
+ runtime.Gosched()
+ }
+ c <- struct{}{}
+ }()
+ go func() {
+ for i := 0; i < 10000; i++ {
+ _ = m[6]
+ runtime.Gosched()
+ }
+ c <- struct{}{}
+ }()
+ <-c
+ <-c
+}
+
+func concurrentMapIterateWrite() {
+ m := map[int]int{}
+ c := make(chan struct{})
+ go func() {
+ for i := 0; i < 10000; i++ {
+ m[5] = 0
+ runtime.Gosched()
+ }
+ c <- struct{}{}
+ }()
+ go func() {
+ for i := 0; i < 10000; i++ {
+ for range m {
+ }
+ runtime.Gosched()
+ }
+ c <- struct{}{}
+ }()
+ <-c
+ <-c
+}
diff --git a/src/runtime/testdata/testprogcgo/pprof.go b/src/runtime/testdata/testprogcgo/pprof.go
index cb30ec5..4460b93 100644
--- a/src/runtime/testdata/testprogcgo/pprof.go
+++ b/src/runtime/testdata/testprogcgo/pprof.go
@@ -1,4 +1,4 @@
-// Copyright 2016 The Go Authors. All rights reserved.
+// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
diff --git a/src/runtime/testdata/testprogcgo/raceprof.go b/src/runtime/testdata/testprogcgo/raceprof.go
new file mode 100644
index 0000000..fe624c5
--- /dev/null
+++ b/src/runtime/testdata/testprogcgo/raceprof.go
@@ -0,0 +1,78 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build linux,amd64
+
+package main
+
+// Test that we can collect a lot of colliding profiling signals from
+// an external C thread. This used to fail when built with the race
+// detector, because a call of the predeclared function copy was
+// turned into a call to runtime.slicecopy, which is not marked nosplit.
+
+/*
+#include <signal.h>
+#include <stdint.h>
+#include <pthread.h>
+#include <sched.h>
+
+struct cgoTracebackArg {
+ uintptr_t context;
+ uintptr_t sigContext;
+ uintptr_t* buf;
+ uintptr_t max;
+};
+
+static int raceprofCount;
+
+// We want a bunch of different profile stacks that collide in the
+// hash table maintained in runtime/cpuprof.go. This code knows the
+// size of the hash table (1 << 10) and knows that the hash function
+// is simply multiplicative.
+void raceprofTraceback(void* parg) {
+ struct cgoTracebackArg* arg = (struct cgoTracebackArg*)(parg);
+ raceprofCount++;
+ arg->buf[0] = raceprofCount * (1 << 10);
+ arg->buf[1] = 0;
+}
+
+static void* raceprofThread(void* p) {
+ int i;
+
+ for (i = 0; i < 100; i++) {
+ pthread_kill(pthread_self(), SIGPROF);
+ sched_yield();
+ }
+ return 0;
+}
+
+void runRaceprofThread() {
+ pthread_t tid;
+ pthread_create(&tid, 0, raceprofThread, 0);
+ pthread_join(tid, 0);
+}
+*/
+import "C"
+
+import (
+ "bytes"
+ "fmt"
+ "runtime"
+ "runtime/pprof"
+ "unsafe"
+)
+
+func init() {
+ register("CgoRaceprof", CgoRaceprof)
+}
+
+func CgoRaceprof() {
+ runtime.SetCgoTraceback(0, unsafe.Pointer(C.raceprofTraceback), nil, nil)
+
+ var buf bytes.Buffer
+ pprof.StartCPUProfile(&buf)
+
+ C.runRaceprofThread()
+ fmt.Println("OK")
+}
diff --git a/src/runtime/testdata/testprogcgo/racesig.go b/src/runtime/testdata/testprogcgo/racesig.go
new file mode 100644
index 0000000..d0c1c3c
--- /dev/null
+++ b/src/runtime/testdata/testprogcgo/racesig.go
@@ -0,0 +1,102 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build linux,amd64
+
+package main
+
+// Test that an external C thread that is calling malloc can be hit
+// with SIGCHLD signals. This used to fail when built with the race
+// detector, because in that case the signal handler would indirectly
+// call the C malloc function.
+
+/*
+#include <errno.h>
+#include <signal.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include <sched.h>
+#include <unistd.h>
+
+#define ALLOCERS 100
+#define SIGNALERS 10
+
+static void* signalThread(void* p) {
+ pthread_t* pt = (pthread_t*)(p);
+ int i, j;
+
+ for (i = 0; i < 100; i++) {
+ for (j = 0; j < ALLOCERS; j++) {
+ if (pthread_kill(pt[j], SIGCHLD) < 0) {
+ return NULL;
+ }
+ }
+ usleep(1);
+ }
+ return NULL;
+}
+
+#define CALLS 100
+
+static void* mallocThread(void* p) {
+ int i;
+ void *a[CALLS];
+
+ for (i = 0; i < ALLOCERS; i++) {
+ sched_yield();
+ }
+ for (i = 0; i < CALLS; i++) {
+ a[i] = malloc(i);
+ }
+ for (i = 0; i < CALLS; i++) {
+ free(a[i]);
+ }
+ return NULL;
+}
+
+void runRaceSignalThread() {
+ int i;
+ pthread_t m[ALLOCERS];
+ pthread_t s[SIGNALERS];
+
+ for (i = 0; i < ALLOCERS; i++) {
+ pthread_create(&m[i], NULL, mallocThread, NULL);
+ }
+ for (i = 0; i < SIGNALERS; i++) {
+ pthread_create(&s[i], NULL, signalThread, &m[0]);
+ }
+ for (i = 0; i < SIGNALERS; i++) {
+ pthread_join(s[i], NULL);
+ }
+ for (i = 0; i < ALLOCERS; i++) {
+ pthread_join(m[i], NULL);
+ }
+}
+*/
+import "C"
+
+import (
+ "fmt"
+ "os"
+ "time"
+)
+
+func init() {
+ register("CgoRaceSignal", CgoRaceSignal)
+}
+
+func CgoRaceSignal() {
+ // The failure symptom is that the program hangs because of a
+ // deadlock in malloc, so set an alarm.
+ go func() {
+ time.Sleep(5 * time.Second)
+ fmt.Println("Hung for 5 seconds")
+ os.Exit(1)
+ }()
+
+ C.runRaceSignalThread()
+ fmt.Println("OK")
+}
diff --git a/src/runtime/testdata/testprogcgo/threadpprof.go b/src/runtime/testdata/testprogcgo/threadpprof.go
index fdeee69..44afb91 100644
--- a/src/runtime/testdata/testprogcgo/threadpprof.go
+++ b/src/runtime/testdata/testprogcgo/threadpprof.go
@@ -1,4 +1,4 @@
-// Copyright 2016 The Go Authors. All rights reserved.
+// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
@@ -39,17 +39,6 @@ struct cgoTracebackArg {
uintptr_t max;
};
-static void *pprofThread(void* p) {
- time_t start;
-
- (void)p;
- start = time(NULL);
- while (__sync_add_and_fetch(&cpuHogThreadCount, 0) < 2 && time(NULL) - start < 2) {
- cpuHogThread();
- }
-}
-
-
// pprofCgoThreadTraceback is passed to runtime.SetCgoTraceback.
// For testing purposes it pretends that all CPU hits in C code are in cpuHog.
void pprofCgoThreadTraceback(void* parg) {
@@ -64,6 +53,18 @@ void pprofCgoThreadTraceback(void* parg) {
int getCPUHogThreadCount() {
return __sync_add_and_fetch(&cpuHogThreadCount, 0);
}
+
+static void* cpuHogDriver(void* arg __attribute__ ((unused))) {
+ while (1) {
+ cpuHogThread();
+ }
+ return 0;
+}
+
+void runCPUHogThread() {
+ pthread_t tid;
+ pthread_create(&tid, 0, cpuHogDriver, 0);
+}
*/
import "C"
@@ -79,11 +80,19 @@ import (
func init() {
register("CgoPprofThread", CgoPprofThread)
+ register("CgoPprofThreadNoTraceback", CgoPprofThreadNoTraceback)
}
func CgoPprofThread() {
runtime.SetCgoTraceback(0, unsafe.Pointer(C.pprofCgoThreadTraceback), nil, nil)
+ pprofThread()
+}
+
+func CgoPprofThreadNoTraceback() {
+ pprofThread()
+}
+func pprofThread() {
f, err := ioutil.TempFile("", "prof")
if err != nil {
fmt.Fprintln(os.Stderr, err)
@@ -95,6 +104,8 @@ func CgoPprofThread() {
os.Exit(2)
}
+ C.runCPUHogThread()
+
t0 := time.Now()
for C.getCPUHogThreadCount() < 2 && time.Since(t0) < time.Second {
time.Sleep(100 * time.Millisecond)
diff --git a/src/runtime/testdata/testprogcgo/threadprof.go b/src/runtime/testdata/testprogcgo/threadprof.go
index a77479d..2d4c103 100644
--- a/src/runtime/testdata/testprogcgo/threadprof.go
+++ b/src/runtime/testdata/testprogcgo/threadprof.go
@@ -2,7 +2,11 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// We only build this file with the tag "threadprof", since it starts
+// a thread running a busy loop at constructor time.
+
// +build !plan9,!windows
+// +build threadprof
package main
@@ -21,6 +25,7 @@ static void *thread1(void *p) {
spinlock = 0;
return NULL;
}
+
__attribute__((constructor)) void issue9456() {
pthread_t tid;
pthread_create(&tid, 0, thread1, NULL);
@@ -84,8 +89,8 @@ func CgoExternalThreadSignal() {
out, err := exec.Command(os.Args[0], "CgoExternalThreadSignal", "crash").CombinedOutput()
if err == nil {
- fmt.Println("C signal did not crash as expected\n")
- fmt.Printf("%s\n", out)
+ fmt.Println("C signal did not crash as expected")
+ fmt.Printf("\n%s\n", out)
os.Exit(1)
}
diff --git a/src/runtime/time.go b/src/runtime/time.go
index 8df185d..604ccde 100644
--- a/src/runtime/time.go
+++ b/src/runtime/time.go
@@ -88,12 +88,12 @@ func addtimer(t *timer) {
unlock(&timers.lock)
}
-// Add a timer to the heap and start or kick the timer proc.
-// If the new timer is earlier than any of the others.
+// Add a timer to the heap and start or kick timerproc if the new timer is
+// earlier than any of the others.
// Timers are locked.
func addtimerLocked(t *timer) {
// when must never be negative; otherwise timerproc will overflow
- // during its delta calculation and never expire other runtime·timers.
+ // during its delta calculation and never expire other runtime timers.
if t.when < 0 {
t.when = 1<<63 - 1
}
@@ -150,7 +150,7 @@ func deltimer(t *timer) bool {
// Timerproc runs the time-driven events.
// It sleeps until the next event in the timers heap.
-// If addtimer inserts a new earlier event, addtimer1 wakes timerproc early.
+// If addtimer inserts a new earlier event, it wakes timerproc early.
func timerproc() {
timers.gp = getg()
for {
diff --git a/src/runtime/tls_mipsx.s b/src/runtime/tls_mipsx.s
new file mode 100644
index 0000000..95fbc32
--- /dev/null
+++ b/src/runtime/tls_mipsx.s
@@ -0,0 +1,21 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build mips mipsle
+
+#include "go_asm.h"
+#include "go_tls.h"
+#include "funcdata.h"
+#include "textflag.h"
+
+// If !iscgo, this is a no-op.
+TEXT runtime·save_g(SB),NOSPLIT,$-4-0
+ MOVB runtime·iscgo(SB), R23
+ BEQ R23, nocgo
+ UNDEF
+nocgo:
+ RET
+
+TEXT runtime·load_g(SB),NOSPLIT,$-4-0
+ RET
diff --git a/src/runtime/trace.go b/src/runtime/trace.go
index 092f941..a8f4ab6 100644
--- a/src/runtime/trace.go
+++ b/src/runtime/trace.go
@@ -28,8 +28,8 @@ const (
traceEvProcStop = 6 // stop of P [timestamp]
traceEvGCStart = 7 // GC start [timestamp, seq, stack id]
traceEvGCDone = 8 // GC done [timestamp]
- traceEvGCScanStart = 9 // GC scan start [timestamp]
- traceEvGCScanDone = 10 // GC scan done [timestamp]
+ 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]
@@ -60,7 +60,9 @@ const (
traceEvGoStartLocal = 38 // goroutine starts running on the same P as the last event [timestamp, goroutine id]
traceEvGoUnblockLocal = 39 // goroutine is unblocked on the same P as the last event [timestamp, goroutine id, stack]
traceEvGoSysExitLocal = 40 // syscall exit on the same P as the last event [timestamp, goroutine id, real timestamp]
- traceEvCount = 41
+ 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
)
const (
@@ -112,15 +114,20 @@ var trace struct {
empty traceBufPtr // stack of empty buffers
fullHead traceBufPtr // queue of full buffers
fullTail traceBufPtr
- reader *g // goroutine that called ReadTrace, or nil
+ reader guintptr // goroutine that called ReadTrace, or nil
stackTab traceStackTable // maps stack traces to unique ids
// Dictionary for traceEvString.
- // Currently this is used only for func/file:line info after tracing session,
- // so we assume single-threaded access.
+ //
+ // Currently this is used only at trace setup and for
+ // func/file:line info after tracing session, so we assume
+ // single-threaded access.
strings map[string]uint64
stringSeq uint64
+ // markWorkerLabels maps gcMarkWorkerMode to string ID.
+ markWorkerLabels [len(gcMarkWorkerModeStrings)]uint64
+
bufLock mutex // protects buf
buf traceBufPtr // global trace buffer, used when running without a p
}
@@ -134,6 +141,8 @@ type traceBufHeader struct {
}
// traceBuf is per-P tracing buffer.
+//
+//go:notinheap
type traceBuf struct {
traceBufHeader
arr [64<<10 - unsafe.Sizeof(traceBufHeader{})]byte // underlying buffer for traceBufHeader.buf
@@ -144,6 +153,8 @@ type traceBuf struct {
// allocated from the GC'd heap, so this is safe, and are often
// manipulated in contexts where write barriers are not allowed, so
// this is necessary.
+//
+// TODO: Since traceBuf is now go:notinheap, this isn't necessary.
type traceBufPtr uintptr
func (tp traceBufPtr) ptr() *traceBuf { return (*traceBuf)(unsafe.Pointer(tp)) }
@@ -184,10 +195,21 @@ func StartTrace() error {
// trace.enabled is set afterwards once we have emitted all preliminary events.
_g_ := getg()
_g_.m.startingtrace = true
+
+ // Obtain current stack ID to use in all traceEvGoCreate events below.
+ mp := acquirem()
+ stkBuf := make([]uintptr, traceStackSize)
+ stackID := traceStackID(mp, stkBuf, 2)
+ releasem(mp)
+
for _, gp := range allgs {
status := readgstatus(gp)
if status != _Gdead {
- traceGoCreate(gp, gp.startpc) // also resets gp.traceseq/tracelastp
+ gp.traceseq = 0
+ gp.tracelastp = getg().m.p
+ // +PCQuantum because traceFrameForPC expects return PCs and subtracts PCQuantum.
+ id := trace.stackTab.put([]uintptr{gp.startpc + sys.PCQuantum})
+ traceEvent(traceEvGoCreate, -1, uint64(gp.goid), uint64(id), stackID)
}
if status == _Gwaiting {
// traceEvGoWaiting is implied to have seq=1.
@@ -217,6 +239,18 @@ func StartTrace() error {
_g_.m.startingtrace = false
trace.enabled = true
+ // Register runtime goroutine labels.
+ _, pid, bufp := traceAcquireBuffer()
+ buf := (*bufp).ptr()
+ if buf == nil {
+ buf = traceFlush(0).ptr()
+ (*bufp).set(buf)
+ }
+ for i, label := range gcMarkWorkerModeStrings[:] {
+ trace.markWorkerLabels[i], buf = traceString(buf, label)
+ }
+ traceReleaseBuffer(pid)
+
unlock(&trace.bufLock)
startTheWorld()
@@ -251,10 +285,12 @@ func StopTrace() {
p.tracebuf = 0
}
}
- if trace.buf != 0 && trace.buf.ptr().pos != 0 {
+ if trace.buf != 0 {
buf := trace.buf
trace.buf = 0
- traceFullQueue(buf)
+ if buf.ptr().pos != 0 {
+ traceFullQueue(buf)
+ }
}
for {
@@ -275,7 +311,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, false)
+ semacquire(&trace.shutdownSema, 0)
if raceenabled {
raceacquire(unsafe.Pointer(&trace.shutdownSema))
}
@@ -296,7 +332,7 @@ func StopTrace() {
if trace.fullHead != 0 || trace.fullTail != 0 {
throw("trace: non-empty full trace buffer")
}
- if trace.reading != 0 || trace.reader != nil {
+ if trace.reading != 0 || trace.reader != 0 {
throw("trace: reading after shutdown")
}
for trace.empty != 0 {
@@ -324,7 +360,7 @@ func ReadTrace() []byte {
lock(&trace.lock)
trace.lockOwner = getg()
- if trace.reader != nil {
+ if trace.reader != 0 {
// More than one goroutine reads trace. This is bad.
// But we rather do not crash the program because of tracing,
// because tracing can be enabled at runtime on prod servers.
@@ -344,11 +380,11 @@ func ReadTrace() []byte {
trace.headerWritten = true
trace.lockOwner = nil
unlock(&trace.lock)
- return []byte("go 1.7 trace\x00\x00\x00\x00")
+ return []byte("go 1.8 trace\x00\x00\x00\x00")
}
// Wait for new data.
if trace.fullHead == 0 && !trace.shutdown {
- trace.reader = getg()
+ trace.reader.set(getg())
goparkunlock(&trace.lock, "trace reader (blocked)", traceEvGoBlock, 2)
lock(&trace.lock)
}
@@ -402,16 +438,16 @@ func ReadTrace() []byte {
// traceReader returns the trace reader that should be woken up, if any.
func traceReader() *g {
- if trace.reader == nil || (trace.fullHead == 0 && !trace.shutdown) {
+ if trace.reader == 0 || (trace.fullHead == 0 && !trace.shutdown) {
return nil
}
lock(&trace.lock)
- if trace.reader == nil || (trace.fullHead == 0 && !trace.shutdown) {
+ if trace.reader == 0 || (trace.fullHead == 0 && !trace.shutdown) {
unlock(&trace.lock)
return nil
}
- gp := trace.reader
- trace.reader = nil
+ gp := trace.reader.ptr()
+ trace.reader.set(nil)
unlock(&trace.lock)
return gp
}
@@ -513,28 +549,7 @@ func traceEvent(ev byte, skip int, args ...uint64) {
if skip == 0 {
buf.varint(0)
} else if skip > 0 {
- _g_ := getg()
- gp := mp.curg
- var nstk int
- if gp == _g_ {
- nstk = callers(skip, buf.stk[:])
- } else if gp != nil {
- gp = mp.curg
- // This may happen when tracing a system call,
- // so we must lock the stack.
- if gcTryLockStackBarriers(gp) {
- nstk = gcallers(gp, skip, buf.stk[:])
- gcUnlockStackBarriers(gp)
- }
- }
- if nstk > 0 {
- nstk-- // skip runtime.goexit
- }
- if nstk > 0 && gp.goid == 1 {
- nstk-- // skip runtime.main
- }
- id := trace.stackTab.put(buf.stk[:nstk])
- buf.varint(uint64(id))
+ buf.varint(traceStackID(mp, buf.stk[:], skip))
}
evSize := buf.pos - startPos
if evSize > maxSize {
@@ -547,6 +562,31 @@ func traceEvent(ev byte, skip int, args ...uint64) {
traceReleaseBuffer(pid)
}
+func traceStackID(mp *m, buf []uintptr, skip int) uint64 {
+ _g_ := getg()
+ gp := mp.curg
+ var nstk int
+ if gp == _g_ {
+ 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)
+ }
+ }
+ if nstk > 0 {
+ nstk-- // skip runtime.goexit
+ }
+ if nstk > 0 && gp.goid == 1 {
+ nstk-- // skip runtime.main
+ }
+ id := trace.stackTab.put(buf[:nstk])
+ return uint64(id)
+}
+
// traceAcquireBuffer returns trace buffer to use and, if necessary, locks it.
func traceAcquireBuffer() (mp *m, pid int32, bufp *traceBufPtr) {
mp = acquirem()
@@ -811,11 +851,14 @@ type traceAlloc struct {
// traceAllocBlock is allocated from non-GC'd memory, so it must not
// contain heap pointers. Writes to pointers to traceAllocBlocks do
// not need write barriers.
+//
+//go:notinheap
type traceAllocBlock struct {
next traceAllocBlockPtr
data [64<<10 - sys.PtrSize]byte
}
+// TODO: Since traceAllocBlock is now go:notinheap, this isn't necessary.
type traceAllocBlockPtr uintptr
func (p traceAllocBlockPtr) ptr() *traceAllocBlock { return (*traceAllocBlock)(unsafe.Pointer(p)) }
@@ -908,7 +951,9 @@ func traceGoStart() {
_g_ := getg().m.curg
_p_ := _g_.m.p
_g_.traceseq++
- if _g_.tracelastp == _p_ {
+ if _g_ == _p_.ptr().gcBgMarkWorker.ptr() {
+ traceEvent(traceEvGoStartLabel, -1, uint64(_g_.goid), _g_.traceseq, trace.markWorkerLabels[_p_.ptr().gcMarkWorkerMode])
+ } else if _g_.tracelastp == _p_ {
traceEvent(traceEvGoStartLocal, -1, uint64(_g_.goid))
} else {
_g_.tracelastp = _p_
@@ -989,5 +1034,10 @@ func traceHeapAlloc() {
}
func traceNextGC() {
- traceEvent(traceEvNextGC, -1, memstats.next_gc)
+ if memstats.next_gc == ^uint64(0) {
+ // Heap-based triggering is disabled.
+ traceEvent(traceEvNextGC, -1, 0)
+ } else {
+ traceEvent(traceEvNextGC, -1, memstats.next_gc)
+ }
}
diff --git a/src/runtime/trace/trace_stack_test.go b/src/runtime/trace/trace_stack_test.go
index 52a71bf..c37b33d 100644
--- a/src/runtime/trace/trace_stack_test.go
+++ b/src/runtime/trace/trace_stack_test.go
@@ -85,7 +85,8 @@ func TestTraceSymbolize(t *testing.T) {
go func() {
c, err := ln.Accept()
if err != nil {
- t.Fatalf("failed to accept: %v", err)
+ t.Errorf("failed to accept: %v", err)
+ return
}
c.Close()
}()
@@ -102,10 +103,10 @@ func TestTraceSymbolize(t *testing.T) {
pipeReadDone <- true
}()
- time.Sleep(time.Millisecond)
+ time.Sleep(100 * time.Millisecond)
runtime.GC()
runtime.Gosched()
- time.Sleep(time.Millisecond) // the last chance for the goroutines above to block
+ time.Sleep(100 * time.Millisecond) // the last chance for the goroutines above to block
done1 <- true
<-done2
select {
@@ -139,14 +140,14 @@ func TestTraceSymbolize(t *testing.T) {
want := []eventDesc{
{trace.EvGCStart, []frame{
{"runtime.GC", 0},
- {"runtime/trace_test.TestTraceSymbolize", 106},
+ {"runtime/trace_test.TestTraceSymbolize", 107},
{"testing.tRunner", 0},
}},
{trace.EvGoStart, []frame{
{"runtime/trace_test.TestTraceSymbolize.func1", 37},
}},
{trace.EvGoSched, []frame{
- {"runtime/trace_test.TestTraceSymbolize", 107},
+ {"runtime/trace_test.TestTraceSymbolize", 108},
{"testing.tRunner", 0},
}},
{trace.EvGoCreate, []frame{
@@ -171,7 +172,7 @@ func TestTraceSymbolize(t *testing.T) {
}},
{trace.EvGoUnblock, []frame{
{"runtime.chansend1", 0},
- {"runtime/trace_test.TestTraceSymbolize", 109},
+ {"runtime/trace_test.TestTraceSymbolize", 110},
{"testing.tRunner", 0},
}},
{trace.EvGoBlockSend, []frame{
@@ -180,7 +181,7 @@ func TestTraceSymbolize(t *testing.T) {
}},
{trace.EvGoUnblock, []frame{
{"runtime.chanrecv1", 0},
- {"runtime/trace_test.TestTraceSymbolize", 110},
+ {"runtime/trace_test.TestTraceSymbolize", 111},
{"testing.tRunner", 0},
}},
{trace.EvGoBlockSelect, []frame{
@@ -189,7 +190,7 @@ func TestTraceSymbolize(t *testing.T) {
}},
{trace.EvGoUnblock, []frame{
{"runtime.selectgo", 0},
- {"runtime/trace_test.TestTraceSymbolize", 111},
+ {"runtime/trace_test.TestTraceSymbolize", 112},
{"testing.tRunner", 0},
}},
{trace.EvGoBlockSync, []frame{
@@ -198,7 +199,7 @@ func TestTraceSymbolize(t *testing.T) {
}},
{trace.EvGoUnblock, []frame{
{"sync.(*Mutex).Unlock", 0},
- {"runtime/trace_test.TestTraceSymbolize", 115},
+ {"runtime/trace_test.TestTraceSymbolize", 116},
{"testing.tRunner", 0},
}},
{trace.EvGoBlockSync, []frame{
@@ -208,7 +209,7 @@ func TestTraceSymbolize(t *testing.T) {
{trace.EvGoUnblock, []frame{
{"sync.(*WaitGroup).Add", 0},
{"sync.(*WaitGroup).Done", 0},
- {"runtime/trace_test.TestTraceSymbolize", 116},
+ {"runtime/trace_test.TestTraceSymbolize", 117},
{"testing.tRunner", 0},
}},
{trace.EvGoBlockCond, []frame{
@@ -217,12 +218,12 @@ func TestTraceSymbolize(t *testing.T) {
}},
{trace.EvGoUnblock, []frame{
{"sync.(*Cond).Signal", 0},
- {"runtime/trace_test.TestTraceSymbolize", 117},
+ {"runtime/trace_test.TestTraceSymbolize", 118},
{"testing.tRunner", 0},
}},
{trace.EvGoSleep, []frame{
{"time.Sleep", 0},
- {"runtime/trace_test.TestTraceSymbolize", 108},
+ {"runtime/trace_test.TestTraceSymbolize", 109},
{"testing.tRunner", 0},
}},
}
@@ -240,7 +241,7 @@ func TestTraceSymbolize(t *testing.T) {
{"syscall.Read", 0},
{"os.(*File).read", 0},
{"os.(*File).Read", 0},
- {"runtime/trace_test.TestTraceSymbolize.func11", 101},
+ {"runtime/trace_test.TestTraceSymbolize.func11", 102},
}},
}...)
}
diff --git a/src/runtime/trace/trace_test.go b/src/runtime/trace/trace_test.go
index 5fad3fb..c5f64fc 100644
--- a/src/runtime/trace/trace_test.go
+++ b/src/runtime/trace/trace_test.go
@@ -6,8 +6,10 @@ package trace_test
import (
"bytes"
+ "flag"
"internal/trace"
"io"
+ "io/ioutil"
"net"
"os"
"runtime"
@@ -17,6 +19,10 @@ import (
"time"
)
+var (
+ saveTraces = flag.Bool("savetraces", false, "save traces collected by tests")
+)
+
func TestTraceStartStop(t *testing.T) {
buf := new(bytes.Buffer)
if err := Start(buf); err != nil {
@@ -31,6 +37,7 @@ func TestTraceStartStop(t *testing.T) {
if size != buf.Len() {
t.Fatalf("trace writes after stop: %v -> %v", size, buf.Len())
}
+ saveTrace(t, buf, "TestTraceStartStop")
}
func TestTraceDoubleStart(t *testing.T) {
@@ -52,6 +59,7 @@ func TestTrace(t *testing.T) {
t.Fatalf("failed to start tracing: %v", err)
}
Stop()
+ saveTrace(t, buf, "TestTrace")
_, err := trace.Parse(buf, "")
if err == trace.ErrTimeOrder {
t.Skipf("skipping trace: %v", err)
@@ -233,6 +241,7 @@ func TestTraceStress(t *testing.T) {
runtime.GOMAXPROCS(procs)
Stop()
+ saveTrace(t, buf, "TestTraceStress")
trace := buf.Bytes()
parseTrace(t, buf)
testBrokenTimestamps(t, trace)
@@ -260,7 +269,8 @@ func TestTraceStressStartStop(t *testing.T) {
rp, wp, err := os.Pipe()
if err != nil {
- t.Fatalf("failed to create pipe: %v", err)
+ t.Errorf("failed to create pipe: %v", err)
+ return
}
defer func() {
rp.Close()
@@ -336,7 +346,8 @@ func TestTraceStressStartStop(t *testing.T) {
// A bit of network.
ln, err := net.Listen("tcp", "127.0.0.1:0")
if err != nil {
- t.Fatalf("listen failed: %v", err)
+ t.Errorf("listen failed: %v", err)
+ return
}
defer ln.Close()
go func() {
@@ -351,7 +362,8 @@ func TestTraceStressStartStop(t *testing.T) {
}()
c, err := net.Dial("tcp", ln.Addr().String())
if err != nil {
- t.Fatalf("dial failed: %v", err)
+ t.Errorf("dial failed: %v", err)
+ return
}
var tmp [1]byte
c.Read(tmp[:])
@@ -376,6 +388,7 @@ func TestTraceStressStartStop(t *testing.T) {
}
time.Sleep(time.Millisecond)
Stop()
+ saveTrace(t, buf, "TestTraceStressStartStop")
trace := buf.Bytes()
parseTrace(t, buf)
testBrokenTimestamps(t, trace)
@@ -436,6 +449,7 @@ func TestTraceFutileWakeup(t *testing.T) {
done.Wait()
Stop()
+ saveTrace(t, buf, "TestTraceFutileWakeup")
events, _ := parseTrace(t, buf)
// Check that (1) trace does not contain EvFutileWakeup events and
// (2) there are no consecutive EvGoBlock/EvGCStart/EvGoBlock events
@@ -464,3 +478,12 @@ func TestTraceFutileWakeup(t *testing.T) {
}
}
}
+
+func saveTrace(t *testing.T, buf *bytes.Buffer, name string) {
+ if !*saveTraces {
+ return
+ }
+ if err := ioutil.WriteFile(name+".trace", buf.Bytes(), 0600); err != nil {
+ t.Errorf("failed to write trace file: %s", err)
+ }
+}
diff --git a/src/runtime/traceback.go b/src/runtime/traceback.go
index 80a5440..0049e82 100644
--- a/src/runtime/traceback.go
+++ b/src/runtime/traceback.go
@@ -107,7 +107,7 @@ func tracebackdefers(gp *g, callback func(*stkframe, unsafe.Pointer) bool, v uns
}
frame.fn = f
frame.argp = uintptr(deferArgs(d))
- frame.arglen, frame.argmap = getArgInfo(&frame, f, true)
+ frame.arglen, frame.argmap = getArgInfo(&frame, f, true, fn)
}
frame.continpc = frame.pc
if !callback((*stkframe)(noescape(unsafe.Pointer(&frame))), v) {
@@ -339,7 +339,7 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
// metadata recorded by f's caller.
if callback != nil || printing {
frame.argp = frame.fp + sys.MinFrameSize
- frame.arglen, frame.argmap = getArgInfo(&frame, f, callback != nil)
+ frame.arglen, frame.argmap = getArgInfo(&frame, f, callback != nil, nil)
}
// Determine frame's 'continuation PC', where it can continue.
@@ -380,7 +380,7 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
}
}
if printing {
- if (flags&_TraceRuntimeFrames) != 0 || showframe(f, gp) {
+ if (flags&_TraceRuntimeFrames) != 0 || showframe(f, gp, nprint == 0) {
// Print during crash.
// main(0x1, 0x2, 0x3)
// /home/rsc/go/src/runtime/x.go:23 +0xf
@@ -546,19 +546,48 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
return n
}
-func getArgInfo(frame *stkframe, f *_func, needArgMap bool) (arglen uintptr, argmap *bitvector) {
+// reflectMethodValue is a partial duplicate of reflect.methodValue.
+type reflectMethodValue struct {
+ fn uintptr
+ stack *bitvector // args bitmap
+}
+
+// getArgInfo returns the argument frame information for a call to f
+// with call frame frame.
+//
+// This is used for both actual calls with active stack frames and for
+// deferred calls that are not yet executing. If this is an actual
+// 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) {
arglen = uintptr(f.args)
if needArgMap && f.args == _ArgsSizeUnknown {
// Extract argument bitmaps for reflect stubs from the calls they made to reflect.
switch funcname(f) {
case "reflect.makeFuncStub", "reflect.methodValueCall":
- arg0 := frame.sp + sys.MinFrameSize
- fn := *(**[2]uintptr)(unsafe.Pointer(arg0))
- if fn[0] != f.entry {
+ // These take a *reflect.methodValue as their
+ // context register.
+ var mv *reflectMethodValue
+ if ctxt != nil {
+ // This is not an actual call, but a
+ // deferred call. The function value
+ // is itself the *reflect.methodValue.
+ mv = (*reflectMethodValue)(unsafe.Pointer(ctxt))
+ } else {
+ // This is a real call that took the
+ // *reflect.methodValue as its context
+ // register and immediately saved it
+ // to 0(SP). Get the methodValue from
+ // 0(SP).
+ arg0 := frame.sp + sys.MinFrameSize
+ mv = *(**reflectMethodValue)(unsafe.Pointer(arg0))
+ }
+ if mv.fn != f.entry {
print("runtime: confused by ", funcname(f), "\n")
throw("reflect mismatch")
}
- bv := (*bitvector)(unsafe.Pointer(fn[1]))
+ bv := mv.stack
arglen = uintptr(bv.n * sys.PtrSize)
argmap = bv
}
@@ -603,7 +632,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) && gp.goid != 1 {
+ if f != nil && 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 {
@@ -683,7 +712,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) bool {
+func showframe(f *_func, 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
@@ -691,10 +720,12 @@ func showframe(f *_func, gp *g) bool {
level, _, _ := gotraceback()
name := funcname(f)
- // Special case: always show runtime.gopanic frame, so that we can
- // see where a panic started in the middle of a stack trace.
+ // Special case: always show runtime.gopanic frame
+ // in the middle of a stack trace, so that we can
+ // see the boundary between ordinary code and
+ // panic-induced deferred code.
// See golang.org/issue/5832.
- if name == "runtime.gopanic" {
+ if name == "runtime.gopanic" && !firstFrame {
return true
}
@@ -1077,6 +1108,9 @@ func callCgoSymbolizer(arg *cgoSymbolizerArg) {
// or when on the system stack.
call = asmcgocall
}
+ if msanenabled {
+ msanwrite(unsafe.Pointer(arg), unsafe.Sizeof(cgoSymbolizerArg{}))
+ }
call(cgoSymbolizer, noescape(unsafe.Pointer(arg)))
}
@@ -1096,5 +1130,8 @@ func cgoContextPCs(ctxt uintptr, buf []uintptr) {
buf: (*uintptr)(noescape(unsafe.Pointer(&buf[0]))),
max: uintptr(len(buf)),
}
+ if msanenabled {
+ msanwrite(unsafe.Pointer(&arg), unsafe.Sizeof(arg))
+ }
call(cgoTraceback, noescape(unsafe.Pointer(&arg)))
}
diff --git a/src/runtime/type.go b/src/runtime/type.go
index 5ef11a4..3ecc54c 100644
--- a/src/runtime/type.go
+++ b/src/runtime/type.go
@@ -199,11 +199,11 @@ func (t *_type) nameOff(off nameOff) name {
return resolveNameOff(unsafe.Pointer(t), off)
}
-func (t *_type) typeOff(off typeOff) *_type {
+func resolveTypeOff(ptrInModule unsafe.Pointer, off typeOff) *_type {
if off == 0 {
return nil
}
- base := uintptr(unsafe.Pointer(t))
+ base := uintptr(ptrInModule)
var md *moduledata
for next := &firstmoduledata; next != nil; next = next.next {
if base >= next.types && base < next.etypes {
@@ -235,6 +235,10 @@ func (t *_type) typeOff(off typeOff) *_type {
return (*_type)(unsafe.Pointer(res))
}
+func (t *_type) typeOff(off typeOff) *_type {
+ return resolveTypeOff(unsafe.Pointer(t), off)
+}
+
func (t *_type) textOff(off textOff) unsafe.Pointer {
base := uintptr(unsafe.Pointer(t))
var md *moduledata
@@ -257,7 +261,30 @@ func (t *_type) textOff(off textOff) unsafe.Pointer {
}
return res
}
- res := md.text + uintptr(off)
+ res := uintptr(0)
+
+ // The text, or instruction stream is generated as one large buffer. The off (offset) for a method is
+ // its offset within this buffer. If the total text size gets too large, there can be issues on platforms like ppc64 if
+ // the target of calls are too far for the call instruction. To resolve the large text issue, the text is split
+ // into multiple text sections to allow the linker to generate long calls when necessary. When this happens, the vaddr
+ // for each text section is set to its offset within the text. Each method's offset is compared against the section
+ // vaddrs and sizes to determine the containing section. Then the section relative offset is added to the section's
+ // relocated baseaddr to compute the method addess.
+
+ if len(md.textsectmap) > 1 {
+ for i := range md.textsectmap {
+ sectaddr := md.textsectmap[i].vaddr
+ sectlen := md.textsectmap[i].length
+ if uintptr(off) >= sectaddr && uintptr(off) <= sectaddr+sectlen {
+ res = md.textsectmap[i].baseaddr + uintptr(off) - uintptr(md.textsectmap[i].vaddr)
+ break
+ }
+ }
+ } else {
+ // single text section
+ res = md.text + uintptr(off)
+ }
+
if res > md.etext {
println("runtime: textOff", hex(off), "out of range", hex(md.text), "-", hex(md.etext))
throw("runtime: text offset out of range")
@@ -446,14 +473,11 @@ func typelinksinit() {
if firstmoduledata.next == nil {
return
}
- typehash := make(map[uint32][]*_type)
+ typehash := make(map[uint32][]*_type, len(firstmoduledata.typelinks))
- modules := []*moduledata{}
- for md := &firstmoduledata; md != nil; md = md.next {
- modules = append(modules, md)
- }
- prev, modules := modules[len(modules)-1], modules[:len(modules)-1]
- for len(modules) > 0 {
+ modules := activeModules()
+ prev := modules[0]
+ for _, md := range modules[1:] {
// Collect types from the previous module into typehash.
collect:
for _, tl := range prev.typelinks {
@@ -473,23 +497,26 @@ func typelinksinit() {
typehash[t.hash] = append(tlist, t)
}
- // If any of this module's typelinks match a type from a
- // prior module, prefer that prior type by adding the offset
- // to this module's typemap.
- md := modules[len(modules)-1]
- md.typemap = make(map[typeOff]*_type, len(md.typelinks))
- for _, tl := range md.typelinks {
- t := (*_type)(unsafe.Pointer(md.types + uintptr(tl)))
- for _, candidate := range typehash[t.hash] {
- if typesEqual(t, candidate) {
- t = candidate
- break
+ if md.typemap == nil {
+ // If any of this module's typelinks match a type from a
+ // prior module, prefer that prior type by adding the offset
+ // to this module's typemap.
+ tm := make(map[typeOff]*_type, len(md.typelinks))
+ pinnedTypemaps = append(pinnedTypemaps, tm)
+ md.typemap = tm
+ for _, tl := range md.typelinks {
+ t := (*_type)(unsafe.Pointer(md.types + uintptr(tl)))
+ for _, candidate := range typehash[t.hash] {
+ if typesEqual(t, candidate) {
+ t = candidate
+ break
+ }
}
+ md.typemap[typeOff(tl)] = t
}
- md.typemap[typeOff(tl)] = t
}
- prev, modules = md, modules[:len(modules)-1]
+ prev = md
}
}
@@ -573,15 +600,19 @@ func typesEqual(t, v *_type) bool {
for i := range it.mhdr {
tm := &it.mhdr[i]
vm := &iv.mhdr[i]
- tname := it.typ.nameOff(tm.name)
- vname := iv.typ.nameOff(vm.name)
+ // Note the mhdr array can be relocated from
+ // another module. See #17724.
+ tname := resolveNameOff(unsafe.Pointer(tm), tm.name)
+ vname := resolveNameOff(unsafe.Pointer(vm), vm.name)
if tname.name() != vname.name() {
return false
}
if tname.pkgPath() != vname.pkgPath() {
return false
}
- if !typesEqual(it.typ.typeOff(tm.ityp), iv.typ.typeOff(vm.ityp)) {
+ tityp := resolveTypeOff(unsafe.Pointer(tm), tm.ityp)
+ vityp := resolveTypeOff(unsafe.Pointer(vm), vm.ityp)
+ if !typesEqual(tityp, vityp) {
return false
}
}
diff --git a/src/runtime/unaligned2.go b/src/runtime/unaligned2.go
index fed3cca..28b6119 100644
--- a/src/runtime/unaligned2.go
+++ b/src/runtime/unaligned2.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build arm mips64 mips64le
+// +build arm mips mipsle mips64 mips64le
package runtime
diff --git a/src/runtime/utf8.go b/src/runtime/utf8.go
new file mode 100644
index 0000000..24ef179
--- /dev/null
+++ b/src/runtime/utf8.go
@@ -0,0 +1,123 @@
+// Copyright 2016 The Go Authors. 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
+
+// Numbers fundamental to the encoding.
+const (
+ runeError = '\uFFFD' // the "error" Rune or "Unicode replacement character"
+ runeSelf = 0x80 // characters below Runeself are represented as themselves in a single byte.
+ maxRune = '\U0010FFFF' // Maximum valid Unicode code point.
+)
+
+// Code points in the surrogate range are not valid for UTF-8.
+const (
+ surrogateMin = 0xD800
+ surrogateMax = 0xDFFF
+)
+
+const (
+ t1 = 0x00 // 0000 0000
+ tx = 0x80 // 1000 0000
+ t2 = 0xC0 // 1100 0000
+ t3 = 0xE0 // 1110 0000
+ t4 = 0xF0 // 1111 0000
+ t5 = 0xF8 // 1111 1000
+
+ maskx = 0x3F // 0011 1111
+ mask2 = 0x1F // 0001 1111
+ mask3 = 0x0F // 0000 1111
+ mask4 = 0x07 // 0000 0111
+
+ rune1Max = 1<<7 - 1
+ rune2Max = 1<<11 - 1
+ rune3Max = 1<<16 - 1
+
+ // The default lowest and highest continuation byte.
+ locb = 0x80 // 1000 0000
+ hicb = 0xBF // 1011 1111
+)
+
+// decoderune returns the non-ASCII rune at the start of
+// s[k:] and the index after the rune in s.
+//
+// decoderune assumes that caller has checked that
+// the to be decoded rune is a non-ASCII rune.
+//
+// If the string appears to be incomplete or decoding problems
+// are encountered (runeerror, k + 1) is returned to ensure
+// progress when decoderune is used to iterate over a string.
+func decoderune(s string, k int) (r rune, pos int) {
+ pos = k
+
+ if k >= len(s) {
+ return runeError, k + 1
+ }
+
+ s = s[k:]
+
+ switch {
+ case t2 <= s[0] && s[0] < t3:
+ // 0080-07FF two byte sequence
+ if len(s) > 1 && (locb <= s[1] && s[1] <= hicb) {
+ r = rune(s[0]&mask2)<<6 | rune(s[1]&maskx)
+ pos += 2
+ if rune1Max < r {
+ return
+ }
+ }
+ case t3 <= s[0] && s[0] < t4:
+ // 0800-FFFF three byte sequence
+ if len(s) > 2 && (locb <= s[1] && s[1] <= hicb) && (locb <= s[2] && s[2] <= hicb) {
+ r = rune(s[0]&mask3)<<12 | rune(s[1]&maskx)<<6 | rune(s[2]&maskx)
+ pos += 3
+ if rune2Max < r && !(surrogateMin <= r && r <= surrogateMax) {
+ return
+ }
+ }
+ case t4 <= s[0] && s[0] < t5:
+ // 10000-1FFFFF four byte sequence
+ if len(s) > 3 && (locb <= s[1] && s[1] <= hicb) && (locb <= s[2] && s[2] <= hicb) && (locb <= s[3] && s[3] <= hicb) {
+ r = rune(s[0]&mask4)<<18 | rune(s[1]&maskx)<<12 | rune(s[2]&maskx)<<6 | rune(s[3]&maskx)
+ pos += 4
+ if rune3Max < r && r <= maxRune {
+ return
+ }
+ }
+ }
+
+ return runeError, k + 1
+}
+
+// encoderune writes into p (which must be large enough) the UTF-8 encoding of the rune.
+// It returns the number of bytes written.
+func encoderune(p []byte, r rune) int {
+ // Negative values are erroneous. Making it unsigned addresses the problem.
+ switch i := uint32(r); {
+ case i <= rune1Max:
+ p[0] = byte(r)
+ return 1
+ case i <= rune2Max:
+ _ = p[1] // eliminate bounds checks
+ p[0] = t2 | byte(r>>6)
+ p[1] = tx | byte(r)&maskx
+ return 2
+ case i > maxRune, surrogateMin <= i && i <= surrogateMax:
+ r = runeError
+ fallthrough
+ case i <= rune3Max:
+ _ = p[2] // eliminate bounds checks
+ p[0] = t3 | byte(r>>12)
+ p[1] = tx | byte(r>>6)&maskx
+ p[2] = tx | byte(r)&maskx
+ return 3
+ default:
+ _ = p[3] // eliminate bounds checks
+ p[0] = t4 | byte(r>>18)
+ p[1] = tx | byte(r>>12)&maskx
+ p[2] = tx | byte(r>>6)&maskx
+ p[3] = tx | byte(r)&maskx
+ return 4
+ }
+}
diff --git a/src/runtime/vdso_none.go b/src/runtime/vdso_none.go
index efae23f..fc21240 100644
--- a/src/runtime/vdso_none.go
+++ b/src/runtime/vdso_none.go
@@ -3,6 +3,7 @@
// license that can be found in the LICENSE file.
// +build !linux
+// +build !darwin
package runtime
diff --git a/src/runtime/vlop_386.s b/src/runtime/vlop_386.s
index 92232d5..3387c51 100644
--- a/src/runtime/vlop_386.s
+++ b/src/runtime/vlop_386.s
@@ -1,5 +1,5 @@
// Inferno's libkern/vlop-386.s
-// http://code.google.com/p/inferno-os/source/browse/libkern/vlop-386.s
+// https://bitbucket.org/inferno-os/inferno-os/src/default/libkern/vlop-386.s
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com). All rights reserved.
@@ -29,28 +29,28 @@
* C runtime for 64-bit divide.
*/
-// runtime·_mul64x32(r *uint64, a uint64, b uint32) uint32
-// sets *r = low 64 bits of 96-bit product a*b; returns high 32 bits.
+// runtime·_mul64x32(lo64 *uint64, a uint64, b uint32) (hi32 uint32)
+// sets *lo64 = low 64 bits of 96-bit product a*b; returns high 32 bits.
TEXT runtime·_mul64by32(SB), NOSPLIT, $0
- MOVL r+0(FP), CX
- MOVL a+4(FP), AX
+ MOVL lo64+0(FP), CX
+ MOVL a_lo+4(FP), AX
MULL b+12(FP)
MOVL AX, 0(CX)
MOVL DX, BX
- MOVL a+8(FP), AX
+ MOVL a_hi+8(FP), AX
MULL b+12(FP)
ADDL AX, BX
ADCL $0, DX
MOVL BX, 4(CX)
MOVL DX, AX
- MOVL AX, ret+16(FP)
+ MOVL AX, hi32+16(FP)
RET
TEXT runtime·_div64by32(SB), NOSPLIT, $0
MOVL r+12(FP), CX
- MOVL a+0(FP), AX
- MOVL a+4(FP), DX
+ MOVL a_lo+0(FP), AX
+ MOVL a_hi+4(FP), DX
DIVL b+8(FP)
MOVL DX, 0(CX)
- MOVL AX, ret+16(FP)
+ MOVL AX, q+16(FP)
RET
diff --git a/src/runtime/vlop_arm.s b/src/runtime/vlop_arm.s
index 338d9d5..d4c411c 100644
--- a/src/runtime/vlop_arm.s
+++ b/src/runtime/vlop_arm.s
@@ -1,5 +1,5 @@
// Inferno's libkern/vlop-arm.s
-// http://code.google.com/p/inferno-os/source/browse/libkern/vlop-arm.s
+// https://bitbucket.org/inferno-os/inferno-os/src/default/libkern/vlop-arm.s
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com). All rights reserved.
@@ -107,6 +107,7 @@ TEXT runtime·_sfloatpanic(SB),NOSPLIT,$-4
B runtime·sigpanic(SB)
// func 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
// Morgan Kaufmann; 1 edition (April 8, 2004), ISBN 978-1558608740
@@ -117,7 +118,7 @@ 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 udiv(SB),NOSPLIT,$-4
CLZ Rq, Rs // find normalizing shift
MOVW.S Rq<<Rs, Ra
MOVW $fast_udiv_tab<>-64(SB), RM
@@ -202,8 +203,9 @@ 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 RTMP, and it also
-// expects the result in RTMP
+// 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
@@ -224,10 +226,10 @@ TEXT _divu(SB), NOSPLIT, $16-0
MOVW Rs, 12(R13)
MOVW RM, 16(R13)
- MOVW RTMP, Rr /* numerator */
+ MOVW Rn, Rr /* numerator */
MOVW g_m(g), Rq
MOVW m_divmod(Rq), Rq /* denominator */
- BL udiv<>(SB)
+ BL udiv(SB)
MOVW Rq, RTMP
MOVW 4(R13), Rq
MOVW 8(R13), Rr
@@ -242,10 +244,10 @@ TEXT _modu(SB), NOSPLIT, $16-0
MOVW Rs, 12(R13)
MOVW RM, 16(R13)
- MOVW RTMP, Rr /* numerator */
+ MOVW Rn, Rr /* numerator */
MOVW g_m(g), Rq
MOVW m_divmod(Rq), Rq /* denominator */
- BL udiv<>(SB)
+ BL udiv(SB)
MOVW Rr, RTMP
MOVW 4(R13), Rq
MOVW 8(R13), Rr
@@ -259,7 +261,7 @@ TEXT _div(SB),NOSPLIT,$16-0
MOVW Rr, 8(R13)
MOVW Rs, 12(R13)
MOVW RM, 16(R13)
- MOVW RTMP, Rr /* numerator */
+ MOVW Rn, Rr /* numerator */
MOVW g_m(g), Rq
MOVW m_divmod(Rq), Rq /* denominator */
CMP $0, Rr
@@ -269,16 +271,16 @@ TEXT _div(SB),NOSPLIT,$16-0
BGE d2
RSB $0, Rq, Rq
d0:
- BL udiv<>(SB) /* none/both neg */
+ BL udiv(SB) /* none/both neg */
MOVW Rq, RTMP
- B out1
+ B out1
d1:
CMP $0, Rq
BGE d0
RSB $0, Rq, Rq
d2:
- BL udiv<>(SB) /* one neg */
- RSB $0, Rq, RTMP
+ BL udiv(SB) /* one neg */
+ RSB $0, Rq, RTMP
out1:
MOVW 4(R13), Rq
MOVW 8(R13), Rr
@@ -292,7 +294,7 @@ TEXT _mod(SB),NOSPLIT,$16-0
MOVW Rr, 8(R13)
MOVW Rs, 12(R13)
MOVW RM, 16(R13)
- MOVW RTMP, Rr /* numerator */
+ MOVW Rn, Rr /* numerator */
MOVW g_m(g), Rq
MOVW m_divmod(Rq), Rq /* denominator */
CMP $0, Rq
@@ -300,11 +302,11 @@ TEXT _mod(SB),NOSPLIT,$16-0
CMP $0, Rr
BGE m1
RSB $0, Rr, Rr
- BL udiv<>(SB) /* neg numerator */
+ BL udiv(SB) /* neg numerator */
RSB $0, Rr, RTMP
B out
m1:
- BL udiv<>(SB) /* pos numerator */
+ BL udiv(SB) /* pos numerator */
MOVW Rr, RTMP
out:
MOVW 4(R13), Rq
diff --git a/src/runtime/vlrt.go b/src/runtime/vlrt.go
index cd37828..d63da9c 100644
--- a/src/runtime/vlrt.go
+++ b/src/runtime/vlrt.go
@@ -1,5 +1,5 @@
// Inferno's libkern/vlrt-arm.c
-// http://code.google.com/p/inferno-os/source/browse/libkern/vlrt-arm.c
+// https://bitbucket.org/inferno-os/inferno-os/src/default/libkern/vlrt-arm.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com). All rights reserved.
@@ -23,7 +23,7 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
-// +build arm 386
+// +build arm 386 mips mipsle
package runtime
@@ -198,6 +198,11 @@ func dodiv(n, d uint64) (q, r uint64) {
return slowdodiv(n, d)
}
+ if GOARCH == "mips" || GOARCH == "mipsle" {
+ // No _div64by32 on mips and using only _mul64by32 doesn't bring much benefit
+ return slowdodiv(n, d)
+ }
+
if d > n {
return 0, n
}
@@ -255,3 +260,17 @@ func slowdodiv(n, d uint64) (q, r uint64) {
}
return q, n
}
+
+// Floating point control word values for GOARCH=386 GO386=387.
+// Bits 0-5 are bits to disable floating-point exceptions.
+// Bits 8-9 are the precision control:
+// 0 = single precision a.k.a. float32
+// 2 = double precision a.k.a. float64
+// Bits 10-11 are the rounding mode:
+// 0 = round to nearest (even on a tie)
+// 3 = round toward zero
+var (
+ controlWord64 uint16 = 0x3f + 2<<8 + 0<<10
+ controlWord32 = 0x3f + 0<<8 + 0<<10
+ controlWord64trunc = 0x3f + 2<<8 + 3<<10
+)
diff --git a/src/runtime/write_err_android.go b/src/runtime/write_err_android.go
index 4411a14..748dec6 100644
--- a/src/runtime/write_err_android.go
+++ b/src/runtime/write_err_android.go
@@ -75,7 +75,9 @@ func writeErr(b []byte) {
if v == '\n' || writePos == len(dst)-1 {
dst[writePos] = 0
write(writeFD, unsafe.Pointer(&writeBuf[0]), int32(hlen+writePos))
- memclrBytes(dst)
+ for i := range dst {
+ dst[i] = 0
+ }
writePos = 0
}
}
diff --git a/src/sort/example_search_test.go b/src/sort/example_search_test.go
new file mode 100644
index 0000000..6928f0f
--- /dev/null
+++ b/src/sort/example_search_test.go
@@ -0,0 +1,42 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package sort_test
+
+import (
+ "fmt"
+ "sort"
+)
+
+// This example demonstrates searching a list sorted in ascending order.
+func ExampleSearch() {
+ a := []int{1, 3, 6, 10, 15, 21, 28, 36, 45, 55}
+ x := 6
+
+ i := sort.Search(len(a), func(i int) bool { return a[i] >= x })
+ if i < len(a) && a[i] == x {
+ fmt.Printf("found %d at index %d in %v\n", x, i, a)
+ } else {
+ fmt.Printf("%d not found in %v\n", x, a)
+ }
+ // Output:
+ // found 6 at index 2 in [1 3 6 10 15 21 28 36 45 55]
+}
+
+// This example demonstrates searching a list sorted in descending order.
+// The approach is the same as searching a list in ascending order,
+// but with the condition inverted.
+func ExampleSearch_descendingOrder() {
+ a := []int{55, 45, 36, 28, 21, 15, 10, 6, 3, 1}
+ x := 6
+
+ i := sort.Search(len(a), func(i int) bool { return a[i] <= x })
+ if i < len(a) && a[i] == x {
+ fmt.Printf("found %d at index %d in %v\n", x, i, a)
+ } else {
+ fmt.Printf("%d not found in %v\n", x, a)
+ }
+ // Output:
+ // found 6 at index 7 in [55 45 36 28 21 15 10 6 3 1]
+}
diff --git a/src/sort/genzfunc.go b/src/sort/genzfunc.go
new file mode 100644
index 0000000..6d2b471
--- /dev/null
+++ b/src/sort/genzfunc.go
@@ -0,0 +1,122 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build ignore
+
+// This program is run via "go generate" (via a directive in sort.go)
+// to generate zfuncversion.go.
+//
+// It copies sort.go to zfuncversion.go, only retaining funcs which
+// take a "data Interface" parameter, and renaming each to have a
+// "_func" suffix and taking a "data lessSwap" instead. It then rewrites
+// each internal function call to the appropriate _func variants.
+
+package main
+
+import (
+ "bytes"
+ "go/ast"
+ "go/format"
+ "go/parser"
+ "go/token"
+ "io/ioutil"
+ "log"
+ "regexp"
+)
+
+var fset = token.NewFileSet()
+
+func main() {
+ af, err := parser.ParseFile(fset, "sort.go", nil, 0)
+ if err != nil {
+ log.Fatal(err)
+ }
+ af.Doc = nil
+ af.Imports = nil
+ af.Comments = nil
+
+ var newDecl []ast.Decl
+ for _, d := range af.Decls {
+ fd, ok := d.(*ast.FuncDecl)
+ if !ok {
+ continue
+ }
+ if fd.Recv != nil || fd.Name.IsExported() {
+ continue
+ }
+ typ := fd.Type
+ if len(typ.Params.List) < 1 {
+ continue
+ }
+ arg0 := typ.Params.List[0]
+ arg0Name := arg0.Names[0].Name
+ arg0Type := arg0.Type.(*ast.Ident)
+ if arg0Name != "data" || arg0Type.Name != "Interface" {
+ continue
+ }
+ arg0Type.Name = "lessSwap"
+
+ newDecl = append(newDecl, fd)
+ }
+ af.Decls = newDecl
+ ast.Walk(visitFunc(rewriteCalls), af)
+
+ var out bytes.Buffer
+ if err := format.Node(&out, fset, af); err != nil {
+ log.Fatalf("format.Node: %v", err)
+ }
+
+ // Get rid of blank lines after removal of comments.
+ src := regexp.MustCompile(`\n{2,}`).ReplaceAll(out.Bytes(), []byte("\n"))
+
+ // Add comments to each func, for the lost reader.
+ // This is so much easier than adding comments via the AST
+ // and trying to get position info correct.
+ src = regexp.MustCompile(`(?m)^func (\w+)`).ReplaceAll(src, []byte("\n// Auto-generated variant of sort.go:$1\nfunc ${1}_func"))
+
+ // Final gofmt.
+ src, err = format.Source(src)
+ if err != nil {
+ log.Fatalf("format.Source: %v on\n%s", err, src)
+ }
+
+ out.Reset()
+ out.WriteString(`// DO NOT EDIT; AUTO-GENERATED from sort.go using genzfunc.go
+
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+`)
+ out.Write(src)
+
+ const target = "zfuncversion.go"
+ if err := ioutil.WriteFile(target, out.Bytes(), 0644); err != nil {
+ log.Fatal(err)
+ }
+}
+
+type visitFunc func(ast.Node) ast.Visitor
+
+func (f visitFunc) Visit(n ast.Node) ast.Visitor { return f(n) }
+
+func rewriteCalls(n ast.Node) ast.Visitor {
+ ce, ok := n.(*ast.CallExpr)
+ if ok {
+ rewriteCall(ce)
+ }
+ return visitFunc(rewriteCalls)
+}
+
+func rewriteCall(ce *ast.CallExpr) {
+ ident, ok := ce.Fun.(*ast.Ident)
+ if !ok {
+ // e.g. skip SelectorExpr (data.Less(..) calls)
+ return
+ }
+ if len(ce.Args) < 1 {
+ return
+ }
+ ident.Name += "_func"
+}
diff --git a/src/sort/sort.go b/src/sort/sort.go
index d07a0c2..72d24ef 100644
--- a/src/sort/sort.go
+++ b/src/sort/sort.go
@@ -2,10 +2,14 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:generate go run genzfunc.go
+
// Package sort provides primitives for sorting slices and user-defined
// collections.
package sort
+import "reflect"
+
// A type, typically a collection, that satisfies sort.Interface can be
// sorted by the routines in this package. The methods require that the
// elements of the collection be enumerated by an integer index.
@@ -212,14 +216,63 @@ func quickSort(data Interface, a, b, maxDepth int) {
// It makes one call to data.Len to determine n, and O(n*log(n)) calls to
// data.Less and data.Swap. The sort is not guaranteed to be stable.
func Sort(data Interface) {
- // Switch to heapsort if depth of 2*ceil(lg(n+1)) is reached.
n := data.Len()
- maxDepth := 0
+ quickSort(data, 0, n, maxDepth(n))
+}
+
+// maxDepth returns a threshold at which quicksort should switch
+// to heapsort. It returns 2*ceil(lg(n+1)).
+func maxDepth(n int) int {
+ var depth int
for i := n; i > 0; i >>= 1 {
- maxDepth++
+ depth++
+ }
+ return depth * 2
+}
+
+// lessSwap is a pair of Less and Swap function for use with the
+// auto-generated func-optimized variant of sort.go in
+// zfuncversion.go.
+type lessSwap struct {
+ Less func(i, j int) bool
+ Swap func(i, j int)
+}
+
+// Slice sorts the provided slice given the provided less function.
+//
+// The sort is not guaranteed to be stable. For a stable sort, use
+// SliceStable.
+//
+// The function panics if the provided interface is not a slice.
+func Slice(slice interface{}, less func(i, j int) bool) {
+ rv := reflect.ValueOf(slice)
+ swap := reflect.Swapper(slice)
+ length := rv.Len()
+ quickSort_func(lessSwap{less, swap}, 0, length, maxDepth(length))
+}
+
+// SliceStable sorts the provided slice given the provided less
+// function while keeping the original order of equal elements.
+//
+// The function panics if the provided interface is not a slice.
+func SliceStable(slice interface{}, less func(i, j int) bool) {
+ rv := reflect.ValueOf(slice)
+ swap := reflect.Swapper(slice)
+ stable_func(lessSwap{less, swap}, rv.Len())
+}
+
+// SliceIsSorted tests whether a slice is sorted.
+//
+// The function panics if the provided interface is not a slice.
+func SliceIsSorted(slice interface{}, less func(i, j int) bool) bool {
+ rv := reflect.ValueOf(slice)
+ n := rv.Len()
+ for i := n - 1; i > 0; i-- {
+ if less(i, i-1) {
+ return false
+ }
}
- maxDepth *= 2
- quickSort(data, 0, n, maxDepth)
+ return true
}
type reverse struct {
@@ -337,7 +390,10 @@ func StringsAreSorted(a []string) bool { return IsSorted(StringSlice(a)) }
// It makes one call to data.Len to determine n, O(n*log(n)) calls to
// data.Less and O(n*log(n)*log(n)) calls to data.Swap.
func Stable(data Interface) {
- n := data.Len()
+ stable(data, data.Len())
+}
+
+func stable(data Interface, n int) {
blockSize := 20 // must be > 0
a, b := 0, blockSize
for b <= n {
diff --git a/src/sort/sort_test.go b/src/sort/sort_test.go
index 60fac2d..45713a2 100644
--- a/src/sort/sort_test.go
+++ b/src/sort/sort_test.go
@@ -6,10 +6,12 @@ package sort_test
import (
"fmt"
+ "internal/testenv"
"math"
"math/rand"
. "sort"
"strconv"
+ stringspkg "strings"
"testing"
)
@@ -74,6 +76,17 @@ func TestStrings(t *testing.T) {
}
}
+func TestSlice(t *testing.T) {
+ data := strings
+ Slice(data[:], func(i, j int) bool {
+ return data[i] < data[j]
+ })
+ if !SliceIsSorted(data[:], func(i, j int) bool { return data[i] < data[j] }) {
+ t.Errorf("sorted %v", strings)
+ t.Errorf(" got %v", data)
+ }
+}
+
func TestSortLarge_Random(t *testing.T) {
n := 1000000
if testing.Short() {
@@ -148,24 +161,46 @@ func TestNonDeterministicComparison(t *testing.T) {
func BenchmarkSortString1K(b *testing.B) {
b.StopTimer()
+ unsorted := make([]string, 1<<10)
+ for i := range unsorted {
+ unsorted[i] = strconv.Itoa(i ^ 0x2cc)
+ }
+ data := make([]string, len(unsorted))
+
for i := 0; i < b.N; i++ {
- data := make([]string, 1<<10)
- for i := 0; i < len(data); i++ {
- data[i] = strconv.Itoa(i ^ 0x2cc)
- }
+ copy(data, unsorted)
b.StartTimer()
Strings(data)
b.StopTimer()
}
}
+func BenchmarkSortString1K_Slice(b *testing.B) {
+ b.StopTimer()
+ unsorted := make([]string, 1<<10)
+ for i := range unsorted {
+ unsorted[i] = strconv.Itoa(i ^ 0x2cc)
+ }
+ data := make([]string, len(unsorted))
+
+ for i := 0; i < b.N; i++ {
+ copy(data, unsorted)
+ b.StartTimer()
+ Slice(data, func(i, j int) bool { return data[i] < data[j] })
+ b.StopTimer()
+ }
+}
+
func BenchmarkStableString1K(b *testing.B) {
b.StopTimer()
+ unsorted := make([]string, 1<<10)
+ for i := 0; i < len(data); i++ {
+ unsorted[i] = strconv.Itoa(i ^ 0x2cc)
+ }
+ data := make([]string, len(unsorted))
+
for i := 0; i < b.N; i++ {
- data := make([]string, 1<<10)
- for i := 0; i < len(data); i++ {
- data[i] = strconv.Itoa(i ^ 0x2cc)
- }
+ copy(data, unsorted)
b.StartTimer()
Stable(StringSlice(data))
b.StopTimer()
@@ -187,17 +222,34 @@ func BenchmarkSortInt1K(b *testing.B) {
func BenchmarkStableInt1K(b *testing.B) {
b.StopTimer()
+ unsorted := make([]int, 1<<10)
+ for i := range unsorted {
+ unsorted[i] = i ^ 0x2cc
+ }
+ data := make([]int, len(unsorted))
for i := 0; i < b.N; i++ {
- data := make([]int, 1<<10)
- for i := 0; i < len(data); i++ {
- data[i] = i ^ 0x2cc
- }
+ copy(data, unsorted)
b.StartTimer()
Stable(IntSlice(data))
b.StopTimer()
}
}
+func BenchmarkStableInt1K_Slice(b *testing.B) {
+ b.StopTimer()
+ unsorted := make([]int, 1<<10)
+ for i := range unsorted {
+ unsorted[i] = i ^ 0x2cc
+ }
+ data := make([]int, len(unsorted))
+ for i := 0; i < b.N; i++ {
+ copy(data, unsorted)
+ b.StartTimer()
+ SliceStable(data, func(i, j int) bool { return data[i] < data[j] })
+ b.StopTimer()
+ }
+}
+
func BenchmarkSortInt64K(b *testing.B) {
b.StopTimer()
for i := 0; i < b.N; i++ {
@@ -211,6 +263,19 @@ func BenchmarkSortInt64K(b *testing.B) {
}
}
+func BenchmarkSortInt64K_Slice(b *testing.B) {
+ b.StopTimer()
+ for i := 0; i < b.N; i++ {
+ data := make([]int, 1<<16)
+ for i := 0; i < len(data); i++ {
+ data[i] = i ^ 0xcccc
+ }
+ b.StartTimer()
+ Slice(data, func(i, j int) bool { return data[i] < data[j] })
+ b.StopTimer()
+ }
+}
+
func BenchmarkStableInt64K(b *testing.B) {
b.StopTimer()
for i := 0; i < b.N; i++ {
@@ -555,6 +620,9 @@ func TestCountStableOps(t *testing.T) { countOps(t, Stable, "Stable") }
func TestCountSortOps(t *testing.T) { countOps(t, Sort, "Sort ") }
func bench(b *testing.B, size int, algo func(Interface), name string) {
+ if stringspkg.HasSuffix(testenv.Builder(), "-race") && size > 1e4 {
+ b.Skip("skipping slow benchmark on race builder")
+ }
b.StopTimer()
data := make(intPairs, size)
x := ^uint32(0)
diff --git a/src/sort/zfuncversion.go b/src/sort/zfuncversion.go
new file mode 100644
index 0000000..7abb18a
--- /dev/null
+++ b/src/sort/zfuncversion.go
@@ -0,0 +1,265 @@
+// DO NOT EDIT; AUTO-GENERATED from sort.go using genzfunc.go
+
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package sort
+
+// Auto-generated variant of sort.go:insertionSort
+func insertionSort_func(data lessSwap, a, b int) {
+ for i := a + 1; i < b; i++ {
+ for j := i; j > a && data.Less(j, j-1); j-- {
+ data.Swap(j, j-1)
+ }
+ }
+}
+
+// Auto-generated variant of sort.go:siftDown
+func siftDown_func(data lessSwap, lo, hi, first int) {
+ root := lo
+ for {
+ child := 2*root + 1
+ if child >= hi {
+ break
+ }
+ if child+1 < hi && data.Less(first+child, first+child+1) {
+ child++
+ }
+ if !data.Less(first+root, first+child) {
+ return
+ }
+ data.Swap(first+root, first+child)
+ root = child
+ }
+}
+
+// Auto-generated variant of sort.go:heapSort
+func heapSort_func(data lessSwap, a, b int) {
+ first := a
+ lo := 0
+ hi := b - a
+ for i := (hi - 1) / 2; i >= 0; i-- {
+ siftDown_func(data, i, hi, first)
+ }
+ for i := hi - 1; i >= 0; i-- {
+ data.Swap(first, first+i)
+ siftDown_func(data, lo, i, first)
+ }
+}
+
+// Auto-generated variant of sort.go:medianOfThree
+func medianOfThree_func(data lessSwap, m1, m0, m2 int) {
+ if data.Less(m1, m0) {
+ data.Swap(m1, m0)
+ }
+ if data.Less(m2, m1) {
+ data.Swap(m2, m1)
+ if data.Less(m1, m0) {
+ data.Swap(m1, m0)
+ }
+ }
+}
+
+// Auto-generated variant of sort.go:swapRange
+func swapRange_func(data lessSwap, a, b, n int) {
+ for i := 0; i < n; i++ {
+ data.Swap(a+i, b+i)
+ }
+}
+
+// Auto-generated variant of sort.go:doPivot
+func doPivot_func(data lessSwap, lo, hi int) (midlo, midhi int) {
+ m := lo + (hi-lo)/2
+ if hi-lo > 40 {
+ s := (hi - lo) / 8
+ medianOfThree_func(data, lo, lo+s, lo+2*s)
+ medianOfThree_func(data, m, m-s, m+s)
+ medianOfThree_func(data, hi-1, hi-1-s, hi-1-2*s)
+ }
+ medianOfThree_func(data, lo, m, hi-1)
+ pivot := lo
+ a, c := lo+1, hi-1
+ for ; a < c && data.Less(a, pivot); a++ {
+ }
+ b := a
+ for {
+ for ; b < c && !data.Less(pivot, b); b++ {
+ }
+ for ; b < c && data.Less(pivot, c-1); c-- {
+ }
+ if b >= c {
+ break
+ }
+ data.Swap(b, c-1)
+ b++
+ c--
+ }
+ protect := hi-c < 5
+ if !protect && hi-c < (hi-lo)/4 {
+ dups := 0
+ if !data.Less(pivot, hi-1) {
+ data.Swap(c, hi-1)
+ c++
+ dups++
+ }
+ if !data.Less(b-1, pivot) {
+ b--
+ dups++
+ }
+ if !data.Less(m, pivot) {
+ data.Swap(m, b-1)
+ b--
+ dups++
+ }
+ protect = dups > 1
+ }
+ if protect {
+ for {
+ for ; a < b && !data.Less(b-1, pivot); b-- {
+ }
+ for ; a < b && data.Less(a, pivot); a++ {
+ }
+ if a >= b {
+ break
+ }
+ data.Swap(a, b-1)
+ a++
+ b--
+ }
+ }
+ data.Swap(pivot, b-1)
+ return b - 1, c
+}
+
+// Auto-generated variant of sort.go:quickSort
+func quickSort_func(data lessSwap, a, b, maxDepth int) {
+ for b-a > 12 {
+ if maxDepth == 0 {
+ heapSort_func(data, a, b)
+ return
+ }
+ maxDepth--
+ mlo, mhi := doPivot_func(data, a, b)
+ if mlo-a < b-mhi {
+ quickSort_func(data, a, mlo, maxDepth)
+ a = mhi
+ } else {
+ quickSort_func(data, mhi, b, maxDepth)
+ b = mlo
+ }
+ }
+ if b-a > 1 {
+ for i := a + 6; i < b; i++ {
+ if data.Less(i, i-6) {
+ data.Swap(i, i-6)
+ }
+ }
+ insertionSort_func(data, a, b)
+ }
+}
+
+// Auto-generated variant of sort.go:stable
+func stable_func(data lessSwap, n int) {
+ blockSize := 20
+ a, b := 0, blockSize
+ for b <= n {
+ insertionSort_func(data, a, b)
+ a = b
+ b += blockSize
+ }
+ insertionSort_func(data, a, n)
+ for blockSize < n {
+ a, b = 0, 2*blockSize
+ for b <= n {
+ symMerge_func(data, a, a+blockSize, b)
+ a = b
+ b += 2 * blockSize
+ }
+ if m := a + blockSize; m < n {
+ symMerge_func(data, a, m, n)
+ }
+ blockSize *= 2
+ }
+}
+
+// Auto-generated variant of sort.go:symMerge
+func symMerge_func(data lessSwap, a, m, b int) {
+ if m-a == 1 {
+ i := m
+ j := b
+ for i < j {
+ h := i + (j-i)/2
+ if data.Less(h, a) {
+ i = h + 1
+ } else {
+ j = h
+ }
+ }
+ for k := a; k < i-1; k++ {
+ data.Swap(k, k+1)
+ }
+ return
+ }
+ if b-m == 1 {
+ i := a
+ j := m
+ for i < j {
+ h := i + (j-i)/2
+ if !data.Less(m, h) {
+ i = h + 1
+ } else {
+ j = h
+ }
+ }
+ for k := m; k > i; k-- {
+ data.Swap(k, k-1)
+ }
+ return
+ }
+ mid := a + (b-a)/2
+ n := mid + m
+ var start, r int
+ if m > mid {
+ start = n - b
+ r = mid
+ } else {
+ start = a
+ r = m
+ }
+ p := n - 1
+ for start < r {
+ c := start + (r-start)/2
+ if !data.Less(p-c, c) {
+ start = c + 1
+ } else {
+ r = c
+ }
+ }
+ end := n - start
+ if start < m && m < end {
+ rotate_func(data, start, m, end)
+ }
+ if a < start && start < mid {
+ symMerge_func(data, a, start, mid)
+ }
+ if mid < end && end < b {
+ symMerge_func(data, mid, end, b)
+ }
+}
+
+// Auto-generated variant of sort.go:rotate
+func rotate_func(data lessSwap, a, m, b int) {
+ i := m - a
+ j := b - m
+ for i != j {
+ if i > j {
+ swapRange_func(data, m-i, m, j)
+ i -= j
+ } else {
+ swapRange_func(data, m-i, m+j-i, i)
+ j -= i
+ }
+ }
+ swapRange_func(data, m-i, m, i)
+}
diff --git a/src/strconv/atoi.go b/src/strconv/atoi.go
index a236de4..66df149 100644
--- a/src/strconv/atoi.go
+++ b/src/strconv/atoi.go
@@ -199,6 +199,10 @@ func ParseInt(s string, base int, bitSize int) (i int64, err error) {
// Atoi returns the result of ParseInt(s, 10, 0) converted to type int.
func Atoi(s string) (int, error) {
+ const fnAtoi = "Atoi"
i64, err := ParseInt(s, 10, 0)
+ if nerr, ok := err.(*NumError); ok {
+ nerr.Func = fnAtoi
+ }
return int(i64), err
}
diff --git a/src/strconv/decimal.go b/src/strconv/decimal.go
index 5252d6e..957acd9 100644
--- a/src/strconv/decimal.go
+++ b/src/strconv/decimal.go
@@ -131,11 +131,13 @@ func rightShift(a *decimal, k uint) {
}
a.dp -= r - 1
+ var mask uint = (1 << k) - 1
+
// Pick up a digit, put down a digit.
for ; r < a.nd; r++ {
c := uint(a.d[r])
dig := n >> k
- n -= dig << k
+ n &= mask
a.d[w] = byte(dig + '0')
w++
n = n*10 + c - '0'
@@ -144,7 +146,7 @@ func rightShift(a *decimal, k uint) {
// Put down extra digits.
for n > 0 {
dig := n >> k
- n -= dig << k
+ n &= mask
if w < len(a.d) {
a.d[w] = byte(dig + '0')
w++
diff --git a/src/strconv/ftoa_test.go b/src/strconv/ftoa_test.go
index 1d25242..976bd2c 100644
--- a/src/strconv/ftoa_test.go
+++ b/src/strconv/ftoa_test.go
@@ -208,6 +208,9 @@ var ftoaBenches = []struct {
{"64Fixed2", 123.456, 'e', 3, 64},
{"64Fixed3", 1.23456e+78, 'e', 3, 64},
{"64Fixed4", 1.23456e-78, 'e', 3, 64},
+
+ // Trigger slow path (see issue #15672).
+ {"Slowpath64", 622666234635.3213e-320, 'e', -1, 64},
}
func BenchmarkFormatFloat(b *testing.B) {
diff --git a/src/strconv/quote.go b/src/strconv/quote.go
index becfe1d..76c5c2a 100644
--- a/src/strconv/quote.go
+++ b/src/strconv/quote.go
@@ -362,6 +362,16 @@ func Unquote(s string) (string, error) {
if contains(s, '`') {
return "", ErrSyntax
}
+ if contains(s, '\r') {
+ // -1 because we know there is at least one \r to remove.
+ buf := make([]byte, 0, len(s)-1)
+ for i := 0; i < len(s); i++ {
+ if s[i] != '\r' {
+ buf = append(buf, s[i])
+ }
+ }
+ return string(buf), nil
+ }
return s, nil
}
if quote != '"' && quote != '\'' {
diff --git a/src/strconv/quote_test.go b/src/strconv/quote_test.go
index 10735e3..a4b5804 100644
--- a/src/strconv/quote_test.go
+++ b/src/strconv/quote_test.go
@@ -274,6 +274,7 @@ var unquotetests = []unQuoteTest{
{"`\n`", "\n"},
{"` `", ` `},
{"` `", ` `},
+ {"`a\rb`", "ab"},
}
var misquoted = []string{
@@ -306,7 +307,7 @@ var misquoted = []string{
func TestUnquote(t *testing.T) {
for _, tt := range unquotetests {
- if out, err := Unquote(tt.in); err != nil && out != tt.out {
+ if out, err := Unquote(tt.in); err != nil || out != tt.out {
t.Errorf("Unquote(%#q) = %q, %v want %q, nil", tt.in, out, err, tt.out)
}
}
diff --git a/src/strconv/strconv_test.go b/src/strconv/strconv_test.go
index 9a007dd..0c14236 100644
--- a/src/strconv/strconv_test.go
+++ b/src/strconv/strconv_test.go
@@ -55,3 +55,34 @@ func TestCountMallocs(t *testing.T) {
}
}
}
+
+func TestErrorPrefixes(t *testing.T) {
+ _, errInt := Atoi("INVALID")
+ _, errBool := ParseBool("INVALID")
+ _, errFloat := ParseFloat("INVALID", 64)
+ _, errInt64 := ParseInt("INVALID", 10, 64)
+ _, errUint64 := ParseUint("INVALID", 10, 64)
+
+ vectors := []struct {
+ err error // Input error
+ want string // Function name wanted
+ }{
+ {errInt, "Atoi"},
+ {errBool, "ParseBool"},
+ {errFloat, "ParseFloat"},
+ {errInt64, "ParseInt"},
+ {errUint64, "ParseUint"},
+ }
+
+ for _, v := range vectors {
+ nerr, ok := v.err.(*NumError)
+ if !ok {
+ t.Errorf("test %s, error was not a *NumError", v.want)
+ continue
+ }
+ if got := nerr.Func; got != v.want {
+ t.Errorf("mismatching Func: got %s, want %s", got, v.want)
+ }
+ }
+
+}
diff --git a/src/strings/strings.go b/src/strings/strings.go
index 919e8c8..60a281a 100644
--- a/src/strings/strings.go
+++ b/src/strings/strings.go
@@ -77,48 +77,18 @@ func hashStrRev(sep string) (uint32, uint32) {
func Count(s, sep string) int {
n := 0
// special cases
- switch {
- case len(sep) == 0:
+ if len(sep) == 0 {
return utf8.RuneCountInString(s) + 1
- case len(sep) == 1:
- // special case worth making fast
- c := sep[0]
- for i := 0; i < len(s); i++ {
- if s[i] == c {
- n++
- }
- }
- return n
- case len(sep) > len(s):
- return 0
- case len(sep) == len(s):
- if sep == s {
- return 1
- }
- return 0
}
- // Rabin-Karp search
- hashsep, pow := hashStr(sep)
- h := uint32(0)
- for i := 0; i < len(sep); i++ {
- h = h*primeRK + uint32(s[i])
- }
- lastmatch := 0
- if h == hashsep && s[:len(sep)] == sep {
- n++
- lastmatch = len(sep)
- }
- for i := len(sep); i < len(s); {
- h *= primeRK
- h += uint32(s[i])
- h -= pow * uint32(s[i-len(sep)])
- i++
- if h == hashsep && lastmatch <= i-len(sep) && s[i-len(sep):i] == sep {
- n++
- lastmatch = i
+ offset := 0
+ for {
+ i := Index(s[offset:], sep)
+ if i == -1 {
+ return n
}
+ n++
+ offset += i + len(sep)
}
- return n
}
// Contains reports whether substr is within s.
@@ -175,24 +145,40 @@ func LastIndex(s, sep string) int {
// IndexRune returns the index of the first instance of the Unicode code point
// r, or -1 if rune is not present in s.
+// If r is utf8.RuneError, it returns the first instance of any
+// invalid UTF-8 byte sequence.
func IndexRune(s string, r rune) int {
switch {
- case r < utf8.RuneSelf:
+ case 0 <= r && r < utf8.RuneSelf:
return IndexByte(s, byte(r))
- default:
- for i, c := range s {
- if c == r {
+ case r == utf8.RuneError:
+ for i, r := range s {
+ if r == utf8.RuneError {
return i
}
}
+ return -1
+ case !utf8.ValidRune(r):
+ return -1
+ default:
+ return Index(s, string(r))
}
- return -1
}
// IndexAny returns the index of the first instance of any Unicode code point
// from chars in s, or -1 if no Unicode code point from chars is present in s.
func IndexAny(s, chars string) int {
if len(chars) > 0 {
+ if len(s) > 8 {
+ if as, isASCII := makeASCIISet(chars); isASCII {
+ for i := 0; i < len(s); i++ {
+ if as.contains(s[i]) {
+ return i
+ }
+ }
+ return -1
+ }
+ }
for i, c := range s {
for _, m := range chars {
if c == m {
@@ -209,11 +195,21 @@ func IndexAny(s, chars string) int {
// present in s.
func LastIndexAny(s, chars string) int {
if len(chars) > 0 {
+ if len(s) > 8 {
+ if as, isASCII := makeASCIISet(chars); isASCII {
+ for i := len(s) - 1; i >= 0; i-- {
+ if as.contains(s[i]) {
+ return i
+ }
+ }
+ return -1
+ }
+ }
for i := len(s); i > 0; {
- rune, size := utf8.DecodeLastRuneInString(s[0:i])
+ r, size := utf8.DecodeLastRuneInString(s[:i])
i -= size
- for _, m := range chars {
- if rune == m {
+ for _, c := range chars {
+ if r == c {
return i
}
}
@@ -342,11 +338,19 @@ func FieldsFunc(s string, f func(rune) bool) []string {
// Join concatenates the elements of a to create a single string. The separator string
// sep is placed between elements in the resulting string.
func Join(a []string, sep string) string {
- if len(a) == 0 {
+ switch len(a) {
+ case 0:
return ""
- }
- if len(a) == 1 {
+ case 1:
return a[0]
+ case 2:
+ // Special case for common small values.
+ // Remove if golang.org/issue/6714 is fixed
+ return a[0] + sep + a[1]
+ case 3:
+ // Special case for common small values.
+ // Remove if golang.org/issue/6714 is fixed
+ return a[0] + sep + a[1] + sep + a[2]
}
n := len(sep) * (len(a) - 1)
for i := 0; i < len(a); i++ {
@@ -416,7 +420,20 @@ func Map(mapping func(rune) rune, s string) string {
}
// Repeat returns a new string consisting of count copies of the string s.
+//
+// It panics if count is negative or if
+// the result of (len(s) * count) overflows.
func Repeat(s string, count int) string {
+ // Since we cannot return an error on overflow,
+ // we should panic if the repeat will generate
+ // an overflow.
+ // See Issue golang.org/issue/16237
+ if count < 0 {
+ panic("strings: negative Repeat count")
+ } else if count > 0 && len(s)*count/count != len(s) {
+ panic("strings: Repeat count causes overflow")
+ }
+
b := make([]byte, len(s)*count)
bp := copy(b, s)
for bp < len(b) {
@@ -437,20 +454,20 @@ func ToTitle(s string) string { return Map(unicode.ToTitle, s) }
// ToUpperSpecial returns a copy of the string s with all Unicode letters mapped to their
// upper case, giving priority to the special casing rules.
-func ToUpperSpecial(_case unicode.SpecialCase, s string) string {
- return Map(func(r rune) rune { return _case.ToUpper(r) }, s)
+func ToUpperSpecial(c unicode.SpecialCase, s string) string {
+ return Map(func(r rune) rune { return c.ToUpper(r) }, s)
}
// ToLowerSpecial returns a copy of the string s with all Unicode letters mapped to their
// lower case, giving priority to the special casing rules.
-func ToLowerSpecial(_case unicode.SpecialCase, s string) string {
- return Map(func(r rune) rune { return _case.ToLower(r) }, s)
+func ToLowerSpecial(c unicode.SpecialCase, s string) string {
+ return Map(func(r rune) rune { return c.ToLower(r) }, s)
}
// ToTitleSpecial returns a copy of the string s with all Unicode letters mapped to their
// title case, giving priority to the special casing rules.
-func ToTitleSpecial(_case unicode.SpecialCase, s string) string {
- return Map(func(r rune) rune { return _case.ToTitle(r) }, s)
+func ToTitleSpecial(c unicode.SpecialCase, s string) string {
+ return Map(func(r rune) rune { return c.ToTitle(r) }, s)
}
// isSeparator reports whether the rune could mark a word boundary.
@@ -573,7 +590,43 @@ func lastIndexFunc(s string, f func(rune) bool, truth bool) int {
return -1
}
+// asciiSet is a 32-byte value, where each bit represents the presence of a
+// given ASCII character in the set. The 128-bits of the lower 16 bytes,
+// starting with the least-significant bit of the lowest word to the
+// most-significant bit of the highest word, map to the full range of all
+// 128 ASCII characters. The 128-bits of the upper 16 bytes will be zeroed,
+// ensuring that any non-ASCII character will be reported as not in the set.
+type asciiSet [8]uint32
+
+// makeASCIISet creates a set of ASCII characters and reports whether all
+// characters in chars are ASCII.
+func makeASCIISet(chars string) (as asciiSet, ok bool) {
+ for i := 0; i < len(chars); i++ {
+ c := chars[i]
+ if c >= utf8.RuneSelf {
+ return as, false
+ }
+ as[c>>5] |= 1 << uint(c&31)
+ }
+ return as, true
+}
+
+// contains reports whether c is inside the set.
+func (as *asciiSet) contains(c byte) bool {
+ return (as[c>>5] & (1 << uint(c&31))) != 0
+}
+
func makeCutsetFunc(cutset string) func(rune) bool {
+ if len(cutset) == 1 && cutset[0] < utf8.RuneSelf {
+ return func(r rune) bool {
+ return r == rune(cutset[0])
+ }
+ }
+ if as, isASCII := makeASCIISet(cutset); isASCII {
+ return func(r rune) bool {
+ return r < utf8.RuneSelf && as.contains(byte(r))
+ }
+ }
return func(r rune) bool { return IndexRune(cutset, r) >= 0 }
}
diff --git a/src/strings/strings_amd64.go b/src/strings/strings_amd64.go
index 55bf2d2..23a98d5 100644
--- a/src/strings/strings_amd64.go
+++ b/src/strings/strings_amd64.go
@@ -4,10 +4,22 @@
package strings
+//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
-const shortStringLen = 31
+func supportAVX2() bool // ../runtime/asm_$GOARCH.s
+
+var shortStringLen int
+
+func init() {
+ if supportAVX2() {
+ 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 {
@@ -17,8 +29,6 @@ func Index(s, sep string) int {
return 0
case n == 1:
return IndexByte(s, sep[0])
- case n <= shortStringLen:
- return indexShortStr(s, sep)
case n == len(s):
if sep == s {
return 0
@@ -26,6 +36,42 @@ func Index(s, sep string) int {
return -1
case n > len(s):
return -1
+ case n <= shortStringLen:
+ // Use brute force when s and sep both are small
+ if len(s) <= 64 {
+ return indexShortStr(s, sep)
+ }
+ c := sep[0]
+ i := 0
+ t := s[:len(s)-n+1]
+ fails := 0
+ for i < len(t) {
+ if t[i] != c {
+ // IndexByte skips 16/32 bytes per iteration,
+ // so it's faster than indexShortStr.
+ o := IndexByte(t[i:], c)
+ if o < 0 {
+ return -1
+ }
+ i += o
+ }
+ if s[i:i+n] == sep {
+ return i
+ }
+ fails++
+ i++
+ // Switch to indexShortStr when IndexByte produces too many false positives.
+ // 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)
+ if r >= 0 {
+ return r + i
+ }
+ return -1
+ }
+ }
+ return -1
}
// Rabin-Karp search
hashsep, pow := hashStr(sep)
diff --git a/src/strings/strings_generic.go b/src/strings/strings_generic.go
index d356f50..6e80559 100644
--- a/src/strings/strings_generic.go
+++ b/src/strings/strings_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
+// +build !amd64,!s390x
package strings
diff --git a/src/strings/strings_s390x.go b/src/strings/strings_s390x.go
new file mode 100644
index 0000000..316a1b8
--- /dev/null
+++ b/src/strings/strings_s390x.go
@@ -0,0 +1,98 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package strings
+
+//go:noescape
+
+// indexShortStr returns the index of the first instance of sep in s,
+// or -1 if sep is not present in s.
+// indexShortStr requires 2 <= len(sep) <= shortStringLen
+func indexShortStr(s, sep string) int // ../runtime/asm_$GOARCH.s
+
+// supportsVX reports whether the vector facility is available.
+// indexShortStr must not be called if the vector facility is not
+// available.
+func supportsVX() bool // ../runtime/asm_s390x.s
+
+var shortStringLen = -1
+
+func init() {
+ if supportsVX() {
+ shortStringLen = 64
+ }
+}
+
+// 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)
+ switch {
+ case n == 0:
+ return 0
+ case n == 1:
+ return IndexByte(s, sep[0])
+ case n == len(s):
+ if sep == s {
+ return 0
+ }
+ return -1
+ case n > len(s):
+ return -1
+ case n <= shortStringLen:
+ // Use brute force when s and sep both are small
+ if len(s) <= 64 {
+ return indexShortStr(s, sep)
+ }
+ c := sep[0]
+ i := 0
+ t := s[:len(s)-n+1]
+ fails := 0
+ for i < len(t) {
+ if t[i] != c {
+ // IndexByte skips 16/32 bytes per iteration,
+ // so it's faster than indexShortStr.
+ o := IndexByte(t[i:], c)
+ if o < 0 {
+ return -1
+ }
+ i += o
+ }
+ if s[i:i+n] == sep {
+ return i
+ }
+ fails++
+ i++
+ // Switch to indexShortStr when IndexByte produces too many false positives.
+ // 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)
+ if r >= 0 {
+ return r + i
+ }
+ return -1
+ }
+ }
+ return -1
+ }
+ // Rabin-Karp search
+ hashsep, pow := hashStr(sep)
+ var h uint32
+ for i := 0; i < n; i++ {
+ h = h*primeRK + uint32(s[i])
+ }
+ if h == hashsep && s[:n] == sep {
+ return 0
+ }
+ for i := n; i < len(s); {
+ h *= primeRK
+ h += uint32(s[i])
+ h -= pow * uint32(s[i-n])
+ i++
+ if h == hashsep && s[i-n:i] == sep {
+ return i - n
+ }
+ }
+ return -1
+}
diff --git a/src/strings/strings_test.go b/src/strings/strings_test.go
index fcef761..4397949 100644
--- a/src/strings/strings_test.go
+++ b/src/strings/strings_test.go
@@ -6,6 +6,7 @@ package strings_test
import (
"bytes"
+ "fmt"
"io"
"math/rand"
"reflect"
@@ -86,32 +87,44 @@ var indexTests = []IndexTest{
{"32145678", "01234567", -1},
{"01234567", "01234567", 0},
{"x01234567", "01234567", 1},
+ {"x0123456x01234567", "01234567", 9},
{"xx01234567"[:9], "01234567", -1},
{"", "0123456789", -1},
{"3214567844", "0123456789", -1},
{"0123456789", "0123456789", 0},
{"x0123456789", "0123456789", 1},
+ {"x012345678x0123456789", "0123456789", 11},
{"xyz0123456789"[:12], "0123456789", -1},
{"x01234567x89", "0123456789", -1},
{"", "0123456789012345", -1},
{"3214567889012345", "0123456789012345", -1},
{"0123456789012345", "0123456789012345", 0},
{"x0123456789012345", "0123456789012345", 1},
+ {"x012345678901234x0123456789012345", "0123456789012345", 17},
{"", "01234567890123456789", -1},
{"32145678890123456789", "01234567890123456789", -1},
{"01234567890123456789", "01234567890123456789", 0},
{"x01234567890123456789", "01234567890123456789", 1},
+ {"x0123456789012345678x01234567890123456789", "01234567890123456789", 21},
{"xyz01234567890123456789"[:22], "01234567890123456789", -1},
{"", "0123456789012345678901234567890", -1},
{"321456788901234567890123456789012345678911", "0123456789012345678901234567890", -1},
{"0123456789012345678901234567890", "0123456789012345678901234567890", 0},
{"x0123456789012345678901234567890", "0123456789012345678901234567890", 1},
+ {"x012345678901234567890123456789x0123456789012345678901234567890", "0123456789012345678901234567890", 32},
{"xyz0123456789012345678901234567890"[:33], "0123456789012345678901234567890", -1},
{"", "01234567890123456789012345678901", -1},
{"32145678890123456789012345678901234567890211", "01234567890123456789012345678901", -1},
{"01234567890123456789012345678901", "01234567890123456789012345678901", 0},
{"x01234567890123456789012345678901", "01234567890123456789012345678901", 1},
+ {"x0123456789012345678901234567890x01234567890123456789012345678901", "01234567890123456789012345678901", 33},
{"xyz01234567890123456789012345678901"[:34], "01234567890123456789012345678901", -1},
+ {"xxxxxx012345678901234567890123456789012345678901234567890123456789012", "012345678901234567890123456789012345678901234567890123456789012", 6},
+ {"", "0123456789012345678901234567890123456789", -1},
+ {"xx012345678901234567890123456789012345678901234567890123456789012", "0123456789012345678901234567890123456789", 2},
+ {"xx012345678901234567890123456789012345678901234567890123456789012"[:41], "0123456789012345678901234567890123456789", -1},
+ {"xx012345678901234567890123456789012345678901234567890123456789012", "0123456789012345678901234567890123456xxx", -1},
+ {"xx0123456789012345678901234567890123456789012345678901234567890120123456789012345678901234567890123456xxx", "0123456789012345678901234567890123456xxx", 65},
}
var lastIndexTests = []IndexTest{
@@ -139,10 +152,15 @@ var indexAnyTests = []IndexTest{
{"aaa", "a", 0},
{"abc", "xyz", -1},
{"abc", "xcz", 2},
- {"a☺b☻c☹d", "uvw☻xyz", 2 + len("☺")},
+ {"ab☺c", "x☺yz", 2},
+ {"a☺b☻c☹d", "cx", len("a☺b☻")},
+ {"a☺b☻c☹d", "uvw☻xyz", len("a☺b")},
{"aRegExp*", ".(|)*+?^$[]", 7},
{dots + dots + dots, " ", -1},
+ {"012abcba210", "\xffb", 4},
+ {"012\x80bcb\x80210", "\xffb", 3},
}
+
var lastIndexAnyTests = []IndexTest{
{"", "", -1},
{"", "a", -1},
@@ -152,9 +170,13 @@ var lastIndexAnyTests = []IndexTest{
{"aaa", "a", 2},
{"abc", "xyz", -1},
{"abc", "ab", 1},
- {"a☺b☻c☹d", "uvw☻xyz", 2 + len("☺")},
+ {"ab☺c", "x☺yz", 2},
+ {"a☺b☻c☹d", "cx", len("a☺b☻")},
+ {"a☺b☻c☹d", "uvw☻xyz", len("a☺b")},
{"a.RegExp*", ".(|)*+?^$[]", 8},
{dots + dots + dots, " ", -1},
+ {"012abcba210", "\xffb", 6},
+ {"012\x80bcb\x80210", "\xffb", 7},
}
// Execute f on each test case. funcName should be the name of f; it's used
@@ -227,23 +249,54 @@ func TestIndexRandom(t *testing.T) {
}
}
-var indexRuneTests = []struct {
- s string
- rune rune
- out int
-}{
- {"a A x", 'A', 2},
- {"some_text=some_value", '=', 9},
- {"☺a", 'a', 3},
- {"a☻☺b", '☺', 4},
-}
-
func TestIndexRune(t *testing.T) {
- for _, test := range indexRuneTests {
- if actual := IndexRune(test.s, test.rune); actual != test.out {
- t.Errorf("IndexRune(%q,%d)= %v; want %v", test.s, test.rune, actual, test.out)
+ tests := []struct {
+ in string
+ rune rune
+ want int
+ }{
+ {"", 'a', -1},
+ {"", '☺', -1},
+ {"foo", '☹', -1},
+ {"foo", 'o', 1},
+ {"foo☺bar", '☺', 3},
+ {"foo☺☻☹bar", '☹', 9},
+ {"a A x", 'A', 2},
+ {"some_text=some_value", '=', 9},
+ {"☺a", 'a', 3},
+ {"a☻☺b", '☺', 4},
+
+ // RuneError should match any invalid UTF-8 byte sequence.
+ {"�", '�', 0},
+ {"\xff", '�', 0},
+ {"☻x�", '�', len("☻x")},
+ {"☻x\xe2\x98", '�', len("☻x")},
+ {"☻x\xe2\x98�", '�', len("☻x")},
+ {"☻x\xe2\x98x", '�', len("☻x")},
+
+ // Invalid rune values should never match.
+ {"a☺b☻c☹d\xe2\x98�\xff�\xed\xa0\x80", -1, -1},
+ {"a☺b☻c☹d\xe2\x98�\xff�\xed\xa0\x80", 0xD800, -1}, // Surrogate pair
+ {"a☺b☻c☹d\xe2\x98�\xff�\xed\xa0\x80", utf8.MaxRune + 1, -1},
+ }
+ for _, tt := range tests {
+ if got := IndexRune(tt.in, tt.rune); got != tt.want {
+ t.Errorf("IndexRune(%q, %d) = %v; want %v", tt.in, tt.rune, got, tt.want)
}
}
+
+ haystack := "test世界"
+ allocs := testing.AllocsPerRun(1000, func() {
+ if i := IndexRune(haystack, 's'); i != 2 {
+ t.Fatalf("'s' at %d; want 2", i)
+ }
+ if i := IndexRune(haystack, '世'); i != 4 {
+ t.Fatalf("'世' at %d; want 4", i)
+ }
+ })
+ if allocs != 0 && testing.CoverMode() == "" {
+ t.Errorf("expected no allocations, got %f", allocs)
+ }
}
const benchmarkString = "some_text=some☺value"
@@ -257,6 +310,17 @@ func BenchmarkIndexRune(b *testing.B) {
}
}
+var benchmarkLongString = Repeat(" ", 100) + benchmarkString
+
+func BenchmarkIndexRuneLongString(b *testing.B) {
+ if got := IndexRune(benchmarkLongString, '☺'); got != 114 {
+ b.Fatalf("wrong index: expected 114, got=%d", got)
+ }
+ for i := 0; i < b.N; i++ {
+ IndexRune(benchmarkLongString, '☺')
+ }
+}
+
func BenchmarkIndexRuneFastPath(b *testing.B) {
if got := IndexRune(benchmarkString, 'v'); got != 17 {
b.Fatalf("wrong index: expected 17, got=%d", got)
@@ -613,6 +677,9 @@ var trimTests = []struct {
{"Trim", "* listitem", " *", "listitem"},
{"Trim", `"quote"`, `"`, "quote"},
{"Trim", "\u2C6F\u2C6F\u0250\u0250\u2C6F\u2C6F", "\u2C6F", "\u0250\u0250"},
+ {"Trim", "\x80test\xff", "\xff", "test"},
+ {"Trim", " Ġ ", " ", "Ġ"},
+ {"Trim", " Ġİ0", "0 ", "Ġİ"},
//empty string tests
{"Trim", "abba", "", "abba"},
{"Trim", "", "123", ""},
@@ -855,6 +922,54 @@ func TestRepeat(t *testing.T) {
}
}
+func repeat(s string, count int) (err error) {
+ defer func() {
+ if r := recover(); r != nil {
+ switch v := r.(type) {
+ case error:
+ err = v
+ default:
+ err = fmt.Errorf("%s", v)
+ }
+ }
+ }()
+
+ Repeat(s, count)
+
+ return
+}
+
+// See Issue golang.org/issue/16237
+func TestRepeatCatchesOverflow(t *testing.T) {
+ tests := [...]struct {
+ s string
+ count int
+ errStr string
+ }{
+ 0: {"--", -2147483647, "negative"},
+ 1: {"", int(^uint(0) >> 1), ""},
+ 2: {"-", 10, ""},
+ 3: {"gopher", 0, ""},
+ 4: {"-", -1, "negative"},
+ 5: {"--", -102, "negative"},
+ 6: {string(make([]byte, 255)), int((^uint(0))/255 + 1), "overflow"},
+ }
+
+ for i, tt := range tests {
+ err := repeat(tt.s, tt.count)
+ if tt.errStr == "" {
+ if err != nil {
+ t.Errorf("#%d panicked %v", i, err)
+ }
+ continue
+ }
+
+ if err == nil || !Contains(err.Error(), tt.errStr) {
+ t.Errorf("#%d expected %q got %q", i, tt.errStr, err)
+ }
+ }
+}
+
func runesEqual(a, b []rune) bool {
if len(a) != len(b) {
return false
@@ -1290,6 +1405,9 @@ func benchmarkCountHard(b *testing.B, sep string) {
func BenchmarkIndexHard1(b *testing.B) { benchmarkIndexHard(b, "<>") }
func BenchmarkIndexHard2(b *testing.B) { benchmarkIndexHard(b, "</pre>") }
func BenchmarkIndexHard3(b *testing.B) { benchmarkIndexHard(b, "<b>hello world</b>") }
+func BenchmarkIndexHard4(b *testing.B) {
+ benchmarkIndexHard(b, "<pre><b>hello</b><strong>world</strong></pre>")
+}
func BenchmarkLastIndexHard1(b *testing.B) { benchmarkLastIndexHard(b, "<>") }
func BenchmarkLastIndexHard2(b *testing.B) { benchmarkLastIndexHard(b, "</pre>") }
@@ -1381,3 +1499,31 @@ func BenchmarkRepeat(b *testing.B) {
Repeat("-", 80)
}
}
+
+func BenchmarkIndexAnyASCII(b *testing.B) {
+ x := Repeat("#", 4096) // Never matches set
+ cs := "0123456789abcdef"
+ for k := 1; k <= 4096; k <<= 4 {
+ for j := 1; j <= 16; j <<= 1 {
+ b.Run(fmt.Sprintf("%d:%d", k, j), func(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ IndexAny(x[:k], cs[:j])
+ }
+ })
+ }
+ }
+}
+
+func BenchmarkTrimASCII(b *testing.B) {
+ cs := "0123456789abcdef"
+ for k := 1; k <= 4096; k <<= 4 {
+ for j := 1; j <= 16; j <<= 1 {
+ b.Run(fmt.Sprintf("%d:%d", k, j), func(b *testing.B) {
+ x := Repeat(cs[:j], k) // Always matches set
+ for i := 0; i < b.N; i++ {
+ Trim(x[:k], cs[:j])
+ }
+ })
+ }
+ }
+}
diff --git a/src/sync/atomic/asm_amd64.s b/src/sync/atomic/asm_amd64.s
index 690907c..eddc6c5 100644
--- a/src/sync/atomic/asm_amd64.s
+++ b/src/sync/atomic/asm_amd64.s
@@ -2,6 +2,9 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// Note: some of these functions are semantically inlined
+// by the compiler (in src/cmd/compile/internal/gc/ssa.go).
+
// +build !race
#include "textflag.h"
diff --git a/src/sync/atomic/asm_amd64p32.s b/src/sync/atomic/asm_amd64p32.s
index 8164b3e..5c64dc0 100644
--- a/src/sync/atomic/asm_amd64p32.s
+++ b/src/sync/atomic/asm_amd64p32.s
@@ -2,6 +2,9 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// Note: some of these functions are semantically inlined
+// by the compiler (in src/cmd/compile/internal/gc/ssa.go).
+
#include "textflag.h"
TEXT ·SwapInt32(SB),NOSPLIT,$0-12
@@ -50,9 +53,6 @@ TEXT ·CompareAndSwapInt64(SB),NOSPLIT,$0-25
TEXT ·CompareAndSwapUint64(SB),NOSPLIT,$0-25
MOVL addr+0(FP), BX
- TESTL $7, BX
- JZ 2(PC)
- MOVL 0, BX // crash with nil ptr deref
MOVQ old+8(FP), AX
MOVQ new+16(FP), CX
LOCK
@@ -81,9 +81,6 @@ TEXT ·AddInt64(SB),NOSPLIT,$0-24
TEXT ·AddUint64(SB),NOSPLIT,$0-24
MOVL addr+0(FP), BX
- TESTL $7, BX
- JZ 2(PC)
- MOVL 0, BX // crash with nil ptr deref
MOVQ delta+8(FP), AX
MOVQ AX, CX
LOCK
@@ -106,9 +103,6 @@ TEXT ·LoadInt64(SB),NOSPLIT,$0-16
TEXT ·LoadUint64(SB),NOSPLIT,$0-16
MOVL addr+0(FP), AX
- TESTL $7, AX
- JZ 2(PC)
- MOVL 0, AX // crash with nil ptr deref
MOVQ 0(AX), AX
MOVQ AX, val+8(FP)
RET
@@ -136,9 +130,6 @@ TEXT ·StoreInt64(SB),NOSPLIT,$0-16
TEXT ·StoreUint64(SB),NOSPLIT,$0-16
MOVL addr+0(FP), BX
- TESTL $7, BX
- JZ 2(PC)
- MOVL 0, BX // crash with nil ptr deref
MOVQ val+8(FP), AX
XCHGQ AX, 0(BX)
RET
diff --git a/src/sync/atomic/asm_arm.s b/src/sync/atomic/asm_arm.s
index d35ea2a..77b0b24 100644
--- a/src/sync/atomic/asm_arm.s
+++ b/src/sync/atomic/asm_arm.s
@@ -35,11 +35,11 @@ casloop:
BNE casloop
MOVW $1, R0
DMB_ISH_7
- MOVBU R0, ret+12(FP)
+ MOVBU R0, swapped+12(FP)
RET
casfail:
MOVW $0, R0
- MOVBU R0, ret+12(FP)
+ MOVBU R0, swapped+12(FP)
RET
TEXT ·armCompareAndSwapUint64(SB),NOSPLIT,$0-21
@@ -49,10 +49,10 @@ TEXT ·armCompareAndSwapUint64(SB),NOSPLIT,$0-21
AND.S $7, R1, R2
BEQ 2(PC)
MOVW R2, (R2)
- MOVW oldlo+4(FP), R2
- MOVW oldhi+8(FP), R3
- MOVW newlo+12(FP), R4
- MOVW newhi+16(FP), R5
+ MOVW old_lo+4(FP), R2
+ MOVW old_hi+8(FP), R3
+ MOVW new_lo+12(FP), R4
+ MOVW new_hi+16(FP), R5
cas64loop:
// LDREXD and STREXD were introduced in ARMv6k.
LDREXD (R1), R6 // loads R6 and R7
@@ -66,11 +66,11 @@ cas64loop:
BNE cas64loop
MOVW $1, R0
DMB_ISH_7
- MOVBU R0, ret+20(FP)
+ MOVBU R0, swapped+20(FP)
RET
cas64fail:
MOVW $0, R0
- MOVBU R0, ret+20(FP)
+ MOVBU R0, swapped+20(FP)
RET
TEXT ·armAddUint32(SB),NOSPLIT,$0-12
@@ -85,7 +85,7 @@ addloop:
CMP $0, R0
BNE addloop
DMB_ISH_7
- MOVW R3, ret+8(FP)
+ MOVW R3, new+8(FP)
RET
TEXT ·armAddUint64(SB),NOSPLIT,$0-20
@@ -95,8 +95,8 @@ TEXT ·armAddUint64(SB),NOSPLIT,$0-20
AND.S $7, R1, R2
BEQ 2(PC)
MOVW R2, (R2)
- MOVW deltalo+4(FP), R2
- MOVW deltahi+8(FP), R3
+ MOVW delta_lo+4(FP), R2
+ MOVW delta_hi+8(FP), R3
add64loop:
// LDREXD and STREXD were introduced in ARMv6k.
LDREXD (R1), R4 // loads R4 and R5
@@ -107,8 +107,8 @@ add64loop:
CMP $0, R0
BNE add64loop
DMB_ISH_7
- MOVW R4, retlo+12(FP)
- MOVW R5, rethi+16(FP)
+ MOVW R4, new_lo+12(FP)
+ MOVW R5, new_hi+16(FP)
RET
TEXT ·armSwapUint32(SB),NOSPLIT,$0-12
@@ -132,8 +132,8 @@ TEXT ·armSwapUint64(SB),NOSPLIT,$0-20
AND.S $7, R1, R2
BEQ 2(PC)
MOVW R2, (R2)
- MOVW newlo+4(FP), R2
- MOVW newhi+8(FP), R3
+ MOVW new_lo+4(FP), R2
+ MOVW new_hi+8(FP), R3
swap64loop:
// LDREXD and STREXD were introduced in ARMv6k.
LDREXD (R1), R4 // loads R4 and R5
@@ -142,8 +142,8 @@ swap64loop:
CMP $0, R0
BNE swap64loop
DMB_ISH_7
- MOVW R4, oldlo+12(FP)
- MOVW R5, oldhi+16(FP)
+ MOVW R4, old_lo+12(FP)
+ MOVW R5, old_hi+16(FP)
RET
TEXT ·armLoadUint64(SB),NOSPLIT,$0-12
@@ -160,8 +160,8 @@ load64loop:
CMP $0, R0
BNE load64loop
DMB_ISH_7
- MOVW R2, vallo+4(FP)
- MOVW R3, valhi+8(FP)
+ MOVW R2, val_lo+4(FP)
+ MOVW R3, val_hi+8(FP)
RET
TEXT ·armStoreUint64(SB),NOSPLIT,$0-12
@@ -171,8 +171,8 @@ TEXT ·armStoreUint64(SB),NOSPLIT,$0-12
AND.S $7, R1, R2
BEQ 2(PC)
MOVW R2, (R2)
- MOVW vallo+4(FP), R2
- MOVW valhi+8(FP), R3
+ MOVW val_lo+4(FP), R2
+ MOVW val_hi+8(FP), R3
store64loop:
LDREXD (R1), R4 // loads R4 and R5
DMB_ISHST_7
diff --git a/src/sync/atomic/asm_mips64x.s b/src/sync/atomic/asm_mips64x.s
index b3c4627..b7d4168 100644
--- a/src/sync/atomic/asm_mips64x.s
+++ b/src/sync/atomic/asm_mips64x.s
@@ -104,7 +104,7 @@ TEXT ·AddUint32(SB),NOSPLIT,$0-20
MOVV R4, R1
SC(2, 4) // *R2 = R4
BEQ R4, -4(PC)
- MOVW R1, ret+16(FP)
+ MOVW R1, new+16(FP)
SYNC
RET
@@ -123,7 +123,7 @@ TEXT ·AddUint64(SB),NOSPLIT,$0-24
MOVV R4, R1
SCV(2, 4) // *R2 = R4
BEQ R4, -4(PC)
- MOVV R1, ret+16(FP)
+ MOVV R1, new+16(FP)
SYNC
RET
diff --git a/src/sync/atomic/asm_mipsx.s b/src/sync/atomic/asm_mipsx.s
new file mode 100644
index 0000000..cf3318f
--- /dev/null
+++ b/src/sync/atomic/asm_mipsx.s
@@ -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.
+
+// +build mips mipsle
+
+#include "textflag.h"
+
+TEXT ·SwapInt32(SB),NOSPLIT,$0-12
+ JMP runtime∕internal∕atomic·Xchg(SB)
+
+TEXT ·SwapUint32(SB),NOSPLIT,$0-12
+ JMP runtime∕internal∕atomic·Xchg(SB)
+
+TEXT ·SwapInt64(SB),NOSPLIT,$0-24
+ JMP runtime∕internal∕atomic·Xchg64(SB)
+
+TEXT ·SwapUint64(SB),NOSPLIT,$0-24
+ JMP runtime∕internal∕atomic·Xchg64(SB)
+
+TEXT ·SwapUintptr(SB),NOSPLIT,$0-20
+ JMP runtime∕internal∕atomic·Xchg(SB)
+
+TEXT ·CompareAndSwapInt32(SB),NOSPLIT,$0-13
+ JMP runtime∕internal∕atomic·Cas(SB)
+
+TEXT ·CompareAndSwapUint32(SB),NOSPLIT,$0-13
+ JMP runtime∕internal∕atomic·Cas(SB)
+
+TEXT ·CompareAndSwapUintptr(SB),NOSPLIT,$0-13
+ JMP runtime∕internal∕atomic·Cas(SB)
+
+TEXT ·CompareAndSwapInt64(SB),NOSPLIT,$0-21
+ JMP runtime∕internal∕atomic·Cas64(SB)
+
+TEXT ·CompareAndSwapUint64(SB),NOSPLIT,$0-21
+ JMP runtime∕internal∕atomic·Cas64(SB)
+
+TEXT ·AddInt32(SB),NOSPLIT,$0-12
+ JMP runtime∕internal∕atomic·Xadd(SB)
+
+TEXT ·AddUint32(SB),NOSPLIT,$0-12
+ JMP runtime∕internal∕atomic·Xadd(SB)
+
+TEXT ·AddUintptr(SB),NOSPLIT,$0-12
+ JMP runtime∕internal∕atomic·Xadd(SB)
+
+TEXT ·AddInt64(SB),NOSPLIT,$0-20
+ JMP runtime∕internal∕atomic·Xadd64(SB)
+
+TEXT ·AddUint64(SB),NOSPLIT,$0-20
+ JMP runtime∕internal∕atomic·Xadd64(SB)
+
+TEXT ·LoadInt32(SB),NOSPLIT,$0-8
+ JMP runtime∕internal∕atomic·Load(SB)
+
+TEXT ·LoadUint32(SB),NOSPLIT,$0-8
+ JMP runtime∕internal∕atomic·Load(SB)
+
+TEXT ·LoadInt64(SB),NOSPLIT,$0-12
+ JMP runtime∕internal∕atomic·Load64(SB)
+
+TEXT ·LoadUint64(SB),NOSPLIT,$0-12
+ JMP runtime∕internal∕atomic·Load64(SB)
+
+TEXT ·LoadUintptr(SB),NOSPLIT,$0-8
+ JMP runtime∕internal∕atomic·Load(SB)
+
+TEXT ·LoadPointer(SB),NOSPLIT,$0-8
+ JMP runtime∕internal∕atomic·Load(SB)
+
+TEXT ·StoreInt32(SB),NOSPLIT,$0-8
+ JMP runtime∕internal∕atomic·Store(SB)
+
+TEXT ·StoreUint32(SB),NOSPLIT,$0-8
+ JMP runtime∕internal∕atomic·Store(SB)
+
+TEXT ·StoreInt64(SB),NOSPLIT,$0-12
+ JMP runtime∕internal∕atomic·Store64(SB)
+
+TEXT ·StoreUint64(SB),NOSPLIT,$0-12
+ JMP runtime∕internal∕atomic·Store64(SB)
+
+TEXT ·StoreUintptr(SB),NOSPLIT,$0-8
+ JMP runtime∕internal∕atomic·Store(SB)
diff --git a/src/sync/atomic/asm_ppc64x.s b/src/sync/atomic/asm_ppc64x.s
index 2474e96..44e2669 100644
--- a/src/sync/atomic/asm_ppc64x.s
+++ b/src/sync/atomic/asm_ppc64x.s
@@ -92,7 +92,7 @@ TEXT ·AddUint32(SB),NOSPLIT,$0-20
STWCCC R5, (R3)
BNE -3(PC)
ISYNC
- MOVW R5, ret+16(FP)
+ MOVW R5, new+16(FP)
RET
TEXT ·AddUintptr(SB),NOSPLIT,$0-24
@@ -110,7 +110,7 @@ TEXT ·AddUint64(SB),NOSPLIT,$0-24
STDCCC R5, (R3)
BNE -3(PC)
ISYNC
- MOVD R5, ret+16(FP)
+ MOVD R5, new+16(FP)
RET
TEXT ·LoadInt32(SB),NOSPLIT,$0-12
diff --git a/src/sync/atomic/asm_s390x.s b/src/sync/atomic/asm_s390x.s
index b5389be..cf61013 100644
--- a/src/sync/atomic/asm_s390x.s
+++ b/src/sync/atomic/asm_s390x.s
@@ -37,15 +37,15 @@ TEXT ·CompareAndSwapInt32(SB),NOSPLIT,$0-17
BR ·CompareAndSwapUint32(SB)
TEXT ·CompareAndSwapUint32(SB),NOSPLIT,$0-17
- MOVD ptr+0(FP), R3
+ MOVD addr+0(FP), R3
MOVWZ old+8(FP), R4
MOVWZ new+12(FP), R5
CS R4, R5, 0(R3) // if R4==(R3) then (R3)=R5 else R4=(R3)
BNE cas_fail
- MOVB $1, ret+16(FP)
+ MOVB $1, swapped+16(FP)
RET
cas_fail:
- MOVB $0, ret+16(FP)
+ MOVB $0, swapped+16(FP)
RET
TEXT ·CompareAndSwapUintptr(SB),NOSPLIT,$0-25
@@ -55,29 +55,29 @@ TEXT ·CompareAndSwapInt64(SB),NOSPLIT,$0-25
BR ·CompareAndSwapUint64(SB)
TEXT ·CompareAndSwapUint64(SB),NOSPLIT,$0-25
- MOVD ptr+0(FP), R3
+ MOVD addr+0(FP), R3
MOVD old+8(FP), R4
MOVD new+16(FP), R5
CSG R4, R5, 0(R3) // if R4==(R3) then (R3)=R5 else R4=(R3)
BNE cas64_fail
- MOVB $1, ret+24(FP)
+ MOVB $1, swapped+24(FP)
RET
cas64_fail:
- MOVB $0, ret+24(FP)
+ MOVB $0, swapped+24(FP)
RET
TEXT ·AddInt32(SB),NOSPLIT,$0-20
BR ·AddUint32(SB)
TEXT ·AddUint32(SB),NOSPLIT,$0-20
- MOVD ptr+0(FP), R4
+ MOVD addr+0(FP), R4
MOVWZ delta+8(FP), R5
MOVWZ (R4), R3
repeat:
ADD R3, R5, R6
CS R3, R6, (R4) // if R3==(R4) then (R4)=R6 else R3=(R4)
BNE repeat
- MOVW R6, ret+16(FP)
+ MOVW R6, new+16(FP)
RET
TEXT ·AddUintptr(SB),NOSPLIT,$0-24
@@ -87,14 +87,14 @@ TEXT ·AddInt64(SB),NOSPLIT,$0-24
BR ·AddUint64(SB)
TEXT ·AddUint64(SB),NOSPLIT,$0-24
- MOVD ptr+0(FP), R4
+ MOVD addr+0(FP), R4
MOVD delta+8(FP), R5
MOVD (R4), R3
repeat:
ADD R3, R5, R6
CSG R3, R6, (R4) // if R3==(R4) then (R4)=R6 else R3=(R4)
BNE repeat
- MOVD R6, ret+16(FP)
+ MOVD R6, new+16(FP)
RET
TEXT ·LoadInt32(SB),NOSPLIT,$0-12
@@ -125,7 +125,7 @@ TEXT ·StoreInt32(SB),NOSPLIT,$0-12
BR ·StoreUint32(SB)
TEXT ·StoreUint32(SB),NOSPLIT,$0-12
- MOVD ptr+0(FP), R3
+ MOVD addr+0(FP), R3
MOVW val+8(FP), R4
MOVW R4, 0(R3)
RET
diff --git a/src/sync/atomic/atomic_test.go b/src/sync/atomic/atomic_test.go
index deb3ccb..6d0831c 100644
--- a/src/sync/atomic/atomic_test.go
+++ b/src/sync/atomic/atomic_test.go
@@ -1226,10 +1226,12 @@ func TestStoreLoadSeqCst32(t *testing.T) {
}
his := LoadInt32(&ack[he][i%3])
if (my != i && my != i-1) || (his != i && his != i-1) {
- t.Fatalf("invalid values: %d/%d (%d)", my, his, i)
+ t.Errorf("invalid values: %d/%d (%d)", my, his, i)
+ break
}
if my != i && his != i {
- t.Fatalf("store/load are not sequentially consistent: %d/%d (%d)", my, his, i)
+ t.Errorf("store/load are not sequentially consistent: %d/%d (%d)", my, his, i)
+ break
}
StoreInt32(&ack[me][(i-1)%3], -1)
}
@@ -1269,10 +1271,12 @@ func TestStoreLoadSeqCst64(t *testing.T) {
}
his := LoadInt64(&ack[he][i%3])
if (my != i && my != i-1) || (his != i && his != i-1) {
- t.Fatalf("invalid values: %d/%d (%d)", my, his, i)
+ t.Errorf("invalid values: %d/%d (%d)", my, his, i)
+ break
}
if my != i && his != i {
- t.Fatalf("store/load are not sequentially consistent: %d/%d (%d)", my, his, i)
+ t.Errorf("store/load are not sequentially consistent: %d/%d (%d)", my, his, i)
+ break
}
StoreInt64(&ack[me][(i-1)%3], -1)
}
@@ -1317,7 +1321,8 @@ func TestStoreLoadRelAcq32(t *testing.T) {
d1 := X.data1
d2 := X.data2
if d1 != i || d2 != float32(i) {
- t.Fatalf("incorrect data: %d/%g (%d)", d1, d2, i)
+ t.Errorf("incorrect data: %d/%g (%d)", d1, d2, i)
+ break
}
}
}
@@ -1365,7 +1370,8 @@ func TestStoreLoadRelAcq64(t *testing.T) {
d1 := X.data1
d2 := X.data2
if d1 != i || d2 != float64(i) {
- t.Fatalf("incorrect data: %d/%g (%d)", d1, d2, i)
+ t.Errorf("incorrect data: %d/%g (%d)", d1, d2, i)
+ break
}
}
}
@@ -1389,8 +1395,15 @@ func TestUnaligned64(t *testing.T) {
// Unaligned 64-bit atomics on 32-bit systems are
// a continual source of pain. Test that on 32-bit systems they crash
// instead of failing silently.
- if unsafe.Sizeof(int(0)) != 4 {
- t.Skip("test only runs on 32-bit systems")
+
+ switch runtime.GOARCH {
+ default:
+ if unsafe.Sizeof(int(0)) != 4 {
+ t.Skip("test only runs on 32-bit systems")
+ }
+ case "amd64p32":
+ // amd64p32 can handle unaligned atomics.
+ t.Skipf("test not needed on %v", runtime.GOARCH)
}
x := make([]uint32, 4)
diff --git a/src/sync/cond_test.go b/src/sync/cond_test.go
index 7b07295..9019f8f 100644
--- a/src/sync/cond_test.go
+++ b/src/sync/cond_test.go
@@ -137,7 +137,7 @@ func TestRace(t *testing.T) {
x = 1
c.Wait()
if x != 2 {
- t.Fatal("want 2")
+ t.Error("want 2")
}
x = 3
c.Signal()
@@ -165,7 +165,7 @@ func TestRace(t *testing.T) {
if x == 2 {
c.Wait()
if x != 3 {
- t.Fatal("want 3")
+ t.Error("want 3")
}
break
}
diff --git a/src/sync/example_pool_test.go b/src/sync/example_pool_test.go
new file mode 100644
index 0000000..8288d41
--- /dev/null
+++ b/src/sync/example_pool_test.go
@@ -0,0 +1,45 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package sync_test
+
+import (
+ "bytes"
+ "io"
+ "os"
+ "sync"
+ "time"
+)
+
+var bufPool = sync.Pool{
+ New: func() interface{} {
+ // The Pool's New function should generally only return pointer
+ // types, since a pointer can be put into the return interface
+ // value without an allocation:
+ return new(bytes.Buffer)
+ },
+}
+
+// timeNow is a fake version of time.Now for tests.
+func timeNow() time.Time {
+ return time.Unix(1136214245, 0)
+}
+
+func Log(w io.Writer, key, val string) {
+ b := bufPool.Get().(*bytes.Buffer)
+ b.Reset()
+ // Replace this with time.Now() in a real logger.
+ b.WriteString(timeNow().UTC().Format(time.RFC3339))
+ b.WriteByte(' ')
+ b.WriteString(key)
+ b.WriteByte('=')
+ b.WriteString(val)
+ w.Write(b.Bytes())
+ bufPool.Put(b)
+}
+
+func ExamplePool() {
+ Log(os.Stdout, "path", "/search?q=flowers")
+ // Output: 2006-01-02T15:04:05Z path=/search?q=flowers
+}
diff --git a/src/sync/mutex.go b/src/sync/mutex.go
index 9089279..8c9366f 100644
--- a/src/sync/mutex.go
+++ b/src/sync/mutex.go
@@ -16,6 +16,8 @@ import (
"unsafe"
)
+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.
@@ -74,7 +76,7 @@ func (m *Mutex) Lock() {
// The goroutine has been woken from sleep,
// so we need to reset the flag in either case.
if new&mutexWoken == 0 {
- panic("sync: inconsistent mutex state")
+ throw("sync: inconsistent mutex state")
}
new &^= mutexWoken
}
@@ -82,7 +84,7 @@ func (m *Mutex) Lock() {
if old&mutexLocked == 0 {
break
}
- runtime_Semacquire(&m.sema)
+ runtime_SemacquireMutex(&m.sema)
awoke = true
iter = 0
}
@@ -108,7 +110,7 @@ func (m *Mutex) Unlock() {
// Fast path: drop lock bit.
new := atomic.AddInt32(&m.state, -mutexLocked)
if (new+mutexLocked)&mutexLocked == 0 {
- panic("sync: unlock of unlocked mutex")
+ throw("sync: unlock of unlocked mutex")
}
old := new
diff --git a/src/sync/mutex_test.go b/src/sync/mutex_test.go
index 91a4855..88dbccf 100644
--- a/src/sync/mutex_test.go
+++ b/src/sync/mutex_test.go
@@ -7,7 +7,12 @@
package sync_test
import (
+ "fmt"
+ "internal/testenv"
+ "os"
+ "os/exec"
"runtime"
+ "strings"
. "sync"
"testing"
)
@@ -61,6 +66,10 @@ func HammerMutex(m *Mutex, loops int, cdone chan bool) {
}
func TestMutex(t *testing.T) {
+ if n := runtime.SetMutexProfileFraction(1); n != 0 {
+ t.Logf("got mutexrate %d expected 0", n)
+ }
+ defer runtime.SetMutexProfileFraction(0)
m := new(Mutex)
c := make(chan bool)
for i := 0; i < 10; i++ {
@@ -71,17 +80,98 @@ func TestMutex(t *testing.T) {
}
}
-func TestMutexPanic(t *testing.T) {
- defer func() {
- if recover() == nil {
- t.Fatalf("unlock of unlocked mutex did not panic")
+var misuseTests = []struct {
+ name string
+ f func()
+}{
+ {
+ "Mutex.Unlock",
+ func() {
+ var mu Mutex
+ mu.Unlock()
+ },
+ },
+ {
+ "Mutex.Unlock2",
+ func() {
+ var mu Mutex
+ mu.Lock()
+ mu.Unlock()
+ mu.Unlock()
+ },
+ },
+ {
+ "RWMutex.Unlock",
+ func() {
+ var mu RWMutex
+ mu.Unlock()
+ },
+ },
+ {
+ "RWMutex.Unlock2",
+ func() {
+ var mu RWMutex
+ mu.RLock()
+ mu.Unlock()
+ },
+ },
+ {
+ "RWMutex.Unlock3",
+ func() {
+ var mu RWMutex
+ mu.Lock()
+ mu.Unlock()
+ mu.Unlock()
+ },
+ },
+ {
+ "RWMutex.RUnlock",
+ func() {
+ var mu RWMutex
+ mu.RUnlock()
+ },
+ },
+ {
+ "RWMutex.RUnlock2",
+ func() {
+ var mu RWMutex
+ mu.Lock()
+ mu.RUnlock()
+ },
+ },
+ {
+ "RWMutex.RUnlock3",
+ func() {
+ var mu RWMutex
+ mu.RLock()
+ mu.RUnlock()
+ mu.RUnlock()
+ },
+ },
+}
+
+func init() {
+ if len(os.Args) == 3 && os.Args[1] == "TESTMISUSE" {
+ for _, test := range misuseTests {
+ if test.name == os.Args[2] {
+ test.f()
+ fmt.Printf("test completed\n")
+ os.Exit(0)
+ }
}
- }()
+ fmt.Printf("unknown test\n")
+ os.Exit(0)
+ }
+}
- var mu Mutex
- mu.Lock()
- mu.Unlock()
- mu.Unlock()
+func TestMutexMisuse(t *testing.T) {
+ testenv.MustHaveExec(t)
+ for _, test := range misuseTests {
+ out, err := exec.Command(os.Args[0], "TESTMISUSE", test.name).CombinedOutput()
+ if err == nil || !strings.Contains(string(out), "unlocked") {
+ t.Errorf("%s: did not find failure with message about unlocked lock: %s\n%s\n", test.name, err, out)
+ }
+ }
}
func BenchmarkMutexUncontended(b *testing.B) {
diff --git a/src/sync/pool.go b/src/sync/pool.go
index bf29d88..0acdbde 100644
--- a/src/sync/pool.go
+++ b/src/sync/pool.go
@@ -61,29 +61,49 @@ type poolLocal struct {
pad [128]byte // Prevents false sharing.
}
+// from runtime
+func fastrand() uint32
+
+var poolRaceHash [128]uint64
+
+// poolRaceAddr returns an address to use as the synchronization point
+// for race detector logic. We don't use the actual pointer stored in x
+// directly, for fear of conflicting with other synchronization on that address.
+// Instead, we hash the pointer to get an index into poolRaceHash.
+// See discussion on golang.org/cl/31589.
+func poolRaceAddr(x interface{}) unsafe.Pointer {
+ ptr := uintptr((*[2]unsafe.Pointer)(unsafe.Pointer(&x))[1])
+ h := uint32((uint64(uint32(ptr)) * 0x85ebca6b) >> 16)
+ return unsafe.Pointer(&poolRaceHash[h%uint32(len(poolRaceHash))])
+}
+
// Put adds x to the pool.
func (p *Pool) Put(x interface{}) {
- if race.Enabled {
- // Under race detector the Pool degenerates into no-op.
- // It's conforming, simple and does not introduce excessive
- // happens-before edges between unrelated goroutines.
- return
- }
if x == nil {
return
}
+ if race.Enabled {
+ if fastrand()%4 == 0 {
+ // Randomly drop x on floor.
+ return
+ }
+ race.ReleaseMerge(poolRaceAddr(x))
+ race.Disable()
+ }
l := p.pin()
if l.private == nil {
l.private = x
x = nil
}
runtime_procUnpin()
- if x == nil {
- return
+ if x != nil {
+ l.Lock()
+ l.shared = append(l.shared, x)
+ l.Unlock()
+ }
+ if race.Enabled {
+ race.Enable()
}
- l.Lock()
- l.shared = append(l.shared, x)
- l.Unlock()
}
// Get selects an arbitrary item from the Pool, removes it from the
@@ -96,29 +116,34 @@ func (p *Pool) Put(x interface{}) {
// the result of calling p.New.
func (p *Pool) Get() interface{} {
if race.Enabled {
- if p.New != nil {
- return p.New()
- }
- return nil
+ race.Disable()
}
l := p.pin()
x := l.private
l.private = nil
runtime_procUnpin()
- if x != nil {
- return x
+ if x == nil {
+ l.Lock()
+ last := len(l.shared) - 1
+ if last >= 0 {
+ x = l.shared[last]
+ l.shared = l.shared[:last]
+ }
+ l.Unlock()
+ if x == nil {
+ x = p.getSlow()
+ }
}
- l.Lock()
- last := len(l.shared) - 1
- if last >= 0 {
- x = l.shared[last]
- l.shared = l.shared[:last]
+ if race.Enabled {
+ race.Enable()
+ if x != nil {
+ race.Acquire(poolRaceAddr(x))
+ }
}
- l.Unlock()
- if x != nil {
- return x
+ if x == nil && p.New != nil {
+ x = p.New()
}
- return p.getSlow()
+ return x
}
func (p *Pool) getSlow() (x interface{}) {
@@ -140,10 +165,6 @@ func (p *Pool) getSlow() (x interface{}) {
}
l.Unlock()
}
-
- if x == nil && p.New != nil {
- x = p.New()
- }
return x
}
diff --git a/src/sync/pool_test.go b/src/sync/pool_test.go
index fa1a27b..5a38cbf 100644
--- a/src/sync/pool_test.go
+++ b/src/sync/pool_test.go
@@ -127,7 +127,8 @@ func TestPoolStress(t *testing.T) {
p.Put(v)
v = p.Get()
if v != nil && v.(int) != 0 {
- t.Fatalf("expect 0, got %v", v)
+ t.Errorf("expect 0, got %v", v)
+ break
}
}
done <- true
diff --git a/src/sync/runtime.go b/src/sync/runtime.go
index 96c56c8..4d22ce6 100644
--- a/src/sync/runtime.go
+++ b/src/sync/runtime.go
@@ -13,6 +13,9 @@ import "unsafe"
// library and should not be used directly.
func runtime_Semacquire(s *uint32)
+// SemacquireMutex is like Semacquire, but for profiling contended Mutexes.
+func runtime_SemacquireMutex(*uint32)
+
// 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
diff --git a/src/sync/rwmutex.go b/src/sync/rwmutex.go
index 6734360..71064ee 100644
--- a/src/sync/rwmutex.go
+++ b/src/sync/rwmutex.go
@@ -61,7 +61,7 @@ func (rw *RWMutex) RUnlock() {
if r := atomic.AddInt32(&rw.readerCount, -1); r < 0 {
if r+1 == 0 || r+1 == -rwmutexMaxReaders {
race.Enable()
- panic("sync: RUnlock of unlocked RWMutex")
+ throw("sync: RUnlock of unlocked RWMutex")
}
// A writer is pending.
if atomic.AddInt32(&rw.readerWait, -1) == 0 {
@@ -115,7 +115,7 @@ func (rw *RWMutex) Unlock() {
r := atomic.AddInt32(&rw.readerCount, rwmutexMaxReaders)
if r >= rwmutexMaxReaders {
race.Enable()
- panic("sync: Unlock of unlocked RWMutex")
+ throw("sync: Unlock of unlocked RWMutex")
}
// Unblock blocked readers, if any.
for i := 0; i < int(r); i++ {
diff --git a/src/sync/rwmutex_test.go b/src/sync/rwmutex_test.go
index f625bc3..0436f97 100644
--- a/src/sync/rwmutex_test.go
+++ b/src/sync/rwmutex_test.go
@@ -155,48 +155,6 @@ func TestRLocker(t *testing.T) {
}
}
-func TestUnlockPanic(t *testing.T) {
- defer func() {
- if recover() == nil {
- t.Fatalf("unlock of unlocked RWMutex did not panic")
- }
- }()
- var mu RWMutex
- mu.Unlock()
-}
-
-func TestUnlockPanic2(t *testing.T) {
- defer func() {
- if recover() == nil {
- t.Fatalf("unlock of unlocked RWMutex did not panic")
- }
- }()
- var mu RWMutex
- mu.RLock()
- mu.Unlock()
-}
-
-func TestRUnlockPanic(t *testing.T) {
- defer func() {
- if recover() == nil {
- t.Fatalf("read unlock of unlocked RWMutex did not panic")
- }
- }()
- var mu RWMutex
- mu.RUnlock()
-}
-
-func TestRUnlockPanic2(t *testing.T) {
- defer func() {
- if recover() == nil {
- t.Fatalf("read unlock of unlocked RWMutex did not panic")
- }
- }()
- var mu RWMutex
- mu.Lock()
- mu.RUnlock()
-}
-
func BenchmarkRWMutexUncontended(b *testing.B) {
type PaddedRWMutex struct {
RWMutex
diff --git a/src/syscall/asm9_unix1_amd64.s b/src/syscall/asm9_unix1_amd64.s
new file mode 100644
index 0000000..29af78c
--- /dev/null
+++ b/src/syscall/asm9_unix1_amd64.s
@@ -0,0 +1,45 @@
+// +build netbsd openbsd
+
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "textflag.h"
+#include "funcdata.h"
+
+//
+// Syscall9 support for AMD64, NetBSD and OpenBSD
+//
+
+// func Syscall9(trap int64, a1, a2, a3, a4, a5, a6, a7, a8, a9 int64) (r1, r2, err int64);
+TEXT ·Syscall9(SB),NOSPLIT,$0-104
+ CALL runtime·entersyscall(SB)
+ MOVQ num+0(FP), AX // syscall entry
+ MOVQ a1+8(FP), DI
+ MOVQ a2+16(FP), SI
+ MOVQ a3+24(FP), DX
+ MOVQ a4+32(FP), R10
+ MOVQ a5+40(FP), R8
+ MOVQ a6+48(FP), R9
+ MOVQ a7+56(FP), R11
+ MOVQ a8+64(FP), R12
+ MOVQ a9+72(FP), R13
+ SUBQ $32, SP
+ MOVQ R11, 8(SP) // arg 7
+ MOVQ R12, 16(SP) // arg 8
+ MOVQ R13, 24(SP) // arg 9
+ SYSCALL
+ JCC ok9
+ ADDQ $32, SP
+ MOVQ $-1, 88(SP) // r1
+ MOVQ $0, 96(SP) // r2
+ MOVQ AX, 104(SP) // errno
+ CALL runtime·exitsyscall(SB)
+ RET
+ok9:
+ ADDQ $32, SP
+ MOVQ AX, 88(SP) // r1
+ MOVQ DX, 96(SP) // r2
+ MOVQ $0, 104(SP) // errno
+ CALL runtime·exitsyscall(SB)
+ RET
diff --git a/src/syscall/asm9_unix2_amd64.s b/src/syscall/asm9_unix2_amd64.s
new file mode 100644
index 0000000..11a6c1f
--- /dev/null
+++ b/src/syscall/asm9_unix2_amd64.s
@@ -0,0 +1,46 @@
+// +build dragonfly freebsd
+
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "textflag.h"
+#include "funcdata.h"
+
+//
+// Syscall9 support for AMD64, DragonFly and FreeBSD
+//
+
+// func Syscall9(trap int64, a1, a2, a3, a4, a5, a6, a7, a8, a9 int64) (r1, r2, err int64);
+TEXT ·Syscall9(SB),NOSPLIT,$0-104
+ CALL runtime·entersyscall(SB)
+ MOVQ num+0(FP), AX // syscall entry
+ MOVQ a1+8(FP), DI
+ MOVQ a2+16(FP), SI
+ MOVQ a3+24(FP), DX
+ MOVQ a4+32(FP), R10
+ MOVQ a5+40(FP), R8
+ MOVQ a6+48(FP), R9
+
+ // shift around the last three arguments so they're at the
+ // top of the stack when the syscall is called.
+ MOVQ a7+56(FP), R11 // arg 7
+ MOVQ R11, 8(SP)
+ MOVQ a8+64(FP), R11 // arg 8
+ MOVQ R11, 16(SP)
+ MOVQ a9+72(FP), R11 // arg 9
+ MOVQ R11, 24(SP)
+
+ SYSCALL
+ JCC ok9
+ MOVQ $-1, r1+80(FP) // r1
+ MOVQ $0, r2+88(FP) // r2
+ MOVQ AX, err+96(FP) // errno
+ CALL runtime·exitsyscall(SB)
+ RET
+ok9:
+ MOVQ AX, r1+80(FP) // r1
+ MOVQ DX, r2+88(FP) // r2
+ MOVQ $0, err+96(FP) // errno
+ CALL runtime·exitsyscall(SB)
+ RET
diff --git a/src/syscall/asm_darwin_arm.s b/src/syscall/asm_darwin_arm.s
index 1a2aad0..4eae005 100644
--- a/src/syscall/asm_darwin_arm.s
+++ b/src/syscall/asm_darwin_arm.s
@@ -11,124 +11,123 @@
// func Syscall(syscall uintptr, a1, a2, a3 uintptr) (r1, r2, err uintptr)
TEXT ·Syscall(SB),NOSPLIT,$0-28
BL runtime·entersyscall(SB)
- MOVW syscall+4(SP), R12
- MOVW a1+8(SP), R0
- MOVW a2+12(SP), R1
- MOVW a3+16(SP), R2
+ MOVW trap+0(FP), R12
+ MOVW a1+4(FP), R0
+ MOVW a2+8(FP), R1
+ MOVW a3+12(FP), R2
SWI $0x80
BCC ok
MOVW $-1, R1
- MOVW R1, r1+20(SP) // r1
+ MOVW R1, r1+16(FP) // r1
MOVW $0, R2
- MOVW R2, r2+24(SP) // r2
- MOVW R0, errno+28(SP) // errno
+ MOVW R2, r2+20(FP) // r2
+ MOVW R0, err+24(FP) // err
BL runtime·exitsyscall(SB)
RET
ok:
- MOVW R0, r1+20(SP) // r1
- MOVW R1, r2+24(SP) // r2
+ MOVW R0, r1+16(FP) // r1
+ MOVW R1, r2+20(FP) // r2
MOVW $0, R0
- MOVW R0, errno+28(SP) // errno
+ MOVW R0, err+24(FP) // err
BL runtime·exitsyscall(SB)
RET
// func RawSyscall(trap uintptr, a1, a2, a3 uintptr) (r1, r2, err uintptr)
TEXT ·RawSyscall(SB),NOSPLIT,$0-28
- MOVW syscall+4(SP), R12 // syscall entry
- MOVW a1+8(SP), R0
- MOVW a2+12(SP), R1
- MOVW a3+16(SP), R2
+ MOVW trap+0(FP), R12 // syscall entry
+ MOVW a1+4(FP), R0
+ MOVW a2+8(FP), R1
+ MOVW a3+12(FP), R2
SWI $0x80
BCC ok1
MOVW $-1, R1
- MOVW R1, r1+20(SP) // r1
+ MOVW R1, r1+16(FP) // r1
MOVW $0, R2
- MOVW R2, r2+24(SP) // r2
- MOVW R0, errno+28(SP) // errno
+ MOVW R2, r2+20(FP) // r2
+ MOVW R0, err+24(FP) // err
RET
ok1:
- MOVW R0, r1+20(SP) // r1
- MOVW R1, r2+24(SP) // r2
+ MOVW R0, r1+16(FP) // r1
+ MOVW R1, r2+20(FP) // r2
MOVW $0, R0
- MOVW R0, errno+28(SP) // errno
+ MOVW R0, err+24(FP) // err
RET
// func Syscall6(trap uintptr, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr)
TEXT ·Syscall6(SB),NOSPLIT,$0-40
BL runtime·entersyscall(SB)
- MOVW syscall+4(SP), R12 // syscall entry
- MOVW a1+8(SP), R0
- MOVW a2+12(SP), R1
- MOVW a3+16(SP), R2
- MOVW a4+20(SP), R3
- MOVW a5+24(SP), R4
- MOVW a6+28(SP), R5
+ MOVW trap+0(FP), R12 // syscall entry
+ MOVW a1+4(FP), R0
+ MOVW a2+8(FP), R1
+ MOVW a3+12(FP), R2
+ MOVW a4+16(FP), R3
+ MOVW a5+20(FP), R4
+ MOVW a6+24(FP), R5
SWI $0x80
BCC ok6
MOVW $-1, R1
- MOVW R1, r1+32(SP) // r1
+ MOVW R1, r1+28(FP) // r1
MOVW $0, R2
- MOVW R2, r2+36(SP) // r2
- MOVW R0, errno+40(SP) // errno
+ MOVW R2, r2+32(FP) // r2
+ MOVW R0, err+36(FP) // err
BL runtime·exitsyscall(SB)
RET
ok6:
- MOVW R0, r1+32(SP) // r1
- MOVW R1, r2+36(SP) // r2
+ MOVW R0, r1+28(FP) // r1
+ MOVW R1, r2+32(FP) // r2
MOVW $0, R0
- MOVW R0, errno+40(SP) // errno
+ MOVW R0, err+36(FP) // err
BL runtime·exitsyscall(SB)
RET
// func RawSyscall6(trap uintptr, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr)
TEXT ·RawSyscall6(SB),NOSPLIT,$0-40
- MOVW trap+4(SP), R12 // syscall entry
- MOVW a1+8(SP), R0
- MOVW a2+12(SP), R1
- MOVW a3+16(SP), R2
- MOVW a4+20(SP), R3
- MOVW a5+24(SP), R4
- MOVW a6+28(SP), R5
+ MOVW trap+0(FP), R12 // syscall entry
+ MOVW a1+4(FP), R0
+ MOVW a2+8(FP), R1
+ MOVW a3+12(FP), R2
+ MOVW a4+16(FP), R3
+ MOVW a5+20(FP), R4
+ MOVW a6+24(FP), R5
SWI $0x80
BCC ok2
MOVW $-1, R1
- MOVW R1, r1+32(SP) // r1
+ MOVW R1, r1+28(FP) // r1
MOVW $0, R2
- MOVW R2, r2+36(SP) // r2
- MOVW R0, errno+40(SP) // errno
+ MOVW R2, r2+32(FP) // r2
+ MOVW R0, err+36(FP) // err
RET
ok2:
- MOVW R0, r1+32(SP) // r1
- MOVW R1, r2+36(SP) // r2
+ MOVW R0, r1+28(FP) // r1
+ MOVW R1, r2+32(FP) // r2
MOVW $0, R0
- MOVW R0, errno+40(SP) // errno
+ MOVW R0, err+36(FP) // err
RET
// Actually Syscall7.
TEXT ·Syscall9(SB),NOSPLIT,$0-52
BL runtime·entersyscall(SB)
- MOVW syscall+4(SP), R12 // syscall entry
- MOVW a1+8(SP), R0
- MOVW a2+12(SP), R1
- MOVW a3+16(SP), R2
- MOVW a4+20(SP), R3
- MOVW a5+24(SP), R4
- MOVW a6+28(SP), R5
- MOVW a7+32(SP), R6
+ MOVW num+0(FP), R12 // syscall entry
+ MOVW a1+4(FP), R0
+ MOVW a2+8(FP), R1
+ MOVW a3+12(FP), R2
+ MOVW a4+16(FP), R3
+ MOVW a5+20(FP), R4
+ MOVW a6+24(FP), R5
+ MOVW a7+28(FP), R6
SWI $0x80
BCC ok9
MOVW $-1, R1
- MOVW R1, r1+44(SP) // r1
+ MOVW R1, r1+40(FP) // r1
MOVW $0, R2
- MOVW R2, r2+48(SP) // r2
- MOVW R0, errno+52(SP) // errno
+ MOVW R2, r2+44(FP) // r2
+ MOVW R0, err+48(FP) // err
BL runtime·exitsyscall(SB)
RET
ok9:
- MOVW R0, r1+44(SP) // r1
- MOVW R1, r2+48(SP) // r2
+ MOVW R0, r1+40(FP) // r1
+ MOVW R1, r2+44(FP) // r2
MOVW $0, R0
- MOVW R0, errno+52(SP) // errno
+ MOVW R0, err+48(FP) // err
BL runtime·exitsyscall(SB)
RET
-
diff --git a/src/syscall/asm_darwin_arm64.s b/src/syscall/asm_darwin_arm64.s
index e18ff6a..95b6dc0 100644
--- a/src/syscall/asm_darwin_arm64.s
+++ b/src/syscall/asm_darwin_arm64.s
@@ -8,10 +8,10 @@
// System call support for ARM64, Darwin
//
-// func Syscall(syscall uintptr, a1, a2, a3 uintptr) (r1, r2, err uintptr)
+// func Syscall(trap uintptr, a1, a2, a3 uintptr) (r1, r2, err uintptr)
TEXT ·Syscall(SB),NOSPLIT,$0-56
BL runtime·entersyscall(SB)
- MOVD syscall+0(FP), R16
+ MOVD trap+0(FP), R16
MOVD a1+8(FP), R0
MOVD a2+16(FP), R1
MOVD a3+24(FP), R2
@@ -20,19 +20,19 @@ TEXT ·Syscall(SB),NOSPLIT,$0-56
MOVD $-1, R1
MOVD R1, r1+32(FP) // r1
MOVD ZR, r2+40(FP) // r2
- MOVD R0, errno+48(FP) // errno
+ MOVD R0, err+48(FP) // err
BL runtime·exitsyscall(SB)
RET
ok:
MOVD R0, r1+32(FP) // r1
MOVD R1, r2+40(FP) // r2
- MOVD ZR, errno+48(FP) // errno
+ MOVD ZR, err+48(FP) // err
BL runtime·exitsyscall(SB)
RET
// func RawSyscall(trap uintptr, a1, a2, a3 uintptr) (r1, r2, err uintptr)
TEXT ·RawSyscall(SB),NOSPLIT,$0-56
- MOVD syscall+0(FP), R16 // syscall entry
+ MOVD trap+0(FP), R16 // syscall entry
MOVD a1+8(FP), R0
MOVD a2+16(FP), R1
MOVD a3+24(FP), R2
@@ -41,18 +41,18 @@ TEXT ·RawSyscall(SB),NOSPLIT,$0-56
MOVD $-1, R1
MOVD R1, r1+32(FP) // r1
MOVD ZR, r2+40(FP) // r2
- MOVD R0, errno+48(FP) // errno
+ MOVD R0, err+48(FP) // err
RET
ok:
MOVD R0, r1+32(FP) // r1
MOVD R1, r2+40(FP) // r2
- MOVD ZR, errno+48(FP) // errno
+ MOVD ZR, err+48(FP) // err
RET
// func Syscall6(trap uintptr, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr)
TEXT ·Syscall6(SB),NOSPLIT,$0-80
BL runtime·entersyscall(SB)
- MOVD syscall+0(FP), R16 // syscall entry
+ MOVD trap+0(FP), R16 // syscall entry
MOVD a1+8(FP), R0
MOVD a2+16(FP), R1
MOVD a3+24(FP), R2
@@ -64,13 +64,13 @@ TEXT ·Syscall6(SB),NOSPLIT,$0-80
MOVD $-1, R1
MOVD R1, r1+56(FP) // r1
MOVD ZR, r2+64(FP) // r2
- MOVD R0, errno+72(FP) // errno
+ MOVD R0, err+72(FP) // err
BL runtime·exitsyscall(SB)
RET
ok:
MOVD R0, r1+56(FP) // r1
MOVD R1, r2+64(FP) // r2
- MOVD ZR, errno+72(FP) // errno
+ MOVD ZR, err+72(FP) // err
BL runtime·exitsyscall(SB)
RET
@@ -88,19 +88,19 @@ TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
MOVD $-1, R1
MOVD R1, r1+56(FP) // r1
MOVD ZR, r2+64(FP) // r2
- MOVD R0, errno+72(FP) // errno
+ MOVD R0, err+72(FP) // err
RET
ok:
MOVD R0, r1+56(FP) // r1
MOVD R1, r2+64(FP) // r2
MOVD ZR, R0
- MOVD R0, errno+72(FP) // errno
+ MOVD R0, err+72(FP) // err
RET
// Actually Syscall7
TEXT ·Syscall9(SB),NOSPLIT,$0-104
BL runtime·entersyscall(SB)
- MOVD syscall+0(FP), R16 // syscall entry
+ MOVD num+0(FP), R16 // syscall entry
MOVD a1+8(FP), R0
MOVD a2+16(FP), R1
MOVD a3+24(FP), R2
@@ -115,13 +115,13 @@ TEXT ·Syscall9(SB),NOSPLIT,$0-104
MOVD $-1, R1
MOVD R1, r1+80(FP) // r1
MOVD ZR, r2+88(FP) // r2
- MOVD R0, errno+96(FP) // errno
+ MOVD R0, err+96(FP) // err
BL runtime·exitsyscall(SB)
RET
ok:
MOVD R0, r1+80(FP) // r1
MOVD R1, r2+88(FP) // r2
- MOVD ZR, errno+96(FP) // errno
+ MOVD ZR, err+96(FP) // err
BL runtime·exitsyscall(SB)
RET
diff --git a/src/syscall/asm_dragonfly_amd64.s b/src/syscall/asm_dragonfly_amd64.s
deleted file mode 100644
index 004d360..0000000
--- a/src/syscall/asm_dragonfly_amd64.s
+++ /dev/null
@@ -1,134 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#include "textflag.h"
-#include "funcdata.h"
-
-//
-// System call support for AMD64, DragonFly
-//
-
-// func Syscall(trap int64, a1, a2, a3 int64) (r1, r2, err int64);
-// func Syscall6(trap int64, a1, a2, a3, a4, a5, a6 int64) (r1, r2, err int64);
-// func Syscall9(trap int64, a1, a2, a3, a4, a5, a6, a7, a8, a9 int64) (r1, r2, err int64)
-// Trap # in AX, args in DI SI DX, return in AX DX
-
-TEXT ·Syscall(SB),NOSPLIT,$0-64
- CALL runtime·entersyscall(SB)
- MOVQ 16(SP), DI
- MOVQ 24(SP), SI
- MOVQ 32(SP), DX
- MOVQ $0, R10
- MOVQ $0, R8
- MOVQ $0, R9
- MOVQ 8(SP), AX // syscall entry
- SYSCALL
- JCC ok
- MOVQ $-1, 40(SP) // r1
- MOVQ $0, 48(SP) // r2
- MOVQ AX, 56(SP) // errno
- CALL runtime·exitsyscall(SB)
- RET
-ok:
- MOVQ AX, 40(SP) // r1
- MOVQ DX, 48(SP) // r2
- MOVQ $0, 56(SP) // errno
- CALL runtime·exitsyscall(SB)
- RET
-
-TEXT ·Syscall6(SB),NOSPLIT,$0-88
- CALL runtime·entersyscall(SB)
- MOVQ 16(SP), DI
- MOVQ 24(SP), SI
- MOVQ 32(SP), DX
- MOVQ 40(SP), R10
- MOVQ 48(SP), R8
- MOVQ 56(SP), R9
- MOVQ 8(SP), AX // syscall entry
- SYSCALL
- JCC ok6
- MOVQ $-1, 64(SP) // r1
- MOVQ $0, 72(SP) // r2
- MOVQ AX, 80(SP) // errno
- CALL runtime·exitsyscall(SB)
- RET
-ok6:
- MOVQ AX, 64(SP) // r1
- MOVQ DX, 72(SP) // r2
- MOVQ $0, 80(SP) // errno
- CALL runtime·exitsyscall(SB)
- RET
-
-TEXT ·Syscall9(SB),NOSPLIT,$0-112
- CALL runtime·entersyscall(SB)
- MOVQ 8(SP), AX
- MOVQ 16(SP), DI
- MOVQ 24(SP), SI
- MOVQ 32(SP), DX
- MOVQ 40(SP), R10
- MOVQ 48(SP), R8
- MOVQ 56(SP), R9
-
- // shift around the last three arguments so they're at the
- // top of the stack when the syscall is called.
- MOVQ 64(SP), R11 // arg 7
- MOVQ R11, 8(SP)
- MOVQ 72(SP), R11 // arg 8
- MOVQ R11, 16(SP)
- MOVQ 80(SP), R11 // arg 9
- MOVQ R11, 24(SP)
-
- SYSCALL
- JCC ok9
- MOVQ $-1, 88(SP) // r1
- MOVQ $0, 96(SP) // r2
- MOVQ AX, 104(SP) // errno
- CALL runtime·exitsyscall(SB)
- RET
-ok9:
- MOVQ AX, 88(SP) // r1
- MOVQ DX, 96(SP) // r2
- MOVQ $0, 104(SP) // errno
- CALL runtime·exitsyscall(SB)
- RET
-
-TEXT ·RawSyscall(SB),NOSPLIT,$0-64
- MOVQ 16(SP), DI
- MOVQ 24(SP), SI
- MOVQ 32(SP), DX
- MOVQ $0, R10
- MOVQ $0, R8
- MOVQ $0, R9
- MOVQ 8(SP), AX // syscall entry
- SYSCALL
- JCC ok1
- MOVQ $-1, 40(SP) // r1
- MOVQ $0, 48(SP) // r2
- MOVQ AX, 56(SP) // errno
- RET
-ok1:
- MOVQ AX, 40(SP) // r1
- MOVQ DX, 48(SP) // r2
- MOVQ $0, 56(SP) // errno
- RET
-
-TEXT ·RawSyscall6(SB),NOSPLIT,$0-88
- MOVQ 16(SP), DI
- MOVQ 24(SP), SI
- MOVQ 32(SP), DX
- MOVQ 40(SP), R10
- MOVQ 48(SP), R8
- MOVQ 56(SP), R9
- MOVQ 8(SP), AX // syscall entry
- SYSCALL
- JCC ok2
- MOVQ $-1, 64(SP) // r1
- MOVQ $0, 72(SP) // r2
- MOVQ AX, 80(SP) // errno
- RET
-ok2:
- MOVQ AX, 64(SP) // r1
- MOVQ DX, 72(SP) // r2
- MOVQ $0, 80(SP) // errno
- RET
diff --git a/src/syscall/asm_freebsd_386.s b/src/syscall/asm_freebsd_386.s
deleted file mode 100644
index 1400d5f..0000000
--- a/src/syscall/asm_freebsd_386.s
+++ /dev/null
@@ -1,143 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// TODO(rsc): Rewrite all nn(SP) references into name+(nn-8)(FP)
-// so that go vet can check that they are correct.
-
-#include "textflag.h"
-#include "funcdata.h"
-
-//
-// System call support for 386, FreeBSD
-//
-
-// func Syscall(trap int32, a1, a2, a3 int32) (r1, r2, err int32);
-// func Syscall6(trap int32, a1, a2, a3, a4, a5, a6 int32) (r1, r2, err int32);
-// Trap # in AX, args on stack above caller pc.
-
-TEXT ·Syscall(SB),NOSPLIT,$0-28
- CALL runtime·entersyscall(SB)
- MOVL 4(SP), AX // syscall entry
- // slide args down on top of system call number
- LEAL 8(SP), SI
- LEAL 4(SP), DI
- CLD
- MOVSL
- MOVSL
- MOVSL
- INT $0x80
- JAE ok
- MOVL $-1, 20(SP) // r1
- MOVL $-1, 24(SP) // r2
- MOVL AX, 28(SP) // errno
- CALL runtime·exitsyscall(SB)
- RET
-ok:
- MOVL AX, 20(SP) // r1
- MOVL DX, 24(SP) // r2
- MOVL $0, 28(SP) // errno
- CALL runtime·exitsyscall(SB)
- RET
-
-TEXT ·Syscall6(SB),NOSPLIT,$0-40
- CALL runtime·entersyscall(SB)
- MOVL 4(SP), AX // syscall entry
- // slide args down on top of system call number
- LEAL 8(SP), SI
- LEAL 4(SP), DI
- CLD
- MOVSL
- MOVSL
- MOVSL
- MOVSL
- MOVSL
- MOVSL
- INT $0x80
- JAE ok6
- MOVL $-1, 32(SP) // r1
- MOVL $-1, 36(SP) // r2
- MOVL AX, 40(SP) // errno
- CALL runtime·exitsyscall(SB)
- RET
-ok6:
- MOVL AX, 32(SP) // r1
- MOVL DX, 36(SP) // r2
- MOVL $0, 40(SP) // errno
- CALL runtime·exitsyscall(SB)
- RET
-
-TEXT ·Syscall9(SB),NOSPLIT,$0-52
- CALL runtime·entersyscall(SB)
- MOVL 4(SP), AX // syscall entry
- // slide args down on top of system call number
- LEAL 8(SP), SI
- LEAL 4(SP), DI
- CLD
- MOVSL
- MOVSL
- MOVSL
- MOVSL
- MOVSL
- MOVSL
- MOVSL
- MOVSL
- MOVSL
- INT $0x80
- JAE ok9
- MOVL $-1, 44(SP) // r1
- MOVL $-1, 48(SP) // r2
- MOVL AX, 52(SP) // errno
- CALL runtime·exitsyscall(SB)
- RET
-ok9:
- MOVL AX, 44(SP) // r1
- MOVL DX, 48(SP) // r2
- MOVL $0, 52(SP) // errno
- CALL runtime·exitsyscall(SB)
- RET
-
-TEXT ·RawSyscall(SB),NOSPLIT,$0-28
- MOVL 4(SP), AX // syscall entry
- // slide args down on top of system call number
- LEAL 8(SP), SI
- LEAL 4(SP), DI
- CLD
- MOVSL
- MOVSL
- MOVSL
- INT $0x80
- JAE ok1
- MOVL $-1, 20(SP) // r1
- MOVL $-1, 24(SP) // r2
- MOVL AX, 28(SP) // errno
- RET
-ok1:
- MOVL AX, 20(SP) // r1
- MOVL DX, 24(SP) // r2
- MOVL $0, 28(SP) // errno
- RET
-
-TEXT ·RawSyscall6(SB),NOSPLIT,$0-40
- MOVL 4(SP), AX // syscall entry
- // slide args down on top of system call number
- LEAL 8(SP), SI
- LEAL 4(SP), DI
- CLD
- MOVSL
- MOVSL
- MOVSL
- MOVSL
- MOVSL
- MOVSL
- INT $0x80
- JAE ok2
- MOVL $-1, 32(SP) // r1
- MOVL $-1, 36(SP) // r2
- MOVL AX, 40(SP) // errno
- RET
-ok2:
- MOVL AX, 32(SP) // r1
- MOVL DX, 36(SP) // r2
- MOVL $0, 40(SP) // errno
- RET
diff --git a/src/syscall/asm_freebsd_amd64.s b/src/syscall/asm_freebsd_amd64.s
deleted file mode 100644
index c6988c9..0000000
--- a/src/syscall/asm_freebsd_amd64.s
+++ /dev/null
@@ -1,137 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// TODO(rsc): Rewrite all nn(SP) references into name+(nn-8)(FP)
-// so that go vet can check that they are correct.
-
-#include "textflag.h"
-#include "funcdata.h"
-
-//
-// System call support for AMD64, FreeBSD
-//
-
-// func Syscall(trap int64, a1, a2, a3 int64) (r1, r2, err int64);
-// func Syscall6(trap int64, a1, a2, a3, a4, a5, a6 int64) (r1, r2, err int64);
-// func Syscall9(trap int64, a1, a2, a3, a4, a5, a6, a7, a8, a9 int64) (r1, r2, err int64)
-// Trap # in AX, args in DI SI DX, return in AX DX
-
-TEXT ·Syscall(SB),NOSPLIT,$0-56
- CALL runtime·entersyscall(SB)
- MOVQ 16(SP), DI
- MOVQ 24(SP), SI
- MOVQ 32(SP), DX
- MOVQ $0, R10
- MOVQ $0, R8
- MOVQ $0, R9
- MOVQ 8(SP), AX // syscall entry
- SYSCALL
- JCC ok
- MOVQ $-1, 40(SP) // r1
- MOVQ $0, 48(SP) // r2
- MOVQ AX, 56(SP) // errno
- CALL runtime·exitsyscall(SB)
- RET
-ok:
- MOVQ AX, 40(SP) // r1
- MOVQ DX, 48(SP) // r2
- MOVQ $0, 56(SP) // errno
- CALL runtime·exitsyscall(SB)
- RET
-
-TEXT ·Syscall6(SB),NOSPLIT,$0-80
- CALL runtime·entersyscall(SB)
- MOVQ 16(SP), DI
- MOVQ 24(SP), SI
- MOVQ 32(SP), DX
- MOVQ 40(SP), R10
- MOVQ 48(SP), R8
- MOVQ 56(SP), R9
- MOVQ 8(SP), AX // syscall entry
- SYSCALL
- JCC ok6
- MOVQ $-1, 64(SP) // r1
- MOVQ $0, 72(SP) // r2
- MOVQ AX, 80(SP) // errno
- CALL runtime·exitsyscall(SB)
- RET
-ok6:
- MOVQ AX, 64(SP) // r1
- MOVQ DX, 72(SP) // r2
- MOVQ $0, 80(SP) // errno
- CALL runtime·exitsyscall(SB)
- RET
-
-TEXT ·Syscall9(SB),NOSPLIT,$0-104
- CALL runtime·entersyscall(SB)
- MOVQ 8(SP), AX
- MOVQ 16(SP), DI
- MOVQ 24(SP), SI
- MOVQ 32(SP), DX
- MOVQ 40(SP), R10
- MOVQ 48(SP), R8
- MOVQ 56(SP), R9
-
- // shift around the last three arguments so they're at the
- // top of the stack when the syscall is called.
- MOVQ 64(SP), R11 // arg 7
- MOVQ R11, 8(SP)
- MOVQ 72(SP), R11 // arg 8
- MOVQ R11, 16(SP)
- MOVQ 80(SP), R11 // arg 9
- MOVQ R11, 24(SP)
-
- SYSCALL
- JCC ok9
- MOVQ $-1, 88(SP) // r1
- MOVQ $0, 96(SP) // r2
- MOVQ AX, 104(SP) // errno
- CALL runtime·exitsyscall(SB)
- RET
-ok9:
- MOVQ AX, 88(SP) // r1
- MOVQ DX, 96(SP) // r2
- MOVQ $0, 104(SP) // errno
- CALL runtime·exitsyscall(SB)
- RET
-
-TEXT ·RawSyscall(SB),NOSPLIT,$0-56
- MOVQ 16(SP), DI
- MOVQ 24(SP), SI
- MOVQ 32(SP), DX
- MOVQ $0, R10
- MOVQ $0, R8
- MOVQ $0, R9
- MOVQ 8(SP), AX // syscall entry
- SYSCALL
- JCC ok1
- MOVQ $-1, 40(SP) // r1
- MOVQ $0, 48(SP) // r2
- MOVQ AX, 56(SP) // errno
- RET
-ok1:
- MOVQ AX, 40(SP) // r1
- MOVQ DX, 48(SP) // r2
- MOVQ $0, 56(SP) // errno
- RET
-
-TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
- MOVQ 16(SP), DI
- MOVQ 24(SP), SI
- MOVQ 32(SP), DX
- MOVQ 40(SP), R10
- MOVQ 48(SP), R8
- MOVQ 56(SP), R9
- MOVQ 8(SP), AX // syscall entry
- SYSCALL
- JCC ok2
- MOVQ $-1, 64(SP) // r1
- MOVQ $0, 72(SP) // r2
- MOVQ AX, 80(SP) // errno
- RET
-ok2:
- MOVQ AX, 64(SP) // r1
- MOVQ DX, 72(SP) // r2
- MOVQ $0, 80(SP) // errno
- RET
diff --git a/src/syscall/asm_linux_mipsx.s b/src/syscall/asm_linux_mipsx.s
new file mode 100644
index 0000000..957f2a8
--- /dev/null
+++ b/src/syscall/asm_linux_mipsx.s
@@ -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.
+
+// +build linux
+// +build mips mipsle
+
+#include "textflag.h"
+#include "funcdata.h"
+
+//
+// System calls for mips, Linux
+//
+
+// func Syscall(trap uintptr, a1, a2, a3 uintptr) (r1, r2, err uintptr);
+
+TEXT ·Syscall(SB),NOSPLIT,$0-28
+ JAL runtime·entersyscall(SB)
+ MOVW a1+4(FP), R4
+ MOVW a2+8(FP), R5
+ MOVW a3+12(FP), R6
+ MOVW R0, R7
+ MOVW trap+0(FP), R2 // syscall entry
+ SYSCALL
+ BEQ R7, ok
+ MOVW $-1, R1
+ MOVW R1, r1+16(FP) // r1
+ MOVW R0, r2+20(FP) // r2
+ MOVW R2, err+24(FP) // errno
+ JAL runtime·exitsyscall(SB)
+ RET
+ok:
+ MOVW R2, r1+16(FP) // r1
+ MOVW R3, r2+20(FP) // r2
+ MOVW R0, err+24(FP) // errno
+ JAL runtime·exitsyscall(SB)
+ RET
+
+
+// func Syscall6(trap trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr);
+// 5th and 6th arg go at sp+16, sp+20.
+// Note that frame size of 20 means that 24 bytes gets reserved on stack.
+TEXT ·Syscall6(SB),NOSPLIT,$20-40
+ NO_LOCAL_POINTERS
+ JAL runtime·entersyscall(SB)
+ MOVW a1+4(FP), R4
+ MOVW a2+8(FP), R5
+ MOVW a3+12(FP), R6
+ MOVW a4+16(FP), R7
+ MOVW a5+20(FP), R8
+ MOVW a6+24(FP), R9
+ MOVW R8, 16(R29)
+ MOVW R9, 20(R29)
+ MOVW trap+0(FP), R2 // syscall entry
+ SYSCALL
+ BEQ R7, ok6
+ MOVW $-1, R1
+ MOVW R1, r1+28(FP) // r1
+ MOVW R0, r2+32(FP) // r2
+ MOVW R2, err+36(FP) // errno
+ JAL runtime·exitsyscall(SB)
+ RET
+ok6:
+ MOVW R2, r1+28(FP) // r1
+ MOVW R3, r2+32(FP) // r2
+ MOVW R0, err+36(FP) // errno
+ JAL runtime·exitsyscall(SB)
+ RET
+
+// func Syscall9(trap trap, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2, err uintptr);
+// Actually Syscall8 but the rest of the code expects it to be named Syscall9.
+TEXT ·Syscall9(SB),NOSPLIT,$28-52
+ NO_LOCAL_POINTERS
+ JAL runtime·entersyscall(SB)
+ MOVW a1+4(FP), R4
+ MOVW a2+8(FP), R5
+ MOVW a3+12(FP), R6
+ MOVW a4+16(FP), R7
+ MOVW a5+20(FP), R8
+ MOVW a6+24(FP), R9
+ MOVW a7+28(FP), R10
+ MOVW a8+32(FP), R11
+ MOVW R8, 16(R29)
+ MOVW R9, 20(R29)
+ MOVW R10, 24(R29)
+ MOVW R11, 28(R29)
+ MOVW trap+0(FP), R2 // syscall entry
+ 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
+ JAL runtime·exitsyscall(SB)
+ RET
+ok9:
+ MOVW R2, r1+28(FP) // r1
+ MOVW R3, r2+32(FP) // r2
+ MOVW R0, err+36(FP) // errno
+ JAL runtime·exitsyscall(SB)
+ RET
+
+TEXT ·RawSyscall(SB),NOSPLIT,$24-28
+ MOVW a1+4(FP), R4
+ MOVW a2+8(FP), R5
+ MOVW a3+12(FP), R6
+ MOVW trap+0(FP), R2 // syscall entry
+ SYSCALL
+ BEQ R7, ok1
+ MOVW $-1, R1
+ MOVW R1, r1+16(FP) // r1
+ MOVW R0, r2+20(FP) // r2
+ MOVW R2, err+24(FP) // errno
+ RET
+ok1:
+ MOVW R2, r1+16(FP) // r1
+ MOVW R3, r2+20(FP) // r2
+ MOVW R0, err+24(FP) // errno
+ RET
+
+TEXT ·RawSyscall6(SB),NOSPLIT,$20-40
+ MOVW a1+4(FP), R4
+ MOVW a2+8(FP), R5
+ MOVW a3+12(FP), R6
+ MOVW a4+16(FP), R7
+ MOVW a5+20(FP), R8
+ MOVW a6+24(FP), R9
+ MOVW R8, 16(R29)
+ MOVW R9, 20(R29)
+ MOVW trap+0(FP), R2 // syscall entry
+ SYSCALL
+ BEQ R7, ok2
+ MOVW $-1, R1
+ MOVW R1, r1+28(FP) // r1
+ MOVW R0, r2+32(FP) // r2
+ MOVW R2, err+36(FP) // errno
+ RET
+ok2:
+ MOVW R2, r1+28(FP) // r1
+ MOVW R3, r2+32(FP) // r2
+ MOVW R0, err+36(FP) // errno
+ RET
diff --git a/src/syscall/asm_netbsd_386.s b/src/syscall/asm_netbsd_386.s
deleted file mode 100644
index a8c4849..0000000
--- a/src/syscall/asm_netbsd_386.s
+++ /dev/null
@@ -1,143 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// TODO(rsc): Rewrite all nn(SP) references into name+(nn-8)(FP)
-// so that go vet can check that they are correct.
-
-#include "textflag.h"
-#include "funcdata.h"
-
-//
-// System call support for 386, NetBSD
-//
-
-// func Syscall(trap int32, a1, a2, a3 int32) (r1, r2, err int32);
-// func Syscall6(trap int32, a1, a2, a3, a4, a5, a6 int32) (r1, r2, err int32);
-// Trap # in AX, args on stack above caller pc.
-
-TEXT ·Syscall(SB),NOSPLIT,$0-28
- CALL runtime·entersyscall(SB)
- MOVL 4(SP), AX // syscall entry
- // slide args down on top of system call number
- LEAL 8(SP), SI
- LEAL 4(SP), DI
- CLD
- MOVSL
- MOVSL
- MOVSL
- INT $0x80
- JAE ok
- MOVL $-1, 20(SP) // r1
- MOVL $-1, 24(SP) // r2
- MOVL AX, 28(SP) // errno
- CALL runtime·exitsyscall(SB)
- RET
-ok:
- MOVL AX, 20(SP) // r1
- MOVL DX, 24(SP) // r2
- MOVL $0, 28(SP) // errno
- CALL runtime·exitsyscall(SB)
- RET
-
-TEXT ·Syscall6(SB),NOSPLIT,$0-40
- CALL runtime·entersyscall(SB)
- MOVL 4(SP), AX // syscall entry
- // slide args down on top of system call number
- LEAL 8(SP), SI
- LEAL 4(SP), DI
- CLD
- MOVSL
- MOVSL
- MOVSL
- MOVSL
- MOVSL
- MOVSL
- INT $0x80
- JAE ok6
- MOVL $-1, 32(SP) // r1
- MOVL $-1, 36(SP) // r2
- MOVL AX, 40(SP) // errno
- CALL runtime·exitsyscall(SB)
- RET
-ok6:
- MOVL AX, 32(SP) // r1
- MOVL DX, 36(SP) // r2
- MOVL $0, 40(SP) // errno
- CALL runtime·exitsyscall(SB)
- RET
-
-TEXT ·Syscall9(SB),NOSPLIT,$0-52
- CALL runtime·entersyscall(SB)
- MOVL 4(SP), AX // syscall entry
- // slide args down on top of system call number
- LEAL 8(SP), SI
- LEAL 4(SP), DI
- CLD
- MOVSL
- MOVSL
- MOVSL
- MOVSL
- MOVSL
- MOVSL
- MOVSL
- MOVSL
- MOVSL
- INT $0x80
- JAE ok9
- MOVL $-1, 44(SP) // r1
- MOVL $-1, 48(SP) // r2
- MOVL AX, 52(SP) // errno
- CALL runtime·exitsyscall(SB)
- RET
-ok9:
- MOVL AX, 44(SP) // r1
- MOVL DX, 48(SP) // r2
- MOVL $0, 52(SP) // errno
- CALL runtime·exitsyscall(SB)
- RET
-
-TEXT ·RawSyscall(SB),NOSPLIT,$0-28
- MOVL 4(SP), AX // syscall entry
- // slide args down on top of system call number
- LEAL 8(SP), SI
- LEAL 4(SP), DI
- CLD
- MOVSL
- MOVSL
- MOVSL
- INT $0x80
- JAE ok1
- MOVL $-1, 20(SP) // r1
- MOVL $-1, 24(SP) // r2
- MOVL AX, 28(SP) // errno
- RET
-ok1:
- MOVL AX, 20(SP) // r1
- MOVL DX, 24(SP) // r2
- MOVL $0, 28(SP) // errno
- RET
-
-TEXT ·RawSyscall6(SB),NOSPLIT,$0-40
- MOVL 4(SP), AX // syscall entry
- // slide args down on top of system call number
- LEAL 8(SP), SI
- LEAL 4(SP), DI
- CLD
- MOVSL
- MOVSL
- MOVSL
- MOVSL
- MOVSL
- MOVSL
- INT $0x80
- JAE ok2
- MOVL $-1, 32(SP) // r1
- MOVL $-1, 36(SP) // r2
- MOVL AX, 40(SP) // errno
- RET
-ok2:
- MOVL AX, 32(SP) // r1
- MOVL DX, 36(SP) // r2
- MOVL $0, 40(SP) // errno
- RET
diff --git a/src/syscall/asm_netbsd_amd64.s b/src/syscall/asm_netbsd_amd64.s
deleted file mode 100644
index b300148..0000000
--- a/src/syscall/asm_netbsd_amd64.s
+++ /dev/null
@@ -1,136 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// TODO(rsc): Rewrite all nn(SP) references into name+(nn-8)(FP)
-// so that go vet can check that they are correct.
-
-#include "textflag.h"
-#include "funcdata.h"
-
-//
-// System call support for AMD64, NetBSD
-//
-
-// func Syscall(trap int64, a1, a2, a3 int64) (r1, r2, err int64);
-// func Syscall6(trap int64, a1, a2, a3, a4, a5, a6 int64) (r1, r2, err int64);
-// func Syscall9(trap int64, a1, a2, a3, a4, a5, a6, a7, a8, a9 int64) (r1, r2, err int64);
-// Trap # in AX, args in DI SI DX, return in AX DX
-
-TEXT ·Syscall(SB),NOSPLIT,$0-56
- CALL runtime·entersyscall(SB)
- MOVQ 8(SP), AX // syscall entry
- MOVQ 16(SP), DI
- MOVQ 24(SP), SI
- MOVQ 32(SP), DX
- MOVQ $0, R10
- MOVQ $0, R8
- MOVQ $0, R9
- SYSCALL
- JCC ok
- MOVQ $-1, 40(SP) // r1
- MOVQ $0, 48(SP) // r2
- MOVQ AX, 56(SP) // errno
- CALL runtime·exitsyscall(SB)
- RET
-ok:
- MOVQ AX, 40(SP) // r1
- MOVQ DX, 48(SP) // r2
- MOVQ $0, 56(SP) // errno
- CALL runtime·exitsyscall(SB)
- RET
-
-TEXT ·Syscall6(SB),NOSPLIT,$0-80
- CALL runtime·entersyscall(SB)
- MOVQ 8(SP), AX // syscall entry
- MOVQ 16(SP), DI
- MOVQ 24(SP), SI
- MOVQ 32(SP), DX
- MOVQ 40(SP), R10
- MOVQ 48(SP), R8
- MOVQ 56(SP), R9
- SYSCALL
- JCC ok6
- MOVQ $-1, 64(SP) // r1
- MOVQ $0, 72(SP) // r2
- MOVQ AX, 80(SP) // errno
- CALL runtime·exitsyscall(SB)
- RET
-ok6:
- MOVQ AX, 64(SP) // r1
- MOVQ DX, 72(SP) // r2
- MOVQ $0, 80(SP) // errno
- CALL runtime·exitsyscall(SB)
- RET
-
-TEXT ·Syscall9(SB),NOSPLIT,$0-104
- CALL runtime·entersyscall(SB)
- MOVQ 8(SP), AX // syscall entry
- MOVQ 16(SP), DI
- MOVQ 24(SP), SI
- MOVQ 32(SP), DX
- MOVQ 40(SP), R10
- MOVQ 48(SP), R8
- MOVQ 56(SP), R9
- MOVQ 64(SP), R11
- MOVQ 72(SP), R12
- MOVQ 80(SP), R13
- SUBQ $32, SP
- MOVQ R11, 8(SP) // arg 7
- MOVQ R12, 16(SP) // arg 8
- MOVQ R13, 24(SP) // arg 9
- SYSCALL
- JCC ok9
- ADDQ $32, SP
- MOVQ $-1, 88(SP) // r1
- MOVQ $0, 96(SP) // r2
- MOVQ AX, 104(SP) // errno
- CALL runtime·exitsyscall(SB)
- RET
-ok9:
- ADDQ $32, SP
- MOVQ AX, 88(SP) // r1
- MOVQ DX, 96(SP) // r2
- MOVQ $0, 104(SP) // errno
- CALL runtime·exitsyscall(SB)
- RET
-
-TEXT ·RawSyscall(SB),NOSPLIT,$0-56
- MOVQ 16(SP), DI
- MOVQ 24(SP), SI
- MOVQ 32(SP), DX
- MOVQ $0, R10
- MOVQ $0, R8
- MOVQ $0, R9
- MOVQ 8(SP), AX // syscall entry
- SYSCALL
- JCC ok1
- MOVQ $-1, 40(SP) // r1
- MOVQ $0, 48(SP) // r2
- MOVQ AX, 56(SP) // errno
- RET
-ok1:
- MOVQ AX, 40(SP) // r1
- MOVQ DX, 48(SP) // r2
- MOVQ $0, 56(SP) // errno
- RET
-
-TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
- MOVQ 16(SP), DI
- MOVQ 24(SP), SI
- MOVQ 32(SP), DX
- MOVQ 40(SP), R10
- MOVQ 48(SP), R8
- MOVQ 56(SP), R9
- MOVQ 8(SP), AX // syscall entry
- SYSCALL
- JCC ok2
- MOVQ $-1, 64(SP) // r1
- MOVQ $0, 72(SP) // r2
- MOVQ AX, 80(SP) // errno
- RET
-ok2:
- MOVQ AX, 64(SP) // r1
- MOVQ DX, 72(SP) // r2
- MOVQ $0, 80(SP) // errno
- RET
diff --git a/src/syscall/asm_openbsd_386.s b/src/syscall/asm_openbsd_386.s
deleted file mode 100644
index 6458bdf..0000000
--- a/src/syscall/asm_openbsd_386.s
+++ /dev/null
@@ -1,143 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// TODO(rsc): Rewrite all nn(SP) references into name+(nn-8)(FP)
-// so that go vet can check that they are correct.
-
-#include "textflag.h"
-#include "funcdata.h"
-
-//
-// System call support for 386, OpenBSD
-//
-
-// func Syscall(trap int32, a1, a2, a3 int32) (r1, r2, err int32);
-// func Syscall6(trap int32, a1, a2, a3, a4, a5, a6 int32) (r1, r2, err int32);
-// Trap # in AX, args on stack above caller pc.
-
-TEXT ·Syscall(SB),NOSPLIT,$0-28
- CALL runtime·entersyscall(SB)
- MOVL 4(SP), AX // syscall entry
- // slide args down on top of system call number
- LEAL 8(SP), SI
- LEAL 4(SP), DI
- CLD
- MOVSL
- MOVSL
- MOVSL
- INT $0x80
- JAE ok
- MOVL $-1, 20(SP) // r1
- MOVL $-1, 24(SP) // r2
- MOVL AX, 28(SP) // errno
- CALL runtime·exitsyscall(SB)
- RET
-ok:
- MOVL AX, 20(SP) // r1
- MOVL DX, 24(SP) // r2
- MOVL $0, 28(SP) // errno
- CALL runtime·exitsyscall(SB)
- RET
-
-TEXT ·Syscall6(SB),NOSPLIT,$0-40
- CALL runtime·entersyscall(SB)
- MOVL 4(SP), AX // syscall entry
- // slide args down on top of system call number
- LEAL 8(SP), SI
- LEAL 4(SP), DI
- CLD
- MOVSL
- MOVSL
- MOVSL
- MOVSL
- MOVSL
- MOVSL
- INT $0x80
- JAE ok6
- MOVL $-1, 32(SP) // r1
- MOVL $-1, 36(SP) // r2
- MOVL AX, 40(SP) // errno
- CALL runtime·exitsyscall(SB)
- RET
-ok6:
- MOVL AX, 32(SP) // r1
- MOVL DX, 36(SP) // r2
- MOVL $0, 40(SP) // errno
- CALL runtime·exitsyscall(SB)
- RET
-
-TEXT ·Syscall9(SB),NOSPLIT,$0-52
- CALL runtime·entersyscall(SB)
- MOVL 4(SP), AX // syscall entry
- // slide args down on top of system call number
- LEAL 8(SP), SI
- LEAL 4(SP), DI
- CLD
- MOVSL
- MOVSL
- MOVSL
- MOVSL
- MOVSL
- MOVSL
- MOVSL
- MOVSL
- MOVSL
- INT $0x80
- JAE ok9
- MOVL $-1, 44(SP) // r1
- MOVL $-1, 48(SP) // r2
- MOVL AX, 52(SP) // errno
- CALL runtime·exitsyscall(SB)
- RET
-ok9:
- MOVL AX, 44(SP) // r1
- MOVL DX, 48(SP) // r2
- MOVL $0, 52(SP) // errno
- CALL runtime·exitsyscall(SB)
- RET
-
-TEXT ·RawSyscall(SB),NOSPLIT,$0-28
- MOVL 4(SP), AX // syscall entry
- // slide args down on top of system call number
- LEAL 8(SP), SI
- LEAL 4(SP), DI
- CLD
- MOVSL
- MOVSL
- MOVSL
- INT $0x80
- JAE ok1
- MOVL $-1, 20(SP) // r1
- MOVL $-1, 24(SP) // r2
- MOVL AX, 28(SP) // errno
- RET
-ok1:
- MOVL AX, 20(SP) // r1
- MOVL DX, 24(SP) // r2
- MOVL $0, 28(SP) // errno
- RET
-
-TEXT ·RawSyscall6(SB),NOSPLIT,$0-40
- MOVL 4(SP), AX // syscall entry
- // slide args down on top of system call number
- LEAL 8(SP), SI
- LEAL 4(SP), DI
- CLD
- MOVSL
- MOVSL
- MOVSL
- MOVSL
- MOVSL
- MOVSL
- INT $0x80
- JAE ok2
- MOVL $-1, 32(SP) // r1
- MOVL $-1, 36(SP) // r2
- MOVL AX, 40(SP) // errno
- RET
-ok2:
- MOVL AX, 32(SP) // r1
- MOVL DX, 36(SP) // r2
- MOVL $0, 40(SP) // errno
- RET
diff --git a/src/syscall/asm_openbsd_amd64.s b/src/syscall/asm_openbsd_amd64.s
deleted file mode 100644
index 1e981fc..0000000
--- a/src/syscall/asm_openbsd_amd64.s
+++ /dev/null
@@ -1,136 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// TODO(rsc): Rewrite all nn(SP) references into name+(nn-8)(FP)
-// so that go vet can check that they are correct.
-
-#include "textflag.h"
-#include "funcdata.h"
-
-//
-// System call support for AMD64, OpenBSD
-//
-
-// func Syscall(trap int64, a1, a2, a3 int64) (r1, r2, err int64);
-// func Syscall6(trap int64, a1, a2, a3, a4, a5, a6 int64) (r1, r2, err int64);
-// func Syscall9(trap int64, a1, a2, a3, a4, a5, a6, a7, a8, a9 int64) (r1, r2, err int64);
-// Trap # in AX, args in DI SI DX, return in AX DX
-
-TEXT ·Syscall(SB),NOSPLIT,$0-56
- CALL runtime·entersyscall(SB)
- MOVQ 8(SP), AX // syscall entry
- MOVQ 16(SP), DI
- MOVQ 24(SP), SI
- MOVQ 32(SP), DX
- MOVQ $0, R10
- MOVQ $0, R8
- MOVQ $0, R9
- SYSCALL
- JCC ok
- MOVQ $-1, 40(SP) // r1
- MOVQ $0, 48(SP) // r2
- MOVQ AX, 56(SP) // errno
- CALL runtime·exitsyscall(SB)
- RET
-ok:
- MOVQ AX, 40(SP) // r1
- MOVQ DX, 48(SP) // r2
- MOVQ $0, 56(SP) // errno
- CALL runtime·exitsyscall(SB)
- RET
-
-TEXT ·Syscall6(SB),NOSPLIT,$0-80
- CALL runtime·entersyscall(SB)
- MOVQ 8(SP), AX // syscall entry
- MOVQ 16(SP), DI
- MOVQ 24(SP), SI
- MOVQ 32(SP), DX
- MOVQ 40(SP), R10
- MOVQ 48(SP), R8
- MOVQ 56(SP), R9
- SYSCALL
- JCC ok6
- MOVQ $-1, 64(SP) // r1
- MOVQ $0, 72(SP) // r2
- MOVQ AX, 80(SP) // errno
- CALL runtime·exitsyscall(SB)
- RET
-ok6:
- MOVQ AX, 64(SP) // r1
- MOVQ DX, 72(SP) // r2
- MOVQ $0, 80(SP) // errno
- CALL runtime·exitsyscall(SB)
- RET
-
-TEXT ·Syscall9(SB),NOSPLIT,$0-104
- CALL runtime·entersyscall(SB)
- MOVQ 8(SP), AX // syscall entry
- MOVQ 16(SP), DI
- MOVQ 24(SP), SI
- MOVQ 32(SP), DX
- MOVQ 40(SP), R10
- MOVQ 48(SP), R8
- MOVQ 56(SP), R9
- MOVQ 64(SP), R11
- MOVQ 72(SP), R12
- MOVQ 80(SP), R13
- SUBQ $32, SP
- MOVQ R11, 8(SP) // arg 7
- MOVQ R12, 16(SP) // arg 8
- MOVQ R13, 24(SP) // arg 9
- SYSCALL
- JCC ok9
- ADDQ $32, SP
- MOVQ $-1, 88(SP) // r1
- MOVQ $0, 96(SP) // r2
- MOVQ AX, 104(SP) // errno
- CALL runtime·exitsyscall(SB)
- RET
-ok9:
- ADDQ $32, SP
- MOVQ AX, 88(SP) // r1
- MOVQ DX, 96(SP) // r2
- MOVQ $0, 104(SP) // errno
- CALL runtime·exitsyscall(SB)
- RET
-
-TEXT ·RawSyscall(SB),NOSPLIT,$0-56
- MOVQ 16(SP), DI
- MOVQ 24(SP), SI
- MOVQ 32(SP), DX
- MOVQ $0, R10
- MOVQ $0, R8
- MOVQ $0, R9
- MOVQ 8(SP), AX // syscall entry
- SYSCALL
- JCC ok1
- MOVQ $-1, 40(SP) // r1
- MOVQ $0, 48(SP) // r2
- MOVQ AX, 56(SP) // errno
- RET
-ok1:
- MOVQ AX, 40(SP) // r1
- MOVQ DX, 48(SP) // r2
- MOVQ $0, 56(SP) // errno
- RET
-
-TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
- MOVQ 16(SP), DI
- MOVQ 24(SP), SI
- MOVQ 32(SP), DX
- MOVQ 40(SP), R10
- MOVQ 48(SP), R8
- MOVQ 56(SP), R9
- MOVQ 8(SP), AX // syscall entry
- SYSCALL
- JCC ok2
- MOVQ $-1, 64(SP) // r1
- MOVQ $0, 72(SP) // r2
- MOVQ AX, 80(SP) // errno
- RET
-ok2:
- MOVQ AX, 64(SP) // r1
- MOVQ DX, 72(SP) // r2
- MOVQ $0, 80(SP) // errno
- RET
diff --git a/src/syscall/asm_openbsd_arm.s b/src/syscall/asm_openbsd_arm.s
index 4f034a0..9279ed9 100644
--- a/src/syscall/asm_openbsd_arm.s
+++ b/src/syscall/asm_openbsd_arm.s
@@ -17,7 +17,7 @@
TEXT ·Syscall(SB),NOSPLIT,$0-28
BL runtime·entersyscall(SB)
- MOVW syscall+0(FP), R12 // syscall number
+ MOVW trap+0(FP), R12 // syscall number
MOVW a1+4(FP), R0 // arg 1
MOVW a2+8(FP), R1 // arg 2
MOVW a3+12(FP), R2 // arg 3
@@ -39,7 +39,7 @@ error:
TEXT ·Syscall6(SB),NOSPLIT,$0-40
BL runtime·entersyscall(SB)
- MOVW syscall+0(FP), R12 // syscall number
+ MOVW trap+0(FP), R12 // syscall number
MOVW a1+4(FP), R0 // arg 1
MOVW a2+8(FP), R1 // arg 2
MOVW a3+12(FP), R2 // arg 3
@@ -65,7 +65,7 @@ error6:
TEXT ·Syscall9(SB),NOSPLIT,$0-52
BL runtime·entersyscall(SB)
- MOVW syscall+0(FP), R12 // syscall number
+ MOVW num+0(FP), R12 // syscall number
MOVW a1+4(FP), R0 // arg 1
MOVW a2+8(FP), R1 // arg 2
MOVW a3+12(FP), R2 // arg 3
@@ -90,7 +90,7 @@ error9:
RET
TEXT ·RawSyscall(SB),NOSPLIT,$0-28
- MOVW syscall+0(FP), R12 // syscall number
+ MOVW trap+0(FP), R12 // syscall number
MOVW a1+4(FP), R0 // arg 1
MOVW a2+8(FP), R1 // arg 2
MOVW a3+12(FP), R2 // arg 3
@@ -109,7 +109,7 @@ errorr:
RET
TEXT ·RawSyscall6(SB),NOSPLIT,$0-40
- MOVW syscall+0(FP), R12 // syscall number
+ MOVW trap+0(FP), R12 // syscall number
MOVW a1+4(FP), R0 // arg 1
MOVW a2+8(FP), R1 // arg 2
MOVW a3+12(FP), R2 // arg 3
diff --git a/src/syscall/asm_plan9_386.s b/src/syscall/asm_plan9_386.s
index fc13640..047ae59 100644
--- a/src/syscall/asm_plan9_386.s
+++ b/src/syscall/asm_plan9_386.s
@@ -2,9 +2,6 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// TODO(rsc): Rewrite all nn(SP) references into name+(nn-8)(FP)
-// so that go vet can check that they are correct.
-
#include "textflag.h"
#include "funcdata.h"
@@ -20,17 +17,17 @@
// Trap # in AX, args on stack above caller pc.
TEXT ·Syscall(SB),NOSPLIT,$0-32
CALL runtime·entersyscall(SB)
- MOVL 4(SP), AX // syscall entry
+ MOVL trap+0(FP), AX // syscall entry
// slide args down on top of system call number
- LEAL 8(SP), SI
- LEAL 4(SP), DI
+ LEAL a1+4(FP), SI
+ LEAL trap+0(FP), DI
CLD
MOVSL
MOVSL
MOVSL
INT $64
- MOVL AX, r1+20(SP)
- MOVL $0, r2+24(SP)
+ MOVL AX, r1+16(FP)
+ MOVL $0, r2+20(FP)
CMPL AX, $-1
JNE ok3
@@ -44,7 +41,7 @@ ok3:
LEAL runtime·emptystring(SB), SI
copyresult3:
- LEAL err+28(SP), DI
+ LEAL err+24(FP), DI
CLD
MOVSL
@@ -55,10 +52,10 @@ copyresult3:
TEXT ·Syscall6(SB),NOSPLIT,$0-44
CALL runtime·entersyscall(SB)
- MOVL 4(SP), AX // syscall entry
+ MOVL trap+0(FP), AX // syscall entry
// slide args down on top of system call number
- LEAL 8(SP), SI
- LEAL 4(SP), DI
+ LEAL a1+4(FP), SI
+ LEAL trap+0(FP), DI
CLD
MOVSL
MOVSL
@@ -67,8 +64,8 @@ TEXT ·Syscall6(SB),NOSPLIT,$0-44
MOVSL
MOVSL
INT $64
- MOVL AX, r1+32(SP)
- MOVL $0, r2+36(SP)
+ MOVL AX, r1+28(FP)
+ MOVL $0, r2+32(FP)
CMPL AX, $-1
JNE ok4
@@ -82,7 +79,7 @@ ok4:
LEAL runtime·emptystring(SB), SI
copyresult4:
- LEAL err+40(SP), DI
+ LEAL err+36(FP), DI
CLD
MOVSL
@@ -92,25 +89,25 @@ copyresult4:
RET
TEXT ·RawSyscall(SB),NOSPLIT,$0-28
- MOVL 4(SP), AX // syscall entry
+ MOVL trap+0(FP), AX // syscall entry
// slide args down on top of system call number
- LEAL 8(SP), SI
- LEAL 4(SP), DI
+ LEAL a1+4(FP), SI
+ LEAL trap+0(FP), DI
CLD
MOVSL
MOVSL
MOVSL
INT $64
- MOVL AX, r1+20(SP)
- MOVL AX, r2+24(SP)
- MOVL AX, err+28(SP)
+ MOVL AX, r1+16(FP)
+ MOVL AX, r2+20(FP)
+ MOVL AX, err+24(FP)
RET
TEXT ·RawSyscall6(SB),NOSPLIT,$0-40
- MOVL 4(SP), AX // syscall entry
+ MOVL trap+0(FP), AX // syscall entry
// slide args down on top of system call number
- LEAL 8(SP), SI
- LEAL 4(SP), DI
+ LEAL a1+4(FP), SI
+ LEAL trap+0(FP), DI
CLD
MOVSL
MOVSL
@@ -119,25 +116,25 @@ TEXT ·RawSyscall6(SB),NOSPLIT,$0-40
MOVSL
MOVSL
INT $64
- MOVL AX, r1+32(SP)
- MOVL AX, r2+36(SP)
- MOVL AX, err+40(SP)
+ MOVL AX, r1+28(FP)
+ MOVL AX, r2+32(FP)
+ MOVL AX, err+36(FP)
RET
#define SYS_SEEK 39 /* from zsysnum_plan9_386.go */
//func seek(placeholder uintptr, fd int, offset int64, whence int) (newoffset int64, err string)
TEXT ·seek(SB),NOSPLIT,$0-36
- LEAL newoffset+24(SP), AX
- MOVL AX, placeholder+4(SP)
+ LEAL newoffset+20(FP), AX
+ MOVL AX, placeholder+0(FP)
MOVL $SYS_SEEK, AX // syscall entry
INT $64
CMPL AX, $-1
JNE ok6
- MOVL AX, 24(SP) // newoffset low
- MOVL AX, 28(SP) // newoffset high
+ MOVL AX, newoffset_lo+20(FP)
+ MOVL AX, newoffset_hi+24(FP)
SUBL $8, SP
CALL syscall·errstr(SB)
@@ -149,7 +146,7 @@ ok6:
LEAL runtime·emptystring(SB), SI
copyresult6:
- LEAL err+32(SP), DI
+ LEAL err+28(FP), DI
CLD
MOVSL
diff --git a/src/syscall/asm_plan9_amd64.s b/src/syscall/asm_plan9_amd64.s
index 92419b7..8405023 100644
--- a/src/syscall/asm_plan9_amd64.s
+++ b/src/syscall/asm_plan9_amd64.s
@@ -2,9 +2,6 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// TODO(rsc): Rewrite all nn(SP) references into name+(nn-8)(FP)
-// so that go vet can check that they are correct.
-
#include "textflag.h"
#include "funcdata.h"
@@ -19,17 +16,17 @@
TEXT ·Syscall(SB),NOSPLIT,$0-64
CALL runtime·entersyscall(SB)
- MOVQ 8(SP), BP // syscall entry
+ MOVQ trap+0(FP), BP // syscall entry
// slide args down on top of system call number
- LEAQ 16(SP), SI
- LEAQ 8(SP), DI
+ LEAQ a1+8(FP), SI
+ LEAQ trap+0(FP), DI
CLD
MOVSQ
MOVSQ
MOVSQ
SYSCALL
- MOVQ AX, r1+40(SP)
- MOVQ $0, r2+48(SP)
+ MOVQ AX, r1+32(FP)
+ MOVQ $0, r2+40(FP)
CMPL AX, $-1
JNE ok3
@@ -43,7 +40,7 @@ ok3:
LEAQ runtime·emptystring(SB), SI
copyresult3:
- LEAQ err+56(SP), DI
+ LEAQ err+48(FP), DI
CLD
MOVSQ
@@ -54,10 +51,10 @@ copyresult3:
TEXT ·Syscall6(SB),NOSPLIT,$0-88
CALL runtime·entersyscall(SB)
- MOVQ 8(SP), BP // syscall entry
+ MOVQ trap+0(FP), BP // syscall entry
// slide args down on top of system call number
- LEAQ 16(SP), SI
- LEAQ 8(SP), DI
+ LEAQ a1+8(FP), SI
+ LEAQ trap+0(FP), DI
CLD
MOVSQ
MOVSQ
@@ -66,8 +63,8 @@ TEXT ·Syscall6(SB),NOSPLIT,$0-88
MOVSQ
MOVSQ
SYSCALL
- MOVQ AX, r1+64(SP)
- MOVQ $0, r2+72(SP)
+ MOVQ AX, r1+56(FP)
+ MOVQ $0, r2+64(FP)
CMPL AX, $-1
JNE ok4
@@ -81,7 +78,7 @@ ok4:
LEAQ runtime·emptystring(SB), SI
copyresult4:
- LEAQ err+80(SP), DI
+ LEAQ err+72(FP), DI
CLD
MOVSQ
@@ -91,25 +88,25 @@ copyresult4:
RET
TEXT ·RawSyscall(SB),NOSPLIT,$0-56
- MOVQ 8(SP), BP // syscall entry
+ MOVQ trap+0(FP), BP // syscall entry
// slide args down on top of system call number
- LEAQ 16(SP), SI
- LEAQ 8(SP), DI
+ LEAQ a1+8(FP), SI
+ LEAQ trap+0(FP), DI
CLD
MOVSQ
MOVSQ
MOVSQ
SYSCALL
- MOVQ AX, r1+40(SP)
- MOVQ AX, r2+48(SP)
- MOVQ AX, err+56(SP)
+ MOVQ AX, r1+32(FP)
+ MOVQ AX, r2+40(FP)
+ MOVQ AX, err+48(FP)
RET
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
- MOVQ 8(SP), BP // syscall entry
+ MOVQ trap+0(FP), BP // syscall entry
// slide args down on top of system call number
- LEAQ 16(SP), SI
- LEAQ 8(SP), DI
+ LEAQ a1+8(FP), SI
+ LEAQ trap+0(FP), DI
CLD
MOVSQ
MOVSQ
@@ -118,24 +115,24 @@ TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
MOVSQ
MOVSQ
SYSCALL
- MOVQ AX, r1+64(SP)
- MOVQ AX, r2+72(SP)
- MOVQ AX, err+80(SP)
+ MOVQ AX, r1+56(FP)
+ MOVQ AX, r2+64(FP)
+ MOVQ AX, err+72(FP)
RET
#define SYS_SEEK 39 /* from zsysnum_plan9_amd64.go */
//func seek(placeholder uintptr, fd int, offset int64, whence int) (newoffset int64, err string)
TEXT ·seek(SB),NOSPLIT,$0-56
- LEAQ newoffset+40(SP), AX
- MOVQ AX, placeholder+8(SP)
+ LEAQ newoffset+32(FP), AX
+ MOVQ AX, placeholder+0(FP)
MOVQ $SYS_SEEK, BP // syscall entry
SYSCALL
CMPL AX, $-1
JNE ok6
- MOVQ $-1, newoffset+40(SP)
+ MOVQ $-1, newoffset+32(FP)
SUBQ $16, SP
CALL syscall·errstr(SB)
@@ -147,7 +144,7 @@ ok6:
LEAQ runtime·emptystring(SB), SI
copyresult6:
- LEAQ err+48(SP), DI
+ LEAQ err+40(FP), DI
CLD
MOVSQ
diff --git a/src/syscall/asm_unix_386.s b/src/syscall/asm_unix_386.s
new file mode 100644
index 0000000..263355c
--- /dev/null
+++ b/src/syscall/asm_unix_386.s
@@ -0,0 +1,142 @@
+// +build netbsd freebsd openbsd
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "textflag.h"
+#include "funcdata.h"
+
+//
+// System call support for some 386 unixes
+//
+
+// func Syscall(trap int32, a1, a2, a3 int32) (r1, r2, err int32);
+// func Syscall6(trap int32, a1, a2, a3, a4, a5, a6 int32) (r1, r2, err int32);
+// Trap # in AX, args on stack above caller pc.
+
+TEXT ·Syscall(SB),NOSPLIT,$0-28
+ CALL runtime·entersyscall(SB)
+ MOVL trap+0(FP), AX // syscall entry
+ // slide args down on top of system call number
+ LEAL 8(SP), SI
+ LEAL 4(SP), DI
+ CLD
+ MOVSL
+ MOVSL
+ MOVSL
+ INT $0x80
+ JAE ok
+ MOVL $-1, r1+16(FP) // r1
+ MOVL $-1, r2+20(FP) // r2
+ MOVL AX, err+24(FP) // errno
+ CALL runtime·exitsyscall(SB)
+ RET
+ok:
+ MOVL AX, r1+16(FP) // r1
+ MOVL DX, r2+20(FP) // r2
+ MOVL $0, err+24(FP) // errno
+ CALL runtime·exitsyscall(SB)
+ RET
+
+TEXT ·Syscall6(SB),NOSPLIT,$0-40
+ CALL runtime·entersyscall(SB)
+ MOVL trap+0(FP), AX // syscall entry
+ // slide args down on top of system call number
+ LEAL 8(SP), SI
+ LEAL 4(SP), DI
+ CLD
+ MOVSL
+ MOVSL
+ MOVSL
+ MOVSL
+ MOVSL
+ MOVSL
+ INT $0x80
+ JAE ok6
+ MOVL $-1, r1+28(FP) // r1
+ MOVL $-1, r2+32(FP) // r2
+ MOVL AX, err+36(FP) // errno
+ CALL runtime·exitsyscall(SB)
+ RET
+ok6:
+ MOVL AX, r1+28(FP) // r1
+ MOVL DX, r2+32(FP) // r2
+ MOVL $0, err+36(FP) // errno
+ CALL runtime·exitsyscall(SB)
+ RET
+
+TEXT ·Syscall9(SB),NOSPLIT,$0-52
+ CALL runtime·entersyscall(SB)
+ MOVL num+0(FP), AX // syscall entry
+ // slide args down on top of system call number
+ LEAL 8(SP), SI
+ LEAL 4(SP), DI
+ CLD
+ MOVSL
+ MOVSL
+ MOVSL
+ MOVSL
+ MOVSL
+ MOVSL
+ MOVSL
+ MOVSL
+ MOVSL
+ INT $0x80
+ JAE ok9
+ MOVL $-1, r1+40(FP) // r1
+ MOVL $-1, r2+44(FP) // r2
+ MOVL AX, err+48(FP) // errno
+ CALL runtime·exitsyscall(SB)
+ RET
+ok9:
+ MOVL AX, r1+40(FP) // r1
+ MOVL DX, r2+44(FP) // r2
+ MOVL $0, err+48(FP) // errno
+ CALL runtime·exitsyscall(SB)
+ RET
+
+TEXT ·RawSyscall(SB),NOSPLIT,$0-28
+ MOVL trap+0(FP), AX // syscall entry
+ // slide args down on top of system call number
+ LEAL 8(SP), SI
+ LEAL 4(SP), DI
+ CLD
+ MOVSL
+ MOVSL
+ MOVSL
+ INT $0x80
+ JAE ok1
+ MOVL $-1, r1+16(FP) // r1
+ MOVL $-1, r2+20(FP) // r2
+ MOVL AX, err+24(FP) // errno
+ RET
+ok1:
+ MOVL AX, r1+16(FP) // r1
+ MOVL DX, r2+20(FP) // r2
+ MOVL $0, err+24(FP) // errno
+ RET
+
+TEXT ·RawSyscall6(SB),NOSPLIT,$0-40
+ MOVL trap+0(FP), AX // syscall entry
+ // slide args down on top of system call number
+ LEAL 8(SP), SI
+ LEAL 4(SP), DI
+ CLD
+ MOVSL
+ MOVSL
+ MOVSL
+ MOVSL
+ MOVSL
+ MOVSL
+ INT $0x80
+ JAE ok2
+ MOVL $-1, r1+28(FP) // r1
+ MOVL $-1, r2+32(FP) // r2
+ MOVL AX, err+36(FP) // errno
+ RET
+ok2:
+ MOVL AX, r1+28(FP) // r1
+ MOVL DX, r2+32(FP) // r2
+ MOVL $0, err+36(FP) // errno
+ RET
diff --git a/src/syscall/asm_unix_amd64.s b/src/syscall/asm_unix_amd64.s
new file mode 100644
index 0000000..025408f
--- /dev/null
+++ b/src/syscall/asm_unix_amd64.s
@@ -0,0 +1,102 @@
+// +build netbsd freebsd openbsd dragonfly
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "textflag.h"
+#include "funcdata.h"
+
+//
+// System call support for AMD64 unixes
+//
+
+// func Syscall(trap int64, a1, a2, a3 int64) (r1, r2, err int64)
+// func Syscall6(trap int64, a1, a2, a3, a4, a5, a6 int64) (r1, r2, err int64)
+// Trap # in AX, args in DI SI DX, return in AX DX
+
+TEXT ·Syscall(SB),NOSPLIT,$0-56
+ CALL runtime·entersyscall(SB)
+ MOVQ trap+0(FP), AX // syscall entry
+ MOVQ a1+8(FP), DI
+ MOVQ a2+16(FP), SI
+ MOVQ a3+24(FP), DX
+ MOVQ $0, R10
+ MOVQ $0, R8
+ MOVQ $0, R9
+ SYSCALL
+ JCC ok
+ MOVQ $-1, r1+32(FP) // r1
+ MOVQ $0, r2+40(FP) // r2
+ MOVQ AX, err+48(FP) // errno
+ CALL runtime·exitsyscall(SB)
+ RET
+ok:
+ MOVQ AX, r1+32(FP) // r1
+ MOVQ DX, r2+40(FP) // r2
+ MOVQ $0, err+48(FP) // errno
+ CALL runtime·exitsyscall(SB)
+ RET
+
+TEXT ·Syscall6(SB),NOSPLIT,$0-80
+ CALL runtime·entersyscall(SB)
+ MOVQ trap+0(FP), AX // syscall entry
+ MOVQ a1+8(FP), DI
+ MOVQ a2+16(FP), SI
+ MOVQ a3+24(FP), DX
+ MOVQ a4+32(FP), R10
+ MOVQ a5+40(FP), R8
+ MOVQ a6+48(FP), R9
+ SYSCALL
+ JCC ok6
+ MOVQ $-1, r1+56(FP) // r1
+ MOVQ $0, r2+64(FP) // r2
+ MOVQ AX, err+72(FP) // errno
+ CALL runtime·exitsyscall(SB)
+ RET
+ok6:
+ MOVQ AX, r1+56(FP) // r1
+ MOVQ DX, r2+64(FP) // r2
+ MOVQ $0, err+72(FP) // errno
+ CALL runtime·exitsyscall(SB)
+ RET
+
+TEXT ·RawSyscall(SB),NOSPLIT,$0-56
+ MOVQ a1+8(FP), DI
+ MOVQ a2+16(FP), SI
+ MOVQ a3+24(FP), DX
+ MOVQ $0, R10
+ MOVQ $0, R8
+ MOVQ $0, R9
+ MOVQ trap+0(FP), AX // syscall entry
+ SYSCALL
+ JCC ok1
+ MOVQ $-1, r1+32(FP) // r1
+ MOVQ $0, r2+40(FP) // r2
+ MOVQ AX, err+48(FP) // errno
+ RET
+ok1:
+ MOVQ AX, r1+32(FP) // r1
+ MOVQ DX, r2+40(FP) // r2
+ MOVQ $0, err+48(FP) // errno
+ RET
+
+TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
+ MOVQ a1+8(FP), DI
+ MOVQ a2+16(FP), SI
+ MOVQ a3+24(FP), DX
+ MOVQ a4+32(FP), R10
+ MOVQ a5+40(FP), R8
+ MOVQ a6+48(FP), R9
+ MOVQ trap+0(FP), AX // syscall entry
+ SYSCALL
+ JCC ok2
+ MOVQ $-1, r1+56(FP) // r1
+ MOVQ $0, r2+64(FP) // r2
+ MOVQ AX, err+72(FP) // errno
+ RET
+ok2:
+ MOVQ AX, r1+56(FP) // r1
+ MOVQ DX, r2+64(FP) // r2
+ MOVQ $0, err+72(FP) // errno
+ RET
diff --git a/src/syscall/const_plan9.go b/src/syscall/const_plan9.go
index ba26f12..063d5df 100644
--- a/src/syscall/const_plan9.go
+++ b/src/syscall/const_plan9.go
@@ -12,6 +12,17 @@ const (
O_EXCL = 0x1000
)
+// Bind flags
+const (
+ MORDER = 0x0003 // mask for bits defining order of mounting
+ MREPL = 0x0000 // mount replaces object
+ MBEFORE = 0x0001 // mount goes before others in union directory
+ MAFTER = 0x0002 // mount goes after others in union directory
+ MCREATE = 0x0004 // permit creation in mounted directory
+ MCACHE = 0x0010 // cache some data
+ MMASK = 0x0017 // all bits on
+)
+
// Rfork flags
const (
RFNAMEG = 1 << 0
diff --git a/src/syscall/dir_plan9.go b/src/syscall/dir_plan9.go
index 15b2674..4ed052d 100644
--- a/src/syscall/dir_plan9.go
+++ b/src/syscall/dir_plan9.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.
-// Plan 9 directory marshalling. See intro(5).
+// Plan 9 directory marshaling. See intro(5).
package syscall
diff --git a/src/syscall/dirent.go b/src/syscall/dirent.go
new file mode 100644
index 0000000..4db2d43
--- /dev/null
+++ b/src/syscall/dirent.go
@@ -0,0 +1,102 @@
+// Copyright 2009 The Go Authors. 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 syscall
+
+import "unsafe"
+
+// readInt returns the size-bytes unsigned integer in native byte order at offset off.
+func readInt(b []byte, off, size uintptr) (u uint64, ok bool) {
+ if len(b) < int(off+size) {
+ return 0, false
+ }
+ if isBigEndian {
+ return readIntBE(b[off:], size), true
+ }
+ return readIntLE(b[off:], size), true
+}
+
+func readIntBE(b []byte, size uintptr) uint64 {
+ switch size {
+ case 1:
+ return uint64(b[0])
+ case 2:
+ _ = b[1] // bounds check hint to compiler; see golang.org/issue/14808
+ return uint64(b[1]) | uint64(b[0])<<8
+ case 4:
+ _ = b[3] // bounds check hint to compiler; see golang.org/issue/14808
+ return uint64(b[3]) | uint64(b[2])<<8 | uint64(b[1])<<16 | uint64(b[0])<<24
+ case 8:
+ _ = 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
+ default:
+ panic("syscall: readInt with unsupported size")
+ }
+}
+
+func readIntLE(b []byte, size uintptr) uint64 {
+ switch size {
+ case 1:
+ return uint64(b[0])
+ case 2:
+ _ = b[1] // bounds check hint to compiler; see golang.org/issue/14808
+ return uint64(b[0]) | uint64(b[1])<<8
+ case 4:
+ _ = b[3] // bounds check hint to compiler; see golang.org/issue/14808
+ return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24
+ case 8:
+ _ = b[7] // bounds check hint to compiler; see golang.org/issue/14808
+ return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 |
+ uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56
+ default:
+ panic("syscall: readInt with unsupported size")
+ }
+}
+
+// ParseDirent parses up to max directory entries in buf,
+// appending the names to names. It returns the number of
+// bytes consumed from buf, the number of entries added
+// to names, and the new names slice.
+func ParseDirent(buf []byte, max int, names []string) (consumed int, count int, newnames []string) {
+ origlen := len(buf)
+ count = 0
+ for max != 0 && len(buf) > 0 {
+ reclen, ok := direntReclen(buf)
+ if !ok || reclen > uint64(len(buf)) {
+ return origlen, count, names
+ }
+ rec := buf[:reclen]
+ buf = buf[reclen:]
+ ino, ok := direntIno(rec)
+ if !ok {
+ break
+ }
+ if ino == 0 { // File absent in directory.
+ continue
+ }
+ const namoff = uint64(unsafe.Offsetof(Dirent{}.Name))
+ namlen, ok := direntNamlen(rec)
+ if !ok || namoff+namlen > uint64(len(rec)) {
+ break
+ }
+ name := rec[namoff : namoff+namlen]
+ for i, c := range name {
+ if c == 0 {
+ name = name[:i]
+ break
+ }
+ }
+ // Check for useless names before allocating a string.
+ if string(name) == "." || string(name) == ".." {
+ continue
+ }
+ max--
+ count++
+ names = append(names, string(name))
+ }
+ return origlen - len(buf), count, names
+}
diff --git a/src/syscall/dll_windows.go b/src/syscall/dll_windows.go
index e563848..864473b 100644
--- a/src/syscall/dll_windows.go
+++ b/src/syscall/dll_windows.go
@@ -176,7 +176,6 @@ func (p *Proc) Call(a ...uintptr) (r1, r2 uintptr, lastErr error) {
default:
panic("Call " + p.Name + " with too many arguments " + itoa(len(a)) + ".")
}
- return
}
// A LazyDLL implements access to a single DLL.
diff --git a/src/syscall/endian_big.go b/src/syscall/endian_big.go
new file mode 100644
index 0000000..3c26005
--- /dev/null
+++ b/src/syscall/endian_big.go
@@ -0,0 +1,9 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+//
+// +build ppc64 s390x mips mips64
+
+package syscall
+
+const isBigEndian = true
diff --git a/src/syscall/endian_little.go b/src/syscall/endian_little.go
new file mode 100644
index 0000000..bd6f06e
--- /dev/null
+++ b/src/syscall/endian_little.go
@@ -0,0 +1,9 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+//
+// +build 386 amd64 amd64p32 arm arm64 ppc64le mips64le mipsle
+
+package syscall
+
+const isBigEndian = false
diff --git a/src/syscall/env_windows.go b/src/syscall/env_windows.go
index 3f75167..1606b42 100644
--- a/src/syscall/env_windows.go
+++ b/src/syscall/env_windows.go
@@ -60,7 +60,7 @@ func Clearenv() {
// http://blogs.msdn.com/b/oldnewthing/archive/2010/05/06/10008132.aspx
for j := 1; j < len(s); j++ {
if s[j] == '=' {
- Setenv(s[0:j], "")
+ Unsetenv(s[0:j])
break
}
}
diff --git a/src/syscall/exec_linux.go b/src/syscall/exec_linux.go
index 39764f7..979b6a2 100644
--- a/src/syscall/exec_linux.go
+++ b/src/syscall/exec_linux.go
@@ -214,16 +214,16 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr
// and disabled setgroups, because otherwise unprivileged user namespace
// will fail with any non-empty SysProcAttr.Credential.
if !(sys.GidMappings != nil && !sys.GidMappingsEnableSetgroups && ngroups == 0) {
- _, _, err1 = RawSyscall(SYS_SETGROUPS, ngroups, groups, 0)
+ _, _, err1 = RawSyscall(_SYS_setgroups, ngroups, groups, 0)
if err1 != 0 {
goto childerror
}
}
- _, _, err1 = RawSyscall(SYS_SETGID, uintptr(cred.Gid), 0, 0)
+ _, _, err1 = RawSyscall(sys_SETGID, uintptr(cred.Gid), 0, 0)
if err1 != 0 {
goto childerror
}
- _, _, err1 = RawSyscall(SYS_SETUID, uintptr(cred.Uid), 0, 0)
+ _, _, err1 = RawSyscall(sys_SETUID, uintptr(cred.Uid), 0, 0)
if err1 != 0 {
goto childerror
}
diff --git a/src/syscall/exec_linux_test.go b/src/syscall/exec_linux_test.go
index aaffa06..7a4b571 100644
--- a/src/syscall/exec_linux_test.go
+++ b/src/syscall/exec_linux_test.go
@@ -162,6 +162,12 @@ func TestUnshare(t *testing.T) {
t.Fatal(err)
}
+ orig, err := ioutil.ReadFile(path)
+ if err != nil {
+ t.Fatal(err)
+ }
+ origLines := strings.Split(strings.TrimSpace(string(orig)), "\n")
+
cmd := exec.Command("cat", path)
cmd.SysProcAttr = &syscall.SysProcAttr{
Unshareflags: syscall.CLONE_NEWNET,
@@ -178,8 +184,8 @@ func TestUnshare(t *testing.T) {
}
lines := strings.Split(sout, "\n")
- if len(lines) != 3 {
- t.Fatalf("Expected 3 lines of output, got %d", len(lines))
+ if len(lines) >= len(origLines) {
+ t.Fatalf("Got %d lines of output, want <%d", len(lines), len(origLines))
}
}
diff --git a/src/syscall/exec_plan9.go b/src/syscall/exec_plan9.go
index 6551bcb..47ccbdc 100644
--- a/src/syscall/exec_plan9.go
+++ b/src/syscall/exec_plan9.go
@@ -298,11 +298,6 @@ childerror1:
for {
RawSyscall(SYS_EXITS, 0, 0, 0)
}
-
- // Calling panic is not actually safe,
- // but the for loop above won't break
- // and this shuts up the compiler.
- panic("unreached")
}
// close the numbered file descriptor, unless it is fd1, fd2, or a member of fds.
diff --git a/src/syscall/exec_unix.go b/src/syscall/exec_unix.go
index 9fd8cf4..af59c5d 100644
--- a/src/syscall/exec_unix.go
+++ b/src/syscall/exec_unix.go
@@ -241,7 +241,7 @@ func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, handle
return pid, 0, err
}
-// Ordinary exec.
+// Exec invokes the execve(2) system call.
func Exec(argv0 string, argv []string, envv []string) (err error) {
argv0p, err := BytePtrFromString(argv0)
if err != nil {
diff --git a/src/syscall/exec_windows.go b/src/syscall/exec_windows.go
index 5a01843..cafce1e 100644
--- a/src/syscall/exec_windows.go
+++ b/src/syscall/exec_windows.go
@@ -209,8 +209,6 @@ func joinExeDirAndFName(dir, p string) (name string, err error) {
return FullPath(d + "\\" + p)
}
}
- // we shouldn't be here
- return "", EINVAL
}
type ProcAttr struct {
diff --git a/src/syscall/flock_linux_32bit.go b/src/syscall/flock_linux_32bit.go
index 500a973..e154899 100644
--- a/src/syscall/flock_linux_32bit.go
+++ b/src/syscall/flock_linux_32bit.go
@@ -1,4 +1,4 @@
-// +build linux,386 linux,arm
+// +build linux,386 linux,arm linux,mips linux,mipsle
// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
diff --git a/src/syscall/mkall.sh b/src/syscall/mkall.sh
index 6a9aacb..987ac23 100755
--- a/src/syscall/mkall.sh
+++ b/src/syscall/mkall.sh
@@ -275,7 +275,7 @@ solaris_amd64)
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
;;
windows_*)
- echo 'run "go generate syscall_windows.go" instead' 1>&2
+ echo 'run "go generate" instead' 1>&2
exit 1
;;
*)
diff --git a/src/syscall/mksyscall_windows.go b/src/syscall/mksyscall_windows.go
index 1e0d940..37e4a07 100644
--- a/src/syscall/mksyscall_windows.go
+++ b/src/syscall/mksyscall_windows.go
@@ -281,7 +281,7 @@ func (r *Rets) SetReturnValuesCode() string {
func (r *Rets) useLongHandleErrorCode(retvar string) string {
const code = `if %s {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = %sEINVAL
}
@@ -708,6 +708,10 @@ func (src *Source) IsStdRepo() (bool, error) {
abspath = strings.ToLower(abspath)
goroot = strings.ToLower(goroot)
}
+ sep := string(os.PathSeparator)
+ if !strings.HasSuffix(goroot, sep) {
+ goroot += sep
+ }
return strings.HasPrefix(abspath, goroot), nil
}
@@ -825,6 +829,31 @@ import (
var _ unsafe.Pointer
+// Do the interface allocations only once for common
+// Errno values.
+const (
+ errnoERROR_IO_PENDING = 997
+)
+
+var (
+ errERROR_IO_PENDING error = {{syscalldot}}Errno(errnoERROR_IO_PENDING)
+)
+
+// errnoErr returns common boxed Errno values, to prevent
+// allocations at runtime.
+func errnoErr(e {{syscalldot}}Errno) error {
+ switch e {
+ case 0:
+ return nil
+ case errnoERROR_IO_PENDING:
+ return errERROR_IO_PENDING
+ }
+ // TODO: add more here, after collecting data on the common
+ // error values see on Windows. (perhaps when running
+ // all.bat?)
+ return e
+}
+
var (
{{template "dlls" .}}
{{template "funcnames" .}})
diff --git a/src/syscall/mksysnum_linux.pl b/src/syscall/mksysnum_linux.pl
index b6fbcb5..4db8149 100755
--- a/src/syscall/mksysnum_linux.pl
+++ b/src/syscall/mksysnum_linux.pl
@@ -16,21 +16,28 @@ package syscall
const(
EOF
+my $offset = 0;
+
sub fmt {
my ($name, $num) = @_;
if($num > 999){
- # ignore depricated syscalls that are no longer implemented
+ # ignore deprecated syscalls that are no longer implemented
# https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/include/uapi/asm-generic/unistd.h?id=refs/heads/master#n716
return;
}
$name =~ y/a-z/A-Z/;
+ $num = $num + $offset;
print " SYS_$name = $num;\n";
}
my $prev;
open(GCC, "gcc -E -dD $ARGV[0] |") || die "can't run gcc";
while(<GCC>){
- if(/^#define __NR_syscalls\s+/) {
+ if(/^#define __NR_Linux\s+([0-9]+)/){
+ # mips/mips64: extract offset
+ $offset = $1;
+ }
+ elsif(/^#define __NR_syscalls\s+/) {
# ignore redefinitions of __NR_syscalls
}
elsif(/^#define __NR_(\w+)\s+([0-9]+)/){
@@ -44,6 +51,9 @@ while(<GCC>){
elsif(/^#define __NR_(\w+)\s+\(\w+\+\s*([0-9]+)\)/){
fmt($1, $prev+$2)
}
+ elsif(/^#define __NR_(\w+)\s+\(__NR_Linux \+ ([0-9]+)/){
+ fmt($1, $2);
+ }
}
print <<EOF;
diff --git a/src/syscall/net_nacl.go b/src/syscall/net_nacl.go
index 1a0122c..9dc5d0c 100644
--- a/src/syscall/net_nacl.go
+++ b/src/syscall/net_nacl.go
@@ -6,6 +6,8 @@
// The simulation is not particularly tied to NaCl,
// but other systems have real networks.
+// All int64 times are UnixNanos.
+
package syscall
import (
@@ -50,6 +52,22 @@ func (t *timer) stop() {
stopTimer(&t.r)
}
+func (t *timer) reset(q *queue, deadline int64) {
+ if t.r.f != nil {
+ t.stop()
+ }
+ if deadline == 0 {
+ return
+ }
+ if t.r.f == nil {
+ t.q = q
+ t.r.f = timerExpired
+ t.r.arg = t
+ }
+ t.r.when = deadline
+ startTimer(&t.r)
+}
+
func timerExpired(i interface{}, seq uintptr) {
t := i.(*timer)
go func() {
@@ -233,9 +251,11 @@ type queue struct {
sync.Mutex
canRead sync.Cond
canWrite sync.Cond
- r int // total read index
- w int // total write index
- m int // index mask
+ rtimer *timer // non-nil if in read
+ wtimer *timer // non-nil if in write
+ r int // total read index
+ w int // total write index
+ m int // index mask
closed bool
}
@@ -259,9 +279,11 @@ func (q *queue) waitRead(n int, deadline int64) (int, error) {
}
var t timer
t.start(q, deadline)
+ q.rtimer = &t
for q.w-q.r == 0 && !q.closed && !t.expired {
q.canRead.Wait()
}
+ q.rtimer = nil
t.stop()
m := q.w - q.r
if m == 0 && t.expired {
@@ -281,9 +303,11 @@ func (q *queue) waitWrite(n int, deadline int64) (int, error) {
}
var t timer
t.start(q, deadline)
+ q.wtimer = &t
for q.w-q.r > q.m && !q.closed && !t.expired {
q.canWrite.Wait()
}
+ q.wtimer = nil
t.stop()
m := q.m + 1 - (q.w - q.r)
if m == 0 && t.expired {
@@ -871,6 +895,13 @@ func SetReadDeadline(fd int, t int64) error {
return err
}
atomic.StoreInt64(&f.rddeadline, t)
+ if bq := f.rd; bq != nil {
+ bq.Lock()
+ if timer := bq.rtimer; timer != nil {
+ timer.reset(&bq.queue, t)
+ }
+ bq.Unlock()
+ }
return nil
}
@@ -884,6 +915,13 @@ func SetWriteDeadline(fd int, t int64) error {
return err
}
atomic.StoreInt64(&f.wrdeadline, t)
+ if bq := f.wr; bq != nil {
+ bq.Lock()
+ if timer := bq.wtimer; timer != nil {
+ timer.reset(&bq.queue, t)
+ }
+ bq.Unlock()
+ }
return nil
}
diff --git a/src/syscall/netlink_linux.go b/src/syscall/netlink_linux.go
index 26b3040..1cda8c7 100644
--- a/src/syscall/netlink_linux.go
+++ b/src/syscall/netlink_linux.go
@@ -129,10 +129,11 @@ func ParseNetlinkMessage(b []byte) ([]NetlinkMessage, error) {
func netlinkMessageHeaderAndData(b []byte) (*NlMsghdr, []byte, int, error) {
h := (*NlMsghdr)(unsafe.Pointer(&b[0]))
- if int(h.Len) < NLMSG_HDRLEN || int(h.Len) > len(b) {
+ l := nlmAlignOf(int(h.Len))
+ if int(h.Len) < NLMSG_HDRLEN || l > len(b) {
return nil, nil, 0, EINVAL
}
- return h, b[NLMSG_HDRLEN:], nlmAlignOf(int(h.Len)), nil
+ return h, b[NLMSG_HDRLEN:], l, nil
}
// NetlinkRouteAttr represents a netlink route attribute.
diff --git a/src/syscall/setuidgid_32_linux.go b/src/syscall/setuidgid_32_linux.go
new file mode 100644
index 0000000..182f5d2
--- /dev/null
+++ b/src/syscall/setuidgid_32_linux.go
@@ -0,0 +1,13 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build linux
+// +build 386 arm
+
+package syscall
+
+const (
+ sys_SETGID = SYS_SETGID32
+ sys_SETUID = SYS_SETUID32
+)
diff --git a/src/syscall/setuidgid_linux.go b/src/syscall/setuidgid_linux.go
new file mode 100644
index 0000000..bf40d2d
--- /dev/null
+++ b/src/syscall/setuidgid_linux.go
@@ -0,0 +1,13 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build linux
+// +build !386,!arm
+
+package syscall
+
+const (
+ sys_SETGID = SYS_SETGID
+ sys_SETUID = SYS_SETUID
+)
diff --git a/src/syscall/sockcmsg_linux.go b/src/syscall/sockcmsg_linux.go
index 5a56b25..4cb9075 100644
--- a/src/syscall/sockcmsg_linux.go
+++ b/src/syscall/sockcmsg_linux.go
@@ -31,6 +31,9 @@ func ParseUnixCredentials(m *SocketControlMessage) (*Ucred, error) {
if m.Header.Type != SCM_CREDENTIALS {
return nil, EINVAL
}
+ if uintptr(len(m.Data)) < unsafe.Sizeof(Ucred{}) {
+ return nil, EINVAL
+ }
ucred := *(*Ucred)(unsafe.Pointer(&m.Data[0]))
return &ucred, nil
}
diff --git a/src/syscall/sockcmsg_unix.go b/src/syscall/sockcmsg_unix.go
index bc4caf5..5712bf1 100644
--- a/src/syscall/sockcmsg_unix.go
+++ b/src/syscall/sockcmsg_unix.go
@@ -13,9 +13,10 @@ import "unsafe"
// Round the length of a raw sockaddr up to align it properly.
func cmsgAlignOf(salen int) int {
salign := sizeofPtr
- // NOTE: It seems like 64-bit Darwin and DragonFly BSD kernels
- // still require 32-bit aligned access to network subsystem.
- if darwin64Bit || dragonfly64Bit {
+ // NOTE: It seems like 64-bit Darwin, DragonFly BSD and
+ // Solaris kernels still require 32-bit aligned access to
+ // network subsystem.
+ if darwin64Bit || dragonfly64Bit || solaris64Bit {
salign = 4
}
return (salen + salign - 1) & ^(salign - 1)
diff --git a/src/syscall/syscall.go b/src/syscall/syscall.go
index bb102c6..2fbe624 100644
--- a/src/syscall/syscall.go
+++ b/src/syscall/syscall.go
@@ -28,6 +28,8 @@ 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,
// If s contains a NUL byte this function panics instead of
// returning an error.
@@ -93,6 +95,10 @@ func (tv *Timeval) Nano() int64 {
return int64(tv.Sec)*1e9 + int64(tv.Usec)*1000
}
+// 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.
diff --git a/src/syscall/syscall_darwin.go b/src/syscall/syscall_darwin.go
index 380be70..689bc14 100644
--- a/src/syscall/syscall_darwin.go
+++ b/src/syscall/syscall_darwin.go
@@ -75,32 +75,16 @@ func nametomib(name string) (mib []_C_int, err error) {
return buf[0 : n/siz], nil
}
-// ParseDirent parses up to max directory entries in buf,
-// appending the names to names. It returns the number
-// bytes consumed from buf, the number of entries added
-// to names, and the new names slice.
-func ParseDirent(buf []byte, max int, names []string) (consumed int, count int, newnames []string) {
- origlen := len(buf)
- for max != 0 && len(buf) > 0 {
- dirent := (*Dirent)(unsafe.Pointer(&buf[0]))
- if dirent.Reclen == 0 {
- buf = nil
- break
- }
- buf = buf[dirent.Reclen:]
- if dirent.Ino == 0 { // File absent in directory.
- continue
- }
- bytes := (*[10000]byte)(unsafe.Pointer(&dirent.Name[0]))
- var name = string(bytes[0:dirent.Namlen])
- if name == "." || name == ".." { // Useless names
- continue
- }
- max--
- count++
- names = append(names, name)
- }
- return origlen - len(buf), count, names
+func direntIno(buf []byte) (uint64, bool) {
+ return readInt(buf, unsafe.Offsetof(Dirent{}.Ino), unsafe.Sizeof(Dirent{}.Ino))
+}
+
+func direntReclen(buf []byte) (uint64, bool) {
+ return readInt(buf, unsafe.Offsetof(Dirent{}.Reclen), unsafe.Sizeof(Dirent{}.Reclen))
+}
+
+func direntNamlen(buf []byte) (uint64, bool) {
+ return readInt(buf, unsafe.Offsetof(Dirent{}.Namlen), unsafe.Sizeof(Dirent{}.Namlen))
}
//sys ptrace(request int, pid int, addr uintptr, data uintptr) (err error)
diff --git a/src/syscall/syscall_darwin_386.go b/src/syscall/syscall_darwin_386.go
index f75de00..05d02fc 100644
--- a/src/syscall/syscall_darwin_386.go
+++ b/src/syscall/syscall_darwin_386.go
@@ -6,23 +6,12 @@ package syscall
import "unsafe"
-func Getpagesize() int { return 4096 }
-
-func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
-
-func NsecToTimespec(nsec int64) (ts Timespec) {
- ts.Sec = int32(nsec / 1e9)
- ts.Nsec = int32(nsec % 1e9)
- return
+func setTimespec(sec, nsec int64) Timespec {
+ return Timespec{Sec: int32(sec), Nsec: int32(nsec)}
}
-func TimevalToNsec(tv Timeval) int64 { return int64(tv.Sec)*1e9 + int64(tv.Usec)*1e3 }
-
-func NsecToTimeval(nsec int64) (tv Timeval) {
- nsec += 999 // round up to microsecond
- tv.Usec = int32(nsec % 1e9 / 1e3)
- tv.Sec = int32(nsec / 1e9)
- return
+func setTimeval(sec, usec int64) Timeval {
+ return Timeval{Sec: int32(sec), Usec: int32(usec)}
}
//sysnb gettimeofday(tp *Timeval) (sec int32, usec int32, err error)
diff --git a/src/syscall/syscall_darwin_amd64.go b/src/syscall/syscall_darwin_amd64.go
index 7908311..b15bd68 100644
--- a/src/syscall/syscall_darwin_amd64.go
+++ b/src/syscall/syscall_darwin_amd64.go
@@ -6,23 +6,12 @@ package syscall
import "unsafe"
-func Getpagesize() int { return 4096 }
-
-func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
-
-func NsecToTimespec(nsec int64) (ts Timespec) {
- ts.Sec = nsec / 1e9
- ts.Nsec = nsec % 1e9
- return
+func setTimespec(sec, nsec int64) Timespec {
+ return Timespec{Sec: sec, Nsec: nsec}
}
-func TimevalToNsec(tv Timeval) int64 { return int64(tv.Sec)*1e9 + int64(tv.Usec)*1e3 }
-
-func NsecToTimeval(nsec int64) (tv Timeval) {
- nsec += 999 // round up to microsecond
- tv.Usec = int32(nsec % 1e9 / 1e3)
- tv.Sec = int64(nsec / 1e9)
- return
+func setTimeval(sec, usec int64) Timeval {
+ return Timeval{Sec: sec, Usec: int32(usec)}
}
//sysnb gettimeofday(tp *Timeval) (sec int64, usec int32, err error)
diff --git a/src/syscall/syscall_darwin_arm.go b/src/syscall/syscall_darwin_arm.go
index fe43103..73bf83f 100644
--- a/src/syscall/syscall_darwin_arm.go
+++ b/src/syscall/syscall_darwin_arm.go
@@ -6,23 +6,12 @@ package syscall
import "unsafe"
-func Getpagesize() int { return 4096 }
-
-func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
-
-func NsecToTimespec(nsec int64) (ts Timespec) {
- ts.Sec = int32(nsec / 1e9)
- ts.Nsec = int32(nsec % 1e9)
- return
+func setTimespec(sec, nsec int64) Timespec {
+ return Timespec{Sec: int32(sec), Nsec: int32(nsec)}
}
-func TimevalToNsec(tv Timeval) int64 { return int64(tv.Sec)*1e9 + int64(tv.Usec)*1e3 }
-
-func NsecToTimeval(nsec int64) (tv Timeval) {
- nsec += 999 // round up to microsecond
- tv.Usec = int32(nsec % 1e9 / 1e3)
- tv.Sec = int32(nsec / 1e9)
- return
+func setTimeval(sec, usec int64) Timeval {
+ return Timeval{Sec: int32(sec), Usec: int32(usec)}
}
//sysnb gettimeofday(tp *Timeval) (sec int32, usec int32, err error)
diff --git a/src/syscall/syscall_darwin_arm64.go b/src/syscall/syscall_darwin_arm64.go
index d396e25..6c8f996 100644
--- a/src/syscall/syscall_darwin_arm64.go
+++ b/src/syscall/syscall_darwin_arm64.go
@@ -6,23 +6,12 @@ package syscall
import "unsafe"
-func Getpagesize() int { return 16384 }
-
-func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
-
-func NsecToTimespec(nsec int64) (ts Timespec) {
- ts.Sec = nsec / 1e9
- ts.Nsec = nsec % 1e9
- return
+func setTimespec(sec, nsec int64) Timespec {
+ return Timespec{Sec: int64(sec), Nsec: int64(nsec)}
}
-func TimevalToNsec(tv Timeval) int64 { return int64(tv.Sec)*1e9 + int64(tv.Usec)*1e3 }
-
-func NsecToTimeval(nsec int64) (tv Timeval) {
- nsec += 999 // round up to microsecond
- tv.Usec = int32(nsec % 1e9 / 1e3)
- tv.Sec = int64(nsec / 1e9)
- return
+func setTimeval(sec, usec int64) Timeval {
+ return Timeval{Sec: int64(sec), Usec: int32(usec)}
}
//sysnb gettimeofday(tp *Timeval) (sec int64, usec int32, err error)
diff --git a/src/syscall/syscall_darwin_test.go b/src/syscall/syscall_darwin_test.go
deleted file mode 100644
index cea5636..0000000
--- a/src/syscall/syscall_darwin_test.go
+++ /dev/null
@@ -1,23 +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 darwin
-// +build amd64 386 arm arm64
-
-package syscall_test
-
-import (
- "syscall"
- "testing"
-)
-
-func TestDarwinGettimeofday(t *testing.T) {
- tv := &syscall.Timeval{}
- if err := syscall.Gettimeofday(tv); err != nil {
- t.Fatal(err)
- }
- if tv.Sec == 0 && tv.Usec == 0 {
- t.Fatal("Sec and Usec both zero")
- }
-}
diff --git a/src/syscall/syscall_dragonfly.go b/src/syscall/syscall_dragonfly.go
index 4080b6b..980687c 100644
--- a/src/syscall/syscall_dragonfly.go
+++ b/src/syscall/syscall_dragonfly.go
@@ -56,29 +56,20 @@ func nametomib(name string) (mib []_C_int, err error) {
return buf[0 : n/siz], nil
}
-// ParseDirent parses up to max directory entries in buf,
-// appending the names to names. It returns the number
-// bytes consumed from buf, the number of entries added
-// to names, and the new names slice.
-func ParseDirent(buf []byte, max int, names []string) (consumed int, count int, newnames []string) {
- origlen := len(buf)
- for max != 0 && len(buf) > 0 {
- dirent := (*Dirent)(unsafe.Pointer(&buf[0]))
- reclen := int(16+dirent.Namlen+1+7) & ^7
- buf = buf[reclen:]
- if dirent.Fileno == 0 { // File absent in directory.
- continue
- }
- bytes := (*[10000]byte)(unsafe.Pointer(&dirent.Name[0]))
- var name = string(bytes[0:dirent.Namlen])
- if name == "." || name == ".." { // Useless names
- continue
- }
- max--
- count++
- names = append(names, name)
+func direntIno(buf []byte) (uint64, bool) {
+ return readInt(buf, unsafe.Offsetof(Dirent{}.Fileno), unsafe.Sizeof(Dirent{}.Fileno))
+}
+
+func direntReclen(buf []byte) (uint64, bool) {
+ namlen, ok := direntNamlen(buf)
+ if !ok {
+ return 0, false
}
- return origlen - len(buf), count, names
+ return (16 + namlen + 1 + 7) & ^uint64(7), true
+}
+
+func direntNamlen(buf []byte) (uint64, bool) {
+ return readInt(buf, unsafe.Offsetof(Dirent{}.Namlen), unsafe.Sizeof(Dirent{}.Namlen))
}
//sysnb pipe() (r int, w int, err error)
diff --git a/src/syscall/syscall_dragonfly_amd64.go b/src/syscall/syscall_dragonfly_amd64.go
index 70c2ffb..bb6130d 100644
--- a/src/syscall/syscall_dragonfly_amd64.go
+++ b/src/syscall/syscall_dragonfly_amd64.go
@@ -6,23 +6,12 @@ package syscall
import "unsafe"
-func Getpagesize() int { return 4096 }
-
-func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
-
-func NsecToTimespec(nsec int64) (ts Timespec) {
- ts.Sec = nsec / 1e9
- ts.Nsec = nsec % 1e9
- return
+func setTimespec(sec, nsec int64) Timespec {
+ return Timespec{Sec: sec, Nsec: nsec}
}
-func TimevalToNsec(tv Timeval) int64 { return int64(tv.Sec)*1e9 + int64(tv.Usec)*1e3 }
-
-func NsecToTimeval(nsec int64) (tv Timeval) {
- nsec += 999 // round up to microsecond
- tv.Usec = nsec % 1e9 / 1e3
- tv.Sec = int64(nsec / 1e9)
- return
+func setTimeval(sec, usec int64) Timeval {
+ return Timeval{Sec: sec, Usec: usec}
}
func SetKevent(k *Kevent_t, fd, mode, flags int) {
diff --git a/src/syscall/syscall_freebsd.go b/src/syscall/syscall_freebsd.go
index 950dc64..2a304cd 100644
--- a/src/syscall/syscall_freebsd.go
+++ b/src/syscall/syscall_freebsd.go
@@ -54,32 +54,16 @@ func nametomib(name string) (mib []_C_int, err error) {
return buf[0 : n/siz], nil
}
-// ParseDirent parses up to max directory entries in buf,
-// appending the names to names. It returns the number
-// bytes consumed from buf, the number of entries added
-// to names, and the new names slice.
-func ParseDirent(buf []byte, max int, names []string) (consumed int, count int, newnames []string) {
- origlen := len(buf)
- for max != 0 && len(buf) > 0 {
- dirent := (*Dirent)(unsafe.Pointer(&buf[0]))
- if dirent.Reclen == 0 {
- buf = nil
- break
- }
- buf = buf[dirent.Reclen:]
- if dirent.Fileno == 0 { // File absent in directory.
- continue
- }
- bytes := (*[10000]byte)(unsafe.Pointer(&dirent.Name[0]))
- var name = string(bytes[0:dirent.Namlen])
- if name == "." || name == ".." { // Useless names
- continue
- }
- max--
- count++
- names = append(names, name)
- }
- return origlen - len(buf), count, names
+func direntIno(buf []byte) (uint64, bool) {
+ return readInt(buf, unsafe.Offsetof(Dirent{}.Fileno), unsafe.Sizeof(Dirent{}.Fileno))
+}
+
+func direntReclen(buf []byte) (uint64, bool) {
+ return readInt(buf, unsafe.Offsetof(Dirent{}.Reclen), unsafe.Sizeof(Dirent{}.Reclen))
+}
+
+func direntNamlen(buf []byte) (uint64, bool) {
+ return readInt(buf, unsafe.Offsetof(Dirent{}.Namlen), unsafe.Sizeof(Dirent{}.Namlen))
}
//sysnb pipe() (r int, w int, err error)
diff --git a/src/syscall/syscall_freebsd_386.go b/src/syscall/syscall_freebsd_386.go
index ebd3d4c..60359e3 100644
--- a/src/syscall/syscall_freebsd_386.go
+++ b/src/syscall/syscall_freebsd_386.go
@@ -6,23 +6,12 @@ package syscall
import "unsafe"
-func Getpagesize() int { return 4096 }
-
-func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
-
-func NsecToTimespec(nsec int64) (ts Timespec) {
- ts.Sec = int32(nsec / 1e9)
- ts.Nsec = int32(nsec % 1e9)
- return
+func setTimespec(sec, nsec int64) Timespec {
+ return Timespec{Sec: int32(sec), Nsec: int32(nsec)}
}
-func TimevalToNsec(tv Timeval) int64 { return int64(tv.Sec)*1e9 + int64(tv.Usec)*1e3 }
-
-func NsecToTimeval(nsec int64) (tv Timeval) {
- nsec += 999 // round up to microsecond
- tv.Usec = int32(nsec % 1e9 / 1e3)
- tv.Sec = int32(nsec / 1e9)
- return
+func setTimeval(sec, usec int64) Timeval {
+ return Timeval{Sec: int32(sec), Usec: int32(usec)}
}
func SetKevent(k *Kevent_t, fd, mode, flags int) {
diff --git a/src/syscall/syscall_freebsd_amd64.go b/src/syscall/syscall_freebsd_amd64.go
index 70c2ffb..bb6130d 100644
--- a/src/syscall/syscall_freebsd_amd64.go
+++ b/src/syscall/syscall_freebsd_amd64.go
@@ -6,23 +6,12 @@ package syscall
import "unsafe"
-func Getpagesize() int { return 4096 }
-
-func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
-
-func NsecToTimespec(nsec int64) (ts Timespec) {
- ts.Sec = nsec / 1e9
- ts.Nsec = nsec % 1e9
- return
+func setTimespec(sec, nsec int64) Timespec {
+ return Timespec{Sec: sec, Nsec: nsec}
}
-func TimevalToNsec(tv Timeval) int64 { return int64(tv.Sec)*1e9 + int64(tv.Usec)*1e3 }
-
-func NsecToTimeval(nsec int64) (tv Timeval) {
- nsec += 999 // round up to microsecond
- tv.Usec = nsec % 1e9 / 1e3
- tv.Sec = int64(nsec / 1e9)
- return
+func setTimeval(sec, usec int64) Timeval {
+ return Timeval{Sec: sec, Usec: usec}
}
func SetKevent(k *Kevent_t, fd, mode, flags int) {
diff --git a/src/syscall/syscall_freebsd_arm.go b/src/syscall/syscall_freebsd_arm.go
index ab72871..351f88f 100644
--- a/src/syscall/syscall_freebsd_arm.go
+++ b/src/syscall/syscall_freebsd_arm.go
@@ -6,23 +6,12 @@ package syscall
import "unsafe"
-func Getpagesize() int { return 4096 }
-
-func TimespecToNsec(ts Timespec) int64 { return ts.Sec*1e9 + int64(ts.Nsec) }
-
-func NsecToTimespec(nsec int64) (ts Timespec) {
- ts.Sec = nsec / 1e9
- ts.Nsec = int32(nsec % 1e9)
- return
+func setTimespec(sec, nsec int64) Timespec {
+ return Timespec{Sec: sec, Nsec: int32(nsec)}
}
-func TimevalToNsec(tv Timeval) int64 { return tv.Sec*1e9 + int64(tv.Usec)*1e3 }
-
-func NsecToTimeval(nsec int64) (tv Timeval) {
- nsec += 999 // round up to microsecond
- tv.Usec = int32(nsec % 1e9 / 1e3)
- tv.Sec = nsec / 1e9
- return
+func setTimeval(sec, usec int64) Timeval {
+ return Timeval{Sec: sec, Usec: int32(usec)}
}
func SetKevent(k *Kevent_t, fd, mode, flags int) {
diff --git a/src/syscall/syscall_linux.go b/src/syscall/syscall_linux.go
index 73a16f8..a8801ad 100644
--- a/src/syscall/syscall_linux.go
+++ b/src/syscall/syscall_linux.go
@@ -757,38 +757,24 @@ func Reboot(cmd int) (err error) {
return reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, cmd, "")
}
-func clen(n []byte) int {
- for i := 0; i < len(n); i++ {
- if n[i] == 0 {
- return i
- }
- }
- return len(n)
-}
-
func ReadDirent(fd int, buf []byte) (n int, err error) {
return Getdents(fd, buf)
}
-func ParseDirent(buf []byte, max int, names []string) (consumed int, count int, newnames []string) {
- origlen := len(buf)
- count = 0
- for max != 0 && len(buf) > 0 {
- dirent := (*Dirent)(unsafe.Pointer(&buf[0]))
- buf = buf[dirent.Reclen:]
- if dirent.Ino == 0 { // File absent in directory.
- continue
- }
- bytes := (*[10000]byte)(unsafe.Pointer(&dirent.Name[0]))
- var name = string(bytes[0:clen(bytes[:])])
- if name == "." || name == ".." { // Useless names
- continue
- }
- max--
- count++
- names = append(names, name)
+func direntIno(buf []byte) (uint64, bool) {
+ return readInt(buf, unsafe.Offsetof(Dirent{}.Ino), unsafe.Sizeof(Dirent{}.Ino))
+}
+
+func direntReclen(buf []byte) (uint64, bool) {
+ return readInt(buf, unsafe.Offsetof(Dirent{}.Reclen), unsafe.Sizeof(Dirent{}.Reclen))
+}
+
+func direntNamlen(buf []byte) (uint64, bool) {
+ reclen, ok := direntReclen(buf)
+ if !ok {
+ return 0, false
}
- return origlen - len(buf), count, names
+ return reclen - uint64(unsafe.Offsetof(Dirent{}.Name)), true
}
//sys mount(source string, target string, fstype string, flags uintptr, data *byte) (err error)
@@ -862,7 +848,7 @@ func Getpgrp() (pid int) {
//sys Nanosleep(time *Timespec, leftover *Timespec) (err error)
//sys Pause() (err error)
//sys PivotRoot(newroot string, putold string) (err error) = SYS_PIVOT_ROOT
-//sysnb prlimit(pid int, resource int, old *Rlimit, newlimit *Rlimit) (err error) = SYS_PRLIMIT64
+//sysnb prlimit(pid int, resource int, newlimit *Rlimit, old *Rlimit) (err error) = SYS_PRLIMIT64
//sys read(fd int, p []byte) (n int, err error)
//sys Removexattr(path string, attr string) (err error)
//sys Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err error)
diff --git a/src/syscall/syscall_linux_386.go b/src/syscall/syscall_linux_386.go
index d9e0ed5..00cf262 100644
--- a/src/syscall/syscall_linux_386.go
+++ b/src/syscall/syscall_linux_386.go
@@ -10,27 +10,17 @@ package syscall
import "unsafe"
const (
- _SYS_dup = SYS_DUP2
- _SYS_getdents = SYS_GETDENTS64
+ _SYS_dup = SYS_DUP2
+ _SYS_getdents = SYS_GETDENTS64
+ _SYS_setgroups = SYS_SETGROUPS32
)
-func Getpagesize() int { return 4096 }
-
-func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
-
-func NsecToTimespec(nsec int64) (ts Timespec) {
- ts.Sec = int32(nsec / 1e9)
- ts.Nsec = int32(nsec % 1e9)
- return
+func setTimespec(sec, nsec int64) Timespec {
+ return Timespec{Sec: int32(sec), Nsec: int32(nsec)}
}
-func TimevalToNsec(tv Timeval) int64 { return int64(tv.Sec)*1e9 + int64(tv.Usec)*1e3 }
-
-func NsecToTimeval(nsec int64) (tv Timeval) {
- nsec += 999 // round up to microsecond
- tv.Sec = int32(nsec / 1e9)
- tv.Usec = int32(nsec % 1e9 / 1e3)
- return
+func setTimeval(sec, usec int64) Timeval {
+ return Timeval{Sec: int32(sec), Usec: int32(usec)}
}
//sysnb pipe(p *[2]_C_int) (err error)
diff --git a/src/syscall/syscall_linux_amd64.go b/src/syscall/syscall_linux_amd64.go
index d1bda29..0184d7d 100644
--- a/src/syscall/syscall_linux_amd64.go
+++ b/src/syscall/syscall_linux_amd64.go
@@ -5,8 +5,9 @@
package syscall
const (
- _SYS_dup = SYS_DUP2
- _SYS_getdents = SYS_GETDENTS64
+ _SYS_dup = SYS_DUP2
+ _SYS_getdents = SYS_GETDENTS64
+ _SYS_setgroups = SYS_SETGROUPS
)
//sys Dup2(oldfd int, newfd int) (err error)
@@ -72,8 +73,6 @@ func Gettimeofday(tv *Timeval) (err error) {
return nil
}
-func Getpagesize() int { return 4096 }
-
func Time(t *Time_t) (tt Time_t, err error) {
var tv Timeval
errno := gettimeofday(&tv)
@@ -86,21 +85,12 @@ func Time(t *Time_t) (tt Time_t, err error) {
return Time_t(tv.Sec), nil
}
-func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
-
-func NsecToTimespec(nsec int64) (ts Timespec) {
- ts.Sec = nsec / 1e9
- ts.Nsec = nsec % 1e9
- return
+func setTimespec(sec, nsec int64) Timespec {
+ return Timespec{Sec: sec, Nsec: nsec}
}
-func TimevalToNsec(tv Timeval) int64 { return int64(tv.Sec)*1e9 + int64(tv.Usec)*1e3 }
-
-func NsecToTimeval(nsec int64) (tv Timeval) {
- nsec += 999 // round up to microsecond
- tv.Sec = nsec / 1e9
- tv.Usec = nsec % 1e9 / 1e3
- return
+func setTimeval(sec, usec int64) Timeval {
+ return Timeval{Sec: sec, Usec: usec}
}
//sysnb pipe(p *[2]_C_int) (err error)
diff --git a/src/syscall/syscall_linux_arm.go b/src/syscall/syscall_linux_arm.go
index 7c78254..2ed31f0 100644
--- a/src/syscall/syscall_linux_arm.go
+++ b/src/syscall/syscall_linux_arm.go
@@ -7,25 +7,17 @@ package syscall
import "unsafe"
const (
- _SYS_dup = SYS_DUP2
- _SYS_getdents = SYS_GETDENTS64
+ _SYS_dup = SYS_DUP2
+ _SYS_getdents = SYS_GETDENTS64
+ _SYS_setgroups = SYS_SETGROUPS32
)
-func Getpagesize() int { return 4096 }
-
-func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
-
-func NsecToTimespec(nsec int64) (ts Timespec) {
- ts.Sec = int32(nsec / 1e9)
- ts.Nsec = int32(nsec % 1e9)
- return
+func setTimespec(sec, nsec int64) Timespec {
+ return Timespec{Sec: int32(sec), Nsec: int32(nsec)}
}
-func NsecToTimeval(nsec int64) (tv Timeval) {
- nsec += 999 // round up to microsecond
- tv.Sec = int32(nsec / 1e9)
- tv.Usec = int32(nsec % 1e9 / 1e3)
- return
+func setTimeval(sec, usec int64) Timeval {
+ return Timeval{Sec: int32(sec), Usec: int32(usec)}
}
func Pipe(p []int) (err error) {
diff --git a/src/syscall/syscall_linux_arm64.go b/src/syscall/syscall_linux_arm64.go
index 5f1478c..4462139 100644
--- a/src/syscall/syscall_linux_arm64.go
+++ b/src/syscall/syscall_linux_arm64.go
@@ -5,8 +5,9 @@
package syscall
const (
- _SYS_dup = SYS_DUP3
- _SYS_getdents = SYS_GETDENTS64
+ _SYS_dup = SYS_DUP3
+ _SYS_getdents = SYS_GETDENTS64
+ _SYS_setgroups = SYS_SETGROUPS
)
//sys Fchown(fd int, uid int, gid int) (err error)
@@ -68,26 +69,15 @@ func Lstat(path string, stat *Stat_t) (err error) {
//sys sendmsg(s int, msg *Msghdr, flags int) (n int, err error)
//sys mmap(addr uintptr, length uintptr, prot int, flags int, fd int, offset int64) (xaddr uintptr, err error)
-func Getpagesize() int { return 65536 }
-
//sysnb Gettimeofday(tv *Timeval) (err error)
//sysnb Time(t *Time_t) (tt Time_t, err error)
-func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
-
-func NsecToTimespec(nsec int64) (ts Timespec) {
- ts.Sec = nsec / 1e9
- ts.Nsec = nsec % 1e9
- return
+func setTimespec(sec, nsec int64) Timespec {
+ return Timespec{Sec: sec, Nsec: nsec}
}
-func TimevalToNsec(tv Timeval) int64 { return int64(tv.Sec)*1e9 + int64(tv.Usec)*1e3 }
-
-func NsecToTimeval(nsec int64) (tv Timeval) {
- nsec += 999 // round up to microsecond
- tv.Sec = nsec / 1e9
- tv.Usec = nsec % 1e9 / 1e3
- return
+func setTimeval(sec, usec int64) Timeval {
+ return Timeval{Sec: sec, Usec: usec}
}
func Pipe(p []int) (err error) {
diff --git a/src/syscall/syscall_linux_mips64x.go b/src/syscall/syscall_linux_mips64x.go
index a14485a..9fd7982 100644
--- a/src/syscall/syscall_linux_mips64x.go
+++ b/src/syscall/syscall_linux_mips64x.go
@@ -15,7 +15,8 @@ const (
// to support older kernels, we have to use getdents for mips64.
// Also note that struct dirent is different for these two.
// Lookup linux_dirent{,64} in kernel source code for details.
- _SYS_getdents = SYS_GETDENTS
+ _SYS_getdents = SYS_GETDENTS
+ _SYS_setgroups = SYS_SETGROUPS
)
//sys Dup2(oldfd int, newfd int) (err error)
@@ -65,8 +66,6 @@ const (
//sys sendmsg(s int, msg *Msghdr, flags int) (n int, err error)
//sys mmap(addr uintptr, length uintptr, prot int, flags int, fd int, offset int64) (xaddr uintptr, err error)
-func Getpagesize() int { return 65536 }
-
//sysnb Gettimeofday(tv *Timeval) (err error)
func Time(t *Time_t) (tt Time_t, err error) {
@@ -81,21 +80,12 @@ func Time(t *Time_t) (tt Time_t, err error) {
return Time_t(tv.Sec), nil
}
-func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
-
-func NsecToTimespec(nsec int64) (ts Timespec) {
- ts.Sec = nsec / 1e9
- ts.Nsec = nsec % 1e9
- return
+func setTimespec(sec, nsec int64) Timespec {
+ return Timespec{Sec: sec, Nsec: nsec}
}
-func TimevalToNsec(tv Timeval) int64 { return int64(tv.Sec)*1e9 + int64(tv.Usec)*1e3 }
-
-func NsecToTimeval(nsec int64) (tv Timeval) {
- nsec += 999 // round up to microsecond
- tv.Sec = nsec / 1e9
- tv.Usec = nsec % 1e9 / 1e3
- return
+func setTimeval(sec, usec int64) Timeval {
+ return Timeval{Sec: sec, Usec: usec}
}
func Pipe(p []int) (err error) {
diff --git a/src/syscall/syscall_linux_mipsx.go b/src/syscall/syscall_linux_mipsx.go
new file mode 100644
index 0000000..48e79ea
--- /dev/null
+++ b/src/syscall/syscall_linux_mipsx.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.
+
+// +build linux
+// +build mips mipsle
+
+package syscall
+
+import "unsafe"
+
+const (
+ _SYS_dup = SYS_DUP2
+ _SYS_getdents = SYS_GETDENTS64
+ _SYS_setgroups = SYS_SETGROUPS
+)
+
+func Syscall9(trap, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err Errno)
+
+//sys Dup2(oldfd int, newfd int) (err error)
+//sys Fchown(fd int, uid int, gid int) (err error)
+//sys Ftruncate(fd int, length int64) (err error) = SYS_FTRUNCATE64
+//sysnb Getegid() (egid int)
+//sysnb Geteuid() (euid int)
+//sysnb Getgid() (gid int)
+//sysnb Getuid() (uid int)
+//sys Lchown(path string, uid int, gid int) (err error)
+//sys Listen(s int, n int) (err error)
+//sys Pread(fd int, p []byte, offset int64) (n int, err error) = SYS_PREAD64
+//sys Pwrite(fd int, p []byte, offset int64) (n int, err error) = SYS_PWRITE64
+//sys Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, err error) = SYS__NEWSELECT
+//sys sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) = SYS_SENDFILE64
+//sys Setfsgid(gid int) (err error)
+//sys Setfsuid(uid int) (err error)
+//sysnb Setregid(rgid int, egid int) (err error)
+//sysnb Setresgid(rgid int, egid int, sgid int) (err error)
+//sysnb Setresuid(ruid int, euid int, suid int) (err error)
+
+//sysnb Setreuid(ruid int, euid int) (err error)
+//sys Shutdown(fd int, how int) (err error)
+//sys Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int64, err error)
+
+//sys SyncFileRange(fd int, off int64, n int64, flags int) (err error)
+//sys Truncate(path string, length int64) (err error) = SYS_TRUNCATE64
+//sys accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error)
+//sys accept4(s int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (fd int, err error)
+//sys bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error)
+//sys connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error)
+//sysnb getgroups(n int, list *_Gid_t) (nn int, err error)
+//sysnb setgroups(n int, list *_Gid_t) (err error)
+//sys getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error)
+//sys setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error)
+//sysnb socket(domain int, typ int, proto int) (fd int, err error)
+//sysnb socketpair(domain int, typ int, proto int, fd *[2]int32) (err error)
+//sysnb getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error)
+//sysnb getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error)
+//sys recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Socklen) (n int, err error)
+//sys sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error)
+//sys recvmsg(s int, msg *Msghdr, flags int) (n int, err error)
+//sys sendmsg(s int, msg *Msghdr, flags int) (n int, err error)
+
+//sysnb InotifyInit() (fd int, err error)
+//sys Ioperm(from int, num int, on int) (err error)
+//sys Iopl(level int) (err error)
+
+//sysnb Gettimeofday(tv *Timeval) (err error)
+//sysnb Time(t *Time_t) (tt Time_t, err error)
+
+//sys Lstat(path string, stat *Stat_t) (err error) = SYS_LSTAT64
+//sys Fstat(fd int, stat *Stat_t) (err error) = SYS_FSTAT64
+//sys Stat(path string, stat *Stat_t) (err error) = SYS_STAT64
+
+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)
+ }
+ return
+}
+
+func Statfs(path string, buf *Statfs_t) (err error) {
+ p, err := BytePtrFromString(path)
+ if err != nil {
+ 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)
+ }
+ return
+}
+
+func Seek(fd int, offset int64, whence int) (off int64, err error) {
+ _, _, e := Syscall6(SYS__LLSEEK, uintptr(fd), uintptr(offset>>32), uintptr(offset), uintptr(unsafe.Pointer(&off)), uintptr(whence), 0)
+ if e != 0 {
+ err = errnoErr(e)
+ }
+ return
+}
+
+func setTimespec(sec, nsec int64) Timespec {
+ return Timespec{Sec: int32(sec), Nsec: int32(nsec)}
+}
+
+func setTimeval(sec, usec int64) Timeval {
+ return Timeval{Sec: int32(sec), Usec: int32(usec)}
+}
+
+//sysnb pipe2(p *[2]_C_int, flags int) (err error)
+
+func Pipe2(p []int, flags int) (err error) {
+ if len(p) != 2 {
+ return EINVAL
+ }
+ var pp [2]_C_int
+ err = pipe2(&pp, flags)
+ p[0] = int(pp[0])
+ p[1] = int(pp[1])
+ return
+}
+
+func Pipe(p []int) (err error) {
+ if len(p) != 2 {
+ return EINVAL
+ }
+ var pp [2]_C_int
+ err = pipe2(&pp, 0)
+ p[0] = int(pp[0])
+ p[1] = int(pp[1])
+ return
+}
+
+//sys mmap2(addr uintptr, length uintptr, prot int, flags int, fd int, pageOffset uintptr) (xaddr uintptr, err error)
+
+func mmap(addr uintptr, length uintptr, prot int, flags int, fd int, offset int64) (xaddr uintptr, err error) {
+ page := uintptr(offset / 4096)
+ if offset != int64(page)*4096 {
+ return 0, EINVAL
+ }
+ return mmap2(addr, length, prot, flags, fd, page)
+}
+
+const rlimInf32 = ^uint32(0)
+const rlimInf64 = ^uint64(0)
+
+type rlimit32 struct {
+ Cur uint32
+ Max uint32
+}
+
+//sysnb getrlimit(resource int, rlim *rlimit32) (err error) = SYS_GETRLIMIT
+
+func Getrlimit(resource int, rlim *Rlimit) (err error) {
+ err = prlimit(0, resource, nil, rlim)
+ if err != ENOSYS {
+ return err
+ }
+
+ rl := rlimit32{}
+ err = getrlimit(resource, &rl)
+ if err != nil {
+ return
+ }
+
+ if rl.Cur == rlimInf32 {
+ rlim.Cur = rlimInf64
+ } else {
+ rlim.Cur = uint64(rl.Cur)
+ }
+
+ if rl.Max == rlimInf32 {
+ rlim.Max = rlimInf64
+ } else {
+ rlim.Max = uint64(rl.Max)
+ }
+ return
+}
+
+//sysnb setrlimit(resource int, rlim *rlimit32) (err error) = SYS_SETRLIMIT
+
+func Setrlimit(resource int, rlim *Rlimit) (err error) {
+ err = prlimit(0, resource, rlim, nil)
+ if err != ENOSYS {
+ return err
+ }
+
+ rl := rlimit32{}
+ if rlim.Cur == rlimInf64 {
+ rl.Cur = rlimInf32
+ } else if rlim.Cur < uint64(rlimInf32) {
+ rl.Cur = uint32(rlim.Cur)
+ } else {
+ return EINVAL
+ }
+ if rlim.Max == rlimInf64 {
+ rl.Max = rlimInf32
+ } else if rlim.Max < uint64(rlimInf32) {
+ rl.Max = uint32(rlim.Max)
+ } else {
+ return EINVAL
+ }
+
+ return setrlimit(resource, &rl)
+}
+
+func (r *PtraceRegs) PC() uint64 { return uint64(r.Regs[64]) }
+
+func (r *PtraceRegs) SetPC(pc uint64) { r.Regs[64] = uint32(pc) }
+
+func (iov *Iovec) SetLen(length int) {
+ iov.Len = uint32(length)
+}
+
+func (msghdr *Msghdr) SetControllen(length int) {
+ msghdr.Controllen = uint32(length)
+}
+
+func (cmsg *Cmsghdr) SetLen(length int) {
+ cmsg.Len = uint32(length)
+}
diff --git a/src/syscall/syscall_linux_ppc64x.go b/src/syscall/syscall_linux_ppc64x.go
index 9f1c07e..307abc9 100644
--- a/src/syscall/syscall_linux_ppc64x.go
+++ b/src/syscall/syscall_linux_ppc64x.go
@@ -8,8 +8,9 @@
package syscall
const (
- _SYS_dup = SYS_DUP2
- _SYS_getdents = SYS_GETDENTS64
+ _SYS_dup = SYS_DUP2
+ _SYS_getdents = SYS_GETDENTS64
+ _SYS_setgroups = SYS_SETGROUPS
)
//sys Dup2(oldfd int, newfd int) (err error)
@@ -64,26 +65,15 @@ const (
//sys sendmsg(s int, msg *Msghdr, flags int) (n int, err error)
//sys mmap(addr uintptr, length uintptr, prot int, flags int, fd int, offset int64) (xaddr uintptr, err error)
-func Getpagesize() int { return 65536 }
-
//sysnb Gettimeofday(tv *Timeval) (err error)
//sysnb Time(t *Time_t) (tt Time_t, err error)
-func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
-
-func NsecToTimespec(nsec int64) (ts Timespec) {
- ts.Sec = nsec / 1e9
- ts.Nsec = nsec % 1e9
- return
+func setTimespec(sec, nsec int64) Timespec {
+ return Timespec{Sec: sec, Nsec: nsec}
}
-func TimevalToNsec(tv Timeval) int64 { return int64(tv.Sec)*1e9 + int64(tv.Usec)*1e3 }
-
-func NsecToTimeval(nsec int64) (tv Timeval) {
- nsec += 999 // round up to microsecond
- tv.Sec = nsec / 1e9
- tv.Usec = nsec % 1e9 / 1e3
- return
+func setTimeval(sec, usec int64) Timeval {
+ return Timeval{Sec: sec, Usec: usec}
}
func Pipe(p []int) (err error) {
diff --git a/src/syscall/syscall_linux_s390x.go b/src/syscall/syscall_linux_s390x.go
index d74277a..148790e 100644
--- a/src/syscall/syscall_linux_s390x.go
+++ b/src/syscall/syscall_linux_s390x.go
@@ -7,8 +7,9 @@ package syscall
import "unsafe"
const (
- _SYS_dup = SYS_DUP2
- _SYS_getdents = SYS_GETDENTS64
+ _SYS_dup = SYS_DUP2
+ _SYS_getdents = SYS_GETDENTS64
+ _SYS_setgroups = SYS_SETGROUPS
)
//sys Dup2(oldfd int, newfd int) (err error)
@@ -44,8 +45,6 @@ const (
//sysnb getgroups(n int, list *_Gid_t) (nn int, err error)
//sysnb setgroups(n int, list *_Gid_t) (err error)
-func Getpagesize() int { return 4096 }
-
//sysnb Gettimeofday(tv *Timeval) (err error)
func Time(t *Time_t) (tt Time_t, err error) {
@@ -60,21 +59,12 @@ func Time(t *Time_t) (tt Time_t, err error) {
return Time_t(tv.Sec), nil
}
-func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
-
-func NsecToTimespec(nsec int64) (ts Timespec) {
- ts.Sec = nsec / 1e9
- ts.Nsec = nsec % 1e9
- return
+func setTimespec(sec, nsec int64) Timespec {
+ return Timespec{Sec: sec, Nsec: nsec}
}
-func TimevalToNsec(tv Timeval) int64 { return int64(tv.Sec)*1e9 + int64(tv.Usec)*1e3 }
-
-func NsecToTimeval(nsec int64) (tv Timeval) {
- nsec += 999 // round up to microsecond
- tv.Sec = nsec / 1e9
- tv.Usec = nsec % 1e9 / 1e3
- return
+func setTimeval(sec, usec int64) Timeval {
+ return Timeval{Sec: sec, Usec: usec}
}
func Pipe(p []int) (err error) {
diff --git a/src/syscall/syscall_linux_test.go b/src/syscall/syscall_linux_test.go
index 4cabf6c..2c4d953 100644
--- a/src/syscall/syscall_linux_test.go
+++ b/src/syscall/syscall_linux_test.go
@@ -138,3 +138,31 @@ func deathSignalChild() {
fmt.Println("not ok")
os.Exit(1)
}
+
+func TestParseNetlinkMessage(t *testing.T) {
+ for i, b := range [][]byte{
+ {103, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 2, 11, 0, 1, 0, 0, 0, 0, 5, 8, 0, 3,
+ 0, 8, 0, 6, 0, 0, 0, 0, 1, 63, 0, 10, 0, 69, 16, 0, 59, 39, 82, 64, 0, 64, 6, 21, 89, 127, 0, 0,
+ 1, 127, 0, 0, 1, 230, 228, 31, 144, 32, 186, 155, 211, 185, 151, 209, 179, 128, 24, 1, 86,
+ 53, 119, 0, 0, 1, 1, 8, 10, 0, 17, 234, 12, 0, 17, 189, 126, 107, 106, 108, 107, 106, 13, 10,
+ },
+ {106, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 2, 11, 0, 1, 0, 0, 0, 0, 3, 8, 0, 3,
+ 0, 8, 0, 6, 0, 0, 0, 0, 1, 66, 0, 10, 0, 69, 0, 0, 62, 230, 255, 64, 0, 64, 6, 85, 184, 127, 0, 0,
+ 1, 127, 0, 0, 1, 237, 206, 31, 144, 73, 197, 128, 65, 250, 60, 192, 97, 128, 24, 1, 86, 253, 21, 0,
+ 0, 1, 1, 8, 10, 0, 51, 106, 89, 0, 51, 102, 198, 108, 104, 106, 108, 107, 104, 108, 107, 104, 10,
+ },
+ {102, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 2, 11, 0, 1, 0, 0, 0, 0, 1, 8, 0, 3, 0,
+ 8, 0, 6, 0, 0, 0, 0, 1, 62, 0, 10, 0, 69, 0, 0, 58, 231, 2, 64, 0, 64, 6, 85, 185, 127, 0, 0, 1, 127,
+ 0, 0, 1, 237, 206, 31, 144, 73, 197, 128, 86, 250, 60, 192, 97, 128, 24, 1, 86, 104, 64, 0, 0, 1, 1, 8,
+ 10, 0, 52, 198, 200, 0, 51, 135, 232, 101, 115, 97, 103, 103, 10,
+ },
+ } {
+ m, err := syscall.ParseNetlinkMessage(b)
+ if err != syscall.EINVAL {
+ t.Errorf("#%d: got %v; want EINVAL", i, err)
+ }
+ if m != nil {
+ t.Errorf("#%d: got %v; want nil", i, m)
+ }
+ }
+}
diff --git a/src/syscall/syscall_nacl.go b/src/syscall/syscall_nacl.go
index ba6eafe..3247505 100644
--- a/src/syscall/syscall_nacl.go
+++ b/src/syscall/syscall_nacl.go
@@ -26,34 +26,20 @@ type Dirent struct {
Name [256]byte
}
-func ParseDirent(buf []byte, max int, names []string) (consumed int, count int, newnames []string) {
- origlen := len(buf)
- count = 0
- for max != 0 && len(buf) > 0 {
- dirent := (*Dirent)(unsafe.Pointer(&buf[0]))
- buf = buf[dirent.Reclen:]
- if dirent.Ino == 0 { // File absent in directory.
- continue
- }
- bytes := (*[512 + PathMax]byte)(unsafe.Pointer(&dirent.Name[0]))
- var name = string(bytes[0:clen(bytes[:])])
- if name == "." || name == ".." { // Useless names
- continue
- }
- max--
- count++
- names = append(names, name)
- }
- return origlen - len(buf), count, names
+func direntIno(buf []byte) (uint64, bool) {
+ return readInt(buf, unsafe.Offsetof(Dirent{}.Ino), unsafe.Sizeof(Dirent{}.Ino))
}
-func clen(n []byte) int {
- for i := 0; i < len(n); i++ {
- if n[i] == 0 {
- return i
- }
+func direntReclen(buf []byte) (uint64, bool) {
+ return readInt(buf, unsafe.Offsetof(Dirent{}.Reclen), unsafe.Sizeof(Dirent{}.Reclen))
+}
+
+func direntNamlen(buf []byte) (uint64, bool) {
+ reclen, ok := direntReclen(buf)
+ if !ok {
+ return 0, false
}
- return len(n)
+ return reclen - uint64(unsafe.Offsetof(Dirent{}.Name)), true
}
const PathMax = 256
@@ -292,9 +278,9 @@ func Getegid() int { return 1 }
func Geteuid() int { return 1 }
func Getgid() int { return 1 }
func Getgroups() ([]int, error) { return []int{1}, nil }
-func Getpagesize() int { return 65536 }
func Getppid() int { return 2 }
func Getpid() int { return 3 }
+func Gettimeofday(tv *Timeval) error { return ENOSYS }
func Getuid() int { return 1 }
func Kill(pid int, signum Signal) error { return ENOSYS }
func Sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) {
@@ -310,3 +296,5 @@ func RouteRIB(facility, param int) ([]byte, error) { return nil,
func ParseRoutingMessage(b []byte) ([]RoutingMessage, error) { return nil, ENOSYS }
func ParseRoutingSockaddr(msg RoutingMessage) ([]Sockaddr, error) { return nil, ENOSYS }
func SysctlUint32(name string) (value uint32, err error) { return 0, ENOSYS }
+
+type Iovec struct{} // dummy
diff --git a/src/syscall/syscall_nacl_386.go b/src/syscall/syscall_nacl_386.go
index 0d685a6..39112eb 100644
--- a/src/syscall/syscall_nacl_386.go
+++ b/src/syscall/syscall_nacl_386.go
@@ -14,19 +14,10 @@ type Timeval struct {
Usec int32
}
-func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
-
-func NsecToTimespec(nsec int64) (ts Timespec) {
- ts.Sec = int64(nsec / 1e9)
- ts.Nsec = int32(nsec % 1e9)
- return
+func setTimespec(sec, nsec int64) Timespec {
+ return Timespec{Sec: sec, Nsec: int32(nsec)}
}
-func TimevalToNsec(tv Timeval) int64 { return int64(tv.Sec)*1e9 + int64(tv.Usec)*1e3 }
-
-func NsecToTimeval(nsec int64) (tv Timeval) {
- nsec += 999 // round up to microsecond
- tv.Usec = int32(nsec % 1e9 / 1e3)
- tv.Sec = int64(nsec / 1e9)
- return
+func setTimeval(sec, usec int64) Timeval {
+ return Timeval{Sec: sec, Usec: int32(usec)}
}
diff --git a/src/syscall/syscall_nacl_amd64p32.go b/src/syscall/syscall_nacl_amd64p32.go
index 0d685a6..39112eb 100644
--- a/src/syscall/syscall_nacl_amd64p32.go
+++ b/src/syscall/syscall_nacl_amd64p32.go
@@ -14,19 +14,10 @@ type Timeval struct {
Usec int32
}
-func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
-
-func NsecToTimespec(nsec int64) (ts Timespec) {
- ts.Sec = int64(nsec / 1e9)
- ts.Nsec = int32(nsec % 1e9)
- return
+func setTimespec(sec, nsec int64) Timespec {
+ return Timespec{Sec: sec, Nsec: int32(nsec)}
}
-func TimevalToNsec(tv Timeval) int64 { return int64(tv.Sec)*1e9 + int64(tv.Usec)*1e3 }
-
-func NsecToTimeval(nsec int64) (tv Timeval) {
- nsec += 999 // round up to microsecond
- tv.Usec = int32(nsec % 1e9 / 1e3)
- tv.Sec = int64(nsec / 1e9)
- return
+func setTimeval(sec, usec int64) Timeval {
+ return Timeval{Sec: sec, Usec: int32(usec)}
}
diff --git a/src/syscall/syscall_nacl_arm.go b/src/syscall/syscall_nacl_arm.go
index 5d72503..dec97b5 100644
--- a/src/syscall/syscall_nacl_arm.go
+++ b/src/syscall/syscall_nacl_arm.go
@@ -14,19 +14,10 @@ type Timeval struct {
Usec int32
}
-func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
-
-func NsecToTimespec(nsec int64) (ts Timespec) {
- ts.Sec = int64(nsec / 1e9)
- ts.Nsec = int32(nsec % 1e9)
- return
+func setTimespec(sec, nsec int64) Timespec {
+ return Timespec{Sec: sec, Nsec: int32(nsec)}
}
-func TimevalToNsec(tv Timeval) int64 { return int64(tv.Sec)*1e9 + int64(tv.Usec)*1e3 }
-
-func NsecToTimeval(nsec int64) (tv Timeval) {
- nsec += 999 // round up to microsecond
- tv.Usec = int32(nsec % 1e9 / 1e3)
- tv.Sec = int64(nsec / 1e9)
- return
+func setTimeval(sec, usec int64) Timeval {
+ return Timeval{Sec: sec, Usec: int32(usec)}
}
diff --git a/src/syscall/syscall_netbsd.go b/src/syscall/syscall_netbsd.go
index 7fd6e2b..f2e1694 100644
--- a/src/syscall/syscall_netbsd.go
+++ b/src/syscall/syscall_netbsd.go
@@ -26,7 +26,7 @@ type SockaddrDatalink struct {
raw RawSockaddrDatalink
}
-func Syscall9(trap, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err Errno)
+func Syscall9(num, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err Errno)
func sysctlNodes(mib []_C_int) (nodes []Sysctlnode, err error) {
var olen uintptr
@@ -90,32 +90,16 @@ func nametomib(name string) (mib []_C_int, err error) {
return mib, nil
}
-// ParseDirent parses up to max directory entries in buf,
-// appending the names to names. It returns the number
-// bytes consumed from buf, the number of entries added
-// to names, and the new names slice.
-func ParseDirent(buf []byte, max int, names []string) (consumed int, count int, newnames []string) {
- origlen := len(buf)
- for max != 0 && len(buf) > 0 {
- dirent := (*Dirent)(unsafe.Pointer(&buf[0]))
- if dirent.Reclen == 0 {
- buf = nil
- break
- }
- buf = buf[dirent.Reclen:]
- if dirent.Fileno == 0 { // File absent in directory.
- continue
- }
- bytes := (*[10000]byte)(unsafe.Pointer(&dirent.Name[0]))
- var name = string(bytes[0:dirent.Namlen])
- if name == "." || name == ".." { // Useless names
- continue
- }
- max--
- count++
- names = append(names, name)
- }
- return origlen - len(buf), count, names
+func direntIno(buf []byte) (uint64, bool) {
+ return readInt(buf, unsafe.Offsetof(Dirent{}.Fileno), unsafe.Sizeof(Dirent{}.Fileno))
+}
+
+func direntReclen(buf []byte) (uint64, bool) {
+ return readInt(buf, unsafe.Offsetof(Dirent{}.Reclen), unsafe.Sizeof(Dirent{}.Reclen))
+}
+
+func direntNamlen(buf []byte) (uint64, bool) {
+ return readInt(buf, unsafe.Offsetof(Dirent{}.Namlen), unsafe.Sizeof(Dirent{}.Namlen))
}
//sysnb pipe() (fd1 int, fd2 int, err error)
diff --git a/src/syscall/syscall_netbsd_386.go b/src/syscall/syscall_netbsd_386.go
index 2dbff07..3059b9a 100644
--- a/src/syscall/syscall_netbsd_386.go
+++ b/src/syscall/syscall_netbsd_386.go
@@ -4,23 +4,12 @@
package syscall
-func Getpagesize() int { return 4096 }
-
-func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
-
-func NsecToTimespec(nsec int64) (ts Timespec) {
- ts.Sec = int64(nsec / 1e9)
- ts.Nsec = int32(nsec % 1e9)
- return
+func setTimespec(sec, nsec int64) Timespec {
+ return Timespec{Sec: sec, Nsec: int32(nsec)}
}
-func TimevalToNsec(tv Timeval) int64 { return int64(tv.Sec)*1e9 + int64(tv.Usec)*1e3 }
-
-func NsecToTimeval(nsec int64) (tv Timeval) {
- nsec += 999 // round up to microsecond
- tv.Usec = int32(nsec % 1e9 / 1e3)
- tv.Sec = int64(nsec / 1e9)
- return
+func setTimeval(sec, usec int64) Timeval {
+ return Timeval{Sec: sec, Usec: int32(usec)}
}
func SetKevent(k *Kevent_t, fd, mode, flags int) {
diff --git a/src/syscall/syscall_netbsd_amd64.go b/src/syscall/syscall_netbsd_amd64.go
index 5784db9..b4c5d0d 100644
--- a/src/syscall/syscall_netbsd_amd64.go
+++ b/src/syscall/syscall_netbsd_amd64.go
@@ -4,23 +4,12 @@
package syscall
-func Getpagesize() int { return 4096 }
-
-func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
-
-func NsecToTimespec(nsec int64) (ts Timespec) {
- ts.Sec = int64(nsec / 1e9)
- ts.Nsec = int64(nsec % 1e9)
- return
+func setTimespec(sec, nsec int64) Timespec {
+ return Timespec{Sec: sec, Nsec: nsec}
}
-func TimevalToNsec(tv Timeval) int64 { return int64(tv.Sec)*1e9 + int64(tv.Usec)*1e3 }
-
-func NsecToTimeval(nsec int64) (tv Timeval) {
- nsec += 999 // round up to microsecond
- tv.Usec = int32(nsec % 1e9 / 1e3)
- tv.Sec = int64(nsec / 1e9)
- return
+func setTimeval(sec, usec int64) Timeval {
+ return Timeval{Sec: sec, Usec: int32(usec)}
}
func SetKevent(k *Kevent_t, fd, mode, flags int) {
diff --git a/src/syscall/syscall_netbsd_arm.go b/src/syscall/syscall_netbsd_arm.go
index 659698a..dcafd1f 100644
--- a/src/syscall/syscall_netbsd_arm.go
+++ b/src/syscall/syscall_netbsd_arm.go
@@ -4,23 +4,12 @@
package syscall
-func Getpagesize() int { return 4096 }
-
-func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
-
-func NsecToTimespec(nsec int64) (ts Timespec) {
- ts.Sec = int64(nsec / 1e9)
- ts.Nsec = int32(nsec % 1e9)
- return
+func setTimespec(sec, nsec int64) Timespec {
+ return Timespec{Sec: sec, Nsec: int32(nsec)}
}
-func TimevalToNsec(tv Timeval) int64 { return int64(tv.Sec)*1e9 + int64(tv.Usec)*1e3 }
-
-func NsecToTimeval(nsec int64) (tv Timeval) {
- nsec += 999 // round up to microsecond
- tv.Usec = int32(nsec % 1e9 / 1e3)
- tv.Sec = int64(nsec / 1e9)
- return
+func setTimeval(sec, usec int64) Timeval {
+ return Timeval{Sec: sec, Usec: int32(usec)}
}
func SetKevent(k *Kevent_t, fd, mode, flags int) {
diff --git a/src/syscall/syscall_openbsd.go b/src/syscall/syscall_openbsd.go
index e196e59..bd25fbf 100644
--- a/src/syscall/syscall_openbsd.go
+++ b/src/syscall/syscall_openbsd.go
@@ -26,7 +26,7 @@ type SockaddrDatalink struct {
raw RawSockaddrDatalink
}
-func Syscall9(trap, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err Errno)
+func Syscall9(num, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err Errno)
func nametomib(name string) (mib []_C_int, err error) {
@@ -50,32 +50,16 @@ func nametomib(name string) (mib []_C_int, err error) {
return nil, EINVAL
}
-// ParseDirent parses up to max directory entries in buf,
-// appending the names to names. It returns the number
-// bytes consumed from buf, the number of entries added
-// to names, and the new names slice.
-func ParseDirent(buf []byte, max int, names []string) (consumed int, count int, newnames []string) {
- origlen := len(buf)
- for max != 0 && len(buf) > 0 {
- dirent := (*Dirent)(unsafe.Pointer(&buf[0]))
- if dirent.Reclen == 0 {
- buf = nil
- break
- }
- buf = buf[dirent.Reclen:]
- if dirent.Fileno == 0 { // File absent in directory.
- continue
- }
- bytes := (*[10000]byte)(unsafe.Pointer(&dirent.Name[0]))
- var name = string(bytes[0:dirent.Namlen])
- if name == "." || name == ".." { // Useless names
- continue
- }
- max--
- count++
- names = append(names, name)
- }
- return origlen - len(buf), count, names
+func direntIno(buf []byte) (uint64, bool) {
+ return readInt(buf, unsafe.Offsetof(Dirent{}.Fileno), unsafe.Sizeof(Dirent{}.Fileno))
+}
+
+func direntReclen(buf []byte) (uint64, bool) {
+ return readInt(buf, unsafe.Offsetof(Dirent{}.Reclen), unsafe.Sizeof(Dirent{}.Reclen))
+}
+
+func direntNamlen(buf []byte) (uint64, bool) {
+ return readInt(buf, unsafe.Offsetof(Dirent{}.Namlen), unsafe.Sizeof(Dirent{}.Namlen))
}
//sysnb pipe(p *[2]_C_int) (err error)
diff --git a/src/syscall/syscall_openbsd_386.go b/src/syscall/syscall_openbsd_386.go
index ad5ae14..ca07ae0 100644
--- a/src/syscall/syscall_openbsd_386.go
+++ b/src/syscall/syscall_openbsd_386.go
@@ -4,23 +4,12 @@
package syscall
-func Getpagesize() int { return 4096 }
-
-func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
-
-func NsecToTimespec(nsec int64) (ts Timespec) {
- ts.Sec = int64(nsec / 1e9)
- ts.Nsec = int32(nsec % 1e9)
- return
+func setTimespec(sec, nsec int64) Timespec {
+ return Timespec{Sec: sec, Nsec: int32(nsec)}
}
-func TimevalToNsec(tv Timeval) int64 { return int64(tv.Sec)*1e9 + int64(tv.Usec)*1e3 }
-
-func NsecToTimeval(nsec int64) (tv Timeval) {
- nsec += 999 // round up to microsecond
- tv.Usec = int32(nsec % 1e9 / 1e3)
- tv.Sec = int64(nsec / 1e9)
- return
+func setTimeval(sec, usec int64) Timeval {
+ return Timeval{Sec: sec, Usec: int32(usec)}
}
func SetKevent(k *Kevent_t, fd, mode, flags int) {
diff --git a/src/syscall/syscall_openbsd_amd64.go b/src/syscall/syscall_openbsd_amd64.go
index 6181344..47fc7e7 100644
--- a/src/syscall/syscall_openbsd_amd64.go
+++ b/src/syscall/syscall_openbsd_amd64.go
@@ -4,23 +4,12 @@
package syscall
-func Getpagesize() int { return 4096 }
-
-func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
-
-func NsecToTimespec(nsec int64) (ts Timespec) {
- ts.Sec = nsec / 1e9
- ts.Nsec = nsec % 1e9
- return
+func setTimespec(sec, nsec int64) Timespec {
+ return Timespec{Sec: sec, Nsec: nsec}
}
-func TimevalToNsec(tv Timeval) int64 { return int64(tv.Sec)*1e9 + int64(tv.Usec)*1e3 }
-
-func NsecToTimeval(nsec int64) (tv Timeval) {
- nsec += 999 // round up to microsecond
- tv.Usec = nsec % 1e9 / 1e3
- tv.Sec = nsec / 1e9
- return
+func setTimeval(sec, usec int64) Timeval {
+ return Timeval{Sec: sec, Usec: usec}
}
func SetKevent(k *Kevent_t, fd, mode, flags int) {
diff --git a/src/syscall/syscall_openbsd_arm.go b/src/syscall/syscall_openbsd_arm.go
index ad5ae14..ca07ae0 100644
--- a/src/syscall/syscall_openbsd_arm.go
+++ b/src/syscall/syscall_openbsd_arm.go
@@ -4,23 +4,12 @@
package syscall
-func Getpagesize() int { return 4096 }
-
-func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
-
-func NsecToTimespec(nsec int64) (ts Timespec) {
- ts.Sec = int64(nsec / 1e9)
- ts.Nsec = int32(nsec % 1e9)
- return
+func setTimespec(sec, nsec int64) Timespec {
+ return Timespec{Sec: sec, Nsec: int32(nsec)}
}
-func TimevalToNsec(tv Timeval) int64 { return int64(tv.Sec)*1e9 + int64(tv.Usec)*1e3 }
-
-func NsecToTimeval(nsec int64) (tv Timeval) {
- nsec += 999 // round up to microsecond
- tv.Usec = int32(nsec % 1e9 / 1e3)
- tv.Sec = int64(nsec / 1e9)
- return
+func setTimeval(sec, usec int64) Timeval {
+ return Timeval{Sec: sec, Usec: int32(usec)}
}
func SetKevent(k *Kevent_t, fd, mode, flags int) {
diff --git a/src/syscall/syscall_plan9.go b/src/syscall/syscall_plan9.go
index b511867..0691889 100644
--- a/src/syscall/syscall_plan9.go
+++ b/src/syscall/syscall_plan9.go
@@ -305,8 +305,6 @@ func Gettimeofday(tv *Timeval) error {
return nil
}
-func Getpagesize() int { return 0x1000 }
-
func Getegid() (egid int) { return -1 }
func Geteuid() (euid int) { return -1 }
func Getgid() (gid int) { return -1 }
diff --git a/src/syscall/syscall_solaris.go b/src/syscall/syscall_solaris.go
index b307a80..636de92 100644
--- a/src/syscall/syscall_solaris.go
+++ b/src/syscall/syscall_solaris.go
@@ -38,32 +38,20 @@ func clen(n []byte) int {
return len(n)
}
-// ParseDirent parses up to max directory entries in buf,
-// appending the names to names. It returns the number
-// bytes consumed from buf, the number of entries added
-// to names, and the new names slice.
-func ParseDirent(buf []byte, max int, names []string) (consumed int, count int, newnames []string) {
- origlen := len(buf)
- for max != 0 && len(buf) > 0 {
- dirent := (*Dirent)(unsafe.Pointer(&buf[0]))
- if dirent.Reclen == 0 {
- buf = nil
- break
- }
- buf = buf[dirent.Reclen:]
- if dirent.Ino == 0 { // File absent in directory.
- continue
- }
- bytes := (*[10000]byte)(unsafe.Pointer(&dirent.Name[0]))
- var name = string(bytes[0:clen(bytes[:])])
- if name == "." || name == ".." { // Useless names
- continue
- }
- max--
- count++
- names = append(names, name)
+func direntIno(buf []byte) (uint64, bool) {
+ return readInt(buf, unsafe.Offsetof(Dirent{}.Ino), unsafe.Sizeof(Dirent{}.Ino))
+}
+
+func direntReclen(buf []byte) (uint64, bool) {
+ return readInt(buf, unsafe.Offsetof(Dirent{}.Reclen), unsafe.Sizeof(Dirent{}.Reclen))
+}
+
+func direntNamlen(buf []byte) (uint64, bool) {
+ reclen, ok := direntReclen(buf)
+ if !ok {
+ return 0, false
}
- return origlen - len(buf), count, names
+ return reclen - uint64(unsafe.Offsetof(Dirent{}.Name)), true
}
func pipe() (r uintptr, w uintptr, err uintptr)
@@ -291,7 +279,7 @@ func UtimesNano(path string, ts []Timespec) (err error) {
tv[i].Sec = ts[i].Sec
tv[i].Usec = ts[i].Nsec / 1000
}
- return Utimes(path, (*[2]Timeval)(unsafe.Pointer(&tv[0])))
+ return utimes(path, (*[2]Timeval)(unsafe.Pointer(&tv[0])))
}
//sys fcntl(fd int, cmd int, arg int) (val int, err error)
@@ -382,6 +370,7 @@ func Recvmsg(fd int, p, oob []byte, flags int) (n, oobn int, recvflags int, from
iov.SetLen(1)
}
msg.Accrights = (*int8)(unsafe.Pointer(&oob[0]))
+ msg.Accrightslen = int32(len(oob))
}
msg.Iov = &iov
msg.Iovlen = 1
@@ -401,7 +390,7 @@ func Sendmsg(fd int, p, oob []byte, to Sockaddr, flags int) (err error) {
return
}
-//sys sendmsg(s int, msg *Msghdr, flags int) (n int, err error) = libsocket.sendmsg
+//sys sendmsg(s int, msg *Msghdr, flags int) (n int, err error) = libsocket.__xnet_sendmsg
func SendmsgN(fd int, p, oob []byte, to Sockaddr, flags int) (n int, err error) {
var ptr unsafe.Pointer
@@ -428,6 +417,7 @@ func SendmsgN(fd int, p, oob []byte, to Sockaddr, flags int) (n int, err error)
iov.SetLen(1)
}
msg.Accrights = (*int8)(unsafe.Pointer(&oob[0]))
+ msg.Accrightslen = int32(len(oob))
}
msg.Iov = &iov
msg.Iovlen = 1
@@ -470,7 +460,7 @@ func SendmsgN(fd int, p, oob []byte, to Sockaddr, flags int) (n int, err error)
//sys Kill(pid int, signum Signal) (err error)
//sys Lchown(path string, uid int, gid int) (err error)
//sys Link(path string, link string) (err error)
-//sys Listen(s int, backlog int) (err error) = libsocket.listen
+//sys Listen(s int, backlog int) (err error) = libsocket.__xnet_listen
//sys Lstat(path string, stat *Stat_t) (err error)
//sys Mkdir(path string, mode uint32) (err error)
//sys Mknod(path string, mode uint32, dev int) (err error)
@@ -504,21 +494,36 @@ func SendmsgN(fd int, p, oob []byte, to Sockaddr, flags int) (n int, err error)
//sys Ftruncate(fd int, length int64) (err error)
//sys Umask(newmask int) (oldmask int)
//sys Unlink(path string) (err error)
-//sys Utimes(path string, times *[2]Timeval) (err error)
-//sys bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) = libsocket.bind
-//sys connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) = libsocket.connect
+//sys utimes(path string, times *[2]Timeval) (err error)
+//sys bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) = libsocket.__xnet_bind
+//sys connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) = libsocket.__xnet_connect
//sys mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (ret uintptr, err error)
//sys munmap(addr uintptr, length uintptr) (err error)
-//sys sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error) = libsocket.sendto
-//sys socket(domain int, typ int, proto int) (fd int, err error) = libsocket.socket
-//sysnb socketpair(domain int, typ int, proto int, fd *[2]int32) (err error) = libsocket.socketpair
+//sys sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error) = libsocket.__xnet_sendto
+//sys socket(domain int, typ int, proto int) (fd int, err error) = libsocket.__xnet_socket
+//sysnb socketpair(domain int, typ int, proto int, fd *[2]int32) (err error) = libsocket.__xnet_socketpair
//sys write(fd int, p []byte) (n int, err error)
-//sys getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) = libsocket.getsockopt
+//sys getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) = libsocket.__xnet_getsockopt
//sysnb getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) = libsocket.getpeername
//sys getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) = libsocket.getsockname
//sys setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) = libsocket.setsockopt
//sys recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Socklen) (n int, err error) = libsocket.recvfrom
-//sys recvmsg(s int, msg *Msghdr, flags int) (n int, err error) = libsocket.recvmsg
+//sys recvmsg(s int, msg *Msghdr, flags int) (n int, err error) = libsocket.__xnet_recvmsg
+//sys getexecname() (path unsafe.Pointer, err error) = libc.getexecname
+
+func Getexecname() (path string, err error) {
+ ptr, err := getexecname()
+ if err != nil {
+ return "", err
+ }
+ bytes := (*[1 << 29]byte)(ptr)[:]
+ for i, b := range bytes {
+ if b == 0 {
+ return string(bytes[:i]), nil
+ }
+ }
+ panic("unreachable")
+}
func readlen(fd int, buf *byte, nbuf int) (n int, err error) {
r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_read)), 3, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf), 0, 0, 0)
@@ -537,3 +542,10 @@ func writelen(fd int, buf *byte, nbuf int) (n int, err error) {
}
return
}
+
+func Utimes(path string, tv []Timeval) error {
+ if len(tv) != 2 {
+ return EINVAL
+ }
+ return utimes(path, (*[2]Timeval)(unsafe.Pointer(&tv[0])))
+}
diff --git a/src/syscall/syscall_solaris_amd64.go b/src/syscall/syscall_solaris_amd64.go
index 67b8af1..87ad4bf 100644
--- a/src/syscall/syscall_solaris_amd64.go
+++ b/src/syscall/syscall_solaris_amd64.go
@@ -4,23 +4,12 @@
package syscall
-func Getpagesize() int { return 4096 }
-
-func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
-
-func NsecToTimespec(nsec int64) (ts Timespec) {
- ts.Sec = nsec / 1e9
- ts.Nsec = nsec % 1e9
- return
+func setTimespec(sec, nsec int64) Timespec {
+ return Timespec{Sec: sec, Nsec: nsec}
}
-func TimevalToNsec(tv Timeval) int64 { return int64(tv.Sec)*1e9 + int64(tv.Usec)*1e3 }
-
-func NsecToTimeval(nsec int64) (tv Timeval) {
- nsec += 999 // round up to microsecond
- tv.Usec = nsec % 1e9 / 1e3
- tv.Sec = int64(nsec / 1e9)
- return
+func setTimeval(sec, usec int64) Timeval {
+ return Timeval{Sec: sec, Usec: usec}
}
func (iov *Iovec) SetLen(length int) {
diff --git a/src/syscall/syscall_test.go b/src/syscall/syscall_test.go
index 0a0b8b7..c3fffda 100644
--- a/src/syscall/syscall_test.go
+++ b/src/syscall/syscall_test.go
@@ -8,6 +8,7 @@ import (
"fmt"
"internal/testenv"
"os"
+ "runtime"
"syscall"
"testing"
)
@@ -59,3 +60,16 @@ func TestExecErrPermutedFds(t *testing.T) {
t.Fatalf("StartProcess of invalid program returned err = nil")
}
}
+
+func TestGettimeofday(t *testing.T) {
+ if runtime.GOOS == "nacl" {
+ t.Skip("not implemented on nacl")
+ }
+ tv := &syscall.Timeval{}
+ if err := syscall.Gettimeofday(tv); err != nil {
+ t.Fatal(err)
+ }
+ if tv.Sec == 0 && tv.Usec == 0 {
+ t.Fatal("Sec and Usec both zero")
+ }
+}
diff --git a/src/syscall/syscall_unix.go b/src/syscall/syscall_unix.go
index 4dae9d9..442f558 100644
--- a/src/syscall/syscall_unix.go
+++ b/src/syscall/syscall_unix.go
@@ -23,6 +23,7 @@ const (
darwin64Bit = runtime.GOOS == "darwin" && sizeofPtr == 8
dragonfly64Bit = runtime.GOOS == "dragonfly" && sizeofPtr == 8
netbsd32Bit = runtime.GOOS == "netbsd" && sizeofPtr == 4
+ solaris64Bit = runtime.GOOS == "solaris" && sizeofPtr == 8
)
func Syscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno)
diff --git a/src/syscall/syscall_unix_test.go b/src/syscall/syscall_unix_test.go
index 80544f3..2f25d18 100644
--- a/src/syscall/syscall_unix_test.go
+++ b/src/syscall/syscall_unix_test.go
@@ -125,15 +125,6 @@ func TestFcntlFlock(t *testing.T) {
// "-test.run=^TestPassFD$" and an environment variable used to signal
// that the test should become the child process instead.
func TestPassFD(t *testing.T) {
- switch runtime.GOOS {
- case "dragonfly":
- // TODO(jsing): Figure out why sendmsg is returning EINVAL.
- t.Skip("skipping test on dragonfly")
- case "solaris":
- // TODO(aram): Figure out why ReadMsgUnix is returning empty message.
- t.Skip("skipping test on solaris, see issue 7402")
- }
-
testenv.MustHaveExec(t)
if os.Getenv("GO_WANT_HELPER_PROCESS") == "1" {
diff --git a/src/syscall/syscall_windows.go b/src/syscall/syscall_windows.go
index 703bb53..f4f8f3a 100644
--- a/src/syscall/syscall_windows.go
+++ b/src/syscall/syscall_windows.go
@@ -14,8 +14,6 @@ import (
"unsafe"
)
-//go:generate go run mksyscall_windows.go -systemdll -output zsyscall_windows.go syscall_windows.go security_windows.go
-
type Handle uintptr
const InvalidHandle = ^Handle(0)
@@ -76,8 +74,6 @@ func UTF16PtrFromString(s string) (*uint16, error) {
return &a[0], nil
}
-func Getpagesize() int { return 4096 }
-
// Errno is the Windows error number.
type Errno uintptr
@@ -1028,11 +1024,31 @@ func Readlink(path string, buf []byte) (n int, err error) {
case IO_REPARSE_TAG_SYMLINK:
data := (*symbolicLinkReparseBuffer)(unsafe.Pointer(&rdb.reparseBuffer))
p := (*[0xffff]uint16)(unsafe.Pointer(&data.PathBuffer[0]))
- s = UTF16ToString(p[data.PrintNameOffset/2 : (data.PrintNameLength-data.PrintNameOffset)/2])
+ s = UTF16ToString(p[data.SubstituteNameOffset/2 : (data.SubstituteNameOffset+data.SubstituteNameLength)/2])
+ if data.Flags&_SYMLINK_FLAG_RELATIVE == 0 {
+ if len(s) >= 4 && s[:4] == `\??\` {
+ s = s[4:]
+ switch {
+ case len(s) >= 2 && s[1] == ':': // \??\C:\foo\bar
+ // do nothing
+ case len(s) >= 4 && s[:4] == `UNC\`: // \??\UNC\foo\bar
+ s = `\\` + s[4:]
+ default:
+ // unexpected; do nothing
+ }
+ } else {
+ // unexpected; do nothing
+ }
+ }
case _IO_REPARSE_TAG_MOUNT_POINT:
data := (*mountPointReparseBuffer)(unsafe.Pointer(&rdb.reparseBuffer))
p := (*[0xffff]uint16)(unsafe.Pointer(&data.PathBuffer[0]))
- s = UTF16ToString(p[data.PrintNameOffset/2 : (data.PrintNameLength-data.PrintNameOffset)/2])
+ s = UTF16ToString(p[data.SubstituteNameOffset/2 : (data.SubstituteNameOffset+data.SubstituteNameLength)/2])
+ if len(s) >= 4 && s[:4] == `\??\` { // \??\C:\foo\bar
+ s = s[4:]
+ } else {
+ // unexpected; do nothing
+ }
default:
// the path is not a symlink or junction but another type of reparse
// point
diff --git a/src/syscall/timestruct.go b/src/syscall/timestruct.go
new file mode 100644
index 0000000..49c3383
--- /dev/null
+++ b/src/syscall/timestruct.go
@@ -0,0 +1,40 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
+
+package syscall
+
+// TimespecToNsec converts a Timespec value into a number of
+// nanoseconds since the Unix epoch.
+func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
+
+// NsecToTimespec takes a number of nanoseconds since the Unix epoch
+// and returns the corresponding Timespec value.
+func NsecToTimespec(nsec int64) Timespec {
+ sec := nsec / 1e9
+ nsec = nsec % 1e9
+ if nsec < 0 {
+ nsec += 1e9
+ sec--
+ }
+ return setTimespec(sec, nsec)
+}
+
+// TimevalToNsec converts a Timeval value into a number of nanoseconds
+// since the Unix epoch.
+func TimevalToNsec(tv Timeval) int64 { return int64(tv.Sec)*1e9 + int64(tv.Usec)*1e3 }
+
+// NsecToTimeval takes a number of nanoseconds since the Unix epoch
+// and returns the corresponding Timeval value.
+func NsecToTimeval(nsec int64) Timeval {
+ nsec += 999 // round up to microsecond
+ usec := nsec % 1e9 / 1e3
+ sec := nsec / 1e9
+ if usec < 0 {
+ usec += 1e6
+ sec--
+ }
+ return setTimeval(sec, usec)
+}
diff --git a/src/syscall/types_linux.go b/src/syscall/types_linux.go
index 2a16650..125f69d 100644
--- a/src/syscall/types_linux.go
+++ b/src/syscall/types_linux.go
@@ -112,7 +112,7 @@ typedef struct {} ptracePer;
// The real epoll_event is a union, and godefs doesn't handle it well.
struct my_epoll_event {
uint32_t events;
-#ifdef __ARM_EABI__
+#if defined(__ARM_EABI__) || (defined(__mips__) && _MIPS_SIM == _ABIO32)
// padding is not specified in linux/eventpoll.h but added to conform to the
// alignment requirements of EABI
int32_t padFd;
diff --git a/src/syscall/zerrors_linux_mips.go b/src/syscall/zerrors_linux_mips.go
new file mode 100644
index 0000000..580d66f
--- /dev/null
+++ b/src/syscall/zerrors_linux_mips.go
@@ -0,0 +1,1834 @@
+// mkerrors.sh
+// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs -- _const.go
+
+package syscall
+
+const (
+ AF_ALG = 0x26
+ AF_APPLETALK = 0x5
+ AF_ASH = 0x12
+ AF_ATMPVC = 0x8
+ AF_ATMSVC = 0x14
+ AF_AX25 = 0x3
+ AF_BLUETOOTH = 0x1f
+ AF_BRIDGE = 0x7
+ AF_CAIF = 0x25
+ AF_CAN = 0x1d
+ AF_DECnet = 0xc
+ AF_ECONET = 0x13
+ AF_FILE = 0x1
+ AF_IEEE802154 = 0x24
+ AF_INET = 0x2
+ AF_INET6 = 0xa
+ AF_IPX = 0x4
+ AF_IRDA = 0x17
+ AF_ISDN = 0x22
+ AF_IUCV = 0x20
+ AF_KEY = 0xf
+ AF_LLC = 0x1a
+ AF_LOCAL = 0x1
+ AF_MAX = 0x29
+ AF_NETBEUI = 0xd
+ AF_NETLINK = 0x10
+ AF_NETROM = 0x6
+ AF_NFC = 0x27
+ AF_PACKET = 0x11
+ AF_PHONET = 0x23
+ AF_PPPOX = 0x18
+ AF_RDS = 0x15
+ AF_ROSE = 0xb
+ AF_ROUTE = 0x10
+ AF_RXRPC = 0x21
+ AF_SECURITY = 0xe
+ AF_SNA = 0x16
+ AF_TIPC = 0x1e
+ AF_UNIX = 0x1
+ AF_UNSPEC = 0x0
+ AF_VSOCK = 0x28
+ AF_WANPIPE = 0x19
+ AF_X25 = 0x9
+ ARPHRD_6LOWPAN = 0x339
+ ARPHRD_ADAPT = 0x108
+ ARPHRD_APPLETLK = 0x8
+ ARPHRD_ARCNET = 0x7
+ ARPHRD_ASH = 0x30d
+ ARPHRD_ATM = 0x13
+ ARPHRD_AX25 = 0x3
+ ARPHRD_BIF = 0x307
+ ARPHRD_CAIF = 0x336
+ ARPHRD_CAN = 0x118
+ ARPHRD_CHAOS = 0x5
+ ARPHRD_CISCO = 0x201
+ ARPHRD_CSLIP = 0x101
+ ARPHRD_CSLIP6 = 0x103
+ ARPHRD_DDCMP = 0x205
+ ARPHRD_DLCI = 0xf
+ ARPHRD_ECONET = 0x30e
+ ARPHRD_EETHER = 0x2
+ ARPHRD_ETHER = 0x1
+ ARPHRD_EUI64 = 0x1b
+ ARPHRD_FCAL = 0x311
+ ARPHRD_FCFABRIC = 0x313
+ ARPHRD_FCPL = 0x312
+ ARPHRD_FCPP = 0x310
+ ARPHRD_FDDI = 0x306
+ ARPHRD_FRAD = 0x302
+ ARPHRD_HDLC = 0x201
+ ARPHRD_HIPPI = 0x30c
+ ARPHRD_HWX25 = 0x110
+ ARPHRD_IEEE1394 = 0x18
+ ARPHRD_IEEE802 = 0x6
+ ARPHRD_IEEE80211 = 0x321
+ ARPHRD_IEEE80211_PRISM = 0x322
+ ARPHRD_IEEE80211_RADIOTAP = 0x323
+ ARPHRD_IEEE802154 = 0x324
+ ARPHRD_IEEE802154_MONITOR = 0x325
+ ARPHRD_IEEE802_TR = 0x320
+ ARPHRD_INFINIBAND = 0x20
+ ARPHRD_IP6GRE = 0x337
+ ARPHRD_IPDDP = 0x309
+ ARPHRD_IPGRE = 0x30a
+ ARPHRD_IRDA = 0x30f
+ ARPHRD_LAPB = 0x204
+ ARPHRD_LOCALTLK = 0x305
+ ARPHRD_LOOPBACK = 0x304
+ ARPHRD_METRICOM = 0x17
+ ARPHRD_NETLINK = 0x338
+ ARPHRD_NETROM = 0x0
+ ARPHRD_NONE = 0xfffe
+ ARPHRD_PHONET = 0x334
+ ARPHRD_PHONET_PIPE = 0x335
+ ARPHRD_PIMREG = 0x30b
+ ARPHRD_PPP = 0x200
+ ARPHRD_PRONET = 0x4
+ ARPHRD_RAWHDLC = 0x206
+ ARPHRD_ROSE = 0x10e
+ ARPHRD_RSRVD = 0x104
+ ARPHRD_SIT = 0x308
+ ARPHRD_SKIP = 0x303
+ ARPHRD_SLIP = 0x100
+ ARPHRD_SLIP6 = 0x102
+ ARPHRD_TUNNEL = 0x300
+ ARPHRD_TUNNEL6 = 0x301
+ ARPHRD_VOID = 0xffff
+ ARPHRD_X25 = 0x10f
+ B0 = 0x0
+ B1000000 = 0x1008
+ B110 = 0x3
+ B115200 = 0x1002
+ B1152000 = 0x1009
+ B1200 = 0x9
+ B134 = 0x4
+ B150 = 0x5
+ B1500000 = 0x100a
+ B1800 = 0xa
+ B19200 = 0xe
+ B200 = 0x6
+ B2000000 = 0x100b
+ B230400 = 0x1003
+ B2400 = 0xb
+ B2500000 = 0x100c
+ B300 = 0x7
+ B3000000 = 0x100d
+ B3500000 = 0x100e
+ B38400 = 0xf
+ B4000000 = 0x100f
+ B460800 = 0x1004
+ B4800 = 0xc
+ B50 = 0x1
+ B500000 = 0x1005
+ B57600 = 0x1001
+ B576000 = 0x1006
+ B600 = 0x8
+ B75 = 0x2
+ B921600 = 0x1007
+ B9600 = 0xd
+ BPF_A = 0x10
+ BPF_ABS = 0x20
+ BPF_ADD = 0x0
+ BPF_ALU = 0x4
+ BPF_AND = 0x50
+ BPF_B = 0x10
+ BPF_DIV = 0x30
+ BPF_H = 0x8
+ BPF_IMM = 0x0
+ BPF_IND = 0x40
+ BPF_JA = 0x0
+ BPF_JEQ = 0x10
+ BPF_JGE = 0x30
+ BPF_JGT = 0x20
+ BPF_JMP = 0x5
+ BPF_JSET = 0x40
+ BPF_K = 0x0
+ BPF_LD = 0x0
+ BPF_LDX = 0x1
+ BPF_LEN = 0x80
+ BPF_LSH = 0x60
+ BPF_MAJOR_VERSION = 0x1
+ BPF_MAXINSNS = 0x1000
+ BPF_MEM = 0x60
+ BPF_MEMWORDS = 0x10
+ BPF_MINOR_VERSION = 0x1
+ BPF_MISC = 0x7
+ BPF_MOD = 0x90
+ BPF_MSH = 0xa0
+ BPF_MUL = 0x20
+ BPF_NEG = 0x80
+ BPF_OR = 0x40
+ BPF_RET = 0x6
+ BPF_RSH = 0x70
+ BPF_ST = 0x2
+ BPF_STX = 0x3
+ BPF_SUB = 0x10
+ BPF_TAX = 0x0
+ BPF_TXA = 0x80
+ BPF_W = 0x0
+ BPF_X = 0x8
+ BPF_XOR = 0xa0
+ BRKINT = 0x2
+ CFLUSH = 0xf
+ CLOCAL = 0x800
+ CLONE_CHILD_CLEARTID = 0x200000
+ CLONE_CHILD_SETTID = 0x1000000
+ CLONE_DETACHED = 0x400000
+ CLONE_FILES = 0x400
+ CLONE_FS = 0x200
+ CLONE_IO = 0x80000000
+ CLONE_NEWIPC = 0x8000000
+ CLONE_NEWNET = 0x40000000
+ CLONE_NEWNS = 0x20000
+ CLONE_NEWPID = 0x20000000
+ CLONE_NEWUSER = 0x10000000
+ CLONE_NEWUTS = 0x4000000
+ CLONE_PARENT = 0x8000
+ CLONE_PARENT_SETTID = 0x100000
+ CLONE_PTRACE = 0x2000
+ CLONE_SETTLS = 0x80000
+ CLONE_SIGHAND = 0x800
+ CLONE_SYSVSEM = 0x40000
+ CLONE_THREAD = 0x10000
+ CLONE_UNTRACED = 0x800000
+ CLONE_VFORK = 0x4000
+ CLONE_VM = 0x100
+ CREAD = 0x80
+ CS5 = 0x0
+ CS6 = 0x10
+ CS7 = 0x20
+ CS8 = 0x30
+ CSIGNAL = 0xff
+ CSIZE = 0x30
+ CSTART = 0x11
+ CSTATUS = 0x0
+ CSTOP = 0x13
+ CSTOPB = 0x40
+ CSUSP = 0x1a
+ DT_BLK = 0x6
+ DT_CHR = 0x2
+ DT_DIR = 0x4
+ DT_FIFO = 0x1
+ DT_LNK = 0xa
+ DT_REG = 0x8
+ DT_SOCK = 0xc
+ DT_UNKNOWN = 0x0
+ DT_WHT = 0xe
+ ECHO = 0x8
+ ECHOCTL = 0x200
+ ECHOE = 0x10
+ ECHOK = 0x20
+ ECHOKE = 0x800
+ ECHONL = 0x40
+ ECHOPRT = 0x400
+ ENCODING_DEFAULT = 0x0
+ ENCODING_FM_MARK = 0x3
+ ENCODING_FM_SPACE = 0x4
+ ENCODING_MANCHESTER = 0x5
+ ENCODING_NRZ = 0x1
+ ENCODING_NRZI = 0x2
+ EPOLLERR = 0x8
+ EPOLLET = 0x80000000
+ EPOLLHUP = 0x10
+ EPOLLIN = 0x1
+ EPOLLMSG = 0x400
+ EPOLLONESHOT = 0x40000000
+ EPOLLOUT = 0x4
+ EPOLLPRI = 0x2
+ EPOLLRDBAND = 0x80
+ EPOLLRDHUP = 0x2000
+ EPOLLRDNORM = 0x40
+ EPOLLWAKEUP = 0x20000000
+ EPOLLWRBAND = 0x200
+ EPOLLWRNORM = 0x100
+ EPOLL_CLOEXEC = 0x80000
+ EPOLL_CTL_ADD = 0x1
+ EPOLL_CTL_DEL = 0x2
+ EPOLL_CTL_MOD = 0x3
+ ETH_P_1588 = 0x88f7
+ ETH_P_8021AD = 0x88a8
+ ETH_P_8021AH = 0x88e7
+ ETH_P_8021Q = 0x8100
+ ETH_P_80221 = 0x8917
+ ETH_P_802_2 = 0x4
+ ETH_P_802_3 = 0x1
+ ETH_P_802_3_MIN = 0x600
+ ETH_P_802_EX1 = 0x88b5
+ ETH_P_AARP = 0x80f3
+ ETH_P_AF_IUCV = 0xfbfb
+ ETH_P_ALL = 0x3
+ ETH_P_AOE = 0x88a2
+ ETH_P_ARCNET = 0x1a
+ ETH_P_ARP = 0x806
+ ETH_P_ATALK = 0x809b
+ ETH_P_ATMFATE = 0x8884
+ ETH_P_ATMMPOA = 0x884c
+ ETH_P_AX25 = 0x2
+ ETH_P_BATMAN = 0x4305
+ ETH_P_BPQ = 0x8ff
+ ETH_P_CAIF = 0xf7
+ ETH_P_CAN = 0xc
+ ETH_P_CANFD = 0xd
+ ETH_P_CONTROL = 0x16
+ ETH_P_CUST = 0x6006
+ ETH_P_DDCMP = 0x6
+ ETH_P_DEC = 0x6000
+ ETH_P_DIAG = 0x6005
+ ETH_P_DNA_DL = 0x6001
+ ETH_P_DNA_RC = 0x6002
+ ETH_P_DNA_RT = 0x6003
+ ETH_P_DSA = 0x1b
+ ETH_P_ECONET = 0x18
+ ETH_P_EDSA = 0xdada
+ ETH_P_FCOE = 0x8906
+ ETH_P_FIP = 0x8914
+ ETH_P_HDLC = 0x19
+ ETH_P_IEEE802154 = 0xf6
+ ETH_P_IEEEPUP = 0xa00
+ ETH_P_IEEEPUPAT = 0xa01
+ ETH_P_IP = 0x800
+ ETH_P_IPV6 = 0x86dd
+ ETH_P_IPX = 0x8137
+ ETH_P_IRDA = 0x17
+ ETH_P_LAT = 0x6004
+ ETH_P_LINK_CTL = 0x886c
+ ETH_P_LOCALTALK = 0x9
+ ETH_P_LOOP = 0x60
+ ETH_P_LOOPBACK = 0x9000
+ ETH_P_MOBITEX = 0x15
+ ETH_P_MPLS_MC = 0x8848
+ ETH_P_MPLS_UC = 0x8847
+ ETH_P_MVRP = 0x88f5
+ ETH_P_PAE = 0x888e
+ ETH_P_PAUSE = 0x8808
+ ETH_P_PHONET = 0xf5
+ ETH_P_PPPTALK = 0x10
+ ETH_P_PPP_DISC = 0x8863
+ ETH_P_PPP_MP = 0x8
+ ETH_P_PPP_SES = 0x8864
+ ETH_P_PRP = 0x88fb
+ ETH_P_PUP = 0x200
+ ETH_P_PUPAT = 0x201
+ ETH_P_QINQ1 = 0x9100
+ ETH_P_QINQ2 = 0x9200
+ ETH_P_QINQ3 = 0x9300
+ ETH_P_RARP = 0x8035
+ ETH_P_SCA = 0x6007
+ ETH_P_SLOW = 0x8809
+ ETH_P_SNAP = 0x5
+ ETH_P_TDLS = 0x890d
+ ETH_P_TEB = 0x6558
+ ETH_P_TIPC = 0x88ca
+ ETH_P_TRAILER = 0x1c
+ ETH_P_TR_802_2 = 0x11
+ ETH_P_WAN_PPP = 0x7
+ ETH_P_WCCP = 0x883e
+ ETH_P_X25 = 0x805
+ EXTA = 0xe
+ EXTB = 0xf
+ EXTPROC = 0x10000
+ FD_CLOEXEC = 0x1
+ FD_SETSIZE = 0x400
+ FLUSHO = 0x2000
+ F_DUPFD = 0x0
+ F_DUPFD_CLOEXEC = 0x406
+ F_EXLCK = 0x4
+ F_GETFD = 0x1
+ F_GETFL = 0x3
+ F_GETLEASE = 0x401
+ F_GETLK = 0x21
+ F_GETLK64 = 0x21
+ F_GETOWN = 0x17
+ F_GETOWN_EX = 0x10
+ F_GETPIPE_SZ = 0x408
+ F_GETSIG = 0xb
+ F_LOCK = 0x1
+ F_NOTIFY = 0x402
+ F_OK = 0x0
+ F_RDLCK = 0x0
+ F_SETFD = 0x2
+ F_SETFL = 0x4
+ F_SETLEASE = 0x400
+ F_SETLK = 0x22
+ F_SETLK64 = 0x22
+ F_SETLKW = 0x23
+ F_SETLKW64 = 0x23
+ F_SETOWN = 0x18
+ F_SETOWN_EX = 0xf
+ F_SETPIPE_SZ = 0x407
+ F_SETSIG = 0xa
+ F_SHLCK = 0x8
+ F_TEST = 0x3
+ F_TLOCK = 0x2
+ F_ULOCK = 0x0
+ F_UNLCK = 0x2
+ F_WRLCK = 0x1
+ HUPCL = 0x400
+ ICANON = 0x2
+ ICMPV6_FILTER = 0x1
+ ICRNL = 0x100
+ IEXTEN = 0x100
+ IFA_F_DADFAILED = 0x8
+ IFA_F_DEPRECATED = 0x20
+ IFA_F_HOMEADDRESS = 0x10
+ IFA_F_MANAGETEMPADDR = 0x100
+ IFA_F_NODAD = 0x2
+ IFA_F_NOPREFIXROUTE = 0x200
+ IFA_F_OPTIMISTIC = 0x4
+ IFA_F_PERMANENT = 0x80
+ IFA_F_SECONDARY = 0x1
+ IFA_F_TEMPORARY = 0x1
+ IFA_F_TENTATIVE = 0x40
+ IFA_MAX = 0x8
+ IFF_ALLMULTI = 0x200
+ IFF_ATTACH_QUEUE = 0x200
+ IFF_AUTOMEDIA = 0x4000
+ IFF_BROADCAST = 0x2
+ IFF_DEBUG = 0x4
+ IFF_DETACH_QUEUE = 0x400
+ IFF_DORMANT = 0x20000
+ IFF_DYNAMIC = 0x8000
+ IFF_ECHO = 0x40000
+ IFF_LOOPBACK = 0x8
+ IFF_LOWER_UP = 0x10000
+ IFF_MASTER = 0x400
+ IFF_MULTICAST = 0x1000
+ IFF_MULTI_QUEUE = 0x100
+ IFF_NOARP = 0x80
+ IFF_NOFILTER = 0x1000
+ IFF_NOTRAILERS = 0x20
+ IFF_NO_PI = 0x1000
+ IFF_ONE_QUEUE = 0x2000
+ IFF_PERSIST = 0x800
+ IFF_POINTOPOINT = 0x10
+ IFF_PORTSEL = 0x2000
+ IFF_PROMISC = 0x100
+ IFF_RUNNING = 0x40
+ IFF_SLAVE = 0x800
+ IFF_TAP = 0x2
+ IFF_TUN = 0x1
+ IFF_TUN_EXCL = 0x8000
+ IFF_UP = 0x1
+ IFF_VNET_HDR = 0x4000
+ IFF_VOLATILE = 0x70c5a
+ IFNAMSIZ = 0x10
+ IGNBRK = 0x1
+ IGNCR = 0x80
+ IGNPAR = 0x4
+ IMAXBEL = 0x2000
+ INLCR = 0x40
+ INPCK = 0x10
+ IN_ACCESS = 0x1
+ IN_ALL_EVENTS = 0xfff
+ IN_ATTRIB = 0x4
+ IN_CLASSA_HOST = 0xffffff
+ IN_CLASSA_MAX = 0x80
+ IN_CLASSA_NET = 0xff000000
+ IN_CLASSA_NSHIFT = 0x18
+ IN_CLASSB_HOST = 0xffff
+ IN_CLASSB_MAX = 0x10000
+ IN_CLASSB_NET = 0xffff0000
+ IN_CLASSB_NSHIFT = 0x10
+ IN_CLASSC_HOST = 0xff
+ IN_CLASSC_NET = 0xffffff00
+ IN_CLASSC_NSHIFT = 0x8
+ IN_CLOEXEC = 0x80000
+ IN_CLOSE = 0x18
+ IN_CLOSE_NOWRITE = 0x10
+ IN_CLOSE_WRITE = 0x8
+ IN_CREATE = 0x100
+ IN_DELETE = 0x200
+ IN_DELETE_SELF = 0x400
+ IN_DONT_FOLLOW = 0x2000000
+ IN_EXCL_UNLINK = 0x4000000
+ IN_IGNORED = 0x8000
+ IN_ISDIR = 0x40000000
+ IN_LOOPBACKNET = 0x7f
+ IN_MASK_ADD = 0x20000000
+ IN_MODIFY = 0x2
+ IN_MOVE = 0xc0
+ IN_MOVED_FROM = 0x40
+ IN_MOVED_TO = 0x80
+ IN_MOVE_SELF = 0x800
+ IN_NONBLOCK = 0x80
+ IN_ONESHOT = 0x80000000
+ IN_ONLYDIR = 0x1000000
+ IN_OPEN = 0x20
+ IN_Q_OVERFLOW = 0x4000
+ IN_UNMOUNT = 0x2000
+ IPPROTO_AH = 0x33
+ IPPROTO_BEETPH = 0x5e
+ IPPROTO_COMP = 0x6c
+ IPPROTO_DCCP = 0x21
+ IPPROTO_DSTOPTS = 0x3c
+ IPPROTO_EGP = 0x8
+ IPPROTO_ENCAP = 0x62
+ IPPROTO_ESP = 0x32
+ IPPROTO_FRAGMENT = 0x2c
+ IPPROTO_GRE = 0x2f
+ IPPROTO_HOPOPTS = 0x0
+ IPPROTO_ICMP = 0x1
+ IPPROTO_ICMPV6 = 0x3a
+ IPPROTO_IDP = 0x16
+ IPPROTO_IGMP = 0x2
+ IPPROTO_IP = 0x0
+ IPPROTO_IPIP = 0x4
+ IPPROTO_IPV6 = 0x29
+ IPPROTO_MH = 0x87
+ IPPROTO_MTP = 0x5c
+ IPPROTO_NONE = 0x3b
+ IPPROTO_PIM = 0x67
+ IPPROTO_PUP = 0xc
+ IPPROTO_RAW = 0xff
+ IPPROTO_ROUTING = 0x2b
+ IPPROTO_RSVP = 0x2e
+ IPPROTO_SCTP = 0x84
+ IPPROTO_TCP = 0x6
+ IPPROTO_TP = 0x1d
+ IPPROTO_UDP = 0x11
+ IPPROTO_UDPLITE = 0x88
+ IPV6_2292DSTOPTS = 0x4
+ IPV6_2292HOPLIMIT = 0x8
+ IPV6_2292HOPOPTS = 0x3
+ IPV6_2292PKTINFO = 0x2
+ IPV6_2292PKTOPTIONS = 0x6
+ IPV6_2292RTHDR = 0x5
+ IPV6_ADDRFORM = 0x1
+ IPV6_ADD_MEMBERSHIP = 0x14
+ IPV6_AUTHHDR = 0xa
+ IPV6_CHECKSUM = 0x7
+ IPV6_DROP_MEMBERSHIP = 0x15
+ IPV6_DSTOPTS = 0x3b
+ IPV6_HOPLIMIT = 0x34
+ IPV6_HOPOPTS = 0x36
+ IPV6_IPSEC_POLICY = 0x22
+ IPV6_JOIN_ANYCAST = 0x1b
+ IPV6_JOIN_GROUP = 0x14
+ IPV6_LEAVE_ANYCAST = 0x1c
+ IPV6_LEAVE_GROUP = 0x15
+ IPV6_MTU = 0x18
+ IPV6_MTU_DISCOVER = 0x17
+ IPV6_MULTICAST_HOPS = 0x12
+ IPV6_MULTICAST_IF = 0x11
+ IPV6_MULTICAST_LOOP = 0x13
+ IPV6_NEXTHOP = 0x9
+ IPV6_PKTINFO = 0x32
+ IPV6_PMTUDISC_DO = 0x2
+ IPV6_PMTUDISC_DONT = 0x0
+ IPV6_PMTUDISC_PROBE = 0x3
+ IPV6_PMTUDISC_WANT = 0x1
+ IPV6_RECVDSTOPTS = 0x3a
+ IPV6_RECVERR = 0x19
+ IPV6_RECVHOPLIMIT = 0x33
+ IPV6_RECVHOPOPTS = 0x35
+ IPV6_RECVPKTINFO = 0x31
+ IPV6_RECVRTHDR = 0x38
+ IPV6_RECVTCLASS = 0x42
+ IPV6_ROUTER_ALERT = 0x16
+ IPV6_RTHDR = 0x39
+ IPV6_RTHDRDSTOPTS = 0x37
+ IPV6_RTHDR_LOOSE = 0x0
+ IPV6_RTHDR_STRICT = 0x1
+ IPV6_RTHDR_TYPE_0 = 0x0
+ IPV6_RXDSTOPTS = 0x3b
+ IPV6_RXHOPOPTS = 0x36
+ IPV6_TCLASS = 0x43
+ IPV6_UNICAST_HOPS = 0x10
+ IPV6_V6ONLY = 0x1a
+ IPV6_XFRM_POLICY = 0x23
+ IP_ADD_MEMBERSHIP = 0x23
+ IP_ADD_SOURCE_MEMBERSHIP = 0x27
+ IP_BLOCK_SOURCE = 0x26
+ IP_DEFAULT_MULTICAST_LOOP = 0x1
+ IP_DEFAULT_MULTICAST_TTL = 0x1
+ IP_DF = 0x4000
+ IP_DROP_MEMBERSHIP = 0x24
+ IP_DROP_SOURCE_MEMBERSHIP = 0x28
+ IP_FREEBIND = 0xf
+ IP_HDRINCL = 0x3
+ IP_IPSEC_POLICY = 0x10
+ IP_MAXPACKET = 0xffff
+ IP_MAX_MEMBERSHIPS = 0x14
+ IP_MF = 0x2000
+ IP_MINTTL = 0x15
+ IP_MSFILTER = 0x29
+ IP_MSS = 0x240
+ IP_MTU = 0xe
+ IP_MTU_DISCOVER = 0xa
+ IP_MULTICAST_ALL = 0x31
+ IP_MULTICAST_IF = 0x20
+ IP_MULTICAST_LOOP = 0x22
+ IP_MULTICAST_TTL = 0x21
+ IP_OFFMASK = 0x1fff
+ IP_OPTIONS = 0x4
+ IP_ORIGDSTADDR = 0x14
+ IP_PASSSEC = 0x12
+ IP_PKTINFO = 0x8
+ IP_PKTOPTIONS = 0x9
+ IP_PMTUDISC = 0xa
+ IP_PMTUDISC_DO = 0x2
+ IP_PMTUDISC_DONT = 0x0
+ IP_PMTUDISC_PROBE = 0x3
+ IP_PMTUDISC_WANT = 0x1
+ IP_RECVERR = 0xb
+ IP_RECVOPTS = 0x6
+ IP_RECVORIGDSTADDR = 0x14
+ IP_RECVRETOPTS = 0x7
+ IP_RECVTOS = 0xd
+ IP_RECVTTL = 0xc
+ IP_RETOPTS = 0x7
+ IP_RF = 0x8000
+ IP_ROUTER_ALERT = 0x5
+ IP_TOS = 0x1
+ IP_TRANSPARENT = 0x13
+ IP_TTL = 0x2
+ IP_UNBLOCK_SOURCE = 0x25
+ IP_UNICAST_IF = 0x32
+ IP_XFRM_POLICY = 0x11
+ ISIG = 0x1
+ ISTRIP = 0x20
+ IUTF8 = 0x4000
+ IXANY = 0x800
+ IXOFF = 0x1000
+ IXON = 0x400
+ LINUX_REBOOT_CMD_CAD_OFF = 0x0
+ LINUX_REBOOT_CMD_CAD_ON = 0x89abcdef
+ LINUX_REBOOT_CMD_HALT = 0xcdef0123
+ LINUX_REBOOT_CMD_KEXEC = 0x45584543
+ LINUX_REBOOT_CMD_POWER_OFF = 0x4321fedc
+ LINUX_REBOOT_CMD_RESTART = 0x1234567
+ LINUX_REBOOT_CMD_RESTART2 = 0xa1b2c3d4
+ LINUX_REBOOT_CMD_SW_SUSPEND = 0xd000fce2
+ LINUX_REBOOT_MAGIC1 = 0xfee1dead
+ LINUX_REBOOT_MAGIC2 = 0x28121969
+ LOCK_EX = 0x2
+ LOCK_NB = 0x4
+ LOCK_SH = 0x1
+ LOCK_UN = 0x8
+ MADV_DODUMP = 0x11
+ MADV_DOFORK = 0xb
+ MADV_DONTDUMP = 0x10
+ MADV_DONTFORK = 0xa
+ MADV_DONTNEED = 0x4
+ MADV_HUGEPAGE = 0xe
+ MADV_HWPOISON = 0x64
+ MADV_MERGEABLE = 0xc
+ MADV_NOHUGEPAGE = 0xf
+ MADV_NORMAL = 0x0
+ MADV_RANDOM = 0x1
+ MADV_REMOVE = 0x9
+ MADV_SEQUENTIAL = 0x2
+ MADV_UNMERGEABLE = 0xd
+ MADV_WILLNEED = 0x3
+ MAP_ANON = 0x800
+ MAP_ANONYMOUS = 0x800
+ MAP_DENYWRITE = 0x2000
+ MAP_EXECUTABLE = 0x4000
+ MAP_FILE = 0x0
+ MAP_FIXED = 0x10
+ MAP_GROWSDOWN = 0x1000
+ MAP_HUGETLB = 0x80000
+ MAP_HUGE_MASK = 0x3f
+ MAP_HUGE_SHIFT = 0x1a
+ MAP_LOCKED = 0x8000
+ MAP_NONBLOCK = 0x20000
+ MAP_NORESERVE = 0x400
+ MAP_POPULATE = 0x10000
+ MAP_PRIVATE = 0x2
+ MAP_RENAME = 0x800
+ MAP_SHARED = 0x1
+ MAP_STACK = 0x40000
+ MAP_TYPE = 0xf
+ MCL_CURRENT = 0x1
+ MCL_FUTURE = 0x2
+ MNT_DETACH = 0x2
+ MNT_EXPIRE = 0x4
+ MNT_FORCE = 0x1
+ MSG_CMSG_CLOEXEC = 0x40000000
+ MSG_CONFIRM = 0x800
+ MSG_CTRUNC = 0x8
+ MSG_DONTROUTE = 0x4
+ MSG_DONTWAIT = 0x40
+ MSG_EOR = 0x80
+ MSG_ERRQUEUE = 0x2000
+ MSG_FASTOPEN = 0x20000000
+ MSG_FIN = 0x200
+ MSG_MORE = 0x8000
+ MSG_NOSIGNAL = 0x4000
+ MSG_OOB = 0x1
+ MSG_PEEK = 0x2
+ MSG_PROXY = 0x10
+ MSG_RST = 0x1000
+ MSG_SYN = 0x400
+ MSG_TRUNC = 0x20
+ MSG_TRYHARD = 0x4
+ MSG_WAITALL = 0x100
+ MSG_WAITFORONE = 0x10000
+ MS_ACTIVE = 0x40000000
+ MS_ASYNC = 0x1
+ MS_BIND = 0x1000
+ MS_DIRSYNC = 0x80
+ MS_INVALIDATE = 0x2
+ MS_I_VERSION = 0x800000
+ MS_KERNMOUNT = 0x400000
+ MS_MANDLOCK = 0x40
+ MS_MGC_MSK = 0xffff0000
+ MS_MGC_VAL = 0xc0ed0000
+ MS_MOVE = 0x2000
+ MS_NOATIME = 0x400
+ MS_NODEV = 0x4
+ MS_NODIRATIME = 0x800
+ MS_NOEXEC = 0x8
+ MS_NOSUID = 0x2
+ MS_NOUSER = -0x80000000
+ MS_POSIXACL = 0x10000
+ MS_PRIVATE = 0x40000
+ MS_RDONLY = 0x1
+ MS_REC = 0x4000
+ MS_RELATIME = 0x200000
+ MS_REMOUNT = 0x20
+ MS_RMT_MASK = 0x800051
+ MS_SHARED = 0x100000
+ MS_SILENT = 0x8000
+ MS_SLAVE = 0x80000
+ MS_STRICTATIME = 0x1000000
+ MS_SYNC = 0x4
+ MS_SYNCHRONOUS = 0x10
+ MS_UNBINDABLE = 0x20000
+ NAME_MAX = 0xff
+ NETLINK_ADD_MEMBERSHIP = 0x1
+ NETLINK_AUDIT = 0x9
+ NETLINK_BROADCAST_ERROR = 0x4
+ NETLINK_CONNECTOR = 0xb
+ NETLINK_CRYPTO = 0x15
+ NETLINK_DNRTMSG = 0xe
+ NETLINK_DROP_MEMBERSHIP = 0x2
+ NETLINK_ECRYPTFS = 0x13
+ NETLINK_FIB_LOOKUP = 0xa
+ NETLINK_FIREWALL = 0x3
+ NETLINK_GENERIC = 0x10
+ NETLINK_INET_DIAG = 0x4
+ NETLINK_IP6_FW = 0xd
+ NETLINK_ISCSI = 0x8
+ NETLINK_KOBJECT_UEVENT = 0xf
+ NETLINK_NETFILTER = 0xc
+ NETLINK_NFLOG = 0x5
+ NETLINK_NO_ENOBUFS = 0x5
+ NETLINK_PKTINFO = 0x3
+ NETLINK_RDMA = 0x14
+ NETLINK_ROUTE = 0x0
+ NETLINK_RX_RING = 0x6
+ NETLINK_SCSITRANSPORT = 0x12
+ NETLINK_SELINUX = 0x7
+ NETLINK_SOCK_DIAG = 0x4
+ NETLINK_TX_RING = 0x7
+ NETLINK_UNUSED = 0x1
+ NETLINK_USERSOCK = 0x2
+ NETLINK_XFRM = 0x6
+ NLA_ALIGNTO = 0x4
+ NLA_F_NESTED = 0x8000
+ NLA_F_NET_BYTEORDER = 0x4000
+ NLA_HDRLEN = 0x4
+ NLMSG_ALIGNTO = 0x4
+ NLMSG_DONE = 0x3
+ NLMSG_ERROR = 0x2
+ NLMSG_HDRLEN = 0x10
+ NLMSG_MIN_TYPE = 0x10
+ NLMSG_NOOP = 0x1
+ NLMSG_OVERRUN = 0x4
+ NLM_F_ACK = 0x4
+ NLM_F_APPEND = 0x800
+ NLM_F_ATOMIC = 0x400
+ NLM_F_CREATE = 0x400
+ NLM_F_DUMP = 0x300
+ NLM_F_DUMP_INTR = 0x10
+ NLM_F_ECHO = 0x8
+ NLM_F_EXCL = 0x200
+ NLM_F_MATCH = 0x200
+ NLM_F_MULTI = 0x2
+ NLM_F_REPLACE = 0x100
+ NLM_F_REQUEST = 0x1
+ NLM_F_ROOT = 0x100
+ NOFLSH = 0x80
+ OCRNL = 0x8
+ OFDEL = 0x80
+ OFILL = 0x40
+ ONLCR = 0x4
+ ONLRET = 0x20
+ ONOCR = 0x10
+ OPOST = 0x1
+ O_ACCMODE = 0x3
+ O_APPEND = 0x8
+ O_ASYNC = 0x1000
+ O_CLOEXEC = 0x80000
+ O_CREAT = 0x100
+ O_DIRECT = 0x8000
+ O_DIRECTORY = 0x10000
+ O_DSYNC = 0x10
+ O_EXCL = 0x400
+ O_FSYNC = 0x4010
+ O_LARGEFILE = 0x2000
+ O_NDELAY = 0x80
+ O_NOATIME = 0x40000
+ O_NOCTTY = 0x800
+ O_NOFOLLOW = 0x20000
+ O_NONBLOCK = 0x80
+ O_PATH = 0x200000
+ O_RDONLY = 0x0
+ O_RDWR = 0x2
+ O_RSYNC = 0x4010
+ O_SYNC = 0x4010
+ O_TMPFILE = 0x410000
+ O_TRUNC = 0x200
+ O_WRONLY = 0x1
+ PACKET_ADD_MEMBERSHIP = 0x1
+ PACKET_AUXDATA = 0x8
+ PACKET_BROADCAST = 0x1
+ PACKET_COPY_THRESH = 0x7
+ PACKET_DROP_MEMBERSHIP = 0x2
+ PACKET_FANOUT = 0x12
+ PACKET_FANOUT_CPU = 0x2
+ PACKET_FANOUT_FLAG_DEFRAG = 0x8000
+ PACKET_FANOUT_FLAG_ROLLOVER = 0x1000
+ PACKET_FANOUT_HASH = 0x0
+ PACKET_FANOUT_LB = 0x1
+ PACKET_FANOUT_QM = 0x5
+ PACKET_FANOUT_RND = 0x4
+ PACKET_FANOUT_ROLLOVER = 0x3
+ PACKET_FASTROUTE = 0x6
+ PACKET_HDRLEN = 0xb
+ PACKET_HOST = 0x0
+ PACKET_KERNEL = 0x7
+ PACKET_LOOPBACK = 0x5
+ PACKET_LOSS = 0xe
+ PACKET_MR_ALLMULTI = 0x2
+ PACKET_MR_MULTICAST = 0x0
+ PACKET_MR_PROMISC = 0x1
+ PACKET_MR_UNICAST = 0x3
+ PACKET_MULTICAST = 0x2
+ PACKET_ORIGDEV = 0x9
+ PACKET_OTHERHOST = 0x3
+ PACKET_OUTGOING = 0x4
+ PACKET_QDISC_BYPASS = 0x14
+ PACKET_RECV_OUTPUT = 0x3
+ PACKET_RESERVE = 0xc
+ PACKET_RX_RING = 0x5
+ PACKET_STATISTICS = 0x6
+ PACKET_TIMESTAMP = 0x11
+ PACKET_TX_HAS_OFF = 0x13
+ PACKET_TX_RING = 0xd
+ PACKET_TX_TIMESTAMP = 0x10
+ PACKET_USER = 0x6
+ PACKET_VERSION = 0xa
+ PACKET_VNET_HDR = 0xf
+ PARENB = 0x100
+ PARITY_CRC16_PR0 = 0x2
+ PARITY_CRC16_PR0_CCITT = 0x4
+ PARITY_CRC16_PR1 = 0x3
+ PARITY_CRC16_PR1_CCITT = 0x5
+ PARITY_CRC32_PR0_CCITT = 0x6
+ PARITY_CRC32_PR1_CCITT = 0x7
+ PARITY_DEFAULT = 0x0
+ PARITY_NONE = 0x1
+ PARMRK = 0x8
+ PARODD = 0x200
+ PENDIN = 0x4000
+ PRIO_PGRP = 0x1
+ PRIO_PROCESS = 0x0
+ PRIO_USER = 0x2
+ PROT_EXEC = 0x4
+ PROT_GROWSDOWN = 0x1000000
+ PROT_GROWSUP = 0x2000000
+ PROT_NONE = 0x0
+ PROT_READ = 0x1
+ PROT_WRITE = 0x2
+ PR_CAPBSET_DROP = 0x18
+ PR_CAPBSET_READ = 0x17
+ PR_ENDIAN_BIG = 0x0
+ PR_ENDIAN_LITTLE = 0x1
+ PR_ENDIAN_PPC_LITTLE = 0x2
+ PR_FPEMU_NOPRINT = 0x1
+ PR_FPEMU_SIGFPE = 0x2
+ PR_FP_EXC_ASYNC = 0x2
+ PR_FP_EXC_DISABLED = 0x0
+ PR_FP_EXC_DIV = 0x10000
+ PR_FP_EXC_INV = 0x100000
+ PR_FP_EXC_NONRECOV = 0x1
+ PR_FP_EXC_OVF = 0x20000
+ PR_FP_EXC_PRECISE = 0x3
+ PR_FP_EXC_RES = 0x80000
+ PR_FP_EXC_SW_ENABLE = 0x80
+ PR_FP_EXC_UND = 0x40000
+ PR_GET_CHILD_SUBREAPER = 0x25
+ PR_GET_DUMPABLE = 0x3
+ PR_GET_ENDIAN = 0x13
+ PR_GET_FPEMU = 0x9
+ PR_GET_FPEXC = 0xb
+ PR_GET_KEEPCAPS = 0x7
+ PR_GET_NAME = 0x10
+ PR_GET_NO_NEW_PRIVS = 0x27
+ PR_GET_PDEATHSIG = 0x2
+ PR_GET_SECCOMP = 0x15
+ PR_GET_SECUREBITS = 0x1b
+ PR_GET_THP_DISABLE = 0x2a
+ PR_GET_TID_ADDRESS = 0x28
+ PR_GET_TIMERSLACK = 0x1e
+ PR_GET_TIMING = 0xd
+ PR_GET_TSC = 0x19
+ PR_GET_UNALIGN = 0x5
+ PR_MCE_KILL = 0x21
+ PR_MCE_KILL_CLEAR = 0x0
+ PR_MCE_KILL_DEFAULT = 0x2
+ PR_MCE_KILL_EARLY = 0x1
+ PR_MCE_KILL_GET = 0x22
+ PR_MCE_KILL_LATE = 0x0
+ PR_MCE_KILL_SET = 0x1
+ PR_SET_CHILD_SUBREAPER = 0x24
+ PR_SET_DUMPABLE = 0x4
+ PR_SET_ENDIAN = 0x14
+ PR_SET_FPEMU = 0xa
+ PR_SET_FPEXC = 0xc
+ PR_SET_KEEPCAPS = 0x8
+ PR_SET_MM = 0x23
+ PR_SET_MM_ARG_END = 0x9
+ PR_SET_MM_ARG_START = 0x8
+ PR_SET_MM_AUXV = 0xc
+ PR_SET_MM_BRK = 0x7
+ PR_SET_MM_END_CODE = 0x2
+ PR_SET_MM_END_DATA = 0x4
+ PR_SET_MM_ENV_END = 0xb
+ PR_SET_MM_ENV_START = 0xa
+ PR_SET_MM_EXE_FILE = 0xd
+ PR_SET_MM_START_BRK = 0x6
+ PR_SET_MM_START_CODE = 0x1
+ PR_SET_MM_START_DATA = 0x3
+ PR_SET_MM_START_STACK = 0x5
+ PR_SET_NAME = 0xf
+ PR_SET_NO_NEW_PRIVS = 0x26
+ PR_SET_PDEATHSIG = 0x1
+ PR_SET_PTRACER = 0x59616d61
+ PR_SET_PTRACER_ANY = 0xffffffff
+ PR_SET_SECCOMP = 0x16
+ PR_SET_SECUREBITS = 0x1c
+ PR_SET_THP_DISABLE = 0x29
+ PR_SET_TIMERSLACK = 0x1d
+ PR_SET_TIMING = 0xe
+ PR_SET_TSC = 0x1a
+ PR_SET_UNALIGN = 0x6
+ PR_TASK_PERF_EVENTS_DISABLE = 0x1f
+ PR_TASK_PERF_EVENTS_ENABLE = 0x20
+ PR_TIMING_STATISTICAL = 0x0
+ PR_TIMING_TIMESTAMP = 0x1
+ PR_TSC_ENABLE = 0x1
+ PR_TSC_SIGSEGV = 0x2
+ PR_UNALIGN_NOPRINT = 0x1
+ PR_UNALIGN_SIGBUS = 0x2
+ PTRACE_ATTACH = 0x10
+ PTRACE_CONT = 0x7
+ PTRACE_DETACH = 0x11
+ PTRACE_EVENT_CLONE = 0x3
+ PTRACE_EVENT_EXEC = 0x4
+ PTRACE_EVENT_EXIT = 0x6
+ PTRACE_EVENT_FORK = 0x1
+ PTRACE_EVENT_SECCOMP = 0x7
+ PTRACE_EVENT_STOP = 0x80
+ PTRACE_EVENT_VFORK = 0x2
+ PTRACE_EVENT_VFORK_DONE = 0x5
+ PTRACE_GETEVENTMSG = 0x4201
+ PTRACE_GETFPREGS = 0xe
+ PTRACE_GETREGS = 0xc
+ PTRACE_GETREGSET = 0x4204
+ PTRACE_GETSIGINFO = 0x4202
+ PTRACE_GETSIGMASK = 0x420a
+ PTRACE_GET_THREAD_AREA = 0x19
+ PTRACE_GET_THREAD_AREA_3264 = 0xc4
+ PTRACE_GET_WATCH_REGS = 0xd0
+ PTRACE_INTERRUPT = 0x4207
+ PTRACE_KILL = 0x8
+ PTRACE_LISTEN = 0x4208
+ PTRACE_OLDSETOPTIONS = 0x15
+ PTRACE_O_EXITKILL = 0x100000
+ PTRACE_O_MASK = 0x1000ff
+ PTRACE_O_TRACECLONE = 0x8
+ PTRACE_O_TRACEEXEC = 0x10
+ PTRACE_O_TRACEEXIT = 0x40
+ PTRACE_O_TRACEFORK = 0x2
+ PTRACE_O_TRACESECCOMP = 0x80
+ PTRACE_O_TRACESYSGOOD = 0x1
+ PTRACE_O_TRACEVFORK = 0x4
+ PTRACE_O_TRACEVFORKDONE = 0x20
+ PTRACE_PEEKDATA = 0x2
+ PTRACE_PEEKDATA_3264 = 0xc1
+ PTRACE_PEEKSIGINFO = 0x4209
+ PTRACE_PEEKSIGINFO_SHARED = 0x1
+ PTRACE_PEEKTEXT = 0x1
+ PTRACE_PEEKTEXT_3264 = 0xc0
+ PTRACE_PEEKUSR = 0x3
+ PTRACE_POKEDATA = 0x5
+ PTRACE_POKEDATA_3264 = 0xc3
+ PTRACE_POKETEXT = 0x4
+ PTRACE_POKETEXT_3264 = 0xc2
+ PTRACE_POKEUSR = 0x6
+ PTRACE_SEIZE = 0x4206
+ PTRACE_SETFPREGS = 0xf
+ PTRACE_SETOPTIONS = 0x4200
+ PTRACE_SETREGS = 0xd
+ PTRACE_SETREGSET = 0x4205
+ PTRACE_SETSIGINFO = 0x4203
+ PTRACE_SETSIGMASK = 0x420b
+ PTRACE_SET_THREAD_AREA = 0x1a
+ PTRACE_SET_WATCH_REGS = 0xd1
+ PTRACE_SINGLESTEP = 0x9
+ PTRACE_SYSCALL = 0x18
+ PTRACE_TRACEME = 0x0
+ RLIMIT_AS = 0x6
+ RLIMIT_CORE = 0x4
+ RLIMIT_CPU = 0x0
+ RLIMIT_DATA = 0x2
+ RLIMIT_FSIZE = 0x1
+ RLIMIT_NOFILE = 0x5
+ RLIMIT_STACK = 0x3
+ RLIM_INFINITY = -0x1
+ RTAX_ADVMSS = 0x8
+ RTAX_CWND = 0x7
+ RTAX_FEATURES = 0xc
+ RTAX_FEATURE_ALLFRAG = 0x8
+ RTAX_FEATURE_ECN = 0x1
+ RTAX_FEATURE_SACK = 0x2
+ RTAX_FEATURE_TIMESTAMP = 0x4
+ RTAX_HOPLIMIT = 0xa
+ RTAX_INITCWND = 0xb
+ RTAX_INITRWND = 0xe
+ RTAX_LOCK = 0x1
+ RTAX_MAX = 0xf
+ RTAX_MTU = 0x2
+ RTAX_QUICKACK = 0xf
+ RTAX_REORDERING = 0x9
+ RTAX_RTO_MIN = 0xd
+ RTAX_RTT = 0x4
+ RTAX_RTTVAR = 0x5
+ RTAX_SSTHRESH = 0x6
+ RTAX_UNSPEC = 0x0
+ RTAX_WINDOW = 0x3
+ RTA_ALIGNTO = 0x4
+ RTA_MAX = 0x11
+ RTCF_DIRECTSRC = 0x4000000
+ RTCF_DOREDIRECT = 0x1000000
+ RTCF_LOG = 0x2000000
+ RTCF_MASQ = 0x400000
+ RTCF_NAT = 0x800000
+ RTCF_VALVE = 0x200000
+ RTF_ADDRCLASSMASK = 0xf8000000
+ RTF_ADDRCONF = 0x40000
+ RTF_ALLONLINK = 0x20000
+ RTF_BROADCAST = 0x10000000
+ RTF_CACHE = 0x1000000
+ RTF_DEFAULT = 0x10000
+ RTF_DYNAMIC = 0x10
+ RTF_FLOW = 0x2000000
+ RTF_GATEWAY = 0x2
+ RTF_HOST = 0x4
+ RTF_INTERFACE = 0x40000000
+ RTF_IRTT = 0x100
+ RTF_LINKRT = 0x100000
+ RTF_LOCAL = 0x80000000
+ RTF_MODIFIED = 0x20
+ RTF_MSS = 0x40
+ RTF_MTU = 0x40
+ RTF_MULTICAST = 0x20000000
+ RTF_NAT = 0x8000000
+ RTF_NOFORWARD = 0x1000
+ RTF_NONEXTHOP = 0x200000
+ RTF_NOPMTUDISC = 0x4000
+ RTF_POLICY = 0x4000000
+ RTF_REINSTATE = 0x8
+ RTF_REJECT = 0x200
+ RTF_STATIC = 0x400
+ RTF_THROW = 0x2000
+ RTF_UP = 0x1
+ RTF_WINDOW = 0x80
+ RTF_XRESOLVE = 0x800
+ RTM_BASE = 0x10
+ RTM_DELACTION = 0x31
+ RTM_DELADDR = 0x15
+ RTM_DELADDRLABEL = 0x49
+ RTM_DELLINK = 0x11
+ RTM_DELMDB = 0x55
+ RTM_DELNEIGH = 0x1d
+ RTM_DELQDISC = 0x25
+ RTM_DELROUTE = 0x19
+ RTM_DELRULE = 0x21
+ RTM_DELTCLASS = 0x29
+ RTM_DELTFILTER = 0x2d
+ RTM_F_CLONED = 0x200
+ RTM_F_EQUALIZE = 0x400
+ RTM_F_NOTIFY = 0x100
+ RTM_F_PREFIX = 0x800
+ RTM_GETACTION = 0x32
+ RTM_GETADDR = 0x16
+ RTM_GETADDRLABEL = 0x4a
+ RTM_GETANYCAST = 0x3e
+ RTM_GETDCB = 0x4e
+ RTM_GETLINK = 0x12
+ RTM_GETMDB = 0x56
+ RTM_GETMULTICAST = 0x3a
+ RTM_GETNEIGH = 0x1e
+ RTM_GETNEIGHTBL = 0x42
+ RTM_GETNETCONF = 0x52
+ RTM_GETQDISC = 0x26
+ RTM_GETROUTE = 0x1a
+ RTM_GETRULE = 0x22
+ RTM_GETTCLASS = 0x2a
+ RTM_GETTFILTER = 0x2e
+ RTM_MAX = 0x57
+ RTM_NEWACTION = 0x30
+ RTM_NEWADDR = 0x14
+ RTM_NEWADDRLABEL = 0x48
+ RTM_NEWLINK = 0x10
+ RTM_NEWMDB = 0x54
+ RTM_NEWNDUSEROPT = 0x44
+ RTM_NEWNEIGH = 0x1c
+ RTM_NEWNEIGHTBL = 0x40
+ RTM_NEWNETCONF = 0x50
+ RTM_NEWPREFIX = 0x34
+ RTM_NEWQDISC = 0x24
+ RTM_NEWROUTE = 0x18
+ RTM_NEWRULE = 0x20
+ RTM_NEWTCLASS = 0x28
+ RTM_NEWTFILTER = 0x2c
+ RTM_NR_FAMILIES = 0x12
+ RTM_NR_MSGTYPES = 0x48
+ RTM_SETDCB = 0x4f
+ RTM_SETLINK = 0x13
+ RTM_SETNEIGHTBL = 0x43
+ RTNH_ALIGNTO = 0x4
+ RTNH_F_DEAD = 0x1
+ RTNH_F_ONLINK = 0x4
+ RTNH_F_PERVASIVE = 0x2
+ RTN_MAX = 0xb
+ RTPROT_BIRD = 0xc
+ RTPROT_BOOT = 0x3
+ RTPROT_DHCP = 0x10
+ RTPROT_DNROUTED = 0xd
+ RTPROT_GATED = 0x8
+ RTPROT_KERNEL = 0x2
+ RTPROT_MROUTED = 0x11
+ RTPROT_MRT = 0xa
+ RTPROT_NTK = 0xf
+ RTPROT_RA = 0x9
+ RTPROT_REDIRECT = 0x1
+ RTPROT_STATIC = 0x4
+ RTPROT_UNSPEC = 0x0
+ RTPROT_XORP = 0xe
+ RTPROT_ZEBRA = 0xb
+ RT_CLASS_DEFAULT = 0xfd
+ RT_CLASS_LOCAL = 0xff
+ RT_CLASS_MAIN = 0xfe
+ RT_CLASS_MAX = 0xff
+ RT_CLASS_UNSPEC = 0x0
+ RUSAGE_CHILDREN = -0x1
+ RUSAGE_SELF = 0x0
+ RUSAGE_THREAD = 0x1
+ SCM_CREDENTIALS = 0x2
+ SCM_RIGHTS = 0x1
+ SCM_TIMESTAMP = 0x1d
+ SCM_TIMESTAMPING = 0x25
+ SCM_TIMESTAMPNS = 0x23
+ SCM_WIFI_STATUS = 0x29
+ SHUT_RD = 0x0
+ SHUT_RDWR = 0x2
+ SHUT_WR = 0x1
+ SIOCADDDLCI = 0x8980
+ SIOCADDMULTI = 0x8931
+ SIOCADDRT = 0x890b
+ SIOCATMARK = 0x40047307
+ SIOCDARP = 0x8953
+ SIOCDELDLCI = 0x8981
+ SIOCDELMULTI = 0x8932
+ SIOCDELRT = 0x890c
+ SIOCDEVPRIVATE = 0x89f0
+ SIOCDIFADDR = 0x8936
+ SIOCDRARP = 0x8960
+ SIOCGARP = 0x8954
+ SIOCGIFADDR = 0x8915
+ SIOCGIFBR = 0x8940
+ SIOCGIFBRDADDR = 0x8919
+ SIOCGIFCONF = 0x8912
+ SIOCGIFCOUNT = 0x8938
+ SIOCGIFDSTADDR = 0x8917
+ SIOCGIFENCAP = 0x8925
+ SIOCGIFFLAGS = 0x8913
+ SIOCGIFHWADDR = 0x8927
+ SIOCGIFINDEX = 0x8933
+ SIOCGIFMAP = 0x8970
+ SIOCGIFMEM = 0x891f
+ SIOCGIFMETRIC = 0x891d
+ SIOCGIFMTU = 0x8921
+ SIOCGIFNAME = 0x8910
+ SIOCGIFNETMASK = 0x891b
+ SIOCGIFPFLAGS = 0x8935
+ SIOCGIFSLAVE = 0x8929
+ SIOCGIFTXQLEN = 0x8942
+ SIOCGPGRP = 0x40047309
+ SIOCGRARP = 0x8961
+ SIOCGSTAMP = 0x8906
+ SIOCGSTAMPNS = 0x8907
+ SIOCPROTOPRIVATE = 0x89e0
+ SIOCRTMSG = 0x890d
+ SIOCSARP = 0x8955
+ SIOCSIFADDR = 0x8916
+ SIOCSIFBR = 0x8941
+ SIOCSIFBRDADDR = 0x891a
+ SIOCSIFDSTADDR = 0x8918
+ SIOCSIFENCAP = 0x8926
+ SIOCSIFFLAGS = 0x8914
+ SIOCSIFHWADDR = 0x8924
+ SIOCSIFHWBROADCAST = 0x8937
+ SIOCSIFLINK = 0x8911
+ SIOCSIFMAP = 0x8971
+ SIOCSIFMEM = 0x8920
+ SIOCSIFMETRIC = 0x891e
+ SIOCSIFMTU = 0x8922
+ SIOCSIFNAME = 0x8923
+ SIOCSIFNETMASK = 0x891c
+ SIOCSIFPFLAGS = 0x8934
+ SIOCSIFSLAVE = 0x8930
+ SIOCSIFTXQLEN = 0x8943
+ SIOCSPGRP = 0x80047308
+ SIOCSRARP = 0x8962
+ SOCK_CLOEXEC = 0x80000
+ SOCK_DCCP = 0x6
+ SOCK_DGRAM = 0x1
+ SOCK_NONBLOCK = 0x80
+ SOCK_PACKET = 0xa
+ SOCK_RAW = 0x3
+ SOCK_RDM = 0x4
+ SOCK_SEQPACKET = 0x5
+ SOCK_STREAM = 0x2
+ SOL_AAL = 0x109
+ SOL_ATM = 0x108
+ SOL_DECNET = 0x105
+ SOL_ICMPV6 = 0x3a
+ SOL_IP = 0x0
+ SOL_IPV6 = 0x29
+ SOL_IRDA = 0x10a
+ SOL_PACKET = 0x107
+ SOL_RAW = 0xff
+ SOL_SOCKET = 0xffff
+ SOL_TCP = 0x6
+ SOL_X25 = 0x106
+ SOMAXCONN = 0x80
+ SO_ACCEPTCONN = 0x1009
+ SO_ATTACH_FILTER = 0x1a
+ SO_BINDTODEVICE = 0x19
+ SO_BPF_EXTENSIONS = 0x30
+ SO_BROADCAST = 0x20
+ SO_BSDCOMPAT = 0xe
+ SO_BUSY_POLL = 0x2e
+ SO_DEBUG = 0x1
+ SO_DETACH_FILTER = 0x1b
+ SO_DOMAIN = 0x1029
+ SO_DONTROUTE = 0x10
+ SO_ERROR = 0x1007
+ SO_GET_FILTER = 0x1a
+ SO_KEEPALIVE = 0x8
+ SO_LINGER = 0x80
+ SO_LOCK_FILTER = 0x2c
+ SO_MARK = 0x24
+ SO_MAX_PACING_RATE = 0x2f
+ SO_NOFCS = 0x2b
+ SO_NO_CHECK = 0xb
+ SO_OOBINLINE = 0x100
+ SO_PASSCRED = 0x11
+ SO_PASSSEC = 0x22
+ SO_PEEK_OFF = 0x2a
+ SO_PEERCRED = 0x12
+ SO_PEERNAME = 0x1c
+ SO_PEERSEC = 0x1e
+ SO_PRIORITY = 0xc
+ SO_PROTOCOL = 0x1028
+ SO_RCVBUF = 0x1002
+ SO_RCVBUFFORCE = 0x21
+ SO_RCVLOWAT = 0x1004
+ SO_RCVTIMEO = 0x1006
+ SO_REUSEADDR = 0x4
+ SO_REUSEPORT = 0x200
+ SO_RXQ_OVFL = 0x28
+ SO_SECURITY_AUTHENTICATION = 0x16
+ SO_SECURITY_ENCRYPTION_NETWORK = 0x18
+ SO_SECURITY_ENCRYPTION_TRANSPORT = 0x17
+ SO_SELECT_ERR_QUEUE = 0x2d
+ SO_SNDBUF = 0x1001
+ SO_SNDBUFFORCE = 0x1f
+ SO_SNDLOWAT = 0x1003
+ SO_SNDTIMEO = 0x1005
+ SO_STYLE = 0x1008
+ SO_TIMESTAMP = 0x1d
+ SO_TIMESTAMPING = 0x25
+ SO_TIMESTAMPNS = 0x23
+ SO_TYPE = 0x1008
+ SO_WIFI_STATUS = 0x29
+ S_BLKSIZE = 0x200
+ S_IEXEC = 0x40
+ S_IFBLK = 0x6000
+ S_IFCHR = 0x2000
+ S_IFDIR = 0x4000
+ S_IFIFO = 0x1000
+ S_IFLNK = 0xa000
+ S_IFMT = 0xf000
+ S_IFREG = 0x8000
+ S_IFSOCK = 0xc000
+ S_IREAD = 0x100
+ S_IRGRP = 0x20
+ S_IROTH = 0x4
+ S_IRUSR = 0x100
+ S_IRWXG = 0x38
+ S_IRWXO = 0x7
+ S_IRWXU = 0x1c0
+ S_ISGID = 0x400
+ S_ISUID = 0x800
+ S_ISVTX = 0x200
+ S_IWGRP = 0x10
+ S_IWOTH = 0x2
+ S_IWRITE = 0x80
+ S_IWUSR = 0x80
+ S_IXGRP = 0x8
+ S_IXOTH = 0x1
+ S_IXUSR = 0x40
+ TCFLSH = 0x5407
+ TCIFLUSH = 0x0
+ TCIOFLUSH = 0x2
+ TCOFLUSH = 0x1
+ TCP_CONGESTION = 0xd
+ TCP_COOKIE_IN_ALWAYS = 0x1
+ TCP_COOKIE_MAX = 0x10
+ TCP_COOKIE_MIN = 0x8
+ TCP_COOKIE_OUT_NEVER = 0x2
+ TCP_COOKIE_PAIR_SIZE = 0x20
+ TCP_COOKIE_TRANSACTIONS = 0xf
+ TCP_CORK = 0x3
+ TCP_DEFER_ACCEPT = 0x9
+ TCP_FASTOPEN = 0x17
+ TCP_INFO = 0xb
+ TCP_KEEPCNT = 0x6
+ TCP_KEEPIDLE = 0x4
+ TCP_KEEPINTVL = 0x5
+ TCP_LINGER2 = 0x8
+ TCP_MAXSEG = 0x2
+ TCP_MAXWIN = 0xffff
+ TCP_MAX_WINSHIFT = 0xe
+ TCP_MD5SIG = 0xe
+ TCP_MD5SIG_MAXKEYLEN = 0x50
+ TCP_MSS = 0x200
+ TCP_MSS_DEFAULT = 0x218
+ TCP_MSS_DESIRED = 0x4c4
+ TCP_NODELAY = 0x1
+ TCP_QUEUE_SEQ = 0x15
+ TCP_QUICKACK = 0xc
+ TCP_REPAIR = 0x13
+ TCP_REPAIR_OPTIONS = 0x16
+ TCP_REPAIR_QUEUE = 0x14
+ TCP_SYNCNT = 0x7
+ TCP_S_DATA_IN = 0x4
+ TCP_S_DATA_OUT = 0x8
+ TCP_THIN_DUPACK = 0x11
+ TCP_THIN_LINEAR_TIMEOUTS = 0x10
+ TCP_TIMESTAMP = 0x18
+ TCP_USER_TIMEOUT = 0x12
+ TCP_WINDOW_CLAMP = 0xa
+ TCSAFLUSH = 0x5410
+ TIOCCBRK = 0x5428
+ TIOCCONS = 0x80047478
+ TIOCEXCL = 0x740d
+ TIOCGDEV = 0x40045432
+ TIOCGETD = 0x7400
+ TIOCGETP = 0x7408
+ TIOCGEXCL = 0x40045440
+ TIOCGICOUNT = 0x5492
+ TIOCGLCKTRMIOS = 0x548b
+ TIOCGLTC = 0x7474
+ TIOCGPGRP = 0x40047477
+ TIOCGPKT = 0x40045438
+ TIOCGPTLCK = 0x40045439
+ TIOCGPTN = 0x40045430
+ TIOCGSERIAL = 0x5484
+ TIOCGSID = 0x7416
+ TIOCGSOFTCAR = 0x5481
+ TIOCGWINSZ = 0x40087468
+ TIOCINQ = 0x467f
+ TIOCLINUX = 0x5483
+ TIOCMBIC = 0x741c
+ TIOCMBIS = 0x741b
+ TIOCMGET = 0x741d
+ TIOCMIWAIT = 0x5491
+ TIOCMSET = 0x741a
+ TIOCM_CAR = 0x100
+ TIOCM_CD = 0x100
+ TIOCM_CTS = 0x40
+ TIOCM_DSR = 0x400
+ TIOCM_DTR = 0x2
+ TIOCM_LE = 0x1
+ TIOCM_RI = 0x200
+ TIOCM_RNG = 0x200
+ TIOCM_RTS = 0x4
+ TIOCM_SR = 0x20
+ TIOCM_ST = 0x10
+ TIOCNOTTY = 0x5471
+ TIOCNXCL = 0x740e
+ TIOCOUTQ = 0x7472
+ TIOCPKT = 0x5470
+ TIOCPKT_DATA = 0x0
+ TIOCPKT_DOSTOP = 0x20
+ TIOCPKT_FLUSHREAD = 0x1
+ TIOCPKT_FLUSHWRITE = 0x2
+ TIOCPKT_IOCTL = 0x40
+ TIOCPKT_NOSTOP = 0x10
+ TIOCPKT_START = 0x8
+ TIOCPKT_STOP = 0x4
+ TIOCSBRK = 0x5427
+ TIOCSCTTY = 0x5480
+ TIOCSERCONFIG = 0x5488
+ TIOCSERGETLSR = 0x548e
+ TIOCSERGETMULTI = 0x548f
+ TIOCSERGSTRUCT = 0x548d
+ TIOCSERGWILD = 0x5489
+ TIOCSERSETMULTI = 0x5490
+ TIOCSERSWILD = 0x548a
+ TIOCSER_TEMT = 0x1
+ TIOCSETD = 0x7401
+ TIOCSETN = 0x740a
+ TIOCSETP = 0x7409
+ TIOCSIG = 0x80045436
+ TIOCSLCKTRMIOS = 0x548c
+ TIOCSLTC = 0x7475
+ TIOCSPGRP = 0x80047476
+ TIOCSPTLCK = 0x80045431
+ TIOCSSERIAL = 0x5485
+ TIOCSSOFTCAR = 0x5482
+ TIOCSTI = 0x5472
+ TIOCSWINSZ = 0x80087467
+ TIOCVHANGUP = 0x5437
+ TOSTOP = 0x8000
+ TUNATTACHFILTER = 0x800854d5
+ TUNDETACHFILTER = 0x800854d6
+ TUNGETFEATURES = 0x400454cf
+ TUNGETFILTER = 0x400854db
+ TUNGETIFF = 0x400454d2
+ TUNGETSNDBUF = 0x400454d3
+ TUNGETVNETHDRSZ = 0x400454d7
+ TUNSETDEBUG = 0x800454c9
+ TUNSETGROUP = 0x800454ce
+ TUNSETIFF = 0x800454ca
+ TUNSETIFINDEX = 0x800454da
+ TUNSETLINK = 0x800454cd
+ TUNSETNOCSUM = 0x800454c8
+ TUNSETOFFLOAD = 0x800454d0
+ TUNSETOWNER = 0x800454cc
+ TUNSETPERSIST = 0x800454cb
+ TUNSETQUEUE = 0x800454d9
+ TUNSETSNDBUF = 0x800454d4
+ TUNSETTXFILTER = 0x800454d1
+ TUNSETVNETHDRSZ = 0x800454d8
+ VDISCARD = 0xd
+ VEOF = 0x10
+ VEOL = 0x11
+ VEOL2 = 0x6
+ VERASE = 0x2
+ VINTR = 0x0
+ VKILL = 0x3
+ VLNEXT = 0xf
+ VMIN = 0x4
+ VQUIT = 0x1
+ VREPRINT = 0xc
+ VSTART = 0x8
+ VSTOP = 0x9
+ VSUSP = 0xa
+ VSWTC = 0x7
+ VSWTCH = 0x7
+ VT0 = 0x0
+ VT1 = 0x4000
+ VTDLY = 0x4000
+ VTIME = 0x5
+ VWERASE = 0xe
+ WALL = 0x40000000
+ WCLONE = 0x80000000
+ WCONTINUED = 0x8
+ WEXITED = 0x4
+ WNOHANG = 0x1
+ WNOTHREAD = 0x20000000
+ WNOWAIT = 0x1000000
+ WORDSIZE = 0x20
+ WSTOPPED = 0x2
+ WUNTRACED = 0x2
+)
+
+// Errors
+const (
+ E2BIG = Errno(0x7)
+ EACCES = Errno(0xd)
+ EADDRINUSE = Errno(0x7d)
+ EADDRNOTAVAIL = Errno(0x7e)
+ EADV = Errno(0x44)
+ EAFNOSUPPORT = Errno(0x7c)
+ EAGAIN = Errno(0xb)
+ EALREADY = Errno(0x95)
+ EBADE = Errno(0x32)
+ EBADF = Errno(0x9)
+ EBADFD = Errno(0x51)
+ EBADMSG = Errno(0x4d)
+ EBADR = Errno(0x33)
+ EBADRQC = Errno(0x36)
+ EBADSLT = Errno(0x37)
+ EBFONT = Errno(0x3b)
+ EBUSY = Errno(0x10)
+ ECANCELED = Errno(0x9e)
+ ECHILD = Errno(0xa)
+ ECHRNG = Errno(0x25)
+ ECOMM = Errno(0x46)
+ ECONNABORTED = Errno(0x82)
+ ECONNREFUSED = Errno(0x92)
+ ECONNRESET = Errno(0x83)
+ EDEADLK = Errno(0x2d)
+ EDEADLOCK = Errno(0x38)
+ EDESTADDRREQ = Errno(0x60)
+ EDOM = Errno(0x21)
+ EDOTDOT = Errno(0x49)
+ EDQUOT = Errno(0x46d)
+ EEXIST = Errno(0x11)
+ EFAULT = Errno(0xe)
+ EFBIG = Errno(0x1b)
+ EHOSTDOWN = Errno(0x93)
+ EHOSTUNREACH = Errno(0x94)
+ EHWPOISON = Errno(0xa8)
+ EIDRM = Errno(0x24)
+ EILSEQ = Errno(0x58)
+ EINIT = Errno(0x8d)
+ EINPROGRESS = Errno(0x96)
+ EINTR = Errno(0x4)
+ EINVAL = Errno(0x16)
+ EIO = Errno(0x5)
+ EISCONN = Errno(0x85)
+ EISDIR = Errno(0x15)
+ EISNAM = Errno(0x8b)
+ EKEYEXPIRED = Errno(0xa2)
+ EKEYREJECTED = Errno(0xa4)
+ EKEYREVOKED = Errno(0xa3)
+ EL2HLT = Errno(0x2c)
+ EL2NSYNC = Errno(0x26)
+ EL3HLT = Errno(0x27)
+ EL3RST = Errno(0x28)
+ ELIBACC = Errno(0x53)
+ ELIBBAD = Errno(0x54)
+ ELIBEXEC = Errno(0x57)
+ ELIBMAX = Errno(0x56)
+ ELIBSCN = Errno(0x55)
+ ELNRNG = Errno(0x29)
+ ELOOP = Errno(0x5a)
+ EMEDIUMTYPE = Errno(0xa0)
+ EMFILE = Errno(0x18)
+ EMLINK = Errno(0x1f)
+ EMSGSIZE = Errno(0x61)
+ EMULTIHOP = Errno(0x4a)
+ ENAMETOOLONG = Errno(0x4e)
+ ENAVAIL = Errno(0x8a)
+ ENETDOWN = Errno(0x7f)
+ ENETRESET = Errno(0x81)
+ ENETUNREACH = Errno(0x80)
+ ENFILE = Errno(0x17)
+ ENOANO = Errno(0x35)
+ ENOBUFS = Errno(0x84)
+ ENOCSI = Errno(0x2b)
+ ENODATA = Errno(0x3d)
+ ENODEV = Errno(0x13)
+ ENOENT = Errno(0x2)
+ ENOEXEC = Errno(0x8)
+ ENOKEY = Errno(0xa1)
+ ENOLCK = Errno(0x2e)
+ ENOLINK = Errno(0x43)
+ ENOMEDIUM = Errno(0x9f)
+ ENOMEM = Errno(0xc)
+ ENOMSG = Errno(0x23)
+ ENONET = Errno(0x40)
+ ENOPKG = Errno(0x41)
+ ENOPROTOOPT = Errno(0x63)
+ ENOSPC = Errno(0x1c)
+ ENOSR = Errno(0x3f)
+ ENOSTR = Errno(0x3c)
+ ENOSYS = Errno(0x59)
+ ENOTBLK = Errno(0xf)
+ ENOTCONN = Errno(0x86)
+ ENOTDIR = Errno(0x14)
+ ENOTEMPTY = Errno(0x5d)
+ ENOTNAM = Errno(0x89)
+ ENOTRECOVERABLE = Errno(0xa6)
+ ENOTSOCK = Errno(0x5f)
+ ENOTSUP = Errno(0x7a)
+ ENOTTY = Errno(0x19)
+ ENOTUNIQ = Errno(0x50)
+ ENXIO = Errno(0x6)
+ EOPNOTSUPP = Errno(0x7a)
+ EOVERFLOW = Errno(0x4f)
+ EOWNERDEAD = Errno(0xa5)
+ EPERM = Errno(0x1)
+ EPFNOSUPPORT = Errno(0x7b)
+ EPIPE = Errno(0x20)
+ EPROTO = Errno(0x47)
+ EPROTONOSUPPORT = Errno(0x78)
+ EPROTOTYPE = Errno(0x62)
+ ERANGE = Errno(0x22)
+ EREMCHG = Errno(0x52)
+ EREMDEV = Errno(0x8e)
+ EREMOTE = Errno(0x42)
+ EREMOTEIO = Errno(0x8c)
+ ERESTART = Errno(0x5b)
+ ERFKILL = Errno(0xa7)
+ EROFS = Errno(0x1e)
+ ESHUTDOWN = Errno(0x8f)
+ ESOCKTNOSUPPORT = Errno(0x79)
+ ESPIPE = Errno(0x1d)
+ ESRCH = Errno(0x3)
+ ESRMNT = Errno(0x45)
+ ESTALE = Errno(0x97)
+ ESTRPIPE = Errno(0x5c)
+ ETIME = Errno(0x3e)
+ ETIMEDOUT = Errno(0x91)
+ ETOOMANYREFS = Errno(0x90)
+ ETXTBSY = Errno(0x1a)
+ EUCLEAN = Errno(0x87)
+ EUNATCH = Errno(0x2a)
+ EUSERS = Errno(0x5e)
+ EWOULDBLOCK = Errno(0xb)
+ EXDEV = Errno(0x12)
+ EXFULL = Errno(0x34)
+)
+
+// Signals
+const (
+ SIGABRT = Signal(0x6)
+ SIGALRM = Signal(0xe)
+ SIGBUS = Signal(0xa)
+ SIGCHLD = Signal(0x12)
+ SIGCLD = Signal(0x12)
+ SIGCONT = Signal(0x19)
+ SIGEMT = Signal(0x7)
+ SIGFPE = Signal(0x8)
+ SIGHUP = Signal(0x1)
+ SIGILL = Signal(0x4)
+ SIGINT = Signal(0x2)
+ SIGIO = Signal(0x16)
+ SIGIOT = Signal(0x6)
+ SIGKILL = Signal(0x9)
+ SIGPIPE = Signal(0xd)
+ SIGPOLL = Signal(0x16)
+ SIGPROF = Signal(0x1d)
+ SIGPWR = Signal(0x13)
+ SIGQUIT = Signal(0x3)
+ SIGSEGV = Signal(0xb)
+ SIGSTOP = Signal(0x17)
+ SIGSYS = Signal(0xc)
+ SIGTERM = Signal(0xf)
+ SIGTRAP = Signal(0x5)
+ SIGTSTP = Signal(0x18)
+ SIGTTIN = Signal(0x1a)
+ SIGTTOU = Signal(0x1b)
+ SIGURG = Signal(0x15)
+ SIGUSR1 = Signal(0x10)
+ SIGUSR2 = Signal(0x11)
+ SIGVTALRM = Signal(0x1c)
+ SIGWINCH = Signal(0x14)
+ SIGXCPU = Signal(0x1e)
+ SIGXFSZ = Signal(0x1f)
+)
+
+// Error table
+var errors = [...]string{
+ 1: "operation not permitted",
+ 2: "no such file or directory",
+ 3: "no such process",
+ 4: "interrupted system call",
+ 5: "input/output error",
+ 6: "no such device or address",
+ 7: "argument list too long",
+ 8: "exec format error",
+ 9: "bad file descriptor",
+ 10: "no child processes",
+ 11: "resource temporarily unavailable",
+ 12: "cannot allocate memory",
+ 13: "permission denied",
+ 14: "bad address",
+ 15: "block device required",
+ 16: "device or resource busy",
+ 17: "file exists",
+ 18: "invalid cross-device link",
+ 19: "no such device",
+ 20: "not a directory",
+ 21: "is a directory",
+ 22: "invalid argument",
+ 23: "too many open files in system",
+ 24: "too many open files",
+ 25: "inappropriate ioctl for device",
+ 26: "text file busy",
+ 27: "file too large",
+ 28: "no space left on device",
+ 29: "illegal seek",
+ 30: "read-only file system",
+ 31: "too many links",
+ 32: "broken pipe",
+ 33: "numerical argument out of domain",
+ 34: "numerical result out of range",
+ 35: "no message of desired type",
+ 36: "identifier removed",
+ 37: "channel number out of range",
+ 38: "level 2 not synchronized",
+ 39: "level 3 halted",
+ 40: "level 3 reset",
+ 41: "link number out of range",
+ 42: "protocol driver not attached",
+ 43: "no CSI structure available",
+ 44: "level 2 halted",
+ 45: "resource deadlock avoided",
+ 46: "no locks available",
+ 50: "invalid exchange",
+ 51: "invalid request descriptor",
+ 52: "exchange full",
+ 53: "no anode",
+ 54: "invalid request code",
+ 55: "invalid slot",
+ 56: "file locking deadlock error",
+ 59: "bad font file format",
+ 60: "device not a stream",
+ 61: "no data available",
+ 62: "timer expired",
+ 63: "out of streams resources",
+ 64: "machine is not on the network",
+ 65: "package not installed",
+ 66: "object is remote",
+ 67: "link has been severed",
+ 68: "advertise error",
+ 69: "srmount error",
+ 70: "communication error on send",
+ 71: "protocol error",
+ 73: "RFS specific error",
+ 74: "multihop attempted",
+ 77: "bad message",
+ 78: "file name too long",
+ 79: "value too large for defined data type",
+ 80: "name not unique on network",
+ 81: "file descriptor in bad state",
+ 82: "remote address changed",
+ 83: "can not access a needed shared library",
+ 84: "accessing a corrupted shared library",
+ 85: ".lib section in a.out corrupted",
+ 86: "attempting to link in too many shared libraries",
+ 87: "cannot exec a shared library directly",
+ 88: "invalid or incomplete multibyte or wide character",
+ 89: "function not implemented",
+ 90: "too many levels of symbolic links",
+ 91: "interrupted system call should be restarted",
+ 92: "streams pipe error",
+ 93: "directory not empty",
+ 94: "too many users",
+ 95: "socket operation on non-socket",
+ 96: "destination address required",
+ 97: "message too long",
+ 98: "protocol wrong type for socket",
+ 99: "protocol not available",
+ 120: "protocol not supported",
+ 121: "socket type not supported",
+ 122: "operation not supported",
+ 123: "protocol family not supported",
+ 124: "address family not supported by protocol",
+ 125: "address already in use",
+ 126: "cannot assign requested address",
+ 127: "network is down",
+ 128: "network is unreachable",
+ 129: "network dropped connection on reset",
+ 130: "software caused connection abort",
+ 131: "connection reset by peer",
+ 132: "no buffer space available",
+ 133: "transport endpoint is already connected",
+ 134: "transport endpoint is not connected",
+ 135: "structure needs cleaning",
+ 137: "not a XENIX named type file",
+ 138: "no XENIX semaphores available",
+ 139: "is a named type file",
+ 140: "remote I/O error",
+ 141: "unknown error 141",
+ 142: "unknown error 142",
+ 143: "cannot send after transport endpoint shutdown",
+ 144: "too many references: cannot splice",
+ 145: "connection timed out",
+ 146: "connection refused",
+ 147: "host is down",
+ 148: "no route to host",
+ 149: "operation already in progress",
+ 150: "operation now in progress",
+ 151: "stale file handle",
+ 158: "operation canceled",
+ 159: "no medium found",
+ 160: "wrong medium type",
+ 161: "required key not available",
+ 162: "key has expired",
+ 163: "key has been revoked",
+ 164: "key was rejected by service",
+ 165: "owner died",
+ 166: "state not recoverable",
+ 167: "operation not possible due to RF-kill",
+ 168: "memory page has hardware error",
+ 1133: "disk quota exceeded",
+}
+
+// Signal table
+var signals = [...]string{
+ 1: "hangup",
+ 2: "interrupt",
+ 3: "quit",
+ 4: "illegal instruction",
+ 5: "trace/breakpoint trap",
+ 6: "aborted",
+ 7: "EMT trap",
+ 8: "floating point exception",
+ 9: "killed",
+ 10: "bus error",
+ 11: "segmentation fault",
+ 12: "bad system call",
+ 13: "broken pipe",
+ 14: "alarm clock",
+ 15: "terminated",
+ 16: "user defined signal 1",
+ 17: "user defined signal 2",
+ 18: "child exited",
+ 19: "power failure",
+ 20: "window changed",
+ 21: "urgent I/O condition",
+ 22: "I/O possible",
+ 23: "stopped (signal)",
+ 24: "stopped",
+ 25: "continued",
+ 26: "stopped (tty input)",
+ 27: "stopped (tty output)",
+ 28: "virtual timer expired",
+ 29: "profiling timer expired",
+ 30: "CPU time limit exceeded",
+ 31: "file size limit exceeded",
+}
diff --git a/src/syscall/zerrors_linux_mipsle.go b/src/syscall/zerrors_linux_mipsle.go
new file mode 100644
index 0000000..580d66f
--- /dev/null
+++ b/src/syscall/zerrors_linux_mipsle.go
@@ -0,0 +1,1834 @@
+// mkerrors.sh
+// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs -- _const.go
+
+package syscall
+
+const (
+ AF_ALG = 0x26
+ AF_APPLETALK = 0x5
+ AF_ASH = 0x12
+ AF_ATMPVC = 0x8
+ AF_ATMSVC = 0x14
+ AF_AX25 = 0x3
+ AF_BLUETOOTH = 0x1f
+ AF_BRIDGE = 0x7
+ AF_CAIF = 0x25
+ AF_CAN = 0x1d
+ AF_DECnet = 0xc
+ AF_ECONET = 0x13
+ AF_FILE = 0x1
+ AF_IEEE802154 = 0x24
+ AF_INET = 0x2
+ AF_INET6 = 0xa
+ AF_IPX = 0x4
+ AF_IRDA = 0x17
+ AF_ISDN = 0x22
+ AF_IUCV = 0x20
+ AF_KEY = 0xf
+ AF_LLC = 0x1a
+ AF_LOCAL = 0x1
+ AF_MAX = 0x29
+ AF_NETBEUI = 0xd
+ AF_NETLINK = 0x10
+ AF_NETROM = 0x6
+ AF_NFC = 0x27
+ AF_PACKET = 0x11
+ AF_PHONET = 0x23
+ AF_PPPOX = 0x18
+ AF_RDS = 0x15
+ AF_ROSE = 0xb
+ AF_ROUTE = 0x10
+ AF_RXRPC = 0x21
+ AF_SECURITY = 0xe
+ AF_SNA = 0x16
+ AF_TIPC = 0x1e
+ AF_UNIX = 0x1
+ AF_UNSPEC = 0x0
+ AF_VSOCK = 0x28
+ AF_WANPIPE = 0x19
+ AF_X25 = 0x9
+ ARPHRD_6LOWPAN = 0x339
+ ARPHRD_ADAPT = 0x108
+ ARPHRD_APPLETLK = 0x8
+ ARPHRD_ARCNET = 0x7
+ ARPHRD_ASH = 0x30d
+ ARPHRD_ATM = 0x13
+ ARPHRD_AX25 = 0x3
+ ARPHRD_BIF = 0x307
+ ARPHRD_CAIF = 0x336
+ ARPHRD_CAN = 0x118
+ ARPHRD_CHAOS = 0x5
+ ARPHRD_CISCO = 0x201
+ ARPHRD_CSLIP = 0x101
+ ARPHRD_CSLIP6 = 0x103
+ ARPHRD_DDCMP = 0x205
+ ARPHRD_DLCI = 0xf
+ ARPHRD_ECONET = 0x30e
+ ARPHRD_EETHER = 0x2
+ ARPHRD_ETHER = 0x1
+ ARPHRD_EUI64 = 0x1b
+ ARPHRD_FCAL = 0x311
+ ARPHRD_FCFABRIC = 0x313
+ ARPHRD_FCPL = 0x312
+ ARPHRD_FCPP = 0x310
+ ARPHRD_FDDI = 0x306
+ ARPHRD_FRAD = 0x302
+ ARPHRD_HDLC = 0x201
+ ARPHRD_HIPPI = 0x30c
+ ARPHRD_HWX25 = 0x110
+ ARPHRD_IEEE1394 = 0x18
+ ARPHRD_IEEE802 = 0x6
+ ARPHRD_IEEE80211 = 0x321
+ ARPHRD_IEEE80211_PRISM = 0x322
+ ARPHRD_IEEE80211_RADIOTAP = 0x323
+ ARPHRD_IEEE802154 = 0x324
+ ARPHRD_IEEE802154_MONITOR = 0x325
+ ARPHRD_IEEE802_TR = 0x320
+ ARPHRD_INFINIBAND = 0x20
+ ARPHRD_IP6GRE = 0x337
+ ARPHRD_IPDDP = 0x309
+ ARPHRD_IPGRE = 0x30a
+ ARPHRD_IRDA = 0x30f
+ ARPHRD_LAPB = 0x204
+ ARPHRD_LOCALTLK = 0x305
+ ARPHRD_LOOPBACK = 0x304
+ ARPHRD_METRICOM = 0x17
+ ARPHRD_NETLINK = 0x338
+ ARPHRD_NETROM = 0x0
+ ARPHRD_NONE = 0xfffe
+ ARPHRD_PHONET = 0x334
+ ARPHRD_PHONET_PIPE = 0x335
+ ARPHRD_PIMREG = 0x30b
+ ARPHRD_PPP = 0x200
+ ARPHRD_PRONET = 0x4
+ ARPHRD_RAWHDLC = 0x206
+ ARPHRD_ROSE = 0x10e
+ ARPHRD_RSRVD = 0x104
+ ARPHRD_SIT = 0x308
+ ARPHRD_SKIP = 0x303
+ ARPHRD_SLIP = 0x100
+ ARPHRD_SLIP6 = 0x102
+ ARPHRD_TUNNEL = 0x300
+ ARPHRD_TUNNEL6 = 0x301
+ ARPHRD_VOID = 0xffff
+ ARPHRD_X25 = 0x10f
+ B0 = 0x0
+ B1000000 = 0x1008
+ B110 = 0x3
+ B115200 = 0x1002
+ B1152000 = 0x1009
+ B1200 = 0x9
+ B134 = 0x4
+ B150 = 0x5
+ B1500000 = 0x100a
+ B1800 = 0xa
+ B19200 = 0xe
+ B200 = 0x6
+ B2000000 = 0x100b
+ B230400 = 0x1003
+ B2400 = 0xb
+ B2500000 = 0x100c
+ B300 = 0x7
+ B3000000 = 0x100d
+ B3500000 = 0x100e
+ B38400 = 0xf
+ B4000000 = 0x100f
+ B460800 = 0x1004
+ B4800 = 0xc
+ B50 = 0x1
+ B500000 = 0x1005
+ B57600 = 0x1001
+ B576000 = 0x1006
+ B600 = 0x8
+ B75 = 0x2
+ B921600 = 0x1007
+ B9600 = 0xd
+ BPF_A = 0x10
+ BPF_ABS = 0x20
+ BPF_ADD = 0x0
+ BPF_ALU = 0x4
+ BPF_AND = 0x50
+ BPF_B = 0x10
+ BPF_DIV = 0x30
+ BPF_H = 0x8
+ BPF_IMM = 0x0
+ BPF_IND = 0x40
+ BPF_JA = 0x0
+ BPF_JEQ = 0x10
+ BPF_JGE = 0x30
+ BPF_JGT = 0x20
+ BPF_JMP = 0x5
+ BPF_JSET = 0x40
+ BPF_K = 0x0
+ BPF_LD = 0x0
+ BPF_LDX = 0x1
+ BPF_LEN = 0x80
+ BPF_LSH = 0x60
+ BPF_MAJOR_VERSION = 0x1
+ BPF_MAXINSNS = 0x1000
+ BPF_MEM = 0x60
+ BPF_MEMWORDS = 0x10
+ BPF_MINOR_VERSION = 0x1
+ BPF_MISC = 0x7
+ BPF_MOD = 0x90
+ BPF_MSH = 0xa0
+ BPF_MUL = 0x20
+ BPF_NEG = 0x80
+ BPF_OR = 0x40
+ BPF_RET = 0x6
+ BPF_RSH = 0x70
+ BPF_ST = 0x2
+ BPF_STX = 0x3
+ BPF_SUB = 0x10
+ BPF_TAX = 0x0
+ BPF_TXA = 0x80
+ BPF_W = 0x0
+ BPF_X = 0x8
+ BPF_XOR = 0xa0
+ BRKINT = 0x2
+ CFLUSH = 0xf
+ CLOCAL = 0x800
+ CLONE_CHILD_CLEARTID = 0x200000
+ CLONE_CHILD_SETTID = 0x1000000
+ CLONE_DETACHED = 0x400000
+ CLONE_FILES = 0x400
+ CLONE_FS = 0x200
+ CLONE_IO = 0x80000000
+ CLONE_NEWIPC = 0x8000000
+ CLONE_NEWNET = 0x40000000
+ CLONE_NEWNS = 0x20000
+ CLONE_NEWPID = 0x20000000
+ CLONE_NEWUSER = 0x10000000
+ CLONE_NEWUTS = 0x4000000
+ CLONE_PARENT = 0x8000
+ CLONE_PARENT_SETTID = 0x100000
+ CLONE_PTRACE = 0x2000
+ CLONE_SETTLS = 0x80000
+ CLONE_SIGHAND = 0x800
+ CLONE_SYSVSEM = 0x40000
+ CLONE_THREAD = 0x10000
+ CLONE_UNTRACED = 0x800000
+ CLONE_VFORK = 0x4000
+ CLONE_VM = 0x100
+ CREAD = 0x80
+ CS5 = 0x0
+ CS6 = 0x10
+ CS7 = 0x20
+ CS8 = 0x30
+ CSIGNAL = 0xff
+ CSIZE = 0x30
+ CSTART = 0x11
+ CSTATUS = 0x0
+ CSTOP = 0x13
+ CSTOPB = 0x40
+ CSUSP = 0x1a
+ DT_BLK = 0x6
+ DT_CHR = 0x2
+ DT_DIR = 0x4
+ DT_FIFO = 0x1
+ DT_LNK = 0xa
+ DT_REG = 0x8
+ DT_SOCK = 0xc
+ DT_UNKNOWN = 0x0
+ DT_WHT = 0xe
+ ECHO = 0x8
+ ECHOCTL = 0x200
+ ECHOE = 0x10
+ ECHOK = 0x20
+ ECHOKE = 0x800
+ ECHONL = 0x40
+ ECHOPRT = 0x400
+ ENCODING_DEFAULT = 0x0
+ ENCODING_FM_MARK = 0x3
+ ENCODING_FM_SPACE = 0x4
+ ENCODING_MANCHESTER = 0x5
+ ENCODING_NRZ = 0x1
+ ENCODING_NRZI = 0x2
+ EPOLLERR = 0x8
+ EPOLLET = 0x80000000
+ EPOLLHUP = 0x10
+ EPOLLIN = 0x1
+ EPOLLMSG = 0x400
+ EPOLLONESHOT = 0x40000000
+ EPOLLOUT = 0x4
+ EPOLLPRI = 0x2
+ EPOLLRDBAND = 0x80
+ EPOLLRDHUP = 0x2000
+ EPOLLRDNORM = 0x40
+ EPOLLWAKEUP = 0x20000000
+ EPOLLWRBAND = 0x200
+ EPOLLWRNORM = 0x100
+ EPOLL_CLOEXEC = 0x80000
+ EPOLL_CTL_ADD = 0x1
+ EPOLL_CTL_DEL = 0x2
+ EPOLL_CTL_MOD = 0x3
+ ETH_P_1588 = 0x88f7
+ ETH_P_8021AD = 0x88a8
+ ETH_P_8021AH = 0x88e7
+ ETH_P_8021Q = 0x8100
+ ETH_P_80221 = 0x8917
+ ETH_P_802_2 = 0x4
+ ETH_P_802_3 = 0x1
+ ETH_P_802_3_MIN = 0x600
+ ETH_P_802_EX1 = 0x88b5
+ ETH_P_AARP = 0x80f3
+ ETH_P_AF_IUCV = 0xfbfb
+ ETH_P_ALL = 0x3
+ ETH_P_AOE = 0x88a2
+ ETH_P_ARCNET = 0x1a
+ ETH_P_ARP = 0x806
+ ETH_P_ATALK = 0x809b
+ ETH_P_ATMFATE = 0x8884
+ ETH_P_ATMMPOA = 0x884c
+ ETH_P_AX25 = 0x2
+ ETH_P_BATMAN = 0x4305
+ ETH_P_BPQ = 0x8ff
+ ETH_P_CAIF = 0xf7
+ ETH_P_CAN = 0xc
+ ETH_P_CANFD = 0xd
+ ETH_P_CONTROL = 0x16
+ ETH_P_CUST = 0x6006
+ ETH_P_DDCMP = 0x6
+ ETH_P_DEC = 0x6000
+ ETH_P_DIAG = 0x6005
+ ETH_P_DNA_DL = 0x6001
+ ETH_P_DNA_RC = 0x6002
+ ETH_P_DNA_RT = 0x6003
+ ETH_P_DSA = 0x1b
+ ETH_P_ECONET = 0x18
+ ETH_P_EDSA = 0xdada
+ ETH_P_FCOE = 0x8906
+ ETH_P_FIP = 0x8914
+ ETH_P_HDLC = 0x19
+ ETH_P_IEEE802154 = 0xf6
+ ETH_P_IEEEPUP = 0xa00
+ ETH_P_IEEEPUPAT = 0xa01
+ ETH_P_IP = 0x800
+ ETH_P_IPV6 = 0x86dd
+ ETH_P_IPX = 0x8137
+ ETH_P_IRDA = 0x17
+ ETH_P_LAT = 0x6004
+ ETH_P_LINK_CTL = 0x886c
+ ETH_P_LOCALTALK = 0x9
+ ETH_P_LOOP = 0x60
+ ETH_P_LOOPBACK = 0x9000
+ ETH_P_MOBITEX = 0x15
+ ETH_P_MPLS_MC = 0x8848
+ ETH_P_MPLS_UC = 0x8847
+ ETH_P_MVRP = 0x88f5
+ ETH_P_PAE = 0x888e
+ ETH_P_PAUSE = 0x8808
+ ETH_P_PHONET = 0xf5
+ ETH_P_PPPTALK = 0x10
+ ETH_P_PPP_DISC = 0x8863
+ ETH_P_PPP_MP = 0x8
+ ETH_P_PPP_SES = 0x8864
+ ETH_P_PRP = 0x88fb
+ ETH_P_PUP = 0x200
+ ETH_P_PUPAT = 0x201
+ ETH_P_QINQ1 = 0x9100
+ ETH_P_QINQ2 = 0x9200
+ ETH_P_QINQ3 = 0x9300
+ ETH_P_RARP = 0x8035
+ ETH_P_SCA = 0x6007
+ ETH_P_SLOW = 0x8809
+ ETH_P_SNAP = 0x5
+ ETH_P_TDLS = 0x890d
+ ETH_P_TEB = 0x6558
+ ETH_P_TIPC = 0x88ca
+ ETH_P_TRAILER = 0x1c
+ ETH_P_TR_802_2 = 0x11
+ ETH_P_WAN_PPP = 0x7
+ ETH_P_WCCP = 0x883e
+ ETH_P_X25 = 0x805
+ EXTA = 0xe
+ EXTB = 0xf
+ EXTPROC = 0x10000
+ FD_CLOEXEC = 0x1
+ FD_SETSIZE = 0x400
+ FLUSHO = 0x2000
+ F_DUPFD = 0x0
+ F_DUPFD_CLOEXEC = 0x406
+ F_EXLCK = 0x4
+ F_GETFD = 0x1
+ F_GETFL = 0x3
+ F_GETLEASE = 0x401
+ F_GETLK = 0x21
+ F_GETLK64 = 0x21
+ F_GETOWN = 0x17
+ F_GETOWN_EX = 0x10
+ F_GETPIPE_SZ = 0x408
+ F_GETSIG = 0xb
+ F_LOCK = 0x1
+ F_NOTIFY = 0x402
+ F_OK = 0x0
+ F_RDLCK = 0x0
+ F_SETFD = 0x2
+ F_SETFL = 0x4
+ F_SETLEASE = 0x400
+ F_SETLK = 0x22
+ F_SETLK64 = 0x22
+ F_SETLKW = 0x23
+ F_SETLKW64 = 0x23
+ F_SETOWN = 0x18
+ F_SETOWN_EX = 0xf
+ F_SETPIPE_SZ = 0x407
+ F_SETSIG = 0xa
+ F_SHLCK = 0x8
+ F_TEST = 0x3
+ F_TLOCK = 0x2
+ F_ULOCK = 0x0
+ F_UNLCK = 0x2
+ F_WRLCK = 0x1
+ HUPCL = 0x400
+ ICANON = 0x2
+ ICMPV6_FILTER = 0x1
+ ICRNL = 0x100
+ IEXTEN = 0x100
+ IFA_F_DADFAILED = 0x8
+ IFA_F_DEPRECATED = 0x20
+ IFA_F_HOMEADDRESS = 0x10
+ IFA_F_MANAGETEMPADDR = 0x100
+ IFA_F_NODAD = 0x2
+ IFA_F_NOPREFIXROUTE = 0x200
+ IFA_F_OPTIMISTIC = 0x4
+ IFA_F_PERMANENT = 0x80
+ IFA_F_SECONDARY = 0x1
+ IFA_F_TEMPORARY = 0x1
+ IFA_F_TENTATIVE = 0x40
+ IFA_MAX = 0x8
+ IFF_ALLMULTI = 0x200
+ IFF_ATTACH_QUEUE = 0x200
+ IFF_AUTOMEDIA = 0x4000
+ IFF_BROADCAST = 0x2
+ IFF_DEBUG = 0x4
+ IFF_DETACH_QUEUE = 0x400
+ IFF_DORMANT = 0x20000
+ IFF_DYNAMIC = 0x8000
+ IFF_ECHO = 0x40000
+ IFF_LOOPBACK = 0x8
+ IFF_LOWER_UP = 0x10000
+ IFF_MASTER = 0x400
+ IFF_MULTICAST = 0x1000
+ IFF_MULTI_QUEUE = 0x100
+ IFF_NOARP = 0x80
+ IFF_NOFILTER = 0x1000
+ IFF_NOTRAILERS = 0x20
+ IFF_NO_PI = 0x1000
+ IFF_ONE_QUEUE = 0x2000
+ IFF_PERSIST = 0x800
+ IFF_POINTOPOINT = 0x10
+ IFF_PORTSEL = 0x2000
+ IFF_PROMISC = 0x100
+ IFF_RUNNING = 0x40
+ IFF_SLAVE = 0x800
+ IFF_TAP = 0x2
+ IFF_TUN = 0x1
+ IFF_TUN_EXCL = 0x8000
+ IFF_UP = 0x1
+ IFF_VNET_HDR = 0x4000
+ IFF_VOLATILE = 0x70c5a
+ IFNAMSIZ = 0x10
+ IGNBRK = 0x1
+ IGNCR = 0x80
+ IGNPAR = 0x4
+ IMAXBEL = 0x2000
+ INLCR = 0x40
+ INPCK = 0x10
+ IN_ACCESS = 0x1
+ IN_ALL_EVENTS = 0xfff
+ IN_ATTRIB = 0x4
+ IN_CLASSA_HOST = 0xffffff
+ IN_CLASSA_MAX = 0x80
+ IN_CLASSA_NET = 0xff000000
+ IN_CLASSA_NSHIFT = 0x18
+ IN_CLASSB_HOST = 0xffff
+ IN_CLASSB_MAX = 0x10000
+ IN_CLASSB_NET = 0xffff0000
+ IN_CLASSB_NSHIFT = 0x10
+ IN_CLASSC_HOST = 0xff
+ IN_CLASSC_NET = 0xffffff00
+ IN_CLASSC_NSHIFT = 0x8
+ IN_CLOEXEC = 0x80000
+ IN_CLOSE = 0x18
+ IN_CLOSE_NOWRITE = 0x10
+ IN_CLOSE_WRITE = 0x8
+ IN_CREATE = 0x100
+ IN_DELETE = 0x200
+ IN_DELETE_SELF = 0x400
+ IN_DONT_FOLLOW = 0x2000000
+ IN_EXCL_UNLINK = 0x4000000
+ IN_IGNORED = 0x8000
+ IN_ISDIR = 0x40000000
+ IN_LOOPBACKNET = 0x7f
+ IN_MASK_ADD = 0x20000000
+ IN_MODIFY = 0x2
+ IN_MOVE = 0xc0
+ IN_MOVED_FROM = 0x40
+ IN_MOVED_TO = 0x80
+ IN_MOVE_SELF = 0x800
+ IN_NONBLOCK = 0x80
+ IN_ONESHOT = 0x80000000
+ IN_ONLYDIR = 0x1000000
+ IN_OPEN = 0x20
+ IN_Q_OVERFLOW = 0x4000
+ IN_UNMOUNT = 0x2000
+ IPPROTO_AH = 0x33
+ IPPROTO_BEETPH = 0x5e
+ IPPROTO_COMP = 0x6c
+ IPPROTO_DCCP = 0x21
+ IPPROTO_DSTOPTS = 0x3c
+ IPPROTO_EGP = 0x8
+ IPPROTO_ENCAP = 0x62
+ IPPROTO_ESP = 0x32
+ IPPROTO_FRAGMENT = 0x2c
+ IPPROTO_GRE = 0x2f
+ IPPROTO_HOPOPTS = 0x0
+ IPPROTO_ICMP = 0x1
+ IPPROTO_ICMPV6 = 0x3a
+ IPPROTO_IDP = 0x16
+ IPPROTO_IGMP = 0x2
+ IPPROTO_IP = 0x0
+ IPPROTO_IPIP = 0x4
+ IPPROTO_IPV6 = 0x29
+ IPPROTO_MH = 0x87
+ IPPROTO_MTP = 0x5c
+ IPPROTO_NONE = 0x3b
+ IPPROTO_PIM = 0x67
+ IPPROTO_PUP = 0xc
+ IPPROTO_RAW = 0xff
+ IPPROTO_ROUTING = 0x2b
+ IPPROTO_RSVP = 0x2e
+ IPPROTO_SCTP = 0x84
+ IPPROTO_TCP = 0x6
+ IPPROTO_TP = 0x1d
+ IPPROTO_UDP = 0x11
+ IPPROTO_UDPLITE = 0x88
+ IPV6_2292DSTOPTS = 0x4
+ IPV6_2292HOPLIMIT = 0x8
+ IPV6_2292HOPOPTS = 0x3
+ IPV6_2292PKTINFO = 0x2
+ IPV6_2292PKTOPTIONS = 0x6
+ IPV6_2292RTHDR = 0x5
+ IPV6_ADDRFORM = 0x1
+ IPV6_ADD_MEMBERSHIP = 0x14
+ IPV6_AUTHHDR = 0xa
+ IPV6_CHECKSUM = 0x7
+ IPV6_DROP_MEMBERSHIP = 0x15
+ IPV6_DSTOPTS = 0x3b
+ IPV6_HOPLIMIT = 0x34
+ IPV6_HOPOPTS = 0x36
+ IPV6_IPSEC_POLICY = 0x22
+ IPV6_JOIN_ANYCAST = 0x1b
+ IPV6_JOIN_GROUP = 0x14
+ IPV6_LEAVE_ANYCAST = 0x1c
+ IPV6_LEAVE_GROUP = 0x15
+ IPV6_MTU = 0x18
+ IPV6_MTU_DISCOVER = 0x17
+ IPV6_MULTICAST_HOPS = 0x12
+ IPV6_MULTICAST_IF = 0x11
+ IPV6_MULTICAST_LOOP = 0x13
+ IPV6_NEXTHOP = 0x9
+ IPV6_PKTINFO = 0x32
+ IPV6_PMTUDISC_DO = 0x2
+ IPV6_PMTUDISC_DONT = 0x0
+ IPV6_PMTUDISC_PROBE = 0x3
+ IPV6_PMTUDISC_WANT = 0x1
+ IPV6_RECVDSTOPTS = 0x3a
+ IPV6_RECVERR = 0x19
+ IPV6_RECVHOPLIMIT = 0x33
+ IPV6_RECVHOPOPTS = 0x35
+ IPV6_RECVPKTINFO = 0x31
+ IPV6_RECVRTHDR = 0x38
+ IPV6_RECVTCLASS = 0x42
+ IPV6_ROUTER_ALERT = 0x16
+ IPV6_RTHDR = 0x39
+ IPV6_RTHDRDSTOPTS = 0x37
+ IPV6_RTHDR_LOOSE = 0x0
+ IPV6_RTHDR_STRICT = 0x1
+ IPV6_RTHDR_TYPE_0 = 0x0
+ IPV6_RXDSTOPTS = 0x3b
+ IPV6_RXHOPOPTS = 0x36
+ IPV6_TCLASS = 0x43
+ IPV6_UNICAST_HOPS = 0x10
+ IPV6_V6ONLY = 0x1a
+ IPV6_XFRM_POLICY = 0x23
+ IP_ADD_MEMBERSHIP = 0x23
+ IP_ADD_SOURCE_MEMBERSHIP = 0x27
+ IP_BLOCK_SOURCE = 0x26
+ IP_DEFAULT_MULTICAST_LOOP = 0x1
+ IP_DEFAULT_MULTICAST_TTL = 0x1
+ IP_DF = 0x4000
+ IP_DROP_MEMBERSHIP = 0x24
+ IP_DROP_SOURCE_MEMBERSHIP = 0x28
+ IP_FREEBIND = 0xf
+ IP_HDRINCL = 0x3
+ IP_IPSEC_POLICY = 0x10
+ IP_MAXPACKET = 0xffff
+ IP_MAX_MEMBERSHIPS = 0x14
+ IP_MF = 0x2000
+ IP_MINTTL = 0x15
+ IP_MSFILTER = 0x29
+ IP_MSS = 0x240
+ IP_MTU = 0xe
+ IP_MTU_DISCOVER = 0xa
+ IP_MULTICAST_ALL = 0x31
+ IP_MULTICAST_IF = 0x20
+ IP_MULTICAST_LOOP = 0x22
+ IP_MULTICAST_TTL = 0x21
+ IP_OFFMASK = 0x1fff
+ IP_OPTIONS = 0x4
+ IP_ORIGDSTADDR = 0x14
+ IP_PASSSEC = 0x12
+ IP_PKTINFO = 0x8
+ IP_PKTOPTIONS = 0x9
+ IP_PMTUDISC = 0xa
+ IP_PMTUDISC_DO = 0x2
+ IP_PMTUDISC_DONT = 0x0
+ IP_PMTUDISC_PROBE = 0x3
+ IP_PMTUDISC_WANT = 0x1
+ IP_RECVERR = 0xb
+ IP_RECVOPTS = 0x6
+ IP_RECVORIGDSTADDR = 0x14
+ IP_RECVRETOPTS = 0x7
+ IP_RECVTOS = 0xd
+ IP_RECVTTL = 0xc
+ IP_RETOPTS = 0x7
+ IP_RF = 0x8000
+ IP_ROUTER_ALERT = 0x5
+ IP_TOS = 0x1
+ IP_TRANSPARENT = 0x13
+ IP_TTL = 0x2
+ IP_UNBLOCK_SOURCE = 0x25
+ IP_UNICAST_IF = 0x32
+ IP_XFRM_POLICY = 0x11
+ ISIG = 0x1
+ ISTRIP = 0x20
+ IUTF8 = 0x4000
+ IXANY = 0x800
+ IXOFF = 0x1000
+ IXON = 0x400
+ LINUX_REBOOT_CMD_CAD_OFF = 0x0
+ LINUX_REBOOT_CMD_CAD_ON = 0x89abcdef
+ LINUX_REBOOT_CMD_HALT = 0xcdef0123
+ LINUX_REBOOT_CMD_KEXEC = 0x45584543
+ LINUX_REBOOT_CMD_POWER_OFF = 0x4321fedc
+ LINUX_REBOOT_CMD_RESTART = 0x1234567
+ LINUX_REBOOT_CMD_RESTART2 = 0xa1b2c3d4
+ LINUX_REBOOT_CMD_SW_SUSPEND = 0xd000fce2
+ LINUX_REBOOT_MAGIC1 = 0xfee1dead
+ LINUX_REBOOT_MAGIC2 = 0x28121969
+ LOCK_EX = 0x2
+ LOCK_NB = 0x4
+ LOCK_SH = 0x1
+ LOCK_UN = 0x8
+ MADV_DODUMP = 0x11
+ MADV_DOFORK = 0xb
+ MADV_DONTDUMP = 0x10
+ MADV_DONTFORK = 0xa
+ MADV_DONTNEED = 0x4
+ MADV_HUGEPAGE = 0xe
+ MADV_HWPOISON = 0x64
+ MADV_MERGEABLE = 0xc
+ MADV_NOHUGEPAGE = 0xf
+ MADV_NORMAL = 0x0
+ MADV_RANDOM = 0x1
+ MADV_REMOVE = 0x9
+ MADV_SEQUENTIAL = 0x2
+ MADV_UNMERGEABLE = 0xd
+ MADV_WILLNEED = 0x3
+ MAP_ANON = 0x800
+ MAP_ANONYMOUS = 0x800
+ MAP_DENYWRITE = 0x2000
+ MAP_EXECUTABLE = 0x4000
+ MAP_FILE = 0x0
+ MAP_FIXED = 0x10
+ MAP_GROWSDOWN = 0x1000
+ MAP_HUGETLB = 0x80000
+ MAP_HUGE_MASK = 0x3f
+ MAP_HUGE_SHIFT = 0x1a
+ MAP_LOCKED = 0x8000
+ MAP_NONBLOCK = 0x20000
+ MAP_NORESERVE = 0x400
+ MAP_POPULATE = 0x10000
+ MAP_PRIVATE = 0x2
+ MAP_RENAME = 0x800
+ MAP_SHARED = 0x1
+ MAP_STACK = 0x40000
+ MAP_TYPE = 0xf
+ MCL_CURRENT = 0x1
+ MCL_FUTURE = 0x2
+ MNT_DETACH = 0x2
+ MNT_EXPIRE = 0x4
+ MNT_FORCE = 0x1
+ MSG_CMSG_CLOEXEC = 0x40000000
+ MSG_CONFIRM = 0x800
+ MSG_CTRUNC = 0x8
+ MSG_DONTROUTE = 0x4
+ MSG_DONTWAIT = 0x40
+ MSG_EOR = 0x80
+ MSG_ERRQUEUE = 0x2000
+ MSG_FASTOPEN = 0x20000000
+ MSG_FIN = 0x200
+ MSG_MORE = 0x8000
+ MSG_NOSIGNAL = 0x4000
+ MSG_OOB = 0x1
+ MSG_PEEK = 0x2
+ MSG_PROXY = 0x10
+ MSG_RST = 0x1000
+ MSG_SYN = 0x400
+ MSG_TRUNC = 0x20
+ MSG_TRYHARD = 0x4
+ MSG_WAITALL = 0x100
+ MSG_WAITFORONE = 0x10000
+ MS_ACTIVE = 0x40000000
+ MS_ASYNC = 0x1
+ MS_BIND = 0x1000
+ MS_DIRSYNC = 0x80
+ MS_INVALIDATE = 0x2
+ MS_I_VERSION = 0x800000
+ MS_KERNMOUNT = 0x400000
+ MS_MANDLOCK = 0x40
+ MS_MGC_MSK = 0xffff0000
+ MS_MGC_VAL = 0xc0ed0000
+ MS_MOVE = 0x2000
+ MS_NOATIME = 0x400
+ MS_NODEV = 0x4
+ MS_NODIRATIME = 0x800
+ MS_NOEXEC = 0x8
+ MS_NOSUID = 0x2
+ MS_NOUSER = -0x80000000
+ MS_POSIXACL = 0x10000
+ MS_PRIVATE = 0x40000
+ MS_RDONLY = 0x1
+ MS_REC = 0x4000
+ MS_RELATIME = 0x200000
+ MS_REMOUNT = 0x20
+ MS_RMT_MASK = 0x800051
+ MS_SHARED = 0x100000
+ MS_SILENT = 0x8000
+ MS_SLAVE = 0x80000
+ MS_STRICTATIME = 0x1000000
+ MS_SYNC = 0x4
+ MS_SYNCHRONOUS = 0x10
+ MS_UNBINDABLE = 0x20000
+ NAME_MAX = 0xff
+ NETLINK_ADD_MEMBERSHIP = 0x1
+ NETLINK_AUDIT = 0x9
+ NETLINK_BROADCAST_ERROR = 0x4
+ NETLINK_CONNECTOR = 0xb
+ NETLINK_CRYPTO = 0x15
+ NETLINK_DNRTMSG = 0xe
+ NETLINK_DROP_MEMBERSHIP = 0x2
+ NETLINK_ECRYPTFS = 0x13
+ NETLINK_FIB_LOOKUP = 0xa
+ NETLINK_FIREWALL = 0x3
+ NETLINK_GENERIC = 0x10
+ NETLINK_INET_DIAG = 0x4
+ NETLINK_IP6_FW = 0xd
+ NETLINK_ISCSI = 0x8
+ NETLINK_KOBJECT_UEVENT = 0xf
+ NETLINK_NETFILTER = 0xc
+ NETLINK_NFLOG = 0x5
+ NETLINK_NO_ENOBUFS = 0x5
+ NETLINK_PKTINFO = 0x3
+ NETLINK_RDMA = 0x14
+ NETLINK_ROUTE = 0x0
+ NETLINK_RX_RING = 0x6
+ NETLINK_SCSITRANSPORT = 0x12
+ NETLINK_SELINUX = 0x7
+ NETLINK_SOCK_DIAG = 0x4
+ NETLINK_TX_RING = 0x7
+ NETLINK_UNUSED = 0x1
+ NETLINK_USERSOCK = 0x2
+ NETLINK_XFRM = 0x6
+ NLA_ALIGNTO = 0x4
+ NLA_F_NESTED = 0x8000
+ NLA_F_NET_BYTEORDER = 0x4000
+ NLA_HDRLEN = 0x4
+ NLMSG_ALIGNTO = 0x4
+ NLMSG_DONE = 0x3
+ NLMSG_ERROR = 0x2
+ NLMSG_HDRLEN = 0x10
+ NLMSG_MIN_TYPE = 0x10
+ NLMSG_NOOP = 0x1
+ NLMSG_OVERRUN = 0x4
+ NLM_F_ACK = 0x4
+ NLM_F_APPEND = 0x800
+ NLM_F_ATOMIC = 0x400
+ NLM_F_CREATE = 0x400
+ NLM_F_DUMP = 0x300
+ NLM_F_DUMP_INTR = 0x10
+ NLM_F_ECHO = 0x8
+ NLM_F_EXCL = 0x200
+ NLM_F_MATCH = 0x200
+ NLM_F_MULTI = 0x2
+ NLM_F_REPLACE = 0x100
+ NLM_F_REQUEST = 0x1
+ NLM_F_ROOT = 0x100
+ NOFLSH = 0x80
+ OCRNL = 0x8
+ OFDEL = 0x80
+ OFILL = 0x40
+ ONLCR = 0x4
+ ONLRET = 0x20
+ ONOCR = 0x10
+ OPOST = 0x1
+ O_ACCMODE = 0x3
+ O_APPEND = 0x8
+ O_ASYNC = 0x1000
+ O_CLOEXEC = 0x80000
+ O_CREAT = 0x100
+ O_DIRECT = 0x8000
+ O_DIRECTORY = 0x10000
+ O_DSYNC = 0x10
+ O_EXCL = 0x400
+ O_FSYNC = 0x4010
+ O_LARGEFILE = 0x2000
+ O_NDELAY = 0x80
+ O_NOATIME = 0x40000
+ O_NOCTTY = 0x800
+ O_NOFOLLOW = 0x20000
+ O_NONBLOCK = 0x80
+ O_PATH = 0x200000
+ O_RDONLY = 0x0
+ O_RDWR = 0x2
+ O_RSYNC = 0x4010
+ O_SYNC = 0x4010
+ O_TMPFILE = 0x410000
+ O_TRUNC = 0x200
+ O_WRONLY = 0x1
+ PACKET_ADD_MEMBERSHIP = 0x1
+ PACKET_AUXDATA = 0x8
+ PACKET_BROADCAST = 0x1
+ PACKET_COPY_THRESH = 0x7
+ PACKET_DROP_MEMBERSHIP = 0x2
+ PACKET_FANOUT = 0x12
+ PACKET_FANOUT_CPU = 0x2
+ PACKET_FANOUT_FLAG_DEFRAG = 0x8000
+ PACKET_FANOUT_FLAG_ROLLOVER = 0x1000
+ PACKET_FANOUT_HASH = 0x0
+ PACKET_FANOUT_LB = 0x1
+ PACKET_FANOUT_QM = 0x5
+ PACKET_FANOUT_RND = 0x4
+ PACKET_FANOUT_ROLLOVER = 0x3
+ PACKET_FASTROUTE = 0x6
+ PACKET_HDRLEN = 0xb
+ PACKET_HOST = 0x0
+ PACKET_KERNEL = 0x7
+ PACKET_LOOPBACK = 0x5
+ PACKET_LOSS = 0xe
+ PACKET_MR_ALLMULTI = 0x2
+ PACKET_MR_MULTICAST = 0x0
+ PACKET_MR_PROMISC = 0x1
+ PACKET_MR_UNICAST = 0x3
+ PACKET_MULTICAST = 0x2
+ PACKET_ORIGDEV = 0x9
+ PACKET_OTHERHOST = 0x3
+ PACKET_OUTGOING = 0x4
+ PACKET_QDISC_BYPASS = 0x14
+ PACKET_RECV_OUTPUT = 0x3
+ PACKET_RESERVE = 0xc
+ PACKET_RX_RING = 0x5
+ PACKET_STATISTICS = 0x6
+ PACKET_TIMESTAMP = 0x11
+ PACKET_TX_HAS_OFF = 0x13
+ PACKET_TX_RING = 0xd
+ PACKET_TX_TIMESTAMP = 0x10
+ PACKET_USER = 0x6
+ PACKET_VERSION = 0xa
+ PACKET_VNET_HDR = 0xf
+ PARENB = 0x100
+ PARITY_CRC16_PR0 = 0x2
+ PARITY_CRC16_PR0_CCITT = 0x4
+ PARITY_CRC16_PR1 = 0x3
+ PARITY_CRC16_PR1_CCITT = 0x5
+ PARITY_CRC32_PR0_CCITT = 0x6
+ PARITY_CRC32_PR1_CCITT = 0x7
+ PARITY_DEFAULT = 0x0
+ PARITY_NONE = 0x1
+ PARMRK = 0x8
+ PARODD = 0x200
+ PENDIN = 0x4000
+ PRIO_PGRP = 0x1
+ PRIO_PROCESS = 0x0
+ PRIO_USER = 0x2
+ PROT_EXEC = 0x4
+ PROT_GROWSDOWN = 0x1000000
+ PROT_GROWSUP = 0x2000000
+ PROT_NONE = 0x0
+ PROT_READ = 0x1
+ PROT_WRITE = 0x2
+ PR_CAPBSET_DROP = 0x18
+ PR_CAPBSET_READ = 0x17
+ PR_ENDIAN_BIG = 0x0
+ PR_ENDIAN_LITTLE = 0x1
+ PR_ENDIAN_PPC_LITTLE = 0x2
+ PR_FPEMU_NOPRINT = 0x1
+ PR_FPEMU_SIGFPE = 0x2
+ PR_FP_EXC_ASYNC = 0x2
+ PR_FP_EXC_DISABLED = 0x0
+ PR_FP_EXC_DIV = 0x10000
+ PR_FP_EXC_INV = 0x100000
+ PR_FP_EXC_NONRECOV = 0x1
+ PR_FP_EXC_OVF = 0x20000
+ PR_FP_EXC_PRECISE = 0x3
+ PR_FP_EXC_RES = 0x80000
+ PR_FP_EXC_SW_ENABLE = 0x80
+ PR_FP_EXC_UND = 0x40000
+ PR_GET_CHILD_SUBREAPER = 0x25
+ PR_GET_DUMPABLE = 0x3
+ PR_GET_ENDIAN = 0x13
+ PR_GET_FPEMU = 0x9
+ PR_GET_FPEXC = 0xb
+ PR_GET_KEEPCAPS = 0x7
+ PR_GET_NAME = 0x10
+ PR_GET_NO_NEW_PRIVS = 0x27
+ PR_GET_PDEATHSIG = 0x2
+ PR_GET_SECCOMP = 0x15
+ PR_GET_SECUREBITS = 0x1b
+ PR_GET_THP_DISABLE = 0x2a
+ PR_GET_TID_ADDRESS = 0x28
+ PR_GET_TIMERSLACK = 0x1e
+ PR_GET_TIMING = 0xd
+ PR_GET_TSC = 0x19
+ PR_GET_UNALIGN = 0x5
+ PR_MCE_KILL = 0x21
+ PR_MCE_KILL_CLEAR = 0x0
+ PR_MCE_KILL_DEFAULT = 0x2
+ PR_MCE_KILL_EARLY = 0x1
+ PR_MCE_KILL_GET = 0x22
+ PR_MCE_KILL_LATE = 0x0
+ PR_MCE_KILL_SET = 0x1
+ PR_SET_CHILD_SUBREAPER = 0x24
+ PR_SET_DUMPABLE = 0x4
+ PR_SET_ENDIAN = 0x14
+ PR_SET_FPEMU = 0xa
+ PR_SET_FPEXC = 0xc
+ PR_SET_KEEPCAPS = 0x8
+ PR_SET_MM = 0x23
+ PR_SET_MM_ARG_END = 0x9
+ PR_SET_MM_ARG_START = 0x8
+ PR_SET_MM_AUXV = 0xc
+ PR_SET_MM_BRK = 0x7
+ PR_SET_MM_END_CODE = 0x2
+ PR_SET_MM_END_DATA = 0x4
+ PR_SET_MM_ENV_END = 0xb
+ PR_SET_MM_ENV_START = 0xa
+ PR_SET_MM_EXE_FILE = 0xd
+ PR_SET_MM_START_BRK = 0x6
+ PR_SET_MM_START_CODE = 0x1
+ PR_SET_MM_START_DATA = 0x3
+ PR_SET_MM_START_STACK = 0x5
+ PR_SET_NAME = 0xf
+ PR_SET_NO_NEW_PRIVS = 0x26
+ PR_SET_PDEATHSIG = 0x1
+ PR_SET_PTRACER = 0x59616d61
+ PR_SET_PTRACER_ANY = 0xffffffff
+ PR_SET_SECCOMP = 0x16
+ PR_SET_SECUREBITS = 0x1c
+ PR_SET_THP_DISABLE = 0x29
+ PR_SET_TIMERSLACK = 0x1d
+ PR_SET_TIMING = 0xe
+ PR_SET_TSC = 0x1a
+ PR_SET_UNALIGN = 0x6
+ PR_TASK_PERF_EVENTS_DISABLE = 0x1f
+ PR_TASK_PERF_EVENTS_ENABLE = 0x20
+ PR_TIMING_STATISTICAL = 0x0
+ PR_TIMING_TIMESTAMP = 0x1
+ PR_TSC_ENABLE = 0x1
+ PR_TSC_SIGSEGV = 0x2
+ PR_UNALIGN_NOPRINT = 0x1
+ PR_UNALIGN_SIGBUS = 0x2
+ PTRACE_ATTACH = 0x10
+ PTRACE_CONT = 0x7
+ PTRACE_DETACH = 0x11
+ PTRACE_EVENT_CLONE = 0x3
+ PTRACE_EVENT_EXEC = 0x4
+ PTRACE_EVENT_EXIT = 0x6
+ PTRACE_EVENT_FORK = 0x1
+ PTRACE_EVENT_SECCOMP = 0x7
+ PTRACE_EVENT_STOP = 0x80
+ PTRACE_EVENT_VFORK = 0x2
+ PTRACE_EVENT_VFORK_DONE = 0x5
+ PTRACE_GETEVENTMSG = 0x4201
+ PTRACE_GETFPREGS = 0xe
+ PTRACE_GETREGS = 0xc
+ PTRACE_GETREGSET = 0x4204
+ PTRACE_GETSIGINFO = 0x4202
+ PTRACE_GETSIGMASK = 0x420a
+ PTRACE_GET_THREAD_AREA = 0x19
+ PTRACE_GET_THREAD_AREA_3264 = 0xc4
+ PTRACE_GET_WATCH_REGS = 0xd0
+ PTRACE_INTERRUPT = 0x4207
+ PTRACE_KILL = 0x8
+ PTRACE_LISTEN = 0x4208
+ PTRACE_OLDSETOPTIONS = 0x15
+ PTRACE_O_EXITKILL = 0x100000
+ PTRACE_O_MASK = 0x1000ff
+ PTRACE_O_TRACECLONE = 0x8
+ PTRACE_O_TRACEEXEC = 0x10
+ PTRACE_O_TRACEEXIT = 0x40
+ PTRACE_O_TRACEFORK = 0x2
+ PTRACE_O_TRACESECCOMP = 0x80
+ PTRACE_O_TRACESYSGOOD = 0x1
+ PTRACE_O_TRACEVFORK = 0x4
+ PTRACE_O_TRACEVFORKDONE = 0x20
+ PTRACE_PEEKDATA = 0x2
+ PTRACE_PEEKDATA_3264 = 0xc1
+ PTRACE_PEEKSIGINFO = 0x4209
+ PTRACE_PEEKSIGINFO_SHARED = 0x1
+ PTRACE_PEEKTEXT = 0x1
+ PTRACE_PEEKTEXT_3264 = 0xc0
+ PTRACE_PEEKUSR = 0x3
+ PTRACE_POKEDATA = 0x5
+ PTRACE_POKEDATA_3264 = 0xc3
+ PTRACE_POKETEXT = 0x4
+ PTRACE_POKETEXT_3264 = 0xc2
+ PTRACE_POKEUSR = 0x6
+ PTRACE_SEIZE = 0x4206
+ PTRACE_SETFPREGS = 0xf
+ PTRACE_SETOPTIONS = 0x4200
+ PTRACE_SETREGS = 0xd
+ PTRACE_SETREGSET = 0x4205
+ PTRACE_SETSIGINFO = 0x4203
+ PTRACE_SETSIGMASK = 0x420b
+ PTRACE_SET_THREAD_AREA = 0x1a
+ PTRACE_SET_WATCH_REGS = 0xd1
+ PTRACE_SINGLESTEP = 0x9
+ PTRACE_SYSCALL = 0x18
+ PTRACE_TRACEME = 0x0
+ RLIMIT_AS = 0x6
+ RLIMIT_CORE = 0x4
+ RLIMIT_CPU = 0x0
+ RLIMIT_DATA = 0x2
+ RLIMIT_FSIZE = 0x1
+ RLIMIT_NOFILE = 0x5
+ RLIMIT_STACK = 0x3
+ RLIM_INFINITY = -0x1
+ RTAX_ADVMSS = 0x8
+ RTAX_CWND = 0x7
+ RTAX_FEATURES = 0xc
+ RTAX_FEATURE_ALLFRAG = 0x8
+ RTAX_FEATURE_ECN = 0x1
+ RTAX_FEATURE_SACK = 0x2
+ RTAX_FEATURE_TIMESTAMP = 0x4
+ RTAX_HOPLIMIT = 0xa
+ RTAX_INITCWND = 0xb
+ RTAX_INITRWND = 0xe
+ RTAX_LOCK = 0x1
+ RTAX_MAX = 0xf
+ RTAX_MTU = 0x2
+ RTAX_QUICKACK = 0xf
+ RTAX_REORDERING = 0x9
+ RTAX_RTO_MIN = 0xd
+ RTAX_RTT = 0x4
+ RTAX_RTTVAR = 0x5
+ RTAX_SSTHRESH = 0x6
+ RTAX_UNSPEC = 0x0
+ RTAX_WINDOW = 0x3
+ RTA_ALIGNTO = 0x4
+ RTA_MAX = 0x11
+ RTCF_DIRECTSRC = 0x4000000
+ RTCF_DOREDIRECT = 0x1000000
+ RTCF_LOG = 0x2000000
+ RTCF_MASQ = 0x400000
+ RTCF_NAT = 0x800000
+ RTCF_VALVE = 0x200000
+ RTF_ADDRCLASSMASK = 0xf8000000
+ RTF_ADDRCONF = 0x40000
+ RTF_ALLONLINK = 0x20000
+ RTF_BROADCAST = 0x10000000
+ RTF_CACHE = 0x1000000
+ RTF_DEFAULT = 0x10000
+ RTF_DYNAMIC = 0x10
+ RTF_FLOW = 0x2000000
+ RTF_GATEWAY = 0x2
+ RTF_HOST = 0x4
+ RTF_INTERFACE = 0x40000000
+ RTF_IRTT = 0x100
+ RTF_LINKRT = 0x100000
+ RTF_LOCAL = 0x80000000
+ RTF_MODIFIED = 0x20
+ RTF_MSS = 0x40
+ RTF_MTU = 0x40
+ RTF_MULTICAST = 0x20000000
+ RTF_NAT = 0x8000000
+ RTF_NOFORWARD = 0x1000
+ RTF_NONEXTHOP = 0x200000
+ RTF_NOPMTUDISC = 0x4000
+ RTF_POLICY = 0x4000000
+ RTF_REINSTATE = 0x8
+ RTF_REJECT = 0x200
+ RTF_STATIC = 0x400
+ RTF_THROW = 0x2000
+ RTF_UP = 0x1
+ RTF_WINDOW = 0x80
+ RTF_XRESOLVE = 0x800
+ RTM_BASE = 0x10
+ RTM_DELACTION = 0x31
+ RTM_DELADDR = 0x15
+ RTM_DELADDRLABEL = 0x49
+ RTM_DELLINK = 0x11
+ RTM_DELMDB = 0x55
+ RTM_DELNEIGH = 0x1d
+ RTM_DELQDISC = 0x25
+ RTM_DELROUTE = 0x19
+ RTM_DELRULE = 0x21
+ RTM_DELTCLASS = 0x29
+ RTM_DELTFILTER = 0x2d
+ RTM_F_CLONED = 0x200
+ RTM_F_EQUALIZE = 0x400
+ RTM_F_NOTIFY = 0x100
+ RTM_F_PREFIX = 0x800
+ RTM_GETACTION = 0x32
+ RTM_GETADDR = 0x16
+ RTM_GETADDRLABEL = 0x4a
+ RTM_GETANYCAST = 0x3e
+ RTM_GETDCB = 0x4e
+ RTM_GETLINK = 0x12
+ RTM_GETMDB = 0x56
+ RTM_GETMULTICAST = 0x3a
+ RTM_GETNEIGH = 0x1e
+ RTM_GETNEIGHTBL = 0x42
+ RTM_GETNETCONF = 0x52
+ RTM_GETQDISC = 0x26
+ RTM_GETROUTE = 0x1a
+ RTM_GETRULE = 0x22
+ RTM_GETTCLASS = 0x2a
+ RTM_GETTFILTER = 0x2e
+ RTM_MAX = 0x57
+ RTM_NEWACTION = 0x30
+ RTM_NEWADDR = 0x14
+ RTM_NEWADDRLABEL = 0x48
+ RTM_NEWLINK = 0x10
+ RTM_NEWMDB = 0x54
+ RTM_NEWNDUSEROPT = 0x44
+ RTM_NEWNEIGH = 0x1c
+ RTM_NEWNEIGHTBL = 0x40
+ RTM_NEWNETCONF = 0x50
+ RTM_NEWPREFIX = 0x34
+ RTM_NEWQDISC = 0x24
+ RTM_NEWROUTE = 0x18
+ RTM_NEWRULE = 0x20
+ RTM_NEWTCLASS = 0x28
+ RTM_NEWTFILTER = 0x2c
+ RTM_NR_FAMILIES = 0x12
+ RTM_NR_MSGTYPES = 0x48
+ RTM_SETDCB = 0x4f
+ RTM_SETLINK = 0x13
+ RTM_SETNEIGHTBL = 0x43
+ RTNH_ALIGNTO = 0x4
+ RTNH_F_DEAD = 0x1
+ RTNH_F_ONLINK = 0x4
+ RTNH_F_PERVASIVE = 0x2
+ RTN_MAX = 0xb
+ RTPROT_BIRD = 0xc
+ RTPROT_BOOT = 0x3
+ RTPROT_DHCP = 0x10
+ RTPROT_DNROUTED = 0xd
+ RTPROT_GATED = 0x8
+ RTPROT_KERNEL = 0x2
+ RTPROT_MROUTED = 0x11
+ RTPROT_MRT = 0xa
+ RTPROT_NTK = 0xf
+ RTPROT_RA = 0x9
+ RTPROT_REDIRECT = 0x1
+ RTPROT_STATIC = 0x4
+ RTPROT_UNSPEC = 0x0
+ RTPROT_XORP = 0xe
+ RTPROT_ZEBRA = 0xb
+ RT_CLASS_DEFAULT = 0xfd
+ RT_CLASS_LOCAL = 0xff
+ RT_CLASS_MAIN = 0xfe
+ RT_CLASS_MAX = 0xff
+ RT_CLASS_UNSPEC = 0x0
+ RUSAGE_CHILDREN = -0x1
+ RUSAGE_SELF = 0x0
+ RUSAGE_THREAD = 0x1
+ SCM_CREDENTIALS = 0x2
+ SCM_RIGHTS = 0x1
+ SCM_TIMESTAMP = 0x1d
+ SCM_TIMESTAMPING = 0x25
+ SCM_TIMESTAMPNS = 0x23
+ SCM_WIFI_STATUS = 0x29
+ SHUT_RD = 0x0
+ SHUT_RDWR = 0x2
+ SHUT_WR = 0x1
+ SIOCADDDLCI = 0x8980
+ SIOCADDMULTI = 0x8931
+ SIOCADDRT = 0x890b
+ SIOCATMARK = 0x40047307
+ SIOCDARP = 0x8953
+ SIOCDELDLCI = 0x8981
+ SIOCDELMULTI = 0x8932
+ SIOCDELRT = 0x890c
+ SIOCDEVPRIVATE = 0x89f0
+ SIOCDIFADDR = 0x8936
+ SIOCDRARP = 0x8960
+ SIOCGARP = 0x8954
+ SIOCGIFADDR = 0x8915
+ SIOCGIFBR = 0x8940
+ SIOCGIFBRDADDR = 0x8919
+ SIOCGIFCONF = 0x8912
+ SIOCGIFCOUNT = 0x8938
+ SIOCGIFDSTADDR = 0x8917
+ SIOCGIFENCAP = 0x8925
+ SIOCGIFFLAGS = 0x8913
+ SIOCGIFHWADDR = 0x8927
+ SIOCGIFINDEX = 0x8933
+ SIOCGIFMAP = 0x8970
+ SIOCGIFMEM = 0x891f
+ SIOCGIFMETRIC = 0x891d
+ SIOCGIFMTU = 0x8921
+ SIOCGIFNAME = 0x8910
+ SIOCGIFNETMASK = 0x891b
+ SIOCGIFPFLAGS = 0x8935
+ SIOCGIFSLAVE = 0x8929
+ SIOCGIFTXQLEN = 0x8942
+ SIOCGPGRP = 0x40047309
+ SIOCGRARP = 0x8961
+ SIOCGSTAMP = 0x8906
+ SIOCGSTAMPNS = 0x8907
+ SIOCPROTOPRIVATE = 0x89e0
+ SIOCRTMSG = 0x890d
+ SIOCSARP = 0x8955
+ SIOCSIFADDR = 0x8916
+ SIOCSIFBR = 0x8941
+ SIOCSIFBRDADDR = 0x891a
+ SIOCSIFDSTADDR = 0x8918
+ SIOCSIFENCAP = 0x8926
+ SIOCSIFFLAGS = 0x8914
+ SIOCSIFHWADDR = 0x8924
+ SIOCSIFHWBROADCAST = 0x8937
+ SIOCSIFLINK = 0x8911
+ SIOCSIFMAP = 0x8971
+ SIOCSIFMEM = 0x8920
+ SIOCSIFMETRIC = 0x891e
+ SIOCSIFMTU = 0x8922
+ SIOCSIFNAME = 0x8923
+ SIOCSIFNETMASK = 0x891c
+ SIOCSIFPFLAGS = 0x8934
+ SIOCSIFSLAVE = 0x8930
+ SIOCSIFTXQLEN = 0x8943
+ SIOCSPGRP = 0x80047308
+ SIOCSRARP = 0x8962
+ SOCK_CLOEXEC = 0x80000
+ SOCK_DCCP = 0x6
+ SOCK_DGRAM = 0x1
+ SOCK_NONBLOCK = 0x80
+ SOCK_PACKET = 0xa
+ SOCK_RAW = 0x3
+ SOCK_RDM = 0x4
+ SOCK_SEQPACKET = 0x5
+ SOCK_STREAM = 0x2
+ SOL_AAL = 0x109
+ SOL_ATM = 0x108
+ SOL_DECNET = 0x105
+ SOL_ICMPV6 = 0x3a
+ SOL_IP = 0x0
+ SOL_IPV6 = 0x29
+ SOL_IRDA = 0x10a
+ SOL_PACKET = 0x107
+ SOL_RAW = 0xff
+ SOL_SOCKET = 0xffff
+ SOL_TCP = 0x6
+ SOL_X25 = 0x106
+ SOMAXCONN = 0x80
+ SO_ACCEPTCONN = 0x1009
+ SO_ATTACH_FILTER = 0x1a
+ SO_BINDTODEVICE = 0x19
+ SO_BPF_EXTENSIONS = 0x30
+ SO_BROADCAST = 0x20
+ SO_BSDCOMPAT = 0xe
+ SO_BUSY_POLL = 0x2e
+ SO_DEBUG = 0x1
+ SO_DETACH_FILTER = 0x1b
+ SO_DOMAIN = 0x1029
+ SO_DONTROUTE = 0x10
+ SO_ERROR = 0x1007
+ SO_GET_FILTER = 0x1a
+ SO_KEEPALIVE = 0x8
+ SO_LINGER = 0x80
+ SO_LOCK_FILTER = 0x2c
+ SO_MARK = 0x24
+ SO_MAX_PACING_RATE = 0x2f
+ SO_NOFCS = 0x2b
+ SO_NO_CHECK = 0xb
+ SO_OOBINLINE = 0x100
+ SO_PASSCRED = 0x11
+ SO_PASSSEC = 0x22
+ SO_PEEK_OFF = 0x2a
+ SO_PEERCRED = 0x12
+ SO_PEERNAME = 0x1c
+ SO_PEERSEC = 0x1e
+ SO_PRIORITY = 0xc
+ SO_PROTOCOL = 0x1028
+ SO_RCVBUF = 0x1002
+ SO_RCVBUFFORCE = 0x21
+ SO_RCVLOWAT = 0x1004
+ SO_RCVTIMEO = 0x1006
+ SO_REUSEADDR = 0x4
+ SO_REUSEPORT = 0x200
+ SO_RXQ_OVFL = 0x28
+ SO_SECURITY_AUTHENTICATION = 0x16
+ SO_SECURITY_ENCRYPTION_NETWORK = 0x18
+ SO_SECURITY_ENCRYPTION_TRANSPORT = 0x17
+ SO_SELECT_ERR_QUEUE = 0x2d
+ SO_SNDBUF = 0x1001
+ SO_SNDBUFFORCE = 0x1f
+ SO_SNDLOWAT = 0x1003
+ SO_SNDTIMEO = 0x1005
+ SO_STYLE = 0x1008
+ SO_TIMESTAMP = 0x1d
+ SO_TIMESTAMPING = 0x25
+ SO_TIMESTAMPNS = 0x23
+ SO_TYPE = 0x1008
+ SO_WIFI_STATUS = 0x29
+ S_BLKSIZE = 0x200
+ S_IEXEC = 0x40
+ S_IFBLK = 0x6000
+ S_IFCHR = 0x2000
+ S_IFDIR = 0x4000
+ S_IFIFO = 0x1000
+ S_IFLNK = 0xa000
+ S_IFMT = 0xf000
+ S_IFREG = 0x8000
+ S_IFSOCK = 0xc000
+ S_IREAD = 0x100
+ S_IRGRP = 0x20
+ S_IROTH = 0x4
+ S_IRUSR = 0x100
+ S_IRWXG = 0x38
+ S_IRWXO = 0x7
+ S_IRWXU = 0x1c0
+ S_ISGID = 0x400
+ S_ISUID = 0x800
+ S_ISVTX = 0x200
+ S_IWGRP = 0x10
+ S_IWOTH = 0x2
+ S_IWRITE = 0x80
+ S_IWUSR = 0x80
+ S_IXGRP = 0x8
+ S_IXOTH = 0x1
+ S_IXUSR = 0x40
+ TCFLSH = 0x5407
+ TCIFLUSH = 0x0
+ TCIOFLUSH = 0x2
+ TCOFLUSH = 0x1
+ TCP_CONGESTION = 0xd
+ TCP_COOKIE_IN_ALWAYS = 0x1
+ TCP_COOKIE_MAX = 0x10
+ TCP_COOKIE_MIN = 0x8
+ TCP_COOKIE_OUT_NEVER = 0x2
+ TCP_COOKIE_PAIR_SIZE = 0x20
+ TCP_COOKIE_TRANSACTIONS = 0xf
+ TCP_CORK = 0x3
+ TCP_DEFER_ACCEPT = 0x9
+ TCP_FASTOPEN = 0x17
+ TCP_INFO = 0xb
+ TCP_KEEPCNT = 0x6
+ TCP_KEEPIDLE = 0x4
+ TCP_KEEPINTVL = 0x5
+ TCP_LINGER2 = 0x8
+ TCP_MAXSEG = 0x2
+ TCP_MAXWIN = 0xffff
+ TCP_MAX_WINSHIFT = 0xe
+ TCP_MD5SIG = 0xe
+ TCP_MD5SIG_MAXKEYLEN = 0x50
+ TCP_MSS = 0x200
+ TCP_MSS_DEFAULT = 0x218
+ TCP_MSS_DESIRED = 0x4c4
+ TCP_NODELAY = 0x1
+ TCP_QUEUE_SEQ = 0x15
+ TCP_QUICKACK = 0xc
+ TCP_REPAIR = 0x13
+ TCP_REPAIR_OPTIONS = 0x16
+ TCP_REPAIR_QUEUE = 0x14
+ TCP_SYNCNT = 0x7
+ TCP_S_DATA_IN = 0x4
+ TCP_S_DATA_OUT = 0x8
+ TCP_THIN_DUPACK = 0x11
+ TCP_THIN_LINEAR_TIMEOUTS = 0x10
+ TCP_TIMESTAMP = 0x18
+ TCP_USER_TIMEOUT = 0x12
+ TCP_WINDOW_CLAMP = 0xa
+ TCSAFLUSH = 0x5410
+ TIOCCBRK = 0x5428
+ TIOCCONS = 0x80047478
+ TIOCEXCL = 0x740d
+ TIOCGDEV = 0x40045432
+ TIOCGETD = 0x7400
+ TIOCGETP = 0x7408
+ TIOCGEXCL = 0x40045440
+ TIOCGICOUNT = 0x5492
+ TIOCGLCKTRMIOS = 0x548b
+ TIOCGLTC = 0x7474
+ TIOCGPGRP = 0x40047477
+ TIOCGPKT = 0x40045438
+ TIOCGPTLCK = 0x40045439
+ TIOCGPTN = 0x40045430
+ TIOCGSERIAL = 0x5484
+ TIOCGSID = 0x7416
+ TIOCGSOFTCAR = 0x5481
+ TIOCGWINSZ = 0x40087468
+ TIOCINQ = 0x467f
+ TIOCLINUX = 0x5483
+ TIOCMBIC = 0x741c
+ TIOCMBIS = 0x741b
+ TIOCMGET = 0x741d
+ TIOCMIWAIT = 0x5491
+ TIOCMSET = 0x741a
+ TIOCM_CAR = 0x100
+ TIOCM_CD = 0x100
+ TIOCM_CTS = 0x40
+ TIOCM_DSR = 0x400
+ TIOCM_DTR = 0x2
+ TIOCM_LE = 0x1
+ TIOCM_RI = 0x200
+ TIOCM_RNG = 0x200
+ TIOCM_RTS = 0x4
+ TIOCM_SR = 0x20
+ TIOCM_ST = 0x10
+ TIOCNOTTY = 0x5471
+ TIOCNXCL = 0x740e
+ TIOCOUTQ = 0x7472
+ TIOCPKT = 0x5470
+ TIOCPKT_DATA = 0x0
+ TIOCPKT_DOSTOP = 0x20
+ TIOCPKT_FLUSHREAD = 0x1
+ TIOCPKT_FLUSHWRITE = 0x2
+ TIOCPKT_IOCTL = 0x40
+ TIOCPKT_NOSTOP = 0x10
+ TIOCPKT_START = 0x8
+ TIOCPKT_STOP = 0x4
+ TIOCSBRK = 0x5427
+ TIOCSCTTY = 0x5480
+ TIOCSERCONFIG = 0x5488
+ TIOCSERGETLSR = 0x548e
+ TIOCSERGETMULTI = 0x548f
+ TIOCSERGSTRUCT = 0x548d
+ TIOCSERGWILD = 0x5489
+ TIOCSERSETMULTI = 0x5490
+ TIOCSERSWILD = 0x548a
+ TIOCSER_TEMT = 0x1
+ TIOCSETD = 0x7401
+ TIOCSETN = 0x740a
+ TIOCSETP = 0x7409
+ TIOCSIG = 0x80045436
+ TIOCSLCKTRMIOS = 0x548c
+ TIOCSLTC = 0x7475
+ TIOCSPGRP = 0x80047476
+ TIOCSPTLCK = 0x80045431
+ TIOCSSERIAL = 0x5485
+ TIOCSSOFTCAR = 0x5482
+ TIOCSTI = 0x5472
+ TIOCSWINSZ = 0x80087467
+ TIOCVHANGUP = 0x5437
+ TOSTOP = 0x8000
+ TUNATTACHFILTER = 0x800854d5
+ TUNDETACHFILTER = 0x800854d6
+ TUNGETFEATURES = 0x400454cf
+ TUNGETFILTER = 0x400854db
+ TUNGETIFF = 0x400454d2
+ TUNGETSNDBUF = 0x400454d3
+ TUNGETVNETHDRSZ = 0x400454d7
+ TUNSETDEBUG = 0x800454c9
+ TUNSETGROUP = 0x800454ce
+ TUNSETIFF = 0x800454ca
+ TUNSETIFINDEX = 0x800454da
+ TUNSETLINK = 0x800454cd
+ TUNSETNOCSUM = 0x800454c8
+ TUNSETOFFLOAD = 0x800454d0
+ TUNSETOWNER = 0x800454cc
+ TUNSETPERSIST = 0x800454cb
+ TUNSETQUEUE = 0x800454d9
+ TUNSETSNDBUF = 0x800454d4
+ TUNSETTXFILTER = 0x800454d1
+ TUNSETVNETHDRSZ = 0x800454d8
+ VDISCARD = 0xd
+ VEOF = 0x10
+ VEOL = 0x11
+ VEOL2 = 0x6
+ VERASE = 0x2
+ VINTR = 0x0
+ VKILL = 0x3
+ VLNEXT = 0xf
+ VMIN = 0x4
+ VQUIT = 0x1
+ VREPRINT = 0xc
+ VSTART = 0x8
+ VSTOP = 0x9
+ VSUSP = 0xa
+ VSWTC = 0x7
+ VSWTCH = 0x7
+ VT0 = 0x0
+ VT1 = 0x4000
+ VTDLY = 0x4000
+ VTIME = 0x5
+ VWERASE = 0xe
+ WALL = 0x40000000
+ WCLONE = 0x80000000
+ WCONTINUED = 0x8
+ WEXITED = 0x4
+ WNOHANG = 0x1
+ WNOTHREAD = 0x20000000
+ WNOWAIT = 0x1000000
+ WORDSIZE = 0x20
+ WSTOPPED = 0x2
+ WUNTRACED = 0x2
+)
+
+// Errors
+const (
+ E2BIG = Errno(0x7)
+ EACCES = Errno(0xd)
+ EADDRINUSE = Errno(0x7d)
+ EADDRNOTAVAIL = Errno(0x7e)
+ EADV = Errno(0x44)
+ EAFNOSUPPORT = Errno(0x7c)
+ EAGAIN = Errno(0xb)
+ EALREADY = Errno(0x95)
+ EBADE = Errno(0x32)
+ EBADF = Errno(0x9)
+ EBADFD = Errno(0x51)
+ EBADMSG = Errno(0x4d)
+ EBADR = Errno(0x33)
+ EBADRQC = Errno(0x36)
+ EBADSLT = Errno(0x37)
+ EBFONT = Errno(0x3b)
+ EBUSY = Errno(0x10)
+ ECANCELED = Errno(0x9e)
+ ECHILD = Errno(0xa)
+ ECHRNG = Errno(0x25)
+ ECOMM = Errno(0x46)
+ ECONNABORTED = Errno(0x82)
+ ECONNREFUSED = Errno(0x92)
+ ECONNRESET = Errno(0x83)
+ EDEADLK = Errno(0x2d)
+ EDEADLOCK = Errno(0x38)
+ EDESTADDRREQ = Errno(0x60)
+ EDOM = Errno(0x21)
+ EDOTDOT = Errno(0x49)
+ EDQUOT = Errno(0x46d)
+ EEXIST = Errno(0x11)
+ EFAULT = Errno(0xe)
+ EFBIG = Errno(0x1b)
+ EHOSTDOWN = Errno(0x93)
+ EHOSTUNREACH = Errno(0x94)
+ EHWPOISON = Errno(0xa8)
+ EIDRM = Errno(0x24)
+ EILSEQ = Errno(0x58)
+ EINIT = Errno(0x8d)
+ EINPROGRESS = Errno(0x96)
+ EINTR = Errno(0x4)
+ EINVAL = Errno(0x16)
+ EIO = Errno(0x5)
+ EISCONN = Errno(0x85)
+ EISDIR = Errno(0x15)
+ EISNAM = Errno(0x8b)
+ EKEYEXPIRED = Errno(0xa2)
+ EKEYREJECTED = Errno(0xa4)
+ EKEYREVOKED = Errno(0xa3)
+ EL2HLT = Errno(0x2c)
+ EL2NSYNC = Errno(0x26)
+ EL3HLT = Errno(0x27)
+ EL3RST = Errno(0x28)
+ ELIBACC = Errno(0x53)
+ ELIBBAD = Errno(0x54)
+ ELIBEXEC = Errno(0x57)
+ ELIBMAX = Errno(0x56)
+ ELIBSCN = Errno(0x55)
+ ELNRNG = Errno(0x29)
+ ELOOP = Errno(0x5a)
+ EMEDIUMTYPE = Errno(0xa0)
+ EMFILE = Errno(0x18)
+ EMLINK = Errno(0x1f)
+ EMSGSIZE = Errno(0x61)
+ EMULTIHOP = Errno(0x4a)
+ ENAMETOOLONG = Errno(0x4e)
+ ENAVAIL = Errno(0x8a)
+ ENETDOWN = Errno(0x7f)
+ ENETRESET = Errno(0x81)
+ ENETUNREACH = Errno(0x80)
+ ENFILE = Errno(0x17)
+ ENOANO = Errno(0x35)
+ ENOBUFS = Errno(0x84)
+ ENOCSI = Errno(0x2b)
+ ENODATA = Errno(0x3d)
+ ENODEV = Errno(0x13)
+ ENOENT = Errno(0x2)
+ ENOEXEC = Errno(0x8)
+ ENOKEY = Errno(0xa1)
+ ENOLCK = Errno(0x2e)
+ ENOLINK = Errno(0x43)
+ ENOMEDIUM = Errno(0x9f)
+ ENOMEM = Errno(0xc)
+ ENOMSG = Errno(0x23)
+ ENONET = Errno(0x40)
+ ENOPKG = Errno(0x41)
+ ENOPROTOOPT = Errno(0x63)
+ ENOSPC = Errno(0x1c)
+ ENOSR = Errno(0x3f)
+ ENOSTR = Errno(0x3c)
+ ENOSYS = Errno(0x59)
+ ENOTBLK = Errno(0xf)
+ ENOTCONN = Errno(0x86)
+ ENOTDIR = Errno(0x14)
+ ENOTEMPTY = Errno(0x5d)
+ ENOTNAM = Errno(0x89)
+ ENOTRECOVERABLE = Errno(0xa6)
+ ENOTSOCK = Errno(0x5f)
+ ENOTSUP = Errno(0x7a)
+ ENOTTY = Errno(0x19)
+ ENOTUNIQ = Errno(0x50)
+ ENXIO = Errno(0x6)
+ EOPNOTSUPP = Errno(0x7a)
+ EOVERFLOW = Errno(0x4f)
+ EOWNERDEAD = Errno(0xa5)
+ EPERM = Errno(0x1)
+ EPFNOSUPPORT = Errno(0x7b)
+ EPIPE = Errno(0x20)
+ EPROTO = Errno(0x47)
+ EPROTONOSUPPORT = Errno(0x78)
+ EPROTOTYPE = Errno(0x62)
+ ERANGE = Errno(0x22)
+ EREMCHG = Errno(0x52)
+ EREMDEV = Errno(0x8e)
+ EREMOTE = Errno(0x42)
+ EREMOTEIO = Errno(0x8c)
+ ERESTART = Errno(0x5b)
+ ERFKILL = Errno(0xa7)
+ EROFS = Errno(0x1e)
+ ESHUTDOWN = Errno(0x8f)
+ ESOCKTNOSUPPORT = Errno(0x79)
+ ESPIPE = Errno(0x1d)
+ ESRCH = Errno(0x3)
+ ESRMNT = Errno(0x45)
+ ESTALE = Errno(0x97)
+ ESTRPIPE = Errno(0x5c)
+ ETIME = Errno(0x3e)
+ ETIMEDOUT = Errno(0x91)
+ ETOOMANYREFS = Errno(0x90)
+ ETXTBSY = Errno(0x1a)
+ EUCLEAN = Errno(0x87)
+ EUNATCH = Errno(0x2a)
+ EUSERS = Errno(0x5e)
+ EWOULDBLOCK = Errno(0xb)
+ EXDEV = Errno(0x12)
+ EXFULL = Errno(0x34)
+)
+
+// Signals
+const (
+ SIGABRT = Signal(0x6)
+ SIGALRM = Signal(0xe)
+ SIGBUS = Signal(0xa)
+ SIGCHLD = Signal(0x12)
+ SIGCLD = Signal(0x12)
+ SIGCONT = Signal(0x19)
+ SIGEMT = Signal(0x7)
+ SIGFPE = Signal(0x8)
+ SIGHUP = Signal(0x1)
+ SIGILL = Signal(0x4)
+ SIGINT = Signal(0x2)
+ SIGIO = Signal(0x16)
+ SIGIOT = Signal(0x6)
+ SIGKILL = Signal(0x9)
+ SIGPIPE = Signal(0xd)
+ SIGPOLL = Signal(0x16)
+ SIGPROF = Signal(0x1d)
+ SIGPWR = Signal(0x13)
+ SIGQUIT = Signal(0x3)
+ SIGSEGV = Signal(0xb)
+ SIGSTOP = Signal(0x17)
+ SIGSYS = Signal(0xc)
+ SIGTERM = Signal(0xf)
+ SIGTRAP = Signal(0x5)
+ SIGTSTP = Signal(0x18)
+ SIGTTIN = Signal(0x1a)
+ SIGTTOU = Signal(0x1b)
+ SIGURG = Signal(0x15)
+ SIGUSR1 = Signal(0x10)
+ SIGUSR2 = Signal(0x11)
+ SIGVTALRM = Signal(0x1c)
+ SIGWINCH = Signal(0x14)
+ SIGXCPU = Signal(0x1e)
+ SIGXFSZ = Signal(0x1f)
+)
+
+// Error table
+var errors = [...]string{
+ 1: "operation not permitted",
+ 2: "no such file or directory",
+ 3: "no such process",
+ 4: "interrupted system call",
+ 5: "input/output error",
+ 6: "no such device or address",
+ 7: "argument list too long",
+ 8: "exec format error",
+ 9: "bad file descriptor",
+ 10: "no child processes",
+ 11: "resource temporarily unavailable",
+ 12: "cannot allocate memory",
+ 13: "permission denied",
+ 14: "bad address",
+ 15: "block device required",
+ 16: "device or resource busy",
+ 17: "file exists",
+ 18: "invalid cross-device link",
+ 19: "no such device",
+ 20: "not a directory",
+ 21: "is a directory",
+ 22: "invalid argument",
+ 23: "too many open files in system",
+ 24: "too many open files",
+ 25: "inappropriate ioctl for device",
+ 26: "text file busy",
+ 27: "file too large",
+ 28: "no space left on device",
+ 29: "illegal seek",
+ 30: "read-only file system",
+ 31: "too many links",
+ 32: "broken pipe",
+ 33: "numerical argument out of domain",
+ 34: "numerical result out of range",
+ 35: "no message of desired type",
+ 36: "identifier removed",
+ 37: "channel number out of range",
+ 38: "level 2 not synchronized",
+ 39: "level 3 halted",
+ 40: "level 3 reset",
+ 41: "link number out of range",
+ 42: "protocol driver not attached",
+ 43: "no CSI structure available",
+ 44: "level 2 halted",
+ 45: "resource deadlock avoided",
+ 46: "no locks available",
+ 50: "invalid exchange",
+ 51: "invalid request descriptor",
+ 52: "exchange full",
+ 53: "no anode",
+ 54: "invalid request code",
+ 55: "invalid slot",
+ 56: "file locking deadlock error",
+ 59: "bad font file format",
+ 60: "device not a stream",
+ 61: "no data available",
+ 62: "timer expired",
+ 63: "out of streams resources",
+ 64: "machine is not on the network",
+ 65: "package not installed",
+ 66: "object is remote",
+ 67: "link has been severed",
+ 68: "advertise error",
+ 69: "srmount error",
+ 70: "communication error on send",
+ 71: "protocol error",
+ 73: "RFS specific error",
+ 74: "multihop attempted",
+ 77: "bad message",
+ 78: "file name too long",
+ 79: "value too large for defined data type",
+ 80: "name not unique on network",
+ 81: "file descriptor in bad state",
+ 82: "remote address changed",
+ 83: "can not access a needed shared library",
+ 84: "accessing a corrupted shared library",
+ 85: ".lib section in a.out corrupted",
+ 86: "attempting to link in too many shared libraries",
+ 87: "cannot exec a shared library directly",
+ 88: "invalid or incomplete multibyte or wide character",
+ 89: "function not implemented",
+ 90: "too many levels of symbolic links",
+ 91: "interrupted system call should be restarted",
+ 92: "streams pipe error",
+ 93: "directory not empty",
+ 94: "too many users",
+ 95: "socket operation on non-socket",
+ 96: "destination address required",
+ 97: "message too long",
+ 98: "protocol wrong type for socket",
+ 99: "protocol not available",
+ 120: "protocol not supported",
+ 121: "socket type not supported",
+ 122: "operation not supported",
+ 123: "protocol family not supported",
+ 124: "address family not supported by protocol",
+ 125: "address already in use",
+ 126: "cannot assign requested address",
+ 127: "network is down",
+ 128: "network is unreachable",
+ 129: "network dropped connection on reset",
+ 130: "software caused connection abort",
+ 131: "connection reset by peer",
+ 132: "no buffer space available",
+ 133: "transport endpoint is already connected",
+ 134: "transport endpoint is not connected",
+ 135: "structure needs cleaning",
+ 137: "not a XENIX named type file",
+ 138: "no XENIX semaphores available",
+ 139: "is a named type file",
+ 140: "remote I/O error",
+ 141: "unknown error 141",
+ 142: "unknown error 142",
+ 143: "cannot send after transport endpoint shutdown",
+ 144: "too many references: cannot splice",
+ 145: "connection timed out",
+ 146: "connection refused",
+ 147: "host is down",
+ 148: "no route to host",
+ 149: "operation already in progress",
+ 150: "operation now in progress",
+ 151: "stale file handle",
+ 158: "operation canceled",
+ 159: "no medium found",
+ 160: "wrong medium type",
+ 161: "required key not available",
+ 162: "key has expired",
+ 163: "key has been revoked",
+ 164: "key was rejected by service",
+ 165: "owner died",
+ 166: "state not recoverable",
+ 167: "operation not possible due to RF-kill",
+ 168: "memory page has hardware error",
+ 1133: "disk quota exceeded",
+}
+
+// Signal table
+var signals = [...]string{
+ 1: "hangup",
+ 2: "interrupt",
+ 3: "quit",
+ 4: "illegal instruction",
+ 5: "trace/breakpoint trap",
+ 6: "aborted",
+ 7: "EMT trap",
+ 8: "floating point exception",
+ 9: "killed",
+ 10: "bus error",
+ 11: "segmentation fault",
+ 12: "bad system call",
+ 13: "broken pipe",
+ 14: "alarm clock",
+ 15: "terminated",
+ 16: "user defined signal 1",
+ 17: "user defined signal 2",
+ 18: "child exited",
+ 19: "power failure",
+ 20: "window changed",
+ 21: "urgent I/O condition",
+ 22: "I/O possible",
+ 23: "stopped (signal)",
+ 24: "stopped",
+ 25: "continued",
+ 26: "stopped (tty input)",
+ 27: "stopped (tty output)",
+ 28: "virtual timer expired",
+ 29: "profiling timer expired",
+ 30: "CPU time limit exceeded",
+ 31: "file size limit exceeded",
+}
diff --git a/src/syscall/zsyscall_linux_386.go b/src/syscall/zsyscall_linux_386.go
index 82834fd..195228d 100644
--- a/src/syscall/zsyscall_linux_386.go
+++ b/src/syscall/zsyscall_linux_386.go
@@ -763,8 +763,8 @@ func PivotRoot(newroot string, putold string) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func prlimit(pid int, resource int, old *Rlimit, newlimit *Rlimit) (err error) {
- _, _, e1 := RawSyscall6(SYS_PRLIMIT64, uintptr(pid), uintptr(resource), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(newlimit)), 0, 0)
+func prlimit(pid int, resource int, newlimit *Rlimit, old *Rlimit) (err error) {
+ _, _, e1 := RawSyscall6(SYS_PRLIMIT64, uintptr(pid), uintptr(resource), uintptr(unsafe.Pointer(newlimit)), uintptr(unsafe.Pointer(old)), 0, 0)
if e1 != 0 {
err = errnoErr(e1)
}
diff --git a/src/syscall/zsyscall_linux_amd64.go b/src/syscall/zsyscall_linux_amd64.go
index e7f754e..f413a19 100644
--- a/src/syscall/zsyscall_linux_amd64.go
+++ b/src/syscall/zsyscall_linux_amd64.go
@@ -763,8 +763,8 @@ func PivotRoot(newroot string, putold string) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func prlimit(pid int, resource int, old *Rlimit, newlimit *Rlimit) (err error) {
- _, _, e1 := RawSyscall6(SYS_PRLIMIT64, uintptr(pid), uintptr(resource), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(newlimit)), 0, 0)
+func prlimit(pid int, resource int, newlimit *Rlimit, old *Rlimit) (err error) {
+ _, _, e1 := RawSyscall6(SYS_PRLIMIT64, uintptr(pid), uintptr(resource), uintptr(unsafe.Pointer(newlimit)), uintptr(unsafe.Pointer(old)), 0, 0)
if e1 != 0 {
err = errnoErr(e1)
}
diff --git a/src/syscall/zsyscall_linux_arm.go b/src/syscall/zsyscall_linux_arm.go
index aed89cd..7773436 100644
--- a/src/syscall/zsyscall_linux_arm.go
+++ b/src/syscall/zsyscall_linux_arm.go
@@ -763,8 +763,8 @@ func PivotRoot(newroot string, putold string) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func prlimit(pid int, resource int, old *Rlimit, newlimit *Rlimit) (err error) {
- _, _, e1 := RawSyscall6(SYS_PRLIMIT64, uintptr(pid), uintptr(resource), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(newlimit)), 0, 0)
+func prlimit(pid int, resource int, newlimit *Rlimit, old *Rlimit) (err error) {
+ _, _, e1 := RawSyscall6(SYS_PRLIMIT64, uintptr(pid), uintptr(resource), uintptr(unsafe.Pointer(newlimit)), uintptr(unsafe.Pointer(old)), 0, 0)
if e1 != 0 {
err = errnoErr(e1)
}
diff --git a/src/syscall/zsyscall_linux_arm64.go b/src/syscall/zsyscall_linux_arm64.go
index 69df407..8e02f3c 100644
--- a/src/syscall/zsyscall_linux_arm64.go
+++ b/src/syscall/zsyscall_linux_arm64.go
@@ -763,8 +763,8 @@ func PivotRoot(newroot string, putold string) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func prlimit(pid int, resource int, old *Rlimit, newlimit *Rlimit) (err error) {
- _, _, e1 := RawSyscall6(SYS_PRLIMIT64, uintptr(pid), uintptr(resource), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(newlimit)), 0, 0)
+func prlimit(pid int, resource int, newlimit *Rlimit, old *Rlimit) (err error) {
+ _, _, e1 := RawSyscall6(SYS_PRLIMIT64, uintptr(pid), uintptr(resource), uintptr(unsafe.Pointer(newlimit)), uintptr(unsafe.Pointer(old)), 0, 0)
if e1 != 0 {
err = errnoErr(e1)
}
diff --git a/src/syscall/zsyscall_linux_mips.go b/src/syscall/zsyscall_linux_mips.go
new file mode 100644
index 0000000..0fa1452
--- /dev/null
+++ b/src/syscall/zsyscall_linux_mips.go
@@ -0,0 +1,1759 @@
+// mksyscall.pl -b32 -arm syscall_linux.go syscall_linux_mipsx.go
+// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+
+package syscall
+
+import "unsafe"
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func linkat(olddirfd int, oldpath string, newdirfd int, newpath string, flags int) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(oldpath)
+ if err != nil {
+ return
+ }
+ var _p1 *byte
+ _p1, err = BytePtrFromString(newpath)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall6(SYS_LINKAT, uintptr(olddirfd), uintptr(unsafe.Pointer(_p0)), uintptr(newdirfd), uintptr(unsafe.Pointer(_p1)), uintptr(flags), 0)
+ use(unsafe.Pointer(_p0))
+ use(unsafe.Pointer(_p1))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func openat(dirfd int, path string, flags int, mode uint32) (fd int, err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ r0, _, e1 := Syscall6(SYS_OPENAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(flags), uintptr(mode), 0, 0)
+ use(unsafe.Pointer(_p0))
+ fd = int(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func readlinkat(dirfd int, path string, buf []byte) (n int, err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ var _p1 unsafe.Pointer
+ if len(buf) > 0 {
+ _p1 = unsafe.Pointer(&buf[0])
+ } else {
+ _p1 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall6(SYS_READLINKAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(buf)), 0, 0)
+ use(unsafe.Pointer(_p0))
+ n = int(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func symlinkat(oldpath string, newdirfd int, newpath string) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(oldpath)
+ if err != nil {
+ return
+ }
+ var _p1 *byte
+ _p1, err = BytePtrFromString(newpath)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_SYMLINKAT, uintptr(unsafe.Pointer(_p0)), uintptr(newdirfd), uintptr(unsafe.Pointer(_p1)))
+ use(unsafe.Pointer(_p0))
+ use(unsafe.Pointer(_p1))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func unlinkat(dirfd int, path string, flags int) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_UNLINKAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(flags))
+ use(unsafe.Pointer(_p0))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func utimes(path string, times *[2]Timeval) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)), 0)
+ use(unsafe.Pointer(_p0))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func utimensat(dirfd int, path string, times *[2]Timespec) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_UTIMENSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)))
+ use(unsafe.Pointer(_p0))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func futimesat(dirfd int, path *byte, times *[2]Timeval) (err error) {
+ _, _, e1 := Syscall(SYS_FUTIMESAT, uintptr(dirfd), uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(times)))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getcwd(buf []byte) (n int, err error) {
+ var _p0 unsafe.Pointer
+ if len(buf) > 0 {
+ _p0 = unsafe.Pointer(&buf[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall(SYS_GETCWD, uintptr(_p0), uintptr(len(buf)), 0)
+ n = int(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, err error) {
+ r0, _, e1 := Syscall6(SYS_WAIT4, uintptr(pid), uintptr(unsafe.Pointer(wstatus)), uintptr(options), uintptr(unsafe.Pointer(rusage)), 0, 0)
+ wpid = int(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func ptrace(request int, pid int, addr uintptr, data uintptr) (err error) {
+ _, _, e1 := Syscall6(SYS_PTRACE, uintptr(request), uintptr(pid), uintptr(addr), uintptr(data), 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func reboot(magic1 uint, magic2 uint, cmd int, arg string) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(arg)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall6(SYS_REBOOT, uintptr(magic1), uintptr(magic2), uintptr(cmd), uintptr(unsafe.Pointer(_p0)), 0, 0)
+ use(unsafe.Pointer(_p0))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func mount(source string, target string, fstype string, flags uintptr, data *byte) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(source)
+ if err != nil {
+ return
+ }
+ var _p1 *byte
+ _p1, err = BytePtrFromString(target)
+ if err != nil {
+ return
+ }
+ var _p2 *byte
+ _p2, err = BytePtrFromString(fstype)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall6(SYS_MOUNT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(unsafe.Pointer(_p2)), uintptr(flags), uintptr(unsafe.Pointer(data)), 0)
+ use(unsafe.Pointer(_p0))
+ use(unsafe.Pointer(_p1))
+ use(unsafe.Pointer(_p2))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Acct(path string) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_ACCT, uintptr(unsafe.Pointer(_p0)), 0, 0)
+ use(unsafe.Pointer(_p0))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Adjtimex(buf *Timex) (state int, err error) {
+ r0, _, e1 := Syscall(SYS_ADJTIMEX, uintptr(unsafe.Pointer(buf)), 0, 0)
+ state = int(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Chdir(path string) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
+ use(unsafe.Pointer(_p0))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Chroot(path string) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(_p0)), 0, 0)
+ use(unsafe.Pointer(_p0))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Close(fd int) (err error) {
+ _, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Dup(oldfd int) (fd int, err error) {
+ r0, _, e1 := Syscall(SYS_DUP, uintptr(oldfd), 0, 0)
+ fd = int(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Dup3(oldfd int, newfd int, flags int) (err error) {
+ _, _, e1 := Syscall(SYS_DUP3, uintptr(oldfd), uintptr(newfd), uintptr(flags))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func EpollCreate(size int) (fd int, err error) {
+ r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE, uintptr(size), 0, 0)
+ fd = int(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func EpollCreate1(flag int) (fd int, err error) {
+ r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE1, uintptr(flag), 0, 0)
+ fd = int(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func EpollCtl(epfd int, op int, fd int, event *EpollEvent) (err error) {
+ _, _, e1 := RawSyscall6(SYS_EPOLL_CTL, uintptr(epfd), uintptr(op), uintptr(fd), uintptr(unsafe.Pointer(event)), 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) {
+ var _p0 unsafe.Pointer
+ if len(events) > 0 {
+ _p0 = unsafe.Pointer(&events[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall6(SYS_EPOLL_WAIT, uintptr(epfd), uintptr(_p0), uintptr(len(events)), uintptr(msec), 0, 0)
+ n = int(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Exit(code int) {
+ Syscall(SYS_EXIT_GROUP, uintptr(code), 0, 0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall6(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0)
+ use(unsafe.Pointer(_p0))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fallocate(fd int, mode uint32, off int64, len int64) (err error) {
+ _, _, e1 := Syscall6(SYS_FALLOCATE, uintptr(fd), uintptr(mode), uintptr(off>>32), uintptr(off), uintptr(len>>32), uintptr(len))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fchdir(fd int) (err error) {
+ _, _, e1 := Syscall(SYS_FCHDIR, uintptr(fd), 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fchmod(fd int, mode uint32) (err error) {
+ _, _, e1 := Syscall(SYS_FCHMOD, uintptr(fd), uintptr(mode), 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall6(SYS_FCHMODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0)
+ use(unsafe.Pointer(_p0))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall6(SYS_FCHOWNAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid), uintptr(flags), 0)
+ use(unsafe.Pointer(_p0))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func fcntl(fd int, cmd int, arg int) (val int, err error) {
+ r0, _, e1 := Syscall(SYS_FCNTL, uintptr(fd), uintptr(cmd), uintptr(arg))
+ val = int(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fdatasync(fd int) (err error) {
+ _, _, e1 := Syscall(SYS_FDATASYNC, uintptr(fd), 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Flock(fd int, how int) (err error) {
+ _, _, e1 := Syscall(SYS_FLOCK, uintptr(fd), uintptr(how), 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fsync(fd int) (err error) {
+ _, _, e1 := Syscall(SYS_FSYNC, uintptr(fd), 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getdents(fd int, buf []byte) (n int, err error) {
+ var _p0 unsafe.Pointer
+ if len(buf) > 0 {
+ _p0 = unsafe.Pointer(&buf[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall(_SYS_getdents, uintptr(fd), uintptr(_p0), uintptr(len(buf)))
+ n = int(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getpgid(pid int) (pgid int, err error) {
+ r0, _, e1 := RawSyscall(SYS_GETPGID, uintptr(pid), 0, 0)
+ pgid = int(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getpid() (pid int) {
+ r0, _, _ := RawSyscall(SYS_GETPID, 0, 0, 0)
+ pid = int(r0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getppid() (ppid int) {
+ r0, _, _ := RawSyscall(SYS_GETPPID, 0, 0, 0)
+ ppid = int(r0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getpriority(which int, who int) (prio int, err error) {
+ r0, _, e1 := Syscall(SYS_GETPRIORITY, uintptr(which), uintptr(who), 0)
+ prio = int(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getrusage(who int, rusage *Rusage) (err error) {
+ _, _, e1 := RawSyscall(SYS_GETRUSAGE, uintptr(who), uintptr(unsafe.Pointer(rusage)), 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Gettid() (tid int) {
+ r0, _, _ := RawSyscall(SYS_GETTID, 0, 0, 0)
+ tid = int(r0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getxattr(path string, attr string, dest []byte) (sz int, err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ var _p1 *byte
+ _p1, err = BytePtrFromString(attr)
+ if err != nil {
+ return
+ }
+ var _p2 unsafe.Pointer
+ if len(dest) > 0 {
+ _p2 = unsafe.Pointer(&dest[0])
+ } else {
+ _p2 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall6(SYS_GETXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(_p2), uintptr(len(dest)), 0, 0)
+ use(unsafe.Pointer(_p0))
+ use(unsafe.Pointer(_p1))
+ sz = int(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func InotifyAddWatch(fd int, pathname string, mask uint32) (watchdesc int, err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(pathname)
+ if err != nil {
+ return
+ }
+ r0, _, e1 := Syscall(SYS_INOTIFY_ADD_WATCH, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(mask))
+ use(unsafe.Pointer(_p0))
+ watchdesc = int(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func InotifyInit1(flags int) (fd int, err error) {
+ r0, _, e1 := RawSyscall(SYS_INOTIFY_INIT1, uintptr(flags), 0, 0)
+ fd = int(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func InotifyRmWatch(fd int, watchdesc uint32) (success int, err error) {
+ r0, _, e1 := RawSyscall(SYS_INOTIFY_RM_WATCH, uintptr(fd), uintptr(watchdesc), 0)
+ success = int(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Kill(pid int, sig Signal) (err error) {
+ _, _, e1 := RawSyscall(SYS_KILL, uintptr(pid), uintptr(sig), 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Klogctl(typ int, buf []byte) (n int, err error) {
+ var _p0 unsafe.Pointer
+ if len(buf) > 0 {
+ _p0 = unsafe.Pointer(&buf[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall(SYS_SYSLOG, uintptr(typ), uintptr(_p0), uintptr(len(buf)))
+ n = int(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Listxattr(path string, dest []byte) (sz int, err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ var _p1 unsafe.Pointer
+ if len(dest) > 0 {
+ _p1 = unsafe.Pointer(&dest[0])
+ } else {
+ _p1 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall(SYS_LISTXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(dest)))
+ use(unsafe.Pointer(_p0))
+ sz = int(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Mkdirat(dirfd int, path string, mode uint32) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_MKDIRAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode))
+ use(unsafe.Pointer(_p0))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Mknodat(dirfd int, path string, mode uint32, dev int) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall6(SYS_MKNODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev), 0, 0)
+ use(unsafe.Pointer(_p0))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Nanosleep(time *Timespec, leftover *Timespec) (err error) {
+ _, _, e1 := Syscall(SYS_NANOSLEEP, uintptr(unsafe.Pointer(time)), uintptr(unsafe.Pointer(leftover)), 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Pause() (err error) {
+ _, _, e1 := Syscall(SYS_PAUSE, 0, 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func PivotRoot(newroot string, putold string) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(newroot)
+ if err != nil {
+ return
+ }
+ var _p1 *byte
+ _p1, err = BytePtrFromString(putold)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_PIVOT_ROOT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0)
+ use(unsafe.Pointer(_p0))
+ use(unsafe.Pointer(_p1))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func prlimit(pid int, resource int, newlimit *Rlimit, old *Rlimit) (err error) {
+ _, _, e1 := RawSyscall6(SYS_PRLIMIT64, uintptr(pid), uintptr(resource), uintptr(unsafe.Pointer(newlimit)), uintptr(unsafe.Pointer(old)), 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func read(fd int, p []byte) (n int, err error) {
+ var _p0 unsafe.Pointer
+ if len(p) > 0 {
+ _p0 = unsafe.Pointer(&p[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(_p0), uintptr(len(p)))
+ n = int(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Removexattr(path string, attr string) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ var _p1 *byte
+ _p1, err = BytePtrFromString(attr)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_REMOVEXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0)
+ use(unsafe.Pointer(_p0))
+ use(unsafe.Pointer(_p1))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(oldpath)
+ if err != nil {
+ return
+ }
+ var _p1 *byte
+ _p1, err = BytePtrFromString(newpath)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall6(SYS_RENAMEAT, uintptr(olddirfd), uintptr(unsafe.Pointer(_p0)), uintptr(newdirfd), uintptr(unsafe.Pointer(_p1)), 0, 0)
+ use(unsafe.Pointer(_p0))
+ use(unsafe.Pointer(_p1))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setdomainname(p []byte) (err error) {
+ var _p0 unsafe.Pointer
+ if len(p) > 0 {
+ _p0 = unsafe.Pointer(&p[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ _, _, e1 := Syscall(SYS_SETDOMAINNAME, uintptr(_p0), uintptr(len(p)), 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Sethostname(p []byte) (err error) {
+ var _p0 unsafe.Pointer
+ if len(p) > 0 {
+ _p0 = unsafe.Pointer(&p[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ _, _, e1 := Syscall(SYS_SETHOSTNAME, uintptr(_p0), uintptr(len(p)), 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setpgid(pid int, pgid int) (err error) {
+ _, _, e1 := RawSyscall(SYS_SETPGID, uintptr(pid), uintptr(pgid), 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setsid() (pid int, err error) {
+ r0, _, e1 := RawSyscall(SYS_SETSID, 0, 0, 0)
+ pid = int(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Settimeofday(tv *Timeval) (err error) {
+ _, _, e1 := RawSyscall(SYS_SETTIMEOFDAY, uintptr(unsafe.Pointer(tv)), 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setpriority(which int, who int, prio int) (err error) {
+ _, _, e1 := Syscall(SYS_SETPRIORITY, uintptr(which), uintptr(who), uintptr(prio))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setxattr(path string, attr string, data []byte, flags int) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ var _p1 *byte
+ _p1, err = BytePtrFromString(attr)
+ if err != nil {
+ return
+ }
+ var _p2 unsafe.Pointer
+ if len(data) > 0 {
+ _p2 = unsafe.Pointer(&data[0])
+ } else {
+ _p2 = unsafe.Pointer(&_zero)
+ }
+ _, _, e1 := Syscall6(SYS_SETXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(_p2), uintptr(len(data)), uintptr(flags), 0)
+ use(unsafe.Pointer(_p0))
+ use(unsafe.Pointer(_p1))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Sync() {
+ Syscall(SYS_SYNC, 0, 0, 0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Sysinfo(info *Sysinfo_t) (err error) {
+ _, _, e1 := RawSyscall(SYS_SYSINFO, uintptr(unsafe.Pointer(info)), 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Tee(rfd int, wfd int, len int, flags int) (n int64, err error) {
+ r0, r1, e1 := Syscall6(SYS_TEE, uintptr(rfd), uintptr(wfd), uintptr(len), uintptr(flags), 0, 0)
+ n = int64(int64(r0)<<32 | int64(r1))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Tgkill(tgid int, tid int, sig Signal) (err error) {
+ _, _, e1 := RawSyscall(SYS_TGKILL, uintptr(tgid), uintptr(tid), uintptr(sig))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Times(tms *Tms) (ticks uintptr, err error) {
+ r0, _, e1 := RawSyscall(SYS_TIMES, uintptr(unsafe.Pointer(tms)), 0, 0)
+ ticks = uintptr(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Umask(mask int) (oldmask int) {
+ r0, _, _ := RawSyscall(SYS_UMASK, uintptr(mask), 0, 0)
+ oldmask = int(r0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Uname(buf *Utsname) (err error) {
+ _, _, e1 := RawSyscall(SYS_UNAME, uintptr(unsafe.Pointer(buf)), 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Unmount(target string, flags int) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(target)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_UMOUNT2, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
+ use(unsafe.Pointer(_p0))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Unshare(flags int) (err error) {
+ _, _, e1 := Syscall(SYS_UNSHARE, uintptr(flags), 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Ustat(dev int, ubuf *Ustat_t) (err error) {
+ _, _, e1 := Syscall(SYS_USTAT, uintptr(dev), uintptr(unsafe.Pointer(ubuf)), 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Utime(path string, buf *Utimbuf) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_UTIME, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(buf)), 0)
+ use(unsafe.Pointer(_p0))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func write(fd int, p []byte) (n int, err error) {
+ var _p0 unsafe.Pointer
+ if len(p) > 0 {
+ _p0 = unsafe.Pointer(&p[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)))
+ n = int(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func exitThread(code int) (err error) {
+ _, _, e1 := Syscall(SYS_EXIT, uintptr(code), 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func readlen(fd int, p *byte, np int) (n int, err error) {
+ r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(unsafe.Pointer(p)), uintptr(np))
+ n = int(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func writelen(fd int, p *byte, np int) (n int, err error) {
+ r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(unsafe.Pointer(p)), uintptr(np))
+ n = int(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func munmap(addr uintptr, length uintptr) (err error) {
+ _, _, e1 := Syscall(SYS_MUNMAP, uintptr(addr), uintptr(length), 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Madvise(b []byte, advice int) (err error) {
+ var _p0 unsafe.Pointer
+ if len(b) > 0 {
+ _p0 = unsafe.Pointer(&b[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ _, _, e1 := Syscall(SYS_MADVISE, uintptr(_p0), uintptr(len(b)), uintptr(advice))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Mprotect(b []byte, prot int) (err error) {
+ var _p0 unsafe.Pointer
+ if len(b) > 0 {
+ _p0 = unsafe.Pointer(&b[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ _, _, e1 := Syscall(SYS_MPROTECT, uintptr(_p0), uintptr(len(b)), uintptr(prot))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Mlock(b []byte) (err error) {
+ var _p0 unsafe.Pointer
+ if len(b) > 0 {
+ _p0 = unsafe.Pointer(&b[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ _, _, e1 := Syscall(SYS_MLOCK, uintptr(_p0), uintptr(len(b)), 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Munlock(b []byte) (err error) {
+ var _p0 unsafe.Pointer
+ if len(b) > 0 {
+ _p0 = unsafe.Pointer(&b[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ _, _, e1 := Syscall(SYS_MUNLOCK, uintptr(_p0), uintptr(len(b)), 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Mlockall(flags int) (err error) {
+ _, _, e1 := Syscall(SYS_MLOCKALL, uintptr(flags), 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Munlockall() (err error) {
+ _, _, e1 := Syscall(SYS_MUNLOCKALL, 0, 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Dup2(oldfd int, newfd int) (err error) {
+ _, _, e1 := Syscall(SYS_DUP2, uintptr(oldfd), uintptr(newfd), 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fchown(fd int, uid int, gid int) (err error) {
+ _, _, e1 := Syscall(SYS_FCHOWN, uintptr(fd), uintptr(uid), uintptr(gid))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Ftruncate(fd int, length int64) (err error) {
+ _, _, e1 := Syscall6(SYS_FTRUNCATE64, uintptr(fd), 0, uintptr(length>>32), uintptr(length), 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getegid() (egid int) {
+ r0, _, _ := RawSyscall(SYS_GETEGID, 0, 0, 0)
+ egid = int(r0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Geteuid() (euid int) {
+ r0, _, _ := RawSyscall(SYS_GETEUID, 0, 0, 0)
+ euid = int(r0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getgid() (gid int) {
+ r0, _, _ := RawSyscall(SYS_GETGID, 0, 0, 0)
+ gid = int(r0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getuid() (uid int) {
+ r0, _, _ := RawSyscall(SYS_GETUID, 0, 0, 0)
+ uid = int(r0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Lchown(path string, uid int, gid int) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_LCHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
+ use(unsafe.Pointer(_p0))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Listen(s int, n int) (err error) {
+ _, _, e1 := Syscall(SYS_LISTEN, uintptr(s), uintptr(n), 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Pread(fd int, p []byte, offset int64) (n int, err error) {
+ var _p0 unsafe.Pointer
+ if len(p) > 0 {
+ _p0 = unsafe.Pointer(&p[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall6(SYS_PREAD64, uintptr(fd), uintptr(_p0), uintptr(len(p)), 0, uintptr(offset>>32), uintptr(offset))
+ n = int(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Pwrite(fd int, p []byte, offset int64) (n int, err error) {
+ var _p0 unsafe.Pointer
+ if len(p) > 0 {
+ _p0 = unsafe.Pointer(&p[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall6(SYS_PWRITE64, uintptr(fd), uintptr(_p0), uintptr(len(p)), 0, uintptr(offset>>32), uintptr(offset))
+ n = int(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, err error) {
+ r0, _, e1 := Syscall6(SYS__NEWSELECT, uintptr(nfd), uintptr(unsafe.Pointer(r)), uintptr(unsafe.Pointer(w)), uintptr(unsafe.Pointer(e)), uintptr(unsafe.Pointer(timeout)), 0)
+ n = int(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) {
+ r0, _, e1 := Syscall6(SYS_SENDFILE64, uintptr(outfd), uintptr(infd), uintptr(unsafe.Pointer(offset)), uintptr(count), 0, 0)
+ written = int(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setfsgid(gid int) (err error) {
+ _, _, e1 := Syscall(SYS_SETFSGID, uintptr(gid), 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setfsuid(uid int) (err error) {
+ _, _, e1 := Syscall(SYS_SETFSUID, uintptr(uid), 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setregid(rgid int, egid int) (err error) {
+ _, _, e1 := RawSyscall(SYS_SETREGID, uintptr(rgid), uintptr(egid), 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setresgid(rgid int, egid int, sgid int) (err error) {
+ _, _, e1 := RawSyscall(SYS_SETRESGID, uintptr(rgid), uintptr(egid), uintptr(sgid))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setresuid(ruid int, euid int, suid int) (err error) {
+ _, _, e1 := RawSyscall(SYS_SETRESUID, uintptr(ruid), uintptr(euid), uintptr(suid))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setreuid(ruid int, euid int) (err error) {
+ _, _, e1 := RawSyscall(SYS_SETREUID, uintptr(ruid), uintptr(euid), 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Shutdown(fd int, how int) (err error) {
+ _, _, e1 := Syscall(SYS_SHUTDOWN, uintptr(fd), uintptr(how), 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int64, err error) {
+ r0, r1, e1 := Syscall6(SYS_SPLICE, uintptr(rfd), uintptr(unsafe.Pointer(roff)), uintptr(wfd), uintptr(unsafe.Pointer(woff)), uintptr(len), uintptr(flags))
+ n = int64(int64(r0)<<32 | int64(r1))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func SyncFileRange(fd int, off int64, n int64, flags int) (err error) {
+ _, _, e1 := Syscall9(SYS_SYNC_FILE_RANGE, uintptr(fd), 0, uintptr(off>>32), uintptr(off), uintptr(n>>32), uintptr(n), uintptr(flags), 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Truncate(path string, length int64) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := 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)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) {
+ r0, _, e1 := Syscall(SYS_ACCEPT, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
+ fd = int(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func accept4(s int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (fd int, err error) {
+ r0, _, e1 := Syscall6(SYS_ACCEPT4, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), uintptr(flags), 0, 0)
+ fd = int(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
+ _, _, e1 := Syscall(SYS_BIND, uintptr(s), uintptr(addr), uintptr(addrlen))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
+ _, _, e1 := Syscall(SYS_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func getgroups(n int, list *_Gid_t) (nn int, err error) {
+ r0, _, e1 := RawSyscall(SYS_GETGROUPS, uintptr(n), uintptr(unsafe.Pointer(list)), 0)
+ nn = int(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func setgroups(n int, list *_Gid_t) (err error) {
+ _, _, e1 := RawSyscall(SYS_SETGROUPS, uintptr(n), uintptr(unsafe.Pointer(list)), 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) {
+ _, _, e1 := Syscall6(SYS_GETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) {
+ _, _, e1 := Syscall6(SYS_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func socket(domain int, typ int, proto int) (fd int, err error) {
+ r0, _, e1 := RawSyscall(SYS_SOCKET, uintptr(domain), uintptr(typ), uintptr(proto))
+ fd = int(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func socketpair(domain int, typ int, proto int, fd *[2]int32) (err error) {
+ _, _, e1 := RawSyscall6(SYS_SOCKETPAIR, uintptr(domain), uintptr(typ), uintptr(proto), uintptr(unsafe.Pointer(fd)), 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
+ _, _, e1 := RawSyscall(SYS_GETPEERNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
+ _, _, e1 := RawSyscall(SYS_GETSOCKNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Socklen) (n int, err error) {
+ var _p0 unsafe.Pointer
+ if len(p) > 0 {
+ _p0 = unsafe.Pointer(&p[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall6(SYS_RECVFROM, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(flags), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen)))
+ n = int(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error) {
+ var _p0 unsafe.Pointer
+ if len(buf) > 0 {
+ _p0 = unsafe.Pointer(&buf[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ _, _, e1 := Syscall6(SYS_SENDTO, uintptr(s), uintptr(_p0), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(addrlen))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) {
+ r0, _, e1 := Syscall(SYS_RECVMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+ n = int(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func sendmsg(s int, msg *Msghdr, flags int) (n int, err error) {
+ r0, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+ n = int(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func InotifyInit() (fd int, err error) {
+ r0, _, e1 := RawSyscall(SYS_INOTIFY_INIT, 0, 0, 0)
+ fd = int(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Ioperm(from int, num int, on int) (err error) {
+ _, _, e1 := Syscall(SYS_IOPERM, uintptr(from), uintptr(num), uintptr(on))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Iopl(level int) (err error) {
+ _, _, e1 := Syscall(SYS_IOPL, uintptr(level), 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Gettimeofday(tv *Timeval) (err error) {
+ _, _, e1 := RawSyscall(SYS_GETTIMEOFDAY, uintptr(unsafe.Pointer(tv)), 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Time(t *Time_t) (tt Time_t, err error) {
+ r0, _, e1 := RawSyscall(SYS_TIME, uintptr(unsafe.Pointer(t)), 0, 0)
+ tt = Time_t(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Lstat(path string, stat *Stat_t) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_LSTAT64, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
+ use(unsafe.Pointer(_p0))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fstat(fd int, stat *Stat_t) (err error) {
+ _, _, e1 := Syscall(SYS_FSTAT64, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Stat(path string, stat *Stat_t) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_STAT64, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
+ use(unsafe.Pointer(_p0))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func 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 mmap2(addr uintptr, length uintptr, prot int, flags int, fd int, pageOffset uintptr) (xaddr uintptr, err error) {
+ r0, _, e1 := Syscall6(SYS_MMAP2, uintptr(addr), uintptr(length), uintptr(prot), uintptr(flags), uintptr(fd), uintptr(pageOffset))
+ xaddr = uintptr(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func getrlimit(resource int, rlim *rlimit32) (err error) {
+ _, _, e1 := RawSyscall(SYS_GETRLIMIT, uintptr(resource), uintptr(unsafe.Pointer(rlim)), 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func setrlimit(resource int, rlim *rlimit32) (err error) {
+ _, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(resource), uintptr(unsafe.Pointer(rlim)), 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
diff --git a/src/syscall/zsyscall_linux_mips64.go b/src/syscall/zsyscall_linux_mips64.go
index d1d5f24..b9708e3 100644
--- a/src/syscall/zsyscall_linux_mips64.go
+++ b/src/syscall/zsyscall_linux_mips64.go
@@ -761,8 +761,8 @@ func PivotRoot(newroot string, putold string) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func prlimit(pid int, resource int, old *Rlimit, newlimit *Rlimit) (err error) {
- _, _, e1 := RawSyscall6(SYS_PRLIMIT64, uintptr(pid), uintptr(resource), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(newlimit)), 0, 0)
+func prlimit(pid int, resource int, newlimit *Rlimit, old *Rlimit) (err error) {
+ _, _, e1 := RawSyscall6(SYS_PRLIMIT64, uintptr(pid), uintptr(resource), uintptr(unsafe.Pointer(newlimit)), uintptr(unsafe.Pointer(old)), 0, 0)
if e1 != 0 {
err = errnoErr(e1)
}
diff --git a/src/syscall/zsyscall_linux_mips64le.go b/src/syscall/zsyscall_linux_mips64le.go
index d1d5f24..b9708e3 100644
--- a/src/syscall/zsyscall_linux_mips64le.go
+++ b/src/syscall/zsyscall_linux_mips64le.go
@@ -761,8 +761,8 @@ func PivotRoot(newroot string, putold string) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func prlimit(pid int, resource int, old *Rlimit, newlimit *Rlimit) (err error) {
- _, _, e1 := RawSyscall6(SYS_PRLIMIT64, uintptr(pid), uintptr(resource), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(newlimit)), 0, 0)
+func prlimit(pid int, resource int, newlimit *Rlimit, old *Rlimit) (err error) {
+ _, _, e1 := RawSyscall6(SYS_PRLIMIT64, uintptr(pid), uintptr(resource), uintptr(unsafe.Pointer(newlimit)), uintptr(unsafe.Pointer(old)), 0, 0)
if e1 != 0 {
err = errnoErr(e1)
}
diff --git a/src/syscall/zsyscall_linux_mipsle.go b/src/syscall/zsyscall_linux_mipsle.go
new file mode 100644
index 0000000..527e3ef
--- /dev/null
+++ b/src/syscall/zsyscall_linux_mipsle.go
@@ -0,0 +1,1759 @@
+// mksyscall.pl -l32 -arm syscall_linux.go syscall_linux_mipsx.go
+// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+
+package syscall
+
+import "unsafe"
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func linkat(olddirfd int, oldpath string, newdirfd int, newpath string, flags int) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(oldpath)
+ if err != nil {
+ return
+ }
+ var _p1 *byte
+ _p1, err = BytePtrFromString(newpath)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall6(SYS_LINKAT, uintptr(olddirfd), uintptr(unsafe.Pointer(_p0)), uintptr(newdirfd), uintptr(unsafe.Pointer(_p1)), uintptr(flags), 0)
+ use(unsafe.Pointer(_p0))
+ use(unsafe.Pointer(_p1))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func openat(dirfd int, path string, flags int, mode uint32) (fd int, err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ r0, _, e1 := Syscall6(SYS_OPENAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(flags), uintptr(mode), 0, 0)
+ use(unsafe.Pointer(_p0))
+ fd = int(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func readlinkat(dirfd int, path string, buf []byte) (n int, err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ var _p1 unsafe.Pointer
+ if len(buf) > 0 {
+ _p1 = unsafe.Pointer(&buf[0])
+ } else {
+ _p1 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall6(SYS_READLINKAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(buf)), 0, 0)
+ use(unsafe.Pointer(_p0))
+ n = int(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func symlinkat(oldpath string, newdirfd int, newpath string) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(oldpath)
+ if err != nil {
+ return
+ }
+ var _p1 *byte
+ _p1, err = BytePtrFromString(newpath)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_SYMLINKAT, uintptr(unsafe.Pointer(_p0)), uintptr(newdirfd), uintptr(unsafe.Pointer(_p1)))
+ use(unsafe.Pointer(_p0))
+ use(unsafe.Pointer(_p1))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func unlinkat(dirfd int, path string, flags int) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_UNLINKAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(flags))
+ use(unsafe.Pointer(_p0))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func utimes(path string, times *[2]Timeval) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)), 0)
+ use(unsafe.Pointer(_p0))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func utimensat(dirfd int, path string, times *[2]Timespec) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_UTIMENSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)))
+ use(unsafe.Pointer(_p0))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func futimesat(dirfd int, path *byte, times *[2]Timeval) (err error) {
+ _, _, e1 := Syscall(SYS_FUTIMESAT, uintptr(dirfd), uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(times)))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getcwd(buf []byte) (n int, err error) {
+ var _p0 unsafe.Pointer
+ if len(buf) > 0 {
+ _p0 = unsafe.Pointer(&buf[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall(SYS_GETCWD, uintptr(_p0), uintptr(len(buf)), 0)
+ n = int(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, err error) {
+ r0, _, e1 := Syscall6(SYS_WAIT4, uintptr(pid), uintptr(unsafe.Pointer(wstatus)), uintptr(options), uintptr(unsafe.Pointer(rusage)), 0, 0)
+ wpid = int(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func ptrace(request int, pid int, addr uintptr, data uintptr) (err error) {
+ _, _, e1 := Syscall6(SYS_PTRACE, uintptr(request), uintptr(pid), uintptr(addr), uintptr(data), 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func reboot(magic1 uint, magic2 uint, cmd int, arg string) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(arg)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall6(SYS_REBOOT, uintptr(magic1), uintptr(magic2), uintptr(cmd), uintptr(unsafe.Pointer(_p0)), 0, 0)
+ use(unsafe.Pointer(_p0))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func mount(source string, target string, fstype string, flags uintptr, data *byte) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(source)
+ if err != nil {
+ return
+ }
+ var _p1 *byte
+ _p1, err = BytePtrFromString(target)
+ if err != nil {
+ return
+ }
+ var _p2 *byte
+ _p2, err = BytePtrFromString(fstype)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall6(SYS_MOUNT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(unsafe.Pointer(_p2)), uintptr(flags), uintptr(unsafe.Pointer(data)), 0)
+ use(unsafe.Pointer(_p0))
+ use(unsafe.Pointer(_p1))
+ use(unsafe.Pointer(_p2))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Acct(path string) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_ACCT, uintptr(unsafe.Pointer(_p0)), 0, 0)
+ use(unsafe.Pointer(_p0))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Adjtimex(buf *Timex) (state int, err error) {
+ r0, _, e1 := Syscall(SYS_ADJTIMEX, uintptr(unsafe.Pointer(buf)), 0, 0)
+ state = int(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Chdir(path string) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
+ use(unsafe.Pointer(_p0))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Chroot(path string) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(_p0)), 0, 0)
+ use(unsafe.Pointer(_p0))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Close(fd int) (err error) {
+ _, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Dup(oldfd int) (fd int, err error) {
+ r0, _, e1 := Syscall(SYS_DUP, uintptr(oldfd), 0, 0)
+ fd = int(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Dup3(oldfd int, newfd int, flags int) (err error) {
+ _, _, e1 := Syscall(SYS_DUP3, uintptr(oldfd), uintptr(newfd), uintptr(flags))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func EpollCreate(size int) (fd int, err error) {
+ r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE, uintptr(size), 0, 0)
+ fd = int(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func EpollCreate1(flag int) (fd int, err error) {
+ r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE1, uintptr(flag), 0, 0)
+ fd = int(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func EpollCtl(epfd int, op int, fd int, event *EpollEvent) (err error) {
+ _, _, e1 := RawSyscall6(SYS_EPOLL_CTL, uintptr(epfd), uintptr(op), uintptr(fd), uintptr(unsafe.Pointer(event)), 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) {
+ var _p0 unsafe.Pointer
+ if len(events) > 0 {
+ _p0 = unsafe.Pointer(&events[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall6(SYS_EPOLL_WAIT, uintptr(epfd), uintptr(_p0), uintptr(len(events)), uintptr(msec), 0, 0)
+ n = int(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Exit(code int) {
+ Syscall(SYS_EXIT_GROUP, uintptr(code), 0, 0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall6(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0)
+ use(unsafe.Pointer(_p0))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fallocate(fd int, mode uint32, off int64, len int64) (err error) {
+ _, _, e1 := Syscall6(SYS_FALLOCATE, uintptr(fd), uintptr(mode), uintptr(off), uintptr(off>>32), uintptr(len), uintptr(len>>32))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fchdir(fd int) (err error) {
+ _, _, e1 := Syscall(SYS_FCHDIR, uintptr(fd), 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fchmod(fd int, mode uint32) (err error) {
+ _, _, e1 := Syscall(SYS_FCHMOD, uintptr(fd), uintptr(mode), 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall6(SYS_FCHMODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0)
+ use(unsafe.Pointer(_p0))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall6(SYS_FCHOWNAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid), uintptr(flags), 0)
+ use(unsafe.Pointer(_p0))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func fcntl(fd int, cmd int, arg int) (val int, err error) {
+ r0, _, e1 := Syscall(SYS_FCNTL, uintptr(fd), uintptr(cmd), uintptr(arg))
+ val = int(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fdatasync(fd int) (err error) {
+ _, _, e1 := Syscall(SYS_FDATASYNC, uintptr(fd), 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Flock(fd int, how int) (err error) {
+ _, _, e1 := Syscall(SYS_FLOCK, uintptr(fd), uintptr(how), 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fsync(fd int) (err error) {
+ _, _, e1 := Syscall(SYS_FSYNC, uintptr(fd), 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getdents(fd int, buf []byte) (n int, err error) {
+ var _p0 unsafe.Pointer
+ if len(buf) > 0 {
+ _p0 = unsafe.Pointer(&buf[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall(_SYS_getdents, uintptr(fd), uintptr(_p0), uintptr(len(buf)))
+ n = int(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getpgid(pid int) (pgid int, err error) {
+ r0, _, e1 := RawSyscall(SYS_GETPGID, uintptr(pid), 0, 0)
+ pgid = int(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getpid() (pid int) {
+ r0, _, _ := RawSyscall(SYS_GETPID, 0, 0, 0)
+ pid = int(r0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getppid() (ppid int) {
+ r0, _, _ := RawSyscall(SYS_GETPPID, 0, 0, 0)
+ ppid = int(r0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getpriority(which int, who int) (prio int, err error) {
+ r0, _, e1 := Syscall(SYS_GETPRIORITY, uintptr(which), uintptr(who), 0)
+ prio = int(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getrusage(who int, rusage *Rusage) (err error) {
+ _, _, e1 := RawSyscall(SYS_GETRUSAGE, uintptr(who), uintptr(unsafe.Pointer(rusage)), 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Gettid() (tid int) {
+ r0, _, _ := RawSyscall(SYS_GETTID, 0, 0, 0)
+ tid = int(r0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getxattr(path string, attr string, dest []byte) (sz int, err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ var _p1 *byte
+ _p1, err = BytePtrFromString(attr)
+ if err != nil {
+ return
+ }
+ var _p2 unsafe.Pointer
+ if len(dest) > 0 {
+ _p2 = unsafe.Pointer(&dest[0])
+ } else {
+ _p2 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall6(SYS_GETXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(_p2), uintptr(len(dest)), 0, 0)
+ use(unsafe.Pointer(_p0))
+ use(unsafe.Pointer(_p1))
+ sz = int(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func InotifyAddWatch(fd int, pathname string, mask uint32) (watchdesc int, err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(pathname)
+ if err != nil {
+ return
+ }
+ r0, _, e1 := Syscall(SYS_INOTIFY_ADD_WATCH, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(mask))
+ use(unsafe.Pointer(_p0))
+ watchdesc = int(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func InotifyInit1(flags int) (fd int, err error) {
+ r0, _, e1 := RawSyscall(SYS_INOTIFY_INIT1, uintptr(flags), 0, 0)
+ fd = int(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func InotifyRmWatch(fd int, watchdesc uint32) (success int, err error) {
+ r0, _, e1 := RawSyscall(SYS_INOTIFY_RM_WATCH, uintptr(fd), uintptr(watchdesc), 0)
+ success = int(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Kill(pid int, sig Signal) (err error) {
+ _, _, e1 := RawSyscall(SYS_KILL, uintptr(pid), uintptr(sig), 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Klogctl(typ int, buf []byte) (n int, err error) {
+ var _p0 unsafe.Pointer
+ if len(buf) > 0 {
+ _p0 = unsafe.Pointer(&buf[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall(SYS_SYSLOG, uintptr(typ), uintptr(_p0), uintptr(len(buf)))
+ n = int(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Listxattr(path string, dest []byte) (sz int, err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ var _p1 unsafe.Pointer
+ if len(dest) > 0 {
+ _p1 = unsafe.Pointer(&dest[0])
+ } else {
+ _p1 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall(SYS_LISTXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(dest)))
+ use(unsafe.Pointer(_p0))
+ sz = int(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Mkdirat(dirfd int, path string, mode uint32) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_MKDIRAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode))
+ use(unsafe.Pointer(_p0))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Mknodat(dirfd int, path string, mode uint32, dev int) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall6(SYS_MKNODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev), 0, 0)
+ use(unsafe.Pointer(_p0))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Nanosleep(time *Timespec, leftover *Timespec) (err error) {
+ _, _, e1 := Syscall(SYS_NANOSLEEP, uintptr(unsafe.Pointer(time)), uintptr(unsafe.Pointer(leftover)), 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Pause() (err error) {
+ _, _, e1 := Syscall(SYS_PAUSE, 0, 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func PivotRoot(newroot string, putold string) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(newroot)
+ if err != nil {
+ return
+ }
+ var _p1 *byte
+ _p1, err = BytePtrFromString(putold)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_PIVOT_ROOT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0)
+ use(unsafe.Pointer(_p0))
+ use(unsafe.Pointer(_p1))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func prlimit(pid int, resource int, newlimit *Rlimit, old *Rlimit) (err error) {
+ _, _, e1 := RawSyscall6(SYS_PRLIMIT64, uintptr(pid), uintptr(resource), uintptr(unsafe.Pointer(newlimit)), uintptr(unsafe.Pointer(old)), 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func read(fd int, p []byte) (n int, err error) {
+ var _p0 unsafe.Pointer
+ if len(p) > 0 {
+ _p0 = unsafe.Pointer(&p[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(_p0), uintptr(len(p)))
+ n = int(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Removexattr(path string, attr string) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ var _p1 *byte
+ _p1, err = BytePtrFromString(attr)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_REMOVEXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0)
+ use(unsafe.Pointer(_p0))
+ use(unsafe.Pointer(_p1))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(oldpath)
+ if err != nil {
+ return
+ }
+ var _p1 *byte
+ _p1, err = BytePtrFromString(newpath)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall6(SYS_RENAMEAT, uintptr(olddirfd), uintptr(unsafe.Pointer(_p0)), uintptr(newdirfd), uintptr(unsafe.Pointer(_p1)), 0, 0)
+ use(unsafe.Pointer(_p0))
+ use(unsafe.Pointer(_p1))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setdomainname(p []byte) (err error) {
+ var _p0 unsafe.Pointer
+ if len(p) > 0 {
+ _p0 = unsafe.Pointer(&p[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ _, _, e1 := Syscall(SYS_SETDOMAINNAME, uintptr(_p0), uintptr(len(p)), 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Sethostname(p []byte) (err error) {
+ var _p0 unsafe.Pointer
+ if len(p) > 0 {
+ _p0 = unsafe.Pointer(&p[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ _, _, e1 := Syscall(SYS_SETHOSTNAME, uintptr(_p0), uintptr(len(p)), 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setpgid(pid int, pgid int) (err error) {
+ _, _, e1 := RawSyscall(SYS_SETPGID, uintptr(pid), uintptr(pgid), 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setsid() (pid int, err error) {
+ r0, _, e1 := RawSyscall(SYS_SETSID, 0, 0, 0)
+ pid = int(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Settimeofday(tv *Timeval) (err error) {
+ _, _, e1 := RawSyscall(SYS_SETTIMEOFDAY, uintptr(unsafe.Pointer(tv)), 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setpriority(which int, who int, prio int) (err error) {
+ _, _, e1 := Syscall(SYS_SETPRIORITY, uintptr(which), uintptr(who), uintptr(prio))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setxattr(path string, attr string, data []byte, flags int) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ var _p1 *byte
+ _p1, err = BytePtrFromString(attr)
+ if err != nil {
+ return
+ }
+ var _p2 unsafe.Pointer
+ if len(data) > 0 {
+ _p2 = unsafe.Pointer(&data[0])
+ } else {
+ _p2 = unsafe.Pointer(&_zero)
+ }
+ _, _, e1 := Syscall6(SYS_SETXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(_p2), uintptr(len(data)), uintptr(flags), 0)
+ use(unsafe.Pointer(_p0))
+ use(unsafe.Pointer(_p1))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Sync() {
+ Syscall(SYS_SYNC, 0, 0, 0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Sysinfo(info *Sysinfo_t) (err error) {
+ _, _, e1 := RawSyscall(SYS_SYSINFO, uintptr(unsafe.Pointer(info)), 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Tee(rfd int, wfd int, len int, flags int) (n int64, err error) {
+ r0, r1, e1 := Syscall6(SYS_TEE, uintptr(rfd), uintptr(wfd), uintptr(len), uintptr(flags), 0, 0)
+ n = int64(int64(r1)<<32 | int64(r0))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Tgkill(tgid int, tid int, sig Signal) (err error) {
+ _, _, e1 := RawSyscall(SYS_TGKILL, uintptr(tgid), uintptr(tid), uintptr(sig))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Times(tms *Tms) (ticks uintptr, err error) {
+ r0, _, e1 := RawSyscall(SYS_TIMES, uintptr(unsafe.Pointer(tms)), 0, 0)
+ ticks = uintptr(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Umask(mask int) (oldmask int) {
+ r0, _, _ := RawSyscall(SYS_UMASK, uintptr(mask), 0, 0)
+ oldmask = int(r0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Uname(buf *Utsname) (err error) {
+ _, _, e1 := RawSyscall(SYS_UNAME, uintptr(unsafe.Pointer(buf)), 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Unmount(target string, flags int) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(target)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_UMOUNT2, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
+ use(unsafe.Pointer(_p0))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Unshare(flags int) (err error) {
+ _, _, e1 := Syscall(SYS_UNSHARE, uintptr(flags), 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Ustat(dev int, ubuf *Ustat_t) (err error) {
+ _, _, e1 := Syscall(SYS_USTAT, uintptr(dev), uintptr(unsafe.Pointer(ubuf)), 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Utime(path string, buf *Utimbuf) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_UTIME, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(buf)), 0)
+ use(unsafe.Pointer(_p0))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func write(fd int, p []byte) (n int, err error) {
+ var _p0 unsafe.Pointer
+ if len(p) > 0 {
+ _p0 = unsafe.Pointer(&p[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)))
+ n = int(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func exitThread(code int) (err error) {
+ _, _, e1 := Syscall(SYS_EXIT, uintptr(code), 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func readlen(fd int, p *byte, np int) (n int, err error) {
+ r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(unsafe.Pointer(p)), uintptr(np))
+ n = int(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func writelen(fd int, p *byte, np int) (n int, err error) {
+ r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(unsafe.Pointer(p)), uintptr(np))
+ n = int(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func munmap(addr uintptr, length uintptr) (err error) {
+ _, _, e1 := Syscall(SYS_MUNMAP, uintptr(addr), uintptr(length), 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Madvise(b []byte, advice int) (err error) {
+ var _p0 unsafe.Pointer
+ if len(b) > 0 {
+ _p0 = unsafe.Pointer(&b[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ _, _, e1 := Syscall(SYS_MADVISE, uintptr(_p0), uintptr(len(b)), uintptr(advice))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Mprotect(b []byte, prot int) (err error) {
+ var _p0 unsafe.Pointer
+ if len(b) > 0 {
+ _p0 = unsafe.Pointer(&b[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ _, _, e1 := Syscall(SYS_MPROTECT, uintptr(_p0), uintptr(len(b)), uintptr(prot))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Mlock(b []byte) (err error) {
+ var _p0 unsafe.Pointer
+ if len(b) > 0 {
+ _p0 = unsafe.Pointer(&b[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ _, _, e1 := Syscall(SYS_MLOCK, uintptr(_p0), uintptr(len(b)), 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Munlock(b []byte) (err error) {
+ var _p0 unsafe.Pointer
+ if len(b) > 0 {
+ _p0 = unsafe.Pointer(&b[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ _, _, e1 := Syscall(SYS_MUNLOCK, uintptr(_p0), uintptr(len(b)), 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Mlockall(flags int) (err error) {
+ _, _, e1 := Syscall(SYS_MLOCKALL, uintptr(flags), 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Munlockall() (err error) {
+ _, _, e1 := Syscall(SYS_MUNLOCKALL, 0, 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Dup2(oldfd int, newfd int) (err error) {
+ _, _, e1 := Syscall(SYS_DUP2, uintptr(oldfd), uintptr(newfd), 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fchown(fd int, uid int, gid int) (err error) {
+ _, _, e1 := Syscall(SYS_FCHOWN, uintptr(fd), uintptr(uid), uintptr(gid))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Ftruncate(fd int, length int64) (err error) {
+ _, _, e1 := Syscall6(SYS_FTRUNCATE64, uintptr(fd), 0, uintptr(length), uintptr(length>>32), 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getegid() (egid int) {
+ r0, _, _ := RawSyscall(SYS_GETEGID, 0, 0, 0)
+ egid = int(r0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Geteuid() (euid int) {
+ r0, _, _ := RawSyscall(SYS_GETEUID, 0, 0, 0)
+ euid = int(r0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getgid() (gid int) {
+ r0, _, _ := RawSyscall(SYS_GETGID, 0, 0, 0)
+ gid = int(r0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getuid() (uid int) {
+ r0, _, _ := RawSyscall(SYS_GETUID, 0, 0, 0)
+ uid = int(r0)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Lchown(path string, uid int, gid int) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_LCHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
+ use(unsafe.Pointer(_p0))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Listen(s int, n int) (err error) {
+ _, _, e1 := Syscall(SYS_LISTEN, uintptr(s), uintptr(n), 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Pread(fd int, p []byte, offset int64) (n int, err error) {
+ var _p0 unsafe.Pointer
+ if len(p) > 0 {
+ _p0 = unsafe.Pointer(&p[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall6(SYS_PREAD64, uintptr(fd), uintptr(_p0), uintptr(len(p)), 0, uintptr(offset), uintptr(offset>>32))
+ n = int(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Pwrite(fd int, p []byte, offset int64) (n int, err error) {
+ var _p0 unsafe.Pointer
+ if len(p) > 0 {
+ _p0 = unsafe.Pointer(&p[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall6(SYS_PWRITE64, uintptr(fd), uintptr(_p0), uintptr(len(p)), 0, uintptr(offset), uintptr(offset>>32))
+ n = int(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, err error) {
+ r0, _, e1 := Syscall6(SYS__NEWSELECT, uintptr(nfd), uintptr(unsafe.Pointer(r)), uintptr(unsafe.Pointer(w)), uintptr(unsafe.Pointer(e)), uintptr(unsafe.Pointer(timeout)), 0)
+ n = int(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) {
+ r0, _, e1 := Syscall6(SYS_SENDFILE64, uintptr(outfd), uintptr(infd), uintptr(unsafe.Pointer(offset)), uintptr(count), 0, 0)
+ written = int(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setfsgid(gid int) (err error) {
+ _, _, e1 := Syscall(SYS_SETFSGID, uintptr(gid), 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setfsuid(uid int) (err error) {
+ _, _, e1 := Syscall(SYS_SETFSUID, uintptr(uid), 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setregid(rgid int, egid int) (err error) {
+ _, _, e1 := RawSyscall(SYS_SETREGID, uintptr(rgid), uintptr(egid), 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setresgid(rgid int, egid int, sgid int) (err error) {
+ _, _, e1 := RawSyscall(SYS_SETRESGID, uintptr(rgid), uintptr(egid), uintptr(sgid))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setresuid(ruid int, euid int, suid int) (err error) {
+ _, _, e1 := RawSyscall(SYS_SETRESUID, uintptr(ruid), uintptr(euid), uintptr(suid))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setreuid(ruid int, euid int) (err error) {
+ _, _, e1 := RawSyscall(SYS_SETREUID, uintptr(ruid), uintptr(euid), 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Shutdown(fd int, how int) (err error) {
+ _, _, e1 := Syscall(SYS_SHUTDOWN, uintptr(fd), uintptr(how), 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int64, err error) {
+ r0, r1, e1 := Syscall6(SYS_SPLICE, uintptr(rfd), uintptr(unsafe.Pointer(roff)), uintptr(wfd), uintptr(unsafe.Pointer(woff)), uintptr(len), uintptr(flags))
+ n = int64(int64(r1)<<32 | int64(r0))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func SyncFileRange(fd int, off int64, n int64, flags int) (err error) {
+ _, _, e1 := Syscall9(SYS_SYNC_FILE_RANGE, uintptr(fd), 0, uintptr(off), uintptr(off>>32), uintptr(n), uintptr(n>>32), uintptr(flags), 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Truncate(path string, length int64) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := 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)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) {
+ r0, _, e1 := Syscall(SYS_ACCEPT, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
+ fd = int(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func accept4(s int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (fd int, err error) {
+ r0, _, e1 := Syscall6(SYS_ACCEPT4, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), uintptr(flags), 0, 0)
+ fd = int(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
+ _, _, e1 := Syscall(SYS_BIND, uintptr(s), uintptr(addr), uintptr(addrlen))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
+ _, _, e1 := Syscall(SYS_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func getgroups(n int, list *_Gid_t) (nn int, err error) {
+ r0, _, e1 := RawSyscall(SYS_GETGROUPS, uintptr(n), uintptr(unsafe.Pointer(list)), 0)
+ nn = int(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func setgroups(n int, list *_Gid_t) (err error) {
+ _, _, e1 := RawSyscall(SYS_SETGROUPS, uintptr(n), uintptr(unsafe.Pointer(list)), 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) {
+ _, _, e1 := Syscall6(SYS_GETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) {
+ _, _, e1 := Syscall6(SYS_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func socket(domain int, typ int, proto int) (fd int, err error) {
+ r0, _, e1 := RawSyscall(SYS_SOCKET, uintptr(domain), uintptr(typ), uintptr(proto))
+ fd = int(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func socketpair(domain int, typ int, proto int, fd *[2]int32) (err error) {
+ _, _, e1 := RawSyscall6(SYS_SOCKETPAIR, uintptr(domain), uintptr(typ), uintptr(proto), uintptr(unsafe.Pointer(fd)), 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
+ _, _, e1 := RawSyscall(SYS_GETPEERNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
+ _, _, e1 := RawSyscall(SYS_GETSOCKNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Socklen) (n int, err error) {
+ var _p0 unsafe.Pointer
+ if len(p) > 0 {
+ _p0 = unsafe.Pointer(&p[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall6(SYS_RECVFROM, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(flags), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen)))
+ n = int(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error) {
+ var _p0 unsafe.Pointer
+ if len(buf) > 0 {
+ _p0 = unsafe.Pointer(&buf[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ _, _, e1 := Syscall6(SYS_SENDTO, uintptr(s), uintptr(_p0), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(addrlen))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) {
+ r0, _, e1 := Syscall(SYS_RECVMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+ n = int(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func sendmsg(s int, msg *Msghdr, flags int) (n int, err error) {
+ r0, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+ n = int(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func InotifyInit() (fd int, err error) {
+ r0, _, e1 := RawSyscall(SYS_INOTIFY_INIT, 0, 0, 0)
+ fd = int(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Ioperm(from int, num int, on int) (err error) {
+ _, _, e1 := Syscall(SYS_IOPERM, uintptr(from), uintptr(num), uintptr(on))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Iopl(level int) (err error) {
+ _, _, e1 := Syscall(SYS_IOPL, uintptr(level), 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Gettimeofday(tv *Timeval) (err error) {
+ _, _, e1 := RawSyscall(SYS_GETTIMEOFDAY, uintptr(unsafe.Pointer(tv)), 0, 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Time(t *Time_t) (tt Time_t, err error) {
+ r0, _, e1 := RawSyscall(SYS_TIME, uintptr(unsafe.Pointer(t)), 0, 0)
+ tt = Time_t(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Lstat(path string, stat *Stat_t) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_LSTAT64, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
+ use(unsafe.Pointer(_p0))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fstat(fd int, stat *Stat_t) (err error) {
+ _, _, e1 := Syscall(SYS_FSTAT64, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Stat(path string, stat *Stat_t) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_STAT64, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
+ use(unsafe.Pointer(_p0))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func 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 mmap2(addr uintptr, length uintptr, prot int, flags int, fd int, pageOffset uintptr) (xaddr uintptr, err error) {
+ r0, _, e1 := Syscall6(SYS_MMAP2, uintptr(addr), uintptr(length), uintptr(prot), uintptr(flags), uintptr(fd), uintptr(pageOffset))
+ xaddr = uintptr(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func getrlimit(resource int, rlim *rlimit32) (err error) {
+ _, _, e1 := RawSyscall(SYS_GETRLIMIT, uintptr(resource), uintptr(unsafe.Pointer(rlim)), 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func setrlimit(resource int, rlim *rlimit32) (err error) {
+ _, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(resource), uintptr(unsafe.Pointer(rlim)), 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
diff --git a/src/syscall/zsyscall_linux_ppc64.go b/src/syscall/zsyscall_linux_ppc64.go
index 352525f..b5315cd 100644
--- a/src/syscall/zsyscall_linux_ppc64.go
+++ b/src/syscall/zsyscall_linux_ppc64.go
@@ -763,8 +763,8 @@ func PivotRoot(newroot string, putold string) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func prlimit(pid int, resource int, old *Rlimit, newlimit *Rlimit) (err error) {
- _, _, e1 := RawSyscall6(SYS_PRLIMIT64, uintptr(pid), uintptr(resource), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(newlimit)), 0, 0)
+func prlimit(pid int, resource int, newlimit *Rlimit, old *Rlimit) (err error) {
+ _, _, e1 := RawSyscall6(SYS_PRLIMIT64, uintptr(pid), uintptr(resource), uintptr(unsafe.Pointer(newlimit)), uintptr(unsafe.Pointer(old)), 0, 0)
if e1 != 0 {
err = errnoErr(e1)
}
diff --git a/src/syscall/zsyscall_linux_ppc64le.go b/src/syscall/zsyscall_linux_ppc64le.go
index ac49c5c..501d680 100644
--- a/src/syscall/zsyscall_linux_ppc64le.go
+++ b/src/syscall/zsyscall_linux_ppc64le.go
@@ -763,8 +763,8 @@ func PivotRoot(newroot string, putold string) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func prlimit(pid int, resource int, old *Rlimit, newlimit *Rlimit) (err error) {
- _, _, e1 := RawSyscall6(SYS_PRLIMIT64, uintptr(pid), uintptr(resource), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(newlimit)), 0, 0)
+func prlimit(pid int, resource int, newlimit *Rlimit, old *Rlimit) (err error) {
+ _, _, e1 := RawSyscall6(SYS_PRLIMIT64, uintptr(pid), uintptr(resource), uintptr(unsafe.Pointer(newlimit)), uintptr(unsafe.Pointer(old)), 0, 0)
if e1 != 0 {
err = errnoErr(e1)
}
diff --git a/src/syscall/zsyscall_linux_s390x.go b/src/syscall/zsyscall_linux_s390x.go
index fd15366..b33ce68 100644
--- a/src/syscall/zsyscall_linux_s390x.go
+++ b/src/syscall/zsyscall_linux_s390x.go
@@ -761,8 +761,8 @@ func PivotRoot(newroot string, putold string) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func prlimit(pid int, resource int, old *Rlimit, newlimit *Rlimit) (err error) {
- _, _, e1 := RawSyscall6(SYS_PRLIMIT64, uintptr(pid), uintptr(resource), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(newlimit)), 0, 0)
+func prlimit(pid int, resource int, newlimit *Rlimit, old *Rlimit) (err error) {
+ _, _, e1 := RawSyscall6(SYS_PRLIMIT64, uintptr(pid), uintptr(resource), uintptr(unsafe.Pointer(newlimit)), uintptr(unsafe.Pointer(old)), 0, 0)
if e1 != 0 {
err = errnoErr(e1)
}
diff --git a/src/syscall/zsyscall_solaris_amd64.go b/src/syscall/zsyscall_solaris_amd64.go
index ebdeb92..8cc3740 100644
--- a/src/syscall/zsyscall_solaris_amd64.go
+++ b/src/syscall/zsyscall_solaris_amd64.go
@@ -12,7 +12,7 @@ import "unsafe"
//go:cgo_import_dynamic libc_setgroups setgroups "libc.so"
//go:cgo_import_dynamic libc_fcntl fcntl "libc.so"
//go:cgo_import_dynamic libc_accept accept "libsocket.so"
-//go:cgo_import_dynamic libc_sendmsg sendmsg "libsocket.so"
+//go:cgo_import_dynamic libc___xnet_sendmsg __xnet_sendmsg "libsocket.so"
//go:cgo_import_dynamic libc_Access access "libc.so"
//go:cgo_import_dynamic libc_Adjtime adjtime "libc.so"
//go:cgo_import_dynamic libc_Chdir chdir "libc.so"
@@ -40,7 +40,7 @@ import "unsafe"
//go:cgo_import_dynamic libc_Kill kill "libc.so"
//go:cgo_import_dynamic libc_Lchown lchown "libc.so"
//go:cgo_import_dynamic libc_Link link "libc.so"
-//go:cgo_import_dynamic libc_listen listen "libsocket.so"
+//go:cgo_import_dynamic libc___xnet_listen __xnet_listen "libsocket.so"
//go:cgo_import_dynamic libc_Lstat lstat "libc.so"
//go:cgo_import_dynamic libc_Mkdir mkdir "libc.so"
//go:cgo_import_dynamic libc_Mknod mknod "libc.so"
@@ -75,27 +75,28 @@ import "unsafe"
//go:cgo_import_dynamic libc_Umask umask "libc.so"
//go:cgo_import_dynamic libc_Unlink unlink "libc.so"
//go:cgo_import_dynamic libc_Utimes utimes "libc.so"
-//go:cgo_import_dynamic libc_bind bind "libsocket.so"
-//go:cgo_import_dynamic libc_connect connect "libsocket.so"
+//go:cgo_import_dynamic libc___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"
//go:cgo_import_dynamic libc_munmap munmap "libc.so"
-//go:cgo_import_dynamic libc_sendto sendto "libsocket.so"
-//go:cgo_import_dynamic libc_socket socket "libsocket.so"
-//go:cgo_import_dynamic libc_socketpair socketpair "libsocket.so"
+//go:cgo_import_dynamic libc___xnet_sendto __xnet_sendto "libsocket.so"
+//go:cgo_import_dynamic libc___xnet_socket __xnet_socket "libsocket.so"
+//go:cgo_import_dynamic libc___xnet_socketpair __xnet_socketpair "libsocket.so"
//go:cgo_import_dynamic libc_write write "libc.so"
-//go:cgo_import_dynamic libc_getsockopt getsockopt "libsocket.so"
+//go:cgo_import_dynamic libc___xnet_getsockopt __xnet_getsockopt "libsocket.so"
//go:cgo_import_dynamic libc_getpeername getpeername "libsocket.so"
//go:cgo_import_dynamic libc_getsockname getsockname "libsocket.so"
//go:cgo_import_dynamic libc_setsockopt setsockopt "libsocket.so"
//go:cgo_import_dynamic libc_recvfrom recvfrom "libsocket.so"
-//go:cgo_import_dynamic libc_recvmsg recvmsg "libsocket.so"
+//go:cgo_import_dynamic libc___xnet_recvmsg __xnet_recvmsg "libsocket.so"
+//go:cgo_import_dynamic libc_getexecname getexecname "libc.so"
//go:linkname libc_Getcwd libc_Getcwd
//go:linkname libc_getgroups libc_getgroups
//go:linkname libc_setgroups libc_setgroups
//go:linkname libc_fcntl libc_fcntl
//go:linkname libc_accept libc_accept
-//go:linkname libc_sendmsg libc_sendmsg
+//go:linkname libc___xnet_sendmsg libc___xnet_sendmsg
//go:linkname libc_Access libc_Access
//go:linkname libc_Adjtime libc_Adjtime
//go:linkname libc_Chdir libc_Chdir
@@ -123,7 +124,7 @@ import "unsafe"
//go:linkname libc_Kill libc_Kill
//go:linkname libc_Lchown libc_Lchown
//go:linkname libc_Link libc_Link
-//go:linkname libc_listen libc_listen
+//go:linkname libc___xnet_listen libc___xnet_listen
//go:linkname libc_Lstat libc_Lstat
//go:linkname libc_Mkdir libc_Mkdir
//go:linkname libc_Mknod libc_Mknod
@@ -158,20 +159,21 @@ import "unsafe"
//go:linkname libc_Umask libc_Umask
//go:linkname libc_Unlink libc_Unlink
//go:linkname libc_Utimes libc_Utimes
-//go:linkname libc_bind libc_bind
-//go:linkname libc_connect libc_connect
+//go:linkname libc___xnet_bind libc___xnet_bind
+//go:linkname libc___xnet_connect libc___xnet_connect
//go:linkname libc_mmap libc_mmap
//go:linkname libc_munmap libc_munmap
-//go:linkname libc_sendto libc_sendto
-//go:linkname libc_socket libc_socket
-//go:linkname libc_socketpair libc_socketpair
+//go:linkname libc___xnet_sendto libc___xnet_sendto
+//go:linkname libc___xnet_socket libc___xnet_socket
+//go:linkname libc___xnet_socketpair libc___xnet_socketpair
//go:linkname libc_write libc_write
-//go:linkname libc_getsockopt libc_getsockopt
+//go:linkname libc___xnet_getsockopt libc___xnet_getsockopt
//go:linkname libc_getpeername libc_getpeername
//go:linkname libc_getsockname libc_getsockname
//go:linkname libc_setsockopt libc_setsockopt
//go:linkname libc_recvfrom libc_recvfrom
-//go:linkname libc_recvmsg libc_recvmsg
+//go:linkname libc___xnet_recvmsg libc___xnet_recvmsg
+//go:linkname libc_getexecname libc_getexecname
type libcFunc uintptr
@@ -181,7 +183,7 @@ var (
libc_setgroups,
libc_fcntl,
libc_accept,
- libc_sendmsg,
+ libc___xnet_sendmsg,
libc_Access,
libc_Adjtime,
libc_Chdir,
@@ -209,7 +211,7 @@ var (
libc_Kill,
libc_Lchown,
libc_Link,
- libc_listen,
+ libc___xnet_listen,
libc_Lstat,
libc_Mkdir,
libc_Mknod,
@@ -244,20 +246,21 @@ var (
libc_Umask,
libc_Unlink,
libc_Utimes,
- libc_bind,
- libc_connect,
+ libc___xnet_bind,
+ libc___xnet_connect,
libc_mmap,
libc_munmap,
- libc_sendto,
- libc_socket,
- libc_socketpair,
+ libc___xnet_sendto,
+ libc___xnet_socket,
+ libc___xnet_socketpair,
libc_write,
- libc_getsockopt,
+ libc___xnet_getsockopt,
libc_getpeername,
libc_getsockname,
libc_setsockopt,
libc_recvfrom,
- libc_recvmsg libcFunc
+ libc___xnet_recvmsg,
+ libc_getexecname libcFunc
)
func Getcwd(buf []byte) (n int, err error) {
@@ -309,7 +312,7 @@ func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) {
}
func sendmsg(s int, msg *Msghdr, flags int) (n int, err error) {
- r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_sendmsg)), 3, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags), 0, 0, 0)
+ r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc___xnet_sendmsg)), 3, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags), 0, 0, 0)
n = int(r0)
if e1 != 0 {
err = errnoErr(e1)
@@ -575,7 +578,7 @@ func Link(path string, link string) (err error) {
}
func Listen(s int, backlog int) (err error) {
- _, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_listen)), 2, uintptr(s), uintptr(backlog), 0, 0, 0, 0)
+ _, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc___xnet_listen)), 2, uintptr(s), uintptr(backlog), 0, 0, 0, 0)
if e1 != 0 {
err = errnoErr(e1)
}
@@ -953,7 +956,7 @@ func Unlink(path string) (err error) {
return
}
-func Utimes(path string, times *[2]Timeval) (err error) {
+func utimes(path string, times *[2]Timeval) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
if err != nil {
@@ -968,7 +971,7 @@ func Utimes(path string, times *[2]Timeval) (err error) {
}
func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
- _, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_bind)), 3, uintptr(s), uintptr(addr), uintptr(addrlen), 0, 0, 0)
+ _, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc___xnet_bind)), 3, uintptr(s), uintptr(addr), uintptr(addrlen), 0, 0, 0)
if e1 != 0 {
err = errnoErr(e1)
}
@@ -976,7 +979,7 @@ func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
}
func connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
- _, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_connect)), 3, uintptr(s), uintptr(addr), uintptr(addrlen), 0, 0, 0)
+ _, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc___xnet_connect)), 3, uintptr(s), uintptr(addr), uintptr(addrlen), 0, 0, 0)
if e1 != 0 {
err = errnoErr(e1)
}
@@ -1005,7 +1008,7 @@ func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (
if len(buf) > 0 {
_p0 = &buf[0]
}
- _, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_sendto)), 6, uintptr(s), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(addrlen))
+ _, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc___xnet_sendto)), 6, uintptr(s), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(addrlen))
if e1 != 0 {
err = errnoErr(e1)
}
@@ -1013,7 +1016,7 @@ func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (
}
func socket(domain int, typ int, proto int) (fd int, err error) {
- r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_socket)), 3, uintptr(domain), uintptr(typ), uintptr(proto), 0, 0, 0)
+ r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc___xnet_socket)), 3, uintptr(domain), uintptr(typ), uintptr(proto), 0, 0, 0)
fd = int(r0)
if e1 != 0 {
err = errnoErr(e1)
@@ -1022,7 +1025,7 @@ func socket(domain int, typ int, proto int) (fd int, err error) {
}
func socketpair(domain int, typ int, proto int, fd *[2]int32) (err error) {
- _, _, e1 := rawSysvicall6(uintptr(unsafe.Pointer(&libc_socketpair)), 4, uintptr(domain), uintptr(typ), uintptr(proto), uintptr(unsafe.Pointer(fd)), 0, 0)
+ _, _, e1 := rawSysvicall6(uintptr(unsafe.Pointer(&libc___xnet_socketpair)), 4, uintptr(domain), uintptr(typ), uintptr(proto), uintptr(unsafe.Pointer(fd)), 0, 0)
if e1 != 0 {
err = errnoErr(e1)
}
@@ -1043,7 +1046,7 @@ func write(fd int, p []byte) (n int, err error) {
}
func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) {
- _, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_getsockopt)), 5, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0)
+ _, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc___xnet_getsockopt)), 5, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0)
if e1 != 0 {
err = errnoErr(e1)
}
@@ -1088,10 +1091,19 @@ func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Sockl
}
func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) {
- r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_recvmsg)), 3, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags), 0, 0, 0)
+ r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc___xnet_recvmsg)), 3, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags), 0, 0, 0)
n = int(r0)
if e1 != 0 {
err = errnoErr(e1)
}
return
}
+
+func getexecname() (path unsafe.Pointer, err error) {
+ r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_getexecname)), 0, 0, 0, 0, 0, 0, 0)
+ path = unsafe.Pointer(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
diff --git a/src/syscall/zsyscall_windows.go b/src/syscall/zsyscall_windows.go
index bb3e892..2283c79 100644
--- a/src/syscall/zsyscall_windows.go
+++ b/src/syscall/zsyscall_windows.go
@@ -9,6 +9,31 @@ import (
var _ unsafe.Pointer
+// Do the interface allocations only once for common
+// Errno values.
+const (
+ errnoERROR_IO_PENDING = 997
+)
+
+var (
+ errERROR_IO_PENDING error = Errno(errnoERROR_IO_PENDING)
+)
+
+// errnoErr returns common boxed Errno values, to prevent
+// allocations at runtime.
+func errnoErr(e Errno) error {
+ switch e {
+ case 0:
+ return nil
+ case errnoERROR_IO_PENDING:
+ return errERROR_IO_PENDING
+ }
+ // TODO: add more here, after collecting data on the common
+ // error values see on Windows. (perhaps when running
+ // all.bat?)
+ return e
+}
+
var (
modkernel32 = NewLazyDLL(sysdll.Add("kernel32.dll"))
modadvapi32 = NewLazyDLL(sysdll.Add("advapi32.dll"))
@@ -188,7 +213,7 @@ func _LoadLibrary(libname *uint16) (handle Handle, err error) {
handle = Handle(r0)
if handle == 0 {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -200,7 +225,7 @@ func FreeLibrary(handle Handle) (err error) {
r1, _, e1 := Syscall(procFreeLibrary.Addr(), 1, uintptr(handle), 0, 0)
if r1 == 0 {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -222,7 +247,7 @@ func _GetProcAddress(module Handle, procname *byte) (proc uintptr, err error) {
proc = uintptr(r0)
if proc == 0 {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -235,7 +260,7 @@ func GetVersion() (ver uint32, err error) {
ver = uint32(r0)
if ver == 0 {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -252,7 +277,7 @@ func formatMessage(flags uint32, msgsrc uintptr, msgid uint32, langid uint32, bu
n = uint32(r0)
if n == 0 {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -270,7 +295,7 @@ func CreateFile(name *uint16, access uint32, mode uint32, sa *SecurityAttributes
handle = Handle(r0)
if handle == InvalidHandle {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -286,7 +311,7 @@ func ReadFile(handle Handle, buf []byte, done *uint32, overlapped *Overlapped) (
r1, _, e1 := Syscall6(procReadFile.Addr(), 5, uintptr(handle), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), uintptr(unsafe.Pointer(done)), uintptr(unsafe.Pointer(overlapped)), 0)
if r1 == 0 {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -302,7 +327,7 @@ func WriteFile(handle Handle, buf []byte, done *uint32, overlapped *Overlapped)
r1, _, e1 := Syscall6(procWriteFile.Addr(), 5, uintptr(handle), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), uintptr(unsafe.Pointer(done)), uintptr(unsafe.Pointer(overlapped)), 0)
if r1 == 0 {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -315,7 +340,7 @@ func SetFilePointer(handle Handle, lowoffset int32, highoffsetptr *int32, whence
newlowoffset = uint32(r0)
if newlowoffset == 0xffffffff {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -327,7 +352,7 @@ func CloseHandle(handle Handle) (err error) {
r1, _, e1 := Syscall(procCloseHandle.Addr(), 1, uintptr(handle), 0, 0)
if r1 == 0 {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -340,7 +365,7 @@ func GetStdHandle(stdhandle int) (handle Handle, err error) {
handle = Handle(r0)
if handle == InvalidHandle {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -353,7 +378,7 @@ func findFirstFile1(name *uint16, data *win32finddata1) (handle Handle, err erro
handle = Handle(r0)
if handle == InvalidHandle {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -365,7 +390,7 @@ func findNextFile1(handle Handle, data *win32finddata1) (err error) {
r1, _, e1 := Syscall(procFindNextFileW.Addr(), 2, uintptr(handle), uintptr(unsafe.Pointer(data)), 0)
if r1 == 0 {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -377,7 +402,7 @@ func FindClose(handle Handle) (err error) {
r1, _, e1 := Syscall(procFindClose.Addr(), 1, uintptr(handle), 0, 0)
if r1 == 0 {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -389,7 +414,7 @@ func GetFileInformationByHandle(handle Handle, data *ByHandleFileInformation) (e
r1, _, e1 := Syscall(procGetFileInformationByHandle.Addr(), 2, uintptr(handle), uintptr(unsafe.Pointer(data)), 0)
if r1 == 0 {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -402,7 +427,7 @@ func GetCurrentDirectory(buflen uint32, buf *uint16) (n uint32, err error) {
n = uint32(r0)
if n == 0 {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -414,7 +439,7 @@ func SetCurrentDirectory(path *uint16) (err error) {
r1, _, e1 := Syscall(procSetCurrentDirectoryW.Addr(), 1, uintptr(unsafe.Pointer(path)), 0, 0)
if r1 == 0 {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -426,7 +451,7 @@ func CreateDirectory(path *uint16, sa *SecurityAttributes) (err error) {
r1, _, e1 := Syscall(procCreateDirectoryW.Addr(), 2, uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(sa)), 0)
if r1 == 0 {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -438,7 +463,7 @@ func RemoveDirectory(path *uint16) (err error) {
r1, _, e1 := Syscall(procRemoveDirectoryW.Addr(), 1, uintptr(unsafe.Pointer(path)), 0, 0)
if r1 == 0 {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -450,7 +475,7 @@ func DeleteFile(path *uint16) (err error) {
r1, _, e1 := Syscall(procDeleteFileW.Addr(), 1, uintptr(unsafe.Pointer(path)), 0, 0)
if r1 == 0 {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -462,7 +487,7 @@ func MoveFile(from *uint16, to *uint16) (err error) {
r1, _, e1 := Syscall(procMoveFileW.Addr(), 2, uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(to)), 0)
if r1 == 0 {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -474,7 +499,7 @@ func GetComputerName(buf *uint16, n *uint32) (err error) {
r1, _, e1 := Syscall(procGetComputerNameW.Addr(), 2, uintptr(unsafe.Pointer(buf)), uintptr(unsafe.Pointer(n)), 0)
if r1 == 0 {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -486,7 +511,7 @@ func SetEndOfFile(handle Handle) (err error) {
r1, _, e1 := Syscall(procSetEndOfFile.Addr(), 1, uintptr(handle), 0, 0)
if r1 == 0 {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -504,7 +529,7 @@ func GetTimeZoneInformation(tzi *Timezoneinformation) (rc uint32, err error) {
rc = uint32(r0)
if rc == 0xffffffff {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -517,7 +542,7 @@ func CreateIoCompletionPort(filehandle Handle, cphandle Handle, key uint32, thre
handle = Handle(r0)
if handle == 0 {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -529,7 +554,7 @@ func GetQueuedCompletionStatus(cphandle Handle, qty *uint32, key *uint32, overla
r1, _, e1 := Syscall6(procGetQueuedCompletionStatus.Addr(), 5, uintptr(cphandle), uintptr(unsafe.Pointer(qty)), uintptr(unsafe.Pointer(key)), uintptr(unsafe.Pointer(overlapped)), uintptr(timeout), 0)
if r1 == 0 {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -541,7 +566,7 @@ func PostQueuedCompletionStatus(cphandle Handle, qty uint32, key uint32, overlap
r1, _, e1 := Syscall6(procPostQueuedCompletionStatus.Addr(), 4, uintptr(cphandle), uintptr(qty), uintptr(key), uintptr(unsafe.Pointer(overlapped)), 0, 0)
if r1 == 0 {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -553,7 +578,7 @@ func CancelIo(s Handle) (err error) {
r1, _, e1 := Syscall(procCancelIo.Addr(), 1, uintptr(s), 0, 0)
if r1 == 0 {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -565,7 +590,7 @@ func CancelIoEx(s Handle, o *Overlapped) (err error) {
r1, _, e1 := Syscall(procCancelIoEx.Addr(), 2, uintptr(s), uintptr(unsafe.Pointer(o)), 0)
if r1 == 0 {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -583,7 +608,7 @@ func CreateProcess(appName *uint16, commandLine *uint16, procSecurity *SecurityA
r1, _, e1 := Syscall12(procCreateProcessW.Addr(), 10, uintptr(unsafe.Pointer(appName)), uintptr(unsafe.Pointer(commandLine)), uintptr(unsafe.Pointer(procSecurity)), uintptr(unsafe.Pointer(threadSecurity)), uintptr(_p0), uintptr(creationFlags), uintptr(unsafe.Pointer(env)), uintptr(unsafe.Pointer(currentDir)), uintptr(unsafe.Pointer(startupInfo)), uintptr(unsafe.Pointer(outProcInfo)), 0, 0)
if r1 == 0 {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -602,7 +627,7 @@ func OpenProcess(da uint32, inheritHandle bool, pid uint32) (handle Handle, err
handle = Handle(r0)
if handle == 0 {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -614,7 +639,7 @@ func TerminateProcess(handle Handle, exitcode uint32) (err error) {
r1, _, e1 := Syscall(procTerminateProcess.Addr(), 2, uintptr(handle), uintptr(exitcode), 0)
if r1 == 0 {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -626,7 +651,7 @@ func GetExitCodeProcess(handle Handle, exitcode *uint32) (err error) {
r1, _, e1 := Syscall(procGetExitCodeProcess.Addr(), 2, uintptr(handle), uintptr(unsafe.Pointer(exitcode)), 0)
if r1 == 0 {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -638,7 +663,7 @@ func GetStartupInfo(startupInfo *StartupInfo) (err error) {
r1, _, e1 := Syscall(procGetStartupInfoW.Addr(), 1, uintptr(unsafe.Pointer(startupInfo)), 0, 0)
if r1 == 0 {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -651,7 +676,7 @@ func GetCurrentProcess() (pseudoHandle Handle, err error) {
pseudoHandle = Handle(r0)
if pseudoHandle == 0 {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -663,7 +688,7 @@ func GetProcessTimes(handle Handle, creationTime *Filetime, exitTime *Filetime,
r1, _, e1 := Syscall6(procGetProcessTimes.Addr(), 5, uintptr(handle), uintptr(unsafe.Pointer(creationTime)), uintptr(unsafe.Pointer(exitTime)), uintptr(unsafe.Pointer(kernelTime)), uintptr(unsafe.Pointer(userTime)), 0)
if r1 == 0 {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -681,7 +706,7 @@ func DuplicateHandle(hSourceProcessHandle Handle, hSourceHandle Handle, hTargetP
r1, _, e1 := Syscall9(procDuplicateHandle.Addr(), 7, uintptr(hSourceProcessHandle), uintptr(hSourceHandle), uintptr(hTargetProcessHandle), uintptr(unsafe.Pointer(lpTargetHandle)), uintptr(dwDesiredAccess), uintptr(_p0), uintptr(dwOptions), 0, 0)
if r1 == 0 {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -694,7 +719,7 @@ func WaitForSingleObject(handle Handle, waitMilliseconds uint32) (event uint32,
event = uint32(r0)
if event == 0xffffffff {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -707,7 +732,7 @@ func GetTempPath(buflen uint32, buf *uint16) (n uint32, err error) {
n = uint32(r0)
if n == 0 {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -719,7 +744,7 @@ func CreatePipe(readhandle *Handle, writehandle *Handle, sa *SecurityAttributes,
r1, _, e1 := Syscall6(procCreatePipe.Addr(), 4, uintptr(unsafe.Pointer(readhandle)), uintptr(unsafe.Pointer(writehandle)), uintptr(unsafe.Pointer(sa)), uintptr(size), 0, 0)
if r1 == 0 {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -732,7 +757,7 @@ func GetFileType(filehandle Handle) (n uint32, err error) {
n = uint32(r0)
if n == 0 {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -744,7 +769,7 @@ func CryptAcquireContext(provhandle *Handle, container *uint16, provider *uint16
r1, _, e1 := Syscall6(procCryptAcquireContextW.Addr(), 5, uintptr(unsafe.Pointer(provhandle)), uintptr(unsafe.Pointer(container)), uintptr(unsafe.Pointer(provider)), uintptr(provtype), uintptr(flags), 0)
if r1 == 0 {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -756,7 +781,7 @@ func CryptReleaseContext(provhandle Handle, flags uint32) (err error) {
r1, _, e1 := Syscall(procCryptReleaseContext.Addr(), 2, uintptr(provhandle), uintptr(flags), 0)
if r1 == 0 {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -768,7 +793,7 @@ func CryptGenRandom(provhandle Handle, buflen uint32, buf *byte) (err error) {
r1, _, e1 := Syscall(procCryptGenRandom.Addr(), 3, uintptr(provhandle), uintptr(buflen), uintptr(unsafe.Pointer(buf)))
if r1 == 0 {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -781,7 +806,7 @@ func GetEnvironmentStrings() (envs *uint16, err error) {
envs = (*uint16)(unsafe.Pointer(r0))
if envs == nil {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -793,7 +818,7 @@ func FreeEnvironmentStrings(envs *uint16) (err error) {
r1, _, e1 := Syscall(procFreeEnvironmentStringsW.Addr(), 1, uintptr(unsafe.Pointer(envs)), 0, 0)
if r1 == 0 {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -806,7 +831,7 @@ func GetEnvironmentVariable(name *uint16, buffer *uint16, size uint32) (n uint32
n = uint32(r0)
if n == 0 {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -818,7 +843,7 @@ func SetEnvironmentVariable(name *uint16, value *uint16) (err error) {
r1, _, e1 := Syscall(procSetEnvironmentVariableW.Addr(), 2, uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(value)), 0)
if r1 == 0 {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -830,7 +855,7 @@ func SetFileTime(handle Handle, ctime *Filetime, atime *Filetime, wtime *Filetim
r1, _, e1 := Syscall6(procSetFileTime.Addr(), 4, uintptr(handle), uintptr(unsafe.Pointer(ctime)), uintptr(unsafe.Pointer(atime)), uintptr(unsafe.Pointer(wtime)), 0, 0)
if r1 == 0 {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -843,7 +868,7 @@ func GetFileAttributes(name *uint16) (attrs uint32, err error) {
attrs = uint32(r0)
if attrs == INVALID_FILE_ATTRIBUTES {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -855,7 +880,7 @@ func SetFileAttributes(name *uint16, attrs uint32) (err error) {
r1, _, e1 := Syscall(procSetFileAttributesW.Addr(), 2, uintptr(unsafe.Pointer(name)), uintptr(attrs), 0)
if r1 == 0 {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -867,7 +892,7 @@ func GetFileAttributesEx(name *uint16, level uint32, info *byte) (err error) {
r1, _, e1 := Syscall(procGetFileAttributesExW.Addr(), 3, uintptr(unsafe.Pointer(name)), uintptr(level), uintptr(unsafe.Pointer(info)))
if r1 == 0 {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -886,7 +911,7 @@ func CommandLineToArgv(cmd *uint16, argc *int32) (argv *[8192]*[8192]uint16, err
argv = (*[8192]*[8192]uint16)(unsafe.Pointer(r0))
if argv == nil {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -899,7 +924,7 @@ func LocalFree(hmem Handle) (handle Handle, err error) {
handle = Handle(r0)
if handle != 0 {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -911,7 +936,7 @@ func SetHandleInformation(handle Handle, mask uint32, flags uint32) (err error)
r1, _, e1 := Syscall(procSetHandleInformation.Addr(), 3, uintptr(handle), uintptr(mask), uintptr(flags))
if r1 == 0 {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -923,7 +948,7 @@ func FlushFileBuffers(handle Handle) (err error) {
r1, _, e1 := Syscall(procFlushFileBuffers.Addr(), 1, uintptr(handle), 0, 0)
if r1 == 0 {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -936,7 +961,7 @@ func GetFullPathName(path *uint16, buflen uint32, buf *uint16, fname **uint16) (
n = uint32(r0)
if n == 0 {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -949,7 +974,7 @@ func GetLongPathName(path *uint16, buf *uint16, buflen uint32) (n uint32, err er
n = uint32(r0)
if n == 0 {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -962,7 +987,7 @@ func GetShortPathName(longpath *uint16, shortpath *uint16, buflen uint32) (n uin
n = uint32(r0)
if n == 0 {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -975,7 +1000,7 @@ func CreateFileMapping(fhandle Handle, sa *SecurityAttributes, prot uint32, maxS
handle = Handle(r0)
if handle == 0 {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -988,7 +1013,7 @@ func MapViewOfFile(handle Handle, access uint32, offsetHigh uint32, offsetLow ui
addr = uintptr(r0)
if addr == 0 {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -1000,7 +1025,7 @@ func UnmapViewOfFile(addr uintptr) (err error) {
r1, _, e1 := Syscall(procUnmapViewOfFile.Addr(), 1, uintptr(addr), 0, 0)
if r1 == 0 {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -1012,7 +1037,7 @@ func FlushViewOfFile(addr uintptr, length uintptr) (err error) {
r1, _, e1 := Syscall(procFlushViewOfFile.Addr(), 2, uintptr(addr), uintptr(length), 0)
if r1 == 0 {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -1024,7 +1049,7 @@ func VirtualLock(addr uintptr, length uintptr) (err error) {
r1, _, e1 := Syscall(procVirtualLock.Addr(), 2, uintptr(addr), uintptr(length), 0)
if r1 == 0 {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -1036,7 +1061,7 @@ func VirtualUnlock(addr uintptr, length uintptr) (err error) {
r1, _, e1 := Syscall(procVirtualUnlock.Addr(), 2, uintptr(addr), uintptr(length), 0)
if r1 == 0 {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -1048,7 +1073,7 @@ func TransmitFile(s Handle, handle Handle, bytesToWrite uint32, bytsPerSend uint
r1, _, e1 := Syscall9(procTransmitFile.Addr(), 7, uintptr(s), uintptr(handle), uintptr(bytesToWrite), uintptr(bytsPerSend), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(transmitFileBuf)), uintptr(flags), 0, 0)
if r1 == 0 {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -1066,7 +1091,7 @@ func ReadDirectoryChanges(handle Handle, buf *byte, buflen uint32, watchSubTree
r1, _, e1 := Syscall9(procReadDirectoryChangesW.Addr(), 8, uintptr(handle), uintptr(unsafe.Pointer(buf)), uintptr(buflen), uintptr(_p0), uintptr(mask), uintptr(unsafe.Pointer(retlen)), uintptr(unsafe.Pointer(overlapped)), uintptr(completionRoutine), 0)
if r1 == 0 {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -1079,7 +1104,7 @@ func CertOpenSystemStore(hprov Handle, name *uint16) (store Handle, err error) {
store = Handle(r0)
if store == 0 {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -1092,7 +1117,7 @@ func CertOpenStore(storeProvider uintptr, msgAndCertEncodingType uint32, cryptPr
handle = Handle(r0)
if handle == InvalidHandle {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -1105,7 +1130,7 @@ func CertEnumCertificatesInStore(store Handle, prevContext *CertContext) (contex
context = (*CertContext)(unsafe.Pointer(r0))
if context == nil {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -1117,7 +1142,7 @@ func CertAddCertificateContextToStore(store Handle, certContext *CertContext, ad
r1, _, e1 := Syscall6(procCertAddCertificateContextToStore.Addr(), 4, uintptr(store), uintptr(unsafe.Pointer(certContext)), uintptr(addDisposition), uintptr(unsafe.Pointer(storeContext)), 0, 0)
if r1 == 0 {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -1129,7 +1154,7 @@ func CertCloseStore(store Handle, flags uint32) (err error) {
r1, _, e1 := Syscall(procCertCloseStore.Addr(), 2, uintptr(store), uintptr(flags), 0)
if r1 == 0 {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -1141,7 +1166,7 @@ func CertGetCertificateChain(engine Handle, leaf *CertContext, time *Filetime, a
r1, _, e1 := Syscall9(procCertGetCertificateChain.Addr(), 8, uintptr(engine), uintptr(unsafe.Pointer(leaf)), uintptr(unsafe.Pointer(time)), uintptr(additionalStore), uintptr(unsafe.Pointer(para)), uintptr(flags), uintptr(reserved), uintptr(unsafe.Pointer(chainCtx)), 0)
if r1 == 0 {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -1159,7 +1184,7 @@ func CertCreateCertificateContext(certEncodingType uint32, certEncoded *byte, en
context = (*CertContext)(unsafe.Pointer(r0))
if context == nil {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -1171,7 +1196,7 @@ func CertFreeCertificateContext(ctx *CertContext) (err error) {
r1, _, e1 := Syscall(procCertFreeCertificateContext.Addr(), 1, uintptr(unsafe.Pointer(ctx)), 0, 0)
if r1 == 0 {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -1183,7 +1208,7 @@ func CertVerifyCertificateChainPolicy(policyOID uintptr, chain *CertChainContext
r1, _, e1 := Syscall6(procCertVerifyCertificateChainPolicy.Addr(), 4, uintptr(policyOID), uintptr(unsafe.Pointer(chain)), uintptr(unsafe.Pointer(para)), uintptr(unsafe.Pointer(status)), 0, 0)
if r1 == 0 {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -1241,7 +1266,7 @@ func GetConsoleMode(console Handle, mode *uint32) (err error) {
r1, _, e1 := Syscall(procGetConsoleMode.Addr(), 2, uintptr(console), uintptr(unsafe.Pointer(mode)), 0)
if r1 == 0 {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -1253,7 +1278,7 @@ func WriteConsole(console Handle, buf *uint16, towrite uint32, written *uint32,
r1, _, e1 := Syscall6(procWriteConsoleW.Addr(), 5, uintptr(console), uintptr(unsafe.Pointer(buf)), uintptr(towrite), uintptr(unsafe.Pointer(written)), uintptr(unsafe.Pointer(reserved)), 0)
if r1 == 0 {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -1265,7 +1290,7 @@ func ReadConsole(console Handle, buf *uint16, toread uint32, read *uint32, input
r1, _, e1 := Syscall6(procReadConsoleW.Addr(), 5, uintptr(console), uintptr(unsafe.Pointer(buf)), uintptr(toread), uintptr(unsafe.Pointer(read)), uintptr(unsafe.Pointer(inputControl)), 0)
if r1 == 0 {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -1278,7 +1303,7 @@ func CreateToolhelp32Snapshot(flags uint32, processId uint32) (handle Handle, er
handle = Handle(r0)
if handle == InvalidHandle {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -1290,7 +1315,7 @@ func Process32First(snapshot Handle, procEntry *ProcessEntry32) (err error) {
r1, _, e1 := Syscall(procProcess32FirstW.Addr(), 2, uintptr(snapshot), uintptr(unsafe.Pointer(procEntry)), 0)
if r1 == 0 {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -1302,7 +1327,7 @@ func Process32Next(snapshot Handle, procEntry *ProcessEntry32) (err error) {
r1, _, e1 := Syscall(procProcess32NextW.Addr(), 2, uintptr(snapshot), uintptr(unsafe.Pointer(procEntry)), 0)
if r1 == 0 {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -1314,7 +1339,7 @@ func DeviceIoControl(handle Handle, ioControlCode uint32, inBuffer *byte, inBuff
r1, _, e1 := Syscall9(procDeviceIoControl.Addr(), 8, uintptr(handle), uintptr(ioControlCode), uintptr(unsafe.Pointer(inBuffer)), uintptr(inBufferSize), uintptr(unsafe.Pointer(outBuffer)), uintptr(outBufferSize), uintptr(unsafe.Pointer(bytesReturned)), uintptr(unsafe.Pointer(overlapped)), 0)
if r1 == 0 {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -1326,7 +1351,7 @@ func CreateSymbolicLink(symlinkfilename *uint16, targetfilename *uint16, flags u
r1, _, e1 := Syscall(procCreateSymbolicLinkW.Addr(), 3, uintptr(unsafe.Pointer(symlinkfilename)), uintptr(unsafe.Pointer(targetfilename)), uintptr(flags))
if r1&0xff == 0 {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -1338,7 +1363,7 @@ func CreateHardLink(filename *uint16, existingfilename *uint16, reserved uintptr
r1, _, e1 := Syscall(procCreateHardLinkW.Addr(), 3, uintptr(unsafe.Pointer(filename)), uintptr(unsafe.Pointer(existingfilename)), uintptr(reserved))
if r1&0xff == 0 {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -1358,7 +1383,7 @@ func WSACleanup() (err error) {
r1, _, e1 := Syscall(procWSACleanup.Addr(), 0, 0, 0, 0)
if r1 == socket_error {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -1370,7 +1395,7 @@ func WSAIoctl(s Handle, iocc uint32, inbuf *byte, cbif uint32, outbuf *byte, cbo
r1, _, e1 := Syscall9(procWSAIoctl.Addr(), 9, uintptr(s), uintptr(iocc), uintptr(unsafe.Pointer(inbuf)), uintptr(cbif), uintptr(unsafe.Pointer(outbuf)), uintptr(cbob), uintptr(unsafe.Pointer(cbbr)), uintptr(unsafe.Pointer(overlapped)), uintptr(completionRoutine))
if r1 == socket_error {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -1383,7 +1408,7 @@ func socket(af int32, typ int32, protocol int32) (handle Handle, err error) {
handle = Handle(r0)
if handle == InvalidHandle {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -1395,7 +1420,7 @@ func Setsockopt(s Handle, level int32, optname int32, optval *byte, optlen int32
r1, _, e1 := Syscall6(procsetsockopt.Addr(), 5, uintptr(s), uintptr(level), uintptr(optname), uintptr(unsafe.Pointer(optval)), uintptr(optlen), 0)
if r1 == socket_error {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -1407,7 +1432,7 @@ func Getsockopt(s Handle, level int32, optname int32, optval *byte, optlen *int3
r1, _, e1 := Syscall6(procgetsockopt.Addr(), 5, uintptr(s), uintptr(level), uintptr(optname), uintptr(unsafe.Pointer(optval)), uintptr(unsafe.Pointer(optlen)), 0)
if r1 == socket_error {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -1419,7 +1444,7 @@ func bind(s Handle, name unsafe.Pointer, namelen int32) (err error) {
r1, _, e1 := Syscall(procbind.Addr(), 3, uintptr(s), uintptr(name), uintptr(namelen))
if r1 == socket_error {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -1431,7 +1456,7 @@ func connect(s Handle, name unsafe.Pointer, namelen int32) (err error) {
r1, _, e1 := Syscall(procconnect.Addr(), 3, uintptr(s), uintptr(name), uintptr(namelen))
if r1 == socket_error {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -1443,7 +1468,7 @@ func getsockname(s Handle, rsa *RawSockaddrAny, addrlen *int32) (err error) {
r1, _, e1 := Syscall(procgetsockname.Addr(), 3, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
if r1 == socket_error {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -1455,7 +1480,7 @@ func getpeername(s Handle, rsa *RawSockaddrAny, addrlen *int32) (err error) {
r1, _, e1 := Syscall(procgetpeername.Addr(), 3, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
if r1 == socket_error {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -1467,7 +1492,7 @@ func listen(s Handle, backlog int32) (err error) {
r1, _, e1 := Syscall(proclisten.Addr(), 2, uintptr(s), uintptr(backlog), 0)
if r1 == socket_error {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -1479,7 +1504,7 @@ func shutdown(s Handle, how int32) (err error) {
r1, _, e1 := Syscall(procshutdown.Addr(), 2, uintptr(s), uintptr(how), 0)
if r1 == socket_error {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -1491,7 +1516,7 @@ func Closesocket(s Handle) (err error) {
r1, _, e1 := Syscall(procclosesocket.Addr(), 1, uintptr(s), 0, 0)
if r1 == socket_error {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -1503,7 +1528,7 @@ func AcceptEx(ls Handle, as Handle, buf *byte, rxdatalen uint32, laddrlen uint32
r1, _, e1 := Syscall9(procAcceptEx.Addr(), 8, uintptr(ls), uintptr(as), uintptr(unsafe.Pointer(buf)), uintptr(rxdatalen), uintptr(laddrlen), uintptr(raddrlen), uintptr(unsafe.Pointer(recvd)), uintptr(unsafe.Pointer(overlapped)), 0)
if r1 == 0 {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -1520,7 +1545,7 @@ func WSARecv(s Handle, bufs *WSABuf, bufcnt uint32, recvd *uint32, flags *uint32
r1, _, e1 := Syscall9(procWSARecv.Addr(), 7, uintptr(s), uintptr(unsafe.Pointer(bufs)), uintptr(bufcnt), uintptr(unsafe.Pointer(recvd)), uintptr(unsafe.Pointer(flags)), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(croutine)), 0, 0)
if r1 == socket_error {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -1532,7 +1557,7 @@ func WSASend(s Handle, bufs *WSABuf, bufcnt uint32, sent *uint32, flags uint32,
r1, _, e1 := Syscall9(procWSASend.Addr(), 7, uintptr(s), uintptr(unsafe.Pointer(bufs)), uintptr(bufcnt), uintptr(unsafe.Pointer(sent)), uintptr(flags), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(croutine)), 0, 0)
if r1 == socket_error {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -1544,7 +1569,7 @@ func WSARecvFrom(s Handle, bufs *WSABuf, bufcnt uint32, recvd *uint32, flags *ui
r1, _, e1 := Syscall9(procWSARecvFrom.Addr(), 9, uintptr(s), uintptr(unsafe.Pointer(bufs)), uintptr(bufcnt), uintptr(unsafe.Pointer(recvd)), uintptr(unsafe.Pointer(flags)), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen)), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(croutine)))
if r1 == socket_error {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -1556,7 +1581,7 @@ func WSASendTo(s Handle, bufs *WSABuf, bufcnt uint32, sent *uint32, flags uint32
r1, _, e1 := Syscall9(procWSASendTo.Addr(), 9, uintptr(s), uintptr(unsafe.Pointer(bufs)), uintptr(bufcnt), uintptr(unsafe.Pointer(sent)), uintptr(flags), uintptr(unsafe.Pointer(to)), uintptr(tolen), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(croutine)))
if r1 == socket_error {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -1578,7 +1603,7 @@ func _GetHostByName(name *byte) (h *Hostent, err error) {
h = (*Hostent)(unsafe.Pointer(r0))
if h == nil {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -1605,7 +1630,7 @@ func _GetServByName(name *byte, proto *byte) (s *Servent, err error) {
s = (*Servent)(unsafe.Pointer(r0))
if s == nil {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -1633,7 +1658,7 @@ func _GetProtoByName(name *byte) (p *Protoent, err error) {
p = (*Protoent)(unsafe.Pointer(r0))
if p == nil {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -1702,7 +1727,7 @@ func SetFileCompletionNotificationModes(handle Handle, flags uint8) (err error)
r1, _, e1 := Syscall(procSetFileCompletionNotificationModes.Addr(), 2, uintptr(handle), uintptr(flags), 0)
if r1 == 0 {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -1715,7 +1740,7 @@ func WSAEnumProtocols(protocols *int32, protocolBuffer *WSAProtocolInfo, bufferL
n = int32(r0)
if n == -1 {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -1727,7 +1752,7 @@ func TranslateName(accName *uint16, accNameFormat uint32, desiredNameFormat uint
r1, _, e1 := Syscall6(procTranslateNameW.Addr(), 5, uintptr(unsafe.Pointer(accName)), uintptr(accNameFormat), uintptr(desiredNameFormat), uintptr(unsafe.Pointer(translatedName)), uintptr(unsafe.Pointer(nSize)), 0)
if r1&0xff == 0 {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -1739,7 +1764,7 @@ func GetUserNameEx(nameFormat uint32, nameBuffre *uint16, nSize *uint32) (err er
r1, _, e1 := Syscall(procGetUserNameExW.Addr(), 3, uintptr(nameFormat), uintptr(unsafe.Pointer(nameBuffre)), uintptr(unsafe.Pointer(nSize)))
if r1&0xff == 0 {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -1775,7 +1800,7 @@ func LookupAccountSid(systemName *uint16, sid *SID, name *uint16, nameLen *uint3
r1, _, e1 := Syscall9(procLookupAccountSidW.Addr(), 7, uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(sid)), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(nameLen)), uintptr(unsafe.Pointer(refdDomainName)), uintptr(unsafe.Pointer(refdDomainNameLen)), uintptr(unsafe.Pointer(use)), 0, 0)
if r1 == 0 {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -1787,7 +1812,7 @@ func LookupAccountName(systemName *uint16, accountName *uint16, sid *SID, sidLen
r1, _, e1 := Syscall9(procLookupAccountNameW.Addr(), 7, uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(accountName)), uintptr(unsafe.Pointer(sid)), uintptr(unsafe.Pointer(sidLen)), uintptr(unsafe.Pointer(refdDomainName)), uintptr(unsafe.Pointer(refdDomainNameLen)), uintptr(unsafe.Pointer(use)), 0, 0)
if r1 == 0 {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -1799,7 +1824,7 @@ func ConvertSidToStringSid(sid *SID, stringSid **uint16) (err error) {
r1, _, e1 := Syscall(procConvertSidToStringSidW.Addr(), 2, uintptr(unsafe.Pointer(sid)), uintptr(unsafe.Pointer(stringSid)), 0)
if r1 == 0 {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -1811,7 +1836,7 @@ func ConvertStringSidToSid(stringSid *uint16, sid **SID) (err error) {
r1, _, e1 := Syscall(procConvertStringSidToSidW.Addr(), 2, uintptr(unsafe.Pointer(stringSid)), uintptr(unsafe.Pointer(sid)), 0)
if r1 == 0 {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -1829,7 +1854,7 @@ func CopySid(destSidLen uint32, destSid *SID, srcSid *SID) (err error) {
r1, _, e1 := Syscall(procCopySid.Addr(), 3, uintptr(destSidLen), uintptr(unsafe.Pointer(destSid)), uintptr(unsafe.Pointer(srcSid)))
if r1 == 0 {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -1841,7 +1866,7 @@ func OpenProcessToken(h Handle, access uint32, token *Token) (err error) {
r1, _, e1 := Syscall(procOpenProcessToken.Addr(), 3, uintptr(h), uintptr(access), uintptr(unsafe.Pointer(token)))
if r1 == 0 {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -1853,7 +1878,7 @@ func GetTokenInformation(t Token, infoClass uint32, info *byte, infoLen uint32,
r1, _, e1 := Syscall6(procGetTokenInformation.Addr(), 5, uintptr(t), uintptr(infoClass), uintptr(unsafe.Pointer(info)), uintptr(infoLen), uintptr(unsafe.Pointer(returnedLen)), 0)
if r1 == 0 {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
@@ -1865,7 +1890,7 @@ func GetUserProfileDirectory(t Token, dir *uint16, dirLen *uint32) (err error) {
r1, _, e1 := Syscall(procGetUserProfileDirectoryW.Addr(), 3, uintptr(t), uintptr(unsafe.Pointer(dir)), uintptr(unsafe.Pointer(dirLen)))
if r1 == 0 {
if e1 != 0 {
- err = error(e1)
+ err = errnoErr(e1)
} else {
err = EINVAL
}
diff --git a/src/syscall/zsysnum_linux_mips.go b/src/syscall/zsysnum_linux_mips.go
new file mode 100644
index 0000000..f99ca56
--- /dev/null
+++ b/src/syscall/zsysnum_linux_mips.go
@@ -0,0 +1,357 @@
+// mksysnum_linux.pl /usr/include/mips-linux-gnu/asm/unistd.h
+// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
+
+package syscall
+
+const (
+ SYS_SYSCALL = 4000
+ SYS_EXIT = 4001
+ SYS_FORK = 4002
+ SYS_READ = 4003
+ SYS_WRITE = 4004
+ SYS_OPEN = 4005
+ SYS_CLOSE = 4006
+ SYS_WAITPID = 4007
+ SYS_CREAT = 4008
+ SYS_LINK = 4009
+ SYS_UNLINK = 4010
+ SYS_EXECVE = 4011
+ SYS_CHDIR = 4012
+ SYS_TIME = 4013
+ SYS_MKNOD = 4014
+ SYS_CHMOD = 4015
+ SYS_LCHOWN = 4016
+ SYS_BREAK = 4017
+ SYS_UNUSED18 = 4018
+ SYS_LSEEK = 4019
+ SYS_GETPID = 4020
+ SYS_MOUNT = 4021
+ SYS_UMOUNT = 4022
+ SYS_SETUID = 4023
+ SYS_GETUID = 4024
+ SYS_STIME = 4025
+ SYS_PTRACE = 4026
+ SYS_ALARM = 4027
+ SYS_UNUSED28 = 4028
+ SYS_PAUSE = 4029
+ SYS_UTIME = 4030
+ SYS_STTY = 4031
+ SYS_GTTY = 4032
+ SYS_ACCESS = 4033
+ SYS_NICE = 4034
+ SYS_FTIME = 4035
+ SYS_SYNC = 4036
+ SYS_KILL = 4037
+ SYS_RENAME = 4038
+ SYS_MKDIR = 4039
+ SYS_RMDIR = 4040
+ SYS_DUP = 4041
+ SYS_PIPE = 4042
+ SYS_TIMES = 4043
+ SYS_PROF = 4044
+ SYS_BRK = 4045
+ SYS_SETGID = 4046
+ SYS_GETGID = 4047
+ SYS_SIGNAL = 4048
+ SYS_GETEUID = 4049
+ SYS_GETEGID = 4050
+ SYS_ACCT = 4051
+ SYS_UMOUNT2 = 4052
+ SYS_LOCK = 4053
+ SYS_IOCTL = 4054
+ SYS_FCNTL = 4055
+ SYS_MPX = 4056
+ SYS_SETPGID = 4057
+ SYS_ULIMIT = 4058
+ SYS_UNUSED59 = 4059
+ SYS_UMASK = 4060
+ SYS_CHROOT = 4061
+ SYS_USTAT = 4062
+ SYS_DUP2 = 4063
+ SYS_GETPPID = 4064
+ SYS_GETPGRP = 4065
+ SYS_SETSID = 4066
+ SYS_SIGACTION = 4067
+ SYS_SGETMASK = 4068
+ SYS_SSETMASK = 4069
+ SYS_SETREUID = 4070
+ SYS_SETREGID = 4071
+ SYS_SIGSUSPEND = 4072
+ SYS_SIGPENDING = 4073
+ SYS_SETHOSTNAME = 4074
+ SYS_SETRLIMIT = 4075
+ SYS_GETRLIMIT = 4076
+ SYS_GETRUSAGE = 4077
+ SYS_GETTIMEOFDAY = 4078
+ SYS_SETTIMEOFDAY = 4079
+ SYS_GETGROUPS = 4080
+ SYS_SETGROUPS = 4081
+ SYS_RESERVED82 = 4082
+ SYS_SYMLINK = 4083
+ SYS_UNUSED84 = 4084
+ SYS_READLINK = 4085
+ SYS_USELIB = 4086
+ SYS_SWAPON = 4087
+ SYS_REBOOT = 4088
+ SYS_READDIR = 4089
+ SYS_MMAP = 4090
+ SYS_MUNMAP = 4091
+ SYS_TRUNCATE = 4092
+ SYS_FTRUNCATE = 4093
+ SYS_FCHMOD = 4094
+ SYS_FCHOWN = 4095
+ SYS_GETPRIORITY = 4096
+ SYS_SETPRIORITY = 4097
+ SYS_PROFIL = 4098
+ SYS_STATFS = 4099
+ SYS_FSTATFS = 4100
+ SYS_IOPERM = 4101
+ SYS_SOCKETCALL = 4102
+ SYS_SYSLOG = 4103
+ SYS_SETITIMER = 4104
+ SYS_GETITIMER = 4105
+ SYS_STAT = 4106
+ SYS_LSTAT = 4107
+ SYS_FSTAT = 4108
+ SYS_UNUSED109 = 4109
+ SYS_IOPL = 4110
+ SYS_VHANGUP = 4111
+ SYS_IDLE = 4112
+ SYS_VM86 = 4113
+ SYS_WAIT4 = 4114
+ SYS_SWAPOFF = 4115
+ SYS_SYSINFO = 4116
+ SYS_IPC = 4117
+ SYS_FSYNC = 4118
+ SYS_SIGRETURN = 4119
+ SYS_CLONE = 4120
+ SYS_SETDOMAINNAME = 4121
+ SYS_UNAME = 4122
+ SYS_MODIFY_LDT = 4123
+ SYS_ADJTIMEX = 4124
+ SYS_MPROTECT = 4125
+ SYS_SIGPROCMASK = 4126
+ SYS_CREATE_MODULE = 4127
+ SYS_INIT_MODULE = 4128
+ SYS_DELETE_MODULE = 4129
+ SYS_GET_KERNEL_SYMS = 4130
+ SYS_QUOTACTL = 4131
+ SYS_GETPGID = 4132
+ SYS_FCHDIR = 4133
+ SYS_BDFLUSH = 4134
+ SYS_SYSFS = 4135
+ SYS_PERSONALITY = 4136
+ SYS_AFS_SYSCALL = 4137
+ SYS_SETFSUID = 4138
+ SYS_SETFSGID = 4139
+ SYS__LLSEEK = 4140
+ SYS_GETDENTS = 4141
+ SYS__NEWSELECT = 4142
+ SYS_FLOCK = 4143
+ SYS_MSYNC = 4144
+ SYS_READV = 4145
+ SYS_WRITEV = 4146
+ SYS_CACHEFLUSH = 4147
+ SYS_CACHECTL = 4148
+ SYS_SYSMIPS = 4149
+ SYS_UNUSED150 = 4150
+ SYS_GETSID = 4151
+ SYS_FDATASYNC = 4152
+ SYS__SYSCTL = 4153
+ SYS_MLOCK = 4154
+ SYS_MUNLOCK = 4155
+ SYS_MLOCKALL = 4156
+ SYS_MUNLOCKALL = 4157
+ SYS_SCHED_SETPARAM = 4158
+ SYS_SCHED_GETPARAM = 4159
+ SYS_SCHED_SETSCHEDULER = 4160
+ SYS_SCHED_GETSCHEDULER = 4161
+ SYS_SCHED_YIELD = 4162
+ SYS_SCHED_GET_PRIORITY_MAX = 4163
+ SYS_SCHED_GET_PRIORITY_MIN = 4164
+ SYS_SCHED_RR_GET_INTERVAL = 4165
+ SYS_NANOSLEEP = 4166
+ SYS_MREMAP = 4167
+ SYS_ACCEPT = 4168
+ SYS_BIND = 4169
+ SYS_CONNECT = 4170
+ SYS_GETPEERNAME = 4171
+ SYS_GETSOCKNAME = 4172
+ SYS_GETSOCKOPT = 4173
+ SYS_LISTEN = 4174
+ SYS_RECV = 4175
+ SYS_RECVFROM = 4176
+ SYS_RECVMSG = 4177
+ SYS_SEND = 4178
+ SYS_SENDMSG = 4179
+ SYS_SENDTO = 4180
+ SYS_SETSOCKOPT = 4181
+ SYS_SHUTDOWN = 4182
+ SYS_SOCKET = 4183
+ SYS_SOCKETPAIR = 4184
+ SYS_SETRESUID = 4185
+ SYS_GETRESUID = 4186
+ SYS_QUERY_MODULE = 4187
+ SYS_POLL = 4188
+ SYS_NFSSERVCTL = 4189
+ SYS_SETRESGID = 4190
+ SYS_GETRESGID = 4191
+ SYS_PRCTL = 4192
+ SYS_RT_SIGRETURN = 4193
+ SYS_RT_SIGACTION = 4194
+ SYS_RT_SIGPROCMASK = 4195
+ SYS_RT_SIGPENDING = 4196
+ SYS_RT_SIGTIMEDWAIT = 4197
+ SYS_RT_SIGQUEUEINFO = 4198
+ SYS_RT_SIGSUSPEND = 4199
+ SYS_PREAD64 = 4200
+ SYS_PWRITE64 = 4201
+ SYS_CHOWN = 4202
+ SYS_GETCWD = 4203
+ SYS_CAPGET = 4204
+ SYS_CAPSET = 4205
+ SYS_SIGALTSTACK = 4206
+ SYS_SENDFILE = 4207
+ SYS_GETPMSG = 4208
+ SYS_PUTPMSG = 4209
+ SYS_MMAP2 = 4210
+ SYS_TRUNCATE64 = 4211
+ SYS_FTRUNCATE64 = 4212
+ SYS_STAT64 = 4213
+ SYS_LSTAT64 = 4214
+ SYS_FSTAT64 = 4215
+ SYS_PIVOT_ROOT = 4216
+ SYS_MINCORE = 4217
+ SYS_MADVISE = 4218
+ SYS_GETDENTS64 = 4219
+ SYS_FCNTL64 = 4220
+ SYS_RESERVED221 = 4221
+ SYS_GETTID = 4222
+ SYS_READAHEAD = 4223
+ SYS_SETXATTR = 4224
+ SYS_LSETXATTR = 4225
+ SYS_FSETXATTR = 4226
+ SYS_GETXATTR = 4227
+ SYS_LGETXATTR = 4228
+ SYS_FGETXATTR = 4229
+ SYS_LISTXATTR = 4230
+ SYS_LLISTXATTR = 4231
+ SYS_FLISTXATTR = 4232
+ SYS_REMOVEXATTR = 4233
+ SYS_LREMOVEXATTR = 4234
+ SYS_FREMOVEXATTR = 4235
+ SYS_TKILL = 4236
+ SYS_SENDFILE64 = 4237
+ SYS_FUTEX = 4238
+ SYS_SCHED_SETAFFINITY = 4239
+ SYS_SCHED_GETAFFINITY = 4240
+ SYS_IO_SETUP = 4241
+ SYS_IO_DESTROY = 4242
+ SYS_IO_GETEVENTS = 4243
+ SYS_IO_SUBMIT = 4244
+ SYS_IO_CANCEL = 4245
+ SYS_EXIT_GROUP = 4246
+ SYS_LOOKUP_DCOOKIE = 4247
+ SYS_EPOLL_CREATE = 4248
+ SYS_EPOLL_CTL = 4249
+ SYS_EPOLL_WAIT = 4250
+ SYS_REMAP_FILE_PAGES = 4251
+ SYS_SET_TID_ADDRESS = 4252
+ SYS_RESTART_SYSCALL = 4253
+ SYS_FADVISE64 = 4254
+ SYS_STATFS64 = 4255
+ SYS_FSTATFS64 = 4256
+ SYS_TIMER_CREATE = 4257
+ SYS_TIMER_SETTIME = 4258
+ SYS_TIMER_GETTIME = 4259
+ SYS_TIMER_GETOVERRUN = 4260
+ SYS_TIMER_DELETE = 4261
+ SYS_CLOCK_SETTIME = 4262
+ SYS_CLOCK_GETTIME = 4263
+ SYS_CLOCK_GETRES = 4264
+ SYS_CLOCK_NANOSLEEP = 4265
+ SYS_TGKILL = 4266
+ SYS_UTIMES = 4267
+ SYS_MBIND = 4268
+ SYS_GET_MEMPOLICY = 4269
+ SYS_SET_MEMPOLICY = 4270
+ SYS_MQ_OPEN = 4271
+ SYS_MQ_UNLINK = 4272
+ SYS_MQ_TIMEDSEND = 4273
+ SYS_MQ_TIMEDRECEIVE = 4274
+ SYS_MQ_NOTIFY = 4275
+ SYS_MQ_GETSETATTR = 4276
+ SYS_VSERVER = 4277
+ SYS_WAITID = 4278
+ SYS_ADD_KEY = 4280
+ SYS_REQUEST_KEY = 4281
+ SYS_KEYCTL = 4282
+ SYS_SET_THREAD_AREA = 4283
+ SYS_INOTIFY_INIT = 4284
+ SYS_INOTIFY_ADD_WATCH = 4285
+ SYS_INOTIFY_RM_WATCH = 4286
+ SYS_MIGRATE_PAGES = 4287
+ SYS_OPENAT = 4288
+ SYS_MKDIRAT = 4289
+ SYS_MKNODAT = 4290
+ SYS_FCHOWNAT = 4291
+ SYS_FUTIMESAT = 4292
+ SYS_FSTATAT64 = 4293
+ SYS_UNLINKAT = 4294
+ SYS_RENAMEAT = 4295
+ SYS_LINKAT = 4296
+ SYS_SYMLINKAT = 4297
+ SYS_READLINKAT = 4298
+ SYS_FCHMODAT = 4299
+ SYS_FACCESSAT = 4300
+ SYS_PSELECT6 = 4301
+ SYS_PPOLL = 4302
+ SYS_UNSHARE = 4303
+ SYS_SPLICE = 4304
+ SYS_SYNC_FILE_RANGE = 4305
+ SYS_TEE = 4306
+ SYS_VMSPLICE = 4307
+ SYS_MOVE_PAGES = 4308
+ SYS_SET_ROBUST_LIST = 4309
+ SYS_GET_ROBUST_LIST = 4310
+ SYS_KEXEC_LOAD = 4311
+ SYS_GETCPU = 4312
+ SYS_EPOLL_PWAIT = 4313
+ SYS_IOPRIO_SET = 4314
+ SYS_IOPRIO_GET = 4315
+ SYS_UTIMENSAT = 4316
+ SYS_SIGNALFD = 4317
+ SYS_TIMERFD = 4318
+ SYS_EVENTFD = 4319
+ SYS_FALLOCATE = 4320
+ SYS_TIMERFD_CREATE = 4321
+ SYS_TIMERFD_GETTIME = 4322
+ SYS_TIMERFD_SETTIME = 4323
+ SYS_SIGNALFD4 = 4324
+ SYS_EVENTFD2 = 4325
+ SYS_EPOLL_CREATE1 = 4326
+ SYS_DUP3 = 4327
+ SYS_PIPE2 = 4328
+ SYS_INOTIFY_INIT1 = 4329
+ SYS_PREADV = 4330
+ SYS_PWRITEV = 4331
+ SYS_RT_TGSIGQUEUEINFO = 4332
+ SYS_PERF_EVENT_OPEN = 4333
+ SYS_ACCEPT4 = 4334
+ SYS_RECVMMSG = 4335
+ SYS_FANOTIFY_INIT = 4336
+ SYS_FANOTIFY_MARK = 4337
+ SYS_PRLIMIT64 = 4338
+ SYS_NAME_TO_HANDLE_AT = 4339
+ SYS_OPEN_BY_HANDLE_AT = 4340
+ SYS_CLOCK_ADJTIME = 4341
+ SYS_SYNCFS = 4342
+ SYS_SENDMMSG = 4343
+ SYS_SETNS = 4344
+ SYS_PROCESS_VM_READV = 4345
+ SYS_PROCESS_VM_WRITEV = 4346
+ SYS_LINUX_SYSCALLS = 4346
+ SYS_O32_LINUX_SYSCALLS = 4346
+ SYS_64_LINUX_SYSCALLS = 4305
+ SYS_N32_LINUX_SYSCALLS = 4310
+)
diff --git a/src/syscall/zsysnum_linux_mipsle.go b/src/syscall/zsysnum_linux_mipsle.go
new file mode 100644
index 0000000..f99ca56
--- /dev/null
+++ b/src/syscall/zsysnum_linux_mipsle.go
@@ -0,0 +1,357 @@
+// mksysnum_linux.pl /usr/include/mips-linux-gnu/asm/unistd.h
+// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
+
+package syscall
+
+const (
+ SYS_SYSCALL = 4000
+ SYS_EXIT = 4001
+ SYS_FORK = 4002
+ SYS_READ = 4003
+ SYS_WRITE = 4004
+ SYS_OPEN = 4005
+ SYS_CLOSE = 4006
+ SYS_WAITPID = 4007
+ SYS_CREAT = 4008
+ SYS_LINK = 4009
+ SYS_UNLINK = 4010
+ SYS_EXECVE = 4011
+ SYS_CHDIR = 4012
+ SYS_TIME = 4013
+ SYS_MKNOD = 4014
+ SYS_CHMOD = 4015
+ SYS_LCHOWN = 4016
+ SYS_BREAK = 4017
+ SYS_UNUSED18 = 4018
+ SYS_LSEEK = 4019
+ SYS_GETPID = 4020
+ SYS_MOUNT = 4021
+ SYS_UMOUNT = 4022
+ SYS_SETUID = 4023
+ SYS_GETUID = 4024
+ SYS_STIME = 4025
+ SYS_PTRACE = 4026
+ SYS_ALARM = 4027
+ SYS_UNUSED28 = 4028
+ SYS_PAUSE = 4029
+ SYS_UTIME = 4030
+ SYS_STTY = 4031
+ SYS_GTTY = 4032
+ SYS_ACCESS = 4033
+ SYS_NICE = 4034
+ SYS_FTIME = 4035
+ SYS_SYNC = 4036
+ SYS_KILL = 4037
+ SYS_RENAME = 4038
+ SYS_MKDIR = 4039
+ SYS_RMDIR = 4040
+ SYS_DUP = 4041
+ SYS_PIPE = 4042
+ SYS_TIMES = 4043
+ SYS_PROF = 4044
+ SYS_BRK = 4045
+ SYS_SETGID = 4046
+ SYS_GETGID = 4047
+ SYS_SIGNAL = 4048
+ SYS_GETEUID = 4049
+ SYS_GETEGID = 4050
+ SYS_ACCT = 4051
+ SYS_UMOUNT2 = 4052
+ SYS_LOCK = 4053
+ SYS_IOCTL = 4054
+ SYS_FCNTL = 4055
+ SYS_MPX = 4056
+ SYS_SETPGID = 4057
+ SYS_ULIMIT = 4058
+ SYS_UNUSED59 = 4059
+ SYS_UMASK = 4060
+ SYS_CHROOT = 4061
+ SYS_USTAT = 4062
+ SYS_DUP2 = 4063
+ SYS_GETPPID = 4064
+ SYS_GETPGRP = 4065
+ SYS_SETSID = 4066
+ SYS_SIGACTION = 4067
+ SYS_SGETMASK = 4068
+ SYS_SSETMASK = 4069
+ SYS_SETREUID = 4070
+ SYS_SETREGID = 4071
+ SYS_SIGSUSPEND = 4072
+ SYS_SIGPENDING = 4073
+ SYS_SETHOSTNAME = 4074
+ SYS_SETRLIMIT = 4075
+ SYS_GETRLIMIT = 4076
+ SYS_GETRUSAGE = 4077
+ SYS_GETTIMEOFDAY = 4078
+ SYS_SETTIMEOFDAY = 4079
+ SYS_GETGROUPS = 4080
+ SYS_SETGROUPS = 4081
+ SYS_RESERVED82 = 4082
+ SYS_SYMLINK = 4083
+ SYS_UNUSED84 = 4084
+ SYS_READLINK = 4085
+ SYS_USELIB = 4086
+ SYS_SWAPON = 4087
+ SYS_REBOOT = 4088
+ SYS_READDIR = 4089
+ SYS_MMAP = 4090
+ SYS_MUNMAP = 4091
+ SYS_TRUNCATE = 4092
+ SYS_FTRUNCATE = 4093
+ SYS_FCHMOD = 4094
+ SYS_FCHOWN = 4095
+ SYS_GETPRIORITY = 4096
+ SYS_SETPRIORITY = 4097
+ SYS_PROFIL = 4098
+ SYS_STATFS = 4099
+ SYS_FSTATFS = 4100
+ SYS_IOPERM = 4101
+ SYS_SOCKETCALL = 4102
+ SYS_SYSLOG = 4103
+ SYS_SETITIMER = 4104
+ SYS_GETITIMER = 4105
+ SYS_STAT = 4106
+ SYS_LSTAT = 4107
+ SYS_FSTAT = 4108
+ SYS_UNUSED109 = 4109
+ SYS_IOPL = 4110
+ SYS_VHANGUP = 4111
+ SYS_IDLE = 4112
+ SYS_VM86 = 4113
+ SYS_WAIT4 = 4114
+ SYS_SWAPOFF = 4115
+ SYS_SYSINFO = 4116
+ SYS_IPC = 4117
+ SYS_FSYNC = 4118
+ SYS_SIGRETURN = 4119
+ SYS_CLONE = 4120
+ SYS_SETDOMAINNAME = 4121
+ SYS_UNAME = 4122
+ SYS_MODIFY_LDT = 4123
+ SYS_ADJTIMEX = 4124
+ SYS_MPROTECT = 4125
+ SYS_SIGPROCMASK = 4126
+ SYS_CREATE_MODULE = 4127
+ SYS_INIT_MODULE = 4128
+ SYS_DELETE_MODULE = 4129
+ SYS_GET_KERNEL_SYMS = 4130
+ SYS_QUOTACTL = 4131
+ SYS_GETPGID = 4132
+ SYS_FCHDIR = 4133
+ SYS_BDFLUSH = 4134
+ SYS_SYSFS = 4135
+ SYS_PERSONALITY = 4136
+ SYS_AFS_SYSCALL = 4137
+ SYS_SETFSUID = 4138
+ SYS_SETFSGID = 4139
+ SYS__LLSEEK = 4140
+ SYS_GETDENTS = 4141
+ SYS__NEWSELECT = 4142
+ SYS_FLOCK = 4143
+ SYS_MSYNC = 4144
+ SYS_READV = 4145
+ SYS_WRITEV = 4146
+ SYS_CACHEFLUSH = 4147
+ SYS_CACHECTL = 4148
+ SYS_SYSMIPS = 4149
+ SYS_UNUSED150 = 4150
+ SYS_GETSID = 4151
+ SYS_FDATASYNC = 4152
+ SYS__SYSCTL = 4153
+ SYS_MLOCK = 4154
+ SYS_MUNLOCK = 4155
+ SYS_MLOCKALL = 4156
+ SYS_MUNLOCKALL = 4157
+ SYS_SCHED_SETPARAM = 4158
+ SYS_SCHED_GETPARAM = 4159
+ SYS_SCHED_SETSCHEDULER = 4160
+ SYS_SCHED_GETSCHEDULER = 4161
+ SYS_SCHED_YIELD = 4162
+ SYS_SCHED_GET_PRIORITY_MAX = 4163
+ SYS_SCHED_GET_PRIORITY_MIN = 4164
+ SYS_SCHED_RR_GET_INTERVAL = 4165
+ SYS_NANOSLEEP = 4166
+ SYS_MREMAP = 4167
+ SYS_ACCEPT = 4168
+ SYS_BIND = 4169
+ SYS_CONNECT = 4170
+ SYS_GETPEERNAME = 4171
+ SYS_GETSOCKNAME = 4172
+ SYS_GETSOCKOPT = 4173
+ SYS_LISTEN = 4174
+ SYS_RECV = 4175
+ SYS_RECVFROM = 4176
+ SYS_RECVMSG = 4177
+ SYS_SEND = 4178
+ SYS_SENDMSG = 4179
+ SYS_SENDTO = 4180
+ SYS_SETSOCKOPT = 4181
+ SYS_SHUTDOWN = 4182
+ SYS_SOCKET = 4183
+ SYS_SOCKETPAIR = 4184
+ SYS_SETRESUID = 4185
+ SYS_GETRESUID = 4186
+ SYS_QUERY_MODULE = 4187
+ SYS_POLL = 4188
+ SYS_NFSSERVCTL = 4189
+ SYS_SETRESGID = 4190
+ SYS_GETRESGID = 4191
+ SYS_PRCTL = 4192
+ SYS_RT_SIGRETURN = 4193
+ SYS_RT_SIGACTION = 4194
+ SYS_RT_SIGPROCMASK = 4195
+ SYS_RT_SIGPENDING = 4196
+ SYS_RT_SIGTIMEDWAIT = 4197
+ SYS_RT_SIGQUEUEINFO = 4198
+ SYS_RT_SIGSUSPEND = 4199
+ SYS_PREAD64 = 4200
+ SYS_PWRITE64 = 4201
+ SYS_CHOWN = 4202
+ SYS_GETCWD = 4203
+ SYS_CAPGET = 4204
+ SYS_CAPSET = 4205
+ SYS_SIGALTSTACK = 4206
+ SYS_SENDFILE = 4207
+ SYS_GETPMSG = 4208
+ SYS_PUTPMSG = 4209
+ SYS_MMAP2 = 4210
+ SYS_TRUNCATE64 = 4211
+ SYS_FTRUNCATE64 = 4212
+ SYS_STAT64 = 4213
+ SYS_LSTAT64 = 4214
+ SYS_FSTAT64 = 4215
+ SYS_PIVOT_ROOT = 4216
+ SYS_MINCORE = 4217
+ SYS_MADVISE = 4218
+ SYS_GETDENTS64 = 4219
+ SYS_FCNTL64 = 4220
+ SYS_RESERVED221 = 4221
+ SYS_GETTID = 4222
+ SYS_READAHEAD = 4223
+ SYS_SETXATTR = 4224
+ SYS_LSETXATTR = 4225
+ SYS_FSETXATTR = 4226
+ SYS_GETXATTR = 4227
+ SYS_LGETXATTR = 4228
+ SYS_FGETXATTR = 4229
+ SYS_LISTXATTR = 4230
+ SYS_LLISTXATTR = 4231
+ SYS_FLISTXATTR = 4232
+ SYS_REMOVEXATTR = 4233
+ SYS_LREMOVEXATTR = 4234
+ SYS_FREMOVEXATTR = 4235
+ SYS_TKILL = 4236
+ SYS_SENDFILE64 = 4237
+ SYS_FUTEX = 4238
+ SYS_SCHED_SETAFFINITY = 4239
+ SYS_SCHED_GETAFFINITY = 4240
+ SYS_IO_SETUP = 4241
+ SYS_IO_DESTROY = 4242
+ SYS_IO_GETEVENTS = 4243
+ SYS_IO_SUBMIT = 4244
+ SYS_IO_CANCEL = 4245
+ SYS_EXIT_GROUP = 4246
+ SYS_LOOKUP_DCOOKIE = 4247
+ SYS_EPOLL_CREATE = 4248
+ SYS_EPOLL_CTL = 4249
+ SYS_EPOLL_WAIT = 4250
+ SYS_REMAP_FILE_PAGES = 4251
+ SYS_SET_TID_ADDRESS = 4252
+ SYS_RESTART_SYSCALL = 4253
+ SYS_FADVISE64 = 4254
+ SYS_STATFS64 = 4255
+ SYS_FSTATFS64 = 4256
+ SYS_TIMER_CREATE = 4257
+ SYS_TIMER_SETTIME = 4258
+ SYS_TIMER_GETTIME = 4259
+ SYS_TIMER_GETOVERRUN = 4260
+ SYS_TIMER_DELETE = 4261
+ SYS_CLOCK_SETTIME = 4262
+ SYS_CLOCK_GETTIME = 4263
+ SYS_CLOCK_GETRES = 4264
+ SYS_CLOCK_NANOSLEEP = 4265
+ SYS_TGKILL = 4266
+ SYS_UTIMES = 4267
+ SYS_MBIND = 4268
+ SYS_GET_MEMPOLICY = 4269
+ SYS_SET_MEMPOLICY = 4270
+ SYS_MQ_OPEN = 4271
+ SYS_MQ_UNLINK = 4272
+ SYS_MQ_TIMEDSEND = 4273
+ SYS_MQ_TIMEDRECEIVE = 4274
+ SYS_MQ_NOTIFY = 4275
+ SYS_MQ_GETSETATTR = 4276
+ SYS_VSERVER = 4277
+ SYS_WAITID = 4278
+ SYS_ADD_KEY = 4280
+ SYS_REQUEST_KEY = 4281
+ SYS_KEYCTL = 4282
+ SYS_SET_THREAD_AREA = 4283
+ SYS_INOTIFY_INIT = 4284
+ SYS_INOTIFY_ADD_WATCH = 4285
+ SYS_INOTIFY_RM_WATCH = 4286
+ SYS_MIGRATE_PAGES = 4287
+ SYS_OPENAT = 4288
+ SYS_MKDIRAT = 4289
+ SYS_MKNODAT = 4290
+ SYS_FCHOWNAT = 4291
+ SYS_FUTIMESAT = 4292
+ SYS_FSTATAT64 = 4293
+ SYS_UNLINKAT = 4294
+ SYS_RENAMEAT = 4295
+ SYS_LINKAT = 4296
+ SYS_SYMLINKAT = 4297
+ SYS_READLINKAT = 4298
+ SYS_FCHMODAT = 4299
+ SYS_FACCESSAT = 4300
+ SYS_PSELECT6 = 4301
+ SYS_PPOLL = 4302
+ SYS_UNSHARE = 4303
+ SYS_SPLICE = 4304
+ SYS_SYNC_FILE_RANGE = 4305
+ SYS_TEE = 4306
+ SYS_VMSPLICE = 4307
+ SYS_MOVE_PAGES = 4308
+ SYS_SET_ROBUST_LIST = 4309
+ SYS_GET_ROBUST_LIST = 4310
+ SYS_KEXEC_LOAD = 4311
+ SYS_GETCPU = 4312
+ SYS_EPOLL_PWAIT = 4313
+ SYS_IOPRIO_SET = 4314
+ SYS_IOPRIO_GET = 4315
+ SYS_UTIMENSAT = 4316
+ SYS_SIGNALFD = 4317
+ SYS_TIMERFD = 4318
+ SYS_EVENTFD = 4319
+ SYS_FALLOCATE = 4320
+ SYS_TIMERFD_CREATE = 4321
+ SYS_TIMERFD_GETTIME = 4322
+ SYS_TIMERFD_SETTIME = 4323
+ SYS_SIGNALFD4 = 4324
+ SYS_EVENTFD2 = 4325
+ SYS_EPOLL_CREATE1 = 4326
+ SYS_DUP3 = 4327
+ SYS_PIPE2 = 4328
+ SYS_INOTIFY_INIT1 = 4329
+ SYS_PREADV = 4330
+ SYS_PWRITEV = 4331
+ SYS_RT_TGSIGQUEUEINFO = 4332
+ SYS_PERF_EVENT_OPEN = 4333
+ SYS_ACCEPT4 = 4334
+ SYS_RECVMMSG = 4335
+ SYS_FANOTIFY_INIT = 4336
+ SYS_FANOTIFY_MARK = 4337
+ SYS_PRLIMIT64 = 4338
+ SYS_NAME_TO_HANDLE_AT = 4339
+ SYS_OPEN_BY_HANDLE_AT = 4340
+ SYS_CLOCK_ADJTIME = 4341
+ SYS_SYNCFS = 4342
+ SYS_SENDMMSG = 4343
+ SYS_SETNS = 4344
+ SYS_PROCESS_VM_READV = 4345
+ SYS_PROCESS_VM_WRITEV = 4346
+ SYS_LINUX_SYSCALLS = 4346
+ SYS_O32_LINUX_SYSCALLS = 4346
+ SYS_64_LINUX_SYSCALLS = 4305
+ SYS_N32_LINUX_SYSCALLS = 4310
+)
diff --git a/src/syscall/ztypes_linux_386.go b/src/syscall/ztypes_linux_386.go
index dd198cb..a73c917 100644
--- a/src/syscall/ztypes_linux_386.go
+++ b/src/syscall/ztypes_linux_386.go
@@ -238,10 +238,9 @@ type Msghdr struct {
}
type Cmsghdr struct {
- Len uint32
- Level int32
- Type int32
- X__cmsg_data [0]uint8
+ Len uint32
+ Level int32
+ Type int32
}
type Inet4Pktinfo struct {
diff --git a/src/syscall/ztypes_linux_amd64.go b/src/syscall/ztypes_linux_amd64.go
index a39489e..4cbd5d8 100644
--- a/src/syscall/ztypes_linux_amd64.go
+++ b/src/syscall/ztypes_linux_amd64.go
@@ -242,10 +242,9 @@ type Msghdr struct {
}
type Cmsghdr struct {
- Len uint64
- Level int32
- Type int32
- X__cmsg_data [0]uint8
+ Len uint64
+ Level int32
+ Type int32
}
type Inet4Pktinfo struct {
diff --git a/src/syscall/ztypes_linux_arm.go b/src/syscall/ztypes_linux_arm.go
index f446e41..16aa014 100644
--- a/src/syscall/ztypes_linux_arm.go
+++ b/src/syscall/ztypes_linux_arm.go
@@ -242,10 +242,9 @@ type Msghdr struct {
}
type Cmsghdr struct {
- Len uint32
- Level int32
- Type int32
- X__cmsg_data [0]uint8
+ Len uint32
+ Level int32
+ Type int32
}
type Inet4Pktinfo struct {
diff --git a/src/syscall/ztypes_linux_arm64.go b/src/syscall/ztypes_linux_arm64.go
index dcb1178..e5d669c 100644
--- a/src/syscall/ztypes_linux_arm64.go
+++ b/src/syscall/ztypes_linux_arm64.go
@@ -243,10 +243,9 @@ type Msghdr struct {
}
type Cmsghdr struct {
- Len uint64
- Level int32
- Type int32
- X__cmsg_data [0]uint8
+ Len uint64
+ Level int32
+ Type int32
}
type Inet4Pktinfo struct {
diff --git a/src/syscall/ztypes_linux_mips.go b/src/syscall/ztypes_linux_mips.go
new file mode 100644
index 0000000..7a8d34d
--- /dev/null
+++ b/src/syscall/ztypes_linux_mips.go
@@ -0,0 +1,592 @@
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs types_linux.go
+
+package syscall
+
+const (
+ sizeofPtr = 0x4
+ sizeofShort = 0x2
+ sizeofInt = 0x4
+ sizeofLong = 0x4
+ sizeofLongLong = 0x8
+ PathMax = 0x1000
+)
+
+type (
+ _C_short int16
+ _C_int int32
+ _C_long int32
+ _C_long_long int64
+)
+
+type Timespec struct {
+ Sec int32
+ Nsec int32
+}
+
+type Timeval struct {
+ Sec int32
+ Usec int32
+}
+
+type Timex struct {
+ Modes uint32
+ Offset int32
+ Freq int32
+ Maxerror int32
+ Esterror int32
+ Status int32
+ Constant int32
+ Precision int32
+ Tolerance int32
+ Time Timeval
+ Tick int32
+ Ppsfreq int32
+ Jitter int32
+ Shift int32
+ Stabil int32
+ Jitcnt int32
+ Calcnt int32
+ Errcnt int32
+ Stbcnt int32
+ Tai int32
+ Pad_cgo_0 [44]byte
+}
+
+type Time_t int32
+
+type Tms struct {
+ Utime int32
+ Stime int32
+ Cutime int32
+ Cstime int32
+}
+
+type Utimbuf struct {
+ Actime int32
+ Modtime int32
+}
+
+type Rusage struct {
+ Utime Timeval
+ Stime Timeval
+ Maxrss int32
+ Ixrss int32
+ Idrss int32
+ Isrss int32
+ Minflt int32
+ Majflt int32
+ Nswap int32
+ Inblock int32
+ Oublock int32
+ Msgsnd int32
+ Msgrcv int32
+ Nsignals int32
+ Nvcsw int32
+ Nivcsw int32
+}
+
+type Rlimit struct {
+ Cur uint64
+ Max uint64
+}
+
+type _Gid_t uint32
+
+type Stat_t struct {
+ Dev uint32
+ Pad1 [3]int32
+ Ino uint64
+ Mode uint32
+ Nlink uint32
+ Uid uint32
+ Gid uint32
+ Rdev uint32
+ Pad2 [3]int32
+ Size int64
+ Atim Timespec
+ Mtim Timespec
+ Ctim Timespec
+ Blksize int32
+ Pad4 int32
+ Blocks int64
+ Pad5 [14]int32
+}
+
+type Statfs_t struct {
+ Type int32
+ Bsize int32
+ Frsize int32
+ Pad_cgo_0 [4]byte
+ Blocks uint64
+ Bfree uint64
+ Files uint64
+ Ffree uint64
+ Bavail uint64
+ Fsid Fsid
+ Namelen int32
+ Flags int32
+ Spare [5]int32
+ Pad_cgo_1 [4]byte
+}
+
+type Dirent struct {
+ Ino uint64
+ Off int64
+ Reclen uint16
+ Type uint8
+ Name [256]int8
+ Pad_cgo_0 [5]byte
+}
+
+type Fsid struct {
+ X__val [2]int32
+}
+
+type Flock_t struct {
+ Type int16
+ Whence int16
+ Pad_cgo_0 [4]byte
+ Start int64
+ Len int64
+ Pid int32
+ Pad_cgo_1 [4]byte
+}
+
+type RawSockaddrInet4 struct {
+ Family uint16
+ Port uint16
+ Addr [4]byte /* in_addr */
+ Zero [8]uint8
+}
+
+type RawSockaddrInet6 struct {
+ Family uint16
+ Port uint16
+ Flowinfo uint32
+ Addr [16]byte /* in6_addr */
+ Scope_id uint32
+}
+
+type RawSockaddrUnix struct {
+ Family uint16
+ Path [108]int8
+}
+
+type RawSockaddrLinklayer struct {
+ Family uint16
+ Protocol uint16
+ Ifindex int32
+ Hatype uint16
+ Pkttype uint8
+ Halen uint8
+ Addr [8]uint8
+}
+
+type RawSockaddrNetlink struct {
+ Family uint16
+ Pad uint16
+ Pid uint32
+ Groups uint32
+}
+
+type RawSockaddr struct {
+ Family uint16
+ Data [14]int8
+}
+
+type RawSockaddrAny struct {
+ Addr RawSockaddr
+ Pad [96]int8
+}
+
+type _Socklen uint32
+
+type Linger struct {
+ Onoff int32
+ Linger int32
+}
+
+type Iovec struct {
+ Base *byte
+ Len uint32
+}
+
+type IPMreq struct {
+ Multiaddr [4]byte /* in_addr */
+ Interface [4]byte /* in_addr */
+}
+
+type IPMreqn struct {
+ Multiaddr [4]byte /* in_addr */
+ Address [4]byte /* in_addr */
+ Ifindex int32
+}
+
+type IPv6Mreq struct {
+ Multiaddr [16]byte /* in6_addr */
+ Interface uint32
+}
+
+type Msghdr struct {
+ Name *byte
+ Namelen uint32
+ Iov *Iovec
+ Iovlen uint32
+ Control *byte
+ Controllen uint32
+ Flags int32
+}
+
+type Cmsghdr struct {
+ Len uint32
+ Level int32
+ Type int32
+}
+
+type Inet4Pktinfo struct {
+ Ifindex int32
+ Spec_dst [4]byte /* in_addr */
+ Addr [4]byte /* in_addr */
+}
+
+type Inet6Pktinfo struct {
+ Addr [16]byte /* in6_addr */
+ Ifindex uint32
+}
+
+type IPv6MTUInfo struct {
+ Addr RawSockaddrInet6
+ Mtu uint32
+}
+
+type ICMPv6Filter struct {
+ Data [8]uint32
+}
+
+type Ucred struct {
+ Pid int32
+ Uid uint32
+ Gid uint32
+}
+
+type TCPInfo struct {
+ State uint8
+ Ca_state uint8
+ Retransmits uint8
+ Probes uint8
+ Backoff uint8
+ Options uint8
+ Pad_cgo_0 [2]byte
+ Rto uint32
+ Ato uint32
+ Snd_mss uint32
+ Rcv_mss uint32
+ Unacked uint32
+ Sacked uint32
+ Lost uint32
+ Retrans uint32
+ Fackets uint32
+ Last_data_sent uint32
+ Last_ack_sent uint32
+ Last_data_recv uint32
+ Last_ack_recv uint32
+ Pmtu uint32
+ Rcv_ssthresh uint32
+ Rtt uint32
+ Rttvar uint32
+ Snd_ssthresh uint32
+ Snd_cwnd uint32
+ Advmss uint32
+ Reordering uint32
+ Rcv_rtt uint32
+ Rcv_space uint32
+ Total_retrans uint32
+}
+
+const (
+ SizeofSockaddrInet4 = 0x10
+ SizeofSockaddrInet6 = 0x1c
+ SizeofSockaddrAny = 0x70
+ SizeofSockaddrUnix = 0x6e
+ SizeofSockaddrLinklayer = 0x14
+ SizeofSockaddrNetlink = 0xc
+ SizeofLinger = 0x8
+ SizeofIPMreq = 0x8
+ SizeofIPMreqn = 0xc
+ SizeofIPv6Mreq = 0x14
+ SizeofMsghdr = 0x1c
+ SizeofCmsghdr = 0xc
+ SizeofInet4Pktinfo = 0xc
+ SizeofInet6Pktinfo = 0x14
+ SizeofIPv6MTUInfo = 0x20
+ SizeofICMPv6Filter = 0x20
+ SizeofUcred = 0xc
+ SizeofTCPInfo = 0x68
+)
+
+const (
+ IFA_UNSPEC = 0x0
+ IFA_ADDRESS = 0x1
+ IFA_LOCAL = 0x2
+ IFA_LABEL = 0x3
+ IFA_BROADCAST = 0x4
+ IFA_ANYCAST = 0x5
+ IFA_CACHEINFO = 0x6
+ IFA_MULTICAST = 0x7
+ IFLA_UNSPEC = 0x0
+ IFLA_ADDRESS = 0x1
+ IFLA_BROADCAST = 0x2
+ IFLA_IFNAME = 0x3
+ IFLA_MTU = 0x4
+ IFLA_LINK = 0x5
+ IFLA_QDISC = 0x6
+ IFLA_STATS = 0x7
+ IFLA_COST = 0x8
+ IFLA_PRIORITY = 0x9
+ IFLA_MASTER = 0xa
+ IFLA_WIRELESS = 0xb
+ IFLA_PROTINFO = 0xc
+ IFLA_TXQLEN = 0xd
+ IFLA_MAP = 0xe
+ IFLA_WEIGHT = 0xf
+ IFLA_OPERSTATE = 0x10
+ IFLA_LINKMODE = 0x11
+ IFLA_LINKINFO = 0x12
+ IFLA_NET_NS_PID = 0x13
+ IFLA_IFALIAS = 0x14
+ IFLA_MAX = 0x27
+ RT_SCOPE_UNIVERSE = 0x0
+ RT_SCOPE_SITE = 0xc8
+ RT_SCOPE_LINK = 0xfd
+ RT_SCOPE_HOST = 0xfe
+ RT_SCOPE_NOWHERE = 0xff
+ RT_TABLE_UNSPEC = 0x0
+ RT_TABLE_COMPAT = 0xfc
+ RT_TABLE_DEFAULT = 0xfd
+ RT_TABLE_MAIN = 0xfe
+ RT_TABLE_LOCAL = 0xff
+ RT_TABLE_MAX = 0xffffffff
+ RTA_UNSPEC = 0x0
+ RTA_DST = 0x1
+ RTA_SRC = 0x2
+ RTA_IIF = 0x3
+ RTA_OIF = 0x4
+ RTA_GATEWAY = 0x5
+ RTA_PRIORITY = 0x6
+ RTA_PREFSRC = 0x7
+ RTA_METRICS = 0x8
+ RTA_MULTIPATH = 0x9
+ RTA_FLOW = 0xb
+ RTA_CACHEINFO = 0xc
+ RTA_TABLE = 0xf
+ RTN_UNSPEC = 0x0
+ RTN_UNICAST = 0x1
+ RTN_LOCAL = 0x2
+ RTN_BROADCAST = 0x3
+ RTN_ANYCAST = 0x4
+ RTN_MULTICAST = 0x5
+ RTN_BLACKHOLE = 0x6
+ RTN_UNREACHABLE = 0x7
+ RTN_PROHIBIT = 0x8
+ RTN_THROW = 0x9
+ RTN_NAT = 0xa
+ RTN_XRESOLVE = 0xb
+ RTNLGRP_NONE = 0x0
+ RTNLGRP_LINK = 0x1
+ RTNLGRP_NOTIFY = 0x2
+ RTNLGRP_NEIGH = 0x3
+ RTNLGRP_TC = 0x4
+ RTNLGRP_IPV4_IFADDR = 0x5
+ RTNLGRP_IPV4_MROUTE = 0x6
+ RTNLGRP_IPV4_ROUTE = 0x7
+ RTNLGRP_IPV4_RULE = 0x8
+ RTNLGRP_IPV6_IFADDR = 0x9
+ RTNLGRP_IPV6_MROUTE = 0xa
+ RTNLGRP_IPV6_ROUTE = 0xb
+ RTNLGRP_IPV6_IFINFO = 0xc
+ RTNLGRP_IPV6_PREFIX = 0x12
+ RTNLGRP_IPV6_RULE = 0x13
+ RTNLGRP_ND_USEROPT = 0x14
+ SizeofNlMsghdr = 0x10
+ SizeofNlMsgerr = 0x14
+ SizeofRtGenmsg = 0x1
+ SizeofNlAttr = 0x4
+ SizeofRtAttr = 0x4
+ SizeofIfInfomsg = 0x10
+ SizeofIfAddrmsg = 0x8
+ SizeofRtMsg = 0xc
+ SizeofRtNexthop = 0x8
+)
+
+type NlMsghdr struct {
+ Len uint32
+ Type uint16
+ Flags uint16
+ Seq uint32
+ Pid uint32
+}
+
+type NlMsgerr struct {
+ Error int32
+ Msg NlMsghdr
+}
+
+type RtGenmsg struct {
+ Family uint8
+}
+
+type NlAttr struct {
+ Len uint16
+ Type uint16
+}
+
+type RtAttr struct {
+ Len uint16
+ Type uint16
+}
+
+type IfInfomsg struct {
+ Family uint8
+ X__ifi_pad uint8
+ Type uint16
+ Index int32
+ Flags uint32
+ Change uint32
+}
+
+type IfAddrmsg struct {
+ Family uint8
+ Prefixlen uint8
+ Flags uint8
+ Scope uint8
+ Index uint32
+}
+
+type RtMsg struct {
+ Family uint8
+ Dst_len uint8
+ Src_len uint8
+ Tos uint8
+ Table uint8
+ Protocol uint8
+ Scope uint8
+ Type uint8
+ Flags uint32
+}
+
+type RtNexthop struct {
+ Len uint16
+ Flags uint8
+ Hops uint8
+ Ifindex int32
+}
+
+const (
+ SizeofSockFilter = 0x8
+ SizeofSockFprog = 0x8
+)
+
+type SockFilter struct {
+ Code uint16
+ Jt uint8
+ Jf uint8
+ K uint32
+}
+
+type SockFprog struct {
+ Len uint16
+ Pad_cgo_0 [2]byte
+ Filter *SockFilter
+}
+
+type InotifyEvent struct {
+ Wd int32
+ Mask uint32
+ Cookie uint32
+ Len uint32
+}
+
+const SizeofInotifyEvent = 0x10
+
+type PtraceRegs struct {
+ Regs [109]uint32
+ U_tsize uint32
+ U_dsize uint32
+ U_ssize uint32
+ Start_code uint32
+ Start_data uint32
+ Start_stack uint32
+ Signal int32
+ U_ar0 *byte
+ Magic uint32
+ U_comm [32]int8
+}
+
+type FdSet struct {
+ Bits [32]int32
+}
+
+type Sysinfo_t struct {
+ Uptime int32
+ Loads [3]uint32
+ Totalram uint32
+ Freeram uint32
+ Sharedram uint32
+ Bufferram uint32
+ Totalswap uint32
+ Freeswap uint32
+ Procs uint16
+ Pad uint16
+ Totalhigh uint32
+ Freehigh uint32
+ Unit uint32
+ X_f [8]int8
+}
+
+type Utsname struct {
+ Sysname [65]int8
+ Nodename [65]int8
+ Release [65]int8
+ Version [65]int8
+ Machine [65]int8
+ Domainname [65]int8
+}
+
+type Ustat_t struct {
+ Tfree int32
+ Tinode uint32
+ Fname [6]int8
+ Fpack [6]int8
+}
+
+type EpollEvent struct {
+ Events uint32
+ PadFd int32
+ Fd int32
+ Pad int32
+}
+
+const (
+ _AT_FDCWD = -0x64
+ _AT_REMOVEDIR = 0x200
+ _AT_SYMLINK_NOFOLLOW = 0x100
+)
+
+type Termios struct {
+ Iflag uint32
+ Oflag uint32
+ Cflag uint32
+ Lflag uint32
+ Line uint8
+ Cc [32]uint8
+ Pad_cgo_0 [3]byte
+}
+
+const (
+ IUCLC = 0x200
+ OLCUC = 0x2
+ TCGETS = 0x540d
+ TCSETS = 0x540e
+ XCASE = 0x4
+)
diff --git a/src/syscall/ztypes_linux_mips64.go b/src/syscall/ztypes_linux_mips64.go
index 9093086..925afb9 100644
--- a/src/syscall/ztypes_linux_mips64.go
+++ b/src/syscall/ztypes_linux_mips64.go
@@ -244,10 +244,9 @@ type Msghdr struct {
}
type Cmsghdr struct {
- Len uint64
- Level int32
- Type int32
- X__cmsg_data [0]uint8
+ Len uint64
+ Level int32
+ Type int32
}
type Inet4Pktinfo struct {
diff --git a/src/syscall/ztypes_linux_mips64le.go b/src/syscall/ztypes_linux_mips64le.go
index 9093086..925afb9 100644
--- a/src/syscall/ztypes_linux_mips64le.go
+++ b/src/syscall/ztypes_linux_mips64le.go
@@ -244,10 +244,9 @@ type Msghdr struct {
}
type Cmsghdr struct {
- Len uint64
- Level int32
- Type int32
- X__cmsg_data [0]uint8
+ Len uint64
+ Level int32
+ Type int32
}
type Inet4Pktinfo struct {
diff --git a/src/syscall/ztypes_linux_mipsle.go b/src/syscall/ztypes_linux_mipsle.go
new file mode 100644
index 0000000..7a8d34d
--- /dev/null
+++ b/src/syscall/ztypes_linux_mipsle.go
@@ -0,0 +1,592 @@
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs types_linux.go
+
+package syscall
+
+const (
+ sizeofPtr = 0x4
+ sizeofShort = 0x2
+ sizeofInt = 0x4
+ sizeofLong = 0x4
+ sizeofLongLong = 0x8
+ PathMax = 0x1000
+)
+
+type (
+ _C_short int16
+ _C_int int32
+ _C_long int32
+ _C_long_long int64
+)
+
+type Timespec struct {
+ Sec int32
+ Nsec int32
+}
+
+type Timeval struct {
+ Sec int32
+ Usec int32
+}
+
+type Timex struct {
+ Modes uint32
+ Offset int32
+ Freq int32
+ Maxerror int32
+ Esterror int32
+ Status int32
+ Constant int32
+ Precision int32
+ Tolerance int32
+ Time Timeval
+ Tick int32
+ Ppsfreq int32
+ Jitter int32
+ Shift int32
+ Stabil int32
+ Jitcnt int32
+ Calcnt int32
+ Errcnt int32
+ Stbcnt int32
+ Tai int32
+ Pad_cgo_0 [44]byte
+}
+
+type Time_t int32
+
+type Tms struct {
+ Utime int32
+ Stime int32
+ Cutime int32
+ Cstime int32
+}
+
+type Utimbuf struct {
+ Actime int32
+ Modtime int32
+}
+
+type Rusage struct {
+ Utime Timeval
+ Stime Timeval
+ Maxrss int32
+ Ixrss int32
+ Idrss int32
+ Isrss int32
+ Minflt int32
+ Majflt int32
+ Nswap int32
+ Inblock int32
+ Oublock int32
+ Msgsnd int32
+ Msgrcv int32
+ Nsignals int32
+ Nvcsw int32
+ Nivcsw int32
+}
+
+type Rlimit struct {
+ Cur uint64
+ Max uint64
+}
+
+type _Gid_t uint32
+
+type Stat_t struct {
+ Dev uint32
+ Pad1 [3]int32
+ Ino uint64
+ Mode uint32
+ Nlink uint32
+ Uid uint32
+ Gid uint32
+ Rdev uint32
+ Pad2 [3]int32
+ Size int64
+ Atim Timespec
+ Mtim Timespec
+ Ctim Timespec
+ Blksize int32
+ Pad4 int32
+ Blocks int64
+ Pad5 [14]int32
+}
+
+type Statfs_t struct {
+ Type int32
+ Bsize int32
+ Frsize int32
+ Pad_cgo_0 [4]byte
+ Blocks uint64
+ Bfree uint64
+ Files uint64
+ Ffree uint64
+ Bavail uint64
+ Fsid Fsid
+ Namelen int32
+ Flags int32
+ Spare [5]int32
+ Pad_cgo_1 [4]byte
+}
+
+type Dirent struct {
+ Ino uint64
+ Off int64
+ Reclen uint16
+ Type uint8
+ Name [256]int8
+ Pad_cgo_0 [5]byte
+}
+
+type Fsid struct {
+ X__val [2]int32
+}
+
+type Flock_t struct {
+ Type int16
+ Whence int16
+ Pad_cgo_0 [4]byte
+ Start int64
+ Len int64
+ Pid int32
+ Pad_cgo_1 [4]byte
+}
+
+type RawSockaddrInet4 struct {
+ Family uint16
+ Port uint16
+ Addr [4]byte /* in_addr */
+ Zero [8]uint8
+}
+
+type RawSockaddrInet6 struct {
+ Family uint16
+ Port uint16
+ Flowinfo uint32
+ Addr [16]byte /* in6_addr */
+ Scope_id uint32
+}
+
+type RawSockaddrUnix struct {
+ Family uint16
+ Path [108]int8
+}
+
+type RawSockaddrLinklayer struct {
+ Family uint16
+ Protocol uint16
+ Ifindex int32
+ Hatype uint16
+ Pkttype uint8
+ Halen uint8
+ Addr [8]uint8
+}
+
+type RawSockaddrNetlink struct {
+ Family uint16
+ Pad uint16
+ Pid uint32
+ Groups uint32
+}
+
+type RawSockaddr struct {
+ Family uint16
+ Data [14]int8
+}
+
+type RawSockaddrAny struct {
+ Addr RawSockaddr
+ Pad [96]int8
+}
+
+type _Socklen uint32
+
+type Linger struct {
+ Onoff int32
+ Linger int32
+}
+
+type Iovec struct {
+ Base *byte
+ Len uint32
+}
+
+type IPMreq struct {
+ Multiaddr [4]byte /* in_addr */
+ Interface [4]byte /* in_addr */
+}
+
+type IPMreqn struct {
+ Multiaddr [4]byte /* in_addr */
+ Address [4]byte /* in_addr */
+ Ifindex int32
+}
+
+type IPv6Mreq struct {
+ Multiaddr [16]byte /* in6_addr */
+ Interface uint32
+}
+
+type Msghdr struct {
+ Name *byte
+ Namelen uint32
+ Iov *Iovec
+ Iovlen uint32
+ Control *byte
+ Controllen uint32
+ Flags int32
+}
+
+type Cmsghdr struct {
+ Len uint32
+ Level int32
+ Type int32
+}
+
+type Inet4Pktinfo struct {
+ Ifindex int32
+ Spec_dst [4]byte /* in_addr */
+ Addr [4]byte /* in_addr */
+}
+
+type Inet6Pktinfo struct {
+ Addr [16]byte /* in6_addr */
+ Ifindex uint32
+}
+
+type IPv6MTUInfo struct {
+ Addr RawSockaddrInet6
+ Mtu uint32
+}
+
+type ICMPv6Filter struct {
+ Data [8]uint32
+}
+
+type Ucred struct {
+ Pid int32
+ Uid uint32
+ Gid uint32
+}
+
+type TCPInfo struct {
+ State uint8
+ Ca_state uint8
+ Retransmits uint8
+ Probes uint8
+ Backoff uint8
+ Options uint8
+ Pad_cgo_0 [2]byte
+ Rto uint32
+ Ato uint32
+ Snd_mss uint32
+ Rcv_mss uint32
+ Unacked uint32
+ Sacked uint32
+ Lost uint32
+ Retrans uint32
+ Fackets uint32
+ Last_data_sent uint32
+ Last_ack_sent uint32
+ Last_data_recv uint32
+ Last_ack_recv uint32
+ Pmtu uint32
+ Rcv_ssthresh uint32
+ Rtt uint32
+ Rttvar uint32
+ Snd_ssthresh uint32
+ Snd_cwnd uint32
+ Advmss uint32
+ Reordering uint32
+ Rcv_rtt uint32
+ Rcv_space uint32
+ Total_retrans uint32
+}
+
+const (
+ SizeofSockaddrInet4 = 0x10
+ SizeofSockaddrInet6 = 0x1c
+ SizeofSockaddrAny = 0x70
+ SizeofSockaddrUnix = 0x6e
+ SizeofSockaddrLinklayer = 0x14
+ SizeofSockaddrNetlink = 0xc
+ SizeofLinger = 0x8
+ SizeofIPMreq = 0x8
+ SizeofIPMreqn = 0xc
+ SizeofIPv6Mreq = 0x14
+ SizeofMsghdr = 0x1c
+ SizeofCmsghdr = 0xc
+ SizeofInet4Pktinfo = 0xc
+ SizeofInet6Pktinfo = 0x14
+ SizeofIPv6MTUInfo = 0x20
+ SizeofICMPv6Filter = 0x20
+ SizeofUcred = 0xc
+ SizeofTCPInfo = 0x68
+)
+
+const (
+ IFA_UNSPEC = 0x0
+ IFA_ADDRESS = 0x1
+ IFA_LOCAL = 0x2
+ IFA_LABEL = 0x3
+ IFA_BROADCAST = 0x4
+ IFA_ANYCAST = 0x5
+ IFA_CACHEINFO = 0x6
+ IFA_MULTICAST = 0x7
+ IFLA_UNSPEC = 0x0
+ IFLA_ADDRESS = 0x1
+ IFLA_BROADCAST = 0x2
+ IFLA_IFNAME = 0x3
+ IFLA_MTU = 0x4
+ IFLA_LINK = 0x5
+ IFLA_QDISC = 0x6
+ IFLA_STATS = 0x7
+ IFLA_COST = 0x8
+ IFLA_PRIORITY = 0x9
+ IFLA_MASTER = 0xa
+ IFLA_WIRELESS = 0xb
+ IFLA_PROTINFO = 0xc
+ IFLA_TXQLEN = 0xd
+ IFLA_MAP = 0xe
+ IFLA_WEIGHT = 0xf
+ IFLA_OPERSTATE = 0x10
+ IFLA_LINKMODE = 0x11
+ IFLA_LINKINFO = 0x12
+ IFLA_NET_NS_PID = 0x13
+ IFLA_IFALIAS = 0x14
+ IFLA_MAX = 0x27
+ RT_SCOPE_UNIVERSE = 0x0
+ RT_SCOPE_SITE = 0xc8
+ RT_SCOPE_LINK = 0xfd
+ RT_SCOPE_HOST = 0xfe
+ RT_SCOPE_NOWHERE = 0xff
+ RT_TABLE_UNSPEC = 0x0
+ RT_TABLE_COMPAT = 0xfc
+ RT_TABLE_DEFAULT = 0xfd
+ RT_TABLE_MAIN = 0xfe
+ RT_TABLE_LOCAL = 0xff
+ RT_TABLE_MAX = 0xffffffff
+ RTA_UNSPEC = 0x0
+ RTA_DST = 0x1
+ RTA_SRC = 0x2
+ RTA_IIF = 0x3
+ RTA_OIF = 0x4
+ RTA_GATEWAY = 0x5
+ RTA_PRIORITY = 0x6
+ RTA_PREFSRC = 0x7
+ RTA_METRICS = 0x8
+ RTA_MULTIPATH = 0x9
+ RTA_FLOW = 0xb
+ RTA_CACHEINFO = 0xc
+ RTA_TABLE = 0xf
+ RTN_UNSPEC = 0x0
+ RTN_UNICAST = 0x1
+ RTN_LOCAL = 0x2
+ RTN_BROADCAST = 0x3
+ RTN_ANYCAST = 0x4
+ RTN_MULTICAST = 0x5
+ RTN_BLACKHOLE = 0x6
+ RTN_UNREACHABLE = 0x7
+ RTN_PROHIBIT = 0x8
+ RTN_THROW = 0x9
+ RTN_NAT = 0xa
+ RTN_XRESOLVE = 0xb
+ RTNLGRP_NONE = 0x0
+ RTNLGRP_LINK = 0x1
+ RTNLGRP_NOTIFY = 0x2
+ RTNLGRP_NEIGH = 0x3
+ RTNLGRP_TC = 0x4
+ RTNLGRP_IPV4_IFADDR = 0x5
+ RTNLGRP_IPV4_MROUTE = 0x6
+ RTNLGRP_IPV4_ROUTE = 0x7
+ RTNLGRP_IPV4_RULE = 0x8
+ RTNLGRP_IPV6_IFADDR = 0x9
+ RTNLGRP_IPV6_MROUTE = 0xa
+ RTNLGRP_IPV6_ROUTE = 0xb
+ RTNLGRP_IPV6_IFINFO = 0xc
+ RTNLGRP_IPV6_PREFIX = 0x12
+ RTNLGRP_IPV6_RULE = 0x13
+ RTNLGRP_ND_USEROPT = 0x14
+ SizeofNlMsghdr = 0x10
+ SizeofNlMsgerr = 0x14
+ SizeofRtGenmsg = 0x1
+ SizeofNlAttr = 0x4
+ SizeofRtAttr = 0x4
+ SizeofIfInfomsg = 0x10
+ SizeofIfAddrmsg = 0x8
+ SizeofRtMsg = 0xc
+ SizeofRtNexthop = 0x8
+)
+
+type NlMsghdr struct {
+ Len uint32
+ Type uint16
+ Flags uint16
+ Seq uint32
+ Pid uint32
+}
+
+type NlMsgerr struct {
+ Error int32
+ Msg NlMsghdr
+}
+
+type RtGenmsg struct {
+ Family uint8
+}
+
+type NlAttr struct {
+ Len uint16
+ Type uint16
+}
+
+type RtAttr struct {
+ Len uint16
+ Type uint16
+}
+
+type IfInfomsg struct {
+ Family uint8
+ X__ifi_pad uint8
+ Type uint16
+ Index int32
+ Flags uint32
+ Change uint32
+}
+
+type IfAddrmsg struct {
+ Family uint8
+ Prefixlen uint8
+ Flags uint8
+ Scope uint8
+ Index uint32
+}
+
+type RtMsg struct {
+ Family uint8
+ Dst_len uint8
+ Src_len uint8
+ Tos uint8
+ Table uint8
+ Protocol uint8
+ Scope uint8
+ Type uint8
+ Flags uint32
+}
+
+type RtNexthop struct {
+ Len uint16
+ Flags uint8
+ Hops uint8
+ Ifindex int32
+}
+
+const (
+ SizeofSockFilter = 0x8
+ SizeofSockFprog = 0x8
+)
+
+type SockFilter struct {
+ Code uint16
+ Jt uint8
+ Jf uint8
+ K uint32
+}
+
+type SockFprog struct {
+ Len uint16
+ Pad_cgo_0 [2]byte
+ Filter *SockFilter
+}
+
+type InotifyEvent struct {
+ Wd int32
+ Mask uint32
+ Cookie uint32
+ Len uint32
+}
+
+const SizeofInotifyEvent = 0x10
+
+type PtraceRegs struct {
+ Regs [109]uint32
+ U_tsize uint32
+ U_dsize uint32
+ U_ssize uint32
+ Start_code uint32
+ Start_data uint32
+ Start_stack uint32
+ Signal int32
+ U_ar0 *byte
+ Magic uint32
+ U_comm [32]int8
+}
+
+type FdSet struct {
+ Bits [32]int32
+}
+
+type Sysinfo_t struct {
+ Uptime int32
+ Loads [3]uint32
+ Totalram uint32
+ Freeram uint32
+ Sharedram uint32
+ Bufferram uint32
+ Totalswap uint32
+ Freeswap uint32
+ Procs uint16
+ Pad uint16
+ Totalhigh uint32
+ Freehigh uint32
+ Unit uint32
+ X_f [8]int8
+}
+
+type Utsname struct {
+ Sysname [65]int8
+ Nodename [65]int8
+ Release [65]int8
+ Version [65]int8
+ Machine [65]int8
+ Domainname [65]int8
+}
+
+type Ustat_t struct {
+ Tfree int32
+ Tinode uint32
+ Fname [6]int8
+ Fpack [6]int8
+}
+
+type EpollEvent struct {
+ Events uint32
+ PadFd int32
+ Fd int32
+ Pad int32
+}
+
+const (
+ _AT_FDCWD = -0x64
+ _AT_REMOVEDIR = 0x200
+ _AT_SYMLINK_NOFOLLOW = 0x100
+)
+
+type Termios struct {
+ Iflag uint32
+ Oflag uint32
+ Cflag uint32
+ Lflag uint32
+ Line uint8
+ Cc [32]uint8
+ Pad_cgo_0 [3]byte
+}
+
+const (
+ IUCLC = 0x200
+ OLCUC = 0x2
+ TCGETS = 0x540d
+ TCSETS = 0x540e
+ XCASE = 0x4
+)
diff --git a/src/syscall/ztypes_linux_ppc64.go b/src/syscall/ztypes_linux_ppc64.go
index 915ca95..de817f5 100644
--- a/src/syscall/ztypes_linux_ppc64.go
+++ b/src/syscall/ztypes_linux_ppc64.go
@@ -244,10 +244,9 @@ type Msghdr struct {
}
type Cmsghdr struct {
- Len uint64
- Level int32
- Type int32
- X__cmsg_data [0]uint8
+ Len uint64
+ Level int32
+ Type int32
}
type Inet4Pktinfo struct {
diff --git a/src/syscall/ztypes_linux_ppc64le.go b/src/syscall/ztypes_linux_ppc64le.go
index a118055..e75d8e3 100644
--- a/src/syscall/ztypes_linux_ppc64le.go
+++ b/src/syscall/ztypes_linux_ppc64le.go
@@ -244,10 +244,9 @@ type Msghdr struct {
}
type Cmsghdr struct {
- Len uint64
- Level int32
- Type int32
- X__cmsg_data [0]uint8
+ Len uint64
+ Level int32
+ Type int32
}
type Inet4Pktinfo struct {
diff --git a/src/syscall/ztypes_windows.go b/src/syscall/ztypes_windows.go
index 191c6e6..1fb6f5c 100644
--- a/src/syscall/ztypes_windows.go
+++ b/src/syscall/ztypes_windows.go
@@ -18,6 +18,7 @@ const (
ERROR_INSUFFICIENT_BUFFER Errno = 122
ERROR_MOD_NOT_FOUND Errno = 126
ERROR_PROC_NOT_FOUND Errno = 127
+ ERROR_DIR_NOT_EMPTY Errno = 145
ERROR_ALREADY_EXISTS Errno = 183
ERROR_ENVVAR_NOT_FOUND Errno = 203
ERROR_MORE_DATA Errno = 234
@@ -1115,4 +1116,5 @@ const (
_IO_REPARSE_TAG_MOUNT_POINT = 0xA0000003
IO_REPARSE_TAG_SYMLINK = 0xA000000C
SYMBOLIC_LINK_FLAG_DIRECTORY = 0x1
+ _SYMLINK_FLAG_RELATIVE = 1
)
diff --git a/src/testing/benchmark.go b/src/testing/benchmark.go
index 5d58b85..b1c6d2e 100644
--- a/src/testing/benchmark.go
+++ b/src/testing/benchmark.go
@@ -5,8 +5,10 @@
package testing
import (
+ "context"
"flag"
"fmt"
+ "internal/race"
"os"
"runtime"
"sync"
@@ -14,8 +16,8 @@ import (
"time"
)
-var matchBenchmarks = flag.String("test.bench", "", "regular expression per path component to select benchmarks to run")
-var benchTime = flag.Duration("test.benchtime", 1*time.Second, "approximate run time for each benchmark")
+var matchBenchmarks = flag.String("test.bench", "", "run only benchmarks matching `regexp`")
+var benchTime = flag.Duration("test.benchtime", 1*time.Second, "run each benchmark for duration `d`")
var benchmarkMemory = flag.Bool("test.benchmem", false, "print memory allocations for benchmarks")
// Global lock to ensure only one benchmark runs at a time.
@@ -56,7 +58,6 @@ type B struct {
missingBytes bool // one of the subbenchmarks does not have bytes set.
timerOn bool
showAllocResult bool
- hasSub bool
result BenchmarkResult
parallelism int // RunParallel creates parallelism*GOMAXPROCS goroutines
// The initial states of memStats.Mallocs and memStats.TotalAlloc.
@@ -127,11 +128,15 @@ func (b *B) nsPerOp() int64 {
// runN runs a single benchmark for the specified number of iterations.
func (b *B) runN(n int) {
+ b.ctx, b.cancel = context.WithCancel(b.parentContext())
+ defer b.cancel()
+
benchmarkLock.Lock()
defer benchmarkLock.Unlock()
// Try to get a comparable environment for each run
// by clearing garbage from previous runs.
runtime.GC()
+ b.raceErrors = -race.Errors()
b.N = n
b.parallelism = 1
b.ResetTimer()
@@ -140,6 +145,10 @@ func (b *B) runN(n int) {
b.StopTimer()
b.previousN = n
b.previousDuration = b.duration
+ b.raceErrors += race.Errors()
+ if b.raceErrors > 0 {
+ b.Errorf("race detected during execution of benchmark")
+ }
}
func min(x, y int) int {
@@ -263,10 +272,9 @@ func (b *B) launch() {
for n := 1; !b.failed && b.duration < d && n < 1e9; {
last := n
// Predict required iterations.
- if b.nsPerOp() == 0 {
- n = 1e9
- } else {
- n = int(d.Nanoseconds() / b.nsPerOp())
+ n = int(d.Nanoseconds())
+ if nsop := b.nsPerOp(); nsop != 0 {
+ n /= int(nsop)
}
// Run more iterations than we think we'll need (1.2x).
// Don't grow too fast in case we had timing errors previously.
@@ -359,10 +367,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) {
- runBenchmarksInternal(matchString, benchmarks)
+ runBenchmarks(matchString, benchmarks)
}
-func runBenchmarksInternal(matchString func(pat, str string) (bool, error), benchmarks []InternalBenchmark) bool {
+func runBenchmarks(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
diff --git a/src/testing/example.go b/src/testing/example.go
index fd8343f..e5bce7a 100644
--- a/src/testing/example.go
+++ b/src/testing/example.go
@@ -21,7 +21,14 @@ type InternalExample struct {
Unordered bool
}
+// An internal function but exported because it is cross-package; part of the implementation
+// of the "go test" command.
func RunExamples(matchString func(pat, str string) (bool, error), examples []InternalExample) (ok bool) {
+ _, ok = runExamples(matchString, examples)
+ return ok
+}
+
+func runExamples(matchString func(pat, str string) (bool, error), examples []InternalExample) (ran, ok bool) {
ok = true
var eg InternalExample
@@ -35,12 +42,13 @@ func RunExamples(matchString func(pat, str string) (bool, error), examples []Int
if !matched {
continue
}
+ ran = true
if !runExample(eg) {
ok = false
}
}
- return
+ return ran, ok
}
func sortLines(output string) string {
diff --git a/src/testing/internal/testdeps/deps.go b/src/testing/internal/testdeps/deps.go
new file mode 100644
index 0000000..b08300b
--- /dev/null
+++ b/src/testing/internal/testdeps/deps.go
@@ -0,0 +1,51 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package testdeps provides access to dependencies needed by test execution.
+//
+// This package is imported by the generated main package, which passes
+// TestDeps into testing.Main. This allows tests to use packages at run time
+// without making those packages direct dependencies of package testing.
+// Direct dependencies of package testing are harder to write tests for.
+package testdeps
+
+import (
+ "io"
+ "regexp"
+ "runtime/pprof"
+)
+
+// TestDeps is an implementation of the testing.testDeps interface,
+// suitable for passing to testing.MainStart.
+type TestDeps struct{}
+
+var matchPat string
+var matchRe *regexp.Regexp
+
+func (TestDeps) MatchString(pat, str string) (result bool, err error) {
+ if matchRe == nil || matchPat != pat {
+ matchPat = pat
+ matchRe, err = regexp.Compile(matchPat)
+ if err != nil {
+ return
+ }
+ }
+ return matchRe.MatchString(str), nil
+}
+
+func (TestDeps) StartCPUProfile(w io.Writer) error {
+ return pprof.StartCPUProfile(w)
+}
+
+func (TestDeps) StopCPUProfile() {
+ pprof.StopCPUProfile()
+}
+
+func (TestDeps) WriteHeapProfile(w io.Writer) error {
+ return pprof.WriteHeapProfile(w)
+}
+
+func (TestDeps) WriteProfileTo(name string, w io.Writer, debug int) error {
+ return pprof.Lookup(name).WriteTo(w, debug)
+}
diff --git a/src/testing/quick/quick.go b/src/testing/quick/quick.go
index 798d41a..95860fd 100644
--- a/src/testing/quick/quick.go
+++ b/src/testing/quick/quick.go
@@ -3,6 +3,8 @@
// license that can be found in the LICENSE file.
// Package quick implements utility functions to help with black box testing.
+//
+// The testing/quick package is frozen and is not accepting new features.
package quick
import (
diff --git a/src/testing/sub_test.go b/src/testing/sub_test.go
index 2a24aaa..563e865 100644
--- a/src/testing/sub_test.go
+++ b/src/testing/sub_test.go
@@ -6,6 +6,7 @@ package testing
import (
"bytes"
+ "context"
"regexp"
"strings"
"sync/atomic"
@@ -277,28 +278,33 @@ func TestTRun(t *T) {
ok: true,
maxPar: 4,
f: func(t *T) {
- t.Parallel()
- for i := 0; i < 12; i++ {
- t.Run("a", func(t *T) {
- t.Parallel()
- time.Sleep(time.Nanosecond)
- for i := 0; i < 12; i++ {
- t.Run("b", func(t *T) {
- time.Sleep(time.Nanosecond)
- for i := 0; i < 12; i++ {
- t.Run("c", func(t *T) {
- t.Parallel()
- time.Sleep(time.Nanosecond)
- t.Run("d1", func(t *T) {})
- t.Run("d2", func(t *T) {})
- t.Run("d3", func(t *T) {})
- t.Run("d4", func(t *T) {})
- })
- }
- })
- }
- })
- }
+ // t.Parallel doesn't work in the pseudo-T we start with:
+ // it leaks a goroutine.
+ // Call t.Run to get a real one.
+ t.Run("X", func(t *T) {
+ t.Parallel()
+ for i := 0; i < 12; i++ {
+ t.Run("a", func(t *T) {
+ t.Parallel()
+ time.Sleep(time.Nanosecond)
+ for i := 0; i < 12; i++ {
+ t.Run("b", func(t *T) {
+ time.Sleep(time.Nanosecond)
+ for i := 0; i < 12; i++ {
+ t.Run("c", func(t *T) {
+ t.Parallel()
+ time.Sleep(time.Nanosecond)
+ t.Run("d1", func(t *T) {})
+ t.Run("d2", func(t *T) {})
+ t.Run("d3", func(t *T) {})
+ t.Run("d4", func(t *T) {})
+ })
+ }
+ })
+ }
+ })
+ }
+ })
},
}, {
desc: "skip output",
@@ -341,6 +347,7 @@ func TestTRun(t *T) {
},
context: ctx,
}
+ root.ctx, root.cancel = context.WithCancel(context.Background())
ok := root.Run(tc.desc, tc.f)
ctx.release()
diff --git a/src/testing/testing.go b/src/testing/testing.go
index e1dbe00..f08c5c6 100644
--- a/src/testing/testing.go
+++ b/src/testing/testing.go
@@ -137,13 +137,17 @@
// of the top-level test and the sequence of names passed to Run, separated by
// slashes, with an optional trailing sequence number for disambiguation.
//
-// The argument to the -run and -bench command-line flags is a slash-separated
-// list of regular expressions that match each name element in turn.
-// For example:
+// The argument to the -run and -bench command-line flags is an unanchored regular
+// expression that matches the test's name. For tests with multiple slash-separated
+// elements, such as subtests, the argument is itself slash-separated, with
+// expressions matching each name element in turn. Because it is unanchored, an
+// empty expression matches any string.
+// For example, using "matching" to mean "whose name contains":
//
-// go test -run Foo # Run top-level tests matching "Foo".
-// go test -run Foo/A= # Run subtests of Foo matching "A=".
-// go test -run /A=1 # Run all subtests of a top-level test matching "A=1".
+// go test -run '' # Run all tests.
+// go test -run Foo # Run top-level tests matching "Foo", such as "TestFooBar".
+// go test -run Foo/A= # For top-level tests matching "Foo", run subtests matching "A=".
+// go test -run /A=1 # For all top-level tests, run subtests matching "A=1".
//
// Subtests can also be used to control parallelism. A parent test will only
// complete once all of its subtests complete. In this example, all tests are
@@ -192,7 +196,7 @@
// A simple implementation of TestMain is:
//
// func TestMain(m *testing.M) {
-// flag.Parse()
+// // call flag.Parse() here if TestMain uses flags
// os.Exit(m.Run())
// }
//
@@ -200,13 +204,15 @@ package testing
import (
"bytes"
+ "context"
+ "errors"
"flag"
"fmt"
+ "internal/race"
"io"
"os"
"runtime"
"runtime/debug"
- "runtime/pprof"
"runtime/trace"
"strconv"
"strings"
@@ -226,22 +232,24 @@ var (
// "go test", the binary always runs in the source directory for the package;
// this flag lets "go test" tell the binary to write the files in the directory where
// the "go test" command is run.
- outputDir = flag.String("test.outputdir", "", "directory in which to write profiles")
+ outputDir = flag.String("test.outputdir", "", "write profiles to `dir`")
// Report as tests are run; default is silent for success.
- chatty = flag.Bool("test.v", false, "verbose: print additional output")
- count = flag.Uint("test.count", 1, "run tests and benchmarks `n` times")
- coverProfile = flag.String("test.coverprofile", "", "write a coverage profile to the named file after execution")
- match = flag.String("test.run", "", "regular expression to select tests and examples to run")
- memProfile = flag.String("test.memprofile", "", "write a memory profile to the named file after execution")
- memProfileRate = flag.Int("test.memprofilerate", 0, "if >=0, sets runtime.MemProfileRate")
- cpuProfile = flag.String("test.cpuprofile", "", "write a cpu profile to the named file during execution")
- blockProfile = flag.String("test.blockprofile", "", "write a goroutine blocking profile to the named file after execution")
- blockProfileRate = flag.Int("test.blockprofilerate", 1, "if >= 0, calls runtime.SetBlockProfileRate()")
- traceFile = flag.String("test.trace", "", "write an execution trace to the named file after execution")
- timeout = flag.Duration("test.timeout", 0, "if positive, sets an aggregate time limit for all tests")
- cpuListStr = flag.String("test.cpu", "", "comma-separated list of number of CPUs to use for each test")
- parallel = flag.Int("test.parallel", runtime.GOMAXPROCS(0), "maximum test parallelism")
+ 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`")
+ 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)")
+ cpuProfile = flag.String("test.cpuprofile", "", "write a cpu profile to `file`")
+ blockProfile = flag.String("test.blockprofile", "", "write a goroutine blocking profile to `file`")
+ blockProfileRate = flag.Int("test.blockprofilerate", 1, "set blocking profile `rate` (see runtime.SetBlockProfileRate)")
+ mutexProfile = flag.String("test.mutexprofile", "", "write a mutex contention profile to the named file after execution")
+ mutexProfileFraction = flag.Int("test.mutexprofilefraction", 1, "if >= 0, calls runtime.SetMutexProfileFraction()")
+ traceFile = flag.String("test.trace", "", "write an execution trace to `file`")
+ timeout = flag.Duration("test.timeout", 0, "fail test binary execution after duration `d` (0 means unlimited)")
+ cpuListStr = flag.String("test.cpu", "", "comma-separated `list` of cpu counts to run each test with")
+ parallel = flag.Int("test.parallel", runtime.GOMAXPROCS(0), "run at most `n` tests in parallel")
haveExamples bool // are there examples?
@@ -251,14 +259,19 @@ var (
// common holds the elements common between T and B and
// captures common methods such as Errorf.
type common struct {
- mu sync.RWMutex // guards output, failed, and done.
- output []byte // Output generated by test or benchmark.
- w io.Writer // For flushToParent.
- chatty bool // A copy of the chatty flag.
- failed bool // Test or benchmark has failed.
- skipped bool // Test of benchmark has been skipped.
- finished bool // Test function has completed.
- done bool // Test is finished and all subtests have completed.
+ mu sync.RWMutex // guards output, failed, and done.
+ output []byte // Output generated by test or benchmark.
+ w io.Writer // For flushToParent.
+ ctx context.Context
+ cancel context.CancelFunc
+ 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 bool
+ raceErrors int // number of races detected during test
parent *common
level int // Nesting depth of test or benchmark.
@@ -270,11 +283,25 @@ type common struct {
sub []*T // Queue of subtests to be run in parallel.
}
+func (c *common) parentContext() context.Context {
+ if c == nil || c.parent == nil || c.parent.ctx == nil {
+ return context.Background()
+ }
+ return c.parent.ctx
+}
+
// Short reports whether the -test.short flag is set.
func Short() bool {
return *short
}
+// CoverMode reports what the test coverage mode is set to. The
+// values are "set", "count", or "atomic". The return value will be
+// empty if test coverage is not enabled.
+func CoverMode() string {
+ return cover.Mode
+}
+
// Verbose reports whether the -test.v flag is set.
func Verbose() bool {
return *chatty
@@ -359,6 +386,7 @@ func fmtDuration(d time.Duration) string {
// TB is the interface common to T and B.
type TB interface {
+ Context() context.Context
Error(args ...interface{})
Errorf(format string, args ...interface{})
Fail()
@@ -368,6 +396,7 @@ type TB interface {
Fatalf(format string, args ...interface{})
Log(args ...interface{})
Logf(format string, args ...interface{})
+ Name() string
Skip(args ...interface{})
SkipNow()
Skipf(format string, args ...interface{})
@@ -400,6 +429,29 @@ type T struct {
func (c *common) private() {}
+// Name returns the name of the running test or benchmark.
+func (c *common) Name() string {
+ return c.name
+}
+
+// Context returns the context for the current test or benchmark.
+// The context is cancelled when the test or benchmark finishes.
+// A goroutine started during a test or benchmark can wait for the
+// context's Done channel to become readable as a signal that the
+// test or benchmark is over, so that the goroutine can exit.
+func (c *common) Context() context.Context {
+ return c.ctx
+}
+
+func (c *common) setRan() {
+ if c.parent != nil {
+ c.parent.setRan()
+ }
+ c.mu.Lock()
+ defer c.mu.Unlock()
+ c.ran = true
+}
+
// Fail marks the function as having failed but continues execution.
func (c *common) Fail() {
if c.parent != nil {
@@ -466,10 +518,11 @@ func (c *common) log(s string) {
// printed to avoid having performance depend on the value of the -test.v flag.
func (c *common) Log(args ...interface{}) { c.log(fmt.Sprintln(args...)) }
-// Logf formats its arguments according to the format, analogous to Printf,
-// and records the text in the error log. For tests, the text will be printed only if
-// the test fails or the -test.v flag is set. For benchmarks, the text is always
-// printed to avoid having performance depend on the value of the -test.v flag.
+// Logf formats its arguments according to the format, analogous to Printf, and
+// records the text in the error log. A final newline is added if not provided. For
+// tests, the text will be printed only if the test fails or the -test.v flag is
+// set. For benchmarks, the text is always printed to avoid having performance
+// depend on the value of the -test.v flag.
func (c *common) Logf(format string, args ...interface{}) { c.log(fmt.Sprintf(format, args...)) }
// Error is equivalent to Log followed by Fail.
@@ -509,6 +562,8 @@ func (c *common) Skipf(format string, args ...interface{}) {
}
// SkipNow marks the test as having been skipped and stops its execution.
+// If a test fails (see Error, Errorf, Fail) and is then skipped,
+// it is still considered to have failed.
// Execution will continue at the next test or benchmark. See also FailNow.
// SkipNow must be called from the goroutine running the test, not from
// other goroutines created during the test. Calling SkipNow does not stop
@@ -547,11 +602,13 @@ func (t *T) Parallel() {
// Add to the list of tests to be released by the parent.
t.parent.sub = append(t.parent.sub, t)
+ t.raceErrors += race.Errors()
t.signal <- true // Release calling test.
<-t.parent.barrier // Wait for the parent test to complete.
t.context.waitParallel()
t.start = time.Now()
+ t.raceErrors += -race.Errors()
}
// An internal type but exported because it is cross-package; part of the implementation
@@ -562,11 +619,19 @@ type InternalTest struct {
}
func tRunner(t *T, fn func(t *T)) {
+ t.ctx, t.cancel = context.WithCancel(t.parentContext())
+ defer t.cancel()
+
// When this goroutine is done, either because fn(t)
// returned normally or because a test failure triggered
// a call to runtime.Goexit, record the duration and send
// a signal saying that the test is done.
defer func() {
+ t.raceErrors += race.Errors()
+ if t.raceErrors > 0 {
+ t.Errorf("race detected during execution of test")
+ }
+
t.duration += time.Now().Sub(t.start)
// If the test panicked, print any test output before dying.
err := recover()
@@ -603,10 +668,14 @@ func tRunner(t *T, fn func(t *T)) {
// Do not lock t.done to allow race detector to detect race in case
// the user does not appropriately synchronizes a goroutine.
t.done = true
+ if t.parent != nil && !t.hasSub {
+ t.setRan()
+ }
t.signal <- true
}()
t.start = time.Now()
+ t.raceErrors = -race.Errors()
fn(t)
t.finished = true
}
@@ -614,6 +683,7 @@ func tRunner(t *T, fn func(t *T)) {
// Run runs f as a subtest of t called name. It reports whether f succeeded.
// Run will block until all its parallel subtests have completed.
func (t *T) Run(name string, f func(t *T)) bool {
+ t.hasSub = true
testName, ok := t.context.match.fullName(&t.common, name)
if !ok {
return true
@@ -702,29 +772,57 @@ func (c *testContext) release() {
c.startParallel <- true // Pick a waiting test to be run.
}
-// An internal function but exported because it is cross-package; part of the implementation
-// of the "go test" command.
+// No one should be using func Main anymore.
+// See the doc comment on func Main and use MainStart instead.
+var errMain = errors.New("testing: unexpected use of func Main")
+
+type matchStringOnly func(pat, str string) (bool, error)
+
+func (f matchStringOnly) MatchString(pat, str string) (bool, error) { return f(pat, str) }
+func (f matchStringOnly) StartCPUProfile(w io.Writer) error { return errMain }
+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 }
+
+// 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.
+// It is no longer used by "go test" but preserved, as much as possible, for other
+// systems that simulate "go test" using Main, but Main sometimes cannot be updated as
+// new functionality is added to the testing package.
+// Systems simulating "go test" should be updated to use MainStart.
func Main(matchString func(pat, str string) (bool, error), tests []InternalTest, benchmarks []InternalBenchmark, examples []InternalExample) {
- os.Exit(MainStart(matchString, tests, benchmarks, examples).Run())
+ os.Exit(MainStart(matchStringOnly(matchString), tests, benchmarks, examples).Run())
}
// M is a type passed to a TestMain function to run the actual tests.
type M struct {
- matchString func(pat, str string) (bool, error)
- tests []InternalTest
- benchmarks []InternalBenchmark
- examples []InternalExample
+ deps testDeps
+ tests []InternalTest
+ benchmarks []InternalBenchmark
+ examples []InternalExample
+}
+
+// testDeps is an internal interface of functionality that is
+// passed into this package by a test's generated main package.
+// The canonical implementation of this interface is
+// testing/internal/testdeps's TestDeps.
+type testDeps interface {
+ MatchString(pat, str string) (bool, error)
+ StartCPUProfile(io.Writer) error
+ StopCPUProfile()
+ WriteHeapProfile(io.Writer) error
+ WriteProfileTo(string, io.Writer, int) error
}
// MainStart is meant for use by tests generated by 'go test'.
// It is not meant to be called directly and is not subject to the Go 1 compatibility document.
// It may change signature from release to release.
-func MainStart(matchString func(pat, str string) (bool, error), tests []InternalTest, benchmarks []InternalBenchmark, examples []InternalExample) *M {
+func MainStart(deps testDeps, tests []InternalTest, benchmarks []InternalBenchmark, examples []InternalExample) *M {
return &M{
- matchString: matchString,
- tests: tests,
- benchmarks: benchmarks,
- examples: examples,
+ deps: deps,
+ tests: tests,
+ benchmarks: benchmarks,
+ examples: examples,
}
}
@@ -737,19 +835,22 @@ func (m *M) Run() int {
parseCpuList()
- before()
+ m.before()
startAlarm()
haveExamples = len(m.examples) > 0
- testOk := RunTests(m.matchString, m.tests)
- exampleOk := RunExamples(m.matchString, m.examples)
- stopAlarm()
- if !testOk || !exampleOk || !runBenchmarksInternal(m.matchString, m.benchmarks) {
+ testRan, testOk := runTests(m.deps.MatchString, m.tests)
+ exampleRan, exampleOk := runExamples(m.deps.MatchString, m.examples)
+ 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 {
fmt.Println("FAIL")
- after()
+ m.after()
return 1
}
+
fmt.Println("PASS")
- after()
+ m.after()
return 0
}
@@ -770,12 +871,18 @@ func (t *T) report() {
}
}
+// 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) {
- ok = true
- if len(tests) == 0 && !haveExamples {
+ ran, ok := runTests(matchString, tests)
+ if !ran && !haveExamples {
fmt.Fprintln(os.Stderr, "testing: warning: no tests to run")
- return
}
+ return ok
+}
+
+func runTests(matchString func(pat, str string) (bool, error), tests []InternalTest) (ran, ok bool) {
+ ok = true
for _, procs := range cpuList {
runtime.GOMAXPROCS(procs)
ctx := newTestContext(*parallel, newMatcher(matchString, *match, "-test.run"))
@@ -798,12 +905,13 @@ func RunTests(matchString func(pat, str string) (bool, error), tests []InternalT
go func() { <-t.signal }()
})
ok = ok && !t.Failed()
+ ran = ran || t.ran
}
- return
+ return ran, ok
}
// before runs before all testing.
-func before() {
+func (m *M) before() {
if *memProfileRate > 0 {
runtime.MemProfileRate = *memProfileRate
}
@@ -813,7 +921,7 @@ func before() {
fmt.Fprintf(os.Stderr, "testing: %s", err)
return
}
- if err := pprof.StartCPUProfile(f); err != nil {
+ if err := m.deps.StartCPUProfile(f); err != nil {
fmt.Fprintf(os.Stderr, "testing: can't start cpu profile: %s", err)
f.Close()
return
@@ -836,6 +944,9 @@ func before() {
if *blockProfile != "" && *blockProfileRate >= 0 {
runtime.SetBlockProfileRate(*blockProfileRate)
}
+ if *mutexProfile != "" && *mutexProfileFraction >= 0 {
+ runtime.SetMutexProfileFraction(*mutexProfileFraction)
+ }
if *coverProfile != "" && cover.Mode == "" {
fmt.Fprintf(os.Stderr, "testing: cannot use -test.coverprofile because test binary was not built with coverage enabled\n")
os.Exit(2)
@@ -843,9 +954,9 @@ func before() {
}
// after runs after all testing.
-func after() {
+func (m *M) after() {
if *cpuProfile != "" {
- pprof.StopCPUProfile() // flushes profile to disk
+ m.deps.StopCPUProfile() // flushes profile to disk
}
if *traceFile != "" {
trace.Stop() // flushes trace to disk
@@ -857,7 +968,7 @@ func after() {
os.Exit(2)
}
runtime.GC() // materialize all statistics
- if err = pprof.WriteHeapProfile(f); err != nil {
+ if err = m.deps.WriteHeapProfile(f); err != nil {
fmt.Fprintf(os.Stderr, "testing: can't write %s: %s\n", *memProfile, err)
os.Exit(2)
}
@@ -869,7 +980,19 @@ func after() {
fmt.Fprintf(os.Stderr, "testing: %s\n", err)
os.Exit(2)
}
- if err = pprof.Lookup("block").WriteTo(f, 0); err != nil {
+ if err = m.deps.WriteProfileTo("block", f, 0); err != nil {
+ fmt.Fprintf(os.Stderr, "testing: can't write %s: %s\n", *blockProfile, err)
+ os.Exit(2)
+ }
+ f.Close()
+ }
+ if *mutexProfile != "" && *mutexProfileFraction >= 0 {
+ f, err := os.Create(toOutputDir(*mutexProfile))
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "testing: %s\n", err)
+ os.Exit(2)
+ }
+ if err = m.deps.WriteProfileTo("mutex", f, 0); err != nil {
fmt.Fprintf(os.Stderr, "testing: can't write %s: %s\n", *blockProfile, err)
os.Exit(2)
}
diff --git a/src/testing/testing_test.go b/src/testing/testing_test.go
index 45e4468..9954f9a 100644
--- a/src/testing/testing_test.go
+++ b/src/testing/testing_test.go
@@ -5,14 +5,42 @@
package testing_test
import (
+ "fmt"
"os"
+ "runtime"
"testing"
+ "time"
)
-// This is exactly what a test would do without a TestMain.
-// It's here only so that there is at least one package in the
-// standard library with a TestMain, so that code is executed.
-
func TestMain(m *testing.M) {
- os.Exit(m.Run())
+ g0 := runtime.NumGoroutine()
+
+ code := m.Run()
+ if code != 0 {
+ os.Exit(code)
+ }
+
+ // Check that there are no goroutines left behind.
+ t0 := time.Now()
+ stacks := make([]byte, 1<<20)
+ for {
+ g1 := runtime.NumGoroutine()
+ if g1 == g0 {
+ return
+ }
+ stacks = stacks[:runtime.Stack(stacks, true)]
+ time.Sleep(50 * time.Millisecond)
+ if time.Since(t0) > 2*time.Second {
+ fmt.Fprintf(os.Stderr, "Unexpected leftover goroutines detected: %v -> %v\n%s\n", g0, g1, stacks)
+ os.Exit(1)
+ }
+ }
+}
+
+func TestContextCancel(t *testing.T) {
+ ctx := t.Context()
+ // Tests we don't leak this goroutine:
+ go func() {
+ <-ctx.Done()
+ }()
}
diff --git a/src/text/tabwriter/tabwriter.go b/src/text/tabwriter/tabwriter.go
index 796e1e8..752c9b8 100644
--- a/src/text/tabwriter/tabwriter.go
+++ b/src/text/tabwriter/tabwriter.go
@@ -8,6 +8,7 @@
// The package is using the Elastic Tabstops algorithm described at
// http://nickgravgaard.com/elastictabstops/index.html.
//
+// The text/tabwriter package is frozen and is not accepting new features.
package tabwriter
import (
diff --git a/src/text/template/exec.go b/src/text/template/exec.go
index 8e5ad93..ea964dc 100644
--- a/src/text/template/exec.go
+++ b/src/text/template/exec.go
@@ -171,20 +171,26 @@ func (t *Template) ExecuteTemplate(wr io.Writer, name string, data interface{})
// execution stops, but partial results may already have been written to
// the output writer.
// A template may be executed safely in parallel.
+//
+// If data is a reflect.Value, the template applies to the concrete
+// value that the reflect.Value holds, as in fmt.Print.
func (t *Template) Execute(wr io.Writer, data interface{}) error {
return t.execute(wr, data)
}
func (t *Template) execute(wr io.Writer, data interface{}) (err error) {
defer errRecover(&err)
- value := reflect.ValueOf(data)
+ value, ok := data.(reflect.Value)
+ if !ok {
+ value = reflect.ValueOf(data)
+ }
state := &state{
tmpl: t,
wr: wr,
vars: []variable{{"$", value}},
}
if t.Tree == nil || t.Root == nil {
- state.errorf("%q is an incomplete or empty template%s", t.Name(), t.DefinedTemplates())
+ state.errorf("%q is an incomplete or empty template", t.Name())
}
state.walk(value, t.Root)
return
@@ -535,6 +541,9 @@ func (s *state) evalFunction(dot reflect.Value, node *parse.IdentifierNode, cmd
// value of the pipeline, if any.
func (s *state) evalField(dot reflect.Value, fieldName string, node parse.Node, args []parse.Node, final, receiver reflect.Value) reflect.Value {
if !receiver.IsValid() {
+ if s.tmpl.option.missingKey == mapError { // Treat invalid value as missing map key.
+ s.errorf("nil data; no entry for key %q", fieldName)
+ }
return zero
}
typ := receiver.Type()
@@ -596,8 +605,9 @@ func (s *state) evalField(dot reflect.Value, fieldName string, node parse.Node,
}
var (
- errorType = reflect.TypeOf((*error)(nil)).Elem()
- fmtStringerType = reflect.TypeOf((*fmt.Stringer)(nil)).Elem()
+ errorType = reflect.TypeOf((*error)(nil)).Elem()
+ fmtStringerType = reflect.TypeOf((*fmt.Stringer)(nil)).Elem()
+ reflectValueType = reflect.TypeOf((*reflect.Value)(nil)).Elem()
)
// evalCall executes a function or method call. If it's a method, fun already has the receiver bound, so
@@ -661,7 +671,11 @@ func (s *state) evalCall(dot, fun reflect.Value, node parse.Node, name string, a
s.at(node)
s.errorf("error calling %s: %s", name, result[1].Interface().(error))
}
- return result[0]
+ v := result[0]
+ if v.Type() == reflectValueType {
+ v = v.Interface().(reflect.Value)
+ }
+ return v
}
// canBeNil reports whether an untyped nil can be assigned to the type. See reflect.Zero.
@@ -669,6 +683,8 @@ func canBeNil(typ reflect.Type) bool {
switch typ.Kind() {
case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice:
return true
+ case reflect.Struct:
+ return typ == reflectValueType
}
return false
}
@@ -682,6 +698,9 @@ func (s *state) validateType(value reflect.Value, typ reflect.Type) reflect.Valu
}
s.errorf("invalid value; expected %s", typ)
}
+ if typ == reflectValueType && value.Type() != typ {
+ return reflect.ValueOf(value)
+ }
if typ != nil && !value.Type().AssignableTo(typ) {
if value.Kind() == reflect.Interface && !value.IsNil() {
value = value.Elem()
@@ -743,6 +762,10 @@ func (s *state) evalArg(dot reflect.Value, typ reflect.Type, n parse.Node) refle
if typ.NumMethod() == 0 {
return s.evalEmptyInterface(dot, n)
}
+ case reflect.Struct:
+ if typ == reflectValueType {
+ return reflect.ValueOf(s.evalEmptyInterface(dot, n))
+ }
case reflect.String:
return s.evalString(typ, n)
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
@@ -854,6 +877,20 @@ func indirect(v reflect.Value) (rv reflect.Value, isNil bool) {
return v, false
}
+// indirectInterface returns the concrete value in an interface value,
+// or else the zero reflect.Value.
+// That is, if v represents the interface value x, the result is the same as reflect.ValueOf(x):
+// the fact that x was an interface value is forgotten.
+func indirectInterface(v reflect.Value) reflect.Value {
+ if v.Kind() != reflect.Interface {
+ return v
+ }
+ if v.IsNil() {
+ return reflect.Value{}
+ }
+ return v.Elem()
+}
+
// printValue writes the textual representation of the value to the output of
// the template.
func (s *state) printValue(n parse.Node, v reflect.Value) {
diff --git a/src/text/template/exec_test.go b/src/text/template/exec_test.go
index 3ef065e..5892b27 100644
--- a/src/text/template/exec_test.go
+++ b/src/text/template/exec_test.go
@@ -932,7 +932,7 @@ func TestMessageForExecuteEmpty(t *testing.T) {
t.Fatal("expected second error")
}
got = err.Error()
- want = `template: empty: "empty" is an incomplete or empty template; defined templates are: "secondary"`
+ want = `template: empty: "empty" is an incomplete or empty template`
if got != want {
t.Errorf("expected error %s got %s", want, got)
}
@@ -1142,6 +1142,12 @@ func TestMissingMapKey(t *testing.T) {
if err == nil {
t.Errorf("expected error; got none")
}
+ // same Option, but now a nil interface: ask for an error
+ err = tmpl.Execute(&b, nil)
+ t.Log(err)
+ if err == nil {
+ t.Errorf("expected error for nil-interface; got none")
+ }
}
// Test that the error message for multiline unterminated string
@@ -1152,7 +1158,7 @@ func TestUnterminatedStringError(t *testing.T) {
t.Fatal("expected error")
}
str := err.Error()
- if !strings.Contains(str, "X:3: unexpected unterminated raw quoted strin") {
+ if !strings.Contains(str, "X:3: unexpected unterminated raw quoted string") {
t.Fatalf("unexpected error: %s", str)
}
}
@@ -1310,3 +1316,99 @@ func TestMaxExecDepth(t *testing.T) {
t.Errorf("got error %q; want %q", got, want)
}
}
+
+func TestAddrOfIndex(t *testing.T) {
+ // golang.org/issue/14916.
+ // Before index worked on reflect.Values, the .String could not be
+ // found on the (incorrectly unaddressable) V value,
+ // in contrast to range, which worked fine.
+ // Also testing that passing a reflect.Value to tmpl.Execute works.
+ texts := []string{
+ `{{range .}}{{.String}}{{end}}`,
+ `{{with index . 0}}{{.String}}{{end}}`,
+ }
+ for _, text := range texts {
+ tmpl := Must(New("tmpl").Parse(text))
+ var buf bytes.Buffer
+ err := tmpl.Execute(&buf, reflect.ValueOf([]V{{1}}))
+ if err != nil {
+ t.Fatalf("%s: Execute: %v", text, err)
+ }
+ if buf.String() != "<1>" {
+ t.Fatalf("%s: template output = %q, want %q", text, &buf, "<1>")
+ }
+ }
+}
+
+func TestInterfaceValues(t *testing.T) {
+ // golang.org/issue/17714.
+ // Before index worked on reflect.Values, interface values
+ // were always implicitly promoted to the underlying value,
+ // except that nil interfaces were promoted to the zero reflect.Value.
+ // Eliminating a round trip to interface{} and back to reflect.Value
+ // eliminated this promotion, breaking these cases.
+ tests := []struct {
+ text string
+ out string
+ }{
+ {`{{index .Nil 1}}`, "ERROR: index of untyped nil"},
+ {`{{index .Slice 2}}`, "2"},
+ {`{{index .Slice .Two}}`, "2"},
+ {`{{call .Nil 1}}`, "ERROR: call of nil"},
+ {`{{call .PlusOne 1}}`, "2"},
+ {`{{call .PlusOne .One}}`, "2"},
+ {`{{and (index .Slice 0) true}}`, "0"},
+ {`{{and .Zero true}}`, "0"},
+ {`{{and (index .Slice 1) false}}`, "false"},
+ {`{{and .One false}}`, "false"},
+ {`{{or (index .Slice 0) false}}`, "false"},
+ {`{{or .Zero false}}`, "false"},
+ {`{{or (index .Slice 1) true}}`, "1"},
+ {`{{or .One true}}`, "1"},
+ {`{{not (index .Slice 0)}}`, "true"},
+ {`{{not .Zero}}`, "true"},
+ {`{{not (index .Slice 1)}}`, "false"},
+ {`{{not .One}}`, "false"},
+ {`{{eq (index .Slice 0) .Zero}}`, "true"},
+ {`{{eq (index .Slice 1) .One}}`, "true"},
+ {`{{ne (index .Slice 0) .Zero}}`, "false"},
+ {`{{ne (index .Slice 1) .One}}`, "false"},
+ {`{{ge (index .Slice 0) .One}}`, "false"},
+ {`{{ge (index .Slice 1) .Zero}}`, "true"},
+ {`{{gt (index .Slice 0) .One}}`, "false"},
+ {`{{gt (index .Slice 1) .Zero}}`, "true"},
+ {`{{le (index .Slice 0) .One}}`, "true"},
+ {`{{le (index .Slice 1) .Zero}}`, "false"},
+ {`{{lt (index .Slice 0) .One}}`, "true"},
+ {`{{lt (index .Slice 1) .Zero}}`, "false"},
+ }
+
+ for _, tt := range tests {
+ tmpl := Must(New("tmpl").Parse(tt.text))
+ var buf bytes.Buffer
+ err := tmpl.Execute(&buf, map[string]interface{}{
+ "PlusOne": func(n int) int {
+ return n + 1
+ },
+ "Slice": []int{0, 1, 2, 3},
+ "One": 1,
+ "Two": 2,
+ "Nil": nil,
+ "Zero": 0,
+ })
+ if strings.HasPrefix(tt.out, "ERROR:") {
+ e := strings.TrimSpace(strings.TrimPrefix(tt.out, "ERROR:"))
+ if err == nil || !strings.Contains(err.Error(), e) {
+ t.Errorf("%s: Execute: %v, want error %q", tt.text, err, e)
+ }
+ continue
+ }
+ if err != nil {
+ t.Errorf("%s: Execute: %v", tt.text, err)
+ continue
+ }
+ if buf.String() != tt.out {
+ t.Errorf("%s: template output = %q, want %q", tt.text, &buf, tt.out)
+ }
+ }
+}
diff --git a/src/text/template/funcs.go b/src/text/template/funcs.go
index cd0b82b..3047b27 100644
--- a/src/text/template/funcs.go
+++ b/src/text/template/funcs.go
@@ -21,6 +21,12 @@ import (
// which the second has type error. In that case, if the second (error)
// return value evaluates to non-nil during execution, execution terminates and
// Execute returns that error.
+//
+// When template execution invokes a function with an argument list, that list
+// must be assignable to the function's parameter types. Functions meant to
+// apply to arguments of arbitrary type can use parameters of type interface{} or
+// of type reflect.Value. Similarly, functions meant to return a result of arbitrary
+// type can return interface{} or reflect.Value.
type FuncMap map[string]interface{}
var builtins = FuncMap{
@@ -144,16 +150,16 @@ func prepareArg(value reflect.Value, argType reflect.Type) (reflect.Value, error
// index returns the result of indexing its first argument by the following
// arguments. Thus "index x 1 2 3" is, in Go syntax, x[1][2][3]. Each
// indexed item must be a map, slice, or array.
-func index(item interface{}, indices ...interface{}) (interface{}, error) {
- v := reflect.ValueOf(item)
+func index(item reflect.Value, indices ...reflect.Value) (reflect.Value, error) {
+ v := indirectInterface(item)
if !v.IsValid() {
- return nil, fmt.Errorf("index of untyped nil")
+ return reflect.Value{}, fmt.Errorf("index of untyped nil")
}
for _, i := range indices {
- index := reflect.ValueOf(i)
+ index := indirectInterface(i)
var isNil bool
if v, isNil = indirect(v); isNil {
- return nil, fmt.Errorf("index of nil pointer")
+ return reflect.Value{}, fmt.Errorf("index of nil pointer")
}
switch v.Kind() {
case reflect.Array, reflect.Slice, reflect.String:
@@ -164,18 +170,18 @@ func index(item interface{}, indices ...interface{}) (interface{}, error) {
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
x = int64(index.Uint())
case reflect.Invalid:
- return nil, fmt.Errorf("cannot index slice/array with nil")
+ return reflect.Value{}, fmt.Errorf("cannot index slice/array with nil")
default:
- return nil, fmt.Errorf("cannot index slice/array with type %s", index.Type())
+ return reflect.Value{}, fmt.Errorf("cannot index slice/array with type %s", index.Type())
}
if x < 0 || x >= int64(v.Len()) {
- return nil, fmt.Errorf("index out of range: %d", x)
+ return reflect.Value{}, fmt.Errorf("index out of range: %d", x)
}
v = v.Index(int(x))
case reflect.Map:
index, err := prepareArg(index, v.Type().Key())
if err != nil {
- return nil, err
+ return reflect.Value{}, err
}
if x := v.MapIndex(index); x.IsValid() {
v = x
@@ -186,10 +192,10 @@ func index(item interface{}, indices ...interface{}) (interface{}, error) {
// the loop holds invariant: v.IsValid()
panic("unreachable")
default:
- return nil, fmt.Errorf("can't index item of type %s", v.Type())
+ return reflect.Value{}, fmt.Errorf("can't index item of type %s", v.Type())
}
}
- return v.Interface(), nil
+ return v, nil
}
// Length
@@ -215,33 +221,33 @@ func length(item interface{}) (int, error) {
// call returns the result of evaluating the first argument as a function.
// The function must return 1 result, or 2 results, the second of which is an error.
-func call(fn interface{}, args ...interface{}) (interface{}, error) {
- v := reflect.ValueOf(fn)
+func call(fn reflect.Value, args ...reflect.Value) (reflect.Value, error) {
+ v := indirectInterface(fn)
if !v.IsValid() {
- return nil, fmt.Errorf("call of nil")
+ return reflect.Value{}, fmt.Errorf("call of nil")
}
typ := v.Type()
if typ.Kind() != reflect.Func {
- return nil, fmt.Errorf("non-function of type %s", typ)
+ return reflect.Value{}, fmt.Errorf("non-function of type %s", typ)
}
if !goodFunc(typ) {
- return nil, fmt.Errorf("function called with %d args; should be 1 or 2", typ.NumOut())
+ return reflect.Value{}, fmt.Errorf("function called with %d args; should be 1 or 2", typ.NumOut())
}
numIn := typ.NumIn()
var dddType reflect.Type
if typ.IsVariadic() {
if len(args) < numIn-1 {
- return nil, fmt.Errorf("wrong number of args: got %d want at least %d", len(args), numIn-1)
+ return reflect.Value{}, fmt.Errorf("wrong number of args: got %d want at least %d", len(args), numIn-1)
}
dddType = typ.In(numIn - 1).Elem()
} else {
if len(args) != numIn {
- return nil, fmt.Errorf("wrong number of args: got %d want %d", len(args), numIn)
+ return reflect.Value{}, fmt.Errorf("wrong number of args: got %d want %d", len(args), numIn)
}
}
argv := make([]reflect.Value, len(args))
for i, arg := range args {
- value := reflect.ValueOf(arg)
+ value := indirectInterface(arg)
// Compute the expected type. Clumsy because of variadics.
var argType reflect.Type
if !typ.IsVariadic() || i < numIn-1 {
@@ -252,26 +258,26 @@ func call(fn interface{}, args ...interface{}) (interface{}, error) {
var err error
if argv[i], err = prepareArg(value, argType); err != nil {
- return nil, fmt.Errorf("arg %d: %s", i, err)
+ return reflect.Value{}, fmt.Errorf("arg %d: %s", i, err)
}
}
result := v.Call(argv)
if len(result) == 2 && !result[1].IsNil() {
- return result[0].Interface(), result[1].Interface().(error)
+ return result[0], result[1].Interface().(error)
}
- return result[0].Interface(), nil
+ return result[0], nil
}
// Boolean logic.
-func truth(a interface{}) bool {
- t, _ := IsTrue(a)
+func truth(arg reflect.Value) bool {
+ t, _ := isTrue(indirectInterface(arg))
return t
}
// and computes the Boolean AND of its arguments, returning
// the first false argument it encounters, or the last argument.
-func and(arg0 interface{}, args ...interface{}) interface{} {
+func and(arg0 reflect.Value, args ...reflect.Value) reflect.Value {
if !truth(arg0) {
return arg0
}
@@ -286,7 +292,7 @@ func and(arg0 interface{}, args ...interface{}) interface{} {
// or computes the Boolean OR of its arguments, returning
// the first true argument it encounters, or the last argument.
-func or(arg0 interface{}, args ...interface{}) interface{} {
+func or(arg0 reflect.Value, args ...reflect.Value) reflect.Value {
if truth(arg0) {
return arg0
}
@@ -300,7 +306,7 @@ func or(arg0 interface{}, args ...interface{}) interface{} {
}
// not returns the Boolean negation of its argument.
-func not(arg interface{}) bool {
+func not(arg reflect.Value) bool {
return !truth(arg)
}
@@ -345,8 +351,8 @@ func basicKind(v reflect.Value) (kind, error) {
}
// eq evaluates the comparison a == b || a == c || ...
-func eq(arg1 interface{}, arg2 ...interface{}) (bool, error) {
- v1 := reflect.ValueOf(arg1)
+func eq(arg1 reflect.Value, arg2 ...reflect.Value) (bool, error) {
+ v1 := indirectInterface(arg1)
k1, err := basicKind(v1)
if err != nil {
return false, err
@@ -355,7 +361,7 @@ func eq(arg1 interface{}, arg2 ...interface{}) (bool, error) {
return false, errNoComparison
}
for _, arg := range arg2 {
- v2 := reflect.ValueOf(arg)
+ v2 := indirectInterface(arg)
k2, err := basicKind(v2)
if err != nil {
return false, err
@@ -397,20 +403,20 @@ func eq(arg1 interface{}, arg2 ...interface{}) (bool, error) {
}
// ne evaluates the comparison a != b.
-func ne(arg1, arg2 interface{}) (bool, error) {
+func ne(arg1, arg2 reflect.Value) (bool, error) {
// != is the inverse of ==.
equal, err := eq(arg1, arg2)
return !equal, err
}
// lt evaluates the comparison a < b.
-func lt(arg1, arg2 interface{}) (bool, error) {
- v1 := reflect.ValueOf(arg1)
+func lt(arg1, arg2 reflect.Value) (bool, error) {
+ v1 := indirectInterface(arg1)
k1, err := basicKind(v1)
if err != nil {
return false, err
}
- v2 := reflect.ValueOf(arg2)
+ v2 := indirectInterface(arg2)
k2, err := basicKind(v2)
if err != nil {
return false, err
@@ -446,7 +452,7 @@ func lt(arg1, arg2 interface{}) (bool, error) {
}
// le evaluates the comparison <= b.
-func le(arg1, arg2 interface{}) (bool, error) {
+func le(arg1, arg2 reflect.Value) (bool, error) {
// <= is < or ==.
lessThan, err := lt(arg1, arg2)
if lessThan || err != nil {
@@ -456,7 +462,7 @@ func le(arg1, arg2 interface{}) (bool, error) {
}
// gt evaluates the comparison a > b.
-func gt(arg1, arg2 interface{}) (bool, error) {
+func gt(arg1, arg2 reflect.Value) (bool, error) {
// > is the inverse of <=.
lessOrEqual, err := le(arg1, arg2)
if err != nil {
@@ -466,7 +472,7 @@ func gt(arg1, arg2 interface{}) (bool, error) {
}
// ge evaluates the comparison a >= b.
-func ge(arg1, arg2 interface{}) (bool, error) {
+func ge(arg1, arg2 reflect.Value) (bool, error) {
// >= is the inverse of <.
lessThan, err := lt(arg1, arg2)
if err != nil {
diff --git a/src/text/template/multi_test.go b/src/text/template/multi_test.go
index c8723cb..8142f00 100644
--- a/src/text/template/multi_test.go
+++ b/src/text/template/multi_test.go
@@ -349,3 +349,39 @@ func TestParse(t *testing.T) {
t.Fatalf("parsing test: %s", err)
}
}
+
+func TestEmptyTemplate(t *testing.T) {
+ cases := []struct {
+ defn []string
+ in string
+ want string
+ }{
+ {[]string{""}, "once", ""},
+ {[]string{"", ""}, "twice", ""},
+ {[]string{"{{.}}", "{{.}}"}, "twice", "twice"},
+ {[]string{"{{/* a comment */}}", "{{/* a comment */}}"}, "comment", ""},
+ {[]string{"{{.}}", ""}, "twice", ""},
+ }
+
+ for _, c := range cases {
+ root := New("root")
+
+ var (
+ m *Template
+ err error
+ )
+ for _, d := range c.defn {
+ m, err = root.New(c.in).Parse(d)
+ if err != nil {
+ t.Fatal(err)
+ }
+ }
+ buf := &bytes.Buffer{}
+ if err := m.Execute(buf, c.in); err != nil {
+ t.Fatal(err)
+ }
+ if buf.String() != c.want {
+ t.Errorf("expected string %q: got %q", c.want, buf.String())
+ }
+ }
+}
diff --git a/src/text/template/parse/lex.go b/src/text/template/parse/lex.go
index 079c0ea..6fbf36d 100644
--- a/src/text/template/parse/lex.go
+++ b/src/text/template/parse/lex.go
@@ -13,9 +13,10 @@ import (
// item represents a token or text string returned from the scanner.
type item struct {
- typ itemType // The type of this item.
- pos Pos // The starting position, in bytes, of this item in the input string.
- val string // The value of this item.
+ typ itemType // The type of this item.
+ pos Pos // The starting position, in bytes, of this item in the input string.
+ val string // The value of this item.
+ line int // The line number at the start of this item.
}
func (i item) String() string {
@@ -116,6 +117,7 @@ type lexer struct {
lastPos Pos // position of most recent item returned by nextItem
items chan item // channel of scanned items
parenDepth int // nesting depth of ( ) exprs
+ line int // 1+number of newlines seen
}
// next returns the next rune in the input.
@@ -127,6 +129,9 @@ func (l *lexer) next() rune {
r, w := utf8.DecodeRuneInString(l.input[l.pos:])
l.width = Pos(w)
l.pos += l.width
+ if r == '\n' {
+ l.line++
+ }
return r
}
@@ -140,11 +145,20 @@ func (l *lexer) peek() rune {
// backup steps back one rune. Can only be called once per call of next.
func (l *lexer) backup() {
l.pos -= l.width
+ // Correct newline count.
+ if l.width == 1 && l.input[l.pos] == '\n' {
+ l.line--
+ }
}
// emit passes an item back to the client.
func (l *lexer) emit(t itemType) {
- l.items <- item{t, l.start, l.input[l.start:l.pos]}
+ l.items <- item{t, l.start, l.input[l.start:l.pos], l.line}
+ // Some items contain text internally. If so, count their newlines.
+ switch t {
+ case itemText, itemRawString, itemLeftDelim, itemRightDelim:
+ l.line += strings.Count(l.input[l.start:l.pos], "\n")
+ }
l.start = l.pos
}
@@ -169,17 +183,10 @@ func (l *lexer) acceptRun(valid string) {
l.backup()
}
-// lineNumber reports which line we're on, based on the position of
-// the previous item returned by nextItem. Doing it this way
-// means we don't have to worry about peek double counting.
-func (l *lexer) lineNumber() int {
- return 1 + strings.Count(l.input[:l.lastPos], "\n")
-}
-
// errorf returns an error token and terminates the scan by passing
// back a nil pointer that will be the next state, terminating l.nextItem.
func (l *lexer) errorf(format string, args ...interface{}) stateFn {
- l.items <- item{itemError, l.start, fmt.Sprintf(format, args...)}
+ l.items <- item{itemError, l.start, fmt.Sprintf(format, args...), l.line}
return nil
}
@@ -212,6 +219,7 @@ func lex(name, input, left, right string) *lexer {
leftDelim: left,
rightDelim: right,
items: make(chan item),
+ line: 1,
}
go l.run()
return l
@@ -236,24 +244,23 @@ const (
// lexText scans until an opening action delimiter, "{{".
func lexText(l *lexer) stateFn {
- for {
- delim, trimSpace := l.atLeftDelim()
- if delim {
- trimLength := Pos(0)
- if trimSpace {
- trimLength = rightTrimLength(l.input[l.start:l.pos])
- }
- l.pos -= trimLength
- if l.pos > l.start {
- l.emit(itemText)
- }
- l.pos += trimLength
- l.ignore()
- return lexLeftDelim
+ l.width = 0
+ if x := strings.Index(l.input[l.pos:], l.leftDelim); x >= 0 {
+ ldn := Pos(len(l.leftDelim))
+ l.pos += Pos(x)
+ trimLength := Pos(0)
+ if strings.HasPrefix(l.input[l.pos+ldn:], leftTrimMarker) {
+ trimLength = rightTrimLength(l.input[l.start:l.pos])
}
- if l.next() == eof {
- break
+ l.pos -= trimLength
+ if l.pos > l.start {
+ l.emit(itemText)
}
+ l.pos += trimLength
+ l.ignore()
+ return lexLeftDelim
+ } else {
+ l.pos = Pos(len(l.input))
}
// Correctly reached EOF.
if l.pos > l.start {
@@ -263,16 +270,6 @@ func lexText(l *lexer) stateFn {
return nil
}
-// atLeftDelim reports whether the lexer is at a left delimiter, possibly followed by a trim marker.
-func (l *lexer) atLeftDelim() (delim, trimSpaces bool) {
- if !strings.HasPrefix(l.input[l.pos:], l.leftDelim) {
- return false, false
- }
- // The left delim might have the marker afterwards.
- trimSpaces = strings.HasPrefix(l.input[l.pos+Pos(len(l.leftDelim)):], leftTrimMarker)
- return true, trimSpaces
-}
-
// rightTrimLength returns the length of the spaces at the end of the string.
func rightTrimLength(s string) Pos {
return Pos(len(s) - len(strings.TrimRight(s, spaceChars)))
@@ -613,10 +610,14 @@ Loop:
// lexRawQuote scans a raw quoted string.
func lexRawQuote(l *lexer) stateFn {
+ startLine := l.line
Loop:
for {
switch l.next() {
case eof:
+ // Restore line number to location of opening quote.
+ // We will error out so it's ok just to overwrite the field.
+ l.line = startLine
return l.errorf("unterminated raw quoted string")
case '`':
break Loop
diff --git a/src/text/template/parse/lex_test.go b/src/text/template/parse/lex_test.go
index e35ebf1..d655d78 100644
--- a/src/text/template/parse/lex_test.go
+++ b/src/text/template/parse/lex_test.go
@@ -58,39 +58,46 @@ type lexTest struct {
items []item
}
+func mkItem(typ itemType, text string) item {
+ return item{
+ typ: typ,
+ val: text,
+ }
+}
+
var (
- tDot = item{itemDot, 0, "."}
- tBlock = item{itemBlock, 0, "block"}
- tEOF = item{itemEOF, 0, ""}
- tFor = item{itemIdentifier, 0, "for"}
- tLeft = item{itemLeftDelim, 0, "{{"}
- tLpar = item{itemLeftParen, 0, "("}
- tPipe = item{itemPipe, 0, "|"}
- tQuote = item{itemString, 0, `"abc \n\t\" "`}
- tRange = item{itemRange, 0, "range"}
- tRight = item{itemRightDelim, 0, "}}"}
- tRpar = item{itemRightParen, 0, ")"}
- tSpace = item{itemSpace, 0, " "}
+ tDot = mkItem(itemDot, ".")
+ tBlock = mkItem(itemBlock, "block")
+ tEOF = mkItem(itemEOF, "")
+ tFor = mkItem(itemIdentifier, "for")
+ tLeft = mkItem(itemLeftDelim, "{{")
+ tLpar = mkItem(itemLeftParen, "(")
+ tPipe = mkItem(itemPipe, "|")
+ tQuote = mkItem(itemString, `"abc \n\t\" "`)
+ tRange = mkItem(itemRange, "range")
+ tRight = mkItem(itemRightDelim, "}}")
+ tRpar = mkItem(itemRightParen, ")")
+ tSpace = mkItem(itemSpace, " ")
raw = "`" + `abc\n\t\" ` + "`"
rawNL = "`now is{{\n}}the time`" // Contains newline inside raw quote.
- tRawQuote = item{itemRawString, 0, raw}
- tRawQuoteNL = item{itemRawString, 0, rawNL}
+ tRawQuote = mkItem(itemRawString, raw)
+ tRawQuoteNL = mkItem(itemRawString, rawNL)
)
var lexTests = []lexTest{
{"empty", "", []item{tEOF}},
- {"spaces", " \t\n", []item{{itemText, 0, " \t\n"}, tEOF}},
- {"text", `now is the time`, []item{{itemText, 0, "now is the time"}, tEOF}},
+ {"spaces", " \t\n", []item{mkItem(itemText, " \t\n"), tEOF}},
+ {"text", `now is the time`, []item{mkItem(itemText, "now is the time"), tEOF}},
{"text with comment", "hello-{{/* this is a comment */}}-world", []item{
- {itemText, 0, "hello-"},
- {itemText, 0, "-world"},
+ mkItem(itemText, "hello-"),
+ mkItem(itemText, "-world"),
tEOF,
}},
{"punctuation", "{{,@% }}", []item{
tLeft,
- {itemChar, 0, ","},
- {itemChar, 0, "@"},
- {itemChar, 0, "%"},
+ mkItem(itemChar, ","),
+ mkItem(itemChar, "@"),
+ mkItem(itemChar, "%"),
tSpace,
tRight,
tEOF,
@@ -99,7 +106,7 @@ var lexTests = []lexTest{
tLeft,
tLpar,
tLpar,
- {itemNumber, 0, "3"},
+ mkItem(itemNumber, "3"),
tRpar,
tRpar,
tRight,
@@ -108,54 +115,54 @@ var lexTests = []lexTest{
{"empty action", `{{}}`, []item{tLeft, tRight, tEOF}},
{"for", `{{for}}`, []item{tLeft, tFor, tRight, tEOF}},
{"block", `{{block "foo" .}}`, []item{
- tLeft, tBlock, tSpace, {itemString, 0, `"foo"`}, tSpace, tDot, tRight, tEOF,
+ tLeft, tBlock, tSpace, mkItem(itemString, `"foo"`), tSpace, tDot, tRight, tEOF,
}},
{"quote", `{{"abc \n\t\" "}}`, []item{tLeft, tQuote, tRight, tEOF}},
{"raw quote", "{{" + raw + "}}", []item{tLeft, tRawQuote, tRight, tEOF}},
{"raw quote with newline", "{{" + rawNL + "}}", []item{tLeft, tRawQuoteNL, tRight, tEOF}},
{"numbers", "{{1 02 0x14 -7.2i 1e3 +1.2e-4 4.2i 1+2i}}", []item{
tLeft,
- {itemNumber, 0, "1"},
+ mkItem(itemNumber, "1"),
tSpace,
- {itemNumber, 0, "02"},
+ mkItem(itemNumber, "02"),
tSpace,
- {itemNumber, 0, "0x14"},
+ mkItem(itemNumber, "0x14"),
tSpace,
- {itemNumber, 0, "-7.2i"},
+ mkItem(itemNumber, "-7.2i"),
tSpace,
- {itemNumber, 0, "1e3"},
+ mkItem(itemNumber, "1e3"),
tSpace,
- {itemNumber, 0, "+1.2e-4"},
+ mkItem(itemNumber, "+1.2e-4"),
tSpace,
- {itemNumber, 0, "4.2i"},
+ mkItem(itemNumber, "4.2i"),
tSpace,
- {itemComplex, 0, "1+2i"},
+ mkItem(itemComplex, "1+2i"),
tRight,
tEOF,
}},
{"characters", `{{'a' '\n' '\'' '\\' '\u00FF' '\xFF' '本'}}`, []item{
tLeft,
- {itemCharConstant, 0, `'a'`},
+ mkItem(itemCharConstant, `'a'`),
tSpace,
- {itemCharConstant, 0, `'\n'`},
+ mkItem(itemCharConstant, `'\n'`),
tSpace,
- {itemCharConstant, 0, `'\''`},
+ mkItem(itemCharConstant, `'\''`),
tSpace,
- {itemCharConstant, 0, `'\\'`},
+ mkItem(itemCharConstant, `'\\'`),
tSpace,
- {itemCharConstant, 0, `'\u00FF'`},
+ mkItem(itemCharConstant, `'\u00FF'`),
tSpace,
- {itemCharConstant, 0, `'\xFF'`},
+ mkItem(itemCharConstant, `'\xFF'`),
tSpace,
- {itemCharConstant, 0, `'本'`},
+ mkItem(itemCharConstant, `'本'`),
tRight,
tEOF,
}},
{"bools", "{{true false}}", []item{
tLeft,
- {itemBool, 0, "true"},
+ mkItem(itemBool, "true"),
tSpace,
- {itemBool, 0, "false"},
+ mkItem(itemBool, "false"),
tRight,
tEOF,
}},
@@ -167,178 +174,178 @@ var lexTests = []lexTest{
}},
{"nil", "{{nil}}", []item{
tLeft,
- {itemNil, 0, "nil"},
+ mkItem(itemNil, "nil"),
tRight,
tEOF,
}},
{"dots", "{{.x . .2 .x.y.z}}", []item{
tLeft,
- {itemField, 0, ".x"},
+ mkItem(itemField, ".x"),
tSpace,
tDot,
tSpace,
- {itemNumber, 0, ".2"},
+ mkItem(itemNumber, ".2"),
tSpace,
- {itemField, 0, ".x"},
- {itemField, 0, ".y"},
- {itemField, 0, ".z"},
+ mkItem(itemField, ".x"),
+ mkItem(itemField, ".y"),
+ mkItem(itemField, ".z"),
tRight,
tEOF,
}},
{"keywords", "{{range if else end with}}", []item{
tLeft,
- {itemRange, 0, "range"},
+ mkItem(itemRange, "range"),
tSpace,
- {itemIf, 0, "if"},
+ mkItem(itemIf, "if"),
tSpace,
- {itemElse, 0, "else"},
+ mkItem(itemElse, "else"),
tSpace,
- {itemEnd, 0, "end"},
+ mkItem(itemEnd, "end"),
tSpace,
- {itemWith, 0, "with"},
+ mkItem(itemWith, "with"),
tRight,
tEOF,
}},
{"variables", "{{$c := printf $ $hello $23 $ $var.Field .Method}}", []item{
tLeft,
- {itemVariable, 0, "$c"},
+ mkItem(itemVariable, "$c"),
tSpace,
- {itemColonEquals, 0, ":="},
+ mkItem(itemColonEquals, ":="),
tSpace,
- {itemIdentifier, 0, "printf"},
+ mkItem(itemIdentifier, "printf"),
tSpace,
- {itemVariable, 0, "$"},
+ mkItem(itemVariable, "$"),
tSpace,
- {itemVariable, 0, "$hello"},
+ mkItem(itemVariable, "$hello"),
tSpace,
- {itemVariable, 0, "$23"},
+ mkItem(itemVariable, "$23"),
tSpace,
- {itemVariable, 0, "$"},
+ mkItem(itemVariable, "$"),
tSpace,
- {itemVariable, 0, "$var"},
- {itemField, 0, ".Field"},
+ mkItem(itemVariable, "$var"),
+ mkItem(itemField, ".Field"),
tSpace,
- {itemField, 0, ".Method"},
+ mkItem(itemField, ".Method"),
tRight,
tEOF,
}},
{"variable invocation", "{{$x 23}}", []item{
tLeft,
- {itemVariable, 0, "$x"},
+ mkItem(itemVariable, "$x"),
tSpace,
- {itemNumber, 0, "23"},
+ mkItem(itemNumber, "23"),
tRight,
tEOF,
}},
{"pipeline", `intro {{echo hi 1.2 |noargs|args 1 "hi"}} outro`, []item{
- {itemText, 0, "intro "},
+ mkItem(itemText, "intro "),
tLeft,
- {itemIdentifier, 0, "echo"},
+ mkItem(itemIdentifier, "echo"),
tSpace,
- {itemIdentifier, 0, "hi"},
+ mkItem(itemIdentifier, "hi"),
tSpace,
- {itemNumber, 0, "1.2"},
+ mkItem(itemNumber, "1.2"),
tSpace,
tPipe,
- {itemIdentifier, 0, "noargs"},
+ mkItem(itemIdentifier, "noargs"),
tPipe,
- {itemIdentifier, 0, "args"},
+ mkItem(itemIdentifier, "args"),
tSpace,
- {itemNumber, 0, "1"},
+ mkItem(itemNumber, "1"),
tSpace,
- {itemString, 0, `"hi"`},
+ mkItem(itemString, `"hi"`),
tRight,
- {itemText, 0, " outro"},
+ mkItem(itemText, " outro"),
tEOF,
}},
{"declaration", "{{$v := 3}}", []item{
tLeft,
- {itemVariable, 0, "$v"},
+ mkItem(itemVariable, "$v"),
tSpace,
- {itemColonEquals, 0, ":="},
+ mkItem(itemColonEquals, ":="),
tSpace,
- {itemNumber, 0, "3"},
+ mkItem(itemNumber, "3"),
tRight,
tEOF,
}},
{"2 declarations", "{{$v , $w := 3}}", []item{
tLeft,
- {itemVariable, 0, "$v"},
+ mkItem(itemVariable, "$v"),
tSpace,
- {itemChar, 0, ","},
+ mkItem(itemChar, ","),
tSpace,
- {itemVariable, 0, "$w"},
+ mkItem(itemVariable, "$w"),
tSpace,
- {itemColonEquals, 0, ":="},
+ mkItem(itemColonEquals, ":="),
tSpace,
- {itemNumber, 0, "3"},
+ mkItem(itemNumber, "3"),
tRight,
tEOF,
}},
{"field of parenthesized expression", "{{(.X).Y}}", []item{
tLeft,
tLpar,
- {itemField, 0, ".X"},
+ mkItem(itemField, ".X"),
tRpar,
- {itemField, 0, ".Y"},
+ mkItem(itemField, ".Y"),
tRight,
tEOF,
}},
{"trimming spaces before and after", "hello- {{- 3 -}} -world", []item{
- {itemText, 0, "hello-"},
+ mkItem(itemText, "hello-"),
tLeft,
- {itemNumber, 0, "3"},
+ mkItem(itemNumber, "3"),
tRight,
- {itemText, 0, "-world"},
+ mkItem(itemText, "-world"),
tEOF,
}},
{"trimming spaces before and after comment", "hello- {{- /* hello */ -}} -world", []item{
- {itemText, 0, "hello-"},
- {itemText, 0, "-world"},
+ mkItem(itemText, "hello-"),
+ mkItem(itemText, "-world"),
tEOF,
}},
// errors
{"badchar", "#{{\x01}}", []item{
- {itemText, 0, "#"},
+ mkItem(itemText, "#"),
tLeft,
- {itemError, 0, "unrecognized character in action: U+0001"},
+ mkItem(itemError, "unrecognized character in action: U+0001"),
}},
{"unclosed action", "{{\n}}", []item{
tLeft,
- {itemError, 0, "unclosed action"},
+ mkItem(itemError, "unclosed action"),
}},
{"EOF in action", "{{range", []item{
tLeft,
tRange,
- {itemError, 0, "unclosed action"},
+ mkItem(itemError, "unclosed action"),
}},
{"unclosed quote", "{{\"\n\"}}", []item{
tLeft,
- {itemError, 0, "unterminated quoted string"},
+ mkItem(itemError, "unterminated quoted string"),
}},
{"unclosed raw quote", "{{`xx}}", []item{
tLeft,
- {itemError, 0, "unterminated raw quoted string"},
+ mkItem(itemError, "unterminated raw quoted string"),
}},
{"unclosed char constant", "{{'\n}}", []item{
tLeft,
- {itemError, 0, "unterminated character constant"},
+ mkItem(itemError, "unterminated character constant"),
}},
{"bad number", "{{3k}}", []item{
tLeft,
- {itemError, 0, `bad number syntax: "3k"`},
+ mkItem(itemError, `bad number syntax: "3k"`),
}},
{"unclosed paren", "{{(3}}", []item{
tLeft,
tLpar,
- {itemNumber, 0, "3"},
- {itemError, 0, `unclosed left paren`},
+ mkItem(itemNumber, "3"),
+ mkItem(itemError, `unclosed left paren`),
}},
{"extra right paren", "{{3)}}", []item{
tLeft,
- {itemNumber, 0, "3"},
+ mkItem(itemNumber, "3"),
tRpar,
- {itemError, 0, `unexpected right paren U+0029 ')'`},
+ mkItem(itemError, `unexpected right paren U+0029 ')'`),
}},
// Fixed bugs
@@ -355,17 +362,17 @@ var lexTests = []lexTest{
tEOF,
}},
{"text with bad comment", "hello-{{/*/}}-world", []item{
- {itemText, 0, "hello-"},
- {itemError, 0, `unclosed comment`},
+ mkItem(itemText, "hello-"),
+ mkItem(itemError, `unclosed comment`),
}},
{"text with comment close separated from delim", "hello-{{/* */ }}-world", []item{
- {itemText, 0, "hello-"},
- {itemError, 0, `comment ends before closing delimiter`},
+ mkItem(itemText, "hello-"),
+ mkItem(itemError, `comment ends before closing delimiter`),
}},
// This one is an error that we can't catch because it breaks templates with
// minimized JavaScript. Should have fixed it before Go 1.1.
{"unmatched right delimiter", "hello-{.}}-world", []item{
- {itemText, 0, "hello-{.}}-world"},
+ mkItem(itemText, "hello-{.}}-world"),
tEOF,
}},
}
@@ -414,13 +421,13 @@ func TestLex(t *testing.T) {
var lexDelimTests = []lexTest{
{"punctuation", "$$,@%{{}}@@", []item{
tLeftDelim,
- {itemChar, 0, ","},
- {itemChar, 0, "@"},
- {itemChar, 0, "%"},
- {itemChar, 0, "{"},
- {itemChar, 0, "{"},
- {itemChar, 0, "}"},
- {itemChar, 0, "}"},
+ mkItem(itemChar, ","),
+ mkItem(itemChar, "@"),
+ mkItem(itemChar, "%"),
+ mkItem(itemChar, "{"),
+ mkItem(itemChar, "{"),
+ mkItem(itemChar, "}"),
+ mkItem(itemChar, "}"),
tRightDelim,
tEOF,
}},
@@ -431,8 +438,8 @@ var lexDelimTests = []lexTest{
}
var (
- tLeftDelim = item{itemLeftDelim, 0, "$$"}
- tRightDelim = item{itemRightDelim, 0, "@@"}
+ tLeftDelim = mkItem(itemLeftDelim, "$$")
+ tRightDelim = mkItem(itemRightDelim, "@@")
)
func TestDelims(t *testing.T) {
@@ -447,21 +454,21 @@ func TestDelims(t *testing.T) {
var lexPosTests = []lexTest{
{"empty", "", []item{tEOF}},
{"punctuation", "{{,@%#}}", []item{
- {itemLeftDelim, 0, "{{"},
- {itemChar, 2, ","},
- {itemChar, 3, "@"},
- {itemChar, 4, "%"},
- {itemChar, 5, "#"},
- {itemRightDelim, 6, "}}"},
- {itemEOF, 8, ""},
+ {itemLeftDelim, 0, "{{", 1},
+ {itemChar, 2, ",", 1},
+ {itemChar, 3, "@", 1},
+ {itemChar, 4, "%", 1},
+ {itemChar, 5, "#", 1},
+ {itemRightDelim, 6, "}}", 1},
+ {itemEOF, 8, "", 1},
}},
{"sample", "0123{{hello}}xyz", []item{
- {itemText, 0, "0123"},
- {itemLeftDelim, 4, "{{"},
- {itemIdentifier, 6, "hello"},
- {itemRightDelim, 11, "}}"},
- {itemText, 13, "xyz"},
- {itemEOF, 16, ""},
+ {itemText, 0, "0123", 1},
+ {itemLeftDelim, 4, "{{", 1},
+ {itemIdentifier, 6, "hello", 1},
+ {itemRightDelim, 11, "}}", 1},
+ {itemText, 13, "xyz", 1},
+ {itemEOF, 16, "", 1},
}},
}
diff --git a/src/text/template/parse/parse.go b/src/text/template/parse/parse.go
index 86705e5..6060c6d 100644
--- a/src/text/template/parse/parse.go
+++ b/src/text/template/parse/parse.go
@@ -157,7 +157,7 @@ func (t *Tree) ErrorContext(n Node) (location, context string) {
// errorf formats the error and terminates processing.
func (t *Tree) errorf(format string, args ...interface{}) {
t.Root = nil
- format = fmt.Sprintf("template: %s:%d: %s", t.ParseName, t.lex.lineNumber(), format)
+ format = fmt.Sprintf("template: %s:%d: %s", t.ParseName, t.token[0].line, format)
panic(fmt.Errorf(format, args...))
}
@@ -277,7 +277,7 @@ func IsEmptyTree(n Node) bool {
// parse is the top-level parser for a template, essentially the same
// as itemList except it also parses {{define}} actions.
// It runs to EOF.
-func (t *Tree) parse() (next Node) {
+func (t *Tree) parse() {
t.Root = t.newList(t.peek().pos)
for t.peek().typ != itemEOF {
if t.peek().typ == itemLeftDelim {
@@ -299,7 +299,6 @@ func (t *Tree) parse() (next Node) {
t.Root.append(n)
}
}
- return nil
}
// parseDefinition parses a {{define}} ... {{end}} template definition and
@@ -377,15 +376,17 @@ func (t *Tree) action() (n Node) {
return t.withControl()
}
t.backup()
+ token := t.peek()
// Do not pop variables; they persist until "end".
- return t.newAction(t.peek().pos, t.lex.lineNumber(), t.pipeline("command"))
+ return t.newAction(token.pos, token.line, t.pipeline("command"))
}
// Pipeline:
// declarations? command ('|' command)*
func (t *Tree) pipeline(context string) (pipe *PipeNode) {
var decl []*VariableNode
- pos := t.peekNonSpace().pos
+ token := t.peekNonSpace()
+ pos := token.pos
// Are there declarations?
for {
if v := t.peekNonSpace(); v.typ == itemVariable {
@@ -414,7 +415,7 @@ func (t *Tree) pipeline(context string) (pipe *PipeNode) {
}
break
}
- pipe = t.newPipeline(pos, t.lex.lineNumber(), decl)
+ pipe = t.newPipeline(pos, token.line, decl)
for {
switch token := t.nextNonSpace(); token.typ {
case itemRightDelim, itemRightParen:
@@ -451,7 +452,6 @@ func (t *Tree) checkPipeline(pipe *PipeNode, context string) {
func (t *Tree) parseControl(allowElseIf bool, context string) (pos Pos, line int, pipe *PipeNode, list, elseList *ListNode) {
defer t.popVars(len(t.vars))
- line = t.lex.lineNumber()
pipe = t.pipeline(context)
var next Node
list, next = t.itemList()
@@ -480,7 +480,7 @@ func (t *Tree) parseControl(allowElseIf bool, context string) (pos Pos, line int
t.errorf("expected end; found %s", next)
}
}
- return pipe.Position(), line, pipe, list, elseList
+ return pipe.Position(), pipe.Line, pipe, list, elseList
}
// If:
@@ -522,9 +522,10 @@ func (t *Tree) elseControl() Node {
peek := t.peekNonSpace()
if peek.typ == itemIf {
// We see "{{else if ... " but in effect rewrite it to {{else}}{{if ... ".
- return t.newElse(peek.pos, t.lex.lineNumber())
+ return t.newElse(peek.pos, peek.line)
}
- return t.newElse(t.expect(itemRightDelim, "else").pos, t.lex.lineNumber())
+ token := t.expect(itemRightDelim, "else")
+ return t.newElse(token.pos, token.line)
}
// Block:
@@ -551,7 +552,7 @@ func (t *Tree) blockControl() Node {
block.add()
block.stopParse()
- return t.newTemplate(token.pos, t.lex.lineNumber(), name, pipe)
+ return t.newTemplate(token.pos, token.line, name, pipe)
}
// Template:
@@ -568,7 +569,7 @@ func (t *Tree) templateControl() Node {
// Do not pop variables; they persist until "end".
pipe = t.pipeline(context)
}
- return t.newTemplate(token.pos, t.lex.lineNumber(), name, pipe)
+ return t.newTemplate(token.pos, token.line, name, pipe)
}
func (t *Tree) parseTemplateName(token item, context string) (name string) {
diff --git a/src/text/template/parse/parse_test.go b/src/text/template/parse/parse_test.go
index 9d856bc..81f14ac 100644
--- a/src/text/template/parse/parse_test.go
+++ b/src/text/template/parse/parse_test.go
@@ -484,3 +484,37 @@ func TestBlock(t *testing.T) {
t.Errorf("inner template = %q, want %q", g, w)
}
}
+
+func TestLineNum(t *testing.T) {
+ const count = 100
+ text := strings.Repeat("{{printf 1234}}\n", count)
+ tree, err := New("bench").Parse(text, "", "", make(map[string]*Tree), builtins)
+ if err != nil {
+ t.Fatal(err)
+ }
+ // Check the line numbers. Each line is an action containing a template, followed by text.
+ // That's two nodes per line.
+ nodes := tree.Root.Nodes
+ for i := 0; i < len(nodes); i += 2 {
+ line := 1 + i/2
+ // Action first.
+ action := nodes[i].(*ActionNode)
+ if action.Line != line {
+ t.Fatalf("line %d: action is line %d", line, action.Line)
+ }
+ pipe := action.Pipe
+ if pipe.Line != line {
+ t.Fatalf("line %d: pipe is line %d", line, pipe.Line)
+ }
+ }
+}
+
+func BenchmarkParseLarge(b *testing.B) {
+ text := strings.Repeat("{{1234}}\n", 10000)
+ for i := 0; i < b.N; i++ {
+ _, err := New("bench").Parse(text, "", "", make(map[string]*Tree), builtins)
+ if err != nil {
+ b.Fatal(err)
+ }
+ }
+}
diff --git a/src/text/template/template.go b/src/text/template/template.go
index 7a7f42a..b6fceb1 100644
--- a/src/text/template/template.go
+++ b/src/text/template/template.go
@@ -181,9 +181,16 @@ func (t *Template) Lookup(name string) *Template {
return t.tmpl[name]
}
-// Parse defines the template by parsing the text. Nested template definitions will be
-// associated with the top-level template t. Parse may be called multiple times
-// to parse definitions of templates to associate with t.
+// Parse parses text as a template body for t.
+// Named template definitions ({{define ...}} or {{block ...}} statements) in text
+// define additional templates associated with t and are removed from the
+// definition of t itself.
+//
+// Templates can be redefined in successive calls to Parse.
+// A template definition with a body containing only white space and comments
+// is considered empty and will not replace an existing template's body.
+// This allows using Parse to add new named template definitions without
+// overwriting the main template body.
func (t *Template) Parse(text string) (*Template, error) {
t.init()
t.muFuncs.RLock()
@@ -208,7 +215,7 @@ func (t *Template) associate(new *Template, tree *parse.Tree) (bool, error) {
if new.common != t.common {
panic("internal error: associate not common")
}
- if t.tmpl[new.name] != nil && parse.IsEmptyTree(tree.Root) {
+ if t.tmpl[new.name] != nil && parse.IsEmptyTree(tree.Root) && t.Tree != nil {
// If a template by that name exists,
// don't replace it with an empty template.
return false, nil
diff --git a/src/time/example_test.go b/src/time/example_test.go
index 4170d51..7dc2bb5 100644
--- a/src/time/example_test.go
+++ b/src/time/example_test.go
@@ -251,20 +251,18 @@ func ExampleTime_Truncate() {
2 * time.Second,
time.Minute,
10 * time.Minute,
- time.Hour,
}
for _, d := range trunc {
- fmt.Printf("t.Truncate(%6s) = %s\n", d, t.Truncate(d).Format("15:04:05.999999999"))
+ fmt.Printf("t.Truncate(%5s) = %s\n", d, t.Truncate(d).Format("15:04:05.999999999"))
}
// Output:
- // t.Truncate( 1ns) = 12:15:30.918273645
- // t.Truncate( 1µs) = 12:15:30.918273
- // t.Truncate( 1ms) = 12:15:30.918
- // t.Truncate( 1s) = 12:15:30
- // t.Truncate( 2s) = 12:15:30
- // t.Truncate( 1m0s) = 12:15:00
- // t.Truncate( 10m0s) = 12:10:00
- // t.Truncate(1h0m0s) = 12:00:00
+ // t.Truncate( 1ns) = 12:15:30.918273645
+ // t.Truncate( 1µs) = 12:15:30.918273
+ // t.Truncate( 1ms) = 12:15:30.918
+ // t.Truncate( 1s) = 12:15:30
+ // t.Truncate( 2s) = 12:15:30
+ // t.Truncate( 1m0s) = 12:15:00
+ // t.Truncate(10m0s) = 12:10:00
}
diff --git a/src/time/export_android_test.go b/src/time/export_android_test.go
new file mode 100644
index 0000000..fa6a058
--- /dev/null
+++ b/src/time/export_android_test.go
@@ -0,0 +1,12 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package time
+
+func ForceAndroidTzdataForTest(tzdata bool) {
+ tzdataPaths = origTzdataPaths
+ if tzdata {
+ tzdataPaths = tzdataPaths[:1]
+ }
+}
diff --git a/src/time/format.go b/src/time/format.go
index c2ae793..3fbfa73 100644
--- a/src/time/format.go
+++ b/src/time/format.go
@@ -42,6 +42,13 @@ import "errors"
// Z07:00 Z or ±hh:mm
// Z07 Z or ±hh
//
+// The recognized day of week formats are "Mon" and "Monday".
+// The recognized month formats are "Jan" and "January".
+//
+// Text in the format string that is not recognized as part of the reference
+// time is echoed verbatim during Format and expected to appear verbatim
+// in the input to Parse.
+//
// The executable example for time.Format demonstrates the working
// of the layout string in detail and is a good reference.
//
@@ -844,6 +851,7 @@ func parse(layout, value string, defaultLocation, local *Location) (Time, error)
sec, value, err = getnum(value, std == stdZeroSecond)
if sec < 0 || 60 <= sec {
rangeErrString = "second"
+ break
}
// Special case: do we have a fractional second but no
// fractional second in the format?
@@ -1004,7 +1012,7 @@ func parse(layout, value string, defaultLocation, local *Location) (Time, error)
}
// Validate the day of the month.
- if day > daysIn(Month(month), year) {
+ if day < 1 || day > daysIn(Month(month), year) {
return Time{}, &ParseError{alayout, avalue, "", value, ": day out of range"}
}
@@ -1020,12 +1028,12 @@ func parse(layout, value string, defaultLocation, local *Location) (Time, error)
// If that zone was in effect at the given time, use it.
name, offset, _, _, _ := local.lookup(t.sec + internalToUnix)
if offset == zoneOffset && (zoneName == "" || name == zoneName) {
- t.loc = local
+ t.setLoc(local)
return t, nil
}
// Otherwise create fake zone to record offset.
- t.loc = FixedZone(zoneName, zoneOffset)
+ t.setLoc(FixedZone(zoneName, zoneOffset))
return t, nil
}
@@ -1036,7 +1044,7 @@ func parse(layout, value string, defaultLocation, local *Location) (Time, error)
offset, _, ok := local.lookupName(zoneName, t.sec+internalToUnix)
if ok {
t.sec -= int64(offset)
- t.loc = local
+ t.setLoc(local)
return t, nil
}
@@ -1045,7 +1053,7 @@ func parse(layout, value string, defaultLocation, local *Location) (Time, error)
offset, _ = atoi(zoneName[3:]) // Guaranteed OK by parseGMT.
offset *= 3600
}
- t.loc = FixedZone(zoneName, offset)
+ t.setLoc(FixedZone(zoneName, offset))
return t, nil
}
@@ -1173,6 +1181,37 @@ func leadingInt(s string) (x int64, rem string, err error) {
return x, s[i:], nil
}
+// leadingFraction consumes the leading [0-9]* from s.
+// It is used only for fractions, so does not return an error on overflow,
+// it just stops accumulating precision.
+func leadingFraction(s string) (x int64, scale float64, rem string) {
+ i := 0
+ scale = 1
+ overflow := false
+ for ; i < len(s); i++ {
+ c := s[i]
+ if c < '0' || c > '9' {
+ break
+ }
+ if overflow {
+ continue
+ }
+ if x > (1<<63-1)/10 {
+ // It's possible for overflow to give a positive number, so take care.
+ overflow = true
+ continue
+ }
+ y := x*10 + int64(c) - '0'
+ if y < 0 {
+ overflow = true
+ continue
+ }
+ x = y
+ scale *= 10
+ }
+ return x, scale, s[i:]
+}
+
var unitMap = map[string]int64{
"ns": int64(Nanosecond),
"us": int64(Microsecond),
@@ -1235,13 +1274,7 @@ func ParseDuration(s string) (Duration, error) {
if s != "" && s[0] == '.' {
s = s[1:]
pl := len(s)
- f, s, err = leadingInt(s)
- if err != nil {
- return 0, errors.New("time: invalid duration " + orig)
- }
- for n := pl - len(s); n > 0; n-- {
- scale *= 10
- }
+ f, scale, s = leadingFraction(s)
post = pl != len(s)
}
if !pre && !post {
diff --git a/src/time/format_test.go b/src/time/format_test.go
index 8c47dbc..aa4434a 100644
--- a/src/time/format_test.go
+++ b/src/time/format_test.go
@@ -224,6 +224,7 @@ var dayOutOfRangeTests = []struct {
{"Thu Nov 31 21:00:57 2010", false},
{"Thu Dec 31 21:00:57 2010", true},
{"Thu Dec 32 21:00:57 2010", false},
+ {"Thu Dec 00 21:00:57 2010", false},
}
func TestParseDayOutOfRange(t *testing.T) {
@@ -440,6 +441,8 @@ var parseErrorTests = []ParseErrorTest{
{RFC3339, "2006-01-02T15:04_abc", `parsing time "2006-01-02T15:04_abc" as "2006-01-02T15:04:05Z07:00": cannot parse "_abc" as ":"`},
{RFC3339, "2006-01-02T15:04:05_abc", `parsing time "2006-01-02T15:04:05_abc" as "2006-01-02T15:04:05Z07:00": cannot parse "_abc" as "Z07:00"`},
{RFC3339, "2006-01-02T15:04:05Z_abc", `parsing time "2006-01-02T15:04:05Z_abc": extra text: _abc`},
+ // invalid second followed by optional fractional seconds
+ {RFC3339, "2010-02-04T21:00:67.012345678-08:00", "second out of range"},
}
func TestParseErrors(t *testing.T) {
diff --git a/src/time/sleep.go b/src/time/sleep.go
index 73114f5..4b01404 100644
--- a/src/time/sleep.go
+++ b/src/time/sleep.go
@@ -12,7 +12,7 @@ func Sleep(d Duration)
func runtimeNano() int64
// Interface to timers implemented in package runtime.
-// Must be in sync with ../runtime/runtime.h:/^struct.Timer$
+// Must be in sync with ../runtime/time.go:/^type timer
type runtimeTimer struct {
i int
when int64
@@ -55,13 +55,22 @@ type Timer struct {
// Stop does not close the channel, to prevent a read from the channel succeeding
// incorrectly.
//
-// To prevent the timer firing after a call to Stop,
-// check the return value and drain the channel. For example:
+// To prevent a timer created with NewTimer from firing after a call to Stop,
+// check the return value and drain the channel.
+// For example, assuming the program has not received from t.C already:
+//
// if !t.Stop() {
// <-t.C
// }
+//
// This cannot be done concurrent to other receives from the Timer's
// channel.
+//
+// For a timer created with AfterFunc(d, f), if t.Stop returns false, then the timer
+// has already expired and the function f has been started in its own goroutine;
+// Stop does not wait for f to complete before returning.
+// If the caller needs to know whether f is completed, it must coordinate
+// with f explicitly.
func (t *Timer) Stop() bool {
if t.r.f == nil {
panic("time: Stop called on uninitialized Timer")
@@ -89,18 +98,25 @@ func NewTimer(d Duration) *Timer {
// It returns true if the timer had been active, false if the timer had
// expired or been stopped.
//
-// To reuse an active timer, always call its Stop method first and—if it had
-// expired—drain the value from its channel. For example:
+// Resetting a timer must take care not to race with the send into t.C
+// that happens when the current timer expires.
+// If a program has already received a value from t.C, the timer is known
+// to have expired, and t.Reset can be used directly.
+// If a program has not yet received a value from t.C, however,
+// the timer must be stopped and—if Stop reports that the timer expired
+// before being stopped—the channel explicitly drained:
+//
// if !t.Stop() {
// <-t.C
// }
// t.Reset(d)
+//
// This should not be done concurrent to other receives from the Timer's
// channel.
//
// Note that it is not possible to use Reset's return value correctly, as there
// is a race condition between draining the channel and the new timer expiring.
-// Reset should always be used in concert with Stop, as described above.
+// Reset should always be invoked on stopped or expired channels, as described above.
// The return value exists to preserve compatibility with existing programs.
func (t *Timer) Reset(d Duration) bool {
if t.r.f == nil {
diff --git a/src/time/time.go b/src/time/time.go
index c31de35..10b3246 100644
--- a/src/time/time.go
+++ b/src/time/time.go
@@ -4,7 +4,8 @@
// Package time provides functionality for measuring and displaying time.
//
-// The calendrical calculations always assume a Gregorian calendar.
+// The calendrical calculations always assume a Gregorian calendar, with
+// no leap seconds.
package time
import "errors"
@@ -49,11 +50,18 @@ type Time struct {
// loc specifies the Location that should be used to
// determine the minute, hour, month, day, and year
// that correspond to this Time.
- // Only the zero Time has a nil Location.
- // In that case it is interpreted to mean UTC.
+ // The nil location means UTC.
+ // All UTC times are represented with loc==nil, never loc==&utcLoc.
loc *Location
}
+func (t *Time) setLoc(loc *Location) {
+ if loc == &utcLoc {
+ loc = nil
+ }
+ t.loc = loc
+}
+
// 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
@@ -67,8 +75,7 @@ func (t Time) Before(u Time) bool {
// 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.
-// This comparison is different from using t == u, which also compares
-// the locations.
+// Do not use == with Time values.
func (t Time) Equal(u Time) bool {
return t.sec == u.sec && t.nsec == u.nsec
}
@@ -107,7 +114,14 @@ var months = [...]string{
}
// String returns the English name of the month ("January", "February", ...).
-func (m Month) String() string { return months[m-1] }
+func (m Month) String() string {
+ if January <= m && m <= December {
+ return months[m-1]
+ }
+ buf := make([]byte, 20)
+ n := fmtInt(buf, uint64(m))
+ return "%!Month(" + string(buf[n:]) + ")"
+}
// A Weekday specifies a day of the week (Sunday = 0, ...).
type Weekday int
@@ -585,21 +599,21 @@ func (d Duration) Nanoseconds() int64 { return int64(d) }
func (d Duration) Seconds() float64 {
sec := d / Second
nsec := d % Second
- return float64(sec) + float64(nsec)*1e-9
+ return float64(sec) + float64(nsec)/1e9
}
// Minutes returns the duration as a floating point number of minutes.
func (d Duration) Minutes() float64 {
min := d / Minute
nsec := d % Minute
- return float64(min) + float64(nsec)*(1e-9/60)
+ return float64(min) + float64(nsec)/(60*1e9)
}
// Hours returns the duration as a floating point number of hours.
func (d Duration) Hours() float64 {
hour := d / Hour
nsec := d % Hour
- return float64(hour) + float64(nsec)*(1e-9/60/60)
+ return float64(hour) + float64(nsec)/(60*60*1e9)
}
// Add returns the time t+d.
@@ -640,6 +654,12 @@ func Since(t Time) Duration {
return Now().Sub(t)
}
+// Until returns the duration until t.
+// It is shorthand for t.Sub(time.Now()).
+func Until(t Time) Duration {
+ return t.Sub(Now())
+}
+
// AddDate returns the time corresponding to adding the
// given number of years, months, and days to t.
// For example, AddDate(-1, 2, 3) applied to January 1, 2011
@@ -651,7 +671,7 @@ func Since(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.loc)
+ return Date(year+years, month+Month(months), day+days, hour, min, sec, int(t.nsec), t.Location())
}
const (
@@ -781,13 +801,13 @@ func Now() Time {
// UTC returns t with the location set to UTC.
func (t Time) UTC() Time {
- t.loc = UTC
+ t.setLoc(&utcLoc)
return t
}
// Local returns t with the location set to local time.
func (t Time) Local() Time {
- t.loc = Local
+ t.setLoc(Local)
return t
}
@@ -798,7 +818,7 @@ func (t Time) In(loc *Location) Time {
if loc == nil {
panic("time: missing Location in call to Time.In")
}
- t.loc = loc
+ t.setLoc(loc)
return t
}
@@ -826,8 +846,9 @@ func (t Time) Unix() int64 {
// UnixNano returns t as a Unix time, the number of nanoseconds elapsed
// since January 1, 1970 UTC. The result is undefined if the Unix time
-// in nanoseconds cannot be represented by an int64. Note that this
-// means the result of calling UnixNano on the zero Time is undefined.
+// in nanoseconds cannot be represented by an int64 (a date before the year
+// 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)
}
@@ -838,7 +859,7 @@ const timeBinaryVersion byte = 1
func (t Time) MarshalBinary() ([]byte, error) {
var offsetMin int16 // minutes east of UTC. -1 is UTC.
- if t.Location() == &utcLoc {
+ if t.Location() == UTC {
offsetMin = -1
} else {
_, offset := t.Zone()
@@ -899,11 +920,11 @@ func (t *Time) UnmarshalBinary(data []byte) error {
offset := int(int16(buf[1])|int16(buf[0])<<8) * 60
if offset == -1*60 {
- t.loc = &utcLoc
+ t.setLoc(&utcLoc)
} else if _, localoff, _, _, _ := Local.lookup(t.sec + internalToUnix); offset == localoff {
- t.loc = Local
+ t.setLoc(Local)
} else {
- t.loc = FixedZone("", offset)
+ t.setLoc(FixedZone("", offset))
}
return nil
@@ -942,6 +963,10 @@ func (t Time) MarshalJSON() ([]byte, error) {
// UnmarshalJSON implements the json.Unmarshaler interface.
// The time is expected to be a quoted string in RFC 3339 format.
func (t *Time) UnmarshalJSON(data []byte) error {
+ // Ignore null, like in the main JSON package.
+ if string(data) == "null" {
+ return nil
+ }
// Fractional seconds are handled implicitly by Parse.
var err error
*t, err = Parse(`"`+RFC3339+`"`, string(data))
@@ -1092,11 +1117,18 @@ func Date(year int, month Month, day, hour, min, sec, nsec int, loc *Location) T
unix -= int64(offset)
}
- return Time{unix + unixToInternal, int32(nsec), loc}
+ t := Time{unix + unixToInternal, int32(nsec), nil}
+ t.setLoc(loc)
+ return t
}
// Truncate returns the result of rounding t down to a multiple of d (since the zero time).
// If d <= 0, Truncate returns t unchanged.
+//
+// Truncate operates on the time as an absolute duration since the
+// zero time; it does not operate on the presentation form of the
+// 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 {
if d <= 0 {
return t
@@ -1108,6 +1140,11 @@ func (t Time) Truncate(d Duration) Time {
// Round returns the result of rounding t to the nearest multiple of d (since the zero time).
// The rounding behavior for halfway values is to round up.
// If d <= 0, Round returns t unchanged.
+//
+// Round operates on the time as an absolute duration since the
+// zero time; it does not operate on the presentation form of the
+// 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 {
if d <= 0 {
return t
diff --git a/src/time/time_test.go b/src/time/time_test.go
index b7ebb37..2922560 100644
--- a/src/time/time_test.go
+++ b/src/time/time_test.go
@@ -840,6 +840,10 @@ var parseDurationTests = []struct {
{"9223372036s854ms775us807ns", true, (1<<63 - 1) * Nanosecond},
// large negative value
{"-9223372036854775807ns", true, -1<<63 + 1*Nanosecond},
+ // huge string; issue 15011.
+ {"0.100000000000000000000h", true, 6 * Minute},
+ // This value tests the first overflow check in leadingFraction.
+ {"0.830103483285477580700h", true, 49*Minute + 48*Second + 372539827*Nanosecond},
// errors
{"", false, 0},
@@ -891,7 +895,7 @@ func TestLocationRace(t *testing.T) {
go func() {
c <- Now().String()
}()
- Now().String()
+ _ = Now().String()
<-c
Sleep(100 * Millisecond)
@@ -939,8 +943,11 @@ func TestLoadFixed(t *testing.T) {
// but Go and most other systems use "east is positive".
// So GMT+1 corresponds to -3600 in the Go zone, not +3600.
name, offset := Now().In(loc).Zone()
- if name != "GMT+1" || offset != -1*60*60 {
- t.Errorf("Now().In(loc).Zone() = %q, %d, want %q, %d", name, offset, "GMT+1", -1*60*60)
+ // The zone abbreviation is "-01" since tzdata-2016g, and "GMT+1"
+ // on earlier versions; we accept both. (Issue #17276).
+ if !(name == "GMT+1" || name == "-01") || offset != -1*60*60 {
+ t.Errorf("Now().In(loc).Zone() = %q, %d, want %q or %q, %d",
+ name, offset, "GMT+1", "-01", -1*60*60)
}
}
@@ -996,6 +1003,21 @@ func TestDurationNanoseconds(t *testing.T) {
}
}
+var secDurationTests = []struct {
+ d Duration
+ want float64
+}{
+ {Duration(300000000), 0.3},
+}
+
+func TestDurationSeconds(t *testing.T) {
+ for _, tt := range secDurationTests {
+ if got := tt.d.Seconds(); got != tt.want {
+ t.Errorf("d.Seconds() = %g; want: %g", got, tt.want)
+ }
+ }
+}
+
var minDurationTests = []struct {
d Duration
want float64
@@ -1004,6 +1026,7 @@ var minDurationTests = []struct {
{Duration(-1), -1 / 60e9},
{Duration(1), 1 / 60e9},
{Duration(60000000000), 1},
+ {Duration(3000), 5e-8},
}
func TestDurationMinutes(t *testing.T) {
@@ -1022,6 +1045,7 @@ var hourDurationTests = []struct {
{Duration(-1), -1 / 3600e9},
{Duration(1), 1 / 3600e9},
{Duration(3600000000000), 1},
+ {Duration(36), 1e-11},
}
func TestDurationHours(t *testing.T) {
@@ -1032,6 +1056,100 @@ func TestDurationHours(t *testing.T) {
}
}
+var defaultLocTests = []struct {
+ name string
+ f func(t1, t2 Time) bool
+}{
+ {"After", func(t1, t2 Time) bool { return t1.After(t2) == t2.After(t1) }},
+ {"Before", func(t1, t2 Time) bool { return t1.Before(t2) == t2.Before(t1) }},
+ {"Equal", func(t1, t2 Time) bool { return t1.Equal(t2) == t2.Equal(t1) }},
+
+ {"IsZero", func(t1, t2 Time) bool { return t1.IsZero() == t2.IsZero() }},
+ {"Date", func(t1, t2 Time) bool {
+ a1, b1, c1 := t1.Date()
+ a2, b2, c2 := t2.Date()
+ return a1 == a2 && b1 == b2 && c1 == c2
+ }},
+ {"Year", func(t1, t2 Time) bool { return t1.Year() == t2.Year() }},
+ {"Month", func(t1, t2 Time) bool { return t1.Month() == t2.Month() }},
+ {"Day", func(t1, t2 Time) bool { return t1.Day() == t2.Day() }},
+ {"Weekday", func(t1, t2 Time) bool { return t1.Weekday() == t2.Weekday() }},
+ {"ISOWeek", func(t1, t2 Time) bool {
+ a1, b1 := t1.ISOWeek()
+ a2, b2 := t2.ISOWeek()
+ return a1 == a2 && b1 == b2
+ }},
+ {"Clock", func(t1, t2 Time) bool {
+ a1, b1, c1 := t1.Clock()
+ a2, b2, c2 := t2.Clock()
+ return a1 == a2 && b1 == b2 && c1 == c2
+ }},
+ {"Hour", func(t1, t2 Time) bool { return t1.Hour() == t2.Hour() }},
+ {"Minute", func(t1, t2 Time) bool { return t1.Minute() == t2.Minute() }},
+ {"Second", func(t1, t2 Time) bool { return t1.Second() == t2.Second() }},
+ {"Nanosecond", func(t1, t2 Time) bool { return t1.Hour() == t2.Hour() }},
+ {"YearDay", func(t1, t2 Time) bool { return t1.YearDay() == t2.YearDay() }},
+
+ // Using Equal since Add don't modify loc using "==" will cause a fail
+ {"Add", func(t1, t2 Time) bool { return t1.Add(Hour).Equal(t2.Add(Hour)) }},
+ {"Sub", func(t1, t2 Time) bool { return t1.Sub(t2) == t2.Sub(t1) }},
+
+ //Original caus for this test case bug 15852
+ {"AddDate", func(t1, t2 Time) bool { return t1.AddDate(1991, 9, 3) == t2.AddDate(1991, 9, 3) }},
+
+ {"UTC", func(t1, t2 Time) bool { return t1.UTC() == t2.UTC() }},
+ {"Local", func(t1, t2 Time) bool { return t1.Local() == t2.Local() }},
+ {"In", func(t1, t2 Time) bool { return t1.In(UTC) == t2.In(UTC) }},
+
+ {"Local", func(t1, t2 Time) bool { return t1.Local() == t2.Local() }},
+ {"Zone", func(t1, t2 Time) bool {
+ a1, b1 := t1.Zone()
+ a2, b2 := t2.Zone()
+ return a1 == a2 && b1 == b2
+ }},
+
+ {"Unix", func(t1, t2 Time) bool { return t1.Unix() == t2.Unix() }},
+ {"UnixNano", func(t1, t2 Time) bool { return t1.UnixNano() == t2.UnixNano() }},
+
+ {"MarshalBinary", func(t1, t2 Time) bool {
+ a1, b1 := t1.MarshalBinary()
+ a2, b2 := t2.MarshalBinary()
+ return bytes.Equal(a1, a2) && b1 == b2
+ }},
+ {"GobEncode", func(t1, t2 Time) bool {
+ a1, b1 := t1.GobEncode()
+ a2, b2 := t2.GobEncode()
+ return bytes.Equal(a1, a2) && b1 == b2
+ }},
+ {"MarshalJSON", func(t1, t2 Time) bool {
+ a1, b1 := t1.MarshalJSON()
+ a2, b2 := t2.MarshalJSON()
+ return bytes.Equal(a1, a2) && b1 == b2
+ }},
+ {"MarshalText", func(t1, t2 Time) bool {
+ a1, b1 := t1.MarshalText()
+ a2, b2 := t2.MarshalText()
+ return bytes.Equal(a1, a2) && b1 == b2
+ }},
+
+ {"Truncate", func(t1, t2 Time) bool { return t1.Truncate(Hour).Equal(t2.Truncate(Hour)) }},
+ {"Round", func(t1, t2 Time) bool { return t1.Round(Hour).Equal(t2.Round(Hour)) }},
+
+ {"== Time{}", func(t1, t2 Time) bool { return (t1 == Time{}) == (t2 == Time{}) }},
+}
+
+func TestDefaultLoc(t *testing.T) {
+ //This test verifyes that all Time's methods behaves identical if loc is set
+ //as nil or UTC
+ for _, tt := range defaultLocTests {
+ t1 := Time{}
+ t2 := Time{}.UTC()
+ if !tt.f(t1, t2) {
+ t.Errorf("Time{} and Time{}.UTC() behave differently for %s", tt.name)
+ }
+ }
+}
+
func BenchmarkNow(b *testing.B) {
for i := 0; i < b.N; i++ {
t = Now()
@@ -1114,3 +1232,25 @@ func BenchmarkDay(b *testing.B) {
_ = t.Day()
}
}
+
+func TestMarshalBinaryZeroTime(t *testing.T) {
+ t0 := Time{}
+ enc, err := t0.MarshalBinary()
+ if err != nil {
+ t.Fatal(err)
+ }
+ t1 := Now() // not zero
+ if err := t1.UnmarshalBinary(enc); err != nil {
+ t.Fatal(err)
+ }
+ if t1 != t0 {
+ t.Errorf("t0=%#v\nt1=%#v\nwant identical structures", t0, t1)
+ }
+}
+
+// Issue 17720: Zero value of time.Month fails to print
+func TestZeroMonthString(t *testing.T) {
+ if got, want := Month(0).String(), "%!Month(0)"; got != want {
+ t.Errorf("zero month = %q; want %q", got, want)
+ }
+}
diff --git a/src/time/zoneinfo.go b/src/time/zoneinfo.go
index c567439..fb0aa39 100644
--- a/src/time/zoneinfo.go
+++ b/src/time/zoneinfo.go
@@ -9,6 +9,8 @@ import (
"syscall"
)
+//go:generate env ZONEINFO=$GOROOT/lib/time/zoneinfo.zip go run genzabbrs.go -output zoneinfo_abbrs_windows.go
+
// A Location maps time instants to the zone in use at that time.
// Typically, the Location represents the collection of time offsets
// in use in a geographical area, such as CEST and CET for central Europe.
diff --git a/src/time/zoneinfo_abbrs_windows.go b/src/time/zoneinfo_abbrs_windows.go
index 344a891..9425db8 100644
--- a/src/time/zoneinfo_abbrs_windows.go
+++ b/src/time/zoneinfo_abbrs_windows.go
@@ -13,92 +13,106 @@ type abbr struct {
}
var abbrs = map[string]abbr{
- "Egypt Standard Time": {"EET", "EET"}, // Africa/Cairo
- "Morocco Standard Time": {"WET", "WEST"}, // Africa/Casablanca
- "South Africa Standard Time": {"SAST", "SAST"}, // Africa/Johannesburg
- "W. Central Africa Standard Time": {"WAT", "WAT"}, // Africa/Lagos
- "E. Africa Standard Time": {"EAT", "EAT"}, // Africa/Nairobi
- "Libya Standard Time": {"EET", "EET"}, // Africa/Tripoli
- "Namibia Standard Time": {"WAT", "WAST"}, // Africa/Windhoek
- "Alaskan Standard Time": {"AKST", "AKDT"}, // America/Anchorage
- "Paraguay Standard Time": {"PYT", "PYST"}, // America/Asuncion
- "Bahia Standard Time": {"BRT", "BRT"}, // America/Bahia
- "SA Pacific Standard Time": {"COT", "COT"}, // America/Bogota
- "Argentina Standard Time": {"ART", "ART"}, // America/Buenos_Aires
- "Eastern Standard Time (Mexico)": {"EST", "EST"}, // America/Cancun
- "Venezuela Standard Time": {"VET", "VET"}, // America/Caracas
- "SA Eastern Standard Time": {"GFT", "GFT"}, // America/Cayenne
- "Central Standard Time": {"CST", "CDT"}, // America/Chicago
- "Mountain Standard Time (Mexico)": {"MST", "MDT"}, // America/Chihuahua
- "Central Brazilian Standard Time": {"AMT", "AMST"}, // America/Cuiaba
- "Mountain Standard Time": {"MST", "MDT"}, // America/Denver
- "Greenland Standard Time": {"WGT", "WGST"}, // America/Godthab
- "Central America Standard Time": {"CST", "CST"}, // America/Guatemala
- "Atlantic Standard Time": {"AST", "ADT"}, // America/Halifax
- "US Eastern Standard Time": {"EST", "EDT"}, // America/Indianapolis
- "SA Western Standard Time": {"BOT", "BOT"}, // America/La_Paz
- "Pacific Standard Time": {"PST", "PDT"}, // America/Los_Angeles
- "Central Standard Time (Mexico)": {"CST", "CDT"}, // America/Mexico_City
- "Montevideo Standard Time": {"UYT", "UYT"}, // America/Montevideo
- "Eastern Standard Time": {"EST", "EDT"}, // America/New_York
- "US Mountain Standard Time": {"MST", "MST"}, // America/Phoenix
- "Canada Central Standard Time": {"CST", "CST"}, // America/Regina
- "Pacific SA Standard Time": {"CLT", "CLST"}, // America/Santiago
- "E. South America Standard Time": {"BRT", "BRST"}, // America/Sao_Paulo
- "Newfoundland Standard Time": {"NST", "NDT"}, // America/St_Johns
- "Central Asia Standard Time": {"+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
- "Middle East Standard Time": {"EET", "EEST"}, // Asia/Beirut
- "India Standard Time": {"IST", "IST"}, // Asia/Calcutta
- "Transbaikal Standard Time": {"IRKT", "YAKT"}, // Asia/Chita
- "Sri Lanka Standard Time": {"IST", "IST"}, // Asia/Colombo
- "Syria Standard Time": {"EET", "EEST"}, // Asia/Damascus
- "Bangladesh Standard Time": {"BDT", "BDT"}, // Asia/Dhaka
- "Arabian Standard Time": {"GST", "GST"}, // Asia/Dubai
- "North Asia East Standard Time": {"IRKT", "IRKT"}, // Asia/Irkutsk
- "Israel Standard Time": {"IST", "IDT"}, // Asia/Jerusalem
- "Afghanistan Standard Time": {"AFT", "AFT"}, // Asia/Kabul
- "Russia Time Zone 11": {"PETT", "PETT"}, // Asia/Kamchatka
- "Pakistan Standard Time": {"PKT", "PKT"}, // Asia/Karachi
- "Nepal Standard Time": {"NPT", "NPT"}, // Asia/Katmandu
- "North Asia Standard Time": {"KRAT", "KRAT"}, // Asia/Krasnoyarsk
- "Magadan Standard Time": {"MAGT", "MAGT"}, // Asia/Magadan
- "N. Central Asia Standard Time": {"NOVT", "NOVT"}, // Asia/Novosibirsk
- "North Korea Standard Time": {"KST", "KST"}, // Asia/Pyongyang
- "Myanmar Standard Time": {"MMT", "MMT"}, // Asia/Rangoon
- "Arab Standard Time": {"AST", "AST"}, // Asia/Riyadh
- "Sakhalin Standard Time": {"SAKT", "SAKT"}, // Asia/Sakhalin
- "Korea Standard Time": {"KST", "KST"}, // Asia/Seoul
- "China Standard Time": {"CST", "CST"}, // Asia/Shanghai
- "Singapore Standard Time": {"SGT", "SGT"}, // Asia/Singapore
- "Russia Time Zone 10": {"SRET", "SRET"}, // Asia/Srednekolymsk
- "Taipei Standard Time": {"CST", "CST"}, // Asia/Taipei
- "West Asia Standard Time": {"UZT", "UZT"}, // Asia/Tashkent
- "Georgian Standard Time": {"GET", "GET"}, // Asia/Tbilisi
- "Iran Standard Time": {"IRST", "IRDT"}, // Asia/Tehran
- "Tokyo Standard Time": {"JST", "JST"}, // Asia/Tokyo
- "Ulaanbaatar Standard Time": {"ULAT", "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
- "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
- "Tasmania Standard Time": {"AEST", "AEDT"}, // Australia/Hobart
- "W. Australia Standard Time": {"AWST", "AWST"}, // Australia/Perth
- "AUS Eastern Standard Time": {"AEST", "AEDT"}, // Australia/Sydney
+ "Egypt Standard Time": {"EET", "EET"}, // Africa/Cairo
+ "Morocco Standard Time": {"WET", "WEST"}, // Africa/Casablanca
+ "South Africa Standard Time": {"SAST", "SAST"}, // Africa/Johannesburg
+ "W. Central Africa Standard Time": {"WAT", "WAT"}, // Africa/Lagos
+ "E. Africa Standard Time": {"EAT", "EAT"}, // Africa/Nairobi
+ "Libya Standard Time": {"EET", "EET"}, // Africa/Tripoli
+ "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
+ "Eastern Standard Time (Mexico)": {"EST", "EST"}, // America/Cancun
+ "Venezuela Standard Time": {"VET", "VET"}, // America/Caracas
+ "SA Eastern Standard Time": {"GFT", "GFT"}, // America/Cayenne
+ "Central Standard Time": {"CST", "CDT"}, // America/Chicago
+ "Mountain Standard Time (Mexico)": {"MST", "MDT"}, // America/Chihuahua
+ "Central Brazilian Standard Time": {"AMT", "AMST"}, // America/Cuiaba
+ "Mountain Standard Time": {"MST", "MDT"}, // America/Denver
+ "Greenland Standard Time": {"WGT", "WGST"}, // 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
+ "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
+ "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
+ "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
+ "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
+ "Middle East Standard Time": {"EET", "EEST"}, // Asia/Beirut
+ "India Standard Time": {"IST", "IST"}, // Asia/Calcutta
+ "Transbaikal Standard Time": {"IRKT", "YAKT"}, // Asia/Chita
+ "Sri Lanka Standard Time": {"IST", "IST"}, // Asia/Colombo
+ "Syria Standard Time": {"EET", "EEST"}, // Asia/Damascus
+ "Bangladesh Standard Time": {"BDT", "BDT"}, // Asia/Dhaka
+ "Arabian Standard Time": {"GST", "GST"}, // 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
+ "Israel Standard Time": {"IST", "IDT"}, // Asia/Jerusalem
+ "Afghanistan Standard Time": {"AFT", "AFT"}, // Asia/Kabul
+ "Russia Time Zone 11": {"PETT", "PETT"}, // Asia/Kamchatka
+ "Pakistan Standard Time": {"PKT", "PKT"}, // Asia/Karachi
+ "Nepal Standard Time": {"NPT", "NPT"}, // Asia/Katmandu
+ "North Asia Standard Time": {"KRAT", "KRAT"}, // Asia/Krasnoyarsk
+ "Magadan Standard Time": {"MAGT", "MAGT"}, // Asia/Magadan
+ "N. Central Asia Standard Time": {"+06", "+07"}, // Asia/Novosibirsk
+ "North Korea Standard Time": {"KST", "KST"}, // Asia/Pyongyang
+ "Myanmar Standard Time": {"MMT", "MMT"}, // Asia/Rangoon
+ "Arab Standard Time": {"AST", "AST"}, // Asia/Riyadh
+ "Sakhalin Standard Time": {"SAKT", "SAKT"}, // Asia/Sakhalin
+ "Korea Standard Time": {"KST", "KST"}, // Asia/Seoul
+ "China Standard Time": {"CST", "CST"}, // Asia/Shanghai
+ "Singapore Standard Time": {"SGT", "SGT"}, // Asia/Singapore
+ "Russia Time Zone 10": {"SRET", "SRET"}, // Asia/Srednekolymsk
+ "Taipei Standard Time": {"CST", "CST"}, // Asia/Taipei
+ "West Asia Standard Time": {"UZT", "UZT"}, // Asia/Tashkent
+ "Georgian Standard Time": {"GET", "GET"}, // Asia/Tbilisi
+ "Iran Standard Time": {"IRST", "IRDT"}, // Asia/Tehran
+ "Tokyo Standard Time": {"JST", "JST"}, // Asia/Tokyo
+ "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
+ "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
+ "Tasmania Standard Time": {"AEST", "AEDT"}, // Australia/Hobart
+ "Lord Howe Standard Time": {"LHST", "LHDT"}, // 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
@@ -117,10 +131,15 @@ var abbrs = map[string]abbr{
"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
}
diff --git a/src/time/zoneinfo_android.go b/src/time/zoneinfo_android.go
new file mode 100644
index 0000000..695a8ad
--- /dev/null
+++ b/src/time/zoneinfo_android.go
@@ -0,0 +1,119 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Parse the "tzdata" packed timezone file used on Android.
+// The format is lifted from ZoneInfoDB.java and ZoneInfo.java in
+// java/libcore/util in the AOSP.
+
+package time
+
+import (
+ "errors"
+ "runtime"
+)
+
+var tzdataPaths = []string{
+ "/system/usr/share/zoneinfo/tzdata",
+ "/data/misc/zoneinfo/current/tzdata",
+ runtime.GOROOT() + "/lib/time/zoneinfo.zip",
+}
+
+var origTzdataPaths = tzdataPaths
+
+func forceZipFileForTesting(zipOnly bool) {
+ tzdataPaths = make([]string, len(origTzdataPaths))
+ copy(tzdataPaths, origTzdataPaths)
+ if zipOnly {
+ for i := 0; i < len(tzdataPaths)-1; i++ {
+ tzdataPaths[i] = "/XXXNOEXIST"
+ }
+ }
+}
+
+func initTestingZone() {
+ z, err := loadLocation("America/Los_Angeles")
+ if err != nil {
+ panic("cannot load America/Los_Angeles for testing: " + err.Error())
+ }
+ z.name = "Local"
+ localLoc = *z
+}
+
+func initLocal() {
+ // TODO(elias.naur): getprop persist.sys.timezone
+ localLoc = *UTC
+}
+
+func loadLocation(name string) (*Location, error) {
+ var firstErr error
+ for _, path := range tzdataPaths {
+ var z *Location
+ var err error
+ if len(path) > 4 && path[len(path)-4:] == ".zip" {
+ z, err = loadZoneZip(path, name)
+ } else {
+ z, err = loadTzdataFile(path, name)
+ }
+ if err == nil {
+ z.name = name
+ return z, nil
+ } else if firstErr == nil && !isNotExist(err) {
+ firstErr = err
+ }
+ }
+ if firstErr != nil {
+ return nil, firstErr
+ }
+ return nil, errors.New("unknown time zone " + name)
+}
+
+func loadTzdataFile(file, name string) (*Location, error) {
+ const (
+ headersize = 12 + 3*4
+ namesize = 40
+ entrysize = namesize + 3*4
+ )
+ if len(name) > namesize {
+ return nil, errors.New(name + " is longer than the maximum zone name length (40 bytes)")
+ }
+ fd, err := open(file)
+ if err != nil {
+ return nil, err
+ }
+ defer closefd(fd)
+
+ buf := make([]byte, headersize)
+ if err := preadn(fd, buf, 0); err != nil {
+ return nil, errors.New("corrupt tzdata file " + file)
+ }
+ d := data{buf, false}
+ if magic := d.read(6); string(magic) != "tzdata" {
+ return nil, errors.New("corrupt tzdata file " + file)
+ }
+ d = data{buf[12:], false}
+ indexOff, _ := d.big4()
+ dataOff, _ := d.big4()
+ indexSize := dataOff - indexOff
+ entrycount := indexSize / entrysize
+ buf = make([]byte, indexSize)
+ if err := preadn(fd, buf, int(indexOff)); err != nil {
+ return nil, errors.New("corrupt tzdata file " + file)
+ }
+ for i := 0; i < int(entrycount); i++ {
+ entry := buf[i*entrysize : (i+1)*entrysize]
+ // len(name) <= namesize is checked at function entry
+ if string(entry[:len(name)]) != name {
+ continue
+ }
+ d := data{entry[namesize:], false}
+ off, _ := d.big4()
+ size, _ := d.big4()
+ buf := make([]byte, size)
+ if err := preadn(fd, buf, int(off+dataOff)); err != nil {
+ return nil, errors.New("corrupt tzdata file " + file)
+ }
+ return loadZoneData(buf)
+ }
+ return nil, errors.New("cannot find " + name + " in tzdata file " + file)
+}
diff --git a/src/time/zoneinfo_android_test.go b/src/time/zoneinfo_android_test.go
new file mode 100644
index 0000000..ba065d1
--- /dev/null
+++ b/src/time/zoneinfo_android_test.go
@@ -0,0 +1,18 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package time_test
+
+import (
+ "testing"
+ . "time"
+)
+
+func TestAndroidTzdata(t *testing.T) {
+ ForceAndroidTzdataForTest(true)
+ defer ForceAndroidTzdataForTest(false)
+ if _, err := LoadLocation("America/Los_Angeles"); err != nil {
+ t.Error(err)
+ }
+}
diff --git a/src/time/zoneinfo_unix.go b/src/time/zoneinfo_unix.go
index ed9502d..bbf263a 100644
--- a/src/time/zoneinfo_unix.go
+++ b/src/time/zoneinfo_unix.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin,386 darwin,amd64 dragonfly freebsd linux nacl netbsd openbsd solaris
+// +build darwin,386 darwin,amd64 dragonfly freebsd linux,!android nacl netbsd openbsd solaris
// Parse "zoneinfo" time zone file.
// This is a fairly standard file format used on OS X, Linux, BSD, Sun, and others.
diff --git a/src/time/zoneinfo_windows.go b/src/time/zoneinfo_windows.go
index a6546f5..a6e227b 100644
--- a/src/time/zoneinfo_windows.go
+++ b/src/time/zoneinfo_windows.go
@@ -11,8 +11,6 @@ import (
"syscall"
)
-//go:generate go run genzabbrs.go -output zoneinfo_abbrs_windows.go
-
// TODO(rsc): Fall back to copy of zoneinfo files.
// BUG(brainman,rsc): On Windows, the operating system does not provide complete
diff --git a/src/unicode/letter.go b/src/unicode/letter.go
index 8aec920..b43cc66 100644
--- a/src/unicode/letter.go
+++ b/src/unicode/letter.go
@@ -320,6 +320,7 @@ type foldPair struct {
// the Unicode-defined simple case folding. Among the code points
// equivalent to rune (including rune itself), SimpleFold returns the
// smallest rune > r if one exists, or else the smallest rune >= 0.
+// If r is not a valid Unicode code point, SimpleFold(r) returns r.
//
// For example:
// SimpleFold('A') = 'a'
@@ -331,7 +332,13 @@ type foldPair struct {
//
// SimpleFold('1') = '1'
//
+// SimpleFold(-2) = -2
+//
func SimpleFold(r rune) rune {
+ if r < 0 || r > MaxRune {
+ return r
+ }
+
if int(r) < len(asciiFold) {
return rune(asciiFold[r])
}
diff --git a/src/unicode/letter_test.go b/src/unicode/letter_test.go
index 0eb9ee9..3fe72ff 100644
--- a/src/unicode/letter_test.go
+++ b/src/unicode/letter_test.go
@@ -432,6 +432,10 @@ func TestSimpleFold(t *testing.T) {
r = out
}
}
+
+ if r := SimpleFold(-42); r != -42 {
+ t.Errorf("SimpleFold(-42) = %v, want -42", r)
+ }
}
// Running 'go test -calibrate' runs the calibration to find a plausible
diff --git a/src/unicode/utf8/utf8.go b/src/unicode/utf8/utf8.go
index 9d35be6..6ccd464 100644
--- a/src/unicode/utf8/utf8.go
+++ b/src/unicode/utf8/utf8.go
@@ -347,6 +347,7 @@ func EncodeRune(p []byte, r rune) int {
p[0] = byte(r)
return 1
case i <= rune2Max:
+ _ = p[1] // eliminate bounds checks
p[0] = t2 | byte(r>>6)
p[1] = tx | byte(r)&maskx
return 2
@@ -354,11 +355,13 @@ func EncodeRune(p []byte, r rune) int {
r = RuneError
fallthrough
case i <= rune3Max:
+ _ = p[2] // eliminate bounds checks
p[0] = t3 | byte(r>>12)
p[1] = tx | byte(r>>6)&maskx
p[2] = tx | byte(r)&maskx
return 3
default:
+ _ = p[3] // eliminate bounds checks
p[0] = t4 | byte(r>>18)
p[1] = tx | byte(r>>12)&maskx
p[2] = tx | byte(r>>6)&maskx
@@ -513,12 +516,10 @@ func ValidString(s string) bool {
// Code points that are out of range or a surrogate half are illegal.
func ValidRune(r rune) bool {
switch {
- case r < 0:
- return false
- case surrogateMin <= r && r <= surrogateMax:
- return false
- case r > MaxRune:
- return false
+ case 0 <= r && r < surrogateMin:
+ return true
+ case surrogateMax < r && r <= MaxRune:
+ return true
}
- return true
+ return false
}
diff --git a/src/unicode/utf8/utf8_test.go b/src/unicode/utf8/utf8_test.go
index 51571b6..dc9c425 100644
--- a/src/unicode/utf8/utf8_test.go
+++ b/src/unicode/utf8/utf8_test.go
@@ -54,14 +54,18 @@ var utf8map = []Utf8Map{
{0x00ff, "\xc3\xbf"},
{0x0100, "\xc4\x80"},
{0x07ff, "\xdf\xbf"},
+ {0x0400, "\xd0\x80"},
{0x0800, "\xe0\xa0\x80"},
{0x0801, "\xe0\xa0\x81"},
+ {0x1000, "\xe1\x80\x80"},
+ {0xd000, "\xed\x80\x80"},
{0xd7ff, "\xed\x9f\xbf"}, // last code point before surrogate half.
{0xe000, "\xee\x80\x80"}, // first code point after surrogate half.
{0xfffe, "\xef\xbf\xbe"},
{0xffff, "\xef\xbf\xbf"},
{0x10000, "\xf0\x90\x80\x80"},
{0x10001, "\xf0\x90\x80\x81"},
+ {0x40000, "\xf1\x80\x80\x80"},
{0x10fffe, "\xf4\x8f\xbf\xbe"},
{0x10ffff, "\xf4\x8f\xbf\xbf"},
{0xFFFD, "\xef\xbf\xbd"},
@@ -228,6 +232,93 @@ func TestIntConversion(t *testing.T) {
}
}
+var invalidSequenceTests = []string{
+ "\xed\xa0\x80\x80", // surrogate min
+ "\xed\xbf\xbf\x80", // surrogate max
+
+ // xx
+ "\x91\x80\x80\x80",
+
+ // s1
+ "\xC2\x7F\x80\x80",
+ "\xC2\xC0\x80\x80",
+ "\xDF\x7F\x80\x80",
+ "\xDF\xC0\x80\x80",
+
+ // s2
+ "\xE0\x9F\xBF\x80",
+ "\xE0\xA0\x7F\x80",
+ "\xE0\xBF\xC0\x80",
+ "\xE0\xC0\x80\x80",
+
+ // s3
+ "\xE1\x7F\xBF\x80",
+ "\xE1\x80\x7F\x80",
+ "\xE1\xBF\xC0\x80",
+ "\xE1\xC0\x80\x80",
+
+ //s4
+ "\xED\x7F\xBF\x80",
+ "\xED\x80\x7F\x80",
+ "\xED\x9F\xC0\x80",
+ "\xED\xA0\x80\x80",
+
+ // s5
+ "\xF0\x8F\xBF\xBF",
+ "\xF0\x90\x7F\xBF",
+ "\xF0\x90\x80\x7F",
+ "\xF0\xBF\xBF\xC0",
+ "\xF0\xBF\xC0\x80",
+ "\xF0\xC0\x80\x80",
+
+ // s6
+ "\xF1\x7F\xBF\xBF",
+ "\xF1\x80\x7F\xBF",
+ "\xF1\x80\x80\x7F",
+ "\xF1\xBF\xBF\xC0",
+ "\xF1\xBF\xC0\x80",
+ "\xF1\xC0\x80\x80",
+
+ // s7
+ "\xF4\x7F\xBF\xBF",
+ "\xF4\x80\x7F\xBF",
+ "\xF4\x80\x80\x7F",
+ "\xF4\x8F\xBF\xC0",
+ "\xF4\x8F\xC0\x80",
+ "\xF4\x90\x80\x80",
+}
+
+func runtimeDecodeRune(s string) rune {
+ for _, r := range s {
+ return r
+ }
+ return -1
+}
+
+func TestDecodeInvalidSequence(t *testing.T) {
+ for _, s := range invalidSequenceTests {
+ r1, _ := DecodeRune([]byte(s))
+ if want := RuneError; r1 != want {
+ t.Errorf("DecodeRune(%#x) = %#04x, want %#04x", s, r1, want)
+ return
+ }
+ r2, _ := DecodeRuneInString(s)
+ if want := RuneError; r2 != want {
+ t.Errorf("DecodeRuneInString(%q) = %#04x, want %#04x", s, r2, want)
+ return
+ }
+ if r1 != r2 {
+ t.Errorf("DecodeRune(%#x) = %#04x mismatch with DecodeRuneInString(%q) = %#04x", s, r1, s, r2)
+ return
+ }
+ r3 := runtimeDecodeRune(s)
+ if r2 != r3 {
+ t.Errorf("DecodeRuneInString(%q) = %#04x mismatch with runtime.decoderune(%q) = %#04x", s, r2, s, r3)
+ return
+ }
+ }
+}
+
func testSequence(t *testing.T, s string) {
type info struct {
index int
diff --git a/src/unsafe/unsafe.go b/src/unsafe/unsafe.go
index 8f43e72..859ca4f 100644
--- a/src/unsafe/unsafe.go
+++ b/src/unsafe/unsafe.go
@@ -76,8 +76,10 @@ type ArbitraryType int
// // equivalent to e := unsafe.Pointer(&x[i])
// e := unsafe.Pointer(uintptr(unsafe.Pointer(&x[0])) + i*unsafe.Sizeof(x[0]))
//
-// It is valid both to add and to subtract offsets from a pointer in this way,
-// but the result must continue to point into the original allocated object.
+// It is valid both to add and to subtract offsets from a pointer in this way.
+// It is also valid to use &^ to round pointers, usually for alignment.
+// In all cases, the result must continue to point into the original allocated object.
+//
// Unlike in C, it is not valid to advance a pointer just beyond the end of
// its original allocation:
//
@@ -153,7 +155,7 @@ type ArbitraryType int
// var s string
// hdr := (*reflect.StringHeader)(unsafe.Pointer(&s)) // case 1
// hdr.Data = uintptr(unsafe.Pointer(p)) // case 6 (this case)
-// hdr.Len = uintptr(n)
+// hdr.Len = n
//
// In this usage hdr.Data is really an alternate way to refer to the underlying
// pointer in the slice header, not a uintptr variable itself.
@@ -166,7 +168,7 @@ type ArbitraryType int
// // INVALID: a directly-declared header will not hold Data as a reference.
// var hdr reflect.StringHeader
// hdr.Data = uintptr(unsafe.Pointer(p))
-// hdr.Len = uintptr(n)
+// hdr.Len = n
// s := *(*string)(unsafe.Pointer(&hdr)) // p possibly already lost
//
type Pointer *ArbitraryType
diff --git a/src/vendor/golang_org/x/crypto/chacha20poly1305/chacha20poly1305.go b/src/vendor/golang_org/x/crypto/chacha20poly1305/chacha20poly1305.go
new file mode 100644
index 0000000..eb6739a
--- /dev/null
+++ b/src/vendor/golang_org/x/crypto/chacha20poly1305/chacha20poly1305.go
@@ -0,0 +1,83 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package chacha20poly1305 implements the ChaCha20-Poly1305 AEAD as specified in RFC 7539.
+package chacha20poly1305
+
+import (
+ "crypto/cipher"
+ "errors"
+)
+
+const (
+ // KeySize is the size of the key used by this AEAD, in bytes.
+ KeySize = 32
+ // NonceSize is the size of the nonce used with this AEAD, in bytes.
+ NonceSize = 12
+)
+
+type chacha20poly1305 struct {
+ key [32]byte
+}
+
+// New returns a ChaCha20-Poly1305 AEAD that uses the given, 256-bit key.
+func New(key []byte) (cipher.AEAD, error) {
+ if len(key) != KeySize {
+ return nil, errors.New("chacha20poly1305: bad key length")
+ }
+ ret := new(chacha20poly1305)
+ copy(ret.key[:], key)
+ return ret, nil
+}
+
+func (c *chacha20poly1305) NonceSize() int {
+ return NonceSize
+}
+
+func (c *chacha20poly1305) Overhead() int {
+ return 16
+}
+
+func (c *chacha20poly1305) Seal(dst, nonce, plaintext, additionalData []byte) []byte {
+ if len(nonce) != NonceSize {
+ panic("chacha20poly1305: bad nonce length passed to Seal")
+ }
+
+ if uint64(len(plaintext)) > (1<<38)-64 {
+ panic("chacha20poly1305: plaintext too large")
+ }
+
+ return c.seal(dst, nonce, plaintext, additionalData)
+}
+
+var errOpen = errors.New("chacha20poly1305: message authentication failed")
+
+func (c *chacha20poly1305) Open(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) {
+ if len(nonce) != NonceSize {
+ panic("chacha20poly1305: bad nonce length passed to Open")
+ }
+ if len(ciphertext) < 16 {
+ return nil, errOpen
+ }
+ if uint64(len(ciphertext)) > (1<<38)-48 {
+ panic("chacha20poly1305: ciphertext too large")
+ }
+
+ return c.open(dst, nonce, ciphertext, additionalData)
+}
+
+// sliceForAppend takes a slice and a requested number of bytes. It returns a
+// slice with the contents of the given slice followed by that many bytes and a
+// second slice that aliases into it and contains only the extra bytes. If the
+// original slice has sufficient capacity then no allocation is performed.
+func sliceForAppend(in []byte, n int) (head, tail []byte) {
+ if total := len(in) + n; cap(in) >= total {
+ head = in[:total]
+ } else {
+ head = make([]byte, total)
+ copy(head, in)
+ }
+ tail = head[len(in):]
+ return
+}
diff --git a/src/vendor/golang_org/x/crypto/chacha20poly1305/chacha20poly1305_amd64.go b/src/vendor/golang_org/x/crypto/chacha20poly1305/chacha20poly1305_amd64.go
new file mode 100644
index 0000000..f0d3485
--- /dev/null
+++ b/src/vendor/golang_org/x/crypto/chacha20poly1305/chacha20poly1305_amd64.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.
+
+// +build amd64,go1.7
+
+package chacha20poly1305
+
+import "encoding/binary"
+
+//go:noescape
+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
+
+var canUseASM bool
+
+func init() {
+ canUseASM = haveSSSE3()
+}
+
+// setupState writes a ChaCha20 input matrix to state. See
+// https://tools.ietf.org/html/rfc7539#section-2.3.
+func setupState(state *[16]uint32, key *[32]byte, nonce []byte) {
+ state[0] = 0x61707865
+ state[1] = 0x3320646e
+ state[2] = 0x79622d32
+ state[3] = 0x6b206574
+
+ state[4] = binary.LittleEndian.Uint32(key[:4])
+ state[5] = binary.LittleEndian.Uint32(key[4:8])
+ state[6] = binary.LittleEndian.Uint32(key[8:12])
+ state[7] = binary.LittleEndian.Uint32(key[12:16])
+ state[8] = binary.LittleEndian.Uint32(key[16:20])
+ state[9] = binary.LittleEndian.Uint32(key[20:24])
+ state[10] = binary.LittleEndian.Uint32(key[24:28])
+ state[11] = binary.LittleEndian.Uint32(key[28:32])
+
+ state[12] = 0
+ state[13] = binary.LittleEndian.Uint32(nonce[:4])
+ state[14] = binary.LittleEndian.Uint32(nonce[4:8])
+ state[15] = binary.LittleEndian.Uint32(nonce[8:12])
+}
+
+func (c *chacha20poly1305) seal(dst, nonce, plaintext, additionalData []byte) []byte {
+ if !canUseASM {
+ return c.sealGeneric(dst, nonce, plaintext, additionalData)
+ }
+
+ var state [16]uint32
+ setupState(&state, &c.key, nonce)
+
+ ret, out := sliceForAppend(dst, len(plaintext)+16)
+ chacha20Poly1305Seal(out[:], state[:], plaintext, additionalData)
+ return ret
+}
+
+func (c *chacha20poly1305) open(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) {
+ if !canUseASM {
+ return c.openGeneric(dst, nonce, ciphertext, additionalData)
+ }
+
+ var state [16]uint32
+ setupState(&state, &c.key, nonce)
+
+ ciphertext = ciphertext[:len(ciphertext)-16]
+ ret, out := sliceForAppend(dst, len(ciphertext))
+ if !chacha20Poly1305Open(out, state[:], ciphertext, additionalData) {
+ for i := range out {
+ out[i] = 0
+ }
+ return nil, errOpen
+ }
+
+ return ret, nil
+}
diff --git a/src/vendor/golang_org/x/crypto/chacha20poly1305/chacha20poly1305_amd64.s b/src/vendor/golang_org/x/crypto/chacha20poly1305/chacha20poly1305_amd64.s
new file mode 100644
index 0000000..ac95844
--- /dev/null
+++ b/src/vendor/golang_org/x/crypto/chacha20poly1305/chacha20poly1305_amd64.s
@@ -0,0 +1,2707 @@
+// Copyright 2016 The Go 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 was originally from https://golang.org/cl/24717 by Vlad Krasnov of CloudFlare.
+
+// +build go1.7
+
+#include "textflag.h"
+// General register allocation
+#define oup DI
+#define inp SI
+#define inl BX
+#define adp CX // free to reuse, after we hash the additional data
+#define keyp R8 // free to reuse, when we copy the key to stack
+#define itr2 R9 // general iterator
+#define itr1 CX // general iterator
+#define acc0 R10
+#define acc1 R11
+#define acc2 R12
+#define t0 R13
+#define t1 R14
+#define t2 R15
+#define t3 R8
+// Register and stack allocation for the SSE code
+#define rStore (0*16)(BP)
+#define sStore (1*16)(BP)
+#define state1Store (2*16)(BP)
+#define state2Store (3*16)(BP)
+#define tmpStore (4*16)(BP)
+#define ctr0Store (5*16)(BP)
+#define ctr1Store (6*16)(BP)
+#define ctr2Store (7*16)(BP)
+#define ctr3Store (8*16)(BP)
+#define A0 X0
+#define A1 X1
+#define A2 X2
+#define B0 X3
+#define B1 X4
+#define B2 X5
+#define C0 X6
+#define C1 X7
+#define C2 X8
+#define D0 X9
+#define D1 X10
+#define D2 X11
+#define T0 X12
+#define T1 X13
+#define T2 X14
+#define T3 X15
+#define A3 T0
+#define B3 T1
+#define C3 T2
+#define D3 T3
+// Register and stack allocation for the AVX2 code
+#define rsStoreAVX2 (0*32)(BP)
+#define state1StoreAVX2 (1*32)(BP)
+#define state2StoreAVX2 (2*32)(BP)
+#define ctr0StoreAVX2 (3*32)(BP)
+#define ctr1StoreAVX2 (4*32)(BP)
+#define ctr2StoreAVX2 (5*32)(BP)
+#define ctr3StoreAVX2 (6*32)(BP)
+#define tmpStoreAVX2 (7*32)(BP) // 256 bytes on stack
+#define AA0 Y0
+#define AA1 Y5
+#define AA2 Y6
+#define AA3 Y7
+#define BB0 Y14
+#define BB1 Y9
+#define BB2 Y10
+#define BB3 Y11
+#define CC0 Y12
+#define CC1 Y13
+#define CC2 Y8
+#define CC3 Y15
+#define DD0 Y4
+#define DD1 Y1
+#define DD2 Y2
+#define DD3 Y3
+#define TT0 DD3
+#define TT1 AA3
+#define TT2 BB3
+#define TT3 CC3
+// ChaCha20 constants
+DATA ·chacha20Constants<>+0x00(SB)/4, $0x61707865
+DATA ·chacha20Constants<>+0x04(SB)/4, $0x3320646e
+DATA ·chacha20Constants<>+0x08(SB)/4, $0x79622d32
+DATA ·chacha20Constants<>+0x0c(SB)/4, $0x6b206574
+DATA ·chacha20Constants<>+0x10(SB)/4, $0x61707865
+DATA ·chacha20Constants<>+0x14(SB)/4, $0x3320646e
+DATA ·chacha20Constants<>+0x18(SB)/4, $0x79622d32
+DATA ·chacha20Constants<>+0x1c(SB)/4, $0x6b206574
+// <<< 16 with PSHUFB
+DATA ·rol16<>+0x00(SB)/8, $0x0504070601000302
+DATA ·rol16<>+0x08(SB)/8, $0x0D0C0F0E09080B0A
+DATA ·rol16<>+0x10(SB)/8, $0x0504070601000302
+DATA ·rol16<>+0x18(SB)/8, $0x0D0C0F0E09080B0A
+// <<< 8 with PSHUFB
+DATA ·rol8<>+0x00(SB)/8, $0x0605040702010003
+DATA ·rol8<>+0x08(SB)/8, $0x0E0D0C0F0A09080B
+DATA ·rol8<>+0x10(SB)/8, $0x0605040702010003
+DATA ·rol8<>+0x18(SB)/8, $0x0E0D0C0F0A09080B
+
+DATA ·avx2InitMask<>+0x00(SB)/8, $0x0
+DATA ·avx2InitMask<>+0x08(SB)/8, $0x0
+DATA ·avx2InitMask<>+0x10(SB)/8, $0x1
+DATA ·avx2InitMask<>+0x18(SB)/8, $0x0
+
+DATA ·avx2IncMask<>+0x00(SB)/8, $0x2
+DATA ·avx2IncMask<>+0x08(SB)/8, $0x0
+DATA ·avx2IncMask<>+0x10(SB)/8, $0x2
+DATA ·avx2IncMask<>+0x18(SB)/8, $0x0
+// Poly1305 key clamp
+DATA ·polyClampMask<>+0x00(SB)/8, $0x0FFFFFFC0FFFFFFF
+DATA ·polyClampMask<>+0x08(SB)/8, $0x0FFFFFFC0FFFFFFC
+DATA ·polyClampMask<>+0x10(SB)/8, $0xFFFFFFFFFFFFFFFF
+DATA ·polyClampMask<>+0x18(SB)/8, $0xFFFFFFFFFFFFFFFF
+
+DATA ·sseIncMask<>+0x00(SB)/8, $0x1
+DATA ·sseIncMask<>+0x08(SB)/8, $0x0
+// To load/store the last < 16 bytes in a buffer
+DATA ·andMask<>+0x00(SB)/8, $0x00000000000000ff
+DATA ·andMask<>+0x08(SB)/8, $0x0000000000000000
+DATA ·andMask<>+0x10(SB)/8, $0x000000000000ffff
+DATA ·andMask<>+0x18(SB)/8, $0x0000000000000000
+DATA ·andMask<>+0x20(SB)/8, $0x0000000000ffffff
+DATA ·andMask<>+0x28(SB)/8, $0x0000000000000000
+DATA ·andMask<>+0x30(SB)/8, $0x00000000ffffffff
+DATA ·andMask<>+0x38(SB)/8, $0x0000000000000000
+DATA ·andMask<>+0x40(SB)/8, $0x000000ffffffffff
+DATA ·andMask<>+0x48(SB)/8, $0x0000000000000000
+DATA ·andMask<>+0x50(SB)/8, $0x0000ffffffffffff
+DATA ·andMask<>+0x58(SB)/8, $0x0000000000000000
+DATA ·andMask<>+0x60(SB)/8, $0x00ffffffffffffff
+DATA ·andMask<>+0x68(SB)/8, $0x0000000000000000
+DATA ·andMask<>+0x70(SB)/8, $0xffffffffffffffff
+DATA ·andMask<>+0x78(SB)/8, $0x0000000000000000
+DATA ·andMask<>+0x80(SB)/8, $0xffffffffffffffff
+DATA ·andMask<>+0x88(SB)/8, $0x00000000000000ff
+DATA ·andMask<>+0x90(SB)/8, $0xffffffffffffffff
+DATA ·andMask<>+0x98(SB)/8, $0x000000000000ffff
+DATA ·andMask<>+0xa0(SB)/8, $0xffffffffffffffff
+DATA ·andMask<>+0xa8(SB)/8, $0x0000000000ffffff
+DATA ·andMask<>+0xb0(SB)/8, $0xffffffffffffffff
+DATA ·andMask<>+0xb8(SB)/8, $0x00000000ffffffff
+DATA ·andMask<>+0xc0(SB)/8, $0xffffffffffffffff
+DATA ·andMask<>+0xc8(SB)/8, $0x000000ffffffffff
+DATA ·andMask<>+0xd0(SB)/8, $0xffffffffffffffff
+DATA ·andMask<>+0xd8(SB)/8, $0x0000ffffffffffff
+DATA ·andMask<>+0xe0(SB)/8, $0xffffffffffffffff
+DATA ·andMask<>+0xe8(SB)/8, $0x00ffffffffffffff
+
+GLOBL ·chacha20Constants<>(SB), (NOPTR+RODATA), $32
+GLOBL ·rol16<>(SB), (NOPTR+RODATA), $32
+GLOBL ·rol8<>(SB), (NOPTR+RODATA), $32
+GLOBL ·sseIncMask<>(SB), (NOPTR+RODATA), $16
+GLOBL ·avx2IncMask<>(SB), (NOPTR+RODATA), $32
+GLOBL ·avx2InitMask<>(SB), (NOPTR+RODATA), $32
+GLOBL ·polyClampMask<>(SB), (NOPTR+RODATA), $32
+GLOBL ·andMask<>(SB), (NOPTR+RODATA), $240
+// No PALIGNR in Go ASM yet (but VPALIGNR is present).
+#define shiftB0Left BYTE $0x66; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xdb; BYTE $0x04 // PALIGNR $4, X3, X3
+#define shiftB1Left BYTE $0x66; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xe4; BYTE $0x04 // PALIGNR $4, X4, X4
+#define shiftB2Left BYTE $0x66; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xed; BYTE $0x04 // PALIGNR $4, X5, X5
+#define shiftB3Left BYTE $0x66; BYTE $0x45; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xed; BYTE $0x04 // PALIGNR $4, X13, X13
+#define shiftC0Left BYTE $0x66; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xf6; BYTE $0x08 // PALIGNR $8, X6, X6
+#define shiftC1Left BYTE $0x66; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xff; BYTE $0x08 // PALIGNR $8, X7, X7
+#define shiftC2Left BYTE $0x66; BYTE $0x45; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xc0; BYTE $0x08 // PALIGNR $8, X8, X8
+#define shiftC3Left BYTE $0x66; BYTE $0x45; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xf6; BYTE $0x08 // PALIGNR $8, X14, X14
+#define shiftD0Left BYTE $0x66; BYTE $0x45; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xc9; BYTE $0x0c // PALIGNR $12, X9, X9
+#define shiftD1Left BYTE $0x66; BYTE $0x45; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xd2; BYTE $0x0c // PALIGNR $12, X10, X10
+#define shiftD2Left BYTE $0x66; BYTE $0x45; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xdb; BYTE $0x0c // PALIGNR $12, X11, X11
+#define shiftD3Left BYTE $0x66; BYTE $0x45; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xff; BYTE $0x0c // PALIGNR $12, X15, X15
+#define shiftB0Right BYTE $0x66; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xdb; BYTE $0x0c // PALIGNR $12, X3, X3
+#define shiftB1Right BYTE $0x66; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xe4; BYTE $0x0c // PALIGNR $12, X4, X4
+#define shiftB2Right BYTE $0x66; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xed; BYTE $0x0c // PALIGNR $12, X5, X5
+#define shiftB3Right BYTE $0x66; BYTE $0x45; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xed; BYTE $0x0c // PALIGNR $12, X13, X13
+#define shiftC0Right shiftC0Left
+#define shiftC1Right shiftC1Left
+#define shiftC2Right shiftC2Left
+#define shiftC3Right shiftC3Left
+#define shiftD0Right BYTE $0x66; BYTE $0x45; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xc9; BYTE $0x04 // PALIGNR $4, X9, X9
+#define shiftD1Right BYTE $0x66; BYTE $0x45; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xd2; BYTE $0x04 // PALIGNR $4, X10, X10
+#define shiftD2Right BYTE $0x66; BYTE $0x45; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xdb; BYTE $0x04 // PALIGNR $4, X11, X11
+#define shiftD3Right BYTE $0x66; BYTE $0x45; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xff; BYTE $0x04 // PALIGNR $4, X15, X15
+// Some macros
+#define chachaQR(A, B, C, D, T) \
+ PADDD B, A; PXOR A, D; PSHUFB ·rol16<>(SB), D \
+ PADDD D, C; PXOR C, B; MOVO B, T; PSLLL $12, T; PSRLL $20, B; PXOR T, B \
+ PADDD B, A; PXOR A, D; PSHUFB ·rol8<>(SB), D \
+ PADDD D, C; PXOR C, B; MOVO B, T; PSLLL $7, T; PSRLL $25, B; PXOR T, B
+
+#define chachaQR_AVX2(A, B, C, D, T) \
+ VPADDD B, A, A; VPXOR A, D, D; VPSHUFB ·rol16<>(SB), D, D \
+ VPADDD D, C, C; VPXOR C, B, B; VPSLLD $12, B, T; VPSRLD $20, B, B; VPXOR T, B, B \
+ VPADDD B, A, A; VPXOR A, D, D; VPSHUFB ·rol8<>(SB), D, D \
+ VPADDD D, C, C; VPXOR C, B, B; VPSLLD $7, B, T; VPSRLD $25, B, B; VPXOR T, B, B
+
+#define polyAdd(S) ADDQ S, acc0; ADCQ 8+S, acc1; ADCQ $1, acc2
+#define polyMulStage1 MOVQ (0*8)(BP), AX; MOVQ AX, t2; MULQ acc0; MOVQ AX, t0; MOVQ DX, t1; MOVQ (0*8)(BP), AX; MULQ acc1; IMULQ acc2, t2; ADDQ AX, t1; ADCQ DX, t2
+#define polyMulStage2 MOVQ (1*8)(BP), AX; MOVQ AX, t3; MULQ acc0; ADDQ AX, t1; ADCQ $0, DX; MOVQ DX, acc0; MOVQ (1*8)(BP), AX; MULQ acc1; ADDQ AX, t2; ADCQ $0, DX
+#define polyMulStage3 IMULQ acc2, t3; ADDQ acc0, t2; ADCQ DX, t3
+#define polyMulReduceStage MOVQ t0, acc0; MOVQ t1, acc1; MOVQ t2, acc2; ANDQ $3, acc2; MOVQ t2, t0; ANDQ $-4, t0; MOVQ t3, t1; SHRQ $2, t2:t3; SHRQ $2, t3; ADDQ t0, acc0; ADCQ t1, acc1; ADCQ $0, acc2; ADDQ t2, acc0; ADCQ t3, acc1; ADCQ $0, acc2
+
+#define polyMulStage1_AVX2 MOVQ (0*8)(BP), DX; MOVQ DX, t2; MULXQ acc0, t0, t1; IMULQ acc2, t2; MULXQ acc1, AX, DX; ADDQ AX, t1; ADCQ DX, t2
+#define polyMulStage2_AVX2 MOVQ (1*8)(BP), DX; MULXQ acc0, acc0, AX; ADDQ acc0, t1; MULXQ acc1, acc1, t3; ADCQ acc1, t2; ADCQ $0, t3
+#define polyMulStage3_AVX2 IMULQ acc2, DX; ADDQ AX, t2; ADCQ DX, t3
+
+#define polyMul polyMulStage1; polyMulStage2; polyMulStage3; polyMulReduceStage
+#define polyMulAVX2 polyMulStage1_AVX2; polyMulStage2_AVX2; polyMulStage3_AVX2; polyMulReduceStage
+// ----------------------------------------------------------------------------
+TEXT polyHashADInternal(SB), NOSPLIT, $0
+ // adp points to beginning of additional data
+ // itr2 holds ad length
+ XORQ acc0, acc0
+ XORQ acc1, acc1
+ XORQ acc2, acc2
+ CMPQ itr2, $13
+ JNE hashADLoop
+
+openFastTLSAD:
+ // Special treatment for the TLS case of 13 bytes
+ MOVQ (adp), acc0
+ MOVQ 5(adp), acc1
+ SHRQ $24, acc1
+ MOVQ $1, acc2
+ polyMul
+ RET
+
+hashADLoop:
+ // Hash in 16 byte chunks
+ CMPQ itr2, $16
+ JB hashADTail
+ polyAdd(0(adp))
+ LEAQ (1*16)(adp), adp
+ SUBQ $16, itr2
+ polyMul
+ JMP hashADLoop
+
+hashADTail:
+ CMPQ itr2, $0
+ JE hashADDone
+
+ // Hash last < 16 byte tail
+ XORQ t0, t0
+ XORQ t1, t1
+ XORQ t2, t2
+ ADDQ itr2, adp
+
+hashADTailLoop:
+ SHLQ $8, t1:t0
+ SHLQ $8, t0
+ MOVB -1(adp), t2
+ XORQ t2, t0
+ DECQ adp
+ DECQ itr2
+ JNE hashADTailLoop
+
+hashADTailFinish:
+ ADDQ t0, acc0; ADCQ t1, acc1; ADCQ $1, acc2
+ polyMul
+
+ // Finished AD
+hashADDone:
+ RET
+
+// ----------------------------------------------------------------------------
+// func chacha20Poly1305Open(dst, key, src, ad []byte) bool
+TEXT ·chacha20Poly1305Open(SB), 0, $288-97
+ // For aligned stack access
+ MOVQ SP, BP
+ ADDQ $32, BP
+ ANDQ $-32, BP
+ MOVQ dst+0(FP), oup
+ MOVQ key+24(FP), keyp
+ MOVQ src+48(FP), inp
+ MOVQ src_len+56(FP), inl
+ MOVQ ad+72(FP), adp
+
+ // Check for AVX2 support
+ CMPB runtime·support_avx2(SB), $1
+ JE chacha20Poly1305Open_AVX2
+
+ // Special optimization, for very short buffers
+ CMPQ inl, $128
+ JBE openSSE128 // About 16% faster
+
+ // For long buffers, prepare the poly key first
+ MOVOU ·chacha20Constants<>(SB), A0
+ MOVOU (1*16)(keyp), B0
+ MOVOU (2*16)(keyp), C0
+ MOVOU (3*16)(keyp), D0
+ MOVO D0, T1
+
+ // Store state on stack for future use
+ MOVO B0, state1Store
+ MOVO C0, state2Store
+ MOVO D0, ctr3Store
+ MOVQ $10, itr2
+
+openSSEPreparePolyKey:
+ chachaQR(A0, B0, C0, D0, T0)
+ shiftB0Left; shiftC0Left; shiftD0Left
+ chachaQR(A0, B0, C0, D0, T0)
+ shiftB0Right; shiftC0Right; shiftD0Right
+ DECQ itr2
+ JNE openSSEPreparePolyKey
+
+ // A0|B0 hold the Poly1305 32-byte key, C0,D0 can be discarded
+ PADDL ·chacha20Constants<>(SB), A0; PADDL state1Store, B0
+
+ // Clamp and store the key
+ PAND ·polyClampMask<>(SB), A0
+ MOVO A0, rStore; MOVO B0, sStore
+
+ // Hash AAD
+ MOVQ ad_len+80(FP), itr2
+ CALL polyHashADInternal(SB)
+
+openSSEMainLoop:
+ CMPQ inl, $256
+ JB openSSEMainLoopDone
+
+ // Load state, increment counter blocks
+ MOVO ·chacha20Constants<>(SB), A0; MOVO state1Store, B0; MOVO state2Store, C0; MOVO ctr3Store, D0; PADDL ·sseIncMask<>(SB), D0
+ MOVO A0, A1; MOVO B0, B1; MOVO C0, C1; MOVO D0, D1; PADDL ·sseIncMask<>(SB), D1
+ MOVO A1, A2; MOVO B1, B2; MOVO C1, C2; MOVO D1, D2; PADDL ·sseIncMask<>(SB), D2
+ MOVO A2, A3; MOVO B2, B3; MOVO C2, C3; MOVO D2, D3; PADDL ·sseIncMask<>(SB), D3
+
+ // Store counters
+ MOVO D0, ctr0Store; MOVO D1, ctr1Store; MOVO D2, ctr2Store; MOVO D3, ctr3Store
+
+ // There are 10 ChaCha20 iterations of 2QR each, so for 6 iterations we hash 2 blocks, and for the remaining 4 only 1 block - for a total of 16
+ MOVQ $4, itr1
+ MOVQ inp, itr2
+
+openSSEInternalLoop:
+ MOVO C3, tmpStore
+ chachaQR(A0, B0, C0, D0, C3); chachaQR(A1, B1, C1, D1, C3); chachaQR(A2, B2, C2, D2, C3)
+ MOVO tmpStore, C3
+ MOVO C1, tmpStore
+ chachaQR(A3, B3, C3, D3, C1)
+ MOVO tmpStore, C1
+ polyAdd(0(itr2))
+ shiftB0Left; shiftB1Left; shiftB2Left; shiftB3Left
+ shiftC0Left; shiftC1Left; shiftC2Left; shiftC3Left
+ shiftD0Left; shiftD1Left; shiftD2Left; shiftD3Left
+ polyMulStage1
+ polyMulStage2
+ LEAQ (2*8)(itr2), itr2
+ MOVO C3, tmpStore
+ chachaQR(A0, B0, C0, D0, C3); chachaQR(A1, B1, C1, D1, C3); chachaQR(A2, B2, C2, D2, C3)
+ MOVO tmpStore, C3
+ MOVO C1, tmpStore
+ polyMulStage3
+ chachaQR(A3, B3, C3, D3, C1)
+ MOVO tmpStore, C1
+ polyMulReduceStage
+ shiftB0Right; shiftB1Right; shiftB2Right; shiftB3Right
+ shiftC0Right; shiftC1Right; shiftC2Right; shiftC3Right
+ shiftD0Right; shiftD1Right; shiftD2Right; shiftD3Right
+ DECQ itr1
+ JGE openSSEInternalLoop
+
+ polyAdd(0(itr2))
+ polyMul
+ LEAQ (2*8)(itr2), itr2
+
+ CMPQ itr1, $-6
+ JG openSSEInternalLoop
+
+ // Add in the state
+ PADDD ·chacha20Constants<>(SB), A0; PADDD ·chacha20Constants<>(SB), A1; PADDD ·chacha20Constants<>(SB), A2; PADDD ·chacha20Constants<>(SB), A3
+ PADDD state1Store, B0; PADDD state1Store, B1; PADDD state1Store, B2; PADDD state1Store, B3
+ PADDD state2Store, C0; PADDD state2Store, C1; PADDD state2Store, C2; PADDD state2Store, C3
+ PADDD ctr0Store, D0; PADDD ctr1Store, D1; PADDD ctr2Store, D2; PADDD ctr3Store, D3
+
+ // Load - xor - store
+ MOVO D3, tmpStore
+ MOVOU (0*16)(inp), D3; PXOR D3, A0; MOVOU A0, (0*16)(oup)
+ MOVOU (1*16)(inp), D3; PXOR D3, B0; MOVOU B0, (1*16)(oup)
+ MOVOU (2*16)(inp), D3; PXOR D3, C0; MOVOU C0, (2*16)(oup)
+ MOVOU (3*16)(inp), D3; PXOR D3, D0; MOVOU D0, (3*16)(oup)
+ MOVOU (4*16)(inp), D0; PXOR D0, A1; MOVOU A1, (4*16)(oup)
+ MOVOU (5*16)(inp), D0; PXOR D0, B1; MOVOU B1, (5*16)(oup)
+ MOVOU (6*16)(inp), D0; PXOR D0, C1; MOVOU C1, (6*16)(oup)
+ MOVOU (7*16)(inp), D0; PXOR D0, D1; MOVOU D1, (7*16)(oup)
+ MOVOU (8*16)(inp), D0; PXOR D0, A2; MOVOU A2, (8*16)(oup)
+ MOVOU (9*16)(inp), D0; PXOR D0, B2; MOVOU B2, (9*16)(oup)
+ MOVOU (10*16)(inp), D0; PXOR D0, C2; MOVOU C2, (10*16)(oup)
+ MOVOU (11*16)(inp), D0; PXOR D0, D2; MOVOU D2, (11*16)(oup)
+ MOVOU (12*16)(inp), D0; PXOR D0, A3; MOVOU A3, (12*16)(oup)
+ MOVOU (13*16)(inp), D0; PXOR D0, B3; MOVOU B3, (13*16)(oup)
+ MOVOU (14*16)(inp), D0; PXOR D0, C3; MOVOU C3, (14*16)(oup)
+ MOVOU (15*16)(inp), D0; PXOR tmpStore, D0; MOVOU D0, (15*16)(oup)
+ LEAQ 256(inp), inp
+ LEAQ 256(oup), oup
+ SUBQ $256, inl
+ JMP openSSEMainLoop
+
+openSSEMainLoopDone:
+ // Handle the various tail sizes efficiently
+ TESTQ inl, inl
+ JE openSSEFinalize
+ CMPQ inl, $64
+ JBE openSSETail64
+ CMPQ inl, $128
+ JBE openSSETail128
+ CMPQ inl, $192
+ JBE openSSETail192
+ JMP openSSETail256
+
+openSSEFinalize:
+ // Hash in the PT, AAD lengths
+ ADDQ ad_len+80(FP), acc0; ADCQ src_len+56(FP), acc1; ADCQ $1, acc2
+ polyMul
+
+ // Final reduce
+ MOVQ acc0, t0
+ MOVQ acc1, t1
+ MOVQ acc2, t2
+ SUBQ $-5, acc0
+ SBBQ $-1, acc1
+ SBBQ $3, acc2
+ CMOVQCS t0, acc0
+ CMOVQCS t1, acc1
+ CMOVQCS t2, acc2
+
+ // Add in the "s" part of the key
+ ADDQ 0+sStore, acc0
+ ADCQ 8+sStore, acc1
+
+ // Finally, constant time compare to the tag at the end of the message
+ XORQ AX, AX
+ MOVQ $1, DX
+ XORQ (0*8)(inp), acc0
+ XORQ (1*8)(inp), acc1
+ ORQ acc1, acc0
+ CMOVQEQ DX, AX
+
+ // Return true iff tags are equal
+ MOVB AX, ret+96(FP)
+ RET
+
+// ----------------------------------------------------------------------------
+// Special optimization for buffers smaller than 129 bytes
+openSSE128:
+ // For up to 128 bytes of ciphertext and 64 bytes for the poly key, we require to process three blocks
+ MOVOU ·chacha20Constants<>(SB), A0; MOVOU (1*16)(keyp), B0; MOVOU (2*16)(keyp), C0; MOVOU (3*16)(keyp), D0
+ MOVO A0, A1; MOVO B0, B1; MOVO C0, C1; MOVO D0, D1; PADDL ·sseIncMask<>(SB), D1
+ MOVO A1, A2; MOVO B1, B2; MOVO C1, C2; MOVO D1, D2; PADDL ·sseIncMask<>(SB), D2
+ MOVO B0, T1; MOVO C0, T2; MOVO D1, T3
+ MOVQ $10, itr2
+
+openSSE128InnerCipherLoop:
+ chachaQR(A0, B0, C0, D0, T0); chachaQR(A1, B1, C1, D1, T0); chachaQR(A2, B2, C2, D2, T0)
+ shiftB0Left; shiftB1Left; shiftB2Left
+ shiftC0Left; shiftC1Left; shiftC2Left
+ shiftD0Left; shiftD1Left; shiftD2Left
+ chachaQR(A0, B0, C0, D0, T0); chachaQR(A1, B1, C1, D1, T0); chachaQR(A2, B2, C2, D2, T0)
+ shiftB0Right; shiftB1Right; shiftB2Right
+ shiftC0Right; shiftC1Right; shiftC2Right
+ shiftD0Right; shiftD1Right; shiftD2Right
+ DECQ itr2
+ JNE openSSE128InnerCipherLoop
+
+ // A0|B0 hold the Poly1305 32-byte key, C0,D0 can be discarded
+ PADDL ·chacha20Constants<>(SB), A0; PADDL ·chacha20Constants<>(SB), A1; PADDL ·chacha20Constants<>(SB), A2
+ PADDL T1, B0; PADDL T1, B1; PADDL T1, B2
+ PADDL T2, C1; PADDL T2, C2
+ PADDL T3, D1; PADDL ·sseIncMask<>(SB), T3; PADDL T3, D2
+
+ // Clamp and store the key
+ PAND ·polyClampMask<>(SB), A0
+ MOVOU A0, rStore; MOVOU B0, sStore
+
+ // Hash
+ MOVQ ad_len+80(FP), itr2
+ CALL polyHashADInternal(SB)
+
+openSSE128Open:
+ CMPQ inl, $16
+ JB openSSETail16
+ SUBQ $16, inl
+
+ // Load for hashing
+ polyAdd(0(inp))
+
+ // Load for decryption
+ MOVOU (inp), T0; PXOR T0, A1; MOVOU A1, (oup)
+ LEAQ (1*16)(inp), inp
+ LEAQ (1*16)(oup), oup
+ polyMul
+
+ // Shift the stream "left"
+ MOVO B1, A1
+ MOVO C1, B1
+ MOVO D1, C1
+ MOVO A2, D1
+ MOVO B2, A2
+ MOVO C2, B2
+ MOVO D2, C2
+ JMP openSSE128Open
+
+openSSETail16:
+ TESTQ inl, inl
+ JE openSSEFinalize
+
+ // We can safely load the CT from the end, because it is padded with the MAC
+ MOVQ inl, itr2
+ SHLQ $4, itr2
+ LEAQ ·andMask<>(SB), t0
+ MOVOU (inp), T0
+ ADDQ inl, inp
+ PAND -16(t0)(itr2*1), T0
+ MOVO T0, 0+tmpStore
+ MOVQ T0, t0
+ MOVQ 8+tmpStore, t1
+ PXOR A1, T0
+
+ // We can only store one byte at a time, since plaintext can be shorter than 16 bytes
+openSSETail16Store:
+ MOVQ T0, t3
+ MOVB t3, (oup)
+ PSRLDQ $1, T0
+ INCQ oup
+ DECQ inl
+ JNE openSSETail16Store
+ ADDQ t0, acc0; ADCQ t1, acc1; ADCQ $1, acc2
+ polyMul
+ JMP openSSEFinalize
+
+// ----------------------------------------------------------------------------
+// Special optimization for the last 64 bytes of ciphertext
+openSSETail64:
+ // Need to decrypt up to 64 bytes - prepare single block
+ MOVO ·chacha20Constants<>(SB), A0; MOVO state1Store, B0; MOVO state2Store, C0; MOVO ctr3Store, D0; PADDL ·sseIncMask<>(SB), D0; MOVO D0, ctr0Store
+ XORQ itr2, itr2
+ MOVQ inl, itr1
+ CMPQ itr1, $16
+ JB openSSETail64LoopB
+
+openSSETail64LoopA:
+ // Perform ChaCha rounds, while hashing the remaining input
+ polyAdd(0(inp)(itr2*1))
+ polyMul
+ SUBQ $16, itr1
+
+openSSETail64LoopB:
+ ADDQ $16, itr2
+ chachaQR(A0, B0, C0, D0, T0)
+ shiftB0Left; shiftC0Left; shiftD0Left
+ chachaQR(A0, B0, C0, D0, T0)
+ shiftB0Right; shiftC0Right; shiftD0Right
+
+ CMPQ itr1, $16
+ JAE openSSETail64LoopA
+
+ CMPQ itr2, $160
+ JNE openSSETail64LoopB
+
+ PADDL ·chacha20Constants<>(SB), A0; PADDL state1Store, B0; PADDL state2Store, C0; PADDL ctr0Store, D0
+
+openSSETail64DecLoop:
+ CMPQ inl, $16
+ JB openSSETail64DecLoopDone
+ SUBQ $16, inl
+ MOVOU (inp), T0
+ PXOR T0, A0
+ MOVOU A0, (oup)
+ LEAQ 16(inp), inp
+ LEAQ 16(oup), oup
+ MOVO B0, A0
+ MOVO C0, B0
+ MOVO D0, C0
+ JMP openSSETail64DecLoop
+
+openSSETail64DecLoopDone:
+ MOVO A0, A1
+ JMP openSSETail16
+
+// ----------------------------------------------------------------------------
+// Special optimization for the last 128 bytes of ciphertext
+openSSETail128:
+ // Need to decrypt up to 128 bytes - prepare two blocks
+ MOVO ·chacha20Constants<>(SB), A1; MOVO state1Store, B1; MOVO state2Store, C1; MOVO ctr3Store, D1; PADDL ·sseIncMask<>(SB), D1; MOVO D1, ctr0Store
+ MOVO A1, A0; MOVO B1, B0; MOVO C1, C0; MOVO D1, D0; PADDL ·sseIncMask<>(SB), D0; MOVO D0, ctr1Store
+ XORQ itr2, itr2
+ MOVQ inl, itr1
+ ANDQ $-16, itr1
+
+openSSETail128LoopA:
+ // Perform ChaCha rounds, while hashing the remaining input
+ polyAdd(0(inp)(itr2*1))
+ polyMul
+
+openSSETail128LoopB:
+ ADDQ $16, itr2
+ chachaQR(A0, B0, C0, D0, T0); chachaQR(A1, B1, C1, D1, T0)
+ shiftB0Left; shiftC0Left; shiftD0Left
+ shiftB1Left; shiftC1Left; shiftD1Left
+ chachaQR(A0, B0, C0, D0, T0); chachaQR(A1, B1, C1, D1, T0)
+ shiftB0Right; shiftC0Right; shiftD0Right
+ shiftB1Right; shiftC1Right; shiftD1Right
+
+ CMPQ itr2, itr1
+ JB openSSETail128LoopA
+
+ CMPQ itr2, $160
+ JNE openSSETail128LoopB
+
+ PADDL ·chacha20Constants<>(SB), A0; PADDL ·chacha20Constants<>(SB), A1
+ PADDL state1Store, B0; PADDL state1Store, B1
+ PADDL state2Store, C0; PADDL state2Store, C1
+ PADDL ctr1Store, D0; PADDL ctr0Store, D1
+
+ MOVOU (0*16)(inp), T0; MOVOU (1*16)(inp), T1; MOVOU (2*16)(inp), T2; MOVOU (3*16)(inp), T3
+ PXOR T0, A1; PXOR T1, B1; PXOR T2, C1; PXOR T3, D1
+ MOVOU A1, (0*16)(oup); MOVOU B1, (1*16)(oup); MOVOU C1, (2*16)(oup); MOVOU D1, (3*16)(oup)
+
+ SUBQ $64, inl
+ LEAQ 64(inp), inp
+ LEAQ 64(oup), oup
+ JMP openSSETail64DecLoop
+
+// ----------------------------------------------------------------------------
+// Special optimization for the last 192 bytes of ciphertext
+openSSETail192:
+ // Need to decrypt up to 192 bytes - prepare three blocks
+ MOVO ·chacha20Constants<>(SB), A2; MOVO state1Store, B2; MOVO state2Store, C2; MOVO ctr3Store, D2; PADDL ·sseIncMask<>(SB), D2; MOVO D2, ctr0Store
+ MOVO A2, A1; MOVO B2, B1; MOVO C2, C1; MOVO D2, D1; PADDL ·sseIncMask<>(SB), D1; MOVO D1, ctr1Store
+ MOVO A1, A0; MOVO B1, B0; MOVO C1, C0; MOVO D1, D0; PADDL ·sseIncMask<>(SB), D0; MOVO D0, ctr2Store
+
+ MOVQ inl, itr1
+ MOVQ $160, itr2
+ CMPQ itr1, $160
+ CMOVQGT itr2, itr1
+ ANDQ $-16, itr1
+ XORQ itr2, itr2
+
+openSSLTail192LoopA:
+ // Perform ChaCha rounds, while hashing the remaining input
+ polyAdd(0(inp)(itr2*1))
+ polyMul
+
+openSSLTail192LoopB:
+ ADDQ $16, itr2
+ chachaQR(A0, B0, C0, D0, T0); chachaQR(A1, B1, C1, D1, T0); chachaQR(A2, B2, C2, D2, T0)
+ shiftB0Left; shiftC0Left; shiftD0Left
+ shiftB1Left; shiftC1Left; shiftD1Left
+ shiftB2Left; shiftC2Left; shiftD2Left
+
+ chachaQR(A0, B0, C0, D0, T0); chachaQR(A1, B1, C1, D1, T0); chachaQR(A2, B2, C2, D2, T0)
+ shiftB0Right; shiftC0Right; shiftD0Right
+ shiftB1Right; shiftC1Right; shiftD1Right
+ shiftB2Right; shiftC2Right; shiftD2Right
+
+ CMPQ itr2, itr1
+ JB openSSLTail192LoopA
+
+ CMPQ itr2, $160
+ JNE openSSLTail192LoopB
+
+ CMPQ inl, $176
+ JB openSSLTail192Store
+
+ polyAdd(160(inp))
+ polyMul
+
+ CMPQ inl, $192
+ JB openSSLTail192Store
+
+ polyAdd(176(inp))
+ polyMul
+
+openSSLTail192Store:
+ PADDL ·chacha20Constants<>(SB), A0; PADDL ·chacha20Constants<>(SB), A1; PADDL ·chacha20Constants<>(SB), A2
+ PADDL state1Store, B0; PADDL state1Store, B1; PADDL state1Store, B2
+ PADDL state2Store, C0; PADDL state2Store, C1; PADDL state2Store, C2
+ PADDL ctr2Store, D0; PADDL ctr1Store, D1; PADDL ctr0Store, D2
+
+ MOVOU (0*16)(inp), T0; MOVOU (1*16)(inp), T1; MOVOU (2*16)(inp), T2; MOVOU (3*16)(inp), T3
+ PXOR T0, A2; PXOR T1, B2; PXOR T2, C2; PXOR T3, D2
+ MOVOU A2, (0*16)(oup); MOVOU B2, (1*16)(oup); MOVOU C2, (2*16)(oup); MOVOU D2, (3*16)(oup)
+
+ MOVOU (4*16)(inp), T0; MOVOU (5*16)(inp), T1; MOVOU (6*16)(inp), T2; MOVOU (7*16)(inp), T3
+ PXOR T0, A1; PXOR T1, B1; PXOR T2, C1; PXOR T3, D1
+ MOVOU A1, (4*16)(oup); MOVOU B1, (5*16)(oup); MOVOU C1, (6*16)(oup); MOVOU D1, (7*16)(oup)
+
+ SUBQ $128, inl
+ LEAQ 128(inp), inp
+ LEAQ 128(oup), oup
+ JMP openSSETail64DecLoop
+
+// ----------------------------------------------------------------------------
+// Special optimization for the last 256 bytes of ciphertext
+openSSETail256:
+ // Need to decrypt up to 256 bytes - prepare four blocks
+ MOVO ·chacha20Constants<>(SB), A0; MOVO state1Store, B0; MOVO state2Store, C0; MOVO ctr3Store, D0; PADDL ·sseIncMask<>(SB), D0
+ MOVO A0, A1; MOVO B0, B1; MOVO C0, C1; MOVO D0, D1; PADDL ·sseIncMask<>(SB), D1
+ MOVO A1, A2; MOVO B1, B2; MOVO C1, C2; MOVO D1, D2; PADDL ·sseIncMask<>(SB), D2
+ MOVO A2, A3; MOVO B2, B3; MOVO C2, C3; MOVO D2, D3; PADDL ·sseIncMask<>(SB), D3
+
+ // Store counters
+ MOVO D0, ctr0Store; MOVO D1, ctr1Store; MOVO D2, ctr2Store; MOVO D3, ctr3Store
+ XORQ itr2, itr2
+
+openSSETail256Loop:
+ // This loop inteleaves 8 ChaCha quarter rounds with 1 poly multiplication
+ polyAdd(0(inp)(itr2*1))
+ MOVO C3, tmpStore
+ chachaQR(A0, B0, C0, D0, C3); chachaQR(A1, B1, C1, D1, C3); chachaQR(A2, B2, C2, D2, C3)
+ MOVO tmpStore, C3
+ MOVO C1, tmpStore
+ chachaQR(A3, B3, C3, D3, C1)
+ MOVO tmpStore, C1
+ shiftB0Left; shiftB1Left; shiftB2Left; shiftB3Left
+ shiftC0Left; shiftC1Left; shiftC2Left; shiftC3Left
+ shiftD0Left; shiftD1Left; shiftD2Left; shiftD3Left
+ polyMulStage1
+ polyMulStage2
+ MOVO C3, tmpStore
+ chachaQR(A0, B0, C0, D0, C3); chachaQR(A1, B1, C1, D1, C3); chachaQR(A2, B2, C2, D2, C3)
+ MOVO tmpStore, C3
+ MOVO C1, tmpStore
+ chachaQR(A3, B3, C3, D3, C1)
+ MOVO tmpStore, C1
+ polyMulStage3
+ polyMulReduceStage
+ shiftB0Right; shiftB1Right; shiftB2Right; shiftB3Right
+ shiftC0Right; shiftC1Right; shiftC2Right; shiftC3Right
+ shiftD0Right; shiftD1Right; shiftD2Right; shiftD3Right
+ ADDQ $2*8, itr2
+ CMPQ itr2, $160
+ JB openSSETail256Loop
+ MOVQ inl, itr1
+ ANDQ $-16, itr1
+
+openSSETail256HashLoop:
+ polyAdd(0(inp)(itr2*1))
+ polyMul
+ ADDQ $2*8, itr2
+ CMPQ itr2, itr1
+ JB openSSETail256HashLoop
+
+ // Add in the state
+ PADDD ·chacha20Constants<>(SB), A0; PADDD ·chacha20Constants<>(SB), A1; PADDD ·chacha20Constants<>(SB), A2; PADDD ·chacha20Constants<>(SB), A3
+ PADDD state1Store, B0; PADDD state1Store, B1; PADDD state1Store, B2; PADDD state1Store, B3
+ PADDD state2Store, C0; PADDD state2Store, C1; PADDD state2Store, C2; PADDD state2Store, C3
+ PADDD ctr0Store, D0; PADDD ctr1Store, D1; PADDD ctr2Store, D2; PADDD ctr3Store, D3
+ MOVO D3, tmpStore
+
+ // Load - xor - store
+ MOVOU (0*16)(inp), D3; PXOR D3, A0
+ MOVOU (1*16)(inp), D3; PXOR D3, B0
+ MOVOU (2*16)(inp), D3; PXOR D3, C0
+ MOVOU (3*16)(inp), D3; PXOR D3, D0
+ MOVOU A0, (0*16)(oup)
+ MOVOU B0, (1*16)(oup)
+ MOVOU C0, (2*16)(oup)
+ MOVOU D0, (3*16)(oup)
+ MOVOU (4*16)(inp), A0; MOVOU (5*16)(inp), B0; MOVOU (6*16)(inp), C0; MOVOU (7*16)(inp), D0
+ PXOR A0, A1; PXOR B0, B1; PXOR C0, C1; PXOR D0, D1
+ MOVOU A1, (4*16)(oup); MOVOU B1, (5*16)(oup); MOVOU C1, (6*16)(oup); MOVOU D1, (7*16)(oup)
+ MOVOU (8*16)(inp), A0; MOVOU (9*16)(inp), B0; MOVOU (10*16)(inp), C0; MOVOU (11*16)(inp), D0
+ PXOR A0, A2; PXOR B0, B2; PXOR C0, C2; PXOR D0, D2
+ MOVOU A2, (8*16)(oup); MOVOU B2, (9*16)(oup); MOVOU C2, (10*16)(oup); MOVOU D2, (11*16)(oup)
+ LEAQ 192(inp), inp
+ LEAQ 192(oup), oup
+ SUBQ $192, inl
+ MOVO A3, A0
+ MOVO B3, B0
+ MOVO C3, C0
+ MOVO tmpStore, D0
+
+ JMP openSSETail64DecLoop
+
+// ----------------------------------------------------------------------------
+// ------------------------- AVX2 Code ----------------------------------------
+chacha20Poly1305Open_AVX2:
+ VZEROUPPER
+ VMOVDQU ·chacha20Constants<>(SB), AA0
+ BYTE $0xc4; BYTE $0x42; BYTE $0x7d; BYTE $0x5a; BYTE $0x70; BYTE $0x10 // broadcasti128 16(r8), ymm14
+ BYTE $0xc4; BYTE $0x42; BYTE $0x7d; BYTE $0x5a; BYTE $0x60; BYTE $0x20 // broadcasti128 32(r8), ymm12
+ BYTE $0xc4; BYTE $0xc2; BYTE $0x7d; BYTE $0x5a; BYTE $0x60; BYTE $0x30 // broadcasti128 48(r8), ymm4
+ VPADDD ·avx2InitMask<>(SB), DD0, DD0
+
+ // Special optimization, for very short buffers
+ CMPQ inl, $192
+ JBE openAVX2192
+ CMPQ inl, $320
+ JBE openAVX2320
+
+ // For the general key prepare the key first - as a byproduct we have 64 bytes of cipher stream
+ VMOVDQA BB0, state1StoreAVX2
+ VMOVDQA CC0, state2StoreAVX2
+ VMOVDQA DD0, ctr3StoreAVX2
+ MOVQ $10, itr2
+
+openAVX2PreparePolyKey:
+ chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0)
+ VPALIGNR $4, BB0, BB0, BB0; VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $12, DD0, DD0, DD0
+ chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0)
+ VPALIGNR $12, BB0, BB0, BB0; VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $4, DD0, DD0, DD0
+ DECQ itr2
+ JNE openAVX2PreparePolyKey
+
+ VPADDD ·chacha20Constants<>(SB), AA0, AA0
+ VPADDD state1StoreAVX2, BB0, BB0
+ VPADDD state2StoreAVX2, CC0, CC0
+ VPADDD ctr3StoreAVX2, DD0, DD0
+
+ VPERM2I128 $0x02, AA0, BB0, TT0
+
+ // Clamp and store poly key
+ VPAND ·polyClampMask<>(SB), TT0, TT0
+ VMOVDQA TT0, rsStoreAVX2
+
+ // Stream for the first 64 bytes
+ VPERM2I128 $0x13, AA0, BB0, AA0
+ VPERM2I128 $0x13, CC0, DD0, BB0
+
+ // Hash AD + first 64 bytes
+ MOVQ ad_len+80(FP), itr2
+ CALL polyHashADInternal(SB)
+ XORQ itr1, itr1
+
+openAVX2InitialHash64:
+ polyAdd(0(inp)(itr1*1))
+ polyMulAVX2
+ ADDQ $16, itr1
+ CMPQ itr1, $64
+ JNE openAVX2InitialHash64
+
+ // Decrypt the first 64 bytes
+ VPXOR (0*32)(inp), AA0, AA0
+ VPXOR (1*32)(inp), BB0, BB0
+ VMOVDQU AA0, (0*32)(oup)
+ VMOVDQU BB0, (1*32)(oup)
+ LEAQ (2*32)(inp), inp
+ LEAQ (2*32)(oup), oup
+ SUBQ $64, inl
+
+openAVX2MainLoop:
+ CMPQ inl, $512
+ JB openAVX2MainLoopDone
+
+ // Load state, increment counter blocks, store the incremented counters
+ VMOVDQU ·chacha20Constants<>(SB), AA0; VMOVDQA AA0, AA1; VMOVDQA AA0, AA2; VMOVDQA AA0, AA3
+ VMOVDQA state1StoreAVX2, BB0; VMOVDQA BB0, BB1; VMOVDQA BB0, BB2; VMOVDQA BB0, BB3
+ VMOVDQA state2StoreAVX2, CC0; VMOVDQA CC0, CC1; VMOVDQA CC0, CC2; VMOVDQA CC0, CC3
+ VMOVDQA ctr3StoreAVX2, DD0; VPADDD ·avx2IncMask<>(SB), DD0, DD0; VPADDD ·avx2IncMask<>(SB), DD0, DD1; VPADDD ·avx2IncMask<>(SB), DD1, DD2; VPADDD ·avx2IncMask<>(SB), DD2, DD3
+ VMOVDQA DD0, ctr0StoreAVX2; VMOVDQA DD1, ctr1StoreAVX2; VMOVDQA DD2, ctr2StoreAVX2; VMOVDQA DD3, ctr3StoreAVX2
+ XORQ itr1, itr1
+
+openAVX2InternalLoop:
+ // Lets just say this spaghetti loop interleaves 2 quarter rounds with 3 poly multiplications
+ // Effectively per 512 bytes of stream we hash 480 bytes of ciphertext
+ polyAdd(0*8(inp)(itr1*1))
+ VPADDD BB0, AA0, AA0; VPADDD BB1, AA1, AA1; VPADDD BB2, AA2, AA2; VPADDD BB3, AA3, AA3
+ polyMulStage1_AVX2
+ VPXOR AA0, DD0, DD0; VPXOR AA1, DD1, DD1; VPXOR AA2, DD2, DD2; VPXOR AA3, DD3, DD3
+ VPSHUFB ·rol16<>(SB), DD0, DD0; VPSHUFB ·rol16<>(SB), DD1, DD1; VPSHUFB ·rol16<>(SB), DD2, DD2; VPSHUFB ·rol16<>(SB), DD3, DD3
+ polyMulStage2_AVX2
+ VPADDD DD0, CC0, CC0; VPADDD DD1, CC1, CC1; VPADDD DD2, CC2, CC2; VPADDD DD3, CC3, CC3
+ VPXOR CC0, BB0, BB0; VPXOR CC1, BB1, BB1; VPXOR CC2, BB2, BB2; VPXOR CC3, BB3, BB3
+ polyMulStage3_AVX2
+ VMOVDQA CC3, tmpStoreAVX2
+ VPSLLD $12, BB0, CC3; VPSRLD $20, BB0, BB0; VPXOR CC3, BB0, BB0
+ VPSLLD $12, BB1, CC3; VPSRLD $20, BB1, BB1; VPXOR CC3, BB1, BB1
+ VPSLLD $12, BB2, CC3; VPSRLD $20, BB2, BB2; VPXOR CC3, BB2, BB2
+ VPSLLD $12, BB3, CC3; VPSRLD $20, BB3, BB3; VPXOR CC3, BB3, BB3
+ VMOVDQA tmpStoreAVX2, CC3
+ polyMulReduceStage
+ VPADDD BB0, AA0, AA0; VPADDD BB1, AA1, AA1; VPADDD BB2, AA2, AA2; VPADDD BB3, AA3, AA3
+ VPXOR AA0, DD0, DD0; VPXOR AA1, DD1, DD1; VPXOR AA2, DD2, DD2; VPXOR AA3, DD3, DD3
+ VPSHUFB ·rol8<>(SB), DD0, DD0; VPSHUFB ·rol8<>(SB), DD1, DD1; VPSHUFB ·rol8<>(SB), DD2, DD2; VPSHUFB ·rol8<>(SB), DD3, DD3
+ polyAdd(2*8(inp)(itr1*1))
+ VPADDD DD0, CC0, CC0; VPADDD DD1, CC1, CC1; VPADDD DD2, CC2, CC2; VPADDD DD3, CC3, CC3
+ polyMulStage1_AVX2
+ VPXOR CC0, BB0, BB0; VPXOR CC1, BB1, BB1; VPXOR CC2, BB2, BB2; VPXOR CC3, BB3, BB3
+ VMOVDQA CC3, tmpStoreAVX2
+ VPSLLD $7, BB0, CC3; VPSRLD $25, BB0, BB0; VPXOR CC3, BB0, BB0
+ VPSLLD $7, BB1, CC3; VPSRLD $25, BB1, BB1; VPXOR CC3, BB1, BB1
+ VPSLLD $7, BB2, CC3; VPSRLD $25, BB2, BB2; VPXOR CC3, BB2, BB2
+ VPSLLD $7, BB3, CC3; VPSRLD $25, BB3, BB3; VPXOR CC3, BB3, BB3
+ VMOVDQA tmpStoreAVX2, CC3
+ polyMulStage2_AVX2
+ VPALIGNR $4, BB0, BB0, BB0; VPALIGNR $4, BB1, BB1, BB1; VPALIGNR $4, BB2, BB2, BB2; VPALIGNR $4, BB3, BB3, BB3
+ VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1; VPALIGNR $8, CC2, CC2, CC2; VPALIGNR $8, CC3, CC3, CC3
+ VPALIGNR $12, DD0, DD0, DD0; VPALIGNR $12, DD1, DD1, DD1; VPALIGNR $12, DD2, DD2, DD2; VPALIGNR $12, DD3, DD3, DD3
+ VPADDD BB0, AA0, AA0; VPADDD BB1, AA1, AA1; VPADDD BB2, AA2, AA2; VPADDD BB3, AA3, AA3
+ polyMulStage3_AVX2
+ VPXOR AA0, DD0, DD0; VPXOR AA1, DD1, DD1; VPXOR AA2, DD2, DD2; VPXOR AA3, DD3, DD3
+ VPSHUFB ·rol16<>(SB), DD0, DD0; VPSHUFB ·rol16<>(SB), DD1, DD1; VPSHUFB ·rol16<>(SB), DD2, DD2; VPSHUFB ·rol16<>(SB), DD3, DD3
+ polyMulReduceStage
+ VPADDD DD0, CC0, CC0; VPADDD DD1, CC1, CC1; VPADDD DD2, CC2, CC2; VPADDD DD3, CC3, CC3
+ VPXOR CC0, BB0, BB0; VPXOR CC1, BB1, BB1; VPXOR CC2, BB2, BB2; VPXOR CC3, BB3, BB3
+ polyAdd(4*8(inp)(itr1*1))
+ LEAQ (6*8)(itr1), itr1
+ VMOVDQA CC3, tmpStoreAVX2
+ VPSLLD $12, BB0, CC3; VPSRLD $20, BB0, BB0; VPXOR CC3, BB0, BB0
+ VPSLLD $12, BB1, CC3; VPSRLD $20, BB1, BB1; VPXOR CC3, BB1, BB1
+ VPSLLD $12, BB2, CC3; VPSRLD $20, BB2, BB2; VPXOR CC3, BB2, BB2
+ VPSLLD $12, BB3, CC3; VPSRLD $20, BB3, BB3; VPXOR CC3, BB3, BB3
+ VMOVDQA tmpStoreAVX2, CC3
+ polyMulStage1_AVX2
+ VPADDD BB0, AA0, AA0; VPADDD BB1, AA1, AA1; VPADDD BB2, AA2, AA2; VPADDD BB3, AA3, AA3
+ VPXOR AA0, DD0, DD0; VPXOR AA1, DD1, DD1; VPXOR AA2, DD2, DD2; VPXOR AA3, DD3, DD3
+ polyMulStage2_AVX2
+ VPSHUFB ·rol8<>(SB), DD0, DD0; VPSHUFB ·rol8<>(SB), DD1, DD1; VPSHUFB ·rol8<>(SB), DD2, DD2; VPSHUFB ·rol8<>(SB), DD3, DD3
+ VPADDD DD0, CC0, CC0; VPADDD DD1, CC1, CC1; VPADDD DD2, CC2, CC2; VPADDD DD3, CC3, CC3
+ polyMulStage3_AVX2
+ VPXOR CC0, BB0, BB0; VPXOR CC1, BB1, BB1; VPXOR CC2, BB2, BB2; VPXOR CC3, BB3, BB3
+ VMOVDQA CC3, tmpStoreAVX2
+ VPSLLD $7, BB0, CC3; VPSRLD $25, BB0, BB0; VPXOR CC3, BB0, BB0
+ VPSLLD $7, BB1, CC3; VPSRLD $25, BB1, BB1; VPXOR CC3, BB1, BB1
+ VPSLLD $7, BB2, CC3; VPSRLD $25, BB2, BB2; VPXOR CC3, BB2, BB2
+ VPSLLD $7, BB3, CC3; VPSRLD $25, BB3, BB3; VPXOR CC3, BB3, BB3
+ VMOVDQA tmpStoreAVX2, CC3
+ polyMulReduceStage
+ VPALIGNR $12, BB0, BB0, BB0; VPALIGNR $12, BB1, BB1, BB1; VPALIGNR $12, BB2, BB2, BB2; VPALIGNR $12, BB3, BB3, BB3
+ VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1; VPALIGNR $8, CC2, CC2, CC2; VPALIGNR $8, CC3, CC3, CC3
+ VPALIGNR $4, DD0, DD0, DD0; VPALIGNR $4, DD1, DD1, DD1; VPALIGNR $4, DD2, DD2, DD2; VPALIGNR $4, DD3, DD3, DD3
+ CMPQ itr1, $480
+ JNE openAVX2InternalLoop
+
+ VPADDD ·chacha20Constants<>(SB), AA0, AA0; VPADDD ·chacha20Constants<>(SB), AA1, AA1; VPADDD ·chacha20Constants<>(SB), AA2, AA2; VPADDD ·chacha20Constants<>(SB), AA3, AA3
+ VPADDD state1StoreAVX2, BB0, BB0; VPADDD state1StoreAVX2, BB1, BB1; VPADDD state1StoreAVX2, BB2, BB2; VPADDD state1StoreAVX2, BB3, BB3
+ VPADDD state2StoreAVX2, CC0, CC0; VPADDD state2StoreAVX2, CC1, CC1; VPADDD state2StoreAVX2, CC2, CC2; VPADDD state2StoreAVX2, CC3, CC3
+ VPADDD ctr0StoreAVX2, DD0, DD0; VPADDD ctr1StoreAVX2, DD1, DD1; VPADDD ctr2StoreAVX2, DD2, DD2; VPADDD ctr3StoreAVX2, DD3, DD3
+ VMOVDQA CC3, tmpStoreAVX2
+
+ // We only hashed 480 of the 512 bytes available - hash the remaining 32 here
+ polyAdd(480(inp))
+ polyMulAVX2
+ VPERM2I128 $0x02, AA0, BB0, CC3; VPERM2I128 $0x13, AA0, BB0, BB0; VPERM2I128 $0x02, CC0, DD0, AA0; VPERM2I128 $0x13, CC0, DD0, CC0
+ VPXOR (0*32)(inp), CC3, CC3; VPXOR (1*32)(inp), AA0, AA0; VPXOR (2*32)(inp), BB0, BB0; VPXOR (3*32)(inp), CC0, CC0
+ VMOVDQU CC3, (0*32)(oup); VMOVDQU AA0, (1*32)(oup); VMOVDQU BB0, (2*32)(oup); VMOVDQU CC0, (3*32)(oup)
+ VPERM2I128 $0x02, AA1, BB1, AA0; VPERM2I128 $0x02, CC1, DD1, BB0; VPERM2I128 $0x13, AA1, BB1, CC0; VPERM2I128 $0x13, CC1, DD1, DD0
+ VPXOR (4*32)(inp), AA0, AA0; VPXOR (5*32)(inp), BB0, BB0; VPXOR (6*32)(inp), CC0, CC0; VPXOR (7*32)(inp), DD0, DD0
+ VMOVDQU AA0, (4*32)(oup); VMOVDQU BB0, (5*32)(oup); VMOVDQU CC0, (6*32)(oup); VMOVDQU DD0, (7*32)(oup)
+
+ // and here
+ polyAdd(496(inp))
+ polyMulAVX2
+ VPERM2I128 $0x02, AA2, BB2, AA0; VPERM2I128 $0x02, CC2, DD2, BB0; VPERM2I128 $0x13, AA2, BB2, CC0; VPERM2I128 $0x13, CC2, DD2, DD0
+ VPXOR (8*32)(inp), AA0, AA0; VPXOR (9*32)(inp), BB0, BB0; VPXOR (10*32)(inp), CC0, CC0; VPXOR (11*32)(inp), DD0, DD0
+ VMOVDQU AA0, (8*32)(oup); VMOVDQU BB0, (9*32)(oup); VMOVDQU CC0, (10*32)(oup); VMOVDQU DD0, (11*32)(oup)
+ VPERM2I128 $0x02, AA3, BB3, AA0; VPERM2I128 $0x02, tmpStoreAVX2, DD3, BB0; VPERM2I128 $0x13, AA3, BB3, CC0; VPERM2I128 $0x13, tmpStoreAVX2, DD3, DD0
+ VPXOR (12*32)(inp), AA0, AA0; VPXOR (13*32)(inp), BB0, BB0; VPXOR (14*32)(inp), CC0, CC0; VPXOR (15*32)(inp), DD0, DD0
+ VMOVDQU AA0, (12*32)(oup); VMOVDQU BB0, (13*32)(oup); VMOVDQU CC0, (14*32)(oup); VMOVDQU DD0, (15*32)(oup)
+ LEAQ (32*16)(inp), inp
+ LEAQ (32*16)(oup), oup
+ SUBQ $(32*16), inl
+ JMP openAVX2MainLoop
+
+openAVX2MainLoopDone:
+ // Handle the various tail sizes efficiently
+ TESTQ inl, inl
+ JE openSSEFinalize
+ CMPQ inl, $128
+ JBE openAVX2Tail128
+ CMPQ inl, $256
+ JBE openAVX2Tail256
+ CMPQ inl, $384
+ JBE openAVX2Tail384
+ JMP openAVX2Tail512
+
+// ----------------------------------------------------------------------------
+// Special optimization for buffers smaller than 193 bytes
+openAVX2192:
+ // For up to 192 bytes of ciphertext and 64 bytes for the poly key, we process four blocks
+ VMOVDQA AA0, AA1
+ VMOVDQA BB0, BB1
+ VMOVDQA CC0, CC1
+ VPADDD ·avx2IncMask<>(SB), DD0, DD1
+ VMOVDQA AA0, AA2
+ VMOVDQA BB0, BB2
+ VMOVDQA CC0, CC2
+ VMOVDQA DD0, DD2
+ VMOVDQA DD1, TT3
+ MOVQ $10, itr2
+
+openAVX2192InnerCipherLoop:
+ chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0); chachaQR_AVX2(AA1, BB1, CC1, DD1, TT0)
+ VPALIGNR $4, BB0, BB0, BB0; VPALIGNR $4, BB1, BB1, BB1
+ VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1
+ VPALIGNR $12, DD0, DD0, DD0; VPALIGNR $12, DD1, DD1, DD1
+ chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0); chachaQR_AVX2(AA1, BB1, CC1, DD1, TT0)
+ VPALIGNR $12, BB0, BB0, BB0; VPALIGNR $12, BB1, BB1, BB1
+ VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1
+ VPALIGNR $4, DD0, DD0, DD0; VPALIGNR $4, DD1, DD1, DD1
+ DECQ itr2
+ JNE openAVX2192InnerCipherLoop
+ VPADDD AA2, AA0, AA0; VPADDD AA2, AA1, AA1
+ VPADDD BB2, BB0, BB0; VPADDD BB2, BB1, BB1
+ VPADDD CC2, CC0, CC0; VPADDD CC2, CC1, CC1
+ VPADDD DD2, DD0, DD0; VPADDD TT3, DD1, DD1
+ VPERM2I128 $0x02, AA0, BB0, TT0
+
+ // Clamp and store poly key
+ VPAND ·polyClampMask<>(SB), TT0, TT0
+ VMOVDQA TT0, rsStoreAVX2
+
+ // Stream for up to 192 bytes
+ VPERM2I128 $0x13, AA0, BB0, AA0
+ VPERM2I128 $0x13, CC0, DD0, BB0
+ VPERM2I128 $0x02, AA1, BB1, CC0
+ VPERM2I128 $0x02, CC1, DD1, DD0
+ VPERM2I128 $0x13, AA1, BB1, AA1
+ VPERM2I128 $0x13, CC1, DD1, BB1
+
+openAVX2ShortOpen:
+ // Hash
+ MOVQ ad_len+80(FP), itr2
+ CALL polyHashADInternal(SB)
+
+openAVX2ShortOpenLoop:
+ CMPQ inl, $32
+ JB openAVX2ShortTail32
+ SUBQ $32, inl
+
+ // Load for hashing
+ polyAdd(0*8(inp))
+ polyMulAVX2
+ polyAdd(2*8(inp))
+ polyMulAVX2
+
+ // Load for decryption
+ VPXOR (inp), AA0, AA0
+ VMOVDQU AA0, (oup)
+ LEAQ (1*32)(inp), inp
+ LEAQ (1*32)(oup), oup
+
+ // Shift stream left
+ VMOVDQA BB0, AA0
+ VMOVDQA CC0, BB0
+ VMOVDQA DD0, CC0
+ VMOVDQA AA1, DD0
+ VMOVDQA BB1, AA1
+ VMOVDQA CC1, BB1
+ VMOVDQA DD1, CC1
+ VMOVDQA AA2, DD1
+ VMOVDQA BB2, AA2
+ JMP openAVX2ShortOpenLoop
+
+openAVX2ShortTail32:
+ CMPQ inl, $16
+ VMOVDQA A0, A1
+ JB openAVX2ShortDone
+
+ SUBQ $16, inl
+
+ // Load for hashing
+ polyAdd(0*8(inp))
+ polyMulAVX2
+
+ // Load for decryption
+ VPXOR (inp), A0, T0
+ VMOVDQU T0, (oup)
+ LEAQ (1*16)(inp), inp
+ LEAQ (1*16)(oup), oup
+ VPERM2I128 $0x11, AA0, AA0, AA0
+ VMOVDQA A0, A1
+
+openAVX2ShortDone:
+ VZEROUPPER
+ JMP openSSETail16
+
+// ----------------------------------------------------------------------------
+// Special optimization for buffers smaller than 321 bytes
+openAVX2320:
+ // For up to 320 bytes of ciphertext and 64 bytes for the poly key, we process six blocks
+ VMOVDQA AA0, AA1; VMOVDQA BB0, BB1; VMOVDQA CC0, CC1; VPADDD ·avx2IncMask<>(SB), DD0, DD1
+ VMOVDQA AA0, AA2; VMOVDQA BB0, BB2; VMOVDQA CC0, CC2; VPADDD ·avx2IncMask<>(SB), DD1, DD2
+ VMOVDQA BB0, TT1; VMOVDQA CC0, TT2; VMOVDQA DD0, TT3
+ MOVQ $10, itr2
+
+openAVX2320InnerCipherLoop:
+ chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0); chachaQR_AVX2(AA1, BB1, CC1, DD1, TT0); chachaQR_AVX2(AA2, BB2, CC2, DD2, TT0)
+ VPALIGNR $4, BB0, BB0, BB0; VPALIGNR $4, BB1, BB1, BB1; VPALIGNR $4, BB2, BB2, BB2
+ VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1; VPALIGNR $8, CC2, CC2, CC2
+ VPALIGNR $12, DD0, DD0, DD0; VPALIGNR $12, DD1, DD1, DD1; VPALIGNR $12, DD2, DD2, DD2
+ chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0); chachaQR_AVX2(AA1, BB1, CC1, DD1, TT0); chachaQR_AVX2(AA2, BB2, CC2, DD2, TT0)
+ VPALIGNR $12, BB0, BB0, BB0; VPALIGNR $12, BB1, BB1, BB1; VPALIGNR $12, BB2, BB2, BB2
+ VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1; VPALIGNR $8, CC2, CC2, CC2
+ VPALIGNR $4, DD0, DD0, DD0; VPALIGNR $4, DD1, DD1, DD1; VPALIGNR $4, DD2, DD2, DD2
+ DECQ itr2
+ JNE openAVX2320InnerCipherLoop
+
+ VMOVDQA ·chacha20Constants<>(SB), TT0
+ VPADDD TT0, AA0, AA0; VPADDD TT0, AA1, AA1; VPADDD TT0, AA2, AA2
+ VPADDD TT1, BB0, BB0; VPADDD TT1, BB1, BB1; VPADDD TT1, BB2, BB2
+ VPADDD TT2, CC0, CC0; VPADDD TT2, CC1, CC1; VPADDD TT2, CC2, CC2
+ VMOVDQA ·avx2IncMask<>(SB), TT0
+ VPADDD TT3, DD0, DD0; VPADDD TT0, TT3, TT3
+ VPADDD TT3, DD1, DD1; VPADDD TT0, TT3, TT3
+ VPADDD TT3, DD2, DD2
+
+ // Clamp and store poly key
+ VPERM2I128 $0x02, AA0, BB0, TT0
+ VPAND ·polyClampMask<>(SB), TT0, TT0
+ VMOVDQA TT0, rsStoreAVX2
+
+ // Stream for up to 320 bytes
+ VPERM2I128 $0x13, AA0, BB0, AA0
+ VPERM2I128 $0x13, CC0, DD0, BB0
+ VPERM2I128 $0x02, AA1, BB1, CC0
+ VPERM2I128 $0x02, CC1, DD1, DD0
+ VPERM2I128 $0x13, AA1, BB1, AA1
+ VPERM2I128 $0x13, CC1, DD1, BB1
+ VPERM2I128 $0x02, AA2, BB2, CC1
+ VPERM2I128 $0x02, CC2, DD2, DD1
+ VPERM2I128 $0x13, AA2, BB2, AA2
+ VPERM2I128 $0x13, CC2, DD2, BB2
+ JMP openAVX2ShortOpen
+
+// ----------------------------------------------------------------------------
+// Special optimization for the last 128 bytes of ciphertext
+openAVX2Tail128:
+ // Need to decrypt up to 128 bytes - prepare two blocks
+ VMOVDQA ·chacha20Constants<>(SB), AA1
+ VMOVDQA state1StoreAVX2, BB1
+ VMOVDQA state2StoreAVX2, CC1
+ VMOVDQA ctr3StoreAVX2, DD1
+ VPADDD ·avx2IncMask<>(SB), DD1, DD1
+ VMOVDQA DD1, DD0
+
+ XORQ itr2, itr2
+ MOVQ inl, itr1
+ ANDQ $-16, itr1
+ TESTQ itr1, itr1
+ JE openAVX2Tail128LoopB
+
+openAVX2Tail128LoopA:
+ // Perform ChaCha rounds, while hashing the remaining input
+ polyAdd(0(inp)(itr2*1))
+ polyMulAVX2
+
+openAVX2Tail128LoopB:
+ ADDQ $16, itr2
+ chachaQR_AVX2(AA1, BB1, CC1, DD1, TT0)
+ VPALIGNR $4, BB1, BB1, BB1
+ VPALIGNR $8, CC1, CC1, CC1
+ VPALIGNR $12, DD1, DD1, DD1
+ chachaQR_AVX2(AA1, BB1, CC1, DD1, TT0)
+ VPALIGNR $12, BB1, BB1, BB1
+ VPALIGNR $8, CC1, CC1, CC1
+ VPALIGNR $4, DD1, DD1, DD1
+ CMPQ itr2, itr1
+ JB openAVX2Tail128LoopA
+ CMPQ itr2, $160
+ JNE openAVX2Tail128LoopB
+
+ VPADDD ·chacha20Constants<>(SB), AA1, AA1
+ VPADDD state1StoreAVX2, BB1, BB1
+ VPADDD state2StoreAVX2, CC1, CC1
+ VPADDD DD0, DD1, DD1
+ VPERM2I128 $0x02, AA1, BB1, AA0; VPERM2I128 $0x02, CC1, DD1, BB0; VPERM2I128 $0x13, AA1, BB1, CC0; VPERM2I128 $0x13, CC1, DD1, DD0
+
+openAVX2TailLoop:
+ CMPQ inl, $32
+ JB openAVX2Tail
+ SUBQ $32, inl
+
+ // Load for decryption
+ VPXOR (inp), AA0, AA0
+ VMOVDQU AA0, (oup)
+ LEAQ (1*32)(inp), inp
+ LEAQ (1*32)(oup), oup
+ VMOVDQA BB0, AA0
+ VMOVDQA CC0, BB0
+ VMOVDQA DD0, CC0
+ JMP openAVX2TailLoop
+
+openAVX2Tail:
+ CMPQ inl, $16
+ VMOVDQA A0, A1
+ JB openAVX2TailDone
+ SUBQ $16, inl
+
+ // Load for decryption
+ VPXOR (inp), A0, T0
+ VMOVDQU T0, (oup)
+ LEAQ (1*16)(inp), inp
+ LEAQ (1*16)(oup), oup
+ VPERM2I128 $0x11, AA0, AA0, AA0
+ VMOVDQA A0, A1
+
+openAVX2TailDone:
+ VZEROUPPER
+ JMP openSSETail16
+
+// ----------------------------------------------------------------------------
+// Special optimization for the last 256 bytes of ciphertext
+openAVX2Tail256:
+ // Need to decrypt up to 256 bytes - prepare four blocks
+ VMOVDQA ·chacha20Constants<>(SB), AA0; VMOVDQA AA0, AA1
+ VMOVDQA state1StoreAVX2, BB0; VMOVDQA BB0, BB1
+ VMOVDQA state2StoreAVX2, CC0; VMOVDQA CC0, CC1
+ VMOVDQA ctr3StoreAVX2, DD0
+ VPADDD ·avx2IncMask<>(SB), DD0, DD0
+ VPADDD ·avx2IncMask<>(SB), DD0, DD1
+ VMOVDQA DD0, TT1
+ VMOVDQA DD1, TT2
+
+ // Compute the number of iterations that will hash data
+ MOVQ inl, tmpStoreAVX2
+ MOVQ inl, itr1
+ SUBQ $128, itr1
+ SHRQ $4, itr1
+ MOVQ $10, itr2
+ CMPQ itr1, $10
+ CMOVQGT itr2, itr1
+ MOVQ inp, inl
+ XORQ itr2, itr2
+
+openAVX2Tail256LoopA:
+ polyAdd(0(inl))
+ polyMulAVX2
+ LEAQ 16(inl), inl
+
+ // Perform ChaCha rounds, while hashing the remaining input
+openAVX2Tail256LoopB:
+ chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0); chachaQR_AVX2(AA1, BB1, CC1, DD1, TT0)
+ VPALIGNR $4, BB0, BB0, BB0; VPALIGNR $4, BB1, BB1, BB1
+ VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1
+ VPALIGNR $12, DD0, DD0, DD0; VPALIGNR $12, DD1, DD1, DD1
+ INCQ itr2
+ chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0); chachaQR_AVX2(AA1, BB1, CC1, DD1, TT0)
+ VPALIGNR $12, BB0, BB0, BB0; VPALIGNR $12, BB1, BB1, BB1
+ VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1
+ VPALIGNR $4, DD0, DD0, DD0; VPALIGNR $4, DD1, DD1, DD1
+ CMPQ itr2, itr1
+ JB openAVX2Tail256LoopA
+
+ CMPQ itr2, $10
+ JNE openAVX2Tail256LoopB
+
+ MOVQ inl, itr2
+ SUBQ inp, inl
+ MOVQ inl, itr1
+ MOVQ tmpStoreAVX2, inl
+
+ // Hash the remainder of data (if any)
+openAVX2Tail256Hash:
+ ADDQ $16, itr1
+ CMPQ itr1, inl
+ JGT openAVX2Tail256HashEnd
+ polyAdd (0(itr2))
+ polyMulAVX2
+ LEAQ 16(itr2), itr2
+ JMP openAVX2Tail256Hash
+
+// Store 128 bytes safely, then go to store loop
+openAVX2Tail256HashEnd:
+ VPADDD ·chacha20Constants<>(SB), AA0, AA0; VPADDD ·chacha20Constants<>(SB), AA1, AA1
+ VPADDD state1StoreAVX2, BB0, BB0; VPADDD state1StoreAVX2, BB1, BB1
+ VPADDD state2StoreAVX2, CC0, CC0; VPADDD state2StoreAVX2, CC1, CC1
+ VPADDD TT1, DD0, DD0; VPADDD TT2, DD1, DD1
+ VPERM2I128 $0x02, AA0, BB0, AA2; VPERM2I128 $0x02, CC0, DD0, BB2; VPERM2I128 $0x13, AA0, BB0, CC2; VPERM2I128 $0x13, CC0, DD0, DD2
+ VPERM2I128 $0x02, AA1, BB1, AA0; VPERM2I128 $0x02, CC1, DD1, BB0; VPERM2I128 $0x13, AA1, BB1, CC0; VPERM2I128 $0x13, CC1, DD1, DD0
+
+ VPXOR (0*32)(inp), AA2, AA2; VPXOR (1*32)(inp), BB2, BB2; VPXOR (2*32)(inp), CC2, CC2; VPXOR (3*32)(inp), DD2, DD2
+ VMOVDQU AA2, (0*32)(oup); VMOVDQU BB2, (1*32)(oup); VMOVDQU CC2, (2*32)(oup); VMOVDQU DD2, (3*32)(oup)
+ LEAQ (4*32)(inp), inp
+ LEAQ (4*32)(oup), oup
+ SUBQ $4*32, inl
+
+ JMP openAVX2TailLoop
+
+// ----------------------------------------------------------------------------
+// Special optimization for the last 384 bytes of ciphertext
+openAVX2Tail384:
+ // Need to decrypt up to 384 bytes - prepare six blocks
+ VMOVDQA ·chacha20Constants<>(SB), AA0; VMOVDQA AA0, AA1; VMOVDQA AA0, AA2
+ VMOVDQA state1StoreAVX2, BB0; VMOVDQA BB0, BB1; VMOVDQA BB0, BB2
+ VMOVDQA state2StoreAVX2, CC0; VMOVDQA CC0, CC1; VMOVDQA CC0, CC2
+ VMOVDQA ctr3StoreAVX2, DD0
+ VPADDD ·avx2IncMask<>(SB), DD0, DD0
+ VPADDD ·avx2IncMask<>(SB), DD0, DD1
+ VPADDD ·avx2IncMask<>(SB), DD1, DD2
+ VMOVDQA DD0, ctr0StoreAVX2
+ VMOVDQA DD1, ctr1StoreAVX2
+ VMOVDQA DD2, ctr2StoreAVX2
+
+ // Compute the number of iterations that will hash two blocks of data
+ MOVQ inl, tmpStoreAVX2
+ MOVQ inl, itr1
+ SUBQ $256, itr1
+ SHRQ $4, itr1
+ ADDQ $6, itr1
+ MOVQ $10, itr2
+ CMPQ itr1, $10
+ CMOVQGT itr2, itr1
+ MOVQ inp, inl
+ XORQ itr2, itr2
+
+ // Perform ChaCha rounds, while hashing the remaining input
+openAVX2Tail384LoopB:
+ polyAdd(0(inl))
+ polyMulAVX2
+ LEAQ 16(inl), inl
+
+openAVX2Tail384LoopA:
+ chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0); chachaQR_AVX2(AA1, BB1, CC1, DD1, TT0); chachaQR_AVX2(AA2, BB2, CC2, DD2, TT0)
+ VPALIGNR $4, BB0, BB0, BB0; VPALIGNR $4, BB1, BB1, BB1; VPALIGNR $4, BB2, BB2, BB2
+ VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1; VPALIGNR $8, CC2, CC2, CC2
+ VPALIGNR $12, DD0, DD0, DD0; VPALIGNR $12, DD1, DD1, DD1; VPALIGNR $12, DD2, DD2, DD2
+ polyAdd(0(inl))
+ polyMulAVX2
+ LEAQ 16(inl), inl
+ INCQ itr2
+ chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0); chachaQR_AVX2(AA1, BB1, CC1, DD1, TT0); chachaQR_AVX2(AA2, BB2, CC2, DD2, TT0)
+ VPALIGNR $12, BB0, BB0, BB0; VPALIGNR $12, BB1, BB1, BB1; VPALIGNR $12, BB2, BB2, BB2
+ VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1; VPALIGNR $8, CC2, CC2, CC2
+ VPALIGNR $4, DD0, DD0, DD0; VPALIGNR $4, DD1, DD1, DD1; VPALIGNR $4, DD2, DD2, DD2
+
+ CMPQ itr2, itr1
+ JB openAVX2Tail384LoopB
+
+ CMPQ itr2, $10
+ JNE openAVX2Tail384LoopA
+
+ MOVQ inl, itr2
+ SUBQ inp, inl
+ MOVQ inl, itr1
+ MOVQ tmpStoreAVX2, inl
+
+openAVX2Tail384Hash:
+ ADDQ $16, itr1
+ CMPQ itr1, inl
+ JGT openAVX2Tail384HashEnd
+ polyAdd(0(itr2))
+ polyMulAVX2
+ LEAQ 16(itr2), itr2
+ JMP openAVX2Tail384Hash
+
+// Store 256 bytes safely, then go to store loop
+openAVX2Tail384HashEnd:
+ VPADDD ·chacha20Constants<>(SB), AA0, AA0; VPADDD ·chacha20Constants<>(SB), AA1, AA1; VPADDD ·chacha20Constants<>(SB), AA2, AA2
+ VPADDD state1StoreAVX2, BB0, BB0; VPADDD state1StoreAVX2, BB1, BB1; VPADDD state1StoreAVX2, BB2, BB2
+ VPADDD state2StoreAVX2, CC0, CC0; VPADDD state2StoreAVX2, CC1, CC1; VPADDD state2StoreAVX2, CC2, CC2
+ VPADDD ctr0StoreAVX2, DD0, DD0; VPADDD ctr1StoreAVX2, DD1, DD1; VPADDD ctr2StoreAVX2, DD2, DD2
+ VPERM2I128 $0x02, AA0, BB0, TT0; VPERM2I128 $0x02, CC0, DD0, TT1; VPERM2I128 $0x13, AA0, BB0, TT2; VPERM2I128 $0x13, CC0, DD0, TT3
+ VPXOR (0*32)(inp), TT0, TT0; VPXOR (1*32)(inp), TT1, TT1; VPXOR (2*32)(inp), TT2, TT2; VPXOR (3*32)(inp), TT3, TT3
+ VMOVDQU TT0, (0*32)(oup); VMOVDQU TT1, (1*32)(oup); VMOVDQU TT2, (2*32)(oup); VMOVDQU TT3, (3*32)(oup)
+ VPERM2I128 $0x02, AA1, BB1, TT0; VPERM2I128 $0x02, CC1, DD1, TT1; VPERM2I128 $0x13, AA1, BB1, TT2; VPERM2I128 $0x13, CC1, DD1, TT3
+ VPXOR (4*32)(inp), TT0, TT0; VPXOR (5*32)(inp), TT1, TT1; VPXOR (6*32)(inp), TT2, TT2; VPXOR (7*32)(inp), TT3, TT3
+ VMOVDQU TT0, (4*32)(oup); VMOVDQU TT1, (5*32)(oup); VMOVDQU TT2, (6*32)(oup); VMOVDQU TT3, (7*32)(oup)
+ VPERM2I128 $0x02, AA2, BB2, AA0; VPERM2I128 $0x02, CC2, DD2, BB0; VPERM2I128 $0x13, AA2, BB2, CC0; VPERM2I128 $0x13, CC2, DD2, DD0
+ LEAQ (8*32)(inp), inp
+ LEAQ (8*32)(oup), oup
+ SUBQ $8*32, inl
+ JMP openAVX2TailLoop
+
+// ----------------------------------------------------------------------------
+// Special optimization for the last 512 bytes of ciphertext
+openAVX2Tail512:
+ VMOVDQU ·chacha20Constants<>(SB), AA0; VMOVDQA AA0, AA1; VMOVDQA AA0, AA2; VMOVDQA AA0, AA3
+ VMOVDQA state1StoreAVX2, BB0; VMOVDQA BB0, BB1; VMOVDQA BB0, BB2; VMOVDQA BB0, BB3
+ VMOVDQA state2StoreAVX2, CC0; VMOVDQA CC0, CC1; VMOVDQA CC0, CC2; VMOVDQA CC0, CC3
+ VMOVDQA ctr3StoreAVX2, DD0; VPADDD ·avx2IncMask<>(SB), DD0, DD0; VPADDD ·avx2IncMask<>(SB), DD0, DD1; VPADDD ·avx2IncMask<>(SB), DD1, DD2; VPADDD ·avx2IncMask<>(SB), DD2, DD3
+ VMOVDQA DD0, ctr0StoreAVX2; VMOVDQA DD1, ctr1StoreAVX2; VMOVDQA DD2, ctr2StoreAVX2; VMOVDQA DD3, ctr3StoreAVX2
+ XORQ itr1, itr1
+ MOVQ inp, itr2
+
+openAVX2Tail512LoopB:
+ polyAdd(0(itr2))
+ polyMulAVX2
+ LEAQ (2*8)(itr2), itr2
+
+openAVX2Tail512LoopA:
+ VPADDD BB0, AA0, AA0; VPADDD BB1, AA1, AA1; VPADDD BB2, AA2, AA2; VPADDD BB3, AA3, AA3
+ VPXOR AA0, DD0, DD0; VPXOR AA1, DD1, DD1; VPXOR AA2, DD2, DD2; VPXOR AA3, DD3, DD3
+ VPSHUFB ·rol16<>(SB), DD0, DD0; VPSHUFB ·rol16<>(SB), DD1, DD1; VPSHUFB ·rol16<>(SB), DD2, DD2; VPSHUFB ·rol16<>(SB), DD3, DD3
+ VPADDD DD0, CC0, CC0; VPADDD DD1, CC1, CC1; VPADDD DD2, CC2, CC2; VPADDD DD3, CC3, CC3
+ VPXOR CC0, BB0, BB0; VPXOR CC1, BB1, BB1; VPXOR CC2, BB2, BB2; VPXOR CC3, BB3, BB3
+ VMOVDQA CC3, tmpStoreAVX2
+ VPSLLD $12, BB0, CC3; VPSRLD $20, BB0, BB0; VPXOR CC3, BB0, BB0
+ VPSLLD $12, BB1, CC3; VPSRLD $20, BB1, BB1; VPXOR CC3, BB1, BB1
+ VPSLLD $12, BB2, CC3; VPSRLD $20, BB2, BB2; VPXOR CC3, BB2, BB2
+ VPSLLD $12, BB3, CC3; VPSRLD $20, BB3, BB3; VPXOR CC3, BB3, BB3
+ VMOVDQA tmpStoreAVX2, CC3
+ polyAdd(0*8(itr2))
+ polyMulAVX2
+ VPADDD BB0, AA0, AA0; VPADDD BB1, AA1, AA1; VPADDD BB2, AA2, AA2; VPADDD BB3, AA3, AA3
+ VPXOR AA0, DD0, DD0; VPXOR AA1, DD1, DD1; VPXOR AA2, DD2, DD2; VPXOR AA3, DD3, DD3
+ VPSHUFB ·rol8<>(SB), DD0, DD0; VPSHUFB ·rol8<>(SB), DD1, DD1; VPSHUFB ·rol8<>(SB), DD2, DD2; VPSHUFB ·rol8<>(SB), DD3, DD3
+ VPADDD DD0, CC0, CC0; VPADDD DD1, CC1, CC1; VPADDD DD2, CC2, CC2; VPADDD DD3, CC3, CC3
+ VPXOR CC0, BB0, BB0; VPXOR CC1, BB1, BB1; VPXOR CC2, BB2, BB2; VPXOR CC3, BB3, BB3
+ VMOVDQA CC3, tmpStoreAVX2
+ VPSLLD $7, BB0, CC3; VPSRLD $25, BB0, BB0; VPXOR CC3, BB0, BB0
+ VPSLLD $7, BB1, CC3; VPSRLD $25, BB1, BB1; VPXOR CC3, BB1, BB1
+ VPSLLD $7, BB2, CC3; VPSRLD $25, BB2, BB2; VPXOR CC3, BB2, BB2
+ VPSLLD $7, BB3, CC3; VPSRLD $25, BB3, BB3; VPXOR CC3, BB3, BB3
+ VMOVDQA tmpStoreAVX2, CC3
+ VPALIGNR $4, BB0, BB0, BB0; VPALIGNR $4, BB1, BB1, BB1; VPALIGNR $4, BB2, BB2, BB2; VPALIGNR $4, BB3, BB3, BB3
+ VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1; VPALIGNR $8, CC2, CC2, CC2; VPALIGNR $8, CC3, CC3, CC3
+ VPALIGNR $12, DD0, DD0, DD0; VPALIGNR $12, DD1, DD1, DD1; VPALIGNR $12, DD2, DD2, DD2; VPALIGNR $12, DD3, DD3, DD3
+ VPADDD BB0, AA0, AA0; VPADDD BB1, AA1, AA1; VPADDD BB2, AA2, AA2; VPADDD BB3, AA3, AA3
+ VPXOR AA0, DD0, DD0; VPXOR AA1, DD1, DD1; VPXOR AA2, DD2, DD2; VPXOR AA3, DD3, DD3
+ VPSHUFB ·rol16<>(SB), DD0, DD0; VPSHUFB ·rol16<>(SB), DD1, DD1; VPSHUFB ·rol16<>(SB), DD2, DD2; VPSHUFB ·rol16<>(SB), DD3, DD3
+ VPADDD DD0, CC0, CC0; VPADDD DD1, CC1, CC1; VPADDD DD2, CC2, CC2; VPADDD DD3, CC3, CC3
+ VPXOR CC0, BB0, BB0; VPXOR CC1, BB1, BB1; VPXOR CC2, BB2, BB2; VPXOR CC3, BB3, BB3
+ polyAdd(2*8(itr2))
+ polyMulAVX2
+ LEAQ (4*8)(itr2), itr2
+ VMOVDQA CC3, tmpStoreAVX2
+ VPSLLD $12, BB0, CC3; VPSRLD $20, BB0, BB0; VPXOR CC3, BB0, BB0
+ VPSLLD $12, BB1, CC3; VPSRLD $20, BB1, BB1; VPXOR CC3, BB1, BB1
+ VPSLLD $12, BB2, CC3; VPSRLD $20, BB2, BB2; VPXOR CC3, BB2, BB2
+ VPSLLD $12, BB3, CC3; VPSRLD $20, BB3, BB3; VPXOR CC3, BB3, BB3
+ VMOVDQA tmpStoreAVX2, CC3
+ VPADDD BB0, AA0, AA0; VPADDD BB1, AA1, AA1; VPADDD BB2, AA2, AA2; VPADDD BB3, AA3, AA3
+ VPXOR AA0, DD0, DD0; VPXOR AA1, DD1, DD1; VPXOR AA2, DD2, DD2; VPXOR AA3, DD3, DD3
+ VPSHUFB ·rol8<>(SB), DD0, DD0; VPSHUFB ·rol8<>(SB), DD1, DD1; VPSHUFB ·rol8<>(SB), DD2, DD2; VPSHUFB ·rol8<>(SB), DD3, DD3
+ VPADDD DD0, CC0, CC0; VPADDD DD1, CC1, CC1; VPADDD DD2, CC2, CC2; VPADDD DD3, CC3, CC3
+ VPXOR CC0, BB0, BB0; VPXOR CC1, BB1, BB1; VPXOR CC2, BB2, BB2; VPXOR CC3, BB3, BB3
+ VMOVDQA CC3, tmpStoreAVX2
+ VPSLLD $7, BB0, CC3; VPSRLD $25, BB0, BB0; VPXOR CC3, BB0, BB0
+ VPSLLD $7, BB1, CC3; VPSRLD $25, BB1, BB1; VPXOR CC3, BB1, BB1
+ VPSLLD $7, BB2, CC3; VPSRLD $25, BB2, BB2; VPXOR CC3, BB2, BB2
+ VPSLLD $7, BB3, CC3; VPSRLD $25, BB3, BB3; VPXOR CC3, BB3, BB3
+ VMOVDQA tmpStoreAVX2, CC3
+ VPALIGNR $12, BB0, BB0, BB0; VPALIGNR $12, BB1, BB1, BB1; VPALIGNR $12, BB2, BB2, BB2; VPALIGNR $12, BB3, BB3, BB3
+ VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1; VPALIGNR $8, CC2, CC2, CC2; VPALIGNR $8, CC3, CC3, CC3
+ VPALIGNR $4, DD0, DD0, DD0; VPALIGNR $4, DD1, DD1, DD1; VPALIGNR $4, DD2, DD2, DD2; VPALIGNR $4, DD3, DD3, DD3
+ INCQ itr1
+ CMPQ itr1, $4
+ JLT openAVX2Tail512LoopB
+
+ CMPQ itr1, $10
+ JNE openAVX2Tail512LoopA
+
+ MOVQ inl, itr1
+ SUBQ $384, itr1
+ ANDQ $-16, itr1
+
+openAVX2Tail512HashLoop:
+ TESTQ itr1, itr1
+ JE openAVX2Tail512HashEnd
+ polyAdd(0(itr2))
+ polyMulAVX2
+ LEAQ 16(itr2), itr2
+ SUBQ $16, itr1
+ JMP openAVX2Tail512HashLoop
+
+openAVX2Tail512HashEnd:
+ VPADDD ·chacha20Constants<>(SB), AA0, AA0; VPADDD ·chacha20Constants<>(SB), AA1, AA1; VPADDD ·chacha20Constants<>(SB), AA2, AA2; VPADDD ·chacha20Constants<>(SB), AA3, AA3
+ VPADDD state1StoreAVX2, BB0, BB0; VPADDD state1StoreAVX2, BB1, BB1; VPADDD state1StoreAVX2, BB2, BB2; VPADDD state1StoreAVX2, BB3, BB3
+ VPADDD state2StoreAVX2, CC0, CC0; VPADDD state2StoreAVX2, CC1, CC1; VPADDD state2StoreAVX2, CC2, CC2; VPADDD state2StoreAVX2, CC3, CC3
+ VPADDD ctr0StoreAVX2, DD0, DD0; VPADDD ctr1StoreAVX2, DD1, DD1; VPADDD ctr2StoreAVX2, DD2, DD2; VPADDD ctr3StoreAVX2, DD3, DD3
+ VMOVDQA CC3, tmpStoreAVX2
+ VPERM2I128 $0x02, AA0, BB0, CC3; VPERM2I128 $0x13, AA0, BB0, BB0; VPERM2I128 $0x02, CC0, DD0, AA0; VPERM2I128 $0x13, CC0, DD0, CC0
+ VPXOR (0*32)(inp), CC3, CC3; VPXOR (1*32)(inp), AA0, AA0; VPXOR (2*32)(inp), BB0, BB0; VPXOR (3*32)(inp), CC0, CC0
+ VMOVDQU CC3, (0*32)(oup); VMOVDQU AA0, (1*32)(oup); VMOVDQU BB0, (2*32)(oup); VMOVDQU CC0, (3*32)(oup)
+ VPERM2I128 $0x02, AA1, BB1, AA0; VPERM2I128 $0x02, CC1, DD1, BB0; VPERM2I128 $0x13, AA1, BB1, CC0; VPERM2I128 $0x13, CC1, DD1, DD0
+ VPXOR (4*32)(inp), AA0, AA0; VPXOR (5*32)(inp), BB0, BB0; VPXOR (6*32)(inp), CC0, CC0; VPXOR (7*32)(inp), DD0, DD0
+ VMOVDQU AA0, (4*32)(oup); VMOVDQU BB0, (5*32)(oup); VMOVDQU CC0, (6*32)(oup); VMOVDQU DD0, (7*32)(oup)
+ VPERM2I128 $0x02, AA2, BB2, AA0; VPERM2I128 $0x02, CC2, DD2, BB0; VPERM2I128 $0x13, AA2, BB2, CC0; VPERM2I128 $0x13, CC2, DD2, DD0
+ VPXOR (8*32)(inp), AA0, AA0; VPXOR (9*32)(inp), BB0, BB0; VPXOR (10*32)(inp), CC0, CC0; VPXOR (11*32)(inp), DD0, DD0
+ VMOVDQU AA0, (8*32)(oup); VMOVDQU BB0, (9*32)(oup); VMOVDQU CC0, (10*32)(oup); VMOVDQU DD0, (11*32)(oup)
+ VPERM2I128 $0x02, AA3, BB3, AA0; VPERM2I128 $0x02, tmpStoreAVX2, DD3, BB0; VPERM2I128 $0x13, AA3, BB3, CC0; VPERM2I128 $0x13, tmpStoreAVX2, DD3, DD0
+
+ LEAQ (12*32)(inp), inp
+ LEAQ (12*32)(oup), oup
+ SUBQ $12*32, inl
+
+ JMP openAVX2TailLoop
+
+// ----------------------------------------------------------------------------
+// ----------------------------------------------------------------------------
+// func chacha20Poly1305Seal(dst, key, src, ad []byte)
+TEXT ·chacha20Poly1305Seal(SB), 0, $288-96
+ // For aligned stack access
+ MOVQ SP, BP
+ ADDQ $32, BP
+ ANDQ $-32, BP
+ MOVQ dst+0(FP), oup
+ MOVQ key+24(FP), keyp
+ MOVQ src+48(FP), inp
+ MOVQ src_len+56(FP), inl
+ MOVQ ad+72(FP), adp
+
+ // Check for AVX2 support
+ CMPB runtime·support_avx2(SB), $1
+ JE chacha20Poly1305Seal_AVX2
+
+ // Special optimization, for very short buffers
+ CMPQ inl, $128
+ JBE sealSSE128 // About 15% faster
+
+ // In the seal case - prepare the poly key + 3 blocks of stream in the first iteration
+ MOVOU ·chacha20Constants<>(SB), A0
+ MOVOU (1*16)(keyp), B0
+ MOVOU (2*16)(keyp), C0
+ MOVOU (3*16)(keyp), D0
+
+ // Store state on stack for future use
+ MOVO B0, state1Store
+ MOVO C0, state2Store
+
+ // Load state, increment counter blocks
+ MOVO A0, A1; MOVO B0, B1; MOVO C0, C1; MOVO D0, D1; PADDL ·sseIncMask<>(SB), D1
+ MOVO A1, A2; MOVO B1, B2; MOVO C1, C2; MOVO D1, D2; PADDL ·sseIncMask<>(SB), D2
+ MOVO A2, A3; MOVO B2, B3; MOVO C2, C3; MOVO D2, D3; PADDL ·sseIncMask<>(SB), D3
+
+ // Store counters
+ MOVO D0, ctr0Store; MOVO D1, ctr1Store; MOVO D2, ctr2Store; MOVO D3, ctr3Store
+ MOVQ $10, itr2
+
+sealSSEIntroLoop:
+ MOVO C3, tmpStore
+ chachaQR(A0, B0, C0, D0, C3); chachaQR(A1, B1, C1, D1, C3); chachaQR(A2, B2, C2, D2, C3)
+ MOVO tmpStore, C3
+ MOVO C1, tmpStore
+ chachaQR(A3, B3, C3, D3, C1)
+ MOVO tmpStore, C1
+ shiftB0Left; shiftB1Left; shiftB2Left; shiftB3Left
+ shiftC0Left; shiftC1Left; shiftC2Left; shiftC3Left
+ shiftD0Left; shiftD1Left; shiftD2Left; shiftD3Left
+
+ MOVO C3, tmpStore
+ chachaQR(A0, B0, C0, D0, C3); chachaQR(A1, B1, C1, D1, C3); chachaQR(A2, B2, C2, D2, C3)
+ MOVO tmpStore, C3
+ MOVO C1, tmpStore
+ chachaQR(A3, B3, C3, D3, C1)
+ MOVO tmpStore, C1
+ shiftB0Right; shiftB1Right; shiftB2Right; shiftB3Right
+ shiftC0Right; shiftC1Right; shiftC2Right; shiftC3Right
+ shiftD0Right; shiftD1Right; shiftD2Right; shiftD3Right
+ DECQ itr2
+ JNE sealSSEIntroLoop
+
+ // Add in the state
+ PADDD ·chacha20Constants<>(SB), A0; PADDD ·chacha20Constants<>(SB), A1; PADDD ·chacha20Constants<>(SB), A2; PADDD ·chacha20Constants<>(SB), A3
+ PADDD state1Store, B0; PADDD state1Store, B1; PADDD state1Store, B2; PADDD state1Store, B3
+ PADDD state2Store, C1; PADDD state2Store, C2; PADDD state2Store, C3
+ PADDD ctr1Store, D1; PADDD ctr2Store, D2; PADDD ctr3Store, D3
+
+ // Clamp and store the key
+ PAND ·polyClampMask<>(SB), A0
+ MOVO A0, rStore
+ MOVO B0, sStore
+
+ // Hash AAD
+ MOVQ ad_len+80(FP), itr2
+ CALL polyHashADInternal(SB)
+
+ MOVOU (0*16)(inp), A0; MOVOU (1*16)(inp), B0; MOVOU (2*16)(inp), C0; MOVOU (3*16)(inp), D0
+ PXOR A0, A1; PXOR B0, B1; PXOR C0, C1; PXOR D0, D1
+ MOVOU A1, (0*16)(oup); MOVOU B1, (1*16)(oup); MOVOU C1, (2*16)(oup); MOVOU D1, (3*16)(oup)
+ MOVOU (4*16)(inp), A0; MOVOU (5*16)(inp), B0; MOVOU (6*16)(inp), C0; MOVOU (7*16)(inp), D0
+ PXOR A0, A2; PXOR B0, B2; PXOR C0, C2; PXOR D0, D2
+ MOVOU A2, (4*16)(oup); MOVOU B2, (5*16)(oup); MOVOU C2, (6*16)(oup); MOVOU D2, (7*16)(oup)
+
+ MOVQ $128, itr1
+ SUBQ $128, inl
+ LEAQ 128(inp), inp
+
+ MOVO A3, A1; MOVO B3, B1; MOVO C3, C1; MOVO D3, D1
+
+ CMPQ inl, $64
+ JBE sealSSE128SealHash
+
+ MOVOU (0*16)(inp), A0; MOVOU (1*16)(inp), B0; MOVOU (2*16)(inp), C0; MOVOU (3*16)(inp), D0
+ PXOR A0, A3; PXOR B0, B3; PXOR C0, C3; PXOR D0, D3
+ MOVOU A3, (8*16)(oup); MOVOU B3, (9*16)(oup); MOVOU C3, (10*16)(oup); MOVOU D3, (11*16)(oup)
+
+ ADDQ $64, itr1
+ SUBQ $64, inl
+ LEAQ 64(inp), inp
+
+ MOVQ $2, itr1
+ MOVQ $8, itr2
+
+ CMPQ inl, $64
+ JBE sealSSETail64
+ CMPQ inl, $128
+ JBE sealSSETail128
+ CMPQ inl, $192
+ JBE sealSSETail192
+
+sealSSEMainLoop:
+ // Load state, increment counter blocks
+ MOVO ·chacha20Constants<>(SB), A0; MOVO state1Store, B0; MOVO state2Store, C0; MOVO ctr3Store, D0; PADDL ·sseIncMask<>(SB), D0
+ MOVO A0, A1; MOVO B0, B1; MOVO C0, C1; MOVO D0, D1; PADDL ·sseIncMask<>(SB), D1
+ MOVO A1, A2; MOVO B1, B2; MOVO C1, C2; MOVO D1, D2; PADDL ·sseIncMask<>(SB), D2
+ MOVO A2, A3; MOVO B2, B3; MOVO C2, C3; MOVO D2, D3; PADDL ·sseIncMask<>(SB), D3
+
+ // Store counters
+ MOVO D0, ctr0Store; MOVO D1, ctr1Store; MOVO D2, ctr2Store; MOVO D3, ctr3Store
+
+sealSSEInnerLoop:
+ MOVO C3, tmpStore
+ chachaQR(A0, B0, C0, D0, C3); chachaQR(A1, B1, C1, D1, C3); chachaQR(A2, B2, C2, D2, C3)
+ MOVO tmpStore, C3
+ MOVO C1, tmpStore
+ chachaQR(A3, B3, C3, D3, C1)
+ MOVO tmpStore, C1
+ polyAdd(0(oup))
+ shiftB0Left; shiftB1Left; shiftB2Left; shiftB3Left
+ shiftC0Left; shiftC1Left; shiftC2Left; shiftC3Left
+ shiftD0Left; shiftD1Left; shiftD2Left; shiftD3Left
+ polyMulStage1
+ polyMulStage2
+ LEAQ (2*8)(oup), oup
+ MOVO C3, tmpStore
+ chachaQR(A0, B0, C0, D0, C3); chachaQR(A1, B1, C1, D1, C3); chachaQR(A2, B2, C2, D2, C3)
+ MOVO tmpStore, C3
+ MOVO C1, tmpStore
+ polyMulStage3
+ chachaQR(A3, B3, C3, D3, C1)
+ MOVO tmpStore, C1
+ polyMulReduceStage
+ shiftB0Right; shiftB1Right; shiftB2Right; shiftB3Right
+ shiftC0Right; shiftC1Right; shiftC2Right; shiftC3Right
+ shiftD0Right; shiftD1Right; shiftD2Right; shiftD3Right
+ DECQ itr2
+ JGE sealSSEInnerLoop
+ polyAdd(0(oup))
+ polyMul
+ LEAQ (2*8)(oup), oup
+ DECQ itr1
+ JG sealSSEInnerLoop
+
+ // Add in the state
+ PADDD ·chacha20Constants<>(SB), A0; PADDD ·chacha20Constants<>(SB), A1; PADDD ·chacha20Constants<>(SB), A2; PADDD ·chacha20Constants<>(SB), A3
+ PADDD state1Store, B0; PADDD state1Store, B1; PADDD state1Store, B2; PADDD state1Store, B3
+ PADDD state2Store, C0; PADDD state2Store, C1; PADDD state2Store, C2; PADDD state2Store, C3
+ PADDD ctr0Store, D0; PADDD ctr1Store, D1; PADDD ctr2Store, D2; PADDD ctr3Store, D3
+ MOVO D3, tmpStore
+
+ // Load - xor - store
+ MOVOU (0*16)(inp), D3; PXOR D3, A0
+ MOVOU (1*16)(inp), D3; PXOR D3, B0
+ MOVOU (2*16)(inp), D3; PXOR D3, C0
+ MOVOU (3*16)(inp), D3; PXOR D3, D0
+ MOVOU A0, (0*16)(oup)
+ MOVOU B0, (1*16)(oup)
+ MOVOU C0, (2*16)(oup)
+ MOVOU D0, (3*16)(oup)
+ MOVO tmpStore, D3
+
+ MOVOU (4*16)(inp), A0; MOVOU (5*16)(inp), B0; MOVOU (6*16)(inp), C0; MOVOU (7*16)(inp), D0
+ PXOR A0, A1; PXOR B0, B1; PXOR C0, C1; PXOR D0, D1
+ MOVOU A1, (4*16)(oup); MOVOU B1, (5*16)(oup); MOVOU C1, (6*16)(oup); MOVOU D1, (7*16)(oup)
+ MOVOU (8*16)(inp), A0; MOVOU (9*16)(inp), B0; MOVOU (10*16)(inp), C0; MOVOU (11*16)(inp), D0
+ PXOR A0, A2; PXOR B0, B2; PXOR C0, C2; PXOR D0, D2
+ MOVOU A2, (8*16)(oup); MOVOU B2, (9*16)(oup); MOVOU C2, (10*16)(oup); MOVOU D2, (11*16)(oup)
+ ADDQ $192, inp
+ MOVQ $192, itr1
+ SUBQ $192, inl
+ MOVO A3, A1
+ MOVO B3, B1
+ MOVO C3, C1
+ MOVO D3, D1
+ CMPQ inl, $64
+ JBE sealSSE128SealHash
+ MOVOU (0*16)(inp), A0; MOVOU (1*16)(inp), B0; MOVOU (2*16)(inp), C0; MOVOU (3*16)(inp), D0
+ PXOR A0, A3; PXOR B0, B3; PXOR C0, C3; PXOR D0, D3
+ MOVOU A3, (12*16)(oup); MOVOU B3, (13*16)(oup); MOVOU C3, (14*16)(oup); MOVOU D3, (15*16)(oup)
+ LEAQ 64(inp), inp
+ SUBQ $64, inl
+ MOVQ $6, itr1
+ MOVQ $4, itr2
+ CMPQ inl, $192
+ JG sealSSEMainLoop
+
+ MOVQ inl, itr1
+ TESTQ inl, inl
+ JE sealSSE128SealHash
+ MOVQ $6, itr1
+ CMPQ inl, $64
+ JBE sealSSETail64
+ CMPQ inl, $128
+ JBE sealSSETail128
+ JMP sealSSETail192
+
+// ----------------------------------------------------------------------------
+// Special optimization for the last 64 bytes of plaintext
+sealSSETail64:
+ // Need to encrypt up to 64 bytes - prepare single block, hash 192 or 256 bytes
+ MOVO ·chacha20Constants<>(SB), A1
+ MOVO state1Store, B1
+ MOVO state2Store, C1
+ MOVO ctr3Store, D1
+ PADDL ·sseIncMask<>(SB), D1
+ MOVO D1, ctr0Store
+
+sealSSETail64LoopA:
+ // Perform ChaCha rounds, while hashing the prevsiosly encrpyted ciphertext
+ polyAdd(0(oup))
+ polyMul
+ LEAQ 16(oup), oup
+
+sealSSETail64LoopB:
+ chachaQR(A1, B1, C1, D1, T1)
+ shiftB1Left; shiftC1Left; shiftD1Left
+ chachaQR(A1, B1, C1, D1, T1)
+ shiftB1Right; shiftC1Right; shiftD1Right
+ polyAdd(0(oup))
+ polyMul
+ LEAQ 16(oup), oup
+
+ DECQ itr1
+ JG sealSSETail64LoopA
+
+ DECQ itr2
+ JGE sealSSETail64LoopB
+ PADDL ·chacha20Constants<>(SB), A1
+ PADDL state1Store, B1
+ PADDL state2Store, C1
+ PADDL ctr0Store, D1
+
+ JMP sealSSE128Seal
+
+// ----------------------------------------------------------------------------
+// Special optimization for the last 128 bytes of plaintext
+sealSSETail128:
+ // Need to encrypt up to 128 bytes - prepare two blocks, hash 192 or 256 bytes
+ MOVO ·chacha20Constants<>(SB), A0; MOVO state1Store, B0; MOVO state2Store, C0; MOVO ctr3Store, D0; PADDL ·sseIncMask<>(SB), D0; MOVO D0, ctr0Store
+ MOVO A0, A1; MOVO B0, B1; MOVO C0, C1; MOVO D0, D1; PADDL ·sseIncMask<>(SB), D1; MOVO D1, ctr1Store
+
+sealSSETail128LoopA:
+ // Perform ChaCha rounds, while hashing the prevsiosly encrpyted ciphertext
+ polyAdd(0(oup))
+ polyMul
+ LEAQ 16(oup), oup
+
+sealSSETail128LoopB:
+ chachaQR(A0, B0, C0, D0, T0); chachaQR(A1, B1, C1, D1, T0)
+ shiftB0Left; shiftC0Left; shiftD0Left
+ shiftB1Left; shiftC1Left; shiftD1Left
+ polyAdd(0(oup))
+ polyMul
+ LEAQ 16(oup), oup
+ chachaQR(A0, B0, C0, D0, T0); chachaQR(A1, B1, C1, D1, T0)
+ shiftB0Right; shiftC0Right; shiftD0Right
+ shiftB1Right; shiftC1Right; shiftD1Right
+
+ DECQ itr1
+ JG sealSSETail128LoopA
+
+ DECQ itr2
+ JGE sealSSETail128LoopB
+
+ PADDL ·chacha20Constants<>(SB), A0; PADDL ·chacha20Constants<>(SB), A1
+ PADDL state1Store, B0; PADDL state1Store, B1
+ PADDL state2Store, C0; PADDL state2Store, C1
+ PADDL ctr0Store, D0; PADDL ctr1Store, D1
+
+ MOVOU (0*16)(inp), T0; MOVOU (1*16)(inp), T1; MOVOU (2*16)(inp), T2; MOVOU (3*16)(inp), T3
+ PXOR T0, A0; PXOR T1, B0; PXOR T2, C0; PXOR T3, D0
+ MOVOU A0, (0*16)(oup); MOVOU B0, (1*16)(oup); MOVOU C0, (2*16)(oup); MOVOU D0, (3*16)(oup)
+
+ MOVQ $64, itr1
+ LEAQ 64(inp), inp
+ SUBQ $64, inl
+
+ JMP sealSSE128SealHash
+
+// ----------------------------------------------------------------------------
+// Special optimization for the last 192 bytes of plaintext
+sealSSETail192:
+ // Need to encrypt up to 192 bytes - prepare three blocks, hash 192 or 256 bytes
+ MOVO ·chacha20Constants<>(SB), A0; MOVO state1Store, B0; MOVO state2Store, C0; MOVO ctr3Store, D0; PADDL ·sseIncMask<>(SB), D0; MOVO D0, ctr0Store
+ MOVO A0, A1; MOVO B0, B1; MOVO C0, C1; MOVO D0, D1; PADDL ·sseIncMask<>(SB), D1; MOVO D1, ctr1Store
+ MOVO A1, A2; MOVO B1, B2; MOVO C1, C2; MOVO D1, D2; PADDL ·sseIncMask<>(SB), D2; MOVO D2, ctr2Store
+
+sealSSETail192LoopA:
+ // Perform ChaCha rounds, while hashing the prevsiosly encrpyted ciphertext
+ polyAdd(0(oup))
+ polyMul
+ LEAQ 16(oup), oup
+
+sealSSETail192LoopB:
+ chachaQR(A0, B0, C0, D0, T0); chachaQR(A1, B1, C1, D1, T0); chachaQR(A2, B2, C2, D2, T0)
+ shiftB0Left; shiftC0Left; shiftD0Left
+ shiftB1Left; shiftC1Left; shiftD1Left
+ shiftB2Left; shiftC2Left; shiftD2Left
+
+ polyAdd(0(oup))
+ polyMul
+ LEAQ 16(oup), oup
+
+ chachaQR(A0, B0, C0, D0, T0); chachaQR(A1, B1, C1, D1, T0); chachaQR(A2, B2, C2, D2, T0)
+ shiftB0Right; shiftC0Right; shiftD0Right
+ shiftB1Right; shiftC1Right; shiftD1Right
+ shiftB2Right; shiftC2Right; shiftD2Right
+
+ DECQ itr1
+ JG sealSSETail192LoopA
+
+ DECQ itr2
+ JGE sealSSETail192LoopB
+
+ PADDL ·chacha20Constants<>(SB), A0; PADDL ·chacha20Constants<>(SB), A1; PADDL ·chacha20Constants<>(SB), A2
+ PADDL state1Store, B0; PADDL state1Store, B1; PADDL state1Store, B2
+ PADDL state2Store, C0; PADDL state2Store, C1; PADDL state2Store, C2
+ PADDL ctr0Store, D0; PADDL ctr1Store, D1; PADDL ctr2Store, D2
+
+ MOVOU (0*16)(inp), T0; MOVOU (1*16)(inp), T1; MOVOU (2*16)(inp), T2; MOVOU (3*16)(inp), T3
+ PXOR T0, A0; PXOR T1, B0; PXOR T2, C0; PXOR T3, D0
+ MOVOU A0, (0*16)(oup); MOVOU B0, (1*16)(oup); MOVOU C0, (2*16)(oup); MOVOU D0, (3*16)(oup)
+ MOVOU (4*16)(inp), T0; MOVOU (5*16)(inp), T1; MOVOU (6*16)(inp), T2; MOVOU (7*16)(inp), T3
+ PXOR T0, A1; PXOR T1, B1; PXOR T2, C1; PXOR T3, D1
+ MOVOU A1, (4*16)(oup); MOVOU B1, (5*16)(oup); MOVOU C1, (6*16)(oup); MOVOU D1, (7*16)(oup)
+
+ MOVO A2, A1
+ MOVO B2, B1
+ MOVO C2, C1
+ MOVO D2, D1
+ MOVQ $128, itr1
+ LEAQ 128(inp), inp
+ SUBQ $128, inl
+
+ JMP sealSSE128SealHash
+
+// ----------------------------------------------------------------------------
+// Special seal optimization for buffers smaller than 129 bytes
+sealSSE128:
+ // For up to 128 bytes of ciphertext and 64 bytes for the poly key, we require to process three blocks
+ MOVOU ·chacha20Constants<>(SB), A0; MOVOU (1*16)(keyp), B0; MOVOU (2*16)(keyp), C0; MOVOU (3*16)(keyp), D0
+ MOVO A0, A1; MOVO B0, B1; MOVO C0, C1; MOVO D0, D1; PADDL ·sseIncMask<>(SB), D1
+ MOVO A1, A2; MOVO B1, B2; MOVO C1, C2; MOVO D1, D2; PADDL ·sseIncMask<>(SB), D2
+ MOVO B0, T1; MOVO C0, T2; MOVO D1, T3
+ MOVQ $10, itr2
+
+sealSSE128InnerCipherLoop:
+ chachaQR(A0, B0, C0, D0, T0); chachaQR(A1, B1, C1, D1, T0); chachaQR(A2, B2, C2, D2, T0)
+ shiftB0Left; shiftB1Left; shiftB2Left
+ shiftC0Left; shiftC1Left; shiftC2Left
+ shiftD0Left; shiftD1Left; shiftD2Left
+ chachaQR(A0, B0, C0, D0, T0); chachaQR(A1, B1, C1, D1, T0); chachaQR(A2, B2, C2, D2, T0)
+ shiftB0Right; shiftB1Right; shiftB2Right
+ shiftC0Right; shiftC1Right; shiftC2Right
+ shiftD0Right; shiftD1Right; shiftD2Right
+ DECQ itr2
+ JNE sealSSE128InnerCipherLoop
+
+ // A0|B0 hold the Poly1305 32-byte key, C0,D0 can be discarded
+ PADDL ·chacha20Constants<>(SB), A0; PADDL ·chacha20Constants<>(SB), A1; PADDL ·chacha20Constants<>(SB), A2
+ PADDL T1, B0; PADDL T1, B1; PADDL T1, B2
+ PADDL T2, C1; PADDL T2, C2
+ PADDL T3, D1; PADDL ·sseIncMask<>(SB), T3; PADDL T3, D2
+ PAND ·polyClampMask<>(SB), A0
+ MOVOU A0, rStore
+ MOVOU B0, sStore
+
+ // Hash
+ MOVQ ad_len+80(FP), itr2
+ CALL polyHashADInternal(SB)
+ XORQ itr1, itr1
+
+sealSSE128SealHash:
+ // itr1 holds the number of bytes encrypted but not yet hashed
+ CMPQ itr1, $16
+ JB sealSSE128Seal
+ polyAdd(0(oup))
+ polyMul
+
+ SUBQ $16, itr1
+ ADDQ $16, oup
+
+ JMP sealSSE128SealHash
+
+sealSSE128Seal:
+ CMPQ inl, $16
+ JB sealSSETail
+ SUBQ $16, inl
+
+ // Load for decryption
+ MOVOU (inp), T0
+ PXOR T0, A1
+ MOVOU A1, (oup)
+ LEAQ (1*16)(inp), inp
+ LEAQ (1*16)(oup), oup
+
+ // Extract for hashing
+ MOVQ A1, t0
+ PSRLDQ $8, A1
+ MOVQ A1, t1
+ ADDQ t0, acc0; ADCQ t1, acc1; ADCQ $1, acc2
+ polyMul
+
+ // Shift the stream "left"
+ MOVO B1, A1
+ MOVO C1, B1
+ MOVO D1, C1
+ MOVO A2, D1
+ MOVO B2, A2
+ MOVO C2, B2
+ MOVO D2, C2
+ JMP sealSSE128Seal
+
+sealSSETail:
+ TESTQ inl, inl
+ JE sealSSEFinalize
+
+ // We can only load the PT one byte at a time to avoid read after end of buffer
+ MOVQ inl, itr2
+ SHLQ $4, itr2
+ LEAQ ·andMask<>(SB), t0
+ MOVQ inl, itr1
+ LEAQ -1(inp)(inl*1), inp
+ XORQ t2, t2
+ XORQ t3, t3
+ XORQ AX, AX
+
+sealSSETailLoadLoop:
+ SHLQ $8, t2, t3
+ SHLQ $8, t2
+ MOVB (inp), AX
+ XORQ AX, t2
+ LEAQ -1(inp), inp
+ DECQ itr1
+ JNE sealSSETailLoadLoop
+ MOVQ t2, 0+tmpStore
+ MOVQ t3, 8+tmpStore
+ PXOR 0+tmpStore, A1
+ MOVOU A1, (oup)
+ MOVOU -16(t0)(itr2*1), T0
+ PAND T0, A1
+ MOVQ A1, t0
+ PSRLDQ $8, A1
+ MOVQ A1, t1
+ ADDQ t0, acc0; ADCQ t1, acc1; ADCQ $1, acc2
+ polyMul
+
+ ADDQ inl, oup
+
+sealSSEFinalize:
+ // Hash in the buffer lengths
+ ADDQ ad_len+80(FP), acc0
+ ADCQ src_len+56(FP), acc1
+ ADCQ $1, acc2
+ polyMul
+
+ // Final reduce
+ MOVQ acc0, t0
+ MOVQ acc1, t1
+ MOVQ acc2, t2
+ SUBQ $-5, acc0
+ SBBQ $-1, acc1
+ SBBQ $3, acc2
+ CMOVQCS t0, acc0
+ CMOVQCS t1, acc1
+ CMOVQCS t2, acc2
+
+ // Add in the "s" part of the key
+ ADDQ 0+sStore, acc0
+ ADCQ 8+sStore, acc1
+
+ // Finally store the tag at the end of the message
+ MOVQ acc0, (0*8)(oup)
+ MOVQ acc1, (1*8)(oup)
+ RET
+
+// ----------------------------------------------------------------------------
+// ------------------------- AVX2 Code ----------------------------------------
+chacha20Poly1305Seal_AVX2:
+ VZEROUPPER
+ VMOVDQU ·chacha20Constants<>(SB), AA0
+ BYTE $0xc4; BYTE $0x42; BYTE $0x7d; BYTE $0x5a; BYTE $0x70; BYTE $0x10 // broadcasti128 16(r8), ymm14
+ BYTE $0xc4; BYTE $0x42; BYTE $0x7d; BYTE $0x5a; BYTE $0x60; BYTE $0x20 // broadcasti128 32(r8), ymm12
+ BYTE $0xc4; BYTE $0xc2; BYTE $0x7d; BYTE $0x5a; BYTE $0x60; BYTE $0x30 // broadcasti128 48(r8), ymm4
+ VPADDD ·avx2InitMask<>(SB), DD0, DD0
+
+ // Special optimizations, for very short buffers
+ CMPQ inl, $192
+ JBE seal192AVX2 // 33% faster
+ CMPQ inl, $320
+ JBE seal320AVX2 // 17% faster
+
+ // For the general key prepare the key first - as a byproduct we have 64 bytes of cipher stream
+ VMOVDQA AA0, AA1; VMOVDQA AA0, AA2; VMOVDQA AA0, AA3
+ VMOVDQA BB0, BB1; VMOVDQA BB0, BB2; VMOVDQA BB0, BB3; VMOVDQA BB0, state1StoreAVX2
+ VMOVDQA CC0, CC1; VMOVDQA CC0, CC2; VMOVDQA CC0, CC3; VMOVDQA CC0, state2StoreAVX2
+ VPADDD ·avx2IncMask<>(SB), DD0, DD1; VMOVDQA DD0, ctr0StoreAVX2
+ VPADDD ·avx2IncMask<>(SB), DD1, DD2; VMOVDQA DD1, ctr1StoreAVX2
+ VPADDD ·avx2IncMask<>(SB), DD2, DD3; VMOVDQA DD2, ctr2StoreAVX2
+ VMOVDQA DD3, ctr3StoreAVX2
+ MOVQ $10, itr2
+
+sealAVX2IntroLoop:
+ VMOVDQA CC3, tmpStoreAVX2
+ chachaQR_AVX2(AA0, BB0, CC0, DD0, CC3); chachaQR_AVX2(AA1, BB1, CC1, DD1, CC3); chachaQR_AVX2(AA2, BB2, CC2, DD2, CC3)
+ VMOVDQA tmpStoreAVX2, CC3
+ VMOVDQA CC1, tmpStoreAVX2
+ chachaQR_AVX2(AA3, BB3, CC3, DD3, CC1)
+ VMOVDQA tmpStoreAVX2, CC1
+
+ VPALIGNR $4, BB0, BB0, BB0; VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $12, DD0, DD0, DD0
+ VPALIGNR $4, BB1, BB1, BB1; VPALIGNR $8, CC1, CC1, CC1; VPALIGNR $12, DD1, DD1, DD1
+ VPALIGNR $4, BB2, BB2, BB2; VPALIGNR $8, CC2, CC2, CC2; VPALIGNR $12, DD2, DD2, DD2
+ VPALIGNR $4, BB3, BB3, BB3; VPALIGNR $8, CC3, CC3, CC3; VPALIGNR $12, DD3, DD3, DD3
+
+ VMOVDQA CC3, tmpStoreAVX2
+ chachaQR_AVX2(AA0, BB0, CC0, DD0, CC3); chachaQR_AVX2(AA1, BB1, CC1, DD1, CC3); chachaQR_AVX2(AA2, BB2, CC2, DD2, CC3)
+ VMOVDQA tmpStoreAVX2, CC3
+ VMOVDQA CC1, tmpStoreAVX2
+ chachaQR_AVX2(AA3, BB3, CC3, DD3, CC1)
+ VMOVDQA tmpStoreAVX2, CC1
+
+ VPALIGNR $12, BB0, BB0, BB0; VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $4, DD0, DD0, DD0
+ VPALIGNR $12, BB1, BB1, BB1; VPALIGNR $8, CC1, CC1, CC1; VPALIGNR $4, DD1, DD1, DD1
+ VPALIGNR $12, BB2, BB2, BB2; VPALIGNR $8, CC2, CC2, CC2; VPALIGNR $4, DD2, DD2, DD2
+ VPALIGNR $12, BB3, BB3, BB3; VPALIGNR $8, CC3, CC3, CC3; VPALIGNR $4, DD3, DD3, DD3
+ DECQ itr2
+ JNE sealAVX2IntroLoop
+
+ VPADDD ·chacha20Constants<>(SB), AA0, AA0; VPADDD ·chacha20Constants<>(SB), AA1, AA1; VPADDD ·chacha20Constants<>(SB), AA2, AA2; VPADDD ·chacha20Constants<>(SB), AA3, AA3
+ VPADDD state1StoreAVX2, BB0, BB0; VPADDD state1StoreAVX2, BB1, BB1; VPADDD state1StoreAVX2, BB2, BB2; VPADDD state1StoreAVX2, BB3, BB3
+ VPADDD state2StoreAVX2, CC0, CC0; VPADDD state2StoreAVX2, CC1, CC1; VPADDD state2StoreAVX2, CC2, CC2; VPADDD state2StoreAVX2, CC3, CC3
+ VPADDD ctr0StoreAVX2, DD0, DD0; VPADDD ctr1StoreAVX2, DD1, DD1; VPADDD ctr2StoreAVX2, DD2, DD2; VPADDD ctr3StoreAVX2, DD3, DD3
+
+ VPERM2I128 $0x13, CC0, DD0, CC0 // Stream bytes 96 - 127
+ VPERM2I128 $0x02, AA0, BB0, DD0 // The Poly1305 key
+ VPERM2I128 $0x13, AA0, BB0, AA0 // Stream bytes 64 - 95
+
+ // Clamp and store poly key
+ VPAND ·polyClampMask<>(SB), DD0, DD0
+ VMOVDQA DD0, rsStoreAVX2
+
+ // Hash AD
+ MOVQ ad_len+80(FP), itr2
+ CALL polyHashADInternal(SB)
+
+ // Can store at least 320 bytes
+ VPXOR (0*32)(inp), AA0, AA0
+ VPXOR (1*32)(inp), CC0, CC0
+ VMOVDQU AA0, (0*32)(oup)
+ VMOVDQU CC0, (1*32)(oup)
+
+ VPERM2I128 $0x02, AA1, BB1, AA0; VPERM2I128 $0x02, CC1, DD1, BB0; VPERM2I128 $0x13, AA1, BB1, CC0; VPERM2I128 $0x13, CC1, DD1, DD0
+ VPXOR (2*32)(inp), AA0, AA0; VPXOR (3*32)(inp), BB0, BB0; VPXOR (4*32)(inp), CC0, CC0; VPXOR (5*32)(inp), DD0, DD0
+ VMOVDQU AA0, (2*32)(oup); VMOVDQU BB0, (3*32)(oup); VMOVDQU CC0, (4*32)(oup); VMOVDQU DD0, (5*32)(oup)
+ VPERM2I128 $0x02, AA2, BB2, AA0; VPERM2I128 $0x02, CC2, DD2, BB0; VPERM2I128 $0x13, AA2, BB2, CC0; VPERM2I128 $0x13, CC2, DD2, DD0
+ VPXOR (6*32)(inp), AA0, AA0; VPXOR (7*32)(inp), BB0, BB0; VPXOR (8*32)(inp), CC0, CC0; VPXOR (9*32)(inp), DD0, DD0
+ VMOVDQU AA0, (6*32)(oup); VMOVDQU BB0, (7*32)(oup); VMOVDQU CC0, (8*32)(oup); VMOVDQU DD0, (9*32)(oup)
+
+ MOVQ $320, itr1
+ SUBQ $320, inl
+ LEAQ 320(inp), inp
+
+ VPERM2I128 $0x02, AA3, BB3, AA0; VPERM2I128 $0x02, CC3, DD3, BB0; VPERM2I128 $0x13, AA3, BB3, CC0; VPERM2I128 $0x13, CC3, DD3, DD0
+ CMPQ inl, $128
+ JBE sealAVX2SealHash
+
+ VPXOR (0*32)(inp), AA0, AA0; VPXOR (1*32)(inp), BB0, BB0; VPXOR (2*32)(inp), CC0, CC0; VPXOR (3*32)(inp), DD0, DD0
+ VMOVDQU AA0, (10*32)(oup); VMOVDQU BB0, (11*32)(oup); VMOVDQU CC0, (12*32)(oup); VMOVDQU DD0, (13*32)(oup)
+ SUBQ $128, inl
+ LEAQ 128(inp), inp
+
+ MOVQ $8, itr1
+ MOVQ $2, itr2
+
+ CMPQ inl, $128
+ JBE sealAVX2Tail128
+ CMPQ inl, $256
+ JBE sealAVX2Tail256
+ CMPQ inl, $384
+ JBE sealAVX2Tail384
+ CMPQ inl, $512
+ JBE sealAVX2Tail512
+
+ // We have 448 bytes to hash, but main loop hashes 512 bytes at a time - perform some rounds, before the main loop
+ VMOVDQA ·chacha20Constants<>(SB), AA0; VMOVDQA AA0, AA1; VMOVDQA AA0, AA2; VMOVDQA AA0, AA3
+ VMOVDQA state1StoreAVX2, BB0; VMOVDQA BB0, BB1; VMOVDQA BB0, BB2; VMOVDQA BB0, BB3
+ VMOVDQA state2StoreAVX2, CC0; VMOVDQA CC0, CC1; VMOVDQA CC0, CC2; VMOVDQA CC0, CC3
+ VMOVDQA ctr3StoreAVX2, DD0
+ VPADDD ·avx2IncMask<>(SB), DD0, DD0; VPADDD ·avx2IncMask<>(SB), DD0, DD1; VPADDD ·avx2IncMask<>(SB), DD1, DD2; VPADDD ·avx2IncMask<>(SB), DD2, DD3
+ VMOVDQA DD0, ctr0StoreAVX2; VMOVDQA DD1, ctr1StoreAVX2; VMOVDQA DD2, ctr2StoreAVX2; VMOVDQA DD3, ctr3StoreAVX2
+
+ VMOVDQA CC3, tmpStoreAVX2
+ chachaQR_AVX2(AA0, BB0, CC0, DD0, CC3); chachaQR_AVX2(AA1, BB1, CC1, DD1, CC3); chachaQR_AVX2(AA2, BB2, CC2, DD2, CC3)
+ VMOVDQA tmpStoreAVX2, CC3
+ VMOVDQA CC1, tmpStoreAVX2
+ chachaQR_AVX2(AA3, BB3, CC3, DD3, CC1)
+ VMOVDQA tmpStoreAVX2, CC1
+
+ VPALIGNR $4, BB0, BB0, BB0; VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $12, DD0, DD0, DD0
+ VPALIGNR $4, BB1, BB1, BB1; VPALIGNR $8, CC1, CC1, CC1; VPALIGNR $12, DD1, DD1, DD1
+ VPALIGNR $4, BB2, BB2, BB2; VPALIGNR $8, CC2, CC2, CC2; VPALIGNR $12, DD2, DD2, DD2
+ VPALIGNR $4, BB3, BB3, BB3; VPALIGNR $8, CC3, CC3, CC3; VPALIGNR $12, DD3, DD3, DD3
+
+ VMOVDQA CC3, tmpStoreAVX2
+ chachaQR_AVX2(AA0, BB0, CC0, DD0, CC3); chachaQR_AVX2(AA1, BB1, CC1, DD1, CC3); chachaQR_AVX2(AA2, BB2, CC2, DD2, CC3)
+ VMOVDQA tmpStoreAVX2, CC3
+ VMOVDQA CC1, tmpStoreAVX2
+ chachaQR_AVX2(AA3, BB3, CC3, DD3, CC1)
+ VMOVDQA tmpStoreAVX2, CC1
+
+ VPALIGNR $12, BB0, BB0, BB0; VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $4, DD0, DD0, DD0
+ VPALIGNR $12, BB1, BB1, BB1; VPALIGNR $8, CC1, CC1, CC1; VPALIGNR $4, DD1, DD1, DD1
+ VPALIGNR $12, BB2, BB2, BB2; VPALIGNR $8, CC2, CC2, CC2; VPALIGNR $4, DD2, DD2, DD2
+ VPALIGNR $12, BB3, BB3, BB3; VPALIGNR $8, CC3, CC3, CC3; VPALIGNR $4, DD3, DD3, DD3
+ VPADDD BB0, AA0, AA0; VPADDD BB1, AA1, AA1; VPADDD BB2, AA2, AA2; VPADDD BB3, AA3, AA3
+ VPXOR AA0, DD0, DD0; VPXOR AA1, DD1, DD1; VPXOR AA2, DD2, DD2; VPXOR AA3, DD3, DD3
+ VPSHUFB ·rol16<>(SB), DD0, DD0; VPSHUFB ·rol16<>(SB), DD1, DD1; VPSHUFB ·rol16<>(SB), DD2, DD2; VPSHUFB ·rol16<>(SB), DD3, DD3
+ VPADDD DD0, CC0, CC0; VPADDD DD1, CC1, CC1; VPADDD DD2, CC2, CC2; VPADDD DD3, CC3, CC3
+ VPXOR CC0, BB0, BB0; VPXOR CC1, BB1, BB1; VPXOR CC2, BB2, BB2; VPXOR CC3, BB3, BB3
+ VMOVDQA CC3, tmpStoreAVX2
+ VPSLLD $12, BB0, CC3; VPSRLD $20, BB0, BB0; VPXOR CC3, BB0, BB0
+ VPSLLD $12, BB1, CC3; VPSRLD $20, BB1, BB1; VPXOR CC3, BB1, BB1
+ VPSLLD $12, BB2, CC3; VPSRLD $20, BB2, BB2; VPXOR CC3, BB2, BB2
+ VPSLLD $12, BB3, CC3; VPSRLD $20, BB3, BB3; VPXOR CC3, BB3, BB3
+ VMOVDQA tmpStoreAVX2, CC3
+
+ SUBQ $16, oup // Adjust the pointer
+ MOVQ $9, itr1
+ JMP sealAVX2InternalLoopStart
+
+sealAVX2MainLoop:
+ // Load state, increment counter blocks, store the incremented counters
+ VMOVDQU ·chacha20Constants<>(SB), AA0; VMOVDQA AA0, AA1; VMOVDQA AA0, AA2; VMOVDQA AA0, AA3
+ VMOVDQA state1StoreAVX2, BB0; VMOVDQA BB0, BB1; VMOVDQA BB0, BB2; VMOVDQA BB0, BB3
+ VMOVDQA state2StoreAVX2, CC0; VMOVDQA CC0, CC1; VMOVDQA CC0, CC2; VMOVDQA CC0, CC3
+ VMOVDQA ctr3StoreAVX2, DD0; VPADDD ·avx2IncMask<>(SB), DD0, DD0; VPADDD ·avx2IncMask<>(SB), DD0, DD1; VPADDD ·avx2IncMask<>(SB), DD1, DD2; VPADDD ·avx2IncMask<>(SB), DD2, DD3
+ VMOVDQA DD0, ctr0StoreAVX2; VMOVDQA DD1, ctr1StoreAVX2; VMOVDQA DD2, ctr2StoreAVX2; VMOVDQA DD3, ctr3StoreAVX2
+ MOVQ $10, itr1
+
+sealAVX2InternalLoop:
+ polyAdd(0*8(oup))
+ VPADDD BB0, AA0, AA0; VPADDD BB1, AA1, AA1; VPADDD BB2, AA2, AA2; VPADDD BB3, AA3, AA3
+ polyMulStage1_AVX2
+ VPXOR AA0, DD0, DD0; VPXOR AA1, DD1, DD1; VPXOR AA2, DD2, DD2; VPXOR AA3, DD3, DD3
+ VPSHUFB ·rol16<>(SB), DD0, DD0; VPSHUFB ·rol16<>(SB), DD1, DD1; VPSHUFB ·rol16<>(SB), DD2, DD2; VPSHUFB ·rol16<>(SB), DD3, DD3
+ polyMulStage2_AVX2
+ VPADDD DD0, CC0, CC0; VPADDD DD1, CC1, CC1; VPADDD DD2, CC2, CC2; VPADDD DD3, CC3, CC3
+ VPXOR CC0, BB0, BB0; VPXOR CC1, BB1, BB1; VPXOR CC2, BB2, BB2; VPXOR CC3, BB3, BB3
+ polyMulStage3_AVX2
+ VMOVDQA CC3, tmpStoreAVX2
+ VPSLLD $12, BB0, CC3; VPSRLD $20, BB0, BB0; VPXOR CC3, BB0, BB0
+ VPSLLD $12, BB1, CC3; VPSRLD $20, BB1, BB1; VPXOR CC3, BB1, BB1
+ VPSLLD $12, BB2, CC3; VPSRLD $20, BB2, BB2; VPXOR CC3, BB2, BB2
+ VPSLLD $12, BB3, CC3; VPSRLD $20, BB3, BB3; VPXOR CC3, BB3, BB3
+ VMOVDQA tmpStoreAVX2, CC3
+ polyMulReduceStage
+
+sealAVX2InternalLoopStart:
+ VPADDD BB0, AA0, AA0; VPADDD BB1, AA1, AA1; VPADDD BB2, AA2, AA2; VPADDD BB3, AA3, AA3
+ VPXOR AA0, DD0, DD0; VPXOR AA1, DD1, DD1; VPXOR AA2, DD2, DD2; VPXOR AA3, DD3, DD3
+ VPSHUFB ·rol8<>(SB), DD0, DD0; VPSHUFB ·rol8<>(SB), DD1, DD1; VPSHUFB ·rol8<>(SB), DD2, DD2; VPSHUFB ·rol8<>(SB), DD3, DD3
+ polyAdd(2*8(oup))
+ VPADDD DD0, CC0, CC0; VPADDD DD1, CC1, CC1; VPADDD DD2, CC2, CC2; VPADDD DD3, CC3, CC3
+ polyMulStage1_AVX2
+ VPXOR CC0, BB0, BB0; VPXOR CC1, BB1, BB1; VPXOR CC2, BB2, BB2; VPXOR CC3, BB3, BB3
+ VMOVDQA CC3, tmpStoreAVX2
+ VPSLLD $7, BB0, CC3; VPSRLD $25, BB0, BB0; VPXOR CC3, BB0, BB0
+ VPSLLD $7, BB1, CC3; VPSRLD $25, BB1, BB1; VPXOR CC3, BB1, BB1
+ VPSLLD $7, BB2, CC3; VPSRLD $25, BB2, BB2; VPXOR CC3, BB2, BB2
+ VPSLLD $7, BB3, CC3; VPSRLD $25, BB3, BB3; VPXOR CC3, BB3, BB3
+ VMOVDQA tmpStoreAVX2, CC3
+ polyMulStage2_AVX2
+ VPALIGNR $4, BB0, BB0, BB0; VPALIGNR $4, BB1, BB1, BB1; VPALIGNR $4, BB2, BB2, BB2; VPALIGNR $4, BB3, BB3, BB3
+ VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1; VPALIGNR $8, CC2, CC2, CC2; VPALIGNR $8, CC3, CC3, CC3
+ VPALIGNR $12, DD0, DD0, DD0; VPALIGNR $12, DD1, DD1, DD1; VPALIGNR $12, DD2, DD2, DD2; VPALIGNR $12, DD3, DD3, DD3
+ VPADDD BB0, AA0, AA0; VPADDD BB1, AA1, AA1; VPADDD BB2, AA2, AA2; VPADDD BB3, AA3, AA3
+ polyMulStage3_AVX2
+ VPXOR AA0, DD0, DD0; VPXOR AA1, DD1, DD1; VPXOR AA2, DD2, DD2; VPXOR AA3, DD3, DD3
+ VPSHUFB ·rol16<>(SB), DD0, DD0; VPSHUFB ·rol16<>(SB), DD1, DD1; VPSHUFB ·rol16<>(SB), DD2, DD2; VPSHUFB ·rol16<>(SB), DD3, DD3
+ polyMulReduceStage
+ VPADDD DD0, CC0, CC0; VPADDD DD1, CC1, CC1; VPADDD DD2, CC2, CC2; VPADDD DD3, CC3, CC3
+ VPXOR CC0, BB0, BB0; VPXOR CC1, BB1, BB1; VPXOR CC2, BB2, BB2; VPXOR CC3, BB3, BB3
+ polyAdd(4*8(oup))
+ LEAQ (6*8)(oup), oup
+ VMOVDQA CC3, tmpStoreAVX2
+ VPSLLD $12, BB0, CC3; VPSRLD $20, BB0, BB0; VPXOR CC3, BB0, BB0
+ VPSLLD $12, BB1, CC3; VPSRLD $20, BB1, BB1; VPXOR CC3, BB1, BB1
+ VPSLLD $12, BB2, CC3; VPSRLD $20, BB2, BB2; VPXOR CC3, BB2, BB2
+ VPSLLD $12, BB3, CC3; VPSRLD $20, BB3, BB3; VPXOR CC3, BB3, BB3
+ VMOVDQA tmpStoreAVX2, CC3
+ polyMulStage1_AVX2
+ VPADDD BB0, AA0, AA0; VPADDD BB1, AA1, AA1; VPADDD BB2, AA2, AA2; VPADDD BB3, AA3, AA3
+ VPXOR AA0, DD0, DD0; VPXOR AA1, DD1, DD1; VPXOR AA2, DD2, DD2; VPXOR AA3, DD3, DD3
+ polyMulStage2_AVX2
+ VPSHUFB ·rol8<>(SB), DD0, DD0; VPSHUFB ·rol8<>(SB), DD1, DD1; VPSHUFB ·rol8<>(SB), DD2, DD2; VPSHUFB ·rol8<>(SB), DD3, DD3
+ VPADDD DD0, CC0, CC0; VPADDD DD1, CC1, CC1; VPADDD DD2, CC2, CC2; VPADDD DD3, CC3, CC3
+ polyMulStage3_AVX2
+ VPXOR CC0, BB0, BB0; VPXOR CC1, BB1, BB1; VPXOR CC2, BB2, BB2; VPXOR CC3, BB3, BB3
+ VMOVDQA CC3, tmpStoreAVX2
+ VPSLLD $7, BB0, CC3; VPSRLD $25, BB0, BB0; VPXOR CC3, BB0, BB0
+ VPSLLD $7, BB1, CC3; VPSRLD $25, BB1, BB1; VPXOR CC3, BB1, BB1
+ VPSLLD $7, BB2, CC3; VPSRLD $25, BB2, BB2; VPXOR CC3, BB2, BB2
+ VPSLLD $7, BB3, CC3; VPSRLD $25, BB3, BB3; VPXOR CC3, BB3, BB3
+ VMOVDQA tmpStoreAVX2, CC3
+ polyMulReduceStage
+ VPALIGNR $12, BB0, BB0, BB0; VPALIGNR $12, BB1, BB1, BB1; VPALIGNR $12, BB2, BB2, BB2; VPALIGNR $12, BB3, BB3, BB3
+ VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1; VPALIGNR $8, CC2, CC2, CC2; VPALIGNR $8, CC3, CC3, CC3
+ VPALIGNR $4, DD0, DD0, DD0; VPALIGNR $4, DD1, DD1, DD1; VPALIGNR $4, DD2, DD2, DD2; VPALIGNR $4, DD3, DD3, DD3
+ DECQ itr1
+ JNE sealAVX2InternalLoop
+
+ VPADDD ·chacha20Constants<>(SB), AA0, AA0; VPADDD ·chacha20Constants<>(SB), AA1, AA1; VPADDD ·chacha20Constants<>(SB), AA2, AA2; VPADDD ·chacha20Constants<>(SB), AA3, AA3
+ VPADDD state1StoreAVX2, BB0, BB0; VPADDD state1StoreAVX2, BB1, BB1; VPADDD state1StoreAVX2, BB2, BB2; VPADDD state1StoreAVX2, BB3, BB3
+ VPADDD state2StoreAVX2, CC0, CC0; VPADDD state2StoreAVX2, CC1, CC1; VPADDD state2StoreAVX2, CC2, CC2; VPADDD state2StoreAVX2, CC3, CC3
+ VPADDD ctr0StoreAVX2, DD0, DD0; VPADDD ctr1StoreAVX2, DD1, DD1; VPADDD ctr2StoreAVX2, DD2, DD2; VPADDD ctr3StoreAVX2, DD3, DD3
+ VMOVDQA CC3, tmpStoreAVX2
+
+ // We only hashed 480 of the 512 bytes available - hash the remaining 32 here
+ polyAdd(0*8(oup))
+ polyMulAVX2
+ LEAQ (4*8)(oup), oup
+ VPERM2I128 $0x02, AA0, BB0, CC3; VPERM2I128 $0x13, AA0, BB0, BB0; VPERM2I128 $0x02, CC0, DD0, AA0; VPERM2I128 $0x13, CC0, DD0, CC0
+ VPXOR (0*32)(inp), CC3, CC3; VPXOR (1*32)(inp), AA0, AA0; VPXOR (2*32)(inp), BB0, BB0; VPXOR (3*32)(inp), CC0, CC0
+ VMOVDQU CC3, (0*32)(oup); VMOVDQU AA0, (1*32)(oup); VMOVDQU BB0, (2*32)(oup); VMOVDQU CC0, (3*32)(oup)
+ VPERM2I128 $0x02, AA1, BB1, AA0; VPERM2I128 $0x02, CC1, DD1, BB0; VPERM2I128 $0x13, AA1, BB1, CC0; VPERM2I128 $0x13, CC1, DD1, DD0
+ VPXOR (4*32)(inp), AA0, AA0; VPXOR (5*32)(inp), BB0, BB0; VPXOR (6*32)(inp), CC0, CC0; VPXOR (7*32)(inp), DD0, DD0
+ VMOVDQU AA0, (4*32)(oup); VMOVDQU BB0, (5*32)(oup); VMOVDQU CC0, (6*32)(oup); VMOVDQU DD0, (7*32)(oup)
+
+ // and here
+ polyAdd(-2*8(oup))
+ polyMulAVX2
+ VPERM2I128 $0x02, AA2, BB2, AA0; VPERM2I128 $0x02, CC2, DD2, BB0; VPERM2I128 $0x13, AA2, BB2, CC0; VPERM2I128 $0x13, CC2, DD2, DD0
+ VPXOR (8*32)(inp), AA0, AA0; VPXOR (9*32)(inp), BB0, BB0; VPXOR (10*32)(inp), CC0, CC0; VPXOR (11*32)(inp), DD0, DD0
+ VMOVDQU AA0, (8*32)(oup); VMOVDQU BB0, (9*32)(oup); VMOVDQU CC0, (10*32)(oup); VMOVDQU DD0, (11*32)(oup)
+ VPERM2I128 $0x02, AA3, BB3, AA0; VPERM2I128 $0x02, tmpStoreAVX2, DD3, BB0; VPERM2I128 $0x13, AA3, BB3, CC0; VPERM2I128 $0x13, tmpStoreAVX2, DD3, DD0
+ VPXOR (12*32)(inp), AA0, AA0; VPXOR (13*32)(inp), BB0, BB0; VPXOR (14*32)(inp), CC0, CC0; VPXOR (15*32)(inp), DD0, DD0
+ VMOVDQU AA0, (12*32)(oup); VMOVDQU BB0, (13*32)(oup); VMOVDQU CC0, (14*32)(oup); VMOVDQU DD0, (15*32)(oup)
+ LEAQ (32*16)(inp), inp
+ SUBQ $(32*16), inl
+ CMPQ inl, $512
+ JG sealAVX2MainLoop
+
+ // Tail can only hash 480 bytes
+ polyAdd(0*8(oup))
+ polyMulAVX2
+ polyAdd(2*8(oup))
+ polyMulAVX2
+ LEAQ 32(oup), oup
+
+ MOVQ $10, itr1
+ MOVQ $0, itr2
+ CMPQ inl, $128
+ JBE sealAVX2Tail128
+ CMPQ inl, $256
+ JBE sealAVX2Tail256
+ CMPQ inl, $384
+ JBE sealAVX2Tail384
+ JMP sealAVX2Tail512
+
+// ----------------------------------------------------------------------------
+// Special optimization for buffers smaller than 193 bytes
+seal192AVX2:
+ // For up to 192 bytes of ciphertext and 64 bytes for the poly key, we process four blocks
+ VMOVDQA AA0, AA1
+ VMOVDQA BB0, BB1
+ VMOVDQA CC0, CC1
+ VPADDD ·avx2IncMask<>(SB), DD0, DD1
+ VMOVDQA AA0, AA2
+ VMOVDQA BB0, BB2
+ VMOVDQA CC0, CC2
+ VMOVDQA DD0, DD2
+ VMOVDQA DD1, TT3
+ MOVQ $10, itr2
+
+sealAVX2192InnerCipherLoop:
+ chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0); chachaQR_AVX2(AA1, BB1, CC1, DD1, TT0)
+ VPALIGNR $4, BB0, BB0, BB0; VPALIGNR $4, BB1, BB1, BB1
+ VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1
+ VPALIGNR $12, DD0, DD0, DD0; VPALIGNR $12, DD1, DD1, DD1
+ chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0); chachaQR_AVX2(AA1, BB1, CC1, DD1, TT0)
+ VPALIGNR $12, BB0, BB0, BB0; VPALIGNR $12, BB1, BB1, BB1
+ VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1
+ VPALIGNR $4, DD0, DD0, DD0; VPALIGNR $4, DD1, DD1, DD1
+ DECQ itr2
+ JNE sealAVX2192InnerCipherLoop
+ VPADDD AA2, AA0, AA0; VPADDD AA2, AA1, AA1
+ VPADDD BB2, BB0, BB0; VPADDD BB2, BB1, BB1
+ VPADDD CC2, CC0, CC0; VPADDD CC2, CC1, CC1
+ VPADDD DD2, DD0, DD0; VPADDD TT3, DD1, DD1
+ VPERM2I128 $0x02, AA0, BB0, TT0
+
+ // Clamp and store poly key
+ VPAND ·polyClampMask<>(SB), TT0, TT0
+ VMOVDQA TT0, rsStoreAVX2
+
+ // Stream for up to 192 bytes
+ VPERM2I128 $0x13, AA0, BB0, AA0
+ VPERM2I128 $0x13, CC0, DD0, BB0
+ VPERM2I128 $0x02, AA1, BB1, CC0
+ VPERM2I128 $0x02, CC1, DD1, DD0
+ VPERM2I128 $0x13, AA1, BB1, AA1
+ VPERM2I128 $0x13, CC1, DD1, BB1
+
+sealAVX2ShortSeal:
+ // Hash aad
+ MOVQ ad_len+80(FP), itr2
+ CALL polyHashADInternal(SB)
+ XORQ itr1, itr1
+
+sealAVX2SealHash:
+ // itr1 holds the number of bytes encrypted but not yet hashed
+ CMPQ itr1, $16
+ JB sealAVX2ShortSealLoop
+ polyAdd(0(oup))
+ polyMul
+ SUBQ $16, itr1
+ ADDQ $16, oup
+ JMP sealAVX2SealHash
+
+sealAVX2ShortSealLoop:
+ CMPQ inl, $32
+ JB sealAVX2ShortTail32
+ SUBQ $32, inl
+
+ // Load for encryption
+ VPXOR (inp), AA0, AA0
+ VMOVDQU AA0, (oup)
+ LEAQ (1*32)(inp), inp
+
+ // Now can hash
+ polyAdd(0*8(oup))
+ polyMulAVX2
+ polyAdd(2*8(oup))
+ polyMulAVX2
+ LEAQ (1*32)(oup), oup
+
+ // Shift stream left
+ VMOVDQA BB0, AA0
+ VMOVDQA CC0, BB0
+ VMOVDQA DD0, CC0
+ VMOVDQA AA1, DD0
+ VMOVDQA BB1, AA1
+ VMOVDQA CC1, BB1
+ VMOVDQA DD1, CC1
+ VMOVDQA AA2, DD1
+ VMOVDQA BB2, AA2
+ JMP sealAVX2ShortSealLoop
+
+sealAVX2ShortTail32:
+ CMPQ inl, $16
+ VMOVDQA A0, A1
+ JB sealAVX2ShortDone
+
+ SUBQ $16, inl
+
+ // Load for encryption
+ VPXOR (inp), A0, T0
+ VMOVDQU T0, (oup)
+ LEAQ (1*16)(inp), inp
+
+ // Hash
+ polyAdd(0*8(oup))
+ polyMulAVX2
+ LEAQ (1*16)(oup), oup
+ VPERM2I128 $0x11, AA0, AA0, AA0
+ VMOVDQA A0, A1
+
+sealAVX2ShortDone:
+ VZEROUPPER
+ JMP sealSSETail
+
+// ----------------------------------------------------------------------------
+// Special optimization for buffers smaller than 321 bytes
+seal320AVX2:
+ // For up to 320 bytes of ciphertext and 64 bytes for the poly key, we process six blocks
+ VMOVDQA AA0, AA1; VMOVDQA BB0, BB1; VMOVDQA CC0, CC1; VPADDD ·avx2IncMask<>(SB), DD0, DD1
+ VMOVDQA AA0, AA2; VMOVDQA BB0, BB2; VMOVDQA CC0, CC2; VPADDD ·avx2IncMask<>(SB), DD1, DD2
+ VMOVDQA BB0, TT1; VMOVDQA CC0, TT2; VMOVDQA DD0, TT3
+ MOVQ $10, itr2
+
+sealAVX2320InnerCipherLoop:
+ chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0); chachaQR_AVX2(AA1, BB1, CC1, DD1, TT0); chachaQR_AVX2(AA2, BB2, CC2, DD2, TT0)
+ VPALIGNR $4, BB0, BB0, BB0; VPALIGNR $4, BB1, BB1, BB1; VPALIGNR $4, BB2, BB2, BB2
+ VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1; VPALIGNR $8, CC2, CC2, CC2
+ VPALIGNR $12, DD0, DD0, DD0; VPALIGNR $12, DD1, DD1, DD1; VPALIGNR $12, DD2, DD2, DD2
+ chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0); chachaQR_AVX2(AA1, BB1, CC1, DD1, TT0); chachaQR_AVX2(AA2, BB2, CC2, DD2, TT0)
+ VPALIGNR $12, BB0, BB0, BB0; VPALIGNR $12, BB1, BB1, BB1; VPALIGNR $12, BB2, BB2, BB2
+ VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1; VPALIGNR $8, CC2, CC2, CC2
+ VPALIGNR $4, DD0, DD0, DD0; VPALIGNR $4, DD1, DD1, DD1; VPALIGNR $4, DD2, DD2, DD2
+ DECQ itr2
+ JNE sealAVX2320InnerCipherLoop
+
+ VMOVDQA ·chacha20Constants<>(SB), TT0
+ VPADDD TT0, AA0, AA0; VPADDD TT0, AA1, AA1; VPADDD TT0, AA2, AA2
+ VPADDD TT1, BB0, BB0; VPADDD TT1, BB1, BB1; VPADDD TT1, BB2, BB2
+ VPADDD TT2, CC0, CC0; VPADDD TT2, CC1, CC1; VPADDD TT2, CC2, CC2
+ VMOVDQA ·avx2IncMask<>(SB), TT0
+ VPADDD TT3, DD0, DD0; VPADDD TT0, TT3, TT3
+ VPADDD TT3, DD1, DD1; VPADDD TT0, TT3, TT3
+ VPADDD TT3, DD2, DD2
+
+ // Clamp and store poly key
+ VPERM2I128 $0x02, AA0, BB0, TT0
+ VPAND ·polyClampMask<>(SB), TT0, TT0
+ VMOVDQA TT0, rsStoreAVX2
+
+ // Stream for up to 320 bytes
+ VPERM2I128 $0x13, AA0, BB0, AA0
+ VPERM2I128 $0x13, CC0, DD0, BB0
+ VPERM2I128 $0x02, AA1, BB1, CC0
+ VPERM2I128 $0x02, CC1, DD1, DD0
+ VPERM2I128 $0x13, AA1, BB1, AA1
+ VPERM2I128 $0x13, CC1, DD1, BB1
+ VPERM2I128 $0x02, AA2, BB2, CC1
+ VPERM2I128 $0x02, CC2, DD2, DD1
+ VPERM2I128 $0x13, AA2, BB2, AA2
+ VPERM2I128 $0x13, CC2, DD2, BB2
+ JMP sealAVX2ShortSeal
+
+// ----------------------------------------------------------------------------
+// Special optimization for the last 128 bytes of ciphertext
+sealAVX2Tail128:
+ // Need to decrypt up to 128 bytes - prepare two blocks
+ // If we got here after the main loop - there are 512 encrypted bytes waiting to be hashed
+ // If we got here before the main loop - there are 448 encrpyred bytes waiting to be hashed
+ VMOVDQA ·chacha20Constants<>(SB), AA0
+ VMOVDQA state1StoreAVX2, BB0
+ VMOVDQA state2StoreAVX2, CC0
+ VMOVDQA ctr3StoreAVX2, DD0
+ VPADDD ·avx2IncMask<>(SB), DD0, DD0
+ VMOVDQA DD0, DD1
+
+sealAVX2Tail128LoopA:
+ polyAdd(0(oup))
+ polyMul
+ LEAQ 16(oup), oup
+
+sealAVX2Tail128LoopB:
+ chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0)
+ polyAdd(0(oup))
+ polyMul
+ VPALIGNR $4, BB0, BB0, BB0
+ VPALIGNR $8, CC0, CC0, CC0
+ VPALIGNR $12, DD0, DD0, DD0
+ chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0)
+ polyAdd(16(oup))
+ polyMul
+ LEAQ 32(oup), oup
+ VPALIGNR $12, BB0, BB0, BB0
+ VPALIGNR $8, CC0, CC0, CC0
+ VPALIGNR $4, DD0, DD0, DD0
+ DECQ itr1
+ JG sealAVX2Tail128LoopA
+ DECQ itr2
+ JGE sealAVX2Tail128LoopB
+
+ VPADDD ·chacha20Constants<>(SB), AA0, AA1
+ VPADDD state1StoreAVX2, BB0, BB1
+ VPADDD state2StoreAVX2, CC0, CC1
+ VPADDD DD1, DD0, DD1
+
+ VPERM2I128 $0x02, AA1, BB1, AA0
+ VPERM2I128 $0x02, CC1, DD1, BB0
+ VPERM2I128 $0x13, AA1, BB1, CC0
+ VPERM2I128 $0x13, CC1, DD1, DD0
+ JMP sealAVX2ShortSealLoop
+
+// ----------------------------------------------------------------------------
+// Special optimization for the last 256 bytes of ciphertext
+sealAVX2Tail256:
+ // Need to decrypt up to 256 bytes - prepare two blocks
+ // If we got here after the main loop - there are 512 encrypted bytes waiting to be hashed
+ // If we got here before the main loop - there are 448 encrpyred bytes waiting to be hashed
+ VMOVDQA ·chacha20Constants<>(SB), AA0; VMOVDQA ·chacha20Constants<>(SB), AA1
+ VMOVDQA state1StoreAVX2, BB0; VMOVDQA state1StoreAVX2, BB1
+ VMOVDQA state2StoreAVX2, CC0; VMOVDQA state2StoreAVX2, CC1
+ VMOVDQA ctr3StoreAVX2, DD0
+ VPADDD ·avx2IncMask<>(SB), DD0, DD0
+ VPADDD ·avx2IncMask<>(SB), DD0, DD1
+ VMOVDQA DD0, TT1
+ VMOVDQA DD1, TT2
+
+sealAVX2Tail256LoopA:
+ polyAdd(0(oup))
+ polyMul
+ LEAQ 16(oup), oup
+
+sealAVX2Tail256LoopB:
+ chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0); chachaQR_AVX2(AA1, BB1, CC1, DD1, TT0)
+ polyAdd(0(oup))
+ polyMul
+ VPALIGNR $4, BB0, BB0, BB0; VPALIGNR $4, BB1, BB1, BB1
+ VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1
+ VPALIGNR $12, DD0, DD0, DD0; VPALIGNR $12, DD1, DD1, DD1
+ chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0); chachaQR_AVX2(AA1, BB1, CC1, DD1, TT0)
+ polyAdd(16(oup))
+ polyMul
+ LEAQ 32(oup), oup
+ VPALIGNR $12, BB0, BB0, BB0; VPALIGNR $12, BB1, BB1, BB1
+ VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1
+ VPALIGNR $4, DD0, DD0, DD0; VPALIGNR $4, DD1, DD1, DD1
+ DECQ itr1
+ JG sealAVX2Tail256LoopA
+ DECQ itr2
+ JGE sealAVX2Tail256LoopB
+
+ VPADDD ·chacha20Constants<>(SB), AA0, AA0; VPADDD ·chacha20Constants<>(SB), AA1, AA1
+ VPADDD state1StoreAVX2, BB0, BB0; VPADDD state1StoreAVX2, BB1, BB1
+ VPADDD state2StoreAVX2, CC0, CC0; VPADDD state2StoreAVX2, CC1, CC1
+ VPADDD TT1, DD0, DD0; VPADDD TT2, DD1, DD1
+ VPERM2I128 $0x02, AA0, BB0, TT0
+ VPERM2I128 $0x02, CC0, DD0, TT1
+ VPERM2I128 $0x13, AA0, BB0, TT2
+ VPERM2I128 $0x13, CC0, DD0, TT3
+ VPXOR (0*32)(inp), TT0, TT0; VPXOR (1*32)(inp), TT1, TT1; VPXOR (2*32)(inp), TT2, TT2; VPXOR (3*32)(inp), TT3, TT3
+ VMOVDQU TT0, (0*32)(oup); VMOVDQU TT1, (1*32)(oup); VMOVDQU TT2, (2*32)(oup); VMOVDQU TT3, (3*32)(oup)
+ MOVQ $128, itr1
+ LEAQ 128(inp), inp
+ SUBQ $128, inl
+ VPERM2I128 $0x02, AA1, BB1, AA0
+ VPERM2I128 $0x02, CC1, DD1, BB0
+ VPERM2I128 $0x13, AA1, BB1, CC0
+ VPERM2I128 $0x13, CC1, DD1, DD0
+
+ JMP sealAVX2SealHash
+
+// ----------------------------------------------------------------------------
+// Special optimization for the last 384 bytes of ciphertext
+sealAVX2Tail384:
+ // Need to decrypt up to 384 bytes - prepare two blocks
+ // If we got here after the main loop - there are 512 encrypted bytes waiting to be hashed
+ // If we got here before the main loop - there are 448 encrpyred bytes waiting to be hashed
+ VMOVDQA ·chacha20Constants<>(SB), AA0; VMOVDQA AA0, AA1; VMOVDQA AA0, AA2
+ VMOVDQA state1StoreAVX2, BB0; VMOVDQA BB0, BB1; VMOVDQA BB0, BB2
+ VMOVDQA state2StoreAVX2, CC0; VMOVDQA CC0, CC1; VMOVDQA CC0, CC2
+ VMOVDQA ctr3StoreAVX2, DD0
+ VPADDD ·avx2IncMask<>(SB), DD0, DD0; VPADDD ·avx2IncMask<>(SB), DD0, DD1; VPADDD ·avx2IncMask<>(SB), DD1, DD2
+ VMOVDQA DD0, TT1; VMOVDQA DD1, TT2; VMOVDQA DD2, TT3
+
+sealAVX2Tail384LoopA:
+ polyAdd(0(oup))
+ polyMul
+ LEAQ 16(oup), oup
+
+sealAVX2Tail384LoopB:
+ chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0); chachaQR_AVX2(AA1, BB1, CC1, DD1, TT0); chachaQR_AVX2(AA2, BB2, CC2, DD2, TT0)
+ polyAdd(0(oup))
+ polyMul
+ VPALIGNR $4, BB0, BB0, BB0; VPALIGNR $4, BB1, BB1, BB1; VPALIGNR $4, BB2, BB2, BB2
+ VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1; VPALIGNR $8, CC2, CC2, CC2
+ VPALIGNR $12, DD0, DD0, DD0; VPALIGNR $12, DD1, DD1, DD1; VPALIGNR $12, DD2, DD2, DD2
+ chachaQR_AVX2(AA0, BB0, CC0, DD0, TT0); chachaQR_AVX2(AA1, BB1, CC1, DD1, TT0); chachaQR_AVX2(AA2, BB2, CC2, DD2, TT0)
+ polyAdd(16(oup))
+ polyMul
+ LEAQ 32(oup), oup
+ VPALIGNR $12, BB0, BB0, BB0; VPALIGNR $12, BB1, BB1, BB1; VPALIGNR $12, BB2, BB2, BB2
+ VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1; VPALIGNR $8, CC2, CC2, CC2
+ VPALIGNR $4, DD0, DD0, DD0; VPALIGNR $4, DD1, DD1, DD1; VPALIGNR $4, DD2, DD2, DD2
+ DECQ itr1
+ JG sealAVX2Tail384LoopA
+ DECQ itr2
+ JGE sealAVX2Tail384LoopB
+
+ VPADDD ·chacha20Constants<>(SB), AA0, AA0; VPADDD ·chacha20Constants<>(SB), AA1, AA1; VPADDD ·chacha20Constants<>(SB), AA2, AA2
+ VPADDD state1StoreAVX2, BB0, BB0; VPADDD state1StoreAVX2, BB1, BB1; VPADDD state1StoreAVX2, BB2, BB2
+ VPADDD state2StoreAVX2, CC0, CC0; VPADDD state2StoreAVX2, CC1, CC1; VPADDD state2StoreAVX2, CC2, CC2
+ VPADDD TT1, DD0, DD0; VPADDD TT2, DD1, DD1; VPADDD TT3, DD2, DD2
+ VPERM2I128 $0x02, AA0, BB0, TT0
+ VPERM2I128 $0x02, CC0, DD0, TT1
+ VPERM2I128 $0x13, AA0, BB0, TT2
+ VPERM2I128 $0x13, CC0, DD0, TT3
+ VPXOR (0*32)(inp), TT0, TT0; VPXOR (1*32)(inp), TT1, TT1; VPXOR (2*32)(inp), TT2, TT2; VPXOR (3*32)(inp), TT3, TT3
+ VMOVDQU TT0, (0*32)(oup); VMOVDQU TT1, (1*32)(oup); VMOVDQU TT2, (2*32)(oup); VMOVDQU TT3, (3*32)(oup)
+ VPERM2I128 $0x02, AA1, BB1, TT0
+ VPERM2I128 $0x02, CC1, DD1, TT1
+ VPERM2I128 $0x13, AA1, BB1, TT2
+ VPERM2I128 $0x13, CC1, DD1, TT3
+ VPXOR (4*32)(inp), TT0, TT0; VPXOR (5*32)(inp), TT1, TT1; VPXOR (6*32)(inp), TT2, TT2; VPXOR (7*32)(inp), TT3, TT3
+ VMOVDQU TT0, (4*32)(oup); VMOVDQU TT1, (5*32)(oup); VMOVDQU TT2, (6*32)(oup); VMOVDQU TT3, (7*32)(oup)
+ MOVQ $256, itr1
+ LEAQ 256(inp), inp
+ SUBQ $256, inl
+ VPERM2I128 $0x02, AA2, BB2, AA0
+ VPERM2I128 $0x02, CC2, DD2, BB0
+ VPERM2I128 $0x13, AA2, BB2, CC0
+ VPERM2I128 $0x13, CC2, DD2, DD0
+
+ JMP sealAVX2SealHash
+
+// ----------------------------------------------------------------------------
+// Special optimization for the last 512 bytes of ciphertext
+sealAVX2Tail512:
+ // Need to decrypt up to 512 bytes - prepare two blocks
+ // If we got here after the main loop - there are 512 encrypted bytes waiting to be hashed
+ // If we got here before the main loop - there are 448 encrpyred bytes waiting to be hashed
+ VMOVDQA ·chacha20Constants<>(SB), AA0; VMOVDQA AA0, AA1; VMOVDQA AA0, AA2; VMOVDQA AA0, AA3
+ VMOVDQA state1StoreAVX2, BB0; VMOVDQA BB0, BB1; VMOVDQA BB0, BB2; VMOVDQA BB0, BB3
+ VMOVDQA state2StoreAVX2, CC0; VMOVDQA CC0, CC1; VMOVDQA CC0, CC2; VMOVDQA CC0, CC3
+ VMOVDQA ctr3StoreAVX2, DD0
+ VPADDD ·avx2IncMask<>(SB), DD0, DD0; VPADDD ·avx2IncMask<>(SB), DD0, DD1; VPADDD ·avx2IncMask<>(SB), DD1, DD2; VPADDD ·avx2IncMask<>(SB), DD2, DD3
+ VMOVDQA DD0, ctr0StoreAVX2; VMOVDQA DD1, ctr1StoreAVX2; VMOVDQA DD2, ctr2StoreAVX2; VMOVDQA DD3, ctr3StoreAVX2
+
+sealAVX2Tail512LoopA:
+ polyAdd(0(oup))
+ polyMul
+ LEAQ 16(oup), oup
+
+sealAVX2Tail512LoopB:
+ VPADDD BB0, AA0, AA0; VPADDD BB1, AA1, AA1; VPADDD BB2, AA2, AA2; VPADDD BB3, AA3, AA3
+ VPXOR AA0, DD0, DD0; VPXOR AA1, DD1, DD1; VPXOR AA2, DD2, DD2; VPXOR AA3, DD3, DD3
+ VPSHUFB ·rol16<>(SB), DD0, DD0; VPSHUFB ·rol16<>(SB), DD1, DD1; VPSHUFB ·rol16<>(SB), DD2, DD2; VPSHUFB ·rol16<>(SB), DD3, DD3
+ VPADDD DD0, CC0, CC0; VPADDD DD1, CC1, CC1; VPADDD DD2, CC2, CC2; VPADDD DD3, CC3, CC3
+ VPXOR CC0, BB0, BB0; VPXOR CC1, BB1, BB1; VPXOR CC2, BB2, BB2; VPXOR CC3, BB3, BB3
+ VMOVDQA CC3, tmpStoreAVX2
+ VPSLLD $12, BB0, CC3; VPSRLD $20, BB0, BB0; VPXOR CC3, BB0, BB0
+ VPSLLD $12, BB1, CC3; VPSRLD $20, BB1, BB1; VPXOR CC3, BB1, BB1
+ VPSLLD $12, BB2, CC3; VPSRLD $20, BB2, BB2; VPXOR CC3, BB2, BB2
+ VPSLLD $12, BB3, CC3; VPSRLD $20, BB3, BB3; VPXOR CC3, BB3, BB3
+ VMOVDQA tmpStoreAVX2, CC3
+ polyAdd(0*8(oup))
+ polyMulAVX2
+ VPADDD BB0, AA0, AA0; VPADDD BB1, AA1, AA1; VPADDD BB2, AA2, AA2; VPADDD BB3, AA3, AA3
+ VPXOR AA0, DD0, DD0; VPXOR AA1, DD1, DD1; VPXOR AA2, DD2, DD2; VPXOR AA3, DD3, DD3
+ VPSHUFB ·rol8<>(SB), DD0, DD0; VPSHUFB ·rol8<>(SB), DD1, DD1; VPSHUFB ·rol8<>(SB), DD2, DD2; VPSHUFB ·rol8<>(SB), DD3, DD3
+ VPADDD DD0, CC0, CC0; VPADDD DD1, CC1, CC1; VPADDD DD2, CC2, CC2; VPADDD DD3, CC3, CC3
+ VPXOR CC0, BB0, BB0; VPXOR CC1, BB1, BB1; VPXOR CC2, BB2, BB2; VPXOR CC3, BB3, BB3
+ VMOVDQA CC3, tmpStoreAVX2
+ VPSLLD $7, BB0, CC3; VPSRLD $25, BB0, BB0; VPXOR CC3, BB0, BB0
+ VPSLLD $7, BB1, CC3; VPSRLD $25, BB1, BB1; VPXOR CC3, BB1, BB1
+ VPSLLD $7, BB2, CC3; VPSRLD $25, BB2, BB2; VPXOR CC3, BB2, BB2
+ VPSLLD $7, BB3, CC3; VPSRLD $25, BB3, BB3; VPXOR CC3, BB3, BB3
+ VMOVDQA tmpStoreAVX2, CC3
+ VPALIGNR $4, BB0, BB0, BB0; VPALIGNR $4, BB1, BB1, BB1; VPALIGNR $4, BB2, BB2, BB2; VPALIGNR $4, BB3, BB3, BB3
+ VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1; VPALIGNR $8, CC2, CC2, CC2; VPALIGNR $8, CC3, CC3, CC3
+ VPALIGNR $12, DD0, DD0, DD0; VPALIGNR $12, DD1, DD1, DD1; VPALIGNR $12, DD2, DD2, DD2; VPALIGNR $12, DD3, DD3, DD3
+ VPADDD BB0, AA0, AA0; VPADDD BB1, AA1, AA1; VPADDD BB2, AA2, AA2; VPADDD BB3, AA3, AA3
+ VPXOR AA0, DD0, DD0; VPXOR AA1, DD1, DD1; VPXOR AA2, DD2, DD2; VPXOR AA3, DD3, DD3
+ VPSHUFB ·rol16<>(SB), DD0, DD0; VPSHUFB ·rol16<>(SB), DD1, DD1; VPSHUFB ·rol16<>(SB), DD2, DD2; VPSHUFB ·rol16<>(SB), DD3, DD3
+ VPADDD DD0, CC0, CC0; VPADDD DD1, CC1, CC1; VPADDD DD2, CC2, CC2; VPADDD DD3, CC3, CC3
+ VPXOR CC0, BB0, BB0; VPXOR CC1, BB1, BB1; VPXOR CC2, BB2, BB2; VPXOR CC3, BB3, BB3
+ polyAdd(2*8(oup))
+ polyMulAVX2
+ LEAQ (4*8)(oup), oup
+ VMOVDQA CC3, tmpStoreAVX2
+ VPSLLD $12, BB0, CC3; VPSRLD $20, BB0, BB0; VPXOR CC3, BB0, BB0
+ VPSLLD $12, BB1, CC3; VPSRLD $20, BB1, BB1; VPXOR CC3, BB1, BB1
+ VPSLLD $12, BB2, CC3; VPSRLD $20, BB2, BB2; VPXOR CC3, BB2, BB2
+ VPSLLD $12, BB3, CC3; VPSRLD $20, BB3, BB3; VPXOR CC3, BB3, BB3
+ VMOVDQA tmpStoreAVX2, CC3
+ VPADDD BB0, AA0, AA0; VPADDD BB1, AA1, AA1; VPADDD BB2, AA2, AA2; VPADDD BB3, AA3, AA3
+ VPXOR AA0, DD0, DD0; VPXOR AA1, DD1, DD1; VPXOR AA2, DD2, DD2; VPXOR AA3, DD3, DD3
+ VPSHUFB ·rol8<>(SB), DD0, DD0; VPSHUFB ·rol8<>(SB), DD1, DD1; VPSHUFB ·rol8<>(SB), DD2, DD2; VPSHUFB ·rol8<>(SB), DD3, DD3
+ VPADDD DD0, CC0, CC0; VPADDD DD1, CC1, CC1; VPADDD DD2, CC2, CC2; VPADDD DD3, CC3, CC3
+ VPXOR CC0, BB0, BB0; VPXOR CC1, BB1, BB1; VPXOR CC2, BB2, BB2; VPXOR CC3, BB3, BB3
+ VMOVDQA CC3, tmpStoreAVX2
+ VPSLLD $7, BB0, CC3; VPSRLD $25, BB0, BB0; VPXOR CC3, BB0, BB0
+ VPSLLD $7, BB1, CC3; VPSRLD $25, BB1, BB1; VPXOR CC3, BB1, BB1
+ VPSLLD $7, BB2, CC3; VPSRLD $25, BB2, BB2; VPXOR CC3, BB2, BB2
+ VPSLLD $7, BB3, CC3; VPSRLD $25, BB3, BB3; VPXOR CC3, BB3, BB3
+ VMOVDQA tmpStoreAVX2, CC3
+ VPALIGNR $12, BB0, BB0, BB0; VPALIGNR $12, BB1, BB1, BB1; VPALIGNR $12, BB2, BB2, BB2; VPALIGNR $12, BB3, BB3, BB3
+ VPALIGNR $8, CC0, CC0, CC0; VPALIGNR $8, CC1, CC1, CC1; VPALIGNR $8, CC2, CC2, CC2; VPALIGNR $8, CC3, CC3, CC3
+ VPALIGNR $4, DD0, DD0, DD0; VPALIGNR $4, DD1, DD1, DD1; VPALIGNR $4, DD2, DD2, DD2; VPALIGNR $4, DD3, DD3, DD3
+
+ DECQ itr1
+ JG sealAVX2Tail512LoopA
+ DECQ itr2
+ JGE sealAVX2Tail512LoopB
+
+ VPADDD ·chacha20Constants<>(SB), AA0, AA0; VPADDD ·chacha20Constants<>(SB), AA1, AA1; VPADDD ·chacha20Constants<>(SB), AA2, AA2; VPADDD ·chacha20Constants<>(SB), AA3, AA3
+ VPADDD state1StoreAVX2, BB0, BB0; VPADDD state1StoreAVX2, BB1, BB1; VPADDD state1StoreAVX2, BB2, BB2; VPADDD state1StoreAVX2, BB3, BB3
+ VPADDD state2StoreAVX2, CC0, CC0; VPADDD state2StoreAVX2, CC1, CC1; VPADDD state2StoreAVX2, CC2, CC2; VPADDD state2StoreAVX2, CC3, CC3
+ VPADDD ctr0StoreAVX2, DD0, DD0; VPADDD ctr1StoreAVX2, DD1, DD1; VPADDD ctr2StoreAVX2, DD2, DD2; VPADDD ctr3StoreAVX2, DD3, DD3
+ VMOVDQA CC3, tmpStoreAVX2
+ VPERM2I128 $0x02, AA0, BB0, CC3
+ VPXOR (0*32)(inp), CC3, CC3
+ VMOVDQU CC3, (0*32)(oup)
+ VPERM2I128 $0x02, CC0, DD0, CC3
+ VPXOR (1*32)(inp), CC3, CC3
+ VMOVDQU CC3, (1*32)(oup)
+ VPERM2I128 $0x13, AA0, BB0, CC3
+ VPXOR (2*32)(inp), CC3, CC3
+ VMOVDQU CC3, (2*32)(oup)
+ VPERM2I128 $0x13, CC0, DD0, CC3
+ VPXOR (3*32)(inp), CC3, CC3
+ VMOVDQU CC3, (3*32)(oup)
+
+ VPERM2I128 $0x02, AA1, BB1, AA0
+ VPERM2I128 $0x02, CC1, DD1, BB0
+ VPERM2I128 $0x13, AA1, BB1, CC0
+ VPERM2I128 $0x13, CC1, DD1, DD0
+ VPXOR (4*32)(inp), AA0, AA0; VPXOR (5*32)(inp), BB0, BB0; VPXOR (6*32)(inp), CC0, CC0; VPXOR (7*32)(inp), DD0, DD0
+ VMOVDQU AA0, (4*32)(oup); VMOVDQU BB0, (5*32)(oup); VMOVDQU CC0, (6*32)(oup); VMOVDQU DD0, (7*32)(oup)
+
+ VPERM2I128 $0x02, AA2, BB2, AA0
+ VPERM2I128 $0x02, CC2, DD2, BB0
+ VPERM2I128 $0x13, AA2, BB2, CC0
+ VPERM2I128 $0x13, CC2, DD2, DD0
+ VPXOR (8*32)(inp), AA0, AA0; VPXOR (9*32)(inp), BB0, BB0; VPXOR (10*32)(inp), CC0, CC0; VPXOR (11*32)(inp), DD0, DD0
+ VMOVDQU AA0, (8*32)(oup); VMOVDQU BB0, (9*32)(oup); VMOVDQU CC0, (10*32)(oup); VMOVDQU DD0, (11*32)(oup)
+
+ MOVQ $384, itr1
+ LEAQ 384(inp), inp
+ SUBQ $384, inl
+ VPERM2I128 $0x02, AA3, BB3, AA0
+ VPERM2I128 $0x02, tmpStoreAVX2, DD3, BB0
+ VPERM2I128 $0x13, AA3, BB3, CC0
+ VPERM2I128 $0x13, tmpStoreAVX2, DD3, DD0
+
+ JMP sealAVX2SealHash
+
+// func haveSSSE3() bool
+TEXT ·haveSSSE3(SB), NOSPLIT, $0
+ XORQ AX, AX
+ INCL AX
+ CPUID
+ SHRQ $9, CX
+ ANDQ $1, CX
+ MOVB CX, ret+0(FP)
+ RET
+
diff --git a/src/vendor/golang_org/x/crypto/chacha20poly1305/chacha20poly1305_generic.go b/src/vendor/golang_org/x/crypto/chacha20poly1305/chacha20poly1305_generic.go
new file mode 100644
index 0000000..b9a55ea
--- /dev/null
+++ b/src/vendor/golang_org/x/crypto/chacha20poly1305/chacha20poly1305_generic.go
@@ -0,0 +1,70 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package chacha20poly1305
+
+import (
+ "encoding/binary"
+
+ "golang_org/x/crypto/chacha20poly1305/internal/chacha20"
+ "golang_org/x/crypto/poly1305"
+)
+
+func roundTo16(n int) int {
+ return 16 * ((n + 15) / 16)
+}
+
+func (c *chacha20poly1305) sealGeneric(dst, nonce, plaintext, additionalData []byte) []byte {
+ var counter [16]byte
+ copy(counter[4:], nonce)
+
+ var polyKey [32]byte
+ chacha20.XORKeyStream(polyKey[:], polyKey[:], &counter, &c.key)
+
+ ret, out := sliceForAppend(dst, len(plaintext)+poly1305.TagSize)
+ counter[0] = 1
+ chacha20.XORKeyStream(out, plaintext, &counter, &c.key)
+
+ polyInput := make([]byte, roundTo16(len(additionalData))+roundTo16(len(plaintext))+8+8)
+ copy(polyInput, additionalData)
+ copy(polyInput[roundTo16(len(additionalData)):], out[:len(plaintext)])
+ binary.LittleEndian.PutUint64(polyInput[len(polyInput)-16:], uint64(len(additionalData)))
+ binary.LittleEndian.PutUint64(polyInput[len(polyInput)-8:], uint64(len(plaintext)))
+
+ var tag [poly1305.TagSize]byte
+ poly1305.Sum(&tag, polyInput, &polyKey)
+ copy(out[len(plaintext):], tag[:])
+
+ return ret
+}
+
+func (c *chacha20poly1305) openGeneric(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) {
+ var tag [poly1305.TagSize]byte
+ copy(tag[:], ciphertext[len(ciphertext)-16:])
+ ciphertext = ciphertext[:len(ciphertext)-16]
+
+ var counter [16]byte
+ copy(counter[4:], nonce)
+
+ var polyKey [32]byte
+ chacha20.XORKeyStream(polyKey[:], polyKey[:], &counter, &c.key)
+
+ polyInput := make([]byte, roundTo16(len(additionalData))+roundTo16(len(ciphertext))+8+8)
+ copy(polyInput, additionalData)
+ copy(polyInput[roundTo16(len(additionalData)):], ciphertext)
+ binary.LittleEndian.PutUint64(polyInput[len(polyInput)-16:], uint64(len(additionalData)))
+ binary.LittleEndian.PutUint64(polyInput[len(polyInput)-8:], uint64(len(ciphertext)))
+
+ ret, out := sliceForAppend(dst, len(ciphertext))
+ if !poly1305.Verify(&tag, polyInput, &polyKey) {
+ for i := range out {
+ out[i] = 0
+ }
+ return nil, errOpen
+ }
+
+ counter[0] = 1
+ chacha20.XORKeyStream(out, ciphertext, &counter, &c.key)
+ return ret, nil
+}
diff --git a/src/vendor/golang_org/x/crypto/chacha20poly1305/chacha20poly1305_noasm.go b/src/vendor/golang_org/x/crypto/chacha20poly1305/chacha20poly1305_noasm.go
new file mode 100644
index 0000000..1d4dcd3
--- /dev/null
+++ b/src/vendor/golang_org/x/crypto/chacha20poly1305/chacha20poly1305_noasm.go
@@ -0,0 +1,15 @@
+// Copyright 2016 The Go Authors. 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 !go1.7
+
+package chacha20poly1305
+
+func (c *chacha20poly1305) seal(dst, nonce, plaintext, additionalData []byte) []byte {
+ return c.sealGeneric(dst, nonce, plaintext, additionalData)
+}
+
+func (c *chacha20poly1305) open(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) {
+ return c.openGeneric(dst, nonce, ciphertext, additionalData)
+}
diff --git a/src/vendor/golang_org/x/crypto/chacha20poly1305/chacha20poly1305_test.go b/src/vendor/golang_org/x/crypto/chacha20poly1305/chacha20poly1305_test.go
new file mode 100644
index 0000000..78f981a
--- /dev/null
+++ b/src/vendor/golang_org/x/crypto/chacha20poly1305/chacha20poly1305_test.go
@@ -0,0 +1,182 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package chacha20poly1305
+
+import (
+ "bytes"
+ cr "crypto/rand"
+ "encoding/hex"
+ mr "math/rand"
+ "testing"
+)
+
+func TestVectors(t *testing.T) {
+ for i, test := range chacha20Poly1305Tests {
+ key, _ := hex.DecodeString(test.key)
+ nonce, _ := hex.DecodeString(test.nonce)
+ ad, _ := hex.DecodeString(test.aad)
+ plaintext, _ := hex.DecodeString(test.plaintext)
+
+ aead, err := New(key)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ ct := aead.Seal(nil, nonce, plaintext, ad)
+ if ctHex := hex.EncodeToString(ct); ctHex != test.out {
+ t.Errorf("#%d: got %s, want %s", i, ctHex, test.out)
+ continue
+ }
+
+ plaintext2, err := aead.Open(nil, nonce, ct, ad)
+ if err != nil {
+ t.Errorf("#%d: Open failed", i)
+ continue
+ }
+
+ if !bytes.Equal(plaintext, plaintext2) {
+ t.Errorf("#%d: plaintext's don't match: got %x vs %x", i, plaintext2, plaintext)
+ continue
+ }
+
+ if len(ad) > 0 {
+ alterAdIdx := mr.Intn(len(ad))
+ ad[alterAdIdx] ^= 0x80
+ if _, err := aead.Open(nil, nonce, ct, ad); err == nil {
+ t.Errorf("#%d: Open was successful after altering additional data", i)
+ }
+ ad[alterAdIdx] ^= 0x80
+ }
+
+ alterNonceIdx := mr.Intn(aead.NonceSize())
+ nonce[alterNonceIdx] ^= 0x80
+ if _, err := aead.Open(nil, nonce, ct, ad); err == nil {
+ t.Errorf("#%d: Open was successful after altering nonce", i)
+ }
+ nonce[alterNonceIdx] ^= 0x80
+
+ alterCtIdx := mr.Intn(len(ct))
+ ct[alterCtIdx] ^= 0x80
+ if _, err := aead.Open(nil, nonce, ct, ad); err == nil {
+ t.Errorf("#%d: Open was successful after altering ciphertext", i)
+ }
+ ct[alterCtIdx] ^= 0x80
+ }
+}
+
+func TestRandom(t *testing.T) {
+ // Some random tests to verify Open(Seal) == Plaintext
+ for i := 0; i < 256; i++ {
+ var nonce [12]byte
+ var key [32]byte
+
+ al := mr.Intn(128)
+ pl := mr.Intn(16384)
+ ad := make([]byte, al)
+ plaintext := make([]byte, pl)
+ cr.Read(key[:])
+ cr.Read(nonce[:])
+ cr.Read(ad)
+ cr.Read(plaintext)
+
+ aead, err := New(key[:])
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ ct := aead.Seal(nil, nonce[:], plaintext, ad)
+
+ plaintext2, err := aead.Open(nil, nonce[:], ct, ad)
+ if err != nil {
+ t.Errorf("Random #%d: Open failed", i)
+ continue
+ }
+
+ if !bytes.Equal(plaintext, plaintext2) {
+ t.Errorf("Random #%d: plaintext's don't match: got %x vs %x", i, plaintext2, plaintext)
+ continue
+ }
+
+ if len(ad) > 0 {
+ alterAdIdx := mr.Intn(len(ad))
+ ad[alterAdIdx] ^= 0x80
+ if _, err := aead.Open(nil, nonce[:], ct, ad); err == nil {
+ t.Errorf("Random #%d: Open was successful after altering additional data", i)
+ }
+ ad[alterAdIdx] ^= 0x80
+ }
+
+ alterNonceIdx := mr.Intn(aead.NonceSize())
+ nonce[alterNonceIdx] ^= 0x80
+ if _, err := aead.Open(nil, nonce[:], ct, ad); err == nil {
+ t.Errorf("Random #%d: Open was successful after altering nonce", i)
+ }
+ nonce[alterNonceIdx] ^= 0x80
+
+ alterCtIdx := mr.Intn(len(ct))
+ ct[alterCtIdx] ^= 0x80
+ if _, err := aead.Open(nil, nonce[:], ct, ad); err == nil {
+ t.Errorf("Random #%d: Open was successful after altering ciphertext", i)
+ }
+ ct[alterCtIdx] ^= 0x80
+ }
+}
+
+func benchamarkChaCha20Poly1305Seal(b *testing.B, buf []byte) {
+ b.SetBytes(int64(len(buf)))
+
+ var key [32]byte
+ var nonce [12]byte
+ var ad [13]byte
+ var out []byte
+
+ aead, _ := New(key[:])
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ out = aead.Seal(out[:0], nonce[:], buf[:], ad[:])
+ }
+}
+
+func benchamarkChaCha20Poly1305Open(b *testing.B, buf []byte) {
+ b.SetBytes(int64(len(buf)))
+
+ var key [32]byte
+ var nonce [12]byte
+ var ad [13]byte
+ var ct []byte
+ var out []byte
+
+ aead, _ := New(key[:])
+ ct = aead.Seal(ct[:0], nonce[:], buf[:], ad[:])
+
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ out, _ = aead.Open(out[:0], nonce[:], ct[:], ad[:])
+ }
+}
+
+func BenchmarkChacha20Poly1305Open_64(b *testing.B) {
+ benchamarkChaCha20Poly1305Open(b, make([]byte, 64))
+}
+
+func BenchmarkChacha20Poly1305Seal_64(b *testing.B) {
+ benchamarkChaCha20Poly1305Seal(b, make([]byte, 64))
+}
+
+func BenchmarkChacha20Poly1305Open_1350(b *testing.B) {
+ benchamarkChaCha20Poly1305Open(b, make([]byte, 1350))
+}
+
+func BenchmarkChacha20Poly1305Seal_1350(b *testing.B) {
+ benchamarkChaCha20Poly1305Seal(b, make([]byte, 1350))
+}
+
+func BenchmarkChacha20Poly1305Open_8K(b *testing.B) {
+ benchamarkChaCha20Poly1305Open(b, make([]byte, 8*1024))
+}
+
+func BenchmarkChacha20Poly1305Seal_8K(b *testing.B) {
+ benchamarkChaCha20Poly1305Seal(b, make([]byte, 8*1024))
+}
diff --git a/src/vendor/golang_org/x/crypto/chacha20poly1305/chacha20poly1305_test_vectors.go b/src/vendor/golang_org/x/crypto/chacha20poly1305/chacha20poly1305_test_vectors.go
new file mode 100644
index 0000000..49f0da6
--- /dev/null
+++ b/src/vendor/golang_org/x/crypto/chacha20poly1305/chacha20poly1305_test_vectors.go
@@ -0,0 +1,332 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package chacha20poly1305
+
+var chacha20Poly1305Tests = []struct {
+ plaintext, aad, key, nonce, out string
+}{
+ {
+ "4c616469657320616e642047656e746c656d656e206f662074686520636c617373206f66202739393a204966204920636f756c64206f6666657220796f75206f6e6c79206f6e652074697020666f7220746865206675747572652c2073756e73637265656e20776f756c642062652069742e",
+ "50515253c0c1c2c3c4c5c6c7",
+ "808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f",
+ "070000004041424344454647",
+ "d31a8d34648e60db7b86afbc53ef7ec2a4aded51296e08fea9e2b5a736ee62d63dbea45e8ca9671282fafb69da92728b1a71de0a9e060b2905d6a5b67ecd3b3692ddbd7f2d778b8c9803aee328091b58fab324e4fad675945585808b4831d7bc3ff4def08e4b7a9de576d26586cec64b61161ae10b594f09e26a7e902ecbd0600691",
+ },
+ {
+ "1400000cebccee3bf561b292340fec60",
+ "00000000000000001603030010",
+ "a5117e70953568bf750862df9e6f92af81677c3a188e847917a4a915bda7792e",
+ "129039b5572e8a7a8131f76a",
+ "2b487a2941bc07f3cc76d1a531662588ee7c2598e59778c24d5b27559a80d163",
+ },
+ {
+ "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 [...]
+ "00000000000000000000000000",
+ "a5117e70953568bf750862df9e6f92af81677c3a188e847917a4a915bda7792e",
+ "129039b5572e8a7a8131f76a",
+ "3f487a25aa70e9c8391763370569c9e83b7650dd1921c8b78869f241f25d2096c910b180930c5b8747fd90959fe8ca2dcadb4fa50fa1439f916b2301e1cc0810d6725775d3ab86721700f96e22709b0a7a8bef32627dd929b2dd3ba15772b669062bb558bc92e6c241a1d60d9f0035e80c335f854815fe1138ab8af653eab3e122135feeec7dfaba1cc24af82a2b7acccdd824899a7e03cc29c25be8a4f56a66673845b93bae1556f09dafc89a0d22af207718e2a6bb022e9d917597295992ea3b750cc0e7a7c3d33b23c5a8aeab45f5bb542f6c9e6c1747ae5a344aff483ba38577ad534b33b3abc7d284776ea33ed488c2a2475 [...]
+ },
+ {
+ "0967de57eefe1aaa999b9b746d88a1a248000d8734e0e938c6aa87",
+ "e4f0a3a4f90a8250f8806aa319053e8d73c62f150e2f239563037e9cc92823ad18c65111d0d462c954cc6c6ed2aafb45702a5a7e597d13bd8091594ab97cf7d1",
+ "f2db28620582e05f00f31c808475ca3df1c20e340bf14828352499466d79295f",
+ "4349e2131d44dc711148dfe3",
+ "bd06cc144fdc0d8b735fa4452eabbf78fd4ad2966ea41a84f68da40ca2da439777bc2ba6c4ec2de0d003eb",
+ },
+ {
+ "c4c920fb52a56fe66eaa8aa3fa187c543e3db8e5c8094c4313dc4ed35dfc5821c5791d171e8cfe8d37883031a0ad",
+ "85deea3dc4",
+ "05ff881d1e151bab4ca3db7d44880222733fe62686f71ce1e4610f2ea19599a7",
+ "b34710f65aed442e4a40866b",
+ "b154452fb7e85d175dd0b0db08591565c5587a725cf22386922f5d27a01015aba778975510b38754b2182e24352f019b7ad493e1ed255906715644aec6e0",
+ },
+ {
+ "c4b337df5e83823900c6c202e93541cf5bc8c677a9aad8b8d87a4d7221e294e595cbc4f34e462d4e0def50f62491c57f598cf60236cfba0f4908816aea154f80e013732e59a07c668fcc5cb35d2232b7ae29b9e4f874f3417c74ab6689fae6690d5a9766fa13cd8adf293d3d4b70f4f999adde9121d1d29d467d04cf77ea398444d0ea3fe4b7c9c3e106002c76f4260fa204a0c3d5",
+ "72611bef65eb664f24ea94f4d5d3d88c9c9c6da29c9a1991c02833c4c9f6993b57b5",
+ "dd0f2d4bb1c9e5ca5aa5f38d69bc8402f7dbb7229857b4a41b3044d481b7655e",
+ "2bbca0910cc47ca0b8517391",
+ "83aa28d6d98901e2981d21d3758ae4db8cce07fe08d82ca6f036a68daa88a7dda56eeb38040c942bdda0fd2d369eec44bd070e2c9314992f68dc16989a6ac0c3912c378cf3254f4bae74a66b075e828df6f855c0d8a827ffed3c03582c12a9112eeb7be43dfe8bd78beb2d1e56678b99a0372531727cb7f2b98d2f917ec10de93fe86267100c20356e80528c5066688c8b7acba76e591449952343f663993d5b642e59eb0f",
+ },
+ {
+ "a9775b8e42b63335439cf1c79fe8a3560b3baebfdfc9ef239d70da02cea0947817f00659a63a8ee9d67fb1756854cc738f7a326e432191e1916be35f0b78d72268de7c0e180af7ee8aa864f2fc30658baa97f9edb88ace49f5b2a8002a8023925e9fa076a997643340c8253cf88ac8a221c190d94c5e224110cb423a4b65cca9046c1fad0483e1444c0680449148e7b20a778c56d5ae97e679d920c43eed6d42598cf05d10d1a15cd722a0686a871b74fea7cad45562bacf3bda937ac701bc218dac7e9d7d20f955429abdac21d821207febf4d54daea4898837035038bf71c66cef63e90f5d3e51f7fcfe18d41f38540a2c2958d [...]
+ "74ba3372d308910b5c9c3885f41252d57556",
+ "9cf77bd06a4ed8fb59349791b98ba40b6019611942f5768e8be2ee88477149e3",
+ "b928935c4c966c60fd6583c0",
+ "ec7fd64fd75b254961a2b7fc942470d8620f439258b871d0d00f58028b5e0bee5e139e8108ac439391465d6658f559b1df57aa21cf826ede1a28bc11af885e13eebfc009870928fae8abfdd943a60c54fca93f0502dc23d29c2fd5340f9bc0e6ef2a18b66ef627af95f796d5bbca50de22c8ec802da9397089b25c6ba5262468e3977b45dc112e51896c70731b0a52d7efec7c93b41995823436bf4b0c477ae79684407c9831b487928b2b8303caca752b3edf1f0598e15831155462706f94ef3fa3a9e5f937f37085afa9b4bbf939d275796a61b78f70597acfd25cd87f967021cd99328fc371b5eb5739869520657b30e4a5b0d [...]
+ },
+ {
+ "b3d3128bce6bbf66fd78f1a18352bae56bfcdae18b65c379ee0aeb37ee54fba1270d2df578ec5b75654d16e89fd1cd0acda7ec580dafd2fbbabd32a8112d49383a762db2638928c8d63eb0750f7e7fdd256b35321b072dd5c45f7dd58cc60dc63d3b79a0c4a1689adf180fef968eccbcfa01ee15091ceacd7b67a3082db0ce6aeb470aafe87249c88b58b721e783dde184ccf68de8e05b6347fe6b74ae3adf9a81e9496a5c9332e7ebe908d26ce6b3f0b2a97e9a89d9fdd0d7694585a3241f240d698e69fcc050e7a959ba153f6d06f117848ba05d887134f1b6b994dad9b9e74247513e08a125b1fadfc7394dcd2a6451b504ae3 [...]
+ "7e8da4f3018f673f8e43bd7a1dee05f8031ec49129c361abbc2a434e9eaf791c3c1d0f3dad767d3bba3ab6d728bbcf2bd994bd03571eae1348f161e6a1da03ddf7121ba4",
+ "7ee32dd501dce849cd492f6e23324c1a4567bfceff9f11d1352bcb8615f1b093",
+ "8998e043d2961afa51ea262a",
+ "ba85e72af18cb5ba85a4a0d6c28b4ac1e5509a3a2fdb0e3255cbc559df5e6a661fc560c756a0264dd99b72c61c51a4b7ad56ca4c8ccb7e8edfc48ff3cceac5d1e8ac5fc87096adc4d0e9a27492857b17604c3a694cfe0e70b22df106c8f3c61f840bcd634964cdb571840e125e381e7dd3a0d97972e965f16f775fa4ce555124318290bf508beb7bd77e633042deb0e863631478fc3dc9122862b3c31264471bcce54e0b74040c8bafd481cf798f332e8940f1134d3027d6f28e771d15e154fc89c6c25fe18a5d312807cc2e623bb1bbb4f0b6ec71d009407eb54bb0759f03682f65d0da8812f84d8e97483f6a8d76a8417efcd95 [...]
+ },
+ {
+ "68d5ba501e87994ef6bc8042d7c5a99693a835a4796ad044f0e536a0790a7ee1e03832fec0cb4cb688cdf85f92a1f526492acac2949a0684803c24f947a3da27db0c259bd87251603f49bfd1eab4f733dec2f5725cfcf6dc381ad57fbdb0a699bccc34943e86f47dcfb34eba6746ed4508e3b764dfad4117c8169785c63d1e8309531747d90cc4a8bf13622759506c613324c512d10629991dc01fe3fe3d6607907e4f698a1312492674707fc4dde0f701a609d2ac336cc9f38badf1c813f9599148c21b5bd4658249d5010db2e205b3880e863441f2fe357dab2645be1f9e5067616bc335d0457ea6468c5828910cb09f92e5e18 [...]
+ "63b90dd89066ad7b61cc39497899a8f14399eace1810f5fe3b76d2501f5d8f83169c5ba602082164d45aad4df3553e36ef29050739fa067470d8c58f3554124bf06df1f27612564a6c04976059d69648ff9b50389556ad052e729563c6a7",
+ "7d5c4314a542aff57a454b274a7999dfdc5f878a159c29be27dabdfcf7c06975",
+ "aeb6159fa88bb1ffd51d036d",
+ "7597f7f44191e815a409754db7fea688e0105c987fa065e621823ea6dea617aed613092ad566c487cfa1a93f556615d2a575fb30ac34b11e19cd908d74545906f929dc9e59f6f1e1e6eaaabe182748ef87057ef7820ffcf254c40237d3ea9ff004472db783ed54b5a294a46cf90519bf89367b04fc01ce544c5bcdd3197eb1237923ce2c0c99921ca959c53b54176d292e97f6d9696ded6054711721aebda543e3e077c90e6f216cdc275b86d45603521c5aab24f08fd06833b0743c388382f941e19e0283ac7c4ef22383e1b9b08572882769c1382bab9ad127e7f3e09b5330b82d3e0c7d6f0df46edc93265999eef8e7afa0cb1 [...]
+ },
+ {
+ "89c1ee38b6697d0190c87a2aa756892ee09fca095df1e31aeedbda5750f604d9b8f2116e5b8f70ec57ea16fe419f2d213ef72b9be90eb5d7e98f2e398632123e2524ac80b31c6c0a07820848223569602d94fc16a3b1ed8c411bc6c74ed80573fcb1f3afce60b9d5e2c21d04f78665241b613abe12274a5343101a91e91f04e5d1f7959f574e743a10913e0817a32c320467f0178e3b6ad14b856234a4661a755eaf14b5fd88ef0e192e1631d14263d6a954ed388f5709dadc6c0f81d229f630d80be6d593d5e3ad03f9ded53c41abe595981d24ef27ffcc930e4d653743960f4e7ce4e251c88f55c16d2afdaed5e3446d00685c2 [...]
+ "7219bd21a834d917f93a9b45647ec77102578bc2f2a132dfde6489b9095b4f7b740c9c1c4075333ab0ce7f14",
+ "a7f849b054982cc8a4c8e5e53e181feee79e0233e58882839892134ad582da7c",
+ "4c46854e9e101090b1436f90",
+ "ab2e189baf60886bed88eb751bf3560a8bd3cdb6ee621d8c18b5fb3aa418f350048ecf359a7d542daf7090ec8688c3b0fe85914aa49d83be4ae3396f7bdc48051afae6a97fca7b42c0bf612a42d3c79ef6aadceb57f5cfe8d67f89d49add0ea1ffd423da058297239e72a85fa6cd1d82e243a503b1b0e12d7510a9ee98d7921dae2754d7581e52acb8ab9e7f9df3c73410789115cef6ce7c937a5441ad4edf2b7a8c0c6d152d5a5909c4ce839d59594a6163364038c4c71a1507389717f61e2bda1ea66a83ef477762e7834ebcfaa8f2ee61ced1605ba1380108236e1763bf40af5259da07dd3e3d0fb2801868c2e7c839e318678 [...]
+ },
+ {
+ "2dcfbb59975f217c445f95634d7c0250afe7d8316a70c47dba99ff94167ab74349729ce1d2bd5d161df27a6a6e7cba1e63924fcd03134abdad4952c3c409060d7ca2ee4e5f4c647c3edee7ad5aa1cbbd341a8a372ed4f4db1e469ee250a4efcc46de1aa52a7e22685d0915b7aae075defbff1529d40a04f250a2d4a046c36c8ca18631cb055334625c4919072a8ee5258efb4e6205525455f428f63aeb62c68de9f758ee4b8c50a7d669ae00f89425868f73e894c53ce9b964dff34f42b9dc2bb03519fbc169a397d25197cae5bc50742f3808f474f2add8d1a0281359043e0a395705fbc0a89293fa2a5ddfe6ae5416e65c0a5b4 [...]
+ "33791b0d653fb72c2d88519b02bde85a7c51f99cfb4456dfa6f84a61e10b4a14846521",
+ "a0a7b73ca2fc9282a28acc036bd74d7f5cb2a146577a5c29dbc3963fe7ebfd87",
+ "eaa4d916d261676d632455be",
+ "c9a631de470fd04dcbf8ea9f4d8ac37c3988878b6381707ac2c91d3720edbb31576ba90731f433a5e13582aca2b3c76ae75ca8881a463ecfa789910d3a776a9ad4800521c6baa120b2f1afd10f32ef8da63f5b69f5e5fd88ee84bf66b0666b15d05c4050f5358a050b9d5cf1503719f56cd48ceba78f29efe2ae8092e37f5134df526831532f86ccb9339637e2c9e9b9036f83cc058fda23e826a188456e7fd3f4ee20f4e4a3221883fe3232b49db607b90a8956133ab95051c9ec33a908ea7e81a1bfa7bd06c09f0143d07bb23a3feeac7f0d7720269c93e2df19d03605828c8713b84d183c9a50954c12fe3b047511ad15ef03a [...]
+ },
+ {
+ "c335b055b752e083554b5aa2cbb6556cfcace658d5c11b6b000256fd89e9b24c1e62a2d5b582580acdb2ad9869020465aeeabe83acd9eeacdc44aa652d5cb24bbe542073d6787ea32b2b3c942d40f9db2bb75ed7914c836d902dd2be89840948d82abbaea23952cd648e6191ce5b6cf912cad0a3165410a781e3650b676e5340980eee3b484008acce6a3e9dc5aa96d775677b8bbb8b323c6e9747d6069a169ea904d9f145e29d134cdbb0118647e8fbae638669efb9a55d50ed33568749f5304ece2193b0bfa6fc9a570d209ef61b4c59a2b5485b5aa6ab47d902cf23f7ff71c5210476e0aa727a01809b9f76b6ebcf58a018b3f [...]
+ "f5ff810a41d4b34751e9942970d4c9f26b33f24689a4b1e4449b243490afc485af468ff01a42376b2bcb949b9f5e8d0b917f511a",
+ "a74271c184a82cb074c14b131fd91eb05870cb7c73c9e511ec8140bfe2f34089",
+ "2403fe689e239c2ed261b381",
+ "af9be893d5fd23aab42e6a2e59a8e7cb13d4f543db02af87cb0802bc1af7c717cd0093cc8244994cf21189146922b69927ffd5745e57118bea07a6afe7c21d952c13ab636b3c2e461dc9ffb3ae701175360156338be94b1fa7115799831019455cfaf5114010fe45f8fb9c77ec50fe06f2c5a32423edccb3b2210ee1200a78e1a3130c567542377827586ca8cf0c14c19fa1449a2cce9c039bb441b04e9c0a3f9a743b31c828032174fcdb7c894349aa68f5adf97dfe9294d24e6b5fed95eb994397883f58487bf5c57b0aea5268be7cee9efeab370f89805ebe5373ab2e93658fc078955ccf68b554dd5605005751ee8531c35ca [...]
+ },
+ {
+ "4aba5a776ace38b6e2578f0007e770d264e39c49f588ca3547ad2888365e3a811994f8836330394587c8458eb0b6611499fd5d8e8527c3cdd4ec550b4a8f8c632384e786b420cb3be911c999c72aad60270aefad31b27a069ecf11e95e9d4c81213308d554d3103de4d9d6ab04830c2b8dfbd8bead52c44c21d5357f72810193b5096809dc7846c1521c6c569f78812c735aea21acaf6dce84a24df7234e8ad857f3e1346b27f5bd436113e2da950e4deff96e9ba8db692c7db723a105ae795da15b910c8286cac6e7dda8c172b70f61b07dfd58596684d61da8772356f180f74c1103ce97cd947eab3d401df44f7fa4cc7cfc25e [...]
+ "921a401db90935c60edda8624a0590d5c46eff3522e35de2872f6f9394e24126fd8143b68a797c995624fba0298b75eef974",
+ "6a4d35ae03bf277f587da4541dcddf92bbd906dff45d5ff23c0f60ae53b062be",
+ "231b5780fedfb06d724450b3",
+ "ba40968282d98849b19d867f8b564ea5a81d657516099362926bca4cb6e9ae02719d10c8061f53008c727a0eeea5e1e36c9e55c117e9434e213316c96840231a1e356b254a9981d4a6ca3c66cfc61018bcaade1a4486506559e6aa3a86bac980d391d835fd5ded98d10f1394d84bf1bbf2cd3397890d704154802f7864ecc753db782fd3d19213ae65ace4770e1bacf32d61c6730aa5adcab4d7e2e437888c11c29abba4890a17a00f67a53b660becd94092df0598df5ac57326f6860593a519e28bd4a39f6481e1a4748881fd5f0456a3cd9f28d1d1e78dc64030cbd8fdb2c5abdab3f13d6ccccd187e71e989f8c486929efcdbf [...]
+ },
+ {
+ "6c0056937faf1023032df1e2bfacbbc58bb022eba25ffa020d4eb26f0caf0678af5d0b2f0c1b520f4843f107f0adcc7b5dee66ff4d61025bafb4cabb64d133132e3e423a599549a1d83aa8c8e774444462aa44b00b460bbafad5755ea6a872d4e6b40e3f4957e0229288ea79fc2ebe5fd9020fe4481a9f42ef14a196bd136aa3c779e311d0c333624c1ddc484c9aa7259cb609e4d0a826c0bdc7567adac01da23900b30ac4e66c100348584fe200747eb67e6287268947e3509d5d2b5d7bcd977b80a13f660d4f6956a8b938a82db75eab19e5d2a22cb5f3c9131e278eebbe096b5f49d16c983ac240f3fbe821b247cccb2c9e6e5 [...]
+ "0d55dcd08b54e58916f622f81761ef6a2e19b167ac47d3",
+ "e42e1d6d44138f3d2bf12c951f454686f18d590fd30057405b5a3dc2b317fa97",
+ "1e46a7486c5a03fd6758d938",
+ "fd3c1fac10cc82e49235fd57f5aea0ee7a7bd6d539b138d4b3fb623aee591615c1a61228ef9673113a3a90a3687a12d4c6367d5f7bc67d422fdc4106455084d79c2c42c5e86368dd164bcbce7925bfffe7d96c13a2f49aac8e9d1ada3554e3fdc21aab00455a0f33b0c1fdea91b3588e7ad301bfccf9940027332fbdf966463491f7a33c093e0a13831ea9d2183294f89f414cf7b5876af04fa68d594430194429df74fa5915394427259e832bc545c13400aef6cf16620d48280798a6e49773c9316d79fa1dc758e54cde2e2cdb856092d83f4e9b698385cb976fd6cc2538abe055273a5b34a784182ea5e7d3ac9019a05de5e5a [...]
+ },
+ {
+ "04892b94c65685f2eba438322b29bf8439938590d3e0eb10a29e279d356cb439f6dfcdbc3552af21f7e753221012a649a52bda780bc589ae63b04b981dffd113df9fcf14f17e35e865880a769bb1bf40dc99b9e85e4296c1f2e1590fe02b22bfcaf2d4bb7009a4d692ae4c2d5f0b6d3ca526240368bac55b9b1e6a7b498d3b137f0fcfef1873c5aa2111d7811d45bdc26be1c5d49b8a2f36a999b1f226ec06a5fbd59514485abe696c96ea89dba74b4688101a239b495944e30b3609f73caff3114407599ec5c30a5bad933655de7dddef97018ae15acec46504cd5d417c5052c057ac5f1c6f69781cfdae71db2b4fcac35054a4a [...]
+ "67b5eccb1790babc2dab5e0d1ff3871c3024177d45a2ae",
+ "259603e1c3af3fd0ce3257eb627b02e0c0a48ea2f175de3d8c36570a445e5369",
+ "e14de73c4b17581a7e0d0649",
+ "33522e67ef932da5fa8abe628b51f3abd5049951dbc982ea95b7769652d4830c588fa45e3fcff094c8602b9008d7b2f9bf6c1c4a8cfb515401c7c44a7ec42ccb967722a710199e121a41160b1ec581507e9bd2e2e506b10c4b5a8d6977435aa08e27504957cd49e756e1574c4ccbbdde937de35128b7ee3455d2e665c596c2e97c253c94e405f85eb5de84874c099b4a97eb8f492d28f2e4bc64b228dd5984e76ca08376d7f1355ba8e0fa60fca96635075417d8b436278e0fb91e3bfc7d61ca8c7407086933c061b2d318f46f352099e1d317d6c44098539d1d2c1b7894db668e7a82ff991864fae236570cc420a4229883f1e22 [...]
+ },
+ {
+ "4ab8068988d4bbe0bf1e5bc2fe1c668cbe58019c958dd2ec97164aea7f3f41c9f747527f1c0e5fdb2cbb9d2ad704b6955cb731f14403dddb1a28c5996707635e4eb5dd6ac33d46eff8e319cfe7cf6443869534ca9812a5b23a6b4ca172afffc064dc2b28197117115431e03c00447f87d9b45172c6f724006270a1d41fa094847cbfac9630c3a785f488c1f5cc407ca6f4cd18bac43cba26ad5bfaccfb8f50784efc0e7fc0b504b43dc5a90a0525b0faf3c8b4b7046fdeb1cad87ec667ce3eb6cb4c358b01393f3ffee949030ef9fd01c1b2b9c5219777eb6ff5b1d7c3ef8d8e3bc2193dfb597cf942c5fc50befa527fac0b44cda [...]
+ "0d471079ad3c3432b6de852ec71692d12d9df4f984554d458a9dd1f28a2697976da8111ae4454c9a23d1c8eae75bbc14f8b00e7c065bc290f8938282b91a1a26c22b40a6708c40945d087e45633a595beb67d8f1c29a81",
+ "f3dac58738ce057d3140d68d2b3e651c00ff9dbb2ca0f913be50219dd36f23c6",
+ "bb2d033de71d570ddf824e85",
+ "238c4e6be84bfb151557327095c88f6dc2889bce2d6f0329e0c42a5cd7554ab16c8b5a4db26eab30f519c24766b1085e11d40823053ca77adfe2af387b4dcde12bc38502229510606ff086265f45b1087375dc4a022eb0b641101c74ad566ab6f230133b7aa61861aa8202b67beddc30dda506691a42032357010d45adc7ee633b536a2fefb3b2143837bb46db04f66a6e2bc628d6041b3d306ff78e96205ab66847036efa1fb6e6a387cf8d5a105738be7163df9da0db48e3d8fd6a786f0f887968e180ad6888e110fb3d7919c42a7f8c92491d795c813f30ea645fafcddf877f5035f133f864fd0ba1415b3d698f2349ebe03d9 [...]
+ },
+ {
+ "4d81b652fee892d575bd13dad913d976cf0517c819d5183a72eba995b1f27efe743451721ce34791a15a6b7a6e44f13d4a080563dd1d9d4f0946e5ba3863b9ac970a1fb4ed66458ec1b1092ff5fa6c3f0271a2df8e3f2e97851352be760b6a0e1589c202f00791b1b89ae0ae944ced96bd90754bcfa3e355b735132d407d3b5507fd57f705e8a8bd82886b16d459ac91e921dcb8c5bf0d7cf420a9349ee589a5e2e19ce7c944a54ccc1062a0690f3152300d0bf5cd1871c1391bf6d7007f7ce26018ca2a5c6f76287fd8c8e9e7f93b1806460dd35f7f95989a8b6f9a0aeb7c6b0346955fb50b8735e34f1ecb4859e34ea0f022ff6 [...]
+ "2538d98b64b6aa9258f9141840a5abef66d6037a10356366a3a294719c10d6c148b04cac66f63ebff052d730f8821f5e5822d869573bcffbdd636c7973433abbf38767597da5186df8ef9df071bc4ecade2633366102313e659db8d8e0f293d379fa2df79f456497",
+ "a5049b0aa153e282457555bf6f82b60fc81aa6fd1c2ea3db031478ffb74b5b5d",
+ "350287a6bed5709dfba3d35c",
+ "849670914f5fe318eb01e8849e536374ec11e813acdbbe6a5e82a506f6aef4f916a3a7fb2e41db3adf990175e21f2386d1805af9bbc32a6ac156b13b1a9505958f68599019c4b7297314229c467114754277b10e9f49a4d12837ef24184629c8902ebe2a23f740dc826b01f8963d47100bf617b314835e436104eb207fa9a1079b8feba06d9369b9aa8222d38d87096b73678bc5db9a1add59394530e678b6ec93a80efc6e8320f2909e3e891306d69b016ade0d30cde64c2c903b401f9d01a29b5cb8619dc68ad6c21900b365a6b657f7d9ca4c145fe598a94eeea741e20a9329996b17aba5d7115c93623f2f5d6927068d0f190 [...]
+ },
+ {
+ "67f0494a728fbfc84e2f4a043e121ee40f3b12b31616c78e157ed970db28674318b08d8b3f4c538d7b9d91b9b0b09ebfebb07201c6398fdbb8684c9390b3d6a8636333a3b086302b24c2e5d47283935d33065efa3fedd5f755218be5d4618d38c5c1db75470ba06bcd853f3f08d39c3cd9fa3618e70b103c2d9b2101fcaf39c1701436b720d723ed5c622d6535c9a10ec4d727abe237e80fd20911ceb84a90285fc6e07f9d036cfa65995f9b6300a927d7d0d2b907bac9d9c4daa87c2438a583fe85029c886f96ed08f5886bf53292cc0265850a1f4ee3e3288b604dc305d0c28ad35e1242f4ff4ae988b6deba48aabcad2fc6cd7 [...]
+ "74dfdc364097c39ef91c01b707a522e28edb1c11529d5050ff820234e6c0295aa00591e09d547e9671804d7825705ab44b76c59d1315ed1297ef477db070d85076693013bdafa92e2ff6a654660008b176cd4e8ae23b9c792be3f7db54cf2bca385bddf50a8624397cca8ee3cb96944164e3cb461e68",
+ "b3b5ccd7ef49a27d2c6d13c0ae77a37abec2e27e0b2d3530cdbb7f36792a7d2c",
+ "c0494bb7249f864f69beab46",
+ "ed8d6e964bcde1df68e7f362243073941fd68ac77929c8e480c89f519f748b3dc337b1af6231632c975167a8425b174b42c2c60dfc0ec85a0a212bf5c9aada818a83f9664c8712d96de1036b5e5d8c8298786b753638de3a8da958549f16eb9c723355cdf7b999aac464ec39df7d6c1607e81b88b63043d1c847dab618f1b19336911b4b0145c2a694e61db71e021282006d48e37f10f3b6314dd012a07618228532c28ca84a936e0eff83723d117b2f2db857d14af5bbd5948a0e53018b31e57cc2a81f36aa013a844990753ccb347fe98fab294cbd252a8b8f7246276275d2780511fd3cb7baa2fd1548184f968c422230f7ad7 [...]
+ },
+ {
+ "04cf92a64cbe135f7fc1d7223b95e41d13f04b482018039f4e7ccacba8aa15ac79a752c5666524e527fb076290ec80a3dccbebfce3ee9b316a65fd130f12bf88b9124d1f7772049e6d0c01fef881a1d44c8dd02f7b6b60e6d15df9e06fb86929cab64842284de09659e19451623525aec2f5dd3e603e24319b1d120bd57b34a0317ce25ac9c2f022a4847306b998b57c8d92baeed0de1f6cfb3177d0acab70de275238f1152813b9ac87bf651f74e1ad079b9bd779ba4374ecba459865b5768d08ae7e1dd691d6821895e8380ac9e5116580e8de3a2c5326e698bf4c4d35d955e45772bae8483d01de2539e8ee1ef9539ee132d80 [...]
+ "001084c8a5175c0ad43108f9215c35886c82321c800740c6118a3fcd45776a4588ee0e2d056a37d99b40d2bd9c0845088a77240b7e65d18fef105d3488c77910b5873dbbf275948db5",
+ "d614d2e671066e387f7eee07bca9f9313d86e6a4d1371360900d670e11ecf1e7",
+ "674a516f8f59f9067e0485e3",
+ "1ee376e9e3c89b2147bcf75480ff0dec1d0e8cd45ba812f34c84124871d484b4ca87bfc8cf99f85ad452c482933801426e2737a97468809fa36caebebe8eed07a626b3bc3614ef1ceb54f9221ecb16f413f0bd9ed4b3010c40632f05223484af7bf5948c2fb8a3d2ce04c53e3f2682494f3969a0f8eb738cf93c0141799c9e6b68924433f0326991e19626bb19e6fbb5dd46baf39f92e830f9b1ff465a007f031891fb1f1799cc122d3ae7a55624356b5297bd5d948d9ff2e414cd8adf00a53524df43f398938d33c93b2c06bcde2679566c0a7b0177b4a873f35874739d550712d5cfe3d25c19292ba97c01d84224738bb25546e [...]
+ },
+ {
+ "ce72c93caa49bb9850774149a87fcf8e23a0c53701554468645554553d54190bc6e247712b02097b794bc421ca94afed34742435ca689d2ebef183fb469c060c7f4d7daa508726c9d2eaeb9c7e9a89b30faee8d9168607d4778acfbd27d5caa623475073ce763ca061273cdfc2c692d1747baa8a01b15f783b2e36620400082747599a16cfd6b630fef310c0b9a2912d1d3bb71eec16972745cd8a49cd927014eb0a2abbe0e1ebded4fb9e8d9e2fbabb6a71da5688717ecd3e08160b9a861f86904a41702b2c4fff28ed8cc61d468187b75bde3fcc5c0c0a642215fea83584387fc5a9aaf2f8a91ae535e0027b618a32bd687289c [...]
+ "08b3fbd73d157e79ea9f61665d19867dcb8c1598c1d37b793606936d8aecd992a0d46addeae857d488b83be5d1c1639d4d78350e4cb08782b61bef4107c9d3a79d3d85",
+ "a56f38b4bbe83b3d9e562cdf5ef5b30593f08a1a166676c4fb0d5861654e640b",
+ "8726dc5cae9497936658f603",
+ "88420357d1ad70e7c7bfd55b3cfd4bf06cd4e9b4ed5cba681045199a06985956d35fe86b28b9a4599964930d05d230a23c55a6a152f67082a453fc31f68489df05c553f9ae5cdb3f611445db384d79af865e52440a876fc4153d896b7a2318dbc2a4495ecdbb2e9dc68022326d35289e82aa55197aedc266dd91ba3018c7b474ba22b4e773773f3e9890ea84bc16a6b235e4bb69e785c40c1adc15b0e0ef03aa147b0d14e62341e27398b84a53f72c9199cc1c94cbcad2bd31aa69c96b06d01775b8c0f80278a43f526664bdd430164863c9c9140ad87798a5b8f38dfe90d37f54d1137709d5311136b728e6c799da244294daa4c [...]
+ },
+ {
+ "bf7884fab52251e202afd7b5b46aa53f85bca5fb80a009d8016e276579e401385d853312a884f4aa33cc5fe7360426bbc0ccb7416cc0196e2e40d3a825d5e0825a1394029789acca550bb28b10d847d0a4fe1111be2b7fec6b5294902775128288a784203031ea853c9c104c75571d19552e2a1359a900c5fc9455230968a5920f2ab23f5b9cc49739d4e4ae2c01c7812ff295899b954e9729a3bb330b60c51a8a7759e5131d7d4cf261fa1e62c29f91b4341a4fc968e7f30ca2261702eb328d628b7275a9efc29b50bcb9b27e5844328d5e8256c76949d30b6fea0d5a1c9abca80d3251fcf4ec4db0a5ff2ffd43618aa2e3e1694 [...]
+ "eaae1c53919e2029c137a80f91704d0871be2c1870d0333d8bcf7f94",
+ "4c434cddb399e52457113cc7e16f046c3f8301f5b6c296979f8a091a9ea557ea",
+ "b633c1a0e1ddf4727b149b3d",
+ "f1de487001a580cee6edadb1ef6b700c861a70c6ef16274447b8c61bb10d2d1efbf104d5f7d7172c6a5cf9c06d886165a2919ee9418e2e8f803d47832dae5ef232ee300d1f973a6298c22d777a1b16264353cc731a7a683cfe31e0abc704460788c555c0c24f281b81d7761235a955c736f17f213a896b40a034609ca8456ec3cf5906d01121b7580ce19d89347b6a59c81add318df487b2442a7a8b5e30df78467abbf46bcd5ee5b994a39ca5bd8846caba6f02f4f1335b73d4e20be0b6ad85966f86d1bb857713ebf947ae936782f1f4929498bbd66bdd5ad6fa252364a5a6b46180e93b54cc321b3cf63cf23d55392475c6b8c [...]
+ },
+ {
+ "c89c3cadc094bffd5ba06c600dabe30ea19ad037316fc13b895fe0e14ac8841264c1bf25557e22b01f8e102c3af43adb8e0a12bf79d3fa0232dae37ca3688e07294e2c7ecc4e2eebdd3f17173351f2c15b0480d4d77bd70955ba86f82214004b622cc92f7bf81a5837326f6a83612bdf65abb33c268a457c45cb7467e074b342a17c711c748c74abbee31541444020a9ecd4e5125e2a8ea3f6030bd677be18183a8a34af16a85ad48b7015cfb036789c0a5daf68883d0c7e401754b8d56cd00ff605be0cad19e03989f608392c81d636de859e66c2aae403c138bb96a58ba69b9064a83e7d8877067e7f40aa0016e0df9b7f455d2 [...]
+ "82abb4ff5457b21f359754f151e456e2c0a185c8363d15918bcee0d6d49f12564ac655",
+ "b63b577e719494032062e3f63682098dcdcfe26cedea2a40893c847a331e4ce9",
+ "9f1d08be539f1244f0f69ad2",
+ "88dcdb0309f8c4a96ad5560f8210eda1f5afb31b85b7a8b15525777748967d4ed77c063f65d64ef19b31044f2adc690f5e457faa1abe2e127b38c626eaa94053c9ae1b6b4d0db1f02c8404b50f58210cc9fcc6fa4ecc615631da631031cd6253b4a13a3e88295ffdc775fd4bdf29655d9780dbe02b0a82aad4c4088e90b51f170909c0f98ff93ca3926067ec94be05841603db4f913b7025a9ee34b8d8bc629ed827a2a9857e0814d36b83cba21e670f8f94ceb4be5757e0b8782895b5d8605868e4f584b5bb6a5f3a94edd9b23fc2b6fa06914aec970c260fc370aa245ca68888c90c43eecb68474c9e45c53a7da055f5bfe39b5 [...]
+ },
+ {
+ "68ca38fccd585eb14f953358220027046c14ef965478d3d8f206f63fef4fe3571a1b53e774b298c347cc1b69cc426d39575ccfabd5a284c7a87a0698cae9efe40543cb79f5643c3c3057a5fc991235f06f059c44a7200b509a12e864fbd748001a14790f78b54ba80cf0a4a603da9672df32b68652c1d6edd3be51cf969acfb0ae49c026fe0bce0bfc72b1ff4c47712b7a27b2cce888b9bc470b8bdda55a8d53a34d79a25947ad55b95e5406a5c5311fece3ecd46ca590b3b01b9055761da8196b21bbc468681922c66d286c32598b1e3d77f2a91d835ccd9eec231409cb2e74ede9385552517718be9f84f0f9100e368701dfa48 [...]
+ "ea196b6a64be4b0799b1c2f72281300c3a2577db44e5d3606b8b02fa8fc46c7aded7e442",
+ "7c86a2c06b7520d60023d18fe73d09c514ed07a91d50d8fd5bff00e7550faed1",
+ "952f492fe00b26028c560fc6",
+ "b3f3294815ce461c8843172efe93f73a8254e58a0e71953e35c15aa89a7bd9dfee967853dcbfba73d3b87fa60449cbcabf13b1206d0cb27d2c3fedcfa695b6d41efda37bb6db35449bd470a23787619ee48f981d3f0b1c8e121725b2289b6d67858a4f9ab41683bdaec8a913ca2cc292a9640efe50fb85a1d1f7b286f45d4448f85b3242f45ab44e3281d759db24dfabbae4259f127d6546ecb914d7e93e2c19230c67fba8a6cba6069023ff7ea3d8a170289c2b4391bb97a7b899228d032b36186dfbb29ae8f0e6c06d753f4c6b21982d49ee682bef50a5c2c8434510c5fa2b9c0349592f33f8d7ad6f7243d42b292aee6d210c6 [...]
+ },
+ {
+ "9100c5b2d7c5d5a854bce55e82f94b89a268da7b66357a661dcf75cba10a1b320ae0e4e1a5b989f9766e57f867a3810a0b5b857191ffd7aece4c796f5694a2617486421940cc12b63a6aaea20d2fac188b318a1c3061cafeae436e04d710654b96a864d674768caee03a50ed6afc06f52d90115df1db5c9f1ecaa4f5da094070b1a447251ad3d4fb0e24e87821ee6d4e7e7eac7059080f77d2b36cacbdac1c6e5063946a376865458c4ebdad3c2afcbba8a82b01b03a7882eee42eab904a19e0aead4ae515b02aa2fee74f3a114bf5b9f320baa35b3225491653f4a69e0d864cbbd031d0805b727e42c2b9530dae0c01cfc6a42af [...]
+ "3c77f30bbb698b1571aeb54653fcae2c23dc16be58603f0c361eedd813ec0c4f63005a1e69e533da93e820e6e4ce1308aa29c60289060ebf24fc9738e8a4874ca4e26a0dc79ee75b8607416bd554737f",
+ "0223c0a6052bb3cdc99a284fa169ba76be2df53b677642a606090a9267a60769",
+ "7d3981073f90c6648c5e9c74",
+ "61ec5230306b70113f67b340575b77ef76d521ff75b754d551e4177591a02351ad382b2a4067f2b3af7e8e15431c7133e98be9d8293d17ef40161dbad9a4f1a4f30cdd557bb9a8b03b5f1b277c850e23ecfa0fc2ab1102e4b1d5e836a606883c3d43527fc3aa26955964b144a9a56cafa7b174d72a0635b80e7b4f871ead3838a955a14c4b8c5c3c66fd86a5e4ff10dfaa92105378bbc5f76ad29727e5bc4779ba3e6dc19bf45020f6ce4dfb3400df05cac51577d58eec21b22839b8f055226b204e641783bb3305b4461172f1c1d48eec56fe6f82aae564ac6688d7b0994747d9b23a24418e69f8a4fc548f854f86baacbdec78b [...]
+ },
+ {
+ "0fcff2c29cbb5cc40bfd2ec573ecf368275ade6a00e5730b77dab17e437b46524b3814e7f470acff6ddac4e0c6b748ed112657120bca1d83a4ce01e74a473995804d7c74bd28732a02370ac8ef52b600790d1284d82f077cfe096448509dddd0eb5944a882b7d384efdd4dde3003dea910f12de82035651e3ec9668e66435f519da3fa1f5bcda34aaaf028daf3068304f7b1ec18e65136241a9db281e011d27db5cc9c1099405a4430821e2488a228805314983966ce5d806b0f014c21d4c9d6a066e63aa6407ed6c29cfa4a3e22ca913762ca9d31271d9c371fe858f3b22e931814cdbe544b9416e88f6026b12bb8e88d8285bea [...]
+ "0c5fb7075f5e15a6733737b614bf46871e29417e4b140bae6e10081623f5c52f557c36b4da4b5a4e82920497514b1e6f745fedbf73f86ee10976f82c6cbd5bc13a917514ddd062",
+ "e70954c812cac03e367e99f7b82a6dcc073d2f679f965d524872756ee58654cc",
+ "5f6267f6b3b21423267310e6",
+ "c53868c0fdc14e891ae1bc257fbb13be210a5d9cdbd9d18fe1b474f9a1929dbba3f25222d8fe8c1be3eef22352100064b922fd9642ad128a202b6382ae0a67c8affb0c5bfa1a80e55c1084cc372485243df872d677a80a3ef1ca3589908bca621f6f50133eb762cb9c05775d13db7dd3eb65ffd3eef96e8dd42928facc68390f6bbc50b17e1ef5ea6310d8756dd177be2cceb63a97bcceaa046794915589ca022d90756b02c22e8634c0ed44192abc3b8b1e2814c855ab27aaae3bdd801a73e6209fdd559ceb59a94fd98a66d12a31a643ca2f4b07ed910bc390f77ab89395d5cd1d783d8940dad4447f0452991b209cfcd998b0c [...]
+ },
+ {
+ "95a17355dfa9d378a18ba20e58aa4b8711ea1d6e3c65e0b2d3c6382892c7d02768437d47ed50bf8edc619c340be7bb1cd1d88b0d3d6bbf1031f738c4be09eb264c686d39b92cc7958e63c9994a84b61b5c412999ace8a9dee0e2a29eeb8dc537f63271af5f3844ed9c0d86e6913c02ed7d2b862a132f08f311aa92fc3757342d89a5dce8dd20d5792d5c60be9862ab168d3140a061489472f2266f297da357064833ef2554c49f8120ff40b961ebcfee1d0f8e7e5722f049485f72c502c9cc4afdbb70517f0fd2a00e12596ffe285d1b37eb998e0e89d756e9491ceb13e83610a3a66122b533c2c3461b3244438f5f7a7af808888 [...]
+ "5e24f34a8d53b17bd0c2aee5369e3276dbd7e7c2ea0990f1300fbbb00831b76655aab1e2fd625ecd",
+ "c1d796f1e651a1ee825855d80206baff6818cc8c247ee6ce62b7531e6e9ac32f",
+ "240cb25aaae4d085bbb747a5",
+ "319e968ad291ea5d4a057c38f7afa4ddb9c9565962fa1a7b231e397a268ad8e0c5030a2df09dc4f99402ddf2e0d06e753bf55e1b318b3e5ff0108de2328d3b8d53e23e08bf7d84d59fededd60d47bbb52736b0491f82c616eb5f779c496abd6499555035e4513c8613e7204e6bff8d06dfecd9ce38c6b83efd8d0e41f84f7cfc9ae07113237987a4b2eaa87f7e0a310155e282e57858244e9071712fa026cb781e5a4bfe6fa1bc480e534096394459a3d1354e2d9a54aac6926a60b388410fd0b53f7a3a9116292f37406369c22ea674418c4deeead171e00f74f5cabae5d24a0686a4bcd8ba99aea613a23edd0a019a319daa377 [...]
+ },
+ {
+ "2158abc2472e1b9c061da2c01d0ad9e996fd687cccca331fe8a2baacd12c06f284b1b5cbdfd067e5ed09a60a137ff4a97c5c26482659680ffb22bbcd4ec1bfd272749e52440537320fdd3c225c30ccd98cf221b34b89c247ab7d14f93ed3ccb0486a028c6f3abe7e17fba1742b6d4db85f6e6baaf82df1a3aa059de8d9699821d39bad42d56cc1ec67626092cfad4a2e1cb5d814e2cab78ccf5474a8bd0dc990a877d37de394694af6cadcc57727f393dccba7bf955f4b65b3c00d71cdd701754ed4f231685b7b5e2557239d7e16305be2d81a773765dcea25ea5bf2c15d670f3159409ab5bbf8da121c779132a8ec1480068cb76 [...]
+ "088fc7ba068f80efd8d4d62813c93c1eba77e9ff400c7781314abc901873ce200295da09245bf8fd2fce254397616151d94b511957c89a881256182ac9e64acb7b25d4a080cc9daf9ac2f231235483fc9fd415f69caf7eaf0597",
+ "78d5f86b071bbf8a185e5e2d54faddd2a9e26983b1e7a74be0f0b979b9f4af31",
+ "d9ce7d249af9496e99c93b36",
+ "ad542824b49fc520f0b7ff8ce2bff8b3d47baacb4a1c95ed56a306483aac551fffba48e8a8f5e4cc536e9266182f6811d070fb9282f5c542cefb4993ccc7044b42cfd6fc71793dc8dd2de23c630f9ceaeddba45efed9d7fca25fcb07d193c000822478b19c2ee9fb31760cfe01475ba8a003db469d1130318a79345a29d054a9f9412dca1edf6d8f1498af5bb6fdbbd3d5f9a244ff176f62742c53779291ef6294df6540d841f4ee8c7c58fc8497ba74d9cf7947add5373427d81ae928305b93dd26cfc65e63b0ed0812ce759511bfbb10aca98f2abdbc9055c4e5ab82637f6a965bb74f592bdf11118b8eb79d50331e76cb4d10c [...]
+ },
+ {
+ "9cd1c25b5bdab9b9080db3e5e05dc749e0783087c310777d89307138613bdffe0ca259677c13208420d4690031314a11a97a986d8b0fea143f5b4da0972c9ea3cef80b4b0b2bcf2bff392c306a764113f0d9807be86a9027c6ddc85d096600d85e0b236937f295362bc1679537a8a9278229a36a9433925a105ab719c0b7f11fc31488fa071d3032de97c81540713dc29ae02c2e13be8823183f3cd9f72ef8ba4280b4499ee47c7c7c4492bcb5cf7e4fafaa7ec26906e58146215a3d4f52f792d3abdb718f57ed0b9b7fc7504e45a0fdf01ebf5924a4da6ac635a715879ea75a4983cbd9dab9e47638acc687f16684e184443aa9e [...]
+ "c22add33457539a957d32dd07ec9110f8cdd2f00ab6ac256b4bc7732f63dd3b867b0ecac262555",
+ "e71f9a3dd457b4064df1d9055889f105af175a2d10dd7b8729da0d0116c2d9fd",
+ "7df9824e774c5f86d83cb5d8",
+ "689683c9e7aa9c48b9fda0cfffea0458ea0c3dedccd21efeb06126f1194780917c9f4f2f44b1daceec3f6b1f75506f4169bdacf12c1f65958784851056fe0b4b42a22aeb043ab35ca73747346ac58c550324c4b849a404c94b8860967b6fc58aff25dad0556f1952c045b91f56ec8eebf6f552c18b2a0641c037e6c6538b289601e1fd5a7bbe7b6e0b224124fec341bf77615183abafb52b3e30082a0abfc2cf224324338c132426011d9f800b382e6b834896ea48a8247f149d92ded7e69c7800096076cd2a729a1fe41c70dafb1f855ffa2ffc27b93e2f5f6827ade7118af60730033675d84de9cde6c260d3d615a945dfe0ed2 [...]
+ },
+ {
+ "3ab6cbeebc18df951d371e0f3cce2697fb367476bd9d50ca9e668c77636eeb9d24b68be0ce6a75eca194fbde6221755d57e9d3148623de24896a9becd98789fd3d14de0c7e53f81fe7f3fd491472a66b5b797fe19c5d0525c7a111a0289a9e65ae7c712ccf694cb75c490070bca7db17205af9bdb7fee27f9ff41fc78ebd2d3d399e690908b5c064ffc0d5bb67b0d2880bcb45c2ca2741691b6131aa1e5ee758fc50610406216905e13ec049ee92d1f95e16bc283dfd91595ec2037d20ead51d3a362140578a4538c80581b79852b0f6686c1ea66aafffc872024592ec1aaf2650d167a75bace024b261db4ab48b401cf85ec2620 [...]
+ "50772c5a0e156ba13a9d86edc0e600021d56f7d31e7e452a74ad53a6775339c7ca6521d87a8c79b42900a1e9e6a1ec03f7e3d615611c3fd5c9927c40e5b508af1a298794b60148df01e9c9e78ab5ea8198c097fadcd6cfa6694be64e00eefe1a1885aece86f6ad87df766e692b58ebc41982bef5",
+ "93a2561a9904a1787a10e2a668cd6a814f2877a7b512698e94796805875c8d1a",
+ "588d9bc1d98210d9700ef488",
+ "165d8c9eabcd5e93e6eff7be122c8c242e1a7f284790c93324f924efabcec4a4ce48262011b7360c2833143d645ff295453853c92f0c48c6dfc2af7ec58d9bec0d13239c7e5593cdb39d49376c6341263df80c0ed2ed79fe9899d0c07de93f6ea95a5dfd307e49bdb5672b158a4df623ee86d54cd1a0fa9a60ce39d1f5f4b6b0ce9daf2a61a907cff3bdd3f29156ac439638e0910d728843ae17ea7368814ad7734732e7c023d4954e1cd5fd19fc9b76e9bb84b61dd4371478917757b14b366b4bfab4eab0d9de746088ad43d8742e2b9e58faff15c2eff084df5f4316111d5dd7d23cc0b1ee1000253f26cd260aa636f03f64a83 [...]
+ },
+ {
+ "3497e8d61062e6f2084ebf72d00e9a47b550591edeee9746f31ea28039a1646d384c4348af293ab778f92a4807c48fbd14e8dbf3d67339c991dc4aca7dae38b5fb7bfeaaa538611d328b653950f4f664dcd257b345917cd66dc6a1ea75d99f70549d1af9d67b1608077b41576f38bb4c0a13ff4fa47b251142c6fbb79f9a27f43841ed0ebc0416c37f571aef8fd63b99e93ae88db50e9ef7d499ae7433d5686b165579d3598f96d9e7b1c876870310703df8fdf2069beadb34984f676eb7d3840c4c5766dcee3fc39f0739260a499647429339482e232362bc72c92a299cae36e9069cc5f4db8893e2c1b9ec0b4f334de26c95109 [...]
+ "823d0cd34e7450550da9716c1f456ce0cbc79431483a6214939266581b0e899e4c95719a09c1ef166a618289a6ee6971b6fea3fe380512cb977823b387ac51d341c26d4a835c61eebde37764d2e1d588df7886177e98e3151106c898b3196bf4dbd83f5f",
+ "a4639c22fc7f370d8500a53819102df5e86c541c0ca10e8f6564e50b90c28f34",
+ "34a04df283c45655a52bdd84",
+ "cd8d1b2e5f65ddb3c0da8f12096134da22ad4d541444964077610aafc1f77f8da5ffc75bee807541cb6eb0526e78d57fd88fa9d9608914cf391ae7ccb8eedb0aa711889f9b6192601163b271c90df5d69fef487b6c05a24fc667469cf16cbd5afd58fc830119fc9f61b26dd50a96ed84c96825a615a3aee84ea4c950152323b20884346b25c9e2a6be3a93505ba059fbb114c224bed8f05f54eab76b2c9c23a0fd942eef9696ff67484b542c8347f1b1fd7df7242872b3528c9e45030447b2bc85eaf191963291e4223b75778335e5f1256618ff87bbd68b5a9e5cbd2ca1dc8aff4625c834edf8fb0d879b1f75ba9b85895a6bb4d [...]
+ },
+ {
+ "5622aa8d2f308dd468a7e4959ccc01f0e80d91f79df65b8201eb44911f6abc758c6703bb97908fff377395d33f96c328a4541f414b7ac34c6607dd85729afbfe01feba988e4997c6bd2c99fcc35d2467b143a8fcbe6b49247226a9e4c0a4e3c1a29d5931e6f1f7a31d90a0e0edc4479f08ef9bc65ae4eacd0b93b1cb38948dda31e60b18d702bbf5935bd580201d1f280cbbee679fd834aa6be576a37a037eabe989c3c18c7fb61fda8b9ffaa8bf22b57a101c19e850c454353af7af3d755b26ff1ee78b9d9daa78294972d108958682a5a29c8ef260e2289ad9d7d74f32fd4e51e5d9ee828366abccd97dd56e035713a6f3a1985 [...]
+ "9f522375925222a04f5c95ee14b6386412025903ecad0bc3ab78afe1145136b3a3592835ab4ad6faa66be9",
+ "d1ba82b3ced3e9817642aaacedf482e79bedd0560ef2754215ee792514bbf8e6",
+ "bb21211f342379370f2642d3",
+ "1a6683805d3f478ca1c1512b9846468378f83be27393db63956e151ec408368b47334afe610249182f54c4d0a01b704db2aa90a9755b8feb67ef9301f0715d7d6bdfa5cc4497cef1142a43eeb42f7c413e8f489af30d742a706d05a40a0c4a5991f9e2cc5d9fbca6ad3767682e20c146ac35aef38dfb2a77388b738fa022158d5c802e5f0761096bb45b50815ebf09172759521b5c5d459703ebe9ff669ee4d14a86e5d0650b597f4a082ba0aef366a924ea378b91c3262d99f48189eea19c76c0f644079f8415c11033cf24d30d6c149ab13ca5c29deafdc816e457257361c1af4b915da312d2e6c7fc712faa27be3e67c893f90 [...]
+ },
+ {
+ "99444e82c6c4c47070b164f298ffdf6955ee5bcb3070b9aa95ce658db4db084d2056cfe61a93568b44ba7ddcba5d450f4ba0da7b119425a6628b3416663c638692326cacc5c237097db5e537122b465dcb21d8dcb5fe831789b72deff3907685c2e23187a56990221e755930a09f8d6cc065487563cb8cec82b9dc754952fa0b342c92d99522fbb39854e338f470a4b4d5ed2a39b8b6253b7001b0b953abc588d757616c7a5d1f12b1024aa572ef5a47dc8480943aa6cfaaa78064fb2b29830280e46efa418d0cf38f57980146f2482276c9b6b16f865b1606bf1131e894336979a163ba2e70adbdc746be0d38062fafcfe5603e6 [...]
+ "0ce980442336d0f427db869a6799baa6785b5e030567c588e2a7d2680e96c11b7f415fa27730969e0b1c3973b5f3192d4e773153def6dcc09dae29ac44eac7c42c2666a356fd4262197bd5cf6eeefcbd662d104423ec05c19a2e6ddf1834a3445a09e8b1062a1320a5e8ef13d6ebd03c19e1813ccd86fd68b46a",
+ "1ac8a509db7bf4acb80d8d394a5abf47c273b2093f50f35049e749f3e16cb0fb",
+ "47cc9eea11f9f3f9aafa23bd",
+ "088888333340b3a057b05491fb2402301c8654948aa6d5ee1ec75eb045858c22056fef0873d6675f897126052923a47a30675b266ffb6181cbd29ce2da3720e36a227e4c6e53328d789913c0d9cd149a6e49293996b1be7d6c513b24d876445a950e723ade3efc36907c840b9b8cfdb1503811b4044d931a0009b381fd60a5bf1e73d16348cb57eea672709875fb9d56908dbc729d5d7d322a17a41d0f62c9af9a013ab1e19fb7b6c6e7fa0c0b18bec5e3d3e92546c77e3753193389e5fcdb6a6a1896cba461343e71ef7a156b136b27ae6f45be9368301cfade203e9b53824d70f07de9abfea1968b8ff8489b9804422ba05ac3c [...]
+ },
+ {
+ "0410d1f8bc890649c250a3819766f4496f339a6384e34acdd72b3a87266edd2a7eae223a372883f978277a108d6e59fca1f35f25d7a9f3aed42d35fa9b12241ac04754f76fd8f0e8ff6af88cd851887a45e89f1c9192ca66bfff605b128575d2ccc9ca3ba1ba23a0251b2cfd6db577b29d17ce2ea998946997f5c4a97a397c46024681a400a54425c071232d269adfc3b1adf15b4586c4dd7b8886f5c1023bc348bc674961ac6e221d914f432c2f06dddcf738227dfcfff88485ed45882809d0e57019461c88683919b87c45e78223c37a5be5f758e4f0dc6add22f2062bc2eb9bdc31b8649af17d526ec339f0e6fc6a41e26299c [...]
+ "113b261414b4b7dfa028668ac8b0cde5734120124991c54f4dd16a87d181efe2bc15f6d0caaeaf6ad615f59ec5c2833904a34b4d34109c82e10609b387f995430e8c13d83ac34310d838af9efa32d7fed6224c0a33",
+ "cd762390b93369f1e207eb15deeaeb0036f5331e82480d180f84a76c3e44550b",
+ "e88c14ef96c7768f5dba9de9",
+ "8d6aaa27892a76fb05a2e96cef9a9b4b7ae0670a12cff95f7b076372456889fbd3b9b4fb5fd98b3bd85b247f15009be2f4e7a0329dd118b6872199b314e159618ede0381dd97db28743461ace1a694c0383d8458150a501d6c45f4b50d5b1bd47e61a51f9ed4929bf2e564f201ed0e6825170027d93e482c1ce268459d2f81cab41f0e7ff281430c16b34a29b5c76630dba72ab9e751bae41122b26121d91f2af271a23e818263f46e05fdd52f319d58330bcabf66637a368c0a8aeeb20cad1916d966e5e0b0de74cc67ebe57e3d1fe01e9743d42a931cb4b98bb762ea43ab937d1e5c42eb08fd56e70e911bdcc1ca4ca0604a329 [...]
+ },
+ {
+ "9c73ac05648e0c50a3ea3a8eea70841e8e06669c1e7520c5e25e093769c4b005375c0a9cea16ec8e00261ceb96a00924a66fc0c4e4e089c63e93fea857aead8e0ab82af4ce1682cf3c9fbad23fc3f7e632b7aa169834ddd6c7db7e1e892cac93e4d787b2ed0a812aa93bfce8fef3ce30ab794743ad241974ff989288c43e1ba815a25a03acdc2d5517293e161d0c46c8858d0b32b124a6b0bc3838807753288cf6838fa25fbcf876e6368c0342d3cbc860d6fa12faa1c2b7d9fb37504e60dd44e36ce74229dfb80f1545125718dd1f78b31a8aadbb4d6494489ce596fcc2dbdf2ec22157a1d966b61e780d36552daf084739b6028 [...]
+ "bf96bbc17abcd1f56a9f22ad164d25ca72f8c996f1a7a66d6effe140336da4f20460b47e1c8573872496343be35a055552ceec437692b0e4919224c4ffc8b603286a8245eff5cc148b004f6e5a54c4ac22b0f09842a07cd332a09732694d3591b8b7d6a7ada2bb38a30aa7fd5e6baa811b9a195d3a96306d",
+ "aa2f714d3a184a9883f4199e8e33fbc9c92b36fff2d59f07a9d0d335d7476e81",
+ "36c79f9f14d431cc8c077439",
+ "873d0617c986dc9d83e9cdfc50b1f916626a9d9e1c595dc7ccd99d1e993d25d89b04a893c89e205952eef8f1733054bbb55fa5e1b07135787d4fcfae226737b50cafa2c11276e8708451be9b4d7f662e98ef6b705c5c4fc64588728eab1dfee22a0a92bae61828a7394977b0ae8a3b6d0126a23583fec025becf0a72a28891391ac1495732a7a4a1d43a63ed8eb37b280b6d886096fbc4f77aadbc5e441e996334d0e10cd7f3dbba9bb7efb147297986509a07735385c681e0543186dc166291edc3b4664f5c8ffb0965c85bc30ff5e7769a69609c69ebb68f35d104bafe3dbd3e2a40e13865f19bca3612e48592aa930eaee2944 [...]
+ },
+ {
+ "ceb1f819497c0d631a9c9616655f419b5e3470fd3b19cd0e4fa556bd26cd9df57e960ec7121b2a2cb7c0421c1f84b77eb8277bf341490190ee574d1424eb09a281176a933394bfea5502077486bef23ee66e3127b732b7a58a04b9aeefc35170dabb030d4fc3f8a4c5ff194bbd0b89a379baca30ec81d576868f25755276e62c31e93a80ac322571313ebcee494592c3ff5cf3ecdec962645887d9aafdbfd62ea910af5542d4c7731283625bc9f41ec85012b42edb1792339e6cdd9c2bb3cad4c4792a064df17a5f74dcbb3dd0d90620ebba4fc6d1e1f9704dd60c798ad64d4e5077549d68cefdddaab81a7a91209b7ddbea43acc [...]
+ "e45eef9561f3acb3672b4f38570256e8cc4d877e2998e72b022e33de8fc20f7320fe0882f2b53559e084923786e8205336a7d15f3fb88a41e7bd20767f2feaa02df2221fa7577988db0bbf61f3dfb429868688c53e130725d0279c505686f083",
+ "475a44cde0cc931edf9a44b0c1e0001766f09ade023dfe6b59a6af800e549b55",
+ "7812a320691ca8442767a51a",
+ "eaa577bd67fe79ce4586f43355c94528e306c1678946e4f7a907d2a8ee7f4281270502522119a8b09b6f05d864921cb515fddf6a1000fc2f67b52d0627998591e2acf5b6faf71c278e5754b2703662ce670dd049da8d6e280c2b84d6a9b29ce28980563c40e03381a49c54608b72faec9b272ef05cfa41957d9eaf3e944b22610c725d8efea90aaac6e782848d368ffc08784d7fe37ea1effbbbb34952def29fc511fb10a1282bb0b6334328e4d00529a44de3259b522553a07d524dc75f431cc9670127c15670c0df419826617cfb5ebdd8788d5f528a9eb1e61324eac5c1746f339aae2e2e2fae598642a389da671482128acf2 [...]
+ },
+ {
+ "228eabb5ad8b4ff13b10d13b27372bc2152dff149859ba47d9c89b741d4a5340d8fff5858a4576c55547007d7e2b3f94583ea8f0976237712bd2e5481c3988f5387e7ac2c3f18718388795b7b2d44b0a13f3faaa55311b800301c9203a511572cf8f349280bbabb9424070f415bbfe28aef8d20329ee842cef4d4c299e619b6ef1cf00718aab2accec9ac00155be2903b6fb07dfe98b0bd8d8580176b99ce4aa6be51cf59046c17ce1817d363fa63af5a241d48bcce064a438651af102ff9c6de4b86374fe24f1dfa66e16e51550dbb791af425d8fa601c70c1bb90e1a557bfe0dde730b0364eba9d2018ee751699ee219e13fa88 [...]
+ "ade72c2ea29cf829ffe99c2d63840b2eef9b51a9919c02128347d2e88e9f063b86326928cf6252ce4beefbae7206dc61a22d0b33c90d464d551835e3b73c1e3d6e88663deab80c35a607e4180ec079b0ee84e3b7922904e7423acaf976e837",
+ "43348cf32211d7daa300de8a4218543c8e3c7373ad10950765c39760f80b733c",
+ "e4709d225a552e90fb357413",
+ "562050bfb40451f27b1181c389508550a0f46b53d14ca73143da9dae3d3d2b466e9618db39e3219675d2b6eadded7dd9c741d7c9bf3c5619a521189607acbcf6b3964d469d966fa134444aa06d80749c873f0f976e0c5efc5be8d00a2729f03eda6a7b8630575df8b3a19388ff88daf0d00bb3e7c35a525ded90a4511ce815fe6c8904406cf72d7bfa14ca533566f7b54268835285c5402e22a63f98b5d90c86dae0a76d65eacc1ba85b3f5a1499d5f3432dd5455fab9e8bfbd266e99283c2bddf9b556410956b2f061603d1fc91194766f90da841699ba7da3d53ed5abdd8e98034f8fe734446d92b458a731aa4c578552ec1ac5 [...]
+ },
+ {
+ "2f6210063cb3071b3d49339185c2cef8357b08ca826d8d1acd852540c16540f1c850f70404fe1f414853d3cd15a1c64a1cce149e3ca1b80926de4ae8438ad90bdad010decf2f201782f3e49794aae1b079f54eb59607bebde508a528927e346d4e444b1d736b34f65e198df2c36fa23c64f1f1fbf8b0b8ddb85d054bdb39b8297d0347f16f7be7cd9474c058e36294485386434b36fb28ee582e393367f15ce5f5a3d6641fbd31b331f10b1554a05da726a0f35c9b1b4af3498426b17582966a266cce452900f85af1046f45a4ccedca6ce02607fb70fa45f420f66aa38cd4c9f8a30e21a3067b940aebdaaeb7c77824a79e2ba20 [...]
+ "fd5008477b0855f6f2486fd4f74b9fb4f6e19726c6996bc66893183bd76054d5b05c1c2b64722256ba912ab2dcca66d2abfdf972966438fff7513acfb18ea461eac08c4e32aea4ed3fcf9f1c9905ee4402e7b6984bef974340d212f160b6524b76de99a98d3e96cc0d35e8a63ad7ea3cbea1d40a906c4dd03e5fc19e1513e9",
+ "390a5e75c9ff4ad38fb6205ff47f209294337c1f25ff54a3c01eee8e1e220257",
+ "8bf183347ec1ca4bceff3374",
+ "19fa2641519e21293094e9d767ee1237f9e0715dc57172794867c3bbe2cb647f9b28a8d3f85c0ff557b91bad66f5ea16e0107757b0277fdd3ca05bf47c19bcb92a958a57e8c142a51af29bddb20af84377b6db65f77494e0dc4d2634a776b3a5d777319873bc0dacbbd4b9ebccfae849fa7e9769cdf54660ecca0d5cf4fa5190713726d54d02b3a3f21857125b8a808c0ca2f99d11dc430ed5113ee49ff8f00bcc08f0370dd510e8100e1285659a7b2c7457a6049f2af7786c4db1471ce5bd164e11c7a2165e83e03a135ae2b3429f82f677de044a067e99e0bda2d65a7270d629c00e1d528212d3aeb2896e58ee5145a93ed06a9 [...]
+ },
+ {
+ "67c6697351ff4aec29cdbaabf2fbe3467cc254f81be8e78d765a2e63339fc99a66320db73158a35a255d051758e95ed4abb2cdc69bb454110e827441213ddc8770e93ea141e1fc673e017e97eadc6b968f385c2aecb03bfb32af3c54ec18db5c021afe43fbfaaa3afb29d1e6053c7c9475d8be6189f95cbba8990f95b1ebf1b305eff700e9a13ae5ca0bcbd0484764bd1f231ea81c7b64c514735ac55e4b79633b706424119e09dcaad4acf21b10af3b33cde3504847155cbb6f2219ba9b7df50be11a1c7f23f829f8a41b13b5ca4ee8983238e0794d3d34bc5f4e77facb6c05ac86212baa1a55a2be70b5733b045cd33694b3afe [...]
+ "0942e506c433afcda3847f2dad",
+ "a5117e70953568bf750862df9e6f92af81677c3a188e847917a4a915bda7792e",
+ "129039b5572e8a7a8131f76a",
+ "588e1356fb8fa32410dad99cf7922aae47b4042502c92f3afe33dc22c1c2e90caf22bc37a254f8dd62a09582c70194f9616982639415178e9fe95740c0f1d497a69b69d4924a7a15290187f9c8acf09cf5b3b3188ecde2d2807207f5bb6a6d3504314b1b47684cf8ba8807eb9a3c497c79ebe1e4c1eca2aa90328563e201425227fca8ee05dcc05fd6c98128626c1e71d2fb3a21860567093db1012dfabe13055c48219d2a301c8a5a49033a811d8d9413bafbb2eefc177226fe578e93c2ef1f309416dc98843bfac387debb1b610b1d2366178ce7212a7312057a3d058357a629f18c78e129e60979a2310455a76207be5611e8b [...]
+ },
+ {
+ "67c6697351ff4aec29cdbaabf2fbe3467cc254f81be8e78d765a2e63339fc99a66320db73158a35a255d051758e95ed4abb2cdc69bb454110e827441213ddc8770e93ea141e1fc673e017e97eadc6b968f385c2aecb03bfb32af3c54ec18db5c021afe43fbfaaa3afb29d1e6053c7c9475d8be6189f95cbba8990f95b1ebf1b305eff700e9a13ae5ca0bcbd0484764bd1f231ea81c7b64c514735ac55e4b79633b706424119e09dcaad4acf21b10af3b33cde3504847155cbb6f2219ba9b7df50be11a1c7f23f829f8a41b13b5ca4ee8983238e0794d3d34bc5f4e77facb6c05ac86212baa1a55a2be70b5733b045cd33694b3afe [...]
+ "d3d934f75ea0f210a8f6059401",
+ "a5117e70953568bf750862df9e6f92af81677c3a188e847917a4a915bda7792e",
+ "129039b5572e8a7a8131f76a",
+ "588e1356fb8fa32410dad99cf7922aae47b4042502c92f3afe33dc22c1c2e90caf22bc37a254f8dd62a09582c70194f9616982639415178e9fe95740c0f1d497a69b69d4924a7a15290187f9c8acf09cf5b3b3188ecde2d2807207f5bb6a6d3504314b1b47684cf8ba8807eb9a3c497c79ebe1e4c1eca2aa90328563e201425227fca8ee05dcc05fd6c98128626c1e71d2fb3a21860567093db1012dfabe13055c48219d2a301c8a5a49033a811d8d9413bafbb2eefc177226fe578e93c2ef1f309416dc98843bfac387debb1b610b1d2366178ce7212a7312057a3d058357a629f18c78e129e60979a2310455a76207be5611e8b [...]
+ },
+ {
+ "67c6697351ff4aec29cdbaabf2fbe3467cc254f81be8e78d765a2e63339fc99a66320db73158a35a255d051758e95ed4abb2cdc69bb454110e827441213ddc8770e93ea141e1fc673e017e97eadc6b968f385c2aecb03bfb32af3c54ec18db5c021afe43fbfaaa3afb29d1e6053c7c9475d8be6189f95cbba8990f95b1ebf1b305eff700e9a13ae5ca0bcbd0484764bd1f231ea81c7b64c514735ac55e4b79633b706424119e09dcaad4acf21b10af3b33cde3504847155cbb6f2219ba9b7df50be11a1c7f23f829f8a41b13b5ca4ee8983238e0794d3d34bc5f4e77facb6c05ac86212baa1a55a2be70b5733b045cd33694b3afe [...]
+ "d3d934f75ea0f210a8f6059401beb4bc4478fa4969e623d01ada696a7e4c7e5125b34884533a94fb319990325744ee9bbce9e525cf08f5e9e25e5360aad2b2d085fa54d835e8d466826498d9a8877565705a8a3f62802944de7ca5894e5759d351adac869580ec17e485f18c0c66f17cc07cbb",
+ "a5117e70953568bf750862df9e6f92af81677c3a188e847917a4a915bda7792e",
+ "129039b5572e8a7a8131f76a",
+ "588e1356fb8fa32410dad99cf7922aae47b4042502c92f3afe33dc22c1c2e90caf22bc37a254f8dd62a09582c70194f9616982639415178e9fe95740c0f1d497a69b69d4924a7a15290187f9c8acf09cf5b3b3188ecde2d2807207f5bb6a6d3504314b1b47684cf8ba8807eb9a3c497c79ebe1e4c1eca2aa90328563e201425227fca8ee05dcc05fd6c98128626c1e71d2fb3a21860567093db1012dfabe13055c48219d2a301c8a5a49033a811d8d9413bafbb2eefc177226fe578e93c2ef1f309416dc98843bfac387debb1b610b1d2366178ce7212a7312057a3d058357a629f18c78e129e60979a2310455a76207be5611e8b [...]
+ },
+ {
+ "67c6697351ff4aec29cdbaabf2fbe3467cc254f81be8e78d765a2e63339fc99a66320db73158a35a255d051758e95ed4abb2cdc69bb454110e827441213ddc8770e93ea141e1fc673e017e97eadc6b968f385c2aecb03bfb32af3c54ec18db5c021afe43fbfaaa3afb29d1e6053c7c9475d8be6189f95cbba8990f95b1ebf1b305eff700e9a13ae5ca0bcbd0484764bd1f231ea81c7b64c514735ac55e4b79633b706424119e09dcaad4acf21b10af3b33cde3504847155cbb6f2219ba9b7df50be11a1c7f23f829f8a41b13b5ca4ee8983238e0794d3d34bc5f4e77facb6c05ac86212baa1a55a2be70b5733b045cd33694b3afe [...]
+ "bc",
+ "a5117e70953568bf750862df9e6f92af81677c3a188e847917a4a915bda7792e",
+ "129039b5572e8a7a8131f76a",
+ "588e1356fb8fa32410dad99cf7922aae47b4042502c92f3afe33dc22c1c2e90caf22bc37a254f8dd62a09582c70194f9616982639415178e9fe95740c0f1d497a69b69d4924a7a15290187f9c8acf09cf5b3b3188ecde2d2807207f5bb6a6d3504314b1b47684cf8ba8807eb9a3c497c79ebe1e4c1eca2aa90328563e201425227fca8ee05dcc05fd6c98128626c1e71d2fb3a21860567093db1012dfabe13055c48219d2a301c8a5a49033a811d8d9413bafbb2eefc177226fe578e93c2ef1f309416dc98843bfac387debb1b610b1d2366178ce7212a7312057a3d058357a629f18c78e129e60979a2310455a76207be5611e8b [...]
+ },
+ {
+ "67c6697351ff4aec29cdbaabf2fbe3467cc254f81be8e78d765a2e63339fc99a66320db73158a35a255d051758e95ed4abb2cdc69bb454110e827441213ddc8770e93ea141e1fc673e017e97eadc6b968f385c2aecb03bfb32af3c54ec18db5c021afe43fbfaaa3afb29d1e6053c7c9475d8be6189f95cbba8990f95b1ebf1b305eff700e9a13ae5ca0bcbd0484764bd1f231ea81c7b64c514735ac55e4b79633b706424119e09dcaad4acf21b10af3b33cde3504847155cbb6f2219ba9b7df50be11a1c7f23f829f8a41b13b5ca4ee8983238e0794d3d34bc5f4e77facb6c05ac86212baa1a55a2be70b5733b045cd33694b3afe [...]
+ "7cbb22fce466da610b63af62bc83b4692f3affaf271693ac071fb86d11342d",
+ "a5117e70953568bf750862df9e6f92af81677c3a188e847917a4a915bda7792e",
+ "129039b5572e8a7a8131f76a",
+ "588e1356fb8fa32410dad99cf7922aae47b4042502c92f3afe33dc22c1c2e90caf22bc37a254f8dd62a09582c70194f9616982639415178e9fe95740c0f1d497a69b69d4924a7a15290187f9c8acf09cf5b3b3188ecde2d2807207f5bb6a6d3504314b1b47684cf8ba8807eb9a3c497c79ebe1e4c1eca2aa90328563e201425227fca8ee05dcc05fd6c98128626c1e71d2fb3a21860567093db1012dfabe13055c48219d2a301c8a5a49033a811d8d9413bafbb2eefc177226fe578e93c2ef1f309416dc98843bfac387debb1b610b1d2366178ce7212a7312057a3d058357a629f18c78e129e60979a2310455a76207be5611e8b [...]
+ },
+ {
+ "67c6697351ff4aec29cdbaabf2fbe3467cc254f81be8e78d765a2e63339fc99a66320db73158a35a255d051758e95ed4abb2cdc69bb454110e827441213ddc8770e93ea141e1fc673e017e97eadc6b968f385c2aecb03bfb32af3c54ec18db5c021afe43fbfaaa3afb29d1e6053c7c9475d8be6189f95cbba8990f95b1ebf1b305eff700e9a13ae5ca0bcbd0484764bd1f231ea81c7b64c514735ac55e4b79633b706424119e09dcaad4acf21b10af3b33cde3504847155cbb6f2219ba9b7df50be11a1c7f23f829f8a41b13b5ca4ee8983238e0794d3d34bc5f4e77facb6c05ac86212baa1a55a2be70b5733b045cd33694b3afe [...]
+ "",
+ "a5117e70953568bf750862df9e6f92af81677c3a188e847917a4a915bda7792e",
+ "129039b5572e8a7a8131f76a",
+ "588e1356fb8fa32410dad99cf7922aae47b4042502c92f3afe33dc22c1c2e90caf22bc37a254f8dd62a09582c70194f9616982639415178e9fe95740c0f1d497a69b69d4924a7a15290187f9c8acf09cf5b3b3188ecde2d2807207f5bb6a6d3504314b1b47684cf8ba8807eb9a3c497c79ebe1e4c1eca2aa90328563e201425227fca8ee05dcc05fd6c98128626c1e71d2fb3a21860567093db1012dfabe13055c48219d2a301c8a5a49033a811d8d9413bafbb2eefc177226fe578e93c2ef1f309416dc98843bfac387debb1b610b1d2366178ce7212a7312057a3d058357a629f18c78e129e60979a2310455a76207be5611e8b [...]
+ },
+ {
+ "0fb826ddb2eb5e708de203d0438be12cf708d635ebdbae56278be09077009586b9bc646ba7c2db35a5de05e86ae71461efea96dac64430edcf117d461113cccacf303576f310ab98efb180599894ba877e50614494923163a3afa9b4c2757f91a6b40799c5b331b464b10dfc45c783c317e408ab76390e19e8b7ceaa2c4d3bd201436bc6f69c7a5a4d8756924ed95665bd5e1034971e4d80d51b2a",
+ "026866d46aa940309fdcabf92a324fbc",
+ "a5117e70953568bf750862df9e6f92af81677c3a188e847917a4a915bda7792e",
+ "129039b5572e8a7a8131f76a",
+ "30f05cf8189bb7b8b4f560e746e228c4cc7e86e8f2fa66e1afe212d1855db51070acd5eb34ce80b2e223957df50fde4c2531d97fc9e573725e7a5e47f0dfc4da1942620320bb2deaf8b17937bae4218d04db8e76f6efe84a117292159507c9f8a09fb2c17921d7762510dbf1dac7b62b1bd7572e3e2cf008d01c445c7fa78833235034281ae180e051451c6a64f22ca9708634bd0d604e4cfcd971b13742efa5b6363e662a875daccb2b00",
+ },
+ {
+ "c7d4f8790e4c47d4daecbddf5939973521ddbf3b832e564afc66f03b5583c41c58bd956609dc3ae3c8f7c2213059575236168dba44e3044049f47c9e7840bbd0fd5036062d70e9f567ac1797056ee93c8476f6c959fa09a3ee854166c6fc36c34d6cca7adcb36f435f86db65f4c4a1793b974294914b377fd179e697751c5ac289243c65d8aca93732849c27483da083d4e218652d4fe5fec8cb953ee7f00070143dd6ece97f241b03c0424bfee2cfd2c4e738f2361df0ffe8863dcf763d408a7a167763959b7f985bc1e359a4b22c6899645ad0814bcf69d10c38474978d1c48e482723e3a6bb3f689f980c51c474eb28cfbba91 [...]
+ "56",
+ "a5117e70953568bf750862df9e6f92af81677c3a188e847917a4a915bda7792e",
+ "129039b5572e8a7a8131f76a",
+ "f89c825ca43cae1ce3fbdee85c505edd1aabefe69a0f9efd740f027aa7dee48a91ad24e69ad061648f0a52b4afb19d7ffccdc21f4b4247dfd89f5f9f998cb3c02b226173fedb6f8770aceef9271e7236fefd19fb3b87d08a5c587ac7918e80aa4b477f22602189811e270d686bc4949137a41d11d95ec96ee9d26c6126f6e923ab37638b34d1538d2e46d6df6216da4f193a3cecb731e632e109ced643056a1673059355d2d1314df35ded8364efed7de490201090a6f2d1751748585f64d26041637ba3723cbc4b60e226f10a19699d223075bc1f27d82e7f560c0db630ea670b3f8a70a8950894af4d1c7b3f674a3fa00d19ee4 [...]
+ },
+ {
+ "135a28170fe89066da7bcff3a9ccc1b27dfe942a6f47b23835ef746aaea63dc10066d90f4e697528e5451b8e11dd408fdbd4b94a1c6c82515bf7bc099df9cb9d5fa4acad0d22d5f267f18078cec107a995c1f3b12d7603886dbf910ab85ca7180053c50e759b00dc8c81555a425c03d71df6894a6c8cd2d94b64e303c08a1bc1dee1cf537ccf300850856292e1656aff5bf349c87f1ca1ca8085cd400fe901edcad04146a0714ef0f6b083d715edd670e020385f3cda29bc5ff6fc6edffe5ca9ce9def6e0e3d5f04ede2db02cfb2",
+ "73afd2ab0e0e8537cae42dc6530dc4afb6934ca6",
+ "a5117e70953568bf750862df9e6f92af81677c3a188e847917a4a915bda7792e",
+ "129039b5572e8a7a8131f76a",
+ "2c125232a59879aee36cacc4aca5085a4688c4f776667a8fbd86862b5cfb1d57c976688fdd652eafa2b88b1b8e358aa2110ff6ef13cdc1ceca9c9f087c35c38d89d6fbd8de89538070f17916ecb19ca3ef4a1c834f0bdaa1df62aaabef2e117106787056c909e61ecd208357dd5c363f11c5d6cf24992cc873cf69f59360a820fcf290bd90b2cab24c47286acb4e1033962b6d41e562a206a94796a8ab1c6b8bade804ff9bdf5ba6062d2c1f8fe0f4dfc05720bd9a612b92c26789f9f6a7ce43f5e8e3aee99a9cd7d6c11eaa611983c36935b0dda57d898a60a0ab7c4b54",
+ },
+}
diff --git a/src/vendor/golang_org/x/crypto/chacha20poly1305/internal/chacha20/chacha_generic.go b/src/vendor/golang_org/x/crypto/chacha20poly1305/internal/chacha20/chacha_generic.go
new file mode 100644
index 0000000..f9e8a3a
--- /dev/null
+++ b/src/vendor/golang_org/x/crypto/chacha20poly1305/internal/chacha20/chacha_generic.go
@@ -0,0 +1,199 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package ChaCha20 implements the core ChaCha20 function as specified in https://tools.ietf.org/html/rfc7539#section-2.3.
+package chacha20
+
+import "encoding/binary"
+
+const rounds = 20
+
+// core applies the ChaCha20 core function to 16-byte input in, 32-byte key k,
+// and 16-byte constant c, and puts the result into 64-byte array out.
+func core(out *[64]byte, in *[16]byte, k *[32]byte) {
+ j0 := uint32(0x61707865)
+ j1 := uint32(0x3320646e)
+ j2 := uint32(0x79622d32)
+ j3 := uint32(0x6b206574)
+ j4 := binary.LittleEndian.Uint32(k[0:4])
+ j5 := binary.LittleEndian.Uint32(k[4:8])
+ j6 := binary.LittleEndian.Uint32(k[8:12])
+ j7 := binary.LittleEndian.Uint32(k[12:16])
+ j8 := binary.LittleEndian.Uint32(k[16:20])
+ j9 := binary.LittleEndian.Uint32(k[20:24])
+ j10 := binary.LittleEndian.Uint32(k[24:28])
+ j11 := binary.LittleEndian.Uint32(k[28:32])
+ j12 := binary.LittleEndian.Uint32(in[0:4])
+ j13 := binary.LittleEndian.Uint32(in[4:8])
+ j14 := binary.LittleEndian.Uint32(in[8:12])
+ j15 := binary.LittleEndian.Uint32(in[12:16])
+
+ x0, x1, x2, x3, x4, x5, x6, x7 := j0, j1, j2, j3, j4, j5, j6, j7
+ x8, x9, x10, x11, x12, x13, x14, x15 := j8, j9, j10, j11, j12, j13, j14, j15
+
+ for i := 0; i < rounds; i += 2 {
+ x0 += x4
+ x12 ^= x0
+ x12 = (x12 << 16) | (x12 >> (16))
+ x8 += x12
+ x4 ^= x8
+ x4 = (x4 << 12) | (x4 >> (20))
+ x0 += x4
+ x12 ^= x0
+ x12 = (x12 << 8) | (x12 >> (24))
+ x8 += x12
+ x4 ^= x8
+ x4 = (x4 << 7) | (x4 >> (25))
+ x1 += x5
+ x13 ^= x1
+ x13 = (x13 << 16) | (x13 >> 16)
+ x9 += x13
+ x5 ^= x9
+ x5 = (x5 << 12) | (x5 >> 20)
+ x1 += x5
+ x13 ^= x1
+ x13 = (x13 << 8) | (x13 >> 24)
+ x9 += x13
+ x5 ^= x9
+ x5 = (x5 << 7) | (x5 >> 25)
+ x2 += x6
+ x14 ^= x2
+ x14 = (x14 << 16) | (x14 >> 16)
+ x10 += x14
+ x6 ^= x10
+ x6 = (x6 << 12) | (x6 >> 20)
+ x2 += x6
+ x14 ^= x2
+ x14 = (x14 << 8) | (x14 >> 24)
+ x10 += x14
+ x6 ^= x10
+ x6 = (x6 << 7) | (x6 >> 25)
+ x3 += x7
+ x15 ^= x3
+ x15 = (x15 << 16) | (x15 >> 16)
+ x11 += x15
+ x7 ^= x11
+ x7 = (x7 << 12) | (x7 >> 20)
+ x3 += x7
+ x15 ^= x3
+ x15 = (x15 << 8) | (x15 >> 24)
+ x11 += x15
+ x7 ^= x11
+ x7 = (x7 << 7) | (x7 >> 25)
+ x0 += x5
+ x15 ^= x0
+ x15 = (x15 << 16) | (x15 >> 16)
+ x10 += x15
+ x5 ^= x10
+ x5 = (x5 << 12) | (x5 >> 20)
+ x0 += x5
+ x15 ^= x0
+ x15 = (x15 << 8) | (x15 >> 24)
+ x10 += x15
+ x5 ^= x10
+ x5 = (x5 << 7) | (x5 >> 25)
+ x1 += x6
+ x12 ^= x1
+ x12 = (x12 << 16) | (x12 >> 16)
+ x11 += x12
+ x6 ^= x11
+ x6 = (x6 << 12) | (x6 >> 20)
+ x1 += x6
+ x12 ^= x1
+ x12 = (x12 << 8) | (x12 >> 24)
+ x11 += x12
+ x6 ^= x11
+ x6 = (x6 << 7) | (x6 >> 25)
+ x2 += x7
+ x13 ^= x2
+ x13 = (x13 << 16) | (x13 >> 16)
+ x8 += x13
+ x7 ^= x8
+ x7 = (x7 << 12) | (x7 >> 20)
+ x2 += x7
+ x13 ^= x2
+ x13 = (x13 << 8) | (x13 >> 24)
+ x8 += x13
+ x7 ^= x8
+ x7 = (x7 << 7) | (x7 >> 25)
+ x3 += x4
+ x14 ^= x3
+ x14 = (x14 << 16) | (x14 >> 16)
+ x9 += x14
+ x4 ^= x9
+ x4 = (x4 << 12) | (x4 >> 20)
+ x3 += x4
+ x14 ^= x3
+ x14 = (x14 << 8) | (x14 >> 24)
+ x9 += x14
+ x4 ^= x9
+ x4 = (x4 << 7) | (x4 >> 25)
+ }
+
+ x0 += j0
+ x1 += j1
+ x2 += j2
+ x3 += j3
+ x4 += j4
+ x5 += j5
+ x6 += j6
+ x7 += j7
+ x8 += j8
+ x9 += j9
+ x10 += j10
+ x11 += j11
+ x12 += j12
+ x13 += j13
+ x14 += j14
+ x15 += j15
+
+ binary.LittleEndian.PutUint32(out[0:4], x0)
+ binary.LittleEndian.PutUint32(out[4:8], x1)
+ binary.LittleEndian.PutUint32(out[8:12], x2)
+ binary.LittleEndian.PutUint32(out[12:16], x3)
+ binary.LittleEndian.PutUint32(out[16:20], x4)
+ binary.LittleEndian.PutUint32(out[20:24], x5)
+ binary.LittleEndian.PutUint32(out[24:28], x6)
+ binary.LittleEndian.PutUint32(out[28:32], x7)
+ binary.LittleEndian.PutUint32(out[32:36], x8)
+ binary.LittleEndian.PutUint32(out[36:40], x9)
+ binary.LittleEndian.PutUint32(out[40:44], x10)
+ binary.LittleEndian.PutUint32(out[44:48], x11)
+ binary.LittleEndian.PutUint32(out[48:52], x12)
+ binary.LittleEndian.PutUint32(out[52:56], x13)
+ binary.LittleEndian.PutUint32(out[56:60], x14)
+ binary.LittleEndian.PutUint32(out[60:64], x15)
+}
+
+// XORKeyStream crypts bytes from in to out using the given key and counters.
+// In and out may be the same slice but otherwise should not overlap. Counter
+// contains the raw ChaCha20 counter bytes (i.e. block counter followed by
+// nonce).
+func XORKeyStream(out, in []byte, counter *[16]byte, key *[32]byte) {
+ var block [64]byte
+ var counterCopy [16]byte
+ copy(counterCopy[:], counter[:])
+
+ for len(in) >= 64 {
+ core(&block, &counterCopy, key)
+ for i, x := range block {
+ out[i] = in[i] ^ x
+ }
+ u := uint32(1)
+ for i := 0; i < 4; i++ {
+ u += uint32(counterCopy[i])
+ counterCopy[i] = byte(u)
+ u >>= 8
+ }
+ in = in[64:]
+ out = out[64:]
+ }
+
+ if len(in) > 0 {
+ core(&block, &counterCopy, key)
+ for i, v := range in {
+ out[i] = v ^ block[i]
+ }
+ }
+}
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
new file mode 100644
index 0000000..ca9663f
--- /dev/null
+++ b/src/vendor/golang_org/x/crypto/chacha20poly1305/internal/chacha20/chacha_test.go
@@ -0,0 +1,29 @@
+package chacha20
+
+import (
+ "encoding/hex"
+ "testing"
+)
+
+func TestCore(t *testing.T) {
+ // This is just a smoke test that checks the example from
+ // https://tools.ietf.org/html/rfc7539#section-2.3.2. The
+ // chacha20poly1305 package contains much more extensive tests of this
+ // code.
+ var key [32]byte
+ for i := range key {
+ key[i] = byte(i)
+ }
+
+ var input [16]byte
+ input[0] = 1
+ input[7] = 9
+ input[11] = 0x4a
+
+ var out [64]byte
+ XORKeyStream(out[:], out[:], &input, &key)
+ const expected = "10f1e7e4d13b5915500fdd1fa32071c4c7d1f4c733c068030422aa9ac3d46c4ed2826446079faa0914c2d705d98b02a2b5129cd1de164eb9cbd083e8a2503c4e"
+ if result := hex.EncodeToString(out[:]); result != expected {
+ t.Errorf("wanted %x but got %x", expected, result)
+ }
+}
diff --git a/src/vendor/golang_org/x/crypto/curve25519/const_amd64.s b/src/vendor/golang_org/x/crypto/curve25519/const_amd64.s
new file mode 100644
index 0000000..797f9b0
--- /dev/null
+++ b/src/vendor/golang_org/x/crypto/curve25519/const_amd64.s
@@ -0,0 +1,20 @@
+// Copyright 2012 The Go 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 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
+
+DATA ·REDMASK51(SB)/8, $0x0007FFFFFFFFFFFF
+GLOBL ·REDMASK51(SB), 8, $8
+
+DATA ·_121666_213(SB)/8, $996687872
+GLOBL ·_121666_213(SB), 8, $8
+
+DATA ·_2P0(SB)/8, $0xFFFFFFFFFFFDA
+GLOBL ·_2P0(SB), 8, $8
+
+DATA ·_2P1234(SB)/8, $0xFFFFFFFFFFFFE
+GLOBL ·_2P1234(SB), 8, $8
diff --git a/src/vendor/golang_org/x/crypto/curve25519/cswap_amd64.s b/src/vendor/golang_org/x/crypto/curve25519/cswap_amd64.s
new file mode 100644
index 0000000..45484d1
--- /dev/null
+++ b/src/vendor/golang_org/x/crypto/curve25519/cswap_amd64.s
@@ -0,0 +1,88 @@
+// Copyright 2012 The Go 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 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)
+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
+ RET
diff --git a/src/vendor/golang_org/x/crypto/curve25519/curve25519.go b/src/vendor/golang_org/x/crypto/curve25519/curve25519.go
new file mode 100644
index 0000000..6918c47
--- /dev/null
+++ b/src/vendor/golang_org/x/crypto/curve25519/curve25519.go
@@ -0,0 +1,841 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// We have a implementation in amd64 assembly so this code is only run on
+// non-amd64 platforms. The amd64 assembly does not support gccgo.
+// +build !amd64 gccgo appengine
+
+package curve25519
+
+// This code is a port of the public domain, "ref10" implementation of
+// curve25519 from SUPERCOP 20130419 by D. J. Bernstein.
+
+// fieldElement represents an element of the field GF(2^255 - 19). An element
+// t, entries t[0]...t[9], represents the integer t[0]+2^26 t[1]+2^51 t[2]+2^77
+// t[3]+2^102 t[4]+...+2^230 t[9]. Bounds on each t[i] vary depending on
+// context.
+type fieldElement [10]int32
+
+func feZero(fe *fieldElement) {
+ for i := range fe {
+ fe[i] = 0
+ }
+}
+
+func feOne(fe *fieldElement) {
+ feZero(fe)
+ fe[0] = 1
+}
+
+func feAdd(dst, a, b *fieldElement) {
+ for i := range dst {
+ dst[i] = a[i] + b[i]
+ }
+}
+
+func feSub(dst, a, b *fieldElement) {
+ for i := range dst {
+ dst[i] = a[i] - b[i]
+ }
+}
+
+func feCopy(dst, src *fieldElement) {
+ for i := range dst {
+ dst[i] = src[i]
+ }
+}
+
+// feCSwap replaces (f,g) with (g,f) if b == 1; replaces (f,g) with (f,g) if b == 0.
+//
+// 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]
+ }
+}
+
+// load3 reads a 24-bit, little-endian value from in.
+func load3(in []byte) int64 {
+ var r int64
+ r = int64(in[0])
+ r |= int64(in[1]) << 8
+ r |= int64(in[2]) << 16
+ return r
+}
+
+// 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
+}
+
+func feFromBytes(dst *fieldElement, src *[32]byte) {
+ h0 := load4(src[:])
+ h1 := load3(src[4:]) << 6
+ h2 := load3(src[7:]) << 5
+ h3 := load3(src[10:]) << 3
+ h4 := load3(src[13:]) << 2
+ h5 := load4(src[16:])
+ h6 := load3(src[20:]) << 7
+ h7 := load3(src[23:]) << 5
+ h8 := load3(src[26:]) << 4
+ h9 := load3(src[29:]) << 2
+
+ var carry [10]int64
+ carry[9] = (h9 + 1<<24) >> 25
+ h0 += carry[9] * 19
+ h9 -= carry[9] << 25
+ carry[1] = (h1 + 1<<24) >> 25
+ h2 += carry[1]
+ h1 -= carry[1] << 25
+ carry[3] = (h3 + 1<<24) >> 25
+ h4 += carry[3]
+ h3 -= carry[3] << 25
+ carry[5] = (h5 + 1<<24) >> 25
+ h6 += carry[5]
+ h5 -= carry[5] << 25
+ carry[7] = (h7 + 1<<24) >> 25
+ h8 += carry[7]
+ h7 -= carry[7] << 25
+
+ carry[0] = (h0 + 1<<25) >> 26
+ h1 += carry[0]
+ h0 -= carry[0] << 26
+ carry[2] = (h2 + 1<<25) >> 26
+ h3 += carry[2]
+ h2 -= carry[2] << 26
+ carry[4] = (h4 + 1<<25) >> 26
+ h5 += carry[4]
+ h4 -= carry[4] << 26
+ carry[6] = (h6 + 1<<25) >> 26
+ h7 += carry[6]
+ h6 -= carry[6] << 26
+ carry[8] = (h8 + 1<<25) >> 26
+ h9 += carry[8]
+ h8 -= carry[8] << 26
+
+ dst[0] = int32(h0)
+ dst[1] = int32(h1)
+ dst[2] = int32(h2)
+ dst[3] = int32(h3)
+ dst[4] = int32(h4)
+ dst[5] = int32(h5)
+ dst[6] = int32(h6)
+ dst[7] = int32(h7)
+ dst[8] = int32(h8)
+ dst[9] = int32(h9)
+}
+
+// feToBytes marshals h to s.
+// Preconditions:
+// |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
+//
+// Write p=2^255-19; q=floor(h/p).
+// Basic claim: q = floor(2^(-255)(h + 19 2^(-25)h9 + 2^(-1))).
+//
+// Proof:
+// Have |h|<=p so |q|<=1 so |19^2 2^(-255) q|<1/4.
+// Also have |h-2^230 h9|<2^230 so |19 2^(-255)(h-2^230 h9)|<1/4.
+//
+// Write y=2^(-1)-19^2 2^(-255)q-19 2^(-255)(h-2^230 h9).
+// Then 0<y<1.
+//
+// Write r=h-pq.
+// Have 0<=r<=p-1=2^255-20.
+// Thus 0<=r+19(2^-255)r<r+19(2^-255)2^255<=2^255-1.
+//
+// Write x=r+19(2^-255)r+y.
+// Then 0<x<2^255 so floor(2^(-255)x) = 0 so floor(q+2^(-255)x) = q.
+//
+// Have q+2^(-255)x = 2^(-255)(h + 19 2^(-25) h9 + 2^(-1))
+// so floor(2^(-255)(h + 19 2^(-25) h9 + 2^(-1))) = q.
+func feToBytes(s *[32]byte, h *fieldElement) {
+ var carry [10]int32
+
+ q := (19*h[9] + (1 << 24)) >> 25
+ q = (h[0] + q) >> 26
+ q = (h[1] + q) >> 25
+ q = (h[2] + q) >> 26
+ q = (h[3] + q) >> 25
+ q = (h[4] + q) >> 26
+ q = (h[5] + q) >> 25
+ q = (h[6] + q) >> 26
+ q = (h[7] + q) >> 25
+ q = (h[8] + q) >> 26
+ q = (h[9] + q) >> 25
+
+ // Goal: Output h-(2^255-19)q, which is between 0 and 2^255-20.
+ h[0] += 19 * q
+ // Goal: Output h-2^255 q, which is between 0 and 2^255-20.
+
+ carry[0] = h[0] >> 26
+ h[1] += carry[0]
+ h[0] -= carry[0] << 26
+ carry[1] = h[1] >> 25
+ h[2] += carry[1]
+ h[1] -= carry[1] << 25
+ carry[2] = h[2] >> 26
+ h[3] += carry[2]
+ h[2] -= carry[2] << 26
+ carry[3] = h[3] >> 25
+ h[4] += carry[3]
+ h[3] -= carry[3] << 25
+ carry[4] = h[4] >> 26
+ h[5] += carry[4]
+ h[4] -= carry[4] << 26
+ carry[5] = h[5] >> 25
+ h[6] += carry[5]
+ h[5] -= carry[5] << 25
+ carry[6] = h[6] >> 26
+ h[7] += carry[6]
+ h[6] -= carry[6] << 26
+ carry[7] = h[7] >> 25
+ h[8] += carry[7]
+ h[7] -= carry[7] << 25
+ carry[8] = h[8] >> 26
+ h[9] += carry[8]
+ h[8] -= carry[8] << 26
+ carry[9] = h[9] >> 25
+ h[9] -= carry[9] << 25
+ // h10 = carry9
+
+ // Goal: Output h[0]+...+2^255 h10-2^255 q, which is between 0 and 2^255-20.
+ // Have h[0]+...+2^230 h[9] between 0 and 2^255-1;
+ // evidently 2^255 h10-2^255 q = 0.
+ // Goal: Output h[0]+...+2^230 h[9].
+
+ s[0] = byte(h[0] >> 0)
+ s[1] = byte(h[0] >> 8)
+ s[2] = byte(h[0] >> 16)
+ s[3] = byte((h[0] >> 24) | (h[1] << 2))
+ s[4] = byte(h[1] >> 6)
+ s[5] = byte(h[1] >> 14)
+ s[6] = byte((h[1] >> 22) | (h[2] << 3))
+ s[7] = byte(h[2] >> 5)
+ s[8] = byte(h[2] >> 13)
+ s[9] = byte((h[2] >> 21) | (h[3] << 5))
+ s[10] = byte(h[3] >> 3)
+ s[11] = byte(h[3] >> 11)
+ s[12] = byte((h[3] >> 19) | (h[4] << 6))
+ s[13] = byte(h[4] >> 2)
+ s[14] = byte(h[4] >> 10)
+ s[15] = byte(h[4] >> 18)
+ s[16] = byte(h[5] >> 0)
+ s[17] = byte(h[5] >> 8)
+ s[18] = byte(h[5] >> 16)
+ s[19] = byte((h[5] >> 24) | (h[6] << 1))
+ s[20] = byte(h[6] >> 7)
+ s[21] = byte(h[6] >> 15)
+ s[22] = byte((h[6] >> 23) | (h[7] << 3))
+ s[23] = byte(h[7] >> 5)
+ s[24] = byte(h[7] >> 13)
+ s[25] = byte((h[7] >> 21) | (h[8] << 4))
+ s[26] = byte(h[8] >> 4)
+ s[27] = byte(h[8] >> 12)
+ s[28] = byte((h[8] >> 20) | (h[9] << 6))
+ s[29] = byte(h[9] >> 2)
+ s[30] = byte(h[9] >> 10)
+ s[31] = byte(h[9] >> 18)
+}
+
+// feMul calculates h = f * g
+// Can overlap h with f or g.
+//
+// Preconditions:
+// |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
+// |g| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
+//
+// Postconditions:
+// |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
+//
+// Notes on implementation strategy:
+//
+// Using schoolbook multiplication.
+// Karatsuba would save a little in some cost models.
+//
+// Most multiplications by 2 and 19 are 32-bit precomputations;
+// cheaper than 64-bit postcomputations.
+//
+// There is one remaining multiplication by 19 in the carry chain;
+// one *19 precomputation can be merged into this,
+// but the resulting data flow is considerably less clean.
+//
+// There are 12 carries below.
+// 10 of them are 2-way parallelizable and vectorizable.
+// Can get away with 11 carries, but then data flow is much deeper.
+//
+// With tighter constraints on inputs can squeeze carries into int32.
+func feMul(h, f, g *fieldElement) {
+ f0 := f[0]
+ f1 := f[1]
+ f2 := f[2]
+ f3 := f[3]
+ f4 := f[4]
+ f5 := f[5]
+ f6 := f[6]
+ f7 := f[7]
+ f8 := f[8]
+ f9 := f[9]
+ g0 := g[0]
+ g1 := g[1]
+ g2 := g[2]
+ g3 := g[3]
+ g4 := g[4]
+ g5 := g[5]
+ g6 := g[6]
+ g7 := g[7]
+ g8 := g[8]
+ g9 := g[9]
+ g1_19 := 19 * g1 // 1.4*2^29
+ g2_19 := 19 * g2 // 1.4*2^30; still ok
+ g3_19 := 19 * g3
+ g4_19 := 19 * g4
+ g5_19 := 19 * g5
+ g6_19 := 19 * g6
+ g7_19 := 19 * g7
+ g8_19 := 19 * g8
+ g9_19 := 19 * g9
+ f1_2 := 2 * f1
+ f3_2 := 2 * f3
+ f5_2 := 2 * f5
+ f7_2 := 2 * f7
+ f9_2 := 2 * f9
+ f0g0 := int64(f0) * int64(g0)
+ f0g1 := int64(f0) * int64(g1)
+ f0g2 := int64(f0) * int64(g2)
+ f0g3 := int64(f0) * int64(g3)
+ f0g4 := int64(f0) * int64(g4)
+ f0g5 := int64(f0) * int64(g5)
+ f0g6 := int64(f0) * int64(g6)
+ f0g7 := int64(f0) * int64(g7)
+ f0g8 := int64(f0) * int64(g8)
+ f0g9 := int64(f0) * int64(g9)
+ f1g0 := int64(f1) * int64(g0)
+ f1g1_2 := int64(f1_2) * int64(g1)
+ f1g2 := int64(f1) * int64(g2)
+ f1g3_2 := int64(f1_2) * int64(g3)
+ f1g4 := int64(f1) * int64(g4)
+ f1g5_2 := int64(f1_2) * int64(g5)
+ f1g6 := int64(f1) * int64(g6)
+ f1g7_2 := int64(f1_2) * int64(g7)
+ f1g8 := int64(f1) * int64(g8)
+ f1g9_38 := int64(f1_2) * int64(g9_19)
+ f2g0 := int64(f2) * int64(g0)
+ f2g1 := int64(f2) * int64(g1)
+ f2g2 := int64(f2) * int64(g2)
+ f2g3 := int64(f2) * int64(g3)
+ f2g4 := int64(f2) * int64(g4)
+ f2g5 := int64(f2) * int64(g5)
+ f2g6 := int64(f2) * int64(g6)
+ f2g7 := int64(f2) * int64(g7)
+ f2g8_19 := int64(f2) * int64(g8_19)
+ f2g9_19 := int64(f2) * int64(g9_19)
+ f3g0 := int64(f3) * int64(g0)
+ f3g1_2 := int64(f3_2) * int64(g1)
+ f3g2 := int64(f3) * int64(g2)
+ f3g3_2 := int64(f3_2) * int64(g3)
+ f3g4 := int64(f3) * int64(g4)
+ f3g5_2 := int64(f3_2) * int64(g5)
+ f3g6 := int64(f3) * int64(g6)
+ f3g7_38 := int64(f3_2) * int64(g7_19)
+ f3g8_19 := int64(f3) * int64(g8_19)
+ f3g9_38 := int64(f3_2) * int64(g9_19)
+ f4g0 := int64(f4) * int64(g0)
+ f4g1 := int64(f4) * int64(g1)
+ f4g2 := int64(f4) * int64(g2)
+ f4g3 := int64(f4) * int64(g3)
+ f4g4 := int64(f4) * int64(g4)
+ f4g5 := int64(f4) * int64(g5)
+ f4g6_19 := int64(f4) * int64(g6_19)
+ f4g7_19 := int64(f4) * int64(g7_19)
+ f4g8_19 := int64(f4) * int64(g8_19)
+ f4g9_19 := int64(f4) * int64(g9_19)
+ f5g0 := int64(f5) * int64(g0)
+ f5g1_2 := int64(f5_2) * int64(g1)
+ f5g2 := int64(f5) * int64(g2)
+ f5g3_2 := int64(f5_2) * int64(g3)
+ f5g4 := int64(f5) * int64(g4)
+ f5g5_38 := int64(f5_2) * int64(g5_19)
+ f5g6_19 := int64(f5) * int64(g6_19)
+ f5g7_38 := int64(f5_2) * int64(g7_19)
+ f5g8_19 := int64(f5) * int64(g8_19)
+ f5g9_38 := int64(f5_2) * int64(g9_19)
+ f6g0 := int64(f6) * int64(g0)
+ f6g1 := int64(f6) * int64(g1)
+ f6g2 := int64(f6) * int64(g2)
+ f6g3 := int64(f6) * int64(g3)
+ f6g4_19 := int64(f6) * int64(g4_19)
+ f6g5_19 := int64(f6) * int64(g5_19)
+ f6g6_19 := int64(f6) * int64(g6_19)
+ f6g7_19 := int64(f6) * int64(g7_19)
+ f6g8_19 := int64(f6) * int64(g8_19)
+ f6g9_19 := int64(f6) * int64(g9_19)
+ f7g0 := int64(f7) * int64(g0)
+ f7g1_2 := int64(f7_2) * int64(g1)
+ f7g2 := int64(f7) * int64(g2)
+ f7g3_38 := int64(f7_2) * int64(g3_19)
+ f7g4_19 := int64(f7) * int64(g4_19)
+ f7g5_38 := int64(f7_2) * int64(g5_19)
+ f7g6_19 := int64(f7) * int64(g6_19)
+ f7g7_38 := int64(f7_2) * int64(g7_19)
+ f7g8_19 := int64(f7) * int64(g8_19)
+ f7g9_38 := int64(f7_2) * int64(g9_19)
+ f8g0 := int64(f8) * int64(g0)
+ f8g1 := int64(f8) * int64(g1)
+ f8g2_19 := int64(f8) * int64(g2_19)
+ f8g3_19 := int64(f8) * int64(g3_19)
+ f8g4_19 := int64(f8) * int64(g4_19)
+ f8g5_19 := int64(f8) * int64(g5_19)
+ f8g6_19 := int64(f8) * int64(g6_19)
+ f8g7_19 := int64(f8) * int64(g7_19)
+ f8g8_19 := int64(f8) * int64(g8_19)
+ f8g9_19 := int64(f8) * int64(g9_19)
+ f9g0 := int64(f9) * int64(g0)
+ f9g1_38 := int64(f9_2) * int64(g1_19)
+ f9g2_19 := int64(f9) * int64(g2_19)
+ f9g3_38 := int64(f9_2) * int64(g3_19)
+ f9g4_19 := int64(f9) * int64(g4_19)
+ f9g5_38 := int64(f9_2) * int64(g5_19)
+ f9g6_19 := int64(f9) * int64(g6_19)
+ f9g7_38 := int64(f9_2) * int64(g7_19)
+ f9g8_19 := int64(f9) * int64(g8_19)
+ f9g9_38 := int64(f9_2) * int64(g9_19)
+ h0 := f0g0 + f1g9_38 + f2g8_19 + f3g7_38 + f4g6_19 + f5g5_38 + f6g4_19 + f7g3_38 + f8g2_19 + f9g1_38
+ h1 := f0g1 + f1g0 + f2g9_19 + f3g8_19 + f4g7_19 + f5g6_19 + f6g5_19 + f7g4_19 + f8g3_19 + f9g2_19
+ h2 := f0g2 + f1g1_2 + f2g0 + f3g9_38 + f4g8_19 + f5g7_38 + f6g6_19 + f7g5_38 + f8g4_19 + f9g3_38
+ h3 := f0g3 + f1g2 + f2g1 + f3g0 + f4g9_19 + f5g8_19 + f6g7_19 + f7g6_19 + f8g5_19 + f9g4_19
+ h4 := f0g4 + f1g3_2 + f2g2 + f3g1_2 + f4g0 + f5g9_38 + f6g8_19 + f7g7_38 + f8g6_19 + f9g5_38
+ h5 := f0g5 + f1g4 + f2g3 + f3g2 + f4g1 + f5g0 + f6g9_19 + f7g8_19 + f8g7_19 + f9g6_19
+ h6 := f0g6 + f1g5_2 + f2g4 + f3g3_2 + f4g2 + f5g1_2 + f6g0 + f7g9_38 + f8g8_19 + f9g7_38
+ h7 := f0g7 + f1g6 + f2g5 + f3g4 + f4g3 + f5g2 + f6g1 + f7g0 + f8g9_19 + f9g8_19
+ h8 := f0g8 + f1g7_2 + f2g6 + f3g5_2 + f4g4 + f5g3_2 + f6g2 + f7g1_2 + f8g0 + f9g9_38
+ h9 := f0g9 + f1g8 + f2g7 + f3g6 + f4g5 + f5g4 + f6g3 + f7g2 + f8g1 + f9g0
+ var carry [10]int64
+
+ // |h0| <= (1.1*1.1*2^52*(1+19+19+19+19)+1.1*1.1*2^50*(38+38+38+38+38))
+ // i.e. |h0| <= 1.2*2^59; narrower ranges for h2, h4, h6, h8
+ // |h1| <= (1.1*1.1*2^51*(1+1+19+19+19+19+19+19+19+19))
+ // i.e. |h1| <= 1.5*2^58; narrower ranges for h3, h5, h7, h9
+
+ carry[0] = (h0 + (1 << 25)) >> 26
+ h1 += carry[0]
+ h0 -= carry[0] << 26
+ carry[4] = (h4 + (1 << 25)) >> 26
+ h5 += carry[4]
+ h4 -= carry[4] << 26
+ // |h0| <= 2^25
+ // |h4| <= 2^25
+ // |h1| <= 1.51*2^58
+ // |h5| <= 1.51*2^58
+
+ carry[1] = (h1 + (1 << 24)) >> 25
+ h2 += carry[1]
+ h1 -= carry[1] << 25
+ carry[5] = (h5 + (1 << 24)) >> 25
+ h6 += carry[5]
+ h5 -= carry[5] << 25
+ // |h1| <= 2^24; from now on fits into int32
+ // |h5| <= 2^24; from now on fits into int32
+ // |h2| <= 1.21*2^59
+ // |h6| <= 1.21*2^59
+
+ carry[2] = (h2 + (1 << 25)) >> 26
+ h3 += carry[2]
+ h2 -= carry[2] << 26
+ carry[6] = (h6 + (1 << 25)) >> 26
+ h7 += carry[6]
+ h6 -= carry[6] << 26
+ // |h2| <= 2^25; from now on fits into int32 unchanged
+ // |h6| <= 2^25; from now on fits into int32 unchanged
+ // |h3| <= 1.51*2^58
+ // |h7| <= 1.51*2^58
+
+ carry[3] = (h3 + (1 << 24)) >> 25
+ h4 += carry[3]
+ h3 -= carry[3] << 25
+ carry[7] = (h7 + (1 << 24)) >> 25
+ h8 += carry[7]
+ h7 -= carry[7] << 25
+ // |h3| <= 2^24; from now on fits into int32 unchanged
+ // |h7| <= 2^24; from now on fits into int32 unchanged
+ // |h4| <= 1.52*2^33
+ // |h8| <= 1.52*2^33
+
+ carry[4] = (h4 + (1 << 25)) >> 26
+ h5 += carry[4]
+ h4 -= carry[4] << 26
+ carry[8] = (h8 + (1 << 25)) >> 26
+ h9 += carry[8]
+ h8 -= carry[8] << 26
+ // |h4| <= 2^25; from now on fits into int32 unchanged
+ // |h8| <= 2^25; from now on fits into int32 unchanged
+ // |h5| <= 1.01*2^24
+ // |h9| <= 1.51*2^58
+
+ carry[9] = (h9 + (1 << 24)) >> 25
+ h0 += carry[9] * 19
+ h9 -= carry[9] << 25
+ // |h9| <= 2^24; from now on fits into int32 unchanged
+ // |h0| <= 1.8*2^37
+
+ carry[0] = (h0 + (1 << 25)) >> 26
+ h1 += carry[0]
+ h0 -= carry[0] << 26
+ // |h0| <= 2^25; from now on fits into int32 unchanged
+ // |h1| <= 1.01*2^24
+
+ h[0] = int32(h0)
+ h[1] = int32(h1)
+ h[2] = int32(h2)
+ h[3] = int32(h3)
+ h[4] = int32(h4)
+ h[5] = int32(h5)
+ h[6] = int32(h6)
+ h[7] = int32(h7)
+ h[8] = int32(h8)
+ h[9] = int32(h9)
+}
+
+// feSquare calculates h = f*f. Can overlap h with f.
+//
+// Preconditions:
+// |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
+//
+// Postconditions:
+// |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
+func feSquare(h, f *fieldElement) {
+ f0 := f[0]
+ f1 := f[1]
+ f2 := f[2]
+ f3 := f[3]
+ f4 := f[4]
+ f5 := f[5]
+ f6 := f[6]
+ f7 := f[7]
+ f8 := f[8]
+ f9 := f[9]
+ f0_2 := 2 * f0
+ f1_2 := 2 * f1
+ f2_2 := 2 * f2
+ f3_2 := 2 * f3
+ f4_2 := 2 * f4
+ f5_2 := 2 * f5
+ f6_2 := 2 * f6
+ f7_2 := 2 * f7
+ f5_38 := 38 * f5 // 1.31*2^30
+ f6_19 := 19 * f6 // 1.31*2^30
+ f7_38 := 38 * f7 // 1.31*2^30
+ f8_19 := 19 * f8 // 1.31*2^30
+ f9_38 := 38 * f9 // 1.31*2^30
+ f0f0 := int64(f0) * int64(f0)
+ f0f1_2 := int64(f0_2) * int64(f1)
+ f0f2_2 := int64(f0_2) * int64(f2)
+ f0f3_2 := int64(f0_2) * int64(f3)
+ f0f4_2 := int64(f0_2) * int64(f4)
+ f0f5_2 := int64(f0_2) * int64(f5)
+ f0f6_2 := int64(f0_2) * int64(f6)
+ f0f7_2 := int64(f0_2) * int64(f7)
+ f0f8_2 := int64(f0_2) * int64(f8)
+ f0f9_2 := int64(f0_2) * int64(f9)
+ f1f1_2 := int64(f1_2) * int64(f1)
+ f1f2_2 := int64(f1_2) * int64(f2)
+ f1f3_4 := int64(f1_2) * int64(f3_2)
+ f1f4_2 := int64(f1_2) * int64(f4)
+ f1f5_4 := int64(f1_2) * int64(f5_2)
+ f1f6_2 := int64(f1_2) * int64(f6)
+ f1f7_4 := int64(f1_2) * int64(f7_2)
+ f1f8_2 := int64(f1_2) * int64(f8)
+ f1f9_76 := int64(f1_2) * int64(f9_38)
+ f2f2 := int64(f2) * int64(f2)
+ f2f3_2 := int64(f2_2) * int64(f3)
+ f2f4_2 := int64(f2_2) * int64(f4)
+ f2f5_2 := int64(f2_2) * int64(f5)
+ f2f6_2 := int64(f2_2) * int64(f6)
+ f2f7_2 := int64(f2_2) * int64(f7)
+ f2f8_38 := int64(f2_2) * int64(f8_19)
+ f2f9_38 := int64(f2) * int64(f9_38)
+ f3f3_2 := int64(f3_2) * int64(f3)
+ f3f4_2 := int64(f3_2) * int64(f4)
+ f3f5_4 := int64(f3_2) * int64(f5_2)
+ f3f6_2 := int64(f3_2) * int64(f6)
+ f3f7_76 := int64(f3_2) * int64(f7_38)
+ f3f8_38 := int64(f3_2) * int64(f8_19)
+ f3f9_76 := int64(f3_2) * int64(f9_38)
+ f4f4 := int64(f4) * int64(f4)
+ f4f5_2 := int64(f4_2) * int64(f5)
+ f4f6_38 := int64(f4_2) * int64(f6_19)
+ f4f7_38 := int64(f4) * int64(f7_38)
+ f4f8_38 := int64(f4_2) * int64(f8_19)
+ f4f9_38 := int64(f4) * int64(f9_38)
+ f5f5_38 := int64(f5) * int64(f5_38)
+ f5f6_38 := int64(f5_2) * int64(f6_19)
+ f5f7_76 := int64(f5_2) * int64(f7_38)
+ f5f8_38 := int64(f5_2) * int64(f8_19)
+ f5f9_76 := int64(f5_2) * int64(f9_38)
+ f6f6_19 := int64(f6) * int64(f6_19)
+ f6f7_38 := int64(f6) * int64(f7_38)
+ f6f8_38 := int64(f6_2) * int64(f8_19)
+ f6f9_38 := int64(f6) * int64(f9_38)
+ f7f7_38 := int64(f7) * int64(f7_38)
+ f7f8_38 := int64(f7_2) * int64(f8_19)
+ f7f9_76 := int64(f7_2) * int64(f9_38)
+ f8f8_19 := int64(f8) * int64(f8_19)
+ f8f9_38 := int64(f8) * int64(f9_38)
+ f9f9_38 := int64(f9) * int64(f9_38)
+ h0 := f0f0 + f1f9_76 + f2f8_38 + f3f7_76 + f4f6_38 + f5f5_38
+ h1 := f0f1_2 + f2f9_38 + f3f8_38 + f4f7_38 + f5f6_38
+ h2 := f0f2_2 + f1f1_2 + f3f9_76 + f4f8_38 + f5f7_76 + f6f6_19
+ h3 := f0f3_2 + f1f2_2 + f4f9_38 + f5f8_38 + f6f7_38
+ h4 := f0f4_2 + f1f3_4 + f2f2 + f5f9_76 + f6f8_38 + f7f7_38
+ h5 := f0f5_2 + f1f4_2 + f2f3_2 + f6f9_38 + f7f8_38
+ h6 := f0f6_2 + f1f5_4 + f2f4_2 + f3f3_2 + f7f9_76 + f8f8_19
+ h7 := f0f7_2 + f1f6_2 + f2f5_2 + f3f4_2 + f8f9_38
+ h8 := f0f8_2 + f1f7_4 + f2f6_2 + f3f5_4 + f4f4 + f9f9_38
+ h9 := f0f9_2 + f1f8_2 + f2f7_2 + f3f6_2 + f4f5_2
+ var carry [10]int64
+
+ carry[0] = (h0 + (1 << 25)) >> 26
+ h1 += carry[0]
+ h0 -= carry[0] << 26
+ carry[4] = (h4 + (1 << 25)) >> 26
+ h5 += carry[4]
+ h4 -= carry[4] << 26
+
+ carry[1] = (h1 + (1 << 24)) >> 25
+ h2 += carry[1]
+ h1 -= carry[1] << 25
+ carry[5] = (h5 + (1 << 24)) >> 25
+ h6 += carry[5]
+ h5 -= carry[5] << 25
+
+ carry[2] = (h2 + (1 << 25)) >> 26
+ h3 += carry[2]
+ h2 -= carry[2] << 26
+ carry[6] = (h6 + (1 << 25)) >> 26
+ h7 += carry[6]
+ h6 -= carry[6] << 26
+
+ carry[3] = (h3 + (1 << 24)) >> 25
+ h4 += carry[3]
+ h3 -= carry[3] << 25
+ carry[7] = (h7 + (1 << 24)) >> 25
+ h8 += carry[7]
+ h7 -= carry[7] << 25
+
+ carry[4] = (h4 + (1 << 25)) >> 26
+ h5 += carry[4]
+ h4 -= carry[4] << 26
+ carry[8] = (h8 + (1 << 25)) >> 26
+ h9 += carry[8]
+ h8 -= carry[8] << 26
+
+ carry[9] = (h9 + (1 << 24)) >> 25
+ h0 += carry[9] * 19
+ h9 -= carry[9] << 25
+
+ carry[0] = (h0 + (1 << 25)) >> 26
+ h1 += carry[0]
+ h0 -= carry[0] << 26
+
+ h[0] = int32(h0)
+ h[1] = int32(h1)
+ h[2] = int32(h2)
+ h[3] = int32(h3)
+ h[4] = int32(h4)
+ h[5] = int32(h5)
+ h[6] = int32(h6)
+ h[7] = int32(h7)
+ h[8] = int32(h8)
+ h[9] = int32(h9)
+}
+
+// feMul121666 calculates h = f * 121666. Can overlap h with f.
+//
+// Preconditions:
+// |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
+//
+// Postconditions:
+// |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
+func feMul121666(h, f *fieldElement) {
+ h0 := int64(f[0]) * 121666
+ h1 := int64(f[1]) * 121666
+ h2 := int64(f[2]) * 121666
+ h3 := int64(f[3]) * 121666
+ h4 := int64(f[4]) * 121666
+ h5 := int64(f[5]) * 121666
+ h6 := int64(f[6]) * 121666
+ h7 := int64(f[7]) * 121666
+ h8 := int64(f[8]) * 121666
+ h9 := int64(f[9]) * 121666
+ var carry [10]int64
+
+ carry[9] = (h9 + (1 << 24)) >> 25
+ h0 += carry[9] * 19
+ h9 -= carry[9] << 25
+ carry[1] = (h1 + (1 << 24)) >> 25
+ h2 += carry[1]
+ h1 -= carry[1] << 25
+ carry[3] = (h3 + (1 << 24)) >> 25
+ h4 += carry[3]
+ h3 -= carry[3] << 25
+ carry[5] = (h5 + (1 << 24)) >> 25
+ h6 += carry[5]
+ h5 -= carry[5] << 25
+ carry[7] = (h7 + (1 << 24)) >> 25
+ h8 += carry[7]
+ h7 -= carry[7] << 25
+
+ carry[0] = (h0 + (1 << 25)) >> 26
+ h1 += carry[0]
+ h0 -= carry[0] << 26
+ carry[2] = (h2 + (1 << 25)) >> 26
+ h3 += carry[2]
+ h2 -= carry[2] << 26
+ carry[4] = (h4 + (1 << 25)) >> 26
+ h5 += carry[4]
+ h4 -= carry[4] << 26
+ carry[6] = (h6 + (1 << 25)) >> 26
+ h7 += carry[6]
+ h6 -= carry[6] << 26
+ carry[8] = (h8 + (1 << 25)) >> 26
+ h9 += carry[8]
+ h8 -= carry[8] << 26
+
+ h[0] = int32(h0)
+ h[1] = int32(h1)
+ h[2] = int32(h2)
+ h[3] = int32(h3)
+ h[4] = int32(h4)
+ h[5] = int32(h5)
+ h[6] = int32(h6)
+ h[7] = int32(h7)
+ h[8] = int32(h8)
+ h[9] = int32(h9)
+}
+
+// feInvert sets out = z^-1.
+func feInvert(out, z *fieldElement) {
+ var t0, t1, t2, t3 fieldElement
+ var i int
+
+ feSquare(&t0, z)
+ for i = 1; i < 1; i++ {
+ feSquare(&t0, &t0)
+ }
+ feSquare(&t1, &t0)
+ for i = 1; i < 2; i++ {
+ feSquare(&t1, &t1)
+ }
+ feMul(&t1, z, &t1)
+ feMul(&t0, &t0, &t1)
+ feSquare(&t2, &t0)
+ for i = 1; i < 1; i++ {
+ feSquare(&t2, &t2)
+ }
+ feMul(&t1, &t1, &t2)
+ feSquare(&t2, &t1)
+ for i = 1; i < 5; i++ {
+ feSquare(&t2, &t2)
+ }
+ feMul(&t1, &t2, &t1)
+ feSquare(&t2, &t1)
+ for i = 1; i < 10; i++ {
+ feSquare(&t2, &t2)
+ }
+ feMul(&t2, &t2, &t1)
+ feSquare(&t3, &t2)
+ for i = 1; i < 20; i++ {
+ feSquare(&t3, &t3)
+ }
+ feMul(&t2, &t3, &t2)
+ feSquare(&t2, &t2)
+ for i = 1; i < 10; i++ {
+ feSquare(&t2, &t2)
+ }
+ feMul(&t1, &t2, &t1)
+ feSquare(&t2, &t1)
+ for i = 1; i < 50; i++ {
+ feSquare(&t2, &t2)
+ }
+ feMul(&t2, &t2, &t1)
+ feSquare(&t3, &t2)
+ for i = 1; i < 100; i++ {
+ feSquare(&t3, &t3)
+ }
+ feMul(&t2, &t3, &t2)
+ feSquare(&t2, &t2)
+ for i = 1; i < 50; i++ {
+ feSquare(&t2, &t2)
+ }
+ feMul(&t1, &t2, &t1)
+ feSquare(&t1, &t1)
+ for i = 1; i < 5; i++ {
+ feSquare(&t1, &t1)
+ }
+ feMul(out, &t1, &t0)
+}
+
+func scalarMult(out, in, base *[32]byte) {
+ var e [32]byte
+
+ copy(e[:], in[:])
+ e[0] &= 248
+ e[31] &= 127
+ e[31] |= 64
+
+ var x1, x2, z2, x3, z3, tmp0, tmp1 fieldElement
+ feFromBytes(&x1, base)
+ feOne(&x2)
+ feCopy(&x3, &x1)
+ feOne(&z3)
+
+ swap := int32(0)
+ for pos := 254; pos >= 0; pos-- {
+ b := e[pos/8] >> uint(pos&7)
+ b &= 1
+ swap ^= int32(b)
+ feCSwap(&x2, &x3, swap)
+ feCSwap(&z2, &z3, swap)
+ swap = int32(b)
+
+ feSub(&tmp0, &x3, &z3)
+ feSub(&tmp1, &x2, &z2)
+ feAdd(&x2, &x2, &z2)
+ feAdd(&z2, &x3, &z3)
+ feMul(&z3, &tmp0, &x2)
+ feMul(&z2, &z2, &tmp1)
+ feSquare(&tmp0, &tmp1)
+ feSquare(&tmp1, &x2)
+ feAdd(&x3, &z3, &z2)
+ feSub(&z2, &z3, &z2)
+ feMul(&x2, &tmp1, &tmp0)
+ feSub(&tmp1, &tmp1, &tmp0)
+ feSquare(&z2, &z2)
+ feMul121666(&z3, &tmp1)
+ feSquare(&x3, &x3)
+ feAdd(&tmp0, &tmp0, &z3)
+ feMul(&z3, &x1, &z2)
+ feMul(&z2, &tmp1, &tmp0)
+ }
+
+ feCSwap(&x2, &x3, swap)
+ feCSwap(&z2, &z3, swap)
+
+ feInvert(&z2, &z2)
+ feMul(&x2, &x2, &z2)
+ feToBytes(out, &x2)
+}
diff --git a/src/vendor/golang_org/x/crypto/curve25519/curve25519_test.go b/src/vendor/golang_org/x/crypto/curve25519/curve25519_test.go
new file mode 100644
index 0000000..14b0ee8
--- /dev/null
+++ b/src/vendor/golang_org/x/crypto/curve25519/curve25519_test.go
@@ -0,0 +1,29 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package curve25519
+
+import (
+ "fmt"
+ "testing"
+)
+
+const expectedHex = "89161fde887b2b53de549af483940106ecc114d6982daa98256de23bdf77661a"
+
+func TestBaseScalarMult(t *testing.T) {
+ var a, b [32]byte
+ in := &a
+ out := &b
+ a[0] = 1
+
+ for i := 0; i < 200; i++ {
+ ScalarBaseMult(out, in)
+ in, out = out, in
+ }
+
+ result := fmt.Sprintf("%x", in[:])
+ if result != expectedHex {
+ t.Errorf("incorrect result: got %s, want %s", result, expectedHex)
+ }
+}
diff --git a/src/vendor/golang_org/x/crypto/curve25519/doc.go b/src/vendor/golang_org/x/crypto/curve25519/doc.go
new file mode 100644
index 0000000..ebeea3c
--- /dev/null
+++ b/src/vendor/golang_org/x/crypto/curve25519/doc.go
@@ -0,0 +1,23 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package curve25519 provides an implementation of scalar multiplication on
+// the elliptic curve known as curve25519. See http://cr.yp.to/ecdh.html
+package curve25519 // import "golang.org/x/crypto/curve25519"
+
+// basePoint is the x coordinate of the generator of the curve.
+var basePoint = [32]byte{9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+
+// ScalarMult sets dst to the product in*base where dst and base are the x
+// coordinates of group points and all values are in little-endian form.
+func ScalarMult(dst, in, base *[32]byte) {
+ scalarMult(dst, in, base)
+}
+
+// ScalarBaseMult sets dst to the product in*base where dst and base are the x
+// coordinates of group points, base is the standard generator and all values
+// are in little-endian form.
+func ScalarBaseMult(dst, in *[32]byte) {
+ ScalarMult(dst, in, &basePoint)
+}
diff --git a/src/vendor/golang_org/x/crypto/curve25519/freeze_amd64.s b/src/vendor/golang_org/x/crypto/curve25519/freeze_amd64.s
new file mode 100644
index 0000000..932800b
--- /dev/null
+++ b/src/vendor/golang_org/x/crypto/curve25519/freeze_amd64.s
@@ -0,0 +1,71 @@
+// Copyright 2012 The Go 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 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 freeze(inout *[5]uint64)
+TEXT ·freeze(SB),7,$0-8
+ MOVQ inout+0(FP), DI
+
+ MOVQ 0(DI),SI
+ MOVQ 8(DI),DX
+ MOVQ 16(DI),CX
+ MOVQ 24(DI),R8
+ MOVQ 32(DI),R9
+ MOVQ ·REDMASK51(SB),AX
+ MOVQ AX,R10
+ SUBQ $18,R10
+ MOVQ $3,R11
+REDUCELOOP:
+ MOVQ SI,R12
+ SHRQ $51,R12
+ ANDQ AX,SI
+ ADDQ R12,DX
+ MOVQ DX,R12
+ SHRQ $51,R12
+ ANDQ AX,DX
+ ADDQ R12,CX
+ MOVQ CX,R12
+ SHRQ $51,R12
+ ANDQ AX,CX
+ ADDQ R12,R8
+ MOVQ R8,R12
+ SHRQ $51,R12
+ ANDQ AX,R8
+ ADDQ R12,R9
+ MOVQ R9,R12
+ SHRQ $51,R12
+ ANDQ AX,R9
+ IMUL3Q $19,R12,R12
+ ADDQ R12,SI
+ SUBQ $1,R11
+ JA REDUCELOOP
+ MOVQ $1,R12
+ CMPQ R10,SI
+ CMOVQLT R11,R12
+ CMPQ AX,DX
+ CMOVQNE R11,R12
+ CMPQ AX,CX
+ CMOVQNE R11,R12
+ CMPQ AX,R8
+ CMOVQNE R11,R12
+ CMPQ AX,R9
+ CMOVQNE R11,R12
+ NEGQ R12
+ ANDQ R12,AX
+ ANDQ R12,R10
+ SUBQ R10,SI
+ SUBQ AX,DX
+ SUBQ AX,CX
+ SUBQ AX,R8
+ SUBQ AX,R9
+ MOVQ SI,0(DI)
+ MOVQ DX,8(DI)
+ MOVQ CX,16(DI)
+ MOVQ R8,24(DI)
+ MOVQ R9,32(DI)
+ RET
diff --git a/src/vendor/golang_org/x/crypto/curve25519/ladderstep_amd64.s b/src/vendor/golang_org/x/crypto/curve25519/ladderstep_amd64.s
new file mode 100644
index 0000000..ee7b36c
--- /dev/null
+++ b/src/vendor/golang_org/x/crypto/curve25519/ladderstep_amd64.s
@@ -0,0 +1,1375 @@
+// Copyright 2012 The Go 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 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 ladderstep(inout *[5][5]uint64)
+TEXT ·ladderstep(SB),0,$296-8
+ MOVQ inout+0(FP),DI
+
+ MOVQ 40(DI),SI
+ MOVQ 48(DI),DX
+ MOVQ 56(DI),CX
+ MOVQ 64(DI),R8
+ MOVQ 72(DI),R9
+ MOVQ SI,AX
+ MOVQ DX,R10
+ MOVQ CX,R11
+ MOVQ R8,R12
+ MOVQ R9,R13
+ ADDQ ·_2P0(SB),AX
+ ADDQ ·_2P1234(SB),R10
+ ADDQ ·_2P1234(SB),R11
+ ADDQ ·_2P1234(SB),R12
+ ADDQ ·_2P1234(SB),R13
+ ADDQ 80(DI),SI
+ ADDQ 88(DI),DX
+ ADDQ 96(DI),CX
+ ADDQ 104(DI),R8
+ ADDQ 112(DI),R9
+ SUBQ 80(DI),AX
+ SUBQ 88(DI),R10
+ SUBQ 96(DI),R11
+ SUBQ 104(DI),R12
+ SUBQ 112(DI),R13
+ MOVQ SI,0(SP)
+ MOVQ DX,8(SP)
+ MOVQ CX,16(SP)
+ MOVQ R8,24(SP)
+ MOVQ R9,32(SP)
+ MOVQ AX,40(SP)
+ MOVQ R10,48(SP)
+ MOVQ R11,56(SP)
+ MOVQ R12,64(SP)
+ MOVQ R13,72(SP)
+ MOVQ 40(SP),AX
+ MULQ 40(SP)
+ MOVQ AX,SI
+ MOVQ DX,CX
+ MOVQ 40(SP),AX
+ SHLQ $1,AX
+ MULQ 48(SP)
+ MOVQ AX,R8
+ MOVQ DX,R9
+ MOVQ 40(SP),AX
+ SHLQ $1,AX
+ MULQ 56(SP)
+ MOVQ AX,R10
+ MOVQ DX,R11
+ MOVQ 40(SP),AX
+ SHLQ $1,AX
+ MULQ 64(SP)
+ MOVQ AX,R12
+ MOVQ DX,R13
+ MOVQ 40(SP),AX
+ SHLQ $1,AX
+ MULQ 72(SP)
+ MOVQ AX,R14
+ MOVQ DX,R15
+ MOVQ 48(SP),AX
+ MULQ 48(SP)
+ ADDQ AX,R10
+ ADCQ DX,R11
+ MOVQ 48(SP),AX
+ SHLQ $1,AX
+ MULQ 56(SP)
+ ADDQ AX,R12
+ ADCQ DX,R13
+ MOVQ 48(SP),AX
+ SHLQ $1,AX
+ MULQ 64(SP)
+ ADDQ AX,R14
+ ADCQ DX,R15
+ MOVQ 48(SP),DX
+ IMUL3Q $38,DX,AX
+ MULQ 72(SP)
+ ADDQ AX,SI
+ ADCQ DX,CX
+ MOVQ 56(SP),AX
+ MULQ 56(SP)
+ ADDQ AX,R14
+ ADCQ DX,R15
+ MOVQ 56(SP),DX
+ IMUL3Q $38,DX,AX
+ MULQ 64(SP)
+ ADDQ AX,SI
+ ADCQ DX,CX
+ MOVQ 56(SP),DX
+ IMUL3Q $38,DX,AX
+ MULQ 72(SP)
+ ADDQ AX,R8
+ ADCQ DX,R9
+ MOVQ 64(SP),DX
+ IMUL3Q $19,DX,AX
+ MULQ 64(SP)
+ ADDQ AX,R8
+ ADCQ DX,R9
+ MOVQ 64(SP),DX
+ IMUL3Q $38,DX,AX
+ MULQ 72(SP)
+ ADDQ AX,R10
+ ADCQ DX,R11
+ MOVQ 72(SP),DX
+ IMUL3Q $19,DX,AX
+ MULQ 72(SP)
+ ADDQ AX,R12
+ ADCQ DX,R13
+ MOVQ ·REDMASK51(SB),DX
+ SHLQ $13,CX:SI
+ ANDQ DX,SI
+ SHLQ $13,R9:R8
+ ANDQ DX,R8
+ ADDQ CX,R8
+ SHLQ $13,R11:R10
+ ANDQ DX,R10
+ ADDQ R9,R10
+ SHLQ $13,R13:R12
+ ANDQ DX,R12
+ ADDQ R11,R12
+ SHLQ $13,R15:R14
+ ANDQ DX,R14
+ ADDQ R13,R14
+ IMUL3Q $19,R15,CX
+ ADDQ CX,SI
+ MOVQ SI,CX
+ SHRQ $51,CX
+ ADDQ R8,CX
+ ANDQ DX,SI
+ MOVQ CX,R8
+ SHRQ $51,CX
+ ADDQ R10,CX
+ ANDQ DX,R8
+ MOVQ CX,R9
+ SHRQ $51,CX
+ ADDQ R12,CX
+ ANDQ DX,R9
+ MOVQ CX,AX
+ SHRQ $51,CX
+ ADDQ R14,CX
+ ANDQ DX,AX
+ MOVQ CX,R10
+ SHRQ $51,CX
+ IMUL3Q $19,CX,CX
+ ADDQ CX,SI
+ ANDQ DX,R10
+ MOVQ SI,80(SP)
+ MOVQ R8,88(SP)
+ MOVQ R9,96(SP)
+ MOVQ AX,104(SP)
+ MOVQ R10,112(SP)
+ MOVQ 0(SP),AX
+ MULQ 0(SP)
+ MOVQ AX,SI
+ MOVQ DX,CX
+ MOVQ 0(SP),AX
+ SHLQ $1,AX
+ MULQ 8(SP)
+ MOVQ AX,R8
+ MOVQ DX,R9
+ MOVQ 0(SP),AX
+ SHLQ $1,AX
+ MULQ 16(SP)
+ MOVQ AX,R10
+ MOVQ DX,R11
+ MOVQ 0(SP),AX
+ SHLQ $1,AX
+ MULQ 24(SP)
+ MOVQ AX,R12
+ MOVQ DX,R13
+ MOVQ 0(SP),AX
+ SHLQ $1,AX
+ MULQ 32(SP)
+ MOVQ AX,R14
+ MOVQ DX,R15
+ MOVQ 8(SP),AX
+ MULQ 8(SP)
+ ADDQ AX,R10
+ ADCQ DX,R11
+ MOVQ 8(SP),AX
+ SHLQ $1,AX
+ MULQ 16(SP)
+ ADDQ AX,R12
+ ADCQ DX,R13
+ MOVQ 8(SP),AX
+ SHLQ $1,AX
+ MULQ 24(SP)
+ ADDQ AX,R14
+ ADCQ DX,R15
+ MOVQ 8(SP),DX
+ IMUL3Q $38,DX,AX
+ MULQ 32(SP)
+ ADDQ AX,SI
+ ADCQ DX,CX
+ MOVQ 16(SP),AX
+ MULQ 16(SP)
+ ADDQ AX,R14
+ ADCQ DX,R15
+ MOVQ 16(SP),DX
+ IMUL3Q $38,DX,AX
+ MULQ 24(SP)
+ ADDQ AX,SI
+ ADCQ DX,CX
+ MOVQ 16(SP),DX
+ IMUL3Q $38,DX,AX
+ MULQ 32(SP)
+ ADDQ AX,R8
+ ADCQ DX,R9
+ MOVQ 24(SP),DX
+ IMUL3Q $19,DX,AX
+ MULQ 24(SP)
+ ADDQ AX,R8
+ ADCQ DX,R9
+ MOVQ 24(SP),DX
+ IMUL3Q $38,DX,AX
+ MULQ 32(SP)
+ ADDQ AX,R10
+ ADCQ DX,R11
+ MOVQ 32(SP),DX
+ IMUL3Q $19,DX,AX
+ MULQ 32(SP)
+ ADDQ AX,R12
+ ADCQ DX,R13
+ MOVQ ·REDMASK51(SB),DX
+ SHLQ $13,CX:SI
+ ANDQ DX,SI
+ SHLQ $13,R9:R8
+ ANDQ DX,R8
+ ADDQ CX,R8
+ SHLQ $13,R11:R10
+ ANDQ DX,R10
+ ADDQ R9,R10
+ SHLQ $13,R13:R12
+ ANDQ DX,R12
+ ADDQ R11,R12
+ SHLQ $13,R15:R14
+ ANDQ DX,R14
+ ADDQ R13,R14
+ IMUL3Q $19,R15,CX
+ ADDQ CX,SI
+ MOVQ SI,CX
+ SHRQ $51,CX
+ ADDQ R8,CX
+ ANDQ DX,SI
+ MOVQ CX,R8
+ SHRQ $51,CX
+ ADDQ R10,CX
+ ANDQ DX,R8
+ MOVQ CX,R9
+ SHRQ $51,CX
+ ADDQ R12,CX
+ ANDQ DX,R9
+ MOVQ CX,AX
+ SHRQ $51,CX
+ ADDQ R14,CX
+ ANDQ DX,AX
+ MOVQ CX,R10
+ SHRQ $51,CX
+ IMUL3Q $19,CX,CX
+ ADDQ CX,SI
+ ANDQ DX,R10
+ MOVQ SI,120(SP)
+ MOVQ R8,128(SP)
+ MOVQ R9,136(SP)
+ MOVQ AX,144(SP)
+ MOVQ R10,152(SP)
+ MOVQ SI,SI
+ MOVQ R8,DX
+ MOVQ R9,CX
+ MOVQ AX,R8
+ MOVQ R10,R9
+ ADDQ ·_2P0(SB),SI
+ ADDQ ·_2P1234(SB),DX
+ ADDQ ·_2P1234(SB),CX
+ ADDQ ·_2P1234(SB),R8
+ ADDQ ·_2P1234(SB),R9
+ SUBQ 80(SP),SI
+ SUBQ 88(SP),DX
+ SUBQ 96(SP),CX
+ SUBQ 104(SP),R8
+ SUBQ 112(SP),R9
+ MOVQ SI,160(SP)
+ MOVQ DX,168(SP)
+ MOVQ CX,176(SP)
+ MOVQ R8,184(SP)
+ MOVQ R9,192(SP)
+ MOVQ 120(DI),SI
+ MOVQ 128(DI),DX
+ MOVQ 136(DI),CX
+ MOVQ 144(DI),R8
+ MOVQ 152(DI),R9
+ MOVQ SI,AX
+ MOVQ DX,R10
+ MOVQ CX,R11
+ MOVQ R8,R12
+ MOVQ R9,R13
+ ADDQ ·_2P0(SB),AX
+ ADDQ ·_2P1234(SB),R10
+ ADDQ ·_2P1234(SB),R11
+ ADDQ ·_2P1234(SB),R12
+ ADDQ ·_2P1234(SB),R13
+ ADDQ 160(DI),SI
+ ADDQ 168(DI),DX
+ ADDQ 176(DI),CX
+ ADDQ 184(DI),R8
+ ADDQ 192(DI),R9
+ SUBQ 160(DI),AX
+ SUBQ 168(DI),R10
+ SUBQ 176(DI),R11
+ SUBQ 184(DI),R12
+ SUBQ 192(DI),R13
+ MOVQ SI,200(SP)
+ MOVQ DX,208(SP)
+ MOVQ CX,216(SP)
+ MOVQ R8,224(SP)
+ MOVQ R9,232(SP)
+ MOVQ AX,240(SP)
+ MOVQ R10,248(SP)
+ MOVQ R11,256(SP)
+ MOVQ R12,264(SP)
+ MOVQ R13,272(SP)
+ MOVQ 224(SP),SI
+ IMUL3Q $19,SI,AX
+ MOVQ AX,280(SP)
+ MULQ 56(SP)
+ MOVQ AX,SI
+ MOVQ DX,CX
+ MOVQ 232(SP),DX
+ IMUL3Q $19,DX,AX
+ MOVQ AX,288(SP)
+ MULQ 48(SP)
+ ADDQ AX,SI
+ ADCQ DX,CX
+ MOVQ 200(SP),AX
+ MULQ 40(SP)
+ ADDQ AX,SI
+ ADCQ DX,CX
+ MOVQ 200(SP),AX
+ MULQ 48(SP)
+ MOVQ AX,R8
+ MOVQ DX,R9
+ MOVQ 200(SP),AX
+ MULQ 56(SP)
+ MOVQ AX,R10
+ MOVQ DX,R11
+ MOVQ 200(SP),AX
+ MULQ 64(SP)
+ MOVQ AX,R12
+ MOVQ DX,R13
+ MOVQ 200(SP),AX
+ MULQ 72(SP)
+ MOVQ AX,R14
+ MOVQ DX,R15
+ MOVQ 208(SP),AX
+ MULQ 40(SP)
+ ADDQ AX,R8
+ ADCQ DX,R9
+ MOVQ 208(SP),AX
+ MULQ 48(SP)
+ ADDQ AX,R10
+ ADCQ DX,R11
+ MOVQ 208(SP),AX
+ MULQ 56(SP)
+ ADDQ AX,R12
+ ADCQ DX,R13
+ MOVQ 208(SP),AX
+ MULQ 64(SP)
+ ADDQ AX,R14
+ ADCQ DX,R15
+ MOVQ 208(SP),DX
+ IMUL3Q $19,DX,AX
+ MULQ 72(SP)
+ ADDQ AX,SI
+ ADCQ DX,CX
+ MOVQ 216(SP),AX
+ MULQ 40(SP)
+ ADDQ AX,R10
+ ADCQ DX,R11
+ MOVQ 216(SP),AX
+ MULQ 48(SP)
+ ADDQ AX,R12
+ ADCQ DX,R13
+ MOVQ 216(SP),AX
+ MULQ 56(SP)
+ ADDQ AX,R14
+ ADCQ DX,R15
+ MOVQ 216(SP),DX
+ IMUL3Q $19,DX,AX
+ MULQ 64(SP)
+ ADDQ AX,SI
+ ADCQ DX,CX
+ MOVQ 216(SP),DX
+ IMUL3Q $19,DX,AX
+ MULQ 72(SP)
+ ADDQ AX,R8
+ ADCQ DX,R9
+ MOVQ 224(SP),AX
+ MULQ 40(SP)
+ ADDQ AX,R12
+ ADCQ DX,R13
+ MOVQ 224(SP),AX
+ MULQ 48(SP)
+ ADDQ AX,R14
+ ADCQ DX,R15
+ MOVQ 280(SP),AX
+ MULQ 64(SP)
+ ADDQ AX,R8
+ ADCQ DX,R9
+ MOVQ 280(SP),AX
+ MULQ 72(SP)
+ ADDQ AX,R10
+ ADCQ DX,R11
+ MOVQ 232(SP),AX
+ MULQ 40(SP)
+ ADDQ AX,R14
+ ADCQ DX,R15
+ MOVQ 288(SP),AX
+ MULQ 56(SP)
+ ADDQ AX,R8
+ ADCQ DX,R9
+ MOVQ 288(SP),AX
+ MULQ 64(SP)
+ ADDQ AX,R10
+ ADCQ DX,R11
+ MOVQ 288(SP),AX
+ MULQ 72(SP)
+ ADDQ AX,R12
+ ADCQ DX,R13
+ MOVQ ·REDMASK51(SB),DX
+ SHLQ $13,CX:SI
+ ANDQ DX,SI
+ SHLQ $13,R9:R8
+ ANDQ DX,R8
+ ADDQ CX,R8
+ SHLQ $13,R11:R10
+ ANDQ DX,R10
+ ADDQ R9,R10
+ SHLQ $13,R13:R12
+ ANDQ DX,R12
+ ADDQ R11,R12
+ SHLQ $13,R15:R14
+ ANDQ DX,R14
+ ADDQ R13,R14
+ IMUL3Q $19,R15,CX
+ ADDQ CX,SI
+ MOVQ SI,CX
+ SHRQ $51,CX
+ ADDQ R8,CX
+ MOVQ CX,R8
+ SHRQ $51,CX
+ ANDQ DX,SI
+ ADDQ R10,CX
+ MOVQ CX,R9
+ SHRQ $51,CX
+ ANDQ DX,R8
+ ADDQ R12,CX
+ MOVQ CX,AX
+ SHRQ $51,CX
+ ANDQ DX,R9
+ ADDQ R14,CX
+ MOVQ CX,R10
+ SHRQ $51,CX
+ ANDQ DX,AX
+ IMUL3Q $19,CX,CX
+ ADDQ CX,SI
+ ANDQ DX,R10
+ MOVQ SI,40(SP)
+ MOVQ R8,48(SP)
+ MOVQ R9,56(SP)
+ MOVQ AX,64(SP)
+ MOVQ R10,72(SP)
+ MOVQ 264(SP),SI
+ IMUL3Q $19,SI,AX
+ MOVQ AX,200(SP)
+ MULQ 16(SP)
+ MOVQ AX,SI
+ MOVQ DX,CX
+ MOVQ 272(SP),DX
+ IMUL3Q $19,DX,AX
+ MOVQ AX,208(SP)
+ MULQ 8(SP)
+ ADDQ AX,SI
+ ADCQ DX,CX
+ MOVQ 240(SP),AX
+ MULQ 0(SP)
+ ADDQ AX,SI
+ ADCQ DX,CX
+ MOVQ 240(SP),AX
+ MULQ 8(SP)
+ MOVQ AX,R8
+ MOVQ DX,R9
+ MOVQ 240(SP),AX
+ MULQ 16(SP)
+ MOVQ AX,R10
+ MOVQ DX,R11
+ MOVQ 240(SP),AX
+ MULQ 24(SP)
+ MOVQ AX,R12
+ MOVQ DX,R13
+ MOVQ 240(SP),AX
+ MULQ 32(SP)
+ MOVQ AX,R14
+ MOVQ DX,R15
+ MOVQ 248(SP),AX
+ MULQ 0(SP)
+ ADDQ AX,R8
+ ADCQ DX,R9
+ MOVQ 248(SP),AX
+ MULQ 8(SP)
+ ADDQ AX,R10
+ ADCQ DX,R11
+ MOVQ 248(SP),AX
+ MULQ 16(SP)
+ ADDQ AX,R12
+ ADCQ DX,R13
+ MOVQ 248(SP),AX
+ MULQ 24(SP)
+ ADDQ AX,R14
+ ADCQ DX,R15
+ MOVQ 248(SP),DX
+ IMUL3Q $19,DX,AX
+ MULQ 32(SP)
+ ADDQ AX,SI
+ ADCQ DX,CX
+ MOVQ 256(SP),AX
+ MULQ 0(SP)
+ ADDQ AX,R10
+ ADCQ DX,R11
+ MOVQ 256(SP),AX
+ MULQ 8(SP)
+ ADDQ AX,R12
+ ADCQ DX,R13
+ MOVQ 256(SP),AX
+ MULQ 16(SP)
+ ADDQ AX,R14
+ ADCQ DX,R15
+ MOVQ 256(SP),DX
+ IMUL3Q $19,DX,AX
+ MULQ 24(SP)
+ ADDQ AX,SI
+ ADCQ DX,CX
+ MOVQ 256(SP),DX
+ IMUL3Q $19,DX,AX
+ MULQ 32(SP)
+ ADDQ AX,R8
+ ADCQ DX,R9
+ MOVQ 264(SP),AX
+ MULQ 0(SP)
+ ADDQ AX,R12
+ ADCQ DX,R13
+ MOVQ 264(SP),AX
+ MULQ 8(SP)
+ ADDQ AX,R14
+ ADCQ DX,R15
+ MOVQ 200(SP),AX
+ MULQ 24(SP)
+ ADDQ AX,R8
+ ADCQ DX,R9
+ MOVQ 200(SP),AX
+ MULQ 32(SP)
+ ADDQ AX,R10
+ ADCQ DX,R11
+ MOVQ 272(SP),AX
+ MULQ 0(SP)
+ ADDQ AX,R14
+ ADCQ DX,R15
+ MOVQ 208(SP),AX
+ MULQ 16(SP)
+ ADDQ AX,R8
+ ADCQ DX,R9
+ MOVQ 208(SP),AX
+ MULQ 24(SP)
+ ADDQ AX,R10
+ ADCQ DX,R11
+ MOVQ 208(SP),AX
+ MULQ 32(SP)
+ ADDQ AX,R12
+ ADCQ DX,R13
+ MOVQ ·REDMASK51(SB),DX
+ SHLQ $13,CX:SI
+ ANDQ DX,SI
+ SHLQ $13,R9:R8
+ ANDQ DX,R8
+ ADDQ CX,R8
+ SHLQ $13,R11:R10
+ ANDQ DX,R10
+ ADDQ R9,R10
+ SHLQ $13,R13:R12
+ ANDQ DX,R12
+ ADDQ R11,R12
+ SHLQ $13,R15:R14
+ ANDQ DX,R14
+ ADDQ R13,R14
+ IMUL3Q $19,R15,CX
+ ADDQ CX,SI
+ MOVQ SI,CX
+ SHRQ $51,CX
+ ADDQ R8,CX
+ MOVQ CX,R8
+ SHRQ $51,CX
+ ANDQ DX,SI
+ ADDQ R10,CX
+ MOVQ CX,R9
+ SHRQ $51,CX
+ ANDQ DX,R8
+ ADDQ R12,CX
+ MOVQ CX,AX
+ SHRQ $51,CX
+ ANDQ DX,R9
+ ADDQ R14,CX
+ MOVQ CX,R10
+ SHRQ $51,CX
+ ANDQ DX,AX
+ IMUL3Q $19,CX,CX
+ ADDQ CX,SI
+ ANDQ DX,R10
+ MOVQ SI,DX
+ MOVQ R8,CX
+ MOVQ R9,R11
+ MOVQ AX,R12
+ MOVQ R10,R13
+ ADDQ ·_2P0(SB),DX
+ ADDQ ·_2P1234(SB),CX
+ ADDQ ·_2P1234(SB),R11
+ ADDQ ·_2P1234(SB),R12
+ ADDQ ·_2P1234(SB),R13
+ ADDQ 40(SP),SI
+ ADDQ 48(SP),R8
+ ADDQ 56(SP),R9
+ ADDQ 64(SP),AX
+ ADDQ 72(SP),R10
+ SUBQ 40(SP),DX
+ SUBQ 48(SP),CX
+ SUBQ 56(SP),R11
+ SUBQ 64(SP),R12
+ SUBQ 72(SP),R13
+ MOVQ SI,120(DI)
+ MOVQ R8,128(DI)
+ MOVQ R9,136(DI)
+ MOVQ AX,144(DI)
+ MOVQ R10,152(DI)
+ MOVQ DX,160(DI)
+ MOVQ CX,168(DI)
+ MOVQ R11,176(DI)
+ MOVQ R12,184(DI)
+ MOVQ R13,192(DI)
+ MOVQ 120(DI),AX
+ MULQ 120(DI)
+ MOVQ AX,SI
+ MOVQ DX,CX
+ MOVQ 120(DI),AX
+ SHLQ $1,AX
+ MULQ 128(DI)
+ MOVQ AX,R8
+ MOVQ DX,R9
+ MOVQ 120(DI),AX
+ SHLQ $1,AX
+ MULQ 136(DI)
+ MOVQ AX,R10
+ MOVQ DX,R11
+ MOVQ 120(DI),AX
+ SHLQ $1,AX
+ MULQ 144(DI)
+ MOVQ AX,R12
+ MOVQ DX,R13
+ MOVQ 120(DI),AX
+ SHLQ $1,AX
+ MULQ 152(DI)
+ MOVQ AX,R14
+ MOVQ DX,R15
+ MOVQ 128(DI),AX
+ MULQ 128(DI)
+ ADDQ AX,R10
+ ADCQ DX,R11
+ MOVQ 128(DI),AX
+ SHLQ $1,AX
+ MULQ 136(DI)
+ ADDQ AX,R12
+ ADCQ DX,R13
+ MOVQ 128(DI),AX
+ SHLQ $1,AX
+ MULQ 144(DI)
+ ADDQ AX,R14
+ ADCQ DX,R15
+ MOVQ 128(DI),DX
+ IMUL3Q $38,DX,AX
+ MULQ 152(DI)
+ ADDQ AX,SI
+ ADCQ DX,CX
+ MOVQ 136(DI),AX
+ MULQ 136(DI)
+ ADDQ AX,R14
+ ADCQ DX,R15
+ MOVQ 136(DI),DX
+ IMUL3Q $38,DX,AX
+ MULQ 144(DI)
+ ADDQ AX,SI
+ ADCQ DX,CX
+ MOVQ 136(DI),DX
+ IMUL3Q $38,DX,AX
+ MULQ 152(DI)
+ ADDQ AX,R8
+ ADCQ DX,R9
+ MOVQ 144(DI),DX
+ IMUL3Q $19,DX,AX
+ MULQ 144(DI)
+ ADDQ AX,R8
+ ADCQ DX,R9
+ MOVQ 144(DI),DX
+ IMUL3Q $38,DX,AX
+ MULQ 152(DI)
+ ADDQ AX,R10
+ ADCQ DX,R11
+ MOVQ 152(DI),DX
+ IMUL3Q $19,DX,AX
+ MULQ 152(DI)
+ ADDQ AX,R12
+ ADCQ DX,R13
+ MOVQ ·REDMASK51(SB),DX
+ SHLQ $13,CX:SI
+ ANDQ DX,SI
+ SHLQ $13,R9:R8
+ ANDQ DX,R8
+ ADDQ CX,R8
+ SHLQ $13,R11:R10
+ ANDQ DX,R10
+ ADDQ R9,R10
+ SHLQ $13,R13:R12
+ ANDQ DX,R12
+ ADDQ R11,R12
+ SHLQ $13,R15:R14
+ ANDQ DX,R14
+ ADDQ R13,R14
+ IMUL3Q $19,R15,CX
+ ADDQ CX,SI
+ MOVQ SI,CX
+ SHRQ $51,CX
+ ADDQ R8,CX
+ ANDQ DX,SI
+ MOVQ CX,R8
+ SHRQ $51,CX
+ ADDQ R10,CX
+ ANDQ DX,R8
+ MOVQ CX,R9
+ SHRQ $51,CX
+ ADDQ R12,CX
+ ANDQ DX,R9
+ MOVQ CX,AX
+ SHRQ $51,CX
+ ADDQ R14,CX
+ ANDQ DX,AX
+ MOVQ CX,R10
+ SHRQ $51,CX
+ IMUL3Q $19,CX,CX
+ ADDQ CX,SI
+ ANDQ DX,R10
+ MOVQ SI,120(DI)
+ MOVQ R8,128(DI)
+ MOVQ R9,136(DI)
+ MOVQ AX,144(DI)
+ MOVQ R10,152(DI)
+ MOVQ 160(DI),AX
+ MULQ 160(DI)
+ MOVQ AX,SI
+ MOVQ DX,CX
+ MOVQ 160(DI),AX
+ SHLQ $1,AX
+ MULQ 168(DI)
+ MOVQ AX,R8
+ MOVQ DX,R9
+ MOVQ 160(DI),AX
+ SHLQ $1,AX
+ MULQ 176(DI)
+ MOVQ AX,R10
+ MOVQ DX,R11
+ MOVQ 160(DI),AX
+ SHLQ $1,AX
+ MULQ 184(DI)
+ MOVQ AX,R12
+ MOVQ DX,R13
+ MOVQ 160(DI),AX
+ SHLQ $1,AX
+ MULQ 192(DI)
+ MOVQ AX,R14
+ MOVQ DX,R15
+ MOVQ 168(DI),AX
+ MULQ 168(DI)
+ ADDQ AX,R10
+ ADCQ DX,R11
+ MOVQ 168(DI),AX
+ SHLQ $1,AX
+ MULQ 176(DI)
+ ADDQ AX,R12
+ ADCQ DX,R13
+ MOVQ 168(DI),AX
+ SHLQ $1,AX
+ MULQ 184(DI)
+ ADDQ AX,R14
+ ADCQ DX,R15
+ MOVQ 168(DI),DX
+ IMUL3Q $38,DX,AX
+ MULQ 192(DI)
+ ADDQ AX,SI
+ ADCQ DX,CX
+ MOVQ 176(DI),AX
+ MULQ 176(DI)
+ ADDQ AX,R14
+ ADCQ DX,R15
+ MOVQ 176(DI),DX
+ IMUL3Q $38,DX,AX
+ MULQ 184(DI)
+ ADDQ AX,SI
+ ADCQ DX,CX
+ MOVQ 176(DI),DX
+ IMUL3Q $38,DX,AX
+ MULQ 192(DI)
+ ADDQ AX,R8
+ ADCQ DX,R9
+ MOVQ 184(DI),DX
+ IMUL3Q $19,DX,AX
+ MULQ 184(DI)
+ ADDQ AX,R8
+ ADCQ DX,R9
+ MOVQ 184(DI),DX
+ IMUL3Q $38,DX,AX
+ MULQ 192(DI)
+ ADDQ AX,R10
+ ADCQ DX,R11
+ MOVQ 192(DI),DX
+ IMUL3Q $19,DX,AX
+ MULQ 192(DI)
+ ADDQ AX,R12
+ ADCQ DX,R13
+ MOVQ ·REDMASK51(SB),DX
+ SHLQ $13,CX:SI
+ ANDQ DX,SI
+ SHLQ $13,R9:R8
+ ANDQ DX,R8
+ ADDQ CX,R8
+ SHLQ $13,R11:R10
+ ANDQ DX,R10
+ ADDQ R9,R10
+ SHLQ $13,R13:R12
+ ANDQ DX,R12
+ ADDQ R11,R12
+ SHLQ $13,R15:R14
+ ANDQ DX,R14
+ ADDQ R13,R14
+ IMUL3Q $19,R15,CX
+ ADDQ CX,SI
+ MOVQ SI,CX
+ SHRQ $51,CX
+ ADDQ R8,CX
+ ANDQ DX,SI
+ MOVQ CX,R8
+ SHRQ $51,CX
+ ADDQ R10,CX
+ ANDQ DX,R8
+ MOVQ CX,R9
+ SHRQ $51,CX
+ ADDQ R12,CX
+ ANDQ DX,R9
+ MOVQ CX,AX
+ SHRQ $51,CX
+ ADDQ R14,CX
+ ANDQ DX,AX
+ MOVQ CX,R10
+ SHRQ $51,CX
+ IMUL3Q $19,CX,CX
+ ADDQ CX,SI
+ ANDQ DX,R10
+ MOVQ SI,160(DI)
+ MOVQ R8,168(DI)
+ MOVQ R9,176(DI)
+ MOVQ AX,184(DI)
+ MOVQ R10,192(DI)
+ MOVQ 184(DI),SI
+ IMUL3Q $19,SI,AX
+ MOVQ AX,0(SP)
+ MULQ 16(DI)
+ MOVQ AX,SI
+ MOVQ DX,CX
+ MOVQ 192(DI),DX
+ IMUL3Q $19,DX,AX
+ MOVQ AX,8(SP)
+ MULQ 8(DI)
+ ADDQ AX,SI
+ ADCQ DX,CX
+ MOVQ 160(DI),AX
+ MULQ 0(DI)
+ ADDQ AX,SI
+ ADCQ DX,CX
+ MOVQ 160(DI),AX
+ MULQ 8(DI)
+ MOVQ AX,R8
+ MOVQ DX,R9
+ MOVQ 160(DI),AX
+ MULQ 16(DI)
+ MOVQ AX,R10
+ MOVQ DX,R11
+ MOVQ 160(DI),AX
+ MULQ 24(DI)
+ MOVQ AX,R12
+ MOVQ DX,R13
+ MOVQ 160(DI),AX
+ MULQ 32(DI)
+ MOVQ AX,R14
+ MOVQ DX,R15
+ MOVQ 168(DI),AX
+ MULQ 0(DI)
+ ADDQ AX,R8
+ ADCQ DX,R9
+ MOVQ 168(DI),AX
+ MULQ 8(DI)
+ ADDQ AX,R10
+ ADCQ DX,R11
+ MOVQ 168(DI),AX
+ MULQ 16(DI)
+ ADDQ AX,R12
+ ADCQ DX,R13
+ MOVQ 168(DI),AX
+ MULQ 24(DI)
+ ADDQ AX,R14
+ ADCQ DX,R15
+ MOVQ 168(DI),DX
+ IMUL3Q $19,DX,AX
+ MULQ 32(DI)
+ ADDQ AX,SI
+ ADCQ DX,CX
+ MOVQ 176(DI),AX
+ MULQ 0(DI)
+ ADDQ AX,R10
+ ADCQ DX,R11
+ MOVQ 176(DI),AX
+ MULQ 8(DI)
+ ADDQ AX,R12
+ ADCQ DX,R13
+ MOVQ 176(DI),AX
+ MULQ 16(DI)
+ ADDQ AX,R14
+ ADCQ DX,R15
+ MOVQ 176(DI),DX
+ IMUL3Q $19,DX,AX
+ MULQ 24(DI)
+ ADDQ AX,SI
+ ADCQ DX,CX
+ MOVQ 176(DI),DX
+ IMUL3Q $19,DX,AX
+ MULQ 32(DI)
+ ADDQ AX,R8
+ ADCQ DX,R9
+ MOVQ 184(DI),AX
+ MULQ 0(DI)
+ ADDQ AX,R12
+ ADCQ DX,R13
+ MOVQ 184(DI),AX
+ MULQ 8(DI)
+ ADDQ AX,R14
+ ADCQ DX,R15
+ MOVQ 0(SP),AX
+ MULQ 24(DI)
+ ADDQ AX,R8
+ ADCQ DX,R9
+ MOVQ 0(SP),AX
+ MULQ 32(DI)
+ ADDQ AX,R10
+ ADCQ DX,R11
+ MOVQ 192(DI),AX
+ MULQ 0(DI)
+ ADDQ AX,R14
+ ADCQ DX,R15
+ MOVQ 8(SP),AX
+ MULQ 16(DI)
+ ADDQ AX,R8
+ ADCQ DX,R9
+ MOVQ 8(SP),AX
+ MULQ 24(DI)
+ ADDQ AX,R10
+ ADCQ DX,R11
+ MOVQ 8(SP),AX
+ MULQ 32(DI)
+ ADDQ AX,R12
+ ADCQ DX,R13
+ MOVQ ·REDMASK51(SB),DX
+ SHLQ $13,CX:SI
+ ANDQ DX,SI
+ SHLQ $13,R9:R8
+ ANDQ DX,R8
+ ADDQ CX,R8
+ SHLQ $13,R11:R10
+ ANDQ DX,R10
+ ADDQ R9,R10
+ SHLQ $13,R13:R12
+ ANDQ DX,R12
+ ADDQ R11,R12
+ SHLQ $13,R15:R14
+ ANDQ DX,R14
+ ADDQ R13,R14
+ IMUL3Q $19,R15,CX
+ ADDQ CX,SI
+ MOVQ SI,CX
+ SHRQ $51,CX
+ ADDQ R8,CX
+ MOVQ CX,R8
+ SHRQ $51,CX
+ ANDQ DX,SI
+ ADDQ R10,CX
+ MOVQ CX,R9
+ SHRQ $51,CX
+ ANDQ DX,R8
+ ADDQ R12,CX
+ MOVQ CX,AX
+ SHRQ $51,CX
+ ANDQ DX,R9
+ ADDQ R14,CX
+ MOVQ CX,R10
+ SHRQ $51,CX
+ ANDQ DX,AX
+ IMUL3Q $19,CX,CX
+ ADDQ CX,SI
+ ANDQ DX,R10
+ MOVQ SI,160(DI)
+ MOVQ R8,168(DI)
+ MOVQ R9,176(DI)
+ MOVQ AX,184(DI)
+ MOVQ R10,192(DI)
+ MOVQ 144(SP),SI
+ IMUL3Q $19,SI,AX
+ MOVQ AX,0(SP)
+ MULQ 96(SP)
+ MOVQ AX,SI
+ MOVQ DX,CX
+ MOVQ 152(SP),DX
+ IMUL3Q $19,DX,AX
+ MOVQ AX,8(SP)
+ MULQ 88(SP)
+ ADDQ AX,SI
+ ADCQ DX,CX
+ MOVQ 120(SP),AX
+ MULQ 80(SP)
+ ADDQ AX,SI
+ ADCQ DX,CX
+ MOVQ 120(SP),AX
+ MULQ 88(SP)
+ MOVQ AX,R8
+ MOVQ DX,R9
+ MOVQ 120(SP),AX
+ MULQ 96(SP)
+ MOVQ AX,R10
+ MOVQ DX,R11
+ MOVQ 120(SP),AX
+ MULQ 104(SP)
+ MOVQ AX,R12
+ MOVQ DX,R13
+ MOVQ 120(SP),AX
+ MULQ 112(SP)
+ MOVQ AX,R14
+ MOVQ DX,R15
+ MOVQ 128(SP),AX
+ MULQ 80(SP)
+ ADDQ AX,R8
+ ADCQ DX,R9
+ MOVQ 128(SP),AX
+ MULQ 88(SP)
+ ADDQ AX,R10
+ ADCQ DX,R11
+ MOVQ 128(SP),AX
+ MULQ 96(SP)
+ ADDQ AX,R12
+ ADCQ DX,R13
+ MOVQ 128(SP),AX
+ MULQ 104(SP)
+ ADDQ AX,R14
+ ADCQ DX,R15
+ MOVQ 128(SP),DX
+ IMUL3Q $19,DX,AX
+ MULQ 112(SP)
+ ADDQ AX,SI
+ ADCQ DX,CX
+ MOVQ 136(SP),AX
+ MULQ 80(SP)
+ ADDQ AX,R10
+ ADCQ DX,R11
+ MOVQ 136(SP),AX
+ MULQ 88(SP)
+ ADDQ AX,R12
+ ADCQ DX,R13
+ MOVQ 136(SP),AX
+ MULQ 96(SP)
+ ADDQ AX,R14
+ ADCQ DX,R15
+ MOVQ 136(SP),DX
+ IMUL3Q $19,DX,AX
+ MULQ 104(SP)
+ ADDQ AX,SI
+ ADCQ DX,CX
+ MOVQ 136(SP),DX
+ IMUL3Q $19,DX,AX
+ MULQ 112(SP)
+ ADDQ AX,R8
+ ADCQ DX,R9
+ MOVQ 144(SP),AX
+ MULQ 80(SP)
+ ADDQ AX,R12
+ ADCQ DX,R13
+ MOVQ 144(SP),AX
+ MULQ 88(SP)
+ ADDQ AX,R14
+ ADCQ DX,R15
+ MOVQ 0(SP),AX
+ MULQ 104(SP)
+ ADDQ AX,R8
+ ADCQ DX,R9
+ MOVQ 0(SP),AX
+ MULQ 112(SP)
+ ADDQ AX,R10
+ ADCQ DX,R11
+ MOVQ 152(SP),AX
+ MULQ 80(SP)
+ ADDQ AX,R14
+ ADCQ DX,R15
+ MOVQ 8(SP),AX
+ MULQ 96(SP)
+ ADDQ AX,R8
+ ADCQ DX,R9
+ MOVQ 8(SP),AX
+ MULQ 104(SP)
+ ADDQ AX,R10
+ ADCQ DX,R11
+ MOVQ 8(SP),AX
+ MULQ 112(SP)
+ ADDQ AX,R12
+ ADCQ DX,R13
+ MOVQ ·REDMASK51(SB),DX
+ SHLQ $13,CX:SI
+ ANDQ DX,SI
+ SHLQ $13,R9:R8
+ ANDQ DX,R8
+ ADDQ CX,R8
+ SHLQ $13,R11:R10
+ ANDQ DX,R10
+ ADDQ R9,R10
+ SHLQ $13,R13:R12
+ ANDQ DX,R12
+ ADDQ R11,R12
+ SHLQ $13,R15:R14
+ ANDQ DX,R14
+ ADDQ R13,R14
+ IMUL3Q $19,R15,CX
+ ADDQ CX,SI
+ MOVQ SI,CX
+ SHRQ $51,CX
+ ADDQ R8,CX
+ MOVQ CX,R8
+ SHRQ $51,CX
+ ANDQ DX,SI
+ ADDQ R10,CX
+ MOVQ CX,R9
+ SHRQ $51,CX
+ ANDQ DX,R8
+ ADDQ R12,CX
+ MOVQ CX,AX
+ SHRQ $51,CX
+ ANDQ DX,R9
+ ADDQ R14,CX
+ MOVQ CX,R10
+ SHRQ $51,CX
+ ANDQ DX,AX
+ IMUL3Q $19,CX,CX
+ ADDQ CX,SI
+ ANDQ DX,R10
+ MOVQ SI,40(DI)
+ MOVQ R8,48(DI)
+ MOVQ R9,56(DI)
+ MOVQ AX,64(DI)
+ MOVQ R10,72(DI)
+ MOVQ 160(SP),AX
+ MULQ ·_121666_213(SB)
+ SHRQ $13,AX
+ MOVQ AX,SI
+ MOVQ DX,CX
+ MOVQ 168(SP),AX
+ MULQ ·_121666_213(SB)
+ SHRQ $13,AX
+ ADDQ AX,CX
+ MOVQ DX,R8
+ MOVQ 176(SP),AX
+ MULQ ·_121666_213(SB)
+ SHRQ $13,AX
+ ADDQ AX,R8
+ MOVQ DX,R9
+ MOVQ 184(SP),AX
+ MULQ ·_121666_213(SB)
+ SHRQ $13,AX
+ ADDQ AX,R9
+ MOVQ DX,R10
+ MOVQ 192(SP),AX
+ MULQ ·_121666_213(SB)
+ SHRQ $13,AX
+ ADDQ AX,R10
+ IMUL3Q $19,DX,DX
+ ADDQ DX,SI
+ ADDQ 80(SP),SI
+ ADDQ 88(SP),CX
+ ADDQ 96(SP),R8
+ ADDQ 104(SP),R9
+ ADDQ 112(SP),R10
+ MOVQ SI,80(DI)
+ MOVQ CX,88(DI)
+ MOVQ R8,96(DI)
+ MOVQ R9,104(DI)
+ MOVQ R10,112(DI)
+ MOVQ 104(DI),SI
+ IMUL3Q $19,SI,AX
+ MOVQ AX,0(SP)
+ MULQ 176(SP)
+ MOVQ AX,SI
+ MOVQ DX,CX
+ MOVQ 112(DI),DX
+ IMUL3Q $19,DX,AX
+ MOVQ AX,8(SP)
+ MULQ 168(SP)
+ ADDQ AX,SI
+ ADCQ DX,CX
+ MOVQ 80(DI),AX
+ MULQ 160(SP)
+ ADDQ AX,SI
+ ADCQ DX,CX
+ MOVQ 80(DI),AX
+ MULQ 168(SP)
+ MOVQ AX,R8
+ MOVQ DX,R9
+ MOVQ 80(DI),AX
+ MULQ 176(SP)
+ MOVQ AX,R10
+ MOVQ DX,R11
+ MOVQ 80(DI),AX
+ MULQ 184(SP)
+ MOVQ AX,R12
+ MOVQ DX,R13
+ MOVQ 80(DI),AX
+ MULQ 192(SP)
+ MOVQ AX,R14
+ MOVQ DX,R15
+ MOVQ 88(DI),AX
+ MULQ 160(SP)
+ ADDQ AX,R8
+ ADCQ DX,R9
+ MOVQ 88(DI),AX
+ MULQ 168(SP)
+ ADDQ AX,R10
+ ADCQ DX,R11
+ MOVQ 88(DI),AX
+ MULQ 176(SP)
+ ADDQ AX,R12
+ ADCQ DX,R13
+ MOVQ 88(DI),AX
+ MULQ 184(SP)
+ ADDQ AX,R14
+ ADCQ DX,R15
+ MOVQ 88(DI),DX
+ IMUL3Q $19,DX,AX
+ MULQ 192(SP)
+ ADDQ AX,SI
+ ADCQ DX,CX
+ MOVQ 96(DI),AX
+ MULQ 160(SP)
+ ADDQ AX,R10
+ ADCQ DX,R11
+ MOVQ 96(DI),AX
+ MULQ 168(SP)
+ ADDQ AX,R12
+ ADCQ DX,R13
+ MOVQ 96(DI),AX
+ MULQ 176(SP)
+ ADDQ AX,R14
+ ADCQ DX,R15
+ MOVQ 96(DI),DX
+ IMUL3Q $19,DX,AX
+ MULQ 184(SP)
+ ADDQ AX,SI
+ ADCQ DX,CX
+ MOVQ 96(DI),DX
+ IMUL3Q $19,DX,AX
+ MULQ 192(SP)
+ ADDQ AX,R8
+ ADCQ DX,R9
+ MOVQ 104(DI),AX
+ MULQ 160(SP)
+ ADDQ AX,R12
+ ADCQ DX,R13
+ MOVQ 104(DI),AX
+ MULQ 168(SP)
+ ADDQ AX,R14
+ ADCQ DX,R15
+ MOVQ 0(SP),AX
+ MULQ 184(SP)
+ ADDQ AX,R8
+ ADCQ DX,R9
+ MOVQ 0(SP),AX
+ MULQ 192(SP)
+ ADDQ AX,R10
+ ADCQ DX,R11
+ MOVQ 112(DI),AX
+ MULQ 160(SP)
+ ADDQ AX,R14
+ ADCQ DX,R15
+ MOVQ 8(SP),AX
+ MULQ 176(SP)
+ ADDQ AX,R8
+ ADCQ DX,R9
+ MOVQ 8(SP),AX
+ MULQ 184(SP)
+ ADDQ AX,R10
+ ADCQ DX,R11
+ MOVQ 8(SP),AX
+ MULQ 192(SP)
+ ADDQ AX,R12
+ ADCQ DX,R13
+ MOVQ ·REDMASK51(SB),DX
+ SHLQ $13,CX:SI
+ ANDQ DX,SI
+ SHLQ $13,R9:R8
+ ANDQ DX,R8
+ ADDQ CX,R8
+ SHLQ $13,R11:R10
+ ANDQ DX,R10
+ ADDQ R9,R10
+ SHLQ $13,R13:R12
+ ANDQ DX,R12
+ ADDQ R11,R12
+ SHLQ $13,R15:R14
+ ANDQ DX,R14
+ ADDQ R13,R14
+ IMUL3Q $19,R15,CX
+ ADDQ CX,SI
+ MOVQ SI,CX
+ SHRQ $51,CX
+ ADDQ R8,CX
+ MOVQ CX,R8
+ SHRQ $51,CX
+ ANDQ DX,SI
+ ADDQ R10,CX
+ MOVQ CX,R9
+ SHRQ $51,CX
+ ANDQ DX,R8
+ ADDQ R12,CX
+ MOVQ CX,AX
+ SHRQ $51,CX
+ ANDQ DX,R9
+ ADDQ R14,CX
+ MOVQ CX,R10
+ SHRQ $51,CX
+ ANDQ DX,AX
+ IMUL3Q $19,CX,CX
+ ADDQ CX,SI
+ ANDQ DX,R10
+ MOVQ SI,80(DI)
+ MOVQ R8,88(DI)
+ MOVQ R9,96(DI)
+ MOVQ AX,104(DI)
+ MOVQ R10,112(DI)
+ RET
diff --git a/src/vendor/golang_org/x/crypto/curve25519/mont25519_amd64.go b/src/vendor/golang_org/x/crypto/curve25519/mont25519_amd64.go
new file mode 100644
index 0000000..5822bd5
--- /dev/null
+++ b/src/vendor/golang_org/x/crypto/curve25519/mont25519_amd64.go
@@ -0,0 +1,240 @@
+// Copyright 2012 The Go Authors. 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,!gccgo,!appengine
+
+package curve25519
+
+// These functions are implemented in the .s files. The names of the functions
+// in the rest of the file are also taken from the SUPERCOP sources to help
+// people following along.
+
+//go:noescape
+
+func cswap(inout *[5]uint64, v uint64)
+
+//go:noescape
+
+func ladderstep(inout *[5][5]uint64)
+
+//go:noescape
+
+func freeze(inout *[5]uint64)
+
+//go:noescape
+
+func mul(dest, a, b *[5]uint64)
+
+//go:noescape
+
+func square(out, in *[5]uint64)
+
+// mladder uses a Montgomery ladder to calculate (xr/zr) *= s.
+func mladder(xr, zr *[5]uint64, s *[32]byte) {
+ var work [5][5]uint64
+
+ work[0] = *xr
+ setint(&work[1], 1)
+ setint(&work[2], 0)
+ work[3] = *xr
+ setint(&work[4], 1)
+
+ j := uint(6)
+ var prevbit byte
+
+ for i := 31; i >= 0; i-- {
+ for j < 8 {
+ bit := ((*s)[i] >> j) & 1
+ swap := bit ^ prevbit
+ prevbit = bit
+ cswap(&work[1], uint64(swap))
+ ladderstep(&work)
+ j--
+ }
+ j = 7
+ }
+
+ *xr = work[1]
+ *zr = work[2]
+}
+
+func scalarMult(out, in, base *[32]byte) {
+ var e [32]byte
+ copy(e[:], (*in)[:])
+ e[0] &= 248
+ e[31] &= 127
+ e[31] |= 64
+
+ var t, z [5]uint64
+ unpack(&t, base)
+ mladder(&t, &z, &e)
+ invert(&z, &z)
+ mul(&t, &t, &z)
+ pack(out, &t)
+}
+
+func setint(r *[5]uint64, v uint64) {
+ r[0] = v
+ r[1] = 0
+ r[2] = 0
+ r[3] = 0
+ r[4] = 0
+}
+
+// unpack sets r = x where r consists of 5, 51-bit limbs in little-endian
+// order.
+func unpack(r *[5]uint64, x *[32]byte) {
+ r[0] = uint64(x[0]) |
+ uint64(x[1])<<8 |
+ uint64(x[2])<<16 |
+ uint64(x[3])<<24 |
+ uint64(x[4])<<32 |
+ uint64(x[5])<<40 |
+ uint64(x[6]&7)<<48
+
+ r[1] = uint64(x[6])>>3 |
+ uint64(x[7])<<5 |
+ uint64(x[8])<<13 |
+ uint64(x[9])<<21 |
+ uint64(x[10])<<29 |
+ uint64(x[11])<<37 |
+ uint64(x[12]&63)<<45
+
+ r[2] = uint64(x[12])>>6 |
+ uint64(x[13])<<2 |
+ uint64(x[14])<<10 |
+ uint64(x[15])<<18 |
+ uint64(x[16])<<26 |
+ uint64(x[17])<<34 |
+ uint64(x[18])<<42 |
+ uint64(x[19]&1)<<50
+
+ r[3] = uint64(x[19])>>1 |
+ uint64(x[20])<<7 |
+ uint64(x[21])<<15 |
+ uint64(x[22])<<23 |
+ uint64(x[23])<<31 |
+ uint64(x[24])<<39 |
+ uint64(x[25]&15)<<47
+
+ r[4] = uint64(x[25])>>4 |
+ uint64(x[26])<<4 |
+ uint64(x[27])<<12 |
+ uint64(x[28])<<20 |
+ uint64(x[29])<<28 |
+ uint64(x[30])<<36 |
+ uint64(x[31]&127)<<44
+}
+
+// pack sets out = x where out is the usual, little-endian form of the 5,
+// 51-bit limbs in x.
+func pack(out *[32]byte, x *[5]uint64) {
+ t := *x
+ freeze(&t)
+
+ out[0] = byte(t[0])
+ out[1] = byte(t[0] >> 8)
+ out[2] = byte(t[0] >> 16)
+ out[3] = byte(t[0] >> 24)
+ out[4] = byte(t[0] >> 32)
+ out[5] = byte(t[0] >> 40)
+ out[6] = byte(t[0] >> 48)
+
+ out[6] ^= byte(t[1]<<3) & 0xf8
+ out[7] = byte(t[1] >> 5)
+ out[8] = byte(t[1] >> 13)
+ out[9] = byte(t[1] >> 21)
+ out[10] = byte(t[1] >> 29)
+ out[11] = byte(t[1] >> 37)
+ out[12] = byte(t[1] >> 45)
+
+ out[12] ^= byte(t[2]<<6) & 0xc0
+ out[13] = byte(t[2] >> 2)
+ out[14] = byte(t[2] >> 10)
+ out[15] = byte(t[2] >> 18)
+ out[16] = byte(t[2] >> 26)
+ out[17] = byte(t[2] >> 34)
+ out[18] = byte(t[2] >> 42)
+ out[19] = byte(t[2] >> 50)
+
+ out[19] ^= byte(t[3]<<1) & 0xfe
+ out[20] = byte(t[3] >> 7)
+ out[21] = byte(t[3] >> 15)
+ out[22] = byte(t[3] >> 23)
+ out[23] = byte(t[3] >> 31)
+ out[24] = byte(t[3] >> 39)
+ out[25] = byte(t[3] >> 47)
+
+ out[25] ^= byte(t[4]<<4) & 0xf0
+ out[26] = byte(t[4] >> 4)
+ out[27] = byte(t[4] >> 12)
+ out[28] = byte(t[4] >> 20)
+ out[29] = byte(t[4] >> 28)
+ out[30] = byte(t[4] >> 36)
+ out[31] = byte(t[4] >> 44)
+}
+
+// invert calculates r = x^-1 mod p using Fermat's little theorem.
+func invert(r *[5]uint64, x *[5]uint64) {
+ var z2, z9, z11, z2_5_0, z2_10_0, z2_20_0, z2_50_0, z2_100_0, t [5]uint64
+
+ square(&z2, x) /* 2 */
+ square(&t, &z2) /* 4 */
+ square(&t, &t) /* 8 */
+ mul(&z9, &t, x) /* 9 */
+ mul(&z11, &z9, &z2) /* 11 */
+ square(&t, &z11) /* 22 */
+ mul(&z2_5_0, &t, &z9) /* 2^5 - 2^0 = 31 */
+
+ square(&t, &z2_5_0) /* 2^6 - 2^1 */
+ for i := 1; i < 5; i++ { /* 2^20 - 2^10 */
+ square(&t, &t)
+ }
+ mul(&z2_10_0, &t, &z2_5_0) /* 2^10 - 2^0 */
+
+ square(&t, &z2_10_0) /* 2^11 - 2^1 */
+ for i := 1; i < 10; i++ { /* 2^20 - 2^10 */
+ square(&t, &t)
+ }
+ mul(&z2_20_0, &t, &z2_10_0) /* 2^20 - 2^0 */
+
+ square(&t, &z2_20_0) /* 2^21 - 2^1 */
+ for i := 1; i < 20; i++ { /* 2^40 - 2^20 */
+ square(&t, &t)
+ }
+ mul(&t, &t, &z2_20_0) /* 2^40 - 2^0 */
+
+ square(&t, &t) /* 2^41 - 2^1 */
+ for i := 1; i < 10; i++ { /* 2^50 - 2^10 */
+ square(&t, &t)
+ }
+ mul(&z2_50_0, &t, &z2_10_0) /* 2^50 - 2^0 */
+
+ square(&t, &z2_50_0) /* 2^51 - 2^1 */
+ for i := 1; i < 50; i++ { /* 2^100 - 2^50 */
+ square(&t, &t)
+ }
+ mul(&z2_100_0, &t, &z2_50_0) /* 2^100 - 2^0 */
+
+ square(&t, &z2_100_0) /* 2^101 - 2^1 */
+ for i := 1; i < 100; i++ { /* 2^200 - 2^100 */
+ square(&t, &t)
+ }
+ mul(&t, &t, &z2_100_0) /* 2^200 - 2^0 */
+
+ square(&t, &t) /* 2^201 - 2^1 */
+ for i := 1; i < 50; i++ { /* 2^250 - 2^50 */
+ square(&t, &t)
+ }
+ mul(&t, &t, &z2_50_0) /* 2^250 - 2^0 */
+
+ square(&t, &t) /* 2^251 - 2^1 */
+ square(&t, &t) /* 2^252 - 2^2 */
+ square(&t, &t) /* 2^253 - 2^3 */
+
+ square(&t, &t) /* 2^254 - 2^4 */
+
+ square(&t, &t) /* 2^255 - 2^5 */
+ mul(r, &t, &z11) /* 2^255 - 21 */
+}
diff --git a/src/vendor/golang_org/x/crypto/curve25519/mul_amd64.s b/src/vendor/golang_org/x/crypto/curve25519/mul_amd64.s
new file mode 100644
index 0000000..33ce57d
--- /dev/null
+++ b/src/vendor/golang_org/x/crypto/curve25519/mul_amd64.s
@@ -0,0 +1,167 @@
+// Copyright 2012 The Go 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 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 mul(dest, a, b *[5]uint64)
+TEXT ·mul(SB),0,$16-24
+ MOVQ dest+0(FP), DI
+ MOVQ a+8(FP), SI
+ MOVQ b+16(FP), DX
+
+ MOVQ DX,CX
+ MOVQ 24(SI),DX
+ IMUL3Q $19,DX,AX
+ MOVQ AX,0(SP)
+ MULQ 16(CX)
+ MOVQ AX,R8
+ MOVQ DX,R9
+ MOVQ 32(SI),DX
+ IMUL3Q $19,DX,AX
+ MOVQ AX,8(SP)
+ MULQ 8(CX)
+ ADDQ AX,R8
+ ADCQ DX,R9
+ MOVQ 0(SI),AX
+ MULQ 0(CX)
+ ADDQ AX,R8
+ ADCQ DX,R9
+ MOVQ 0(SI),AX
+ MULQ 8(CX)
+ MOVQ AX,R10
+ MOVQ DX,R11
+ MOVQ 0(SI),AX
+ MULQ 16(CX)
+ MOVQ AX,R12
+ MOVQ DX,R13
+ MOVQ 0(SI),AX
+ MULQ 24(CX)
+ MOVQ AX,R14
+ MOVQ DX,R15
+ MOVQ 0(SI),AX
+ MULQ 32(CX)
+ MOVQ AX,BX
+ MOVQ DX,BP
+ MOVQ 8(SI),AX
+ MULQ 0(CX)
+ ADDQ AX,R10
+ ADCQ DX,R11
+ MOVQ 8(SI),AX
+ MULQ 8(CX)
+ ADDQ AX,R12
+ ADCQ DX,R13
+ MOVQ 8(SI),AX
+ MULQ 16(CX)
+ ADDQ AX,R14
+ ADCQ DX,R15
+ MOVQ 8(SI),AX
+ MULQ 24(CX)
+ ADDQ AX,BX
+ ADCQ DX,BP
+ MOVQ 8(SI),DX
+ IMUL3Q $19,DX,AX
+ MULQ 32(CX)
+ ADDQ AX,R8
+ ADCQ DX,R9
+ MOVQ 16(SI),AX
+ MULQ 0(CX)
+ ADDQ AX,R12
+ ADCQ DX,R13
+ MOVQ 16(SI),AX
+ MULQ 8(CX)
+ ADDQ AX,R14
+ ADCQ DX,R15
+ MOVQ 16(SI),AX
+ MULQ 16(CX)
+ ADDQ AX,BX
+ ADCQ DX,BP
+ MOVQ 16(SI),DX
+ IMUL3Q $19,DX,AX
+ MULQ 24(CX)
+ ADDQ AX,R8
+ ADCQ DX,R9
+ MOVQ 16(SI),DX
+ IMUL3Q $19,DX,AX
+ MULQ 32(CX)
+ ADDQ AX,R10
+ ADCQ DX,R11
+ MOVQ 24(SI),AX
+ MULQ 0(CX)
+ ADDQ AX,R14
+ ADCQ DX,R15
+ MOVQ 24(SI),AX
+ MULQ 8(CX)
+ ADDQ AX,BX
+ ADCQ DX,BP
+ MOVQ 0(SP),AX
+ MULQ 24(CX)
+ ADDQ AX,R10
+ ADCQ DX,R11
+ MOVQ 0(SP),AX
+ MULQ 32(CX)
+ ADDQ AX,R12
+ ADCQ DX,R13
+ MOVQ 32(SI),AX
+ MULQ 0(CX)
+ ADDQ AX,BX
+ ADCQ DX,BP
+ MOVQ 8(SP),AX
+ MULQ 16(CX)
+ ADDQ AX,R10
+ ADCQ DX,R11
+ MOVQ 8(SP),AX
+ MULQ 24(CX)
+ ADDQ AX,R12
+ ADCQ DX,R13
+ MOVQ 8(SP),AX
+ MULQ 32(CX)
+ ADDQ AX,R14
+ ADCQ DX,R15
+ MOVQ ·REDMASK51(SB),SI
+ SHLQ $13,R9:R8
+ ANDQ SI,R8
+ SHLQ $13,R11:R10
+ ANDQ SI,R10
+ ADDQ R9,R10
+ SHLQ $13,R13:R12
+ ANDQ SI,R12
+ ADDQ R11,R12
+ SHLQ $13,R15:R14
+ ANDQ SI,R14
+ ADDQ R13,R14
+ SHLQ $13,BP:BX
+ ANDQ SI,BX
+ ADDQ R15,BX
+ IMUL3Q $19,BP,DX
+ ADDQ DX,R8
+ MOVQ R8,DX
+ SHRQ $51,DX
+ ADDQ R10,DX
+ MOVQ DX,CX
+ SHRQ $51,DX
+ ANDQ SI,R8
+ ADDQ R12,DX
+ MOVQ DX,R9
+ SHRQ $51,DX
+ ANDQ SI,CX
+ ADDQ R14,DX
+ MOVQ DX,AX
+ SHRQ $51,DX
+ ANDQ SI,R9
+ ADDQ BX,DX
+ MOVQ DX,R10
+ SHRQ $51,DX
+ ANDQ SI,AX
+ IMUL3Q $19,DX,DX
+ ADDQ DX,R8
+ ANDQ SI,R10
+ MOVQ R8,0(DI)
+ MOVQ CX,8(DI)
+ MOVQ R9,16(DI)
+ MOVQ AX,24(DI)
+ MOVQ R10,32(DI)
+ RET
diff --git a/src/vendor/golang_org/x/crypto/curve25519/square_amd64.s b/src/vendor/golang_org/x/crypto/curve25519/square_amd64.s
new file mode 100644
index 0000000..3a92804
--- /dev/null
+++ b/src/vendor/golang_org/x/crypto/curve25519/square_amd64.s
@@ -0,0 +1,130 @@
+// Copyright 2012 The Go 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 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 square(out, in *[5]uint64)
+TEXT ·square(SB),7,$0-16
+ MOVQ out+0(FP), DI
+ MOVQ in+8(FP), SI
+
+ MOVQ 0(SI),AX
+ MULQ 0(SI)
+ MOVQ AX,CX
+ MOVQ DX,R8
+ MOVQ 0(SI),AX
+ SHLQ $1,AX
+ MULQ 8(SI)
+ MOVQ AX,R9
+ MOVQ DX,R10
+ MOVQ 0(SI),AX
+ SHLQ $1,AX
+ MULQ 16(SI)
+ MOVQ AX,R11
+ MOVQ DX,R12
+ MOVQ 0(SI),AX
+ SHLQ $1,AX
+ MULQ 24(SI)
+ MOVQ AX,R13
+ MOVQ DX,R14
+ MOVQ 0(SI),AX
+ SHLQ $1,AX
+ MULQ 32(SI)
+ MOVQ AX,R15
+ MOVQ DX,BX
+ MOVQ 8(SI),AX
+ MULQ 8(SI)
+ ADDQ AX,R11
+ ADCQ DX,R12
+ MOVQ 8(SI),AX
+ SHLQ $1,AX
+ MULQ 16(SI)
+ ADDQ AX,R13
+ ADCQ DX,R14
+ MOVQ 8(SI),AX
+ SHLQ $1,AX
+ MULQ 24(SI)
+ ADDQ AX,R15
+ ADCQ DX,BX
+ MOVQ 8(SI),DX
+ IMUL3Q $38,DX,AX
+ MULQ 32(SI)
+ ADDQ AX,CX
+ ADCQ DX,R8
+ MOVQ 16(SI),AX
+ MULQ 16(SI)
+ ADDQ AX,R15
+ ADCQ DX,BX
+ MOVQ 16(SI),DX
+ IMUL3Q $38,DX,AX
+ MULQ 24(SI)
+ ADDQ AX,CX
+ ADCQ DX,R8
+ MOVQ 16(SI),DX
+ IMUL3Q $38,DX,AX
+ MULQ 32(SI)
+ ADDQ AX,R9
+ ADCQ DX,R10
+ MOVQ 24(SI),DX
+ IMUL3Q $19,DX,AX
+ MULQ 24(SI)
+ ADDQ AX,R9
+ ADCQ DX,R10
+ MOVQ 24(SI),DX
+ IMUL3Q $38,DX,AX
+ MULQ 32(SI)
+ ADDQ AX,R11
+ ADCQ DX,R12
+ MOVQ 32(SI),DX
+ IMUL3Q $19,DX,AX
+ MULQ 32(SI)
+ ADDQ AX,R13
+ ADCQ DX,R14
+ MOVQ ·REDMASK51(SB),SI
+ SHLQ $13,R8:CX
+ ANDQ SI,CX
+ SHLQ $13,R10:R9
+ ANDQ SI,R9
+ ADDQ R8,R9
+ SHLQ $13,R12:R11
+ ANDQ SI,R11
+ ADDQ R10,R11
+ SHLQ $13,R14:R13
+ ANDQ SI,R13
+ ADDQ R12,R13
+ SHLQ $13,BX:R15
+ ANDQ SI,R15
+ ADDQ R14,R15
+ IMUL3Q $19,BX,DX
+ ADDQ DX,CX
+ MOVQ CX,DX
+ SHRQ $51,DX
+ ADDQ R9,DX
+ ANDQ SI,CX
+ MOVQ DX,R8
+ SHRQ $51,DX
+ ADDQ R11,DX
+ ANDQ SI,R8
+ MOVQ DX,R9
+ SHRQ $51,DX
+ ADDQ R13,DX
+ ANDQ SI,R9
+ MOVQ DX,AX
+ SHRQ $51,DX
+ ADDQ R15,DX
+ ANDQ SI,AX
+ MOVQ DX,R10
+ SHRQ $51,DX
+ IMUL3Q $19,DX,DX
+ ADDQ DX,CX
+ ANDQ SI,R10
+ MOVQ CX,0(DI)
+ MOVQ R8,8(DI)
+ MOVQ R9,16(DI)
+ MOVQ AX,24(DI)
+ MOVQ R10,32(DI)
+ RET
diff --git a/src/vendor/golang_org/x/crypto/poly1305/poly1305.go b/src/vendor/golang_org/x/crypto/poly1305/poly1305.go
new file mode 100644
index 0000000..4a5f826
--- /dev/null
+++ b/src/vendor/golang_org/x/crypto/poly1305/poly1305.go
@@ -0,0 +1,32 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+Package poly1305 implements Poly1305 one-time message authentication code as specified in http://cr.yp.to/mac/poly1305-20050329.pdf.
+
+Poly1305 is a fast, one-time authentication function. It is infeasible for an
+attacker to generate an authenticator for a message without the key. However, a
+key must only be used for a single message. Authenticating two different
+messages with the same key allows an attacker to forge authenticators for other
+messages with the same key.
+
+Poly1305 was originally coupled with AES in order to make Poly1305-AES. AES was
+used with a fixed key in order to generate one-time keys from an nonce.
+However, in this package AES isn't used and the one-time key is specified
+directly.
+*/
+package poly1305 // import "golang.org/x/crypto/poly1305"
+
+import "crypto/subtle"
+
+// TagSize is the size, in bytes, of a poly1305 authenticator.
+const TagSize = 16
+
+// Verify returns true if mac is a valid authenticator for m with the given
+// key.
+func Verify(mac *[16]byte, m []byte, key *[32]byte) bool {
+ var tmp [16]byte
+ Sum(&tmp, m, key)
+ return subtle.ConstantTimeCompare(tmp[:], mac[:]) == 1
+}
diff --git a/src/vendor/golang_org/x/crypto/poly1305/poly1305_test.go b/src/vendor/golang_org/x/crypto/poly1305/poly1305_test.go
new file mode 100644
index 0000000..91b8e2b
--- /dev/null
+++ b/src/vendor/golang_org/x/crypto/poly1305/poly1305_test.go
@@ -0,0 +1,92 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package poly1305
+
+import (
+ "bytes"
+ "testing"
+ "unsafe"
+)
+
+var testData = []struct {
+ in, k, correct []byte
+}{
+ {
+ []byte("Hello world!"),
+ []byte("this is 32-byte key for Poly1305"),
+ []byte{0xa6, 0xf7, 0x45, 0x00, 0x8f, 0x81, 0xc9, 0x16, 0xa2, 0x0d, 0xcc, 0x74, 0xee, 0xf2, 0xb2, 0xf0},
+ },
+ {
+ make([]byte, 32),
+ []byte("this is 32-byte key for Poly1305"),
+ []byte{0x49, 0xec, 0x78, 0x09, 0x0e, 0x48, 0x1e, 0xc6, 0xc2, 0x6b, 0x33, 0xb9, 0x1c, 0xcc, 0x03, 0x07},
+ },
+ {
+ make([]byte, 2007),
+ []byte("this is 32-byte key for Poly1305"),
+ []byte{0xda, 0x84, 0xbc, 0xab, 0x02, 0x67, 0x6c, 0x38, 0xcd, 0xb0, 0x15, 0x60, 0x42, 0x74, 0xc2, 0xaa},
+ },
+ {
+ make([]byte, 2007),
+ make([]byte, 32),
+ make([]byte, 16),
+ },
+ {
+ // This test triggers an edge-case. See https://go-review.googlesource.com/#/c/30101/.
+ []byte{0x81, 0xd8, 0xb2, 0xe4, 0x6a, 0x25, 0x21, 0x3b, 0x58, 0xfe, 0xe4, 0x21, 0x3a, 0x2a, 0x28, 0xe9, 0x21, 0xc1, 0x2a, 0x96, 0x32, 0x51, 0x6d, 0x3b, 0x73, 0x27, 0x27, 0x27, 0xbe, 0xcf, 0x21, 0x29},
+ []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},
+ },
+}
+
+func testSum(t *testing.T, unaligned bool) {
+ var out [16]byte
+ var key [32]byte
+
+ for i, v := range testData {
+ in := v.in
+ if unaligned {
+ in = unalignBytes(in)
+ }
+ copy(key[:], v.k)
+ Sum(&out, in, &key)
+ if !bytes.Equal(out[:], v.correct) {
+ t.Errorf("%d: expected %x, got %x", i, v.correct, out[:])
+ }
+ }
+}
+
+func TestSum(t *testing.T) { testSum(t, false) }
+func TestSumUnaligned(t *testing.T) { testSum(t, true) }
+
+func benchmark(b *testing.B, size int, unaligned bool) {
+ var out [16]byte
+ var key [32]byte
+ in := make([]byte, size)
+ if unaligned {
+ in = unalignBytes(in)
+ }
+ b.SetBytes(int64(len(in)))
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ Sum(&out, in, &key)
+ }
+}
+
+func Benchmark64(b *testing.B) { benchmark(b, 64, false) }
+func Benchmark1K(b *testing.B) { benchmark(b, 1024, false) }
+func Benchmark64Unaligned(b *testing.B) { benchmark(b, 64, true) }
+func Benchmark1KUnaligned(b *testing.B) { benchmark(b, 1024, true) }
+
+func unalignBytes(in []byte) []byte {
+ out := make([]byte, len(in)+1)
+ if uintptr(unsafe.Pointer(&out[0]))&(unsafe.Alignof(uint32(0))-1) == 0 {
+ out = out[1:]
+ } else {
+ out = out[:len(in)]
+ }
+ copy(out, in)
+ return out
+}
diff --git a/src/vendor/golang_org/x/crypto/poly1305/sum_amd64.go b/src/vendor/golang_org/x/crypto/poly1305/sum_amd64.go
new file mode 100644
index 0000000..4dd72fe
--- /dev/null
+++ b/src/vendor/golang_org/x/crypto/poly1305/sum_amd64.go
@@ -0,0 +1,22 @@
+// Copyright 2012 The Go Authors. 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,!gccgo,!appengine
+
+package poly1305
+
+// This function is implemented in sum_amd64.s
+//go:noescape
+func poly1305(out *[16]byte, m *byte, mlen uint64, key *[32]byte)
+
+// Sum generates an authenticator for m 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) {
+ var mPtr *byte
+ if len(m) > 0 {
+ mPtr = &m[0]
+ }
+ poly1305(out, mPtr, uint64(len(m)), key)
+}
diff --git a/src/vendor/golang_org/x/crypto/poly1305/sum_amd64.s b/src/vendor/golang_org/x/crypto/poly1305/sum_amd64.s
new file mode 100644
index 0000000..bc75c61
--- /dev/null
+++ b/src/vendor/golang_org/x/crypto/poly1305/sum_amd64.s
@@ -0,0 +1,125 @@
+// Copyright 2012 The Go Authors. 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,!gccgo,!appengine
+
+#include "textflag.h"
+
+#define POLY1305_ADD(msg, h0, h1, h2) \
+ ADDQ 0(msg), h0; \
+ ADCQ 8(msg), h1; \
+ ADCQ $1, h2; \
+ LEAQ 16(msg), msg
+
+#define POLY1305_MUL(h0, h1, h2, r0, r1, t0, t1, t2, t3) \
+ MOVQ r0, AX; \
+ MULQ h0; \
+ MOVQ AX, t0; \
+ MOVQ DX, t1; \
+ MOVQ r0, AX; \
+ MULQ h1; \
+ ADDQ AX, t1; \
+ ADCQ $0, DX; \
+ MOVQ r0, t2; \
+ IMULQ h2, t2; \
+ ADDQ DX, t2; \
+ \
+ MOVQ r1, AX; \
+ MULQ h0; \
+ ADDQ AX, t1; \
+ ADCQ $0, DX; \
+ MOVQ DX, h0; \
+ MOVQ r1, t3; \
+ IMULQ h2, t3; \
+ MOVQ r1, AX; \
+ MULQ h1; \
+ ADDQ AX, t2; \
+ ADCQ DX, t3; \
+ ADDQ h0, t2; \
+ ADCQ $0, t3; \
+ \
+ MOVQ t0, h0; \
+ MOVQ t1, h1; \
+ MOVQ t2, h2; \
+ ANDQ $3, h2; \
+ MOVQ t2, t0; \
+ ANDQ $0xFFFFFFFFFFFFFFFC, t0; \
+ ADDQ t0, h0; \
+ ADCQ t3, h1; \
+ ADCQ $0, h2; \
+ SHRQ $2, t3, t2; \
+ SHRQ $2, t3; \
+ ADDQ t2, h0; \
+ ADCQ t3, h1; \
+ ADCQ $0, h2
+
+DATA poly1305Mask<>+0x00(SB)/8, $0x0FFFFFFC0FFFFFFF
+DATA poly1305Mask<>+0x08(SB)/8, $0x0FFFFFFC0FFFFFFC
+GLOBL poly1305Mask<>(SB), RODATA, $16
+
+// func poly1305(out *[16]byte, m *byte, mlen uint64, key *[32]key)
+TEXT ·poly1305(SB), $0-32
+ MOVQ out+0(FP), DI
+ MOVQ m+8(FP), SI
+ MOVQ mlen+16(FP), R15
+ MOVQ key+24(FP), AX
+
+ MOVQ 0(AX), R11
+ MOVQ 8(AX), R12
+ ANDQ poly1305Mask<>(SB), R11 // r0
+ ANDQ poly1305Mask<>+8(SB), R12 // r1
+ XORQ R8, R8 // h0
+ XORQ R9, R9 // h1
+ XORQ R10, R10 // h2
+
+ CMPQ R15, $16
+ JB bytes_between_0_and_15
+
+loop:
+ POLY1305_ADD(SI, R8, R9, R10)
+
+multiply:
+ POLY1305_MUL(R8, R9, R10, R11, R12, BX, CX, R13, R14)
+ SUBQ $16, R15
+ CMPQ R15, $16
+ JAE loop
+
+bytes_between_0_and_15:
+ TESTQ R15, R15
+ JZ done
+ MOVQ $1, BX
+ XORQ CX, CX
+ XORQ R13, R13
+ ADDQ R15, SI
+
+flush_buffer:
+ SHLQ $8, BX, CX
+ SHLQ $8, BX
+ MOVB -1(SI), R13
+ XORQ R13, BX
+ DECQ SI
+ DECQ R15
+ JNZ flush_buffer
+
+ ADDQ BX, R8
+ ADCQ CX, R9
+ ADCQ $0, R10
+ MOVQ $16, R15
+ JMP multiply
+
+done:
+ MOVQ R8, AX
+ MOVQ R9, BX
+ SUBQ $0xFFFFFFFFFFFFFFFB, AX
+ SBBQ $0xFFFFFFFFFFFFFFFF, BX
+ SBBQ $3, R10
+ CMOVQCS R8, AX
+ CMOVQCS R9, BX
+ MOVQ key+24(FP), R8
+ ADDQ 16(R8), AX
+ ADCQ 24(R8), BX
+
+ MOVQ AX, 0(DI)
+ MOVQ BX, 8(DI)
+ RET
diff --git a/src/vendor/golang_org/x/crypto/poly1305/sum_arm.go b/src/vendor/golang_org/x/crypto/poly1305/sum_arm.go
new file mode 100644
index 0000000..5dc321c
--- /dev/null
+++ b/src/vendor/golang_org/x/crypto/poly1305/sum_arm.go
@@ -0,0 +1,22 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build arm,!gccgo,!appengine,!nacl
+
+package poly1305
+
+// This function is implemented in sum_arm.s
+//go:noescape
+func poly1305_auth_armv6(out *[16]byte, m *byte, mlen uint32, key *[32]byte)
+
+// Sum generates an authenticator for m 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) {
+ var mPtr *byte
+ if len(m) > 0 {
+ mPtr = &m[0]
+ }
+ poly1305_auth_armv6(out, mPtr, uint32(len(m)), key)
+}
diff --git a/src/vendor/golang_org/x/crypto/poly1305/sum_arm.s b/src/vendor/golang_org/x/crypto/poly1305/sum_arm.s
new file mode 100644
index 0000000..93167b2
--- /dev/null
+++ b/src/vendor/golang_org/x/crypto/poly1305/sum_arm.s
@@ -0,0 +1,427 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build arm,!gccgo,!appengine,!nacl
+
+#include "textflag.h"
+
+// This code was translated into a form compatible with 5a from the public
+// domain source by Andrew Moon: github.com/floodyberry/poly1305-opt/blob/master/app/extensions/poly1305.
+
+DATA poly1305_init_constants_armv6<>+0x00(SB)/4, $0x3ffffff
+DATA poly1305_init_constants_armv6<>+0x04(SB)/4, $0x3ffff03
+DATA poly1305_init_constants_armv6<>+0x08(SB)/4, $0x3ffc0ff
+DATA poly1305_init_constants_armv6<>+0x0c(SB)/4, $0x3f03fff
+DATA poly1305_init_constants_armv6<>+0x10(SB)/4, $0x00fffff
+GLOBL poly1305_init_constants_armv6<>(SB), 8, $20
+
+// Warning: the linker may use R11 to synthesize certain instructions. Please
+// take care and verify that no synthetic instructions use it.
+
+TEXT poly1305_init_ext_armv6<>(SB), NOSPLIT, $0
+ // Needs 16 bytes of stack and 64 bytes of space pointed to by R0. (It
+ // might look like it's only 60 bytes of space but the final four bytes
+ // will be written by another function.) We need to skip over four
+ // bytes of stack because that's saving the value of 'g'.
+ ADD $4, R13, R8
+ MOVM.IB [R4-R7], (R8)
+ MOVM.IA.W (R1), [R2-R5]
+ MOVW $poly1305_init_constants_armv6<>(SB), R7
+ MOVW R2, R8
+ MOVW R2>>26, R9
+ MOVW R3>>20, g
+ MOVW R4>>14, R11
+ MOVW R5>>8, R12
+ ORR R3<<6, R9, R9
+ ORR R4<<12, g, g
+ ORR R5<<18, R11, R11
+ MOVM.IA (R7), [R2-R6]
+ AND R8, R2, R2
+ AND R9, R3, R3
+ AND g, R4, R4
+ AND R11, R5, R5
+ AND R12, R6, R6
+ MOVM.IA.W [R2-R6], (R0)
+ EOR R2, R2, R2
+ EOR R3, R3, R3
+ EOR R4, R4, R4
+ EOR R5, R5, R5
+ EOR R6, R6, R6
+ MOVM.IA.W [R2-R6], (R0)
+ MOVM.IA.W (R1), [R2-R5]
+ MOVM.IA [R2-R6], (R0)
+ ADD $20, R13, R0
+ MOVM.DA (R0), [R4-R7]
+ RET
+
+#define MOVW_UNALIGNED(Rsrc, Rdst, Rtmp, offset) \
+ MOVBU (offset+0)(Rsrc), Rtmp; \
+ MOVBU Rtmp, (offset+0)(Rdst); \
+ MOVBU (offset+1)(Rsrc), Rtmp; \
+ MOVBU Rtmp, (offset+1)(Rdst); \
+ MOVBU (offset+2)(Rsrc), Rtmp; \
+ MOVBU Rtmp, (offset+2)(Rdst); \
+ MOVBU (offset+3)(Rsrc), Rtmp; \
+ MOVBU Rtmp, (offset+3)(Rdst)
+
+TEXT poly1305_blocks_armv6<>(SB), NOSPLIT, $0
+ // Needs 24 bytes of stack for saved registers and then 88 bytes of
+ // scratch space after that. We assume that 24 bytes at (R13) have
+ // already been used: four bytes for the link register saved in the
+ // prelude of poly1305_auth_armv6, four bytes for saving the value of g
+ // in that function and 16 bytes of scratch space used around
+ // poly1305_finish_ext_armv6_skip1.
+ ADD $24, R13, R12
+ MOVM.IB [R4-R8, R14], (R12)
+ MOVW R0, 88(R13)
+ MOVW R1, 92(R13)
+ MOVW R2, 96(R13)
+ MOVW R1, R14
+ MOVW R2, R12
+ MOVW 56(R0), R8
+ WORD $0xe1180008 // TST R8, R8 not working see issue 5921
+ EOR R6, R6, R6
+ MOVW.EQ $(1<<24), R6
+ MOVW R6, 84(R13)
+ ADD $116, R13, g
+ MOVM.IA (R0), [R0-R9]
+ MOVM.IA [R0-R4], (g)
+ CMP $16, R12
+ BLO poly1305_blocks_armv6_done
+
+poly1305_blocks_armv6_mainloop:
+ WORD $0xe31e0003 // TST R14, #3 not working see issue 5921
+ BEQ poly1305_blocks_armv6_mainloop_aligned
+ ADD $100, R13, g
+ MOVW_UNALIGNED(R14, g, R0, 0)
+ MOVW_UNALIGNED(R14, g, R0, 4)
+ MOVW_UNALIGNED(R14, g, R0, 8)
+ MOVW_UNALIGNED(R14, g, R0, 12)
+ MOVM.IA (g), [R0-R3]
+ ADD $16, R14
+ B poly1305_blocks_armv6_mainloop_loaded
+
+poly1305_blocks_armv6_mainloop_aligned:
+ MOVM.IA.W (R14), [R0-R3]
+
+poly1305_blocks_armv6_mainloop_loaded:
+ MOVW R0>>26, g
+ MOVW R1>>20, R11
+ MOVW R2>>14, R12
+ MOVW R14, 92(R13)
+ MOVW R3>>8, R4
+ ORR R1<<6, g, g
+ ORR R2<<12, R11, R11
+ ORR R3<<18, R12, R12
+ BIC $0xfc000000, R0, R0
+ BIC $0xfc000000, g, g
+ MOVW 84(R13), R3
+ BIC $0xfc000000, R11, R11
+ BIC $0xfc000000, R12, R12
+ ADD R0, R5, R5
+ ADD g, R6, R6
+ ORR R3, R4, R4
+ ADD R11, R7, R7
+ ADD $116, R13, R14
+ ADD R12, R8, R8
+ ADD R4, R9, R9
+ MOVM.IA (R14), [R0-R4]
+ MULLU R4, R5, (R11, g)
+ MULLU R3, R5, (R14, R12)
+ MULALU R3, R6, (R11, g)
+ MULALU R2, R6, (R14, R12)
+ MULALU R2, R7, (R11, g)
+ MULALU R1, R7, (R14, R12)
+ ADD R4<<2, R4, R4
+ ADD R3<<2, R3, R3
+ MULALU R1, R8, (R11, g)
+ MULALU R0, R8, (R14, R12)
+ MULALU R0, R9, (R11, g)
+ MULALU R4, R9, (R14, R12)
+ MOVW g, 76(R13)
+ MOVW R11, 80(R13)
+ MOVW R12, 68(R13)
+ MOVW R14, 72(R13)
+ MULLU R2, R5, (R11, g)
+ MULLU R1, R5, (R14, R12)
+ MULALU R1, R6, (R11, g)
+ MULALU R0, R6, (R14, R12)
+ MULALU R0, R7, (R11, g)
+ MULALU R4, R7, (R14, R12)
+ ADD R2<<2, R2, R2
+ ADD R1<<2, R1, R1
+ MULALU R4, R8, (R11, g)
+ MULALU R3, R8, (R14, R12)
+ MULALU R3, R9, (R11, g)
+ MULALU R2, R9, (R14, R12)
+ MOVW g, 60(R13)
+ MOVW R11, 64(R13)
+ MOVW R12, 52(R13)
+ MOVW R14, 56(R13)
+ MULLU R0, R5, (R11, g)
+ MULALU R4, R6, (R11, g)
+ MULALU R3, R7, (R11, g)
+ MULALU R2, R8, (R11, g)
+ MULALU R1, R9, (R11, g)
+ ADD $52, R13, R0
+ MOVM.IA (R0), [R0-R7]
+ MOVW g>>26, R12
+ MOVW R4>>26, R14
+ ORR R11<<6, R12, R12
+ ORR R5<<6, R14, R14
+ BIC $0xfc000000, g, g
+ BIC $0xfc000000, R4, R4
+ ADD.S R12, R0, R0
+ ADC $0, R1, R1
+ ADD.S R14, R6, R6
+ ADC $0, R7, R7
+ MOVW R0>>26, R12
+ MOVW R6>>26, R14
+ ORR R1<<6, R12, R12
+ ORR R7<<6, R14, R14
+ BIC $0xfc000000, R0, R0
+ BIC $0xfc000000, R6, R6
+ ADD R14<<2, R14, R14
+ ADD.S R12, R2, R2
+ ADC $0, R3, R3
+ ADD R14, g, g
+ MOVW R2>>26, R12
+ MOVW g>>26, R14
+ ORR R3<<6, R12, R12
+ BIC $0xfc000000, g, R5
+ BIC $0xfc000000, R2, R7
+ ADD R12, R4, R4
+ ADD R14, R0, R0
+ MOVW R4>>26, R12
+ BIC $0xfc000000, R4, R8
+ ADD R12, R6, R9
+ MOVW 96(R13), R12
+ MOVW 92(R13), R14
+ MOVW R0, R6
+ CMP $32, R12
+ SUB $16, R12, R12
+ MOVW R12, 96(R13)
+ BHS poly1305_blocks_armv6_mainloop
+
+poly1305_blocks_armv6_done:
+ MOVW 88(R13), R12
+ MOVW R5, 20(R12)
+ MOVW R6, 24(R12)
+ MOVW R7, 28(R12)
+ MOVW R8, 32(R12)
+ MOVW R9, 36(R12)
+ ADD $48, R13, R0
+ MOVM.DA (R0), [R4-R8, R14]
+ RET
+
+#define MOVHUP_UNALIGNED(Rsrc, Rdst, Rtmp) \
+ MOVBU.P 1(Rsrc), Rtmp; \
+ MOVBU.P Rtmp, 1(Rdst); \
+ MOVBU.P 1(Rsrc), Rtmp; \
+ MOVBU.P Rtmp, 1(Rdst)
+
+#define MOVWP_UNALIGNED(Rsrc, Rdst, Rtmp) \
+ MOVHUP_UNALIGNED(Rsrc, Rdst, Rtmp); \
+ MOVHUP_UNALIGNED(Rsrc, Rdst, Rtmp)
+
+// func poly1305_auth_armv6(out *[16]byte, m *byte, mlen uint32, key *[32]key)
+TEXT ·poly1305_auth_armv6(SB), $196-16
+ // The value 196, just above, is the sum of 64 (the size of the context
+ // structure) and 132 (the amount of stack needed).
+ //
+ // At this point, the stack pointer (R13) has been moved down. It
+ // points to the saved link register and there's 196 bytes of free
+ // space above it.
+ //
+ // The stack for this function looks like:
+ //
+ // +---------------------
+ // |
+ // | 64 bytes of context structure
+ // |
+ // +---------------------
+ // |
+ // | 112 bytes for poly1305_blocks_armv6
+ // |
+ // +---------------------
+ // | 16 bytes of final block, constructed at
+ // | poly1305_finish_ext_armv6_skip8
+ // +---------------------
+ // | four bytes of saved 'g'
+ // +---------------------
+ // | lr, saved by prelude <- R13 points here
+ // +---------------------
+ MOVW g, 4(R13)
+
+ MOVW out+0(FP), R4
+ MOVW m+4(FP), R5
+ MOVW mlen+8(FP), R6
+ MOVW key+12(FP), R7
+
+ ADD $136, R13, R0 // 136 = 4 + 4 + 16 + 112
+ MOVW R7, R1
+
+ // poly1305_init_ext_armv6 will write to the stack from R13+4, but
+ // that's ok because none of the other values have been written yet.
+ BL poly1305_init_ext_armv6<>(SB)
+ BIC.S $15, R6, R2
+ BEQ poly1305_auth_armv6_noblocks
+ ADD $136, R13, R0
+ MOVW R5, R1
+ ADD R2, R5, R5
+ SUB R2, R6, R6
+ BL poly1305_blocks_armv6<>(SB)
+
+poly1305_auth_armv6_noblocks:
+ ADD $136, R13, R0
+ MOVW R5, R1
+ MOVW R6, R2
+ MOVW R4, R3
+
+ MOVW R0, R5
+ MOVW R1, R6
+ MOVW R2, R7
+ MOVW R3, R8
+ AND.S R2, R2, R2
+ BEQ poly1305_finish_ext_armv6_noremaining
+ EOR R0, R0
+ ADD $8, R13, R9 // 8 = offset to 16 byte scratch space
+ MOVW R0, (R9)
+ MOVW R0, 4(R9)
+ MOVW R0, 8(R9)
+ MOVW R0, 12(R9)
+ WORD $0xe3110003 // TST R1, #3 not working see issue 5921
+ BEQ poly1305_finish_ext_armv6_aligned
+ WORD $0xe3120008 // TST R2, #8 not working see issue 5921
+ BEQ poly1305_finish_ext_armv6_skip8
+ MOVWP_UNALIGNED(R1, R9, g)
+ MOVWP_UNALIGNED(R1, R9, g)
+
+poly1305_finish_ext_armv6_skip8:
+ WORD $0xe3120004 // TST $4, R2 not working see issue 5921
+ BEQ poly1305_finish_ext_armv6_skip4
+ MOVWP_UNALIGNED(R1, R9, g)
+
+poly1305_finish_ext_armv6_skip4:
+ WORD $0xe3120002 // TST $2, R2 not working see issue 5921
+ BEQ poly1305_finish_ext_armv6_skip2
+ MOVHUP_UNALIGNED(R1, R9, g)
+ B poly1305_finish_ext_armv6_skip2
+
+poly1305_finish_ext_armv6_aligned:
+ WORD $0xe3120008 // TST R2, #8 not working see issue 5921
+ BEQ poly1305_finish_ext_armv6_skip8_aligned
+ MOVM.IA.W (R1), [g-R11]
+ MOVM.IA.W [g-R11], (R9)
+
+poly1305_finish_ext_armv6_skip8_aligned:
+ WORD $0xe3120004 // TST $4, R2 not working see issue 5921
+ BEQ poly1305_finish_ext_armv6_skip4_aligned
+ MOVW.P 4(R1), g
+ MOVW.P g, 4(R9)
+
+poly1305_finish_ext_armv6_skip4_aligned:
+ WORD $0xe3120002 // TST $2, R2 not working see issue 5921
+ BEQ poly1305_finish_ext_armv6_skip2
+ MOVHU.P 2(R1), g
+ MOVH.P g, 2(R9)
+
+poly1305_finish_ext_armv6_skip2:
+ WORD $0xe3120001 // TST $1, R2 not working see issue 5921
+ BEQ poly1305_finish_ext_armv6_skip1
+ MOVBU.P 1(R1), g
+ MOVBU.P g, 1(R9)
+
+poly1305_finish_ext_armv6_skip1:
+ MOVW $1, R11
+ MOVBU R11, 0(R9)
+ MOVW R11, 56(R5)
+ MOVW R5, R0
+ ADD $8, R13, R1
+ MOVW $16, R2
+ BL poly1305_blocks_armv6<>(SB)
+
+poly1305_finish_ext_armv6_noremaining:
+ MOVW 20(R5), R0
+ MOVW 24(R5), R1
+ MOVW 28(R5), R2
+ MOVW 32(R5), R3
+ MOVW 36(R5), R4
+ MOVW R4>>26, R12
+ BIC $0xfc000000, R4, R4
+ ADD R12<<2, R12, R12
+ ADD R12, R0, R0
+ MOVW R0>>26, R12
+ BIC $0xfc000000, R0, R0
+ ADD R12, R1, R1
+ MOVW R1>>26, R12
+ BIC $0xfc000000, R1, R1
+ ADD R12, R2, R2
+ MOVW R2>>26, R12
+ BIC $0xfc000000, R2, R2
+ ADD R12, R3, R3
+ MOVW R3>>26, R12
+ BIC $0xfc000000, R3, R3
+ ADD R12, R4, R4
+ ADD $5, R0, R6
+ MOVW R6>>26, R12
+ BIC $0xfc000000, R6, R6
+ ADD R12, R1, R7
+ MOVW R7>>26, R12
+ BIC $0xfc000000, R7, R7
+ ADD R12, R2, g
+ MOVW g>>26, R12
+ BIC $0xfc000000, g, g
+ ADD R12, R3, R11
+ MOVW $-(1<<26), R12
+ ADD R11>>26, R12, R12
+ BIC $0xfc000000, R11, R11
+ ADD R12, R4, R9
+ MOVW R9>>31, R12
+ SUB $1, R12
+ AND R12, R6, R6
+ AND R12, R7, R7
+ AND R12, g, g
+ AND R12, R11, R11
+ AND R12, R9, R9
+ MVN R12, R12
+ AND R12, R0, R0
+ AND R12, R1, R1
+ AND R12, R2, R2
+ AND R12, R3, R3
+ AND R12, R4, R4
+ ORR R6, R0, R0
+ ORR R7, R1, R1
+ ORR g, R2, R2
+ ORR R11, R3, R3
+ ORR R9, R4, R4
+ ORR R1<<26, R0, R0
+ MOVW R1>>6, R1
+ ORR R2<<20, R1, R1
+ MOVW R2>>12, R2
+ ORR R3<<14, R2, R2
+ MOVW R3>>18, R3
+ ORR R4<<8, R3, R3
+ MOVW 40(R5), R6
+ MOVW 44(R5), R7
+ MOVW 48(R5), g
+ MOVW 52(R5), R11
+ ADD.S R6, R0, R0
+ ADC.S R7, R1, R1
+ ADC.S g, R2, R2
+ ADC.S R11, R3, R3
+ MOVM.IA [R0-R3], (R8)
+ MOVW R5, R12
+ EOR R0, R0, R0
+ EOR R1, R1, R1
+ EOR R2, R2, R2
+ EOR R3, R3, R3
+ EOR R4, R4, R4
+ EOR R5, R5, R5
+ EOR R6, R6, R6
+ EOR R7, R7, R7
+ MOVM.IA.W [R0-R7], (R12)
+ MOVM.IA [R0-R7], (R12)
+ MOVW 4(R13), g
+ RET
diff --git a/src/vendor/golang_org/x/crypto/poly1305/sum_ref.go b/src/vendor/golang_org/x/crypto/poly1305/sum_ref.go
new file mode 100644
index 0000000..dbe50e7
--- /dev/null
+++ b/src/vendor/golang_org/x/crypto/poly1305/sum_ref.go
@@ -0,0 +1,1531 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !amd64,!arm gccgo appengine nacl
+
+package poly1305
+
+// Based on original, public domain implementation from NaCl by D. J.
+// Bernstein.
+
+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
+// 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:]
+ 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
+ )
+
+ 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
+ }
+
+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
+ }
+
+ 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)
+}
diff --git a/src/vendor/golang_org/x/net/idna/idna.go b/src/vendor/golang_org/x/net/idna/idna.go
new file mode 100644
index 0000000..3daa897
--- /dev/null
+++ b/src/vendor/golang_org/x/net/idna/idna.go
@@ -0,0 +1,68 @@
+// Copyright 2012 The Go Authors. 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"
+
+import (
+ "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
+
+// acePrefix is the ASCII Compatible Encoding prefix.
+const acePrefix = "xn--"
+
+// 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".
+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 strings.Join(labels, "."), nil
+}
+
+// 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
+ }
+ labels := strings.Split(s, ".")
+ for i, label := range labels {
+ if strings.HasPrefix(label, acePrefix) {
+ u, err := decode(label[len(acePrefix):])
+ if err != nil {
+ return "", err
+ }
+ labels[i] = u
+ }
+ }
+ return strings.Join(labels, "."), nil
+}
+
+func ascii(s string) bool {
+ for i := 0; i < len(s); i++ {
+ if s[i] >= utf8.RuneSelf {
+ return false
+ }
+ }
+ return true
+}
diff --git a/src/vendor/golang_org/x/net/idna/idna_test.go b/src/vendor/golang_org/x/net/idna/idna_test.go
new file mode 100644
index 0000000..b1bc6fa
--- /dev/null
+++ b/src/vendor/golang_org/x/net/idna/idna_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.
+
+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
new file mode 100644
index 0000000..92e733f
--- /dev/null
+++ b/src/vendor/golang_org/x/net/idna/punycode.go
@@ -0,0 +1,200 @@
+// Copyright 2012 The Go Authors. 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
+
+// This file implements the Punycode algorithm from RFC 3492.
+
+import (
+ "fmt"
+ "math"
+ "strings"
+ "unicode/utf8"
+)
+
+// These parameter values are specified in section 5.
+//
+// All computation is done with int32s, so that overflow behavior is identical
+// regardless of whether int is 32-bit or 64-bit.
+const (
+ base int32 = 36
+ damp int32 = 700
+ initialBias int32 = 72
+ initialN int32 = 128
+ skew int32 = 38
+ tmax int32 = 26
+ tmin int32 = 1
+)
+
+// decode decodes a string as specified in section 6.2.
+func decode(encoded string) (string, error) {
+ if encoded == "" {
+ return "", nil
+ }
+ pos := 1 + strings.LastIndex(encoded, "-")
+ if pos == 1 {
+ return "", fmt.Errorf("idna: invalid label %q", encoded)
+ }
+ if pos == len(encoded) {
+ return encoded[:len(encoded)-1], nil
+ }
+ output := make([]rune, 0, len(encoded))
+ if pos != 0 {
+ for _, r := range encoded[:pos-1] {
+ output = append(output, r)
+ }
+ }
+ i, n, bias := int32(0), initialN, initialBias
+ for pos < len(encoded) {
+ oldI, w := i, int32(1)
+ for k := base; ; k += base {
+ if pos == len(encoded) {
+ return "", fmt.Errorf("idna: invalid label %q", encoded)
+ }
+ digit, ok := decodeDigit(encoded[pos])
+ if !ok {
+ return "", fmt.Errorf("idna: invalid label %q", encoded)
+ }
+ pos++
+ i += digit * w
+ if i < 0 {
+ return "", fmt.Errorf("idna: invalid label %q", encoded)
+ }
+ t := k - bias
+ if t < tmin {
+ t = tmin
+ } else if t > tmax {
+ t = tmax
+ }
+ if digit < t {
+ break
+ }
+ w *= base - t
+ if w >= math.MaxInt32/base {
+ return "", fmt.Errorf("idna: invalid label %q", encoded)
+ }
+ }
+ x := int32(len(output) + 1)
+ bias = adapt(i-oldI, x, oldI == 0)
+ n += i / x
+ i %= x
+ if n > utf8.MaxRune || len(output) >= 1024 {
+ return "", fmt.Errorf("idna: invalid label %q", encoded)
+ }
+ output = append(output, 0)
+ copy(output[i+1:], output[i:])
+ output[i] = n
+ i++
+ }
+ return string(output), nil
+}
+
+// encode encodes a string as specified in section 6.3 and prepends prefix to
+// the result.
+//
+// The "while h < length(input)" line in the specification becomes "for
+// remaining != 0" in the Go code, because len(s) in Go is in bytes, not runes.
+func encode(prefix, s string) (string, error) {
+ output := make([]byte, len(prefix), len(prefix)+1+2*len(s))
+ copy(output, prefix)
+ delta, n, bias := int32(0), initialN, initialBias
+ b, remaining := int32(0), int32(0)
+ for _, r := range s {
+ if r < 0x80 {
+ b++
+ output = append(output, byte(r))
+ } else {
+ remaining++
+ }
+ }
+ h := b
+ if b > 0 {
+ output = append(output, '-')
+ }
+ for remaining != 0 {
+ m := int32(0x7fffffff)
+ for _, r := range s {
+ if m > r && r >= n {
+ m = r
+ }
+ }
+ delta += (m - n) * (h + 1)
+ if delta < 0 {
+ return "", fmt.Errorf("idna: invalid label %q", s)
+ }
+ n = m
+ for _, r := range s {
+ if r < n {
+ delta++
+ if delta < 0 {
+ return "", fmt.Errorf("idna: invalid label %q", s)
+ }
+ continue
+ }
+ if r > n {
+ continue
+ }
+ q := delta
+ for k := base; ; k += base {
+ t := k - bias
+ if t < tmin {
+ t = tmin
+ } else if t > tmax {
+ t = tmax
+ }
+ if q < t {
+ break
+ }
+ output = append(output, encodeDigit(t+(q-t)%(base-t)))
+ q = (q - t) / (base - t)
+ }
+ output = append(output, encodeDigit(q))
+ bias = adapt(delta, h+1, h == b)
+ delta = 0
+ h++
+ remaining--
+ }
+ delta++
+ n++
+ }
+ return string(output), nil
+}
+
+func decodeDigit(x byte) (digit int32, ok bool) {
+ switch {
+ case '0' <= x && x <= '9':
+ return int32(x - ('0' - 26)), true
+ case 'A' <= x && x <= 'Z':
+ return int32(x - 'A'), true
+ case 'a' <= x && x <= 'z':
+ return int32(x - 'a'), true
+ }
+ return 0, false
+}
+
+func encodeDigit(digit int32) byte {
+ switch {
+ case 0 <= digit && digit < 26:
+ return byte(digit + 'a')
+ case 26 <= digit && digit < 36:
+ return byte(digit + ('0' - 26))
+ }
+ panic("idna: internal error in punycode encoding")
+}
+
+// adapt is the bias adaptation function specified in section 6.1.
+func adapt(delta, numPoints int32, firstTime bool) int32 {
+ if firstTime {
+ delta /= damp
+ } else {
+ delta /= 2
+ }
+ delta += delta / numPoints
+ k := int32(0)
+ for delta > ((base-tmin)*tmax)/2 {
+ delta /= base - tmin
+ k += base
+ }
+ return k + (base-tmin+1)*delta/(delta+skew)
+}
diff --git a/src/vendor/golang_org/x/net/idna/punycode_test.go b/src/vendor/golang_org/x/net/idna/punycode_test.go
new file mode 100644
index 0000000..bfec81d
--- /dev/null
+++ b/src/vendor/golang_org/x/net/idna/punycode_test.go
@@ -0,0 +1,198 @@
+// Copyright 2012 The Go Authors. 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 (
+ "strings"
+ "testing"
+)
+
+var punycodeTestCases = [...]struct {
+ s, encoded string
+}{
+ {"", ""},
+ {"-", "--"},
+ {"-a", "-a-"},
+ {"-a-", "-a--"},
+ {"a", "a-"},
+ {"a-", "a--"},
+ {"a-b", "a-b-"},
+ {"books", "books-"},
+ {"bücher", "bcher-kva"},
+ {"Hello世界", "Hello-ck1hg65u"},
+ {"ü", "tda"},
+ {"üý", "tdac"},
+
+ // The test cases below come from RFC 3492 section 7.1 with Errata 3026.
+ {
+ // (A) Arabic (Egyptian).
+ "\u0644\u064A\u0647\u0645\u0627\u0628\u062A\u0643\u0644" +
+ "\u0645\u0648\u0634\u0639\u0631\u0628\u064A\u061F",
+ "egbpdaj6bu4bxfgehfvwxn",
+ },
+ {
+ // (B) Chinese (simplified).
+ "\u4ED6\u4EEC\u4E3A\u4EC0\u4E48\u4E0D\u8BF4\u4E2D\u6587",
+ "ihqwcrb4cv8a8dqg056pqjye",
+ },
+ {
+ // (C) Chinese (traditional).
+ "\u4ED6\u5011\u7232\u4EC0\u9EBD\u4E0D\u8AAA\u4E2D\u6587",
+ "ihqwctvzc91f659drss3x8bo0yb",
+ },
+ {
+ // (D) Czech.
+ "\u0050\u0072\u006F\u010D\u0070\u0072\u006F\u0073\u0074" +
+ "\u011B\u006E\u0065\u006D\u006C\u0075\u0076\u00ED\u010D" +
+ "\u0065\u0073\u006B\u0079",
+ "Proprostnemluvesky-uyb24dma41a",
+ },
+ {
+ // (E) Hebrew.
+ "\u05DC\u05DE\u05D4\u05D4\u05DD\u05E4\u05E9\u05D5\u05D8" +
+ "\u05DC\u05D0\u05DE\u05D3\u05D1\u05E8\u05D9\u05DD\u05E2" +
+ "\u05D1\u05E8\u05D9\u05EA",
+ "4dbcagdahymbxekheh6e0a7fei0b",
+ },
+ {
+ // (F) Hindi (Devanagari).
+ "\u092F\u0939\u0932\u094B\u0917\u0939\u093F\u0928\u094D" +
+ "\u0926\u0940\u0915\u094D\u092F\u094B\u0902\u0928\u0939" +
+ "\u0940\u0902\u092C\u094B\u0932\u0938\u0915\u0924\u0947" +
+ "\u0939\u0948\u0902",
+ "i1baa7eci9glrd9b2ae1bj0hfcgg6iyaf8o0a1dig0cd",
+ },
+ {
+ // (G) Japanese (kanji and hiragana).
+ "\u306A\u305C\u307F\u3093\u306A\u65E5\u672C\u8A9E\u3092" +
+ "\u8A71\u3057\u3066\u304F\u308C\u306A\u3044\u306E\u304B",
+ "n8jok5ay5dzabd5bym9f0cm5685rrjetr6pdxa",
+ },
+ {
+ // (H) Korean (Hangul syllables).
+ "\uC138\uACC4\uC758\uBAA8\uB4E0\uC0AC\uB78C\uB4E4\uC774" +
+ "\uD55C\uAD6D\uC5B4\uB97C\uC774\uD574\uD55C\uB2E4\uBA74" +
+ "\uC5BC\uB9C8\uB098\uC88B\uC744\uAE4C",
+ "989aomsvi5e83db1d2a355cv1e0vak1dwrv93d5xbh15a0dt30a5j" +
+ "psd879ccm6fea98c",
+ },
+ {
+ // (I) Russian (Cyrillic).
+ "\u043F\u043E\u0447\u0435\u043C\u0443\u0436\u0435\u043E" +
+ "\u043D\u0438\u043D\u0435\u0433\u043E\u0432\u043E\u0440" +
+ "\u044F\u0442\u043F\u043E\u0440\u0443\u0441\u0441\u043A" +
+ "\u0438",
+ "b1abfaaepdrnnbgefbadotcwatmq2g4l",
+ },
+ {
+ // (J) Spanish.
+ "\u0050\u006F\u0072\u0071\u0075\u00E9\u006E\u006F\u0070" +
+ "\u0075\u0065\u0064\u0065\u006E\u0073\u0069\u006D\u0070" +
+ "\u006C\u0065\u006D\u0065\u006E\u0074\u0065\u0068\u0061" +
+ "\u0062\u006C\u0061\u0072\u0065\u006E\u0045\u0073\u0070" +
+ "\u0061\u00F1\u006F\u006C",
+ "PorqunopuedensimplementehablarenEspaol-fmd56a",
+ },
+ {
+ // (K) Vietnamese.
+ "\u0054\u1EA1\u0069\u0073\u0061\u006F\u0068\u1ECD\u006B" +
+ "\u0068\u00F4\u006E\u0067\u0074\u0068\u1EC3\u0063\u0068" +
+ "\u1EC9\u006E\u00F3\u0069\u0074\u0069\u1EBF\u006E\u0067" +
+ "\u0056\u0069\u1EC7\u0074",
+ "TisaohkhngthchnitingVit-kjcr8268qyxafd2f1b9g",
+ },
+ {
+ // (L) 3<nen>B<gumi><kinpachi><sensei>.
+ "\u0033\u5E74\u0042\u7D44\u91D1\u516B\u5148\u751F",
+ "3B-ww4c5e180e575a65lsy2b",
+ },
+ {
+ // (M) <amuro><namie>-with-SUPER-MONKEYS.
+ "\u5B89\u5BA4\u5948\u7F8E\u6075\u002D\u0077\u0069\u0074" +
+ "\u0068\u002D\u0053\u0055\u0050\u0045\u0052\u002D\u004D" +
+ "\u004F\u004E\u004B\u0045\u0059\u0053",
+ "-with-SUPER-MONKEYS-pc58ag80a8qai00g7n9n",
+ },
+ {
+ // (N) Hello-Another-Way-<sorezore><no><basho>.
+ "\u0048\u0065\u006C\u006C\u006F\u002D\u0041\u006E\u006F" +
+ "\u0074\u0068\u0065\u0072\u002D\u0057\u0061\u0079\u002D" +
+ "\u305D\u308C\u305E\u308C\u306E\u5834\u6240",
+ "Hello-Another-Way--fc4qua05auwb3674vfr0b",
+ },
+ {
+ // (O) <hitotsu><yane><no><shita>2.
+ "\u3072\u3068\u3064\u5C4B\u6839\u306E\u4E0B\u0032",
+ "2-u9tlzr9756bt3uc0v",
+ },
+ {
+ // (P) Maji<de>Koi<suru>5<byou><mae>
+ "\u004D\u0061\u006A\u0069\u3067\u004B\u006F\u0069\u3059" +
+ "\u308B\u0035\u79D2\u524D",
+ "MajiKoi5-783gue6qz075azm5e",
+ },
+ {
+ // (Q) <pafii>de<runba>
+ "\u30D1\u30D5\u30A3\u30FC\u0064\u0065\u30EB\u30F3\u30D0",
+ "de-jg4avhby1noc0d",
+ },
+ {
+ // (R) <sono><supiido><de>
+ "\u305D\u306E\u30B9\u30D4\u30FC\u30C9\u3067",
+ "d9juau41awczczp",
+ },
+ {
+ // (S) -> $1.00 <-
+ "\u002D\u003E\u0020\u0024\u0031\u002E\u0030\u0030\u0020" +
+ "\u003C\u002D",
+ "-> $1.00 <--",
+ },
+}
+
+func TestPunycode(t *testing.T) {
+ for _, tc := range punycodeTestCases {
+ if got, err := decode(tc.encoded); err != nil {
+ t.Errorf("decode(%q): %v", tc.encoded, err)
+ } else if got != tc.s {
+ t.Errorf("decode(%q): got %q, want %q", tc.encoded, got, tc.s)
+ }
+
+ if got, err := encode("", tc.s); err != nil {
+ t.Errorf(`encode("", %q): %v`, tc.s, err)
+ } else if got != tc.encoded {
+ t.Errorf(`encode("", %q): got %q, want %q`, tc.s, got, tc.encoded)
+ }
+ }
+}
+
+var punycodeErrorTestCases = [...]string{
+ "decode -", // A sole '-' is invalid.
+ "decode foo\x00bar", // '\x00' is not in [0-9A-Za-z].
+ "decode foo#bar", // '#' is not in [0-9A-Za-z].
+ "decode foo\u00A3bar", // '\u00A3' is not in [0-9A-Za-z].
+ "decode 9", // "9a" decodes to codepoint \u00A3; "9" is truncated.
+ "decode 99999a", // "99999a" decodes to codepoint \U0048A3C1, which is > \U0010FFFF.
+ "decode 9999999999a", // "9999999999a" overflows the int32 calculation.
+
+ "encode " + strings.Repeat("x", 65536) + "\uff00", // int32 overflow.
+}
+
+func TestPunycodeErrors(t *testing.T) {
+ for _, tc := range punycodeErrorTestCases {
+ var err error
+ switch {
+ case strings.HasPrefix(tc, "decode "):
+ _, err = decode(tc[7:])
+ case strings.HasPrefix(tc, "encode "):
+ _, err = encode("", tc[7:])
+ }
+ if err == nil {
+ if len(tc) > 256 {
+ tc = tc[:100] + "..." + tc[len(tc)-100:]
+ }
+ t.Errorf("no error for %s", tc)
+ }
+ }
+}
diff --git a/src/vendor/golang_org/x/net/lex/httplex/httplex.go b/src/vendor/golang_org/x/net/lex/httplex/httplex.go
index bd0ec24..b6493f0 100644
--- a/src/vendor/golang_org/x/net/lex/httplex/httplex.go
+++ b/src/vendor/golang_org/x/net/lex/httplex/httplex.go
@@ -10,8 +10,11 @@
package httplex
import (
+ "net"
"strings"
"unicode/utf8"
+
+ "golang_org/x/net/idna"
)
var isTokenTable = [127]bool{
@@ -310,3 +313,39 @@ func ValidHeaderFieldValue(v string) bool {
}
return true
}
+
+func isASCII(s string) bool {
+ for i := 0; i < len(s); i++ {
+ if s[i] >= utf8.RuneSelf {
+ return false
+ }
+ }
+ return true
+}
+
+// PunycodeHostPort returns the IDNA Punycode version
+// of the provided "host" or "host:port" string.
+func PunycodeHostPort(v string) (string, error) {
+ if isASCII(v) {
+ return v, nil
+ }
+
+ host, port, err := net.SplitHostPort(v)
+ if err != nil {
+ // The input 'v' argument was just a "host" argument,
+ // without a port. This error should not be returned
+ // to the caller.
+ host = v
+ port = ""
+ }
+ host, err = idna.ToASCII(host)
+ if err != nil {
+ // Non-UTF-8? Not representable in Punycode, in any
+ // case.
+ return "", err
+ }
+ if port == "" {
+ return host, nil
+ }
+ return net.JoinHostPort(host, port), nil
+}
diff --git a/src/vendor/golang_org/x/net/lex/httplex/httplex_test.go b/src/vendor/golang_org/x/net/lex/httplex/httplex_test.go
index c4ace19..f47adc9 100644
--- a/src/vendor/golang_org/x/net/lex/httplex/httplex_test.go
+++ b/src/vendor/golang_org/x/net/lex/httplex/httplex_test.go
@@ -99,3 +99,21 @@ func TestHeaderValuesContainsToken(t *testing.T) {
}
}
}
+
+func TestPunycodeHostPort(t *testing.T) {
+ tests := []struct {
+ in, want string
+ }{
+ {"www.google.com", "www.google.com"},
+ {"гофер.рф", "xn--c1ae0ajs.xn--p1ai"},
+ {"bücher.de", "xn--bcher-kva.de"},
+ {"bücher.de:8080", "xn--bcher-kva.de:8080"},
+ {"[1::6]:8080", "[1::6]:8080"},
+ }
+ for _, tt := range tests {
+ got, err := PunycodeHostPort(tt.in)
+ if tt.want != got || err != nil {
+ t.Errorf("PunycodeHostPort(%q) = %q, %v, want %q, nil", tt.in, got, err, tt.want)
+ }
+ }
+}
diff --git a/src/vendor/golang_org/x/net/lif/address.go b/src/vendor/golang_org/x/net/lif/address.go
new file mode 100644
index 0000000..f9b34ae
--- /dev/null
+++ b/src/vendor/golang_org/x/net/lif/address.go
@@ -0,0 +1,105 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build solaris
+
+package lif
+
+import (
+ "errors"
+ "unsafe"
+)
+
+// An Addr represents an address associated with packet routing.
+type Addr interface {
+ // Family returns an address family.
+ Family() int
+}
+
+// An Inet4Addr represents an internet address for IPv4.
+type Inet4Addr struct {
+ IP [4]byte // IP address
+ PrefixLen int // address prefix length
+}
+
+// Family implements the Family method of Addr interface.
+func (a *Inet4Addr) Family() int { return sysAF_INET }
+
+// An Inet6Addr represents an internet address for IPv6.
+type Inet6Addr struct {
+ IP [16]byte // IP address
+ PrefixLen int // address prefix length
+ ZoneID int // zone identifier
+}
+
+// Family implements the Family method of Addr interface.
+func (a *Inet6Addr) Family() int { return sysAF_INET6 }
+
+// Addrs returns a list of interface addresses.
+//
+// The provided af must be an address family and name must be a data
+// link name. The zero value of af or name means a wildcard.
+func Addrs(af int, name string) ([]Addr, error) {
+ eps, err := newEndpoints(af)
+ if len(eps) == 0 {
+ return nil, err
+ }
+ defer func() {
+ for _, ep := range eps {
+ ep.close()
+ }
+ }()
+ lls, err := links(eps, name)
+ if len(lls) == 0 {
+ return nil, err
+ }
+ var as []Addr
+ for _, ll := range lls {
+ var lifr lifreq
+ for i := 0; i < len(ll.Name); i++ {
+ lifr.Name[i] = int8(ll.Name[i])
+ }
+ for _, ep := range eps {
+ ioc := int64(sysSIOCGLIFADDR)
+ err := ioctl(ep.s, uintptr(ioc), unsafe.Pointer(&lifr))
+ if err != nil {
+ continue
+ }
+ sa := (*sockaddrStorage)(unsafe.Pointer(&lifr.Lifru[0]))
+ l := int(littleEndian.Uint32(lifr.Lifru1[:4]))
+ if l == 0 {
+ continue
+ }
+ switch sa.Family {
+ case sysAF_INET:
+ a := &Inet4Addr{PrefixLen: l}
+ 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]))}
+ copy(a.IP[:], lifr.Lifru[8:24])
+ as = append(as, a)
+ }
+ }
+ }
+ return as, nil
+}
+
+func parseLinkAddr(b []byte) ([]byte, error) {
+ nlen, alen, slen := int(b[1]), int(b[2]), int(b[3])
+ l := 4 + nlen + alen + slen
+ if len(b) < l {
+ return nil, errors.New("invalid address")
+ }
+ b = b[4:]
+ var addr []byte
+ if nlen > 0 {
+ b = b[nlen:]
+ }
+ if alen > 0 {
+ addr = make([]byte, alen)
+ copy(addr, b[:alen])
+ }
+ return addr, nil
+}
diff --git a/src/vendor/golang_org/x/net/lif/address_test.go b/src/vendor/golang_org/x/net/lif/address_test.go
new file mode 100644
index 0000000..f62ed93
--- /dev/null
+++ b/src/vendor/golang_org/x/net/lif/address_test.go
@@ -0,0 +1,121 @@
+// Copyright 2016 The Go Authors. 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 (
+ "fmt"
+ "testing"
+)
+
+type addrFamily int
+
+func (af addrFamily) String() string {
+ switch af {
+ case sysAF_UNSPEC:
+ return "unspec"
+ case sysAF_INET:
+ return "inet4"
+ case sysAF_INET6:
+ return "inet6"
+ default:
+ return fmt.Sprintf("%d", af)
+ }
+}
+
+const hexDigit = "0123456789abcdef"
+
+type llAddr []byte
+
+func (a llAddr) String() string {
+ if len(a) == 0 {
+ return ""
+ }
+ buf := make([]byte, 0, len(a)*3-1)
+ for i, b := range a {
+ if i > 0 {
+ buf = append(buf, ':')
+ }
+ buf = append(buf, hexDigit[b>>4])
+ buf = append(buf, hexDigit[b&0xF])
+ }
+ return string(buf)
+}
+
+type ipAddr []byte
+
+func (a ipAddr) String() string {
+ if len(a) == 0 {
+ return "<nil>"
+ }
+ if len(a) == 4 {
+ return fmt.Sprintf("%d.%d.%d.%d", a[0], a[1], a[2], a[3])
+ }
+ if len(a) == 16 {
+ return fmt.Sprintf("%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x", a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], a[14], a[15])
+ }
+ s := make([]byte, len(a)*2)
+ for i, tn := range a {
+ s[i*2], s[i*2+1] = hexDigit[tn>>4], hexDigit[tn&0xf]
+ }
+ return string(s)
+}
+
+func (a *Inet4Addr) String() string {
+ return fmt.Sprintf("(%s %s %d)", addrFamily(a.Family()), ipAddr(a.IP[:]), a.PrefixLen)
+}
+
+func (a *Inet6Addr) String() string {
+ return fmt.Sprintf("(%s %s %d %d)", addrFamily(a.Family()), ipAddr(a.IP[:]), a.PrefixLen, a.ZoneID)
+}
+
+type addrPack struct {
+ af int
+ as []Addr
+}
+
+func addrPacks() ([]addrPack, error) {
+ var aps []addrPack
+ for _, af := range [...]int{sysAF_UNSPEC, sysAF_INET, sysAF_INET6} {
+ as, err := Addrs(af, "")
+ if err != nil {
+ return nil, err
+ }
+ aps = append(aps, addrPack{af: af, as: as})
+ }
+ return aps, nil
+}
+
+func TestAddrs(t *testing.T) {
+ aps, err := addrPacks()
+ if len(aps) == 0 && err != nil {
+ t.Fatal(err)
+ }
+ lps, err := linkPacks()
+ if len(lps) == 0 && err != nil {
+ t.Fatal(err)
+ }
+ for _, lp := range lps {
+ n := 0
+ for _, ll := range lp.lls {
+ as, err := Addrs(lp.af, ll.Name)
+ if err != nil {
+ t.Fatal(lp.af, ll.Name, err)
+ }
+ t.Logf("af=%s name=%s %v", addrFamily(lp.af), ll.Name, as)
+ n += len(as)
+ }
+ for _, ap := range aps {
+ if ap.af != lp.af {
+ continue
+ }
+ if n != len(ap.as) {
+ t.Errorf("af=%s got %d; want %d", addrFamily(lp.af), n, len(ap.as))
+ continue
+ }
+ }
+ }
+}
diff --git a/src/vendor/golang_org/x/net/lif/binary.go b/src/vendor/golang_org/x/net/lif/binary.go
new file mode 100644
index 0000000..aade9ea
--- /dev/null
+++ b/src/vendor/golang_org/x/net/lif/binary.go
@@ -0,0 +1,68 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build solaris
+
+package lif
+
+// This file contains duplicates of encoding/binary package.
+//
+// This package is supposed to be used by the net package of standard
+// library. Therefore the package set used in the package must be the
+// same as net package.
+
+var littleEndian binaryLittleEndian
+
+type binaryByteOrder interface {
+ Uint16([]byte) uint16
+ Uint32([]byte) uint32
+ Uint64([]byte) uint64
+ PutUint16([]byte, uint16)
+ PutUint32([]byte, uint32)
+ PutUint64([]byte, uint64)
+}
+
+type binaryLittleEndian struct{}
+
+func (binaryLittleEndian) Uint16(b []byte) uint16 {
+ _ = b[1] // bounds check hint to compiler; see golang.org/issue/14808
+ return uint16(b[0]) | uint16(b[1])<<8
+}
+
+func (binaryLittleEndian) PutUint16(b []byte, v uint16) {
+ _ = b[1] // early bounds check to guarantee safety of writes below
+ b[0] = byte(v)
+ b[1] = byte(v >> 8)
+}
+
+func (binaryLittleEndian) Uint32(b []byte) uint32 {
+ _ = b[3] // bounds check hint to compiler; see golang.org/issue/14808
+ return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24
+}
+
+func (binaryLittleEndian) PutUint32(b []byte, v uint32) {
+ _ = b[3] // early bounds check to guarantee safety of writes below
+ b[0] = byte(v)
+ b[1] = byte(v >> 8)
+ b[2] = byte(v >> 16)
+ b[3] = byte(v >> 24)
+}
+
+func (binaryLittleEndian) Uint64(b []byte) uint64 {
+ _ = b[7] // bounds check hint to compiler; see golang.org/issue/14808
+ return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 |
+ uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56
+}
+
+func (binaryLittleEndian) PutUint64(b []byte, v uint64) {
+ _ = b[7] // early bounds check to guarantee safety of writes below
+ b[0] = byte(v)
+ b[1] = byte(v >> 8)
+ b[2] = byte(v >> 16)
+ b[3] = byte(v >> 24)
+ b[4] = byte(v >> 32)
+ b[5] = byte(v >> 40)
+ b[6] = byte(v >> 48)
+ b[7] = byte(v >> 56)
+}
diff --git a/src/vendor/golang_org/x/net/lif/defs_solaris.go b/src/vendor/golang_org/x/net/lif/defs_solaris.go
new file mode 100644
index 0000000..8b84ba5
--- /dev/null
+++ b/src/vendor/golang_org/x/net/lif/defs_solaris.go
@@ -0,0 +1,90 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build ignore
+
+// +godefs map struct_in_addr [4]byte /* in_addr */
+// +godefs map struct_in6_addr [16]byte /* in6_addr */
+
+package lif
+
+/*
+#include <sys/socket.h>
+#include <sys/sockio.h>
+
+#include <net/if.h>
+#include <net/if_types.h>
+*/
+import "C"
+
+const (
+ sysAF_UNSPEC = C.AF_UNSPEC
+ sysAF_INET = C.AF_INET
+ sysAF_INET6 = C.AF_INET6
+
+ sysSOCK_DGRAM = C.SOCK_DGRAM
+)
+
+type sockaddrStorage C.struct_sockaddr_storage
+
+const (
+ sysLIFC_NOXMIT = C.LIFC_NOXMIT
+ sysLIFC_EXTERNAL_SOURCE = C.LIFC_EXTERNAL_SOURCE
+ sysLIFC_TEMPORARY = C.LIFC_TEMPORARY
+ sysLIFC_ALLZONES = C.LIFC_ALLZONES
+ sysLIFC_UNDER_IPMP = C.LIFC_UNDER_IPMP
+ sysLIFC_ENABLED = C.LIFC_ENABLED
+
+ sysSIOCGLIFADDR = C.SIOCGLIFADDR
+ sysSIOCGLIFDSTADDR = C.SIOCGLIFDSTADDR
+ sysSIOCGLIFFLAGS = C.SIOCGLIFFLAGS
+ sysSIOCGLIFMTU = C.SIOCGLIFMTU
+ sysSIOCGLIFNETMASK = C.SIOCGLIFNETMASK
+ sysSIOCGLIFMETRIC = C.SIOCGLIFMETRIC
+ sysSIOCGLIFNUM = C.SIOCGLIFNUM
+ sysSIOCGLIFINDEX = C.SIOCGLIFINDEX
+ sysSIOCGLIFSUBNET = C.SIOCGLIFSUBNET
+ sysSIOCGLIFLNKINFO = C.SIOCGLIFLNKINFO
+ sysSIOCGLIFCONF = C.SIOCGLIFCONF
+ sysSIOCGLIFHWADDR = C.SIOCGLIFHWADDR
+)
+
+const (
+ sysIFF_UP = C.IFF_UP
+ sysIFF_BROADCAST = C.IFF_BROADCAST
+ sysIFF_DEBUG = C.IFF_DEBUG
+ sysIFF_LOOPBACK = C.IFF_LOOPBACK
+ sysIFF_POINTOPOINT = C.IFF_POINTOPOINT
+ sysIFF_NOTRAILERS = C.IFF_NOTRAILERS
+ sysIFF_RUNNING = C.IFF_RUNNING
+ sysIFF_NOARP = C.IFF_NOARP
+ sysIFF_PROMISC = C.IFF_PROMISC
+ sysIFF_ALLMULTI = C.IFF_ALLMULTI
+ sysIFF_INTELLIGENT = C.IFF_INTELLIGENT
+ sysIFF_MULTICAST = C.IFF_MULTICAST
+ sysIFF_MULTI_BCAST = C.IFF_MULTI_BCAST
+ sysIFF_UNNUMBERED = C.IFF_UNNUMBERED
+ sysIFF_PRIVATE = C.IFF_PRIVATE
+)
+
+const (
+ sizeofLifnum = C.sizeof_struct_lifnum
+ sizeofLifreq = C.sizeof_struct_lifreq
+ sizeofLifconf = C.sizeof_struct_lifconf
+ sizeofLifIfinfoReq = C.sizeof_struct_lif_ifinfo_req
+)
+
+type sysLifnum C.struct_lifnum
+
+type lifreq C.struct_lifreq
+
+type lifconf C.struct_lifconf
+
+type lifIfinfoReq C.struct_lif_ifinfo_req
+
+const (
+ sysIFT_IPV4 = C.IFT_IPV4
+ sysIFT_IPV6 = C.IFT_IPV6
+ sysIFT_6TO4 = C.IFT_6TO4
+)
diff --git a/src/vendor/golang_org/x/net/lif/lif.go b/src/vendor/golang_org/x/net/lif/lif.go
new file mode 100644
index 0000000..6e81f81
--- /dev/null
+++ b/src/vendor/golang_org/x/net/lif/lif.go
@@ -0,0 +1,43 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build solaris
+
+// Package lif provides basic functions for the manipulation of
+// logical network interfaces and interface addresses on Solaris.
+//
+// The package supports Solaris 11 or above.
+package lif
+
+import "syscall"
+
+type endpoint struct {
+ af int
+ s uintptr
+}
+
+func (ep *endpoint) close() error {
+ return syscall.Close(int(ep.s))
+}
+
+func newEndpoints(af int) ([]endpoint, error) {
+ var lastErr error
+ var eps []endpoint
+ afs := []int{sysAF_INET, sysAF_INET6}
+ if af != sysAF_UNSPEC {
+ afs = []int{af}
+ }
+ for _, af := range afs {
+ s, err := syscall.Socket(af, sysSOCK_DGRAM, 0)
+ if err != nil {
+ lastErr = err
+ continue
+ }
+ eps = append(eps, endpoint{af: af, s: uintptr(s)})
+ }
+ if len(eps) == 0 {
+ return nil, lastErr
+ }
+ return eps, nil
+}
diff --git a/src/vendor/golang_org/x/net/lif/link.go b/src/vendor/golang_org/x/net/lif/link.go
new file mode 100644
index 0000000..76fa6c6
--- /dev/null
+++ b/src/vendor/golang_org/x/net/lif/link.go
@@ -0,0 +1,122 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build solaris
+
+package lif
+
+import "unsafe"
+
+// A Link represents logical data link information.
+//
+// It also represents base information for logical network interface.
+// On Solaris, each logical network interface represents network layer
+// adjacency information and the interface has a only single network
+// address or address pair for tunneling. It's usual that multiple
+// logical network interfaces share the same logical data link.
+type Link struct {
+ Name string // name, equivalent to IP interface name
+ Index int // index, equivalent to IP interface index
+ Type int // type
+ Flags int // flags
+ MTU int // maximum transmission unit, basically link MTU but may differ between IP address families
+ Addr []byte // address
+}
+
+func (ll *Link) fetch(s uintptr) {
+ var lifr lifreq
+ for i := 0; i < len(ll.Name); i++ {
+ lifr.Name[i] = int8(ll.Name[i])
+ }
+ ioc := int64(sysSIOCGLIFINDEX)
+ if err := ioctl(s, uintptr(ioc), unsafe.Pointer(&lifr)); err == nil {
+ ll.Index = int(littleEndian.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]))
+ }
+ ioc = int64(sysSIOCGLIFMTU)
+ if err := ioctl(s, uintptr(ioc), unsafe.Pointer(&lifr)); err == nil {
+ ll.MTU = int(littleEndian.Uint32(lifr.Lifru[:4]))
+ }
+ switch ll.Type {
+ case sysIFT_IPV4, sysIFT_IPV6, sysIFT_6TO4:
+ default:
+ ioc = int64(sysSIOCGLIFHWADDR)
+ if err := ioctl(s, uintptr(ioc), unsafe.Pointer(&lifr)); err == nil {
+ ll.Addr, _ = parseLinkAddr(lifr.Lifru[4:])
+ }
+ }
+}
+
+// Links returns a list of logical data links.
+//
+// The provided af must be an address family and name must be a data
+// link name. The zero value of af or name means a wildcard.
+func Links(af int, name string) ([]Link, error) {
+ eps, err := newEndpoints(af)
+ if len(eps) == 0 {
+ return nil, err
+ }
+ defer func() {
+ for _, ep := range eps {
+ ep.close()
+ }
+ }()
+ return links(eps, name)
+}
+
+func links(eps []endpoint, name string) ([]Link, error) {
+ var lls []Link
+ lifn := sysLifnum{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)
+ ioc := int64(sysSIOCGLIFNUM)
+ if err := ioctl(ep.s, uintptr(ioc), unsafe.Pointer(&lifn)); err != nil {
+ continue
+ }
+ if lifn.Count == 0 {
+ continue
+ }
+ 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]))))
+ ioc = int64(sysSIOCGLIFCONF)
+ if err := ioctl(ep.s, uintptr(ioc), unsafe.Pointer(&lifc)); err != nil {
+ continue
+ }
+ nb := make([]byte, 32) // see LIFNAMSIZ in net/if.h
+ for i := 0; i < int(lifn.Count); i++ {
+ lifr := (*lifreq)(unsafe.Pointer(&b[i*sizeofLifreq]))
+ for i := 0; i < 32; i++ {
+ if lifr.Name[i] == 0 {
+ nb = nb[:i]
+ break
+ }
+ nb[i] = byte(lifr.Name[i])
+ }
+ llname := string(nb)
+ nb = nb[:32]
+ if isDupLink(lls, llname) || name != "" && name != llname {
+ continue
+ }
+ ll := Link{Name: llname, Type: int(lifr.Type)}
+ ll.fetch(ep.s)
+ lls = append(lls, ll)
+ }
+ }
+ return lls, nil
+}
+
+func isDupLink(lls []Link, name string) bool {
+ for _, ll := range lls {
+ if ll.Name == name {
+ return true
+ }
+ }
+ return false
+}
diff --git a/src/vendor/golang_org/x/net/lif/link_test.go b/src/vendor/golang_org/x/net/lif/link_test.go
new file mode 100644
index 0000000..8fb2bf6
--- /dev/null
+++ b/src/vendor/golang_org/x/net/lif/link_test.go
@@ -0,0 +1,61 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build solaris
+
+package lif
+
+import (
+ "fmt"
+ "testing"
+)
+
+func (ll *Link) String() string {
+ return fmt.Sprintf("name=%s index=%d type=%d flags=%#x mtu=%d addr=%v", ll.Name, ll.Index, ll.Type, ll.Flags, ll.MTU, llAddr(ll.Addr))
+}
+
+type linkPack struct {
+ af int
+ lls []Link
+}
+
+func linkPacks() ([]linkPack, error) {
+ var lps []linkPack
+ for _, af := range [...]int{sysAF_UNSPEC, sysAF_INET, sysAF_INET6} {
+ lls, err := Links(af, "")
+ if err != nil {
+ return nil, err
+ }
+ lps = append(lps, linkPack{af: af, lls: lls})
+ }
+ return lps, nil
+}
+
+func TestLinks(t *testing.T) {
+ lps, err := linkPacks()
+ if len(lps) == 0 && err != nil {
+ t.Fatal(err)
+ }
+ for _, lp := range lps {
+ n := 0
+ for _, sll := range lp.lls {
+ lls, err := Links(lp.af, sll.Name)
+ if err != nil {
+ t.Fatal(lp.af, sll.Name, err)
+ }
+ for _, ll := range lls {
+ if ll.Name != sll.Name || ll.Index != sll.Index {
+ t.Errorf("af=%s got %v; want %v", addrFamily(lp.af), &ll, &sll)
+ continue
+ }
+ t.Logf("af=%s name=%s %v", addrFamily(lp.af), sll.Name, &ll)
+ n++
+ }
+ }
+ if n != len(lp.lls) {
+ t.Errorf("af=%s got %d; want %d", addrFamily(lp.af), n, len(lp.lls))
+ continue
+ }
+ }
+}
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
new file mode 100644
index 0000000..1ebca37
--- /dev/null
+++ b/src/vendor/golang_org/x/net/lif/sys_solaris_amd64.s
@@ -0,0 +1,11 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "textflag.h"
+
+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
new file mode 100644
index 0000000..5fe0736
--- /dev/null
+++ b/src/vendor/golang_org/x/net/lif/syscall.go
@@ -0,0 +1,33 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build solaris
+
+package lif
+
+import (
+ "syscall"
+ "unsafe"
+)
+
+//go:cgo_import_dynamic libc_ioctl ioctl "libc.so"
+
+//go:linkname procIoctl libc_ioctl
+
+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)
+ }
+ return nil
+}
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
new file mode 100644
index 0000000..94231c4
--- /dev/null
+++ b/src/vendor/golang_org/x/net/lif/zsys_solaris_amd64.go
@@ -0,0 +1,103 @@
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs defs_solaris.go
+
+package lif
+
+const (
+ sysAF_UNSPEC = 0x0
+ sysAF_INET = 0x2
+ sysAF_INET6 = 0x1a
+
+ sysSOCK_DGRAM = 0x1
+)
+
+type sockaddrStorage struct {
+ Family uint16
+ X_ss_pad1 [6]int8
+ X_ss_align float64
+ X_ss_pad2 [240]int8
+}
+
+const (
+ sysLIFC_NOXMIT = 0x1
+ sysLIFC_EXTERNAL_SOURCE = 0x2
+ sysLIFC_TEMPORARY = 0x4
+ sysLIFC_ALLZONES = 0x8
+ sysLIFC_UNDER_IPMP = 0x10
+ sysLIFC_ENABLED = 0x20
+
+ sysSIOCGLIFADDR = -0x3f87968f
+ sysSIOCGLIFDSTADDR = -0x3f87968d
+ sysSIOCGLIFFLAGS = -0x3f87968b
+ sysSIOCGLIFMTU = -0x3f879686
+ sysSIOCGLIFNETMASK = -0x3f879683
+ sysSIOCGLIFMETRIC = -0x3f879681
+ sysSIOCGLIFNUM = -0x3ff3967e
+ sysSIOCGLIFINDEX = -0x3f87967b
+ sysSIOCGLIFSUBNET = -0x3f879676
+ sysSIOCGLIFLNKINFO = -0x3f879674
+ sysSIOCGLIFCONF = -0x3fef965b
+ sysSIOCGLIFHWADDR = -0x3f879640
+)
+
+const (
+ sysIFF_UP = 0x1
+ sysIFF_BROADCAST = 0x2
+ sysIFF_DEBUG = 0x4
+ sysIFF_LOOPBACK = 0x8
+ sysIFF_POINTOPOINT = 0x10
+ sysIFF_NOTRAILERS = 0x20
+ sysIFF_RUNNING = 0x40
+ sysIFF_NOARP = 0x80
+ sysIFF_PROMISC = 0x100
+ sysIFF_ALLMULTI = 0x200
+ sysIFF_INTELLIGENT = 0x400
+ sysIFF_MULTICAST = 0x800
+ sysIFF_MULTI_BCAST = 0x1000
+ sysIFF_UNNUMBERED = 0x2000
+ sysIFF_PRIVATE = 0x8000
+)
+
+const (
+ sizeofLifnum = 0xc
+ sizeofLifreq = 0x178
+ sizeofLifconf = 0x18
+ sizeofLifIfinfoReq = 0x10
+)
+
+type sysLifnum struct {
+ Family uint16
+ Pad_cgo_0 [2]byte
+ Flags int32
+ Count int32
+}
+
+type lifreq struct {
+ Name [32]int8
+ Lifru1 [4]byte
+ Type uint32
+ Lifru [336]byte
+}
+
+type lifconf struct {
+ Family uint16
+ Pad_cgo_0 [2]byte
+ Flags int32
+ Len int32
+ Pad_cgo_1 [4]byte
+ Lifcu [8]byte
+}
+
+type lifIfinfoReq struct {
+ Maxhops uint8
+ Pad_cgo_0 [3]byte
+ Reachtime uint32
+ Reachretrans uint32
+ Maxmtu uint32
+}
+
+const (
+ sysIFT_IPV4 = 0xc8
+ sysIFT_IPV6 = 0xc9
+ sysIFT_6TO4 = 0xca
+)
diff --git a/src/vendor/golang_org/x/net/route/address.go b/src/vendor/golang_org/x/net/route/address.go
index 206a837..a56909c 100644
--- a/src/vendor/golang_org/x/net/route/address.go
+++ b/src/vendor/golang_org/x/net/route/address.go
@@ -234,7 +234,11 @@ func parseAddrs(attrs uint, fn func(int, []byte) (int, Addr, error), b []byte) (
return nil, err
}
as[i] = a
- b = b[roundup(int(b[0])):]
+ l := roundup(int(b[0]))
+ if len(b) < l {
+ return nil, errMessageTooShort
+ }
+ b = b[l:]
case sysAF_INET, sysAF_INET6:
af = int(b[1])
a, err := parseInetAddr(af, b)
@@ -242,7 +246,11 @@ func parseAddrs(attrs uint, fn func(int, []byte) (int, Addr, error), b []byte) (
return nil, err
}
as[i] = a
- b = b[roundup(int(b[0])):]
+ l := roundup(int(b[0]))
+ if len(b) < l {
+ return nil, errMessageTooShort
+ }
+ b = b[l:]
default:
l, a, err := fn(af, b)
if err != nil {
@@ -262,7 +270,11 @@ func parseAddrs(attrs uint, fn func(int, []byte) (int, Addr, error), b []byte) (
return nil, err
}
as[i] = a
- b = b[roundup(int(b[0])):]
+ l := roundup(int(b[0]))
+ if len(b) < l {
+ return nil, errMessageTooShort
+ }
+ b = b[l:]
}
}
return as[:], nil
diff --git a/src/vendor/golang_org/x/net/route/interface_freebsd.go b/src/vendor/golang_org/x/net/route/interface_freebsd.go
index c830539..9f6f50c 100644
--- a/src/vendor/golang_org/x/net/route/interface_freebsd.go
+++ b/src/vendor/golang_org/x/net/route/interface_freebsd.go
@@ -13,12 +13,12 @@ func (w *wireFormat) parseInterfaceMessage(typ RIBType, b []byte) (Message, erro
extOff = int(nativeEndian.Uint16(b[18:20]))
bodyOff = int(nativeEndian.Uint16(b[16:18]))
} else {
- if len(b) < w.bodyOff {
- return nil, errMessageTooShort
- }
extOff = w.extOff
bodyOff = w.bodyOff
}
+ if len(b) < extOff || len(b) < bodyOff {
+ return nil, errInvalidMessage
+ }
l := int(nativeEndian.Uint16(b[:2]))
if len(b) < l {
return nil, errInvalidMessage
@@ -53,11 +53,11 @@ func (w *wireFormat) parseInterfaceAddrMessage(typ RIBType, b []byte) (Message,
}
bodyOff = int(nativeEndian.Uint16(b[16:18]))
} else {
- if len(b) < w.bodyOff {
- return nil, errMessageTooShort
- }
bodyOff = w.bodyOff
}
+ if len(b) < bodyOff {
+ return nil, errInvalidMessage
+ }
l := int(nativeEndian.Uint16(b[:2]))
if len(b) < l {
return nil, errInvalidMessage
diff --git a/src/vendor/golang_org/x/net/route/interface_openbsd.go b/src/vendor/golang_org/x/net/route/interface_openbsd.go
index 24451d8..e4a143c 100644
--- a/src/vendor/golang_org/x/net/route/interface_openbsd.go
+++ b/src/vendor/golang_org/x/net/route/interface_openbsd.go
@@ -24,7 +24,11 @@ func (*wireFormat) parseInterfaceMessage(_ RIBType, b []byte) (Message, error) {
Addrs: make([]Addr, sysRTAX_MAX),
raw: b[:l],
}
- a, err := parseLinkAddr(b[int(nativeEndian.Uint16(b[4:6])):])
+ ll := int(nativeEndian.Uint16(b[4:6]))
+ if len(b) < ll {
+ return nil, errInvalidMessage
+ }
+ a, err := parseLinkAddr(b[ll:])
if err != nil {
return nil, err
}
@@ -42,6 +46,9 @@ func (*wireFormat) parseInterfaceAddrMessage(_ RIBType, b []byte) (Message, erro
return nil, errInvalidMessage
}
bodyOff := int(nativeEndian.Uint16(b[4:6]))
+ if len(b) < bodyOff {
+ return nil, errInvalidMessage
+ }
m := &InterfaceAddrMessage{
Version: int(b[2]),
Type: int(b[3]),
diff --git a/src/vendor/golang_org/x/net/route/message.go b/src/vendor/golang_org/x/net/route/message.go
index 27cbf6b..d7ae0eb 100644
--- a/src/vendor/golang_org/x/net/route/message.go
+++ b/src/vendor/golang_org/x/net/route/message.go
@@ -42,6 +42,12 @@ func ParseRIB(typ RIBType, b []byte) ([]Message, error) {
for len(b) > 4 {
nmsgs++
l := int(nativeEndian.Uint16(b[:2]))
+ if l == 0 {
+ return nil, errInvalidMessage
+ }
+ if len(b) < l {
+ return nil, errMessageTooShort
+ }
if b[2] != sysRTM_VERSION {
b = b[l:]
continue
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 a1263d8..c0c7c57 100644
--- a/src/vendor/golang_org/x/net/route/message_test.go
+++ b/src/vendor/golang_org/x/net/route/message_test.go
@@ -93,3 +93,26 @@ func TestMonitorAndParseRIB(t *testing.T) {
time.Sleep(200 * time.Millisecond)
}
}
+
+func TestParseRIBWithFuzz(t *testing.T) {
+ for _, fuzz := range []string{
+ "0\x00\x05\x050000000000000000" +
+ "00000000000000000000" +
+ "00000000000000000000" +
+ "00000000000000000000" +
+ "0000000000000\x02000000" +
+ "00000000",
+ "\x02\x00\x05\f0000000000000000" +
+ "0\x0200000000000000",
+ "\x02\x00\x05\x100000000000000\x1200" +
+ "0\x00\xff\x00",
+ "\x02\x00\x05\f0000000000000000" +
+ "0\x12000\x00\x02\x0000",
+ "\x00\x00\x00\x01\x00",
+ "00000",
+ } {
+ for typ := RIBType(0); typ < 256; typ++ {
+ ParseRIB(typ, []byte(fuzz))
+ }
+ }
+}
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 b07862f..76eae40 100644
--- a/src/vendor/golang_org/x/net/route/route_openbsd.go
+++ b/src/vendor/golang_org/x/net/route/route_openbsd.go
@@ -19,7 +19,11 @@ func (*wireFormat) parseRouteMessage(_ RIBType, b []byte) (Message, error) {
Index: int(nativeEndian.Uint16(b[6:8])),
raw: b[:l],
}
- as, err := parseAddrs(uint(nativeEndian.Uint32(b[12:16])), parseKernelInetAddr, b[int(nativeEndian.Uint16(b[4:6])):])
+ ll := int(nativeEndian.Uint16(b[4:6]))
+ if len(b) < ll {
+ return nil, errInvalidMessage
+ }
+ 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/route_test.go b/src/vendor/golang_org/x/net/route/route_test.go
index 99f57b7..63fd8c5 100644
--- a/src/vendor/golang_org/x/net/route/route_test.go
+++ b/src/vendor/golang_org/x/net/route/route_test.go
@@ -235,7 +235,7 @@ func (a *LinkAddr) String() string {
return fmt.Sprintf("(%v %d %s %s)", addrFamily(a.Family()), a.Index, name, lla)
}
-func (a Inet4Addr) String() string {
+func (a *Inet4Addr) String() string {
return fmt.Sprintf("(%v %v)", addrFamily(a.Family()), ipAddr(a.IP[:]))
}
@@ -325,6 +325,7 @@ func fetchAndParseRIB(af int, typ RIBType) ([]Message, error) {
return ms, nil
}
+// propVirtual is a proprietary virtual network interface.
type propVirtual struct {
name string
addr, mask string
@@ -332,18 +333,18 @@ type propVirtual struct {
teardownCmds []*exec.Cmd
}
-func (ti *propVirtual) setup() error {
- for _, cmd := range ti.setupCmds {
+func (pv *propVirtual) setup() error {
+ for _, cmd := range pv.setupCmds {
if err := cmd.Run(); err != nil {
- ti.teardown()
+ pv.teardown()
return err
}
}
return nil
}
-func (ti *propVirtual) teardown() error {
- for _, cmd := range ti.teardownCmds {
+func (pv *propVirtual) teardown() error {
+ for _, cmd := range pv.teardownCmds {
if err := cmd.Run(); err != nil {
return err
}
@@ -351,35 +352,35 @@ func (ti *propVirtual) teardown() error {
return nil
}
-func (ti *propVirtual) configure(suffix int) error {
+func (pv *propVirtual) configure(suffix int) error {
if runtime.GOOS == "openbsd" {
- ti.name = fmt.Sprintf("vether%d", suffix)
+ pv.name = fmt.Sprintf("vether%d", suffix)
} else {
- ti.name = fmt.Sprintf("vlan%d", suffix)
+ pv.name = fmt.Sprintf("vlan%d", suffix)
}
xname, err := exec.LookPath("ifconfig")
if err != nil {
return err
}
- ti.setupCmds = append(ti.setupCmds, &exec.Cmd{
+ pv.setupCmds = append(pv.setupCmds, &exec.Cmd{
Path: xname,
- Args: []string{"ifconfig", ti.name, "create"},
+ Args: []string{"ifconfig", pv.name, "create"},
})
if runtime.GOOS == "netbsd" {
// NetBSD requires an underlying dot1Q-capable network
// interface.
- ti.setupCmds = append(ti.setupCmds, &exec.Cmd{
+ pv.setupCmds = append(pv.setupCmds, &exec.Cmd{
Path: xname,
- Args: []string{"ifconfig", ti.name, "vlan", fmt.Sprintf("%d", suffix&0xfff), "vlanif", "wm0"},
+ Args: []string{"ifconfig", pv.name, "vlan", fmt.Sprintf("%d", suffix&0xfff), "vlanif", "wm0"},
})
}
- ti.setupCmds = append(ti.setupCmds, &exec.Cmd{
+ pv.setupCmds = append(pv.setupCmds, &exec.Cmd{
Path: xname,
- Args: []string{"ifconfig", ti.name, "inet", ti.addr, "netmask", ti.mask},
+ Args: []string{"ifconfig", pv.name, "inet", pv.addr, "netmask", pv.mask},
})
- ti.teardownCmds = append(ti.teardownCmds, &exec.Cmd{
+ pv.teardownCmds = append(pv.teardownCmds, &exec.Cmd{
Path: xname,
- Args: []string{"ifconfig", ti.name, "destroy"},
+ Args: []string{"ifconfig", pv.name, "destroy"},
})
return nil
}
diff --git a/src/vendor/golang_org/x/text/transform/transform.go b/src/vendor/golang_org/x/text/transform/transform.go
new file mode 100644
index 0000000..fe47b9b
--- /dev/null
+++ b/src/vendor/golang_org/x/text/transform/transform.go
@@ -0,0 +1,705 @@
+// Copyright 2013 The Go Authors. 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 provides reader and writer wrappers that transform the
+// 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"
+
+import (
+ "bytes"
+ "errors"
+ "io"
+ "unicode/utf8"
+)
+
+var (
+ // ErrShortDst means that the destination buffer was too short to
+ // receive all of the transformed bytes.
+ ErrShortDst = errors.New("transform: short destination buffer")
+
+ // ErrShortSrc means that the source buffer has insufficient data to
+ // complete the transformation.
+ ErrShortSrc = errors.New("transform: short source buffer")
+
+ // ErrEndOfSpan means that the input and output (the transformed input)
+ // are not identical.
+ ErrEndOfSpan = errors.New("transform: input and output are not identical")
+
+ // errInconsistentByteCount means that Transform returned success (nil
+ // error) but also returned nSrc inconsistent with the src argument.
+ errInconsistentByteCount = errors.New("transform: inconsistent byte count returned")
+
+ // errShortInternal means that an internal buffer is not large enough
+ // to make progress and the Transform operation must be aborted.
+ errShortInternal = errors.New("transform: short internal buffer")
+)
+
+// Transformer transforms bytes.
+type Transformer interface {
+ // Transform writes to dst the transformed bytes read from src, and
+ // returns the number of dst bytes written and src bytes read. The
+ // atEOF argument tells whether src represents the last bytes of the
+ // input.
+ //
+ // Callers should always process the nDst bytes produced and account
+ // for the nSrc bytes consumed before considering the error err.
+ //
+ // A nil error means that all of the transformed bytes (whether freshly
+ // transformed from src or left over from previous Transform calls)
+ // were written to dst. A nil error can be returned regardless of
+ // whether atEOF is true. If err is nil then nSrc must equal len(src);
+ // the converse is not necessarily true.
+ //
+ // ErrShortDst means that dst was too short to receive all of the
+ // transformed bytes. ErrShortSrc means that src had insufficient data
+ // to complete the transformation. If both conditions apply, then
+ // either error may be returned. Other than the error conditions listed
+ // here, implementations are free to report other errors that arise.
+ Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error)
+
+ // Reset resets the state and allows a Transformer to be reused.
+ Reset()
+}
+
+// SpanningTransformer extends the Transformer interface with a Span method
+// that determines how much of the input already conforms to the Transformer.
+type SpanningTransformer interface {
+ Transformer
+
+ // Span returns a position in src such that transforming src[:n] results in
+ // identical output src[:n] for these bytes. It does not necessarily return
+ // the largest such n. The atEOF argument tells whether src represents the
+ // last bytes of the input.
+ //
+ // Callers should always account for the n bytes consumed before
+ // considering the error err.
+ //
+ // A nil error means that all input bytes are known to be identical to the
+ // output produced by the Transformer. A nil error can be be returned
+ // regardless of whether atEOF is true. If err is nil, then then n must
+ // equal len(src); the converse is not necessarily true.
+ //
+ // ErrEndOfSpan means that the Transformer output may differ from the
+ // input after n bytes. Note that n may be len(src), meaning that the output
+ // would contain additional bytes after otherwise identical output.
+ // ErrShortSrc means that src had insufficient data to determine whether the
+ // remaining bytes would change. Other than the error conditions listed
+ // here, implementations are free to report other errors that arise.
+ //
+ // Calling Span can modify the Transformer state as a side effect. In
+ // effect, it does the transformation just as calling Transform would, only
+ // without copying to a destination buffer and only up to a point it can
+ // determine the input and output bytes are the same. This is obviously more
+ // limited than calling Transform, but can be more efficient in terms of
+ // copying and allocating buffers. Calls to Span and Transform may be
+ // interleaved.
+ Span(src []byte, atEOF bool) (n int, err error)
+}
+
+// NopResetter can be embedded by implementations of Transformer to add a nop
+// Reset method.
+type NopResetter struct{}
+
+// Reset implements the Reset method of the Transformer interface.
+func (NopResetter) Reset() {}
+
+// Reader wraps another io.Reader by transforming the bytes read.
+type Reader struct {
+ r io.Reader
+ t Transformer
+ err error
+
+ // dst[dst0:dst1] contains bytes that have been transformed by t but
+ // not yet copied out via Read.
+ dst []byte
+ dst0, dst1 int
+
+ // src[src0:src1] contains bytes that have been read from r but not
+ // yet transformed through t.
+ src []byte
+ src0, src1 int
+
+ // transformComplete is whether the transformation is complete,
+ // regardless of whether or not it was successful.
+ transformComplete bool
+}
+
+const defaultBufSize = 4096
+
+// NewReader returns a new Reader that wraps r by transforming the bytes read
+// via t. It calls Reset on t.
+func NewReader(r io.Reader, t Transformer) *Reader {
+ t.Reset()
+ return &Reader{
+ r: r,
+ t: t,
+ dst: make([]byte, defaultBufSize),
+ src: make([]byte, defaultBufSize),
+ }
+}
+
+// Read implements the io.Reader interface.
+func (r *Reader) Read(p []byte) (int, error) {
+ n, err := 0, error(nil)
+ for {
+ // Copy out any transformed bytes and return the final error if we are done.
+ if r.dst0 != r.dst1 {
+ n = copy(p, r.dst[r.dst0:r.dst1])
+ r.dst0 += n
+ if r.dst0 == r.dst1 && r.transformComplete {
+ return n, r.err
+ }
+ return n, nil
+ } else if r.transformComplete {
+ return 0, r.err
+ }
+
+ // Try to transform some source bytes, or to flush the transformer if we
+ // are out of source bytes. We do this even if r.r.Read returned an error.
+ // As the io.Reader documentation says, "process the n > 0 bytes returned
+ // before considering the error".
+ if r.src0 != r.src1 || r.err != nil {
+ r.dst0 = 0
+ r.dst1, n, err = r.t.Transform(r.dst, r.src[r.src0:r.src1], r.err == io.EOF)
+ r.src0 += n
+
+ switch {
+ case err == nil:
+ if r.src0 != r.src1 {
+ r.err = errInconsistentByteCount
+ }
+ // The Transform call was successful; we are complete if we
+ // cannot read more bytes into src.
+ r.transformComplete = r.err != nil
+ continue
+ case err == ErrShortDst && (r.dst1 != 0 || n != 0):
+ // Make room in dst by copying out, and try again.
+ continue
+ case err == ErrShortSrc && r.src1-r.src0 != len(r.src) && r.err == nil:
+ // Read more bytes into src via the code below, and try again.
+ default:
+ r.transformComplete = true
+ // The reader error (r.err) takes precedence over the
+ // transformer error (err) unless r.err is nil or io.EOF.
+ if r.err == nil || r.err == io.EOF {
+ r.err = err
+ }
+ continue
+ }
+ }
+
+ // Move any untransformed source bytes to the start of the buffer
+ // and read more bytes.
+ if r.src0 != 0 {
+ r.src0, r.src1 = 0, copy(r.src, r.src[r.src0:r.src1])
+ }
+ n, r.err = r.r.Read(r.src[r.src1:])
+ r.src1 += n
+ }
+}
+
+// TODO: implement ReadByte (and ReadRune??).
+
+// Writer wraps another io.Writer by transforming the bytes read.
+// The user needs to call Close to flush unwritten bytes that may
+// be buffered.
+type Writer struct {
+ w io.Writer
+ t Transformer
+ dst []byte
+
+ // src[:n] contains bytes that have not yet passed through t.
+ src []byte
+ n int
+}
+
+// NewWriter returns a new Writer that wraps w by transforming the bytes written
+// via t. It calls Reset on t.
+func NewWriter(w io.Writer, t Transformer) *Writer {
+ t.Reset()
+ return &Writer{
+ w: w,
+ t: t,
+ dst: make([]byte, defaultBufSize),
+ src: make([]byte, defaultBufSize),
+ }
+}
+
+// Write implements the io.Writer interface. If there are not enough
+// bytes available to complete a Transform, the bytes will be buffered
+// for the next write. Call Close to convert the remaining bytes.
+func (w *Writer) Write(data []byte) (n int, err error) {
+ src := data
+ if w.n > 0 {
+ // Append bytes from data to the last remainder.
+ // TODO: limit the amount copied on first try.
+ n = copy(w.src[w.n:], data)
+ w.n += n
+ src = w.src[:w.n]
+ }
+ for {
+ nDst, nSrc, err := w.t.Transform(w.dst, src, false)
+ if _, werr := w.w.Write(w.dst[:nDst]); werr != nil {
+ return n, werr
+ }
+ src = src[nSrc:]
+ if w.n == 0 {
+ n += nSrc
+ } else if len(src) <= n {
+ // Enough bytes from w.src have been consumed. We make src point
+ // to data instead to reduce the copying.
+ w.n = 0
+ n -= len(src)
+ src = data[n:]
+ if n < len(data) && (err == nil || err == ErrShortSrc) {
+ continue
+ }
+ }
+ switch err {
+ case ErrShortDst:
+ // This error is okay as long as we are making progress.
+ if nDst > 0 || nSrc > 0 {
+ continue
+ }
+ case ErrShortSrc:
+ if len(src) < len(w.src) {
+ m := copy(w.src, src)
+ // If w.n > 0, bytes from data were already copied to w.src and n
+ // was already set to the number of bytes consumed.
+ if w.n == 0 {
+ n += m
+ }
+ w.n = m
+ err = nil
+ } else if nDst > 0 || nSrc > 0 {
+ // Not enough buffer to store the remainder. Keep processing as
+ // long as there is progress. Without this case, transforms that
+ // require a lookahead larger than the buffer may result in an
+ // error. This is not something one may expect to be common in
+ // practice, but it may occur when buffers are set to small
+ // sizes during testing.
+ continue
+ }
+ case nil:
+ if w.n > 0 {
+ err = errInconsistentByteCount
+ }
+ }
+ return n, err
+ }
+}
+
+// Close implements the io.Closer interface.
+func (w *Writer) Close() error {
+ src := w.src[:w.n]
+ for {
+ nDst, nSrc, err := w.t.Transform(w.dst, src, true)
+ if _, werr := w.w.Write(w.dst[:nDst]); werr != nil {
+ return werr
+ }
+ if err != ErrShortDst {
+ return err
+ }
+ src = src[nSrc:]
+ }
+}
+
+type nop struct{ NopResetter }
+
+func (nop) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
+ n := copy(dst, src)
+ if n < len(src) {
+ err = ErrShortDst
+ }
+ return n, n, err
+}
+
+func (nop) Span(src []byte, atEOF bool) (n int, err error) {
+ return len(src), nil
+}
+
+type discard struct{ NopResetter }
+
+func (discard) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
+ return 0, len(src), nil
+}
+
+var (
+ // Discard is a Transformer for which all Transform calls succeed
+ // by consuming all bytes and writing nothing.
+ Discard Transformer = discard{}
+
+ // Nop is a SpanningTransformer that copies src to dst.
+ Nop SpanningTransformer = nop{}
+)
+
+// chain is a sequence of links. A chain with N Transformers has N+1 links and
+// N+1 buffers. Of those N+1 buffers, the first and last are the src and dst
+// buffers given to chain.Transform and the middle N-1 buffers are intermediate
+// buffers owned by the chain. The i'th link transforms bytes from the i'th
+// buffer chain.link[i].b at read offset chain.link[i].p to the i+1'th buffer
+// chain.link[i+1].b at write offset chain.link[i+1].n, for i in [0, N).
+type chain struct {
+ link []link
+ err error
+ // errStart is the index at which the error occurred plus 1. Processing
+ // errStart at this level at the next call to Transform. As long as
+ // errStart > 0, chain will not consume any more source bytes.
+ errStart int
+}
+
+func (c *chain) fatalError(errIndex int, err error) {
+ if i := errIndex + 1; i > c.errStart {
+ c.errStart = i
+ c.err = err
+ }
+}
+
+type link struct {
+ t Transformer
+ // b[p:n] holds the bytes to be transformed by t.
+ b []byte
+ p int
+ n int
+}
+
+func (l *link) src() []byte {
+ return l.b[l.p:l.n]
+}
+
+func (l *link) dst() []byte {
+ return l.b[l.n:]
+}
+
+// Chain returns a Transformer that applies t in sequence.
+func Chain(t ...Transformer) Transformer {
+ if len(t) == 0 {
+ return nop{}
+ }
+ c := &chain{link: make([]link, len(t)+1)}
+ for i, tt := range t {
+ c.link[i].t = tt
+ }
+ // Allocate intermediate buffers.
+ b := make([][defaultBufSize]byte, len(t)-1)
+ for i := range b {
+ c.link[i+1].b = b[i][:]
+ }
+ return c
+}
+
+// Reset resets the state of Chain. It calls Reset on all the Transformers.
+func (c *chain) Reset() {
+ for i, l := range c.link {
+ if l.t != nil {
+ l.t.Reset()
+ }
+ c.link[i].p, c.link[i].n = 0, 0
+ }
+}
+
+// TODO: make chain use Span (is going to be fun to implement!)
+
+// Transform applies the transformers of c in sequence.
+func (c *chain) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
+ // Set up src and dst in the chain.
+ srcL := &c.link[0]
+ dstL := &c.link[len(c.link)-1]
+ srcL.b, srcL.p, srcL.n = src, 0, len(src)
+ dstL.b, dstL.n = dst, 0
+ var lastFull, needProgress bool // for detecting progress
+
+ // i is the index of the next Transformer to apply, for i in [low, high].
+ // low is the lowest index for which c.link[low] may still produce bytes.
+ // high is the highest index for which c.link[high] has a Transformer.
+ // The error returned by Transform determines whether to increase or
+ // decrease i. We try to completely fill a buffer before converting it.
+ for low, i, high := c.errStart, c.errStart, len(c.link)-2; low <= i && i <= high; {
+ in, out := &c.link[i], &c.link[i+1]
+ nDst, nSrc, err0 := in.t.Transform(out.dst(), in.src(), atEOF && low == i)
+ out.n += nDst
+ in.p += nSrc
+ if i > 0 && in.p == in.n {
+ in.p, in.n = 0, 0
+ }
+ needProgress, lastFull = lastFull, false
+ switch err0 {
+ case ErrShortDst:
+ // Process the destination buffer next. Return if we are already
+ // at the high index.
+ if i == high {
+ return dstL.n, srcL.p, ErrShortDst
+ }
+ if out.n != 0 {
+ i++
+ // If the Transformer at the next index is not able to process any
+ // source bytes there is nothing that can be done to make progress
+ // and the bytes will remain unprocessed. lastFull is used to
+ // detect this and break out of the loop with a fatal error.
+ lastFull = true
+ continue
+ }
+ // The destination buffer was too small, but is completely empty.
+ // Return a fatal error as this transformation can never complete.
+ c.fatalError(i, errShortInternal)
+ case ErrShortSrc:
+ if i == 0 {
+ // Save ErrShortSrc in err. All other errors take precedence.
+ err = ErrShortSrc
+ break
+ }
+ // Source bytes were depleted before filling up the destination buffer.
+ // Verify we made some progress, move the remaining bytes to the errStart
+ // and try to get more source bytes.
+ if needProgress && nSrc == 0 || in.n-in.p == len(in.b) {
+ // There were not enough source bytes to proceed while the source
+ // buffer cannot hold any more bytes. Return a fatal error as this
+ // transformation can never complete.
+ c.fatalError(i, errShortInternal)
+ break
+ }
+ // in.b is an internal buffer and we can make progress.
+ in.p, in.n = 0, copy(in.b, in.src())
+ fallthrough
+ case nil:
+ // if i == low, we have depleted the bytes at index i or any lower levels.
+ // In that case we increase low and i. In all other cases we decrease i to
+ // fetch more bytes before proceeding to the next index.
+ if i > low {
+ i--
+ continue
+ }
+ default:
+ c.fatalError(i, err0)
+ }
+ // Exhausted level low or fatal error: increase low and continue
+ // to process the bytes accepted so far.
+ i++
+ low = i
+ }
+
+ // If c.errStart > 0, this means we found a fatal error. We will clear
+ // all upstream buffers. At this point, no more progress can be made
+ // downstream, as Transform would have bailed while handling ErrShortDst.
+ if c.errStart > 0 {
+ for i := 1; i < c.errStart; i++ {
+ c.link[i].p, c.link[i].n = 0, 0
+ }
+ err, c.errStart, c.err = c.err, 0, nil
+ }
+ return dstL.n, srcL.p, err
+}
+
+// Deprecated: use runes.Remove instead.
+func RemoveFunc(f func(r rune) bool) Transformer {
+ return removeF(f)
+}
+
+type removeF func(r rune) bool
+
+func (removeF) Reset() {}
+
+// Transform implements the Transformer interface.
+func (t removeF) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
+ for r, sz := rune(0), 0; len(src) > 0; src = src[sz:] {
+
+ if r = rune(src[0]); r < utf8.RuneSelf {
+ sz = 1
+ } else {
+ r, sz = utf8.DecodeRune(src)
+
+ if sz == 1 {
+ // Invalid rune.
+ if !atEOF && !utf8.FullRune(src) {
+ err = ErrShortSrc
+ break
+ }
+ // We replace illegal bytes with RuneError. Not doing so might
+ // otherwise turn a sequence of invalid UTF-8 into valid UTF-8.
+ // The resulting byte sequence may subsequently contain runes
+ // for which t(r) is true that were passed unnoticed.
+ if !t(r) {
+ if nDst+3 > len(dst) {
+ err = ErrShortDst
+ break
+ }
+ nDst += copy(dst[nDst:], "\uFFFD")
+ }
+ nSrc++
+ continue
+ }
+ }
+
+ if !t(r) {
+ if nDst+sz > len(dst) {
+ err = ErrShortDst
+ break
+ }
+ nDst += copy(dst[nDst:], src[:sz])
+ }
+ nSrc += sz
+ }
+ return
+}
+
+// grow returns a new []byte that is longer than b, and copies the first n bytes
+// of b to the start of the new slice.
+func grow(b []byte, n int) []byte {
+ m := len(b)
+ if m <= 32 {
+ m = 64
+ } else if m <= 256 {
+ m *= 2
+ } else {
+ m += m >> 1
+ }
+ buf := make([]byte, m)
+ copy(buf, b[:n])
+ return buf
+}
+
+const initialBufSize = 128
+
+// String returns a string with the result of converting s[:n] using t, where
+// n <= len(s). If err == nil, n will be len(s). It calls Reset on t.
+func String(t Transformer, s string) (result string, n int, err error) {
+ t.Reset()
+ if s == "" {
+ // Fast path for the common case for empty input. Results in about a
+ // 86% reduction of running time for BenchmarkStringLowerEmpty.
+ if _, _, err := t.Transform(nil, nil, true); err == nil {
+ return "", 0, nil
+ }
+ }
+
+ // Allocate only once. Note that both dst and src escape when passed to
+ // Transform.
+ buf := [2 * initialBufSize]byte{}
+ dst := buf[:initialBufSize:initialBufSize]
+ src := buf[initialBufSize : 2*initialBufSize]
+
+ // The input string s is transformed in multiple chunks (starting with a
+ // chunk size of initialBufSize). nDst and nSrc are per-chunk (or
+ // per-Transform-call) indexes, pDst and pSrc are overall indexes.
+ nDst, nSrc := 0, 0
+ pDst, pSrc := 0, 0
+
+ // pPrefix is the length of a common prefix: the first pPrefix bytes of the
+ // result will equal the first pPrefix bytes of s. It is not guaranteed to
+ // be the largest such value, but if pPrefix, len(result) and len(s) are
+ // all equal after the final transform (i.e. calling Transform with atEOF
+ // being true returned nil error) then we don't need to allocate a new
+ // result string.
+ pPrefix := 0
+ for {
+ // Invariant: pDst == pPrefix && pSrc == pPrefix.
+
+ n := copy(src, s[pSrc:])
+ nDst, nSrc, err = t.Transform(dst, src[:n], pSrc+n == len(s))
+ pDst += nDst
+ pSrc += nSrc
+
+ // TODO: let transformers implement an optional Spanner interface, akin
+ // to norm's QuickSpan. This would even allow us to avoid any allocation.
+ if !bytes.Equal(dst[:nDst], src[:nSrc]) {
+ break
+ }
+ pPrefix = pSrc
+ if err == ErrShortDst {
+ // A buffer can only be short if a transformer modifies its input.
+ break
+ } else if err == ErrShortSrc {
+ if nSrc == 0 {
+ // No progress was made.
+ break
+ }
+ // Equal so far and !atEOF, so continue checking.
+ } else if err != nil || pPrefix == len(s) {
+ return string(s[:pPrefix]), pPrefix, err
+ }
+ }
+ // Post-condition: pDst == pPrefix + nDst && pSrc == pPrefix + nSrc.
+
+ // We have transformed the first pSrc bytes of the input s to become pDst
+ // transformed bytes. Those transformed bytes are discontiguous: the first
+ // pPrefix of them equal s[:pPrefix] and the last nDst of them equal
+ // dst[:nDst]. We copy them around, into a new dst buffer if necessary, so
+ // that they become one contiguous slice: dst[:pDst].
+ if pPrefix != 0 {
+ newDst := dst
+ if pDst > len(newDst) {
+ newDst = make([]byte, len(s)+nDst-nSrc)
+ }
+ copy(newDst[pPrefix:pDst], dst[:nDst])
+ copy(newDst[:pPrefix], s[:pPrefix])
+ dst = newDst
+ }
+
+ // Prevent duplicate Transform calls with atEOF being true at the end of
+ // the input. Also return if we have an unrecoverable error.
+ if (err == nil && pSrc == len(s)) ||
+ (err != nil && err != ErrShortDst && err != ErrShortSrc) {
+ return string(dst[:pDst]), pSrc, err
+ }
+
+ // Transform the remaining input, growing dst and src buffers as necessary.
+ for {
+ n := copy(src, s[pSrc:])
+ nDst, nSrc, err := t.Transform(dst[pDst:], src[:n], pSrc+n == len(s))
+ pDst += nDst
+ pSrc += nSrc
+
+ // If we got ErrShortDst or ErrShortSrc, do not grow as long as we can
+ // make progress. This may avoid excessive allocations.
+ if err == ErrShortDst {
+ if nDst == 0 {
+ dst = grow(dst, pDst)
+ }
+ } else if err == ErrShortSrc {
+ if nSrc == 0 {
+ src = grow(src, 0)
+ }
+ } else if err != nil || pSrc == len(s) {
+ return string(dst[:pDst]), pSrc, err
+ }
+ }
+}
+
+// Bytes returns a new byte slice with the result of converting b[:n] using t,
+// where n <= len(b). If err == nil, n will be len(b). It calls Reset on t.
+func Bytes(t Transformer, b []byte) (result []byte, n int, err error) {
+ return doAppend(t, 0, make([]byte, len(b)), b)
+}
+
+// Append appends the result of converting src[:n] using t to dst, where
+// n <= len(src), If err == nil, n will be len(src). It calls Reset on t.
+func Append(t Transformer, dst, src []byte) (result []byte, n int, err error) {
+ if len(dst) == cap(dst) {
+ n := len(src) + len(dst) // It is okay for this to be 0.
+ b := make([]byte, n)
+ dst = b[:copy(b, dst)]
+ }
+ return doAppend(t, len(dst), dst[:cap(dst)], src)
+}
+
+func doAppend(t Transformer, pDst int, dst, src []byte) (result []byte, n int, err error) {
+ t.Reset()
+ pSrc := 0
+ for {
+ nDst, nSrc, err := t.Transform(dst[pDst:], src[pSrc:], true)
+ pDst += nDst
+ pSrc += nSrc
+ if err != ErrShortDst {
+ return dst[:pDst], pSrc, err
+ }
+
+ // Grow the destination buffer, but do not grow as long as we can make
+ // progress. This may avoid excessive allocations.
+ if nDst == 0 {
+ dst = grow(dst, pDst)
+ }
+ }
+}
diff --git a/src/vendor/golang_org/x/text/unicode/norm/composition.go b/src/vendor/golang_org/x/text/unicode/norm/composition.go
new file mode 100644
index 0000000..d17b278
--- /dev/null
+++ b/src/vendor/golang_org/x/text/unicode/norm/composition.go
@@ -0,0 +1,514 @@
+// Copyright 2011 The Go Authors. 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
+
+import "unicode/utf8"
+
+const (
+ maxNonStarters = 30
+ // The maximum number of characters needed for a buffer is
+ // maxNonStarters + 1 for the starter + 1 for the GCJ
+ maxBufferSize = maxNonStarters + 2
+ maxNFCExpansion = 3 // NFC(0x1D160)
+ maxNFKCExpansion = 18 // NFKC(0xFDFA)
+
+ maxByteBufferSize = utf8.UTFMax * maxBufferSize // 128
+)
+
+// ssState is used for reporting the segment state after inserting a rune.
+// It is returned by streamSafe.next.
+type ssState int
+
+const (
+ // Indicates a rune was successfully added to the segment.
+ ssSuccess ssState = iota
+ // Indicates a rune starts a new segment and should not be added.
+ ssStarter
+ // Indicates a rune caused a segment overflow and a CGJ should be inserted.
+ ssOverflow
+)
+
+// streamSafe implements the policy of when a CGJ should be inserted.
+type streamSafe uint8
+
+// mkStreamSafe is a shorthand for declaring a streamSafe var and calling
+// first on it.
+func mkStreamSafe(p Properties) streamSafe {
+ return streamSafe(p.nTrailingNonStarters())
+}
+
+// first inserts the first rune of a segment.
+func (ss *streamSafe) first(p Properties) {
+ if *ss != 0 {
+ panic("!= 0")
+ }
+ *ss = streamSafe(p.nTrailingNonStarters())
+}
+
+// insert returns a ssState value to indicate whether a rune represented by p
+// can be inserted.
+func (ss *streamSafe) next(p Properties) ssState {
+ if *ss > maxNonStarters {
+ panic("streamSafe was not reset")
+ }
+ n := p.nLeadingNonStarters()
+ if *ss += streamSafe(n); *ss > maxNonStarters {
+ *ss = 0
+ return ssOverflow
+ }
+ // The Stream-Safe Text Processing prescribes that the counting can stop
+ // as soon as a starter is encountered. However, there are some starters,
+ // like Jamo V and T, that can combine with other runes, leaving their
+ // successive non-starters appended to the previous, possibly causing an
+ // overflow. We will therefore consider any rune with a non-zero nLead to
+ // be a non-starter. Note that it always hold that if nLead > 0 then
+ // nLead == nTrail.
+ if n == 0 {
+ *ss = 0
+ return ssStarter
+ }
+ return ssSuccess
+}
+
+// backwards is used for checking for overflow and segment starts
+// when traversing a string backwards. Users do not need to call first
+// for the first rune. The state of the streamSafe retains the count of
+// the non-starters loaded.
+func (ss *streamSafe) backwards(p Properties) ssState {
+ if *ss > maxNonStarters {
+ panic("streamSafe was not reset")
+ }
+ c := *ss + streamSafe(p.nTrailingNonStarters())
+ if c > maxNonStarters {
+ return ssOverflow
+ }
+ *ss = c
+ if p.nLeadingNonStarters() == 0 {
+ return ssStarter
+ }
+ return ssSuccess
+}
+
+func (ss streamSafe) isMax() bool {
+ return ss == maxNonStarters
+}
+
+// GraphemeJoiner is inserted after maxNonStarters non-starter runes.
+const GraphemeJoiner = "\u034F"
+
+// reorderBuffer is used to normalize a single segment. Characters inserted with
+// insert are decomposed and reordered based on CCC. The compose method can
+// be used to recombine characters. Note that the byte buffer does not hold
+// the UTF-8 characters in order. Only the rune array is maintained in sorted
+// order. flush writes the resulting segment to a byte array.
+type reorderBuffer struct {
+ rune [maxBufferSize]Properties // Per character info.
+ byte [maxByteBufferSize]byte // UTF-8 buffer. Referenced by runeInfo.pos.
+ nbyte uint8 // Number or bytes.
+ ss streamSafe // For limiting length of non-starter sequence.
+ nrune int // Number of runeInfos.
+ f formInfo
+
+ src input
+ nsrc int
+ tmpBytes input
+
+ out []byte
+ flushF func(*reorderBuffer) bool
+}
+
+func (rb *reorderBuffer) init(f Form, src []byte) {
+ rb.f = *formTable[f]
+ rb.src.setBytes(src)
+ rb.nsrc = len(src)
+ rb.ss = 0
+}
+
+func (rb *reorderBuffer) initString(f Form, src string) {
+ rb.f = *formTable[f]
+ rb.src.setString(src)
+ rb.nsrc = len(src)
+ rb.ss = 0
+}
+
+func (rb *reorderBuffer) setFlusher(out []byte, f func(*reorderBuffer) bool) {
+ rb.out = out
+ rb.flushF = f
+}
+
+// reset discards all characters from the buffer.
+func (rb *reorderBuffer) reset() {
+ rb.nrune = 0
+ rb.nbyte = 0
+ rb.ss = 0
+}
+
+func (rb *reorderBuffer) doFlush() bool {
+ if rb.f.composing {
+ rb.compose()
+ }
+ res := rb.flushF(rb)
+ rb.reset()
+ return res
+}
+
+// appendFlush appends the normalized segment to rb.out.
+func appendFlush(rb *reorderBuffer) bool {
+ for i := 0; i < rb.nrune; i++ {
+ start := rb.rune[i].pos
+ end := start + rb.rune[i].size
+ rb.out = append(rb.out, rb.byte[start:end]...)
+ }
+ return true
+}
+
+// flush appends the normalized segment to out and resets rb.
+func (rb *reorderBuffer) flush(out []byte) []byte {
+ for i := 0; i < rb.nrune; i++ {
+ start := rb.rune[i].pos
+ end := start + rb.rune[i].size
+ out = append(out, rb.byte[start:end]...)
+ }
+ rb.reset()
+ return out
+}
+
+// flushCopy copies the normalized segment to buf and resets rb.
+// It returns the number of bytes written to buf.
+func (rb *reorderBuffer) flushCopy(buf []byte) int {
+ p := 0
+ for i := 0; i < rb.nrune; i++ {
+ runep := rb.rune[i]
+ p += copy(buf[p:], rb.byte[runep.pos:runep.pos+runep.size])
+ }
+ rb.reset()
+ return p
+}
+
+// insertOrdered inserts a rune in the buffer, ordered by Canonical Combining Class.
+// It returns false if the buffer is not large enough to hold the rune.
+// It is used internally by insert and insertString only.
+func (rb *reorderBuffer) insertOrdered(info Properties) {
+ n := rb.nrune
+ b := rb.rune[:]
+ cc := info.ccc
+ if cc > 0 {
+ // Find insertion position + move elements to make room.
+ for ; n > 0; n-- {
+ if b[n-1].ccc <= cc {
+ break
+ }
+ b[n] = b[n-1]
+ }
+ }
+ rb.nrune += 1
+ pos := uint8(rb.nbyte)
+ rb.nbyte += utf8.UTFMax
+ info.pos = pos
+ b[n] = info
+}
+
+// insertErr is an error code returned by insert. Using this type instead
+// of error improves performance up to 20% for many of the benchmarks.
+type insertErr int
+
+const (
+ iSuccess insertErr = -iota
+ iShortDst
+ iShortSrc
+)
+
+// insertFlush inserts the given rune in the buffer ordered by CCC.
+// If a decomposition with multiple segments are encountered, they leading
+// ones are flushed.
+// It returns a non-zero error code if the rune was not inserted.
+func (rb *reorderBuffer) insertFlush(src input, i int, info Properties) insertErr {
+ if rune := src.hangul(i); rune != 0 {
+ rb.decomposeHangul(rune)
+ return iSuccess
+ }
+ if info.hasDecomposition() {
+ return rb.insertDecomposed(info.Decomposition())
+ }
+ rb.insertSingle(src, i, info)
+ return iSuccess
+}
+
+// insertUnsafe inserts the given rune in the buffer ordered by CCC.
+// It is assumed there is sufficient space to hold the runes. It is the
+// responsibility of the caller to ensure this. This can be done by checking
+// the state returned by the streamSafe type.
+func (rb *reorderBuffer) insertUnsafe(src input, i int, info Properties) {
+ if rune := src.hangul(i); rune != 0 {
+ rb.decomposeHangul(rune)
+ }
+ if info.hasDecomposition() {
+ // TODO: inline.
+ rb.insertDecomposed(info.Decomposition())
+ } else {
+ rb.insertSingle(src, i, info)
+ }
+}
+
+// insertDecomposed inserts an entry in to the reorderBuffer for each rune
+// in dcomp. dcomp must be a sequence of decomposed UTF-8-encoded runes.
+// It flushes the buffer on each new segment start.
+func (rb *reorderBuffer) insertDecomposed(dcomp []byte) insertErr {
+ rb.tmpBytes.setBytes(dcomp)
+ for i := 0; i < len(dcomp); {
+ info := rb.f.info(rb.tmpBytes, i)
+ if info.BoundaryBefore() && rb.nrune > 0 && !rb.doFlush() {
+ return iShortDst
+ }
+ i += copy(rb.byte[rb.nbyte:], dcomp[i:i+int(info.size)])
+ rb.insertOrdered(info)
+ }
+ return iSuccess
+}
+
+// insertSingle inserts an entry in the reorderBuffer for the rune at
+// position i. info is the runeInfo for the rune at position i.
+func (rb *reorderBuffer) insertSingle(src input, i int, info Properties) {
+ src.copySlice(rb.byte[rb.nbyte:], i, i+int(info.size))
+ rb.insertOrdered(info)
+}
+
+// insertCGJ inserts a Combining Grapheme Joiner (0x034f) into rb.
+func (rb *reorderBuffer) insertCGJ() {
+ rb.insertSingle(input{str: GraphemeJoiner}, 0, Properties{size: uint8(len(GraphemeJoiner))})
+}
+
+// appendRune inserts a rune at the end of the buffer. It is used for Hangul.
+func (rb *reorderBuffer) appendRune(r rune) {
+ bn := rb.nbyte
+ sz := utf8.EncodeRune(rb.byte[bn:], rune(r))
+ rb.nbyte += utf8.UTFMax
+ rb.rune[rb.nrune] = Properties{pos: bn, size: uint8(sz)}
+ rb.nrune++
+}
+
+// assignRune sets a rune at position pos. It is used for Hangul and recomposition.
+func (rb *reorderBuffer) assignRune(pos int, r rune) {
+ bn := rb.rune[pos].pos
+ sz := utf8.EncodeRune(rb.byte[bn:], rune(r))
+ rb.rune[pos] = Properties{pos: bn, size: uint8(sz)}
+}
+
+// runeAt returns the rune at position n. It is used for Hangul and recomposition.
+func (rb *reorderBuffer) runeAt(n int) rune {
+ inf := rb.rune[n]
+ r, _ := utf8.DecodeRune(rb.byte[inf.pos : inf.pos+inf.size])
+ return r
+}
+
+// bytesAt returns the UTF-8 encoding of the rune at position n.
+// It is used for Hangul and recomposition.
+func (rb *reorderBuffer) bytesAt(n int) []byte {
+ inf := rb.rune[n]
+ return rb.byte[inf.pos : int(inf.pos)+int(inf.size)]
+}
+
+// For Hangul we combine algorithmically, instead of using tables.
+const (
+ hangulBase = 0xAC00 // UTF-8(hangulBase) -> EA B0 80
+ hangulBase0 = 0xEA
+ hangulBase1 = 0xB0
+ hangulBase2 = 0x80
+
+ hangulEnd = hangulBase + jamoLVTCount // UTF-8(0xD7A4) -> ED 9E A4
+ hangulEnd0 = 0xED
+ hangulEnd1 = 0x9E
+ hangulEnd2 = 0xA4
+
+ jamoLBase = 0x1100 // UTF-8(jamoLBase) -> E1 84 00
+ jamoLBase0 = 0xE1
+ jamoLBase1 = 0x84
+ jamoLEnd = 0x1113
+ jamoVBase = 0x1161
+ jamoVEnd = 0x1176
+ jamoTBase = 0x11A7
+ jamoTEnd = 0x11C3
+
+ jamoTCount = 28
+ jamoVCount = 21
+ jamoVTCount = 21 * 28
+ jamoLVTCount = 19 * 21 * 28
+)
+
+const hangulUTF8Size = 3
+
+func isHangul(b []byte) bool {
+ if len(b) < hangulUTF8Size {
+ return false
+ }
+ b0 := b[0]
+ if b0 < hangulBase0 {
+ return false
+ }
+ b1 := b[1]
+ switch {
+ case b0 == hangulBase0:
+ return b1 >= hangulBase1
+ case b0 < hangulEnd0:
+ return true
+ case b0 > hangulEnd0:
+ return false
+ case b1 < hangulEnd1:
+ return true
+ }
+ return b1 == hangulEnd1 && b[2] < hangulEnd2
+}
+
+func isHangulString(b string) bool {
+ if len(b) < hangulUTF8Size {
+ return false
+ }
+ b0 := b[0]
+ if b0 < hangulBase0 {
+ return false
+ }
+ b1 := b[1]
+ switch {
+ case b0 == hangulBase0:
+ return b1 >= hangulBase1
+ case b0 < hangulEnd0:
+ return true
+ case b0 > hangulEnd0:
+ return false
+ case b1 < hangulEnd1:
+ return true
+ }
+ return b1 == hangulEnd1 && b[2] < hangulEnd2
+}
+
+// Caller must ensure len(b) >= 2.
+func isJamoVT(b []byte) bool {
+ // True if (rune & 0xff00) == jamoLBase
+ return b[0] == jamoLBase0 && (b[1]&0xFC) == jamoLBase1
+}
+
+func isHangulWithoutJamoT(b []byte) bool {
+ c, _ := utf8.DecodeRune(b)
+ c -= hangulBase
+ return c < jamoLVTCount && c%jamoTCount == 0
+}
+
+// decomposeHangul writes the decomposed Hangul to buf and returns the number
+// of bytes written. len(buf) should be at least 9.
+func decomposeHangul(buf []byte, r rune) int {
+ const JamoUTF8Len = 3
+ r -= hangulBase
+ x := r % jamoTCount
+ r /= jamoTCount
+ utf8.EncodeRune(buf, jamoLBase+r/jamoVCount)
+ utf8.EncodeRune(buf[JamoUTF8Len:], jamoVBase+r%jamoVCount)
+ if x != 0 {
+ utf8.EncodeRune(buf[2*JamoUTF8Len:], jamoTBase+x)
+ return 3 * JamoUTF8Len
+ }
+ return 2 * JamoUTF8Len
+}
+
+// decomposeHangul algorithmically decomposes a Hangul rune into
+// its Jamo components.
+// See http://unicode.org/reports/tr15/#Hangul for details on decomposing Hangul.
+func (rb *reorderBuffer) decomposeHangul(r rune) {
+ r -= hangulBase
+ x := r % jamoTCount
+ r /= jamoTCount
+ rb.appendRune(jamoLBase + r/jamoVCount)
+ rb.appendRune(jamoVBase + r%jamoVCount)
+ if x != 0 {
+ rb.appendRune(jamoTBase + x)
+ }
+}
+
+// combineHangul algorithmically combines Jamo character components into Hangul.
+// See http://unicode.org/reports/tr15/#Hangul for details on combining Hangul.
+func (rb *reorderBuffer) combineHangul(s, i, k int) {
+ b := rb.rune[:]
+ bn := rb.nrune
+ for ; i < bn; i++ {
+ cccB := b[k-1].ccc
+ cccC := b[i].ccc
+ if cccB == 0 {
+ s = k - 1
+ }
+ if s != k-1 && cccB >= cccC {
+ // b[i] is blocked by greater-equal cccX below it
+ b[k] = b[i]
+ k++
+ } else {
+ l := rb.runeAt(s) // also used to compare to hangulBase
+ v := rb.runeAt(i) // also used to compare to jamoT
+ switch {
+ case jamoLBase <= l && l < jamoLEnd &&
+ jamoVBase <= v && v < jamoVEnd:
+ // 11xx plus 116x to LV
+ rb.assignRune(s, hangulBase+
+ (l-jamoLBase)*jamoVTCount+(v-jamoVBase)*jamoTCount)
+ case hangulBase <= l && l < hangulEnd &&
+ jamoTBase < v && v < jamoTEnd &&
+ ((l-hangulBase)%jamoTCount) == 0:
+ // ACxx plus 11Ax to LVT
+ rb.assignRune(s, l+v-jamoTBase)
+ default:
+ b[k] = b[i]
+ k++
+ }
+ }
+ }
+ rb.nrune = k
+}
+
+// compose recombines the runes in the buffer.
+// It should only be used to recompose a single segment, as it will not
+// handle alternations between Hangul and non-Hangul characters correctly.
+func (rb *reorderBuffer) compose() {
+ // UAX #15, section X5 , including Corrigendum #5
+ // "In any character sequence beginning with starter S, a character C is
+ // blocked from S if and only if there is some character B between S
+ // and C, and either B is a starter or it has the same or higher
+ // combining class as C."
+ bn := rb.nrune
+ if bn == 0 {
+ return
+ }
+ k := 1
+ b := rb.rune[:]
+ for s, i := 0, 1; i < bn; i++ {
+ if isJamoVT(rb.bytesAt(i)) {
+ // Redo from start in Hangul mode. Necessary to support
+ // U+320E..U+321E in NFKC mode.
+ rb.combineHangul(s, i, k)
+ return
+ }
+ ii := b[i]
+ // We can only use combineForward as a filter if we later
+ // get the info for the combined character. This is more
+ // expensive than using the filter. Using combinesBackward()
+ // is safe.
+ if ii.combinesBackward() {
+ cccB := b[k-1].ccc
+ cccC := ii.ccc
+ blocked := false // b[i] blocked by starter or greater or equal CCC?
+ if cccB == 0 {
+ s = k - 1
+ } else {
+ blocked = s != k-1 && cccB >= cccC
+ }
+ if !blocked {
+ combined := combine(rb.runeAt(s), rb.runeAt(i))
+ if combined != 0 {
+ rb.assignRune(s, combined)
+ continue
+ }
+ }
+ }
+ b[k] = b[i]
+ k++
+ }
+ rb.nrune = k
+}
diff --git a/src/vendor/golang_org/x/text/unicode/norm/forminfo.go b/src/vendor/golang_org/x/text/unicode/norm/forminfo.go
new file mode 100644
index 0000000..15a67c6
--- /dev/null
+++ b/src/vendor/golang_org/x/text/unicode/norm/forminfo.go
@@ -0,0 +1,256 @@
+// Copyright 2011 The Go Authors. 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
+
+// This file contains Form-specific logic and wrappers for data in tables.go.
+
+// Rune info is stored in a separate trie per composing form. A composing form
+// 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)
+// 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
+// into a byte array of UTF-8 decomposition sequences and additional info and
+// has the form:
+// <header> <decomp_byte>* [<tccc> [<lccc>]]
+// The header contains the number of bytes in the decomposition (excluding this
+// length byte). The two most significant bits of this length byte correspond
+// to bit 5 and 4 of qcInfo (see below). The byte sequence itself starts at v+1.
+// The byte sequence is followed by a trailing and leading CCC if the values
+// for these are not zero. The value of v determines which ccc are appended
+// to the sequences. For v < firstCCC, there are none, for v >= firstCCC,
+// the sequence is followed by a trailing ccc, and for v >= firstLeadingCC
+// there is an additional leading ccc. The value of tccc itself is the
+// trailing CCC shifted left 2 bits. The two least-significant bits of tccc
+// are the number of trailing non-starters.
+
+const (
+ qcInfoMask = 0x3F // to clear all but the relevant bits in a qcInfo
+ headerLenMask = 0x3F // extract the length value from the header byte
+ headerFlagsMask = 0xC0 // extract the qcInfo bits from the header byte
+)
+
+// Properties provides access to normalization properties of a rune.
+type Properties struct {
+ pos uint8 // start position in reorderBuffer; used in composition.go
+ size uint8 // length of UTF-8 encoding of this rune
+ ccc uint8 // leading canonical combining class (ccc if not decomposition)
+ tccc uint8 // trailing canonical combining class (ccc if not decomposition)
+ nLead uint8 // number of leading non-starters.
+ flags qcInfo // quick check flags
+ index uint16
+}
+
+// functions dispatchable per form
+type lookupFunc func(b input, i int) Properties
+
+// formInfo holds Form-specific functions and tables.
+type formInfo struct {
+ form Form
+ composing, compatibility bool // form type
+ info lookupFunc
+ 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
+ }
+ }
+}
+
+// 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
+// after 'a'. However, 'a' might combine with modifiers, so from the application's
+// perspective it is not a good boundary. We will therefore always use the
+// boundaries for the combining variants.
+
+// BoundaryBefore returns true if this rune starts a new segment and
+// cannot combine with any rune on the left.
+func (p Properties) BoundaryBefore() bool {
+ if p.ccc == 0 && !p.combinesBackward() {
+ return true
+ }
+ // We assume that the CCC of the first character in a decomposition
+ // is always non-zero if different from info.ccc and that we can return
+ // false at this point. This is verified by maketables.
+ return false
+}
+
+// BoundaryAfter returns true if runes cannot combine with or otherwise
+// interact with this or previous runes.
+func (p Properties) BoundaryAfter() bool {
+ // TODO: loosen these conditions.
+ return p.isInert()
+}
+
+// We pack quick check data in 4 bits:
+// 5: Combines forward (0 == false, 1 == true)
+// 4..3: NFC_QC Yes(00), No (10), or Maybe (11)
+// 2: NFD_QC Yes (0) or No (1). No also means there is a decomposition.
+// 1..0: Number of trailing non-starters.
+//
+// When all 4 bits are zero, the character is inert, meaning it is never
+// influenced by normalization.
+type qcInfo uint8
+
+func (p Properties) isYesC() bool { return p.flags&0x10 == 0 }
+func (p Properties) isYesD() bool { return p.flags&0x4 == 0 }
+
+func (p Properties) combinesForward() bool { return p.flags&0x20 != 0 }
+func (p Properties) combinesBackward() bool { return p.flags&0x8 != 0 } // == isMaybe
+func (p Properties) hasDecomposition() bool { return p.flags&0x4 != 0 } // == isNoD
+
+func (p Properties) isInert() bool {
+ return p.flags&qcInfoMask == 0 && p.ccc == 0
+}
+
+func (p Properties) multiSegment() bool {
+ return p.index >= firstMulti && p.index < endMulti
+}
+
+func (p Properties) nLeadingNonStarters() uint8 {
+ return p.nLead
+}
+
+func (p Properties) nTrailingNonStarters() uint8 {
+ return uint8(p.flags & 0x03)
+}
+
+// Decomposition returns the decomposition for the underlying rune
+// or nil if there is none.
+func (p Properties) Decomposition() []byte {
+ // TODO: create the decomposition for Hangul?
+ if p.index == 0 {
+ return nil
+ }
+ i := p.index
+ n := decomps[i] & headerLenMask
+ i++
+ return decomps[i : i+uint16(n)]
+}
+
+// Size returns the length of UTF-8 encoding of the rune.
+func (p Properties) Size() int {
+ return int(p.size)
+}
+
+// CCC returns the canonical combining class of the underlying rune.
+func (p Properties) CCC() uint8 {
+ if p.index >= firstCCCZeroExcept {
+ return 0
+ }
+ return ccc[p.ccc]
+}
+
+// LeadCCC returns the CCC of the first rune in the decomposition.
+// If there is no decomposition, LeadCCC equals CCC.
+func (p Properties) LeadCCC() uint8 {
+ return ccc[p.ccc]
+}
+
+// TrailCCC returns the CCC of the last rune in the decomposition.
+// If there is no decomposition, TrailCCC equals CCC.
+func (p Properties) TrailCCC() uint8 {
+ return ccc[p.tccc]
+}
+
+// Recomposition
+// We use 32-bit keys instead of 64-bit for the two codepoint keys.
+// This clips off the bits of three entries, but we know this will not
+// result in a collision. In the unlikely event that changes to
+// UnicodeData.txt introduce collisions, the compiler will catch it.
+// Note that the recomposition map for NFC and NFKC are identical.
+
+// combine returns the combined rune or 0 if it doesn't exist.
+func combine(a, b rune) rune {
+ key := uint32(uint16(a))<<16 + uint32(uint16(b))
+ return recompMap[key]
+}
+
+func lookupInfoNFC(b input, i int) Properties {
+ v, sz := b.charinfoNFC(i)
+ return compInfo(v, sz)
+}
+
+func lookupInfoNFKC(b input, i int) Properties {
+ v, sz := b.charinfoNFKC(i)
+ return compInfo(v, sz)
+}
+
+// Properties returns properties for the first rune in s.
+func (f Form) Properties(s []byte) Properties {
+ if f == NFC || f == NFD {
+ return compInfo(nfcData.lookup(s))
+ }
+ return compInfo(nfkcData.lookup(s))
+}
+
+// PropertiesString returns properties for the first rune in s.
+func (f Form) PropertiesString(s string) Properties {
+ if f == NFC || f == NFD {
+ return compInfo(nfcData.lookupString(s))
+ }
+ return compInfo(nfkcData.lookupString(s))
+}
+
+// compInfo converts the information contained in v and sz
+// to a Properties. See the comment at the top of the file
+// for more information on the format.
+func compInfo(v uint16, sz int) Properties {
+ if v == 0 {
+ return Properties{size: uint8(sz)}
+ } else if v >= 0x8000 {
+ p := Properties{
+ size: uint8(sz),
+ ccc: uint8(v),
+ tccc: uint8(v),
+ flags: qcInfo(v >> 8),
+ }
+ if p.ccc > 0 || p.combinesBackward() {
+ p.nLead = uint8(p.flags & 0x3)
+ }
+ return p
+ }
+ // has decomposition
+ h := decomps[v]
+ f := (qcInfo(h&headerFlagsMask) >> 2) | 0x4
+ p := Properties{size: uint8(sz), flags: f, index: v}
+ if v >= firstCCC {
+ v += uint16(h&headerLenMask) + 1
+ c := decomps[v]
+ p.tccc = c >> 2
+ p.flags |= qcInfo(c & 0x3)
+ if v >= firstLeadingCCC {
+ p.nLead = c & 0x3
+ if v >= firstStarterWithNLead {
+ // We were tricked. Remove the decomposition.
+ p.flags &= 0x03
+ p.index = 0
+ return p
+ }
+ p.ccc = decomps[v+1]
+ }
+ }
+ return p
+}
diff --git a/src/vendor/golang_org/x/text/unicode/norm/input.go b/src/vendor/golang_org/x/text/unicode/norm/input.go
new file mode 100644
index 0000000..045d4cc
--- /dev/null
+++ b/src/vendor/golang_org/x/text/unicode/norm/input.go
@@ -0,0 +1,105 @@
+// Copyright 2011 The Go Authors. 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
+
+import "unicode/utf8"
+
+type input struct {
+ str string
+ bytes []byte
+}
+
+func inputBytes(str []byte) input {
+ return input{bytes: str}
+}
+
+func inputString(str string) input {
+ return input{str: str}
+}
+
+func (in *input) setBytes(str []byte) {
+ in.str = ""
+ in.bytes = str
+}
+
+func (in *input) setString(str string) {
+ in.str = str
+ in.bytes = nil
+}
+
+func (in *input) _byte(p int) byte {
+ if in.bytes == nil {
+ return in.str[p]
+ }
+ return in.bytes[p]
+}
+
+func (in *input) skipASCII(p, max int) int {
+ if in.bytes == nil {
+ for ; p < max && in.str[p] < utf8.RuneSelf; p++ {
+ }
+ } else {
+ for ; p < max && in.bytes[p] < utf8.RuneSelf; p++ {
+ }
+ }
+ return p
+}
+
+func (in *input) skipContinuationBytes(p int) int {
+ if in.bytes == nil {
+ for ; p < len(in.str) && !utf8.RuneStart(in.str[p]); p++ {
+ }
+ } else {
+ for ; p < len(in.bytes) && !utf8.RuneStart(in.bytes[p]); p++ {
+ }
+ }
+ return p
+}
+
+func (in *input) appendSlice(buf []byte, b, e int) []byte {
+ if in.bytes != nil {
+ return append(buf, in.bytes[b:e]...)
+ }
+ for i := b; i < e; i++ {
+ buf = append(buf, in.str[i])
+ }
+ return buf
+}
+
+func (in *input) copySlice(buf []byte, b, e int) int {
+ if in.bytes == nil {
+ return copy(buf, in.str[b:e])
+ }
+ return copy(buf, in.bytes[b:e])
+}
+
+func (in *input) charinfoNFC(p int) (uint16, int) {
+ if in.bytes == nil {
+ return nfcData.lookupString(in.str[p:])
+ }
+ return nfcData.lookup(in.bytes[p:])
+}
+
+func (in *input) charinfoNFKC(p int) (uint16, int) {
+ if in.bytes == nil {
+ return nfkcData.lookupString(in.str[p:])
+ }
+ return nfkcData.lookup(in.bytes[p:])
+}
+
+func (in *input) hangul(p int) (r rune) {
+ if in.bytes == nil {
+ if !isHangulString(in.str[p:]) {
+ return 0
+ }
+ r, _ = utf8.DecodeRuneInString(in.str[p:])
+ } else {
+ if !isHangul(in.bytes[p:]) {
+ return 0
+ }
+ r, _ = utf8.DecodeRune(in.bytes[p:])
+ }
+ return r
+}
diff --git a/src/vendor/golang_org/x/text/unicode/norm/iter.go b/src/vendor/golang_org/x/text/unicode/norm/iter.go
new file mode 100644
index 0000000..0a42a72
--- /dev/null
+++ b/src/vendor/golang_org/x/text/unicode/norm/iter.go
@@ -0,0 +1,450 @@
+// Copyright 2011 The Go Authors. 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
+
+import (
+ "fmt"
+ "unicode/utf8"
+)
+
+// MaxSegmentSize is the maximum size of a byte buffer needed to consider any
+// sequence of starter and non-starter runes for the purpose of normalization.
+const MaxSegmentSize = maxByteBufferSize
+
+// An Iter iterates over a string or byte slice, while normalizing it
+// to a given Form.
+type Iter struct {
+ rb reorderBuffer
+ buf [maxByteBufferSize]byte
+ info Properties // first character saved from previous iteration
+ next iterFunc // implementation of next depends on form
+ asciiF iterFunc
+
+ p int // current position in input source
+ multiSeg []byte // remainder of multi-segment decomposition
+}
+
+type iterFunc func(*Iter) []byte
+
+// Init initializes i to iterate over src after normalizing it to Form f.
+func (i *Iter) Init(f Form, src []byte) {
+ i.p = 0
+ if len(src) == 0 {
+ i.setDone()
+ i.rb.nsrc = 0
+ return
+ }
+ i.multiSeg = nil
+ i.rb.init(f, src)
+ i.next = i.rb.f.nextMain
+ i.asciiF = nextASCIIBytes
+ i.info = i.rb.f.info(i.rb.src, i.p)
+}
+
+// InitString initializes i to iterate over src after normalizing it to Form f.
+func (i *Iter) InitString(f Form, src string) {
+ i.p = 0
+ if len(src) == 0 {
+ i.setDone()
+ i.rb.nsrc = 0
+ return
+ }
+ i.multiSeg = nil
+ i.rb.initString(f, src)
+ i.next = i.rb.f.nextMain
+ i.asciiF = nextASCIIString
+ i.info = i.rb.f.info(i.rb.src, i.p)
+}
+
+// Seek sets the segment to be returned by the next call to Next to start
+// at position p. It is the responsibility of the caller to set p to the
+// start of a UTF8 rune.
+func (i *Iter) Seek(offset int64, whence int) (int64, error) {
+ var abs int64
+ switch whence {
+ case 0:
+ abs = offset
+ case 1:
+ abs = int64(i.p) + offset
+ case 2:
+ abs = int64(i.rb.nsrc) + offset
+ default:
+ return 0, fmt.Errorf("norm: invalid whence")
+ }
+ if abs < 0 {
+ return 0, fmt.Errorf("norm: negative position")
+ }
+ if int(abs) >= i.rb.nsrc {
+ i.setDone()
+ return int64(i.p), nil
+ }
+ i.p = int(abs)
+ i.multiSeg = nil
+ i.next = i.rb.f.nextMain
+ i.info = i.rb.f.info(i.rb.src, i.p)
+ return abs, nil
+}
+
+// returnSlice returns a slice of the underlying input type as a byte slice.
+// If the underlying is of type []byte, it will simply return a slice.
+// If the underlying is of type string, it will copy the slice to the buffer
+// and return that.
+func (i *Iter) returnSlice(a, b int) []byte {
+ if i.rb.src.bytes == nil {
+ return i.buf[:copy(i.buf[:], i.rb.src.str[a:b])]
+ }
+ return i.rb.src.bytes[a:b]
+}
+
+// Pos returns the byte position at which the next call to Next will commence processing.
+func (i *Iter) Pos() int {
+ return i.p
+}
+
+func (i *Iter) setDone() {
+ i.next = nextDone
+ i.p = i.rb.nsrc
+}
+
+// Done returns true if there is no more input to process.
+func (i *Iter) Done() bool {
+ return i.p >= i.rb.nsrc
+}
+
+// Next returns f(i.input[i.Pos():n]), where n is a boundary of i.input.
+// For any input a and b for which f(a) == f(b), subsequent calls
+// to Next will return the same segments.
+// Modifying runes are grouped together with the preceding starter, if such a starter exists.
+// Although not guaranteed, n will typically be the smallest possible n.
+func (i *Iter) Next() []byte {
+ return i.next(i)
+}
+
+func nextASCIIBytes(i *Iter) []byte {
+ p := i.p + 1
+ if p >= i.rb.nsrc {
+ i.setDone()
+ return i.rb.src.bytes[i.p:p]
+ }
+ if i.rb.src.bytes[p] < utf8.RuneSelf {
+ p0 := i.p
+ i.p = p
+ return i.rb.src.bytes[p0:p]
+ }
+ i.info = i.rb.f.info(i.rb.src, i.p)
+ i.next = i.rb.f.nextMain
+ return i.next(i)
+}
+
+func nextASCIIString(i *Iter) []byte {
+ p := i.p + 1
+ if p >= i.rb.nsrc {
+ i.buf[0] = i.rb.src.str[i.p]
+ i.setDone()
+ return i.buf[:1]
+ }
+ if i.rb.src.str[p] < utf8.RuneSelf {
+ i.buf[0] = i.rb.src.str[i.p]
+ i.p = p
+ return i.buf[:1]
+ }
+ i.info = i.rb.f.info(i.rb.src, i.p)
+ i.next = i.rb.f.nextMain
+ return i.next(i)
+}
+
+func nextHangul(i *Iter) []byte {
+ p := i.p
+ next := p + hangulUTF8Size
+ if next >= i.rb.nsrc {
+ i.setDone()
+ } else if i.rb.src.hangul(next) == 0 {
+ i.info = i.rb.f.info(i.rb.src, i.p)
+ i.next = i.rb.f.nextMain
+ return i.next(i)
+ }
+ i.p = next
+ return i.buf[:decomposeHangul(i.buf[:], i.rb.src.hangul(p))]
+}
+
+func nextDone(i *Iter) []byte {
+ return nil
+}
+
+// nextMulti is used for iterating over multi-segment decompositions
+// for decomposing normal forms.
+func nextMulti(i *Iter) []byte {
+ j := 0
+ d := i.multiSeg
+ // skip first rune
+ for j = 1; j < len(d) && !utf8.RuneStart(d[j]); j++ {
+ }
+ for j < len(d) {
+ info := i.rb.f.info(input{bytes: d}, j)
+ if info.BoundaryBefore() {
+ i.multiSeg = d[j:]
+ return d[:j]
+ }
+ j += int(info.size)
+ }
+ // treat last segment as normal decomposition
+ i.next = i.rb.f.nextMain
+ return i.next(i)
+}
+
+// nextMultiNorm is used for iterating over multi-segment decompositions
+// for composing normal forms.
+func nextMultiNorm(i *Iter) []byte {
+ j := 0
+ d := i.multiSeg
+ for j < len(d) {
+ info := i.rb.f.info(input{bytes: d}, j)
+ if info.BoundaryBefore() {
+ i.rb.compose()
+ seg := i.buf[:i.rb.flushCopy(i.buf[:])]
+ i.rb.ss.first(info)
+ i.rb.insertUnsafe(input{bytes: d}, j, info)
+ i.multiSeg = d[j+int(info.size):]
+ return seg
+ }
+ i.rb.ss.next(info)
+ i.rb.insertUnsafe(input{bytes: d}, j, info)
+ j += int(info.size)
+ }
+ i.multiSeg = nil
+ i.next = nextComposed
+ return doNormComposed(i)
+}
+
+// nextDecomposed is the implementation of Next for forms NFD and NFKD.
+func nextDecomposed(i *Iter) (next []byte) {
+ outp := 0
+ inCopyStart, outCopyStart := i.p, 0
+ ss := mkStreamSafe(i.info)
+ for {
+ if sz := int(i.info.size); sz <= 1 {
+ p := i.p
+ i.p++ // ASCII or illegal byte. Either way, advance by 1.
+ if i.p >= i.rb.nsrc {
+ i.setDone()
+ return i.returnSlice(p, i.p)
+ } else if i.rb.src._byte(i.p) < utf8.RuneSelf {
+ i.next = i.asciiF
+ return i.returnSlice(p, i.p)
+ }
+ outp++
+ } else if d := i.info.Decomposition(); d != nil {
+ // Note: If leading CCC != 0, then len(d) == 2 and last is also non-zero.
+ // Case 1: there is a leftover to copy. In this case the decomposition
+ // must begin with a modifier and should always be appended.
+ // Case 2: no leftover. Simply return d if followed by a ccc == 0 value.
+ p := outp + len(d)
+ if outp > 0 {
+ i.rb.src.copySlice(i.buf[outCopyStart:], inCopyStart, i.p)
+ if p > len(i.buf) {
+ return i.buf[:outp]
+ }
+ } else if i.info.multiSegment() {
+ // outp must be 0 as multi-segment decompositions always
+ // start a new segment.
+ if i.multiSeg == nil {
+ i.multiSeg = d
+ i.next = nextMulti
+ return nextMulti(i)
+ }
+ // We are in the last segment. Treat as normal decomposition.
+ d = i.multiSeg
+ i.multiSeg = nil
+ p = len(d)
+ }
+ prevCC := i.info.tccc
+ if i.p += sz; i.p >= i.rb.nsrc {
+ i.setDone()
+ i.info = Properties{} // Force BoundaryBefore to succeed.
+ } else {
+ i.info = i.rb.f.info(i.rb.src, i.p)
+ }
+ switch ss.next(i.info) {
+ case ssOverflow:
+ i.next = nextCGJDecompose
+ fallthrough
+ case ssStarter:
+ if outp > 0 {
+ copy(i.buf[outp:], d)
+ return i.buf[:p]
+ }
+ return d
+ }
+ copy(i.buf[outp:], d)
+ outp = p
+ inCopyStart, outCopyStart = i.p, outp
+ if i.info.ccc < prevCC {
+ goto doNorm
+ }
+ continue
+ } else if r := i.rb.src.hangul(i.p); r != 0 {
+ outp = decomposeHangul(i.buf[:], r)
+ i.p += hangulUTF8Size
+ inCopyStart, outCopyStart = i.p, outp
+ if i.p >= i.rb.nsrc {
+ i.setDone()
+ break
+ } else if i.rb.src.hangul(i.p) != 0 {
+ i.next = nextHangul
+ return i.buf[:outp]
+ }
+ } else {
+ p := outp + sz
+ if p > len(i.buf) {
+ break
+ }
+ outp = p
+ i.p += sz
+ }
+ if i.p >= i.rb.nsrc {
+ i.setDone()
+ break
+ }
+ prevCC := i.info.tccc
+ i.info = i.rb.f.info(i.rb.src, i.p)
+ if v := ss.next(i.info); v == ssStarter {
+ break
+ } else if v == ssOverflow {
+ i.next = nextCGJDecompose
+ break
+ }
+ if i.info.ccc < prevCC {
+ goto doNorm
+ }
+ }
+ if outCopyStart == 0 {
+ return i.returnSlice(inCopyStart, i.p)
+ } else if inCopyStart < i.p {
+ i.rb.src.copySlice(i.buf[outCopyStart:], inCopyStart, i.p)
+ }
+ return i.buf[:outp]
+doNorm:
+ // Insert what we have decomposed so far in the reorderBuffer.
+ // As we will only reorder, there will always be enough room.
+ i.rb.src.copySlice(i.buf[outCopyStart:], inCopyStart, i.p)
+ i.rb.insertDecomposed(i.buf[0:outp])
+ return doNormDecomposed(i)
+}
+
+func doNormDecomposed(i *Iter) []byte {
+ for {
+ if s := i.rb.ss.next(i.info); s == ssOverflow {
+ i.next = nextCGJDecompose
+ break
+ }
+ i.rb.insertUnsafe(i.rb.src, i.p, i.info)
+ if i.p += int(i.info.size); i.p >= i.rb.nsrc {
+ i.setDone()
+ break
+ }
+ i.info = i.rb.f.info(i.rb.src, i.p)
+ if i.info.ccc == 0 {
+ break
+ }
+ }
+ // new segment or too many combining characters: exit normalization
+ return i.buf[:i.rb.flushCopy(i.buf[:])]
+}
+
+func nextCGJDecompose(i *Iter) []byte {
+ i.rb.ss = 0
+ i.rb.insertCGJ()
+ i.next = nextDecomposed
+ buf := doNormDecomposed(i)
+ return buf
+}
+
+// nextComposed is the implementation of Next for forms NFC and NFKC.
+func nextComposed(i *Iter) []byte {
+ outp, startp := 0, i.p
+ var prevCC uint8
+ ss := mkStreamSafe(i.info)
+ for {
+ if !i.info.isYesC() {
+ goto doNorm
+ }
+ prevCC = i.info.tccc
+ sz := int(i.info.size)
+ if sz == 0 {
+ sz = 1 // illegal rune: copy byte-by-byte
+ }
+ p := outp + sz
+ if p > len(i.buf) {
+ break
+ }
+ outp = p
+ i.p += sz
+ if i.p >= i.rb.nsrc {
+ i.setDone()
+ break
+ } else if i.rb.src._byte(i.p) < utf8.RuneSelf {
+ i.next = i.asciiF
+ break
+ }
+ i.info = i.rb.f.info(i.rb.src, i.p)
+ if v := ss.next(i.info); v == ssStarter {
+ break
+ } else if v == ssOverflow {
+ i.next = nextCGJCompose
+ break
+ }
+ if i.info.ccc < prevCC {
+ goto doNorm
+ }
+ }
+ return i.returnSlice(startp, i.p)
+doNorm:
+ i.p = startp
+ i.info = i.rb.f.info(i.rb.src, i.p)
+ if i.info.multiSegment() {
+ d := i.info.Decomposition()
+ info := i.rb.f.info(input{bytes: d}, 0)
+ i.rb.insertUnsafe(input{bytes: d}, 0, info)
+ i.multiSeg = d[int(info.size):]
+ i.next = nextMultiNorm
+ return nextMultiNorm(i)
+ }
+ i.rb.ss.first(i.info)
+ i.rb.insertUnsafe(i.rb.src, i.p, i.info)
+ return doNormComposed(i)
+}
+
+func doNormComposed(i *Iter) []byte {
+ // First rune should already be inserted.
+ for {
+ if i.p += int(i.info.size); i.p >= i.rb.nsrc {
+ i.setDone()
+ break
+ }
+ i.info = i.rb.f.info(i.rb.src, i.p)
+ if s := i.rb.ss.next(i.info); s == ssStarter {
+ break
+ } else if s == ssOverflow {
+ i.next = nextCGJCompose
+ break
+ }
+ i.rb.insertUnsafe(i.rb.src, i.p, i.info)
+ }
+ i.rb.compose()
+ seg := i.buf[:i.rb.flushCopy(i.buf[:])]
+ return seg
+}
+
+func nextCGJCompose(i *Iter) []byte {
+ i.rb.ss = 0 // instead of first
+ i.rb.insertCGJ()
+ i.next = nextComposed
+ // Note that we treat any rune with nLeadingNonStarters > 0 as a non-starter,
+ // even if they are not. This is particularly dubious for U+FF9E and UFF9A.
+ // If we ever change that, insert a check here.
+ i.rb.ss.first(i.info)
+ i.rb.insertUnsafe(i.rb.src, i.p, i.info)
+ return doNormComposed(i)
+}
diff --git a/src/vendor/golang_org/x/text/unicode/norm/normalize.go b/src/vendor/golang_org/x/text/unicode/norm/normalize.go
new file mode 100644
index 0000000..15c962e
--- /dev/null
+++ b/src/vendor/golang_org/x/text/unicode/norm/normalize.go
@@ -0,0 +1,608 @@
+// Copyright 2011 The Go 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
+
+// Package norm contains types and functions for normalizing Unicode strings.
+package norm // import "golang.org/x/text/unicode/norm"
+
+import (
+ "unicode/utf8"
+
+ "golang_org/x/text/transform"
+)
+
+// A Form denotes a canonical representation of Unicode code points.
+// The Unicode-defined normalization and equivalence forms are:
+//
+// NFC Unicode Normalization Form C
+// NFD Unicode Normalization Form D
+// NFKC Unicode Normalization Form KC
+// NFKD Unicode Normalization Form KD
+//
+// For a Form f, this documentation uses the notation f(x) to mean
+// the bytes or string x converted to the given form.
+// A position n in x is called a boundary if conversion to the form can
+// proceed independently on both sides:
+// f(x) == append(f(x[0:n]), f(x[n:])...)
+//
+// References: http://unicode.org/reports/tr15/ and
+// http://unicode.org/notes/tn5/.
+type Form int
+
+const (
+ NFC Form = iota
+ NFD
+ NFKC
+ NFKD
+)
+
+// Bytes returns f(b). May return b if f(b) = b.
+func (f Form) Bytes(b []byte) []byte {
+ src := inputBytes(b)
+ ft := formTable[f]
+ n, ok := ft.quickSpan(src, 0, len(b), true)
+ if ok {
+ return b
+ }
+ out := make([]byte, n, len(b))
+ copy(out, b[0:n])
+ rb := reorderBuffer{f: *ft, src: src, nsrc: len(b), out: out, flushF: appendFlush}
+ return doAppendInner(&rb, n)
+}
+
+// String returns f(s).
+func (f Form) String(s string) string {
+ src := inputString(s)
+ ft := formTable[f]
+ n, ok := ft.quickSpan(src, 0, len(s), true)
+ if ok {
+ return s
+ }
+ out := make([]byte, n, len(s))
+ copy(out, s[0:n])
+ rb := reorderBuffer{f: *ft, src: src, nsrc: len(s), out: out, flushF: appendFlush}
+ return string(doAppendInner(&rb, n))
+}
+
+// IsNormal returns true if b == f(b).
+func (f Form) IsNormal(b []byte) bool {
+ src := inputBytes(b)
+ ft := formTable[f]
+ bp, ok := ft.quickSpan(src, 0, len(b), true)
+ if ok {
+ return true
+ }
+ rb := reorderBuffer{f: *ft, src: src, nsrc: len(b)}
+ rb.setFlusher(nil, cmpNormalBytes)
+ for bp < len(b) {
+ rb.out = b[bp:]
+ if bp = decomposeSegment(&rb, bp, true); bp < 0 {
+ return false
+ }
+ bp, _ = rb.f.quickSpan(rb.src, bp, len(b), true)
+ }
+ return true
+}
+
+func cmpNormalBytes(rb *reorderBuffer) bool {
+ b := rb.out
+ for i := 0; i < rb.nrune; i++ {
+ info := rb.rune[i]
+ if int(info.size) > len(b) {
+ return false
+ }
+ p := info.pos
+ pe := p + info.size
+ for ; p < pe; p++ {
+ if b[0] != rb.byte[p] {
+ return false
+ }
+ b = b[1:]
+ }
+ }
+ return true
+}
+
+// IsNormalString returns true if s == f(s).
+func (f Form) IsNormalString(s string) bool {
+ src := inputString(s)
+ ft := formTable[f]
+ bp, ok := ft.quickSpan(src, 0, len(s), true)
+ if ok {
+ return true
+ }
+ rb := reorderBuffer{f: *ft, src: src, nsrc: len(s)}
+ rb.setFlusher(nil, func(rb *reorderBuffer) bool {
+ for i := 0; i < rb.nrune; i++ {
+ info := rb.rune[i]
+ if bp+int(info.size) > len(s) {
+ return false
+ }
+ p := info.pos
+ pe := p + info.size
+ for ; p < pe; p++ {
+ if s[bp] != rb.byte[p] {
+ return false
+ }
+ bp++
+ }
+ }
+ return true
+ })
+ for bp < len(s) {
+ if bp = decomposeSegment(&rb, bp, true); bp < 0 {
+ return false
+ }
+ bp, _ = rb.f.quickSpan(rb.src, bp, len(s), true)
+ }
+ return true
+}
+
+// patchTail fixes a case where a rune may be incorrectly normalized
+// if it is followed by illegal continuation bytes. It returns the
+// patched buffer and whether the decomposition is still in progress.
+func patchTail(rb *reorderBuffer) bool {
+ info, p := lastRuneStart(&rb.f, rb.out)
+ if p == -1 || info.size == 0 {
+ return true
+ }
+ end := p + int(info.size)
+ extra := len(rb.out) - end
+ if extra > 0 {
+ // Potentially allocating memory. However, this only
+ // happens with ill-formed UTF-8.
+ x := make([]byte, 0)
+ x = append(x, rb.out[len(rb.out)-extra:]...)
+ rb.out = rb.out[:end]
+ decomposeToLastBoundary(rb)
+ rb.doFlush()
+ rb.out = append(rb.out, x...)
+ return false
+ }
+ buf := rb.out[p:]
+ rb.out = rb.out[:p]
+ decomposeToLastBoundary(rb)
+ if s := rb.ss.next(info); s == ssStarter {
+ rb.doFlush()
+ rb.ss.first(info)
+ } else if s == ssOverflow {
+ rb.doFlush()
+ rb.insertCGJ()
+ rb.ss = 0
+ }
+ rb.insertUnsafe(inputBytes(buf), 0, info)
+ return true
+}
+
+func appendQuick(rb *reorderBuffer, i int) int {
+ if rb.nsrc == i {
+ return i
+ }
+ end, _ := rb.f.quickSpan(rb.src, i, rb.nsrc, true)
+ rb.out = rb.src.appendSlice(rb.out, i, end)
+ return end
+}
+
+// Append returns f(append(out, b...)).
+// The buffer out must be nil, empty, or equal to f(out).
+func (f Form) Append(out []byte, src ...byte) []byte {
+ return f.doAppend(out, inputBytes(src), len(src))
+}
+
+func (f Form) doAppend(out []byte, src input, n int) []byte {
+ if n == 0 {
+ return out
+ }
+ ft := formTable[f]
+ // Attempt to do a quickSpan first so we can avoid initializing the reorderBuffer.
+ if len(out) == 0 {
+ p, _ := ft.quickSpan(src, 0, n, true)
+ out = src.appendSlice(out, 0, p)
+ if p == n {
+ return out
+ }
+ rb := reorderBuffer{f: *ft, src: src, nsrc: n, out: out, flushF: appendFlush}
+ return doAppendInner(&rb, p)
+ }
+ rb := reorderBuffer{f: *ft, src: src, nsrc: n}
+ return doAppend(&rb, out, 0)
+}
+
+func doAppend(rb *reorderBuffer, out []byte, p int) []byte {
+ rb.setFlusher(out, appendFlush)
+ src, n := rb.src, rb.nsrc
+ doMerge := len(out) > 0
+ if q := src.skipContinuationBytes(p); q > p {
+ // Move leading non-starters to destination.
+ rb.out = src.appendSlice(rb.out, p, q)
+ p = q
+ doMerge = patchTail(rb)
+ }
+ fd := &rb.f
+ if doMerge {
+ var info Properties
+ if p < n {
+ info = fd.info(src, p)
+ if !info.BoundaryBefore() || info.nLeadingNonStarters() > 0 {
+ if p == 0 {
+ decomposeToLastBoundary(rb)
+ }
+ p = decomposeSegment(rb, p, true)
+ }
+ }
+ if info.size == 0 {
+ rb.doFlush()
+ // Append incomplete UTF-8 encoding.
+ return src.appendSlice(rb.out, p, n)
+ }
+ if rb.nrune > 0 {
+ return doAppendInner(rb, p)
+ }
+ }
+ p = appendQuick(rb, p)
+ return doAppendInner(rb, p)
+}
+
+func doAppendInner(rb *reorderBuffer, p int) []byte {
+ for n := rb.nsrc; p < n; {
+ p = decomposeSegment(rb, p, true)
+ p = appendQuick(rb, p)
+ }
+ return rb.out
+}
+
+// AppendString returns f(append(out, []byte(s))).
+// The buffer out must be nil, empty, or equal to f(out).
+func (f Form) AppendString(out []byte, src string) []byte {
+ return f.doAppend(out, inputString(src), len(src))
+}
+
+// QuickSpan returns a boundary n such that b[0:n] == f(b[0:n]).
+// It is not guaranteed to return the largest such n.
+func (f Form) QuickSpan(b []byte) int {
+ n, _ := formTable[f].quickSpan(inputBytes(b), 0, len(b), true)
+ return n
+}
+
+// Span implements transform.SpanningTransformer. It returns a boundary n such
+// that b[0:n] == f(b[0:n]). It is not guaranteed to return the largest such n.
+func (f Form) Span(b []byte, atEOF bool) (n int, err error) {
+ n, ok := formTable[f].quickSpan(inputBytes(b), 0, len(b), atEOF)
+ if n < len(b) {
+ if !ok {
+ err = transform.ErrEndOfSpan
+ } else {
+ err = transform.ErrShortSrc
+ }
+ }
+ return n, err
+}
+
+// SpanString returns a boundary n such that s[0:n] == f(s[0:n]).
+// It is not guaranteed to return the largest such n.
+func (f Form) SpanString(s string, atEOF bool) (n int, err error) {
+ n, ok := formTable[f].quickSpan(inputString(s), 0, len(s), atEOF)
+ if n < len(s) {
+ if !ok {
+ err = transform.ErrEndOfSpan
+ } else {
+ err = transform.ErrShortSrc
+ }
+ }
+ return n, err
+}
+
+// quickSpan returns a boundary n such that src[0:n] == f(src[0:n]) and
+// whether any non-normalized parts were found. If atEOF is false, n will
+// not point past the last segment if this segment might be become
+// non-normalized by appending other runes.
+func (f *formInfo) quickSpan(src input, i, end int, atEOF bool) (n int, ok bool) {
+ var lastCC uint8
+ ss := streamSafe(0)
+ lastSegStart := i
+ for n = end; i < n; {
+ if j := src.skipASCII(i, n); i != j {
+ i = j
+ lastSegStart = i - 1
+ lastCC = 0
+ ss = 0
+ continue
+ }
+ info := f.info(src, i)
+ if info.size == 0 {
+ if atEOF {
+ // include incomplete runes
+ return n, true
+ }
+ return lastSegStart, true
+ }
+ // This block needs to be before the next, because it is possible to
+ // have an overflow for runes that are starters (e.g. with U+FF9E).
+ switch ss.next(info) {
+ case ssStarter:
+ ss.first(info)
+ lastSegStart = i
+ case ssOverflow:
+ return lastSegStart, false
+ case ssSuccess:
+ if lastCC > info.ccc {
+ return lastSegStart, false
+ }
+ }
+ if f.composing {
+ if !info.isYesC() {
+ break
+ }
+ } else {
+ if !info.isYesD() {
+ break
+ }
+ }
+ lastCC = info.ccc
+ i += int(info.size)
+ }
+ if i == n {
+ if !atEOF {
+ n = lastSegStart
+ }
+ return n, true
+ }
+ return lastSegStart, false
+}
+
+// QuickSpanString returns a boundary n such that s[0:n] == f(s[0:n]).
+// It is not guaranteed to return the largest such n.
+func (f Form) QuickSpanString(s string) int {
+ n, _ := formTable[f].quickSpan(inputString(s), 0, len(s), true)
+ return n
+}
+
+// FirstBoundary returns the position i of the first boundary in b
+// or -1 if b contains no boundary.
+func (f Form) FirstBoundary(b []byte) int {
+ return f.firstBoundary(inputBytes(b), len(b))
+}
+
+func (f Form) firstBoundary(src input, nsrc int) int {
+ i := src.skipContinuationBytes(0)
+ if i >= nsrc {
+ return -1
+ }
+ fd := formTable[f]
+ ss := streamSafe(0)
+ // We should call ss.first here, but we can't as the first rune is
+ // skipped already. This means FirstBoundary can't really determine
+ // CGJ insertion points correctly. Luckily it doesn't have to.
+ for {
+ info := fd.info(src, i)
+ if info.size == 0 {
+ return -1
+ }
+ if s := ss.next(info); s != ssSuccess {
+ return i
+ }
+ i += int(info.size)
+ if i >= nsrc {
+ if !info.BoundaryAfter() && !ss.isMax() {
+ return -1
+ }
+ return nsrc
+ }
+ }
+}
+
+// FirstBoundaryInString returns the position i of the first boundary in s
+// or -1 if s contains no boundary.
+func (f Form) FirstBoundaryInString(s string) int {
+ return f.firstBoundary(inputString(s), len(s))
+}
+
+// NextBoundary reports the index of the boundary between the first and next
+// segment in b or -1 if atEOF is false and there are not enough bytes to
+// determine this boundary.
+func (f Form) NextBoundary(b []byte, atEOF bool) int {
+ return f.nextBoundary(inputBytes(b), len(b), atEOF)
+}
+
+// NextBoundaryInString reports the index of the boundary between the first and
+// next segment in b or -1 if atEOF is false and there are not enough bytes to
+// determine this boundary.
+func (f Form) NextBoundaryInString(s string, atEOF bool) int {
+ return f.nextBoundary(inputString(s), len(s), atEOF)
+}
+
+func (f Form) nextBoundary(src input, nsrc int, atEOF bool) int {
+ if nsrc == 0 {
+ if atEOF {
+ return 0
+ }
+ return -1
+ }
+ fd := formTable[f]
+ info := fd.info(src, 0)
+ if info.size == 0 {
+ if atEOF {
+ return 1
+ }
+ return -1
+ }
+ ss := streamSafe(0)
+ ss.first(info)
+
+ for i := int(info.size); i < nsrc; i += int(info.size) {
+ info = fd.info(src, i)
+ if info.size == 0 {
+ if atEOF {
+ return i
+ }
+ return -1
+ }
+ if s := ss.next(info); s != ssSuccess {
+ return i
+ }
+ }
+ if !atEOF && !info.BoundaryAfter() && !ss.isMax() {
+ return -1
+ }
+ return nsrc
+}
+
+// LastBoundary returns the position i of the last boundary in b
+// or -1 if b contains no boundary.
+func (f Form) LastBoundary(b []byte) int {
+ return lastBoundary(formTable[f], b)
+}
+
+func lastBoundary(fd *formInfo, b []byte) int {
+ i := len(b)
+ info, p := lastRuneStart(fd, b)
+ if p == -1 {
+ return -1
+ }
+ if info.size == 0 { // ends with incomplete rune
+ if p == 0 { // starts with incomplete rune
+ return -1
+ }
+ i = p
+ info, p = lastRuneStart(fd, b[:i])
+ if p == -1 { // incomplete UTF-8 encoding or non-starter bytes without a starter
+ return i
+ }
+ }
+ if p+int(info.size) != i { // trailing non-starter bytes: illegal UTF-8
+ return i
+ }
+ if info.BoundaryAfter() {
+ return i
+ }
+ ss := streamSafe(0)
+ v := ss.backwards(info)
+ for i = p; i >= 0 && v != ssStarter; i = p {
+ info, p = lastRuneStart(fd, b[:i])
+ if v = ss.backwards(info); v == ssOverflow {
+ break
+ }
+ if p+int(info.size) != i {
+ if p == -1 { // no boundary found
+ return -1
+ }
+ return i // boundary after an illegal UTF-8 encoding
+ }
+ }
+ return i
+}
+
+// decomposeSegment scans the first segment in src into rb. It inserts 0x034f
+// (Grapheme Joiner) when it encounters a sequence of more than 30 non-starters
+// and returns the number of bytes consumed from src or iShortDst or iShortSrc.
+func decomposeSegment(rb *reorderBuffer, sp int, atEOF bool) int {
+ // Force one character to be consumed.
+ info := rb.f.info(rb.src, sp)
+ if info.size == 0 {
+ return 0
+ }
+ if rb.nrune > 0 {
+ if s := rb.ss.next(info); s == ssStarter {
+ goto end
+ } else if s == ssOverflow {
+ rb.insertCGJ()
+ goto end
+ }
+ } else {
+ rb.ss.first(info)
+ }
+ if err := rb.insertFlush(rb.src, sp, info); err != iSuccess {
+ return int(err)
+ }
+ for {
+ sp += int(info.size)
+ if sp >= rb.nsrc {
+ if !atEOF && !info.BoundaryAfter() {
+ return int(iShortSrc)
+ }
+ break
+ }
+ info = rb.f.info(rb.src, sp)
+ if info.size == 0 {
+ if !atEOF {
+ return int(iShortSrc)
+ }
+ break
+ }
+ if s := rb.ss.next(info); s == ssStarter {
+ break
+ } else if s == ssOverflow {
+ rb.insertCGJ()
+ break
+ }
+ if err := rb.insertFlush(rb.src, sp, info); err != iSuccess {
+ return int(err)
+ }
+ }
+end:
+ if !rb.doFlush() {
+ return int(iShortDst)
+ }
+ return sp
+}
+
+// lastRuneStart returns the runeInfo and position of the last
+// rune in buf or the zero runeInfo and -1 if no rune was found.
+func lastRuneStart(fd *formInfo, buf []byte) (Properties, int) {
+ p := len(buf) - 1
+ for ; p >= 0 && !utf8.RuneStart(buf[p]); p-- {
+ }
+ if p < 0 {
+ return Properties{}, -1
+ }
+ return fd.info(inputBytes(buf), p), p
+}
+
+// decomposeToLastBoundary finds an open segment at the end of the buffer
+// and scans it into rb. Returns the buffer minus the last segment.
+func decomposeToLastBoundary(rb *reorderBuffer) {
+ fd := &rb.f
+ info, i := lastRuneStart(fd, rb.out)
+ if int(info.size) != len(rb.out)-i {
+ // illegal trailing continuation bytes
+ return
+ }
+ if info.BoundaryAfter() {
+ return
+ }
+ var add [maxNonStarters + 1]Properties // stores runeInfo in reverse order
+ padd := 0
+ ss := streamSafe(0)
+ p := len(rb.out)
+ for {
+ add[padd] = info
+ v := ss.backwards(info)
+ if v == ssOverflow {
+ // Note that if we have an overflow, it the string we are appending to
+ // is not correctly normalized. In this case the behavior is undefined.
+ break
+ }
+ padd++
+ p -= int(info.size)
+ if v == ssStarter || p < 0 {
+ break
+ }
+ info, i = lastRuneStart(fd, rb.out[:p])
+ if int(info.size) != p-i {
+ break
+ }
+ }
+ rb.ss = ss
+ // Copy bytes for insertion as we may need to overwrite rb.out.
+ var buf [maxBufferSize * utf8.UTFMax]byte
+ cp := buf[:copy(buf[:], rb.out[p:])]
+ rb.out = rb.out[:p]
+ for padd--; padd >= 0; padd-- {
+ info = add[padd]
+ rb.insertUnsafe(inputBytes(cp), 0, info)
+ cp = cp[info.size:]
+ }
+}
diff --git a/src/vendor/golang_org/x/text/unicode/norm/readwriter.go b/src/vendor/golang_org/x/text/unicode/norm/readwriter.go
new file mode 100644
index 0000000..d926ee9
--- /dev/null
+++ b/src/vendor/golang_org/x/text/unicode/norm/readwriter.go
@@ -0,0 +1,125 @@
+// Copyright 2011 The Go Authors. 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
+
+import "io"
+
+type normWriter struct {
+ rb reorderBuffer
+ w io.Writer
+ buf []byte
+}
+
+// Write implements the standard write interface. If the last characters are
+// not at a normalization boundary, the bytes will be buffered for the next
+// write. The remaining bytes will be written on close.
+func (w *normWriter) Write(data []byte) (n int, err error) {
+ // Process data in pieces to keep w.buf size bounded.
+ const chunk = 4000
+
+ for len(data) > 0 {
+ // Normalize into w.buf.
+ m := len(data)
+ if m > chunk {
+ m = chunk
+ }
+ w.rb.src = inputBytes(data[:m])
+ w.rb.nsrc = m
+ w.buf = doAppend(&w.rb, w.buf, 0)
+ data = data[m:]
+ n += m
+
+ // Write out complete prefix, save remainder.
+ // Note that lastBoundary looks back at most 31 runes.
+ i := lastBoundary(&w.rb.f, w.buf)
+ if i == -1 {
+ i = 0
+ }
+ if i > 0 {
+ if _, err = w.w.Write(w.buf[:i]); err != nil {
+ break
+ }
+ bn := copy(w.buf, w.buf[i:])
+ w.buf = w.buf[:bn]
+ }
+ }
+ return n, err
+}
+
+// Close forces data that remains in the buffer to be written.
+func (w *normWriter) Close() error {
+ if len(w.buf) > 0 {
+ _, err := w.w.Write(w.buf)
+ if err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// Writer returns a new writer that implements Write(b)
+// by writing f(b) to w. The returned writer may use an
+// an internal buffer to maintain state across Write calls.
+// Calling its Close method writes any buffered data to w.
+func (f Form) Writer(w io.Writer) io.WriteCloser {
+ wr := &normWriter{rb: reorderBuffer{}, w: w}
+ wr.rb.init(f, nil)
+ return wr
+}
+
+type normReader struct {
+ rb reorderBuffer
+ r io.Reader
+ inbuf []byte
+ outbuf []byte
+ bufStart int
+ lastBoundary int
+ err error
+}
+
+// Read implements the standard read interface.
+func (r *normReader) Read(p []byte) (int, error) {
+ for {
+ if r.lastBoundary-r.bufStart > 0 {
+ n := copy(p, r.outbuf[r.bufStart:r.lastBoundary])
+ r.bufStart += n
+ if r.lastBoundary-r.bufStart > 0 {
+ return n, nil
+ }
+ return n, r.err
+ }
+ if r.err != nil {
+ return 0, r.err
+ }
+ outn := copy(r.outbuf, r.outbuf[r.lastBoundary:])
+ r.outbuf = r.outbuf[0:outn]
+ r.bufStart = 0
+
+ n, err := r.r.Read(r.inbuf)
+ r.rb.src = inputBytes(r.inbuf[0:n])
+ r.rb.nsrc, r.err = n, err
+ if n > 0 {
+ r.outbuf = doAppend(&r.rb, r.outbuf, 0)
+ }
+ if err == io.EOF {
+ r.lastBoundary = len(r.outbuf)
+ } else {
+ r.lastBoundary = lastBoundary(&r.rb.f, r.outbuf)
+ if r.lastBoundary == -1 {
+ r.lastBoundary = 0
+ }
+ }
+ }
+}
+
+// Reader returns a new reader that implements Read
+// by reading data from r and returning f(data).
+func (f Form) Reader(r io.Reader) io.Reader {
+ const chunk = 4000
+ buf := make([]byte, chunk)
+ rr := &normReader{rb: reorderBuffer{}, r: r, inbuf: buf}
+ rr.rb.init(f, buf)
+ return rr
+}
diff --git a/src/vendor/golang_org/x/text/unicode/norm/tables.go b/src/vendor/golang_org/x/text/unicode/norm/tables.go
new file mode 100644
index 0000000..a56697b
--- /dev/null
+++ b/src/vendor/golang_org/x/text/unicode/norm/tables.go
@@ -0,0 +1,7627 @@
+// This file was generated by go generate; DO NOT EDIT
+
+package norm
+
+const (
+ // Version is the Unicode edition from which the tables are derived.
+ Version = "9.0.0"
+
+ // MaxTransformChunkSize indicates the maximum number of bytes that Transform
+ // may need to write atomically for any Form. Making a destination buffer at
+ // least this size ensures that Transform can always make progress and that
+ // the user does not need to grow the buffer on an ErrShortDst.
+ MaxTransformChunkSize = 35 + maxNonStarters*4
+)
+
+var ccc = [55]uint8{
+ 0, 1, 7, 8, 9, 10, 11, 12,
+ 13, 14, 15, 16, 17, 18, 19, 20,
+ 21, 22, 23, 24, 25, 26, 27, 28,
+ 29, 30, 31, 32, 33, 34, 35, 36,
+ 84, 91, 103, 107, 118, 122, 129, 130,
+ 132, 202, 214, 216, 218, 220, 222, 224,
+ 226, 228, 230, 232, 233, 234, 240,
+}
+
+const (
+ firstMulti = 0x186D
+ firstCCC = 0x2C9E
+ endMulti = 0x2F60
+ firstLeadingCCC = 0x4A44
+ firstCCCZeroExcept = 0x4A5A
+ firstStarterWithNLead = 0x4A81
+ lastDecomp = 0x4A83
+ maxDecomp = 0x8000
+)
+
+// decomps: 19075 bytes
+var decomps = [...]byte{
+ // Bytes 0 - 3f
+ 0x00, 0x41, 0x20, 0x41, 0x21, 0x41, 0x22, 0x41,
+ 0x23, 0x41, 0x24, 0x41, 0x25, 0x41, 0x26, 0x41,
+ 0x27, 0x41, 0x28, 0x41, 0x29, 0x41, 0x2A, 0x41,
+ 0x2B, 0x41, 0x2C, 0x41, 0x2D, 0x41, 0x2E, 0x41,
+ 0x2F, 0x41, 0x30, 0x41, 0x31, 0x41, 0x32, 0x41,
+ 0x33, 0x41, 0x34, 0x41, 0x35, 0x41, 0x36, 0x41,
+ 0x37, 0x41, 0x38, 0x41, 0x39, 0x41, 0x3A, 0x41,
+ 0x3B, 0x41, 0x3C, 0x41, 0x3D, 0x41, 0x3E, 0x41,
+ // Bytes 40 - 7f
+ 0x3F, 0x41, 0x40, 0x41, 0x41, 0x41, 0x42, 0x41,
+ 0x43, 0x41, 0x44, 0x41, 0x45, 0x41, 0x46, 0x41,
+ 0x47, 0x41, 0x48, 0x41, 0x49, 0x41, 0x4A, 0x41,
+ 0x4B, 0x41, 0x4C, 0x41, 0x4D, 0x41, 0x4E, 0x41,
+ 0x4F, 0x41, 0x50, 0x41, 0x51, 0x41, 0x52, 0x41,
+ 0x53, 0x41, 0x54, 0x41, 0x55, 0x41, 0x56, 0x41,
+ 0x57, 0x41, 0x58, 0x41, 0x59, 0x41, 0x5A, 0x41,
+ 0x5B, 0x41, 0x5C, 0x41, 0x5D, 0x41, 0x5E, 0x41,
+ // Bytes 80 - bf
+ 0x5F, 0x41, 0x60, 0x41, 0x61, 0x41, 0x62, 0x41,
+ 0x63, 0x41, 0x64, 0x41, 0x65, 0x41, 0x66, 0x41,
+ 0x67, 0x41, 0x68, 0x41, 0x69, 0x41, 0x6A, 0x41,
+ 0x6B, 0x41, 0x6C, 0x41, 0x6D, 0x41, 0x6E, 0x41,
+ 0x6F, 0x41, 0x70, 0x41, 0x71, 0x41, 0x72, 0x41,
+ 0x73, 0x41, 0x74, 0x41, 0x75, 0x41, 0x76, 0x41,
+ 0x77, 0x41, 0x78, 0x41, 0x79, 0x41, 0x7A, 0x41,
+ 0x7B, 0x41, 0x7C, 0x41, 0x7D, 0x41, 0x7E, 0x42,
+ // Bytes c0 - ff
+ 0xC2, 0xA2, 0x42, 0xC2, 0xA3, 0x42, 0xC2, 0xA5,
+ 0x42, 0xC2, 0xA6, 0x42, 0xC2, 0xAC, 0x42, 0xC2,
+ 0xB7, 0x42, 0xC3, 0x86, 0x42, 0xC3, 0xB0, 0x42,
+ 0xC4, 0xA6, 0x42, 0xC4, 0xA7, 0x42, 0xC4, 0xB1,
+ 0x42, 0xC5, 0x8B, 0x42, 0xC5, 0x93, 0x42, 0xC6,
+ 0x8E, 0x42, 0xC6, 0x90, 0x42, 0xC6, 0xAB, 0x42,
+ 0xC8, 0xA2, 0x42, 0xC8, 0xB7, 0x42, 0xC9, 0x90,
+ 0x42, 0xC9, 0x91, 0x42, 0xC9, 0x92, 0x42, 0xC9,
+ // Bytes 100 - 13f
+ 0x94, 0x42, 0xC9, 0x95, 0x42, 0xC9, 0x99, 0x42,
+ 0xC9, 0x9B, 0x42, 0xC9, 0x9C, 0x42, 0xC9, 0x9F,
+ 0x42, 0xC9, 0xA1, 0x42, 0xC9, 0xA3, 0x42, 0xC9,
+ 0xA5, 0x42, 0xC9, 0xA6, 0x42, 0xC9, 0xA8, 0x42,
+ 0xC9, 0xA9, 0x42, 0xC9, 0xAA, 0x42, 0xC9, 0xAB,
+ 0x42, 0xC9, 0xAD, 0x42, 0xC9, 0xAF, 0x42, 0xC9,
+ 0xB0, 0x42, 0xC9, 0xB1, 0x42, 0xC9, 0xB2, 0x42,
+ 0xC9, 0xB3, 0x42, 0xC9, 0xB4, 0x42, 0xC9, 0xB5,
+ // Bytes 140 - 17f
+ 0x42, 0xC9, 0xB8, 0x42, 0xC9, 0xB9, 0x42, 0xC9,
+ 0xBB, 0x42, 0xCA, 0x81, 0x42, 0xCA, 0x82, 0x42,
+ 0xCA, 0x83, 0x42, 0xCA, 0x89, 0x42, 0xCA, 0x8A,
+ 0x42, 0xCA, 0x8B, 0x42, 0xCA, 0x8C, 0x42, 0xCA,
+ 0x90, 0x42, 0xCA, 0x91, 0x42, 0xCA, 0x92, 0x42,
+ 0xCA, 0x95, 0x42, 0xCA, 0x9D, 0x42, 0xCA, 0x9F,
+ 0x42, 0xCA, 0xB9, 0x42, 0xCE, 0x91, 0x42, 0xCE,
+ 0x92, 0x42, 0xCE, 0x93, 0x42, 0xCE, 0x94, 0x42,
+ // Bytes 180 - 1bf
+ 0xCE, 0x95, 0x42, 0xCE, 0x96, 0x42, 0xCE, 0x97,
+ 0x42, 0xCE, 0x98, 0x42, 0xCE, 0x99, 0x42, 0xCE,
+ 0x9A, 0x42, 0xCE, 0x9B, 0x42, 0xCE, 0x9C, 0x42,
+ 0xCE, 0x9D, 0x42, 0xCE, 0x9E, 0x42, 0xCE, 0x9F,
+ 0x42, 0xCE, 0xA0, 0x42, 0xCE, 0xA1, 0x42, 0xCE,
+ 0xA3, 0x42, 0xCE, 0xA4, 0x42, 0xCE, 0xA5, 0x42,
+ 0xCE, 0xA6, 0x42, 0xCE, 0xA7, 0x42, 0xCE, 0xA8,
+ 0x42, 0xCE, 0xA9, 0x42, 0xCE, 0xB1, 0x42, 0xCE,
+ // Bytes 1c0 - 1ff
+ 0xB2, 0x42, 0xCE, 0xB3, 0x42, 0xCE, 0xB4, 0x42,
+ 0xCE, 0xB5, 0x42, 0xCE, 0xB6, 0x42, 0xCE, 0xB7,
+ 0x42, 0xCE, 0xB8, 0x42, 0xCE, 0xB9, 0x42, 0xCE,
+ 0xBA, 0x42, 0xCE, 0xBB, 0x42, 0xCE, 0xBC, 0x42,
+ 0xCE, 0xBD, 0x42, 0xCE, 0xBE, 0x42, 0xCE, 0xBF,
+ 0x42, 0xCF, 0x80, 0x42, 0xCF, 0x81, 0x42, 0xCF,
+ 0x82, 0x42, 0xCF, 0x83, 0x42, 0xCF, 0x84, 0x42,
+ 0xCF, 0x85, 0x42, 0xCF, 0x86, 0x42, 0xCF, 0x87,
+ // Bytes 200 - 23f
+ 0x42, 0xCF, 0x88, 0x42, 0xCF, 0x89, 0x42, 0xCF,
+ 0x9C, 0x42, 0xCF, 0x9D, 0x42, 0xD0, 0xBD, 0x42,
+ 0xD1, 0x8A, 0x42, 0xD1, 0x8C, 0x42, 0xD7, 0x90,
+ 0x42, 0xD7, 0x91, 0x42, 0xD7, 0x92, 0x42, 0xD7,
+ 0x93, 0x42, 0xD7, 0x94, 0x42, 0xD7, 0x9B, 0x42,
+ 0xD7, 0x9C, 0x42, 0xD7, 0x9D, 0x42, 0xD7, 0xA2,
+ 0x42, 0xD7, 0xA8, 0x42, 0xD7, 0xAA, 0x42, 0xD8,
+ 0xA1, 0x42, 0xD8, 0xA7, 0x42, 0xD8, 0xA8, 0x42,
+ // Bytes 240 - 27f
+ 0xD8, 0xA9, 0x42, 0xD8, 0xAA, 0x42, 0xD8, 0xAB,
+ 0x42, 0xD8, 0xAC, 0x42, 0xD8, 0xAD, 0x42, 0xD8,
+ 0xAE, 0x42, 0xD8, 0xAF, 0x42, 0xD8, 0xB0, 0x42,
+ 0xD8, 0xB1, 0x42, 0xD8, 0xB2, 0x42, 0xD8, 0xB3,
+ 0x42, 0xD8, 0xB4, 0x42, 0xD8, 0xB5, 0x42, 0xD8,
+ 0xB6, 0x42, 0xD8, 0xB7, 0x42, 0xD8, 0xB8, 0x42,
+ 0xD8, 0xB9, 0x42, 0xD8, 0xBA, 0x42, 0xD9, 0x81,
+ 0x42, 0xD9, 0x82, 0x42, 0xD9, 0x83, 0x42, 0xD9,
+ // Bytes 280 - 2bf
+ 0x84, 0x42, 0xD9, 0x85, 0x42, 0xD9, 0x86, 0x42,
+ 0xD9, 0x87, 0x42, 0xD9, 0x88, 0x42, 0xD9, 0x89,
+ 0x42, 0xD9, 0x8A, 0x42, 0xD9, 0xAE, 0x42, 0xD9,
+ 0xAF, 0x42, 0xD9, 0xB1, 0x42, 0xD9, 0xB9, 0x42,
+ 0xD9, 0xBA, 0x42, 0xD9, 0xBB, 0x42, 0xD9, 0xBE,
+ 0x42, 0xD9, 0xBF, 0x42, 0xDA, 0x80, 0x42, 0xDA,
+ 0x83, 0x42, 0xDA, 0x84, 0x42, 0xDA, 0x86, 0x42,
+ 0xDA, 0x87, 0x42, 0xDA, 0x88, 0x42, 0xDA, 0x8C,
+ // Bytes 2c0 - 2ff
+ 0x42, 0xDA, 0x8D, 0x42, 0xDA, 0x8E, 0x42, 0xDA,
+ 0x91, 0x42, 0xDA, 0x98, 0x42, 0xDA, 0xA1, 0x42,
+ 0xDA, 0xA4, 0x42, 0xDA, 0xA6, 0x42, 0xDA, 0xA9,
+ 0x42, 0xDA, 0xAD, 0x42, 0xDA, 0xAF, 0x42, 0xDA,
+ 0xB1, 0x42, 0xDA, 0xB3, 0x42, 0xDA, 0xBA, 0x42,
+ 0xDA, 0xBB, 0x42, 0xDA, 0xBE, 0x42, 0xDB, 0x81,
+ 0x42, 0xDB, 0x85, 0x42, 0xDB, 0x86, 0x42, 0xDB,
+ 0x87, 0x42, 0xDB, 0x88, 0x42, 0xDB, 0x89, 0x42,
+ // Bytes 300 - 33f
+ 0xDB, 0x8B, 0x42, 0xDB, 0x8C, 0x42, 0xDB, 0x90,
+ 0x42, 0xDB, 0x92, 0x43, 0xE0, 0xBC, 0x8B, 0x43,
+ 0xE1, 0x83, 0x9C, 0x43, 0xE1, 0x84, 0x80, 0x43,
+ 0xE1, 0x84, 0x81, 0x43, 0xE1, 0x84, 0x82, 0x43,
+ 0xE1, 0x84, 0x83, 0x43, 0xE1, 0x84, 0x84, 0x43,
+ 0xE1, 0x84, 0x85, 0x43, 0xE1, 0x84, 0x86, 0x43,
+ 0xE1, 0x84, 0x87, 0x43, 0xE1, 0x84, 0x88, 0x43,
+ 0xE1, 0x84, 0x89, 0x43, 0xE1, 0x84, 0x8A, 0x43,
+ // Bytes 340 - 37f
+ 0xE1, 0x84, 0x8B, 0x43, 0xE1, 0x84, 0x8C, 0x43,
+ 0xE1, 0x84, 0x8D, 0x43, 0xE1, 0x84, 0x8E, 0x43,
+ 0xE1, 0x84, 0x8F, 0x43, 0xE1, 0x84, 0x90, 0x43,
+ 0xE1, 0x84, 0x91, 0x43, 0xE1, 0x84, 0x92, 0x43,
+ 0xE1, 0x84, 0x94, 0x43, 0xE1, 0x84, 0x95, 0x43,
+ 0xE1, 0x84, 0x9A, 0x43, 0xE1, 0x84, 0x9C, 0x43,
+ 0xE1, 0x84, 0x9D, 0x43, 0xE1, 0x84, 0x9E, 0x43,
+ 0xE1, 0x84, 0xA0, 0x43, 0xE1, 0x84, 0xA1, 0x43,
+ // Bytes 380 - 3bf
+ 0xE1, 0x84, 0xA2, 0x43, 0xE1, 0x84, 0xA3, 0x43,
+ 0xE1, 0x84, 0xA7, 0x43, 0xE1, 0x84, 0xA9, 0x43,
+ 0xE1, 0x84, 0xAB, 0x43, 0xE1, 0x84, 0xAC, 0x43,
+ 0xE1, 0x84, 0xAD, 0x43, 0xE1, 0x84, 0xAE, 0x43,
+ 0xE1, 0x84, 0xAF, 0x43, 0xE1, 0x84, 0xB2, 0x43,
+ 0xE1, 0x84, 0xB6, 0x43, 0xE1, 0x85, 0x80, 0x43,
+ 0xE1, 0x85, 0x87, 0x43, 0xE1, 0x85, 0x8C, 0x43,
+ 0xE1, 0x85, 0x97, 0x43, 0xE1, 0x85, 0x98, 0x43,
+ // Bytes 3c0 - 3ff
+ 0xE1, 0x85, 0x99, 0x43, 0xE1, 0x85, 0xA0, 0x43,
+ 0xE1, 0x86, 0x84, 0x43, 0xE1, 0x86, 0x85, 0x43,
+ 0xE1, 0x86, 0x88, 0x43, 0xE1, 0x86, 0x91, 0x43,
+ 0xE1, 0x86, 0x92, 0x43, 0xE1, 0x86, 0x94, 0x43,
+ 0xE1, 0x86, 0x9E, 0x43, 0xE1, 0x86, 0xA1, 0x43,
+ 0xE1, 0x87, 0x87, 0x43, 0xE1, 0x87, 0x88, 0x43,
+ 0xE1, 0x87, 0x8C, 0x43, 0xE1, 0x87, 0x8E, 0x43,
+ 0xE1, 0x87, 0x93, 0x43, 0xE1, 0x87, 0x97, 0x43,
+ // Bytes 400 - 43f
+ 0xE1, 0x87, 0x99, 0x43, 0xE1, 0x87, 0x9D, 0x43,
+ 0xE1, 0x87, 0x9F, 0x43, 0xE1, 0x87, 0xB1, 0x43,
+ 0xE1, 0x87, 0xB2, 0x43, 0xE1, 0xB4, 0x82, 0x43,
+ 0xE1, 0xB4, 0x96, 0x43, 0xE1, 0xB4, 0x97, 0x43,
+ 0xE1, 0xB4, 0x9C, 0x43, 0xE1, 0xB4, 0x9D, 0x43,
+ 0xE1, 0xB4, 0xA5, 0x43, 0xE1, 0xB5, 0xBB, 0x43,
+ 0xE1, 0xB6, 0x85, 0x43, 0xE2, 0x80, 0x82, 0x43,
+ 0xE2, 0x80, 0x83, 0x43, 0xE2, 0x80, 0x90, 0x43,
+ // Bytes 440 - 47f
+ 0xE2, 0x80, 0x93, 0x43, 0xE2, 0x80, 0x94, 0x43,
+ 0xE2, 0x82, 0xA9, 0x43, 0xE2, 0x86, 0x90, 0x43,
+ 0xE2, 0x86, 0x91, 0x43, 0xE2, 0x86, 0x92, 0x43,
+ 0xE2, 0x86, 0x93, 0x43, 0xE2, 0x88, 0x82, 0x43,
+ 0xE2, 0x88, 0x87, 0x43, 0xE2, 0x88, 0x91, 0x43,
+ 0xE2, 0x88, 0x92, 0x43, 0xE2, 0x94, 0x82, 0x43,
+ 0xE2, 0x96, 0xA0, 0x43, 0xE2, 0x97, 0x8B, 0x43,
+ 0xE2, 0xA6, 0x85, 0x43, 0xE2, 0xA6, 0x86, 0x43,
+ // Bytes 480 - 4bf
+ 0xE2, 0xB5, 0xA1, 0x43, 0xE3, 0x80, 0x81, 0x43,
+ 0xE3, 0x80, 0x82, 0x43, 0xE3, 0x80, 0x88, 0x43,
+ 0xE3, 0x80, 0x89, 0x43, 0xE3, 0x80, 0x8A, 0x43,
+ 0xE3, 0x80, 0x8B, 0x43, 0xE3, 0x80, 0x8C, 0x43,
+ 0xE3, 0x80, 0x8D, 0x43, 0xE3, 0x80, 0x8E, 0x43,
+ 0xE3, 0x80, 0x8F, 0x43, 0xE3, 0x80, 0x90, 0x43,
+ 0xE3, 0x80, 0x91, 0x43, 0xE3, 0x80, 0x92, 0x43,
+ 0xE3, 0x80, 0x94, 0x43, 0xE3, 0x80, 0x95, 0x43,
+ // Bytes 4c0 - 4ff
+ 0xE3, 0x80, 0x96, 0x43, 0xE3, 0x80, 0x97, 0x43,
+ 0xE3, 0x82, 0xA1, 0x43, 0xE3, 0x82, 0xA2, 0x43,
+ 0xE3, 0x82, 0xA3, 0x43, 0xE3, 0x82, 0xA4, 0x43,
+ 0xE3, 0x82, 0xA5, 0x43, 0xE3, 0x82, 0xA6, 0x43,
+ 0xE3, 0x82, 0xA7, 0x43, 0xE3, 0x82, 0xA8, 0x43,
+ 0xE3, 0x82, 0xA9, 0x43, 0xE3, 0x82, 0xAA, 0x43,
+ 0xE3, 0x82, 0xAB, 0x43, 0xE3, 0x82, 0xAD, 0x43,
+ 0xE3, 0x82, 0xAF, 0x43, 0xE3, 0x82, 0xB1, 0x43,
+ // Bytes 500 - 53f
+ 0xE3, 0x82, 0xB3, 0x43, 0xE3, 0x82, 0xB5, 0x43,
+ 0xE3, 0x82, 0xB7, 0x43, 0xE3, 0x82, 0xB9, 0x43,
+ 0xE3, 0x82, 0xBB, 0x43, 0xE3, 0x82, 0xBD, 0x43,
+ 0xE3, 0x82, 0xBF, 0x43, 0xE3, 0x83, 0x81, 0x43,
+ 0xE3, 0x83, 0x83, 0x43, 0xE3, 0x83, 0x84, 0x43,
+ 0xE3, 0x83, 0x86, 0x43, 0xE3, 0x83, 0x88, 0x43,
+ 0xE3, 0x83, 0x8A, 0x43, 0xE3, 0x83, 0x8B, 0x43,
+ 0xE3, 0x83, 0x8C, 0x43, 0xE3, 0x83, 0x8D, 0x43,
+ // Bytes 540 - 57f
+ 0xE3, 0x83, 0x8E, 0x43, 0xE3, 0x83, 0x8F, 0x43,
+ 0xE3, 0x83, 0x92, 0x43, 0xE3, 0x83, 0x95, 0x43,
+ 0xE3, 0x83, 0x98, 0x43, 0xE3, 0x83, 0x9B, 0x43,
+ 0xE3, 0x83, 0x9E, 0x43, 0xE3, 0x83, 0x9F, 0x43,
+ 0xE3, 0x83, 0xA0, 0x43, 0xE3, 0x83, 0xA1, 0x43,
+ 0xE3, 0x83, 0xA2, 0x43, 0xE3, 0x83, 0xA3, 0x43,
+ 0xE3, 0x83, 0xA4, 0x43, 0xE3, 0x83, 0xA5, 0x43,
+ 0xE3, 0x83, 0xA6, 0x43, 0xE3, 0x83, 0xA7, 0x43,
+ // Bytes 580 - 5bf
+ 0xE3, 0x83, 0xA8, 0x43, 0xE3, 0x83, 0xA9, 0x43,
+ 0xE3, 0x83, 0xAA, 0x43, 0xE3, 0x83, 0xAB, 0x43,
+ 0xE3, 0x83, 0xAC, 0x43, 0xE3, 0x83, 0xAD, 0x43,
+ 0xE3, 0x83, 0xAF, 0x43, 0xE3, 0x83, 0xB0, 0x43,
+ 0xE3, 0x83, 0xB1, 0x43, 0xE3, 0x83, 0xB2, 0x43,
+ 0xE3, 0x83, 0xB3, 0x43, 0xE3, 0x83, 0xBB, 0x43,
+ 0xE3, 0x83, 0xBC, 0x43, 0xE3, 0x92, 0x9E, 0x43,
+ 0xE3, 0x92, 0xB9, 0x43, 0xE3, 0x92, 0xBB, 0x43,
+ // Bytes 5c0 - 5ff
+ 0xE3, 0x93, 0x9F, 0x43, 0xE3, 0x94, 0x95, 0x43,
+ 0xE3, 0x9B, 0xAE, 0x43, 0xE3, 0x9B, 0xBC, 0x43,
+ 0xE3, 0x9E, 0x81, 0x43, 0xE3, 0xA0, 0xAF, 0x43,
+ 0xE3, 0xA1, 0xA2, 0x43, 0xE3, 0xA1, 0xBC, 0x43,
+ 0xE3, 0xA3, 0x87, 0x43, 0xE3, 0xA3, 0xA3, 0x43,
+ 0xE3, 0xA4, 0x9C, 0x43, 0xE3, 0xA4, 0xBA, 0x43,
+ 0xE3, 0xA8, 0xAE, 0x43, 0xE3, 0xA9, 0xAC, 0x43,
+ 0xE3, 0xAB, 0xA4, 0x43, 0xE3, 0xAC, 0x88, 0x43,
+ // Bytes 600 - 63f
+ 0xE3, 0xAC, 0x99, 0x43, 0xE3, 0xAD, 0x89, 0x43,
+ 0xE3, 0xAE, 0x9D, 0x43, 0xE3, 0xB0, 0x98, 0x43,
+ 0xE3, 0xB1, 0x8E, 0x43, 0xE3, 0xB4, 0xB3, 0x43,
+ 0xE3, 0xB6, 0x96, 0x43, 0xE3, 0xBA, 0xAC, 0x43,
+ 0xE3, 0xBA, 0xB8, 0x43, 0xE3, 0xBC, 0x9B, 0x43,
+ 0xE3, 0xBF, 0xBC, 0x43, 0xE4, 0x80, 0x88, 0x43,
+ 0xE4, 0x80, 0x98, 0x43, 0xE4, 0x80, 0xB9, 0x43,
+ 0xE4, 0x81, 0x86, 0x43, 0xE4, 0x82, 0x96, 0x43,
+ // Bytes 640 - 67f
+ 0xE4, 0x83, 0xA3, 0x43, 0xE4, 0x84, 0xAF, 0x43,
+ 0xE4, 0x88, 0x82, 0x43, 0xE4, 0x88, 0xA7, 0x43,
+ 0xE4, 0x8A, 0xA0, 0x43, 0xE4, 0x8C, 0x81, 0x43,
+ 0xE4, 0x8C, 0xB4, 0x43, 0xE4, 0x8D, 0x99, 0x43,
+ 0xE4, 0x8F, 0x95, 0x43, 0xE4, 0x8F, 0x99, 0x43,
+ 0xE4, 0x90, 0x8B, 0x43, 0xE4, 0x91, 0xAB, 0x43,
+ 0xE4, 0x94, 0xAB, 0x43, 0xE4, 0x95, 0x9D, 0x43,
+ 0xE4, 0x95, 0xA1, 0x43, 0xE4, 0x95, 0xAB, 0x43,
+ // Bytes 680 - 6bf
+ 0xE4, 0x97, 0x97, 0x43, 0xE4, 0x97, 0xB9, 0x43,
+ 0xE4, 0x98, 0xB5, 0x43, 0xE4, 0x9A, 0xBE, 0x43,
+ 0xE4, 0x9B, 0x87, 0x43, 0xE4, 0xA6, 0x95, 0x43,
+ 0xE4, 0xA7, 0xA6, 0x43, 0xE4, 0xA9, 0xAE, 0x43,
+ 0xE4, 0xA9, 0xB6, 0x43, 0xE4, 0xAA, 0xB2, 0x43,
+ 0xE4, 0xAC, 0xB3, 0x43, 0xE4, 0xAF, 0x8E, 0x43,
+ 0xE4, 0xB3, 0x8E, 0x43, 0xE4, 0xB3, 0xAD, 0x43,
+ 0xE4, 0xB3, 0xB8, 0x43, 0xE4, 0xB5, 0x96, 0x43,
+ // Bytes 6c0 - 6ff
+ 0xE4, 0xB8, 0x80, 0x43, 0xE4, 0xB8, 0x81, 0x43,
+ 0xE4, 0xB8, 0x83, 0x43, 0xE4, 0xB8, 0x89, 0x43,
+ 0xE4, 0xB8, 0x8A, 0x43, 0xE4, 0xB8, 0x8B, 0x43,
+ 0xE4, 0xB8, 0x8D, 0x43, 0xE4, 0xB8, 0x99, 0x43,
+ 0xE4, 0xB8, 0xA6, 0x43, 0xE4, 0xB8, 0xA8, 0x43,
+ 0xE4, 0xB8, 0xAD, 0x43, 0xE4, 0xB8, 0xB2, 0x43,
+ 0xE4, 0xB8, 0xB6, 0x43, 0xE4, 0xB8, 0xB8, 0x43,
+ 0xE4, 0xB8, 0xB9, 0x43, 0xE4, 0xB8, 0xBD, 0x43,
+ // Bytes 700 - 73f
+ 0xE4, 0xB8, 0xBF, 0x43, 0xE4, 0xB9, 0x81, 0x43,
+ 0xE4, 0xB9, 0x99, 0x43, 0xE4, 0xB9, 0x9D, 0x43,
+ 0xE4, 0xBA, 0x82, 0x43, 0xE4, 0xBA, 0x85, 0x43,
+ 0xE4, 0xBA, 0x86, 0x43, 0xE4, 0xBA, 0x8C, 0x43,
+ 0xE4, 0xBA, 0x94, 0x43, 0xE4, 0xBA, 0xA0, 0x43,
+ 0xE4, 0xBA, 0xA4, 0x43, 0xE4, 0xBA, 0xAE, 0x43,
+ 0xE4, 0xBA, 0xBA, 0x43, 0xE4, 0xBB, 0x80, 0x43,
+ 0xE4, 0xBB, 0x8C, 0x43, 0xE4, 0xBB, 0xA4, 0x43,
+ // Bytes 740 - 77f
+ 0xE4, 0xBC, 0x81, 0x43, 0xE4, 0xBC, 0x91, 0x43,
+ 0xE4, 0xBD, 0xA0, 0x43, 0xE4, 0xBE, 0x80, 0x43,
+ 0xE4, 0xBE, 0x86, 0x43, 0xE4, 0xBE, 0x8B, 0x43,
+ 0xE4, 0xBE, 0xAE, 0x43, 0xE4, 0xBE, 0xBB, 0x43,
+ 0xE4, 0xBE, 0xBF, 0x43, 0xE5, 0x80, 0x82, 0x43,
+ 0xE5, 0x80, 0xAB, 0x43, 0xE5, 0x81, 0xBA, 0x43,
+ 0xE5, 0x82, 0x99, 0x43, 0xE5, 0x83, 0x8F, 0x43,
+ 0xE5, 0x83, 0x9A, 0x43, 0xE5, 0x83, 0xA7, 0x43,
+ // Bytes 780 - 7bf
+ 0xE5, 0x84, 0xAA, 0x43, 0xE5, 0x84, 0xBF, 0x43,
+ 0xE5, 0x85, 0x80, 0x43, 0xE5, 0x85, 0x85, 0x43,
+ 0xE5, 0x85, 0x8D, 0x43, 0xE5, 0x85, 0x94, 0x43,
+ 0xE5, 0x85, 0xA4, 0x43, 0xE5, 0x85, 0xA5, 0x43,
+ 0xE5, 0x85, 0xA7, 0x43, 0xE5, 0x85, 0xA8, 0x43,
+ 0xE5, 0x85, 0xA9, 0x43, 0xE5, 0x85, 0xAB, 0x43,
+ 0xE5, 0x85, 0xAD, 0x43, 0xE5, 0x85, 0xB7, 0x43,
+ 0xE5, 0x86, 0x80, 0x43, 0xE5, 0x86, 0x82, 0x43,
+ // Bytes 7c0 - 7ff
+ 0xE5, 0x86, 0x8D, 0x43, 0xE5, 0x86, 0x92, 0x43,
+ 0xE5, 0x86, 0x95, 0x43, 0xE5, 0x86, 0x96, 0x43,
+ 0xE5, 0x86, 0x97, 0x43, 0xE5, 0x86, 0x99, 0x43,
+ 0xE5, 0x86, 0xA4, 0x43, 0xE5, 0x86, 0xAB, 0x43,
+ 0xE5, 0x86, 0xAC, 0x43, 0xE5, 0x86, 0xB5, 0x43,
+ 0xE5, 0x86, 0xB7, 0x43, 0xE5, 0x87, 0x89, 0x43,
+ 0xE5, 0x87, 0x8C, 0x43, 0xE5, 0x87, 0x9C, 0x43,
+ 0xE5, 0x87, 0x9E, 0x43, 0xE5, 0x87, 0xA0, 0x43,
+ // Bytes 800 - 83f
+ 0xE5, 0x87, 0xB5, 0x43, 0xE5, 0x88, 0x80, 0x43,
+ 0xE5, 0x88, 0x83, 0x43, 0xE5, 0x88, 0x87, 0x43,
+ 0xE5, 0x88, 0x97, 0x43, 0xE5, 0x88, 0x9D, 0x43,
+ 0xE5, 0x88, 0xA9, 0x43, 0xE5, 0x88, 0xBA, 0x43,
+ 0xE5, 0x88, 0xBB, 0x43, 0xE5, 0x89, 0x86, 0x43,
+ 0xE5, 0x89, 0x8D, 0x43, 0xE5, 0x89, 0xB2, 0x43,
+ 0xE5, 0x89, 0xB7, 0x43, 0xE5, 0x8A, 0x89, 0x43,
+ 0xE5, 0x8A, 0x9B, 0x43, 0xE5, 0x8A, 0xA3, 0x43,
+ // Bytes 840 - 87f
+ 0xE5, 0x8A, 0xB3, 0x43, 0xE5, 0x8A, 0xB4, 0x43,
+ 0xE5, 0x8B, 0x87, 0x43, 0xE5, 0x8B, 0x89, 0x43,
+ 0xE5, 0x8B, 0x92, 0x43, 0xE5, 0x8B, 0x9E, 0x43,
+ 0xE5, 0x8B, 0xA4, 0x43, 0xE5, 0x8B, 0xB5, 0x43,
+ 0xE5, 0x8B, 0xB9, 0x43, 0xE5, 0x8B, 0xBA, 0x43,
+ 0xE5, 0x8C, 0x85, 0x43, 0xE5, 0x8C, 0x86, 0x43,
+ 0xE5, 0x8C, 0x95, 0x43, 0xE5, 0x8C, 0x97, 0x43,
+ 0xE5, 0x8C, 0x9A, 0x43, 0xE5, 0x8C, 0xB8, 0x43,
+ // Bytes 880 - 8bf
+ 0xE5, 0x8C, 0xBB, 0x43, 0xE5, 0x8C, 0xBF, 0x43,
+ 0xE5, 0x8D, 0x81, 0x43, 0xE5, 0x8D, 0x84, 0x43,
+ 0xE5, 0x8D, 0x85, 0x43, 0xE5, 0x8D, 0x89, 0x43,
+ 0xE5, 0x8D, 0x91, 0x43, 0xE5, 0x8D, 0x94, 0x43,
+ 0xE5, 0x8D, 0x9A, 0x43, 0xE5, 0x8D, 0x9C, 0x43,
+ 0xE5, 0x8D, 0xA9, 0x43, 0xE5, 0x8D, 0xB0, 0x43,
+ 0xE5, 0x8D, 0xB3, 0x43, 0xE5, 0x8D, 0xB5, 0x43,
+ 0xE5, 0x8D, 0xBD, 0x43, 0xE5, 0x8D, 0xBF, 0x43,
+ // Bytes 8c0 - 8ff
+ 0xE5, 0x8E, 0x82, 0x43, 0xE5, 0x8E, 0xB6, 0x43,
+ 0xE5, 0x8F, 0x83, 0x43, 0xE5, 0x8F, 0x88, 0x43,
+ 0xE5, 0x8F, 0x8A, 0x43, 0xE5, 0x8F, 0x8C, 0x43,
+ 0xE5, 0x8F, 0x9F, 0x43, 0xE5, 0x8F, 0xA3, 0x43,
+ 0xE5, 0x8F, 0xA5, 0x43, 0xE5, 0x8F, 0xAB, 0x43,
+ 0xE5, 0x8F, 0xAF, 0x43, 0xE5, 0x8F, 0xB1, 0x43,
+ 0xE5, 0x8F, 0xB3, 0x43, 0xE5, 0x90, 0x86, 0x43,
+ 0xE5, 0x90, 0x88, 0x43, 0xE5, 0x90, 0x8D, 0x43,
+ // Bytes 900 - 93f
+ 0xE5, 0x90, 0x8F, 0x43, 0xE5, 0x90, 0x9D, 0x43,
+ 0xE5, 0x90, 0xB8, 0x43, 0xE5, 0x90, 0xB9, 0x43,
+ 0xE5, 0x91, 0x82, 0x43, 0xE5, 0x91, 0x88, 0x43,
+ 0xE5, 0x91, 0xA8, 0x43, 0xE5, 0x92, 0x9E, 0x43,
+ 0xE5, 0x92, 0xA2, 0x43, 0xE5, 0x92, 0xBD, 0x43,
+ 0xE5, 0x93, 0xB6, 0x43, 0xE5, 0x94, 0x90, 0x43,
+ 0xE5, 0x95, 0x8F, 0x43, 0xE5, 0x95, 0x93, 0x43,
+ 0xE5, 0x95, 0x95, 0x43, 0xE5, 0x95, 0xA3, 0x43,
+ // Bytes 940 - 97f
+ 0xE5, 0x96, 0x84, 0x43, 0xE5, 0x96, 0x87, 0x43,
+ 0xE5, 0x96, 0x99, 0x43, 0xE5, 0x96, 0x9D, 0x43,
+ 0xE5, 0x96, 0xAB, 0x43, 0xE5, 0x96, 0xB3, 0x43,
+ 0xE5, 0x96, 0xB6, 0x43, 0xE5, 0x97, 0x80, 0x43,
+ 0xE5, 0x97, 0x82, 0x43, 0xE5, 0x97, 0xA2, 0x43,
+ 0xE5, 0x98, 0x86, 0x43, 0xE5, 0x99, 0x91, 0x43,
+ 0xE5, 0x99, 0xA8, 0x43, 0xE5, 0x99, 0xB4, 0x43,
+ 0xE5, 0x9B, 0x97, 0x43, 0xE5, 0x9B, 0x9B, 0x43,
+ // Bytes 980 - 9bf
+ 0xE5, 0x9B, 0xB9, 0x43, 0xE5, 0x9C, 0x96, 0x43,
+ 0xE5, 0x9C, 0x97, 0x43, 0xE5, 0x9C, 0x9F, 0x43,
+ 0xE5, 0x9C, 0xB0, 0x43, 0xE5, 0x9E, 0x8B, 0x43,
+ 0xE5, 0x9F, 0x8E, 0x43, 0xE5, 0x9F, 0xB4, 0x43,
+ 0xE5, 0xA0, 0x8D, 0x43, 0xE5, 0xA0, 0xB1, 0x43,
+ 0xE5, 0xA0, 0xB2, 0x43, 0xE5, 0xA1, 0x80, 0x43,
+ 0xE5, 0xA1, 0x9A, 0x43, 0xE5, 0xA1, 0x9E, 0x43,
+ 0xE5, 0xA2, 0xA8, 0x43, 0xE5, 0xA2, 0xAC, 0x43,
+ // Bytes 9c0 - 9ff
+ 0xE5, 0xA2, 0xB3, 0x43, 0xE5, 0xA3, 0x98, 0x43,
+ 0xE5, 0xA3, 0x9F, 0x43, 0xE5, 0xA3, 0xAB, 0x43,
+ 0xE5, 0xA3, 0xAE, 0x43, 0xE5, 0xA3, 0xB0, 0x43,
+ 0xE5, 0xA3, 0xB2, 0x43, 0xE5, 0xA3, 0xB7, 0x43,
+ 0xE5, 0xA4, 0x82, 0x43, 0xE5, 0xA4, 0x86, 0x43,
+ 0xE5, 0xA4, 0x8A, 0x43, 0xE5, 0xA4, 0x95, 0x43,
+ 0xE5, 0xA4, 0x9A, 0x43, 0xE5, 0xA4, 0x9C, 0x43,
+ 0xE5, 0xA4, 0xA2, 0x43, 0xE5, 0xA4, 0xA7, 0x43,
+ // Bytes a00 - a3f
+ 0xE5, 0xA4, 0xA9, 0x43, 0xE5, 0xA5, 0x84, 0x43,
+ 0xE5, 0xA5, 0x88, 0x43, 0xE5, 0xA5, 0x91, 0x43,
+ 0xE5, 0xA5, 0x94, 0x43, 0xE5, 0xA5, 0xA2, 0x43,
+ 0xE5, 0xA5, 0xB3, 0x43, 0xE5, 0xA7, 0x98, 0x43,
+ 0xE5, 0xA7, 0xAC, 0x43, 0xE5, 0xA8, 0x9B, 0x43,
+ 0xE5, 0xA8, 0xA7, 0x43, 0xE5, 0xA9, 0xA2, 0x43,
+ 0xE5, 0xA9, 0xA6, 0x43, 0xE5, 0xAA, 0xB5, 0x43,
+ 0xE5, 0xAC, 0x88, 0x43, 0xE5, 0xAC, 0xA8, 0x43,
+ // Bytes a40 - a7f
+ 0xE5, 0xAC, 0xBE, 0x43, 0xE5, 0xAD, 0x90, 0x43,
+ 0xE5, 0xAD, 0x97, 0x43, 0xE5, 0xAD, 0xA6, 0x43,
+ 0xE5, 0xAE, 0x80, 0x43, 0xE5, 0xAE, 0x85, 0x43,
+ 0xE5, 0xAE, 0x97, 0x43, 0xE5, 0xAF, 0x83, 0x43,
+ 0xE5, 0xAF, 0x98, 0x43, 0xE5, 0xAF, 0xA7, 0x43,
+ 0xE5, 0xAF, 0xAE, 0x43, 0xE5, 0xAF, 0xB3, 0x43,
+ 0xE5, 0xAF, 0xB8, 0x43, 0xE5, 0xAF, 0xBF, 0x43,
+ 0xE5, 0xB0, 0x86, 0x43, 0xE5, 0xB0, 0x8F, 0x43,
+ // Bytes a80 - abf
+ 0xE5, 0xB0, 0xA2, 0x43, 0xE5, 0xB0, 0xB8, 0x43,
+ 0xE5, 0xB0, 0xBF, 0x43, 0xE5, 0xB1, 0xA0, 0x43,
+ 0xE5, 0xB1, 0xA2, 0x43, 0xE5, 0xB1, 0xA4, 0x43,
+ 0xE5, 0xB1, 0xA5, 0x43, 0xE5, 0xB1, 0xAE, 0x43,
+ 0xE5, 0xB1, 0xB1, 0x43, 0xE5, 0xB2, 0x8D, 0x43,
+ 0xE5, 0xB3, 0x80, 0x43, 0xE5, 0xB4, 0x99, 0x43,
+ 0xE5, 0xB5, 0x83, 0x43, 0xE5, 0xB5, 0x90, 0x43,
+ 0xE5, 0xB5, 0xAB, 0x43, 0xE5, 0xB5, 0xAE, 0x43,
+ // Bytes ac0 - aff
+ 0xE5, 0xB5, 0xBC, 0x43, 0xE5, 0xB6, 0xB2, 0x43,
+ 0xE5, 0xB6, 0xBA, 0x43, 0xE5, 0xB7, 0x9B, 0x43,
+ 0xE5, 0xB7, 0xA1, 0x43, 0xE5, 0xB7, 0xA2, 0x43,
+ 0xE5, 0xB7, 0xA5, 0x43, 0xE5, 0xB7, 0xA6, 0x43,
+ 0xE5, 0xB7, 0xB1, 0x43, 0xE5, 0xB7, 0xBD, 0x43,
+ 0xE5, 0xB7, 0xBE, 0x43, 0xE5, 0xB8, 0xA8, 0x43,
+ 0xE5, 0xB8, 0xBD, 0x43, 0xE5, 0xB9, 0xA9, 0x43,
+ 0xE5, 0xB9, 0xB2, 0x43, 0xE5, 0xB9, 0xB4, 0x43,
+ // Bytes b00 - b3f
+ 0xE5, 0xB9, 0xBA, 0x43, 0xE5, 0xB9, 0xBC, 0x43,
+ 0xE5, 0xB9, 0xBF, 0x43, 0xE5, 0xBA, 0xA6, 0x43,
+ 0xE5, 0xBA, 0xB0, 0x43, 0xE5, 0xBA, 0xB3, 0x43,
+ 0xE5, 0xBA, 0xB6, 0x43, 0xE5, 0xBB, 0x89, 0x43,
+ 0xE5, 0xBB, 0x8A, 0x43, 0xE5, 0xBB, 0x92, 0x43,
+ 0xE5, 0xBB, 0x93, 0x43, 0xE5, 0xBB, 0x99, 0x43,
+ 0xE5, 0xBB, 0xAC, 0x43, 0xE5, 0xBB, 0xB4, 0x43,
+ 0xE5, 0xBB, 0xBE, 0x43, 0xE5, 0xBC, 0x84, 0x43,
+ // Bytes b40 - b7f
+ 0xE5, 0xBC, 0x8B, 0x43, 0xE5, 0xBC, 0x93, 0x43,
+ 0xE5, 0xBC, 0xA2, 0x43, 0xE5, 0xBD, 0x90, 0x43,
+ 0xE5, 0xBD, 0x93, 0x43, 0xE5, 0xBD, 0xA1, 0x43,
+ 0xE5, 0xBD, 0xA2, 0x43, 0xE5, 0xBD, 0xA9, 0x43,
+ 0xE5, 0xBD, 0xAB, 0x43, 0xE5, 0xBD, 0xB3, 0x43,
+ 0xE5, 0xBE, 0x8B, 0x43, 0xE5, 0xBE, 0x8C, 0x43,
+ 0xE5, 0xBE, 0x97, 0x43, 0xE5, 0xBE, 0x9A, 0x43,
+ 0xE5, 0xBE, 0xA9, 0x43, 0xE5, 0xBE, 0xAD, 0x43,
+ // Bytes b80 - bbf
+ 0xE5, 0xBF, 0x83, 0x43, 0xE5, 0xBF, 0x8D, 0x43,
+ 0xE5, 0xBF, 0x97, 0x43, 0xE5, 0xBF, 0xB5, 0x43,
+ 0xE5, 0xBF, 0xB9, 0x43, 0xE6, 0x80, 0x92, 0x43,
+ 0xE6, 0x80, 0x9C, 0x43, 0xE6, 0x81, 0xB5, 0x43,
+ 0xE6, 0x82, 0x81, 0x43, 0xE6, 0x82, 0x94, 0x43,
+ 0xE6, 0x83, 0x87, 0x43, 0xE6, 0x83, 0x98, 0x43,
+ 0xE6, 0x83, 0xA1, 0x43, 0xE6, 0x84, 0x88, 0x43,
+ 0xE6, 0x85, 0x84, 0x43, 0xE6, 0x85, 0x88, 0x43,
+ // Bytes bc0 - bff
+ 0xE6, 0x85, 0x8C, 0x43, 0xE6, 0x85, 0x8E, 0x43,
+ 0xE6, 0x85, 0xA0, 0x43, 0xE6, 0x85, 0xA8, 0x43,
+ 0xE6, 0x85, 0xBA, 0x43, 0xE6, 0x86, 0x8E, 0x43,
+ 0xE6, 0x86, 0x90, 0x43, 0xE6, 0x86, 0xA4, 0x43,
+ 0xE6, 0x86, 0xAF, 0x43, 0xE6, 0x86, 0xB2, 0x43,
+ 0xE6, 0x87, 0x9E, 0x43, 0xE6, 0x87, 0xB2, 0x43,
+ 0xE6, 0x87, 0xB6, 0x43, 0xE6, 0x88, 0x80, 0x43,
+ 0xE6, 0x88, 0x88, 0x43, 0xE6, 0x88, 0x90, 0x43,
+ // Bytes c00 - c3f
+ 0xE6, 0x88, 0x9B, 0x43, 0xE6, 0x88, 0xAE, 0x43,
+ 0xE6, 0x88, 0xB4, 0x43, 0xE6, 0x88, 0xB6, 0x43,
+ 0xE6, 0x89, 0x8B, 0x43, 0xE6, 0x89, 0x93, 0x43,
+ 0xE6, 0x89, 0x9D, 0x43, 0xE6, 0x8A, 0x95, 0x43,
+ 0xE6, 0x8A, 0xB1, 0x43, 0xE6, 0x8B, 0x89, 0x43,
+ 0xE6, 0x8B, 0x8F, 0x43, 0xE6, 0x8B, 0x93, 0x43,
+ 0xE6, 0x8B, 0x94, 0x43, 0xE6, 0x8B, 0xBC, 0x43,
+ 0xE6, 0x8B, 0xBE, 0x43, 0xE6, 0x8C, 0x87, 0x43,
+ // Bytes c40 - c7f
+ 0xE6, 0x8C, 0xBD, 0x43, 0xE6, 0x8D, 0x90, 0x43,
+ 0xE6, 0x8D, 0x95, 0x43, 0xE6, 0x8D, 0xA8, 0x43,
+ 0xE6, 0x8D, 0xBB, 0x43, 0xE6, 0x8E, 0x83, 0x43,
+ 0xE6, 0x8E, 0xA0, 0x43, 0xE6, 0x8E, 0xA9, 0x43,
+ 0xE6, 0x8F, 0x84, 0x43, 0xE6, 0x8F, 0x85, 0x43,
+ 0xE6, 0x8F, 0xA4, 0x43, 0xE6, 0x90, 0x9C, 0x43,
+ 0xE6, 0x90, 0xA2, 0x43, 0xE6, 0x91, 0x92, 0x43,
+ 0xE6, 0x91, 0xA9, 0x43, 0xE6, 0x91, 0xB7, 0x43,
+ // Bytes c80 - cbf
+ 0xE6, 0x91, 0xBE, 0x43, 0xE6, 0x92, 0x9A, 0x43,
+ 0xE6, 0x92, 0x9D, 0x43, 0xE6, 0x93, 0x84, 0x43,
+ 0xE6, 0x94, 0xAF, 0x43, 0xE6, 0x94, 0xB4, 0x43,
+ 0xE6, 0x95, 0x8F, 0x43, 0xE6, 0x95, 0x96, 0x43,
+ 0xE6, 0x95, 0xAC, 0x43, 0xE6, 0x95, 0xB8, 0x43,
+ 0xE6, 0x96, 0x87, 0x43, 0xE6, 0x96, 0x97, 0x43,
+ 0xE6, 0x96, 0x99, 0x43, 0xE6, 0x96, 0xA4, 0x43,
+ 0xE6, 0x96, 0xB0, 0x43, 0xE6, 0x96, 0xB9, 0x43,
+ // Bytes cc0 - cff
+ 0xE6, 0x97, 0x85, 0x43, 0xE6, 0x97, 0xA0, 0x43,
+ 0xE6, 0x97, 0xA2, 0x43, 0xE6, 0x97, 0xA3, 0x43,
+ 0xE6, 0x97, 0xA5, 0x43, 0xE6, 0x98, 0x93, 0x43,
+ 0xE6, 0x98, 0xA0, 0x43, 0xE6, 0x99, 0x89, 0x43,
+ 0xE6, 0x99, 0xB4, 0x43, 0xE6, 0x9A, 0x88, 0x43,
+ 0xE6, 0x9A, 0x91, 0x43, 0xE6, 0x9A, 0x9C, 0x43,
+ 0xE6, 0x9A, 0xB4, 0x43, 0xE6, 0x9B, 0x86, 0x43,
+ 0xE6, 0x9B, 0xB0, 0x43, 0xE6, 0x9B, 0xB4, 0x43,
+ // Bytes d00 - d3f
+ 0xE6, 0x9B, 0xB8, 0x43, 0xE6, 0x9C, 0x80, 0x43,
+ 0xE6, 0x9C, 0x88, 0x43, 0xE6, 0x9C, 0x89, 0x43,
+ 0xE6, 0x9C, 0x97, 0x43, 0xE6, 0x9C, 0x9B, 0x43,
+ 0xE6, 0x9C, 0xA1, 0x43, 0xE6, 0x9C, 0xA8, 0x43,
+ 0xE6, 0x9D, 0x8E, 0x43, 0xE6, 0x9D, 0x93, 0x43,
+ 0xE6, 0x9D, 0x96, 0x43, 0xE6, 0x9D, 0x9E, 0x43,
+ 0xE6, 0x9D, 0xBB, 0x43, 0xE6, 0x9E, 0x85, 0x43,
+ 0xE6, 0x9E, 0x97, 0x43, 0xE6, 0x9F, 0xB3, 0x43,
+ // Bytes d40 - d7f
+ 0xE6, 0x9F, 0xBA, 0x43, 0xE6, 0xA0, 0x97, 0x43,
+ 0xE6, 0xA0, 0x9F, 0x43, 0xE6, 0xA0, 0xAA, 0x43,
+ 0xE6, 0xA1, 0x92, 0x43, 0xE6, 0xA2, 0x81, 0x43,
+ 0xE6, 0xA2, 0x85, 0x43, 0xE6, 0xA2, 0x8E, 0x43,
+ 0xE6, 0xA2, 0xA8, 0x43, 0xE6, 0xA4, 0x94, 0x43,
+ 0xE6, 0xA5, 0x82, 0x43, 0xE6, 0xA6, 0xA3, 0x43,
+ 0xE6, 0xA7, 0xAA, 0x43, 0xE6, 0xA8, 0x82, 0x43,
+ 0xE6, 0xA8, 0x93, 0x43, 0xE6, 0xAA, 0xA8, 0x43,
+ // Bytes d80 - dbf
+ 0xE6, 0xAB, 0x93, 0x43, 0xE6, 0xAB, 0x9B, 0x43,
+ 0xE6, 0xAC, 0x84, 0x43, 0xE6, 0xAC, 0xA0, 0x43,
+ 0xE6, 0xAC, 0xA1, 0x43, 0xE6, 0xAD, 0x94, 0x43,
+ 0xE6, 0xAD, 0xA2, 0x43, 0xE6, 0xAD, 0xA3, 0x43,
+ 0xE6, 0xAD, 0xB2, 0x43, 0xE6, 0xAD, 0xB7, 0x43,
+ 0xE6, 0xAD, 0xB9, 0x43, 0xE6, 0xAE, 0x9F, 0x43,
+ 0xE6, 0xAE, 0xAE, 0x43, 0xE6, 0xAE, 0xB3, 0x43,
+ 0xE6, 0xAE, 0xBA, 0x43, 0xE6, 0xAE, 0xBB, 0x43,
+ // Bytes dc0 - dff
+ 0xE6, 0xAF, 0x8B, 0x43, 0xE6, 0xAF, 0x8D, 0x43,
+ 0xE6, 0xAF, 0x94, 0x43, 0xE6, 0xAF, 0x9B, 0x43,
+ 0xE6, 0xB0, 0x8F, 0x43, 0xE6, 0xB0, 0x94, 0x43,
+ 0xE6, 0xB0, 0xB4, 0x43, 0xE6, 0xB1, 0x8E, 0x43,
+ 0xE6, 0xB1, 0xA7, 0x43, 0xE6, 0xB2, 0x88, 0x43,
+ 0xE6, 0xB2, 0xBF, 0x43, 0xE6, 0xB3, 0x8C, 0x43,
+ 0xE6, 0xB3, 0x8D, 0x43, 0xE6, 0xB3, 0xA5, 0x43,
+ 0xE6, 0xB3, 0xA8, 0x43, 0xE6, 0xB4, 0x96, 0x43,
+ // Bytes e00 - e3f
+ 0xE6, 0xB4, 0x9B, 0x43, 0xE6, 0xB4, 0x9E, 0x43,
+ 0xE6, 0xB4, 0xB4, 0x43, 0xE6, 0xB4, 0xBE, 0x43,
+ 0xE6, 0xB5, 0x81, 0x43, 0xE6, 0xB5, 0xA9, 0x43,
+ 0xE6, 0xB5, 0xAA, 0x43, 0xE6, 0xB5, 0xB7, 0x43,
+ 0xE6, 0xB5, 0xB8, 0x43, 0xE6, 0xB6, 0x85, 0x43,
+ 0xE6, 0xB7, 0x8B, 0x43, 0xE6, 0xB7, 0x9A, 0x43,
+ 0xE6, 0xB7, 0xAA, 0x43, 0xE6, 0xB7, 0xB9, 0x43,
+ 0xE6, 0xB8, 0x9A, 0x43, 0xE6, 0xB8, 0xAF, 0x43,
+ // Bytes e40 - e7f
+ 0xE6, 0xB9, 0xAE, 0x43, 0xE6, 0xBA, 0x80, 0x43,
+ 0xE6, 0xBA, 0x9C, 0x43, 0xE6, 0xBA, 0xBA, 0x43,
+ 0xE6, 0xBB, 0x87, 0x43, 0xE6, 0xBB, 0x8B, 0x43,
+ 0xE6, 0xBB, 0x91, 0x43, 0xE6, 0xBB, 0x9B, 0x43,
+ 0xE6, 0xBC, 0x8F, 0x43, 0xE6, 0xBC, 0x94, 0x43,
+ 0xE6, 0xBC, 0xA2, 0x43, 0xE6, 0xBC, 0xA3, 0x43,
+ 0xE6, 0xBD, 0xAE, 0x43, 0xE6, 0xBF, 0x86, 0x43,
+ 0xE6, 0xBF, 0xAB, 0x43, 0xE6, 0xBF, 0xBE, 0x43,
+ // Bytes e80 - ebf
+ 0xE7, 0x80, 0x9B, 0x43, 0xE7, 0x80, 0x9E, 0x43,
+ 0xE7, 0x80, 0xB9, 0x43, 0xE7, 0x81, 0x8A, 0x43,
+ 0xE7, 0x81, 0xAB, 0x43, 0xE7, 0x81, 0xB0, 0x43,
+ 0xE7, 0x81, 0xB7, 0x43, 0xE7, 0x81, 0xBD, 0x43,
+ 0xE7, 0x82, 0x99, 0x43, 0xE7, 0x82, 0xAD, 0x43,
+ 0xE7, 0x83, 0x88, 0x43, 0xE7, 0x83, 0x99, 0x43,
+ 0xE7, 0x84, 0xA1, 0x43, 0xE7, 0x85, 0x85, 0x43,
+ 0xE7, 0x85, 0x89, 0x43, 0xE7, 0x85, 0xAE, 0x43,
+ // Bytes ec0 - eff
+ 0xE7, 0x86, 0x9C, 0x43, 0xE7, 0x87, 0x8E, 0x43,
+ 0xE7, 0x87, 0x90, 0x43, 0xE7, 0x88, 0x90, 0x43,
+ 0xE7, 0x88, 0x9B, 0x43, 0xE7, 0x88, 0xA8, 0x43,
+ 0xE7, 0x88, 0xAA, 0x43, 0xE7, 0x88, 0xAB, 0x43,
+ 0xE7, 0x88, 0xB5, 0x43, 0xE7, 0x88, 0xB6, 0x43,
+ 0xE7, 0x88, 0xBB, 0x43, 0xE7, 0x88, 0xBF, 0x43,
+ 0xE7, 0x89, 0x87, 0x43, 0xE7, 0x89, 0x90, 0x43,
+ 0xE7, 0x89, 0x99, 0x43, 0xE7, 0x89, 0x9B, 0x43,
+ // Bytes f00 - f3f
+ 0xE7, 0x89, 0xA2, 0x43, 0xE7, 0x89, 0xB9, 0x43,
+ 0xE7, 0x8A, 0x80, 0x43, 0xE7, 0x8A, 0x95, 0x43,
+ 0xE7, 0x8A, 0xAC, 0x43, 0xE7, 0x8A, 0xAF, 0x43,
+ 0xE7, 0x8B, 0x80, 0x43, 0xE7, 0x8B, 0xBC, 0x43,
+ 0xE7, 0x8C, 0xAA, 0x43, 0xE7, 0x8D, 0xB5, 0x43,
+ 0xE7, 0x8D, 0xBA, 0x43, 0xE7, 0x8E, 0x84, 0x43,
+ 0xE7, 0x8E, 0x87, 0x43, 0xE7, 0x8E, 0x89, 0x43,
+ 0xE7, 0x8E, 0x8B, 0x43, 0xE7, 0x8E, 0xA5, 0x43,
+ // Bytes f40 - f7f
+ 0xE7, 0x8E, 0xB2, 0x43, 0xE7, 0x8F, 0x9E, 0x43,
+ 0xE7, 0x90, 0x86, 0x43, 0xE7, 0x90, 0x89, 0x43,
+ 0xE7, 0x90, 0xA2, 0x43, 0xE7, 0x91, 0x87, 0x43,
+ 0xE7, 0x91, 0x9C, 0x43, 0xE7, 0x91, 0xA9, 0x43,
+ 0xE7, 0x91, 0xB1, 0x43, 0xE7, 0x92, 0x85, 0x43,
+ 0xE7, 0x92, 0x89, 0x43, 0xE7, 0x92, 0x98, 0x43,
+ 0xE7, 0x93, 0x8A, 0x43, 0xE7, 0x93, 0x9C, 0x43,
+ 0xE7, 0x93, 0xA6, 0x43, 0xE7, 0x94, 0x86, 0x43,
+ // Bytes f80 - fbf
+ 0xE7, 0x94, 0x98, 0x43, 0xE7, 0x94, 0x9F, 0x43,
+ 0xE7, 0x94, 0xA4, 0x43, 0xE7, 0x94, 0xA8, 0x43,
+ 0xE7, 0x94, 0xB0, 0x43, 0xE7, 0x94, 0xB2, 0x43,
+ 0xE7, 0x94, 0xB3, 0x43, 0xE7, 0x94, 0xB7, 0x43,
+ 0xE7, 0x94, 0xBB, 0x43, 0xE7, 0x94, 0xBE, 0x43,
+ 0xE7, 0x95, 0x99, 0x43, 0xE7, 0x95, 0xA5, 0x43,
+ 0xE7, 0x95, 0xB0, 0x43, 0xE7, 0x96, 0x8B, 0x43,
+ 0xE7, 0x96, 0x92, 0x43, 0xE7, 0x97, 0xA2, 0x43,
+ // Bytes fc0 - fff
+ 0xE7, 0x98, 0x90, 0x43, 0xE7, 0x98, 0x9D, 0x43,
+ 0xE7, 0x98, 0x9F, 0x43, 0xE7, 0x99, 0x82, 0x43,
+ 0xE7, 0x99, 0xA9, 0x43, 0xE7, 0x99, 0xB6, 0x43,
+ 0xE7, 0x99, 0xBD, 0x43, 0xE7, 0x9A, 0xAE, 0x43,
+ 0xE7, 0x9A, 0xBF, 0x43, 0xE7, 0x9B, 0x8A, 0x43,
+ 0xE7, 0x9B, 0x9B, 0x43, 0xE7, 0x9B, 0xA3, 0x43,
+ 0xE7, 0x9B, 0xA7, 0x43, 0xE7, 0x9B, 0xAE, 0x43,
+ 0xE7, 0x9B, 0xB4, 0x43, 0xE7, 0x9C, 0x81, 0x43,
+ // Bytes 1000 - 103f
+ 0xE7, 0x9C, 0x9E, 0x43, 0xE7, 0x9C, 0x9F, 0x43,
+ 0xE7, 0x9D, 0x80, 0x43, 0xE7, 0x9D, 0x8A, 0x43,
+ 0xE7, 0x9E, 0x8B, 0x43, 0xE7, 0x9E, 0xA7, 0x43,
+ 0xE7, 0x9F, 0x9B, 0x43, 0xE7, 0x9F, 0xA2, 0x43,
+ 0xE7, 0x9F, 0xB3, 0x43, 0xE7, 0xA1, 0x8E, 0x43,
+ 0xE7, 0xA1, 0xAB, 0x43, 0xE7, 0xA2, 0x8C, 0x43,
+ 0xE7, 0xA2, 0x91, 0x43, 0xE7, 0xA3, 0x8A, 0x43,
+ 0xE7, 0xA3, 0x8C, 0x43, 0xE7, 0xA3, 0xBB, 0x43,
+ // Bytes 1040 - 107f
+ 0xE7, 0xA4, 0xAA, 0x43, 0xE7, 0xA4, 0xBA, 0x43,
+ 0xE7, 0xA4, 0xBC, 0x43, 0xE7, 0xA4, 0xBE, 0x43,
+ 0xE7, 0xA5, 0x88, 0x43, 0xE7, 0xA5, 0x89, 0x43,
+ 0xE7, 0xA5, 0x90, 0x43, 0xE7, 0xA5, 0x96, 0x43,
+ 0xE7, 0xA5, 0x9D, 0x43, 0xE7, 0xA5, 0x9E, 0x43,
+ 0xE7, 0xA5, 0xA5, 0x43, 0xE7, 0xA5, 0xBF, 0x43,
+ 0xE7, 0xA6, 0x81, 0x43, 0xE7, 0xA6, 0x8D, 0x43,
+ 0xE7, 0xA6, 0x8E, 0x43, 0xE7, 0xA6, 0x8F, 0x43,
+ // Bytes 1080 - 10bf
+ 0xE7, 0xA6, 0xAE, 0x43, 0xE7, 0xA6, 0xB8, 0x43,
+ 0xE7, 0xA6, 0xBE, 0x43, 0xE7, 0xA7, 0x8A, 0x43,
+ 0xE7, 0xA7, 0x98, 0x43, 0xE7, 0xA7, 0xAB, 0x43,
+ 0xE7, 0xA8, 0x9C, 0x43, 0xE7, 0xA9, 0x80, 0x43,
+ 0xE7, 0xA9, 0x8A, 0x43, 0xE7, 0xA9, 0x8F, 0x43,
+ 0xE7, 0xA9, 0xB4, 0x43, 0xE7, 0xA9, 0xBA, 0x43,
+ 0xE7, 0xAA, 0x81, 0x43, 0xE7, 0xAA, 0xB1, 0x43,
+ 0xE7, 0xAB, 0x8B, 0x43, 0xE7, 0xAB, 0xAE, 0x43,
+ // Bytes 10c0 - 10ff
+ 0xE7, 0xAB, 0xB9, 0x43, 0xE7, 0xAC, 0xA0, 0x43,
+ 0xE7, 0xAE, 0x8F, 0x43, 0xE7, 0xAF, 0x80, 0x43,
+ 0xE7, 0xAF, 0x86, 0x43, 0xE7, 0xAF, 0x89, 0x43,
+ 0xE7, 0xB0, 0xBE, 0x43, 0xE7, 0xB1, 0xA0, 0x43,
+ 0xE7, 0xB1, 0xB3, 0x43, 0xE7, 0xB1, 0xBB, 0x43,
+ 0xE7, 0xB2, 0x92, 0x43, 0xE7, 0xB2, 0xBE, 0x43,
+ 0xE7, 0xB3, 0x92, 0x43, 0xE7, 0xB3, 0x96, 0x43,
+ 0xE7, 0xB3, 0xA3, 0x43, 0xE7, 0xB3, 0xA7, 0x43,
+ // Bytes 1100 - 113f
+ 0xE7, 0xB3, 0xA8, 0x43, 0xE7, 0xB3, 0xB8, 0x43,
+ 0xE7, 0xB4, 0x80, 0x43, 0xE7, 0xB4, 0x90, 0x43,
+ 0xE7, 0xB4, 0xA2, 0x43, 0xE7, 0xB4, 0xAF, 0x43,
+ 0xE7, 0xB5, 0x82, 0x43, 0xE7, 0xB5, 0x9B, 0x43,
+ 0xE7, 0xB5, 0xA3, 0x43, 0xE7, 0xB6, 0xA0, 0x43,
+ 0xE7, 0xB6, 0xBE, 0x43, 0xE7, 0xB7, 0x87, 0x43,
+ 0xE7, 0xB7, 0xB4, 0x43, 0xE7, 0xB8, 0x82, 0x43,
+ 0xE7, 0xB8, 0x89, 0x43, 0xE7, 0xB8, 0xB7, 0x43,
+ // Bytes 1140 - 117f
+ 0xE7, 0xB9, 0x81, 0x43, 0xE7, 0xB9, 0x85, 0x43,
+ 0xE7, 0xBC, 0xB6, 0x43, 0xE7, 0xBC, 0xBE, 0x43,
+ 0xE7, 0xBD, 0x91, 0x43, 0xE7, 0xBD, 0xB2, 0x43,
+ 0xE7, 0xBD, 0xB9, 0x43, 0xE7, 0xBD, 0xBA, 0x43,
+ 0xE7, 0xBE, 0x85, 0x43, 0xE7, 0xBE, 0x8A, 0x43,
+ 0xE7, 0xBE, 0x95, 0x43, 0xE7, 0xBE, 0x9A, 0x43,
+ 0xE7, 0xBE, 0xBD, 0x43, 0xE7, 0xBF, 0xBA, 0x43,
+ 0xE8, 0x80, 0x81, 0x43, 0xE8, 0x80, 0x85, 0x43,
+ // Bytes 1180 - 11bf
+ 0xE8, 0x80, 0x8C, 0x43, 0xE8, 0x80, 0x92, 0x43,
+ 0xE8, 0x80, 0xB3, 0x43, 0xE8, 0x81, 0x86, 0x43,
+ 0xE8, 0x81, 0xA0, 0x43, 0xE8, 0x81, 0xAF, 0x43,
+ 0xE8, 0x81, 0xB0, 0x43, 0xE8, 0x81, 0xBE, 0x43,
+ 0xE8, 0x81, 0xBF, 0x43, 0xE8, 0x82, 0x89, 0x43,
+ 0xE8, 0x82, 0x8B, 0x43, 0xE8, 0x82, 0xAD, 0x43,
+ 0xE8, 0x82, 0xB2, 0x43, 0xE8, 0x84, 0x83, 0x43,
+ 0xE8, 0x84, 0xBE, 0x43, 0xE8, 0x87, 0x98, 0x43,
+ // Bytes 11c0 - 11ff
+ 0xE8, 0x87, 0xA3, 0x43, 0xE8, 0x87, 0xA8, 0x43,
+ 0xE8, 0x87, 0xAA, 0x43, 0xE8, 0x87, 0xAD, 0x43,
+ 0xE8, 0x87, 0xB3, 0x43, 0xE8, 0x87, 0xBC, 0x43,
+ 0xE8, 0x88, 0x81, 0x43, 0xE8, 0x88, 0x84, 0x43,
+ 0xE8, 0x88, 0x8C, 0x43, 0xE8, 0x88, 0x98, 0x43,
+ 0xE8, 0x88, 0x9B, 0x43, 0xE8, 0x88, 0x9F, 0x43,
+ 0xE8, 0x89, 0xAE, 0x43, 0xE8, 0x89, 0xAF, 0x43,
+ 0xE8, 0x89, 0xB2, 0x43, 0xE8, 0x89, 0xB8, 0x43,
+ // Bytes 1200 - 123f
+ 0xE8, 0x89, 0xB9, 0x43, 0xE8, 0x8A, 0x8B, 0x43,
+ 0xE8, 0x8A, 0x91, 0x43, 0xE8, 0x8A, 0x9D, 0x43,
+ 0xE8, 0x8A, 0xB1, 0x43, 0xE8, 0x8A, 0xB3, 0x43,
+ 0xE8, 0x8A, 0xBD, 0x43, 0xE8, 0x8B, 0xA5, 0x43,
+ 0xE8, 0x8B, 0xA6, 0x43, 0xE8, 0x8C, 0x9D, 0x43,
+ 0xE8, 0x8C, 0xA3, 0x43, 0xE8, 0x8C, 0xB6, 0x43,
+ 0xE8, 0x8D, 0x92, 0x43, 0xE8, 0x8D, 0x93, 0x43,
+ 0xE8, 0x8D, 0xA3, 0x43, 0xE8, 0x8E, 0xAD, 0x43,
+ // Bytes 1240 - 127f
+ 0xE8, 0x8E, 0xBD, 0x43, 0xE8, 0x8F, 0x89, 0x43,
+ 0xE8, 0x8F, 0x8A, 0x43, 0xE8, 0x8F, 0x8C, 0x43,
+ 0xE8, 0x8F, 0x9C, 0x43, 0xE8, 0x8F, 0xA7, 0x43,
+ 0xE8, 0x8F, 0xAF, 0x43, 0xE8, 0x8F, 0xB1, 0x43,
+ 0xE8, 0x90, 0xBD, 0x43, 0xE8, 0x91, 0x89, 0x43,
+ 0xE8, 0x91, 0x97, 0x43, 0xE8, 0x93, 0xAE, 0x43,
+ 0xE8, 0x93, 0xB1, 0x43, 0xE8, 0x93, 0xB3, 0x43,
+ 0xE8, 0x93, 0xBC, 0x43, 0xE8, 0x94, 0x96, 0x43,
+ // Bytes 1280 - 12bf
+ 0xE8, 0x95, 0xA4, 0x43, 0xE8, 0x97, 0x8D, 0x43,
+ 0xE8, 0x97, 0xBA, 0x43, 0xE8, 0x98, 0x86, 0x43,
+ 0xE8, 0x98, 0x92, 0x43, 0xE8, 0x98, 0xAD, 0x43,
+ 0xE8, 0x98, 0xBF, 0x43, 0xE8, 0x99, 0x8D, 0x43,
+ 0xE8, 0x99, 0x90, 0x43, 0xE8, 0x99, 0x9C, 0x43,
+ 0xE8, 0x99, 0xA7, 0x43, 0xE8, 0x99, 0xA9, 0x43,
+ 0xE8, 0x99, 0xAB, 0x43, 0xE8, 0x9A, 0x88, 0x43,
+ 0xE8, 0x9A, 0xA9, 0x43, 0xE8, 0x9B, 0xA2, 0x43,
+ // Bytes 12c0 - 12ff
+ 0xE8, 0x9C, 0x8E, 0x43, 0xE8, 0x9C, 0xA8, 0x43,
+ 0xE8, 0x9D, 0xAB, 0x43, 0xE8, 0x9D, 0xB9, 0x43,
+ 0xE8, 0x9E, 0x86, 0x43, 0xE8, 0x9E, 0xBA, 0x43,
+ 0xE8, 0x9F, 0xA1, 0x43, 0xE8, 0xA0, 0x81, 0x43,
+ 0xE8, 0xA0, 0x9F, 0x43, 0xE8, 0xA1, 0x80, 0x43,
+ 0xE8, 0xA1, 0x8C, 0x43, 0xE8, 0xA1, 0xA0, 0x43,
+ 0xE8, 0xA1, 0xA3, 0x43, 0xE8, 0xA3, 0x82, 0x43,
+ 0xE8, 0xA3, 0x8F, 0x43, 0xE8, 0xA3, 0x97, 0x43,
+ // Bytes 1300 - 133f
+ 0xE8, 0xA3, 0x9E, 0x43, 0xE8, 0xA3, 0xA1, 0x43,
+ 0xE8, 0xA3, 0xB8, 0x43, 0xE8, 0xA3, 0xBA, 0x43,
+ 0xE8, 0xA4, 0x90, 0x43, 0xE8, 0xA5, 0x81, 0x43,
+ 0xE8, 0xA5, 0xA4, 0x43, 0xE8, 0xA5, 0xBE, 0x43,
+ 0xE8, 0xA6, 0x86, 0x43, 0xE8, 0xA6, 0x8B, 0x43,
+ 0xE8, 0xA6, 0x96, 0x43, 0xE8, 0xA7, 0x92, 0x43,
+ 0xE8, 0xA7, 0xA3, 0x43, 0xE8, 0xA8, 0x80, 0x43,
+ 0xE8, 0xAA, 0xA0, 0x43, 0xE8, 0xAA, 0xAA, 0x43,
+ // Bytes 1340 - 137f
+ 0xE8, 0xAA, 0xBF, 0x43, 0xE8, 0xAB, 0x8B, 0x43,
+ 0xE8, 0xAB, 0x92, 0x43, 0xE8, 0xAB, 0x96, 0x43,
+ 0xE8, 0xAB, 0xAD, 0x43, 0xE8, 0xAB, 0xB8, 0x43,
+ 0xE8, 0xAB, 0xBE, 0x43, 0xE8, 0xAC, 0x81, 0x43,
+ 0xE8, 0xAC, 0xB9, 0x43, 0xE8, 0xAD, 0x98, 0x43,
+ 0xE8, 0xAE, 0x80, 0x43, 0xE8, 0xAE, 0x8A, 0x43,
+ 0xE8, 0xB0, 0xB7, 0x43, 0xE8, 0xB1, 0x86, 0x43,
+ 0xE8, 0xB1, 0x88, 0x43, 0xE8, 0xB1, 0x95, 0x43,
+ // Bytes 1380 - 13bf
+ 0xE8, 0xB1, 0xB8, 0x43, 0xE8, 0xB2, 0x9D, 0x43,
+ 0xE8, 0xB2, 0xA1, 0x43, 0xE8, 0xB2, 0xA9, 0x43,
+ 0xE8, 0xB2, 0xAB, 0x43, 0xE8, 0xB3, 0x81, 0x43,
+ 0xE8, 0xB3, 0x82, 0x43, 0xE8, 0xB3, 0x87, 0x43,
+ 0xE8, 0xB3, 0x88, 0x43, 0xE8, 0xB3, 0x93, 0x43,
+ 0xE8, 0xB4, 0x88, 0x43, 0xE8, 0xB4, 0x9B, 0x43,
+ 0xE8, 0xB5, 0xA4, 0x43, 0xE8, 0xB5, 0xB0, 0x43,
+ 0xE8, 0xB5, 0xB7, 0x43, 0xE8, 0xB6, 0xB3, 0x43,
+ // Bytes 13c0 - 13ff
+ 0xE8, 0xB6, 0xBC, 0x43, 0xE8, 0xB7, 0x8B, 0x43,
+ 0xE8, 0xB7, 0xAF, 0x43, 0xE8, 0xB7, 0xB0, 0x43,
+ 0xE8, 0xBA, 0xAB, 0x43, 0xE8, 0xBB, 0x8A, 0x43,
+ 0xE8, 0xBB, 0x94, 0x43, 0xE8, 0xBC, 0xA6, 0x43,
+ 0xE8, 0xBC, 0xAA, 0x43, 0xE8, 0xBC, 0xB8, 0x43,
+ 0xE8, 0xBC, 0xBB, 0x43, 0xE8, 0xBD, 0xA2, 0x43,
+ 0xE8, 0xBE, 0x9B, 0x43, 0xE8, 0xBE, 0x9E, 0x43,
+ 0xE8, 0xBE, 0xB0, 0x43, 0xE8, 0xBE, 0xB5, 0x43,
+ // Bytes 1400 - 143f
+ 0xE8, 0xBE, 0xB6, 0x43, 0xE9, 0x80, 0xA3, 0x43,
+ 0xE9, 0x80, 0xB8, 0x43, 0xE9, 0x81, 0x8A, 0x43,
+ 0xE9, 0x81, 0xA9, 0x43, 0xE9, 0x81, 0xB2, 0x43,
+ 0xE9, 0x81, 0xBC, 0x43, 0xE9, 0x82, 0x8F, 0x43,
+ 0xE9, 0x82, 0x91, 0x43, 0xE9, 0x82, 0x94, 0x43,
+ 0xE9, 0x83, 0x8E, 0x43, 0xE9, 0x83, 0x9E, 0x43,
+ 0xE9, 0x83, 0xB1, 0x43, 0xE9, 0x83, 0xBD, 0x43,
+ 0xE9, 0x84, 0x91, 0x43, 0xE9, 0x84, 0x9B, 0x43,
+ // Bytes 1440 - 147f
+ 0xE9, 0x85, 0x89, 0x43, 0xE9, 0x85, 0x8D, 0x43,
+ 0xE9, 0x85, 0xAA, 0x43, 0xE9, 0x86, 0x99, 0x43,
+ 0xE9, 0x86, 0xB4, 0x43, 0xE9, 0x87, 0x86, 0x43,
+ 0xE9, 0x87, 0x8C, 0x43, 0xE9, 0x87, 0x8F, 0x43,
+ 0xE9, 0x87, 0x91, 0x43, 0xE9, 0x88, 0xB4, 0x43,
+ 0xE9, 0x88, 0xB8, 0x43, 0xE9, 0x89, 0xB6, 0x43,
+ 0xE9, 0x89, 0xBC, 0x43, 0xE9, 0x8B, 0x97, 0x43,
+ 0xE9, 0x8B, 0x98, 0x43, 0xE9, 0x8C, 0x84, 0x43,
+ // Bytes 1480 - 14bf
+ 0xE9, 0x8D, 0x8A, 0x43, 0xE9, 0x8F, 0xB9, 0x43,
+ 0xE9, 0x90, 0x95, 0x43, 0xE9, 0x95, 0xB7, 0x43,
+ 0xE9, 0x96, 0x80, 0x43, 0xE9, 0x96, 0x8B, 0x43,
+ 0xE9, 0x96, 0xAD, 0x43, 0xE9, 0x96, 0xB7, 0x43,
+ 0xE9, 0x98, 0x9C, 0x43, 0xE9, 0x98, 0xAE, 0x43,
+ 0xE9, 0x99, 0x8B, 0x43, 0xE9, 0x99, 0x8D, 0x43,
+ 0xE9, 0x99, 0xB5, 0x43, 0xE9, 0x99, 0xB8, 0x43,
+ 0xE9, 0x99, 0xBC, 0x43, 0xE9, 0x9A, 0x86, 0x43,
+ // Bytes 14c0 - 14ff
+ 0xE9, 0x9A, 0xA3, 0x43, 0xE9, 0x9A, 0xB6, 0x43,
+ 0xE9, 0x9A, 0xB7, 0x43, 0xE9, 0x9A, 0xB8, 0x43,
+ 0xE9, 0x9A, 0xB9, 0x43, 0xE9, 0x9B, 0x83, 0x43,
+ 0xE9, 0x9B, 0xA2, 0x43, 0xE9, 0x9B, 0xA3, 0x43,
+ 0xE9, 0x9B, 0xA8, 0x43, 0xE9, 0x9B, 0xB6, 0x43,
+ 0xE9, 0x9B, 0xB7, 0x43, 0xE9, 0x9C, 0xA3, 0x43,
+ 0xE9, 0x9C, 0xB2, 0x43, 0xE9, 0x9D, 0x88, 0x43,
+ 0xE9, 0x9D, 0x91, 0x43, 0xE9, 0x9D, 0x96, 0x43,
+ // Bytes 1500 - 153f
+ 0xE9, 0x9D, 0x9E, 0x43, 0xE9, 0x9D, 0xA2, 0x43,
+ 0xE9, 0x9D, 0xA9, 0x43, 0xE9, 0x9F, 0x8B, 0x43,
+ 0xE9, 0x9F, 0x9B, 0x43, 0xE9, 0x9F, 0xA0, 0x43,
+ 0xE9, 0x9F, 0xAD, 0x43, 0xE9, 0x9F, 0xB3, 0x43,
+ 0xE9, 0x9F, 0xBF, 0x43, 0xE9, 0xA0, 0x81, 0x43,
+ 0xE9, 0xA0, 0x85, 0x43, 0xE9, 0xA0, 0x8B, 0x43,
+ 0xE9, 0xA0, 0x98, 0x43, 0xE9, 0xA0, 0xA9, 0x43,
+ 0xE9, 0xA0, 0xBB, 0x43, 0xE9, 0xA1, 0x9E, 0x43,
+ // Bytes 1540 - 157f
+ 0xE9, 0xA2, 0xA8, 0x43, 0xE9, 0xA3, 0x9B, 0x43,
+ 0xE9, 0xA3, 0x9F, 0x43, 0xE9, 0xA3, 0xA2, 0x43,
+ 0xE9, 0xA3, 0xAF, 0x43, 0xE9, 0xA3, 0xBC, 0x43,
+ 0xE9, 0xA4, 0xA8, 0x43, 0xE9, 0xA4, 0xA9, 0x43,
+ 0xE9, 0xA6, 0x96, 0x43, 0xE9, 0xA6, 0x99, 0x43,
+ 0xE9, 0xA6, 0xA7, 0x43, 0xE9, 0xA6, 0xAC, 0x43,
+ 0xE9, 0xA7, 0x82, 0x43, 0xE9, 0xA7, 0xB1, 0x43,
+ 0xE9, 0xA7, 0xBE, 0x43, 0xE9, 0xA9, 0xAA, 0x43,
+ // Bytes 1580 - 15bf
+ 0xE9, 0xAA, 0xA8, 0x43, 0xE9, 0xAB, 0x98, 0x43,
+ 0xE9, 0xAB, 0x9F, 0x43, 0xE9, 0xAC, 0x92, 0x43,
+ 0xE9, 0xAC, 0xA5, 0x43, 0xE9, 0xAC, 0xAF, 0x43,
+ 0xE9, 0xAC, 0xB2, 0x43, 0xE9, 0xAC, 0xBC, 0x43,
+ 0xE9, 0xAD, 0x9A, 0x43, 0xE9, 0xAD, 0xAF, 0x43,
+ 0xE9, 0xB1, 0x80, 0x43, 0xE9, 0xB1, 0x97, 0x43,
+ 0xE9, 0xB3, 0xA5, 0x43, 0xE9, 0xB3, 0xBD, 0x43,
+ 0xE9, 0xB5, 0xA7, 0x43, 0xE9, 0xB6, 0xB4, 0x43,
+ // Bytes 15c0 - 15ff
+ 0xE9, 0xB7, 0xBA, 0x43, 0xE9, 0xB8, 0x9E, 0x43,
+ 0xE9, 0xB9, 0xB5, 0x43, 0xE9, 0xB9, 0xBF, 0x43,
+ 0xE9, 0xBA, 0x97, 0x43, 0xE9, 0xBA, 0x9F, 0x43,
+ 0xE9, 0xBA, 0xA5, 0x43, 0xE9, 0xBA, 0xBB, 0x43,
+ 0xE9, 0xBB, 0x83, 0x43, 0xE9, 0xBB, 0x8D, 0x43,
+ 0xE9, 0xBB, 0x8E, 0x43, 0xE9, 0xBB, 0x91, 0x43,
+ 0xE9, 0xBB, 0xB9, 0x43, 0xE9, 0xBB, 0xBD, 0x43,
+ 0xE9, 0xBB, 0xBE, 0x43, 0xE9, 0xBC, 0x85, 0x43,
+ // Bytes 1600 - 163f
+ 0xE9, 0xBC, 0x8E, 0x43, 0xE9, 0xBC, 0x8F, 0x43,
+ 0xE9, 0xBC, 0x93, 0x43, 0xE9, 0xBC, 0x96, 0x43,
+ 0xE9, 0xBC, 0xA0, 0x43, 0xE9, 0xBC, 0xBB, 0x43,
+ 0xE9, 0xBD, 0x83, 0x43, 0xE9, 0xBD, 0x8A, 0x43,
+ 0xE9, 0xBD, 0x92, 0x43, 0xE9, 0xBE, 0x8D, 0x43,
+ 0xE9, 0xBE, 0x8E, 0x43, 0xE9, 0xBE, 0x9C, 0x43,
+ 0xE9, 0xBE, 0x9F, 0x43, 0xE9, 0xBE, 0xA0, 0x43,
+ 0xEA, 0x9C, 0xA7, 0x43, 0xEA, 0x9D, 0xAF, 0x43,
+ // Bytes 1640 - 167f
+ 0xEA, 0xAC, 0xB7, 0x43, 0xEA, 0xAD, 0x92, 0x44,
+ 0xF0, 0xA0, 0x84, 0xA2, 0x44, 0xF0, 0xA0, 0x94,
+ 0x9C, 0x44, 0xF0, 0xA0, 0x94, 0xA5, 0x44, 0xF0,
+ 0xA0, 0x95, 0x8B, 0x44, 0xF0, 0xA0, 0x98, 0xBA,
+ 0x44, 0xF0, 0xA0, 0xA0, 0x84, 0x44, 0xF0, 0xA0,
+ 0xA3, 0x9E, 0x44, 0xF0, 0xA0, 0xA8, 0xAC, 0x44,
+ 0xF0, 0xA0, 0xAD, 0xA3, 0x44, 0xF0, 0xA1, 0x93,
+ 0xA4, 0x44, 0xF0, 0xA1, 0x9A, 0xA8, 0x44, 0xF0,
+ // Bytes 1680 - 16bf
+ 0xA1, 0x9B, 0xAA, 0x44, 0xF0, 0xA1, 0xA7, 0x88,
+ 0x44, 0xF0, 0xA1, 0xAC, 0x98, 0x44, 0xF0, 0xA1,
+ 0xB4, 0x8B, 0x44, 0xF0, 0xA1, 0xB7, 0xA4, 0x44,
+ 0xF0, 0xA1, 0xB7, 0xA6, 0x44, 0xF0, 0xA2, 0x86,
+ 0x83, 0x44, 0xF0, 0xA2, 0x86, 0x9F, 0x44, 0xF0,
+ 0xA2, 0x8C, 0xB1, 0x44, 0xF0, 0xA2, 0x9B, 0x94,
+ 0x44, 0xF0, 0xA2, 0xA1, 0x84, 0x44, 0xF0, 0xA2,
+ 0xA1, 0x8A, 0x44, 0xF0, 0xA2, 0xAC, 0x8C, 0x44,
+ // Bytes 16c0 - 16ff
+ 0xF0, 0xA2, 0xAF, 0xB1, 0x44, 0xF0, 0xA3, 0x80,
+ 0x8A, 0x44, 0xF0, 0xA3, 0x8A, 0xB8, 0x44, 0xF0,
+ 0xA3, 0x8D, 0x9F, 0x44, 0xF0, 0xA3, 0x8E, 0x93,
+ 0x44, 0xF0, 0xA3, 0x8E, 0x9C, 0x44, 0xF0, 0xA3,
+ 0x8F, 0x83, 0x44, 0xF0, 0xA3, 0x8F, 0x95, 0x44,
+ 0xF0, 0xA3, 0x91, 0xAD, 0x44, 0xF0, 0xA3, 0x9A,
+ 0xA3, 0x44, 0xF0, 0xA3, 0xA2, 0xA7, 0x44, 0xF0,
+ 0xA3, 0xAA, 0x8D, 0x44, 0xF0, 0xA3, 0xAB, 0xBA,
+ // Bytes 1700 - 173f
+ 0x44, 0xF0, 0xA3, 0xB2, 0xBC, 0x44, 0xF0, 0xA3,
+ 0xB4, 0x9E, 0x44, 0xF0, 0xA3, 0xBB, 0x91, 0x44,
+ 0xF0, 0xA3, 0xBD, 0x9E, 0x44, 0xF0, 0xA3, 0xBE,
+ 0x8E, 0x44, 0xF0, 0xA4, 0x89, 0xA3, 0x44, 0xF0,
+ 0xA4, 0x8B, 0xAE, 0x44, 0xF0, 0xA4, 0x8E, 0xAB,
+ 0x44, 0xF0, 0xA4, 0x98, 0x88, 0x44, 0xF0, 0xA4,
+ 0x9C, 0xB5, 0x44, 0xF0, 0xA4, 0xA0, 0x94, 0x44,
+ 0xF0, 0xA4, 0xB0, 0xB6, 0x44, 0xF0, 0xA4, 0xB2,
+ // Bytes 1740 - 177f
+ 0x92, 0x44, 0xF0, 0xA4, 0xBE, 0xA1, 0x44, 0xF0,
+ 0xA4, 0xBE, 0xB8, 0x44, 0xF0, 0xA5, 0x81, 0x84,
+ 0x44, 0xF0, 0xA5, 0x83, 0xB2, 0x44, 0xF0, 0xA5,
+ 0x83, 0xB3, 0x44, 0xF0, 0xA5, 0x84, 0x99, 0x44,
+ 0xF0, 0xA5, 0x84, 0xB3, 0x44, 0xF0, 0xA5, 0x89,
+ 0x89, 0x44, 0xF0, 0xA5, 0x90, 0x9D, 0x44, 0xF0,
+ 0xA5, 0x98, 0xA6, 0x44, 0xF0, 0xA5, 0x9A, 0x9A,
+ 0x44, 0xF0, 0xA5, 0x9B, 0x85, 0x44, 0xF0, 0xA5,
+ // Bytes 1780 - 17bf
+ 0xA5, 0xBC, 0x44, 0xF0, 0xA5, 0xAA, 0xA7, 0x44,
+ 0xF0, 0xA5, 0xAE, 0xAB, 0x44, 0xF0, 0xA5, 0xB2,
+ 0x80, 0x44, 0xF0, 0xA5, 0xB3, 0x90, 0x44, 0xF0,
+ 0xA5, 0xBE, 0x86, 0x44, 0xF0, 0xA6, 0x87, 0x9A,
+ 0x44, 0xF0, 0xA6, 0x88, 0xA8, 0x44, 0xF0, 0xA6,
+ 0x89, 0x87, 0x44, 0xF0, 0xA6, 0x8B, 0x99, 0x44,
+ 0xF0, 0xA6, 0x8C, 0xBE, 0x44, 0xF0, 0xA6, 0x93,
+ 0x9A, 0x44, 0xF0, 0xA6, 0x94, 0xA3, 0x44, 0xF0,
+ // Bytes 17c0 - 17ff
+ 0xA6, 0x96, 0xA8, 0x44, 0xF0, 0xA6, 0x9E, 0xA7,
+ 0x44, 0xF0, 0xA6, 0x9E, 0xB5, 0x44, 0xF0, 0xA6,
+ 0xAC, 0xBC, 0x44, 0xF0, 0xA6, 0xB0, 0xB6, 0x44,
+ 0xF0, 0xA6, 0xB3, 0x95, 0x44, 0xF0, 0xA6, 0xB5,
+ 0xAB, 0x44, 0xF0, 0xA6, 0xBC, 0xAC, 0x44, 0xF0,
+ 0xA6, 0xBE, 0xB1, 0x44, 0xF0, 0xA7, 0x83, 0x92,
+ 0x44, 0xF0, 0xA7, 0x8F, 0x8A, 0x44, 0xF0, 0xA7,
+ 0x99, 0xA7, 0x44, 0xF0, 0xA7, 0xA2, 0xAE, 0x44,
+ // Bytes 1800 - 183f
+ 0xF0, 0xA7, 0xA5, 0xA6, 0x44, 0xF0, 0xA7, 0xB2,
+ 0xA8, 0x44, 0xF0, 0xA7, 0xBB, 0x93, 0x44, 0xF0,
+ 0xA7, 0xBC, 0xAF, 0x44, 0xF0, 0xA8, 0x97, 0x92,
+ 0x44, 0xF0, 0xA8, 0x97, 0xAD, 0x44, 0xF0, 0xA8,
+ 0x9C, 0xAE, 0x44, 0xF0, 0xA8, 0xAF, 0xBA, 0x44,
+ 0xF0, 0xA8, 0xB5, 0xB7, 0x44, 0xF0, 0xA9, 0x85,
+ 0x85, 0x44, 0xF0, 0xA9, 0x87, 0x9F, 0x44, 0xF0,
+ 0xA9, 0x88, 0x9A, 0x44, 0xF0, 0xA9, 0x90, 0x8A,
+ // Bytes 1840 - 187f
+ 0x44, 0xF0, 0xA9, 0x92, 0x96, 0x44, 0xF0, 0xA9,
+ 0x96, 0xB6, 0x44, 0xF0, 0xA9, 0xAC, 0xB0, 0x44,
+ 0xF0, 0xAA, 0x83, 0x8E, 0x44, 0xF0, 0xAA, 0x84,
+ 0x85, 0x44, 0xF0, 0xAA, 0x88, 0x8E, 0x44, 0xF0,
+ 0xAA, 0x8A, 0x91, 0x44, 0xF0, 0xAA, 0x8E, 0x92,
+ 0x44, 0xF0, 0xAA, 0x98, 0x80, 0x42, 0x21, 0x21,
+ 0x42, 0x21, 0x3F, 0x42, 0x2E, 0x2E, 0x42, 0x30,
+ 0x2C, 0x42, 0x30, 0x2E, 0x42, 0x31, 0x2C, 0x42,
+ // Bytes 1880 - 18bf
+ 0x31, 0x2E, 0x42, 0x31, 0x30, 0x42, 0x31, 0x31,
+ 0x42, 0x31, 0x32, 0x42, 0x31, 0x33, 0x42, 0x31,
+ 0x34, 0x42, 0x31, 0x35, 0x42, 0x31, 0x36, 0x42,
+ 0x31, 0x37, 0x42, 0x31, 0x38, 0x42, 0x31, 0x39,
+ 0x42, 0x32, 0x2C, 0x42, 0x32, 0x2E, 0x42, 0x32,
+ 0x30, 0x42, 0x32, 0x31, 0x42, 0x32, 0x32, 0x42,
+ 0x32, 0x33, 0x42, 0x32, 0x34, 0x42, 0x32, 0x35,
+ 0x42, 0x32, 0x36, 0x42, 0x32, 0x37, 0x42, 0x32,
+ // Bytes 18c0 - 18ff
+ 0x38, 0x42, 0x32, 0x39, 0x42, 0x33, 0x2C, 0x42,
+ 0x33, 0x2E, 0x42, 0x33, 0x30, 0x42, 0x33, 0x31,
+ 0x42, 0x33, 0x32, 0x42, 0x33, 0x33, 0x42, 0x33,
+ 0x34, 0x42, 0x33, 0x35, 0x42, 0x33, 0x36, 0x42,
+ 0x33, 0x37, 0x42, 0x33, 0x38, 0x42, 0x33, 0x39,
+ 0x42, 0x34, 0x2C, 0x42, 0x34, 0x2E, 0x42, 0x34,
+ 0x30, 0x42, 0x34, 0x31, 0x42, 0x34, 0x32, 0x42,
+ 0x34, 0x33, 0x42, 0x34, 0x34, 0x42, 0x34, 0x35,
+ // Bytes 1900 - 193f
+ 0x42, 0x34, 0x36, 0x42, 0x34, 0x37, 0x42, 0x34,
+ 0x38, 0x42, 0x34, 0x39, 0x42, 0x35, 0x2C, 0x42,
+ 0x35, 0x2E, 0x42, 0x35, 0x30, 0x42, 0x36, 0x2C,
+ 0x42, 0x36, 0x2E, 0x42, 0x37, 0x2C, 0x42, 0x37,
+ 0x2E, 0x42, 0x38, 0x2C, 0x42, 0x38, 0x2E, 0x42,
+ 0x39, 0x2C, 0x42, 0x39, 0x2E, 0x42, 0x3D, 0x3D,
+ 0x42, 0x3F, 0x21, 0x42, 0x3F, 0x3F, 0x42, 0x41,
+ 0x55, 0x42, 0x42, 0x71, 0x42, 0x43, 0x44, 0x42,
+ // Bytes 1940 - 197f
+ 0x44, 0x4A, 0x42, 0x44, 0x5A, 0x42, 0x44, 0x7A,
+ 0x42, 0x47, 0x42, 0x42, 0x47, 0x79, 0x42, 0x48,
+ 0x50, 0x42, 0x48, 0x56, 0x42, 0x48, 0x67, 0x42,
+ 0x48, 0x7A, 0x42, 0x49, 0x49, 0x42, 0x49, 0x4A,
+ 0x42, 0x49, 0x55, 0x42, 0x49, 0x56, 0x42, 0x49,
+ 0x58, 0x42, 0x4B, 0x42, 0x42, 0x4B, 0x4B, 0x42,
+ 0x4B, 0x4D, 0x42, 0x4C, 0x4A, 0x42, 0x4C, 0x6A,
+ 0x42, 0x4D, 0x42, 0x42, 0x4D, 0x43, 0x42, 0x4D,
+ // Bytes 1980 - 19bf
+ 0x44, 0x42, 0x4D, 0x56, 0x42, 0x4D, 0x57, 0x42,
+ 0x4E, 0x4A, 0x42, 0x4E, 0x6A, 0x42, 0x4E, 0x6F,
+ 0x42, 0x50, 0x48, 0x42, 0x50, 0x52, 0x42, 0x50,
+ 0x61, 0x42, 0x52, 0x73, 0x42, 0x53, 0x44, 0x42,
+ 0x53, 0x4D, 0x42, 0x53, 0x53, 0x42, 0x53, 0x76,
+ 0x42, 0x54, 0x4D, 0x42, 0x56, 0x49, 0x42, 0x57,
+ 0x43, 0x42, 0x57, 0x5A, 0x42, 0x57, 0x62, 0x42,
+ 0x58, 0x49, 0x42, 0x63, 0x63, 0x42, 0x63, 0x64,
+ // Bytes 19c0 - 19ff
+ 0x42, 0x63, 0x6D, 0x42, 0x64, 0x42, 0x42, 0x64,
+ 0x61, 0x42, 0x64, 0x6C, 0x42, 0x64, 0x6D, 0x42,
+ 0x64, 0x7A, 0x42, 0x65, 0x56, 0x42, 0x66, 0x66,
+ 0x42, 0x66, 0x69, 0x42, 0x66, 0x6C, 0x42, 0x66,
+ 0x6D, 0x42, 0x68, 0x61, 0x42, 0x69, 0x69, 0x42,
+ 0x69, 0x6A, 0x42, 0x69, 0x6E, 0x42, 0x69, 0x76,
+ 0x42, 0x69, 0x78, 0x42, 0x6B, 0x41, 0x42, 0x6B,
+ 0x56, 0x42, 0x6B, 0x57, 0x42, 0x6B, 0x67, 0x42,
+ // Bytes 1a00 - 1a3f
+ 0x6B, 0x6C, 0x42, 0x6B, 0x6D, 0x42, 0x6B, 0x74,
+ 0x42, 0x6C, 0x6A, 0x42, 0x6C, 0x6D, 0x42, 0x6C,
+ 0x6E, 0x42, 0x6C, 0x78, 0x42, 0x6D, 0x32, 0x42,
+ 0x6D, 0x33, 0x42, 0x6D, 0x41, 0x42, 0x6D, 0x56,
+ 0x42, 0x6D, 0x57, 0x42, 0x6D, 0x62, 0x42, 0x6D,
+ 0x67, 0x42, 0x6D, 0x6C, 0x42, 0x6D, 0x6D, 0x42,
+ 0x6D, 0x73, 0x42, 0x6E, 0x41, 0x42, 0x6E, 0x46,
+ 0x42, 0x6E, 0x56, 0x42, 0x6E, 0x57, 0x42, 0x6E,
+ // Bytes 1a40 - 1a7f
+ 0x6A, 0x42, 0x6E, 0x6D, 0x42, 0x6E, 0x73, 0x42,
+ 0x6F, 0x56, 0x42, 0x70, 0x41, 0x42, 0x70, 0x46,
+ 0x42, 0x70, 0x56, 0x42, 0x70, 0x57, 0x42, 0x70,
+ 0x63, 0x42, 0x70, 0x73, 0x42, 0x73, 0x72, 0x42,
+ 0x73, 0x74, 0x42, 0x76, 0x69, 0x42, 0x78, 0x69,
+ 0x43, 0x28, 0x31, 0x29, 0x43, 0x28, 0x32, 0x29,
+ 0x43, 0x28, 0x33, 0x29, 0x43, 0x28, 0x34, 0x29,
+ 0x43, 0x28, 0x35, 0x29, 0x43, 0x28, 0x36, 0x29,
+ // Bytes 1a80 - 1abf
+ 0x43, 0x28, 0x37, 0x29, 0x43, 0x28, 0x38, 0x29,
+ 0x43, 0x28, 0x39, 0x29, 0x43, 0x28, 0x41, 0x29,
+ 0x43, 0x28, 0x42, 0x29, 0x43, 0x28, 0x43, 0x29,
+ 0x43, 0x28, 0x44, 0x29, 0x43, 0x28, 0x45, 0x29,
+ 0x43, 0x28, 0x46, 0x29, 0x43, 0x28, 0x47, 0x29,
+ 0x43, 0x28, 0x48, 0x29, 0x43, 0x28, 0x49, 0x29,
+ 0x43, 0x28, 0x4A, 0x29, 0x43, 0x28, 0x4B, 0x29,
+ 0x43, 0x28, 0x4C, 0x29, 0x43, 0x28, 0x4D, 0x29,
+ // Bytes 1ac0 - 1aff
+ 0x43, 0x28, 0x4E, 0x29, 0x43, 0x28, 0x4F, 0x29,
+ 0x43, 0x28, 0x50, 0x29, 0x43, 0x28, 0x51, 0x29,
+ 0x43, 0x28, 0x52, 0x29, 0x43, 0x28, 0x53, 0x29,
+ 0x43, 0x28, 0x54, 0x29, 0x43, 0x28, 0x55, 0x29,
+ 0x43, 0x28, 0x56, 0x29, 0x43, 0x28, 0x57, 0x29,
+ 0x43, 0x28, 0x58, 0x29, 0x43, 0x28, 0x59, 0x29,
+ 0x43, 0x28, 0x5A, 0x29, 0x43, 0x28, 0x61, 0x29,
+ 0x43, 0x28, 0x62, 0x29, 0x43, 0x28, 0x63, 0x29,
+ // Bytes 1b00 - 1b3f
+ 0x43, 0x28, 0x64, 0x29, 0x43, 0x28, 0x65, 0x29,
+ 0x43, 0x28, 0x66, 0x29, 0x43, 0x28, 0x67, 0x29,
+ 0x43, 0x28, 0x68, 0x29, 0x43, 0x28, 0x69, 0x29,
+ 0x43, 0x28, 0x6A, 0x29, 0x43, 0x28, 0x6B, 0x29,
+ 0x43, 0x28, 0x6C, 0x29, 0x43, 0x28, 0x6D, 0x29,
+ 0x43, 0x28, 0x6E, 0x29, 0x43, 0x28, 0x6F, 0x29,
+ 0x43, 0x28, 0x70, 0x29, 0x43, 0x28, 0x71, 0x29,
+ 0x43, 0x28, 0x72, 0x29, 0x43, 0x28, 0x73, 0x29,
+ // Bytes 1b40 - 1b7f
+ 0x43, 0x28, 0x74, 0x29, 0x43, 0x28, 0x75, 0x29,
+ 0x43, 0x28, 0x76, 0x29, 0x43, 0x28, 0x77, 0x29,
+ 0x43, 0x28, 0x78, 0x29, 0x43, 0x28, 0x79, 0x29,
+ 0x43, 0x28, 0x7A, 0x29, 0x43, 0x2E, 0x2E, 0x2E,
+ 0x43, 0x31, 0x30, 0x2E, 0x43, 0x31, 0x31, 0x2E,
+ 0x43, 0x31, 0x32, 0x2E, 0x43, 0x31, 0x33, 0x2E,
+ 0x43, 0x31, 0x34, 0x2E, 0x43, 0x31, 0x35, 0x2E,
+ 0x43, 0x31, 0x36, 0x2E, 0x43, 0x31, 0x37, 0x2E,
+ // Bytes 1b80 - 1bbf
+ 0x43, 0x31, 0x38, 0x2E, 0x43, 0x31, 0x39, 0x2E,
+ 0x43, 0x32, 0x30, 0x2E, 0x43, 0x3A, 0x3A, 0x3D,
+ 0x43, 0x3D, 0x3D, 0x3D, 0x43, 0x43, 0x6F, 0x2E,
+ 0x43, 0x46, 0x41, 0x58, 0x43, 0x47, 0x48, 0x7A,
+ 0x43, 0x47, 0x50, 0x61, 0x43, 0x49, 0x49, 0x49,
+ 0x43, 0x4C, 0x54, 0x44, 0x43, 0x4C, 0xC2, 0xB7,
+ 0x43, 0x4D, 0x48, 0x7A, 0x43, 0x4D, 0x50, 0x61,
+ 0x43, 0x4D, 0xCE, 0xA9, 0x43, 0x50, 0x50, 0x4D,
+ // Bytes 1bc0 - 1bff
+ 0x43, 0x50, 0x50, 0x56, 0x43, 0x50, 0x54, 0x45,
+ 0x43, 0x54, 0x45, 0x4C, 0x43, 0x54, 0x48, 0x7A,
+ 0x43, 0x56, 0x49, 0x49, 0x43, 0x58, 0x49, 0x49,
+ 0x43, 0x61, 0x2F, 0x63, 0x43, 0x61, 0x2F, 0x73,
+ 0x43, 0x61, 0xCA, 0xBE, 0x43, 0x62, 0x61, 0x72,
+ 0x43, 0x63, 0x2F, 0x6F, 0x43, 0x63, 0x2F, 0x75,
+ 0x43, 0x63, 0x61, 0x6C, 0x43, 0x63, 0x6D, 0x32,
+ 0x43, 0x63, 0x6D, 0x33, 0x43, 0x64, 0x6D, 0x32,
+ // Bytes 1c00 - 1c3f
+ 0x43, 0x64, 0x6D, 0x33, 0x43, 0x65, 0x72, 0x67,
+ 0x43, 0x66, 0x66, 0x69, 0x43, 0x66, 0x66, 0x6C,
+ 0x43, 0x67, 0x61, 0x6C, 0x43, 0x68, 0x50, 0x61,
+ 0x43, 0x69, 0x69, 0x69, 0x43, 0x6B, 0x48, 0x7A,
+ 0x43, 0x6B, 0x50, 0x61, 0x43, 0x6B, 0x6D, 0x32,
+ 0x43, 0x6B, 0x6D, 0x33, 0x43, 0x6B, 0xCE, 0xA9,
+ 0x43, 0x6C, 0x6F, 0x67, 0x43, 0x6C, 0xC2, 0xB7,
+ 0x43, 0x6D, 0x69, 0x6C, 0x43, 0x6D, 0x6D, 0x32,
+ // Bytes 1c40 - 1c7f
+ 0x43, 0x6D, 0x6D, 0x33, 0x43, 0x6D, 0x6F, 0x6C,
+ 0x43, 0x72, 0x61, 0x64, 0x43, 0x76, 0x69, 0x69,
+ 0x43, 0x78, 0x69, 0x69, 0x43, 0xC2, 0xB0, 0x43,
+ 0x43, 0xC2, 0xB0, 0x46, 0x43, 0xCA, 0xBC, 0x6E,
+ 0x43, 0xCE, 0xBC, 0x41, 0x43, 0xCE, 0xBC, 0x46,
+ 0x43, 0xCE, 0xBC, 0x56, 0x43, 0xCE, 0xBC, 0x57,
+ 0x43, 0xCE, 0xBC, 0x67, 0x43, 0xCE, 0xBC, 0x6C,
+ 0x43, 0xCE, 0xBC, 0x6D, 0x43, 0xCE, 0xBC, 0x73,
+ // Bytes 1c80 - 1cbf
+ 0x44, 0x28, 0x31, 0x30, 0x29, 0x44, 0x28, 0x31,
+ 0x31, 0x29, 0x44, 0x28, 0x31, 0x32, 0x29, 0x44,
+ 0x28, 0x31, 0x33, 0x29, 0x44, 0x28, 0x31, 0x34,
+ 0x29, 0x44, 0x28, 0x31, 0x35, 0x29, 0x44, 0x28,
+ 0x31, 0x36, 0x29, 0x44, 0x28, 0x31, 0x37, 0x29,
+ 0x44, 0x28, 0x31, 0x38, 0x29, 0x44, 0x28, 0x31,
+ 0x39, 0x29, 0x44, 0x28, 0x32, 0x30, 0x29, 0x44,
+ 0x30, 0xE7, 0x82, 0xB9, 0x44, 0x31, 0xE2, 0x81,
+ // Bytes 1cc0 - 1cff
+ 0x84, 0x44, 0x31, 0xE6, 0x97, 0xA5, 0x44, 0x31,
+ 0xE6, 0x9C, 0x88, 0x44, 0x31, 0xE7, 0x82, 0xB9,
+ 0x44, 0x32, 0xE6, 0x97, 0xA5, 0x44, 0x32, 0xE6,
+ 0x9C, 0x88, 0x44, 0x32, 0xE7, 0x82, 0xB9, 0x44,
+ 0x33, 0xE6, 0x97, 0xA5, 0x44, 0x33, 0xE6, 0x9C,
+ 0x88, 0x44, 0x33, 0xE7, 0x82, 0xB9, 0x44, 0x34,
+ 0xE6, 0x97, 0xA5, 0x44, 0x34, 0xE6, 0x9C, 0x88,
+ 0x44, 0x34, 0xE7, 0x82, 0xB9, 0x44, 0x35, 0xE6,
+ // Bytes 1d00 - 1d3f
+ 0x97, 0xA5, 0x44, 0x35, 0xE6, 0x9C, 0x88, 0x44,
+ 0x35, 0xE7, 0x82, 0xB9, 0x44, 0x36, 0xE6, 0x97,
+ 0xA5, 0x44, 0x36, 0xE6, 0x9C, 0x88, 0x44, 0x36,
+ 0xE7, 0x82, 0xB9, 0x44, 0x37, 0xE6, 0x97, 0xA5,
+ 0x44, 0x37, 0xE6, 0x9C, 0x88, 0x44, 0x37, 0xE7,
+ 0x82, 0xB9, 0x44, 0x38, 0xE6, 0x97, 0xA5, 0x44,
+ 0x38, 0xE6, 0x9C, 0x88, 0x44, 0x38, 0xE7, 0x82,
+ 0xB9, 0x44, 0x39, 0xE6, 0x97, 0xA5, 0x44, 0x39,
+ // Bytes 1d40 - 1d7f
+ 0xE6, 0x9C, 0x88, 0x44, 0x39, 0xE7, 0x82, 0xB9,
+ 0x44, 0x56, 0x49, 0x49, 0x49, 0x44, 0x61, 0x2E,
+ 0x6D, 0x2E, 0x44, 0x6B, 0x63, 0x61, 0x6C, 0x44,
+ 0x70, 0x2E, 0x6D, 0x2E, 0x44, 0x76, 0x69, 0x69,
+ 0x69, 0x44, 0xD5, 0xA5, 0xD6, 0x82, 0x44, 0xD5,
+ 0xB4, 0xD5, 0xA5, 0x44, 0xD5, 0xB4, 0xD5, 0xAB,
+ 0x44, 0xD5, 0xB4, 0xD5, 0xAD, 0x44, 0xD5, 0xB4,
+ 0xD5, 0xB6, 0x44, 0xD5, 0xBE, 0xD5, 0xB6, 0x44,
+ // Bytes 1d80 - 1dbf
+ 0xD7, 0x90, 0xD7, 0x9C, 0x44, 0xD8, 0xA7, 0xD9,
+ 0xB4, 0x44, 0xD8, 0xA8, 0xD8, 0xAC, 0x44, 0xD8,
+ 0xA8, 0xD8, 0xAD, 0x44, 0xD8, 0xA8, 0xD8, 0xAE,
+ 0x44, 0xD8, 0xA8, 0xD8, 0xB1, 0x44, 0xD8, 0xA8,
+ 0xD8, 0xB2, 0x44, 0xD8, 0xA8, 0xD9, 0x85, 0x44,
+ 0xD8, 0xA8, 0xD9, 0x86, 0x44, 0xD8, 0xA8, 0xD9,
+ 0x87, 0x44, 0xD8, 0xA8, 0xD9, 0x89, 0x44, 0xD8,
+ 0xA8, 0xD9, 0x8A, 0x44, 0xD8, 0xAA, 0xD8, 0xAC,
+ // Bytes 1dc0 - 1dff
+ 0x44, 0xD8, 0xAA, 0xD8, 0xAD, 0x44, 0xD8, 0xAA,
+ 0xD8, 0xAE, 0x44, 0xD8, 0xAA, 0xD8, 0xB1, 0x44,
+ 0xD8, 0xAA, 0xD8, 0xB2, 0x44, 0xD8, 0xAA, 0xD9,
+ 0x85, 0x44, 0xD8, 0xAA, 0xD9, 0x86, 0x44, 0xD8,
+ 0xAA, 0xD9, 0x87, 0x44, 0xD8, 0xAA, 0xD9, 0x89,
+ 0x44, 0xD8, 0xAA, 0xD9, 0x8A, 0x44, 0xD8, 0xAB,
+ 0xD8, 0xAC, 0x44, 0xD8, 0xAB, 0xD8, 0xB1, 0x44,
+ 0xD8, 0xAB, 0xD8, 0xB2, 0x44, 0xD8, 0xAB, 0xD9,
+ // Bytes 1e00 - 1e3f
+ 0x85, 0x44, 0xD8, 0xAB, 0xD9, 0x86, 0x44, 0xD8,
+ 0xAB, 0xD9, 0x87, 0x44, 0xD8, 0xAB, 0xD9, 0x89,
+ 0x44, 0xD8, 0xAB, 0xD9, 0x8A, 0x44, 0xD8, 0xAC,
+ 0xD8, 0xAD, 0x44, 0xD8, 0xAC, 0xD9, 0x85, 0x44,
+ 0xD8, 0xAC, 0xD9, 0x89, 0x44, 0xD8, 0xAC, 0xD9,
+ 0x8A, 0x44, 0xD8, 0xAD, 0xD8, 0xAC, 0x44, 0xD8,
+ 0xAD, 0xD9, 0x85, 0x44, 0xD8, 0xAD, 0xD9, 0x89,
+ 0x44, 0xD8, 0xAD, 0xD9, 0x8A, 0x44, 0xD8, 0xAE,
+ // Bytes 1e40 - 1e7f
+ 0xD8, 0xAC, 0x44, 0xD8, 0xAE, 0xD8, 0xAD, 0x44,
+ 0xD8, 0xAE, 0xD9, 0x85, 0x44, 0xD8, 0xAE, 0xD9,
+ 0x89, 0x44, 0xD8, 0xAE, 0xD9, 0x8A, 0x44, 0xD8,
+ 0xB3, 0xD8, 0xAC, 0x44, 0xD8, 0xB3, 0xD8, 0xAD,
+ 0x44, 0xD8, 0xB3, 0xD8, 0xAE, 0x44, 0xD8, 0xB3,
+ 0xD8, 0xB1, 0x44, 0xD8, 0xB3, 0xD9, 0x85, 0x44,
+ 0xD8, 0xB3, 0xD9, 0x87, 0x44, 0xD8, 0xB3, 0xD9,
+ 0x89, 0x44, 0xD8, 0xB3, 0xD9, 0x8A, 0x44, 0xD8,
+ // Bytes 1e80 - 1ebf
+ 0xB4, 0xD8, 0xAC, 0x44, 0xD8, 0xB4, 0xD8, 0xAD,
+ 0x44, 0xD8, 0xB4, 0xD8, 0xAE, 0x44, 0xD8, 0xB4,
+ 0xD8, 0xB1, 0x44, 0xD8, 0xB4, 0xD9, 0x85, 0x44,
+ 0xD8, 0xB4, 0xD9, 0x87, 0x44, 0xD8, 0xB4, 0xD9,
+ 0x89, 0x44, 0xD8, 0xB4, 0xD9, 0x8A, 0x44, 0xD8,
+ 0xB5, 0xD8, 0xAD, 0x44, 0xD8, 0xB5, 0xD8, 0xAE,
+ 0x44, 0xD8, 0xB5, 0xD8, 0xB1, 0x44, 0xD8, 0xB5,
+ 0xD9, 0x85, 0x44, 0xD8, 0xB5, 0xD9, 0x89, 0x44,
+ // Bytes 1ec0 - 1eff
+ 0xD8, 0xB5, 0xD9, 0x8A, 0x44, 0xD8, 0xB6, 0xD8,
+ 0xAC, 0x44, 0xD8, 0xB6, 0xD8, 0xAD, 0x44, 0xD8,
+ 0xB6, 0xD8, 0xAE, 0x44, 0xD8, 0xB6, 0xD8, 0xB1,
+ 0x44, 0xD8, 0xB6, 0xD9, 0x85, 0x44, 0xD8, 0xB6,
+ 0xD9, 0x89, 0x44, 0xD8, 0xB6, 0xD9, 0x8A, 0x44,
+ 0xD8, 0xB7, 0xD8, 0xAD, 0x44, 0xD8, 0xB7, 0xD9,
+ 0x85, 0x44, 0xD8, 0xB7, 0xD9, 0x89, 0x44, 0xD8,
+ 0xB7, 0xD9, 0x8A, 0x44, 0xD8, 0xB8, 0xD9, 0x85,
+ // Bytes 1f00 - 1f3f
+ 0x44, 0xD8, 0xB9, 0xD8, 0xAC, 0x44, 0xD8, 0xB9,
+ 0xD9, 0x85, 0x44, 0xD8, 0xB9, 0xD9, 0x89, 0x44,
+ 0xD8, 0xB9, 0xD9, 0x8A, 0x44, 0xD8, 0xBA, 0xD8,
+ 0xAC, 0x44, 0xD8, 0xBA, 0xD9, 0x85, 0x44, 0xD8,
+ 0xBA, 0xD9, 0x89, 0x44, 0xD8, 0xBA, 0xD9, 0x8A,
+ 0x44, 0xD9, 0x81, 0xD8, 0xAC, 0x44, 0xD9, 0x81,
+ 0xD8, 0xAD, 0x44, 0xD9, 0x81, 0xD8, 0xAE, 0x44,
+ 0xD9, 0x81, 0xD9, 0x85, 0x44, 0xD9, 0x81, 0xD9,
+ // Bytes 1f40 - 1f7f
+ 0x89, 0x44, 0xD9, 0x81, 0xD9, 0x8A, 0x44, 0xD9,
+ 0x82, 0xD8, 0xAD, 0x44, 0xD9, 0x82, 0xD9, 0x85,
+ 0x44, 0xD9, 0x82, 0xD9, 0x89, 0x44, 0xD9, 0x82,
+ 0xD9, 0x8A, 0x44, 0xD9, 0x83, 0xD8, 0xA7, 0x44,
+ 0xD9, 0x83, 0xD8, 0xAC, 0x44, 0xD9, 0x83, 0xD8,
+ 0xAD, 0x44, 0xD9, 0x83, 0xD8, 0xAE, 0x44, 0xD9,
+ 0x83, 0xD9, 0x84, 0x44, 0xD9, 0x83, 0xD9, 0x85,
+ 0x44, 0xD9, 0x83, 0xD9, 0x89, 0x44, 0xD9, 0x83,
+ // Bytes 1f80 - 1fbf
+ 0xD9, 0x8A, 0x44, 0xD9, 0x84, 0xD8, 0xA7, 0x44,
+ 0xD9, 0x84, 0xD8, 0xAC, 0x44, 0xD9, 0x84, 0xD8,
+ 0xAD, 0x44, 0xD9, 0x84, 0xD8, 0xAE, 0x44, 0xD9,
+ 0x84, 0xD9, 0x85, 0x44, 0xD9, 0x84, 0xD9, 0x87,
+ 0x44, 0xD9, 0x84, 0xD9, 0x89, 0x44, 0xD9, 0x84,
+ 0xD9, 0x8A, 0x44, 0xD9, 0x85, 0xD8, 0xA7, 0x44,
+ 0xD9, 0x85, 0xD8, 0xAC, 0x44, 0xD9, 0x85, 0xD8,
+ 0xAD, 0x44, 0xD9, 0x85, 0xD8, 0xAE, 0x44, 0xD9,
+ // Bytes 1fc0 - 1fff
+ 0x85, 0xD9, 0x85, 0x44, 0xD9, 0x85, 0xD9, 0x89,
+ 0x44, 0xD9, 0x85, 0xD9, 0x8A, 0x44, 0xD9, 0x86,
+ 0xD8, 0xAC, 0x44, 0xD9, 0x86, 0xD8, 0xAD, 0x44,
+ 0xD9, 0x86, 0xD8, 0xAE, 0x44, 0xD9, 0x86, 0xD8,
+ 0xB1, 0x44, 0xD9, 0x86, 0xD8, 0xB2, 0x44, 0xD9,
+ 0x86, 0xD9, 0x85, 0x44, 0xD9, 0x86, 0xD9, 0x86,
+ 0x44, 0xD9, 0x86, 0xD9, 0x87, 0x44, 0xD9, 0x86,
+ 0xD9, 0x89, 0x44, 0xD9, 0x86, 0xD9, 0x8A, 0x44,
+ // Bytes 2000 - 203f
+ 0xD9, 0x87, 0xD8, 0xAC, 0x44, 0xD9, 0x87, 0xD9,
+ 0x85, 0x44, 0xD9, 0x87, 0xD9, 0x89, 0x44, 0xD9,
+ 0x87, 0xD9, 0x8A, 0x44, 0xD9, 0x88, 0xD9, 0xB4,
+ 0x44, 0xD9, 0x8A, 0xD8, 0xAC, 0x44, 0xD9, 0x8A,
+ 0xD8, 0xAD, 0x44, 0xD9, 0x8A, 0xD8, 0xAE, 0x44,
+ 0xD9, 0x8A, 0xD8, 0xB1, 0x44, 0xD9, 0x8A, 0xD8,
+ 0xB2, 0x44, 0xD9, 0x8A, 0xD9, 0x85, 0x44, 0xD9,
+ 0x8A, 0xD9, 0x86, 0x44, 0xD9, 0x8A, 0xD9, 0x87,
+ // Bytes 2040 - 207f
+ 0x44, 0xD9, 0x8A, 0xD9, 0x89, 0x44, 0xD9, 0x8A,
+ 0xD9, 0x8A, 0x44, 0xD9, 0x8A, 0xD9, 0xB4, 0x44,
+ 0xDB, 0x87, 0xD9, 0xB4, 0x45, 0x28, 0xE1, 0x84,
+ 0x80, 0x29, 0x45, 0x28, 0xE1, 0x84, 0x82, 0x29,
+ 0x45, 0x28, 0xE1, 0x84, 0x83, 0x29, 0x45, 0x28,
+ 0xE1, 0x84, 0x85, 0x29, 0x45, 0x28, 0xE1, 0x84,
+ 0x86, 0x29, 0x45, 0x28, 0xE1, 0x84, 0x87, 0x29,
+ 0x45, 0x28, 0xE1, 0x84, 0x89, 0x29, 0x45, 0x28,
+ // Bytes 2080 - 20bf
+ 0xE1, 0x84, 0x8B, 0x29, 0x45, 0x28, 0xE1, 0x84,
+ 0x8C, 0x29, 0x45, 0x28, 0xE1, 0x84, 0x8E, 0x29,
+ 0x45, 0x28, 0xE1, 0x84, 0x8F, 0x29, 0x45, 0x28,
+ 0xE1, 0x84, 0x90, 0x29, 0x45, 0x28, 0xE1, 0x84,
+ 0x91, 0x29, 0x45, 0x28, 0xE1, 0x84, 0x92, 0x29,
+ 0x45, 0x28, 0xE4, 0xB8, 0x80, 0x29, 0x45, 0x28,
+ 0xE4, 0xB8, 0x83, 0x29, 0x45, 0x28, 0xE4, 0xB8,
+ 0x89, 0x29, 0x45, 0x28, 0xE4, 0xB9, 0x9D, 0x29,
+ // Bytes 20c0 - 20ff
+ 0x45, 0x28, 0xE4, 0xBA, 0x8C, 0x29, 0x45, 0x28,
+ 0xE4, 0xBA, 0x94, 0x29, 0x45, 0x28, 0xE4, 0xBB,
+ 0xA3, 0x29, 0x45, 0x28, 0xE4, 0xBC, 0x81, 0x29,
+ 0x45, 0x28, 0xE4, 0xBC, 0x91, 0x29, 0x45, 0x28,
+ 0xE5, 0x85, 0xAB, 0x29, 0x45, 0x28, 0xE5, 0x85,
+ 0xAD, 0x29, 0x45, 0x28, 0xE5, 0x8A, 0xB4, 0x29,
+ 0x45, 0x28, 0xE5, 0x8D, 0x81, 0x29, 0x45, 0x28,
+ 0xE5, 0x8D, 0x94, 0x29, 0x45, 0x28, 0xE5, 0x90,
+ // Bytes 2100 - 213f
+ 0x8D, 0x29, 0x45, 0x28, 0xE5, 0x91, 0xBC, 0x29,
+ 0x45, 0x28, 0xE5, 0x9B, 0x9B, 0x29, 0x45, 0x28,
+ 0xE5, 0x9C, 0x9F, 0x29, 0x45, 0x28, 0xE5, 0xAD,
+ 0xA6, 0x29, 0x45, 0x28, 0xE6, 0x97, 0xA5, 0x29,
+ 0x45, 0x28, 0xE6, 0x9C, 0x88, 0x29, 0x45, 0x28,
+ 0xE6, 0x9C, 0x89, 0x29, 0x45, 0x28, 0xE6, 0x9C,
+ 0xA8, 0x29, 0x45, 0x28, 0xE6, 0xA0, 0xAA, 0x29,
+ 0x45, 0x28, 0xE6, 0xB0, 0xB4, 0x29, 0x45, 0x28,
+ // Bytes 2140 - 217f
+ 0xE7, 0x81, 0xAB, 0x29, 0x45, 0x28, 0xE7, 0x89,
+ 0xB9, 0x29, 0x45, 0x28, 0xE7, 0x9B, 0xA3, 0x29,
+ 0x45, 0x28, 0xE7, 0xA4, 0xBE, 0x29, 0x45, 0x28,
+ 0xE7, 0xA5, 0x9D, 0x29, 0x45, 0x28, 0xE7, 0xA5,
+ 0xAD, 0x29, 0x45, 0x28, 0xE8, 0x87, 0xAA, 0x29,
+ 0x45, 0x28, 0xE8, 0x87, 0xB3, 0x29, 0x45, 0x28,
+ 0xE8, 0xB2, 0xA1, 0x29, 0x45, 0x28, 0xE8, 0xB3,
+ 0x87, 0x29, 0x45, 0x28, 0xE9, 0x87, 0x91, 0x29,
+ // Bytes 2180 - 21bf
+ 0x45, 0x30, 0xE2, 0x81, 0x84, 0x33, 0x45, 0x31,
+ 0x30, 0xE6, 0x97, 0xA5, 0x45, 0x31, 0x30, 0xE6,
+ 0x9C, 0x88, 0x45, 0x31, 0x30, 0xE7, 0x82, 0xB9,
+ 0x45, 0x31, 0x31, 0xE6, 0x97, 0xA5, 0x45, 0x31,
+ 0x31, 0xE6, 0x9C, 0x88, 0x45, 0x31, 0x31, 0xE7,
+ 0x82, 0xB9, 0x45, 0x31, 0x32, 0xE6, 0x97, 0xA5,
+ 0x45, 0x31, 0x32, 0xE6, 0x9C, 0x88, 0x45, 0x31,
+ 0x32, 0xE7, 0x82, 0xB9, 0x45, 0x31, 0x33, 0xE6,
+ // Bytes 21c0 - 21ff
+ 0x97, 0xA5, 0x45, 0x31, 0x33, 0xE7, 0x82, 0xB9,
+ 0x45, 0x31, 0x34, 0xE6, 0x97, 0xA5, 0x45, 0x31,
+ 0x34, 0xE7, 0x82, 0xB9, 0x45, 0x31, 0x35, 0xE6,
+ 0x97, 0xA5, 0x45, 0x31, 0x35, 0xE7, 0x82, 0xB9,
+ 0x45, 0x31, 0x36, 0xE6, 0x97, 0xA5, 0x45, 0x31,
+ 0x36, 0xE7, 0x82, 0xB9, 0x45, 0x31, 0x37, 0xE6,
+ 0x97, 0xA5, 0x45, 0x31, 0x37, 0xE7, 0x82, 0xB9,
+ 0x45, 0x31, 0x38, 0xE6, 0x97, 0xA5, 0x45, 0x31,
+ // Bytes 2200 - 223f
+ 0x38, 0xE7, 0x82, 0xB9, 0x45, 0x31, 0x39, 0xE6,
+ 0x97, 0xA5, 0x45, 0x31, 0x39, 0xE7, 0x82, 0xB9,
+ 0x45, 0x31, 0xE2, 0x81, 0x84, 0x32, 0x45, 0x31,
+ 0xE2, 0x81, 0x84, 0x33, 0x45, 0x31, 0xE2, 0x81,
+ 0x84, 0x34, 0x45, 0x31, 0xE2, 0x81, 0x84, 0x35,
+ 0x45, 0x31, 0xE2, 0x81, 0x84, 0x36, 0x45, 0x31,
+ 0xE2, 0x81, 0x84, 0x37, 0x45, 0x31, 0xE2, 0x81,
+ 0x84, 0x38, 0x45, 0x31, 0xE2, 0x81, 0x84, 0x39,
+ // Bytes 2240 - 227f
+ 0x45, 0x32, 0x30, 0xE6, 0x97, 0xA5, 0x45, 0x32,
+ 0x30, 0xE7, 0x82, 0xB9, 0x45, 0x32, 0x31, 0xE6,
+ 0x97, 0xA5, 0x45, 0x32, 0x31, 0xE7, 0x82, 0xB9,
+ 0x45, 0x32, 0x32, 0xE6, 0x97, 0xA5, 0x45, 0x32,
+ 0x32, 0xE7, 0x82, 0xB9, 0x45, 0x32, 0x33, 0xE6,
+ 0x97, 0xA5, 0x45, 0x32, 0x33, 0xE7, 0x82, 0xB9,
+ 0x45, 0x32, 0x34, 0xE6, 0x97, 0xA5, 0x45, 0x32,
+ 0x34, 0xE7, 0x82, 0xB9, 0x45, 0x32, 0x35, 0xE6,
+ // Bytes 2280 - 22bf
+ 0x97, 0xA5, 0x45, 0x32, 0x36, 0xE6, 0x97, 0xA5,
+ 0x45, 0x32, 0x37, 0xE6, 0x97, 0xA5, 0x45, 0x32,
+ 0x38, 0xE6, 0x97, 0xA5, 0x45, 0x32, 0x39, 0xE6,
+ 0x97, 0xA5, 0x45, 0x32, 0xE2, 0x81, 0x84, 0x33,
+ 0x45, 0x32, 0xE2, 0x81, 0x84, 0x35, 0x45, 0x33,
+ 0x30, 0xE6, 0x97, 0xA5, 0x45, 0x33, 0x31, 0xE6,
+ 0x97, 0xA5, 0x45, 0x33, 0xE2, 0x81, 0x84, 0x34,
+ 0x45, 0x33, 0xE2, 0x81, 0x84, 0x35, 0x45, 0x33,
+ // Bytes 22c0 - 22ff
+ 0xE2, 0x81, 0x84, 0x38, 0x45, 0x34, 0xE2, 0x81,
+ 0x84, 0x35, 0x45, 0x35, 0xE2, 0x81, 0x84, 0x36,
+ 0x45, 0x35, 0xE2, 0x81, 0x84, 0x38, 0x45, 0x37,
+ 0xE2, 0x81, 0x84, 0x38, 0x45, 0x41, 0xE2, 0x88,
+ 0x95, 0x6D, 0x45, 0x56, 0xE2, 0x88, 0x95, 0x6D,
+ 0x45, 0x6D, 0xE2, 0x88, 0x95, 0x73, 0x46, 0x31,
+ 0xE2, 0x81, 0x84, 0x31, 0x30, 0x46, 0x43, 0xE2,
+ 0x88, 0x95, 0x6B, 0x67, 0x46, 0x6D, 0xE2, 0x88,
+ // Bytes 2300 - 233f
+ 0x95, 0x73, 0x32, 0x46, 0xD8, 0xA8, 0xD8, 0xAD,
+ 0xD9, 0x8A, 0x46, 0xD8, 0xA8, 0xD8, 0xAE, 0xD9,
+ 0x8A, 0x46, 0xD8, 0xAA, 0xD8, 0xAC, 0xD9, 0x85,
+ 0x46, 0xD8, 0xAA, 0xD8, 0xAC, 0xD9, 0x89, 0x46,
+ 0xD8, 0xAA, 0xD8, 0xAC, 0xD9, 0x8A, 0x46, 0xD8,
+ 0xAA, 0xD8, 0xAD, 0xD8, 0xAC, 0x46, 0xD8, 0xAA,
+ 0xD8, 0xAD, 0xD9, 0x85, 0x46, 0xD8, 0xAA, 0xD8,
+ 0xAE, 0xD9, 0x85, 0x46, 0xD8, 0xAA, 0xD8, 0xAE,
+ // Bytes 2340 - 237f
+ 0xD9, 0x89, 0x46, 0xD8, 0xAA, 0xD8, 0xAE, 0xD9,
+ 0x8A, 0x46, 0xD8, 0xAA, 0xD9, 0x85, 0xD8, 0xAC,
+ 0x46, 0xD8, 0xAA, 0xD9, 0x85, 0xD8, 0xAD, 0x46,
+ 0xD8, 0xAA, 0xD9, 0x85, 0xD8, 0xAE, 0x46, 0xD8,
+ 0xAA, 0xD9, 0x85, 0xD9, 0x89, 0x46, 0xD8, 0xAA,
+ 0xD9, 0x85, 0xD9, 0x8A, 0x46, 0xD8, 0xAC, 0xD8,
+ 0xAD, 0xD9, 0x89, 0x46, 0xD8, 0xAC, 0xD8, 0xAD,
+ 0xD9, 0x8A, 0x46, 0xD8, 0xAC, 0xD9, 0x85, 0xD8,
+ // Bytes 2380 - 23bf
+ 0xAD, 0x46, 0xD8, 0xAC, 0xD9, 0x85, 0xD9, 0x89,
+ 0x46, 0xD8, 0xAC, 0xD9, 0x85, 0xD9, 0x8A, 0x46,
+ 0xD8, 0xAD, 0xD8, 0xAC, 0xD9, 0x8A, 0x46, 0xD8,
+ 0xAD, 0xD9, 0x85, 0xD9, 0x89, 0x46, 0xD8, 0xAD,
+ 0xD9, 0x85, 0xD9, 0x8A, 0x46, 0xD8, 0xB3, 0xD8,
+ 0xAC, 0xD8, 0xAD, 0x46, 0xD8, 0xB3, 0xD8, 0xAC,
+ 0xD9, 0x89, 0x46, 0xD8, 0xB3, 0xD8, 0xAD, 0xD8,
+ 0xAC, 0x46, 0xD8, 0xB3, 0xD8, 0xAE, 0xD9, 0x89,
+ // Bytes 23c0 - 23ff
+ 0x46, 0xD8, 0xB3, 0xD8, 0xAE, 0xD9, 0x8A, 0x46,
+ 0xD8, 0xB3, 0xD9, 0x85, 0xD8, 0xAC, 0x46, 0xD8,
+ 0xB3, 0xD9, 0x85, 0xD8, 0xAD, 0x46, 0xD8, 0xB3,
+ 0xD9, 0x85, 0xD9, 0x85, 0x46, 0xD8, 0xB4, 0xD8,
+ 0xAC, 0xD9, 0x8A, 0x46, 0xD8, 0xB4, 0xD8, 0xAD,
+ 0xD9, 0x85, 0x46, 0xD8, 0xB4, 0xD8, 0xAD, 0xD9,
+ 0x8A, 0x46, 0xD8, 0xB4, 0xD9, 0x85, 0xD8, 0xAE,
+ 0x46, 0xD8, 0xB4, 0xD9, 0x85, 0xD9, 0x85, 0x46,
+ // Bytes 2400 - 243f
+ 0xD8, 0xB5, 0xD8, 0xAD, 0xD8, 0xAD, 0x46, 0xD8,
+ 0xB5, 0xD8, 0xAD, 0xD9, 0x8A, 0x46, 0xD8, 0xB5,
+ 0xD9, 0x84, 0xD9, 0x89, 0x46, 0xD8, 0xB5, 0xD9,
+ 0x84, 0xDB, 0x92, 0x46, 0xD8, 0xB5, 0xD9, 0x85,
+ 0xD9, 0x85, 0x46, 0xD8, 0xB6, 0xD8, 0xAD, 0xD9,
+ 0x89, 0x46, 0xD8, 0xB6, 0xD8, 0xAD, 0xD9, 0x8A,
+ 0x46, 0xD8, 0xB6, 0xD8, 0xAE, 0xD9, 0x85, 0x46,
+ 0xD8, 0xB7, 0xD9, 0x85, 0xD8, 0xAD, 0x46, 0xD8,
+ // Bytes 2440 - 247f
+ 0xB7, 0xD9, 0x85, 0xD9, 0x85, 0x46, 0xD8, 0xB7,
+ 0xD9, 0x85, 0xD9, 0x8A, 0x46, 0xD8, 0xB9, 0xD8,
+ 0xAC, 0xD9, 0x85, 0x46, 0xD8, 0xB9, 0xD9, 0x85,
+ 0xD9, 0x85, 0x46, 0xD8, 0xB9, 0xD9, 0x85, 0xD9,
+ 0x89, 0x46, 0xD8, 0xB9, 0xD9, 0x85, 0xD9, 0x8A,
+ 0x46, 0xD8, 0xBA, 0xD9, 0x85, 0xD9, 0x85, 0x46,
+ 0xD8, 0xBA, 0xD9, 0x85, 0xD9, 0x89, 0x46, 0xD8,
+ 0xBA, 0xD9, 0x85, 0xD9, 0x8A, 0x46, 0xD9, 0x81,
+ // Bytes 2480 - 24bf
+ 0xD8, 0xAE, 0xD9, 0x85, 0x46, 0xD9, 0x81, 0xD9,
+ 0x85, 0xD9, 0x8A, 0x46, 0xD9, 0x82, 0xD9, 0x84,
+ 0xDB, 0x92, 0x46, 0xD9, 0x82, 0xD9, 0x85, 0xD8,
+ 0xAD, 0x46, 0xD9, 0x82, 0xD9, 0x85, 0xD9, 0x85,
+ 0x46, 0xD9, 0x82, 0xD9, 0x85, 0xD9, 0x8A, 0x46,
+ 0xD9, 0x83, 0xD9, 0x85, 0xD9, 0x85, 0x46, 0xD9,
+ 0x83, 0xD9, 0x85, 0xD9, 0x8A, 0x46, 0xD9, 0x84,
+ 0xD8, 0xAC, 0xD8, 0xAC, 0x46, 0xD9, 0x84, 0xD8,
+ // Bytes 24c0 - 24ff
+ 0xAC, 0xD9, 0x85, 0x46, 0xD9, 0x84, 0xD8, 0xAC,
+ 0xD9, 0x8A, 0x46, 0xD9, 0x84, 0xD8, 0xAD, 0xD9,
+ 0x85, 0x46, 0xD9, 0x84, 0xD8, 0xAD, 0xD9, 0x89,
+ 0x46, 0xD9, 0x84, 0xD8, 0xAD, 0xD9, 0x8A, 0x46,
+ 0xD9, 0x84, 0xD8, 0xAE, 0xD9, 0x85, 0x46, 0xD9,
+ 0x84, 0xD9, 0x85, 0xD8, 0xAD, 0x46, 0xD9, 0x84,
+ 0xD9, 0x85, 0xD9, 0x8A, 0x46, 0xD9, 0x85, 0xD8,
+ 0xAC, 0xD8, 0xAD, 0x46, 0xD9, 0x85, 0xD8, 0xAC,
+ // Bytes 2500 - 253f
+ 0xD8, 0xAE, 0x46, 0xD9, 0x85, 0xD8, 0xAC, 0xD9,
+ 0x85, 0x46, 0xD9, 0x85, 0xD8, 0xAC, 0xD9, 0x8A,
+ 0x46, 0xD9, 0x85, 0xD8, 0xAD, 0xD8, 0xAC, 0x46,
+ 0xD9, 0x85, 0xD8, 0xAD, 0xD9, 0x85, 0x46, 0xD9,
+ 0x85, 0xD8, 0xAD, 0xD9, 0x8A, 0x46, 0xD9, 0x85,
+ 0xD8, 0xAE, 0xD8, 0xAC, 0x46, 0xD9, 0x85, 0xD8,
+ 0xAE, 0xD9, 0x85, 0x46, 0xD9, 0x85, 0xD8, 0xAE,
+ 0xD9, 0x8A, 0x46, 0xD9, 0x85, 0xD9, 0x85, 0xD9,
+ // Bytes 2540 - 257f
+ 0x8A, 0x46, 0xD9, 0x86, 0xD8, 0xAC, 0xD8, 0xAD,
+ 0x46, 0xD9, 0x86, 0xD8, 0xAC, 0xD9, 0x85, 0x46,
+ 0xD9, 0x86, 0xD8, 0xAC, 0xD9, 0x89, 0x46, 0xD9,
+ 0x86, 0xD8, 0xAC, 0xD9, 0x8A, 0x46, 0xD9, 0x86,
+ 0xD8, 0xAD, 0xD9, 0x85, 0x46, 0xD9, 0x86, 0xD8,
+ 0xAD, 0xD9, 0x89, 0x46, 0xD9, 0x86, 0xD8, 0xAD,
+ 0xD9, 0x8A, 0x46, 0xD9, 0x86, 0xD9, 0x85, 0xD9,
+ 0x89, 0x46, 0xD9, 0x86, 0xD9, 0x85, 0xD9, 0x8A,
+ // Bytes 2580 - 25bf
+ 0x46, 0xD9, 0x87, 0xD9, 0x85, 0xD8, 0xAC, 0x46,
+ 0xD9, 0x87, 0xD9, 0x85, 0xD9, 0x85, 0x46, 0xD9,
+ 0x8A, 0xD8, 0xAC, 0xD9, 0x8A, 0x46, 0xD9, 0x8A,
+ 0xD8, 0xAD, 0xD9, 0x8A, 0x46, 0xD9, 0x8A, 0xD9,
+ 0x85, 0xD9, 0x85, 0x46, 0xD9, 0x8A, 0xD9, 0x85,
+ 0xD9, 0x8A, 0x46, 0xD9, 0x8A, 0xD9, 0x94, 0xD8,
+ 0xA7, 0x46, 0xD9, 0x8A, 0xD9, 0x94, 0xD8, 0xAC,
+ 0x46, 0xD9, 0x8A, 0xD9, 0x94, 0xD8, 0xAD, 0x46,
+ // Bytes 25c0 - 25ff
+ 0xD9, 0x8A, 0xD9, 0x94, 0xD8, 0xAE, 0x46, 0xD9,
+ 0x8A, 0xD9, 0x94, 0xD8, 0xB1, 0x46, 0xD9, 0x8A,
+ 0xD9, 0x94, 0xD8, 0xB2, 0x46, 0xD9, 0x8A, 0xD9,
+ 0x94, 0xD9, 0x85, 0x46, 0xD9, 0x8A, 0xD9, 0x94,
+ 0xD9, 0x86, 0x46, 0xD9, 0x8A, 0xD9, 0x94, 0xD9,
+ 0x87, 0x46, 0xD9, 0x8A, 0xD9, 0x94, 0xD9, 0x88,
+ 0x46, 0xD9, 0x8A, 0xD9, 0x94, 0xD9, 0x89, 0x46,
+ 0xD9, 0x8A, 0xD9, 0x94, 0xD9, 0x8A, 0x46, 0xD9,
+ // Bytes 2600 - 263f
+ 0x8A, 0xD9, 0x94, 0xDB, 0x86, 0x46, 0xD9, 0x8A,
+ 0xD9, 0x94, 0xDB, 0x87, 0x46, 0xD9, 0x8A, 0xD9,
+ 0x94, 0xDB, 0x88, 0x46, 0xD9, 0x8A, 0xD9, 0x94,
+ 0xDB, 0x90, 0x46, 0xD9, 0x8A, 0xD9, 0x94, 0xDB,
+ 0x95, 0x46, 0xE0, 0xB9, 0x8D, 0xE0, 0xB8, 0xB2,
+ 0x46, 0xE0, 0xBA, 0xAB, 0xE0, 0xBA, 0x99, 0x46,
+ 0xE0, 0xBA, 0xAB, 0xE0, 0xBA, 0xA1, 0x46, 0xE0,
+ 0xBB, 0x8D, 0xE0, 0xBA, 0xB2, 0x46, 0xE0, 0xBD,
+ // Bytes 2640 - 267f
+ 0x80, 0xE0, 0xBE, 0xB5, 0x46, 0xE0, 0xBD, 0x82,
+ 0xE0, 0xBE, 0xB7, 0x46, 0xE0, 0xBD, 0x8C, 0xE0,
+ 0xBE, 0xB7, 0x46, 0xE0, 0xBD, 0x91, 0xE0, 0xBE,
+ 0xB7, 0x46, 0xE0, 0xBD, 0x96, 0xE0, 0xBE, 0xB7,
+ 0x46, 0xE0, 0xBD, 0x9B, 0xE0, 0xBE, 0xB7, 0x46,
+ 0xE0, 0xBE, 0x90, 0xE0, 0xBE, 0xB5, 0x46, 0xE0,
+ 0xBE, 0x92, 0xE0, 0xBE, 0xB7, 0x46, 0xE0, 0xBE,
+ 0x9C, 0xE0, 0xBE, 0xB7, 0x46, 0xE0, 0xBE, 0xA1,
+ // Bytes 2680 - 26bf
+ 0xE0, 0xBE, 0xB7, 0x46, 0xE0, 0xBE, 0xA6, 0xE0,
+ 0xBE, 0xB7, 0x46, 0xE0, 0xBE, 0xAB, 0xE0, 0xBE,
+ 0xB7, 0x46, 0xE2, 0x80, 0xB2, 0xE2, 0x80, 0xB2,
+ 0x46, 0xE2, 0x80, 0xB5, 0xE2, 0x80, 0xB5, 0x46,
+ 0xE2, 0x88, 0xAB, 0xE2, 0x88, 0xAB, 0x46, 0xE2,
+ 0x88, 0xAE, 0xE2, 0x88, 0xAE, 0x46, 0xE3, 0x81,
+ 0xBB, 0xE3, 0x81, 0x8B, 0x46, 0xE3, 0x82, 0x88,
+ 0xE3, 0x82, 0x8A, 0x46, 0xE3, 0x82, 0xAD, 0xE3,
+ // Bytes 26c0 - 26ff
+ 0x83, 0xAD, 0x46, 0xE3, 0x82, 0xB3, 0xE3, 0x82,
+ 0xB3, 0x46, 0xE3, 0x82, 0xB3, 0xE3, 0x83, 0x88,
+ 0x46, 0xE3, 0x83, 0x88, 0xE3, 0x83, 0xB3, 0x46,
+ 0xE3, 0x83, 0x8A, 0xE3, 0x83, 0x8E, 0x46, 0xE3,
+ 0x83, 0x9B, 0xE3, 0x83, 0xB3, 0x46, 0xE3, 0x83,
+ 0x9F, 0xE3, 0x83, 0xAA, 0x46, 0xE3, 0x83, 0xAA,
+ 0xE3, 0x83, 0xA9, 0x46, 0xE3, 0x83, 0xAC, 0xE3,
+ 0x83, 0xA0, 0x46, 0xE5, 0xA4, 0xA7, 0xE6, 0xAD,
+ // Bytes 2700 - 273f
+ 0xA3, 0x46, 0xE5, 0xB9, 0xB3, 0xE6, 0x88, 0x90,
+ 0x46, 0xE6, 0x98, 0x8E, 0xE6, 0xB2, 0xBB, 0x46,
+ 0xE6, 0x98, 0xAD, 0xE5, 0x92, 0x8C, 0x47, 0x72,
+ 0x61, 0x64, 0xE2, 0x88, 0x95, 0x73, 0x47, 0xE3,
+ 0x80, 0x94, 0x53, 0xE3, 0x80, 0x95, 0x48, 0x28,
+ 0xE1, 0x84, 0x80, 0xE1, 0x85, 0xA1, 0x29, 0x48,
+ 0x28, 0xE1, 0x84, 0x82, 0xE1, 0x85, 0xA1, 0x29,
+ 0x48, 0x28, 0xE1, 0x84, 0x83, 0xE1, 0x85, 0xA1,
+ // Bytes 2740 - 277f
+ 0x29, 0x48, 0x28, 0xE1, 0x84, 0x85, 0xE1, 0x85,
+ 0xA1, 0x29, 0x48, 0x28, 0xE1, 0x84, 0x86, 0xE1,
+ 0x85, 0xA1, 0x29, 0x48, 0x28, 0xE1, 0x84, 0x87,
+ 0xE1, 0x85, 0xA1, 0x29, 0x48, 0x28, 0xE1, 0x84,
+ 0x89, 0xE1, 0x85, 0xA1, 0x29, 0x48, 0x28, 0xE1,
+ 0x84, 0x8B, 0xE1, 0x85, 0xA1, 0x29, 0x48, 0x28,
+ 0xE1, 0x84, 0x8C, 0xE1, 0x85, 0xA1, 0x29, 0x48,
+ 0x28, 0xE1, 0x84, 0x8C, 0xE1, 0x85, 0xAE, 0x29,
+ // Bytes 2780 - 27bf
+ 0x48, 0x28, 0xE1, 0x84, 0x8E, 0xE1, 0x85, 0xA1,
+ 0x29, 0x48, 0x28, 0xE1, 0x84, 0x8F, 0xE1, 0x85,
+ 0xA1, 0x29, 0x48, 0x28, 0xE1, 0x84, 0x90, 0xE1,
+ 0x85, 0xA1, 0x29, 0x48, 0x28, 0xE1, 0x84, 0x91,
+ 0xE1, 0x85, 0xA1, 0x29, 0x48, 0x28, 0xE1, 0x84,
+ 0x92, 0xE1, 0x85, 0xA1, 0x29, 0x48, 0x72, 0x61,
+ 0x64, 0xE2, 0x88, 0x95, 0x73, 0x32, 0x48, 0xD8,
+ 0xA7, 0xD9, 0x83, 0xD8, 0xA8, 0xD8, 0xB1, 0x48,
+ // Bytes 27c0 - 27ff
+ 0xD8, 0xA7, 0xD9, 0x84, 0xD9, 0x84, 0xD9, 0x87,
+ 0x48, 0xD8, 0xB1, 0xD8, 0xB3, 0xD9, 0x88, 0xD9,
+ 0x84, 0x48, 0xD8, 0xB1, 0xDB, 0x8C, 0xD8, 0xA7,
+ 0xD9, 0x84, 0x48, 0xD8, 0xB5, 0xD9, 0x84, 0xD8,
+ 0xB9, 0xD9, 0x85, 0x48, 0xD8, 0xB9, 0xD9, 0x84,
+ 0xD9, 0x8A, 0xD9, 0x87, 0x48, 0xD9, 0x85, 0xD8,
+ 0xAD, 0xD9, 0x85, 0xD8, 0xAF, 0x48, 0xD9, 0x88,
+ 0xD8, 0xB3, 0xD9, 0x84, 0xD9, 0x85, 0x49, 0xE2,
+ // Bytes 2800 - 283f
+ 0x80, 0xB2, 0xE2, 0x80, 0xB2, 0xE2, 0x80, 0xB2,
+ 0x49, 0xE2, 0x80, 0xB5, 0xE2, 0x80, 0xB5, 0xE2,
+ 0x80, 0xB5, 0x49, 0xE2, 0x88, 0xAB, 0xE2, 0x88,
+ 0xAB, 0xE2, 0x88, 0xAB, 0x49, 0xE2, 0x88, 0xAE,
+ 0xE2, 0x88, 0xAE, 0xE2, 0x88, 0xAE, 0x49, 0xE3,
+ 0x80, 0x94, 0xE4, 0xB8, 0x89, 0xE3, 0x80, 0x95,
+ 0x49, 0xE3, 0x80, 0x94, 0xE4, 0xBA, 0x8C, 0xE3,
+ 0x80, 0x95, 0x49, 0xE3, 0x80, 0x94, 0xE5, 0x8B,
+ // Bytes 2840 - 287f
+ 0x9D, 0xE3, 0x80, 0x95, 0x49, 0xE3, 0x80, 0x94,
+ 0xE5, 0xAE, 0x89, 0xE3, 0x80, 0x95, 0x49, 0xE3,
+ 0x80, 0x94, 0xE6, 0x89, 0x93, 0xE3, 0x80, 0x95,
+ 0x49, 0xE3, 0x80, 0x94, 0xE6, 0x95, 0x97, 0xE3,
+ 0x80, 0x95, 0x49, 0xE3, 0x80, 0x94, 0xE6, 0x9C,
+ 0xAC, 0xE3, 0x80, 0x95, 0x49, 0xE3, 0x80, 0x94,
+ 0xE7, 0x82, 0xB9, 0xE3, 0x80, 0x95, 0x49, 0xE3,
+ 0x80, 0x94, 0xE7, 0x9B, 0x97, 0xE3, 0x80, 0x95,
+ // Bytes 2880 - 28bf
+ 0x49, 0xE3, 0x82, 0xA2, 0xE3, 0x83, 0xBC, 0xE3,
+ 0x83, 0xAB, 0x49, 0xE3, 0x82, 0xA4, 0xE3, 0x83,
+ 0xB3, 0xE3, 0x83, 0x81, 0x49, 0xE3, 0x82, 0xA6,
+ 0xE3, 0x82, 0xA9, 0xE3, 0x83, 0xB3, 0x49, 0xE3,
+ 0x82, 0xAA, 0xE3, 0x83, 0xB3, 0xE3, 0x82, 0xB9,
+ 0x49, 0xE3, 0x82, 0xAA, 0xE3, 0x83, 0xBC, 0xE3,
+ 0x83, 0xA0, 0x49, 0xE3, 0x82, 0xAB, 0xE3, 0x82,
+ 0xA4, 0xE3, 0x83, 0xAA, 0x49, 0xE3, 0x82, 0xB1,
+ // Bytes 28c0 - 28ff
+ 0xE3, 0x83, 0xBC, 0xE3, 0x82, 0xB9, 0x49, 0xE3,
+ 0x82, 0xB3, 0xE3, 0x83, 0xAB, 0xE3, 0x83, 0x8A,
+ 0x49, 0xE3, 0x82, 0xBB, 0xE3, 0x83, 0xB3, 0xE3,
+ 0x83, 0x81, 0x49, 0xE3, 0x82, 0xBB, 0xE3, 0x83,
+ 0xB3, 0xE3, 0x83, 0x88, 0x49, 0xE3, 0x83, 0x86,
+ 0xE3, 0x82, 0x99, 0xE3, 0x82, 0xB7, 0x49, 0xE3,
+ 0x83, 0x88, 0xE3, 0x82, 0x99, 0xE3, 0x83, 0xAB,
+ 0x49, 0xE3, 0x83, 0x8E, 0xE3, 0x83, 0x83, 0xE3,
+ // Bytes 2900 - 293f
+ 0x83, 0x88, 0x49, 0xE3, 0x83, 0x8F, 0xE3, 0x82,
+ 0xA4, 0xE3, 0x83, 0x84, 0x49, 0xE3, 0x83, 0x92,
+ 0xE3, 0x82, 0x99, 0xE3, 0x83, 0xAB, 0x49, 0xE3,
+ 0x83, 0x92, 0xE3, 0x82, 0x9A, 0xE3, 0x82, 0xB3,
+ 0x49, 0xE3, 0x83, 0x95, 0xE3, 0x83, 0xA9, 0xE3,
+ 0x83, 0xB3, 0x49, 0xE3, 0x83, 0x98, 0xE3, 0x82,
+ 0x9A, 0xE3, 0x82, 0xBD, 0x49, 0xE3, 0x83, 0x98,
+ 0xE3, 0x83, 0xAB, 0xE3, 0x83, 0x84, 0x49, 0xE3,
+ // Bytes 2940 - 297f
+ 0x83, 0x9B, 0xE3, 0x83, 0xBC, 0xE3, 0x83, 0xAB,
+ 0x49, 0xE3, 0x83, 0x9B, 0xE3, 0x83, 0xBC, 0xE3,
+ 0x83, 0xB3, 0x49, 0xE3, 0x83, 0x9E, 0xE3, 0x82,
+ 0xA4, 0xE3, 0x83, 0xAB, 0x49, 0xE3, 0x83, 0x9E,
+ 0xE3, 0x83, 0x83, 0xE3, 0x83, 0x8F, 0x49, 0xE3,
+ 0x83, 0x9E, 0xE3, 0x83, 0xAB, 0xE3, 0x82, 0xAF,
+ 0x49, 0xE3, 0x83, 0xA4, 0xE3, 0x83, 0xBC, 0xE3,
+ 0x83, 0xAB, 0x49, 0xE3, 0x83, 0xA6, 0xE3, 0x82,
+ // Bytes 2980 - 29bf
+ 0xA2, 0xE3, 0x83, 0xB3, 0x49, 0xE3, 0x83, 0xAF,
+ 0xE3, 0x83, 0x83, 0xE3, 0x83, 0x88, 0x4C, 0xE2,
+ 0x80, 0xB2, 0xE2, 0x80, 0xB2, 0xE2, 0x80, 0xB2,
+ 0xE2, 0x80, 0xB2, 0x4C, 0xE2, 0x88, 0xAB, 0xE2,
+ 0x88, 0xAB, 0xE2, 0x88, 0xAB, 0xE2, 0x88, 0xAB,
+ 0x4C, 0xE3, 0x82, 0xA2, 0xE3, 0x83, 0xAB, 0xE3,
+ 0x83, 0x95, 0xE3, 0x82, 0xA1, 0x4C, 0xE3, 0x82,
+ 0xA8, 0xE3, 0x83, 0xBC, 0xE3, 0x82, 0xAB, 0xE3,
+ // Bytes 29c0 - 29ff
+ 0x83, 0xBC, 0x4C, 0xE3, 0x82, 0xAB, 0xE3, 0x82,
+ 0x99, 0xE3, 0x83, 0xAD, 0xE3, 0x83, 0xB3, 0x4C,
+ 0xE3, 0x82, 0xAB, 0xE3, 0x82, 0x99, 0xE3, 0x83,
+ 0xB3, 0xE3, 0x83, 0x9E, 0x4C, 0xE3, 0x82, 0xAB,
+ 0xE3, 0x83, 0xA9, 0xE3, 0x83, 0x83, 0xE3, 0x83,
+ 0x88, 0x4C, 0xE3, 0x82, 0xAB, 0xE3, 0x83, 0xAD,
+ 0xE3, 0x83, 0xAA, 0xE3, 0x83, 0xBC, 0x4C, 0xE3,
+ 0x82, 0xAD, 0xE3, 0x82, 0x99, 0xE3, 0x83, 0x8B,
+ // Bytes 2a00 - 2a3f
+ 0xE3, 0x83, 0xBC, 0x4C, 0xE3, 0x82, 0xAD, 0xE3,
+ 0x83, 0xA5, 0xE3, 0x83, 0xAA, 0xE3, 0x83, 0xBC,
+ 0x4C, 0xE3, 0x82, 0xAF, 0xE3, 0x82, 0x99, 0xE3,
+ 0x83, 0xA9, 0xE3, 0x83, 0xA0, 0x4C, 0xE3, 0x82,
+ 0xAF, 0xE3, 0x83, 0xAD, 0xE3, 0x83, 0xBC, 0xE3,
+ 0x83, 0x8D, 0x4C, 0xE3, 0x82, 0xB5, 0xE3, 0x82,
+ 0xA4, 0xE3, 0x82, 0xAF, 0xE3, 0x83, 0xAB, 0x4C,
+ 0xE3, 0x82, 0xBF, 0xE3, 0x82, 0x99, 0xE3, 0x83,
+ // Bytes 2a40 - 2a7f
+ 0xBC, 0xE3, 0x82, 0xB9, 0x4C, 0xE3, 0x83, 0x8F,
+ 0xE3, 0x82, 0x9A, 0xE3, 0x83, 0xBC, 0xE3, 0x83,
+ 0x84, 0x4C, 0xE3, 0x83, 0x92, 0xE3, 0x82, 0x9A,
+ 0xE3, 0x82, 0xAF, 0xE3, 0x83, 0xAB, 0x4C, 0xE3,
+ 0x83, 0x95, 0xE3, 0x82, 0xA3, 0xE3, 0x83, 0xBC,
+ 0xE3, 0x83, 0x88, 0x4C, 0xE3, 0x83, 0x98, 0xE3,
+ 0x82, 0x99, 0xE3, 0x83, 0xBC, 0xE3, 0x82, 0xBF,
+ 0x4C, 0xE3, 0x83, 0x98, 0xE3, 0x82, 0x9A, 0xE3,
+ // Bytes 2a80 - 2abf
+ 0x83, 0x8B, 0xE3, 0x83, 0x92, 0x4C, 0xE3, 0x83,
+ 0x98, 0xE3, 0x82, 0x9A, 0xE3, 0x83, 0xB3, 0xE3,
+ 0x82, 0xB9, 0x4C, 0xE3, 0x83, 0x9B, 0xE3, 0x82,
+ 0x99, 0xE3, 0x83, 0xAB, 0xE3, 0x83, 0x88, 0x4C,
+ 0xE3, 0x83, 0x9E, 0xE3, 0x82, 0xA4, 0xE3, 0x82,
+ 0xAF, 0xE3, 0x83, 0xAD, 0x4C, 0xE3, 0x83, 0x9F,
+ 0xE3, 0x82, 0xAF, 0xE3, 0x83, 0xAD, 0xE3, 0x83,
+ 0xB3, 0x4C, 0xE3, 0x83, 0xA1, 0xE3, 0x83, 0xBC,
+ // Bytes 2ac0 - 2aff
+ 0xE3, 0x83, 0x88, 0xE3, 0x83, 0xAB, 0x4C, 0xE3,
+ 0x83, 0xAA, 0xE3, 0x83, 0x83, 0xE3, 0x83, 0x88,
+ 0xE3, 0x83, 0xAB, 0x4C, 0xE3, 0x83, 0xAB, 0xE3,
+ 0x83, 0x92, 0xE3, 0x82, 0x9A, 0xE3, 0x83, 0xBC,
+ 0x4C, 0xE6, 0xA0, 0xAA, 0xE5, 0xBC, 0x8F, 0xE4,
+ 0xBC, 0x9A, 0xE7, 0xA4, 0xBE, 0x4E, 0x28, 0xE1,
+ 0x84, 0x8B, 0xE1, 0x85, 0xA9, 0xE1, 0x84, 0x92,
+ 0xE1, 0x85, 0xAE, 0x29, 0x4F, 0xD8, 0xAC, 0xD9,
+ // Bytes 2b00 - 2b3f
+ 0x84, 0x20, 0xD8, 0xAC, 0xD9, 0x84, 0xD8, 0xA7,
+ 0xD9, 0x84, 0xD9, 0x87, 0x4F, 0xE3, 0x82, 0xA2,
+ 0xE3, 0x83, 0x8F, 0xE3, 0x82, 0x9A, 0xE3, 0x83,
+ 0xBC, 0xE3, 0x83, 0x88, 0x4F, 0xE3, 0x82, 0xA2,
+ 0xE3, 0x83, 0xB3, 0xE3, 0x83, 0x98, 0xE3, 0x82,
+ 0x9A, 0xE3, 0x82, 0xA2, 0x4F, 0xE3, 0x82, 0xAD,
+ 0xE3, 0x83, 0xAD, 0xE3, 0x83, 0xAF, 0xE3, 0x83,
+ 0x83, 0xE3, 0x83, 0x88, 0x4F, 0xE3, 0x82, 0xB5,
+ // Bytes 2b40 - 2b7f
+ 0xE3, 0x83, 0xB3, 0xE3, 0x83, 0x81, 0xE3, 0x83,
+ 0xBC, 0xE3, 0x83, 0xA0, 0x4F, 0xE3, 0x83, 0x8F,
+ 0xE3, 0x82, 0x99, 0xE3, 0x83, 0xBC, 0xE3, 0x83,
+ 0xAC, 0xE3, 0x83, 0xAB, 0x4F, 0xE3, 0x83, 0x98,
+ 0xE3, 0x82, 0xAF, 0xE3, 0x82, 0xBF, 0xE3, 0x83,
+ 0xBC, 0xE3, 0x83, 0xAB, 0x4F, 0xE3, 0x83, 0x9B,
+ 0xE3, 0x82, 0x9A, 0xE3, 0x82, 0xA4, 0xE3, 0x83,
+ 0xB3, 0xE3, 0x83, 0x88, 0x4F, 0xE3, 0x83, 0x9E,
+ // Bytes 2b80 - 2bbf
+ 0xE3, 0x83, 0xB3, 0xE3, 0x82, 0xB7, 0xE3, 0x83,
+ 0xA7, 0xE3, 0x83, 0xB3, 0x4F, 0xE3, 0x83, 0xA1,
+ 0xE3, 0x82, 0xAB, 0xE3, 0x82, 0x99, 0xE3, 0x83,
+ 0x88, 0xE3, 0x83, 0xB3, 0x4F, 0xE3, 0x83, 0xAB,
+ 0xE3, 0x83, 0xBC, 0xE3, 0x83, 0x95, 0xE3, 0x82,
+ 0x99, 0xE3, 0x83, 0xAB, 0x51, 0x28, 0xE1, 0x84,
+ 0x8B, 0xE1, 0x85, 0xA9, 0xE1, 0x84, 0x8C, 0xE1,
+ 0x85, 0xA5, 0xE1, 0x86, 0xAB, 0x29, 0x52, 0xE3,
+ // Bytes 2bc0 - 2bff
+ 0x82, 0xAD, 0xE3, 0x82, 0x99, 0xE3, 0x83, 0xAB,
+ 0xE3, 0x82, 0xBF, 0xE3, 0x82, 0x99, 0xE3, 0x83,
+ 0xBC, 0x52, 0xE3, 0x82, 0xAD, 0xE3, 0x83, 0xAD,
+ 0xE3, 0x82, 0xAF, 0xE3, 0x82, 0x99, 0xE3, 0x83,
+ 0xA9, 0xE3, 0x83, 0xA0, 0x52, 0xE3, 0x82, 0xAD,
+ 0xE3, 0x83, 0xAD, 0xE3, 0x83, 0xA1, 0xE3, 0x83,
+ 0xBC, 0xE3, 0x83, 0x88, 0xE3, 0x83, 0xAB, 0x52,
+ 0xE3, 0x82, 0xAF, 0xE3, 0x82, 0x99, 0xE3, 0x83,
+ // Bytes 2c00 - 2c3f
+ 0xA9, 0xE3, 0x83, 0xA0, 0xE3, 0x83, 0x88, 0xE3,
+ 0x83, 0xB3, 0x52, 0xE3, 0x82, 0xAF, 0xE3, 0x83,
+ 0xAB, 0xE3, 0x82, 0xBB, 0xE3, 0x82, 0x99, 0xE3,
+ 0x82, 0xA4, 0xE3, 0x83, 0xAD, 0x52, 0xE3, 0x83,
+ 0x8F, 0xE3, 0x82, 0x9A, 0xE3, 0x83, 0xBC, 0xE3,
+ 0x82, 0xBB, 0xE3, 0x83, 0xB3, 0xE3, 0x83, 0x88,
+ 0x52, 0xE3, 0x83, 0x92, 0xE3, 0x82, 0x9A, 0xE3,
+ 0x82, 0xA2, 0xE3, 0x82, 0xB9, 0xE3, 0x83, 0x88,
+ // Bytes 2c40 - 2c7f
+ 0xE3, 0x83, 0xAB, 0x52, 0xE3, 0x83, 0x95, 0xE3,
+ 0x82, 0x99, 0xE3, 0x83, 0x83, 0xE3, 0x82, 0xB7,
+ 0xE3, 0x82, 0xA7, 0xE3, 0x83, 0xAB, 0x52, 0xE3,
+ 0x83, 0x9F, 0xE3, 0x83, 0xAA, 0xE3, 0x83, 0x8F,
+ 0xE3, 0x82, 0x99, 0xE3, 0x83, 0xBC, 0xE3, 0x83,
+ 0xAB, 0x52, 0xE3, 0x83, 0xAC, 0xE3, 0x83, 0xB3,
+ 0xE3, 0x83, 0x88, 0xE3, 0x82, 0xB1, 0xE3, 0x82,
+ 0x99, 0xE3, 0x83, 0xB3, 0x61, 0xD8, 0xB5, 0xD9,
+ // Bytes 2c80 - 2cbf
+ 0x84, 0xD9, 0x89, 0x20, 0xD8, 0xA7, 0xD9, 0x84,
+ 0xD9, 0x84, 0xD9, 0x87, 0x20, 0xD8, 0xB9, 0xD9,
+ 0x84, 0xD9, 0x8A, 0xD9, 0x87, 0x20, 0xD9, 0x88,
+ 0xD8, 0xB3, 0xD9, 0x84, 0xD9, 0x85, 0x06, 0xE0,
+ 0xA7, 0x87, 0xE0, 0xA6, 0xBE, 0x01, 0x06, 0xE0,
+ 0xA7, 0x87, 0xE0, 0xA7, 0x97, 0x01, 0x06, 0xE0,
+ 0xAD, 0x87, 0xE0, 0xAC, 0xBE, 0x01, 0x06, 0xE0,
+ 0xAD, 0x87, 0xE0, 0xAD, 0x96, 0x01, 0x06, 0xE0,
+ // Bytes 2cc0 - 2cff
+ 0xAD, 0x87, 0xE0, 0xAD, 0x97, 0x01, 0x06, 0xE0,
+ 0xAE, 0x92, 0xE0, 0xAF, 0x97, 0x01, 0x06, 0xE0,
+ 0xAF, 0x86, 0xE0, 0xAE, 0xBE, 0x01, 0x06, 0xE0,
+ 0xAF, 0x86, 0xE0, 0xAF, 0x97, 0x01, 0x06, 0xE0,
+ 0xAF, 0x87, 0xE0, 0xAE, 0xBE, 0x01, 0x06, 0xE0,
+ 0xB2, 0xBF, 0xE0, 0xB3, 0x95, 0x01, 0x06, 0xE0,
+ 0xB3, 0x86, 0xE0, 0xB3, 0x95, 0x01, 0x06, 0xE0,
+ 0xB3, 0x86, 0xE0, 0xB3, 0x96, 0x01, 0x06, 0xE0,
+ // Bytes 2d00 - 2d3f
+ 0xB5, 0x86, 0xE0, 0xB4, 0xBE, 0x01, 0x06, 0xE0,
+ 0xB5, 0x86, 0xE0, 0xB5, 0x97, 0x01, 0x06, 0xE0,
+ 0xB5, 0x87, 0xE0, 0xB4, 0xBE, 0x01, 0x06, 0xE0,
+ 0xB7, 0x99, 0xE0, 0xB7, 0x9F, 0x01, 0x06, 0xE1,
+ 0x80, 0xA5, 0xE1, 0x80, 0xAE, 0x01, 0x06, 0xE1,
+ 0xAC, 0x85, 0xE1, 0xAC, 0xB5, 0x01, 0x06, 0xE1,
+ 0xAC, 0x87, 0xE1, 0xAC, 0xB5, 0x01, 0x06, 0xE1,
+ 0xAC, 0x89, 0xE1, 0xAC, 0xB5, 0x01, 0x06, 0xE1,
+ // Bytes 2d40 - 2d7f
+ 0xAC, 0x8B, 0xE1, 0xAC, 0xB5, 0x01, 0x06, 0xE1,
+ 0xAC, 0x8D, 0xE1, 0xAC, 0xB5, 0x01, 0x06, 0xE1,
+ 0xAC, 0x91, 0xE1, 0xAC, 0xB5, 0x01, 0x06, 0xE1,
+ 0xAC, 0xBA, 0xE1, 0xAC, 0xB5, 0x01, 0x06, 0xE1,
+ 0xAC, 0xBC, 0xE1, 0xAC, 0xB5, 0x01, 0x06, 0xE1,
+ 0xAC, 0xBE, 0xE1, 0xAC, 0xB5, 0x01, 0x06, 0xE1,
+ 0xAC, 0xBF, 0xE1, 0xAC, 0xB5, 0x01, 0x06, 0xE1,
+ 0xAD, 0x82, 0xE1, 0xAC, 0xB5, 0x01, 0x08, 0xF0,
+ // Bytes 2d80 - 2dbf
+ 0x91, 0x84, 0xB1, 0xF0, 0x91, 0x84, 0xA7, 0x01,
+ 0x08, 0xF0, 0x91, 0x84, 0xB2, 0xF0, 0x91, 0x84,
+ 0xA7, 0x01, 0x08, 0xF0, 0x91, 0x8D, 0x87, 0xF0,
+ 0x91, 0x8C, 0xBE, 0x01, 0x08, 0xF0, 0x91, 0x8D,
+ 0x87, 0xF0, 0x91, 0x8D, 0x97, 0x01, 0x08, 0xF0,
+ 0x91, 0x92, 0xB9, 0xF0, 0x91, 0x92, 0xB0, 0x01,
+ 0x08, 0xF0, 0x91, 0x92, 0xB9, 0xF0, 0x91, 0x92,
+ 0xBA, 0x01, 0x08, 0xF0, 0x91, 0x92, 0xB9, 0xF0,
+ // Bytes 2dc0 - 2dff
+ 0x91, 0x92, 0xBD, 0x01, 0x08, 0xF0, 0x91, 0x96,
+ 0xB8, 0xF0, 0x91, 0x96, 0xAF, 0x01, 0x08, 0xF0,
+ 0x91, 0x96, 0xB9, 0xF0, 0x91, 0x96, 0xAF, 0x01,
+ 0x09, 0xE0, 0xB3, 0x86, 0xE0, 0xB3, 0x82, 0xE0,
+ 0xB3, 0x95, 0x02, 0x09, 0xE0, 0xB7, 0x99, 0xE0,
+ 0xB7, 0x8F, 0xE0, 0xB7, 0x8A, 0x12, 0x44, 0x44,
+ 0x5A, 0xCC, 0x8C, 0xC9, 0x44, 0x44, 0x7A, 0xCC,
+ 0x8C, 0xC9, 0x44, 0x64, 0x7A, 0xCC, 0x8C, 0xC9,
+ // Bytes 2e00 - 2e3f
+ 0x46, 0xD9, 0x84, 0xD8, 0xA7, 0xD9, 0x93, 0xC9,
+ 0x46, 0xD9, 0x84, 0xD8, 0xA7, 0xD9, 0x94, 0xC9,
+ 0x46, 0xD9, 0x84, 0xD8, 0xA7, 0xD9, 0x95, 0xB5,
+ 0x46, 0xE1, 0x84, 0x80, 0xE1, 0x85, 0xA1, 0x01,
+ 0x46, 0xE1, 0x84, 0x82, 0xE1, 0x85, 0xA1, 0x01,
+ 0x46, 0xE1, 0x84, 0x83, 0xE1, 0x85, 0xA1, 0x01,
+ 0x46, 0xE1, 0x84, 0x85, 0xE1, 0x85, 0xA1, 0x01,
+ 0x46, 0xE1, 0x84, 0x86, 0xE1, 0x85, 0xA1, 0x01,
+ // Bytes 2e40 - 2e7f
+ 0x46, 0xE1, 0x84, 0x87, 0xE1, 0x85, 0xA1, 0x01,
+ 0x46, 0xE1, 0x84, 0x89, 0xE1, 0x85, 0xA1, 0x01,
+ 0x46, 0xE1, 0x84, 0x8B, 0xE1, 0x85, 0xA1, 0x01,
+ 0x46, 0xE1, 0x84, 0x8B, 0xE1, 0x85, 0xAE, 0x01,
+ 0x46, 0xE1, 0x84, 0x8C, 0xE1, 0x85, 0xA1, 0x01,
+ 0x46, 0xE1, 0x84, 0x8E, 0xE1, 0x85, 0xA1, 0x01,
+ 0x46, 0xE1, 0x84, 0x8F, 0xE1, 0x85, 0xA1, 0x01,
+ 0x46, 0xE1, 0x84, 0x90, 0xE1, 0x85, 0xA1, 0x01,
+ // Bytes 2e80 - 2ebf
+ 0x46, 0xE1, 0x84, 0x91, 0xE1, 0x85, 0xA1, 0x01,
+ 0x46, 0xE1, 0x84, 0x92, 0xE1, 0x85, 0xA1, 0x01,
+ 0x49, 0xE3, 0x83, 0xA1, 0xE3, 0x82, 0xAB, 0xE3,
+ 0x82, 0x99, 0x0D, 0x4C, 0xE1, 0x84, 0x8C, 0xE1,
+ 0x85, 0xAE, 0xE1, 0x84, 0x8B, 0xE1, 0x85, 0xB4,
+ 0x01, 0x4C, 0xE3, 0x82, 0xAD, 0xE3, 0x82, 0x99,
+ 0xE3, 0x82, 0xAB, 0xE3, 0x82, 0x99, 0x0D, 0x4C,
+ 0xE3, 0x82, 0xB3, 0xE3, 0x83, 0xBC, 0xE3, 0x83,
+ // Bytes 2ec0 - 2eff
+ 0x9B, 0xE3, 0x82, 0x9A, 0x0D, 0x4C, 0xE3, 0x83,
+ 0xA4, 0xE3, 0x83, 0xBC, 0xE3, 0x83, 0x88, 0xE3,
+ 0x82, 0x99, 0x0D, 0x4F, 0xE1, 0x84, 0x8E, 0xE1,
+ 0x85, 0xA1, 0xE1, 0x86, 0xB7, 0xE1, 0x84, 0x80,
+ 0xE1, 0x85, 0xA9, 0x01, 0x4F, 0xE3, 0x82, 0xA4,
+ 0xE3, 0x83, 0x8B, 0xE3, 0x83, 0xB3, 0xE3, 0x82,
+ 0xAF, 0xE3, 0x82, 0x99, 0x0D, 0x4F, 0xE3, 0x82,
+ 0xB7, 0xE3, 0x83, 0xAA, 0xE3, 0x83, 0xB3, 0xE3,
+ // Bytes 2f00 - 2f3f
+ 0x82, 0xAF, 0xE3, 0x82, 0x99, 0x0D, 0x4F, 0xE3,
+ 0x83, 0x98, 0xE3, 0x82, 0x9A, 0xE3, 0x83, 0xBC,
+ 0xE3, 0x82, 0xB7, 0xE3, 0x82, 0x99, 0x0D, 0x4F,
+ 0xE3, 0x83, 0x9B, 0xE3, 0x82, 0x9A, 0xE3, 0x83,
+ 0xB3, 0xE3, 0x83, 0x88, 0xE3, 0x82, 0x99, 0x0D,
+ 0x52, 0xE3, 0x82, 0xA8, 0xE3, 0x82, 0xB9, 0xE3,
+ 0x82, 0xAF, 0xE3, 0x83, 0xBC, 0xE3, 0x83, 0x88,
+ 0xE3, 0x82, 0x99, 0x0D, 0x52, 0xE3, 0x83, 0x95,
+ // Bytes 2f40 - 2f7f
+ 0xE3, 0x82, 0xA1, 0xE3, 0x83, 0xA9, 0xE3, 0x83,
+ 0x83, 0xE3, 0x83, 0x88, 0xE3, 0x82, 0x99, 0x0D,
+ 0x86, 0xE0, 0xB3, 0x86, 0xE0, 0xB3, 0x82, 0x01,
+ 0x86, 0xE0, 0xB7, 0x99, 0xE0, 0xB7, 0x8F, 0x01,
+ 0x03, 0x3C, 0xCC, 0xB8, 0x05, 0x03, 0x3D, 0xCC,
+ 0xB8, 0x05, 0x03, 0x3E, 0xCC, 0xB8, 0x05, 0x03,
+ 0x41, 0xCC, 0x80, 0xC9, 0x03, 0x41, 0xCC, 0x81,
+ 0xC9, 0x03, 0x41, 0xCC, 0x83, 0xC9, 0x03, 0x41,
+ // Bytes 2f80 - 2fbf
+ 0xCC, 0x84, 0xC9, 0x03, 0x41, 0xCC, 0x89, 0xC9,
+ 0x03, 0x41, 0xCC, 0x8C, 0xC9, 0x03, 0x41, 0xCC,
+ 0x8F, 0xC9, 0x03, 0x41, 0xCC, 0x91, 0xC9, 0x03,
+ 0x41, 0xCC, 0xA5, 0xB5, 0x03, 0x41, 0xCC, 0xA8,
+ 0xA5, 0x03, 0x42, 0xCC, 0x87, 0xC9, 0x03, 0x42,
+ 0xCC, 0xA3, 0xB5, 0x03, 0x42, 0xCC, 0xB1, 0xB5,
+ 0x03, 0x43, 0xCC, 0x81, 0xC9, 0x03, 0x43, 0xCC,
+ 0x82, 0xC9, 0x03, 0x43, 0xCC, 0x87, 0xC9, 0x03,
+ // Bytes 2fc0 - 2fff
+ 0x43, 0xCC, 0x8C, 0xC9, 0x03, 0x44, 0xCC, 0x87,
+ 0xC9, 0x03, 0x44, 0xCC, 0x8C, 0xC9, 0x03, 0x44,
+ 0xCC, 0xA3, 0xB5, 0x03, 0x44, 0xCC, 0xA7, 0xA5,
+ 0x03, 0x44, 0xCC, 0xAD, 0xB5, 0x03, 0x44, 0xCC,
+ 0xB1, 0xB5, 0x03, 0x45, 0xCC, 0x80, 0xC9, 0x03,
+ 0x45, 0xCC, 0x81, 0xC9, 0x03, 0x45, 0xCC, 0x83,
+ 0xC9, 0x03, 0x45, 0xCC, 0x86, 0xC9, 0x03, 0x45,
+ 0xCC, 0x87, 0xC9, 0x03, 0x45, 0xCC, 0x88, 0xC9,
+ // Bytes 3000 - 303f
+ 0x03, 0x45, 0xCC, 0x89, 0xC9, 0x03, 0x45, 0xCC,
+ 0x8C, 0xC9, 0x03, 0x45, 0xCC, 0x8F, 0xC9, 0x03,
+ 0x45, 0xCC, 0x91, 0xC9, 0x03, 0x45, 0xCC, 0xA8,
+ 0xA5, 0x03, 0x45, 0xCC, 0xAD, 0xB5, 0x03, 0x45,
+ 0xCC, 0xB0, 0xB5, 0x03, 0x46, 0xCC, 0x87, 0xC9,
+ 0x03, 0x47, 0xCC, 0x81, 0xC9, 0x03, 0x47, 0xCC,
+ 0x82, 0xC9, 0x03, 0x47, 0xCC, 0x84, 0xC9, 0x03,
+ 0x47, 0xCC, 0x86, 0xC9, 0x03, 0x47, 0xCC, 0x87,
+ // Bytes 3040 - 307f
+ 0xC9, 0x03, 0x47, 0xCC, 0x8C, 0xC9, 0x03, 0x47,
+ 0xCC, 0xA7, 0xA5, 0x03, 0x48, 0xCC, 0x82, 0xC9,
+ 0x03, 0x48, 0xCC, 0x87, 0xC9, 0x03, 0x48, 0xCC,
+ 0x88, 0xC9, 0x03, 0x48, 0xCC, 0x8C, 0xC9, 0x03,
+ 0x48, 0xCC, 0xA3, 0xB5, 0x03, 0x48, 0xCC, 0xA7,
+ 0xA5, 0x03, 0x48, 0xCC, 0xAE, 0xB5, 0x03, 0x49,
+ 0xCC, 0x80, 0xC9, 0x03, 0x49, 0xCC, 0x81, 0xC9,
+ 0x03, 0x49, 0xCC, 0x82, 0xC9, 0x03, 0x49, 0xCC,
+ // Bytes 3080 - 30bf
+ 0x83, 0xC9, 0x03, 0x49, 0xCC, 0x84, 0xC9, 0x03,
+ 0x49, 0xCC, 0x86, 0xC9, 0x03, 0x49, 0xCC, 0x87,
+ 0xC9, 0x03, 0x49, 0xCC, 0x89, 0xC9, 0x03, 0x49,
+ 0xCC, 0x8C, 0xC9, 0x03, 0x49, 0xCC, 0x8F, 0xC9,
+ 0x03, 0x49, 0xCC, 0x91, 0xC9, 0x03, 0x49, 0xCC,
+ 0xA3, 0xB5, 0x03, 0x49, 0xCC, 0xA8, 0xA5, 0x03,
+ 0x49, 0xCC, 0xB0, 0xB5, 0x03, 0x4A, 0xCC, 0x82,
+ 0xC9, 0x03, 0x4B, 0xCC, 0x81, 0xC9, 0x03, 0x4B,
+ // Bytes 30c0 - 30ff
+ 0xCC, 0x8C, 0xC9, 0x03, 0x4B, 0xCC, 0xA3, 0xB5,
+ 0x03, 0x4B, 0xCC, 0xA7, 0xA5, 0x03, 0x4B, 0xCC,
+ 0xB1, 0xB5, 0x03, 0x4C, 0xCC, 0x81, 0xC9, 0x03,
+ 0x4C, 0xCC, 0x8C, 0xC9, 0x03, 0x4C, 0xCC, 0xA7,
+ 0xA5, 0x03, 0x4C, 0xCC, 0xAD, 0xB5, 0x03, 0x4C,
+ 0xCC, 0xB1, 0xB5, 0x03, 0x4D, 0xCC, 0x81, 0xC9,
+ 0x03, 0x4D, 0xCC, 0x87, 0xC9, 0x03, 0x4D, 0xCC,
+ 0xA3, 0xB5, 0x03, 0x4E, 0xCC, 0x80, 0xC9, 0x03,
+ // Bytes 3100 - 313f
+ 0x4E, 0xCC, 0x81, 0xC9, 0x03, 0x4E, 0xCC, 0x83,
+ 0xC9, 0x03, 0x4E, 0xCC, 0x87, 0xC9, 0x03, 0x4E,
+ 0xCC, 0x8C, 0xC9, 0x03, 0x4E, 0xCC, 0xA3, 0xB5,
+ 0x03, 0x4E, 0xCC, 0xA7, 0xA5, 0x03, 0x4E, 0xCC,
+ 0xAD, 0xB5, 0x03, 0x4E, 0xCC, 0xB1, 0xB5, 0x03,
+ 0x4F, 0xCC, 0x80, 0xC9, 0x03, 0x4F, 0xCC, 0x81,
+ 0xC9, 0x03, 0x4F, 0xCC, 0x86, 0xC9, 0x03, 0x4F,
+ 0xCC, 0x89, 0xC9, 0x03, 0x4F, 0xCC, 0x8B, 0xC9,
+ // Bytes 3140 - 317f
+ 0x03, 0x4F, 0xCC, 0x8C, 0xC9, 0x03, 0x4F, 0xCC,
+ 0x8F, 0xC9, 0x03, 0x4F, 0xCC, 0x91, 0xC9, 0x03,
+ 0x50, 0xCC, 0x81, 0xC9, 0x03, 0x50, 0xCC, 0x87,
+ 0xC9, 0x03, 0x52, 0xCC, 0x81, 0xC9, 0x03, 0x52,
+ 0xCC, 0x87, 0xC9, 0x03, 0x52, 0xCC, 0x8C, 0xC9,
+ 0x03, 0x52, 0xCC, 0x8F, 0xC9, 0x03, 0x52, 0xCC,
+ 0x91, 0xC9, 0x03, 0x52, 0xCC, 0xA7, 0xA5, 0x03,
+ 0x52, 0xCC, 0xB1, 0xB5, 0x03, 0x53, 0xCC, 0x82,
+ // Bytes 3180 - 31bf
+ 0xC9, 0x03, 0x53, 0xCC, 0x87, 0xC9, 0x03, 0x53,
+ 0xCC, 0xA6, 0xB5, 0x03, 0x53, 0xCC, 0xA7, 0xA5,
+ 0x03, 0x54, 0xCC, 0x87, 0xC9, 0x03, 0x54, 0xCC,
+ 0x8C, 0xC9, 0x03, 0x54, 0xCC, 0xA3, 0xB5, 0x03,
+ 0x54, 0xCC, 0xA6, 0xB5, 0x03, 0x54, 0xCC, 0xA7,
+ 0xA5, 0x03, 0x54, 0xCC, 0xAD, 0xB5, 0x03, 0x54,
+ 0xCC, 0xB1, 0xB5, 0x03, 0x55, 0xCC, 0x80, 0xC9,
+ 0x03, 0x55, 0xCC, 0x81, 0xC9, 0x03, 0x55, 0xCC,
+ // Bytes 31c0 - 31ff
+ 0x82, 0xC9, 0x03, 0x55, 0xCC, 0x86, 0xC9, 0x03,
+ 0x55, 0xCC, 0x89, 0xC9, 0x03, 0x55, 0xCC, 0x8A,
+ 0xC9, 0x03, 0x55, 0xCC, 0x8B, 0xC9, 0x03, 0x55,
+ 0xCC, 0x8C, 0xC9, 0x03, 0x55, 0xCC, 0x8F, 0xC9,
+ 0x03, 0x55, 0xCC, 0x91, 0xC9, 0x03, 0x55, 0xCC,
+ 0xA3, 0xB5, 0x03, 0x55, 0xCC, 0xA4, 0xB5, 0x03,
+ 0x55, 0xCC, 0xA8, 0xA5, 0x03, 0x55, 0xCC, 0xAD,
+ 0xB5, 0x03, 0x55, 0xCC, 0xB0, 0xB5, 0x03, 0x56,
+ // Bytes 3200 - 323f
+ 0xCC, 0x83, 0xC9, 0x03, 0x56, 0xCC, 0xA3, 0xB5,
+ 0x03, 0x57, 0xCC, 0x80, 0xC9, 0x03, 0x57, 0xCC,
+ 0x81, 0xC9, 0x03, 0x57, 0xCC, 0x82, 0xC9, 0x03,
+ 0x57, 0xCC, 0x87, 0xC9, 0x03, 0x57, 0xCC, 0x88,
+ 0xC9, 0x03, 0x57, 0xCC, 0xA3, 0xB5, 0x03, 0x58,
+ 0xCC, 0x87, 0xC9, 0x03, 0x58, 0xCC, 0x88, 0xC9,
+ 0x03, 0x59, 0xCC, 0x80, 0xC9, 0x03, 0x59, 0xCC,
+ 0x81, 0xC9, 0x03, 0x59, 0xCC, 0x82, 0xC9, 0x03,
+ // Bytes 3240 - 327f
+ 0x59, 0xCC, 0x83, 0xC9, 0x03, 0x59, 0xCC, 0x84,
+ 0xC9, 0x03, 0x59, 0xCC, 0x87, 0xC9, 0x03, 0x59,
+ 0xCC, 0x88, 0xC9, 0x03, 0x59, 0xCC, 0x89, 0xC9,
+ 0x03, 0x59, 0xCC, 0xA3, 0xB5, 0x03, 0x5A, 0xCC,
+ 0x81, 0xC9, 0x03, 0x5A, 0xCC, 0x82, 0xC9, 0x03,
+ 0x5A, 0xCC, 0x87, 0xC9, 0x03, 0x5A, 0xCC, 0x8C,
+ 0xC9, 0x03, 0x5A, 0xCC, 0xA3, 0xB5, 0x03, 0x5A,
+ 0xCC, 0xB1, 0xB5, 0x03, 0x61, 0xCC, 0x80, 0xC9,
+ // Bytes 3280 - 32bf
+ 0x03, 0x61, 0xCC, 0x81, 0xC9, 0x03, 0x61, 0xCC,
+ 0x83, 0xC9, 0x03, 0x61, 0xCC, 0x84, 0xC9, 0x03,
+ 0x61, 0xCC, 0x89, 0xC9, 0x03, 0x61, 0xCC, 0x8C,
+ 0xC9, 0x03, 0x61, 0xCC, 0x8F, 0xC9, 0x03, 0x61,
+ 0xCC, 0x91, 0xC9, 0x03, 0x61, 0xCC, 0xA5, 0xB5,
+ 0x03, 0x61, 0xCC, 0xA8, 0xA5, 0x03, 0x62, 0xCC,
+ 0x87, 0xC9, 0x03, 0x62, 0xCC, 0xA3, 0xB5, 0x03,
+ 0x62, 0xCC, 0xB1, 0xB5, 0x03, 0x63, 0xCC, 0x81,
+ // Bytes 32c0 - 32ff
+ 0xC9, 0x03, 0x63, 0xCC, 0x82, 0xC9, 0x03, 0x63,
+ 0xCC, 0x87, 0xC9, 0x03, 0x63, 0xCC, 0x8C, 0xC9,
+ 0x03, 0x64, 0xCC, 0x87, 0xC9, 0x03, 0x64, 0xCC,
+ 0x8C, 0xC9, 0x03, 0x64, 0xCC, 0xA3, 0xB5, 0x03,
+ 0x64, 0xCC, 0xA7, 0xA5, 0x03, 0x64, 0xCC, 0xAD,
+ 0xB5, 0x03, 0x64, 0xCC, 0xB1, 0xB5, 0x03, 0x65,
+ 0xCC, 0x80, 0xC9, 0x03, 0x65, 0xCC, 0x81, 0xC9,
+ 0x03, 0x65, 0xCC, 0x83, 0xC9, 0x03, 0x65, 0xCC,
+ // Bytes 3300 - 333f
+ 0x86, 0xC9, 0x03, 0x65, 0xCC, 0x87, 0xC9, 0x03,
+ 0x65, 0xCC, 0x88, 0xC9, 0x03, 0x65, 0xCC, 0x89,
+ 0xC9, 0x03, 0x65, 0xCC, 0x8C, 0xC9, 0x03, 0x65,
+ 0xCC, 0x8F, 0xC9, 0x03, 0x65, 0xCC, 0x91, 0xC9,
+ 0x03, 0x65, 0xCC, 0xA8, 0xA5, 0x03, 0x65, 0xCC,
+ 0xAD, 0xB5, 0x03, 0x65, 0xCC, 0xB0, 0xB5, 0x03,
+ 0x66, 0xCC, 0x87, 0xC9, 0x03, 0x67, 0xCC, 0x81,
+ 0xC9, 0x03, 0x67, 0xCC, 0x82, 0xC9, 0x03, 0x67,
+ // Bytes 3340 - 337f
+ 0xCC, 0x84, 0xC9, 0x03, 0x67, 0xCC, 0x86, 0xC9,
+ 0x03, 0x67, 0xCC, 0x87, 0xC9, 0x03, 0x67, 0xCC,
+ 0x8C, 0xC9, 0x03, 0x67, 0xCC, 0xA7, 0xA5, 0x03,
+ 0x68, 0xCC, 0x82, 0xC9, 0x03, 0x68, 0xCC, 0x87,
+ 0xC9, 0x03, 0x68, 0xCC, 0x88, 0xC9, 0x03, 0x68,
+ 0xCC, 0x8C, 0xC9, 0x03, 0x68, 0xCC, 0xA3, 0xB5,
+ 0x03, 0x68, 0xCC, 0xA7, 0xA5, 0x03, 0x68, 0xCC,
+ 0xAE, 0xB5, 0x03, 0x68, 0xCC, 0xB1, 0xB5, 0x03,
+ // Bytes 3380 - 33bf
+ 0x69, 0xCC, 0x80, 0xC9, 0x03, 0x69, 0xCC, 0x81,
+ 0xC9, 0x03, 0x69, 0xCC, 0x82, 0xC9, 0x03, 0x69,
+ 0xCC, 0x83, 0xC9, 0x03, 0x69, 0xCC, 0x84, 0xC9,
+ 0x03, 0x69, 0xCC, 0x86, 0xC9, 0x03, 0x69, 0xCC,
+ 0x89, 0xC9, 0x03, 0x69, 0xCC, 0x8C, 0xC9, 0x03,
+ 0x69, 0xCC, 0x8F, 0xC9, 0x03, 0x69, 0xCC, 0x91,
+ 0xC9, 0x03, 0x69, 0xCC, 0xA3, 0xB5, 0x03, 0x69,
+ 0xCC, 0xA8, 0xA5, 0x03, 0x69, 0xCC, 0xB0, 0xB5,
+ // Bytes 33c0 - 33ff
+ 0x03, 0x6A, 0xCC, 0x82, 0xC9, 0x03, 0x6A, 0xCC,
+ 0x8C, 0xC9, 0x03, 0x6B, 0xCC, 0x81, 0xC9, 0x03,
+ 0x6B, 0xCC, 0x8C, 0xC9, 0x03, 0x6B, 0xCC, 0xA3,
+ 0xB5, 0x03, 0x6B, 0xCC, 0xA7, 0xA5, 0x03, 0x6B,
+ 0xCC, 0xB1, 0xB5, 0x03, 0x6C, 0xCC, 0x81, 0xC9,
+ 0x03, 0x6C, 0xCC, 0x8C, 0xC9, 0x03, 0x6C, 0xCC,
+ 0xA7, 0xA5, 0x03, 0x6C, 0xCC, 0xAD, 0xB5, 0x03,
+ 0x6C, 0xCC, 0xB1, 0xB5, 0x03, 0x6D, 0xCC, 0x81,
+ // Bytes 3400 - 343f
+ 0xC9, 0x03, 0x6D, 0xCC, 0x87, 0xC9, 0x03, 0x6D,
+ 0xCC, 0xA3, 0xB5, 0x03, 0x6E, 0xCC, 0x80, 0xC9,
+ 0x03, 0x6E, 0xCC, 0x81, 0xC9, 0x03, 0x6E, 0xCC,
+ 0x83, 0xC9, 0x03, 0x6E, 0xCC, 0x87, 0xC9, 0x03,
+ 0x6E, 0xCC, 0x8C, 0xC9, 0x03, 0x6E, 0xCC, 0xA3,
+ 0xB5, 0x03, 0x6E, 0xCC, 0xA7, 0xA5, 0x03, 0x6E,
+ 0xCC, 0xAD, 0xB5, 0x03, 0x6E, 0xCC, 0xB1, 0xB5,
+ 0x03, 0x6F, 0xCC, 0x80, 0xC9, 0x03, 0x6F, 0xCC,
+ // Bytes 3440 - 347f
+ 0x81, 0xC9, 0x03, 0x6F, 0xCC, 0x86, 0xC9, 0x03,
+ 0x6F, 0xCC, 0x89, 0xC9, 0x03, 0x6F, 0xCC, 0x8B,
+ 0xC9, 0x03, 0x6F, 0xCC, 0x8C, 0xC9, 0x03, 0x6F,
+ 0xCC, 0x8F, 0xC9, 0x03, 0x6F, 0xCC, 0x91, 0xC9,
+ 0x03, 0x70, 0xCC, 0x81, 0xC9, 0x03, 0x70, 0xCC,
+ 0x87, 0xC9, 0x03, 0x72, 0xCC, 0x81, 0xC9, 0x03,
+ 0x72, 0xCC, 0x87, 0xC9, 0x03, 0x72, 0xCC, 0x8C,
+ 0xC9, 0x03, 0x72, 0xCC, 0x8F, 0xC9, 0x03, 0x72,
+ // Bytes 3480 - 34bf
+ 0xCC, 0x91, 0xC9, 0x03, 0x72, 0xCC, 0xA7, 0xA5,
+ 0x03, 0x72, 0xCC, 0xB1, 0xB5, 0x03, 0x73, 0xCC,
+ 0x82, 0xC9, 0x03, 0x73, 0xCC, 0x87, 0xC9, 0x03,
+ 0x73, 0xCC, 0xA6, 0xB5, 0x03, 0x73, 0xCC, 0xA7,
+ 0xA5, 0x03, 0x74, 0xCC, 0x87, 0xC9, 0x03, 0x74,
+ 0xCC, 0x88, 0xC9, 0x03, 0x74, 0xCC, 0x8C, 0xC9,
+ 0x03, 0x74, 0xCC, 0xA3, 0xB5, 0x03, 0x74, 0xCC,
+ 0xA6, 0xB5, 0x03, 0x74, 0xCC, 0xA7, 0xA5, 0x03,
+ // Bytes 34c0 - 34ff
+ 0x74, 0xCC, 0xAD, 0xB5, 0x03, 0x74, 0xCC, 0xB1,
+ 0xB5, 0x03, 0x75, 0xCC, 0x80, 0xC9, 0x03, 0x75,
+ 0xCC, 0x81, 0xC9, 0x03, 0x75, 0xCC, 0x82, 0xC9,
+ 0x03, 0x75, 0xCC, 0x86, 0xC9, 0x03, 0x75, 0xCC,
+ 0x89, 0xC9, 0x03, 0x75, 0xCC, 0x8A, 0xC9, 0x03,
+ 0x75, 0xCC, 0x8B, 0xC9, 0x03, 0x75, 0xCC, 0x8C,
+ 0xC9, 0x03, 0x75, 0xCC, 0x8F, 0xC9, 0x03, 0x75,
+ 0xCC, 0x91, 0xC9, 0x03, 0x75, 0xCC, 0xA3, 0xB5,
+ // Bytes 3500 - 353f
+ 0x03, 0x75, 0xCC, 0xA4, 0xB5, 0x03, 0x75, 0xCC,
+ 0xA8, 0xA5, 0x03, 0x75, 0xCC, 0xAD, 0xB5, 0x03,
+ 0x75, 0xCC, 0xB0, 0xB5, 0x03, 0x76, 0xCC, 0x83,
+ 0xC9, 0x03, 0x76, 0xCC, 0xA3, 0xB5, 0x03, 0x77,
+ 0xCC, 0x80, 0xC9, 0x03, 0x77, 0xCC, 0x81, 0xC9,
+ 0x03, 0x77, 0xCC, 0x82, 0xC9, 0x03, 0x77, 0xCC,
+ 0x87, 0xC9, 0x03, 0x77, 0xCC, 0x88, 0xC9, 0x03,
+ 0x77, 0xCC, 0x8A, 0xC9, 0x03, 0x77, 0xCC, 0xA3,
+ // Bytes 3540 - 357f
+ 0xB5, 0x03, 0x78, 0xCC, 0x87, 0xC9, 0x03, 0x78,
+ 0xCC, 0x88, 0xC9, 0x03, 0x79, 0xCC, 0x80, 0xC9,
+ 0x03, 0x79, 0xCC, 0x81, 0xC9, 0x03, 0x79, 0xCC,
+ 0x82, 0xC9, 0x03, 0x79, 0xCC, 0x83, 0xC9, 0x03,
+ 0x79, 0xCC, 0x84, 0xC9, 0x03, 0x79, 0xCC, 0x87,
+ 0xC9, 0x03, 0x79, 0xCC, 0x88, 0xC9, 0x03, 0x79,
+ 0xCC, 0x89, 0xC9, 0x03, 0x79, 0xCC, 0x8A, 0xC9,
+ 0x03, 0x79, 0xCC, 0xA3, 0xB5, 0x03, 0x7A, 0xCC,
+ // Bytes 3580 - 35bf
+ 0x81, 0xC9, 0x03, 0x7A, 0xCC, 0x82, 0xC9, 0x03,
+ 0x7A, 0xCC, 0x87, 0xC9, 0x03, 0x7A, 0xCC, 0x8C,
+ 0xC9, 0x03, 0x7A, 0xCC, 0xA3, 0xB5, 0x03, 0x7A,
+ 0xCC, 0xB1, 0xB5, 0x04, 0xC2, 0xA8, 0xCC, 0x80,
+ 0xCA, 0x04, 0xC2, 0xA8, 0xCC, 0x81, 0xCA, 0x04,
+ 0xC2, 0xA8, 0xCD, 0x82, 0xCA, 0x04, 0xC3, 0x86,
+ 0xCC, 0x81, 0xC9, 0x04, 0xC3, 0x86, 0xCC, 0x84,
+ 0xC9, 0x04, 0xC3, 0x98, 0xCC, 0x81, 0xC9, 0x04,
+ // Bytes 35c0 - 35ff
+ 0xC3, 0xA6, 0xCC, 0x81, 0xC9, 0x04, 0xC3, 0xA6,
+ 0xCC, 0x84, 0xC9, 0x04, 0xC3, 0xB8, 0xCC, 0x81,
+ 0xC9, 0x04, 0xC5, 0xBF, 0xCC, 0x87, 0xC9, 0x04,
+ 0xC6, 0xB7, 0xCC, 0x8C, 0xC9, 0x04, 0xCA, 0x92,
+ 0xCC, 0x8C, 0xC9, 0x04, 0xCE, 0x91, 0xCC, 0x80,
+ 0xC9, 0x04, 0xCE, 0x91, 0xCC, 0x81, 0xC9, 0x04,
+ 0xCE, 0x91, 0xCC, 0x84, 0xC9, 0x04, 0xCE, 0x91,
+ 0xCC, 0x86, 0xC9, 0x04, 0xCE, 0x91, 0xCD, 0x85,
+ // Bytes 3600 - 363f
+ 0xD9, 0x04, 0xCE, 0x95, 0xCC, 0x80, 0xC9, 0x04,
+ 0xCE, 0x95, 0xCC, 0x81, 0xC9, 0x04, 0xCE, 0x97,
+ 0xCC, 0x80, 0xC9, 0x04, 0xCE, 0x97, 0xCC, 0x81,
+ 0xC9, 0x04, 0xCE, 0x97, 0xCD, 0x85, 0xD9, 0x04,
+ 0xCE, 0x99, 0xCC, 0x80, 0xC9, 0x04, 0xCE, 0x99,
+ 0xCC, 0x81, 0xC9, 0x04, 0xCE, 0x99, 0xCC, 0x84,
+ 0xC9, 0x04, 0xCE, 0x99, 0xCC, 0x86, 0xC9, 0x04,
+ 0xCE, 0x99, 0xCC, 0x88, 0xC9, 0x04, 0xCE, 0x9F,
+ // Bytes 3640 - 367f
+ 0xCC, 0x80, 0xC9, 0x04, 0xCE, 0x9F, 0xCC, 0x81,
+ 0xC9, 0x04, 0xCE, 0xA1, 0xCC, 0x94, 0xC9, 0x04,
+ 0xCE, 0xA5, 0xCC, 0x80, 0xC9, 0x04, 0xCE, 0xA5,
+ 0xCC, 0x81, 0xC9, 0x04, 0xCE, 0xA5, 0xCC, 0x84,
+ 0xC9, 0x04, 0xCE, 0xA5, 0xCC, 0x86, 0xC9, 0x04,
+ 0xCE, 0xA5, 0xCC, 0x88, 0xC9, 0x04, 0xCE, 0xA9,
+ 0xCC, 0x80, 0xC9, 0x04, 0xCE, 0xA9, 0xCC, 0x81,
+ 0xC9, 0x04, 0xCE, 0xA9, 0xCD, 0x85, 0xD9, 0x04,
+ // Bytes 3680 - 36bf
+ 0xCE, 0xB1, 0xCC, 0x84, 0xC9, 0x04, 0xCE, 0xB1,
+ 0xCC, 0x86, 0xC9, 0x04, 0xCE, 0xB1, 0xCD, 0x85,
+ 0xD9, 0x04, 0xCE, 0xB5, 0xCC, 0x80, 0xC9, 0x04,
+ 0xCE, 0xB5, 0xCC, 0x81, 0xC9, 0x04, 0xCE, 0xB7,
+ 0xCD, 0x85, 0xD9, 0x04, 0xCE, 0xB9, 0xCC, 0x80,
+ 0xC9, 0x04, 0xCE, 0xB9, 0xCC, 0x81, 0xC9, 0x04,
+ 0xCE, 0xB9, 0xCC, 0x84, 0xC9, 0x04, 0xCE, 0xB9,
+ 0xCC, 0x86, 0xC9, 0x04, 0xCE, 0xB9, 0xCD, 0x82,
+ // Bytes 36c0 - 36ff
+ 0xC9, 0x04, 0xCE, 0xBF, 0xCC, 0x80, 0xC9, 0x04,
+ 0xCE, 0xBF, 0xCC, 0x81, 0xC9, 0x04, 0xCF, 0x81,
+ 0xCC, 0x93, 0xC9, 0x04, 0xCF, 0x81, 0xCC, 0x94,
+ 0xC9, 0x04, 0xCF, 0x85, 0xCC, 0x80, 0xC9, 0x04,
+ 0xCF, 0x85, 0xCC, 0x81, 0xC9, 0x04, 0xCF, 0x85,
+ 0xCC, 0x84, 0xC9, 0x04, 0xCF, 0x85, 0xCC, 0x86,
+ 0xC9, 0x04, 0xCF, 0x85, 0xCD, 0x82, 0xC9, 0x04,
+ 0xCF, 0x89, 0xCD, 0x85, 0xD9, 0x04, 0xCF, 0x92,
+ // Bytes 3700 - 373f
+ 0xCC, 0x81, 0xC9, 0x04, 0xCF, 0x92, 0xCC, 0x88,
+ 0xC9, 0x04, 0xD0, 0x86, 0xCC, 0x88, 0xC9, 0x04,
+ 0xD0, 0x90, 0xCC, 0x86, 0xC9, 0x04, 0xD0, 0x90,
+ 0xCC, 0x88, 0xC9, 0x04, 0xD0, 0x93, 0xCC, 0x81,
+ 0xC9, 0x04, 0xD0, 0x95, 0xCC, 0x80, 0xC9, 0x04,
+ 0xD0, 0x95, 0xCC, 0x86, 0xC9, 0x04, 0xD0, 0x95,
+ 0xCC, 0x88, 0xC9, 0x04, 0xD0, 0x96, 0xCC, 0x86,
+ 0xC9, 0x04, 0xD0, 0x96, 0xCC, 0x88, 0xC9, 0x04,
+ // Bytes 3740 - 377f
+ 0xD0, 0x97, 0xCC, 0x88, 0xC9, 0x04, 0xD0, 0x98,
+ 0xCC, 0x80, 0xC9, 0x04, 0xD0, 0x98, 0xCC, 0x84,
+ 0xC9, 0x04, 0xD0, 0x98, 0xCC, 0x86, 0xC9, 0x04,
+ 0xD0, 0x98, 0xCC, 0x88, 0xC9, 0x04, 0xD0, 0x9A,
+ 0xCC, 0x81, 0xC9, 0x04, 0xD0, 0x9E, 0xCC, 0x88,
+ 0xC9, 0x04, 0xD0, 0xA3, 0xCC, 0x84, 0xC9, 0x04,
+ 0xD0, 0xA3, 0xCC, 0x86, 0xC9, 0x04, 0xD0, 0xA3,
+ 0xCC, 0x88, 0xC9, 0x04, 0xD0, 0xA3, 0xCC, 0x8B,
+ // Bytes 3780 - 37bf
+ 0xC9, 0x04, 0xD0, 0xA7, 0xCC, 0x88, 0xC9, 0x04,
+ 0xD0, 0xAB, 0xCC, 0x88, 0xC9, 0x04, 0xD0, 0xAD,
+ 0xCC, 0x88, 0xC9, 0x04, 0xD0, 0xB0, 0xCC, 0x86,
+ 0xC9, 0x04, 0xD0, 0xB0, 0xCC, 0x88, 0xC9, 0x04,
+ 0xD0, 0xB3, 0xCC, 0x81, 0xC9, 0x04, 0xD0, 0xB5,
+ 0xCC, 0x80, 0xC9, 0x04, 0xD0, 0xB5, 0xCC, 0x86,
+ 0xC9, 0x04, 0xD0, 0xB5, 0xCC, 0x88, 0xC9, 0x04,
+ 0xD0, 0xB6, 0xCC, 0x86, 0xC9, 0x04, 0xD0, 0xB6,
+ // Bytes 37c0 - 37ff
+ 0xCC, 0x88, 0xC9, 0x04, 0xD0, 0xB7, 0xCC, 0x88,
+ 0xC9, 0x04, 0xD0, 0xB8, 0xCC, 0x80, 0xC9, 0x04,
+ 0xD0, 0xB8, 0xCC, 0x84, 0xC9, 0x04, 0xD0, 0xB8,
+ 0xCC, 0x86, 0xC9, 0x04, 0xD0, 0xB8, 0xCC, 0x88,
+ 0xC9, 0x04, 0xD0, 0xBA, 0xCC, 0x81, 0xC9, 0x04,
+ 0xD0, 0xBE, 0xCC, 0x88, 0xC9, 0x04, 0xD1, 0x83,
+ 0xCC, 0x84, 0xC9, 0x04, 0xD1, 0x83, 0xCC, 0x86,
+ 0xC9, 0x04, 0xD1, 0x83, 0xCC, 0x88, 0xC9, 0x04,
+ // Bytes 3800 - 383f
+ 0xD1, 0x83, 0xCC, 0x8B, 0xC9, 0x04, 0xD1, 0x87,
+ 0xCC, 0x88, 0xC9, 0x04, 0xD1, 0x8B, 0xCC, 0x88,
+ 0xC9, 0x04, 0xD1, 0x8D, 0xCC, 0x88, 0xC9, 0x04,
+ 0xD1, 0x96, 0xCC, 0x88, 0xC9, 0x04, 0xD1, 0xB4,
+ 0xCC, 0x8F, 0xC9, 0x04, 0xD1, 0xB5, 0xCC, 0x8F,
+ 0xC9, 0x04, 0xD3, 0x98, 0xCC, 0x88, 0xC9, 0x04,
+ 0xD3, 0x99, 0xCC, 0x88, 0xC9, 0x04, 0xD3, 0xA8,
+ 0xCC, 0x88, 0xC9, 0x04, 0xD3, 0xA9, 0xCC, 0x88,
+ // Bytes 3840 - 387f
+ 0xC9, 0x04, 0xD8, 0xA7, 0xD9, 0x93, 0xC9, 0x04,
+ 0xD8, 0xA7, 0xD9, 0x94, 0xC9, 0x04, 0xD8, 0xA7,
+ 0xD9, 0x95, 0xB5, 0x04, 0xD9, 0x88, 0xD9, 0x94,
+ 0xC9, 0x04, 0xD9, 0x8A, 0xD9, 0x94, 0xC9, 0x04,
+ 0xDB, 0x81, 0xD9, 0x94, 0xC9, 0x04, 0xDB, 0x92,
+ 0xD9, 0x94, 0xC9, 0x04, 0xDB, 0x95, 0xD9, 0x94,
+ 0xC9, 0x05, 0x41, 0xCC, 0x82, 0xCC, 0x80, 0xCA,
+ 0x05, 0x41, 0xCC, 0x82, 0xCC, 0x81, 0xCA, 0x05,
+ // Bytes 3880 - 38bf
+ 0x41, 0xCC, 0x82, 0xCC, 0x83, 0xCA, 0x05, 0x41,
+ 0xCC, 0x82, 0xCC, 0x89, 0xCA, 0x05, 0x41, 0xCC,
+ 0x86, 0xCC, 0x80, 0xCA, 0x05, 0x41, 0xCC, 0x86,
+ 0xCC, 0x81, 0xCA, 0x05, 0x41, 0xCC, 0x86, 0xCC,
+ 0x83, 0xCA, 0x05, 0x41, 0xCC, 0x86, 0xCC, 0x89,
+ 0xCA, 0x05, 0x41, 0xCC, 0x87, 0xCC, 0x84, 0xCA,
+ 0x05, 0x41, 0xCC, 0x88, 0xCC, 0x84, 0xCA, 0x05,
+ 0x41, 0xCC, 0x8A, 0xCC, 0x81, 0xCA, 0x05, 0x41,
+ // Bytes 38c0 - 38ff
+ 0xCC, 0xA3, 0xCC, 0x82, 0xCA, 0x05, 0x41, 0xCC,
+ 0xA3, 0xCC, 0x86, 0xCA, 0x05, 0x43, 0xCC, 0xA7,
+ 0xCC, 0x81, 0xCA, 0x05, 0x45, 0xCC, 0x82, 0xCC,
+ 0x80, 0xCA, 0x05, 0x45, 0xCC, 0x82, 0xCC, 0x81,
+ 0xCA, 0x05, 0x45, 0xCC, 0x82, 0xCC, 0x83, 0xCA,
+ 0x05, 0x45, 0xCC, 0x82, 0xCC, 0x89, 0xCA, 0x05,
+ 0x45, 0xCC, 0x84, 0xCC, 0x80, 0xCA, 0x05, 0x45,
+ 0xCC, 0x84, 0xCC, 0x81, 0xCA, 0x05, 0x45, 0xCC,
+ // Bytes 3900 - 393f
+ 0xA3, 0xCC, 0x82, 0xCA, 0x05, 0x45, 0xCC, 0xA7,
+ 0xCC, 0x86, 0xCA, 0x05, 0x49, 0xCC, 0x88, 0xCC,
+ 0x81, 0xCA, 0x05, 0x4C, 0xCC, 0xA3, 0xCC, 0x84,
+ 0xCA, 0x05, 0x4F, 0xCC, 0x82, 0xCC, 0x80, 0xCA,
+ 0x05, 0x4F, 0xCC, 0x82, 0xCC, 0x81, 0xCA, 0x05,
+ 0x4F, 0xCC, 0x82, 0xCC, 0x83, 0xCA, 0x05, 0x4F,
+ 0xCC, 0x82, 0xCC, 0x89, 0xCA, 0x05, 0x4F, 0xCC,
+ 0x83, 0xCC, 0x81, 0xCA, 0x05, 0x4F, 0xCC, 0x83,
+ // Bytes 3940 - 397f
+ 0xCC, 0x84, 0xCA, 0x05, 0x4F, 0xCC, 0x83, 0xCC,
+ 0x88, 0xCA, 0x05, 0x4F, 0xCC, 0x84, 0xCC, 0x80,
+ 0xCA, 0x05, 0x4F, 0xCC, 0x84, 0xCC, 0x81, 0xCA,
+ 0x05, 0x4F, 0xCC, 0x87, 0xCC, 0x84, 0xCA, 0x05,
+ 0x4F, 0xCC, 0x88, 0xCC, 0x84, 0xCA, 0x05, 0x4F,
+ 0xCC, 0x9B, 0xCC, 0x80, 0xCA, 0x05, 0x4F, 0xCC,
+ 0x9B, 0xCC, 0x81, 0xCA, 0x05, 0x4F, 0xCC, 0x9B,
+ 0xCC, 0x83, 0xCA, 0x05, 0x4F, 0xCC, 0x9B, 0xCC,
+ // Bytes 3980 - 39bf
+ 0x89, 0xCA, 0x05, 0x4F, 0xCC, 0x9B, 0xCC, 0xA3,
+ 0xB6, 0x05, 0x4F, 0xCC, 0xA3, 0xCC, 0x82, 0xCA,
+ 0x05, 0x4F, 0xCC, 0xA8, 0xCC, 0x84, 0xCA, 0x05,
+ 0x52, 0xCC, 0xA3, 0xCC, 0x84, 0xCA, 0x05, 0x53,
+ 0xCC, 0x81, 0xCC, 0x87, 0xCA, 0x05, 0x53, 0xCC,
+ 0x8C, 0xCC, 0x87, 0xCA, 0x05, 0x53, 0xCC, 0xA3,
+ 0xCC, 0x87, 0xCA, 0x05, 0x55, 0xCC, 0x83, 0xCC,
+ 0x81, 0xCA, 0x05, 0x55, 0xCC, 0x84, 0xCC, 0x88,
+ // Bytes 39c0 - 39ff
+ 0xCA, 0x05, 0x55, 0xCC, 0x88, 0xCC, 0x80, 0xCA,
+ 0x05, 0x55, 0xCC, 0x88, 0xCC, 0x81, 0xCA, 0x05,
+ 0x55, 0xCC, 0x88, 0xCC, 0x84, 0xCA, 0x05, 0x55,
+ 0xCC, 0x88, 0xCC, 0x8C, 0xCA, 0x05, 0x55, 0xCC,
+ 0x9B, 0xCC, 0x80, 0xCA, 0x05, 0x55, 0xCC, 0x9B,
+ 0xCC, 0x81, 0xCA, 0x05, 0x55, 0xCC, 0x9B, 0xCC,
+ 0x83, 0xCA, 0x05, 0x55, 0xCC, 0x9B, 0xCC, 0x89,
+ 0xCA, 0x05, 0x55, 0xCC, 0x9B, 0xCC, 0xA3, 0xB6,
+ // Bytes 3a00 - 3a3f
+ 0x05, 0x61, 0xCC, 0x82, 0xCC, 0x80, 0xCA, 0x05,
+ 0x61, 0xCC, 0x82, 0xCC, 0x81, 0xCA, 0x05, 0x61,
+ 0xCC, 0x82, 0xCC, 0x83, 0xCA, 0x05, 0x61, 0xCC,
+ 0x82, 0xCC, 0x89, 0xCA, 0x05, 0x61, 0xCC, 0x86,
+ 0xCC, 0x80, 0xCA, 0x05, 0x61, 0xCC, 0x86, 0xCC,
+ 0x81, 0xCA, 0x05, 0x61, 0xCC, 0x86, 0xCC, 0x83,
+ 0xCA, 0x05, 0x61, 0xCC, 0x86, 0xCC, 0x89, 0xCA,
+ 0x05, 0x61, 0xCC, 0x87, 0xCC, 0x84, 0xCA, 0x05,
+ // Bytes 3a40 - 3a7f
+ 0x61, 0xCC, 0x88, 0xCC, 0x84, 0xCA, 0x05, 0x61,
+ 0xCC, 0x8A, 0xCC, 0x81, 0xCA, 0x05, 0x61, 0xCC,
+ 0xA3, 0xCC, 0x82, 0xCA, 0x05, 0x61, 0xCC, 0xA3,
+ 0xCC, 0x86, 0xCA, 0x05, 0x63, 0xCC, 0xA7, 0xCC,
+ 0x81, 0xCA, 0x05, 0x65, 0xCC, 0x82, 0xCC, 0x80,
+ 0xCA, 0x05, 0x65, 0xCC, 0x82, 0xCC, 0x81, 0xCA,
+ 0x05, 0x65, 0xCC, 0x82, 0xCC, 0x83, 0xCA, 0x05,
+ 0x65, 0xCC, 0x82, 0xCC, 0x89, 0xCA, 0x05, 0x65,
+ // Bytes 3a80 - 3abf
+ 0xCC, 0x84, 0xCC, 0x80, 0xCA, 0x05, 0x65, 0xCC,
+ 0x84, 0xCC, 0x81, 0xCA, 0x05, 0x65, 0xCC, 0xA3,
+ 0xCC, 0x82, 0xCA, 0x05, 0x65, 0xCC, 0xA7, 0xCC,
+ 0x86, 0xCA, 0x05, 0x69, 0xCC, 0x88, 0xCC, 0x81,
+ 0xCA, 0x05, 0x6C, 0xCC, 0xA3, 0xCC, 0x84, 0xCA,
+ 0x05, 0x6F, 0xCC, 0x82, 0xCC, 0x80, 0xCA, 0x05,
+ 0x6F, 0xCC, 0x82, 0xCC, 0x81, 0xCA, 0x05, 0x6F,
+ 0xCC, 0x82, 0xCC, 0x83, 0xCA, 0x05, 0x6F, 0xCC,
+ // Bytes 3ac0 - 3aff
+ 0x82, 0xCC, 0x89, 0xCA, 0x05, 0x6F, 0xCC, 0x83,
+ 0xCC, 0x81, 0xCA, 0x05, 0x6F, 0xCC, 0x83, 0xCC,
+ 0x84, 0xCA, 0x05, 0x6F, 0xCC, 0x83, 0xCC, 0x88,
+ 0xCA, 0x05, 0x6F, 0xCC, 0x84, 0xCC, 0x80, 0xCA,
+ 0x05, 0x6F, 0xCC, 0x84, 0xCC, 0x81, 0xCA, 0x05,
+ 0x6F, 0xCC, 0x87, 0xCC, 0x84, 0xCA, 0x05, 0x6F,
+ 0xCC, 0x88, 0xCC, 0x84, 0xCA, 0x05, 0x6F, 0xCC,
+ 0x9B, 0xCC, 0x80, 0xCA, 0x05, 0x6F, 0xCC, 0x9B,
+ // Bytes 3b00 - 3b3f
+ 0xCC, 0x81, 0xCA, 0x05, 0x6F, 0xCC, 0x9B, 0xCC,
+ 0x83, 0xCA, 0x05, 0x6F, 0xCC, 0x9B, 0xCC, 0x89,
+ 0xCA, 0x05, 0x6F, 0xCC, 0x9B, 0xCC, 0xA3, 0xB6,
+ 0x05, 0x6F, 0xCC, 0xA3, 0xCC, 0x82, 0xCA, 0x05,
+ 0x6F, 0xCC, 0xA8, 0xCC, 0x84, 0xCA, 0x05, 0x72,
+ 0xCC, 0xA3, 0xCC, 0x84, 0xCA, 0x05, 0x73, 0xCC,
+ 0x81, 0xCC, 0x87, 0xCA, 0x05, 0x73, 0xCC, 0x8C,
+ 0xCC, 0x87, 0xCA, 0x05, 0x73, 0xCC, 0xA3, 0xCC,
+ // Bytes 3b40 - 3b7f
+ 0x87, 0xCA, 0x05, 0x75, 0xCC, 0x83, 0xCC, 0x81,
+ 0xCA, 0x05, 0x75, 0xCC, 0x84, 0xCC, 0x88, 0xCA,
+ 0x05, 0x75, 0xCC, 0x88, 0xCC, 0x80, 0xCA, 0x05,
+ 0x75, 0xCC, 0x88, 0xCC, 0x81, 0xCA, 0x05, 0x75,
+ 0xCC, 0x88, 0xCC, 0x84, 0xCA, 0x05, 0x75, 0xCC,
+ 0x88, 0xCC, 0x8C, 0xCA, 0x05, 0x75, 0xCC, 0x9B,
+ 0xCC, 0x80, 0xCA, 0x05, 0x75, 0xCC, 0x9B, 0xCC,
+ 0x81, 0xCA, 0x05, 0x75, 0xCC, 0x9B, 0xCC, 0x83,
+ // Bytes 3b80 - 3bbf
+ 0xCA, 0x05, 0x75, 0xCC, 0x9B, 0xCC, 0x89, 0xCA,
+ 0x05, 0x75, 0xCC, 0x9B, 0xCC, 0xA3, 0xB6, 0x05,
+ 0xE1, 0xBE, 0xBF, 0xCC, 0x80, 0xCA, 0x05, 0xE1,
+ 0xBE, 0xBF, 0xCC, 0x81, 0xCA, 0x05, 0xE1, 0xBE,
+ 0xBF, 0xCD, 0x82, 0xCA, 0x05, 0xE1, 0xBF, 0xBE,
+ 0xCC, 0x80, 0xCA, 0x05, 0xE1, 0xBF, 0xBE, 0xCC,
+ 0x81, 0xCA, 0x05, 0xE1, 0xBF, 0xBE, 0xCD, 0x82,
+ 0xCA, 0x05, 0xE2, 0x86, 0x90, 0xCC, 0xB8, 0x05,
+ // Bytes 3bc0 - 3bff
+ 0x05, 0xE2, 0x86, 0x92, 0xCC, 0xB8, 0x05, 0x05,
+ 0xE2, 0x86, 0x94, 0xCC, 0xB8, 0x05, 0x05, 0xE2,
+ 0x87, 0x90, 0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x87,
+ 0x92, 0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x87, 0x94,
+ 0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x88, 0x83, 0xCC,
+ 0xB8, 0x05, 0x05, 0xE2, 0x88, 0x88, 0xCC, 0xB8,
+ 0x05, 0x05, 0xE2, 0x88, 0x8B, 0xCC, 0xB8, 0x05,
+ 0x05, 0xE2, 0x88, 0xA3, 0xCC, 0xB8, 0x05, 0x05,
+ // Bytes 3c00 - 3c3f
+ 0xE2, 0x88, 0xA5, 0xCC, 0xB8, 0x05, 0x05, 0xE2,
+ 0x88, 0xBC, 0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x89,
+ 0x83, 0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x89, 0x85,
+ 0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x89, 0x88, 0xCC,
+ 0xB8, 0x05, 0x05, 0xE2, 0x89, 0x8D, 0xCC, 0xB8,
+ 0x05, 0x05, 0xE2, 0x89, 0xA1, 0xCC, 0xB8, 0x05,
+ 0x05, 0xE2, 0x89, 0xA4, 0xCC, 0xB8, 0x05, 0x05,
+ 0xE2, 0x89, 0xA5, 0xCC, 0xB8, 0x05, 0x05, 0xE2,
+ // Bytes 3c40 - 3c7f
+ 0x89, 0xB2, 0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x89,
+ 0xB3, 0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x89, 0xB6,
+ 0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x89, 0xB7, 0xCC,
+ 0xB8, 0x05, 0x05, 0xE2, 0x89, 0xBA, 0xCC, 0xB8,
+ 0x05, 0x05, 0xE2, 0x89, 0xBB, 0xCC, 0xB8, 0x05,
+ 0x05, 0xE2, 0x89, 0xBC, 0xCC, 0xB8, 0x05, 0x05,
+ 0xE2, 0x89, 0xBD, 0xCC, 0xB8, 0x05, 0x05, 0xE2,
+ 0x8A, 0x82, 0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x8A,
+ // Bytes 3c80 - 3cbf
+ 0x83, 0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x8A, 0x86,
+ 0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x8A, 0x87, 0xCC,
+ 0xB8, 0x05, 0x05, 0xE2, 0x8A, 0x91, 0xCC, 0xB8,
+ 0x05, 0x05, 0xE2, 0x8A, 0x92, 0xCC, 0xB8, 0x05,
+ 0x05, 0xE2, 0x8A, 0xA2, 0xCC, 0xB8, 0x05, 0x05,
+ 0xE2, 0x8A, 0xA8, 0xCC, 0xB8, 0x05, 0x05, 0xE2,
+ 0x8A, 0xA9, 0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x8A,
+ 0xAB, 0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x8A, 0xB2,
+ // Bytes 3cc0 - 3cff
+ 0xCC, 0xB8, 0x05, 0x05, 0xE2, 0x8A, 0xB3, 0xCC,
+ 0xB8, 0x05, 0x05, 0xE2, 0x8A, 0xB4, 0xCC, 0xB8,
+ 0x05, 0x05, 0xE2, 0x8A, 0xB5, 0xCC, 0xB8, 0x05,
+ 0x06, 0xCE, 0x91, 0xCC, 0x93, 0xCD, 0x85, 0xDA,
+ 0x06, 0xCE, 0x91, 0xCC, 0x94, 0xCD, 0x85, 0xDA,
+ 0x06, 0xCE, 0x95, 0xCC, 0x93, 0xCC, 0x80, 0xCA,
+ 0x06, 0xCE, 0x95, 0xCC, 0x93, 0xCC, 0x81, 0xCA,
+ 0x06, 0xCE, 0x95, 0xCC, 0x94, 0xCC, 0x80, 0xCA,
+ // Bytes 3d00 - 3d3f
+ 0x06, 0xCE, 0x95, 0xCC, 0x94, 0xCC, 0x81, 0xCA,
+ 0x06, 0xCE, 0x97, 0xCC, 0x93, 0xCD, 0x85, 0xDA,
+ 0x06, 0xCE, 0x97, 0xCC, 0x94, 0xCD, 0x85, 0xDA,
+ 0x06, 0xCE, 0x99, 0xCC, 0x93, 0xCC, 0x80, 0xCA,
+ 0x06, 0xCE, 0x99, 0xCC, 0x93, 0xCC, 0x81, 0xCA,
+ 0x06, 0xCE, 0x99, 0xCC, 0x93, 0xCD, 0x82, 0xCA,
+ 0x06, 0xCE, 0x99, 0xCC, 0x94, 0xCC, 0x80, 0xCA,
+ 0x06, 0xCE, 0x99, 0xCC, 0x94, 0xCC, 0x81, 0xCA,
+ // Bytes 3d40 - 3d7f
+ 0x06, 0xCE, 0x99, 0xCC, 0x94, 0xCD, 0x82, 0xCA,
+ 0x06, 0xCE, 0x9F, 0xCC, 0x93, 0xCC, 0x80, 0xCA,
+ 0x06, 0xCE, 0x9F, 0xCC, 0x93, 0xCC, 0x81, 0xCA,
+ 0x06, 0xCE, 0x9F, 0xCC, 0x94, 0xCC, 0x80, 0xCA,
+ 0x06, 0xCE, 0x9F, 0xCC, 0x94, 0xCC, 0x81, 0xCA,
+ 0x06, 0xCE, 0xA5, 0xCC, 0x94, 0xCC, 0x80, 0xCA,
+ 0x06, 0xCE, 0xA5, 0xCC, 0x94, 0xCC, 0x81, 0xCA,
+ 0x06, 0xCE, 0xA5, 0xCC, 0x94, 0xCD, 0x82, 0xCA,
+ // Bytes 3d80 - 3dbf
+ 0x06, 0xCE, 0xA9, 0xCC, 0x93, 0xCD, 0x85, 0xDA,
+ 0x06, 0xCE, 0xA9, 0xCC, 0x94, 0xCD, 0x85, 0xDA,
+ 0x06, 0xCE, 0xB1, 0xCC, 0x80, 0xCD, 0x85, 0xDA,
+ 0x06, 0xCE, 0xB1, 0xCC, 0x81, 0xCD, 0x85, 0xDA,
+ 0x06, 0xCE, 0xB1, 0xCC, 0x93, 0xCD, 0x85, 0xDA,
+ 0x06, 0xCE, 0xB1, 0xCC, 0x94, 0xCD, 0x85, 0xDA,
+ 0x06, 0xCE, 0xB1, 0xCD, 0x82, 0xCD, 0x85, 0xDA,
+ 0x06, 0xCE, 0xB5, 0xCC, 0x93, 0xCC, 0x80, 0xCA,
+ // Bytes 3dc0 - 3dff
+ 0x06, 0xCE, 0xB5, 0xCC, 0x93, 0xCC, 0x81, 0xCA,
+ 0x06, 0xCE, 0xB5, 0xCC, 0x94, 0xCC, 0x80, 0xCA,
+ 0x06, 0xCE, 0xB5, 0xCC, 0x94, 0xCC, 0x81, 0xCA,
+ 0x06, 0xCE, 0xB7, 0xCC, 0x80, 0xCD, 0x85, 0xDA,
+ 0x06, 0xCE, 0xB7, 0xCC, 0x81, 0xCD, 0x85, 0xDA,
+ 0x06, 0xCE, 0xB7, 0xCC, 0x93, 0xCD, 0x85, 0xDA,
+ 0x06, 0xCE, 0xB7, 0xCC, 0x94, 0xCD, 0x85, 0xDA,
+ 0x06, 0xCE, 0xB7, 0xCD, 0x82, 0xCD, 0x85, 0xDA,
+ // Bytes 3e00 - 3e3f
+ 0x06, 0xCE, 0xB9, 0xCC, 0x88, 0xCC, 0x80, 0xCA,
+ 0x06, 0xCE, 0xB9, 0xCC, 0x88, 0xCC, 0x81, 0xCA,
+ 0x06, 0xCE, 0xB9, 0xCC, 0x88, 0xCD, 0x82, 0xCA,
+ 0x06, 0xCE, 0xB9, 0xCC, 0x93, 0xCC, 0x80, 0xCA,
+ 0x06, 0xCE, 0xB9, 0xCC, 0x93, 0xCC, 0x81, 0xCA,
+ 0x06, 0xCE, 0xB9, 0xCC, 0x93, 0xCD, 0x82, 0xCA,
+ 0x06, 0xCE, 0xB9, 0xCC, 0x94, 0xCC, 0x80, 0xCA,
+ 0x06, 0xCE, 0xB9, 0xCC, 0x94, 0xCC, 0x81, 0xCA,
+ // Bytes 3e40 - 3e7f
+ 0x06, 0xCE, 0xB9, 0xCC, 0x94, 0xCD, 0x82, 0xCA,
+ 0x06, 0xCE, 0xBF, 0xCC, 0x93, 0xCC, 0x80, 0xCA,
+ 0x06, 0xCE, 0xBF, 0xCC, 0x93, 0xCC, 0x81, 0xCA,
+ 0x06, 0xCE, 0xBF, 0xCC, 0x94, 0xCC, 0x80, 0xCA,
+ 0x06, 0xCE, 0xBF, 0xCC, 0x94, 0xCC, 0x81, 0xCA,
+ 0x06, 0xCF, 0x85, 0xCC, 0x88, 0xCC, 0x80, 0xCA,
+ 0x06, 0xCF, 0x85, 0xCC, 0x88, 0xCC, 0x81, 0xCA,
+ 0x06, 0xCF, 0x85, 0xCC, 0x88, 0xCD, 0x82, 0xCA,
+ // Bytes 3e80 - 3ebf
+ 0x06, 0xCF, 0x85, 0xCC, 0x93, 0xCC, 0x80, 0xCA,
+ 0x06, 0xCF, 0x85, 0xCC, 0x93, 0xCC, 0x81, 0xCA,
+ 0x06, 0xCF, 0x85, 0xCC, 0x93, 0xCD, 0x82, 0xCA,
+ 0x06, 0xCF, 0x85, 0xCC, 0x94, 0xCC, 0x80, 0xCA,
+ 0x06, 0xCF, 0x85, 0xCC, 0x94, 0xCC, 0x81, 0xCA,
+ 0x06, 0xCF, 0x85, 0xCC, 0x94, 0xCD, 0x82, 0xCA,
+ 0x06, 0xCF, 0x89, 0xCC, 0x80, 0xCD, 0x85, 0xDA,
+ 0x06, 0xCF, 0x89, 0xCC, 0x81, 0xCD, 0x85, 0xDA,
+ // Bytes 3ec0 - 3eff
+ 0x06, 0xCF, 0x89, 0xCC, 0x93, 0xCD, 0x85, 0xDA,
+ 0x06, 0xCF, 0x89, 0xCC, 0x94, 0xCD, 0x85, 0xDA,
+ 0x06, 0xCF, 0x89, 0xCD, 0x82, 0xCD, 0x85, 0xDA,
+ 0x06, 0xE0, 0xA4, 0xA8, 0xE0, 0xA4, 0xBC, 0x09,
+ 0x06, 0xE0, 0xA4, 0xB0, 0xE0, 0xA4, 0xBC, 0x09,
+ 0x06, 0xE0, 0xA4, 0xB3, 0xE0, 0xA4, 0xBC, 0x09,
+ 0x06, 0xE0, 0xB1, 0x86, 0xE0, 0xB1, 0x96, 0x85,
+ 0x06, 0xE0, 0xB7, 0x99, 0xE0, 0xB7, 0x8A, 0x11,
+ // Bytes 3f00 - 3f3f
+ 0x06, 0xE3, 0x81, 0x86, 0xE3, 0x82, 0x99, 0x0D,
+ 0x06, 0xE3, 0x81, 0x8B, 0xE3, 0x82, 0x99, 0x0D,
+ 0x06, 0xE3, 0x81, 0x8D, 0xE3, 0x82, 0x99, 0x0D,
+ 0x06, 0xE3, 0x81, 0x8F, 0xE3, 0x82, 0x99, 0x0D,
+ 0x06, 0xE3, 0x81, 0x91, 0xE3, 0x82, 0x99, 0x0D,
+ 0x06, 0xE3, 0x81, 0x93, 0xE3, 0x82, 0x99, 0x0D,
+ 0x06, 0xE3, 0x81, 0x95, 0xE3, 0x82, 0x99, 0x0D,
+ 0x06, 0xE3, 0x81, 0x97, 0xE3, 0x82, 0x99, 0x0D,
+ // Bytes 3f40 - 3f7f
+ 0x06, 0xE3, 0x81, 0x99, 0xE3, 0x82, 0x99, 0x0D,
+ 0x06, 0xE3, 0x81, 0x9B, 0xE3, 0x82, 0x99, 0x0D,
+ 0x06, 0xE3, 0x81, 0x9D, 0xE3, 0x82, 0x99, 0x0D,
+ 0x06, 0xE3, 0x81, 0x9F, 0xE3, 0x82, 0x99, 0x0D,
+ 0x06, 0xE3, 0x81, 0xA1, 0xE3, 0x82, 0x99, 0x0D,
+ 0x06, 0xE3, 0x81, 0xA4, 0xE3, 0x82, 0x99, 0x0D,
+ 0x06, 0xE3, 0x81, 0xA6, 0xE3, 0x82, 0x99, 0x0D,
+ 0x06, 0xE3, 0x81, 0xA8, 0xE3, 0x82, 0x99, 0x0D,
+ // Bytes 3f80 - 3fbf
+ 0x06, 0xE3, 0x81, 0xAF, 0xE3, 0x82, 0x99, 0x0D,
+ 0x06, 0xE3, 0x81, 0xAF, 0xE3, 0x82, 0x9A, 0x0D,
+ 0x06, 0xE3, 0x81, 0xB2, 0xE3, 0x82, 0x99, 0x0D,
+ 0x06, 0xE3, 0x81, 0xB2, 0xE3, 0x82, 0x9A, 0x0D,
+ 0x06, 0xE3, 0x81, 0xB5, 0xE3, 0x82, 0x99, 0x0D,
+ 0x06, 0xE3, 0x81, 0xB5, 0xE3, 0x82, 0x9A, 0x0D,
+ 0x06, 0xE3, 0x81, 0xB8, 0xE3, 0x82, 0x99, 0x0D,
+ 0x06, 0xE3, 0x81, 0xB8, 0xE3, 0x82, 0x9A, 0x0D,
+ // Bytes 3fc0 - 3fff
+ 0x06, 0xE3, 0x81, 0xBB, 0xE3, 0x82, 0x99, 0x0D,
+ 0x06, 0xE3, 0x81, 0xBB, 0xE3, 0x82, 0x9A, 0x0D,
+ 0x06, 0xE3, 0x82, 0x9D, 0xE3, 0x82, 0x99, 0x0D,
+ 0x06, 0xE3, 0x82, 0xA6, 0xE3, 0x82, 0x99, 0x0D,
+ 0x06, 0xE3, 0x82, 0xAB, 0xE3, 0x82, 0x99, 0x0D,
+ 0x06, 0xE3, 0x82, 0xAD, 0xE3, 0x82, 0x99, 0x0D,
+ 0x06, 0xE3, 0x82, 0xAF, 0xE3, 0x82, 0x99, 0x0D,
+ 0x06, 0xE3, 0x82, 0xB1, 0xE3, 0x82, 0x99, 0x0D,
+ // Bytes 4000 - 403f
+ 0x06, 0xE3, 0x82, 0xB3, 0xE3, 0x82, 0x99, 0x0D,
+ 0x06, 0xE3, 0x82, 0xB5, 0xE3, 0x82, 0x99, 0x0D,
+ 0x06, 0xE3, 0x82, 0xB7, 0xE3, 0x82, 0x99, 0x0D,
+ 0x06, 0xE3, 0x82, 0xB9, 0xE3, 0x82, 0x99, 0x0D,
+ 0x06, 0xE3, 0x82, 0xBB, 0xE3, 0x82, 0x99, 0x0D,
+ 0x06, 0xE3, 0x82, 0xBD, 0xE3, 0x82, 0x99, 0x0D,
+ 0x06, 0xE3, 0x82, 0xBF, 0xE3, 0x82, 0x99, 0x0D,
+ 0x06, 0xE3, 0x83, 0x81, 0xE3, 0x82, 0x99, 0x0D,
+ // Bytes 4040 - 407f
+ 0x06, 0xE3, 0x83, 0x84, 0xE3, 0x82, 0x99, 0x0D,
+ 0x06, 0xE3, 0x83, 0x86, 0xE3, 0x82, 0x99, 0x0D,
+ 0x06, 0xE3, 0x83, 0x88, 0xE3, 0x82, 0x99, 0x0D,
+ 0x06, 0xE3, 0x83, 0x8F, 0xE3, 0x82, 0x99, 0x0D,
+ 0x06, 0xE3, 0x83, 0x8F, 0xE3, 0x82, 0x9A, 0x0D,
+ 0x06, 0xE3, 0x83, 0x92, 0xE3, 0x82, 0x99, 0x0D,
+ 0x06, 0xE3, 0x83, 0x92, 0xE3, 0x82, 0x9A, 0x0D,
+ 0x06, 0xE3, 0x83, 0x95, 0xE3, 0x82, 0x99, 0x0D,
+ // Bytes 4080 - 40bf
+ 0x06, 0xE3, 0x83, 0x95, 0xE3, 0x82, 0x9A, 0x0D,
+ 0x06, 0xE3, 0x83, 0x98, 0xE3, 0x82, 0x99, 0x0D,
+ 0x06, 0xE3, 0x83, 0x98, 0xE3, 0x82, 0x9A, 0x0D,
+ 0x06, 0xE3, 0x83, 0x9B, 0xE3, 0x82, 0x99, 0x0D,
+ 0x06, 0xE3, 0x83, 0x9B, 0xE3, 0x82, 0x9A, 0x0D,
+ 0x06, 0xE3, 0x83, 0xAF, 0xE3, 0x82, 0x99, 0x0D,
+ 0x06, 0xE3, 0x83, 0xB0, 0xE3, 0x82, 0x99, 0x0D,
+ 0x06, 0xE3, 0x83, 0xB1, 0xE3, 0x82, 0x99, 0x0D,
+ // Bytes 40c0 - 40ff
+ 0x06, 0xE3, 0x83, 0xB2, 0xE3, 0x82, 0x99, 0x0D,
+ 0x06, 0xE3, 0x83, 0xBD, 0xE3, 0x82, 0x99, 0x0D,
+ 0x08, 0xCE, 0x91, 0xCC, 0x93, 0xCC, 0x80, 0xCD,
+ 0x85, 0xDB, 0x08, 0xCE, 0x91, 0xCC, 0x93, 0xCC,
+ 0x81, 0xCD, 0x85, 0xDB, 0x08, 0xCE, 0x91, 0xCC,
+ 0x93, 0xCD, 0x82, 0xCD, 0x85, 0xDB, 0x08, 0xCE,
+ 0x91, 0xCC, 0x94, 0xCC, 0x80, 0xCD, 0x85, 0xDB,
+ 0x08, 0xCE, 0x91, 0xCC, 0x94, 0xCC, 0x81, 0xCD,
+ // Bytes 4100 - 413f
+ 0x85, 0xDB, 0x08, 0xCE, 0x91, 0xCC, 0x94, 0xCD,
+ 0x82, 0xCD, 0x85, 0xDB, 0x08, 0xCE, 0x97, 0xCC,
+ 0x93, 0xCC, 0x80, 0xCD, 0x85, 0xDB, 0x08, 0xCE,
+ 0x97, 0xCC, 0x93, 0xCC, 0x81, 0xCD, 0x85, 0xDB,
+ 0x08, 0xCE, 0x97, 0xCC, 0x93, 0xCD, 0x82, 0xCD,
+ 0x85, 0xDB, 0x08, 0xCE, 0x97, 0xCC, 0x94, 0xCC,
+ 0x80, 0xCD, 0x85, 0xDB, 0x08, 0xCE, 0x97, 0xCC,
+ 0x94, 0xCC, 0x81, 0xCD, 0x85, 0xDB, 0x08, 0xCE,
+ // Bytes 4140 - 417f
+ 0x97, 0xCC, 0x94, 0xCD, 0x82, 0xCD, 0x85, 0xDB,
+ 0x08, 0xCE, 0xA9, 0xCC, 0x93, 0xCC, 0x80, 0xCD,
+ 0x85, 0xDB, 0x08, 0xCE, 0xA9, 0xCC, 0x93, 0xCC,
+ 0x81, 0xCD, 0x85, 0xDB, 0x08, 0xCE, 0xA9, 0xCC,
+ 0x93, 0xCD, 0x82, 0xCD, 0x85, 0xDB, 0x08, 0xCE,
+ 0xA9, 0xCC, 0x94, 0xCC, 0x80, 0xCD, 0x85, 0xDB,
+ 0x08, 0xCE, 0xA9, 0xCC, 0x94, 0xCC, 0x81, 0xCD,
+ 0x85, 0xDB, 0x08, 0xCE, 0xA9, 0xCC, 0x94, 0xCD,
+ // Bytes 4180 - 41bf
+ 0x82, 0xCD, 0x85, 0xDB, 0x08, 0xCE, 0xB1, 0xCC,
+ 0x93, 0xCC, 0x80, 0xCD, 0x85, 0xDB, 0x08, 0xCE,
+ 0xB1, 0xCC, 0x93, 0xCC, 0x81, 0xCD, 0x85, 0xDB,
+ 0x08, 0xCE, 0xB1, 0xCC, 0x93, 0xCD, 0x82, 0xCD,
+ 0x85, 0xDB, 0x08, 0xCE, 0xB1, 0xCC, 0x94, 0xCC,
+ 0x80, 0xCD, 0x85, 0xDB, 0x08, 0xCE, 0xB1, 0xCC,
+ 0x94, 0xCC, 0x81, 0xCD, 0x85, 0xDB, 0x08, 0xCE,
+ 0xB1, 0xCC, 0x94, 0xCD, 0x82, 0xCD, 0x85, 0xDB,
+ // Bytes 41c0 - 41ff
+ 0x08, 0xCE, 0xB7, 0xCC, 0x93, 0xCC, 0x80, 0xCD,
+ 0x85, 0xDB, 0x08, 0xCE, 0xB7, 0xCC, 0x93, 0xCC,
+ 0x81, 0xCD, 0x85, 0xDB, 0x08, 0xCE, 0xB7, 0xCC,
+ 0x93, 0xCD, 0x82, 0xCD, 0x85, 0xDB, 0x08, 0xCE,
+ 0xB7, 0xCC, 0x94, 0xCC, 0x80, 0xCD, 0x85, 0xDB,
+ 0x08, 0xCE, 0xB7, 0xCC, 0x94, 0xCC, 0x81, 0xCD,
+ 0x85, 0xDB, 0x08, 0xCE, 0xB7, 0xCC, 0x94, 0xCD,
+ 0x82, 0xCD, 0x85, 0xDB, 0x08, 0xCF, 0x89, 0xCC,
+ // Bytes 4200 - 423f
+ 0x93, 0xCC, 0x80, 0xCD, 0x85, 0xDB, 0x08, 0xCF,
+ 0x89, 0xCC, 0x93, 0xCC, 0x81, 0xCD, 0x85, 0xDB,
+ 0x08, 0xCF, 0x89, 0xCC, 0x93, 0xCD, 0x82, 0xCD,
+ 0x85, 0xDB, 0x08, 0xCF, 0x89, 0xCC, 0x94, 0xCC,
+ 0x80, 0xCD, 0x85, 0xDB, 0x08, 0xCF, 0x89, 0xCC,
+ 0x94, 0xCC, 0x81, 0xCD, 0x85, 0xDB, 0x08, 0xCF,
+ 0x89, 0xCC, 0x94, 0xCD, 0x82, 0xCD, 0x85, 0xDB,
+ 0x08, 0xF0, 0x91, 0x82, 0x99, 0xF0, 0x91, 0x82,
+ // Bytes 4240 - 427f
+ 0xBA, 0x09, 0x08, 0xF0, 0x91, 0x82, 0x9B, 0xF0,
+ 0x91, 0x82, 0xBA, 0x09, 0x08, 0xF0, 0x91, 0x82,
+ 0xA5, 0xF0, 0x91, 0x82, 0xBA, 0x09, 0x42, 0xC2,
+ 0xB4, 0x01, 0x43, 0x20, 0xCC, 0x81, 0xC9, 0x43,
+ 0x20, 0xCC, 0x83, 0xC9, 0x43, 0x20, 0xCC, 0x84,
+ 0xC9, 0x43, 0x20, 0xCC, 0x85, 0xC9, 0x43, 0x20,
+ 0xCC, 0x86, 0xC9, 0x43, 0x20, 0xCC, 0x87, 0xC9,
+ 0x43, 0x20, 0xCC, 0x88, 0xC9, 0x43, 0x20, 0xCC,
+ // Bytes 4280 - 42bf
+ 0x8A, 0xC9, 0x43, 0x20, 0xCC, 0x8B, 0xC9, 0x43,
+ 0x20, 0xCC, 0x93, 0xC9, 0x43, 0x20, 0xCC, 0x94,
+ 0xC9, 0x43, 0x20, 0xCC, 0xA7, 0xA5, 0x43, 0x20,
+ 0xCC, 0xA8, 0xA5, 0x43, 0x20, 0xCC, 0xB3, 0xB5,
+ 0x43, 0x20, 0xCD, 0x82, 0xC9, 0x43, 0x20, 0xCD,
+ 0x85, 0xD9, 0x43, 0x20, 0xD9, 0x8B, 0x59, 0x43,
+ 0x20, 0xD9, 0x8C, 0x5D, 0x43, 0x20, 0xD9, 0x8D,
+ 0x61, 0x43, 0x20, 0xD9, 0x8E, 0x65, 0x43, 0x20,
+ // Bytes 42c0 - 42ff
+ 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,
+ // 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,
+ // 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,
+ // 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,
+ // 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,
+ // 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,
+ // 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,
+ // 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,
+ // 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,
+ // 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,
+ // 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,
+ // 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,
+ // 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,
+ // 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,
+ 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, 0xAF, 0xAE, 0x4C, 0xF0, 0x9D, 0x85,
+ // Bytes 46c0 - 46ff
+ 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,
+ 0x9D, 0x86, 0xB9, 0xF0, 0x9D, 0x85, 0xA5, 0xF0,
+ 0x9D, 0x85, 0xAE, 0xAE, 0x4C, 0xF0, 0x9D, 0x86,
+ 0xB9, 0xF0, 0x9D, 0x85, 0xA5, 0xF0, 0x9D, 0x85,
+ // 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,
+ // 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,
+ // 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,
+ // 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,
+ // 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,
+ // 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,
+ // 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,
+ // 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,
+ // 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,
+ // 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,
+ // 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,
+ // 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,
+ // 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,
+ // 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,
+ // Bytes 4a80 - 4abf
+ 0x26, 0x00, 0x01,
+}
+
+// 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 *nfcTrie) lookup(s []byte) (v uint16, sz int) {
+ c0 := s[0]
+ switch {
+ case c0 < 0x80: // is ASCII
+ return nfcValues[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 := nfcIndex[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 := nfcIndex[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 = nfcIndex[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 := nfcIndex[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 = nfcIndex[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 = nfcIndex[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 *nfcTrie) lookupUnsafe(s []byte) uint16 {
+ c0 := s[0]
+ if c0 < 0x80 { // is ASCII
+ return nfcValues[c0]
+ }
+ i := nfcIndex[c0]
+ if c0 < 0xE0 { // 2-byte UTF-8
+ return t.lookupValue(uint32(i), s[1])
+ }
+ i = nfcIndex[uint32(i)<<6+uint32(s[1])]
+ if c0 < 0xF0 { // 3-byte UTF-8
+ return t.lookupValue(uint32(i), s[2])
+ }
+ i = nfcIndex[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 *nfcTrie) lookupString(s string) (v uint16, sz int) {
+ c0 := s[0]
+ switch {
+ case c0 < 0x80: // is ASCII
+ return nfcValues[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 := nfcIndex[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 := nfcIndex[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 = nfcIndex[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 := nfcIndex[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 = nfcIndex[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 = nfcIndex[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 *nfcTrie) lookupStringUnsafe(s string) uint16 {
+ c0 := s[0]
+ if c0 < 0x80 { // is ASCII
+ return nfcValues[c0]
+ }
+ i := nfcIndex[c0]
+ if c0 < 0xE0 { // 2-byte UTF-8
+ return t.lookupValue(uint32(i), s[1])
+ }
+ i = nfcIndex[uint32(i)<<6+uint32(s[1])]
+ if c0 < 0xF0 { // 3-byte UTF-8
+ return t.lookupValue(uint32(i), s[2])
+ }
+ i = nfcIndex[uint32(i)<<6+uint32(s[2])]
+ if c0 < 0xF8 { // 4-byte UTF-8
+ return t.lookupValue(uint32(i), s[3])
+ }
+ return 0
+}
+
+// nfcTrie. Total size: 10332 bytes (10.09 KiB). Checksum: ad355b768fddb1b6.
+type nfcTrie struct{}
+
+func newNfcTrie(i int) *nfcTrie {
+ return &nfcTrie{}
+}
+
+// lookupValue determines the type of block n and looks up the value for b.
+func (t *nfcTrie) lookupValue(n uint32, b byte) uint16 {
+ switch {
+ case n < 44:
+ return uint16(nfcValues[n<<6+uint32(b)])
+ default:
+ n -= 44
+ return uint16(nfcSparse.lookup(n, b))
+ }
+}
+
+// nfcValues: 46 blocks, 2944 entries, 5888 bytes
+// The third block is the zero block.
+var nfcValues = [2944]uint16{
+ // Block 0x0, offset 0x0
+ 0x3c: 0xa000, 0x3d: 0xa000, 0x3e: 0xa000,
+ // Block 0x1, offset 0x40
+ 0x41: 0xa000, 0x42: 0xa000, 0x43: 0xa000, 0x44: 0xa000, 0x45: 0xa000,
+ 0x46: 0xa000, 0x47: 0xa000, 0x48: 0xa000, 0x49: 0xa000, 0x4a: 0xa000, 0x4b: 0xa000,
+ 0x4c: 0xa000, 0x4d: 0xa000, 0x4e: 0xa000, 0x4f: 0xa000, 0x50: 0xa000,
+ 0x52: 0xa000, 0x53: 0xa000, 0x54: 0xa000, 0x55: 0xa000, 0x56: 0xa000, 0x57: 0xa000,
+ 0x58: 0xa000, 0x59: 0xa000, 0x5a: 0xa000,
+ 0x61: 0xa000, 0x62: 0xa000, 0x63: 0xa000,
+ 0x64: 0xa000, 0x65: 0xa000, 0x66: 0xa000, 0x67: 0xa000, 0x68: 0xa000, 0x69: 0xa000,
+ 0x6a: 0xa000, 0x6b: 0xa000, 0x6c: 0xa000, 0x6d: 0xa000, 0x6e: 0xa000, 0x6f: 0xa000,
+ 0x70: 0xa000, 0x72: 0xa000, 0x73: 0xa000, 0x74: 0xa000, 0x75: 0xa000,
+ 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,
+ // Block 0x4, offset 0x100
+ 0x100: 0x2f7e, 0x101: 0x328a, 0x102: 0x4723, 0x103: 0x47b4, 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,
+ 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,
+ 0x12a: 0x3082, 0x12b: 0x3393, 0x12c: 0x3087, 0x12d: 0x3398, 0x12e: 0x30aa, 0x12f: 0x33b6,
+ 0x130: 0x308c, 0x134: 0x30b4, 0x135: 0x33c0,
+ 0x136: 0x30c8, 0x137: 0x33d9, 0x139: 0x30d2, 0x13a: 0x33e3, 0x13b: 0x30dc,
+ 0x13c: 0x33ed, 0x13d: 0x30d7, 0x13e: 0x33e8,
+ // 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,
+ 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,
+ 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,
+ // Block 0x6, offset 0x180
+ 0x184: 0x8100, 0x185: 0x8100,
+ 0x186: 0x8100,
+ 0x18d: 0x2f88, 0x18e: 0x3294, 0x18f: 0x3096, 0x190: 0x33a2, 0x191: 0x3140,
+ 0x192: 0x3451, 0x193: 0x31d6, 0x194: 0x34ec, 0x195: 0x39cf, 0x196: 0x3b5e, 0x197: 0x39c8,
+ 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,
+ 0x1b0: 0x33c5, 0x1b4: 0x3028, 0x1b5: 0x3334,
+ 0x1b8: 0x30fa, 0x1b9: 0x340b, 0x1ba: 0x38b7, 0x1bb: 0x3a46,
+ 0x1bc: 0x35ad, 0x1bd: 0x35bf, 0x1be: 0x35b9, 0x1bf: 0x35cb,
+ // Block 0x7, offset 0x1c0
+ 0x1c0: 0x2f8d, 0x1c1: 0x3299, 0x1c2: 0x2f92, 0x1c3: 0x329e, 0x1c4: 0x300a, 0x1c5: 0x3316,
+ 0x1c6: 0x300f, 0x1c7: 0x331b, 0x1c8: 0x309b, 0x1c9: 0x33a7, 0x1ca: 0x30a0, 0x1cb: 0x33ac,
+ 0x1cc: 0x3145, 0x1cd: 0x3456, 0x1ce: 0x314a, 0x1cf: 0x345b, 0x1d0: 0x3168, 0x1d1: 0x3479,
+ 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,
+ 0x1f0: 0x3958, 0x1f1: 0x3ae7, 0x1f2: 0x3244, 0x1f3: 0x355f,
+ // Block 0x8, offset 0x200
+ 0x200: 0x9932, 0x201: 0x9932, 0x202: 0x9932, 0x203: 0x9932, 0x204: 0x9932, 0x205: 0x8132,
+ 0x206: 0x9932, 0x207: 0x9932, 0x208: 0x9932, 0x209: 0x9932, 0x20a: 0x9932, 0x20b: 0x9932,
+ 0x20c: 0x9932, 0x20d: 0x8132, 0x20e: 0x8132, 0x20f: 0x9932, 0x210: 0x8132, 0x211: 0x9932,
+ 0x212: 0x8132, 0x213: 0x9932, 0x214: 0x9932, 0x215: 0x8133, 0x216: 0x812d, 0x217: 0x812d,
+ 0x218: 0x812d, 0x219: 0x812d, 0x21a: 0x8133, 0x21b: 0x992b, 0x21c: 0x812d, 0x21d: 0x812d,
+ 0x21e: 0x812d, 0x21f: 0x812d, 0x220: 0x812d, 0x221: 0x8129, 0x222: 0x8129, 0x223: 0x992d,
+ 0x224: 0x992d, 0x225: 0x992d, 0x226: 0x992d, 0x227: 0x9929, 0x228: 0x9929, 0x229: 0x812d,
+ 0x22a: 0x812d, 0x22b: 0x812d, 0x22c: 0x812d, 0x22d: 0x992d, 0x22e: 0x992d, 0x22f: 0x812d,
+ 0x230: 0x992d, 0x231: 0x992d, 0x232: 0x812d, 0x233: 0x812d, 0x234: 0x8101, 0x235: 0x8101,
+ 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,
+ 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,
+ 0x258: 0x8133, 0x259: 0x812d, 0x25a: 0x812d, 0x25b: 0x8132, 0x25c: 0x8134, 0x25d: 0x8135,
+ 0x25e: 0x8135, 0x25f: 0x8134, 0x260: 0x8135, 0x261: 0x8135, 0x262: 0x8134, 0x263: 0x8132,
+ 0x264: 0x8132, 0x265: 0x8132, 0x266: 0x8132, 0x267: 0x8132, 0x268: 0x8132, 0x269: 0x8132,
+ 0x26a: 0x8132, 0x26b: 0x8132, 0x26c: 0x8132, 0x26d: 0x8132, 0x26e: 0x8132, 0x26f: 0x8132,
+ 0x274: 0x0170,
+ 0x27a: 0x8100,
+ 0x27e: 0x0037,
+ // Block 0xa, offset 0x280
+ 0x284: 0x8100, 0x285: 0x35a1,
+ 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,
+ 0x2b0: 0x3e70, 0x2b1: 0xa000, 0x2b5: 0xa000,
+ 0x2b7: 0xa000, 0x2b9: 0xa000,
+ 0x2bf: 0xa000,
+ // Block 0xb, offset 0x2c0
+ 0x2c0: 0x3721, 0x2c1: 0x372d, 0x2c3: 0x371b,
+ 0x2c6: 0xa000, 0x2c7: 0x3709,
+ 0x2cc: 0x375d, 0x2cd: 0x3745, 0x2ce: 0x376f, 0x2d0: 0xa000,
+ 0x2d3: 0xa000, 0x2d5: 0xa000, 0x2d6: 0xa000, 0x2d7: 0xa000,
+ 0x2d8: 0xa000, 0x2d9: 0x3751, 0x2da: 0xa000,
+ 0x2de: 0xa000, 0x2e3: 0xa000,
+ 0x2e7: 0xa000,
+ 0x2eb: 0xa000, 0x2ed: 0xa000,
+ 0x2f0: 0xa000, 0x2f3: 0xa000, 0x2f5: 0xa000,
+ 0x2f6: 0xa000, 0x2f7: 0xa000, 0x2f8: 0xa000, 0x2f9: 0x37d5, 0x2fa: 0xa000,
+ 0x2fe: 0xa000,
+ // Block 0xc, offset 0x300
+ 0x301: 0x3733, 0x302: 0x37b7,
+ 0x310: 0x370f, 0x311: 0x3793,
+ 0x312: 0x3715, 0x313: 0x3799, 0x316: 0x3727, 0x317: 0x37ab,
+ 0x318: 0xa000, 0x319: 0xa000, 0x31a: 0x3829, 0x31b: 0x382f, 0x31c: 0x3739, 0x31d: 0x37bd,
+ 0x31e: 0x373f, 0x31f: 0x37c3, 0x322: 0x374b, 0x323: 0x37cf,
+ 0x324: 0x3757, 0x325: 0x37db, 0x326: 0x3763, 0x327: 0x37e7, 0x328: 0xa000, 0x329: 0xa000,
+ 0x32a: 0x3835, 0x32b: 0x383b, 0x32c: 0x378d, 0x32d: 0x3811, 0x32e: 0x3769, 0x32f: 0x37ed,
+ 0x330: 0x3775, 0x331: 0x37f9, 0x332: 0x377b, 0x333: 0x37ff, 0x334: 0x3781, 0x335: 0x3805,
+ 0x338: 0x3787, 0x339: 0x380b,
+ // Block 0xd, offset 0x340
+ 0x351: 0x812d,
+ 0x352: 0x8132, 0x353: 0x8132, 0x354: 0x8132, 0x355: 0x8132, 0x356: 0x812d, 0x357: 0x8132,
+ 0x358: 0x8132, 0x359: 0x8132, 0x35a: 0x812e, 0x35b: 0x812d, 0x35c: 0x8132, 0x35d: 0x8132,
+ 0x35e: 0x8132, 0x35f: 0x8132, 0x360: 0x8132, 0x361: 0x8132, 0x362: 0x812d, 0x363: 0x812d,
+ 0x364: 0x812d, 0x365: 0x812d, 0x366: 0x812d, 0x367: 0x812d, 0x368: 0x8132, 0x369: 0x8132,
+ 0x36a: 0x812d, 0x36b: 0x8132, 0x36c: 0x8132, 0x36d: 0x812e, 0x36e: 0x8131, 0x36f: 0x8132,
+ 0x370: 0x8105, 0x371: 0x8106, 0x372: 0x8107, 0x373: 0x8108, 0x374: 0x8109, 0x375: 0x810a,
+ 0x376: 0x810b, 0x377: 0x810c, 0x378: 0x810d, 0x379: 0x810e, 0x37a: 0x810e, 0x37b: 0x810f,
+ 0x37c: 0x8110, 0x37d: 0x8111, 0x37f: 0x8112,
+ // Block 0xe, offset 0x380
+ 0x388: 0xa000, 0x38a: 0xa000, 0x38b: 0x8116,
+ 0x38c: 0x8117, 0x38d: 0x8118, 0x38e: 0x8119, 0x38f: 0x811a, 0x390: 0x811b, 0x391: 0x811c,
+ 0x392: 0x811d, 0x393: 0x9932, 0x394: 0x9932, 0x395: 0x992d, 0x396: 0x812d, 0x397: 0x8132,
+ 0x398: 0x8132, 0x399: 0x8132, 0x39a: 0x8132, 0x39b: 0x8132, 0x39c: 0x812d, 0x39d: 0x8132,
+ 0x39e: 0x8132, 0x39f: 0x812d,
+ 0x3b0: 0x811e,
+ // Block 0xf, offset 0x3c0
+ 0x3c5: 0xa000,
+ 0x3c6: 0x2d26, 0x3c7: 0xa000, 0x3c8: 0x2d2e, 0x3c9: 0xa000, 0x3ca: 0x2d36, 0x3cb: 0xa000,
+ 0x3cc: 0x2d3e, 0x3cd: 0xa000, 0x3ce: 0x2d46, 0x3d1: 0xa000,
+ 0x3d2: 0x2d4e,
+ 0x3f4: 0x8102, 0x3f5: 0x9900,
+ 0x3fa: 0xa000, 0x3fb: 0x2d56,
+ 0x3fc: 0xa000, 0x3fd: 0x2d5e, 0x3fe: 0xa000, 0x3ff: 0xa000,
+ // Block 0x10, offset 0x400
+ 0x400: 0x2f97, 0x401: 0x32a3, 0x402: 0x2fa1, 0x403: 0x32ad, 0x404: 0x2fa6, 0x405: 0x32b2,
+ 0x406: 0x2fab, 0x407: 0x32b7, 0x408: 0x38cc, 0x409: 0x3a5b, 0x40a: 0x2fc4, 0x40b: 0x32d0,
+ 0x40c: 0x2fce, 0x40d: 0x32da, 0x40e: 0x2fdd, 0x40f: 0x32e9, 0x410: 0x2fd3, 0x411: 0x32df,
+ 0x412: 0x2fd8, 0x413: 0x32e4, 0x414: 0x38ef, 0x415: 0x3a7e, 0x416: 0x38f6, 0x417: 0x3a85,
+ 0x418: 0x3019, 0x419: 0x3325, 0x41a: 0x301e, 0x41b: 0x332a, 0x41c: 0x3904, 0x41d: 0x3a93,
+ 0x41e: 0x3023, 0x41f: 0x332f, 0x420: 0x3032, 0x421: 0x333e, 0x422: 0x3050, 0x423: 0x335c,
+ 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,
+ 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,
+ 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,
+ 0x476: 0x31f4, 0x477: 0x350a, 0x478: 0x39b3, 0x479: 0x3b42, 0x47a: 0x39ba, 0x47b: 0x3b49,
+ 0x47c: 0x31fe, 0x47d: 0x3514, 0x47e: 0x3203, 0x47f: 0x3519,
+ // Block 0x12, offset 0x480
+ 0x480: 0x3208, 0x481: 0x351e, 0x482: 0x320d, 0x483: 0x3523, 0x484: 0x321c, 0x485: 0x3532,
+ 0x486: 0x3217, 0x487: 0x352d, 0x488: 0x3221, 0x489: 0x353c, 0x48a: 0x3226, 0x48b: 0x3541,
+ 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,
+ 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,
+ 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,
+ 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,
+ 0x4e4: 0x31e5, 0x4e5: 0x34fb, 0x4e6: 0x31c7, 0x4e7: 0x34dd, 0x4e8: 0x39e4, 0x4e9: 0x3b73,
+ 0x4ea: 0x39dd, 0x4eb: 0x3b6c, 0x4ec: 0x39f2, 0x4ed: 0x3b81, 0x4ee: 0x39eb, 0x4ef: 0x3b7a,
+ 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,
+ 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,
+ 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,
+ 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,
+ // 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,
+ 0x58c: 0x40da, 0x58d: 0x40f8, 0x58e: 0x40e4, 0x58f: 0x4102, 0x590: 0x3de8, 0x591: 0x3df0,
+ 0x592: 0x41c0, 0x593: 0x41de, 0x594: 0x41ca, 0x595: 0x41e8, 0x596: 0x41d4, 0x597: 0x41f2,
+ 0x598: 0x3d08, 0x599: 0x3d10, 0x59a: 0x410c, 0x59b: 0x412a, 0x59c: 0x4116, 0x59d: 0x4134,
+ 0x59e: 0x4120, 0x59f: 0x413e, 0x5a0: 0x3ec0, 0x5a1: 0x3ec8, 0x5a2: 0x41fc, 0x5a3: 0x421a,
+ 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,
+ 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,
+ 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,
+ 0x5e4: 0x36cd, 0x5e5: 0x36d3, 0x5e6: 0x36f1, 0x5e7: 0x3e78, 0x5e8: 0x3661, 0x5e9: 0x365b,
+ 0x5ea: 0x364f, 0x5eb: 0x43a2, 0x5ec: 0x3649, 0x5ed: 0x359b, 0x5ee: 0x437e, 0x5ef: 0x0081,
+ 0x5f2: 0x3eb0, 0x5f3: 0x36f7, 0x5f4: 0x3eb8,
+ 0x5f6: 0x491e, 0x5f7: 0x3ed0, 0x5f8: 0x363d, 0x5f9: 0x439c, 0x5fa: 0x366d, 0x5fb: 0x43ae,
+ 0x5fc: 0x3679, 0x5fd: 0x4256, 0x5fe: 0xa100,
+ // Block 0x18, offset 0x600
+ 0x601: 0x3c06, 0x603: 0xa000, 0x604: 0x3c0d, 0x605: 0xa000,
+ 0x607: 0x3c14, 0x608: 0xa000, 0x609: 0x3c1b,
+ 0x60d: 0xa000,
+ 0x620: 0x2f65, 0x621: 0xa000, 0x622: 0x3c29,
+ 0x624: 0xa000, 0x625: 0xa000,
+ 0x62d: 0x3c22, 0x62e: 0x2f60, 0x62f: 0x2f6a,
+ 0x630: 0x3c30, 0x631: 0x3c37, 0x632: 0xa000, 0x633: 0xa000, 0x634: 0x3c3e, 0x635: 0x3c45,
+ 0x636: 0xa000, 0x637: 0xa000, 0x638: 0x3c4c, 0x639: 0x3c53, 0x63a: 0xa000, 0x63b: 0xa000,
+ 0x63c: 0xa000, 0x63d: 0xa000,
+ // Block 0x19, offset 0x640
+ 0x640: 0x3c5a, 0x641: 0x3c61, 0x642: 0xa000, 0x643: 0xa000, 0x644: 0x3c76, 0x645: 0x3c7d,
+ 0x646: 0xa000, 0x647: 0xa000, 0x648: 0x3c84, 0x649: 0x3c8b,
+ 0x651: 0xa000,
+ 0x652: 0xa000,
+ 0x662: 0xa000,
+ 0x668: 0xa000, 0x669: 0xa000,
+ 0x66b: 0xa000, 0x66c: 0x3ca0, 0x66d: 0x3ca7, 0x66e: 0x3cae, 0x66f: 0x3cb5,
+ 0x672: 0xa000, 0x673: 0xa000, 0x674: 0xa000, 0x675: 0xa000,
+ // Block 0x1a, offset 0x680
+ 0x686: 0xa000, 0x68b: 0xa000,
+ 0x68c: 0x3f08, 0x68d: 0xa000, 0x68e: 0x3f10, 0x68f: 0xa000, 0x690: 0x3f18, 0x691: 0xa000,
+ 0x692: 0x3f20, 0x693: 0xa000, 0x694: 0x3f28, 0x695: 0xa000, 0x696: 0x3f30, 0x697: 0xa000,
+ 0x698: 0x3f38, 0x699: 0xa000, 0x69a: 0x3f40, 0x69b: 0xa000, 0x69c: 0x3f48, 0x69d: 0xa000,
+ 0x69e: 0x3f50, 0x69f: 0xa000, 0x6a0: 0x3f58, 0x6a1: 0xa000, 0x6a2: 0x3f60,
+ 0x6a4: 0xa000, 0x6a5: 0x3f68, 0x6a6: 0xa000, 0x6a7: 0x3f70, 0x6a8: 0xa000, 0x6a9: 0x3f78,
+ 0x6af: 0xa000,
+ 0x6b0: 0x3f80, 0x6b1: 0x3f88, 0x6b2: 0xa000, 0x6b3: 0x3f90, 0x6b4: 0x3f98, 0x6b5: 0xa000,
+ 0x6b6: 0x3fa0, 0x6b7: 0x3fa8, 0x6b8: 0xa000, 0x6b9: 0x3fb0, 0x6ba: 0x3fb8, 0x6bb: 0xa000,
+ 0x6bc: 0x3fc0, 0x6bd: 0x3fc8,
+ // Block 0x1b, offset 0x6c0
+ 0x6d4: 0x3f00,
+ 0x6d9: 0x9903, 0x6da: 0x9903, 0x6db: 0x8100, 0x6dc: 0x8100, 0x6dd: 0xa000,
+ 0x6de: 0x3fd0,
+ 0x6e6: 0xa000,
+ 0x6eb: 0xa000, 0x6ec: 0x3fe0, 0x6ed: 0xa000, 0x6ee: 0x3fe8, 0x6ef: 0xa000,
+ 0x6f0: 0x3ff0, 0x6f1: 0xa000, 0x6f2: 0x3ff8, 0x6f3: 0xa000, 0x6f4: 0x4000, 0x6f5: 0xa000,
+ 0x6f6: 0x4008, 0x6f7: 0xa000, 0x6f8: 0x4010, 0x6f9: 0xa000, 0x6fa: 0x4018, 0x6fb: 0xa000,
+ 0x6fc: 0x4020, 0x6fd: 0xa000, 0x6fe: 0x4028, 0x6ff: 0xa000,
+ // Block 0x1c, offset 0x700
+ 0x700: 0x4030, 0x701: 0xa000, 0x702: 0x4038, 0x704: 0xa000, 0x705: 0x4040,
+ 0x706: 0xa000, 0x707: 0x4048, 0x708: 0xa000, 0x709: 0x4050,
+ 0x70f: 0xa000, 0x710: 0x4058, 0x711: 0x4060,
+ 0x712: 0xa000, 0x713: 0x4068, 0x714: 0x4070, 0x715: 0xa000, 0x716: 0x4078, 0x717: 0x4080,
+ 0x718: 0xa000, 0x719: 0x4088, 0x71a: 0x4090, 0x71b: 0xa000, 0x71c: 0x4098, 0x71d: 0x40a0,
+ 0x72f: 0xa000,
+ 0x730: 0xa000, 0x731: 0xa000, 0x732: 0xa000, 0x734: 0x3fd8,
+ 0x737: 0x40a8, 0x738: 0x40b0, 0x739: 0x40b8, 0x73a: 0x40c0,
+ 0x73d: 0xa000, 0x73e: 0x40c8,
+ // Block 0x1d, offset 0x740
+ 0x740: 0x1377, 0x741: 0x0cfb, 0x742: 0x13d3, 0x743: 0x139f, 0x744: 0x0e57, 0x745: 0x06eb,
+ 0x746: 0x08df, 0x747: 0x162b, 0x748: 0x162b, 0x749: 0x0a0b, 0x74a: 0x145f, 0x74b: 0x0943,
+ 0x74c: 0x0a07, 0x74d: 0x0bef, 0x74e: 0x0fcf, 0x74f: 0x115f, 0x750: 0x1297, 0x751: 0x12d3,
+ 0x752: 0x1307, 0x753: 0x141b, 0x754: 0x0d73, 0x755: 0x0dff, 0x756: 0x0eab, 0x757: 0x0f43,
+ 0x758: 0x125f, 0x759: 0x1447, 0x75a: 0x1573, 0x75b: 0x070f, 0x75c: 0x08b3, 0x75d: 0x0d87,
+ 0x75e: 0x0ecf, 0x75f: 0x1293, 0x760: 0x15c3, 0x761: 0x0ab3, 0x762: 0x0e77, 0x763: 0x1283,
+ 0x764: 0x1317, 0x765: 0x0c23, 0x766: 0x11bb, 0x767: 0x12df, 0x768: 0x0b1f, 0x769: 0x0d0f,
+ 0x76a: 0x0e17, 0x76b: 0x0f1b, 0x76c: 0x1427, 0x76d: 0x074f, 0x76e: 0x07e7, 0x76f: 0x0853,
+ 0x770: 0x0c8b, 0x771: 0x0d7f, 0x772: 0x0ecb, 0x773: 0x0fef, 0x774: 0x1177, 0x775: 0x128b,
+ 0x776: 0x12a3, 0x777: 0x13c7, 0x778: 0x14ef, 0x779: 0x15a3, 0x77a: 0x15bf, 0x77b: 0x102b,
+ 0x77c: 0x106b, 0x77d: 0x1123, 0x77e: 0x1243, 0x77f: 0x147b,
+ // Block 0x1e, offset 0x780
+ 0x780: 0x15cb, 0x781: 0x134b, 0x782: 0x09c7, 0x783: 0x0b3b, 0x784: 0x10db, 0x785: 0x119b,
+ 0x786: 0x0eff, 0x787: 0x1033, 0x788: 0x1397, 0x789: 0x14e7, 0x78a: 0x09c3, 0x78b: 0x0a8f,
+ 0x78c: 0x0d77, 0x78d: 0x0e2b, 0x78e: 0x0e5f, 0x78f: 0x1113, 0x790: 0x113b, 0x791: 0x14a7,
+ 0x792: 0x084f, 0x793: 0x11a7, 0x794: 0x07f3, 0x795: 0x07ef, 0x796: 0x1097, 0x797: 0x1127,
+ 0x798: 0x125b, 0x799: 0x14af, 0x79a: 0x1367, 0x79b: 0x0c27, 0x79c: 0x0d73, 0x79d: 0x1357,
+ 0x79e: 0x06f7, 0x79f: 0x0a63, 0x7a0: 0x0b93, 0x7a1: 0x0f2f, 0x7a2: 0x0faf, 0x7a3: 0x0873,
+ 0x7a4: 0x103b, 0x7a5: 0x075f, 0x7a6: 0x0b77, 0x7a7: 0x06d7, 0x7a8: 0x0deb, 0x7a9: 0x0ca3,
+ 0x7aa: 0x110f, 0x7ab: 0x08c7, 0x7ac: 0x09b3, 0x7ad: 0x0ffb, 0x7ae: 0x1263, 0x7af: 0x133b,
+ 0x7b0: 0x0db7, 0x7b1: 0x13f7, 0x7b2: 0x0de3, 0x7b3: 0x0c37, 0x7b4: 0x121b, 0x7b5: 0x0c57,
+ 0x7b6: 0x0fab, 0x7b7: 0x072b, 0x7b8: 0x07a7, 0x7b9: 0x07eb, 0x7ba: 0x0d53, 0x7bb: 0x10fb,
+ 0x7bc: 0x11f3, 0x7bd: 0x1347, 0x7be: 0x145b, 0x7bf: 0x085b,
+ // Block 0x1f, offset 0x7c0
+ 0x7c0: 0x090f, 0x7c1: 0x0a17, 0x7c2: 0x0b2f, 0x7c3: 0x0cbf, 0x7c4: 0x0e7b, 0x7c5: 0x103f,
+ 0x7c6: 0x1497, 0x7c7: 0x157b, 0x7c8: 0x15cf, 0x7c9: 0x15e7, 0x7ca: 0x0837, 0x7cb: 0x0cf3,
+ 0x7cc: 0x0da3, 0x7cd: 0x13eb, 0x7ce: 0x0afb, 0x7cf: 0x0bd7, 0x7d0: 0x0bf3, 0x7d1: 0x0c83,
+ 0x7d2: 0x0e6b, 0x7d3: 0x0eb7, 0x7d4: 0x0f67, 0x7d5: 0x108b, 0x7d6: 0x112f, 0x7d7: 0x1193,
+ 0x7d8: 0x13db, 0x7d9: 0x126b, 0x7da: 0x1403, 0x7db: 0x147f, 0x7dc: 0x080f, 0x7dd: 0x083b,
+ 0x7de: 0x0923, 0x7df: 0x0ea7, 0x7e0: 0x12f3, 0x7e1: 0x133b, 0x7e2: 0x0b1b, 0x7e3: 0x0b8b,
+ 0x7e4: 0x0c4f, 0x7e5: 0x0daf, 0x7e6: 0x10d7, 0x7e7: 0x0f23, 0x7e8: 0x073b, 0x7e9: 0x097f,
+ 0x7ea: 0x0a63, 0x7eb: 0x0ac7, 0x7ec: 0x0b97, 0x7ed: 0x0f3f, 0x7ee: 0x0f5b, 0x7ef: 0x116b,
+ 0x7f0: 0x118b, 0x7f1: 0x1463, 0x7f2: 0x14e3, 0x7f3: 0x14f3, 0x7f4: 0x152f, 0x7f5: 0x0753,
+ 0x7f6: 0x107f, 0x7f7: 0x144f, 0x7f8: 0x14cb, 0x7f9: 0x0baf, 0x7fa: 0x0717, 0x7fb: 0x0777,
+ 0x7fc: 0x0a67, 0x7fd: 0x0a87, 0x7fe: 0x0caf, 0x7ff: 0x0d73,
+ // Block 0x20, offset 0x800
+ 0x800: 0x0ec3, 0x801: 0x0fcb, 0x802: 0x1277, 0x803: 0x1417, 0x804: 0x1623, 0x805: 0x0ce3,
+ 0x806: 0x14a3, 0x807: 0x0833, 0x808: 0x0d2f, 0x809: 0x0d3b, 0x80a: 0x0e0f, 0x80b: 0x0e47,
+ 0x80c: 0x0f4b, 0x80d: 0x0fa7, 0x80e: 0x1027, 0x80f: 0x110b, 0x810: 0x153b, 0x811: 0x07af,
+ 0x812: 0x0c03, 0x813: 0x14b3, 0x814: 0x0767, 0x815: 0x0aab, 0x816: 0x0e2f, 0x817: 0x13df,
+ 0x818: 0x0b67, 0x819: 0x0bb7, 0x81a: 0x0d43, 0x81b: 0x0f2f, 0x81c: 0x14bb, 0x81d: 0x0817,
+ 0x81e: 0x08ff, 0x81f: 0x0a97, 0x820: 0x0cd3, 0x821: 0x0d1f, 0x822: 0x0d5f, 0x823: 0x0df3,
+ 0x824: 0x0f47, 0x825: 0x0fbb, 0x826: 0x1157, 0x827: 0x12f7, 0x828: 0x1303, 0x829: 0x1457,
+ 0x82a: 0x14d7, 0x82b: 0x0883, 0x82c: 0x0e4b, 0x82d: 0x0903, 0x82e: 0x0ec7, 0x82f: 0x0f6b,
+ 0x830: 0x1287, 0x831: 0x14bf, 0x832: 0x15ab, 0x833: 0x15d3, 0x834: 0x0d37, 0x835: 0x0e27,
+ 0x836: 0x11c3, 0x837: 0x10b7, 0x838: 0x10c3, 0x839: 0x10e7, 0x83a: 0x0f17, 0x83b: 0x0e9f,
+ 0x83c: 0x1363, 0x83d: 0x0733, 0x83e: 0x122b, 0x83f: 0x081b,
+ // Block 0x21, offset 0x840
+ 0x840: 0x080b, 0x841: 0x0b0b, 0x842: 0x0c2b, 0x843: 0x10f3, 0x844: 0x0a53, 0x845: 0x0e03,
+ 0x846: 0x0cef, 0x847: 0x13e7, 0x848: 0x12e7, 0x849: 0x14ab, 0x84a: 0x1323, 0x84b: 0x0b27,
+ 0x84c: 0x0787, 0x84d: 0x095b, 0x850: 0x09af,
+ 0x852: 0x0cdf, 0x855: 0x07f7, 0x856: 0x0f1f, 0x857: 0x0fe3,
+ 0x858: 0x1047, 0x859: 0x1063, 0x85a: 0x1067, 0x85b: 0x107b, 0x85c: 0x14fb, 0x85d: 0x10eb,
+ 0x85e: 0x116f, 0x860: 0x128f, 0x862: 0x1353,
+ 0x865: 0x1407, 0x866: 0x1433,
+ 0x86a: 0x154f, 0x86b: 0x1553, 0x86c: 0x1557, 0x86d: 0x15bb, 0x86e: 0x142b, 0x86f: 0x14c7,
+ 0x870: 0x0757, 0x871: 0x077b, 0x872: 0x078f, 0x873: 0x084b, 0x874: 0x0857, 0x875: 0x0897,
+ 0x876: 0x094b, 0x877: 0x0967, 0x878: 0x096f, 0x879: 0x09ab, 0x87a: 0x09b7, 0x87b: 0x0a93,
+ 0x87c: 0x0a9b, 0x87d: 0x0ba3, 0x87e: 0x0bcb, 0x87f: 0x0bd3,
+ // Block 0x22, offset 0x880
+ 0x880: 0x0beb, 0x881: 0x0c97, 0x882: 0x0cc7, 0x883: 0x0ce7, 0x884: 0x0d57, 0x885: 0x0e1b,
+ 0x886: 0x0e37, 0x887: 0x0e67, 0x888: 0x0ebb, 0x889: 0x0edb, 0x88a: 0x0f4f, 0x88b: 0x102f,
+ 0x88c: 0x104b, 0x88d: 0x1053, 0x88e: 0x104f, 0x88f: 0x1057, 0x890: 0x105b, 0x891: 0x105f,
+ 0x892: 0x1073, 0x893: 0x1077, 0x894: 0x109b, 0x895: 0x10af, 0x896: 0x10cb, 0x897: 0x112f,
+ 0x898: 0x1137, 0x899: 0x113f, 0x89a: 0x1153, 0x89b: 0x117b, 0x89c: 0x11cb, 0x89d: 0x11ff,
+ 0x89e: 0x11ff, 0x89f: 0x1267, 0x8a0: 0x130f, 0x8a1: 0x1327, 0x8a2: 0x135b, 0x8a3: 0x135f,
+ 0x8a4: 0x13a3, 0x8a5: 0x13a7, 0x8a6: 0x13ff, 0x8a7: 0x1407, 0x8a8: 0x14db, 0x8a9: 0x151f,
+ 0x8aa: 0x1537, 0x8ab: 0x0b9b, 0x8ac: 0x171e, 0x8ad: 0x11e3,
+ 0x8b0: 0x06df, 0x8b1: 0x07e3, 0x8b2: 0x07a3, 0x8b3: 0x074b, 0x8b4: 0x078b, 0x8b5: 0x07b7,
+ 0x8b6: 0x0847, 0x8b7: 0x0863, 0x8b8: 0x094b, 0x8b9: 0x0937, 0x8ba: 0x0947, 0x8bb: 0x0963,
+ 0x8bc: 0x09af, 0x8bd: 0x09bf, 0x8be: 0x0a03, 0x8bf: 0x0a0f,
+ // Block 0x23, offset 0x8c0
+ 0x8c0: 0x0a2b, 0x8c1: 0x0a3b, 0x8c2: 0x0b23, 0x8c3: 0x0b2b, 0x8c4: 0x0b5b, 0x8c5: 0x0b7b,
+ 0x8c6: 0x0bab, 0x8c7: 0x0bc3, 0x8c8: 0x0bb3, 0x8c9: 0x0bd3, 0x8ca: 0x0bc7, 0x8cb: 0x0beb,
+ 0x8cc: 0x0c07, 0x8cd: 0x0c5f, 0x8ce: 0x0c6b, 0x8cf: 0x0c73, 0x8d0: 0x0c9b, 0x8d1: 0x0cdf,
+ 0x8d2: 0x0d0f, 0x8d3: 0x0d13, 0x8d4: 0x0d27, 0x8d5: 0x0da7, 0x8d6: 0x0db7, 0x8d7: 0x0e0f,
+ 0x8d8: 0x0e5b, 0x8d9: 0x0e53, 0x8da: 0x0e67, 0x8db: 0x0e83, 0x8dc: 0x0ebb, 0x8dd: 0x1013,
+ 0x8de: 0x0edf, 0x8df: 0x0f13, 0x8e0: 0x0f1f, 0x8e1: 0x0f5f, 0x8e2: 0x0f7b, 0x8e3: 0x0f9f,
+ 0x8e4: 0x0fc3, 0x8e5: 0x0fc7, 0x8e6: 0x0fe3, 0x8e7: 0x0fe7, 0x8e8: 0x0ff7, 0x8e9: 0x100b,
+ 0x8ea: 0x1007, 0x8eb: 0x1037, 0x8ec: 0x10b3, 0x8ed: 0x10cb, 0x8ee: 0x10e3, 0x8ef: 0x111b,
+ 0x8f0: 0x112f, 0x8f1: 0x114b, 0x8f2: 0x117b, 0x8f3: 0x122f, 0x8f4: 0x1257, 0x8f5: 0x12cb,
+ 0x8f6: 0x1313, 0x8f7: 0x131f, 0x8f8: 0x1327, 0x8f9: 0x133f, 0x8fa: 0x1353, 0x8fb: 0x1343,
+ 0x8fc: 0x135b, 0x8fd: 0x1357, 0x8fe: 0x134f, 0x8ff: 0x135f,
+ // Block 0x24, offset 0x900
+ 0x900: 0x136b, 0x901: 0x13a7, 0x902: 0x13e3, 0x903: 0x1413, 0x904: 0x144b, 0x905: 0x146b,
+ 0x906: 0x14b7, 0x907: 0x14db, 0x908: 0x14fb, 0x909: 0x150f, 0x90a: 0x151f, 0x90b: 0x152b,
+ 0x90c: 0x1537, 0x90d: 0x158b, 0x90e: 0x162b, 0x90f: 0x16b5, 0x910: 0x16b0, 0x911: 0x16e2,
+ 0x912: 0x0607, 0x913: 0x062f, 0x914: 0x0633, 0x915: 0x1764, 0x916: 0x1791, 0x917: 0x1809,
+ 0x918: 0x1617, 0x919: 0x1627,
+ // Block 0x25, offset 0x940
+ 0x940: 0x06fb, 0x941: 0x06f3, 0x942: 0x0703, 0x943: 0x1647, 0x944: 0x0747, 0x945: 0x0757,
+ 0x946: 0x075b, 0x947: 0x0763, 0x948: 0x076b, 0x949: 0x076f, 0x94a: 0x077b, 0x94b: 0x0773,
+ 0x94c: 0x05b3, 0x94d: 0x165b, 0x94e: 0x078f, 0x94f: 0x0793, 0x950: 0x0797, 0x951: 0x07b3,
+ 0x952: 0x164c, 0x953: 0x05b7, 0x954: 0x079f, 0x955: 0x07bf, 0x956: 0x1656, 0x957: 0x07cf,
+ 0x958: 0x07d7, 0x959: 0x0737, 0x95a: 0x07df, 0x95b: 0x07e3, 0x95c: 0x1831, 0x95d: 0x07ff,
+ 0x95e: 0x0807, 0x95f: 0x05bf, 0x960: 0x081f, 0x961: 0x0823, 0x962: 0x082b, 0x963: 0x082f,
+ 0x964: 0x05c3, 0x965: 0x0847, 0x966: 0x084b, 0x967: 0x0857, 0x968: 0x0863, 0x969: 0x0867,
+ 0x96a: 0x086b, 0x96b: 0x0873, 0x96c: 0x0893, 0x96d: 0x0897, 0x96e: 0x089f, 0x96f: 0x08af,
+ 0x970: 0x08b7, 0x971: 0x08bb, 0x972: 0x08bb, 0x973: 0x08bb, 0x974: 0x166a, 0x975: 0x0e93,
+ 0x976: 0x08cf, 0x977: 0x08d7, 0x978: 0x166f, 0x979: 0x08e3, 0x97a: 0x08eb, 0x97b: 0x08f3,
+ 0x97c: 0x091b, 0x97d: 0x0907, 0x97e: 0x0913, 0x97f: 0x0917,
+ // Block 0x26, offset 0x980
+ 0x980: 0x091f, 0x981: 0x0927, 0x982: 0x092b, 0x983: 0x0933, 0x984: 0x093b, 0x985: 0x093f,
+ 0x986: 0x093f, 0x987: 0x0947, 0x988: 0x094f, 0x989: 0x0953, 0x98a: 0x095f, 0x98b: 0x0983,
+ 0x98c: 0x0967, 0x98d: 0x0987, 0x98e: 0x096b, 0x98f: 0x0973, 0x990: 0x080b, 0x991: 0x09cf,
+ 0x992: 0x0997, 0x993: 0x099b, 0x994: 0x099f, 0x995: 0x0993, 0x996: 0x09a7, 0x997: 0x09a3,
+ 0x998: 0x09bb, 0x999: 0x1674, 0x99a: 0x09d7, 0x99b: 0x09db, 0x99c: 0x09e3, 0x99d: 0x09ef,
+ 0x99e: 0x09f7, 0x99f: 0x0a13, 0x9a0: 0x1679, 0x9a1: 0x167e, 0x9a2: 0x0a1f, 0x9a3: 0x0a23,
+ 0x9a4: 0x0a27, 0x9a5: 0x0a1b, 0x9a6: 0x0a2f, 0x9a7: 0x05c7, 0x9a8: 0x05cb, 0x9a9: 0x0a37,
+ 0x9aa: 0x0a3f, 0x9ab: 0x0a3f, 0x9ac: 0x1683, 0x9ad: 0x0a5b, 0x9ae: 0x0a5f, 0x9af: 0x0a63,
+ 0x9b0: 0x0a6b, 0x9b1: 0x1688, 0x9b2: 0x0a73, 0x9b3: 0x0a77, 0x9b4: 0x0b4f, 0x9b5: 0x0a7f,
+ 0x9b6: 0x05cf, 0x9b7: 0x0a8b, 0x9b8: 0x0a9b, 0x9b9: 0x0aa7, 0x9ba: 0x0aa3, 0x9bb: 0x1692,
+ 0x9bc: 0x0aaf, 0x9bd: 0x1697, 0x9be: 0x0abb, 0x9bf: 0x0ab7,
+ // Block 0x27, offset 0x9c0
+ 0x9c0: 0x0abf, 0x9c1: 0x0acf, 0x9c2: 0x0ad3, 0x9c3: 0x05d3, 0x9c4: 0x0ae3, 0x9c5: 0x0aeb,
+ 0x9c6: 0x0aef, 0x9c7: 0x0af3, 0x9c8: 0x05d7, 0x9c9: 0x169c, 0x9ca: 0x05db, 0x9cb: 0x0b0f,
+ 0x9cc: 0x0b13, 0x9cd: 0x0b17, 0x9ce: 0x0b1f, 0x9cf: 0x1863, 0x9d0: 0x0b37, 0x9d1: 0x16a6,
+ 0x9d2: 0x16a6, 0x9d3: 0x11d7, 0x9d4: 0x0b47, 0x9d5: 0x0b47, 0x9d6: 0x05df, 0x9d7: 0x16c9,
+ 0x9d8: 0x179b, 0x9d9: 0x0b57, 0x9da: 0x0b5f, 0x9db: 0x05e3, 0x9dc: 0x0b73, 0x9dd: 0x0b83,
+ 0x9de: 0x0b87, 0x9df: 0x0b8f, 0x9e0: 0x0b9f, 0x9e1: 0x05eb, 0x9e2: 0x05e7, 0x9e3: 0x0ba3,
+ 0x9e4: 0x16ab, 0x9e5: 0x0ba7, 0x9e6: 0x0bbb, 0x9e7: 0x0bbf, 0x9e8: 0x0bc3, 0x9e9: 0x0bbf,
+ 0x9ea: 0x0bcf, 0x9eb: 0x0bd3, 0x9ec: 0x0be3, 0x9ed: 0x0bdb, 0x9ee: 0x0bdf, 0x9ef: 0x0be7,
+ 0x9f0: 0x0beb, 0x9f1: 0x0bef, 0x9f2: 0x0bfb, 0x9f3: 0x0bff, 0x9f4: 0x0c17, 0x9f5: 0x0c1f,
+ 0x9f6: 0x0c2f, 0x9f7: 0x0c43, 0x9f8: 0x16ba, 0x9f9: 0x0c3f, 0x9fa: 0x0c33, 0x9fb: 0x0c4b,
+ 0x9fc: 0x0c53, 0x9fd: 0x0c67, 0x9fe: 0x16bf, 0x9ff: 0x0c6f,
+ // Block 0x28, offset 0xa00
+ 0xa00: 0x0c63, 0xa01: 0x0c5b, 0xa02: 0x05ef, 0xa03: 0x0c77, 0xa04: 0x0c7f, 0xa05: 0x0c87,
+ 0xa06: 0x0c7b, 0xa07: 0x05f3, 0xa08: 0x0c97, 0xa09: 0x0c9f, 0xa0a: 0x16c4, 0xa0b: 0x0ccb,
+ 0xa0c: 0x0cff, 0xa0d: 0x0cdb, 0xa0e: 0x05ff, 0xa0f: 0x0ce7, 0xa10: 0x05fb, 0xa11: 0x05f7,
+ 0xa12: 0x07c3, 0xa13: 0x07c7, 0xa14: 0x0d03, 0xa15: 0x0ceb, 0xa16: 0x11ab, 0xa17: 0x0663,
+ 0xa18: 0x0d0f, 0xa19: 0x0d13, 0xa1a: 0x0d17, 0xa1b: 0x0d2b, 0xa1c: 0x0d23, 0xa1d: 0x16dd,
+ 0xa1e: 0x0603, 0xa1f: 0x0d3f, 0xa20: 0x0d33, 0xa21: 0x0d4f, 0xa22: 0x0d57, 0xa23: 0x16e7,
+ 0xa24: 0x0d5b, 0xa25: 0x0d47, 0xa26: 0x0d63, 0xa27: 0x0607, 0xa28: 0x0d67, 0xa29: 0x0d6b,
+ 0xa2a: 0x0d6f, 0xa2b: 0x0d7b, 0xa2c: 0x16ec, 0xa2d: 0x0d83, 0xa2e: 0x060b, 0xa2f: 0x0d8f,
+ 0xa30: 0x16f1, 0xa31: 0x0d93, 0xa32: 0x060f, 0xa33: 0x0d9f, 0xa34: 0x0dab, 0xa35: 0x0db7,
+ 0xa36: 0x0dbb, 0xa37: 0x16f6, 0xa38: 0x168d, 0xa39: 0x16fb, 0xa3a: 0x0ddb, 0xa3b: 0x1700,
+ 0xa3c: 0x0de7, 0xa3d: 0x0def, 0xa3e: 0x0ddf, 0xa3f: 0x0dfb,
+ // Block 0x29, offset 0xa40
+ 0xa40: 0x0e0b, 0xa41: 0x0e1b, 0xa42: 0x0e0f, 0xa43: 0x0e13, 0xa44: 0x0e1f, 0xa45: 0x0e23,
+ 0xa46: 0x1705, 0xa47: 0x0e07, 0xa48: 0x0e3b, 0xa49: 0x0e3f, 0xa4a: 0x0613, 0xa4b: 0x0e53,
+ 0xa4c: 0x0e4f, 0xa4d: 0x170a, 0xa4e: 0x0e33, 0xa4f: 0x0e6f, 0xa50: 0x170f, 0xa51: 0x1714,
+ 0xa52: 0x0e73, 0xa53: 0x0e87, 0xa54: 0x0e83, 0xa55: 0x0e7f, 0xa56: 0x0617, 0xa57: 0x0e8b,
+ 0xa58: 0x0e9b, 0xa59: 0x0e97, 0xa5a: 0x0ea3, 0xa5b: 0x1651, 0xa5c: 0x0eb3, 0xa5d: 0x1719,
+ 0xa5e: 0x0ebf, 0xa5f: 0x1723, 0xa60: 0x0ed3, 0xa61: 0x0edf, 0xa62: 0x0ef3, 0xa63: 0x1728,
+ 0xa64: 0x0f07, 0xa65: 0x0f0b, 0xa66: 0x172d, 0xa67: 0x1732, 0xa68: 0x0f27, 0xa69: 0x0f37,
+ 0xa6a: 0x061b, 0xa6b: 0x0f3b, 0xa6c: 0x061f, 0xa6d: 0x061f, 0xa6e: 0x0f53, 0xa6f: 0x0f57,
+ 0xa70: 0x0f5f, 0xa71: 0x0f63, 0xa72: 0x0f6f, 0xa73: 0x0623, 0xa74: 0x0f87, 0xa75: 0x1737,
+ 0xa76: 0x0fa3, 0xa77: 0x173c, 0xa78: 0x0faf, 0xa79: 0x16a1, 0xa7a: 0x0fbf, 0xa7b: 0x1741,
+ 0xa7c: 0x1746, 0xa7d: 0x174b, 0xa7e: 0x0627, 0xa7f: 0x062b,
+ // Block 0x2a, offset 0xa80
+ 0xa80: 0x0ff7, 0xa81: 0x1755, 0xa82: 0x1750, 0xa83: 0x175a, 0xa84: 0x175f, 0xa85: 0x0fff,
+ 0xa86: 0x1003, 0xa87: 0x1003, 0xa88: 0x100b, 0xa89: 0x0633, 0xa8a: 0x100f, 0xa8b: 0x0637,
+ 0xa8c: 0x063b, 0xa8d: 0x1769, 0xa8e: 0x1023, 0xa8f: 0x102b, 0xa90: 0x1037, 0xa91: 0x063f,
+ 0xa92: 0x176e, 0xa93: 0x105b, 0xa94: 0x1773, 0xa95: 0x1778, 0xa96: 0x107b, 0xa97: 0x1093,
+ 0xa98: 0x0643, 0xa99: 0x109b, 0xa9a: 0x109f, 0xa9b: 0x10a3, 0xa9c: 0x177d, 0xa9d: 0x1782,
+ 0xa9e: 0x1782, 0xa9f: 0x10bb, 0xaa0: 0x0647, 0xaa1: 0x1787, 0xaa2: 0x10cf, 0xaa3: 0x10d3,
+ 0xaa4: 0x064b, 0xaa5: 0x178c, 0xaa6: 0x10ef, 0xaa7: 0x064f, 0xaa8: 0x10ff, 0xaa9: 0x10f7,
+ 0xaaa: 0x1107, 0xaab: 0x1796, 0xaac: 0x111f, 0xaad: 0x0653, 0xaae: 0x112b, 0xaaf: 0x1133,
+ 0xab0: 0x1143, 0xab1: 0x0657, 0xab2: 0x17a0, 0xab3: 0x17a5, 0xab4: 0x065b, 0xab5: 0x17aa,
+ 0xab6: 0x115b, 0xab7: 0x17af, 0xab8: 0x1167, 0xab9: 0x1173, 0xaba: 0x117b, 0xabb: 0x17b4,
+ 0xabc: 0x17b9, 0xabd: 0x118f, 0xabe: 0x17be, 0xabf: 0x1197,
+ // Block 0x2b, offset 0xac0
+ 0xac0: 0x16ce, 0xac1: 0x065f, 0xac2: 0x11af, 0xac3: 0x11b3, 0xac4: 0x0667, 0xac5: 0x11b7,
+ 0xac6: 0x0a33, 0xac7: 0x17c3, 0xac8: 0x17c8, 0xac9: 0x16d3, 0xaca: 0x16d8, 0xacb: 0x11d7,
+ 0xacc: 0x11db, 0xacd: 0x13f3, 0xace: 0x066b, 0xacf: 0x1207, 0xad0: 0x1203, 0xad1: 0x120b,
+ 0xad2: 0x083f, 0xad3: 0x120f, 0xad4: 0x1213, 0xad5: 0x1217, 0xad6: 0x121f, 0xad7: 0x17cd,
+ 0xad8: 0x121b, 0xad9: 0x1223, 0xada: 0x1237, 0xadb: 0x123b, 0xadc: 0x1227, 0xadd: 0x123f,
+ 0xade: 0x1253, 0xadf: 0x1267, 0xae0: 0x1233, 0xae1: 0x1247, 0xae2: 0x124b, 0xae3: 0x124f,
+ 0xae4: 0x17d2, 0xae5: 0x17dc, 0xae6: 0x17d7, 0xae7: 0x066f, 0xae8: 0x126f, 0xae9: 0x1273,
+ 0xaea: 0x127b, 0xaeb: 0x17f0, 0xaec: 0x127f, 0xaed: 0x17e1, 0xaee: 0x0673, 0xaef: 0x0677,
+ 0xaf0: 0x17e6, 0xaf1: 0x17eb, 0xaf2: 0x067b, 0xaf3: 0x129f, 0xaf4: 0x12a3, 0xaf5: 0x12a7,
+ 0xaf6: 0x12ab, 0xaf7: 0x12b7, 0xaf8: 0x12b3, 0xaf9: 0x12bf, 0xafa: 0x12bb, 0xafb: 0x12cb,
+ 0xafc: 0x12c3, 0xafd: 0x12c7, 0xafe: 0x12cf, 0xaff: 0x067f,
+ // Block 0x2c, offset 0xb00
+ 0xb00: 0x12d7, 0xb01: 0x12db, 0xb02: 0x0683, 0xb03: 0x12eb, 0xb04: 0x12ef, 0xb05: 0x17f5,
+ 0xb06: 0x12fb, 0xb07: 0x12ff, 0xb08: 0x0687, 0xb09: 0x130b, 0xb0a: 0x05bb, 0xb0b: 0x17fa,
+ 0xb0c: 0x17ff, 0xb0d: 0x068b, 0xb0e: 0x068f, 0xb0f: 0x1337, 0xb10: 0x134f, 0xb11: 0x136b,
+ 0xb12: 0x137b, 0xb13: 0x1804, 0xb14: 0x138f, 0xb15: 0x1393, 0xb16: 0x13ab, 0xb17: 0x13b7,
+ 0xb18: 0x180e, 0xb19: 0x1660, 0xb1a: 0x13c3, 0xb1b: 0x13bf, 0xb1c: 0x13cb, 0xb1d: 0x1665,
+ 0xb1e: 0x13d7, 0xb1f: 0x13e3, 0xb20: 0x1813, 0xb21: 0x1818, 0xb22: 0x1423, 0xb23: 0x142f,
+ 0xb24: 0x1437, 0xb25: 0x181d, 0xb26: 0x143b, 0xb27: 0x1467, 0xb28: 0x1473, 0xb29: 0x1477,
+ 0xb2a: 0x146f, 0xb2b: 0x1483, 0xb2c: 0x1487, 0xb2d: 0x1822, 0xb2e: 0x1493, 0xb2f: 0x0693,
+ 0xb30: 0x149b, 0xb31: 0x1827, 0xb32: 0x0697, 0xb33: 0x14d3, 0xb34: 0x0ac3, 0xb35: 0x14eb,
+ 0xb36: 0x182c, 0xb37: 0x1836, 0xb38: 0x069b, 0xb39: 0x069f, 0xb3a: 0x1513, 0xb3b: 0x183b,
+ 0xb3c: 0x06a3, 0xb3d: 0x1840, 0xb3e: 0x152b, 0xb3f: 0x152b,
+ // Block 0x2d, offset 0xb40
+ 0xb40: 0x1533, 0xb41: 0x1845, 0xb42: 0x154b, 0xb43: 0x06a7, 0xb44: 0x155b, 0xb45: 0x1567,
+ 0xb46: 0x156f, 0xb47: 0x1577, 0xb48: 0x06ab, 0xb49: 0x184a, 0xb4a: 0x158b, 0xb4b: 0x15a7,
+ 0xb4c: 0x15b3, 0xb4d: 0x06af, 0xb4e: 0x06b3, 0xb4f: 0x15b7, 0xb50: 0x184f, 0xb51: 0x06b7,
+ 0xb52: 0x1854, 0xb53: 0x1859, 0xb54: 0x185e, 0xb55: 0x15db, 0xb56: 0x06bb, 0xb57: 0x15ef,
+ 0xb58: 0x15f7, 0xb59: 0x15fb, 0xb5a: 0x1603, 0xb5b: 0x160b, 0xb5c: 0x1613, 0xb5d: 0x1868,
+}
+
+// nfcIndex: 22 blocks, 1408 entries, 1408 bytes
+// Block 0 is the zero block.
+var nfcIndex = [1408]uint8{
+ // Block 0x0, offset 0x0
+ // Block 0x1, offset 0x40
+ // Block 0x2, offset 0x80
+ // Block 0x3, offset 0xc0
+ 0xc2: 0x2c, 0xc3: 0x01, 0xc4: 0x02, 0xc5: 0x03, 0xc6: 0x2d, 0xc7: 0x04,
+ 0xc8: 0x05, 0xca: 0x2e, 0xcb: 0x2f, 0xcc: 0x06, 0xcd: 0x07, 0xce: 0x08, 0xcf: 0x30,
+ 0xd0: 0x09, 0xd1: 0x31, 0xd2: 0x32, 0xd3: 0x0a, 0xd6: 0x0b, 0xd7: 0x33,
+ 0xd8: 0x34, 0xd9: 0x0c, 0xdb: 0x35, 0xdc: 0x36, 0xdd: 0x37, 0xdf: 0x38,
+ 0xe0: 0x02, 0xe1: 0x03, 0xe2: 0x04, 0xe3: 0x05,
+ 0xea: 0x06, 0xeb: 0x07, 0xec: 0x08, 0xed: 0x09, 0xef: 0x0a,
+ 0xf0: 0x13,
+ // Block 0x4, offset 0x100
+ 0x120: 0x39, 0x121: 0x3a, 0x123: 0x3b, 0x124: 0x3c, 0x125: 0x3d, 0x126: 0x3e, 0x127: 0x3f,
+ 0x128: 0x40, 0x129: 0x41, 0x12a: 0x42, 0x12b: 0x43, 0x12c: 0x3e, 0x12d: 0x44, 0x12e: 0x45, 0x12f: 0x46,
+ 0x131: 0x47, 0x132: 0x48, 0x133: 0x49, 0x134: 0x4a, 0x135: 0x4b, 0x137: 0x4c,
+ 0x138: 0x4d, 0x139: 0x4e, 0x13a: 0x4f, 0x13b: 0x50, 0x13c: 0x51, 0x13d: 0x52, 0x13e: 0x53, 0x13f: 0x54,
+ // Block 0x5, offset 0x140
+ 0x140: 0x55, 0x142: 0x56, 0x144: 0x57, 0x145: 0x58, 0x146: 0x59, 0x147: 0x5a,
+ 0x14d: 0x5b,
+ 0x15c: 0x5c, 0x15f: 0x5d,
+ 0x162: 0x5e, 0x164: 0x5f,
+ 0x168: 0x60, 0x169: 0x61, 0x16a: 0x62, 0x16c: 0x0d, 0x16d: 0x63, 0x16e: 0x64, 0x16f: 0x65,
+ 0x170: 0x66, 0x173: 0x67, 0x177: 0x68,
+ 0x178: 0x0e, 0x179: 0x0f, 0x17a: 0x10, 0x17b: 0x11, 0x17c: 0x12, 0x17d: 0x13, 0x17e: 0x14, 0x17f: 0x15,
+ // Block 0x6, offset 0x180
+ 0x180: 0x69, 0x183: 0x6a, 0x184: 0x6b, 0x186: 0x6c, 0x187: 0x6d,
+ 0x188: 0x6e, 0x189: 0x16, 0x18a: 0x17, 0x18b: 0x6f, 0x18c: 0x70,
+ 0x1ab: 0x71,
+ 0x1b3: 0x72, 0x1b5: 0x73, 0x1b7: 0x74,
+ // Block 0x7, offset 0x1c0
+ 0x1c0: 0x75, 0x1c1: 0x18, 0x1c2: 0x19, 0x1c3: 0x1a, 0x1c4: 0x76, 0x1c5: 0x77,
+ 0x1c9: 0x78, 0x1cc: 0x79, 0x1cd: 0x7a,
+ // Block 0x8, offset 0x200
+ 0x219: 0x7b, 0x21a: 0x7c, 0x21b: 0x7d,
+ 0x220: 0x7e, 0x223: 0x7f, 0x224: 0x80, 0x225: 0x81, 0x226: 0x82, 0x227: 0x83,
+ 0x22a: 0x84, 0x22b: 0x85, 0x22f: 0x86,
+ 0x230: 0x87, 0x231: 0x88, 0x232: 0x89, 0x233: 0x8a, 0x234: 0x8b, 0x235: 0x8c, 0x236: 0x8d, 0x237: 0x87,
+ 0x238: 0x88, 0x239: 0x89, 0x23a: 0x8a, 0x23b: 0x8b, 0x23c: 0x8c, 0x23d: 0x8d, 0x23e: 0x87, 0x23f: 0x88,
+ // Block 0x9, offset 0x240
+ 0x240: 0x89, 0x241: 0x8a, 0x242: 0x8b, 0x243: 0x8c, 0x244: 0x8d, 0x245: 0x87, 0x246: 0x88, 0x247: 0x89,
+ 0x248: 0x8a, 0x249: 0x8b, 0x24a: 0x8c, 0x24b: 0x8d, 0x24c: 0x87, 0x24d: 0x88, 0x24e: 0x89, 0x24f: 0x8a,
+ 0x250: 0x8b, 0x251: 0x8c, 0x252: 0x8d, 0x253: 0x87, 0x254: 0x88, 0x255: 0x89, 0x256: 0x8a, 0x257: 0x8b,
+ 0x258: 0x8c, 0x259: 0x8d, 0x25a: 0x87, 0x25b: 0x88, 0x25c: 0x89, 0x25d: 0x8a, 0x25e: 0x8b, 0x25f: 0x8c,
+ 0x260: 0x8d, 0x261: 0x87, 0x262: 0x88, 0x263: 0x89, 0x264: 0x8a, 0x265: 0x8b, 0x266: 0x8c, 0x267: 0x8d,
+ 0x268: 0x87, 0x269: 0x88, 0x26a: 0x89, 0x26b: 0x8a, 0x26c: 0x8b, 0x26d: 0x8c, 0x26e: 0x8d, 0x26f: 0x87,
+ 0x270: 0x88, 0x271: 0x89, 0x272: 0x8a, 0x273: 0x8b, 0x274: 0x8c, 0x275: 0x8d, 0x276: 0x87, 0x277: 0x88,
+ 0x278: 0x89, 0x279: 0x8a, 0x27a: 0x8b, 0x27b: 0x8c, 0x27c: 0x8d, 0x27d: 0x87, 0x27e: 0x88, 0x27f: 0x89,
+ // Block 0xa, offset 0x280
+ 0x280: 0x8a, 0x281: 0x8b, 0x282: 0x8c, 0x283: 0x8d, 0x284: 0x87, 0x285: 0x88, 0x286: 0x89, 0x287: 0x8a,
+ 0x288: 0x8b, 0x289: 0x8c, 0x28a: 0x8d, 0x28b: 0x87, 0x28c: 0x88, 0x28d: 0x89, 0x28e: 0x8a, 0x28f: 0x8b,
+ 0x290: 0x8c, 0x291: 0x8d, 0x292: 0x87, 0x293: 0x88, 0x294: 0x89, 0x295: 0x8a, 0x296: 0x8b, 0x297: 0x8c,
+ 0x298: 0x8d, 0x299: 0x87, 0x29a: 0x88, 0x29b: 0x89, 0x29c: 0x8a, 0x29d: 0x8b, 0x29e: 0x8c, 0x29f: 0x8d,
+ 0x2a0: 0x87, 0x2a1: 0x88, 0x2a2: 0x89, 0x2a3: 0x8a, 0x2a4: 0x8b, 0x2a5: 0x8c, 0x2a6: 0x8d, 0x2a7: 0x87,
+ 0x2a8: 0x88, 0x2a9: 0x89, 0x2aa: 0x8a, 0x2ab: 0x8b, 0x2ac: 0x8c, 0x2ad: 0x8d, 0x2ae: 0x87, 0x2af: 0x88,
+ 0x2b0: 0x89, 0x2b1: 0x8a, 0x2b2: 0x8b, 0x2b3: 0x8c, 0x2b4: 0x8d, 0x2b5: 0x87, 0x2b6: 0x88, 0x2b7: 0x89,
+ 0x2b8: 0x8a, 0x2b9: 0x8b, 0x2ba: 0x8c, 0x2bb: 0x8d, 0x2bc: 0x87, 0x2bd: 0x88, 0x2be: 0x89, 0x2bf: 0x8a,
+ // Block 0xb, offset 0x2c0
+ 0x2c0: 0x8b, 0x2c1: 0x8c, 0x2c2: 0x8d, 0x2c3: 0x87, 0x2c4: 0x88, 0x2c5: 0x89, 0x2c6: 0x8a, 0x2c7: 0x8b,
+ 0x2c8: 0x8c, 0x2c9: 0x8d, 0x2ca: 0x87, 0x2cb: 0x88, 0x2cc: 0x89, 0x2cd: 0x8a, 0x2ce: 0x8b, 0x2cf: 0x8c,
+ 0x2d0: 0x8d, 0x2d1: 0x87, 0x2d2: 0x88, 0x2d3: 0x89, 0x2d4: 0x8a, 0x2d5: 0x8b, 0x2d6: 0x8c, 0x2d7: 0x8d,
+ 0x2d8: 0x87, 0x2d9: 0x88, 0x2da: 0x89, 0x2db: 0x8a, 0x2dc: 0x8b, 0x2dd: 0x8c, 0x2de: 0x8e,
+ // Block 0xc, offset 0x300
+ 0x324: 0x1b, 0x325: 0x1c, 0x326: 0x1d, 0x327: 0x1e,
+ 0x328: 0x1f, 0x329: 0x20, 0x32a: 0x21, 0x32b: 0x22, 0x32c: 0x8f, 0x32d: 0x90, 0x32e: 0x91,
+ 0x331: 0x92, 0x332: 0x93, 0x333: 0x94, 0x334: 0x95,
+ 0x338: 0x96, 0x339: 0x97, 0x33a: 0x98, 0x33b: 0x99, 0x33e: 0x9a, 0x33f: 0x9b,
+ // Block 0xd, offset 0x340
+ 0x347: 0x9c,
+ 0x34b: 0x9d, 0x34d: 0x9e,
+ 0x368: 0x9f, 0x36b: 0xa0,
+ // Block 0xe, offset 0x380
+ 0x381: 0xa1, 0x382: 0xa2, 0x384: 0xa3, 0x385: 0x82, 0x387: 0xa4,
+ 0x388: 0xa5, 0x38b: 0xa6, 0x38c: 0x3e, 0x38d: 0xa7,
+ 0x391: 0xa8, 0x392: 0xa9, 0x393: 0xaa, 0x396: 0xab, 0x397: 0xac,
+ 0x398: 0x73, 0x39a: 0xad, 0x39c: 0xae,
+ 0x3b0: 0x73,
+ // Block 0xf, offset 0x3c0
+ 0x3eb: 0xaf, 0x3ec: 0xb0,
+ // Block 0x10, offset 0x400
+ 0x432: 0xb1,
+ // Block 0x11, offset 0x440
+ 0x445: 0xb2, 0x446: 0xb3, 0x447: 0xb4,
+ 0x449: 0xb5,
+ // Block 0x12, offset 0x480
+ 0x480: 0xb6,
+ 0x4a3: 0xb7, 0x4a5: 0xb8,
+ // Block 0x13, offset 0x4c0
+ 0x4c8: 0xb9,
+ // Block 0x14, offset 0x500
+ 0x520: 0x23, 0x521: 0x24, 0x522: 0x25, 0x523: 0x26, 0x524: 0x27, 0x525: 0x28, 0x526: 0x29, 0x527: 0x2a,
+ 0x528: 0x2b,
+ // Block 0x15, offset 0x540
+ 0x550: 0x0b, 0x551: 0x0c, 0x556: 0x0d,
+ 0x55b: 0x0e, 0x55d: 0x0f, 0x55e: 0x10, 0x55f: 0x11,
+ 0x56f: 0x12,
+}
+
+// nfcSparseOffset: 142 entries, 284 bytes
+var nfcSparseOffset = []uint16{0x0, 0x5, 0x9, 0xb, 0xd, 0x18, 0x28, 0x2a, 0x2f, 0x3a, 0x49, 0x56, 0x5e, 0x62, 0x67, 0x69, 0x7a, 0x82, 0x89, 0x8c, 0x93, 0x97, 0x9b, 0x9d, 0x9f, 0xa8, 0xac, 0xb3, 0xb8, 0xbb, 0xc5, 0xc7, 0xce, 0xd6, 0xd9, 0xdb, 0xdd, 0xdf, 0xe4, 0xf5, 0x101, 0x103, 0x109, 0x10b, 0x10d, 0x10f, 0x111, 0x113, 0x115, 0x118, 0x11b, 0x11d, 0x120, 0x123, 0x127, 0x12c, 0x135, 0x137, 0x13a, 0x13c, 0x147, 0x157, 0x15b, 0x169, 0x16c, 0x172, 0x178, 0x183, 0x187, 0x189, 0x18b, 0x18d, 0x [...]
+
+// nfcSparseValues: 688 entries, 2752 bytes
+var nfcSparseValues = [688]valueRange{
+ // Block 0x0, offset 0x0
+ {value: 0x0000, lo: 0x04},
+ {value: 0xa100, lo: 0xa8, hi: 0xa8},
+ {value: 0x8100, lo: 0xaf, hi: 0xaf},
+ {value: 0x8100, lo: 0xb4, hi: 0xb4},
+ {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: 0xa000, lo: 0xb7, hi: 0xb7},
+ // Block 0x2, offset 0x9
+ {value: 0x0000, lo: 0x01},
+ {value: 0xa000, lo: 0x92, hi: 0x92},
+ // Block 0x3, offset 0xb
+ {value: 0x0000, lo: 0x01},
+ {value: 0x8100, lo: 0x98, hi: 0x9d},
+ // Block 0x4, offset 0xd
+ {value: 0x0006, lo: 0x0a},
+ {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: 0x36c7, lo: 0x8c, hi: 0x8c},
+ {value: 0x36df, lo: 0x8d, hi: 0x8d},
+ {value: 0x490c, lo: 0x8e, hi: 0x8e},
+ {value: 0xa000, lo: 0x92, hi: 0x92},
+ {value: 0x36fd, lo: 0x93, hi: 0x94},
+ // Block 0x5, offset 0x18
+ {value: 0x0000, lo: 0x0f},
+ {value: 0xa000, lo: 0x83, hi: 0x83},
+ {value: 0xa000, lo: 0x87, hi: 0x87},
+ {value: 0xa000, lo: 0x8b, hi: 0x8b},
+ {value: 0xa000, lo: 0x8d, hi: 0x8d},
+ {value: 0x37a5, lo: 0x90, hi: 0x90},
+ {value: 0x37b1, lo: 0x91, hi: 0x91},
+ {value: 0x379f, lo: 0x93, hi: 0x93},
+ {value: 0xa000, lo: 0x96, hi: 0x96},
+ {value: 0x3817, lo: 0x97, hi: 0x97},
+ {value: 0x37e1, lo: 0x9c, hi: 0x9c},
+ {value: 0x37c9, lo: 0x9d, hi: 0x9d},
+ {value: 0x37f3, lo: 0x9e, hi: 0x9e},
+ {value: 0xa000, lo: 0xb4, hi: 0xb5},
+ {value: 0x381d, lo: 0xb6, hi: 0xb6},
+ {value: 0x3823, lo: 0xb7, hi: 0xb7},
+ // Block 0x6, offset 0x28
+ {value: 0x0000, lo: 0x01},
+ {value: 0x8132, lo: 0x83, hi: 0x87},
+ // Block 0x7, offset 0x2a
+ {value: 0x0001, lo: 0x04},
+ {value: 0x8113, lo: 0x81, hi: 0x82},
+ {value: 0x8132, lo: 0x84, hi: 0x84},
+ {value: 0x812d, lo: 0x85, hi: 0x85},
+ {value: 0x810d, lo: 0x87, hi: 0x87},
+ // Block 0x8, offset 0x2f
+ {value: 0x0000, lo: 0x0a},
+ {value: 0x8132, lo: 0x90, hi: 0x97},
+ {value: 0x8119, lo: 0x98, hi: 0x98},
+ {value: 0x811a, lo: 0x99, hi: 0x99},
+ {value: 0x811b, lo: 0x9a, hi: 0x9a},
+ {value: 0x3841, lo: 0xa2, hi: 0xa2},
+ {value: 0x3847, lo: 0xa3, hi: 0xa3},
+ {value: 0x3853, lo: 0xa4, hi: 0xa4},
+ {value: 0x384d, lo: 0xa5, hi: 0xa5},
+ {value: 0x3859, lo: 0xa6, hi: 0xa6},
+ {value: 0xa000, lo: 0xa7, hi: 0xa7},
+ // Block 0x9, offset 0x3a
+ {value: 0x0000, lo: 0x0e},
+ {value: 0x386b, lo: 0x80, hi: 0x80},
+ {value: 0xa000, lo: 0x81, hi: 0x81},
+ {value: 0x385f, lo: 0x82, hi: 0x82},
+ {value: 0xa000, lo: 0x92, hi: 0x92},
+ {value: 0x3865, lo: 0x93, hi: 0x93},
+ {value: 0xa000, lo: 0x95, hi: 0x95},
+ {value: 0x8132, lo: 0x96, hi: 0x9c},
+ {value: 0x8132, lo: 0x9f, hi: 0xa2},
+ {value: 0x812d, lo: 0xa3, hi: 0xa3},
+ {value: 0x8132, lo: 0xa4, hi: 0xa4},
+ {value: 0x8132, lo: 0xa7, hi: 0xa8},
+ {value: 0x812d, lo: 0xaa, hi: 0xaa},
+ {value: 0x8132, lo: 0xab, hi: 0xac},
+ {value: 0x812d, lo: 0xad, hi: 0xad},
+ // Block 0xa, offset 0x49
+ {value: 0x0000, lo: 0x0c},
+ {value: 0x811f, lo: 0x91, hi: 0x91},
+ {value: 0x8132, lo: 0xb0, hi: 0xb0},
+ {value: 0x812d, lo: 0xb1, hi: 0xb1},
+ {value: 0x8132, lo: 0xb2, hi: 0xb3},
+ {value: 0x812d, lo: 0xb4, hi: 0xb4},
+ {value: 0x8132, lo: 0xb5, hi: 0xb6},
+ {value: 0x812d, lo: 0xb7, hi: 0xb9},
+ {value: 0x8132, lo: 0xba, hi: 0xba},
+ {value: 0x812d, lo: 0xbb, hi: 0xbc},
+ {value: 0x8132, lo: 0xbd, hi: 0xbd},
+ {value: 0x812d, lo: 0xbe, hi: 0xbe},
+ {value: 0x8132, lo: 0xbf, hi: 0xbf},
+ // Block 0xb, offset 0x56
+ {value: 0x0005, lo: 0x07},
+ {value: 0x8132, lo: 0x80, hi: 0x80},
+ {value: 0x8132, lo: 0x81, hi: 0x81},
+ {value: 0x812d, lo: 0x82, hi: 0x83},
+ {value: 0x812d, lo: 0x84, hi: 0x85},
+ {value: 0x812d, lo: 0x86, hi: 0x87},
+ {value: 0x812d, lo: 0x88, hi: 0x89},
+ {value: 0x8132, lo: 0x8a, hi: 0x8a},
+ // Block 0xc, offset 0x5e
+ {value: 0x0000, lo: 0x03},
+ {value: 0x8132, lo: 0xab, hi: 0xb1},
+ {value: 0x812d, lo: 0xb2, hi: 0xb2},
+ {value: 0x8132, lo: 0xb3, hi: 0xb3},
+ // Block 0xd, offset 0x62
+ {value: 0x0000, lo: 0x04},
+ {value: 0x8132, lo: 0x96, hi: 0x99},
+ {value: 0x8132, lo: 0x9b, hi: 0xa3},
+ {value: 0x8132, lo: 0xa5, hi: 0xa7},
+ {value: 0x8132, lo: 0xa9, hi: 0xad},
+ // Block 0xe, offset 0x67
+ {value: 0x0000, lo: 0x01},
+ {value: 0x812d, lo: 0x99, hi: 0x9b},
+ // Block 0xf, offset 0x69
+ {value: 0x0000, lo: 0x10},
+ {value: 0x8132, lo: 0x94, hi: 0xa1},
+ {value: 0x812d, lo: 0xa3, hi: 0xa3},
+ {value: 0x8132, lo: 0xa4, hi: 0xa5},
+ {value: 0x812d, lo: 0xa6, hi: 0xa6},
+ {value: 0x8132, lo: 0xa7, hi: 0xa8},
+ {value: 0x812d, lo: 0xa9, hi: 0xa9},
+ {value: 0x8132, lo: 0xaa, hi: 0xac},
+ {value: 0x812d, lo: 0xad, hi: 0xaf},
+ {value: 0x8116, lo: 0xb0, hi: 0xb0},
+ {value: 0x8117, lo: 0xb1, hi: 0xb1},
+ {value: 0x8118, lo: 0xb2, hi: 0xb2},
+ {value: 0x8132, lo: 0xb3, hi: 0xb5},
+ {value: 0x812d, lo: 0xb6, hi: 0xb6},
+ {value: 0x8132, lo: 0xb7, hi: 0xb8},
+ {value: 0x812d, lo: 0xb9, hi: 0xba},
+ {value: 0x8132, lo: 0xbb, hi: 0xbf},
+ // Block 0x10, offset 0x7a
+ {value: 0x0000, lo: 0x07},
+ {value: 0xa000, lo: 0xa8, hi: 0xa8},
+ {value: 0x3ed8, lo: 0xa9, hi: 0xa9},
+ {value: 0xa000, lo: 0xb0, hi: 0xb0},
+ {value: 0x3ee0, lo: 0xb1, hi: 0xb1},
+ {value: 0xa000, lo: 0xb3, hi: 0xb3},
+ {value: 0x3ee8, lo: 0xb4, hi: 0xb4},
+ {value: 0x9902, lo: 0xbc, hi: 0xbc},
+ // Block 0x11, offset 0x82
+ {value: 0x0008, lo: 0x06},
+ {value: 0x8104, lo: 0x8d, hi: 0x8d},
+ {value: 0x8132, lo: 0x91, hi: 0x91},
+ {value: 0x812d, lo: 0x92, hi: 0x92},
+ {value: 0x8132, lo: 0x93, hi: 0x93},
+ {value: 0x8132, lo: 0x94, hi: 0x94},
+ {value: 0x45b2, lo: 0x98, hi: 0x9f},
+ // Block 0x12, offset 0x89
+ {value: 0x0000, lo: 0x02},
+ {value: 0x8102, lo: 0xbc, hi: 0xbc},
+ {value: 0x9900, lo: 0xbe, hi: 0xbe},
+ // Block 0x13, offset 0x8c
+ {value: 0x0008, lo: 0x06},
+ {value: 0xa000, lo: 0x87, hi: 0x87},
+ {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},
+ // Block 0x14, offset 0x93
+ {value: 0x0000, lo: 0x03},
+ {value: 0x462a, lo: 0xb3, hi: 0xb3},
+ {value: 0x4632, 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},
+ // Block 0x16, offset 0x9b
+ {value: 0x0000, lo: 0x01},
+ {value: 0x8102, lo: 0xbc, hi: 0xbc},
+ // Block 0x17, offset 0x9d
+ {value: 0x0000, lo: 0x01},
+ {value: 0x8104, lo: 0x8d, hi: 0x8d},
+ // Block 0x18, offset 0x9f
+ {value: 0x0000, lo: 0x08},
+ {value: 0xa000, lo: 0x87, hi: 0x87},
+ {value: 0x2cb6, lo: 0x88, hi: 0x88},
+ {value: 0x2cae, lo: 0x8b, hi: 0x8b},
+ {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},
+ // Block 0x19, offset 0xa8
+ {value: 0x0000, lo: 0x03},
+ {value: 0xa000, lo: 0x92, hi: 0x92},
+ {value: 0x2cc6, lo: 0x94, hi: 0x94},
+ {value: 0x9900, lo: 0xbe, hi: 0xbe},
+ // Block 0x1a, offset 0xac
+ {value: 0x0000, lo: 0x06},
+ {value: 0xa000, lo: 0x86, hi: 0x87},
+ {value: 0x2cce, lo: 0x8a, hi: 0x8a},
+ {value: 0x2cde, lo: 0x8b, hi: 0x8b},
+ {value: 0x2cd6, lo: 0x8c, hi: 0x8c},
+ {value: 0x8104, lo: 0x8d, hi: 0x8d},
+ {value: 0x9900, lo: 0x97, hi: 0x97},
+ // Block 0x1b, offset 0xb3
+ {value: 0x1801, lo: 0x04},
+ {value: 0xa000, lo: 0x86, hi: 0x86},
+ {value: 0x3ef0, lo: 0x88, hi: 0x88},
+ {value: 0x8104, lo: 0x8d, hi: 0x8d},
+ {value: 0x8120, lo: 0x95, hi: 0x96},
+ // Block 0x1c, offset 0xb8
+ {value: 0x0000, lo: 0x02},
+ {value: 0x8102, lo: 0xbc, hi: 0xbc},
+ {value: 0xa000, lo: 0xbf, hi: 0xbf},
+ // Block 0x1d, offset 0xbb
+ {value: 0x0000, lo: 0x09},
+ {value: 0x2ce6, lo: 0x80, hi: 0x80},
+ {value: 0x9900, lo: 0x82, hi: 0x82},
+ {value: 0xa000, lo: 0x86, hi: 0x86},
+ {value: 0x2cee, lo: 0x87, hi: 0x87},
+ {value: 0x2cf6, lo: 0x88, hi: 0x88},
+ {value: 0x2f50, lo: 0x8a, hi: 0x8a},
+ {value: 0x2dd8, lo: 0x8b, hi: 0x8b},
+ {value: 0x8104, lo: 0x8d, hi: 0x8d},
+ {value: 0x9900, lo: 0x95, hi: 0x96},
+ // Block 0x1e, offset 0xc5
+ {value: 0x0000, lo: 0x01},
+ {value: 0x9900, lo: 0xbe, hi: 0xbe},
+ // Block 0x1f, offset 0xc7
+ {value: 0x0000, lo: 0x06},
+ {value: 0xa000, lo: 0x86, hi: 0x87},
+ {value: 0x2cfe, lo: 0x8a, hi: 0x8a},
+ {value: 0x2d0e, lo: 0x8b, hi: 0x8b},
+ {value: 0x2d06, lo: 0x8c, hi: 0x8c},
+ {value: 0x8104, lo: 0x8d, hi: 0x8d},
+ {value: 0x9900, lo: 0x97, hi: 0x97},
+ // Block 0x20, offset 0xce
+ {value: 0x6bea, lo: 0x07},
+ {value: 0x9904, lo: 0x8a, hi: 0x8a},
+ {value: 0x9900, lo: 0x8f, hi: 0x8f},
+ {value: 0xa000, lo: 0x99, hi: 0x99},
+ {value: 0x3ef8, lo: 0x9a, hi: 0x9a},
+ {value: 0x2f58, lo: 0x9c, hi: 0x9c},
+ {value: 0x2de3, lo: 0x9d, hi: 0x9d},
+ {value: 0x2d16, lo: 0x9e, hi: 0x9f},
+ // Block 0x21, offset 0xd6
+ {value: 0x0000, lo: 0x02},
+ {value: 0x8122, lo: 0xb8, hi: 0xb9},
+ {value: 0x8104, lo: 0xba, hi: 0xba},
+ // Block 0x22, offset 0xd9
+ {value: 0x0000, lo: 0x01},
+ {value: 0x8123, lo: 0x88, hi: 0x8b},
+ // Block 0x23, offset 0xdb
+ {value: 0x0000, lo: 0x01},
+ {value: 0x8124, lo: 0xb8, hi: 0xb9},
+ // Block 0x24, offset 0xdd
+ {value: 0x0000, lo: 0x01},
+ {value: 0x8125, lo: 0x88, hi: 0x8b},
+ // Block 0x25, offset 0xdf
+ {value: 0x0000, lo: 0x04},
+ {value: 0x812d, lo: 0x98, hi: 0x99},
+ {value: 0x812d, lo: 0xb5, hi: 0xb5},
+ {value: 0x812d, lo: 0xb7, hi: 0xb7},
+ {value: 0x812b, lo: 0xb9, hi: 0xb9},
+ // Block 0x26, offset 0xe4
+ {value: 0x0000, lo: 0x10},
+ {value: 0x2644, lo: 0x83, hi: 0x83},
+ {value: 0x264b, lo: 0x8d, hi: 0x8d},
+ {value: 0x2652, lo: 0x92, hi: 0x92},
+ {value: 0x2659, lo: 0x97, hi: 0x97},
+ {value: 0x2660, lo: 0x9c, hi: 0x9c},
+ {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: 0x8128, lo: 0xb4, hi: 0xb4},
+ {value: 0x4a6f, lo: 0xb5, hi: 0xb5},
+ {value: 0x464a, lo: 0xb6, hi: 0xb6},
+ {value: 0x8200, lo: 0xb7, hi: 0xb7},
+ {value: 0x4652, 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: 0x8132, lo: 0x82, hi: 0x83},
+ {value: 0x8104, lo: 0x84, hi: 0x84},
+ {value: 0x8132, lo: 0x86, hi: 0x87},
+ {value: 0x266e, lo: 0x93, hi: 0x93},
+ {value: 0x2675, lo: 0x9d, hi: 0x9d},
+ {value: 0x267c, lo: 0xa2, hi: 0xa2},
+ {value: 0x2683, lo: 0xa7, hi: 0xa7},
+ {value: 0x268a, lo: 0xac, hi: 0xac},
+ {value: 0x2667, lo: 0xb9, hi: 0xb9},
+ // Block 0x28, offset 0x101
+ {value: 0x0000, lo: 0x01},
+ {value: 0x812d, lo: 0x86, hi: 0x86},
+ // Block 0x29, offset 0x103
+ {value: 0x0000, lo: 0x05},
+ {value: 0xa000, lo: 0xa5, hi: 0xa5},
+ {value: 0x2d1e, lo: 0xa6, hi: 0xa6},
+ {value: 0x9900, lo: 0xae, hi: 0xae},
+ {value: 0x8102, lo: 0xb7, hi: 0xb7},
+ {value: 0x8104, lo: 0xb9, hi: 0xba},
+ // Block 0x2a, offset 0x109
+ {value: 0x0000, lo: 0x01},
+ {value: 0x812d, lo: 0x8d, hi: 0x8d},
+ // Block 0x2b, offset 0x10b
+ {value: 0x0000, lo: 0x01},
+ {value: 0xa000, lo: 0x80, hi: 0x92},
+ // Block 0x2c, offset 0x10d
+ {value: 0x0000, lo: 0x01},
+ {value: 0xb900, lo: 0xa1, hi: 0xb5},
+ // Block 0x2d, offset 0x10f
+ {value: 0x0000, lo: 0x01},
+ {value: 0x9900, lo: 0xa8, hi: 0xbf},
+ // Block 0x2e, offset 0x111
+ {value: 0x0000, lo: 0x01},
+ {value: 0x9900, lo: 0x80, hi: 0x82},
+ // Block 0x2f, offset 0x113
+ {value: 0x0000, lo: 0x01},
+ {value: 0x8132, lo: 0x9d, hi: 0x9f},
+ // Block 0x30, offset 0x115
+ {value: 0x0000, lo: 0x02},
+ {value: 0x8104, lo: 0x94, hi: 0x94},
+ {value: 0x8104, lo: 0xb4, hi: 0xb4},
+ // Block 0x31, offset 0x118
+ {value: 0x0000, lo: 0x02},
+ {value: 0x8104, lo: 0x92, hi: 0x92},
+ {value: 0x8132, lo: 0x9d, hi: 0x9d},
+ // Block 0x32, offset 0x11b
+ {value: 0x0000, lo: 0x01},
+ {value: 0x8131, lo: 0xa9, hi: 0xa9},
+ // Block 0x33, offset 0x11d
+ {value: 0x0004, lo: 0x02},
+ {value: 0x812e, lo: 0xb9, hi: 0xba},
+ {value: 0x812d, lo: 0xbb, hi: 0xbb},
+ // Block 0x34, offset 0x120
+ {value: 0x0000, lo: 0x02},
+ {value: 0x8132, lo: 0x97, hi: 0x97},
+ {value: 0x812d, lo: 0x98, hi: 0x98},
+ // Block 0x35, offset 0x123
+ {value: 0x0000, lo: 0x03},
+ {value: 0x8104, lo: 0xa0, hi: 0xa0},
+ {value: 0x8132, lo: 0xb5, hi: 0xbc},
+ {value: 0x812d, lo: 0xbf, hi: 0xbf},
+ // Block 0x36, offset 0x127
+ {value: 0x0000, lo: 0x04},
+ {value: 0x8132, lo: 0xb0, hi: 0xb4},
+ {value: 0x812d, lo: 0xb5, hi: 0xba},
+ {value: 0x8132, lo: 0xbb, hi: 0xbc},
+ {value: 0x812d, lo: 0xbd, hi: 0xbd},
+ // Block 0x37, offset 0x12c
+ {value: 0x0000, lo: 0x08},
+ {value: 0x2d66, lo: 0x80, hi: 0x80},
+ {value: 0x2d6e, lo: 0x81, hi: 0x81},
+ {value: 0xa000, lo: 0x82, hi: 0x82},
+ {value: 0x2d76, lo: 0x83, hi: 0x83},
+ {value: 0x8104, lo: 0x84, hi: 0x84},
+ {value: 0x8132, lo: 0xab, hi: 0xab},
+ {value: 0x812d, lo: 0xac, hi: 0xac},
+ {value: 0x8132, lo: 0xad, hi: 0xb3},
+ // Block 0x38, offset 0x135
+ {value: 0x0000, lo: 0x01},
+ {value: 0x8104, lo: 0xaa, hi: 0xab},
+ // Block 0x39, offset 0x137
+ {value: 0x0000, lo: 0x02},
+ {value: 0x8102, lo: 0xa6, hi: 0xa6},
+ {value: 0x8104, lo: 0xb2, hi: 0xb3},
+ // Block 0x3a, offset 0x13a
+ {value: 0x0000, lo: 0x01},
+ {value: 0x8102, lo: 0xb7, hi: 0xb7},
+ // Block 0x3b, offset 0x13c
+ {value: 0x0000, lo: 0x0a},
+ {value: 0x8132, lo: 0x90, hi: 0x92},
+ {value: 0x8101, lo: 0x94, hi: 0x94},
+ {value: 0x812d, lo: 0x95, hi: 0x99},
+ {value: 0x8132, lo: 0x9a, hi: 0x9b},
+ {value: 0x812d, lo: 0x9c, hi: 0x9f},
+ {value: 0x8132, lo: 0xa0, hi: 0xa0},
+ {value: 0x8101, lo: 0xa2, hi: 0xa8},
+ {value: 0x812d, lo: 0xad, hi: 0xad},
+ {value: 0x8132, lo: 0xb4, hi: 0xb4},
+ {value: 0x8132, lo: 0xb8, hi: 0xb9},
+ // Block 0x3c, offset 0x147
+ {value: 0x0000, lo: 0x0f},
+ {value: 0x8132, lo: 0x80, hi: 0x81},
+ {value: 0x812d, lo: 0x82, hi: 0x82},
+ {value: 0x8132, lo: 0x83, hi: 0x89},
+ {value: 0x812d, lo: 0x8a, hi: 0x8a},
+ {value: 0x8132, lo: 0x8b, hi: 0x8c},
+ {value: 0x8135, lo: 0x8d, hi: 0x8d},
+ {value: 0x812a, lo: 0x8e, hi: 0x8e},
+ {value: 0x812d, lo: 0x8f, hi: 0x8f},
+ {value: 0x8129, lo: 0x90, hi: 0x90},
+ {value: 0x8132, lo: 0x91, hi: 0xb5},
+ {value: 0x8132, lo: 0xbb, hi: 0xbb},
+ {value: 0x8134, lo: 0xbc, hi: 0xbc},
+ {value: 0x812d, lo: 0xbd, hi: 0xbd},
+ {value: 0x8132, lo: 0xbe, hi: 0xbe},
+ {value: 0x812d, lo: 0xbf, hi: 0xbf},
+ // Block 0x3d, offset 0x157
+ {value: 0x0004, lo: 0x03},
+ {value: 0x0433, lo: 0x80, hi: 0x81},
+ {value: 0x8100, lo: 0x97, hi: 0x97},
+ {value: 0x8100, lo: 0xbe, hi: 0xbe},
+ // Block 0x3e, offset 0x15b
+ {value: 0x0000, lo: 0x0d},
+ {value: 0x8132, lo: 0x90, hi: 0x91},
+ {value: 0x8101, lo: 0x92, hi: 0x93},
+ {value: 0x8132, lo: 0x94, hi: 0x97},
+ {value: 0x8101, lo: 0x98, hi: 0x9a},
+ {value: 0x8132, lo: 0x9b, hi: 0x9c},
+ {value: 0x8132, lo: 0xa1, hi: 0xa1},
+ {value: 0x8101, lo: 0xa5, hi: 0xa6},
+ {value: 0x8132, lo: 0xa7, hi: 0xa7},
+ {value: 0x812d, lo: 0xa8, hi: 0xa8},
+ {value: 0x8132, lo: 0xa9, hi: 0xa9},
+ {value: 0x8101, lo: 0xaa, hi: 0xab},
+ {value: 0x812d, lo: 0xac, hi: 0xaf},
+ {value: 0x8132, lo: 0xb0, hi: 0xb0},
+ // Block 0x3f, offset 0x169
+ {value: 0x427b, lo: 0x02},
+ {value: 0x01b8, lo: 0xa6, hi: 0xa6},
+ {value: 0x0057, lo: 0xaa, hi: 0xab},
+ // Block 0x40, offset 0x16c
+ {value: 0x0007, lo: 0x05},
+ {value: 0xa000, lo: 0x90, hi: 0x90},
+ {value: 0xa000, lo: 0x92, hi: 0x92},
+ {value: 0xa000, lo: 0x94, hi: 0x94},
+ {value: 0x3bb9, lo: 0x9a, hi: 0x9b},
+ {value: 0x3bc7, lo: 0xae, hi: 0xae},
+ // Block 0x41, offset 0x172
+ {value: 0x000e, lo: 0x05},
+ {value: 0x3bce, lo: 0x8d, hi: 0x8e},
+ {value: 0x3bd5, lo: 0x8f, hi: 0x8f},
+ {value: 0xa000, lo: 0x90, hi: 0x90},
+ {value: 0xa000, lo: 0x92, hi: 0x92},
+ {value: 0xa000, lo: 0x94, hi: 0x94},
+ // Block 0x42, offset 0x178
+ {value: 0x6408, lo: 0x0a},
+ {value: 0xa000, lo: 0x83, hi: 0x83},
+ {value: 0x3be3, lo: 0x84, hi: 0x84},
+ {value: 0xa000, lo: 0x88, hi: 0x88},
+ {value: 0x3bea, lo: 0x89, hi: 0x89},
+ {value: 0xa000, lo: 0x8b, hi: 0x8b},
+ {value: 0x3bf1, lo: 0x8c, hi: 0x8c},
+ {value: 0xa000, lo: 0xa3, hi: 0xa3},
+ {value: 0x3bf8, lo: 0xa4, hi: 0xa5},
+ {value: 0x3bff, lo: 0xa6, hi: 0xa6},
+ {value: 0xa000, lo: 0xbc, hi: 0xbc},
+ // Block 0x43, offset 0x183
+ {value: 0x0007, lo: 0x03},
+ {value: 0x3c68, lo: 0xa0, hi: 0xa1},
+ {value: 0x3c92, lo: 0xa2, hi: 0xa3},
+ {value: 0x3cbc, lo: 0xaa, hi: 0xad},
+ // Block 0x44, offset 0x187
+ {value: 0x0004, lo: 0x01},
+ {value: 0x048b, lo: 0xa9, hi: 0xaa},
+ // Block 0x45, offset 0x189
+ {value: 0x0000, lo: 0x01},
+ {value: 0x4573, lo: 0x9c, hi: 0x9c},
+ // Block 0x46, offset 0x18b
+ {value: 0x0000, lo: 0x01},
+ {value: 0x8132, lo: 0xaf, hi: 0xb1},
+ // Block 0x47, offset 0x18d
+ {value: 0x0000, lo: 0x01},
+ {value: 0x8104, lo: 0xbf, hi: 0xbf},
+ // Block 0x48, offset 0x18f
+ {value: 0x0000, lo: 0x01},
+ {value: 0x8132, lo: 0xa0, hi: 0xbf},
+ // Block 0x49, offset 0x191
+ {value: 0x0000, lo: 0x05},
+ {value: 0x812c, lo: 0xaa, hi: 0xaa},
+ {value: 0x8131, lo: 0xab, hi: 0xab},
+ {value: 0x8133, lo: 0xac, hi: 0xac},
+ {value: 0x812e, lo: 0xad, hi: 0xad},
+ {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},
+ // Block 0x4b, offset 0x19b
+ {value: 0x0000, lo: 0x01},
+ {value: 0x4a81, lo: 0x8f, hi: 0xa3},
+ // Block 0x4c, offset 0x19d
+ {value: 0x0000, lo: 0x01},
+ {value: 0x8100, lo: 0xae, hi: 0xbe},
+ // Block 0x4d, offset 0x19f
+ {value: 0x0000, lo: 0x07},
+ {value: 0x8100, lo: 0x84, hi: 0x84},
+ {value: 0x8100, lo: 0x87, hi: 0x87},
+ {value: 0x8100, lo: 0x90, hi: 0x90},
+ {value: 0x8100, lo: 0x9e, hi: 0x9e},
+ {value: 0x8100, lo: 0xa1, hi: 0xa1},
+ {value: 0x8100, lo: 0xb2, hi: 0xb2},
+ {value: 0x8100, lo: 0xbb, hi: 0xbb},
+ // Block 0x4e, offset 0x1a7
+ {value: 0x0000, lo: 0x03},
+ {value: 0x8100, lo: 0x80, hi: 0x80},
+ {value: 0x8100, lo: 0x8b, hi: 0x8b},
+ {value: 0x8100, lo: 0x8e, hi: 0x8e},
+ // Block 0x4f, offset 0x1ab
+ {value: 0x0000, lo: 0x02},
+ {value: 0x8132, lo: 0xaf, hi: 0xaf},
+ {value: 0x8132, lo: 0xb4, hi: 0xbd},
+ // Block 0x50, offset 0x1ae
+ {value: 0x0000, lo: 0x01},
+ {value: 0x8132, lo: 0x9e, hi: 0x9f},
+ // Block 0x51, offset 0x1b0
+ {value: 0x0000, lo: 0x01},
+ {value: 0x8132, lo: 0xb0, hi: 0xb1},
+ // Block 0x52, offset 0x1b2
+ {value: 0x0000, lo: 0x01},
+ {value: 0x8104, lo: 0x86, hi: 0x86},
+ // Block 0x53, offset 0x1b4
+ {value: 0x0000, lo: 0x02},
+ {value: 0x8104, lo: 0x84, hi: 0x84},
+ {value: 0x8132, lo: 0xa0, hi: 0xb1},
+ // Block 0x54, offset 0x1b7
+ {value: 0x0000, lo: 0x01},
+ {value: 0x812d, lo: 0xab, hi: 0xad},
+ // Block 0x55, offset 0x1b9
+ {value: 0x0000, lo: 0x01},
+ {value: 0x8104, lo: 0x93, hi: 0x93},
+ // Block 0x56, offset 0x1bb
+ {value: 0x0000, lo: 0x01},
+ {value: 0x8102, lo: 0xb3, hi: 0xb3},
+ // Block 0x57, offset 0x1bd
+ {value: 0x0000, lo: 0x01},
+ {value: 0x8104, lo: 0x80, hi: 0x80},
+ // Block 0x58, offset 0x1bf
+ {value: 0x0000, lo: 0x05},
+ {value: 0x8132, lo: 0xb0, hi: 0xb0},
+ {value: 0x8132, lo: 0xb2, hi: 0xb3},
+ {value: 0x812d, lo: 0xb4, hi: 0xb4},
+ {value: 0x8132, lo: 0xb7, hi: 0xb8},
+ {value: 0x8132, lo: 0xbe, hi: 0xbf},
+ // Block 0x59, offset 0x1c5
+ {value: 0x0000, lo: 0x02},
+ {value: 0x8132, lo: 0x81, hi: 0x81},
+ {value: 0x8104, lo: 0xb6, hi: 0xb6},
+ // Block 0x5a, offset 0x1c8
+ {value: 0x0000, lo: 0x01},
+ {value: 0x8104, lo: 0xad, hi: 0xad},
+ // Block 0x5b, offset 0x1ca
+ {value: 0x0000, lo: 0x06},
+ {value: 0xe500, lo: 0x80, hi: 0x80},
+ {value: 0xc600, lo: 0x81, hi: 0x9b},
+ {value: 0xe500, lo: 0x9c, hi: 0x9c},
+ {value: 0xc600, lo: 0x9d, hi: 0xb7},
+ {value: 0xe500, lo: 0xb8, hi: 0xb8},
+ {value: 0xc600, lo: 0xb9, hi: 0xbf},
+ // Block 0x5c, offset 0x1d1
+ {value: 0x0000, lo: 0x05},
+ {value: 0xc600, lo: 0x80, hi: 0x93},
+ {value: 0xe500, lo: 0x94, hi: 0x94},
+ {value: 0xc600, lo: 0x95, hi: 0xaf},
+ {value: 0xe500, lo: 0xb0, hi: 0xb0},
+ {value: 0xc600, lo: 0xb1, hi: 0xbf},
+ // Block 0x5d, offset 0x1d7
+ {value: 0x0000, lo: 0x05},
+ {value: 0xc600, lo: 0x80, hi: 0x8b},
+ {value: 0xe500, lo: 0x8c, hi: 0x8c},
+ {value: 0xc600, lo: 0x8d, hi: 0xa7},
+ {value: 0xe500, lo: 0xa8, hi: 0xa8},
+ {value: 0xc600, lo: 0xa9, hi: 0xbf},
+ // Block 0x5e, offset 0x1dd
+ {value: 0x0000, lo: 0x07},
+ {value: 0xc600, lo: 0x80, hi: 0x83},
+ {value: 0xe500, lo: 0x84, hi: 0x84},
+ {value: 0xc600, lo: 0x85, hi: 0x9f},
+ {value: 0xe500, lo: 0xa0, hi: 0xa0},
+ {value: 0xc600, lo: 0xa1, hi: 0xbb},
+ {value: 0xe500, lo: 0xbc, hi: 0xbc},
+ {value: 0xc600, lo: 0xbd, hi: 0xbf},
+ // Block 0x5f, offset 0x1e5
+ {value: 0x0000, lo: 0x05},
+ {value: 0xc600, lo: 0x80, hi: 0x97},
+ {value: 0xe500, lo: 0x98, hi: 0x98},
+ {value: 0xc600, lo: 0x99, hi: 0xb3},
+ {value: 0xe500, lo: 0xb4, hi: 0xb4},
+ {value: 0xc600, lo: 0xb5, hi: 0xbf},
+ // Block 0x60, offset 0x1eb
+ {value: 0x0000, lo: 0x05},
+ {value: 0xc600, lo: 0x80, hi: 0x8f},
+ {value: 0xe500, lo: 0x90, hi: 0x90},
+ {value: 0xc600, lo: 0x91, hi: 0xab},
+ {value: 0xe500, lo: 0xac, hi: 0xac},
+ {value: 0xc600, lo: 0xad, hi: 0xbf},
+ // Block 0x61, offset 0x1f1
+ {value: 0x0000, lo: 0x05},
+ {value: 0xc600, lo: 0x80, hi: 0x87},
+ {value: 0xe500, lo: 0x88, hi: 0x88},
+ {value: 0xc600, lo: 0x89, hi: 0xa3},
+ {value: 0xe500, lo: 0xa4, hi: 0xa4},
+ {value: 0xc600, lo: 0xa5, hi: 0xbf},
+ // Block 0x62, offset 0x1f7
+ {value: 0x0000, lo: 0x03},
+ {value: 0xc600, lo: 0x80, hi: 0x87},
+ {value: 0xe500, lo: 0x88, hi: 0x88},
+ {value: 0xc600, lo: 0x89, hi: 0xa3},
+ // Block 0x63, offset 0x1fb
+ {value: 0x0006, lo: 0x0d},
+ {value: 0x4426, 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},
+ // 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},
+ // Block 0x65, offset 0x212
+ {value: 0x0000, lo: 0x02},
+ {value: 0x8100, lo: 0xa4, hi: 0xa5},
+ {value: 0x8100, lo: 0xb0, hi: 0xb1},
+ // Block 0x66, offset 0x215
+ {value: 0x0000, lo: 0x02},
+ {value: 0x8100, lo: 0x9b, hi: 0x9d},
+ {value: 0x8200, lo: 0x9e, hi: 0xa3},
+ // Block 0x67, offset 0x218
+ {value: 0x0000, lo: 0x01},
+ {value: 0x8100, lo: 0x90, hi: 0x90},
+ // Block 0x68, offset 0x21a
+ {value: 0x0000, lo: 0x02},
+ {value: 0x8100, lo: 0x99, hi: 0x99},
+ {value: 0x8200, lo: 0xb2, hi: 0xb4},
+ // Block 0x69, offset 0x21d
+ {value: 0x0000, lo: 0x01},
+ {value: 0x8100, lo: 0xbc, hi: 0xbd},
+ // Block 0x6a, offset 0x21f
+ {value: 0x0000, lo: 0x03},
+ {value: 0x8132, lo: 0xa0, hi: 0xa6},
+ {value: 0x812d, lo: 0xa7, hi: 0xad},
+ {value: 0x8132, lo: 0xae, hi: 0xaf},
+ // Block 0x6b, offset 0x223
+ {value: 0x0000, lo: 0x04},
+ {value: 0x8100, lo: 0x89, hi: 0x8c},
+ {value: 0x8100, lo: 0xb0, hi: 0xb2},
+ {value: 0x8100, lo: 0xb4, hi: 0xb4},
+ {value: 0x8100, lo: 0xb6, hi: 0xbf},
+ // Block 0x6c, offset 0x228
+ {value: 0x0000, lo: 0x01},
+ {value: 0x8100, lo: 0x81, hi: 0x8c},
+ // Block 0x6d, offset 0x22a
+ {value: 0x0000, lo: 0x01},
+ {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},
+ // 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: 0x8100, lo: 0xa3, hi: 0xa3},
+ // Block 0x70, offset 0x237
+ {value: 0x0000, lo: 0x01},
+ {value: 0x812d, lo: 0xbd, hi: 0xbd},
+ // Block 0x71, offset 0x239
+ {value: 0x0000, lo: 0x01},
+ {value: 0x812d, lo: 0xa0, hi: 0xa0},
+ // Block 0x72, offset 0x23b
+ {value: 0x0000, lo: 0x01},
+ {value: 0x8132, lo: 0xb6, hi: 0xba},
+ // Block 0x73, offset 0x23d
+ {value: 0x002c, lo: 0x05},
+ {value: 0x812d, lo: 0x8d, hi: 0x8d},
+ {value: 0x8132, lo: 0x8f, hi: 0x8f},
+ {value: 0x8132, lo: 0xb8, hi: 0xb8},
+ {value: 0x8101, lo: 0xb9, hi: 0xba},
+ {value: 0x8104, lo: 0xbf, hi: 0xbf},
+ // Block 0x74, offset 0x243
+ {value: 0x0000, lo: 0x02},
+ {value: 0x8132, lo: 0xa5, hi: 0xa5},
+ {value: 0x812d, lo: 0xa6, hi: 0xa6},
+ // Block 0x75, offset 0x246
+ {value: 0x0000, lo: 0x02},
+ {value: 0x8104, lo: 0x86, hi: 0x86},
+ {value: 0x8104, lo: 0xbf, hi: 0xbf},
+ // Block 0x76, offset 0x249
+ {value: 0x17fe, lo: 0x07},
+ {value: 0xa000, lo: 0x99, hi: 0x99},
+ {value: 0x4238, lo: 0x9a, hi: 0x9a},
+ {value: 0xa000, lo: 0x9b, hi: 0x9b},
+ {value: 0x4242, lo: 0x9c, hi: 0x9c},
+ {value: 0xa000, lo: 0xa5, hi: 0xa5},
+ {value: 0x424c, lo: 0xab, hi: 0xab},
+ {value: 0x8104, lo: 0xb9, hi: 0xba},
+ // Block 0x77, offset 0x251
+ {value: 0x0000, lo: 0x06},
+ {value: 0x8132, lo: 0x80, hi: 0x82},
+ {value: 0x9900, lo: 0xa7, hi: 0xa7},
+ {value: 0x2d7e, lo: 0xae, hi: 0xae},
+ {value: 0x2d88, lo: 0xaf, hi: 0xaf},
+ {value: 0xa000, lo: 0xb1, hi: 0xb2},
+ {value: 0x8104, lo: 0xb3, hi: 0xb4},
+ // Block 0x78, offset 0x258
+ {value: 0x0000, lo: 0x02},
+ {value: 0x8104, lo: 0x80, hi: 0x80},
+ {value: 0x8102, lo: 0x8a, hi: 0x8a},
+ // Block 0x79, offset 0x25b
+ {value: 0x0000, lo: 0x02},
+ {value: 0x8104, lo: 0xb5, hi: 0xb5},
+ {value: 0x8102, lo: 0xb6, hi: 0xb6},
+ // Block 0x7a, offset 0x25e
+ {value: 0x0002, lo: 0x01},
+ {value: 0x8102, lo: 0xa9, hi: 0xaa},
+ // Block 0x7b, offset 0x260
+ {value: 0x0000, lo: 0x07},
+ {value: 0xa000, lo: 0x87, hi: 0x87},
+ {value: 0x2d92, lo: 0x8b, hi: 0x8b},
+ {value: 0x2d9c, lo: 0x8c, hi: 0x8c},
+ {value: 0x8104, lo: 0x8d, hi: 0x8d},
+ {value: 0x9900, lo: 0x97, hi: 0x97},
+ {value: 0x8132, lo: 0xa6, hi: 0xac},
+ {value: 0x8132, lo: 0xb0, hi: 0xb4},
+ // Block 0x7c, offset 0x268
+ {value: 0x0000, lo: 0x02},
+ {value: 0x8104, lo: 0x82, hi: 0x82},
+ {value: 0x8102, lo: 0x86, hi: 0x86},
+ // Block 0x7d, offset 0x26b
+ {value: 0x6b5a, lo: 0x06},
+ {value: 0x9900, lo: 0xb0, hi: 0xb0},
+ {value: 0xa000, lo: 0xb9, hi: 0xb9},
+ {value: 0x9900, lo: 0xba, hi: 0xba},
+ {value: 0x2db0, lo: 0xbb, hi: 0xbb},
+ {value: 0x2da6, lo: 0xbc, hi: 0xbd},
+ {value: 0x2dba, lo: 0xbe, hi: 0xbe},
+ // Block 0x7e, offset 0x272
+ {value: 0x0000, lo: 0x02},
+ {value: 0x8104, lo: 0x82, hi: 0x82},
+ {value: 0x8102, lo: 0x83, hi: 0x83},
+ // Block 0x7f, offset 0x275
+ {value: 0x0000, lo: 0x05},
+ {value: 0x9900, lo: 0xaf, hi: 0xaf},
+ {value: 0xa000, lo: 0xb8, hi: 0xb9},
+ {value: 0x2dc4, lo: 0xba, hi: 0xba},
+ {value: 0x2dce, lo: 0xbb, hi: 0xbb},
+ {value: 0x8104, lo: 0xbf, hi: 0xbf},
+ // Block 0x80, offset 0x27b
+ {value: 0x0000, lo: 0x01},
+ {value: 0x8102, lo: 0x80, hi: 0x80},
+ // Block 0x81, offset 0x27d
+ {value: 0x0000, lo: 0x02},
+ {value: 0x8104, lo: 0xb6, hi: 0xb6},
+ {value: 0x8102, lo: 0xb7, hi: 0xb7},
+ // Block 0x82, offset 0x280
+ {value: 0x0000, lo: 0x01},
+ {value: 0x8104, lo: 0xab, hi: 0xab},
+ // Block 0x83, offset 0x282
+ {value: 0x0000, lo: 0x01},
+ {value: 0x8101, lo: 0xb0, hi: 0xb4},
+ // Block 0x84, offset 0x284
+ {value: 0x0000, lo: 0x01},
+ {value: 0x8132, lo: 0xb0, hi: 0xb6},
+ // Block 0x85, offset 0x286
+ {value: 0x0000, lo: 0x01},
+ {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: 0x812b, lo: 0xa5, hi: 0xa6},
+ {value: 0x8101, lo: 0xa7, hi: 0xa9},
+ {value: 0x8130, lo: 0xad, hi: 0xad},
+ {value: 0x812b, lo: 0xae, hi: 0xb2},
+ {value: 0x812d, lo: 0xbb, hi: 0xbf},
+ // Block 0x87, offset 0x295
+ {value: 0x0000, lo: 0x09},
+ {value: 0x812d, lo: 0x80, hi: 0x82},
+ {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},
+ // Block 0x88, offset 0x29f
+ {value: 0x0000, lo: 0x01},
+ {value: 0x4710, lo: 0x80, hi: 0x80},
+ // Block 0x89, offset 0x2a1
+ {value: 0x0000, lo: 0x01},
+ {value: 0x8132, lo: 0x82, hi: 0x84},
+ // Block 0x8a, offset 0x2a3
+ {value: 0x0000, lo: 0x05},
+ {value: 0x8132, lo: 0x80, hi: 0x86},
+ {value: 0x8132, lo: 0x88, hi: 0x98},
+ {value: 0x8132, lo: 0x9b, hi: 0xa1},
+ {value: 0x8132, lo: 0xa3, hi: 0xa4},
+ {value: 0x8132, lo: 0xa6, hi: 0xaa},
+ // Block 0x8b, offset 0x2a9
+ {value: 0x0000, lo: 0x01},
+ {value: 0x812d, lo: 0x90, hi: 0x96},
+ // Block 0x8c, offset 0x2ab
+ {value: 0x0000, lo: 0x02},
+ {value: 0x8132, lo: 0x84, hi: 0x89},
+ {value: 0x8102, lo: 0x8a, hi: 0x8a},
+ // Block 0x8d, offset 0x2ae
+ {value: 0x0000, lo: 0x01},
+ {value: 0x8100, lo: 0x93, hi: 0x93},
+}
+
+// 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 *nfkcTrie) lookup(s []byte) (v uint16, sz int) {
+ c0 := s[0]
+ switch {
+ case c0 < 0x80: // is ASCII
+ return nfkcValues[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 := nfkcIndex[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 := nfkcIndex[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 = nfkcIndex[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 := nfkcIndex[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 = nfkcIndex[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 = nfkcIndex[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 *nfkcTrie) lookupUnsafe(s []byte) uint16 {
+ c0 := s[0]
+ if c0 < 0x80 { // is ASCII
+ return nfkcValues[c0]
+ }
+ i := nfkcIndex[c0]
+ if c0 < 0xE0 { // 2-byte UTF-8
+ return t.lookupValue(uint32(i), s[1])
+ }
+ i = nfkcIndex[uint32(i)<<6+uint32(s[1])]
+ if c0 < 0xF0 { // 3-byte UTF-8
+ return t.lookupValue(uint32(i), s[2])
+ }
+ i = nfkcIndex[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 *nfkcTrie) lookupString(s string) (v uint16, sz int) {
+ c0 := s[0]
+ switch {
+ case c0 < 0x80: // is ASCII
+ return nfkcValues[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 := nfkcIndex[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 := nfkcIndex[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 = nfkcIndex[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 := nfkcIndex[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 = nfkcIndex[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 = nfkcIndex[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 *nfkcTrie) lookupStringUnsafe(s string) uint16 {
+ c0 := s[0]
+ if c0 < 0x80 { // is ASCII
+ return nfkcValues[c0]
+ }
+ i := nfkcIndex[c0]
+ if c0 < 0xE0 { // 2-byte UTF-8
+ return t.lookupValue(uint32(i), s[1])
+ }
+ i = nfkcIndex[uint32(i)<<6+uint32(s[1])]
+ if c0 < 0xF0 { // 3-byte UTF-8
+ return t.lookupValue(uint32(i), s[2])
+ }
+ i = nfkcIndex[uint32(i)<<6+uint32(s[2])]
+ if c0 < 0xF8 { // 4-byte UTF-8
+ return t.lookupValue(uint32(i), s[3])
+ }
+ return 0
+}
+
+// nfkcTrie. Total size: 16994 bytes (16.60 KiB). Checksum: 146925fc21092b17.
+type nfkcTrie struct{}
+
+func newNfkcTrie(i int) *nfkcTrie {
+ return &nfkcTrie{}
+}
+
+// lookupValue determines the type of block n and looks up the value for b.
+func (t *nfkcTrie) lookupValue(n uint32, b byte) uint16 {
+ switch {
+ case n < 90:
+ return uint16(nfkcValues[n<<6+uint32(b)])
+ default:
+ n -= 90
+ return uint16(nfkcSparse.lookup(n, b))
+ }
+}
+
+// nfkcValues: 92 blocks, 5888 entries, 11776 bytes
+// The third block is the zero block.
+var nfkcValues = [5888]uint16{
+ // Block 0x0, offset 0x0
+ 0x3c: 0xa000, 0x3d: 0xa000, 0x3e: 0xa000,
+ // Block 0x1, offset 0x40
+ 0x41: 0xa000, 0x42: 0xa000, 0x43: 0xa000, 0x44: 0xa000, 0x45: 0xa000,
+ 0x46: 0xa000, 0x47: 0xa000, 0x48: 0xa000, 0x49: 0xa000, 0x4a: 0xa000, 0x4b: 0xa000,
+ 0x4c: 0xa000, 0x4d: 0xa000, 0x4e: 0xa000, 0x4f: 0xa000, 0x50: 0xa000,
+ 0x52: 0xa000, 0x53: 0xa000, 0x54: 0xa000, 0x55: 0xa000, 0x56: 0xa000, 0x57: 0xa000,
+ 0x58: 0xa000, 0x59: 0xa000, 0x5a: 0xa000,
+ 0x61: 0xa000, 0x62: 0xa000, 0x63: 0xa000,
+ 0x64: 0xa000, 0x65: 0xa000, 0x66: 0xa000, 0x67: 0xa000, 0x68: 0xa000, 0x69: 0xa000,
+ 0x6a: 0xa000, 0x6b: 0xa000, 0x6c: 0xa000, 0x6d: 0xa000, 0x6e: 0xa000, 0x6f: 0xa000,
+ 0x70: 0xa000, 0x72: 0xa000, 0x73: 0xa000, 0x74: 0xa000, 0x75: 0xa000,
+ 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,
+ // Block 0x4, offset 0x100
+ 0x100: 0x2f7e, 0x101: 0x328a, 0x102: 0x4723, 0x103: 0x47b4, 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,
+ 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,
+ 0x12a: 0x3082, 0x12b: 0x3393, 0x12c: 0x3087, 0x12d: 0x3398, 0x12e: 0x30aa, 0x12f: 0x33b6,
+ 0x130: 0x308c, 0x132: 0x195d, 0x133: 0x19e7, 0x134: 0x30b4, 0x135: 0x33c0,
+ 0x136: 0x30c8, 0x137: 0x33d9, 0x139: 0x30d2, 0x13a: 0x33e3, 0x13b: 0x30dc,
+ 0x13c: 0x33ed, 0x13d: 0x30d7, 0x13e: 0x33e8, 0x13f: 0x1bac,
+ // 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,
+ 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,
+ 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,
+ // Block 0x6, offset 0x180
+ 0x184: 0x2dee, 0x185: 0x2df4,
+ 0x186: 0x2dfa, 0x187: 0x1972, 0x188: 0x1975, 0x189: 0x1a08, 0x18a: 0x1987, 0x18b: 0x198a,
+ 0x18c: 0x1a3e, 0x18d: 0x2f88, 0x18e: 0x3294, 0x18f: 0x3096, 0x190: 0x33a2, 0x191: 0x3140,
+ 0x192: 0x3451, 0x193: 0x31d6, 0x194: 0x34ec, 0x195: 0x39cf, 0x196: 0x3b5e, 0x197: 0x39c8,
+ 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,
+ 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,
+ // Block 0x7, offset 0x1c0
+ 0x1c0: 0x2f8d, 0x1c1: 0x3299, 0x1c2: 0x2f92, 0x1c3: 0x329e, 0x1c4: 0x300a, 0x1c5: 0x3316,
+ 0x1c6: 0x300f, 0x1c7: 0x331b, 0x1c8: 0x309b, 0x1c9: 0x33a7, 0x1ca: 0x30a0, 0x1cb: 0x33ac,
+ 0x1cc: 0x3145, 0x1cd: 0x3456, 0x1ce: 0x314a, 0x1cf: 0x345b, 0x1d0: 0x3168, 0x1d1: 0x3479,
+ 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,
+ 0x1f0: 0x3958, 0x1f1: 0x3ae7, 0x1f2: 0x3244, 0x1f3: 0x355f,
+ // Block 0x8, offset 0x200
+ 0x200: 0x9932, 0x201: 0x9932, 0x202: 0x9932, 0x203: 0x9932, 0x204: 0x9932, 0x205: 0x8132,
+ 0x206: 0x9932, 0x207: 0x9932, 0x208: 0x9932, 0x209: 0x9932, 0x20a: 0x9932, 0x20b: 0x9932,
+ 0x20c: 0x9932, 0x20d: 0x8132, 0x20e: 0x8132, 0x20f: 0x9932, 0x210: 0x8132, 0x211: 0x9932,
+ 0x212: 0x8132, 0x213: 0x9932, 0x214: 0x9932, 0x215: 0x8133, 0x216: 0x812d, 0x217: 0x812d,
+ 0x218: 0x812d, 0x219: 0x812d, 0x21a: 0x8133, 0x21b: 0x992b, 0x21c: 0x812d, 0x21d: 0x812d,
+ 0x21e: 0x812d, 0x21f: 0x812d, 0x220: 0x812d, 0x221: 0x8129, 0x222: 0x8129, 0x223: 0x992d,
+ 0x224: 0x992d, 0x225: 0x992d, 0x226: 0x992d, 0x227: 0x9929, 0x228: 0x9929, 0x229: 0x812d,
+ 0x22a: 0x812d, 0x22b: 0x812d, 0x22c: 0x812d, 0x22d: 0x992d, 0x22e: 0x992d, 0x22f: 0x812d,
+ 0x230: 0x992d, 0x231: 0x992d, 0x232: 0x812d, 0x233: 0x812d, 0x234: 0x8101, 0x235: 0x8101,
+ 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,
+ 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,
+ 0x258: 0x8133, 0x259: 0x812d, 0x25a: 0x812d, 0x25b: 0x8132, 0x25c: 0x8134, 0x25d: 0x8135,
+ 0x25e: 0x8135, 0x25f: 0x8134, 0x260: 0x8135, 0x261: 0x8135, 0x262: 0x8134, 0x263: 0x8132,
+ 0x264: 0x8132, 0x265: 0x8132, 0x266: 0x8132, 0x267: 0x8132, 0x268: 0x8132, 0x269: 0x8132,
+ 0x26a: 0x8132, 0x26b: 0x8132, 0x26c: 0x8132, 0x26d: 0x8132, 0x26e: 0x8132, 0x26f: 0x8132,
+ 0x274: 0x0170,
+ 0x27a: 0x42a5,
+ 0x27e: 0x0037,
+ // Block 0xa, offset 0x280
+ 0x284: 0x425a, 0x285: 0x4511,
+ 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,
+ 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,
+ 0x2f0: 0x01d6, 0x2f1: 0x01eb, 0x2f2: 0x01ee, 0x2f4: 0x0188, 0x2f5: 0x01c7,
+ 0x2f9: 0x01a6,
+ // Block 0xc, offset 0x300
+ 0x300: 0x3721, 0x301: 0x372d, 0x303: 0x371b,
+ 0x306: 0xa000, 0x307: 0x3709,
+ 0x30c: 0x375d, 0x30d: 0x3745, 0x30e: 0x376f, 0x310: 0xa000,
+ 0x313: 0xa000, 0x315: 0xa000, 0x316: 0xa000, 0x317: 0xa000,
+ 0x318: 0xa000, 0x319: 0x3751, 0x31a: 0xa000,
+ 0x31e: 0xa000, 0x323: 0xa000,
+ 0x327: 0xa000,
+ 0x32b: 0xa000, 0x32d: 0xa000,
+ 0x330: 0xa000, 0x333: 0xa000, 0x335: 0xa000,
+ 0x336: 0xa000, 0x337: 0xa000, 0x338: 0xa000, 0x339: 0x37d5, 0x33a: 0xa000,
+ 0x33e: 0xa000,
+ // Block 0xd, offset 0x340
+ 0x341: 0x3733, 0x342: 0x37b7,
+ 0x350: 0x370f, 0x351: 0x3793,
+ 0x352: 0x3715, 0x353: 0x3799, 0x356: 0x3727, 0x357: 0x37ab,
+ 0x358: 0xa000, 0x359: 0xa000, 0x35a: 0x3829, 0x35b: 0x382f, 0x35c: 0x3739, 0x35d: 0x37bd,
+ 0x35e: 0x373f, 0x35f: 0x37c3, 0x362: 0x374b, 0x363: 0x37cf,
+ 0x364: 0x3757, 0x365: 0x37db, 0x366: 0x3763, 0x367: 0x37e7, 0x368: 0xa000, 0x369: 0xa000,
+ 0x36a: 0x3835, 0x36b: 0x383b, 0x36c: 0x378d, 0x36d: 0x3811, 0x36e: 0x3769, 0x36f: 0x37ed,
+ 0x370: 0x3775, 0x371: 0x37f9, 0x372: 0x377b, 0x373: 0x37ff, 0x374: 0x3781, 0x375: 0x3805,
+ 0x378: 0x3787, 0x379: 0x380b,
+ // Block 0xe, offset 0x380
+ 0x387: 0x1d61,
+ 0x391: 0x812d,
+ 0x392: 0x8132, 0x393: 0x8132, 0x394: 0x8132, 0x395: 0x8132, 0x396: 0x812d, 0x397: 0x8132,
+ 0x398: 0x8132, 0x399: 0x8132, 0x39a: 0x812e, 0x39b: 0x812d, 0x39c: 0x8132, 0x39d: 0x8132,
+ 0x39e: 0x8132, 0x39f: 0x8132, 0x3a0: 0x8132, 0x3a1: 0x8132, 0x3a2: 0x812d, 0x3a3: 0x812d,
+ 0x3a4: 0x812d, 0x3a5: 0x812d, 0x3a6: 0x812d, 0x3a7: 0x812d, 0x3a8: 0x8132, 0x3a9: 0x8132,
+ 0x3aa: 0x812d, 0x3ab: 0x8132, 0x3ac: 0x8132, 0x3ad: 0x812e, 0x3ae: 0x8131, 0x3af: 0x8132,
+ 0x3b0: 0x8105, 0x3b1: 0x8106, 0x3b2: 0x8107, 0x3b3: 0x8108, 0x3b4: 0x8109, 0x3b5: 0x810a,
+ 0x3b6: 0x810b, 0x3b7: 0x810c, 0x3b8: 0x810d, 0x3b9: 0x810e, 0x3ba: 0x810e, 0x3bb: 0x810f,
+ 0x3bc: 0x8110, 0x3bd: 0x8111, 0x3bf: 0x8112,
+ // Block 0xf, offset 0x3c0
+ 0x3c8: 0xa000, 0x3ca: 0xa000, 0x3cb: 0x8116,
+ 0x3cc: 0x8117, 0x3cd: 0x8118, 0x3ce: 0x8119, 0x3cf: 0x811a, 0x3d0: 0x811b, 0x3d1: 0x811c,
+ 0x3d2: 0x811d, 0x3d3: 0x9932, 0x3d4: 0x9932, 0x3d5: 0x992d, 0x3d6: 0x812d, 0x3d7: 0x8132,
+ 0x3d8: 0x8132, 0x3d9: 0x8132, 0x3da: 0x8132, 0x3db: 0x8132, 0x3dc: 0x812d, 0x3dd: 0x8132,
+ 0x3de: 0x8132, 0x3df: 0x812d,
+ 0x3f0: 0x811e, 0x3f5: 0x1d84,
+ 0x3f6: 0x2013, 0x3f7: 0x204f, 0x3f8: 0x204a,
+ // Block 0x10, offset 0x400
+ 0x405: 0xa000,
+ 0x406: 0x2d26, 0x407: 0xa000, 0x408: 0x2d2e, 0x409: 0xa000, 0x40a: 0x2d36, 0x40b: 0xa000,
+ 0x40c: 0x2d3e, 0x40d: 0xa000, 0x40e: 0x2d46, 0x411: 0xa000,
+ 0x412: 0x2d4e,
+ 0x434: 0x8102, 0x435: 0x9900,
+ 0x43a: 0xa000, 0x43b: 0x2d56,
+ 0x43c: 0xa000, 0x43d: 0x2d5e, 0x43e: 0xa000, 0x43f: 0xa000,
+ // Block 0x11, offset 0x440
+ 0x440: 0x0069, 0x441: 0x006b, 0x442: 0x006f, 0x443: 0x0083, 0x444: 0x00f5, 0x445: 0x00f8,
+ 0x446: 0x0413, 0x447: 0x0085, 0x448: 0x0089, 0x449: 0x008b, 0x44a: 0x0104, 0x44b: 0x0107,
+ 0x44c: 0x010a, 0x44d: 0x008f, 0x44f: 0x0097, 0x450: 0x009b, 0x451: 0x00e0,
+ 0x452: 0x009f, 0x453: 0x00fe, 0x454: 0x0417, 0x455: 0x041b, 0x456: 0x00a1, 0x457: 0x00a9,
+ 0x458: 0x00ab, 0x459: 0x0423, 0x45a: 0x012b, 0x45b: 0x00ad, 0x45c: 0x0427, 0x45d: 0x01be,
+ 0x45e: 0x01c1, 0x45f: 0x01c4, 0x460: 0x01fa, 0x461: 0x01fd, 0x462: 0x0093, 0x463: 0x00a5,
+ 0x464: 0x00ab, 0x465: 0x00ad, 0x466: 0x01be, 0x467: 0x01c1, 0x468: 0x01eb, 0x469: 0x01fa,
+ 0x46a: 0x01fd,
+ 0x478: 0x020c,
+ // Block 0x12, offset 0x480
+ 0x49b: 0x00fb, 0x49c: 0x0087, 0x49d: 0x0101,
+ 0x49e: 0x00d4, 0x49f: 0x010a, 0x4a0: 0x008d, 0x4a1: 0x010d, 0x4a2: 0x0110, 0x4a3: 0x0116,
+ 0x4a4: 0x011c, 0x4a5: 0x011f, 0x4a6: 0x0122, 0x4a7: 0x042b, 0x4a8: 0x016a, 0x4a9: 0x0128,
+ 0x4aa: 0x042f, 0x4ab: 0x016d, 0x4ac: 0x0131, 0x4ad: 0x012e, 0x4ae: 0x0134, 0x4af: 0x0137,
+ 0x4b0: 0x013a, 0x4b1: 0x013d, 0x4b2: 0x0140, 0x4b3: 0x014c, 0x4b4: 0x014f, 0x4b5: 0x00ec,
+ 0x4b6: 0x0152, 0x4b7: 0x0155, 0x4b8: 0x041f, 0x4b9: 0x0158, 0x4ba: 0x015b, 0x4bb: 0x00b5,
+ 0x4bc: 0x015e, 0x4bd: 0x0161, 0x4be: 0x0164, 0x4bf: 0x01d0,
+ // Block 0x13, offset 0x4c0
+ 0x4c0: 0x2f97, 0x4c1: 0x32a3, 0x4c2: 0x2fa1, 0x4c3: 0x32ad, 0x4c4: 0x2fa6, 0x4c5: 0x32b2,
+ 0x4c6: 0x2fab, 0x4c7: 0x32b7, 0x4c8: 0x38cc, 0x4c9: 0x3a5b, 0x4ca: 0x2fc4, 0x4cb: 0x32d0,
+ 0x4cc: 0x2fce, 0x4cd: 0x32da, 0x4ce: 0x2fdd, 0x4cf: 0x32e9, 0x4d0: 0x2fd3, 0x4d1: 0x32df,
+ 0x4d2: 0x2fd8, 0x4d3: 0x32e4, 0x4d4: 0x38ef, 0x4d5: 0x3a7e, 0x4d6: 0x38f6, 0x4d7: 0x3a85,
+ 0x4d8: 0x3019, 0x4d9: 0x3325, 0x4da: 0x301e, 0x4db: 0x332a, 0x4dc: 0x3904, 0x4dd: 0x3a93,
+ 0x4de: 0x3023, 0x4df: 0x332f, 0x4e0: 0x3032, 0x4e1: 0x333e, 0x4e2: 0x3050, 0x4e3: 0x335c,
+ 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,
+ 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,
+ 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,
+ 0x536: 0x31f4, 0x537: 0x350a, 0x538: 0x39b3, 0x539: 0x3b42, 0x53a: 0x39ba, 0x53b: 0x3b49,
+ 0x53c: 0x31fe, 0x53d: 0x3514, 0x53e: 0x3203, 0x53f: 0x3519,
+ // Block 0x15, offset 0x540
+ 0x540: 0x3208, 0x541: 0x351e, 0x542: 0x320d, 0x543: 0x3523, 0x544: 0x321c, 0x545: 0x3532,
+ 0x546: 0x3217, 0x547: 0x352d, 0x548: 0x3221, 0x549: 0x353c, 0x54a: 0x3226, 0x54b: 0x3541,
+ 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,
+ 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,
+ 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,
+ 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,
+ 0x5a4: 0x31e5, 0x5a5: 0x34fb, 0x5a6: 0x31c7, 0x5a7: 0x34dd, 0x5a8: 0x39e4, 0x5a9: 0x3b73,
+ 0x5aa: 0x39dd, 0x5ab: 0x3b6c, 0x5ac: 0x39f2, 0x5ad: 0x3b81, 0x5ae: 0x39eb, 0x5af: 0x3b7a,
+ 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,
+ 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,
+ 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,
+ 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,
+ // 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,
+ 0x64c: 0x40da, 0x64d: 0x40f8, 0x64e: 0x40e4, 0x64f: 0x4102, 0x650: 0x3de8, 0x651: 0x3df0,
+ 0x652: 0x41c0, 0x653: 0x41de, 0x654: 0x41ca, 0x655: 0x41e8, 0x656: 0x41d4, 0x657: 0x41f2,
+ 0x658: 0x3d08, 0x659: 0x3d10, 0x65a: 0x410c, 0x65b: 0x412a, 0x65c: 0x4116, 0x65d: 0x4134,
+ 0x65e: 0x4120, 0x65f: 0x413e, 0x660: 0x3ec0, 0x661: 0x3ec8, 0x662: 0x41fc, 0x663: 0x421a,
+ 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,
+ 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,
+ 0x6a4: 0x36cd, 0x6a5: 0x36d3, 0x6a6: 0x36f1, 0x6a7: 0x3e78, 0x6a8: 0x3661, 0x6a9: 0x365b,
+ 0x6aa: 0x364f, 0x6ab: 0x43a2, 0x6ac: 0x3649, 0x6ad: 0x450a, 0x6ae: 0x4511, 0x6af: 0x0081,
+ 0x6b2: 0x3eb0, 0x6b3: 0x36f7, 0x6b4: 0x3eb8,
+ 0x6b6: 0x491e, 0x6b7: 0x3ed0, 0x6b8: 0x363d, 0x6b9: 0x439c, 0x6ba: 0x366d, 0x6bb: 0x43ae,
+ 0x6bc: 0x3679, 0x6bd: 0x425a, 0x6be: 0x428c,
+ // Block 0x1b, offset 0x6c0
+ 0x6c0: 0x1bd8, 0x6c1: 0x1bdc, 0x6c2: 0x0047, 0x6c3: 0x1c54, 0x6c5: 0x1be8,
+ 0x6c6: 0x1bec, 0x6c7: 0x00e9, 0x6c9: 0x1c58, 0x6ca: 0x008f, 0x6cb: 0x0051,
+ 0x6cc: 0x0051, 0x6cd: 0x0051, 0x6ce: 0x0091, 0x6cf: 0x00da, 0x6d0: 0x0053, 0x6d1: 0x0053,
+ 0x6d2: 0x0059, 0x6d3: 0x0099, 0x6d5: 0x005d, 0x6d6: 0x198d,
+ 0x6d9: 0x0061, 0x6da: 0x0063, 0x6db: 0x0065, 0x6dc: 0x0065, 0x6dd: 0x0065,
+ 0x6e0: 0x199f, 0x6e1: 0x1bc8, 0x6e2: 0x19a8,
+ 0x6e4: 0x0075, 0x6e6: 0x01b8, 0x6e8: 0x0075,
+ 0x6ea: 0x0057, 0x6eb: 0x42d2, 0x6ec: 0x0045, 0x6ed: 0x0047, 0x6ef: 0x008b,
+ 0x6f0: 0x004b, 0x6f1: 0x004d, 0x6f3: 0x005b, 0x6f4: 0x009f, 0x6f5: 0x0215,
+ 0x6f6: 0x0218, 0x6f7: 0x021b, 0x6f8: 0x021e, 0x6f9: 0x0093, 0x6fb: 0x1b98,
+ 0x6fc: 0x01e8, 0x6fd: 0x01c1, 0x6fe: 0x0179, 0x6ff: 0x01a0,
+ // Block 0x1c, offset 0x700
+ 0x700: 0x0463, 0x705: 0x0049,
+ 0x706: 0x0089, 0x707: 0x008b, 0x708: 0x0093, 0x709: 0x0095,
+ 0x710: 0x222e, 0x711: 0x223a,
+ 0x712: 0x22ee, 0x713: 0x2216, 0x714: 0x229a, 0x715: 0x2222, 0x716: 0x22a0, 0x717: 0x22b8,
+ 0x718: 0x22c4, 0x719: 0x2228, 0x71a: 0x22ca, 0x71b: 0x2234, 0x71c: 0x22be, 0x71d: 0x22d0,
+ 0x71e: 0x22d6, 0x71f: 0x1cbc, 0x720: 0x0053, 0x721: 0x195a, 0x722: 0x1ba4, 0x723: 0x1963,
+ 0x724: 0x006d, 0x725: 0x19ab, 0x726: 0x1bd0, 0x727: 0x1d48, 0x728: 0x1966, 0x729: 0x0071,
+ 0x72a: 0x19b7, 0x72b: 0x1bd4, 0x72c: 0x0059, 0x72d: 0x0047, 0x72e: 0x0049, 0x72f: 0x005b,
+ 0x730: 0x0093, 0x731: 0x19e4, 0x732: 0x1c18, 0x733: 0x19ed, 0x734: 0x00ad, 0x735: 0x1a62,
+ 0x736: 0x1c4c, 0x737: 0x1d5c, 0x738: 0x19f0, 0x739: 0x00b1, 0x73a: 0x1a65, 0x73b: 0x1c50,
+ 0x73c: 0x0099, 0x73d: 0x0087, 0x73e: 0x0089, 0x73f: 0x009b,
+ // Block 0x1d, offset 0x740
+ 0x741: 0x3c06, 0x743: 0xa000, 0x744: 0x3c0d, 0x745: 0xa000,
+ 0x747: 0x3c14, 0x748: 0xa000, 0x749: 0x3c1b,
+ 0x74d: 0xa000,
+ 0x760: 0x2f65, 0x761: 0xa000, 0x762: 0x3c29,
+ 0x764: 0xa000, 0x765: 0xa000,
+ 0x76d: 0x3c22, 0x76e: 0x2f60, 0x76f: 0x2f6a,
+ 0x770: 0x3c30, 0x771: 0x3c37, 0x772: 0xa000, 0x773: 0xa000, 0x774: 0x3c3e, 0x775: 0x3c45,
+ 0x776: 0xa000, 0x777: 0xa000, 0x778: 0x3c4c, 0x779: 0x3c53, 0x77a: 0xa000, 0x77b: 0xa000,
+ 0x77c: 0xa000, 0x77d: 0xa000,
+ // Block 0x1e, offset 0x780
+ 0x780: 0x3c5a, 0x781: 0x3c61, 0x782: 0xa000, 0x783: 0xa000, 0x784: 0x3c76, 0x785: 0x3c7d,
+ 0x786: 0xa000, 0x787: 0xa000, 0x788: 0x3c84, 0x789: 0x3c8b,
+ 0x791: 0xa000,
+ 0x792: 0xa000,
+ 0x7a2: 0xa000,
+ 0x7a8: 0xa000, 0x7a9: 0xa000,
+ 0x7ab: 0xa000, 0x7ac: 0x3ca0, 0x7ad: 0x3ca7, 0x7ae: 0x3cae, 0x7af: 0x3cb5,
+ 0x7b2: 0xa000, 0x7b3: 0xa000, 0x7b4: 0xa000, 0x7b5: 0xa000,
+ // Block 0x1f, offset 0x7c0
+ 0x7e0: 0x0023, 0x7e1: 0x0025, 0x7e2: 0x0027, 0x7e3: 0x0029,
+ 0x7e4: 0x002b, 0x7e5: 0x002d, 0x7e6: 0x002f, 0x7e7: 0x0031, 0x7e8: 0x0033, 0x7e9: 0x1882,
+ 0x7ea: 0x1885, 0x7eb: 0x1888, 0x7ec: 0x188b, 0x7ed: 0x188e, 0x7ee: 0x1891, 0x7ef: 0x1894,
+ 0x7f0: 0x1897, 0x7f1: 0x189a, 0x7f2: 0x189d, 0x7f3: 0x18a6, 0x7f4: 0x1a68, 0x7f5: 0x1a6c,
+ 0x7f6: 0x1a70, 0x7f7: 0x1a74, 0x7f8: 0x1a78, 0x7f9: 0x1a7c, 0x7fa: 0x1a80, 0x7fb: 0x1a84,
+ 0x7fc: 0x1a88, 0x7fd: 0x1c80, 0x7fe: 0x1c85, 0x7ff: 0x1c8a,
+ // Block 0x20, offset 0x800
+ 0x800: 0x1c8f, 0x801: 0x1c94, 0x802: 0x1c99, 0x803: 0x1c9e, 0x804: 0x1ca3, 0x805: 0x1ca8,
+ 0x806: 0x1cad, 0x807: 0x1cb2, 0x808: 0x187f, 0x809: 0x18a3, 0x80a: 0x18c7, 0x80b: 0x18eb,
+ 0x80c: 0x190f, 0x80d: 0x1918, 0x80e: 0x191e, 0x80f: 0x1924, 0x810: 0x192a, 0x811: 0x1b60,
+ 0x812: 0x1b64, 0x813: 0x1b68, 0x814: 0x1b6c, 0x815: 0x1b70, 0x816: 0x1b74, 0x817: 0x1b78,
+ 0x818: 0x1b7c, 0x819: 0x1b80, 0x81a: 0x1b84, 0x81b: 0x1b88, 0x81c: 0x1af4, 0x81d: 0x1af8,
+ 0x81e: 0x1afc, 0x81f: 0x1b00, 0x820: 0x1b04, 0x821: 0x1b08, 0x822: 0x1b0c, 0x823: 0x1b10,
+ 0x824: 0x1b14, 0x825: 0x1b18, 0x826: 0x1b1c, 0x827: 0x1b20, 0x828: 0x1b24, 0x829: 0x1b28,
+ 0x82a: 0x1b2c, 0x82b: 0x1b30, 0x82c: 0x1b34, 0x82d: 0x1b38, 0x82e: 0x1b3c, 0x82f: 0x1b40,
+ 0x830: 0x1b44, 0x831: 0x1b48, 0x832: 0x1b4c, 0x833: 0x1b50, 0x834: 0x1b54, 0x835: 0x1b58,
+ 0x836: 0x0043, 0x837: 0x0045, 0x838: 0x0047, 0x839: 0x0049, 0x83a: 0x004b, 0x83b: 0x004d,
+ 0x83c: 0x004f, 0x83d: 0x0051, 0x83e: 0x0053, 0x83f: 0x0055,
+ // Block 0x21, offset 0x840
+ 0x840: 0x06bf, 0x841: 0x06e3, 0x842: 0x06ef, 0x843: 0x06ff, 0x844: 0x0707, 0x845: 0x0713,
+ 0x846: 0x071b, 0x847: 0x0723, 0x848: 0x072f, 0x849: 0x0783, 0x84a: 0x079b, 0x84b: 0x07ab,
+ 0x84c: 0x07bb, 0x84d: 0x07cb, 0x84e: 0x07db, 0x84f: 0x07fb, 0x850: 0x07ff, 0x851: 0x0803,
+ 0x852: 0x0837, 0x853: 0x085f, 0x854: 0x086f, 0x855: 0x0877, 0x856: 0x087b, 0x857: 0x0887,
+ 0x858: 0x08a3, 0x859: 0x08a7, 0x85a: 0x08bf, 0x85b: 0x08c3, 0x85c: 0x08cb, 0x85d: 0x08db,
+ 0x85e: 0x0977, 0x85f: 0x098b, 0x860: 0x09cb, 0x861: 0x09df, 0x862: 0x09e7, 0x863: 0x09eb,
+ 0x864: 0x09fb, 0x865: 0x0a17, 0x866: 0x0a43, 0x867: 0x0a4f, 0x868: 0x0a6f, 0x869: 0x0a7b,
+ 0x86a: 0x0a7f, 0x86b: 0x0a83, 0x86c: 0x0a9b, 0x86d: 0x0a9f, 0x86e: 0x0acb, 0x86f: 0x0ad7,
+ 0x870: 0x0adf, 0x871: 0x0ae7, 0x872: 0x0af7, 0x873: 0x0aff, 0x874: 0x0b07, 0x875: 0x0b33,
+ 0x876: 0x0b37, 0x877: 0x0b3f, 0x878: 0x0b43, 0x879: 0x0b4b, 0x87a: 0x0b53, 0x87b: 0x0b63,
+ 0x87c: 0x0b7f, 0x87d: 0x0bf7, 0x87e: 0x0c0b, 0x87f: 0x0c0f,
+ // Block 0x22, offset 0x880
+ 0x880: 0x0c8f, 0x881: 0x0c93, 0x882: 0x0ca7, 0x883: 0x0cab, 0x884: 0x0cb3, 0x885: 0x0cbb,
+ 0x886: 0x0cc3, 0x887: 0x0ccf, 0x888: 0x0cf7, 0x889: 0x0d07, 0x88a: 0x0d1b, 0x88b: 0x0d8b,
+ 0x88c: 0x0d97, 0x88d: 0x0da7, 0x88e: 0x0db3, 0x88f: 0x0dbf, 0x890: 0x0dc7, 0x891: 0x0dcb,
+ 0x892: 0x0dcf, 0x893: 0x0dd3, 0x894: 0x0dd7, 0x895: 0x0e8f, 0x896: 0x0ed7, 0x897: 0x0ee3,
+ 0x898: 0x0ee7, 0x899: 0x0eeb, 0x89a: 0x0eef, 0x89b: 0x0ef7, 0x89c: 0x0efb, 0x89d: 0x0f0f,
+ 0x89e: 0x0f2b, 0x89f: 0x0f33, 0x8a0: 0x0f73, 0x8a1: 0x0f77, 0x8a2: 0x0f7f, 0x8a3: 0x0f83,
+ 0x8a4: 0x0f8b, 0x8a5: 0x0f8f, 0x8a6: 0x0fb3, 0x8a7: 0x0fb7, 0x8a8: 0x0fd3, 0x8a9: 0x0fd7,
+ 0x8aa: 0x0fdb, 0x8ab: 0x0fdf, 0x8ac: 0x0ff3, 0x8ad: 0x1017, 0x8ae: 0x101b, 0x8af: 0x101f,
+ 0x8b0: 0x1043, 0x8b1: 0x1083, 0x8b2: 0x1087, 0x8b3: 0x10a7, 0x8b4: 0x10b7, 0x8b5: 0x10bf,
+ 0x8b6: 0x10df, 0x8b7: 0x1103, 0x8b8: 0x1147, 0x8b9: 0x114f, 0x8ba: 0x1163, 0x8bb: 0x116f,
+ 0x8bc: 0x1177, 0x8bd: 0x117f, 0x8be: 0x1183, 0x8bf: 0x1187,
+ // Block 0x23, offset 0x8c0
+ 0x8c0: 0x119f, 0x8c1: 0x11a3, 0x8c2: 0x11bf, 0x8c3: 0x11c7, 0x8c4: 0x11cf, 0x8c5: 0x11d3,
+ 0x8c6: 0x11df, 0x8c7: 0x11e7, 0x8c8: 0x11eb, 0x8c9: 0x11ef, 0x8ca: 0x11f7, 0x8cb: 0x11fb,
+ 0x8cc: 0x129b, 0x8cd: 0x12af, 0x8ce: 0x12e3, 0x8cf: 0x12e7, 0x8d0: 0x12ef, 0x8d1: 0x131b,
+ 0x8d2: 0x1323, 0x8d3: 0x132b, 0x8d4: 0x1333, 0x8d5: 0x136f, 0x8d6: 0x1373, 0x8d7: 0x137b,
+ 0x8d8: 0x137f, 0x8d9: 0x1383, 0x8da: 0x13af, 0x8db: 0x13b3, 0x8dc: 0x13bb, 0x8dd: 0x13cf,
+ 0x8de: 0x13d3, 0x8df: 0x13ef, 0x8e0: 0x13f7, 0x8e1: 0x13fb, 0x8e2: 0x141f, 0x8e3: 0x143f,
+ 0x8e4: 0x1453, 0x8e5: 0x1457, 0x8e6: 0x145f, 0x8e7: 0x148b, 0x8e8: 0x148f, 0x8e9: 0x149f,
+ 0x8ea: 0x14c3, 0x8eb: 0x14cf, 0x8ec: 0x14df, 0x8ed: 0x14f7, 0x8ee: 0x14ff, 0x8ef: 0x1503,
+ 0x8f0: 0x1507, 0x8f1: 0x150b, 0x8f2: 0x1517, 0x8f3: 0x151b, 0x8f4: 0x1523, 0x8f5: 0x153f,
+ 0x8f6: 0x1543, 0x8f7: 0x1547, 0x8f8: 0x155f, 0x8f9: 0x1563, 0x8fa: 0x156b, 0x8fb: 0x157f,
+ 0x8fc: 0x1583, 0x8fd: 0x1587, 0x8fe: 0x158f, 0x8ff: 0x1593,
+ // Block 0x24, offset 0x900
+ 0x906: 0xa000, 0x90b: 0xa000,
+ 0x90c: 0x3f08, 0x90d: 0xa000, 0x90e: 0x3f10, 0x90f: 0xa000, 0x910: 0x3f18, 0x911: 0xa000,
+ 0x912: 0x3f20, 0x913: 0xa000, 0x914: 0x3f28, 0x915: 0xa000, 0x916: 0x3f30, 0x917: 0xa000,
+ 0x918: 0x3f38, 0x919: 0xa000, 0x91a: 0x3f40, 0x91b: 0xa000, 0x91c: 0x3f48, 0x91d: 0xa000,
+ 0x91e: 0x3f50, 0x91f: 0xa000, 0x920: 0x3f58, 0x921: 0xa000, 0x922: 0x3f60,
+ 0x924: 0xa000, 0x925: 0x3f68, 0x926: 0xa000, 0x927: 0x3f70, 0x928: 0xa000, 0x929: 0x3f78,
+ 0x92f: 0xa000,
+ 0x930: 0x3f80, 0x931: 0x3f88, 0x932: 0xa000, 0x933: 0x3f90, 0x934: 0x3f98, 0x935: 0xa000,
+ 0x936: 0x3fa0, 0x937: 0x3fa8, 0x938: 0xa000, 0x939: 0x3fb0, 0x93a: 0x3fb8, 0x93b: 0xa000,
+ 0x93c: 0x3fc0, 0x93d: 0x3fc8,
+ // Block 0x25, offset 0x940
+ 0x954: 0x3f00,
+ 0x959: 0x9903, 0x95a: 0x9903, 0x95b: 0x4372, 0x95c: 0x4378, 0x95d: 0xa000,
+ 0x95e: 0x3fd0, 0x95f: 0x26b4,
+ 0x966: 0xa000,
+ 0x96b: 0xa000, 0x96c: 0x3fe0, 0x96d: 0xa000, 0x96e: 0x3fe8, 0x96f: 0xa000,
+ 0x970: 0x3ff0, 0x971: 0xa000, 0x972: 0x3ff8, 0x973: 0xa000, 0x974: 0x4000, 0x975: 0xa000,
+ 0x976: 0x4008, 0x977: 0xa000, 0x978: 0x4010, 0x979: 0xa000, 0x97a: 0x4018, 0x97b: 0xa000,
+ 0x97c: 0x4020, 0x97d: 0xa000, 0x97e: 0x4028, 0x97f: 0xa000,
+ // Block 0x26, offset 0x980
+ 0x980: 0x4030, 0x981: 0xa000, 0x982: 0x4038, 0x984: 0xa000, 0x985: 0x4040,
+ 0x986: 0xa000, 0x987: 0x4048, 0x988: 0xa000, 0x989: 0x4050,
+ 0x98f: 0xa000, 0x990: 0x4058, 0x991: 0x4060,
+ 0x992: 0xa000, 0x993: 0x4068, 0x994: 0x4070, 0x995: 0xa000, 0x996: 0x4078, 0x997: 0x4080,
+ 0x998: 0xa000, 0x999: 0x4088, 0x99a: 0x4090, 0x99b: 0xa000, 0x99c: 0x4098, 0x99d: 0x40a0,
+ 0x9af: 0xa000,
+ 0x9b0: 0xa000, 0x9b1: 0xa000, 0x9b2: 0xa000, 0x9b4: 0x3fd8,
+ 0x9b7: 0x40a8, 0x9b8: 0x40b0, 0x9b9: 0x40b8, 0x9ba: 0x40c0,
+ 0x9bd: 0xa000, 0x9be: 0x40c8, 0x9bf: 0x26c9,
+ // 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,
+ 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,
+ 0x9f6: 0x0387, 0x9f7: 0x038b, 0x9f8: 0x038f, 0x9f9: 0x0393, 0x9fa: 0x0397, 0x9fb: 0x039b,
+ 0x9fc: 0x039f, 0x9fd: 0x03a3, 0x9fe: 0x03a7, 0x9ff: 0x03ab,
+ // Block 0x28, offset 0xa00
+ 0xa00: 0x03af, 0xa01: 0x03b3, 0xa02: 0x040b, 0xa03: 0x040f, 0xa04: 0x03b7, 0xa05: 0x03bb,
+ 0xa06: 0x03bf, 0xa07: 0x03c7, 0xa08: 0x03cb, 0xa09: 0x03cf, 0xa0a: 0x03d3, 0xa0b: 0x03d7,
+ 0xa0c: 0x03db, 0xa0d: 0x03df, 0xa0e: 0x03e3,
+ 0xa12: 0x06bf, 0xa13: 0x071b, 0xa14: 0x06cb, 0xa15: 0x097b, 0xa16: 0x06cf, 0xa17: 0x06e7,
+ 0xa18: 0x06d3, 0xa19: 0x0f93, 0xa1a: 0x0707, 0xa1b: 0x06db, 0xa1c: 0x06c3, 0xa1d: 0x09ff,
+ 0xa1e: 0x098f, 0xa1f: 0x072f,
+ // Block 0x29, offset 0xa40
+ 0xa40: 0x2054, 0xa41: 0x205a, 0xa42: 0x2060, 0xa43: 0x2066, 0xa44: 0x206c, 0xa45: 0x2072,
+ 0xa46: 0x2078, 0xa47: 0x207e, 0xa48: 0x2084, 0xa49: 0x208a, 0xa4a: 0x2090, 0xa4b: 0x2096,
+ 0xa4c: 0x209c, 0xa4d: 0x20a2, 0xa4e: 0x2726, 0xa4f: 0x272f, 0xa50: 0x2738, 0xa51: 0x2741,
+ 0xa52: 0x274a, 0xa53: 0x2753, 0xa54: 0x275c, 0xa55: 0x2765, 0xa56: 0x276e, 0xa57: 0x2780,
+ 0xa58: 0x2789, 0xa59: 0x2792, 0xa5a: 0x279b, 0xa5b: 0x27a4, 0xa5c: 0x2777, 0xa5d: 0x2bac,
+ 0xa5e: 0x2aed, 0xa60: 0x20a8, 0xa61: 0x20c0, 0xa62: 0x20b4, 0xa63: 0x2108,
+ 0xa64: 0x20c6, 0xa65: 0x20e4, 0xa66: 0x20ae, 0xa67: 0x20de, 0xa68: 0x20ba, 0xa69: 0x20f0,
+ 0xa6a: 0x2120, 0xa6b: 0x213e, 0xa6c: 0x2138, 0xa6d: 0x212c, 0xa6e: 0x217a, 0xa6f: 0x210e,
+ 0xa70: 0x211a, 0xa71: 0x2132, 0xa72: 0x2126, 0xa73: 0x2150, 0xa74: 0x20fc, 0xa75: 0x2144,
+ 0xa76: 0x216e, 0xa77: 0x2156, 0xa78: 0x20ea, 0xa79: 0x20cc, 0xa7a: 0x2102, 0xa7b: 0x2114,
+ 0xa7c: 0x214a, 0xa7d: 0x20d2, 0xa7e: 0x2174, 0xa7f: 0x20f6,
+ // Block 0x2a, offset 0xa80
+ 0xa80: 0x215c, 0xa81: 0x20d8, 0xa82: 0x2162, 0xa83: 0x2168, 0xa84: 0x092f, 0xa85: 0x0b03,
+ 0xa86: 0x0ca7, 0xa87: 0x10c7,
+ 0xa90: 0x1bc4, 0xa91: 0x18a9,
+ 0xa92: 0x18ac, 0xa93: 0x18af, 0xa94: 0x18b2, 0xa95: 0x18b5, 0xa96: 0x18b8, 0xa97: 0x18bb,
+ 0xa98: 0x18be, 0xa99: 0x18c1, 0xa9a: 0x18ca, 0xa9b: 0x18cd, 0xa9c: 0x18d0, 0xa9d: 0x18d3,
+ 0xa9e: 0x18d6, 0xa9f: 0x18d9, 0xaa0: 0x0313, 0xaa1: 0x031b, 0xaa2: 0x031f, 0xaa3: 0x0327,
+ 0xaa4: 0x032b, 0xaa5: 0x032f, 0xaa6: 0x0337, 0xaa7: 0x033f, 0xaa8: 0x0343, 0xaa9: 0x034b,
+ 0xaaa: 0x034f, 0xaab: 0x0353, 0xaac: 0x0357, 0xaad: 0x035b, 0xaae: 0x2e18, 0xaaf: 0x2e20,
+ 0xab0: 0x2e28, 0xab1: 0x2e30, 0xab2: 0x2e38, 0xab3: 0x2e40, 0xab4: 0x2e48, 0xab5: 0x2e50,
+ 0xab6: 0x2e60, 0xab7: 0x2e68, 0xab8: 0x2e70, 0xab9: 0x2e78, 0xaba: 0x2e80, 0xabb: 0x2e88,
+ 0xabc: 0x2ed3, 0xabd: 0x2e9b, 0xabe: 0x2e58,
+ // Block 0x2b, offset 0xac0
+ 0xac0: 0x06bf, 0xac1: 0x071b, 0xac2: 0x06cb, 0xac3: 0x097b, 0xac4: 0x071f, 0xac5: 0x07af,
+ 0xac6: 0x06c7, 0xac7: 0x07ab, 0xac8: 0x070b, 0xac9: 0x0887, 0xaca: 0x0d07, 0xacb: 0x0e8f,
+ 0xacc: 0x0dd7, 0xacd: 0x0d1b, 0xace: 0x145f, 0xacf: 0x098b, 0xad0: 0x0ccf, 0xad1: 0x0d4b,
+ 0xad2: 0x0d0b, 0xad3: 0x104b, 0xad4: 0x08fb, 0xad5: 0x0f03, 0xad6: 0x1387, 0xad7: 0x105f,
+ 0xad8: 0x0843, 0xad9: 0x108f, 0xada: 0x0f9b, 0xadb: 0x0a17, 0xadc: 0x140f, 0xadd: 0x077f,
+ 0xade: 0x08ab, 0xadf: 0x0df7, 0xae0: 0x1527, 0xae1: 0x0743, 0xae2: 0x07d3, 0xae3: 0x0d9b,
+ 0xae4: 0x06cf, 0xae5: 0x06e7, 0xae6: 0x06d3, 0xae7: 0x0adb, 0xae8: 0x08ef, 0xae9: 0x087f,
+ 0xaea: 0x0a57, 0xaeb: 0x0a4b, 0xaec: 0x0feb, 0xaed: 0x073f, 0xaee: 0x139b, 0xaef: 0x089b,
+ 0xaf0: 0x09f3, 0xaf1: 0x18dc, 0xaf2: 0x18df, 0xaf3: 0x18e2, 0xaf4: 0x18e5, 0xaf5: 0x18ee,
+ 0xaf6: 0x18f1, 0xaf7: 0x18f4, 0xaf8: 0x18f7, 0xaf9: 0x18fa, 0xafa: 0x18fd, 0xafb: 0x1900,
+ 0xafc: 0x1903, 0xafd: 0x1906, 0xafe: 0x1909, 0xaff: 0x1912,
+ // Block 0x2c, offset 0xb00
+ 0xb00: 0x1cc6, 0xb01: 0x1cd5, 0xb02: 0x1ce4, 0xb03: 0x1cf3, 0xb04: 0x1d02, 0xb05: 0x1d11,
+ 0xb06: 0x1d20, 0xb07: 0x1d2f, 0xb08: 0x1d3e, 0xb09: 0x218c, 0xb0a: 0x219e, 0xb0b: 0x21b0,
+ 0xb0c: 0x1954, 0xb0d: 0x1c04, 0xb0e: 0x19d2, 0xb0f: 0x1ba8, 0xb10: 0x04cb, 0xb11: 0x04d3,
+ 0xb12: 0x04db, 0xb13: 0x04e3, 0xb14: 0x04eb, 0xb15: 0x04ef, 0xb16: 0x04f3, 0xb17: 0x04f7,
+ 0xb18: 0x04fb, 0xb19: 0x04ff, 0xb1a: 0x0503, 0xb1b: 0x0507, 0xb1c: 0x050b, 0xb1d: 0x050f,
+ 0xb1e: 0x0513, 0xb1f: 0x0517, 0xb20: 0x051b, 0xb21: 0x0523, 0xb22: 0x0527, 0xb23: 0x052b,
+ 0xb24: 0x052f, 0xb25: 0x0533, 0xb26: 0x0537, 0xb27: 0x053b, 0xb28: 0x053f, 0xb29: 0x0543,
+ 0xb2a: 0x0547, 0xb2b: 0x054b, 0xb2c: 0x054f, 0xb2d: 0x0553, 0xb2e: 0x0557, 0xb2f: 0x055b,
+ 0xb30: 0x055f, 0xb31: 0x0563, 0xb32: 0x0567, 0xb33: 0x056f, 0xb34: 0x0577, 0xb35: 0x057f,
+ 0xb36: 0x0583, 0xb37: 0x0587, 0xb38: 0x058b, 0xb39: 0x058f, 0xb3a: 0x0593, 0xb3b: 0x0597,
+ 0xb3c: 0x059b, 0xb3d: 0x059f, 0xb3e: 0x05a3,
+ // Block 0x2d, offset 0xb40
+ 0xb40: 0x2b0c, 0xb41: 0x29a8, 0xb42: 0x2b1c, 0xb43: 0x2880, 0xb44: 0x2ee4, 0xb45: 0x288a,
+ 0xb46: 0x2894, 0xb47: 0x2f28, 0xb48: 0x29b5, 0xb49: 0x289e, 0xb4a: 0x28a8, 0xb4b: 0x28b2,
+ 0xb4c: 0x29dc, 0xb4d: 0x29e9, 0xb4e: 0x29c2, 0xb4f: 0x29cf, 0xb50: 0x2ea9, 0xb51: 0x29f6,
+ 0xb52: 0x2a03, 0xb53: 0x2bbe, 0xb54: 0x26bb, 0xb55: 0x2bd1, 0xb56: 0x2be4, 0xb57: 0x2b2c,
+ 0xb58: 0x2a10, 0xb59: 0x2bf7, 0xb5a: 0x2c0a, 0xb5b: 0x2a1d, 0xb5c: 0x28bc, 0xb5d: 0x28c6,
+ 0xb5e: 0x2eb7, 0xb5f: 0x2a2a, 0xb60: 0x2b3c, 0xb61: 0x2ef5, 0xb62: 0x28d0, 0xb63: 0x28da,
+ 0xb64: 0x2a37, 0xb65: 0x28e4, 0xb66: 0x28ee, 0xb67: 0x26d0, 0xb68: 0x26d7, 0xb69: 0x28f8,
+ 0xb6a: 0x2902, 0xb6b: 0x2c1d, 0xb6c: 0x2a44, 0xb6d: 0x2b4c, 0xb6e: 0x2c30, 0xb6f: 0x2a51,
+ 0xb70: 0x2916, 0xb71: 0x290c, 0xb72: 0x2f3c, 0xb73: 0x2a5e, 0xb74: 0x2c43, 0xb75: 0x2920,
+ 0xb76: 0x2b5c, 0xb77: 0x292a, 0xb78: 0x2a78, 0xb79: 0x2934, 0xb7a: 0x2a85, 0xb7b: 0x2f06,
+ 0xb7c: 0x2a6b, 0xb7d: 0x2b6c, 0xb7e: 0x2a92, 0xb7f: 0x26de,
+ // Block 0x2e, offset 0xb80
+ 0xb80: 0x2f17, 0xb81: 0x293e, 0xb82: 0x2948, 0xb83: 0x2a9f, 0xb84: 0x2952, 0xb85: 0x295c,
+ 0xb86: 0x2966, 0xb87: 0x2b7c, 0xb88: 0x2aac, 0xb89: 0x26e5, 0xb8a: 0x2c56, 0xb8b: 0x2e90,
+ 0xb8c: 0x2b8c, 0xb8d: 0x2ab9, 0xb8e: 0x2ec5, 0xb8f: 0x2970, 0xb90: 0x297a, 0xb91: 0x2ac6,
+ 0xb92: 0x26ec, 0xb93: 0x2ad3, 0xb94: 0x2b9c, 0xb95: 0x26f3, 0xb96: 0x2c69, 0xb97: 0x2984,
+ 0xb98: 0x1cb7, 0xb99: 0x1ccb, 0xb9a: 0x1cda, 0xb9b: 0x1ce9, 0xb9c: 0x1cf8, 0xb9d: 0x1d07,
+ 0xb9e: 0x1d16, 0xb9f: 0x1d25, 0xba0: 0x1d34, 0xba1: 0x1d43, 0xba2: 0x2192, 0xba3: 0x21a4,
+ 0xba4: 0x21b6, 0xba5: 0x21c2, 0xba6: 0x21ce, 0xba7: 0x21da, 0xba8: 0x21e6, 0xba9: 0x21f2,
+ 0xbaa: 0x21fe, 0xbab: 0x220a, 0xbac: 0x2246, 0xbad: 0x2252, 0xbae: 0x225e, 0xbaf: 0x226a,
+ 0xbb0: 0x2276, 0xbb1: 0x1c14, 0xbb2: 0x19c6, 0xbb3: 0x1936, 0xbb4: 0x1be4, 0xbb5: 0x1a47,
+ 0xbb6: 0x1a56, 0xbb7: 0x19cc, 0xbb8: 0x1bfc, 0xbb9: 0x1c00, 0xbba: 0x1960, 0xbbb: 0x2701,
+ 0xbbc: 0x270f, 0xbbd: 0x26fa, 0xbbe: 0x2708, 0xbbf: 0x2ae0,
+ // Block 0x2f, offset 0xbc0
+ 0xbc0: 0x1a4a, 0xbc1: 0x1a32, 0xbc2: 0x1c60, 0xbc3: 0x1a1a, 0xbc4: 0x19f3, 0xbc5: 0x1969,
+ 0xbc6: 0x1978, 0xbc7: 0x1948, 0xbc8: 0x1bf0, 0xbc9: 0x1d52, 0xbca: 0x1a4d, 0xbcb: 0x1a35,
+ 0xbcc: 0x1c64, 0xbcd: 0x1c70, 0xbce: 0x1a26, 0xbcf: 0x19fc, 0xbd0: 0x1957, 0xbd1: 0x1c1c,
+ 0xbd2: 0x1bb0, 0xbd3: 0x1b9c, 0xbd4: 0x1bcc, 0xbd5: 0x1c74, 0xbd6: 0x1a29, 0xbd7: 0x19c9,
+ 0xbd8: 0x19ff, 0xbd9: 0x19de, 0xbda: 0x1a41, 0xbdb: 0x1c78, 0xbdc: 0x1a2c, 0xbdd: 0x19c0,
+ 0xbde: 0x1a02, 0xbdf: 0x1c3c, 0xbe0: 0x1bf4, 0xbe1: 0x1a14, 0xbe2: 0x1c24, 0xbe3: 0x1c40,
+ 0xbe4: 0x1bf8, 0xbe5: 0x1a17, 0xbe6: 0x1c28, 0xbe7: 0x22e8, 0xbe8: 0x22fc, 0xbe9: 0x1996,
+ 0xbea: 0x1c20, 0xbeb: 0x1bb4, 0xbec: 0x1ba0, 0xbed: 0x1c48, 0xbee: 0x2716, 0xbef: 0x27ad,
+ 0xbf0: 0x1a59, 0xbf1: 0x1a44, 0xbf2: 0x1c7c, 0xbf3: 0x1a2f, 0xbf4: 0x1a50, 0xbf5: 0x1a38,
+ 0xbf6: 0x1c68, 0xbf7: 0x1a1d, 0xbf8: 0x19f6, 0xbf9: 0x1981, 0xbfa: 0x1a53, 0xbfb: 0x1a3b,
+ 0xbfc: 0x1c6c, 0xbfd: 0x1a20, 0xbfe: 0x19f9, 0xbff: 0x1984,
+ // Block 0x30, offset 0xc00
+ 0xc00: 0x1c2c, 0xc01: 0x1bb8, 0xc02: 0x1d4d, 0xc03: 0x1939, 0xc04: 0x19ba, 0xc05: 0x19bd,
+ 0xc06: 0x22f5, 0xc07: 0x1b94, 0xc08: 0x19c3, 0xc09: 0x194b, 0xc0a: 0x19e1, 0xc0b: 0x194e,
+ 0xc0c: 0x19ea, 0xc0d: 0x196c, 0xc0e: 0x196f, 0xc0f: 0x1a05, 0xc10: 0x1a0b, 0xc11: 0x1a0e,
+ 0xc12: 0x1c30, 0xc13: 0x1a11, 0xc14: 0x1a23, 0xc15: 0x1c38, 0xc16: 0x1c44, 0xc17: 0x1990,
+ 0xc18: 0x1d57, 0xc19: 0x1bbc, 0xc1a: 0x1993, 0xc1b: 0x1a5c, 0xc1c: 0x19a5, 0xc1d: 0x19b4,
+ 0xc1e: 0x22e2, 0xc1f: 0x22dc, 0xc20: 0x1cc1, 0xc21: 0x1cd0, 0xc22: 0x1cdf, 0xc23: 0x1cee,
+ 0xc24: 0x1cfd, 0xc25: 0x1d0c, 0xc26: 0x1d1b, 0xc27: 0x1d2a, 0xc28: 0x1d39, 0xc29: 0x2186,
+ 0xc2a: 0x2198, 0xc2b: 0x21aa, 0xc2c: 0x21bc, 0xc2d: 0x21c8, 0xc2e: 0x21d4, 0xc2f: 0x21e0,
+ 0xc30: 0x21ec, 0xc31: 0x21f8, 0xc32: 0x2204, 0xc33: 0x2240, 0xc34: 0x224c, 0xc35: 0x2258,
+ 0xc36: 0x2264, 0xc37: 0x2270, 0xc38: 0x227c, 0xc39: 0x2282, 0xc3a: 0x2288, 0xc3b: 0x228e,
+ 0xc3c: 0x2294, 0xc3d: 0x22a6, 0xc3e: 0x22ac, 0xc3f: 0x1c10,
+ // Block 0x31, offset 0xc40
+ 0xc40: 0x1377, 0xc41: 0x0cfb, 0xc42: 0x13d3, 0xc43: 0x139f, 0xc44: 0x0e57, 0xc45: 0x06eb,
+ 0xc46: 0x08df, 0xc47: 0x162b, 0xc48: 0x162b, 0xc49: 0x0a0b, 0xc4a: 0x145f, 0xc4b: 0x0943,
+ 0xc4c: 0x0a07, 0xc4d: 0x0bef, 0xc4e: 0x0fcf, 0xc4f: 0x115f, 0xc50: 0x1297, 0xc51: 0x12d3,
+ 0xc52: 0x1307, 0xc53: 0x141b, 0xc54: 0x0d73, 0xc55: 0x0dff, 0xc56: 0x0eab, 0xc57: 0x0f43,
+ 0xc58: 0x125f, 0xc59: 0x1447, 0xc5a: 0x1573, 0xc5b: 0x070f, 0xc5c: 0x08b3, 0xc5d: 0x0d87,
+ 0xc5e: 0x0ecf, 0xc5f: 0x1293, 0xc60: 0x15c3, 0xc61: 0x0ab3, 0xc62: 0x0e77, 0xc63: 0x1283,
+ 0xc64: 0x1317, 0xc65: 0x0c23, 0xc66: 0x11bb, 0xc67: 0x12df, 0xc68: 0x0b1f, 0xc69: 0x0d0f,
+ 0xc6a: 0x0e17, 0xc6b: 0x0f1b, 0xc6c: 0x1427, 0xc6d: 0x074f, 0xc6e: 0x07e7, 0xc6f: 0x0853,
+ 0xc70: 0x0c8b, 0xc71: 0x0d7f, 0xc72: 0x0ecb, 0xc73: 0x0fef, 0xc74: 0x1177, 0xc75: 0x128b,
+ 0xc76: 0x12a3, 0xc77: 0x13c7, 0xc78: 0x14ef, 0xc79: 0x15a3, 0xc7a: 0x15bf, 0xc7b: 0x102b,
+ 0xc7c: 0x106b, 0xc7d: 0x1123, 0xc7e: 0x1243, 0xc7f: 0x147b,
+ // Block 0x32, offset 0xc80
+ 0xc80: 0x15cb, 0xc81: 0x134b, 0xc82: 0x09c7, 0xc83: 0x0b3b, 0xc84: 0x10db, 0xc85: 0x119b,
+ 0xc86: 0x0eff, 0xc87: 0x1033, 0xc88: 0x1397, 0xc89: 0x14e7, 0xc8a: 0x09c3, 0xc8b: 0x0a8f,
+ 0xc8c: 0x0d77, 0xc8d: 0x0e2b, 0xc8e: 0x0e5f, 0xc8f: 0x1113, 0xc90: 0x113b, 0xc91: 0x14a7,
+ 0xc92: 0x084f, 0xc93: 0x11a7, 0xc94: 0x07f3, 0xc95: 0x07ef, 0xc96: 0x1097, 0xc97: 0x1127,
+ 0xc98: 0x125b, 0xc99: 0x14af, 0xc9a: 0x1367, 0xc9b: 0x0c27, 0xc9c: 0x0d73, 0xc9d: 0x1357,
+ 0xc9e: 0x06f7, 0xc9f: 0x0a63, 0xca0: 0x0b93, 0xca1: 0x0f2f, 0xca2: 0x0faf, 0xca3: 0x0873,
+ 0xca4: 0x103b, 0xca5: 0x075f, 0xca6: 0x0b77, 0xca7: 0x06d7, 0xca8: 0x0deb, 0xca9: 0x0ca3,
+ 0xcaa: 0x110f, 0xcab: 0x08c7, 0xcac: 0x09b3, 0xcad: 0x0ffb, 0xcae: 0x1263, 0xcaf: 0x133b,
+ 0xcb0: 0x0db7, 0xcb1: 0x13f7, 0xcb2: 0x0de3, 0xcb3: 0x0c37, 0xcb4: 0x121b, 0xcb5: 0x0c57,
+ 0xcb6: 0x0fab, 0xcb7: 0x072b, 0xcb8: 0x07a7, 0xcb9: 0x07eb, 0xcba: 0x0d53, 0xcbb: 0x10fb,
+ 0xcbc: 0x11f3, 0xcbd: 0x1347, 0xcbe: 0x145b, 0xcbf: 0x085b,
+ // Block 0x33, offset 0xcc0
+ 0xcc0: 0x090f, 0xcc1: 0x0a17, 0xcc2: 0x0b2f, 0xcc3: 0x0cbf, 0xcc4: 0x0e7b, 0xcc5: 0x103f,
+ 0xcc6: 0x1497, 0xcc7: 0x157b, 0xcc8: 0x15cf, 0xcc9: 0x15e7, 0xcca: 0x0837, 0xccb: 0x0cf3,
+ 0xccc: 0x0da3, 0xccd: 0x13eb, 0xcce: 0x0afb, 0xccf: 0x0bd7, 0xcd0: 0x0bf3, 0xcd1: 0x0c83,
+ 0xcd2: 0x0e6b, 0xcd3: 0x0eb7, 0xcd4: 0x0f67, 0xcd5: 0x108b, 0xcd6: 0x112f, 0xcd7: 0x1193,
+ 0xcd8: 0x13db, 0xcd9: 0x126b, 0xcda: 0x1403, 0xcdb: 0x147f, 0xcdc: 0x080f, 0xcdd: 0x083b,
+ 0xcde: 0x0923, 0xcdf: 0x0ea7, 0xce0: 0x12f3, 0xce1: 0x133b, 0xce2: 0x0b1b, 0xce3: 0x0b8b,
+ 0xce4: 0x0c4f, 0xce5: 0x0daf, 0xce6: 0x10d7, 0xce7: 0x0f23, 0xce8: 0x073b, 0xce9: 0x097f,
+ 0xcea: 0x0a63, 0xceb: 0x0ac7, 0xcec: 0x0b97, 0xced: 0x0f3f, 0xcee: 0x0f5b, 0xcef: 0x116b,
+ 0xcf0: 0x118b, 0xcf1: 0x1463, 0xcf2: 0x14e3, 0xcf3: 0x14f3, 0xcf4: 0x152f, 0xcf5: 0x0753,
+ 0xcf6: 0x107f, 0xcf7: 0x144f, 0xcf8: 0x14cb, 0xcf9: 0x0baf, 0xcfa: 0x0717, 0xcfb: 0x0777,
+ 0xcfc: 0x0a67, 0xcfd: 0x0a87, 0xcfe: 0x0caf, 0xcff: 0x0d73,
+ // Block 0x34, offset 0xd00
+ 0xd00: 0x0ec3, 0xd01: 0x0fcb, 0xd02: 0x1277, 0xd03: 0x1417, 0xd04: 0x1623, 0xd05: 0x0ce3,
+ 0xd06: 0x14a3, 0xd07: 0x0833, 0xd08: 0x0d2f, 0xd09: 0x0d3b, 0xd0a: 0x0e0f, 0xd0b: 0x0e47,
+ 0xd0c: 0x0f4b, 0xd0d: 0x0fa7, 0xd0e: 0x1027, 0xd0f: 0x110b, 0xd10: 0x153b, 0xd11: 0x07af,
+ 0xd12: 0x0c03, 0xd13: 0x14b3, 0xd14: 0x0767, 0xd15: 0x0aab, 0xd16: 0x0e2f, 0xd17: 0x13df,
+ 0xd18: 0x0b67, 0xd19: 0x0bb7, 0xd1a: 0x0d43, 0xd1b: 0x0f2f, 0xd1c: 0x14bb, 0xd1d: 0x0817,
+ 0xd1e: 0x08ff, 0xd1f: 0x0a97, 0xd20: 0x0cd3, 0xd21: 0x0d1f, 0xd22: 0x0d5f, 0xd23: 0x0df3,
+ 0xd24: 0x0f47, 0xd25: 0x0fbb, 0xd26: 0x1157, 0xd27: 0x12f7, 0xd28: 0x1303, 0xd29: 0x1457,
+ 0xd2a: 0x14d7, 0xd2b: 0x0883, 0xd2c: 0x0e4b, 0xd2d: 0x0903, 0xd2e: 0x0ec7, 0xd2f: 0x0f6b,
+ 0xd30: 0x1287, 0xd31: 0x14bf, 0xd32: 0x15ab, 0xd33: 0x15d3, 0xd34: 0x0d37, 0xd35: 0x0e27,
+ 0xd36: 0x11c3, 0xd37: 0x10b7, 0xd38: 0x10c3, 0xd39: 0x10e7, 0xd3a: 0x0f17, 0xd3b: 0x0e9f,
+ 0xd3c: 0x1363, 0xd3d: 0x0733, 0xd3e: 0x122b, 0xd3f: 0x081b,
+ // Block 0x35, offset 0xd40
+ 0xd40: 0x080b, 0xd41: 0x0b0b, 0xd42: 0x0c2b, 0xd43: 0x10f3, 0xd44: 0x0a53, 0xd45: 0x0e03,
+ 0xd46: 0x0cef, 0xd47: 0x13e7, 0xd48: 0x12e7, 0xd49: 0x14ab, 0xd4a: 0x1323, 0xd4b: 0x0b27,
+ 0xd4c: 0x0787, 0xd4d: 0x095b, 0xd50: 0x09af,
+ 0xd52: 0x0cdf, 0xd55: 0x07f7, 0xd56: 0x0f1f, 0xd57: 0x0fe3,
+ 0xd58: 0x1047, 0xd59: 0x1063, 0xd5a: 0x1067, 0xd5b: 0x107b, 0xd5c: 0x14fb, 0xd5d: 0x10eb,
+ 0xd5e: 0x116f, 0xd60: 0x128f, 0xd62: 0x1353,
+ 0xd65: 0x1407, 0xd66: 0x1433,
+ 0xd6a: 0x154f, 0xd6b: 0x1553, 0xd6c: 0x1557, 0xd6d: 0x15bb, 0xd6e: 0x142b, 0xd6f: 0x14c7,
+ 0xd70: 0x0757, 0xd71: 0x077b, 0xd72: 0x078f, 0xd73: 0x084b, 0xd74: 0x0857, 0xd75: 0x0897,
+ 0xd76: 0x094b, 0xd77: 0x0967, 0xd78: 0x096f, 0xd79: 0x09ab, 0xd7a: 0x09b7, 0xd7b: 0x0a93,
+ 0xd7c: 0x0a9b, 0xd7d: 0x0ba3, 0xd7e: 0x0bcb, 0xd7f: 0x0bd3,
+ // Block 0x36, offset 0xd80
+ 0xd80: 0x0beb, 0xd81: 0x0c97, 0xd82: 0x0cc7, 0xd83: 0x0ce7, 0xd84: 0x0d57, 0xd85: 0x0e1b,
+ 0xd86: 0x0e37, 0xd87: 0x0e67, 0xd88: 0x0ebb, 0xd89: 0x0edb, 0xd8a: 0x0f4f, 0xd8b: 0x102f,
+ 0xd8c: 0x104b, 0xd8d: 0x1053, 0xd8e: 0x104f, 0xd8f: 0x1057, 0xd90: 0x105b, 0xd91: 0x105f,
+ 0xd92: 0x1073, 0xd93: 0x1077, 0xd94: 0x109b, 0xd95: 0x10af, 0xd96: 0x10cb, 0xd97: 0x112f,
+ 0xd98: 0x1137, 0xd99: 0x113f, 0xd9a: 0x1153, 0xd9b: 0x117b, 0xd9c: 0x11cb, 0xd9d: 0x11ff,
+ 0xd9e: 0x11ff, 0xd9f: 0x1267, 0xda0: 0x130f, 0xda1: 0x1327, 0xda2: 0x135b, 0xda3: 0x135f,
+ 0xda4: 0x13a3, 0xda5: 0x13a7, 0xda6: 0x13ff, 0xda7: 0x1407, 0xda8: 0x14db, 0xda9: 0x151f,
+ 0xdaa: 0x1537, 0xdab: 0x0b9b, 0xdac: 0x171e, 0xdad: 0x11e3,
+ 0xdb0: 0x06df, 0xdb1: 0x07e3, 0xdb2: 0x07a3, 0xdb3: 0x074b, 0xdb4: 0x078b, 0xdb5: 0x07b7,
+ 0xdb6: 0x0847, 0xdb7: 0x0863, 0xdb8: 0x094b, 0xdb9: 0x0937, 0xdba: 0x0947, 0xdbb: 0x0963,
+ 0xdbc: 0x09af, 0xdbd: 0x09bf, 0xdbe: 0x0a03, 0xdbf: 0x0a0f,
+ // Block 0x37, offset 0xdc0
+ 0xdc0: 0x0a2b, 0xdc1: 0x0a3b, 0xdc2: 0x0b23, 0xdc3: 0x0b2b, 0xdc4: 0x0b5b, 0xdc5: 0x0b7b,
+ 0xdc6: 0x0bab, 0xdc7: 0x0bc3, 0xdc8: 0x0bb3, 0xdc9: 0x0bd3, 0xdca: 0x0bc7, 0xdcb: 0x0beb,
+ 0xdcc: 0x0c07, 0xdcd: 0x0c5f, 0xdce: 0x0c6b, 0xdcf: 0x0c73, 0xdd0: 0x0c9b, 0xdd1: 0x0cdf,
+ 0xdd2: 0x0d0f, 0xdd3: 0x0d13, 0xdd4: 0x0d27, 0xdd5: 0x0da7, 0xdd6: 0x0db7, 0xdd7: 0x0e0f,
+ 0xdd8: 0x0e5b, 0xdd9: 0x0e53, 0xdda: 0x0e67, 0xddb: 0x0e83, 0xddc: 0x0ebb, 0xddd: 0x1013,
+ 0xdde: 0x0edf, 0xddf: 0x0f13, 0xde0: 0x0f1f, 0xde1: 0x0f5f, 0xde2: 0x0f7b, 0xde3: 0x0f9f,
+ 0xde4: 0x0fc3, 0xde5: 0x0fc7, 0xde6: 0x0fe3, 0xde7: 0x0fe7, 0xde8: 0x0ff7, 0xde9: 0x100b,
+ 0xdea: 0x1007, 0xdeb: 0x1037, 0xdec: 0x10b3, 0xded: 0x10cb, 0xdee: 0x10e3, 0xdef: 0x111b,
+ 0xdf0: 0x112f, 0xdf1: 0x114b, 0xdf2: 0x117b, 0xdf3: 0x122f, 0xdf4: 0x1257, 0xdf5: 0x12cb,
+ 0xdf6: 0x1313, 0xdf7: 0x131f, 0xdf8: 0x1327, 0xdf9: 0x133f, 0xdfa: 0x1353, 0xdfb: 0x1343,
+ 0xdfc: 0x135b, 0xdfd: 0x1357, 0xdfe: 0x134f, 0xdff: 0x135f,
+ // Block 0x38, offset 0xe00
+ 0xe00: 0x136b, 0xe01: 0x13a7, 0xe02: 0x13e3, 0xe03: 0x1413, 0xe04: 0x144b, 0xe05: 0x146b,
+ 0xe06: 0x14b7, 0xe07: 0x14db, 0xe08: 0x14fb, 0xe09: 0x150f, 0xe0a: 0x151f, 0xe0b: 0x152b,
+ 0xe0c: 0x1537, 0xe0d: 0x158b, 0xe0e: 0x162b, 0xe0f: 0x16b5, 0xe10: 0x16b0, 0xe11: 0x16e2,
+ 0xe12: 0x0607, 0xe13: 0x062f, 0xe14: 0x0633, 0xe15: 0x1764, 0xe16: 0x1791, 0xe17: 0x1809,
+ 0xe18: 0x1617, 0xe19: 0x1627,
+ // Block 0x39, offset 0xe40
+ 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,
+ 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,
+ // 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,
+ 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,
+ 0xea4: 0x02a8, 0xea5: 0x02a8, 0xea6: 0x029c, 0xea7: 0x029c, 0xea8: 0x029c, 0xea9: 0x029c,
+ 0xeaa: 0x02cf, 0xeab: 0x02cf, 0xeac: 0x02cf, 0xead: 0x02cf, 0xeae: 0x02d2, 0xeaf: 0x02d2,
+ 0xeb0: 0x02d2, 0xeb1: 0x02d2, 0xeb2: 0x02b1, 0xeb3: 0x02b1, 0xeb4: 0x02b1, 0xeb5: 0x02b1,
+ 0xeb6: 0x02ae, 0xeb7: 0x02ae, 0xeb8: 0x02ae, 0xeb9: 0x02ae, 0xeba: 0x02b4, 0xebb: 0x02b4,
+ 0xebc: 0x02b4, 0xebd: 0x02b4, 0xebe: 0x02b7, 0xebf: 0x02b7,
+ // Block 0x3b, offset 0xec0
+ 0xec0: 0x02b7, 0xec1: 0x02b7, 0xec2: 0x02c0, 0xec3: 0x02c0, 0xec4: 0x02bd, 0xec5: 0x02bd,
+ 0xec6: 0x02c3, 0xec7: 0x02c3, 0xec8: 0x02ba, 0xec9: 0x02ba, 0xeca: 0x02c9, 0xecb: 0x02c9,
+ 0xecc: 0x02c6, 0xecd: 0x02c6, 0xece: 0x02d5, 0xecf: 0x02d5, 0xed0: 0x02d5, 0xed1: 0x02d5,
+ 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,
+ 0xeea: 0x02ea, 0xeeb: 0x02ea, 0xeec: 0x02ea, 0xeed: 0x02ea, 0xeee: 0x0308, 0xeef: 0x0308,
+ 0xef0: 0x44fe, 0xef1: 0x44fe,
+ // 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,
+ 0xf1e: 0x02ff, 0xf1f: 0x02ff, 0xf20: 0x02f0, 0xf21: 0x02f0, 0xf22: 0x02fc, 0xf23: 0x02fc,
+ 0xf24: 0x0305, 0xf25: 0x0305, 0xf26: 0x0305, 0xf27: 0x0305, 0xf28: 0x028d, 0xf29: 0x028d,
+ 0xf2a: 0x25aa, 0xf2b: 0x25aa, 0xf2c: 0x261a, 0xf2d: 0x261a, 0xf2e: 0x25e9, 0xf2f: 0x25e9,
+ 0xf30: 0x2605, 0xf31: 0x2605, 0xf32: 0x25fe, 0xf33: 0x25fe, 0xf34: 0x260c, 0xf35: 0x260c,
+ 0xf36: 0x2613, 0xf37: 0x2613, 0xf38: 0x2613, 0xf39: 0x25f0, 0xf3a: 0x25f0, 0xf3b: 0x25f0,
+ 0xf3c: 0x0302, 0xf3d: 0x0302, 0xf3e: 0x0302, 0xf3f: 0x0302,
+ // Block 0x3d, offset 0xf40
+ 0xf40: 0x25b1, 0xf41: 0x25b8, 0xf42: 0x25d4, 0xf43: 0x25f0, 0xf44: 0x25f7, 0xf45: 0x1d89,
+ 0xf46: 0x1d8e, 0xf47: 0x1d93, 0xf48: 0x1da2, 0xf49: 0x1db1, 0xf4a: 0x1db6, 0xf4b: 0x1dbb,
+ 0xf4c: 0x1dc0, 0xf4d: 0x1dc5, 0xf4e: 0x1dd4, 0xf4f: 0x1de3, 0xf50: 0x1de8, 0xf51: 0x1ded,
+ 0xf52: 0x1dfc, 0xf53: 0x1e0b, 0xf54: 0x1e10, 0xf55: 0x1e15, 0xf56: 0x1e1a, 0xf57: 0x1e29,
+ 0xf58: 0x1e2e, 0xf59: 0x1e3d, 0xf5a: 0x1e42, 0xf5b: 0x1e47, 0xf5c: 0x1e56, 0xf5d: 0x1e5b,
+ 0xf5e: 0x1e60, 0xf5f: 0x1e6a, 0xf60: 0x1ea6, 0xf61: 0x1eb5, 0xf62: 0x1ec4, 0xf63: 0x1ec9,
+ 0xf64: 0x1ece, 0xf65: 0x1ed8, 0xf66: 0x1ee7, 0xf67: 0x1eec, 0xf68: 0x1efb, 0xf69: 0x1f00,
+ 0xf6a: 0x1f05, 0xf6b: 0x1f14, 0xf6c: 0x1f19, 0xf6d: 0x1f28, 0xf6e: 0x1f2d, 0xf6f: 0x1f32,
+ 0xf70: 0x1f37, 0xf71: 0x1f3c, 0xf72: 0x1f41, 0xf73: 0x1f46, 0xf74: 0x1f4b, 0xf75: 0x1f50,
+ 0xf76: 0x1f55, 0xf77: 0x1f5a, 0xf78: 0x1f5f, 0xf79: 0x1f64, 0xf7a: 0x1f69, 0xf7b: 0x1f6e,
+ 0xf7c: 0x1f73, 0xf7d: 0x1f78, 0xf7e: 0x1f7d, 0xf7f: 0x1f87,
+ // Block 0x3e, offset 0xf80
+ 0xf80: 0x1f8c, 0xf81: 0x1f91, 0xf82: 0x1f96, 0xf83: 0x1fa0, 0xf84: 0x1fa5, 0xf85: 0x1faf,
+ 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,
+ 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,
+ 0xfb6: 0x1df2, 0xfb7: 0x1df7, 0xfb8: 0x1dfc, 0xfb9: 0x1e01, 0xfba: 0x1e0b, 0xfbb: 0x1e10,
+ 0xfbc: 0x1f3c, 0xfbd: 0x1f41, 0xfbe: 0x1f50, 0xfbf: 0x1f55,
+ // 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,
+ 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,
+ 0xfe4: 0x1dd4, 0xfe5: 0x1dde, 0xfe6: 0x1dfc, 0xfe7: 0x1e15, 0xfe8: 0x1e1a, 0xfe9: 0x1e29,
+ 0xfea: 0x1e2e, 0xfeb: 0x1e3d, 0xfec: 0x1e47, 0xfed: 0x1e56, 0xfee: 0x1e5b, 0xfef: 0x1e60,
+ 0xff0: 0x1e6a, 0xff1: 0x1ea6, 0xff2: 0x1eab, 0xff3: 0x1eb5, 0xff4: 0x1ec4, 0xff5: 0x1ec9,
+ 0xff6: 0x1ece, 0xff7: 0x1ed8, 0xff8: 0x1ee7, 0xff9: 0x1efb, 0xffa: 0x1f00, 0xffb: 0x1f05,
+ 0xffc: 0x1f14, 0xffd: 0x1f19, 0xffe: 0x1f28, 0xfff: 0x1f2d,
+ // Block 0x40, offset 0x1000
+ 0x1000: 0x1f32, 0x1001: 0x1f37, 0x1002: 0x1f46, 0x1003: 0x1f4b, 0x1004: 0x1f5f, 0x1005: 0x1f64,
+ 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,
+ 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,
+ 0x1036: 0x1ef6, 0x1037: 0x1f0a, 0x1038: 0x1f0f, 0x1039: 0x1f1e, 0x103a: 0x1f23, 0x103b: 0x1e74,
+ 0x103c: 0x1e79, 0x103d: 0x1e9c, 0x103e: 0x1ea1, 0x103f: 0x1e33,
+ // Block 0x41, offset 0x1040
+ 0x1040: 0x1e38, 0x1041: 0x1e1f, 0x1042: 0x1e24, 0x1043: 0x1e4c, 0x1044: 0x1e51, 0x1045: 0x1eba,
+ 0x1046: 0x1ebf, 0x1047: 0x1edd, 0x1048: 0x1ee2, 0x1049: 0x1e7e, 0x104a: 0x1e83, 0x104b: 0x1e88,
+ 0x104c: 0x1e92, 0x104d: 0x1e8d, 0x104e: 0x1e65, 0x104f: 0x1eb0, 0x1050: 0x1ed3, 0x1051: 0x1ef1,
+ 0x1052: 0x1ef6, 0x1053: 0x1f0a, 0x1054: 0x1f0f, 0x1055: 0x1f1e, 0x1056: 0x1f23, 0x1057: 0x1e74,
+ 0x1058: 0x1e79, 0x1059: 0x1e9c, 0x105a: 0x1ea1, 0x105b: 0x1e33, 0x105c: 0x1e38, 0x105d: 0x1e1f,
+ 0x105e: 0x1e24, 0x105f: 0x1e4c, 0x1060: 0x1e51, 0x1061: 0x1eba, 0x1062: 0x1ebf, 0x1063: 0x1edd,
+ 0x1064: 0x1ee2, 0x1065: 0x1e7e, 0x1066: 0x1e83, 0x1067: 0x1e88, 0x1068: 0x1e92, 0x1069: 0x1e8d,
+ 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,
+ // Block 0x42, offset 0x1080
+ 0x1090: 0x2311, 0x1091: 0x2326,
+ 0x1092: 0x2326, 0x1093: 0x232d, 0x1094: 0x2334, 0x1095: 0x2349, 0x1096: 0x2350, 0x1097: 0x2357,
+ 0x1098: 0x237a, 0x1099: 0x237a, 0x109a: 0x239d, 0x109b: 0x2396, 0x109c: 0x23b2, 0x109d: 0x23a4,
+ 0x109e: 0x23ab, 0x109f: 0x23ce, 0x10a0: 0x23ce, 0x10a1: 0x23c7, 0x10a2: 0x23d5, 0x10a3: 0x23d5,
+ 0x10a4: 0x23ff, 0x10a5: 0x23ff, 0x10a6: 0x241b, 0x10a7: 0x23e3, 0x10a8: 0x23e3, 0x10a9: 0x23dc,
+ 0x10aa: 0x23f1, 0x10ab: 0x23f1, 0x10ac: 0x23f8, 0x10ad: 0x23f8, 0x10ae: 0x2422, 0x10af: 0x2430,
+ 0x10b0: 0x2430, 0x10b1: 0x2437, 0x10b2: 0x2437, 0x10b3: 0x243e, 0x10b4: 0x2445, 0x10b5: 0x244c,
+ 0x10b6: 0x2453, 0x10b7: 0x2453, 0x10b8: 0x245a, 0x10b9: 0x2468, 0x10ba: 0x2476, 0x10bb: 0x246f,
+ 0x10bc: 0x247d, 0x10bd: 0x247d, 0x10be: 0x2492, 0x10bf: 0x2499,
+ // Block 0x43, offset 0x10c0
+ 0x10c0: 0x24ca, 0x10c1: 0x24d8, 0x10c2: 0x24d1, 0x10c3: 0x24b5, 0x10c4: 0x24b5, 0x10c5: 0x24df,
+ 0x10c6: 0x24df, 0x10c7: 0x24e6, 0x10c8: 0x24e6, 0x10c9: 0x2510, 0x10ca: 0x2517, 0x10cb: 0x251e,
+ 0x10cc: 0x24f4, 0x10cd: 0x2502, 0x10ce: 0x2525, 0x10cf: 0x252c,
+ 0x10d2: 0x24fb, 0x10d3: 0x2580, 0x10d4: 0x2587, 0x10d5: 0x255d, 0x10d6: 0x2564, 0x10d7: 0x2548,
+ 0x10d8: 0x2548, 0x10d9: 0x254f, 0x10da: 0x2579, 0x10db: 0x2572, 0x10dc: 0x259c, 0x10dd: 0x259c,
+ 0x10de: 0x230a, 0x10df: 0x231f, 0x10e0: 0x2318, 0x10e1: 0x2342, 0x10e2: 0x233b, 0x10e3: 0x2365,
+ 0x10e4: 0x235e, 0x10e5: 0x2388, 0x10e6: 0x236c, 0x10e7: 0x2381, 0x10e8: 0x23b9, 0x10e9: 0x2406,
+ 0x10ea: 0x23ea, 0x10eb: 0x2429, 0x10ec: 0x24c3, 0x10ed: 0x24ed, 0x10ee: 0x2595, 0x10ef: 0x258e,
+ 0x10f0: 0x25a3, 0x10f1: 0x253a, 0x10f2: 0x24a0, 0x10f3: 0x256b, 0x10f4: 0x2492, 0x10f5: 0x24ca,
+ 0x10f6: 0x2461, 0x10f7: 0x24ae, 0x10f8: 0x2541, 0x10f9: 0x2533, 0x10fa: 0x24bc, 0x10fb: 0x24a7,
+ 0x10fc: 0x24bc, 0x10fd: 0x2541, 0x10fe: 0x2373, 0x10ff: 0x238f,
+ // Block 0x44, offset 0x1100
+ 0x1100: 0x2509, 0x1101: 0x2484, 0x1102: 0x2303, 0x1103: 0x24a7, 0x1104: 0x244c, 0x1105: 0x241b,
+ 0x1106: 0x23c0, 0x1107: 0x2556,
+ 0x1130: 0x2414, 0x1131: 0x248b, 0x1132: 0x27bf, 0x1133: 0x27b6, 0x1134: 0x27ec, 0x1135: 0x27da,
+ 0x1136: 0x27c8, 0x1137: 0x27e3, 0x1138: 0x27f5, 0x1139: 0x240d, 0x113a: 0x2c7c, 0x113b: 0x2afc,
+ 0x113c: 0x27d1,
+ // Block 0x45, offset 0x1140
+ 0x1150: 0x0019, 0x1151: 0x0483,
+ 0x1152: 0x0487, 0x1153: 0x0035, 0x1154: 0x0037, 0x1155: 0x0003, 0x1156: 0x003f, 0x1157: 0x04bf,
+ 0x1158: 0x04c3, 0x1159: 0x1b5c,
+ 0x1160: 0x8132, 0x1161: 0x8132, 0x1162: 0x8132, 0x1163: 0x8132,
+ 0x1164: 0x8132, 0x1165: 0x8132, 0x1166: 0x8132, 0x1167: 0x812d, 0x1168: 0x812d, 0x1169: 0x812d,
+ 0x116a: 0x812d, 0x116b: 0x812d, 0x116c: 0x812d, 0x116d: 0x812d, 0x116e: 0x8132, 0x116f: 0x8132,
+ 0x1170: 0x1873, 0x1171: 0x0443, 0x1172: 0x043f, 0x1173: 0x007f, 0x1174: 0x007f, 0x1175: 0x0011,
+ 0x1176: 0x0013, 0x1177: 0x00b7, 0x1178: 0x00bb, 0x1179: 0x04b7, 0x117a: 0x04bb, 0x117b: 0x04ab,
+ 0x117c: 0x04af, 0x117d: 0x0493, 0x117e: 0x0497, 0x117f: 0x048b,
+ // Block 0x46, offset 0x1180
+ 0x1180: 0x048f, 0x1181: 0x049b, 0x1182: 0x049f, 0x1183: 0x04a3, 0x1184: 0x04a7,
+ 0x1187: 0x0077, 0x1188: 0x007b, 0x1189: 0x4269, 0x118a: 0x4269, 0x118b: 0x4269,
+ 0x118c: 0x4269, 0x118d: 0x007f, 0x118e: 0x007f, 0x118f: 0x007f, 0x1190: 0x0019, 0x1191: 0x0483,
+ 0x1192: 0x001d, 0x1194: 0x0037, 0x1195: 0x0035, 0x1196: 0x003f, 0x1197: 0x0003,
+ 0x1198: 0x0443, 0x1199: 0x0011, 0x119a: 0x0013, 0x119b: 0x00b7, 0x119c: 0x00bb, 0x119d: 0x04b7,
+ 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,
+ // 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,
+ 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,
+ 0x11e4: 0x024b, 0x11e5: 0x024e, 0x11e6: 0x024e, 0x11e7: 0x024e, 0x11e8: 0x024e, 0x11e9: 0x0251,
+ 0x11ea: 0x0251, 0x11eb: 0x0254, 0x11ec: 0x0254, 0x11ed: 0x0257, 0x11ee: 0x0257, 0x11ef: 0x025a,
+ 0x11f0: 0x025a, 0x11f1: 0x025d, 0x11f2: 0x025d, 0x11f3: 0x025d, 0x11f4: 0x025d, 0x11f5: 0x0260,
+ 0x11f6: 0x0260, 0x11f7: 0x0260, 0x11f8: 0x0260, 0x11f9: 0x0263, 0x11fa: 0x0263, 0x11fb: 0x0263,
+ 0x11fc: 0x0263, 0x11fd: 0x0266, 0x11fe: 0x0266, 0x11ff: 0x0266,
+ // Block 0x48, offset 0x1200
+ 0x1200: 0x0266, 0x1201: 0x0269, 0x1202: 0x0269, 0x1203: 0x0269, 0x1204: 0x0269, 0x1205: 0x026c,
+ 0x1206: 0x026c, 0x1207: 0x026c, 0x1208: 0x026c, 0x1209: 0x026f, 0x120a: 0x026f, 0x120b: 0x026f,
+ 0x120c: 0x026f, 0x120d: 0x0272, 0x120e: 0x0272, 0x120f: 0x0272, 0x1210: 0x0272, 0x1211: 0x0275,
+ 0x1212: 0x0275, 0x1213: 0x0275, 0x1214: 0x0275, 0x1215: 0x0278, 0x1216: 0x0278, 0x1217: 0x0278,
+ 0x1218: 0x0278, 0x1219: 0x027b, 0x121a: 0x027b, 0x121b: 0x027b, 0x121c: 0x027b, 0x121d: 0x027e,
+ 0x121e: 0x027e, 0x121f: 0x027e, 0x1220: 0x027e, 0x1221: 0x0281, 0x1222: 0x0281, 0x1223: 0x0281,
+ 0x1224: 0x0281, 0x1225: 0x0284, 0x1226: 0x0284, 0x1227: 0x0284, 0x1228: 0x0284, 0x1229: 0x0287,
+ 0x122a: 0x0287, 0x122b: 0x0287, 0x122c: 0x0287, 0x122d: 0x028a, 0x122e: 0x028a, 0x122f: 0x028d,
+ 0x1230: 0x028d, 0x1231: 0x0290, 0x1232: 0x0290, 0x1233: 0x0290, 0x1234: 0x0290, 0x1235: 0x2e00,
+ 0x1236: 0x2e00, 0x1237: 0x2e08, 0x1238: 0x2e08, 0x1239: 0x2e10, 0x123a: 0x2e10, 0x123b: 0x1f82,
+ 0x123c: 0x1f82,
+ // Block 0x49, offset 0x1240
+ 0x1240: 0x0081, 0x1241: 0x0083, 0x1242: 0x0085, 0x1243: 0x0087, 0x1244: 0x0089, 0x1245: 0x008b,
+ 0x1246: 0x008d, 0x1247: 0x008f, 0x1248: 0x0091, 0x1249: 0x0093, 0x124a: 0x0095, 0x124b: 0x0097,
+ 0x124c: 0x0099, 0x124d: 0x009b, 0x124e: 0x009d, 0x124f: 0x009f, 0x1250: 0x00a1, 0x1251: 0x00a3,
+ 0x1252: 0x00a5, 0x1253: 0x00a7, 0x1254: 0x00a9, 0x1255: 0x00ab, 0x1256: 0x00ad, 0x1257: 0x00af,
+ 0x1258: 0x00b1, 0x1259: 0x00b3, 0x125a: 0x00b5, 0x125b: 0x00b7, 0x125c: 0x00b9, 0x125d: 0x00bb,
+ 0x125e: 0x00bd, 0x125f: 0x0477, 0x1260: 0x047b, 0x1261: 0x0487, 0x1262: 0x049b, 0x1263: 0x049f,
+ 0x1264: 0x0483, 0x1265: 0x05ab, 0x1266: 0x05a3, 0x1267: 0x04c7, 0x1268: 0x04cf, 0x1269: 0x04d7,
+ 0x126a: 0x04df, 0x126b: 0x04e7, 0x126c: 0x056b, 0x126d: 0x0573, 0x126e: 0x057b, 0x126f: 0x051f,
+ 0x1270: 0x05af, 0x1271: 0x04cb, 0x1272: 0x04d3, 0x1273: 0x04db, 0x1274: 0x04e3, 0x1275: 0x04eb,
+ 0x1276: 0x04ef, 0x1277: 0x04f3, 0x1278: 0x04f7, 0x1279: 0x04fb, 0x127a: 0x04ff, 0x127b: 0x0503,
+ 0x127c: 0x0507, 0x127d: 0x050b, 0x127e: 0x050f, 0x127f: 0x0513,
+ // Block 0x4a, offset 0x1280
+ 0x1280: 0x0517, 0x1281: 0x051b, 0x1282: 0x0523, 0x1283: 0x0527, 0x1284: 0x052b, 0x1285: 0x052f,
+ 0x1286: 0x0533, 0x1287: 0x0537, 0x1288: 0x053b, 0x1289: 0x053f, 0x128a: 0x0543, 0x128b: 0x0547,
+ 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,
+ 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,
+ 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,
+ // Block 0x4c, offset 0x1300
+ 0x1300: 0x0063, 0x1301: 0x0065, 0x1302: 0x0067, 0x1303: 0x0069, 0x1304: 0x006b, 0x1305: 0x006d,
+ 0x1306: 0x006f, 0x1307: 0x0071, 0x1308: 0x0073, 0x1309: 0x0075, 0x130a: 0x0083, 0x130b: 0x0085,
+ 0x130c: 0x0087, 0x130d: 0x0089, 0x130e: 0x008b, 0x130f: 0x008d, 0x1310: 0x008f, 0x1311: 0x0091,
+ 0x1312: 0x0093, 0x1313: 0x0095, 0x1314: 0x0097, 0x1315: 0x0099, 0x1316: 0x009b, 0x1317: 0x009d,
+ 0x1318: 0x009f, 0x1319: 0x00a1, 0x131a: 0x00a3, 0x131b: 0x00a5, 0x131c: 0x00a7, 0x131d: 0x00a9,
+ 0x131e: 0x00ab, 0x131f: 0x00ad, 0x1320: 0x00af, 0x1321: 0x00b1, 0x1322: 0x00b3, 0x1323: 0x00b5,
+ 0x1324: 0x00dd, 0x1325: 0x00f2, 0x1328: 0x0173, 0x1329: 0x0176,
+ 0x132a: 0x0179, 0x132b: 0x017c, 0x132c: 0x017f, 0x132d: 0x0182, 0x132e: 0x0185, 0x132f: 0x0188,
+ 0x1330: 0x018b, 0x1331: 0x018e, 0x1332: 0x0191, 0x1333: 0x0194, 0x1334: 0x0197, 0x1335: 0x019a,
+ 0x1336: 0x019d, 0x1337: 0x01a0, 0x1338: 0x01a3, 0x1339: 0x0188, 0x133a: 0x01a6, 0x133b: 0x01a9,
+ 0x133c: 0x01ac, 0x133d: 0x01af, 0x133e: 0x01b2, 0x133f: 0x01b5,
+ // Block 0x4d, offset 0x1340
+ 0x1340: 0x01fd, 0x1341: 0x0200, 0x1342: 0x0203, 0x1343: 0x045b, 0x1344: 0x01c7, 0x1345: 0x01d0,
+ 0x1346: 0x01d6, 0x1347: 0x01fa, 0x1348: 0x01eb, 0x1349: 0x01e8, 0x134a: 0x0206, 0x134b: 0x0209,
+ 0x134e: 0x0021, 0x134f: 0x0023, 0x1350: 0x0025, 0x1351: 0x0027,
+ 0x1352: 0x0029, 0x1353: 0x002b, 0x1354: 0x002d, 0x1355: 0x002f, 0x1356: 0x0031, 0x1357: 0x0033,
+ 0x1358: 0x0021, 0x1359: 0x0023, 0x135a: 0x0025, 0x135b: 0x0027, 0x135c: 0x0029, 0x135d: 0x002b,
+ 0x135e: 0x002d, 0x135f: 0x002f, 0x1360: 0x0031, 0x1361: 0x0033, 0x1362: 0x0021, 0x1363: 0x0023,
+ 0x1364: 0x0025, 0x1365: 0x0027, 0x1366: 0x0029, 0x1367: 0x002b, 0x1368: 0x002d, 0x1369: 0x002f,
+ 0x136a: 0x0031, 0x136b: 0x0033, 0x136c: 0x0021, 0x136d: 0x0023, 0x136e: 0x0025, 0x136f: 0x0027,
+ 0x1370: 0x0029, 0x1371: 0x002b, 0x1372: 0x002d, 0x1373: 0x002f, 0x1374: 0x0031, 0x1375: 0x0033,
+ 0x1376: 0x0021, 0x1377: 0x0023, 0x1378: 0x0025, 0x1379: 0x0027, 0x137a: 0x0029, 0x137b: 0x002b,
+ 0x137c: 0x002d, 0x137d: 0x002f, 0x137e: 0x0031, 0x137f: 0x0033,
+ // Block 0x4e, offset 0x1380
+ 0x1380: 0x0239, 0x1381: 0x023c, 0x1382: 0x0248, 0x1383: 0x0251, 0x1385: 0x028a,
+ 0x1386: 0x025a, 0x1387: 0x024b, 0x1388: 0x0269, 0x1389: 0x0290, 0x138a: 0x027b, 0x138b: 0x027e,
+ 0x138c: 0x0281, 0x138d: 0x0284, 0x138e: 0x025d, 0x138f: 0x026f, 0x1390: 0x0275, 0x1391: 0x0263,
+ 0x1392: 0x0278, 0x1393: 0x0257, 0x1394: 0x0260, 0x1395: 0x0242, 0x1396: 0x0245, 0x1397: 0x024e,
+ 0x1398: 0x0254, 0x1399: 0x0266, 0x139a: 0x026c, 0x139b: 0x0272, 0x139c: 0x0293, 0x139d: 0x02e4,
+ 0x139e: 0x02cc, 0x139f: 0x0296, 0x13a1: 0x023c, 0x13a2: 0x0248,
+ 0x13a4: 0x0287, 0x13a7: 0x024b, 0x13a9: 0x0290,
+ 0x13aa: 0x027b, 0x13ab: 0x027e, 0x13ac: 0x0281, 0x13ad: 0x0284, 0x13ae: 0x025d, 0x13af: 0x026f,
+ 0x13b0: 0x0275, 0x13b1: 0x0263, 0x13b2: 0x0278, 0x13b4: 0x0260, 0x13b5: 0x0242,
+ 0x13b6: 0x0245, 0x13b7: 0x024e, 0x13b9: 0x0266, 0x13bb: 0x0272,
+ // Block 0x4f, offset 0x13c0
+ 0x13c2: 0x0248,
+ 0x13c7: 0x024b, 0x13c9: 0x0290, 0x13cb: 0x027e,
+ 0x13cd: 0x0284, 0x13ce: 0x025d, 0x13cf: 0x026f, 0x13d1: 0x0263,
+ 0x13d2: 0x0278, 0x13d4: 0x0260, 0x13d7: 0x024e,
+ 0x13d9: 0x0266, 0x13db: 0x0272, 0x13dd: 0x02e4,
+ 0x13df: 0x0296, 0x13e1: 0x023c, 0x13e2: 0x0248,
+ 0x13e4: 0x0287, 0x13e7: 0x024b, 0x13e8: 0x0269, 0x13e9: 0x0290,
+ 0x13ea: 0x027b, 0x13ec: 0x0281, 0x13ed: 0x0284, 0x13ee: 0x025d, 0x13ef: 0x026f,
+ 0x13f0: 0x0275, 0x13f1: 0x0263, 0x13f2: 0x0278, 0x13f4: 0x0260, 0x13f5: 0x0242,
+ 0x13f6: 0x0245, 0x13f7: 0x024e, 0x13f9: 0x0266, 0x13fa: 0x026c, 0x13fb: 0x0272,
+ 0x13fc: 0x0293, 0x13fe: 0x02cc,
+ // Block 0x50, offset 0x1400
+ 0x1400: 0x0239, 0x1401: 0x023c, 0x1402: 0x0248, 0x1403: 0x0251, 0x1404: 0x0287, 0x1405: 0x028a,
+ 0x1406: 0x025a, 0x1407: 0x024b, 0x1408: 0x0269, 0x1409: 0x0290, 0x140b: 0x027e,
+ 0x140c: 0x0281, 0x140d: 0x0284, 0x140e: 0x025d, 0x140f: 0x026f, 0x1410: 0x0275, 0x1411: 0x0263,
+ 0x1412: 0x0278, 0x1413: 0x0257, 0x1414: 0x0260, 0x1415: 0x0242, 0x1416: 0x0245, 0x1417: 0x024e,
+ 0x1418: 0x0254, 0x1419: 0x0266, 0x141a: 0x026c, 0x141b: 0x0272,
+ 0x1421: 0x023c, 0x1422: 0x0248, 0x1423: 0x0251,
+ 0x1425: 0x028a, 0x1426: 0x025a, 0x1427: 0x024b, 0x1428: 0x0269, 0x1429: 0x0290,
+ 0x142b: 0x027e, 0x142c: 0x0281, 0x142d: 0x0284, 0x142e: 0x025d, 0x142f: 0x026f,
+ 0x1430: 0x0275, 0x1431: 0x0263, 0x1432: 0x0278, 0x1433: 0x0257, 0x1434: 0x0260, 0x1435: 0x0242,
+ 0x1436: 0x0245, 0x1437: 0x024e, 0x1438: 0x0254, 0x1439: 0x0266, 0x143a: 0x026c, 0x143b: 0x0272,
+ // Block 0x51, offset 0x1440
+ 0x1440: 0x1879, 0x1441: 0x1876, 0x1442: 0x187c, 0x1443: 0x18a0, 0x1444: 0x18c4, 0x1445: 0x18e8,
+ 0x1446: 0x190c, 0x1447: 0x1915, 0x1448: 0x191b, 0x1449: 0x1921, 0x144a: 0x1927,
+ 0x1450: 0x1a8c, 0x1451: 0x1a90,
+ 0x1452: 0x1a94, 0x1453: 0x1a98, 0x1454: 0x1a9c, 0x1455: 0x1aa0, 0x1456: 0x1aa4, 0x1457: 0x1aa8,
+ 0x1458: 0x1aac, 0x1459: 0x1ab0, 0x145a: 0x1ab4, 0x145b: 0x1ab8, 0x145c: 0x1abc, 0x145d: 0x1ac0,
+ 0x145e: 0x1ac4, 0x145f: 0x1ac8, 0x1460: 0x1acc, 0x1461: 0x1ad0, 0x1462: 0x1ad4, 0x1463: 0x1ad8,
+ 0x1464: 0x1adc, 0x1465: 0x1ae0, 0x1466: 0x1ae4, 0x1467: 0x1ae8, 0x1468: 0x1aec, 0x1469: 0x1af0,
+ 0x146a: 0x271e, 0x146b: 0x0047, 0x146c: 0x0065, 0x146d: 0x193c, 0x146e: 0x19b1,
+ 0x1470: 0x0043, 0x1471: 0x0045, 0x1472: 0x0047, 0x1473: 0x0049, 0x1474: 0x004b, 0x1475: 0x004d,
+ 0x1476: 0x004f, 0x1477: 0x0051, 0x1478: 0x0053, 0x1479: 0x0055, 0x147a: 0x0057, 0x147b: 0x0059,
+ 0x147c: 0x005b, 0x147d: 0x005d, 0x147e: 0x005f, 0x147f: 0x0061,
+ // 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,
+ 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,
+ 0x14aa: 0x06cb, 0x14ab: 0x140b, 0x14ac: 0x0adb, 0x14ad: 0x06e7, 0x14ae: 0x08ef, 0x14af: 0x0c3b,
+ 0x14b0: 0x13b3, 0x14b1: 0x0c13, 0x14b2: 0x106f, 0x14b3: 0x10ab, 0x14b4: 0x08f7, 0x14b5: 0x0e43,
+ 0x14b6: 0x0d0b, 0x14b7: 0x0d07, 0x14b8: 0x0f97, 0x14b9: 0x082b, 0x14ba: 0x0957, 0x14bb: 0x1443,
+ // Block 0x53, offset 0x14c0
+ 0x14c0: 0x06fb, 0x14c1: 0x06f3, 0x14c2: 0x0703, 0x14c3: 0x1647, 0x14c4: 0x0747, 0x14c5: 0x0757,
+ 0x14c6: 0x075b, 0x14c7: 0x0763, 0x14c8: 0x076b, 0x14c9: 0x076f, 0x14ca: 0x077b, 0x14cb: 0x0773,
+ 0x14cc: 0x05b3, 0x14cd: 0x165b, 0x14ce: 0x078f, 0x14cf: 0x0793, 0x14d0: 0x0797, 0x14d1: 0x07b3,
+ 0x14d2: 0x164c, 0x14d3: 0x05b7, 0x14d4: 0x079f, 0x14d5: 0x07bf, 0x14d6: 0x1656, 0x14d7: 0x07cf,
+ 0x14d8: 0x07d7, 0x14d9: 0x0737, 0x14da: 0x07df, 0x14db: 0x07e3, 0x14dc: 0x1831, 0x14dd: 0x07ff,
+ 0x14de: 0x0807, 0x14df: 0x05bf, 0x14e0: 0x081f, 0x14e1: 0x0823, 0x14e2: 0x082b, 0x14e3: 0x082f,
+ 0x14e4: 0x05c3, 0x14e5: 0x0847, 0x14e6: 0x084b, 0x14e7: 0x0857, 0x14e8: 0x0863, 0x14e9: 0x0867,
+ 0x14ea: 0x086b, 0x14eb: 0x0873, 0x14ec: 0x0893, 0x14ed: 0x0897, 0x14ee: 0x089f, 0x14ef: 0x08af,
+ 0x14f0: 0x08b7, 0x14f1: 0x08bb, 0x14f2: 0x08bb, 0x14f3: 0x08bb, 0x14f4: 0x166a, 0x14f5: 0x0e93,
+ 0x14f6: 0x08cf, 0x14f7: 0x08d7, 0x14f8: 0x166f, 0x14f9: 0x08e3, 0x14fa: 0x08eb, 0x14fb: 0x08f3,
+ 0x14fc: 0x091b, 0x14fd: 0x0907, 0x14fe: 0x0913, 0x14ff: 0x0917,
+ // Block 0x54, offset 0x1500
+ 0x1500: 0x091f, 0x1501: 0x0927, 0x1502: 0x092b, 0x1503: 0x0933, 0x1504: 0x093b, 0x1505: 0x093f,
+ 0x1506: 0x093f, 0x1507: 0x0947, 0x1508: 0x094f, 0x1509: 0x0953, 0x150a: 0x095f, 0x150b: 0x0983,
+ 0x150c: 0x0967, 0x150d: 0x0987, 0x150e: 0x096b, 0x150f: 0x0973, 0x1510: 0x080b, 0x1511: 0x09cf,
+ 0x1512: 0x0997, 0x1513: 0x099b, 0x1514: 0x099f, 0x1515: 0x0993, 0x1516: 0x09a7, 0x1517: 0x09a3,
+ 0x1518: 0x09bb, 0x1519: 0x1674, 0x151a: 0x09d7, 0x151b: 0x09db, 0x151c: 0x09e3, 0x151d: 0x09ef,
+ 0x151e: 0x09f7, 0x151f: 0x0a13, 0x1520: 0x1679, 0x1521: 0x167e, 0x1522: 0x0a1f, 0x1523: 0x0a23,
+ 0x1524: 0x0a27, 0x1525: 0x0a1b, 0x1526: 0x0a2f, 0x1527: 0x05c7, 0x1528: 0x05cb, 0x1529: 0x0a37,
+ 0x152a: 0x0a3f, 0x152b: 0x0a3f, 0x152c: 0x1683, 0x152d: 0x0a5b, 0x152e: 0x0a5f, 0x152f: 0x0a63,
+ 0x1530: 0x0a6b, 0x1531: 0x1688, 0x1532: 0x0a73, 0x1533: 0x0a77, 0x1534: 0x0b4f, 0x1535: 0x0a7f,
+ 0x1536: 0x05cf, 0x1537: 0x0a8b, 0x1538: 0x0a9b, 0x1539: 0x0aa7, 0x153a: 0x0aa3, 0x153b: 0x1692,
+ 0x153c: 0x0aaf, 0x153d: 0x1697, 0x153e: 0x0abb, 0x153f: 0x0ab7,
+ // Block 0x55, offset 0x1540
+ 0x1540: 0x0abf, 0x1541: 0x0acf, 0x1542: 0x0ad3, 0x1543: 0x05d3, 0x1544: 0x0ae3, 0x1545: 0x0aeb,
+ 0x1546: 0x0aef, 0x1547: 0x0af3, 0x1548: 0x05d7, 0x1549: 0x169c, 0x154a: 0x05db, 0x154b: 0x0b0f,
+ 0x154c: 0x0b13, 0x154d: 0x0b17, 0x154e: 0x0b1f, 0x154f: 0x1863, 0x1550: 0x0b37, 0x1551: 0x16a6,
+ 0x1552: 0x16a6, 0x1553: 0x11d7, 0x1554: 0x0b47, 0x1555: 0x0b47, 0x1556: 0x05df, 0x1557: 0x16c9,
+ 0x1558: 0x179b, 0x1559: 0x0b57, 0x155a: 0x0b5f, 0x155b: 0x05e3, 0x155c: 0x0b73, 0x155d: 0x0b83,
+ 0x155e: 0x0b87, 0x155f: 0x0b8f, 0x1560: 0x0b9f, 0x1561: 0x05eb, 0x1562: 0x05e7, 0x1563: 0x0ba3,
+ 0x1564: 0x16ab, 0x1565: 0x0ba7, 0x1566: 0x0bbb, 0x1567: 0x0bbf, 0x1568: 0x0bc3, 0x1569: 0x0bbf,
+ 0x156a: 0x0bcf, 0x156b: 0x0bd3, 0x156c: 0x0be3, 0x156d: 0x0bdb, 0x156e: 0x0bdf, 0x156f: 0x0be7,
+ 0x1570: 0x0beb, 0x1571: 0x0bef, 0x1572: 0x0bfb, 0x1573: 0x0bff, 0x1574: 0x0c17, 0x1575: 0x0c1f,
+ 0x1576: 0x0c2f, 0x1577: 0x0c43, 0x1578: 0x16ba, 0x1579: 0x0c3f, 0x157a: 0x0c33, 0x157b: 0x0c4b,
+ 0x157c: 0x0c53, 0x157d: 0x0c67, 0x157e: 0x16bf, 0x157f: 0x0c6f,
+ // Block 0x56, offset 0x1580
+ 0x1580: 0x0c63, 0x1581: 0x0c5b, 0x1582: 0x05ef, 0x1583: 0x0c77, 0x1584: 0x0c7f, 0x1585: 0x0c87,
+ 0x1586: 0x0c7b, 0x1587: 0x05f3, 0x1588: 0x0c97, 0x1589: 0x0c9f, 0x158a: 0x16c4, 0x158b: 0x0ccb,
+ 0x158c: 0x0cff, 0x158d: 0x0cdb, 0x158e: 0x05ff, 0x158f: 0x0ce7, 0x1590: 0x05fb, 0x1591: 0x05f7,
+ 0x1592: 0x07c3, 0x1593: 0x07c7, 0x1594: 0x0d03, 0x1595: 0x0ceb, 0x1596: 0x11ab, 0x1597: 0x0663,
+ 0x1598: 0x0d0f, 0x1599: 0x0d13, 0x159a: 0x0d17, 0x159b: 0x0d2b, 0x159c: 0x0d23, 0x159d: 0x16dd,
+ 0x159e: 0x0603, 0x159f: 0x0d3f, 0x15a0: 0x0d33, 0x15a1: 0x0d4f, 0x15a2: 0x0d57, 0x15a3: 0x16e7,
+ 0x15a4: 0x0d5b, 0x15a5: 0x0d47, 0x15a6: 0x0d63, 0x15a7: 0x0607, 0x15a8: 0x0d67, 0x15a9: 0x0d6b,
+ 0x15aa: 0x0d6f, 0x15ab: 0x0d7b, 0x15ac: 0x16ec, 0x15ad: 0x0d83, 0x15ae: 0x060b, 0x15af: 0x0d8f,
+ 0x15b0: 0x16f1, 0x15b1: 0x0d93, 0x15b2: 0x060f, 0x15b3: 0x0d9f, 0x15b4: 0x0dab, 0x15b5: 0x0db7,
+ 0x15b6: 0x0dbb, 0x15b7: 0x16f6, 0x15b8: 0x168d, 0x15b9: 0x16fb, 0x15ba: 0x0ddb, 0x15bb: 0x1700,
+ 0x15bc: 0x0de7, 0x15bd: 0x0def, 0x15be: 0x0ddf, 0x15bf: 0x0dfb,
+ // Block 0x57, offset 0x15c0
+ 0x15c0: 0x0e0b, 0x15c1: 0x0e1b, 0x15c2: 0x0e0f, 0x15c3: 0x0e13, 0x15c4: 0x0e1f, 0x15c5: 0x0e23,
+ 0x15c6: 0x1705, 0x15c7: 0x0e07, 0x15c8: 0x0e3b, 0x15c9: 0x0e3f, 0x15ca: 0x0613, 0x15cb: 0x0e53,
+ 0x15cc: 0x0e4f, 0x15cd: 0x170a, 0x15ce: 0x0e33, 0x15cf: 0x0e6f, 0x15d0: 0x170f, 0x15d1: 0x1714,
+ 0x15d2: 0x0e73, 0x15d3: 0x0e87, 0x15d4: 0x0e83, 0x15d5: 0x0e7f, 0x15d6: 0x0617, 0x15d7: 0x0e8b,
+ 0x15d8: 0x0e9b, 0x15d9: 0x0e97, 0x15da: 0x0ea3, 0x15db: 0x1651, 0x15dc: 0x0eb3, 0x15dd: 0x1719,
+ 0x15de: 0x0ebf, 0x15df: 0x1723, 0x15e0: 0x0ed3, 0x15e1: 0x0edf, 0x15e2: 0x0ef3, 0x15e3: 0x1728,
+ 0x15e4: 0x0f07, 0x15e5: 0x0f0b, 0x15e6: 0x172d, 0x15e7: 0x1732, 0x15e8: 0x0f27, 0x15e9: 0x0f37,
+ 0x15ea: 0x061b, 0x15eb: 0x0f3b, 0x15ec: 0x061f, 0x15ed: 0x061f, 0x15ee: 0x0f53, 0x15ef: 0x0f57,
+ 0x15f0: 0x0f5f, 0x15f1: 0x0f63, 0x15f2: 0x0f6f, 0x15f3: 0x0623, 0x15f4: 0x0f87, 0x15f5: 0x1737,
+ 0x15f6: 0x0fa3, 0x15f7: 0x173c, 0x15f8: 0x0faf, 0x15f9: 0x16a1, 0x15fa: 0x0fbf, 0x15fb: 0x1741,
+ 0x15fc: 0x1746, 0x15fd: 0x174b, 0x15fe: 0x0627, 0x15ff: 0x062b,
+ // Block 0x58, offset 0x1600
+ 0x1600: 0x0ff7, 0x1601: 0x1755, 0x1602: 0x1750, 0x1603: 0x175a, 0x1604: 0x175f, 0x1605: 0x0fff,
+ 0x1606: 0x1003, 0x1607: 0x1003, 0x1608: 0x100b, 0x1609: 0x0633, 0x160a: 0x100f, 0x160b: 0x0637,
+ 0x160c: 0x063b, 0x160d: 0x1769, 0x160e: 0x1023, 0x160f: 0x102b, 0x1610: 0x1037, 0x1611: 0x063f,
+ 0x1612: 0x176e, 0x1613: 0x105b, 0x1614: 0x1773, 0x1615: 0x1778, 0x1616: 0x107b, 0x1617: 0x1093,
+ 0x1618: 0x0643, 0x1619: 0x109b, 0x161a: 0x109f, 0x161b: 0x10a3, 0x161c: 0x177d, 0x161d: 0x1782,
+ 0x161e: 0x1782, 0x161f: 0x10bb, 0x1620: 0x0647, 0x1621: 0x1787, 0x1622: 0x10cf, 0x1623: 0x10d3,
+ 0x1624: 0x064b, 0x1625: 0x178c, 0x1626: 0x10ef, 0x1627: 0x064f, 0x1628: 0x10ff, 0x1629: 0x10f7,
+ 0x162a: 0x1107, 0x162b: 0x1796, 0x162c: 0x111f, 0x162d: 0x0653, 0x162e: 0x112b, 0x162f: 0x1133,
+ 0x1630: 0x1143, 0x1631: 0x0657, 0x1632: 0x17a0, 0x1633: 0x17a5, 0x1634: 0x065b, 0x1635: 0x17aa,
+ 0x1636: 0x115b, 0x1637: 0x17af, 0x1638: 0x1167, 0x1639: 0x1173, 0x163a: 0x117b, 0x163b: 0x17b4,
+ 0x163c: 0x17b9, 0x163d: 0x118f, 0x163e: 0x17be, 0x163f: 0x1197,
+ // Block 0x59, offset 0x1640
+ 0x1640: 0x16ce, 0x1641: 0x065f, 0x1642: 0x11af, 0x1643: 0x11b3, 0x1644: 0x0667, 0x1645: 0x11b7,
+ 0x1646: 0x0a33, 0x1647: 0x17c3, 0x1648: 0x17c8, 0x1649: 0x16d3, 0x164a: 0x16d8, 0x164b: 0x11d7,
+ 0x164c: 0x11db, 0x164d: 0x13f3, 0x164e: 0x066b, 0x164f: 0x1207, 0x1650: 0x1203, 0x1651: 0x120b,
+ 0x1652: 0x083f, 0x1653: 0x120f, 0x1654: 0x1213, 0x1655: 0x1217, 0x1656: 0x121f, 0x1657: 0x17cd,
+ 0x1658: 0x121b, 0x1659: 0x1223, 0x165a: 0x1237, 0x165b: 0x123b, 0x165c: 0x1227, 0x165d: 0x123f,
+ 0x165e: 0x1253, 0x165f: 0x1267, 0x1660: 0x1233, 0x1661: 0x1247, 0x1662: 0x124b, 0x1663: 0x124f,
+ 0x1664: 0x17d2, 0x1665: 0x17dc, 0x1666: 0x17d7, 0x1667: 0x066f, 0x1668: 0x126f, 0x1669: 0x1273,
+ 0x166a: 0x127b, 0x166b: 0x17f0, 0x166c: 0x127f, 0x166d: 0x17e1, 0x166e: 0x0673, 0x166f: 0x0677,
+ 0x1670: 0x17e6, 0x1671: 0x17eb, 0x1672: 0x067b, 0x1673: 0x129f, 0x1674: 0x12a3, 0x1675: 0x12a7,
+ 0x1676: 0x12ab, 0x1677: 0x12b7, 0x1678: 0x12b3, 0x1679: 0x12bf, 0x167a: 0x12bb, 0x167b: 0x12cb,
+ 0x167c: 0x12c3, 0x167d: 0x12c7, 0x167e: 0x12cf, 0x167f: 0x067f,
+ // Block 0x5a, offset 0x1680
+ 0x1680: 0x12d7, 0x1681: 0x12db, 0x1682: 0x0683, 0x1683: 0x12eb, 0x1684: 0x12ef, 0x1685: 0x17f5,
+ 0x1686: 0x12fb, 0x1687: 0x12ff, 0x1688: 0x0687, 0x1689: 0x130b, 0x168a: 0x05bb, 0x168b: 0x17fa,
+ 0x168c: 0x17ff, 0x168d: 0x068b, 0x168e: 0x068f, 0x168f: 0x1337, 0x1690: 0x134f, 0x1691: 0x136b,
+ 0x1692: 0x137b, 0x1693: 0x1804, 0x1694: 0x138f, 0x1695: 0x1393, 0x1696: 0x13ab, 0x1697: 0x13b7,
+ 0x1698: 0x180e, 0x1699: 0x1660, 0x169a: 0x13c3, 0x169b: 0x13bf, 0x169c: 0x13cb, 0x169d: 0x1665,
+ 0x169e: 0x13d7, 0x169f: 0x13e3, 0x16a0: 0x1813, 0x16a1: 0x1818, 0x16a2: 0x1423, 0x16a3: 0x142f,
+ 0x16a4: 0x1437, 0x16a5: 0x181d, 0x16a6: 0x143b, 0x16a7: 0x1467, 0x16a8: 0x1473, 0x16a9: 0x1477,
+ 0x16aa: 0x146f, 0x16ab: 0x1483, 0x16ac: 0x1487, 0x16ad: 0x1822, 0x16ae: 0x1493, 0x16af: 0x0693,
+ 0x16b0: 0x149b, 0x16b1: 0x1827, 0x16b2: 0x0697, 0x16b3: 0x14d3, 0x16b4: 0x0ac3, 0x16b5: 0x14eb,
+ 0x16b6: 0x182c, 0x16b7: 0x1836, 0x16b8: 0x069b, 0x16b9: 0x069f, 0x16ba: 0x1513, 0x16bb: 0x183b,
+ 0x16bc: 0x06a3, 0x16bd: 0x1840, 0x16be: 0x152b, 0x16bf: 0x152b,
+ // Block 0x5b, offset 0x16c0
+ 0x16c0: 0x1533, 0x16c1: 0x1845, 0x16c2: 0x154b, 0x16c3: 0x06a7, 0x16c4: 0x155b, 0x16c5: 0x1567,
+ 0x16c6: 0x156f, 0x16c7: 0x1577, 0x16c8: 0x06ab, 0x16c9: 0x184a, 0x16ca: 0x158b, 0x16cb: 0x15a7,
+ 0x16cc: 0x15b3, 0x16cd: 0x06af, 0x16ce: 0x06b3, 0x16cf: 0x15b7, 0x16d0: 0x184f, 0x16d1: 0x06b7,
+ 0x16d2: 0x1854, 0x16d3: 0x1859, 0x16d4: 0x185e, 0x16d5: 0x15db, 0x16d6: 0x06bb, 0x16d7: 0x15ef,
+ 0x16d8: 0x15f7, 0x16d9: 0x15fb, 0x16da: 0x1603, 0x16db: 0x160b, 0x16dc: 0x1613, 0x16dd: 0x1868,
+}
+
+// nfkcIndex: 22 blocks, 1408 entries, 1408 bytes
+// Block 0 is the zero block.
+var nfkcIndex = [1408]uint8{
+ // Block 0x0, offset 0x0
+ // Block 0x1, offset 0x40
+ // Block 0x2, offset 0x80
+ // Block 0x3, offset 0xc0
+ 0xc2: 0x5a, 0xc3: 0x01, 0xc4: 0x02, 0xc5: 0x03, 0xc6: 0x5b, 0xc7: 0x04,
+ 0xc8: 0x05, 0xca: 0x5c, 0xcb: 0x5d, 0xcc: 0x06, 0xcd: 0x07, 0xce: 0x08, 0xcf: 0x09,
+ 0xd0: 0x0a, 0xd1: 0x5e, 0xd2: 0x5f, 0xd3: 0x0b, 0xd6: 0x0c, 0xd7: 0x60,
+ 0xd8: 0x61, 0xd9: 0x0d, 0xdb: 0x62, 0xdc: 0x63, 0xdd: 0x64, 0xdf: 0x65,
+ 0xe0: 0x02, 0xe1: 0x03, 0xe2: 0x04, 0xe3: 0x05,
+ 0xea: 0x06, 0xeb: 0x07, 0xec: 0x08, 0xed: 0x09, 0xef: 0x0a,
+ 0xf0: 0x13,
+ // Block 0x4, offset 0x100
+ 0x120: 0x66, 0x121: 0x67, 0x123: 0x68, 0x124: 0x69, 0x125: 0x6a, 0x126: 0x6b, 0x127: 0x6c,
+ 0x128: 0x6d, 0x129: 0x6e, 0x12a: 0x6f, 0x12b: 0x70, 0x12c: 0x6b, 0x12d: 0x71, 0x12e: 0x72, 0x12f: 0x73,
+ 0x131: 0x74, 0x132: 0x75, 0x133: 0x76, 0x134: 0x77, 0x135: 0x78, 0x137: 0x79,
+ 0x138: 0x7a, 0x139: 0x7b, 0x13a: 0x7c, 0x13b: 0x7d, 0x13c: 0x7e, 0x13d: 0x7f, 0x13e: 0x80, 0x13f: 0x81,
+ // Block 0x5, offset 0x140
+ 0x140: 0x82, 0x142: 0x83, 0x143: 0x84, 0x144: 0x85, 0x145: 0x86, 0x146: 0x87, 0x147: 0x88,
+ 0x14d: 0x89,
+ 0x15c: 0x8a, 0x15f: 0x8b,
+ 0x162: 0x8c, 0x164: 0x8d,
+ 0x168: 0x8e, 0x169: 0x8f, 0x16a: 0x90, 0x16c: 0x0e, 0x16d: 0x91, 0x16e: 0x92, 0x16f: 0x93,
+ 0x170: 0x94, 0x173: 0x95, 0x174: 0x96, 0x175: 0x0f, 0x176: 0x10, 0x177: 0x97,
+ 0x178: 0x11, 0x179: 0x12, 0x17a: 0x13, 0x17b: 0x14, 0x17c: 0x15, 0x17d: 0x16, 0x17e: 0x17, 0x17f: 0x18,
+ // Block 0x6, offset 0x180
+ 0x180: 0x98, 0x181: 0x99, 0x182: 0x9a, 0x183: 0x9b, 0x184: 0x19, 0x185: 0x1a, 0x186: 0x9c, 0x187: 0x9d,
+ 0x188: 0x9e, 0x189: 0x1b, 0x18a: 0x1c, 0x18b: 0x9f, 0x18c: 0xa0,
+ 0x191: 0x1d, 0x192: 0x1e, 0x193: 0xa1,
+ 0x1a8: 0xa2, 0x1a9: 0xa3, 0x1ab: 0xa4,
+ 0x1b1: 0xa5, 0x1b3: 0xa6, 0x1b5: 0xa7, 0x1b7: 0xa8,
+ 0x1ba: 0xa9, 0x1bb: 0xaa, 0x1bc: 0x1f, 0x1bd: 0x20, 0x1be: 0x21, 0x1bf: 0xab,
+ // Block 0x7, offset 0x1c0
+ 0x1c0: 0xac, 0x1c1: 0x22, 0x1c2: 0x23, 0x1c3: 0x24, 0x1c4: 0xad, 0x1c5: 0x25, 0x1c6: 0x26,
+ 0x1c8: 0x27, 0x1c9: 0x28, 0x1ca: 0x29, 0x1cb: 0x2a, 0x1cc: 0x2b, 0x1cd: 0x2c, 0x1ce: 0x2d, 0x1cf: 0x2e,
+ // Block 0x8, offset 0x200
+ 0x219: 0xae, 0x21a: 0xaf, 0x21b: 0xb0, 0x21d: 0xb1, 0x21f: 0xb2,
+ 0x220: 0xb3, 0x223: 0xb4, 0x224: 0xb5, 0x225: 0xb6, 0x226: 0xb7, 0x227: 0xb8,
+ 0x22a: 0xb9, 0x22b: 0xba, 0x22d: 0xbb, 0x22f: 0xbc,
+ 0x230: 0xbd, 0x231: 0xbe, 0x232: 0xbf, 0x233: 0xc0, 0x234: 0xc1, 0x235: 0xc2, 0x236: 0xc3, 0x237: 0xbd,
+ 0x238: 0xbe, 0x239: 0xbf, 0x23a: 0xc0, 0x23b: 0xc1, 0x23c: 0xc2, 0x23d: 0xc3, 0x23e: 0xbd, 0x23f: 0xbe,
+ // Block 0x9, offset 0x240
+ 0x240: 0xbf, 0x241: 0xc0, 0x242: 0xc1, 0x243: 0xc2, 0x244: 0xc3, 0x245: 0xbd, 0x246: 0xbe, 0x247: 0xbf,
+ 0x248: 0xc0, 0x249: 0xc1, 0x24a: 0xc2, 0x24b: 0xc3, 0x24c: 0xbd, 0x24d: 0xbe, 0x24e: 0xbf, 0x24f: 0xc0,
+ 0x250: 0xc1, 0x251: 0xc2, 0x252: 0xc3, 0x253: 0xbd, 0x254: 0xbe, 0x255: 0xbf, 0x256: 0xc0, 0x257: 0xc1,
+ 0x258: 0xc2, 0x259: 0xc3, 0x25a: 0xbd, 0x25b: 0xbe, 0x25c: 0xbf, 0x25d: 0xc0, 0x25e: 0xc1, 0x25f: 0xc2,
+ 0x260: 0xc3, 0x261: 0xbd, 0x262: 0xbe, 0x263: 0xbf, 0x264: 0xc0, 0x265: 0xc1, 0x266: 0xc2, 0x267: 0xc3,
+ 0x268: 0xbd, 0x269: 0xbe, 0x26a: 0xbf, 0x26b: 0xc0, 0x26c: 0xc1, 0x26d: 0xc2, 0x26e: 0xc3, 0x26f: 0xbd,
+ 0x270: 0xbe, 0x271: 0xbf, 0x272: 0xc0, 0x273: 0xc1, 0x274: 0xc2, 0x275: 0xc3, 0x276: 0xbd, 0x277: 0xbe,
+ 0x278: 0xbf, 0x279: 0xc0, 0x27a: 0xc1, 0x27b: 0xc2, 0x27c: 0xc3, 0x27d: 0xbd, 0x27e: 0xbe, 0x27f: 0xbf,
+ // Block 0xa, offset 0x280
+ 0x280: 0xc0, 0x281: 0xc1, 0x282: 0xc2, 0x283: 0xc3, 0x284: 0xbd, 0x285: 0xbe, 0x286: 0xbf, 0x287: 0xc0,
+ 0x288: 0xc1, 0x289: 0xc2, 0x28a: 0xc3, 0x28b: 0xbd, 0x28c: 0xbe, 0x28d: 0xbf, 0x28e: 0xc0, 0x28f: 0xc1,
+ 0x290: 0xc2, 0x291: 0xc3, 0x292: 0xbd, 0x293: 0xbe, 0x294: 0xbf, 0x295: 0xc0, 0x296: 0xc1, 0x297: 0xc2,
+ 0x298: 0xc3, 0x299: 0xbd, 0x29a: 0xbe, 0x29b: 0xbf, 0x29c: 0xc0, 0x29d: 0xc1, 0x29e: 0xc2, 0x29f: 0xc3,
+ 0x2a0: 0xbd, 0x2a1: 0xbe, 0x2a2: 0xbf, 0x2a3: 0xc0, 0x2a4: 0xc1, 0x2a5: 0xc2, 0x2a6: 0xc3, 0x2a7: 0xbd,
+ 0x2a8: 0xbe, 0x2a9: 0xbf, 0x2aa: 0xc0, 0x2ab: 0xc1, 0x2ac: 0xc2, 0x2ad: 0xc3, 0x2ae: 0xbd, 0x2af: 0xbe,
+ 0x2b0: 0xbf, 0x2b1: 0xc0, 0x2b2: 0xc1, 0x2b3: 0xc2, 0x2b4: 0xc3, 0x2b5: 0xbd, 0x2b6: 0xbe, 0x2b7: 0xbf,
+ 0x2b8: 0xc0, 0x2b9: 0xc1, 0x2ba: 0xc2, 0x2bb: 0xc3, 0x2bc: 0xbd, 0x2bd: 0xbe, 0x2be: 0xbf, 0x2bf: 0xc0,
+ // Block 0xb, offset 0x2c0
+ 0x2c0: 0xc1, 0x2c1: 0xc2, 0x2c2: 0xc3, 0x2c3: 0xbd, 0x2c4: 0xbe, 0x2c5: 0xbf, 0x2c6: 0xc0, 0x2c7: 0xc1,
+ 0x2c8: 0xc2, 0x2c9: 0xc3, 0x2ca: 0xbd, 0x2cb: 0xbe, 0x2cc: 0xbf, 0x2cd: 0xc0, 0x2ce: 0xc1, 0x2cf: 0xc2,
+ 0x2d0: 0xc3, 0x2d1: 0xbd, 0x2d2: 0xbe, 0x2d3: 0xbf, 0x2d4: 0xc0, 0x2d5: 0xc1, 0x2d6: 0xc2, 0x2d7: 0xc3,
+ 0x2d8: 0xbd, 0x2d9: 0xbe, 0x2da: 0xbf, 0x2db: 0xc0, 0x2dc: 0xc1, 0x2dd: 0xc2, 0x2de: 0xc4,
+ // Block 0xc, offset 0x300
+ 0x324: 0x2f, 0x325: 0x30, 0x326: 0x31, 0x327: 0x32,
+ 0x328: 0x33, 0x329: 0x34, 0x32a: 0x35, 0x32b: 0x36, 0x32c: 0x37, 0x32d: 0x38, 0x32e: 0x39, 0x32f: 0x3a,
+ 0x330: 0x3b, 0x331: 0x3c, 0x332: 0x3d, 0x333: 0x3e, 0x334: 0x3f, 0x335: 0x40, 0x336: 0x41, 0x337: 0x42,
+ 0x338: 0x43, 0x339: 0x44, 0x33a: 0x45, 0x33b: 0x46, 0x33c: 0xc5, 0x33d: 0x47, 0x33e: 0x48, 0x33f: 0x49,
+ // Block 0xd, offset 0x340
+ 0x347: 0xc6,
+ 0x34b: 0xc7, 0x34d: 0xc8,
+ 0x368: 0xc9, 0x36b: 0xca,
+ // Block 0xe, offset 0x380
+ 0x381: 0xcb, 0x382: 0xcc, 0x384: 0xcd, 0x385: 0xb7, 0x387: 0xce,
+ 0x388: 0xcf, 0x38b: 0xd0, 0x38c: 0x6b, 0x38d: 0xd1,
+ 0x391: 0xd2, 0x392: 0xd3, 0x393: 0xd4, 0x396: 0xd5, 0x397: 0xd6,
+ 0x398: 0xd7, 0x39a: 0xd8, 0x39c: 0xd9,
+ 0x3b0: 0xd7,
+ // Block 0xf, offset 0x3c0
+ 0x3eb: 0xda, 0x3ec: 0xdb,
+ // Block 0x10, offset 0x400
+ 0x432: 0xdc,
+ // Block 0x11, offset 0x440
+ 0x445: 0xdd, 0x446: 0xde, 0x447: 0xdf,
+ 0x449: 0xe0,
+ 0x450: 0xe1, 0x451: 0xe2, 0x452: 0xe3, 0x453: 0xe4, 0x454: 0xe5, 0x455: 0xe6, 0x456: 0xe7, 0x457: 0xe8,
+ 0x458: 0xe9, 0x459: 0xea, 0x45a: 0x4a, 0x45b: 0xeb, 0x45c: 0xec, 0x45d: 0xed, 0x45e: 0xee, 0x45f: 0x4b,
+ // Block 0x12, offset 0x480
+ 0x480: 0xef,
+ 0x4a3: 0xf0, 0x4a5: 0xf1,
+ 0x4b8: 0x4c, 0x4b9: 0x4d, 0x4ba: 0x4e,
+ // Block 0x13, offset 0x4c0
+ 0x4c4: 0x4f, 0x4c5: 0xf2, 0x4c6: 0xf3,
+ 0x4c8: 0x50, 0x4c9: 0xf4,
+ // Block 0x14, offset 0x500
+ 0x520: 0x51, 0x521: 0x52, 0x522: 0x53, 0x523: 0x54, 0x524: 0x55, 0x525: 0x56, 0x526: 0x57, 0x527: 0x58,
+ 0x528: 0x59,
+ // Block 0x15, offset 0x540
+ 0x550: 0x0b, 0x551: 0x0c, 0x556: 0x0d,
+ 0x55b: 0x0e, 0x55d: 0x0f, 0x55e: 0x10, 0x55f: 0x11,
+ 0x56f: 0x12,
+}
+
+// nfkcSparseOffset: 155 entries, 310 bytes
+var nfkcSparseOffset = []uint16{0x0, 0xe, 0x12, 0x1b, 0x25, 0x35, 0x37, 0x3c, 0x47, 0x56, 0x63, 0x6b, 0x6f, 0x74, 0x76, 0x87, 0x8f, 0x96, 0x99, 0xa0, 0xa4, 0xa8, 0xaa, 0xac, 0xb5, 0xb9, 0xc0, 0xc5, 0xc8, 0xd2, 0xd4, 0xdb, 0xe3, 0xe7, 0xe9, 0xec, 0xf0, 0xf6, 0x107, 0x113, 0x115, 0x11b, 0x11d, 0x11f, 0x121, 0x123, 0x125, 0x127, 0x129, 0x12c, 0x12f, 0x131, 0x134, 0x137, 0x13b, 0x140, 0x149, 0x14b, 0x14e, 0x150, 0x15b, 0x166, 0x176, 0x184, 0x192, 0x1a2, 0x1b0, 0x1b7, 0x1bd, 0x1cc, 0x1d0, 0x1 [...]
+
+// nfkcSparseValues: 875 entries, 3500 bytes
+var nfkcSparseValues = [875]valueRange{
+ // Block 0x0, offset 0x0
+ {value: 0x0002, lo: 0x0d},
+ {value: 0x0001, lo: 0xa0, hi: 0xa0},
+ {value: 0x4278, lo: 0xa8, hi: 0xa8},
+ {value: 0x0083, lo: 0xaa, hi: 0xaa},
+ {value: 0x4264, lo: 0xaf, hi: 0xaf},
+ {value: 0x0025, lo: 0xb2, hi: 0xb3},
+ {value: 0x425a, lo: 0xb4, hi: 0xb4},
+ {value: 0x01dc, lo: 0xb5, hi: 0xb5},
+ {value: 0x4291, lo: 0xb8, hi: 0xb8},
+ {value: 0x0023, lo: 0xb9, hi: 0xb9},
+ {value: 0x009f, lo: 0xba, hi: 0xba},
+ {value: 0x221c, lo: 0xbc, hi: 0xbc},
+ {value: 0x2210, lo: 0xbd, hi: 0xbd},
+ {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: 0xa000, lo: 0xb7, hi: 0xb7},
+ // Block 0x2, offset 0x12
+ {value: 0x0003, lo: 0x08},
+ {value: 0xa000, lo: 0x92, hi: 0x92},
+ {value: 0x0091, lo: 0xb0, hi: 0xb0},
+ {value: 0x0119, lo: 0xb1, hi: 0xb1},
+ {value: 0x0095, lo: 0xb2, hi: 0xb2},
+ {value: 0x00a5, lo: 0xb3, hi: 0xb3},
+ {value: 0x0143, lo: 0xb4, hi: 0xb6},
+ {value: 0x00af, lo: 0xb7, hi: 0xb7},
+ {value: 0x00b3, lo: 0xb8, hi: 0xb8},
+ // Block 0x3, offset 0x1b
+ {value: 0x000a, lo: 0x09},
+ {value: 0x426e, lo: 0x98, hi: 0x98},
+ {value: 0x4273, lo: 0x99, hi: 0x9a},
+ {value: 0x4296, lo: 0x9b, hi: 0x9b},
+ {value: 0x425f, lo: 0x9c, hi: 0x9c},
+ {value: 0x4282, lo: 0x9d, hi: 0x9d},
+ {value: 0x0113, lo: 0xa0, hi: 0xa0},
+ {value: 0x0099, lo: 0xa1, hi: 0xa1},
+ {value: 0x00a7, lo: 0xa2, hi: 0xa3},
+ {value: 0x0167, lo: 0xa4, hi: 0xa4},
+ // Block 0x4, offset 0x25
+ {value: 0x0000, lo: 0x0f},
+ {value: 0xa000, lo: 0x83, hi: 0x83},
+ {value: 0xa000, lo: 0x87, hi: 0x87},
+ {value: 0xa000, lo: 0x8b, hi: 0x8b},
+ {value: 0xa000, lo: 0x8d, hi: 0x8d},
+ {value: 0x37a5, lo: 0x90, hi: 0x90},
+ {value: 0x37b1, lo: 0x91, hi: 0x91},
+ {value: 0x379f, lo: 0x93, hi: 0x93},
+ {value: 0xa000, lo: 0x96, hi: 0x96},
+ {value: 0x3817, lo: 0x97, hi: 0x97},
+ {value: 0x37e1, lo: 0x9c, hi: 0x9c},
+ {value: 0x37c9, lo: 0x9d, hi: 0x9d},
+ {value: 0x37f3, lo: 0x9e, hi: 0x9e},
+ {value: 0xa000, lo: 0xb4, hi: 0xb5},
+ {value: 0x381d, lo: 0xb6, hi: 0xb6},
+ {value: 0x3823, lo: 0xb7, hi: 0xb7},
+ // Block 0x5, offset 0x35
+ {value: 0x0000, lo: 0x01},
+ {value: 0x8132, lo: 0x83, hi: 0x87},
+ // Block 0x6, offset 0x37
+ {value: 0x0001, lo: 0x04},
+ {value: 0x8113, lo: 0x81, hi: 0x82},
+ {value: 0x8132, lo: 0x84, hi: 0x84},
+ {value: 0x812d, lo: 0x85, hi: 0x85},
+ {value: 0x810d, lo: 0x87, hi: 0x87},
+ // Block 0x7, offset 0x3c
+ {value: 0x0000, lo: 0x0a},
+ {value: 0x8132, lo: 0x90, hi: 0x97},
+ {value: 0x8119, lo: 0x98, hi: 0x98},
+ {value: 0x811a, lo: 0x99, hi: 0x99},
+ {value: 0x811b, lo: 0x9a, hi: 0x9a},
+ {value: 0x3841, lo: 0xa2, hi: 0xa2},
+ {value: 0x3847, lo: 0xa3, hi: 0xa3},
+ {value: 0x3853, lo: 0xa4, hi: 0xa4},
+ {value: 0x384d, lo: 0xa5, hi: 0xa5},
+ {value: 0x3859, lo: 0xa6, hi: 0xa6},
+ {value: 0xa000, lo: 0xa7, hi: 0xa7},
+ // Block 0x8, offset 0x47
+ {value: 0x0000, lo: 0x0e},
+ {value: 0x386b, lo: 0x80, hi: 0x80},
+ {value: 0xa000, lo: 0x81, hi: 0x81},
+ {value: 0x385f, lo: 0x82, hi: 0x82},
+ {value: 0xa000, lo: 0x92, hi: 0x92},
+ {value: 0x3865, lo: 0x93, hi: 0x93},
+ {value: 0xa000, lo: 0x95, hi: 0x95},
+ {value: 0x8132, lo: 0x96, hi: 0x9c},
+ {value: 0x8132, lo: 0x9f, hi: 0xa2},
+ {value: 0x812d, lo: 0xa3, hi: 0xa3},
+ {value: 0x8132, lo: 0xa4, hi: 0xa4},
+ {value: 0x8132, lo: 0xa7, hi: 0xa8},
+ {value: 0x812d, lo: 0xaa, hi: 0xaa},
+ {value: 0x8132, lo: 0xab, hi: 0xac},
+ {value: 0x812d, lo: 0xad, hi: 0xad},
+ // Block 0x9, offset 0x56
+ {value: 0x0000, lo: 0x0c},
+ {value: 0x811f, lo: 0x91, hi: 0x91},
+ {value: 0x8132, lo: 0xb0, hi: 0xb0},
+ {value: 0x812d, lo: 0xb1, hi: 0xb1},
+ {value: 0x8132, lo: 0xb2, hi: 0xb3},
+ {value: 0x812d, lo: 0xb4, hi: 0xb4},
+ {value: 0x8132, lo: 0xb5, hi: 0xb6},
+ {value: 0x812d, lo: 0xb7, hi: 0xb9},
+ {value: 0x8132, lo: 0xba, hi: 0xba},
+ {value: 0x812d, lo: 0xbb, hi: 0xbc},
+ {value: 0x8132, lo: 0xbd, hi: 0xbd},
+ {value: 0x812d, lo: 0xbe, hi: 0xbe},
+ {value: 0x8132, lo: 0xbf, hi: 0xbf},
+ // Block 0xa, offset 0x63
+ {value: 0x0005, lo: 0x07},
+ {value: 0x8132, lo: 0x80, hi: 0x80},
+ {value: 0x8132, lo: 0x81, hi: 0x81},
+ {value: 0x812d, lo: 0x82, hi: 0x83},
+ {value: 0x812d, lo: 0x84, hi: 0x85},
+ {value: 0x812d, lo: 0x86, hi: 0x87},
+ {value: 0x812d, lo: 0x88, hi: 0x89},
+ {value: 0x8132, lo: 0x8a, hi: 0x8a},
+ // Block 0xb, offset 0x6b
+ {value: 0x0000, lo: 0x03},
+ {value: 0x8132, lo: 0xab, hi: 0xb1},
+ {value: 0x812d, lo: 0xb2, hi: 0xb2},
+ {value: 0x8132, lo: 0xb3, hi: 0xb3},
+ // Block 0xc, offset 0x6f
+ {value: 0x0000, lo: 0x04},
+ {value: 0x8132, lo: 0x96, hi: 0x99},
+ {value: 0x8132, lo: 0x9b, hi: 0xa3},
+ {value: 0x8132, lo: 0xa5, hi: 0xa7},
+ {value: 0x8132, lo: 0xa9, hi: 0xad},
+ // Block 0xd, offset 0x74
+ {value: 0x0000, lo: 0x01},
+ {value: 0x812d, lo: 0x99, hi: 0x9b},
+ // Block 0xe, offset 0x76
+ {value: 0x0000, lo: 0x10},
+ {value: 0x8132, lo: 0x94, hi: 0xa1},
+ {value: 0x812d, lo: 0xa3, hi: 0xa3},
+ {value: 0x8132, lo: 0xa4, hi: 0xa5},
+ {value: 0x812d, lo: 0xa6, hi: 0xa6},
+ {value: 0x8132, lo: 0xa7, hi: 0xa8},
+ {value: 0x812d, lo: 0xa9, hi: 0xa9},
+ {value: 0x8132, lo: 0xaa, hi: 0xac},
+ {value: 0x812d, lo: 0xad, hi: 0xaf},
+ {value: 0x8116, lo: 0xb0, hi: 0xb0},
+ {value: 0x8117, lo: 0xb1, hi: 0xb1},
+ {value: 0x8118, lo: 0xb2, hi: 0xb2},
+ {value: 0x8132, lo: 0xb3, hi: 0xb5},
+ {value: 0x812d, lo: 0xb6, hi: 0xb6},
+ {value: 0x8132, lo: 0xb7, hi: 0xb8},
+ {value: 0x812d, lo: 0xb9, hi: 0xba},
+ {value: 0x8132, lo: 0xbb, hi: 0xbf},
+ // Block 0xf, offset 0x87
+ {value: 0x0000, lo: 0x07},
+ {value: 0xa000, lo: 0xa8, hi: 0xa8},
+ {value: 0x3ed8, lo: 0xa9, hi: 0xa9},
+ {value: 0xa000, lo: 0xb0, hi: 0xb0},
+ {value: 0x3ee0, lo: 0xb1, hi: 0xb1},
+ {value: 0xa000, lo: 0xb3, hi: 0xb3},
+ {value: 0x3ee8, lo: 0xb4, hi: 0xb4},
+ {value: 0x9902, lo: 0xbc, hi: 0xbc},
+ // Block 0x10, offset 0x8f
+ {value: 0x0008, lo: 0x06},
+ {value: 0x8104, lo: 0x8d, hi: 0x8d},
+ {value: 0x8132, lo: 0x91, hi: 0x91},
+ {value: 0x812d, lo: 0x92, hi: 0x92},
+ {value: 0x8132, lo: 0x93, hi: 0x93},
+ {value: 0x8132, lo: 0x94, hi: 0x94},
+ {value: 0x45b2, lo: 0x98, hi: 0x9f},
+ // Block 0x11, offset 0x96
+ {value: 0x0000, lo: 0x02},
+ {value: 0x8102, lo: 0xbc, hi: 0xbc},
+ {value: 0x9900, lo: 0xbe, hi: 0xbe},
+ // Block 0x12, offset 0x99
+ {value: 0x0008, lo: 0x06},
+ {value: 0xa000, lo: 0x87, hi: 0x87},
+ {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},
+ // Block 0x13, offset 0xa0
+ {value: 0x0000, lo: 0x03},
+ {value: 0x462a, lo: 0xb3, hi: 0xb3},
+ {value: 0x4632, 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},
+ // Block 0x15, offset 0xa8
+ {value: 0x0000, lo: 0x01},
+ {value: 0x8102, lo: 0xbc, hi: 0xbc},
+ // Block 0x16, offset 0xaa
+ {value: 0x0000, lo: 0x01},
+ {value: 0x8104, lo: 0x8d, hi: 0x8d},
+ // Block 0x17, offset 0xac
+ {value: 0x0000, lo: 0x08},
+ {value: 0xa000, lo: 0x87, hi: 0x87},
+ {value: 0x2cb6, lo: 0x88, hi: 0x88},
+ {value: 0x2cae, lo: 0x8b, hi: 0x8b},
+ {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},
+ // Block 0x18, offset 0xb5
+ {value: 0x0000, lo: 0x03},
+ {value: 0xa000, lo: 0x92, hi: 0x92},
+ {value: 0x2cc6, lo: 0x94, hi: 0x94},
+ {value: 0x9900, lo: 0xbe, hi: 0xbe},
+ // Block 0x19, offset 0xb9
+ {value: 0x0000, lo: 0x06},
+ {value: 0xa000, lo: 0x86, hi: 0x87},
+ {value: 0x2cce, lo: 0x8a, hi: 0x8a},
+ {value: 0x2cde, lo: 0x8b, hi: 0x8b},
+ {value: 0x2cd6, lo: 0x8c, hi: 0x8c},
+ {value: 0x8104, lo: 0x8d, hi: 0x8d},
+ {value: 0x9900, lo: 0x97, hi: 0x97},
+ // Block 0x1a, offset 0xc0
+ {value: 0x1801, lo: 0x04},
+ {value: 0xa000, lo: 0x86, hi: 0x86},
+ {value: 0x3ef0, lo: 0x88, hi: 0x88},
+ {value: 0x8104, lo: 0x8d, hi: 0x8d},
+ {value: 0x8120, lo: 0x95, hi: 0x96},
+ // Block 0x1b, offset 0xc5
+ {value: 0x0000, lo: 0x02},
+ {value: 0x8102, lo: 0xbc, hi: 0xbc},
+ {value: 0xa000, lo: 0xbf, hi: 0xbf},
+ // Block 0x1c, offset 0xc8
+ {value: 0x0000, lo: 0x09},
+ {value: 0x2ce6, lo: 0x80, hi: 0x80},
+ {value: 0x9900, lo: 0x82, hi: 0x82},
+ {value: 0xa000, lo: 0x86, hi: 0x86},
+ {value: 0x2cee, lo: 0x87, hi: 0x87},
+ {value: 0x2cf6, lo: 0x88, hi: 0x88},
+ {value: 0x2f50, lo: 0x8a, hi: 0x8a},
+ {value: 0x2dd8, lo: 0x8b, hi: 0x8b},
+ {value: 0x8104, lo: 0x8d, hi: 0x8d},
+ {value: 0x9900, lo: 0x95, hi: 0x96},
+ // Block 0x1d, offset 0xd2
+ {value: 0x0000, lo: 0x01},
+ {value: 0x9900, lo: 0xbe, hi: 0xbe},
+ // Block 0x1e, offset 0xd4
+ {value: 0x0000, lo: 0x06},
+ {value: 0xa000, lo: 0x86, hi: 0x87},
+ {value: 0x2cfe, lo: 0x8a, hi: 0x8a},
+ {value: 0x2d0e, lo: 0x8b, hi: 0x8b},
+ {value: 0x2d06, lo: 0x8c, hi: 0x8c},
+ {value: 0x8104, lo: 0x8d, hi: 0x8d},
+ {value: 0x9900, lo: 0x97, hi: 0x97},
+ // Block 0x1f, offset 0xdb
+ {value: 0x6bea, lo: 0x07},
+ {value: 0x9904, lo: 0x8a, hi: 0x8a},
+ {value: 0x9900, lo: 0x8f, hi: 0x8f},
+ {value: 0xa000, lo: 0x99, hi: 0x99},
+ {value: 0x3ef8, lo: 0x9a, hi: 0x9a},
+ {value: 0x2f58, lo: 0x9c, hi: 0x9c},
+ {value: 0x2de3, lo: 0x9d, hi: 0x9d},
+ {value: 0x2d16, lo: 0x9e, hi: 0x9f},
+ // Block 0x20, offset 0xe3
+ {value: 0x0000, lo: 0x03},
+ {value: 0x2621, lo: 0xb3, hi: 0xb3},
+ {value: 0x8122, lo: 0xb8, hi: 0xb9},
+ {value: 0x8104, lo: 0xba, hi: 0xba},
+ // Block 0x21, offset 0xe7
+ {value: 0x0000, lo: 0x01},
+ {value: 0x8123, lo: 0x88, hi: 0x8b},
+ // Block 0x22, offset 0xe9
+ {value: 0x0000, lo: 0x02},
+ {value: 0x2636, lo: 0xb3, hi: 0xb3},
+ {value: 0x8124, lo: 0xb8, hi: 0xb9},
+ // Block 0x23, offset 0xec
+ {value: 0x0000, lo: 0x03},
+ {value: 0x8125, lo: 0x88, hi: 0x8b},
+ {value: 0x2628, lo: 0x9c, hi: 0x9c},
+ {value: 0x262f, lo: 0x9d, hi: 0x9d},
+ // Block 0x24, offset 0xf0
+ {value: 0x0000, lo: 0x05},
+ {value: 0x030b, lo: 0x8c, hi: 0x8c},
+ {value: 0x812d, lo: 0x98, hi: 0x99},
+ {value: 0x812d, lo: 0xb5, hi: 0xb5},
+ {value: 0x812d, lo: 0xb7, hi: 0xb7},
+ {value: 0x812b, lo: 0xb9, hi: 0xb9},
+ // Block 0x25, offset 0xf6
+ {value: 0x0000, lo: 0x10},
+ {value: 0x2644, lo: 0x83, hi: 0x83},
+ {value: 0x264b, lo: 0x8d, hi: 0x8d},
+ {value: 0x2652, lo: 0x92, hi: 0x92},
+ {value: 0x2659, lo: 0x97, hi: 0x97},
+ {value: 0x2660, lo: 0x9c, hi: 0x9c},
+ {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: 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: 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: 0x8132, lo: 0x82, hi: 0x83},
+ {value: 0x8104, lo: 0x84, hi: 0x84},
+ {value: 0x8132, lo: 0x86, hi: 0x87},
+ {value: 0x266e, lo: 0x93, hi: 0x93},
+ {value: 0x2675, lo: 0x9d, hi: 0x9d},
+ {value: 0x267c, lo: 0xa2, hi: 0xa2},
+ {value: 0x2683, lo: 0xa7, hi: 0xa7},
+ {value: 0x268a, lo: 0xac, hi: 0xac},
+ {value: 0x2667, lo: 0xb9, hi: 0xb9},
+ // Block 0x27, offset 0x113
+ {value: 0x0000, lo: 0x01},
+ {value: 0x812d, lo: 0x86, hi: 0x86},
+ // Block 0x28, offset 0x115
+ {value: 0x0000, lo: 0x05},
+ {value: 0xa000, lo: 0xa5, hi: 0xa5},
+ {value: 0x2d1e, lo: 0xa6, hi: 0xa6},
+ {value: 0x9900, lo: 0xae, hi: 0xae},
+ {value: 0x8102, lo: 0xb7, hi: 0xb7},
+ {value: 0x8104, lo: 0xb9, hi: 0xba},
+ // Block 0x29, offset 0x11b
+ {value: 0x0000, lo: 0x01},
+ {value: 0x812d, lo: 0x8d, hi: 0x8d},
+ // Block 0x2a, offset 0x11d
+ {value: 0x0000, lo: 0x01},
+ {value: 0x030f, lo: 0xbc, hi: 0xbc},
+ // Block 0x2b, offset 0x11f
+ {value: 0x0000, lo: 0x01},
+ {value: 0xa000, lo: 0x80, hi: 0x92},
+ // Block 0x2c, offset 0x121
+ {value: 0x0000, lo: 0x01},
+ {value: 0xb900, lo: 0xa1, hi: 0xb5},
+ // Block 0x2d, offset 0x123
+ {value: 0x0000, lo: 0x01},
+ {value: 0x9900, lo: 0xa8, hi: 0xbf},
+ // Block 0x2e, offset 0x125
+ {value: 0x0000, lo: 0x01},
+ {value: 0x9900, lo: 0x80, hi: 0x82},
+ // Block 0x2f, offset 0x127
+ {value: 0x0000, lo: 0x01},
+ {value: 0x8132, lo: 0x9d, hi: 0x9f},
+ // Block 0x30, offset 0x129
+ {value: 0x0000, lo: 0x02},
+ {value: 0x8104, lo: 0x94, hi: 0x94},
+ {value: 0x8104, lo: 0xb4, hi: 0xb4},
+ // Block 0x31, offset 0x12c
+ {value: 0x0000, lo: 0x02},
+ {value: 0x8104, lo: 0x92, hi: 0x92},
+ {value: 0x8132, lo: 0x9d, hi: 0x9d},
+ // Block 0x32, offset 0x12f
+ {value: 0x0000, lo: 0x01},
+ {value: 0x8131, lo: 0xa9, hi: 0xa9},
+ // Block 0x33, offset 0x131
+ {value: 0x0004, lo: 0x02},
+ {value: 0x812e, lo: 0xb9, hi: 0xba},
+ {value: 0x812d, lo: 0xbb, hi: 0xbb},
+ // Block 0x34, offset 0x134
+ {value: 0x0000, lo: 0x02},
+ {value: 0x8132, lo: 0x97, hi: 0x97},
+ {value: 0x812d, lo: 0x98, hi: 0x98},
+ // Block 0x35, offset 0x137
+ {value: 0x0000, lo: 0x03},
+ {value: 0x8104, lo: 0xa0, hi: 0xa0},
+ {value: 0x8132, lo: 0xb5, hi: 0xbc},
+ {value: 0x812d, lo: 0xbf, hi: 0xbf},
+ // Block 0x36, offset 0x13b
+ {value: 0x0000, lo: 0x04},
+ {value: 0x8132, lo: 0xb0, hi: 0xb4},
+ {value: 0x812d, lo: 0xb5, hi: 0xba},
+ {value: 0x8132, lo: 0xbb, hi: 0xbc},
+ {value: 0x812d, lo: 0xbd, hi: 0xbd},
+ // Block 0x37, offset 0x140
+ {value: 0x0000, lo: 0x08},
+ {value: 0x2d66, lo: 0x80, hi: 0x80},
+ {value: 0x2d6e, lo: 0x81, hi: 0x81},
+ {value: 0xa000, lo: 0x82, hi: 0x82},
+ {value: 0x2d76, lo: 0x83, hi: 0x83},
+ {value: 0x8104, lo: 0x84, hi: 0x84},
+ {value: 0x8132, lo: 0xab, hi: 0xab},
+ {value: 0x812d, lo: 0xac, hi: 0xac},
+ {value: 0x8132, lo: 0xad, hi: 0xb3},
+ // Block 0x38, offset 0x149
+ {value: 0x0000, lo: 0x01},
+ {value: 0x8104, lo: 0xaa, hi: 0xab},
+ // Block 0x39, offset 0x14b
+ {value: 0x0000, lo: 0x02},
+ {value: 0x8102, lo: 0xa6, hi: 0xa6},
+ {value: 0x8104, lo: 0xb2, hi: 0xb3},
+ // Block 0x3a, offset 0x14e
+ {value: 0x0000, lo: 0x01},
+ {value: 0x8102, lo: 0xb7, hi: 0xb7},
+ // Block 0x3b, offset 0x150
+ {value: 0x0000, lo: 0x0a},
+ {value: 0x8132, lo: 0x90, hi: 0x92},
+ {value: 0x8101, lo: 0x94, hi: 0x94},
+ {value: 0x812d, lo: 0x95, hi: 0x99},
+ {value: 0x8132, lo: 0x9a, hi: 0x9b},
+ {value: 0x812d, lo: 0x9c, hi: 0x9f},
+ {value: 0x8132, lo: 0xa0, hi: 0xa0},
+ {value: 0x8101, lo: 0xa2, hi: 0xa8},
+ {value: 0x812d, lo: 0xad, hi: 0xad},
+ {value: 0x8132, lo: 0xb4, hi: 0xb4},
+ {value: 0x8132, lo: 0xb8, hi: 0xb9},
+ // Block 0x3c, offset 0x15b
+ {value: 0x0002, lo: 0x0a},
+ {value: 0x0043, lo: 0xac, hi: 0xac},
+ {value: 0x00d1, lo: 0xad, hi: 0xad},
+ {value: 0x0045, lo: 0xae, hi: 0xae},
+ {value: 0x0049, lo: 0xb0, hi: 0xb1},
+ {value: 0x00e6, lo: 0xb2, hi: 0xb2},
+ {value: 0x004f, lo: 0xb3, hi: 0xba},
+ {value: 0x005f, lo: 0xbc, hi: 0xbc},
+ {value: 0x00ef, lo: 0xbd, hi: 0xbd},
+ {value: 0x0061, lo: 0xbe, hi: 0xbe},
+ {value: 0x0065, lo: 0xbf, hi: 0xbf},
+ // Block 0x3d, offset 0x166
+ {value: 0x0000, lo: 0x0f},
+ {value: 0x8132, lo: 0x80, hi: 0x81},
+ {value: 0x812d, lo: 0x82, hi: 0x82},
+ {value: 0x8132, lo: 0x83, hi: 0x89},
+ {value: 0x812d, lo: 0x8a, hi: 0x8a},
+ {value: 0x8132, lo: 0x8b, hi: 0x8c},
+ {value: 0x8135, lo: 0x8d, hi: 0x8d},
+ {value: 0x812a, lo: 0x8e, hi: 0x8e},
+ {value: 0x812d, lo: 0x8f, hi: 0x8f},
+ {value: 0x8129, lo: 0x90, hi: 0x90},
+ {value: 0x8132, lo: 0x91, hi: 0xb5},
+ {value: 0x8132, lo: 0xbb, hi: 0xbb},
+ {value: 0x8134, lo: 0xbc, hi: 0xbc},
+ {value: 0x812d, lo: 0xbd, hi: 0xbd},
+ {value: 0x8132, lo: 0xbe, hi: 0xbe},
+ {value: 0x812d, lo: 0xbf, hi: 0xbf},
+ // Block 0x3e, offset 0x176
+ {value: 0x0000, lo: 0x0d},
+ {value: 0x0001, lo: 0x80, hi: 0x8a},
+ {value: 0x043b, lo: 0x91, hi: 0x91},
+ {value: 0x429b, lo: 0x97, hi: 0x97},
+ {value: 0x001d, lo: 0xa4, hi: 0xa4},
+ {value: 0x1873, lo: 0xa5, hi: 0xa5},
+ {value: 0x1b5c, lo: 0xa6, hi: 0xa6},
+ {value: 0x0001, lo: 0xaf, hi: 0xaf},
+ {value: 0x2691, lo: 0xb3, hi: 0xb3},
+ {value: 0x27fe, lo: 0xb4, hi: 0xb4},
+ {value: 0x2698, lo: 0xb6, hi: 0xb6},
+ {value: 0x2808, lo: 0xb7, hi: 0xb7},
+ {value: 0x186d, lo: 0xbc, hi: 0xbc},
+ {value: 0x4269, lo: 0xbe, hi: 0xbe},
+ // Block 0x3f, offset 0x184
+ {value: 0x0002, lo: 0x0d},
+ {value: 0x1933, lo: 0x87, hi: 0x87},
+ {value: 0x1930, lo: 0x88, hi: 0x88},
+ {value: 0x1870, lo: 0x89, hi: 0x89},
+ {value: 0x298e, lo: 0x97, hi: 0x97},
+ {value: 0x0001, lo: 0x9f, hi: 0x9f},
+ {value: 0x0021, lo: 0xb0, hi: 0xb0},
+ {value: 0x0093, lo: 0xb1, hi: 0xb1},
+ {value: 0x0029, lo: 0xb4, hi: 0xb9},
+ {value: 0x0017, lo: 0xba, hi: 0xba},
+ {value: 0x0467, lo: 0xbb, hi: 0xbb},
+ {value: 0x003b, lo: 0xbc, hi: 0xbc},
+ {value: 0x0011, lo: 0xbd, hi: 0xbe},
+ {value: 0x009d, lo: 0xbf, hi: 0xbf},
+ // Block 0x40, offset 0x192
+ {value: 0x0002, lo: 0x0f},
+ {value: 0x0021, lo: 0x80, hi: 0x89},
+ {value: 0x0017, lo: 0x8a, hi: 0x8a},
+ {value: 0x0467, lo: 0x8b, hi: 0x8b},
+ {value: 0x003b, lo: 0x8c, hi: 0x8c},
+ {value: 0x0011, lo: 0x8d, hi: 0x8e},
+ {value: 0x0083, lo: 0x90, hi: 0x90},
+ {value: 0x008b, lo: 0x91, hi: 0x91},
+ {value: 0x009f, lo: 0x92, hi: 0x92},
+ {value: 0x00b1, lo: 0x93, hi: 0x93},
+ {value: 0x0104, lo: 0x94, hi: 0x94},
+ {value: 0x0091, lo: 0x95, hi: 0x95},
+ {value: 0x0097, lo: 0x96, hi: 0x99},
+ {value: 0x00a1, lo: 0x9a, hi: 0x9a},
+ {value: 0x00a7, lo: 0x9b, hi: 0x9c},
+ {value: 0x1999, lo: 0xa8, hi: 0xa8},
+ // Block 0x41, offset 0x1a2
+ {value: 0x0000, lo: 0x0d},
+ {value: 0x8132, lo: 0x90, hi: 0x91},
+ {value: 0x8101, lo: 0x92, hi: 0x93},
+ {value: 0x8132, lo: 0x94, hi: 0x97},
+ {value: 0x8101, lo: 0x98, hi: 0x9a},
+ {value: 0x8132, lo: 0x9b, hi: 0x9c},
+ {value: 0x8132, lo: 0xa1, hi: 0xa1},
+ {value: 0x8101, lo: 0xa5, hi: 0xa6},
+ {value: 0x8132, lo: 0xa7, hi: 0xa7},
+ {value: 0x812d, lo: 0xa8, hi: 0xa8},
+ {value: 0x8132, lo: 0xa9, hi: 0xa9},
+ {value: 0x8101, lo: 0xaa, hi: 0xab},
+ {value: 0x812d, lo: 0xac, hi: 0xaf},
+ {value: 0x8132, lo: 0xb0, hi: 0xb0},
+ // Block 0x42, offset 0x1b0
+ {value: 0x0007, lo: 0x06},
+ {value: 0x2180, lo: 0x89, hi: 0x89},
+ {value: 0xa000, lo: 0x90, hi: 0x90},
+ {value: 0xa000, lo: 0x92, hi: 0x92},
+ {value: 0xa000, lo: 0x94, hi: 0x94},
+ {value: 0x3bb9, lo: 0x9a, hi: 0x9b},
+ {value: 0x3bc7, lo: 0xae, hi: 0xae},
+ // Block 0x43, offset 0x1b7
+ {value: 0x000e, lo: 0x05},
+ {value: 0x3bce, lo: 0x8d, hi: 0x8e},
+ {value: 0x3bd5, lo: 0x8f, hi: 0x8f},
+ {value: 0xa000, lo: 0x90, hi: 0x90},
+ {value: 0xa000, lo: 0x92, hi: 0x92},
+ {value: 0xa000, lo: 0x94, hi: 0x94},
+ // Block 0x44, offset 0x1bd
+ {value: 0x0173, lo: 0x0e},
+ {value: 0xa000, lo: 0x83, hi: 0x83},
+ {value: 0x3be3, lo: 0x84, hi: 0x84},
+ {value: 0xa000, lo: 0x88, hi: 0x88},
+ {value: 0x3bea, lo: 0x89, hi: 0x89},
+ {value: 0xa000, lo: 0x8b, hi: 0x8b},
+ {value: 0x3bf1, lo: 0x8c, hi: 0x8c},
+ {value: 0xa000, lo: 0xa3, hi: 0xa3},
+ {value: 0x3bf8, lo: 0xa4, hi: 0xa4},
+ {value: 0xa000, lo: 0xa5, hi: 0xa5},
+ {value: 0x3bff, lo: 0xa6, hi: 0xa6},
+ {value: 0x269f, lo: 0xac, hi: 0xad},
+ {value: 0x26a6, lo: 0xaf, hi: 0xaf},
+ {value: 0x281c, lo: 0xb0, hi: 0xb0},
+ {value: 0xa000, lo: 0xbc, hi: 0xbc},
+ // Block 0x45, offset 0x1cc
+ {value: 0x0007, lo: 0x03},
+ {value: 0x3c68, lo: 0xa0, hi: 0xa1},
+ {value: 0x3c92, lo: 0xa2, hi: 0xa3},
+ {value: 0x3cbc, lo: 0xaa, hi: 0xad},
+ // Block 0x46, offset 0x1d0
+ {value: 0x0004, lo: 0x01},
+ {value: 0x048b, lo: 0xa9, hi: 0xaa},
+ // Block 0x47, offset 0x1d2
+ {value: 0x0002, lo: 0x03},
+ {value: 0x0057, lo: 0x80, hi: 0x8f},
+ {value: 0x0083, lo: 0x90, hi: 0xa9},
+ {value: 0x0021, lo: 0xaa, hi: 0xaa},
+ // Block 0x48, offset 0x1d6
+ {value: 0x0000, lo: 0x01},
+ {value: 0x299b, lo: 0x8c, hi: 0x8c},
+ // Block 0x49, offset 0x1d8
+ {value: 0x0263, lo: 0x02},
+ {value: 0x1b8c, lo: 0xb4, hi: 0xb4},
+ {value: 0x192d, lo: 0xb5, hi: 0xb6},
+ // Block 0x4a, offset 0x1db
+ {value: 0x0000, lo: 0x01},
+ {value: 0x4573, lo: 0x9c, hi: 0x9c},
+ // Block 0x4b, offset 0x1dd
+ {value: 0x0000, lo: 0x02},
+ {value: 0x0095, lo: 0xbc, hi: 0xbc},
+ {value: 0x006d, lo: 0xbd, hi: 0xbd},
+ // Block 0x4c, offset 0x1e0
+ {value: 0x0000, lo: 0x01},
+ {value: 0x8132, lo: 0xaf, hi: 0xb1},
+ // Block 0x4d, offset 0x1e2
+ {value: 0x0000, lo: 0x02},
+ {value: 0x047f, lo: 0xaf, hi: 0xaf},
+ {value: 0x8104, lo: 0xbf, hi: 0xbf},
+ // Block 0x4e, offset 0x1e5
+ {value: 0x0000, lo: 0x01},
+ {value: 0x8132, lo: 0xa0, hi: 0xbf},
+ // Block 0x4f, offset 0x1e7
+ {value: 0x0000, lo: 0x01},
+ {value: 0x0dc3, lo: 0x9f, hi: 0x9f},
+ // Block 0x50, offset 0x1e9
+ {value: 0x0000, lo: 0x01},
+ {value: 0x162f, lo: 0xb3, hi: 0xb3},
+ // Block 0x51, offset 0x1eb
+ {value: 0x0004, lo: 0x0b},
+ {value: 0x1597, lo: 0x80, hi: 0x82},
+ {value: 0x15af, lo: 0x83, hi: 0x83},
+ {value: 0x15c7, lo: 0x84, hi: 0x85},
+ {value: 0x15d7, lo: 0x86, hi: 0x89},
+ {value: 0x15eb, lo: 0x8a, hi: 0x8c},
+ {value: 0x15ff, lo: 0x8d, hi: 0x8d},
+ {value: 0x1607, lo: 0x8e, hi: 0x8e},
+ {value: 0x160f, lo: 0x8f, hi: 0x90},
+ {value: 0x161b, lo: 0x91, hi: 0x93},
+ {value: 0x162b, lo: 0x94, hi: 0x94},
+ {value: 0x1633, lo: 0x95, hi: 0x95},
+ // Block 0x52, offset 0x1f7
+ {value: 0x0004, lo: 0x09},
+ {value: 0x0001, lo: 0x80, hi: 0x80},
+ {value: 0x812c, lo: 0xaa, hi: 0xaa},
+ {value: 0x8131, lo: 0xab, hi: 0xab},
+ {value: 0x8133, lo: 0xac, hi: 0xac},
+ {value: 0x812e, lo: 0xad, hi: 0xad},
+ {value: 0x812f, lo: 0xae, hi: 0xae},
+ {value: 0x812f, lo: 0xaf, hi: 0xaf},
+ {value: 0x04b3, lo: 0xb6, hi: 0xb6},
+ {value: 0x0887, lo: 0xb8, hi: 0xba},
+ // Block 0x53, offset 0x201
+ {value: 0x0005, lo: 0x09},
+ {value: 0x0313, lo: 0xb1, hi: 0xb1},
+ {value: 0x0317, lo: 0xb2, hi: 0xb2},
+ {value: 0x4345, lo: 0xb3, hi: 0xb3},
+ {value: 0x031b, lo: 0xb4, hi: 0xb4},
+ {value: 0x434a, 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},
+ // Block 0x54, offset 0x20b
+ {value: 0x0000, lo: 0x02},
+ {value: 0x8132, lo: 0xaf, hi: 0xaf},
+ {value: 0x8132, lo: 0xb4, hi: 0xbd},
+ // Block 0x55, offset 0x20e
+ {value: 0x0000, lo: 0x03},
+ {value: 0x020f, lo: 0x9c, hi: 0x9c},
+ {value: 0x0212, lo: 0x9d, hi: 0x9d},
+ {value: 0x8132, lo: 0x9e, hi: 0x9f},
+ // Block 0x56, offset 0x212
+ {value: 0x0000, lo: 0x01},
+ {value: 0x8132, lo: 0xb0, hi: 0xb1},
+ // Block 0x57, offset 0x214
+ {value: 0x0000, lo: 0x01},
+ {value: 0x163b, lo: 0xb0, hi: 0xb0},
+ // Block 0x58, offset 0x216
+ {value: 0x000c, lo: 0x01},
+ {value: 0x00d7, lo: 0xb8, hi: 0xb9},
+ // Block 0x59, offset 0x218
+ {value: 0x0000, lo: 0x01},
+ {value: 0x8104, lo: 0x86, hi: 0x86},
+ // Block 0x5a, offset 0x21a
+ {value: 0x0000, lo: 0x02},
+ {value: 0x8104, lo: 0x84, hi: 0x84},
+ {value: 0x8132, lo: 0xa0, hi: 0xb1},
+ // Block 0x5b, offset 0x21d
+ {value: 0x0000, lo: 0x01},
+ {value: 0x812d, lo: 0xab, hi: 0xad},
+ // Block 0x5c, offset 0x21f
+ {value: 0x0000, lo: 0x01},
+ {value: 0x8104, lo: 0x93, hi: 0x93},
+ // Block 0x5d, offset 0x221
+ {value: 0x0000, lo: 0x01},
+ {value: 0x8102, lo: 0xb3, hi: 0xb3},
+ // Block 0x5e, offset 0x223
+ {value: 0x0000, lo: 0x01},
+ {value: 0x8104, lo: 0x80, hi: 0x80},
+ // Block 0x5f, offset 0x225
+ {value: 0x0000, lo: 0x05},
+ {value: 0x8132, lo: 0xb0, hi: 0xb0},
+ {value: 0x8132, lo: 0xb2, hi: 0xb3},
+ {value: 0x812d, lo: 0xb4, hi: 0xb4},
+ {value: 0x8132, lo: 0xb7, hi: 0xb8},
+ {value: 0x8132, lo: 0xbe, hi: 0xbf},
+ // Block 0x60, offset 0x22b
+ {value: 0x0000, lo: 0x02},
+ {value: 0x8132, lo: 0x81, hi: 0x81},
+ {value: 0x8104, lo: 0xb6, hi: 0xb6},
+ // Block 0x61, offset 0x22e
+ {value: 0x0008, lo: 0x03},
+ {value: 0x1637, lo: 0x9c, hi: 0x9d},
+ {value: 0x0125, lo: 0x9e, hi: 0x9e},
+ {value: 0x1643, lo: 0x9f, hi: 0x9f},
+ // Block 0x62, offset 0x232
+ {value: 0x0000, lo: 0x01},
+ {value: 0x8104, lo: 0xad, hi: 0xad},
+ // Block 0x63, offset 0x234
+ {value: 0x0000, lo: 0x06},
+ {value: 0xe500, lo: 0x80, hi: 0x80},
+ {value: 0xc600, lo: 0x81, hi: 0x9b},
+ {value: 0xe500, lo: 0x9c, hi: 0x9c},
+ {value: 0xc600, lo: 0x9d, hi: 0xb7},
+ {value: 0xe500, lo: 0xb8, hi: 0xb8},
+ {value: 0xc600, lo: 0xb9, hi: 0xbf},
+ // Block 0x64, offset 0x23b
+ {value: 0x0000, lo: 0x05},
+ {value: 0xc600, lo: 0x80, hi: 0x93},
+ {value: 0xe500, lo: 0x94, hi: 0x94},
+ {value: 0xc600, lo: 0x95, hi: 0xaf},
+ {value: 0xe500, lo: 0xb0, hi: 0xb0},
+ {value: 0xc600, lo: 0xb1, hi: 0xbf},
+ // Block 0x65, offset 0x241
+ {value: 0x0000, lo: 0x05},
+ {value: 0xc600, lo: 0x80, hi: 0x8b},
+ {value: 0xe500, lo: 0x8c, hi: 0x8c},
+ {value: 0xc600, lo: 0x8d, hi: 0xa7},
+ {value: 0xe500, lo: 0xa8, hi: 0xa8},
+ {value: 0xc600, lo: 0xa9, hi: 0xbf},
+ // Block 0x66, offset 0x247
+ {value: 0x0000, lo: 0x07},
+ {value: 0xc600, lo: 0x80, hi: 0x83},
+ {value: 0xe500, lo: 0x84, hi: 0x84},
+ {value: 0xc600, lo: 0x85, hi: 0x9f},
+ {value: 0xe500, lo: 0xa0, hi: 0xa0},
+ {value: 0xc600, lo: 0xa1, hi: 0xbb},
+ {value: 0xe500, lo: 0xbc, hi: 0xbc},
+ {value: 0xc600, lo: 0xbd, hi: 0xbf},
+ // Block 0x67, offset 0x24f
+ {value: 0x0000, lo: 0x05},
+ {value: 0xc600, lo: 0x80, hi: 0x97},
+ {value: 0xe500, lo: 0x98, hi: 0x98},
+ {value: 0xc600, lo: 0x99, hi: 0xb3},
+ {value: 0xe500, lo: 0xb4, hi: 0xb4},
+ {value: 0xc600, lo: 0xb5, hi: 0xbf},
+ // Block 0x68, offset 0x255
+ {value: 0x0000, lo: 0x05},
+ {value: 0xc600, lo: 0x80, hi: 0x8f},
+ {value: 0xe500, lo: 0x90, hi: 0x90},
+ {value: 0xc600, lo: 0x91, hi: 0xab},
+ {value: 0xe500, lo: 0xac, hi: 0xac},
+ {value: 0xc600, lo: 0xad, hi: 0xbf},
+ // Block 0x69, offset 0x25b
+ {value: 0x0000, lo: 0x05},
+ {value: 0xc600, lo: 0x80, hi: 0x87},
+ {value: 0xe500, lo: 0x88, hi: 0x88},
+ {value: 0xc600, lo: 0x89, hi: 0xa3},
+ {value: 0xe500, lo: 0xa4, hi: 0xa4},
+ {value: 0xc600, lo: 0xa5, hi: 0xbf},
+ // Block 0x6a, offset 0x261
+ {value: 0x0000, lo: 0x03},
+ {value: 0xc600, lo: 0x80, hi: 0x87},
+ {value: 0xe500, lo: 0x88, hi: 0x88},
+ {value: 0xc600, lo: 0x89, hi: 0xa3},
+ // Block 0x6b, offset 0x265
+ {value: 0x0002, lo: 0x01},
+ {value: 0x0003, lo: 0x81, hi: 0xbf},
+ // Block 0x6c, offset 0x267
+ {value: 0x0000, lo: 0x01},
+ {value: 0x812d, lo: 0xbd, hi: 0xbd},
+ // Block 0x6d, offset 0x269
+ {value: 0x0000, lo: 0x01},
+ {value: 0x812d, lo: 0xa0, hi: 0xa0},
+ // Block 0x6e, offset 0x26b
+ {value: 0x0000, lo: 0x01},
+ {value: 0x8132, lo: 0xb6, hi: 0xba},
+ // Block 0x6f, offset 0x26d
+ {value: 0x002c, lo: 0x05},
+ {value: 0x812d, lo: 0x8d, hi: 0x8d},
+ {value: 0x8132, lo: 0x8f, hi: 0x8f},
+ {value: 0x8132, lo: 0xb8, hi: 0xb8},
+ {value: 0x8101, lo: 0xb9, hi: 0xba},
+ {value: 0x8104, lo: 0xbf, hi: 0xbf},
+ // Block 0x70, offset 0x273
+ {value: 0x0000, lo: 0x02},
+ {value: 0x8132, lo: 0xa5, hi: 0xa5},
+ {value: 0x812d, lo: 0xa6, hi: 0xa6},
+ // Block 0x71, offset 0x276
+ {value: 0x0000, lo: 0x02},
+ {value: 0x8104, lo: 0x86, hi: 0x86},
+ {value: 0x8104, lo: 0xbf, hi: 0xbf},
+ // Block 0x72, offset 0x279
+ {value: 0x17fe, lo: 0x07},
+ {value: 0xa000, lo: 0x99, hi: 0x99},
+ {value: 0x4238, lo: 0x9a, hi: 0x9a},
+ {value: 0xa000, lo: 0x9b, hi: 0x9b},
+ {value: 0x4242, lo: 0x9c, hi: 0x9c},
+ {value: 0xa000, lo: 0xa5, hi: 0xa5},
+ {value: 0x424c, lo: 0xab, hi: 0xab},
+ {value: 0x8104, lo: 0xb9, hi: 0xba},
+ // Block 0x73, offset 0x281
+ {value: 0x0000, lo: 0x06},
+ {value: 0x8132, lo: 0x80, hi: 0x82},
+ {value: 0x9900, lo: 0xa7, hi: 0xa7},
+ {value: 0x2d7e, lo: 0xae, hi: 0xae},
+ {value: 0x2d88, lo: 0xaf, hi: 0xaf},
+ {value: 0xa000, lo: 0xb1, hi: 0xb2},
+ {value: 0x8104, lo: 0xb3, hi: 0xb4},
+ // Block 0x74, offset 0x288
+ {value: 0x0000, lo: 0x02},
+ {value: 0x8104, lo: 0x80, hi: 0x80},
+ {value: 0x8102, lo: 0x8a, hi: 0x8a},
+ // Block 0x75, offset 0x28b
+ {value: 0x0000, lo: 0x02},
+ {value: 0x8104, lo: 0xb5, hi: 0xb5},
+ {value: 0x8102, lo: 0xb6, hi: 0xb6},
+ // Block 0x76, offset 0x28e
+ {value: 0x0002, lo: 0x01},
+ {value: 0x8102, lo: 0xa9, hi: 0xaa},
+ // Block 0x77, offset 0x290
+ {value: 0x0000, lo: 0x07},
+ {value: 0xa000, lo: 0x87, hi: 0x87},
+ {value: 0x2d92, lo: 0x8b, hi: 0x8b},
+ {value: 0x2d9c, lo: 0x8c, hi: 0x8c},
+ {value: 0x8104, lo: 0x8d, hi: 0x8d},
+ {value: 0x9900, lo: 0x97, hi: 0x97},
+ {value: 0x8132, lo: 0xa6, hi: 0xac},
+ {value: 0x8132, lo: 0xb0, hi: 0xb4},
+ // Block 0x78, offset 0x298
+ {value: 0x0000, lo: 0x02},
+ {value: 0x8104, lo: 0x82, hi: 0x82},
+ {value: 0x8102, lo: 0x86, hi: 0x86},
+ // Block 0x79, offset 0x29b
+ {value: 0x6b5a, lo: 0x06},
+ {value: 0x9900, lo: 0xb0, hi: 0xb0},
+ {value: 0xa000, lo: 0xb9, hi: 0xb9},
+ {value: 0x9900, lo: 0xba, hi: 0xba},
+ {value: 0x2db0, lo: 0xbb, hi: 0xbb},
+ {value: 0x2da6, lo: 0xbc, hi: 0xbd},
+ {value: 0x2dba, lo: 0xbe, hi: 0xbe},
+ // Block 0x7a, offset 0x2a2
+ {value: 0x0000, lo: 0x02},
+ {value: 0x8104, lo: 0x82, hi: 0x82},
+ {value: 0x8102, lo: 0x83, hi: 0x83},
+ // Block 0x7b, offset 0x2a5
+ {value: 0x0000, lo: 0x05},
+ {value: 0x9900, lo: 0xaf, hi: 0xaf},
+ {value: 0xa000, lo: 0xb8, hi: 0xb9},
+ {value: 0x2dc4, lo: 0xba, hi: 0xba},
+ {value: 0x2dce, lo: 0xbb, hi: 0xbb},
+ {value: 0x8104, lo: 0xbf, hi: 0xbf},
+ // Block 0x7c, offset 0x2ab
+ {value: 0x0000, lo: 0x01},
+ {value: 0x8102, lo: 0x80, hi: 0x80},
+ // Block 0x7d, offset 0x2ad
+ {value: 0x0000, lo: 0x01},
+ {value: 0x8104, lo: 0xbf, hi: 0xbf},
+ // Block 0x7e, offset 0x2af
+ {value: 0x0000, lo: 0x02},
+ {value: 0x8104, lo: 0xb6, hi: 0xb6},
+ {value: 0x8102, lo: 0xb7, hi: 0xb7},
+ // Block 0x7f, offset 0x2b2
+ {value: 0x0000, lo: 0x01},
+ {value: 0x8104, lo: 0xab, hi: 0xab},
+ // Block 0x80, offset 0x2b4
+ {value: 0x0000, lo: 0x01},
+ {value: 0x8101, lo: 0xb0, hi: 0xb4},
+ // Block 0x81, offset 0x2b6
+ {value: 0x0000, lo: 0x01},
+ {value: 0x8132, lo: 0xb0, hi: 0xb6},
+ // Block 0x82, offset 0x2b8
+ {value: 0x0000, lo: 0x01},
+ {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: 0x812b, lo: 0xa5, hi: 0xa6},
+ {value: 0x8101, lo: 0xa7, hi: 0xa9},
+ {value: 0x8130, lo: 0xad, hi: 0xad},
+ {value: 0x812b, lo: 0xae, hi: 0xb2},
+ {value: 0x812d, lo: 0xbb, hi: 0xbf},
+ // Block 0x84, offset 0x2c7
+ {value: 0x0000, lo: 0x09},
+ {value: 0x812d, lo: 0x80, hi: 0x82},
+ {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},
+ // Block 0x85, offset 0x2d1
+ {value: 0x0000, lo: 0x01},
+ {value: 0x4710, lo: 0x80, hi: 0x80},
+ // Block 0x86, offset 0x2d3
+ {value: 0x0000, lo: 0x01},
+ {value: 0x8132, lo: 0x82, hi: 0x84},
+ // Block 0x87, offset 0x2d5
+ {value: 0x0002, lo: 0x03},
+ {value: 0x0043, lo: 0x80, hi: 0x99},
+ {value: 0x0083, lo: 0x9a, hi: 0xb3},
+ {value: 0x0043, lo: 0xb4, hi: 0xbf},
+ // Block 0x88, offset 0x2d9
+ {value: 0x0002, lo: 0x04},
+ {value: 0x005b, lo: 0x80, hi: 0x8d},
+ {value: 0x0083, lo: 0x8e, hi: 0x94},
+ {value: 0x0093, lo: 0x96, hi: 0xa7},
+ {value: 0x0043, lo: 0xa8, hi: 0xbf},
+ // Block 0x89, offset 0x2de
+ {value: 0x0002, lo: 0x0b},
+ {value: 0x0073, lo: 0x80, hi: 0x81},
+ {value: 0x0083, lo: 0x82, hi: 0x9b},
+ {value: 0x0043, lo: 0x9c, hi: 0x9c},
+ {value: 0x0047, lo: 0x9e, hi: 0x9f},
+ {value: 0x004f, lo: 0xa2, hi: 0xa2},
+ {value: 0x0055, lo: 0xa5, hi: 0xa6},
+ {value: 0x005d, lo: 0xa9, hi: 0xac},
+ {value: 0x0067, lo: 0xae, hi: 0xb5},
+ {value: 0x0083, lo: 0xb6, hi: 0xb9},
+ {value: 0x008d, lo: 0xbb, hi: 0xbb},
+ {value: 0x0091, lo: 0xbd, hi: 0xbf},
+ // Block 0x8a, offset 0x2ea
+ {value: 0x0002, lo: 0x04},
+ {value: 0x0097, lo: 0x80, hi: 0x83},
+ {value: 0x00a1, lo: 0x85, hi: 0x8f},
+ {value: 0x0043, lo: 0x90, hi: 0xa9},
+ {value: 0x0083, lo: 0xaa, hi: 0xbf},
+ // Block 0x8b, offset 0x2ef
+ {value: 0x0002, lo: 0x08},
+ {value: 0x00af, lo: 0x80, hi: 0x83},
+ {value: 0x0043, lo: 0x84, hi: 0x85},
+ {value: 0x0049, lo: 0x87, hi: 0x8a},
+ {value: 0x0055, lo: 0x8d, hi: 0x94},
+ {value: 0x0067, lo: 0x96, hi: 0x9c},
+ {value: 0x0083, lo: 0x9e, hi: 0xb7},
+ {value: 0x0043, lo: 0xb8, hi: 0xb9},
+ {value: 0x0049, lo: 0xbb, hi: 0xbe},
+ // Block 0x8c, offset 0x2f8
+ {value: 0x0002, lo: 0x05},
+ {value: 0x0053, lo: 0x80, hi: 0x84},
+ {value: 0x005f, lo: 0x86, hi: 0x86},
+ {value: 0x0067, lo: 0x8a, hi: 0x90},
+ {value: 0x0083, lo: 0x92, hi: 0xab},
+ {value: 0x0043, lo: 0xac, hi: 0xbf},
+ // Block 0x8d, offset 0x2fe
+ {value: 0x0002, lo: 0x04},
+ {value: 0x006b, lo: 0x80, hi: 0x85},
+ {value: 0x0083, lo: 0x86, hi: 0x9f},
+ {value: 0x0043, lo: 0xa0, hi: 0xb9},
+ {value: 0x0083, lo: 0xba, hi: 0xbf},
+ // Block 0x8e, offset 0x303
+ {value: 0x0002, lo: 0x03},
+ {value: 0x008f, lo: 0x80, hi: 0x93},
+ {value: 0x0043, lo: 0x94, hi: 0xad},
+ {value: 0x0083, lo: 0xae, hi: 0xbf},
+ // Block 0x8f, offset 0x307
+ {value: 0x0002, lo: 0x04},
+ {value: 0x00a7, lo: 0x80, hi: 0x87},
+ {value: 0x0043, lo: 0x88, hi: 0xa1},
+ {value: 0x0083, lo: 0xa2, hi: 0xbb},
+ {value: 0x0043, lo: 0xbc, hi: 0xbf},
+ // Block 0x90, offset 0x30c
+ {value: 0x0002, lo: 0x03},
+ {value: 0x004b, lo: 0x80, hi: 0x95},
+ {value: 0x0083, lo: 0x96, hi: 0xaf},
+ {value: 0x0043, lo: 0xb0, hi: 0xbf},
+ // Block 0x91, offset 0x310
+ {value: 0x0003, lo: 0x0f},
+ {value: 0x01b8, lo: 0x80, hi: 0x80},
+ {value: 0x045f, lo: 0x81, hi: 0x81},
+ {value: 0x01bb, lo: 0x82, hi: 0x9a},
+ {value: 0x045b, lo: 0x9b, hi: 0x9b},
+ {value: 0x01c7, lo: 0x9c, hi: 0x9c},
+ {value: 0x01d0, lo: 0x9d, hi: 0x9d},
+ {value: 0x01d6, lo: 0x9e, hi: 0x9e},
+ {value: 0x01fa, lo: 0x9f, hi: 0x9f},
+ {value: 0x01eb, lo: 0xa0, hi: 0xa0},
+ {value: 0x01e8, lo: 0xa1, hi: 0xa1},
+ {value: 0x0173, lo: 0xa2, hi: 0xb2},
+ {value: 0x0188, lo: 0xb3, hi: 0xb3},
+ {value: 0x01a6, lo: 0xb4, hi: 0xba},
+ {value: 0x045f, lo: 0xbb, hi: 0xbb},
+ {value: 0x01bb, lo: 0xbc, hi: 0xbf},
+ // Block 0x92, offset 0x320
+ {value: 0x0003, lo: 0x0d},
+ {value: 0x01c7, lo: 0x80, hi: 0x94},
+ {value: 0x045b, lo: 0x95, hi: 0x95},
+ {value: 0x01c7, lo: 0x96, hi: 0x96},
+ {value: 0x01d0, lo: 0x97, hi: 0x97},
+ {value: 0x01d6, lo: 0x98, hi: 0x98},
+ {value: 0x01fa, lo: 0x99, hi: 0x99},
+ {value: 0x01eb, lo: 0x9a, hi: 0x9a},
+ {value: 0x01e8, lo: 0x9b, hi: 0x9b},
+ {value: 0x0173, lo: 0x9c, hi: 0xac},
+ {value: 0x0188, lo: 0xad, hi: 0xad},
+ {value: 0x01a6, lo: 0xae, hi: 0xb4},
+ {value: 0x045f, lo: 0xb5, hi: 0xb5},
+ {value: 0x01bb, lo: 0xb6, hi: 0xbf},
+ // Block 0x93, offset 0x32e
+ {value: 0x0003, lo: 0x0d},
+ {value: 0x01d9, lo: 0x80, hi: 0x8e},
+ {value: 0x045b, lo: 0x8f, hi: 0x8f},
+ {value: 0x01c7, lo: 0x90, hi: 0x90},
+ {value: 0x01d0, lo: 0x91, hi: 0x91},
+ {value: 0x01d6, lo: 0x92, hi: 0x92},
+ {value: 0x01fa, lo: 0x93, hi: 0x93},
+ {value: 0x01eb, lo: 0x94, hi: 0x94},
+ {value: 0x01e8, lo: 0x95, hi: 0x95},
+ {value: 0x0173, lo: 0x96, hi: 0xa6},
+ {value: 0x0188, lo: 0xa7, hi: 0xa7},
+ {value: 0x01a6, lo: 0xa8, hi: 0xae},
+ {value: 0x045f, lo: 0xaf, hi: 0xaf},
+ {value: 0x01bb, lo: 0xb0, hi: 0xbf},
+ // Block 0x94, offset 0x33c
+ {value: 0x0003, lo: 0x0d},
+ {value: 0x01eb, lo: 0x80, hi: 0x88},
+ {value: 0x045b, lo: 0x89, hi: 0x89},
+ {value: 0x01c7, lo: 0x8a, hi: 0x8a},
+ {value: 0x01d0, lo: 0x8b, hi: 0x8b},
+ {value: 0x01d6, lo: 0x8c, hi: 0x8c},
+ {value: 0x01fa, lo: 0x8d, hi: 0x8d},
+ {value: 0x01eb, lo: 0x8e, hi: 0x8e},
+ {value: 0x01e8, lo: 0x8f, hi: 0x8f},
+ {value: 0x0173, lo: 0x90, hi: 0xa0},
+ {value: 0x0188, lo: 0xa1, hi: 0xa1},
+ {value: 0x01a6, lo: 0xa2, hi: 0xa8},
+ {value: 0x045f, lo: 0xa9, hi: 0xa9},
+ {value: 0x01bb, lo: 0xaa, hi: 0xbf},
+ // Block 0x95, offset 0x34a
+ {value: 0x0000, lo: 0x05},
+ {value: 0x8132, lo: 0x80, hi: 0x86},
+ {value: 0x8132, lo: 0x88, hi: 0x98},
+ {value: 0x8132, lo: 0x9b, hi: 0xa1},
+ {value: 0x8132, lo: 0xa3, hi: 0xa4},
+ {value: 0x8132, lo: 0xa6, hi: 0xaa},
+ // Block 0x96, offset 0x350
+ {value: 0x0000, lo: 0x01},
+ {value: 0x812d, lo: 0x90, hi: 0x96},
+ // Block 0x97, offset 0x352
+ {value: 0x0000, lo: 0x02},
+ {value: 0x8132, lo: 0x84, hi: 0x89},
+ {value: 0x8102, lo: 0x8a, hi: 0x8a},
+ // Block 0x98, offset 0x355
+ {value: 0x0002, lo: 0x09},
+ {value: 0x0063, lo: 0x80, hi: 0x89},
+ {value: 0x1951, lo: 0x8a, hi: 0x8a},
+ {value: 0x1981, lo: 0x8b, hi: 0x8b},
+ {value: 0x199c, lo: 0x8c, hi: 0x8c},
+ {value: 0x19a2, lo: 0x8d, hi: 0x8d},
+ {value: 0x1bc0, lo: 0x8e, hi: 0x8e},
+ {value: 0x19ae, lo: 0x8f, hi: 0x8f},
+ {value: 0x197b, lo: 0xaa, hi: 0xaa},
+ {value: 0x197e, lo: 0xab, hi: 0xab},
+ // Block 0x99, offset 0x35f
+ {value: 0x0000, lo: 0x01},
+ {value: 0x193f, lo: 0x90, hi: 0x90},
+ // Block 0x9a, offset 0x361
+ {value: 0x0028, lo: 0x09},
+ {value: 0x2862, lo: 0x80, hi: 0x80},
+ {value: 0x2826, lo: 0x81, hi: 0x81},
+ {value: 0x2830, lo: 0x82, hi: 0x82},
+ {value: 0x2844, lo: 0x83, hi: 0x84},
+ {value: 0x284e, lo: 0x85, hi: 0x86},
+ {value: 0x283a, lo: 0x87, hi: 0x87},
+ {value: 0x2858, lo: 0x88, hi: 0x88},
+ {value: 0x0b6f, lo: 0x90, hi: 0x90},
+ {value: 0x08e7, lo: 0x91, hi: 0x91},
+}
+
+// recompMap: 7520 bytes (entries only)
+var recompMap = map[uint32]rune{
+ 0x00410300: 0x00C0,
+ 0x00410301: 0x00C1,
+ 0x00410302: 0x00C2,
+ 0x00410303: 0x00C3,
+ 0x00410308: 0x00C4,
+ 0x0041030A: 0x00C5,
+ 0x00430327: 0x00C7,
+ 0x00450300: 0x00C8,
+ 0x00450301: 0x00C9,
+ 0x00450302: 0x00CA,
+ 0x00450308: 0x00CB,
+ 0x00490300: 0x00CC,
+ 0x00490301: 0x00CD,
+ 0x00490302: 0x00CE,
+ 0x00490308: 0x00CF,
+ 0x004E0303: 0x00D1,
+ 0x004F0300: 0x00D2,
+ 0x004F0301: 0x00D3,
+ 0x004F0302: 0x00D4,
+ 0x004F0303: 0x00D5,
+ 0x004F0308: 0x00D6,
+ 0x00550300: 0x00D9,
+ 0x00550301: 0x00DA,
+ 0x00550302: 0x00DB,
+ 0x00550308: 0x00DC,
+ 0x00590301: 0x00DD,
+ 0x00610300: 0x00E0,
+ 0x00610301: 0x00E1,
+ 0x00610302: 0x00E2,
+ 0x00610303: 0x00E3,
+ 0x00610308: 0x00E4,
+ 0x0061030A: 0x00E5,
+ 0x00630327: 0x00E7,
+ 0x00650300: 0x00E8,
+ 0x00650301: 0x00E9,
+ 0x00650302: 0x00EA,
+ 0x00650308: 0x00EB,
+ 0x00690300: 0x00EC,
+ 0x00690301: 0x00ED,
+ 0x00690302: 0x00EE,
+ 0x00690308: 0x00EF,
+ 0x006E0303: 0x00F1,
+ 0x006F0300: 0x00F2,
+ 0x006F0301: 0x00F3,
+ 0x006F0302: 0x00F4,
+ 0x006F0303: 0x00F5,
+ 0x006F0308: 0x00F6,
+ 0x00750300: 0x00F9,
+ 0x00750301: 0x00FA,
+ 0x00750302: 0x00FB,
+ 0x00750308: 0x00FC,
+ 0x00790301: 0x00FD,
+ 0x00790308: 0x00FF,
+ 0x00410304: 0x0100,
+ 0x00610304: 0x0101,
+ 0x00410306: 0x0102,
+ 0x00610306: 0x0103,
+ 0x00410328: 0x0104,
+ 0x00610328: 0x0105,
+ 0x00430301: 0x0106,
+ 0x00630301: 0x0107,
+ 0x00430302: 0x0108,
+ 0x00630302: 0x0109,
+ 0x00430307: 0x010A,
+ 0x00630307: 0x010B,
+ 0x0043030C: 0x010C,
+ 0x0063030C: 0x010D,
+ 0x0044030C: 0x010E,
+ 0x0064030C: 0x010F,
+ 0x00450304: 0x0112,
+ 0x00650304: 0x0113,
+ 0x00450306: 0x0114,
+ 0x00650306: 0x0115,
+ 0x00450307: 0x0116,
+ 0x00650307: 0x0117,
+ 0x00450328: 0x0118,
+ 0x00650328: 0x0119,
+ 0x0045030C: 0x011A,
+ 0x0065030C: 0x011B,
+ 0x00470302: 0x011C,
+ 0x00670302: 0x011D,
+ 0x00470306: 0x011E,
+ 0x00670306: 0x011F,
+ 0x00470307: 0x0120,
+ 0x00670307: 0x0121,
+ 0x00470327: 0x0122,
+ 0x00670327: 0x0123,
+ 0x00480302: 0x0124,
+ 0x00680302: 0x0125,
+ 0x00490303: 0x0128,
+ 0x00690303: 0x0129,
+ 0x00490304: 0x012A,
+ 0x00690304: 0x012B,
+ 0x00490306: 0x012C,
+ 0x00690306: 0x012D,
+ 0x00490328: 0x012E,
+ 0x00690328: 0x012F,
+ 0x00490307: 0x0130,
+ 0x004A0302: 0x0134,
+ 0x006A0302: 0x0135,
+ 0x004B0327: 0x0136,
+ 0x006B0327: 0x0137,
+ 0x004C0301: 0x0139,
+ 0x006C0301: 0x013A,
+ 0x004C0327: 0x013B,
+ 0x006C0327: 0x013C,
+ 0x004C030C: 0x013D,
+ 0x006C030C: 0x013E,
+ 0x004E0301: 0x0143,
+ 0x006E0301: 0x0144,
+ 0x004E0327: 0x0145,
+ 0x006E0327: 0x0146,
+ 0x004E030C: 0x0147,
+ 0x006E030C: 0x0148,
+ 0x004F0304: 0x014C,
+ 0x006F0304: 0x014D,
+ 0x004F0306: 0x014E,
+ 0x006F0306: 0x014F,
+ 0x004F030B: 0x0150,
+ 0x006F030B: 0x0151,
+ 0x00520301: 0x0154,
+ 0x00720301: 0x0155,
+ 0x00520327: 0x0156,
+ 0x00720327: 0x0157,
+ 0x0052030C: 0x0158,
+ 0x0072030C: 0x0159,
+ 0x00530301: 0x015A,
+ 0x00730301: 0x015B,
+ 0x00530302: 0x015C,
+ 0x00730302: 0x015D,
+ 0x00530327: 0x015E,
+ 0x00730327: 0x015F,
+ 0x0053030C: 0x0160,
+ 0x0073030C: 0x0161,
+ 0x00540327: 0x0162,
+ 0x00740327: 0x0163,
+ 0x0054030C: 0x0164,
+ 0x0074030C: 0x0165,
+ 0x00550303: 0x0168,
+ 0x00750303: 0x0169,
+ 0x00550304: 0x016A,
+ 0x00750304: 0x016B,
+ 0x00550306: 0x016C,
+ 0x00750306: 0x016D,
+ 0x0055030A: 0x016E,
+ 0x0075030A: 0x016F,
+ 0x0055030B: 0x0170,
+ 0x0075030B: 0x0171,
+ 0x00550328: 0x0172,
+ 0x00750328: 0x0173,
+ 0x00570302: 0x0174,
+ 0x00770302: 0x0175,
+ 0x00590302: 0x0176,
+ 0x00790302: 0x0177,
+ 0x00590308: 0x0178,
+ 0x005A0301: 0x0179,
+ 0x007A0301: 0x017A,
+ 0x005A0307: 0x017B,
+ 0x007A0307: 0x017C,
+ 0x005A030C: 0x017D,
+ 0x007A030C: 0x017E,
+ 0x004F031B: 0x01A0,
+ 0x006F031B: 0x01A1,
+ 0x0055031B: 0x01AF,
+ 0x0075031B: 0x01B0,
+ 0x0041030C: 0x01CD,
+ 0x0061030C: 0x01CE,
+ 0x0049030C: 0x01CF,
+ 0x0069030C: 0x01D0,
+ 0x004F030C: 0x01D1,
+ 0x006F030C: 0x01D2,
+ 0x0055030C: 0x01D3,
+ 0x0075030C: 0x01D4,
+ 0x00DC0304: 0x01D5,
+ 0x00FC0304: 0x01D6,
+ 0x00DC0301: 0x01D7,
+ 0x00FC0301: 0x01D8,
+ 0x00DC030C: 0x01D9,
+ 0x00FC030C: 0x01DA,
+ 0x00DC0300: 0x01DB,
+ 0x00FC0300: 0x01DC,
+ 0x00C40304: 0x01DE,
+ 0x00E40304: 0x01DF,
+ 0x02260304: 0x01E0,
+ 0x02270304: 0x01E1,
+ 0x00C60304: 0x01E2,
+ 0x00E60304: 0x01E3,
+ 0x0047030C: 0x01E6,
+ 0x0067030C: 0x01E7,
+ 0x004B030C: 0x01E8,
+ 0x006B030C: 0x01E9,
+ 0x004F0328: 0x01EA,
+ 0x006F0328: 0x01EB,
+ 0x01EA0304: 0x01EC,
+ 0x01EB0304: 0x01ED,
+ 0x01B7030C: 0x01EE,
+ 0x0292030C: 0x01EF,
+ 0x006A030C: 0x01F0,
+ 0x00470301: 0x01F4,
+ 0x00670301: 0x01F5,
+ 0x004E0300: 0x01F8,
+ 0x006E0300: 0x01F9,
+ 0x00C50301: 0x01FA,
+ 0x00E50301: 0x01FB,
+ 0x00C60301: 0x01FC,
+ 0x00E60301: 0x01FD,
+ 0x00D80301: 0x01FE,
+ 0x00F80301: 0x01FF,
+ 0x0041030F: 0x0200,
+ 0x0061030F: 0x0201,
+ 0x00410311: 0x0202,
+ 0x00610311: 0x0203,
+ 0x0045030F: 0x0204,
+ 0x0065030F: 0x0205,
+ 0x00450311: 0x0206,
+ 0x00650311: 0x0207,
+ 0x0049030F: 0x0208,
+ 0x0069030F: 0x0209,
+ 0x00490311: 0x020A,
+ 0x00690311: 0x020B,
+ 0x004F030F: 0x020C,
+ 0x006F030F: 0x020D,
+ 0x004F0311: 0x020E,
+ 0x006F0311: 0x020F,
+ 0x0052030F: 0x0210,
+ 0x0072030F: 0x0211,
+ 0x00520311: 0x0212,
+ 0x00720311: 0x0213,
+ 0x0055030F: 0x0214,
+ 0x0075030F: 0x0215,
+ 0x00550311: 0x0216,
+ 0x00750311: 0x0217,
+ 0x00530326: 0x0218,
+ 0x00730326: 0x0219,
+ 0x00540326: 0x021A,
+ 0x00740326: 0x021B,
+ 0x0048030C: 0x021E,
+ 0x0068030C: 0x021F,
+ 0x00410307: 0x0226,
+ 0x00610307: 0x0227,
+ 0x00450327: 0x0228,
+ 0x00650327: 0x0229,
+ 0x00D60304: 0x022A,
+ 0x00F60304: 0x022B,
+ 0x00D50304: 0x022C,
+ 0x00F50304: 0x022D,
+ 0x004F0307: 0x022E,
+ 0x006F0307: 0x022F,
+ 0x022E0304: 0x0230,
+ 0x022F0304: 0x0231,
+ 0x00590304: 0x0232,
+ 0x00790304: 0x0233,
+ 0x00A80301: 0x0385,
+ 0x03910301: 0x0386,
+ 0x03950301: 0x0388,
+ 0x03970301: 0x0389,
+ 0x03990301: 0x038A,
+ 0x039F0301: 0x038C,
+ 0x03A50301: 0x038E,
+ 0x03A90301: 0x038F,
+ 0x03CA0301: 0x0390,
+ 0x03990308: 0x03AA,
+ 0x03A50308: 0x03AB,
+ 0x03B10301: 0x03AC,
+ 0x03B50301: 0x03AD,
+ 0x03B70301: 0x03AE,
+ 0x03B90301: 0x03AF,
+ 0x03CB0301: 0x03B0,
+ 0x03B90308: 0x03CA,
+ 0x03C50308: 0x03CB,
+ 0x03BF0301: 0x03CC,
+ 0x03C50301: 0x03CD,
+ 0x03C90301: 0x03CE,
+ 0x03D20301: 0x03D3,
+ 0x03D20308: 0x03D4,
+ 0x04150300: 0x0400,
+ 0x04150308: 0x0401,
+ 0x04130301: 0x0403,
+ 0x04060308: 0x0407,
+ 0x041A0301: 0x040C,
+ 0x04180300: 0x040D,
+ 0x04230306: 0x040E,
+ 0x04180306: 0x0419,
+ 0x04380306: 0x0439,
+ 0x04350300: 0x0450,
+ 0x04350308: 0x0451,
+ 0x04330301: 0x0453,
+ 0x04560308: 0x0457,
+ 0x043A0301: 0x045C,
+ 0x04380300: 0x045D,
+ 0x04430306: 0x045E,
+ 0x0474030F: 0x0476,
+ 0x0475030F: 0x0477,
+ 0x04160306: 0x04C1,
+ 0x04360306: 0x04C2,
+ 0x04100306: 0x04D0,
+ 0x04300306: 0x04D1,
+ 0x04100308: 0x04D2,
+ 0x04300308: 0x04D3,
+ 0x04150306: 0x04D6,
+ 0x04350306: 0x04D7,
+ 0x04D80308: 0x04DA,
+ 0x04D90308: 0x04DB,
+ 0x04160308: 0x04DC,
+ 0x04360308: 0x04DD,
+ 0x04170308: 0x04DE,
+ 0x04370308: 0x04DF,
+ 0x04180304: 0x04E2,
+ 0x04380304: 0x04E3,
+ 0x04180308: 0x04E4,
+ 0x04380308: 0x04E5,
+ 0x041E0308: 0x04E6,
+ 0x043E0308: 0x04E7,
+ 0x04E80308: 0x04EA,
+ 0x04E90308: 0x04EB,
+ 0x042D0308: 0x04EC,
+ 0x044D0308: 0x04ED,
+ 0x04230304: 0x04EE,
+ 0x04430304: 0x04EF,
+ 0x04230308: 0x04F0,
+ 0x04430308: 0x04F1,
+ 0x0423030B: 0x04F2,
+ 0x0443030B: 0x04F3,
+ 0x04270308: 0x04F4,
+ 0x04470308: 0x04F5,
+ 0x042B0308: 0x04F8,
+ 0x044B0308: 0x04F9,
+ 0x06270653: 0x0622,
+ 0x06270654: 0x0623,
+ 0x06480654: 0x0624,
+ 0x06270655: 0x0625,
+ 0x064A0654: 0x0626,
+ 0x06D50654: 0x06C0,
+ 0x06C10654: 0x06C2,
+ 0x06D20654: 0x06D3,
+ 0x0928093C: 0x0929,
+ 0x0930093C: 0x0931,
+ 0x0933093C: 0x0934,
+ 0x09C709BE: 0x09CB,
+ 0x09C709D7: 0x09CC,
+ 0x0B470B56: 0x0B48,
+ 0x0B470B3E: 0x0B4B,
+ 0x0B470B57: 0x0B4C,
+ 0x0B920BD7: 0x0B94,
+ 0x0BC60BBE: 0x0BCA,
+ 0x0BC70BBE: 0x0BCB,
+ 0x0BC60BD7: 0x0BCC,
+ 0x0C460C56: 0x0C48,
+ 0x0CBF0CD5: 0x0CC0,
+ 0x0CC60CD5: 0x0CC7,
+ 0x0CC60CD6: 0x0CC8,
+ 0x0CC60CC2: 0x0CCA,
+ 0x0CCA0CD5: 0x0CCB,
+ 0x0D460D3E: 0x0D4A,
+ 0x0D470D3E: 0x0D4B,
+ 0x0D460D57: 0x0D4C,
+ 0x0DD90DCA: 0x0DDA,
+ 0x0DD90DCF: 0x0DDC,
+ 0x0DDC0DCA: 0x0DDD,
+ 0x0DD90DDF: 0x0DDE,
+ 0x1025102E: 0x1026,
+ 0x1B051B35: 0x1B06,
+ 0x1B071B35: 0x1B08,
+ 0x1B091B35: 0x1B0A,
+ 0x1B0B1B35: 0x1B0C,
+ 0x1B0D1B35: 0x1B0E,
+ 0x1B111B35: 0x1B12,
+ 0x1B3A1B35: 0x1B3B,
+ 0x1B3C1B35: 0x1B3D,
+ 0x1B3E1B35: 0x1B40,
+ 0x1B3F1B35: 0x1B41,
+ 0x1B421B35: 0x1B43,
+ 0x00410325: 0x1E00,
+ 0x00610325: 0x1E01,
+ 0x00420307: 0x1E02,
+ 0x00620307: 0x1E03,
+ 0x00420323: 0x1E04,
+ 0x00620323: 0x1E05,
+ 0x00420331: 0x1E06,
+ 0x00620331: 0x1E07,
+ 0x00C70301: 0x1E08,
+ 0x00E70301: 0x1E09,
+ 0x00440307: 0x1E0A,
+ 0x00640307: 0x1E0B,
+ 0x00440323: 0x1E0C,
+ 0x00640323: 0x1E0D,
+ 0x00440331: 0x1E0E,
+ 0x00640331: 0x1E0F,
+ 0x00440327: 0x1E10,
+ 0x00640327: 0x1E11,
+ 0x0044032D: 0x1E12,
+ 0x0064032D: 0x1E13,
+ 0x01120300: 0x1E14,
+ 0x01130300: 0x1E15,
+ 0x01120301: 0x1E16,
+ 0x01130301: 0x1E17,
+ 0x0045032D: 0x1E18,
+ 0x0065032D: 0x1E19,
+ 0x00450330: 0x1E1A,
+ 0x00650330: 0x1E1B,
+ 0x02280306: 0x1E1C,
+ 0x02290306: 0x1E1D,
+ 0x00460307: 0x1E1E,
+ 0x00660307: 0x1E1F,
+ 0x00470304: 0x1E20,
+ 0x00670304: 0x1E21,
+ 0x00480307: 0x1E22,
+ 0x00680307: 0x1E23,
+ 0x00480323: 0x1E24,
+ 0x00680323: 0x1E25,
+ 0x00480308: 0x1E26,
+ 0x00680308: 0x1E27,
+ 0x00480327: 0x1E28,
+ 0x00680327: 0x1E29,
+ 0x0048032E: 0x1E2A,
+ 0x0068032E: 0x1E2B,
+ 0x00490330: 0x1E2C,
+ 0x00690330: 0x1E2D,
+ 0x00CF0301: 0x1E2E,
+ 0x00EF0301: 0x1E2F,
+ 0x004B0301: 0x1E30,
+ 0x006B0301: 0x1E31,
+ 0x004B0323: 0x1E32,
+ 0x006B0323: 0x1E33,
+ 0x004B0331: 0x1E34,
+ 0x006B0331: 0x1E35,
+ 0x004C0323: 0x1E36,
+ 0x006C0323: 0x1E37,
+ 0x1E360304: 0x1E38,
+ 0x1E370304: 0x1E39,
+ 0x004C0331: 0x1E3A,
+ 0x006C0331: 0x1E3B,
+ 0x004C032D: 0x1E3C,
+ 0x006C032D: 0x1E3D,
+ 0x004D0301: 0x1E3E,
+ 0x006D0301: 0x1E3F,
+ 0x004D0307: 0x1E40,
+ 0x006D0307: 0x1E41,
+ 0x004D0323: 0x1E42,
+ 0x006D0323: 0x1E43,
+ 0x004E0307: 0x1E44,
+ 0x006E0307: 0x1E45,
+ 0x004E0323: 0x1E46,
+ 0x006E0323: 0x1E47,
+ 0x004E0331: 0x1E48,
+ 0x006E0331: 0x1E49,
+ 0x004E032D: 0x1E4A,
+ 0x006E032D: 0x1E4B,
+ 0x00D50301: 0x1E4C,
+ 0x00F50301: 0x1E4D,
+ 0x00D50308: 0x1E4E,
+ 0x00F50308: 0x1E4F,
+ 0x014C0300: 0x1E50,
+ 0x014D0300: 0x1E51,
+ 0x014C0301: 0x1E52,
+ 0x014D0301: 0x1E53,
+ 0x00500301: 0x1E54,
+ 0x00700301: 0x1E55,
+ 0x00500307: 0x1E56,
+ 0x00700307: 0x1E57,
+ 0x00520307: 0x1E58,
+ 0x00720307: 0x1E59,
+ 0x00520323: 0x1E5A,
+ 0x00720323: 0x1E5B,
+ 0x1E5A0304: 0x1E5C,
+ 0x1E5B0304: 0x1E5D,
+ 0x00520331: 0x1E5E,
+ 0x00720331: 0x1E5F,
+ 0x00530307: 0x1E60,
+ 0x00730307: 0x1E61,
+ 0x00530323: 0x1E62,
+ 0x00730323: 0x1E63,
+ 0x015A0307: 0x1E64,
+ 0x015B0307: 0x1E65,
+ 0x01600307: 0x1E66,
+ 0x01610307: 0x1E67,
+ 0x1E620307: 0x1E68,
+ 0x1E630307: 0x1E69,
+ 0x00540307: 0x1E6A,
+ 0x00740307: 0x1E6B,
+ 0x00540323: 0x1E6C,
+ 0x00740323: 0x1E6D,
+ 0x00540331: 0x1E6E,
+ 0x00740331: 0x1E6F,
+ 0x0054032D: 0x1E70,
+ 0x0074032D: 0x1E71,
+ 0x00550324: 0x1E72,
+ 0x00750324: 0x1E73,
+ 0x00550330: 0x1E74,
+ 0x00750330: 0x1E75,
+ 0x0055032D: 0x1E76,
+ 0x0075032D: 0x1E77,
+ 0x01680301: 0x1E78,
+ 0x01690301: 0x1E79,
+ 0x016A0308: 0x1E7A,
+ 0x016B0308: 0x1E7B,
+ 0x00560303: 0x1E7C,
+ 0x00760303: 0x1E7D,
+ 0x00560323: 0x1E7E,
+ 0x00760323: 0x1E7F,
+ 0x00570300: 0x1E80,
+ 0x00770300: 0x1E81,
+ 0x00570301: 0x1E82,
+ 0x00770301: 0x1E83,
+ 0x00570308: 0x1E84,
+ 0x00770308: 0x1E85,
+ 0x00570307: 0x1E86,
+ 0x00770307: 0x1E87,
+ 0x00570323: 0x1E88,
+ 0x00770323: 0x1E89,
+ 0x00580307: 0x1E8A,
+ 0x00780307: 0x1E8B,
+ 0x00580308: 0x1E8C,
+ 0x00780308: 0x1E8D,
+ 0x00590307: 0x1E8E,
+ 0x00790307: 0x1E8F,
+ 0x005A0302: 0x1E90,
+ 0x007A0302: 0x1E91,
+ 0x005A0323: 0x1E92,
+ 0x007A0323: 0x1E93,
+ 0x005A0331: 0x1E94,
+ 0x007A0331: 0x1E95,
+ 0x00680331: 0x1E96,
+ 0x00740308: 0x1E97,
+ 0x0077030A: 0x1E98,
+ 0x0079030A: 0x1E99,
+ 0x017F0307: 0x1E9B,
+ 0x00410323: 0x1EA0,
+ 0x00610323: 0x1EA1,
+ 0x00410309: 0x1EA2,
+ 0x00610309: 0x1EA3,
+ 0x00C20301: 0x1EA4,
+ 0x00E20301: 0x1EA5,
+ 0x00C20300: 0x1EA6,
+ 0x00E20300: 0x1EA7,
+ 0x00C20309: 0x1EA8,
+ 0x00E20309: 0x1EA9,
+ 0x00C20303: 0x1EAA,
+ 0x00E20303: 0x1EAB,
+ 0x1EA00302: 0x1EAC,
+ 0x1EA10302: 0x1EAD,
+ 0x01020301: 0x1EAE,
+ 0x01030301: 0x1EAF,
+ 0x01020300: 0x1EB0,
+ 0x01030300: 0x1EB1,
+ 0x01020309: 0x1EB2,
+ 0x01030309: 0x1EB3,
+ 0x01020303: 0x1EB4,
+ 0x01030303: 0x1EB5,
+ 0x1EA00306: 0x1EB6,
+ 0x1EA10306: 0x1EB7,
+ 0x00450323: 0x1EB8,
+ 0x00650323: 0x1EB9,
+ 0x00450309: 0x1EBA,
+ 0x00650309: 0x1EBB,
+ 0x00450303: 0x1EBC,
+ 0x00650303: 0x1EBD,
+ 0x00CA0301: 0x1EBE,
+ 0x00EA0301: 0x1EBF,
+ 0x00CA0300: 0x1EC0,
+ 0x00EA0300: 0x1EC1,
+ 0x00CA0309: 0x1EC2,
+ 0x00EA0309: 0x1EC3,
+ 0x00CA0303: 0x1EC4,
+ 0x00EA0303: 0x1EC5,
+ 0x1EB80302: 0x1EC6,
+ 0x1EB90302: 0x1EC7,
+ 0x00490309: 0x1EC8,
+ 0x00690309: 0x1EC9,
+ 0x00490323: 0x1ECA,
+ 0x00690323: 0x1ECB,
+ 0x004F0323: 0x1ECC,
+ 0x006F0323: 0x1ECD,
+ 0x004F0309: 0x1ECE,
+ 0x006F0309: 0x1ECF,
+ 0x00D40301: 0x1ED0,
+ 0x00F40301: 0x1ED1,
+ 0x00D40300: 0x1ED2,
+ 0x00F40300: 0x1ED3,
+ 0x00D40309: 0x1ED4,
+ 0x00F40309: 0x1ED5,
+ 0x00D40303: 0x1ED6,
+ 0x00F40303: 0x1ED7,
+ 0x1ECC0302: 0x1ED8,
+ 0x1ECD0302: 0x1ED9,
+ 0x01A00301: 0x1EDA,
+ 0x01A10301: 0x1EDB,
+ 0x01A00300: 0x1EDC,
+ 0x01A10300: 0x1EDD,
+ 0x01A00309: 0x1EDE,
+ 0x01A10309: 0x1EDF,
+ 0x01A00303: 0x1EE0,
+ 0x01A10303: 0x1EE1,
+ 0x01A00323: 0x1EE2,
+ 0x01A10323: 0x1EE3,
+ 0x00550323: 0x1EE4,
+ 0x00750323: 0x1EE5,
+ 0x00550309: 0x1EE6,
+ 0x00750309: 0x1EE7,
+ 0x01AF0301: 0x1EE8,
+ 0x01B00301: 0x1EE9,
+ 0x01AF0300: 0x1EEA,
+ 0x01B00300: 0x1EEB,
+ 0x01AF0309: 0x1EEC,
+ 0x01B00309: 0x1EED,
+ 0x01AF0303: 0x1EEE,
+ 0x01B00303: 0x1EEF,
+ 0x01AF0323: 0x1EF0,
+ 0x01B00323: 0x1EF1,
+ 0x00590300: 0x1EF2,
+ 0x00790300: 0x1EF3,
+ 0x00590323: 0x1EF4,
+ 0x00790323: 0x1EF5,
+ 0x00590309: 0x1EF6,
+ 0x00790309: 0x1EF7,
+ 0x00590303: 0x1EF8,
+ 0x00790303: 0x1EF9,
+ 0x03B10313: 0x1F00,
+ 0x03B10314: 0x1F01,
+ 0x1F000300: 0x1F02,
+ 0x1F010300: 0x1F03,
+ 0x1F000301: 0x1F04,
+ 0x1F010301: 0x1F05,
+ 0x1F000342: 0x1F06,
+ 0x1F010342: 0x1F07,
+ 0x03910313: 0x1F08,
+ 0x03910314: 0x1F09,
+ 0x1F080300: 0x1F0A,
+ 0x1F090300: 0x1F0B,
+ 0x1F080301: 0x1F0C,
+ 0x1F090301: 0x1F0D,
+ 0x1F080342: 0x1F0E,
+ 0x1F090342: 0x1F0F,
+ 0x03B50313: 0x1F10,
+ 0x03B50314: 0x1F11,
+ 0x1F100300: 0x1F12,
+ 0x1F110300: 0x1F13,
+ 0x1F100301: 0x1F14,
+ 0x1F110301: 0x1F15,
+ 0x03950313: 0x1F18,
+ 0x03950314: 0x1F19,
+ 0x1F180300: 0x1F1A,
+ 0x1F190300: 0x1F1B,
+ 0x1F180301: 0x1F1C,
+ 0x1F190301: 0x1F1D,
+ 0x03B70313: 0x1F20,
+ 0x03B70314: 0x1F21,
+ 0x1F200300: 0x1F22,
+ 0x1F210300: 0x1F23,
+ 0x1F200301: 0x1F24,
+ 0x1F210301: 0x1F25,
+ 0x1F200342: 0x1F26,
+ 0x1F210342: 0x1F27,
+ 0x03970313: 0x1F28,
+ 0x03970314: 0x1F29,
+ 0x1F280300: 0x1F2A,
+ 0x1F290300: 0x1F2B,
+ 0x1F280301: 0x1F2C,
+ 0x1F290301: 0x1F2D,
+ 0x1F280342: 0x1F2E,
+ 0x1F290342: 0x1F2F,
+ 0x03B90313: 0x1F30,
+ 0x03B90314: 0x1F31,
+ 0x1F300300: 0x1F32,
+ 0x1F310300: 0x1F33,
+ 0x1F300301: 0x1F34,
+ 0x1F310301: 0x1F35,
+ 0x1F300342: 0x1F36,
+ 0x1F310342: 0x1F37,
+ 0x03990313: 0x1F38,
+ 0x03990314: 0x1F39,
+ 0x1F380300: 0x1F3A,
+ 0x1F390300: 0x1F3B,
+ 0x1F380301: 0x1F3C,
+ 0x1F390301: 0x1F3D,
+ 0x1F380342: 0x1F3E,
+ 0x1F390342: 0x1F3F,
+ 0x03BF0313: 0x1F40,
+ 0x03BF0314: 0x1F41,
+ 0x1F400300: 0x1F42,
+ 0x1F410300: 0x1F43,
+ 0x1F400301: 0x1F44,
+ 0x1F410301: 0x1F45,
+ 0x039F0313: 0x1F48,
+ 0x039F0314: 0x1F49,
+ 0x1F480300: 0x1F4A,
+ 0x1F490300: 0x1F4B,
+ 0x1F480301: 0x1F4C,
+ 0x1F490301: 0x1F4D,
+ 0x03C50313: 0x1F50,
+ 0x03C50314: 0x1F51,
+ 0x1F500300: 0x1F52,
+ 0x1F510300: 0x1F53,
+ 0x1F500301: 0x1F54,
+ 0x1F510301: 0x1F55,
+ 0x1F500342: 0x1F56,
+ 0x1F510342: 0x1F57,
+ 0x03A50314: 0x1F59,
+ 0x1F590300: 0x1F5B,
+ 0x1F590301: 0x1F5D,
+ 0x1F590342: 0x1F5F,
+ 0x03C90313: 0x1F60,
+ 0x03C90314: 0x1F61,
+ 0x1F600300: 0x1F62,
+ 0x1F610300: 0x1F63,
+ 0x1F600301: 0x1F64,
+ 0x1F610301: 0x1F65,
+ 0x1F600342: 0x1F66,
+ 0x1F610342: 0x1F67,
+ 0x03A90313: 0x1F68,
+ 0x03A90314: 0x1F69,
+ 0x1F680300: 0x1F6A,
+ 0x1F690300: 0x1F6B,
+ 0x1F680301: 0x1F6C,
+ 0x1F690301: 0x1F6D,
+ 0x1F680342: 0x1F6E,
+ 0x1F690342: 0x1F6F,
+ 0x03B10300: 0x1F70,
+ 0x03B50300: 0x1F72,
+ 0x03B70300: 0x1F74,
+ 0x03B90300: 0x1F76,
+ 0x03BF0300: 0x1F78,
+ 0x03C50300: 0x1F7A,
+ 0x03C90300: 0x1F7C,
+ 0x1F000345: 0x1F80,
+ 0x1F010345: 0x1F81,
+ 0x1F020345: 0x1F82,
+ 0x1F030345: 0x1F83,
+ 0x1F040345: 0x1F84,
+ 0x1F050345: 0x1F85,
+ 0x1F060345: 0x1F86,
+ 0x1F070345: 0x1F87,
+ 0x1F080345: 0x1F88,
+ 0x1F090345: 0x1F89,
+ 0x1F0A0345: 0x1F8A,
+ 0x1F0B0345: 0x1F8B,
+ 0x1F0C0345: 0x1F8C,
+ 0x1F0D0345: 0x1F8D,
+ 0x1F0E0345: 0x1F8E,
+ 0x1F0F0345: 0x1F8F,
+ 0x1F200345: 0x1F90,
+ 0x1F210345: 0x1F91,
+ 0x1F220345: 0x1F92,
+ 0x1F230345: 0x1F93,
+ 0x1F240345: 0x1F94,
+ 0x1F250345: 0x1F95,
+ 0x1F260345: 0x1F96,
+ 0x1F270345: 0x1F97,
+ 0x1F280345: 0x1F98,
+ 0x1F290345: 0x1F99,
+ 0x1F2A0345: 0x1F9A,
+ 0x1F2B0345: 0x1F9B,
+ 0x1F2C0345: 0x1F9C,
+ 0x1F2D0345: 0x1F9D,
+ 0x1F2E0345: 0x1F9E,
+ 0x1F2F0345: 0x1F9F,
+ 0x1F600345: 0x1FA0,
+ 0x1F610345: 0x1FA1,
+ 0x1F620345: 0x1FA2,
+ 0x1F630345: 0x1FA3,
+ 0x1F640345: 0x1FA4,
+ 0x1F650345: 0x1FA5,
+ 0x1F660345: 0x1FA6,
+ 0x1F670345: 0x1FA7,
+ 0x1F680345: 0x1FA8,
+ 0x1F690345: 0x1FA9,
+ 0x1F6A0345: 0x1FAA,
+ 0x1F6B0345: 0x1FAB,
+ 0x1F6C0345: 0x1FAC,
+ 0x1F6D0345: 0x1FAD,
+ 0x1F6E0345: 0x1FAE,
+ 0x1F6F0345: 0x1FAF,
+ 0x03B10306: 0x1FB0,
+ 0x03B10304: 0x1FB1,
+ 0x1F700345: 0x1FB2,
+ 0x03B10345: 0x1FB3,
+ 0x03AC0345: 0x1FB4,
+ 0x03B10342: 0x1FB6,
+ 0x1FB60345: 0x1FB7,
+ 0x03910306: 0x1FB8,
+ 0x03910304: 0x1FB9,
+ 0x03910300: 0x1FBA,
+ 0x03910345: 0x1FBC,
+ 0x00A80342: 0x1FC1,
+ 0x1F740345: 0x1FC2,
+ 0x03B70345: 0x1FC3,
+ 0x03AE0345: 0x1FC4,
+ 0x03B70342: 0x1FC6,
+ 0x1FC60345: 0x1FC7,
+ 0x03950300: 0x1FC8,
+ 0x03970300: 0x1FCA,
+ 0x03970345: 0x1FCC,
+ 0x1FBF0300: 0x1FCD,
+ 0x1FBF0301: 0x1FCE,
+ 0x1FBF0342: 0x1FCF,
+ 0x03B90306: 0x1FD0,
+ 0x03B90304: 0x1FD1,
+ 0x03CA0300: 0x1FD2,
+ 0x03B90342: 0x1FD6,
+ 0x03CA0342: 0x1FD7,
+ 0x03990306: 0x1FD8,
+ 0x03990304: 0x1FD9,
+ 0x03990300: 0x1FDA,
+ 0x1FFE0300: 0x1FDD,
+ 0x1FFE0301: 0x1FDE,
+ 0x1FFE0342: 0x1FDF,
+ 0x03C50306: 0x1FE0,
+ 0x03C50304: 0x1FE1,
+ 0x03CB0300: 0x1FE2,
+ 0x03C10313: 0x1FE4,
+ 0x03C10314: 0x1FE5,
+ 0x03C50342: 0x1FE6,
+ 0x03CB0342: 0x1FE7,
+ 0x03A50306: 0x1FE8,
+ 0x03A50304: 0x1FE9,
+ 0x03A50300: 0x1FEA,
+ 0x03A10314: 0x1FEC,
+ 0x00A80300: 0x1FED,
+ 0x1F7C0345: 0x1FF2,
+ 0x03C90345: 0x1FF3,
+ 0x03CE0345: 0x1FF4,
+ 0x03C90342: 0x1FF6,
+ 0x1FF60345: 0x1FF7,
+ 0x039F0300: 0x1FF8,
+ 0x03A90300: 0x1FFA,
+ 0x03A90345: 0x1FFC,
+ 0x21900338: 0x219A,
+ 0x21920338: 0x219B,
+ 0x21940338: 0x21AE,
+ 0x21D00338: 0x21CD,
+ 0x21D40338: 0x21CE,
+ 0x21D20338: 0x21CF,
+ 0x22030338: 0x2204,
+ 0x22080338: 0x2209,
+ 0x220B0338: 0x220C,
+ 0x22230338: 0x2224,
+ 0x22250338: 0x2226,
+ 0x223C0338: 0x2241,
+ 0x22430338: 0x2244,
+ 0x22450338: 0x2247,
+ 0x22480338: 0x2249,
+ 0x003D0338: 0x2260,
+ 0x22610338: 0x2262,
+ 0x224D0338: 0x226D,
+ 0x003C0338: 0x226E,
+ 0x003E0338: 0x226F,
+ 0x22640338: 0x2270,
+ 0x22650338: 0x2271,
+ 0x22720338: 0x2274,
+ 0x22730338: 0x2275,
+ 0x22760338: 0x2278,
+ 0x22770338: 0x2279,
+ 0x227A0338: 0x2280,
+ 0x227B0338: 0x2281,
+ 0x22820338: 0x2284,
+ 0x22830338: 0x2285,
+ 0x22860338: 0x2288,
+ 0x22870338: 0x2289,
+ 0x22A20338: 0x22AC,
+ 0x22A80338: 0x22AD,
+ 0x22A90338: 0x22AE,
+ 0x22AB0338: 0x22AF,
+ 0x227C0338: 0x22E0,
+ 0x227D0338: 0x22E1,
+ 0x22910338: 0x22E2,
+ 0x22920338: 0x22E3,
+ 0x22B20338: 0x22EA,
+ 0x22B30338: 0x22EB,
+ 0x22B40338: 0x22EC,
+ 0x22B50338: 0x22ED,
+ 0x304B3099: 0x304C,
+ 0x304D3099: 0x304E,
+ 0x304F3099: 0x3050,
+ 0x30513099: 0x3052,
+ 0x30533099: 0x3054,
+ 0x30553099: 0x3056,
+ 0x30573099: 0x3058,
+ 0x30593099: 0x305A,
+ 0x305B3099: 0x305C,
+ 0x305D3099: 0x305E,
+ 0x305F3099: 0x3060,
+ 0x30613099: 0x3062,
+ 0x30643099: 0x3065,
+ 0x30663099: 0x3067,
+ 0x30683099: 0x3069,
+ 0x306F3099: 0x3070,
+ 0x306F309A: 0x3071,
+ 0x30723099: 0x3073,
+ 0x3072309A: 0x3074,
+ 0x30753099: 0x3076,
+ 0x3075309A: 0x3077,
+ 0x30783099: 0x3079,
+ 0x3078309A: 0x307A,
+ 0x307B3099: 0x307C,
+ 0x307B309A: 0x307D,
+ 0x30463099: 0x3094,
+ 0x309D3099: 0x309E,
+ 0x30AB3099: 0x30AC,
+ 0x30AD3099: 0x30AE,
+ 0x30AF3099: 0x30B0,
+ 0x30B13099: 0x30B2,
+ 0x30B33099: 0x30B4,
+ 0x30B53099: 0x30B6,
+ 0x30B73099: 0x30B8,
+ 0x30B93099: 0x30BA,
+ 0x30BB3099: 0x30BC,
+ 0x30BD3099: 0x30BE,
+ 0x30BF3099: 0x30C0,
+ 0x30C13099: 0x30C2,
+ 0x30C43099: 0x30C5,
+ 0x30C63099: 0x30C7,
+ 0x30C83099: 0x30C9,
+ 0x30CF3099: 0x30D0,
+ 0x30CF309A: 0x30D1,
+ 0x30D23099: 0x30D3,
+ 0x30D2309A: 0x30D4,
+ 0x30D53099: 0x30D6,
+ 0x30D5309A: 0x30D7,
+ 0x30D83099: 0x30D9,
+ 0x30D8309A: 0x30DA,
+ 0x30DB3099: 0x30DC,
+ 0x30DB309A: 0x30DD,
+ 0x30A63099: 0x30F4,
+ 0x30EF3099: 0x30F7,
+ 0x30F03099: 0x30F8,
+ 0x30F13099: 0x30F9,
+ 0x30F23099: 0x30FA,
+ 0x30FD3099: 0x30FE,
+ 0x109910BA: 0x1109A,
+ 0x109B10BA: 0x1109C,
+ 0x10A510BA: 0x110AB,
+ 0x11311127: 0x1112E,
+ 0x11321127: 0x1112F,
+ 0x1347133E: 0x1134B,
+ 0x13471357: 0x1134C,
+ 0x14B914BA: 0x114BB,
+ 0x14B914B0: 0x114BC,
+ 0x14B914BD: 0x114BE,
+ 0x15B815AF: 0x115BA,
+ 0x15B915AF: 0x115BB,
+}
+
+// Total size of tables: 53KB (53976 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
new file mode 100644
index 0000000..b341789
--- /dev/null
+++ b/src/vendor/golang_org/x/text/unicode/norm/transform.go
@@ -0,0 +1,88 @@
+// Copyright 2013 The Go Authors. 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
+
+import (
+ "unicode/utf8"
+
+ "golang_org/x/text/transform"
+)
+
+// Reset implements the Reset method of the transform.Transformer interface.
+func (Form) Reset() {}
+
+// Transform implements the Transform method of the transform.Transformer
+// interface. It may need to write segments of up to MaxSegmentSize at once.
+// Users should either catch ErrShortDst and allow dst to grow or have dst be at
+// least of size MaxTransformChunkSize to be guaranteed of progress.
+func (f Form) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
+ n := 0
+ // Cap the maximum number of src bytes to check.
+ b := src
+ eof := atEOF
+ if ns := len(dst); ns < len(b) {
+ err = transform.ErrShortDst
+ eof = false
+ b = b[:ns]
+ }
+ i, ok := formTable[f].quickSpan(inputBytes(b), n, len(b), eof)
+ n += copy(dst[n:], b[n:i])
+ if !ok {
+ nDst, nSrc, err = f.transform(dst[n:], src[n:], atEOF)
+ return nDst + n, nSrc + n, err
+ }
+ if n < len(src) && !atEOF {
+ err = transform.ErrShortSrc
+ }
+ return n, n, err
+}
+
+func flushTransform(rb *reorderBuffer) bool {
+ // Write out (must fully fit in dst, or else it is a ErrShortDst).
+ if len(rb.out) < rb.nrune*utf8.UTFMax {
+ return false
+ }
+ rb.out = rb.out[rb.flushCopy(rb.out):]
+ return true
+}
+
+var errs = []error{nil, transform.ErrShortDst, transform.ErrShortSrc}
+
+// transform implements the transform.Transformer interface. It is only called
+// when quickSpan does not pass for a given string.
+func (f Form) transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
+ // TODO: get rid of reorderBuffer. See CL 23460044.
+ rb := reorderBuffer{}
+ rb.init(f, src)
+ for {
+ // Load segment into reorder buffer.
+ rb.setFlusher(dst[nDst:], flushTransform)
+ end := decomposeSegment(&rb, nSrc, atEOF)
+ if end < 0 {
+ return nDst, nSrc, errs[-end]
+ }
+ nDst = len(dst) - len(rb.out)
+ nSrc = end
+
+ // Next quickSpan.
+ end = rb.nsrc
+ eof := atEOF
+ if n := nSrc + len(dst) - nDst; n < end {
+ err = transform.ErrShortDst
+ end = n
+ eof = false
+ }
+ end, ok := rb.f.quickSpan(rb.src, nSrc, end, eof)
+ n := copy(dst[nDst:], rb.src.bytes[nSrc:end])
+ nSrc += n
+ nDst += n
+ if ok {
+ if n < rb.nsrc && !atEOF {
+ err = transform.ErrShortSrc
+ }
+ return nDst, nSrc, err
+ }
+ }
+}
diff --git a/src/vendor/golang_org/x/text/unicode/norm/trie.go b/src/vendor/golang_org/x/text/unicode/norm/trie.go
new file mode 100644
index 0000000..423386b
--- /dev/null
+++ b/src/vendor/golang_org/x/text/unicode/norm/trie.go
@@ -0,0 +1,54 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package norm
+
+type valueRange struct {
+ value uint16 // header: value:stride
+ lo, hi byte // header: lo:n
+}
+
+type sparseBlocks struct {
+ values []valueRange
+ offset []uint16
+}
+
+var nfcSparse = sparseBlocks{
+ values: nfcSparseValues[:],
+ offset: nfcSparseOffset[:],
+}
+
+var nfkcSparse = sparseBlocks{
+ values: nfkcSparseValues[:],
+ offset: nfkcSparseOffset[:],
+}
+
+var (
+ nfcData = newNfcTrie(0)
+ nfkcData = newNfkcTrie(0)
+)
+
+// lookupValue 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/text/unicode/norm/triegen.go b/src/vendor/golang_org/x/text/unicode/norm/triegen.go
new file mode 100644
index 0000000..45d7119
--- /dev/null
+++ b/src/vendor/golang_org/x/text/unicode/norm/triegen.go
@@ -0,0 +1,117 @@
+// Copyright 2011 The Go Authors. 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
+
+// Trie table generator.
+// Used by make*tables tools to generate a go file with trie data structures
+// for mapping UTF-8 to a 16-bit value. All but the last byte in a UTF-8 byte
+// sequence are used to lookup offsets in the index table to be used for the
+// next byte. The last byte is used to index into a table with 16-bit values.
+
+package main
+
+import (
+ "fmt"
+ "io"
+)
+
+const maxSparseEntries = 16
+
+type normCompacter struct {
+ sparseBlocks [][]uint64
+ sparseOffset []uint16
+ sparseCount int
+ name string
+}
+
+func mostFrequentStride(a []uint64) int {
+ counts := make(map[int]int)
+ var v int
+ for _, x := range a {
+ if stride := int(x) - v; v != 0 && stride >= 0 {
+ counts[stride]++
+ }
+ v = int(x)
+ }
+ var maxs, maxc int
+ for stride, cnt := range counts {
+ if cnt > maxc || (cnt == maxc && stride < maxs) {
+ maxs, maxc = stride, cnt
+ }
+ }
+ return maxs
+}
+
+func countSparseEntries(a []uint64) int {
+ stride := mostFrequentStride(a)
+ var v, count int
+ for _, tv := range a {
+ if int(tv)-v != stride {
+ if tv != 0 {
+ count++
+ }
+ }
+ v = int(tv)
+ }
+ return count
+}
+
+func (c *normCompacter) Size(v []uint64) (sz int, ok bool) {
+ if n := countSparseEntries(v); n <= maxSparseEntries {
+ return (n+1)*4 + 2, true
+ }
+ return 0, false
+}
+
+func (c *normCompacter) Store(v []uint64) uint32 {
+ h := uint32(len(c.sparseOffset))
+ c.sparseBlocks = append(c.sparseBlocks, v)
+ c.sparseOffset = append(c.sparseOffset, uint16(c.sparseCount))
+ c.sparseCount += countSparseEntries(v) + 1
+ return h
+}
+
+func (c *normCompacter) Handler() string {
+ return c.name + "Sparse.lookup"
+}
+
+func (c *normCompacter) Print(w io.Writer) (retErr error) {
+ p := func(f string, x ...interface{}) {
+ if _, err := fmt.Fprintf(w, f, x...); retErr == nil && err != nil {
+ retErr = err
+ }
+ }
+
+ ls := len(c.sparseBlocks)
+ p("// %sSparseOffset: %d entries, %d bytes\n", c.name, ls, ls*2)
+ p("var %sSparseOffset = %#v\n\n", c.name, c.sparseOffset)
+
+ ns := c.sparseCount
+ p("// %sSparseValues: %d entries, %d bytes\n", c.name, ns, ns*4)
+ p("var %sSparseValues = [%d]valueRange {", c.name, ns)
+ for i, b := range c.sparseBlocks {
+ p("\n// Block %#x, offset %#x", i, c.sparseOffset[i])
+ var v int
+ stride := mostFrequentStride(b)
+ n := countSparseEntries(b)
+ p("\n{value:%#04x,lo:%#02x},", stride, uint8(n))
+ for i, nv := range b {
+ if int(nv)-v != stride {
+ if v != 0 {
+ p(",hi:%#02x},", 0x80+i-1)
+ }
+ if nv != 0 {
+ p("\n{value:%#04x,lo:%#02x", nv, 0x80+i)
+ }
+ }
+ v = int(nv)
+ }
+ if v != 0 {
+ p(",hi:%#02x},", 0x80+len(b)-1)
+ }
+ }
+ p("\n}\n\n")
+ return
+}
diff --git a/src/vendor/golang_org/x/text/width/kind_string.go b/src/vendor/golang_org/x/text/width/kind_string.go
new file mode 100644
index 0000000..ab4fee5
--- /dev/null
+++ b/src/vendor/golang_org/x/text/width/kind_string.go
@@ -0,0 +1,16 @@
+// 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
new file mode 100644
index 0000000..242da0f
--- /dev/null
+++ b/src/vendor/golang_org/x/text/width/tables.go
@@ -0,0 +1,1284 @@
+// 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
new file mode 100644
index 0000000..04f1a3f
--- /dev/null
+++ b/src/vendor/golang_org/x/text/width/transform.go
@@ -0,0 +1,239 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+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
new file mode 100644
index 0000000..0ecffb4
--- /dev/null
+++ b/src/vendor/golang_org/x/text/width/trieval.go
@@ -0,0 +1,30 @@
+// 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
new file mode 100644
index 0000000..27f55b8
--- /dev/null
+++ b/src/vendor/golang_org/x/text/width/width.go
@@ -0,0 +1,206 @@
+// Copyright 2015 The Go 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/bugs/bug395.go b/test/bugs/bug395.go
deleted file mode 100644
index 4fe81e0..0000000
--- a/test/bugs/bug395.go
+++ /dev/null
@@ -1,24 +0,0 @@
-// skip
-
-// When issue 1909 is fixed, change from skip to compile.
-
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// Issue 1909
-// Would OOM due to exponential recursion on Foo's expanded methodset in nodefmt
-
-package test
-
-type Foo interface {
- Bar() interface {
- Foo
- }
- Baz() interface {
- Foo
- }
- Bug() interface {
- Foo
- }
-}
diff --git a/test/bugs/placeholder b/test/bugs/placeholder
deleted file mode 100644
index b816d34..0000000
--- a/test/bugs/placeholder
+++ /dev/null
@@ -1,2 +0,0 @@
-This file keeps Mercurial from deleting the directory
-when there are no known bugs.
diff --git a/test/checkbce.go b/test/checkbce.go
index fa0ea12..59bd41b 100644
--- a/test/checkbce.go
+++ b/test/checkbce.go
@@ -21,7 +21,9 @@ func f1(a [256]int, i int) {
if 4 <= i && i < len(a) {
useInt(a[i])
useInt(a[i-1]) // ERROR "Found IsInBounds$"
- useInt(a[i-4]) // ERROR "Found IsInBounds$"
+ // TODO: 'if 4 <= i && i < len(a)' gets rewritten to 'if uint(i - 4) < 256 - 4',
+ // which the bounds checker cannot yet use to infer that the next line doesn't need a bounds check.
+ useInt(a[i-4])
}
}
diff --git a/test/const.go b/test/const.go
index 6c29336..f8e0a75 100644
--- a/test/const.go
+++ b/test/const.go
@@ -123,9 +123,44 @@ func floats() {
assert(f == f1e3, "f == f1e3")
}
+func interfaces() {
+ var (
+ nilN interface{}
+ nilI *int
+ five = 5
+
+ _ = nil == interface{}(nil)
+ _ = interface{}(nil) == nil
+ )
+ ii := func(i1 interface{}, i2 interface{}) bool { return i1 == i2 }
+ ni := func(n interface{}, i int) bool { return n == i }
+ in := func(i int, n interface{}) bool { return i == n }
+ pi := func(p *int, i interface{}) bool { return p == i }
+ ip := func(i interface{}, p *int) bool { return i == p }
+
+ assert((interface{}(nil) == interface{}(nil)) == ii(nilN, nilN),
+ "for interface{}==interface{} compiler == runtime")
+
+ assert(((*int)(nil) == interface{}(nil)) == pi(nilI, nilN),
+ "for *int==interface{} compiler == runtime")
+ assert((interface{}(nil) == (*int)(nil)) == ip(nilN, nilI),
+ "for interface{}==*int compiler == runtime")
+
+ assert((&five == interface{}(nil)) == pi(&five, nilN),
+ "for interface{}==*int compiler == runtime")
+ assert((interface{}(nil) == &five) == ip(nilN, &five),
+ "for interface{}==*int compiler == runtime")
+
+ assert((5 == interface{}(5)) == ni(five, five),
+ "for int==interface{} compiler == runtime")
+ assert((interface{}(5) == 5) == in(five, five),
+ "for interface{}==int comipiler == runtime")
+}
+
func main() {
ints()
floats()
+ interfaces()
assert(ctrue == true, "ctrue == true")
assert(cfalse == false, "cfalse == false")
diff --git a/test/convert2.go b/test/convert2.go
new file mode 100644
index 0000000..c500638
--- /dev/null
+++ b/test/convert2.go
@@ -0,0 +1,315 @@
+// 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 various valid and invalid struct assignments and conversions.
+// Does not compile.
+
+package main
+
+type I interface {
+ m()
+}
+
+// conversions between structs
+
+func _() {
+ type S struct{}
+ type T struct{}
+ var s S
+ var t T
+ var u struct{}
+ s = s
+ s = t // ERROR "cannot use .* in assignment"
+ s = u
+ s = S(s)
+ s = S(t)
+ s = S(u)
+ t = u
+ t = T(u)
+}
+
+func _() {
+ type S struct{ x int }
+ type T struct {
+ x int "foo"
+ }
+ var s S
+ var t T
+ var u struct {
+ x int "bar"
+ }
+ s = s
+ s = t // ERROR "cannot use .* in assignment"
+ s = u // ERROR "cannot use .* in assignment"
+ s = S(s)
+ s = S(t)
+ s = S(u)
+ t = u // ERROR "cannot use .* in assignment"
+ t = T(u)
+}
+
+func _() {
+ type E struct{ x int }
+ type S struct{ x E }
+ type T struct {
+ x E "foo"
+ }
+ var s S
+ var t T
+ var u struct {
+ x E "bar"
+ }
+ s = s
+ s = t // ERROR "cannot use .* in assignment"
+ s = u // ERROR "cannot use .* in assignment"
+ s = S(s)
+ s = S(t)
+ s = S(u)
+ t = u // ERROR "cannot use .* in assignment"
+ t = T(u)
+}
+
+func _() {
+ type S struct {
+ x struct {
+ x int "foo"
+ }
+ }
+ type T struct {
+ x struct {
+ x int "bar"
+ } "foo"
+ }
+ var s S
+ var t T
+ var u struct {
+ x struct {
+ x int "bar"
+ } "bar"
+ }
+ s = s
+ s = t // ERROR "cannot use .* in assignment"
+ s = u // ERROR "cannot use .* in assignment"
+ s = S(s)
+ s = S(t)
+ s = S(u)
+ t = u // ERROR "cannot use .* in assignment"
+ t = T(u)
+}
+
+func _() {
+ type E1 struct {
+ x int "foo"
+ }
+ type E2 struct {
+ x int "bar"
+ }
+ type S struct{ x E1 }
+ type T struct {
+ x E2 "foo"
+ }
+ var s S
+ var t T
+ var u struct {
+ x E2 "bar"
+ }
+ s = s
+ s = t // ERROR "cannot use .* in assignment"
+ s = u // ERROR "cannot use .* in assignment"
+ s = S(s)
+ s = S(t) // ERROR "cannot convert"
+ s = S(u) // ERROR "cannot convert"
+ t = u // ERROR "cannot use .* in assignment"
+ t = T(u)
+}
+
+func _() {
+ type E struct{ x int }
+ type S struct {
+ f func(struct {
+ x int "foo"
+ })
+ }
+ type T struct {
+ f func(struct {
+ x int "bar"
+ })
+ }
+ var s S
+ var t T
+ var u struct{ f func(E) }
+ s = s
+ s = t // ERROR "cannot use .* in assignment"
+ s = u // ERROR "cannot use .* in assignment"
+ s = S(s)
+ s = S(t)
+ s = S(u) // ERROR "cannot convert"
+ t = u // ERROR "cannot use .* in assignment"
+ t = T(u) // ERROR "cannot convert"
+}
+
+// conversions between pointers to structs
+
+func _() {
+ type S struct{}
+ type T struct{}
+ var s *S
+ var t *T
+ var u *struct{}
+ s = s
+ s = t // ERROR "cannot use .* in assignment"
+ s = u // ERROR "cannot use .* in assignment"
+ s = (*S)(s)
+ s = (*S)(t)
+ s = (*S)(u)
+ t = u // ERROR "cannot use .* in assignment"
+ t = (*T)(u)
+}
+
+func _() {
+ type S struct{ x int }
+ type T struct {
+ x int "foo"
+ }
+ var s *S
+ var t *T
+ var u *struct {
+ x int "bar"
+ }
+ s = s
+ s = t // ERROR "cannot use .* in assignment"
+ s = u // ERROR "cannot use .* in assignment"
+ s = (*S)(s)
+ s = (*S)(t)
+ s = (*S)(u)
+ t = u // ERROR "cannot use .* in assignment"
+ t = (*T)(u)
+}
+
+func _() {
+ type E struct{ x int }
+ type S struct{ x E }
+ type T struct {
+ x E "foo"
+ }
+ var s *S
+ var t *T
+ var u *struct {
+ x E "bar"
+ }
+ s = s
+ s = t // ERROR "cannot use .* in assignment"
+ s = u // ERROR "cannot use .* in assignment"
+ s = (*S)(s)
+ s = (*S)(t)
+ s = (*S)(u)
+ t = u // ERROR "cannot use .* in assignment"
+ t = (*T)(u)
+}
+
+func _() {
+ type S struct {
+ x struct {
+ x int "foo"
+ }
+ }
+ type T struct {
+ x struct {
+ x int "bar"
+ } "foo"
+ }
+ var s *S
+ var t *T
+ var u *struct {
+ x struct {
+ x int "bar"
+ } "bar"
+ }
+ s = s
+ s = t // ERROR "cannot use .* in assignment"
+ s = u // ERROR "cannot use .* in assignment"
+ s = (*S)(s)
+ s = (*S)(t)
+ s = (*S)(u)
+ t = u // ERROR "cannot use .* in assignment"
+ t = (*T)(u)
+}
+
+func _() {
+ type E1 struct {
+ x int "foo"
+ }
+ type E2 struct {
+ x int "bar"
+ }
+ type S struct{ x E1 }
+ type T struct {
+ x E2 "foo"
+ }
+ var s *S
+ var t *T
+ var u *struct {
+ x E2 "bar"
+ }
+ s = s
+ s = t // ERROR "cannot use .* in assignment"
+ s = u // ERROR "cannot use .* in assignment"
+ s = (*S)(s)
+ s = (*S)(t) // ERROR "cannot convert"
+ s = (*S)(u) // ERROR "cannot convert"
+ t = u // ERROR "cannot use .* in assignment"
+ t = (*T)(u)
+}
+
+func _() {
+ type E struct{ x int }
+ type S struct {
+ f func(struct {
+ x int "foo"
+ })
+ }
+ type T struct {
+ f func(struct {
+ x int "bar"
+ })
+ }
+ var s *S
+ var t *T
+ var u *struct{ f func(E) }
+ s = s
+ s = t // ERROR "cannot use .* in assignment"
+ s = u // ERROR "cannot use .* in assignment"
+ s = (*S)(s)
+ s = (*S)(t)
+ s = (*S)(u) // ERROR "cannot convert"
+ t = u // ERROR "cannot use .* in assignment"
+ t = (*T)(u) // ERROR "cannot convert"
+}
+
+func _() {
+ type E struct{ x int }
+ type S struct {
+ f func(*struct {
+ x int "foo"
+ })
+ }
+ type T struct {
+ f func(*struct {
+ x int "bar"
+ })
+ }
+ var s *S
+ var t *T
+ var u *struct{ f func(E) }
+ s = s
+ s = t // ERROR "cannot use .* in assignment"
+ s = u // ERROR "cannot use .* in assignment"
+ s = (*S)(s)
+ s = (*S)(t)
+ s = (*S)(u) // ERROR "cannot convert"
+ t = u // ERROR "cannot use .* in assignment"
+ t = (*T)(u) // ERROR "cannot convert"
+}
diff --git a/test/ddd1.go b/test/ddd1.go
index 7ea04f3..cf6a3a5 100644
--- a/test/ddd1.go
+++ b/test/ddd1.go
@@ -27,9 +27,9 @@ func tuple() (int, int, int) { return 1, 2, 3 }
var (
_ = sum(tuple())
- _ = sum(tuple()...) // ERROR "multiple-value|[.][.][.]"
+ _ = sum(tuple()...) // ERROR "multiple-value"
_ = sum3(tuple())
- _ = sum3(tuple()...) // ERROR "multiple-value|[.][.][.]" "not enough"
+ _ = sum3(tuple()...) // ERROR "multiple-value" "not enough"
)
type T []T
@@ -59,4 +59,3 @@ func bad(args ...int) {
_ = [...]byte("foo") // ERROR "[.][.][.]"
_ = [...][...]int{{1,2,3},{4,5,6}} // ERROR "[.][.][.]"
}
-
diff --git a/test/escape_because.go b/test/escape_because.go
index f0bbd0b..7d349b7 100644
--- a/test/escape_because.go
+++ b/test/escape_because.go
@@ -30,22 +30,22 @@ func (p *pair) EqualParts() bool { // ERROR "\(\*pair\).EqualParts p does not es
return p != nil && (p.x == p.y || *p.x == *p.y)
}
-func f1(p *int) { // ERROR "from \[3\]\*int literal \(array literal element\) at escape_because.go:34$" "from a \(assigned\) at escape_because.go:34$" "from a \(interface-converted\) at escape_because.go:35$" "from sink \(assigned to top level variable\) at escape_because.go:19$" "leaking param: p$"
+func f1(p *int) { // ERROR "from \[3\]\*int literal \(array literal element\) at escape_because.go:34$" "from a \(assigned\) at escape_because.go:34$" "from a \(interface-converted\) at escape_because.go:35$" "from sink \(assigned to top level variable\) at escape_because.go:35$" "leaking param: p$"
a := [3]*int{p, nil, nil}
- sink = a // ERROR "a escapes to heap$" "from sink \(assigned to top level variable\) at escape_because.go:19$"
+ sink = a // ERROR "a escapes to heap$" "from sink \(assigned to top level variable\) at escape_because.go:35$"
}
-func f2(q *int) { // ERROR "from &u \(address-of\) at escape_because.go:43$" "from &u \(interface-converted\) at escape_because.go:43$" "from pair literal \(struct literal element\) at escape_because.go:41$" "from s \(assigned\) at escape_because.go:40$" "from sink \(assigned to top level variable\) at escape_because.go:19$" "from t \(assigned\) at escape_because.go:41$" "from u \(assigned\) at escape_because.go:42$" "leaking param: q$"
+func f2(q *int) { // ERROR "from &u \(address-of\) at escape_because.go:43$" "from &u \(interface-converted\) at escape_because.go:43$" "from pair literal \(struct literal element\) at escape_because.go:41$" "from s \(assigned\) at escape_because.go:40$" "from sink \(assigned to top level variable\) at escape_because.go:43$" "from t \(assigned\) at escape_because.go:41$" "from u \(assigned\) at escape_because.go:42$" "leaking param: q$"
s := q
t := pair{s, nil}
u := t // ERROR "moved to heap: u$"
- sink = &u // ERROR "&u escapes to heap$" "from &u \(interface-converted\) at escape_because.go:43$" "from sink \(assigned to top level variable\) at escape_because.go:19$"
+ sink = &u // ERROR "&u escapes to heap$" "from &u \(interface-converted\) at escape_because.go:43$" "from sink \(assigned to top level variable\) at escape_because.go:43$"
}
-func f3(r *int) interface{} { // ERROR "from \[\]\*int literal \(slice-literal-element\) at escape_because.go:47$" "from c \(assigned\) at escape_because.go:47$" "from c \(interface-converted\) at escape_because.go:48$" "from ~r1 \(return\) at escape_because.go:46$" "leaking param: r to result ~r1 level=-1$"
- c := []*int{r} // ERROR "\[\]\*int literal escapes to heap$" "from c \(assigned\) at escape_because.go:47$" "from c \(interface-converted\) at escape_because.go:48$" "from ~r1 \(return\) at escape_because.go:46$"
- return c // "return" // ERROR "c escapes to heap$" "from ~r1 \(return\) at escape_because.go:46$"
+func f3(r *int) interface{} { // ERROR "from \[\]\*int literal \(slice-literal-element\) at escape_because.go:47$" "from c \(assigned\) at escape_because.go:47$" "from c \(interface-converted\) at escape_because.go:48$" "from ~r1 \(return\) at escape_because.go:48$" "leaking param: r to result ~r1 level=-1$"
+ c := []*int{r} // ERROR "\[\]\*int literal escapes to heap$" "from c \(assigned\) at escape_because.go:47$" "from c \(interface-converted\) at escape_because.go:48$" "from ~r1 \(return\) at escape_because.go:48$"
+ return c // "return" // ERROR "c escapes to heap$" "from ~r1 \(return\) at escape_because.go:48$"
}
func f4(a *int, s []*int) int { // ERROR "from \*s \(indirection\) at escape_because.go:51$" "from append\(s, a\) \(appended to slice\) at escape_because.go:52$" "from append\(s, a\) \(appendee slice\) at escape_because.go:52$" "leaking param content: s$" "leaking param: a$"
@@ -73,15 +73,15 @@ func f7(x map[int]*int, y int) *int { // ERROR "f7 x does not escape$"
return z
}
-func f8(x int, y *int) *int { // ERROR "from ~r2 \(return\) at escape_because.go:76$" "from ~r2 \(returned from recursive function\) at escape_because.go:76$" "leaking param: y$" "moved to heap: x$"
+func f8(x int, y *int) *int { // ERROR "from ~r2 \(return\) at escape_because.go:78$" "from ~r2 \(returned from recursive function\) at escape_because.go:76$" "leaking param: y$" "moved to heap: x$"
if x <= 0 {
return y
}
x--
- return f8(*y, &x) // ERROR "&x escapes to heap$" "from y \(arg to recursive call\) at escape_because.go:76$" "from ~r2 \(return\) at escape_because.go:76$" "from ~r2 \(returned from recursive function\) at escape_because.go:76$"
+ return f8(*y, &x) // ERROR "&x escapes to heap$" "from y \(arg to recursive call\) at escape_because.go:81$" "from ~r2 \(return\) at escape_because.go:78$" "from ~r2 \(returned from recursive function\) at escape_because.go:76$"
}
-func f9(x int, y ...*int) *int { // ERROR "from y\[0\] \(dot of pointer\) at escape_because.go:86$" "from ~r2 \(return\) at escape_because.go:84$" "from ~r2 \(returned from recursive function\) at escape_because.go:84$" "leaking param content: y$" "leaking param: y to result ~r2 level=1$" "moved to heap: x$"
+func f9(x int, y ...*int) *int { // ERROR "from y\[0\] \(dot of pointer\) at escape_because.go:86$" "from ~r2 \(return\) at escape_because.go:86$" "from ~r2 \(returned from recursive function\) at escape_because.go:84$" "leaking param content: y$" "leaking param: y to result ~r2 level=1$" "moved to heap: x$"
if x <= 0 {
return y[0]
}
@@ -95,7 +95,27 @@ func f10(x map[*int]*int, y, z *int) *int { // ERROR "f10 x does not escape$" "f
}
func f11(x map[*int]*int, y, z *int) map[*int]*int { // ERROR "f11 x does not escape$" "from map\[\*int\]\*int literal \(map literal key\) at escape_because.go:98$" "from map\[\*int\]\*int literal \(map literal value\) at escape_because.go:98$" "leaking param: y$" "leaking param: z$"
- return map[*int]*int{y: z} // ERROR "from ~r3 \(return\) at escape_because.go:97$" "map\[\*int\]\*int literal escapes to heap$"
+ return map[*int]*int{y: z} // ERROR "from ~r3 \(return\) at escape_because.go:98$" "map\[\*int\]\*int literal escapes to heap$"
+}
+
+func f12() {
+ b := []byte("test") // ERROR "\(\[\]byte\)\(.test.\) escapes to heap$" "from b \(assigned\) at escape_because.go:102$" "from b \(passed to call\[argument escapes\]\) at escape_because.go:103$"
+ escape(b)
+}
+
+func escape(b []byte) { // ERROR "from panic\(b\) \(panic\) at escape_because.go:107$" "leaking param: b$"
+ panic(b)
+}
+
+func f13() {
+ b := []byte("test") // ERROR "\(\[\]byte\)\(.test.\) escapes to heap$" "from .out0 \(passed-to-and-returned-from-call\) at escape_because.go:112$" "from b \(assigned\) at escape_because.go:111$" "from c \(assigned\) at escape_because.go:112$" "from c \(passed to call\[argument escapes\]\) at escape_because.go:113$"
+ c := transmit(b)
+ escape(c)
+}
+
+//go:noinline
+func transmit(b []byte) []byte { // ERROR "from ~r1 \(return\) at escape_because.go:118$" "leaking param: b to result ~r1 level=0$"
+ return b
}
// The list below is all of the why-escapes messages seen building the escape analysis tests.
@@ -142,9 +162,9 @@ key of map put
map literal key
map literal value
parameter to indirect call
-passed to function[content escapes]
-passed to function[unknown]
-passed-to-and-returned-from-function
+passed to call[argument content escapes]
+passed to call[argument escapes]
+passed-to-and-returned-from-call
pointer literal
range
range-deref
diff --git a/test/escape_iface.go b/test/escape_iface.go
index 50a5132..8a11d7e 100644
--- a/test/escape_iface.go
+++ b/test/escape_iface.go
@@ -226,22 +226,36 @@ func dotTypeEscape() *T2 { // #11931
}
}
-func dotTypeEscape2() { // #13805
+func dotTypeEscape2() { // #13805, #15796
{
i := 0
+ j := 0
var v int
+ var ok bool
var x interface{} = i // ERROR "i does not escape"
+ var y interface{} = j // ERROR "j does not escape"
+
*(&v) = x.(int) // ERROR "&v does not escape"
+ *(&v), *(&ok) = y.(int) // ERROR "&v does not escape" "&ok does not escape"
}
{
i := 0
+ j := 0
+ var ok bool
var x interface{} = i // ERROR "i does not escape"
- sink = x.(int) // ERROR "x.\(int\) escapes to heap"
+ var y interface{} = j // ERROR "j does not escape"
+ sink = x.(int) // ERROR "x.\(int\) escapes to heap"
+ sink, *(&ok) = y.(int) // ERROR "&ok does not escape"
}
{
i := 0 // ERROR "moved to heap: i"
+ j := 0 // ERROR "moved to heap: j"
+ var ok bool
var x interface{} = &i // ERROR "&i escapes to heap"
+ var y interface{} = &j // ERROR "&j escapes to heap"
+
sink = x.(*int) // ERROR "x.\(\*int\) escapes to heap"
+ sink, *(&ok) = y.(*int) // ERROR "&ok does not escape"
}
}
diff --git a/test/fixedbugs/bug255.go b/test/fixedbugs/bug255.go
index cc7d92f..247ca32 100644
--- a/test/fixedbugs/bug255.go
+++ b/test/fixedbugs/bug255.go
@@ -10,7 +10,7 @@ var a [10]int // ok
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 "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 g [1 << 65]int // ERROR "array bound is too large|overflows"
var h [len(a)]int // ok
diff --git a/test/fixedbugs/bug332.go b/test/fixedbugs/bug332.go
index 91ae0b2..d43c2dd 100644
--- a/test/fixedbugs/bug332.go
+++ b/test/fixedbugs/bug332.go
@@ -13,5 +13,5 @@ func main() {}
// issue 1474
// important: no newline on end of next line.
-// 6g used to print <epoch> instead of bug332.go:111
-func (t *T) F() {} // ERROR "bug332"
\ No newline at end of file
+// 6g used to print <epoch> instead of bug332.go:111
+func (t *T) F() {} // ERROR "undefined: T"
\ No newline at end of file
diff --git a/test/fixedbugs/bug376.go b/test/fixedbugs/bug376.go
index 7bef58b..cd70012 100644
--- a/test/fixedbugs/bug376.go
+++ b/test/fixedbugs/bug376.go
@@ -7,5 +7,4 @@
// issue 1951
package foo
import "unsafe"
-var v = unsafe.Sizeof // ERROR "must be called"
-
+var v = unsafe.Sizeof // ERROR "not in function call|must be called"
diff --git a/test/fixedbugs/bug498.go b/test/fixedbugs/bug498.go
new file mode 100644
index 0000000..91b5c2f
--- /dev/null
+++ b/test/fixedbugs/bug498.go
@@ -0,0 +1,23 @@
+// run
+
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Gccgo incorrectly rejected an assignment to multiple instances of
+// the same variable.
+
+package main
+
+var a int
+
+func F() {
+ a, a, a = 1, 2, 3
+}
+
+func main() {
+ F()
+ if a != 3 {
+ panic(a)
+ }
+}
diff --git a/test/fixedbugs/bug499.go b/test/fixedbugs/bug499.go
new file mode 100644
index 0000000..e4142e9
--- /dev/null
+++ b/test/fixedbugs/bug499.go
@@ -0,0 +1,15 @@
+// run
+
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Gccgo got confused when a type was used both for a map bucket type
+// and for a map key type.
+
+package main
+
+func main() {
+ _ = make(map[byte]byte)
+ _ = make(map[[8]byte]chan struct{})
+}
diff --git a/test/fixedbugs/issue10607.go b/test/fixedbugs/issue10607.go
index bf527d0..52fb51a 100644
--- a/test/fixedbugs/issue10607.go
+++ b/test/fixedbugs/issue10607.go
@@ -1,4 +1,4 @@
-// +build linux,!ppc64,!ppc64le
+// +build linux,!mips,!mipsle,!ppc64
// run
// Copyright 2015 The Go Authors. All rights reserved.
diff --git a/test/fixedbugs/issue11370.go b/test/fixedbugs/issue11370.go
new file mode 100644
index 0000000..30f2904
--- /dev/null
+++ b/test/fixedbugs/issue11370.go
@@ -0,0 +1,13 @@
+// compile
+
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// issue 11370: cmd/compile: "0"[0] should not be a constant
+
+package p
+
+func main() {
+ println(-"abc"[1] >> 1)
+}
diff --git a/test/fixedbugs/issue11610.go b/test/fixedbugs/issue11610.go
index f32d480..5e77932 100644
--- a/test/fixedbugs/issue11610.go
+++ b/test/fixedbugs/issue11610.go
@@ -11,7 +11,7 @@ package a
import"" // ERROR "import path is empty"
var? // ERROR "illegal character U\+003F '\?'"
-var x int // ERROR "unexpected var" "cannot declare name"
+var x int // ERROR "unexpected var"
func main() {
}
diff --git a/test/fixedbugs/issue13162.go b/test/fixedbugs/issue13162.go
new file mode 100644
index 0000000..f8b3150
--- /dev/null
+++ b/test/fixedbugs/issue13162.go
@@ -0,0 +1,82 @@
+// run
+
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Ensure that range loops over a string have the requisite side-effects.
+
+package main
+
+import (
+ "fmt"
+ "os"
+)
+
+func check(n int) {
+ var i int
+ var r rune
+
+ b := make([]byte, n)
+ for i = range b {
+ b[i] = byte(i + 1)
+ }
+ s := string(b)
+
+ // When n == 0, i is untouched by the range loop.
+ // Picking an initial value of -1 for i makes the
+ // "want" calculation below correct in all cases.
+ i = -1
+ for i = range s {
+ b[i] = s[i]
+ }
+ if want := n - 1; i != want {
+ fmt.Printf("index after range with side-effect = %d want %d\n", i, want)
+ os.Exit(1)
+ }
+
+ i = -1
+ r = '\x00'
+ for i, r = range s {
+ b[i] = byte(r)
+ }
+ if want := n - 1; i != want {
+ fmt.Printf("index after range with side-effect = %d want %d\n", i, want)
+ os.Exit(1)
+ }
+ if want := rune(n); r != want {
+ fmt.Printf("rune after range with side-effect = %q want %q\n", r, want)
+ os.Exit(1)
+ }
+
+ i = -1
+ // i is shadowed here, so its value should be unchanged.
+ for i := range s {
+ b[i] = s[i]
+ }
+ if want := -1; i != want {
+ fmt.Printf("index after range without side-effect = %d want %d\n", i, want)
+ os.Exit(1)
+ }
+
+ i = -1
+ r = -1
+ // i and r are shadowed here, so their values should be unchanged.
+ for i, r := range s {
+ b[i] = byte(r)
+ }
+ if want := -1; i != want {
+ fmt.Printf("index after range without side-effect = %d want %d\n", i, want)
+ os.Exit(1)
+ }
+ if want := rune(-1); r != want {
+ fmt.Printf("rune after range without side-effect = %q want %q\n", r, want)
+ os.Exit(1)
+ }
+}
+
+func main() {
+ check(0)
+ check(1)
+ check(15)
+}
diff --git a/test/fixedbugs/issue13171.go b/test/fixedbugs/issue13171.go
index 5d127a5..addb872 100644
--- a/test/fixedbugs/issue13171.go
+++ b/test/fixedbugs/issue13171.go
@@ -14,7 +14,7 @@ import "fmt"
func f(x float64) float64 {
// y is allocated to X0
y := x + 5
- // marshals z before y. Marshalling z
+ // marshals z before y. Marshaling z
// calls DUFFCOPY.
return g(z, y)
}
diff --git a/test/fixedbugs/issue13262.go b/test/fixedbugs/issue13262.go
new file mode 100644
index 0000000..8837c00
--- /dev/null
+++ b/test/fixedbugs/issue13262.go
@@ -0,0 +1,21 @@
+// compile
+
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Issue 13262: cmd/compile: bogus "fallthrough
+// statement out of place" error
+
+package p
+
+func f() int {
+ var a int
+ switch a {
+ case 0:
+ return func() int { return 1 }()
+ fallthrough
+ default:
+ }
+ return 0
+}
diff --git a/test/fixedbugs/issue13485.go b/test/fixedbugs/issue13485.go
new file mode 100644
index 0000000..a9beea1
--- /dev/null
+++ b/test/fixedbugs/issue13485.go
@@ -0,0 +1,18 @@
+// 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 p
+
+var (
+ _ [10]int
+ _ [10.0]int
+ _ [float64(10)]int // ERROR "invalid array bound"
+ _ [10 + 0i]int
+ _ [complex(10, 0)]int
+ _ [complex128(complex(10, 0))]int // ERROR "invalid array bound"
+ _ ['a']int
+ _ [rune(65)]int
+)
diff --git a/test/fixedbugs/issue14136.go b/test/fixedbugs/issue14136.go
index 928a60b..f9efd05 100644
--- a/test/fixedbugs/issue14136.go
+++ b/test/fixedbugs/issue14136.go
@@ -14,6 +14,6 @@ package main
type T struct{}
func main() {
- t := T{X: 1, X: 1, X: 1, X: 1, X: 1, X: 1, X: 1, X: 1, X: 1, X: 1} // ERROR "unknown T field"
+ t := T{X: 1, X: 1, X: 1, X: 1, X: 1, X: 1, X: 1, X: 1, X: 1, X: 1} // ERROR "unknown field 'X' in struct literal of type T"
var s string = 1 // ERROR "cannot use 1"
}
diff --git a/test/fixedbugs/issue15141.go b/test/fixedbugs/issue15141.go
new file mode 100644
index 0000000..752f530
--- /dev/null
+++ b/test/fixedbugs/issue15141.go
@@ -0,0 +1,33 @@
+// compile
+
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func main() {
+ a := f(1, 99)
+ b := g(0xFFFFFFe, 98)
+ c := h(0xFFFFFFe, 98)
+ println(a[1], b[1], c[1], a[0xFFFFFFe], b[0xFFFFFFe], c[0xFFFFFFe])
+}
+
+//go:noinline
+func f(i, y int) (a [0xFFFFFFF]byte) {
+ a[i] = byte(y)
+ return
+}
+
+//go:noinline
+func g(i, y int) [0xFFFFFFF]byte {
+ var a [0xFFFFFFF]byte
+ a[i] = byte(y)
+ return a
+}
+
+//go:noinline
+func h(i, y int) (a [0xFFFFFFF]byte) {
+ a[i] = byte(y)
+ return a
+}
diff --git a/test/fixedbugs/issue15277.go b/test/fixedbugs/issue15277.go
index 719c9a4..af165f7 100644
--- a/test/fixedbugs/issue15277.go
+++ b/test/fixedbugs/issue15277.go
@@ -15,6 +15,7 @@ func f(x *big, start int64) {
if delta := inuse() - start; delta < 9<<20 {
println("after alloc: expected delta at least 9MB, got: ", delta)
}
+ runtime.KeepAlive(x)
x = nil
if delta := inuse() - start; delta > 1<<20 {
println("after drop: expected delta below 1MB, got: ", delta)
@@ -23,6 +24,7 @@ func f(x *big, start int64) {
if delta := inuse() - start; delta < 9<<20 {
println("second alloc: expected delta at least 9MB, got: ", delta)
}
+ runtime.KeepAlive(x)
}
func main() {
diff --git a/test/fixedbugs/issue15303.go b/test/fixedbugs/issue15303.go
new file mode 100644
index 0000000..c8dfa30
--- /dev/null
+++ b/test/fixedbugs/issue15303.go
@@ -0,0 +1,24 @@
+// run
+
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Ensure that inlined struct/array comparisons have the right side-effects.
+
+package main
+
+import "os"
+
+func main() {
+ var x int
+ f := func() (r [4]int) {
+ x++
+ return
+ }
+ _ = f() == f()
+ if x != 2 {
+ println("f evaluated ", x, " times, want 2")
+ os.Exit(1)
+ }
+}
diff --git a/test/fixedbugs/issue15514.dir/a.go b/test/fixedbugs/issue15514.dir/a.go
new file mode 100644
index 0000000..663303b
--- /dev/null
+++ b/test/fixedbugs/issue15514.dir/a.go
@@ -0,0 +1,7 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package a
+
+type A struct{ _ int32 }
diff --git a/test/fixedbugs/issue15514.dir/b.go b/test/fixedbugs/issue15514.dir/b.go
new file mode 100644
index 0000000..f0750d3
--- /dev/null
+++ b/test/fixedbugs/issue15514.dir/b.go
@@ -0,0 +1,7 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package b
+
+func B() (_ struct{ _ int32 }) { return }
diff --git a/test/fixedbugs/issue15514.dir/c.go b/test/fixedbugs/issue15514.dir/c.go
new file mode 100644
index 0000000..11624f9
--- /dev/null
+++ b/test/fixedbugs/issue15514.dir/c.go
@@ -0,0 +1,10 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package c
+
+import "./a"
+import "./b"
+
+var _ a.A = b.B() // ERROR "cannot use b\.B"
diff --git a/test/fixedbugs/issue15514.go b/test/fixedbugs/issue15514.go
new file mode 100644
index 0000000..626f7ad
--- /dev/null
+++ b/test/fixedbugs/issue15514.go
@@ -0,0 +1,7 @@
+// errorcheckdir
+
+// Copyright 2016 The Go Authors. 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/issue15528.go b/test/fixedbugs/issue15528.go
new file mode 100644
index 0000000..b1f9dfb
--- /dev/null
+++ b/test/fixedbugs/issue15528.go
@@ -0,0 +1,131 @@
+// run
+
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "fmt"
+ "io"
+ "os"
+ "reflect"
+ "unsafe"
+)
+
+type RWS struct{}
+
+func (x *RWS) Read(p []byte) (n int, err error) { return }
+func (x *RWS) Write(p []byte) (n int, err error) { return }
+func (x *RWS) Seek(offset int64, whence int) (n int64, err error) { return }
+func (x *RWS) String() string { return "rws" }
+
+func makeRWS() io.ReadWriteSeeker { return &RWS{} }
+func makeStringer() fmt.Stringer { return &RWS{} }
+
+// Test correct construction of static empty interface values
+var efaces = [...]struct {
+ x interface{}
+ s string
+}{
+ {nil, "<nil> <nil>"},
+ {1, "int 1"},
+ {int(1), "int 1"},
+ {Int(int(2)), "main.Int Int=2"},
+ {int(Int(3)), "int 3"},
+ {[1]int{2}, "[1]int [2]"},
+ {io.Reader(io.ReadWriter(io.ReadWriteSeeker(nil))), "<nil> <nil>"},
+ {io.Reader(io.ReadWriter(io.ReadWriteSeeker(&RWS{}))), "*main.RWS rws"},
+ {makeRWS(), "*main.RWS rws"},
+ {map[string]string{"here": "there"}, "map[string]string map[here:there]"},
+ {chan bool(nil), "chan bool <nil>"},
+ {unsafe.Pointer(uintptr(0)), "unsafe.Pointer <nil>"},
+ {(*byte)(nil), "*uint8 <nil>"},
+ {io.Writer((*os.File)(nil)), "*os.File <nil>"},
+ {(interface{})(io.Writer((*os.File)(nil))), "*os.File <nil>"},
+ {fmt.Stringer(Strunger(((*Int)(nil)))), "*main.Int <nil>"},
+}
+
+type Int int
+
+func (i Int) String() string { return fmt.Sprintf("Int=%d", i) }
+func (i Int) Strung() {}
+
+type Strunger interface {
+ fmt.Stringer
+ Strung()
+}
+
+// Test correct construction of static non-empty interface values
+var ifaces = [...]struct {
+ x fmt.Stringer
+ s string
+}{
+ {nil, "<nil> <nil> %!s(<nil>)"},
+ {Int(3), "main.Int 3 Int=3"},
+ {Int(int(Int(4))), "main.Int 4 Int=4"},
+ {Strunger(Int(5)), "main.Int 5 Int=5"},
+ {makeStringer(), "*main.RWS &main.RWS{} rws"},
+ {fmt.Stringer(nil), "<nil> <nil> %!s(<nil>)"},
+ {(*RWS)(nil), "*main.RWS (*main.RWS)(nil) rws"},
+}
+
+// Test correct handling of direct interface values
+var (
+ one int = 1
+ iptr interface{} = &one
+ clos int
+ f interface{} = func() { clos++ }
+ deep interface{} = [1]struct{ a *[2]byte }{{a: &[2]byte{'z', 'w'}}}
+ ch interface{} = make(chan bool, 1)
+)
+
+func main() {
+ var fail bool
+ for i, test := range efaces {
+ s := fmt.Sprintf("%[1]T %[1]v", test.x)
+ if s != test.s {
+ fmt.Printf("eface(%d)=%q want %q\n", i, s, test.s)
+ fail = true
+ }
+ }
+
+ for i, test := range ifaces {
+ s := fmt.Sprintf("%[1]T %#[1]v %[1]s", test.x)
+ if s != test.s {
+ fmt.Printf("iface(%d)=%q want %q\n", i, s, test.s)
+ fail = true
+ }
+ }
+
+ if got := *(iptr.(*int)); got != 1 {
+ fmt.Printf("bad int ptr %d\n", got)
+ fail = true
+ }
+
+ f.(func())()
+ f.(func())()
+ f.(func())()
+ if clos != 3 {
+ fmt.Printf("bad closure exec %d\n", clos)
+ fail = true
+ }
+
+ if !reflect.DeepEqual(*(deep.([1]struct{ a *[2]byte })[0].a), [2]byte{'z', 'w'}) {
+ fmt.Printf("bad deep directiface\n")
+ fail = true
+ }
+
+ cc := ch.(chan bool)
+ cc <- true
+ if got := <-cc; !got {
+ fmt.Printf("bad chan\n")
+ fail = true
+ }
+
+ if fail {
+ fmt.Println("BUG")
+ os.Exit(1)
+ }
+}
diff --git a/test/fixedbugs/issue15609.dir/call.go b/test/fixedbugs/issue15609.dir/call.go
new file mode 100644
index 0000000..41a489c
--- /dev/null
+++ b/test/fixedbugs/issue15609.dir/call.go
@@ -0,0 +1,7 @@
+// +build !amd64,!386
+
+package main
+
+func jump() {
+ target()
+}
diff --git a/test/fixedbugs/issue15609.dir/call_386.s b/test/fixedbugs/issue15609.dir/call_386.s
new file mode 100644
index 0000000..751084c
--- /dev/null
+++ b/test/fixedbugs/issue15609.dir/call_386.s
@@ -0,0 +1,8 @@
+#include "textflag.h"
+
+DATA ·pointer(SB)/4, $·target(SB)
+GLOBL ·pointer(SB),RODATA,$4
+
+TEXT ·jump(SB),NOSPLIT,$4
+ CALL *·pointer(SB)
+ RET
diff --git a/test/fixedbugs/issue15609.dir/call_amd64.s b/test/fixedbugs/issue15609.dir/call_amd64.s
new file mode 100644
index 0000000..09fbe5d
--- /dev/null
+++ b/test/fixedbugs/issue15609.dir/call_amd64.s
@@ -0,0 +1,8 @@
+#include "textflag.h"
+
+DATA ·pointer(SB)/8, $·target(SB)
+GLOBL ·pointer(SB),RODATA,$8
+
+TEXT ·jump(SB),NOSPLIT,$8
+ CALL *·pointer(SB)
+ RET
diff --git a/test/fixedbugs/issue15609.dir/call_decl.go b/test/fixedbugs/issue15609.dir/call_decl.go
new file mode 100644
index 0000000..d9c5a4e
--- /dev/null
+++ b/test/fixedbugs/issue15609.dir/call_decl.go
@@ -0,0 +1,5 @@
+// +build amd64 386
+
+package main
+
+func jump()
diff --git a/test/fixedbugs/issue15609.dir/main.go b/test/fixedbugs/issue15609.dir/main.go
new file mode 100644
index 0000000..4855e31
--- /dev/null
+++ b/test/fixedbugs/issue15609.dir/main.go
@@ -0,0 +1,14 @@
+package main
+
+var called bool
+
+func target() {
+ called = true
+}
+
+func main() {
+ jump()
+ if !called {
+ panic("target not called")
+ }
+}
diff --git a/test/fixedbugs/issue15722.go b/test/fixedbugs/issue15722.go
new file mode 100644
index 0000000..dec5458
--- /dev/null
+++ b/test/fixedbugs/issue15722.go
@@ -0,0 +1,21 @@
+// 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.
+
+// Checks to make sure that the compiler can catch a specific invalid
+// method type expression. NB: gccgo and gc have slightly different
+// error messages, hence the generic test for 'method' and not something
+// more specific.
+
+package issue15722
+
+type T int
+type P *T
+
+func (T) t() {}
+
+func _(p P) {
+ P.t(p) // ERROR "method"
+}
diff --git a/test/fixedbugs/issue15747.go b/test/fixedbugs/issue15747.go
index 34ec719..836d0ea 100644
--- a/test/fixedbugs/issue15747.go
+++ b/test/fixedbugs/issue15747.go
@@ -17,23 +17,24 @@ type T struct{ M string }
var b bool
-func f1(q *Q, xx []byte) interface{} { // ERROR "live at entry to f1: q xx" "live at call to newobject: q xx" "live at call to writebarrierptr: q &xx"
+func f1(q *Q, xx []byte) interface{} { // ERROR "live at call to newobject: xx$" "live at call to writebarrierptr: &xx$" "live at entry to f1: xx$"
// xx was copied from the stack to the heap on the previous line:
// xx was live for the first two prints but then it switched to &xx
// being live. We should not see plain xx again.
if b {
- global = &xx // ERROR "live at call to writebarrierptr: q &xx$"
+ global = &xx // ERROR "live at call to writebarrierptr: &xx$"
}
- xx, _, err := f2(xx, 5) // ERROR "live at call to newobject: q( d)? &xx( odata.ptr)?" "live at call to writebarrierptr: q (e|err.data err.type)$"
+ xx, _, err := f2(xx, 5) // ERROR "live at call to f2: &xx$" "live at call to writebarrierptr: err.data err.type$"
if err != nil {
return err
}
return nil
}
-func f2(d []byte, n int) (odata, res []byte, e interface{}) { // ERROR "live at entry to f2: d"
+//go:noinline
+func f2(d []byte, n int) (odata, res []byte, e interface{}) { // ERROR "live at entry to f2: d$"
if n > len(d) {
- return d, nil, &T{M: "hello"} // ERROR "live at call to newobject: d"
+ return d, nil, &T{M: "hello"} // ERROR "live at call to newobject: d" "live at call to writebarrierptr: d"
}
res = d[:n]
odata = d[n:]
diff --git a/test/fixedbugs/issue15895.go b/test/fixedbugs/issue15895.go
new file mode 100644
index 0000000..3ef295c
--- /dev/null
+++ b/test/fixedbugs/issue15895.go
@@ -0,0 +1,27 @@
+// compile
+
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// func bad used to fail to compile.
+
+package p
+
+type A [1]int
+
+func bad(x A) {
+ switch x {
+ case A([1]int{1}):
+ case A([1]int{1}):
+ }
+}
+
+func good(x A) {
+ y := A([1]int{1})
+ z := A([1]int{1})
+ switch x {
+ case y:
+ case z:
+ }
+}
diff --git a/test/fixedbugs/issue16306.go b/test/fixedbugs/issue16306.go
new file mode 100644
index 0000000..d29a75a
--- /dev/null
+++ b/test/fixedbugs/issue16306.go
@@ -0,0 +1,15 @@
+// compile
+
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "unsafe"
+
+var x = unsafe.Pointer(uintptr(0))
+
+func main() {
+ _ = map[unsafe.Pointer]int{unsafe.Pointer(uintptr(0)): 0}
+}
diff --git a/test/fixedbugs/issue16317.dir/a.go b/test/fixedbugs/issue16317.dir/a.go
new file mode 100644
index 0000000..3a1b7e0
--- /dev/null
+++ b/test/fixedbugs/issue16317.dir/a.go
@@ -0,0 +1,11 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package a
+
+import "unsafe"
+
+func ConstUnsafePointer() unsafe.Pointer {
+ return unsafe.Pointer(uintptr(0))
+}
diff --git a/test/fixedbugs/issue16317.dir/b.go b/test/fixedbugs/issue16317.dir/b.go
new file mode 100644
index 0000000..b813918
--- /dev/null
+++ b/test/fixedbugs/issue16317.dir/b.go
@@ -0,0 +1,11 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "./a"
+
+func main() {
+ _ = a.ConstUnsafePointer()
+}
diff --git a/test/fixedbugs/issue16317.go b/test/fixedbugs/issue16317.go
new file mode 100644
index 0000000..b3376bb
--- /dev/null
+++ b/test/fixedbugs/issue16317.go
@@ -0,0 +1,10 @@
+// compiledir
+
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Issue 16317: cmd/compile: internal compiler error:
+// unhandled OCONV INT -> TUNSAFEPTR
+
+package ignored
diff --git a/test/fixedbugs/issue16331.go b/test/fixedbugs/issue16331.go
new file mode 100644
index 0000000..665e7fc
--- /dev/null
+++ b/test/fixedbugs/issue16331.go
@@ -0,0 +1,48 @@
+// run
+
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Perform tracebackdefers with a deferred reflection method.
+
+package main
+
+import "reflect"
+
+type T struct{}
+
+func (T) M() {
+}
+
+func F(args []reflect.Value) (results []reflect.Value) {
+ return nil
+}
+
+func main() {
+ done := make(chan bool)
+ go func() {
+ // Test reflect.makeFuncStub.
+ t := reflect.TypeOf((func())(nil))
+ f := reflect.MakeFunc(t, F).Interface().(func())
+ defer f()
+ growstack(10000)
+ done <- true
+ }()
+ <-done
+ go func() {
+ // Test reflect.methodValueCall.
+ f := reflect.ValueOf(T{}).Method(0).Interface().(func())
+ defer f()
+ growstack(10000)
+ done <- true
+ }()
+ <-done
+}
+
+func growstack(x int) {
+ if x == 0 {
+ return
+ }
+ growstack(x - 1)
+}
diff --git a/test/fixedbugs/issue16369.go b/test/fixedbugs/issue16369.go
new file mode 100644
index 0000000..bd03fbc
--- /dev/null
+++ b/test/fixedbugs/issue16369.go
@@ -0,0 +1,13 @@
+// errorcheck
+
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package p
+
+type T interface {
+ M(interface {
+ T
+ }) // ERROR "cannot export unnamed recursive interface"
+}
diff --git a/test/fixedbugs/issue16428.go b/test/fixedbugs/issue16428.go
new file mode 100644
index 0000000..5696d18
--- /dev/null
+++ b/test/fixedbugs/issue16428.go
@@ -0,0 +1,12 @@
+// errorcheck
+
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package p
+
+var (
+ b = [...]byte("abc") // ERROR "outside of array literal"
+ s = len(b)
+)
diff --git a/test/fixedbugs/issue16439.go b/test/fixedbugs/issue16439.go
new file mode 100644
index 0000000..d321b60
--- /dev/null
+++ b/test/fixedbugs/issue16439.go
@@ -0,0 +1,18 @@
+// errorcheck
+
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package p
+
+var a []int = []int{1: 1}
+var b []int = []int{-1: 1} // ERROR "must be non-negative integer constant"
+
+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 g []int = []int{"a": 4} // ERROR "must be non-negative integer constant"
diff --git a/test/fixedbugs/issue16616.dir/a.go b/test/fixedbugs/issue16616.dir/a.go
new file mode 100644
index 0000000..0ffdbbe
--- /dev/null
+++ b/test/fixedbugs/issue16616.dir/a.go
@@ -0,0 +1,7 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package a
+
+type V struct{ i int }
diff --git a/test/fixedbugs/issue16616.dir/b.go b/test/fixedbugs/issue16616.dir/b.go
new file mode 100644
index 0000000..4f238b9
--- /dev/null
+++ b/test/fixedbugs/issue16616.dir/b.go
@@ -0,0 +1,14 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package b
+
+import "./a"
+
+var V struct{ i int }
+
+var U struct {
+ a.V
+ j int
+}
diff --git a/test/fixedbugs/issue16616.dir/issue16616.go b/test/fixedbugs/issue16616.dir/issue16616.go
new file mode 100644
index 0000000..0bfadb8
--- /dev/null
+++ b/test/fixedbugs/issue16616.dir/issue16616.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 main
+
+import (
+ "reflect"
+
+ _ "./a"
+ "./b"
+)
+
+var V struct{ i int }
+
+func main() {
+ if got := reflect.ValueOf(b.V).Type().Field(0).PkgPath; got != "b" {
+ panic(`PkgPath=` + got + ` for first field of b.V, want "b"`)
+ }
+ if got := reflect.ValueOf(V).Type().Field(0).PkgPath; got != "main" {
+ panic(`PkgPath=` + got + ` for first field of V, want "main"`)
+ }
+ if got := reflect.ValueOf(b.U).Type().Field(0).PkgPath; got != "b" {
+ panic(`PkgPath=` + got + ` for first field of b.U, want "b"`)
+ }
+}
diff --git a/test/fixedbugs/issue16616.go b/test/fixedbugs/issue16616.go
new file mode 100644
index 0000000..a7d6ac0
--- /dev/null
+++ b/test/fixedbugs/issue16616.go
@@ -0,0 +1,9 @@
+// compiledir
+
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Tests that unexported fields of unnamed types have different PkgPath values.
+
+package ignored
diff --git a/test/fixedbugs/issue16733.go b/test/fixedbugs/issue16733.go
new file mode 100644
index 0000000..850b042
--- /dev/null
+++ b/test/fixedbugs/issue16733.go
@@ -0,0 +1,16 @@
+// compile
+
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Issue 16733: don't fold constant factors into a multiply
+// beyond the capacity of a MULQ instruction (32 bits).
+
+package p
+
+func f(n int64) int64 {
+ n *= 1000000
+ n *= 1000000
+ return n
+}
diff --git a/test/fixedbugs/issue16741.go b/test/fixedbugs/issue16741.go
new file mode 100644
index 0000000..9946062
--- /dev/null
+++ b/test/fixedbugs/issue16741.go
@@ -0,0 +1,17 @@
+// compile
+
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Make sure CSE of multi-output opcodes works correctly
+// with select0/1 operations.
+
+package main
+
+func div(d, r int64) int64 {
+ if m := d % r; m > 0 {
+ return d/r + 1
+ }
+ return d / r
+}
diff --git a/test/fixedbugs/issue16760.go b/test/fixedbugs/issue16760.go
new file mode 100644
index 0000000..d0e08b5
--- /dev/null
+++ b/test/fixedbugs/issue16760.go
@@ -0,0 +1,42 @@
+// run
+
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Make sure we don't start marshaling (writing to the stack)
+// arguments until those arguments are evaluated and known
+// not to unconditinally panic. If they unconditionally panic,
+// we write some args but never do the call. That messes up
+// the logic which decides how big the argout section needs to be.
+
+package main
+
+type W interface {
+ Write([]byte)
+}
+
+type F func(W)
+
+func foo(f F) {
+ defer func() {
+ if r := recover(); r != nil {
+ usestack(1000)
+ }
+ }()
+ f(nil)
+}
+
+func main() {
+ foo(func(w W) {
+ var x []string
+ w.Write([]byte(x[5]))
+ })
+}
+
+func usestack(n int) {
+ if n == 0 {
+ return
+ }
+ usestack(n - 1)
+}
diff --git a/test/fixedbugs/issue16804.go b/test/fixedbugs/issue16804.go
new file mode 100644
index 0000000..46dd4a3
--- /dev/null
+++ b/test/fixedbugs/issue16804.go
@@ -0,0 +1,16 @@
+// compile
+
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Issue 16804: internal error for math.Sqrt as statement
+// rather than expression
+
+package main
+
+import "math"
+
+func sqrt() {
+ math.Sqrt(2.0)
+}
diff --git a/test/fixedbugs/issue16870.go b/test/fixedbugs/issue16870.go
new file mode 100644
index 0000000..2309997
--- /dev/null
+++ b/test/fixedbugs/issue16870.go
@@ -0,0 +1,140 @@
+// run
+
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "log"
+ "reflect"
+)
+
+func test(got, want interface{}) {
+ if !reflect.DeepEqual(got, want) {
+ log.Fatalf("got %v, want %v", got, want)
+ }
+}
+
+func main() {
+ var i int
+ var ip *int
+ var ok interface{}
+
+ // Channel receives.
+ c := make(chan int, 1)
+ c2 := make(chan int)
+
+ c <- 42
+ i, ok = <-c
+ test(i, 42)
+ test(ok, true)
+
+ c <- 42
+ _, ok = <-c
+ test(ok, true)
+
+ c <- 42
+ select {
+ case i, ok = <-c:
+ test(i, 42)
+ test(ok, true)
+ }
+
+ c <- 42
+ select {
+ case _, ok = <-c:
+ test(ok, true)
+ }
+
+ c <- 42
+ select {
+ case i, ok = <-c:
+ test(i, 42)
+ test(ok, true)
+ default:
+ log.Fatal("bad select")
+ }
+
+ c <- 42
+ select {
+ case _, ok = <-c:
+ test(ok, true)
+ default:
+ log.Fatal("bad select")
+ }
+
+ c <- 42
+ select {
+ case i, ok = <-c:
+ test(i, 42)
+ test(ok, true)
+ case <-c2:
+ log.Fatal("bad select")
+ }
+
+ c <- 42
+ select {
+ case _, ok = <-c:
+ test(ok, true)
+ case <-c2:
+ log.Fatal("bad select")
+ }
+
+ close(c)
+ i, ok = <-c
+ test(i, 0)
+ test(ok, false)
+
+ _, ok = <-c
+ test(ok, false)
+
+ // Map indexing.
+ m := make(map[int]int)
+
+ i, ok = m[0]
+ test(i, 0)
+ test(ok, false)
+
+ _, ok = m[0]
+ test(ok, false)
+
+ m[0] = 42
+ i, ok = m[0]
+ test(i, 42)
+ test(ok, true)
+
+ _, ok = m[0]
+ test(ok, true)
+
+ // Type assertions.
+ var u interface{}
+
+ i, ok = u.(int)
+ test(i, 0)
+ test(ok, false)
+
+ ip, ok = u.(*int)
+ test(ip, (*int)(nil))
+ test(ok, false)
+
+ _, ok = u.(int)
+ test(ok, false)
+
+ u = 42
+ i, ok = u.(int)
+ test(i, 42)
+ test(ok, true)
+
+ _, ok = u.(int)
+ test(ok, true)
+
+ u = &i
+ ip, ok = u.(*int)
+ test(ip, &i)
+ test(ok, true)
+
+ _, ok = u.(*int)
+ test(ok, true)
+}
diff --git a/test/fixedbugs/issue16948.go b/test/fixedbugs/issue16948.go
new file mode 100644
index 0000000..c986024
--- /dev/null
+++ b/test/fixedbugs/issue16948.go
@@ -0,0 +1,34 @@
+// run
+
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// issue 16948: make sure intrinsified atomic ops won't
+// confuse the scheduler.
+
+package main
+
+import "sync/atomic"
+
+func main() {
+ f()
+}
+
+var x int32
+
+type T [10]int
+var sink *T
+
+func f() (t T) {
+ atomic.AddInt32(&x, 1)
+ g(42, 42, 42, 42, 42, &t) // use int values that is invalid pointer to smash the stack slot of return value of runtime.newobject
+ return
+}
+
+//go:noinline
+func g(a, b, c, d, e int, p *T) {
+ var t [10000]int // a large stack frame to trigger stack growing
+ _ = t
+ sink = p // force p (in caller) heap allocated
+}
diff --git a/test/fixedbugs/issue16949.go b/test/fixedbugs/issue16949.go
new file mode 100644
index 0000000..9ee3387
--- /dev/null
+++ b/test/fixedbugs/issue16949.go
@@ -0,0 +1,30 @@
+// 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.
+
+// Ensure that typed non-integer len and cap make arguments are not accepted.
+
+package main
+
+var sink []byte
+
+func main() {
+ sink = make([]byte, 1.0)
+ sink = make([]byte, float32(1.0)) // ERROR "non-integer.*len"
+ sink = make([]byte, float64(1.0)) // ERROR "non-integer.*len"
+
+ sink = make([]byte, 0, 1.0)
+ sink = make([]byte, 0, float32(1.0)) // ERROR "non-integer.*cap"
+ sink = make([]byte, 0, float64(1.0)) // ERROR "non-integer.*cap"
+
+ sink = make([]byte, 1+0i)
+ sink = make([]byte, complex64(1+0i)) // ERROR "non-integer.*len"
+ sink = make([]byte, complex128(1+0i)) // ERROR "non-integer.*len"
+
+ sink = make([]byte, 0, 1+0i)
+ sink = make([]byte, 0, complex64(1+0i)) // ERROR "non-integer.*cap"
+ sink = make([]byte, 0, complex128(1+0i)) // ERROR "non-integer.*cap"
+
+}
diff --git a/test/fixedbugs/issue16985.go b/test/fixedbugs/issue16985.go
new file mode 100644
index 0000000..0cb0dae
--- /dev/null
+++ b/test/fixedbugs/issue16985.go
@@ -0,0 +1,37 @@
+// run
+
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// issue 16985: intrinsified AMD64 atomic ops should clobber flags
+
+package main
+
+import "sync/atomic"
+
+var count uint32
+
+func main() {
+ buffer := []byte("T")
+ for i := 0; i < len(buffer); {
+ atomic.AddUint32(&count, 1)
+ _ = buffer[i]
+ i++
+ i++
+ }
+
+ for i := 0; i < len(buffer); {
+ atomic.CompareAndSwapUint32(&count, 0, 1)
+ _ = buffer[i]
+ i++
+ i++
+ }
+
+ for i := 0; i < len(buffer); {
+ atomic.SwapUint32(&count, 1)
+ _ = buffer[i]
+ i++
+ i++
+ }
+}
diff --git a/test/fixedbugs/issue17005.go b/test/fixedbugs/issue17005.go
new file mode 100644
index 0000000..e539519
--- /dev/null
+++ b/test/fixedbugs/issue17005.go
@@ -0,0 +1,46 @@
+// compile
+
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This tickles (a version of) the PPC64 back end to
+// emit a BVS instruction.
+
+package foo
+
+type Flag int
+
+const (
+ Identity Flag = iota - 2 // H is the identity matrix; no rotation is needed.
+ Rescaling // H specifies rescaling.
+)
+
+type DrotmParams struct {
+ Flag
+}
+
+func Drotmg(d1, d2, x1, y1 float64) (p DrotmParams, rd1, rd2, rx1 float64) {
+
+ const (
+ gam = 4.0
+ gamsq = 16.0
+ rgamsq = 5e-8
+ )
+
+ if d1 < 0 {
+ p.Flag = Rescaling
+ return
+ }
+
+ for rd1 <= rgamsq || rd1 >= gamsq {
+ if rd1 <= rgamsq {
+ rd1 *= gam * gam
+ rx1 /= gam
+ } else {
+ rd1 /= gam * gam
+ rx1 *= gam
+ }
+ }
+ return
+}
diff --git a/test/fixedbugs/issue17038.go b/test/fixedbugs/issue17038.go
new file mode 100644
index 0000000..1b65ffc
--- /dev/null
+++ b/test/fixedbugs/issue17038.go
@@ -0,0 +1,9 @@
+// errorcheck
+
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+const A = complex(0()) // ERROR "cannot call non-function"
diff --git a/test/fixedbugs/issue17039.go b/test/fixedbugs/issue17039.go
new file mode 100644
index 0000000..1298e2b
--- /dev/null
+++ b/test/fixedbugs/issue17039.go
@@ -0,0 +1,17 @@
+// run
+
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type S []S
+
+func main() {
+ var s S
+ s = append(s, s) // append a nil value to s
+ if s[0] != nil {
+ println("BUG: s[0] != nil")
+ }
+}
diff --git a/test/fixedbugs/issue17111.go b/test/fixedbugs/issue17111.go
new file mode 100644
index 0000000..05284a7
--- /dev/null
+++ b/test/fixedbugs/issue17111.go
@@ -0,0 +1,16 @@
+// compile
+
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type I int
+
+var (
+ i int
+ x = I(i)
+
+ e interface{} = x
+)
diff --git a/test/fixedbugs/issue17194.go b/test/fixedbugs/issue17194.go
new file mode 100644
index 0000000..0594e1c
--- /dev/null
+++ b/test/fixedbugs/issue17194.go
@@ -0,0 +1,17 @@
+// compile
+
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package foo
+
+func f(x []interface{}) (err error) {
+ for _, d := range x {
+ _, ok := d.(*int)
+ if ok {
+ return
+ }
+ }
+ return
+}
diff --git a/test/fixedbugs/issue17270.go b/test/fixedbugs/issue17270.go
new file mode 100644
index 0000000..5c009b5
--- /dev/null
+++ b/test/fixedbugs/issue17270.go
@@ -0,0 +1,11 @@
+// compile
+
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package p
+
+import "unsafe"
+
+const _ = (unsafe.Sizeof)(0)
diff --git a/test/fixedbugs/issue17381.go b/test/fixedbugs/issue17381.go
new file mode 100644
index 0000000..be63633
--- /dev/null
+++ b/test/fixedbugs/issue17381.go
@@ -0,0 +1,54 @@
+// run
+
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// issue 17381: make sure leave function with non-empty frame
+// saves link register, so that traceback will work.
+
+package main
+
+import (
+ "runtime"
+ "unsafe"
+)
+
+func main() {
+ defer func() {
+ if recover() == nil {
+ panic("did not panic")
+ }
+ pcs := make([]uintptr, 20)
+ n := runtime.Callers(1, pcs)
+ for _, pc := range pcs[:n] {
+ if runtime.FuncForPC(pc).Name() == "main.main" {
+ return
+ }
+ }
+ panic("cannot find main.main in backtrace")
+ }()
+
+ prep()
+ f() // should panic
+}
+
+func funcPC(f interface{}) uintptr {
+ var ptr uintptr
+ return **(**uintptr)(unsafe.Pointer(uintptr(unsafe.Pointer(&f)) + unsafe.Sizeof(ptr)))
+}
+
+//go:noinline
+func f() {
+ var t [1]int // non-empty frame
+ *(*int)(nil) = t[0]
+}
+
+var p = funcPC(runtime.GC) + 8
+
+//go:noinline
+func prep() {
+ // put some garbage on stack
+ var x = [20]uintptr{p, p, p, p, p, p, p, p, p, p, p, p, p, p, p, p, p, p, p, p}
+ _ = x
+}
diff --git a/test/fixedbugs/issue17449.go b/test/fixedbugs/issue17449.go
new file mode 100644
index 0000000..2302917
--- /dev/null
+++ b/test/fixedbugs/issue17449.go
@@ -0,0 +1,34 @@
+// errorcheck -0 -race
+
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Issue 17449: race instrumentation copies over previous instrumented nodes from parents block into child's Ninit block.
+// This code surfaces the duplication at compile time because of generated inline labels.
+
+package master
+
+type PriorityList struct {
+ elems []interface{}
+}
+
+func (x *PriorityList) Len() int { return len(x.elems) }
+
+func (l *PriorityList) remove(i int) interface{} {
+ elem := l.elems[i]
+ l.elems = append(l.elems[:i], l.elems[i+1:]...)
+ return elem
+}
+
+func (l *PriorityList) Next() interface{} {
+ return l.remove(l.Len() - 1)
+}
+
+var l *PriorityList
+
+func Foo() {
+ // It would fail here if instrumented code (including inline-label) was copied.
+ for elem := l.Next(); elem != nil; elem = l.Next() {
+ }
+}
diff --git a/test/fixedbugs/issue17551.go b/test/fixedbugs/issue17551.go
new file mode 100644
index 0000000..b8751ab
--- /dev/null
+++ b/test/fixedbugs/issue17551.go
@@ -0,0 +1,21 @@
+// compile
+
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Issue 17551: inrange optimization failed to preserve type information.
+
+package main
+
+import "fmt"
+
+func main() {
+ _, x := X()
+ fmt.Printf("x = %v\n", x)
+}
+
+func X() (i int, ok bool) {
+ ii := int(1)
+ return ii, 0 <= ii && ii <= 0x7fffffff
+}
diff --git a/test/fixedbugs/issue17588.go b/test/fixedbugs/issue17588.go
new file mode 100644
index 0000000..1be57c6
--- /dev/null
+++ b/test/fixedbugs/issue17588.go
@@ -0,0 +1,20 @@
+// errorcheck
+
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Issue 17588: internal compiler error in typecheckclosure()
+// because in case of Func.Nname.Type == nil, Decldepth
+// is not initialized in typecheckfunc(). This test
+// produces that case.
+
+package p
+
+type F func(b T) // ERROR "T is not a type"
+
+func T(fn F) {
+ func() {
+ fn(nil) // If Decldepth is not initialized properly, typecheckclosure() Fatals here.
+ }()
+}
diff --git a/test/fixedbugs/issue17596.go b/test/fixedbugs/issue17596.go
new file mode 100644
index 0000000..7398292
--- /dev/null
+++ b/test/fixedbugs/issue17596.go
@@ -0,0 +1,19 @@
+// compile
+
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package foo
+
+type T interface {
+ foo()
+}
+
+func f() (T, int)
+
+func g(v interface{}) (interface{}, int) {
+ var x int
+ v, x = f()
+ return v, x
+}
diff --git a/test/fixedbugs/issue17631.go b/test/fixedbugs/issue17631.go
new file mode 100644
index 0000000..79b7e8a
--- /dev/null
+++ b/test/fixedbugs/issue17631.go
@@ -0,0 +1,22 @@
+// 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
+
+import "time"
+
+func main() {
+ _ = struct {
+ about string
+ before map[string]uint
+ update map[string]int
+ updateTime time.Time
+ expect map[string]int
+ }{
+ about: "this one",
+ updates: map[string]int{"gopher": 10}, // ERROR "unknown field 'updates' in struct literal of type"
+ }
+}
diff --git a/test/fixedbugs/issue17640.go b/test/fixedbugs/issue17640.go
new file mode 100644
index 0000000..a311521
--- /dev/null
+++ b/test/fixedbugs/issue17640.go
@@ -0,0 +1,28 @@
+// run
+
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "fmt"
+
+var results string
+
+type TwoInts struct {
+ x, y int
+}
+
+func f(x int) int { results = results + fmt.Sprintf("_%d", x); return x }
+
+func main() {
+ _ = [19]int{1: f(1), 0: f(0), 2: f(2), 6, 7}
+ _ = [2]int{1: f(4), 0: f(3)}
+ _ = TwoInts{y: f(6), x: f(5)}
+ _ = map[int]int{f(f(9) + 1): f(8), 0: f(7), f(22): -1}
+ if results != "_1_0_2_4_3_6_5_9_10_8_7_22" {
+ fmt.Printf("unexpected: %s\n", results)
+ panic("fail")
+ }
+}
diff --git a/test/fixedbugs/issue17645.go b/test/fixedbugs/issue17645.go
new file mode 100644
index 0000000..ed92c54
--- /dev/null
+++ b/test/fixedbugs/issue17645.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
+
+type Foo struct {
+ X int
+}
+
+func main() {
+ var s []int
+ var _ string = append(s, Foo{""}) // ERROR "cannot use .. \(type string\) as type int in field value" "cannot use Foo literal \(type Foo\) as type int in append" "cannot use append\(s\, Foo literal\) \(type \[\]int\) as type string in assignment"
+}
+
diff --git a/test/fixedbugs/issue17710.go b/test/fixedbugs/issue17710.go
new file mode 100644
index 0000000..2843458
--- /dev/null
+++ b/test/fixedbugs/issue17710.go
@@ -0,0 +1,13 @@
+// compile
+
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "runtime"
+
+func f(x interface{}) {
+ runtime.KeepAlive(x)
+}
diff --git a/test/fixedbugs/issue17752.go b/test/fixedbugs/issue17752.go
new file mode 100644
index 0000000..83283ad
--- /dev/null
+++ b/test/fixedbugs/issue17752.go
@@ -0,0 +1,20 @@
+// run
+
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func f(m map[string]int) int {
+ return m["a"]
+}
+
+func g(m map[[8]string]int) int {
+ return m[[8]string{"a", "a", "a", "a", "a", "a", "a", "a"}]
+}
+
+func main() {
+ m := map[[8]string]int{}
+ g(m)
+}
diff --git a/test/fixedbugs/issue17918.go b/test/fixedbugs/issue17918.go
new file mode 100644
index 0000000..88ede6f
--- /dev/null
+++ b/test/fixedbugs/issue17918.go
@@ -0,0 +1,41 @@
+// compile
+
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Issue 17918: slice out-of-bounds in ssa/cse
+
+package dead
+
+import (
+ "fmt"
+ "time"
+)
+
+var (
+ units = []struct {
+ divisor time.Duration
+ unit rune
+ }{
+ {1000000, 's'},
+ {60, 'm'},
+ {60, 'h'},
+ {24, 'd'},
+ {7, 'w'},
+ }
+)
+
+func foobar(d time.Duration) string {
+ d /= time.Microsecond
+ unit := 'u'
+
+ for _, f := range units {
+ if d%f.divisor != 0 {
+ break
+ }
+ d /= f.divisor
+ unit = f.unit
+ }
+ return fmt.Sprintf("%d%c", d, unit)
+}
diff --git a/test/fixedbugs/issue18092.go b/test/fixedbugs/issue18092.go
new file mode 100644
index 0000000..94fd2dd
--- /dev/null
+++ b/test/fixedbugs/issue18092.go
@@ -0,0 +1,15 @@
+// errorcheck
+
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package p
+
+func _() {
+ var ch chan bool
+ select {
+ default:
+ case <-ch { // don't crash here
+ } // ERROR "expecting :"
+}
diff --git a/test/fixedbugs/issue4085b.go b/test/fixedbugs/issue4085b.go
index 583c417..b91bbd7 100644
--- a/test/fixedbugs/issue4085b.go
+++ b/test/fixedbugs/issue4085b.go
@@ -15,21 +15,25 @@ type T []int
func main() {
n := -1
- shouldPanic("len out of range", func() {_ = make(T, n)})
- shouldPanic("cap out of range", func() {_ = make(T, 0, n)})
+ shouldPanic("len out of range", func() { _ = make(T, n) })
+ shouldPanic("cap out of range", func() { _ = make(T, 0, n) })
+ shouldPanic("len out of range", func() { _ = make(T, int64(n)) })
+ shouldPanic("cap out of range", func() { _ = make(T, 0, int64(n)) })
var t *byte
if unsafe.Sizeof(t) == 8 {
- n = 1<<20
+ n = 1 << 20
n <<= 20
- shouldPanic("len out of range", func() {_ = make(T, n)})
- shouldPanic("cap out of range", func() {_ = make(T, 0, n)})
+ shouldPanic("len out of range", func() { _ = make(T, n) })
+ shouldPanic("cap out of range", func() { _ = make(T, 0, n) })
n <<= 20
- shouldPanic("len out of range", func() {_ = make(T, n)})
- shouldPanic("cap out of range", func() {_ = make(T, 0, n)})
+ shouldPanic("len out of range", func() { _ = make(T, n) })
+ shouldPanic("cap out of range", func() { _ = make(T, 0, n) })
} else {
n = 1<<31 - 1
- shouldPanic("len out of range", func() {_ = make(T, n)})
- shouldPanic("cap out of range", func() {_ = make(T, 0, n)})
+ shouldPanic("len out of range", func() { _ = make(T, n) })
+ shouldPanic("cap out of range", func() { _ = make(T, 0, n) })
+ shouldPanic("len out of range", func() { _ = make(T, int64(n)) })
+ shouldPanic("cap out of range", func() { _ = make(T, 0, int64(n)) })
}
}
@@ -44,6 +48,6 @@ func shouldPanic(str string, f func()) {
panic("got panic " + s + ", want " + str)
}
}()
-
+
f()
}
diff --git a/test/fixedbugs/issue4215.go b/test/fixedbugs/issue4215.go
new file mode 100644
index 0000000..795d48d
--- /dev/null
+++ b/test/fixedbugs/issue4215.go
@@ -0,0 +1,53 @@
+// 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 foo() (int, int) {
+ return 2.3 // ERROR "not enough arguments to return\n\thave \(number\)\n\twant \(int, int\)"
+}
+
+func foo2() {
+ return int(2), 2 // ERROR "too many arguments to return\n\thave \(int, number\)\n\twant \(\)"
+}
+
+func foo3(v int) (a, b, c, d int) {
+ if v >= 0 {
+ return 1 // ERROR "not enough arguments to return\n\thave \(number\)\n\twant \(int, int, int, int\)"
+ }
+ return 2, 3 // ERROR "not enough arguments to return\n\thave \(number, number\)\n\twant \(int, int, int, int\)"
+}
+
+func foo4(name string) (string, int) {
+ switch name {
+ case "cow":
+ return "moo" // ERROR "not enough arguments to return\n\thave \(string\)\n\twant \(string, int\)"
+ case "dog":
+ return "dog", 10, true // ERROR "too many arguments to return\n\thave \(string, number, bool\)\n\twant \(string, int\)"
+ case "fish":
+ return "" // ERROR "not enough arguments to return\n\thave \(string\)\n\twant \(string, int\)"
+ default:
+ return "lizard", 10
+ }
+}
+
+type S int
+type T string
+type U float64
+
+func foo5() (S, T, U) {
+ if false {
+ return "" // ERROR "not enough arguments to return\n\thave \(string\)\n\twant \(S, T, U\)"
+ } else {
+ ptr := new(T)
+ return ptr // ERROR "not enough arguments to return\n\thave \(\*T\)\n\twant \(S, T, U\)"
+ }
+ return new(S), 12.34, 1 + 0i, 'r', true // ERROR "too many arguments to return\n\thave \(\*S, number, number, number, bool\)\n\twant \(S, T, U\)"
+}
+
+func foo6() (T, string) {
+ return "T", true, true // ERROR "too many arguments to return\n\thave \(string, bool, bool\)\n\twant \(T, string\)"
+}
diff --git a/test/fixedbugs/issue6750.go b/test/fixedbugs/issue6750.go
new file mode 100644
index 0000000..dbbb454
--- /dev/null
+++ b/test/fixedbugs/issue6750.go
@@ -0,0 +1,22 @@
+// 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
+
+import "fmt"
+
+func printmany(nums ...int) {
+ for i, n := range nums {
+ fmt.Printf("%d: %d\n", i, n)
+ }
+ fmt.Printf("\n")
+}
+
+func main() {
+ printmany(1, 2, 3)
+ printmany([]int{1, 2, 3}...)
+ printmany(1, "abc", []int{2, 3}...) // ERROR "too many arguments in call to printmany\n\thave \(number, string, \[\]int\.\.\.\)\n\twant \(...int\)"
+}
diff --git a/test/fixedbugs/issue8613.go b/test/fixedbugs/issue8613.go
index c0ad131..ffa75a4 100644
--- a/test/fixedbugs/issue8613.go
+++ b/test/fixedbugs/issue8613.go
@@ -1,4 +1,3 @@
-// +build amd64
// run
// Copyright 2016 The Go Authors. All rights reserved.
diff --git a/test/fixedbugs/issue9608.dir/issue9608.go b/test/fixedbugs/issue9608.dir/issue9608.go
index 56b52cc..ca82ded 100644
--- a/test/fixedbugs/issue9608.dir/issue9608.go
+++ b/test/fixedbugs/issue9608.dir/issue9608.go
@@ -67,6 +67,15 @@ func init() {
case true:
fail()
}
+
+ // Test dead code elimination in large ranges.
+ switch 5 {
+ case 3, 4, 5, 6, 7:
+ case 0, 1, 2:
+ fail()
+ default:
+ fail()
+ }
}
func main() {
diff --git a/test/float_lit2.go b/test/float_lit2.go
index bb86559..901698f 100644
--- a/test/float_lit2.go
+++ b/test/float_lit2.go
@@ -13,12 +13,12 @@ import (
"math"
)
-// The largest exact float32 is f₁ = (1+(1-2²³))×2¹²⁷ = (1-2²⁴)×2¹²⁸ = 2¹²⁸ - 2¹⁰⁴.
+// The largest exact float32 is f₁ = (1+1-1/2²³)×2¹²⁷ = (2-2⁻²³)×2¹²⁷ = 2¹²⁸ - 2¹⁰⁴.
// The next float32 would be f₂ = (1+1)×2¹²⁷ = 1×2¹²⁸, except that exponent is out of range.
// Float32 conversion rounds to the nearest float32, rounding to even mantissa:
// between f₁ and f₂, values closer to f₁ round to f₁ and values closer to f₂ are rejected as out of range.
// f₁ is an odd mantissa, so the halfway point (f₁+f₂)/2 rounds to f₂ and is rejected.
-// The halfway point is (f₁+f₂)/2 = 2¹²⁸ - 2¹⁰⁵.
+// The halfway point is (f₁+f₂)/2 = 2¹²⁸ - 2¹⁰³.
//
// The same is true of float64, with different constants: s/24/53/ and s/128/1024/.
diff --git a/test/inline_variadic.go b/test/inline_variadic.go
new file mode 100644
index 0000000..6466c2b
--- /dev/null
+++ b/test/inline_variadic.go
@@ -0,0 +1,19 @@
+// errorcheck -0 -m -l=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 more aggressive inlining (-l=3 allows variadic functions)
+// See issue #18116.
+
+package foo
+
+func head(xs ...string) string { // ERROR "can inline head" "leaking param: xs to result"
+ return xs[0]
+}
+
+func f() string { // ERROR "can inline f"
+ x := head("hello", "world") // ERROR "inlining call to head" "\[\]string literal does not escape"
+ return x
+}
diff --git a/test/interface/assertinline.go b/test/interface/assertinline.go
index 227fe70..324316b 100644
--- a/test/interface/assertinline.go
+++ b/test/interface/assertinline.go
@@ -24,30 +24,51 @@ func assertfunc2(x interface{}) (func(), bool) {
return z, ok
}
-// TODO(rsc): struct{*int} is stored directly in the interface
-// and should be possible to fetch back out of the interface,
-// but more of the general data movement code needs to
-// realize that before we can inline the assertion.
-
func assertstruct(x interface{}) struct{ *int } {
- return x.(struct{ *int }) // ERROR "type assertion not inlined"
+ return x.(struct{ *int }) // ERROR "type assertion inlined"
}
func assertstruct2(x interface{}) (struct{ *int }, bool) {
- z, ok := x.(struct{ *int }) // ERROR "type assertion not inlined"
+ z, ok := x.(struct{ *int }) // ERROR "type assertion inlined"
return z, ok
}
func assertbig(x interface{}) complex128 {
- return x.(complex128) // ERROR "type assertion not inlined"
+ return x.(complex128) // ERROR "type assertion inlined"
}
func assertbig2(x interface{}) (complex128, bool) {
- z, ok := x.(complex128) // ERROR "type assertion not inlined"
+ z, ok := x.(complex128) // ERROR "type assertion inlined"
return z, ok
}
func assertbig2ok(x interface{}) (complex128, bool) {
- _, ok := x.(complex128) // ERROR "type assertion [(]ok only[)] inlined"
+ _, ok := x.(complex128) // ERROR "type assertion inlined"
return 0, ok
}
+
+func assertslice(x interface{}) []int {
+ return x.([]int) // ERROR "type assertion inlined"
+}
+
+func assertslice2(x interface{}) ([]int, bool) {
+ z, ok := x.([]int) // ERROR "type assertion inlined"
+ return z, ok
+}
+
+func assertslice2ok(x interface{}) ([]int, bool) {
+ _, ok := x.([]int) // ERROR "type assertion inlined"
+ return nil, ok
+}
+
+type I interface {
+ foo()
+}
+
+func assertInter(x interface{}) I {
+ return x.(I) // ERROR "type assertion not inlined"
+}
+func assertInter2(x interface{}) (I, bool) {
+ z, ok := x.(I) // ERROR "type assertion not inlined"
+ return z, ok
+}
diff --git a/test/intrinsic.dir/main.go b/test/intrinsic.dir/main.go
index 46e6cb3..e0c11d0 100644
--- a/test/intrinsic.dir/main.go
+++ b/test/intrinsic.dir/main.go
@@ -45,18 +45,6 @@ func test(i, x uint64) {
logf("Ctz32(0x%x) expected %d but got %d\n", x32, i, t32)
}
}
- if i <= 16 {
- x16 := uint16(x)
- t16 := T.Ctz16(x16) // ERROR "intrinsic substitution for Ctz16"
- if uint16(i) != t16 {
- logf("Ctz16(0x%x) expected %d but got %d\n", x16, i, t16)
- }
- x16 = -x16
- t16 = T.Ctz16(x16) // ERROR "intrinsic substitution for Ctz16"
- if uint16(i) != t16 {
- logf("Ctz16(0x%x) expected %d but got %d\n", x16, i, t16)
- }
- }
}
func main() {
@@ -88,9 +76,6 @@ func main() {
}
// Zero is a special case, be sure it is done right.
- if T.Ctz16(0) != 16 { // ERROR "intrinsic substitution for Ctz16"
- logf("ctz16(0) != 16")
- }
if T.Ctz32(0) != 32 { // ERROR "intrinsic substitution for Ctz32"
logf("ctz32(0) != 32")
}
diff --git a/test/intrinsic.go b/test/intrinsic.go
index f774128..0b783d1 100644
--- a/test/intrinsic.go
+++ b/test/intrinsic.go
@@ -1,5 +1,5 @@
// errorcheckandrundir -0 -d=ssa/intrinsics/debug
-// +build !ppc64,!ppc64le,amd64
+// +build amd64 arm64 arm s390x
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
diff --git a/test/intrinsic_atomic.go b/test/intrinsic_atomic.go
new file mode 100644
index 0000000..dd765a0
--- /dev/null
+++ b/test/intrinsic_atomic.go
@@ -0,0 +1,20 @@
+// errorcheck -0 -d=ssa/intrinsics/debug
+// +build amd64 arm64
+
+// Copyright 2016 The Go Authors. 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 "sync/atomic"
+
+var x uint32
+
+func atomics() {
+ _ = atomic.LoadUint32(&x) // ERROR "intrinsic substitution for LoadUint32"
+ atomic.StoreUint32(&x, 1) // ERROR "intrinsic substitution for StoreUint32"
+ atomic.AddUint32(&x, 1) // ERROR "intrinsic substitution for AddUint32"
+ atomic.SwapUint32(&x, 1) // ERROR "intrinsic substitution for SwapUint32"
+ atomic.CompareAndSwapUint32(&x, 1, 2) // ERROR "intrinsic substitution for CompareAndSwapUint32"
+}
diff --git a/test/live.go b/test/live.go
index da0606d..4fb231c 100644
--- a/test/live.go
+++ b/test/live.go
@@ -1,5 +1,6 @@
-// +build !amd64
-// errorcheck -0 -l -live -wb=0
+// errorcheckwithauto -0 -l -live -wb=0
+// +build !ppc64,!ppc64le
+// ppc64 needs a better tighten pass to make f18 pass
// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
@@ -45,25 +46,26 @@ func f2(b bool) {
printpointer(&x) // ERROR "live at call to printpointer: x$"
}
-func f3(b bool) {
- // Because x and y are ambiguously live, they appear
- // live throughout the function, to avoid being poisoned
- // in GODEBUG=gcdead=1 mode.
+func f3(b1, b2 bool) {
+ // Here x and y are ambiguously live. In previous go versions they
+ // were marked as live throughout the function to avoid being
+ // poisoned in GODEBUG=gcdead=1 mode; this is now no longer the
+ // case.
- printint(0) // ERROR "live at call to printint: x y$"
- if b == false {
- printint(0) // ERROR "live at call to printint: x y$"
+ printint(0)
+ if b1 == false {
+ printint(0)
return
}
- if b {
+ if b2 {
var x *int
- printpointer(&x) // ERROR "live at call to printpointer: x y$"
- printpointer(&x) // ERROR "live at call to printpointer: x y$"
+ printpointer(&x) // ERROR "live at call to printpointer: x$"
+ printpointer(&x) // ERROR "live at call to printpointer: x$"
} else {
var y *int
- printpointer(&y) // ERROR "live at call to printpointer: x y$"
- printpointer(&y) // ERROR "live at call to printpointer: x y$"
+ printpointer(&y) // ERROR "live at call to printpointer: y$"
+ printpointer(&y) // ERROR "live at call to printpointer: y$"
}
printint(0) // ERROR "f3: x \(type \*int\) is ambiguously live$" "f3: y \(type \*int\) is ambiguously live$" "live at call to printint: x y$"
}
@@ -83,13 +85,13 @@ func f4(b1, b2 bool) { // x not live here
x := new(int)
*x = 42
z = &x
- printint(**z) // ERROR "live at call to printint: x z$"
+ printint(**z) // ERROR "live at call to printint: x$"
if b2 {
- printint(1) // ERROR "live at call to printint: x$"
+ printint(1) // x not live here
return
}
for {
- printint(**z) // ERROR "live at call to printint: x z$"
+ printint(**z) // ERROR "live at call to printint: x$"
}
}
@@ -138,7 +140,9 @@ var i9 interface{}
func f9() bool {
g8()
x := i9
- return x != interface{}(99.0i) // ERROR "live at call to convT2E: x$"
+ y := interface{}(99.0i) // ERROR "live at call to convT2E: x.data x.type$"
+ i9 = y // make y escape so the line above has to call convT2E
+ return x != y
}
// liveness formerly confused by UNDEF followed by RET,
@@ -158,10 +162,10 @@ var b bool
// this used to have a spurious "live at entry to f11a: ~r0"
func f11a() *int {
- select { // ERROR "live at call to newselect: autotmp_[0-9]+$" "live at call to selectgo: autotmp_[0-9]+$"
- case <-c: // ERROR "live at call to selectrecv: autotmp_[0-9]+$"
+ select { // ERROR "live at call to newselect: .autotmp_[0-9]+$" "live at call to selectgo: .autotmp_[0-9]+$"
+ case <-c: // ERROR "live at call to selectrecv: .autotmp_[0-9]+$"
return nil
- case <-c: // ERROR "live at call to selectrecv: autotmp_[0-9]+$"
+ case <-c: // ERROR "live at call to selectrecv: .autotmp_[0-9]+$"
return nil
}
}
@@ -173,10 +177,10 @@ func f11b() *int {
// get to the bottom of the function.
// This used to have a spurious "live at call to printint: p".
printint(1) // nothing live here!
- select { // ERROR "live at call to newselect: autotmp_[0-9]+$" "live at call to selectgo: autotmp_[0-9]+$"
- case <-c: // ERROR "live at call to selectrecv: autotmp_[0-9]+$"
+ select { // ERROR "live at call to newselect: .autotmp_[0-9]+$" "live at call to selectgo: .autotmp_[0-9]+$"
+ case <-c: // ERROR "live at call to selectrecv: .autotmp_[0-9]+$"
return nil
- case <-c: // ERROR "live at call to selectrecv: autotmp_[0-9]+$"
+ case <-c: // ERROR "live at call to selectrecv: .autotmp_[0-9]+$"
return nil
}
}
@@ -184,15 +188,18 @@ func f11b() *int {
return nil
}
+var sink *int
+
func f11c() *int {
p := new(int)
+ sink = p // prevent stack allocation, otherwise p is rematerializeable
if b {
// Unlike previous, the cases in this select fall through,
// so we can get to the println, so p is not dead.
printint(1) // ERROR "live at call to printint: p$"
- select { // ERROR "live at call to newselect: autotmp_[0-9]+ p$" "live at call to selectgo: autotmp_[0-9]+ p$"
- case <-c: // ERROR "live at call to selectrecv: autotmp_[0-9]+ p$"
- case <-c: // ERROR "live at call to selectrecv: autotmp_[0-9]+ p$"
+ select { // ERROR "live at call to newselect: .autotmp_[0-9]+ p$" "live at call to selectgo: .autotmp_[0-9]+ p$"
+ case <-c: // ERROR "live at call to selectrecv: .autotmp_[0-9]+ p$"
+ case <-c: // ERROR "live at call to selectrecv: .autotmp_[0-9]+ p$"
}
}
println(*p)
@@ -215,8 +222,8 @@ func f12() *int {
// needed for the call to h13).
func f13() {
- s := "hello"
- s = h13(s, g13(s)) // ERROR "live at call to g13: s$"
+ s := g14()
+ s = h13(s, g13(s)) // ERROR "live at call to g13: s.ptr$"
}
func g13(string) string
@@ -250,10 +257,10 @@ var m map[string]int
func f16() {
if b {
- delete(m, "hi") // ERROR "live at call to mapdelete: autotmp_[0-9]+$"
+ delete(m, "hi") // ERROR "live at call to mapdelete: .autotmp_[0-9]+$"
}
- delete(m, "hi") // ERROR "live at call to mapdelete: autotmp_[0-9]+$"
- delete(m, "hi") // ERROR "live at call to mapdelete: autotmp_[0-9]+$"
+ delete(m, "hi") // ERROR "live at call to mapdelete: .autotmp_[0-9]+$"
+ delete(m, "hi") // ERROR "live at call to mapdelete: .autotmp_[0-9]+$"
}
var m2s map[string]*byte
@@ -261,33 +268,34 @@ var m2 map[[2]string]*byte
var x2 [2]string
var bp *byte
-func f17a() {
- // value temporary only
+func f17a(p *byte) { // ERROR "live at entry to f17a: p$"
if b {
- m2[x2] = nil // ERROR "live at call to mapassign1: autotmp_[0-9]+$"
+ m2[x2] = p // ERROR "live at call to mapassign: p$"
}
- m2[x2] = nil // ERROR "live at call to mapassign1: autotmp_[0-9]+$"
- m2[x2] = nil // ERROR "live at call to mapassign1: autotmp_[0-9]+$"
+ m2[x2] = p // ERROR "live at call to mapassign: p$"
+ m2[x2] = p // ERROR "live at call to mapassign: p$"
}
-func f17b() {
- // key temporary only
+func f17b(p *byte) { // ERROR "live at entry to f17b: p$"
+ // key temporary
if b {
- m2s["x"] = bp // ERROR "live at call to mapassign1: autotmp_[0-9]+$"
+ m2s["x"] = p // ERROR "live at call to mapassign: p .autotmp_[0-9]+$"
}
- m2s["x"] = bp // ERROR "live at call to mapassign1: autotmp_[0-9]+$"
- m2s["x"] = bp // ERROR "live at call to mapassign1: autotmp_[0-9]+$"
+ 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]+$"
}
func f17c() {
// key and value temporaries
if b {
- m2s["x"] = nil // ERROR "live at call to mapassign1: autotmp_[0-9]+ autotmp_[0-9]+$"
+ m2s["x"] = f17d() // ERROR "live at call to f17d: .autotmp_[0-9]+$" "live at call to mapassign: .autotmp_[0-9]+ .autotmp_[0-9]+$"
}
- m2s["x"] = nil // ERROR "live at call to mapassign1: autotmp_[0-9]+ autotmp_[0-9]+$"
- m2s["x"] = nil // ERROR "live at call to mapassign1: autotmp_[0-9]+ autotmp_[0-9]+$"
+ 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]+$"
}
+func f17d() *byte
+
func g18() [2]string
func f18() {
@@ -295,10 +303,10 @@ func f18() {
// temporary introduced by orderexpr.
var z *byte
if b {
- z = m2[g18()] // ERROR "live at call to mapaccess1: autotmp_[0-9]+$"
+ z = m2[g18()] // ERROR "live at call to mapaccess1: .autotmp_[0-9]+$"
}
- z = m2[g18()] // ERROR "live at call to mapaccess1: autotmp_[0-9]+$"
- z = m2[g18()] // ERROR "live at call to mapaccess1: autotmp_[0-9]+$"
+ z = m2[g18()] // ERROR "live at call to mapaccess1: .autotmp_[0-9]+$"
+ z = m2[g18()] // ERROR "live at call to mapaccess1: .autotmp_[0-9]+$"
printbytepointer(z)
}
@@ -309,30 +317,30 @@ func f19() {
var z *byte
if b {
- z = <-ch // ERROR "live at call to chanrecv1: autotmp_[0-9]+$"
+ z = <-ch // ERROR "live at call to chanrecv1: .autotmp_[0-9]+$"
}
- z = <-ch // ERROR "live at call to chanrecv1: autotmp_[0-9]+$"
- z = <-ch // ERROR "live at call to chanrecv1: autotmp_[0-9]+$"
+ z = <-ch // ERROR "live at call to chanrecv1: .autotmp_[0-9]+$"
+ z = <-ch // ERROR "live at call to chanrecv1: .autotmp_[0-9]+$"
printbytepointer(z)
}
func f20() {
// src temporary for channel send
if b {
- ch <- nil // ERROR "live at call to chansend1: autotmp_[0-9]+$"
+ ch <- nil // ERROR "live at call to chansend1: .autotmp_[0-9]+$"
}
- ch <- nil // ERROR "live at call to chansend1: autotmp_[0-9]+$"
- ch <- nil // ERROR "live at call to chansend1: autotmp_[0-9]+$"
+ ch <- nil // ERROR "live at call to chansend1: .autotmp_[0-9]+$"
+ ch <- nil // ERROR "live at call to chansend1: .autotmp_[0-9]+$"
}
func f21() {
// key temporary for mapaccess using array literal key.
var z *byte
if b {
- z = m2[[2]string{"x", "y"}] // ERROR "live at call to mapaccess1: autotmp_[0-9]+$"
+ z = m2[[2]string{"x", "y"}] // ERROR "live at call to mapaccess1: .autotmp_[0-9]+$"
}
- z = m2[[2]string{"x", "y"}] // ERROR "live at call to mapaccess1: autotmp_[0-9]+$"
- z = m2[[2]string{"x", "y"}] // ERROR "live at call to mapaccess1: autotmp_[0-9]+$"
+ z = m2[[2]string{"x", "y"}] // ERROR "live at call to mapaccess1: .autotmp_[0-9]+$"
+ z = m2[[2]string{"x", "y"}] // ERROR "live at call to mapaccess1: .autotmp_[0-9]+$"
printbytepointer(z)
}
@@ -341,10 +349,10 @@ func f23() {
var z *byte
var ok bool
if b {
- z, ok = m2[[2]string{"x", "y"}] // ERROR "live at call to mapaccess2: autotmp_[0-9]+$"
+ z, ok = m2[[2]string{"x", "y"}] // ERROR "live at call to mapaccess2: .autotmp_[0-9]+$"
}
- z, ok = m2[[2]string{"x", "y"}] // ERROR "live at call to mapaccess2: autotmp_[0-9]+$"
- z, ok = m2[[2]string{"x", "y"}] // ERROR "live at call to mapaccess2: autotmp_[0-9]+$"
+ z, ok = m2[[2]string{"x", "y"}] // ERROR "live at call to mapaccess2: .autotmp_[0-9]+$"
+ z, ok = m2[[2]string{"x", "y"}] // ERROR "live at call to mapaccess2: .autotmp_[0-9]+$"
printbytepointer(z)
print(ok)
}
@@ -353,10 +361,10 @@ func f24() {
// key temporary for map access using array literal key.
// value temporary too.
if b {
- m2[[2]string{"x", "y"}] = nil // ERROR "live at call to mapassign1: autotmp_[0-9]+ autotmp_[0-9]+$"
+ m2[[2]string{"x", "y"}] = nil // ERROR "live at call to mapassign: .autotmp_[0-9]+$"
}
- m2[[2]string{"x", "y"}] = nil // ERROR "live at call to mapassign1: autotmp_[0-9]+ autotmp_[0-9]+$"
- m2[[2]string{"x", "y"}] = nil // ERROR "live at call to mapassign1: autotmp_[0-9]+ autotmp_[0-9]+$"
+ m2[[2]string{"x", "y"}] = nil // ERROR "live at call to mapassign: .autotmp_[0-9]+$"
+ m2[[2]string{"x", "y"}] = nil // ERROR "live at call to mapassign: .autotmp_[0-9]+$"
}
// defer should not cause spurious ambiguously live variables
@@ -380,10 +388,10 @@ func g25()
func f26(b bool) {
if b {
- print26((*int)(nil), (*int)(nil), (*int)(nil)) // ERROR "live at call to print26: autotmp_[0-9]+$"
+ print26((*int)(nil), (*int)(nil), (*int)(nil)) // ERROR "live at call to print26: .autotmp_[0-9]+$"
}
- print26((*int)(nil), (*int)(nil), (*int)(nil)) // ERROR "live at call to print26: autotmp_[0-9]+$"
- print26((*int)(nil), (*int)(nil), (*int)(nil)) // ERROR "live at call to print26: autotmp_[0-9]+$"
+ print26((*int)(nil), (*int)(nil), (*int)(nil)) // ERROR "live at call to print26: .autotmp_[0-9]+$"
+ print26((*int)(nil), (*int)(nil), (*int)(nil)) // ERROR "live at call to print26: .autotmp_[0-9]+$"
printnl()
}
@@ -395,10 +403,10 @@ func print26(...interface{})
func f27(b bool) {
x := 0
if b {
- call27(func() { x++ }) // ERROR "live at call to call27: autotmp_[0-9]+$"
+ call27(func() { x++ }) // ERROR "live at call to call27: .autotmp_[0-9]+$"
}
- call27(func() { x++ }) // ERROR "live at call to call27: autotmp_[0-9]+$"
- call27(func() { x++ }) // ERROR "live at call to call27: autotmp_[0-9]+$"
+ call27(func() { x++ }) // ERROR "live at call to call27: .autotmp_[0-9]+$"
+ call27(func() { x++ }) // ERROR "live at call to call27: .autotmp_[0-9]+$"
printnl()
}
@@ -407,11 +415,11 @@ func f27(b bool) {
func f27defer(b bool) {
x := 0
if b {
- defer call27(func() { x++ }) // ERROR "live at call to deferproc: autotmp_[0-9]+$" "live at call to deferreturn: autotmp_[0-9]+$"
+ defer call27(func() { x++ }) // ERROR "live at call to deferproc: .autotmp_[0-9]+$" "live at call to deferreturn: .autotmp_[0-9]+$"
}
- defer call27(func() { x++ }) // ERROR "f27defer: autotmp_[0-9]+ \(type struct { F uintptr; x \*int }\) is ambiguously live$" "live at call to deferproc: autotmp_[0-9]+ autotmp_[0-9]+$" "live at call to deferreturn: autotmp_[0-9]+ autotmp_[0-9]+$"
- printnl() // ERROR "live at call to printnl: autotmp_[0-9]+ autotmp_[0-9]+$"
-} // ERROR "live at call to deferreturn: autotmp_[0-9]+ autotmp_[0-9]+$"
+ defer call27(func() { x++ }) // ERROR "f27defer: .autotmp_[0-9]+ \(type struct { F uintptr; x \*int }\) is ambiguously live$" "live at call to deferproc: .autotmp_[0-9]+ .autotmp_[0-9]+$" "live at call to deferreturn: .autotmp_[0-9]+ .autotmp_[0-9]+$"
+ printnl() // ERROR "live at call to printnl: .autotmp_[0-9]+ .autotmp_[0-9]+$"
+} // ERROR "live at call to deferreturn: .autotmp_[0-9]+ .autotmp_[0-9]+$"
// and newproc (go) escapes to the heap
@@ -433,25 +441,25 @@ var s1, s2, s3, s4, s5, s6, s7, s8, s9, s10 string
func f28(b bool) {
if b {
- printstring(s1 + s2 + s3 + s4 + s5 + s6 + s7 + s8 + s9 + s10) // ERROR "live at call to concatstrings: autotmp_[0-9]+$" "live at call to printstring: autotmp_[0-9]+$"
+ printstring(s1 + s2 + s3 + s4 + s5 + s6 + s7 + s8 + s9 + s10) // ERROR "live at call to concatstrings: .autotmp_[0-9]+$" "live at call to printstring: .autotmp_[0-9]+$"
}
- printstring(s1 + s2 + s3 + s4 + s5 + s6 + s7 + s8 + s9 + s10) // ERROR "live at call to concatstrings: autotmp_[0-9]+$" "live at call to printstring: autotmp_[0-9]+$"
- printstring(s1 + s2 + s3 + s4 + s5 + s6 + s7 + s8 + s9 + s10) // ERROR "live at call to concatstrings: autotmp_[0-9]+$" "live at call to printstring: autotmp_[0-9]+$"
+ printstring(s1 + s2 + s3 + s4 + s5 + s6 + s7 + s8 + s9 + s10) // ERROR "live at call to concatstrings: .autotmp_[0-9]+$" "live at call to printstring: .autotmp_[0-9]+$"
+ printstring(s1 + s2 + s3 + s4 + s5 + s6 + s7 + s8 + s9 + s10) // ERROR "live at call to concatstrings: .autotmp_[0-9]+$" "live at call to printstring: .autotmp_[0-9]+$"
}
// map iterator should die on end of range loop
func f29(b bool) {
if b {
- for k := range m { // ERROR "live at call to mapiterinit: autotmp_[0-9]+$" "live at call to mapiternext: autotmp_[0-9]+$"
- printstring(k) // ERROR "live at call to printstring: autotmp_[0-9]+$"
+ for k := range m { // ERROR "live at call to mapiterinit: .autotmp_[0-9]+$" "live at call to mapiternext: .autotmp_[0-9]+$"
+ printstring(k) // ERROR "live at call to printstring: .autotmp_[0-9]+$"
}
}
- for k := range m { // ERROR "live at call to mapiterinit: autotmp_[0-9]+$" "live at call to mapiternext: autotmp_[0-9]+$"
- printstring(k) // ERROR "live at call to printstring: autotmp_[0-9]+$"
+ for k := range m { // ERROR "live at call to mapiterinit: .autotmp_[0-9]+$" "live at call to mapiternext: .autotmp_[0-9]+$"
+ printstring(k) // ERROR "live at call to printstring: .autotmp_[0-9]+$"
}
- for k := range m { // ERROR "live at call to mapiterinit: autotmp_[0-9]+$" "live at call to mapiternext: autotmp_[0-9]+$"
- printstring(k) // ERROR "live at call to printstring: autotmp_[0-9]+$"
+ for k := range m { // ERROR "live at call to mapiterinit: .autotmp_[0-9]+$" "live at call to mapiternext: .autotmp_[0-9]+$"
+ printstring(k) // ERROR "live at call to printstring: .autotmp_[0-9]+$"
}
}
@@ -464,14 +472,14 @@ func f30(b bool) {
// the copy of ptrarr and the internal iterator pointer.
if b {
for _, p := range ptrarr {
- printintpointer(p) // ERROR "live at call to printintpointer: autotmp_[0-9]+ autotmp_[0-9]+$"
+ printintpointer(p) // ERROR "live at call to printintpointer: .autotmp_[0-9]+ .autotmp_[0-9]+$"
}
}
for _, p := range ptrarr {
- printintpointer(p) // ERROR "live at call to printintpointer: autotmp_[0-9]+ autotmp_[0-9]+$"
+ printintpointer(p) // ERROR "live at call to printintpointer: .autotmp_[0-9]+ .autotmp_[0-9]+$"
}
for _, p := range ptrarr {
- printintpointer(p) // ERROR "live at call to printintpointer: autotmp_[0-9]+ autotmp_[0-9]+$"
+ printintpointer(p) // ERROR "live at call to printintpointer: .autotmp_[0-9]+ .autotmp_[0-9]+$"
}
}
@@ -479,13 +487,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("a") // ERROR "live at call to convT2E: .autotmp_[0-9]+$" "live at call to g31: .autotmp_[0-9]+$"
}
if b2 {
- h31("b") // ERROR "live at call to convT2E: autotmp_[0-9]+ autotmp_[0-9]+$" "live at call to h31: autotmp_[0-9]+$" "live at call to newobject: autotmp_[0-9]+$"
+ h31("b") // ERROR "live at call to convT2E: .autotmp_[0-9]+ .autotmp_[0-9]+$" "live at call to h31: .autotmp_[0-9]+$" "live at call to newobject: .autotmp_[0-9]+$"
}
if b3 {
- panic("asdf") // ERROR "live at call to convT2E: autotmp_[0-9]+$" "live at call to gopanic: autotmp_[0-9]+$"
+ panic("asdf") // ERROR "live at call to convT2E: .autotmp_[0-9]+$" "live at call to gopanic: .autotmp_[0-9]+$"
}
print(b3)
}
@@ -505,10 +513,10 @@ var t32 T32
func f32(b bool) {
if b {
- call32(t32.Inc) // ERROR "live at call to call32: autotmp_[0-9]+$"
+ call32(t32.Inc) // ERROR "live at call to call32: .autotmp_[0-9]+$"
}
- call32(t32.Inc) // ERROR "live at call to call32: autotmp_[0-9]+$"
- call32(t32.Inc) // ERROR "live at call to call32: autotmp_[0-9]+$"
+ call32(t32.Inc) // ERROR "live at call to call32: .autotmp_[0-9]+$"
+ call32(t32.Inc) // ERROR "live at call to call32: .autotmp_[0-9]+$"
}
//go:noescape
@@ -520,7 +528,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[nil] == 0 { // ERROR "live at call to mapaccess1: .autotmp_[0-9]+$"
printnl()
return
} else {
@@ -530,7 +538,7 @@ func f33() {
}
func f34() {
- if m33[nil] == 0 { // ERROR "live at call to mapaccess1: autotmp_[0-9]+$"
+ if m33[nil] == 0 { // ERROR "live at call to mapaccess1: .autotmp_[0-9]+$"
printnl()
return
}
@@ -538,7 +546,7 @@ func f34() {
}
func f35() {
- if m33[nil] == 0 && m33[nil] == 0 { // ERROR "live at call to mapaccess1: autotmp_[0-9]+$"
+ if m33[nil] == 0 && m33[nil] == 0 { // ERROR "live at call to mapaccess1: .autotmp_[0-9]+$"
printnl()
return
}
@@ -546,7 +554,7 @@ func f35() {
}
func f36() {
- if m33[nil] == 0 || m33[nil] == 0 { // ERROR "live at call to mapaccess1: autotmp_[0-9]+$"
+ if m33[nil] == 0 || m33[nil] == 0 { // ERROR "live at call to mapaccess1: .autotmp_[0-9]+$"
printnl()
return
}
@@ -554,7 +562,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[nil] == 0 || m33[nil] == 0) && m33[nil] == 0 { // ERROR "live at call to mapaccess1: .autotmp_[0-9]+$"
printnl()
return
}
@@ -574,14 +582,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]+ .autotmp_[0-9]+ .autotmp_[0-9]+ .autotmp_[0-9]+ .autotmp_[0-9]+ .autotmp_[0-9]+ .autotmp_[0-9]+ .autotmp_[0-9]+$" "live at call to selectgo: .autotmp_[0-9]+ .autotmp_[0-9]+ .autotmp_[0-9]+ .autotmp_[0-9]+ .autotmp_[0-9]+ .autotmp_[0-9]+ .autotmp_[0-9]+$"
+ case <-fc38(): // ERROR "live at call to selectrecv: .autotmp_[0-9]+ .autotmp_[0-9]+ .autotmp_[0-9]+ .autotmp_[0-9]+ .autotmp_[0-9]+ .autotmp_[0-9]+ .autotmp_[0-9]+$"
printnl()
- case fc38() <- *fi38(1): // ERROR "live at call to fc38: autotmp_[0-9]+$" "live at call to fi38: autotmp_[0-9]+ autotmp_[0-9]+$" "live at call to selectsend: autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+$"
+ case fc38() <- *fi38(1): // ERROR "live at call to fc38: .autotmp_[0-9]+$" "live at call to fi38: .autotmp_[0-9]+ .autotmp_[0-9]+$" "live at call to selectsend: .autotmp_[0-9]+ .autotmp_[0-9]+ .autotmp_[0-9]+ .autotmp_[0-9]+ .autotmp_[0-9]+ .autotmp_[0-9]+ .autotmp_[0-9]+$"
printnl()
- case *fi38(2) = <-fc38(): // ERROR "live at call to fc38: autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+$" "live at call to fi38: autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+$" "live at call to selectrecv: autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+$"
+ case *fi38(2) = <-fc38(): // ERROR "live at call to fc38: .autotmp_[0-9]+ .autotmp_[0-9]+ .autotmp_[0-9]+$" "live at call to fi38: .autotmp_[0-9]+ .autotmp_[0-9]+ .autotmp_[0-9]+$" "live at call to selectrecv: .autotmp_[0-9]+ .autotmp_[0-9]+ .autotmp_[0-9]+ .autotmp_[0-9]+ .autotmp_[0-9]+ .autotmp_[0-9]+ .autotmp_[0-9]+$"
printnl()
- case *fi38(3), *fb38() = <-fc38(): // ERROR "live at call to fb38: autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+$" "live at call to fc38: autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+$" "live at call to fi38: autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+$" "live at call to selectrecv2: autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+$"
+ case *fi38(3), *fb38() = <-fc38(): // ERROR "live at call to fb38: .autotmp_[0-9]+ .autotmp_[0-9]+ .autotmp_[0-9]+$" "live at call to fc38: .autotmp_[0-9]+ .autotmp_[0-9]+ .autotmp_[0-9]+ .autotmp_[0-9]+ .autotmp_[0-9]+$" "live at call to fi38: .autotmp_[0-9]+ .autotmp_[0-9]+ .autotmp_[0-9]+$" "live at call to selectrecv2: .autotmp_[0-9]+ .autotmp_[0-9]+ .autotmp_[0-9]+ .autotmp_[0-9]+ .autotmp_[0-9]+ .autotmp_[0-9]+ .autotmp_[0-9]+$"
printnl()
}
printnl()
@@ -593,13 +601,13 @@ func f38(b bool) {
func f39() (x []int) {
x = []int{1}
- printnl() // ERROR "live at call to printnl: x$"
+ printnl() // ERROR "live at call to printnl: .autotmp_[0-9]+$"
return x
}
func f39a() (x []int) {
x = []int{1}
- printnl() // ERROR "live at call to printnl: x$"
+ printnl() // ERROR "live at call to printnl: .autotmp_[0-9]+$"
return
}
@@ -638,8 +646,24 @@ func bad40() {
func good40() {
ret := T40{}
- ret.m = make(map[int]int) // ERROR "live at call to makemap: autotmp_[0-9]+ ret$"
+ ret.m = make(map[int]int) // ERROR "live at call to makemap: .autotmp_[0-9]+ ret$"
t := &ret
- printnl() // ERROR "live at call to printnl: autotmp_[0-9]+ ret$"
+ printnl() // ERROR "live at call to printnl: .autotmp_[0-9]+ ret$"
_ = t
}
+
+func ddd1(x, y *int) { // ERROR "live at entry to ddd1: x y$"
+ ddd2(x, y) // ERROR "live at call to ddd2: .autotmp_[0-9]+$"
+ printnl()
+ // Note: no .?autotmp live at printnl. See issue 16996.
+}
+func ddd2(a ...*int) { // ERROR "live at entry to ddd2: a$"
+ sink = a[0]
+}
+
+// issue 16016: autogenerated wrapper should have arguments live
+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"
diff --git a/test/live2.go b/test/live2.go
index a5bbfa5..6138d36 100644
--- a/test/live2.go
+++ b/test/live2.go
@@ -1,4 +1,3 @@
-// +build !amd64
// errorcheck -0 -live -wb=0
// Copyright 2014 The Go Authors. All rights reserved.
@@ -21,20 +20,20 @@ type T40 struct {
func newT40() *T40 {
ret := T40{}
- ret.m = make(map[int]int) // ERROR "live at call to makemap: &ret"
+ ret.m = make(map[int]int) // ERROR "live at call to makemap: &ret$"
return &ret
}
func bad40() {
- t := newT40() // ERROR "live at call to makemap: autotmp_.* ret"
- printnl() // ERROR "live at call to printnl: autotmp_.* ret"
+ t := newT40() // ERROR "live at call to makemap: .autotmp_[0-9]+ ret$"
+ printnl() // ERROR "live at call to printnl: .autotmp_[0-9]+ ret$"
_ = t
}
func good40() {
ret := T40{}
- ret.m = make(map[int]int) // ERROR "live at call to makemap: autotmp_.* ret"
+ ret.m = make(map[int]int) // ERROR "live at call to makemap: .autotmp_[0-9]+ ret$"
t := &ret
- printnl() // ERROR "live at call to printnl: autotmp_.* ret"
+ printnl() // ERROR "live at call to printnl: .autotmp_[0-9]+ ret$"
_ = t
}
diff --git a/test/live_ssa.go b/test/live_ssa.go
deleted file mode 100644
index bd70924..0000000
--- a/test/live_ssa.go
+++ /dev/null
@@ -1,648 +0,0 @@
-// +build amd64
-// errorcheck -0 -l -live -wb=0
-
-// Copyright 2014 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// liveness tests with inlining disabled.
-// see also live2.go.
-
-package main
-
-func printnl()
-
-//go:noescape
-func printpointer(**int)
-
-//go:noescape
-func printintpointer(*int)
-
-//go:noescape
-func printstringpointer(*string)
-
-//go:noescape
-func printstring(string)
-
-//go:noescape
-func printbytepointer(*byte)
-
-func printint(int)
-
-func f1() {
- var x *int
- printpointer(&x) // ERROR "live at call to printpointer: x$"
- printpointer(&x) // ERROR "live at call to printpointer: x$"
-}
-
-func f2(b bool) {
- if b {
- printint(0) // nothing live here
- return
- }
- var x *int
- printpointer(&x) // ERROR "live at call to printpointer: x$"
- printpointer(&x) // ERROR "live at call to printpointer: x$"
-}
-
-func f3(b1, b2 bool) {
- // Because x and y are ambiguously live, they appear
- // live throughout the function, to avoid being poisoned
- // in GODEBUG=gcdead=1 mode.
-
- printint(0) // ERROR "live at call to printint: x y$"
- if b1 == false {
- printint(0) // ERROR "live at call to printint: x y$"
- return
- }
-
- if b2 {
- var x *int
- printpointer(&x) // ERROR "live at call to printpointer: x y$"
- printpointer(&x) // ERROR "live at call to printpointer: x y$"
- } else {
- var y *int
- printpointer(&y) // ERROR "live at call to printpointer: x y$"
- printpointer(&y) // ERROR "live at call to printpointer: x y$"
- }
- printint(0) // ERROR "f3: x \(type \*int\) is ambiguously live$" "f3: y \(type \*int\) is ambiguously live$" "live at call to printint: x y$"
-}
-
-// The old algorithm treated x as live on all code that
-// could flow to a return statement, so it included the
-// function entry and code above the declaration of x
-// but would not include an indirect use of x in an infinite loop.
-// Check that these cases are handled correctly.
-
-func f4(b1, b2 bool) { // x not live here
- if b2 {
- printint(0) // x not live here
- return
- }
- var z **int
- x := new(int)
- *x = 42
- z = &x
- printint(**z) // ERROR "live at call to printint: x$"
- if b2 {
- printint(1) // x not live here
- return
- }
- for {
- printint(**z) // ERROR "live at call to printint: x$"
- }
-}
-
-func f5(b1 bool) {
- var z **int
- if b1 {
- x := new(int)
- *x = 42
- z = &x
- } else {
- y := new(int)
- *y = 54
- z = &y
- }
- printint(**z) // ERROR "f5: x \(type \*int\) is ambiguously live$" "f5: y \(type \*int\) is ambiguously live$" "live at call to printint: x y$"
-}
-
-// confusion about the _ result used to cause spurious "live at entry to f6: _".
-
-func f6() (_, y string) {
- y = "hello"
- return
-}
-
-// confusion about addressed results used to cause "live at entry to f7: x".
-
-func f7() (x string) {
- _ = &x
- x = "hello"
- return
-}
-
-// ignoring block returns used to cause "live at entry to f8: x, y".
-
-func f8() (x, y string) {
- return g8()
-}
-
-func g8() (string, string)
-
-// ignoring block assignments used to cause "live at entry to f9: x"
-// issue 7205
-
-var i9 interface{}
-
-func f9() bool {
- g8()
- x := i9
- return x != interface{}(99.0i) // ERROR "live at call to convT2E: x.data x.type$"
-}
-
-// liveness formerly confused by UNDEF followed by RET,
-// leading to "live at entry to f10: ~r1" (unnamed result).
-
-func f10() string {
- panic(1)
-}
-
-// liveness formerly confused by select, thinking runtime.selectgo
-// can return to next instruction; it always jumps elsewhere.
-// note that you have to use at least two cases in the select
-// to get a true select; smaller selects compile to optimized helper functions.
-
-var c chan *int
-var b bool
-
-// this used to have a spurious "live at entry to f11a: ~r0"
-func f11a() *int {
- select { // ERROR "live at call to newselect: autotmp_[0-9]+$" "live at call to selectgo: autotmp_[0-9]+$"
- case <-c: // ERROR "live at call to selectrecv: autotmp_[0-9]+$"
- return nil
- case <-c: // ERROR "live at call to selectrecv: autotmp_[0-9]+$"
- return nil
- }
-}
-
-func f11b() *int {
- p := new(int)
- if b {
- // At this point p is dead: the code here cannot
- // get to the bottom of the function.
- // This used to have a spurious "live at call to printint: p".
- printint(1) // nothing live here!
- select { // ERROR "live at call to newselect: autotmp_[0-9]+$" "live at call to selectgo: autotmp_[0-9]+$"
- case <-c: // ERROR "live at call to selectrecv: autotmp_[0-9]+$"
- return nil
- case <-c: // ERROR "live at call to selectrecv: autotmp_[0-9]+$"
- return nil
- }
- }
- println(*p)
- return nil
-}
-
-var sink *int
-
-func f11c() *int {
- p := new(int)
- sink = p // prevent stack allocation, otherwise p is rematerializeable
- if b {
- // Unlike previous, the cases in this select fall through,
- // so we can get to the println, so p is not dead.
- printint(1) // ERROR "live at call to printint: p$"
- select { // ERROR "live at call to newselect: autotmp_[0-9]+ p$" "live at call to selectgo: autotmp_[0-9]+ p$"
- case <-c: // ERROR "live at call to selectrecv: autotmp_[0-9]+ p$"
- case <-c: // ERROR "live at call to selectrecv: autotmp_[0-9]+ p$"
- }
- }
- println(*p)
- return nil
-}
-
-// similarly, select{} does not fall through.
-// this used to have a spurious "live at entry to f12: ~r0".
-
-func f12() *int {
- if b {
- select {}
- } else {
- return nil
- }
-}
-
-// incorrectly placed VARDEF annotations can cause missing liveness annotations.
-// this used to be missing the fact that s is live during the call to g13 (because it is
-// needed for the call to h13).
-
-func f13() {
- s := g14()
- s = h13(s, g13(s)) // ERROR "live at call to g13: s.ptr$"
-}
-
-func g13(string) string
-func h13(string, string) string
-
-// more incorrectly placed VARDEF.
-
-func f14() {
- x := g14()
- printstringpointer(&x) // ERROR "live at call to printstringpointer: x$"
-}
-
-func g14() string
-
-func f15() {
- var x string
- _ = &x
- x = g15() // ERROR "live at call to g15: x$"
- printstring(x) // ERROR "live at call to printstring: x$"
-}
-
-func g15() string
-
-// Checking that various temporaries do not persist or cause
-// ambiguously live values that must be zeroed.
-// The exact temporary names are inconsequential but we are
-// trying to check that there is only one at any given site,
-// and also that none show up in "ambiguously live" messages.
-
-var m map[string]int
-
-func f16() {
- if b {
- delete(m, "hi") // ERROR "live at call to mapdelete: autotmp_[0-9]+$"
- }
- delete(m, "hi") // ERROR "live at call to mapdelete: autotmp_[0-9]+$"
- delete(m, "hi") // ERROR "live at call to mapdelete: autotmp_[0-9]+$"
-}
-
-var m2s map[string]*byte
-var m2 map[[2]string]*byte
-var x2 [2]string
-var bp *byte
-
-func f17a() {
- // value temporary only
- if b {
- m2[x2] = nil // ERROR "live at call to mapassign1: autotmp_[0-9]+$"
- }
- m2[x2] = nil // ERROR "live at call to mapassign1: autotmp_[0-9]+$"
- m2[x2] = nil // ERROR "live at call to mapassign1: autotmp_[0-9]+$"
-}
-
-func f17b() {
- // key temporary only
- if b {
- m2s["x"] = bp // ERROR "live at call to mapassign1: autotmp_[0-9]+$"
- }
- m2s["x"] = bp // ERROR "live at call to mapassign1: autotmp_[0-9]+$"
- m2s["x"] = bp // ERROR "live at call to mapassign1: autotmp_[0-9]+$"
-}
-
-func f17c() {
- // key and value temporaries
- if b {
- m2s["x"] = nil // ERROR "live at call to mapassign1: autotmp_[0-9]+ autotmp_[0-9]+$"
- }
- m2s["x"] = nil // ERROR "live at call to mapassign1: autotmp_[0-9]+ autotmp_[0-9]+$"
- m2s["x"] = nil // ERROR "live at call to mapassign1: autotmp_[0-9]+ autotmp_[0-9]+$"
-}
-
-func g18() [2]string
-
-func f18() {
- // key temporary for mapaccess.
- // temporary introduced by orderexpr.
- var z *byte
- if b {
- z = m2[g18()] // ERROR "live at call to mapaccess1: autotmp_[0-9]+$"
- }
- z = m2[g18()] // ERROR "live at call to mapaccess1: autotmp_[0-9]+$"
- z = m2[g18()] // ERROR "live at call to mapaccess1: autotmp_[0-9]+$"
- printbytepointer(z)
-}
-
-var ch chan *byte
-
-func f19() {
- // dest temporary for channel receive.
- var z *byte
-
- if b {
- z = <-ch // ERROR "live at call to chanrecv1: autotmp_[0-9]+$"
- }
- z = <-ch // ERROR "live at call to chanrecv1: autotmp_[0-9]+$"
- z = <-ch // ERROR "live at call to chanrecv1: autotmp_[0-9]+$"
- printbytepointer(z)
-}
-
-func f20() {
- // src temporary for channel send
- if b {
- ch <- nil // ERROR "live at call to chansend1: autotmp_[0-9]+$"
- }
- ch <- nil // ERROR "live at call to chansend1: autotmp_[0-9]+$"
- ch <- nil // ERROR "live at call to chansend1: autotmp_[0-9]+$"
-}
-
-func f21() {
- // key temporary for mapaccess using array literal key.
- var z *byte
- if b {
- z = m2[[2]string{"x", "y"}] // ERROR "live at call to mapaccess1: autotmp_[0-9]+$"
- }
- z = m2[[2]string{"x", "y"}] // ERROR "live at call to mapaccess1: autotmp_[0-9]+$"
- z = m2[[2]string{"x", "y"}] // ERROR "live at call to mapaccess1: autotmp_[0-9]+$"
- printbytepointer(z)
-}
-
-func f23() {
- // key temporary for two-result map access using array literal key.
- var z *byte
- var ok bool
- if b {
- z, ok = m2[[2]string{"x", "y"}] // ERROR "live at call to mapaccess2: autotmp_[0-9]+$"
- }
- z, ok = m2[[2]string{"x", "y"}] // ERROR "live at call to mapaccess2: autotmp_[0-9]+$"
- z, ok = m2[[2]string{"x", "y"}] // ERROR "live at call to mapaccess2: autotmp_[0-9]+$"
- printbytepointer(z)
- print(ok)
-}
-
-func f24() {
- // key temporary for map access using array literal key.
- // value temporary too.
- if b {
- m2[[2]string{"x", "y"}] = nil // ERROR "live at call to mapassign1: autotmp_[0-9]+ autotmp_[0-9]+$"
- }
- m2[[2]string{"x", "y"}] = nil // ERROR "live at call to mapassign1: autotmp_[0-9]+ autotmp_[0-9]+$"
- m2[[2]string{"x", "y"}] = nil // ERROR "live at call to mapassign1: autotmp_[0-9]+ autotmp_[0-9]+$"
-}
-
-// defer should not cause spurious ambiguously live variables
-
-func f25(b bool) {
- defer g25()
- if b {
- return
- }
- var x string
- _ = &x
- x = g15() // ERROR "live at call to g15: x$"
- printstring(x) // ERROR "live at call to printstring: x$"
-} // ERROR "live at call to deferreturn: x$"
-
-func g25()
-
-// non-escaping ... slices passed to function call should die on return,
-// so that the temporaries do not stack and do not cause ambiguously
-// live variables.
-
-func f26(b bool) {
- if b {
- print26((*int)(nil), (*int)(nil), (*int)(nil)) // ERROR "live at call to print26: autotmp_[0-9]+$"
- }
- print26((*int)(nil), (*int)(nil), (*int)(nil)) // ERROR "live at call to print26: autotmp_[0-9]+$"
- print26((*int)(nil), (*int)(nil), (*int)(nil)) // ERROR "live at call to print26: autotmp_[0-9]+$"
- printnl()
-}
-
-//go:noescape
-func print26(...interface{})
-
-// non-escaping closures passed to function call should die on return
-
-func f27(b bool) {
- x := 0
- if b {
- call27(func() { x++ }) // ERROR "live at call to call27: autotmp_[0-9]+$"
- }
- call27(func() { x++ }) // ERROR "live at call to call27: autotmp_[0-9]+$"
- call27(func() { x++ }) // ERROR "live at call to call27: autotmp_[0-9]+$"
- printnl()
-}
-
-// but defer does escape to later execution in the function
-
-func f27defer(b bool) {
- x := 0
- if b {
- defer call27(func() { x++ }) // ERROR "live at call to deferproc: autotmp_[0-9]+$" "live at call to deferreturn: autotmp_[0-9]+$"
- }
- defer call27(func() { x++ }) // ERROR "f27defer: autotmp_[0-9]+ \(type struct { F uintptr; x \*int }\) is ambiguously live$" "live at call to deferproc: autotmp_[0-9]+ autotmp_[0-9]+$" "live at call to deferreturn: autotmp_[0-9]+ autotmp_[0-9]+$"
- printnl() // ERROR "live at call to printnl: autotmp_[0-9]+ autotmp_[0-9]+$"
-} // ERROR "live at call to deferreturn: autotmp_[0-9]+ autotmp_[0-9]+$"
-
-// and newproc (go) escapes to the heap
-
-func f27go(b bool) {
- x := 0
- if b {
- go call27(func() { x++ }) // ERROR "live at call to newobject: &x$" "live at call to newproc: &x$"
- }
- go call27(func() { x++ }) // ERROR "live at call to newobject: &x$"
- printnl()
-}
-
-//go:noescape
-func call27(func())
-
-// concatstring slice should die on return
-
-var s1, s2, s3, s4, s5, s6, s7, s8, s9, s10 string
-
-func f28(b bool) {
- if b {
- printstring(s1 + s2 + s3 + s4 + s5 + s6 + s7 + s8 + s9 + s10) // ERROR "live at call to concatstrings: autotmp_[0-9]+$" "live at call to printstring: autotmp_[0-9]+$"
- }
- printstring(s1 + s2 + s3 + s4 + s5 + s6 + s7 + s8 + s9 + s10) // ERROR "live at call to concatstrings: autotmp_[0-9]+$" "live at call to printstring: autotmp_[0-9]+$"
- printstring(s1 + s2 + s3 + s4 + s5 + s6 + s7 + s8 + s9 + s10) // ERROR "live at call to concatstrings: autotmp_[0-9]+$" "live at call to printstring: autotmp_[0-9]+$"
-}
-
-// map iterator should die on end of range loop
-
-func f29(b bool) {
- if b {
- for k := range m { // ERROR "live at call to mapiterinit: autotmp_[0-9]+$" "live at call to mapiternext: autotmp_[0-9]+$"
- printstring(k) // ERROR "live at call to printstring: autotmp_[0-9]+$"
- }
- }
- for k := range m { // ERROR "live at call to mapiterinit: autotmp_[0-9]+$" "live at call to mapiternext: autotmp_[0-9]+$"
- printstring(k) // ERROR "live at call to printstring: autotmp_[0-9]+$"
- }
- for k := range m { // ERROR "live at call to mapiterinit: autotmp_[0-9]+$" "live at call to mapiternext: autotmp_[0-9]+$"
- printstring(k) // ERROR "live at call to printstring: autotmp_[0-9]+$"
- }
-}
-
-// copy of array of pointers should die at end of range loop
-
-var ptrarr [10]*int
-
-func f30(b bool) {
- // two live temps during print(p):
- // the copy of ptrarr and the internal iterator pointer.
- if b {
- for _, p := range ptrarr {
- printintpointer(p) // ERROR "live at call to printintpointer: autotmp_[0-9]+ autotmp_[0-9]+$"
- }
- }
- for _, p := range ptrarr {
- printintpointer(p) // ERROR "live at call to printintpointer: autotmp_[0-9]+ autotmp_[0-9]+$"
- }
- for _, p := range ptrarr {
- printintpointer(p) // ERROR "live at call to printintpointer: autotmp_[0-9]+ autotmp_[0-9]+$"
- }
-}
-
-// conversion to interface should not leave temporary behind
-
-func f31(b1, b2, b3 bool) {
- if b1 {
- g31("a") // ERROR "live at call to convT2E: autotmp_[0-9]+$" "live at call to g31: autotmp_[0-9]+$"
- }
- if b2 {
- h31("b") // ERROR "live at call to convT2E: autotmp_[0-9]+ autotmp_[0-9]+$" "live at call to h31: autotmp_[0-9]+$" "live at call to newobject: autotmp_[0-9]+$"
- }
- if b3 {
- panic("asdf") // ERROR "live at call to convT2E: autotmp_[0-9]+$" "live at call to gopanic: autotmp_[0-9]+$"
- }
- print(b3)
-}
-
-func g31(interface{})
-func h31(...interface{})
-
-// non-escaping partial functions passed to function call should die on return
-
-type T32 int
-
-func (t *T32) Inc() { // ERROR "live at entry to \(\*T32\).Inc: t$"
- *t++
-}
-
-var t32 T32
-
-func f32(b bool) {
- if b {
- call32(t32.Inc) // ERROR "live at call to call32: autotmp_[0-9]+$"
- }
- call32(t32.Inc) // ERROR "live at call to call32: autotmp_[0-9]+$"
- call32(t32.Inc) // ERROR "live at call to call32: autotmp_[0-9]+$"
-}
-
-//go:noescape
-func call32(func())
-
-// temporaries introduced during if conditions and && || expressions
-// should die once the condition has been acted upon.
-
-var m33 map[interface{}]int
-
-func f33() {
- if m33[nil] == 0 { // ERROR "live at call to mapaccess1: autotmp_[0-9]+$"
- printnl()
- return
- } else {
- printnl()
- }
- printnl()
-}
-
-func f34() {
- if m33[nil] == 0 { // ERROR "live at call to mapaccess1: autotmp_[0-9]+$"
- printnl()
- return
- }
- printnl()
-}
-
-func f35() {
- if m33[nil] == 0 && m33[nil] == 0 { // ERROR "live at call to mapaccess1: autotmp_[0-9]+$"
- printnl()
- return
- }
- printnl()
-}
-
-func f36() {
- if m33[nil] == 0 || m33[nil] == 0 { // ERROR "live at call to mapaccess1: autotmp_[0-9]+$"
- printnl()
- return
- }
- printnl()
-}
-
-func f37() {
- if (m33[nil] == 0 || m33[nil] == 0) && m33[nil] == 0 { // ERROR "live at call to mapaccess1: autotmp_[0-9]+$"
- printnl()
- return
- }
- printnl()
-}
-
-// select temps should disappear in the case bodies
-
-var c38 chan string
-
-func fc38() chan string
-func fi38(int) *string
-func fb38() *bool
-
-func f38(b bool) {
- // we don't care what temps are printed on the lines with output.
- // we care that the println lines have no live variables
- // and therefore no output.
- if b {
- select { // ERROR "live at call to newselect: autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+$" "live at call to selectgo: autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+$"
- case <-fc38(): // ERROR "live at call to selectrecv: autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+$"
- printnl()
- case fc38() <- *fi38(1): // ERROR "live at call to fc38: autotmp_[0-9]+$" "live at call to fi38: autotmp_[0-9]+ autotmp_[0-9]+$" "live at call to selectsend: autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+$"
- printnl()
- case *fi38(2) = <-fc38(): // ERROR "live at call to fc38: autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+$" "live at call to fi38: autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+$" "live at call to selectrecv: autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+$"
- printnl()
- case *fi38(3), *fb38() = <-fc38(): // ERROR "live at call to fb38: autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+$" "live at call to fc38: autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+$" "live at call to fi38: autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+$" "live at call to selectrecv2: autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+$"
- printnl()
- }
- printnl()
- }
- printnl()
-}
-
-// issue 8097: mishandling of x = x during return.
-
-func f39() (x []int) {
- x = []int{1}
- printnl() // ERROR "live at call to printnl: autotmp_[0-9]+$"
- return x
-}
-
-func f39a() (x []int) {
- x = []int{1}
- printnl() // ERROR "live at call to printnl: autotmp_[0-9]+$"
- return
-}
-
-func f39b() (x [10]*int) {
- x = [10]*int{}
- x[0] = new(int) // ERROR "live at call to newobject: x$"
- printnl() // ERROR "live at call to printnl: x$"
- return x
-}
-
-func f39c() (x [10]*int) {
- x = [10]*int{}
- x[0] = new(int) // ERROR "live at call to newobject: x$"
- printnl() // ERROR "live at call to printnl: x$"
- return
-}
-
-// issue 8142: lost 'addrtaken' bit on inlined variables.
-// no inlining in this test, so just checking that non-inlined works.
-
-type T40 struct {
- m map[int]int
-}
-
-func newT40() *T40 {
- ret := T40{}
- ret.m = make(map[int]int) // ERROR "live at call to makemap: &ret$"
- return &ret
-}
-
-func bad40() {
- t := newT40()
- _ = t
- printnl()
-}
-
-func good40() {
- ret := T40{}
- ret.m = make(map[int]int) // ERROR "live at call to makemap: autotmp_[0-9]+ ret$"
- t := &ret
- printnl() // ERROR "live at call to printnl: autotmp_[0-9]+ ret$"
- _ = t
-}
diff --git a/test/live_syscall.go b/test/live_syscall.go
index 8aaa691..f693e93 100644
--- a/test/live_syscall.go
+++ b/test/live_syscall.go
@@ -19,10 +19,10 @@ func f(uintptr) // ERROR "f assuming arg#1 is unsafe uintptr"
func g() {
var t int
- f(uintptr(unsafe.Pointer(&t))) // ERROR "live at call to f: autotmp" "g &t does not escape"
+ f(uintptr(unsafe.Pointer(&t))) // ERROR "live at call to f: .?autotmp" "g &t does not escape"
}
func h() {
var v int
- syscall.Syscall(0, 1, uintptr(unsafe.Pointer(&v)), 2) // ERROR "live at call to Syscall: autotmp" "h &v does not escape"
+ syscall.Syscall(0, 1, uintptr(unsafe.Pointer(&v)), 2) // ERROR "live at call to Syscall: .?autotmp" "h &v does not escape"
}
diff --git a/test/method2.go b/test/method2.go
index aaa850e..e55aee4 100644
--- a/test/method2.go
+++ b/test/method2.go
@@ -33,5 +33,5 @@ var _ = (*Val).val // ERROR "method"
var v Val
var pv = &v
-var _ = pv.val() // ERROR "method"
-var _ = pv.val // ERROR "method"
+var _ = pv.val() // ERROR "pv.val undefined"
+var _ = pv.val // ERROR "pv.val undefined"
diff --git a/test/nilptr3.go b/test/nilptr3.go
index 8922729..8fdae8c 100644
--- a/test/nilptr3.go
+++ b/test/nilptr3.go
@@ -1,8 +1,4 @@
// errorcheck -0 -d=nil
-// Fails on ppc64x because of incomplete optimization.
-// See issues 9058.
-// Same reason for mips64x and s390x.
-// +build !ppc64,!ppc64le,!mips64,!mips64le,!amd64,!s390x
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
@@ -52,15 +48,15 @@ func f1() {
_ = *arrayp // ERROR "generated nil check"
// 0-byte indirect doesn't suffice.
- // we don't registerize globals, so there are no removed repeated nil checks.
- _ = *array0p // ERROR "generated nil check"
+ // we don't registerize globals, so there are no removed.* nil checks.
_ = *array0p // ERROR "generated nil check"
+ _ = *array0p // ERROR "removed nil check"
- _ = *intp // ERROR "generated nil check"
- _ = *arrayp // 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() {
@@ -78,12 +74,12 @@ func f2() {
_ = *intp // ERROR "generated nil check"
_ = *arrayp // ERROR "generated nil check"
_ = *array0p // ERROR "generated nil check"
- _ = *array0p // ERROR "removed repeated nil check"
- _ = *intp // ERROR "removed repeated nil check"
- _ = *arrayp // ERROR "removed repeated nil check"
+ _ = *array0p // ERROR "removed.* nil check"
+ _ = *intp // ERROR "removed.* nil check"
+ _ = *arrayp // ERROR "removed.* nil check"
_ = *structp // ERROR "generated nil check"
_ = *emptyp // ERROR "generated nil check"
- _ = *arrayp // ERROR "removed repeated 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"
@@ -99,7 +95,7 @@ func f3(x *[10000]int) {
_ = x[9999] // ERROR "generated nil check"
for {
- if x[9999] != 0 { // ERROR "generated nil check"
+ if x[9999] != 0 { // ERROR "removed nil check"
break
}
}
@@ -107,11 +103,11 @@ func f3(x *[10000]int) {
x = fx10k()
_ = x[9999] // ERROR "generated nil check"
if b {
- _ = x[9999] // ERROR "removed repeated nil check"
+ _ = x[9999] // ERROR "removed.* nil check"
} else {
- _ = x[9999] // ERROR "removed repeated nil check"
+ _ = x[9999] // ERROR "removed.* nil check"
}
- _ = x[9999] // ERROR "generated nil check"
+ _ = x[9999] // ERROR "removed nil check"
x = fx10k()
if b {
@@ -126,7 +122,7 @@ 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"
+ _ = x[9999] // ERROR "removed nil check"
}
func f3a() {
@@ -135,7 +131,7 @@ func f3a() {
z := fx10k()
_ = &x[9] // ERROR "generated nil check"
y = z
- _ = &x[9] // ERROR "removed repeated nil check"
+ _ = &x[9] // ERROR "removed.* nil check"
x = y
_ = &x[9] // ERROR "generated nil check"
}
@@ -145,9 +141,9 @@ func f3b() {
y := fx10k()
_ = &x[9] // ERROR "generated nil check"
y = x
- _ = &x[9] // ERROR "removed repeated nil check"
+ _ = &x[9] // ERROR "removed.* nil check"
x = y
- _ = &x[9] // ERROR "removed repeated nil check"
+ _ = &x[9] // ERROR "removed.* nil check"
}
func fx10() *[10]int
@@ -157,41 +153,56 @@ func f4(x *[10]int) {
// and the offset is small enough that if x is nil, the address will still be
// in the first unmapped page of memory.
- _ = x[9] // ERROR "removed nil check before indirect"
+ _ = x[9] // ERROR "generated nil check" // bug: would like to remove this check (but nilcheck and load are in different blocks)
for {
- if x[9] != 0 { // ERROR "removed nil check before indirect"
+ if x[9] != 0 { // ERROR "removed nil check"
break
}
}
x = fx10()
- _ = x[9] // ERROR "removed nil check before indirect"
+ _ = x[9] // ERROR "generated nil check" // bug would like to remove before indirect
if b {
- _ = x[9] // ERROR "removed nil check before indirect"
+ _ = x[9] // ERROR "removed nil check"
} else {
- _ = x[9] // ERROR "removed nil check before indirect"
+ _ = x[9] // ERROR "removed nil check"
}
- _ = x[9] // ERROR "removed nil check before indirect"
+ _ = x[9] // ERROR "removed nil check"
x = fx10()
if b {
- _ = x[9] // ERROR "removed nil check before indirect"
+ _ = x[9] // ERROR "generated nil check" // bug would like to remove before indirect
} else {
_ = &x[9] // ERROR "generated nil check"
}
- _ = x[9] // ERROR "removed nil check before indirect"
+ _ = x[9] // ERROR "generated nil check" // bug would like to remove before indirect
fx10()
- _ = x[9] // ERROR "removed nil check before indirect"
+ _ = x[9] // ERROR "removed nil check"
x = fx10()
y := fx10()
_ = &x[9] // ERROR "generated nil check"
y = x
- _ = &x[9] // ERROR "removed repeated nil check"
+ _ = &x[9] // ERROR "removed[a-z ]* nil check"
x = y
- _ = &x[9] // ERROR "removed repeated nil check"
+ _ = &x[9] // ERROR "removed[a-z ]* nil check"
+}
+
+func f5(p *float32, q *float64, r *float32, s *float64) float64 {
+ x := float64(*p) // ERROR "removed nil check"
+ y := *q // ERROR "removed nil check"
+ *r = 7 // ERROR "removed nil check"
+ *s = 9 // ERROR "removed nil check"
+ return x + y
+}
+
+type T [29]byte
+
+func f6(p, q *T) {
+ x := *p // ERROR "removed nil check"
+ *q = x // ERROR "removed nil check"
}
func m1(m map[int][80]byte) byte {
@@ -214,3 +225,32 @@ func p1() byte {
p := new([100]byte)
return p[5] // ERROR "removed nil check"
}
+
+// make sure not to do nil check for access of PAUTOHEAP
+//go:noinline
+func (p *Struct) m() {}
+func c1() {
+ var x Struct
+ func() { x.m() }() // ERROR "removed nil check"
+}
+
+type SS struct {
+ x byte
+}
+
+type TT struct {
+ SS
+}
+
+func f(t *TT) *byte {
+ // See issue 17242.
+ s := &t.SS // ERROR "removed nil check"
+ return &s.x // ERROR "generated nil check"
+}
+
+// make sure not to do nil check for newobject
+func f7() (*Struct, float64) {
+ t := new(Struct)
+ p := &t.Y // ERROR "removed nil check"
+ return t, *p // ERROR "removed nil check"
+}
diff --git a/test/nilptr3_ssa.go b/test/nilptr3_ssa.go
deleted file mode 100644
index 0d690eb..0000000
--- a/test/nilptr3_ssa.go
+++ /dev/null
@@ -1,230 +0,0 @@
-// errorcheck -0 -d=nil
-// Fails on ppc64x because of incomplete optimization.
-// See issues 9058.
-// +build !ppc64,!ppc64le,amd64
-
-// Copyright 2013 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// Test that nil checks are removed.
-// Optimization is enabled.
-
-package p
-
-type Struct struct {
- X int
- Y float64
-}
-
-type BigStruct struct {
- X int
- Y float64
- A [1 << 20]int
- Z string
-}
-
-type Empty struct {
-}
-
-type Empty1 struct {
- Empty
-}
-
-var (
- intp *int
- arrayp *[10]int
- array0p *[0]int
- bigarrayp *[1 << 26]int
- structp *Struct
- bigstructp *BigStruct
- emptyp *Empty
- empty1p *Empty1
-)
-
-func f1() {
- _ = *intp // ERROR "generated nil check"
-
- // This one should be removed but the block copy needs
- // to be turned into its own pseudo-op in order to see
- // the indirect.
- _ = *arrayp // ERROR "generated nil check"
-
- // 0-byte indirect doesn't suffice.
- // we don't registerize globals, so there are no removed.* nil checks.
- _ = *array0p // ERROR "generated nil check"
- _ = *array0p // ERROR "removed nil check"
-
- _ = *intp // ERROR "removed nil check"
- _ = *arrayp // ERROR "removed nil check"
- _ = *structp // ERROR "generated nil check"
- _ = *emptyp // ERROR "generated nil check"
- _ = *arrayp // ERROR "removed nil check"
-}
-
-func f2() {
- var (
- intp *int
- arrayp *[10]int
- array0p *[0]int
- bigarrayp *[1 << 20]int
- structp *Struct
- bigstructp *BigStruct
- emptyp *Empty
- empty1p *Empty1
- )
-
- _ = *intp // ERROR "generated nil check"
- _ = *arrayp // ERROR "generated nil check"
- _ = *array0p // ERROR "generated nil check"
- _ = *array0p // ERROR "removed.* nil check"
- _ = *intp // ERROR "removed.* nil check"
- _ = *arrayp // ERROR "removed.* nil check"
- _ = *structp // ERROR "generated nil check"
- _ = *emptyp // ERROR "generated nil check"
- _ = *arrayp // ERROR "removed.* nil check"
- _ = *bigarrayp // ERROR "generated nil check" ARM removed nil check before indirect!!
- _ = *bigstructp // ERROR "generated nil check"
- _ = *empty1p // ERROR "generated nil check"
-}
-
-func fx10k() *[10000]int
-
-var b bool
-
-func f3(x *[10000]int) {
- // Using a huge type and huge offsets so the compiler
- // does not expect the memory hardware to fault.
- _ = x[9999] // ERROR "generated nil check"
-
- for {
- if x[9999] != 0 { // ERROR "removed nil check"
- break
- }
- }
-
- x = fx10k()
- _ = x[9999] // ERROR "generated nil check"
- if b {
- _ = x[9999] // ERROR "removed.* nil check"
- } else {
- _ = x[9999] // ERROR "removed.* nil check"
- }
- _ = x[9999] // ERROR "removed nil check"
-
- x = fx10k()
- if b {
- _ = x[9999] // ERROR "generated nil check"
- } else {
- _ = x[9999] // ERROR "generated nil check"
- }
- _ = x[9999] // ERROR "generated nil check"
-
- fx10k()
- // This one is a bit redundant, if we figured out that
- // x wasn't going to change across the function call.
- // But it's a little complex to do and in practice doesn't
- // matter enough.
- _ = x[9999] // ERROR "removed nil check"
-}
-
-func f3a() {
- x := fx10k()
- y := fx10k()
- z := fx10k()
- _ = &x[9] // ERROR "generated nil check"
- y = z
- _ = &x[9] // ERROR "removed.* nil check"
- x = y
- _ = &x[9] // ERROR "generated nil check"
-}
-
-func f3b() {
- x := fx10k()
- y := fx10k()
- _ = &x[9] // ERROR "generated nil check"
- y = x
- _ = &x[9] // ERROR "removed.* nil check"
- x = y
- _ = &x[9] // ERROR "removed.* nil check"
-}
-
-func fx10() *[10]int
-
-func f4(x *[10]int) {
- // Most of these have no checks because a real memory reference follows,
- // and the offset is small enough that if x is nil, the address will still be
- // in the first unmapped page of memory.
-
- _ = x[9] // ERROR "removed nil check"
-
- for {
- if x[9] != 0 { // ERROR "removed nil check"
- break
- }
- }
-
- x = fx10()
- _ = x[9] // ERROR "generated nil check" // bug would like to remove before indirect
- if b {
- _ = x[9] // ERROR "removed nil check"
- } else {
- _ = x[9] // ERROR "removed nil check"
- }
- _ = x[9] // ERROR "removed nil check"
-
- x = fx10()
- if b {
- _ = x[9] // ERROR "generated nil check" // bug would like to remove before indirect
- } else {
- _ = &x[9] // ERROR "generated nil check"
- }
- _ = x[9] // ERROR "generated nil check" // bug would like to remove before indirect
-
- fx10()
- _ = x[9] // ERROR "removed nil check"
-
- x = fx10()
- y := fx10()
- _ = &x[9] // ERROR "generated nil check"
- y = x
- _ = &x[9] // ERROR "removed[a-z ]* nil check"
- x = y
- _ = &x[9] // ERROR "removed[a-z ]* nil check"
-}
-
-func f5(p *float32, q *float64, r *float32, s *float64) float64 {
- x := float64(*p) // ERROR "removed nil check"
- y := *q // ERROR "removed nil check"
- *r = 7 // ERROR "removed nil check"
- *s = 9 // ERROR "removed nil check"
- return x + y
-}
-
-type T [29]byte
-
-func f6(p, q *T) {
- x := *p // ERROR "removed nil check"
- *q = x // ERROR "removed nil check"
-}
-
-func m1(m map[int][80]byte) byte {
- v := m[3] // ERROR "removed nil check"
- return v[5]
-}
-func m2(m map[int][800]byte) byte {
- v := m[3] // ERROR "removed nil check"
- return v[5]
-}
-func m3(m map[int][80]byte) (byte, bool) {
- v, ok := m[3] // ERROR "removed nil check"
- return v[5], ok
-}
-func m4(m map[int][800]byte) (byte, bool) {
- v, ok := m[3] // ERROR "removed nil check"
- return v[5], ok
-}
-func p1() byte {
- p := new([100]byte)
- return p[5] // ERROR "removed nil check"
-}
diff --git a/test/nosplit.go b/test/nosplit.go
index a58a645..5f4e62f 100644
--- a/test/nosplit.go
+++ b/test/nosplit.go
@@ -305,13 +305,13 @@ TestCases:
// Instead of rewriting the test cases above, adjust
// the first stack frame to use up the extra bytes.
if i == 0 {
- size += (720 - 128) - 128
+ size += (880 - 128) - 128
// Noopt builds have a larger stackguard.
// See ../src/cmd/dist/buildruntime.go:stackGuardMultiplier
// This increase is included in obj.StackGuard
for _, s := range strings.Split(os.Getenv("GO_GCFLAGS"), " ") {
if s == "-N" {
- size += 720
+ size += 880
}
}
}
diff --git a/test/notinheap.go b/test/notinheap.go
new file mode 100644
index 0000000..c3fdfd6
--- /dev/null
+++ b/test/notinheap.go
@@ -0,0 +1,55 @@
+// 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 type-checking errors for go:notinheap.
+
+package p
+
+//go:notinheap
+type nih struct{}
+
+// Types embedding notinheap types must be notinheap.
+
+type embed1 struct {
+ x nih
+} // ERROR "must be go:notinheap"
+
+type embed2 [1]nih // ERROR "must be go:notinheap"
+
+type embed3 struct {
+ x [1]nih
+} // ERROR "must be go:notinheap"
+
+type embed4 map[nih]int // ERROR "go:notinheap map key not allowed"
+
+type embed5 map[int]nih // ERROR "go:notinheap map value not allowed"
+
+type emebd6 chan nih // ERROR "chan of go:notinheap type not allowed"
+
+type okay1 *nih
+
+type okay2 []nih
+
+type okay3 func(x nih) nih
+
+type okay4 interface {
+ f(x nih) nih
+}
+
+// Type conversions don't let you sneak past notinheap.
+
+type t1 struct{ x int }
+
+//go:notinheap
+type t2 t1
+
+var sink interface{}
+
+func i() {
+ sink = new(t1) // no error
+ sink = (*t2)(new(t1)) // ERROR "cannot convert(.|\n)*t2 is go:notinheap"
+ sink = (*t2)(new(struct{ x int })) // ERROR "cannot convert(.|\n)*t2 is go:notinheap"
+}
diff --git a/test/notinheap2.go b/test/notinheap2.go
new file mode 100644
index 0000000..944f299
--- /dev/null
+++ b/test/notinheap2.go
@@ -0,0 +1,43 @@
+// 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 walk errors for go:notinheap.
+
+package p
+
+//go:notinheap
+type nih struct {
+ next *nih
+}
+
+// Globals and stack variables are okay.
+
+var x nih
+
+func f() {
+ var y nih
+ x = y
+}
+
+// Heap allocation is not okay.
+
+var y *nih
+var z []nih
+
+func g() {
+ y = new(nih) // ERROR "heap allocation disallowed"
+ z = make([]nih, 1) // ERROR "heap allocation disallowed"
+ z = append(z, x) // ERROR "heap allocation disallowed"
+}
+
+// Writes don't produce write barriers.
+
+var p *nih
+
+//go:nowritebarrier
+func h() {
+ y.next = p.next
+}
diff --git a/test/nowritebarrier.go b/test/nowritebarrier.go
new file mode 100644
index 0000000..23dce75
--- /dev/null
+++ b/test/nowritebarrier.go
@@ -0,0 +1,78 @@
+// 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 go:nowritebarrier and related directives.
+
+package p
+
+type t struct {
+ f *t
+}
+
+var x t
+var y *t
+
+//go:nowritebarrier
+func a1() {
+ x.f = y // ERROR "write barrier prohibited"
+ a2() // no error
+}
+
+//go:noinline
+func a2() {
+ x.f = y
+}
+
+//go:nowritebarrierrec
+func b1() {
+ b2()
+}
+
+//go:noinline
+func b2() {
+ x.f = y // ERROR "write barrier prohibited by caller"
+}
+
+// Test recursive cycles through nowritebarrierrec and yeswritebarrierrec.
+
+//go:nowritebarrierrec
+func c1() {
+ c2()
+}
+
+//go:yeswritebarrierrec
+func c2() {
+ c3()
+}
+
+func c3() {
+ x.f = y
+ c4()
+}
+
+//go:nowritebarrierrec
+func c4() {
+ c2()
+}
+
+//go:nowritebarrierrec
+func d1() {
+ d2()
+}
+
+func d2() {
+ d3()
+}
+
+func d3() {
+ x.f = y // ERROR "write barrier prohibited by caller"
+ d4()
+}
+
+//go:yeswritebarrierrec
+func d4() {
+ d2()
+}
diff --git a/test/nul1.go b/test/nul1.go
index 20426b4..fbba198 100644
--- a/test/nul1.go
+++ b/test/nul1.go
@@ -36,7 +36,7 @@ var y = ` + "`in raw string \x00 foo`" + ` // ERROR "NUL"
/* in other comment ` + "\x00" + ` */ // ERROR "NUL"
-/* in source code */ ` + "\x00" + `// ERROR "NUL" "illegal character"
+/* in source code */ ` + "\x00" + `// ERROR "NUL"
var xx = "in string ` + "\xc2\xff" + `" // ERROR "UTF-8"
@@ -47,10 +47,9 @@ var yy = ` + "`in raw string \xff foo`" + ` // ERROR "UTF-8"
/* in other comment ` + "\xe0\x00\x00" + ` */ // ERROR "UTF-8|NUL"
/* in variable name */
-var z` + "\xc1\x81" + ` int // ERROR "UTF-8" "invalid identifier character"
+var z` + "\xc1\x81" + ` int // ERROR "UTF-8"
-/* in source code */ ` + "var \xc2A int" + `// ERROR "UTF-8" "invalid identifier character"
+/* in source code */ ` + "var \xc2A int" + `// ERROR "UTF-8"
`)
}
-
diff --git a/test/phiopt.go b/test/phiopt.go
index 21dd131..98a7b75 100644
--- a/test/phiopt.go
+++ b/test/phiopt.go
@@ -1,4 +1,4 @@
-// +build amd64
+// +build amd64 s390x
// errorcheck -0 -d=ssa/phiopt/debug=3
// Copyright 2016 The Go Authors. All rights reserved.
diff --git a/test/prove.go b/test/prove.go
index 8bcc9ae..9ced616 100644
--- a/test/prove.go
+++ b/test/prove.go
@@ -1,5 +1,5 @@
// +build amd64
-// errorcheck -0 -d=ssa/prove/debug=3
+// errorcheck -0 -d=ssa/prove/debug=1
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
@@ -250,7 +250,7 @@ func f9(a, b bool) int {
func f10(a string) int {
n := len(a)
- if a[:n>>1] == "aaa" {
+ if a[:n>>1] == "aaaaaaaaaaaaaa" {
return 0
}
return 1
diff --git a/test/range.go b/test/range.go
index af89eda..bae7a1c 100644
--- a/test/range.go
+++ b/test/range.go
@@ -110,6 +110,30 @@ func testslice2() {
}
}
+// test that range over []byte(string) only evaluates
+// the expression after "range" once.
+
+func makenumstring() string {
+ nmake++
+ return "\x01\x02\x03\x04\x05"
+}
+
+func testslice3() {
+ s := byte(0)
+ nmake = 0
+ for _, v := range []byte(makenumstring()) {
+ s += v
+ }
+ if nmake != 1 {
+ println("range called makenumstring", nmake, "times")
+ panic("fail")
+ }
+ if s != 15 {
+ println("wrong sum ranging over []byte(makenumstring)", s)
+ panic("fail")
+ }
+}
+
// test that range over array only evaluates
// the expression after "range" once.
@@ -392,6 +416,7 @@ func main() {
testslice()
testslice1()
testslice2()
+ testslice3()
teststring()
teststring1()
teststring2()
diff --git a/test/run.go b/test/run.go
index a1ab9d5..0dee6b5 100644
--- a/test/run.go
+++ b/test/run.go
@@ -52,7 +52,7 @@ var (
// dirs are the directories to look for *.go files in.
// TODO(bradfitz): just use all directories?
- dirs = []string{".", "ken", "chan", "interface", "syntax", "dwarf", "fixedbugs", "bugs"}
+ dirs = []string{".", "ken", "chan", "interface", "syntax", "dwarf", "fixedbugs"}
// ratec controls the max number of tests running at a time.
ratec chan bool
@@ -242,8 +242,7 @@ type test struct {
donec chan bool // closed when done
dt time.Duration
- src string
- action string // "compile", "build", etc.
+ src string
tempDir string
err error
@@ -457,15 +456,15 @@ func (t *test) run() {
pkgPos = pos // some files are intentionally malformed
}
if ok, why := shouldTest(t.src[:pkgPos], goos, goarch); !ok {
- t.action = "skip"
if *showSkips {
- fmt.Printf("%-20s %-20s: %s\n", t.action, t.goFileName(), why)
+ fmt.Printf("%-20s %-20s: %s\n", "skip", t.goFileName(), why)
}
return
}
var args, flags []string
wantError := false
+ wantAuto := false
singlefilepkgs := false
f := strings.Fields(action)
if len(f) > 0 {
@@ -477,27 +476,25 @@ func (t *test) run() {
switch action {
case "rundircmpout":
action = "rundir"
- t.action = "rundir"
case "cmpout":
action = "run" // the run case already looks for <dir>/<test>.out files
- fallthrough
case "compile", "compiledir", "build", "run", "runoutput", "rundir":
- t.action = action
+ // nothing to do
case "errorcheckandrundir":
wantError = false // should be no error if also will run
- fallthrough
+ case "errorcheckwithauto":
+ action = "errorcheck"
+ wantAuto = true
+ wantError = true
case "errorcheck", "errorcheckdir", "errorcheckoutput":
- t.action = action
wantError = true
case "skip":
if *runSkips {
break
}
- t.action = "skip"
return
default:
t.err = skipError("skipped; unknown pattern: " + action)
- t.action = "??"
return
}
@@ -531,7 +528,6 @@ func (t *test) run() {
}
useTmp := true
- ssaMain := false
runcmd := func(args ...string) ([]byte, error) {
cmd := exec.Command(args[0], args[1:]...)
var buf bytes.Buffer
@@ -543,9 +539,6 @@ func (t *test) run() {
} else {
cmd.Env = os.Environ()
}
- if ssaMain && os.Getenv("GOARCH") == "amd64" {
- cmd.Env = append(cmd.Env, "GOSSAPKG=main")
- }
err := cmd.Run()
if err != nil {
err = fmt.Errorf("%s\n%s", err, buf.Bytes())
@@ -578,7 +571,7 @@ func (t *test) run() {
if *updateErrors {
t.updateErrors(string(out), long)
}
- t.err = t.errorCheck(string(out), long, t.gofile)
+ t.err = t.errorCheck(string(out), wantAuto, long, t.gofile)
return
case "compile":
@@ -626,7 +619,7 @@ func (t *test) run() {
for _, name := range gofiles {
fullshort = append(fullshort, filepath.Join(longdir, name), name)
}
- t.err = t.errorCheck(string(out), fullshort...)
+ t.err = t.errorCheck(string(out), wantAuto, fullshort...)
if t.err != nil {
break
}
@@ -680,7 +673,6 @@ func (t *test) run() {
case "run":
useTmp = false
- ssaMain = true
cmd := []string{"go", "run"}
if *linkshared {
cmd = append(cmd, "-linkshared")
@@ -716,7 +708,6 @@ func (t *test) run() {
t.err = fmt.Errorf("write tempfile:%s", err)
return
}
- ssaMain = true
cmd = []string{"go", "run"}
if *linkshared {
cmd = append(cmd, "-linkshared")
@@ -764,7 +755,7 @@ func (t *test) run() {
return
}
}
- t.err = t.errorCheck(string(out), tfile, "tmp__.go")
+ t.err = t.errorCheck(string(out), false, tfile, "tmp__.go")
return
}
}
@@ -807,7 +798,7 @@ func (t *test) expectedOutput() string {
return string(b)
}
-func splitOutput(out string) []string {
+func splitOutput(out string, wantAuto bool) []string {
// gc error messages continue onto additional lines with leading tabs.
// Split the output at the beginning of each line that doesn't begin with a tab.
// <autogenerated> lines are impossible to match so those are filtered out.
@@ -818,7 +809,7 @@ func splitOutput(out string) []string {
}
if strings.HasPrefix(line, "\t") {
res[len(res)-1] += "\n" + line
- } else if strings.HasPrefix(line, "go tool") || strings.HasPrefix(line, "<autogenerated>") || strings.HasPrefix(line, "#") {
+ } else if strings.HasPrefix(line, "go tool") || strings.HasPrefix(line, "#") || !wantAuto && strings.HasPrefix(line, "<autogenerated>") {
continue
} else if strings.TrimSpace(line) != "" {
res = append(res, line)
@@ -827,14 +818,14 @@ func splitOutput(out string) []string {
return res
}
-func (t *test) errorCheck(outStr string, fullshort ...string) (err error) {
+func (t *test) errorCheck(outStr string, wantAuto bool, fullshort ...string) (err error) {
defer func() {
if *verbose && err != nil {
log.Printf("%s gc output:\n%s", t, outStr)
}
}()
var errs []error
- out := splitOutput(outStr)
+ out := splitOutput(outStr, wantAuto)
// Cut directory name.
for i := range out {
@@ -852,7 +843,11 @@ func (t *test) errorCheck(outStr string, fullshort ...string) (err error) {
for _, we := range want {
var errmsgs []string
- errmsgs, out = partitionStrings(we.prefix, out)
+ if we.auto {
+ errmsgs, out = partitionStrings("<autogenerated>", out)
+ } else {
+ errmsgs, out = partitionStrings(we.prefix, out)
+ }
if len(errmsgs) == 0 {
errs = append(errs, fmt.Errorf("%s:%d: missing error %q", we.file, we.lineNum, we.reStr))
continue
@@ -860,7 +855,13 @@ func (t *test) errorCheck(outStr string, fullshort ...string) (err error) {
matched := false
n := len(out)
for _, errmsg := range errmsgs {
- if we.re.MatchString(errmsg) {
+ // Assume errmsg says "file:line: foo".
+ // Cut leading "file:line: " to avoid accidental matching of file name instead of message.
+ text := errmsg
+ if i := strings.Index(text, " "); i >= 0 {
+ text = text[i+1:]
+ }
+ if we.re.MatchString(text) {
matched = true
} else {
out = append(out, errmsg)
@@ -912,7 +913,7 @@ func (t *test) updateErrors(out, file string) {
// Parse new errors.
errors := make(map[int]map[string]bool)
tmpRe := regexp.MustCompile(`autotmp_[0-9]+`)
- for _, errStr := range splitOutput(out) {
+ for _, errStr := range splitOutput(out, false) {
colon1 := strings.Index(errStr, ":")
if colon1 < 0 || errStr[:colon1] != file {
continue
@@ -997,12 +998,14 @@ type wantedError struct {
reStr string
re *regexp.Regexp
lineNum int
+ auto bool // match <autogenerated> line
file string
prefix string
}
var (
errRx = regexp.MustCompile(`// (?:GC_)?ERROR (.*)`)
+ errAutoRx = regexp.MustCompile(`// (?:GC_)?ERRORAUTO (.*)`)
errQuotesRx = regexp.MustCompile(`"([^"]*)"`)
lineRx = regexp.MustCompile(`LINE(([+-])([0-9]+))?`)
)
@@ -1017,7 +1020,13 @@ func (t *test) wantedErrors(file, short string) (errs []wantedError) {
// double comment disables ERROR
continue
}
- m := errRx.FindStringSubmatch(line)
+ var auto bool
+ m := errAutoRx.FindStringSubmatch(line)
+ if m != nil {
+ auto = true
+ } else {
+ m = errRx.FindStringSubmatch(line)
+ }
if m == nil {
continue
}
@@ -1052,6 +1061,7 @@ func (t *test) wantedErrors(file, short string) (errs []wantedError) {
reStr: rx,
re: re,
prefix: prefix,
+ auto: auto,
lineNum: lineNum,
file: short,
})
diff --git a/test/sliceopt.go b/test/sliceopt.go
index a830ab7..eb24701 100644
--- a/test/sliceopt.go
+++ b/test/sliceopt.go
@@ -1,5 +1,4 @@
-// +build !amd64
-// errorcheck -0 -d=append,slice
+// errorcheck -0 -d=append,slice,ssa/prove/debug=1
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
@@ -10,51 +9,63 @@
package main
func a1(x []int, y int) []int {
- x = append(x, y) // ERROR "append: len-only update"
+ x = append(x, y) // ERROR "append: len-only update \(in local slice\)$"
return x
}
func a2(x []int, y int) []int {
- return append(x, y) // ERROR "append: full update"
+ return append(x, y)
}
func a3(x *[]int, y int) {
- *x = append(*x, y) // ERROR "append: len-only update"
+ *x = append(*x, y) // ERROR "append: len-only update$"
+}
+
+// s1_if_false_then_anything
+func s1_if_false_then_anything(x **[]int, xs **string, i, j int) {
+ z := (**x)[0:i]
+ z = z[i : i+1]
+ println(z) // if we get here, then we have proven that i==i+1 (this cannot happen, but the program is still being analyzed...)
+
+ zs := (**xs)[0:i] // since i=i+1 is proven, i+1 is "in bounds", ha-ha
+ zs = zs[i : i+1] // ERROR "Proved boolean IsSliceInBounds$"
+ println(zs)
}
func s1(x **[]int, xs **string, i, j int) {
var z []int
- z = (**x)[2:] // ERROR "slice: omit check for 2nd index"
- z = (**x)[2:len(**x)] // not yet: "slice: reuse len" "slice: omit check for 2nd index"
- z = (**x)[2:cap(**x)] // not yet: "slice: reuse cap" "slice: omit check for 2nd index"
- z = (**x)[i:i] // ERROR "slice: reuse 1st index" "slice: omit check for 1st index" "slice: result len == 0"
- z = (**x)[1:i:i] // ERROR "slice: reuse 2nd index" "slice: omit check for 2nd index" "slice: result cap == result len"
- z = (**x)[i:j:0] // ERROR "slice: omit check for 3rd index"
- z = (**x)[i:0:j] // ERROR "slice: omit check for 2nd index"
- z = (**x)[0:i:j] // ERROR "slice: omit check for 1st index" "slice: skip base adjustment for 1st index 0"
- z = (**x)[0:] // ERROR "slice: omit slice operation"
- z = (**x)[2:8] // ERROR "slice: omit check for 1st index" "slice: result len == 6"
- z = (**x)[2:2] // ERROR "slice: omit check for 1st index" "slice: result len == 0"
- z = (**x)[0:i] // ERROR "slice: omit check for 1st index" "slice: skip base adjustment for 1st index 0"
- z = (**x)[2:i:8] // ERROR "slice: result cap == 6"
- z = (**x)[i:2:i] // ERROR "slice: reuse 1st index" "slice: result cap == 0" "slice: skip base adjustment for cap == 0"
-
- z = z[0:i] // ERROR "slice: omit check for 1st index" "slice: result cap not computed" "slice: skip base adjustment for 1st index 0" "slice: len-only update"
- z = z[0:i : i+1] // ERROR "slice: omit check for 1st index" "slice: skip base adjustment for 1st index 0" "slice: len/cap-only update"
- z = z[i : i+1]
+ z = (**x)[2:]
+ z = (**x)[2:len(**x)] // ERROR "Proved boolean IsSliceInBounds$"
+ z = (**x)[2:cap(**x)] // ERROR "Proved IsSliceInBounds$"
+ z = (**x)[i:i] // -ERROR "Proved IsSliceInBounds"
+ z = (**x)[1:i:i] // ERROR "Proved boolean IsSliceInBounds$"
+ z = (**x)[i:j:0]
+ z = (**x)[i:0:j] // ERROR "Disproved IsSliceInBounds$"
+ z = (**x)[0:i:j] // ERROR "Proved boolean IsSliceInBounds$"
+ z = (**x)[0:] // ERROR "slice: omit slice operation$"
+ z = (**x)[2:8] // ERROR "Proved slicemask not needed$"
+ println(z)
+ z = (**x)[2:2]
+ z = (**x)[0:i]
+ z = (**x)[2:i:8] // ERROR "Disproved IsSliceInBounds$" "Proved IsSliceInBounds$"
+ z = (**x)[i:2:i] // ERROR "Proved IsSliceInBounds$" "Proved boolean IsSliceInBounds$"
+
+ z = z[0:i] // ERROR "Proved boolean IsSliceInBounds"
+ z = z[0:i : i+1]
+ z = z[i : i+1] // ERROR "Proved boolean IsSliceInBounds$"
println(z)
var zs string
- zs = (**xs)[2:] // ERROR "slice: omit check for 2nd index"
- zs = (**xs)[2:len(**xs)] // not yet: "slice: reuse len" "slice: omit check for 2nd index"
- zs = (**xs)[i:i] // ERROR "slice: reuse 1st index" "slice: omit check for 1st index" "slice: result len == 0" "slice: skip base adjustment for string len == 0"
- zs = (**xs)[0:] // ERROR "slice: omit slice operation"
- zs = (**xs)[2:8] // ERROR "slice: omit check for 1st index" "slice: result len == 6"
- zs = (**xs)[2:2] // ERROR "slice: omit check for 1st index" "slice: result len == 0" "slice: skip base adjustment for string len == 0"
- zs = (**xs)[0:i] // ERROR "slice: omit check for 1st index" "slice: skip base adjustment for 1st index 0"
-
- zs = zs[0:i] // ERROR "slice: omit check for 1st index" "slice: skip base adjustment for 1st index 0" "slice: len-only update"
- zs = zs[i : i+1]
+ zs = (**xs)[2:]
+ zs = (**xs)[2:len(**xs)] // ERROR "Proved IsSliceInBounds$" "Proved boolean IsSliceInBounds$"
+ zs = (**xs)[i:i] // -ERROR "Proved boolean IsSliceInBounds"
+ zs = (**xs)[0:] // ERROR "slice: omit slice operation$"
+ zs = (**xs)[2:8]
+ zs = (**xs)[2:2] // ERROR "Proved boolean IsSliceInBounds$"
+ zs = (**xs)[0:i] // ERROR "Proved boolean IsSliceInBounds$"
+
+ zs = zs[0:i] // See s1_if_false_then_anything above to explain the counterfactual bounds check result below
+ zs = zs[i : i+1] // ERROR "Proved boolean IsSliceInBounds$"
println(zs)
}
diff --git a/test/switch2.go b/test/switch2.go
index 11ff5c5..11b85d3 100644
--- a/test/switch2.go
+++ b/test/switch2.go
@@ -11,11 +11,11 @@ package main
func f() {
switch {
- case 0; // ERROR "expecting := or = or : or comma"
+ case 0; // ERROR "expecting := or = or : or comma|expecting :"
}
switch {
- case 0; // ERROR "expecting := or = or : or comma"
+ case 0; // ERROR "expecting := or = or : or comma|expecting :"
default:
}
diff --git a/test/switch5.go b/test/switch5.go
index 7da2c66..5ca53ba 100644
--- a/test/switch5.go
+++ b/test/switch5.go
@@ -57,8 +57,8 @@ func f4(e interface{}) {
case int:
case int: // ERROR "duplicate case int in type switch"
case int64:
- case error: // ERROR "duplicate case error in type switch"
case error:
+ case error: // ERROR "duplicate case error in type switch"
case fmt.Stringer:
case fmt.Stringer: // ERROR "duplicate case fmt.Stringer in type switch"
case struct {
@@ -79,3 +79,23 @@ func f5(a [1]int) {
case [1]int{0}: // OK -- see issue 15896
}
}
+
+// Ensure duplicate const bool clauses are accepted.
+func f6() int {
+ switch {
+ case 0 == 0:
+ return 0
+ case 1 == 1: // Intentionally OK, even though a duplicate of the above const true
+ return 1
+ }
+ return 2
+}
+
+// Ensure duplicates in ranges are detected (issue #17517).
+func f7(a int) {
+ switch a {
+ case 0:
+ case 0, 1: // ERROR "duplicate case 0"
+ case 1, 2, 3, 4: // ERROR "duplicate case 1"
+ }
+}
diff --git a/test/switch6.go b/test/switch6.go
index bd62c62..32392d8 100644
--- a/test/switch6.go
+++ b/test/switch6.go
@@ -21,12 +21,12 @@ func f0(e error) {
// Verify that the compiler rejects multiple default cases.
func f1(e interface{}) {
- switch e { // ERROR "multiple defaults in switch"
- default:
+ switch e {
default:
+ default: // ERROR "multiple defaults in switch"
}
- switch e.(type) { // ERROR "multiple defaults in switch"
- default:
+ switch e.(type) {
default:
+ default: // ERROR "multiple defaults in switch"
}
}
diff --git a/test/syntax/chan1.go b/test/syntax/chan1.go
index 2e9929b..a33a0d4 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"
+ if c <- v { // ERROR "used as value|missing condition|invalid condition"
}
}
-var _ = c <- v // ERROR "used as value"
+var _ = c <- v // ERROR "used as value|unexpected <-"
diff --git a/test/syntax/semi4.go b/test/syntax/semi4.go
index 6315f34..6f5592e 100644
--- a/test/syntax/semi4.go
+++ b/test/syntax/semi4.go
@@ -4,11 +4,14 @@
// 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 // GCCGO_ERROR "undefined"
-
-
+ z // ERROR "undefined|missing { after for clause"
diff --git a/test/uintptrescapes2.go b/test/uintptrescapes2.go
index 7ff676d..57c21ed 100644
--- a/test/uintptrescapes2.go
+++ b/test/uintptrescapes2.go
@@ -18,14 +18,14 @@ func F1(a uintptr) {} // ERROR "escaping uintptr"
//go:uintptrescapes
//go:noinline
-func F2(a ...uintptr) {} // ERROR "escaping ...uintptr" "live at entry" "a does not escape"
+func F2(a ...uintptr) {} // ERROR "escaping ...uintptr" "a does not escape"
func G() {
- var t int // ERROR "moved to heap"
- F1(uintptr(unsafe.Pointer(&t))) // ERROR "live at call to F1: autotmp" "&t escapes to heap"
+ var t int // ERROR "moved to heap"
+ F1(uintptr(unsafe.Pointer(&t))) // ERROR "live at call to F1: .?autotmp" "&t escapes to heap"
}
func H() {
- var v int // ERROR "moved to heap"
- F2(0, 1, uintptr(unsafe.Pointer(&v)), 2) // ERROR "live at call to newobject: autotmp" "live at call to F2: autotmp" "escapes to heap"
+ var v int // ERROR "moved to heap"
+ F2(0, 1, uintptr(unsafe.Pointer(&v)), 2) // ERROR "live at call to newobject: .?autotmp" "live at call to F2: .?autotmp" "escapes to heap"
}
diff --git a/test/writebarrier.go b/test/writebarrier.go
index 88b4b29..6460a6f 100644
--- a/test/writebarrier.go
+++ b/test/writebarrier.go
@@ -164,8 +164,9 @@ type T17 struct {
}
func f17(x *T17) {
- // See golang.org/issue/13901
- x.f = f17 // no barrier
+ // Originally from golang.org/issue/13901, but the hybrid
+ // barrier requires both to have barriers.
+ x.f = f17 // ERROR "write barrier"
x.f = func(y *T17) { *y = *x } // ERROR "write barrier"
}
@@ -207,7 +208,15 @@ func f21(x *int) {
// Global -> heap pointer updates must have write barriers.
x21 = x // ERROR "write barrier"
y21.x = x // ERROR "write barrier"
- x21 = &z21 // no barrier
- y21.x = &z21 // no barrier
+ x21 = &z21 // ERROR "write barrier"
+ y21.x = &z21 // ERROR "write barrier"
y21 = struct{ x *int }{x} // ERROR "write barrier"
}
+
+func f22(x *int) (y *int) {
+ // pointer write on stack should have no write barrier.
+ // this is a case that the frontend failed to eliminate.
+ p := &y
+ *p = x // no barrier
+ return
+}
--
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